summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore43
-rw-r--r--bin/empty.txt1
-rwxr-xr-xbootstrap.sh19
-rw-r--r--build/empty.txt1
-rw-r--r--compiler.nimble11
-rw-r--r--compiler/aliases.nim182
-rw-r--r--compiler/ast.nim1550
-rw-r--r--compiler/astalgo.nim903
-rw-r--r--compiler/bitsets.nim71
-rw-r--r--compiler/canonicalizer.nim416
-rw-r--r--compiler/ccgcalls.nim542
-rw-r--r--compiler/ccgexprs.nim2198
-rw-r--r--compiler/ccgmerge.nim298
-rw-r--r--compiler/ccgstmts.nim1112
-rw-r--r--compiler/ccgthreadvars.nim65
-rw-r--r--compiler/ccgtrav.nim151
-rw-r--r--compiler/ccgtypes.nim1034
-rw-r--r--compiler/ccgutils.nim212
-rw-r--r--compiler/cgen.nim1330
-rw-r--r--compiler/cgendata.nim162
-rw-r--r--compiler/cgmeth.nim
-rw-r--r--config/nimdoc.tex.cfg123
-rw-r--r--config/rename.rules.cfg9
-rw-r--r--contributors.txt13
-rw-r--r--copying.txt24
-rw-r--r--doc/advopt.txt78
-rw-r--r--doc/apis.txt81
-rw-r--r--doc/astspec.txt572
-rw-r--r--doc/backends.txt463
-rw-r--r--doc/basicopt.txt40
-rw-r--r--doc/docgen.txt355
-rw-r--r--doc/docgen_sample.nim12
-rw-r--r--doc/docs.txt40
-rw-r--r--doc/effects.txt41
-rw-r--r--doc/endb.txt203
-rw-r--r--doc/estp.txt195
-rw-r--r--doc/exception_hierarchy_fragment.txt28
-rw-r--r--doc/filelist.txt54
-rw-r--r--doc/filters.txt196
-rw-r--r--doc/gc.txt131
-rw-r--r--doc/grammar.txt196
-rw-r--r--doc/idetools.txt588
-rw-r--r--doc/intern.txt568
-rw-r--r--doc/keywords.txt21
-rw-r--r--doc/koch.txt151
-rw-r--r--doc/lib.txt610
-rw-r--r--doc/manual.txt39
-rw-r--r--doc/manual/about.txt37
-rw-r--r--doc/manual/compiler_msgs.txt7
-rw-r--r--doc/manual/definitions.txt49
-rw-r--r--doc/manual/effects.txt129
-rw-r--r--doc/manual/exceptions.txt158
-rw-r--r--doc/manual/ffi.txt209
-rw-r--r--doc/manual/generics.txt321
-rw-r--r--doc/manual/lexing.txt375
-rw-r--r--doc/manual/locking.txt200
-rw-r--r--doc/manual/modules.txt202
-rw-r--r--doc/manual/pragmas.txt513
-rw-r--r--doc/manual/procs.txt667
-rw-r--r--doc/manual/special_ops.txt54
-rw-r--r--doc/manual/stmts.txt660
-rw-r--r--doc/manual/syntax.txt109
-rw-r--r--doc/manual/taint.txt20
-rw-r--r--doc/manual/templates.txt436
-rw-r--r--doc/manual/threads.txt208
-rw-r--r--doc/manual/trmacros.txt367
-rw-r--r--doc/manual/type_bound_ops.txt134
-rw-r--r--doc/manual/type_rel.txt342
-rw-r--r--doc/manual/type_sections.txt23
-rw-r--r--doc/manual/typedesc.txt127
-rw-r--r--doc/manual/types.txt1199
-rw-r--r--doc/mytest.cfg20
-rw-r--r--doc/nimc.txt921
-rw-r--r--doc/nimdoc.css300
-rw-r--r--doc/nimfix.txt56
-rw-r--r--doc/nimgrep.txt50
-rw-r--r--doc/niminst.txt195
-rw-r--r--doc/nimsuggest.txt174
-rw-r--r--doc/overview.txt9
-rw-r--r--doc/pegdocs.txt222
-rw-r--r--doc/readme.txt7
-rw-r--r--doc/regexprs.txt274
-rw-r--r--doc/sets_fragment.txt39
-rw-r--r--doc/spawn.txt96
-rw-r--r--doc/subexes.txt61
-rw-r--r--doc/tools.txt29
-rw-r--r--doc/tut1.txt1670
-rw-r--r--doc/tut2.txt994
-rw-r--r--examples/allany.nim26
-rw-r--r--examples/c++iface/irrlichtex.nim114
-rw-r--r--examples/cgi/cgi_server.py11
-rw-r--r--examples/cgi/cgi_stacktrace.nim5
-rw-r--r--examples/cgi/example.nim7
-rw-r--r--examples/cgiex.nim12
-rw-r--r--examples/cross_calculator/.gitignore12
-rw-r--r--examples/cross_calculator/android/AndroidManifest.xml18
-rw-r--r--examples/cross_calculator/android/build.xml92
-rw-r--r--examples/cross_calculator/android/custom_rules.xml17
-rw-r--r--examples/cross_calculator/android/jni/Android.mk32
-rw-r--r--examples/cross_calculator/android/jni/backend-jni.c42
-rw-r--r--examples/cross_calculator/android/project.properties14
-rw-r--r--examples/cross_calculator/android/readme.txt30
-rw-r--r--examples/cross_calculator/android/res/layout/cross_calculator.xml72
-rw-r--r--examples/cross_calculator/android/res/values/strings.xml4
-rw-r--r--examples/cross_calculator/android/scripts/jnibuild.sh22
-rw-r--r--examples/cross_calculator/android/scripts/nimbuild.sh34
-rw-r--r--examples/cross_calculator/android/scripts/tags.sh13
-rw-r--r--examples/cross_calculator/android/src/com/github/nimrod/crosscalculator/CrossCalculator.java80
-rw-r--r--examples/cross_calculator/ios/cross-calculator.xcodeproj/project.pbxproj337
-rw-r--r--examples/cross_calculator/ios/readme.txt17
-rw-r--r--examples/cross_calculator/ios/resources/plist/cross-calculator-Info.plist30
-rw-r--r--examples/cross_calculator/ios/resources/ui/NRViewController.xib479
-rw-r--r--examples/cross_calculator/ios/scripts/tags.sh13
-rw-r--r--examples/cross_calculator/ios/scripts/xcode_prebuild.sh35
-rw-r--r--examples/cross_calculator/ios/src/AppDelegate.h7
-rw-r--r--examples/cross_calculator/ios/src/AppDelegate.m39
-rw-r--r--examples/cross_calculator/ios/src/NRViewController.h11
-rw-r--r--examples/cross_calculator/ios/src/NRViewController.m210
-rw-r--r--examples/cross_calculator/ios/src/cross-calculator-Prefix.pch10
-rw-r--r--examples/cross_calculator/ios/src/main.m13
-rw-r--r--examples/cross_calculator/lazarus/nimlaz.lpi140
-rw-r--r--examples/cross_calculator/lazarus/nimlaz.lpr21
-rw-r--r--examples/cross_calculator/lazarus/nimlaz.lrs5222
-rw-r--r--examples/cross_calculator/lazarus/nimlaz.rc6
-rw-r--r--examples/cross_calculator/lazarus/readme.txt8
-rw-r--r--examples/cross_calculator/lazarus/unit1.lfm46
-rw-r--r--examples/cross_calculator/lazarus/unit1.pas58
-rw-r--r--examples/cross_calculator/nim_backend/backend.nim5
-rw-r--r--examples/cross_calculator/nim_commandline/nim.cfg4
-rw-r--r--examples/cross_calculator/nim_commandline/nimcalculator.nim109
-rw-r--r--examples/cross_calculator/nim_commandline/readme.txt10
-rw-r--r--examples/cross_calculator/readme.txt13
-rw-r--r--examples/cross_todo/nim_backend/backend.nim219
-rw-r--r--examples/cross_todo/nim_backend/readme.txt14
-rw-r--r--examples/cross_todo/nim_backend/testbackend.nim83
-rw-r--r--examples/cross_todo/nim_commandline/nim.cfg4
-rw-r--r--examples/cross_todo/nim_commandline/nimtodo.nim327
-rw-r--r--examples/cross_todo/nim_commandline/readme.txt19
-rw-r--r--examples/cross_todo/readme.txt7
-rw-r--r--examples/curlex.nim10
-rw-r--r--examples/debugging.nim17
-rw-r--r--examples/filterex.nim23
-rw-r--r--examples/fizzbuzz.nim14
-rw-r--r--examples/hallo.nim3
-rw-r--r--examples/htmlrefs.nim57
-rw-r--r--examples/htmltitle.nim36
-rw-r--r--examples/httpserver2.nim247
-rw-r--r--examples/iupex1.nim37
-rw-r--r--examples/keyval.nim9
-rw-r--r--examples/keyval2.nim7
-rw-r--r--examples/maximum.nim6
-rw-r--r--examples/myfile.txt11
-rw-r--r--examples/objciface/gnustepex.nim40
-rw-r--r--examples/parsecfgex.nim25
-rw-r--r--examples/readme.txt5
-rw-r--r--examples/sdlex.nim52
-rw-r--r--examples/statcsv.nim60
-rw-r--r--examples/talk/dsl.nim33
-rw-r--r--examples/talk/formatoptimizer.nim55
-rw-r--r--examples/talk/hoisting.nim23
-rw-r--r--examples/talk/lazyeval.nim12
-rw-r--r--examples/talk/quasiquote.nim11
-rw-r--r--examples/talk/tags.nim8
-rw-r--r--examples/transff.nim8
-rw-r--r--examples/tunit.nim47
-rw-r--r--examples/wingui.nim9
-rw-r--r--icons/koch.icobin0 -> 5430 bytes-rw-r--r--icons/koch.rc3
-rw-r--r--icons/koch.resbin0 -> 5768 bytes-rw-r--r--icons/koch_icon.obin0 -> 5768 bytes-rw-r--r--icons/nim.icobin0 -> 30319 bytes-rw-r--r--icons/nim.rc3
-rw-r--r--icons/nim.resbin0 -> 30830 bytes-rw-r--r--icons/nim_icon.obin0 -> 30830 bytes-rw-r--r--install.sh.template9
-rw-r--r--install.txt68
-rw-r--r--koch.nim383
-rw-r--r--koch.nim.cfg1
-rw-r--r--lib/core/locks.nim67
-rw-r--r--lib/core/macros.nim845
-rw-r--r--lib/core/typeinfo.nim702
-rw-r--r--lib/core/unsigned.nim57
-rw-r--r--lib/cycle.h514
-rw-r--r--lib/impure/db_mysql.nim237
-rw-r--r--lib/impure/db_postgres.nim268
-rw-r--r--lib/impure/db_sqlite.nim219
-rw-r--r--lib/impure/dialogs.nim226
-rw-r--r--lib/impure/graphics.nim575
-rw-r--r--lib/impure/nre/.gitignore9
-rw-r--r--lib/impure/nre/LICENCE (renamed from LICENCE)0
-rw-r--r--lib/impure/nre/README.rst (renamed from README.rst)0
-rw-r--r--lib/impure/nre/circle.yml (renamed from circle.yml)0
-rw-r--r--lib/impure/nre/nre.nimble (renamed from nre.nimble)0
-rwxr-xr-xlib/impure/nre/runtests.sh (renamed from runtests.sh)0
-rw-r--r--lib/impure/nre/src/nre.nim (renamed from src/nre.nim)0
-rw-r--r--lib/impure/nre/src/private/pcre.h (renamed from src/private/pcre.h)0
-rw-r--r--lib/impure/nre/src/private/pcre.nim (renamed from src/private/pcre.nim)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/config.h (renamed from src/private/pcre_src/config.h)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre.h (renamed from src/private/pcre_src/pcre.h)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_byte_order.c (renamed from src/private/pcre_src/pcre_byte_order.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_chartables.c (renamed from src/private/pcre_src/pcre_chartables.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_compile.c (renamed from src/private/pcre_src/pcre_compile.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_config.c (renamed from src/private/pcre_src/pcre_config.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_dfa_exec.c (renamed from src/private/pcre_src/pcre_dfa_exec.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_exec.c (renamed from src/private/pcre_src/pcre_exec.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_fullinfo.c (renamed from src/private/pcre_src/pcre_fullinfo.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_get.c (renamed from src/private/pcre_src/pcre_get.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_globals.c (renamed from src/private/pcre_src/pcre_globals.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_internal.h (renamed from src/private/pcre_src/pcre_internal.h)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_jit_compile.c (renamed from src/private/pcre_src/pcre_jit_compile.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_maketables.c (renamed from src/private/pcre_src/pcre_maketables.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_newline.c (renamed from src/private/pcre_src/pcre_newline.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_ord2utf8.c (renamed from src/private/pcre_src/pcre_ord2utf8.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_refcount.c (renamed from src/private/pcre_src/pcre_refcount.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_string_utils.c (renamed from src/private/pcre_src/pcre_string_utils.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_study.c (renamed from src/private/pcre_src/pcre_study.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_tables.c (renamed from src/private/pcre_src/pcre_tables.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_ucd.c (renamed from src/private/pcre_src/pcre_ucd.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_valid_utf8.c (renamed from src/private/pcre_src/pcre_valid_utf8.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_version.c (renamed from src/private/pcre_src/pcre_version.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/pcre_xclass.c (renamed from src/private/pcre_src/pcre_xclass.c)0
-rw-r--r--lib/impure/nre/src/private/pcre_src/ucp.h (renamed from src/private/pcre_src/ucp.h)0
-rw-r--r--lib/impure/nre/src/private/util.nim (renamed from src/private/util.nim)0
-rw-r--r--lib/impure/nre/test/captures.nim (renamed from test/captures.nim)0
-rw-r--r--lib/impure/nre/test/escape.nim (renamed from test/escape.nim)0
-rw-r--r--lib/impure/nre/test/find.nim (renamed from test/find.nim)0
-rw-r--r--lib/impure/nre/test/init.nim (renamed from test/init.nim)0
-rw-r--r--lib/impure/nre/test/match.nim (renamed from test/match.nim)0
-rw-r--r--lib/impure/nre/test/misc.nim (renamed from test/misc.nim)0
-rw-r--r--lib/impure/nre/test/optional_nonstrict.nim (renamed from test/optional_nonstrict.nim)0
-rw-r--r--lib/impure/nre/test/replace.nim (renamed from test/replace.nim)0
-rw-r--r--lib/impure/nre/test/split.nim (renamed from test/split.nim)0
-rw-r--r--lib/impure/nre/test/testall.nim (renamed from test/testall.nim)0
-rw-r--r--lib/impure/nre/web/logo.png (renamed from web/logo.png)bin41667 -> 41667 bytes-rw-r--r--lib/impure/nre/web/logo.svg (renamed from web/logo.svg)0
-rw-r--r--lib/impure/osinfo_posix.nim10
-rw-r--r--lib/impure/osinfo_win.nim10
-rw-r--r--lib/impure/rdstdin.nim148
-rw-r--r--lib/impure/re.nim510
-rw-r--r--lib/impure/ssl.nim96
-rw-r--r--lib/impure/zipfiles.nim183
-rw-r--r--lib/js/dom.nim487
-rw-r--r--lib/nimbase.h411
-rw-r--r--lib/nimrtl.nim36
-rw-r--r--lib/nimrtl.nim.cfg5
-rw-r--r--lib/packages/docutils/docutils.babel6
-rw-r--r--lib/packages/docutils/highlite.nim567
-rw-r--r--lib/packages/docutils/rst.nim1708
-rw-r--r--lib/packages/docutils/rstast.nim313
-rw-r--r--lib/packages/docutils/rstgen.nim1256
-rw-r--r--lib/posix/epoll.nim92
-rw-r--r--lib/posix/inotify.nim72
-rw-r--r--lib/posix/linux.nim28
-rw-r--r--lib/posix/posix.nim2585
-rw-r--r--lib/posix/termios.nim261
-rw-r--r--lib/prelude.nim23
-rw-r--r--lib/pure/actors.nim239
-rw-r--r--lib/pure/actors.nim.cfg3
-rw-r--r--lib/pure/algorithm.nim333
-rw-r--r--lib/pure/asyncdispatch.nim1547
-rw-r--r--lib/pure/asyncdispatch.nim.cfg3
-rw-r--r--lib/pure/asyncfile.nim325
-rw-r--r--lib/pure/asyncftpclient.nim313
-rw-r--r--lib/pure/asynchttpserver.nim277
-rw-r--r--lib/pure/asyncio.nim712
-rw-r--r--lib/pure/asyncnet.nim548
-rw-r--r--lib/pure/base64.nim128
-rw-r--r--lib/pure/basic2d.nim855
-rw-r--r--lib/pure/basic3d.nim1040
-rw-r--r--lib/pure/browsers.nim48
-rw-r--r--lib/pure/cgi.nim400
-rw-r--r--lib/pure/collections/LockFreeHash.nim607
-rw-r--r--lib/pure/collections/critbits.nim304
-rw-r--r--lib/pure/collections/intsets.nim218
-rw-r--r--lib/pure/collections/lists.nim343
-rw-r--r--lib/pure/collections/queues.nim102
-rw-r--r--lib/pure/collections/rtarrays.nim36
-rw-r--r--lib/pure/collections/sequtils.nim619
-rw-r--r--lib/pure/collections/sets.nim976
-rw-r--r--lib/pure/collections/tables.nim1102
-rw-r--r--lib/pure/colors.nim411
-rw-r--r--lib/pure/complex.nim443
-rw-r--r--lib/pure/concurrency/cpuinfo.nim67
-rw-r--r--lib/pure/concurrency/cpuload.nim96
-rw-r--r--lib/pure/concurrency/threadpool.nim401
-rw-r--r--lib/pure/concurrency/threadpool.nim.cfg1
-rw-r--r--lib/pure/cookies.nim67
-rw-r--r--lib/pure/dynlib.nim100
-rw-r--r--lib/pure/encodings.nim464
-rw-r--r--lib/pure/endians.nim59
-rw-r--r--lib/pure/events.nim103
-rw-r--r--lib/pure/fenv.nim181
-rw-r--r--lib/pure/fsmonitor.nim217
-rw-r--r--lib/pure/ftpclient.nim646
-rw-r--r--lib/pure/future.nim183
-rw-r--r--lib/pure/gentabs.nim206
-rw-r--r--lib/pure/hashes.nim170
-rw-r--r--lib/pure/htmlgen.nim490
-rw-r--r--lib/pure/htmlparser.nim608
-rw-r--r--lib/pure/httpclient.nim861
-rw-r--r--lib/pure/httpserver.nim532
-rw-r--r--lib/pure/json.nim1262
-rw-r--r--lib/pure/lexbase.nim169
-rw-r--r--lib/pure/logging.nim291
-rw-r--r--lib/pure/marshal.nim330
-rw-r--r--lib/pure/matchers.nim64
-rw-r--r--lib/pure/math.nim389
-rw-r--r--lib/pure/md5.nim245
-rw-r--r--lib/pure/memfiles.nim247
-rw-r--r--lib/pure/mersenne.nim39
-rw-r--r--lib/pure/mimetypes.nim522
-rw-r--r--lib/pure/net.nim1271
-rw-r--r--lib/pure/nimprof.nim205
-rw-r--r--lib/pure/nimprof.nim.cfg1
-rw-r--r--lib/pure/numeric.nim84
-rw-r--r--lib/pure/oids.nim93
-rw-r--r--lib/pure/options.nim160
-rw-r--r--lib/pure/os.nim2068
-rw-r--r--lib/pure/osproc.nim983
-rw-r--r--lib/pure/parsecfg.nim361
-rw-r--r--lib/pure/parsecsv.nim180
-rw-r--r--lib/pure/parseopt.nim159
-rw-r--r--lib/pure/parseopt2.nim152
-rw-r--r--lib/pure/parsesql.nim1350
-rw-r--r--lib/pure/parseurl.nim114
-rw-r--r--lib/pure/parseutils.nim342
-rw-r--r--lib/pure/parsexml.nim662
-rw-r--r--lib/pure/pegs.nim1791
-rw-r--r--lib/pure/poly.nim368
-rw-r--r--lib/pure/rationals.nim289
-rw-r--r--lib/pure/rawsockets.nim436
-rw-r--r--lib/pure/redis.nim1096
-rw-r--r--lib/pure/romans.nim56
-rw-r--r--lib/pure/ropes.nim386
-rw-r--r--lib/pure/scgi.nim297
-rw-r--r--lib/pure/selectors.nim323
-rw-r--r--lib/pure/sexp.nim697
-rw-r--r--lib/pure/smtp.nim277
-rw-r--r--lib/pure/smtp.nim.cfg1
-rw-r--r--lib/pure/sockets.nim1740
-rw-r--r--lib/pure/streams.nim464
-rw-r--r--lib/pure/strtabs.nim250
-rw-r--r--lib/pure/strutils.nim1441
-rw-r--r--lib/pure/subexes.nim411
-rw-r--r--lib/pure/terminal.nim390
-rw-r--r--lib/pure/times.nim1120
-rw-r--r--lib/pure/typetraits.nim36
-rw-r--r--lib/pure/unicode.nim1318
-rw-r--r--lib/pure/unidecode/gen.py26
-rw-r--r--lib/pure/unidecode/unidecode.dat65411
-rw-r--r--lib/pure/unidecode/unidecode.nim74
-rw-r--r--lib/pure/unittest.nim237
-rw-r--r--lib/pure/uri.nim421
-rw-r--r--lib/pure/xmldom.nim1120
-rw-r--r--lib/pure/xmldomparser.nim168
-rw-r--r--lib/pure/xmlparser.nim159
-rw-r--r--lib/pure/xmltree.nim357
-rw-r--r--lib/stdlib.nimble6
-rw-r--r--lib/system.nim3276
-rw-r--r--lib/system/alloc.nim854
-rw-r--r--lib/system/ansi_c.nim168
-rw-r--r--lib/system/arithm.nim343
-rw-r--r--lib/system/assign.nim234
-rw-r--r--lib/system/atomics.nim227
-rw-r--r--lib/system/avltree.nim91
-rw-r--r--lib/system/cellsets.nim220
-rw-r--r--lib/system/cgprocs.nim25
-rw-r--r--lib/system/channels.nim265
-rw-r--r--lib/system/chcks.nim99
-rw-r--r--lib/system/debugger.nim303
-rw-r--r--lib/system/deepcopy.nim141
-rw-r--r--lib/system/dyncalls.nim150
-rw-r--r--lib/system/embedded.nim43
-rw-r--r--lib/system/endb.nim538
-rw-r--r--lib/system/excpt.nim369
-rw-r--r--lib/system/gc.nim1142
-rw-r--r--lib/system/gc2.nim1393
-rw-r--r--lib/system/gc_ms.nim605
-rw-r--r--lib/system/hti.nim92
-rw-r--r--lib/system/inclrtl.nim53
-rw-r--r--lib/system/jssys.nim730
-rw-r--r--lib/system/mmdisp.nim337
-rw-r--r--lib/system/platforms.nim74
-rw-r--r--lib/system/profiler.nim99
-rw-r--r--lib/system/repr.nim287
-rw-r--r--lib/system/reprjs.nim23
-rw-r--r--lib/system/sets.nim28
-rw-r--r--lib/system/sysio.nim321
-rw-r--r--lib/system/syslocks.nim104
-rw-r--r--lib/system/sysspawn.nim194
-rw-r--r--lib/system/sysstr.nim423
-rw-r--r--lib/system/threads.nim410
-rw-r--r--lib/system/timers.nim93
-rw-r--r--lib/system/widestrs.nim153
-rw-r--r--lib/windows/mmsystem.nim2652
-rw-r--r--lib/windows/nb30.nim232
-rw-r--r--lib/windows/psapi.nim202
-rw-r--r--lib/windows/shellapi.nim863
-rw-r--r--lib/windows/shfolder.nim93
-rw-r--r--lib/windows/windows.nim23973
-rw-r--r--lib/windows/winlean.nim757
-rw-r--r--lib/wrappers/claro.nim2734
-rw-r--r--lib/wrappers/expat.nim877
-rw-r--r--lib/wrappers/iup.nim949
-rw-r--r--lib/wrappers/joyent_http_parser.nim81
-rw-r--r--lib/wrappers/libcurl.nim494
-rw-r--r--lib/wrappers/libffi/common/ffi.h331
-rw-r--r--lib/wrappers/libffi/common/ffi_common.h77
-rw-r--r--lib/wrappers/libffi/common/fficonfig.h96
-rw-r--r--lib/wrappers/libffi/common/ffitarget.h150
-rw-r--r--lib/wrappers/libffi/common/malloc_closure.c110
-rw-r--r--lib/wrappers/libffi/common/raw_api.c254
-rw-r--r--lib/wrappers/libffi/gcc/closures.c627
-rw-r--r--lib/wrappers/libffi/gcc/ffi.c841
-rw-r--r--lib/wrappers/libffi/gcc/ffi64.c673
-rw-r--r--lib/wrappers/libffi/gcc/prep_cif.c237
-rw-r--r--lib/wrappers/libffi/gcc/types.c77
-rw-r--r--lib/wrappers/libffi/gcc/win32_asm.asm759
-rw-r--r--lib/wrappers/libffi/gcc/win32_asm.s736
-rw-r--r--lib/wrappers/libffi/gcc/win64_asm.asm467
-rw-r--r--lib/wrappers/libffi/gcc/win64_asm.s227
-rw-r--r--lib/wrappers/libffi/libffi.nim171
-rw-r--r--lib/wrappers/libffi/msvc/ffi.c457
-rw-r--r--lib/wrappers/libffi/msvc/prep_cif.c175
-rw-r--r--lib/wrappers/libffi/msvc/types.c104
-rw-r--r--lib/wrappers/libffi/msvc/win32.c162
-rw-r--r--lib/wrappers/libffi/msvc/win32_asm.asm470
-rw-r--r--lib/wrappers/libffi/msvc/win64_asm.asm156
-rw-r--r--lib/wrappers/libsvm.nim116
-rw-r--r--lib/wrappers/libuv.nim701
-rw-r--r--lib/wrappers/mysql.nim1081
-rw-r--r--lib/wrappers/odbcsql.nim788
-rw-r--r--lib/wrappers/openssl.nim576
-rw-r--r--lib/wrappers/pcre.nim501
-rw-r--r--lib/wrappers/pdcurses.nim1539
-rw-r--r--lib/wrappers/postgres.nim352
-rw-r--r--lib/wrappers/readline/history.nim277
-rw-r--r--lib/wrappers/readline/readline.nim1202
-rw-r--r--lib/wrappers/readline/rltypedefs.nim74
-rw-r--r--lib/wrappers/readline/tweaked/history.h257
-rw-r--r--lib/wrappers/readline/tweaked/readline.h956
-rw-r--r--lib/wrappers/readline/tweaked/rltypedefs.h78
-rw-r--r--lib/wrappers/readline/tweaked/tilde.h77
-rw-r--r--lib/wrappers/sdl/sdl.nim2538
-rw-r--r--lib/wrappers/sdl/sdl_gfx.nim452
-rw-r--r--lib/wrappers/sdl/sdl_image.nim243
-rw-r--r--lib/wrappers/sdl/sdl_mixer.nim484
-rw-r--r--lib/wrappers/sdl/sdl_mixer_nosmpeg.nim351
-rw-r--r--lib/wrappers/sdl/sdl_net.nim426
-rw-r--r--lib/wrappers/sdl/sdl_ttf.nim337
-rw-r--r--lib/wrappers/sdl/smpeg.nim332
-rw-r--r--lib/wrappers/sphinx.nim261
-rw-r--r--lib/wrappers/sqlite3.nim357
-rw-r--r--lib/wrappers/tinyc.nim118
-rw-r--r--lib/wrappers/tre.nim186
-rw-r--r--lib/wrappers/zip/libzip.nim249
-rw-r--r--lib/wrappers/zip/libzip_all.c4189
-rw-r--r--lib/wrappers/zip/zlib.nim310
-rw-r--r--lib/wrappers/zip/zzip.nim172
-rw-r--r--readme.md84
-rw-r--r--readme.txt18
-rw-r--r--start.bat6
-rw-r--r--tests/actiontable/tactiontable.nim27
-rw-r--r--tests/actiontable/tactiontable2.nim27
-rw-r--r--tests/alias/talias.nim66
-rw-r--r--tests/ambsym/mambsym1.nim10
-rw-r--r--tests/ambsym/mambsym2.nim3
-rw-r--r--tests/ambsym/mambsys1.nim7
-rw-r--r--tests/ambsym/mambsys2.nim4
-rw-r--r--tests/ambsym/tambsym.nim15
-rw-r--r--tests/ambsym/tambsym2.nim24
-rw-r--r--tests/ambsym/tambsym3.nim15
-rw-r--r--tests/ambsym/tambsys.nim13
-rw-r--r--tests/array/tarray.nim40
-rw-r--r--tests/array/tarray2.nim36
-rw-r--r--tests/array/tarray3.nim13
-rw-r--r--tests/array/tarraycons.nim24
-rw-r--r--tests/array/tarraycons2.nim23
-rw-r--r--tests/array/tarrayplus.nim13
-rw-r--r--tests/array/tarrindx.nim13
-rw-r--r--tests/array/troof1.nim36
-rw-r--r--tests/array/troof2.nim10
-rw-r--r--tests/array/troof3.nim8
-rw-r--r--tests/array/troof4.nim37
-rw-r--r--tests/assert/tassert.nim23
-rw-r--r--tests/assert/tfailedassert.nim51
-rw-r--r--tests/assert/tunittests.nim1
-rw-r--r--tests/assert/tuserassert.nim13
-rw-r--r--tests/assign/moverload_asgn2.nim10
-rw-r--r--tests/assign/tassign.nim31
-rw-r--r--tests/assign/tcopy.nim25
-rw-r--r--tests/assign/tgenericassign.nim24
-rw-r--r--tests/assign/tgenericassigntuples.nim16
-rw-r--r--tests/assign/tobjasgn.nim44
-rw-r--r--tests/assign/toverload_asgn1.nim75
-rw-r--r--tests/assign/toverload_asgn2.nim22
-rw-r--r--tests/assign/tvariantasgn.nim30
-rw-r--r--tests/astoverload/tastoverload1.nim21
-rw-r--r--tests/async/tasyncawait.nim65
-rw-r--r--tests/async/tasyncdiscard.nim39
-rw-r--r--tests/async/tasyncexceptions.nim39
-rw-r--r--tests/async/tasyncfile.nim36
-rw-r--r--tests/async/tasynciossl.nim92
-rw-r--r--tests/async/tasynctry.nim104
-rw-r--r--tests/async/tasynctry2.nim16
-rw-r--r--tests/async/tasyncudp.nim78
-rw-r--r--tests/async/tnestedpfuturetypeparam.nim8
-rw-r--r--tests/benchmark.nim47
-rw-r--r--tests/benchmarks/fannkuch.nim69
-rw-r--r--tests/benchmarks/quicksort.nim54
-rw-r--r--tests/bind/mbind3.nim10
-rw-r--r--tests/bind/tbind1.nim21
-rw-r--r--tests/bind/tbind2.nim17
-rw-r--r--tests/bind/tbind3.nim11
-rw-r--r--tests/bind/tbindoverload.nim12
-rw-r--r--tests/bind/tdatabind.nim95
-rw-r--r--tests/bind/tinvalidbindtypedesc.nim11
-rw-r--r--tests/bind/tmixin.nim27
-rw-r--r--tests/bind/tnicerrorforsymchoice.nim18
-rw-r--r--tests/borrow/tborrow.nim21
-rw-r--r--tests/borrow/tinvalidborrow.nim17
-rw-r--r--tests/caas/absurd_nesting.nim29
-rw-r--r--tests/caas/absurd_nesting.txt29
-rw-r--r--tests/caas/basic-recompile.txt10
-rw-r--r--tests/caas/compile-suggest.txt7
-rw-r--r--tests/caas/compile-then-def.txt11
-rw-r--r--tests/caas/completion_dot_syntax.txt9
-rw-r--r--tests/caas/completion_dot_syntax_dirty.nim25
-rw-r--r--tests/caas/completion_dot_syntax_main.nim24
-rw-r--r--tests/caas/def-def-compile.txt12
-rw-r--r--tests/caas/def-then-compile.txt8
-rw-r--r--tests/caas/forward_declarations.nim15
-rw-r--r--tests/caas/forward_declarations.txt9
-rw-r--r--tests/caas/forward_usages.txt17
-rw-r--r--tests/caas/idetools_api.nim84
-rw-r--r--tests/caas/idetools_api.txt59
-rw-r--r--tests/caas/imported.nim3
-rw-r--r--tests/caas/issue_416_template_shift.nim17
-rw-r--r--tests/caas/issue_416_template_shift.txt14
-rw-r--r--tests/caas/issue_452_export_shift.nim8
-rw-r--r--tests/caas/issue_452_export_shift.txt11
-rw-r--r--tests/caas/issue_477_dynamic_dispatch.nim19
-rw-r--r--tests/caas/issue_477_dynamic_dispatch.txt5
-rw-r--r--tests/caas/its_full_of_procs.nim29
-rw-r--r--tests/caas/its_full_of_procs.txt20
-rw-r--r--tests/caas/main.nim7
-rw-r--r--tests/caas/main_dirty.nim14
-rw-r--r--tests/caas/suggest-compile.txt13
-rw-r--r--tests/caas/suggest-invalid-source.txt26
-rw-r--r--tests/casestmt/tcase_arrayconstr.nim19
-rw-r--r--tests/casestmt/tcase_emptyset_when.nim24
-rw-r--r--tests/casestmt/tcase_setconstr.nim15
-rw-r--r--tests/casestmt/tcaseexpr1.nim30
-rw-r--r--tests/casestmt/tcaseoverlaprange.nim15
-rw-r--r--tests/casestmt/tcaseoverlaprange2.nim18
-rw-r--r--tests/casestmt/tcasestm.nim40
-rw-r--r--tests/casestmt/tcomputedgoto.nim48
-rw-r--r--tests/casestmt/tlinearscanend.nim24
-rw-r--r--tests/ccgbugs/tarray_equality.nim15
-rw-r--r--tests/ccgbugs/tbug1081.nim17
-rw-r--r--tests/ccgbugs/tccgen1.nim67
-rw-r--r--tests/ccgbugs/tcgbug.nim38
-rw-r--r--tests/ccgbugs/tcodegenbug1.nim67
-rw-r--r--tests/ccgbugs/tconstobj.nim16
-rw-r--r--tests/ccgbugs/tcvarargs.nim34
-rw-r--r--tests/ccgbugs/tmissingbracket.nim52
-rw-r--r--tests/ccgbugs/tmissingderef.nim30
-rw-r--r--tests/ccgbugs/tmissinginit.nim30
-rw-r--r--tests/ccgbugs/tmissingvolatile.nim20
-rw-r--r--tests/ccgbugs/tpartialcs.nim20
-rw-r--r--tests/ccgbugs/trecursive_closure.nim8
-rw-r--r--tests/ccgbugs/trecursive_table.nim17
-rw-r--r--tests/ccgbugs/tstringslice.nim24
-rw-r--r--tests/ccgbugs/tuple_canon.nim80
-rw-r--r--tests/ccgbugs/twrong_tupleconv.nim20
-rw-r--r--tests/clearmsg/mb.nim2
-rw-r--r--tests/clearmsg/mc.nim3
-rw-r--r--tests/clearmsg/ta.nim12
-rw-r--r--tests/clearmsg/tconsttypemismatch.nim8
-rw-r--r--tests/closure/tclosure.nim47
-rw-r--r--tests/closure/tclosure2.nim101
-rw-r--r--tests/closure/tclosure3.nim20
-rw-r--r--tests/closure/tclosure4.nim13
-rw-r--r--tests/closure/tclosurebug2.nim194
-rw-r--r--tests/closure/tfib50.nim22
-rw-r--r--tests/closure/tforum.nim44
-rw-r--r--tests/closure/tinterf.nim24
-rw-r--r--tests/closure/tinvalidclosure.nim12
-rw-r--r--tests/closure/tinvalidclosure2.nim14
-rw-r--r--tests/closure/tissue1642.nim7
-rw-r--r--tests/closure/tjester.nim32
-rw-r--r--tests/closure/tnamedparamanonproc.nim14
-rw-r--r--tests/closure/tnestedclosure.nim51
-rw-r--r--tests/closure/tnestedproc.nim12
-rw-r--r--tests/closure/ttimeinfo.nim15
-rw-r--r--tests/closure/uclosures.nim12
-rw-r--r--tests/cnstseq/tcnstseq.nim17
-rw-r--r--tests/cnstseq/tcnstseq2.nim12
-rw-r--r--tests/cnstseq/tcnstseq3.nim7
-rw-r--r--tests/collections/tcounttable.nim19
-rw-r--r--tests/collections/tindexby.nim22
-rw-r--r--tests/collections/tsets.nim37
-rw-r--r--tests/collections/ttableconstr.nim16
-rw-r--r--tests/collections/ttables.nim154
-rw-r--r--tests/collections/ttables2.nim30
-rw-r--r--tests/collections/ttablesref.nim144
-rw-r--r--tests/collections/ttablesref2.nim20
-rw-r--r--tests/compiles/tcompiles.nim28
-rw-r--r--tests/compiles/tevilcompiles.nim12
-rw-r--r--tests/concat/tconcat.nim11
-rw-r--r--tests/concepts/mvarconcept.nim13
-rw-r--r--tests/concepts/tmanual.nim43
-rw-r--r--tests/concepts/tswizzle.nim80
-rw-r--r--tests/concepts/tusertypeclasses.nim68
-rw-r--r--tests/concepts/tusertypeclasses2.nim24
-rw-r--r--tests/concepts/tvarconcept.nim9
-rw-r--r--tests/constr/tconstr1.nim30
-rw-r--r--tests/constr/tconstr2.nim26
-rw-r--r--tests/constraints/tconstraints.nim18
-rw-r--r--tests/controlflow/tblock1.nim18
-rw-r--r--tests/controlflow/tbreak.nim44
-rw-r--r--tests/controlflow/tcontinue.nim28
-rw-r--r--tests/controlflow/tnestif.nim24
-rw-r--r--tests/controlflow/tstatret.nim12
-rw-r--r--tests/converter/tconvcolors.nim5
-rw-r--r--tests/converter/tconvert.nim20
-rw-r--r--tests/converter/tgenericconverter.nim30
-rw-r--r--tests/converter/ttypeconverter1.nim15
-rw-r--r--tests/cpp/tcppraise.nim17
-rw-r--r--tests/cpp/tget_subsystem.nim23
-rw-r--r--tests/cpp/trawsockets.nim5
-rw-r--r--tests/cpp/tstaticvar_via_typedesc.nim20
-rw-r--r--tests/cpp/tthread_createthread.nim14
-rw-r--r--tests/cpp/ttypeinfo.nim5
-rw-r--r--tests/cpp/tvector_iterator.nim19
-rw-r--r--tests/cpp/tvectorseq.nim38
-rw-r--r--tests/defaultprocparam/mdefaultprocparam.nim5
-rw-r--r--tests/defaultprocparam/tdefaultprocparam.nim4
-rw-r--r--tests/deprecated/tdeprecated.nim9
-rw-r--r--tests/destructor/tdestructor.nim130
-rw-r--r--tests/destructor/tdestructor2.nim27
-rw-r--r--tests/destructor/tdictdestruct.nim20
-rw-r--r--tests/dir with space/tspace.nim3
-rw-r--r--tests/discard/tdiscardable.nim29
-rw-r--r--tests/discard/tneedsdiscard.nim12
-rw-r--r--tests/distinct/tborrowdot.nim13
-rw-r--r--tests/distinct/tcurrncy.nim38
-rw-r--r--tests/distinct/tdistinct_consts.nim20
-rw-r--r--tests/dll/client.nim41
-rw-r--r--tests/dll/client.nim.cfg1
-rw-r--r--tests/dll/server.nim34
-rw-r--r--tests/dll/server.nim.cfg2
-rw-r--r--tests/effects/teffects1.nim20
-rw-r--r--tests/effects/teffects2.nim20
-rw-r--r--tests/effects/teffects3.nim19
-rw-r--r--tests/effects/teffects4.nim24
-rw-r--r--tests/effects/teffects5.nim14
-rw-r--r--tests/effects/teffects6.nim31
-rw-r--r--tests/effects/tgcsafe.nim17
-rw-r--r--tests/effects/tsidee1.nim18
-rw-r--r--tests/effects/tsidee2.nim17
-rw-r--r--tests/effects/tsidee3.nim17
-rw-r--r--tests/effects/tsidee4.nim17
-rw-r--r--tests/enum/tenum.nim8
-rw-r--r--tests/enum/tenum2.nim16
-rw-r--r--tests/enum/tenum3.nim16
-rw-r--r--tests/enum/tenumhole.nim25
-rw-r--r--tests/enum/tenumitems.nim9
-rw-r--r--tests/enum/tenumitems2.nim14
-rw-r--r--tests/enum/tenummix.nim11
-rw-r--r--tests/enum/tnamedenumfields.nim23
-rw-r--r--tests/enum/toptions.nim18
-rw-r--r--tests/exception/tcontinuexc.nim30
-rw-r--r--tests/exception/tdefer1.nim18
-rw-r--r--tests/exception/texceptionbreak.nim45
-rw-r--r--tests/exception/texceptions.nim66
-rw-r--r--tests/exception/texcpt1.nim30
-rw-r--r--tests/exception/texcsub.nim17
-rw-r--r--tests/exception/tfinally.nim19
-rw-r--r--tests/exception/tfinally2.nim30
-rw-r--r--tests/exception/tfinally3.nim18
-rw-r--r--tests/exception/tfinally4.nim40
-rw-r--r--tests/exception/tnestedreturn.nim40
-rw-r--r--tests/exception/tnestedreturn2.nim20
-rw-r--r--tests/exception/tonraise.nim34
-rw-r--r--tests/exception/treraise.nim24
-rw-r--r--tests/exception/tunhandledexc.nim23
-rw-r--r--tests/exception/twrongexc.nim13
-rw-r--r--tests/exprs/texprstmt.nim12
-rw-r--r--tests/exprs/thighCString.nim6
-rw-r--r--tests/exprs/tifexpr_typeinference.nim20
-rw-r--r--tests/exprs/tresultwarning.nim6
-rw-r--r--tests/exprs/tstmtexp.nim9
-rw-r--r--tests/exprs/tstmtexprs.nim124
-rw-r--r--tests/fields/tfieldindex.nim21
-rw-r--r--tests/fields/tfielditerator.nim46
-rw-r--r--tests/fields/tfielditerator2.nim70
-rw-r--r--tests/fields/tfields_in_template.nim15
-rw-r--r--tests/fields/tfields_with_break.nim33
-rw-r--r--tests/float/tfloat1.nim15
-rw-r--r--tests/float/tfloat2.nim15
-rw-r--r--tests/float/tfloat3.nim24
-rw-r--r--tests/float/tfloat4.nim42
-rw-r--r--tests/friends/mfriends.nim11
-rw-r--r--tests/friends/tfriends.nim11
-rw-r--r--tests/gc/bintrees.nim54
-rw-r--r--tests/gc/closureleak.nim33
-rw-r--r--tests/gc/cyclecollector.nim21
-rw-r--r--tests/gc/cycleleak.nim56
-rw-r--r--tests/gc/gcbench.nim168
-rw-r--r--tests/gc/gcleak.nim23
-rw-r--r--tests/gc/gcleak2.nim28
-rw-r--r--tests/gc/gcleak3.nim30
-rw-r--r--tests/gc/gcleak4.nim51
-rw-r--r--tests/gc/gcleak5.nim25
-rw-r--r--tests/gc/gctest.nim203
-rw-r--r--tests/gc/growobjcrash.nim29
-rw-r--r--tests/gc/refarrayleak.nim39
-rw-r--r--tests/gc/stackrefleak.nim31
-rw-r--r--tests/gc/weakrefs.nim50
-rw-r--r--tests/generics/mdotlookup.nim16
-rw-r--r--tests/generics/t1050.nim16
-rw-r--r--tests/generics/t1056.nim25
-rw-r--r--tests/generics/t1789.nim44
-rw-r--r--tests/generics/tableref_is_nil.nim9
-rw-r--r--tests/generics/tarray_with_somenumber.nim11
-rw-r--r--tests/generics/tbadgenericlambda.nim7
-rw-r--r--tests/generics/tbintre2.nim31
-rw-r--r--tests/generics/tbintree.nim107
-rw-r--r--tests/generics/tcan_alias_generic.nim11
-rw-r--r--tests/generics/tcan_alias_specialised_generic.nim17
-rw-r--r--tests/generics/tcan_inherit_generic.nim17
-rw-r--r--tests/generics/tcan_specialise_generic.nim11
-rw-r--r--tests/generics/tcannot_pass_empty_seq_to_generic.nim17
-rw-r--r--tests/generics/tconfusing_arrow.nim15
-rw-r--r--tests/generics/tdotlookup.nim10
-rw-r--r--tests/generics/texplicitgeneric1.nim38
-rw-r--r--tests/generics/texplicitgeneric2.nim35
-rw-r--r--tests/generics/tforwardgeneric.nim14
-rw-r--r--tests/generics/tgeneric0.nim27
-rw-r--r--tests/generics/tgeneric1.nim53
-rw-r--r--tests/generics/tgeneric2.nim15
-rw-r--r--tests/generics/tgeneric3.nim474
-rw-r--r--tests/generics/tgeneric4.nim10
-rw-r--r--tests/generics/tgeneric_closure.nim37
-rw-r--r--tests/generics/tgeneric_inheritance.nim19
-rw-r--r--tests/generics/tgenericdefaults.nim29
-rw-r--r--tests/generics/tgenericlambda.nim23
-rw-r--r--tests/generics/tgenericmatcher.nim22
-rw-r--r--tests/generics/tgenericmatcher2.nim18
-rw-r--r--tests/generics/tgenericprocvar.nim36
-rw-r--r--tests/generics/tgenericprop.nim12
-rw-r--r--tests/generics/tgenericrefs.nim38
-rw-r--r--tests/generics/tgenericshardcases.nim42
-rw-r--r--tests/generics/tgenerictmpl.nim12
-rw-r--r--tests/generics/tgenericvariant.nim23
-rw-r--r--tests/generics/tinferredgenericprocs.nim20
-rw-r--r--tests/generics/tlateboundstatic.nim16
-rw-r--r--tests/generics/tmetafield.nim18
-rw-r--r--tests/generics/tsigtypeop.nim9
-rw-r--r--tests/generics/tspecialised_is_equivalent.nim15
-rw-r--r--tests/generics/tsubtypeconstraint.nim13
-rw-r--r--tests/generics/tthread_generic.nim39
-rw-r--r--tests/generics/tunique_type.nim67
-rw-r--r--tests/generics/tvarargs_vs_generic.nim26
-rw-r--r--tests/generics/twrong_field_caching.nim68
-rw-r--r--tests/generics/twrong_floatlit_type.nim118
-rw-r--r--tests/generics/twrong_generic_object.nim21
-rw-r--r--tests/gensym/tgensym.nim16
-rw-r--r--tests/gensym/tgensymgeneric.nim31
-rw-r--r--tests/global/globalaux.nim15
-rw-r--r--tests/global/globalaux2.nim4
-rw-r--r--tests/global/tglobal.nim16
-rw-r--r--tests/global/tglobalforvar.nim7
-rw-r--r--tests/implicit/timplicititems.nim4
-rw-r--r--tests/implicit/timplictderef.nim35
-rw-r--r--tests/init/tuninit1.nim36
-rw-r--r--tests/init/tuninit2.nim54
-rw-r--r--tests/init/tzeroarray.nim18
-rw-r--r--tests/iter/tanoniter1.nim32
-rw-r--r--tests/iter/tchainediterators.nim41
-rw-r--r--tests/iter/tconcat.nim24
-rw-r--r--tests/iter/tcountup.nim14
-rw-r--r--tests/iter/timplicit_auto.nim18
-rw-r--r--tests/iter/titer.nim44
-rw-r--r--tests/iter/titer2.nim57
-rw-r--r--tests/iter/titer3.nim22
-rw-r--r--tests/iter/titer4.nim10
-rw-r--r--tests/iter/titer5.nim16
-rw-r--r--tests/iter/titer6.nim37
-rw-r--r--tests/iter/titer7.nim57
-rw-r--r--tests/iter/titer8.nim117
-rw-r--r--tests/iter/titer9.nim20
-rw-r--r--tests/iter/titer_no_tuple_unpack.nim13
-rw-r--r--tests/iter/titerable.nim26
-rw-r--r--tests/iter/titerovl.nim21
-rw-r--r--tests/iter/titerslice.nim9
-rw-r--r--tests/iter/titervaropenarray.nim16
-rw-r--r--tests/iter/tmoditer.nim29
-rw-r--r--tests/iter/tobj_iter.nim20
-rw-r--r--tests/iter/treciter.nim14
-rw-r--r--tests/iter/tscheduler.nim76
-rw-r--r--tests/iter/tshallowcopy_closures.nim31
-rw-r--r--tests/iter/twrongiter.nim13
-rw-r--r--tests/js.html21
-rw-r--r--tests/js.nim24
-rw-r--r--tests/js/taddr.nim36
-rw-r--r--tests/js/tbyvar.nim33
-rw-r--r--tests/js/test1.nim22
-rw-r--r--tests/js/test2.nim31
-rw-r--r--tests/js/testmagic.nim9
-rw-r--r--tests/js/testobjs.nim34
-rw-r--r--tests/js/tfloatround.nim7
-rw-r--r--tests/js/tobjfieldbyvar.nim20
-rw-r--r--tests/js/tstringitems.nim24
-rw-r--r--tests/js/tunittests.nim12
-rw-r--r--tests/let/tlet.nim11
-rw-r--r--tests/let/tlet2.nim16
-rw-r--r--tests/lexer/thexlit.nim12
-rw-r--r--tests/lexer/thexrange.nim8
-rw-r--r--tests/lexer/tident.nim22
-rw-r--r--tests/lexer/tind1.nim27
-rw-r--r--tests/lexer/tindent1.nim42
-rw-r--r--tests/lexer/tlexer.nim60
-rw-r--r--tests/lexer/tmissingnl.nim10
-rw-r--r--tests/lexer/tstrlits.nim20
-rw-r--r--tests/lexer/tunderscores.nim14
-rw-r--r--tests/lookups/tkoeniglookup.nim17
-rw-r--r--tests/lookups/tredef.nim29
-rw-r--r--tests/macros/macro_bug.nim17
-rw-r--r--tests/macros/tbindsym.nim25
-rw-r--r--tests/macros/tbugs.nim90
-rw-r--r--tests/macros/tclosuremacro.nim43
-rw-r--r--tests/macros/tdebugstmt.nim29
-rw-r--r--tests/macros/tdumpast.nim33
-rw-r--r--tests/macros/tdumpast2.nim36
-rw-r--r--tests/macros/tdumptree.nim26
-rw-r--r--tests/macros/texprcolonexpr.nim19
-rw-r--r--tests/macros/tgensym.nim63
-rw-r--r--tests/macros/tgentemplates.nim35
-rw-r--r--tests/macros/tgettype.nim20
-rw-r--r--tests/macros/tidgen.nim19
-rw-r--r--tests/macros/tlexerex.nim16
-rw-r--r--tests/macros/tmacro1.nim23
-rw-r--r--tests/macros/tmacro2.nim28
-rw-r--r--tests/macros/tmacro3.nim31
-rw-r--r--tests/macros/tmacro4.nim19
-rw-r--r--tests/macros/tmacro5.nim59
-rw-r--r--tests/macros/tmacro_in_template.nim10
-rw-r--r--tests/macros/tmacroaspragma.nim8
-rw-r--r--tests/macros/tmacrogenerics.nim37
-rw-r--r--tests/macros/tmacros1.nim31
-rw-r--r--tests/macros/tmacrostmt.nim26
-rw-r--r--tests/macros/tmacrotypes.nim16
-rw-r--r--tests/macros/tmemit.nim21
-rw-r--r--tests/macros/tnimnode_for_runtime.nim12
-rw-r--r--tests/macros/tprintf.nim16
-rw-r--r--tests/macros/tquotewords.nim26
-rw-r--r--tests/macros/trecmacro.nim14
-rw-r--r--tests/macros/treturnsempty.nim12
-rw-r--r--tests/macros/tsame_name_497.nim9
-rw-r--r--tests/macros/tstringinterp.nim74
-rw-r--r--tests/macros/ttryparseexpr.nim20
-rw-r--r--tests/macros/tvarnimnode.nim19
-rw-r--r--tests/macros/tvtable.nim74
-rw-r--r--tests/macros/typesapi.nim17
-rw-r--r--tests/macros/typesapi2.nim49
-rw-r--r--tests/magics/tlowhigh.nim24
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim494
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim87
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim.cfg1
-rw-r--r--tests/manyloc/keineschweine/README.md26
-rw-r--r--tests/manyloc/keineschweine/TODO.md21
-rw-r--r--tests/manyloc/keineschweine/client_settings.json10
-rw-r--r--tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim1515
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/enet.nim613
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/testclient.nim49
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/testserver.nim45
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim295
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim287
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim64
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim47
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nake.nim83
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nakefile.nim23
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/README.md13
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml.nim1121
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim899
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim15
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim2
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_client.nim229
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_server.nim294
-rw-r--r--tests/manyloc/keineschweine/enet_server/nakefile.nim13
-rw-r--r--tests/manyloc/keineschweine/enet_server/nim.cfg9
-rw-r--r--tests/manyloc/keineschweine/enet_server/server_settings.json8
-rw-r--r--tests/manyloc/keineschweine/enet_server/server_utils.nim120
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim725
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim.cfg9
-rw-r--r--tests/manyloc/keineschweine/lib/animations.nim75
-rw-r--r--tests/manyloc/keineschweine/lib/client_helpers.nim142
-rw-r--r--tests/manyloc/keineschweine/lib/estreams.nim122
-rw-r--r--tests/manyloc/keineschweine/lib/game_objects.nim34
-rw-r--r--tests/manyloc/keineschweine/lib/gl.nim1536
-rw-r--r--tests/manyloc/keineschweine/lib/glext.nim4673
-rw-r--r--tests/manyloc/keineschweine/lib/glu.nim335
-rw-r--r--tests/manyloc/keineschweine/lib/glut.nim438
-rw-r--r--tests/manyloc/keineschweine/lib/glx.nim153
-rw-r--r--tests/manyloc/keineschweine/lib/idgen.nim23
-rw-r--r--tests/manyloc/keineschweine/lib/input_helpers.nim138
-rw-r--r--tests/manyloc/keineschweine/lib/map_filter.nim41
-rw-r--r--tests/manyloc/keineschweine/lib/math_helpers.nim10
-rw-r--r--tests/manyloc/keineschweine/lib/sfml_stuff.nim37
-rw-r--r--tests/manyloc/keineschweine/lib/sg_assets.nim610
-rw-r--r--tests/manyloc/keineschweine/lib/sg_gui.nim281
-rw-r--r--tests/manyloc/keineschweine/lib/sg_packets.nim108
-rw-r--r--tests/manyloc/keineschweine/lib/sound_buffer.nim38
-rw-r--r--tests/manyloc/keineschweine/lib/vehicles.nim35
-rw-r--r--tests/manyloc/keineschweine/lib/wingl.nim368
-rw-r--r--tests/manyloc/keineschweine/lib/zlib_helpers.nim40
-rw-r--r--tests/manyloc/keineschweine/server/dirserver_settings.json7
-rw-r--r--tests/manyloc/keineschweine/server/nim.cfg6
-rw-r--r--tests/manyloc/keineschweine/server/old_dirserver.nim201
-rw-r--r--tests/manyloc/keineschweine/server/old_server_utils.nim98
-rw-r--r--tests/manyloc/keineschweine/server/old_sg_server.nim254
-rw-r--r--tests/manyloc/keineschweine/server/sg_lobby.nim267
-rw-r--r--tests/manyloc/nake/nake.nim83
-rw-r--r--tests/manyloc/nake/nakefile.nim155
-rw-r--r--tests/manyloc/nake/nakefile.nim.cfg1
-rw-r--r--tests/manyloc/named_argument_bug/gui.nim44
-rw-r--r--tests/manyloc/named_argument_bug/main.nim23
-rw-r--r--tests/manyloc/named_argument_bug/main.nim.cfg2
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/config.nim6
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim58
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim61
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim157
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim103
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim31
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/circle.nim9
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/rect.nim8
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/vec.nim55
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim106
-rw-r--r--tests/manyloc/packages/noconflicts.nim16
-rw-r--r--tests/manyloc/packages/noconflicts.nim.cfg1
-rw-r--r--tests/manyloc/packages/os.nim5
-rw-r--r--tests/manyloc/packages/package1/p1.babel0
-rw-r--r--tests/manyloc/packages/package1/strutils.nim5
-rw-r--r--tests/manyloc/packages/package2/p2.babel0
-rw-r--r--tests/manyloc/packages/package2/strutils.nim5
-rw-r--r--tests/manyloc/standalone/barebone.nim9
-rw-r--r--tests/manyloc/standalone/barebone.nim.cfg2
-rw-r--r--tests/manyloc/standalone/panicoverride.nim19
-rw-r--r--tests/metatype/tautonotgeneric.nim15
-rw-r--r--tests/metatype/tautoproc.nim22
-rw-r--r--tests/metatype/tbindtypedesc.nim88
-rw-r--r--tests/metatype/tcompositetypeclasses.nim59
-rw-r--r--tests/metatype/tconstraints.nim15
-rw-r--r--tests/metatype/tmatrix.nim48
-rw-r--r--tests/metatype/tmatrix1.nim19
-rw-r--r--tests/metatype/tmatrix2.nim22
-rw-r--r--tests/metatype/tmatrix3.nim19
-rw-r--r--tests/metatype/tsemistatic.nim31
-rw-r--r--tests/metatype/tstatic_overloading.nim10
-rw-r--r--tests/metatype/tstaticparammacro.nim75
-rw-r--r--tests/metatype/tstaticparams.nim142
-rw-r--r--tests/metatype/tstaticvector.nim17
-rw-r--r--tests/metatype/ttypebar.nim14
-rw-r--r--tests/metatype/ttypeclasses.nim70
-rw-r--r--tests/metatype/ttypedesc1.nim42
-rw-r--r--tests/metatype/ttypedesc2.nim37
-rw-r--r--tests/metatype/ttypedesc3.nim19
-rw-r--r--tests/metatype/ttypeselectors.nim39
-rw-r--r--tests/metatype/ttypetraits.nim60
-rw-r--r--tests/metatype/tymatrix.nim23
-rw-r--r--tests/metatype/typeclassinference.nim22
-rw-r--r--tests/metatype/typedesc_as_value.nim11
-rw-r--r--tests/metatype/utypeclasses.nim13
-rw-r--r--tests/method/mmultim3.nim12
-rw-r--r--tests/method/temptybody.nim11
-rw-r--r--tests/method/tmethod.nim8
-rw-r--r--tests/method/tmethods1.nim22
-rw-r--r--tests/method/tmproto.nim25
-rw-r--r--tests/method/tmultim1.nim29
-rw-r--r--tests/method/tmultim2.nim39
-rw-r--r--tests/method/tmultim3.nim20
-rw-r--r--tests/method/tmultim4.nim47
-rw-r--r--tests/method/tmultim6.nim30
-rw-r--r--tests/method/trecmeth.nim22
-rw-r--r--tests/method/tsimmeth.nim14
-rw-r--r--tests/misc/99bottles.nim1
-rw-r--r--tests/misc/minit.nim2
-rw-r--r--tests/misc/mvarious.nim6
-rw-r--r--tests/misc/parsecomb.nim105
-rw-r--r--tests/misc/t99bott.nim36
-rw-r--r--tests/misc/tack.nim21
-rw-r--r--tests/misc/tatomic.nim12
-rw-r--r--tests/misc/tbug1217bracketquotes.nim14
-rw-r--r--tests/misc/tbug511622.nim16
-rw-r--r--tests/misc/tcharinc.nim10
-rw-r--r--tests/misc/tcmdline.nim14
-rw-r--r--tests/misc/tcolonisproc.nim13
-rw-r--r--tests/misc/tdllvar.nim16
-rw-r--r--tests/misc/temit.nim20
-rw-r--r--tests/misc/temptyecho.nim2
-rw-r--r--tests/misc/tendian.nim3
-rw-r--r--tests/misc/teventemitter.nim33
-rw-r--r--tests/misc/tevents.nim48
-rw-r--r--tests/misc/tfib.nim11
-rw-r--r--tests/misc/tfilter.nim41
-rw-r--r--tests/misc/tgenconstraints.nim32
-rw-r--r--tests/misc/tgetstartmilsecs.nim7
-rw-r--r--tests/misc/thallo.nim85
-rw-r--r--tests/misc/theaproots.nim71
-rw-r--r--tests/misc/thintoff.nim12
-rw-r--r--tests/misc/tinc.nim12
-rw-r--r--tests/misc/tinit.nim12
-rw-r--r--tests/misc/tinout.nim16
-rw-r--r--tests/misc/tints.nim54
-rw-r--r--tests/misc/tinvalidarrayaccess.nim14
-rw-r--r--tests/misc/tinvalidnewseq.nim27
-rw-r--r--tests/misc/tissue710.nim10
-rw-r--r--tests/misc/tlastmod.nim18
-rw-r--r--tests/misc/tlocals.nim11
-rw-r--r--tests/misc/tloops.nim87
-rw-r--r--tests/misc/tmandelbrot.nim57
-rw-r--r--tests/misc/tmemoization.nim17
-rw-r--r--tests/misc/tmissingnilcheck.nim20
-rw-r--r--tests/misc/tnew.nim49
-rw-r--r--tests/misc/tnewderef.nim11
-rw-r--r--tests/misc/tnewsets.nim6
-rw-r--r--tests/misc/tnewuns.nim12
-rw-r--r--tests/misc/tnoforward.nim14
-rw-r--r--tests/misc/tnoinst.nim17
-rw-r--r--tests/misc/tnolen.nim9
-rw-r--r--tests/misc/tnoop.nim11
-rw-r--r--tests/misc/tnot.nim22
-rw-r--r--tests/misc/tparedef.nim4
-rw-r--r--tests/misc/tparsecombnum.nim55
-rw-r--r--tests/misc/tpos.nim35
-rw-r--r--tests/misc/tprep.nim30
-rw-r--r--tests/misc/tquicksort.nim26
-rw-r--r--tests/misc/tradix.nim319
-rw-r--r--tests/misc/trangechecks.nim43
-rw-r--r--tests/misc/trawstr.nim12
-rw-r--r--tests/misc/treadln.nim12
-rw-r--r--tests/misc/treadx.nim14
-rw-r--r--tests/misc/tromans.nim71
-rw-r--r--tests/misc/tshadow_magic_type.nim24
-rw-r--r--tests/misc/tsimplesort.nim309
-rw-r--r--tests/misc/tsimtych.nim12
-rw-r--r--tests/misc/tsizeof.nim10
-rw-r--r--tests/misc/tslices.nim59
-rw-r--r--tests/misc/tsortdev.nim59
-rw-r--r--tests/misc/tstrace.nim16
-rw-r--r--tests/misc/tstrange.nim28
-rw-r--r--tests/misc/tstrdesc.nim14
-rw-r--r--tests/misc/tstrdist.nim26
-rw-r--r--tests/misc/tunsigned64mod.nim26
-rw-r--r--tests/misc/tunsignedcmp.nim15
-rw-r--r--tests/misc/tunsignedcomp.nim136
-rw-r--r--tests/misc/tunsignedconv.nim43
-rw-r--r--tests/misc/tunsignedinc.nim14
-rw-r--r--tests/misc/tvarious.nim68
-rw-r--r--tests/misc/tvarious1.nim48
-rw-r--r--tests/misc/tvarnums.nim142
-rw-r--r--tests/mmaptest.nim48
-rw-r--r--tests/modules/mexport2a.nim7
-rw-r--r--tests/modules/mexport2b.nim3
-rw-r--r--tests/modules/mexporta.nim8
-rw-r--r--tests/modules/mexportb.nim7
-rw-r--r--tests/modules/mnamspc1.nim2
-rw-r--r--tests/modules/mnamspc2.nim3
-rw-r--r--tests/modules/mopaque.nim7
-rw-r--r--tests/modules/mrecmod.nim1
-rw-r--r--tests/modules/mrecmod2.nim9
-rw-r--r--tests/modules/texport.nim13
-rw-r--r--tests/modules/texport2.nim11
-rw-r--r--tests/modules/timportexcept.nim10
-rw-r--r--tests/modules/tmismatchedvisibility.nim9
-rw-r--r--tests/modules/tnamspc.nim12
-rw-r--r--tests/modules/topaque.nim18
-rw-r--r--tests/modules/trecinca.nim12
-rw-r--r--tests/modules/trecincb.nim13
-rw-r--r--tests/modules/trecmod.nim2
-rw-r--r--tests/modules/trecmod2.nim10
-rw-r--r--tests/modules/tselfimport.nim9
-rw-r--r--tests/namedparams/tnamedparams.nim15
-rw-r--r--tests/namedparams/tnamedparams2.nim8
-rw-r--r--tests/notnil/tnotnil.nim23
-rw-r--r--tests/notnil/tnotnil1.nim40
-rw-r--r--tests/notnil/tnotnil2.nim24
-rw-r--r--tests/notnil/tnotnil3.nim35
-rw-r--r--tests/notnil/tnotnil4.nim20
-rw-r--r--tests/notnil/tnotnil_in_generic.nim27
-rw-r--r--tests/notnil/tnotnil_in_objconstr.nim14
-rw-r--r--tests/objects/tillegal_recursion.nim7
-rw-r--r--tests/objects/tinherentedvalues.nim55
-rw-r--r--tests/objects/tobjconstr.nim41
-rw-r--r--tests/objects/tobjconstr2.nim50
-rw-r--r--tests/objects/tobjcov.nim17
-rw-r--r--tests/objects/tobject.nim15
-rw-r--r--tests/objects/tobject2.nim21
-rw-r--r--tests/objects/tobject3.nim59
-rw-r--r--tests/objects/tobjects.nim52
-rw-r--r--tests/objects/tobjloop.nim15
-rw-r--r--tests/objects/tobjpragma.nim52
-rw-r--r--tests/objects/tofopr.nim26
-rw-r--r--tests/objects/toop.nim21
-rw-r--r--tests/objects/toop1.nim86
-rw-r--r--tests/objects/trefobjsyntax.nim27
-rw-r--r--tests/objects/trefobjsyntax2.nim19
-rw-r--r--tests/objvariant/tadrdisc.nim20
-rw-r--r--tests/objvariant/tcheckedfield1.nim60
-rw-r--r--tests/objvariant/temptycaseobj.nim14
-rw-r--r--tests/objvariant/treassign.nim27
-rw-r--r--tests/objvariant/tvariantstack.nim52
-rw-r--r--tests/objvariant/tyaoption.nim47
-rw-r--r--tests/openarray/topena1.nim12
-rw-r--r--tests/openarray/topenarrayrepr.nim17
-rw-r--r--tests/openarray/topenlen.nim18
-rw-r--r--tests/osproc/ta.nim3
-rw-r--r--tests/osproc/tstdin.nim19
-rw-r--r--tests/overflw/toverflw.nim21
-rw-r--r--tests/overflw/toverflw2.nim10
-rw-r--r--tests/overflw/tovfint.nim23
-rw-r--r--tests/overload/tissue966.nim12
-rw-r--r--tests/overload/toverl.nim13
-rw-r--r--tests/overload/toverl2.nim33
-rw-r--r--tests/overload/toverl3.nim20
-rw-r--r--tests/overload/toverl4.nim77
-rw-r--r--tests/overload/toverprc.nim45
-rw-r--r--tests/overload/toverwr.nim13
-rw-r--r--tests/overload/tparams_after_varargs.nim17
-rw-r--r--tests/overload/tprefer_specialized_generic.nim22
-rw-r--r--tests/overload/tprefer_tygenericinst.nim42
-rw-r--r--tests/overload/tspec.nim118
-rw-r--r--tests/overload/tstmtoverload.nim38
-rw-r--r--tests/overload/tsymtabchange_during_or.nim24
-rw-r--r--tests/overload/tsystemcmp.nim22
-rw-r--r--tests/parallel/nim.cfg1
-rw-r--r--tests/parallel/t5000.nim25
-rw-r--r--tests/parallel/tarray_of_channels.nim26
-rw-r--r--tests/parallel/tconvexhull.nim64
-rw-r--r--tests/parallel/tdeepcopy.nim18
-rw-r--r--tests/parallel/tdeepcopy2.nim35
-rw-r--r--tests/parallel/tdisjoint_slice1.nim21
-rw-r--r--tests/parallel/tdisjoint_slice2.nim33
-rw-r--r--tests/parallel/tdont_be_stupid.nim15
-rw-r--r--tests/parallel/tflowvar.nim36
-rw-r--r--tests/parallel/tforstmt.nim25
-rw-r--r--tests/parallel/tgc_unsafe.nim32
-rw-r--r--tests/parallel/tgc_unsafe2.nim39
-rw-r--r--tests/parallel/tguard1.nim37
-rw-r--r--tests/parallel/tguard2.nim27
-rw-r--r--tests/parallel/tinvalid_array_bounds.nim25
-rw-r--r--tests/parallel/tinvalid_counter_usage.nim26
-rw-r--r--tests/parallel/tlet_spawn.nim14
-rw-r--r--tests/parallel/tmissing_deepcopy.nim40
-rw-r--r--tests/parallel/tnon_disjoint_slice1.nim25
-rw-r--r--tests/parallel/tpi.nim26
-rw-r--r--tests/parallel/treadafterwrite.nim31
-rw-r--r--tests/parallel/tsimple_array_checks.nim41
-rw-r--r--tests/parallel/tsysspawn.nim31
-rw-r--r--tests/parallel/tsysspawnbadarg.nim9
-rw-r--r--tests/parallel/tuseafterdef.nim31
-rw-r--r--tests/parallel/twrong_refcounts.nim53
-rw-r--r--tests/parser/tcommand_as_expr.nim26
-rw-r--r--tests/parser/tdomulttest.nim17
-rw-r--r--tests/parser/tinvcolonlocation1.nim12
-rw-r--r--tests/parser/tinvcolonlocation2.nim15
-rw-r--r--tests/parser/tinvcolonlocation3.nim12
-rw-r--r--tests/parser/tinvwhen.nim15
-rw-r--r--tests/parser/toprprec.nim39
-rw-r--r--tests/parser/tprecedence.nim15
-rw-r--r--tests/parser/tproctype_pragmas.nim19
-rw-r--r--tests/parser/tstrongspaces.nim83
-rw-r--r--tests/parser/ttupleunpack.nim35
-rw-r--r--tests/parser/ttypeof.nim26
-rw-r--r--tests/parser/twhen_in_enum.nim11
-rw-r--r--tests/pragmas/tpush.nim15
-rw-r--r--tests/pragmas/tuserpragma.nim7
-rw-r--r--tests/proc/tnestprc.nim16
-rw-r--r--tests/proc/tprocredef.nim9
-rw-r--r--tests/procvar/tgenericprocvar.nim5
-rw-r--r--tests/procvar/tprocvar.nim18
-rw-r--r--tests/procvar/tprocvar2.nim32
-rw-r--r--tests/procvar/tprocvars.nim6
-rw-r--r--tests/range/compilehelpers.nim6
-rw-r--r--tests/range/tbug499771.nim14
-rw-r--r--tests/range/tcolors.nim39
-rw-r--r--tests/range/tmatrix3.nim41
-rw-r--r--tests/range/tsubrange.nim21
-rw-r--r--tests/range/tsubrange2.nim17
-rw-r--r--tests/range/tsubrange3.nim18
-rw-r--r--tests/readme.txt13
-rw-r--r--tests/realtimeGC/cmain.c67
-rw-r--r--tests/realtimeGC/main.nim.cfg6
-rw-r--r--tests/realtimeGC/nmain.nim46
-rw-r--r--tests/realtimeGC/readme.txt21
-rw-r--r--tests/realtimeGC/shared.nim63
-rw-r--r--tests/realtimeGC/shared.nim.cfg5
-rw-r--r--tests/rectest.nim6
-rw-r--r--tests/rodfiles/aconv.nim9
-rw-r--r--tests/rodfiles/amethods.nim13
-rw-r--r--tests/rodfiles/bconv.nim9
-rw-r--r--tests/rodfiles/bmethods.nim29
-rw-r--r--tests/rodfiles/bmethods2.nim29
-rw-r--r--tests/rodfiles/deada.nim8
-rw-r--r--tests/rodfiles/deada2.nim12
-rw-r--r--tests/rodfiles/deadb.nim7
-rw-r--r--tests/rodfiles/deadg.nim10
-rw-r--r--tests/rodfiles/gtkex1.nim14
-rw-r--r--tests/rodfiles/gtkex2.nim22
-rw-r--r--tests/rodfiles/hallo.nim6
-rw-r--r--tests/rodfiles/hallo2.nim17
-rw-r--r--tests/rodfiles/int2bool.nim8
-rw-r--r--tests/rodfiles/nim.cfg2
-rw-r--r--tests/rodfiles/tgeneric1.nim13
-rw-r--r--tests/rodfiles/tgeneric2.nim13
-rw-r--r--tests/seq/tseq2.nim11
-rw-r--r--tests/seq/tseqcon.nim51
-rw-r--r--tests/seq/tseqcon2.nim9
-rw-r--r--tests/seq/tseqtuple.nim28
-rw-r--r--tests/seq/tsequtils.nim55
-rw-r--r--tests/seq/ttoseq.nim18
-rw-r--r--tests/sets/tsets.nim204
-rw-r--r--tests/sets/tsets2.nim61
-rw-r--r--tests/sets/tsets3.nim100
-rw-r--r--tests/sets/tsets_lt.nim12
-rw-r--r--tests/showoff/tdrdobbs_examples.nim134
-rw-r--r--tests/showoff/tformatopt.nim57
-rw-r--r--tests/showoff/thello2.nim11
-rw-r--r--tests/showoff/thtml1.nim11
-rw-r--r--tests/showoff/thtml2.nim37
-rw-r--r--tests/showoff/tonce.nim22
-rw-r--r--tests/showoff/tquasiquote.nim14
-rw-r--r--tests/specialops/tdotops.nim66
-rw-r--r--tests/stckovfl.nim10
-rw-r--r--tests/stdlib/talgorithm.nim11
-rw-r--r--tests/stdlib/tcount.nim29
-rw-r--r--tests/stdlib/tcputime.nim13
-rw-r--r--tests/stdlib/tcritbits.nim28
-rw-r--r--tests/stdlib/techo.nim3
-rw-r--r--tests/stdlib/testequivalence.nim14
-rw-r--r--tests/stdlib/tformat.nim12
-rw-r--r--tests/stdlib/tgetfileinfo.nim96
-rw-r--r--tests/stdlib/thashes.nim8
-rw-r--r--tests/stdlib/tio.nim7
-rw-r--r--tests/stdlib/tlists.nim66
-rw-r--r--tests/stdlib/tmarshal.nim77
-rw-r--r--tests/stdlib/tmath.nim61
-rw-r--r--tests/stdlib/tmath2.nim85
-rw-r--r--tests/stdlib/tmitems.nim136
-rw-r--r--tests/stdlib/tnet.nim47
-rw-r--r--tests/stdlib/tos.nim12
-rw-r--r--tests/stdlib/tosprocterminate.nim21
-rw-r--r--tests/stdlib/tparscfg.nim25
-rw-r--r--tests/stdlib/tparsopt.nim27
-rw-r--r--tests/stdlib/tpegs.nim1770
-rw-r--r--tests/stdlib/tpermutations.nim19
-rw-r--r--tests/stdlib/tposix.nim16
-rw-r--r--tests/stdlib/tquit.nim6
-rw-r--r--tests/stdlib/tregex.nim31
-rw-r--r--tests/stdlib/treguse.nim27
-rw-r--r--tests/stdlib/treloop.nim9
-rw-r--r--tests/stdlib/trepr.nim29
-rw-r--r--tests/stdlib/trepr2.nim32
-rw-r--r--tests/stdlib/tsinglylinkedring.nim29
-rw-r--r--tests/stdlib/tsortcall.nim5
-rw-r--r--tests/stdlib/tsplit.nim20
-rw-r--r--tests/stdlib/tstreams.nim7
-rw-r--r--tests/stdlib/tstrset.nim74
-rw-r--r--tests/stdlib/tstrtabs.nim12
-rw-r--r--tests/stdlib/tstrutil.nim58
-rw-r--r--tests/stdlib/ttime.nim6
-rw-r--r--tests/stdlib/tunidecode.nim12
-rw-r--r--tests/stdlib/twalker.nim13
-rw-r--r--tests/stdlib/txmlgen.nim12
-rw-r--r--tests/stdlib/txmltree.nim13
-rw-r--r--tests/system/alloc.nim52
-rw-r--r--tests/system/helpers/readall_echo.nim2
-rw-r--r--tests/system/io.nim25
-rw-r--r--tests/system/params.nim18
-rw-r--r--tests/system/tfloatToString.nim22
-rw-r--r--tests/system/toString.nim9
-rw-r--r--tests/system/tsettostring.nim8
-rw-r--r--tests/template/annotate.nim113
-rw-r--r--tests/template/mcan_access_hidden_field.nim9
-rw-r--r--tests/template/mtempl5.nim10
-rw-r--r--tests/template/otests.nim219
-rw-r--r--tests/template/sunset.tmpl68
-rw-r--r--tests/template/t2do.nim22
-rw-r--r--tests/template/t_otemplates.nim345
-rw-r--r--tests/template/tcan_access_hidden_field.nim9
-rw-r--r--tests/template/tdefault_nil.nim14
-rw-r--r--tests/template/texponential_eval.nim47
-rw-r--r--tests/template/thygienictempl.nim18
-rw-r--r--tests/template/tissue909.nim16
-rw-r--r--tests/template/tissue993.nim21
-rw-r--r--tests/template/tit.nim11
-rw-r--r--tests/template/tmodulealias.nim19
-rw-r--r--tests/template/tparams_gensymed.nim62
-rw-r--r--tests/template/tprefer_immediate.nim17
-rw-r--r--tests/template/tscope.nim12
-rw-r--r--tests/template/tstempl.nim24
-rw-r--r--tests/template/tstmt_semchecked_twice.nim30
-rw-r--r--tests/template/tsymchoicefield.nim12
-rw-r--r--tests/template/ttempl.nim27
-rw-r--r--tests/template/ttempl2.nim19
-rw-r--r--tests/template/ttempl3.nim58
-rw-r--r--tests/template/ttempl4.nim8
-rw-r--r--tests/template/ttempl5.nim29
-rw-r--r--tests/template/ttemplreturntype.nim4
-rw-r--r--tests/template/twrongmapit.nim32
-rw-r--r--tests/template/twrongopensymchoice.nim24
-rw-r--r--tests/template/utemplates.nim32
-rw-r--r--tests/testament/backend.nim121
-rw-r--r--tests/testament/caasdriver.nim195
-rw-r--r--tests/testament/categories.nim380
-rw-r--r--tests/testament/css/boilerplate.css138
-rw-r--r--tests/testament/css/style.css114
-rw-r--r--tests/testament/htmlgen.nim228
-rw-r--r--tests/testament/specs.nim151
-rw-r--r--tests/testament/tester.nim360
-rw-r--r--tests/testament/tester.nim.cfg1
-rw-r--r--tests/testdata/csvtest.csv8
-rw-r--r--tests/testdata/data.csv6
-rw-r--r--tests/testdata/doc1.xml14
-rw-r--r--tests/testdata/jsontest.json26
-rw-r--r--tests/testdata/jsontest2.json80
-rw-r--r--tests/testdata/mycert.pem32
-rw-r--r--tests/testdata/string.txt1
-rw-r--r--tests/testdata/wildhtml.html25
-rw-r--r--tests/testdata/xmltest.html111
-rw-r--r--tests/threads/nim.cfg1
-rw-r--r--tests/threads/tactors.nim13
-rw-r--r--tests/threads/tactors2.nim25
-rw-r--r--tests/threads/threadex.nim44
-rw-r--r--tests/threads/trecursive_actor.nim19
-rw-r--r--tests/threads/tthreadanalysis.nim53
-rw-r--r--tests/threads/tthreadanalysis2.nim52
-rw-r--r--tests/threads/tthreadheapviolation1.nim20
-rw-r--r--tests/threads/ttryrecv.nim35
-rw-r--r--tests/trmacros/targlist.nim9
-rw-r--r--tests/trmacros/tcse.nim13
-rw-r--r--tests/trmacros/tdisallowif.nim29
-rw-r--r--tests/trmacros/thoist.nim13
-rw-r--r--tests/trmacros/tmatrix.nim29
-rw-r--r--tests/trmacros/tnoalias.nim16
-rw-r--r--tests/trmacros/tnoalias2.nim19
-rw-r--r--tests/trmacros/tnoendlessrec.nim10
-rw-r--r--tests/trmacros/tor.nim28
-rw-r--r--tests/trmacros/tpartial.nim11
-rw-r--r--tests/trmacros/tpatterns.nim17
-rw-r--r--tests/trmacros/tstar.nim19
-rw-r--r--tests/trmacros/tstmtlist.nim19
-rw-r--r--tests/tuples/tanontuples.nim14
-rw-r--r--tests/tuples/tdifferent_instantiations.nim9
-rw-r--r--tests/tuples/tgeneric_tuple.nim9
-rw-r--r--tests/tuples/tgeneric_tuple2.nim17
-rw-r--r--tests/tuples/tuint_tuple.nim10
-rw-r--r--tests/tuples/tuple_with_nil.nim766
-rw-r--r--tests/tuples/tuple_with_seq.nim46
-rw-r--r--tests/tuples/twrongtupleaccess.nim10
-rw-r--r--tests/typerel/tcommontype.nim20
-rw-r--r--tests/typerel/texplicitcmp.nim32
-rw-r--r--tests/typerel/tno_gcmem_in_shared.nim22
-rw-r--r--tests/typerel/tno_int_in_bool_context.nim8
-rw-r--r--tests/typerel/tnoargopenarray.nim7
-rw-r--r--tests/typerel/tnocontains.nim11
-rw-r--r--tests/typerel/trectuple.nim16
-rw-r--r--tests/typerel/trectuples.nim14
-rw-r--r--tests/typerel/trectype.nim26
-rw-r--r--tests/typerel/trefs.nim23
-rw-r--r--tests/typerel/tregionptrs.nim16
-rw-r--r--tests/typerel/tregionptrs2.nim23
-rw-r--r--tests/typerel/trettypeinference.nim33
-rw-r--r--tests/typerel/tsecondarrayproperty.nim28
-rw-r--r--tests/typerel/tsymchoice_for_expr.nim15
-rw-r--r--tests/typerel/ttuple1.nim16
-rw-r--r--tests/typerel/ttypelessemptyset.nim6
-rw-r--r--tests/typerel/ttypenoval.nim55
-rw-r--r--tests/typerel/ttypenovalue.nim11
-rw-r--r--tests/typerel/tvarargsexpr.nim18
-rw-r--r--tests/typerel/tvoid.nim37
-rw-r--r--tests/typerel/typalias.nim15
-rw-r--r--tests/typerel/typedescs.nim7
-rw-r--r--tests/typerel/typredef.nim8
-rw-r--r--tests/types/tauto_canbe_void.nim9
-rw-r--r--tests/types/temptyseqs.nim90
-rw-r--r--tests/types/tfinalobj.nim16
-rw-r--r--tests/types/tforwty.nim9
-rw-r--r--tests/types/tforwty2.nim22
-rw-r--r--tests/types/tillegaltyperecursion.nim66
-rw-r--r--tests/types/tillrec.nim16
-rw-r--r--tests/types/tinfiniterecursion.nim8
-rw-r--r--tests/types/tinheritref.nim27
-rw-r--r--tests/types/tisop.nim48
-rw-r--r--tests/types/tisopr.nim90
-rw-r--r--tests/usingstmt/tusingstatement.nim89
-rw-r--r--tests/varres/tvarres1.nim17
-rw-r--r--tests/varres/tvarres2.nim16
-rw-r--r--tests/varres/tvarres3.nim15
-rw-r--r--tests/varres/tvarres4.nim20
-rw-r--r--tests/varres/tvartup.nim17
-rw-r--r--tests/varstmt/tlet.nim19
-rw-r--r--tests/varstmt/tvardecl.nim15
-rw-r--r--tests/vm/tarrayboundeval.nim31
-rw-r--r--tests/vm/tasmparser.nim174
-rw-r--r--tests/vm/tcompiletimetable.nim49
-rw-r--r--tests/vm/tconsteval.nim31
-rw-r--r--tests/vm/tconsttable.nim19
-rw-r--r--tests/vm/teval1.nim24
-rw-r--r--tests/vm/tldconst.nim14
-rw-r--r--tests/vm/toverflowopcaddimmint.nim11
-rw-r--r--tests/vm/toverflowopcaddint.nim12
-rw-r--r--tests/vm/toverflowopcmulint.nim11
-rw-r--r--tests/vm/toverflowopcsubimmint.nim10
-rw-r--r--tests/vm/toverflowopcsubint.nim12
-rw-r--r--tests/vm/tquadplus.nim17
-rw-r--r--tests/vm/trgba.nim36
-rw-r--r--tests/vm/triangle_array.nim17
-rw-r--r--tests/vm/tslurp.nim6
-rw-r--r--tests/vm/tstaticprintseq.nim82
-rw-r--r--tests/vm/tstringnil.nim50
-rw-r--r--tests/vm/twrongarray.nim17
-rw-r--r--tests/vm/twrongconst.nim9
-rw-r--r--tests/vm/twrongwhen.nim13
-rw-r--r--tinyc/arm-gen.c1734
-rw-r--r--tinyc/c67-gen.c2548
-rw-r--r--tinyc/coff.h446
-rw-r--r--tinyc/config.h22
-rw-r--r--tinyc/config.mak20
-rw-r--r--tinyc/config.texi1
-rw-r--r--tinyc/config_edited.h20
-rw-r--r--tinyc/elf.h1714
-rw-r--r--tinyc/examples/ex1.c8
-rw-r--r--tinyc/examples/ex2.c98
-rw-r--r--tinyc/examples/ex3.c24
-rw-r--r--tinyc/examples/ex4.c26
-rw-r--r--tinyc/examples/ex5.c8
-rw-r--r--tinyc/i386-asm.c1211
-rw-r--r--tinyc/i386-asm.h446
-rw-r--r--tinyc/i386-gen.c1034
-rw-r--r--tinyc/il-gen.c667
-rw-r--r--tinyc/il-opcodes.h251
-rw-r--r--tinyc/include/float.h57
-rw-r--r--tinyc/include/stdarg.h67
-rw-r--r--tinyc/include/stdbool.h10
-rw-r--r--tinyc/include/stddef.h20
-rw-r--r--tinyc/include/tcclib.h78
-rw-r--r--tinyc/include/varargs.h11
-rw-r--r--tinyc/lib/alloca86-bt.S45
-rw-r--r--tinyc/lib/alloca86.S33
-rw-r--r--tinyc/lib/bcheck.c868
-rw-r--r--tinyc/lib/libtcc1.c607
-rw-r--r--tinyc/libtcc.c2259
-rw-r--r--tinyc/libtcc.h108
-rw-r--r--tinyc/stab.def234
-rw-r--r--tinyc/stab.h17
-rw-r--r--tinyc/tcc-doc.html2241
-rw-r--r--tinyc/tcc-doc.texi1227
-rw-r--r--tinyc/tcc.c553
-rw-r--r--tinyc/tcc.h766
-rw-r--r--tinyc/tccasm.c1021
-rw-r--r--tinyc/tcccoff.c957
-rw-r--r--tinyc/tccelf.c2732
-rw-r--r--tinyc/tccgen.c5122
-rw-r--r--tinyc/tccpe.c1559
-rw-r--r--tinyc/tccpp.c2935
-rw-r--r--tinyc/tcctok.h469
-rw-r--r--tinyc/tests/asmtest.S558
-rw-r--r--tinyc/tests/boundtest.c214
-rw-r--r--tinyc/tests/gcctestsuite.sh33
-rw-r--r--tinyc/tests/libtcc_test.c84
-rw-r--r--tinyc/tests/tcctest.c2202
-rw-r--r--tinyc/texi2pod.pl427
-rw-r--r--tinyc/win32/build-tcc.bat28
-rw-r--r--tinyc/win32/examples/dll.c15
-rw-r--r--tinyc/win32/examples/fib.c24
-rw-r--r--tinyc/win32/examples/hello_dll.c19
-rw-r--r--tinyc/win32/examples/hello_win.c159
-rw-r--r--tinyc/win32/include/_mingw.h54
-rw-r--r--tinyc/win32/include/assert.h71
-rw-r--r--tinyc/win32/include/conio.h159
-rw-r--r--tinyc/win32/include/ctype.h232
-rw-r--r--tinyc/win32/include/dir.h26
-rw-r--r--tinyc/win32/include/direct.h95
-rw-r--r--tinyc/win32/include/dirent.h96
-rw-r--r--tinyc/win32/include/dos.h110
-rw-r--r--tinyc/win32/include/errno.h117
-rw-r--r--tinyc/win32/include/excpt.h20
-rw-r--r--tinyc/win32/include/fcntl.h135
-rw-r--r--tinyc/win32/include/fenv.h85
-rw-r--r--tinyc/win32/include/float.h224
-rw-r--r--tinyc/win32/include/inttypes.h275
-rw-r--r--tinyc/win32/include/io.h296
-rw-r--r--tinyc/win32/include/limits.h115
-rw-r--r--tinyc/win32/include/locale.h100
-rw-r--r--tinyc/win32/include/malloc.h87
-rw-r--r--tinyc/win32/include/math.h438
-rw-r--r--tinyc/win32/include/mem.h8
-rw-r--r--tinyc/win32/include/memory.h9
-rw-r--r--tinyc/win32/include/process.h158
-rw-r--r--tinyc/win32/include/setjmp.h72
-rw-r--r--tinyc/win32/include/share.h44
-rw-r--r--tinyc/win32/include/signal.h111
-rw-r--r--tinyc/win32/include/stdarg.h16
-rw-r--r--tinyc/win32/include/stdbool.h10
-rw-r--r--tinyc/win32/include/stddef.h23
-rw-r--r--tinyc/win32/include/stdint.h184
-rw-r--r--tinyc/win32/include/stdio.h413
-rw-r--r--tinyc/win32/include/stdlib.h482
-rw-r--r--tinyc/win32/include/string.h206
-rw-r--r--tinyc/win32/include/sys/fcntl.h8
-rw-r--r--tinyc/win32/include/sys/file.h9
-rw-r--r--tinyc/win32/include/sys/locking.h52
-rw-r--r--tinyc/win32/include/sys/stat.h190
-rw-r--r--tinyc/win32/include/sys/time.h3
-rw-r--r--tinyc/win32/include/sys/timeb.h82
-rw-r--r--tinyc/win32/include/sys/types.h118
-rw-r--r--tinyc/win32/include/sys/unistd.h9
-rw-r--r--tinyc/win32/include/sys/utime.h89
-rw-r--r--tinyc/win32/include/tchar.h367
-rw-r--r--tinyc/win32/include/time.h219
-rw-r--r--tinyc/win32/include/unistd.h10
-rw-r--r--tinyc/win32/include/values.h4
-rw-r--r--tinyc/win32/include/varargs.h11
-rw-r--r--tinyc/win32/include/wchar.h318
-rw-r--r--tinyc/win32/include/wctype.h127
-rw-r--r--tinyc/win32/include/winapi/basetsd.h119
-rw-r--r--tinyc/win32/include/winapi/basetyps.h144
-rw-r--r--tinyc/win32/include/winapi/winbase.h1852
-rw-r--r--tinyc/win32/include/winapi/wincon.h207
-rw-r--r--tinyc/win32/include/winapi/windef.h240
-rw-r--r--tinyc/win32/include/winapi/windows.h176
-rw-r--r--tinyc/win32/include/winapi/winerror.h1054
-rw-r--r--tinyc/win32/include/winapi/wingdi.h2843
-rw-r--r--tinyc/win32/include/winapi/winnetwk.h346
-rw-r--r--tinyc/win32/include/winapi/winnls.h651
-rw-r--r--tinyc/win32/include/winapi/winnt.h2667
-rw-r--r--tinyc/win32/include/winapi/winreg.h159
-rw-r--r--tinyc/win32/include/winapi/winsvc.h309
-rw-r--r--tinyc/win32/include/winapi/winuser.h3472
-rw-r--r--tinyc/win32/include/winapi/winver.h133
-rw-r--r--tinyc/win32/lib/chkstk.S29
-rw-r--r--tinyc/win32/lib/crt1.c35
-rw-r--r--tinyc/win32/lib/dllcrt1.c13
-rw-r--r--tinyc/win32/lib/dllmain.c9
-rw-r--r--tinyc/win32/lib/gdi32.def337
-rw-r--r--tinyc/win32/lib/kernel32.def763
-rw-r--r--tinyc/win32/lib/libtcc1.abin0 -> 10252 bytes-rw-r--r--tinyc/win32/lib/msvcrt.def782
-rw-r--r--tinyc/win32/lib/user32.def654
-rw-r--r--tinyc/win32/lib/wincrt1.c49
-rw-r--r--tinyc/win32/libtcc/libtcc.abin0 -> 146642 bytes-rw-r--r--tinyc/win32/libtcc/libtcc.h108
-rw-r--r--tinyc/win32/tcc-win32.txt158
-rw-r--r--tinyc/win32/tools/tiny_impdef.c393
-rw-r--r--tinyc/win32/tools/tiny_libmaker.c310
-rw-r--r--tinyc/x86_64-gen.c1419
-rw-r--r--todo.txt103
-rw-r--r--tools/cmerge.nim40
-rw-r--r--tools/detect/detect.nim831
-rw-r--r--tools/detect/linux_amd64_consts.nim631
-rw-r--r--tools/detect/macosx_consts.nim629
-rw-r--r--tools/detect/timesize.c9
-rw-r--r--tools/detect/windows_amd64_consts.nim152
-rw-r--r--tools/detect/windows_i386_consts.nim96
-rw-r--r--tools/fakedeps.nim18
-rw-r--r--tools/nimgrep.nim334
-rw-r--r--tools/nimgrep.nim.cfg5
-rw-r--r--tools/niminst/EnvVarUpdate.nsh346
-rw-r--r--tools/niminst/buildbat.tmpl41
-rw-r--r--tools/niminst/buildsh.tmpl158
-rw-r--r--tools/niminst/debcreation.nim235
-rw-r--r--tools/niminst/deinstall.tmpl64
-rw-r--r--tools/niminst/inno.tmpl182
-rw-r--r--tools/niminst/install.tmpl111
-rw-r--r--tools/niminst/makefile.tmpl168
-rw-r--r--tools/niminst/niminst.nim670
-rw-r--r--tools/niminst/nsis.tmpl258
-rw-r--r--tools/nimrepl.nim172
-rw-r--r--tools/nimweb.nim458
-rw-r--r--tools/noprefix.nim32
-rw-r--r--tools/restorecc.nim16
-rw-r--r--tools/trimcc.nim174
-rw-r--r--tools/website.tmpl210
-rw-r--r--web/assets/images/bg.pngbin0 -> 149129 bytes-rw-r--r--web/assets/images/docs-articles.pngbin0 -> 381 bytes-rw-r--r--web/assets/images/docs-examples.pngbin0 -> 596 bytes-rw-r--r--web/assets/images/docs-internals.pngbin0 -> 621 bytes-rw-r--r--web/assets/images/docs-libraries.pngbin0 -> 335 bytes-rw-r--r--web/assets/images/docs-tools.pngbin0 -> 636 bytes-rw-r--r--web/assets/images/docs-tutorials.pngbin0 -> 560 bytes-rw-r--r--web/assets/images/favicon.icobin0 -> 1150 bytes-rw-r--r--web/assets/images/foot.pngbin0 -> 784 bytes-rw-r--r--web/assets/images/glow-arrow.pngbin0 -> 8657 bytes-rw-r--r--web/assets/images/glow-line.pngbin0 -> 2261 bytes-rw-r--r--web/assets/images/head-link.pngbin0 -> 203 bytes-rw-r--r--web/assets/images/head-link_hover.pngbin0 -> 799 bytes-rw-r--r--web/assets/images/head.pngbin0 -> 171 bytes-rw-r--r--web/assets/images/link_aporia.pngbin0 -> 1526 bytes-rw-r--r--web/assets/images/link_forum.pngbin0 -> 1048 bytes-rw-r--r--web/assets/images/link_nimbuild.pngbin0 -> 896 bytes-rw-r--r--web/assets/images/logo.pngbin0 -> 116562 bytes-rw-r--r--web/assets/images/mascot.pngbin0 -> 18022 bytes-rw-r--r--web/assets/images/more-links_editors.pngbin0 -> 852 bytes-rw-r--r--web/assets/images/more-links_forum.pngbin0 -> 858 bytes-rw-r--r--web/assets/images/more-links_github.pngbin0 -> 713 bytes-rw-r--r--web/assets/images/more-links_nimbuild.pngbin0 -> 724 bytes-rw-r--r--web/assets/images/nim-logo.svg500
-rw-r--r--web/assets/images/quote.pngbin0 -> 1045 bytes-rw-r--r--web/assets/images/quotes.pngbin0 -> 979 bytes-rw-r--r--web/assets/images/sidebar.pngbin0 -> 109579 bytes-rw-r--r--web/assets/images/sidebar_h2.pngbin0 -> 2044 bytes-rw-r--r--web/assets/images/sidebar_head.pngbin0 -> 34993 bytes-rw-r--r--web/assets/images/site_foot.pngbin0 -> 3109 bytes-rw-r--r--web/assets/images/site_neck.pngbin0 -> 317 bytes-rw-r--r--web/assets/images/slideshow-nav.pngbin0 -> 416 bytes-rw-r--r--web/assets/images/slideshow-nav_active.pngbin0 -> 673 bytes-rw-r--r--web/assets/images/tabEnd.pngbin0 -> 194 bytes-rw-r--r--web/assets/index.js34
-rw-r--r--web/assets/style.css558
-rw-r--r--web/community.txt124
-rw-r--r--web/documentation.txt57
-rw-r--r--web/download.txt57
-rw-r--r--web/index.txt89
-rw-r--r--web/learn.txt56
-rw-r--r--web/links.txt0
-rw-r--r--web/news.txt1712
-rw-r--r--web/nimblepkglist.nim76
-rw-r--r--web/question.txt169
-rw-r--r--web/snippets/snippet1.nim4
-rw-r--r--web/support.txt39
-rw-r--r--web/ticker.txt16
-rw-r--r--web/website.ini84
1738 files changed, 399240 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index 3d647a25e..1971a23cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,44 @@
-# all executables
 *
-!*/
+!**/
 !*.*
+nimcache/
+
+*.o
+!/icons/*.o
 *.exe
+*.so
+*.dylib
+*.zip
+*.iss
+
+mapping.txt
+tags
+install.sh
+deinstall.sh
 
-# Wildcard patterns.
+doc/*.html
+doc/*.pdf
+doc/*.idx
+/web/upload
+build/*
+bin/*
+
+# iOS specific wildcards.
+*.mode1v3
+*.pbxuser
+*.perspective
+*.perspectivev3
 *.swp
-nimcache
+.DS_Store
+project.xcworkspace/
+xcuserdata/
+
+# Generated files.
+/compile.json
+/compiler/nimrod.dot
+/reject.json
+/run.json
+/testresults.html
+/testresults.json
+testament.db
+/csources
diff --git a/bin/empty.txt b/bin/empty.txt
new file mode 100644
index 000000000..20f9a91e3
--- /dev/null
+++ b/bin/empty.txt
@@ -0,0 +1 @@
+This file keeps several tools from deleting this subdirectory.

diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 000000000..ade74a9aa
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+set -e
+set -x
+
+if [ ! -e csources/.git ]; then
+	git clone --depth 1 git://github.com/nim-lang/csources.git csources
+fi
+
+cd "csources"
+sh build.sh
+cd ".."
+
+./bin/nim c koch
+./koch boot -d:release
+
+cp -f install.sh.template install.sh
+chmod +x install.sh
+
+exit 0
diff --git a/build/empty.txt b/build/empty.txt
new file mode 100644
index 000000000..20f9a91e3
--- /dev/null
+++ b/build/empty.txt
@@ -0,0 +1 @@
+This file keeps several tools from deleting this subdirectory.

diff --git a/compiler.nimble b/compiler.nimble
new file mode 100644
index 000000000..52eb4083b
--- /dev/null
+++ b/compiler.nimble
@@ -0,0 +1,11 @@
+[Package]
+name = "compiler"
+version = "0.10.3"
+author = "Andreas Rumpf"
+description = "Compiler package providing the compiler sources as a library."
+license = "MIT"
+
+InstallDirs = "doc, compiler"
+
+[Deps]
+Requires: "nim >= 0.10.3"
diff --git a/compiler/aliases.nim b/compiler/aliases.nim
new file mode 100644
index 000000000..3f3d45ff7
--- /dev/null
+++ b/compiler/aliases.nim
@@ -0,0 +1,182 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Simple alias analysis for the HLO and the code generators.
+
+import
+  ast, astalgo, types, trees, intsets, msgs
+  
+type
+  TAnalysisResult* = enum
+    arNo, arMaybe, arYes
+
+proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult
+
+proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
+  result = arNo
+  case n.kind
+  of nkRecList: 
+    for i in countup(0, sonsLen(n) - 1): 
+      result = isPartOfAux(n.sons[i], b, marker)
+      if result == arYes: return
+  of nkRecCase:
+    assert(n.sons[0].kind == nkSym)
+    result = isPartOfAux(n.sons[0], b, marker)
+    if result == arYes: return
+    for i in countup(1, sonsLen(n) - 1): 
+      case n.sons[i].kind
+      of nkOfBranch, nkElse: 
+        result = isPartOfAux(lastSon(n.sons[i]), b, marker)
+        if result == arYes: return
+      else: internalError("isPartOfAux(record case branch)")
+  of nkSym:
+    result = isPartOfAux(n.sym.typ, b, marker)
+  else: internalError(n.info, "isPartOfAux()")
+  
+proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = 
+  result = arNo
+  if a == nil or b == nil: return 
+  if containsOrIncl(marker, a.id): return 
+  if compareTypes(a, b, dcEqIgnoreDistinct): return arYes
+  case a.kind
+  of tyObject: 
+    result = isPartOfAux(a.sons[0], b, marker)
+    if result == arNo: result = isPartOfAux(a.n, b, marker)
+  of tyGenericInst, tyDistinct:
+    result = isPartOfAux(lastSon(a), b, marker)
+  of tyArray, tyArrayConstr, tySet, tyTuple: 
+    for i in countup(0, sonsLen(a) - 1): 
+      result = isPartOfAux(a.sons[i], b, marker)
+      if result == arYes: return 
+  else: discard
+
+proc isPartOf(a, b: PType): TAnalysisResult = 
+  ## checks iff 'a' can be part of 'b'. Iterates over VALUE types!
+  var marker = initIntSet()
+  # watch out: parameters reversed because I'm too lazy to change the code...
+  result = isPartOfAux(b, a, marker)
+
+proc isPartOf*(a, b: PNode): TAnalysisResult =
+  ## checks if location `a` can be part of location `b`. We treat seqs and
+  ## strings as pointers because the code gen often just passes them as such.
+  ##
+  ## Note: `a` can only be part of `b`, if `a`'s type can be part of `b`'s
+  ## type. Since however type analysis is more expensive, we perform it only
+  ## if necessary.
+  ##
+  ## cases: 
+  ##
+  ## YES-cases:
+  ##  x    <| x   # for general trees
+  ##  x[]  <| x
+  ##  x[i] <| x
+  ##  x.f  <| x
+  ##  
+  ## NO-cases:
+  ## x           !<| y    # depending on type and symbol kind
+  ## x[constA]   !<| x[constB]
+  ## x.f         !<| x.g
+  ## x.f         !<| y.f  iff x !<= y
+  ##
+  ## MAYBE-cases:
+  ##
+  ##  x[] ?<| y[]   iff compatible type
+  ##
+  ## 
+  ##  x[]  ?<| y  depending on type
+  ##  
+  if a.kind == b.kind:
+    case a.kind
+    of nkSym:
+      const varKinds = {skVar, skTemp, skProc}
+      # same symbol: aliasing:
+      if a.sym.id == b.sym.id: result = arYes
+      elif a.sym.kind in varKinds or b.sym.kind in varKinds: 
+        # actually, a param could alias a var but we know that cannot happen
+        # here. XXX make this more generic
+        result = arNo
+      else:
+        # use expensive type check:
+        if isPartOf(a.sym.typ, b.sym.typ) != arNo:
+          result = arMaybe
+    of nkBracketExpr:
+      result = isPartOf(a[0], b[0])
+      if len(a) >= 2 and len(b) >= 2:
+        # array accesses:
+        if result == arYes and isDeepConstExpr(a[1]) and isDeepConstExpr(b[1]):
+          # we know it's the same array and we have 2 constant indexes; 
+          # if they are 
+          var x = if a[1].kind == nkHiddenStdConv: a[1][1] else: a[1]
+          var y = if b[1].kind == nkHiddenStdConv: b[1][1] else: b[1]
+          
+          if sameValue(x, y): result = arYes
+          else: result = arNo
+        # else: maybe and no are accurate
+      else:
+        # pointer derefs:
+        if result != arYes:
+          if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
+      
+    of nkDotExpr:
+      result = isPartOf(a[0], b[0])
+      if result != arNo:
+        # if the fields are different, it's not the same location
+        if a[1].sym.id != b[1].sym.id:
+          result = arNo
+
+    of nkHiddenDeref, nkDerefExpr:
+      result = isPartOf(a[0], b[0])
+      # weaken because of indirection:
+      if result != arYes:
+        if isPartOf(a.typ, b.typ) != arNo: result = arMaybe
+      
+    of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+      result = isPartOf(a[1], b[1])
+    of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
+      result = isPartOf(a[0], b[0])
+    else: discard
+    # Calls return a new location, so a default of ``arNo`` is fine.
+  else:
+    # go down recursively; this is quite demanding:
+    const 
+      Ix0Kinds = {nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
+                  nkCheckedFieldExpr}
+      Ix1Kinds = {nkHiddenStdConv, nkHiddenSubConv, nkConv}
+      DerefKinds = {nkHiddenDeref, nkDerefExpr}
+    case b.kind
+    of Ix0Kinds:
+      # a* !<| b.f  iff  a* !<| b
+      result = isPartOf(a, b[0])
+    
+    of DerefKinds:
+      # a* !<| b[] iff 
+      if isPartOf(a.typ, b.typ) != arNo:
+        result = isPartOf(a, b[0])
+        if result == arNo: result = arMaybe
+    
+    of Ix1Kinds:
+      # a* !<| T(b)  iff a* !<| b
+      result = isPartOf(a, b[1])
+    
+    of nkSym:
+      # b is an atom, so we have to check a:
+      case a.kind
+      of Ix0Kinds:
+        # a.f !<| b*  iff  a.f !<| b*
+        result = isPartOf(a[0], b)
+      of Ix1Kinds:
+        result = isPartOf(a[1], b)
+      
+      of DerefKinds:
+        if isPartOf(a.typ, b.typ) != arNo:
+          result = isPartOf(a[0], b)
+          if result == arNo: result = arMaybe
+      else: discard
+    else: discard
+
diff --git a/compiler/ast.nim b/compiler/ast.nim
new file mode 100644
index 000000000..64cb1b1bc
--- /dev/null
+++ b/compiler/ast.nim
@@ -0,0 +1,1550 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# abstract syntax tree + symbol table
+
+import
+  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists,
+  intsets, idgen
+
+type
+  TCallingConvention* = enum
+    ccDefault,                # proc has no explicit calling convention
+    ccStdCall,                # procedure is stdcall
+    ccCDecl,                  # cdecl
+    ccSafeCall,               # safecall
+    ccSysCall,                # system call
+    ccInline,                 # proc should be inlined
+    ccNoInline,               # proc should not be inlined
+    ccFastCall,               # fastcall (pass parameters in registers)
+    ccClosure,                # proc has a closure
+    ccNoConvention            # needed for generating proper C procs sometimes
+
+const
+  CallingConvToStr*: array[TCallingConvention, string] = ["", "stdcall",
+    "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall",
+    "closure", "noconv"]
+
+type
+  TNodeKind* = enum # order is extremely important, because ranges are used
+                    # to check whether a node belongs to a certain class
+    nkNone,               # unknown node kind: indicates an error
+                          # Expressions:
+                          # Atoms:
+    nkEmpty,              # the node is empty
+    nkIdent,              # node is an identifier
+    nkSym,                # node is a symbol
+    nkType,               # node is used for its typ field
+
+    nkCharLit,            # a character literal ''
+    nkIntLit,             # an integer literal
+    nkInt8Lit,
+    nkInt16Lit,
+    nkInt32Lit,
+    nkInt64Lit,
+    nkUIntLit,            # an unsigned integer literal
+    nkUInt8Lit,
+    nkUInt16Lit,
+    nkUInt32Lit,
+    nkUInt64Lit,
+    nkFloatLit,           # a floating point literal
+    nkFloat32Lit,
+    nkFloat64Lit,
+    nkFloat128Lit,
+    nkStrLit,             # a string literal ""
+    nkRStrLit,            # a raw string literal r""
+    nkTripleStrLit,       # a triple string literal """
+    nkNilLit,             # the nil literal
+                          # end of atoms
+    nkMetaNode_Obsolete,  # difficult to explain; represents itself
+                          # (used for macros)
+    nkDotCall,            # used to temporarily flag a nkCall node;
+                          # this is used
+                          # for transforming ``s.len`` to ``len(s)``
+
+    nkCommand,            # a call like ``p 2, 4`` without parenthesis
+    nkCall,               # a call like p(x, y) or an operation like +(a, b)
+    nkCallStrLit,         # a call with a string literal
+                          # x"abc" has two sons: nkIdent, nkRStrLit
+                          # x"""abc""" has two sons: nkIdent, nkTripleStrLit
+    nkInfix,              # a call like (a + b)
+    nkPrefix,             # a call like !a
+    nkPostfix,            # something like a! (also used for visibility)
+    nkHiddenCallConv,     # an implicit type conversion via a type converter
+
+    nkExprEqExpr,         # a named parameter with equals: ''expr = expr''
+    nkExprColonExpr,      # a named parameter with colon: ''expr: expr''
+    nkIdentDefs,          # a definition like `a, b: typeDesc = expr`
+                          # either typeDesc or expr may be nil; used in
+                          # formal parameters, var statements, etc.
+    nkVarTuple,           # a ``var (a, b) = expr`` construct
+    nkPar,                # syntactic (); may be a tuple constructor
+    nkObjConstr,          # object constructor: T(a: 1, b: 2)
+    nkCurly,              # syntactic {}
+    nkCurlyExpr,          # an expression like a{i}
+    nkBracket,            # syntactic []
+    nkBracketExpr,        # an expression like a[i..j, k]
+    nkPragmaExpr,         # an expression like a{.pragmas.}
+    nkRange,              # an expression like i..j
+    nkDotExpr,            # a.b
+    nkCheckedFieldExpr,   # a.b, but b is a field that needs to be checked
+    nkDerefExpr,          # a^
+    nkIfExpr,             # if as an expression
+    nkElifExpr,
+    nkElseExpr,
+    nkLambda,             # lambda expression
+    nkDo,                 # lambda block appering as trailing proc param
+    nkAccQuoted,          # `a` as a node
+
+    nkTableConstr,        # a table constructor {expr: expr}
+    nkBind,               # ``bind expr`` node
+    nkClosedSymChoice,    # symbol choice node; a list of nkSyms (closed)
+    nkOpenSymChoice,      # symbol choice node; a list of nkSyms (open)
+    nkHiddenStdConv,      # an implicit standard type conversion
+    nkHiddenSubConv,      # an implicit type conversion from a subtype
+                          # to a supertype
+    nkConv,               # a type conversion
+    nkCast,               # a type cast
+    nkStaticExpr,         # a static expr
+    nkAddr,               # a addr expression
+    nkHiddenAddr,         # implicit address operator
+    nkHiddenDeref,        # implicit ^ operator
+    nkObjDownConv,        # down conversion between object types
+    nkObjUpConv,          # up conversion between object types
+    nkChckRangeF,         # range check for floats
+    nkChckRange64,        # range check for 64 bit ints
+    nkChckRange,          # range check for ints
+    nkStringToCString,    # string to cstring
+    nkCStringToString,    # cstring to string
+                          # end of expressions
+
+    nkAsgn,               # a = b
+    nkFastAsgn,           # internal node for a fast ``a = b``
+                          # (no string copy)
+    nkGenericParams,      # generic parameters
+    nkFormalParams,       # formal parameters
+    nkOfInherit,          # inherited from symbol
+
+    nkImportAs,           # a 'as' b in an import statement
+    nkProcDef,            # a proc
+    nkMethodDef,          # a method
+    nkConverterDef,       # a converter
+    nkMacroDef,           # a macro
+    nkTemplateDef,        # a template
+    nkIteratorDef,        # an iterator
+
+    nkOfBranch,           # used inside case statements
+                          # for (cond, action)-pairs
+    nkElifBranch,         # used in if statements
+    nkExceptBranch,       # an except section
+    nkElse,               # an else part
+    nkAsmStmt,            # an assembler block
+    nkPragma,             # a pragma statement
+    nkPragmaBlock,        # a pragma with a block
+    nkIfStmt,             # an if statement
+    nkWhenStmt,           # a when expression or statement
+    nkForStmt,            # a for statement
+    nkParForStmt,         # a parallel for statement
+    nkWhileStmt,          # a while statement
+    nkCaseStmt,           # a case statement
+    nkTypeSection,        # a type section (consists of type definitions)
+    nkVarSection,         # a var section
+    nkLetSection,         # a let section
+    nkConstSection,       # a const section
+    nkConstDef,           # a const definition
+    nkTypeDef,            # a type definition
+    nkYieldStmt,          # the yield statement as a tree
+    nkDefer,              # the 'defer' statement
+    nkTryStmt,            # a try statement
+    nkFinally,            # a finally section
+    nkRaiseStmt,          # a raise statement
+    nkReturnStmt,         # a return statement
+    nkBreakStmt,          # a break statement
+    nkContinueStmt,       # a continue statement
+    nkBlockStmt,          # a block statement
+    nkStaticStmt,         # a static statement
+    nkDiscardStmt,        # a discard statement
+    nkStmtList,           # a list of statements
+    nkImportStmt,         # an import statement
+    nkImportExceptStmt,   # an import x except a statement
+    nkExportStmt,         # an export statement
+    nkExportExceptStmt,   # an 'export except' statement
+    nkFromStmt,           # a from * import statement
+    nkIncludeStmt,        # an include statement
+    nkBindStmt,           # a bind statement
+    nkMixinStmt,          # a mixin statement
+    nkUsingStmt,          # an using statement
+    nkCommentStmt,        # a comment statement
+    nkStmtListExpr,       # a statement list followed by an expr; this is used
+                          # to allow powerful multi-line templates
+    nkBlockExpr,          # a statement block ending in an expr; this is used
+                          # to allowe powerful multi-line templates that open a
+                          # temporary scope
+    nkStmtListType,       # a statement list ending in a type; for macros
+    nkBlockType,          # a statement block ending in a type; for macros
+                          # types as syntactic trees:
+
+    nkWith,               # distinct with `foo`
+    nkWithout,            # distinct without `foo`
+
+    nkTypeOfExpr,         # type(1+2)
+    nkObjectTy,           # object body
+    nkTupleTy,            # tuple body
+    nkTupleClassTy,       # tuple type class
+    nkTypeClassTy,        # user-defined type class
+    nkStaticTy,           # ``static[T]``
+    nkRecList,            # list of object parts
+    nkRecCase,            # case section of object
+    nkRecWhen,            # when section of object
+    nkRefTy,              # ``ref T``
+    nkPtrTy,              # ``ptr T``
+    nkVarTy,              # ``var T``
+    nkConstTy,            # ``const T``
+    nkMutableTy,          # ``mutable T``
+    nkDistinctTy,         # distinct type
+    nkProcTy,             # proc type
+    nkIteratorTy,         # iterator type
+    nkSharedTy,           # 'shared T'
+                          # we use 'nkPostFix' for the 'not nil' addition
+    nkEnumTy,             # enum body
+    nkEnumFieldDef,       # `ident = expr` in an enumeration
+    nkArgList,            # argument list
+    nkPattern,            # a special pattern; used for matching
+    nkReturnToken,        # token used for interpretation
+    nkClosure,            # (prc, env)-pair (internally used for code gen)
+    nkGotoState,          # used for the state machine (for iterators)
+    nkState,              # give a label to a code section (for iterators)
+    nkBreakState,         # special break statement for easier code generation
+  TNodeKinds* = set[TNodeKind]
+
+type
+  TSymFlag* = enum    # already 32 flags!
+    sfUsed,           # read access of sym (for warnings) or simply used
+    sfExported,       # symbol is exported from module
+    sfFromGeneric,    # symbol is instantiation of a generic; this is needed
+                      # for symbol file generation; such symbols should always
+                      # be written into the ROD file
+    sfGlobal,         # symbol is at global scope
+
+    sfForward,        # symbol is forward declared
+    sfImportc,        # symbol is external; imported
+    sfExportc,        # symbol is exported (under a specified name)
+    sfVolatile,       # variable is volatile
+    sfRegister,       # variable should be placed in a register
+    sfPure,           # object is "pure" that means it has no type-information
+                      # enum is "pure", its values need qualified access
+                      # variable is "pure"; it's an explicit "global"
+    sfNoSideEffect,   # proc has no side effects
+    sfSideEffect,     # proc may have side effects; cannot prove it has none
+    sfMainModule,     # module is the main module
+    sfSystemModule,   # module is the system module
+    sfNoReturn,       # proc never returns (an exit proc)
+    sfAddrTaken,      # the variable's address is taken (ex- or implicitly);
+                      # *OR*: a proc is indirectly called (used as first class)
+    sfCompilerProc,   # proc is a compiler proc, that is a C proc that is
+                      # needed for the code generator
+    sfProcvar,        # proc can be passed to a proc var
+    sfDiscriminant,   # field is a discriminant in a record/object
+    sfDeprecated,     # symbol is deprecated
+    sfError,          # usage of symbol should trigger a compile-time error
+    sfShadowed,       # a symbol that was shadowed in some inner scope
+    sfThread,         # proc will run as a thread
+                      # variable is a thread variable
+    sfCompileTime,    # proc can be evaluated at compile time
+    sfConstructor,    # proc is a C++ constructor
+    sfDeadCodeElim,   # dead code elimination for the module is turned on
+    sfBorrow,         # proc is borrowed
+    sfInfixCall,      # symbol needs infix call syntax in target language;
+                      # for interfacing with C++, JS
+    sfNamedParamCall, # symbol needs named parameter call syntax in target
+                      # language; for interfacing with Objective C
+    sfDiscardable,    # returned value may be discarded implicitly
+    sfOverriden,      # proc is overriden
+    sfGenSym          # symbol is 'gensym'ed; do not add to symbol table
+
+  TSymFlags* = set[TSymFlag]
+
+const
+  sfFakeConst* = sfDeadCodeElim  # const cannot be put into a data section
+  sfDispatcher* = sfDeadCodeElim # copied method symbol is the dispatcher
+  sfNoInit* = sfMainModule       # don't generate code to init the variable
+
+  sfImmediate* = sfDeadCodeElim
+    # macro or template is immediately expanded
+    # without considering any possible overloads
+
+  sfDirty* = sfPure
+    # template is not hygienic (old styled template)
+    # module, compiled from a dirty-buffer
+
+  sfAnon* = sfDiscardable
+    # symbol name that was generated by the compiler
+    # the compiler will avoid printing such names
+    # in user messages.
+
+  sfNoForward* = sfRegister
+    # forward declarations are not required (per module)
+
+  sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't
+                       # require RC ops
+  sfCompileToCpp* = sfInfixCall       # compile the module as C++ code
+  sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
+  sfExperimental* = sfOverriden       # module uses the .experimental switch
+  sfGoto* = sfOverriden               # var is used for 'goto' code generation
+
+const
+  # getting ready for the future expr/stmt merge
+  nkWhen* = nkWhenStmt
+  nkWhenExpr* = nkWhenStmt
+  nkEffectList* = nkArgList
+  # hacks ahead: an nkEffectList is a node with 4 children:
+  exceptionEffects* = 0 # exceptions at position 0
+  usesEffects* = 1      # read effects at position 1
+  writeEffects* = 2     # write effects at position 2
+  tagEffects* = 3       # user defined tag ('gc', 'time' etc.)
+  effectListLen* = 4    # list of effects list
+
+type
+  TTypeKind* = enum  # order is important!
+                     # Don't forget to change hti.nim if you make a change here
+                     # XXX put this into an include file to avoid this issue!
+    tyNone, tyBool, tyChar,
+    tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc,
+    tyGenericInvocation, # ``T[a, b]`` for types to invoke
+    tyGenericBody,       # ``T[a, b, body]`` last parameter is the body
+    tyGenericInst,       # ``T[a, b, realInstance]`` instantiated generic type
+                         # realInstance will be a concrete type like tyObject
+                         # unless this is an instance of a generic alias type.
+                         # then realInstance will be the tyGenericInst of the
+                         # completely (recursively) resolved alias.
+
+    tyGenericParam,      # ``a`` in the above patterns
+    tyDistinct,
+    tyEnum,
+    tyOrdinal,           # integer types (including enums and boolean)
+    tyArray,
+    tyObject,
+    tyTuple,
+    tySet,
+    tyRange,
+    tyPtr, tyRef,
+    tyVar,
+    tySequence,
+    tyProc,
+    tyPointer, tyOpenArray,
+    tyString, tyCString, tyForward,
+    tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
+    tyFloat, tyFloat32, tyFloat64, tyFloat128,
+    tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
+    tyBigNum,
+    tyConst, tyMutable, tyVarargs,
+    tyIter, # unused
+    tyProxy # used as errornous type (for idetools)
+
+    tyBuiltInTypeClass #\
+      # Type such as the catch-all object, tuple, seq, etc
+
+    tyUserTypeClass #\
+      # the body of a user-defined type class
+
+    tyUserTypeClassInst #\
+      # Instance of a parametric user-defined type class.
+      # Structured similarly to tyGenericInst.
+      # tyGenericInst represents concrete types, while
+      # this is still a "generic param" that will bind types
+      # and resolves them during sigmatch and instantiation.
+
+    tyCompositeTypeClass #\
+      # Type such as seq[Number]
+      # The notes for tyUserTypeClassInst apply here as well
+      # sons[0]: the original expression used by the user.
+      # sons[1]: fully expanded and instantiated meta type
+      # (potentially following aliases)
+
+    tyAnd, tyOr, tyNot #\
+      # boolean type classes such as `string|int`,`not seq`,
+      # `Sortable and Enumable`, etc
+
+    tyAnything #\
+      # a type class matching any type
+
+    tyStatic #\
+      # a value known at compile type (the underlying type is .base)
+
+    tyFromExpr #\
+      # This is a type representing an expression that depends
+      # on generic parameters (the expression is stored in t.n)
+      # It will be converted to a real type only during generic
+      # instantiation and prior to this it has the potential to
+      # be any type.
+
+    tyFieldAccessor #\
+      # Expressions such as Type.field (valid in contexts such
+      # as the `is` operator and magics like `high` and `low`).
+      # Could be lifted to a single argument proc returning the
+      # field value.
+      # sons[0]: type of containing object or tuple
+      # sons[1]: field type
+      # .n: nkDotExpr storing the field name
+
+static:
+  # remind us when TTypeKind stops to fit in a single 64-bit word
+  assert TTypeKind.high.ord <= 63
+
+const
+  tyPureObject* = tyTuple
+  GcTypeKinds* = {tyRef, tySequence, tyString}
+  tyError* = tyProxy # as an errornous node should match everything
+  tyUnknown* = tyFromExpr
+
+  tyUnknownTypes* = {tyError, tyFromExpr}
+
+  tyTypeClasses* = {tyBuiltInTypeClass, tyCompositeTypeClass,
+                    tyUserTypeClass, tyUserTypeClassInst,
+                    tyAnd, tyOr, tyNot, tyAnything}
+
+  tyMetaTypes* = {tyGenericParam, tyTypeDesc, tyExpr} + tyTypeClasses
+
+type
+  TTypeKinds* = set[TTypeKind]
+
+  TNodeFlag* = enum
+    nfNone,
+    nfBase2,    # nfBase10 is default, so not needed
+    nfBase8,
+    nfBase16,
+    nfAllConst, # used to mark complex expressions constant; easy to get rid of
+                # but unfortunately it has measurable impact for compilation
+                # efficiency
+    nfTransf,   # node has been transformed
+    nfSem       # node has been checked for semantics
+    nfLL        # node has gone through lambda lifting
+    nfDotField  # the call can use a dot operator
+    nfDotSetter # the call can use a setter dot operarator
+    nfExplicitCall # x.y() was used instead of x.y
+    nfExprCall  # this is an attempt to call a regular expression
+    nfIsRef     # this node is a 'ref' node; used for the VM
+    nfIsCursor  # this node is attached a cursor; used for idetools
+
+  TNodeFlags* = set[TNodeFlag]
+  TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 28)
+    tfVarargs,        # procedure has C styled varargs
+    tfNoSideEffect,   # procedure type does not allow side effects
+    tfFinal,          # is the object final?
+    tfInheritable,    # is the object inheritable?
+    tfAcyclic,        # type is acyclic (for GC optimization)
+    tfEnumHasHoles,   # enum cannot be mapped into a range
+    tfShallow,        # type can be shallow copied on assignment
+    tfThread,         # proc type is marked as ``thread``; alias for ``gcsafe``
+    tfFromGeneric,    # type is an instantiation of a generic; this is needed
+                      # because for instantiations of objects, structural
+                      # type equality has to be used
+    tfUnresolved,     # marks unresolved typedesc/static params: e.g.
+                      # proc foo(T: typedesc, list: seq[T]): var T
+                      # proc foo(L: static[int]): array[L, int]
+                      # can be attached to ranges to indicate that the range
+                      # depends on unresolved static params.
+    tfRetType,        # marks return types in proc (used to detect type classes
+                      # used as return types for return type inference)
+    tfCapturesEnv,    # whether proc really captures some environment
+    tfByCopy,         # pass object/tuple by copy (C backend)
+    tfByRef,          # pass object/tuple by reference (C backend)
+    tfIterator,       # type is really an iterator, not a tyProc
+    tfShared,         # type is 'shared'
+    tfNotNil,         # type cannot be 'nil'
+
+    tfNeedsInit,      # type constains a "not nil" constraint somewhere or some
+                      # other type so that it requires initalization
+    tfVarIsPtr,       # 'var' type is translated like 'ptr' even in C++ mode
+    tfHasMeta,        # type contains "wildcard" sub-types such as generic params
+                      # or other type classes
+    tfHasGCedMem,     # type contains GC'ed memory
+    tfPacked
+    tfHasStatic
+    tfGenericTypeParam
+    tfImplicitTypeParam
+    tfWildcard        # consider a proc like foo[T, I](x: Type[T, I])
+                      # T and I here can bind to both typedesc and static types
+                      # before this is determined, we'll consider them to be a
+                      # wildcard type.
+    tfHasAsgn         # type has overloaded assignment operator
+    tfBorrowDot       # distinct type borrows '.'
+
+  TTypeFlags* = set[TTypeFlag]
+
+  TSymKind* = enum        # the different symbols (start with the prefix sk);
+                          # order is important for the documentation generator!
+    skUnknown,            # unknown symbol: used for parsing assembler blocks
+                          # and first phase symbol lookup in generics
+    skConditional,        # symbol for the preprocessor (may become obsolete)
+    skDynLib,             # symbol represents a dynamic library; this is used
+                          # internally; it does not exist in Nim code
+    skParam,              # a parameter
+    skGenericParam,       # a generic parameter; eq in ``proc x[eq=`==`]()``
+    skTemp,               # a temporary variable (introduced by compiler)
+    skModule,             # module identifier
+    skType,               # a type
+    skVar,                # a variable
+    skLet,                # a 'let' symbol
+    skConst,              # a constant
+    skResult,             # special 'result' variable
+    skProc,               # a proc
+    skMethod,             # a method
+    skIterator,           # an inline iterator
+    skClosureIterator,    # a resumable closure iterator
+    skConverter,          # a type converter
+    skMacro,              # a macro
+    skTemplate,           # a template; currently also misused for user-defined
+                          # pragmas
+    skField,              # a field in a record or object
+    skEnumField,          # an identifier in an enum
+    skForVar,             # a for loop variable
+    skLabel,              # a label (for block statement)
+    skStub,               # symbol is a stub and not yet loaded from the ROD
+                          # file (it is loaded on demand, which may
+                          # mean: never)
+    skPackage,            # symbol is a package (used for canonicalization)
+    skAlias               # an alias (needs to be resolved immediately)
+  TSymKinds* = set[TSymKind]
+
+const
+  routineKinds* = {skProc, skMethod, skIterator, skClosureIterator,
+                   skConverter, skMacro, skTemplate}
+  tfIncompleteStruct* = tfVarargs
+  tfUncheckedArray* = tfVarargs
+  tfUnion* = tfNoSideEffect
+  tfGcSafe* = tfThread
+  tfObjHasKids* = tfEnumHasHoles
+  skError* = skUnknown
+
+  # type flags that are essential for type equality:
+  eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
+
+type
+  TMagic* = enum # symbols that require compiler magic:
+    mNone,
+    mDefined, mDefinedInScope, mCompiles,
+    mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mTypeOf, mRoof, mPlugin,
+    mEcho, mShallowCopy, mSlurp, mStaticExec,
+    mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
+    mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
+    mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+    mIncl, mExcl, mCard, mChr,
+    mGCref, mGCunref,
+
+    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
+    mDivI64, mModI64, mSucc, mPred,
+    mAddF64, mSubF64, mMulF64, mDivF64,
+
+    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
+    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
+    mMinF64, mMaxF64, mAddU, mSubU, mMulU,
+    mDivU, mModU, mEqI, mLeI,
+    mLtI,
+    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mLeU, mLtU, mLeU64, mLtU64,
+    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
+    mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mEqProc, mUnaryMinusI,
+    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryPlusI, mBitnotI,
+    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
+    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
+    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
+    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
+    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mSlice,
+    mDotDot, # this one is only necessary to give nice compile time warnings
+    mFields, mFieldPairs, mOmpParFor,
+    mAppendStrCh, mAppendStrStr, mAppendSeqElem,
+    mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq,
+    mIsPartOf, mAstToStr, mParallel,
+    mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
+    mNewString, mNewStringOfCap, mParseBiggestFloat,
+    mReset,
+    mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
+    mOrdinal,
+    mInt, mInt8, mInt16, mInt32, mInt64,
+    mUInt, mUInt8, mUInt16, mUInt32, mUInt64,
+    mFloat, mFloat32, mFloat64, mFloat128,
+    mBool, mChar, mString, mCstring,
+    mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
+    mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
+    mIsMainModule, mCompileDate, mCompileTime, mProcCall,
+    mCpuEndian, mHostOS, mHostCPU, mAppType,
+    mNaN, mInf, mNegInf,
+    mCompileOption, mCompileOptionArg,
+    mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
+    mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
+    mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
+    mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
+    mNBindSym, mLocals, mNCallSite,
+    mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
+    mInstantiationInfo, mGetTypeInfo, mNGenSym
+
+# things that we can evaluate safely at compile time, even if not asked for it:
+const
+  ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
+    mPred, mInc, mDec, mOrd, mLengthOpenArray,
+    mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
+    mIncl, mExcl, mCard, mChr,
+    mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
+    mDivI64, mModI64, mAddF64, mSubF64, mMulF64, mDivF64,
+    mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
+    mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64,
+    mMinF64, mMaxF64, mAddU, mSubU, mMulU,
+    mDivU, mModU, mEqI, mLeI,
+    mLtI,
+    mEqI64, mLeI64, mLtI64, mEqF64, mLeF64, mLtF64,
+    mLeU, mLtU, mLeU64, mLtU64,
+    mEqEnum, mLeEnum, mLtEnum, mEqCh, mLeCh, mLtCh, mEqB, mLeB, mLtB, mEqRef,
+    mEqProc, mEqUntracedRef, mLePtr, mLtPtr, mEqCString, mXor, mUnaryMinusI,
+    mUnaryMinusI64, mAbsI, mAbsI64, mNot,
+    mUnaryPlusI, mBitnotI,
+    mBitnotI64, mUnaryPlusF64, mUnaryMinusF64, mAbsF64, mZe8ToI, mZe8ToI64,
+    mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64, mToU8, mToU16, mToU32,
+    mToFloat, mToBiggestFloat, mToInt, mToBiggestInt, mCharToStr, mBoolToStr,
+    mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr,
+    mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet,
+    mPlusSet, mMinusSet, mSymDiffSet, mConStrStr,
+    mAppendStrCh, mAppendStrStr, mAppendSeqElem,
+    mInRange, mInSet, mRepr,
+    mCopyStr, mCopyStrLast}
+  # magics that require special semantic checking and
+  # thus cannot be overloaded (also documented in the spec!):
+  SpecialSemMagics* = {
+    mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
+    mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
+
+type
+  PNode* = ref TNode
+  TNodeSeq* = seq[PNode]
+  PType* = ref TType
+  PSym* = ref TSym
+  TNode*{.final, acyclic.} = object # on a 32bit machine, this takes 32 bytes
+    when defined(useNodeIds):
+      id*: int
+    typ*: PType
+    info*: TLineInfo
+    flags*: TNodeFlags
+    case kind*: TNodeKind
+    of nkCharLit..nkUInt64Lit:
+      intVal*: BiggestInt
+    of nkFloatLit..nkFloat128Lit:
+      floatVal*: BiggestFloat
+    of nkStrLit..nkTripleStrLit:
+      strVal*: string
+    of nkSym:
+      sym*: PSym
+    of nkIdent:
+      ident*: PIdent
+    else:
+      sons*: TNodeSeq
+    comment*: string
+
+  TSymSeq* = seq[PSym]
+  TStrTable* = object         # a table[PIdent] of PSym
+    counter*: int
+    data*: TSymSeq
+
+  # -------------- backend information -------------------------------
+  TLocKind* = enum
+    locNone,                  # no location
+    locTemp,                  # temporary location
+    locLocalVar,              # location is a local variable
+    locGlobalVar,             # location is a global variable
+    locParam,                 # location is a parameter
+    locField,                 # location is a record field
+    locExpr,                  # "location" is really an expression
+    locProc,                  # location is a proc (an address of a procedure)
+    locData,                  # location is a constant
+    locCall,                  # location is a call expression
+    locOther                  # location is something other
+  TLocFlag* = enum
+    lfIndirect,               # backend introduced a pointer
+    lfFullExternalName, # only used when 'gCmd == cmdPretty': Indicates
+      # that the symbol has been imported via 'importc: "fullname"' and
+      # no format string.
+    lfNoDeepCopy,             # no need for a deep copy
+    lfNoDecl,                 # do not declare it in C
+    lfDynamicLib,             # link symbol to dynamic library
+    lfExportLib,              # export symbol for dynamic library generation
+    lfHeader,                 # include header file for symbol
+    lfImportCompilerProc,     # ``importc`` of a compilerproc
+    lfSingleUse               # no location yet and will only be used once
+  TStorageLoc* = enum
+    OnUnknown,                # location is unknown (stack, heap or static)
+    OnStack,                  # location is on hardware stack
+    OnHeap                    # location is on heap or global
+                              # (reference counting needed)
+  TLocFlags* = set[TLocFlag]
+  TLoc* = object
+    k*: TLocKind              # kind of location
+    s*: TStorageLoc
+    flags*: TLocFlags         # location's flags
+    t*: PType                 # type of location
+    r*: Rope                 # rope value of location (code generators)
+    heapRoot*: Rope          # keeps track of the enclosing heap object that
+                              # owns this location (required by GC algorithms
+                              # employing heap snapshots or sliding views)
+
+  # ---------------- end of backend information ------------------------------
+
+  TLibKind* = enum
+    libHeader, libDynamic
+  TLib* = object of lists.TListEntry # also misused for headers!
+    kind*: TLibKind
+    generated*: bool          # needed for the backends:
+    isOverriden*: bool
+    name*: Rope
+    path*: PNode              # can be a string literal!
+
+  TInstantiation* = object
+    sym*: PSym
+    concreteTypes*: seq[PType]
+    usedBy*: seq[int32]       # list of modules using the generic
+                              # needed in caas mode for purging the cache
+                              # XXX: it's possible to switch to a
+                              # simple ref count here
+
+  PInstantiation* = ref TInstantiation
+
+  TScope* = object
+    depthLevel*: int
+    symbols*: TStrTable
+    usingSyms*: seq[PNode]
+    parent*: PScope
+
+  PScope* = ref TScope
+
+  PLib* = ref TLib
+  TSym* {.acyclic.} = object of TIdObj
+    # proc and type instantiations are cached in the generic symbol
+    case kind*: TSymKind
+    of skType, skGenericParam:
+      typeInstCache*: seq[PType]
+      typScope*: PScope
+    of routineKinds:
+      procInstCache*: seq[PInstantiation]
+      gcUnsafetyReason*: PSym  # for better error messages wrt gcsafe
+      #scope*: PScope          # the scope where the proc was defined
+    of skModule:
+      # modules keep track of the generic symbols they use from other modules.
+      # this is because in incremental compilation, when a module is about to
+      # be replaced with a newer version, we must decrement the usage count
+      # of all previously used generics.
+      # For 'import as' we copy the module symbol but shallowCopy the 'tab'
+      # and set the 'usedGenerics' to ... XXX gah! Better set module.name
+      # instead? But this doesn't work either. --> We need an skModuleAlias?
+      # No need, just leave it as skModule but set the owner accordingly and
+      # check for the owner when touching 'usedGenerics'.
+      usedGenerics*: seq[PInstantiation]
+      tab*: TStrTable         # interface table for modules
+    of skLet, skVar, skField, skForVar:
+      guard*: PSym
+    else: nil
+    magic*: TMagic
+    typ*: PType
+    name*: PIdent
+    info*: TLineInfo
+    owner*: PSym
+    flags*: TSymFlags
+    ast*: PNode               # syntax tree of proc, iterator, etc.:
+                              # the whole proc including header; this is used
+                              # for easy generation of proper error messages
+                              # for variant record fields the discriminant
+                              # expression
+                              # for modules, it's a placeholder for compiler
+                              # generated code that will be appended to the
+                              # module after the sem pass (see appendToModule)
+    options*: TOptions
+    position*: int            # used for many different things:
+                              # for enum fields its position;
+                              # for fields its offset
+                              # for parameters its position
+                              # for a conditional:
+                              # 1 iff the symbol is defined, else 0
+                              # (or not in symbol table)
+                              # for modules, an unique index corresponding
+                              # to the module's fileIdx
+                              # for variables a slot index for the evaluator
+                              # for routines a superop-ID
+    offset*: int              # offset of record field
+    loc*: TLoc
+    annex*: PLib              # additional fields (seldom used, so we use a
+                              # reference to another object to safe space)
+    constraint*: PNode        # additional constraints like 'lit|result'; also
+                              # misused for the codegenDecl pragma in the hope
+                              # it won't cause problems
+
+  TTypeSeq* = seq[PType]
+  TLockLevel* = distinct int16
+  TType* {.acyclic.} = object of TIdObj # \
+                              # types are identical iff they have the
+                              # same id; there may be multiple copies of a type
+                              # in memory!
+    kind*: TTypeKind          # kind of type
+    callConv*: TCallingConvention # for procs
+    flags*: TTypeFlags        # flags of the type
+    sons*: TTypeSeq           # base types, etc.
+    n*: PNode                 # node for types:
+                              # for range types a nkRange node
+                              # for record types a nkRecord node
+                              # for enum types a list of symbols
+                              # for tyInt it can be the int literal
+                              # for procs and tyGenericBody, it's the
+                              # formal param list
+                              # for concepts, the concept body
+                              # else: unused
+    owner*: PSym              # the 'owner' of the type
+    sym*: PSym                # types have the sym associated with them
+                              # it is used for converting types to strings
+    destructor*: PSym         # destructor. warning: nil here may not necessary
+                              # mean that there is no destructor.
+                              # see instantiateDestructor in semdestruct.nim
+    deepCopy*: PSym           # overriden 'deepCopy' operation
+    assignment*: PSym         # overriden '=' operator
+    size*: BiggestInt         # the size of the type in bytes
+                              # -1 means that the size is unkwown
+    align*: int16             # the type's alignment requirements
+    lockLevel*: TLockLevel    # lock level as required for deadlock checking
+    loc*: TLoc
+
+  TPair* = object
+    key*, val*: RootRef
+
+  TPairSeq* = seq[TPair]
+  TTable* = object   # the same as table[PObject] of PObject
+    counter*: int
+    data*: TPairSeq
+
+  TIdPair* = object
+    key*: PIdObj
+    val*: RootRef
+
+  TIdPairSeq* = seq[TIdPair]
+  TIdTable* = object # the same as table[PIdent] of PObject
+    counter*: int
+    data*: TIdPairSeq
+
+  TIdNodePair* = object
+    key*: PIdObj
+    val*: PNode
+
+  TIdNodePairSeq* = seq[TIdNodePair]
+  TIdNodeTable* = object # the same as table[PIdObj] of PNode
+    counter*: int
+    data*: TIdNodePairSeq
+
+  TNodePair* = object
+    h*: THash                 # because it is expensive to compute!
+    key*: PNode
+    val*: int
+
+  TNodePairSeq* = seq[TNodePair]
+  TNodeTable* = object # the same as table[PNode] of int;
+                                # nodes are compared by structure!
+    counter*: int
+    data*: TNodePairSeq
+
+  TObjectSeq* = seq[RootRef]
+  TObjectSet* = object
+    counter*: int
+    data*: TObjectSeq
+
+  TImplication* = enum
+    impUnknown, impNo, impYes
+
+# BUGFIX: a module is overloadable so that a proc can have the
+# same name as an imported module. This is necessary because of
+# the poor naming choices in the standard library.
+
+const
+  OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
+    skConverter, skModule, skTemplate, skMacro}
+
+  GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
+    tyGenericParam}
+
+  StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
+    tySet, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc, tyOpenArray,
+    tyVarargs}
+
+  ConcreteTypes*: TTypeKinds = { # types of the expr that may occur in::
+                                 # var x = expr
+    tyBool, tyChar, tyEnum, tyArray, tyObject,
+    tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
+    tyPointer,
+    tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
+    tyUInt..tyUInt64}
+  IntegralTypes* = {tyBool, tyChar, tyEnum, tyInt..tyInt64,
+    tyFloat..tyFloat128, tyUInt..tyUInt64}
+  ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
+                                    tyTuple, tySequence}
+  NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
+    tyProc, tyString, tyError}
+  ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
+    skIterator, skClosureIterator,
+    skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
+  PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
+                                      nfDotSetter, nfDotField,
+                                      nfIsRef, nfIsCursor}
+  namePos* = 0
+  patternPos* = 1    # empty except for term rewriting macros
+  genericParamsPos* = 2
+  paramsPos* = 3
+  pragmasPos* = 4
+  optimizedCodePos* = 5  # will be used for exception tracking
+  bodyPos* = 6       # position of body; use rodread.getBody() instead!
+  resultPos* = 7
+  dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
+
+  nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
+                  nkCommand, nkCallStrLit, nkHiddenCallConv}
+  nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
+                   nkClosedSymChoice}
+
+  nkLiterals* = {nkCharLit..nkTripleStrLit}
+  nkLambdaKinds* = {nkLambda, nkDo}
+  declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
+  procDefs* = nkLambdaKinds + declarativeDefs
+
+  nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
+  nkStrKinds* = {nkStrLit..nkTripleStrLit}
+
+  skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
+  skProcKinds* = {skProc, skTemplate, skMacro, skIterator, skClosureIterator,
+                  skMethod, skConverter}
+
+  skIterators* = {skIterator, skClosureIterator}
+
+var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
+
+proc isCallExpr*(n: PNode): bool =
+  result = n.kind in nkCallKinds
+
+proc discardSons*(father: PNode)
+
+proc len*(n: PNode): int {.inline.} =
+  if isNil(n.sons): result = 0
+  else: result = len(n.sons)
+
+proc safeLen*(n: PNode): int {.inline.} =
+  ## works even for leaves.
+  if n.kind in {nkNone..nkNilLit} or isNil(n.sons): result = 0
+  else: result = len(n.sons)
+
+proc add*(father, son: PNode) =
+  assert son != nil
+  if isNil(father.sons): father.sons = @[]
+  add(father.sons, son)
+
+proc `[]`*(n: PNode, i: int): PNode {.inline.} =
+  result = n.sons[i]
+
+# son access operators with support for negative indices
+template `{}`*(n: PNode, i: int): expr = n[i -| n]
+template `{}=`*(n: PNode, i: int, s: PNode): stmt =
+  n.sons[i -| n] = s
+
+when defined(useNodeIds):
+  const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
+  var gNodeId: int
+
+proc newNode*(kind: TNodeKind): PNode =
+  new(result)
+  result.kind = kind
+  #result.info = UnknownLineInfo() inlined:
+  result.info.fileIndex = int32(- 1)
+  result.info.col = int16(- 1)
+  result.info.line = int16(- 1)
+  when defined(useNodeIds):
+    result.id = gNodeId
+    if result.id == nodeIdToDebug:
+      echo "KIND ", result.kind
+      writeStackTrace()
+    inc gNodeId
+
+proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
+  result = newNode(kind)
+  result.intVal = intVal
+
+proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
+  result = newIntNode(kind, intVal)
+  result.typ = typ
+
+proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
+  result = newNode(kind)
+  result.floatVal = floatVal
+
+proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
+  result = newNode(kind)
+  result.strVal = strVal
+
+proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
+             info: TLineInfo): PSym =
+  # generates a symbol and initializes the hash field too
+  new(result)
+  result.name = name
+  result.kind = symKind
+  result.flags = {}
+  result.info = info
+  result.options = gOptions
+  result.owner = owner
+  result.offset = - 1
+  result.id = getID()
+  when debugIds:
+    registerId(result)
+  #if result.id < 2000:
+  #  MessageOut(name.s & " has id: " & toString(result.id))
+
+var emptyNode* = newNode(nkEmpty)
+# There is a single empty node that is shared! Do not overwrite it!
+
+var anyGlobal* = newSym(skVar, getIdent("*"), nil, unknownLineInfo())
+
+proc isMetaType*(t: PType): bool =
+  return t.kind in tyMetaTypes or
+         (t.kind == tyStatic and t.n == nil) or
+         tfHasMeta in t.flags
+
+proc linkTo*(t: PType, s: PSym): PType {.discardable.} =
+  t.sym = s
+  s.typ = t
+  result = t
+
+proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
+  t.sym = s
+  s.typ = t
+  result = s
+
+template fileIdx*(c: PSym): int32 =
+  # XXX: this should be used only on module symbols
+  c.position.int32
+
+template filename*(c: PSym): string =
+  # XXX: this should be used only on module symbols
+  c.position.int32.toFilename
+
+proc appendToModule*(m: PSym, n: PNode) =
+  ## The compiler will use this internally to add nodes that will be
+  ## appended to the module after the sem pass
+  if m.ast == nil:
+    m.ast = newNode(nkStmtList)
+    m.ast.sons = @[n]
+  else:
+    assert m.ast.kind == nkStmtList
+    m.ast.sons.add(n)
+
+const                         # for all kind of hash tables:
+  GrowthFactor* = 2           # must be power of 2, > 0
+  StartSize* = 8              # must be power of 2, > 0
+
+proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
+  dest.counter = src.counter
+  if isNil(src.data): return
+  setLen(dest.data, len(src.data))
+  for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
+
+proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
+  dest.counter = src.counter
+  if isNil(src.data): return
+  newSeq(dest.data, len(src.data))
+  for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
+
+proc copyTable*(dest: var TTable, src: TTable) =
+  dest.counter = src.counter
+  if isNil(src.data): return
+  setLen(dest.data, len(src.data))
+  for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
+
+proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
+  dest.counter = src.counter
+  if isNil(src.data): return
+  setLen(dest.data, len(src.data))
+  for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
+
+proc discardSons*(father: PNode) =
+  father.sons = nil
+
+proc withInfo*(n: PNode, info: TLineInfo): PNode =
+  n.info = info
+  return n
+
+proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
+  result = newNode(nkIdent)
+  result.ident = ident
+  result.info = info
+
+proc newSymNode*(sym: PSym): PNode =
+  result = newNode(nkSym)
+  result.sym = sym
+  result.typ = sym.typ
+  result.info = sym.info
+
+proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
+  result = newNode(nkSym)
+  result.sym = sym
+  result.typ = sym.typ
+  result.info = info
+
+proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode =
+  new(result)
+  result.kind = kind
+  result.info = info
+  when defined(useNodeIds):
+    result.id = gNodeId
+    if result.id == nodeIdToDebug:
+      echo "KIND ", result.kind
+      writeStackTrace()
+    inc gNodeId
+
+proc newNodeI*(kind: TNodeKind, info: TLineInfo, children: int): PNode =
+  new(result)
+  result.kind = kind
+  result.info = info
+  if children > 0:
+    newSeq(result.sons, children)
+  when defined(useNodeIds):
+    result.id = gNodeId
+    if result.id == nodeIdToDebug:
+      echo "KIND ", result.kind
+      writeStackTrace()
+    inc gNodeId
+
+proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
+             typ: PType = nil): PNode =
+  new(result)
+  result.kind = kind
+  result.info = info
+  result.typ = typ
+  # XXX use shallowCopy here for ownership transfer:
+  result.sons = sons
+  when defined(useNodeIds):
+    result.id = gNodeId
+    if result.id == nodeIdToDebug:
+      echo "KIND ", result.kind
+      writeStackTrace()
+    inc gNodeId
+
+proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
+  result = newNode(kind)
+  result.info = info
+  result.typ = typ
+
+proc addSon*(father, son: PNode) =
+  assert son != nil
+  if isNil(father.sons): father.sons = @[]
+  add(father.sons, son)
+
+var emptyParams = newNode(nkFormalParams)
+emptyParams.addSon(emptyNode)
+
+proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
+                 params = emptyParams,
+                 name, pattern, genericParams,
+                 pragmas, exceptions = ast.emptyNode): PNode =
+  result = newNodeI(kind, info)
+  result.sons = @[name, pattern, genericParams, params,
+                  pragmas, exceptions, body]
+
+const
+  UnspecifiedLockLevel* = TLockLevel(-1'i16)
+  MaxLockLevel* = 1000'i16
+  UnknownLockLevel* = TLockLevel(1001'i16)
+
+proc `$`*(x: TLockLevel): string =
+  if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
+  elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
+  else: result = $int16(x)
+
+proc newType*(kind: TTypeKind, owner: PSym): PType =
+  new(result)
+  result.kind = kind
+  result.owner = owner
+  result.size = - 1
+  result.align = 2            # default alignment
+  result.id = getID()
+  result.lockLevel = UnspecifiedLockLevel
+  when debugIds:
+    registerId(result)
+  #if result.id == 92231:
+  #  echo "KNID ", kind
+  #  writeStackTrace()
+  #  messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id))
+
+proc mergeLoc(a: var TLoc, b: TLoc) =
+  if a.k == low(a.k): a.k = b.k
+  if a.s == low(a.s): a.s = b.s
+  a.flags = a.flags + b.flags
+  if a.t == nil: a.t = b.t
+  if a.r == nil: a.r = b.r
+  #if a.a == 0: a.a = b.a
+
+proc newSons*(father: PNode, length: int) =
+  if isNil(father.sons):
+    newSeq(father.sons, length)
+  else:
+    setLen(father.sons, length)
+
+proc newSons*(father: PType, length: int) =
+  if isNil(father.sons):
+    newSeq(father.sons, length)
+  else:
+    setLen(father.sons, length)
+
+proc sonsLen*(n: PType): int = n.sons.len
+proc len*(n: PType): int = n.sons.len
+proc sonsLen*(n: PNode): int = n.sons.len
+proc lastSon*(n: PNode): PNode = n.sons[^1]
+proc lastSon*(n: PType): PType = n.sons[^1]
+
+proc assignType*(dest, src: PType) =
+  dest.kind = src.kind
+  dest.flags = src.flags
+  dest.callConv = src.callConv
+  dest.n = src.n
+  dest.size = src.size
+  dest.align = src.align
+  dest.destructor = src.destructor
+  dest.deepCopy = src.deepCopy
+  dest.assignment = src.assignment
+  dest.lockLevel = src.lockLevel
+  # this fixes 'type TLock = TSysLock':
+  if src.sym != nil:
+    if dest.sym != nil:
+      dest.sym.flags = dest.sym.flags + src.sym.flags
+      if dest.sym.annex == nil: dest.sym.annex = src.sym.annex
+      mergeLoc(dest.sym.loc, src.sym.loc)
+    else:
+      dest.sym = src.sym
+  newSons(dest, sonsLen(src))
+  for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
+
+proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
+  result = newType(t.kind, owner)
+  assignType(result, t)
+  if keepId:
+    result.id = t.id
+  else:
+    when debugIds: registerId(result)
+  result.sym = t.sym          # backend-info should not be copied
+
+proc copySym*(s: PSym, keepId: bool = false): PSym =
+  result = newSym(s.kind, s.name, s.owner, s.info)
+  #result.ast = nil            # BUGFIX; was: s.ast which made problems
+  result.typ = s.typ
+  if keepId:
+    result.id = s.id
+  else:
+    result.id = getID()
+    when debugIds: registerId(result)
+  result.flags = s.flags
+  result.magic = s.magic
+  if s.kind == skModule:
+    copyStrTable(result.tab, s.tab)
+  result.options = s.options
+  result.position = s.position
+  result.loc = s.loc
+  result.annex = s.annex      # BUGFIX
+  if result.kind in {skVar, skLet, skField}:
+    result.guard = s.guard
+
+proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
+  result = newSym(s.kind, newIdent, s.owner, info)
+  # keep ID!
+  result.ast = s.ast
+  result.id = s.id
+  result.flags = s.flags
+  system.shallowCopy(result.tab, s.tab)
+  result.options = s.options
+  result.position = s.position
+  result.loc = s.loc
+  result.annex = s.annex
+  # XXX once usedGenerics is used, ensure module aliases keep working!
+  assert s.usedGenerics == nil
+
+proc initStrTable*(x: var TStrTable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+
+proc newStrTable*: TStrTable =
+  initStrTable(result)
+
+proc initTable(x: var TTable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+
+proc initIdTable*(x: var TIdTable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+
+proc resetIdTable*(x: var TIdTable) =
+  x.counter = 0
+  # clear and set to old initial size:
+  setLen(x.data, 0)
+  setLen(x.data, StartSize)
+
+proc initObjectSet*(x: var TObjectSet) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+
+proc initIdNodeTable*(x: var TIdNodeTable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+
+proc initNodeTable*(x: var TNodeTable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+
+proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
+  ## Used throughout the compiler code to test whether a type tree contains or
+  ## doesn't contain a specific type/types - it is often the case that only the
+  ## last child nodes of a type tree need to be searched. This is a really hot
+  ## path within the compiler!
+  result = t
+  while result.kind in kinds: result = lastSon(result)
+
+proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
+  ## same as skipTypes but handles 'nil'
+  result = t
+  while result != nil and result.kind in kinds:
+    if result.len == 0: return nil
+    result = lastSon(result)
+
+proc isGCedMem*(t: PType): bool {.inline.} =
+  result = t.kind in {tyString, tyRef, tySequence} or
+           t.kind == tyProc and t.callConv == ccClosure
+
+proc propagateToOwner*(owner, elem: PType) =
+  const HaveTheirOwnEmpty = {tySequence, tySet, tyPtr, tyRef, tyProc}
+  owner.flags = owner.flags + (elem.flags * {tfHasMeta})
+  if tfNotNil in elem.flags:
+    if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
+      owner.flags.incl tfNotNil
+    elif owner.kind notin HaveTheirOwnEmpty:
+      owner.flags.incl tfNeedsInit
+
+  if tfNeedsInit in elem.flags:
+    if owner.kind in HaveTheirOwnEmpty: discard
+    else: owner.flags.incl tfNeedsInit
+
+  if elem.isMetaType:
+    owner.flags.incl tfHasMeta
+
+  if tfHasAsgn in elem.flags:
+    let o2 = elem.skipTypes({tyGenericInst})
+    if o2.kind in {tyTuple, tyObject, tyArray, tyArrayConstr,
+                   tySequence, tySet, tyDistinct}:
+      o2.flags.incl tfHasAsgn
+      owner.flags.incl tfHasAsgn
+
+  if owner.kind notin {tyProc, tyGenericInst, tyGenericBody,
+                       tyGenericInvocation}:
+    let elemB = elem.skipTypes({tyGenericInst})
+    if elemB.isGCedMem or tfHasGCedMem in elemB.flags:
+      # for simplicity, we propagate this flag even to generics. We then
+      # ensure this doesn't bite us in sempass2.
+      owner.flags.incl tfHasGCedMem
+
+proc rawAddSon*(father, son: PType) =
+  if isNil(father.sons): father.sons = @[]
+  add(father.sons, son)
+  if not son.isNil: propagateToOwner(father, son)
+
+proc addSonNilAllowed*(father, son: PNode) =
+  if isNil(father.sons): father.sons = @[]
+  add(father.sons, son)
+
+proc delSon*(father: PNode, idx: int) =
+  if isNil(father.sons): return
+  var length = sonsLen(father)
+  for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
+  setLen(father.sons, length - 1)
+
+proc copyNode*(src: PNode): PNode =
+  # does not copy its sons!
+  if src == nil:
+    return nil
+  result = newNode(src.kind)
+  result.info = src.info
+  result.typ = src.typ
+  result.flags = src.flags * PersistentNodeFlags
+  when defined(useNodeIds):
+    if result.id == nodeIdToDebug:
+      echo "COMES FROM ", src.id
+  case src.kind
+  of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
+  of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
+  of nkSym: result.sym = src.sym
+  of nkIdent: result.ident = src.ident
+  of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
+  else: discard
+
+proc shallowCopy*(src: PNode): PNode =
+  # does not copy its sons, but provides space for them:
+  if src == nil: return nil
+  result = newNode(src.kind)
+  result.info = src.info
+  result.typ = src.typ
+  result.flags = src.flags * PersistentNodeFlags
+  when defined(useNodeIds):
+    if result.id == nodeIdToDebug:
+      echo "COMES FROM ", src.id
+  case src.kind
+  of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
+  of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
+  of nkSym: result.sym = src.sym
+  of nkIdent: result.ident = src.ident
+  of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
+  else: newSeq(result.sons, sonsLen(src))
+
+proc copyTree*(src: PNode): PNode =
+  # copy a whole syntax tree; performs deep copying
+  if src == nil:
+    return nil
+  result = newNode(src.kind)
+  result.info = src.info
+  result.typ = src.typ
+  result.flags = src.flags * PersistentNodeFlags
+  when defined(useNodeIds):
+    if result.id == nodeIdToDebug:
+      echo "COMES FROM ", src.id
+  case src.kind
+  of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
+  of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
+  of nkSym: result.sym = src.sym
+  of nkIdent: result.ident = src.ident
+  of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
+  else:
+    newSeq(result.sons, sonsLen(src))
+    for i in countup(0, sonsLen(src) - 1):
+      result.sons[i] = copyTree(src.sons[i])
+
+proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i].kind == kind:
+      return true
+  result = false
+
+proc hasNilSon*(n: PNode): bool =
+  for i in countup(0, safeLen(n) - 1):
+    if n.sons[i] == nil:
+      return true
+    elif hasNilSon(n.sons[i]):
+      return true
+  result = false
+
+proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
+  if n == nil: return
+  case n.kind
+  of nkEmpty..nkNilLit: result = n.kind in kinds
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      if n.kind in kinds or containsNode(n.sons[i], kinds): return true
+
+proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
+  case n.kind
+  of nkEmpty..nkNilLit: result = n.kind == kind
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      if (n.sons[i].kind == kind) or hasSubnodeWith(n.sons[i], kind):
+        return true
+    result = false
+
+proc replaceSons(n: PNode, oldKind, newKind: TNodeKind) =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i].kind == oldKind: n.sons[i].kind = newKind
+
+proc sonsNotNil(n: PNode): bool =
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i] == nil:
+      return false
+  result = true
+
+proc getInt*(a: PNode): BiggestInt =
+  case a.kind
+  of nkIntLit..nkUInt64Lit: result = a.intVal
+  else:
+    internalError(a.info, "getInt")
+    result = 0
+
+proc getFloat*(a: PNode): BiggestFloat =
+  case a.kind
+  of nkFloatLit..nkFloat128Lit: result = a.floatVal
+  else:
+    internalError(a.info, "getFloat")
+    result = 0.0
+
+proc getStr*(a: PNode): string =
+  case a.kind
+  of nkStrLit..nkTripleStrLit: result = a.strVal
+  else:
+    internalError(a.info, "getStr")
+    result = ""
+
+proc getStrOrChar*(a: PNode): string =
+  case a.kind
+  of nkStrLit..nkTripleStrLit: result = a.strVal
+  of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
+  else:
+    internalError(a.info, "getStrOrChar")
+    result = ""
+
+proc isGenericRoutine*(s: PSym): bool =
+  case s.kind
+  of skProcKinds:
+    result = sfFromGeneric in s.flags or
+             (s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty)
+  else: discard
+
+proc skipGenericOwner*(s: PSym): PSym =
+  internalAssert s.kind in skProcKinds
+  ## Generic instantiations are owned by their originating generic
+  ## symbol. This proc skips such owners and goes straight to the owner
+  ## of the generic itself (the module or the enclosing proc).
+  result = if sfFromGeneric in s.flags: s.owner.owner
+           else: s.owner
+
+proc originatingModule*(s: PSym): PSym =
+  result = s.owner
+  while result.kind != skModule: result = result.owner
+
+proc isRoutine*(s: PSym): bool {.inline.} =
+  result = s.kind in skProcKinds
+
+proc hasPattern*(s: PSym): bool {.inline.} =
+  result = isRoutine(s) and s.ast.sons[patternPos].kind != nkEmpty
+
+iterator items*(n: PNode): PNode =
+  for i in 0.. <n.len: yield n.sons[i]
+
+iterator pairs*(n: PNode): tuple[i: int, n: PNode] =
+  for i in 0.. <n.len: yield (i, n.sons[i])
+
+proc isAtom*(n: PNode): bool {.inline.} =
+  result = n.kind >= nkNone and n.kind <= nkNilLit
+
+proc isEmptyType*(t: PType): bool {.inline.} =
+  ## 'void' and 'stmt' types are often equivalent to 'nil' these days:
+  result = t == nil or t.kind in {tyEmpty, tyStmt}
+
+proc makeStmtList*(n: PNode): PNode =
+  if n.kind == nkStmtList:
+    result = n
+  else:
+    result = newNodeI(nkStmtList, n.info)
+    result.add n
+
+proc createMagic*(name: string, m: TMagic): PSym =
+  result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
+  result.magic = m
+
+let
+  opNot* = createMagic("not", mNot)
+  opContains* = createMagic("contains", mInSet)
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
new file mode 100644
index 000000000..1707718d7
--- /dev/null
+++ b/compiler/astalgo.nim
@@ -0,0 +1,903 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Algorithms for the abstract syntax tree: hash tables, lists
+# and sets of nodes are supported. Efficiency is important as
+# the data structures here are used in various places of the compiler.
+
+import
+  ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
+
+proc hashNode*(p: RootRef): THash
+proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope
+  # Convert a tree into its YAML representation; this is used by the
+  # YAML code generator and it is invaluable for debugging purposes.
+  # If maxRecDepht <> -1 then it won't print the whole graph.
+proc typeToYaml*(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope
+proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope
+proc lineInfoToStr*(info: TLineInfo): Rope
+
+# ----------------------- node sets: ---------------------------------------
+proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
+  # returns true whether n is in t
+proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
+  # include an element n in the table t
+proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
+  # more are not needed ...
+
+# ----------------------- (key, val)-Hashtables ----------------------------
+proc tablePut*(t: var TTable, key, val: RootRef)
+proc tableGet*(t: TTable, key: RootRef): RootRef
+type
+  TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
+
+proc tableSearch*(t: TTable, key, closure: RootRef,
+                  comparator: TCmpProc): RootRef
+  # return val as soon as comparator returns true; if this never happens,
+  # nil is returned
+
+# ----------------------- str table -----------------------------------------
+proc strTableContains*(t: TStrTable, n: PSym): bool
+proc strTableAdd*(t: var TStrTable, n: PSym)
+proc strTableGet*(t: TStrTable, name: PIdent): PSym
+
+type
+  TTabIter*{.final.} = object # consider all fields here private
+    h*: THash                 # current hash
+
+proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym
+proc nextIter*(ti: var TTabIter, tab: TStrTable): PSym
+  # usage:
+  # var
+  #   i: TTabIter
+  #   s: PSym
+  # s = InitTabIter(i, table)
+  # while s != nil:
+  #   ...
+  #   s = NextIter(i, table)
+  #
+
+type
+  TIdentIter*{.final.} = object # iterator over all syms with same identifier
+    h*: THash                   # current hash
+    name*: PIdent
+
+
+proc initIdentIter*(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym
+proc nextIdentIter*(ti: var TIdentIter, tab: TStrTable): PSym
+
+# these are for debugging only: They are not really deprecated, but I want
+# the warning so that release versions do not contain debugging statements:
+proc debug*(n: PSym) {.deprecated.}
+proc debug*(n: PType) {.deprecated.}
+proc debug*(n: PNode) {.deprecated.}
+
+# --------------------------- ident tables ----------------------------------
+proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
+proc idTableGet*(t: TIdTable, key: int): RootRef
+proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
+proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
+  # checks if `t` contains the `key` (compared by the pointer value, not only
+  # `key`'s id)
+proc idNodeTableGet*(t: TIdNodeTable, key: PIdObj): PNode
+proc idNodeTablePut*(t: var TIdNodeTable, key: PIdObj, val: PNode)
+
+# ---------------------------------------------------------------------------
+
+proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
+proc lookupInRecord*(n: PNode, field: PIdent): PSym
+proc getModule*(s: PSym): PSym
+proc mustRehash*(length, counter: int): bool
+proc nextTry*(h, maxHash: THash): THash {.inline.}
+
+# ------------- table[int, int] ---------------------------------------------
+const
+  InvalidKey* = low(int)
+
+type
+  TIIPair*{.final.} = object
+    key*, val*: int
+
+  TIIPairSeq* = seq[TIIPair]
+  TIITable*{.final.} = object # table[int, int]
+    counter*: int
+    data*: TIIPairSeq
+
+
+proc initIiTable*(x: var TIITable)
+proc iiTableGet*(t: TIITable, key: int): int
+proc iiTablePut*(t: var TIITable, key, val: int)
+
+# implementation
+
+proc skipConvAndClosure*(n: PNode): PNode =
+  result = n
+  while true:
+    case result.kind
+    of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64,
+       nkClosure:
+      result = result.sons[0]
+    of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+      result = result.sons[1]
+    else: break
+
+proc sameValue*(a, b: PNode): bool =
+  result = false
+  case a.kind
+  of nkCharLit..nkUInt64Lit:
+    if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
+  of nkFloatLit..nkFloat64Lit:
+    if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
+  of nkStrLit..nkTripleStrLit:
+    if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal == b.strVal
+  else:
+    # don't raise an internal error for 'nimrod check':
+    #InternalError(a.info, "SameValue")
+    discard
+
+proc leValue*(a, b: PNode): bool =
+  # a <= b?
+  result = false
+  case a.kind
+  of nkCharLit..nkUInt32Lit:
+    if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
+  of nkFloatLit..nkFloat64Lit:
+    if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
+  of nkStrLit..nkTripleStrLit:
+    if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
+  else:
+    # don't raise an internal error for 'nimrod check':
+    #InternalError(a.info, "leValue")
+    discard
+
+proc weakLeValue*(a, b: PNode): TImplication =
+  if a.kind notin nkLiterals or b.kind notin nkLiterals:
+    result = impUnknown
+  else:
+    result = if leValue(a, b): impYes else: impNo
+
+proc lookupInRecord(n: PNode, field: PIdent): PSym =
+  result = nil
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      result = lookupInRecord(n.sons[i], field)
+      if result != nil: return
+  of nkRecCase:
+    if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
+    result = lookupInRecord(n.sons[0], field)
+    if result != nil: return
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        result = lookupInRecord(lastSon(n.sons[i]), field)
+        if result != nil: return
+      else: internalError(n.info, "lookupInRecord(record case branch)")
+  of nkSym:
+    if n.sym.name.id == field.id: result = n.sym
+  else: internalError(n.info, "lookupInRecord()")
+
+proc getModule(s: PSym): PSym =
+  result = s
+  assert((result.kind == skModule) or (result.owner != result))
+  while result != nil and result.kind != skModule: result = result.owner
+
+proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
+  for i in countup(start, sonsLen(list) - 1):
+    if list.sons[i].kind == nkSym:
+      result = list.sons[i].sym
+      if result.name.id == ident.id: return
+    else: internalError(list.info, "getSymFromList")
+  result = nil
+
+proc hashNode(p: RootRef): THash =
+  result = hash(cast[pointer](p))
+
+proc mustRehash(length, counter: int): bool =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc rspaces(x: int): Rope =
+  # returns x spaces
+  result = rope(spaces(x))
+
+proc toYamlChar(c: char): string =
+  case c
+  of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
+  of '\'', '\"', '\\': result = '\\' & c
+  else: result = $c
+
+proc makeYamlString*(s: string): Rope =
+  # We have to split long strings into many ropes. Otherwise
+  # this could trigger InternalError(111). See the ropes module for
+  # further information.
+  const MaxLineLength = 64
+  result = nil
+  var res = "\""
+  for i in countup(0, if s.isNil: -1 else: (len(s)-1)):
+    if (i + 1) mod MaxLineLength == 0:
+      add(res, '\"')
+      add(res, "\n")
+      add(result, rope(res))
+      res = "\""              # reset
+    add(res, toYamlChar(s[i]))
+  add(res, '\"')
+  add(result, rope(res))
+
+proc flagsToStr[T](flags: set[T]): Rope =
+  if flags == {}:
+    result = rope("[]")
+  else:
+    result = nil
+    for x in items(flags):
+      if result != nil: add(result, ", ")
+      add(result, makeYamlString($x))
+    result = "[" & result & "]"
+
+proc lineInfoToStr(info: TLineInfo): Rope =
+  result = "[$1, $2, $3]" % [makeYamlString(toFilename(info)),
+                             rope(toLinenumber(info)),
+                             rope(toColumn(info))]
+
+proc treeToYamlAux(n: PNode, marker: var IntSet,
+                   indent, maxRecDepth: int): Rope
+proc symToYamlAux(n: PSym, marker: var IntSet,
+                  indent, maxRecDepth: int): Rope
+proc typeToYamlAux(n: PType, marker: var IntSet,
+                   indent, maxRecDepth: int): Rope
+proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
+                    maxRecDepth: int): Rope =
+  var istr = rspaces(indent + 2)
+  result = rope("[")
+  var mycount = 0
+  for i in countup(0, high(n.data)):
+    if n.data[i] != nil:
+      if mycount > 0: add(result, ",")
+      addf(result, "$N$1$2",
+           [istr, symToYamlAux(n.data[i], marker, indent + 2, maxRecDepth - 1)])
+      inc(mycount)
+  if mycount > 0: addf(result, "$N$1", [rspaces(indent)])
+  add(result, "]")
+  assert(mycount == n.counter)
+
+proc ropeConstr(indent: int, c: openArray[Rope]): Rope =
+  # array of (name, value) pairs
+  var istr = rspaces(indent + 2)
+  result = rope("{")
+  var i = 0
+  while i <= high(c):
+    if i > 0: add(result, ",")
+    addf(result, "$N$1\"$2\": $3", [istr, c[i], c[i + 1]])
+    inc(i, 2)
+  addf(result, "$N$1}", [rspaces(indent)])
+
+proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
+                  maxRecDepth: int): Rope =
+  if n == nil:
+    result = rope("null")
+  elif containsOrIncl(marker, n.id):
+    result = "\"$1 @$2\"" % [rope(n.name.s), rope(
+        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+  else:
+    var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
+    result = ropeConstr(indent, [rope("kind"),
+                                 makeYamlString($n.kind),
+                                 rope("name"), makeYamlString(n.name.s),
+                                 rope("typ"), typeToYamlAux(n.typ, marker,
+                                   indent + 2, maxRecDepth - 1),
+                                 rope("info"), lineInfoToStr(n.info),
+                                 rope("flags"), flagsToStr(n.flags),
+                                 rope("magic"), makeYamlString($n.magic),
+                                 rope("ast"), ast, rope("options"),
+                                 flagsToStr(n.options), rope("position"),
+                                 rope(n.position)])
+
+proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
+                   maxRecDepth: int): Rope =
+  if n == nil:
+    result = rope("null")
+  elif containsOrIncl(marker, n.id):
+    result = "\"$1 @$2\"" % [rope($n.kind), rope(
+        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+  else:
+    if sonsLen(n) > 0:
+      result = rope("[")
+      for i in countup(0, sonsLen(n) - 1):
+        if i > 0: add(result, ",")
+        addf(result, "$N$1$2", [rspaces(indent + 4), typeToYamlAux(n.sons[i],
+            marker, indent + 4, maxRecDepth - 1)])
+      addf(result, "$N$1]", [rspaces(indent + 2)])
+    else:
+      result = rope("null")
+    result = ropeConstr(indent, [rope("kind"),
+                                 makeYamlString($n.kind),
+                                 rope("sym"), symToYamlAux(n.sym, marker,
+        indent + 2, maxRecDepth - 1), rope("n"), treeToYamlAux(n.n, marker,
+        indent + 2, maxRecDepth - 1), rope("flags"), flagsToStr(n.flags),
+                                 rope("callconv"),
+                                 makeYamlString(CallingConvToStr[n.callConv]),
+                                 rope("size"), rope(n.size),
+                                 rope("align"), rope(n.align),
+                                 rope("sons"), result])
+
+proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
+                   maxRecDepth: int): Rope =
+  if n == nil:
+    result = rope("null")
+  else:
+    var istr = rspaces(indent + 2)
+    result = "{$N$1\"kind\": $2" % [istr, makeYamlString($n.kind)]
+    if maxRecDepth != 0:
+      addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
+      case n.kind
+      of nkCharLit..nkInt64Lit:
+        addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+      of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+        addf(result, ",$N$1\"floatVal\": $2",
+            [istr, rope(n.floatVal.toStrMaxPrecision)])
+      of nkStrLit..nkTripleStrLit:
+        if n.strVal.isNil:
+          addf(result, ",$N$1\"strVal\": null", [istr])
+        else:
+          addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+      of nkSym:
+        addf(result, ",$N$1\"sym\": $2",
+             [istr, symToYamlAux(n.sym, marker, indent + 2, maxRecDepth)])
+      of nkIdent:
+        if n.ident != nil:
+          addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+        else:
+          addf(result, ",$N$1\"ident\": null", [istr])
+      else:
+        if sonsLen(n) > 0:
+          addf(result, ",$N$1\"sons\": [", [istr])
+          for i in countup(0, sonsLen(n) - 1):
+            if i > 0: add(result, ",")
+            addf(result, "$N$1$2", [rspaces(indent + 4), treeToYamlAux(n.sons[i],
+                marker, indent + 4, maxRecDepth - 1)])
+          addf(result, "$N$1]", [istr])
+      addf(result, ",$N$1\"typ\": $2",
+           [istr, typeToYamlAux(n.typ, marker, indent + 2, maxRecDepth)])
+    addf(result, "$N$1}", [rspaces(indent)])
+
+proc treeToYaml(n: PNode, indent: int = 0, maxRecDepth: int = - 1): Rope =
+  var marker = initIntSet()
+  result = treeToYamlAux(n, marker, indent, maxRecDepth)
+
+proc typeToYaml(n: PType, indent: int = 0, maxRecDepth: int = - 1): Rope =
+  var marker = initIntSet()
+  result = typeToYamlAux(n, marker, indent, maxRecDepth)
+
+proc symToYaml(n: PSym, indent: int = 0, maxRecDepth: int = - 1): Rope =
+  var marker = initIntSet()
+  result = symToYamlAux(n, marker, indent, maxRecDepth)
+
+proc debugTree*(n: PNode, indent: int, maxRecDepth: int; renderType=false): Rope
+proc debugType(n: PType, maxRecDepth=100): Rope =
+  if n == nil:
+    result = rope("null")
+  else:
+    result = rope($n.kind)
+    if n.sym != nil:
+      add(result, " ")
+      add(result, n.sym.name.s)
+    if n.kind in IntegralTypes and n.n != nil:
+      add(result, ", node: ")
+      add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
+    if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
+      add(result, "(")
+      for i in countup(0, sonsLen(n) - 1):
+        if i > 0: add(result, ", ")
+        if n.sons[i] == nil:
+          add(result, "null")
+        else:
+          add(result, debugType(n.sons[i], maxRecDepth-1))
+      if n.kind == tyObject and n.n != nil:
+        add(result, ", node: ")
+        add(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
+      add(result, ")")
+
+proc debugTree(n: PNode, indent: int, maxRecDepth: int;
+               renderType=false): Rope =
+  if n == nil:
+    result = rope("null")
+  else:
+    var istr = rspaces(indent + 2)
+    result = "{$N$1\"kind\": $2" %
+             [istr, makeYamlString($n.kind)]
+    if maxRecDepth != 0:
+      case n.kind
+      of nkCharLit..nkUInt64Lit:
+        addf(result, ",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
+      of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
+        addf(result, ",$N$1\"floatVal\": $2",
+            [istr, rope(n.floatVal.toStrMaxPrecision)])
+      of nkStrLit..nkTripleStrLit:
+        if n.strVal.isNil:
+          addf(result, ",$N$1\"strVal\": null", [istr])
+        else:
+          addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
+      of nkSym:
+        addf(result, ",$N$1\"sym\": $2_$3",
+            [istr, rope(n.sym.name.s), rope(n.sym.id)])
+        #     [istr, symToYaml(n.sym, indent, maxRecDepth),
+        #     rope(n.sym.id)])
+        if renderType and n.sym.typ != nil:
+          addf(result, ",$N$1\"typ\": $2", [istr, debugType(n.sym.typ, 2)])
+      of nkIdent:
+        if n.ident != nil:
+          addf(result, ",$N$1\"ident\": $2", [istr, makeYamlString(n.ident.s)])
+        else:
+          addf(result, ",$N$1\"ident\": null", [istr])
+      else:
+        if sonsLen(n) > 0:
+          addf(result, ",$N$1\"sons\": [", [istr])
+          for i in countup(0, sonsLen(n) - 1):
+            if i > 0: add(result, ",")
+            addf(result, "$N$1$2", [rspaces(indent + 4), debugTree(n.sons[i],
+                indent + 4, maxRecDepth - 1, renderType)])
+          addf(result, "$N$1]", [istr])
+    addf(result, ",$N$1\"info\": $2", [istr, lineInfoToStr(n.info)])
+    addf(result, "$N$1}", [rspaces(indent)])
+
+proc debug(n: PSym) =
+  if n == nil:
+    msgWriteln("null")
+  elif n.kind == skUnknown:
+    msgWriteln("skUnknown")
+  else:
+    #writeln(stdout, $symToYaml(n, 0, 1))
+    msgWriteln("$1_$2: $3, $4, $5, $6" % [
+      n.name.s, $n.id, $flagsToStr(n.flags), $flagsToStr(n.loc.flags),
+      $lineInfoToStr(n.info), $n.kind])
+
+proc debug(n: PType) =
+  msgWriteln($debugType(n))
+
+proc debug(n: PNode) =
+  msgWriteln($debugTree(n, 0, 100))
+
+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 objectSetContains(t: TObjectSet, obj: RootRef): bool =
+  # returns true whether n is in t
+  var h: THash = hashNode(obj) and high(t.data) # start with real hash value
+  while t.data[h] != nil:
+    if t.data[h] == obj:
+      return true
+    h = nextTry(h, high(t.data))
+  result = false
+
+proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
+  var h: THash = hashNode(obj) and high(data)
+  while data[h] != nil:
+    assert(data[h] != obj)
+    h = nextTry(h, high(data))
+  assert(data[h] == nil)
+  data[h] = obj
+
+proc objectSetEnlarge(t: var TObjectSet) =
+  var n: TObjectSeq
+  newSeq(n, len(t.data) * GrowthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
+  swap(t.data, n)
+
+proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
+  if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
+  objectSetRawInsert(t.data, obj)
+  inc(t.counter)
+
+proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
+  # returns true if obj is already in the string table:
+  var h: THash = hashNode(obj) and high(t.data)
+  while true:
+    var it = t.data[h]
+    if it == nil: break
+    if it == obj:
+      return true             # found it
+    h = nextTry(h, high(t.data))
+  if mustRehash(len(t.data), t.counter):
+    objectSetEnlarge(t)
+    objectSetRawInsert(t.data, obj)
+  else:
+    assert(t.data[h] == nil)
+    t.data[h] = obj
+  inc(t.counter)
+  result = false
+
+proc tableRawGet(t: TTable, key: RootRef): int =
+  var h: THash = hashNode(key) and high(t.data) # start with real hash value
+  while t.data[h].key != nil:
+    if t.data[h].key == key:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+proc tableSearch(t: TTable, key, closure: RootRef,
+                 comparator: TCmpProc): RootRef =
+  var h: THash = hashNode(key) and high(t.data) # start with real hash value
+  while t.data[h].key != nil:
+    if t.data[h].key == key:
+      if comparator(t.data[h].val, closure):
+        # BUGFIX 1
+        return t.data[h].val
+    h = nextTry(h, high(t.data))
+  result = nil
+
+proc tableGet(t: TTable, key: RootRef): RootRef =
+  var index = tableRawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = nil
+
+proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
+  var h: THash = hashNode(key) and high(data)
+  while data[h].key != nil:
+    assert(data[h].key != key)
+    h = nextTry(h, high(data))
+  assert(data[h].key == nil)
+  data[h].key = key
+  data[h].val = val
+
+proc tableEnlarge(t: var TTable) =
+  var n: TPairSeq
+  newSeq(n, len(t.data) * GrowthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc tablePut(t: var TTable, key, val: RootRef) =
+  var index = tableRawGet(t, key)
+  if index >= 0:
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter): tableEnlarge(t)
+    tableRawInsert(t.data, key, val)
+    inc(t.counter)
+
+proc strTableContains(t: TStrTable, n: PSym): bool =
+  var h: THash = n.name.h and high(t.data) # start with real hash value
+  while t.data[h] != nil:
+    if (t.data[h] == n):
+      return true
+    h = nextTry(h, high(t.data))
+  result = false
+
+proc strTableRawInsert(data: var TSymSeq, n: PSym) =
+  var h: THash = n.name.h and high(data)
+  if sfImmediate notin n.flags:
+    # fast path:
+    while data[h] != nil:
+      if data[h] == n:
+        # allowed for 'export' feature:
+        #InternalError(n.info, "StrTableRawInsert: " & n.name.s)
+        return
+      h = nextTry(h, high(data))
+    assert(data[h] == nil)
+    data[h] = n
+  else:
+    # slow path; we have to ensure immediate symbols are preferred for
+    # symbol lookups.
+    # consider the chain: foo (immediate), foo, bar, bar (immediate)
+    # then bar (immediate) gets replaced with foo (immediate) and the non
+    # immediate foo is picked! Thus we need to replace it with the first
+    # slot that has in fact the same identifier stored in it!
+    var favPos = -1
+    while data[h] != nil:
+      if data[h] == n: return
+      if favPos < 0 and data[h].name.id == n.name.id: favPos = h
+      h = nextTry(h, high(data))
+    assert(data[h] == nil)
+    data[h] = n
+    if favPos >= 0: swap data[h], data[favPos]
+
+proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
+  assert prevSym.name.h == newSym.name.h
+  var h: THash = prevSym.name.h and high(data)
+  while data[h] != nil:
+    if data[h] == prevSym:
+      data[h] = newSym
+      return
+    h = nextTry(h, high(data))
+  assert false
+
+proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
+  symTabReplaceRaw(t.data, prevSym, newSym)
+
+proc strTableEnlarge(t: var TStrTable) =
+  var n: TSymSeq
+  newSeq(n, len(t.data) * GrowthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i] != nil: strTableRawInsert(n, t.data[i])
+  swap(t.data, n)
+
+proc strTableAdd(t: var TStrTable, n: PSym) =
+  if mustRehash(len(t.data), t.counter): strTableEnlarge(t)
+  strTableRawInsert(t.data, n)
+  inc(t.counter)
+
+proc reallySameIdent(a, b: string): bool {.inline.} =
+  when defined(nimfix):
+    result = a[0] == b[0]
+  else:
+    result = true
+
+proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
+  # returns true if n is already in the string table:
+  # It is essential that `n` is written nevertheless!
+  # This way the newest redefinition is picked by the semantic analyses!
+  assert n.name != nil
+  var h: THash = n.name.h and high(t.data)
+  var replaceSlot = -1
+  while true:
+    var it = t.data[h]
+    if it == nil: break
+    # Semantic checking can happen multiple times thanks to templates
+    # and overloading: (var x=@[]; x).mapIt(it).
+    # So it is possible the very same sym is added multiple
+    # times to the symbol table which we allow here with the 'it == n' check.
+    if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s):
+      if it == n: return false
+      replaceSlot = h
+    h = nextTry(h, high(t.data))
+  if replaceSlot >= 0:
+    t.data[replaceSlot] = n # overwrite it with newer definition!
+    return true             # found it
+  elif mustRehash(len(t.data), t.counter):
+    strTableEnlarge(t)
+    strTableRawInsert(t.data, n)
+  else:
+    assert(t.data[h] == nil)
+    t.data[h] = n
+  inc(t.counter)
+  result = false
+
+proc strTableGet(t: TStrTable, name: PIdent): PSym =
+  var h: THash = name.h and high(t.data)
+  while true:
+    result = t.data[h]
+    if result == nil: break
+    if result.name.id == name.id: break
+    h = nextTry(h, high(t.data))
+
+proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
+  ti.h = s.h
+  ti.name = s
+  if tab.counter == 0: result = nil
+  else: result = nextIdentIter(ti, tab)
+
+proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
+  var h = ti.h and high(tab.data)
+  var start = h
+  result = tab.data[h]
+  while result != nil:
+    if result.name.id == ti.name.id: break
+    h = nextTry(h, high(tab.data))
+    if h == start:
+      result = nil
+      break
+    result = tab.data[h]
+  ti.h = nextTry(h, high(tab.data))
+
+proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
+                         excluding: IntSet): PSym =
+  var h: THash = ti.h and high(tab.data)
+  var start = h
+  result = tab.data[h]
+  while result != nil:
+    if result.name.id == ti.name.id and not contains(excluding, result.id):
+      break
+    h = nextTry(h, high(tab.data))
+    if h == start:
+      result = nil
+      break
+    result = tab.data[h]
+  ti.h = nextTry(h, high(tab.data))
+  if result != nil and contains(excluding, result.id): result = nil
+
+proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
+                          excluding: IntSet): PSym =
+  ti.h = s.h
+  ti.name = s
+  if tab.counter == 0: result = nil
+  else: result = nextIdentExcluding(ti, tab, excluding)
+
+proc initTabIter(ti: var TTabIter, tab: TStrTable): PSym =
+  ti.h = 0                    # we start by zero ...
+  if tab.counter == 0:
+    result = nil              # FIX 1: removed endless loop
+  else:
+    result = nextIter(ti, tab)
+
+proc nextIter(ti: var TTabIter, tab: TStrTable): PSym =
+  result = nil
+  while (ti.h <= high(tab.data)):
+    result = tab.data[ti.h]
+    inc(ti.h)                 # ... and increment by one always
+    if result != nil: break
+
+iterator items*(tab: TStrTable): PSym =
+  var it: TTabIter
+  var s = initTabIter(it, tab)
+  while s != nil:
+    yield s
+    s = nextIter(it, tab)
+
+proc hasEmptySlot(data: TIdPairSeq): bool =
+  for h in countup(0, high(data)):
+    if data[h].key == nil:
+      return true
+  result = false
+
+proc idTableRawGet(t: TIdTable, key: int): int =
+  var h: THash
+  h = key and high(t.data)    # start with real hash value
+  while t.data[h].key != nil:
+    if t.data[h].key.id == key:
+      return h
+    h = nextTry(h, high(t.data))
+  result = - 1
+
+proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
+  var index = idTableRawGet(t, key.id)
+  if index >= 0: result = t.data[index].key == key
+  else: result = false
+
+proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
+  var index = idTableRawGet(t, key.id)
+  if index >= 0: result = t.data[index].val
+  else: result = nil
+
+proc idTableGet(t: TIdTable, key: int): RootRef =
+  var index = idTableRawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = nil
+
+iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
+  for i in 0..high(t.data):
+    if t.data[i].key != nil:
+      yield (t.data[i].key.id, t.data[i].val)
+
+proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
+  var h: THash
+  h = key.id and high(data)
+  while data[h].key != nil:
+    assert(data[h].key.id != key.id)
+    h = nextTry(h, high(data))
+  assert(data[h].key == nil)
+  data[h].key = key
+  data[h].val = val
+
+proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
+  var
+    index: int
+    n: TIdPairSeq
+  index = idTableRawGet(t, key.id)
+  if index >= 0:
+    assert(t.data[index].key != nil)
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter):
+      newSeq(n, len(t.data) * GrowthFactor)
+      for i in countup(0, high(t.data)):
+        if t.data[i].key != nil:
+          idTableRawInsert(n, t.data[i].key, t.data[i].val)
+      assert(hasEmptySlot(n))
+      swap(t.data, n)
+    idTableRawInsert(t.data, key, val)
+    inc(t.counter)
+
+iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
+  for i in 0 .. high(t.data):
+    if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
+
+proc idNodeTableRawGet(t: TIdNodeTable, key: PIdObj): int =
+  var h: THash
+  h = key.id and high(t.data) # start with real hash value
+  while t.data[h].key != nil:
+    if t.data[h].key.id == key.id:
+      return h
+    h = nextTry(h, high(t.data))
+  result = - 1
+
+proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode =
+  var index: int
+  index = idNodeTableRawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = nil
+
+proc idNodeTableGetLazy*(t: TIdNodeTable, key: PIdObj): PNode =
+  if not isNil(t.data):
+    result = idNodeTableGet(t, key)
+
+proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) =
+  var h: THash
+  h = key.id and high(data)
+  while data[h].key != nil:
+    assert(data[h].key.id != key.id)
+    h = nextTry(h, high(data))
+  assert(data[h].key == nil)
+  data[h].key = key
+  data[h].val = val
+
+proc idNodeTablePut(t: var TIdNodeTable, key: PIdObj, val: PNode) =
+  var index = idNodeTableRawGet(t, key)
+  if index >= 0:
+    assert(t.data[index].key != nil)
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter):
+      var n: TIdNodePairSeq
+      newSeq(n, len(t.data) * GrowthFactor)
+      for i in countup(0, high(t.data)):
+        if t.data[i].key != nil:
+          idNodeTableRawInsert(n, t.data[i].key, t.data[i].val)
+      swap(t.data, n)
+    idNodeTableRawInsert(t.data, key, val)
+    inc(t.counter)
+
+proc idNodeTablePutLazy*(t: var TIdNodeTable, key: PIdObj, val: PNode) =
+  if isNil(t.data): initIdNodeTable(t)
+  idNodeTablePut(t, key, val)
+
+iterator pairs*(t: TIdNodeTable): tuple[key: PIdObj, val: PNode] =
+  for i in 0 .. high(t.data):
+    if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
+
+proc initIITable(x: var TIITable) =
+  x.counter = 0
+  newSeq(x.data, StartSize)
+  for i in countup(0, StartSize - 1): x.data[i].key = InvalidKey
+
+proc iiTableRawGet(t: TIITable, key: int): int =
+  var h: THash
+  h = key and high(t.data)    # start with real hash value
+  while t.data[h].key != InvalidKey:
+    if t.data[h].key == key: return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+proc iiTableGet(t: TIITable, key: int): int =
+  var index = iiTableRawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = InvalidKey
+
+proc iiTableRawInsert(data: var TIIPairSeq, key, val: int) =
+  var h: THash
+  h = key and high(data)
+  while data[h].key != InvalidKey:
+    assert(data[h].key != key)
+    h = nextTry(h, high(data))
+  assert(data[h].key == InvalidKey)
+  data[h].key = key
+  data[h].val = val
+
+proc iiTablePut(t: var TIITable, key, val: int) =
+  var index = iiTableRawGet(t, key)
+  if index >= 0:
+    assert(t.data[index].key != InvalidKey)
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter):
+      var n: TIIPairSeq
+      newSeq(n, len(t.data) * GrowthFactor)
+      for i in countup(0, high(n)): n[i].key = InvalidKey
+      for i in countup(0, high(t.data)):
+        if t.data[i].key != InvalidKey:
+          iiTableRawInsert(n, t.data[i].key, t.data[i].val)
+      swap(t.data, n)
+    iiTableRawInsert(t.data, key, val)
+    inc(t.counter)
diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim
new file mode 100644
index 000000000..a2324f4e2
--- /dev/null
+++ b/compiler/bitsets.nim
@@ -0,0 +1,71 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# this unit handles Nim sets; it implements bit sets
+# the code here should be reused in the Nim standard library
+
+type 
+  TBitSet* = seq[int8]        # we use byte here to avoid issues with
+                              # cross-compiling; uint would be more efficient
+                              # however
+
+const 
+  ElemSize* = sizeof(int8) * 8
+
+proc bitSetInit*(b: var TBitSet, length: int)
+proc bitSetUnion*(x: var TBitSet, y: TBitSet)
+proc bitSetDiff*(x: var TBitSet, y: TBitSet)
+proc bitSetSymDiff*(x: var TBitSet, y: TBitSet)
+proc bitSetIntersect*(x: var TBitSet, y: TBitSet)
+proc bitSetIncl*(x: var TBitSet, elem: BiggestInt)
+proc bitSetExcl*(x: var TBitSet, elem: BiggestInt)
+proc bitSetIn*(x: TBitSet, e: BiggestInt): bool
+proc bitSetEquals*(x, y: TBitSet): bool
+proc bitSetContains*(x, y: TBitSet): bool
+# implementation
+
+proc bitSetIn(x: TBitSet, e: BiggestInt): bool = 
+  result = (x[int(e div ElemSize)] and toU8(int(1 shl (e mod ElemSize)))) !=
+      toU8(0)
+
+proc bitSetIncl(x: var TBitSet, elem: BiggestInt) = 
+  assert(elem >= 0)
+  x[int(elem div ElemSize)] = x[int(elem div ElemSize)] or
+      toU8(int(1 shl (elem mod ElemSize)))
+
+proc bitSetExcl(x: var TBitSet, elem: BiggestInt) = 
+  x[int(elem div ElemSize)] = x[int(elem div ElemSize)] and
+      not toU8(int(1 shl (elem mod ElemSize)))
+
+proc bitSetInit(b: var TBitSet, length: int) = 
+  newSeq(b, length)
+
+proc bitSetUnion(x: var TBitSet, y: TBitSet) = 
+  for i in countup(0, high(x)): x[i] = x[i] or y[i]
+  
+proc bitSetDiff(x: var TBitSet, y: TBitSet) = 
+  for i in countup(0, high(x)): x[i] = x[i] and not y[i]
+  
+proc bitSetSymDiff(x: var TBitSet, y: TBitSet) = 
+  for i in countup(0, high(x)): x[i] = x[i] xor y[i]
+  
+proc bitSetIntersect(x: var TBitSet, y: TBitSet) = 
+  for i in countup(0, high(x)): x[i] = x[i] and y[i]
+  
+proc bitSetEquals(x, y: TBitSet): bool = 
+  for i in countup(0, high(x)): 
+    if x[i] != y[i]: 
+      return false
+  result = true
+
+proc bitSetContains(x, y: TBitSet): bool = 
+  for i in countup(0, high(x)): 
+    if (x[i] and not y[i]) != int8(0): 
+      return false
+  result = true
diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim
new file mode 100644
index 000000000..6fcc57a91
--- /dev/null
+++ b/compiler/canonicalizer.nim
@@ -0,0 +1,416 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the canonalization for the various caching mechanisms.
+
+import strutils, db_sqlite, md5
+
+var db: TDbConn
+
+# We *hash* the relevant information into 128 bit hashes. This should be good
+# enough to prevent any collisions.
+
+type
+  TUid = distinct MD5Digest
+
+# For name mangling we encode these hashes via a variant of base64 (called
+# 'base64a') and prepend the *primary* identifier to ease the debugging pain.
+# So a signature like:
+#
+#   proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt)
+#
+# is mangled into:
+#   gABI_MTdmOWY5MTQ1MDcyNGQ3ZA
+#
+# This is a good compromise between correctness and brevity. ;-)
+
+const

+  cb64 = [
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
+    "O", "P", "Q", "R", "S", "T" "U", "V", "W", "X", "Y", "Z", 
+    "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", 
+    "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 
+    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+    "_A", "_B"]

+

+proc toBase64a(s: cstring, len: int): string =

+  ## encodes `s` into base64 representation. After `lineLen` characters, a 

+  ## `newline` is added.

+  result = newStringOfCap(((len + 2) div 3) * 4)

+  var i = 0

+  while i < s.len - 2:

+    let a = ord(s[i])

+    let b = ord(s[i+1])

+    let c = ord(s[i+2])

+    result.add cb64[a shr 2]

+    result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]

+    result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]

+    result.add cb64[c and 0x3F]

+    inc(i, 3)

+  if i < s.len-1:

+    let a = ord(s[i])

+    let b = ord(s[i+1])

+    result.add cb64[a shr 2]

+    result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]

+    result.add cb64[((b and 0x0F) shl 2)]

+  elif i < s.len:

+    let a = ord(s[i])

+    result.add cb64[a shr 2]

+    result.add cb64[(a and 3) shl 4]

+
+proc toBase64a(u: TUid): string = toBase64a(cast[cstring](u), sizeof(u))
+
+proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
+
+proc hashSym(c: var MD5Context, s: PSym) =
+  if sfAnon in s.flags or s.kind == skGenericParam:
+    c &= ":anon"
+  else:
+    var it = s.owner
+    while it != nil: 
+      hashSym(c, it)
+      c &= "."
+      it = s.owner
+    c &= s.name.s
+
+proc hashTree(c: var MD5Context, n: PNode) =
+  if n == nil:
+    c &= "\255"
+    return
+  var k = n.kind
+  md5Update(c, cast[cstring](addr(k)), 1)
+  # we really must not hash line information. 'n.typ' is debatable but
+  # shouldn't be necessary for now and avoids potential infinite recursions.
+  case n.kind
+  of nkEmpty, nkNilLit, nkType: discard
+  of nkIdent:
+    c &= n.ident.s
+  of nkSym:
+    hashSym(c, n.sym)
+  of nkCharLit..nkUInt64Lit:
+    var v = n.intVal
+    md5Update(c, cast[cstring](addr(v)), sizeof(v))
+  of nkFloatLit..nkFloat64Lit:
+    var v = n.floatVal
+    md5Update(c, cast[cstring](addr(v)), sizeof(v))
+  of nkStrLit..nkTripleStrLit:
+    c &= n.strVal
+  else:
+    for i in 0.. <n.len: hashTree(c, n.sons[i])
+
+proc hashType(c: var MD5Context, t: PType) =
+  # modelled after 'typeToString'
+  if t == nil: 
+    c &= "\254"
+    return
+
+  var k = t.kind
+  md5Update(c, cast[cstring](addr(k)), 1)
+  
+  if t.sym != nil and sfAnon notin t.sym.flags:
+    # t.n for literals, but not for e.g. objects!
+    if t.kind in {tyFloat, tyInt}: c.hashNode(t.n)
+    c.hashSym(t.sym)
+    
+  case t.kind
+  of tyGenericBody, tyGenericInst, tyGenericInvocation:
+    for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
+      c.hashType t.sons[i]
+  of tyUserTypeClass:
+    internalAssert t.sym != nil and t.sym.owner != nil
+    c &= t.sym.owner.name.s
+  of tyUserTypeClassInst:
+    let body = t.base
+    c.hashSym body.sym
+    for i in countup(1, sonsLen(t) - 2):
+      c.hashType t.sons[i]
+  of tyFromExpr, tyFieldAccessor:
+    c.hashTree(t.n)
+  of tyArrayConstr:
+    c.hashTree(t.sons[0].n)
+    c.hashType(t.sons[1])
+  of tyTuple: 
+    if t.n != nil:
+      assert(sonsLen(t.n) == sonsLen(t))
+      for i in countup(0, sonsLen(t.n) - 1): 
+        assert(t.n.sons[i].kind == nkSym)
+        c &= t.n.sons[i].sym.name.s
+        c &= ":"
+        c.hashType(t.sons[i])
+        c &= ","
+    else:
+      for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i]
+  of tyRange:
+    c.hashTree(t.n)
+    c.hashType(t.sons[0])
+  of tyProc:
+    c &= (if tfIterator in t.flags: "iterator " else: "proc ")
+    for i in 0.. <t.len: c.hashType(t.sons[i])
+    md5Update(c, cast[cstring](addr(t.callConv)), 1)
+
+    if tfNoSideEffect in t.flags: c &= ".noSideEffect"
+    if tfThread in t.flags: c &= ".thread"
+  else:
+    for i in 0.. <t.len: c.hashType(t.sons[i])
+  if tfShared in t.flags: c &= "shared"
+  if tfNotNil in t.flags: c &= "not nil"
+
+proc canonConst(n: PNode): TUid =
+  var c: MD5Context
+  md5Init(c)
+  c.hashTree(n)
+  c.hashType(n.typ)
+  md5Final(c, MD5Digest(result))
+
+proc canonSym(s: PSym): TUid =
+  var c: MD5Context
+  md5Init(c)
+  c.hashSym(s)
+  md5Final(c, MD5Digest(result))
+
+proc pushType(w: PRodWriter, t: PType) =
+  # check so that the stack does not grow too large:
+  if iiTableGet(w.index.tab, t.id) == InvalidKey:
+    w.tstack.add(t)
+
+proc pushSym(w: PRodWriter, s: PSym) =
+  # check so that the stack does not grow too large:
+  if iiTableGet(w.index.tab, s.id) == InvalidKey:
+    w.sstack.add(s)
+
+proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, 
+                result: var string) = 
+  if n == nil: 
+    # nil nodes have to be stored too:
+    result.add("()")
+    return
+  result.add('(')
+  encodeVInt(ord(n.kind), result) 
+  # we do not write comments for now
+  # Line information takes easily 20% or more of the filesize! Therefore we
+  # omit line information if it is the same as the father's line information:
+  if fInfo.fileIndex != n.info.fileIndex: 
+    result.add('?')
+    encodeVInt(n.info.col, result)
+    result.add(',')
+    encodeVInt(n.info.line, result)
+    result.add(',')
+    encodeVInt(fileIdx(w, toFilename(n.info)), result)
+  elif fInfo.line != n.info.line:
+    result.add('?')
+    encodeVInt(n.info.col, result)
+    result.add(',')
+    encodeVInt(n.info.line, result)
+  elif fInfo.col != n.info.col:
+    result.add('?')
+    encodeVInt(n.info.col, result)
+  var f = n.flags * PersistentNodeFlags
+  if f != {}: 
+    result.add('$')
+    encodeVInt(cast[int32](f), result)
+  if n.typ != nil:
+    result.add('^')
+    encodeVInt(n.typ.id, result)
+    pushType(w, n.typ)
+  case n.kind
+  of nkCharLit..nkInt64Lit: 
+    if n.intVal != 0:
+      result.add('!')
+      encodeVBiggestInt(n.intVal, result)
+  of nkFloatLit..nkFloat64Lit: 
+    if n.floatVal != 0.0: 
+      result.add('!')
+      encodeStr($n.floatVal, result)
+  of nkStrLit..nkTripleStrLit:
+    if n.strVal != "": 
+      result.add('!')
+      encodeStr(n.strVal, result)
+  of nkIdent:
+    result.add('!')
+    encodeStr(n.ident.s, result)
+  of nkSym:
+    result.add('!')
+    encodeVInt(n.sym.id, result)
+    pushSym(w, n.sym)
+  else:
+    for i in countup(0, sonsLen(n) - 1): 
+      encodeNode(w, n.info, n.sons[i], result)
+  add(result, ')')
+
+proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
+  var oldLen = result.len
+  result.add('<')
+  if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
+  if loc.s != low(loc.s):
+    add(result, '*')
+    encodeVInt(ord(loc.s), result)
+  if loc.flags != {}:
+    add(result, '$')
+    encodeVInt(cast[int32](loc.flags), result)
+  if loc.t != nil:
+    add(result, '^')
+    encodeVInt(cast[int32](loc.t.id), result)
+    pushType(w, loc.t)
+  if loc.r != nil:
+    add(result, '!')
+    encodeStr($loc.r, result)
+  if loc.a != 0:
+    add(result, '?')
+    encodeVInt(loc.a, result)
+  if oldLen + 1 == result.len:
+    # no data was necessary, so remove the '<' again:
+    setLen(result, oldLen)
+  else:
+    add(result, '>')
+  
+proc encodeType(w: PRodWriter, t: PType, result: var string) = 
+  if t == nil: 
+    # nil nodes have to be stored too:
+    result.add("[]")
+    return
+  # we need no surrounding [] here because the type is in a line of its own
+  if t.kind == tyForward: internalError("encodeType: tyForward")
+  # for the new rodfile viewer we use a preceeding [ so that the data section
+  # can easily be disambiguated:
+  add(result, '[')
+  encodeVInt(ord(t.kind), result)
+  add(result, '+')
+  encodeVInt(t.id, result)
+  if t.n != nil: 
+    encodeNode(w, unknownLineInfo(), t.n, result)
+  if t.flags != {}: 
+    add(result, '$')
+    encodeVInt(cast[int32](t.flags), result)
+  if t.callConv != low(t.callConv): 
+    add(result, '?')
+    encodeVInt(ord(t.callConv), result)
+  if t.owner != nil: 
+    add(result, '*')
+    encodeVInt(t.owner.id, result)
+    pushSym(w, t.owner)
+  if t.sym != nil: 
+    add(result, '&')
+    encodeVInt(t.sym.id, result)
+    pushSym(w, t.sym)
+  if t.size != - 1: 
+    add(result, '/')
+    encodeVBiggestInt(t.size, result)
+  if t.align != 2: 
+    add(result, '=')
+    encodeVInt(t.align, result)
+  encodeLoc(w, t.loc, result)
+  for i in countup(0, sonsLen(t) - 1): 
+    if t.sons[i] == nil: 
+      add(result, "^()")
+    else: 
+      add(result, '^') 
+      encodeVInt(t.sons[i].id, result)
+      pushType(w, t.sons[i])
+
+proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = 
+  add(result, '|')
+  encodeVInt(ord(lib.kind), result)
+  add(result, '|')
+  encodeStr($lib.name, result)
+  add(result, '|')
+  encodeNode(w, info, lib.path, result)
+
+proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
+  if s == nil:
+    # nil nodes have to be stored too:
+    result.add("{}")
+    return
+  # we need no surrounding {} here because the symbol is in a line of its own
+  encodeVInt(ord(s.kind), result)
+  result.add('+')
+  encodeVInt(s.id, result)
+  result.add('&')
+  encodeStr(s.name.s, result)
+  if s.typ != nil:
+    result.add('^')
+    encodeVInt(s.typ.id, result)
+    pushType(w, s.typ)
+  result.add('?')
+  if s.info.col != -1'i16: encodeVInt(s.info.col, result)
+  result.add(',')
+  if s.info.line != -1'i16: encodeVInt(s.info.line, result)
+  result.add(',')
+  encodeVInt(fileIdx(w, toFilename(s.info)), result)
+  if s.owner != nil:
+    result.add('*')
+    encodeVInt(s.owner.id, result)
+    pushSym(w, s.owner)
+  if s.flags != {}:
+    result.add('$')
+    encodeVInt(cast[int32](s.flags), result)
+  if s.magic != mNone:
+    result.add('@')
+    encodeVInt(ord(s.magic), result)
+  if s.options != w.options: 
+    result.add('!')
+    encodeVInt(cast[int32](s.options), result)
+  if s.position != 0: 
+    result.add('%')
+    encodeVInt(s.position, result)
+  if s.offset != - 1:
+    result.add('`')
+    encodeVInt(s.offset, result)
+  encodeLoc(w, s.loc, result)
+  if s.annex != nil: encodeLib(w, s.annex, s.info, result)
+  if s.constraint != nil:
+    add(result, '#')
+    encodeNode(w, unknownLineInfo(), s.constraint, result)
+  # lazy loading will soon reload the ast lazily, so the ast needs to be
+  # the last entry of a symbol:
+  if s.ast != nil:
+    # we used to attempt to save space here by only storing a dummy AST if
+    # it is not necessary, but Nim's heavy compile-time evaluation features
+    # make that unfeasible nowadays:
+    encodeNode(w, s.info, s.ast, result)
+
+
+proc createDb() =
+  db.exec(sql"""
+    create table if not exists Module(
+      id integer primary key,
+      name varchar(256) not null,
+      fullpath varchar(256) not null,
+      interfHash varchar(256) not null,
+      fullHash varchar(256) not null,
+      
+      created timestamp not null default (DATETIME('now')),
+    );""")
+
+  db.exec(sql"""
+    create table if not exists Symbol(
+      id integer primary key,
+      module integer not null,
+      name varchar(max) not null,
+      data varchar(max) not null,
+      created timestamp not null default (DATETIME('now')),
+
+      foreign key (module) references module(id)
+    );""")
+    
+  db.exec(sql"""
+    create table if not exists Type(
+      id integer primary key,
+      module integer not null,
+      name varchar(max) not null,
+      data varchar(max) not null,
+      created timestamp not null default (DATETIME('now')),
+
+      foreign key (module) references module(id)
+    );""")
+
+
+  #db.exec(sql"""
+  #  --create unique index if not exists TsstNameIx on TestResult(name);
+  #  """, [])
+
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
new file mode 100644
index 000000000..2dacc25e9
--- /dev/null
+++ b/compiler/ccgcalls.nim
@@ -0,0 +1,542 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+#
+# included from cgen.nim
+
+proc leftAppearsOnRightSide(le, ri: PNode): bool =
+  if le != nil:
+    for i in 1 .. <ri.len:
+      let r = ri[i]
+      if isPartOf(le, r) != arNo: return true
+
+proc hasNoInit(call: PNode): bool {.inline.} =
+  result = call.sons[0].kind == nkSym and sfNoInit in call.sons[0].sym.flags
+
+proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
+               callee, params: Rope) =
+  var pl = callee & ~"(" & params
+  # getUniqueType() is too expensive here:
+  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  if typ.sons[0] != nil:
+    if isInvalidReturnType(typ.sons[0]):
+      if params != nil: pl.add(~", ")
+      # beware of 'result = p(result)'. We may need to allocate a temporary:
+      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+        # Great, we can use 'd':
+        if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
+        elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
+          # reset before pass as 'result' var:
+          resetLoc(p, d)
+        add(pl, addrLoc(d))
+        add(pl, ~");$n")
+        line(p, cpsStmts, pl)
+      else:
+        var tmp: TLoc
+        getTemp(p, typ.sons[0], tmp, needsInit=true)
+        add(pl, addrLoc(tmp))
+        add(pl, ~");$n")
+        line(p, cpsStmts, pl)
+        genAssignment(p, d, tmp, {}) # no need for deep copying
+    else:
+      add(pl, ~")")
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
+  else:
+    add(pl, ~");$n")
+    line(p, cpsStmts, pl)
+
+proc isInCurrentFrame(p: BProc, n: PNode): bool =
+  # checks if `n` is an expression that refers to the current frame;
+  # this does not work reliably because of forwarding + inlining can break it
+  case n.kind
+  of nkSym:
+    if n.sym.kind in {skVar, skResult, skTemp, skLet} and p.prc != nil:
+      result = p.prc.id == n.sym.owner.id
+  of nkDotExpr, nkBracketExpr:
+    if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyPtr,tyRef}:
+      result = isInCurrentFrame(p, n.sons[0])
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    result = isInCurrentFrame(p, n.sons[1])
+  of nkHiddenDeref, nkDerefExpr:
+    # what about: var x = addr(y); callAsOpenArray(x[])?
+    # *shrug* ``addr`` is unsafe anyway.
+    result = false
+  of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
+    result = isInCurrentFrame(p, n.sons[0])
+  else: discard
+
+proc openArrayLoc(p: BProc, n: PNode): Rope =
+  var a: TLoc
+
+  let q = skipConv(n)
+  if getMagic(q) == mSlice:
+    # magic: pass slice to openArray:
+    var b, c: TLoc
+    initLocExpr(p, q[1], a)
+    initLocExpr(p, q[2], b)
+    initLocExpr(p, q[3], c)
+    let fmt =
+      case skipTypes(a.t, abstractVar+{tyPtr}).kind
+      of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
+        "($1)+($2), ($3)-($2)+1"
+      of tyString, tySequence:
+        if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
+          "(*$1)->data+($2), ($3)-($2)+1"
+        else:
+          "$1->data+($2), ($3)-($2)+1"
+      else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
+    result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
+  else:
+    initLocExpr(p, n, a)
+    case skipTypes(a.t, abstractVar).kind
+    of tyOpenArray, tyVarargs:
+      result = "$1, $1Len0" % [rdLoc(a)]
+    of tyString, tySequence:
+      if skipTypes(n.typ, abstractInst).kind == tyVar and
+            not compileToCpp(p.module):
+        result = "(*$1)->data, (*$1)->$2" % [a.rdLoc, lenField(p)]
+      else:
+        result = "$1->data, $1->$2" % [a.rdLoc, lenField(p)]
+    of tyArray, tyArrayConstr:
+      result = "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))]
+    else: internalError("openArrayLoc: " & typeToString(a.t))
+
+proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  result = "$1->data" % [a.rdLoc]
+
+proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
+  var a: TLoc
+  if n.kind == nkStringToCString:
+    result = genArgStringToCString(p, n)
+  elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
+    var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
+    result = openArrayLoc(p, n)
+  elif ccgIntroducedPtr(param):
+    initLocExpr(p, n, a)
+    result = addrLoc(a)
+  elif p.module.compileToCpp and param.typ.kind == tyVar and
+      n.kind == nkHiddenAddr:
+    initLocExprSingleUse(p, n.sons[0], a)
+    # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
+    # means '*T'. See posix.nim for lots of examples that do that in the wild.
+    let callee = call.sons[0]
+    if callee.kind == nkSym and
+        {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
+        {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
+      result = addrLoc(a)
+    else:
+      result = rdLoc(a)
+  else:
+    initLocExprSingleUse(p, n, a)
+    result = rdLoc(a)
+
+proc genArgNoParam(p: BProc, n: PNode): Rope =
+  var a: TLoc
+  if n.kind == nkStringToCString:
+    result = genArgStringToCString(p, n)
+  else:
+    initLocExprSingleUse(p, n, a)
+    result = rdLoc(a)
+
+proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
+  var op: TLoc
+  # this is a hotspot in the compiler
+  initLocExpr(p, ri.sons[0], op)
+  var params: Rope
+  # getUniqueType() is too expensive here:
+  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  assert(typ.kind == tyProc)
+  assert(sonsLen(typ) == sonsLen(typ.n))
+  var length = sonsLen(ri)
+  for i in countup(1, length - 1):
+    if ri.sons[i].typ.isCompileTimeOnly: continue
+    if params != nil: add(params, ~", ")
+    if i < sonsLen(typ):
+      assert(typ.n.sons[i].kind == nkSym)
+      add(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
+    else:
+      add(params, genArgNoParam(p, ri.sons[i]))
+  fixupCall(p, le, ri, d, op.r, params)
+
+proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
+
+  proc getRawProcType(p: BProc, t: PType): Rope =
+    result = getClosureType(p.module, t, clHalf)
+
+  proc addComma(r: Rope): Rope =
+    result = if r == nil: r else: r & ~", "
+
+  const PatProc = "$1.ClEnv? $1.ClPrc($3$1.ClEnv):(($4)($1.ClPrc))($2)"
+  const PatIter = "$1.ClPrc($3$1.ClEnv)" # we know the env exists
+  var op: TLoc
+  initLocExpr(p, ri.sons[0], op)
+  var pl: Rope
+
+  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  assert(typ.kind == tyProc)
+  var length = sonsLen(ri)
+  for i in countup(1, length - 1):
+    assert(sonsLen(typ) == sonsLen(typ.n))
+    if ri.sons[i].typ.isCompileTimeOnly: continue
+    if i < sonsLen(typ):
+      assert(typ.n.sons[i].kind == nkSym)
+      add(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
+    else:
+      add(pl, genArgNoParam(p, ri.sons[i]))
+    if i < length - 1: add(pl, ~", ")
+
+  template genCallPattern {.dirty.} =
+    lineF(p, cpsStmts, callPattern & ";$n", [op.r, pl, pl.addComma, rawProc])
+
+  let rawProc = getRawProcType(p, typ)
+  let callPattern = if tfIterator in typ.flags: PatIter else: PatProc
+  if typ.sons[0] != nil:
+    if isInvalidReturnType(typ.sons[0]):
+      if sonsLen(ri) > 1: add(pl, ~", ")
+      # beware of 'result = p(result)'. We may need to allocate a temporary:
+      if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
+        # Great, we can use 'd':
+        if d.k == locNone:
+          getTemp(p, typ.sons[0], d, needsInit=true)
+        elif d.k notin {locExpr, locTemp} and not hasNoInit(ri):
+          # reset before pass as 'result' var:
+          resetLoc(p, d)
+        add(pl, addrLoc(d))
+        genCallPattern()
+      else:
+        var tmp: TLoc
+        getTemp(p, typ.sons[0], tmp, needsInit=true)
+        add(pl, addrLoc(tmp))
+        genCallPattern()
+        genAssignment(p, d, tmp, {}) # no need for deep copying
+    else:
+      if d.k == locNone: getTemp(p, typ.sons[0], d)
+      assert(d.t != nil)        # generate an assignment to d:
+      var list: TLoc
+      initLoc(list, locCall, d.t, OnUnknown)
+      list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
+      genAssignment(p, d, list, {}) # no need for deep copying
+  else:
+    genCallPattern()
+
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
+  if ri.sons[i].typ.isCompileTimeOnly:
+    result = nil
+  elif i < sonsLen(typ):
+    # 'var T' is 'T&' in C++. This means we ignore the request of
+    # any nkHiddenAddr when it's a 'var T'.
+    assert(typ.n.sons[i].kind == nkSym)
+    if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
+      result = genArgNoParam(p, ri.sons[i][0])
+    else:
+      result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
+  else:
+    result = genArgNoParam(p, ri.sons[i])
+
+discard """
+Dot call syntax in C++
+======================
+
+so c2nim translates 'this' sometimes to 'T' and sometimes to 'var T'
+both of which are wrong, but often more convenient to use.
+For manual wrappers it can also be 'ptr T'
+
+Fortunately we know which parameter is the 'this' parameter and so can fix this
+mess in the codegen.
+now ... if the *argument* is a 'ptr' the codegen shall emit -> and otherwise .
+but this only depends on the argument and not on how the 'this' was declared
+however how the 'this' was declared affects whether we end up with
+wrong 'addr' and '[]' ops...
+
+Since I'm tired I'll enumerate all the cases here:
+
+var
+  x: ptr T
+  y: T
+
+proc t(x: T)
+x[].t()  --> (*x).t()  is correct.
+y.t()    --> y.t()  is correct
+
+proc u(x: ptr T)
+x.u()          --> needs to become  x->u()
+(addr y).u()   --> needs to become  y.u()
+
+proc v(x: var T)
+--> first skip the implicit 'nkAddr' node
+x[].v()        --> (*x).v()  is correct, but might have been eliminated due
+                   to the nkAddr node! So for this case we need to generate '->'
+y.v()          --> y.v() is correct
+
+"""
+
+proc skipAddrDeref(node: PNode): PNode =
+  var n = node
+  var isAddr = false
+  case n.kind
+  of nkAddr, nkHiddenAddr:
+    n = n.sons[0]
+    isAddr = true
+  of nkDerefExpr, nkHiddenDeref:
+    n = n.sons[0]
+  else: return n
+  if n.kind == nkObjDownConv: n = n.sons[0]
+  if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
+    result = n.sons[0]
+  elif n.kind in {nkAddr, nkHiddenAddr}:
+    result = n.sons[0]
+  else:
+    result = node
+
+proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
+  # for better or worse c2nim translates the 'this' argument to a 'var T'.
+  # However manual wrappers may also use 'ptr T'. In any case we support both
+  # for convenience.
+  internalAssert i < sonsLen(typ)
+  assert(typ.n.sons[i].kind == nkSym)
+  # if the parameter is lying (tyVar) and thus we required an additional deref,
+  # skip the deref:
+  var ri = ri[i]
+  while ri.kind == nkObjDownConv: ri = ri[0]
+  let t = typ.sons[i].skipTypes({tyGenericInst})
+  if t.kind == tyVar:
+    let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
+    if x.typ.kind == tyPtr:
+      result = genArgNoParam(p, x)
+      result.add("->")
+    elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
+      result = genArgNoParam(p, x[0])
+      result.add("->")
+    else:
+      result = genArgNoParam(p, x)
+      result.add(".")
+  elif t.kind == tyPtr:
+    if ri.kind in {nkAddr, nkHiddenAddr}:
+      result = genArgNoParam(p, ri[0])
+      result.add(".")
+    else:
+      result = genArgNoParam(p, ri)
+      result.add("->")
+  else:
+    ri = skipAddrDeref(ri)
+    if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
+    result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
+    result.add(".")
+
+proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
+  var i = 0
+  var j = 1
+  while i < pat.len:
+    case pat[i]
+    of '@':
+      if j < ri.len:
+        result.add genOtherArg(p, ri, j, typ)
+        for k in j+1 .. < ri.len:
+          result.add(~", ")
+          result.add genOtherArg(p, ri, k, typ)
+      inc i
+    of '#':
+      if pat[i+1] in {'+', '@'}:
+        let ri = ri[j]
+        if ri.kind in nkCallKinds:
+          let typ = skipTypes(ri.sons[0].typ, abstractInst)
+          if pat[i+1] == '+': result.add genArgNoParam(p, ri.sons[0])
+          result.add(~"(")
+          if 1 < ri.len:
+            result.add genOtherArg(p, ri, 1, typ)
+          for k in j+1 .. < ri.len:
+            result.add(~", ")
+            result.add genOtherArg(p, ri, k, typ)
+          result.add(~")")
+        else:
+          localError(ri.info, "call expression expected for C++ pattern")
+        inc i
+      elif pat[i+1] == '.':
+        result.add genThisArg(p, ri, j, typ)
+        inc i
+      elif pat[i+1] == '[':
+        var arg = ri.sons[j].skipAddrDeref
+        while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
+        result.add genArgNoParam(p, arg)
+        #result.add debugTree(arg, 0, 10)
+      else:
+        result.add genOtherArg(p, ri, j, typ)
+      inc j
+      inc i
+    of '\'':
+      var idx, stars: int
+      if scanCppGenericSlot(pat, i, idx, stars):
+        var t = resolveStarsInCppType(typ, idx, stars)
+        if t == nil: result.add(~"void")
+        else: result.add(getTypeDesc(p.module, t))
+    else:
+      let start = i
+      while i < pat.len:
+        if pat[i] notin {'@', '#', '\''}: inc(i)
+        else: break
+      if i - 1 >= start:
+        add(result, substr(pat, start, i - 1))
+
+proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
+  var op, a: TLoc
+  initLocExpr(p, ri.sons[0], op)
+  # getUniqueType() is too expensive here:
+  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  assert(typ.kind == tyProc)
+  var length = sonsLen(ri)
+  assert(sonsLen(typ) == sonsLen(typ.n))
+  # don't call '$' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  if pat.contains({'#', '(', '@', '\''}):
+    var pl = genPatternCall(p, ri, pat, typ)
+    # simpler version of 'fixupCall' that works with the pl+params combination:
+    var typ = skipTypes(ri.sons[0].typ, abstractInst)
+    if typ.sons[0] != nil:
+      if p.module.compileToCpp and lfSingleUse in d.flags:
+        # do not generate spurious temporaries for C++! For C we're better off
+        # with them to prevent undefined behaviour and because the codegen
+        # is free to emit expressions multiple times!
+        d.k = locCall
+        d.r = pl
+        excl d.flags, lfSingleUse
+      else:
+        if d.k == locNone: getTemp(p, typ.sons[0], d)
+        assert(d.t != nil)        # generate an assignment to d:
+        var list: TLoc
+        initLoc(list, locCall, d.t, OnUnknown)
+        list.r = pl
+        genAssignment(p, d, list, {}) # no need for deep copying
+    else:
+      add(pl, ~";$n")
+      line(p, cpsStmts, pl)
+  else:
+    var pl: Rope = nil
+    #var param = typ.n.sons[1].sym
+    if 1 < ri.len:
+      add(pl, genThisArg(p, ri, 1, typ))
+    add(pl, op.r)
+    var params: Rope
+    for i in countup(2, length - 1):
+      if params != nil: params.add(~", ")
+      assert(sonsLen(typ) == sonsLen(typ.n))
+      add(params, genOtherArg(p, ri, i, typ))
+    fixupCall(p, le, ri, d, pl, params)
+
+proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
+  # generates a crappy ObjC call
+  var op, a: TLoc
+  initLocExpr(p, ri.sons[0], op)
+  var pl = ~"["
+  # getUniqueType() is too expensive here:
+  var typ = skipTypes(ri.sons[0].typ, abstractInst)
+  assert(typ.kind == tyProc)
+  var length = sonsLen(ri)
+  assert(sonsLen(typ) == sonsLen(typ.n))
+
+  # don't call '$' here for efficiency:
+  let pat = ri.sons[0].sym.loc.r.data
+  internalAssert pat != nil
+  var start = 3
+  if ' ' in pat:
+    start = 1
+    add(pl, op.r)
+    if length > 1:
+      add(pl, ~": ")
+      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      start = 2
+  else:
+    if length > 1:
+      add(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
+      add(pl, ~" ")
+    add(pl, op.r)
+    if length > 2:
+      add(pl, ~": ")
+      add(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
+  for i in countup(start, length-1):
+    assert(sonsLen(typ) == sonsLen(typ.n))
+    if i >= sonsLen(typ):
+      internalError(ri.info, "varargs for objective C method?")
+    assert(typ.n.sons[i].kind == nkSym)
+    var param = typ.n.sons[i].sym
+    add(pl, ~" ")
+    add(pl, param.name.s)
+    add(pl, ~": ")
+    add(pl, genArg(p, ri.sons[i], param, ri))
+  if typ.sons[0] != nil:
+    if isInvalidReturnType(typ.sons[0]):
+      if sonsLen(ri) > 1: add(pl, ~" ")
+      # beware of 'result = p(result)'. We always allocate a temporary:
+      if d.k in {locTemp, locNone}:
+        # We already got a temp. Great, special case it:
+        if d.k == locNone: getTemp(p, typ.sons[0], d, needsInit=true)
+        add(pl, ~"Result: ")
+        add(pl, addrLoc(d))
+        add(pl, ~"];$n")
+        line(p, cpsStmts, pl)
+      else:
+        var tmp: TLoc
+        getTemp(p, typ.sons[0], tmp, needsInit=true)
+        add(pl, addrLoc(tmp))
+        add(pl, ~"];$n")
+        line(p, cpsStmts, pl)
+        genAssignment(p, d, tmp, {}) # no need for deep copying
+    else:
+      add(pl, ~"]")
+      if d.k == locNone: getTemp(p, typ.sons[0], d)
+      assert(d.t != nil)        # generate an assignment to d:
+      var list: TLoc
+      initLoc(list, locCall, nil, OnUnknown)
+      list.r = pl
+      genAssignment(p, d, list, {}) # no need for deep copying
+  else:
+    add(pl, ~"];$n")
+    line(p, cpsStmts, pl)
+
+proc genCall(p: BProc, e: PNode, d: var TLoc) =
+  if e.sons[0].typ.callConv == ccClosure:
+    genClosureCall(p, nil, e, d)
+  elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags:
+    genInfixCall(p, nil, e, d)
+  elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
+    genNamedParamCall(p, e, d)
+  else:
+    genPrefixCall(p, nil, e, d)
+  postStmtActions(p)
+  when false:
+    if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
+
+proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
+  if ri.sons[0].typ.callConv == ccClosure:
+    genClosureCall(p, le, ri, d)
+  elif ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags:
+    genInfixCall(p, le, ri, d)
+  elif ri.sons[0].kind == nkSym and sfNamedParamCall in ri.sons[0].sym.flags:
+    genNamedParamCall(p, ri, d)
+  else:
+    genPrefixCall(p, le, ri, d)
+  postStmtActions(p)
+  when false:
+    if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
+
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
new file mode 100644
index 000000000..05a3602d1
--- /dev/null
+++ b/compiler/ccgexprs.nim
@@ -0,0 +1,2198 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# included from cgen.nim
+
+# -------------------------- constant expressions ------------------------
+
+proc int64Literal(i: BiggestInt): Rope =
+  if i > low(int64):
+    result = rfmt(nil, "IL64($1)", rope(i))
+  else:
+    result = ~"(IL64(-9223372036854775807) - IL64(1))"
+
+proc uint64Literal(i: uint64): Rope = rope($i & "ULL")
+
+proc intLiteral(i: BiggestInt): Rope =
+  if i > low(int32) and i <= high(int32):
+    result = rope(i)
+  elif i == low(int32):
+    # Nim has the same bug for the same reasons :-)
+    result = ~"(-2147483647 -1)"
+  elif i > low(int64):
+    result = rfmt(nil, "IL64($1)", rope(i))
+  else:
+    result = ~"(IL64(-9223372036854775807) - IL64(1))"
+
+proc int32Literal(i: int): Rope =
+  if i == int(low(int32)):
+    result = ~"(-2147483647 -1)"
+  else:
+    result = rope(i)
+
+proc genHexLiteral(v: PNode): Rope =
+  # hex literals are unsigned in C
+  # so we don't generate hex literals any longer.
+  if v.kind notin {nkIntLit..nkUInt64Lit}:
+    internalError(v.info, "genHexLiteral")
+  result = intLiteral(v.intVal)
+
+proc getStrLit(m: BModule, s: string): Rope =
+  discard cgsym(m, "TGenericSeq")
+  result = "TMP" & rope(backendId())
+  addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
+       [result, makeCString(s), rope(len(s))])
+
+proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
+  if ty == nil: internalError(n.info, "genLiteral: ty is nil")
+  case n.kind
+  of nkCharLit..nkUInt64Lit:
+    case skipTypes(ty, abstractVarRange).kind
+    of tyChar, tyNil:
+      result = intLiteral(n.intVal)
+    of tyBool:
+      if n.intVal != 0: result = ~"NIM_TRUE"
+      else: result = ~"NIM_FALSE"
+    of tyInt64: result = int64Literal(n.intVal)
+    of tyUInt64: result = uint64Literal(uint64(n.intVal))
+    else:
+      result = "(($1) $2)" % [getTypeDesc(p.module,
+          skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)]
+  of nkNilLit:
+    let t = skipTypes(ty, abstractVarRange)
+    if t.kind == tyProc and t.callConv == ccClosure:
+      var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
+      result = "TMP" & rope(id)
+      if id == gBackendId:
+        # not found in cache:
+        inc(gBackendId)
+        addf(p.module.s[cfsData],
+             "static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
+             [getTypeDesc(p.module, t), result])
+    else:
+      result = rope("NIM_NIL")
+  of nkStrLit..nkTripleStrLit:
+    if n.strVal.isNil:
+      result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
+    elif skipTypes(ty, abstractVarRange).kind == tyString:
+      var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
+      if id == gBackendId:
+        # string literal not found in the cache:
+        result = ropecg(p.module, "((#NimStringDesc*) &$1)",
+                        [getStrLit(p.module, n.strVal)])
+      else:
+        result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
+    else:
+      result = makeCString(n.strVal)
+  of nkFloatLit..nkFloat64Lit:
+    result = rope(n.floatVal.toStrMaxPrecision)
+  else:
+    internalError(n.info, "genLiteral(" & $n.kind & ')')
+    result = nil
+
+proc genLiteral(p: BProc, n: PNode): Rope =
+  result = genLiteral(p, n, n.typ)
+
+proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
+  result = 0
+  when true:
+    for j in countup(0, size - 1):
+      if j < len(s): result = result or `shl`(ze64(s[j]), j * 8)
+  else:
+    # not needed, too complex thinking:
+    if CPU[platform.hostCPU].endian == CPU[targetCPU].endian:
+      for j in countup(0, size - 1):
+        if j < len(s): result = result or `shl`(Ze64(s[j]), j * 8)
+    else:
+      for j in countup(0, size - 1):
+        if j < len(s): result = result or `shl`(Ze64(s[j]), (Size - 1 - j) * 8)
+
+proc genRawSetData(cs: TBitSet, size: int): Rope =
+  var frmt: FormatStr
+  if size > 8:
+    result = "{$n" % []
+    for i in countup(0, size - 1):
+      if i < size - 1:
+        # not last iteration?
+        if (i + 1) mod 8 == 0: frmt = "0x$1,$n"
+        else: frmt = "0x$1, "
+      else:
+        frmt = "0x$1}$n"
+      addf(result, frmt, [rope(toHex(ze64(cs[i]), 2))])
+  else:
+    result = intLiteral(bitSetToWord(cs, size))
+    #  result := rope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
+
+proc genSetNode(p: BProc, n: PNode): Rope =
+  var cs: TBitSet
+  var size = int(getSize(n.typ))
+  toBitSet(n, cs)
+  if size > 8:
+    var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
+    result = "TMP" & rope(id)
+    if id == gBackendId:
+      # not found in cache:
+      inc(gBackendId)
+      addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
+           [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
+  else:
+    result = genRawSetData(cs, size)
+
+proc getStorageLoc(n: PNode): TStorageLoc =
+  case n.kind
+  of nkSym:
+    case n.sym.kind
+    of skParam, skTemp:
+      result = OnStack
+    of skVar, skForVar, skResult, skLet:
+      if sfGlobal in n.sym.flags: result = OnHeap
+      else: result = OnStack
+    of skConst:
+      if sfGlobal in n.sym.flags: result = OnHeap
+      else: result = OnUnknown
+    else: result = OnUnknown
+  of nkDerefExpr, nkHiddenDeref:
+    case n.sons[0].typ.kind
+    of tyVar: result = OnUnknown
+    of tyPtr: result = OnStack
+    of tyRef: result = OnHeap
+    else: internalError(n.info, "getStorageLoc")
+  of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
+    result = getStorageLoc(n.sons[0])
+  else: result = OnUnknown
+
+proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
+  if dest.s == OnStack or not usesNativeGC():
+    linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+    if needToKeepAlive in flags: keepAlive(p, dest)
+  elif dest.s == OnHeap:
+    # location is on heap
+    # now the writer barrier is inlined for performance:
+    #
+    #    if afSrcIsNotNil in flags:
+    #      UseMagic(p.module, 'nimGCref')
+    #      lineF(p, cpsStmts, 'nimGCref($1);$n', [rdLoc(src)])
+    #    elif afSrcIsNil notin flags:
+    #      UseMagic(p.module, 'nimGCref')
+    #      lineF(p, cpsStmts, 'if ($1) nimGCref($1);$n', [rdLoc(src)])
+    #    if afDestIsNotNil in flags:
+    #      UseMagic(p.module, 'nimGCunref')
+    #      lineF(p, cpsStmts, 'nimGCunref($1);$n', [rdLoc(dest)])
+    #    elif afDestIsNil notin flags:
+    #      UseMagic(p.module, 'nimGCunref')
+    #      lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
+    #    lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
+    if canFormAcycle(dest.t):
+      linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
+              addrLoc(dest), rdLoc(src))
+    else:
+      linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n",
+              addrLoc(dest), rdLoc(src))
+  else:
+    linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
+            addrLoc(dest), rdLoc(src))
+    if needToKeepAlive in flags: keepAlive(p, dest)
+
+proc asgnComplexity(n: PNode): int =
+  if n != nil:
+    case n.kind
+    of nkSym: result = 1
+    of nkRecCase:
+      # 'case objects' are too difficult to inline their assignment operation:
+      result = 100
+    of nkRecList:
+      for t in items(n):
+        result += asgnComplexity(t)
+    else: discard
+
+proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
+  assert field != nil
+  result.k = locField
+  result.s = a.s
+  result.t = t
+  result.r = rdLoc(a) & "." & field
+  result.heapRoot = a.heapRoot
+
+proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
+  let newflags =
+    if src.k == locData:
+      flags + {needToCopy}
+    elif tfShallow in dest.t.flags:
+      flags - {needToCopy}
+    else:
+      flags
+  let t = skipTypes(dest.t, abstractInst).getUniqueType()
+  for i in 0 .. <t.len:
+    let t = t.sons[i]
+    let field = "Field$1" % [i.rope]
+    genAssignment(p, optAsgnLoc(dest, t, field),
+                     optAsgnLoc(src, t, field), newflags)
+
+proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
+                      t: PNode) =
+  if t == nil: return
+  let newflags =
+    if src.k == locData:
+      flags + {needToCopy}
+    elif tfShallow in dest.t.flags:
+      flags - {needToCopy}
+    else:
+      flags
+  case t.kind
+  of nkSym:
+    let field = t.sym
+    genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
+                     optAsgnLoc(src, field.typ, field.loc.r), newflags)
+  of nkRecList:
+    for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
+  else: discard
+
+proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
+  # Consider:
+  # type TMyFastString {.shallow.} = string
+  # Due to the implementation of pragmas this would end up to set the
+  # tfShallow flag for the built-in string type too! So we check only
+  # here for this flag, where it is reasonably safe to do so
+  # (for objects, etc.):
+  if needToCopy notin flags or
+      tfShallow in skipTypes(dest.t, abstractVarRange).flags:
+    if dest.s == OnStack or not usesNativeGC():
+      useStringh(p.module)
+      linefmt(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
+           addrLoc(dest), addrLoc(src), rdLoc(dest))
+      if needToKeepAlive in flags: keepAlive(p, dest)
+    else:
+      linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
+              addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
+  else:
+    linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
+            addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
+
+proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
+  # This function replaces all other methods for generating
+  # the assignment operation in C.
+  if src.t != nil and src.t.kind == tyPtr:
+    # little HACK to support the new 'var T' as return type:
+    linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+    return
+  var ty = skipTypes(dest.t, abstractRange)
+  case ty.kind
+  of tyRef:
+    genRefAssign(p, dest, src, flags)
+  of tySequence:
+    if needToCopy notin flags and src.k != locData:
+      genRefAssign(p, dest, src, flags)
+    else:
+      linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
+              addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
+  of tyString:
+    if needToCopy notin flags and src.k != locData:
+      genRefAssign(p, dest, src, flags)
+    else:
+      if dest.s == OnStack or not usesNativeGC():
+        linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
+        if needToKeepAlive in flags: keepAlive(p, dest)
+      elif dest.s == OnHeap:
+        # we use a temporary to care for the dreaded self assignment:
+        var tmp: TLoc
+        getTemp(p, ty, tmp)
+        linefmt(p, cpsStmts, "$3 = $1; $1 = #copyStringRC1($2);$n",
+                dest.rdLoc, src.rdLoc, tmp.rdLoc)
+        linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", tmp.rdLoc)
+      else:
+        linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
+               addrLoc(dest), rdLoc(src))
+        if needToKeepAlive in flags: keepAlive(p, dest)
+  of tyProc:
+    if needsComplexAssignment(dest.t):
+      # optimize closure assignment:
+      let a = optAsgnLoc(dest, dest.t, "ClEnv".rope)
+      let b = optAsgnLoc(src, dest.t, "ClEnv".rope)
+      genRefAssign(p, a, b, flags)
+      linefmt(p, cpsStmts, "$1.ClPrc = $2.ClPrc;$n", rdLoc(dest), rdLoc(src))
+    else:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  of tyTuple:
+    if needsComplexAssignment(dest.t):
+      if dest.t.len <= 4: genOptAsgnTuple(p, dest, src, flags)
+      else: genGenericAsgn(p, dest, src, flags)
+    else:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  of tyObject:
+    # XXX: check for subtyping?
+    if ty.isImportedCppType:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+    elif not isObjLackingTypeField(ty):
+      genGenericAsgn(p, dest, src, flags)
+    elif needsComplexAssignment(ty):
+      if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
+        discard getTypeDesc(p.module, ty)
+        ty = getUniqueType(ty)
+        internalAssert ty.n != nil
+        genOptAsgnObject(p, dest, src, flags, ty.n)
+      else:
+        genGenericAsgn(p, dest, src, flags)
+    else:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  of tyArray, tyArrayConstr:
+    if needsComplexAssignment(dest.t):
+      genGenericAsgn(p, dest, src, flags)
+    else:
+      useStringh(p.module)
+      linefmt(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
+           rdLoc(dest), rdLoc(src))
+  of tyOpenArray, tyVarargs:
+    # open arrays are always on the stack - really? What if a sequence is
+    # passed to an open array?
+    if needsComplexAssignment(dest.t):
+      linefmt(p, cpsStmts,     # XXX: is this correct for arrays?
+           "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n",
+           addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
+    else:
+      useStringh(p.module)
+      linefmt(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n",
+           rdLoc(dest), rdLoc(src))
+  of tySet:
+    if mapType(ty) == ctArray:
+      useStringh(p.module)
+      linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
+              rdLoc(dest), rdLoc(src), rope(getSize(dest.t)))
+    else:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
+     tyInt..tyUInt64, tyRange, tyVar:
+    linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  else: internalError("genAssignment: " & $ty.kind)
+
+proc genDeepCopy(p: BProc; dest, src: TLoc) =
+  var ty = skipTypes(dest.t, abstractVarRange)
+  case ty.kind
+  of tyPtr, tyRef, tyProc, tyTuple, tyObject, tyArray, tyArrayConstr:
+    # XXX optimize this
+    linefmt(p, cpsStmts, "#genericDeepCopy((void*)$1, (void*)$2, $3);$n",
+            addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
+  of tySequence, tyString:
+    linefmt(p, cpsStmts, "#genericSeqDeepCopy($1, $2, $3);$n",
+            addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
+  of tyOpenArray, tyVarargs:
+    linefmt(p, cpsStmts,
+         "#genericDeepCopyOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n",
+         addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t))
+  of tySet:
+    if mapType(ty) == ctArray:
+      useStringh(p.module)
+      linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
+              rdLoc(dest), rdLoc(src), rope(getSize(dest.t)))
+    else:
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  of tyPointer, tyChar, tyBool, tyEnum, tyCString,
+     tyInt..tyUInt64, tyRange, tyVar:
+    linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
+  else: internalError("genDeepCopy: " & $ty.kind)
+
+proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
+  if d.k == locNone: getTemp(p, typ, d)
+
+proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
+  if d.k != locNone:
+    if lfNoDeepCopy in d.flags: genAssignment(p, d, s, {})
+    else: genAssignment(p, d, s, {needToCopy})
+  else:
+    d = s # ``d`` is free, so fill it with ``s``
+
+proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
+  var a: TLoc
+  if d.k != locNone:
+    # need to generate an assignment here
+    initLoc(a, locData, t, OnUnknown)
+    a.r = r
+    if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
+    else: genAssignment(p, d, a, {needToCopy})
+  else:
+    # we cannot call initLoc() here as that would overwrite
+    # the flags field!
+    d.k = locData
+    d.t = t
+    d.r = r
+
+proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
+  var a: TLoc
+  if d.k != locNone:
+    # need to generate an assignment here
+    initLoc(a, locExpr, t, OnUnknown)
+    a.r = r
+    if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
+    else: genAssignment(p, d, a, {needToCopy})
+  else:
+    # we cannot call initLoc() here as that would overwrite
+    # the flags field!
+    d.k = locExpr
+    d.t = t
+    d.r = r
+
+proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a, b: TLoc
+  if d.k != locNone: internalError(e.info, "binaryStmt")
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
+
+proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a: TLoc
+  if d.k != locNone: internalError(e.info, "unaryStmt")
+  initLocExpr(p, e.sons[1], a)
+  lineCg(p, cpsStmts, frmt, [rdLoc(a)])
+
+proc binaryStmtChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a, b: TLoc
+  if (d.k != locNone): internalError(e.info, "binaryStmtChar")
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  lineCg(p, cpsStmts, frmt, [rdCharLoc(a), rdCharLoc(b)])
+
+proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a, b: TLoc
+  assert(e.sons[1].typ != nil)
+  assert(e.sons[2].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)]))
+
+proc binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a, b: TLoc
+  assert(e.sons[1].typ != nil)
+  assert(e.sons[2].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc]))
+
+proc unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a: TLoc
+  initLocExpr(p, e.sons[1], a)
+  putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a)]))
+
+proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a: TLoc
+  initLocExpr(p, e.sons[1], a)
+  putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
+
+proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
+                            frmt: string): Rope =
+  var size = getSize(t)
+  let storage = if size < platform.intSize: rope("NI")
+                else: getTypeDesc(p.module, t)
+  result = getTempName()
+  linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
+  lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
+  if size < platform.intSize or t.kind in {tyRange, tyEnum}:
+    linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
+            result, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
+
+proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
+  const
+    prc: array[mAddI..mPred, string] = [
+      "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n",
+      "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n",
+      "$# = #modInt($#, $#);$n",
+      "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n",
+      "$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n",
+      "$# = #modInt64($#, $#);$n",
+      "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
+    opr: array[mAddI..mPred, string] = [
+      "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
+      "($#)($# / $#)", "($#)($# % $#)",
+      "($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
+      "($#)($# / $#)", "($#)($# % $#)",
+      "($#)($# + $#)", "($#)($# - $#)"]
+  var a, b: TLoc
+  assert(e.sons[1].typ != nil)
+  assert(e.sons[2].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  # skipping 'range' is correct here as we'll generate a proper range check
+  # later via 'chckRange'
+  let t = e.typ.skipTypes(abstractRange)
+  if optOverflowCheck notin p.options:
+    let res = opr[m] % [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)]
+    putIntoDest(p, d, e.typ, res)
+  else:
+    let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
+    putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, t), res])
+
+proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
+  const
+    opr: array[mUnaryMinusI..mAbsI64, string] = [
+      mUnaryMinusI: "((NI$2)-($1))",
+      mUnaryMinusI64: "-($1)",
+      mAbsI: "($1 > 0? ($1) : -($1))",
+      mAbsI64: "($1 > 0? ($1) : -($1))"]
+  var
+    a: TLoc
+    t: PType
+  assert(e.sons[1].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  t = skipTypes(e.typ, abstractRange)
+  if optOverflowCheck in p.options:
+    linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
+            rdLoc(a), intLiteral(firstOrd(t)))
+  putIntoDest(p, d, e.typ, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
+
+proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
+  const
+    binArithTab: array[mAddF64..mXor, string] = [
+      "(($4)($1) + ($4)($2))", # AddF64
+      "(($4)($1) - ($4)($2))", # SubF64
+      "(($4)($1) * ($4)($2))", # MulF64
+      "(($4)($1) / ($4)($2))", # DivF64
+
+      "($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
+      "($4)((NU$3)($1) << (NU$3)($2))", # ShlI
+      "($4)($1 & $2)",      # BitandI
+      "($4)($1 | $2)",      # BitorI
+      "($4)($1 ^ $2)",      # BitxorI
+      "(($1 <= $2) ? $1 : $2)", # MinI
+      "(($1 >= $2) ? $1 : $2)", # MaxI
+      "($4)((NU64)($1) >> (NU64)($2))", # ShrI64
+      "($4)((NU64)($1) << (NU64)($2))", # ShlI64
+      "($4)($1 & $2)",            # BitandI64
+      "($4)($1 | $2)",            # BitorI64
+      "($4)($1 ^ $2)",            # BitxorI64
+      "(($1 <= $2) ? $1 : $2)", # MinF64
+      "(($1 >= $2) ? $1 : $2)", # MaxF64
+      "($4)((NU$3)($1) + (NU$3)($2))", # AddU
+      "($4)((NU$3)($1) - (NU$3)($2))", # SubU
+      "($4)((NU$3)($1) * (NU$3)($2))", # MulU
+      "($4)((NU$3)($1) / (NU$3)($2))", # DivU
+      "($4)((NU$3)($1) % (NU$3)($2))", # ModU
+      "($1 == $2)",           # EqI
+      "($1 <= $2)",           # LeI
+      "($1 < $2)",            # LtI
+      "($1 == $2)",           # EqI64
+      "($1 <= $2)",           # LeI64
+      "($1 < $2)",            # LtI64
+      "($1 == $2)",           # EqF64
+      "($1 <= $2)",           # LeF64
+      "($1 < $2)",            # LtF64
+      "((NU$3)($1) <= (NU$3)($2))", # LeU
+      "((NU$3)($1) < (NU$3)($2))", # LtU
+      "((NU64)($1) <= (NU64)($2))", # LeU64
+      "((NU64)($1) < (NU64)($2))", # LtU64
+      "($1 == $2)",           # EqEnum
+      "($1 <= $2)",           # LeEnum
+      "($1 < $2)",            # LtEnum
+      "((NU8)($1) == (NU8)($2))", # EqCh
+      "((NU8)($1) <= (NU8)($2))", # LeCh
+      "((NU8)($1) < (NU8)($2))", # LtCh
+      "($1 == $2)",           # EqB
+      "($1 <= $2)",           # LeB
+      "($1 < $2)",            # LtB
+      "($1 == $2)",           # EqRef
+      "($1 == $2)",           # EqPtr
+      "($1 <= $2)",           # LePtr
+      "($1 < $2)",            # LtPtr
+      "($1 == $2)",           # EqCString
+      "($1 != $2)"]           # Xor
+  var
+    a, b: TLoc
+    s: BiggestInt
+  assert(e.sons[1].typ != nil)
+  assert(e.sons[2].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  # BUGFIX: cannot use result-type here, as it may be a boolean
+  s = max(getSize(a.t), getSize(b.t)) * 8
+  putIntoDest(p, d, e.typ,
+              binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
+                                      getSimpleTypeDesc(p.module, e.typ)])
+
+proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
+  var a, b: TLoc
+  assert(e.sons[1].typ != nil)
+  assert(e.sons[2].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  if a.t.callConv == ccClosure:
+    putIntoDest(p, d, e.typ,
+      "($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)" % [rdLoc(a), rdLoc(b)])
+  else:
+    putIntoDest(p, d, e.typ, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
+
+proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
+  let t = skipTypes(e.sons[1].typ, abstractRange)
+  if t.kind == tyProc and t.callConv == ccClosure:
+    unaryExpr(p, e, d, "$1.ClPrc == 0")
+  else:
+    unaryExpr(p, e, d, "$1 == 0")
+
+proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
+  const
+    unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
+      "$1",                   # UnaryPlusI
+      "($3)((NU$2) ~($1))",   # BitnotI
+      "($3)((NU$2) ~($1))",   # BitnotI64
+      "$1",                   # UnaryPlusF64
+      "-($1)",                # UnaryMinusF64
+      "($1 > 0? ($1) : -($1))", # AbsF64; BUGFIX: fabs() makes problems
+                                # for Tiny C, so we don't use it
+      "(($3)(NU)(NU8)($1))",  # mZe8ToI
+      "(($3)(NU64)(NU8)($1))", # mZe8ToI64
+      "(($3)(NU)(NU16)($1))", # mZe16ToI
+      "(($3)(NU64)(NU16)($1))", # mZe16ToI64
+      "(($3)(NU64)(NU32)($1))", # mZe32ToI64
+      "(($3)(NU64)(NU)($1))", # mZeIToI64
+      "(($3)(NU8)(NU)($1))", # ToU8
+      "(($3)(NU16)(NU)($1))", # ToU16
+      "(($3)(NU32)(NU64)($1))", # ToU32
+      "((double) ($1))",      # ToFloat
+      "((double) ($1))",      # ToBiggestFloat
+      "float64ToInt32($1)",   # ToInt
+      "float64ToInt64($1)"]   # ToBiggestInt
+  var
+    a: TLoc
+    t: PType
+  assert(e.sons[1].typ != nil)
+  initLocExpr(p, e.sons[1], a)
+  t = skipTypes(e.typ, abstractRange)
+  putIntoDest(p, d, e.typ,
+              unArithTab[op] % [rdLoc(a), rope(getSize(t) * 8),
+                getSimpleTypeDesc(p.module, e.typ)])
+
+proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
+  result = p.module.compileToCpp and
+      skipTypes(typ, abstractInst).kind == tyVar and
+      tfVarIsPtr notin skipTypes(typ, abstractInst).flags
+
+proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
+  let mt = mapType(e.sons[0].typ)
+  if mt in {ctArray, ctPtrToArray} and not enforceDeref:
+    # XXX the amount of hacks for C's arrays is incredible, maybe we should
+    # simply wrap them in a struct? --> Losing auto vectorization then?
+    #if e[0].kind != nkBracketExpr:
+    #  message(e.info, warnUser, "CAME HERE " & renderTree(e))
+    expr(p, e.sons[0], d)
+  else:
+    var a: TLoc
+    initLocExprSingleUse(p, e.sons[0], a)
+    if d.k == locNone:
+      let typ = skipTypes(a.t, abstractInst)
+      # dest = *a;  <-- We do not know that 'dest' is on the heap!
+      # It is completely wrong to set 'd.s' here, unless it's not yet
+      # been assigned to.
+      case typ.kind
+      of tyRef:
+        d.s = OnHeap
+      of tyVar:
+        d.s = OnUnknown
+        if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
+            e.kind == nkHiddenDeref:
+          putIntoDest(p, d, e.typ, rdLoc(a))
+          return
+      of tyPtr:
+        d.s = OnUnknown         # BUGFIX!
+      else: internalError(e.info, "genDeref " & $a.t.kind)
+    elif p.module.compileToCpp:
+      let typ = skipTypes(a.t, abstractInst)
+      if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
+           e.kind == nkHiddenDeref:
+        putIntoDest(p, d, e.typ, rdLoc(a))
+        return
+    if enforceDeref and mt == ctPtrToArray:
+      # we lie about the type for better C interop: 'ptr array[3,T]' is
+      # translated to 'ptr T', but for deref'ing this produces wrong code.
+      # See tmissingderef. So we get rid of the deref instead. The codegen
+      # ends up using 'memcpy' for the array assignment,
+      # so the '&' and '*' cancel out:
+      putIntoDest(p, d, a.t.sons[0], rdLoc(a))
+    else:
+      putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)])
+
+proc genAddr(p: BProc, e: PNode, d: var TLoc) =
+  # careful  'addr(myptrToArray)' needs to get the ampersand:
+  if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
+    var a: TLoc
+    initLocExpr(p, e.sons[0], a)
+    putIntoDest(p, d, e.typ, "&" & a.r)
+    #Message(e.info, warnUser, "HERE NEW &")
+  elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
+    expr(p, e.sons[0], d)
+  else:
+    var a: TLoc
+    initLocExpr(p, e.sons[0], a)
+    putIntoDest(p, d, e.typ, addrLoc(a))
+
+template inheritLocation(d: var TLoc, a: TLoc) =
+  if d.k == locNone: d.s = a.s
+  if d.heapRoot == nil:
+    d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
+
+proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
+  initLocExpr(p, e.sons[0], a)
+  if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
+  d.inheritLocation(a)
+  discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
+  result = a.t.getUniqueType
+
+proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
+  var
+    a: TLoc
+    i: int
+  initLocExpr(p, e.sons[0], a)
+  d.inheritLocation(a)
+  discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
+  var ty = a.t.getUniqueType
+  var r = rdLoc(a)
+  case e.sons[1].kind
+  of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
+  else: internalError(e.info, "genTupleElem")
+  addf(r, ".Field$1", [rope(i)])
+  putIntoDest(p, d, ty.sons[i], r)
+
+proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
+  var a: TLoc
+  var ty = genRecordFieldAux(p, e, d, a)
+  var r = rdLoc(a)
+  var f = e.sons[1].sym
+  if ty.kind == tyTuple:
+    # we found a unique tuple type which lacks field information
+    # so we use Field$i
+    addf(r, ".Field$1", [rope(f.position)])
+    putIntoDest(p, d, f.typ, r)
+  else:
+    var field: PSym = nil
+    while ty != nil:
+      if ty.kind notin {tyTuple, tyObject}:
+        internalError(e.info, "genRecordField")
+      field = lookupInRecord(ty.n, f.name)
+      if field != nil: break
+      if not p.module.compileToCpp: add(r, ".Sup")
+      ty = getUniqueType(ty.sons[0])
+    if field == nil: internalError(e.info, "genRecordField 2 ")
+    if field.loc.r == nil: internalError(e.info, "genRecordField 3")
+    addf(r, ".$1", [field.loc.r])
+    putIntoDest(p, d, field.typ, r)
+  #d.s = a.s
+
+proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
+
+proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
+  var test, u, v: TLoc
+  for i in countup(1, sonsLen(e) - 1):
+    var it = e.sons[i]
+    assert(it.kind in nkCallKinds)
+    assert(it.sons[0].kind == nkSym)
+    let op = it.sons[0].sym
+    if op.magic == mNot: it = it.sons[1]
+    let disc = it.sons[2].skipConv
+    assert(disc.kind == nkSym)
+    initLoc(test, locNone, it.typ, OnStack)
+    initLocExpr(p, it.sons[1], u)
+    initLoc(v, locExpr, disc.typ, OnUnknown)
+    v.r = "$1.$2" % [obj, disc.sym.loc.r]
+    genInExprAux(p, it, u, v, test)
+    let id = nodeTableTestOrSet(p.module.dataCache,
+                               newStrNode(nkStrLit, field.name.s), gBackendId)
+    let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
+                 else: "TMP" & rope(id)
+    if op.magic == mNot:
+      linefmt(p, cpsStmts,
+              "if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
+              rdLoc(test), strLit)
+    else:
+      linefmt(p, cpsStmts,
+              "if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
+              rdLoc(test), strLit)
+
+proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
+  if optFieldCheck in p.options:
+    var
+      a: TLoc
+      f, field: PSym
+      ty: PType
+      r: Rope
+    ty = genRecordFieldAux(p, e.sons[0], d, a)
+    r = rdLoc(a)
+    f = e.sons[0].sons[1].sym
+    field = nil
+    while ty != nil:
+      assert(ty.kind in {tyTuple, tyObject})
+      field = lookupInRecord(ty.n, f.name)
+      if field != nil: break
+      if not p.module.compileToCpp: add(r, ".Sup")
+      ty = getUniqueType(ty.sons[0])
+    if field == nil: internalError(e.info, "genCheckedRecordField")
+    if field.loc.r == nil:
+      internalError(e.info, "genCheckedRecordField") # generate the checks:
+    genFieldCheck(p, e, r, field)
+    add(r, rfmt(nil, ".$1", field.loc.r))
+    putIntoDest(p, d, field.typ, r)
+  else:
+    genRecordField(p, e.sons[0], d)
+
+proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
+  var a, b: TLoc
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b)
+  var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
+  var first = intLiteral(firstOrd(ty))
+  # emit range check:
+  if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
+    if not isConstExpr(y):
+      # semantic pass has already checked for const index expressions
+      if firstOrd(ty) == 0:
+        if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
+          linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n",
+                  rdCharLoc(b), intLiteral(lastOrd(ty)))
+      else:
+        linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
+                rdCharLoc(b), first, intLiteral(lastOrd(ty)))
+    else:
+      let idx = getOrdValue(y)
+      if idx < firstOrd(ty) or idx > lastOrd(ty):
+        localError(x.info, errIndexOutOfBounds)
+  d.inheritLocation(a)
+  putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
+              rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
+
+proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
+  var a, b: TLoc
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b)
+  var ty = skipTypes(a.t, abstractVarRange)
+  if d.k == locNone: d.s = a.s
+  putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
+              rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
+
+proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
+  var a, b: TLoc
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b) # emit range check:
+  if optBoundsCheck in p.options:
+    linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
+            rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
+  if d.k == locNone: d.s = a.s
+  putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
+              rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
+
+proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
+  var a, b: TLoc
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b)
+  var ty = skipTypes(a.t, abstractVarRange)
+  if ty.kind in {tyRef, tyPtr}:
+    ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
+  if optBoundsCheck in p.options:
+    if ty.kind == tyString:
+      linefmt(p, cpsStmts,
+           "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
+           rdLoc(b), rdLoc(a), lenField(p))
+    else:
+      linefmt(p, cpsStmts,
+           "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
+           rdLoc(b), rdLoc(a), lenField(p))
+  if d.k == locNone: d.s = OnHeap
+  d.heapRoot = a.r
+  if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
+    a.r = rfmt(nil, "(*$1)", a.r)
+  putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
+              rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
+
+proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
+  var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+  if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
+  case ty.kind
+  of tyArray, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d)
+  of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d)
+  of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d)
+  of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d)
+  of tyTuple: genTupleElem(p, n, d)
+  else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
+
+proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
+  # how to generate code?
+  #  'expr1 and expr2' becomes:
+  #     result = expr1
+  #     fjmp result, end
+  #     result = expr2
+  #  end:
+  #  ... (result computed)
+  # BUGFIX:
+  #   a = b or a
+  # used to generate:
+  # a = b
+  # if a: goto end
+  # a = a
+  # end:
+  # now it generates:
+  # tmp = b
+  # if tmp: goto end
+  # tmp = a
+  # end:
+  # a = tmp
+  var
+    L: TLabel
+    tmp: TLoc
+  getTemp(p, e.typ, tmp)      # force it into a temp!
+  inc p.splitDecls
+  expr(p, e.sons[1], tmp)
+  L = getLabel(p)
+  if m == mOr:
+    lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
+  else:
+    lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
+  expr(p, e.sons[2], tmp)
+  fixLabel(p, L)
+  if d.k == locNone:
+    d = tmp
+  else:
+    genAssignment(p, d, tmp, {}) # no need for deep copying
+  dec p.splitDecls
+
+proc genEcho(p: BProc, n: PNode) =
+  # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
+  # is threadsafe.
+  internalAssert n.kind == nkBracket
+  discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
+  var args: Rope = nil
+  var a: TLoc
+  for i in countup(0, n.len-1):
+    if n.sons[i].skipConv.kind == nkNilLit:
+      add(args, ", \"nil\"")
+    else:
+      initLocExpr(p, n.sons[i], a)
+      addf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
+  linefmt(p, cpsStmts, "printf($1$2);$n",
+          makeCString(repeat("%s", n.len) & tnl), args)
+
+proc gcUsage(n: PNode) =
+  if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
+
+proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
+  #   <Nim code>
+  #   s = 'Hello ' & name & ', how do you feel?' & 'z'
+  #
+  #   <generated C code>
+  #  {
+  #    string tmp0;
+  #    ...
+  #    tmp0 = rawNewString(6 + 17 + 1 + s2->len);
+  #    // we cannot generate s = rawNewString(...) here, because
+  #    // ``s`` may be used on the right side of the expression
+  #    appendString(tmp0, strlit_1);
+  #    appendString(tmp0, name);
+  #    appendString(tmp0, strlit_2);
+  #    appendChar(tmp0, 'z');
+  #    asgn(s, tmp0);
+  #  }
+  var a, tmp: TLoc
+  getTemp(p, e.typ, tmp)
+  var L = 0
+  var appends: Rope = nil
+  var lens: Rope = nil
+  for i in countup(0, sonsLen(e) - 2):
+    # compute the length expression:
+    initLocExpr(p, e.sons[i + 1], a)
+    if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
+      inc(L)
+      add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
+    else:
+      if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
+        inc(L, len(e.sons[i + 1].strVal))
+      else:
+        addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
+      add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
+  linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
+  add(p.s(cpsStmts), appends)
+  if d.k == locNone:
+    d = tmp
+    keepAlive(p, tmp)
+  else:
+    genAssignment(p, d, tmp, {needToKeepAlive}) # no need for deep copying
+  gcUsage(e)
+
+proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
+  #  <Nim code>
+  #  s &= 'Hello ' & name & ', how do you feel?' & 'z'
+  #  // BUG: what if s is on the left side too?
+  #  <generated C code>
+  #  {
+  #    s = resizeString(s, 6 + 17 + 1 + name->len);
+  #    appendString(s, strlit_1);
+  #    appendString(s, name);
+  #    appendString(s, strlit_2);
+  #    appendChar(s, 'z');
+  #  }
+  var
+    a, dest: TLoc
+    appends, lens: Rope
+  assert(d.k == locNone)
+  var L = 0
+  initLocExpr(p, e.sons[1], dest)
+  for i in countup(0, sonsLen(e) - 3):
+    # compute the length expression:
+    initLocExpr(p, e.sons[i + 2], a)
+    if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
+      inc(L)
+      add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
+                        rdLoc(dest), rdLoc(a)))
+    else:
+      if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
+        inc(L, len(e.sons[i + 2].strVal))
+      else:
+        addf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
+      add(appends, rfmt(p.module, "#appendString($1, $2);$n",
+                        rdLoc(dest), rdLoc(a)))
+  linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
+          rdLoc(dest), lens, rope(L))
+  keepAlive(p, dest)
+  add(p.s(cpsStmts), appends)
+  gcUsage(e)
+
+proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
+  # seq &= x  -->
+  #    seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
+  #    seq->data[seq->len-1] = x;
+  let seqAppendPattern = if not p.module.compileToCpp:
+                           "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
+                         else:
+                           "$1 = ($2) #incrSeq($1, sizeof($3));$n"
+  var a, b, dest: TLoc
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  lineCg(p, cpsStmts, seqAppendPattern, [
+      rdLoc(a),
+      getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)),
+      getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
+  keepAlive(p, a)
+  initLoc(dest, locExpr, b.t, OnHeap)
+  dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p))
+  genAssignment(p, dest, b, {needToCopy, afDestIsNil})
+  gcUsage(e)
+
+proc genReset(p: BProc, n: PNode) =
+  var a: TLoc
+  initLocExpr(p, n.sons[1], a)
+  linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
+          addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange)))
+
+proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
+  var sizeExpr = sizeExpr
+  let refType = skipTypes(a.t, abstractVarRange)
+  var b: TLoc
+  initLoc(b, locExpr, a.t, OnHeap)
+  if sizeExpr.isNil:
+    sizeExpr = "sizeof($1)" %
+        [getTypeDesc(p.module, skipTypes(refType.sons[0], abstractRange))]
+  let args = [getTypeDesc(p.module, refType),
+              genTypeInfo(p.module, refType),
+              sizeExpr]
+  if a.s == OnHeap and usesNativeGC():
+    # use newObjRC1 as an optimization; and we don't need 'keepAlive' either
+    if canFormAcycle(a.t):
+      linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", a.rdLoc)
+    else:
+      linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", a.rdLoc)
+    b.r = ropecg(p.module, "($1) #newObjRC1($2, $3)", args)
+    linefmt(p, cpsStmts, "$1 = $2;$n", a.rdLoc, b.rdLoc)
+  else:
+    b.r = ropecg(p.module, "($1) #newObj($2, $3)", args)
+    genAssignment(p, a, b, {needToKeepAlive})  # set the object type:
+  let bt = skipTypes(refType.sons[0], abstractRange)
+  genObjectInit(p, cpsStmts, bt, a, false)
+
+proc genNew(p: BProc, e: PNode) =
+  var a: TLoc
+  initLocExpr(p, e.sons[1], a)
+  # 'genNew' also handles 'unsafeNew':
+  if e.len == 3:
+    var se: TLoc
+    initLocExpr(p, e.sons[2], se)
+    rawGenNew(p, a, se.rdLoc)
+  else:
+    rawGenNew(p, a, nil)
+  gcUsage(e)
+
+proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
+  let seqtype = skipTypes(dest.t, abstractVarRange)
+  let args = [getTypeDesc(p.module, seqtype),
+              genTypeInfo(p.module, seqtype), length]
+  var call: TLoc
+  initLoc(call, locExpr, dest.t, OnHeap)
+  if dest.s == OnHeap and usesNativeGC():
+    if canFormAcycle(dest.t):
+      linefmt(p, cpsStmts, "if ($1) #nimGCunref($1);$n", dest.rdLoc)
+    else:
+      linefmt(p, cpsStmts, "if ($1) #nimGCunrefNoCycle($1);$n", dest.rdLoc)
+    call.r = ropecg(p.module, "($1) #newSeqRC1($2, $3)", args)
+    linefmt(p, cpsStmts, "$1 = $2;$n", dest.rdLoc, call.rdLoc)
+  else:
+    call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
+    genAssignment(p, dest, call, {needToKeepAlive})
+
+proc genNewSeq(p: BProc, e: PNode) =
+  var a, b: TLoc
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  genNewSeqAux(p, a, b.rdLoc)
+  gcUsage(e)
+
+proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
+  var tmp: TLoc
+  var t = e.typ.skipTypes(abstractInst)
+  getTemp(p, t, tmp)
+  let isRef = t.kind == tyRef
+  var r = rdLoc(tmp)
+  if isRef:
+    rawGenNew(p, tmp, nil)
+    t = t.lastSon.skipTypes(abstractInst)
+    r = "(*$1)" % [r]
+    gcUsage(e)
+  else:
+    constructLoc(p, tmp)
+  discard getTypeDesc(p.module, t)
+  for i in 1 .. <e.len:
+    let it = e.sons[i]
+    var tmp2: TLoc
+    tmp2.r = r
+    var field: PSym = nil
+    var ty = getUniqueType(t)
+    while ty != nil:
+      field = lookupInRecord(ty.n, it.sons[0].sym.name)
+      if field != nil: break
+      if not p.module.compileToCpp: add(tmp2.r, ".Sup")
+      ty = getUniqueType(ty.sons[0])
+    if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
+    if it.len == 3 and optFieldCheck in p.options:
+      genFieldCheck(p, it.sons[2], tmp2.r, field)
+    add(tmp2.r, ".")
+    add(tmp2.r, field.loc.r)
+    tmp2.k = locTemp
+    tmp2.t = field.loc.t
+    tmp2.s = if isRef: OnHeap else: OnStack
+    tmp2.heapRoot = tmp.r
+    expr(p, it.sons[1], tmp2)
+
+  if d.k == locNone:
+    d = tmp
+  else:
+    genAssignment(p, d, tmp, {})
+
+proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
+  var arr: TLoc
+  if d.k == locNone:
+    getTemp(p, t.typ, d)
+  # generate call to newSeq before adding the elements per hand:
+  genNewSeqAux(p, d, intLiteral(sonsLen(t)))
+  for i in countup(0, sonsLen(t) - 1):
+    initLoc(arr, locExpr, elemType(skipTypes(t.typ, typedescInst)), OnHeap)
+    arr.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
+    arr.s = OnHeap            # we know that sequences are on the heap
+    expr(p, t.sons[i], arr)
+  gcUsage(t)
+
+proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
+  var elem, a, arr: TLoc
+  if t.kind == nkBracket:
+    t.sons[1].typ = t.typ
+    genSeqConstr(p, t.sons[1], d)
+    return
+  if d.k == locNone:
+    getTemp(p, t.typ, d)
+  # generate call to newSeq before adding the elements per hand:
+  var L = int(lengthOrd(t.sons[1].typ))
+
+  genNewSeqAux(p, d, intLiteral(L))
+  initLocExpr(p, t.sons[1], a)
+  for i in countup(0, L - 1):
+    initLoc(elem, locExpr, elemType(skipTypes(t.typ, abstractInst)), OnHeap)
+    elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
+    elem.s = OnHeap # we know that sequences are on the heap
+    initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
+    arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
+    genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
+
+proc genNewFinalize(p: BProc, e: PNode) =
+  var
+    a, b, f: TLoc
+    refType, bt: PType
+    ti: Rope
+    oldModule: BModule
+  refType = skipTypes(e.sons[1].typ, abstractVarRange)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], f)
+  initLoc(b, locExpr, a.t, OnHeap)
+  ti = genTypeInfo(p.module, refType)
+  addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
+  b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
+      getTypeDesc(p.module, refType),
+      ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
+  genAssignment(p, a, b, {needToKeepAlive})  # set the object type:
+  bt = skipTypes(refType.lastSon, abstractRange)
+  genObjectInit(p, cpsStmts, bt, a, false)
+  gcUsage(e)
+
+proc genOfHelper(p: BProc; dest: PType; a: Rope): Rope =
+  # unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
+  # have to call it here first:
+  let ti = genTypeInfo(p.module, dest)
+  if tfFinal in dest.flags or (p.module.objHasKidsValid and
+                               tfObjHasKids notin dest.flags):
+    result = "$1.m_type == $2" % [a, ti]
+  else:
+    discard cgsym(p.module, "TNimType")
+    inc p.module.labels
+    let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
+    addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
+    result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
+  when false:
+    # former version:
+    result = rfmt(p.module, "#isObj($1.m_type, $2)",
+                  a, genTypeInfo(p.module, dest))
+
+proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
+  var a: TLoc
+  initLocExpr(p, x, a)
+  var dest = skipTypes(typ, typedescPtrs)
+  var r = rdLoc(a)
+  var nilCheck: Rope = nil
+  var t = skipTypes(a.t, abstractInst)
+  while t.kind in {tyVar, tyPtr, tyRef}:
+    if t.kind != tyVar: nilCheck = r
+    if t.kind != tyVar or not p.module.compileToCpp:
+      r = rfmt(nil, "(*$1)", r)
+    t = skipTypes(t.lastSon, typedescInst)
+  if not p.module.compileToCpp:
+    while t.kind == tyObject and t.sons[0] != nil:
+      add(r, ~".Sup")
+      t = skipTypes(t.sons[0], typedescInst)
+  if isObjLackingTypeField(t):
+    globalError(x.info, errGenerated,
+      "no 'of' operator available for pure objects")
+  if nilCheck != nil:
+    r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
+  else:
+    r = rfmt(p.module, "($1)", genOfHelper(p, dest, r))
+  putIntoDest(p, d, getSysType(tyBool), r)
+
+proc genOf(p: BProc, n: PNode, d: var TLoc) =
+  genOf(p, n.sons[1], n.sons[2].typ, d)
+
+proc genRepr(p: BProc, e: PNode, d: var TLoc) =
+  var a: TLoc
+  initLocExpr(p, e.sons[1], a)
+  var t = skipTypes(e.sons[1].typ, abstractVarRange)
+  case t.kind
+  of tyInt..tyInt64, tyUInt..tyUInt64:
+    putIntoDest(p, d, e.typ,
+                ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
+  of tyFloat..tyFloat128:
+    putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
+  of tyBool:
+    putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]))
+  of tyChar:
+    putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]))
+  of tyEnum, tyOrdinal:
+    putIntoDest(p, d, e.typ,
+                ropecg(p.module, "#reprEnum($1, $2)", [
+                rdLoc(a), genTypeInfo(p.module, t)]))
+  of tyString:
+    putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]))
+  of tySet:
+    putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [
+                addrLoc(a), genTypeInfo(p.module, t)]))
+  of tyOpenArray, tyVarargs:
+    var b: TLoc
+    case a.t.kind
+    of tyOpenArray, tyVarargs:
+      putIntoDest(p, b, e.typ, "$1, $1Len0" % [rdLoc(a)])
+    of tyString, tySequence:
+      putIntoDest(p, b, e.typ,
+                  "$1->data, $1->$2" % [rdLoc(a), lenField(p)])
+    of tyArray, tyArrayConstr:
+      putIntoDest(p, b, e.typ,
+                  "$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))])
+    else: internalError(e.sons[0].info, "genRepr()")
+    putIntoDest(p, d, e.typ,
+        ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
+        genTypeInfo(p.module, elemType(t))]))
+  of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
+     tySequence:
+    putIntoDest(p, d, e.typ,
+                ropecg(p.module, "#reprAny($1, $2)", [
+                rdLoc(a), genTypeInfo(p.module, t)]))
+  else:
+    putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
+                                   [addrLoc(a), genTypeInfo(p.module, t)]))
+  gcUsage(e)
+
+proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
+  var t = skipTypes(e.sons[1].typ, abstractVarRange)
+  putIntoDest(p, d, e.typ, genTypeInfo(p.module, t))
+
+proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
+  var a: TLoc
+  initLocExpr(p, n.sons[1], a)
+  a.r = ropecg(p.module, frmt, [rdLoc(a)])
+  if d.k == locNone: getTemp(p, n.typ, d)
+  genAssignment(p, d, a, {needToKeepAlive})
+  gcUsage(n)
+
+proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
+  var a = e.sons[1]
+  if a.kind == nkHiddenAddr: a = a.sons[0]
+  var typ = skipTypes(a.typ, abstractVar)
+  case typ.kind
+  of tyOpenArray, tyVarargs:
+    if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)")
+    else: unaryExpr(p, e, d, "$1Len0")
+  of tyCString:
+    useStringh(p.module)
+    if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)")
+    else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)")
+  of tyString, tySequence:
+    if not p.module.compileToCpp:
+      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)")
+      else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)")
+    else:
+      if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)")
+      else: unaryExpr(p, e, d, "($1 ? $1->len : 0)")
+  of tyArray, tyArrayConstr:
+    # YYY: length(sideeffect) is optimized away incorrectly?
+    if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
+    else: putIntoDest(p, d, e.typ, rope(lengthOrd(typ)))
+  else: internalError(e.info, "genArrayLen()")
+
+proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
+  var a, b: TLoc
+  assert(d.k == locNone)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  var t = skipTypes(e.sons[1].typ, abstractVar)
+  let setLenPattern = if not p.module.compileToCpp:
+      "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
+    else:
+      "$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
+
+  lineCg(p, cpsStmts, setLenPattern, [
+      rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
+      getTypeDesc(p.module, t.sons[0])])
+  keepAlive(p, a)
+  gcUsage(e)
+
+proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
+  binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
+  keepAlive(p, d)
+  gcUsage(e)
+
+proc genSwap(p: BProc, e: PNode, d: var TLoc) =
+  # swap(a, b) -->
+  # temp = a
+  # a = b
+  # b = temp
+  var a, b, tmp: TLoc
+  getTemp(p, skipTypes(e.sons[1].typ, abstractVar), tmp)
+  initLocExpr(p, e.sons[1], a) # eval a
+  initLocExpr(p, e.sons[2], b) # eval b
+  genAssignment(p, tmp, a, {})
+  genAssignment(p, a, b, {})
+  genAssignment(p, b, tmp, {})
+
+proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
+  # read a location of an set element; it may need a subtraction operation
+  # before the set operation
+  result = rdCharLoc(a)
+  assert(setType.kind == tySet)
+  if firstOrd(setType) != 0:
+    result = "($1- $2)" % [result, rope(firstOrd(setType))]
+
+proc fewCmps(s: PNode): bool =
+  # this function estimates whether it is better to emit code
+  # for constructing the set or generating a bunch of comparisons directly
+  if s.kind != nkCurly: internalError(s.info, "fewCmps")
+  if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags):
+    result = false            # it is better to emit the set generation code
+  elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
+    result = true             # better not emit the set if int is basetype!
+  else:
+    result = sonsLen(s) <= 8  # 8 seems to be a good value
+
+proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
+  putIntoDest(p, d, e.typ, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)])
+
+proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
+  case int(getSize(skipTypes(e.sons[1].typ, abstractVar)))
+  of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&7)))!=0)")
+  of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&15)))!=0)")
+  of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&31)))!=0)")
+  of 8: binaryExprIn(p, e, a, b, d, "(($1 &(IL64(1)<<(($2)&IL64(63))))!=0)")
+  else: binaryExprIn(p, e, a, b, d, "(($1[$2/8] &(1<<($2%8)))!=0)")
+
+proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
+  var a, b: TLoc
+  assert(d.k == locNone)
+  initLocExpr(p, e.sons[1], a)
+  initLocExpr(p, e.sons[2], b)
+  lineF(p, cpsStmts, frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])
+
+proc genInOp(p: BProc, e: PNode, d: var TLoc) =
+  var a, b, x, y: TLoc
+  if (e.sons[1].kind == nkCurly) and fewCmps(e.sons[1]):
+    # a set constructor but not a constant set:
+    # do not emit the set, but generate a bunch of comparisons; and if we do
+    # so, we skip the unnecessary range check: This is a semantical extension
+    # that code now relies on. :-/ XXX
+    let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
+               e.sons[2].sons[0]
+             else:
+               e.sons[2]
+    initLocExpr(p, ea, a)
+    initLoc(b, locExpr, e.typ, OnUnknown)
+    b.r = rope("(")
+    var length = sonsLen(e.sons[1])
+    for i in countup(0, length - 1):
+      if e.sons[1].sons[i].kind == nkRange:
+        initLocExpr(p, e.sons[1].sons[i].sons[0], x)
+        initLocExpr(p, e.sons[1].sons[i].sons[1], y)
+        addf(b.r, "$1 >= $2 && $1 <= $3",
+             [rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
+      else:
+        initLocExpr(p, e.sons[1].sons[i], x)
+        addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
+      if i < length - 1: add(b.r, " || ")
+    add(b.r, ")")
+    putIntoDest(p, d, e.typ, b.r)
+  else:
+    assert(e.sons[1].typ != nil)
+    assert(e.sons[2].typ != nil)
+    initLocExpr(p, e.sons[1], a)
+    initLocExpr(p, e.sons[2], b)
+    genInExprAux(p, e, a, b, d)
+
+proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
+  const
+    lookupOpr: array[mLeSet..mSymDiffSet, string] = [
+      "for ($1 = 0; $1 < $2; $1++) { $n" &
+        "  $3 = (($4[$1] & ~ $5[$1]) == 0);$n" &
+        "  if (!$3) break;}$n", "for ($1 = 0; $1 < $2; $1++) { $n" &
+        "  $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & "  if (!$3) break;}$n" &
+        "if ($3) $3 = (memcmp($4, $5, $2) != 0);$n",
+      "&", "|", "& ~", "^"]
+  var a, b, i: TLoc
+  var setType = skipTypes(e.sons[1].typ, abstractVar)
+  var size = int(getSize(setType))
+  case size
+  of 1, 2, 4, 8:
+    case op
+    of mIncl:
+      var ts = "NI" & $(size * 8)
+      binaryStmtInExcl(p, e, d,
+          "$1 |= ((" & ts & ")1)<<(($2)%(sizeof(" & ts & ")*8));$n")
+    of mExcl:
+      var ts = "NI" & $(size * 8)
+      binaryStmtInExcl(p, e, d, "$1 &= ~(((" & ts & ")1) << (($2) % (sizeof(" &
+          ts & ")*8)));$n")
+    of mCard:
+      if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)")
+      else: unaryExprChar(p, e, d, "#countBits64($1)")
+    of mLtSet: binaryExprChar(p, e, d, "(($1 & ~ $2 ==0)&&($1 != $2))")
+    of mLeSet: binaryExprChar(p, e, d, "(($1 & ~ $2)==0)")
+    of mEqSet: binaryExpr(p, e, d, "($1 == $2)")
+    of mMulSet: binaryExpr(p, e, d, "($1 & $2)")
+    of mPlusSet: binaryExpr(p, e, d, "($1 | $2)")
+    of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)")
+    of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)")
+    of mInSet:
+      genInOp(p, e, d)
+    else: internalError(e.info, "genSetOp()")
+  else:
+    case op
+    of mIncl: binaryStmtInExcl(p, e, d, "$1[$2/8] |=(1<<($2%8));$n")
+    of mExcl: binaryStmtInExcl(p, e, d, "$1[$2/8] &= ~(1<<($2%8));$n")
+    of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')')
+    of mLtSet, mLeSet:
+      getTemp(p, getSysType(tyInt), i) # our counter
+      initLocExpr(p, e.sons[1], a)
+      initLocExpr(p, e.sons[2], b)
+      if d.k == locNone: getTemp(p, getSysType(tyBool), d)
+      lineF(p, cpsStmts, lookupOpr[op],
+           [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
+    of mEqSet:
+      useStringh(p.module)
+      binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
+    of mMulSet, mPlusSet, mMinusSet, mSymDiffSet:
+      # we inline the simple for loop for better code generation:
+      getTemp(p, getSysType(tyInt), i) # our counter
+      initLocExpr(p, e.sons[1], a)
+      initLocExpr(p, e.sons[2], b)
+      if d.k == locNone: getTemp(p, a.t, d)
+      lineF(p, cpsStmts,
+           "for ($1 = 0; $1 < $2; $1++) $n" &
+           "  $3[$1] = $4[$1] $6 $5[$1];$n", [
+          rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
+          rope(lookupOpr[op])])
+    of mInSet: genInOp(p, e, d)
+    else: internalError(e.info, "genSetOp")
+
+proc genOrd(p: BProc, e: PNode, d: var TLoc) =
+  unaryExprChar(p, e, d, "$1")
+
+proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
+  const
+    ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyVarargs,
+                  tyArrayConstr}
+  # we use whatever C gives us. Except if we have a value-type, we need to go
+  # through its address:
+  var a: TLoc
+  initLocExpr(p, e.sons[1], a)
+  let etyp = skipTypes(e.typ, abstractRange)
+  if etyp.kind in ValueTypes and lfIndirect notin a.flags:
+    putIntoDest(p, d, e.typ, "(*($1*) ($2))" %
+        [getTypeDesc(p.module, e.typ), addrLoc(a)])
+  elif etyp.kind == tyProc and etyp.callConv == ccClosure:
+    putIntoDest(p, d, e.typ, "(($1) ($2))" %
+        [getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)])
+  else:
+    putIntoDest(p, d, e.typ, "(($1) ($2))" %
+        [getTypeDesc(p.module, e.typ), rdCharLoc(a)])
+
+proc genCast(p: BProc, e: PNode, d: var TLoc) =
+  const floatTypes = {tyFloat..tyFloat128}
+  let
+    destt = skipTypes(e.typ, abstractRange)
+    srct = skipTypes(e.sons[1].typ, abstractRange)
+  if destt.kind in floatTypes or srct.kind in floatTypes:
+    # 'cast' and some float type involved? --> use a union.
+    inc(p.labels)
+    var lbl = p.labels.rope
+    var tmp: TLoc
+    tmp.r = "LOC$1.source" % [lbl]
+    linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
+      getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
+    tmp.k = locExpr
+    tmp.t = srct
+    tmp.s = OnStack
+    tmp.flags = {}
+    expr(p, e.sons[1], tmp)
+    putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl])
+  else:
+    # I prefer the shorter cast version for pointer types -> generate less
+    # C code; plus it's the right thing to do for closures:
+    genSomeCast(p, e, d)
+
+proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
+  var a: TLoc
+  var dest = skipTypes(n.typ, abstractVar)
+  # range checks for unsigned turned out to be buggy and annoying:
+  if optRangeCheck notin p.options or dest.kind in {tyUInt..tyUInt64}:
+    initLocExpr(p, n.sons[0], a)
+    putIntoDest(p, d, n.typ, "(($1) ($2))" %
+        [getTypeDesc(p.module, dest), rdCharLoc(a)])
+  else:
+    initLocExpr(p, n.sons[0], a)
+    putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
+        getTypeDesc(p.module, dest), rdCharLoc(a),
+        genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
+        rope(magic)]))
+
+proc genConv(p: BProc, e: PNode, d: var TLoc) =
+  let destType = e.typ.skipTypes({tyVar, tyGenericInst})
+  if compareTypes(destType, e.sons[1].typ, dcEqIgnoreDistinct):
+    expr(p, e.sons[1], d)
+  else:
+    genSomeCast(p, e, d)
+
+proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)])
+
+proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  putIntoDest(p, d, skipTypes(n.typ, abstractVar),
+              ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]))
+  gcUsage(n)
+
+proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
+  var x: TLoc
+  var a = e.sons[1]
+  var b = e.sons[2]
+  if (a.kind == nkNilLit) or (b.kind == nkNilLit):
+    binaryExpr(p, e, d, "($1 == $2)")
+  elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
+    initLocExpr(p, e.sons[2], x)
+    putIntoDest(p, d, e.typ,
+      rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
+  elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
+    initLocExpr(p, e.sons[1], x)
+    putIntoDest(p, d, e.typ,
+      rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
+  else:
+    binaryExpr(p, e, d, "#eqStrings($1, $2)")
+
+proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
+  if {optNaNCheck, optInfCheck} * p.options != {}:
+    const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"]
+    var a, b: TLoc
+    assert(e.sons[1].typ != nil)
+    assert(e.sons[2].typ != nil)
+    initLocExpr(p, e.sons[1], a)
+    initLocExpr(p, e.sons[2], b)
+    putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))",
+                                  rope(opr[m]), rdLoc(a), rdLoc(b),
+                                  getSimpleTypeDesc(p.module, e[1].typ)))
+    if optNaNCheck in p.options:
+      linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d))
+    if optInfCheck in p.options:
+      linefmt(p, cpsStmts, "#infCheck($1);$n", rdLoc(d))
+  else:
+    binaryArith(p, e, d, m)
+
+proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
+  var line, filen: Rope
+  case op
+  of mOr, mAnd: genAndOr(p, e, d, op)
+  of mNot..mToBiggestInt: unaryArith(p, e, d, op)
+  of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op)
+  of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
+  of mShrI..mXor: binaryArith(p, e, d, op)
+  of mEqProc: genEqProc(p, e, d)
+  of mAddI..mPred: binaryArithOverflow(p, e, d, op)
+  of mRepr: genRepr(p, e, d)
+  of mGetTypeInfo: genGetTypeInfo(p, e, d)
+  of mSwap: genSwap(p, e, d)
+  of mUnaryLt:
+    if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
+    else: unaryExpr(p, e, d, "#subInt($1, 1)")
+  of mInc, mDec:
+    const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
+    const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
+                                               "$# = #subInt64($#, $#);$n"]
+    const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
+                                             "$# = #subInt($#, $#);$n"]
+    let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
+    if optOverflowCheck notin p.options or underlying.kind in {tyUInt..tyUInt64}:
+      binaryStmt(p, e, d, opr[op])
+    else:
+      var a, b: TLoc
+      assert(e.sons[1].typ != nil)
+      assert(e.sons[2].typ != nil)
+      initLocExpr(p, e.sons[1], a)
+      initLocExpr(p, e.sons[2], b)
+
+      let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar})
+      let res = binaryArithOverflowRaw(p, ranged, a, b,
+        if underlying.kind == tyInt64: fun64[op] else: fun[op])
+      putIntoDest(p, a, ranged, "($#)($#)" % [
+        getTypeDesc(p.module, ranged), res])
+
+  of mConStrStr: genStrConcat(p, e, d)
+  of mAppendStrCh:
+    binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
+    # strictly speaking we need to generate "keepAlive" here too, but this
+    # very likely not needed and would slow down the code too much I fear
+  of mAppendStrStr: genStrAppend(p, e, d)
+  of mAppendSeqElem: genSeqElemAppend(p, e, d)
+  of mEqStr: genStrEquals(p, e, d)
+  of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
+  of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
+  of mIsNil: genIsNil(p, e, d)
+  of mIntToStr: genDollar(p, e, d, "#nimIntToStr($1)")
+  of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)")
+  of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)")
+  of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
+  of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
+  of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
+  of mStrToStr: expr(p, e.sons[1], d)
+  of mEnumToStr: genRepr(p, e, d)
+  of mOf: genOf(p, e, d)
+  of mNew: genNew(p, e)
+  of mNewFinalize: genNewFinalize(p, e)
+  of mNewSeq: genNewSeq(p, e)
+  of mSizeOf:
+    let t = e.sons[1].typ.skipTypes({tyTypeDesc})
+    putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
+  of mChr: genSomeCast(p, e, d)
+  of mOrd: genOrd(p, e, d)
+  of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
+    genArrayLen(p, e, d, op)
+  of mXLenStr, mXLenSeq:
+    if not p.module.compileToCpp:
+      unaryExpr(p, e, d, "($1->Sup.len-1)")
+    else:
+      unaryExpr(p, e, d, "$1->len")
+  of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
+  of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
+  of mSetLengthStr: genSetLengthStr(p, e, d)
+  of mSetLengthSeq: genSetLengthSeq(p, e, d)
+  of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
+     mInSet:
+    genSetOp(p, e, d, op)
+  of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit,
+      mParseBiggestFloat:
+    var opr = e.sons[0].sym
+    if lfNoDecl notin opr.loc.flags:
+      discard cgsym(p.module, $opr.loc.r)
+    genCall(p, e, d)
+  of mReset: genReset(p, e)
+  of mEcho: genEcho(p, e[1].skipConv)
+  of mArrToSeq: genArrToSeq(p, e, d)
+  of mNLen..mNError, mSlurp..mQuoteAst:
+    localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
+  of mSpawn:
+    let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
+    expr(p, n, d)
+  of mParallel:
+    let n = semparallel.liftParallel(p.module.module, e)
+    expr(p, n, d)
+  of mDeepCopy:
+    var a, b: TLoc
+    let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
+    initLocExpr(p, x, a)
+    initLocExpr(p, e.sons[2], b)
+    genDeepCopy(p, a, b)
+  of mDotDot: genCall(p, e, d)
+  else: internalError(e.info, "genMagicExpr: " & $op)
+
+proc genConstExpr(p: BProc, n: PNode): Rope
+proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
+  if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
+    var t = getUniqueType(n.typ)
+    discard getTypeDesc(p.module, t) # so that any fields are initialized
+    var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
+    fillLoc(d, locData, t, "TMP" & rope(id), OnHeap)
+    if id == gBackendId:
+      # expression not found in the cache:
+      inc(gBackendId)
+      addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+           [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
+    result = true
+  else:
+    result = false
+
+proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
+  # example: { a..b, c, d, e, f..g }
+  # we have to emit an expression of the form:
+  # memset(tmp, 0, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c);
+  # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g);
+  var
+    a, b, idx: TLoc
+  if nfAllConst in e.flags:
+    putIntoDest(p, d, e.typ, genSetNode(p, e))
+  else:
+    if d.k == locNone: getTemp(p, e.typ, d)
+    if getSize(e.typ) > 8:
+      # big set:
+      useStringh(p.module)
+      lineF(p, cpsStmts, "memset($1, 0, sizeof($1));$n", [rdLoc(d)])
+      for i in countup(0, sonsLen(e) - 1):
+        if e.sons[i].kind == nkRange:
+          getTemp(p, getSysType(tyInt), idx) # our counter
+          initLocExpr(p, e.sons[i].sons[0], a)
+          initLocExpr(p, e.sons[i].sons[1], b)
+          lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
+              "$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d),
+              rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)])
+        else:
+          initLocExpr(p, e.sons[i], a)
+          lineF(p, cpsStmts, "$1[$2/8] |=(1<<($2%8));$n",
+               [rdLoc(d), rdSetElemLoc(a, e.typ)])
+    else:
+      # small set
+      var ts = "NI" & $(getSize(e.typ) * 8)
+      lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
+      for i in countup(0, sonsLen(e) - 1):
+        if e.sons[i].kind == nkRange:
+          getTemp(p, getSysType(tyInt), idx) # our counter
+          initLocExpr(p, e.sons[i].sons[0], a)
+          initLocExpr(p, e.sons[i].sons[1], b)
+          lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
+              "$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [
+              rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
+              rdSetElemLoc(b, e.typ)])
+        else:
+          initLocExpr(p, e.sons[i], a)
+          lineF(p, cpsStmts,
+               "$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n",
+               [rdLoc(d), rdSetElemLoc(a, e.typ)])
+
+proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
+  var rec: TLoc
+  if not handleConstExpr(p, n, d):
+    var t = getUniqueType(n.typ)
+    discard getTypeDesc(p.module, t) # so that any fields are initialized
+    if d.k == locNone: getTemp(p, t, d)
+    for i in countup(0, sonsLen(n) - 1):
+      var it = n.sons[i]
+      if it.kind == nkExprColonExpr: it = it.sons[1]
+      initLoc(rec, locExpr, it.typ, d.s)
+      rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
+      expr(p, it, rec)
+      when false:
+        initLoc(rec, locExpr, it.typ, d.s)
+        if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
+        rec.r = "$1.$2" % [rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)]
+        expr(p, it, rec)
+
+proc isConstClosure(n: PNode): bool {.inline.} =
+  result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
+      n.sons[1].kind == nkNilLit
+
+proc genClosure(p: BProc, n: PNode, d: var TLoc) =
+  assert n.kind == nkClosure
+
+  if isConstClosure(n):
+    inc(p.labels)
+    var tmp = "LOC" & rope(p.labels)
+    addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+        [getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
+    putIntoDest(p, d, n.typ, tmp)
+  else:
+    var tmp, a, b: TLoc
+    initLocExpr(p, n.sons[0], a)
+    initLocExpr(p, n.sons[1], b)
+    getTemp(p, n.typ, tmp)
+    linefmt(p, cpsStmts, "$1.ClPrc = $2; $1.ClEnv = $3;$n",
+            tmp.rdLoc, a.rdLoc, b.rdLoc)
+    putLocIntoDest(p, d, tmp)
+
+proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
+  var arr: TLoc
+  if not handleConstExpr(p, n, d):
+    if d.k == locNone: getTemp(p, n.typ, d)
+    for i in countup(0, sonsLen(n) - 1):
+      initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s)
+      arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
+      expr(p, n.sons[i], arr)
+
+proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
+  requestConstImpl(p, sym)
+  assert((sym.loc.r != nil) and (sym.loc.t != nil))
+  putLocIntoDest(p, d, sym.loc)
+
+proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) =
+  var length = sonsLen(n)
+  for i in countup(0, length - 2): genStmts(p, n.sons[i])
+  if length > 0: expr(p, n.sons[length - 1], d)
+
+proc upConv(p: BProc, n: PNode, d: var TLoc) =
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  var dest = skipTypes(n.typ, abstractPtrs)
+  if optObjCheck in p.options and not isObjLackingTypeField(dest):
+    var r = rdLoc(a)
+    var nilCheck: Rope = nil
+    var t = skipTypes(a.t, abstractInst)
+    while t.kind in {tyVar, tyPtr, tyRef}:
+      if t.kind != tyVar: nilCheck = r
+      if t.kind != tyVar or not p.module.compileToCpp:
+        r = "(*$1)" % [r]
+      t = skipTypes(t.lastSon, abstractInst)
+    if not p.module.compileToCpp:
+      while t.kind == tyObject and t.sons[0] != nil:
+        add(r, ".Sup")
+        t = skipTypes(t.sons[0], abstractInst)
+    if nilCheck != nil:
+      linefmt(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
+              nilCheck, r, genTypeInfo(p.module, dest))
+    else:
+      linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
+              r, genTypeInfo(p.module, dest))
+  if n.sons[0].typ.kind != tyObject:
+    putIntoDest(p, d, n.typ,
+                "(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)])
+  else:
+    putIntoDest(p, d, n.typ, "(*($1*) ($2))" %
+                             [getTypeDesc(p.module, dest), addrLoc(a)])
+
+proc downConv(p: BProc, n: PNode, d: var TLoc) =
+  if p.module.compileToCpp:
+    expr(p, n.sons[0], d)     # downcast does C++ for us
+  else:
+    var dest = skipTypes(n.typ, abstractPtrs)
+
+    var arg = n.sons[0]
+    while arg.kind == nkObjDownConv: arg = arg.sons[0]
+
+    var src = skipTypes(arg.typ, abstractPtrs)
+    var a: TLoc
+    initLocExpr(p, arg, a)
+    var r = rdLoc(a)
+    let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
+    if isRef:
+      add(r, "->Sup")
+    else:
+      add(r, ".Sup")
+    for i in countup(2, abs(inheritanceDiff(dest, src))): add(r, ".Sup")
+    if isRef:
+      # it can happen that we end up generating '&&x->Sup' here, so we pack
+      # the '&x->Sup' into a temporary and then those address is taken
+      # (see bug #837). However sometimes using a temporary is not correct:
+      # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
+      # this by ensuring the destination is also a pointer:
+      if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
+        getTemp(p, n.typ, d)
+        linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
+      else:
+        r = "&" & r
+        putIntoDest(p, d, n.typ, r)
+    else:
+      putIntoDest(p, d, n.typ, r)
+
+proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
+  var t = getUniqueType(n.typ)
+  discard getTypeDesc(p.module, t) # so that any fields are initialized
+  var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
+  var tmp = "TMP" & rope(id)
+
+  if id == gBackendId:
+    # expression not found in the cache:
+    inc(gBackendId)
+    addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+         [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
+
+  if d.k == locNone:
+    fillLoc(d, locData, t, tmp, OnHeap)
+  else:
+    putDataIntoDest(p, d, t, tmp)
+
+proc expr(p: BProc, n: PNode, d: var TLoc) =
+  case n.kind
+  of nkSym:
+    var sym = n.sym
+    case sym.kind
+    of skMethod:
+      if {sfDispatcher, sfForward} * sym.flags != {}:
+        # we cannot produce code for the dispatcher yet:
+        fillProcLoc(sym)
+        genProcPrototype(p.module, sym)
+      else:
+        genProc(p.module, sym)
+      putLocIntoDest(p, d, sym.loc)
+    of skProc, skConverter, skIterators:
+      genProc(p.module, sym)
+      if sym.loc.r == nil or sym.loc.t == nil:
+        internalError(n.info, "expr: proc not init " & sym.name.s)
+      putLocIntoDest(p, d, sym.loc)
+    of skConst:
+      if sfFakeConst in sym.flags:
+        if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
+        putLocIntoDest(p, d, sym.loc)
+      elif isSimpleConst(sym.typ):
+        putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ))
+      else:
+        genComplexConst(p, sym, d)
+    of skEnumField:
+      putIntoDest(p, d, n.typ, rope(sym.position))
+    of skVar, skForVar, skResult, skLet:
+      if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
+      if sym.loc.r == nil or sym.loc.t == nil:
+        #echo "FAILED FOR PRCO ", p.prc.name.s
+        internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
+      if sfThread in sym.flags:
+        accessThreadLocalVar(p, sym)
+        if emulatedThreadVars():
+          putIntoDest(p, d, sym.loc.t, "NimTV->" & sym.loc.r)
+        else:
+          putLocIntoDest(p, d, sym.loc)
+      else:
+        putLocIntoDest(p, d, sym.loc)
+    of skTemp:
+      if sym.loc.r == nil or sym.loc.t == nil:
+        #echo "FAILED FOR PRCO ", p.prc.name.s
+        #echo renderTree(p.prc.ast, {renderIds})
+        internalError(n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
+      putLocIntoDest(p, d, sym.loc)
+    of skParam:
+      if sym.loc.r == nil or sym.loc.t == nil:
+        #echo "FAILED FOR PRCO ", p.prc.name.s
+        #debug p.prc.typ.n
+        #echo renderTree(p.prc.ast, {renderIds})
+        internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
+      putLocIntoDest(p, d, sym.loc)
+    else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
+  of nkNilLit:
+    if not isEmptyType(n.typ):
+      putIntoDest(p, d, n.typ, genLiteral(p, n))
+  of nkStrLit..nkTripleStrLit:
+    putDataIntoDest(p, d, n.typ, genLiteral(p, n))
+  of nkIntLit..nkUInt64Lit,
+     nkFloatLit..nkFloat128Lit, nkCharLit:
+    putIntoDest(p, d, n.typ, genLiteral(p, n))
+  of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
+     nkCallStrLit:
+    genLineDir(p, n)
+    let op = n.sons[0]
+    if n.typ.isNil:
+      # discard the value:
+      var a: TLoc
+      if op.kind == nkSym and op.sym.magic != mNone:
+        genMagicExpr(p, n, a, op.sym.magic)
+      else:
+        genCall(p, n, a)
+    else:
+      # load it into 'd':
+      if op.kind == nkSym and op.sym.magic != mNone:
+        genMagicExpr(p, n, d, op.sym.magic)
+      else:
+        genCall(p, n, d)
+  of nkCurly:
+    if isDeepConstExpr(n) and n.len != 0:
+      putIntoDest(p, d, n.typ, genSetNode(p, n))
+    else:
+      genSetConstr(p, n, d)
+  of nkBracket:
+    if isDeepConstExpr(n) and n.len != 0:
+      exprComplexConst(p, n, d)
+    elif skipTypes(n.typ, abstractVarRange).kind == tySequence:
+      genSeqConstr(p, n, d)
+    else:
+      genArrayConstr(p, n, d)
+  of nkPar:
+    if isDeepConstExpr(n) and n.len != 0:
+      exprComplexConst(p, n, d)
+    else:
+      genTupleConstr(p, n, d)
+  of nkObjConstr: genObjConstr(p, n, d)
+  of nkCast: genCast(p, n, d)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
+  of nkHiddenAddr, nkAddr: genAddr(p, n, d)
+  of nkBracketExpr: genBracketExpr(p, n, d)
+  of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
+  of nkDotExpr: genRecordField(p, n, d)
+  of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
+  of nkBlockExpr, nkBlockStmt: genBlock(p, n, d)
+  of nkStmtListExpr: genStmtListExpr(p, n, d)
+  of nkStmtList:
+    for i in countup(0, sonsLen(n) - 1): genStmts(p, n.sons[i])
+  of nkIfExpr, nkIfStmt: genIf(p, n, d)
+  of nkObjDownConv: downConv(p, n, d)
+  of nkObjUpConv: upConv(p, n, d)
+  of nkChckRangeF: genRangeChck(p, n, d, "chckRangeF")
+  of nkChckRange64: genRangeChck(p, n, d, "chckRange64")
+  of nkChckRange: genRangeChck(p, n, d, "chckRange")
+  of nkStringToCString: convStrToCStr(p, n, d)
+  of nkCStringToString: convCStrToStr(p, n, d)
+  of nkLambdaKinds:
+    var sym = n.sons[namePos].sym
+    genProc(p.module, sym)
+    if sym.loc.r == nil or sym.loc.t == nil:
+      internalError(n.info, "expr: proc not init " & sym.name.s)
+    putLocIntoDest(p, d, sym.loc)
+  of nkClosure: genClosure(p, n, d)
+
+  of nkEmpty: discard
+  of nkWhileStmt: genWhileStmt(p, n)
+  of nkVarSection, nkLetSection: genVarStmt(p, n)
+  of nkConstSection: genConstStmt(p, n)
+  of nkForStmt: internalError(n.info, "for statement not eliminated")
+  of nkCaseStmt: genCase(p, n, d)
+  of nkReturnStmt: genReturnStmt(p, n)
+  of nkBreakStmt: genBreakStmt(p, n)
+  of nkAsgn: genAsgn(p, n, fastAsgn=false)
+  of nkFastAsgn:
+    # transf is overly aggressive with 'nkFastAsgn', so we work around here.
+    # See tests/run/tcnstseq3 for an example that would fail otherwise.
+    genAsgn(p, n, fastAsgn=p.prc != nil)
+  of nkDiscardStmt:
+    if n.sons[0].kind != nkEmpty:
+      genLineDir(p, n)
+      var a: TLoc
+      initLocExpr(p, n.sons[0], a)
+  of nkAsmStmt: genAsmStmt(p, n)
+  of nkTryStmt:
+    if p.module.compileToCpp: genTryCpp(p, n, d)
+    else: genTry(p, n, d)
+  of nkRaiseStmt: genRaiseStmt(p, n)
+  of nkTypeSection:
+    # we have to emit the type information for object types here to support
+    # separate compilation:
+    genTypeSection(p.module, n)
+  of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
+     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
+     nkFromStmt, nkTemplateDef, nkMacroDef:
+    discard
+  of nkPragma: genPragma(p, n)
+  of nkPragmaBlock: expr(p, n.lastSon, d)
+  of nkProcDef, nkMethodDef, nkConverterDef:
+    if n.sons[genericParamsPos].kind == nkEmpty:
+      var prc = n.sons[namePos].sym
+      # due to a bug/limitation in the lambda lifting, unused inner procs
+      # are not transformed correctly. We work around this issue (#411) here
+      # by ensuring it's no inner proc (owner is a module):
+      if prc.skipGenericOwner.kind == skModule:
+        if (optDeadCodeElim notin gGlobalOptions and
+            sfDeadCodeElim notin getModule(prc).flags) or
+            ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
+            (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
+            (prc.kind == skMethod):
+          # we have not only the header:
+          if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
+            genProc(p.module, prc)
+  of nkParForStmt: genParForStmt(p, n)
+  of nkState: genState(p, n)
+  of nkGotoState: genGotoState(p, n)
+  of nkBreakState: genBreakState(p, n)
+  else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
+
+proc genNamedConstExpr(p: BProc, n: PNode): Rope =
+  if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
+  else: result = genConstExpr(p, n)
+
+proc genConstSimpleList(p: BProc, n: PNode): Rope =
+  var length = sonsLen(n)
+  result = rope("{")
+  for i in countup(0, length - 2):
+    addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
+  if length > 0: add(result, genNamedConstExpr(p, n.sons[length - 1]))
+  addf(result, "}$n", [])
+
+proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
+  var data = "{{$1, $1}" % [n.len.rope]
+  if n.len > 0:
+    # array part needs extra curlies:
+    data.add(", {")
+    for i in countup(0, n.len - 1):
+      if i > 0: data.addf(",$n", [])
+      data.add genConstExpr(p, n.sons[i])
+    data.add("}")
+  data.add("}")
+
+  inc(gBackendId)
+  result = "CNSTSEQ" & gBackendId.rope
+
+  appcg(p.module, cfsData,
+        "NIM_CONST struct {$n" &
+        "  #TGenericSeq Sup;$n" &
+        "  $1 data[$2];$n" &
+        "} $3 = $4;$n", [
+        getTypeDesc(p.module, t.sons[0]), n.len.rope, result, data])
+
+  result = "(($1)&$2)" % [getTypeDesc(p.module, t), result]
+
+proc genConstExpr(p: BProc, n: PNode): Rope =
+  case n.kind
+  of nkHiddenStdConv, nkHiddenSubConv:
+    result = genConstExpr(p, n.sons[1])
+  of nkCurly:
+    var cs: TBitSet
+    toBitSet(n, cs)
+    result = genRawSetData(cs, int(getSize(n.typ)))
+  of nkBracket, nkPar, nkClosure, nkObjConstr:
+    var t = skipTypes(n.typ, abstractInst)
+    if t.kind == tySequence:
+      result = genConstSeq(p, n, t)
+    else:
+      result = genConstSimpleList(p, n)
+  else:
+    var d: TLoc
+    initLocExpr(p, n, d)
+    result = rdLoc(d)
diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim
new file mode 100644
index 000000000..2a37257b6
--- /dev/null
+++ b/compiler/ccgmerge.nim
@@ -0,0 +1,298 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the merge operation of 2 different C files. This
+## is needed for incremental compilation.
+
+import
+  ast, astalgo, ropes, options, strutils, nimlexbase, msgs, cgendata, rodutils,
+  intsets, platform, llstream
+
+# Careful! Section marks need to contain a tabulator so that they cannot
+# be part of C string literals.
+
+const
+  CFileSectionNames: array[TCFileSection, string] = [
+    cfsMergeInfo: "",
+    cfsHeaders: "NIM_merge_HEADERS",
+    cfsForwardTypes: "NIM_merge_FORWARD_TYPES",
+    cfsTypes: "NIM_merge_TYPES",
+    cfsSeqTypes: "NIM_merge_SEQ_TYPES",
+    cfsFieldInfo: "NIM_merge_FIELD_INFO",
+    cfsTypeInfo: "NIM_merge_TYPE_INFO",
+    cfsProcHeaders: "NIM_merge_PROC_HEADERS",
+    cfsData: "NIM_merge_DATA",
+    cfsVars: "NIM_merge_VARS",
+    cfsProcs: "NIM_merge_PROCS",
+    cfsInitProc: "NIM_merge_INIT_PROC",
+    cfsTypeInit1: "NIM_merge_TYPE_INIT1",
+    cfsTypeInit2: "NIM_merge_TYPE_INIT2",
+    cfsTypeInit3: "NIM_merge_TYPE_INIT3",
+    cfsDebugInit: "NIM_merge_DEBUG_INIT",
+    cfsDynLibInit: "NIM_merge_DYNLIB_INIT",
+    cfsDynLibDeinit: "NIM_merge_DYNLIB_DEINIT",
+  ]
+  CProcSectionNames: array[TCProcSection, string] = [
+    cpsLocals: "NIM_merge_PROC_LOCALS",
+    cpsInit: "NIM_merge_PROC_INIT",
+    cpsStmts: "NIM_merge_PROC_BODY"
+  ]
+  NimMergeEndMark = "/*\tNIM_merge_END:*/"
+
+proc genSectionStart*(fs: TCFileSection): Rope =
+  if compilationCachePresent:
+    result = rope(tnl)
+    add(result, "/*\t")
+    add(result, CFileSectionNames[fs])
+    add(result, ":*/")
+    add(result, tnl)
+
+proc genSectionEnd*(fs: TCFileSection): Rope =
+  if compilationCachePresent:
+    result = rope(NimMergeEndMark & tnl)
+
+proc genSectionStart*(ps: TCProcSection): Rope =
+  if compilationCachePresent:
+    result = rope(tnl)
+    add(result, "/*\t")
+    add(result, CProcSectionNames[ps])
+    add(result, ":*/")
+    add(result, tnl)
+
+proc genSectionEnd*(ps: TCProcSection): Rope =
+  if compilationCachePresent:
+    result = rope(NimMergeEndMark & tnl)
+
+proc writeTypeCache(a: TIdTable, s: var string) =
+  var i = 0
+  for id, value in pairs(a):
+    if i == 10:
+      i = 0
+      s.add(tnl)
+    else:
+      s.add(' ')
+    encodeVInt(id, s)
+    s.add(':')
+    encodeStr($Rope(value), s)
+    inc i
+  s.add('}')
+
+proc writeIntSet(a: IntSet, s: var string) =
+  var i = 0
+  for x in items(a):
+    if i == 10:
+      i = 0
+      s.add(tnl)
+    else:
+      s.add(' ')
+    encodeVInt(x, s)
+    inc i
+  s.add('}')
+
+proc genMergeInfo*(m: BModule): Rope =
+  if optSymbolFiles notin gGlobalOptions: return nil
+  var s = "/*\tNIM_merge_INFO:"
+  s.add(tnl)
+  s.add("typeCache:{")
+  writeTypeCache(m.typeCache, s)
+  s.add("declared:{")
+  writeIntSet(m.declaredThings, s)
+  s.add("typeInfo:{")
+  writeIntSet(m.typeInfoMarker, s)
+  s.add("labels:")
+  encodeVInt(m.labels, s)
+  s.add(" hasframe:")
+  encodeVInt(ord(m.frameDeclared), s)
+  s.add(tnl)
+  s.add("*/")
+  result = s.rope
+
+template `^`(pos: int): expr = L.buf[pos]
+
+proc skipWhite(L: var TBaseLexer) =
+  var pos = L.bufpos
+  while true:
+    case ^pos
+    of CR: pos = nimlexbase.handleCR(L, pos)
+    of LF: pos = nimlexbase.handleLF(L, pos)
+    of ' ': inc pos
+    else: break
+  L.bufpos = pos
+
+proc skipUntilCmd(L: var TBaseLexer) =
+  var pos = L.bufpos
+  while true:
+    case ^pos
+    of CR: pos = nimlexbase.handleCR(L, pos)
+    of LF: pos = nimlexbase.handleLF(L, pos)
+    of '\0': break
+    of '/':
+      if ^(pos+1) == '*' and ^(pos+2) == '\t':
+        inc pos, 3
+        break
+      inc pos
+    else: inc pos
+  L.bufpos = pos
+
+proc atEndMark(buf: cstring, pos: int): bool =
+  var s = 0
+  while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
+  result = s == NimMergeEndMark.len
+
+proc readVerbatimSection(L: var TBaseLexer): Rope =
+  var pos = L.bufpos
+  var buf = L.buf
+  var r = newStringOfCap(30_000)
+  while true:
+    case buf[pos]
+    of CR:
+      pos = nimlexbase.handleCR(L, pos)
+      buf = L.buf
+      r.add(tnl)
+    of LF:
+      pos = nimlexbase.handleLF(L, pos)
+      buf = L.buf
+      r.add(tnl)
+    of '\0':
+      internalError("ccgmerge: expected: " & NimMergeEndMark)
+      break
+    else:
+      if atEndMark(buf, pos):
+        inc pos, NimMergeEndMark.len
+        break
+      r.add(buf[pos])
+      inc pos
+  L.bufpos = pos
+  result = r.rope
+
+proc readKey(L: var TBaseLexer, result: var string) =
+  var pos = L.bufpos
+  var buf = L.buf
+  setLen(result, 0)
+  while buf[pos] in IdentChars:
+    result.add(buf[pos])
+    inc pos
+  if buf[pos] != ':': internalError("ccgmerge: ':' expected")
+  L.bufpos = pos + 1 # skip ':'
+
+proc newFakeType(id: int): PType =
+  new(result)
+  result.id = id
+
+proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
+  if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
+  inc L.bufpos
+  while ^L.bufpos != '}':
+    skipWhite(L)
+    var key = decodeVInt(L.buf, L.bufpos)
+    if ^L.bufpos != ':': internalError("ccgmerge: ':' expected")
+    inc L.bufpos
+    var value = decodeStr(L.buf, L.bufpos)
+    # XXX little hack: we create a "fake" type object with the correct Id
+    # better would be to adapt the data structure to not even store the
+    # object as key, but only the Id
+    idTablePut(result, newFakeType(key), value.rope)
+  inc L.bufpos
+
+proc readIntSet(L: var TBaseLexer, result: var IntSet) =
+  if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
+  inc L.bufpos
+  while ^L.bufpos != '}':
+    skipWhite(L)
+    var key = decodeVInt(L.buf, L.bufpos)
+    result.incl(key)
+  inc L.bufpos
+
+proc processMergeInfo(L: var TBaseLexer, m: BModule) =
+  var k = newStringOfCap("typeCache".len)
+  while true:
+    skipWhite(L)
+    if ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
+      inc(L.bufpos, 2)
+      break
+    readKey(L, k)
+    case k
+    of "typeCache": readTypeCache(L, m.typeCache)
+    of "declared":  readIntSet(L, m.declaredThings)
+    of "typeInfo":  readIntSet(L, m.typeInfoMarker)
+    of "labels":    m.labels = decodeVInt(L.buf, L.bufpos)
+    of "hasframe":  m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
+    else: internalError("ccgmerge: unknown key: " & k)
+
+when not defined(nimhygiene):
+  {.pragma: inject.}
+
+template withCFile(cfilename: string, body: stmt) {.immediate.} =
+  var s = llStreamOpen(cfilename, fmRead)
+  if s == nil: return
+  var L {.inject.}: TBaseLexer
+  openBaseLexer(L, s)
+  var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len)
+  while true:
+    skipUntilCmd(L)
+    if ^L.bufpos == '\0': break
+    body
+  closeBaseLexer(L)
+
+proc readMergeInfo*(cfilename: string, m: BModule) =
+  ## reads the merge meta information into `m`.
+  withCFile(cfilename):
+    readKey(L, k)
+    if k == "NIM_merge_INFO":
+      processMergeInfo(L, m)
+      break
+
+type
+  TMergeSections = object
+    f: TCFileSections
+    p: TCProcSections
+
+proc readMergeSections(cfilename: string, m: var TMergeSections) =
+  ## reads the merge sections into `m`.
+  withCFile(cfilename):
+    readKey(L, k)
+    if k == "NIM_merge_INFO":
+      discard
+    elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
+      inc(L.bufpos, 2)
+      # read back into section
+      skipWhite(L)
+      var verbatim = readVerbatimSection(L)
+      skipWhite(L)
+      var sectionA = CFileSectionNames.find(k)
+      if sectionA > 0 and sectionA <= high(TCFileSection).int:
+        m.f[TCFileSection(sectionA)] = verbatim
+      else:
+        var sectionB = CProcSectionNames.find(k)
+        if sectionB >= 0 and sectionB <= high(TCProcSection).int:
+          m.p[TCProcSection(sectionB)] = verbatim
+        else:
+          internalError("ccgmerge: unknown section: " & k)
+    else:
+      internalError("ccgmerge: '*/' expected")
+
+proc mergeRequired*(m: BModule): bool =
+  for i in cfsHeaders..cfsProcs:
+    if m.s[i] != nil:
+      #echo "not empty: ", i, " ", m.s[i]
+      return true
+  for i in low(TCProcSection)..high(TCProcSection):
+    if m.initProc.s(i) != nil:
+      #echo "not empty: ", i, " ", m.initProc.s[i]
+      return true
+
+proc mergeFiles*(cfilename: string, m: BModule) =
+  ## merges the C file with the old version on hard disc.
+  var old: TMergeSections
+  readMergeSections(cfilename, old)
+  # do the merge; old section before new section:
+  for i in low(TCFileSection)..high(TCFileSection):
+    m.s[i] = old.f[i] & m.s[i]
+  for i in low(TCProcSection)..high(TCProcSection):
+    m.initProc.s(i) = old.p[i] & m.initProc.s(i)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
new file mode 100644
index 000000000..6d29b1684
--- /dev/null
+++ b/compiler/ccgstmts.nim
@@ -0,0 +1,1112 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# included from cgen.nim
+
+const
+  RangeExpandLimit = 256      # do not generate ranges
+                              # over 'RangeExpandLimit' elements
+  stringCaseThreshold = 8
+    # above X strings a hash-switch for strings is generated
+
+proc registerGcRoot(p: BProc, v: PSym) =
+  if gSelectedGC in {gcMarkAndSweep, gcGenerational} and
+      containsGarbageCollectedRef(v.loc.t):
+    # we register a specialized marked proc here; this has the advantage
+    # that it works out of the box for thread local storage then :-)
+    let prc = genTraverseProcForGlobal(p.module, v)
+    linefmt(p.module.initProc, cpsStmts,
+      "#nimRegisterGlobalMarker($1);$n", prc)
+
+proc isAssignedImmediately(n: PNode): bool {.inline.} =
+  if n.kind == nkEmpty: return false
+  if isInvalidReturnType(n.typ):
+    # var v = f()
+    # is transformed into: var v;  f(addr v)
+    # where 'f' **does not** initialize the result!
+    return false
+  result = true
+
+proc genVarTuple(p: BProc, n: PNode) =
+  var tup, field: TLoc
+  if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
+  var L = sonsLen(n)
+
+  # if we have a something that's been captured, use the lowering instead:
+  var useLowering = false
+  for i in countup(0, L-3):
+    if n[i].kind != nkSym:
+      useLowering = true; break
+  if useLowering:
+    genStmts(p, lowerTupleUnpacking(n, p.prc))
+    return
+  genLineDir(p, n)
+  initLocExpr(p, n.sons[L-1], tup)
+  var t = tup.t.getUniqueType
+  for i in countup(0, L-3):
+    var v = n.sons[i].sym
+    if sfCompileTime in v.flags: continue
+    if sfGlobal in v.flags:
+      assignGlobalVar(p, v)
+      genObjectInit(p, cpsInit, v.typ, v.loc, true)
+      registerGcRoot(p, v)
+    else:
+      assignLocalVar(p, v)
+      initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
+    initLoc(field, locExpr, t.sons[i], tup.s)
+    if t.kind == tyTuple:
+      field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
+    else:
+      if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
+      field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
+    putLocIntoDest(p, v.loc, field)
+
+proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
+
+proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
+  if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
+                                 ri.sons[0].sym.magic == mNone):
+    genAsgnCall(p, le, ri, a)
+  elif ri.kind in {nkDerefExpr, nkHiddenDeref}:
+    # this is a hacky way to fix #1181 (tmissingderef)::
+    #
+    #  var arr1 = cast[ptr array[4, int8]](addr foo)[]
+    #
+    # However, fixing this properly really requires modelling 'array' as
+    # a 'struct' in C to preserve dereferencing semantics completely. Not
+    # worth the effort until version 1.0 is out.
+    genDeref(p, ri, a, enforceDeref=true)
+  else:
+    expr(p, ri, a)
+
+proc startBlock(p: BProc, start: FormatStr = "{$n",
+                args: varargs[Rope]): int {.discardable.} =
+  lineCg(p, cpsStmts, start, args)
+  inc(p.labels)
+  result = len(p.blocks)
+  setLen(p.blocks, result + 1)
+  p.blocks[result].id = p.labels
+  p.blocks[result].nestedTryStmts = p.nestedTryStmts.len.int16
+  p.blocks[result].nestedExceptStmts = p.inExceptBlock.int16
+
+proc assignLabel(b: var TBlock): Rope {.inline.} =
+  b.label = "LA" & b.id.rope
+  result = b.label
+
+proc blockBody(b: var TBlock): Rope =
+  result = b.sections[cpsLocals]
+  if b.frameLen > 0:
+    result.addf("F.len+=$1;$n", [b.frameLen.rope])
+  result.add(b.sections[cpsInit])
+  result.add(b.sections[cpsStmts])
+
+proc endBlock(p: BProc, blockEnd: Rope) =
+  let topBlock = p.blocks.len-1
+  # the block is merged into the parent block
+  add(p.blocks[topBlock-1].sections[cpsStmts], p.blocks[topBlock].blockBody)
+  setLen(p.blocks, topBlock)
+  # this is done after the block is popped so $n is
+  # properly indented when pretty printing is enabled
+  line(p, cpsStmts, blockEnd)
+
+proc endBlock(p: BProc) =
+  let topBlock = p.blocks.len - 1
+  var blockEnd = if p.blocks[topBlock].label != nil:
+      rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
+    else:
+      ~"}$n"
+  let frameLen = p.blocks[topBlock].frameLen
+  if frameLen > 0:
+    blockEnd.addf("F.len-=$1;$n", [frameLen.rope])
+  endBlock(p, blockEnd)
+
+proc genSimpleBlock(p: BProc, stmts: PNode) {.inline.} =
+  startBlock(p)
+  genStmts(p, stmts)
+  endBlock(p)
+
+proc exprBlock(p: BProc, n: PNode, d: var TLoc) =
+  startBlock(p)
+  expr(p, n, d)
+  endBlock(p)
+
+template preserveBreakIdx(body: stmt): stmt {.immediate.} =
+  var oldBreakIdx = p.breakIdx
+  body
+  p.breakIdx = oldBreakIdx
+
+proc genState(p: BProc, n: PNode) =
+  internalAssert n.len == 1 and n.sons[0].kind == nkIntLit
+  let idx = n.sons[0].intVal
+  linefmt(p, cpsStmts, "STATE$1: ;$n", idx.rope)
+
+proc genGotoState(p: BProc, n: PNode) =
+  # we resist the temptation to translate it into duff's device as it later
+  # will be translated into computed gotos anyway for GCC at least:
+  # switch (x.state) {
+  #   case 0: goto STATE0;
+  # ...
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
+  p.beforeRetNeeded = true
+  lineF(p, cpsStmts, "case -1: goto BeforeRet;$n", [])
+  for i in 0 .. lastOrd(n.sons[0].typ):
+    lineF(p, cpsStmts, "case $1: goto STATE$1;$n", [rope(i)])
+  lineF(p, cpsStmts, "}$n", [])
+
+proc genBreakState(p: BProc, n: PNode) =
+  var a: TLoc
+  if n.sons[0].kind == nkClosure:
+    # XXX this produces quite inefficient code!
+    initLocExpr(p, n.sons[0].sons[1], a)
+    lineF(p, cpsStmts, "if (((NI*) $1)[0] < 0) break;$n", [rdLoc(a)])
+  else:
+    initLocExpr(p, n.sons[0], a)
+    # the environment is guaranteed to contain the 'state' field at offset 0:
+    lineF(p, cpsStmts, "if ((((NI*) $1.ClEnv)[0]) < 0) break;$n", [rdLoc(a)])
+  #  lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
+
+proc genVarPrototypeAux(m: BModule, sym: PSym)
+
+proc genGotoVar(p: BProc; value: PNode) =
+  if value.kind notin {nkCharLit..nkUInt64Lit}:
+    localError(value.info, "'goto' target must be a literal value")
+  else:
+    lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
+
+proc genSingleVar(p: BProc, a: PNode) =
+  var v = a.sons[0].sym
+  if {sfCompileTime, sfGoto} * v.flags != {}:
+    # translate 'var state {.goto.} = X' into 'goto LX':
+    if sfGoto in v.flags: genGotoVar(p, a.sons[2])
+    return
+  var targetProc = p
+  if sfGlobal in v.flags:
+    if v.flags * {sfImportc, sfExportc} == {sfImportc} and
+        a.sons[2].kind == nkEmpty and
+        v.loc.flags * {lfHeader, lfNoDecl} != {}:
+      return
+    if sfPure in v.flags:
+      # v.owner.kind != skModule:
+      targetProc = p.module.preInitProc
+    assignGlobalVar(targetProc, v)
+    # XXX: be careful here.
+    # Global variables should not be zeromem-ed within loops
+    # (see bug #20).
+    # That's why we are doing the construction inside the preInitProc.
+    # genObjectInit relies on the C runtime's guarantees that
+    # global variables will be initialized to zero.
+    genObjectInit(p.module.preInitProc, cpsInit, v.typ, v.loc, true)
+    # Alternative construction using default constructor (which may zeromem):
+    # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
+    if sfExportc in v.flags and generatedHeader != nil:
+      genVarPrototypeAux(generatedHeader, v)
+    registerGcRoot(p, v)
+  else:
+    let value = a.sons[2]
+    let imm = isAssignedImmediately(value)
+    if imm and p.module.compileToCpp and p.splitDecls == 0 and
+        not containsHiddenPointer(v.typ):
+      # C++ really doesn't like things like 'Foo f; f = x' as that invokes a
+      # parameterless constructor followed by an assignment operator. So we
+      # generate better code here:
+      genLineDir(p, a)
+      let decl = localVarDecl(p, v)
+      var tmp: TLoc
+      if value.kind in nkCallKinds and value[0].kind == nkSym and
+           sfConstructor in value[0].sym.flags:
+        var params: Rope
+        let typ = skipTypes(value.sons[0].typ, abstractInst)
+        assert(typ.kind == tyProc)
+        for i in 1.. <value.len:
+          if params != nil: params.add(~", ")
+          assert(sonsLen(typ) == sonsLen(typ.n))
+          add(params, genOtherArg(p, value, i, typ))
+        lineF(p, cpsStmts, "$#($#);$n", [decl, params])
+      else:
+        initLocExprSingleUse(p, value, tmp)
+        lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
+      return
+    assignLocalVar(p, v)
+    initLocalVar(p, v, imm)
+
+  if a.sons[2].kind != nkEmpty:
+    genLineDir(targetProc, a)
+    loadInto(targetProc, a.sons[0], a.sons[2], v.loc)
+
+proc genClosureVar(p: BProc, a: PNode) =
+  var immediateAsgn = a.sons[2].kind != nkEmpty
+  if immediateAsgn:
+    var v: TLoc
+    initLocExpr(p, a.sons[0], v)
+    genLineDir(p, a)
+    loadInto(p, a.sons[0], a.sons[2], v)
+
+proc genVarStmt(p: BProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if a.kind == nkCommentStmt: continue
+    if a.kind == nkIdentDefs:
+      # can be a lifted var nowadays ...
+      if a.sons[0].kind == nkSym:
+        genSingleVar(p, a)
+      else:
+        genClosureVar(p, a)
+    else:
+      genVarTuple(p, a)
+
+proc genConstStmt(p: BProc, t: PNode) =
+  for i in countup(0, sonsLen(t) - 1):
+    var it = t.sons[i]
+    if it.kind == nkCommentStmt: continue
+    if it.kind != nkConstDef: internalError(t.info, "genConstStmt")
+    var c = it.sons[0].sym
+    if c.typ.containsCompileTimeOnly: continue
+    if sfFakeConst in c.flags:
+      genSingleVar(p, it)
+    elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
+        c.ast.len != 0:
+      if not emitLazily(c): requestConstImpl(p, c)
+
+proc genIf(p: BProc, n: PNode, d: var TLoc) =
+  #
+  #  { if (!expr1) goto L1;
+  #   thenPart }
+  #  goto LEnd
+  #  L1:
+  #  { if (!expr2) goto L2;
+  #   thenPart2 }
+  #  goto LEnd
+  #  L2:
+  #  { elsePart }
+  #  Lend:
+  var
+    a: TLoc
+    lelse: TLabel
+  if not isEmptyType(n.typ) and d.k == locNone:
+    getTemp(p, n.typ, d)
+  genLineDir(p, n)
+  let lend = getLabel(p)
+  for i in countup(0, sonsLen(n) - 1):
+    let it = n.sons[i]
+    if it.len == 2:
+      when newScopeForIf: startBlock(p)
+      initLocExprSingleUse(p, it.sons[0], a)
+      lelse = getLabel(p)
+      inc(p.labels)
+      lineF(p, cpsStmts, "if (!$1) goto $2;$n",
+            [rdLoc(a), lelse])
+      when not newScopeForIf: startBlock(p)
+      if p.module.compileToCpp:
+        # avoid "jump to label crosses initialization" error:
+        add(p.s(cpsStmts), "{")
+        expr(p, it.sons[1], d)
+        add(p.s(cpsStmts), "}")
+      else:
+        expr(p, it.sons[1], d)
+      endBlock(p)
+      if sonsLen(n) > 1:
+        lineF(p, cpsStmts, "goto $1;$n", [lend])
+      fixLabel(p, lelse)
+    elif it.len == 1:
+      startBlock(p)
+      expr(p, it.sons[0], d)
+      endBlock(p)
+    else: internalError(n.info, "genIf()")
+  if sonsLen(n) > 1: fixLabel(p, lend)
+
+
+proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
+  # Called by return and break stmts.
+  # Deals with issues faced when jumping out of try/except/finally stmts,
+
+  var stack: seq[PNode]
+  newSeq(stack, 0)
+
+  var alreadyPoppedCnt = p.inExceptBlock
+  for i in countup(1, howManyTrys):
+    if not p.module.compileToCpp:
+      # Pop safe points generated by try
+      if alreadyPoppedCnt > 0:
+        dec alreadyPoppedCnt
+      else:
+        linefmt(p, cpsStmts, "#popSafePoint();$n")
+
+    # Pop this try-stmt of the list of nested trys
+    # so we don't infinite recurse on it in the next step.
+    var tryStmt = p.nestedTryStmts.pop
+    stack.add(tryStmt)
+
+    # Find finally-stmt for this try-stmt
+    # and generate a copy of its sons
+    var finallyStmt = lastSon(tryStmt)
+    if finallyStmt.kind == nkFinally:
+      genStmts(p, finallyStmt.sons[0])
+
+  # push old elements again:
+  for i in countdown(howManyTrys-1, 0):
+    p.nestedTryStmts.add(stack[i])
+
+  if not p.module.compileToCpp:
+    # Pop exceptions that was handled by the
+    # except-blocks we are in
+    for i in countdown(howManyExcepts-1, 0):
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+
+proc genReturnStmt(p: BProc, t: PNode) =
+  p.beforeRetNeeded = true
+  genLineDir(p, t)
+  if (t.sons[0].kind != nkEmpty): genStmts(p, t.sons[0])
+  blockLeaveActions(p,
+    howManyTrys    = p.nestedTryStmts.len,
+    howManyExcepts = p.inExceptBlock)
+  if (p.finallySafePoints.len > 0):
+    # If we're in a finally block, and we came here by exception
+    # consume it before we return.
+    var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
+    linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
+  lineF(p, cpsStmts, "goto BeforeRet;$n", [])
+
+proc genGotoForCase(p: BProc; caseStmt: PNode) =
+  for i in 1 .. <caseStmt.len:
+    startBlock(p)
+    let it = caseStmt.sons[i]
+    for j in 0 .. it.len-2:
+      if it.sons[j].kind == nkRange:
+        localError(it.info, "range notation not available for computed goto")
+        return
+      let val = getOrdValue(it.sons[j])
+      lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
+    genStmts(p, it.lastSon)
+    endBlock(p)
+
+proc genComputedGoto(p: BProc; n: PNode) =
+  # first pass: Generate array of computed labels:
+  var casePos = -1
+  var arraySize: int
+  for i in 0 .. <n.len:
+    let it = n.sons[i]
+    if it.kind == nkCaseStmt:
+      if lastSon(it).kind != nkOfBranch:
+        localError(it.info,
+            "case statement must be exhaustive for computed goto"); return
+      casePos = i
+      let aSize = lengthOrd(it.sons[0].typ)
+      if aSize > 10_000:
+        localError(it.info,
+            "case statement has too many cases for computed goto"); return
+      arraySize = aSize.int
+      if firstOrd(it.sons[0].typ) != 0:
+        localError(it.info,
+            "case statement has to start at 0 for computed goto"); return
+  if casePos < 0:
+    localError(n.info, "no case statement found for computed goto"); return
+  var id = p.labels+1
+  inc p.labels, arraySize+1
+  let tmp = "TMP$1" % [id.rope]
+  var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
+  for i in 1..arraySize-1:
+    gotoArray.addf("&&TMP$#, ", [(id+i).rope])
+  gotoArray.addf("&&TMP$#};$n", [(id+arraySize).rope])
+  line(p, cpsLocals, gotoArray)
+
+  let topBlock = p.blocks.len-1
+  let oldBody = p.blocks[topBlock].sections[cpsStmts]
+  p.blocks[topBlock].sections[cpsStmts] = nil
+
+  for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
+  let tailB = p.blocks[topBlock].sections[cpsStmts]
+
+  p.blocks[topBlock].sections[cpsStmts] = nil
+  for j in 0 .. casePos-1: genStmts(p, n.sons[j])
+  let tailA = p.blocks[topBlock].sections[cpsStmts]
+
+  p.blocks[topBlock].sections[cpsStmts] = oldBody & tailA
+
+  let caseStmt = n.sons[casePos]
+  var a: TLoc
+  initLocExpr(p, caseStmt.sons[0], a)
+  # first goto:
+  lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
+
+  for i in 1 .. <caseStmt.len:
+    startBlock(p)
+    let it = caseStmt.sons[i]
+    for j in 0 .. it.len-2:
+      if it.sons[j].kind == nkRange:
+        localError(it.info, "range notation not available for computed goto")
+        return
+      let val = getOrdValue(it.sons[j])
+      lineF(p, cpsStmts, "TMP$#:$n", [intLiteral(val+id+1)])
+    genStmts(p, it.lastSon)
+    #for j in casePos+1 .. <n.len: genStmts(p, n.sons[j]) # tailB
+    #for j in 0 .. casePos-1: genStmts(p, n.sons[j])  # tailA
+    add(p.s(cpsStmts), tailB)
+    add(p.s(cpsStmts), tailA)
+
+    var a: TLoc
+    initLocExpr(p, caseStmt.sons[0], a)
+    lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
+    endBlock(p)
+
+proc genWhileStmt(p: BProc, t: PNode) =
+  # we don't generate labels here as for example GCC would produce
+  # significantly worse code
+  var
+    a: TLoc
+    labl: TLabel
+  assert(sonsLen(t) == 2)
+  inc(p.withinLoop)
+  genLineDir(p, t)
+
+  preserveBreakIdx:
+    p.breakIdx = startBlock(p, "while (1) {$n")
+    p.blocks[p.breakIdx].isLoop = true
+    initLocExpr(p, t.sons[0], a)
+    if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
+      let label = assignLabel(p.blocks[p.breakIdx])
+      lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
+    var loopBody = t.sons[1]
+    if loopBody.stmtsContainPragma(wComputedGoto) and
+        hasComputedGoto in CC[cCompiler].props:
+      # for closure support weird loop bodies are generated:
+      if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
+        loopBody = loopBody.sons[1]
+      genComputedGoto(p, loopBody)
+    else:
+      genStmts(p, loopBody)
+
+    if optProfiler in p.options:
+      # invoke at loop body exit:
+      linefmt(p, cpsStmts, "#nimProfile();$n")
+    endBlock(p)
+
+  dec(p.withinLoop)
+
+proc genBlock(p: BProc, t: PNode, d: var TLoc) =
+  preserveBreakIdx:
+    p.breakIdx = startBlock(p)
+    if t.sons[0].kind != nkEmpty:
+      # named block?
+      assert(t.sons[0].kind == nkSym)
+      var sym = t.sons[0].sym
+      sym.loc.k = locOther
+      sym.position = p.breakIdx+1
+    expr(p, t.sons[1], d)
+    endBlock(p)
+
+proc genParForStmt(p: BProc, t: PNode) =
+  assert(sonsLen(t) == 3)
+  inc(p.withinLoop)
+  genLineDir(p, t)
+
+  preserveBreakIdx:
+    let forLoopVar = t.sons[0].sym
+    var rangeA, rangeB: TLoc
+    assignLocalVar(p, forLoopVar)
+    #initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
+    #discard mangleName(forLoopVar)
+    let call = t.sons[1]
+    initLocExpr(p, call.sons[1], rangeA)
+    initLocExpr(p, call.sons[2], rangeB)
+
+    lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
+                        "for ($1 = $2; $1 <= $3; ++$1)",
+                        [forLoopVar.loc.rdLoc,
+                        rangeA.rdLoc, rangeB.rdLoc,
+                        call.sons[3].getStr.rope])
+
+    p.breakIdx = startBlock(p)
+    p.blocks[p.breakIdx].isLoop = true
+    genStmts(p, t.sons[2])
+    endBlock(p)
+
+  dec(p.withinLoop)
+
+proc genBreakStmt(p: BProc, t: PNode) =
+  var idx = p.breakIdx
+  if t.sons[0].kind != nkEmpty:
+    # named break?
+    assert(t.sons[0].kind == nkSym)
+    var sym = t.sons[0].sym
+    assert(sym.loc.k == locOther)
+    idx = sym.position-1
+  else:
+    # an unnamed 'break' can only break a loop after 'transf' pass:
+    while idx >= 0 and not p.blocks[idx].isLoop: dec idx
+    if idx < 0 or not p.blocks[idx].isLoop:
+      internalError(t.info, "no loop to break")
+  let label = assignLabel(p.blocks[idx])
+  blockLeaveActions(p,
+    p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
+    p.inExceptBlock - p.blocks[idx].nestedExceptStmts)
+  genLineDir(p, t)
+  lineF(p, cpsStmts, "goto $1;$n", [label])
+
+proc getRaiseFrmt(p: BProc): string =
+  result = "#raiseException((#Exception*)$1, $2);$n"
+
+proc genRaiseStmt(p: BProc, t: PNode) =
+  if p.inExceptBlock > 0:
+    # if the current try stmt have a finally block,
+    # we must execute it before reraising
+    var finallyBlock = p.nestedTryStmts[p.nestedTryStmts.len - 1].lastSon
+    if finallyBlock.kind == nkFinally:
+      genSimpleBlock(p, finallyBlock.sons[0])
+  if t.sons[0].kind != nkEmpty:
+    var a: TLoc
+    initLocExpr(p, t.sons[0], a)
+    var e = rdLoc(a)
+    var typ = skipTypes(t.sons[0].typ, abstractPtrs)
+    genLineDir(p, t)
+    lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
+  else:
+    genLineDir(p, t)
+    # reraise the last exception:
+    if p.module.compileToCpp:
+      line(p, cpsStmts, ~"throw;$n")
+    else:
+      linefmt(p, cpsStmts, "#reraiseException();$n")
+
+proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
+                          rangeFormat, eqFormat: FormatStr, labl: TLabel) =
+  var
+    x, y: TLoc
+  var length = sonsLen(b)
+  for i in countup(0, length - 2):
+    if b.sons[i].kind == nkRange:
+      initLocExpr(p, b.sons[i].sons[0], x)
+      initLocExpr(p, b.sons[i].sons[1], y)
+      lineCg(p, cpsStmts, rangeFormat,
+           [rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
+    else:
+      initLocExpr(p, b.sons[i], x)
+      lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
+
+proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
+                       labId, until: int): TLabel =
+  var lend = getLabel(p)
+  for i in 1..until:
+    lineF(p, cpsStmts, "LA$1: ;$n", [rope(labId + i)])
+    if t.sons[i].kind == nkOfBranch:
+      var length = sonsLen(t.sons[i])
+      exprBlock(p, t.sons[i].sons[length - 1], d)
+      lineF(p, cpsStmts, "goto $1;$n", [lend])
+    else:
+      exprBlock(p, t.sons[i].sons[0], d)
+  result = lend
+
+proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
+                       rangeFormat, eqFormat: FormatStr,
+                       until: int, a: TLoc): TLabel =
+  # generate a C-if statement for a Nim case statement
+  var labId = p.labels
+  for i in 1..until:
+    inc(p.labels)
+    if t.sons[i].kind == nkOfBranch: # else statement
+      genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat,
+                           "LA" & rope(p.labels))
+    else:
+      lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
+  if until < t.len-1:
+    inc(p.labels)
+    var gotoTarget = p.labels
+    lineF(p, cpsStmts, "goto LA$1;$n", [rope(gotoTarget)])
+    result = genCaseSecondPass(p, t, d, labId, until)
+    lineF(p, cpsStmts, "LA$1: ;$n", [rope(gotoTarget)])
+  else:
+    result = genCaseSecondPass(p, t, d, labId, until)
+
+proc genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
+                    rangeFormat, eqFormat: FormatStr) =
+  var a: TLoc
+  initLocExpr(p, t.sons[0], a)
+  var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, sonsLen(t)-1, a)
+  fixLabel(p, lend)
+
+proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
+                         branches: var openArray[Rope]) =
+  var x: TLoc
+  var length = sonsLen(b)
+  for i in countup(0, length - 2):
+    assert(b.sons[i].kind != nkRange)
+    initLocExpr(p, b.sons[i], x)
+    assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
+    var j = int(hashString(b.sons[i].strVal) and high(branches))
+    appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
+         [rdLoc(e), rdLoc(x), labl])
+
+proc genStringCase(p: BProc, t: PNode, d: var TLoc) =
+  # count how many constant strings there are in the case:
+  var strings = 0
+  for i in countup(1, sonsLen(t) - 1):
+    if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
+  if strings > stringCaseThreshold:
+    var bitMask = math.nextPowerOfTwo(strings) - 1
+    var branches: seq[Rope]
+    newSeq(branches, bitMask + 1)
+    var a: TLoc
+    initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
+    var labId = p.labels
+    for i in countup(1, sonsLen(t) - 1):
+      inc(p.labels)
+      if t.sons[i].kind == nkOfBranch:
+        genCaseStringBranch(p, t.sons[i], a, "LA" & rope(p.labels),
+                            branches)
+      else:
+        # else statement: nothing to do yet
+        # but we reserved a label, which we use later
+        discard
+    linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
+            rdLoc(a), rope(bitMask))
+    for j in countup(0, high(branches)):
+      if branches[j] != nil:
+        lineF(p, cpsStmts, "case $1: $n$2break;$n",
+             [intLiteral(j), branches[j]])
+    lineF(p, cpsStmts, "}$n", []) # else statement:
+    if t.sons[sonsLen(t)-1].kind != nkOfBranch:
+      lineF(p, cpsStmts, "goto LA$1;$n", [rope(p.labels)])
+    # third pass: generate statements
+    var lend = genCaseSecondPass(p, t, d, labId, sonsLen(t)-1)
+    fixLabel(p, lend)
+  else:
+    genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
+
+proc branchHasTooBigRange(b: PNode): bool =
+  for i in countup(0, sonsLen(b)-2):
+    # last son is block
+    if (b.sons[i].kind == nkRange) and
+        b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit:
+      return true
+
+proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
+  for i in 1..n.len-1:
+    var branch = n[i]
+    var stmtBlock = lastSon(branch)
+    if stmtBlock.stmtsContainPragma(wLinearScanEnd):
+      result = i
+    elif hasSwitchRange notin CC[cCompiler].props:
+      if branch.kind == nkOfBranch and branchHasTooBigRange(branch):
+        result = i
+
+proc genCaseRange(p: BProc, branch: PNode) =
+  var length = branch.len
+  for j in 0 .. length-2:
+    if branch[j].kind == nkRange:
+      if hasSwitchRange in CC[cCompiler].props:
+        lineF(p, cpsStmts, "case $1 ... $2:$n", [
+            genLiteral(p, branch[j][0]),
+            genLiteral(p, branch[j][1])])
+      else:
+        var v = copyNode(branch[j][0])
+        while v.intVal <= branch[j][1].intVal:
+          lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, v)])
+          inc(v.intVal)
+    else:
+      lineF(p, cpsStmts, "case $1:$n", [genLiteral(p, branch[j])])
+
+proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
+  # analyse 'case' statement:
+  var splitPoint = ifSwitchSplitPoint(p, n)
+
+  # generate if part (might be empty):
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
+                    rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
+                    eqFormat = "if ($1 == $2) goto $3;$n",
+                    splitPoint, a) else: nil
+
+  # generate switch part (might be empty):
+  if splitPoint+1 < n.len:
+    lineF(p, cpsStmts, "switch ($1) {$n", [rdCharLoc(a)])
+    var hasDefault = false
+    for i in splitPoint+1 .. < n.len:
+      var branch = n[i]
+      if branch.kind == nkOfBranch:
+        genCaseRange(p, branch)
+      else:
+        # else part of case statement:
+        lineF(p, cpsStmts, "default:$n", [])
+        hasDefault = true
+      exprBlock(p, branch.lastSon, d)
+      lineF(p, cpsStmts, "break;$n", [])
+    if (hasAssume in CC[cCompiler].props) and not hasDefault:
+      lineF(p, cpsStmts, "default: __assume(0);$n", [])
+    lineF(p, cpsStmts, "}$n", [])
+  if lend != nil: fixLabel(p, lend)
+
+proc genCase(p: BProc, t: PNode, d: var TLoc) =
+  genLineDir(p, t)
+  if not isEmptyType(t.typ) and d.k == locNone:
+    getTemp(p, t.typ, d)
+  case skipTypes(t.sons[0].typ, abstractVarRange).kind
+  of tyString:
+    genStringCase(p, t, d)
+  of tyFloat..tyFloat128:
+    genCaseGeneric(p, t, d, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
+                            "if ($1 == $2) goto $3;$n")
+  else:
+    if t.sons[0].kind == nkSym and sfGoto in t.sons[0].sym.flags:
+      genGotoForCase(p, t)
+    else:
+      genOrdinalCase(p, t, d)
+
+proc hasGeneralExceptSection(t: PNode): bool =
+  var length = sonsLen(t)
+  var i = 1
+  while (i < length) and (t.sons[i].kind == nkExceptBranch):
+    var blen = sonsLen(t.sons[i])
+    if blen == 1:
+      return true
+    inc(i)
+  result = false
+
+proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
+  # code to generate:
+  #
+  # XXX: There should be a standard dispatch algorithm
+  # that's used both here and with multi-methods
+  #
+  #   try
+  #   {
+  #      myDiv(4, 9);
+  #   } catch (NimException& exp) {
+  #      if (isObj(exp, EIO) {
+  #        ...
+  #      } else if (isObj(exp, ESystem) {
+  #        ...
+  #        finallyPart()
+  #        raise;
+  #      } else {
+  #        // general handler
+  #      }
+  #  }
+  #  finallyPart();
+  if not isEmptyType(t.typ) and d.k == locNone:
+    getTemp(p, t.typ, d)
+  genLineDir(p, t)
+  let exc = getTempName()
+  if getCompilerProc("Exception") != nil:
+    discard cgsym(p.module, "Exception")
+  else:
+    discard cgsym(p.module, "E_Base")
+  add(p.nestedTryStmts, t)
+  startBlock(p, "try {$n")
+  expr(p, t.sons[0], d)
+  let length = sonsLen(t)
+  endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc]))
+  if optStackTrace in p.options:
+    linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
+  inc p.inExceptBlock
+  var i = 1
+  var catchAllPresent = false
+  while (i < length) and (t.sons[i].kind == nkExceptBranch):
+    let blen = sonsLen(t.sons[i])
+    if i > 1: addf(p.s(cpsStmts), "else ", [])
+    if blen == 1:
+      # general except section:
+      catchAllPresent = true
+      startBlock(p)
+      expr(p, t.sons[i].sons[0], d)
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+      endBlock(p)
+    else:
+      var orExpr: Rope = nil
+      for j in countup(0, blen - 2):
+        assert(t.sons[i].sons[j].kind == nkType)
+        if orExpr != nil: add(orExpr, "||")
+        appcg(p.module, orExpr,
+              "#isObj($1.exp->m_type, $2)",
+              [exc, genTypeInfo(p.module, t.sons[i].sons[j].typ)])
+      lineF(p, cpsStmts, "if ($1) ", [orExpr])
+      startBlock(p)
+      expr(p, t.sons[i].sons[blen-1], d)
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+      endBlock(p)
+    inc(i)
+
+  # reraise the exception if there was no catch all
+  # and none of the handlers matched
+  if not catchAllPresent:
+    if i > 1: lineF(p, cpsStmts, "else ", [])
+    startBlock(p)
+    var finallyBlock = t.lastSon
+    if finallyBlock.kind == nkFinally:
+      #expr(p, finallyBlock.sons[0], d)
+      genStmts(p, finallyBlock.sons[0])
+
+    line(p, cpsStmts, ~"throw;$n")
+    endBlock(p)
+
+  lineF(p, cpsStmts, "}$n", []) # end of catch block
+  dec p.inExceptBlock
+
+  discard pop(p.nestedTryStmts)
+  if (i < length) and (t.sons[i].kind == nkFinally):
+    genSimpleBlock(p, t.sons[i].sons[0])
+
+proc genTry(p: BProc, t: PNode, d: var TLoc) =
+  # code to generate:
+  #
+  # XXX: There should be a standard dispatch algorithm
+  # that's used both here and with multi-methods
+  #
+  #  TSafePoint sp;
+  #  pushSafePoint(&sp);
+  #  sp.status = setjmp(sp.context);
+  #  if (sp.status == 0) {
+  #    myDiv(4, 9);
+  #    popSafePoint();
+  #  } else {
+  #    popSafePoint();
+  #    /* except DivisionByZero: */
+  #    if (sp.status == DivisionByZero) {
+  #      printf('Division by Zero\n');
+  #      clearException();
+  #    } else {
+  #      clearException();
+  #    }
+  #  }
+  #  {
+  #    /* finally: */
+  #    printf('fin!\n');
+  #  }
+  #  if (exception not cleared)
+  #    propagateCurrentException();
+  #
+  if not isEmptyType(t.typ) and d.k == locNone:
+    getTemp(p, t.typ, d)
+  discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
+  genLineDir(p, t)
+  var safePoint = getTempName()
+  if getCompilerProc("Exception") != nil:
+    discard cgsym(p.module, "Exception")
+  else:
+    discard cgsym(p.module, "E_Base")
+  linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
+  linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
+  if isDefined("nimStdSetjmp"):
+    linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
+  elif isDefined("nimSigSetjmp"):
+    linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
+  elif isDefined("nimRawSetjmp"):
+    linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
+  else:
+    linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
+  startBlock(p, "if ($1.status == 0) {$n", [safePoint])
+  var length = sonsLen(t)
+  add(p.nestedTryStmts, t)
+  expr(p, t.sons[0], d)
+  linefmt(p, cpsStmts, "#popSafePoint();$n")
+  endBlock(p)
+  startBlock(p, "else {$n")
+  linefmt(p, cpsStmts, "#popSafePoint();$n")
+  if optStackTrace in p.options:
+    linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR);$n")
+  inc p.inExceptBlock
+  var i = 1
+  while (i < length) and (t.sons[i].kind == nkExceptBranch):
+    var blen = sonsLen(t.sons[i])
+    if blen == 1:
+      # general except section:
+      if i > 1: lineF(p, cpsStmts, "else", [])
+      startBlock(p)
+      linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
+      expr(p, t.sons[i].sons[0], d)
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+      endBlock(p)
+    else:
+      var orExpr: Rope = nil
+      for j in countup(0, blen - 2):
+        assert(t.sons[i].sons[j].kind == nkType)
+        if orExpr != nil: add(orExpr, "||")
+        appcg(p.module, orExpr,
+              "#isObj(#getCurrentException()->Sup.m_type, $1)",
+              [genTypeInfo(p.module, t.sons[i].sons[j].typ)])
+      if i > 1: line(p, cpsStmts, "else ")
+      startBlock(p, "if ($1) {$n", [orExpr])
+      linefmt(p, cpsStmts, "$1.status = 0;$n", safePoint)
+      expr(p, t.sons[i].sons[blen-1], d)
+      linefmt(p, cpsStmts, "#popCurrentException();$n")
+      endBlock(p)
+    inc(i)
+  dec p.inExceptBlock
+  discard pop(p.nestedTryStmts)
+  endBlock(p) # end of else block
+  if i < length and t.sons[i].kind == nkFinally:
+    p.finallySafePoints.add(safePoint)
+    genSimpleBlock(p, t.sons[i].sons[0])
+    discard pop(p.finallySafePoints)
+  linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
+
+proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
+  var res = ""
+  for i in countup(0, sonsLen(t) - 1):
+    case t.sons[i].kind
+    of nkStrLit..nkTripleStrLit:
+      res.add(t.sons[i].strVal)
+    of nkSym:
+      var sym = t.sons[i].sym
+      if sym.kind in {skProc, skIterator, skClosureIterator, skMethod}:
+        var a: TLoc
+        initLocExpr(p, t.sons[i], a)
+        res.add($rdLoc(a))
+      else:
+        var r = sym.loc.r
+        if r == nil:
+          # if no name has already been given,
+          # it doesn't matter much:
+          r = mangleName(sym)
+          sym.loc.r = r       # but be consequent!
+        res.add($r)
+    else: internalError(t.sons[i].info, "genAsmOrEmitStmt()")
+
+  if isAsmStmt and hasGnuAsm in CC[cCompiler].props:
+    for x in splitLines(res):
+      var j = 0
+      while x[j] in {' ', '\t'}: inc(j)
+      if x[j] in {'"', ':'}:
+        # don't modify the line if already in quotes or
+        # some clobber register list:
+        add(result, x); add(result, tnl)
+      elif x[j] != '\0':
+        # ignore empty lines
+        add(result, "\"")
+        add(result, x)
+        add(result, "\\n\"\n")
+  else:
+    res.add(tnl)
+    result = res.rope
+
+proc genAsmStmt(p: BProc, t: PNode) =
+  assert(t.kind == nkAsmStmt)
+  genLineDir(p, t)
+  var s = genAsmOrEmitStmt(p, t, isAsmStmt=true)
+  # see bug #2362, "top level asm statements" seem to be a mis-feature
+  # but even if we don't do this, the example in #2362 cannot possibly
+  # work:
+  if p.prc == nil:
+    # top level asm statement?
+    addf(p.module.s[cfsProcHeaders], CC[cCompiler].asmStmtFrmt, [s])
+  else:
+    lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
+
+proc determineSection(n: PNode): TCFileSection =
+  result = cfsProcHeaders
+  if n.len >= 1 and n.sons[0].kind in {nkStrLit..nkTripleStrLit}:
+    if n.sons[0].strVal.startsWith("/*TYPESECTION*/"): result = cfsTypes
+    elif n.sons[0].strVal.startsWith("/*VARSECTION*/"): result = cfsVars
+
+proc genEmit(p: BProc, t: PNode) =
+  var s = genAsmOrEmitStmt(p, t.sons[1])
+  if p.prc == nil:
+    # top level emit pragma?
+    let section = determineSection(t[1])
+    genCLineDir(p.module.s[section], t.info)
+    add(p.module.s[section], s)
+  else:
+    genLineDir(p, t)
+    line(p, cpsStmts, s)
+
+var
+  breakPointId: int = 0
+  gBreakpoints: Rope # later the breakpoints are inserted into the main proc
+
+proc genBreakPoint(p: BProc, t: PNode) =
+  var name: string
+  if optEndb in p.options:
+    if t.kind == nkExprColonExpr:
+      assert(t.sons[1].kind in {nkStrLit..nkTripleStrLit})
+      name = normalize(t.sons[1].strVal)
+    else:
+      inc(breakPointId)
+      name = "bp" & $breakPointId
+    genLineDir(p, t)          # BUGFIX
+    appcg(p.module, gBreakpoints,
+         "#dbgRegisterBreakpoint($1, (NCSTRING)$2, (NCSTRING)$3);$n", [
+        rope(toLinenumber(t.info)), makeCString(toFilename(t.info)),
+        makeCString(name)])
+
+proc genWatchpoint(p: BProc, n: PNode) =
+  if optEndb notin p.options: return
+  var a: TLoc
+  initLocExpr(p, n.sons[1], a)
+  let typ = skipTypes(n.sons[1].typ, abstractVarRange)
+  lineCg(p, cpsStmts, "#dbgRegisterWatchpoint($1, (NCSTRING)$2, $3);$n",
+        [a.addrLoc, makeCString(renderTree(n.sons[1])),
+        genTypeInfo(p.module, typ)])
+
+proc genPragma(p: BProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    case whichPragma(it)
+    of wEmit: genEmit(p, it)
+    of wBreakpoint: genBreakPoint(p, it)
+    of wWatchPoint: genWatchpoint(p, it)
+    of wInjectStmt:
+      var p = newProc(nil, p.module)
+      p.options = p.options - {optLineTrace, optStackTrace}
+      genStmts(p, it.sons[1])
+      p.module.injectStmt = p.s(cpsStmts)
+    else: discard
+
+proc fieldDiscriminantCheckNeeded(p: BProc, asgn: PNode): bool =
+  if optFieldCheck in p.options:
+    var le = asgn.sons[0]
+    if le.kind == nkCheckedFieldExpr:
+      var field = le.sons[0].sons[1].sym
+      result = sfDiscriminant in field.flags
+    elif le.kind == nkDotExpr:
+      var field = le.sons[1].sym
+      result = sfDiscriminant in field.flags
+
+proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
+                          field: PSym) =
+  var t = skipTypes(objtype, abstractVar)
+  assert t.kind == tyObject
+  discard genTypeInfo(p.module, t)
+  var L = lengthOrd(field.typ)
+  if not containsOrIncl(p.module.declaredThings, field.id):
+    appcg(p.module, cfsVars, "extern $1",
+          discriminatorTableDecl(p.module, t, field))
+  lineCg(p, cpsStmts,
+        "#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
+        [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
+         intLiteral(L+1)])
+
+proc asgnFieldDiscriminant(p: BProc, e: PNode) =
+  var a, tmp: TLoc
+  var dotExpr = e.sons[0]
+  var d: PSym
+  if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.sons[0]
+  initLocExpr(p, e.sons[0], a)
+  getTemp(p, a.t, tmp)
+  expr(p, e.sons[1], tmp)
+  genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym)
+  genAssignment(p, a, tmp, {})
+
+proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
+  genLineDir(p, e)
+  if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags:
+    genGotoVar(p, e.sons[1])
+  elif not fieldDiscriminantCheckNeeded(p, e):
+    var a: TLoc
+    initLocExpr(p, e.sons[0], a)
+    if fastAsgn: incl(a.flags, lfNoDeepCopy)
+    assert(a.t != nil)
+    loadInto(p, e.sons[0], e.sons[1], a)
+  else:
+    asgnFieldDiscriminant(p, e)
+
+proc genStmts(p: BProc, t: PNode) =
+  var a: TLoc
+  expr(p, t, a)
+  internalAssert a.k in {locNone, locTemp, locLocalVar}
diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim
new file mode 100644
index 000000000..d741c47a9
--- /dev/null
+++ b/compiler/ccgthreadvars.nim
@@ -0,0 +1,65 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Thread var support for crappy architectures that lack native support for
+## thread local storage. (**Thank you Mac OS X!**)
+
+# included from cgen.nim
+
+proc emulatedThreadVars(): bool =
+  result = {optThreads, optTlsEmulation} <= gGlobalOptions
+
+proc accessThreadLocalVar(p: BProc, s: PSym) =
+  if emulatedThreadVars() and not p.threadVarAccessed:
+    p.threadVarAccessed = true
+    p.module.usesThreadVars = true
+    addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV;$n", [])
+    add(p.procSec(cpsInit),
+      ropecg(p.module, "\tNimTV = (NimThreadVars*) #GetThreadLocalVars();$n"))
+
+var
+  nimtv: Rope                 # nimrod thread vars; the struct body
+  nimtvDeps: seq[PType] = @[]  # type deps: every module needs whole struct
+  nimtvDeclared = initIntSet() # so that every var/field exists only once
+                               # in the struct
+
+# 'nimtv' is incredibly hard to modularize! Best effort is to store all thread
+# vars in a ROD section and with their type deps and load them
+# unconditionally...
+
+# nimtvDeps is VERY hard to cache because it's not a list of IDs nor can it be
+# made to be one.
+
+proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
+  if emulatedThreadVars():
+    # we gather all thread locals var into a struct; we need to allocate
+    # storage for that somehow, can't use the thread local storage
+    # allocator for it :-(
+    if not containsOrIncl(nimtvDeclared, s.id):
+      nimtvDeps.add(s.loc.t)
+      addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
+  else:
+    if isExtern: add(m.s[cfsVars], "extern ")
+    if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
+    add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
+    addf(m.s[cfsVars], " $1;$n", [s.loc.r])
+
+proc generateThreadLocalStorage(m: BModule) =
+  if nimtv != nil and (m.usesThreadVars or sfMainModule in m.module.flags):
+    for t in items(nimtvDeps): discard getTypeDesc(m, t)
+    addf(m.s[cfsSeqTypes], "typedef struct {$1} NimThreadVars;$n", [nimtv])
+
+proc generateThreadVarsSize(m: BModule) =
+  if nimtv != nil:
+    let externc = if gCmd != cmdCompileToCpp and
+                       sfCompileToCpp in m.module.flags: "extern \"C\""
+                  else: ""
+    addf(m.s[cfsProcs],
+      "$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
+      [externc.rope])
diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim
new file mode 100644
index 000000000..5f59702e5
--- /dev/null
+++ b/compiler/ccgtrav.nim
@@ -0,0 +1,151 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Generates traversal procs for the C backend. Traversal procs are only an
+## optimization; the GC works without them too.
+
+# included from cgen.nim
+
+type
+  TTraversalClosure = object
+    p: BProc
+    visitorFrmt: string
+
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType)
+proc genCaseRange(p: BProc, branch: PNode)
+proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false)
+
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, n: PNode) =
+  if n == nil: return
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      genTraverseProc(c, accessor, n.sons[i])
+  of nkRecCase:
+    if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
+    var p = c.p
+    let disc = n.sons[0].sym
+    lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
+    for i in countup(1, sonsLen(n) - 1):
+      let branch = n.sons[i]
+      assert branch.kind in {nkOfBranch, nkElse}
+      if branch.kind == nkOfBranch:
+        genCaseRange(c.p, branch)
+      else:
+        lineF(p, cpsStmts, "default:$n", [])
+      genTraverseProc(c, accessor, lastSon(branch))
+      lineF(p, cpsStmts, "break;$n", [])
+    lineF(p, cpsStmts, "} $n", [])
+  of nkSym:
+    let field = n.sym
+    if field.loc.t == nil:
+      internalError(n.info, "genTraverseProc()")
+    genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
+  else: internalError(n.info, "genTraverseProc()")
+
+proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
+  if not m.compileToCpp:
+    result = "$1.Sup" % [accessor]
+  else:
+    result = accessor
+
+proc genTraverseProc(c: var TTraversalClosure, accessor: Rope, typ: PType) =
+  if typ == nil: return
+  var p = c.p
+  case typ.kind
+  of tyGenericInst, tyGenericBody, tyTypeDesc:
+    genTraverseProc(c, accessor, lastSon(typ))
+  of tyArrayConstr, tyArray:
+    let arraySize = lengthOrd(typ.sons[0])
+    var i: TLoc
+    getTemp(p, getSysType(tyInt), i)
+    linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
+            i.r, arraySize.rope)
+    genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
+    lineF(p, cpsStmts, "}$n", [])
+  of tyObject:
+    for i in countup(0, sonsLen(typ) - 1):
+      genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
+    if typ.n != nil: genTraverseProc(c, accessor, typ.n)
+  of tyTuple:
+    let typ = getUniqueType(typ)
+    for i in countup(0, sonsLen(typ) - 1):
+      genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
+  of tyRef, tyString, tySequence:
+    lineCg(p, cpsStmts, c.visitorFrmt, accessor)
+  of tyProc:
+    if typ.callConv == ccClosure:
+      lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClEnv", accessor))
+  else:
+    discard
+
+proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
+  var p = c.p
+  assert typ.kind == tySequence
+  var i: TLoc
+  getTemp(p, getSysType(tyInt), i)
+  lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
+      [i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
+  genTraverseProc(c, "$1->data[$2]" % [accessor, i.r], typ.sons[0])
+  lineF(p, cpsStmts, "}$n", [])
+
+proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
+  var c: TTraversalClosure
+  var p = newProc(nil, m)
+  result = getGlobalTempName()
+
+  case reason
+  of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
+  else: assert false
+
+  let header = "N_NIMCALL(void, $1)(void* p, NI op)" % [result]
+
+  let t = getTypeDesc(m, typ)
+  lineF(p, cpsLocals, "$1 a;$n", [t])
+  lineF(p, cpsInit, "a = ($1)p;$n", [t])
+
+  c.p = p
+  assert typ.kind != tyTypeDesc
+  if typ.kind == tySequence:
+    genTraverseProcSeq(c, "a".rope, typ)
+  else:
+    if skipTypes(typ.sons[0], typedescInst).kind in {tyArrayConstr, tyArray}:
+      # C's arrays are broken beyond repair:
+      genTraverseProc(c, "a".rope, typ.sons[0])
+    else:
+      genTraverseProc(c, "(*a)".rope, typ.sons[0])
+
+  let generatedProc = "$1 {$n$2$3$4}$n" %
+        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
+
+  m.s[cfsProcHeaders].addf("$1;$n", [header])
+  m.s[cfsProcs].add(generatedProc)
+
+proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
+  discard genTypeInfo(m, s.loc.t)
+
+  var c: TTraversalClosure
+  var p = newProc(nil, m)
+  var sLoc = s.loc.r
+  result = getGlobalTempName()
+
+  if sfThread in s.flags and emulatedThreadVars():
+    accessThreadLocalVar(p, s)
+    sLoc = "NimTV->" & sLoc
+
+  c.visitorFrmt = "#nimGCvisit((void*)$1, 0);$n"
+  c.p = p
+  let header = "N_NIMCALL(void, $1)()" % [result]
+  genTraverseProc(c, sLoc, s.loc.t)
+
+  let generatedProc = "$1 {$n$2$3$4}$n" %
+        [header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)]
+
+  m.s[cfsProcHeaders].addf("$1;$n", [header])
+  m.s[cfsProcs].add(generatedProc)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
new file mode 100644
index 000000000..3742fd2fd
--- /dev/null
+++ b/compiler/ccgtypes.nim
@@ -0,0 +1,1034 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# included from cgen.nim
+
+# ------------------------- Name Mangling --------------------------------
+
+proc isKeyword(w: PIdent): bool =
+  # Nim and C++ share some keywords
+  # it's more efficient to test the whole Nim keywords range
+  case w.id
+  of ccgKeywordsLow..ccgKeywordsHigh,
+     nimKeywordsLow..nimKeywordsHigh,
+     ord(wInline): return true
+  else: return false
+
+proc mangleField(name: PIdent): string =
+  result = mangle(name.s)
+  if isKeyword(name):
+    result[0] = result[0].toUpper # Mangling makes everything lowercase,
+                                  # but some identifiers are C keywords
+
+proc mangleName(s: PSym): Rope =
+  result = s.loc.r
+  if result == nil:
+    when oKeepVariableNames:
+      let keepOrigName = s.kind in skLocalVars - {skForVar} and
+        {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
+        not isKeyword(s.name)
+      # XXX: This is still very experimental
+      #
+      # Even with all these inefficient checks, the bootstrap
+      # time is actually improved. This is probably because so many
+      # rope concatenations are now eliminated.
+      #
+      # Future notes:
+      # sfFromGeneric seems to be needed in order to avoid multiple
+      # definitions of certain variables generated in transf with
+      # names such as:
+      # `r`, `res`
+      # I need to study where these come from.
+      #
+      # about sfShadowed:
+      # consider the following nimrod code:
+      #   var x = 10
+      #   block:
+      #     var x = something(x)
+      # The generated C code will be:
+      #   NI x;
+      #   x = 10;
+      #   {
+      #     NI x;
+      #     x = something(x); // Oops, x is already shadowed here
+      #   }
+      # Right now, we work-around by not keeping the original name
+      # of the shadowed variable, but we can do better - we can
+      # create an alternative reference to it in the outer scope and
+      # use that in the inner scope.
+      #
+      # about isCKeyword:
+      # nimrod variable names can be C keywords.
+      # We need to avoid such names in the generated code.
+      # XXX: Study whether mangleName is called just once per variable.
+      # Otherwise, there might be better place to do this.
+      #
+      # about sfGlobal:
+      # This seems to be harder - a top level extern variable from
+      # another modules can have the same name as a local one.
+      # Maybe we should just implement sfShadowed for them too.
+      #
+      # about skForVar:
+      # These are not properly scoped now - we need to add blocks
+      # around for loops in transf
+      if keepOrigName:
+        result = s.name.s.mangle.rope
+      else:
+        add(result, rope(mangle(s.name.s)))
+        add(result, ~"_")
+        add(result, rope(s.id))
+    else:
+      add(result, rope(mangle(s.name.s)))
+      add(result, ~"_")
+      add(result, rope(s.id))
+    s.loc.r = result
+
+proc typeName(typ: PType): Rope =
+  result = if typ.sym != nil: typ.sym.name.s.mangle.rope
+           else: ~"TY"
+
+proc getTypeName(typ: PType): Rope =
+  if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
+    result = typ.sym.loc.r
+  else:
+    if typ.loc.r == nil:
+      typ.loc.r = typ.typeName & typ.id.rope
+    result = typ.loc.r
+  if result == nil: internalError("getTypeName: " & $typ.kind)
+
+proc mapSetType(typ: PType): TCTypeKind =
+  case int(getSize(typ))
+  of 1: result = ctInt8
+  of 2: result = ctInt16
+  of 4: result = ctInt32
+  of 8: result = ctInt64
+  else: result = ctArray
+
+proc mapType(typ: PType): TCTypeKind =
+  ## Maps a Nim type to a C type
+  case typ.kind
+  of tyNone, tyStmt: result = ctVoid
+  of tyBool: result = ctBool
+  of tyChar: result = ctChar
+  of tySet: result = mapSetType(typ)
+  of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctArray
+  of tyObject, tyTuple: result = ctStruct
+  of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
+     tyConst, tyMutable, tyIter, tyTypeDesc:
+    result = mapType(lastSon(typ))
+  of tyEnum:
+    if firstOrd(typ) < 0:
+      result = ctInt32
+    else:
+      case int(getSize(typ))
+      of 1: result = ctUInt8
+      of 2: result = ctUInt16
+      of 4: result = ctInt32
+      of 8: result = ctInt64
+      else: internalError("mapType")
+  of tyRange: result = mapType(typ.sons[0])
+  of tyPtr, tyVar, tyRef:
+    var base = skipTypes(typ.lastSon, typedescInst)
+    case base.kind
+    of tyOpenArray, tyArrayConstr, tyArray, tyVarargs: result = ctPtrToArray
+    else: result = ctPtr
+  of tyPointer: result = ctPtr
+  of tySequence: result = ctNimSeq
+  of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
+  of tyString: result = ctNimStr
+  of tyCString: result = ctCString
+  of tyInt..tyUInt64:
+    result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
+  else: internalError("mapType")
+
+proc mapReturnType(typ: PType): TCTypeKind =
+  if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
+  else: result = mapType(typ)
+
+proc isImportedType(t: PType): bool =
+  result = t.sym != nil and sfImportc in t.sym.flags
+
+proc isImportedCppType(t: PType): bool =
+  result = t.sym != nil and sfInfixCall in t.sym.flags
+
+proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope
+proc needsComplexAssignment(typ: PType): bool =
+  result = containsGarbageCollectedRef(typ)
+
+proc isObjLackingTypeField(typ: PType): bool {.inline.} =
+  result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
+      (typ.sons[0] == nil) or isPureObject(typ))
+
+proc isInvalidReturnType(rettype: PType): bool =
+  # Arrays and sets cannot be returned by a C procedure, because C is
+  # such a poor programming language.
+  # We exclude records with refs too. This enhances efficiency and
+  # is necessary for proper code generation of assignments.
+  if rettype == nil: result = true
+  else:
+    case mapType(rettype)
+    of ctArray:
+      result = not (skipTypes(rettype, typedescInst).kind in
+          {tyVar, tyRef, tyPtr})
+    of ctStruct:
+      let t = skipTypes(rettype, typedescInst)
+      if rettype.isImportedCppType or t.isImportedCppType: return false
+      result = needsComplexAssignment(t) or
+          (t.kind == tyObject and not isObjLackingTypeField(t))
+    else: result = false
+
+const
+  CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
+    "N_STDCALL", "N_CDECL", "N_SAFECALL",
+    "N_SYSCALL", # this is probably not correct for all platforms,
+                 # but one can #define it to what one wants
+    "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
+
+proc cacheGetType(tab: TIdTable, key: PType): Rope =
+  # returns nil if we need to declare this type
+  # since types are now unique via the ``getUniqueType`` mechanism, this slow
+  # linear search is not necessary anymore:
+  result = Rope(idTableGet(tab, key))
+
+proc getTempName(): Rope =
+  result = rfmt(nil, "TMP$1", rope(backendId()))
+
+proc getGlobalTempName(): Rope =
+  result = rfmt(nil, "TMP$1", rope(backendId()))
+
+proc ccgIntroducedPtr(s: PSym): bool =
+  var pt = skipTypes(s.typ, typedescInst)
+  assert skResult != s.kind
+  if tfByRef in pt.flags: return true
+  elif tfByCopy in pt.flags: return false
+  case pt.kind
+  of tyObject:
+    if (optByRef in s.options) or (getSize(pt) > platform.floatSize * 2):
+      result = true           # requested anyway
+    elif (tfFinal in pt.flags) and (pt.sons[0] == nil):
+      result = false          # no need, because no subtyping possible
+    else:
+      result = true           # ordinary objects are always passed by reference,
+                              # otherwise casting doesn't work
+  of tyTuple:
+    result = (getSize(pt) > platform.floatSize*2) or (optByRef in s.options)
+  else: result = false
+
+proc fillResult(param: PSym) =
+  fillLoc(param.loc, locParam, param.typ, ~"Result",
+          OnStack)
+  if (mapReturnType(param.typ) != ctArray) and isInvalidReturnType(param.typ):
+    incl(param.loc.flags, lfIndirect)
+    param.loc.s = OnUnknown
+
+proc typeNameOrLiteral(t: PType, literal: string): Rope =
+  if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
+    result = getTypeName(t)
+  else:
+    result = rope(literal)
+
+proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
+  const
+    NumericalTypeToStr: array[tyInt..tyUInt64, string] = [
+      "NI", "NI8", "NI16", "NI32", "NI64",
+      "NF", "NF32", "NF64", "NF128",
+      "NU", "NU8", "NU16", "NU32", "NU64",]
+  case typ.kind
+  of tyPointer:
+    result = typeNameOrLiteral(typ, "void*")
+  of tyEnum:
+    if firstOrd(typ) < 0:
+      result = typeNameOrLiteral(typ, "NI32")
+    else:
+      case int(getSize(typ))
+      of 1: result = typeNameOrLiteral(typ, "NU8")
+      of 2: result = typeNameOrLiteral(typ, "NU16")
+      of 4: result = typeNameOrLiteral(typ, "NI32")
+      of 8: result = typeNameOrLiteral(typ, "NI64")
+      else:
+        internalError(typ.sym.info, "getSimpleTypeDesc: " & $(getSize(typ)))
+        result = nil
+  of tyString:
+    discard cgsym(m, "NimStringDesc")
+    result = typeNameOrLiteral(typ, "NimStringDesc*")
+  of tyCString: result = typeNameOrLiteral(typ, "NCSTRING")
+  of tyBool: result = typeNameOrLiteral(typ, "NIM_BOOL")
+  of tyChar: result = typeNameOrLiteral(typ, "NIM_CHAR")
+  of tyNil: result = typeNameOrLiteral(typ, "0")
+  of tyInt..tyUInt64:
+    result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
+  of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
+  else: result = nil
+
+proc pushType(m: BModule, typ: PType) =
+  add(m.typeStack, typ)
+
+proc getTypePre(m: BModule, typ: PType): Rope =
+  if typ == nil: result = rope("void")
+  else:
+    result = getSimpleTypeDesc(m, typ)
+    if result == nil: result = cacheGetType(m.typeCache, typ)
+
+proc structOrUnion(t: PType): Rope =
+  (if tfUnion in t.flags: rope("union") else: rope("struct"))
+
+proc getForwardStructFormat(m: BModule): string =
+  if m.compileToCpp: result = "$1 $2;$n"
+  else: result = "typedef $1 $2 $2;$n"
+
+proc getTypeForward(m: BModule, typ: PType): Rope =
+  result = cacheGetType(m.forwTypeCache, typ)
+  if result != nil: return
+  result = getTypePre(m, typ)
+  if result != nil: return
+  case typ.kind
+  of tySequence, tyTuple, tyObject:
+    result = getTypeName(typ)
+    if not isImportedType(typ):
+      addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+          [structOrUnion(typ), result])
+    idTablePut(m.forwTypeCache, typ, result)
+  else: internalError("getTypeForward(" & $typ.kind & ')')
+
+proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
+  ## like getTypeDescAux but creates only a *weak* dependency. In other words
+  ## we know we only need a pointer to it so we only generate a struct forward
+  ## declaration:
+  var etB = t.skipTypes(abstractInst)
+  case etB.kind
+  of tyObject, tyTuple:
+    if isImportedCppType(etB) and t.kind == tyGenericInst:
+      result = getTypeDescAux(m, t, check)
+    else:
+      let x = getUniqueType(etB)
+      result = getTypeForward(m, x)
+      pushType(m, x)
+  of tySequence:
+    let x = getUniqueType(etB)
+    result = getTypeForward(m, x) & "*"
+    pushType(m, x)
+  else:
+    result = getTypeDescAux(m, t, check)
+
+proc paramStorageLoc(param: PSym): TStorageLoc =
+  if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
+    result = OnStack
+  else:
+    result = OnUnknown
+
+proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
+                   check: var IntSet, declareEnvironment=true) =
+  params = nil
+  if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
+    rettype = ~"void"
+  else:
+    rettype = getTypeDescAux(m, t.sons[0], check)
+  for i in countup(1, sonsLen(t.n) - 1):
+    if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
+    var param = t.n.sons[i].sym
+    if isCompileTimeOnly(param.typ): continue
+    if params != nil: add(params, ~", ")
+    fillLoc(param.loc, locParam, param.typ, mangleName(param),
+            param.paramStorageLoc)
+    if ccgIntroducedPtr(param):
+      add(params, getTypeDescWeak(m, param.typ, check))
+      add(params, ~"*")
+      incl(param.loc.flags, lfIndirect)
+      param.loc.s = OnUnknown
+    else:
+      add(params, getTypeDescAux(m, param.typ, check))
+    add(params, ~" ")
+    add(params, param.loc.r)
+    # declare the len field for open arrays:
+    var arr = param.typ
+    if arr.kind == tyVar: arr = arr.sons[0]
+    var j = 0
+    while arr.kind in {tyOpenArray, tyVarargs}:
+      # this fixes the 'sort' bug:
+      if param.typ.kind == tyVar: param.loc.s = OnUnknown
+      # need to pass hidden parameter:
+      addf(params, ", NI $1Len$2", [param.loc.r, j.rope])
+      inc(j)
+      arr = arr.sons[0]
+  if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
+    var arr = t.sons[0]
+    if params != nil: add(params, ", ")
+    if (mapReturnType(t.sons[0]) != ctArray):
+      add(params, getTypeDescWeak(m, arr, check))
+      add(params, "*")
+    else:
+      add(params, getTypeDescAux(m, arr, check))
+    addf(params, " Result", [])
+  if t.callConv == ccClosure and declareEnvironment:
+    if params != nil: add(params, ", ")
+    add(params, "void* ClEnv")
+  if tfVarargs in t.flags:
+    if params != nil: add(params, ", ")
+    add(params, "...")
+  if params == nil: add(params, "void)")
+  else: add(params, ")")
+  params = "(" & params
+
+proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
+  if (rectype.sym != nil) and
+      ({sfImportc, sfExportc} * rectype.sym.flags != {}):
+    result = field.loc.r
+  else:
+    result = rope(mangleField(field.name))
+  if result == nil: internalError(field.info, "mangleRecFieldName")
+
+proc genRecordFieldsAux(m: BModule, n: PNode,
+                        accessExpr: Rope, rectype: PType,
+                        check: var IntSet): Rope =
+  var
+    ae, uname, sname, a: Rope
+    k: PNode
+    field: PSym
+  result = nil
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
+  of nkRecCase:
+    if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
+    add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
+    uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
+    if accessExpr != nil: ae = "$1.$2" % [accessExpr, uname]
+    else: ae = uname
+    var unionBody: Rope = nil
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        k = lastSon(n.sons[i])
+        if k.kind != nkSym:
+          sname = "S" & rope(i)
+          a = genRecordFieldsAux(m, k, "$1.$2" % [ae, sname], rectype,
+                                 check)
+          if a != nil:
+            add(unionBody, "struct {")
+            add(unionBody, a)
+            addf(unionBody, "} $1;$n", [sname])
+        else:
+          add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
+      else: internalError("genRecordFieldsAux(record case branch)")
+    if unionBody != nil:
+      addf(result, "union{$n$1} $2;$n", [unionBody, uname])
+  of nkSym:
+    field = n.sym
+    if field.typ.kind == tyEmpty: return
+    #assert(field.ast == nil)
+    sname = mangleRecFieldName(field, rectype)
+    if accessExpr != nil: ae = "$1.$2" % [accessExpr, sname]
+    else: ae = sname
+    fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
+    # for importcpp'ed objects, we only need to set field.loc, but don't
+    # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
+    # with heavily templatized C++ code:
+    if not isImportedCppType(rectype):
+      let fieldType = field.loc.t.skipTypes(abstractInst)
+      if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
+        addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
+            [getTypeDescAux(m, fieldType.elemType, check), sname])
+      elif fieldType.kind == tySequence:
+        # we need to use a weak dependency here for trecursive_table.
+        addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
+      else:
+        # don't use fieldType here because we need the
+        # tyGenericInst for C++ template support
+        addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
+  else: internalError(n.info, "genRecordFieldsAux()")
+
+proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
+  result = genRecordFieldsAux(m, typ.n, nil, typ, check)
+
+proc getRecordDesc(m: BModule, typ: PType, name: Rope,
+                   check: var IntSet): Rope =
+  # declare the record:
+  var hasField = false
+
+  var attribute: Rope =
+    if tfPacked in typ.flags: rope(CC[cCompiler].packedPragma)
+    else: nil
+
+  result = ropecg(m, CC[cCompiler].structStmtFmt,
+    [structOrUnion(typ), name, attribute])
+
+  if typ.kind == tyObject:
+
+    if typ.sons[0] == nil:
+      if (typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags:
+        appcg(m, result, " {$n", [])
+      else:
+        appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
+        hasField = true
+    elif m.compileToCpp:
+      appcg(m, result, " : public $1 {$n",
+                      [getTypeDescAux(m, typ.sons[0], check)])
+      hasField = true
+    else:
+      appcg(m, result, " {$n  $1 Sup;$n",
+                      [getTypeDescAux(m, typ.sons[0], check)])
+      hasField = true
+  else:
+    addf(result, " {$n", [name])
+
+  var desc = getRecordFields(m, typ, check)
+  if desc == nil and not hasField:
+    addf(result, "char dummy;$n", [])
+  else:
+    add(result, desc)
+  add(result, "};" & tnl)
+
+proc getTupleDesc(m: BModule, typ: PType, name: Rope,
+                  check: var IntSet): Rope =
+  result = "$1 $2 {$n" % [structOrUnion(typ), name]
+  var desc: Rope = nil
+  for i in countup(0, sonsLen(typ) - 1):
+    addf(desc, "$1 Field$2;$n",
+         [getTypeDescAux(m, typ.sons[i], check), rope(i)])
+  if desc == nil: add(result, "char dummy;" & tnl)
+  else: add(result, desc)
+  add(result, "};" & tnl)
+
+proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
+  # A helper proc for handling cppimport patterns, involving numeric
+  # placeholders for generic types (e.g. '0, '**2, etc).
+  # pre: the cursor must be placed at the ' symbol
+  # post: the cursor will be placed after the final digit
+  # false will returned if the input is not recognized as a placeholder
+  inc cursor
+  let begin = cursor
+  while pat[cursor] == '*': inc cursor
+  if pat[cursor] in Digits:
+    outIdx = pat[cursor].ord - '0'.ord
+    outStars = cursor - begin
+    inc cursor
+    return true
+  else:
+    return false
+
+proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
+  # XXX: we should catch this earlier and report it as a semantic error
+  if idx >= typ.len: internalError "invalid apostrophe type parameter index"
+
+  result = typ.sons[idx]
+  for i in 1..stars:
+    if result != nil and result.len > 0:
+      result = if result.kind == tyGenericInst: result.sons[1]
+               else: result.elemType
+
+proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
+  # returns only the type's name
+  var t = getUniqueType(typ)
+  if t == nil: internalError("getTypeDescAux: t == nil")
+  if t.sym != nil: useHeader(m, t.sym)
+  result = getTypePre(m, t)
+  if result != nil: return
+  if containsOrIncl(check, t.id):
+    if isImportedCppType(typ) or isImportedCppType(t): return
+    internalError("cannot generate C type for: " & typeToString(typ))
+    # XXX: this BUG is hard to fix -> we need to introduce helper structs,
+    # but determining when this needs to be done is hard. We should split
+    # C type generation into an analysis and a code generation phase somehow.
+  case t.kind
+  of tyRef, tyPtr, tyVar:
+    var star = if t.kind == tyVar and tfVarIsPtr notin typ.flags and
+                    compileToCpp(m): "&" else: "*"
+    var et = t.lastSon
+    var etB = et.skipTypes(abstractInst)
+    if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
+      # this is correct! sets have no proper base type, so we treat
+      # ``var set[char]`` in `getParamTypeDesc`
+      et = elemType(etB)
+      etB = et.skipTypes(abstractInst)
+      star[0] = '*'
+    case etB.kind
+    of tyObject, tyTuple:
+      if isImportedCppType(etB) and et.kind == tyGenericInst:
+        result = getTypeDescAux(m, et, check) & star
+      else:
+        # no restriction! We have a forward declaration for structs
+        let x = getUniqueType(etB)
+        let name = getTypeForward(m, x)
+        result = name & star
+        idTablePut(m.typeCache, t, result)
+        pushType(m, x)
+    of tySequence:
+      # no restriction! We have a forward declaration for structs
+      let x = getUniqueType(etB)
+      let name = getTypeForward(m, x)
+      result = name & "*" & star
+      idTablePut(m.typeCache, t, result)
+      pushType(m, x)
+    else:
+      # else we have a strong dependency  :-(
+      result = getTypeDescAux(m, et, check) & star
+      idTablePut(m.typeCache, t, result)
+  of tyOpenArray, tyVarargs:
+    result = getTypeDescAux(m, t.sons[0], check) & "*"
+    idTablePut(m.typeCache, t, result)
+  of tyProc:
+    result = getTypeName(t)
+    idTablePut(m.typeCache, t, result)
+    var rettype, desc: Rope
+    genProcParams(m, t, rettype, desc, check)
+    if not isImportedType(t):
+      if t.callConv != ccClosure: # procedure vars may need a closure!
+        addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+             [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
+      else:
+        addf(m.s[cfsTypes], "typedef struct {$n" &
+            "N_NIMCALL_PTR($2, ClPrc) $3;$n" &
+            "void* ClEnv;$n} $1;$n",
+             [result, rettype, desc])
+  of tySequence:
+    # we cannot use getTypeForward here because then t would be associated
+    # with the name of the struct, not with the pointer to the struct:
+    result = cacheGetType(m.forwTypeCache, t)
+    if result == nil:
+      result = getTypeName(t)
+      if not isImportedType(t):
+        addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+            [structOrUnion(t), result])
+      idTablePut(m.forwTypeCache, t, result)
+    assert(cacheGetType(m.typeCache, t) == nil)
+    idTablePut(m.typeCache, t, result & "*")
+    if not isImportedType(t):
+      if skipTypes(t.sons[0], typedescInst).kind != tyEmpty:
+        const
+          cppSeq = "struct $2 : #TGenericSeq {$n"
+          cSeq = "struct $2 {$n" &
+                 "  #TGenericSeq Sup;$n"
+        appcg(m, m.s[cfsSeqTypes],
+            (if m.compileToCpp: cppSeq else: cSeq) &
+            "  $1 data[SEQ_DECL_SIZE];$n" &
+            "};$n", [getTypeDescAux(m, t.sons[0], check), result])
+      else:
+        result = rope("TGenericSeq")
+    add(result, "*")
+  of tyArrayConstr, tyArray:
+    var n: BiggestInt = lengthOrd(t)
+    if n <= 0: n = 1   # make an array of at least one element
+    result = getTypeName(t)
+    idTablePut(m.typeCache, t, result)
+    if not isImportedType(t):
+      let foo = getTypeDescAux(m, t.sons[1], check)
+      addf(m.s[cfsTypes], "typedef $1 $2[$3];$n",
+           [foo, result, rope(n)])
+  of tyObject, tyTuple:
+    if isImportedCppType(t) and typ.kind == tyGenericInst:
+      # for instantiated templates we do not go through the type cache as the
+      # the type cache is not aware of 'tyGenericInst'.
+      let cppName = getTypeName(t)
+      var i = 0
+      var chunkStart = 0
+      while i < cppName.data.len:
+        if cppName.data[i] == '\'':
+          var chunkEnd = <i
+          var idx, stars: int
+          if scanCppGenericSlot(cppName.data, i, idx, stars):
+            result.add cppName.data.substr(chunkStart, chunkEnd)
+            chunkStart = i
+
+            let typeInSlot = resolveStarsInCppType(typ, idx + 1, stars)
+            if typeInSlot == nil or typeInSlot.kind == tyEmpty:
+              result.add(~"void")
+            else:
+              result.add getTypeDescAux(m, typeInSlot, check)
+        else:
+          inc i
+
+      if chunkStart != 0:
+        result.add cppName.data.substr(chunkStart)
+      else:
+        result = cppName & "<"
+        for i in 1 .. typ.len-2:
+          if i > 1: result.add(", ")
+          result.add(getTypeDescAux(m, typ.sons[i], check))
+        result.add("> ")
+      # always call for sideeffects:
+      assert t.kind != tyTuple
+      discard getRecordDesc(m, t, result, check)
+    else:
+      result = cacheGetType(m.forwTypeCache, t)
+      if result == nil:
+        result = getTypeName(t)
+        if not isImportedType(t):
+          addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
+             [structOrUnion(t), result])
+        idTablePut(m.forwTypeCache, t, result)
+      idTablePut(m.typeCache, t, result) # always call for sideeffects:
+      let recdesc = if t.kind != tyTuple: getRecordDesc(m, t, result, check)
+                    else: getTupleDesc(m, t, result, check)
+      if not isImportedType(t): add(m.s[cfsTypes], recdesc)
+  of tySet:
+    case int(getSize(t))
+    of 1: result = rope("NU8")
+    of 2: result = rope("NU16")
+    of 4: result = rope("NU32")
+    of 8: result = rope("NU64")
+    else:
+      result = getTypeName(t)
+      idTablePut(m.typeCache, t, result)
+      if not isImportedType(t):
+        addf(m.s[cfsTypes], "typedef NU8 $1[$2];$n",
+             [result, rope(getSize(t))])
+  of tyGenericInst, tyDistinct, tyOrdinal, tyConst, tyMutable,
+      tyIter, tyTypeDesc:
+    result = getTypeDescAux(m, lastSon(t), check)
+  else:
+    internalError("getTypeDescAux(" & $t.kind & ')')
+    result = nil
+  # fixes bug #145:
+  excl(check, t.id)
+
+proc getTypeDesc(m: BModule, typ: PType): Rope =
+  var check = initIntSet()
+  result = getTypeDescAux(m, typ, check)
+
+type
+  TClosureTypeKind = enum
+    clHalf, clHalfWithEnv, clFull
+
+proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
+  assert t.kind == tyProc
+  var check = initIntSet()
+  result = getTempName()
+  var rettype, desc: Rope
+  genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
+  if not isImportedType(t):
+    if t.callConv != ccClosure or kind != clFull:
+      addf(m.s[cfsTypes], "typedef $1_PTR($2, $3) $4;$n",
+           [rope(CallingConvToStr[t.callConv]), rettype, result, desc])
+    else:
+      addf(m.s[cfsTypes], "typedef struct {$n" &
+          "N_NIMCALL_PTR($2, ClPrc) $3;$n" &
+          "void* ClEnv;$n} $1;$n",
+           [result, rettype, desc])
+
+proc getTypeDesc(m: BModule, magic: string): Rope =
+  var sym = magicsys.getCompilerProc(magic)
+  if sym != nil:
+    result = getTypeDesc(m, sym.typ)
+  else:
+    rawMessage(errSystemNeeds, magic)
+    result = nil
+
+proc finishTypeDescriptions(m: BModule) =
+  var i = 0
+  while i < len(m.typeStack):
+    discard getTypeDesc(m, m.typeStack[i])
+    inc(i)
+
+template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
+
+proc genProcHeader(m: BModule, prc: PSym): Rope =
+  var
+    rettype, params: Rope
+  genCLineDir(result, prc.info)
+  # using static is needed for inline procs
+  if lfExportLib in prc.loc.flags:
+    if m.isHeaderFile:
+      result.add "N_LIB_IMPORT "
+    else:
+      result.add "N_LIB_EXPORT "
+  elif prc.typ.callConv == ccInline:
+    result.add "static "
+  var check = initIntSet()
+  fillLoc(prc.loc, locProc, prc.typ, mangleName(prc), OnUnknown)
+  genProcParams(m, prc.typ, rettype, params, check)
+  # careful here! don't access ``prc.ast`` as that could reload large parts of
+  # the object graph!
+  if prc.constraint.isNil:
+    addf(result, "$1($2, $3)$4",
+         [rope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
+         params])
+  else:
+    result = prc.cgDeclFrmt % [rettype, prc.loc.r, params]
+
+# ------------------ type info generation -------------------------------------
+
+proc genTypeInfo(m: BModule, t: PType): Rope
+proc getNimNode(m: BModule): Rope =
+  result = "$1[$2]" % [m.typeNodesName, rope(m.typeNodes)]
+  inc(m.typeNodes)
+
+proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: Rope) =
+  var nimtypeKind: int
+  #allocMemTI(m, typ, name)
+  if isObjLackingTypeField(typ):
+    nimtypeKind = ord(tyPureObject)
+  else:
+    nimtypeKind = ord(typ.kind)
+
+  var size: Rope
+  if tfIncompleteStruct in typ.flags: size = rope"void*"
+  elif m.compileToCpp: size = getTypeDesc(m, origType)
+  else: size = getTypeDesc(m, typ)
+  addf(m.s[cfsTypeInit3],
+       "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
+       [name, size, rope(nimtypeKind), base])
+  # compute type flags for GC optimization
+  var flags = 0
+  if not containsGarbageCollectedRef(typ): flags = flags or 1
+  if not canFormAcycle(typ): flags = flags or 2
+  #else MessageOut("can contain a cycle: " & typeToString(typ))
+  if flags != 0:
+    addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
+  discard cgsym(m, "TNimType")
+  addf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
+       [name, rope(typeToString(typ))])
+
+proc genTypeInfoAux(m: BModule, typ, origType: PType, name: Rope) =
+  var base: Rope
+  if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
+    base = genTypeInfo(m, typ.sons[0])
+  else:
+    base = rope("0")
+  genTypeInfoAuxBase(m, typ, origType, name, base)
+
+proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
+  # bugfix: we need to search the type that contains the discriminator:
+  var objtype = objtype
+  while lookupInRecord(objtype.n, d.name) == nil:
+    objtype = objtype.sons[0]
+  if objtype.sym == nil:
+    internalError(d.info, "anonymous obj with discriminator")
+  result = "NimDT_$1_$2" % [rope(objtype.id), rope(d.name.s.mangle)]
+
+proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
+  discard cgsym(m, "TNimNode")
+  var tmp = discriminatorTableName(m, objtype, d)
+  result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(d.typ)+1)]
+
+proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
+  case n.kind
+  of nkRecList:
+    var L = sonsLen(n)
+    if L == 1:
+      genObjectFields(m, typ, n.sons[0], expr)
+    elif L > 0:
+      var tmp = getTempName()
+      addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
+      for i in countup(0, L-1):
+        var tmp2 = getNimNode(m)
+        addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
+        genObjectFields(m, typ, n.sons[i], tmp2)
+      addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+           [expr, rope(L), tmp])
+    else:
+      addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n", [expr, rope(L)])
+  of nkRecCase:
+    assert(n.sons[0].kind == nkSym)
+    var field = n.sons[0].sym
+    var tmp = discriminatorTableName(m, typ, field)
+    var L = lengthOrd(field.typ)
+    assert L > 0
+    addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
+        "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
+        "$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
+        "$1.len = $7;$n", [expr, getTypeDesc(m, typ), field.loc.r,
+                           genTypeInfo(m, field.typ),
+                           makeCString(field.name.s),
+                           tmp, rope(L)])
+    addf(m.s[cfsData], "TNimNode* $1[$2];$n", [tmp, rope(L+1)])
+    for i in countup(1, sonsLen(n)-1):
+      var b = n.sons[i]           # branch
+      var tmp2 = getNimNode(m)
+      genObjectFields(m, typ, lastSon(b), tmp2)
+      case b.kind
+      of nkOfBranch:
+        if sonsLen(b) < 2:
+          internalError(b.info, "genObjectFields; nkOfBranch broken")
+        for j in countup(0, sonsLen(b) - 2):
+          if b.sons[j].kind == nkRange:
+            var x = int(getOrdValue(b.sons[j].sons[0]))
+            var y = int(getOrdValue(b.sons[j].sons[1]))
+            while x <= y:
+              addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
+              inc(x)
+          else:
+            addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+                 [tmp, rope(getOrdValue(b.sons[j])), tmp2])
+      of nkElse:
+        addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
+             [tmp, rope(L), tmp2])
+      else: internalError(n.info, "genObjectFields(nkRecCase)")
+  of nkSym:
+    var field = n.sym
+    addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+        "$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
+        "$1.name = $5;$n", [expr, getTypeDesc(m, typ),
+        field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
+  else: internalError(n.info, "genObjectFields")
+
+proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope) =
+  if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
+  else: genTypeInfoAuxBase(m, typ, origType, name, rope("0"))
+  var tmp = getNimNode(m)
+  if not isImportedCppType(typ):
+    genObjectFields(m, typ, typ.n, tmp)
+  addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
+  var t = typ.sons[0]
+  while t != nil:
+    t = t.skipTypes(abstractInst)
+    t.flags.incl tfObjHasKids
+    t = t.sons[0]
+
+proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
+  genTypeInfoAuxBase(m, typ, typ, name, rope("0"))
+  var expr = getNimNode(m)
+  var length = sonsLen(typ)
+  if length > 0:
+    var tmp = getTempName()
+    addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
+    for i in countup(0, length - 1):
+      var a = typ.sons[i]
+      var tmp2 = getNimNode(m)
+      addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(i), tmp2])
+      addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
+          "$1.offset = offsetof($2, Field$3);$n" &
+          "$1.typ = $4;$n" &
+          "$1.name = \"Field$3\";$n",
+           [tmp2, getTypeDesc(m, typ), rope(i), genTypeInfo(m, a)])
+    addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n",
+         [expr, rope(length), tmp])
+  else:
+    addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 2;$n",
+         [expr, rope(length)])
+  addf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, expr])
+
+proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
+  # Type information for enumerations is quite heavy, so we do some
+  # optimizations here: The ``typ`` field is never set, as it is redundant
+  # anyway. We generate a cstring array and a loop over it. Exceptional
+  # positions will be reset after the loop.
+  genTypeInfoAux(m, typ, typ, name)
+  var nodePtrs = getTempName()
+  var length = sonsLen(typ.n)
+  addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
+       [nodePtrs, rope(length)])
+  var enumNames, specialCases: Rope
+  var firstNimNode = m.typeNodes
+  var hasHoles = false
+  for i in countup(0, length - 1):
+    assert(typ.n.sons[i].kind == nkSym)
+    var field = typ.n.sons[i].sym
+    var elemNode = getNimNode(m)
+    if field.ast == nil:
+      # no explicit string literal for the enum field, so use field.name:
+      add(enumNames, makeCString(field.name.s))
+    else:
+      add(enumNames, makeCString(field.ast.strVal))
+    if i < length - 1: add(enumNames, ", " & tnl)
+    if field.position != i or tfEnumHasHoles in typ.flags:
+      addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
+      hasHoles = true
+  var enumArray = getTempName()
+  var counter = getTempName()
+  addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
+  addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
+       [enumArray, rope(length), enumNames])
+  addf(m.s[cfsTypeInit3], "for ($1 = 0; $1 < $2; $1++) {$n" &
+      "$3[$1+$4].kind = 1;$n" & "$3[$1+$4].offset = $1;$n" &
+      "$3[$1+$4].name = $5[$1];$n" & "$6[$1] = &$3[$1+$4];$n" & "}$n", [counter,
+      rope(length), m.typeNodesName, rope(firstNimNode), enumArray, nodePtrs])
+  add(m.s[cfsTypeInit3], specialCases)
+  addf(m.s[cfsTypeInit3],
+       "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4.node = &$1;$n",
+       [getNimNode(m), rope(length), nodePtrs, name])
+  if hasHoles:
+    # 1 << 2 is {ntfEnumHole}
+    addf(m.s[cfsTypeInit3], "$1.flags = 1<<2;$n", [name])
+
+proc genSetInfo(m: BModule, typ: PType, name: Rope) =
+  assert(typ.sons[0] != nil)
+  genTypeInfoAux(m, typ, typ, name)
+  var tmp = getNimNode(m)
+  addf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
+       [tmp, rope(firstOrd(typ)), name])
+
+proc genArrayInfo(m: BModule, typ: PType, name: Rope) =
+  genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
+
+proc fakeClosureType(owner: PSym): PType =
+  # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
+  result = newType(tyTuple, owner)
+  result.rawAddSon(newType(tyPointer, owner))
+  var r = newType(tyRef, owner)
+  r.rawAddSon(newType(tyTuple, owner))
+  result.rawAddSon(r)
+
+type
+  TTypeInfoReason = enum  ## for what do we need the type info?
+    tiNew,                ## for 'new'
+    tiNewSeq,             ## for 'newSeq'
+    tiNonVariantAsgn,     ## for generic assignment without variants
+    tiVariantAsgn         ## for generic assignment with variants
+
+include ccgtrav
+
+proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
+  genProc(m, s)
+  addf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
+     [result, s.loc.r])
+
+proc genTypeInfo(m: BModule, t: PType): Rope =
+  let origType = t
+  var t = getUniqueType(t)
+  result = "NTI$1" % [rope(t.id)]
+  if containsOrIncl(m.typeInfoMarker, t.id):
+    return "(&".rope & result & ")".rope
+
+  # getUniqueType doesn't skip tyDistinct when that has an overriden operation:
+  while t.kind == tyDistinct: t = t.lastSon
+  let owner = t.skipTypes(typedescPtrs).owner.getModule
+  if owner != m.module:
+    # make sure the type info is created in the owner module
+    discard genTypeInfo(owner.bmod, t)
+    # reference the type info as extern here
+    discard cgsym(m, "TNimType")
+    discard cgsym(m, "TNimNode")
+    addf(m.s[cfsVars], "extern TNimType $1; /* $2 */$n",
+         [result, rope(typeToString(t))])
+    return "(&".rope & result & ")".rope
+  case t.kind
+  of tyEmpty: result = rope"0"
+  of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
+    genTypeInfoAuxBase(m, t, t, result, rope"0")
+  of tyProc:
+    if t.callConv != ccClosure:
+      genTypeInfoAuxBase(m, t, t, result, rope"0")
+    else:
+      genTupleInfo(m, fakeClosureType(t.owner), result)
+  of tySequence, tyRef:
+    genTypeInfoAux(m, t, t, result)
+    if gSelectedGC >= gcMarkAndSweep:
+      let markerProc = genTraverseProc(m, t, tiNew)
+      addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
+  of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
+  of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
+  of tySet: genSetInfo(m, t, result)
+  of tyEnum: genEnumInfo(m, t, result)
+  of tyObject: genObjectInfo(m, t, origType, result)
+  of tyTuple:
+    # if t.n != nil: genObjectInfo(m, t, result)
+    # else:
+    # BUGFIX: use consistently RTTI without proper field names; otherwise
+    # results are not deterministic!
+    genTupleInfo(m, t, result)
+  else: internalError("genTypeInfo(" & $t.kind & ')')
+  if t.deepCopy != nil:
+    genDeepCopyProc(m, t.deepCopy, result)
+  elif origType.deepCopy != nil:
+    genDeepCopyProc(m, origType.deepCopy, result)
+  result = "(&".rope & result & ")".rope
+
+proc genTypeSection(m: BModule, n: PNode) =
+  discard
diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim
new file mode 100644
index 000000000..4ba6643ec
--- /dev/null
+++ b/compiler/ccgutils.nim
@@ -0,0 +1,212 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module declares some helpers for the C code generator.
+
+import
+  ast, astalgo, ropes, lists, hashes, strutils, types, msgs, wordrecg,
+  platform, trees
+
+proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
+  case n.kind
+  of nkStmtList:
+    for i in 0 .. < n.len:
+      result = getPragmaStmt(n[i], w)
+      if result != nil: break
+  of nkPragma:
+    for i in 0 .. < n.len:
+      if whichPragma(n[i]) == w: return n[i]
+  else: discard
+
+proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
+  result = getPragmaStmt(n, w) != nil
+
+proc hashString*(s: string): BiggestInt =
+  # has to be the same algorithm as system.hashString!
+  if CPU[targetCPU].bit == 64:
+    # we have to use the same bitwidth
+    # as the target CPU
+    var b = 0'i64
+    for i in countup(0, len(s) - 1):
+      b = b +% ord(s[i])
+      b = b +% `shl`(b, 10)
+      b = b xor `shr`(b, 6)
+    b = b +% `shl`(b, 3)
+    b = b xor `shr`(b, 11)
+    b = b +% `shl`(b, 15)
+    result = b
+  else:
+    var a = 0'i32
+    for i in countup(0, len(s) - 1):
+      a = a +% ord(s[i]).int32
+      a = a +% `shl`(a, 10'i32)
+      a = a xor `shr`(a, 6'i32)
+    a = a +% `shl`(a, 3'i32)
+    a = a xor `shr`(a, 11'i32)
+    a = a +% `shl`(a, 15'i32)
+    result = a
+
+var
+  gTypeTable: array[TTypeKind, TIdTable]
+  gCanonicalTypes: array[TTypeKind, PType]
+
+proc initTypeTables() =
+  for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])
+
+proc resetCaches* =
+  ## XXX: fix that more properly
+  initTypeTables()
+  for i in low(gCanonicalTypes)..high(gCanonicalTypes):
+    gCanonicalTypes[i] = nil
+
+when false:
+  proc echoStats*() =
+    for i in countup(low(TTypeKind), high(TTypeKind)):
+      echo i, " ", gTypeTable[i].counter
+
+proc slowSearch(key: PType; k: TTypeKind): PType =
+  # tuples are quite horrible as C does not support them directly and
+  # tuple[string, string] is a (strange) subtype of
+  # tuple[nameA, nameB: string]. This bites us here, so we
+  # use 'sameBackendType' instead of 'sameType'.
+  if idTableHasObjectAsKey(gTypeTable[k], key): return key
+  for h in countup(0, high(gTypeTable[k].data)):
+    var t = PType(gTypeTable[k].data[h].key)
+    if t != nil and sameBackendType(t, key):
+      return t
+  idTablePut(gTypeTable[k], key, key)
+  result = key
+
+proc getUniqueType*(key: PType): PType =
+  # this is a hotspot in the compiler!
+  if key == nil: return
+  var k = key.kind
+  case k
+  of tyBool, tyChar, tyInt..tyUInt64:
+    # no canonicalization for integral types, so that e.g. ``pid_t`` is
+    # produced instead of ``NI``.
+    result = key
+  of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
+      tyCString, tyNone, tyBigNum:
+    result = gCanonicalTypes[k]
+    if result == nil:
+      gCanonicalTypes[k] = key
+      result = key
+  of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
+    internalError("getUniqueType")
+  of tyDistinct:
+    if key.deepCopy != nil: result = key
+    else: result = getUniqueType(lastSon(key))
+  of tyGenericInst, tyOrdinal, tyMutable, tyConst, tyIter, tyStatic:
+    result = getUniqueType(lastSon(key))
+    #let obj = lastSon(key)
+    #if obj.sym != nil and obj.sym.name.s == "TOption":
+    #  echo "for ", typeToString(key), " I returned "
+    #  debug result
+  of tyPtr, tyRef, tyVar:
+    let elemType = lastSon(key)
+    if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
+      # no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
+      # produced instead of ``ptr NI``.
+      result = key
+    else:
+      result = slowSearch(key, k)
+  of tyArrayConstr, tyGenericInvocation, tyGenericBody,
+     tyOpenArray, tyArray, tySet, tyRange, tyTuple,
+     tySequence, tyForward, tyVarargs, tyProxy:
+    # we have to do a slow linear search because types may need
+    # to be compared by their structure:
+    result = slowSearch(key, k)
+  of tyObject:
+    if tfFromGeneric notin key.flags:
+      # fast case; lookup per id suffices:
+      result = PType(idTableGet(gTypeTable[k], key))
+      if result == nil:
+        idTablePut(gTypeTable[k], key, key)
+        result = key
+    else:
+      # ugly slow case: need to compare by structure
+      if idTableHasObjectAsKey(gTypeTable[k], key): return key
+      for h in countup(0, high(gTypeTable[k].data)):
+        var t = PType(gTypeTable[k].data[h].key)
+        if t != nil and sameBackendType(t, key):
+          return t
+      idTablePut(gTypeTable[k], key, key)
+      result = key
+  of tyEnum:
+    result = PType(idTableGet(gTypeTable[k], key))
+    if result == nil:
+      idTablePut(gTypeTable[k], key, key)
+      result = key
+  of tyProc:
+    if key.callConv != ccClosure:
+      result = key
+    else:
+      # ugh, we need the canon here:
+      result = slowSearch(key, k)
+
+proc tableGetType*(tab: TIdTable, key: PType): RootRef =
+  # returns nil if we need to declare this type
+  result = idTableGet(tab, key)
+  if (result == nil) and (tab.counter > 0):
+    # we have to do a slow linear search because types may need
+    # to be compared by their structure:
+    for h in countup(0, high(tab.data)):
+      var t = PType(tab.data[h].key)
+      if t != nil:
+        if sameType(t, key):
+          return tab.data[h].val
+
+proc makeSingleLineCString*(s: string): string =
+  result = "\""
+  for c in items(s):
+    result.add(c.toCChar)
+  result.add('\"')
+
+proc mangle*(name: string): string =
+  ## Lowercases the given name and manges any non-alphanumeric characters
+  ## so they are represented as `HEX____`. If the name starts with a number,
+  ## `N` is prepended
+  result = newStringOfCap(name.len)
+  case name[0]
+  of Letters:
+    result.add(name[0])
+  of Digits:
+    result.add("N" & name[0])
+  else:
+    result = "HEX" & toHex(ord(name[0]), 2)
+  for i in 1..(name.len-1):
+    let c = name[i]
+    case c
+    of 'A'..'Z':
+      add(result, c.toLower)
+    of '_':
+      discard
+    of 'a'..'z', '0'..'9':
+      add(result, c)
+    else:
+      add(result, "HEX" & toHex(ord(c), 2))
+
+proc makeLLVMString*(s: string): Rope =
+  const MaxLineLength = 64
+  result = nil
+  var res = "c\""
+  for i in countup(0, len(s) - 1):
+    if (i + 1) mod MaxLineLength == 0:
+      add(result, rope(res))
+      setLen(res, 0)
+    case s[i]
+    of '\0'..'\x1F', '\x80'..'\xFF', '\"', '\\':
+      add(res, '\\')
+      add(res, toHex(ord(s[i]), 2))
+    else: add(res, s[i])
+  add(res, "\\00\"")
+  add(result, rope(res))
+
+initTypeTables()
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
new file mode 100644
index 000000000..4b0bac28a
--- /dev/null
+++ b/compiler/cgen.nim
@@ -0,0 +1,1330 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the C code generator.
+
+import
+  ast, astalgo, hashes, trees, platform, magicsys, extccomp,
+  options, intsets,
+  nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
+  ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
+  rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
+  semparallel
+
+import strutils except `%` # collides with ropes.`%`
+
+when options.hasTinyCBackend:
+  import tccgen
+
+# implementation
+
+var
+  generatedHeader: BModule
+
+proc addForwardedProc(m: BModule, prc: PSym) =
+  m.forwardedProcs.add(prc)
+  inc(gForwardedProcsCounter)
+
+proc getCgenModule(s: PSym): BModule =
+  result = if s.position >= 0 and s.position < gModules.len: gModules[s.position]
+           else: nil
+
+proc findPendingModule(m: BModule, s: PSym): BModule =
+  var ms = getModule(s)
+  result = gModules[ms.position]
+
+proc emitLazily(s: PSym): bool {.inline.} =
+  result = optDeadCodeElim in gGlobalOptions or
+           sfDeadCodeElim in getModule(s).flags
+
+proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
+  result.k = k
+  result.s = s
+  result.t = typ
+  result.r = nil
+  result.flags = {}
+
+proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: Rope, s: TStorageLoc) =
+  # fills the loc if it is not already initialized
+  if a.k == locNone:
+    a.k = k
+    a.t = typ
+    a.s = s
+    if a.r == nil: a.r = r
+
+proc isSimpleConst(typ: PType): bool =
+  let t = skipTypes(typ, abstractVar)
+  result = t.kind notin
+      {tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence} and not
+      (t.kind == tyProc and t.callConv == ccClosure)
+
+proc useStringh(m: BModule) =
+  if not m.includesStringh:
+    m.includesStringh = true
+    discard lists.includeStr(m.headerFiles, "<string.h>")
+
+proc useHeader(m: BModule, sym: PSym) =
+  if lfHeader in sym.loc.flags:
+    assert(sym.annex != nil)
+    discard lists.includeStr(m.headerFiles, getStr(sym.annex.path))
+
+proc cgsym(m: BModule, name: string): Rope
+
+proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
+  var i = 0
+  var length = len(frmt)
+  result = nil
+  var num = 0
+  while i < length:
+    if frmt[i] == '$':
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '$':
+        add(result, "$")
+        inc(i)
+      of '#':
+        inc(i)
+        add(result, args[num])
+        inc(num)
+      of '0'..'9':
+        var j = 0
+        while true:
+          j = (j * 10) + ord(frmt[i]) - ord('0')
+          inc(i)
+          if i >= length or not (frmt[i] in {'0'..'9'}): break
+        num = j
+        if j > high(args) + 1:
+          internalError("ropes: invalid format string $" & $j)
+        add(result, args[j-1])
+      of 'n':
+        if optLineDir notin gOptions: add(result, rnl)
+        inc(i)
+      of 'N':
+        add(result, rnl)
+        inc(i)
+      else: internalError("ropes: invalid format string $" & frmt[i])
+    elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
+      inc(i)
+      var j = i
+      while frmt[j] in IdentChars: inc(j)
+      var ident = substr(frmt, i, j-1)
+      i = j
+      add(result, cgsym(m, ident))
+    elif frmt[i] == '#' and frmt[i+1] == '$':
+      inc(i, 2)
+      var j = 0
+      while frmt[i] in Digits:
+        j = (j * 10) + ord(frmt[i]) - ord('0')
+        inc(i)
+      add(result, cgsym(m, $args[j-1]))
+    var start = i
+    while i < length:
+      if frmt[i] != '$' and frmt[i] != '#': inc(i)
+      else: break
+    if i - 1 >= start:
+      add(result, substr(frmt, start, i - 1))
+
+template rfmt(m: BModule, fmt: string, args: varargs[Rope]): expr =
+  ropecg(m, fmt, args)
+
+proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
+           args: varargs[Rope]) =
+  add(c, ropecg(m, frmt, args))
+
+proc appcg(m: BModule, s: TCFileSection, frmt: FormatStr,
+           args: varargs[Rope]) =
+  add(m.s[s], ropecg(m, frmt, args))
+
+proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
+           args: varargs[Rope]) =
+  add(p.s(s), ropecg(p.module, frmt, args))
+
+var indent = "\t".rope
+proc indentLine(p: BProc, r: Rope): Rope =
+  result = r
+  for i in countup(0, p.blocks.len-1): prepend(result, indent)
+
+proc line(p: BProc, s: TCProcSection, r: Rope) =
+  add(p.s(s), indentLine(p, r))
+
+proc line(p: BProc, s: TCProcSection, r: string) =
+  add(p.s(s), indentLine(p, r.rope))
+
+proc lineF(p: BProc, s: TCProcSection, frmt: FormatStr,
+              args: openarray[Rope]) =
+  add(p.s(s), indentLine(p, frmt % args))
+
+proc lineCg(p: BProc, s: TCProcSection, frmt: FormatStr,
+               args: varargs[Rope]) =
+  add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+
+proc linefmt(p: BProc, s: TCProcSection, frmt: FormatStr,
+             args: varargs[Rope]) =
+  add(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
+
+proc appLineCg(p: BProc, r: var Rope, frmt: FormatStr,
+               args: varargs[Rope]) =
+  add(r, indentLine(p, ropecg(p.module, frmt, args)))
+
+proc safeLineNm(info: TLineInfo): int =
+  result = toLinenumber(info)
+  if result < 0: result = 0 # negative numbers are not allowed in #line
+
+proc genCLineDir(r: var Rope, filename: string, line: int) =
+  assert line >= 0
+  if optLineDir in gOptions:
+    addf(r, "$N#line $2 $1$N",
+        [rope(makeSingleLineCString(filename)), rope(line)])
+
+proc genCLineDir(r: var Rope, info: TLineInfo) =
+  genCLineDir(r, info.toFullPath, info.safeLineNm)
+
+proc freshLineInfo(p: BProc; info: TLineInfo): bool =
+  if p.lastLineInfo.line != info.line or
+     p.lastLineInfo.fileIndex != info.fileIndex:
+    p.lastLineInfo.line = info.line
+    p.lastLineInfo.fileIndex = info.fileIndex
+    result = true
+
+proc genLineDir(p: BProc, t: PNode) =
+  var line = t.info.safeLineNm
+  if optEmbedOrigSrc in gGlobalOptions:
+    add(p.s(cpsStmts), ~"//" & t.info.sourceLine & rnl)
+  genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
+  if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
+      (p.prc == nil or sfPure notin p.prc.flags):
+    if freshLineInfo(p, t.info):
+      linefmt(p, cpsStmts, "#endb($1, $2);$n",
+              line.rope, makeCString(toFilename(t.info)))
+  elif ({optLineTrace, optStackTrace} * p.options ==
+      {optLineTrace, optStackTrace}) and
+      (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
+    if freshLineInfo(p, t.info):
+      linefmt(p, cpsStmts, "nimln($1, $2);$n",
+              line.rope, t.info.quotedFilename)
+
+proc postStmtActions(p: BProc) {.inline.} =
+  add(p.s(cpsStmts), p.module.injectStmt)
+
+proc accessThreadLocalVar(p: BProc, s: PSym)
+proc emulatedThreadVars(): bool {.inline.}
+proc genProc(m: BModule, prc: PSym)
+
+template compileToCpp(m: BModule): expr =
+  gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
+
+include "ccgtypes.nim"
+
+# ------------------------------ Manager of temporaries ------------------
+
+proc rdLoc(a: TLoc): Rope =
+  # 'read' location (deref if indirect)
+  result = a.r
+  if lfIndirect in a.flags: result = "(*$1)" % [result]
+
+proc addrLoc(a: TLoc): Rope =
+  result = a.r
+  if lfIndirect notin a.flags and mapType(a.t) != ctArray:
+    result = "(&" & result & ")"
+
+proc rdCharLoc(a: TLoc): Rope =
+  # read a location that may need a char-cast:
+  result = rdLoc(a)
+  if skipTypes(a.t, abstractRange).kind == tyChar:
+    result = "((NU8)($1))" % [result]
+
+proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
+                   takeAddr: bool) =
+  case analyseObjectWithTypeField(t)
+  of frNone:
+    discard
+  of frHeader:
+    var r = rdLoc(a)
+    if not takeAddr: r = "(*$1)" % [r]
+    var s = skipTypes(t, abstractInst)
+    if not p.module.compileToCpp:
+      while (s.kind == tyObject) and (s.sons[0] != nil):
+        add(r, ".Sup")
+        s = skipTypes(s.sons[0], abstractInst)
+    linefmt(p, section, "$1.m_type = $2;$n", r, genTypeInfo(p.module, t))
+  of frEmbedded:
+    # worst case for performance:
+    var r = if takeAddr: addrLoc(a) else: rdLoc(a)
+    linefmt(p, section, "#objectInit($1, $2);$n", r, genTypeInfo(p.module, t))
+
+type
+  TAssignmentFlag = enum
+    needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil,
+    afSrcIsNotNil, needToKeepAlive
+  TAssignmentFlags = set[TAssignmentFlag]
+
+proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
+
+proc isComplexValueType(t: PType): bool {.inline.} =
+  result = t.kind in {tyArray, tyArrayConstr, tySet, tyTuple, tyObject} or
+    (t.kind == tyProc and t.callConv == ccClosure)
+
+proc resetLoc(p: BProc, loc: var TLoc) =
+  let containsGcRef = containsGarbageCollectedRef(loc.t)
+  let typ = skipTypes(loc.t, abstractVarRange)
+  if isImportedCppType(typ): return
+  if not isComplexValueType(typ):
+    if containsGcRef:
+      var nilLoc: TLoc
+      initLoc(nilLoc, locTemp, loc.t, OnStack)
+      nilLoc.r = rope("NIM_NIL")
+      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+    else:
+      linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
+  else:
+    if optNilCheck in p.options:
+      linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc))
+    if loc.s != OnStack:
+      linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
+              addrLoc(loc), genTypeInfo(p.module, loc.t))
+      # XXX: generated reset procs should not touch the m_type
+      # field, so disabling this should be safe:
+      genObjectInit(p, cpsStmts, loc.t, loc, true)
+    else:
+      useStringh(p.module)
+      linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
+              addrLoc(loc), rdLoc(loc))
+      # XXX: We can be extra clever here and call memset only
+      # on the bytes following the m_type field?
+      genObjectInit(p, cpsStmts, loc.t, loc, true)
+
+proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
+  let typ = skipTypes(loc.t, abstractRange)
+  if not isComplexValueType(typ):
+    linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
+  else:
+    if not isTemp or containsGarbageCollectedRef(loc.t):
+      # don't use memset for temporary values for performance if we can
+      # avoid it:
+      if not isImportedCppType(typ):
+        useStringh(p.module)
+        linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n",
+                addrLoc(loc), rdLoc(loc))
+    genObjectInit(p, cpsStmts, loc.t, loc, true)
+
+proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
+  if sfNoInit notin v.flags:
+    # we know it is a local variable and thus on the stack!
+    # If ``not immediateAsgn`` it is not initialized in a binding like
+    # ``var v = X`` and thus we need to init it.
+    # If ``v`` contains a GC-ref we may pass it to ``unsureAsgnRef`` somehow
+    # which requires initialization. However this can really only happen if
+    # ``var v = X()`` gets transformed into ``X(&v)``.
+    # Nowadays the logic in ccgcalls deals with this case however.
+    if not immediateAsgn:
+      constructLoc(p, v.loc)
+
+proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
+  inc(p.labels)
+  result.r = "LOC" & rope(p.labels)
+  linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
+  result.k = locTemp
+  #result.a = - 1
+  result.t = getUniqueType(t)
+  result.s = OnStack
+  result.flags = {}
+  constructLoc(p, result, not needsInit)
+
+proc keepAlive(p: BProc, toKeepAlive: TLoc) =
+  when false:
+    # deactivated because of the huge slowdown this causes; GC will take care
+    # of interior pointers instead
+    if optRefcGC notin gGlobalOptions: return
+    var result: TLoc
+    var fid = rope(p.gcFrameId)
+    result.r = "GCFRAME.F" & fid
+    addf(p.gcFrameType, "  $1 F$2;$n",
+        [getTypeDesc(p.module, toKeepAlive.t), fid])
+    inc(p.gcFrameId)
+    result.k = locTemp
+    #result.a = -1
+    result.t = toKeepAlive.t
+    result.s = OnStack
+    result.flags = {}
+
+    if not isComplexValueType(skipTypes(toKeepAlive.t, abstractVarRange)):
+      linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(result), rdLoc(toKeepAlive))
+    else:
+      useStringh(p.module)
+      linefmt(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
+           addrLoc(result), addrLoc(toKeepAlive), rdLoc(result))
+
+proc initGCFrame(p: BProc): Rope =
+  if p.gcFrameId > 0: result = "struct {$1} GCFRAME;$n" % [p.gcFrameType]
+
+proc deinitGCFrame(p: BProc): Rope =
+  if p.gcFrameId > 0:
+    result = ropecg(p.module,
+                    "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
+
+proc localDebugInfo(p: BProc, s: PSym) =
+  if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
+  # XXX work around a bug: No type information for open arrays possible:
+  if skipTypes(s.typ, abstractVar).kind in {tyOpenArray, tyVarargs}: return
+  var a = "&" & s.loc.r
+  if s.kind == skParam and ccgIntroducedPtr(s): a = s.loc.r
+  lineF(p, cpsInit,
+       "F.s[$1].address = (void*)$3; F.s[$1].typ = $4; F.s[$1].name = $2;$n",
+       [p.maxFrameLen.rope, makeCString(normalize(s.name.s)), a,
+        genTypeInfo(p.module, s.loc.t)])
+  inc(p.maxFrameLen)
+  inc p.blocks[p.blocks.len-1].frameLen
+
+proc localVarDecl(p: BProc; s: PSym): Rope =
+  if s.loc.k == locNone:
+    fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
+    if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
+  result = getTypeDesc(p.module, s.loc.t)
+  if s.constraint.isNil:
+    if sfRegister in s.flags: add(result, " register")
+    #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
+    #  add(decl, " GC_GUARD")
+    if sfVolatile in s.flags: add(result, " volatile")
+    add(result, " ")
+    add(result, s.loc.r)
+  else:
+    result = s.cgDeclFrmt % [result, s.loc.r]
+
+proc assignLocalVar(p: BProc, s: PSym) =
+  #assert(s.loc.k == locNone) # not yet assigned
+  # this need not be fulfilled for inline procs; they are regenerated
+  # for each module that uses them!
+  let decl = localVarDecl(p, s) & ";" & tnl
+  line(p, cpsLocals, decl)
+  localDebugInfo(p, s)
+
+include ccgthreadvars
+
+proc varInDynamicLib(m: BModule, sym: PSym)
+proc mangleDynLibProc(sym: PSym): Rope
+
+proc assignGlobalVar(p: BProc, s: PSym) =
+  if s.loc.k == locNone:
+    fillLoc(s.loc, locGlobalVar, s.typ, mangleName(s), OnHeap)
+
+  if lfDynamicLib in s.loc.flags:
+    var q = findPendingModule(p.module, s)
+    if q != nil and not containsOrIncl(q.declaredThings, s.id):
+      varInDynamicLib(q, s)
+    else:
+      s.loc.r = mangleDynLibProc(s)
+    return
+  useHeader(p.module, s)
+  if lfNoDecl in s.loc.flags: return
+  if sfThread in s.flags:
+    declareThreadVar(p.module, s, sfImportc in s.flags)
+  else:
+    var decl: Rope = nil
+    var td = getTypeDesc(p.module, s.loc.t)
+    if s.constraint.isNil:
+      if sfImportc in s.flags: add(decl, "extern ")
+      add(decl, td)
+      if sfRegister in s.flags: add(decl, " register")
+      if sfVolatile in s.flags: add(decl, " volatile")
+      addf(decl, " $1;$n", [s.loc.r])
+    else:
+      decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
+    add(p.module.s[cfsVars], decl)
+  if p.withinLoop > 0:
+    # fixes tests/run/tzeroarray:
+    resetLoc(p, s.loc)
+  if p.module.module.options * {optStackTrace, optEndb} ==
+                               {optStackTrace, optEndb}:
+    appcg(p.module, p.module.s[cfsDebugInit],
+          "#dbgRegisterGlobal($1, &$2, $3);$n",
+         [makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
+          s.loc.r, genTypeInfo(p.module, s.typ)])
+
+proc assignParam(p: BProc, s: PSym) =
+  assert(s.loc.r != nil)
+  localDebugInfo(p, s)
+
+proc fillProcLoc(sym: PSym) =
+  if sym.loc.k == locNone:
+    fillLoc(sym.loc, locProc, sym.typ, mangleName(sym), OnStack)
+
+proc getLabel(p: BProc): TLabel =
+  inc(p.labels)
+  result = "LA" & rope(p.labels)
+
+proc fixLabel(p: BProc, labl: TLabel) =
+  lineF(p, cpsStmts, "$1: ;$n", [labl])
+
+proc genVarPrototype(m: BModule, sym: PSym)
+proc requestConstImpl(p: BProc, sym: PSym)
+proc genStmts(p: BProc, t: PNode)
+proc expr(p: BProc, n: PNode, d: var TLoc)
+proc genProcPrototype(m: BModule, sym: PSym)
+proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
+proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
+proc intLiteral(i: BiggestInt): Rope
+proc genLiteral(p: BProc, n: PNode): Rope
+proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
+
+proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
+  initLoc(result, locNone, e.typ, OnUnknown)
+  expr(p, e, result)
+
+proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
+  initLoc(result, locNone, e.typ, OnUnknown)
+  result.flags.incl lfSingleUse
+  expr(p, e, result)
+
+proc lenField(p: BProc): Rope =
+  result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
+
+include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
+
+# ----------------------------- dynamic library handling -----------------
+# We don't finalize dynamic libs as the OS does this for us.
+
+proc isGetProcAddr(lib: PLib): bool =
+  let n = lib.path
+  result = n.kind in nkCallKinds and n.typ != nil and
+    n.typ.kind in {tyPointer, tyProc}
+
+proc loadDynamicLib(m: BModule, lib: PLib) =
+  assert(lib != nil)
+  if not lib.generated:
+    lib.generated = true
+    var tmp = getGlobalTempName()
+    assert(lib.name == nil)
+    lib.name = tmp # BUGFIX: cgsym has awful side-effects
+    addf(m.s[cfsVars], "static void* $1;$n", [tmp])
+    if lib.path.kind in {nkStrLit..nkTripleStrLit}:
+      var s: TStringSeq = @[]
+      libCandidates(lib.path.strVal, s)
+      if gVerbosity >= 2:
+        msgWriteln("Dependency: " & lib.path.strVal)
+      var loadlib: Rope = nil
+      for i in countup(0, high(s)):
+        inc(m.labels)
+        if i > 0: add(loadlib, "||")
+        appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
+              [tmp, getStrLit(m, s[i])])
+      appcg(m, m.s[cfsDynLibInit],
+            "if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
+            [loadlib, getStrLit(m, lib.path.strVal)])
+    else:
+      var p = newProc(nil, m)
+      p.options = p.options - {optStackTrace, optEndb}
+      var dest: TLoc
+      initLocExpr(p, lib.path, dest)
+      add(m.s[cfsVars], p.s(cpsLocals))
+      add(m.s[cfsDynLibInit], p.s(cpsInit))
+      add(m.s[cfsDynLibInit], p.s(cpsStmts))
+      appcg(m, m.s[cfsDynLibInit],
+           "if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
+           [tmp, rdLoc(dest)])
+
+  if lib.name == nil: internalError("loadDynamicLib")
+
+proc mangleDynLibProc(sym: PSym): Rope =
+  if sfCompilerProc in sym.flags:
+    # NOTE: sym.loc.r is the external name!
+    result = rope(sym.name.s)
+  else:
+    result = "Dl_$1" % [rope(sym.id)]
+
+proc symInDynamicLib(m: BModule, sym: PSym) =
+  var lib = sym.annex
+  let isCall = isGetProcAddr(lib)
+  var extname = sym.loc.r
+  if not isCall: loadDynamicLib(m, lib)
+  var tmp = mangleDynLibProc(sym)
+  sym.loc.r = tmp             # from now on we only need the internal name
+  sym.typ.sym = nil           # generate a new name
+  inc(m.labels, 2)
+  if isCall:
+    let n = lib.path
+    var a: TLoc
+    initLocExpr(m.initProc, n[0], a)
+    var params = rdLoc(a) & "("
+    for i in 1 .. n.len-2:
+      initLocExpr(m.initProc, n[i], a)
+      params.add(rdLoc(a))
+      params.add(", ")
+    let load = "\t$1 = ($2) ($3$4));$n" %
+        [tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
+    var last = lastSon(n)
+    if last.kind == nkHiddenStdConv: last = last.sons[1]
+    internalAssert(last.kind == nkStrLit)
+    let idx = last.strVal
+    if idx.len == 0:
+      add(m.initProc.s(cpsStmts), load)
+    elif idx.len == 1 and idx[0] in {'0'..'9'}:
+      add(m.extensionLoaders[idx[0]], load)
+    else:
+      internalError(sym.info, "wrong index: " & idx)
+  else:
+    appcg(m, m.s[cfsDynLibInit],
+        "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
+        [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
+  addf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+
+proc varInDynamicLib(m: BModule, sym: PSym) =
+  var lib = sym.annex
+  var extname = sym.loc.r
+  loadDynamicLib(m, lib)
+  incl(sym.loc.flags, lfIndirect)
+  var tmp = mangleDynLibProc(sym)
+  sym.loc.r = tmp             # from now on we only need the internal name
+  inc(m.labels, 2)
+  appcg(m, m.s[cfsDynLibInit],
+      "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
+      [tmp, getTypeDesc(m, sym.typ), lib.name, makeCString($extname)])
+  addf(m.s[cfsVars], "$2* $1;$n",
+      [sym.loc.r, getTypeDesc(m, sym.loc.t)])
+
+proc symInDynamicLibPartial(m: BModule, sym: PSym) =
+  sym.loc.r = mangleDynLibProc(sym)
+  sym.typ.sym = nil           # generate a new name
+
+proc cgsym(m: BModule, name: string): Rope =
+  var sym = magicsys.getCompilerProc(name)
+  if sym != nil:
+    case sym.kind
+    of skProc, skMethod, skConverter, skIterators: genProc(m, sym)
+    of skVar, skResult, skLet: genVarPrototype(m, sym)
+    of skType: discard getTypeDesc(m, sym.typ)
+    else: internalError("cgsym: " & name)
+  else:
+    # we used to exclude the system module from this check, but for DLL
+    # generation support this sloppyness leads to hard to detect bugs, so
+    # we're picky here for the system module too:
+    rawMessage(errSystemNeeds, name)
+  result = sym.loc.r
+
+proc generateHeaders(m: BModule) =
+  add(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
+  var it = PStrEntry(m.headerFiles.head)
+  while it != nil:
+    if it.data[0] notin {'\"', '<'}:
+      addf(m.s[cfsHeaders], "$N#include \"$1\"$N", [rope(it.data)])
+    else:
+      addf(m.s[cfsHeaders], "$N#include $1$N", [rope(it.data)])
+    it = PStrEntry(it.next)
+
+proc retIsNotVoid(s: PSym): bool =
+  result = (s.typ.sons[0] != nil) and not isInvalidReturnType(s.typ.sons[0])
+
+proc initFrame(p: BProc, procname, filename: Rope): Rope =
+  discard cgsym(p.module, "nimFrame")
+  if p.maxFrameLen > 0:
+    discard cgsym(p.module, "TVarSlot")
+    result = rfmt(nil, "\tnimfrs($1, $2, $3, $4)$N",
+                  procname, filename, p.maxFrameLen.rope,
+                  p.blocks[0].frameLen.rope)
+  else:
+    result = rfmt(nil, "\tnimfr($1, $2)$N", procname, filename)
+
+proc deinitFrame(p: BProc): Rope =
+  result = rfmt(p.module, "\t#popFrame();$n")
+
+proc closureSetup(p: BProc, prc: PSym) =
+  if tfCapturesEnv notin prc.typ.flags: return
+  # prc.ast[paramsPos].last contains the type we're after:
+  var ls = lastSon(prc.ast[paramsPos])
+  if ls.kind != nkSym:
+    internalError(prc.info, "closure generation failed")
+  var env = ls.sym
+  #echo "created environment: ", env.id, " for ", prc.name.s
+  assignLocalVar(p, env)
+  # generate cast assignment:
+  linefmt(p, cpsStmts, "$1 = ($2) ClEnv;$n",
+          rdLoc(env.loc), getTypeDesc(p.module, env.typ))
+
+proc genProcAux(m: BModule, prc: PSym) =
+  var p = newProc(prc, m)
+  var header = genProcHeader(m, prc)
+  var returnStmt: Rope = nil
+  assert(prc.ast != nil)
+  if sfPure notin prc.flags and prc.typ.sons[0] != nil:
+    if resultPos >= prc.ast.len:
+      internalError(prc.info, "proc has no result symbol")
+    var res = prc.ast.sons[resultPos].sym # get result symbol
+    if not isInvalidReturnType(prc.typ.sons[0]):
+      if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
+      # declare the result symbol:
+      assignLocalVar(p, res)
+      assert(res.loc.r != nil)
+      returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc))
+      initLocalVar(p, res, immediateAsgn=false)
+    else:
+      fillResult(res)
+      assignParam(p, res)
+      if skipTypes(res.typ, abstractInst).kind == tyArray:
+        incl(res.loc.flags, lfIndirect)
+        res.loc.s = OnUnknown
+
+  for i in countup(1, sonsLen(prc.typ.n) - 1):
+    var param = prc.typ.n.sons[i].sym
+    if param.typ.isCompileTimeOnly: continue
+    assignParam(p, param)
+  closureSetup(p, prc)
+  genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
+  var generatedProc: Rope
+  if sfNoReturn in prc.flags:
+    if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
+      header = "__declspec(noreturn) " & header
+  if sfPure in prc.flags:
+    if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
+      header = "__declspec(naked) " & header
+    generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
+                         header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
+  else:
+    generatedProc = rfmt(nil, "$N$1 {$N", header)
+    add(generatedProc, initGCFrame(p))
+    if optStackTrace in prc.options:
+      add(generatedProc, p.s(cpsLocals))
+      var procname = makeCString(prc.name.s)
+      add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
+    else:
+      add(generatedProc, p.s(cpsLocals))
+    if optProfiler in prc.options:
+      # invoke at proc entry for recursion:
+      appcg(p, cpsInit, "\t#nimProfile();$n", [])
+    if p.beforeRetNeeded: add(generatedProc, "{")
+    add(generatedProc, p.s(cpsInit))
+    add(generatedProc, p.s(cpsStmts))
+    if p.beforeRetNeeded: add(generatedProc, ~"\t}BeforeRet: ;$n")
+    add(generatedProc, deinitGCFrame(p))
+    if optStackTrace in prc.options: add(generatedProc, deinitFrame(p))
+    add(generatedProc, returnStmt)
+    add(generatedProc, ~"}$N")
+  add(m.s[cfsProcs], generatedProc)
+
+proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
+  result = sfCompileToCpp in m.module.flags and
+           sfCompileToCpp notin sym.getModule().flags and
+           gCmd != cmdCompileToCpp
+
+proc genProcPrototype(m: BModule, sym: PSym) =
+  useHeader(m, sym)
+  if lfNoDecl in sym.loc.flags: return
+  if lfDynamicLib in sym.loc.flags:
+    if getModule(sym).id != m.module.id and
+        not containsOrIncl(m.declaredThings, sym.id):
+      add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
+                        getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
+  elif not containsOrIncl(m.declaredProtos, sym.id):
+    var header = genProcHeader(m, sym)
+    if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
+      header = "extern \"C\" " & header
+    if sfPure in sym.flags and hasAttribute in CC[cCompiler].props:
+      header.add(" __attribute__((naked))")
+    if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
+      header.add(" __attribute__((noreturn))")
+    add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
+
+proc genProcNoForward(m: BModule, prc: PSym) =
+  fillProcLoc(prc)
+  useHeader(m, prc)
+  if lfImportCompilerProc in prc.loc.flags:
+    # dependency to a compilerproc:
+    discard cgsym(m, prc.name.s)
+    return
+  genProcPrototype(m, prc)
+  if lfNoDecl in prc.loc.flags: discard
+  elif prc.typ.callConv == ccInline:
+    # We add inline procs to the calling module to enable C based inlining.
+    # This also means that a check with ``q.declaredThings`` is wrong, we need
+    # a check for ``m.declaredThings``.
+    if not containsOrIncl(m.declaredThings, prc.id): genProcAux(m, prc)
+  elif lfDynamicLib in prc.loc.flags:
+    var q = findPendingModule(m, prc)
+    if q != nil and not containsOrIncl(q.declaredThings, prc.id):
+      symInDynamicLib(q, prc)
+    else:
+      symInDynamicLibPartial(m, prc)
+  elif sfImportc notin prc.flags:
+    var q = findPendingModule(m, prc)
+    if q != nil and not containsOrIncl(q.declaredThings, prc.id):
+      genProcAux(q, prc)
+
+proc requestConstImpl(p: BProc, sym: PSym) =
+  var m = p.module
+  useHeader(m, sym)
+  if sym.loc.k == locNone:
+    fillLoc(sym.loc, locData, sym.typ, mangleName(sym), OnUnknown)
+  if lfNoDecl in sym.loc.flags: return
+  # declare implementation:
+  var q = findPendingModule(m, sym)
+  if q != nil and not containsOrIncl(q.declaredThings, sym.id):
+    assert q.initProc.module == q
+    addf(q.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
+        [getTypeDesc(q, sym.typ), sym.loc.r, genConstExpr(q.initProc, sym.ast)])
+  # declare header:
+  if q != m and not containsOrIncl(m.declaredThings, sym.id):
+    assert(sym.loc.r != nil)
+    let headerDecl = "extern NIM_CONST $1 $2;$n" %
+        [getTypeDesc(m, sym.loc.t), sym.loc.r]
+    add(m.s[cfsData], headerDecl)
+    if sfExportc in sym.flags and generatedHeader != nil:
+      add(generatedHeader.s[cfsData], headerDecl)
+
+proc isActivated(prc: PSym): bool = prc.typ != nil
+
+proc genProc(m: BModule, prc: PSym) =
+  if sfBorrow in prc.flags or not isActivated(prc): return
+  fillProcLoc(prc)
+  if sfForward in prc.flags: addForwardedProc(m, prc)
+  else:
+    genProcNoForward(m, prc)
+    if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
+        generatedHeader != nil and lfNoDecl notin prc.loc.flags:
+      genProcPrototype(generatedHeader, prc)
+      if prc.typ.callConv == ccInline:
+        if not containsOrIncl(generatedHeader.declaredThings, prc.id):
+          genProcAux(generatedHeader, prc)
+
+proc genVarPrototypeAux(m: BModule, sym: PSym) =
+  assert(sfGlobal in sym.flags)
+  useHeader(m, sym)
+  fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
+  if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
+    return
+  if sym.owner.id != m.module.id:
+    # else we already have the symbol generated!
+    assert(sym.loc.r != nil)
+    if sfThread in sym.flags:
+      declareThreadVar(m, sym, true)
+    else:
+      add(m.s[cfsVars], "extern ")
+      add(m.s[cfsVars], getTypeDesc(m, sym.loc.t))
+      if lfDynamicLib in sym.loc.flags: add(m.s[cfsVars], "*")
+      if sfRegister in sym.flags: add(m.s[cfsVars], " register")
+      if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
+      addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
+
+proc genVarPrototype(m: BModule, sym: PSym) =
+  genVarPrototypeAux(m, sym)
+
+proc addIntTypes(result: var Rope) {.inline.} =
+  addf(result, "#define NIM_INTBITS $1", [
+    platform.CPU[targetCPU].intSize.rope])
+
+proc getCopyright(cfile: string): Rope =
+  if optCompileOnly in gGlobalOptions:
+    result = ("/* Generated by Nim Compiler v$1 */$N" &
+        "/*   (c) 2015 Andreas Rumpf */$N" &
+        "/* The generated code is subject to the original license. */$N") %
+        [rope(VersionAsString)]
+  else:
+    result = ("/* Generated by Nim Compiler v$1 */$N" &
+        "/*   (c) 2015 Andreas Rumpf */$N" &
+        "/* The generated code is subject to the original license. */$N" &
+        "/* Compiled for: $2, $3, $4 */$N" &
+        "/* Command for C compiler:$n   $5 */$N") %
+        [rope(VersionAsString),
+        rope(platform.OS[targetOS].name),
+        rope(platform.CPU[targetCPU].name),
+        rope(extccomp.CC[extccomp.cCompiler].name),
+        rope(getCompileCFileCmd(cfile))]
+
+proc getFileHeader(cfile: string): Rope =
+  result = getCopyright(cfile)
+  addIntTypes(result)
+
+proc genFilenames(m: BModule): Rope =
+  discard cgsym(m, "dbgRegisterFilename")
+  result = nil
+  for i in 0.. <fileInfos.len:
+    result.addf("dbgRegisterFilename($1);$N", [fileInfos[i].projPath.makeCString])
+
+proc genMainProc(m: BModule) =
+  const
+    # The use of a volatile function pointer to call Pre/NimMainInner
+    # prevents inlining of the NimMainInner function and dependent
+    # functions, which might otherwise merge their stack frames.
+    PreMainBody =
+      "void PreMainInner() {$N" &
+      "\tsystemInit();$N" &
+      "$1" &
+      "$2" &
+      "$3" &
+      "}$N$N" &
+      "void PreMain() {$N" &
+      "\tvoid (*volatile inner)();$N" &
+      "\tsystemDatInit();$N" &
+      "\tinner = PreMainInner;$N" &
+      "$4$5" &
+      "\t(*inner)();$N" &
+      "}$N$N"
+
+    MainProcs =
+      "\tNimMain();$N"
+
+    MainProcsWithResult =
+      MainProcs & "\treturn nim_program_result;$N"
+
+    NimMainBody =
+      "N_CDECL(void, NimMainInner)(void) {$N" &
+        "$1" &
+      "}$N$N" &
+      "N_CDECL(void, NimMain)(void) {$N" &
+        "\tvoid (*volatile inner)();$N" &
+        "\tPreMain();$N" &
+        "\tinner = NimMainInner;$N" &
+        "$2" &
+        "\t(*inner)();$N" &
+      "}$N$N"
+
+    PosixNimMain =
+      "int cmdCount;$N" &
+      "char** cmdLine;$N" &
+      "char** gEnv;$N" &
+      NimMainBody
+
+    PosixCMain =
+      "int main(int argc, char** args, char** env) {$N" &
+        "\tcmdLine = args;$N" &
+        "\tcmdCount = argc;$N" &
+        "\tgEnv = env;$N" &
+        MainProcsWithResult &
+      "}$N$N"
+
+    StandaloneCMain =
+      "int main(void) {$N" &
+        MainProcs &
+        "\treturn 0;$N" &
+      "}$N$N"
+
+    WinNimMain = NimMainBody
+
+    WinCMain = "N_STDCALL(int, WinMain)(HINSTANCE hCurInstance, $N" &
+      "                        HINSTANCE hPrevInstance, $N" &
+      "                        LPSTR lpCmdLine, int nCmdShow) {$N" &
+      MainProcsWithResult & "}$N$N"
+
+    WinNimDllMain = "N_LIB_EXPORT " & NimMainBody
+
+    WinCDllMain =
+      "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
+      "                    LPVOID lpvReserved) {$N" &
+      "\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
+      "\treturn 1;$N}$N$N"
+
+    PosixNimDllMain = WinNimDllMain
+
+    PosixCDllMain =
+      "void NIM_POSIX_INIT NimMainInit(void) {$N" &
+        MainProcs &
+      "}$N$N"
+
+  var nimMain, otherMain: FormatStr
+  if platform.targetOS == osWindows and
+      gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
+    if optGenGuiApp in gGlobalOptions:
+      nimMain = WinNimMain
+      otherMain = WinCMain
+    else:
+      nimMain = WinNimDllMain
+      otherMain = WinCDllMain
+    discard lists.includeStr(m.headerFiles, "<windows.h>")
+  elif optGenDynLib in gGlobalOptions:
+    nimMain = PosixNimDllMain
+    otherMain = PosixCDllMain
+  elif platform.targetOS == osStandalone:
+    nimMain = PosixNimMain
+    otherMain = StandaloneCMain
+  else:
+    nimMain = PosixNimMain
+    otherMain = PosixCMain
+  if gBreakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
+  if optEndb in gOptions:
+    gBreakpoints.add(m.genFilenames)
+
+  let initStackBottomCall =
+    if platform.targetOS == osStandalone: "".rope
+    else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
+  inc(m.labels)
+  appcg(m, m.s[cfsProcs], PreMainBody, [
+    mainDatInit, gBreakpoints, otherModsInit,
+     if emulatedThreadVars() and platform.targetOS != osStandalone:
+       ropecg(m, "\t#initThreadVarsEmulation();$N")
+     else:
+       "".rope,
+     initStackBottomCall])
+
+  appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, rope(m.labels)])
+  if optNoMain notin gGlobalOptions:
+    appcg(m, m.s[cfsProcs], otherMain, [])
+
+proc getSomeInitName(m: PSym, suffix: string): Rope =
+  assert m.kind == skModule
+  assert m.owner.kind == skPackage
+  if {sfSystemModule, sfMainModule} * m.flags == {}:
+    result = m.owner.name.s.mangle.rope
+    result.add "_"
+  result.add m.name.s
+  result.add suffix
+
+proc getInitName(m: PSym): Rope = getSomeInitName(m, "Init")
+proc getDatInitName(m: PSym): Rope = getSomeInitName(m, "DatInit")
+
+proc registerModuleToMain(m: PSym) =
+  var
+    init = m.getInitName
+    datInit = m.getDatInitName
+  addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
+  addf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
+  if sfSystemModule notin m.flags:
+    addf(mainDatInit, "\t$1();$N", [datInit])
+    let initCall = "\t$1();$N" % [init]
+    if sfMainModule in m.flags:
+      add(mainModInit, initCall)
+    else:
+      add(otherModsInit, initCall)
+
+proc genInitCode(m: BModule) =
+  var initname = getInitName(m.module)
+  var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname]
+  if m.typeNodes > 0:
+    appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
+          [m.typeNodesName, rope(m.typeNodes)])
+  if m.nimTypes > 0:
+    appcg(m, m.s[cfsTypeInit1], "static #TNimType $1[$2];$n",
+          [m.nimTypesName, rope(m.nimTypes)])
+
+  add(prc, initGCFrame(m.initProc))
+
+  add(prc, genSectionStart(cpsLocals))
+  add(prc, m.preInitProc.s(cpsLocals))
+  add(prc, m.initProc.s(cpsLocals))
+  add(prc, m.postInitProc.s(cpsLocals))
+  add(prc, genSectionEnd(cpsLocals))
+
+  if optStackTrace in m.initProc.options and not m.frameDeclared:
+    # BUT: the generated init code might depend on a current frame, so
+    # declare it nevertheless:
+    m.frameDeclared = true
+    if not m.preventStackTrace:
+      var procname = makeCString(m.module.name.s)
+      add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
+    else:
+      add(prc, ~"\tTFrame F; F.len = 0;$N")
+
+  add(prc, genSectionStart(cpsInit))
+  add(prc, m.preInitProc.s(cpsInit))
+  add(prc, m.initProc.s(cpsInit))
+  add(prc, m.postInitProc.s(cpsInit))
+  add(prc, genSectionEnd(cpsInit))
+
+  add(prc, genSectionStart(cpsStmts))
+  add(prc, m.preInitProc.s(cpsStmts))
+  add(prc, m.initProc.s(cpsStmts))
+  add(prc, m.postInitProc.s(cpsStmts))
+  add(prc, genSectionEnd(cpsStmts))
+  if optStackTrace in m.initProc.options and not m.preventStackTrace:
+    add(prc, deinitFrame(m.initProc))
+  add(prc, deinitGCFrame(m.initProc))
+  addf(prc, "}$N$N", [])
+
+  prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
+           [getDatInitName(m.module)])
+
+  for i in cfsTypeInit1..cfsDynLibInit:
+    add(prc, genSectionStart(i))
+    add(prc, m.s[i])
+    add(prc, genSectionEnd(i))
+
+  addf(prc, "}$N$N", [])
+  # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
+  # that would lead to a *nesting* of merge sections which the merger does
+  # not support. So we add it to another special section: ``cfsInitProc``
+  add(m.s[cfsInitProc], prc)
+
+  for i, el in pairs(m.extensionLoaders):
+    if el != nil:
+      let ex = "N_NIMCALL(void, nimLoadProcs$1)(void) {$2}$N$N" %
+        [(i.ord - '0'.ord).rope, el]
+      add(m.s[cfsInitProc], ex)
+
+proc genModule(m: BModule, cfile: string): Rope =
+  result = getFileHeader(cfile)
+  result.add(genMergeInfo(m))
+
+  generateHeaders(m)
+
+  generateThreadLocalStorage(m)
+  for i in countup(cfsHeaders, cfsProcs):
+    add(result, genSectionStart(i))
+    add(result, m.s[i])
+    add(result, genSectionEnd(i))
+  add(result, m.s[cfsInitProc])
+
+proc newPreInitProc(m: BModule): BProc =
+  result = newProc(nil, m)
+  # little hack so that unique temporaries are generated:
+  result.labels = 100_000
+
+proc newPostInitProc(m: BModule): BProc =
+  result = newProc(nil, m)
+  # little hack so that unique temporaries are generated:
+  result.labels = 200_000
+
+proc initProcOptions(m: BModule): TOptions =
+  if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
+
+proc rawNewModule(module: PSym, filename: string): BModule =
+  new(result)
+  initLinkedList(result.headerFiles)
+  result.declaredThings = initIntSet()
+  result.declaredProtos = initIntSet()
+  result.cfilename = filename
+  result.filename = filename
+  initIdTable(result.typeCache)
+  initIdTable(result.forwTypeCache)
+  result.module = module
+  result.typeInfoMarker = initIntSet()
+  result.initProc = newProc(nil, result)
+  result.initProc.options = initProcOptions(result)
+  result.preInitProc = newPreInitProc(result)
+  result.postInitProc = newPostInitProc(result)
+  initNodeTable(result.dataCache)
+  result.typeStack = @[]
+  result.forwardedProcs = @[]
+  result.typeNodesName = getTempName()
+  result.nimTypesName = getTempName()
+  # no line tracing for the init sections of the system module so that we
+  # don't generate a TFrame which can confuse the stack botton initialization:
+  if sfSystemModule in module.flags:
+    result.preventStackTrace = true
+    excl(result.preInitProc.options, optStackTrace)
+    excl(result.postInitProc.options, optStackTrace)
+
+proc nullify[T](arr: var T) =
+  for i in low(arr)..high(arr):
+    arr[i] = nil
+
+proc resetModule*(m: BModule) =
+  # between two compilations in CAAS mode, we can throw
+  # away all the data that was written to disk
+  initLinkedList(m.headerFiles)
+  m.declaredProtos = initIntSet()
+  initIdTable(m.forwTypeCache)
+  m.initProc = newProc(nil, m)
+  m.initProc.options = initProcOptions(m)
+  m.preInitProc = newPreInitProc(m)
+  m.postInitProc = newPostInitProc(m)
+  initNodeTable(m.dataCache)
+  m.typeStack = @[]
+  m.forwardedProcs = @[]
+  m.typeNodesName = getTempName()
+  m.nimTypesName = getTempName()
+  m.preventStackTrace = sfSystemModule in m.module.flags
+  nullify m.s
+  m.usesThreadVars = false
+  m.typeNodes = 0
+  m.nimTypes = 0
+  nullify m.extensionLoaders
+
+  # indicate that this is now cached module
+  # the cache will be invalidated by nullifying gModules
+  m.fromCache = true
+
+  # we keep only the "merge info" information for the module
+  # and the properties that can't change:
+  # m.filename
+  # m.cfilename
+  # m.isHeaderFile
+  # m.module ?
+  # m.typeCache
+  # m.declaredThings
+  # m.typeInfoMarker
+  # m.labels
+  # m.FrameDeclared
+
+proc resetCgenModules* =
+  for m in cgenModules(): resetModule(m)
+
+proc rawNewModule(module: PSym): BModule =
+  result = rawNewModule(module, module.position.int32.toFullPath)
+
+proc newModule(module: PSym): BModule =
+  # we should create only one cgen module for each module sym
+  internalAssert getCgenModule(module) == nil
+
+  result = rawNewModule(module)
+  growCache gModules, module.position
+  gModules[module.position] = result
+
+  if (optDeadCodeElim in gGlobalOptions):
+    if (sfDeadCodeElim in module.flags):
+      internalError("added pending module twice: " & module.filename)
+
+proc myOpen(module: PSym): PPassContext =
+  result = newModule(module)
+  if optGenIndex in gGlobalOptions and generatedHeader == nil:
+    let f = if headerFile.len > 0: headerFile else: gProjectFull
+    generatedHeader = rawNewModule(module,
+      changeFileExt(completeCFilePath(f), hExt))
+    generatedHeader.isHeaderFile = true
+
+proc writeHeader(m: BModule) =
+  var result = getCopyright(m.filename)
+  var guard = "__$1__" % [m.filename.splitFile.name.rope]
+  result.addf("#ifndef $1$n#define $1$n", [guard])
+  addIntTypes(result)
+  generateHeaders(m)
+
+  generateThreadLocalStorage(m)
+  for i in countup(cfsHeaders, cfsProcs):
+    add(result, genSectionStart(i))
+    add(result, m.s[i])
+    add(result, genSectionEnd(i))
+  add(result, m.s[cfsInitProc])
+
+  if optGenDynLib in gGlobalOptions:
+    result.add("N_LIB_IMPORT ")
+  result.addf("N_CDECL(void, NimMain)(void);$n", [])
+  result.addf("#endif /* $1 */$n", [guard])
+  writeRope(result, m.filename)
+
+proc getCFile(m: BModule): string =
+  let ext =
+      if m.compileToCpp: ".cpp"
+      elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
+      else: ".c"
+  result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
+
+proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
+  assert optSymbolFiles in gGlobalOptions
+  var m = newModule(module)
+  readMergeInfo(getCFile(m), m)
+  result = m
+
+proc myProcess(b: PPassContext, n: PNode): PNode =
+  result = n
+  if b == nil or passes.skipCodegen(n): return
+  var m = BModule(b)
+  m.initProc.options = initProcOptions(m)
+  genStmts(m.initProc, n)
+
+proc finishModule(m: BModule) =
+  var i = 0
+  while i <= high(m.forwardedProcs):
+    # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
+    # a ``for`` loop here
+    var prc = m.forwardedProcs[i]
+    if sfForward in prc.flags:
+      internalError(prc.info, "still forwarded: " & prc.name.s)
+    genProcNoForward(m, prc)
+    inc(i)
+  assert(gForwardedProcsCounter >= i)
+  dec(gForwardedProcsCounter, i)
+  setLen(m.forwardedProcs, 0)
+
+proc shouldRecompile(code: Rope, cfile: string): bool =
+  result = true
+  if optForceFullMake notin gGlobalOptions:
+    var objFile = toObjFile(cfile)
+    if writeRopeIfNotEqual(code, cfile): return
+    if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
+  else:
+    writeRope(code, cfile)
+
+# We need 2 different logics here: pending modules (including
+# 'nim__dat') may require file merging for the combination of dead code
+# elimination and incremental compilation! Non pending modules need no
+# such logic and in fact the logic hurts for the main module at least;
+# it would generate multiple 'main' procs, for instance.
+
+proc writeModule(m: BModule, pending: bool) =
+  # generate code for the init statements of the module:
+  var cfile = getCFile(m)
+  var cfilenoext = changeFileExt(cfile, "")
+
+  if not m.fromCache or optForceFullMake in gGlobalOptions:
+    genInitCode(m)
+    finishTypeDescriptions(m)
+    if sfMainModule in m.module.flags:
+      # generate main file:
+      add(m.s[cfsProcHeaders], mainModProcs)
+      generateThreadVarsSize(m)
+
+    var code = genModule(m, cfile)
+    when hasTinyCBackend:
+      if gCmd == cmdRun:
+        tccgen.compileCCode($code)
+        return
+
+    if shouldRecompile(code, cfile):
+      addFileToCompile(cfile)
+  elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
+    mergeFiles(cfile, m)
+    genInitCode(m)
+    finishTypeDescriptions(m)
+    var code = genModule(m, cfile)
+    writeRope(code, cfile)
+    addFileToCompile(cfile)
+  elif not existsFile(toObjFile(cfilenoext)):
+    # Consider: first compilation compiles ``system.nim`` and produces
+    # ``system.c`` but then compilation fails due to an error. This means
+    # that ``system.o`` is missing, so we need to call the C compiler for it:
+    addFileToCompile(cfile)
+
+  addFileToLink(cfilenoext)
+
+proc updateCachedModule(m: BModule) =
+  let cfile = getCFile(m)
+  let cfilenoext = changeFileExt(cfile, "")
+
+  if mergeRequired(m) and sfMainModule notin m.module.flags:
+    mergeFiles(cfile, m)
+    genInitCode(m)
+    finishTypeDescriptions(m)
+    var code = genModule(m, cfile)
+    writeRope(code, cfile)
+    addFileToCompile(cfile)
+
+  addFileToLink(cfilenoext)
+
+proc myClose(b: PPassContext, n: PNode): PNode =
+  result = n
+  if b == nil or passes.skipCodegen(n): return
+  var m = BModule(b)
+  if n != nil:
+    m.initProc.options = initProcOptions(m)
+    genStmts(m.initProc, n)
+  # cached modules need to registered too:
+  registerModuleToMain(m.module)
+
+  if sfMainModule in m.module.flags:
+    m.objHasKidsValid = true
+    var disp = generateMethodDispatchers()
+    for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
+    genMainProc(m)
+
+proc cgenWriteModules* =
+  # we need to process the transitive closure because recursive module
+  # deps are allowed (and the system module is processed in the wrong
+  # order anyway)
+  if generatedHeader != nil: finishModule(generatedHeader)
+  while gForwardedProcsCounter > 0:
+    for m in cgenModules():
+      if not m.fromCache:
+        finishModule(m)
+  for m in cgenModules():
+    if m.fromCache:
+      m.updateCachedModule
+    else:
+      m.writeModule(pending=true)
+  writeMapping(gMapping)
+  if generatedHeader != nil: writeHeader(generatedHeader)
+
+const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
+
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
new file mode 100644
index 000000000..187186373
--- /dev/null
+++ b/compiler/cgendata.nim
@@ -0,0 +1,162 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains the data structures for the C code generation phase.
+
+import
+  ast, astalgo, ropes, passes, options, intsets, lists, platform
+
+from msgs import TLineInfo
+
+type
+  TLabel* = Rope             # for the C generator a label is just a rope
+  TCFileSection* = enum       # the sections a generated C file consists of
+    cfsMergeInfo,             # section containing merge information
+    cfsHeaders,               # section for C include file headers
+    cfsForwardTypes,          # section for C forward typedefs
+    cfsTypes,                 # section for C typedefs
+    cfsSeqTypes,              # section for sequence types only
+                              # this is needed for strange type generation
+                              # reasons
+    cfsFieldInfo,             # section for field information
+    cfsTypeInfo,              # section for type information
+    cfsProcHeaders,           # section for C procs prototypes
+    cfsData,                  # section for C constant data
+    cfsVars,                  # section for C variable declarations
+    cfsProcs,                 # section for C procs that are not inline
+    cfsInitProc,              # section for the C init proc
+    cfsTypeInit1,             # section 1 for declarations of type information
+    cfsTypeInit2,             # section 2 for init of type information
+    cfsTypeInit3,             # section 3 for init of type information
+    cfsDebugInit,             # section for init of debug information
+    cfsDynLibInit,            # section for init of dynamic library binding
+    cfsDynLibDeinit           # section for deinitialization of dynamic
+                              # libraries
+  TCTypeKind* = enum          # describes the type kind of a C type
+    ctVoid, ctChar, ctBool,
+    ctInt, ctInt8, ctInt16, ctInt32, ctInt64,
+    ctFloat, ctFloat32, ctFloat64, ctFloat128,
+    ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64,
+    ctArray, ctPtrToArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc,
+    ctCString
+  TCFileSections* = array[TCFileSection, Rope] # represents a generated C file
+  TCProcSection* = enum       # the sections a generated C proc consists of
+    cpsLocals,                # section of local variables for C proc
+    cpsInit,                  # section for init of variables for C proc
+    cpsStmts                  # section of local statements for C proc
+  TCProcSections* = array[TCProcSection, Rope] # represents a generated C proc
+  BModule* = ref TCGen
+  BProc* = ref TCProc
+  TBlock*{.final.} = object
+    id*: int                  # the ID of the label; positive means that it
+    label*: Rope             # generated text for the label
+                              # nil if label is not used
+    sections*: TCProcSections # the code beloging
+    isLoop*: bool             # whether block is a loop
+    nestedTryStmts*: int16    # how many try statements is it nested into
+    nestedExceptStmts*: int16 # how many except statements is it nested into
+    frameLen*: int16
+
+  TCProc{.final.} = object    # represents C proc that is currently generated
+    prc*: PSym                # the Nim proc that this C proc belongs to
+    beforeRetNeeded*: bool    # true iff 'BeforeRet' label for proc is needed
+    threadVarAccessed*: bool  # true if the proc already accessed some threadvar
+    lastLineInfo*: TLineInfo  # to avoid generating excessive 'nimln' statements
+    nestedTryStmts*: seq[PNode]   # in how many nested try statements we are
+                                  # (the vars must be volatile then)
+    inExceptBlock*: int       # are we currently inside an except block?
+                              # leaving such scopes by raise or by return must
+                              # execute any applicable finally blocks
+    finallySafePoints*: seq[Rope]  # For correctly cleaning up exceptions when
+                                    # using return in finally statements
+    labels*: Natural          # for generating unique labels in the C proc
+    blocks*: seq[TBlock]      # nested blocks
+    breakIdx*: int            # the block that will be exited
+                              # with a regular break
+    options*: TOptions        # options that should be used for code
+                              # generation; this is the same as prc.options
+                              # unless prc == nil
+    maxFrameLen*: int         # max length of frame descriptor
+    module*: BModule          # used to prevent excessive parameter passing
+    withinLoop*: int          # > 0 if we are within a loop
+    splitDecls*: int          # > 0 if we are in some context for C++ that
+                              # requires 'T x = T()' to become 'T x; x = T()'
+                              # (yes, C++ is weird like that)
+    gcFrameId*: Natural       # for the GC stack marking
+    gcFrameType*: Rope       # the struct {} we put the GC markers into
+
+  TTypeSeq* = seq[PType]
+  TCGen = object of TPassContext # represents a C source file
+    module*: PSym
+    filename*: string
+    s*: TCFileSections        # sections of the C file
+    preventStackTrace*: bool  # true if stack traces need to be prevented
+    usesThreadVars*: bool     # true if the module uses a thread var
+    frameDeclared*: bool      # hack for ROD support so that we don't declare
+                              # a frame var twice in an init proc
+    isHeaderFile*: bool       # C source file is the header file
+    includesStringh*: bool    # C source file already includes ``<string.h>``
+    objHasKidsValid*: bool    # whether we can rely on tfObjHasKids
+    cfilename*: string        # filename of the module (including path,
+                              # without extension)
+    typeCache*: TIdTable      # cache the generated types
+    forwTypeCache*: TIdTable  # cache for forward declarations of types
+    declaredThings*: IntSet  # things we have declared in this .c file
+    declaredProtos*: IntSet  # prototypes we have declared in this .c file
+    headerFiles*: TLinkedList # needed headers to include
+    typeInfoMarker*: IntSet  # needed for generating type information
+    initProc*: BProc          # code for init procedure
+    postInitProc*: BProc      # code to be executed after the init proc
+    preInitProc*: BProc       # code executed before the init proc
+    typeStack*: TTypeSeq      # used for type generation
+    dataCache*: TNodeTable
+    forwardedProcs*: TSymSeq  # keep forwarded procs here
+    typeNodes*, nimTypes*: int # used for type info generation
+    typeNodesName*, nimTypesName*: Rope # used for type info generation
+    labels*: Natural          # for generating unique module-scope names
+    extensionLoaders*: array['0'..'9', Rope] # special procs for the
+                                              # OpenGL wrapper
+    injectStmt*: Rope
+
+var
+  mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
+    # varuious parts of the main module
+  gMapping*: Rope             # the generated mapping file (if requested)
+  gModules*: seq[BModule] = @[] # list of all compiled modules
+  gForwardedProcsCounter*: int = 0
+
+proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
+  # section in the current block
+  result = p.blocks[p.blocks.len - 1].sections[s]
+
+proc procSec*(p: BProc, s: TCProcSection): var Rope {.inline.} =
+  # top level proc sections
+  result = p.blocks[0].sections[s]
+
+proc bmod*(module: PSym): BModule =
+  # obtains the BModule for a given module PSym
+  result = gModules[module.position]
+
+proc newProc*(prc: PSym, module: BModule): BProc =
+  new(result)
+  result.prc = prc
+  result.module = module
+  if prc != nil: result.options = prc.options
+  else: result.options = gOptions
+  newSeq(result.blocks, 1)
+  result.nestedTryStmts = @[]
+  result.finallySafePoints = @[]
+
+iterator cgenModules*: BModule =
+  for i in 0..high(gModules):
+    # ultimately, we are iterating over the file ids here.
+    # some "files" won't have an associated cgen module (like stdin)
+    # and we must skip over them.
+    if gModules[i] != nil: yield gModules[i]
+
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
new file mode 100644
index 000000000..6c997b983
--- /dev/null
+++ b/compiler/cgmeth.nim
@@ -0,0 +1,242 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements code generation for multi methods.
+
+import 
+  intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
+  sempass2, strutils
+
+proc genConv(n: PNode, d: PType, downcast: bool): PNode = 
+  var dest = skipTypes(d, abstractPtrs)
+  var source = skipTypes(n.typ, abstractPtrs)
+  if (source.kind == tyObject) and (dest.kind == tyObject): 
+    var diff = inheritanceDiff(dest, source)
+    if diff == high(int): internalError(n.info, "cgmeth.genConv")
+    if diff < 0: 
+      result = newNodeIT(nkObjUpConv, n.info, d)
+      addSon(result, n)
+      if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
+    elif diff > 0: 
+      result = newNodeIT(nkObjDownConv, n.info, d)
+      addSon(result, n)
+      if not downcast: 
+        internalError(n.info, "cgmeth.genConv: no downcast allowed")
+    else: 
+      result = n
+  else: 
+    result = n
+  
+proc methodCall*(n: PNode): PNode = 
+  result = n
+  # replace ordinary method by dispatcher method: 
+  var disp = lastSon(result.sons[0].sym.ast).sym
+  assert sfDispatcher in disp.flags
+  result.sons[0].sym = disp
+  # change the arguments to up/downcasts to fit the dispatcher's parameters:
+  for i in countup(1, sonsLen(result)-1):
+    result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true)
+
+# save for incremental compilation:
+var
+  gMethods: seq[tuple[methods: TSymSeq, dispatcher: PSym]] = @[]
+
+proc sameMethodBucket(a, b: PSym): bool = 
+  result = false
+  if a.name.id != b.name.id: return 
+  if sonsLen(a.typ) != sonsLen(b.typ): 
+    return                    # check for return type:
+  if not sameTypeOrNil(a.typ.sons[0], b.typ.sons[0]): return 
+  for i in countup(1, sonsLen(a.typ) - 1): 
+    var aa = a.typ.sons[i]
+    var bb = b.typ.sons[i]
+    while true: 
+      aa = skipTypes(aa, {tyGenericInst})
+      bb = skipTypes(bb, {tyGenericInst})
+      if (aa.kind == bb.kind) and (aa.kind in {tyVar, tyPtr, tyRef}): 
+        aa = aa.lastSon
+        bb = bb.lastSon
+      else: 
+        break 
+    if sameType(aa, bb) or
+        (aa.kind == tyObject) and (bb.kind == tyObject) and
+        (inheritanceDiff(bb, aa) < 0):
+      discard
+    else:
+      return
+  result = true
+
+proc attachDispatcher(s: PSym, dispatcher: PNode) =
+  var L = s.ast.len-1
+  var x = s.ast.sons[L]
+  if x.kind == nkSym and sfDispatcher in x.sym.flags:
+    # we've added a dispatcher already, so overwrite it
+    s.ast.sons[L] = dispatcher
+  else:
+    s.ast.add(dispatcher)
+
+proc createDispatcher(s: PSym): PSym =
+  var disp = copySym(s)
+  incl(disp.flags, sfDispatcher)
+  excl(disp.flags, sfExported)
+  disp.typ = copyType(disp.typ, disp.typ.owner, false)
+  # we can't inline the dispatcher itself (for now):
+  if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
+  disp.ast = copyTree(s.ast)
+  disp.ast.sons[bodyPos] = ast.emptyNode
+  disp.loc.r = nil
+  if s.typ.sons[0] != nil:
+    if disp.ast.sonsLen > resultPos:
+      disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym)
+    else:
+      # We've encountered a method prototype without a filled-in
+      # resultPos slot. We put a placeholder in there that will
+      # be updated in fixupDispatcher().
+      disp.ast.addSon(ast.emptyNode)
+  attachDispatcher(s, newSymNode(disp))
+  # attach to itself to prevent bugs:
+  attachDispatcher(disp, newSymNode(disp))
+  return disp
+
+proc fixupDispatcher(meth, disp: PSym) =
+  # We may have constructed the dispatcher from a method prototype
+  # and need to augment the incomplete dispatcher with information
+  # from later definitions, particularly the resultPos slot. Also,
+  # the lock level of the dispatcher needs to be updated/checked
+  # against that of the method.
+  if disp.ast.sonsLen > resultPos and meth.ast.sonsLen > resultPos and
+     disp.ast.sons[resultPos] == ast.emptyNode:
+    disp.ast.sons[resultPos] = copyTree(meth.ast.sons[resultPos])
+
+  # The following code works only with lock levels, so we disable
+  # it when they're not available.
+  when declared(TLockLevel):
+    proc `<`(a, b: TLockLevel): bool {.borrow.}
+    proc `==`(a, b: TLockLevel): bool {.borrow.}
+    if disp.typ.lockLevel == UnspecifiedLockLevel:
+      disp.typ.lockLevel = meth.typ.lockLevel
+    elif meth.typ.lockLevel != UnspecifiedLockLevel and
+         meth.typ.lockLevel != disp.typ.lockLevel:
+      message(meth.info, warnLockLevel,
+        "method has lock level $1, but another method has $2" %
+        [$meth.typ.lockLevel, $disp.typ.lockLevel])
+      # XXX The following code silences a duplicate warning in
+      # checkMethodeffects() in sempass2.nim for now.
+      if disp.typ.lockLevel < meth.typ.lockLevel:
+        disp.typ.lockLevel = meth.typ.lockLevel
+
+proc methodDef*(s: PSym, fromCache: bool) =
+  var L = len(gMethods)
+  for i in countup(0, L - 1):
+    var disp = gMethods[i].dispatcher
+    if sameMethodBucket(disp, s):
+      add(gMethods[i].methods, s)
+      attachDispatcher(s, lastSon(disp.ast))
+      fixupDispatcher(s, disp)
+      when useEffectSystem: checkMethodEffects(disp, s)
+      return 
+  # create a new dispatcher:
+  add(gMethods, (methods: @[s], dispatcher: createDispatcher(s)))
+  if fromCache:
+    internalError(s.info, "no method dispatcher found")
+
+proc relevantCol(methods: TSymSeq, col: int): bool =
+  # returns true iff the position is relevant
+  var t = methods[0].typ.sons[col].skipTypes(skipPtrs)
+  if t.kind == tyObject:
+    for i in countup(1, high(methods)):
+      let t2 = skipTypes(methods[i].typ.sons[col], skipPtrs)
+      if not sameType(t2, t):
+        return true
+  
+proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int = 
+  for col in countup(1, sonsLen(a.typ) - 1): 
+    if contains(relevantCols, col): 
+      var aa = skipTypes(a.typ.sons[col], skipPtrs)
+      var bb = skipTypes(b.typ.sons[col], skipPtrs)
+      var d = inheritanceDiff(aa, bb)
+      if (d != high(int)): 
+        return d
+  
+proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = 
+  # we use shellsort here; fast and simple
+  var n = len(a)
+  var h = 1
+  while true: 
+    h = 3 * h + 1
+    if h > n: break 
+  while true: 
+    h = h div 3
+    for i in countup(h, n - 1): 
+      var v = a[i]
+      var j = i
+      while cmpSignatures(a[j - h], v, relevantCols) >= 0: 
+        a[j] = a[j - h]
+        j = j - h
+        if j < h: break 
+      a[j] = v
+    if h == 1: break 
+  
+proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
+  var base = lastSon(methods[0].ast).sym
+  result = base
+  var paramLen = sonsLen(base.typ)
+  var disp = newNodeI(nkIfStmt, base.info)
+  var ands = getSysSym("and")
+  var iss = getSysSym("of")
+  for meth in countup(0, high(methods)):
+    var curr = methods[meth]      # generate condition:
+    var cond: PNode = nil
+    for col in countup(1, paramLen - 1):
+      if contains(relevantCols, col):
+        var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
+        addSon(isn, newSymNode(iss))
+        addSon(isn, newSymNode(base.typ.n.sons[col].sym))
+        addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
+        if cond != nil: 
+          var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
+          addSon(a, newSymNode(ands))
+          addSon(a, cond)
+          addSon(a, isn)
+          cond = a
+        else:
+          cond = isn
+    var call = newNodeI(nkCall, base.info)
+    addSon(call, newSymNode(curr))
+    for col in countup(1, paramLen - 1): 
+      addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym), 
+                           curr.typ.sons[col], false))
+    var ret: PNode
+    if base.typ.sons[0] != nil:
+      var a = newNodeI(nkAsgn, base.info)
+      addSon(a, newSymNode(base.ast.sons[resultPos].sym))
+      addSon(a, call)
+      ret = newNodeI(nkReturnStmt, base.info)
+      addSon(ret, a)
+    else:
+      ret = call
+    if cond != nil:
+      var a = newNodeI(nkElifBranch, base.info)
+      addSon(a, cond)
+      addSon(a, ret)
+      addSon(disp, a)
+    else:
+      disp = ret
+  result.ast.sons[bodyPos] = disp
+
+proc generateMethodDispatchers*(): PNode = 
+  result = newNode(nkStmtList)
+  for bucket in countup(0, len(gMethods) - 1): 
+    var relevantCols = initIntSet()
+    for col in countup(1, sonsLen(gMethods[bucket].methods[0].typ) - 1): 
+      if relevantCol(gMethods[bucket].methods, col): incl(relevantCols, col)
+    sortBucket(gMethods[bucket].methods, relevantCols)
+    addSon(result,
+           newSymNode(genDispatcher(gMethods[bucket].methods, relevantCols)))
+
diff --git a/compiler/commands.nim b/compiler/commands.nim
new file mode 100644
index 000000000..d30d8326c
--- /dev/null
+++ b/compiler/commands.nim
@@ -0,0 +1,621 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module handles the parsing of command line arguments.
+
+
+# We do this here before the 'import' statement so 'defined' does not get
+# confused with 'TGCMode.gcGenerational' etc.
+template bootSwitch(name, expr, userString: expr): expr =
+  # Helper to build boot constants, for debugging you can 'echo' the else part.
+  const name = if expr: " " & userString else: ""
+
+bootSwitch(usedRelease, defined(release), "-d:release")
+bootSwitch(usedGnuReadline, defined(useGnuReadline), "-d:useGnuReadline")
+bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas")
+bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm")
+bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep")
+bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational")
+bootSwitch(usedNoGC, defined(nogc), "--gc:none")
+
+import
+  os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
+  wordrecg, parseutils, nimblecmd, idents, parseopt
+
+# but some have deps to imported modules. Yay.
+bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
+bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine")
+bootSwitch(usedNativeStacktrace,
+  defined(nativeStackTrace) and nativeStackTraceSupported,
+  "-d:nativeStackTrace")
+bootSwitch(usedFFI, hasFFI, "-d:useFFI")
+
+
+proc writeCommandLineUsage*()
+
+type
+  TCmdLinePass* = enum
+    passCmd1,                 # first pass over the command line
+    passCmd2,                 # second pass over the command line
+    passPP                    # preprocessor called processCommand()
+
+proc processCommand*(switch: string, pass: TCmdLinePass)
+proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
+
+# implementation
+
+const
+  HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
+      "Copyright (c) 2006-2015 by Andreas Rumpf\n"
+
+const
+  Usage = slurp"doc/basicopt.txt".replace("//", "")
+  AdvancedUsage = slurp"doc/advopt.txt".replace("//", "")
+
+proc getCommandLineDesc(): string =
+  result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name,
+                           CPU[platform.hostCPU].name]) & Usage
+
+proc helpOnError(pass: TCmdLinePass) =
+  if pass == passCmd1:
+    msgWriteln(getCommandLineDesc())
+    msgQuit(0)
+
+proc writeAdvancedUsage(pass: TCmdLinePass) =
+  if pass == passCmd1:
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
+                                 CPU[platform.hostCPU].name]) & AdvancedUsage)
+    msgQuit(0)
+
+proc writeVersionInfo(pass: TCmdLinePass) =
+  if pass == passCmd1:
+    msgWriteln(`%`(HelpMessage, [VersionAsString,
+                                 platform.OS[platform.hostOS].name,
+                                 CPU[platform.hostCPU].name]))
+
+    const gitHash = gorge("git log -n 1 --format=%H").strip
+    when gitHash.len == 40:
+      msgWriteln("git hash: " & gitHash)
+
+    msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine &
+      usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas &
+      usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedNoGC)
+    msgQuit(0)
+
+var
+  helpWritten: bool
+
+proc writeCommandLineUsage() =
+  if not helpWritten:
+    msgWriteln(getCommandLineDesc())
+    helpWritten = true
+
+proc addPrefix(switch: string): string =
+  if len(switch) == 1: result = "-" & switch
+  else: result = "--" & switch
+
+proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) =
+  if switch == " ": localError(info, errInvalidCmdLineOption, "-")
+  else: localError(info, errInvalidCmdLineOption, addPrefix(switch))
+
+proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass,
+                 info: TLineInfo) =
+  cmd = ""
+  var i = 0
+  if i < len(switch) and switch[i] == '-': inc(i)
+  if i < len(switch) and switch[i] == '-': inc(i)
+  while i < len(switch):
+    case switch[i]
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_', '.': add(cmd, switch[i])
+    else: break
+    inc(i)
+  if i >= len(switch): arg = ""
+  elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1)
+  else: invalidCmdLineOption(pass, switch, info)
+
+proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass,
+                        info: TLineInfo) =
+  case whichKeyword(arg)
+  of wOn: gOptions = gOptions + op
+  of wOff: gOptions = gOptions - op
+  else: localError(info, errOnOrOffExpectedButXFound, arg)
+
+proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass,
+                         info: TLineInfo) =
+  case whichKeyword(arg)
+  of wOn: gGlobalOptions = gGlobalOptions + op
+  of wOff: gGlobalOptions = gGlobalOptions - op
+  else: localError(info, errOnOrOffExpectedButXFound, arg)
+
+proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch))
+
+proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
+
+proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
+                         info: TLineInfo; orig: string) =
+  var id = ""  # arg = "X]:on|off"
+  var i = 0
+  var n = hintMin
+  while i < len(arg) and (arg[i] != ']'):
+    add(id, arg[i])
+    inc(i)
+  if i < len(arg) and (arg[i] == ']'): inc(i)
+  else: invalidCmdLineOption(pass, orig, info)
+  if i < len(arg) and (arg[i] in {':', '='}): inc(i)
+  else: invalidCmdLineOption(pass, orig, info)
+  if state == wHint:
+    var x = findStr(msgs.HintsToStr, id)
+    if x >= 0: n = TNoteKind(x + ord(hintMin))
+    else: localError(info, "unknown hint: " & id)
+  else:
+    var x = findStr(msgs.WarningsToStr, id)
+    if x >= 0: n = TNoteKind(x + ord(warnMin))
+    else: localError(info, "unknown warning: " & id)
+  case whichKeyword(substr(arg, i))
+  of wOn: incl(gNotes, n)
+  of wOff: excl(gNotes, n)
+  else: localError(info, errOnOrOffExpectedButXFound, arg)
+
+proc processCompile(filename: string) =
+  var found = findFile(filename)
+  if found == "": found = filename
+  var trunc = changeFileExt(found, "")
+  extccomp.addExternalFileToCompile(found)
+  extccomp.addFileToLink(completeCFilePath(trunc, false))
+
+proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool =
+  case switch.normalize
+  of "gc":
+    case arg.normalize
+    of "boehm":        result = gSelectedGC == gcBoehm
+    of "refc":         result = gSelectedGC == gcRefc
+    of "v2":           result = gSelectedGC == gcV2
+    of "markandsweep": result = gSelectedGC == gcMarkAndSweep
+    of "generational": result = gSelectedGC == gcGenerational
+    of "none":         result = gSelectedGC == gcNone
+    else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
+  of "opt":
+    case arg.normalize
+    of "speed": result = contains(gOptions, optOptimizeSpeed)
+    of "size": result = contains(gOptions, optOptimizeSize)
+    of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {}
+    else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
+  else: invalidCmdLineOption(passCmd1, switch, info)
+
+proc testCompileOption*(switch: string, info: TLineInfo): bool =
+  case switch.normalize
+  of "debuginfo": result = contains(gGlobalOptions, optCDebug)
+  of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly)
+  of "nolinking": result = contains(gGlobalOptions, optNoLinking)
+  of "nomain": result = contains(gGlobalOptions, optNoMain)
+  of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake)
+  of "warnings", "w": result = contains(gOptions, optWarns)
+  of "hints": result = contains(gOptions, optHints)
+  of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis)
+  of "stacktrace": result = contains(gOptions, optStackTrace)
+  of "linetrace": result = contains(gOptions, optLineTrace)
+  of "debugger": result = contains(gOptions, optEndb)
+  of "profiler": result = contains(gOptions, optProfiler)
+  of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions
+  of "floatchecks":
+    result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck}
+  of "infchecks": result = contains(gOptions, optInfCheck)
+  of "nanchecks": result = contains(gOptions, optNaNCheck)
+  of "objchecks": result = contains(gOptions, optObjCheck)
+  of "fieldchecks": result = contains(gOptions, optFieldCheck)
+  of "rangechecks": result = contains(gOptions, optRangeCheck)
+  of "boundchecks": result = contains(gOptions, optBoundsCheck)
+  of "overflowchecks": result = contains(gOptions, optOverflowCheck)
+  of "linedir": result = contains(gOptions, optLineDir)
+  of "assertions", "a": result = contains(gOptions, optAssert)
+  of "deadcodeelim": result = contains(gGlobalOptions, optDeadCodeElim)
+  of "run", "r": result = contains(gGlobalOptions, optRun)
+  of "symbolfiles": result = contains(gGlobalOptions, optSymbolFiles)
+  of "genscript": result = contains(gGlobalOptions, optGenScript)
+  of "threads": result = contains(gGlobalOptions, optThreads)
+  of "taintmode": result = contains(gGlobalOptions, optTaintMode)
+  of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
+  of "implicitstatic": result = contains(gOptions, optImplicitStatic)
+  of "patterns": result = contains(gOptions, optPatterns)
+  of "experimental": result = gExperimentalMode
+  else: invalidCmdLineOption(passCmd1, switch, info)
+
+proc processPath(path: string, notRelativeToProj = false,
+                               cfginfo = unknownLineInfo()): string =
+  let p = if notRelativeToProj or os.isAbsolute(path) or
+              '$' in path or path[0] == '.':
+            path
+          else:
+            options.gProjectPath / path
+  result = unixToNativePath(p % ["nimrod", getPrefixDir(),
+    "nim", getPrefixDir(),
+    "lib", libpath,
+    "home", removeTrailingDirSep(os.getHomeDir()),
+    "config", cfginfo.toFullPath().splitFile().dir,
+    "projectname", options.gProjectName,
+    "projectpath", options.gProjectPath])
+
+proc trackDirty(arg: string, info: TLineInfo) =
+  var a = arg.split(',')
+  if a.len != 4: localError(info, errTokenExpected,
+                            "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN")
+  var line, column: int
+  if parseUtils.parseInt(a[2], line) <= 0:
+    localError(info, errInvalidNumber, a[1])
+  if parseUtils.parseInt(a[3], column) <= 0:
+    localError(info, errInvalidNumber, a[2])
+
+  let dirtyOriginalIdx = a[1].fileInfoIdx
+  if dirtyOriginalIdx >= 0:
+    msgs.setDirtyFile(dirtyOriginalIdx, a[0])
+
+  gTrackPos = newLineInfo(dirtyOriginalIdx, line, column)
+
+proc track(arg: string, info: TLineInfo) =
+  var a = arg.split(',')
+  if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN")
+  var line, column: int
+  if parseUtils.parseInt(a[1], line) <= 0:
+    localError(info, errInvalidNumber, a[1])
+  if parseUtils.parseInt(a[2], column) <= 0:
+    localError(info, errInvalidNumber, a[2])
+  gTrackPos = newLineInfo(a[0], line, column)
+
+proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  if pass in {passCmd2, passPP}:
+    expectArg(switch, arg, pass, info)
+    options.inclDynlibOverride(arg)
+
+proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
+  var
+    theOS: TSystemOS
+    cpu: TSystemCPU
+    key, val: string
+  case switch.normalize
+  of "path", "p":
+    expectArg(switch, arg, pass, info)
+    addPath(processPath(arg, cfginfo=info), info)
+  of "nimblepath", "babelpath":
+    # keep the old name for compat
+    if pass in {passCmd2, passPP} and not options.gNoNimblePath:
+      expectArg(switch, arg, pass, info)
+      let path = processPath(arg, notRelativeToProj=true)
+      nimblePath(path, info)
+  of "nonimblepath", "nobabelpath":
+    expectNoArg(switch, arg, pass, info)
+    options.gNoNimblePath = true
+  of "excludepath":
+    expectArg(switch, arg, pass, info)
+    let path = processPath(arg)
+    lists.excludePath(options.searchPaths, path)
+    lists.excludePath(options.lazyPaths, path)
+    if (len(path) > 0) and (path[len(path) - 1] == DirSep):
+      let strippedPath = path[0 .. (len(path) - 2)]
+      lists.excludePath(options.searchPaths, strippedPath)
+      lists.excludePath(options.lazyPaths, strippedPath)
+  of "nimcache":
+    expectArg(switch, arg, pass, info)
+    options.nimcacheDir = processPath(arg)
+  of "out", "o":
+    expectArg(switch, arg, pass, info)
+    options.outFile = arg
+  of "docseesrcurl":
+    expectArg(switch, arg, pass, info)
+    options.docSeeSrcUrl = arg
+  of "mainmodule", "m":
+    discard "allow for backwards compatibility, but don't do anything"
+  of "define", "d":
+    expectArg(switch, arg, pass, info)
+    defineSymbol(arg)
+  of "undef", "u":
+    expectArg(switch, arg, pass, info)
+    undefSymbol(arg)
+  of "symbol":
+    expectArg(switch, arg, pass, info)
+    # deprecated, do nothing
+  of "compile":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: processCompile(arg)
+  of "link":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: addFileToLink(arg)
+  of "debuginfo":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optCDebug)
+  of "embedsrc":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optEmbedOrigSrc)
+  of "compileonly", "c":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optCompileOnly)
+  of "nolinking":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optNoLinking)
+  of "nomain":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optNoMain)
+  of "forcebuild", "f":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optForceFullMake)
+  of "project":
+    expectNoArg(switch, arg, pass, info)
+    gWholeProject = true
+  of "gc":
+    expectArg(switch, arg, pass, info)
+    case arg.normalize
+    of "boehm":
+      gSelectedGC = gcBoehm
+      defineSymbol("boehmgc")
+    of "refc":
+      gSelectedGC = gcRefc
+    of "v2":
+      gSelectedGC = gcV2
+    of "markandsweep":
+      gSelectedGC = gcMarkAndSweep
+      defineSymbol("gcmarkandsweep")
+    of "generational":
+      gSelectedGC = gcGenerational
+      defineSymbol("gcgenerational")
+    of "none":
+      gSelectedGC = gcNone
+      defineSymbol("nogc")
+    else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
+  of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
+  of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
+  of "hint": processSpecificNote(arg, wHint, pass, info, switch)
+  of "hints": processOnOffSwitch({optHints}, arg, pass, info)
+  of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
+  of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
+  of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
+  of "debugger":
+    case arg.normalize
+    of "on", "endb":
+      gOptions.incl optEndb
+      defineSymbol("endb")
+    of "off":
+      gOptions.excl optEndb
+      undefSymbol("endb")
+    of "native", "gdb":
+      incl(gGlobalOptions, optCDebug)
+      gOptions = gOptions + {optLineDir} - {optEndb}
+      undefSymbol("endb")
+    else:
+      localError(info, "expected endb|gdb but found " & arg)
+  of "profiler":
+    processOnOffSwitch({optProfiler}, arg, pass, info)
+    if optProfiler in gOptions: defineSymbol("profiler")
+    else: undefSymbol("profiler")
+  of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info)
+  of "floatchecks":
+    processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info)
+  of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info)
+  of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info)
+  of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info)
+  of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info)
+  of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info)
+  of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info)
+  of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info)
+  of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info)
+  of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info)
+  of "deadcodeelim": processOnOffSwitchG({optDeadCodeElim}, arg, pass, info)
+  of "threads":
+    processOnOffSwitchG({optThreads}, arg, pass, info)
+    #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe)
+  of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info)
+  of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info)
+  of "implicitstatic":
+    processOnOffSwitch({optImplicitStatic}, arg, pass, info)
+  of "patterns":
+    processOnOffSwitch({optPatterns}, arg, pass, info)
+  of "opt":
+    expectArg(switch, arg, pass, info)
+    case arg.normalize
+    of "speed":
+      incl(gOptions, optOptimizeSpeed)
+      excl(gOptions, optOptimizeSize)
+    of "size":
+      excl(gOptions, optOptimizeSpeed)
+      incl(gOptions, optOptimizeSize)
+    of "none":
+      excl(gOptions, optOptimizeSpeed)
+      excl(gOptions, optOptimizeSize)
+    else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg)
+  of "app":
+    expectArg(switch, arg, pass, info)
+    case arg.normalize
+    of "gui":
+      incl(gGlobalOptions, optGenGuiApp)
+      defineSymbol("executable")
+      defineSymbol("guiapp")
+    of "console":
+      excl(gGlobalOptions, optGenGuiApp)
+      defineSymbol("executable")
+      defineSymbol("consoleapp")
+    of "lib":
+      incl(gGlobalOptions, optGenDynLib)
+      excl(gGlobalOptions, optGenGuiApp)
+      defineSymbol("library")
+      defineSymbol("dll")
+    of "staticlib":
+      incl(gGlobalOptions, optGenStaticLib)
+      excl(gGlobalOptions, optGenGuiApp)
+      defineSymbol("library")
+      defineSymbol("staticlib")
+    else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg)
+  of "passc", "t":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: extccomp.addCompileOption(arg)
+  of "passl", "l":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: extccomp.addLinkOption(arg)
+  of "cincludes":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: cIncludes.add arg.processPath
+  of "clibdir":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: cLibs.add arg.processPath
+  of "clib":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath
+  of "header":
+    headerFile = arg
+    incl(gGlobalOptions, optGenIndex)
+  of "index":
+    processOnOffSwitchG({optGenIndex}, arg, pass, info)
+  of "import":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: implicitImports.add arg
+  of "include":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd2, passPP}: implicitIncludes.add arg
+  of "listcmd":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optListCmd)
+  of "genmapping":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optGenMapping)
+  of "os":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd1, passPP}:
+      theOS = platform.nameToOS(arg)
+      if theOS == osNone: localError(info, errUnknownOS, arg)
+      elif theOS != platform.hostOS:
+        setTarget(theOS, targetCPU)
+  of "cpu":
+    expectArg(switch, arg, pass, info)
+    if pass in {passCmd1, passPP}:
+      cpu = platform.nameToCPU(arg)
+      if cpu == cpuNone: localError(info, errUnknownCPU, arg)
+      elif cpu != platform.hostCPU:
+        setTarget(targetOS, cpu)
+  of "run", "r":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optRun)
+  of "verbosity":
+    expectArg(switch, arg, pass, info)
+    gVerbosity = parseInt(arg)
+  of "parallelbuild":
+    expectArg(switch, arg, pass, info)
+    gNumberOfProcessors = parseInt(arg)
+  of "version", "v":
+    expectNoArg(switch, arg, pass, info)
+    writeVersionInfo(pass)
+  of "advanced":
+    expectNoArg(switch, arg, pass, info)
+    writeAdvancedUsage(pass)
+  of "help", "h":
+    expectNoArg(switch, arg, pass, info)
+    helpOnError(pass)
+  of "symbolfiles":
+    processOnOffSwitchG({optSymbolFiles}, arg, pass, info)
+  of "skipcfg":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optSkipConfigFile)
+  of "skipprojcfg":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optSkipProjConfigFile)
+  of "skipusercfg":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optSkipUserConfigFile)
+  of "skipparentcfg":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optSkipParentConfigFiles)
+  of "genscript":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optGenScript)
+  of "lib":
+    expectArg(switch, arg, pass, info)
+    libpath = processPath(arg, notRelativeToProj=true)
+  of "putenv":
+    expectArg(switch, arg, pass, info)
+    splitSwitch(arg, key, val, pass, info)
+    os.putEnv(key, val)
+  of "cc":
+    expectArg(switch, arg, pass, info)
+    setCC(arg)
+  of "track":
+    expectArg(switch, arg, pass, info)
+    track(arg, info)
+  of "trackdirty":
+    expectArg(switch, arg, pass, info)
+    trackDirty(arg, info)
+  of "suggest":
+    expectNoArg(switch, arg, pass, info)
+    gIdeCmd = ideSug
+  of "def":
+    expectNoArg(switch, arg, pass, info)
+    gIdeCmd = ideDef
+  of "eval":
+    expectArg(switch, arg, pass, info)
+    gEvalExpr = arg
+  of "context":
+    expectNoArg(switch, arg, pass, info)
+    gIdeCmd = ideCon
+  of "usages":
+    expectNoArg(switch, arg, pass, info)
+    gIdeCmd = ideUse
+  of "stdout":
+    expectNoArg(switch, arg, pass, info)
+    incl(gGlobalOptions, optStdout)
+  of "listfullpaths":
+    expectNoArg(switch, arg, pass, info)
+    gListFullPaths = true
+  of "dynliboverride":
+    dynlibOverride(switch, arg, pass, info)
+  of "cs":
+    expectArg(switch, arg, pass, info)
+    case arg
+    of "partial": idents.firstCharIsCS = true
+    of "none": idents.firstCharIsCS = false
+    else: localError(info, errGenerated,
+      "'partial' or 'none' expected, but found " & arg)
+  of "experimental":
+    expectNoArg(switch, arg, pass, info)
+    gExperimentalMode = true
+  else:
+    if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
+    else: invalidCmdLineOption(pass, switch, info)
+
+proc processCommand(switch: string, pass: TCmdLinePass) =
+  var cmd, arg: string
+  splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
+  processSwitch(cmd, arg, pass, gCmdLineInfo)
+
+
+var
+  arguments* = ""
+    # the arguments to be passed to the program that
+    # should be run
+
+proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
+  # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
+  # we fix this here
+  var bracketLe = strutils.find(p.key, '[')
+  if bracketLe >= 0:
+    var key = substr(p.key, 0, bracketLe - 1)
+    var val = substr(p.key, bracketLe + 1) & ':' & p.val
+    processSwitch(key, val, pass, gCmdLineInfo)
+  else:
+    processSwitch(p.key, p.val, pass, gCmdLineInfo)
+
+proc processArgument*(pass: TCmdLinePass; p: OptParser;
+                      argsCount: var int): bool =
+  if argsCount == 0:
+    options.command = p.key
+  else:
+    if pass == passCmd1: options.commandArgs.add p.key
+    if argsCount == 1:
+      # support UNIX style filenames anywhere for portable build scripts:
+      options.gProjectName = unixToNativePath(p.key)
+      arguments = cmdLineRest(p)
+      result = true
+  inc argsCount
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
new file mode 100644
index 000000000..ad7d80c85
--- /dev/null
+++ b/compiler/condsyms.nim
@@ -0,0 +1,90 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module handles the conditional symbols.
+
+import
+  strtabs, platform, strutils, idents
+
+# We need to use a StringTableRef here as defined symbols are always guaranteed
+# to be style insensitive. Otherwise hell would break lose.
+var gSymbols: StringTableRef
+
+const
+  catNone = "false"
+
+proc defineSymbol*(symbol: string) =
+  gSymbols[symbol] = "true"
+
+proc undefSymbol*(symbol: string) =
+  gSymbols[symbol] = catNone
+
+proc isDefined*(symbol: string): bool =
+  if gSymbols.hasKey(symbol):
+    result = gSymbols[symbol] != catNone
+  elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
+    result = true
+  elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
+    result = true
+  else:
+    case symbol.normalize
+    of "x86": result = targetCPU == cpuI386
+    of "itanium": result = targetCPU == cpuIa64
+    of "x8664": result = targetCPU == cpuAmd64
+    of "posix", "unix":
+      result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
+                            osQnx, osAtari, osAix,
+                            osHaiku, osVxWorks, osSolaris, osNetbsd,
+                            osFreebsd, osOpenbsd, osMacosx}
+    of "bsd":
+      result = targetOS in {osNetbsd, osFreebsd, osOpenbsd}
+    of "emulatedthreadvars":
+      result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
+    of "msdos": result = targetOS == osDos
+    of "mswindows", "win32": result = targetOS == osWindows
+    of "macintosh": result = targetOS in {osMacos, osMacosx}
+    of "sunos": result = targetOS == osSolaris
+    of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
+    of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
+    of "cpu8": result = CPU[targetCPU].bit == 8
+    of "cpu16": result = CPU[targetCPU].bit == 16
+    of "cpu32": result = CPU[targetCPU].bit == 32
+    of "cpu64": result = CPU[targetCPU].bit == 64
+    of "nimrawsetjmp":
+      result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd, osMacosx}
+    else: discard
+
+proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
+
+iterator definedSymbolNames*: string =
+  for key, val in pairs(gSymbols):
+    if val != catNone: yield key
+
+proc countDefinedSymbols*(): int =
+  result = 0
+  for key, val in pairs(gSymbols):
+    if val != catNone: inc(result)
+
+proc initDefines*() =
+  gSymbols = newStringTable(modeStyleInsensitive)
+  defineSymbol("nimrod") # 'nimrod' is always defined
+  # for bootstrapping purposes and old code:
+  defineSymbol("nimhygiene")
+  defineSymbol("niminheritable")
+  defineSymbol("nimmixin")
+  defineSymbol("nimeffects")
+  defineSymbol("nimbabel")
+  defineSymbol("nimcomputedgoto")
+  defineSymbol("nimunion")
+  defineSymbol("nimnewshared")
+  defineSymbol("nimrequiresnimframe")
+  defineSymbol("nimparsebiggestfloatmagic")
+  defineSymbol("nimalias")
+  defineSymbol("nimlocks")
+  defineSymbol("nimnode")
diff --git a/compiler/crc.nim b/compiler/crc.nim
new file mode 100644
index 000000000..a8b61f2a5
--- /dev/null
+++ b/compiler/crc.nim
@@ -0,0 +1,147 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import 
+  strutils
+
+type 
+  TCrc32* = int32
+
+const 
+  InitCrc32* = TCrc32(- 1)
+  InitAdler32* = int32(1)
+
+proc updateCrc32*(val: int8, crc: TCrc32): TCrc32 {.inline.}
+proc updateCrc32*(val: char, crc: TCrc32): TCrc32 {.inline.}
+proc crcFromBuf*(buf: pointer, length: int): TCrc32
+proc strCrc32*(s: string): TCrc32
+proc crcFromFile*(filename: string): TCrc32
+proc updateAdler32*(adler: int32, buf: pointer, length: int): int32
+# implementation
+
+type 
+  TCRC_TabEntry = int
+
+const 
+  crc32table: array[0..255, TCRC_TabEntry] = [0, 1996959894, - 301047508, 
+    - 1727442502, 124634137, 1886057615, - 379345611, - 1637575261, 249268274, 
+    2044508324, - 522852066, - 1747789432, 162941995, 2125561021, - 407360249, 
+    - 1866523247, 498536548, 1789927666, - 205950648, - 2067906082, 450548861, 
+    1843258603, - 187386543, - 2083289657, 325883990, 1684777152, - 43845254, 
+    - 1973040660, 335633487, 1661365465, - 99664541, - 1928851979, 997073096, 
+    1281953886, - 715111964, - 1570279054, 1006888145, 1258607687, - 770865667, 
+    - 1526024853, 901097722, 1119000684, - 608450090, - 1396901568, 853044451, 
+    1172266101, - 589951537, - 1412350631, 651767980, 1373503546, - 925412992, 
+    - 1076862698, 565507253, 1454621731, - 809855591, - 1195530993, 671266974, 
+    1594198024, - 972236366, - 1324619484, 795835527, 1483230225, - 1050600021, 
+    - 1234817731, 1994146192, 31158534, - 1731059524, - 271249366, 1907459465, 
+    112637215, - 1614814043, - 390540237, 2013776290, 251722036, - 1777751922, 
+    - 519137256, 2137656763, 141376813, - 1855689577, - 429695999, 1802195444, 
+    476864866, - 2056965928, - 228458418, 1812370925, 453092731, - 2113342271, 
+    - 183516073, 1706088902, 314042704, - 1950435094, - 54949764, 1658658271, 
+    366619977, - 1932296973, - 69972891, 1303535960, 984961486, - 1547960204, 
+    - 725929758, 1256170817, 1037604311, - 1529756563, - 740887301, 1131014506, 
+    879679996, - 1385723834, - 631195440, 1141124467, 855842277, - 1442165665, 
+    - 586318647, 1342533948, 654459306, - 1106571248, - 921952122, 1466479909, 
+    544179635, - 1184443383, - 832445281, 1591671054, 702138776, - 1328506846, 
+    - 942167884, 1504918807, 783551873, - 1212326853, - 1061524307, - 306674912, 
+    - 1698712650, 62317068, 1957810842, - 355121351, - 1647151185, 81470997, 
+    1943803523, - 480048366, - 1805370492, 225274430, 2053790376, - 468791541, 
+    - 1828061283, 167816743, 2097651377, - 267414716, - 2029476910, 503444072, 
+    1762050814, - 144550051, - 2140837941, 426522225, 1852507879, - 19653770, 
+    - 1982649376, 282753626, 1742555852, - 105259153, - 1900089351, 397917763, 
+    1622183637, - 690576408, - 1580100738, 953729732, 1340076626, - 776247311, 
+    - 1497606297, 1068828381, 1219638859, - 670225446, - 1358292148, 906185462, 
+    1090812512, - 547295293, - 1469587627, 829329135, 1181335161, - 882789492, 
+    - 1134132454, 628085408, 1382605366, - 871598187, - 1156888829, 570562233, 
+    1426400815, - 977650754, - 1296233688, 733239954, 1555261956, - 1026031705, 
+    - 1244606671, 752459403, 1541320221, - 1687895376, - 328994266, 1969922972, 
+    40735498, - 1677130071, - 351390145, 1913087877, 83908371, - 1782625662, 
+    - 491226604, 2075208622, 213261112, - 1831694693, - 438977011, 2094854071, 
+    198958881, - 2032938284, - 237706686, 1759359992, 534414190, - 2118248755, 
+    - 155638181, 1873836001, 414664567, - 2012718362, - 15766928, 1711684554, 
+    285281116, - 1889165569, - 127750551, 1634467795, 376229701, - 1609899400, 
+    - 686959890, 1308918612, 956543938, - 1486412191, - 799009033, 1231636301, 
+    1047427035, - 1362007478, - 640263460, 1088359270, 936918000, - 1447252397, 
+    - 558129467, 1202900863, 817233897, - 1111625188, - 893730166, 1404277552, 
+    615818150, - 1160759803, - 841546093, 1423857449, 601450431, - 1285129682, 
+    - 1000256840, 1567103746, 711928724, - 1274298825, - 1022587231, 1510334235, 
+    755167117]
+
+proc updateCrc32(val: int8, crc: TCrc32): TCrc32 = 
+  result = TCrc32(crc32table[(int(crc) xor (int(val) and 0x000000FF)) and
+      0x000000FF]) xor (crc shr TCrc32(8))
+
+proc updateCrc32(val: char, crc: TCrc32): TCrc32 = 
+  result = updateCrc32(toU8(ord(val)), crc)
+
+proc strCrc32(s: string): TCrc32 = 
+  result = InitCrc32
+  for i in countup(0, len(s) - 1): result = updateCrc32(s[i], result)
+  
+proc `><`*(c: TCrc32, s: string): TCrc32 = 
+  result = c
+  for i in 0..len(s)-1: result = updateCrc32(s[i], result)  
+  
+type 
+  TByteArray = array[0..10000000, int8]
+  PByteArray = ref TByteArray
+
+proc crcFromBuf(buf: pointer, length: int): TCrc32 = 
+  var p = cast[PByteArray](buf)
+  result = InitCrc32
+  for i in countup(0, length - 1): result = updateCrc32(p[i], result)
+  
+proc crcFromFile(filename: string): TCrc32 = 
+  const 
+    bufSize = 8000 # don't use 8K for the memory allocator!
+  var 
+    bin: File
+  result = InitCrc32
+  if not open(bin, filename): 
+    return                    # not equal if file does not exist
+  var buf = alloc(bufSize)
+  var p = cast[PByteArray](buf)
+  while true: 
+    var readBytes = readBuffer(bin, buf, bufSize)
+    for i in countup(0, readBytes - 1): result = updateCrc32(p[i], result)
+    if readBytes != bufSize: break 
+  dealloc(buf)
+  close(bin)
+
+const 
+  base = int32(65521) # largest prime smaller than 65536 
+                      # NMAX = 5552; original code with unsigned 32 bit integer 
+                      # NMAX is the largest n 
+                      # such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 
+  nmax = 3854 # code with signed 32 bit integer 
+              # NMAX is the largest n such that 
+              # 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 
+              # The penalty is the time loss in the extra MOD-calls. 
+
+proc updateAdler32(adler: int32, buf: pointer, length: int): int32 = 
+  var 
+    s1, s2: int32
+    L, k, b: int
+  s1 = adler and int32(0x0000FFFF)
+  s2 = (adler shr int32(16)) and int32(0x0000FFFF)
+  L = length
+  b = 0
+  while (L > 0): 
+    if L < nmax: k = L
+    else: k = nmax
+    dec(L, k)
+    while (k > 0): 
+      s1 = s1 +% int32((cast[cstring](buf))[b])
+      s2 = s2 +% s1
+      inc(b)
+      dec(k)
+    s1 = `%%`(s1, base)
+    s2 = `%%`(s2, base)
+  result = (s2 shl int32(16)) or s1
diff --git a/compiler/depends.nim b/compiler/depends.nim
new file mode 100644
index 000000000..1ccb134f2
--- /dev/null
+++ b/compiler/depends.nim
@@ -0,0 +1,56 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements a dependency file generator.
+
+import
+  os, options, ast, astalgo, msgs, ropes, idents, passes, importer
+
+proc generateDot*(project: string)
+
+type
+  TGen = object of TPassContext
+    module*: PSym
+  PGen = ref TGen
+
+var gDotGraph: Rope # the generated DOT file; we need a global variable
+
+proc addDependencyAux(importing, imported: string) =
+  addf(gDotGraph, "$1 -> $2;$n", [rope(importing), rope(imported)])
+  # s1 -> s2_4[label="[0-9]"];
+
+proc addDotDependency(c: PPassContext, n: PNode): PNode =
+  result = n
+  var g = PGen(c)
+  case n.kind
+  of nkImportStmt:
+    for i in countup(0, sonsLen(n) - 1):
+      var imported = getModuleName(n.sons[i])
+      addDependencyAux(g.module.name.s, imported)
+  of nkFromStmt, nkImportExceptStmt:
+    var imported = getModuleName(n.sons[0])
+    addDependencyAux(g.module.name.s, imported)
+  of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
+    for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
+  else:
+    discard
+
+proc generateDot(project: string) =
+  writeRope("digraph $1 {$n$2}$n" % [
+      rope(changeFileExt(extractFilename(project), "")), gDotGraph],
+            changeFileExt(project, "dot"))
+
+proc myOpen(module: PSym): PPassContext =
+  var g: PGen
+  new(g)
+  g.module = module
+  result = g
+
+const gendependPass* = makePass(open = myOpen, process = addDotDependency)
+
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
new file mode 100644
index 000000000..f8489d825
--- /dev/null
+++ b/compiler/docgen.nim
@@ -0,0 +1,655 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This is the documentation generator. It is currently pretty simple: No
+# semantic checking is done for the code. Cross-references are generated
+# by knowing how the anchors are going to be named.
+
+import
+  ast, strutils, strtabs, options, msgs, os, ropes, idents,
+  wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
+  importer, sempass2, json, xmltree, cgi, typesrenderer
+
+type
+  TSections = array[TSymKind, Rope]
+  TDocumentor = object of rstgen.TRstGenerator
+    modDesc: Rope           # module description
+    id: int                  # for generating IDs
+    toc, section: TSections
+    indexValFilename: string
+    analytics: string  # Google Analytics javascript, "" if doesn't exist
+    seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
+
+  PDoc* = ref TDocumentor ## Alias to type less.
+
+proc compilerMsgHandler(filename: string, line, col: int,
+                        msgKind: rst.TMsgKind, arg: string) {.procvar.} =
+  # translate msg kind:
+  var k: msgs.TMsgKind
+  case msgKind
+  of meCannotOpenFile: k = errCannotOpenFile
+  of meExpected: k = errXExpected
+  of meGridTableNotImplemented: k = errGridTableNotImplemented
+  of meNewSectionExpected: k = errNewSectionExpected
+  of meGeneralParseError: k = errGeneralParseError
+  of meInvalidDirective: k = errInvalidDirectiveX
+  of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
+  of mwUnknownSubstitution: k = warnUnknownSubstitutionX
+  of mwUnsupportedLanguage: k = warnLanguageXNotSupported
+  of mwUnsupportedField: k = warnFieldXNotSupported
+  globalError(newLineInfo(filename, line, col), k, arg)
+
+proc docgenFindFile(s: string): string {.procvar.} =
+  result = options.findFile(s)
+  if result.len == 0:
+    result = getCurrentDir() / s
+    if not existsFile(result): result = ""
+
+proc parseRst(text, filename: string,
+              line, column: int, hasToc: var bool,
+              rstOptions: TRstParseOptions): PRstNode =
+  result = rstParse(text, filename, line, column, hasToc, rstOptions,
+                    docgenFindFile, compilerMsgHandler)
+
+proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
+  new(result)
+  initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
+                   options.gConfigVars, filename, {roSupportRawDirective},
+                   docgenFindFile, compilerMsgHandler)
+
+  if config.hasKey("doc.googleAnalytics"):
+    result.analytics = """
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+  ga('create', '$1', 'auto');
+  ga('send', 'pageview');
+
+</script>
+    """ % [config["doc.googleAnalytics"]]
+  else:
+    result.analytics = ""
+
+  result.seenSymbols = newStringTable(modeCaseInsensitive)
+  result.id = 100
+
+proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
+  if gCmd != cmdRst2tex: addf(dest, xml, args)
+  else: addf(dest, tex, args)
+
+proc getVarIdx(varnames: openArray[string], id: string): int =
+  for i in countup(0, high(varnames)):
+    if cmpIgnoreStyle(varnames[i], id) == 0:
+      return i
+  result = -1
+
+proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
+                         varvalues: openArray[Rope]): Rope =
+  var i = 0
+  var L = len(frmt)
+  result = nil
+  var num = 0
+  while i < L:
+    if frmt[i] == '$':
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '#':
+        add(result, varvalues[num])
+        inc(num)
+        inc(i)
+      of '$':
+        add(result, "$")
+        inc(i)
+      of '0'..'9':
+        var j = 0
+        while true:
+          j = (j * 10) + ord(frmt[i]) - ord('0')
+          inc(i)
+          if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
+        if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
+        num = j
+        add(result, varvalues[j - 1])
+      of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
+        var id = ""
+        while true:
+          add(id, frmt[i])
+          inc(i)
+          if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
+        var idx = getVarIdx(varnames, id)
+        if idx >= 0: add(result, varvalues[idx])
+        else: rawMessage(errUnknownSubstitionVar, id)
+      of '{':
+        var id = ""
+        inc(i)
+        while frmt[i] != '}':
+          if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
+          add(id, frmt[i])
+          inc(i)
+        inc(i)                # skip }
+                              # search for the variable:
+        var idx = getVarIdx(varnames, id)
+        if idx >= 0: add(result, varvalues[idx])
+        else: rawMessage(errUnknownSubstitionVar, id)
+      else: internalError("ropeFormatNamedVars")
+    var start = i
+    while i < L:
+      if frmt[i] != '$': inc(i)
+      else: break
+    if i - 1 >= start: add(result, substr(frmt, start, i - 1))
+
+proc genComment(d: PDoc, n: PNode): string =
+  result = ""
+  var dummyHasToc: bool
+  if n.comment != nil and startsWith(n.comment, "##"):
+    renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
+                               toLinenumber(n.info), toColumn(n.info),
+                               dummyHasToc, d.options + {roSkipPounds}), result)
+
+proc genRecComment(d: PDoc, n: PNode): Rope =
+  if n == nil: return nil
+  result = genComment(d, n).rope
+  if result == nil:
+    if n.kind notin {nkEmpty..nkNilLit}:
+      for i in countup(0, len(n)-1):
+        result = genRecComment(d, n.sons[i])
+        if result != nil: return
+  else:
+    n.comment = nil
+
+proc getPlainDocstring(n: PNode): string =
+  ## Gets the plain text docstring of a node non destructively.
+  ##
+  ## You need to call this before genRecComment, whose side effects are removal
+  ## of comments from the tree. The proc will recursively scan and return all
+  ## the concatenated ``##`` comments of the node.
+  result = ""
+  if n == nil: return
+  if n.comment != nil and startsWith(n.comment, "##"):
+    result = n.comment
+  if result.len < 1:
+    if n.kind notin {nkEmpty..nkNilLit}:
+      for i in countup(0, len(n)-1):
+        result = getPlainDocstring(n.sons[i])
+        if result.len > 0: return
+
+
+proc findDocComment(n: PNode): PNode =
+  if n == nil: return nil
+  if not isNil(n.comment) and startsWith(n.comment, "##"): return n
+  for i in countup(0, safeLen(n)-1):
+    result = findDocComment(n.sons[i])
+    if result != nil: return
+
+proc extractDocComment*(s: PSym, d: PDoc = nil): string =
+  let n = findDocComment(s.ast)
+  result = ""
+  if not n.isNil:
+    if not d.isNil:
+      var dummyHasToc: bool
+      renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
+                                   toLinenumber(n.info), toColumn(n.info),
+                                   dummyHasToc, d.options + {roSkipPounds}),
+                     result)
+    else:
+      result = n.comment.substr(2).replace("\n##", "\n").strip
+
+proc isVisible(n: PNode): bool =
+  result = false
+  if n.kind == nkPostfix:
+    if n.len == 2 and n.sons[0].kind == nkIdent:
+      var v = n.sons[0].ident
+      result = v.id == ord(wStar) or v.id == ord(wMinus)
+  elif n.kind == nkSym:
+    # we cannot generate code for forwarded symbols here as we have no
+    # exception tracking information here. Instead we copy over the comment
+    # from the proc header.
+    result = {sfExported, sfFromGeneric, sfForward}*n.sym.flags == {sfExported}
+  elif n.kind == nkPragmaExpr:
+    result = isVisible(n.sons[0])
+
+proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
+  case n.kind
+  of nkPostfix: result = getName(d, n.sons[1], splitAfter)
+  of nkPragmaExpr: result = getName(d, n.sons[0], splitAfter)
+  of nkSym: result = esc(d.target, n.sym.renderDefinitionName, splitAfter)
+  of nkIdent: result = esc(d.target, n.ident.s, splitAfter)
+  of nkAccQuoted:
+    result = esc(d.target, "`")
+    for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
+    result.add esc(d.target, "`")
+  else:
+    internalError(n.info, "getName()")
+    result = ""
+
+proc getRstName(n: PNode): PRstNode =
+  case n.kind
+  of nkPostfix: result = getRstName(n.sons[1])
+  of nkPragmaExpr: result = getRstName(n.sons[0])
+  of nkSym: result = newRstNode(rnLeaf, n.sym.renderDefinitionName)
+  of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
+  of nkAccQuoted:
+    result = getRstName(n.sons[0])
+    for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
+  else:
+    internalError(n.info, "getRstName()")
+    result = nil
+
+proc newUniquePlainSymbol(d: PDoc, original: string): string =
+  ## Returns a new unique plain symbol made up from the original.
+  ##
+  ## When a collision is found in the seenSymbols table, new numerical variants
+  ## with underscore + number will be generated.
+  if not d.seenSymbols.hasKey(original):
+    result = original
+    d.seenSymbols[original] = ""
+    return
+
+  # Iterate over possible numeric variants of the original name.
+  var count = 2
+
+  while true:
+    result = original & "_" & $count
+    if not d.seenSymbols.hasKey(result):
+      d.seenSymbols[result] = ""
+      break
+    count += 1
+
+
+proc complexName(k: TSymKind, n: PNode, baseName: string): string =
+  ## Builds a complex unique href name for the node.
+  ##
+  ## Pass as ``baseName`` the plain symbol obtained from the nodeName. The
+  ## format of the returned symbol will be ``baseName(.callable type)?,(param
+  ## type)?(,param type)*``. The callable type part will be added only if the
+  ## node is not a proc, as those are the common ones. The suffix will be a dot
+  ## and a single letter representing the type of the callable. The parameter
+  ## types will be added with a preceding dash. Return types won't be added.
+  ##
+  ## If you modify the output of this proc, please update the anchor generation
+  ## section of ``doc/docgen.txt``.
+  result = baseName
+  case k:
+  of skProc: result.add(defaultParamSeparator)
+  of skMacro: result.add(".m" & defaultParamSeparator)
+  of skMethod: result.add(".e" & defaultParamSeparator)
+  of skIterator: result.add(".i" & defaultParamSeparator)
+  of skTemplate: result.add(".t" & defaultParamSeparator)
+  of skConverter: result.add(".c" & defaultParamSeparator)
+  else: discard
+
+  if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams:
+    result.add(renderParamTypes(n[paramsPos]))
+
+
+proc isCallable(n: PNode): bool =
+  ## Returns true if `n` contains a callable node.
+  case n.kind
+  of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef,
+    nkConverterDef: result = true
+  else:
+    result = false
+
+
+proc docstringSummary(rstText: string): string =
+  ## Returns just the first line or a brief chunk of text from a rst string.
+  ##
+  ## Most docstrings will contain a one liner summary, so stripping at the
+  ## first newline is usually fine. If after that the content is still too big,
+  ## it is stripped at the first comma, colon or dot, usual english sentence
+  ## separators.
+  ##
+  ## No guarantees are made on the size of the output, but it should be small.
+  ## Also, we hope to not break the rst, but maybe we do. If there is any
+  ## trimming done, an ellipsis unicode char is added.
+  const maxDocstringChars = 100
+  assert (rstText.len < 2 or (rstText[0] == '#' and rstText[1] == '#'))
+  result = rstText.substr(2).strip
+  var pos = result.find('\L')
+  if pos > 0:
+    result.delete(pos, result.len - 1)
+    result.add("…")
+  if pos < maxDocstringChars:
+    return
+  # Try to keep trimming at other natural boundaries.
+  pos = result.find({'.', ',', ':'})
+  let last = result.len - 1
+  if pos > 0 and pos < last:
+    result.delete(pos, last)
+    result.add("…")
+
+
+proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
+  if not isVisible(nameNode): return
+  let
+    name = getName(d, nameNode)
+    nameRope = name.rope
+    plainDocstring = getPlainDocstring(n) # call here before genRecComment!
+  var result: Rope = nil
+  var literal, plainName = ""
+  var kind = tkEof
+  var comm = genRecComment(d, n)  # call this here for the side-effect!
+  var r: TSrcGen
+  # Obtain the plain rendered string for hyperlink titles.
+  initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
+    renderNoPragmas, renderNoProcDefs})
+  while true:
+    getNextTok(r, kind, literal)
+    if kind == tkEof:
+      break
+    plainName.add(literal)
+
+  # Render the HTML hyperlink.
+  initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
+  while true:
+    getNextTok(r, kind, literal)
+    case kind
+    of tkEof:
+      break
+    of tkComment:
+      dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
+            [rope(esc(d.target, literal))])
+    of tokKeywordLow..tokKeywordHigh:
+      dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
+            [rope(literal)])
+    of tkOpr:
+      dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
+            [rope(esc(d.target, literal))])
+    of tkStrLit..tkTripleStrLit:
+      dispA(result, "<span class=\"StringLit\">$1</span>",
+            "\\spanStringLit{$1}", [rope(esc(d.target, literal))])
+    of tkCharLit:
+      dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
+            [rope(esc(d.target, literal))])
+    of tkIntLit..tkUInt64Lit:
+      dispA(result, "<span class=\"DecNumber\">$1</span>",
+            "\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
+    of tkFloatLit..tkFloat128Lit:
+      dispA(result, "<span class=\"FloatNumber\">$1</span>",
+            "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
+    of tkSymbol:
+      dispA(result, "<span class=\"Identifier\">$1</span>",
+            "\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
+    of tkSpaces, tkInvalid:
+      add(result, literal)
+    of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
+       tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
+       tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
+       tkAccent, tkColonColon,
+       tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
+      dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
+            [rope(esc(d.target, literal))])
+  inc(d.id)
+  let
+    plainNameRope = rope(xmltree.escape(plainName.strip))
+    cleanPlainSymbol = renderPlainSymbolName(nameNode)
+    complexSymbol = complexName(k, n, cleanPlainSymbol)
+    plainSymbolRope = rope(cleanPlainSymbol)
+    plainSymbolEncRope = rope(encodeUrl(cleanPlainSymbol))
+    itemIDRope = rope(d.id)
+    symbolOrId = d.newUniquePlainSymbol(complexSymbol)
+    symbolOrIdRope = symbolOrId.rope
+    symbolOrIdEncRope = encodeUrl(symbolOrId).rope
+
+  var seeSrcRope: Rope = nil
+  let docItemSeeSrc = getConfigVar("doc.item.seesrc")
+  if docItemSeeSrc.len > 0 and options.docSeeSrcUrl.len > 0:
+    # XXX toFilename doesn't really work. We need to ensure that this keeps
+    # returning a relative path.
+    let urlRope = ropeFormatNamedVars(options.docSeeSrcUrl,
+      ["path", "line"], [n.info.toFilename.rope, rope($n.info.line)])
+    dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
+        ["path", "line", "url"], [n.info.toFilename.rope,
+        rope($n.info.line), urlRope])])
+
+  add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
+    ["name", "header", "desc", "itemID", "header_plain", "itemSym",
+      "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
+    [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
+      symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope]))
+  add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
+    ["name", "header", "desc", "itemID", "header_plain", "itemSym",
+      "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc"],
+    [rope(getName(d, nameNode, d.splitAfter)), result, comm,
+      itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope,
+      plainSymbolEncRope, symbolOrIdEncRope]))
+
+  # Ironically for types the complexSymbol is *cleaner* than the plainName
+  # because it doesn't include object fields or documentation comments. So we
+  # use the plain one for callable elements, and the complex for the rest.
+  var linkTitle = changeFileExt(extractFilename(d.filename), "") & " : "
+  if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip))
+  else: linkTitle.add(xmltree.escape(complexSymbol.strip))
+
+  setIndexTerm(d[], symbolOrId, name, linkTitle,
+    xmltree.escape(plainDocstring.docstringSummary))
+
+proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
+  if not isVisible(nameNode): return
+  var
+    name = getName(d, nameNode)
+    comm = $genRecComment(d, n)
+    r: TSrcGen
+
+  initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
+
+  result = %{ "name": %name, "type": %($k) }
+
+  if comm != nil and comm != "":
+    result["description"] = %comm
+  if r.buf != nil:
+    result["code"] = %r.buf
+
+proc checkForFalse(n: PNode): bool =
+  result = n.kind == nkIdent and identEq(n.ident, "false")
+
+proc traceDeps(d: PDoc, n: PNode) =
+  const k = skModule
+  if d.section[k] != nil: add(d.section[k], ", ")
+  dispA(d.section[k],
+        "<a class=\"reference external\" href=\"$1.html\">$1</a>",
+        "$1", [rope(getModuleName(n))])
+
+proc generateDoc*(d: PDoc, n: PNode) =
+  case n.kind
+  of nkCommentStmt: add(d.modDesc, genComment(d, n))
+  of nkProcDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skProc)
+  of nkMethodDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skMethod)
+  of nkIteratorDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skIterator)
+  of nkMacroDef: genItem(d, n, n.sons[namePos], skMacro)
+  of nkTemplateDef: genItem(d, n, n.sons[namePos], skTemplate)
+  of nkConverterDef:
+    when useEffectSystem: documentRaises(n)
+    genItem(d, n, n.sons[namePos], skConverter)
+  of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
+    for i in countup(0, sonsLen(n) - 1):
+      if n.sons[i].kind != nkCommentStmt:
+        # order is always 'type var let const':
+        genItem(d, n.sons[i], n.sons[i].sons[0],
+                succ(skType, ord(n.kind)-ord(nkTypeSection)))
+  of nkStmtList:
+    for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i])
+  of nkWhenStmt:
+    # generate documentation for the first branch only:
+    if not checkForFalse(n.sons[0].sons[0]):
+      generateDoc(d, lastSon(n.sons[0]))
+  of nkImportStmt:
+    for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i])
+  of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
+  else: discard
+
+proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
+  case n.kind
+  of nkCommentStmt:
+    if n.comment != nil and startsWith(n.comment, "##"):
+      let stripped = n.comment.substr(2).strip
+      result = %{ "comment": %stripped }
+  of nkProcDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skProc)
+  of nkMethodDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skMethod)
+  of nkIteratorDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skIterator)
+  of nkMacroDef:
+    result = genJSONItem(d, n, n.sons[namePos], skMacro)
+  of nkTemplateDef:
+    result = genJSONItem(d, n, n.sons[namePos], skTemplate)
+  of nkConverterDef:
+    when useEffectSystem: documentRaises(n)
+    result = genJSONItem(d, n, n.sons[namePos], skConverter)
+  of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
+    for i in countup(0, sonsLen(n) - 1):
+      if n.sons[i].kind != nkCommentStmt:
+        # order is always 'type var let const':
+        result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
+                succ(skType, ord(n.kind)-ord(nkTypeSection)))
+  of nkStmtList:
+    result = if jArray != nil: jArray else: newJArray()
+
+    for i in countup(0, sonsLen(n) - 1):
+      var r = generateJson(d, n.sons[i], result)
+      if r != nil:
+        result.add(r)
+
+  of nkWhenStmt:
+    # generate documentation for the first branch only:
+    if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
+      discard generateJson(d, lastSon(n.sons[0]), jArray)
+  else: discard
+
+proc genSection(d: PDoc, kind: TSymKind) =
+  const sectionNames: array[skModule..skTemplate, string] = [
+    "Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
+    "Iterators", "Iterators", "Converters", "Macros", "Templates"
+  ]
+  if d.section[kind] == nil: return
+  var title = sectionNames[kind].rope
+  d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
+      "sectionid", "sectionTitle", "sectionTitleID", "content"], [
+      ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
+  d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
+      "sectionid", "sectionTitle", "sectionTitleID", "content"], [
+      ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
+
+proc genOutFile(d: PDoc): Rope =
+  var
+    code, content: Rope
+    title = ""
+  var j = 0
+  var tmp = ""
+  renderTocEntries(d[], j, 1, tmp)
+  var toc = tmp.rope
+  for i in countup(low(TSymKind), high(TSymKind)):
+    genSection(d, i)
+    add(toc, d.toc[i])
+  if toc != nil:
+    toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
+  for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
+
+  # Extract the title. Non API modules generate an entry in the index table.
+  if d.meta[metaTitle].len != 0:
+    title = d.meta[metaTitle]
+    setIndexTerm(d[], "", title)
+  else:
+    # Modules get an automatic title for the HTML, but no entry in the index.
+    title = "Module " & extractFilename(changeFileExt(d.filename, ""))
+
+  let bodyname = if d.hasToc: "doc.body_toc" else: "doc.body_no_toc"
+  content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
+      "tableofcontents", "moduledesc", "date", "time", "content"],
+      [title.rope, toc, d.modDesc, rope(getDateStr()),
+      rope(getClockStr()), code])
+  if optCompileOnly notin gGlobalOptions:
+    # XXX what is this hack doing here? 'optCompileOnly' means raw output!?
+    code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
+        "tableofcontents", "moduledesc", "date", "time",
+        "content", "author", "version", "analytics"],
+        [title.rope, toc, d.modDesc, rope(getDateStr()),
+                     rope(getClockStr()), content, d.meta[metaAuthor].rope,
+                     d.meta[metaVersion].rope, d.analytics.rope])
+  else:
+    code = content
+  result = code
+
+proc generateIndex*(d: PDoc) =
+  if optGenIndex in gGlobalOptions:
+    writeIndexFile(d[], splitFile(options.outFile).dir /
+                        splitFile(d.filename).name & IndexExt)
+
+proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
+  var content = genOutFile(d)
+  if optStdout in gGlobalOptions:
+    writeRope(stdout, content)
+  else:
+    writeRope(content, getOutFile(filename, outExt), useWarning)
+
+proc commandDoc*() =
+  var ast = parseFile(gProjectMainIdx)
+  if ast == nil: return
+  var d = newDocumentor(gProjectFull, options.gConfigVars)
+  d.hasToc = true
+  generateDoc(d, ast)
+  writeOutput(d, gProjectFull, HtmlExt)
+  generateIndex(d)
+
+proc commandRstAux(filename, outExt: string) =
+  var filen = addFileExt(filename, "txt")
+  var d = newDocumentor(filen, options.gConfigVars)
+  var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
+                     {roSupportRawDirective})
+  var modDesc = newStringOfCap(30_000)
+  #d.modDesc = newMutableRope(30_000)
+  renderRstToOut(d[], rst, modDesc)
+  #freezeMutableRope(d.modDesc)
+  d.modDesc = rope(modDesc)
+  writeOutput(d, filename, outExt)
+  generateIndex(d)
+
+proc commandRst2Html*() =
+  commandRstAux(gProjectFull, HtmlExt)
+
+proc commandRst2TeX*() =
+  splitter = "\\-"
+  commandRstAux(gProjectFull, TexExt)
+
+proc commandJSON*() =
+  var ast = parseFile(gProjectMainIdx)
+  if ast == nil: return
+  var d = newDocumentor(gProjectFull, options.gConfigVars)
+  d.hasToc = true
+  var json = generateJson(d, ast)
+  var content = rope(pretty(json))
+
+  if optStdout in gGlobalOptions:
+    writeRope(stdout, content)
+  else:
+    echo getOutFile(gProjectFull, JsonExt)
+    writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
+
+proc commandBuildIndex*() =
+  var content = mergeIndexes(gProjectFull).rope
+
+  let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
+      "tableofcontents", "moduledesc", "date", "time",
+      "content", "author", "version", "analytics"],
+      ["Index".rope, nil, nil, rope(getDateStr()),
+                   rope(getClockStr()), content, nil, nil, nil])
+  # no analytics because context is not available
+  writeRope(code, getOutFile("theindex", HtmlExt))
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
new file mode 100644
index 000000000..aa832b6df
--- /dev/null
+++ b/compiler/docgen2.nim
@@ -0,0 +1,49 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements a new documentation generator that runs after
+# semantic checking.
+
+import 
+  os, options, ast, astalgo, msgs, ropes, idents, passes, docgen
+
+type 
+  TGen = object of TPassContext
+    doc: PDoc
+    module: PSym
+  PGen = ref TGen
+
+proc close(p: PPassContext, n: PNode): PNode =
+  var g = PGen(p)
+  let useWarning = sfMainModule notin g.module.flags
+  if gWholeProject or sfMainModule in g.module.flags:
+    writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
+    try:
+      generateIndex(g.doc)
+    except IOError:
+      discard
+
+proc processNode(c: PPassContext, n: PNode): PNode = 
+  result = n
+  var g = PGen(c)
+  generateDoc(g.doc, n)
+
+proc myOpen(module: PSym): PPassContext = 
+  var g: PGen
+  new(g)
+  g.module = module
+  var d = newDocumentor(module.filename, options.gConfigVars)
+  d.hasToc = true
+  g.doc = d
+  result = g
+
+const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
+
+proc finishDoc2Pass*(project: string) = 
+  discard
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
new file mode 100644
index 000000000..8959aa4df
--- /dev/null
+++ b/compiler/evaltempl.nim
@@ -0,0 +1,106 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Template evaluation engine. Now hygienic.
+
+import
+  strutils, options, ast, astalgo, msgs, os, idents, wordrecg, renderer,
+  rodread
+
+type
+  TemplCtx {.pure, final.} = object
+    owner, genSymOwner: PSym
+    instLines: bool   # use the instantiation lines numbers
+    mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
+                      # new symbol
+
+proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
+  result = copyNode(a)
+  if ctx.instLines: result.info = b.info
+
+proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
+  case templ.kind
+  of nkSym:
+    var s = templ.sym
+    if s.owner.id == c.owner.id:
+      if s.kind == skParam and sfGenSym notin s.flags:
+        let x = actual.sons[s.position]
+        if x.kind == nkArgList:
+          for y in items(x): result.add(y)
+        else:
+          result.add copyTree(x)
+      else:
+        internalAssert sfGenSym in s.flags
+        var x = PSym(idTableGet(c.mapping, s))
+        if x == nil:
+          x = copySym(s, false)
+          x.owner = c.genSymOwner
+          idTablePut(c.mapping, s, x)
+        result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
+    else:
+      result.add copyNode(c, templ, actual)
+  of nkNone..nkIdent, nkType..nkNilLit: # atom
+    result.add copyNode(c, templ, actual)
+  else:
+    var res = copyNode(c, templ, actual)
+    for i in countup(0, sonsLen(templ) - 1):
+      evalTemplateAux(templ.sons[i], actual, c, res)
+    result.add res
+
+proc evalTemplateArgs(n: PNode, s: PSym): PNode =
+  # if the template has zero arguments, it can be called without ``()``
+  # `n` is then a nkSym or something similar
+  var a: int
+  case n.kind
+  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
+    a = sonsLen(n)
+  else: a = 0
+  var f = s.typ.sonsLen
+  if a > f: globalError(n.info, errWrongNumberOfArguments)
+
+  result = newNodeI(nkArgList, n.info)
+  for i in countup(1, f - 1):
+    var arg = if i < a: n.sons[i] else: copyTree(s.typ.n.sons[i].sym.ast)
+    if arg == nil or arg.kind == nkEmpty:
+      localError(n.info, errWrongNumberOfArguments)
+    addSon(result, arg)
+
+var evalTemplateCounter* = 0
+  # to prevent endless recursion in templates instantiation
+
+proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym): PNode =
+  inc(evalTemplateCounter)
+  if evalTemplateCounter > 100:
+    globalError(n.info, errTemplateInstantiationTooNested)
+    result = n
+
+  # replace each param by the corresponding node:
+  var args = evalTemplateArgs(n, tmpl)
+  var ctx: TemplCtx
+  ctx.owner = tmpl
+  ctx.genSymOwner = genSymOwner
+  initIdTable(ctx.mapping)
+
+  let body = tmpl.getBody
+  if isAtom(body):
+    result = newNodeI(nkPar, body.info)
+    evalTemplateAux(body, args, ctx, result)
+    if result.len == 1: result = result.sons[0]
+    else:
+      localError(result.info, errIllFormedAstX,
+                  renderTree(result, {renderNoComments}))
+  else:
+    result = copyNode(body)
+    ctx.instLines = body.kind notin {nkStmtList, nkStmtListExpr,
+                                     nkBlockStmt, nkBlockExpr}
+    if ctx.instLines: result.info = n.info
+    for i in countup(0, safeLen(body) - 1):
+      evalTemplateAux(body.sons[i], args, ctx, result)
+
+  dec(evalTemplateCounter)
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
new file mode 100644
index 000000000..186a3884d
--- /dev/null
+++ b/compiler/extccomp.nim
@@ -0,0 +1,740 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Module providing functions for calling the different external C compilers
+# Uses some hard-wired facts about each C/C++ compiler, plus options read
+# from a configuration file, to provide generalized procedures to compile
+# nim files.
+
+import
+  lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
+
+type
+  TSystemCC* = enum
+    ccNone, ccGcc, ccLLVM_Gcc, ccCLang, ccLcc, ccBcc, ccDmc, ccWcc, ccVcc,
+    ccTcc, ccPcc, ccUcc, ccIcl
+  TInfoCCProp* = enum         # properties of the C compiler:
+    hasSwitchRange,           # CC allows ranges in switch statements (GNU C)
+    hasComputedGoto,          # CC has computed goto (GNU C extension)
+    hasCpp,                   # CC is/contains a C++ compiler
+    hasAssume,                # CC has __assume (Visual C extension)
+    hasGcGuard,               # CC supports GC_GUARD to keep stack roots
+    hasGnuAsm,                # CC's asm uses the absurd GNU assembler syntax
+    hasDeclspec,              # CC has __declspec(X)
+    hasAttribute,             # CC has __attribute__((X))
+  TInfoCCProps* = set[TInfoCCProp]
+  TInfoCC* = tuple[
+    name: string,        # the short name of the compiler
+    objExt: string,      # the compiler's object file extenstion
+    optSpeed: string,    # the options for optimization for speed
+    optSize: string,     # the options for optimization for size
+    compilerExe: string, # the compiler's executable
+    cppCompiler: string, # name of the C++ compiler's executable (if supported)
+    compileTmpl: string, # the compile command template
+    buildGui: string,    # command to build a GUI application
+    buildDll: string,    # command to build a shared library
+    buildLib: string,    # command to build a static library
+    linkerExe: string,   # the linker's executable (if not matching compiler's)
+    linkTmpl: string,    # command to link files to produce an exe
+    includeCmd: string,  # command to add an include dir
+    linkDirCmd: string,  # command to add a lib dir
+    linkLibCmd: string,  # command to link an external library
+    debug: string,       # flags for debug build
+    pic: string,         # command for position independent code
+                         # used on some platforms
+    asmStmtFrmt: string, # format of ASM statement
+    structStmtFmt: string, # Format for struct statement
+    packedPragma: string,  # Attribute/pragma to make struct packed (1-byte aligned)
+    props: TInfoCCProps] # properties of the C compiler
+
+
+# Configuration settings for various compilers.
+# When adding new compilers, the cmake sources could be a good reference:
+# http://cmake.org/gitweb?p=cmake.git;a=tree;f=Modules/Platform;
+
+template compiler(name: expr, settings: stmt): stmt {.immediate.} =
+  proc name: TInfoCC {.compileTime.} = settings
+
+# GNU C and C++ Compiler
+compiler gcc:
+  result = (
+    name: "gcc",
+    objExt: "o",
+    optSpeed: " -O3 -ffast-math ",
+    optSize: " -Os -ffast-math ",
+    compilerExe: "gcc",
+    cppCompiler: "g++",
+    compileTmpl: "-c $options $include -o $objfile $file",
+    buildGui: " -mwindows",
+    buildDll: " -shared",
+    buildLib: "ar rcs $libfile $objfiles",
+    linkerExe: "",
+    linkTmpl: "$buildgui $builddll -o $exefile $objfiles $options",
+    includeCmd: " -I",
+    linkDirCmd: " -L",
+    linkLibCmd: " -l$1",
+    debug: "",
+    pic: "-fPIC",
+    asmStmtFrmt: "asm($1);$n",
+    structStmtFmt: "$1 $3 $2 ", # struct|union [packed] $name
+    packedPragma: "__attribute__((__packed__))",
+    props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
+            hasAttribute})
+
+# LLVM Frontend for GCC/G++
+compiler llvmGcc:
+  result = gcc() # Uses settings from GCC
+
+  result.name = "llvm_gcc"
+  result.compilerExe = "llvm-gcc"
+  result.cppCompiler = "llvm-g++"
+  result.buildLib = "llvm-ar rcs $libfile $objfiles"
+
+# Clang (LLVM) C/C++ Compiler
+compiler clang:
+  result = llvmGcc() # Uses settings from llvmGcc
+
+  result.name = "clang"
+  result.compilerExe = "clang"
+  result.cppCompiler = "clang++"
+
+# Microsoft Visual C/C++ Compiler
+compiler vcc:
+  result = (
+    name: "vcc",
+    objExt: "obj",
+    optSpeed: " /Ogityb2 /G7 /arch:SSE2 ",
+    optSize: " /O1 /G7 ",
+    compilerExe: "cl",
+    cppCompiler: "cl",
+    compileTmpl: "/c $options $include /Fo$objfile $file",
+    buildGui: " /link /SUBSYSTEM:WINDOWS ",
+    buildDll: " /LD",
+    buildLib: "lib /OUT:$libfile $objfiles",
+    linkerExe: "cl",
+    linkTmpl: "$options $builddll /Fe$exefile $objfiles $buildgui",
+    includeCmd: " /I",
+    linkDirCmd: " /LIBPATH:",
+    linkLibCmd: " $1.lib",
+    debug: " /GZ /Zi ",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$3$n$1 $2",
+    packedPragma: "#pragma pack(1)",
+    props: {hasCpp, hasAssume, hasDeclspec})
+
+# Intel C/C++ Compiler
+compiler icl:
+  # Intel compilers try to imitate the native ones (gcc and msvc)
+  when defined(windows):
+    result = vcc()
+  else:
+    result = gcc()
+
+  result.name = "icl"
+  result.compilerExe = "icl"
+  result.linkerExe = "icl"
+
+# Local C Compiler
+compiler lcc:
+  result = (
+    name: "lcc",
+    objExt: "obj",
+    optSpeed: " -O -p6 ",
+    optSize: " -O -p6 ",
+    compilerExe: "lcc",
+    cppCompiler: "",
+    compileTmpl: "$options $include -Fo$objfile $file",
+    buildGui: " -subsystem windows",
+    buildDll: " -dll",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "lcclnk",
+    linkTmpl: "$options $buildgui $builddll -O $exefile $objfiles",
+    includeCmd: " -I",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: " -g5 ",
+    pic: "",
+    asmStmtFrmt: "_asm{$n$1$n}$n",
+    structStmtFmt: "$1 $2",
+    packedPragma: "", # XXX: not supported yet
+    props: {})
+
+# Borland C Compiler
+compiler bcc:
+  result = (
+    name: "bcc",
+    objExt: "obj",
+    optSpeed: " -O2 -6 ",
+    optSize: " -O1 -6 ",
+    compilerExe: "bcc32",
+    cppCompiler: "",
+    compileTmpl: "-c $options $include -o$objfile $file",
+    buildGui: " -tW",
+    buildDll: " -tWD",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "bcc32",
+    linkTmpl: "$options $buildgui $builddll -e$exefile $objfiles",
+    includeCmd: " -I",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: "",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$1 $2",
+    packedPragma: "", # XXX: not supported yet
+    props: {hasCpp})
+
+# Digital Mars C Compiler
+compiler dmc:
+  result = (
+    name: "dmc",
+    objExt: "obj",
+    optSpeed: " -ff -o -6 ",
+    optSize: " -ff -o -6 ",
+    compilerExe: "dmc",
+    cppCompiler: "",
+    compileTmpl: "-c $options $include -o$objfile $file",
+    buildGui: " -L/exet:nt/su:windows",
+    buildDll: " -WD",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "dmc",
+    linkTmpl: "$options $buildgui $builddll -o$exefile $objfiles",
+    includeCmd: " -I",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: " -g ",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$3$n$1 $2",
+    packedPragma: "#pragma pack(1)",
+    props: {hasCpp})
+
+# Watcom C Compiler
+compiler wcc:
+  result = (
+    name: "wcc",
+    objExt: "obj",
+    optSpeed: " -ox -on -6 -d0 -fp6 -zW ",
+    optSize: "",
+    compilerExe: "wcl386",
+    cppCompiler: "",
+    compileTmpl: "-c $options $include -fo=$objfile $file",
+    buildGui: " -bw",
+    buildDll: " -bd",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "wcl386",
+    linkTmpl: "$options $buildgui $builddll -fe=$exefile $objfiles ",
+    includeCmd: " -i=",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: " -d2 ",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$1 $2",
+    packedPragma: "", # XXX: not supported yet
+    props: {hasCpp})
+
+# Tiny C Compiler
+compiler tcc:
+  result = (
+    name: "tcc",
+    objExt: "o",
+    optSpeed: "",
+    optSize: "",
+    compilerExe: "tcc",
+    cppCompiler: "",
+    compileTmpl: "-c $options $include -o $objfile $file",
+    buildGui: "UNAVAILABLE!",
+    buildDll: " -shared",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "tcc",
+    linkTmpl: "-o $exefile $options $buildgui $builddll $objfiles",
+    includeCmd: " -I",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: " -g ",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$1 $2",
+    packedPragma: "", # XXX: not supported yet
+    props: {hasSwitchRange, hasComputedGoto})
+
+# Pelles C Compiler
+compiler pcc:
+  # Pelles C
+  result = (
+    name: "pcc",
+    objExt: "obj",
+    optSpeed: " -Ox ",
+    optSize: " -Os ",
+    compilerExe: "cc",
+    cppCompiler: "",
+    compileTmpl: "-c $options $include -Fo$objfile $file",
+    buildGui: " -SUBSYSTEM:WINDOWS",
+    buildDll: " -DLL",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "cc",
+    linkTmpl: "$options $buildgui $builddll -OUT:$exefile $objfiles",
+    includeCmd: " -I",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: " -Zi ",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$1 $2",
+    packedPragma: "", # XXX: not supported yet
+    props: {})
+
+# Your C Compiler
+compiler ucc:
+  result = (
+    name: "ucc",
+    objExt: "o",
+    optSpeed: " -O3 ",
+    optSize: " -O1 ",
+    compilerExe: "cc",
+    cppCompiler: "",
+    compileTmpl: "-c $options $include -o $objfile $file",
+    buildGui: "",
+    buildDll: " -shared ",
+    buildLib: "", # XXX: not supported yet
+    linkerExe: "cc",
+    linkTmpl: "-o $exefile $buildgui $builddll $objfiles $options",
+    includeCmd: " -I",
+    linkDirCmd: "", # XXX: not supported yet
+    linkLibCmd: "", # XXX: not supported yet
+    debug: "",
+    pic: "",
+    asmStmtFrmt: "__asm{$n$1$n}$n",
+    structStmtFmt: "$1 $2",
+    packedPragma: "", # XXX: not supported yet
+    props: {})
+
+const
+  CC*: array[succ(low(TSystemCC))..high(TSystemCC), TInfoCC] = [
+    gcc(),
+    llvmGcc(),
+    clang(),
+    lcc(),
+    bcc(),
+    dmc(),
+    wcc(),
+    vcc(),
+    tcc(),
+    pcc(),
+    ucc(),
+    icl()]
+
+  hExt* = ".h"
+
+var
+  cCompiler* = ccGcc # the used compiler
+  gMixedMode*: bool  # true if some module triggered C++ codegen
+  cIncludes*: seq[string] = @[]   # directories to search for included files
+  cLibs*: seq[string] = @[]       # directories to search for lib files
+  cLinkedLibs*: seq[string] = @[] # libraries to link
+
+# implementation
+
+proc libNameTmpl(): string {.inline.} =
+  result = if targetOS == osWindows: "$1.lib" else: "lib$1.a"
+
+var
+  toLink, toCompile, externalToCompile: TLinkedList
+  linkOptions: string = ""
+  compileOptions: string = ""
+  ccompilerpath: string = ""
+
+proc nameToCC*(name: string): TSystemCC =
+  ## Returns the kind of compiler referred to by `name`, or ccNone
+  ## if the name doesn't refer to any known compiler.
+  for i in countup(succ(ccNone), high(TSystemCC)):
+    if cmpIgnoreStyle(name, CC[i].name) == 0:
+      return i
+  result = ccNone
+
+proc getConfigVar(c: TSystemCC, suffix: string): string =
+  # use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
+  # for niminst support
+  let fullSuffix =
+    if gCmd == cmdCompileToCpp:
+      ".cpp" & suffix
+    elif gCmd == cmdCompileToOC:
+      ".objc" & suffix
+    elif gCmd == cmdCompileToJS:
+      ".js" & suffix
+    else:
+      suffix
+
+  if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
+      optCompileOnly notin gGlobalOptions:
+    let fullCCname = platform.CPU[targetCPU].name & '.' &
+                     platform.OS[targetOS].name & '.' &
+                     CC[c].name & fullSuffix
+    result = getConfigVar(fullCCname)
+    if result.len == 0:
+      # not overriden for this cross compilation setting?
+      result = getConfigVar(CC[c].name & fullSuffix)
+  else:
+    result = getConfigVar(CC[c].name & fullSuffix)
+
+proc setCC*(ccname: string) =
+  cCompiler = nameToCC(ccname)
+  if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
+  compileOptions = getConfigVar(cCompiler, ".options.always")
+  linkOptions = ""
+  ccompilerpath = getConfigVar(cCompiler, ".path")
+  for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
+  defineSymbol(CC[cCompiler].name)
+
+proc addOpt(dest: var string, src: string) =
+  if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
+  add(dest, src)
+
+proc addLinkOption*(option: string) =
+  addOpt(linkOptions, option)
+
+proc addCompileOption*(option: string) =
+  if strutils.find(compileOptions, option, 0) < 0:
+    addOpt(compileOptions, option)
+
+proc initVars*() =
+  # we need to define the symbol here, because ``CC`` may have never been set!
+  for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
+  defineSymbol(CC[cCompiler].name)
+  addCompileOption(getConfigVar(cCompiler, ".options.always"))
+  #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
+  if len(ccompilerpath) == 0:
+    ccompilerpath = getConfigVar(cCompiler, ".path")
+
+proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
+  result = completeGeneratedFilePath(cfile, createSubDir)
+
+proc toObjFile*(filename: string): string =
+  # Object file for compilation
+  result = changeFileExt(filename, CC[cCompiler].objExt)
+
+proc addFileToCompile*(filename: string) =
+  appendStr(toCompile, filename)
+
+proc resetCompilationLists* =
+  initLinkedList(toCompile)
+  ## XXX: we must associate these with their originating module
+  # when the module is loaded/unloaded it adds/removes its items
+  # That's because we still need to CRC check the external files
+  # Maybe we can do that in checkDep on the other hand?
+  initLinkedList(externalToCompile)
+  initLinkedList(toLink)
+
+proc addFileToLink*(filename: string) =
+  prependStr(toLink, filename)
+  # BUGFIX: was ``appendStr``
+
+proc execWithEcho(cmd: string, prettyCmd = ""): int =
+  if optListCmd in gGlobalOptions or gVerbosity > 0:
+    if prettyCmd != "":
+      msgWriteln(prettyCmd)
+    else:
+      msgWriteln(cmd)
+  result = execCmd(cmd)
+
+proc execExternalProgram*(cmd: string, prettyCmd = "") =
+  if execWithEcho(cmd, prettyCmd) != 0:
+    rawMessage(errExecutionOfProgramFailed, "")
+
+proc generateScript(projectFile: string, script: Rope) =
+  let (dir, name, ext) = splitFile(projectFile)
+  writeRope(script, dir / addFileExt("compile_" & name,
+                                     platform.OS[targetOS].scriptExt))
+
+proc getOptSpeed(c: TSystemCC): string =
+  result = getConfigVar(c, ".options.speed")
+  if result == "":
+    result = CC[c].optSpeed   # use default settings from this file
+
+proc getDebug(c: TSystemCC): string =
+  result = getConfigVar(c, ".options.debug")
+  if result == "":
+    result = CC[c].debug      # use default settings from this file
+
+proc getOptSize(c: TSystemCC): string =
+  result = getConfigVar(c, ".options.size")
+  if result == "":
+    result = CC[c].optSize    # use default settings from this file
+
+proc noAbsolutePaths: bool {.inline.} =
+  # We used to check current OS != specified OS, but this makes no sense
+  # really: Cross compilation from Linux to Linux for example is entirely
+  # reasonable.
+  # `optGenMapping` is included here for niminst.
+  result = gGlobalOptions * {optGenScript, optGenMapping} != {}
+
+const
+  specialFileA = 42
+  specialFileB = 42
+
+var fileCounter: int
+
+proc add(s: var string, many: openArray[string]) =
+  s.add many.join
+
+proc cFileSpecificOptions(cfilename: string): string =
+  result = compileOptions
+  var trunk = splitFile(cfilename).name
+  if optCDebug in gGlobalOptions:
+    var key = trunk & ".debug"
+    if existsConfigVar(key): addOpt(result, getConfigVar(key))
+    else: addOpt(result, getDebug(cCompiler))
+  if optOptimizeSpeed in gOptions:
+    var key = trunk & ".speed"
+    if existsConfigVar(key): addOpt(result, getConfigVar(key))
+    else: addOpt(result, getOptSpeed(cCompiler))
+  elif optOptimizeSize in gOptions:
+    var key = trunk & ".size"
+    if existsConfigVar(key): addOpt(result, getConfigVar(key))
+    else: addOpt(result, getOptSize(cCompiler))
+  var key = trunk & ".always"
+  if existsConfigVar(key): addOpt(result, getConfigVar(key))
+
+proc getCompileOptions: string =
+  result = cFileSpecificOptions("__dummy__")
+
+proc getLinkOptions: string =
+  result = linkOptions
+  for linkedLib in items(cLinkedLibs):
+    result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
+  for libDir in items(cLibs):
+    result.add([CC[cCompiler].linkDirCmd, libDir.quoteShell])
+
+proc needsExeExt(): bool {.inline.} =
+  result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
+           (platform.hostOS == osWindows)
+
+proc getCompilerExe(compiler: TSystemCC): string =
+  result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
+           else: CC[compiler].compilerExe
+  if result.len == 0:
+    rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
+
+proc getLinkerExe(compiler: TSystemCC): string =
+  result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
+           elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
+           else: compiler.getCompilerExe
+
+proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
+  var c = cCompiler
+  var options = cFileSpecificOptions(cfilename)
+  var exe = getConfigVar(c, ".exe")
+  if exe.len == 0: exe = c.getCompilerExe
+
+  if needsExeExt(): exe = addFileExt(exe, "exe")
+  if optGenDynLib in gGlobalOptions and
+      ospNeedsPIC in platform.OS[targetOS].props:
+    add(options, ' ' & CC[c].pic)
+
+  var includeCmd, compilePattern: string
+  if not noAbsolutePaths():
+    # compute include paths:
+    includeCmd = CC[c].includeCmd & quoteShell(libpath)
+
+    for includeDir in items(cIncludes):
+      includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
+
+    compilePattern = joinPath(ccompilerpath, exe)
+  else:
+    includeCmd = ""
+    compilePattern = c.getCompilerExe
+
+  var cfile = if noAbsolutePaths(): extractFilename(cfilename)
+              else: cfilename
+  var objfile = if not isExternal or noAbsolutePaths():
+                  toObjFile(cfile)
+                else:
+                  completeCFilePath(toObjFile(cfile))
+  objfile = quoteShell(objfile)
+  cfile = quoteShell(cfile)
+  result = quoteShell(compilePattern % [
+    "file", cfile, "objfile", objfile, "options", options,
+    "include", includeCmd, "nim", getPrefixDir(),
+    "nim", getPrefixDir(), "lib", libpath])
+  add(result, ' ')
+  addf(result, CC[c].compileTmpl, [
+    "file", cfile, "objfile", objfile,
+    "options", options, "include", includeCmd,
+    "nim", quoteShell(getPrefixDir()),
+    "nim", quoteShell(getPrefixDir()),
+    "lib", quoteShell(libpath)])
+
+proc footprint(filename: string): TCrc32 =
+  # note, '><' further modifies a crc value with a string.
+  result = crcFromFile(filename) ><
+      platform.OS[targetOS].name ><
+      platform.CPU[targetCPU].name ><
+      extccomp.CC[extccomp.cCompiler].name ><
+      getCompileCFileCmd(filename, true)
+
+proc externalFileChanged(filename: string): bool =
+  if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
+    return false
+
+  var crcFile = toGeneratedFile(filename.withPackageName, "crc")
+  var currentCrc = int(footprint(filename))
+  var f: File
+  if open(f, crcFile, fmRead):
+    var line = newStringOfCap(40)
+    if not f.readLine(line): line = "0"
+    close(f)
+    var oldCrc = parseInt(line)
+    result = oldCrc != currentCrc
+  else:
+    result = true
+  if result:
+    if open(f, crcFile, fmWrite):
+      f.writeln($currentCrc)
+      close(f)
+
+proc addExternalFileToCompile*(filename: string) =
+  if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
+    appendStr(externalToCompile, filename)
+
+proc compileCFile(list: TLinkedList, script: var Rope, cmds: var TStringSeq,
+                  prettyCmds: var TStringSeq, isExternal: bool) =
+  var it = PStrEntry(list.head)
+  while it != nil:
+    inc(fileCounter)          # call the C compiler for the .c file:
+    var compileCmd = getCompileCFileCmd(it.data, isExternal)
+    if optCompileOnly notin gGlobalOptions:
+      add(cmds, compileCmd)
+      let (dir, name, ext) = splitFile(it.data)
+      add(prettyCmds, "CC: " & name)
+    if optGenScript in gGlobalOptions:
+      add(script, compileCmd)
+      add(script, tnl)
+    it = PStrEntry(it.next)
+
+proc callCCompiler*(projectfile: string) =
+  var
+    linkCmd, buildgui, builddll: string
+  if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
+    return # speed up that call if only compiling and no script shall be
+           # generated
+  fileCounter = 0
+  var c = cCompiler
+  var script: Rope = nil
+  var cmds: TStringSeq = @[]
+  var prettyCmds: TStringSeq = @[]
+  let prettyCb = proc (idx: int) =
+    echo prettyCmds[idx]
+  compileCFile(toCompile, script, cmds, prettyCmds, false)
+  compileCFile(externalToCompile, script, cmds, prettyCmds, true)
+  if optCompileOnly notin gGlobalOptions:
+    if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
+    var res = 0
+    if gNumberOfProcessors <= 1:
+      for i in countup(0, high(cmds)):
+        res = execWithEcho(cmds[i])
+        if res != 0: rawMessage(errExecutionOfProgramFailed, [])
+    elif optListCmd in gGlobalOptions or gVerbosity > 1:
+      res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
+                          gNumberOfProcessors)
+    elif gVerbosity == 1:
+      res = execProcesses(cmds, {poUsePath, poParentStreams},
+                          gNumberOfProcessors, prettyCb)
+    else:
+      res = execProcesses(cmds, {poUsePath, poParentStreams},
+                          gNumberOfProcessors)
+    if res != 0:
+      if gNumberOfProcessors <= 1:
+        rawMessage(errExecutionOfProgramFailed, [])
+      else:
+        rawMessage(errGenerated, " execution of an external program failed; " &
+                   "rerun with --parallelBuild:1 to see the error message")
+  if optNoLinking notin gGlobalOptions:
+    # call the linker:
+    var it = PStrEntry(toLink.head)
+    var objfiles = ""
+    while it != nil:
+      let objFile = if noAbsolutePaths(): it.data.extractFilename else: it.data
+      add(objfiles, ' ')
+      add(objfiles, quoteShell(
+          addFileExt(objFile, CC[cCompiler].objExt)))
+      it = PStrEntry(it.next)
+
+    if optGenStaticLib in gGlobalOptions:
+      let name = splitFile(gProjectName).name
+      linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % name),
+                                  "objfiles", objfiles]
+    else:
+      var linkerExe = getConfigVar(c, ".linkerexe")
+      if len(linkerExe) == 0: linkerExe = c.getLinkerExe
+      if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
+      if noAbsolutePaths(): linkCmd = quoteShell(linkerExe)
+      else: linkCmd = quoteShell(joinPath(ccompilerpath, linkerExe))
+      if optGenGuiApp in gGlobalOptions: buildgui = CC[c].buildGui
+      else: buildgui = ""
+      var exefile: string
+      if optGenDynLib in gGlobalOptions:
+        exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
+        builddll = CC[c].buildDll
+      else:
+        exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
+        builddll = ""
+      if options.outFile.len > 0:
+        exefile = options.outFile.expandTilde
+      if not noAbsolutePaths():
+        if not exefile.isAbsolute():
+          exefile = joinPath(splitFile(projectfile).dir, exefile)
+      exefile = quoteShell(exefile)
+      let linkOptions = getLinkOptions() & " " &
+                        getConfigVar(cCompiler, ".options.linker")
+      linkCmd = quoteShell(linkCmd % ["builddll", builddll,
+          "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
+          "exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
+      linkCmd.add ' '
+      addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
+          "buildgui", buildgui, "options", linkOptions,
+          "objfiles", objfiles, "exefile", exefile,
+          "nim", quoteShell(getPrefixDir()),
+          "lib", quoteShell(libpath)])
+    if optCompileOnly notin gGlobalOptions:
+      if gVerbosity == 1:
+        execExternalProgram(linkCmd, "[Linking]")
+      else:
+        execExternalProgram(linkCmd)
+  else:
+    linkCmd = ""
+  if optGenScript in gGlobalOptions:
+    add(script, linkCmd)
+    add(script, tnl)
+    generateScript(projectfile, script)
+
+proc genMappingFiles(list: TLinkedList): Rope =
+  var it = PStrEntry(list.head)
+  while it != nil:
+    addf(result, "--file:r\"$1\"$N", [rope(it.data)])
+    it = PStrEntry(it.next)
+
+proc writeMapping*(gSymbolMapping: Rope) =
+  if optGenMapping notin gGlobalOptions: return
+  var code = rope("[C_Files]\n")
+  add(code, genMappingFiles(toCompile))
+  add(code, genMappingFiles(externalToCompile))
+  add(code, "\n[C_Compiler]\nFlags=")
+  add(code, strutils.escape(getCompileOptions()))
+
+  add(code, "\n[Linker]\nFlags=")
+  add(code, strutils.escape(getLinkOptions() & " " &
+                            getConfigVar(cCompiler, ".options.linker")))
+
+  add(code, "\n[Environment]\nlibpath=")
+  add(code, strutils.escape(libpath))
+
+  addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
+  writeRope(code, joinPath(gProjectPath, "mapping.txt"))
diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim
new file mode 100644
index 000000000..5d1f73be4
--- /dev/null
+++ b/compiler/filter_tmpl.nim
@@ -0,0 +1,221 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements Nim's standard template filter.
+
+import 
+  llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, 
+  renderer, filters
+
+proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream
+  # #! template(subsChar='$', metaChar='#') | standard(version="0.7.2")
+# implementation
+
+type 
+  TParseState = enum 
+    psDirective, psTempl
+  TTmplParser{.final.} = object 
+    inp: PLLStream
+    state: TParseState
+    info: TLineInfo
+    indent, emitPar: int
+    x: string                # the current input line
+    outp: PLLStream          # the ouput will be parsed by pnimsyn
+    subsChar, nimDirective: char
+    emit, conc, toStr: string
+    curly, bracket, par: int
+    pendingExprLine: bool
+
+
+const 
+  PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
+
+proc newLine(p: var TTmplParser) = 
+  llStreamWrite(p.outp, repeat(')', p.emitPar))
+  p.emitPar = 0
+  if p.info.line > int16(1): llStreamWrite(p.outp, "\n")
+  if p.pendingExprLine:
+    llStreamWrite(p.outp, spaces(2))
+    p.pendingExprLine = false
+  
+proc scanPar(p: var TTmplParser, d: int) = 
+  var i = d
+  while true:
+    case p.x[i]
+    of '\0': break
+    of '(': inc(p.par)
+    of ')': dec(p.par)
+    of '[': inc(p.bracket)
+    of ']': dec(p.bracket)
+    of '{': inc(p.curly)
+    of '}': dec(p.curly)
+    else: discard
+    inc(i)
+
+proc withInExpr(p: TTmplParser): bool {.inline.} = 
+  result = p.par > 0 or p.bracket > 0 or p.curly > 0
+  
+proc parseLine(p: var TTmplParser) = 
+  var 
+    d, j, curly: int
+    keyw: string
+  j = 0
+  while p.x[j] == ' ': inc(j)
+  if (p.x[0] == p.nimDirective) and (p.x[0 + 1] == '!'): 
+    newLine(p)
+  elif (p.x[j] == p.nimDirective): 
+    newLine(p)
+    inc(j)
+    while p.x[j] == ' ': inc(j)
+    d = j
+    keyw = ""
+    while p.x[j] in PatternChars: 
+      add(keyw, p.x[j])
+      inc(j)
+    
+    scanPar(p, j)
+    p.pendingExprLine = withInExpr(p) or llstream.endsWithOpr(p.x)
+    case whichKeyword(keyw)
+    of wEnd: 
+      if p.indent >= 2: 
+        dec(p.indent, 2)
+      else: 
+        p.info.col = int16(j)
+        localError(p.info, errXNotAllowedHere, "end")
+      llStreamWrite(p.outp, spaces(p.indent))
+      llStreamWrite(p.outp, "#end")
+    of wIf, wWhen, wTry, wWhile, wFor, wBlock, wCase, wProc, wIterator, 
+       wConverter, wMacro, wTemplate, wMethod: 
+      llStreamWrite(p.outp, spaces(p.indent))
+      llStreamWrite(p.outp, substr(p.x, d))
+      inc(p.indent, 2)
+    of wElif, wOf, wElse, wExcept, wFinally: 
+      llStreamWrite(p.outp, spaces(p.indent - 2))
+      llStreamWrite(p.outp, substr(p.x, d))
+    of wLet, wVar, wConst, wType:
+      llStreamWrite(p.outp, spaces(p.indent))
+      llStreamWrite(p.outp, substr(p.x, d))
+      if not p.x.contains({':', '='}):
+        # no inline element --> treat as block:
+        inc(p.indent, 2)
+    else:
+      llStreamWrite(p.outp, spaces(p.indent))
+      llStreamWrite(p.outp, substr(p.x, d))
+    p.state = psDirective
+  else: 
+    # data line
+    # reset counters
+    p.par = 0
+    p.curly = 0
+    p.bracket = 0
+    j = 0
+    case p.state
+    of psTempl: 
+      # next line of string literal:
+      llStreamWrite(p.outp, p.conc)
+      llStreamWrite(p.outp, "\n")
+      llStreamWrite(p.outp, spaces(p.indent + 2))
+      llStreamWrite(p.outp, "\"")
+    of psDirective: 
+      newLine(p)
+      llStreamWrite(p.outp, spaces(p.indent))
+      llStreamWrite(p.outp, p.emit)
+      llStreamWrite(p.outp, "(\"")
+      inc(p.emitPar)
+    p.state = psTempl
+    while true: 
+      case p.x[j]
+      of '\0': 
+        break 
+      of '\x01'..'\x1F', '\x80'..'\xFF': 
+        llStreamWrite(p.outp, "\\x")
+        llStreamWrite(p.outp, toHex(ord(p.x[j]), 2))
+        inc(j)
+      of '\\': 
+        llStreamWrite(p.outp, "\\\\")
+        inc(j)
+      of '\'': 
+        llStreamWrite(p.outp, "\\\'")
+        inc(j)
+      of '\"': 
+        llStreamWrite(p.outp, "\\\"")
+        inc(j)
+      else: 
+        if p.x[j] == p.subsChar: 
+          # parse Nim expression:
+          inc(j)
+          case p.x[j]
+          of '{': 
+            p.info.col = int16(j)
+            llStreamWrite(p.outp, '\"')
+            llStreamWrite(p.outp, p.conc)
+            llStreamWrite(p.outp, p.toStr)
+            llStreamWrite(p.outp, '(')
+            inc(j)
+            curly = 0
+            while true: 
+              case p.x[j]
+              of '\0': 
+                localError(p.info, errXExpected, "}")
+                break
+              of '{': 
+                inc(j)
+                inc(curly)
+                llStreamWrite(p.outp, '{')
+              of '}': 
+                inc(j)
+                if curly == 0: break 
+                if curly > 0: dec(curly)
+                llStreamWrite(p.outp, '}')
+              else: 
+                llStreamWrite(p.outp, p.x[j])
+                inc(j)
+            llStreamWrite(p.outp, ')')
+            llStreamWrite(p.outp, p.conc)
+            llStreamWrite(p.outp, '\"')
+          of 'a'..'z', 'A'..'Z', '\x80'..'\xFF': 
+            llStreamWrite(p.outp, '\"')
+            llStreamWrite(p.outp, p.conc)
+            llStreamWrite(p.outp, p.toStr)
+            llStreamWrite(p.outp, '(')
+            while p.x[j] in PatternChars: 
+              llStreamWrite(p.outp, p.x[j])
+              inc(j)
+            llStreamWrite(p.outp, ')')
+            llStreamWrite(p.outp, p.conc)
+            llStreamWrite(p.outp, '\"')
+          else: 
+            if p.x[j] == p.subsChar: 
+              llStreamWrite(p.outp, p.subsChar)
+              inc(j)
+            else: 
+              p.info.col = int16(j)
+              localError(p.info, errInvalidExpression, "$")
+        else: 
+          llStreamWrite(p.outp, p.x[j])
+          inc(j)
+    llStreamWrite(p.outp, "\\n\"")
+
+proc filterTmpl(stdin: PLLStream, filename: string, call: PNode): PLLStream = 
+  var p: TTmplParser
+  p.info = newLineInfo(filename, 0, 0)
+  p.outp = llStreamOpen("")
+  p.inp = stdin
+  p.subsChar = charArg(call, "subschar", 1, '$')
+  p.nimDirective = charArg(call, "metachar", 2, '#')
+  p.emit = strArg(call, "emit", 3, "result.add")
+  p.conc = strArg(call, "conc", 4, " & ")
+  p.toStr = strArg(call, "tostring", 5, "$")
+  p.x = newStringOfCap(120)
+  while llStreamReadLine(p.inp, p.x):
+    p.info.line = p.info.line + int16(1)
+    parseLine(p)
+  newLine(p)
+  result = p.outp
+  llStreamClose(p.inp)
diff --git a/compiler/filters.nim b/compiler/filters.nim
new file mode 100644
index 000000000..783a320a4
--- /dev/null
+++ b/compiler/filters.nim
@@ -0,0 +1,79 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements Nim's simple filters and helpers for filters.
+
+import
+  llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, 
+  renderer
+
+proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream
+proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream
+  # helpers to retrieve arguments:
+proc charArg*(n: PNode, name: string, pos: int, default: char): char
+proc strArg*(n: PNode, name: string, pos: int, default: string): string
+proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool
+# implementation
+
+proc invalidPragma(n: PNode) = 
+  localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
+
+proc getArg(n: PNode, name: string, pos: int): PNode = 
+  result = nil
+  if n.kind in {nkEmpty..nkNilLit}: return 
+  for i in countup(1, sonsLen(n) - 1): 
+    if n.sons[i].kind == nkExprEqExpr: 
+      if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
+      if identEq(n.sons[i].sons[0].ident, name): 
+        return n.sons[i].sons[1]
+    elif i == pos: 
+      return n.sons[i]
+  
+proc charArg(n: PNode, name: string, pos: int, default: char): char = 
+  var x = getArg(n, name, pos)
+  if x == nil: result = default
+  elif x.kind == nkCharLit: result = chr(int(x.intVal))
+  else: invalidPragma(n)
+  
+proc strArg(n: PNode, name: string, pos: int, default: string): string = 
+  var x = getArg(n, name, pos)
+  if x == nil: result = default
+  elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
+  else: invalidPragma(n)
+  
+proc boolArg(n: PNode, name: string, pos: int, default: bool): bool = 
+  var x = getArg(n, name, pos)
+  if x == nil: result = default
+  elif (x.kind == nkIdent) and identEq(x.ident, "true"): result = true
+  elif (x.kind == nkIdent) and identEq(x.ident, "false"): result = false
+  else: invalidPragma(n)
+  
+proc filterStrip(stdin: PLLStream, filename: string, call: PNode): PLLStream = 
+  var pattern = strArg(call, "startswith", 1, "")
+  var leading = boolArg(call, "leading", 2, true)
+  var trailing = boolArg(call, "trailing", 3, true)
+  result = llStreamOpen("")
+  var line = newStringOfCap(80)
+  while llStreamReadLine(stdin, line):
+    var stripped = strip(line, leading, trailing)
+    if (len(pattern) == 0) or startsWith(stripped, pattern): 
+      llStreamWriteln(result, stripped)
+    else: 
+      llStreamWriteln(result, line)
+  llStreamClose(stdin)
+
+proc filterReplace(stdin: PLLStream, filename: string, call: PNode): PLLStream = 
+  var sub = strArg(call, "sub", 1, "")
+  if len(sub) == 0: invalidPragma(call)
+  var by = strArg(call, "by", 2, "")
+  result = llStreamOpen("")
+  var line = newStringOfCap(80)
+  while llStreamReadLine(stdin, line):
+    llStreamWriteln(result, replace(line, sub, by))
+  llStreamClose(stdin)
diff --git a/compiler/forloops.nim b/compiler/forloops.nim
new file mode 100644
index 000000000..efe000968
--- /dev/null
+++ b/compiler/forloops.nim
@@ -0,0 +1,89 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements for loop detection for better C code generation.
+
+import ast, astalgo
+
+const
+  someCmp = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
+    mEqUntracedRef, mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
+    mLeCh, mLeB, mLePtr, mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum, 
+    mLtCh, mLtB, mLtPtr}
+
+proc isCounter(s: PSym): bool {.inline.} =
+  s.kind in {skResult, skVar, skLet, skTemp} and 
+  {sfGlobal, sfAddrTaken} * s.flags == {}
+
+proc isCall(n: PNode): bool {.inline.} =
+  n.kind in nkCallKinds and n[0].kind == nkSym
+
+proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
+
+proc getCounter(lastStmt: PNode): PSym =
+  if lastStmt.isCall:
+    let op = lastStmt.sym
+    if op.magic in {mDec, mInc} or 
+        ((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem):
+      if op[1].kind == nkSym and isCounter(op[1].sym):
+        result = op[1].sym
+
+proc counterInTree(n, loop: PNode; counter: PSym): bool =
+  # prune the search tree: within the loop the counter may be used:
+  if n == loop: return
+  case n.kind
+  of nkSym:
+    if n.sym == counter: return true
+  of nkVarSection, nkLetSection:
+    # definitions are fine!
+    for it in n:
+      if counterInTree(it.lastSon): return true
+  else:
+    for i in 0 .. <safeLen(n):
+      if counterInTree(n[i], loop, counter): return true
+
+proc copyExcept(n: PNode, x, dest: PNode) =
+  if x == n: return
+  if n.kind in {nkStmtList, nkStmtListExpr}:
+    for i in 0 .. <n.len: copyExcept(n[i], x, dest)
+  else:
+    dest.add n
+
+type
+  ForLoop* = object
+    counter*: PSym
+    init*, cond*, increment*, body*: PNode
+
+proc extractForLoop*(loop, fullTree: PNode): ForLoop =
+  ## returns 'counter == nil' if the while loop 'n' is not a for loop:
+  assert loop.kind == nkWhileStmt
+  let cond == loop[0]
+
+  if not cond.isCall: return
+  if cond[0].sym.magic notin someCmp: return
+  
+  var lastStmt = loop[1]
+  while lastStmt.kind in {nkStmtList, nkStmtListExpr}:
+    lastStmt = lastStmt.lastSon
+
+  let counter = getCounter(lastStmt)
+  if counter.isNil or counter.ast.isNil: return
+
+  template `=~`(a, b): expr = a.kind == nkSym and a.sym == b
+  
+  if cond[1] =~ counter or cond[2] =~ counter:
+    # ok, now check 'counter' is not used *after* the loop
+    if counterInTree(fullTree, loop, counter): return
+    # ok, success, fill in the fields:
+    result.counter = counter
+    result.init = counter.ast
+    result.cond = cond
+    result.increment = lastStmt
+    result.body = newNodeI(nkStmtList, loop[1].info)
+    copyExcept(loop[1], lastStmt, result.body)
diff --git a/compiler/guards.nim b/compiler/guards.nim
new file mode 100644
index 000000000..df2c1dd75
--- /dev/null
+++ b/compiler/guards.nim
@@ -0,0 +1,912 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the 'implies' relation for guards.
+
+import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
+  saturate
+
+const
+  someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
+    mEqUntracedRef, mEqStr, mEqSet, mEqCString}
+
+  # set excluded here as the semantics are vastly different:
+  someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
+            mLeCh, mLeB, mLePtr, mLeStr}
+  someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
+            mLtCh, mLtB, mLtPtr, mLtStr}
+
+  someLen = {mLengthOpenArray, mLengthStr, mLengthArray, mLengthSeq,
+             mXLenStr, mXLenSeq}
+
+  someIn = {mInRange, mInSet}
+
+  someHigh = {mHigh}
+  # we don't list unsigned here because wrap around semantics suck for
+  # proving anything:
+  someAdd = {mAddI, mAddI64, mAddF64, mSucc}
+  someSub = {mSubI, mSubI64, mSubF64, mPred}
+  someMul = {mMulI, mMulI64, mMulF64}
+  someDiv = {mDivI, mDivI64, mDivF64}
+  someMod = {mModI, mModI64}
+  someMax = {mMaxI, mMaxF64}
+  someMin = {mMinI, mMinF64}
+
+proc isValue(n: PNode): bool = n.kind in {nkCharLit..nkNilLit}
+proc isLocation(n: PNode): bool = not n.isValue
+
+proc isLet(n: PNode): bool =
+  if n.kind == nkSym:
+    if n.sym.kind in {skLet, skTemp, skForVar}:
+      result = true
+    elif n.sym.kind == skParam and skipTypes(n.sym.typ,
+                                             abstractInst).kind != tyVar:
+      result = true
+
+proc isVar(n: PNode): bool =
+  n.kind == nkSym and n.sym.kind in {skResult, skVar} and
+      {sfGlobal, sfAddrTaken} * n.sym.flags == {}
+
+proc isLetLocation(m: PNode, isApprox: bool): bool =
+  # consider: 'n[].kind' --> we really need to support 1 deref op even if this
+  # is technically wrong due to aliasing :-( We could introduce "soft" facts
+  # for this; this would still be very useful for warnings and also nicely
+  # solves the 'var' problems. For now we fix this by requiring much more
+  # restrictive expressions for the 'not nil' checking.
+  var n = m
+  var derefs = 0
+  while true:
+    case n.kind
+    of nkDotExpr, nkCheckedFieldExpr, nkObjUpConv, nkObjDownConv:
+      n = n.sons[0]
+    of nkDerefExpr, nkHiddenDeref:
+      n = n.sons[0]
+      inc derefs
+    of nkBracketExpr:
+      if isConstExpr(n.sons[1]) or isLet(n.sons[1]):
+        n = n.sons[0]
+      else: return
+    of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+      n = n.sons[1]
+    else:
+      break
+  result = n.isLet and derefs <= ord(isApprox)
+  if not result and isApprox:
+    result = isVar(n)
+
+proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
+
+let
+  opLe = createMagic("<=", mLeI)
+  opLt = createMagic("<", mLtI)
+  opAnd = createMagic("and", mAnd)
+  opOr = createMagic("or", mOr)
+  opIsNil = createMagic("isnil", mIsNil)
+  opEq = createMagic("==", mEqI)
+  opAdd = createMagic("+", mAddI)
+  opSub = createMagic("-", mSubI)
+  opMul = createMagic("*", mMulI)
+  opDiv = createMagic("div", mDivI)
+  opLen = createMagic("len", mLengthSeq)
+
+proc swapArgs(fact: PNode, newOp: PSym): PNode =
+  result = newNodeI(nkCall, fact.info, 3)
+  result.sons[0] = newSymNode(newOp)
+  result.sons[1] = fact.sons[2]
+  result.sons[2] = fact.sons[1]
+
+proc neg(n: PNode): PNode =
+  if n == nil: return nil
+  case n.getMagic
+  of mNot:
+    result = n.sons[1]
+  of someLt:
+    # not (a < b)  ==  a >= b  ==  b <= a
+    result = swapArgs(n, opLe)
+  of someLe:
+    result = swapArgs(n, opLt)
+  of mInSet:
+    if n.sons[1].kind != nkCurly: return nil
+    let t = n.sons[2].typ.skipTypes(abstractInst)
+    result = newNodeI(nkCall, n.info, 3)
+    result.sons[0] = n.sons[0]
+    result.sons[2] = n.sons[2]
+    if t.kind == tyEnum:
+      var s = newNodeIT(nkCurly, n.info, n.sons[1].typ)
+      for e in t.n:
+        let eAsNode = newIntNode(nkIntLit, e.sym.position)
+        if not inSet(n.sons[1], eAsNode): s.add eAsNode
+      result.sons[1] = s
+    elif t.kind notin {tyString, tySequence} and lengthOrd(t) < 1000:
+      result.sons[1] = complement(n.sons[1])
+    else:
+      # not ({2, 3, 4}.contains(x))   x != 2 and x != 3 and x != 4
+      # XXX todo
+      result = nil
+  of mOr:
+    # not (a or b) --> not a and not b
+    let
+      a = n.sons[1].neg
+      b = n.sons[2].neg
+    if a != nil and b != nil:
+      result = newNodeI(nkCall, n.info, 3)
+      result.sons[0] = newSymNode(opAnd)
+      result.sons[1] = a
+      result.sons[2] = b
+    elif a != nil:
+      result = a
+    elif b != nil:
+      result = b
+  else:
+    # leave  not (a == 4)  as it is
+    result = newNodeI(nkCall, n.info, 2)
+    result.sons[0] = newSymNode(opNot)
+    result.sons[1] = n
+
+proc buildCall(op: PSym; a: PNode): PNode =
+  result = newNodeI(nkCall, a.info, 2)
+  result.sons[0] = newSymNode(op)
+  result.sons[1] = a
+
+proc buildCall(op: PSym; a, b: PNode): PNode =
+  result = newNodeI(nkInfix, a.info, 3)
+  result.sons[0] = newSymNode(op)
+  result.sons[1] = a
+  result.sons[2] = b
+
+proc `|+|`(a, b: PNode): PNode =
+  result = copyNode(a)
+  if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |+| b.intVal
+  else: result.floatVal = a.floatVal + b.floatVal
+
+proc `|*|`(a, b: PNode): PNode =
+  result = copyNode(a)
+  if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal |*| b.intVal
+  else: result.floatVal = a.floatVal * b.floatVal
+
+proc negate(a, b, res: PNode): PNode =
+  if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt):
+    var b = copyNode(b)
+    b.intVal = -b.intVal
+    if a.kind in {nkCharLit..nkUInt64Lit}:
+      b.intVal = b.intVal |+| a.intVal
+      result = b
+    else:
+      result = buildCall(opAdd, a, b)
+  elif b.kind in {nkFloatLit..nkFloat64Lit}:
+    var b = copyNode(b)
+    b.floatVal = -b.floatVal
+    result = buildCall(opAdd, a, b)
+  else:
+    result = res
+
+proc zero(): PNode = nkIntLit.newIntNode(0)
+proc one(): PNode = nkIntLit.newIntNode(1)
+proc minusOne(): PNode = nkIntLit.newIntNode(-1)
+
+proc lowBound*(x: PNode): PNode =
+  result = nkIntLit.newIntNode(firstOrd(x.typ))
+  result.info = x.info
+
+proc highBound*(x: PNode): PNode =
+  let typ = x.typ.skipTypes(abstractInst)
+  result = if typ.kind in {tyArrayConstr, tyArray}:
+             nkIntLit.newIntNode(lastOrd(typ))
+           elif typ.kind == tySequence and x.kind == nkSym and
+               x.sym.kind == skConst:
+             nkIntLit.newIntNode(x.sym.ast.len-1)
+           else:
+             opAdd.buildCall(opLen.buildCall(x), minusOne())
+  result.info = x.info
+
+proc reassociation(n: PNode): PNode =
+  result = n
+  # (foo+5)+5 --> foo+10;  same for '*'
+  case result.getMagic
+  of someAdd:
+    if result[2].isValue and
+        result[1].getMagic in someAdd and result[1][2].isValue:
+      result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
+  of someMul:
+    if result[2].isValue and
+        result[1].getMagic in someMul and result[1][2].isValue:
+      result = opAdd.buildCall(result[1][1], result[1][2] |*| result[2])
+  else: discard
+
+proc pred(n: PNode): PNode =
+  if n.kind in {nkCharLit..nkUInt64Lit} and n.intVal != low(BiggestInt):
+    result = copyNode(n)
+    dec result.intVal
+  else:
+    result = n
+
+proc canon*(n: PNode): PNode =
+  # XXX for now only the new code in 'semparallel' uses this
+  if n.safeLen >= 1:
+    result = shallowCopy(n)
+    for i in 0 .. < n.len:
+      result.sons[i] = canon(n.sons[i])
+  elif n.kind == nkSym and n.sym.kind == skLet and
+      n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
+      someMax + someHigh + {mUnaryLt} + someSub + someLen):
+    result = n.sym.ast.copyTree
+  else:
+    result = n
+  case result.getMagic
+  of someEq, someAdd, someMul, someMin, someMax:
+    # these are symmetric; put value as last:
+    if result.sons[1].isValue and not result.sons[2].isValue:
+      result = swapArgs(result, result.sons[0].sym)
+      # (4 + foo) + 2 --> (foo + 4) + 2
+  of someHigh:
+    # high == len+(-1)
+    result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
+  of mUnaryLt:
+    result = buildCall(opAdd, result[1], newIntNode(nkIntLit, -1))
+  of someSub:
+    # x - 4  -->  x + (-4)
+    result = negate(result[1], result[2], result)
+  of someLen:
+    result.sons[0] = opLen.newSymNode
+  of someLt:
+    # x < y  same as x <= y-1:
+    let y = n[2].canon
+    let p = pred(y)
+    let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon
+    result = opLe.buildCall(n[1].canon, minus)
+  else: discard
+
+  result = skipConv(result)
+  result = reassociation(result)
+  # most important rule: (x-4) <= a.len -->  x <= a.len+4
+  case result.getMagic
+  of someLe:
+    let x = result[1]
+    let y = result[2]
+    if x.kind in nkCallKinds and x.len == 3 and x[2].isValue and
+        isLetLocation(x[1], true):
+      case x.getMagic
+      of someSub:
+        result = buildCall(result[0].sym, x[1],
+                           reassociation(opAdd.buildCall(y, x[2])))
+      of someAdd:
+        # Rule A:
+        let plus = negate(y, x[2], nil).reassociation
+        if plus != nil: result = buildCall(result[0].sym, x[1], plus)
+      else: discard
+    elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
+        isLetLocation(y[1], true):
+      # a.len < x-3
+      case y.getMagic
+      of someSub:
+        result = buildCall(result[0].sym, y[1],
+                           reassociation(opAdd.buildCall(x, y[2])))
+      of someAdd:
+        let plus = negate(x, y[2], nil).reassociation
+        # ensure that Rule A will not trigger afterwards with the
+        # additional 'not isLetLocation' constraint:
+        if plus != nil and not isLetLocation(x, true):
+          result = buildCall(result[0].sym, plus, y[1])
+      else: discard
+  else: discard
+
+proc `+@`*(a: PNode; b: BiggestInt): PNode =
+  canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a)
+
+proc usefulFact(n: PNode): PNode =
+  case n.getMagic
+  of someEq:
+    if skipConv(n.sons[2]).kind == nkNilLit and (
+        isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
+      result = opIsNil.buildCall(n.sons[1])
+    else:
+      if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
+        # XXX algebraic simplifications!  'i-1 < a.len' --> 'i < a.len+1'
+        result = n
+  of someLe+someLt:
+    if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
+      # XXX algebraic simplifications!  'i-1 < a.len' --> 'i < a.len+1'
+      result = n
+  of mIsNil:
+    if isLetLocation(n.sons[1], false) or isVar(n.sons[1]):
+      result = n
+  of someIn:
+    if isLetLocation(n.sons[1], true):
+      result = n
+  of mAnd:
+    let
+      a = usefulFact(n.sons[1])
+      b = usefulFact(n.sons[2])
+    if a != nil and b != nil:
+      result = newNodeI(nkCall, n.info, 3)
+      result.sons[0] = newSymNode(opAnd)
+      result.sons[1] = a
+      result.sons[2] = b
+    elif a != nil:
+      result = a
+    elif b != nil:
+      result = b
+  of mNot:
+    let a = usefulFact(n.sons[1])
+    if a != nil:
+      result = a.neg
+  of mOr:
+    # 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
+    # with that knowledge...
+    # DeMorgan helps a little though:
+    #   not a or not b --> not (a and b)
+    #  (x == 3) or (y == 2)  ---> not ( not (x==3) and not (y == 2))
+    #  not (x != 3 and y != 2)
+    let
+      a = usefulFact(n.sons[1]).neg
+      b = usefulFact(n.sons[2]).neg
+    if a != nil and b != nil:
+      result = newNodeI(nkCall, n.info, 3)
+      result.sons[0] = newSymNode(opAnd)
+      result.sons[1] = a
+      result.sons[2] = b
+      result = result.neg
+  elif n.kind == nkSym and n.sym.kind == skLet:
+    # consider:
+    #   let a = 2 < x
+    #   if a:
+    #     ...
+    # We make can easily replace 'a' by '2 < x' here:
+    if n.sym.ast != nil:
+      result = usefulFact(n.sym.ast)
+  elif n.kind == nkStmtListExpr:
+    result = usefulFact(n.lastSon)
+
+type
+  TModel* = seq[PNode] # the "knowledge base"
+
+proc addFact*(m: var TModel, n: PNode) =
+  let n = usefulFact(n)
+  if n != nil: m.add n
+
+proc addFactNeg*(m: var TModel, n: PNode) =
+  let n = n.neg
+  if n != nil: addFact(m, n)
+
+proc canonOpr(opr: PSym): PSym =
+  case opr.magic
+  of someEq: result = opEq
+  of someLe: result = opLe
+  of someLt: result = opLt
+  of someLen: result = opLen
+  of someAdd: result = opAdd
+  of someSub: result = opSub
+  of someMul: result = opMul
+  of someDiv: result = opDiv
+  else: result = opr
+
+proc sameTree*(a, b: PNode): bool =
+  result = false
+  if a == b:
+    result = true
+  elif a != nil and b != nil and a.kind == b.kind:
+    case a.kind
+    of nkSym:
+      result = a.sym == b.sym
+      if not result and a.sym.magic != mNone:
+        result = a.sym.magic == b.sym.magic or canonOpr(a.sym) == canonOpr(b.sym)
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkType: result = a.typ == b.typ
+    of nkEmpty, nkNilLit: result = true
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameTree(a.sons[i], b.sons[i]): return
+        result = true
+
+proc hasSubTree(n, x: PNode): bool =
+  if n.sameTree(x): result = true
+  else:
+    for i in 0..safeLen(n)-1:
+      if hasSubTree(n.sons[i], x): return true
+
+proc invalidateFacts*(m: var TModel, n: PNode) =
+  # We are able to guard local vars (as opposed to 'let' variables)!
+  # 'while p != nil: f(p); p = p.next'
+  # This is actually quite easy to do:
+  # Re-assignments (incl. pass to a 'var' param) trigger an invalidation
+  # of every fact that contains 'v'.
+  #
+  #   if x < 4:
+  #     if y < 5
+  #       x = unknown()
+  #       # we invalidate 'x' here but it's known that x >= 4
+  #       # for the else anyway
+  #   else:
+  #     echo x
+  #
+  # The same mechanism could be used for more complex data stored on the heap;
+  # procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
+  # could CSE these expressions then and help C's optimizer.
+  for i in 0..high(m):
+    if m[i] != nil and m[i].hasSubTree(n): m[i] = nil
+
+proc valuesUnequal(a, b: PNode): bool =
+  if a.isValue and b.isValue:
+    result = not sameValue(a, b)
+
+proc impliesEq(fact, eq: PNode): TImplication =
+  let (loc, val) = if isLocation(eq.sons[1]): (1, 2) else: (2, 1)
+
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], eq.sons[loc]):
+      # this is not correct; consider:  a == b;  a == 1 --> unknown!
+      if sameTree(fact.sons[2], eq.sons[val]): result = impYes
+      elif valuesUnequal(fact.sons[2], eq.sons[val]): result = impNo
+    elif sameTree(fact.sons[2], eq.sons[loc]):
+      if sameTree(fact.sons[1], eq.sons[val]): result = impYes
+      elif valuesUnequal(fact.sons[1], eq.sons[val]): result = impNo
+  of mInSet:
+    # remember: mInSet is 'contains' so the set comes first!
+    if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
+      if inSet(fact.sons[1], eq.sons[val]): result = impYes
+      else: result = impNo
+  of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
+  else: discard
+
+proc leImpliesIn(x, c, aSet: PNode): TImplication =
+  if c.kind in {nkCharLit..nkUInt64Lit}:
+    # fact:  x <= 4;  question x in {56}?
+    # --> true if every value <= 4 is in the set {56}
+    #
+    var value = newIntNode(c.kind, firstOrd(x.typ))
+    # don't iterate too often:
+    if c.intVal - value.intVal < 1000:
+      var i, pos, neg: int
+      while value.intVal <= c.intVal:
+        if inSet(aSet, value): inc pos
+        else: inc neg
+        inc i; inc value.intVal
+      if pos == i: result = impYes
+      elif neg == i: result = impNo
+
+proc geImpliesIn(x, c, aSet: PNode): TImplication =
+  if c.kind in {nkCharLit..nkUInt64Lit}:
+    # fact:  x >= 4;  question x in {56}?
+    # --> true iff every value >= 4 is in the set {56}
+    #
+    var value = newIntNode(c.kind, c.intVal)
+    let max = lastOrd(x.typ)
+    # don't iterate too often:
+    if max - value.intVal < 1000:
+      var i, pos, neg: int
+      while value.intVal <= max:
+        if inSet(aSet, value): inc pos
+        else: inc neg
+        inc i; inc value.intVal
+      if pos == i: result = impYes
+      elif neg == i: result = impNo
+
+proc compareSets(a, b: PNode): TImplication =
+  if equalSets(a, b): result = impYes
+  elif intersectSets(a, b).len == 0: result = impNo
+
+proc impliesIn(fact, loc, aSet: PNode): TImplication =
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], loc):
+      if inSet(aSet, fact.sons[2]): result = impYes
+      else: result = impNo
+    elif sameTree(fact.sons[2], loc):
+      if inSet(aSet, fact.sons[1]): result = impYes
+      else: result = impNo
+  of mInSet:
+    if sameTree(fact.sons[2], loc):
+      result = compareSets(fact.sons[1], aSet)
+  of someLe:
+    if sameTree(fact.sons[1], loc):
+      result = leImpliesIn(fact.sons[1], fact.sons[2], aSet)
+    elif sameTree(fact.sons[2], loc):
+      result = geImpliesIn(fact.sons[2], fact.sons[1], aSet)
+  of someLt:
+    if sameTree(fact.sons[1], loc):
+      result = leImpliesIn(fact.sons[1], fact.sons[2].pred, aSet)
+    elif sameTree(fact.sons[2], loc):
+      # 4 < x  -->  3 <= x
+      result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
+  of mNot, mOr, mAnd: internalError(loc.info, "impliesIn")
+  else: discard
+
+proc valueIsNil(n: PNode): TImplication =
+  if n.kind == nkNilLit: impYes
+  elif n.kind in {nkStrLit..nkTripleStrLit, nkBracket, nkObjConstr}: impNo
+  else: impUnknown
+
+proc impliesIsNil(fact, eq: PNode): TImplication =
+  case fact.sons[0].sym.magic
+  of mIsNil:
+    if sameTree(fact.sons[1], eq.sons[1]):
+      result = impYes
+  of someEq:
+    if sameTree(fact.sons[1], eq.sons[1]):
+      result = valueIsNil(fact.sons[2].skipConv)
+    elif sameTree(fact.sons[2], eq.sons[1]):
+      result = valueIsNil(fact.sons[1].skipConv)
+  of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
+  else: discard
+
+proc impliesGe(fact, x, c: PNode): TImplication =
+  internalAssert isLocation(x)
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x = 4;  question x >= 56? --> true iff 4 >= 56
+        if leValue(c, fact.sons[2]): result = impYes
+        else: result = impNo
+    elif sameTree(fact.sons[2], x):
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c, fact.sons[1]): result = impYes
+        else: result = impNo
+  of someLt:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x < 4;  question N <= x? --> false iff N <= 4
+        if leValue(fact.sons[2], c): result = impNo
+        # fact:  x < 4;  question 2 <= x? --> we don't know
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 < x; question: N-1 < x ?  --> true iff N-1 <= 3
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c.pred, fact.sons[1]): result = impYes
+  of someLe:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x <= 4;  question x >= 56? --> false iff 4 <= 56
+        if leValue(fact.sons[2], c): result = impNo
+        # fact:  x <= 4;  question x >= 2? --> we don't know
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 <= x; question: x >= 2 ?  --> true iff 2 <= 3
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c, fact.sons[1]): result = impYes
+  of mNot, mOr, mAnd: internalError(x.info, "impliesGe")
+  else: discard
+
+proc impliesLe(fact, x, c: PNode): TImplication =
+  if not isLocation(x):
+    return impliesGe(fact, c, x)
+  case fact.sons[0].sym.magic
+  of someEq:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x = 4;  question x <= 56? --> true iff 4 <= 56
+        if leValue(fact.sons[2], c): result = impYes
+        else: result = impNo
+    elif sameTree(fact.sons[2], x):
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(fact.sons[1], c): result = impYes
+        else: result = impNo
+  of someLt:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x < 4;  question x <= N? --> true iff N-1 <= 4
+        if leValue(fact.sons[2], c.pred): result = impYes
+        # fact:  x < 4;  question x <= 2? --> we don't know
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 < x; question: x <= 1 ?  --> false iff 1 <= 3
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c, fact.sons[1]): result = impNo
+
+  of someLe:
+    if sameTree(fact.sons[1], x):
+      if isValue(fact.sons[2]) and isValue(c):
+        # fact:  x <= 4;  question x <= 56? --> true iff 4 <= 56
+        if leValue(fact.sons[2], c): result = impYes
+        # fact:  x <= 4;  question x <= 2? --> we don't know
+
+    elif sameTree(fact.sons[2], x):
+      # fact: 3 <= x; question: x <= 2 ?  --> false iff 2 < 3
+      if isValue(fact.sons[1]) and isValue(c):
+        if leValue(c, fact.sons[1].pred): result = impNo
+
+  of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
+  else: discard
+
+proc impliesLt(fact, x, c: PNode): TImplication =
+  # x < 3  same as x <= 2:
+  let p = c.pred
+  if p != c:
+    result = impliesLe(fact, x, p)
+  else:
+    # 4 < x  same as 3 <= x
+    let q = x.pred
+    if q != x:
+      result = impliesLe(fact, q, c)
+
+proc `~`(x: TImplication): TImplication =
+  case x
+  of impUnknown: impUnknown
+  of impNo: impYes
+  of impYes: impNo
+
+proc factImplies(fact, prop: PNode): TImplication =
+  case fact.getMagic
+  of mNot:
+    # Consider:
+    # enum nkBinary, nkTernary, nkStr
+    # fact:      not (k <= nkBinary)
+    # question:  k in {nkStr}
+    # --> 'not' for facts is entirely different than 'not' for questions!
+    # it's provably wrong if every value > 4 is in the set {56}
+    # That's because we compute the implication and  'a -> not b' cannot
+    # be treated the same as 'not a -> b'
+
+    #  (not a) -> b  compute as  not (a -> b) ???
+    #  == not a or not b == not (a and b)
+    let arg = fact.sons[1]
+    case arg.getMagic
+    of mIsNil, mEqRef:
+      return ~factImplies(arg, prop)
+    of mAnd:
+      # not (a and b)  means  not a or not b:
+      # a or b --> both need to imply 'prop'
+      let a = factImplies(arg.sons[1], prop)
+      let b = factImplies(arg.sons[2], prop)
+      if a == b: return ~a
+      return impUnknown
+    else:
+      return impUnknown
+  of mAnd:
+    result = factImplies(fact.sons[1], prop)
+    if result != impUnknown: return result
+    return factImplies(fact.sons[2], prop)
+  else: discard
+
+  case prop.sons[0].sym.magic
+  of mNot: result = ~fact.factImplies(prop.sons[1])
+  of mIsNil: result = impliesIsNil(fact, prop)
+  of someEq: result = impliesEq(fact, prop)
+  of someLe: result = impliesLe(fact, prop.sons[1], prop.sons[2])
+  of someLt: result = impliesLt(fact, prop.sons[1], prop.sons[2])
+  of mInSet: result = impliesIn(fact, prop.sons[2], prop.sons[1])
+  else: result = impUnknown
+
+proc doesImply*(facts: TModel, prop: PNode): TImplication =
+  assert prop.kind in nkCallKinds
+  for f in facts:
+    # facts can be invalidated, in which case they are 'nil':
+    if not f.isNil:
+      result = f.factImplies(prop)
+      if result != impUnknown: return
+
+proc impliesNotNil*(facts: TModel, arg: PNode): TImplication =
+  result = doesImply(facts, opIsNil.buildCall(arg).neg)
+
+proc simpleSlice*(a, b: PNode): BiggestInt =
+  # returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched
+  # as if it is (i+0)..(i+0).
+  if guards.sameTree(a, b):
+    if a.getMagic in someAdd and a[2].kind in {nkCharLit..nkUInt64Lit}:
+      result = a[2].intVal
+    else:
+      result = 0
+  else:
+    result = -1
+
+proc pleViaModel(model: TModel; aa, bb: PNode): TImplication
+
+proc ple(m: TModel; a, b: PNode): TImplication =
+  template `<=?`(a,b): expr = ple(m,a,b) == impYes
+
+  #   0 <= 3
+  if a.isValue and b.isValue:
+    return if leValue(a, b): impYes else: impNo
+
+  # use type information too:  x <= 4  iff  high(x) <= 4
+  if b.isValue and a.typ != nil and a.typ.isOrdinalType:
+    if lastOrd(a.typ) <= b.intVal: return impYes
+  # 3 <= x   iff  low(x) <= 3
+  if a.isValue and b.typ != nil and b.typ.isOrdinalType:
+    if firstOrd(b.typ) <= a.intVal: return impYes
+
+  # x <= x
+  if sameTree(a, b): return impYes
+
+  # 0 <= x.len
+  if b.getMagic in someLen and a.isValue:
+    if a.intVal <= 0: return impYes
+
+  #   x <= y+c  if 0 <= c and x <= y
+  if b.getMagic in someAdd and zero() <=? b[2] and a <=? b[1]: return impYes
+
+  #   x+c <= y  if c <= 0 and x <= y
+  if a.getMagic in someAdd and a[2] <=? zero() and a[1] <=? b: return impYes
+
+  #   x <= y*c  if  1 <= c and x <= y  and 0 <= y
+  if b.getMagic in someMul:
+    if a <=? b[1] and one() <=? b[2] and zero() <=? b[1]: return impYes
+
+  #   x div c <= y   if   1 <= c  and  0 <= y  and x <= y:
+  if a.getMagic in someDiv:
+    if one() <=? a[2] and zero() <=? b and a[1] <=? b: return impYes
+
+  # slightly subtle:
+  # x <= max(y, z)  iff x <= y or x <= z
+  # note that 'x <= max(x, z)' is a special case of the above rule
+  if b.getMagic in someMax:
+    if a <=? b[1] or a <=? b[2]: return impYes
+
+  # min(x, y) <= z  iff x <= z or y <= z
+  if a.getMagic in someMin:
+    if a[1] <=? b or a[2] <=? b: return impYes
+
+  # use the knowledge base:
+  return pleViaModel(m, a, b)
+  #return doesImply(m, opLe.buildCall(a, b))
+
+type TReplacements = seq[tuple[a,b: PNode]]
+
+proc replaceSubTree(n, x, by: PNode): PNode =
+  if sameTree(n, x):
+    result = by
+  elif hasSubTree(n, x):
+    result = shallowCopy(n)
+    for i in 0 .. safeLen(n)-1:
+      result.sons[i] = replaceSubTree(n.sons[i], x, by)
+  else:
+    result = n
+
+proc applyReplacements(n: PNode; rep: TReplacements): PNode =
+  result = n
+  for x in rep: result = result.replaceSubTree(x.a, x.b)
+
+proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
+  # now check for inferrable facts: a <= b and b <= c  implies a <= c
+  for i in 0..m.high:
+    let fact = m[i]
+    if fact != nil and fact.getMagic in someLe:
+      # x <= y implies a <= b  if  a <= x and y <= b
+      let x = fact[1]
+      let y = fact[2]
+      # mark as used:
+      m[i] = nil
+      if ple(m, a, x) == impYes:
+        if ple(m, y, b) == impYes:
+          return impYes
+        #if pleViaModelRec(m, y, b): return impYes
+      # fact:  16 <= i
+      #         x    y
+      # question: i <= 15? no!
+      result = impliesLe(fact, a, b)
+      if result != impUnknown:
+        return result
+      when false:
+        # given: x <= y;  y==a;  x <= a this means: a <= b  if  x <= b
+        if sameTree(y, a):
+          result = ple(m, b, x)
+          if result != impUnknown:
+            return result
+
+proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
+  # compute replacements:
+  var replacements: TReplacements = @[]
+  for fact in model:
+    if fact != nil and fact.getMagic in someEq:
+      let a = fact[1]
+      let b = fact[2]
+      if a.kind == nkSym: replacements.add((a,b))
+      else: replacements.add((b,a))
+  var m: TModel
+  var a = aa
+  var b = bb
+  if replacements.len > 0:
+    m = @[]
+    # make the other facts consistent:
+    for fact in model:
+      if fact != nil and fact.getMagic notin someEq:
+        # XXX 'canon' should not be necessary here, but it is
+        m.add applyReplacements(fact, replacements).canon
+    a = applyReplacements(aa, replacements)
+    b = applyReplacements(bb, replacements)
+  else:
+    # we have to make a copy here, because the model will be modified:
+    m = model
+  result = pleViaModelRec(m, a, b)
+
+proc proveLe*(m: TModel; a, b: PNode): TImplication =
+  let x = canon(opLe.buildCall(a, b))
+  #echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2])
+  result = ple(m, x[1], x[2])
+  if result == impUnknown:
+    # try an alternative:  a <= b  iff  not (b < a)  iff  not (b+1 <= a):
+    let y = canon(opLe.buildCall(opAdd.buildCall(b, one()), a))
+    result = ~ple(m, y[1], y[2])
+
+proc addFactLe*(m: var TModel; a, b: PNode) =
+  m.add canon(opLe.buildCall(a, b))
+
+proc settype(n: PNode): PType =
+  result = newType(tySet, n.typ.owner)
+  addSonSkipIntLit(result, n.typ)
+
+proc buildOf(it, loc: PNode): PNode =
+  var s = newNodeI(nkCurly, it.info, it.len-1)
+  s.typ = settype(loc)
+  for i in 0..it.len-2: s.sons[i] = it.sons[i]
+  result = newNodeI(nkCall, it.info, 3)
+  result.sons[0] = newSymNode(opContains)
+  result.sons[1] = s
+  result.sons[2] = loc
+
+proc buildElse(n: PNode): PNode =
+  var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
+  for i in 1..n.len-2:
+    let branch = n.sons[i]
+    assert branch.kind == nkOfBranch
+    for j in 0..branch.len-2:
+      s.add(branch.sons[j])
+  result = newNodeI(nkCall, n.info, 3)
+  result.sons[0] = newSymNode(opContains)
+  result.sons[1] = s
+  result.sons[2] = n.sons[0]
+
+proc addDiscriminantFact*(m: var TModel, n: PNode) =
+  var fact = newNodeI(nkCall, n.info, 3)
+  fact.sons[0] = newSymNode(opEq)
+  fact.sons[1] = n.sons[0]
+  fact.sons[2] = n.sons[1]
+  m.add fact
+
+proc addAsgnFact*(m: var TModel, key, value: PNode) =
+  var fact = newNodeI(nkCall, key.info, 3)
+  fact.sons[0] = newSymNode(opEq)
+  fact.sons[1] = key
+  fact.sons[2] = value
+  m.add fact
+
+proc sameSubexprs*(m: TModel; a, b: PNode): bool =
+  # This should be used to check whether two *path expressions* refer to the
+  # same memory location according to 'm'. This is tricky:
+  # lock a[i].guard:
+  #   ...
+  #   access a[i].guarded
+  #
+  # Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'.
+  # However, nil checking requires exactly the same mechanism! But for now
+  # we simply use sameTree and live with the unsoundness of the analysis.
+  var check = newNodeI(nkCall, a.info, 3)
+  check.sons[0] = newSymNode(opEq)
+  check.sons[1] = a
+  check.sons[2] = b
+  result = m.doesImply(check) == impYes
+
+proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
+  let branch = n.sons[i]
+  if branch.kind == nkOfBranch:
+    m.add buildOf(branch, n.sons[0])
+  else:
+    m.add n.buildElse.neg
+
+proc buildProperFieldCheck(access, check: PNode): PNode =
+  if check.sons[1].kind == nkCurly:
+    result = copyTree(check)
+    if access.kind == nkDotExpr:
+      var a = copyTree(access)
+      a.sons[1] = check.sons[2]
+      result.sons[2] = a
+      # 'access.kind != nkDotExpr' can happen for object constructors
+      # which we don't check yet
+  else:
+    # it is some 'not'
+    assert check.getMagic == mNot
+    result = buildProperFieldCheck(access, check.sons[1]).neg
+
+proc checkFieldAccess*(m: TModel, n: PNode) =
+  for i in 1..n.len-1:
+    let check = buildProperFieldCheck(n.sons[0], n.sons[i])
+    if check != nil and m.doesImply(check) != impYes:
+      message(n.info, warnProveField, renderTree(n.sons[0])); break
diff --git a/compiler/hlo.nim b/compiler/hlo.nim
new file mode 100644
index 000000000..363d100be
--- /dev/null
+++ b/compiler/hlo.nim
@@ -0,0 +1,103 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include implements the high level optimization pass.
+
+proc hlo(c: PContext, n: PNode): PNode
+
+proc evalPattern(c: PContext, n, orig: PNode): PNode =
+  internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
+  # we need to ensure that the resulting AST is semchecked. However, it's
+  # aweful to semcheck before macro invocation, so we don't and treat
+  # templates and macros as immediate in this context.
+  var rule: string
+  if optHints in gOptions and hintPattern in gNotes:
+    rule = renderTree(n, {renderNoComments})
+  let s = n.sons[0].sym
+  case s.kind
+  of skMacro:
+    result = semMacroExpr(c, n, orig, s)
+  of skTemplate:
+    result = semTemplateExpr(c, n, s)
+  else:
+    result = semDirectOp(c, n, {})
+  if optHints in gOptions and hintPattern in gNotes:
+    message(orig.info, hintPattern, rule & " --> '" & 
+      renderTree(result, {renderNoComments}) & "'")
+
+proc applyPatterns(c: PContext, n: PNode): PNode =
+  result = n
+  # we apply the last pattern first, so that pattern overriding is possible;
+  # however the resulting AST would better not trigger the old rule then
+  # anymore ;-)
+  for i in countdown(<c.patterns.len, 0):
+    let pattern = c.patterns[i]
+    if not isNil(pattern):
+      let x = applyRule(c, pattern, result)
+      if not isNil(x):
+        assert x.kind in {nkStmtList, nkCall}
+        # better be safe than sorry, so check evalTemplateCounter too:
+        inc(evalTemplateCounter)
+        if evalTemplateCounter > 100:
+          globalError(n.info, errTemplateInstantiationTooNested)
+        # deactivate this pattern:
+        c.patterns[i] = nil
+        if x.kind == nkStmtList:
+          assert x.len == 3
+          x.sons[1] = evalPattern(c, x.sons[1], result)
+          result = flattenStmts(x)
+        else:
+          result = evalPattern(c, x, result)
+        dec(evalTemplateCounter)
+        # activate this pattern again:
+        c.patterns[i] = pattern
+
+proc hlo(c: PContext, n: PNode): PNode =
+  inc(c.hloLoopDetector)
+  # simply stop and do not perform any further transformations:
+  if c.hloLoopDetector > 300: return n
+  case n.kind
+  of nkMacroDef, nkTemplateDef, procDefs:
+    # already processed (special cases in semstmts.nim)
+    result = n
+  else:
+    if n.kind in {nkFastAsgn, nkAsgn, nkIdentDefs, nkVarTuple} and
+        n.sons[0].kind == nkSym and 
+        {sfGlobal, sfPure} * n.sons[0].sym.flags == {sfGlobal, sfPure}:
+      # do not optimize 'var g {.global} = re(...)' again!
+      return n
+    result = applyPatterns(c, n)
+    if result == n:
+      # no optimization applied, try subtrees:
+      for i in 0 .. < safeLen(result):
+        let a = result.sons[i]
+        let h = hlo(c, a)
+        if h != a: result.sons[i] = h
+    else:
+      # perform type checking, so that the replacement still fits:
+      if isEmptyType(n.typ) and isEmptyType(result.typ):
+        discard
+      else:
+        result = fitNode(c, n.typ, result)
+      # optimization has been applied so check again:
+      result = commonOptimizations(c.module, result)
+      result = hlo(c, result)
+      result = commonOptimizations(c.module, result)
+
+proc hloBody(c: PContext, n: PNode): PNode =
+  # fast exit:
+  if c.patterns.len == 0 or optPatterns notin gOptions: return n
+  c.hloLoopDetector = 0
+  result = hlo(c, n)
+
+proc hloStmt(c: PContext, n: PNode): PNode =
+  # fast exit:
+  if c.patterns.len == 0 or optPatterns notin gOptions: return n
+  c.hloLoopDetector = 0
+  result = hlo(c, n)
diff --git a/compiler/idents.nim b/compiler/idents.nim
new file mode 100644
index 000000000..0cca18929
--- /dev/null
+++ b/compiler/idents.nim
@@ -0,0 +1,110 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Identifier handling
+# An identifier is a shared immutable string that can be compared by its
+# id. This module is essential for the compiler's performance.
+
+import 
+  hashes, strutils
+
+type 
+  TIdObj* = object of RootObj
+    id*: int # unique id; use this for comparisons and not the pointers
+  
+  PIdObj* = ref TIdObj
+  PIdent* = ref TIdent
+  TIdent*{.acyclic.} = object of TIdObj
+    s*: string
+    next*: PIdent             # for hash-table chaining
+    h*: THash                 # hash value of s
+
+var firstCharIsCS*: bool = true
+var buckets*: array[0..4096 * 2 - 1, PIdent]
+
+proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
+  if firstCharIsCS:
+    if a[0] != b[0]: return 1
+  var i = 0
+  var j = 0
+  result = 1
+  while j < blen:
+    while a[i] == '_': inc(i)
+    while b[j] == '_': inc(j)
+    # tolower inlined:
+    var aa = a[i]
+    var bb = b[j]
+    if aa >= 'A' and aa <= 'Z': aa = chr(ord(aa) + (ord('a') - ord('A')))
+    if bb >= 'A' and bb <= 'Z': bb = chr(ord(bb) + (ord('a') - ord('A')))
+    result = ord(aa) - ord(bb)
+    if (result != 0) or (aa == '\0'): break 
+    inc(i)
+    inc(j)
+  if result == 0:
+    if a[i] != '\0': result = 1
+  
+proc cmpExact(a, b: cstring, blen: int): int =
+  var i = 0
+  var j = 0
+  result = 1
+  while j < blen:
+    var aa = a[i]
+    var bb = b[j]
+    result = ord(aa) - ord(bb)
+    if (result != 0) or (aa == '\0'): break 
+    inc(i)
+    inc(j)
+  if result == 0: 
+    if a[i] != '\0': result = 1
+
+var wordCounter = 1
+
+proc getIdent*(identifier: cstring, length: int, h: THash): PIdent =
+  var idx = h and high(buckets)
+  result = buckets[idx]
+  var last: PIdent = nil
+  var id = 0
+  while result != nil: 
+    if cmpExact(cstring(result.s), identifier, length) == 0: 
+      if last != nil: 
+        # make access to last looked up identifier faster:
+        last.next = result.next
+        result.next = buckets[idx]
+        buckets[idx] = result
+      return 
+    elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
+      assert((id == 0) or (id == result.id))
+      id = result.id
+    last = result
+    result = result.next
+  new(result)
+  result.h = h
+  result.s = newString(length)
+  for i in countup(0, length - 1): result.s[i] = identifier[i]
+  result.next = buckets[idx]
+  buckets[idx] = result
+  if id == 0: 
+    inc(wordCounter)
+    result.id = -wordCounter
+  else: 
+    result.id = id
+
+proc getIdent*(identifier: string): PIdent = 
+  result = getIdent(cstring(identifier), len(identifier), 
+                    hashIgnoreStyle(identifier))
+
+proc getIdent*(identifier: string, h: THash): PIdent = 
+  result = getIdent(cstring(identifier), len(identifier), h)
+
+proc identEq*(id: PIdent, name: string): bool = 
+  result = id.id == getIdent(name).id
+
+var idAnon* = getIdent":anonymous"
+let idDelegator* = getIdent":delegator"
+
diff --git a/compiler/idgen.nim b/compiler/idgen.nim
new file mode 100644
index 000000000..3c5669b54
--- /dev/null
+++ b/compiler/idgen.nim
@@ -0,0 +1,65 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains a simple persistent id generator.
+
+import idents, strutils, os, options
+
+var gFrontEndId, gBackendId*: int
+
+const
+  debugIds* = false
+
+when debugIds:
+  import intsets
+  
+  var usedIds = initIntSet()
+
+proc registerID*(id: PIdObj) = 
+  when debugIds: 
+    if id.id == -1 or containsOrIncl(usedIds, id.id): 
+      internalError("ID already used: " & $id.id)
+
+proc getID*(): int {.inline.} = 
+  result = gFrontEndId
+  inc(gFrontEndId)
+
+proc backendId*(): int {.inline.} = 
+  result = gBackendId
+  inc(gBackendId)
+
+proc setId*(id: int) {.inline.} = 
+  gFrontEndId = max(gFrontEndId, id + 1)
+
+proc idSynchronizationPoint*(idRange: int) = 
+  gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
+
+proc toGid(f: string): string =
+  # we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
+  # will cause strange bugs if multiple projects are in the same folder, so
+  # we simply use a project independent name:
+  result = options.completeGeneratedFilePath("nimrod.gid")
+
+proc saveMaxIds*(project: string) =
+  var f = open(project.toGid, fmWrite)
+  f.writeln($gFrontEndId)
+  f.writeln($gBackendId)
+  f.close()
+  
+proc loadMaxIds*(project: string) =
+  var f: File
+  if open(f, project.toGid, fmRead):
+    var line = newStringOfCap(20)
+    if f.readLine(line):
+      var frontEndId = parseInt(line)
+      if f.readLine(line):
+        var backEndId = parseInt(line)
+        gFrontEndId = max(gFrontEndId, frontEndId)
+        gBackendId = max(gBackendId, backEndId)
+    f.close()
diff --git a/compiler/importer.nim b/compiler/importer.nim
new file mode 100644
index 000000000..d619725db
--- /dev/null
+++ b/compiler/importer.nim
@@ -0,0 +1,201 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the symbol importing mechanism.
+
+import
+  intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
+  semdata, passes, renderer
+
+proc evalImport*(c: PContext, n: PNode): PNode
+proc evalFrom*(c: PContext, n: PNode): PNode
+
+proc getModuleName*(n: PNode): string =
+  # This returns a short relative module name without the nim extension
+  # e.g. like "system", "importer" or "somepath/module"
+  # The proc won't perform any checks that the path is actually valid
+  case n.kind
+  of nkStrLit, nkRStrLit, nkTripleStrLit:
+    result = unixToNativePath(n.strVal)
+  of nkIdent:
+    result = n.ident.s
+  of nkSym:
+    result = n.sym.name.s
+  of nkInfix, nkPrefix:
+    if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
+      # XXX hack ahead:
+      n.kind = nkImportAs
+      n.sons[0] = n.sons[1]
+      n.sons[1] = n.sons[2]
+      n.sons.setLen(2)
+      return getModuleName(n.sons[0])
+    # hacky way to implement 'x / y /../ z':
+    result = renderTree(n, {renderNoComments}).replace(" ")
+  of nkDotExpr:
+    result = renderTree(n, {renderNoComments}).replace(".", "/")
+  of nkImportAs:
+    result = getModuleName(n.sons[0])
+  else:
+    localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
+    result = ""
+
+proc checkModuleName*(n: PNode): int32 =
+  # This returns the full canonical path for a given module import
+  let modulename = n.getModuleName
+  let fullPath = findModule(modulename, n.info.toFullPath)
+  if fullPath.len == 0:
+    localError(n.info, errCannotOpenFile, modulename)
+    result = InvalidFileIDX
+  else:
+    result = fullPath.fileInfoIdx
+
+proc rawImportSymbol(c: PContext, s: PSym) =
+  # This does not handle stubs, because otherwise loading on demand would be
+  # pointless in practice. So importing stubs is fine here!
+  # check if we have already a symbol of the same name:
+  var check = strTableGet(c.importTable.symbols, s.name)
+  if check != nil and check.id != s.id:
+    if s.kind notin OverloadableSyms:
+      # s and check need to be qualified:
+      incl(c.ambiguousSymbols, s.id)
+      incl(c.ambiguousSymbols, check.id)
+  # thanks to 'export' feature, it could be we import the same symbol from
+  # multiple sources, so we need to call 'StrTableAdd' here:
+  strTableAdd(c.importTable.symbols, s)
+  if s.kind == skType:
+    var etyp = s.typ
+    if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
+      for j in countup(0, sonsLen(etyp.n) - 1):
+        var e = etyp.n.sons[j].sym
+        if e.kind != skEnumField:
+          internalError(s.info, "rawImportSymbol")
+          # BUGFIX: because of aliases for enums the symbol may already
+          # have been put into the symbol table
+          # BUGFIX: but only iff they are the same symbols!
+        var it: TIdentIter
+        check = initIdentIter(it, c.importTable.symbols, e.name)
+        while check != nil:
+          if check.id == e.id:
+            e = nil
+            break
+          check = nextIdentIter(it, c.importTable.symbols)
+        if e != nil:
+          rawImportSymbol(c, e)
+  else:
+    # rodgen assures that converters and patterns are no stubs
+    if s.kind == skConverter: addConverter(c, s)
+    if hasPattern(s): addPattern(c, s)
+
+proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
+  let ident = lookups.considerQuotedIdent(n)
+  let s = strTableGet(fromMod.tab, ident)
+  if s == nil:
+    localError(n.info, errUndeclaredIdentifier, ident.s)
+  else:
+    if s.kind == skStub: loadStub(s)
+    if s.kind notin ExportableSymKinds:
+      internalError(n.info, "importSymbol: 2")
+    # for an enumeration we have to add all identifiers
+    case s.kind
+    of skProcKinds:
+      # for a overloadable syms add all overloaded routines
+      var it: TIdentIter
+      var e = initIdentIter(it, fromMod.tab, s.name)
+      while e != nil:
+        if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
+        rawImportSymbol(c, e)
+        e = nextIdentIter(it, fromMod.tab)
+    else: rawImportSymbol(c, s)
+
+proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
+  var i: TTabIter
+  var s = initTabIter(i, fromMod.tab)
+  while s != nil:
+    if s.kind != skModule:
+      if s.kind != skEnumField:
+        if s.kind notin ExportableSymKinds:
+          internalError(s.info, "importAllSymbols: " & $s.kind)
+        if exceptSet.empty or s.name.id notin exceptSet:
+          rawImportSymbol(c, s)
+    s = nextIter(i, fromMod.tab)
+
+proc importAllSymbols*(c: PContext, fromMod: PSym) =
+  var exceptSet: IntSet
+  importAllSymbolsExcept(c, fromMod, exceptSet)
+
+proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
+  if n.isNil: return
+  case n.kind
+  of nkExportStmt:
+    for a in n:
+      assert a.kind == nkSym
+      let s = a.sym
+      if s.kind == skModule:
+        importAllSymbolsExcept(c, s, exceptSet)
+      elif exceptSet.empty or s.name.id notin exceptSet:
+        rawImportSymbol(c, s)
+  of nkExportExceptStmt:
+    localError(n.info, errGenerated, "'export except' not implemented")
+  else:
+    for i in 0..safeLen(n)-1:
+      importForwarded(c, n.sons[i], exceptSet)
+
+proc importModuleAs(n: PNode, realModule: PSym): PSym =
+  result = realModule
+  if n.kind != nkImportAs: discard
+  elif n.len != 2 or n.sons[1].kind != nkIdent:
+    localError(n.info, errGenerated, "module alias must be an identifier")
+  elif n.sons[1].ident.id != realModule.name.id:
+    # some misguided guy will write 'import abc.foo as foo' ...
+    result = createModuleAlias(realModule, n.sons[1].ident, realModule.info)
+
+proc myImportModule(c: PContext, n: PNode): PSym =
+  var f = checkModuleName(n)
+  if f != InvalidFileIDX:
+    result = importModuleAs(n, gImportModule(c.module, f))
+    if result.info.fileIndex == n.info.fileIndex:
+      localError(n.info, errGenerated, "A module cannot import itself")
+    if sfDeprecated in result.flags:
+      message(n.info, warnDeprecated, result.name.s)
+
+proc evalImport(c: PContext, n: PNode): PNode =
+  result = n
+  var emptySet: IntSet
+  for i in countup(0, sonsLen(n) - 1):
+    var m = myImportModule(c, n.sons[i])
+    if m != nil:
+      # ``addDecl`` needs to be done before ``importAllSymbols``!
+      addDecl(c, m)             # add symbol to symbol table of module
+      importAllSymbolsExcept(c, m, emptySet)
+      #importForwarded(c, m.ast, emptySet)
+
+proc evalFrom(c: PContext, n: PNode): PNode =
+  result = n
+  checkMinSonsLen(n, 2)
+  var m = myImportModule(c, n.sons[0])
+  if m != nil:
+    n.sons[0] = newSymNode(m)
+    addDecl(c, m)               # add symbol to symbol table of module
+    for i in countup(1, sonsLen(n) - 1):
+      if n.sons[i].kind != nkNilLit:
+        importSymbol(c, n.sons[i], m)
+
+proc evalImportExcept*(c: PContext, n: PNode): PNode =
+  result = n
+  checkMinSonsLen(n, 2)
+  var m = myImportModule(c, n.sons[0])
+  if m != nil:
+    n.sons[0] = newSymNode(m)
+    addDecl(c, m)               # add symbol to symbol table of module
+    var exceptSet = initIntSet()
+    for i in countup(1, sonsLen(n) - 1):
+      let ident = lookups.considerQuotedIdent(n.sons[i])
+      exceptSet.incl(ident.id)
+    importAllSymbolsExcept(c, m, exceptSet)
+    #importForwarded(c, m.ast, exceptSet)
diff --git a/compiler/installer.ini b/compiler/installer.ini
new file mode 100644
index 000000000..821309a34
--- /dev/null
+++ b/compiler/installer.ini
@@ -0,0 +1,272 @@
+; This config file holds configuration information about the Nim compiler
+; and project.
+
+[Project]
+Name: "Nim"
+Version: "$version"
+Platforms: """
+  windows: i386;amd64
+  linux: i386;amd64;powerpc64;arm;sparc;mips;powerpc
+  macosx: i386;amd64;powerpc64
+  solaris: i386;amd64;sparc
+  freebsd: i386;amd64
+  netbsd: i386;amd64
+  openbsd: i386;amd64
+  haiku: i386;amd64
+"""
+
+Authors: "Andreas Rumpf"
+Description: """This is the Nim Compiler. Nim is a new statically typed,
+imperative programming language, that supports procedural, functional, object
+oriented and generic programming styles while remaining simple and efficient.
+A special feature that Nim inherited from Lisp is that Nim's abstract
+syntax tree (AST) is part of the specification - this allows a powerful macro
+system which can be used to create domain specific languages.
+
+Nim is a compiled, garbage-collected systems programming language
+which has an excellent productivity/performance ratio. Nim's design
+focuses on the 3E: efficiency, expressiveness, elegance (in the order of
+priority)."""
+
+App: Console
+License: "copying.txt"
+
+[Config]
+Files: "config/nim.cfg"
+Files: "config/nimdoc.cfg"
+Files: "config/nimdoc.tex.cfg"
+
+[Documentation]
+; Files: "doc/*.html"
+; Files: "doc/*.cfg"
+; Files: "doc/*.pdf"
+; Files: "doc/*.ini"
+Files: "doc/overview.html"
+Start: "doc/overview.html"
+
+
+[Other]
+Files: "readme.txt;install.txt;contributors.txt;copying.txt"
+Files: "makefile"
+Files: "*.ini"
+Files: "koch.nim"
+
+Files: "icons/nim.ico"
+Files: "icons/nim.rc"
+Files: "icons/nim.res"
+Files: "icons/nim_icon.o"
+Files: "icons/koch.ico"
+Files: "icons/koch.rc"
+Files: "icons/koch.res"
+Files: "icons/koch_icon.o"
+
+Files: "compiler/readme.txt"
+Files: "compiler/installer.ini"
+Files: "compiler/nim.nim.cfg"
+Files: "compiler/*.nim"
+Files: "doc/*.txt"
+Files: "doc/manual/*.txt"
+Files: "doc/*.nim"
+Files: "doc/*.cfg"
+Files: "compiler/nimfix/*.nim"
+Files: "compiler/nimfix/*.cfg"
+Files: "compiler/nimsuggest/*.nim"
+Files: "compiler/nimsuggest/*.cfg"
+Files: "compiler/plugins/locals/*.nim"
+Files: "compiler/plugins/active.nim"
+Files: "tools/*.nim"
+Files: "tools/*.cfg"
+Files: "tools/*.tmpl"
+Files: "tools/niminst/*.nim"
+Files: "tools/niminst/*.cfg"
+Files: "tools/niminst/*.tmpl"
+Files: "tools/niminst/*.nsh"
+Files: "web/website.ini"
+Files: "web/*.nim"
+Files: "web/*.txt"
+
+[Lib]
+Files: "lib/nimbase.h"
+Files: "lib/*.nim"
+Files: "lib/*.cfg"
+
+Files: "lib/system/*.nim"
+Files: "lib/core/*.nim"
+Files: "lib/pure/*.nim"
+Files: "lib/pure/*.cfg"
+Files: "lib/pure/collections/*.nim"
+Files: "lib/pure/concurrency/*.nim"
+Files: "lib/pure/unidecode/*.nim"
+Files: "lib/pure/concurrency/*.cfg"
+Files: "lib/impure/*.nim"
+Files: "lib/wrappers/*.nim"
+
+Files: "lib/wrappers/readline/*.nim"
+Files: "lib/wrappers/sdl/*.nim"
+Files: "lib/wrappers/zip/*.nim"
+Files: "lib/wrappers/zip/libzip_all.c"
+
+Files: "lib/windows/*.nim"
+Files: "lib/posix/*.nim"
+Files: "lib/js/*.nim"
+Files: "lib/packages/docutils/*.nim"
+
+
+[Other]
+Files: "examples/*.nim"
+Files: "examples/c++iface/*.nim"
+Files: "examples/objciface/*.nim"
+Files: "examples/cross_calculator/"
+
+Files: "examples/*.html"
+Files: "examples/*.txt"
+Files: "examples/*.cfg"
+Files: "examples/*.tmpl"
+
+Files: "tests/actiontable/*.nim"
+Files: "tests/alias/*.nim"
+Files: "tests/ambsym/*.nim"
+Files: "tests/array/*.nim"
+Files: "tests/assign/*.nim"
+Files: "tests/astoverload/*.nim"
+Files: "tests/async/*.nim"
+Files: "tests/benchmarks/*.nim"
+Files: "tests/bind/*.nim"
+Files: "tests/borrow/*.nim"
+Files: "tests/casestmt/*.nim"
+Files: "tests/ccgbugs/*.nim"
+Files: "tests/clearmsg/*.nim"
+Files: "tests/closure/*.nim"
+Files: "tests/cnstseq/*.nim"
+Files: "tests/collections/*.nim"
+Files: "tests/compiles/*.nim"
+Files: "tests/concat/*.nim"
+Files: "tests/concepts/*.nim"
+Files: "tests/constr/*.nim"
+Files: "tests/constraints/*.nim"
+Files: "tests/controlflow/*.nim"
+Files: "tests/converter/*.nim"
+Files: "tests/cpp/*.nim"
+Files: "tests/defaultprocparam/*.nim"
+Files: "tests/deprecated/*.nim"
+Files: "tests/destructor/*.nim"
+Files: "tests/dir with space/*.nim"
+Files: "tests/discard/*.nim"
+Files: "tests/distinct/*.nim"
+Files: "tests/dll/*.nim"
+Files: "tests/effects/*.nim"
+Files: "tests/enum/*.nim"
+Files: "tests/exception/*.nim"
+Files: "tests/exprs/*.nim"
+Files: "tests/fields/*.nim"
+Files: "tests/float/*.nim"
+Files: "tests/friends/*.nim"
+Files: "tests/gc/*.nim"
+Files: "tests/generics/*.nim"
+Files: "tests/gensym/*.nim"
+Files: "tests/global/*.nim"
+Files: "tests/implicit/*.nim"
+Files: "tests/init/*.nim"
+Files: "tests/iter/*.nim"
+Files: "tests/js/*.nim"
+Files: "tests/js/*.cfg"
+Files: "tests/let/*.nim"
+Files: "tests/lexer/*.nim"
+Files: "tests/lookups/*.nim"
+Files: "tests/macros/*.nim"
+Files: "tests/magics/*.nim"
+Files: "tests/metatype/*.nim"
+Files: "tests/method/*.nim"
+Files: "tests/misc/*.nim"
+Files: "tests/modules/*.nim"
+Files: "tests/namedparams/*.nim"
+Files: "tests/notnil/*.nim"
+Files: "tests/objects/*.nim"
+Files: "tests/objvariant/*.nim"
+Files: "tests/openarray/*.nim"
+Files: "tests/osproc/*.nim"
+Files: "tests/overflw/*.nim"
+Files: "tests/overload/*.nim"
+Files: "tests/parallel/*.nim"
+Files: "tests/parallel/*.cfg"
+Files: "tests/parser/*.nim"
+Files: "tests/pragmas/*.nim"
+Files: "tests/proc/*.nim"
+Files: "tests/procvar/*.nim"
+Files: "tests/range/*.nim"
+Files: "tests/rodfiles/*.nim"
+Files: "tests/seq/*.nim"
+Files: "tests/sets/*.nim"
+Files: "tests/showoff/*.nim"
+Files: "tests/specialops/*.nim"
+Files: "tests/stdlib/*.nim"
+Files: "tests/system/*.nim"
+Files: "tests/template/*.nim"
+Files: "tests/testament/*.nim"
+Files: "tests/testdata/*.csv"
+Files: "tests/testdata/*.html"
+Files: "tests/testdata/*.json"
+Files: "tests/testdata/*.txt"
+Files: "tests/testdata/*.xml"
+Files: "tests/threads/*.nim"
+Files: "tests/threads/*.cfg"
+Files: "tests/trmacros/*.nim"
+Files: "tests/tuples/*.nim"
+Files: "tests/typerel/*.nim"
+Files: "tests/types/*.nim"
+Files: "tests/usingstmt/*.nim"
+Files: "tests/varres/*.nim"
+Files: "tests/varstmt/*.nim"
+Files: "tests/vm/*.nim"
+Files: "tests/readme.txt"
+Files: "tests/testament/css/*.css"
+Files: "tests/testament/*.cfg"
+Files: "lib/pure/unidecode/unidecode.dat"
+
+[Windows]
+Files: "bin/nim.exe"
+Files: "bin/c2nim.exe"
+Files: "bin/nimgrep.exe"
+Files: "bin/nimsuggest.exe"
+Files: "bin/nimble.exe"
+Files: "bin/*.dll"
+
+Files: "dist/*.dll"
+Files: "koch.exe"
+; Files: "dist/mingw"
+Files: "start.bat"
+BinPath: r"bin;dist\mingw\bin;dist"
+
+;           Section | dir | zipFile | size hint (in KB) | url | exe start menu entry
+Download: r"Documentation|doc|docs.zip|13824|http://nim-lang.org/download/docs-${version}.zip|overview.html"
+Download: r"C Compiler (MingW)|dist|mingw.zip|82944|http://nim-lang.org/download/${mingw}.zip"
+Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia-0.3.0.zip|aporia-0.3.0\bin\aporia.exe"
+; for now only NSIS supports optional downloads
+
+[UnixBin]
+Files: "bin/nim"
+
+
+[Unix]
+InstallScript: "yes"
+UninstallScript: "yes"
+
+
+[InnoSetup]
+path = r"c:\Program Files (x86)\Inno Setup 5\iscc.exe"
+flags = "/Q"
+
+[NSIS]
+path = r"c:\Program Files (x86)\NSIS\makensis.exe"
+flags = "/V0"
+
+[C_Compiler]
+path = r""
+flags = "-w"
+
+
+[deb]
+buildDepends: "gcc (>= 4:4.3.2)"
+pkgDepends: "gcc (>= 4:4.3.2)"
+shortDesc: "The Nim Compiler"
+licenses: "bin/nim,MIT;lib/*,MIT;"
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
new file mode 100644
index 000000000..0f6323abc
--- /dev/null
+++ b/compiler/jsgen.nim
@@ -0,0 +1,1759 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This is the JavaScript code generator.
+# Soon also a Luajit code generator. ;-)
+
+discard """
+The JS code generator contains only 2 tricks:
+
+Trick 1
+-------
+Some locations (for example 'var int') require "fat pointers" (``etyBaseIndex``)
+which are pairs (array, index). The derefence operation is then 'array[index]'.
+Check ``mapType`` for the details.
+
+Trick 2
+-------
+It is preferable to generate '||' and '&&' if possible since that is more
+idiomatic and hence should be friendlier for the JS JIT implementation. However
+code like ``foo and (let bar = baz())`` cannot be translated this way. Instead
+the expressions need to be transformed into statements. ``isSimpleExpr``
+implements the required case distinction.
+"""
+
+
+import
+  ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
+  options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
+  times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
+  intsets, cgmeth, lowerings
+
+type
+  TTarget = enum
+    targetJS, targetLua
+  TJSGen = object of TPassContext
+    module: PSym
+
+  BModule = ref TJSGen
+  TJSTypeKind = enum       # necessary JS "types"
+    etyNone,                  # no type
+    etyNull,                  # null type
+    etyProc,                  # proc type
+    etyBool,                  # bool type
+    etyInt,                   # JavaScript's int
+    etyFloat,                 # JavaScript's float
+    etyString,                # JavaScript's string
+    etyObject,                # JavaScript's reference to an object
+    etyBaseIndex              # base + index needed
+  TResKind = enum
+    resNone,                  # not set
+    resExpr,                  # is some complex expression
+    resVal                    # is a temporary/value/l-value
+  TCompRes = object
+    kind: TResKind
+    typ: TJSTypeKind
+    res: Rope               # result part; index if this is an
+                             # (address, index)-tuple
+    address: Rope           # address of an (address, index)-tuple
+
+  TBlock = object
+    id: int                  # the ID of the label; positive means that it
+                             # has been used (i.e. the label should be emitted)
+    isLoop: bool             # whether it's a 'block' or 'while'
+
+  TGlobals = object
+    typeInfo, code: Rope
+    forwarded: seq[PSym]
+    generatedSyms: IntSet
+    typeInfoGenerated: IntSet
+
+  PGlobals = ref TGlobals
+  PProc = ref TProc
+  TProc = object
+    procDef: PNode
+    prc: PSym
+    locals, body: Rope
+    options: TOptions
+    module: BModule
+    g: PGlobals
+    beforeRetNeeded: bool
+    target: TTarget # duplicated here for faster dispatching
+    unique: int    # for temp identifier generation
+    blocks: seq[TBlock]
+    up: PProc     # up the call chain; required for closure support
+
+template `|`(a, b: expr): expr {.immediate, dirty.} =
+  (if p.target == targetJS: a else: b)
+
+proc newGlobals(): PGlobals =
+  new(result)
+  result.forwarded = @[]
+  result.generatedSyms = initIntSet()
+  result.typeInfoGenerated = initIntSet()
+
+proc initCompRes(r: var TCompRes) =
+  r.address = nil
+  r.res = nil
+  r.typ = etyNone
+  r.kind = resNone
+
+proc rdLoc(a: TCompRes): Rope {.inline.} =
+  result = a.res
+  when false:
+    if a.typ != etyBaseIndex:
+      result = a.res
+    else:
+      result = "$1[$2]" % [a.address, a.res]
+
+proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
+             options: TOptions): PProc =
+  result = PProc(
+    blocks: @[],
+    options: options,
+    module: module,
+    procDef: procDef,
+    g: globals)
+  if procDef != nil: result.prc = procDef.sons[namePos].sym
+
+const
+  MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
+    tySet, tyBigNum, tyVarargs}
+
+proc mapType(typ: PType): TJSTypeKind =
+  let t = skipTypes(typ, abstractInst)
+  case t.kind
+  of tyVar, tyRef, tyPtr:
+    if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
+      result = etyObject
+    else:
+      result = etyBaseIndex
+  of tyPointer:
+    # treat a tyPointer like a typed pointer to an array of bytes
+    result = etyInt
+  of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy:
+    result = mapType(t.sons[0])
+  of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
+  of tyBool: result = etyBool
+  of tyFloat..tyFloat128: result = etyFloat
+  of tySet: result = etyObject # map a set to a table
+  of tyString, tySequence: result = etyInt # little hack to get right semantics
+  of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
+     tyVarargs:
+    result = etyObject
+  of tyNil: result = etyNull
+  of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
+     tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
+     tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
+    result = etyNone
+  of tyProc: result = etyProc
+  of tyCString: result = etyString
+
+proc mangleName(s: PSym): Rope =
+  result = s.loc.r
+  if result == nil:
+    result = rope(mangle(s.name.s))
+    add(result, "_")
+    add(result, rope(s.id))
+    s.loc.r = result
+
+proc makeJSString(s: string): Rope =
+  (if s.isNil: "null".rope else: strutils.escape(s).rope)
+
+include jstypes
+
+proc gen(p: PProc, n: PNode, r: var TCompRes)
+proc genStmt(p: PProc, n: PNode)
+proc genProc(oldProc: PProc, prc: PSym): Rope
+proc genConstant(p: PProc, c: PSym)
+
+proc useMagic(p: PProc, name: string) =
+  if name.len == 0: return
+  var s = magicsys.getCompilerProc(name)
+  if s != nil:
+    internalAssert s.kind in {skProc, skMethod, skConverter}
+    if not p.g.generatedSyms.containsOrIncl(s.id):
+      add(p.g.code, genProc(p, s))
+  else:
+    # we used to exclude the system module from this check, but for DLL
+    # generation support this sloppyness leads to hard to detect bugs, so
+    # we're picky here for the system module too:
+    if p.prc != nil: globalError(p.prc.info, errSystemNeeds, name)
+    else: rawMessage(errSystemNeeds, name)
+
+proc isSimpleExpr(n: PNode): bool =
+  # calls all the way down --> can stay expression based
+  if n.kind in nkCallKinds+{nkBracketExpr, nkBracket, nkCurly, nkDotExpr, nkPar,
+                            nkObjConstr}:
+    for c in n:
+      if not c.isSimpleExpr: return false
+    result = true
+  elif n.isAtom:
+    result = true
+
+proc getTemp(p: PProc): Rope =
+  inc(p.unique)
+  result = "Tmp$1" % [rope(p.unique)]
+  addf(p.locals, "var $1;$n" | "local $1;$n", [result])
+
+proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
+  assert r.kind == resNone
+  var x, y: TCompRes
+  if a.isSimpleExpr and b.isSimpleExpr:
+    gen(p, a, x)
+    gen(p, b, y)
+    r.kind = resExpr
+    r.res = ("($1 && $2)" | "($1 and $2)") % [x.rdLoc, y.rdLoc]
+  else:
+    r.res = p.getTemp
+    r.kind = resVal
+    # while a and b:
+    # -->
+    # while true:
+    #   aa
+    #   if not a: tmp = false
+    #   else:
+    #     bb
+    #     tmp = b
+    # tmp
+    gen(p, a, x)
+    p.body.addf("if (!$1) $2 = false; else {" |
+                "if not $1 then $2 = false; else", [x.rdLoc, r.rdLoc])
+    gen(p, b, y)
+    p.body.addf("$2 = $1; }" |
+                "$2 = $1 end", [y.rdLoc, r.rdLoc])
+
+proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
+  assert r.kind == resNone
+  var x, y: TCompRes
+  if a.isSimpleExpr and b.isSimpleExpr:
+    gen(p, a, x)
+    gen(p, b, y)
+    r.kind = resExpr
+    r.res = ("($1 || $2)" | "($1 or $2)") % [x.rdLoc, y.rdLoc]
+  else:
+    r.res = p.getTemp
+    r.kind = resVal
+    gen(p, a, x)
+    p.body.addf("if ($1) $2 = true; else {" |
+                "if $1 then $2 = true; else", [x.rdLoc, r.rdLoc])
+    gen(p, b, y)
+    p.body.addf("$2 = $1; }" |
+                "$2 = $1 end", [y.rdLoc, r.rdLoc])
+
+type
+  TMagicFrmt = array[0..3, string]
+  TMagicOps = array[mAddI..mStrToStr, TMagicFrmt]
+
+const # magic checked op; magic unchecked op; checked op; unchecked op
+  jsOps: TMagicOps = [
+    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # AddI
+    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # SubI
+    ["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
+    ["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
+    ["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
+    ["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
+    ["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
+    ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
+    ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
+    ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
+    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
+    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
+    ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
+    ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
+    ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
+    ["", "", "($1 / $2)", "($1 / $2)"], # DivF64
+    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI
+    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI
+    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI
+    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI
+    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
+    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
+    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
+    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
+    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
+    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
+    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
+    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
+    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
+    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
+    ["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
+    ["subU", "subU", "subU($1, $2)", "subU($1, $2)"], # subU
+    ["mulU", "mulU", "mulU($1, $2)", "mulU($1, $2)"], # mulU
+    ["divU", "divU", "divU($1, $2)", "divU($1, $2)"], # divU
+    ["modU", "modU", "modU($1, $2)", "modU($1, $2)"], # modU
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqI
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtI
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqI64
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtI64
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqF64
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtF64
+    ["leU", "leU", "leU($1, $2)", "leU($1, $2)"], # leU
+    ["ltU", "ltU", "ltU($1, $2)", "ltU($1, $2)"], # ltU
+    ["leU64", "leU64", "leU64($1, $2)", "leU64($1, $2)"], # leU64
+    ["ltU64", "ltU64", "ltU64($1, $2)", "ltU64($1, $2)"], # ltU64
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqEnum
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeEnum
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtEnum
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqCh
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeCh
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtCh
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqB
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeB
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtB
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqRef
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqUntracedRef
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqCString
+    ["", "", "($1 != $2)", "($1 != $2)"], # Xor
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqProc
+    ["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
+    ["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
+    ["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
+    ["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
+    ["", "", "!($1)", "!($1)"], # Not
+    ["", "", "+($1)", "+($1)"], # UnaryPlusI
+    ["", "", "~($1)", "~($1)"], # BitnotI
+    ["", "", "~($1)", "~($1)"], # BitnotI64
+    ["", "", "+($1)", "+($1)"], # UnaryPlusF64
+    ["", "", "-($1)", "-($1)"], # UnaryMinusF64
+    ["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
+    ["Ze8ToI", "Ze8ToI", "Ze8ToI($1)", "Ze8ToI($1)"], # mZe8ToI
+    ["Ze8ToI64", "Ze8ToI64", "Ze8ToI64($1)", "Ze8ToI64($1)"], # mZe8ToI64
+    ["Ze16ToI", "Ze16ToI", "Ze16ToI($1)", "Ze16ToI($1)"], # mZe16ToI
+    ["Ze16ToI64", "Ze16ToI64", "Ze16ToI64($1)", "Ze16ToI64($1)"], # mZe16ToI64
+    ["Ze32ToI64", "Ze32ToI64", "Ze32ToI64($1)", "Ze32ToI64($1)"], # mZe32ToI64
+    ["ZeIToI64", "ZeIToI64", "ZeIToI64($1)", "ZeIToI64($1)"], # mZeIToI64
+    ["toU8", "toU8", "toU8($1)", "toU8($1)"], # toU8
+    ["toU16", "toU16", "toU16($1)", "toU16($1)"], # toU16
+    ["toU32", "toU32", "toU32($1)", "toU32($1)"], # toU32
+    ["", "", "$1", "$1"],     # ToFloat
+    ["", "", "$1", "$1"],     # ToBiggestFloat
+    ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
+    ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
+    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
+    ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
+      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
+      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
+                                   "cstrToNimstr(($1)+\"\")",
+                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
+      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
+    ["", "", "$1", "$1"]]
+
+  luaOps: TMagicOps = [
+    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # AddI
+    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # SubI
+    ["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
+    ["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
+    ["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
+    ["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
+    ["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
+    ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
+    ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
+    ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
+    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
+    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
+    ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
+    ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
+    ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
+    ["", "", "($1 / $2)", "($1 / $2)"], # DivF64
+    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI
+    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI
+    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI
+    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI
+    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
+    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
+    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
+    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
+    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
+    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
+    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
+    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
+    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
+    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
+    ["addU", "addU", "addU($1, $2)", "addU($1, $2)"], # addU
+    ["subU", "subU", "subU($1, $2)", "subU($1, $2)"], # subU
+    ["mulU", "mulU", "mulU($1, $2)", "mulU($1, $2)"], # mulU
+    ["divU", "divU", "divU($1, $2)", "divU($1, $2)"], # divU
+    ["modU", "modU", "modU($1, $2)", "modU($1, $2)"], # modU
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqI
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtI
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqI64
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtI64
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqF64
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtF64
+    ["leU", "leU", "leU($1, $2)", "leU($1, $2)"], # leU
+    ["ltU", "ltU", "ltU($1, $2)", "ltU($1, $2)"], # ltU
+    ["leU64", "leU64", "leU64($1, $2)", "leU64($1, $2)"], # leU64
+    ["ltU64", "ltU64", "ltU64($1, $2)", "ltU64($1, $2)"], # ltU64
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqEnum
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeEnum
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtEnum
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqCh
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeCh
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtCh
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqB
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeB
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtB
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqRef
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqUntracedRef
+    ["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
+    ["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqCString
+    ["", "", "($1 != $2)", "($1 != $2)"], # Xor
+    ["", "", "($1 == $2)", "($1 == $2)"], # EqProc
+    ["negInt", "", "negInt($1)", "-($1)"], # UnaryMinusI
+    ["negInt64", "", "negInt64($1)", "-($1)"], # UnaryMinusI64
+    ["absInt", "", "absInt($1)", "Math.abs($1)"], # AbsI
+    ["absInt64", "", "absInt64($1)", "Math.abs($1)"], # AbsI64
+    ["", "", "not ($1)", "not ($1)"], # Not
+    ["", "", "+($1)", "+($1)"], # UnaryPlusI
+    ["", "", "~($1)", "~($1)"], # BitnotI
+    ["", "", "~($1)", "~($1)"], # BitnotI64
+    ["", "", "+($1)", "+($1)"], # UnaryPlusF64
+    ["", "", "-($1)", "-($1)"], # UnaryMinusF64
+    ["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
+    ["Ze8ToI", "Ze8ToI", "Ze8ToI($1)", "Ze8ToI($1)"], # mZe8ToI
+    ["Ze8ToI64", "Ze8ToI64", "Ze8ToI64($1)", "Ze8ToI64($1)"], # mZe8ToI64
+    ["Ze16ToI", "Ze16ToI", "Ze16ToI($1)", "Ze16ToI($1)"], # mZe16ToI
+    ["Ze16ToI64", "Ze16ToI64", "Ze16ToI64($1)", "Ze16ToI64($1)"], # mZe16ToI64
+    ["Ze32ToI64", "Ze32ToI64", "Ze32ToI64($1)", "Ze32ToI64($1)"], # mZe32ToI64
+    ["ZeIToI64", "ZeIToI64", "ZeIToI64($1)", "ZeIToI64($1)"], # mZeIToI64
+    ["toU8", "toU8", "toU8($1)", "toU8($1)"], # toU8
+    ["toU16", "toU16", "toU16($1)", "toU16($1)"], # toU16
+    ["toU32", "toU32", "toU32($1)", "toU32($1)"], # toU32
+    ["", "", "$1", "$1"],     # ToFloat
+    ["", "", "$1", "$1"],     # ToBiggestFloat
+    ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
+    ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
+    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
+    ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
+      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
+      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
+                                   "cstrToNimstr(($1)+\"\")",
+                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
+      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
+    ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
+    ["", "", "$1", "$1"]]
+
+proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
+  var x, y: TCompRes
+  useMagic(p, magic)
+  gen(p, n.sons[1], x)
+  gen(p, n.sons[2], y)
+  r.res = frmt % [x.rdLoc, y.rdLoc]
+  r.kind = resExpr
+
+proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
+  var x, y, z: TCompRes
+  useMagic(p, magic)
+  gen(p, n.sons[1], x)
+  gen(p, n.sons[2], y)
+  gen(p, n.sons[3], z)
+  r.res = frmt % [x.rdLoc, y.rdLoc, z.rdLoc]
+  r.kind = resExpr
+
+proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
+  useMagic(p, magic)
+  gen(p, n.sons[1], r)
+  r.res = frmt % [r.rdLoc]
+  r.kind = resExpr
+
+proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
+  var
+    x, y: TCompRes
+  let i = ord(optOverflowCheck notin p.options)
+  useMagic(p, ops[op][i])
+  if sonsLen(n) > 2:
+    gen(p, n.sons[1], x)
+    gen(p, n.sons[2], y)
+    r.res = ops[op][i + 2] % [x.rdLoc, y.rdLoc]
+  else:
+    gen(p, n.sons[1], r)
+    r.res = ops[op][i + 2] % [r.rdLoc]
+  r.kind = resExpr
+
+proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
+  arithAux(p, n, r, op, jsOps | luaOps)
+
+proc genLineDir(p: PProc, n: PNode) =
+  let line = toLinenumber(n.info)
+  if optLineDir in p.options:
+    addf(p.body, "// line $2 \"$1\"$n" | "-- line $2 \"$1\"$n",
+         [rope(toFilename(n.info)), rope(line)])
+  if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
+      ((p.prc == nil) or sfPure notin p.prc.flags):
+    useMagic(p, "endb")
+    addf(p.body, "endb($1);$n", [rope(line)])
+  elif ({optLineTrace, optStackTrace} * p.options ==
+      {optLineTrace, optStackTrace}) and
+      ((p.prc == nil) or not (sfPure in p.prc.flags)):
+    addf(p.body, "F.line = $1;$n", [rope(line)])
+
+proc genWhileStmt(p: PProc, n: PNode) =
+  var
+    cond: TCompRes
+  internalAssert isEmptyType(n.typ)
+  genLineDir(p, n)
+  inc(p.unique)
+  var length = len(p.blocks)
+  setLen(p.blocks, length + 1)
+  p.blocks[length].id = -p.unique
+  p.blocks[length].isLoop = true
+  let labl = p.unique.rope
+  addf(p.body, "L$1: while (true) {$n" | "while true do$n", [labl])
+  gen(p, n.sons[0], cond)
+  addf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n",
+       [cond.res, labl])
+  genStmt(p, n.sons[1])
+  addf(p.body, "}$n" | "end ::L$#::$n", [labl])
+  setLen(p.blocks, length)
+
+proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
+  if src.kind != resNone:
+    if dest.kind != resNone:
+      p.body.addf("$1 = $2;$n", [dest.rdLoc, src.rdLoc])
+    else:
+      p.body.addf("$1;$n", [src.rdLoc])
+    src.kind = resNone
+    src.res = nil
+
+proc genTry(p: PProc, n: PNode, r: var TCompRes) =
+  # code to generate:
+  #
+  #  var sp = {prev: excHandler, exc: null};
+  #  excHandler = sp;
+  #  try {
+  #    stmts;
+  #    TMP = e
+  #  } catch (e) {
+  #    if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
+  #      stmts;
+  #    } else if (e.typ && e.typ == NTI32342) {
+  #      stmts;
+  #    } else {
+  #      stmts;
+  #    }
+  #  } finally {
+  #    stmts;
+  #    excHandler = excHandler.prev;
+  #  }
+  genLineDir(p, n)
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
+  inc(p.unique)
+  var safePoint = "Tmp$1" % [rope(p.unique)]
+  addf(p.body,
+       "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
+       "local $1 = pcall(",
+       [safePoint])
+  if optStackTrace in p.options: add(p.body, "framePtr = F;" & tnl)
+  addf(p.body, "try {$n" | "function()$n", [])
+  var length = sonsLen(n)
+  var a: TCompRes
+  gen(p, n.sons[0], a)
+  moveInto(p, a, r)
+  var i = 1
+  if p.target == targetJS and length > 1 and n.sons[i].kind == nkExceptBranch:
+    addf(p.body, "} catch (EXC) {$n  lastJSError = EXC;$n", [])
+  elif p.target == targetLua:
+    addf(p.body, "end)$n", [])
+  while i < length and n.sons[i].kind == nkExceptBranch:
+    let blen = sonsLen(n.sons[i])
+    if blen == 1:
+      # general except section:
+      if i > 1: addf(p.body, "else {$n" | "else$n", [])
+      gen(p, n.sons[i].sons[0], a)
+      moveInto(p, a, r)
+      if i > 1: addf(p.body, "}$n" | "end$n", [])
+    else:
+      var orExpr: Rope = nil
+      useMagic(p, "isObj")
+      for j in countup(0, blen - 2):
+        if n.sons[i].sons[j].kind != nkType:
+          internalError(n.info, "genTryStmt")
+        if orExpr != nil: add(orExpr, "||" | " or ")
+        addf(orExpr, "isObj($1.exc.m_type, $2)",
+             [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
+      if i > 1: add(p.body, "else ")
+      addf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
+        [safePoint, orExpr])
+      gen(p, n.sons[i].sons[blen - 1], a)
+      moveInto(p, a, r)
+      addf(p.body, "}$n" | "end$n", [])
+    inc(i)
+  if p.target == targetJS:
+    add(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
+  if i < length and n.sons[i].kind == nkFinally:
+    genStmt(p, n.sons[i].sons[0])
+  if p.target == targetJS:
+    add(p.body, "}" & tnl)
+  if p.target == targetLua:
+    # we need to repeat the finally block for Lua ...
+    if i < length and n.sons[i].kind == nkFinally:
+      genStmt(p, n.sons[i].sons[0])
+
+proc genRaiseStmt(p: PProc, n: PNode) =
+  genLineDir(p, n)
+  if n.sons[0].kind != nkEmpty:
+    var a: TCompRes
+    gen(p, n.sons[0], a)
+    let typ = skipTypes(n.sons[0].typ, abstractPtrs)
+    useMagic(p, "raiseException")
+    addf(p.body, "raiseException($1, $2);$n",
+         [a.rdLoc, makeJSString(typ.sym.name.s)])
+  else:
+    useMagic(p, "reraiseException")
+    add(p.body, "reraiseException();" & tnl)
+
+proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
+  var
+    cond, stmt: TCompRes
+  genLineDir(p, n)
+  gen(p, n.sons[0], cond)
+  let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
+  if stringSwitch:
+    useMagic(p, "toJSStr")
+    addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
+  else:
+    addf(p.body, "switch ($1) {$n", [cond.rdLoc])
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
+  for i in countup(1, sonsLen(n) - 1):
+    let it = n.sons[i]
+    case it.kind
+    of nkOfBranch:
+      for j in countup(0, sonsLen(it) - 2):
+        let e = it.sons[j]
+        if e.kind == nkRange:
+          var v = copyNode(e.sons[0])
+          while v.intVal <= e.sons[1].intVal:
+            gen(p, v, cond)
+            addf(p.body, "case $1: ", [cond.rdLoc])
+            inc(v.intVal)
+        else:
+          if stringSwitch:
+            case e.kind
+            of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
+                [makeJSString(e.strVal)])
+            else: internalError(e.info, "jsgen.genCaseStmt: 2")
+          else:
+            gen(p, e, cond)
+            addf(p.body, "case $1: ", [cond.rdLoc])
+      gen(p, lastSon(it), stmt)
+      moveInto(p, stmt, r)
+      addf(p.body, "$nbreak;$n", [])
+    of nkElse:
+      addf(p.body, "default: $n", [])
+      gen(p, it.sons[0], stmt)
+      moveInto(p, stmt, r)
+      addf(p.body, "break;$n", [])
+    else: internalError(it.info, "jsgen.genCaseStmt")
+  addf(p.body, "}$n", [])
+
+proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
+  var
+    cond, stmt: TCompRes
+  genLineDir(p, n)
+  gen(p, n.sons[0], cond)
+  let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
+  if stringSwitch:
+    useMagic(p, "eqStr")
+  let tmp = getTemp(p)
+  addf(p.body, "$1 = $2;$n", [tmp, cond.rdLoc])
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
+  for i in countup(1, sonsLen(n) - 1):
+    let it = n.sons[i]
+    case it.kind
+    of nkOfBranch:
+      if i != 1: addf(p.body, "$nelsif ", [])
+      else: addf(p.body, "if ", [])
+      for j in countup(0, sonsLen(it) - 2):
+        if j != 0: add(p.body, " or ")
+        let e = it.sons[j]
+        if e.kind == nkRange:
+          var ia, ib: TCompRes
+          gen(p, e.sons[0], ia)
+          gen(p, e.sons[1], ib)
+          addf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
+        else:
+          if stringSwitch:
+            case e.kind
+            of nkStrLit..nkTripleStrLit: addf(p.body, "eqStr($1, $2)",
+                [tmp, makeJSString(e.strVal)])
+            else: internalError(e.info, "jsgen.genCaseStmt: 2")
+          else:
+            gen(p, e, cond)
+            addf(p.body, "$1 == $2", [tmp, cond.rdLoc])
+      addf(p.body, " then$n", [])
+      gen(p, lastSon(it), stmt)
+      moveInto(p, stmt, r)
+    of nkElse:
+      addf(p.body, "else$n", [])
+      gen(p, it.sons[0], stmt)
+      moveInto(p, stmt, r)
+    else: internalError(it.info, "jsgen.genCaseStmt")
+  addf(p.body, "$nend$n", [])
+
+proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
+  inc(p.unique)
+  let idx = len(p.blocks)
+  if n.sons[0].kind != nkEmpty:
+    # named block?
+    if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
+    var sym = n.sons[0].sym
+    sym.loc.k = locOther
+    sym.position = idx+1
+  setLen(p.blocks, idx + 1)
+  p.blocks[idx].id = - p.unique # negative because it isn't used yet
+  let labl = p.unique
+  addf(p.body, "L$1: do {$n" | "", [labl.rope])
+  gen(p, n.sons[1], r)
+  addf(p.body, "} while(false);$n" | "$n::L$#::$n", [labl.rope])
+  setLen(p.blocks, idx)
+
+proc genBreakStmt(p: PProc, n: PNode) =
+  var idx: int
+  genLineDir(p, n)
+  if n.sons[0].kind != nkEmpty:
+    # named break?
+    assert(n.sons[0].kind == nkSym)
+    let sym = n.sons[0].sym
+    assert(sym.loc.k == locOther)
+    idx = sym.position-1
+  else:
+    # an unnamed 'break' can only break a loop after 'transf' pass:
+    idx = len(p.blocks) - 1
+    while idx >= 0 and not p.blocks[idx].isLoop: dec idx
+    if idx < 0 or not p.blocks[idx].isLoop:
+      internalError(n.info, "no loop to break")
+  p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
+  addf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [rope(p.blocks[idx].id)])
+
+proc genAsmStmt(p: PProc, n: PNode) =
+  genLineDir(p, n)
+  assert(n.kind == nkAsmStmt)
+  for i in countup(0, sonsLen(n) - 1):
+    case n.sons[i].kind
+    of nkStrLit..nkTripleStrLit: add(p.body, n.sons[i].strVal)
+    of nkSym: add(p.body, mangleName(n.sons[i].sym))
+    else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
+
+proc genIf(p: PProc, n: PNode, r: var TCompRes) =
+  var cond, stmt: TCompRes
+  var toClose = 0
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
+  for i in countup(0, sonsLen(n) - 1):
+    let it = n.sons[i]
+    if sonsLen(it) != 1:
+      if i > 0:
+        addf(p.body, "else {$n" | "else$n", [])
+        inc(toClose)
+      gen(p, it.sons[0], cond)
+      addf(p.body, "if ($1) {$n" | "if $# then$n", [cond.rdLoc])
+      gen(p, it.sons[1], stmt)
+    else:
+      # else part:
+      addf(p.body, "else {$n" | "else$n", [])
+      gen(p, it.sons[0], stmt)
+    moveInto(p, stmt, r)
+    addf(p.body, "}$n" | "end$n", [])
+  if p.target == targetJS:
+    add(p.body, repeat('}', toClose) & tnl)
+  else:
+    for i in 1..toClose: addf(p.body, "end$n", [])
+
+proc generateHeader(p: PProc, typ: PType): Rope =
+  result = nil
+  for i in countup(1, sonsLen(typ.n) - 1):
+    assert(typ.n.sons[i].kind == nkSym)
+    var param = typ.n.sons[i].sym
+    if isCompileTimeOnly(param.typ): continue
+    if result != nil: add(result, ", ")
+    var name = mangleName(param)
+    add(result, name)
+    if mapType(param.typ) == etyBaseIndex:
+      add(result, ", ")
+      add(result, name)
+      add(result, "_Idx")
+
+const
+  nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
+    nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
+    nkCommand, nkHiddenCallConv, nkCallStrLit}
+
+proc needsNoCopy(y: PNode): bool =
+  result = (y.kind in nodeKindsNeedNoCopy) or
+      (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar})
+
+proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
+  var a, b: TCompRes
+  gen(p, x, a)
+  gen(p, y, b)
+  case mapType(x.typ)
+  of etyObject:
+    if needsNoCopy(y) or noCopyNeeded:
+      addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+    else:
+      useMagic(p, "nimCopy")
+      addf(p.body, "$1 = nimCopy($2, $3);$n",
+           [a.res, b.res, genTypeInfo(p, y.typ)])
+  of etyBaseIndex:
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
+      internalError(x.info, "genAsgn")
+    addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
+  else:
+    addf(p.body, "$1 = $2;$n", [a.res, b.res])
+
+proc genAsgn(p: PProc, n: PNode) =
+  genLineDir(p, n)
+  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
+
+proc genFastAsgn(p: PProc, n: PNode) =
+  genLineDir(p, n)
+  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
+
+proc genSwap(p: PProc, n: PNode) =
+  var a, b: TCompRes
+  gen(p, n.sons[1], a)
+  gen(p, n.sons[2], b)
+  inc(p.unique)
+  var tmp = "Tmp$1" % [rope(p.unique)]
+  if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
+    inc(p.unique)
+    let tmp2 = "Tmp$1" % [rope(p.unique)]
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
+      internalError(n.info, "genSwap")
+    addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
+                 "local $1 = $2; $2 = $3; $3 = $1;$n", [
+                 tmp, a.address, b.address])
+    tmp = tmp2
+  addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
+               "local $1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
+
+proc getFieldPosition(f: PNode): int =
+  case f.kind
+  of nkIntLit..nkUInt64Lit: result = int(f.intVal)
+  of nkSym: result = f.sym.position
+  else: internalError(f.info, "genFieldPosition")
+
+proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes
+  r.typ = etyBaseIndex
+  let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
+  gen(p, b.sons[0], a)
+  if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
+    r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
+  else:
+    if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
+    var f = b.sons[1].sym
+    if f.loc.r == nil: f.loc.r = mangleName(f)
+    r.res = makeJSString($f.loc.r)
+  internalAssert a.typ != etyBaseIndex
+  r.address = a.res
+  r.kind = resExpr
+
+proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
+  r.typ = etyNone
+  gen(p, n.sons[0], r)
+  if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
+    r.res = "$1.Field$2" % [r.res, getFieldPosition(n.sons[1]).rope]
+  else:
+    if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
+    var f = n.sons[1].sym
+    if f.loc.r == nil: f.loc.r = mangleName(f)
+    r.res = "$1.$2" % [r.res, f.loc.r]
+  r.kind = resExpr
+
+proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
+  let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
+  internalAssert m.kind == nkCheckedFieldExpr
+  genFieldAddr(p, m.sons[0], r) # XXX
+
+proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
+  genFieldAccess(p, n.sons[0], r) # XXX
+
+proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
+  var
+    a, b: TCompRes
+    first: BiggestInt
+  r.typ = etyBaseIndex
+  let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
+  gen(p, m.sons[0], a)
+  gen(p, m.sons[1], b)
+  internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
+  r.address = a.res
+  var typ = skipTypes(m.sons[0].typ, abstractPtrs)
+  if typ.kind in {tyArray, tyArrayConstr}: first = firstOrd(typ.sons[0])
+  else: first = 0
+  if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
+    useMagic(p, "chckIndx")
+    r.res = "chckIndx($1, $2, $3.length)-$2" % [b.res, rope(first), a.res]
+  elif first != 0:
+    r.res = "($1)-$2" % [b.res, rope(first)]
+  else:
+    r.res = b.res
+  r.kind = resExpr
+
+proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
+  var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+  if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
+  case ty.kind
+  of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
+     tyVarargs:
+    genArrayAddr(p, n, r)
+  of tyTuple:
+    genFieldAddr(p, n, r)
+  else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
+  r.typ = etyNone
+  if r.res == nil: internalError(n.info, "genArrayAccess")
+  r.res = "$1[$2]" % [r.address, r.res]
+  r.address = nil
+  r.kind = resExpr
+
+proc isIndirect(v: PSym): bool =
+  result = {sfAddrTaken, sfGlobal} * v.flags != {} and
+    #(mapType(v.typ) != etyObject) and
+    {sfImportc, sfVolatile, sfExportc} * v.flags == {} and
+    v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator,
+                  skConst, skTemp, skLet}
+
+proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
+  case n.sons[0].kind
+  of nkSym:
+    let s = n.sons[0].sym
+    if s.loc.r == nil: internalError(n.info, "genAddr: 3")
+    case s.kind
+    of skVar, skLet, skResult:
+      r.kind = resExpr
+      let jsType = mapType(n.typ)
+      if jsType == etyObject:
+        # make addr() a no-op:
+        r.typ = etyNone
+        if isIndirect(s):
+          r.res = s.loc.r & "[0]"
+        else:
+          r.res = s.loc.r
+        r.address = nil
+      elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
+        # for ease of code generation, we do not distinguish between
+        # sfAddrTaken and sfGlobal.
+        r.typ = etyBaseIndex
+        r.address = s.loc.r
+        r.res = rope("0")
+      else:
+        # 'var openArray' for instance produces an 'addr' but this is harmless:
+        gen(p, n.sons[0], r)
+        #internalError(n.info, "genAddr: 4 " & renderTree(n))
+    else: internalError(n.info, "genAddr: 2")
+  of nkCheckedFieldExpr:
+    genCheckedFieldAddr(p, n, r)
+  of nkDotExpr:
+    if mapType(n.typ) == etyBaseIndex:
+      genFieldAddr(p, n.sons[0], r)
+    else:
+      genFieldAccess(p, n.sons[0], r)
+  of nkBracketExpr:
+    var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+    if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
+    case ty.kind
+    of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
+       tyVarargs, tyChar:
+      genArrayAddr(p, n.sons[0], r)
+    of tyTuple:
+      genFieldAddr(p, n.sons[0], r)
+    else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $ty.kind & ')')
+  else: internalError(n.sons[0].info, "genAddr")
+
+proc genSym(p: PProc, n: PNode, r: var TCompRes) =
+  var s = n.sym
+  case s.kind
+  of skVar, skLet, skParam, skTemp, skResult:
+    if s.loc.r == nil:
+      internalError(n.info, "symbol has no generated name: " & s.name.s)
+    let k = mapType(s.typ)
+    if k == etyBaseIndex:
+      r.typ = etyBaseIndex
+      if {sfAddrTaken, sfGlobal} * s.flags != {}:
+        r.address = "$1[0]" % [s.loc.r]
+        r.res = "$1[1]" % [s.loc.r]
+      else:
+        r.address = s.loc.r
+        r.res = s.loc.r & "_Idx"
+    elif isIndirect(s):
+      r.res = "$1[0]" % [s.loc.r]
+    else:
+      r.res = s.loc.r
+  of skConst:
+    genConstant(p, s)
+    if s.loc.r == nil:
+      internalError(n.info, "symbol has no generated name: " & s.name.s)
+    r.res = s.loc.r
+  of skProc, skConverter, skMethod:
+    discard mangleName(s)
+    r.res = s.loc.r
+    if lfNoDecl in s.loc.flags or s.magic != mNone or
+       {sfImportc, sfInfixCall} * s.flags != {}:
+      discard
+    elif s.kind == skMethod and s.getBody.kind == nkEmpty:
+      # we cannot produce code for the dispatcher yet:
+      discard
+    elif sfForward in s.flags:
+      p.g.forwarded.add(s)
+    elif not p.g.generatedSyms.containsOrIncl(s.id):
+      let newp = genProc(p, s)
+      var owner = p
+      while owner != nil and owner.prc != s.owner:
+        owner = owner.up
+      if owner != nil: add(owner.locals, newp)
+      else: add(p.g.code, newp)
+  else:
+    if s.loc.r == nil:
+      internalError(n.info, "symbol has no generated name: " & s.name.s)
+    r.res = s.loc.r
+  r.kind = resVal
+
+proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
+  if mapType(n.sons[0].typ) == etyObject:
+    gen(p, n.sons[0], r)
+  else:
+    var a: TCompRes
+    gen(p, n.sons[0], a)
+    if a.typ != etyBaseIndex: internalError(n.info, "genDeref")
+    r.res = "$1[$2]" % [a.address, a.res]
+
+proc genArg(p: PProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes
+  gen(p, n, a)
+  if a.typ == etyBaseIndex:
+    add(r.res, a.address)
+    add(r.res, ", ")
+    add(r.res, a.res)
+  else:
+    add(r.res, a.res)
+
+proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
+  add(r.res, "(")
+  var hasArgs = false
+  for i in countup(1, sonsLen(n) - 1):
+    let it = n.sons[i]
+    if it.typ.isCompileTimeOnly: continue
+    if hasArgs: add(r.res, ", ")
+    genArg(p, it, r)
+    hasArgs = true
+  add(r.res, ")")
+  r.kind = resExpr
+
+proc genCall(p: PProc, n: PNode, r: var TCompRes) =
+  gen(p, n.sons[0], r)
+  genArgs(p, n, r)
+
+proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
+  gen(p, n.sons[1], r)
+  if r.typ == etyBaseIndex:
+    if r.address == nil:
+      globalError(n.info, "cannot invoke with infix syntax")
+    r.res = "$1[$2]" % [r.address, r.res]
+    r.address = nil
+    r.typ = etyNone
+  add(r.res, ".")
+  var op: TCompRes
+  gen(p, n.sons[0], op)
+  add(r.res, op.res)
+
+  add(r.res, "(")
+  for i in countup(2, sonsLen(n) - 1):
+    if i > 2: add(r.res, ", ")
+    genArg(p, n.sons[i], r)
+  add(r.res, ")")
+  r.kind = resExpr
+
+proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
+  useMagic(p, "rawEcho")
+  add(r.res, "rawEcho(")
+  let n = n[1].skipConv
+  internalAssert n.kind == nkBracket
+  for i in countup(0, sonsLen(n) - 1):
+    let it = n.sons[i]
+    if it.typ.isCompileTimeOnly: continue
+    if i > 0: add(r.res, ", ")
+    genArg(p, it, r)
+  add(r.res, ")")
+  r.kind = resExpr
+
+proc putToSeq(s: string, indirect: bool): Rope =
+  result = rope(s)
+  if indirect: result = "[$1]" % [result]
+
+proc createVar(p: PProc, typ: PType, indirect: bool): Rope
+proc createRecordVarAux(p: PProc, rec: PNode, c: var int): Rope =
+  result = nil
+  case rec.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(rec) - 1):
+      add(result, createRecordVarAux(p, rec.sons[i], c))
+  of nkRecCase:
+    add(result, createRecordVarAux(p, rec.sons[0], c))
+    for i in countup(1, sonsLen(rec) - 1):
+      add(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
+  of nkSym:
+    if c > 0: add(result, ", ")
+    add(result, mangleName(rec.sym))
+    add(result, ": ")
+    add(result, createVar(p, rec.sym.typ, false))
+    inc(c)
+  else: internalError(rec.info, "createRecordVarAux")
+
+proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
+  var t = skipTypes(typ, abstractInst)
+  case t.kind
+  of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar:
+    result = putToSeq("0", indirect)
+  of tyFloat..tyFloat128:
+    result = putToSeq("0.0", indirect)
+  of tyRange, tyGenericInst:
+    result = createVar(p, lastSon(typ), indirect)
+  of tySet:
+    result = putToSeq("{}", indirect)
+  of tyBool:
+    result = putToSeq("false", indirect)
+  of tyArray, tyArrayConstr:
+    var length = int(lengthOrd(t))
+    var e = elemType(t)
+    if length > 32:
+      useMagic(p, "arrayConstr")
+      # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
+      useMagic(p, "nimCopy")
+      result = "arrayConstr($1, $2, $3)" % [rope(length),
+          createVar(p, e, false), genTypeInfo(p, e)]
+    else:
+      result = rope("[")
+      var i = 0
+      while i < length:
+        if i > 0: add(result, ", ")
+        add(result, createVar(p, e, false))
+        inc(i)
+      add(result, "]")
+    if indirect: result = "[$1]" % [result]
+  of tyTuple:
+    result = rope("{")
+    for i in 0.. <t.sonsLen:
+      if i > 0: add(result, ", ")
+      addf(result, "Field$1: $2" | "Field$# = $#", [i.rope,
+           createVar(p, t.sons[i], false)])
+    add(result, "}")
+    if indirect: result = "[$1]" % [result]
+  of tyObject:
+    result = rope("{")
+    var c = 0
+    if tfFinal notin t.flags or t.sons[0] != nil:
+      inc(c)
+      addf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
+    while t != nil:
+      add(result, createRecordVarAux(p, t.n, c))
+      t = t.sons[0]
+    add(result, "}")
+    if indirect: result = "[$1]" % [result]
+  of tyVar, tyPtr, tyRef:
+    if mapType(t) == etyBaseIndex:
+      result = putToSeq("[null, 0]" | "{nil, 0}", indirect)
+    else:
+      result = putToSeq("null" | "nil", indirect)
+  of tySequence, tyString, tyCString, tyPointer, tyProc:
+    result = putToSeq("null" | "nil", indirect)
+  else:
+    internalError("createVar: " & $t.kind)
+    result = nil
+
+proc genVarInit(p: PProc, v: PSym, n: PNode) =
+  var
+    a: TCompRes
+    s: Rope
+  if n.kind == nkEmpty:
+    addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n",
+         [mangleName(v), createVar(p, v.typ, isIndirect(v))])
+  else:
+    discard mangleName(v)
+    gen(p, n, a)
+    case mapType(v.typ)
+    of etyObject:
+      if needsNoCopy(n):
+        s = a.res
+      else:
+        useMagic(p, "nimCopy")
+        s = "nimCopy($1, $2)" % [a.res, genTypeInfo(p, n.typ)]
+    of etyBaseIndex:
+      if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
+      if {sfAddrTaken, sfGlobal} * v.flags != {}:
+        addf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
+            [v.loc.r, a.address, a.res])
+      else:
+        addf(p.body, "var $1 = $2; var $1_Idx = $3;$n" |
+                     "local $1 = $2; local $1_Idx = $3;$n", [
+             v.loc.r, a.address, a.res])
+      return
+    else:
+      s = a.res
+    if isIndirect(v):
+      addf(p.body, "var $1 = /**/[$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
+    else:
+      addf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
+
+proc genVarStmt(p: PProc, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if a.kind != nkCommentStmt:
+      if a.kind == nkVarTuple:
+        let unpacked = lowerTupleUnpacking(a, p.prc)
+        genStmt(p, unpacked)
+      else:
+        assert(a.kind == nkIdentDefs)
+        assert(a.sons[0].kind == nkSym)
+        var v = a.sons[0].sym
+        if lfNoDecl notin v.loc.flags:
+          genLineDir(p, a)
+          genVarInit(p, v, a.sons[2])
+
+proc genConstant(p: PProc, c: PSym) =
+  if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
+    let oldBody = p.body
+    p.body = nil
+    #genLineDir(p, c.ast)
+    genVarInit(p, c, c.ast)
+    add(p.g.code, p.body)
+    p.body = oldBody
+
+proc genNew(p: PProc, n: PNode) =
+  var a: TCompRes
+  gen(p, n.sons[1], a)
+  var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+  addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
+
+proc genNewSeq(p: PProc, n: PNode) =
+  var x, y: TCompRes
+  gen(p, n.sons[1], x)
+  gen(p, n.sons[2], y)
+  let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+  addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
+    x.rdLoc, y.rdLoc, createVar(p, t, false)])
+
+proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
+  case skipTypes(n.sons[1].typ, abstractVar).kind
+  of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
+  of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)" | "toBool($#)")
+  else: internalError(n.info, "genOrd")
+
+proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes
+
+  gen(p, n.sons[1], a)
+  r.kind = resExpr
+  if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
+    r.res.add("[$1].concat(" % [a.res])
+  else:
+    r.res.add("($1.slice(0,-1)).concat(" % [a.res])
+
+  for i in countup(2, sonsLen(n) - 2):
+    gen(p, n.sons[i], a)
+    if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
+      r.res.add("[$1]," % [a.res])
+    else:
+      r.res.add("$1.slice(0,-1)," % [a.res])
+
+  gen(p, n.sons[sonsLen(n) - 1], a)
+  if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
+    r.res.add("[$1, 0])" % [a.res])
+  else:
+    r.res.add("$1)" % [a.res])
+
+proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
+  var t = skipTypes(n.sons[1].typ, abstractVarRange)
+  case t.kind
+  of tyInt..tyUInt64:
+    unaryExpr(p, n, r, "", "(\"\"+ ($1))")
+  of tyEnum, tyOrdinal:
+    gen(p, n.sons[1], r)
+    useMagic(p, "cstrToNimstr")
+    r.kind = resExpr
+    r.res = "cstrToNimstr($1.node.sons[$2].name)" % [genTypeInfo(p, t), r.res]
+  else:
+    # XXX:
+    internalError(n.info, "genRepr: Not implemented")
+
+proc genOf(p: PProc, n: PNode, r: var TCompRes) =
+  var x: TCompRes
+  let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr, tyTypeDesc})
+  gen(p, n.sons[1], x)
+  if tfFinal in t.flags:
+    r.res = "($1.m_type == $2)" % [x.res, genTypeInfo(p, t)]
+  else:
+    useMagic(p, "isObj")
+    r.res = "isObj($1.m_type, $2)" % [x.res, genTypeInfo(p, t)]
+  r.kind = resExpr
+
+proc genReset(p: PProc, n: PNode) =
+  var x: TCompRes
+  useMagic(p, "genericReset")
+  gen(p, n.sons[1], x)
+  addf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
+                genTypeInfo(p, n.sons[1].typ)])
+
+proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
+  var
+    a: TCompRes
+    line, filen: Rope
+  var op = n.sons[0].sym.magic
+  case op
+  of mOr: genOr(p, n.sons[1], n.sons[2], r)
+  of mAnd: genAnd(p, n.sons[1], n.sons[2], r)
+  of mAddI..mStrToStr: arith(p, n, r, op)
+  of mRepr: genRepr(p, n, r)
+  of mSwap: genSwap(p, n)
+  of mUnaryLt:
+    # XXX: range checking?
+    if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
+    else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
+  of mAppendStrCh: binaryExpr(p, n, r, "addChar",
+        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
+  of mAppendStrStr:
+    if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
+        binaryExpr(p, n, r, "", "if ($1 != null) { $1 += $2; } else { $1 = $2; }")
+    else:
+      binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1 = ($1.slice(0, -1)).concat($2); } else { $1 = $2;}")
+    # XXX: make a copy of $2, because of Javascript's sucking semantics
+  of mAppendSeqElem: binaryExpr(p, n, r, "",
+        "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
+  of mConStrStr: genConStrStr(p, n, r)
+  of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
+  of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
+  of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
+  of mIsNil: unaryExpr(p, n, r, "", "$1 == null")
+  of mEnumToStr: genRepr(p, n, r)
+  of mNew, mNewFinalize: genNew(p, n)
+  of mSizeOf: r.res = rope(getSize(n.sons[1].typ))
+  of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
+  of mOrd: genOrd(p, n, r)
+  of mLengthStr: unaryExpr(p, n, r, "", "($1 != null ? $1.length-1 : 0)")
+  of mXLenStr: unaryExpr(p, n, r, "", "$1.length-1")
+  of mLengthSeq, mLengthOpenArray, mLengthArray:
+    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
+  of mXLenSeq:
+    unaryExpr(p, n, r, "", "$1.length")
+  of mHigh:
+    if skipTypes(n.sons[1].typ, abstractVar).kind == tyString:
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-2) : -1)")
+    else:
+      unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
+  of mInc:
+    if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
+    else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
+  of ast.mDec:
+    if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
+    else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
+  of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = $2+1; $1[$1.length-1] = 0")
+  of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2")
+  of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
+  of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
+  of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
+  of mEqSet: binaryExpr(p, n, r, "SetEq", "SetEq($1, $2)")
+  of mMulSet: binaryExpr(p, n, r, "SetMul", "SetMul($1, $2)")
+  of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
+  of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
+  of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
+  of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
+  of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)")
+  of mNewSeq: genNewSeq(p, n)
+  of mOf: genOf(p, n, r)
+  of mReset: genReset(p, n)
+  of mEcho: genEcho(p, n, r)
+  of mNLen..mNError, mSlurp, mStaticExec:
+    localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
+  of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))")
+  of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
+  of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
+  of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
+  else:
+    genCall(p, n, r)
+    #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
+
+proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
+  var
+    a, b: TCompRes
+  useMagic(p, "SetConstr")
+  r.res = rope("SetConstr(")
+  r.kind = resExpr
+  for i in countup(0, sonsLen(n) - 1):
+    if i > 0: add(r.res, ", ")
+    var it = n.sons[i]
+    if it.kind == nkRange:
+      gen(p, it.sons[0], a)
+      gen(p, it.sons[1], b)
+      addf(r.res, "[$1, $2]", [a.res, b.res])
+    else:
+      gen(p, it, a)
+      add(r.res, a.res)
+  add(r.res, ")")
+
+proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes
+  r.res = rope("[")
+  r.kind = resExpr
+  for i in countup(0, sonsLen(n) - 1):
+    if i > 0: add(r.res, ", ")
+    gen(p, n.sons[i], a)
+    add(r.res, a.res)
+  add(r.res, "]")
+
+proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
+  var a: TCompRes
+  r.res = rope("{")
+  r.kind = resExpr
+  for i in countup(0, sonsLen(n) - 1):
+    if i > 0: add(r.res, ", ")
+    var it = n.sons[i]
+    if it.kind == nkExprColonExpr: it = it.sons[1]
+    gen(p, it, a)
+    addf(r.res, "Field$#: $#" | "Field$# = $#", [i.rope, a.res])
+  r.res.add("}")
+
+proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
+  # XXX inheritance?
+  var a: TCompRes
+  r.res = rope("{")
+  r.kind = resExpr
+  for i in countup(1, sonsLen(n) - 1):
+    if i > 1: add(r.res, ", ")
+    var it = n.sons[i]
+    internalAssert it.kind == nkExprColonExpr
+    gen(p, it.sons[1], a)
+    var f = it.sons[0].sym
+    if f.loc.r == nil: f.loc.r = mangleName(f)
+    addf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
+  r.res.add("}")
+
+proc genConv(p: PProc, n: PNode, r: var TCompRes) =
+  var dest = skipTypes(n.typ, abstractVarRange)
+  var src = skipTypes(n.sons[1].typ, abstractVarRange)
+  gen(p, n.sons[1], r)
+  if dest.kind == src.kind:
+    # no-op conversion
+    return
+  case dest.kind:
+  of tyBool:
+    r.res = ("(($1)? 1:0)" | "toBool($#)") % [r.res]
+    r.kind = resExpr
+  of tyInt:
+    r.res = "($1|0)" % [r.res]
+  else:
+    # TODO: What types must we handle here?
+    discard
+
+proc upConv(p: PProc, n: PNode, r: var TCompRes) =
+  gen(p, n.sons[0], r)        # XXX
+
+proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
+  var a, b: TCompRes
+  gen(p, n.sons[0], r)
+  if optRangeCheck in p.options:
+    gen(p, n.sons[1], a)
+    gen(p, n.sons[2], b)
+    useMagic(p, "chckRange")
+    r.res = "chckRange($1, $2, $3)" % [r.res, a.res, b.res]
+    r.kind = resExpr
+
+proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
+  # we do an optimization here as this is likely to slow down
+  # much of the code otherwise:
+  if n.sons[0].kind == nkCStringToString:
+    gen(p, n.sons[0].sons[0], r)
+  else:
+    gen(p, n.sons[0], r)
+    if r.res == nil: internalError(n.info, "convStrToCStr")
+    useMagic(p, "toJSStr")
+    r.res = "toJSStr($1)" % [r.res]
+    r.kind = resExpr
+
+proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
+  # we do an optimization here as this is likely to slow down
+  # much of the code otherwise:
+  if n.sons[0].kind == nkStringToCString:
+    gen(p, n.sons[0].sons[0], r)
+  else:
+    gen(p, n.sons[0], r)
+    if r.res == nil: internalError(n.info, "convCStrToStr")
+    useMagic(p, "cstrToNimstr")
+    r.res = "cstrToNimstr($1)" % [r.res]
+    r.kind = resExpr
+
+proc genReturnStmt(p: PProc, n: PNode) =
+  if p.procDef == nil: internalError(n.info, "genReturnStmt")
+  p.beforeRetNeeded = true
+  if (n.sons[0].kind != nkEmpty):
+    genStmt(p, n.sons[0])
+  else:
+    genLineDir(p, n)
+  addf(p.body, "break BeforeRet;$n" | "goto ::BeforeRet::;$n", [])
+
+proc genProcBody(p: PProc, prc: PSym): Rope =
+  if optStackTrace in prc.options:
+    result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
+               "local F={procname=$#,prev=framePtr,filename=$#,line=0};$n") &
+              "framePtr = F;$n") % [
+              makeJSString(prc.owner.name.s & '.' & prc.name.s),
+              makeJSString(toFilename(prc.info))]
+  else:
+    result = nil
+  if p.beforeRetNeeded:
+    addf(result, "BeforeRet: do {$n$1} while (false); $n" |
+                 "$#;::BeforeRet::$n", [p.body])
+  else:
+    add(result, p.body)
+  if prc.typ.callConv == ccSysCall and p.target == targetJS:
+    result = ("try {$n$1} catch (e) {$n" &
+      " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}") % [result]
+  if optStackTrace in prc.options:
+    add(result, "framePtr = framePtr.prev;" & tnl)
+
+proc genProc(oldProc: PProc, prc: PSym): Rope =
+  var
+    resultSym: PSym
+    name, returnStmt, resultAsgn, header: Rope
+    a: TCompRes
+  #if gVerbosity >= 3:
+  #  echo "BEGIN generating code for: " & prc.name.s
+  var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
+  p.target = oldProc.target
+  p.up = oldProc
+  returnStmt = nil
+  resultAsgn = nil
+  name = mangleName(prc)
+  header = generateHeader(p, prc.typ)
+  if prc.typ.sons[0] != nil and sfPure notin prc.flags:
+    resultSym = prc.ast.sons[resultPos].sym
+    resultAsgn = ("var $# = $#;$n" | "local $# = $#;$n") % [
+        mangleName(resultSym),
+        createVar(p, resultSym.typ, isIndirect(resultSym))]
+    gen(p, prc.ast.sons[resultPos], a)
+    returnStmt = "return $#;$n" % [a.res]
+  genStmt(p, prc.getBody)
+  result = ("function $#($#) {$n$#$#$#$#}$n" |
+            "function $#($#) $n$#$#$#$#$nend$n") %
+            [name, header, p.locals, resultAsgn,
+             genProcBody(p, prc), returnStmt]
+  #if gVerbosity >= 3:
+  #  echo "END   generated code for: " & prc.name.s
+
+proc genStmt(p: PProc, n: PNode) =
+  var r: TCompRes
+  gen(p, n, r)
+  if r.res != nil: addf(p.body, "$#;$n", [r.res])
+
+proc gen(p: PProc, n: PNode, r: var TCompRes) =
+  r.typ = etyNone
+  r.kind = resNone
+  #r.address = nil
+  r.res = nil
+  case n.kind
+  of nkSym:
+    genSym(p, n, r)
+  of nkCharLit..nkInt64Lit:
+    r.res = rope(n.intVal)
+    r.kind = resExpr
+  of nkNilLit:
+    if isEmptyType(n.typ):
+      discard
+    elif mapType(n.typ) == etyBaseIndex:
+      r.typ = etyBaseIndex
+      r.address = rope"null" | rope"nil"
+      r.res = rope"0"
+      r.kind = resExpr
+    else:
+      r.res = rope"null" | rope"nil"
+      r.kind = resExpr
+  of nkStrLit..nkTripleStrLit:
+    if skipTypes(n.typ, abstractVarRange).kind == tyString:
+      useMagic(p, "cstrToNimstr")
+      r.res = "cstrToNimstr($1)" % [makeJSString(n.strVal)]
+    else:
+      r.res = makeJSString(n.strVal)
+    r.kind = resExpr
+  of nkFloatLit..nkFloat64Lit:
+    let f = n.floatVal
+    if f != f: r.res = rope"NaN"
+    elif f == 0.0: r.res = rope"0.0"
+    elif f == 0.5 * f:
+      if f > 0.0: r.res = rope"Infinity"
+      else: r.res = rope"-Infinity"
+    else: r.res = rope(f.toStrMaxPrecision)
+    r.kind = resExpr
+  of nkCallKinds:
+    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
+      genMagic(p, n, r)
+    elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
+        n.len >= 2:
+      genInfixCall(p, n, r)
+    else:
+      genCall(p, n, r)
+  of nkCurly: genSetConstr(p, n, r)
+  of nkBracket: genArrayConstr(p, n, r)
+  of nkPar: genTupleConstr(p, n, r)
+  of nkObjConstr: genObjConstr(p, n, r)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
+  of nkAddr, nkHiddenAddr: genAddr(p, n, r)
+  of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
+  of nkBracketExpr: genArrayAccess(p, n, r)
+  of nkDotExpr: genFieldAccess(p, n, r)
+  of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r)
+  of nkObjDownConv: gen(p, n.sons[0], r)
+  of nkObjUpConv: upConv(p, n, r)
+  of nkCast: gen(p, n.sons[1], r)
+  of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
+  of nkChckRange64: genRangeChck(p, n, r, "chckRange64")
+  of nkChckRange: genRangeChck(p, n, r, "chckRange")
+  of nkStringToCString: convStrToCStr(p, n, r)
+  of nkCStringToString: convCStrToStr(p, n, r)
+  of nkEmpty: discard
+  of nkLambdaKinds:
+    let s = n.sons[namePos].sym
+    discard mangleName(s)
+    r.res = s.loc.r
+    if lfNoDecl in s.loc.flags or s.magic != mNone: discard
+    elif not p.g.generatedSyms.containsOrIncl(s.id):
+      add(p.locals, genProc(p, s))
+  of nkType: r.res = genTypeInfo(p, n.typ)
+  of nkStmtList, nkStmtListExpr:
+    # this shows the distinction is nice for backends and should be kept
+    # in the frontend
+    let isExpr = not isEmptyType(n.typ)
+    for i in countup(0, sonsLen(n) - 1 - isExpr.ord):
+      genStmt(p, n.sons[i])
+    if isExpr:
+      gen(p, lastSon(n), r)
+  of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
+  of nkIfStmt, nkIfExpr: genIf(p, n, r)
+  of nkWhileStmt: genWhileStmt(p, n)
+  of nkVarSection, nkLetSection: genVarStmt(p, n)
+  of nkConstSection: discard
+  of nkForStmt, nkParForStmt:
+    internalError(n.info, "for statement not eliminated")
+  of nkCaseStmt:
+    if p.target == targetJS: genCaseJS(p, n, r)
+    else: genCaseLua(p, n, r)
+  of nkReturnStmt: genReturnStmt(p, n)
+  of nkBreakStmt: genBreakStmt(p, n)
+  of nkAsgn: genAsgn(p, n)
+  of nkFastAsgn: genFastAsgn(p, n)
+  of nkDiscardStmt:
+    if n.sons[0].kind != nkEmpty:
+      genLineDir(p, n)
+      gen(p, n.sons[0], r)
+  of nkAsmStmt: genAsmStmt(p, n)
+  of nkTryStmt: genTry(p, n, r)
+  of nkRaiseStmt: genRaiseStmt(p, n)
+  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
+     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
+     nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
+  of nkProcDef, nkMethodDef, nkConverterDef:
+    var s = n.sons[namePos].sym
+    if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
+      genSym(p, n.sons[namePos], r)
+      r.res = nil
+  of nkGotoState, nkState:
+    internalError(n.info, "first class iterators not implemented")
+  of nkPragmaBlock: gen(p, n.lastSon, r)
+  else: internalError(n.info, "gen: unknown node type: " & $n.kind)
+
+var globals: PGlobals
+
+proc newModule(module: PSym): BModule =
+  new(result)
+  result.module = module
+  if globals == nil: globals = newGlobals()
+
+proc genHeader(): Rope =
+  result = ("/* Generated by the Nim Compiler v$1 */$n" &
+            "/*   (c) 2015 Andreas Rumpf */$n$n" &
+            "var framePtr = null;$n" &
+            "var excHandler = null;$n" &
+            "var lastJSError = null;$n") %
+           [rope(VersionAsString)]
+
+proc genModule(p: PProc, n: PNode) =
+  if optStackTrace in p.options:
+    addf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
+                 "framePtr = F;$n", [
+        makeJSString("module " & p.module.module.name.s),
+        makeJSString(toFilename(p.module.module.info))])
+  genStmt(p, n)
+  if optStackTrace in p.options:
+    addf(p.body, "framePtr = framePtr.prev;$n", [])
+
+proc myProcess(b: PPassContext, n: PNode): PNode =
+  if passes.skipCodegen(n): return n
+  result = n
+  var m = BModule(b)
+  if m.module == nil: internalError(n.info, "myProcess")
+  var p = newProc(globals, m, nil, m.module.options)
+  genModule(p, n)
+  add(p.g.code, p.locals)
+  add(p.g.code, p.body)
+
+proc wholeCode*(m: BModule): Rope =
+  for prc in globals.forwarded:
+    if not globals.generatedSyms.containsOrIncl(prc.id):
+      var p = newProc(globals, m, nil, m.module.options)
+      add(p.g.code, genProc(p, prc))
+
+  var disp = generateMethodDispatchers()
+  for i in 0..sonsLen(disp)-1:
+    let prc = disp.sons[i].sym
+    if not globals.generatedSyms.containsOrIncl(prc.id):
+      var p = newProc(globals, m, nil, m.module.options)
+      add(p.g.code, genProc(p, prc))
+
+  result = globals.typeInfo & globals.code
+
+proc myClose(b: PPassContext, n: PNode): PNode =
+  if passes.skipCodegen(n): return n
+  result = myProcess(b, n)
+  var m = BModule(b)
+  if sfMainModule in m.module.flags:
+    let code = wholeCode(m)
+    let outfile =
+      if options.outFile.len > 0:
+        if options.outFile.isAbsolute: options.outFile
+        else: getCurrentDir() / options.outFile
+      else:
+       changeFileExt(completeCFilePath(m.module.filename), "js")
+    discard writeRopeIfNotEqual(genHeader() & code, outfile)
+
+proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
+  internalError("symbol files are not possible with the JS code generator")
+  result = nil
+
+proc myOpen(s: PSym): PPassContext =
+  result = newModule(s)
+
+const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
new file mode 100644
index 000000000..851938327
--- /dev/null
+++ b/compiler/jstypes.nim
@@ -0,0 +1,148 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Type info generation for the JS backend.
+
+proc genTypeInfo(p: PProc, typ: PType): Rope
+proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
+  var
+    s, u: Rope
+    length: int
+    field: PSym
+    b: PNode
+  result = nil
+  case n.kind
+  of nkRecList:
+    length = sonsLen(n)
+    if length == 1:
+      result = genObjectFields(p, typ, n.sons[0])
+    else:
+      s = nil
+      for i in countup(0, length - 1):
+        if i > 0: add(s, ", " & tnl)
+        add(s, genObjectFields(p, typ, n.sons[i]))
+      result = ("{kind: 2, len: $1, offset: 0, " &
+          "typ: null, name: null, sons: [$2]}") % [rope(length), s]
+  of nkSym:
+    field = n.sym
+    s = genTypeInfo(p, field.typ)
+    result = ("{kind: 1, offset: \"$1\", len: 0, " &
+        "typ: $2, name: $3, sons: null}") %
+                   [mangleName(field), s, makeJSString(field.name.s)]
+  of nkRecCase:
+    length = sonsLen(n)
+    if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
+    field = n.sons[0].sym
+    s = genTypeInfo(p, field.typ)
+    for i in countup(1, length - 1):
+      b = n.sons[i]           # branch
+      u = nil
+      case b.kind
+      of nkOfBranch:
+        if sonsLen(b) < 2:
+          internalError(b.info, "genObjectFields; nkOfBranch broken")
+        for j in countup(0, sonsLen(b) - 2):
+          if u != nil: add(u, ", ")
+          if b.sons[j].kind == nkRange:
+            addf(u, "[$1, $2]", [rope(getOrdValue(b.sons[j].sons[0])),
+                                 rope(getOrdValue(b.sons[j].sons[1]))])
+          else:
+            add(u, rope(getOrdValue(b.sons[j])))
+      of nkElse:
+        u = rope(lengthOrd(field.typ))
+      else: internalError(n.info, "genObjectFields(nkRecCase)")
+      if result != nil: add(result, ", " & tnl)
+      addf(result, "[SetConstr($1), $2]",
+           [u, genObjectFields(p, typ, lastSon(b))])
+    result = ("{kind: 3, offset: \"$1\", len: $3, " &
+        "typ: $2, name: $4, sons: [$5]}") % [mangleName(field), s,
+        rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
+  else: internalError(n.info, "genObjectFields")
+
+proc genObjectInfo(p: PProc, typ: PType, name: Rope) =
+  var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+           "finalizer: null};$n") % [name, rope(ord(typ.kind))]
+  prepend(p.g.typeInfo, s)
+  addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+       [rope(typ.id), genObjectFields(p, typ, typ.n)])
+  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
+  if (typ.kind == tyObject) and (typ.sons[0] != nil):
+    addf(p.g.typeInfo, "$1.base = $2;$n",
+         [name, genTypeInfo(p, typ.sons[0])])
+
+proc genTupleFields(p: PProc, typ: PType): Rope =
+  var s: Rope = nil
+  for i in 0 .. <typ.len:
+    if i > 0: add(s, ", " & tnl)
+    s.addf("{kind: 1, offset: \"Field$1\", len: 0, " &
+           "typ: $2, name: \"Field$1\", sons: null}",
+           [i.rope, genTypeInfo(p, typ.sons[i])])
+  result = ("{kind: 2, len: $1, offset: 0, " &
+            "typ: null, name: null, sons: [$2]}") % [rope(typ.len), s]
+
+proc genTupleInfo(p: PProc, typ: PType, name: Rope) =
+  var s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+           "finalizer: null};$n") % [name, rope(ord(typ.kind))]
+  prepend(p.g.typeInfo, s)
+  addf(p.g.typeInfo, "var NNI$1 = $2;$n",
+       [rope(typ.id), genTupleFields(p, typ)])
+  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
+
+proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
+  let length = sonsLen(typ.n)
+  var s: Rope = nil
+  for i in countup(0, length - 1):
+    if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
+    let field = typ.n.sons[i].sym
+    if i > 0: add(s, ", " & tnl)
+    let extName = if field.ast == nil: field.name.s else: field.ast.strVal
+    addf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}",
+         [rope(field.position), name, makeJSString(extName)])
+  var n = ("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
+      "name: null, len: $2, sons: [$3]};$n") % [rope(typ.id), rope(length), s]
+  s = ("var $1 = {size: 0, kind: $2, base: null, node: null, " &
+       "finalizer: null};$n") % [name, rope(ord(typ.kind))]
+  prepend(p.g.typeInfo, s)
+  add(p.g.typeInfo, n)
+  addf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, rope(typ.id)])
+  if typ.sons[0] != nil:
+    addf(p.g.typeInfo, "$1.base = $2;$n",
+         [name, genTypeInfo(p, typ.sons[0])])
+
+proc genTypeInfo(p: PProc, typ: PType): Rope =
+  var t = typ
+  if t.kind == tyGenericInst: t = lastSon(t)
+  result = "NTI$1" % [rope(t.id)]
+  if containsOrIncl(p.g.typeInfoGenerated, t.id): return
+  case t.kind
+  of tyDistinct:
+    result = genTypeInfo(p, typ.sons[0])
+  of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64:
+    var s =
+      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+      [result, rope(ord(t.kind))]
+    prepend(p.g.typeInfo, s)
+  of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet:
+    var s =
+      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+              [result, rope(ord(t.kind))]
+    prepend(p.g.typeInfo, s)
+    addf(p.g.typeInfo, "$1.base = $2;$n",
+         [result, genTypeInfo(p, typ.lastSon)])
+  of tyArrayConstr, tyArray:
+    var s =
+      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n" %
+              [result, rope(ord(t.kind))]
+    prepend(p.g.typeInfo, s)
+    addf(p.g.typeInfo, "$1.base = $2;$n",
+         [result, genTypeInfo(p, typ.sons[1])])
+  of tyEnum: genEnumInfo(p, t, result)
+  of tyObject: genObjectInfo(p, t, result)
+  of tyTuple: genTupleInfo(p, t, result)
+  else: internalError("genTypeInfo(" & $t.kind & ')')
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
new file mode 100644
index 000000000..c68bc352c
--- /dev/null
+++ b/compiler/lambdalifting.nim
@@ -0,0 +1,1059 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include file implements lambda lifting for the transformator.
+
+import
+  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
+  idents, renderer, types, magicsys, rodread, lowerings
+
+discard """
+  The basic approach is that captured vars need to be put on the heap and
+  that the calling chain needs to be explicitly modelled. Things to consider:
+
+  proc a =
+    var v = 0
+    proc b =
+      var w = 2
+
+      for x in 0..3:
+        proc c = capture v, w, x
+        c()
+    b()
+
+    for x in 0..4:
+      proc d = capture x
+      d()
+
+  Needs to be translated into:
+
+  proc a =
+    var cl: *
+    new cl
+    cl.v = 0
+
+    proc b(cl) =
+      var bcl: *
+      new bcl
+      bcl.w = 2
+      bcl.up = cl
+
+      for x in 0..3:
+        var bcl2: *
+        new bcl2
+        bcl2.up = bcl
+        bcl2.up2 = cl
+        bcl2.x = x
+
+        proc c(cl) = capture cl.up2.v, cl.up.w, cl.x
+        c(bcl2)
+
+      c(bcl)
+
+    b(cl)
+
+    for x in 0..4:
+      var acl2: *
+      new acl2
+      acl2.x = x
+      proc d(cl) = capture cl.x
+      d(acl2)
+
+  Closures as interfaces:
+
+  proc outer: T =
+    var captureMe: TObject # value type required for efficiency
+    proc getter(): int = result = captureMe.x
+    proc setter(x: int) = captureMe.x = x
+
+    result = (getter, setter)
+
+  Is translated to:
+
+  proc outer: T =
+    var cl: *
+    new cl
+
+    proc getter(cl): int = result = cl.captureMe.x
+    proc setter(cl: *, x: int) = cl.captureMe.x = x
+
+    result = ((cl, getter), (cl, setter))
+
+
+  For 'byref' capture, the outer proc needs to access the captured var through
+  the indirection too. For 'bycopy' capture, the outer proc accesses the var
+  not through the indirection.
+
+  Possible optimizations:
+
+  1) If the closure contains a single 'ref' and this
+  reference is not re-assigned (check ``sfAddrTaken`` flag) make this the
+  closure. This is an important optimization if closures are used as
+  interfaces.
+  2) If the closure does not escape, put it onto the stack, not on the heap.
+  3) Dataflow analysis would help to eliminate the 'up' indirections.
+  4) If the captured var is not actually used in the outer proc (common?),
+  put it into an inner proc.
+
+"""
+
+# Important things to keep in mind:
+# * Don't base the analysis on nkProcDef et al. This doesn't work for
+#   instantiated (formerly generic) procs. The analysis has to look at nkSym.
+#   This also means we need to prevent the same proc is processed multiple
+#   times via the 'processed' set.
+# * Keep in mind that the owner of some temporaries used to be unreliable.
+# * For closure iterators we merge the "real" potential closure with the
+#   local storage requirements for efficiency. This means closure iterators
+#   have slightly different semantics from ordinary closures.
+
+
+const
+  upName* = ":up" # field name for the 'up' reference
+  paramName* = ":envP"
+  envName* = ":env"
+
+type
+  POuterContext = ref TOuterContext
+
+  TIter = object
+    fn, closureParam, state, resultSym: PSym # most are only valid if
+                                             # fn.kind == skClosureIterator
+    obj: PType
+
+  PEnv = ref TEnv
+  TEnv {.final.} = object of RootObj
+    attachedNode, replacementNode: PNode
+    createdVar: PNode        # if != nil it is a used environment; for closure
+                             # iterators this can be 'envParam.env'
+    createdVarComesFromIter: bool
+    capturedVars: seq[PSym] # captured variables in this environment
+    up, next: PEnv          # outer scope and next to keep all in a list
+    upField: PSym        # if != nil the dependency to the outer scope is used
+    obj: PType
+    fn: PSym                # function that belongs to this scope;
+                            # if up.fn != fn then we cross function boundaries.
+                            # This is an important case to consider.
+    vars: IntSet           # variables belonging to this environment
+
+  TOuterContext = object
+    fn: PSym # may also be a module!
+    head: PEnv
+    capturedVars, processed: IntSet
+    localsToAccess: TIdNodeTable
+    lambdasToEnv: TIdTable # PSym->PEnv mapping
+
+proc getStateType(iter: PSym): PType =
+  var n = newNodeI(nkRange, iter.info)
+  addSon(n, newIntNode(nkIntLit, -1))
+  addSon(n, newIntNode(nkIntLit, 0))
+  result = newType(tyRange, iter)
+  result.n = n
+  var intType = nilOrSysInt()
+  if intType.isNil: intType = newType(tyInt, iter)
+  rawAddSon(result, intType)
+
+proc createStateField(iter: PSym): PSym =
+  result = newSym(skField, getIdent(":state"), iter, iter.info)
+  result.typ = getStateType(iter)
+
+proc createEnvObj(owner: PSym): PType =
+  # YYY meh, just add the state field for every closure for now, it's too
+  # hard to figure out if it comes from a closure iterator:
+  result = createObj(owner, owner.info)
+  rawAddField(result, createStateField(owner))
+
+proc newIterResult(iter: PSym): PSym =
+  if resultPos < iter.ast.len:
+    result = iter.ast.sons[resultPos].sym
+  else:
+    # XXX a bit hacky:
+    result = newSym(skResult, getIdent":result", iter, iter.info)
+    result.typ = iter.typ.sons[0]
+    incl(result.flags, sfUsed)
+    iter.ast.add newSymNode(result)
+
+proc addHiddenParam(routine: PSym, param: PSym) =
+  assert param.kind == skParam
+  var params = routine.ast.sons[paramsPos]
+  # -1 is correct here as param.position is 0 based but we have at position 0
+  # some nkEffect node:
+  param.position = params.len-1
+  addSon(params, newSymNode(param))
+  incl(routine.typ.flags, tfCapturesEnv)
+  assert sfFromGeneric in param.flags
+  #echo "produced environment: ", param.id, " for ", routine.name.s
+
+proc getHiddenParam(routine: PSym): PSym =
+  let params = routine.ast.sons[paramsPos]
+  let hidden = lastSon(params)
+  internalAssert hidden.kind == nkSym and hidden.sym.kind == skParam
+  result = hidden.sym
+  assert sfFromGeneric in result.flags
+
+proc getEnvParam(routine: PSym): PSym =
+  let params = routine.ast.sons[paramsPos]
+  let hidden = lastSon(params)
+  if hidden.kind == nkSym and hidden.sym.name.s == paramName:
+    result = hidden.sym
+    assert sfFromGeneric in result.flags
+
+proc initIter(iter: PSym): TIter =
+  result.fn = iter
+  if iter.kind == skClosureIterator:
+    var cp = getEnvParam(iter)
+    if cp == nil:
+      result.obj = createEnvObj(iter)
+
+      cp = newSym(skParam, getIdent(paramName), iter, iter.info)
+      incl(cp.flags, sfFromGeneric)
+      cp.typ = newType(tyRef, iter)
+      rawAddSon(cp.typ, result.obj)
+      addHiddenParam(iter, cp)
+    else:
+      result.obj = cp.typ.sons[0]
+      assert result.obj.kind == tyObject
+    internalAssert result.obj.n.len > 0
+    result.state = result.obj.n[0].sym
+    result.closureParam = cp
+    if iter.typ.sons[0] != nil:
+      result.resultSym = newIterResult(iter)
+      #iter.ast.add(newSymNode(c.resultSym))
+
+proc newOuterContext(fn: PSym): POuterContext =
+  new(result)
+  result.fn = fn
+  result.capturedVars = initIntSet()
+  result.processed = initIntSet()
+  initIdNodeTable(result.localsToAccess)
+  initIdTable(result.lambdasToEnv)
+
+proc newEnv(o: POuterContext; up: PEnv, n: PNode; owner: PSym): PEnv =
+  new(result)
+  result.capturedVars = @[]
+  result.up = up
+  result.attachedNode = n
+  result.fn = owner
+  result.vars = initIntSet()
+  result.next = o.head
+  o.head = result
+  if owner.kind != skModule and (up == nil or up.fn != owner):
+    let param = getEnvParam(owner)
+    if param != nil:
+      result.obj = param.typ.sons[0]
+      assert result.obj.kind == tyObject
+  if result.obj.isNil:
+    result.obj = createEnvObj(owner)
+
+proc addCapturedVar(e: PEnv, v: PSym) =
+  for x in e.capturedVars:
+    if x == v: return
+  e.capturedVars.add(v)
+  addField(e.obj, v)
+
+proc newCall(a: PSym, b: PNode): PNode =
+  result = newNodeI(nkCall, a.info)
+  result.add newSymNode(a)
+  result.add b
+
+proc isInnerProc(s, outerProc: PSym): bool =
+  if s.kind in {skProc, skMethod, skConverter, skClosureIterator}:
+    var owner = s.skipGenericOwner
+    while true:
+      if owner.isNil: return false
+      if owner == outerProc: return true
+      owner = owner.owner
+  #s.typ.callConv == ccClosure
+
+proc addClosureParam(fn: PSym; e: PEnv) =
+  var cp = getEnvParam(fn)
+  if cp == nil:
+    cp = newSym(skParam, getIdent(paramName), fn, fn.info)
+    incl(cp.flags, sfFromGeneric)
+    cp.typ = newType(tyRef, fn)
+    rawAddSon(cp.typ, e.obj)
+    addHiddenParam(fn, cp)
+    #else:
+    #cp.typ.sons[0] = e.obj
+    #assert e.obj.kind == tyObject
+
+proc illegalCapture(s: PSym): bool {.inline.} =
+  result = skipTypes(s.typ, abstractInst).kind in
+                   {tyVar, tyOpenArray, tyVarargs} or
+      s.kind == skResult
+
+proc interestingVar(s: PSym): bool {.inline.} =
+  result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
+    sfGlobal notin s.flags
+
+proc nestedAccess(top: PEnv; local: PSym): PNode =
+  # Parts after the transformation are in []:
+  #
+  #  proc main =
+  #    var [:env.]foo = 23
+  #    proc outer(:paramO) =
+  #      [var :envO; createClosure(:envO); :envO.up = paramO]
+  #      proc inner(:paramI) =
+  #        echo [:paramI.up.]foo
+  #      inner([:envO])
+  #    outer([:env])
+  if not interestingVar(local) or top.fn == local.owner:
+    return nil
+  # check it's in fact a captured variable:
+  var it = top
+  while it != nil:
+    if it.vars.contains(local.id): break
+    it = it.up
+  if it == nil: return nil
+  let envParam = top.fn.getEnvParam
+  internalAssert(not envParam.isNil)
+  var access = newSymNode(envParam)
+  it = top.up
+  while it != nil:
+    if it.vars.contains(local.id):
+      access = indirectAccess(access, local, local.info)
+      return access
+    internalAssert it.upField != nil
+    access = indirectAccess(access, it.upField, local.info)
+    it = it.up
+  when false:
+    # Type based expression construction works too, but turned out to hide
+    # other bugs:
+    while true:
+      let obj = access.typ.sons[0]
+      let field = getFieldFromObj(obj, local)
+      if field != nil:
+        return rawIndirectAccess(access, field, local.info)
+      let upField = lookupInRecord(obj.n, getIdent(upName))
+      if upField == nil: break
+      access = rawIndirectAccess(access, upField, local.info)
+  return nil
+
+proc createUpField(obj, fieldType: PType): PSym =
+  let pos = obj.n.len
+  result = newSym(skField, getIdent(upName), obj.owner, obj.owner.info)
+  result.typ = newType(tyRef, obj.owner)
+  result.position = pos
+  rawAddSon(result.typ, fieldType)
+  #rawAddField(obj, result)
+  addField(obj, result)
+
+proc captureVar(o: POuterContext; top: PEnv; local: PSym;
+                info: TLineInfo): bool =
+  # first check if we should be concerned at all:
+  var it = top
+  while it != nil:
+    if it.vars.contains(local.id): break
+    it = it.up
+  if it == nil: return false
+  # yes, so mark every 'up' pointer as taken:
+  if illegalCapture(local) or top.fn.typ.callConv notin {ccClosure, ccDefault}:
+    localError(info, errIllegalCaptureX, local.name.s)
+  it = top
+  while it != nil:
+    if it.vars.contains(local.id): break
+    # keep in mind that the first element of the chain belong to top.fn itself
+    # and these don't need any upFields
+    if it.upField == nil and it.up != nil and it.fn != top.fn:
+      it.upField = createUpField(it.obj, it.up.obj)
+
+    if it.fn != local.owner:
+      it.fn.typ.callConv = ccClosure
+      incl(it.fn.typ.flags, tfCapturesEnv)
+
+      var u = it.up
+      while u != nil and u.fn == it.fn: u = u.up
+      addClosureParam(it.fn, u)
+
+      if idTableGet(o.lambdasToEnv, it.fn) == nil:
+        if u != nil: idTablePut(o.lambdasToEnv, it.fn, u)
+
+    it = it.up
+  # don't do this: 'top' might not require a closure:
+  #if idTableGet(o.lambdasToEnv, it.fn) == nil:
+  #  idTablePut(o.lambdasToEnv, it.fn, top)
+
+  # mark as captured:
+  #if top.iter != nil:
+  #  if not containsOrIncl(o.capturedVars, local.id):
+  #    #addField(top.iter.obj, local)
+  #    addCapturedVar(it, local)
+  #else:
+  incl(o.capturedVars, local.id)
+  addCapturedVar(it, local)
+  result = true
+
+proc semCaptureSym*(s, owner: PSym) =
+  if interestingVar(s) and owner.id != s.owner.id and s.kind != skResult:
+    if owner.typ != nil and not isGenericRoutine(owner):
+      # XXX: is this really safe?
+      # if we capture a var from another generic routine,
+      # it won't be consider captured.
+      owner.typ.callConv = ccClosure
+    #echo "semCaptureSym ", owner.name.s, owner.id, " ", s.name.s, s.id
+    # since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
+    # here
+
+proc gatherVars(o: POuterContext; e: PEnv; n: PNode): int =
+  # gather used vars for closure generation; returns number of captured vars
+  if n == nil: return 0
+  case n.kind
+  of nkSym:
+    var s = n.sym
+    if interestingVar(s) and e.fn != s.owner:
+      if captureVar(o, e, s, n.info): result = 1
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkClosure, nkProcDef,
+     nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkTypeSection:
+    discard
+  else:
+    for k in countup(0, sonsLen(n) - 1):
+      result += gatherVars(o, e, n.sons[k])
+
+proc generateThunk(prc: PNode, dest: PType): PNode =
+  ## Converts 'prc' into '(thunk, nil)' so that it's compatible with
+  ## a closure.
+
+  # we cannot generate a proper thunk here for GC-safety reasons (see internal
+  # documentation):
+  if gCmd == cmdCompileToJS: return prc
+  result = newNodeIT(nkClosure, prc.info, dest)
+  var conv = newNodeIT(nkHiddenStdConv, prc.info, dest)
+  conv.add(emptyNode)
+  conv.add(prc)
+  result.add(conv)
+  result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
+
+proc transformOuterConv(n: PNode): PNode =
+  # numeric types need range checks:
+  var dest = skipTypes(n.typ, abstractVarRange)
+  var source = skipTypes(n.sons[1].typ, abstractVarRange)
+  if dest.kind == tyProc:
+    if dest.callConv == ccClosure and source.callConv == ccDefault:
+      result = generateThunk(n.sons[1], dest)
+
+proc makeClosure(prc: PSym; env: PNode; info: TLineInfo): PNode =
+  result = newNodeIT(nkClosure, info, prc.typ)
+  result.add(newSymNode(prc))
+  if env == nil:
+    result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
+  else:
+    result.add(env)
+
+proc newClosureCreationVar(e: PEnv): PNode =
+  var v = newSym(skVar, getIdent(envName), e.fn, e.attachedNode.info)
+  incl(v.flags, sfShadowed)
+  v.typ = newType(tyRef, e.fn)
+  v.typ.rawAddSon(e.obj)
+  if e.fn.kind == skClosureIterator:
+    let it = initIter(e.fn)
+    addUniqueField(it.obj, v)
+    result = indirectAccess(newSymNode(it.closureParam), v, v.info)
+  else:
+    result = newSymNode(v)
+
+proc getClosureVar(e: PEnv): PNode =
+  if e.createdVar == nil:
+    result = newClosureCreationVar(e)
+    e.createdVar = result
+  else:
+    result = e.createdVar
+
+proc findEnv(o: POuterContext; s: PSym): PEnv =
+  var env = o.head
+  while env != nil:
+    if env.fn == s: break
+    env = env.next
+  internalAssert env != nil and env.up != nil
+  result = env.up
+  while result.fn == s: result = result.up
+
+proc transformInnerProc(o: POuterContext; e: PEnv, n: PNode): PNode =
+  case n.kind
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
+  of nkSym:
+    let s = n.sym
+    if s == e.fn:
+      # recursive calls go through (lambda, hiddenParam):
+      result = makeClosure(s, getEnvParam(s).newSymNode, n.info)
+    elif isInnerProc(s, o.fn) and s.typ.callConv == ccClosure:
+      # ugh: call to some other inner proc;
+      result = makeClosure(s, findEnv(o, s).getClosureVar, n.info)
+    else:
+      # captured symbol?
+      result = nestedAccess(e, n.sym)
+      #result = idNodeTableGet(i.localsToAccess, n.sym)
+    #of nkLambdaKinds, nkIteratorDef:
+    #  if n.typ != nil:
+    #    result = transformInnerProc(o, e, n.sons[namePos])
+    #of nkClosure:
+    #  let x = transformInnerProc(o, e, n.sons[0])
+    #  if x != nil: n.sons[0] = x
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
+     nkLambdaKinds, nkIteratorDef, nkClosure:
+    # don't recurse here:
+    discard
+  else:
+    for j in countup(0, sonsLen(n) - 1):
+      let x = transformInnerProc(o, e, n.sons[j])
+      if x != nil: n.sons[j] = x
+
+proc closureCreationPoint(n: PNode): PNode =
+  if n.kind == nkStmtList and n.len >= 1 and n[0].kind == nkEmpty:
+    # we already have a free slot
+    result = n
+  else:
+    result = newNodeI(nkStmtList, n.info)
+    result.add(emptyNode)
+    result.add(n)
+  #result.flags.incl nfLL
+
+proc addParamsToEnv(fn: PSym; env: PEnv) =
+  let params = fn.typ.n
+  for i in 1.. <params.len:
+    if params.sons[i].kind != nkSym:
+      internalError(params.info, "liftLambdas: strange params")
+    let param = params.sons[i].sym
+    env.vars.incl(param.id)
+  # put the 'result' into the environment so it can be captured:
+  let ast = fn.ast
+  if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
+    env.vars.incl(ast.sons[resultPos].sym.id)
+
+proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
+  if n == nil: return
+  case n.kind
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
+    discard
+  of nkSym:
+    let fn = n.sym
+    if isInnerProc(fn, o.fn) and not containsOrIncl(o.processed, fn.id):
+      let body = fn.getBody
+
+      # handle deeply nested captures:
+      let ex = closureCreationPoint(body)
+      let envB = newEnv(o, env, ex, fn)
+      addParamsToEnv(fn, envB)
+      searchForInnerProcs(o, body, envB)
+      fn.ast.sons[bodyPos] = ex
+
+      let capturedCounter = gatherVars(o, envB, body)
+      # dummy closure param needed?
+      if capturedCounter == 0 and fn.typ.callConv == ccClosure:
+        #assert tfCapturesEnv notin n.sym.typ.flags
+        if idTableGet(o.lambdasToEnv, fn) == nil:
+          idTablePut(o.lambdasToEnv, fn, env)
+        addClosureParam(fn, env)
+
+      elif fn.getEnvParam != nil:
+        # only transform if it really needs a closure:
+        let ti = transformInnerProc(o, envB, body)
+        if ti != nil: fn.ast.sons[bodyPos] = ti
+  of nkLambdaKinds, nkIteratorDef:
+    if n.typ != nil:
+      searchForInnerProcs(o, n.sons[namePos], env)
+  of nkWhileStmt, nkForStmt, nkParForStmt, nkBlockStmt:
+    # some nodes open a new scope, so they are candidates for the insertion
+    # of closure creation; however for simplicity we merge closures between
+    # branches, in fact, only loop bodies are of interest here as only they
+    # yield observable changes in semantics. For Zahary we also
+    # include ``nkBlock``. We don't do this for closure iterators because
+    # 'yield' can produce wrong code otherwise (XXX show example):
+    if env.fn.kind != skClosureIterator:
+      var body = n.len-1
+      for i in countup(0, body - 1): searchForInnerProcs(o, n.sons[i], env)
+      # special handling for the loop body:
+      let ex = closureCreationPoint(n.sons[body])
+      searchForInnerProcs(o, n.sons[body], newEnv(o, env, ex, env.fn))
+      n.sons[body] = ex
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        searchForInnerProcs(o, n.sons[i], env)
+  of nkVarSection, nkLetSection:
+    # we need to compute a mapping var->declaredBlock. Note: The definition
+    # counts, not the block where it is captured!
+    for i in countup(0, sonsLen(n) - 1):
+      var it = n.sons[i]
+      if it.kind == nkCommentStmt: discard
+      elif it.kind == nkIdentDefs:
+        var L = sonsLen(it)
+        if it.sons[0].kind == nkSym:
+          # this can be false for recursive invocations that already
+          # transformed it into 'env.varName':
+          env.vars.incl(it.sons[0].sym.id)
+        searchForInnerProcs(o, it.sons[L-1], env)
+      elif it.kind == nkVarTuple:
+        var L = sonsLen(it)
+        for j in countup(0, L-3):
+          #echo "set: ", it.sons[j].sym.name.s, " ", o.currentBlock == nil
+          if it.sons[j].kind == nkSym:
+            env.vars.incl(it.sons[j].sym.id)
+        searchForInnerProcs(o, it.sons[L-1], env)
+      else:
+        internalError(it.info, "searchForInnerProcs")
+  of nkClosure:
+    searchForInnerProcs(o, n.sons[0], env)
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
+     nkTypeSection:
+    # don't recurse here:
+    discard
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      searchForInnerProcs(o, n.sons[i], env)
+
+proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
+  # Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
+  # mean to be able to capture string literals which have no GC header.
+  # However this can only happen if the capture happens through a parameter,
+  # which is however the only case when we generate an assignment in the first
+  # place.
+  result = newNodeI(nkAsgn, info, 2)
+  result.sons[0] = le
+  result.sons[1] = ri
+
+proc rawClosureCreation(o: POuterContext, scope: PEnv; env: PNode): PNode =
+  result = newNodeI(nkStmtList, env.info)
+  if env.kind == nkSym:
+    var v = newNodeI(nkVarSection, env.info)
+    addVar(v, env)
+    result.add(v)
+  # add 'new' statement:
+  result.add(newCall(getSysSym"internalNew", env))
+
+  # add assignment statements:
+  for local in scope.capturedVars:
+    let fieldAccess = indirectAccess(env, local, env.info)
+    if local.kind == skParam:
+      # maybe later: (sfByCopy in local.flags)
+      # add ``env.param = param``
+      result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
+    # it can happen that we already captured 'local' in some other environment
+    # then we capture by copy for now. This is not entirely correct but better
+    # than nothing:
+    let existing = idNodeTableGet(o.localsToAccess, local)
+    if existing.isNil:
+      idNodeTablePut(o.localsToAccess, local, fieldAccess)
+    else:
+      result.add(newAsgnStmt(fieldAccess, existing, env.info))
+  if scope.upField != nil:
+    # "up" chain has been used:
+    if scope.up.fn != scope.fn:
+      # crosses function boundary:
+      result.add(newAsgnStmt(indirectAccess(env, scope.upField, env.info),
+                 newSymNode(getEnvParam(scope.fn)), env.info))
+    else:
+      result.add(newAsgnStmt(indirectAccess(env, scope.upField, env.info),
+                 getClosureVar(scope.up), env.info))
+
+proc generateClosureCreation(o: POuterContext, scope: PEnv): PNode =
+  var env = getClosureVar(scope)
+  result = rawClosureCreation(o, scope, env)
+
+proc generateIterClosureCreation(o: POuterContext; env: PEnv;
+                                 scope: PNode): PNode =
+  if env.createdVarComesFromIter or env.createdVar.isNil:
+    # we have to create a new closure:
+    result = newClosureCreationVar(env)
+    let cc = rawClosureCreation(o, env, result)
+    var insertPoint = scope.sons[0]
+    if insertPoint.kind == nkEmpty: scope.sons[0] = cc
+    else:
+      assert cc.kind == nkStmtList and insertPoint.kind == nkStmtList
+      for x in cc: insertPoint.add(x)
+    if env.createdVar == nil: env.createdVar = result
+  else:
+    result = env.createdVar
+  env.createdVarComesFromIter = true
+
+proc interestingIterVar(s: PSym): bool {.inline.} =
+  result = s.kind in {skVar, skLet, skTemp, skForVar} and sfGlobal notin s.flags
+
+proc transformOuterProc(o: POuterContext, n: PNode, it: TIter): PNode
+
+proc transformYield(c: POuterContext, n: PNode, it: TIter): PNode =
+  assert it.state != nil
+  assert it.state.typ != nil
+  assert it.state.typ.n != nil
+  inc it.state.typ.n.sons[1].intVal
+  let stateNo = it.state.typ.n.sons[1].intVal
+
+  var stateAsgnStmt = newNodeI(nkAsgn, n.info)
+  stateAsgnStmt.add(rawIndirectAccess(newSymNode(it.closureParam),
+                    it.state, n.info))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+
+  var retStmt = newNodeI(nkReturnStmt, n.info)
+  if n.sons[0].kind != nkEmpty:
+    var a = newNodeI(nkAsgn, n.sons[0].info)
+    var retVal = transformOuterProc(c, n.sons[0], it)
+    addSon(a, newSymNode(it.resultSym))
+    addSon(a, if retVal.isNil: n.sons[0] else: retVal)
+    retStmt.add(a)
+  else:
+    retStmt.add(emptyNode)
+
+  var stateLabelStmt = newNodeI(nkState, n.info)
+  stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
+
+  result = newNodeI(nkStmtList, n.info)
+  result.add(stateAsgnStmt)
+  result.add(retStmt)
+  result.add(stateLabelStmt)
+
+proc transformReturn(c: POuterContext, n: PNode, it: TIter): PNode =
+  result = newNodeI(nkStmtList, n.info)
+  var stateAsgnStmt = newNodeI(nkAsgn, n.info)
+  stateAsgnStmt.add(rawIndirectAccess(newSymNode(it.closureParam), it.state,
+                    n.info))
+  stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
+  result.add(stateAsgnStmt)
+  result.add(n)
+
+proc outerProcSons(o: POuterContext, n: PNode, it: TIter) =
+  for i in countup(0, sonsLen(n) - 1):
+    let x = transformOuterProc(o, n.sons[i], it)
+    if x != nil: n.sons[i] = x
+
+proc liftIterSym(n: PNode; owner: PSym): PNode =
+  # transforms  (iter)  to  (let env = newClosure[iter](); (iter, env))
+  let iter = n.sym
+  assert iter.kind == skClosureIterator
+
+  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
+
+  let hp = getHiddenParam(iter)
+  let env = newSym(skLet, iter.name, owner, n.info)
+  env.typ = hp.typ
+  env.flags = hp.flags
+  var v = newNodeI(nkVarSection, n.info)
+  addVar(v, newSymNode(env))
+  result.add(v)
+  # add 'new' statement:
+  let envAsNode = env.newSymNode
+  result.add newCall(getSysSym"internalNew", envAsNode)
+  result.add makeClosure(iter, envAsNode, n.info)
+
+when false:
+  proc transformRemainingLocals(n: PNode; it: TIter): PNode =
+    assert it.fn.kind == skClosureIterator
+    result = n
+    case n.kind
+    of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
+    of nkSym:
+      let local = n.sym
+      if interestingIterVar(local) and it.fn == local.owner:
+        addUniqueField(it.obj, local)
+        result = indirectAccess(newSymNode(it.closureParam), local, n.info)
+    else:
+      result = newNodeI(n.kind, n.info, n.len)
+      for i in 0.. <n.safeLen:
+        result.sons[i] = transformRemainingLocals(n.sons[i], it)
+
+template envActive(env): expr =
+  (env.capturedVars.len > 0 or env.upField != nil)
+
+# We have to split up environment creation in 2 steps:
+# 1. Generate it and store it in env.replacementNode
+# 2. Insert replacementNode into its forseen slot.
+# This split is necessary so that assignments belonging to closure
+# creation like 'env.param = param' are not transformed
+# into 'env.param = env.param'.
+proc createEnvironments(o: POuterContext) =
+  var env = o.head
+  while env != nil:
+    if envActive(env):
+      var scope = env.attachedNode
+      assert scope.kind == nkStmtList
+      if scope.sons[0].kind == nkEmpty:
+        # prepare for closure construction:
+        env.replacementNode = generateClosureCreation(o, env)
+    env = env.next
+
+proc finishEnvironments(o: POuterContext) =
+  var env = o.head
+  while env != nil:
+    if env.replacementNode != nil:
+      var scope = env.attachedNode
+      assert scope.kind == nkStmtList
+      if scope.sons[0].kind == nkEmpty:
+        # change the empty node to contain the closure construction:
+        scope.sons[0] = env.replacementNode
+        when false:
+          if env.fn.kind == skClosureIterator:
+            scope.sons[0] = transformRemainingLocals(env.replacementNode,
+                                                     initIter(env.fn))
+          else:
+            scope.sons[0] = env.replacementNode
+    env = env.next
+
+proc transformOuterProcBody(o: POuterContext, n: PNode; it: TIter): PNode =
+  if nfLL in n.flags:
+    result = nil
+  elif it.fn.kind == skClosureIterator:
+    # unfortunately control flow is still convoluted and we can end up
+    # multiple times here for the very same iterator. We shield against this
+    # with some rather primitive check for now:
+    if n.kind == nkStmtList and n.len > 0:
+      if n.sons[0].kind == nkGotoState: return nil
+      if n.len > 1 and n[1].kind == nkStmtList and n[1].len > 0 and
+          n[1][0].kind == nkGotoState:
+        return nil
+    result = newNodeI(nkStmtList, it.fn.info)
+    var gs = newNodeI(nkGotoState, it.fn.info)
+    assert it.closureParam != nil
+    assert it.state != nil
+    gs.add(rawIndirectAccess(newSymNode(it.closureParam), it.state, it.fn.info))
+    result.add(gs)
+    var state0 = newNodeI(nkState, it.fn.info)
+    state0.add(newIntNode(nkIntLit, 0))
+    result.add(state0)
+
+    let newBody = transformOuterProc(o, n, it)
+    if newBody != nil:
+      result.add(newBody)
+    else:
+      result.add(n)
+
+    var stateAsgnStmt = newNodeI(nkAsgn, it.fn.info)
+    stateAsgnStmt.add(rawIndirectAccess(newSymNode(it.closureParam),
+                      it.state, it.fn.info))
+    stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
+    result.add(stateAsgnStmt)
+    result.flags.incl nfLL
+  else:
+    result = transformOuterProc(o, n, it)
+    if result != nil: result.flags.incl nfLL
+
+proc transformOuterProc(o: POuterContext, n: PNode; it: TIter): PNode =
+  if n == nil or nfLL in n.flags: return nil
+  case n.kind
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: discard
+  of nkSym:
+    var local = n.sym
+
+    if isInnerProc(local, o.fn) and o.processed.contains(local.id):
+      o.processed.excl(local.id)
+      let body = local.getBody
+      let newBody = transformOuterProcBody(o, body, initIter(local))
+      if newBody != nil:
+        local.ast.sons[bodyPos] = newBody
+
+    if it.fn.kind == skClosureIterator and interestingIterVar(local) and
+        it.fn == local.owner:
+      # every local goes through the closure:
+      #if not containsOrIncl(o.capturedVars, local.id):
+      #  addField(it.obj, local)
+      if contains(o.capturedVars, local.id):
+        # change 'local' to 'closure.local', unless it's a 'byCopy' variable:
+        # if sfByCopy notin local.flags:
+        result = idNodeTableGet(o.localsToAccess, local)
+        assert result != nil, "cannot find: " & local.name.s
+        return result
+      else:
+        addUniqueField(it.obj, local)
+        return indirectAccess(newSymNode(it.closureParam), local, n.info)
+
+    if local.kind == skClosureIterator:
+      # consider: [i1, i2, i1]  Since we merged the iterator's closure
+      # with the captured owning variables, we need to generate the
+      # closure generation code again:
+      if local == o.fn or local == it.fn:
+        message(n.info, errRecursiveDependencyX, local.name.s)
+      # XXX why doesn't this work?
+      var closure = PEnv(idTableGet(o.lambdasToEnv, local))
+      if closure.isNil:
+        return liftIterSym(n, o.fn)
+      else:
+        let createdVar = generateIterClosureCreation(o, closure,
+                                                     closure.attachedNode)
+        let lpt = getHiddenParam(local).typ
+        if lpt != createdVar.typ:
+          assert lpt.kind == tyRef and createdVar.typ.kind == tyRef
+          # fix bug 'tshallowcopy_closures' but report if this gets any weirder:
+          if createdVar.typ.sons[0].len == 1 and lpt.sons[0].len >= 1:
+            createdVar.typ = lpt
+            if createdVar.kind == nkSym: createdVar.sym.typ = lpt
+            closure.obj = lpt.sons[0]
+          else:
+            internalError(n.info, "environment computation failed")
+        return makeClosure(local, createdVar, n.info)
+
+    var closure = PEnv(idTableGet(o.lambdasToEnv, local))
+    if closure != nil:
+      # we need to replace the lambda with '(lambda, env)':
+      let a = closure.createdVar
+      if a != nil:
+        return makeClosure(local, a, n.info)
+      else:
+        # can happen for dummy closures:
+        var scope = closure.attachedNode
+        assert scope.kind == nkStmtList
+        if scope.sons[0].kind == nkEmpty:
+          # change the empty node to contain the closure construction:
+          scope.sons[0] = generateClosureCreation(o, closure)
+        let x = closure.createdVar
+        assert x != nil
+        return makeClosure(local, x, n.info)
+
+    if not contains(o.capturedVars, local.id): return
+    # change 'local' to 'closure.local', unless it's a 'byCopy' variable:
+    # if sfByCopy notin local.flags:
+    result = idNodeTableGet(o.localsToAccess, local)
+    assert result != nil, "cannot find: " & local.name.s
+    # else it is captured by copy and this means that 'outer' should continue
+    # to access the local as a local.
+  of nkLambdaKinds, nkIteratorDef:
+    if n.typ != nil:
+      result = transformOuterProc(o, n.sons[namePos], it)
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef:
+    # don't recurse here:
+    discard
+  of nkClosure:
+    if n.sons[0].kind == nkSym:
+      var local = n.sons[0].sym
+      if isInnerProc(local, o.fn) and o.processed.contains(local.id):
+        o.processed.excl(local.id)
+        let body = local.getBody
+        let newBody = transformOuterProcBody(o, body, initIter(local))
+        if newBody != nil:
+          local.ast.sons[bodyPos] = newBody
+    when false:
+      if n.sons[1].kind == nkSym:
+        var local = n.sons[1].sym
+        if it.fn.kind == skClosureIterator and interestingIterVar(local) and
+            it.fn == local.owner:
+          # every local goes through the closure:
+          addUniqueField(it.obj, local)
+          n.sons[1] = indirectAccess(newSymNode(it.closureParam), local, n.info)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    let x = transformOuterProc(o, n.sons[1], it)
+    if x != nil: n.sons[1] = x
+    result = transformOuterConv(n)
+  of nkYieldStmt:
+    if it.fn.kind == skClosureIterator: result = transformYield(o, n, it)
+    else: outerProcSons(o, n, it)
+  of nkReturnStmt:
+    if it.fn.kind == skClosureIterator: result = transformReturn(o, n, it)
+    else: outerProcSons(o, n, it)
+  else:
+    outerProcSons(o, n, it)
+
+proc liftLambdas*(fn: PSym, body: PNode): PNode =
+  # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
+  # the transformation even when compiling to JS ...
+  if body.kind == nkEmpty or gCmd == cmdCompileToJS or
+      fn.skipGenericOwner.kind != skModule:
+    # ignore forward declaration:
+    result = body
+  else:
+    #if fn.name.s == "sort":
+    #  echo rendertree(fn.ast, {renderIds})
+    var o = newOuterContext(fn)
+    let ex = closureCreationPoint(body)
+    let env = newEnv(o, nil, ex, fn)
+    addParamsToEnv(fn, env)
+    searchForInnerProcs(o, body, env)
+    createEnvironments(o)
+    if fn.kind == skClosureIterator:
+      result = transformOuterProcBody(o, body, initIter(fn))
+    else:
+      discard transformOuterProcBody(o, body, initIter(fn))
+      result = ex
+    finishEnvironments(o)
+    #if fn.name.s == "parseLong":
+    #  echo rendertree(result, {renderIds})
+
+proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
+  if body.kind == nkEmpty or gCmd == cmdCompileToJS:
+    result = body
+  else:
+    var o = newOuterContext(module)
+    let ex = closureCreationPoint(body)
+    let env = newEnv(o, nil, ex, module)
+    searchForInnerProcs(o, body, env)
+    createEnvironments(o)
+    discard transformOuterProc(o, body, initIter(module))
+    finishEnvironments(o)
+    result = ex
+
+# ------------------- iterator transformation --------------------------------
+
+proc liftForLoop*(body: PNode): PNode =
+  # problem ahead: the iterator could be invoked indirectly, but then
+  # we don't know what environment to create here:
+  #
+  # iterator count(): int =
+  #   yield 0
+  #
+  # iterator count2(): int =
+  #   var x = 3
+  #   yield x
+  #   inc x
+  #   yield x
+  #
+  # proc invoke(iter: iterator(): int) =
+  #   for x in iter(): echo x
+  #
+  # --> When to create the closure? --> for the (count) occurrence!
+  discard """
+      for i in foo(): ...
+
+    Is transformed to:
+
+      cl = createClosure()
+      while true:
+        let i = foo(cl)
+        nkBreakState(cl.state)
+        ...
+    """
+  var L = body.len
+  internalAssert body.kind == nkForStmt and body[L-2].kind in nkCallKinds
+  var call = body[L-2]
+
+  result = newNodeI(nkStmtList, body.info)
+
+  # static binding?
+  var env: PSym
+  if call[0].kind == nkSym and call[0].sym.kind == skClosureIterator:
+    # createClosure()
+    let iter = call[0].sym
+    assert iter.kind == skClosureIterator
+    env = copySym(getHiddenParam(iter))
+
+    var v = newNodeI(nkVarSection, body.info)
+    addVar(v, newSymNode(env))
+    result.add(v)
+    # add 'new' statement:
+    result.add(newCall(getSysSym"internalNew", env.newSymNode))
+
+  var loopBody = newNodeI(nkStmtList, body.info, 3)
+  var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
+  whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
+  whileLoop.sons[1] = loopBody
+  result.add whileLoop
+
+  # setup loopBody:
+  # gather vars in a tuple:
+  var v2 = newNodeI(nkLetSection, body.info)
+  var vpart = newNodeI(if L == 3: nkIdentDefs else: nkVarTuple, body.info)
+  for i in 0 .. L-3:
+    assert body[i].kind == nkSym
+    body[i].sym.kind = skLet
+    addSon(vpart, body[i])
+
+  addSon(vpart, ast.emptyNode) # no explicit type
+  if not env.isNil:
+    call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info)
+  addSon(vpart, call)
+  addSon(v2, vpart)
+
+  loopBody.sons[0] = v2
+  var bs = newNodeI(nkBreakState, body.info)
+  bs.addSon(call.sons[0])
+  loopBody.sons[1] = bs
+  loopBody.sons[2] = body[L-1]
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
new file mode 100644
index 000000000..8080e0e8c
--- /dev/null
+++ b/compiler/lexer.nim
@@ -0,0 +1,905 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This scanner is handwritten for efficiency. I used an elegant buffering
+# scheme which I have not seen anywhere else:
+# We guarantee that a whole line is in the buffer. Thus only when scanning
+# the \n or \r character we have to check wether we need to read in the next
+# chunk. (\n or \r already need special handling for incrementing the line
+# counter; choosing both \n and \r allows the scanner to properly read Unix,
+# DOS or Macintosh text files, even when it is not the native format.
+
+import
+  hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
+  wordrecg
+
+const
+  MaxLineLength* = 80         # lines longer than this lead to a warning
+  numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
+  SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
+  SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
+  OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
+    '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
+
+# don't forget to update the 'highlite' module if these charsets should change
+
+type
+  TTokType* = enum
+    tkInvalid, tkEof,         # order is important here!
+    tkSymbol, # keywords:
+    tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
+    tkBind, tkBlock, tkBreak, tkCase, tkCast,
+    tkConcept, tkConst, tkContinue, tkConverter,
+    tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
+    tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
+    tkFinally, tkFor, tkFrom, tkFunc,
+    tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
+    tkIs, tkIsnot, tkIterator,
+    tkLet,
+    tkMacro, tkMethod, tkMixin, tkMod, tkNil, tkNot, tkNotin,
+    tkObject, tkOf, tkOr, tkOut,
+    tkProc, tkPtr, tkRaise, tkRef, tkReturn, tkShl, tkShr, tkStatic,
+    tkTemplate,
+    tkTry, tkTuple, tkType, tkUsing,
+    tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
+    tkYield, # end of keywords
+    tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
+    tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
+    tkFloatLit, tkFloat32Lit, tkFloat64Lit, tkFloat128Lit,
+    tkStrLit, tkRStrLit, tkTripleStrLit,
+    tkGStrLit, tkGTripleStrLit, tkCharLit, tkParLe, tkParRi, tkBracketLe,
+    tkBracketRi, tkCurlyLe, tkCurlyRi,
+    tkBracketDotLe, tkBracketDotRi, # [. and  .]
+    tkCurlyDotLe, tkCurlyDotRi, # {.  and  .}
+    tkParDotLe, tkParDotRi,   # (. and .)
+    tkComma, tkSemiColon,
+    tkColon, tkColonColon, tkEquals, tkDot, tkDotDot,
+    tkOpr, tkComment, tkAccent,
+    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr
+
+  TTokTypes* = set[TTokType]
+
+const
+  tokKeywordLow* = succ(tkSymbol)
+  tokKeywordHigh* = pred(tkIntLit)
+  TokTypeToStr*: array[TTokType, string] = ["tkInvalid", "[EOF]",
+    "tkSymbol",
+    "addr", "and", "as", "asm", "atomic",
+    "bind", "block", "break", "case", "cast",
+    "concept", "const", "continue", "converter",
+    "defer", "discard", "distinct", "div", "do",
+    "elif", "else", "end", "enum", "except", "export",
+    "finally", "for", "from", "func", "generic", "if",
+    "import", "in", "include", "interface", "is", "isnot", "iterator",
+    "let",
+    "macro", "method", "mixin", "mod",
+    "nil", "not", "notin", "object", "of", "or",
+    "out", "proc", "ptr", "raise", "ref", "return",
+    "shl", "shr", "static",
+    "template",
+    "try", "tuple", "type", "using",
+    "var", "when", "while", "with", "without", "xor",
+    "yield",
+    "tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
+    "tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",
+    "tkFloatLit", "tkFloat32Lit", "tkFloat64Lit", "tkFloat128Lit",
+    "tkStrLit", "tkRStrLit",
+    "tkTripleStrLit", "tkGStrLit", "tkGTripleStrLit", "tkCharLit", "(",
+    ")", "[", "]", "{", "}", "[.", ".]", "{.", ".}", "(.", ".)",
+    ",", ";",
+    ":", "::", "=", ".", "..",
+    "tkOpr", "tkComment", "`",
+    "tkSpaces", "tkInfixOpr",
+    "tkPrefixOpr", "tkPostfixOpr"]
+
+type
+  TNumericalBase* = enum
+    base10,                   # base10 is listed as the first element,
+                              # so that it is the correct default value
+    base2, base8, base16
+
+  TToken* = object            # a Nim token
+    tokType*: TTokType        # the type of the token
+    indent*: int              # the indentation; != -1 if the token has been
+                              # preceded with indentation
+    ident*: PIdent            # the parsed identifier
+    iNumber*: BiggestInt      # the parsed integer literal
+    fNumber*: BiggestFloat    # the parsed floating point literal
+    base*: TNumericalBase     # the numerical base; only valid for int
+                              # or float literals
+    strongSpaceA*: int8       # leading spaces of an operator
+    strongSpaceB*: int8       # trailing spaces of an operator
+    literal*: string          # the parsed (string) literal; and
+                              # documentation comments are here too
+    line*, col*: int
+
+  TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
+  TLexer* = object of TBaseLexer
+    fileIdx*: int32
+    indentAhead*: int         # if > 0 an indendation has already been read
+                              # this is needed because scanning comments
+                              # needs so much look-ahead
+    currLineIndent*: int
+    strongSpaces*: bool
+    errorHandler*: TErrorHandler
+
+var gLinesCompiled*: int  # all lines that have been compiled
+
+proc getLineInfo*(L: TLexer, tok: TToken): TLineInfo {.inline.} =
+  newLineInfo(L.fileIdx, tok.line, tok.col)
+
+proc isKeyword*(kind: TTokType): bool =
+  result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
+
+proc isNimIdentifier*(s: string): bool =
+  if s[0] in SymStartChars:
+    var i = 1
+    while i < s.len:
+      if s[i] == '_':
+        inc(i)
+        if s[i] notin SymChars: return
+      if s[i] notin SymChars: return
+      inc(i)
+    result = true
+
+proc tokToStr*(tok: TToken): string =
+  case tok.tokType
+  of tkIntLit..tkInt64Lit: result = $tok.iNumber
+  of tkFloatLit..tkFloat64Lit: result = $tok.fNumber
+  of tkInvalid, tkStrLit..tkCharLit, tkComment: result = tok.literal
+  of tkParLe..tkColon, tkEof, tkAccent:
+    result = TokTypeToStr[tok.tokType]
+  else:
+    if tok.ident != nil:
+      result = tok.ident.s
+    else:
+      internalError("tokToStr")
+      result = ""
+
+proc prettyTok*(tok: TToken): string =
+  if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
+  else: result = tokToStr(tok)
+
+proc printTok*(tok: TToken) =
+  msgWriteln($tok.line & ":" & $tok.col & "\t" &
+      TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
+
+var dummyIdent: PIdent
+
+proc initToken*(L: var TToken) =
+  L.tokType = tkInvalid
+  L.iNumber = 0
+  L.indent = 0
+  L.strongSpaceA = 0
+  L.literal = ""
+  L.fNumber = 0.0
+  L.base = base10
+  L.ident = dummyIdent
+
+proc fillToken(L: var TToken) =
+  L.tokType = tkInvalid
+  L.iNumber = 0
+  L.indent = 0
+  L.strongSpaceA = 0
+  setLen(L.literal, 0)
+  L.fNumber = 0.0
+  L.base = base10
+  L.ident = dummyIdent
+
+proc openLexer*(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
+  openBaseLexer(lex, inputstream)
+  lex.fileIdx = fileidx
+  lex.indentAhead = - 1
+  lex.currLineIndent = 0
+  inc(lex.lineNumber, inputstream.lineOffset)
+
+proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
+  openLexer(lex, filename.fileInfoIdx, inputstream)
+
+proc closeLexer*(lex: var TLexer) =
+  inc(gLinesCompiled, lex.lineNumber)
+  closeBaseLexer(lex)
+
+proc getColumn(L: TLexer): int =
+  result = getColNumber(L, L.bufpos)
+
+proc getLineInfo(L: TLexer): TLineInfo =
+  result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
+
+proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
+  if L.errorHandler.isNil:
+    msgs.message(info, msg, arg)
+  else:
+    L.errorHandler(info, msg, arg)
+
+proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
+  L.dispMessage(getLineInfo(L), msg, arg)
+
+proc lexMessageTok*(L: TLexer, msg: TMsgKind, tok: TToken, arg = "") =
+  var info = newLineInfo(L.fileIdx, tok.line, tok.col)
+  L.dispMessage(info, msg, arg)
+
+proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
+  var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
+  L.dispMessage(info, msg, arg)
+
+proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
+  var pos = L.bufpos              # use registers for pos, buf
+  var buf = L.buf
+  while true:
+    if buf[pos] in chars:
+      add(tok.literal, buf[pos])
+      inc(pos)
+    else:
+      break
+    if buf[pos] == '_':
+      if buf[pos+1] notin chars:
+        lexMessage(L, errInvalidToken, "_")
+        break
+      add(tok.literal, '_')
+      inc(pos)
+  L.bufpos = pos
+
+proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
+  result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
+
+proc isFloatLiteral(s: string): bool =
+  for i in countup(0, len(s) - 1):
+    if s[i] in {'.', 'e', 'E'}:
+      return true
+  result = false
+
+{.push overflowChecks: off.}
+# We need to parse the largest uint literal without overflow checks
+proc unsafeParseUInt(s: string, b: var BiggestInt, start = 0): int =
+  var i = start
+  if s[i] in {'0'..'9'}:
+    b = 0
+    while s[i] in {'0'..'9'}:
+      b = b * 10 + (ord(s[i]) - ord('0'))
+      inc(i)
+      while s[i] == '_': inc(i) # underscores are allowed and ignored
+    result = i - start
+{.pop.} # overflowChecks
+
+proc getNumber(L: var TLexer): TToken =
+  var
+    pos, endpos: int
+    xi: BiggestInt
+  # get the base:
+  result.tokType = tkIntLit   # int literal until we know better
+  result.literal = ""
+  result.base = base10        # BUGFIX
+  pos = L.bufpos     # make sure the literal is correct for error messages:
+  var eallowed = false
+  if L.buf[pos] == '0' and L.buf[pos+1] in {'X', 'x'}:
+    matchUnderscoreChars(L, result, {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x'})
+  else:
+    matchUnderscoreChars(L, result, {'0'..'9', 'b', 'B', 'o', 'c', 'C'})
+    eallowed = true
+  if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
+    add(result.literal, '.')
+    inc(L.bufpos)
+    matchUnderscoreChars(L, result, {'0'..'9'})
+    eallowed = true
+  if eallowed and L.buf[L.bufpos] in {'e', 'E'}:
+    add(result.literal, 'e')
+    inc(L.bufpos)
+    if L.buf[L.bufpos] in {'+', '-'}:
+      add(result.literal, L.buf[L.bufpos])
+      inc(L.bufpos)
+    matchUnderscoreChars(L, result, {'0'..'9'})
+  endpos = L.bufpos
+  if L.buf[endpos] in {'\'', 'f', 'F', 'i', 'I', 'u', 'U'}:
+    if L.buf[endpos] == '\'': inc(endpos)
+    L.bufpos = pos            # restore position
+    case L.buf[endpos]
+    of 'f', 'F':
+      inc(endpos)
+      if (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
+        result.tokType = tkFloat32Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
+        result.tokType = tkFloat64Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '1') and
+           (L.buf[endpos + 1] == '2') and
+           (L.buf[endpos + 2] == '8'):
+        result.tokType = tkFloat128Lit
+        inc(endpos, 3)
+      else:
+        lexMessage(L, errInvalidNumber, result.literal & "'f" & L.buf[endpos])
+    of 'i', 'I':
+      inc(endpos)
+      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
+        result.tokType = tkInt64Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
+        result.tokType = tkInt32Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
+        result.tokType = tkInt16Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '8'):
+        result.tokType = tkInt8Lit
+        inc(endpos)
+      else:
+        lexMessage(L, errInvalidNumber, result.literal & "'i" & L.buf[endpos])
+    of 'u', 'U':
+      inc(endpos)
+      if (L.buf[endpos] == '6') and (L.buf[endpos + 1] == '4'):
+        result.tokType = tkUInt64Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '3') and (L.buf[endpos + 1] == '2'):
+        result.tokType = tkUInt32Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '1') and (L.buf[endpos + 1] == '6'):
+        result.tokType = tkUInt16Lit
+        inc(endpos, 2)
+      elif (L.buf[endpos] == '8'):
+        result.tokType = tkUInt8Lit
+        inc(endpos)
+      else:
+        result.tokType = tkUIntLit
+    else: lexMessage(L, errInvalidNumber, result.literal & "'" & L.buf[endpos])
+  else:
+    L.bufpos = pos            # restore position
+  try:
+    if (L.buf[pos] == '0') and
+        (L.buf[pos + 1] in {'x', 'X', 'b', 'B', 'o', 'O', 'c', 'C'}):
+      inc(pos, 2)
+      xi = 0                  # it may be a base prefix
+      case L.buf[pos - 1]     # now look at the optional type suffix:
+      of 'b', 'B':
+        result.base = base2
+        while true:
+          case L.buf[pos]
+          of '2'..'9', '.':
+            lexMessage(L, errInvalidNumber, result.literal)
+            inc(pos)
+          of '_':
+            if L.buf[pos+1] notin {'0'..'1'}:
+              lexMessage(L, errInvalidToken, "_")
+              break
+            inc(pos)
+          of '0', '1':
+            xi = `shl`(xi, 1) or (ord(L.buf[pos]) - ord('0'))
+            inc(pos)
+          else: break
+      of 'o', 'c', 'C':
+        result.base = base8
+        while true:
+          case L.buf[pos]
+          of '8'..'9', '.':
+            lexMessage(L, errInvalidNumber, result.literal)
+            inc(pos)
+          of '_':
+            if L.buf[pos+1] notin {'0'..'7'}:
+              lexMessage(L, errInvalidToken, "_")
+              break
+            inc(pos)
+          of '0'..'7':
+            xi = `shl`(xi, 3) or (ord(L.buf[pos]) - ord('0'))
+            inc(pos)
+          else: break
+      of 'O':
+        lexMessage(L, errInvalidNumber, result.literal)
+      of 'x', 'X':
+        result.base = base16
+        while true:
+          case L.buf[pos]
+          of '_':
+            if L.buf[pos+1] notin {'0'..'9', 'a'..'f', 'A'..'F'}:
+              lexMessage(L, errInvalidToken, "_")
+              break
+            inc(pos)
+          of '0'..'9':
+            xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('0'))
+            inc(pos)
+          of 'a'..'f':
+            xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('a') + 10)
+            inc(pos)
+          of 'A'..'F':
+            xi = `shl`(xi, 4) or (ord(L.buf[pos]) - ord('A') + 10)
+            inc(pos)
+          else: break
+      else: internalError(getLineInfo(L), "getNumber")
+      case result.tokType
+      of tkIntLit, tkInt64Lit: result.iNumber = xi
+      of tkInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
+      of tkInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
+      of tkInt32Lit: result.iNumber = BiggestInt(toU32(xi))
+      of tkUIntLit, tkUInt64Lit: result.iNumber = xi
+      of tkUInt8Lit: result.iNumber = BiggestInt(int8(toU8(int(xi))))
+      of tkUInt16Lit: result.iNumber = BiggestInt(toU16(int(xi)))
+      of tkUInt32Lit: result.iNumber = BiggestInt(toU32(xi))
+      of tkFloat32Lit:
+        result.fNumber = (cast[PFloat32](addr(xi)))[]
+        # note: this code is endian neutral!
+        # XXX: Test this on big endian machine!
+      of tkFloat64Lit: result.fNumber = (cast[PFloat64](addr(xi)))[]
+      else: internalError(getLineInfo(L), "getNumber")
+    elif isFloatLiteral(result.literal) or (result.tokType == tkFloat32Lit) or
+        (result.tokType == tkFloat64Lit):
+      result.fNumber = parseFloat(result.literal)
+      if result.tokType == tkIntLit: result.tokType = tkFloatLit
+    elif result.tokType == tkUint64Lit:
+      xi = 0
+      let len = unsafeParseUInt(result.literal, xi)
+      if len != result.literal.len or len == 0:
+        raise newException(ValueError, "invalid integer: " & $xi)
+      result.iNumber = xi
+    else:
+      result.iNumber = parseBiggestInt(result.literal)
+      if (result.iNumber < low(int32)) or (result.iNumber > high(int32)):
+        if result.tokType == tkIntLit:
+          result.tokType = tkInt64Lit
+        elif result.tokType in {tkInt8Lit, tkInt16Lit, tkInt32Lit}:
+          lexMessage(L, errNumberOutOfRange, result.literal)
+      elif result.tokType == tkInt8Lit and
+          (result.iNumber < int8.low or result.iNumber > int8.high):
+        lexMessage(L, errNumberOutOfRange, result.literal)
+      elif result.tokType == tkInt16Lit and
+          (result.iNumber < int16.low or result.iNumber > int16.high):
+        lexMessage(L, errNumberOutOfRange, result.literal)
+  except ValueError:
+    lexMessage(L, errInvalidNumber, result.literal)
+  except OverflowError, RangeError:
+    lexMessage(L, errNumberOutOfRange, result.literal)
+  L.bufpos = endpos
+
+proc handleHexChar(L: var TLexer, xi: var int) =
+  case L.buf[L.bufpos]
+  of '0'..'9':
+    xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('0'))
+    inc(L.bufpos)
+  of 'a'..'f':
+    xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('a') + 10)
+    inc(L.bufpos)
+  of 'A'..'F':
+    xi = (xi shl 4) or (ord(L.buf[L.bufpos]) - ord('A') + 10)
+    inc(L.bufpos)
+  else: discard
+
+proc handleDecChars(L: var TLexer, xi: var int) =
+  while L.buf[L.bufpos] in {'0'..'9'}:
+    xi = (xi * 10) + (ord(L.buf[L.bufpos]) - ord('0'))
+    inc(L.bufpos)
+
+proc getEscapedChar(L: var TLexer, tok: var TToken) =
+  inc(L.bufpos)               # skip '\'
+  case L.buf[L.bufpos]
+  of 'n', 'N':
+    if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
+    add(tok.literal, tnl)
+    inc(L.bufpos)
+  of 'r', 'R', 'c', 'C':
+    add(tok.literal, CR)
+    inc(L.bufpos)
+  of 'l', 'L':
+    add(tok.literal, LF)
+    inc(L.bufpos)
+  of 'f', 'F':
+    add(tok.literal, FF)
+    inc(L.bufpos)
+  of 'e', 'E':
+    add(tok.literal, ESC)
+    inc(L.bufpos)
+  of 'a', 'A':
+    add(tok.literal, BEL)
+    inc(L.bufpos)
+  of 'b', 'B':
+    add(tok.literal, BACKSPACE)
+    inc(L.bufpos)
+  of 'v', 'V':
+    add(tok.literal, VT)
+    inc(L.bufpos)
+  of 't', 'T':
+    add(tok.literal, '\t')
+    inc(L.bufpos)
+  of '\'', '\"':
+    add(tok.literal, L.buf[L.bufpos])
+    inc(L.bufpos)
+  of '\\':
+    add(tok.literal, '\\')
+    inc(L.bufpos)
+  of 'x', 'X':
+    inc(L.bufpos)
+    var xi = 0
+    handleHexChar(L, xi)
+    handleHexChar(L, xi)
+    add(tok.literal, chr(xi))
+  of '0'..'9':
+    if matchTwoChars(L, '0', {'0'..'9'}):
+      lexMessage(L, warnOctalEscape)
+    var xi = 0
+    handleDecChars(L, xi)
+    if (xi <= 255): add(tok.literal, chr(xi))
+    else: lexMessage(L, errInvalidCharacterConstant)
+  else: lexMessage(L, errInvalidCharacterConstant)
+
+proc newString(s: cstring, len: int): string =
+  ## XXX, how come there is no support for this?
+  result = newString(len)
+  for i in 0 .. <len:
+    result[i] = s[i]
+
+proc handleCRLF(L: var TLexer, pos: int): int =
+  template registerLine =
+    let col = L.getColNumber(pos)
+
+    if col > MaxLineLength:
+      lexMessagePos(L, hintLineTooLong, pos)
+
+    if optEmbedOrigSrc in gGlobalOptions:
+      let lineStart = cast[ByteAddress](L.buf) + L.lineStart
+      let line = newString(cast[cstring](lineStart), col)
+      addSourceLine(L.fileIdx, line)
+
+  case L.buf[pos]
+  of CR:
+    registerLine()
+    result = nimlexbase.handleCR(L, pos)
+  of LF:
+    registerLine()
+    result = nimlexbase.handleLF(L, pos)
+  else: result = pos
+
+proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
+  var pos = L.bufpos + 1          # skip "
+  var buf = L.buf                 # put `buf` in a register
+  var line = L.lineNumber         # save linenumber for better error message
+  if buf[pos] == '\"' and buf[pos+1] == '\"':
+    tok.tokType = tkTripleStrLit # long string literal:
+    inc(pos, 2)               # skip ""
+    # skip leading newline:
+    if buf[pos] in {' ', '\t'}:
+      var newpos = pos+1
+      while buf[newpos] in {' ', '\t'}: inc newpos
+      if buf[newpos] in {CR, LF}: pos = newpos
+    pos = handleCRLF(L, pos)
+    buf = L.buf
+    while true:
+      case buf[pos]
+      of '\"':
+        if buf[pos+1] == '\"' and buf[pos+2] == '\"' and
+            buf[pos+3] != '\"':
+          L.bufpos = pos + 3 # skip the three """
+          break
+        add(tok.literal, '\"')
+        inc(pos)
+      of CR, LF:
+        pos = handleCRLF(L, pos)
+        buf = L.buf
+        add(tok.literal, tnl)
+      of nimlexbase.EndOfFile:
+        var line2 = L.lineNumber
+        L.lineNumber = line
+        lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
+        L.lineNumber = line2
+        break
+      else:
+        add(tok.literal, buf[pos])
+        inc(pos)
+  else:
+    # ordinary string literal
+    if rawMode: tok.tokType = tkRStrLit
+    else: tok.tokType = tkStrLit
+    while true:
+      var c = buf[pos]
+      if c == '\"':
+        if rawMode and buf[pos+1] == '\"':
+          inc(pos, 2)
+          add(tok.literal, '"')
+        else:
+          inc(pos) # skip '"'
+          break
+      elif c in {CR, LF, nimlexbase.EndOfFile}:
+        lexMessage(L, errClosingQuoteExpected)
+        break
+      elif (c == '\\') and not rawMode:
+        L.bufpos = pos
+        getEscapedChar(L, tok)
+        pos = L.bufpos
+      else:
+        add(tok.literal, c)
+        inc(pos)
+    L.bufpos = pos
+
+proc getCharacter(L: var TLexer, tok: var TToken) =
+  inc(L.bufpos)               # skip '
+  var c = L.buf[L.bufpos]
+  case c
+  of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
+  of '\\': getEscapedChar(L, tok)
+  else:
+    tok.literal = $c
+    inc(L.bufpos)
+  if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
+  inc(L.bufpos)               # skip '
+
+proc getSymbol(L: var TLexer, tok: var TToken) =
+  var h: THash = 0
+  var pos = L.bufpos
+  var buf = L.buf
+  while true:
+    var c = buf[pos]
+    case c
+    of 'a'..'z', '0'..'9', '\x80'..'\xFF':
+      h = h !& ord(c)
+    of 'A'..'Z':
+      c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
+      h = h !& ord(c)
+    of '_':
+      if buf[pos+1] notin SymChars:
+        lexMessage(L, errInvalidToken, "_")
+        break
+    else: break
+    inc(pos)
+  h = !$h
+  tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
+  L.bufpos = pos
+  if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
+      (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
+    tok.tokType = tkSymbol
+  else:
+    tok.tokType = TTokType(tok.ident.id + ord(tkSymbol))
+
+proc endOperator(L: var TLexer, tok: var TToken, pos: int,
+                 hash: THash) {.inline.} =
+  var h = !$hash
+  tok.ident = getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h)
+  if (tok.ident.id < oprLow) or (tok.ident.id > oprHigh): tok.tokType = tkOpr
+  else: tok.tokType = TTokType(tok.ident.id - oprLow + ord(tkColon))
+  L.bufpos = pos
+
+proc getOperator(L: var TLexer, tok: var TToken) =
+  var pos = L.bufpos
+  var buf = L.buf
+  var h: THash = 0
+  while true:
+    var c = buf[pos]
+    if c notin OpChars: break
+    h = h !& ord(c)
+    inc(pos)
+  endOperator(L, tok, pos, h)
+  # advance pos but don't store it in L.bufpos so the next token (which might
+  # be an operator too) gets the preceding spaces:
+  tok.strongSpaceB = 0
+  while buf[pos] == ' ':
+    inc pos
+    inc tok.strongSpaceB
+  if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
+    tok.strongSpaceB = -1
+
+proc scanComment(L: var TLexer, tok: var TToken) =
+  var pos = L.bufpos
+  var buf = L.buf
+  when not defined(nimfix):
+    assert buf[pos+1] == '#'
+    if buf[pos+2] == '[':
+      if buf[pos+3] == ']':
+        #  ##[] is the (rather complex) "cursor token" for idetools
+        tok.tokType = tkComment
+        tok.literal = "[]"
+        inc(L.bufpos, 4)
+        return
+      else:
+        lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
+
+  tok.tokType = tkComment
+  # iNumber contains the number of '\n' in the token
+  tok.iNumber = 0
+  when defined(nimfix):
+    var col = getColNumber(L, pos)
+  while true:
+    var lastBackslash = -1
+    while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
+      if buf[pos] == '\\': lastBackslash = pos+1
+      add(tok.literal, buf[pos])
+      inc(pos)
+    when defined(nimfix):
+      if lastBackslash > 0:
+        # a backslash is a continuation character if only followed by spaces
+        # plus a newline:
+        while buf[lastBackslash] == ' ': inc(lastBackslash)
+        if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
+          # false positive:
+          lastBackslash = -1
+
+    pos = handleCRLF(L, pos)
+    buf = L.buf
+    var indent = 0
+    while buf[pos] == ' ':
+      inc(pos)
+      inc(indent)
+
+    when defined(nimfix):
+      template doContinue(): expr =
+        buf[pos] == '#' and (col == indent or lastBackslash > 0)
+    else:
+      template doContinue(): expr =
+        buf[pos] == '#' and buf[pos+1] == '#'
+    if doContinue():
+      tok.literal.add "\n"
+      when defined(nimfix): col = indent
+      inc tok.iNumber
+    else:
+      if buf[pos] > ' ':
+        L.indentAhead = indent
+      break
+  L.bufpos = pos
+
+proc skip(L: var TLexer, tok: var TToken) =
+  var pos = L.bufpos
+  var buf = L.buf
+  tok.strongSpaceA = 0
+  while true:
+    case buf[pos]
+    of ' ':
+      inc(pos)
+      inc(tok.strongSpaceA)
+    of '\t':
+      lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
+      inc(pos)
+    of CR, LF:
+      pos = handleCRLF(L, pos)
+      buf = L.buf
+      var indent = 0
+      while buf[pos] == ' ':
+        inc(pos)
+        inc(indent)
+      tok.strongSpaceA = 0
+      when defined(nimfix):
+        template doBreak(): expr = buf[pos] > ' '
+      else:
+        template doBreak(): expr =
+          buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
+      if doBreak():
+        tok.indent = indent
+        L.currLineIndent = indent
+        break
+    of '#':
+      when defined(nimfix):
+        break
+      else:
+        # do not skip documentation comment:
+        if buf[pos+1] == '#': break
+        if buf[pos+1] == '[':
+          lexMessagePos(L, warnDeprecated, pos, "use '# [' instead; '#['")
+        while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
+    else:
+      break                   # EndOfFile also leaves the loop
+  L.bufpos = pos
+
+proc rawGetTok*(L: var TLexer, tok: var TToken) =
+  fillToken(tok)
+  if L.indentAhead >= 0:
+    tok.indent = L.indentAhead
+    L.currLineIndent = L.indentAhead
+    L.indentAhead = -1
+  else:
+    tok.indent = -1
+  skip(L, tok)
+  var c = L.buf[L.bufpos]
+  tok.line = L.lineNumber
+  tok.col = getColNumber(L, L.bufpos)
+  if c in SymStartChars - {'r', 'R', 'l'}:
+    getSymbol(L, tok)
+  else:
+    case c
+    of '#':
+      scanComment(L, tok)
+    of '*':
+      # '*:' is unfortunately a special case, because it is two tokens in
+      # 'var v*: int'.
+      if L.buf[L.bufpos+1] == ':' and L.buf[L.bufpos+2] notin OpChars:
+        var h = 0 !& ord('*')
+        endOperator(L, tok, L.bufpos+1, h)
+      else:
+        getOperator(L, tok)
+    of ',':
+      tok.tokType = tkComma
+      inc(L.bufpos)
+    of 'l':
+      # if we parsed exactly one character and its a small L (l), this
+      # is treated as a warning because it may be confused with the number 1
+      if L.buf[L.bufpos+1] notin (SymChars + {'_'}):
+        lexMessage(L, warnSmallLshouldNotBeUsed)
+      getSymbol(L, tok)
+    of 'r', 'R':
+      if L.buf[L.bufpos + 1] == '\"':
+        inc(L.bufpos)
+        getString(L, tok, true)
+      else:
+        getSymbol(L, tok)
+    of '(':
+      inc(L.bufpos)
+      if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
+        tok.tokType = tkParDotLe
+        inc(L.bufpos)
+      else:
+        tok.tokType = tkParLe
+    of ')':
+      tok.tokType = tkParRi
+      inc(L.bufpos)
+    of '[':
+      inc(L.bufpos)
+      if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
+        tok.tokType = tkBracketDotLe
+        inc(L.bufpos)
+      else:
+        tok.tokType = tkBracketLe
+    of ']':
+      tok.tokType = tkBracketRi
+      inc(L.bufpos)
+    of '.':
+      if L.buf[L.bufpos+1] == ']':
+        tok.tokType = tkBracketDotRi
+        inc(L.bufpos, 2)
+      elif L.buf[L.bufpos+1] == '}':
+        tok.tokType = tkCurlyDotRi
+        inc(L.bufpos, 2)
+      elif L.buf[L.bufpos+1] == ')':
+        tok.tokType = tkParDotRi
+        inc(L.bufpos, 2)
+      else:
+        getOperator(L, tok)
+    of '{':
+      inc(L.bufpos)
+      if L.buf[L.bufpos] == '.' and L.buf[L.bufpos+1] != '.':
+        tok.tokType = tkCurlyDotLe
+        inc(L.bufpos)
+      else:
+        tok.tokType = tkCurlyLe
+    of '}':
+      tok.tokType = tkCurlyRi
+      inc(L.bufpos)
+    of ';':
+      tok.tokType = tkSemiColon
+      inc(L.bufpos)
+    of '`':
+      tok.tokType = tkAccent
+      inc(L.bufpos)
+    of '_':
+      inc(L.bufpos)
+      if L.buf[L.bufpos] notin SymChars:
+        tok.tokType = tkSymbol
+        tok.ident = getIdent("_")
+      else:
+        tok.literal = $c
+        tok.tokType = tkInvalid
+        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
+    of '\"':
+      # check for extended raw string literal:
+      var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
+      getString(L, tok, rawMode)
+      if rawMode:
+        # tkRStrLit -> tkGStrLit
+        # tkTripleStrLit -> tkGTripleStrLit
+        inc(tok.tokType, 2)
+    of '\'':
+      tok.tokType = tkCharLit
+      getCharacter(L, tok)
+      tok.tokType = tkCharLit
+    of '0'..'9':
+      tok = getNumber(L)
+    else:
+      if c in OpChars:
+        getOperator(L, tok)
+      elif c == nimlexbase.EndOfFile:
+        tok.tokType = tkEof
+        tok.indent = 0
+      else:
+        tok.literal = $c
+        tok.tokType = tkInvalid
+        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
+        inc(L.bufpos)
+
+dummyIdent = getIdent("")
diff --git a/compiler/lists.nim b/compiler/lists.nim
new file mode 100644
index 000000000..1b2b91bff
--- /dev/null
+++ b/compiler/lists.nim
@@ -0,0 +1,119 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements a generic doubled linked list.
+# TODO Remove this and replace it with something sensible
+import os
+type 
+  PListEntry* = ref TListEntry
+  TListEntry* = object of RootObj
+    prev*, next*: PListEntry
+
+  TStrEntry* = object of TListEntry
+    data*: string
+
+  PStrEntry* = ref TStrEntry
+  TLinkedList* = object       # for the "find" operation:
+    head*, tail*: PListEntry
+    counter*: int
+
+  TCompareProc* = proc (entry: PListEntry, closure: pointer): bool {.nimcall.}
+
+proc initLinkedList*(list: var TLinkedList) = 
+  list.counter = 0
+  list.head = nil
+  list.tail = nil
+
+proc append*(list: var TLinkedList, entry: PListEntry) = 
+  inc(list.counter)
+  entry.next = nil
+  entry.prev = list.tail
+  if list.tail != nil: 
+    assert(list.tail.next == nil)
+    list.tail.next = entry
+  list.tail = entry
+  if list.head == nil: list.head = entry
+  
+proc contains*(list: TLinkedList, data: string): bool = 
+  var it = list.head
+  while it != nil: 
+    if PStrEntry(it).data == data: 
+      return true
+    it = it.next
+  
+proc newStrEntry(data: string): PStrEntry = 
+  new(result)
+  result.data = data
+
+proc appendStr*(list: var TLinkedList, data: string) = 
+  append(list, newStrEntry(data))
+
+proc includeStr*(list: var TLinkedList, data: string): bool = 
+  if contains(list, data): return true
+  appendStr(list, data)       # else: add to list
+
+proc prepend*(list: var TLinkedList, entry: PListEntry) = 
+  inc(list.counter)
+  entry.prev = nil
+  entry.next = list.head
+  if list.head != nil: 
+    assert(list.head.prev == nil)
+    list.head.prev = entry
+  list.head = entry
+  if list.tail == nil: list.tail = entry
+
+proc prependStr*(list: var TLinkedList, data: string) = 
+  prepend(list, newStrEntry(data))
+
+proc insertBefore*(list: var TLinkedList, pos, entry: PListEntry) = 
+  assert(pos != nil)
+  if pos == list.head: 
+    prepend(list, entry)
+  else: 
+    inc(list.counter)
+    entry.next = pos
+    entry.prev = pos.prev
+    if pos.prev != nil: pos.prev.next = entry
+    pos.prev = entry
+ 
+proc remove*(list: var TLinkedList, entry: PListEntry) = 
+  dec(list.counter)
+  if entry == list.tail: 
+    list.tail = entry.prev
+  if entry == list.head: 
+    list.head = entry.next
+  if entry.next != nil: entry.next.prev = entry.prev
+  if entry.prev != nil: entry.prev.next = entry.next
+
+proc bringToFront*(list: var TLinkedList, entry: PListEntry) =
+  when true:
+    list.remove entry
+    list.prepend entry
+  else:
+    if entry == list.head: return
+    if entry == list.tail: list.tail = entry.prev
+    if entry.next != nil: entry.next.prev = entry.prev
+    if entry.prev != nil: entry.prev.next = entry.next
+    entry.prev = nil
+    entry.next = list.head
+    list.head = entry
+
+proc excludePath*(list: var TLinkedList, data: string) =
+  var it = list.head
+  while it != nil:
+    let nxt = it.next
+    if cmpPaths(PStrEntry(it).data, data) == 0:
+      remove(list, it)
+    it = nxt
+
+proc find*(list: TLinkedList, fn: TCompareProc, closure: pointer): PListEntry = 
+  result = list.head
+  while result != nil:
+    if fn(result, closure): return 
+    result = result.next
diff --git a/compiler/llstream.nim b/compiler/llstream.nim
new file mode 100644
index 000000000..18ca4aec7
--- /dev/null
+++ b/compiler/llstream.nim
@@ -0,0 +1,212 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Low-level streams for high performance.
+
+import 
+  strutils
+
+when not defined(windows) and defined(useGnuReadline):
+  import rdstdin
+
+type 
+  TLLStreamKind* = enum       # enum of different stream implementations
+    llsNone,                  # null stream: reading and writing has no effect
+    llsString,                # stream encapsulates a string
+    llsFile,                  # stream encapsulates a file
+    llsStdIn                  # stream encapsulates stdin
+  TLLStream* = object of RootObj
+    kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
+    f*: File
+    s*: string
+    rd*, wr*: int             # for string streams
+    lineOffset*: int          # for fake stdin line numbers
+  
+  PLLStream* = ref TLLStream
+
+proc llStreamOpen*(data: string): PLLStream = 
+  new(result)
+  result.s = data
+  result.kind = llsString
+
+proc llStreamOpen*(f: File): PLLStream = 
+  new(result)
+  result.f = f
+  result.kind = llsFile
+
+proc llStreamOpen*(filename: string, mode: FileMode): PLLStream = 
+  new(result)
+  result.kind = llsFile
+  if not open(result.f, filename, mode): result = nil
+  
+proc llStreamOpen*(): PLLStream = 
+  new(result)
+  result.kind = llsNone
+
+proc llStreamOpenStdIn*(): PLLStream = 
+  new(result)
+  result.kind = llsStdIn
+  result.s = ""
+  result.lineOffset = -1
+
+proc llStreamClose*(s: PLLStream) = 
+  case s.kind
+  of llsNone, llsString, llsStdIn: 
+    discard
+  of llsFile: 
+    close(s.f)
+
+when not declared(readLineFromStdin): 
+  # fallback implementation:
+  proc readLineFromStdin(prompt: string, line: var string): bool =
+    stdout.write(prompt)
+    result = readLine(stdin, line)
+    if not result:
+      stdout.write("\n")
+      quit(0)
+
+proc endsWith*(x: string, s: set[char]): bool =
+  var i = x.len-1
+  while i >= 0 and x[i] == ' ': dec(i)
+  if i >= 0 and x[i] in s:
+    result = true
+
+const 
+  LineContinuationOprs = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^',
+                          '|', '%', '&', '$', '@', '~', ','}
+  AdditionalLineContinuationOprs = {'#', ':', '='}
+
+proc endsWithOpr*(x: string): bool =
+  # also used by the standard template filter:
+  result = x.endsWith(LineContinuationOprs)
+
+proc continueLine(line: string, inTripleString: bool): bool {.inline.} =
+  result = inTripleString or
+      line[0] == ' ' or
+      line.endsWith(LineContinuationOprs+AdditionalLineContinuationOprs)
+
+proc countTriples(s: string): int =
+  var i = 0
+  while i < s.len:
+    if s[i] == '"' and s[i+1] == '"' and s[i+2] == '"':
+      inc result
+      inc i, 2
+    inc i
+
+proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
+  s.s = ""
+  s.rd = 0
+  var line = newStringOfCap(120)
+  var triples = 0
+  while readLineFromStdin(if s.s.len == 0: ">>> " else: "... ", line): 
+    add(s.s, line)
+    add(s.s, "\n")
+    inc triples, countTriples(line)
+    if not continueLine(line, (triples and 1) == 1): break
+  inc(s.lineOffset)
+  result = min(bufLen, len(s.s) - s.rd)
+  if result > 0: 
+    copyMem(buf, addr(s.s[s.rd]), result)
+    inc(s.rd, result)
+
+proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int = 
+  case s.kind
+  of llsNone: 
+    result = 0
+  of llsString: 
+    result = min(bufLen, len(s.s) - s.rd)
+    if result > 0: 
+      copyMem(buf, addr(s.s[0 + s.rd]), result)
+      inc(s.rd, result)
+  of llsFile: 
+    result = readBuffer(s.f, buf, bufLen)
+  of llsStdIn: 
+    result = llReadFromStdin(s, buf, bufLen)
+  
+proc llStreamReadLine*(s: PLLStream, line: var string): bool =
+  setLen(line, 0)
+  case s.kind
+  of llsNone:
+    result = true
+  of llsString:
+    while s.rd < len(s.s):
+      case s.s[s.rd]
+      of '\x0D':
+        inc(s.rd)
+        if s.s[s.rd] == '\x0A': inc(s.rd)
+        break
+      of '\x0A':
+        inc(s.rd)
+        break
+      else:
+        add(line, s.s[s.rd])
+        inc(s.rd)
+    result = line.len > 0 or s.rd < len(s.s)
+  of llsFile:
+    result = readLine(s.f, line)
+  of llsStdIn:
+    result = readLine(stdin, line)
+    
+proc llStreamWrite*(s: PLLStream, data: string) = 
+  case s.kind
+  of llsNone, llsStdIn: 
+    discard
+  of llsString: 
+    add(s.s, data)
+    inc(s.wr, len(data))
+  of llsFile: 
+    write(s.f, data)
+  
+proc llStreamWriteln*(s: PLLStream, data: string) = 
+  llStreamWrite(s, data)
+  llStreamWrite(s, "\n")
+
+proc llStreamWrite*(s: PLLStream, data: char) = 
+  var c: char
+  case s.kind
+  of llsNone, llsStdIn: 
+    discard
+  of llsString: 
+    add(s.s, data)
+    inc(s.wr)
+  of llsFile: 
+    c = data
+    discard writeBuffer(s.f, addr(c), sizeof(c))
+
+proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) = 
+  case s.kind
+  of llsNone, llsStdIn: 
+    discard
+  of llsString: 
+    if buflen > 0: 
+      setLen(s.s, len(s.s) + buflen)
+      copyMem(addr(s.s[0 + s.wr]), buf, buflen)
+      inc(s.wr, buflen)
+  of llsFile: 
+    discard writeBuffer(s.f, buf, buflen)
+  
+proc llStreamReadAll*(s: PLLStream): string = 
+  const 
+    bufSize = 2048
+  case s.kind
+  of llsNone, llsStdIn: 
+    result = ""
+  of llsString: 
+    if s.rd == 0: result = s.s
+    else: result = substr(s.s, s.rd)
+    s.rd = len(s.s)
+  of llsFile: 
+    result = newString(bufSize)
+    var bytes = readBuffer(s.f, addr(result[0]), bufSize)
+    var i = bytes
+    while bytes == bufSize: 
+      setLen(result, i + bufSize)
+      bytes = readBuffer(s.f, addr(result[i + 0]), bufSize)
+      inc(i, bytes)
+    setLen(result, i)
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
new file mode 100644
index 000000000..88e32404a
--- /dev/null
+++ b/compiler/lookups.nim
@@ -0,0 +1,402 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements lookup helpers.
+
+import
+  intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
+  renderer, wordrecg, idgen, nimfix.prettybase
+
+proc ensureNoMissingOrUnusedSymbols(scope: PScope)
+
+proc considerQuotedIdent*(n: PNode): PIdent =
+  ## Retrieve a PIdent from a PNode, taking into account accent nodes.
+  case n.kind
+  of nkIdent: result = n.ident
+  of nkSym: result = n.sym.name
+  of nkAccQuoted:
+    case n.len
+    of 0:
+      localError(n.info, errIdentifierExpected, renderTree(n))
+      result = getIdent"<Error>"
+    of 1: result = considerQuotedIdent(n.sons[0])
+    else:
+      var id = ""
+      for i in 0.. <n.len:
+        let x = n.sons[i]
+        case x.kind
+        of nkIdent: id.add(x.ident.s)
+        of nkSym: id.add(x.sym.name.s)
+        else:
+          localError(n.info, errIdentifierExpected, renderTree(n))
+          return getIdent"<Error>"
+      result = getIdent(id)
+  of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym.name
+  else:
+    localError(n.info, errIdentifierExpected, renderTree(n))
+    result = getIdent"<Error>"
+
+template addSym*(scope: PScope, s: PSym) =
+  strTableAdd(scope.symbols, s)
+
+proc addUniqueSym*(scope: PScope, s: PSym): bool =
+  result = not strTableIncl(scope.symbols, s)
+
+proc openScope*(c: PContext): PScope {.discardable.} =
+  result = PScope(parent: c.currentScope,
+                  symbols: newStrTable(),
+                  depthLevel: c.scopeDepth + 1)
+  c.currentScope = result
+
+proc rawCloseScope*(c: PContext) =
+  c.currentScope = c.currentScope.parent
+
+proc closeScope*(c: PContext) =
+  ensureNoMissingOrUnusedSymbols(c.currentScope)
+  rawCloseScope(c)
+
+iterator walkScopes*(scope: PScope): PScope =
+  var current = scope
+  while current != nil:
+    yield current
+    current = current.parent
+
+proc skipAlias*(s: PSym; n: PNode): PSym =
+  if s == nil or s.kind != skAlias:
+    result = s
+  else:
+    result = s.owner
+    if gCmd == cmdPretty:
+      prettybase.replaceDeprecated(n.info, s, result)
+    else:
+      message(n.info, warnDeprecated, "use " & result.name.s & " instead; " &
+              s.name.s)
+
+proc localSearchInScope*(c: PContext, s: PIdent): PSym =
+  result = strTableGet(c.currentScope.symbols, s)
+
+proc searchInScopes*(c: PContext, s: PIdent): PSym =
+  for scope in walkScopes(c.currentScope):
+    result = strTableGet(scope.symbols, s)
+    if result != nil: return
+  result = nil
+
+proc debugScopes*(c: PContext; limit=0) {.deprecated.} =
+  var i = 0
+  for scope in walkScopes(c.currentScope):
+    echo "scope ", i
+    for h in 0 .. high(scope.symbols.data):
+      if scope.symbols.data[h] != nil:
+        echo scope.symbols.data[h].name.s
+    if i == limit: break
+    inc i
+
+proc searchInScopes*(c: PContext, s: PIdent, filter: TSymKinds): PSym =
+  for scope in walkScopes(c.currentScope):
+    result = strTableGet(scope.symbols, s)
+    if result != nil and result.kind in filter: return
+  result = nil
+
+proc errorSym*(c: PContext, n: PNode): PSym =
+  ## creates an error symbol to avoid cascading errors (for IDE support)
+  var m = n
+  # ensure that 'considerQuotedIdent' can't fail:
+  if m.kind == nkDotExpr: m = m.sons[1]
+  let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
+      considerQuotedIdent(m)
+    else:
+      getIdent("err:" & renderTree(m))
+  result = newSym(skError, ident, getCurrOwner(), n.info)
+  result.typ = errorType(c)
+  incl(result.flags, sfDiscardable)
+  # pretend it's imported from some unknown module to prevent cascading errors:
+  if gCmd != cmdInteractive and c.inCompilesContext == 0:
+    c.importTable.addSym(result)
+
+type
+  TOverloadIterMode* = enum
+    oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice,
+    oimSymChoiceLocalLookup
+  TOverloadIter*{.final.} = object
+    it*: TIdentIter
+    m*: PSym
+    mode*: TOverloadIterMode
+    symChoiceIndex*: int
+    scope*: PScope
+    inSymChoice: IntSet
+
+proc getSymRepr*(s: PSym): string =
+  case s.kind
+  of skProc, skMethod, skConverter, skIterators: result = getProcHeader(s)
+  else: result = s.name.s
+
+proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
+  # check if all symbols have been used and defined:
+  var it: TTabIter
+  var s = initTabIter(it, scope.symbols)
+  var missingImpls = 0
+  while s != nil:
+    if sfForward in s.flags:
+      # too many 'implementation of X' errors are annoying
+      # and slow 'suggest' down:
+      if missingImpls == 0:
+        localError(s.info, errImplOfXexpected, getSymRepr(s))
+      inc missingImpls
+    elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
+      # BUGFIX: check options in s!
+      if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
+        # XXX: implicit type params are currently skTypes
+        # maybe they can be made skGenericParam as well.
+        if s.typ != nil and tfImplicitTypeParam notin s.typ.flags:
+          message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
+    s = nextIter(it, scope.symbols)
+
+proc wrongRedefinition*(info: TLineInfo, s: string) =
+  if gCmd != cmdInteractive:
+    localError(info, errAttemptToRedefine, s)
+
+proc addDecl*(c: PContext, sym: PSym) =
+  if not c.currentScope.addUniqueSym(sym):
+    wrongRedefinition(sym.info, sym.name.s)
+
+proc addPrelimDecl*(c: PContext, sym: PSym) =
+  discard c.currentScope.addUniqueSym(sym)
+
+proc addDeclAt*(scope: PScope, sym: PSym) =
+  if not scope.addUniqueSym(sym):
+    wrongRedefinition(sym.info, sym.name.s)
+
+proc addInterfaceDeclAux(c: PContext, sym: PSym) =
+  if sfExported in sym.flags:
+    # add to interface:
+    if c.module != nil: strTableAdd(c.module.tab, sym)
+    else: internalError(sym.info, "addInterfaceDeclAux")
+
+proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
+  addDeclAt(scope, sym)
+  addInterfaceDeclAux(c, sym)
+
+proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
+  if fn.kind notin OverloadableSyms:
+    internalError(fn.info, "addOverloadableSymAt")
+    return
+  let check = strTableGet(scope.symbols, fn.name)
+  if check != nil and check.kind notin OverloadableSyms:
+    wrongRedefinition(fn.info, fn.name.s)
+  else:
+    scope.addSym(fn)
+
+proc addInterfaceDecl*(c: PContext, sym: PSym) =
+  # it adds the symbol to the interface if appropriate
+  addDecl(c, sym)
+  addInterfaceDeclAux(c, sym)
+
+proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
+  # it adds the symbol to the interface if appropriate
+  addOverloadableSymAt(scope, sym)
+  addInterfaceDeclAux(c, sym)
+
+when defined(nimfix):
+  import strutils
+
+  # when we cannot find the identifier, retry with a changed identifer:
+  proc altSpelling(x: PIdent): PIdent =
+    case x.s[0]
+    of 'A'..'Z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
+    of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1))
+    else: result = x
+
+  template fixSpelling(n: PNode; ident: PIdent; op: expr) =
+    let alt = ident.altSpelling
+    result = op(c, alt).skipAlias(n)
+    if result != nil:
+      prettybase.replaceDeprecated(n.info, ident, alt)
+      return result
+else:
+  template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard
+
+proc lookUp*(c: PContext, n: PNode): PSym =
+  # Looks up a symbol. Generates an error in case of nil.
+  case n.kind
+  of nkIdent:
+    result = searchInScopes(c, n.ident).skipAlias(n)
+    if result == nil:
+      fixSpelling(n, n.ident, searchInScopes)
+      localError(n.info, errUndeclaredIdentifier, n.ident.s)
+      result = errorSym(c, n)
+  of nkSym:
+    result = n.sym
+  of nkAccQuoted:
+    var ident = considerQuotedIdent(n)
+    result = searchInScopes(c, ident).skipAlias(n)
+    if result == nil:
+      fixSpelling(n, ident, searchInScopes)
+      localError(n.info, errUndeclaredIdentifier, ident.s)
+      result = errorSym(c, n)
+  else:
+    internalError(n.info, "lookUp")
+    return
+  if contains(c.ambiguousSymbols, result.id):
+    localError(n.info, errUseQualifier, result.name.s)
+  if result.kind == skStub: loadStub(result)
+
+type
+  TLookupFlag* = enum
+    checkAmbiguity, checkUndeclared
+
+proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
+  case n.kind
+  of nkIdent, nkAccQuoted:
+    var ident = considerQuotedIdent(n)
+    result = searchInScopes(c, ident).skipAlias(n)
+    if result == nil and checkUndeclared in flags:
+      fixSpelling(n, ident, searchInScopes)
+      localError(n.info, errUndeclaredIdentifier, ident.s)
+      result = errorSym(c, n)
+    elif checkAmbiguity in flags and result != nil and
+        contains(c.ambiguousSymbols, result.id):
+      localError(n.info, errUseQualifier, ident.s)
+  of nkSym:
+    result = n.sym
+    if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id):
+      localError(n.info, errUseQualifier, n.sym.name.s)
+  of nkDotExpr:
+    result = nil
+    var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
+    if m != nil and m.kind == skModule:
+      var ident: PIdent = nil
+      if n.sons[1].kind == nkIdent:
+        ident = n.sons[1].ident
+      elif n.sons[1].kind == nkAccQuoted:
+        ident = considerQuotedIdent(n.sons[1])
+      if ident != nil:
+        if m == c.module:
+          result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n)
+        else:
+          result = strTableGet(m.tab, ident).skipAlias(n)
+        if result == nil and checkUndeclared in flags:
+          fixSpelling(n.sons[1], ident, searchInScopes)
+          localError(n.sons[1].info, errUndeclaredIdentifier, ident.s)
+          result = errorSym(c, n.sons[1])
+      elif n.sons[1].kind == nkSym:
+        result = n.sons[1].sym
+      elif checkUndeclared in flags and
+           n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
+        localError(n.sons[1].info, errIdentifierExpected,
+                   renderTree(n.sons[1]))
+        result = errorSym(c, n.sons[1])
+  else:
+    result = nil
+  if result != nil and result.kind == skStub: loadStub(result)
+
+proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
+  case n.kind
+  of nkIdent, nkAccQuoted:
+    var ident = considerQuotedIdent(n)
+    o.scope = c.currentScope
+    o.mode = oimNoQualifier
+    while true:
+      result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n)
+      if result != nil:
+        break
+      else:
+        o.scope = o.scope.parent
+        if o.scope == nil: break
+  of nkSym:
+    result = n.sym
+    o.mode = oimDone
+  of nkDotExpr:
+    o.mode = oimOtherModule
+    o.m = qualifiedLookUp(c, n.sons[0])
+    if o.m != nil and o.m.kind == skModule:
+      var ident: PIdent = nil
+      if n.sons[1].kind == nkIdent:
+        ident = n.sons[1].ident
+      elif n.sons[1].kind == nkAccQuoted:
+        ident = considerQuotedIdent(n.sons[1])
+      if ident != nil:
+        if o.m == c.module:
+          # a module may access its private members:
+          result = initIdentIter(o.it, c.topLevelScope.symbols,
+                                 ident).skipAlias(n)
+          o.mode = oimSelfModule
+        else:
+          result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
+      else:
+        localError(n.sons[1].info, errIdentifierExpected,
+                   renderTree(n.sons[1]))
+        result = errorSym(c, n.sons[1])
+  of nkClosedSymChoice, nkOpenSymChoice:
+    o.mode = oimSymChoice
+    result = n.sons[0].sym
+    o.symChoiceIndex = 1
+    o.inSymChoice = initIntSet()
+    incl(o.inSymChoice, result.id)
+  else: discard
+  if result != nil and result.kind == skStub: loadStub(result)
+
+proc lastOverloadScope*(o: TOverloadIter): int =
+  case o.mode
+  of oimNoQualifier: result = if o.scope.isNil: -1 else: o.scope.depthLevel
+  of oimSelfModule:  result = 1
+  of oimOtherModule: result = 0
+  else: result = -1
+
+proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
+  case o.mode
+  of oimDone:
+    result = nil
+  of oimNoQualifier:
+    if o.scope != nil:
+      result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
+      while result == nil:
+        o.scope = o.scope.parent
+        if o.scope == nil: break
+        result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
+        # BUGFIX: o.it.name <-> n.ident
+    else:
+      result = nil
+  of oimSelfModule:
+    result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
+  of oimOtherModule:
+    result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
+  of oimSymChoice:
+    if o.symChoiceIndex < sonsLen(n):
+      result = n.sons[o.symChoiceIndex].sym
+      incl(o.inSymChoice, result.id)
+      inc o.symChoiceIndex
+    elif n.kind == nkOpenSymChoice:
+      # try 'local' symbols too for Koenig's lookup:
+      o.mode = oimSymChoiceLocalLookup
+      o.scope = c.currentScope
+      result = firstIdentExcluding(o.it, o.scope.symbols,
+                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
+      while result == nil:
+        o.scope = o.scope.parent
+        if o.scope == nil: break
+        result = firstIdentExcluding(o.it, o.scope.symbols,
+                                     n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
+  of oimSymChoiceLocalLookup:
+    result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n)
+    while result == nil:
+      o.scope = o.scope.parent
+      if o.scope == nil: break
+      result = firstIdentExcluding(o.it, o.scope.symbols,
+                                   n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
+
+  if result != nil and result.kind == skStub: loadStub(result)
+
+proc pickSym*(c: PContext, n: PNode; kind: TSymKind;
+              flags: TSymFlags = {}): PSym =
+  var o: TOverloadIter
+  var a = initOverloadIter(o, c, n)
+  while a != nil:
+    if a.kind == kind and flags <= a.flags:
+      return a
+    a = nextOverloadIter(o, c, n)
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
new file mode 100644
index 000000000..b6b01d558
--- /dev/null
+++ b/compiler/lowerings.nim
@@ -0,0 +1,590 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements common simple lowerings.
+
+const
+  genPrefix* = ":tmp"         # prefix for generated names
+
+import ast, astalgo, types, idents, magicsys, msgs, options
+from trees import getMagic
+
+proc newDeref*(n: PNode): PNode {.inline.} =
+  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
+  addSon(result, n)
+
+proc newTupleAccess*(tup: PNode, i: int): PNode =
+  result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
+                     abstractInst).sons[i])
+  addSon(result, copyTree(tup))
+  var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
+  lit.intVal = i
+  addSon(result, lit)
+
+proc addVar*(father, v: PNode) =
+  var vpart = newNodeI(nkIdentDefs, v.info, 3)
+  vpart.sons[0] = v
+  vpart.sons[1] = ast.emptyNode
+  vpart.sons[2] = ast.emptyNode
+  addSon(father, vpart)
+
+proc newAsgnStmt(le, ri: PNode): PNode =
+  result = newNodeI(nkAsgn, le.info, 2)
+  result.sons[0] = le
+  result.sons[1] = ri
+
+proc newFastAsgnStmt(le, ri: PNode): PNode =
+  result = newNodeI(nkFastAsgn, le.info, 2)
+  result.sons[0] = le
+  result.sons[1] = ri
+
+proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
+  assert n.kind == nkVarTuple
+  let value = n.lastSon
+  result = newNodeI(nkStmtList, n.info)
+
+  var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
+  temp.typ = skipTypes(value.typ, abstractInst)
+  incl(temp.flags, sfFromGeneric)
+
+  var v = newNodeI(nkVarSection, value.info)
+  let tempAsNode = newSymNode(temp)
+  v.addVar(tempAsNode)
+  result.add(v)
+
+  result.add newAsgnStmt(tempAsNode, value)
+  for i in 0 .. n.len-3:
+    if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
+    result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
+
+proc createObj*(owner: PSym, info: TLineInfo): PType =
+  result = newType(tyObject, owner)
+  rawAddSon(result, nil)
+  incl result.flags, tfFinal
+  result.n = newNodeI(nkRecList, info)
+
+proc rawAddField*(obj: PType; field: PSym) =
+  assert field.kind == skField
+  field.position = sonsLen(obj.n)
+  addSon(obj.n, newSymNode(field))
+
+proc rawIndirectAccess*(a: PNode; field: PSym; info: TLineInfo): PNode =
+  # returns a[].field as a node
+  assert field.kind == skField
+  var deref = newNodeI(nkHiddenDeref, info)
+  deref.typ = a.typ.skipTypes(abstractInst).sons[0]
+  addSon(deref, a)
+  result = newNodeI(nkDotExpr, info)
+  addSon(result, deref)
+  addSon(result, newSymNode(field))
+  result.typ = field.typ
+
+proc addField*(obj: PType; s: PSym) =
+  # because of 'gensym' support, we have to mangle the name with its ID.
+  # This is hacky but the clean solution is much more complex than it looks.
+  var field = newSym(skField, getIdent(s.name.s & $s.id), s.owner, s.info)
+  let t = skipIntLit(s.typ)
+  field.typ = t
+  assert t.kind != tyStmt
+  field.position = sonsLen(obj.n)
+  addSon(obj.n, newSymNode(field))
+
+proc addUniqueField*(obj: PType; s: PSym) =
+  let fieldName = getIdent(s.name.s & $s.id)
+  if lookupInRecord(obj.n, fieldName) == nil:
+    var field = newSym(skField, fieldName, s.owner, s.info)
+    let t = skipIntLit(s.typ)
+    field.typ = t
+    assert t.kind != tyStmt
+    field.position = sonsLen(obj.n)
+    addSon(obj.n, newSymNode(field))
+
+proc newDotExpr(obj, b: PSym): PNode =
+  result = newNodeI(nkDotExpr, obj.info)
+  let field = getSymFromList(obj.typ.n, getIdent(b.name.s & $b.id))
+  assert field != nil, b.name.s
+  addSon(result, newSymNode(obj))
+  addSon(result, newSymNode(field))
+  result.typ = field.typ
+
+proc indirectAccess*(a: PNode, b: string, info: TLineInfo): PNode =
+  # returns a[].b as a node
+  var deref = newNodeI(nkHiddenDeref, info)
+  deref.typ = a.typ.skipTypes(abstractInst).sons[0]
+  var t = deref.typ.skipTypes(abstractInst)
+  var field: PSym
+  while true:
+    assert t.kind == tyObject
+    field = getSymFromList(t.n, getIdent(b))
+    if field != nil: break
+    t = t.sons[0]
+    if t == nil: break
+    t = t.skipTypes(abstractInst)
+  #if field == nil:
+  #  echo "FIELD ", b
+  #  debug deref.typ
+  internalAssert field != nil
+  addSon(deref, a)
+  result = newNodeI(nkDotExpr, info)
+  addSon(result, deref)
+  addSon(result, newSymNode(field))
+  result.typ = field.typ
+
+proc getFieldFromObj*(t: PType; v: PSym): PSym =
+  assert v.kind != skField
+  let fieldName = getIdent(v.name.s & $v.id)
+  var t = t
+  while true:
+    assert t.kind == tyObject
+    result = getSymFromList(t.n, fieldName)
+    if result != nil: break
+    t = t.sons[0]
+    if t == nil: break
+    t = t.skipTypes(abstractInst)
+
+proc indirectAccess*(a: PNode, b: PSym, info: TLineInfo): PNode =
+  # returns a[].b as a node
+  result = indirectAccess(a, b.name.s & $b.id, info)
+
+proc indirectAccess*(a, b: PSym, info: TLineInfo): PNode =
+  result = indirectAccess(newSymNode(a), b, info)
+
+proc genAddrOf*(n: PNode): PNode =
+  result = newNodeI(nkAddr, n.info, 1)
+  result.sons[0] = n
+  result.typ = newType(tyPtr, n.typ.owner)
+  result.typ.rawAddSon(n.typ)
+
+proc genDeref*(n: PNode): PNode =
+  result = newNodeIT(nkHiddenDeref, n.info,
+                     n.typ.skipTypes(abstractInst).sons[0])
+  result.add n
+
+proc callCodegenProc*(name: string, arg1: PNode;
+                      arg2, arg3: PNode = nil): PNode =
+  result = newNodeI(nkCall, arg1.info)
+  let sym = magicsys.getCompilerProc(name)
+  if sym == nil:
+    localError(arg1.info, errSystemNeeds, name)
+  else:
+    result.add newSymNode(sym)
+    result.add arg1
+    if arg2 != nil: result.add arg2
+    if arg3 != nil: result.add arg3
+    result.typ = sym.typ.sons[0]
+
+proc callProc(a: PNode): PNode =
+  result = newNodeI(nkCall, a.info)
+  result.add a
+  result.typ = a.typ.sons[0]
+
+# we have 4 cases to consider:
+# - a void proc --> nothing to do
+# - a proc returning GC'ed memory --> requires a flowVar
+# - a proc returning non GC'ed memory --> pass as hidden 'var' parameter
+# - not in a parallel environment --> requires a flowVar for memory safety
+type
+  TSpawnResult* = enum
+    srVoid, srFlowVar, srByVar
+  TFlowVarKind = enum
+    fvInvalid # invalid type T for 'FlowVar[T]'
+    fvGC      # FlowVar of a GC'ed type
+    fvBlob    # FlowVar of a blob type
+
+proc spawnResult*(t: PType; inParallel: bool): TSpawnResult =
+  if t.isEmptyType: srVoid
+  elif inParallel and not containsGarbageCollectedRef(t): srByVar
+  else: srFlowVar
+
+proc flowVarKind(t: PType): TFlowVarKind =
+  if t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC
+  elif containsGarbageCollectedRef(t): fvInvalid
+  else: fvBlob
+
+proc typeNeedsNoDeepCopy(t: PType): bool =
+  var t = t.skipTypes(abstractInst)
+  # for the tconvexhull example (and others) we're a bit lax here and pretend
+  # seqs and strings are *by value* only and 'shallow' doesn't exist!
+  if t.kind == tyString: return true
+  # note that seq[T] is fine, but 'var seq[T]' is not, so we need to skip 'var'
+  # for the stricter check and likewise we can skip 'seq' for a less
+  # strict check:
+  if t.kind in {tyVar, tySequence}: t = t.sons[0]
+  result = not containsGarbageCollectedRef(t)
+
+proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
+                 v: PNode; useShallowCopy=false): PSym =
+  result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
+  result.typ = typ
+  incl(result.flags, sfFromGeneric)
+
+  var vpart = newNodeI(nkIdentDefs, varSection.info, 3)
+  vpart.sons[0] = newSymNode(result)
+  vpart.sons[1] = ast.emptyNode
+  vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
+  varSection.add vpart
+  if varInit != nil:
+    if useShallowCopy and typeNeedsNoDeepCopy(typ):
+      varInit.add newFastAsgnStmt(newSymNode(result), v)
+    else:
+      let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
+      deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
+      deepCopyCall.sons[1] = newSymNode(result)
+      deepCopyCall.sons[2] = v
+      varInit.add deepCopyCall
+
+discard """
+We generate roughly this:
+
+proc f_wrapper(thread, args) =
+  barrierEnter(args.barrier)  # for parallel statement
+  var a = args.a # thread transfer; deepCopy or shallowCopy or no copy
+                 # depending on whether we're in a 'parallel' statement
+  var b = args.b
+  var fv = args.fv
+
+  fv.owner = thread # optional
+  nimArgsPassingDone() # signal parent that the work is done
+  #
+  args.fv.blob = f(a, b, ...)
+  nimFlowVarSignal(args.fv)
+
+  # - or -
+  f(a, b, ...)
+  barrierLeave(args.barrier)  # for parallel statement
+
+stmtList:
+  var scratchObj
+  scratchObj.a = a
+  scratchObj.b = b
+
+  nimSpawn(f_wrapper, addr scratchObj)
+  scratchObj.fv # optional
+
+"""
+
+proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
+                       varSection, varInit, call, barrier, fv: PNode;
+                       spawnKind: TSpawnResult): PSym =
+  var body = newNodeI(nkStmtList, f.info)
+  var threadLocalBarrier: PSym
+  if barrier != nil:
+    var varSection2 = newNodeI(nkVarSection, barrier.info)
+    threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
+                                     barrier.typ, barrier)
+    body.add varSection2
+    body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
+  var threadLocalProm: PSym
+  if spawnKind == srByVar:
+    threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
+  elif fv != nil:
+    internalAssert fv.typ.kind == tyGenericInst
+    threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
+  body.add varSection
+  body.add varInit
+  if fv != nil and spawnKind != srByVar:
+    # generate:
+    #   fv.owner = threadParam
+    body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
+      "owner", fv.info), threadParam.newSymNode)
+
+  body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode)
+  if spawnKind == srByVar:
+    body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
+  elif fv != nil:
+    let fk = fv.typ.sons[1].flowVarKind
+    if fk == fvInvalid:
+      localError(f.info, "cannot create a flowVar of type: " &
+        typeToString(fv.typ.sons[1]))
+    body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
+      if fk == fvGC: "data" else: "blob", fv.info), call)
+    if fk == fvGC:
+      let incRefCall = newNodeI(nkCall, fv.info, 2)
+      incRefCall.sons[0] = newSymNode(createMagic("GCref", mGCref))
+      incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
+                                          "data", fv.info)
+      body.add incRefCall
+    if barrier == nil:
+      # by now 'fv' is shared and thus might have beeen overwritten! we need
+      # to use the thread-local view instead:
+      body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
+  else:
+    body.add call
+  if barrier != nil:
+    body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode)
+
+  var params = newNodeI(nkFormalParams, f.info)
+  params.add emptyNode
+  params.add threadParam.newSymNode
+  params.add argsParam.newSymNode
+
+  var t = newType(tyProc, threadParam.owner)
+  t.rawAddSon nil
+  t.rawAddSon threadParam.typ
+  t.rawAddSon argsParam.typ
+  t.n = newNodeI(nkFormalParams, f.info)
+  t.n.add newNodeI(nkEffectList, f.info)
+  t.n.add threadParam.newSymNode
+  t.n.add argsParam.newSymNode
+
+  let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
+  result = newSym(skProc, getIdent(name), argsParam.owner, f.info)
+  result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
+  result.typ = t
+
+proc createCastExpr(argsParam: PSym; objType: PType): PNode =
+  result = newNodeI(nkCast, argsParam.info)
+  result.add emptyNode
+  result.add newSymNode(argsParam)
+  result.typ = newType(tyPtr, objType.owner)
+  result.typ.rawAddSon(objType)
+
+proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
+                             castExpr, call,
+                             varSection, varInit, result: PNode) =
+  let formals = n[0].typ.n
+  let tmpName = getIdent(genPrefix)
+  for i in 1 .. <n.len:
+    # we pick n's type here, which hopefully is 'tyArray' and not
+    # 'tyOpenArray':
+    var argType = n[i].typ.skipTypes(abstractInst)
+    if i < formals.len and formals[i].typ.kind == tyVar:
+      localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
+    #elif containsTyRef(argType):
+    #  localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
+
+    let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
+    var field = newSym(skField, fieldname, objType.owner, n.info)
+    field.typ = argType
+    objType.addField(field)
+    result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
+
+    let temp = addLocalVar(varSection, varInit, objType.owner, argType,
+                           indirectAccess(castExpr, field, n.info))
+    call.add(newSymNode(temp))
+
+proc getRoot*(n: PNode): PSym =
+  ## ``getRoot`` takes a *path* ``n``. A path is an lvalue expression
+  ## like ``obj.x[i].y``. The *root* of a path is the symbol that can be
+  ## determined as the owner; ``obj`` in the example.
+  case n.kind
+  of nkSym:
+    if n.sym.kind in {skVar, skResult, skTemp, skLet, skForVar}:
+      result = n.sym
+  of nkDotExpr, nkBracketExpr, nkHiddenDeref, nkDerefExpr,
+      nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
+    result = getRoot(n.sons[0])
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    result = getRoot(n.sons[1])
+  of nkCallKinds:
+    if getMagic(n) == mSlice: result = getRoot(n.sons[1])
+  else: discard
+
+proc newIntLit*(value: BiggestInt): PNode =
+  result = nkIntLit.newIntNode(value)
+  result.typ = getSysType(tyInt)
+
+proc genHigh*(n: PNode): PNode =
+  if skipTypes(n.typ, abstractVar).kind in {tyArrayConstr, tyArray}:
+    result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
+  else:
+    result = newNodeI(nkCall, n.info, 2)
+    result.typ = getSysType(tyInt)
+    result.sons[0] = newSymNode(createMagic("high", mHigh))
+    result.sons[1] = n
+
+proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
+                             castExpr, call,
+                             varSection, varInit, result: PNode) =
+  let formals = n[0].typ.n
+  let tmpName = getIdent(genPrefix)
+  # we need to copy the foreign scratch object fields into local variables
+  # for correctness: These are called 'threadLocal' here.
+  for i in 1 .. <n.len:
+    let n = n[i]
+    let argType = skipTypes(if i < formals.len: formals[i].typ else: n.typ,
+                            abstractInst)
+    #if containsTyRef(argType):
+    #  localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
+
+    let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
+    var field = newSym(skField, fieldname, objType.owner, n.info)
+
+    if argType.kind in {tyVarargs, tyOpenArray}:
+      # important special case: we always create a zero-copy slice:
+      let slice = newNodeI(nkCall, n.info, 4)
+      slice.typ = n.typ
+      slice.sons[0] = newSymNode(createMagic("slice", mSlice))
+      var fieldB = newSym(skField, tmpName, objType.owner, n.info)
+      fieldB.typ = getSysType(tyInt)
+      objType.addField(fieldB)
+
+      if getMagic(n) == mSlice:
+        let a = genAddrOf(n[1])
+        field.typ = a.typ
+        objType.addField(field)
+        result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
+
+        var fieldA = newSym(skField, tmpName, objType.owner, n.info)
+        fieldA.typ = getSysType(tyInt)
+        objType.addField(fieldA)
+        result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
+        result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
+
+        let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
+                                      indirectAccess(castExpr, fieldA, n.info),
+                                      useShallowCopy=true)
+        slice.sons[2] = threadLocal.newSymNode
+      else:
+        let a = genAddrOf(n)
+        field.typ = a.typ
+        objType.addField(field)
+        result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
+        result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(n))
+
+        slice.sons[2] = newIntLit(0)
+      # the array itself does not need to go through a thread local variable:
+      slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
+
+      let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
+                                    indirectAccess(castExpr, fieldB, n.info),
+                                    useShallowCopy=true)
+      slice.sons[3] = threadLocal.newSymNode
+      call.add slice
+    elif (let size = computeSize(argType); size < 0 or size > 16) and
+        n.getRoot != nil:
+      # it is more efficient to pass a pointer instead:
+      let a = genAddrOf(n)
+      field.typ = a.typ
+      objType.addField(field)
+      result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
+      let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
+                                    indirectAccess(castExpr, field, n.info),
+                                    useShallowCopy=true)
+      call.add(genDeref(threadLocal.newSymNode))
+    else:
+      # boring case
+      field.typ = argType
+      objType.addField(field)
+      result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
+      let threadLocal = addLocalVar(varSection, varInit,
+                                    objType.owner, field.typ,
+                                    indirectAccess(castExpr, field, n.info),
+                                    useShallowCopy=true)
+      call.add(threadLocal.newSymNode)
+
+proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
+                       barrier, dest: PNode = nil): PNode =
+  # if 'barrier' != nil, then it is in a 'parallel' section and we
+  # generate quite different code
+  let n = spawnExpr[1]
+  let spawnKind = spawnResult(retType, barrier!=nil)
+  case spawnKind
+  of srVoid:
+    internalAssert dest == nil
+    result = newNodeI(nkStmtList, n.info)
+  of srFlowVar:
+    internalAssert dest == nil
+    result = newNodeIT(nkStmtListExpr, n.info, retType)
+  of srByVar:
+    if dest == nil: localError(n.info, "'spawn' must not be discarded")
+    result = newNodeI(nkStmtList, n.info)
+
+  if n.kind notin nkCallKinds:
+    localError(n.info, "'spawn' takes a call expression")
+    return
+  if optThreadAnalysis in gGlobalOptions:
+    if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
+      localError(n.info, "'spawn' takes a GC safe call expression")
+  var
+    threadParam = newSym(skParam, getIdent"thread", owner, n.info)
+    argsParam = newSym(skParam, getIdent"args", owner, n.info)
+  block:
+    let ptrType = getSysType(tyPointer)
+    threadParam.typ = ptrType
+    argsParam.typ = ptrType
+    argsParam.position = 1
+
+  var objType = createObj(owner, n.info)
+  incl(objType.flags, tfFinal)
+  let castExpr = createCastExpr(argsParam, objType)
+
+  var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
+  block:
+    scratchObj.typ = objType
+    incl(scratchObj.flags, sfFromGeneric)
+    var varSectionB = newNodeI(nkVarSection, n.info)
+    varSectionB.addVar(scratchObj.newSymNode)
+    result.add varSectionB
+
+  var call = newNodeIT(nkCall, n.info, n.typ)
+  var fn = n.sons[0]
+  # templates and macros are in fact valid here due to the nature of
+  # the transformation:
+  if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
+                                               skMethod, skConverter}):
+    # for indirect calls we pass the function pointer in the scratchObj
+    var argType = n[0].typ.skipTypes(abstractInst)
+    var field = newSym(skField, getIdent"fn", owner, n.info)
+    field.typ = argType
+    objType.addField(field)
+    result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
+    fn = indirectAccess(castExpr, field, n.info)
+  elif fn.kind == nkSym and fn.sym.kind in {skClosureIterator, skIterator}:
+    localError(n.info, "iterator in spawn environment is not allowed")
+  elif fn.typ.callConv == ccClosure:
+    localError(n.info, "closure in spawn environment is not allowed")
+
+  call.add(fn)
+  var varSection = newNodeI(nkVarSection, n.info)
+  var varInit = newNodeI(nkStmtList, n.info)
+  if barrier.isNil:
+    setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
+                            varSection, varInit, result)
+  else:
+    setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
+                            varSection, varInit, result)
+
+  var barrierAsExpr: PNode = nil
+  if barrier != nil:
+    let typ = newType(tyPtr, owner)
+    typ.rawAddSon(magicsys.getCompilerProc("Barrier").typ)
+    var field = newSym(skField, getIdent"barrier", owner, n.info)
+    field.typ = typ
+    objType.addField(field)
+    result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
+    barrierAsExpr = indirectAccess(castExpr, field, n.info)
+
+  var fvField, fvAsExpr: PNode = nil
+  if spawnKind == srFlowVar:
+    var field = newSym(skField, getIdent"fv", owner, n.info)
+    field.typ = retType
+    objType.addField(field)
+    fvField = newDotExpr(scratchObj, field)
+    fvAsExpr = indirectAccess(castExpr, field, n.info)
+    # create flowVar:
+    result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2]))
+    if barrier == nil:
+      result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
+
+  elif spawnKind == srByVar:
+    var field = newSym(skField, getIdent"fv", owner, n.info)
+    field.typ = newType(tyPtr, objType.owner)
+    field.typ.rawAddSon(retType)
+    objType.addField(field)
+    fvAsExpr = indirectAccess(castExpr, field, n.info)
+    result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
+
+  let wrapper = createWrapperProc(fn, threadParam, argsParam,
+                                  varSection, varInit, call,
+                                  barrierAsExpr, fvAsExpr, spawnKind)
+  result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
+                             genAddrOf(scratchObj.newSymNode))
+
+  if spawnKind == srFlowVar: result.add fvField
diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim
new file mode 100644
index 000000000..6d4c65268
--- /dev/null
+++ b/compiler/magicsys.nim
@@ -0,0 +1,181 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Built-in types and compilerprocs are registered here.
+
+import 
+  ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
+
+var systemModule*: PSym
+
+proc registerSysType*(t: PType)
+  # magic symbols in the system module:
+proc getSysType*(kind: TTypeKind): PType
+proc getCompilerProc*(name: string): PSym
+proc registerCompilerProc*(s: PSym)
+proc finishSystem*(tab: TStrTable)
+proc getSysSym*(name: string): PSym
+# implementation
+
+var
+  gSysTypes: array[TTypeKind, PType]
+  compilerprocs: TStrTable
+
+proc nilOrSysInt*: PType = gSysTypes[tyInt]
+
+proc registerSysType(t: PType) = 
+  if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
+  
+proc newSysType(kind: TTypeKind, size: int): PType = 
+  result = newType(kind, systemModule)
+  result.size = size
+  result.align = size.int16
+
+proc getSysSym(name: string): PSym = 
+  result = strTableGet(systemModule.tab, getIdent(name))
+  if result == nil: 
+    rawMessage(errSystemNeeds, name)
+    result = newSym(skError, getIdent(name), systemModule, systemModule.info)
+    result.typ = newType(tyError, systemModule)
+  if result.kind == skStub: loadStub(result)
+  if result.kind == skAlias: result = result.owner
+  
+proc getSysMagic*(name: string, m: TMagic): PSym =
+  var ti: TIdentIter
+  let id = getIdent(name)
+  result = initIdentIter(ti, systemModule.tab, id)
+  while result != nil:
+    if result.kind == skStub: loadStub(result)
+    if result.magic == m: return result
+    result = nextIdentIter(ti, systemModule.tab)
+  rawMessage(errSystemNeeds, name)
+  result = newSym(skError, id, systemModule, systemModule.info)
+  result.typ = newType(tyError, systemModule)
+  
+proc sysTypeFromName*(name: string): PType = 
+  result = getSysSym(name).typ
+
+proc getSysType(kind: TTypeKind): PType = 
+  result = gSysTypes[kind]
+  if result == nil: 
+    case kind
+    of tyInt: result = sysTypeFromName("int")
+    of tyInt8: result = sysTypeFromName("int8")
+    of tyInt16: result = sysTypeFromName("int16")
+    of tyInt32: result = sysTypeFromName("int32")
+    of tyInt64: result = sysTypeFromName("int64")
+    of tyUInt: result = sysTypeFromName("uint")
+    of tyUInt8: result = sysTypeFromName("uint8")
+    of tyUInt16: result = sysTypeFromName("uint16")
+    of tyUInt32: result = sysTypeFromName("uint32")
+    of tyUInt64: result = sysTypeFromName("uint64")
+    of tyFloat: result = sysTypeFromName("float")
+    of tyFloat32: result = sysTypeFromName("float32")
+    of tyFloat64: return sysTypeFromName("float64")
+    of tyFloat128: result = sysTypeFromName("float128")
+    of tyBool: result = sysTypeFromName("bool")
+    of tyChar: result = sysTypeFromName("char")
+    of tyString: result = sysTypeFromName("string")
+    of tyCString: result = sysTypeFromName("cstring")
+    of tyPointer: result = sysTypeFromName("pointer")
+    of tyNil: result = newSysType(tyNil, ptrSize)
+    else: internalError("request for typekind: " & $kind)
+    gSysTypes[kind] = result
+  if result.kind != kind: 
+    internalError("wanted: " & $kind & " got: " & $result.kind)
+  if result == nil: internalError("type not found: " & $kind)
+
+var
+  intTypeCache: array[-5..64, PType]
+
+proc resetSysTypes* =
+  systemModule = nil
+  initStrTable(compilerprocs)
+  for i in low(gSysTypes)..high(gSysTypes):
+    gSysTypes[i] = nil
+
+  for i in low(intTypeCache)..high(intTypeCache):
+    intTypeCache[i] = nil
+
+proc getIntLitType*(literal: PNode): PType =
+  # we cache some common integer literal types for performance:
+  let value = literal.intVal
+  if value >= low(intTypeCache) and value <= high(intTypeCache):
+    result = intTypeCache[value.int]
+    if result == nil:
+      let ti = getSysType(tyInt)
+      result = copyType(ti, ti.owner, false)
+      result.n = literal
+      intTypeCache[value.int] = result
+  else:
+    let ti = getSysType(tyInt)
+    result = copyType(ti, ti.owner, false)
+    result.n = literal
+
+proc getFloatLitType*(literal: PNode): PType =
+  # for now we do not cache these:
+  result = newSysType(tyFloat, size=8)
+  result.n = literal
+
+proc skipIntLit*(t: PType): PType {.inline.} =
+  if t.n != nil:
+    if t.kind in {tyInt, tyFloat}:
+      return getSysType(t.kind)
+  result = t
+
+proc addSonSkipIntLit*(father, son: PType) =
+  if isNil(father.sons): father.sons = @[]
+  let s = son.skipIntLit
+  add(father.sons, s)
+  propagateToOwner(father, s)
+
+proc setIntLitType*(result: PNode) =
+  let i = result.intVal
+  case platform.intSize
+  of 8: result.typ = getIntLitType(result)
+  of 4:
+    if i >= low(int32) and i <= high(int32):
+      result.typ = getIntLitType(result)
+    else:
+      result.typ = getSysType(tyInt64)
+  of 2:
+    if i >= low(int16) and i <= high(int16):
+      result.typ = getIntLitType(result)
+    elif i >= low(int32) and i <= high(int32):
+      result.typ = getSysType(tyInt32)
+    else:
+      result.typ = getSysType(tyInt64)
+  of 1:
+    # 8 bit CPUs are insane ...
+    if i >= low(int8) and i <= high(int8):
+      result.typ = getIntLitType(result)
+    elif i >= low(int16) and i <= high(int16):
+      result.typ = getSysType(tyInt16)
+    elif i >= low(int32) and i <= high(int32):
+      result.typ = getSysType(tyInt32)
+    else:
+      result.typ = getSysType(tyInt64)
+  else: internalError(result.info, "invalid int size")
+
+proc getCompilerProc(name: string): PSym = 
+  var ident = getIdent(name, hashIgnoreStyle(name))
+  result = strTableGet(compilerprocs, ident)
+  if result == nil:
+    result = strTableGet(rodCompilerprocs, ident)
+    if result != nil:
+      strTableAdd(compilerprocs, result)
+      if result.kind == skStub: loadStub(result)
+      if result.kind == skAlias: result = result.owner
+
+proc registerCompilerProc(s: PSym) =
+  strTableAdd(compilerprocs, s)
+
+proc finishSystem(tab: TStrTable) = discard
+
+initStrTable(compilerprocs)
diff --git a/compiler/main.nim b/compiler/main.nim
new file mode 100644
index 000000000..a01b6fe4f
--- /dev/null
+++ b/compiler/main.nim
@@ -0,0 +1,381 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# implements the command dispatcher and several commands
+
+import
+  llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
+  os, condsyms, rodread, rodwrite, times,
+  wordrecg, sem, semdata, idents, passes, docgen, extccomp,
+  cgen, jsgen, json, nversion,
+  platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
+  tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
+
+from magicsys import systemModule, resetSysTypes
+
+proc rodPass =
+  if optSymbolFiles in gGlobalOptions:
+    registerPass(rodwritePass)
+
+proc codegenPass =
+  registerPass cgenPass
+
+proc semanticPasses =
+  registerPass verbosePass
+  registerPass semPass
+
+proc commandGenDepend =
+  semanticPasses()
+  registerPass(gendependPass)
+  registerPass(cleanupPass)
+  compileProject()
+  generateDot(gProjectFull)
+  execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
+      ' ' & changeFileExt(gProjectFull, "dot"))
+
+proc commandCheck =
+  msgs.gErrorMax = high(int)  # do not stop after first error
+  semanticPasses()            # use an empty backend for semantic checking only
+  rodPass()
+  compileProject()
+
+proc commandDoc2 =
+  msgs.gErrorMax = high(int)  # do not stop after first error
+  semanticPasses()
+  registerPass(docgen2Pass)
+  #registerPass(cleanupPass())
+  compileProject()
+  finishDoc2Pass(gProjectName)
+
+proc commandCompileToC =
+  extccomp.initVars()
+  semanticPasses()
+  registerPass(cgenPass)
+  rodPass()
+  #registerPass(cleanupPass())
+
+  compileProject()
+  cgenWriteModules()
+  if gCmd != cmdRun:
+    extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
+
+  if isServing:
+    # caas will keep track only of the compilation commands
+    lastCaasCmd = curCaasCmd
+    resetCgenModules()
+    for i in 0 .. <gMemCacheData.len:
+      gMemCacheData[i].crcStatus = crcCached
+      gMemCacheData[i].needsRecompile = Maybe
+
+      # XXX: clean these global vars
+      # ccgstmts.gBreakpoints
+      # ccgthreadvars.nimtv
+      # ccgthreadvars.nimtVDeps
+      # ccgthreadvars.nimtvDeclared
+      # cgendata
+      # cgmeth?
+      # condsyms?
+      # depends?
+      # lexer.gLinesCompiled
+      # msgs - error counts
+      # magicsys, when system.nim changes
+      # rodread.rodcompilerProcs
+      # rodread.gTypeTable
+      # rodread.gMods
+
+      # !! ropes.cache
+      # semthreads.computed?
+      #
+      # suggest.usageSym
+      #
+      # XXX: can we run out of IDs?
+      # XXX: detect config reloading (implement as error/require restart)
+      # XXX: options are appended (they will accumulate over time)
+    resetCompilationLists()
+    ccgutils.resetCaches()
+    GC_fullCollect()
+
+proc commandCompileToJS =
+  #incl(gGlobalOptions, optSafeCode)
+  setTarget(osJS, cpuJS)
+  #initDefines()
+  defineSymbol("nimrod") # 'nimrod' is always defined
+  defineSymbol("ecmascript") # For backward compatibility
+  defineSymbol("js")
+  semanticPasses()
+  registerPass(JSgenPass)
+  compileProject()
+
+proc interactivePasses =
+  #incl(gGlobalOptions, optSafeCode)
+  #setTarget(osNimrodVM, cpuNimrodVM)
+  initDefines()
+  defineSymbol("nimrodvm")
+  when hasFFI: defineSymbol("nimffi")
+  registerPass(verbosePass)
+  registerPass(semPass)
+  registerPass(evalPass)
+
+proc commandInteractive =
+  msgs.gErrorMax = high(int)  # do not stop after first error
+  interactivePasses()
+  compileSystemModule()
+  if commandArgs.len > 0:
+    discard compileModule(fileInfoIdx(gProjectFull), {})
+  else:
+    var m = makeStdinModule()
+    incl(m.flags, sfMainModule)
+    processModule(m, llStreamOpenStdIn(), nil)
+
+const evalPasses = [verbosePass, semPass, evalPass]
+
+proc evalNim(nodes: PNode, module: PSym) =
+  carryPasses(nodes, module, evalPasses)
+
+proc commandEval(exp: string) =
+  if systemModule == nil:
+    interactivePasses()
+    compileSystemModule()
+  var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
+  evalNim(echoExp.parseString, makeStdinModule())
+
+proc commandScan =
+  var f = addFileExt(mainCommandArg(), NimExt)
+  var stream = llStreamOpen(f, fmRead)
+  if stream != nil:
+    var
+      L: TLexer
+      tok: TToken
+    initToken(tok)
+    openLexer(L, f, stream)
+    while true:
+      rawGetTok(L, tok)
+      printTok(tok)
+      if tok.tokType == tkEof: break
+    closeLexer(L)
+  else:
+    rawMessage(errCannotOpenFile, f)
+
+proc commandSuggest =
+  if isServing:
+    # XXX: hacky work-around ahead
+    # Currently, it's possible to issue a idetools command, before
+    # issuing the first compile command. This will leave the compiler
+    # cache in a state where "no recompilation is necessary", but the
+    # cgen pass was never executed at all.
+    commandCompileToC()
+    let gDirtyBufferIdx = gTrackPos.fileIndex
+    discard compileModule(gDirtyBufferIdx, {sfDirty})
+    resetModule(gDirtyBufferIdx)
+  else:
+    msgs.gErrorMax = high(int)  # do not stop after first error
+    semanticPasses()
+    rodPass()
+    # XXX: this handles the case when the dirty buffer is the main file,
+    # but doesn't handle the case when it's imported module
+    #var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
+    #               else: gProjectMainIdx
+    compileProject() #(projFile)
+
+proc resetMemory =
+  resetCompilationLists()
+  ccgutils.resetCaches()
+  resetAllModules()
+  resetRopeCache()
+  resetSysTypes()
+  gOwners = @[]
+  rangeDestructorProc = nil
+  for i in low(buckets)..high(buckets):
+    buckets[i] = nil
+  idAnon = nil
+
+  # XXX: clean these global vars
+  # ccgstmts.gBreakpoints
+  # ccgthreadvars.nimtv
+  # ccgthreadvars.nimtVDeps
+  # ccgthreadvars.nimtvDeclared
+  # cgendata
+  # cgmeth?
+  # condsyms?
+  # depends?
+  # lexer.gLinesCompiled
+  # msgs - error counts
+  # magicsys, when system.nim changes
+  # rodread.rodcompilerProcs
+  # rodread.gTypeTable
+  # rodread.gMods
+
+  # !! ropes.cache
+  #
+  # suggest.usageSym
+  #
+  # XXX: can we run out of IDs?
+  # XXX: detect config reloading (implement as error/require restart)
+  # XXX: options are appended (they will accumulate over time)
+  # vis = visimpl
+  when compileOption("gc", "v2"):
+    gcDebugging = true
+    echo "COLLECT 1"
+    GC_fullCollect()
+    echo "COLLECT 2"
+    GC_fullCollect()
+    echo "COLLECT 3"
+    GC_fullCollect()
+    echo GC_getStatistics()
+
+const
+  SimulateCaasMemReset = false
+  PrintRopeCacheStats = false
+
+proc mainCommand* =
+  when SimulateCaasMemReset:
+    gGlobalOptions.incl(optCaasEnabled)
+
+  # In "nimrod serve" scenario, each command must reset the registered passes
+  clearPasses()
+  gLastCmdTime = epochTime()
+  appendStr(searchPaths, options.libpath)
+  if gProjectFull.len != 0:
+    # current path is always looked first for modules
+    prependStr(searchPaths, gProjectPath)
+  setId(100)
+  case command.normalize
+  of "c", "cc", "compile", "compiletoc":
+    # compile means compileToC currently
+    gCmd = cmdCompileToC
+    commandCompileToC()
+  of "cpp", "compiletocpp":
+    gCmd = cmdCompileToCpp
+    defineSymbol("cpp")
+    commandCompileToC()
+  of "objc", "compiletooc":
+    gCmd = cmdCompileToOC
+    defineSymbol("objc")
+    commandCompileToC()
+  of "run":
+    gCmd = cmdRun
+    when hasTinyCBackend:
+      extccomp.setCC("tcc")
+      commandCompileToC()
+    else:
+      rawMessage(errInvalidCommandX, command)
+  of "js", "compiletojs":
+    gCmd = cmdCompileToJS
+    commandCompileToJS()
+  of "doc":
+    wantMainModule()
+    gCmd = cmdDoc
+    loadConfigs(DocConfig)
+    commandDoc()
+  of "doc2":
+    gCmd = cmdDoc
+    loadConfigs(DocConfig)
+    defineSymbol("nimdoc")
+    commandDoc2()
+  of "rst2html":
+    gCmd = cmdRst2html
+    loadConfigs(DocConfig)
+    commandRst2Html()
+  of "rst2tex":
+    gCmd = cmdRst2tex
+    loadConfigs(DocTexConfig)
+    commandRst2TeX()
+  of "jsondoc":
+    wantMainModule()
+    gCmd = cmdDoc
+    loadConfigs(DocConfig)
+    wantMainModule()
+    defineSymbol("nimdoc")
+    commandJSON()
+  of "buildindex":
+    gCmd = cmdDoc
+    loadConfigs(DocConfig)
+    commandBuildIndex()
+  of "gendepend":
+    gCmd = cmdGenDepend
+    commandGenDepend()
+  of "dump":
+    gCmd = cmdDump
+    if getConfigVar("dump.format") == "json":
+      wantMainModule()
+
+      var definedSymbols = newJArray()
+      for s in definedSymbolNames(): definedSymbols.elems.add(%s)
+
+      var libpaths = newJArray()
+      for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir)
+
+      var dumpdata = % [
+        (key: "version", val: %VersionAsString),
+        (key: "project_path", val: %gProjectFull),
+        (key: "defined_symbols", val: definedSymbols),
+        (key: "lib_paths", val: libpaths)
+      ]
+
+      outWriteln($dumpdata)
+    else:
+      outWriteln("-- list of currently defined symbols --")
+      for s in definedSymbolNames(): outWriteln(s)
+      outWriteln("-- end of list --")
+
+      for it in iterSearchPath(searchPaths): msgWriteln(it)
+  of "check":
+    gCmd = cmdCheck
+    commandCheck()
+  of "parse":
+    gCmd = cmdParse
+    wantMainModule()
+    discard parseFile(gProjectMainIdx)
+  of "scan":
+    gCmd = cmdScan
+    wantMainModule()
+    commandScan()
+    msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
+  of "i":
+    gCmd = cmdInteractive
+    commandInteractive()
+  of "e":
+    # XXX: temporary command for easier testing
+    commandEval(mainCommandArg())
+  of "reset":
+    resetMemory()
+  of "idetools":
+    gCmd = cmdIdeTools
+    if gEvalExpr != "":
+      commandEval(gEvalExpr)
+    else:
+      commandSuggest()
+  of "serve":
+    isServing = true
+    gGlobalOptions.incl(optCaasEnabled)
+    msgs.gErrorMax = high(int)  # do not stop after first error
+    serve(mainCommand)
+  else:
+    rawMessage(errInvalidCommandX, command)
+
+  if (msgs.gErrorCounter == 0 and
+      gCmd notin {cmdInterpret, cmdRun, cmdDump} and
+      gVerbosity > 0):
+    rawMessage(hintSuccessX, [$gLinesCompiled,
+               formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
+               formatSize(getTotalMem()),
+               if condSyms.isDefined("release"): "Release Build"
+               else: "Debug Build"])
+
+  when PrintRopeCacheStats:
+    echo "rope cache stats: "
+    echo "  tries : ", gCacheTries
+    echo "  misses: ", gCacheMisses
+    echo "  int tries: ", gCacheIntTries
+    echo "  efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
+                                       ffDecimal, 3)
+
+  when SimulateCaasMemReset:
+    resetMemory()
+
diff --git a/compiler/modules.nim b/compiler/modules.nim
new file mode 100644
index 000000000..2fa46f356
--- /dev/null
+++ b/compiler/modules.nim
@@ -0,0 +1,213 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## implements the module handling
+
+import
+  ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options,
+  idents, os, lexer, idgen, passes, syntaxes, llstream
+
+type
+  TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
+  TCrcStatus* = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged
+
+  TModuleInMemory* = object
+    compiledAt*: float
+    crc*: TCrc32
+    deps*: seq[int32] ## XXX: slurped files are currently not tracked
+    needsRecompile*: TNeedRecompile
+    crcStatus*: TCrcStatus
+
+var
+  gCompiledModules: seq[PSym] = @[]
+  gMemCacheData*: seq[TModuleInMemory] = @[]
+    ## XXX: we should implement recycling of file IDs
+    ## if the user keeps renaming modules, the file IDs will keep growing
+
+proc getModule(fileIdx: int32): PSym =
+  if fileIdx >= 0 and fileIdx < gCompiledModules.len:
+    result = gCompiledModules[fileIdx]
+
+template crc(x: PSym): expr =
+  gMemCacheData[x.position].crc
+
+proc crcChanged(fileIdx: int32): bool =
+  internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
+
+  template updateStatus =
+    gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged
+                                       else: crcNotChanged
+    # echo "TESTING CRC: ", fileIdx.toFilename, " ", result
+
+  case gMemCacheData[fileIdx].crcStatus:
+  of crcHasChanged:
+    result = true
+  of crcNotChanged:
+    result = false
+  of crcCached:
+    let newCrc = crcFromFile(fileIdx.toFilename)
+    result = newCrc != gMemCacheData[fileIdx].crc
+    gMemCacheData[fileIdx].crc = newCrc
+    updateStatus()
+  of crcNotTaken:
+    gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
+    result = true
+    updateStatus()
+
+proc doCRC(fileIdx: int32) =
+  if gMemCacheData[fileIdx].crcStatus == crcNotTaken:
+    # echo "FIRST CRC: ", fileIdx.ToFilename
+    gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename)
+
+proc addDep(x: PSym, dep: int32) =
+  growCache gMemCacheData, dep
+  gMemCacheData[x.position].deps.safeAdd(dep)
+
+proc resetModule*(fileIdx: int32) =
+  # echo "HARD RESETTING ", fileIdx.toFilename
+  if fileIdx <% gMemCacheData.len:
+    gMemCacheData[fileIdx].needsRecompile = Yes
+  if fileIdx <% gCompiledModules.len:
+    gCompiledModules[fileIdx] = nil
+  if fileIdx <% cgendata.gModules.len:
+    cgendata.gModules[fileIdx] = nil
+
+proc resetAllModules* =
+  for i in 0..gCompiledModules.high:
+    if gCompiledModules[i] != nil:
+      resetModule(i.int32)
+  resetPackageCache()
+  # for m in cgenModules(): echo "CGEN MODULE FOUND"
+
+proc checkDepMem(fileIdx: int32): TNeedRecompile =
+  template markDirty =
+    resetModule(fileIdx)
+    return Yes
+
+  if gMemCacheData[fileIdx].needsRecompile != Maybe:
+    return gMemCacheData[fileIdx].needsRecompile
+
+  if optForceFullMake in gGlobalOptions or
+     crcChanged(fileIdx):
+       markDirty
+
+  if gMemCacheData[fileIdx].deps != nil:
+    gMemCacheData[fileIdx].needsRecompile = Probing
+    for dep in gMemCacheData[fileIdx].deps:
+      let d = checkDepMem(dep)
+      if d in {Yes, Recompiled}:
+        # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
+        markDirty
+
+  gMemCacheData[fileIdx].needsRecompile = No
+  return No
+
+proc newModule(fileIdx: int32): PSym =
+  # We cannot call ``newSym`` here, because we have to circumvent the ID
+  # mechanism, which we do in order to assign each module a persistent ID.
+  new(result)
+  result.id = - 1             # for better error checking
+  result.kind = skModule
+  let filename = fileIdx.toFullPath
+  result.name = getIdent(splitFile(filename).name)
+  if not isNimIdentifier(result.name.s):
+    rawMessage(errInvalidModuleName, result.name.s)
+
+  result.info = newLineInfo(fileIdx, 1, 1)
+  result.owner = newSym(skPackage, getIdent(getPackageName(filename)), nil,
+                        result.info)
+  result.position = fileIdx
+
+  growCache gMemCacheData, fileIdx
+  growCache gCompiledModules, fileIdx
+  gCompiledModules[result.position] = result
+
+  incl(result.flags, sfUsed)
+  initStrTable(result.tab)
+  strTableAdd(result.tab, result) # a module knows itself
+
+proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym =
+  result = getModule(fileIdx)
+  if result == nil:
+    growCache gMemCacheData, fileIdx
+    gMemCacheData[fileIdx].needsRecompile = Probing
+    result = newModule(fileIdx)
+    #var rd = handleSymbolFile(result)
+    var rd: PRodReader
+    result.flags = result.flags + flags
+    if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
+      rd = handleSymbolFile(result)
+      if result.id < 0:
+        internalError("handleSymbolFile should have set the module\'s ID")
+        return
+    else:
+      result.id = getID()
+    if sfMainModule in flags and gProjectIsStdin:
+      processModule(result, llStreamOpen(stdin), rd)
+    else:
+      processModule(result, nil, rd)
+    if optCaasEnabled in gGlobalOptions:
+      gMemCacheData[fileIdx].compiledAt = gLastCmdTime
+      gMemCacheData[fileIdx].needsRecompile = Recompiled
+      doCRC fileIdx
+  else:
+    if checkDepMem(fileIdx) == Yes:
+      result = compileModule(fileIdx, flags)
+    else:
+      result = gCompiledModules[fileIdx]
+
+proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} =
+  # this is called by the semantic checking phase
+  result = compileModule(fileIdx, {})
+  if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
+  if sfSystemModule in result.flags:
+    localError(result.info, errAttemptToRedefine, result.name.s)
+
+proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
+  result = syntaxes.parseFile(fileIdx)
+  if optCaasEnabled in gGlobalOptions:
+    growCache gMemCacheData, fileIdx
+    addDep(s, fileIdx)
+    doCRC(fileIdx)
+
+proc `==^`(a, b: string): bool =
+  try:
+    result = sameFile(a, b)
+  except OSError:
+    result = false
+
+proc compileSystemModule* =
+  if magicsys.systemModule == nil:
+    systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
+    discard compileModule(systemFileIdx, {sfSystemModule})
+
+proc wantMainModule* =
+  if gProjectFull.len == 0:
+    fatal(gCmdLineInfo, errCommandExpectsFilename)
+  gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
+
+passes.gIncludeFile = includeModule
+passes.gImportModule = importModule
+
+proc compileProject*(projectFileIdx = -1'i32) =
+  wantMainModule()
+  let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
+  let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
+  if projectFile == systemFileIdx:
+    discard compileModule(projectFile, {sfMainModule, sfSystemModule})
+  else:
+    compileSystemModule()
+    discard compileModule(projectFile, {sfMainModule})
+
+var stdinModule: PSym
+proc makeStdinModule*(): PSym =
+  if stdinModule == nil:
+    stdinModule = newModule(fileInfoIdx"stdin")
+    stdinModule.id = getID()
+  result = stdinModule
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
new file mode 100644
index 000000000..041a181be
--- /dev/null
+++ b/compiler/msgs.nim
@@ -0,0 +1,884 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  options, strutils, os, tables, ropes, platform
+
+type
+  TMsgKind* = enum
+    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,
+    errXCompilerDoesNotSupportCpp, errStringLiteralExpected,
+    errIntLiteralExpected, errInvalidCharacterConstant,
+    errClosingTripleQuoteExpected, errClosingQuoteExpected,
+    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,
+    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,
+    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,
+    errNewlineExpected,
+    errInvalidModuleName,
+    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,
+    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
+    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
+    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
+    errExceptionExpected, errExceptionAlreadyHandled,
+    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
+    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,
+    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
+    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
+    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
+    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,
+    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
+    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
+    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
+    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,
+    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
+    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
+    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
+    errConstantDivisionByZero, errOrdinalTypeExpected,
+    errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
+    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
+    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
+    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
+    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
+    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
+    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,
+    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
+    errMagicOnlyInSystem, errPowerOfTwoExpected,
+    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
+    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
+    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
+    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
+    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
+    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
+    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
+    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
+    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
+    errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
+    errVarForOutParamNeeded,
+    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
+    errAmbiguousCallXYZ, errWrongNumberOfArguments,
+    errXCannotBePassedToProcVar,
+    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,
+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
+    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
+    errInvalidOrderInArrayConstructor,
+    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
+    errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
+    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
+    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
+    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
+    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
+    errXNotAllowedHere, errInvalidControlFlowX,
+    errXisNoType, errCircumNeedsPointer, errInvalidExpression,
+    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
+    errNamedExprNotAllowed, errXExpectsOneTypeParam,
+    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
+    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
+    errNoReturnTypeDeclared,
+    errInvalidCommandX, errXOnlyAtModuleScope,
+    errXNeedsParamObjectType,
+    errTemplateInstantiationTooNested, errInstantiationFrom,
+    errInvalidIndexValueForTuple, errCommandExpectsFilename,
+    errMainModuleMustBeSpecified,
+    errXExpected,
+    errTIsNotAConcreteType,
+    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
+    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
+    errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
+    errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
+    errMacroBodyDependsOnGenericTypes,
+    errDestructorNotGenericEnough,
+    errInlineIteratorsAsProcParams,
+    errXExpectsTwoArguments,
+    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
+    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
+    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
+    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
+    errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
+    errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
+    errXCannotBeClosure, errXMustBeCompileTime,
+    errCannotInferTypeOfTheLiteral,
+    errCannotInferReturnType,
+    errGenericLambdaNotAllowed,
+    errCompilerDoesntSupportTarget,
+    errUser,
+    warnCannotOpenFile,
+    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
+    warnDeprecated, warnConfigDeprecated,
+    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
+    warnUnknownSubstitutionX, warnLanguageXNotSupported,
+    warnFieldXNotSupported, warnCommentXIgnored,
+    warnNilStatement, warnTypelessParam,
+    warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
+    warnEachIdentIsTuple, warnShadowIdent,
+    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
+    warnUser,
+    hintSuccess, hintSuccessX,
+    hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
+    hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
+    hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
+    hintConditionAlwaysTrue, hintName, hintPattern,
+    hintUser
+
+const
+  MsgKindToStr*: array[TMsgKind, string] = [
+    errUnknown: "unknown error",
+    errIllFormedAstX: "illformed AST: $1",
+    errInternal: "internal error: $1",
+    errCannotOpenFile: "cannot open \'$1\'",
+    errGenerated: "$1",
+    errXCompilerDoesNotSupportCpp: "\'$1\' compiler does not support C++",
+    errStringLiteralExpected: "string literal expected",
+    errIntLiteralExpected: "integer literal expected",
+    errInvalidCharacterConstant: "invalid character constant",
+    errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
+    errClosingQuoteExpected: "closing \" expected",
+    errTabulatorsAreNotAllowed: "tabulators are not allowed",
+    errInvalidToken: "invalid token: $1",
+    errLineTooLong: "line too long",
+    errInvalidNumber: "$1 is not a valid number",
+    errNumberOutOfRange: "number $1 out of valid range",
+    errNnotAllowedInCharacter: "\\n not allowed in character literal",
+    errClosingBracketExpected: "closing ']' expected, but end of file reached",
+    errMissingFinalQuote: "missing final \' for character literal",
+    errIdentifierExpected: "identifier expected, but found \'$1\'",
+    errNewlineExpected: "newline expected, but found \'$1\'",
+    errInvalidModuleName: "invalid module name: '$1'",
+    errOperatorExpected: "operator expected, but found \'$1\'",
+    errTokenExpected: "\'$1\' expected",
+    errStringAfterIncludeExpected: "string after \'include\' expected",
+    errRecursiveDependencyX: "recursive dependency: \'$1\'",
+    errOnOrOffExpected: "\'on\' or \'off\' expected",
+    errNoneSpeedOrSizeExpected: "\'none\', \'speed\' or \'size\' expected",
+    errInvalidPragma: "invalid pragma",
+    errUnknownPragma: "unknown pragma: \'$1\'",
+    errInvalidDirectiveX: "invalid directive: \'$1\'",
+    errAtPopWithoutPush: "\'pop\' without a \'push\' pragma",
+    errEmptyAsm: "empty asm statement",
+    errInvalidIndentation: "invalid indentation",
+    errExceptionExpected: "exception expected",
+    errExceptionAlreadyHandled: "exception already handled",
+    errYieldNotAllowedHere: "'yield' only allowed in an iterator",
+    errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
+    errInvalidNumberOfYieldExpr: "invalid number of \'yield\' expressions",
+    errCannotReturnExpr: "current routine cannot return an expression",
+    errAttemptToRedefine: "redefinition of \'$1\'",
+    errStmtInvalidAfterReturn: "statement not allowed after \'return\', \'break\', \'raise\' or \'continue'",
+    errStmtExpected: "statement expected",
+    errInvalidLabel: "\'$1\' is no label",
+    errInvalidCmdLineOption: "invalid command line option: \'$1\'",
+    errCmdLineArgExpected: "argument for command line option expected: \'$1\'",
+    errCmdLineNoArgExpected: "invalid argument for command line option: \'$1\'",
+    errInvalidVarSubstitution: "invalid variable substitution in \'$1\'",
+    errUnknownVar: "unknown variable: \'$1\'",
+    errUnknownCcompiler: "unknown C compiler: \'$1\'",
+    errOnOrOffExpectedButXFound: "\'on\' or \'off\' expected, but \'$1\' found",
+    errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
+    errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
+    errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
+    errUnknownOS: "unknown OS: '$1'",
+    errUnknownCPU: "unknown CPU: '$1'",
+    errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
+    errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
+    errInvalidMultipleAsgn: "multiple assignment is not allowed",
+    errColonOrEqualsExpected: "\':\' or \'=\' expected, but found \'$1\'",
+    errExprExpected: "expression expected, but found \'$1\'",
+    errUndeclaredIdentifier: "undeclared identifier: \'$1\'",
+    errUseQualifier: "ambiguous identifier: \'$1\' -- use a qualifier",
+    errTypeExpected: "type expected",
+    errSystemNeeds: "system module needs \'$1\'",
+    errExecutionOfProgramFailed: "execution of an external program failed",
+    errNotOverloadable: "overloaded \'$1\' leads to ambiguous calls",
+    errInvalidArgForX: "invalid argument for \'$1\'",
+    errStmtHasNoEffect: "statement has no effect",
+    errXExpectsTypeOrValue: "\'$1\' expects a type or value",
+    errXExpectsArrayType: "\'$1\' expects an array type",
+    errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
+    errExprXAmbiguous: "expression '$1' ambiguous in this context",
+    errConstantDivisionByZero: "division by zero",
+    errOrdinalTypeExpected: "ordinal type expected",
+    errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
+    errOverOrUnderflow: "over- or underflow",
+    errCannotEvalXBecauseIncompletelyDefined: "cannot evalutate '$1' because type is not defined completely",
+    errChrExpectsRange0_255: "\'chr\' expects an int in the range 0..255",
+    errDynlibRequiresExportc: "\'dynlib\' requires \'exportc\'",
+    errUndeclaredFieldX: "undeclared field: \'$1\'",
+    errNilAccess: "attempt to access a nil address",
+    errIndexOutOfBounds: "index out of bounds",
+    errIndexTypesDoNotMatch: "index types do not match",
+    errBracketsInvalidForType: "\'[]\' operator invalid for this type",
+    errValueOutOfSetBounds: "value out of set bounds",
+    errFieldInitTwice: "field initialized twice: \'$1\'",
+    errFieldNotInit: "field \'$1\' not initialized",
+    errExprXCannotBeCalled: "expression \'$1\' cannot be called",
+    errExprHasNoType: "expression has no type",
+    errExprXHasNoType: "expression \'$1\' has no type (or is ambiguous)",
+    errCastNotInSafeMode: "\'cast\' not allowed in safe mode",
+    errExprCannotBeCastedToX: "expression cannot be casted to $1",
+    errCommaOrParRiExpected: "',' or ')' expected",
+    errCurlyLeOrParLeExpected: "\'{\' or \'(\' expected",
+    errSectionExpected: "section (\'type\', \'proc\', etc.) expected",
+    errRangeExpected: "range expected",
+    errMagicOnlyInSystem: "\'magic\' only allowed in system module",
+    errPowerOfTwoExpected: "power of two expected",
+    errStringMayNotBeEmpty: "string literal may not be empty",
+    errCallConvExpected: "calling convention expected",
+    errProcOnlyOneCallConv: "a proc can only have one calling convention",
+    errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
+    errExprMustBeBool: "expression must be of type 'bool'",
+    errConstExprExpected: "constant expression expected",
+    errDuplicateCaseLabel: "duplicate case label",
+    errRangeIsEmpty: "range is empty",
+    errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
+    errSelectorMustBeOrdinal: "selector must be of an ordinal type",
+    errOrdXMustNotBeNegative: "ord($1) must not be negative",
+    errLenXinvalid: "len($1) must be less than 32768",
+    errWrongNumberOfVariables: "wrong number of variables",
+    errExprCannotBeRaised: "only a 'ref object' can be raised",
+    errBreakOnlyInLoop: "'break' only allowed in loop construct",
+    errTypeXhasUnknownSize: "type \'$1\' has unknown size",
+    errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
+    errConstNeedsValue: "a constant needs a value",
+    errResultCannotBeOpenArray: "the result type cannot be on open array",
+    errSizeTooBig: "computing the type\'s size produced an overflow",
+    errSetTooBig: "set is too large",
+    errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
+    errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
+    errInheritanceOnlyWithEnums: "inheritance only works with an enum",
+    errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'",
+    errCannotInstantiateX: "cannot instantiate: \'$1\'",
+    errExprHasNoAddress: "expression has no address",
+    errXStackEscape: "address of '$1' may not escape its stack frame",
+    errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
+    errPureTypeMismatch: "type mismatch",
+    errTypeMismatch: "type mismatch: got (",
+    errButExpected: "but expected one of: ",
+    errButExpectedX: "but expected \'$1\'",
+    errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
+    errWrongNumberOfArguments: "wrong number of arguments",
+    errXCannotBePassedToProcVar: "\'$1\' cannot be passed to a procvar",
+    errXCannotBeInParamDecl: "$1 cannot be declared in parameter declaration",
+    errPragmaOnlyInHeaderOfProc: "pragmas are only allowed in the header of a proc",
+    errImplOfXNotAllowed: "implementation of \'$1\' is not allowed",
+    errImplOfXexpected: "implementation of \'$1\' expected",
+    errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
+    errDiscardValueX: "value of type '$1' has to be discarded",
+    errInvalidDiscard: "statement returns no value that can be discarded",
+    errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
+    errCannotBindXTwice: "cannot bind parameter \'$1\' twice",
+    errInvalidOrderInArrayConstructor: "invalid order in array constructor",
+    errInvalidOrderInEnumX: "invalid order in enum \'$1\'",
+    errEnumXHasHoles: "enum \'$1\' has holes",
+    errExceptExpected: "\'except\' or \'finally\' expected",
+    errInvalidTry: "after catch all \'except\' or \'finally\' no section may follow",
+    errOptionExpected: "option expected, but found \'$1\'",
+    errXisNoLabel: "\'$1\' is not a label",
+    errNotAllCasesCovered: "not all cases are covered",
+    errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
+    errComplexStmtRequiresInd: "complex statement requires indentation",
+    errXisNotCallable: "\'$1\' is not callable",
+    errNoPragmasAllowedForX: "no pragmas allowed for $1",
+    errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
+    errInvalidParamKindX: "invalid param kind: \'$1\'",
+    errDefaultArgumentInvalid: "default argument invalid",
+    errNamedParamHasToBeIdent: "named parameter has to be an identifier",
+    errNoReturnTypeForX: "no return type allowed for $1",
+    errConvNeedsOneArg: "a type conversion needs exactly one argument",
+    errInvalidPragmaX: "invalid pragma: $1",
+    errXNotAllowedHere: "$1 not allowed here",
+    errInvalidControlFlowX: "invalid control flow: $1",
+    errXisNoType: "invalid type: \'$1\'",
+    errCircumNeedsPointer: "'[]' needs a pointer or reference type",
+    errInvalidExpression: "invalid expression",
+    errInvalidExpressionX: "invalid expression: \'$1\'",
+    errEnumHasNoValueX: "enum has no value \'$1\'",
+    errNamedExprExpected: "named expression expected",
+    errNamedExprNotAllowed: "named expression not allowed here",
+    errXExpectsOneTypeParam: "\'$1\' expects one type parameter",
+    errArrayExpectsTwoTypeParams: "array expects two type parameters",
+    errInvalidVisibilityX: "invalid visibility: \'$1\'",
+    errInitHereNotAllowed: "initialization not allowed here",
+    errXCannotBeAssignedTo: "\'$1\' cannot be assigned to",
+    errIteratorNotAllowed: "iterators can only be defined at the module\'s top level",
+    errXNeedsReturnType: "$1 needs a return type",
+    errNoReturnTypeDeclared: "no return type declared",
+    errInvalidCommandX: "invalid command: \'$1\'",
+    errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
+    errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
+    errTemplateInstantiationTooNested: "template/macro instantiation too nested",
+    errInstantiationFrom: "template/generic instantiation from here",
+    errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
+    errCommandExpectsFilename: "command expects a filename argument",
+    errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
+    errXExpected: "\'$1\' expected",
+    errTIsNotAConcreteType: "\'$1\' is not a concrete type.",
+    errInvalidSectionStart: "invalid section start",
+    errGridTableNotImplemented: "grid table is not implemented",
+    errGeneralParseError: "general parse error",
+    errNewSectionExpected: "new section expected",
+    errWhitespaceExpected: "whitespace expected, got \'$1\'",
+    errXisNoValidIndexFile: "\'$1\' is no valid index file",
+    errCannotRenderX: "cannot render reStructuredText element \'$1\'",
+    errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
+    errInstantiateXExplicitly: "instantiate '$1' explicitly",
+    errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
+    errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
+    errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
+                                       "because the parameter '$1' has a generic type",
+    errDestructorNotGenericEnough: "Destructor signature is too specific. " &
+                                   "A destructor must be associated will all instantiations of a generic type",
+    errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
+                                    "templates, macros and other inline iterators",
+    errXExpectsTwoArguments: "\'$1\' expects two arguments",
+    errXExpectsObjectTypes: "\'$1\' expects object types",
+    errXcanNeverBeOfThisSubtype: "\'$1\' can never be of this subtype",
+    errTooManyIterations: "interpretation requires too many iterations",
+    errCannotInterpretNodeX: "cannot evaluate \'$1\'",
+    errFieldXNotFound: "field \'$1\' cannot be found",
+    errInvalidConversionFromTypeX: "invalid conversion from type \'$1\'",
+    errAssertionFailed: "assertion failed",
+    errCannotGenerateCodeForX: "cannot generate code for \'$1\'",
+    errXRequiresOneArgument: "$1 requires one parameter",
+    errUnhandledExceptionX: "unhandled exception: $1",
+    errCyclicTree: "macro returned a cyclic abstract syntax tree",
+    errXisNoMacroOrTemplate: "\'$1\' is no macro or template",
+    errXhasSideEffects: "\'$1\' can have side effects",
+    errIteratorExpected: "iterator within for loop context expected",
+    errLetNeedsInit: "'let' symbol requires an initialization",
+    errThreadvarCannotInit: "a thread var cannot be initialized explicitly",
+    errWrongSymbolX: "usage of \'$1\' is a user-defined error",
+    errIllegalCaptureX: "illegal capture '$1'",
+    errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
+    errXMustBeCompileTime: "'$1' can only be used in compile-time context",
+    errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
+    errCannotInferReturnType: "cannot infer the return type of the proc",
+    errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
+                                "it is used as an operand to another routine and the types " &
+                                "of the generic paramers can be inferred from the expected signature.",
+    errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
+    errUser: "$1",
+    warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
+    warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
+    warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
+    warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
+    warnDeprecated: "$1 is deprecated [Deprecated]",
+    warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
+    warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
+    warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
+    warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
+    warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
+    warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
+    warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
+    warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
+    warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
+    warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
+    warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
+    warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
+    warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]",
+    warnEachIdentIsTuple: "each identifier is a tuple [EachIdentIsTuple]",
+    warnShadowIdent: "shadowed identifier: '$1' [ShadowIdent]",
+    warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future. [ProveInit]",
+    warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
+    warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
+    warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
+    warnGcUnsafe2: "$1",
+    warnUninit: "'$1' might not have been initialized [Uninit]",
+    warnGcMem: "'$1' uses GC'ed memory [GcMem]",
+    warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future. [Destructor]",
+    warnLockLevel: "$1 [LockLevel]",
+    warnResultShadowed: "Special variable 'result' is shadowed. [ResultShadowed]",
+    warnUser: "$1 [User]",
+    hintSuccess: "operation successful [Success]",
+    hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#) [SuccessX]",
+    hintLineTooLong: "line too long [LineTooLong]",
+    hintXDeclaredButNotUsed: "\'$1\' is declared but not used [XDeclaredButNotUsed]",
+    hintConvToBaseNotNeeded: "conversion to base object is not needed [ConvToBaseNotNeeded]",
+    hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless [ConvFromXtoItselfNotNeeded]",
+    hintExprAlwaysX: "expression evaluates always to \'$1\' [ExprAlwaysX]",
+    hintQuitCalled: "quit() called [QuitCalled]",
+    hintProcessing: "$1 [Processing]",
+    hintCodeBegin: "generated code listing: [CodeBegin]",
+    hintCodeEnd: "end of listing [CodeEnd]",
+    hintConf: "used config file \'$1\' [Conf]",
+    hintPath: "added path: '$1' [Path]",
+    hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
+    hintName: "name should be: '$1' [Name]",
+    hintPattern: "$1 [Pattern]",
+    hintUser: "$1 [User]"]
+
+const
+  WarningsToStr*: array[0..30, string] = ["CannotOpenFile", "OctalEscape",
+    "XIsNeverRead", "XmightNotBeenInit",
+    "Deprecated", "ConfigDeprecated",
+    "SmallLshouldNotBeUsed", "UnknownMagic",
+    "RedefinitionOfLabel", "UnknownSubstitutionX",
+    "LanguageXNotSupported", "FieldXNotSupported",
+    "CommentXIgnored", "NilStmt",
+    "TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
+    "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
+    "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
+    "GcMem", "Destructor", "LockLevel", "ResultShadowed", "User"]
+
+  HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
+    "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
+    "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
+    "Path", "CondTrue", "Name", "Pattern",
+    "User"]
+
+const
+  fatalMin* = errUnknown
+  fatalMax* = errInternal
+  errMin* = errUnknown
+  errMax* = errUser
+  warnMin* = warnCannotOpenFile
+  warnMax* = pred(hintSuccess)
+  hintMin* = hintSuccess
+  hintMax* = high(TMsgKind)
+
+type
+  TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
+  TNoteKinds* = set[TNoteKind]
+
+  TFileInfo* = object
+    fullPath: string           # This is a canonical full filesystem path
+    projPath*: string          # This is relative to the project's root
+    shortName*: string         # short name of the module
+    quotedName*: Rope         # cached quoted short name for codegen
+                               # purposes
+
+    lines*: seq[Rope]         # the source code of the module
+                               #   used for better error messages and
+                               #   embedding the original source in the
+                               #   generated code
+    dirtyfile: string          # the file that is actually read into memory
+                               # and parsed; usually 'nil' but is used
+                               # for 'nimsuggest'
+
+  TLineInfo* = object          # This is designed to be as small as possible,
+                               # because it is used
+                               # in syntax nodes. We save space here by using
+                               # two int16 and an int32.
+                               # On 64 bit and on 32 bit systems this is
+                               # only 8 bytes.
+    line*, col*: int16
+    fileIndex*: int32
+
+  TErrorOutput* = enum
+    eStdOut
+    eStdErr
+    eInMemory
+
+  TErrorOutputs* = set[TErrorOutput]
+
+  ERecoverableError* = object of ValueError
+  ESuggestDone* = object of Exception
+
+const
+  InvalidFileIDX* = int32(-1)
+
+var
+  filenameToIndexTbl = initTable[string, int32]()
+  fileInfos*: seq[TFileInfo] = @[]
+  systemFileIdx*: int32
+
+proc toCChar*(c: char): string =
+  case c
+  of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
+  of '\'', '\"', '\\': result = '\\' & c
+  else: result = $(c)
+
+proc makeCString*(s: string): Rope =
+  const
+    MaxLineLength = 64
+  result = nil
+  var res = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
+  add(res, "\"")
+  for i in countup(0, len(s) - 1):
+    if (i + 1) mod MaxLineLength == 0:
+      add(res, '\"')
+      add(res, tnl)
+      add(res, '\"')
+    add(res, toCChar(s[i]))
+  add(res, '\"')
+  add(result, rope(res))
+
+
+proc newFileInfo(fullPath, projPath: string): TFileInfo =
+  result.fullPath = fullPath
+  #shallow(result.fullPath)
+  result.projPath = projPath
+  #shallow(result.projPath)
+  let fileName = projPath.extractFilename
+  result.shortName = fileName.changeFileExt("")
+  result.quotedName = fileName.makeCString
+  if optEmbedOrigSrc in gGlobalOptions or true:
+    result.lines = @[]
+
+proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
+  var
+    canon: string
+    pseudoPath = false
+
+  try:
+    canon = canonicalizePath(filename)
+    shallow(canon)
+  except:
+    canon = filename
+    # The compiler uses "filenames" such as `command line` or `stdin`
+    # This flag indicates that we are working with such a path here
+    pseudoPath = true
+
+  if filenameToIndexTbl.hasKey(canon):
+    result = filenameToIndexTbl[canon]
+  else:
+    isKnownFile = false
+    result = fileInfos.len.int32
+    fileInfos.add(newFileInfo(canon, if pseudoPath: filename
+                                     else: canon.shortenDir))
+    filenameToIndexTbl[canon] = result
+
+proc fileInfoIdx*(filename: string): int32 =
+  var dummy: bool
+  result = fileInfoIdx(filename, dummy)
+
+proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
+  result.fileIndex = fileInfoIdx
+  result.line = int16(line)
+  result.col = int16(col)
+
+proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
+  result = newLineInfo(filename.fileInfoIdx, line, col)
+
+fileInfos.add(newFileInfo("", "command line"))
+var gCmdLineInfo* = newLineInfo(int32(0), 1, 1)
+
+fileInfos.add(newFileInfo("", "compilation artifact"))
+var gCodegenLineInfo* = newLineInfo(int32(1), 1, 1)
+
+proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
+  raise newException(ERecoverableError, msg)
+
+proc sourceLine*(i: TLineInfo): Rope
+
+var
+  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -
+                        {warnShadowIdent, warnUninit,
+                         warnProveField, warnProveIndex, warnGcUnsafe}
+  gErrorCounter*: int = 0     # counts the number of errors
+  gHintCounter*: int = 0
+  gWarnCounter*: int = 0
+  gErrorMax*: int = 1         # stop after gErrorMax errors
+
+proc unknownLineInfo*(): TLineInfo =
+  result.line = int16(-1)
+  result.col = int16(-1)
+  result.fileIndex = -1
+
+var
+  msgContext: seq[TLineInfo] = @[]
+  lastError = unknownLineInfo()
+
+  errorOutputs* = {eStdOut, eStdErr}
+  writelnHook*: proc (output: string) {.closure.}
+
+proc suggestWriteln*(s: string) =
+  if eStdOut in errorOutputs:
+    if isNil(writelnHook): writeln(stdout, s)
+    else: writelnHook(s)
+
+proc msgQuit*(x: int8) = quit x
+proc msgQuit*(x: string) = quit x
+
+proc suggestQuit*() =
+  raise newException(ESuggestDone, "suggest done")
+
+# this format is understood by many text editors: it is the same that
+# Borland and Freepascal use
+const
+  PosErrorFormat* = "$1($2, $3) Error: $4"
+  PosWarningFormat* = "$1($2, $3) Warning: $4"
+  PosHintFormat* = "$1($2, $3) Hint: $4"
+  PosContextFormat = "$1($2, $3) Info: $4"
+  RawErrorFormat* = "Error: $1"
+  RawWarningFormat* = "Warning: $1"
+  RawHintFormat* = "Hint: $1"
+
+proc getInfoContextLen*(): int = return msgContext.len
+proc setInfoContextLen*(L: int) = setLen(msgContext, L)
+
+proc pushInfoContext*(info: TLineInfo) =
+  msgContext.add(info)
+
+proc popInfoContext*() =
+  setLen(msgContext, len(msgContext) - 1)
+
+proc getInfoContext*(index: int): TLineInfo =
+  let L = msgContext.len
+  let i = if index < 0: L + index else: index
+  if i >=% L: result = unknownLineInfo()
+  else: result = msgContext[i]
+
+proc toFilename*(fileIdx: int32): string =
+  if fileIdx < 0: result = "???"
+  else: result = fileInfos[fileIdx].projPath
+
+proc toFullPath*(fileIdx: int32): string =
+  if fileIdx < 0: result = "???"
+  else: result = fileInfos[fileIdx].fullPath
+
+proc setDirtyFile*(fileIdx: int32; filename: string) =
+  assert fileIdx >= 0
+  fileInfos[fileIdx].dirtyFile = filename
+
+proc toFullPathConsiderDirty*(fileIdx: int32): string =
+  if fileIdx < 0:
+    result = "???"
+  elif not fileInfos[fileIdx].dirtyFile.isNil:
+    result = fileInfos[fileIdx].dirtyFile
+  else:
+    result = fileInfos[fileIdx].fullPath
+
+template toFilename*(info: TLineInfo): string =
+  info.fileIndex.toFilename
+
+template toFullPath*(info: TLineInfo): string =
+  info.fileIndex.toFullPath
+
+proc toMsgFilename*(info: TLineInfo): string =
+  if info.fileIndex < 0:
+    result = "???"
+  elif gListFullPaths:
+    result = fileInfos[info.fileIndex].fullPath
+  else:
+    result = fileInfos[info.fileIndex].projPath
+
+proc toLinenumber*(info: TLineInfo): int {.inline.} =
+  result = info.line
+
+proc toColumn*(info: TLineInfo): int {.inline.} =
+  result = info.col
+
+proc toFileLine*(info: TLineInfo): string {.inline.} =
+  result = info.toFilename & ":" & $info.line
+
+proc toFileLineCol*(info: TLineInfo): string {.inline.} =
+  result = info.toFilename & "(" & $info.line & "," & $info.col & ")"
+
+proc `$`*(info: TLineInfo): string = toFileLineCol(info)
+
+proc `??`* (info: TLineInfo, filename: string): bool =
+  # only for debugging purposes
+  result = filename in info.toFilename
+
+var gTrackPos*: TLineInfo
+
+proc outWriteln*(s: string) =
+  ## Writes to stdout. Always.
+  if eStdOut in errorOutputs: writeln(stdout, s)
+
+proc msgWriteln*(s: string) =
+  ## Writes to stdout. If --stdout option is given, writes to stderr instead.
+
+  #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
+
+  if not isNil(writelnHook):
+    writelnHook(s)
+  elif optStdout in gGlobalOptions:
+    if eStdErr in errorOutputs: writeln(stderr, s)
+  else:
+    if eStdOut in errorOutputs: writeln(stdout, s)
+
+proc coordToStr(coord: int): string =
+  if coord == -1: result = "???"
+  else: result = $coord
+
+proc msgKindToString*(kind: TMsgKind): string =
+  # later versions may provide translated error messages
+  result = MsgKindToStr[kind]
+
+proc getMessageStr(msg: TMsgKind, arg: string): string =
+  result = msgKindToString(msg) % [arg]
+
+type
+  TErrorHandling = enum doNothing, doAbort, doRaise
+
+proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
+  template quit =
+    if defined(debug) or gVerbosity >= 3 or msg == errInternal:
+      if stackTraceAvailable() and isNil(writelnHook):
+        writeStackTrace()
+      else:
+        msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
+    quit 1
+
+  if msg >= fatalMin and msg <= fatalMax:
+    quit()
+  if msg >= errMin and msg <= errMax:
+    inc(gErrorCounter)
+    options.gExitcode = 1'i8
+    if gErrorCounter >= gErrorMax:
+      quit()
+    elif eh == doAbort and gCmd != cmdIdeTools:
+      quit()
+    elif eh == doRaise:
+      raiseRecoverableError(s)
+
+proc `==`*(a, b: TLineInfo): bool =
+  result = a.line == b.line and a.fileIndex == b.fileIndex
+
+proc writeContext(lastinfo: TLineInfo) =
+  var info = lastinfo
+  for i in countup(0, len(msgContext) - 1):
+    if msgContext[i] != lastinfo and msgContext[i] != info:
+      msgWriteln(PosContextFormat % [toMsgFilename(msgContext[i]),
+                                     coordToStr(msgContext[i].line),
+                                     coordToStr(msgContext[i].col+1),
+                                     getMessageStr(errInstantiationFrom, "")])
+    info = msgContext[i]
+
+proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
+  msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
+
+proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
+  var frmt: string
+  case msg
+  of errMin..errMax:
+    writeContext(unknownLineInfo())
+    frmt = RawErrorFormat
+  of warnMin..warnMax:
+    if optWarns notin gOptions: return
+    if msg notin gNotes: return
+    writeContext(unknownLineInfo())
+    frmt = RawWarningFormat
+    inc(gWarnCounter)
+  of hintMin..hintMax:
+    if optHints notin gOptions: return
+    if msg notin gNotes: return
+    frmt = RawHintFormat
+    inc(gHintCounter)
+  let s = `%`(frmt, `%`(msgKindToString(msg), args))
+  if not ignoreMsgBecauseOfIdeTools(msg):
+    msgWriteln(s)
+  handleError(msg, doAbort, s)
+
+proc rawMessage*(msg: TMsgKind, arg: string) =
+  rawMessage(msg, [arg])
+
+proc writeSurroundingSrc(info: TLineInfo) =
+  const indent = "  "
+  msgWriteln(indent & $info.sourceLine)
+  msgWriteln(indent & spaces(info.col) & '^')
+
+proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
+  let frmt = case msg
+             of warnMin..warnMax: PosWarningFormat
+             of hintMin..hintMax: PosHintFormat
+             else: PosErrorFormat
+  result = frmt % [toMsgFilename(info), coordToStr(info.line),
+                   coordToStr(info.col+1), getMessageStr(msg, arg)]
+
+proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
+               eh: TErrorHandling) =
+  var frmt: string
+  var ignoreMsg = false
+  case msg
+  of errMin..errMax:
+    writeContext(info)
+    frmt = PosErrorFormat
+    # we try to filter error messages so that not two error message
+    # in the same file and line are produced:
+    #ignoreMsg = lastError == info and eh != doAbort
+    lastError = info
+  of warnMin..warnMax:
+    ignoreMsg = optWarns notin gOptions or msg notin gNotes
+    if not ignoreMsg: writeContext(info)
+    frmt = PosWarningFormat
+    inc(gWarnCounter)
+  of hintMin..hintMax:
+    ignoreMsg = optHints notin gOptions or msg notin gNotes
+    frmt = PosHintFormat
+    inc(gHintCounter)
+  # NOTE: currently line info line numbers start with 1,
+  # but column numbers start with 0, however most editors expect
+  # first column to be 1, so we need to +1 here
+  let s = frmt % [toMsgFilename(info), coordToStr(info.line),
+                  coordToStr(info.col+1), getMessageStr(msg, arg)]
+  if not ignoreMsg and not ignoreMsgBecauseOfIdeTools(msg):
+    msgWriteln(s)
+    if optPrintSurroundingSrc and msg in errMin..errMax:
+      info.writeSurroundingSrc
+  handleError(msg, eh, s)
+
+proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(info, msg, arg, doAbort)
+
+proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(info, msg, arg, doRaise)
+
+proc globalError*(info: TLineInfo, arg: string) =
+  liMessage(info, errGenerated, arg, doRaise)
+
+proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(info, msg, arg, doNothing)
+
+proc localError*(info: TLineInfo, arg: string) =
+  liMessage(info, errGenerated, arg, doNothing)
+
+proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
+  localError(info, format % params)
+
+proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
+  liMessage(info, msg, arg, doNothing)
+
+proc internalError*(info: TLineInfo, errMsg: string) =
+  if gCmd == cmdIdeTools: return
+  writeContext(info)
+  liMessage(info, errInternal, errMsg, doAbort)
+
+proc internalError*(errMsg: string) =
+  if gCmd == cmdIdeTools: return
+  writeContext(unknownLineInfo())
+  rawMessage(errInternal, errMsg)
+
+template assertNotNil*(e: expr): expr =
+  if e == nil: internalError($instantiationInfo())
+  e
+
+template internalAssert*(e: bool): stmt =
+  if not e: internalError($instantiationInfo())
+
+proc addSourceLine*(fileIdx: int32, line: string) =
+  fileInfos[fileIdx].lines.add line.rope
+
+proc sourceLine*(i: TLineInfo): Rope =
+  if i.fileIndex < 0: return nil
+
+  if not optPreserveOrigSource and fileInfos[i.fileIndex].lines.len == 0:
+    try:
+      for line in lines(i.toFullPath):
+        addSourceLine i.fileIndex, line.string
+    except IOError:
+      discard
+  internalAssert i.fileIndex < fileInfos.len
+  # can happen if the error points to EOF:
+  if i.line > fileInfos[i.fileIndex].lines.len: return nil
+
+  result = fileInfos[i.fileIndex].lines[i.line-1]
+
+proc quotedFilename*(i: TLineInfo): Rope =
+  internalAssert i.fileIndex >= 0
+  result = fileInfos[i.fileIndex].quotedName
+
+ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
+  case err
+  of rInvalidFormatStr:
+    internalError("ropes: invalid format string: " & msg)
+  of rCannotOpenFile:
+    rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
+
diff --git a/compiler/nim.nim b/compiler/nim.nim
new file mode 100644
index 000000000..89db22e8f
--- /dev/null
+++ b/compiler/nim.nim
@@ -0,0 +1,98 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+when defined(gcc) and defined(windows):
+  when defined(x86):
+    {.link: "icons/nim.res".}
+  else:
+    {.link: "icons/nim_icon.o".}
+
+import
+  commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
+  extccomp, strutils, os, osproc, platform, main, parseopt, service,
+  nodejs
+
+when hasTinyCBackend:
+  import tccgen
+
+when defined(profiler) or defined(memProfiler):
+  {.hint: "Profiling support is turned on!".}
+  import nimprof
+
+proc prependCurDir(f: string): string =
+  when defined(unix):
+    if os.isAbsolute(f): result = f
+    else: result = "./" & f
+  else:
+    result = f
+
+proc handleCmdLine() =
+  if paramCount() == 0:
+    writeCommandLineUsage()
+  else:
+    # Process command line arguments:
+    processCmdLine(passCmd1, "")
+    if gProjectName == "-":
+      gProjectName = "stdinfile"
+      gProjectFull = "stdinfile"
+      gProjectPath = getCurrentDir()
+      gProjectIsStdin = true
+    elif gProjectName != "":
+      try:
+        gProjectFull = canonicalizePath(gProjectName)
+      except OSError:
+        gProjectFull = gProjectName
+      var p = splitFile(gProjectFull)
+      gProjectPath = p.dir
+      gProjectName = p.name
+    else:
+      gProjectPath = getCurrentDir()
+    loadConfigs(DefaultConfig) # load all config files
+    # now process command line arguments again, because some options in the
+    # command line can overwite the config file's settings
+    extccomp.initVars()
+    processCmdLine(passCmd2, "")
+    mainCommand()
+    if gVerbosity >= 2: echo(GC_getStatistics())
+    #echo(GC_getStatistics())
+    if msgs.gErrorCounter == 0:
+      when hasTinyCBackend:
+        if gCmd == cmdRun:
+          tccgen.run(commands.arguments)
+      if optRun in gGlobalOptions:
+        if gCmd == cmdCompileToJS:
+          var ex: string
+          if options.outFile.len > 0:
+            ex = options.outFile.prependCurDir.quoteShell
+          else:
+            ex = quoteShell(
+              completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
+          execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments)
+        else:
+          var binPath: string
+          if options.outFile.len > 0:
+            # If the user specified an outFile path, use that directly.
+            binPath = options.outFile.prependCurDir
+          else:
+            # Figure out ourselves a valid binary name.
+            binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
+          var ex = quoteShell(binPath)
+          execExternalProgram(ex & ' ' & commands.arguments)
+
+when declared(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+when compileOption("gc", "v2") or compileOption("gc", "refc"):
+  # the new correct mark&sweet collector is too slow :-/
+  GC_disableMarkAndSweep()
+condsyms.initDefines()
+
+when not defined(selftest):
+  handleCmdLine()
+  msgQuit(int8(msgs.gErrorCounter > 0))
diff --git a/compiler/nim.nim.cfg b/compiler/nim.nim.cfg
new file mode 100644
index 000000000..64631a437
--- /dev/null
+++ b/compiler/nim.nim.cfg
@@ -0,0 +1,21 @@
+# Special configuration file for the Nim project
+
+hint[XDeclaredButNotUsed]:off
+path:"llvm"
+path:"$projectPath/.."
+
+path:"$lib/packages/docutils"
+
+define:booting
+import:testability
+
+@if windows:
+  cincludes: "$lib/wrappers/libffi/common"
+@end
+
+define:useStdoutAsStdmsg
+
+cs:partial
+#define:useNodeIds
+symbol:nimfix
+#gc:markAndSweep
diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim
new file mode 100644
index 000000000..23f3331a2
--- /dev/null
+++ b/compiler/nimblecmd.nim
@@ -0,0 +1,90 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements some helper procs for Nimble (Nim's package manager) support.
+
+import parseutils, strutils, strtabs, os, options, msgs, lists
+
+proc addPath*(path: string, info: TLineInfo) = 
+  if not contains(options.searchPaths, path): 
+    lists.prependStr(options.searchPaths, path)
+
+proc versionSplitPos(s: string): int =
+  result = s.len-2
+  while result > 1 and s[result] in {'0'..'9', '.'}: dec result
+  if s[result] != '-': result = s.len
+
+const
+  latest = "head"
+
+proc `<.`(a, b: string): bool = 
+  # wether a has a smaller version than b:
+  if a == latest: return false
+  var i = 0
+  var j = 0
+  var verA = 0
+  var verB = 0
+  while true:
+    let ii = parseInt(a, verA, i)
+    let jj = parseInt(b, verB, j)
+    # if A has no number left, but B has, B is preferred:  0.8 vs 0.8.3
+    if ii <= 0 or jj <= 0: return jj > 0
+    if verA < verB: return true
+    elif verA > verB: return false
+    # else: same version number; continue:
+    inc i, ii
+    inc j, jj
+    if a[i] == '.': inc i
+    if b[j] == '.': inc j
+
+proc addPackage(packages: StringTableRef, p: string) =
+  let x = versionSplitPos(p)
+  let name = p.substr(0, x-1)
+  if x < p.len:
+    let version = p.substr(x+1)
+    if packages[name] <. version:
+      packages[name] = version
+  else:
+    packages[name] = latest
+
+iterator chosen(packages: StringTableRef): string =
+  for key, val in pairs(packages):
+    let res = if val == latest: key else: key & '-' & val
+    yield res
+
+proc addNimblePath(p: string, info: TLineInfo) =
+  if not contains(options.searchPaths, p):
+    if gVerbosity >= 1: message(info, hintPath, p)
+    lists.prependStr(options.lazyPaths, p)
+
+proc addPathWithNimFiles(p: string, info: TLineInfo) =
+  proc hasNimFile(dir: string): bool =
+    for kind, path in walkDir(dir):
+      if kind == pcFile and path.endsWith(".nim"):
+        result = true
+        break
+  if hasNimFile(p):
+    addNimblePath(p, info)
+  else:
+    for kind, p2 in walkDir(p):
+      if hasNimFile(p2): addNimblePath(p2, info)
+
+proc addPathRec(dir: string, info: TLineInfo) =
+  var packages = newStringTable(modeStyleInsensitive)
+  var pos = dir.len-1
+  if dir[pos] in {DirSep, AltSep}: inc(pos)
+  for k,p in os.walkDir(dir):
+    if k == pcDir and p[pos] != '.':
+      addPackage(packages, p)
+  for p in packages.chosen:
+    addNimblePath(p, info)
+
+proc nimblePath*(path: string, info: TLineInfo) =
+  addPathRec(path, info)
+  addNimblePath(path, info)
diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim
new file mode 100644
index 000000000..711b476e6
--- /dev/null
+++ b/compiler/nimconf.nim
@@ -0,0 +1,262 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module handles the reading of the config file.
+
+import 
+  llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, 
+  options, idents, wordrecg, strtabs
+
+# ---------------- configuration file parser -----------------------------
+# we use Nim's scanner here to save space and work
+
+proc ppGetTok(L: var TLexer, tok: var TToken) = 
+  # simple filter
+  rawGetTok(L, tok)
+  while tok.tokType in {tkComment}: rawGetTok(L, tok)
+  
+proc parseExpr(L: var TLexer, tok: var TToken): bool
+proc parseAtom(L: var TLexer, tok: var TToken): bool = 
+  if tok.tokType == tkParLe: 
+    ppGetTok(L, tok)
+    result = parseExpr(L, tok)
+    if tok.tokType == tkParRi: ppGetTok(L, tok)
+    else: lexMessage(L, errTokenExpected, "\')\'")
+  elif tok.ident.id == ord(wNot): 
+    ppGetTok(L, tok)
+    result = not parseAtom(L, tok)
+  else:
+    result = isDefined(tok.ident)
+    ppGetTok(L, tok)
+
+proc parseAndExpr(L: var TLexer, tok: var TToken): bool = 
+  result = parseAtom(L, tok)
+  while tok.ident.id == ord(wAnd): 
+    ppGetTok(L, tok)          # skip "and"
+    var b = parseAtom(L, tok)
+    result = result and b
+
+proc parseExpr(L: var TLexer, tok: var TToken): bool = 
+  result = parseAndExpr(L, tok)
+  while tok.ident.id == ord(wOr): 
+    ppGetTok(L, tok)          # skip "or"
+    var b = parseAndExpr(L, tok)
+    result = result or b
+
+proc evalppIf(L: var TLexer, tok: var TToken): bool = 
+  ppGetTok(L, tok)            # skip 'if' or 'elif'
+  result = parseExpr(L, tok)
+  if tok.tokType == tkColon: ppGetTok(L, tok)
+  else: lexMessage(L, errTokenExpected, "\':\'")
+  
+var condStack: seq[bool] = @[]
+
+proc doEnd(L: var TLexer, tok: var TToken) = 
+  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+  ppGetTok(L, tok)            # skip 'end'
+  setLen(condStack, high(condStack))
+
+type 
+  TJumpDest = enum 
+    jdEndif, jdElseEndif
+
+proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest)
+proc doElse(L: var TLexer, tok: var TToken) = 
+  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+  ppGetTok(L, tok)
+  if tok.tokType == tkColon: ppGetTok(L, tok)
+  if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif)
+  
+proc doElif(L: var TLexer, tok: var TToken) = 
+  if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
+  var res = evalppIf(L, tok)
+  if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif)
+  else: condStack[high(condStack)] = true
+  
+proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = 
+  var nestedIfs = 0
+  while true: 
+    if tok.ident != nil and tok.ident.s == "@":
+      ppGetTok(L, tok)
+      case whichKeyword(tok.ident)
+      of wIf: 
+        inc(nestedIfs)
+      of wElse: 
+        if dest == jdElseEndif and nestedIfs == 0:
+          doElse(L, tok)
+          break 
+      of wElif: 
+        if dest == jdElseEndif and nestedIfs == 0:
+          doElif(L, tok)
+          break 
+      of wEnd: 
+        if nestedIfs == 0: 
+          doEnd(L, tok)
+          break 
+        if nestedIfs > 0: dec(nestedIfs)
+      else: 
+        discard
+      ppGetTok(L, tok)
+    elif tok.tokType == tkEof:
+      lexMessage(L, errTokenExpected, "@end")
+    else:
+      ppGetTok(L, tok)
+  
+proc parseDirective(L: var TLexer, tok: var TToken) = 
+  ppGetTok(L, tok)            # skip @
+  case whichKeyword(tok.ident)
+  of wIf:
+    setLen(condStack, len(condStack) + 1)
+    let res = evalppIf(L, tok)
+    condStack[high(condStack)] = res
+    if not res: jumpToDirective(L, tok, jdElseEndif)
+  of wElif: doElif(L, tok)
+  of wElse: doElse(L, tok)
+  of wEnd: doEnd(L, tok)
+  of wWrite:
+    ppGetTok(L, tok)
+    msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
+                                {useEnvironment, useKey}))
+    ppGetTok(L, tok)
+  else:
+    case tok.ident.s.normalize
+    of "putenv": 
+      ppGetTok(L, tok)
+      var key = tokToStr(tok)
+      ppGetTok(L, tok)
+      os.putEnv(key, tokToStr(tok))
+      ppGetTok(L, tok)
+    of "prependenv": 
+      ppGetTok(L, tok)
+      var key = tokToStr(tok)
+      ppGetTok(L, tok)
+      os.putEnv(key, tokToStr(tok) & os.getEnv(key))
+      ppGetTok(L, tok)
+    of "appendenv":
+      ppGetTok(L, tok)
+      var key = tokToStr(tok)
+      ppGetTok(L, tok)
+      os.putEnv(key, os.getEnv(key) & tokToStr(tok))
+      ppGetTok(L, tok)
+    else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
+  
+proc confTok(L: var TLexer, tok: var TToken) = 
+  ppGetTok(L, tok)
+  while tok.ident != nil and tok.ident.s == "@": 
+    parseDirective(L, tok)    # else: give the token to the parser
+  
+proc checkSymbol(L: TLexer, tok: TToken) = 
+  if tok.tokType notin {tkSymbol..pred(tkIntLit), tkStrLit..tkTripleStrLit}: 
+    lexMessage(L, errIdentifierExpected, tokToStr(tok))
+  
+proc parseAssignment(L: var TLexer, tok: var TToken) = 
+  if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
+    confTok(L, tok)           # skip unnecessary prefix
+  var info = getLineInfo(L, tok) # save for later in case of an error
+  checkSymbol(L, tok)
+  var s = tokToStr(tok)
+  confTok(L, tok)             # skip symbol
+  var val = ""
+  while tok.tokType == tkDot: 
+    add(s, '.')
+    confTok(L, tok)
+    checkSymbol(L, tok)
+    add(s, tokToStr(tok))
+    confTok(L, tok)
+  if tok.tokType == tkBracketLe: 
+    # BUGFIX: val, not s!
+    # BUGFIX: do not copy '['!
+    confTok(L, tok)
+    checkSymbol(L, tok)
+    add(val, tokToStr(tok))
+    confTok(L, tok)
+    if tok.tokType == tkBracketRi: confTok(L, tok)
+    else: lexMessage(L, errTokenExpected, "']'")
+    add(val, ']')
+  let percent = tok.ident.id == getIdent("%=").id
+  if tok.tokType in {tkColon, tkEquals} or percent: 
+    if len(val) > 0: add(val, ':')
+    confTok(L, tok)           # skip ':' or '=' or '%'
+    checkSymbol(L, tok)
+    add(val, tokToStr(tok))
+    confTok(L, tok)           # skip symbol
+    while tok.ident != nil and tok.ident.id == getIdent("&").id:
+      confTok(L, tok)
+      checkSymbol(L, tok)
+      add(val, tokToStr(tok))
+      confTok(L, tok)
+  if percent:
+    processSwitch(s, strtabs.`%`(val, options.gConfigVars,
+                                {useEnvironment, useEmpty}), passPP, info)
+  else:
+    processSwitch(s, val, passPP, info)
+
+proc readConfigFile(filename: string) =
+  var
+    L: TLexer
+    tok: TToken
+    stream: PLLStream
+  stream = llStreamOpen(filename, fmRead)
+  if stream != nil:
+    initToken(tok)
+    openLexer(L, filename, stream)
+    tok.tokType = tkEof       # to avoid a pointless warning
+    confTok(L, tok)           # read in the first token
+    while tok.tokType != tkEof: parseAssignment(L, tok)
+    if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
+    closeLexer(L)
+    if gVerbosity >= 1: rawMessage(hintConf, filename)
+
+proc getUserConfigPath(filename: string): string =
+  result = joinPath(getConfigDir(), filename)
+
+proc getSystemConfigPath(filename: string): string =
+  # try standard configuration file (installation did not distribute files
+  # the UNIX way)
+  let p = getPrefixDir()
+  result = joinPath([p, "config", filename])
+  when defined(unix):
+    if not existsFile(result): result = joinPath([p, "etc", filename])
+    if not existsFile(result): result = "/etc/" & filename
+
+proc loadConfigs*(cfg: string) =
+  # set default value (can be overwritten):
+  if libpath == "": 
+    # choose default libpath:
+    var prefix = getPrefixDir()
+    when defined(posix):
+      if prefix == "/usr": libpath = "/usr/lib/nim"
+      elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
+      else: libpath = joinPath(prefix, "lib")
+    else: libpath = joinPath(prefix, "lib")
+
+  if optSkipConfigFile notin gGlobalOptions:
+    readConfigFile(getSystemConfigPath(cfg))
+
+  if optSkipUserConfigFile notin gGlobalOptions:
+    readConfigFile(getUserConfigPath(cfg))
+
+  var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
+  if optSkipParentConfigFiles notin gGlobalOptions:
+    for dir in parentDirs(pd, fromRoot=true, inclusive=false):
+      readConfigFile(dir / cfg)
+  
+  if optSkipProjConfigFile notin gGlobalOptions:
+    readConfigFile(pd / cfg)
+    
+    if gProjectName.len != 0:
+      # new project wide config file:
+      var projectConfig = changeFileExt(gProjectFull, "nimcfg")
+      if not fileExists(projectConfig):
+        projectConfig = changeFileExt(gProjectFull, "nim.cfg")
+      if not fileExists(projectConfig):
+        projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
+        if fileExists(projectConfig):
+          rawMessage(warnDeprecated, projectConfig)
+      readConfigFile(projectConfig)
diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim
new file mode 100644
index 000000000..197e8bf86
--- /dev/null
+++ b/compiler/nimeval.nim
@@ -0,0 +1,33 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## exposes the Nim VM to clients.
+
+import
+  ast, modules, passes, passaux, condsyms, 
+  options, nimconf, lists, sem, semdata, llstream, vm
+
+proc execute*(program: string) =
+  passes.gIncludeFile = includeModule
+  passes.gImportModule = importModule
+  initDefines()
+  loadConfigs(DefaultConfig)
+
+  initDefines()
+  defineSymbol("nimrodvm")
+  when hasFFI: defineSymbol("nimffi")
+  registerPass(verbosePass)
+  registerPass(semPass)
+  registerPass(evalPass)
+
+  appendStr(searchPaths, options.libpath)
+  compileSystemModule()
+  var m = makeStdinModule()
+  incl(m.flags, sfMainModule)
+  processModule(m, llStreamOpen(program), nil)
diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim
new file mode 100644
index 000000000..8caa23ee3
--- /dev/null
+++ b/compiler/nimfix/nimfix.nim
@@ -0,0 +1,108 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
+
+import strutils, os, parseopt
+import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
+  extccomp, condsyms, lists
+
+const Usage = """
+Nimfix - Tool to patch Nim code
+Usage:
+  nimfix [options] projectfile.nim
+
+Options:
+  --overwriteFiles:on|off          overwrite the original nim files.
+                                   DEFAULT is ON!
+  --wholeProject                   overwrite every processed file.
+  --checkExtern:on|off             style check also extern names
+  --styleCheck:on|off|auto         performs style checking for identifiers
+                                   and suggests an alternative spelling; 
+                                   'auto' corrects the spelling.
+  --bestEffort                     try to fix the code even when there
+                                   are errors.
+
+In addition, all command line options of Nim are supported.
+"""
+
+proc mainCommand =
+  registerPass verbosePass
+  registerPass semPass
+  gCmd = cmdPretty
+  appendStr(searchPaths, options.libpath)
+  if gProjectFull.len != 0:
+    # current path is always looked first for modules
+    prependStr(searchPaths, gProjectPath)
+
+  compileProject()
+  pretty.overwriteFiles()
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
+  var p = parseopt.initOptParser(cmd)
+  var argsCount = 0
+  gOnlyMainfile = true
+  while true: 
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break 
+    of cmdLongoption, cmdShortOption: 
+      case p.key.normalize
+      of "overwritefiles":
+        case p.val.normalize
+        of "on": gOverWrite = true
+        of "off": gOverWrite = false
+        else: localError(gCmdLineInfo, errOnOrOffExpected)
+      of "checkextern":
+        case p.val.normalize
+        of "on": gCheckExtern = true
+        of "off": gCheckExtern = false
+        else: localError(gCmdLineInfo, errOnOrOffExpected)
+      of "stylecheck":
+        case p.val.normalize
+        of "off": gStyleCheck = StyleCheck.None
+        of "on": gStyleCheck = StyleCheck.Warn
+        of "auto": gStyleCheck = StyleCheck.Auto
+        else: localError(gCmdLineInfo, errOnOrOffExpected)
+      of "wholeproject": gOnlyMainfile = false
+      of "besteffort": msgs.gErrorMax = high(int) # dont stop after first error
+      else:
+        processSwitch(pass, p)
+    of cmdArgument:
+      options.gProjectName = unixToNativePath(p.key)
+      # if processArgument(pass, p, argsCount): break
+
+proc handleCmdLine() =
+  if paramCount() == 0:
+    stdout.writeln(Usage)
+  else:
+    processCmdLine(passCmd1, "")
+    if gProjectName != "":
+      try:
+        gProjectFull = canonicalizePath(gProjectName)
+      except OSError:
+        gProjectFull = gProjectName
+      var p = splitFile(gProjectFull)
+      gProjectPath = p.dir
+      gProjectName = p.name
+    else:
+      gProjectPath = getCurrentDir()
+    loadConfigs(DefaultConfig) # load all config files
+    # now process command line arguments again, because some options in the
+    # command line can overwite the config file's settings
+    extccomp.initVars()
+    processCmdLine(passCmd2, "")
+    mainCommand()
+
+when compileOption("gc", "v2") or compileOption("gc", "refc"):
+  GC_disableMarkAndSweep()
+
+condsyms.initDefines()
+defineSymbol "nimfix"
+handleCmdline()
diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg
new file mode 100644
index 000000000..73219d6f8
--- /dev/null
+++ b/compiler/nimfix/nimfix.nim.cfg
@@ -0,0 +1,17 @@
+# Special configuration file for the Nim project
+# gc:markAndSweep
+
+hint[XDeclaredButNotUsed]:off
+path:"$projectPath/.."
+
+path:"$lib/packages/docutils"
+path:"../../compiler"
+
+define:useStdoutAsStdmsg
+symbol:nimfix
+define:nimfix
+
+cs:partial
+#define:useNodeIds
+define:booting
+define:noDocgen
diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim
new file mode 100644
index 000000000..d2d5b5e83
--- /dev/null
+++ b/compiler/nimfix/pretty.nim
@@ -0,0 +1,152 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the code "prettifier". This is part of the toolchain
+## to convert Nim code into a consistent style.
+
+import 
+  strutils, os, options, ast, astalgo, msgs, ropes, idents,
+  intsets, strtabs, semdata, prettybase
+
+type
+  StyleCheck* {.pure.} = enum None, Warn, Auto
+
+var
+  gOverWrite* = true
+  gStyleCheck*: StyleCheck
+  gCheckExtern*, gOnlyMainfile*: bool
+
+proc overwriteFiles*() =
+  let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
+  for i in 0 .. high(gSourceFiles):
+    if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
+        (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx):
+      let newFile = if gOverWrite: gSourceFiles[i].fullpath
+                    else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
+      try:
+        var f = open(newFile, fmWrite)
+        for line in gSourceFiles[i].lines:
+          if doStrip:
+            f.write line.strip(leading = false, trailing = true)
+          else:
+            f.write line
+          f.write(gSourceFiles[i].newline)
+        f.close
+      except IOError:
+        rawMessage(errCannotOpenFile, newFile)
+
+proc `=~`(s: string, a: openArray[string]): bool =
+  for x in a:
+    if s.startsWith(x): return true
+
+proc beautifyName(s: string, k: TSymKind): string =
+  # minimal set of rules here for transition:
+  # GC_ is allowed
+
+  let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'})
+  if allUpper and k in {skConst, skEnumField, skType}: return s
+  result = newStringOfCap(s.len)
+  var i = 0
+  case k
+  of skType, skGenericParam:
+    # Types should start with a capital unless builtins like 'int' etc.:
+    if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
+             "char", "byte", "bool", "openArray", "seq", "array", "void",
+             "pointer", "float", "csize", "cdouble", "cchar", "cschar",
+             "cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
+             "range", "openarray", "varargs", "set", "cfloat"
+             ]:
+      result.add s[i]
+    else:
+      result.add toUpper(s[i])
+  of skConst, skEnumField:
+    # for 'const' we keep how it's spelt; either upper case or lower case:
+    result.add s[0]
+  else:
+    # as a special rule, don't transform 'L' to 'l'
+    if s.len == 1 and s[0] == 'L': result.add 'L'
+    elif '_' in s: result.add(s[i])
+    else: result.add toLower(s[0])
+  inc i
+  while i < s.len:
+    if s[i] == '_':
+      if i > 0 and s[i-1] in {'A'..'Z'}:
+        # don't skip '_' as it's essential for e.g. 'GC_disable'
+        result.add('_')
+        inc i
+        result.add s[i]
+      else:
+        inc i
+        result.add toUpper(s[i])
+    elif allUpper:
+      result.add toLower(s[i])
+    else:
+      result.add s[i]
+    inc i
+
+proc replaceInFile(info: TLineInfo; newName: string) =
+  loadFile(info)
+  
+  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  var first = min(info.col.int, line.len)
+  if first < 0: return
+  #inc first, skipIgnoreCase(line, "proc ", first)
+  while first > 0 and line[first-1] in prettybase.Letters: dec first
+  if first < 0: return
+  if line[first] == '`': inc first
+  
+  let last = first+identLen(line, first)-1
+  if differ(line, first, last, newName):
+    # last-first+1 != newName.len or 
+    var x = line.substr(0, first-1) & newName & line.substr(last+1)    
+    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
+    gSourceFiles[info.fileIndex].dirty = true
+
+proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
+  let beau = beautifyName(s, k)
+  if s != beau:
+    if gStyleCheck == StyleCheck.Auto: 
+      sym.name = getIdent(beau)
+      replaceInFile(info, beau)
+    else:
+      message(info, hintName, beau)
+
+proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) =
+  # operators stay as they are:
+  if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
+  if k in {skType, skGenericParam} and sfAnon in s.flags: return
+  if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
+    checkStyle(info, s.name.s, k, s)
+
+template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
+  when defined(nimfix):
+    if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k)
+
+template styleCheckDef*(info: TLineInfo; s: PSym) =
+  styleCheckDef(info, s, s.kind)
+template styleCheckDef*(s: PSym) =
+  styleCheckDef(s.info, s, s.kind)
+
+proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
+  if info.fileIndex < 0: return
+  # we simply convert it to what it looks like in the definition
+  # for consistency
+  
+  # operators stay as they are:
+  if s.kind in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters:
+    return
+  if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return
+  let newName = s.name.s
+
+  replaceInFile(info, newName)
+  #if newName == "File": writeStackTrace()
+
+template styleCheckUse*(info: TLineInfo; s: PSym) =
+  when defined(nimfix):
+    if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s)
diff --git a/compiler/nimfix/prettybase.nim b/compiler/nimfix/prettybase.nim
new file mode 100644
index 000000000..5130d1863
--- /dev/null
+++ b/compiler/nimfix/prettybase.nim
@@ -0,0 +1,93 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import ast, msgs, strutils, idents, lexbase, streams
+from os import splitFile
+
+type
+  TSourceFile* = object
+    lines*: seq[string]
+    dirty*, isNimfixFile*: bool
+    fullpath*, newline*: string
+    fileIdx*: int32
+
+var
+  gSourceFiles*: seq[TSourceFile] = @[]
+
+proc loadFile*(info: TLineInfo) =
+  let i = info.fileIndex
+  if i >= gSourceFiles.len:
+    gSourceFiles.setLen(i+1)
+  if gSourceFiles[i].lines.isNil:
+    gSourceFiles[i].fileIdx = info.fileIndex
+    gSourceFiles[i].lines = @[]
+    let path = info.toFullPath
+    gSourceFiles[i].fullpath = path
+    gSourceFiles[i].isNimfixFile = path.splitFile.ext == ".nimfix"
+    # we want to die here for IOError:
+    for line in lines(path):
+      gSourceFiles[i].lines.add(line)
+    # extract line ending of the file:
+    var lex: BaseLexer
+    open(lex, newFileStream(path, fmRead))
+    var pos = lex.bufpos
+    while true:
+      case lex.buf[pos]
+      of '\c': 
+        gSourceFiles[i].newline = "\c\L"
+        break
+      of '\L', '\0':
+        gSourceFiles[i].newline = "\L"
+        break
+      else: discard
+      inc pos
+    close(lex)
+
+const
+  Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
+
+proc identLen*(line: string, start: int): int =
+  while start+result < line.len and line[start+result] in Letters:
+    inc result
+
+proc differ*(line: string, a, b: int, x: string): bool =
+  let y = line[a..b]
+  result = cmpIgnoreStyle(y, x) == 0 and y != x
+
+proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) =
+  loadFile(info)
+
+  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  var first = min(info.col.int, line.len)
+  if first < 0: return
+  #inc first, skipIgnoreCase(line, "proc ", first)
+  while first > 0 and line[first-1] in Letters: dec first
+  if first < 0: return
+  if line[first] == '`': inc first
+  
+  let last = first+identLen(line, first)-1
+  if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
+    var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
+    system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
+    gSourceFiles[info.fileIndex].dirty = true
+    #if newSym.s == "File": writeStackTrace()
+
+proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) =
+  replaceDeprecated(info, oldSym.name, newSym.name)
+
+proc replaceComment*(info: TLineInfo) =
+  loadFile(info)
+
+  let line = gSourceFiles[info.fileIndex].lines[info.line-1]
+  var first = info.col.int
+  if line[first] != '#': inc first
+
+  var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
+  system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x)
+  gSourceFiles[info.fileIndex].dirty = true
diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim
new file mode 100644
index 000000000..f5db5ca4f
--- /dev/null
+++ b/compiler/nimlexbase.nim
@@ -0,0 +1,169 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# 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 
+  llstream, strutils
+
+const 
+  Lrz* = ' '
+  Apo* = '\''
+  Tabulator* = '\x09'
+  ESC* = '\x1B'
+  CR* = '\x0D'
+  FF* = '\x0C'
+  LF* = '\x0A'
+  BEL* = '\x07'
+  BACKSPACE* = '\x08'
+  VT* = '\x0B'
+
+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* = {CR, LF}
+
+type 
+  TBaseLexer* = object of RootObj
+    bufpos*: int
+    buf*: cstring
+    bufLen*: int              # length of buffer in characters
+    stream*: PLLStream        # we read from this stream
+    lineNumber*: int          # the current line number
+                              # private data:
+    sentinel*: int
+    lineStart*: int           # index of last line start in buffer
+  
+
+proc openBaseLexer*(L: var TBaseLexer, inputstream: PLLStream, 
+                    bufLen: int = 8192)
+  # 8K is a reasonable buffer size
+proc closeBaseLexer*(L: var TBaseLexer)
+proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
+proc getColNumber*(L: TBaseLexer, pos: int): int
+proc handleCR*(L: var TBaseLexer, pos: int): int
+  # Call this if you scanned over CR in the buffer; it returns the
+  # position to continue the scanning from. `pos` must be the position
+  # of the CR.
+proc handleLF*(L: var TBaseLexer, pos: int): int
+  # Call this if you scanned over LF in the buffer; it returns the the
+  # position to continue the scanning from. `pos` must be the position
+  # of the LF.
+# implementation
+
+const 
+  chrSize = sizeof(char)
+
+proc closeBaseLexer(L: var TBaseLexer) = 
+  dealloc(L.buf)
+  llStreamClose(L.stream)
+
+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 = llStreamRead(L.stream, 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 = llStreamRead(L.stream, 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] == CR)
+  inc(L.lineNumber)
+  result = fillBaseLexer(L, pos)
+  if L.buf[result] == LF: 
+    result = fillBaseLexer(L, result)
+
+proc handleLF(L: var TBaseLexer, pos: int): int = 
+  assert(L.buf[pos] == LF)
+  inc(L.lineNumber)
+  result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
+  
+proc skipUTF8BOM(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 openBaseLexer(L: var TBaseLexer, inputstream: PLLStream, bufLen = 8192) = 
+  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.stream = inputstream
+  fillBuffer(L)
+  skipUTF8BOM(L)
+
+proc getColNumber(L: TBaseLexer, pos: int): int = 
+  result = abs(pos - L.lineStart)
+
+proc getCurrentLine(L: TBaseLexer, marker: bool = true): string = 
+  result = ""
+  var i = L.lineStart
+  while not (L.buf[i] in {CR, LF, EndOfFile}): 
+    add(result, L.buf[i])
+    inc(i)
+  result.add("\n")
+  if marker: 
+    result.add(spaces(getColNumber(L, L.bufpos)) & '^' & "\n")
diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim
new file mode 100644
index 000000000..aa7686d30
--- /dev/null
+++ b/compiler/nimsets.nim
@@ -0,0 +1,172 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# this unit handles Nim sets; it implements symbolic sets
+
+import 
+  ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
+
+proc toBitSet*(s: PNode, b: var TBitSet)
+  # this function is used for case statement checking:
+proc overlap*(a, b: PNode): bool
+proc inSet*(s: PNode, elem: PNode): bool
+proc someInSet*(s: PNode, a, b: PNode): bool
+proc emptyRange*(a, b: PNode): bool
+proc setHasRange*(s: PNode): bool
+  # returns true if set contains a range (needed by the code generator)
+  # these are used for constant folding:
+proc unionSets*(a, b: PNode): PNode
+proc diffSets*(a, b: PNode): PNode
+proc intersectSets*(a, b: PNode): PNode
+proc symdiffSets*(a, b: PNode): PNode
+proc containsSets*(a, b: PNode): bool
+proc equalSets*(a, b: PNode): bool
+proc cardSet*(s: PNode): BiggestInt
+# implementation
+
+proc inSet(s: PNode, elem: PNode): bool = 
+  if s.kind != nkCurly: 
+    internalError(s.info, "inSet")
+    return false
+  for i in countup(0, sonsLen(s) - 1): 
+    if s.sons[i].kind == nkRange: 
+      if leValue(s.sons[i].sons[0], elem) and
+          leValue(elem, s.sons[i].sons[1]): 
+        return true
+    else: 
+      if sameValue(s.sons[i], elem): 
+        return true
+  result = false
+
+proc overlap(a, b: PNode): bool =
+  if a.kind == nkRange:
+    if b.kind == nkRange:
+      # X..Y and C..D overlap iff (X <= D and C <= Y)
+      result = leValue(a.sons[0], b.sons[1]) and
+               leValue(b.sons[0], a.sons[1])
+    else:
+      result = leValue(a.sons[0], b) and leValue(b, a.sons[1])
+  else:
+    if b.kind == nkRange:
+      result = leValue(b.sons[0], a) and leValue(a, b.sons[1])
+    else:
+      result = sameValue(a, b)
+
+proc someInSet(s: PNode, a, b: PNode): bool = 
+  # checks if some element of a..b is in the set s
+  if s.kind != nkCurly:
+    internalError(s.info, "SomeInSet")
+    return false
+  for i in countup(0, sonsLen(s) - 1): 
+    if s.sons[i].kind == nkRange: 
+      if leValue(s.sons[i].sons[0], b) and leValue(b, s.sons[i].sons[1]) or
+          leValue(s.sons[i].sons[0], a) and leValue(a, s.sons[i].sons[1]): 
+        return true
+    else: 
+      # a <= elem <= b
+      if leValue(a, s.sons[i]) and leValue(s.sons[i], b): 
+        return true
+  result = false
+
+proc toBitSet(s: PNode, b: var TBitSet) = 
+  var first, j: BiggestInt
+  first = firstOrd(s.typ.sons[0])
+  bitSetInit(b, int(getSize(s.typ)))
+  for i in countup(0, sonsLen(s) - 1): 
+    if s.sons[i].kind == nkRange: 
+      j = getOrdValue(s.sons[i].sons[0])
+      while j <= getOrdValue(s.sons[i].sons[1]): 
+        bitSetIncl(b, j - first)
+        inc(j)
+    else: 
+      bitSetIncl(b, getOrdValue(s.sons[i]) - first)
+  
+proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode = 
+  var 
+    a, b, e, first: BiggestInt # a, b are interval borders
+    elemType: PType
+    n: PNode
+  elemType = settype.sons[0]
+  first = firstOrd(elemType)
+  result = newNodeI(nkCurly, info)
+  result.typ = settype
+  result.info = info
+  e = 0
+  while e < len(s) * ElemSize: 
+    if bitSetIn(s, e): 
+      a = e
+      b = e
+      while true: 
+        inc(b)
+        if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break 
+      dec(b)
+      if a == b: 
+        addSon(result, newIntTypeNode(nkIntLit, a + first, elemType))
+      else: 
+        n = newNodeI(nkRange, info)
+        n.typ = elemType
+        addSon(n, newIntTypeNode(nkIntLit, a + first, elemType))
+        addSon(n, newIntTypeNode(nkIntLit, b + first, elemType))
+        addSon(result, n)
+      e = b
+    inc(e)
+
+template nodeSetOp(a, b: PNode, op: expr) {.dirty.} = 
+  var x, y: TBitSet
+  toBitSet(a, x)
+  toBitSet(b, y)
+  op(x, y)
+  result = toTreeSet(x, a.typ, a.info)
+
+proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
+proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
+proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
+proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
+
+proc containsSets(a, b: PNode): bool = 
+  var x, y: TBitSet
+  toBitSet(a, x)
+  toBitSet(b, y)
+  result = bitSetContains(x, y)
+
+proc equalSets(a, b: PNode): bool = 
+  var x, y: TBitSet
+  toBitSet(a, x)
+  toBitSet(b, y)
+  result = bitSetEquals(x, y)
+
+proc complement*(a: PNode): PNode =
+  var x: TBitSet
+  toBitSet(a, x)
+  for i in countup(0, high(x)): x[i] = not x[i]
+  result = toTreeSet(x, a.typ, a.info)
+
+proc cardSet(s: PNode): BiggestInt = 
+  # here we can do better than converting it into a compact set
+  # we just count the elements directly
+  result = 0
+  for i in countup(0, sonsLen(s) - 1): 
+    if s.sons[i].kind == nkRange: 
+      result = result + getOrdValue(s.sons[i].sons[1]) -
+          getOrdValue(s.sons[i].sons[0]) + 1
+    else: 
+      inc(result)
+  
+proc setHasRange(s: PNode): bool = 
+  if s.kind != nkCurly:
+    internalError(s.info, "SetHasRange")
+    return false
+  for i in countup(0, sonsLen(s) - 1): 
+    if s.sons[i].kind == nkRange: 
+      return true
+  result = false
+
+proc emptyRange(a, b: PNode): bool = 
+  result = not leValue(a, b)  # a > b iff not (a <= b)
+  
diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim
new file mode 100644
index 000000000..2c785d118
--- /dev/null
+++ b/compiler/nimsuggest/nimsuggest.nim
@@ -0,0 +1,336 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nimsuggest is a tool that helps to give editors IDE like capabilities.
+
+import strutils, os, parseopt, parseutils, sequtils, net
+# Do NOT import suggest. It will lead to wierd bugs with
+# suggestionResultHook, because suggest.nim is included by sigmatch.
+# So we import that one instead.
+import options, commands, modules, sem, passes, passaux, msgs, nimconf,
+  extccomp, condsyms, lists, net, rdstdin, sexp, sigmatch, ast
+
+when defined(windows):
+  import winlean
+else:
+  import posix
+
+const Usage = """
+Nimsuggest - Tool to give every editor IDE like capabilities for Nim
+Usage:
+  nimsuggest [options] projectfile.nim
+
+Options:
+  --port:PORT             port, by default 6000
+  --address:HOST          binds to that address, by default ""
+  --stdin                 read commands from stdin and write results to
+                          stdout instead of using sockets
+  --epc                   use emacs epc mode
+
+The server then listens to the connection and takes line-based commands.
+
+In addition, all command line options of Nim that do not affect code generation
+are supported.
+"""
+type
+  Mode = enum mstdin, mtcp, mepc
+
+var
+  gPort = 6000.Port
+  gAddress = ""
+  gMode: Mode
+
+const
+  seps = {':', ';', ' ', '\t'}
+  Help = "usage: sug|con|def|use file.nim[;dirtyfile.nim]:line:col\n"&
+         "type 'quit' to quit\n" &
+         "type 'debug' to toggle debug mode on/off\n" &
+         "type 'terse' to toggle terse mode on/off"
+
+type
+  EUnexpectedCommand = object of Exception
+
+proc parseQuoted(cmd: string; outp: var string; start: int): int =
+  var i = start
+  i += skipWhitespace(cmd, i)
+  if cmd[i] == '"':
+    i += parseUntil(cmd, outp, '"', i+1)+2
+  else:
+    i += parseUntil(cmd, outp, seps, i)
+  result = i
+
+proc sexp(s: IdeCmd): SexpNode = sexp($s)
+
+proc sexp(s: TSymKind): SexpNode = sexp($s)
+
+proc sexp(s: Suggest): SexpNode =
+  # If you change the oder here, make sure to change it over in
+  # nim-mode.el too.
+  result = convertSexp([
+    s.section,
+    s.symkind,
+    s.qualifiedPath.map(newSString),
+    s.filePath,
+    s.forth,
+    s.line,
+    s.column,
+    s.doc
+  ])
+
+proc sexp(s: seq[Suggest]): SexpNode =
+  result = newSList()
+  for sug in s:
+    result.add(sexp(sug))
+
+proc listEPC(): SexpNode =
+  let
+    argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
+    docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
+  result = newSList()
+  for command in ["sug", "con", "def", "use"]:
+    let
+      cmd = sexp(command)
+      methodDesc = newSList()
+    methodDesc.add(cmd)
+    methodDesc.add(argspecs)
+    methodDesc.add(docstring)
+    result.add(methodDesc)
+
+proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int) =
+  gIdeCmd = cmd
+  if cmd == ideUse:
+    modules.resetAllModules()
+  var isKnownFile = true
+  let dirtyIdx = file.fileInfoIdx(isKnownFile)
+
+  if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
+  else: msgs.setDirtyFile(dirtyIdx, nil)
+
+  resetModule dirtyIdx
+  if dirtyIdx != gProjectMainIdx:
+    resetModule gProjectMainIdx
+
+  gTrackPos = newLineInfo(dirtyIdx, line, col)
+  gErrorCounter = 0
+  if not isKnownFile:
+    compileProject()
+  compileProject(dirtyIdx)
+
+proc executeEPC(cmd: IdeCmd, args: SexpNode) =
+  let
+    file = args[0].getStr
+    line = args[1].getNum
+    column = args[2].getNum
+  var dirtyfile = ""
+  if len(args) > 3:
+    dirtyfile = args[3].getStr(nil)
+  execute(cmd, file, dirtyfile, int(line), int(column))
+
+proc returnEPC(socket: var Socket, uid: BiggestInt, s: SexpNode, return_symbol = "return") =
+  let response = $convertSexp([newSSymbol(return_symbol), uid, s])
+  socket.send(toHex(len(response), 6))
+  socket.send(response)
+
+proc connectToNextFreePort(server: Socket, host: string, start = 30000): int =
+  result = start
+  while true:
+    try:
+      server.bindaddr(Port(result), host)
+      return
+    except OsError:
+      when defined(windows):
+        let checkFor = WSAEADDRINUSE.OSErrorCode
+      else:
+        let checkFor = EADDRINUSE.OSErrorCode
+      if osLastError() != checkFor:
+        raise getCurrentException()
+      else:
+        result += 1
+
+proc parseCmdLine(cmd: string) =
+  template toggle(sw) =
+    if sw in gGlobalOptions:
+      excl(gGlobalOptions, sw)
+    else:
+      incl(gGlobalOptions, sw)
+    return
+
+  template err() =
+    echo Help
+    return
+
+  var opc = ""
+  var i = parseIdent(cmd, opc, 0)
+  case opc.normalize
+  of "sug": gIdeCmd = ideSug
+  of "con": gIdeCmd = ideCon
+  of "def": gIdeCmd = ideDef
+  of "use": gIdeCmd = ideUse
+  of "quit": quit()
+  of "debug": toggle optIdeDebug
+  of "terse": toggle optIdeTerse
+  else: err()
+  var dirtyfile = ""
+  var orig = ""
+  i = parseQuoted(cmd, orig, i)
+  if cmd[i] == ';':
+    i = parseQuoted(cmd, dirtyfile, i+1)
+  i += skipWhile(cmd, seps, i)
+  var line = -1
+  var col = 0
+  i += parseInt(cmd, line, i)
+  i += skipWhile(cmd, seps, i)
+  i += parseInt(cmd, col, i)
+
+  execute(gIdeCmd, orig, dirtyfile, line, col-1)
+
+proc serve() =
+  case gMode:
+  of mstdin:
+    echo Help
+    var line = ""
+    while readLineFromStdin("> ", line):
+      parseCmdLine line
+      echo ""
+      flushFile(stdout)
+  of mtcp:
+    var server = newSocket()
+    server.bindAddr(gPort, gAddress)
+    var inp = "".TaintedString
+    server.listen()
+
+    while true:
+      var stdoutSocket = newSocket()
+      msgs.writelnHook = proc (line: string) =
+        stdoutSocket.send(line & "\c\L")
+
+      accept(server, stdoutSocket)
+
+      stdoutSocket.readLine(inp)
+      parseCmdLine inp.string
+
+      stdoutSocket.send("\c\L")
+      stdoutSocket.close()
+  of mepc:
+    var server = newSocket()
+    let port = connectToNextFreePort(server, "localhost")
+    var inp = "".TaintedString
+    server.listen()
+    echo(port)
+    var client = newSocket()
+    # Wait for connection
+    accept(server, client)
+    while true:
+      var sizeHex = ""
+      if client.recv(sizeHex, 6) != 6:
+        raise newException(ValueError, "didn't get all the hexbytes")
+      var size = 0
+      if parseHex(sizeHex, size) == 0:
+        raise newException(ValueError, "invalid size hex: " & $sizeHex)
+      var messageBuffer = ""
+      if client.recv(messageBuffer, size) != size:
+        raise newException(ValueError, "didn't get all the bytes")
+      let
+        message = parseSexp($messageBuffer)
+        messageType = message[0].getSymbol
+      case messageType:
+      of "call":
+        var results: seq[Suggest] = @[]
+        suggestionResultHook = proc (s: Suggest) =
+          results.add(s)
+
+        let
+          uid = message[1].getNum
+          cmd = parseIdeCmd(message[2].getSymbol)
+          args = message[3]
+        executeEPC(cmd, args)
+        returnEPC(client, uid, sexp(results))
+      of "return":
+        raise newException(EUnexpectedCommand, "no return expected")
+      of "return-error":
+        raise newException(EUnexpectedCommand, "no return expected")
+      of "epc-error":
+        stderr.writeln("recieved epc error: " & $messageBuffer)
+        raise newException(IOError, "epc error")
+      of "methods":
+        returnEPC(client, message[1].getNum, listEPC())
+      else:
+        raise newException(EUnexpectedCommand, "unexpected call: " & messageType)
+
+proc mainCommand =
+  registerPass verbosePass
+  registerPass semPass
+  gCmd = cmdIdeTools
+  incl gGlobalOptions, optCaasEnabled
+  isServing = true
+  wantMainModule()
+  appendStr(searchPaths, options.libpath)
+  if gProjectFull.len != 0:
+    # current path is always looked first for modules
+    prependStr(searchPaths, gProjectPath)
+
+  # do not stop after the first error:
+  msgs.gErrorMax = high(int)
+  compileProject()
+  serve()
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
+  var p = parseopt.initOptParser(cmd)
+  while true: 
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break 
+    of cmdLongoption, cmdShortOption: 
+      case p.key.normalize
+      of "port":
+        gPort = parseInt(p.val).Port
+        gMode = mtcp
+      of "address":
+        gAddress = p.val
+        gMode = mtcp
+      of "stdin": gMode = mstdin
+      of "epc":
+        gMode = mepc
+        gVerbosity = 0          # Port number gotta be first.
+      else: processSwitch(pass, p)
+    of cmdArgument:
+      options.gProjectName = unixToNativePath(p.key)
+      # if processArgument(pass, p, argsCount): break
+
+proc handleCmdLine() =
+  if paramCount() == 0:
+    stdout.writeln(Usage)
+  else:
+    processCmdLine(passCmd1, "")
+    if gProjectName != "":
+      try:
+        gProjectFull = canonicalizePath(gProjectName)
+      except OSError:
+        gProjectFull = gProjectName
+      var p = splitFile(gProjectFull)
+      gProjectPath = p.dir
+      gProjectName = p.name
+    else:
+      gProjectPath = getCurrentDir()
+    loadConfigs(DefaultConfig) # load all config files
+    # now process command line arguments again, because some options in the
+    # command line can overwite the config file's settings
+    extccomp.initVars()
+    processCmdLine(passCmd2, "")
+    mainCommand()
+
+when false:
+  proc quitCalled() {.noconv.} =
+    writeStackTrace()
+
+  addQuitProc(quitCalled)
+
+condsyms.initDefines()
+defineSymbol "nimsuggest"
+handleCmdline()
diff --git a/compiler/nimsuggest/nimsuggest.nim.cfg b/compiler/nimsuggest/nimsuggest.nim.cfg
new file mode 100644
index 000000000..acca17396
--- /dev/null
+++ b/compiler/nimsuggest/nimsuggest.nim.cfg
@@ -0,0 +1,17 @@
+# Special configuration file for the Nim project
+
+gc:markAndSweep
+
+hint[XDeclaredButNotUsed]:off
+path:"$projectPath/../.."
+
+path:"$lib/packages/docutils"
+path:"../../compiler"
+
+define:useStdoutAsStdmsg
+define:nimsuggest
+
+cs:partial
+#define:useNodeIds
+define:booting
+#define:noDocgen
diff --git a/compiler/nodejs.nim b/compiler/nodejs.nim
new file mode 100644
index 000000000..e2b79df19
--- /dev/null
+++ b/compiler/nodejs.nim
@@ -0,0 +1,6 @@
+import os
+
+proc findNodeJs*(): string =
+  result = findExe("nodejs")
+  if result == "":
+    result = findExe("node")
diff --git a/compiler/nversion.nim b/compiler/nversion.nim
new file mode 100644
index 000000000..4dea62876
--- /dev/null
+++ b/compiler/nversion.nim
@@ -0,0 +1,17 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module contains Nim's version. It is the only place where it needs
+# to be changed.
+
+const 
+  MaxSetElements* = 1 shl 16  # (2^16) to support unicode character sets?
+  VersionAsString* = system.NimVersion
+  RodFileVersion* = "1215"       # modify this if the rod-format changes!
+
diff --git a/compiler/options.nim b/compiler/options.nim
new file mode 100644
index 000000000..b3060a180
--- /dev/null
+++ b/compiler/options.nim
@@ -0,0 +1,413 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  os, lists, strutils, strtabs, osproc, sets
+
+const
+  hasTinyCBackend* = defined(tinyc)
+  useEffectSystem* = true
+  hasFFI* = defined(useFFI)
+  newScopeForIf* = true
+  useCaas* = not defined(noCaas)
+  noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
+
+type                          # please make sure we have under 32 options
+                              # (improves code efficiency a lot!)
+  TOption* = enum             # **keep binary compatible**
+    optNone, optObjCheck, optFieldCheck, optRangeCheck, optBoundsCheck,
+    optOverflowCheck, optNilCheck,
+    optNaNCheck, optInfCheck,
+    optAssert, optLineDir, optWarns, optHints,
+    optOptimizeSpeed, optOptimizeSize, optStackTrace, # stack tracing support
+    optLineTrace,             # line tracing support (includes stack tracing)
+    optEndb,                  # embedded debugger
+    optByRef,                 # use pass by ref for objects
+                              # (for interfacing with C)
+    optProfiler,              # profiler turned on
+    optImplicitStatic,        # optimization: implicit at compile time
+                              # evaluation
+    optPatterns               # en/disable pattern matching
+
+  TOptions* = set[TOption]
+  TGlobalOption* = enum       # **keep binary compatible**
+    gloptNone, optForceFullMake, optDeadCodeElim,
+    optListCmd, optCompileOnly, optNoLinking,
+    optSafeCode,              # only allow safe code
+    optCDebug,                # turn on debugging information
+    optGenDynLib,             # generate a dynamic library
+    optGenStaticLib,          # generate a static library
+    optGenGuiApp,             # generate a GUI application
+    optGenScript,             # generate a script file to compile the *.c files
+    optGenMapping,            # generate a mapping file
+    optRun,                   # run the compiled project
+    optSymbolFiles,           # use symbol files for speeding up compilation
+    optCaasEnabled            # compiler-as-a-service is running
+    optSkipConfigFile,        # skip the general config file
+    optSkipProjConfigFile,    # skip the project's config file
+    optSkipUserConfigFile,    # skip the users's config file
+    optSkipParentConfigFiles, # skip parent dir's config files
+    optNoMain,                # do not generate a "main" proc
+    optThreads,               # support for multi-threading
+    optStdout,                # output to stdout
+    optThreadAnalysis,        # thread analysis pass
+    optTaintMode,             # taint mode turned on
+    optTlsEmulation,          # thread var emulation turned on
+    optGenIndex               # generate index file for documentation;
+    optEmbedOrigSrc           # embed the original source in the generated code
+                              # also: generate header file
+    optIdeDebug               # idetools: debug mode
+    optIdeTerse               # idetools: use terse descriptions
+  TGlobalOptions* = set[TGlobalOption]
+  TCommands* = enum           # Nim's commands
+                              # **keep binary compatible**
+    cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
+    cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
+    cmdGenDepend, cmdDump,
+    cmdCheck,                 # semantic checking for whole project
+    cmdParse,                 # parse a single file (for debugging)
+    cmdScan,                  # scan a single file (for debugging)
+    cmdIdeTools,              # ide tools
+    cmdDef,                   # def feature (find definition for IDEs)
+    cmdRst2html,              # convert a reStructuredText file to HTML
+    cmdRst2tex,               # convert a reStructuredText file to TeX
+    cmdInteractive,           # start interactive session
+    cmdRun                    # run the project via TCC backend
+  TStringSeq* = seq[string]
+  TGCMode* = enum             # the selected GC
+    gcNone, gcBoehm, gcMarkAndSweep, gcRefc, gcV2, gcGenerational
+
+  IdeCmd* = enum
+    ideNone, ideSug, ideCon, ideDef, ideUse
+
+var
+  gIdeCmd*: IdeCmd
+
+const
+  ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
+    optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck}
+
+var
+  gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
+                         optBoundsCheck, optOverflowCheck, optAssert, optWarns,
+                         optHints, optStackTrace, optLineTrace,
+                         optPatterns, optNilCheck}
+  gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
+  gExitcode*: int8
+  gCmd*: TCommands = cmdNone  # the command
+  gSelectedGC* = gcRefc       # the selected GC
+  searchPaths*, lazyPaths*: TLinkedList
+  outFile*: string = ""
+  docSeeSrcUrl*: string = ""  # if empty, no seeSrc will be generated. \
+  # The string uses the formatting variables `path` and `line`.
+  headerFile*: string = ""
+  gVerbosity* = 1             # how verbose the compiler is
+  gNumberOfProcessors*: int   # number of processors
+  gWholeProject*: bool        # for 'doc2': output any dependency
+  gEvalExpr* = ""             # expression for idetools --eval
+  gLastCmdTime*: float        # when caas is enabled, we measure each command
+  gListFullPaths*: bool
+  isServing*: bool = false
+  gNoNimblePath* = false
+  gExperimentalMode*: bool
+
+proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
+proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
+
+template compilationCachePresent*: expr =
+  {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
+
+template optPreserveOrigSource*: expr =
+  optEmbedOrigSrc in gGlobalOptions
+
+template optPrintSurroundingSrc*: expr =
+  gVerbosity >= 2
+
+const
+  genSubDir* = "nimcache"
+  NimExt* = "nim"
+  RodExt* = "rod"
+  HtmlExt* = "html"
+  JsonExt* = "json"
+  TexExt* = "tex"
+  IniExt* = "ini"
+  DefaultConfig* = "nim.cfg"
+  DocConfig* = "nimdoc.cfg"
+  DocTexConfig* = "nimdoc.tex.cfg"
+
+# additional configuration variables:
+var
+  gConfigVars* = newStringTable(modeStyleInsensitive)
+  gDllOverrides = newStringTable(modeCaseInsensitive)
+  libpath* = ""
+  gProjectName* = "" # holds a name like 'nimrod'
+  gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
+  gProjectFull* = "" # projectPath/projectName
+  gProjectIsStdin* = false # whether we're compiling from stdin
+  gProjectMainIdx*: int32 # the canonical path id of the main module
+  nimcacheDir* = ""
+  command* = "" # the main command (e.g. cc, check, scan, etc)
+  commandArgs*: seq[string] = @[] # any arguments after the main command
+  gKeepComments*: bool = true # whether the parser needs to keep comments
+  implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
+  implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
+
+const oKeepVariableNames* = true
+
+proc mainCommandArg*: string =
+  ## This is intended for commands like check or parse
+  ## which will work on the main project file unless
+  ## explicitly given a specific file argument
+  if commandArgs.len > 0:
+    result = commandArgs[0]
+  else:
+    result = gProjectName
+
+proc existsConfigVar*(key: string): bool =
+  result = hasKey(gConfigVars, key)
+
+proc getConfigVar*(key: string): string =
+  result = gConfigVars[key]
+
+proc setConfigVar*(key, val: string) =
+  gConfigVars[key] = val
+
+proc getOutFile*(filename, ext: string): string =
+  if options.outFile != "": result = options.outFile
+  else: result = changeFileExt(filename, ext)
+
+proc getPrefixDir*(): string =
+  ## gets the application directory
+  result = splitPath(getAppDir()).head
+
+proc canonicalizePath*(path: string): string =
+  when not FileSystemCaseSensitive: result = path.expandFilename.toLower
+  else: result = path.expandFilename
+
+proc shortenDir*(dir: string): string =
+  ## returns the interesting part of a dir
+  var prefix = getPrefixDir() & DirSep
+  if startsWith(dir, prefix):
+    return substr(dir, len(prefix))
+  prefix = gProjectPath & DirSep
+  if startsWith(dir, prefix):
+    return substr(dir, len(prefix))
+  result = dir
+
+proc removeTrailingDirSep*(path: string): string =
+  if (len(path) > 0) and (path[len(path) - 1] == DirSep):
+    result = substr(path, 0, len(path) - 2)
+  else:
+    result = path
+
+proc getGeneratedPath: string =
+  result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
+                                                         genSubDir
+
+template newPackageCache(): expr =
+  newStringTable(when FileSystemCaseSensitive:
+                   modeCaseInsensitive
+                 else:
+                   modeCaseSensitive)
+
+var packageCache = newPackageCache()
+
+proc resetPackageCache*() = packageCache = newPackageCache()
+
+iterator myParentDirs(p: string): string =
+  # XXX os's parentDirs is stupid (multiple yields) and triggers an old bug...
+  var current = p
+  while true:
+    current = current.parentDir
+    if current.len == 0: break
+    yield current
+
+proc getPackageName*(path: string): string =
+  var parents = 0
+  block packageSearch:
+    for d in myParentDirs(path):
+      if packageCache.hasKey(d):
+        #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
+        return packageCache[d]
+      inc parents
+      for file in walkFiles(d / "*.nimble"):
+        result = file.splitFile.name
+        break packageSearch
+      for file in walkFiles(d / "*.babel"):
+        result = file.splitFile.name
+        break packageSearch
+  # we also store if we didn't find anything:
+  if result.isNil: result = ""
+  for d in myParentDirs(path):
+    #echo "set cache ", d, " |", result, "|", parents
+    packageCache[d] = result
+    dec parents
+    if parents <= 0: break
+
+proc withPackageName*(path: string): string =
+  let x = path.getPackageName
+  if x.len == 0:
+    result = path
+  else:
+    let (p, file, ext) = path.splitFile
+    result = (p / (x & '_' & file)) & ext
+
+proc toGeneratedFile*(path, ext: string): string =
+  ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
+  var (head, tail) = splitPath(path)
+  #if len(head) > 0: head = shortenDir(head & dirSep)
+  result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)])
+  #echo "toGeneratedFile(", path, ", ", ext, ") = ", result
+
+when noTimeMachine:
+  var alreadyExcludedDirs = initSet[string]()
+  proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
+    ## Calls a macosx command on the directory to exclude it from backups.
+    ##
+    ## The macosx tmutil command is invoked to mark the specified path as an
+    ## item to be excluded from time machine backups. If a path already exists
+    ## with files before excluding it, newer files won't be added to the
+    ## directory, but previous files won't be removed from the backup until the
+    ## user deletes that directory.
+    ##
+    ## The whole proc is optional and will ignore all kinds of errors. The only
+    ## way to be sure that it works is to call ``tmutil isexcluded path``.
+    if alreadyExcludedDirs.contains(dir): return
+    alreadyExcludedDirs.incl(dir)
+    try:
+      var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
+      discard p.waitForExit
+      p.close
+    except Exception:
+      discard
+
+proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
+  var (head, tail) = splitPath(f)
+  #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
+  var subdir = getGeneratedPath() # / head
+  if createSubDir:
+    try:
+      createDir(subdir)
+      when noTimeMachine:
+       excludeDirFromTimeMachine(subdir)
+    except OSError:
+      writeln(stdout, "cannot create directory: " & subdir)
+      quit(1)
+  result = joinPath(subdir, tail)
+  #echo "completeGeneratedFilePath(", f, ") = ", result
+
+iterator iterSearchPath*(searchPaths: TLinkedList): string =
+  var it = PStrEntry(searchPaths.head)
+  while it != nil:
+    yield it.data
+    it = PStrEntry(it.next)
+
+proc rawFindFile(f: string): string =
+  for it in iterSearchPath(searchPaths):
+    result = joinPath(it, f)
+    if existsFile(result):
+      return result.canonicalizePath
+  result = ""
+
+proc rawFindFile2(f: string): string =
+  var it = PStrEntry(lazyPaths.head)
+  while it != nil:
+    result = joinPath(it.data, f)
+    if existsFile(result):
+      bringToFront(lazyPaths, it)
+      return result.canonicalizePath
+    it = PStrEntry(it.next)
+  result = ""
+
+proc findFile*(f: string): string {.procvar.} =
+  result = f.rawFindFile
+  if result.len == 0:
+    result = f.toLower.rawFindFile
+    if result.len == 0:
+      result = f.rawFindFile2
+      if result.len == 0:
+        result = f.toLower.rawFindFile2
+
+proc findModule*(modulename, currentModule: string): string =
+  # returns path to module
+  when defined(nimfix):
+    # '.nimfix' modules are preferred over '.nim' modules so that specialized
+    # versions can be kept for 'nimfix'.
+    block:
+      let m = addFileExt(modulename, "nimfix")
+      let currentPath = currentModule.splitFile.dir
+      result = currentPath / m
+      if not existsFile(result):
+        result = findFile(m)
+        if existsFile(result): return result
+  let m = addFileExt(modulename, NimExt)
+  let currentPath = currentModule.splitFile.dir
+  result = currentPath / m
+  if not existsFile(result):
+    result = findFile(m)
+
+proc libCandidates*(s: string, dest: var seq[string]) =
+  var le = strutils.find(s, '(')
+  var ri = strutils.find(s, ')', le+1)
+  if le >= 0 and ri > le:
+    var prefix = substr(s, 0, le - 1)
+    var suffix = substr(s, ri + 1)
+    for middle in split(substr(s, le + 1, ri - 1), '|'):
+      libCandidates(prefix & middle & suffix, dest)
+  else:
+    add(dest, s)
+
+proc canonDynlibName(s: string): string =
+  let start = if s.startsWith("lib"): 3 else: 0
+  let ende = strutils.find(s, {'(', ')', '.'})
+  if ende >= 0:
+    result = s.substr(start, ende-1)
+  else:
+    result = s.substr(start)
+
+proc inclDynlibOverride*(lib: string) =
+  gDllOverrides[lib.canonDynlibName] = "true"
+
+proc isDynlibOverride*(lib: string): bool =
+  result = gDllOverrides.hasKey(lib.canonDynlibName)
+
+proc binaryStrSearch*(x: openArray[string], y: string): int =
+  var a = 0
+  var b = len(x) - 1
+  while a <= b:
+    var mid = (a + b) div 2
+    var c = cmpIgnoreCase(x[mid], y)
+    if c < 0:
+      a = mid + 1
+    elif c > 0:
+      b = mid - 1
+    else:
+      return mid
+  result = - 1
+
+template nimdbg*: expr = c.module.fileIdx == gProjectMainIdx
+template cnimdbg*: expr = p.module.module.fileIdx == gProjectMainIdx
+template pnimdbg*: expr = p.lex.fileIdx == gProjectMainIdx
+template lnimdbg*: expr = L.fileIdx == gProjectMainIdx
+
+proc parseIdeCmd*(s: string): IdeCmd =
+  case s:
+  of "sug": ideSug
+  of "con": ideCon
+  of "def": ideDef
+  of "use": ideUse
+  else: ideNone
+
+proc `$`*(c: IdeCmd): string =
+  case c:
+  of ideSug: "sug"
+  of ideCon: "con"
+  of ideDef: "def"
+  of ideUse: "use"
+  of ideNone: "none"
diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim
new file mode 100644
index 000000000..b7fe269df
--- /dev/null
+++ b/compiler/parampatterns.nim
@@ -0,0 +1,277 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the pattern matching features for term rewriting
+## macro support.
+
+import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees
+
+# we precompile the pattern here for efficiency into some internal
+# stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
+# actually improves performance.
+type
+  TAliasRequest* = enum # first byte of the bytecode determines alias checking
+    aqNone = 1,         # no alias analysis requested
+    aqShouldAlias,      # with some other param
+    aqNoAlias           # request noalias
+  TOpcode = enum
+    ppEof = 1, # end of compiled pattern
+    ppOr,      # we could short-cut the evaluation for 'and' and 'or',
+    ppAnd,     # but currently we don't
+    ppNot,
+    ppSym,
+    ppAtom,
+    ppLit,
+    ppIdent,
+    ppCall,
+    ppSymKind,
+    ppNodeKind,
+    ppLValue,
+    ppLocal,
+    ppSideEffect,
+    ppNoSideEffect
+  TPatternCode = string
+
+const
+  MaxStackSize* = 64 ## max required stack size by the VM
+
+proc patternError(n: PNode) =
+  localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+
+proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
+  add(code, chr(ord(op)))
+
+proc whichAlias*(p: PSym): TAliasRequest =
+  if p.constraint != nil:
+    result = TAliasRequest(p.constraint.strVal[0].ord)
+  else:
+    result = aqNone
+
+proc compileConstraints(p: PNode, result: var TPatternCode) =
+  case p.kind
+  of nkCallKinds:
+    if p.sons[0].kind != nkIdent:
+      patternError(p.sons[0])
+      return
+    let op = p.sons[0].ident
+    if p.len == 3:
+      if op.s == "|" or op.id == ord(wOr):
+        compileConstraints(p.sons[1], result)
+        compileConstraints(p.sons[2], result)
+        result.add(ppOr)
+      elif op.s == "&" or op.id == ord(wAnd):
+        compileConstraints(p.sons[1], result)
+        compileConstraints(p.sons[2], result)
+        result.add(ppAnd)
+      else:
+        patternError(p)
+    elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)):
+      compileConstraints(p.sons[1], result)
+      result.add(ppNot)
+    else:
+      patternError(p)
+  of nkAccQuoted, nkPar:
+    if p.len == 1:
+      compileConstraints(p.sons[0], result)
+    else:
+      patternError(p)
+  of nkIdent:
+    let spec = p.ident.s.normalize
+    case spec
+    of "atom":  result.add(ppAtom)
+    of "lit":   result.add(ppLit)
+    of "sym":   result.add(ppSym)
+    of "ident": result.add(ppIdent)
+    of "call":  result.add(ppCall)
+    of "alias": result[0] = chr(aqShouldAlias.ord)
+    of "noalias": result[0] = chr(aqNoAlias.ord)
+    of "lvalue": result.add(ppLValue)
+    of "local": result.add(ppLocal)
+    of "sideeffect": result.add(ppSideEffect)
+    of "nosideeffect": result.add(ppNoSideEffect)
+    else:
+      # check all symkinds:
+      internalAssert int(high(TSymKind)) < 255
+      for i in low(TSymKind)..high(TSymKind):
+        if cmpIgnoreStyle(($i).substr(2), spec) == 0:
+          result.add(ppSymKind)
+          result.add(chr(i.ord))
+          return
+      # check all nodekinds:
+      internalAssert int(high(TNodeKind)) < 255
+      for i in low(TNodeKind)..high(TNodeKind):
+        if cmpIgnoreStyle($i, spec) == 0:
+          result.add(ppNodeKind)
+          result.add(chr(i.ord))
+          return
+      patternError(p)
+  else:
+    patternError(p)
+
+proc semNodeKindConstraints*(p: PNode): PNode =
+  ## does semantic checking for a node kind pattern and compiles it into an
+  ## efficient internal format.
+  assert p.kind == nkCurlyExpr
+  result = newNodeI(nkStrLit, p.info)
+  result.strVal = newStringOfCap(10)
+  result.strVal.add(chr(aqNone.ord))
+  if p.len >= 2:
+    for i in 1.. <p.len:
+      compileConstraints(p.sons[i], result.strVal)
+    if result.strVal.len > MaxStackSize-1:
+      internalError(p.info, "parameter pattern too complex")
+  else:
+    patternError(p)
+  result.strVal.add(ppEof)
+
+type
+  TSideEffectAnalysis* = enum
+    seUnknown, seSideEffect, seNoSideEffect
+
+proc checkForSideEffects*(n: PNode): TSideEffectAnalysis =
+  case n.kind
+  of nkCallKinds:
+    # only calls can produce side effects:
+    let op = n.sons[0]
+    if op.kind == nkSym and isRoutine(op.sym):
+      let s = op.sym
+      if sfSideEffect in s.flags:
+        return seSideEffect
+      # assume no side effect:
+      result = seNoSideEffect
+    elif tfNoSideEffect in op.typ.flags:
+      # indirect call without side effects:
+      result = seNoSideEffect
+    else:
+      # indirect call: assume side effect:
+      return seSideEffect
+    # we need to check n[0] too: (FwithSideEffectButReturnsProcWithout)(args)
+    for i in 0 .. <n.len:
+      let ret = checkForSideEffects(n.sons[i])
+      if ret == seSideEffect: return ret
+      elif ret == seUnknown and result == seNoSideEffect:
+        result = seUnknown
+  of nkNone..nkNilLit:
+    # an atom cannot produce a side effect:
+    result = seNoSideEffect
+  else:
+    # assume no side effect:
+    result = seNoSideEffect
+    for i in 0 .. <n.len:
+      let ret = checkForSideEffects(n.sons[i])
+      if ret == seSideEffect: return ret
+      elif ret == seUnknown and result == seNoSideEffect:
+        result = seUnknown
+
+type
+  TAssignableResult* = enum
+    arNone,                   # no l-value and no discriminant
+    arLValue,                 # is an l-value
+    arLocalLValue,            # is an l-value, but local var; must not escape
+                              # its stack frame!
+    arDiscriminant,           # is a discriminant
+    arStrange                 # it is a strange beast like 'typedesc[var T]'
+
+proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
+  ## 'owner' can be nil!
+  result = arNone
+  case n.kind
+  of nkSym:
+    # don't list 'skLet' here:
+    if n.sym.kind in {skVar, skResult, skTemp}:
+      if owner != nil and owner.id == n.sym.owner.id and
+          sfGlobal notin n.sym.flags:
+        result = arLocalLValue
+      else:
+        result = arLValue
+    elif n.sym.kind == skParam and n.sym.typ.kind == tyVar:
+      result = arLValue
+    elif n.sym.kind == skType:
+      let t = n.sym.typ.skipTypes({tyTypeDesc})
+      if t.kind == tyVar: result = arStrange
+  of nkDotExpr:
+    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
+        {tyVar, tyPtr, tyRef}:
+      result = arLValue
+    else:
+      result = isAssignable(owner, n.sons[0])
+    if result != arNone and sfDiscriminant in n.sons[1].sym.flags:
+      result = arDiscriminant
+  of nkBracketExpr:
+    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind in
+        {tyVar, tyPtr, tyRef}:
+      result = arLValue
+    else:
+      result = isAssignable(owner, n.sons[0])
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    # Object and tuple conversions are still addressable, so we skip them
+    # XXX why is 'tyOpenArray' allowed here?
+    if skipTypes(n.typ, abstractPtrs-{tyTypeDesc}).kind in
+        {tyOpenArray, tyTuple, tyObject}:
+      result = isAssignable(owner, n.sons[1])
+    elif compareTypes(n.typ, n.sons[1].typ, dcEqIgnoreDistinct):
+      # types that are equal modulo distinction preserve l-value:
+      result = isAssignable(owner, n.sons[1])
+  of nkHiddenDeref, nkDerefExpr, nkHiddenAddr:
+    result = arLValue
+  of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
+    result = isAssignable(owner, n.sons[0])
+  of nkCallKinds:
+    # builtin slice keeps lvalue-ness:
+    if getMagic(n) == mSlice: result = isAssignable(owner, n.sons[1])
+  else:
+    discard
+
+proc isLValue*(n: PNode): bool =
+  isAssignable(nil, n) in {arLValue, arLocalLValue, arStrange}
+
+proc matchNodeKinds*(p, n: PNode): bool =
+  # matches the parameter constraint 'p' against the concrete AST 'n'.
+  # Efficiency matters here.
+  var stack {.noinit.}: array[0..MaxStackSize, bool]
+  # empty patterns are true:
+  stack[0] = true
+  var sp = 1
+
+  template push(x: bool) =
+    stack[sp] = x
+    inc sp
+
+  let code = p.strVal
+  var pc = 1
+  while true:
+    case TOpcode(code[pc])
+    of ppEof: break
+    of ppOr:
+      stack[sp-2] = stack[sp-1] or stack[sp-2]
+      dec sp
+    of ppAnd:
+      stack[sp-2] = stack[sp-1] and stack[sp-2]
+      dec sp
+    of ppNot: stack[sp-1] = not stack[sp-1]
+    of ppSym: push n.kind == nkSym
+    of ppAtom: push isAtom(n)
+    of ppLit: push n.kind in {nkCharLit..nkNilLit}
+    of ppIdent: push n.kind == nkIdent
+    of ppCall: push n.kind in nkCallKinds
+    of ppSymKind:
+      let kind = TSymKind(code[pc+1])
+      push n.kind == nkSym and n.sym.kind == kind
+      inc pc
+    of ppNodeKind:
+      let kind = TNodeKind(code[pc+1])
+      push n.kind == kind
+      inc pc
+    of ppLValue: push isAssignable(nil, n) in {arLValue, arLocalLValue}
+    of ppLocal: push isAssignable(nil, n) == arLocalLValue
+    of ppSideEffect: push checkForSideEffects(n) == seSideEffect
+    of ppNoSideEffect: push checkForSideEffects(n) != seSideEffect
+    inc pc
+  result = stack[sp-1]
+
diff --git a/compiler/parser.nim b/compiler/parser.nim
new file mode 100644
index 000000000..0d2ba7cfc
--- /dev/null
+++ b/compiler/parser.nim
@@ -0,0 +1,2035 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the parser of the standard Nim syntax.
+# The parser strictly reflects the grammar ("doc/grammar.txt"); however
+# it uses several helper routines to keep the parser small. A special
+# efficient algorithm is used for the precedence levels. The parser here can
+# be seen as a refinement of the grammar, as it specifies how the AST is built
+# from the grammar and how comments belong to the AST.
+
+
+# In fact the grammar is generated from this file:
+when isMainModule:
+  import pegs
+  var outp = open("doc/grammar.txt", fmWrite)
+  for line in lines("compiler/parser.nim"):
+    if line =~ peg" \s* '#| ' {.*}":
+      outp.write matches[0], "\L"
+  outp.close
+
+import
+  llstream, lexer, idents, strutils, ast, astalgo, msgs
+
+type
+  TParser*{.final.} = object  # A TParser object represents a module that
+                              # is being parsed
+    currInd: int              # current indentation level
+    firstTok, strongSpaces: bool # Has the first token been read?
+                                 # Is strongSpaces on?
+    lex*: TLexer              # The lexer that is used for parsing
+    tok*: TToken              # The current token
+    inPragma: int             # Pragma level
+    inSemiStmtList: int
+
+proc parseAll*(p: var TParser): PNode
+proc closeParser*(p: var TParser)
+proc parseTopLevelStmt*(p: var TParser): PNode
+
+# helpers for the other parsers
+proc isOperator*(tok: TToken): bool
+proc getTok*(p: var TParser)
+proc parMessage*(p: TParser, msg: TMsgKind, arg: string = "")
+proc skipComment*(p: var TParser, node: PNode)
+proc newNodeP*(kind: TNodeKind, p: TParser): PNode
+proc newIntNodeP*(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode
+proc newFloatNodeP*(kind: TNodeKind, floatVal: BiggestFloat, p: TParser): PNode
+proc newStrNodeP*(kind: TNodeKind, strVal: string, p: TParser): PNode
+proc newIdentNodeP*(ident: PIdent, p: TParser): PNode
+proc expectIdentOrKeyw*(p: TParser)
+proc expectIdent*(p: TParser)
+proc parLineInfo*(p: TParser): TLineInfo
+proc eat*(p: var TParser, tokType: TTokType)
+proc skipInd*(p: var TParser)
+proc optPar*(p: var TParser)
+proc optInd*(p: var TParser, n: PNode)
+proc indAndComment*(p: var TParser, n: PNode)
+proc setBaseFlags*(n: PNode, base: TNumericalBase)
+proc parseSymbol*(p: var TParser, allowNil = false): PNode
+proc parseTry(p: var TParser; isExpr: bool): PNode
+proc parseCase(p: var TParser): PNode
+# implementation
+
+proc getTok(p: var TParser) =
+  ## Get the next token from the parser's lexer, and store it in the parser's
+  ## `tok` member.
+  rawGetTok(p.lex, p.tok)
+
+proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
+                 strongSpaces=false) =
+  ## Open a parser, using the given arguments to set up its internal state.
+  ##
+  initToken(p.tok)
+  openLexer(p.lex, fileIdx, inputStream)
+  getTok(p)                   # read the first token
+  p.firstTok = true
+  p.strongSpaces = strongSpaces
+
+proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
+                 strongSpaces=false) =
+  openParser(p, filename.fileInfoIdx, inputStream, strongSpaces)
+
+proc closeParser(p: var TParser) =
+  ## Close a parser, freeing up its resources.
+  closeLexer(p.lex)
+
+proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
+  ## Produce and emit the parser message `arg` to output.
+  lexMessageTok(p.lex, msg, p.tok, arg)
+
+proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
+  ## Produce and emit a parser message to output about the token `tok`
+  parMessage(p, msg, prettyTok(tok))
+
+template withInd(p: expr, body: stmt) {.immediate.} =
+  let oldInd = p.currInd
+  p.currInd = p.tok.indent
+  body
+  p.currInd = oldInd
+
+template realInd(p): bool = p.tok.indent > p.currInd
+template sameInd(p): bool = p.tok.indent == p.currInd
+template sameOrNoInd(p): bool = p.tok.indent == p.currInd or p.tok.indent < 0
+
+proc rawSkipComment(p: var TParser, node: PNode) =
+  if p.tok.tokType == tkComment:
+    if node != nil:
+      if node.comment == nil: node.comment = ""
+      if p.tok.literal == "[]":
+        node.flags.incl nfIsCursor
+        #echo "parser: "
+        #debug node
+      else:
+        add(node.comment, p.tok.literal)
+    else:
+      parMessage(p, errInternal, "skipComment")
+    getTok(p)
+
+proc skipComment(p: var TParser, node: PNode) =
+  if p.tok.indent < 0: rawSkipComment(p, node)
+
+proc skipInd(p: var TParser) =
+  if p.tok.indent >= 0:
+    if not realInd(p): parMessage(p, errInvalidIndentation)
+
+proc optPar(p: var TParser) =
+  if p.tok.indent >= 0:
+    if p.tok.indent < p.currInd: parMessage(p, errInvalidIndentation)
+
+proc optInd(p: var TParser, n: PNode) =
+  skipComment(p, n)
+  skipInd(p)
+
+proc getTokNoInd(p: var TParser) =
+  getTok(p)
+  if p.tok.indent >= 0: parMessage(p, errInvalidIndentation)
+
+proc expectIdentOrKeyw(p: TParser) =
+  if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
+    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+
+proc expectIdent(p: TParser) =
+  if p.tok.tokType != tkSymbol:
+    lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
+
+proc eat(p: var TParser, tokType: TTokType) =
+  ## Move the parser to the next token if the current token is of type
+  ## `tokType`, otherwise error.
+  if p.tok.tokType == tokType:
+    getTok(p)
+  else:
+    lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
+
+proc parLineInfo(p: TParser): TLineInfo =
+  ## Retrieve the line information associated with the parser's current state.
+  result = getLineInfo(p.lex, p.tok)
+
+proc indAndComment(p: var TParser, n: PNode) =
+  if p.tok.indent > p.currInd:
+    if p.tok.tokType == tkComment: rawSkipComment(p, n)
+    else: parMessage(p, errInvalidIndentation)
+  else:
+    skipComment(p, n)
+
+proc newNodeP(kind: TNodeKind, p: TParser): PNode =
+  result = newNodeI(kind, parLineInfo(p))
+
+proc newIntNodeP(kind: TNodeKind, intVal: BiggestInt, p: TParser): PNode =
+  result = newNodeP(kind, p)
+  result.intVal = intVal
+
+proc newFloatNodeP(kind: TNodeKind, floatVal: BiggestFloat,
+                   p: TParser): PNode =
+  result = newNodeP(kind, p)
+  result.floatVal = floatVal
+
+proc newStrNodeP(kind: TNodeKind, strVal: string, p: TParser): PNode =
+  result = newNodeP(kind, p)
+  result.strVal = strVal
+
+proc newIdentNodeP(ident: PIdent, p: TParser): PNode =
+  result = newNodeP(nkIdent, p)
+  result.ident = ident
+
+proc parseExpr(p: var TParser): PNode
+proc parseStmt(p: var TParser): PNode
+proc parseTypeDesc(p: var TParser): PNode
+proc parseDoBlocks(p: var TParser, call: PNode)
+proc parseParamList(p: var TParser, retColon = true): PNode
+
+proc isSigilLike(tok: TToken): bool {.inline.} =
+  result = tok.tokType == tkOpr and tok.ident.s[0] == '@'
+
+proc isRightAssociative(tok: TToken): bool {.inline.} =
+  ## Determines whether the token is right assocative.
+  result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
+  # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
+
+proc getPrecedence(tok: TToken, strongSpaces: bool): int =
+  ## Calculates the precedence of the given token.
+  template considerStrongSpaces(x): expr =
+    x + (if strongSpaces: 100 - tok.strongSpaceA.int*10 else: 0)
+
+  case tok.tokType
+  of tkOpr:
+    let L = tok.ident.s.len
+    let relevantChar = tok.ident.s[0]
+
+    # arrow like?
+    if L > 1 and tok.ident.s[L-1] == '>' and
+      tok.ident.s[L-2] in {'-', '~', '='}: return considerStrongSpaces(1)
+
+    template considerAsgn(value: expr) =
+      result = if tok.ident.s[L-1] == '=': 1 else: value
+
+    case relevantChar
+    of '$', '^': considerAsgn(10)
+    of '*', '%', '/', '\\': considerAsgn(9)
+    of '~': result = 8
+    of '+', '-', '|': considerAsgn(8)
+    of '&': considerAsgn(7)
+    of '=', '<', '>', '!': result = 5
+    of '.': considerAsgn(6)
+    of '?': result = 2
+    else: considerAsgn(2)
+  of tkDiv, tkMod, tkShl, tkShr: result = 9
+  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
+  of tkDotDot: result = 6
+  of tkAnd: result = 4
+  of tkOr, tkXor, tkPtr, tkRef: result = 3
+  else: return -10
+  result = considerStrongSpaces(result)
+
+proc isOperator(tok: TToken): bool =
+  ## Determines if the given token is an operator type token.
+  tok.tokType in {tkOpr, tkDiv, tkMod, tkShl, tkShr, tkIn, tkNotin, tkIs,
+                  tkIsnot, tkNot, tkOf, tkAs, tkDotDot, tkAnd, tkOr, tkXor}
+
+proc isUnary(p: TParser): bool =
+  ## Check if the current parser token is a unary operator
+  if p.tok.tokType in {tkOpr, tkDotDot} and
+     p.tok.strongSpaceB == 0 and
+     p.tok.strongSpaceA > 0:
+    # XXX change this after 0.10.4 is out
+    if p.strongSpaces:
+      result = true
+    else:
+      parMessage(p, warnDeprecated,
+        "will be parsed as unary operator; inconsistent spacing")
+
+proc checkBinary(p: TParser) {.inline.} =
+  ## Check if the current parser token is a binary operator.
+  # we don't check '..' here as that's too annoying
+  if p.strongSpaces and p.tok.tokType == tkOpr:
+    if p.tok.strongSpaceB > 0 and p.tok.strongSpaceA != p.tok.strongSpaceB:
+      parMessage(p, errGenerated,
+                 "Number of spaces around '$#' not consistent" %
+                 prettyTok(p.tok))
+    elif p.tok.strongSpaceA notin {0,1,2,4,8}:
+      parMessage(p, errGenerated, "Number of spaces must be 0,1,2,4 or 8")
+
+#| module = stmt ^* (';' / IND{=})
+#|
+#| comma = ',' COMMENT?
+#| semicolon = ';' COMMENT?
+#| colon = ':' COMMENT?
+#| colcom = ':' COMMENT?
+#|
+#| operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
+#|          | 'or' | 'xor' | 'and'
+#|          | 'is' | 'isnot' | 'in' | 'notin' | 'of'
+#|          | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
+#|
+#| prefixOperator = operator
+#|
+#| optInd = COMMENT?
+#| optPar = (IND{>} | IND{=})?
+#|
+#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
+#| arrowExpr = assignExpr (OP1 optInd assignExpr)*
+#| assignExpr = orExpr (OP2 optInd orExpr)*
+#| orExpr = andExpr (OP3 optInd andExpr)*
+#| andExpr = cmpExpr (OP4 optInd cmpExpr)*
+#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
+#| sliceExpr = ampExpr (OP6 optInd ampExpr)*
+#| ampExpr = plusExpr (OP7 optInd plusExpr)*
+#| plusExpr = mulExpr (OP8 optInd mulExpr)*
+#| mulExpr = dollarExpr (OP9 optInd dollarExpr)*
+#| dollarExpr = primary (OP10 optInd primary)*
+
+proc colcom(p: var TParser, n: PNode) =
+  eat(p, tkColon)
+  skipComment(p, n)
+
+proc parseSymbol(p: var TParser, allowNil = false): PNode =
+  #| symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
+  #|        | IDENT | 'addr' | 'type'
+  case p.tok.tokType
+  of tkSymbol, tkAddr, tkType:
+    result = newIdentNodeP(p.tok.ident, p)
+    getTok(p)
+  of tkAccent:
+    result = newNodeP(nkAccQuoted, p)
+    getTok(p)
+    while true:
+      case p.tok.tokType
+      of tkAccent:
+        if result.len == 0:
+          parMessage(p, errIdentifierExpected, p.tok)
+        break
+      of tkOpr, tkDot, tkDotDot, tkEquals, tkParLe..tkParDotRi:
+        var accm = ""
+        while p.tok.tokType in {tkOpr, tkDot, tkDotDot, tkEquals,
+                                tkParLe..tkParDotRi}:
+          accm.add(tokToStr(p.tok))
+          getTok(p)
+        result.add(newIdentNodeP(getIdent(accm), p))
+      of tokKeywordLow..tokKeywordHigh, tkSymbol, tkIntLit..tkCharLit:
+        result.add(newIdentNodeP(getIdent(tokToStr(p.tok)), p))
+        getTok(p)
+      else:
+        parMessage(p, errIdentifierExpected, p.tok)
+    eat(p, tkAccent)
+  else:
+    if allowNil and p.tok.tokType == tkNil:
+      result = newNodeP(nkNilLit, p)
+      getTok(p)
+    else:
+      parMessage(p, errIdentifierExpected, p.tok)
+      # BUGFIX: We must consume a token here to prevent endless loops!
+      # But: this really sucks for idetools and keywords, so we don't do it
+      # if it is a keyword:
+      if not isKeyword(p.tok.tokType): getTok(p)
+      result = ast.emptyNode
+
+proc indexExpr(p: var TParser): PNode =
+  #| indexExpr = expr
+  result = parseExpr(p)
+
+proc indexExprList(p: var TParser, first: PNode, k: TNodeKind,
+                   endToken: TTokType): PNode =
+  #| indexExprList = indexExpr ^+ comma
+  result = newNodeP(k, p)
+  addSon(result, first)
+  getTok(p)
+  optInd(p, result)
+  while p.tok.tokType notin {endToken, tkEof}:
+    var a = indexExpr(p)
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    skipComment(p, a)
+  optPar(p)
+  eat(p, endToken)
+
+proc colonOrEquals(p: var TParser, a: PNode): PNode =
+  if p.tok.tokType == tkColon:
+    result = newNodeP(nkExprColonExpr, p)
+    getTok(p)
+    #optInd(p, result)
+    addSon(result, a)
+    addSon(result, parseExpr(p))
+  elif p.tok.tokType == tkEquals:
+    result = newNodeP(nkExprEqExpr, p)
+    getTok(p)
+    #optInd(p, result)
+    addSon(result, a)
+    addSon(result, parseExpr(p))
+  else:
+    result = a
+
+proc exprColonEqExpr(p: var TParser): PNode =
+  #| exprColonEqExpr = expr (':'|'=' expr)?
+  var a = parseExpr(p)
+  result = colonOrEquals(p, a)
+
+proc exprList(p: var TParser, endTok: TTokType, result: PNode) =
+  #| exprList = expr ^+ comma
+  getTok(p)
+  optInd(p, result)
+  while (p.tok.tokType != endTok) and (p.tok.tokType != tkEof):
+    var a = parseExpr(p)
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, a)
+
+proc dotExpr(p: var TParser, a: PNode): PNode =
+  #| dotExpr = expr '.' optInd symbol
+  var info = p.parLineInfo
+  getTok(p)
+  result = newNodeI(nkDotExpr, info)
+  optInd(p, result)
+  addSon(result, a)
+  addSon(result, parseSymbol(p))
+
+proc qualifiedIdent(p: var TParser): PNode =
+  #| qualifiedIdent = symbol ('.' optInd symbol)?
+  result = parseSymbol(p)
+  if p.tok.tokType == tkDot: result = dotExpr(p, result)
+
+proc exprColonEqExprListAux(p: var TParser, endTok: TTokType, result: PNode) =
+  assert(endTok in {tkCurlyRi, tkCurlyDotRi, tkBracketRi, tkParRi})
+  getTok(p)
+  optInd(p, result)
+  while p.tok.tokType != endTok and p.tok.tokType != tkEof:
+    var a = exprColonEqExpr(p)
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    skipComment(p, a)
+  optPar(p)
+  eat(p, endTok)
+
+proc exprColonEqExprList(p: var TParser, kind: TNodeKind,
+                         endTok: TTokType): PNode =
+  #| exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
+  result = newNodeP(kind, p)
+  exprColonEqExprListAux(p, endTok, result)
+
+proc setOrTableConstr(p: var TParser): PNode =
+  #| setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
+  result = newNodeP(nkCurly, p)
+  getTok(p) # skip '{'
+  optInd(p, result)
+  if p.tok.tokType == tkColon:
+    getTok(p) # skip ':'
+    result.kind = nkTableConstr
+  else:
+    while p.tok.tokType notin {tkCurlyRi, tkEof}:
+      var a = exprColonEqExpr(p)
+      if a.kind == nkExprColonExpr: result.kind = nkTableConstr
+      addSon(result, a)
+      if p.tok.tokType != tkComma: break
+      getTok(p)
+      skipComment(p, a)
+  optPar(p)
+  eat(p, tkCurlyRi) # skip '}'
+
+proc parseCast(p: var TParser): PNode =
+  #| castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
+  result = newNodeP(nkCast, p)
+  getTok(p)
+  eat(p, tkBracketLe)
+  optInd(p, result)
+  addSon(result, parseTypeDesc(p))
+  optPar(p)
+  eat(p, tkBracketRi)
+  eat(p, tkParLe)
+  optInd(p, result)
+  addSon(result, parseExpr(p))
+  optPar(p)
+  eat(p, tkParRi)
+
+proc setBaseFlags(n: PNode, base: TNumericalBase) =
+  case base
+  of base10: discard
+  of base2: incl(n.flags, nfBase2)
+  of base8: incl(n.flags, nfBase8)
+  of base16: incl(n.flags, nfBase16)
+
+proc parseGStrLit(p: var TParser, a: PNode): PNode =
+  case p.tok.tokType
+  of tkGStrLit:
+    result = newNodeP(nkCallStrLit, p)
+    addSon(result, a)
+    addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
+    getTok(p)
+  of tkGTripleStrLit:
+    result = newNodeP(nkCallStrLit, p)
+    addSon(result, a)
+    addSon(result, newStrNodeP(nkTripleStrLit, p.tok.literal, p))
+    getTok(p)
+  else:
+    result = a
+
+type
+  TPrimaryMode = enum pmNormal, pmTypeDesc, pmTypeDef, pmSkipSuffix
+
+proc complexOrSimpleStmt(p: var TParser): PNode
+proc simpleExpr(p: var TParser, mode = pmNormal): PNode
+
+proc semiStmtList(p: var TParser, result: PNode) =
+  inc p.inSemiStmtList
+  result.add(complexOrSimpleStmt(p))
+  while p.tok.tokType == tkSemiColon:
+    getTok(p)
+    optInd(p, result)
+    result.add(complexOrSimpleStmt(p))
+  dec p.inSemiStmtList
+  result.kind = nkStmtListExpr
+
+proc parsePar(p: var TParser): PNode =
+  #| parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
+  #|         | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
+  #|         | 'when' | 'var' | 'mixin'
+  #| par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
+  #|                  | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
+  #|                             | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
+  #|         optPar ')'
+  #
+  # unfortunately it's ambiguous: (expr: expr) vs (exprStmt); however a
+  # leading ';' could be used to enforce a 'stmt' context ...
+  result = newNodeP(nkPar, p)
+  getTok(p)
+  optInd(p, result)
+  if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
+                       tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
+                       tkConst, tkLet, tkWhen, tkVar,
+                       tkMixin}:
+    # XXX 'bind' used to be an expression, so we exclude it here;
+    # tests/reject/tbind2 fails otherwise.
+    semiStmtList(p, result)
+  elif p.tok.tokType == tkSemiColon:
+    # '(;' enforces 'stmt' context:
+    getTok(p)
+    optInd(p, result)
+    semiStmtList(p, result)
+  elif p.tok.tokType != tkParRi:
+    var a = simpleExpr(p)
+    if p.tok.tokType == tkEquals:
+      # special case: allow assignments
+      getTok(p)
+      optInd(p, result)
+      let b = parseExpr(p)
+      let asgn = newNodeI(nkAsgn, a.info, 2)
+      asgn.sons[0] = a
+      asgn.sons[1] = b
+      result.add(asgn)
+      if p.tok.tokType == tkSemiColon:
+        semiStmtList(p, result)
+    elif p.tok.tokType == tkSemiColon:
+      # stmt context:
+      result.add(a)
+      semiStmtList(p, result)
+    else:
+      a = colonOrEquals(p, a)
+      result.add(a)
+      if p.tok.tokType == tkComma:
+        getTok(p)
+        skipComment(p, a)
+        while p.tok.tokType != tkParRi and p.tok.tokType != tkEof:
+          var a = exprColonEqExpr(p)
+          addSon(result, a)
+          if p.tok.tokType != tkComma: break
+          getTok(p)
+          skipComment(p, a)
+  optPar(p)
+  eat(p, tkParRi)
+
+proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
+  #| literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+  #|           | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
+  #|           | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+  #|           | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+  #|           | CHAR_LIT
+  #|           | NIL
+  #| generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
+  #| identOrLiteral = generalizedLit | symbol | literal
+  #|                | par | arrayConstr | setOrTableConstr
+  #|                | castExpr
+  #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
+  #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
+  case p.tok.tokType
+  of tkSymbol, tkType, tkAddr:
+    result = newIdentNodeP(p.tok.ident, p)
+    getTok(p)
+    result = parseGStrLit(p, result)
+  of tkAccent:
+    result = parseSymbol(p)       # literals
+  of tkIntLit:
+    result = newIntNodeP(nkIntLit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkInt8Lit:
+    result = newIntNodeP(nkInt8Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkInt16Lit:
+    result = newIntNodeP(nkInt16Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkInt32Lit:
+    result = newIntNodeP(nkInt32Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkInt64Lit:
+    result = newIntNodeP(nkInt64Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkUIntLit:
+    result = newIntNodeP(nkUIntLit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkUInt8Lit:
+    result = newIntNodeP(nkUInt8Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkUInt16Lit:
+    result = newIntNodeP(nkUInt16Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkUInt32Lit:
+    result = newIntNodeP(nkUInt32Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkUInt64Lit:
+    result = newIntNodeP(nkUInt64Lit, p.tok.iNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkFloatLit:
+    result = newFloatNodeP(nkFloatLit, p.tok.fNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkFloat32Lit:
+    result = newFloatNodeP(nkFloat32Lit, p.tok.fNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkFloat64Lit:
+    result = newFloatNodeP(nkFloat64Lit, p.tok.fNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkFloat128Lit:
+    result = newFloatNodeP(nkFloat128Lit, p.tok.fNumber, p)
+    setBaseFlags(result, p.tok.base)
+    getTok(p)
+  of tkStrLit:
+    result = newStrNodeP(nkStrLit, p.tok.literal, p)
+    getTok(p)
+  of tkRStrLit:
+    result = newStrNodeP(nkRStrLit, p.tok.literal, p)
+    getTok(p)
+  of tkTripleStrLit:
+    result = newStrNodeP(nkTripleStrLit, p.tok.literal, p)
+    getTok(p)
+  of tkCharLit:
+    result = newIntNodeP(nkCharLit, ord(p.tok.literal[0]), p)
+    getTok(p)
+  of tkNil:
+    result = newNodeP(nkNilLit, p)
+    getTok(p)
+  of tkParLe:
+    # () constructor
+    if mode in {pmTypeDesc, pmTypeDef}:
+      result = exprColonEqExprList(p, nkPar, tkParRi)
+    else:
+      result = parsePar(p)
+  of tkCurlyLe:
+    # {} constructor
+    result = setOrTableConstr(p)
+  of tkBracketLe:
+    # [] constructor
+    result = exprColonEqExprList(p, nkBracket, tkBracketRi)
+  of tkCast:
+    result = parseCast(p)
+  else:
+    parMessage(p, errExprExpected, p.tok)
+    getTok(p)  # we must consume a token here to prevend endless loops!
+    result = ast.emptyNode
+
+proc namedParams(p: var TParser, callee: PNode,
+                 kind: TNodeKind, endTok: TTokType): PNode =
+  let a = callee
+  result = newNodeP(kind, p)
+  addSon(result, a)
+  exprColonEqExprListAux(p, endTok, result)
+
+proc parseMacroColon(p: var TParser, x: PNode): PNode
+proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
+  #| primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
+  #|       | doBlocks
+  #|       | '.' optInd symbol generalizedLit?
+  #|       | '[' optInd indexExprList optPar ']'
+  #|       | '{' optInd indexExprList optPar '}'
+  #|       | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
+  result = r
+  while p.tok.indent < 0 or
+       (p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
+    case p.tok.tokType
+    of tkParLe:
+      if p.strongSpaces and p.tok.strongSpaceA > 0: break
+      result = namedParams(p, result, nkCall, tkParRi)
+      if result.len > 1 and result.sons[1].kind == nkExprColonExpr:
+        result.kind = nkObjConstr
+      else:
+        parseDoBlocks(p, result)
+    of tkDo:
+      var a = result
+      result = newNodeP(nkCall, p)
+      addSon(result, a)
+      parseDoBlocks(p, result)
+    of tkDot:
+      result = dotExpr(p, result)
+      result = parseGStrLit(p, result)
+    of tkBracketLe:
+      if p.strongSpaces and p.tok.strongSpaceA > 0: break
+      result = namedParams(p, result, nkBracketExpr, tkBracketRi)
+    of tkCurlyLe:
+      if p.strongSpaces and p.tok.strongSpaceA > 0: break
+      result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
+    of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast, tkAddr, tkType:
+      if p.inPragma == 0:
+        # actually parsing {.push hints:off.} as {.push(hints:off).} is a sweet
+        # solution, but pragmas.nim can't handle that
+        let a = result
+        result = newNodeP(nkCommand, p)
+        addSon(result, a)
+        when true:
+          addSon result, parseExpr(p)
+        else:
+          while p.tok.tokType != tkEof:
+            let x = parseExpr(p)
+            addSon(result, x)
+            if p.tok.tokType != tkComma: break
+            getTok(p)
+            optInd(p, x)
+          if p.tok.tokType == tkDo:
+            parseDoBlocks(p, result)
+          else:
+            result = parseMacroColon(p, result)
+      break
+    else:
+      break
+
+proc primary(p: var TParser, mode: TPrimaryMode): PNode
+proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode
+
+proc parseOperators(p: var TParser, headNode: PNode,
+                    limit: int, mode: TPrimaryMode): PNode =
+  result = headNode
+  # expand while operators have priorities higher than 'limit'
+  var opPrec = getPrecedence(p.tok, p.strongSpaces)
+  let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
+  # the operator itself must not start on a new line:
+  while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
+    checkBinary(p)
+    var leftAssoc = 1-ord(isRightAssociative(p.tok))
+    var a = newNodeP(nkInfix, p)
+    var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
+    getTok(p)
+    optInd(p, a)
+    # read sub-expression with higher priority:
+    var b = simpleExprAux(p, opPrec + leftAssoc, modeB)
+    addSon(a, opNode)
+    addSon(a, result)
+    addSon(a, b)
+    result = a
+    opPrec = getPrecedence(p.tok, p.strongSpaces)
+
+proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
+  result = primary(p, mode)
+  result = parseOperators(p, result, limit, mode)
+
+proc simpleExpr(p: var TParser, mode = pmNormal): PNode =
+  result = simpleExprAux(p, -1, mode)
+
+proc parseIfExpr(p: var TParser, kind: TNodeKind): PNode =
+  #| condExpr = expr colcom expr optInd
+  #|         ('elif' expr colcom expr optInd)*
+  #|          'else' colcom expr
+  #| ifExpr = 'if' condExpr
+  #| whenExpr = 'when' condExpr
+  result = newNodeP(kind, p)
+  while true:
+    getTok(p)                 # skip `if`, `elif`
+    var branch = newNodeP(nkElifExpr, p)
+    addSon(branch, parseExpr(p))
+    colcom(p, branch)
+    addSon(branch, parseExpr(p))
+    optInd(p, branch)
+    addSon(result, branch)
+    if p.tok.tokType != tkElif: break
+  var branch = newNodeP(nkElseExpr, p)
+  eat(p, tkElse)
+  colcom(p, branch)
+  addSon(branch, parseExpr(p))
+  addSon(result, branch)
+
+proc parsePragma(p: var TParser): PNode =
+  #| pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
+  result = newNodeP(nkPragma, p)
+  inc p.inPragma
+  getTok(p)
+  optInd(p, result)
+  while p.tok.tokType notin {tkCurlyDotRi, tkCurlyRi, tkEof}:
+    var a = exprColonEqExpr(p)
+    addSon(result, a)
+    if p.tok.tokType == tkComma:
+      getTok(p)
+      skipComment(p, a)
+  optPar(p)
+  if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
+  else: parMessage(p, errTokenExpected, ".}")
+  dec p.inPragma
+
+proc identVis(p: var TParser): PNode =
+  #| identVis = symbol opr?  # postfix position
+  var a = parseSymbol(p)
+  if p.tok.tokType == tkOpr:
+    result = newNodeP(nkPostfix, p)
+    addSon(result, newIdentNodeP(p.tok.ident, p))
+    addSon(result, a)
+    getTok(p)
+  else:
+    result = a
+
+proc identWithPragma(p: var TParser): PNode =
+  #| identWithPragma = identVis pragma?
+  var a = identVis(p)
+  if p.tok.tokType == tkCurlyDotLe:
+    result = newNodeP(nkPragmaExpr, p)
+    addSon(result, a)
+    addSon(result, parsePragma(p))
+  else:
+    result = a
+
+type
+  TDeclaredIdentFlag = enum
+    withPragma,               # identifier may have pragma
+    withBothOptional          # both ':' and '=' parts are optional
+  TDeclaredIdentFlags = set[TDeclaredIdentFlag]
+
+proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
+  #| declColonEquals = identWithPragma (comma identWithPragma)* comma?
+  #|                   (':' optInd typeDesc)? ('=' optInd expr)?
+  #| identColonEquals = ident (comma ident)* comma?
+  #|      (':' optInd typeDesc)? ('=' optInd expr)?)
+  var a: PNode
+  result = newNodeP(nkIdentDefs, p)
+  while true:
+    case p.tok.tokType
+    of tkSymbol, tkAccent:
+      if withPragma in flags: a = identWithPragma(p)
+      else: a = parseSymbol(p)
+      if a.kind == nkEmpty: return
+    else: break
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, a)
+  if p.tok.tokType == tkColon:
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseTypeDesc(p))
+  else:
+    addSon(result, ast.emptyNode)
+    if p.tok.tokType != tkEquals and withBothOptional notin flags:
+      parMessage(p, errColonOrEqualsExpected, p.tok)
+  if p.tok.tokType == tkEquals:
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseExpr(p))
+  else:
+    addSon(result, ast.emptyNode)
+
+proc parseTuple(p: var TParser, indentAllowed = false): PNode =
+  #| inlTupleDecl = 'tuple'
+  #|     [' optInd  (identColonEquals (comma/semicolon)?)*  optPar ']'
+  #| extTupleDecl = 'tuple'
+  #|     COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
+  #| tupleClass = 'tuple'
+  result = newNodeP(nkTupleTy, p)
+  getTok(p)
+  if p.tok.tokType == tkBracketLe:
+    getTok(p)
+    optInd(p, result)
+    while p.tok.tokType in {tkSymbol, tkAccent}:
+      var a = parseIdentColonEquals(p, {})
+      addSon(result, a)
+      if p.tok.tokType notin {tkComma, tkSemiColon}: break
+      getTok(p)
+      skipComment(p, a)
+    optPar(p)
+    eat(p, tkBracketRi)
+  elif indentAllowed:
+    skipComment(p, result)
+    if realInd(p):
+      withInd(p):
+        skipComment(p, result)
+        while true:
+          case p.tok.tokType
+          of tkSymbol, tkAccent:
+            var a = parseIdentColonEquals(p, {})
+            skipComment(p, a)
+            addSon(result, a)
+          of tkEof: break
+          else:
+            parMessage(p, errIdentifierExpected, p.tok)
+            break
+          if not sameInd(p): break
+  else:
+    result = newNodeP(nkTupleClassTy, p)
+
+proc parseParamList(p: var TParser, retColon = true): PNode =
+  #| paramList = '(' declColonEquals ^* (comma/semicolon) ')'
+  #| paramListArrow = paramList? ('->' optInd typeDesc)?
+  #| paramListColon = paramList? (':' optInd typeDesc)?
+  var a: PNode
+  result = newNodeP(nkFormalParams, p)
+  addSon(result, ast.emptyNode) # return type
+  let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
+  if hasParLe:
+    getTok(p)
+    optInd(p, result)
+    while true:
+      case p.tok.tokType
+      of tkSymbol, tkAccent:
+        a = parseIdentColonEquals(p, {withBothOptional, withPragma})
+      of tkParRi:
+        break
+      else:
+        parMessage(p, errTokenExpected, ")")
+        break
+      addSon(result, a)
+      if p.tok.tokType notin {tkComma, tkSemiColon}: break
+      getTok(p)
+      skipComment(p, a)
+    optPar(p)
+    eat(p, tkParRi)
+  let hasRet = if retColon: p.tok.tokType == tkColon
+               else: p.tok.tokType == tkOpr and identEq(p.tok.ident, "->")
+  if hasRet and p.tok.indent < 0:
+    getTok(p)
+    optInd(p, result)
+    result.sons[0] = parseTypeDesc(p)
+  elif not retColon and not hasParle:
+    # Mark as "not there" in order to mark for deprecation in the semantic pass:
+    result = ast.emptyNode
+
+proc optPragmas(p: var TParser): PNode =
+  if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
+    result = parsePragma(p)
+  else:
+    result = ast.emptyNode
+
+proc parseDoBlock(p: var TParser): PNode =
+  #| doBlock = 'do' paramListArrow pragmas? colcom stmt
+  let info = parLineInfo(p)
+  getTok(p)
+  let params = parseParamList(p, retColon=false)
+  let pragmas = optPragmas(p)
+  colcom(p, result)
+  result = newProcNode(nkDo, info, parseStmt(p),
+                       params = params,
+                       pragmas = pragmas)
+
+proc parseDoBlocks(p: var TParser, call: PNode) =
+  #| doBlocks = doBlock ^* IND{=}
+  if p.tok.tokType == tkDo:
+    addSon(call, parseDoBlock(p))
+    while sameInd(p) and p.tok.tokType == tkDo:
+      addSon(call, parseDoBlock(p))
+
+proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
+  #| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
+  # either a proc type or a anonymous proc
+  let info = parLineInfo(p)
+  getTok(p)
+  let hasSignature = p.tok.tokType in {tkParLe, tkColon} and p.tok.indent < 0
+  let params = parseParamList(p)
+  let pragmas = optPragmas(p)
+  if p.tok.tokType == tkEquals and isExpr:
+    getTok(p)
+    skipComment(p, result)
+    result = newProcNode(nkLambda, info, parseStmt(p),
+                         params = params,
+                         pragmas = pragmas)
+  else:
+    result = newNodeI(nkProcTy, info)
+    if hasSignature:
+      addSon(result, params)
+      addSon(result, pragmas)
+
+proc isExprStart(p: TParser): bool =
+  case p.tok.tokType
+  of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
+     tkProc, tkIterator, tkBind, tkAddr,
+     tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
+     tkTuple, tkObject, tkType, tkWhen, tkCase:
+    result = true
+  else: result = false
+
+proc parseSymbolList(p: var TParser, result: PNode, allowNil = false) =
+  while true:
+    var s = parseSymbol(p, allowNil)
+    if s.kind == nkEmpty: break
+    addSon(result, s)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, s)
+
+proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
+                       mode: TPrimaryMode): PNode =
+  #| distinct = 'distinct' optInd typeDesc
+  result = newNodeP(kind, p)
+  getTok(p)
+  optInd(p, result)
+  if not isOperator(p.tok) and isExprStart(p):
+    addSon(result, primary(p, mode))
+  if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}:
+    let nodeKind = if p.tok.tokType == tkWith: nkWith
+                   else: nkWithout
+    getTok(p)
+    let list = newNodeP(nodeKind, p)
+    result.addSon list
+    parseSymbolList(p, list, allowNil = true)
+
+proc parseExpr(p: var TParser): PNode =
+  #| expr = (ifExpr
+  #|       | whenExpr
+  #|       | caseExpr
+  #|       | tryExpr)
+  #|       / simpleExpr
+  case p.tok.tokType:
+  of tkIf: result = parseIfExpr(p, nkIfExpr)
+  of tkWhen: result = parseIfExpr(p, nkWhenExpr)
+  of tkCase: result = parseCase(p)
+  of tkTry: result = parseTry(p, isExpr=true)
+  else: result = simpleExpr(p)
+
+proc parseEnum(p: var TParser): PNode
+proc parseObject(p: var TParser): PNode
+proc parseTypeClass(p: var TParser): PNode
+
+proc primary(p: var TParser, mode: TPrimaryMode): PNode =
+  #| typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'tuple'
+  #|          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
+  #| primary = typeKeyw typeDescK
+  #|         /  prefixOperator* identOrLiteral primarySuffix*
+  #|         / 'static' primary
+  #|         / 'bind' primary
+  if isOperator(p.tok):
+    let isSigil = isSigilLike(p.tok)
+    result = newNodeP(nkPrefix, p)
+    var a = newIdentNodeP(p.tok.ident, p)
+    addSon(result, a)
+    getTok(p)
+    optInd(p, a)
+    if isSigil:
+      #XXX prefix operators
+      let baseInd = p.lex.currLineIndent
+      addSon(result, primary(p, pmSkipSuffix))
+      result = primarySuffix(p, result, baseInd)
+    else:
+      addSon(result, primary(p, pmNormal))
+    return
+
+  case p.tok.tokType:
+  of tkTuple: result = parseTuple(p, mode == pmTypeDef)
+  of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
+  of tkIterator:
+    when false:
+      if mode in {pmTypeDesc, pmTypeDef}:
+        result = parseProcExpr(p, false)
+        result.kind = nkIteratorTy
+      else:
+        # no anon iterators for now:
+        parMessage(p, errExprExpected, p.tok)
+        getTok(p)  # we must consume a token here to prevend endless loops!
+        result = ast.emptyNode
+    else:
+      result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
+      if result.kind == nkLambda: result.kind = nkIteratorDef
+      else: result.kind = nkIteratorTy
+  of tkEnum:
+    if mode == pmTypeDef:
+      result = parseEnum(p)
+    else:
+      result = newNodeP(nkEnumTy, p)
+      getTok(p)
+  of tkObject:
+    if mode == pmTypeDef:
+      result = parseObject(p)
+    else:
+      result = newNodeP(nkObjectTy, p)
+      getTok(p)
+  of tkGeneric, tkConcept:
+    if mode == pmTypeDef:
+      let wasGeneric = p.tok.tokType == tkGeneric
+      result = parseTypeClass(p)
+      # hack so that it's remembered and can be marked as deprecated in
+      # sem'check:
+      if wasGeneric: result.flags.incl nfBase2
+    else:
+      parMessage(p, errInvalidToken, p.tok)
+  of tkStatic:
+    let info = parLineInfo(p)
+    getTokNoInd(p)
+    let next = primary(p, pmNormal)
+    if next.kind == nkBracket and next.sonsLen == 1:
+      result = newNode(nkStaticTy, info, @[next.sons[0]])
+    else:
+      result = newNode(nkStaticExpr, info, @[next])
+  of tkBind:
+    result = newNodeP(nkBind, p)
+    getTok(p)
+    optInd(p, result)
+    addSon(result, primary(p, pmNormal))
+  of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
+  of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
+  of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
+  of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
+  else:
+    let baseInd = p.lex.currLineIndent
+    result = identOrLiteral(p, mode)
+    if mode != pmSkipSuffix:
+      result = primarySuffix(p, result, baseInd)
+
+proc parseTypeDesc(p: var TParser): PNode =
+  #| typeDesc = simpleExpr
+  result = simpleExpr(p, pmTypeDesc)
+
+proc parseTypeDefAux(p: var TParser): PNode =
+  #| typeDefAux = simpleExpr
+  #|            | 'concept' typeClass
+  result = simpleExpr(p, pmTypeDef)
+
+proc makeCall(n: PNode): PNode =
+  ## Creates a call if the given node isn't already a call.
+  if n.kind in nkCallKinds:
+    result = n
+  else:
+    result = newNodeI(nkCall, n.info)
+    result.add n
+
+proc parseMacroColon(p: var TParser, x: PNode): PNode =
+  #| macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
+  #|                        | IND{=} 'elif' expr ':' stmt
+  #|                        | IND{=} 'except' exprList ':' stmt
+  #|                        | IND{=} 'else' ':' stmt )*
+  result = x
+  if p.tok.tokType == tkColon and p.tok.indent < 0:
+    result = makeCall(result)
+    getTok(p)
+    skipComment(p, result)
+    let stmtList = newNodeP(nkStmtList, p)
+    if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
+      let body = parseStmt(p)
+      stmtList.add body
+      #addSon(result, makeStmtList(body))
+    while sameInd(p):
+      var b: PNode
+      case p.tok.tokType
+      of tkOf:
+        b = newNodeP(nkOfBranch, p)
+        exprList(p, tkColon, b)
+      of tkElif:
+        b = newNodeP(nkElifBranch, p)
+        getTok(p)
+        optInd(p, b)
+        addSon(b, parseExpr(p))
+      of tkExcept:
+        b = newNodeP(nkExceptBranch, p)
+        exprList(p, tkColon, b)
+      of tkElse:
+        b = newNodeP(nkElse, p)
+        getTok(p)
+      else: break
+      eat(p, tkColon)
+      addSon(b, parseStmt(p))
+      addSon(stmtList, b)
+      if b.kind == nkElse: break
+    if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
+      # to keep backwards compatibility (see tests/vm/tstringnil)
+      result.add stmtList[0]
+    else:
+      result.add stmtList
+
+proc parseExprStmt(p: var TParser): PNode =
+  #| exprStmt = simpleExpr
+  #|          (( '=' optInd expr )
+  #|          / ( expr ^+ comma
+  #|              doBlocks
+  #|               / macroColon
+  #|            ))?
+  var a = simpleExpr(p)
+  if p.tok.tokType == tkEquals:
+    getTok(p)
+    optInd(p, result)
+    var b = parseExpr(p)
+    result = newNodeI(nkAsgn, a.info)
+    addSon(result, a)
+    addSon(result, b)
+  else:
+    # simpleExpr parsed 'p a' from 'p a, b'?
+    if p.tok.indent < 0 and p.tok.tokType == tkComma and a.kind == nkCommand:
+      result = a
+      while true:
+        getTok(p)
+        optInd(p, result)
+        var e = parseExpr(p)
+        addSon(result, e)
+        if p.tok.tokType != tkComma: break
+    elif p.tok.indent < 0 and isExprStart(p):
+      if a.kind == nkCommand:
+        result = a
+      else:
+        result = newNode(nkCommand, a.info, @[a])
+      while true:
+        var e = parseExpr(p)
+        addSon(result, e)
+        if p.tok.tokType != tkComma: break
+        getTok(p)
+        optInd(p, result)
+    else:
+      result = a
+    if p.tok.tokType == tkDo and p.tok.indent < 0:
+      result = makeCall(result)
+      parseDoBlocks(p, result)
+      return result
+    result = parseMacroColon(p, result)
+
+proc parseModuleName(p: var TParser, kind: TNodeKind): PNode =
+  result = parseExpr(p)
+  when false:
+    # parseExpr already handles 'as' syntax ...
+    if p.tok.tokType == tkAs and kind == nkImportStmt:
+      let a = result
+      result = newNodeP(nkImportAs, p)
+      getTok(p)
+      result.add(a)
+      result.add(parseExpr(p))
+
+proc parseImport(p: var TParser, kind: TNodeKind): PNode =
+  #| importStmt = 'import' optInd expr
+  #|               ((comma expr)*
+  #|               / 'except' optInd (expr ^+ comma))
+  result = newNodeP(kind, p)
+  getTok(p)                   # skip `import` or `export`
+  optInd(p, result)
+  var a = parseModuleName(p, kind)
+  addSon(result, a)
+  if p.tok.tokType in {tkComma, tkExcept}:
+    if p.tok.tokType == tkExcept:
+      result.kind = succ(kind)
+    getTok(p)
+    optInd(p, result)
+    while true:
+      # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
+      a = parseModuleName(p, kind)
+      if a.kind == nkEmpty: break
+      addSon(result, a)
+      if p.tok.tokType != tkComma: break
+      getTok(p)
+      optInd(p, a)
+  #expectNl(p)
+
+proc parseIncludeStmt(p: var TParser): PNode =
+  #| includeStmt = 'include' optInd expr ^+ comma
+  result = newNodeP(nkIncludeStmt, p)
+  getTok(p)                   # skip `import` or `include`
+  optInd(p, result)
+  while true:
+    # was: while p.tok.tokType notin {tkEof, tkSad, tkDed}:
+    var a = parseExpr(p)
+    if a.kind == nkEmpty: break
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, a)
+  #expectNl(p)
+
+proc parseFromStmt(p: var TParser): PNode =
+  #| fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
+  result = newNodeP(nkFromStmt, p)
+  getTok(p)                   # skip `from`
+  optInd(p, result)
+  var a = parseModuleName(p, nkImportStmt)
+  addSon(result, a)           #optInd(p, a);
+  eat(p, tkImport)
+  optInd(p, result)
+  while true:
+    # p.tok.tokType notin {tkEof, tkSad, tkDed}:
+    a = parseExpr(p)
+    if a.kind == nkEmpty: break
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, a)
+  #expectNl(p)
+
+proc parseReturnOrRaise(p: var TParser, kind: TNodeKind): PNode =
+  #| returnStmt = 'return' optInd expr?
+  #| raiseStmt = 'raise' optInd expr?
+  #| yieldStmt = 'yield' optInd expr?
+  #| discardStmt = 'discard' optInd expr?
+  #| breakStmt = 'break' optInd expr?
+  #| continueStmt = 'break' optInd expr?
+  result = newNodeP(kind, p)
+  getTok(p)
+  if p.tok.tokType == tkComment:
+    skipComment(p, result)
+    addSon(result, ast.emptyNode)
+  elif p.tok.indent >= 0 and p.tok.indent <= p.currInd or not isExprStart(p):
+    # NL terminates:
+    addSon(result, ast.emptyNode)
+  else:
+    addSon(result, parseExpr(p))
+
+proc parseIfOrWhen(p: var TParser, kind: TNodeKind): PNode =
+  #| condStmt = expr colcom stmt COMMENT?
+  #|            (IND{=} 'elif' expr colcom stmt)*
+  #|            (IND{=} 'else' colcom stmt)?
+  #| ifStmt = 'if' condStmt
+  #| whenStmt = 'when' condStmt
+  result = newNodeP(kind, p)
+  while true:
+    getTok(p)                 # skip `if`, `when`, `elif`
+    var branch = newNodeP(nkElifBranch, p)
+    optInd(p, branch)
+    addSon(branch, parseExpr(p))
+    colcom(p, branch)
+    addSon(branch, parseStmt(p))
+    skipComment(p, branch)
+    addSon(result, branch)
+    if p.tok.tokType != tkElif or not sameOrNoInd(p): break
+  if p.tok.tokType == tkElse and sameOrNoInd(p):
+    var branch = newNodeP(nkElse, p)
+    eat(p, tkElse)
+    colcom(p, branch)
+    addSon(branch, parseStmt(p))
+    addSon(result, branch)
+
+proc parseWhile(p: var TParser): PNode =
+  #| whileStmt = 'while' expr colcom stmt
+  result = newNodeP(nkWhileStmt, p)
+  getTok(p)
+  optInd(p, result)
+  addSon(result, parseExpr(p))
+  colcom(p, result)
+  addSon(result, parseStmt(p))
+
+proc parseCase(p: var TParser): PNode =
+  #| ofBranch = 'of' exprList colcom stmt
+  #| ofBranches = ofBranch (IND{=} ofBranch)*
+  #|                       (IND{=} 'elif' expr colcom stmt)*
+  #|                       (IND{=} 'else' colcom stmt)?
+  #| caseStmt = 'case' expr ':'? COMMENT?
+  #|             (IND{>} ofBranches DED
+  #|             | IND{=} ofBranches)
+  var
+    b: PNode
+    inElif= false
+    wasIndented = false
+  result = newNodeP(nkCaseStmt, p)
+  getTok(p)
+  addSon(result, parseExpr(p))
+  if p.tok.tokType == tkColon: getTok(p)
+  skipComment(p, result)
+
+  let oldInd = p.currInd
+  if realInd(p):
+    p.currInd = p.tok.indent
+    wasIndented = true
+
+  while sameInd(p):
+    case p.tok.tokType
+    of tkOf:
+      if inElif: break
+      b = newNodeP(nkOfBranch, p)
+      exprList(p, tkColon, b)
+    of tkElif:
+      inElif = true
+      b = newNodeP(nkElifBranch, p)
+      getTok(p)
+      optInd(p, b)
+      addSon(b, parseExpr(p))
+    of tkElse:
+      b = newNodeP(nkElse, p)
+      getTok(p)
+    else: break
+    colcom(p, b)
+    addSon(b, parseStmt(p))
+    addSon(result, b)
+    if b.kind == nkElse: break
+
+  if wasIndented:
+    p.currInd = oldInd
+
+proc parseTry(p: var TParser; isExpr: bool): PNode =
+  #| tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
+  #|            (IND{=}? 'except' exprList colcom stmt)*
+  #|            (IND{=}? 'finally' colcom stmt)?
+  #| tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
+  #|            (optInd 'except' exprList colcom stmt)*
+  #|            (optInd 'finally' colcom stmt)?
+  result = newNodeP(nkTryStmt, p)
+  getTok(p)
+  colcom(p, result)
+  addSon(result, parseStmt(p))
+  var b: PNode = nil
+  while sameOrNoInd(p) or isExpr:
+    case p.tok.tokType
+    of tkExcept:
+      b = newNodeP(nkExceptBranch, p)
+      exprList(p, tkColon, b)
+    of tkFinally:
+      b = newNodeP(nkFinally, p)
+      getTok(p)
+    else: break
+    colcom(p, b)
+    addSon(b, parseStmt(p))
+    addSon(result, b)
+    if b.kind == nkFinally: break
+  if b == nil: parMessage(p, errTokenExpected, "except")
+
+proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
+  #| exceptBlock = 'except' colcom stmt
+  result = newNodeP(kind, p)
+  getTok(p)
+  colcom(p, result)
+  addSon(result, parseStmt(p))
+
+proc parseFor(p: var TParser): PNode =
+  #| forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
+  result = newNodeP(nkForStmt, p)
+  getTokNoInd(p)
+  var a = identWithPragma(p)
+  addSon(result, a)
+  while p.tok.tokType == tkComma:
+    getTok(p)
+    optInd(p, a)
+    a = identWithPragma(p)
+    addSon(result, a)
+  eat(p, tkIn)
+  addSon(result, parseExpr(p))
+  colcom(p, result)
+  addSon(result, parseStmt(p))
+
+proc parseBlock(p: var TParser): PNode =
+  #| blockStmt = 'block' symbol? colcom stmt
+  result = newNodeP(nkBlockStmt, p)
+  getTokNoInd(p)
+  if p.tok.tokType == tkColon: addSon(result, ast.emptyNode)
+  else: addSon(result, parseSymbol(p))
+  colcom(p, result)
+  addSon(result, parseStmt(p))
+
+proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
+  #| staticStmt = 'static' colcom stmt
+  #| deferStmt = 'defer' colcom stmt
+  result = newNodeP(k, p)
+  getTok(p)
+  colcom(p, result)
+  addSon(result, parseStmt(p))
+
+proc parseAsm(p: var TParser): PNode =
+  #| asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
+  result = newNodeP(nkAsmStmt, p)
+  getTokNoInd(p)
+  if p.tok.tokType == tkCurlyDotLe: addSon(result, parsePragma(p))
+  else: addSon(result, ast.emptyNode)
+  case p.tok.tokType
+  of tkStrLit: addSon(result, newStrNodeP(nkStrLit, p.tok.literal, p))
+  of tkRStrLit: addSon(result, newStrNodeP(nkRStrLit, p.tok.literal, p))
+  of tkTripleStrLit: addSon(result,
+                            newStrNodeP(nkTripleStrLit, p.tok.literal, p))
+  else:
+    parMessage(p, errStringLiteralExpected)
+    addSon(result, ast.emptyNode)
+    return
+  getTok(p)
+
+proc parseGenericParam(p: var TParser): PNode =
+  #| genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
+  var a: PNode
+  result = newNodeP(nkIdentDefs, p)
+  while true:
+    case p.tok.tokType
+    of tkSymbol, tkAccent:
+      a = parseSymbol(p)
+      if a.kind == nkEmpty: return
+    else: break
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, a)
+  if p.tok.tokType == tkColon:
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseExpr(p))
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkEquals:
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseExpr(p))
+  else:
+    addSon(result, ast.emptyNode)
+
+proc parseGenericParamList(p: var TParser): PNode =
+  #| genericParamList = '[' optInd
+  #|   genericParam ^* (comma/semicolon) optPar ']'
+  result = newNodeP(nkGenericParams, p)
+  getTok(p)
+  optInd(p, result)
+  while p.tok.tokType in {tkSymbol, tkAccent}:
+    var a = parseGenericParam(p)
+    addSon(result, a)
+    if p.tok.tokType notin {tkComma, tkSemiColon}: break
+    getTok(p)
+    skipComment(p, a)
+  optPar(p)
+  eat(p, tkBracketRi)
+
+proc parsePattern(p: var TParser): PNode =
+  #| pattern = '{' stmt '}'
+  eat(p, tkCurlyLe)
+  result = parseStmt(p)
+  eat(p, tkCurlyRi)
+
+proc validInd(p: var TParser): bool =
+  result = p.tok.indent < 0 or p.tok.indent > p.currInd
+
+proc parseRoutine(p: var TParser, kind: TNodeKind): PNode =
+  #| indAndComment = (IND{>} COMMENT)? | COMMENT?
+  #| routine = optInd identVis pattern? genericParamList?
+  #|   paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
+  result = newNodeP(kind, p)
+  getTok(p)
+  optInd(p, result)
+  addSon(result, identVis(p))
+  if p.tok.tokType == tkCurlyLe and p.validInd: addSon(result, p.parsePattern)
+  else: addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkBracketLe and p.validInd:
+    result.add(p.parseGenericParamList)
+  else:
+    addSon(result, ast.emptyNode)
+  addSon(result, p.parseParamList)
+  if p.tok.tokType == tkCurlyDotLe and p.validInd: addSon(result, p.parsePragma)
+  else: addSon(result, ast.emptyNode)
+  # empty exception tracking:
+  addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkEquals and p.validInd:
+    getTok(p)
+    skipComment(p, result)
+    addSon(result, parseStmt(p))
+  else:
+    addSon(result, ast.emptyNode)
+  indAndComment(p, result)
+
+proc newCommentStmt(p: var TParser): PNode =
+  #| commentStmt = COMMENT
+  result = newNodeP(nkCommentStmt, p)
+  result.comment = p.tok.literal
+  getTok(p)
+
+type
+  TDefParser = proc (p: var TParser): PNode {.nimcall.}
+
+proc parseSection(p: var TParser, kind: TNodeKind,
+                  defparser: TDefParser): PNode =
+  #| section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
+  result = newNodeP(kind, p)
+  if kind != nkTypeSection: getTok(p)
+  skipComment(p, result)
+  if realInd(p):
+    withInd(p):
+      skipComment(p, result)
+      while sameInd(p):
+        case p.tok.tokType
+        of tkSymbol, tkAccent, tkParLe:
+          var a = defparser(p)
+          skipComment(p, a)
+          addSon(result, a)
+        of tkComment:
+          var a = newCommentStmt(p)
+          addSon(result, a)
+        else:
+          parMessage(p, errIdentifierExpected, p.tok)
+          break
+    if result.len == 0: parMessage(p, errIdentifierExpected, p.tok)
+  elif p.tok.tokType in {tkSymbol, tkAccent, tkParLe} and p.tok.indent < 0:
+    # tkParLe is allowed for ``var (x, y) = ...`` tuple parsing
+    addSon(result, defparser(p))
+  else:
+    parMessage(p, errIdentifierExpected, p.tok)
+
+proc parseConstant(p: var TParser): PNode =
+  #| constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
+  result = newNodeP(nkConstDef, p)
+  addSon(result, identWithPragma(p))
+  if p.tok.tokType == tkColon:
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseTypeDesc(p))
+  else:
+    addSon(result, ast.emptyNode)
+  eat(p, tkEquals)
+  optInd(p, result)
+  addSon(result, parseExpr(p))
+  indAndComment(p, result)
+
+proc parseEnum(p: var TParser): PNode =
+  #| enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
+  result = newNodeP(nkEnumTy, p)
+  getTok(p)
+  addSon(result, ast.emptyNode)
+  optInd(p, result)
+  while true:
+    var a = parseSymbol(p)
+    if a.kind == nkEmpty: return
+    if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
+      add(result, a)
+      break
+    if p.tok.tokType == tkEquals and p.tok.indent < 0:
+      getTok(p)
+      optInd(p, a)
+      var b = a
+      a = newNodeP(nkEnumFieldDef, p)
+      addSon(a, b)
+      addSon(a, parseExpr(p))
+      skipComment(p, a)
+    if p.tok.tokType == tkComma and p.tok.indent < 0:
+      getTok(p)
+      rawSkipComment(p, a)
+    else:
+      skipComment(p, a)
+    addSon(result, a)
+    if p.tok.indent >= 0 and p.tok.indent <= p.currInd or
+        p.tok.tokType == tkEof:
+      break
+  if result.len <= 1:
+    lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
+
+proc parseObjectPart(p: var TParser): PNode
+proc parseObjectWhen(p: var TParser): PNode =
+  #| objectWhen = 'when' expr colcom objectPart COMMENT?
+  #|             ('elif' expr colcom objectPart COMMENT?)*
+  #|             ('else' colcom objectPart COMMENT?)?
+  result = newNodeP(nkRecWhen, p)
+  while sameInd(p):
+    getTok(p)                 # skip `when`, `elif`
+    var branch = newNodeP(nkElifBranch, p)
+    optInd(p, branch)
+    addSon(branch, parseExpr(p))
+    colcom(p, branch)
+    addSon(branch, parseObjectPart(p))
+    skipComment(p, branch)
+    addSon(result, branch)
+    if p.tok.tokType != tkElif: break
+  if p.tok.tokType == tkElse and sameInd(p):
+    var branch = newNodeP(nkElse, p)
+    eat(p, tkElse)
+    colcom(p, branch)
+    addSon(branch, parseObjectPart(p))
+    skipComment(p, branch)
+    addSon(result, branch)
+
+proc parseObjectCase(p: var TParser): PNode =
+  #| objectBranch = 'of' exprList colcom objectPart
+  #| objectBranches = objectBranch (IND{=} objectBranch)*
+  #|                       (IND{=} 'elif' expr colcom objectPart)*
+  #|                       (IND{=} 'else' colcom objectPart)?
+  #| objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
+  #|             (IND{>} objectBranches DED
+  #|             | IND{=} objectBranches)
+  result = newNodeP(nkRecCase, p)
+  getTokNoInd(p)
+  var a = newNodeP(nkIdentDefs, p)
+  addSon(a, identWithPragma(p))
+  eat(p, tkColon)
+  addSon(a, parseTypeDesc(p))
+  addSon(a, ast.emptyNode)
+  addSon(result, a)
+  if p.tok.tokType == tkColon: getTok(p)
+  skipComment(p, result)
+  var wasIndented = false
+  let oldInd = p.currInd
+  if realInd(p):
+    p.currInd = p.tok.indent
+    wasIndented = true
+  while sameInd(p):
+    var b: PNode
+    case p.tok.tokType
+    of tkOf:
+      b = newNodeP(nkOfBranch, p)
+      exprList(p, tkColon, b)
+    of tkElse:
+      b = newNodeP(nkElse, p)
+      getTok(p)
+    else: break
+    colcom(p, b)
+    var fields = parseObjectPart(p)
+    if fields.kind == nkEmpty:
+      parMessage(p, errIdentifierExpected, p.tok)
+      fields = newNodeP(nkNilLit, p) # don't break further semantic checking
+    addSon(b, fields)
+    addSon(result, b)
+    if b.kind == nkElse: break
+  if wasIndented:
+    p.currInd = oldInd
+
+proc parseObjectPart(p: var TParser): PNode =
+  #| objectPart = IND{>} objectPart^+IND{=} DED
+  #|            / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals
+  if realInd(p):
+    result = newNodeP(nkRecList, p)
+    withInd(p):
+      rawSkipComment(p, result)
+      while sameInd(p):
+        case p.tok.tokType
+        of tkCase, tkWhen, tkSymbol, tkAccent, tkNil, tkDiscard:
+          addSon(result, parseObjectPart(p))
+        else:
+          parMessage(p, errIdentifierExpected, p.tok)
+          break
+  else:
+    case p.tok.tokType
+    of tkWhen:
+      result = parseObjectWhen(p)
+    of tkCase:
+      result = parseObjectCase(p)
+    of tkSymbol, tkAccent:
+      result = parseIdentColonEquals(p, {withPragma})
+      skipComment(p, result)
+    of tkNil, tkDiscard:
+      result = newNodeP(nkNilLit, p)
+      getTok(p)
+    else:
+      result = ast.emptyNode
+
+proc parseObject(p: var TParser): PNode =
+  #| object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
+  result = newNodeP(nkObjectTy, p)
+  getTok(p)
+  if p.tok.tokType == tkCurlyDotLe and p.validInd:
+    addSon(result, parsePragma(p))
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkOf and p.tok.indent < 0:
+    var a = newNodeP(nkOfInherit, p)
+    getTok(p)
+    addSon(a, parseTypeDesc(p))
+    addSon(result, a)
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkComment:
+    skipComment(p, result)
+  # an initial IND{>} HAS to follow:
+  if not realInd(p):
+    addSon(result, emptyNode)
+    return
+  addSon(result, parseObjectPart(p))
+
+proc parseTypeClassParam(p: var TParser): PNode =
+  if p.tok.tokType == tkVar:
+    result = newNodeP(nkVarTy, p)
+    getTok(p)
+    result.addSon(p.parseSymbol)
+  else:
+    result = p.parseSymbol
+
+proc parseTypeClass(p: var TParser): PNode =
+  #| typeClassParam = ('var')? symbol
+  #| typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
+  #|               &IND{>} stmt
+  result = newNodeP(nkTypeClassTy, p)
+  getTok(p)
+  var args = newNodeP(nkArgList, p)
+  addSon(result, args)
+  addSon(args, p.parseTypeClassParam)
+  while p.tok.tokType == tkComma:
+    getTok(p)
+    addSon(args, p.parseTypeClassParam)
+  if p.tok.tokType == tkCurlyDotLe and p.validInd:
+    addSon(result, parsePragma(p))
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkOf and p.tok.indent < 0:
+    var a = newNodeP(nkOfInherit, p)
+    getTok(p)
+    while true:
+      addSon(a, parseTypeDesc(p))
+      if p.tok.tokType != tkComma: break
+      getTok(p)
+    addSon(result, a)
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkComment:
+    skipComment(p, result)
+  # an initial IND{>} HAS to follow:
+  if not realInd(p):
+    addSon(result, emptyNode)
+  else:
+    addSon(result, parseStmt(p))
+
+proc parseTypeDef(p: var TParser): PNode =
+  #| typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
+  #|             indAndComment?
+  result = newNodeP(nkTypeDef, p)
+  addSon(result, identWithPragma(p))
+  if p.tok.tokType == tkBracketLe and p.validInd:
+    addSon(result, parseGenericParamList(p))
+  else:
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkEquals:
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseTypeDefAux(p))
+  else:
+    addSon(result, ast.emptyNode)
+  indAndComment(p, result)    # special extension!
+
+proc parseVarTuple(p: var TParser): PNode =
+  #| varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
+  result = newNodeP(nkVarTuple, p)
+  getTok(p)                   # skip '('
+  optInd(p, result)
+  while p.tok.tokType in {tkSymbol, tkAccent}:
+    var a = identWithPragma(p)
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    skipComment(p, a)
+  addSon(result, ast.emptyNode)         # no type desc
+  optPar(p)
+  eat(p, tkParRi)
+  eat(p, tkEquals)
+  optInd(p, result)
+  addSon(result, parseExpr(p))
+
+proc parseVariable(p: var TParser): PNode =
+  #| variable = (varTuple / identColonEquals) indAndComment
+  if p.tok.tokType == tkParLe: result = parseVarTuple(p)
+  else: result = parseIdentColonEquals(p, {withPragma})
+  indAndComment(p, result)
+
+proc parseBind(p: var TParser, k: TNodeKind): PNode =
+  #| bindStmt = 'bind' optInd qualifiedIdent ^+ comma
+  #| mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
+  result = newNodeP(k, p)
+  getTok(p)
+  optInd(p, result)
+  while true:
+    var a = qualifiedIdent(p)
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break
+    getTok(p)
+    optInd(p, a)
+  #expectNl(p)
+
+proc parseStmtPragma(p: var TParser): PNode =
+  #| pragmaStmt = pragma (':' COMMENT? stmt)?
+  result = parsePragma(p)
+  if p.tok.tokType == tkColon and p.tok.indent < 0:
+    let a = result
+    result = newNodeI(nkPragmaBlock, a.info)
+    getTok(p)
+    skipComment(p, result)
+    result.add a
+    result.add parseStmt(p)
+
+proc simpleStmt(p: var TParser): PNode =
+  #| simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
+  #|            | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
+  #|            | includeStmt | commentStmt) / exprStmt) COMMENT?
+  #|
+  case p.tok.tokType
+  of tkReturn: result = parseReturnOrRaise(p, nkReturnStmt)
+  of tkRaise: result = parseReturnOrRaise(p, nkRaiseStmt)
+  of tkYield: result = parseReturnOrRaise(p, nkYieldStmt)
+  of tkDiscard: result = parseReturnOrRaise(p, nkDiscardStmt)
+  of tkBreak: result = parseReturnOrRaise(p, nkBreakStmt)
+  of tkContinue: result = parseReturnOrRaise(p, nkContinueStmt)
+  of tkCurlyDotLe: result = parseStmtPragma(p)
+  of tkImport: result = parseImport(p, nkImportStmt)
+  of tkExport: result = parseImport(p, nkExportStmt)
+  of tkFrom: result = parseFromStmt(p)
+  of tkInclude: result = parseIncludeStmt(p)
+  of tkComment: result = newCommentStmt(p)
+  else:
+    if isExprStart(p): result = parseExprStmt(p)
+    else: result = ast.emptyNode
+  if result.kind notin {nkEmpty, nkCommentStmt}: skipComment(p, result)
+
+proc complexOrSimpleStmt(p: var TParser): PNode =
+  #| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
+  #|                     | tryStmt | forStmt
+  #|                     | blockStmt | staticStmt | deferStmt | asmStmt
+  #|                     | 'proc' routine
+  #|                     | 'method' routine
+  #|                     | 'iterator' routine
+  #|                     | 'macro' routine
+  #|                     | 'template' routine
+  #|                     | 'converter' routine
+  #|                     | 'type' section(typeDef)
+  #|                     | 'const' section(constant)
+  #|                     | ('let' | 'var') section(variable)
+  #|                     | bindStmt | mixinStmt)
+  #|                     / simpleStmt
+  case p.tok.tokType
+  of tkIf: result = parseIfOrWhen(p, nkIfStmt)
+  of tkWhile: result = parseWhile(p)
+  of tkCase: result = parseCase(p)
+  of tkTry: result = parseTry(p, isExpr=false)
+  of tkFinally: result = parseExceptBlock(p, nkFinally)
+  of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
+  of tkFor: result = parseFor(p)
+  of tkBlock: result = parseBlock(p)
+  of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt)
+  of tkDefer: result = parseStaticOrDefer(p, nkDefer)
+  of tkAsm: result = parseAsm(p)
+  of tkProc: result = parseRoutine(p, nkProcDef)
+  of tkMethod: result = parseRoutine(p, nkMethodDef)
+  of tkIterator: result = parseRoutine(p, nkIteratorDef)
+  of tkMacro: result = parseRoutine(p, nkMacroDef)
+  of tkTemplate: result = parseRoutine(p, nkTemplateDef)
+  of tkConverter: result = parseRoutine(p, nkConverterDef)
+  of tkType:
+    getTok(p)
+    if p.tok.tokType == tkParLe:
+      getTok(p)
+      result = newNodeP(nkTypeOfExpr, p)
+      result.addSon(primary(p, pmTypeDesc))
+      eat(p, tkParRi)
+      result = parseOperators(p, result, -1, pmNormal)
+    else:
+      result = parseSection(p, nkTypeSection, parseTypeDef)
+  of tkConst: result = parseSection(p, nkConstSection, parseConstant)
+  of tkLet: result = parseSection(p, nkLetSection, parseVariable)
+  of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
+  of tkVar: result = parseSection(p, nkVarSection, parseVariable)
+  of tkBind: result = parseBind(p, nkBindStmt)
+  of tkMixin: result = parseBind(p, nkMixinStmt)
+  of tkUsing: result = parseBind(p, nkUsingStmt)
+  else: result = simpleStmt(p)
+
+proc parseStmt(p: var TParser): PNode =
+  #| stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
+  #|      / simpleStmt ^+ ';'
+  if p.tok.indent > p.currInd:
+    result = newNodeP(nkStmtList, p)
+    withInd(p):
+      while true:
+        if p.tok.indent == p.currInd:
+          discard
+        elif p.tok.tokType == tkSemiColon:
+          getTok(p)
+          if p.tok.indent < 0 or p.tok.indent == p.currInd: discard
+          else: break
+        else:
+          if p.tok.indent > p.currInd and p.tok.tokType != tkDot:
+            parMessage(p, errInvalidIndentation)
+          break
+        if p.tok.tokType in {tkCurlyRi, tkParRi, tkCurlyDotRi, tkBracketRi}:
+          # XXX this ensures tnamedparamanonproc still compiles;
+          # deprecate this syntax later
+          break
+        var a = complexOrSimpleStmt(p)
+        if a.kind != nkEmpty:
+          addSon(result, a)
+        else:
+          parMessage(p, errExprExpected, p.tok)
+          getTok(p)
+  else:
+    # the case statement is only needed for better error messages:
+    case p.tok.tokType
+    of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkIterator,
+       tkMacro, tkType, tkConst, tkWhen, tkVar:
+      parMessage(p, errComplexStmtRequiresInd)
+      result = ast.emptyNode
+    else:
+      if p.inSemiStmtList > 0:
+        result = simpleStmt(p)
+        if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+      else:
+        result = newNodeP(nkStmtList, p)
+        while true:
+          if p.tok.indent >= 0:
+            parMessage(p, errInvalidIndentation)
+          let a = simpleStmt(p)
+          if a.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+          result.add(a)
+          if p.tok.tokType != tkSemiColon: break
+          getTok(p)
+
+proc parseAll(p: var TParser): PNode =
+  ## Parses the rest of the input stream held by the parser into a PNode.
+  result = newNodeP(nkStmtList, p)
+  while p.tok.tokType != tkEof:
+    var a = complexOrSimpleStmt(p)
+    if a.kind != nkEmpty:
+      addSon(result, a)
+    else:
+      parMessage(p, errExprExpected, p.tok)
+      # bugfix: consume a token here to prevent an endless loop:
+      getTok(p)
+    if p.tok.indent != 0:
+      parMessage(p, errInvalidIndentation)
+
+proc parseTopLevelStmt(p: var TParser): PNode =
+  ## Implements an iterator which, when called repeatedly, returns the next
+  ## top-level statement or emptyNode if end of stream.
+  result = ast.emptyNode
+  while true:
+    if p.tok.indent != 0:
+      if p.firstTok and p.tok.indent < 0: discard
+      elif p.tok.tokType != tkSemiColon:
+        parMessage(p, errInvalidIndentation)
+    p.firstTok = false
+    case p.tok.tokType
+    of tkSemiColon:
+      getTok(p)
+      if p.tok.indent <= 0: discard
+      else: parMessage(p, errInvalidIndentation)
+      p.firstTok = true
+    of tkEof: break
+    else:
+      result = complexOrSimpleStmt(p)
+      if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
+      break
+
+proc parseString*(s: string; filename: string = ""; line: int = 0;
+                  errorHandler: TErrorHandler = nil): PNode =
+  ## Parses a string into an AST, returning the top node.
+  ## `filename` and `line`, although optional, provide info so that the
+  ## compiler can generate correct error messages referring to the original
+  ## source.
+  var stream = llStreamOpen(s)
+  stream.lineOffset = line
+
+  var parser: TParser
+  # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
+  # spaces...
+  parser.lex.errorHandler = errorHandler
+  openParser(parser, filename, stream, false)
+
+  result = parser.parseAll
+  closeParser(parser)
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
new file mode 100644
index 000000000..f754c80e5
--- /dev/null
+++ b/compiler/passaux.nim
@@ -0,0 +1,47 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## implements some little helper passes
+
+import 
+  strutils, ast, astalgo, passes, msgs, options, idgen
+
+proc verboseOpen(s: PSym): PPassContext =
+  #MessageOut('compiling ' + s.name.s);
+  result = nil                # we don't need a context
+  if gVerbosity > 0: rawMessage(hintProcessing, s.name.s)
+  
+proc verboseProcess(context: PPassContext, n: PNode): PNode = 
+  result = n
+  if context != nil: internalError("logpass: context is not nil")
+  if gVerbosity == 3: 
+    # system.nim deactivates all hints, for verbosity:3 we want the processing
+    # messages nonetheless, so we activate them again unconditionally:
+    incl(msgs.gNotes, hintProcessing)
+    message(n.info, hintProcessing, $idgen.gBackendId)
+  
+const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
+
+proc cleanUp(c: PPassContext, n: PNode): PNode = 
+  result = n
+  # we cannot clean up if dead code elimination is activated
+  if optDeadCodeElim in gGlobalOptions or n == nil: return 
+  case n.kind
+  of nkStmtList: 
+    for i in countup(0, sonsLen(n) - 1): discard cleanUp(c, n.sons[i])
+  of nkProcDef, nkMethodDef: 
+    if n.sons[namePos].kind == nkSym: 
+      var s = n.sons[namePos].sym
+      if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s): 
+        s.ast.sons[bodyPos] = ast.emptyNode # free the memory
+  else: 
+    discard
+
+const cleanupPass* = makePass(process = cleanUp, close = cleanUp)
+
diff --git a/compiler/passes.nim b/compiler/passes.nim
new file mode 100644
index 000000000..e031dae10
--- /dev/null
+++ b/compiler/passes.nim
@@ -0,0 +1,205 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the passes functionality. A pass must implement the
+# `TPass` interface.
+
+import
+  strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
+  condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
+  nimsets, syntaxes, times, rodread, idgen
+
+type
+  TPassContext* = object of RootObj # the pass's context
+    fromCache*: bool  # true if created by "openCached"
+
+  PPassContext* = ref TPassContext
+
+  TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
+  TPassOpenCached* =
+    proc (module: PSym, rd: PRodReader): PPassContext {.nimcall.}
+  TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.}
+  TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
+
+  TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached,
+                 process: TPassProcess, close: TPassClose]
+
+  TPassData* = tuple[input: PNode, closeOutput: PNode]
+  TPasses* = openArray[TPass]
+
+# a pass is a tuple of procedure vars ``TPass.close`` may produce additional
+# nodes. These are passed to the other close procedures.
+# This mechanism used to be used for the instantiation of generics.
+
+proc makePass*(open: TPassOpen = nil,
+               openCached: TPassOpenCached = nil,
+               process: TPassProcess = nil,
+               close: TPassClose = nil): TPass =
+  result.open = open
+  result.openCached = openCached
+  result.close = close
+  result.process = process
+
+  # This implements a memory preserving scheme: Top level statements are
+  # processed in a pipeline. The compiler never looks at a whole module
+  # any longer. However, this is simple to change, as new passes may perform
+  # whole program optimizations. For now, we avoid it to save a lot of memory.
+proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
+
+# the semantic checker needs these:
+var
+  gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
+  gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
+
+# implementation
+
+proc skipCodegen*(n: PNode): bool {.inline.} =
+  # can be used by codegen passes to determine whether they should do
+  # something with `n`. Currently, this ignores `n` and uses the global
+  # error count instead.
+  result = msgs.gErrorCounter > 0
+
+proc astNeeded*(s: PSym): bool =
+  # The ``rodwrite`` module uses this to determine if the body of a proc
+  # needs to be stored. The passes manager frees s.sons[codePos] when
+  # appropriate to free the procedure body's memory. This is important
+  # to keep memory usage down.
+  if (s.kind in {skMethod, skProc}) and
+      ({sfCompilerProc, sfCompileTime} * s.flags == {}) and
+      (s.typ.callConv != ccInline) and
+      (s.ast.sons[genericParamsPos].kind == nkEmpty):
+    result = false
+    # XXX this doesn't really make sense with excessive CTFE
+  else:
+    result = true
+
+const
+  maxPasses = 10
+
+type
+  TPassContextArray = array[0..maxPasses - 1, PPassContext]
+
+var
+  gPasses: array[0..maxPasses - 1, TPass]
+  gPassesLen*: int
+
+proc clearPasses* =
+  gPassesLen = 0
+
+proc registerPass*(p: TPass) =
+  gPasses[gPassesLen] = p
+  inc(gPassesLen)
+
+proc carryPass*(p: TPass, module: PSym, m: TPassData): TPassData =
+  var c = p.open(module)
+  result.input = p.process(c, m.input)
+  result.closeOutput = if p.close != nil: p.close(c, m.closeOutput)
+                       else: m.closeOutput
+
+proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
+  var passdata: TPassData
+  passdata.input = nodes
+  for pass in passes:
+    passdata = carryPass(pass, module, passdata)
+
+proc openPasses(a: var TPassContextArray, module: PSym) =
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].open):
+      a[i] = gPasses[i].open(module)
+    else: a[i] = nil
+
+proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached):
+      a[i] = gPasses[i].openCached(module, rd)
+      if a[i] != nil:
+        a[i].fromCache = true
+    else:
+      a[i] = nil
+
+proc closePasses(a: var TPassContextArray) =
+  var m: PNode = nil
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].close): m = gPasses[i].close(a[i], m)
+    a[i] = nil                # free the memory here
+
+proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
+  # this implements the code transformation pipeline
+  var m = n
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].process):
+      m = gPasses[i].process(a[i], m)
+      if isNil(m): return false
+  result = true
+
+proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
+  # this implements the code transformation pipeline
+  var m = n
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
+
+proc closePassesCached(a: var TPassContextArray) =
+  var m: PNode = nil
+  for i in countup(0, gPassesLen - 1):
+    if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
+      m = gPasses[i].close(a[i], m)
+    a[i] = nil                # free the memory here
+
+proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
+                      a: var TPassContextArray) =
+  for module in items(implicits):
+    var importStmt = newNodeI(nodeKind, gCmdLineInfo)
+    var str = newStrNode(nkStrLit, module)
+    str.info = gCmdLineInfo
+    importStmt.addSon str
+    if not processTopLevelStmt(importStmt, a): break
+
+proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
+  var
+    p: TParsers
+    a: TPassContextArray
+    s: PLLStream
+    fileIdx = module.fileIdx
+  if rd == nil:
+    openPasses(a, module)
+    if stream == nil:
+      let filename = fileIdx.toFullPathConsiderDirty
+      s = llStreamOpen(filename, fmRead)
+      if s == nil:
+        rawMessage(errCannotOpenFile, filename)
+        return
+    else:
+      s = stream
+    while true:
+      openParsers(p, fileIdx, s)
+
+      if sfSystemModule notin module.flags:
+        # XXX what about caching? no processing then? what if I change the
+        # modules to include between compilation runs? we'd need to track that
+        # in ROD files. I think we should enable this feature only
+        # for the interactive mode.
+        processImplicits implicitImports, nkImportStmt, a
+        processImplicits implicitIncludes, nkIncludeStmt, a
+
+      while true:
+        var n = parseTopLevelStmt(p)
+        if n.kind == nkEmpty: break
+        if not processTopLevelStmt(n, a): break
+
+      closeParsers(p)
+      if s.kind != llsStdIn: break
+    closePasses(a)
+    # id synchronization point for more consistent code generation:
+    idSynchronizationPoint(1000)
+  else:
+    openPassesCached(a, module, rd)
+    var n = loadInitSection(rd)
+    for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
+    closePassesCached(a)
+
diff --git a/compiler/patterns.nim b/compiler/patterns.nim
new file mode 100644
index 000000000..368b0b37b
--- /dev/null
+++ b/compiler/patterns.nim
@@ -0,0 +1,294 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the pattern matching features for term rewriting
+## macro support.
+
+import
+  ast, astalgo, types, semdata, sigmatch, msgs, idents, aliases, parampatterns,
+  trees
+
+type
+  TPatternContext = object
+    owner: PSym
+    mapping: seq[PNode]  # maps formal parameters to nodes
+    formals: int
+    c: PContext
+    subMatch: bool       # subnode matches are special
+  PPatternContext = var TPatternContext
+
+proc getLazy(c: PPatternContext, sym: PSym): PNode =
+  if not isNil(c.mapping):
+    result = c.mapping[sym.position]
+
+proc putLazy(c: PPatternContext, sym: PSym, n: PNode) =
+  if isNil(c.mapping): newSeq(c.mapping, c.formals)
+  c.mapping[sym.position] = n
+
+proc matches(c: PPatternContext, p, n: PNode): bool
+
+proc canonKind(n: PNode): TNodeKind =
+  ## nodekind canonilization for pattern matching
+  result = n.kind
+  case result
+  of nkCallKinds: result = nkCall
+  of nkStrLit..nkTripleStrLit: result = nkStrLit
+  of nkFastAsgn: result = nkAsgn
+  else: discard
+
+proc sameKinds(a, b: PNode): bool {.inline.} =
+  result = a.kind == b.kind or a.canonKind == b.canonKind
+
+proc sameTrees(a, b: PNode): bool =
+  if sameKinds(a, b):
+    case a.kind
+    of nkSym: result = a.sym == b.sym
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkEmpty, nkNilLit: result = true
+    of nkType: result = sameTypeOrNil(a.typ, b.typ)
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameTrees(a.sons[i], b.sons[i]): return
+        result = true
+
+proc inSymChoice(sc, x: PNode): bool =
+  if sc.kind == nkClosedSymChoice:
+    for i in 0.. <sc.len:
+      if sc.sons[i].sym == x.sym: return true
+  elif sc.kind == nkOpenSymChoice:
+    # same name suffices for open sym choices!
+    result = sc.sons[0].sym.name.id == x.sym.name.id
+  
+proc checkTypes(c: PPatternContext, p: PSym, n: PNode): bool =
+  # check param constraints first here as this is quite optimized:
+  if p.constraint != nil:
+    result = matchNodeKinds(p.constraint, n)
+    if not result: return
+  if isNil(n.typ):
+    result = p.typ.kind in {tyEmpty, tyStmt}
+  else:
+    result = sigmatch.argtypeMatches(c.c, p.typ, n.typ)
+
+proc isPatternParam(c: PPatternContext, p: PNode): bool {.inline.} =
+  result = p.kind == nkSym and p.sym.kind == skParam and p.sym.owner == c.owner
+
+proc matchChoice(c: PPatternContext, p, n: PNode): bool =
+  for i in 1 .. <p.len:
+    if matches(c, p.sons[i], n): return true
+
+proc bindOrCheck(c: PPatternContext, param: PSym, n: PNode): bool =
+  var pp = getLazy(c, param)
+  if pp != nil:
+    # check if we got the same pattern (already unified):
+    result = sameTrees(pp, n) #matches(c, pp, n)
+  elif n.kind == nkArgList or checkTypes(c, param, n):
+    putLazy(c, param, n)
+    result = true
+
+proc gather(c: PPatternContext, param: PSym, n: PNode) =
+  var pp = getLazy(c, param)
+  if pp != nil and pp.kind == nkArgList:
+    pp.add(n)
+  else:
+    pp = newNodeI(nkArgList, n.info, 1)
+    pp.sons[0] = n
+    putLazy(c, param, pp)
+
+proc matchNested(c: PPatternContext, p, n: PNode, rpn: bool): bool =
+  # match ``op * param`` or ``op *| param``
+  proc matchStarAux(c: PPatternContext, op, n, arglist: PNode,
+                    rpn: bool): bool =
+    result = true
+    if n.kind in nkCallKinds and matches(c, op.sons[1], n.sons[0]):
+      for i in 1..sonsLen(n)-1:
+        if not matchStarAux(c, op, n[i], arglist, rpn): return false
+      if rpn: arglist.add(n.sons[0])
+    elif n.kind == nkHiddenStdConv and n.sons[1].kind == nkBracket:
+      let n = n.sons[1]
+      for i in 0.. <n.len: 
+        if not matchStarAux(c, op, n[i], arglist, rpn): return false
+    elif checkTypes(c, p.sons[2].sym, n):
+      add(arglist, n)
+    else:
+      result = false
+    
+  if n.kind notin nkCallKinds: return false
+  if matches(c, p.sons[1], n.sons[0]):
+    var arglist = newNodeI(nkArgList, n.info)
+    if matchStarAux(c, p, n, arglist, rpn):
+      result = bindOrCheck(c, p.sons[2].sym, arglist)
+
+proc matches(c: PPatternContext, p, n: PNode): bool =
+  # hidden conversions (?)
+  if isPatternParam(c, p):
+    result = bindOrCheck(c, p.sym, n)
+  elif n.kind == nkSym and p.kind == nkIdent:
+    result = p.ident.id == n.sym.name.id
+  elif n.kind == nkSym and inSymChoice(p, n):
+    result = true
+  elif n.kind == nkSym and n.sym.kind == skConst:
+    # try both:
+    if p.kind == nkSym: result = p.sym == n.sym
+    elif matches(c, p, n.sym.ast): result = true
+  elif p.kind == nkPattern:
+    # pattern operators: | *
+    let opr = p.sons[0].ident.s
+    case opr
+    of "|": result = matchChoice(c, p, n)
+    of "*": result = matchNested(c, p, n, rpn=false)
+    of "**": result = matchNested(c, p, n, rpn=true)
+    of "~": result = not matches(c, p.sons[1], n)
+    else: internalError(p.info, "invalid pattern")
+    # template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) = 
+    #   add(a, b)
+  elif p.kind == nkCurlyExpr:
+    if p.sons[1].kind == nkPrefix:
+      if matches(c, p.sons[0], n):
+        gather(c, p.sons[1].sons[1].sym, n)
+        result = true
+    else:
+      assert isPatternParam(c, p.sons[1])
+      if matches(c, p.sons[0], n):
+        result = bindOrCheck(c, p.sons[1].sym, n)
+  elif sameKinds(p, n):
+    case p.kind
+    of nkSym: result = p.sym == n.sym
+    of nkIdent: result = p.ident.id == n.ident.id
+    of nkCharLit..nkInt64Lit: result = p.intVal == n.intVal
+    of nkFloatLit..nkFloat64Lit: result = p.floatVal == n.floatVal
+    of nkStrLit..nkTripleStrLit: result = p.strVal == n.strVal
+    of nkEmpty, nkNilLit, nkType:
+      result = true
+    else:
+      var plen = sonsLen(p)
+      # special rule for p(X) ~ f(...); this also works for stuff like
+      # partial case statements, etc! - Not really ... :-/
+      let v = lastSon(p)
+      if isPatternParam(c, v) and v.sym.typ.kind == tyVarargs:
+        var arglist: PNode
+        if plen <= sonsLen(n):
+          for i in countup(0, plen - 2):
+            if not matches(c, p.sons[i], n.sons[i]): return
+          if plen == sonsLen(n) and lastSon(n).kind == nkHiddenStdConv and
+              lastSon(n).sons[1].kind == nkBracket:
+            # unpack varargs:
+            let n = lastSon(n).sons[1]
+            arglist = newNodeI(nkArgList, n.info, n.len)
+            for i in 0.. <n.len: arglist.sons[i] = n.sons[i]
+          else:
+            arglist = newNodeI(nkArgList, n.info, sonsLen(n) - plen + 1)
+            # f(1, 2, 3)
+            # p(X)
+            for i in countup(0, sonsLen(n) - plen):
+              arglist.sons[i] = n.sons[i + plen - 1]
+          return bindOrCheck(c, v.sym, arglist)
+        elif plen-1 == sonsLen(n):
+          for i in countup(0, plen - 2):
+            if not matches(c, p.sons[i], n.sons[i]): return
+          arglist = newNodeI(nkArgList, n.info)
+          return bindOrCheck(c, v.sym, arglist)
+      if plen == sonsLen(n):
+        for i in countup(0, sonsLen(p) - 1):
+          if not matches(c, p.sons[i], n.sons[i]): return
+        result = true
+
+proc matchStmtList(c: PPatternContext, p, n: PNode): PNode =
+  proc matchRange(c: PPatternContext, p, n: PNode, i: int): bool =
+    for j in 0 .. <p.len:
+      if not matches(c, p.sons[j], n.sons[i+j]):
+        # we need to undo any bindings:
+        if not isNil(c.mapping): c.mapping = nil
+        return false
+    result = true
+  
+  if p.kind == nkStmtList and n.kind == p.kind and p.len < n.len:
+    let n = flattenStmts(n)
+    # no need to flatten 'p' here as that has already been done
+    for i in 0 .. n.len - p.len:
+      if matchRange(c, p, n, i):
+        c.subMatch = true
+        result = newNodeI(nkStmtList, n.info, 3)
+        result.sons[0] = extractRange(nkStmtList, n, 0, i-1)
+        result.sons[1] = extractRange(nkStmtList, n, i, i+p.len-1)
+        result.sons[2] = extractRange(nkStmtList, n, i+p.len, n.len-1)
+        break
+  elif matches(c, p, n):
+    result = n
+
+proc aliasAnalysisRequested(params: PNode): bool =
+  if params.len >= 2:
+    for i in 1 .. < params.len:
+      let param = params.sons[i].sym
+      if whichAlias(param) != aqNone: return true
+
+proc addToArgList(result, n: PNode) =
+  if n.typ != nil and n.typ.kind != tyStmt:
+    if n.kind != nkArgList: result.add(n)
+    else:
+      for i in 0 .. <n.len: result.add(n.sons[i])
+
+proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
+  ## returns a tree to semcheck if the rule triggered; nil otherwise
+  var ctx: TPatternContext
+  ctx.owner = s
+  ctx.c = c
+  ctx.formals = sonsLen(s.typ)-1
+  var m = matchStmtList(ctx, s.ast.sons[patternPos], n)
+  if isNil(m): return nil
+  # each parameter should have been bound; we simply setup a call and
+  # let semantic checking deal with the rest :-)
+  result = newNodeI(nkCall, n.info)
+  result.add(newSymNode(s, n.info))
+  let params = s.typ.n
+  let requiresAA = aliasAnalysisRequested(params)
+  var args: PNode
+  if requiresAA:
+    args = newNodeI(nkArgList, n.info)
+  for i in 1 .. < params.len:
+    let param = params.sons[i].sym
+    let x = getLazy(ctx, param)
+    # couldn't bind parameter:
+    if isNil(x): return nil
+    result.add(x)
+    if requiresAA: addToArgList(args, x)
+  # perform alias analysis here:
+  if requiresAA:
+    for i in 1 .. < params.len:
+      var rs = result.sons[i]
+      let param = params.sons[i].sym
+      case whichAlias(param)
+      of aqNone: discard
+      of aqShouldAlias:
+        # it suffices that it aliases for sure with *some* other param:
+        var ok = false
+        for arg in items(args):
+          if arg != rs and aliases.isPartOf(rs, arg) == arYes:
+            ok = true
+            break
+        # constraint not fulfilled:
+        if not ok: return nil
+      of aqNoAlias:
+        # it MUST not alias with any other param:
+        var ok = true
+        for arg in items(args):
+          if arg != rs and aliases.isPartOf(rs, arg) != arNo:
+            ok = false
+            break
+        # constraint not fulfilled:
+        if not ok: return nil
+
+  markUsed(n.info, s)
+  if ctx.subMatch:
+    assert m.len == 3
+    m.sons[1] = result
+    result = m
diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim
new file mode 100644
index 000000000..cf4dbffc5
--- /dev/null
+++ b/compiler/pbraces.nim
@@ -0,0 +1,18 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import 
+  llstream, lexer, parser, idents, strutils, ast, msgs
+
+proc parseAll*(p: var TParser): PNode = 
+  result = nil
+
+proc parseTopLevelStmt*(p: var TParser): PNode = 
+  result = nil
+
diff --git a/compiler/platform.nim b/compiler/platform.nim
new file mode 100644
index 000000000..4dd5d8836
--- /dev/null
+++ b/compiler/platform.nim
@@ -0,0 +1,228 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module contains data about the different processors
+# and operating systems.
+# Note: Unfortunately if an OS or CPU is listed here this does not mean that
+# Nimrod has been tested on this platform or that the RTL has been ported.
+# Feel free to test for your excentric platform!
+
+import
+  strutils
+
+type
+  TSystemOS* = enum # Also add OS in initialization section and alias
+                    # conditionals to condsyms (end of module).
+    osNone, osDos, osWindows, osOs2, osLinux, osMorphos, osSkyos, osSolaris,
+    osIrix, osNetbsd, osFreebsd, osOpenbsd, osAix, osPalmos, osQnx, osAmiga,
+    osAtari, osNetware, osMacos, osMacosx, osHaiku, osVxworks,
+    osJS, osNimrodVM, osStandalone
+
+type
+  TInfoOSProp* = enum
+    ospNeedsPIC,              # OS needs PIC for libraries
+    ospCaseInsensitive,       # OS filesystem is case insensitive
+    ospPosix,                 # OS is posix-like
+    ospLacksThreadVars        # OS lacks proper __threadvar support
+  TInfoOSProps* = set[TInfoOSProp]
+  TInfoOS* = tuple[name: string, parDir: string, dllFrmt: string,
+                   altDirSep: string, objExt: string, newLine: string,
+                   pathSep: string, dirSep: string, scriptExt: string,
+                   curDir: string, exeExt: string, extSep: string,
+                   props: TInfoOSProps]
+
+const
+  OS*: array[succ(low(TSystemOS))..high(TSystemOS), TInfoOS] = [
+     (name: "DOS",
+      parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", objExt: ".obj",
+      newLine: "\x0D\x0A", pathSep: ";", dirSep: "\\", scriptExt: ".bat",
+      curDir: ".", exeExt: ".exe", extSep: ".", props: {ospCaseInsensitive}),
+     (name: "Windows", parDir: "..", dllFrmt: "$1.dll", altDirSep: "/",
+      objExt: ".obj", newLine: "\x0D\x0A", pathSep: ";", dirSep: "\\",
+      scriptExt: ".bat", curDir: ".", exeExt: ".exe", extSep: ".",
+      props: {ospCaseInsensitive}),
+     (name: "OS2", parDir: "..",
+      dllFrmt: "$1.dll", altDirSep: "/",
+      objExt: ".obj", newLine: "\x0D\x0A",
+      pathSep: ";", dirSep: "\\",
+      scriptExt: ".bat", curDir: ".",
+      exeExt: ".exe", extSep: ".",
+      props: {ospCaseInsensitive}),
+     (name: "Linux", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "MorphOS", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "SkyOS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "Solaris", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "Irix", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "NetBSD", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "FreeBSD", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "OpenBSD", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "AIX", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix}),
+     (name: "PalmOS", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".",
+      props: {ospNeedsPIC}),
+     (name: "QNX",
+      parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o",
+      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".", props: {ospNeedsPIC, ospPosix}),
+     (name: "Amiga",
+      parDir: "..", dllFrmt: "$1.library", altDirSep: "/", objExt: ".o",
+      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".", props: {ospNeedsPIC}),
+     (name: "Atari",
+      parDir: "..", dllFrmt: "$1.dll", altDirSep: "/", objExt: ".o",
+      newLine: "\x0A", pathSep: ":", dirSep: "/", scriptExt: "", curDir: ".",
+      exeExt: ".tpp", extSep: ".", props: {ospNeedsPIC}),
+     (name: "Netware",
+      parDir: "..", dllFrmt: "$1.nlm", altDirSep: "/", objExt: "",
+      newLine: "\x0D\x0A", pathSep: ":", dirSep: "/", scriptExt: ".sh",
+      curDir: ".", exeExt: ".nlm", extSep: ".", props: {ospCaseInsensitive}),
+     (name: "MacOS", parDir: "::", dllFrmt: "$1Lib", altDirSep: ":",
+      objExt: ".o", newLine: "\x0D", pathSep: ",", dirSep: ":", scriptExt: "",
+      curDir: ":", exeExt: "", extSep: ".", props: {ospCaseInsensitive}),
+     (name: "MacOSX", parDir: "..", dllFrmt: "lib$1.dylib", altDirSep: ":",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "Haiku", parDir: "..", dllFrmt: "lib$1.so", altDirSep: ":",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
+      scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
+      props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
+     (name: "JS", parDir: "..",
+      dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A",
+      pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".",
+      exeExt: "", extSep: ".", props: {}),
+     (name: "NimrodVM", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
+     (name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
+      objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
+      scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
+      props: {})]
+
+type
+  TSystemCPU* = enum # Also add CPU for in initialization section and
+                     # alias conditionals to condsyms (end of module).
+    cpuNone, cpuI386, cpuM68k, cpuAlpha, cpuPowerpc, cpuPowerpc64,
+    cpuSparc, cpuVm, cpuIa64, cpuAmd64, cpuMips, cpuArm,
+    cpuJS, cpuNimrodVM, cpuAVR
+
+type
+  TEndian* = enum
+    littleEndian, bigEndian
+  TInfoCPU* = tuple[name: string, intSize: int, endian: TEndian,
+                    floatSize, bit: int]
+
+const
+  EndianToStr*: array[TEndian, string] = ["littleEndian", "bigEndian"]
+  CPU*: array[succ(low(TSystemCPU))..high(TSystemCPU), TInfoCPU] = [
+    (name: "i386", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
+    (name: "m68k", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "alpha", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
+    (name: "powerpc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "powerpc64", intSize: 64, endian: bigEndian, floatSize: 64,bit: 64),
+    (name: "sparc", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "vm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
+    (name: "ia64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
+    (name: "amd64", intSize: 64, endian: littleEndian, floatSize: 64, bit: 64),
+    (name: "mips", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "arm", intSize: 32, endian: littleEndian, floatSize: 64, bit: 32),
+    (name: "js", intSize: 32, endian: bigEndian,floatSize: 64,bit: 32),
+    (name: "nimrodvm", intSize: 32, endian: bigEndian, floatSize: 64, bit: 32),
+    (name: "avr", intSize: 16, endian: littleEndian, floatSize: 32, bit: 16)]
+
+var
+  targetCPU*, hostCPU*: TSystemCPU
+  targetOS*, hostOS*: TSystemOS
+
+proc nameToOS*(name: string): TSystemOS
+proc nameToCPU*(name: string): TSystemCPU
+
+var
+  intSize*: int
+  floatSize*: int
+  ptrSize*: int
+  tnl*: string                # target newline
+
+proc setTarget*(o: TSystemOS, c: TSystemCPU) =
+  assert(c != cpuNone)
+  assert(o != osNone)
+  #echo "new Target: OS: ", o, " CPU: ", c
+  targetCPU = c
+  targetOS = o
+  intSize = CPU[c].intSize div 8
+  floatSize = CPU[c].floatSize div 8
+  ptrSize = CPU[c].bit div 8
+  tnl = OS[o].newLine
+
+proc nameToOS(name: string): TSystemOS =
+  for i in countup(succ(osNone), high(TSystemOS)):
+    if cmpIgnoreStyle(name, OS[i].name) == 0:
+      return i
+  result = osNone
+
+proc nameToCPU(name: string): TSystemCPU =
+  for i in countup(succ(cpuNone), high(TSystemCPU)):
+    if cmpIgnoreStyle(name, CPU[i].name) == 0:
+      return i
+  result = cpuNone
+
+hostCPU = nameToCPU(system.hostCPU)
+hostOS = nameToOS(system.hostOS)
+
+setTarget(hostOS, hostCPU) # assume no cross-compiling
+
diff --git a/compiler/plugins.nim b/compiler/plugins.nim
new file mode 100644
index 000000000..1c9b7b77b
--- /dev/null
+++ b/compiler/plugins.nim
@@ -0,0 +1,43 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Plugin support for the Nim compiler. Right now there are no plugins and they
+## need to be build with the compiler, no DLL support.
+
+import ast, semdata, idents
+
+type
+  Transformation* = proc (c: PContext; n: PNode): PNode {.nimcall.}
+  Plugin = ref object
+    fn, module, package: PIdent
+    t: Transformation
+    next: Plugin
+
+proc pluginMatches(p: Plugin; s: PSym): bool =
+  if s.name.id != p.fn.id: return false
+  let module = s.owner
+  if module == nil or module.kind != skModule or
+      module.name.id != p.module.id: return false
+  let package = module.owner
+  if package == nil or package.kind != skPackage or
+      package.name.id != p.package.id: return false
+  return true
+
+var head: Plugin
+
+proc getPlugin*(fn: PSym): Transformation =
+  var it = head
+  while it != nil:
+    if pluginMatches(it, fn): return it.t
+    it = it.next
+
+proc registerPlugin*(package, module, fn: string; t: Transformation) =
+  let oldHead = head
+  head = Plugin(fn: getIdent(fn), module: getIdent(module),
+                 package: getIdent(package), t: t, next: oldHead)
diff --git a/compiler/plugins/active.nim b/compiler/plugins/active.nim
new file mode 100644
index 000000000..e9c11c2ea
--- /dev/null
+++ b/compiler/plugins/active.nim
@@ -0,0 +1,13 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Include file that imports all plugins that are active.
+
+import
+  locals.locals
diff --git a/compiler/plugins/locals/locals.nim b/compiler/plugins/locals/locals.nim
new file mode 100644
index 000000000..d89149f33
--- /dev/null
+++ b/compiler/plugins/locals/locals.nim
@@ -0,0 +1,42 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The builtin 'system.locals' implemented as a plugin.
+
+import plugins, ast, astalgo, magicsys, lookups, semdata, lowerings
+
+proc semLocals(c: PContext, n: PNode): PNode =
+  var counter = 0
+  var tupleType = newTypeS(tyTuple, c)
+  result = newNodeIT(nkPar, n.info, tupleType)
+  tupleType.n = newNodeI(nkRecList, n.info)
+  # for now we skip openarrays ...
+  for scope in walkScopes(c.currentScope):
+    if scope == c.topLevelScope: break
+    for it in items(scope.symbols):
+      # XXX parameters' owners are wrong for generics; this caused some pain
+      # for closures too; we should finally fix it.
+      #if it.owner != c.p.owner: return result
+      if it.kind in skLocalVars and
+          it.typ.skipTypes({tyGenericInst, tyVar}).kind notin
+            {tyVarargs, tyOpenArray, tyTypeDesc, tyStatic, tyExpr, tyStmt, tyEmpty}:
+
+        var field = newSym(skField, it.name, getCurrOwner(), n.info)
+        field.typ = it.typ.skipTypes({tyGenericInst, tyVar})
+        field.position = counter
+        inc(counter)
+
+        addSon(tupleType.n, newSymNode(field))
+        addSonSkipIntLit(tupleType, field.typ)
+
+        var a = newSymNode(it, result.info)
+        if it.typ.skipTypes({tyGenericInst}).kind == tyVar: a = newDeref(a)
+        result.add(a)
+
+registerPlugin("stdlib", "system", "locals", semLocals)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
new file mode 100644
index 000000000..c048d78e9
--- /dev/null
+++ b/compiler/pragmas.nim
@@ -0,0 +1,909 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements semantic checking for pragmas
+
+import
+  os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer,
+  wordrecg, ropes, options, strutils, lists, extccomp, math, magicsys, trees,
+  rodread, types, lookups
+
+const
+  FirstCallConv* = wNimcall
+  LastCallConv* = wNoconv
+
+const
+  procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
+    wMagic, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
+    wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
+    wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
+    wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
+    wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
+    wOverride, wConstructor}
+  converterPragmas* = procPragmas
+  methodPragmas* = procPragmas
+  templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
+    wDelegator}
+  macroPragmas* = {FirstCallConv..LastCallConv, wImmediate, wImportc, wExportc,
+    wNodecl, wMagic, wNosideeffect, wCompilerproc, wDeprecated, wExtern,
+    wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator}
+  iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect,
+    wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
+    wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
+    wTags, wLocks, wGcSafe}
+  exprPragmas* = {wLine, wLocks}
+  stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
+    wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
+    wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError,
+    wFatal, wDefine, wUndef, wCompile, wLink, wLinksys, wPure, wPush, wPop,
+    wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
+    wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
+    wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
+    wInjectStmt, wDeprecated, wExperimental}
+  lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
+    wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
+    wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
+    wRaises, wLocks, wTags, wGcSafe}
+  typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
+    wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow,
+    wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
+    wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
+    wBorrow, wGcSafe}
+  fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
+    wImportCpp, wImportObjC, wError, wGuard}
+  varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
+    wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern,
+    wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
+    wGensym, wInject, wCodegenDecl, wGuard, wGoto}
+  constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
+    wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject}
+  letPragmas* = varPragmas
+  procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
+                      wThread, wRaises, wLocks, wTags, wGcSafe}
+  allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
+
+proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
+# implementation
+
+proc invalidPragma(n: PNode) =
+  localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
+
+proc pragmaAsm*(c: PContext, n: PNode): char =
+  result = '\0'
+  if n != nil:
+    for i in countup(0, sonsLen(n) - 1):
+      let it = n.sons[i]
+      if it.kind == nkExprColonExpr and it.sons[0].kind == nkIdent:
+        case whichKeyword(it.sons[0].ident)
+        of wSubsChar:
+          if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal))
+          else: invalidPragma(it)
+        else: invalidPragma(it)
+      else:
+        invalidPragma(it)
+
+proc setExternName(s: PSym, extname: string) =
+  s.loc.r = rope(extname % s.name.s)
+  if gCmd == cmdPretty and '$' notin extname:
+    # note that '{.importc.}' is transformed into '{.importc: "$1".}'
+    s.loc.flags.incl(lfFullExternalName)
+
+proc makeExternImport(s: PSym, extname: string) =
+  setExternName(s, extname)
+  incl(s.flags, sfImportc)
+  excl(s.flags, sfForward)
+
+proc validateExternCName(s: PSym, info: TLineInfo) =
+  ## Validates that the symbol name in s.loc.r is a valid C identifier.
+  ##
+  ## Valid identifiers are those alphanumeric including the underscore not
+  ## starting with a number. If the check fails, a generic error will be
+  ## displayed to the user.
+  let target = $s.loc.r
+  if target.len < 1 or target[0] notin IdentStartChars or
+      not target.allCharsInSet(IdentChars):
+    localError(info, errGenerated, "invalid exported symbol")
+
+proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname)
+  # XXX to fix make it work with nimrtl.
+  #if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
+  #  validateExternCName(s, info)
+  incl(s.flags, sfExportc)
+
+proc processImportCompilerProc(s: PSym, extname: string) =
+  setExternName(s, extname)
+  incl(s.flags, sfImportc)
+  excl(s.flags, sfForward)
+  incl(s.loc.flags, lfImportCompilerProc)
+
+proc processImportCpp(s: PSym, extname: string) =
+  setExternName(s, extname)
+  incl(s.flags, sfImportc)
+  incl(s.flags, sfInfixCall)
+  excl(s.flags, sfForward)
+  let m = s.getModule()
+  incl(m.flags, sfCompileToCpp)
+  extccomp.gMixedMode = true
+
+proc processImportObjC(s: PSym, extname: string) =
+  setExternName(s, extname)
+  incl(s.flags, sfImportc)
+  incl(s.flags, sfNamedParamCall)
+  excl(s.flags, sfForward)
+  let m = s.getModule()
+  incl(m.flags, sfCompileToObjC)
+
+proc newEmptyStrNode(n: PNode): PNode {.noinline.} =
+  result = newNodeIT(nkStrLit, n.info, getSysType(tyString))
+  result.strVal = ""
+
+proc getStrLitNode(c: PContext, n: PNode): PNode =
+  if n.kind != nkExprColonExpr:
+    localError(n.info, errStringLiteralExpected)
+    # error correction:
+    result = newEmptyStrNode(n)
+  else:
+    n.sons[1] = c.semConstExpr(c, n.sons[1])
+    case n.sons[1].kind
+    of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1]
+    else:
+      localError(n.info, errStringLiteralExpected)
+      # error correction:
+      result = newEmptyStrNode(n)
+
+proc expectStrLit(c: PContext, n: PNode): string =
+  result = getStrLitNode(c, n).strVal
+
+proc expectIntLit(c: PContext, n: PNode): int =
+  if n.kind != nkExprColonExpr:
+    localError(n.info, errIntLiteralExpected)
+  else:
+    n.sons[1] = c.semConstExpr(c, n.sons[1])
+    case n.sons[1].kind
+    of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal)
+    else: localError(n.info, errIntLiteralExpected)
+
+proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
+  if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
+  else: result = defaultStr
+
+proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
+  sym.constraint = getStrLitNode(c, n)
+
+proc processMagic(c: PContext, n: PNode, s: PSym) =
+  #if sfSystemModule notin c.module.flags:
+  #  liMessage(n.info, errMagicOnlyInSystem)
+  if n.kind != nkExprColonExpr:
+    localError(n.info, errStringLiteralExpected)
+    return
+  var v: string
+  if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s
+  else: v = expectStrLit(c, n)
+  for m in countup(low(TMagic), high(TMagic)):
+    if substr($m, 1) == v:
+      s.magic = m
+      break
+  if s.magic == mNone: message(n.info, warnUnknownMagic, v)
+
+proc wordToCallConv(sw: TSpecialWord): TCallingConvention =
+  # this assumes that the order of special words and calling conventions is
+  # the same
+  result = TCallingConvention(ord(ccDefault) + ord(sw) - ord(wNimcall))
+
+proc isTurnedOn(c: PContext, n: PNode): bool =
+  if n.kind == nkExprColonExpr:
+    let x = c.semConstBoolExpr(c, n.sons[1])
+    n.sons[1] = x
+    if x.kind == nkIntLit: return x.intVal != 0
+  localError(n.info, errOnOrOffExpected)
+
+proc onOff(c: PContext, n: PNode, op: TOptions) =
+  if isTurnedOn(c, n): gOptions = gOptions + op
+  else: gOptions = gOptions - op
+
+proc pragmaDeadCodeElim(c: PContext, n: PNode) =
+  if isTurnedOn(c, n): incl(c.module.flags, sfDeadCodeElim)
+  else: excl(c.module.flags, sfDeadCodeElim)
+
+proc pragmaNoForward(c: PContext, n: PNode) =
+  if isTurnedOn(c, n): incl(c.module.flags, sfNoForward)
+  else: excl(c.module.flags, sfNoForward)
+
+proc processCallConv(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
+    var sw = whichKeyword(n.sons[1].ident)
+    case sw
+    of FirstCallConv..LastCallConv:
+      POptionEntry(c.optionStack.tail).defaultCC = wordToCallConv(sw)
+    else: localError(n.info, errCallConvExpected)
+  else:
+    localError(n.info, errCallConvExpected)
+
+proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib =
+  var it = PLib(c.libs.head)
+  while it != nil:
+    if it.kind == kind:
+      if trees.exprStructuralEquivalent(it.path, path): return it
+    it = PLib(it.next)
+  result = newLib(kind)
+  result.path = path
+  append(c.libs, result)
+  if path.kind in {nkStrLit..nkTripleStrLit}:
+    result.isOverriden = options.isDynlibOverride(path.strVal)
+
+proc expectDynlibNode(c: PContext, n: PNode): PNode =
+  if n.kind != nkExprColonExpr:
+    localError(n.info, errStringLiteralExpected)
+    # error correction:
+    result = newEmptyStrNode(n)
+  else:
+    # For the OpenGL wrapper we support:
+    # {.dynlib: myGetProcAddr(...).}
+    result = c.semExpr(c, n.sons[1])
+    if result.kind == nkSym and result.sym.kind == skConst:
+      result = result.sym.ast # look it up
+    if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
+      localError(n.info, errStringLiteralExpected)
+      result = newEmptyStrNode(n)
+
+proc processDynLib(c: PContext, n: PNode, sym: PSym) =
+  if (sym == nil) or (sym.kind == skModule):
+    POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
+        expectDynlibNode(c, n))
+  else:
+    if n.kind == nkExprColonExpr:
+      var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
+      if not lib.isOverriden:
+        addToLib(lib, sym)
+        incl(sym.loc.flags, lfDynamicLib)
+    else:
+      incl(sym.loc.flags, lfExportLib)
+    # since we'll be loading the dynlib symbols dynamically, we must use
+    # a calling convention that doesn't introduce custom name mangling
+    # cdecl is the default - the user can override this explicitly
+    if sym.kind in routineKinds and sym.typ != nil and
+        sym.typ.callConv == ccDefault:
+      sym.typ.callConv = ccCDecl
+
+proc processNote(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
+      (n.sons[0].kind == nkBracketExpr) and
+      (n.sons[0].sons[1].kind == nkIdent) and
+      (n.sons[0].sons[0].kind == nkIdent) and (n.sons[1].kind == nkIdent):
+    var nk: TNoteKind
+    case whichKeyword(n.sons[0].sons[0].ident)
+    of wHint:
+      var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s)
+      if x >= 0: nk = TNoteKind(x + ord(hintMin))
+      else: invalidPragma(n); return
+    of wWarning:
+      var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s)
+      if x >= 0: nk = TNoteKind(x + ord(warnMin))
+      else: invalidPragma(n); return
+    else:
+      invalidPragma(n)
+      return
+
+    let x = c.semConstBoolExpr(c, n.sons[1])
+    n.sons[1] = x
+    if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk)
+    else: excl(gNotes, nk)
+  else:
+    invalidPragma(n)
+
+proc processOption(c: PContext, n: PNode): bool =
+  if n.kind != nkExprColonExpr: result = true
+  elif n.sons[0].kind == nkBracketExpr: processNote(c, n)
+  elif n.sons[0].kind != nkIdent: result = true
+  else:
+    var sw = whichKeyword(n.sons[0].ident)
+    case sw
+    of wChecks: onOff(c, n, ChecksOptions)
+    of wObjChecks: onOff(c, n, {optObjCheck})
+    of wFieldChecks: onOff(c, n, {optFieldCheck})
+    of wRangechecks: onOff(c, n, {optRangeCheck})
+    of wBoundchecks: onOff(c, n, {optBoundsCheck})
+    of wOverflowchecks: onOff(c, n, {optOverflowCheck})
+    of wNilchecks: onOff(c, n, {optNilCheck})
+    of wFloatchecks: onOff(c, n, {optNaNCheck, optInfCheck})
+    of wNanChecks: onOff(c, n, {optNaNCheck})
+    of wInfChecks: onOff(c, n, {optInfCheck})
+    of wAssertions: onOff(c, n, {optAssert})
+    of wWarnings: onOff(c, n, {optWarns})
+    of wHints: onOff(c, n, {optHints})
+    of wCallconv: processCallConv(c, n)
+    of wLinedir: onOff(c, n, {optLineDir})
+    of wStacktrace: onOff(c, n, {optStackTrace})
+    of wLinetrace: onOff(c, n, {optLineTrace})
+    of wDebugger: onOff(c, n, {optEndb})
+    of wProfiler: onOff(c, n, {optProfiler})
+    of wByRef: onOff(c, n, {optByRef})
+    of wDynlib: processDynLib(c, n, nil)
+    of wOptimization:
+      if n.sons[1].kind != nkIdent:
+        invalidPragma(n)
+      else:
+        case n.sons[1].ident.s.normalize
+        of "speed":
+          incl(gOptions, optOptimizeSpeed)
+          excl(gOptions, optOptimizeSize)
+        of "size":
+          excl(gOptions, optOptimizeSpeed)
+          incl(gOptions, optOptimizeSize)
+        of "none":
+          excl(gOptions, optOptimizeSpeed)
+          excl(gOptions, optOptimizeSize)
+        else: localError(n.info, errNoneSpeedOrSizeExpected)
+    of wImplicitStatic: onOff(c, n, {optImplicitStatic})
+    of wPatterns: onOff(c, n, {optPatterns})
+    else: result = true
+
+proc processPush(c: PContext, n: PNode, start: int) =
+  if n.sons[start-1].kind == nkExprColonExpr:
+    localError(n.info, errGenerated, "':' after 'push' not supported")
+  var x = newOptionEntry()
+  var y = POptionEntry(c.optionStack.tail)
+  x.options = gOptions
+  x.defaultCC = y.defaultCC
+  x.dynlib = y.dynlib
+  x.notes = gNotes
+  append(c.optionStack, x)
+  for i in countup(start, sonsLen(n) - 1):
+    if processOption(c, n.sons[i]):
+      # simply store it somewhere:
+      if x.otherPragmas.isNil:
+        x.otherPragmas = newNodeI(nkPragma, n.info)
+      x.otherPragmas.add n.sons[i]
+    #localError(n.info, errOptionExpected)
+
+proc processPop(c: PContext, n: PNode) =
+  if c.optionStack.counter <= 1:
+    localError(n.info, errAtPopWithoutPush)
+  else:
+    gOptions = POptionEntry(c.optionStack.tail).options
+    gNotes = POptionEntry(c.optionStack.tail).notes
+    remove(c.optionStack, c.optionStack.tail)
+
+proc processDefine(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
+    defineSymbol(n.sons[1].ident.s)
+    message(n.info, warnDeprecated, "define")
+  else:
+    invalidPragma(n)
+
+proc processUndef(c: PContext, n: PNode) =
+  if (n.kind == nkExprColonExpr) and (n.sons[1].kind == nkIdent):
+    undefSymbol(n.sons[1].ident.s)
+    message(n.info, warnDeprecated, "undef")
+  else:
+    invalidPragma(n)
+
+type
+  TLinkFeature = enum
+    linkNormal, linkSys
+
+proc processCompile(c: PContext, n: PNode) =
+  var s = expectStrLit(c, n)
+  var found = findFile(s)
+  if found == "": found = s
+  var trunc = changeFileExt(found, "")
+  extccomp.addExternalFileToCompile(found)
+  extccomp.addFileToLink(completeCFilePath(trunc, false))
+
+proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
+  var f = expectStrLit(c, n)
+  if splitFile(f).ext == "": f = addFileExt(f, CC[cCompiler].objExt)
+  var found = findFile(f)
+  if found == "": found = f # use the default
+  case feature
+  of linkNormal: extccomp.addFileToLink(found)
+  of linkSys:
+    extccomp.addFileToLink(libpath / completeCFilePath(found, false))
+  else: internalError(n.info, "processCommonLink")
+
+proc pragmaBreakpoint(c: PContext, n: PNode) =
+  discard getOptionalStr(c, n, "")
+
+proc pragmaWatchpoint(c: PContext, n: PNode) =
+  if n.kind == nkExprColonExpr:
+    n.sons[1] = c.semExpr(c, n.sons[1])
+  else:
+    invalidPragma(n)
+
+proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
+  case n.sons[1].kind
+  of nkStrLit, nkRStrLit, nkTripleStrLit:
+    result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info)
+    var str = n.sons[1].strVal
+    if str == "":
+      localError(n.info, errEmptyAsm)
+      return
+    # now parse the string literal and substitute symbols:
+    var a = 0
+    while true:
+      var b = strutils.find(str, marker, a)
+      var sub = if b < 0: substr(str, a) else: substr(str, a, b - 1)
+      if sub != "": addSon(result, newStrNode(nkStrLit, sub))
+      if b < 0: break
+      var c = strutils.find(str, marker, b + 1)
+      if c < 0: sub = substr(str, b + 1)
+      else: sub = substr(str, b + 1, c - 1)
+      if sub != "":
+        var e = searchInScopes(con, getIdent(sub))
+        if e != nil:
+          if e.kind == skStub: loadStub(e)
+          addSon(result, newSymNode(e))
+        else:
+          addSon(result, newStrNode(nkStrLit, sub))
+      else:
+        # an empty '``' produces a single '`'
+        addSon(result, newStrNode(nkStrLit, $marker))
+      if c < 0: break
+      a = c + 1
+  else:
+    illFormedAstLocal(n)
+    result = newNode(nkAsmStmt, n.info)
+
+proc pragmaEmit(c: PContext, n: PNode) =
+  discard getStrLitNode(c, n)
+  n.sons[1] = semAsmOrEmit(c, n, '`')
+
+proc noVal(n: PNode) =
+  if n.kind == nkExprColonExpr: invalidPragma(n)
+
+proc pragmaUnroll(c: PContext, n: PNode) =
+  if c.p.nestedLoopCounter <= 0:
+    invalidPragma(n)
+  elif n.kind == nkExprColonExpr:
+    var unrollFactor = expectIntLit(c, n)
+    if unrollFactor <% 32:
+      n.sons[1] = newIntNode(nkIntLit, unrollFactor)
+    else:
+      invalidPragma(n)
+
+proc pragmaLine(c: PContext, n: PNode) =
+  if n.kind == nkExprColonExpr:
+    n.sons[1] = c.semConstExpr(c, n.sons[1])
+    let a = n.sons[1]
+    if a.kind == nkPar:
+      var x = a.sons[0]
+      var y = a.sons[1]
+      if x.kind == nkExprColonExpr: x = x.sons[1]
+      if y.kind == nkExprColonExpr: y = y.sons[1]
+      if x.kind != nkStrLit:
+        localError(n.info, errStringLiteralExpected)
+      elif y.kind != nkIntLit:
+        localError(n.info, errIntLiteralExpected)
+      else:
+        n.info.fileIndex = msgs.fileInfoIdx(x.strVal)
+        n.info.line = int16(y.intVal)
+    else:
+      localError(n.info, errXExpected, "tuple")
+  else:
+    # sensible default:
+    n.info = getInfoContext(-1)
+
+proc processPragma(c: PContext, n: PNode, i: int) =
+  var it = n.sons[i]
+  if it.kind != nkExprColonExpr: invalidPragma(n)
+  elif it.sons[0].kind != nkIdent: invalidPragma(n)
+  elif it.sons[1].kind != nkIdent: invalidPragma(n)
+
+  var userPragma = newSym(skTemplate, it.sons[1].ident, nil, it.info)
+  var body = newNodeI(nkPragma, n.info)
+  for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j])
+  userPragma.ast = body
+  strTableAdd(c.userPragmas, userPragma)
+
+proc pragmaRaisesOrTags(c: PContext, n: PNode) =
+  proc processExc(c: PContext, x: PNode) =
+    var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs)
+    if t.kind != tyObject:
+      localError(x.info, errGenerated, "invalid type for raises/tags list")
+    x.typ = t
+
+  if n.kind == nkExprColonExpr:
+    let it = n.sons[1]
+    if it.kind notin {nkCurly, nkBracket}:
+      processExc(c, it)
+    else:
+      for e in items(it): processExc(c, e)
+  else:
+    invalidPragma(n)
+
+proc pragmaLockStmt(c: PContext; it: PNode) =
+  if it.kind != nkExprColonExpr:
+    invalidPragma(it)
+  else:
+    let n = it[1]
+    if n.kind != nkBracket:
+      localError(n.info, errGenerated, "locks pragma takes a list of expressions")
+    else:
+      for i in 0 .. <n.len:
+        n.sons[i] = c.semExpr(c, n.sons[i])
+
+proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
+  if it.kind != nkExprColonExpr:
+    invalidPragma(it)
+  else:
+    if it[1].kind != nkNilLit:
+      let x = expectIntLit(c, it)
+      if x < 0 or x > MaxLockLevel:
+        localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
+      else:
+        result = TLockLevel(x)
+
+proc typeBorrow(sym: PSym, n: PNode) =
+  if n.kind == nkExprColonExpr:
+    let it = n.sons[1]
+    if it.kind != nkAccQuoted:
+      localError(n.info, "a type can only borrow `.` for now")
+  incl(sym.typ.flags, tfBorrowDot)
+
+proc markCompilerProc(s: PSym) =
+  makeExternExport(s, "$1", s.info)
+  incl(s.flags, sfCompilerProc)
+  incl(s.flags, sfUsed)
+  registerCompilerProc(s)
+
+proc deprecatedStmt(c: PContext; pragma: PNode) =
+  let pragma = pragma[1]
+  if pragma.kind != nkBracket:
+    localError(pragma.info, "list of key:value pairs expected"); return
+  for n in pragma:
+    if n.kind in {nkExprColonExpr, nkExprEqExpr}:
+      let dest = qualifiedLookUp(c, n[1])
+      let src = considerQuotedIdent(n[0])
+      let alias = newSym(skAlias, src, dest, n[0].info)
+      incl(alias.flags, sfExported)
+      if sfCompilerProc in dest.flags: markCompilerProc(alias)
+      addInterfaceDecl(c, alias)
+    else:
+      localError(n.info, "key:value pair expected")
+
+proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
+  if it.kind != nkExprColonExpr:
+    invalidPragma(it); return
+  let n = it[1]
+  if n.kind == nkSym:
+    result = n.sym
+  elif kind == skField:
+    # First check if the guard is a global variable:
+    result = qualifiedLookUp(c, n, {})
+    if result.isNil or result.kind notin {skLet, skVar} or
+        sfGlobal notin result.flags:
+      # We return a dummy symbol; later passes over the type will repair it.
+      # Generic instantiation needs to know about this too. But we're lazy
+      # and perform the lookup on demand instead.
+      result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info)
+  else:
+    result = qualifiedLookUp(c, n)
+
+proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
+                  validPragmas: TSpecialWords): bool =
+  var it = n.sons[i]
+  var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
+  if key.kind == nkIdent:
+    var userPragma = strTableGet(c.userPragmas, key.ident)
+    if userPragma != nil:
+      inc c.instCounter
+      if c.instCounter > 100:
+        globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
+      pragma(c, sym, userPragma.ast, validPragmas)
+      # ensure the pragma is also remember for generic instantiations in other
+      # modules:
+      n.sons[i] = userPragma.ast
+      dec c.instCounter
+    else:
+      var k = whichKeyword(key.ident)
+      if k in validPragmas:
+        case k
+        of wExportc:
+          makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
+          incl(sym.flags, sfUsed) # avoid wrong hints
+        of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
+        of wImportCompilerProc:
+          processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
+        of wExtern: setExternName(sym, expectStrLit(c, it))
+        of wImmediate:
+          if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate)
+          else: invalidPragma(it)
+        of wDirty:
+          if sym.kind == skTemplate: incl(sym.flags, sfDirty)
+          else: invalidPragma(it)
+        of wImportCpp:
+          processImportCpp(sym, getOptionalStr(c, it, "$1"))
+        of wImportObjC:
+          processImportObjC(sym, getOptionalStr(c, it, "$1"))
+        of wAlign:
+          if sym.typ == nil: invalidPragma(it)
+          var align = expectIntLit(c, it)
+          if (not isPowerOfTwo(align) and align != 0) or align >% high(int16):
+            localError(it.info, errPowerOfTwoExpected)
+          else:
+            sym.typ.align = align.int16
+        of wSize:
+          if sym.typ == nil: invalidPragma(it)
+          var size = expectIntLit(c, it)
+          if not isPowerOfTwo(size) or size <= 0 or size > 8:
+            localError(it.info, errPowerOfTwoExpected)
+          else:
+            sym.typ.size = size
+        of wNodecl:
+          noVal(it)
+          incl(sym.loc.flags, lfNoDecl)
+        of wPure, wAsmNoStackFrame:
+          noVal(it)
+          if sym != nil:
+            if k == wPure and sym.kind in routineKinds: invalidPragma(it)
+            else: incl(sym.flags, sfPure)
+        of wVolatile:
+          noVal(it)
+          incl(sym.flags, sfVolatile)
+        of wRegister:
+          noVal(it)
+          incl(sym.flags, sfRegister)
+        of wThreadVar:
+          noVal(it)
+          incl(sym.flags, sfThread)
+        of wDeadCodeElim: pragmaDeadCodeElim(c, it)
+        of wNoForward: pragmaNoForward(c, it)
+        of wMagic: processMagic(c, it, sym)
+        of wCompileTime:
+          noVal(it)
+          incl(sym.flags, sfCompileTime)
+          incl(sym.loc.flags, lfNoDecl)
+        of wGlobal:
+          noVal(it)
+          incl(sym.flags, sfGlobal)
+          incl(sym.flags, sfPure)
+        of wMerge:
+          # only supported for backwards compat, doesn't do anything anymore
+          noVal(it)
+        of wConstructor:
+          noVal(it)
+          incl(sym.flags, sfConstructor)
+        of wHeader:
+          var lib = getLib(c, libHeader, getStrLitNode(c, it))
+          addToLib(lib, sym)
+          incl(sym.flags, sfImportc)
+          incl(sym.loc.flags, lfHeader)
+          incl(sym.loc.flags, lfNoDecl)
+          # implies nodecl, because otherwise header would not make sense
+          if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
+        of wDestructor:
+          sym.flags.incl sfOverriden
+          if sym.name.s.normalize != "destroy":
+            localError(n.info, errGenerated, "destructor has to be named 'destroy'")
+        of wOverride:
+          sym.flags.incl sfOverriden
+        of wNosideeffect:
+          noVal(it)
+          incl(sym.flags, sfNoSideEffect)
+          if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
+        of wSideeffect:
+          noVal(it)
+          incl(sym.flags, sfSideEffect)
+        of wNoreturn:
+          noVal(it)
+          incl(sym.flags, sfNoReturn)
+        of wDynlib:
+          processDynLib(c, it, sym)
+        of wCompilerproc:
+          noVal(it)           # compilerproc may not get a string!
+          if sfFromGeneric notin sym.flags: markCompilerProc(sym)
+        of wProcVar:
+          noVal(it)
+          incl(sym.flags, sfProcvar)
+        of wDeprecated:
+          if it.kind == nkExprColonExpr: deprecatedStmt(c, it)
+          elif sym != nil: incl(sym.flags, sfDeprecated)
+          else: incl(c.module.flags, sfDeprecated)
+        of wVarargs:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfVarargs)
+        of wBorrow:
+          if sym.kind == skType:
+            typeBorrow(sym, it)
+          else:
+            noVal(it)
+            incl(sym.flags, sfBorrow)
+        of wFinal:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfFinal)
+        of wInheritable:
+          noVal(it)
+          if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
+          else: incl(sym.typ.flags, tfInheritable)
+        of wAcyclic:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfAcyclic)
+        of wShallow:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfShallow)
+        of wThread:
+          noVal(it)
+          incl(sym.flags, sfThread)
+          incl(sym.flags, sfProcvar)
+          if sym.typ != nil: incl(sym.typ.flags, tfThread)
+        of wGcSafe:
+          noVal(it)
+          if sym.kind != skType: incl(sym.flags, sfThread)
+          if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
+          else: invalidPragma(it)
+        of wPacked:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfPacked)
+        of wHint: message(it.info, hintUser, expectStrLit(c, it))
+        of wWarning: message(it.info, warnUser, expectStrLit(c, it))
+        of wError:
+          if sym != nil and sym.isRoutine:
+            # This is subtle but correct: the error *statement* is only
+            # allowed for top level statements. Seems to be easier than
+            # distinguishing properly between
+            # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
+            noVal(it)
+            incl(sym.flags, sfError)
+          else:
+            localError(it.info, errUser, expectStrLit(c, it))
+        of wFatal: fatal(it.info, errUser, expectStrLit(c, it))
+        of wDefine: processDefine(c, it)
+        of wUndef: processUndef(c, it)
+        of wCompile: processCompile(c, it)
+        of wLink: processCommonLink(c, it, linkNormal)
+        of wLinksys: processCommonLink(c, it, linkSys)
+        of wPassl: extccomp.addLinkOption(expectStrLit(c, it))
+        of wPassc: extccomp.addCompileOption(expectStrLit(c, it))
+        of wBreakpoint: pragmaBreakpoint(c, it)
+        of wWatchPoint: pragmaWatchpoint(c, it)
+        of wPush:
+          processPush(c, n, i + 1)
+          result = true
+        of wPop: processPop(c, it)
+        of wPragma:
+          processPragma(c, n, i)
+          result = true
+        of wDiscardable:
+          noVal(it)
+          if sym != nil: incl(sym.flags, sfDiscardable)
+        of wNoInit:
+          noVal(it)
+          if sym != nil: incl(sym.flags, sfNoInit)
+        of wCodegenDecl: processCodegenDecl(c, it, sym)
+        of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
+           wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
+           wLinedir, wStacktrace, wLinetrace, wOptimization,
+           wCallconv,
+           wDebugger, wProfiler, wFloatchecks, wNanChecks, wInfChecks,
+           wPatterns:
+          if processOption(c, it):
+            # calling conventions (boring...):
+            localError(it.info, errOptionExpected)
+        of FirstCallConv..LastCallConv:
+          assert(sym != nil)
+          if sym.typ == nil: invalidPragma(it)
+          else: sym.typ.callConv = wordToCallConv(k)
+        of wEmit: pragmaEmit(c, it)
+        of wUnroll: pragmaUnroll(c, it)
+        of wLinearScanEnd, wComputedGoto: noVal(it)
+        of wEffects:
+          # is later processed in effect analysis:
+          noVal(it)
+        of wIncompleteStruct:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfIncompleteStruct)
+        of wUnchecked:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfUncheckedArray)
+        of wUnion:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfUnion)
+        of wRequiresInit:
+          noVal(it)
+          if sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfNeedsInit)
+        of wByRef:
+          noVal(it)
+          if sym == nil or sym.typ == nil:
+            if processOption(c, it): localError(it.info, errOptionExpected)
+          else:
+            incl(sym.typ.flags, tfByRef)
+        of wByCopy:
+          noVal(it)
+          if sym.kind != skType or sym.typ == nil: invalidPragma(it)
+          else: incl(sym.typ.flags, tfByCopy)
+        of wInject, wGensym:
+          # We check for errors, but do nothing with these pragmas otherwise
+          # as they are handled directly in 'evalTemplate'.
+          noVal(it)
+          if sym == nil: invalidPragma(it)
+        of wLine: pragmaLine(c, it)
+        of wRaises, wTags: pragmaRaisesOrTags(c, it)
+        of wLocks:
+          if sym == nil: pragmaLockStmt(c, it)
+          elif sym.typ == nil: invalidPragma(it)
+          else: sym.typ.lockLevel = pragmaLocks(c, it)
+        of wGuard:
+          if sym == nil or sym.kind notin {skVar, skLet, skField}:
+            invalidPragma(it)
+          else:
+            sym.guard = pragmaGuard(c, it, sym.kind)
+        of wGoto:
+          if sym == nil or sym.kind notin {skVar, skLet}:
+            invalidPragma(it)
+          else:
+            sym.flags.incl sfGoto
+        of wInjectStmt:
+          if it.kind != nkExprColonExpr:
+            localError(it.info, errExprExpected)
+          else:
+            it.sons[1] = c.semExpr(c, it.sons[1])
+        of wExperimental:
+          noVal(it)
+          if isTopLevel(c):
+            c.module.flags.incl sfExperimental
+          else:
+            localError(it.info, "'experimental' pragma only valid as toplevel statement")
+        else: invalidPragma(it)
+      else: invalidPragma(it)
+  else: processNote(c, it)
+
+proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
+                      validPragmas: TSpecialWords) =
+  if sym != nil and sym.kind != skModule:
+    var it = POptionEntry(c.optionStack.head)
+    while it != nil:
+      let o = it.otherPragmas
+      if not o.isNil:
+        pushInfoContext(n.info)
+        for i in countup(0, sonsLen(o) - 1):
+          if singlePragma(c, sym, o, i, validPragmas):
+            internalError(n.info, "implicitPragmas")
+        popInfoContext()
+      it = it.next.POptionEntry
+
+    if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
+      localError(n.info, errDynlibRequiresExportc)
+    var lib = POptionEntry(c.optionStack.tail).dynlib
+    if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and
+        sfImportc in sym.flags and lib != nil:
+      incl(sym.loc.flags, lfDynamicLib)
+      addToLib(lib, sym)
+      if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
+
+proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
+  if n == nil or n.sons == nil:
+    return false
+
+  for p in n.sons:
+    var key = if p.kind == nkExprColonExpr: p[0] else: p
+    if key.kind == nkIdent and whichKeyword(key.ident) == pragma:
+      return true
+
+  return false
+
+proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
+  if n == nil: return
+  for i in countup(0, sonsLen(n) - 1):
+    if n.sons[i].kind == nkPragma: pragmaRec(c, sym, n.sons[i], validPragmas)
+    elif singlePragma(c, sym, n, i, validPragmas): break
+
+proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
+  if n == nil: return
+  pragmaRec(c, sym, n, validPragmas)
+  implicitPragmas(c, sym, n, validPragmas)
diff --git a/compiler/procfind.nim b/compiler/procfind.nim
new file mode 100644
index 000000000..473965a3d
--- /dev/null
+++ b/compiler/procfind.nim
@@ -0,0 +1,129 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the searching for procs and iterators.
+# This is needed for proper handling of forward declarations.
+
+import
+  ast, astalgo, msgs, semdata, types, trees, strutils
+
+proc equalGenericParams(procA, procB: PNode): bool =
+  if sonsLen(procA) != sonsLen(procB): return
+  for i in countup(0, sonsLen(procA) - 1):
+    if procA.sons[i].kind != nkSym:
+      internalError(procA.info, "equalGenericParams")
+      return
+    if procB.sons[i].kind != nkSym:
+      internalError(procB.info, "equalGenericParams")
+      return
+    let a = procA.sons[i].sym
+    let b = procB.sons[i].sym
+    if a.name.id != b.name.id or
+        not sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}): return
+    if a.ast != nil and b.ast != nil:
+      if not exprStructuralEquivalent(a.ast, b.ast): return
+  result = true
+
+proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
+  # Searchs for a forward declaration or a "twin" symbol of fn
+  # in the symbol table. If the parameter lists are exactly
+  # the same the sym in the symbol table is returned, else nil.
+  var it: TIdentIter
+  result = initIdentIter(it, scope.symbols, fn.name)
+  if isGenericRoutine(fn):
+    # we simply check the AST; this is imprecise but nearly the best what
+    # can be done; this doesn't work either though as type constraints are
+    # not kept in the AST ..
+    while result != nil:
+      if result.kind == fn.kind and isGenericRoutine(result):
+        let genR = result.ast.sons[genericParamsPos]
+        let genF = fn.ast.sons[genericParamsPos]
+        if exprStructuralEquivalent(genR, genF) and
+           exprStructuralEquivalent(result.ast.sons[paramsPos],
+                                    fn.ast.sons[paramsPos]) and
+           equalGenericParams(genR, genF):
+            return
+      result = nextIdentIter(it, scope.symbols)
+  else:
+    while result != nil:
+      if result.kind == fn.kind and not isGenericRoutine(result):
+        case equalParams(result.typ.n, fn.typ.n)
+        of paramsEqual:
+          return
+        of paramsIncompatible:
+          localError(fn.info, errNotOverloadable, fn.name.s)
+          return
+        of paramsNotEqual:
+          discard
+      result = nextIdentIter(it, scope.symbols)
+
+proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
+  const flags = {ExactGenericParams, ExactTypeDescValues,
+                 ExactConstraints, IgnoreCC}
+
+  var it: TIdentIter
+
+  result = initIdentIter(it, scope.symbols, fn.name)
+  while result != nil:
+    if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
+      case equalParams(result.typ.n, fn.typ.n)
+      of paramsEqual:
+        if (sfExported notin result.flags) and (sfExported in fn.flags):
+          let message = ("public implementation '$1' has non-public " &
+                         "forward declaration in $2") %
+                        [getProcHeader(result), $result.info]
+          localError(fn.info, errGenerated, message)
+        return
+      of paramsIncompatible:
+        localError(fn.info, errNotOverloadable, fn.name.s)
+        return
+      of paramsNotEqual:
+        discard
+
+    result = nextIdentIter(it, scope.symbols)
+  
+  return nil
+
+proc searchForProc*(c: PContext, scope: PScope, fn: PSym): PSym =
+  result = searchForProcNew(c, scope, fn)
+  when false:
+    let old = searchForProcOld(c, scope, fn)
+    if old != result:
+      echo "Mismatch in searchForProc: ", fn.info
+      debug fn.typ
+      debug if result != nil: result.typ else: nil
+      debug if old != nil: old.typ else: nil
+ 
+when false:
+  proc paramsFitBorrow(child, parent: PNode): bool = 
+    var length = sonsLen(child)
+    result = false
+    if length == sonsLen(parent): 
+      for i in countup(1, length - 1): 
+        var m = child.sons[i].sym
+        var n = parent.sons[i].sym
+        assert((m.kind == skParam) and (n.kind == skParam))
+        if not compareTypes(m.typ, n.typ, dcEqOrDistinctOf): return 
+      if not compareTypes(child.sons[0].typ, parent.sons[0].typ,
+                          dcEqOrDistinctOf): return
+      result = true
+
+  proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
+    # Searchs for the fn in the symbol table. If the parameter lists are suitable
+    # for borrowing the sym in the symbol table is returned, else nil.
+    var it: TIdentIter
+    for scope in walkScopes(startScope):
+      result = initIdentIter(it, scope.symbols, fn.Name)
+      while result != nil: 
+        # watchout! result must not be the same as fn!
+        if (result.Kind == fn.kind) and (result.id != fn.id): 
+          if equalGenericParams(result.ast.sons[genericParamsPos], 
+                                fn.ast.sons[genericParamsPos]): 
+            if paramsFitBorrow(fn.typ.n, result.typ.n): return 
+        result = NextIdentIter(it, scope.symbols)
diff --git a/compiler/readme.txt b/compiler/readme.txt
new file mode 100644
index 000000000..c4934e031
--- /dev/null
+++ b/compiler/readme.txt
@@ -0,0 +1,4 @@
+This directory contains the Nim compiler written in Nim. Note that this
+code has been translated from a bootstrapping version written in Pascal, so
+the code is **not** a poster child of good Nim code.
+
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
new file mode 100644
index 000000000..ffdb60696
--- /dev/null
+++ b/compiler/renderer.nim
@@ -0,0 +1,1363 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the renderer of the standard Nim representation.
+
+import
+  lexer, options, idents, strutils, ast, msgs, lists
+
+type
+  TRenderFlag* = enum
+    renderNone, renderNoBody, renderNoComments, renderDocComments,
+    renderNoPragmas, renderIds, renderNoProcDefs
+  TRenderFlags* = set[TRenderFlag]
+  TRenderTok*{.final.} = object
+    kind*: TTokType
+    length*: int16
+
+  TRenderTokSeq* = seq[TRenderTok]
+  TSrcGen*{.final.} = object
+    indent*: int
+    lineLen*: int
+    pos*: int              # current position for iteration over the buffer
+    idx*: int              # current token index for iteration over the buffer
+    tokens*: TRenderTokSeq
+    buf*: string
+    pendingNL*: int        # negative if not active; else contains the
+                           # indentation value
+    comStack*: seq[PNode]  # comment stack
+    flags*: TRenderFlags
+    checkAnon: bool        # we're in a context that can contain sfAnon
+    inPragma: int
+
+
+proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
+proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string
+proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {})
+proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string)
+
+proc `$`*(n: PNode): string = n.renderTree
+# implementation
+# We render the source code in a two phases: The first
+# determines how long the subtree will likely be, the second
+# phase appends to a buffer that will be the output.
+
+proc isKeyword*(i: PIdent): bool =
+  if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
+      (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
+    result = true
+
+proc isKeyword*(s: string): bool = isKeyword(getIdent(s))
+
+proc renderDefinitionName*(s: PSym, noQuotes = false): string =
+  ## Returns the definition name of the symbol.
+  ##
+  ## If noQuotes is false the symbol may be returned in backticks. This will
+  ## happen if the name happens to be a keyword or the first character is not
+  ## part of the SymStartChars set.
+  let x = s.name.s
+  if noQuotes or (x[0] in SymStartChars and not renderer.isKeyword(s.name)):
+    result = x
+  else:
+    result = '`' & x & '`'
+
+const
+  IndentWidth = 2
+  longIndentWid = 4
+  MaxLineLen = 80
+  LineCommentColumn = 30
+
+proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
+  g.comStack = @[]
+  g.tokens = @[]
+  g.indent = 0
+  g.lineLen = 0
+  g.pos = 0
+  g.idx = 0
+  g.buf = ""
+  g.flags = renderFlags
+  g.pendingNL = -1
+  g.checkAnon = false
+
+proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
+  var length = len(g.tokens)
+  setLen(g.tokens, length + 1)
+  g.tokens[length].kind = kind
+  g.tokens[length].length = int16(len(s))
+  add(g.buf, s)
+
+proc addPendingNL(g: var TSrcGen) =
+  if g.pendingNL >= 0:
+    addTok(g, tkSpaces, "\n" & spaces(g.pendingNL))
+    g.lineLen = g.pendingNL
+    g.pendingNL = - 1
+
+proc putNL(g: var TSrcGen, indent: int) =
+  if g.pendingNL >= 0: addPendingNL(g)
+  else: addTok(g, tkSpaces, "\n")
+  g.pendingNL = indent
+  g.lineLen = indent
+
+proc putNL(g: var TSrcGen) =
+  putNL(g, g.indent)
+
+proc optNL(g: var TSrcGen, indent: int) =
+  g.pendingNL = indent
+  g.lineLen = indent          # BUGFIX
+
+proc optNL(g: var TSrcGen) =
+  optNL(g, g.indent)
+
+proc indentNL(g: var TSrcGen) =
+  inc(g.indent, IndentWidth)
+  g.pendingNL = g.indent
+  g.lineLen = g.indent
+
+proc dedent(g: var TSrcGen) =
+  dec(g.indent, IndentWidth)
+  assert(g.indent >= 0)
+  if g.pendingNL > IndentWidth:
+    dec(g.pendingNL, IndentWidth)
+    dec(g.lineLen, IndentWidth)
+
+proc put(g: var TSrcGen, kind: TTokType, s: string) =
+  addPendingNL(g)
+  if len(s) > 0:
+    addTok(g, kind, s)
+    inc(g.lineLen, len(s))
+
+proc putLong(g: var TSrcGen, kind: TTokType, s: string, lineLen: int) =
+  # use this for tokens over multiple lines.
+  addPendingNL(g)
+  addTok(g, kind, s)
+  g.lineLen = lineLen
+
+proc toNimChar(c: char): string =
+  case c
+  of '\0': result = "\\0"
+  of '\x01'..'\x1F', '\x80'..'\xFF': result = "\\x" & strutils.toHex(ord(c), 2)
+  of '\'', '\"', '\\': result = '\\' & c
+  else: result = c & ""
+
+proc makeNimString(s: string): string =
+  result = "\""
+  for i in countup(0, len(s)-1): add(result, toNimChar(s[i]))
+  add(result, '\"')
+
+proc putComment(g: var TSrcGen, s: string) =
+  if s.isNil: return
+  var i = 0
+  var comIndent = 1
+  var isCode = (len(s) >= 2) and (s[1] != ' ')
+  var ind = g.lineLen
+  var com = ""
+  while true:
+    case s[i]
+    of '\0':
+      break
+    of '\x0D':
+      put(g, tkComment, com)
+      com = ""
+      inc(i)
+      if s[i] == '\x0A': inc(i)
+      optNL(g, ind)
+    of '\x0A':
+      put(g, tkComment, com)
+      com = ""
+      inc(i)
+      optNL(g, ind)
+    of '#':
+      add(com, s[i])
+      inc(i)
+      comIndent = 0
+      while s[i] == ' ':
+        add(com, s[i])
+        inc(i)
+        inc(comIndent)
+    of ' ', '\x09':
+      add(com, s[i])
+      inc(i)
+    else:
+      # we may break the comment into a multi-line comment if the line
+      # gets too long:
+      # compute length of the following word:
+      var j = i
+      while s[j] > ' ': inc(j)
+      if not isCode and (g.lineLen + (j - i) > MaxLineLen):
+        put(g, tkComment, com)
+        optNL(g, ind)
+        com = '#' & spaces(comIndent)
+      while s[i] > ' ':
+        add(com, s[i])
+        inc(i)
+  put(g, tkComment, com)
+  optNL(g)
+
+proc maxLineLength(s: string): int =
+  if s.isNil: return 0
+  var i = 0
+  var lineLen = 0
+  while true:
+    case s[i]
+    of '\0':
+      break
+    of '\x0D':
+      inc(i)
+      if s[i] == '\x0A': inc(i)
+      result = max(result, lineLen)
+      lineLen = 0
+    of '\x0A':
+      inc(i)
+      result = max(result, lineLen)
+      lineLen = 0
+    else:
+      inc(lineLen)
+      inc(i)
+
+proc putRawStr(g: var TSrcGen, kind: TTokType, s: string) =
+  var i = 0
+  var hi = len(s) - 1
+  var str = ""
+  while i <= hi:
+    case s[i]
+    of '\x0D':
+      put(g, kind, str)
+      str = ""
+      inc(i)
+      if (i <= hi) and (s[i] == '\x0A'): inc(i)
+      optNL(g, 0)
+    of '\x0A':
+      put(g, kind, str)
+      str = ""
+      inc(i)
+      optNL(g, 0)
+    else:
+      add(str, s[i])
+      inc(i)
+  put(g, kind, str)
+
+proc containsNL(s: string): bool =
+  for i in countup(0, len(s) - 1):
+    case s[i]
+    of '\x0D', '\x0A':
+      return true
+    else:
+      discard
+  result = false
+
+proc pushCom(g: var TSrcGen, n: PNode) =
+  var length = len(g.comStack)
+  setLen(g.comStack, length + 1)
+  g.comStack[length] = n
+
+proc popAllComs(g: var TSrcGen) =
+  setLen(g.comStack, 0)
+
+proc popCom(g: var TSrcGen) =
+  setLen(g.comStack, len(g.comStack) - 1)
+
+const
+  Space = " "
+
+proc shouldRenderComment(g: var TSrcGen, n: PNode): bool =
+  result = false
+  if n.comment != nil:
+    result = (renderNoComments notin g.flags) or
+        (renderDocComments in g.flags) and startsWith(n.comment, "##")
+
+proc gcom(g: var TSrcGen, n: PNode) =
+  assert(n != nil)
+  if shouldRenderComment(g, n):
+    if (g.pendingNL < 0) and (len(g.buf) > 0) and (g.buf[len(g.buf)-1] != ' '):
+      put(g, tkSpaces, Space)
+      # Before long comments we cannot make sure that a newline is generated,
+      # because this might be wrong. But it is no problem in practice.
+    if (g.pendingNL < 0) and (len(g.buf) > 0) and
+        (g.lineLen < LineCommentColumn):
+      var ml = maxLineLength(n.comment)
+      if ml + LineCommentColumn <= MaxLineLen:
+        put(g, tkSpaces, spaces(LineCommentColumn - g.lineLen))
+    putComment(g, n.comment)  #assert(g.comStack[high(g.comStack)] = n);
+
+proc gcoms(g: var TSrcGen) =
+  for i in countup(0, high(g.comStack)): gcom(g, g.comStack[i])
+  popAllComs(g)
+
+proc lsub(n: PNode): int
+proc litAux(n: PNode, x: BiggestInt, size: int): string =
+  proc skip(t: PType): PType =
+    result = t
+    while result.kind in {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
+                          tyConst, tyMutable}:
+      result = lastSon(result)
+  if n.typ != nil and n.typ.skip.kind in {tyBool, tyEnum}:
+    let enumfields = n.typ.skip.n
+    # we need a slow linear search because of enums with holes:
+    for e in items(enumfields):
+      if e.sym.position == x: return e.sym.name.s
+
+  if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
+  elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
+  elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
+  else: result = $x
+
+proc ulitAux(n: PNode, x: BiggestInt, size: int): string =
+  if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
+  elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
+  elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
+  else: result = $x
+  # XXX proper unsigned output!
+
+proc atom(n: PNode): string =
+  var f: float32
+  case n.kind
+  of nkEmpty: result = ""
+  of nkIdent: result = n.ident.s
+  of nkSym: result = n.sym.name.s
+  of nkStrLit: result = makeNimString(n.strVal)
+  of nkRStrLit: result = "r\"" & replace(n.strVal, "\"", "\"\"")  & '\"'
+  of nkTripleStrLit: result = "\"\"\"" & n.strVal & "\"\"\""
+  of nkCharLit: result = '\'' & toNimChar(chr(int(n.intVal))) & '\''
+  of nkIntLit: result = litAux(n, n.intVal, 4)
+  of nkInt8Lit: result = litAux(n, n.intVal, 1) & "\'i8"
+  of nkInt16Lit: result = litAux(n, n.intVal, 2) & "\'i16"
+  of nkInt32Lit: result = litAux(n, n.intVal, 4) & "\'i32"
+  of nkInt64Lit: result = litAux(n, n.intVal, 8) & "\'i64"
+  of nkUIntLit: result = ulitAux(n, n.intVal, 4) & "\'u"
+  of nkUInt8Lit: result = ulitAux(n, n.intVal, 1) & "\'u8"
+  of nkUInt16Lit: result = ulitAux(n, n.intVal, 2) & "\'u16"
+  of nkUInt32Lit: result = ulitAux(n, n.intVal, 4) & "\'u32"
+  of nkUInt64Lit: result = ulitAux(n, n.intVal, 8) & "\'u64"
+  of nkFloatLit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}: result = $(n.floatVal)
+    else: result = litAux(n, (cast[PInt64](addr(n.floatVal)))[] , 8)
+  of nkFloat32Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
+      result = $n.floatVal & "\'f32"
+    else:
+      f = n.floatVal.float32
+      result = litAux(n, (cast[PInt32](addr(f)))[], 4) & "\'f32"
+  of nkFloat64Lit:
+    if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
+      result = $n.floatVal & "\'f64"
+    else:
+      result = litAux(n, (cast[PInt64](addr(n.floatVal)))[], 8) & "\'f64"
+  of nkNilLit: result = "nil"
+  of nkType:
+    if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
+    else: result = "[type node]"
+  else:
+    internalError("rnimsyn.atom " & $n.kind)
+    result = ""
+
+proc lcomma(n: PNode, start: int = 0, theEnd: int = - 1): int =
+  assert(theEnd < 0)
+  result = 0
+  for i in countup(start, sonsLen(n) + theEnd):
+    inc(result, lsub(n.sons[i]))
+    inc(result, 2)            # for ``, ``
+  if result > 0:
+    dec(result, 2)            # last does not get a comma!
+
+proc lsons(n: PNode, start: int = 0, theEnd: int = - 1): int =
+  assert(theEnd < 0)
+  result = 0
+  for i in countup(start, sonsLen(n) + theEnd): inc(result, lsub(n.sons[i]))
+
+proc lsub(n: PNode): int =
+  # computes the length of a tree
+  if isNil(n): return 0
+  if n.comment != nil: return MaxLineLen + 1
+  case n.kind
+  of nkEmpty: result = 0
+  of nkTripleStrLit:
+    if containsNL(n.strVal): result = MaxLineLen + 1
+    else: result = len(atom(n))
+  of succ(nkEmpty)..pred(nkTripleStrLit), succ(nkTripleStrLit)..nkNilLit:
+    result = len(atom(n))
+  of nkCall, nkBracketExpr, nkCurlyExpr, nkConv, nkPattern, nkObjConstr:
+    result = lsub(n.sons[0]) + lcomma(n, 1) + 2
+  of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: result = lsub(n[1])
+  of nkCast: result = lsub(n.sons[0]) + lsub(n.sons[1]) + len("cast[]()")
+  of nkAddr: result = (if n.len>0: lsub(n.sons[0]) + len("addr()") else: 4)
+  of nkStaticExpr: result = lsub(n.sons[0]) + len("static_")
+  of nkHiddenAddr, nkHiddenDeref: result = lsub(n.sons[0])
+  of nkCommand: result = lsub(n.sons[0]) + lcomma(n, 1) + 1
+  of nkExprEqExpr, nkAsgn, nkFastAsgn: result = lsons(n) + 3
+  of nkPar, nkCurly, nkBracket, nkClosure: result = lcomma(n) + 2
+  of nkArgList: result = lcomma(n)
+  of nkTableConstr:
+    result = if n.len > 0: lcomma(n) + 2 else: len("{:}")
+  of nkClosedSymChoice, nkOpenSymChoice:
+    result = lsons(n) + len("()") + sonsLen(n) - 1
+  of nkTupleTy: result = lcomma(n) + len("tuple[]")
+  of nkTupleClassTy: result = len("tuple")
+  of nkDotExpr: result = lsons(n) + 1
+  of nkBind: result = lsons(n) + len("bind_")
+  of nkBindStmt: result = lcomma(n) + len("bind_")
+  of nkMixinStmt: result = lcomma(n) + len("mixin_")
+  of nkCheckedFieldExpr: result = lsub(n.sons[0])
+  of nkLambda: result = lsons(n) + len("proc__=_")
+  of nkDo: result = lsons(n) + len("do__:_")
+  of nkConstDef, nkIdentDefs:
+    result = lcomma(n, 0, - 3)
+    var L = sonsLen(n)
+    if n.sons[L - 2].kind != nkEmpty: result = result + lsub(n.sons[L - 2]) + 2
+    if n.sons[L - 1].kind != nkEmpty: result = result + lsub(n.sons[L - 1]) + 3
+  of nkVarTuple: result = lcomma(n, 0, - 3) + len("() = ") + lsub(lastSon(n))
+  of nkChckRangeF: result = len("chckRangeF") + 2 + lcomma(n)
+  of nkChckRange64: result = len("chckRange64") + 2 + lcomma(n)
+  of nkChckRange: result = len("chckRange") + 2 + lcomma(n)
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
+    result = 2
+    if sonsLen(n) >= 1: result = result + lsub(n.sons[0])
+    result = result + lcomma(n, 1)
+  of nkExprColonExpr: result = lsons(n) + 2
+  of nkInfix: result = lsons(n) + 2
+  of nkPrefix:
+    result = lsons(n)+1+(if n.len > 0 and n.sons[1].kind == nkInfix: 2 else: 0)
+  of nkPostfix: result = lsons(n)
+  of nkCallStrLit: result = lsons(n)
+  of nkPragmaExpr: result = lsub(n.sons[0]) + lcomma(n, 1)
+  of nkRange: result = lsons(n) + 2
+  of nkDerefExpr: result = lsub(n.sons[0]) + 2
+  of nkAccQuoted: result = lsons(n) + 2
+  of nkIfExpr:
+    result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) +
+        len("if_:_")
+  of nkElifExpr: result = lsons(n) + len("_elif_:_")
+  of nkElseExpr: result = lsub(n.sons[0]) + len("_else:_") # type descriptions
+  of nkTypeOfExpr: result = (if n.len > 0: lsub(n.sons[0]) else: 0)+len("type_")
+  of nkRefTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ref")
+  of nkPtrTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("ptr")
+  of nkVarTy: result = (if n.len > 0: lsub(n.sons[0])+1 else: 0) + len("var")
+  of nkDistinctTy:
+    result = len("distinct") + (if n.len > 0: lsub(n.sons[0])+1 else: 0)
+    if n.len > 1:
+      result += (if n[1].kind == nkWith: len("_with_") else: len("_without_"))
+      result += lcomma(n[1])
+  of nkStaticTy: result = (if n.len > 0: lsub(n.sons[0]) else: 0) +
+                                                         len("static[]")
+  of nkTypeDef: result = lsons(n) + 3
+  of nkOfInherit: result = lsub(n.sons[0]) + len("of_")
+  of nkProcTy: result = lsons(n) + len("proc_")
+  of nkIteratorTy: result = lsons(n) + len("iterator_")
+  of nkSharedTy: result = lsons(n) + len("shared_")
+  of nkEnumTy:
+    if sonsLen(n) > 0:
+      result = lsub(n.sons[0]) + lcomma(n, 1) + len("enum_")
+    else:
+      result = len("enum")
+  of nkEnumFieldDef: result = lsons(n) + 3
+  of nkVarSection, nkLetSection:
+    if sonsLen(n) > 1: result = MaxLineLen + 1
+    else: result = lsons(n) + len("var_")
+  of nkReturnStmt: result = lsub(n.sons[0]) + len("return_")
+  of nkRaiseStmt: result = lsub(n.sons[0]) + len("raise_")
+  of nkYieldStmt: result = lsub(n.sons[0]) + len("yield_")
+  of nkDiscardStmt: result = lsub(n.sons[0]) + len("discard_")
+  of nkBreakStmt: result = lsub(n.sons[0]) + len("break_")
+  of nkContinueStmt: result = lsub(n.sons[0]) + len("continue_")
+  of nkPragma: result = lcomma(n) + 4
+  of nkCommentStmt: result = if n.comment.isNil: 0 else: len(n.comment)
+  of nkOfBranch: result = lcomma(n, 0, - 2) + lsub(lastSon(n)) + len("of_:_")
+  of nkImportAs: result = lsub(n.sons[0]) + len("_as_") + lsub(n.sons[1])
+  of nkElifBranch: result = lsons(n) + len("elif_:_")
+  of nkElse: result = lsub(n.sons[0]) + len("else:_")
+  of nkFinally: result = lsub(n.sons[0]) + len("finally:_")
+  of nkGenericParams: result = lcomma(n) + 2
+  of nkFormalParams:
+    result = lcomma(n, 1) + 2
+    if n.sons[0].kind != nkEmpty: result = result + lsub(n.sons[0]) + 2
+  of nkExceptBranch:
+    result = lcomma(n, 0, -2) + lsub(lastSon(n)) + len("except_:_")
+  else: result = MaxLineLen + 1
+
+proc fits(g: TSrcGen, x: int): bool =
+  result = x + g.lineLen <= MaxLineLen
+
+type
+  TSubFlag = enum
+    rfLongMode, rfNoIndent, rfInConstExpr
+  TSubFlags = set[TSubFlag]
+  TContext = tuple[spacing: int, flags: TSubFlags]
+
+const
+  emptyContext: TContext = (spacing: 0, flags: {})
+
+proc initContext(c: var TContext) =
+  c.spacing = 0
+  c.flags = {}
+
+proc gsub(g: var TSrcGen, n: PNode, c: TContext)
+proc gsub(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  initContext(c)
+  gsub(g, n, c)
+
+proc hasCom(n: PNode): bool =
+  result = false
+  if n.isNil: return false
+  if n.comment != nil: return true
+  case n.kind
+  of nkEmpty..nkNilLit: discard
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      if hasCom(n.sons[i]): return true
+
+proc putWithSpace(g: var TSrcGen, kind: TTokType, s: string) =
+  put(g, kind, s)
+  put(g, tkSpaces, Space)
+
+proc gcommaAux(g: var TSrcGen, n: PNode, ind: int, start: int = 0,
+               theEnd: int = - 1, separator = tkComma) =
+  for i in countup(start, sonsLen(n) + theEnd):
+    var c = i < sonsLen(n) + theEnd
+    var sublen = lsub(n.sons[i]) + ord(c)
+    if not fits(g, sublen) and (ind + sublen < MaxLineLen): optNL(g, ind)
+    let oldLen = g.tokens.len
+    gsub(g, n.sons[i])
+    if c:
+      if g.tokens.len > oldLen:
+        putWithSpace(g, separator, TokTypeToStr[separator])
+      if hasCom(n.sons[i]):
+        gcoms(g)
+        optNL(g, ind)
+
+proc gcomma(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+            theEnd: int = - 1) =
+  var ind: int
+  if rfInConstExpr in c.flags:
+    ind = g.indent + IndentWidth
+  else:
+    ind = g.lineLen
+    if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
+  gcommaAux(g, n, ind, start, theEnd)
+
+proc gcomma(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
+  var ind = g.lineLen
+  if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
+  gcommaAux(g, n, ind, start, theEnd)
+
+proc gsemicolon(g: var TSrcGen, n: PNode, start: int = 0, theEnd: int = - 1) =
+  var ind = g.lineLen
+  if ind > MaxLineLen div 2: ind = g.indent + longIndentWid
+  gcommaAux(g, n, ind, start, theEnd, tkSemiColon)
+
+proc gsons(g: var TSrcGen, n: PNode, c: TContext, start: int = 0,
+           theEnd: int = - 1) =
+  for i in countup(start, sonsLen(n) + theEnd): gsub(g, n.sons[i], c)
+
+proc gsection(g: var TSrcGen, n: PNode, c: TContext, kind: TTokType,
+              k: string) =
+  if sonsLen(n) == 0: return # empty var sections are possible
+  putWithSpace(g, kind, k)
+  gcoms(g)
+  indentNL(g)
+  for i in countup(0, sonsLen(n) - 1):
+    optNL(g)
+    gsub(g, n.sons[i], c)
+    gcoms(g)
+  dedent(g)
+
+proc longMode(n: PNode, start: int = 0, theEnd: int = - 1): bool =
+  result = n.comment != nil
+  if not result:
+    # check further
+    for i in countup(start, sonsLen(n) + theEnd):
+      if (lsub(n.sons[i]) > MaxLineLen):
+        result = true
+        break
+
+proc gstmts(g: var TSrcGen, n: PNode, c: TContext, doIndent=true) =
+  if n.kind == nkEmpty: return
+  if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
+    if doIndent: indentNL(g)
+    for i in countup(0, sonsLen(n) - 1):
+      optNL(g)
+      if n.sons[i].kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
+        gstmts(g, n.sons[i], c, doIndent=false)
+      else:
+        gsub(g, n.sons[i])
+      gcoms(g)
+    if doIndent: dedent(g)
+  else:
+    if rfLongMode in c.flags: indentNL(g)
+    gsub(g, n)
+    gcoms(g)
+    optNL(g)
+    if rfLongMode in c.flags: dedent(g)
+
+proc gif(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  gsub(g, n.sons[0].sons[0])
+  initContext(c)
+  putWithSpace(g, tkColon, ":")
+  if longMode(n) or (lsub(n.sons[0].sons[1]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n.sons[0].sons[1], c)
+  var length = sonsLen(n)
+  for i in countup(1, length - 1):
+    optNL(g)
+    gsub(g, n.sons[i], c)
+
+proc gwhile(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  putWithSpace(g, tkWhile, "while")
+  gsub(g, n.sons[0])
+  putWithSpace(g, tkColon, ":")
+  initContext(c)
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n.sons[1], c)
+
+proc gpattern(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  put(g, tkCurlyLe, "{")
+  initContext(c)
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n, c)
+  put(g, tkCurlyRi, "}")
+
+proc gpragmaBlock(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  gsub(g, n.sons[0])
+  putWithSpace(g, tkColon, ":")
+  initContext(c)
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n.sons[1], c)
+
+proc gtry(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  put(g, tkTry, "try")
+  putWithSpace(g, tkColon, ":")
+  initContext(c)
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n.sons[0], c)
+  gsons(g, n, c, 1)
+
+proc gfor(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  var length = sonsLen(n)
+  putWithSpace(g, tkFor, "for")
+  initContext(c)
+  if longMode(n) or
+      (lsub(n.sons[length - 1]) + lsub(n.sons[length - 2]) + 6 + g.lineLen >
+      MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcomma(g, n, c, 0, - 3)
+  put(g, tkSpaces, Space)
+  putWithSpace(g, tkIn, "in")
+  gsub(g, n.sons[length - 2], c)
+  putWithSpace(g, tkColon, ":")
+  gcoms(g)
+  gstmts(g, n.sons[length - 1], c)
+
+proc gmacro(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  initContext(c)
+  gsub(g, n.sons[0])
+  putWithSpace(g, tkColon, ":")
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)
+  gsons(g, n, c, 1)
+
+proc gcase(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  initContext(c)
+  var length = sonsLen(n)
+  var last = if n.sons[length-1].kind == nkElse: -2 else: -1
+  if longMode(n, 0, last): incl(c.flags, rfLongMode)
+  putWithSpace(g, tkCase, "case")
+  gsub(g, n.sons[0])
+  gcoms(g)
+  optNL(g)
+  gsons(g, n, c, 1, last)
+  if last == - 2:
+    initContext(c)
+    if longMode(n.sons[length - 1]): incl(c.flags, rfLongMode)
+    gsub(g, n.sons[length - 1], c)
+
+proc gproc(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  if n.sons[namePos].kind == nkSym:
+    put(g, tkSymbol, renderDefinitionName(n.sons[namePos].sym))
+  else:
+    gsub(g, n.sons[namePos])
+
+  if n.sons[patternPos].kind != nkEmpty:
+    gpattern(g, n.sons[patternPos])
+  let oldCheckAnon = g.checkAnon
+  g.checkAnon = true
+  gsub(g, n.sons[genericParamsPos])
+  g.checkAnon = oldCheckAnon
+  gsub(g, n.sons[paramsPos])
+  gsub(g, n.sons[pragmasPos])
+  if renderNoBody notin g.flags:
+    if n.sons[bodyPos].kind != nkEmpty:
+      put(g, tkSpaces, Space)
+      putWithSpace(g, tkEquals, "=")
+      indentNL(g)
+      gcoms(g)
+      dedent(g)
+      initContext(c)
+      gstmts(g, n.sons[bodyPos], c)
+      putNL(g)
+    else:
+      indentNL(g)
+      gcoms(g)
+      dedent(g)
+
+proc gTypeClassTy(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  initContext(c)
+  putWithSpace(g, tkConcept, "concept")
+  gsons(g, n[0], c) # arglist
+  gsub(g, n[1]) # pragmas
+  gsub(g, n[2]) # of
+  gcoms(g)
+  indentNL(g)
+  gcoms(g)
+  gstmts(g, n[3], c)
+  dedent(g)
+
+proc gblock(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  initContext(c)
+  if n.sons[0].kind != nkEmpty:
+    putWithSpace(g, tkBlock, "block")
+    gsub(g, n.sons[0])
+  else:
+    put(g, tkBlock, "block")
+  putWithSpace(g, tkColon, ":")
+  if longMode(n) or (lsub(n.sons[1]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)
+  # XXX I don't get why this is needed here! gstmts should already handle this!
+  indentNL(g)
+  gstmts(g, n.sons[1], c)
+  dedent(g)
+
+proc gstaticStmt(g: var TSrcGen, n: PNode) =
+  var c: TContext
+  putWithSpace(g, tkStatic, "static")
+  putWithSpace(g, tkColon, ":")
+  initContext(c)
+  if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
+    incl(c.flags, rfLongMode)
+  gcoms(g)                    # a good place for comments
+  gstmts(g, n.sons[0], c)
+
+proc gasm(g: var TSrcGen, n: PNode) =
+  putWithSpace(g, tkAsm, "asm")
+  gsub(g, n.sons[0])
+  gcoms(g)
+  gsub(g, n.sons[1])
+
+proc gident(g: var TSrcGen, n: PNode) =
+  if g.checkAnon and n.kind == nkSym and sfAnon in n.sym.flags: return
+  var t: TTokType
+  var s = atom(n)
+  if (s[0] in lexer.SymChars):
+    if (n.kind == nkIdent):
+      if (n.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or
+          (n.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)):
+        t = tkSymbol
+      else:
+        t = TTokType(n.ident.id + ord(tkSymbol))
+    else:
+      t = tkSymbol
+  else:
+    t = tkOpr
+  put(g, t, s)
+  if n.kind == nkSym and renderIds in g.flags: put(g, tkIntLit, $n.sym.id)
+
+proc doParamsAux(g: var TSrcGen, params: PNode) =
+  if params.len > 1:
+    put(g, tkParLe, "(")
+    gsemicolon(g, params, 1)
+    put(g, tkParRi, ")")
+
+  if params.sons[0].kind != nkEmpty:
+    putWithSpace(g, tkOpr, "->")
+    gsub(g, params.sons[0])
+
+proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
+  if isNil(n): return
+  var
+    a: TContext
+  if n.comment != nil: pushCom(g, n)
+  case n.kind                 # atoms:
+  of nkTripleStrLit: putRawStr(g, tkTripleStrLit, n.strVal)
+  of nkEmpty: discard
+  of nkType: put(g, tkInvalid, atom(n))
+  of nkSym, nkIdent: gident(g, n)
+  of nkIntLit: put(g, tkIntLit, atom(n))
+  of nkInt8Lit: put(g, tkInt8Lit, atom(n))
+  of nkInt16Lit: put(g, tkInt16Lit, atom(n))
+  of nkInt32Lit: put(g, tkInt32Lit, atom(n))
+  of nkInt64Lit: put(g, tkInt64Lit, atom(n))
+  of nkUIntLit: put(g, tkUIntLit, atom(n))
+  of nkUInt8Lit: put(g, tkUInt8Lit, atom(n))
+  of nkUInt16Lit: put(g, tkUInt16Lit, atom(n))
+  of nkUInt32Lit: put(g, tkUInt32Lit, atom(n))
+  of nkUInt64Lit: put(g, tkUInt64Lit, atom(n))
+  of nkFloatLit: put(g, tkFloatLit, atom(n))
+  of nkFloat32Lit: put(g, tkFloat32Lit, atom(n))
+  of nkFloat64Lit: put(g, tkFloat64Lit, atom(n))
+  of nkFloat128Lit: put(g, tkFloat128Lit, atom(n))
+  of nkStrLit: put(g, tkStrLit, atom(n))
+  of nkRStrLit: put(g, tkRStrLit, atom(n))
+  of nkCharLit: put(g, tkCharLit, atom(n))
+  of nkNilLit: put(g, tkNil, atom(n))    # complex expressions
+  of nkCall, nkConv, nkDotCall, nkPattern, nkObjConstr:
+    if sonsLen(n) >= 1: gsub(g, n.sons[0])
+    put(g, tkParLe, "(")
+    gcomma(g, n, 1)
+    put(g, tkParRi, ")")
+  of nkCallStrLit:
+    gsub(g, n.sons[0])
+    if n.sons[1].kind == nkRStrLit:
+      put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
+    else:
+      gsub(g, n.sons[1])
+  of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
+  of nkCast:
+    put(g, tkCast, "cast")
+    put(g, tkBracketLe, "[")
+    gsub(g, n.sons[0])
+    put(g, tkBracketRi, "]")
+    put(g, tkParLe, "(")
+    gsub(g, n.sons[1])
+    put(g, tkParRi, ")")
+  of nkAddr:
+    put(g, tkAddr, "addr")
+    if n.len > 0:
+      put(g, tkParLe, "(")
+      gsub(g, n.sons[0])
+      put(g, tkParRi, ")")
+  of nkStaticExpr:
+    put(g, tkStatic, "static")
+    put(g, tkSpaces, Space)
+    gsub(g, n.sons[0])
+  of nkBracketExpr:
+    gsub(g, n.sons[0])
+    put(g, tkBracketLe, "[")
+    gcomma(g, n, 1)
+    put(g, tkBracketRi, "]")
+  of nkCurlyExpr:
+    gsub(g, n.sons[0])
+    put(g, tkCurlyLe, "{")
+    gcomma(g, n, 1)
+    put(g, tkCurlyRi, "}")
+  of nkPragmaExpr:
+    gsub(g, n.sons[0])
+    gcomma(g, n, 1)
+  of nkCommand:
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    gcomma(g, n, 1)
+  of nkExprEqExpr, nkAsgn, nkFastAsgn:
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkEquals, "=")
+    gsub(g, n.sons[1])
+  of nkChckRangeF:
+    put(g, tkSymbol, "chckRangeF")
+    put(g, tkParLe, "(")
+    gcomma(g, n)
+    put(g, tkParRi, ")")
+  of nkChckRange64:
+    put(g, tkSymbol, "chckRange64")
+    put(g, tkParLe, "(")
+    gcomma(g, n)
+    put(g, tkParRi, ")")
+  of nkChckRange:
+    put(g, tkSymbol, "chckRange")
+    put(g, tkParLe, "(")
+    gcomma(g, n)
+    put(g, tkParRi, ")")
+  of nkObjDownConv, nkObjUpConv, nkStringToCString, nkCStringToString:
+    if sonsLen(n) >= 1: gsub(g, n.sons[0])
+    put(g, tkParLe, "(")
+    gcomma(g, n, 1)
+    put(g, tkParRi, ")")
+  of nkClosedSymChoice, nkOpenSymChoice:
+    put(g, tkParLe, "(")
+    for i in countup(0, sonsLen(n) - 1):
+      if i > 0: put(g, tkOpr, "|")
+      if n.sons[i].kind == nkSym:
+        let s = n[i].sym
+        if s.owner != nil:
+          put g, tkSymbol, n[i].sym.owner.name.s
+          put g, tkOpr, "."
+        put g, tkSymbol, n[i].sym.name.s
+      else:
+        gsub(g, n.sons[i], c)
+    put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
+  of nkPar, nkClosure:
+    put(g, tkParLe, "(")
+    gcomma(g, n, c)
+    put(g, tkParRi, ")")
+  of nkCurly:
+    put(g, tkCurlyLe, "{")
+    gcomma(g, n, c)
+    put(g, tkCurlyRi, "}")
+  of nkArgList:
+    gcomma(g, n, c)
+  of nkTableConstr:
+    put(g, tkCurlyLe, "{")
+    if n.len > 0: gcomma(g, n, c)
+    else: put(g, tkColon, ":")
+    put(g, tkCurlyRi, "}")
+  of nkBracket:
+    put(g, tkBracketLe, "[")
+    gcomma(g, n, c)
+    put(g, tkBracketRi, "]")
+  of nkDotExpr:
+    gsub(g, n.sons[0])
+    put(g, tkDot, ".")
+    gsub(g, n.sons[1])
+  of nkBind:
+    putWithSpace(g, tkBind, "bind")
+    gsub(g, n.sons[0])
+  of nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref:
+    gsub(g, n.sons[0])
+  of nkLambda:
+    putWithSpace(g, tkProc, "proc")
+    gsub(g, n.sons[paramsPos])
+    gsub(g, n.sons[pragmasPos])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkEquals, "=")
+    gsub(g, n.sons[bodyPos])
+  of nkDo:
+    putWithSpace(g, tkDo, "do")
+    doParamsAux(g, n.sons[paramsPos])
+    gsub(g, n.sons[pragmasPos])
+    put(g, tkColon, ":")
+    gsub(g, n.sons[bodyPos])
+  of nkConstDef, nkIdentDefs:
+    gcomma(g, n, 0, -3)
+    var L = sonsLen(n)
+    if L >= 2 and n.sons[L - 2].kind != nkEmpty:
+      putWithSpace(g, tkColon, ":")
+      gsub(g, n.sons[L - 2])
+    if L >= 1 and n.sons[L - 1].kind != nkEmpty:
+      put(g, tkSpaces, Space)
+      putWithSpace(g, tkEquals, "=")
+      gsub(g, n.sons[L - 1], c)
+  of nkVarTuple:
+    put(g, tkParLe, "(")
+    gcomma(g, n, 0, -3)
+    put(g, tkParRi, ")")
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkEquals, "=")
+    gsub(g, lastSon(n), c)
+  of nkExprColonExpr:
+    gsub(g, n.sons[0])
+    putWithSpace(g, tkColon, ":")
+    gsub(g, n.sons[1])
+  of nkInfix:
+    gsub(g, n.sons[1])
+    put(g, tkSpaces, Space)
+    gsub(g, n.sons[0])        # binary operator
+    if not fits(g, lsub(n.sons[2]) + lsub(n.sons[0]) + 1):
+      optNL(g, g.indent + longIndentWid)
+    else:
+      put(g, tkSpaces, Space)
+    gsub(g, n.sons[2])
+  of nkPrefix:
+    gsub(g, n.sons[0])
+    if n.len > 1:
+      put(g, tkSpaces, Space)
+      if n.sons[1].kind == nkInfix:
+        put(g, tkParLe, "(")
+        gsub(g, n.sons[1])
+        put(g, tkParRi, ")")
+      else:
+        gsub(g, n.sons[1])
+  of nkPostfix:
+    gsub(g, n.sons[1])
+    gsub(g, n.sons[0])
+  of nkRange:
+    gsub(g, n.sons[0])
+    put(g, tkDotDot, "..")
+    gsub(g, n.sons[1])
+  of nkDerefExpr:
+    gsub(g, n.sons[0])
+    put(g, tkOpr, "[]")
+  of nkAccQuoted:
+    put(g, tkAccent, "`")
+    if n.len > 0: gsub(g, n.sons[0])
+    for i in 1 .. <n.len:
+      put(g, tkSpaces, Space)
+      gsub(g, n.sons[i])
+    put(g, tkAccent, "`")
+  of nkIfExpr:
+    putWithSpace(g, tkIf, "if")
+    gsub(g, n.sons[0].sons[0])
+    putWithSpace(g, tkColon, ":")
+    gsub(g, n.sons[0].sons[1])
+    gsons(g, n, emptyContext, 1)
+  of nkElifExpr:
+    putWithSpace(g, tkElif, " elif")
+    gsub(g, n.sons[0])
+    putWithSpace(g, tkColon, ":")
+    gsub(g, n.sons[1])
+  of nkElseExpr:
+    put(g, tkElse, " else")
+    putWithSpace(g, tkColon, ":")
+    gsub(g, n.sons[0])
+  of nkTypeOfExpr:
+    putWithSpace(g, tkType, "type")
+    if n.len > 0: gsub(g, n.sons[0])
+  of nkRefTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkRef, "ref")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkRef, "ref")
+  of nkPtrTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkPtr, "ptr")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkPtr, "ptr")
+  of nkVarTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkVar, "var")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkVar, "var")
+  of nkDistinctTy:
+    if n.len > 0:
+      putWithSpace(g, tkDistinct, "distinct")
+      gsub(g, n.sons[0])
+      if n.len > 1:
+        if n[1].kind == nkWith:
+          putWithSpace(g, tkWith, " with")
+        else:
+          putWithSpace(g, tkWithout, " without")
+        gcomma(g, n[1])
+    else:
+      put(g, tkDistinct, "distinct")
+  of nkTypeDef:
+    gsub(g, n.sons[0])
+    gsub(g, n.sons[1])
+    put(g, tkSpaces, Space)
+    if n.sons[2].kind != nkEmpty:
+      putWithSpace(g, tkEquals, "=")
+      gsub(g, n.sons[2])
+  of nkObjectTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkObject, "object")
+      gsub(g, n.sons[0])
+      gsub(g, n.sons[1])
+      gcoms(g)
+      gsub(g, n.sons[2])
+    else:
+      put(g, tkObject, "object")
+  of nkRecList:
+    indentNL(g)
+    for i in countup(0, sonsLen(n) - 1):
+      optNL(g)
+      gsub(g, n.sons[i], c)
+      gcoms(g)
+    dedent(g)
+    putNL(g)
+  of nkOfInherit:
+    putWithSpace(g, tkOf, "of")
+    gsub(g, n.sons[0])
+  of nkProcTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkProc, "proc")
+      gsub(g, n.sons[0])
+      gsub(g, n.sons[1])
+    else:
+      put(g, tkProc, "proc")
+  of nkIteratorTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkIterator, "iterator")
+      gsub(g, n.sons[0])
+      gsub(g, n.sons[1])
+    else:
+      put(g, tkIterator, "iterator")
+  of nkStaticTy:
+    put(g, tkStatic, "static")
+    put(g, tkBracketLe, "[")
+    if n.len > 0:
+      gsub(g, n.sons[0])
+    put(g, tkBracketRi, "]")
+  of nkEnumTy:
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkEnum, "enum")
+      gsub(g, n.sons[0])
+      gcoms(g)
+      indentNL(g)
+      gcommaAux(g, n, g.indent, 1)
+      gcoms(g)                  # BUGFIX: comment for the last enum field
+      dedent(g)
+    else:
+      put(g, tkEnum, "enum")
+  of nkEnumFieldDef:
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkEquals, "=")
+    gsub(g, n.sons[1])
+  of nkStmtList, nkStmtListExpr, nkStmtListType: gstmts(g, n, emptyContext)
+  of nkIfStmt:
+    putWithSpace(g, tkIf, "if")
+    gif(g, n)
+  of nkWhen, nkRecWhen:
+    putWithSpace(g, tkWhen, "when")
+    gif(g, n)
+  of nkWhileStmt: gwhile(g, n)
+  of nkPragmaBlock: gpragmaBlock(g, n)
+  of nkCaseStmt, nkRecCase: gcase(g, n)
+  of nkTryStmt: gtry(g, n)
+  of nkForStmt, nkParForStmt: gfor(g, n)
+  of nkBlockStmt, nkBlockExpr: gblock(g, n)
+  of nkStaticStmt: gstaticStmt(g, n)
+  of nkAsmStmt: gasm(g, n)
+  of nkProcDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
+    gproc(g, n)
+  of nkConverterDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
+    gproc(g, n)
+  of nkMethodDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkMethod, "method")
+    gproc(g, n)
+  of nkIteratorDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkIterator, "iterator")
+    gproc(g, n)
+  of nkMacroDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkMacro, "macro")
+    gproc(g, n)
+  of nkTemplateDef:
+    if renderNoProcDefs notin g.flags: putWithSpace(g, tkTemplate, "template")
+    gproc(g, n)
+  of nkTypeSection:
+    gsection(g, n, emptyContext, tkType, "type")
+  of nkConstSection:
+    initContext(a)
+    incl(a.flags, rfInConstExpr)
+    gsection(g, n, a, tkConst, "const")
+  of nkVarSection, nkLetSection:
+    var L = sonsLen(n)
+    if L == 0: return
+    if n.kind == nkVarSection: putWithSpace(g, tkVar, "var")
+    else: putWithSpace(g, tkLet, "let")
+    if L > 1:
+      gcoms(g)
+      indentNL(g)
+      for i in countup(0, L - 1):
+        optNL(g)
+        gsub(g, n.sons[i])
+        gcoms(g)
+      dedent(g)
+    else:
+      gsub(g, n.sons[0])
+  of nkReturnStmt:
+    putWithSpace(g, tkReturn, "return")
+    gsub(g, n.sons[0])
+  of nkRaiseStmt:
+    putWithSpace(g, tkRaise, "raise")
+    gsub(g, n.sons[0])
+  of nkYieldStmt:
+    putWithSpace(g, tkYield, "yield")
+    gsub(g, n.sons[0])
+  of nkDiscardStmt:
+    putWithSpace(g, tkDiscard, "discard")
+    gsub(g, n.sons[0])
+  of nkBreakStmt:
+    putWithSpace(g, tkBreak, "break")
+    gsub(g, n.sons[0])
+  of nkContinueStmt:
+    putWithSpace(g, tkContinue, "continue")
+    gsub(g, n.sons[0])
+  of nkPragma:
+    if renderNoPragmas notin g.flags:
+      if g.inPragma <= 0:
+        inc g.inPragma
+        put(g, tkSpaces, Space)
+        put(g, tkCurlyDotLe, "{.")
+        gcomma(g, n, emptyContext)
+        put(g, tkCurlyDotRi, ".}")
+        dec g.inPragma
+      else:
+        gcomma(g, n, emptyContext)
+  of nkImportStmt, nkExportStmt:
+    if n.kind == nkImportStmt:
+      putWithSpace(g, tkImport, "import")
+    else:
+      putWithSpace(g, tkExport, "export")
+    gcoms(g)
+    indentNL(g)
+    gcommaAux(g, n, g.indent)
+    dedent(g)
+    putNL(g)
+  of nkImportExceptStmt, nkExportExceptStmt:
+    if n.kind == nkImportExceptStmt:
+      putWithSpace(g, tkImport, "import")
+    else:
+      putWithSpace(g, tkExport, "export")
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkExcept, "except")
+    gcommaAux(g, n, g.indent, 1)
+    gcoms(g)
+    putNL(g)
+  of nkFromStmt:
+    putWithSpace(g, tkFrom, "from")
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkImport, "import")
+    gcomma(g, n, emptyContext, 1)
+    putNL(g)
+  of nkIncludeStmt:
+    putWithSpace(g, tkInclude, "include")
+    gcoms(g)
+    indentNL(g)
+    gcommaAux(g, n, g.indent)
+    dedent(g)
+    putNL(g)
+  of nkCommentStmt:
+    gcoms(g)
+    optNL(g)
+  of nkOfBranch:
+    optNL(g)
+    putWithSpace(g, tkOf, "of")
+    gcomma(g, n, c, 0, - 2)
+    putWithSpace(g, tkColon, ":")
+    gcoms(g)
+    gstmts(g, lastSon(n), c)
+  of nkImportAs:
+    gsub(g, n.sons[0])
+    put(g, tkSpaces, Space)
+    putWithSpace(g, tkAs, "as")
+    gsub(g, n.sons[1])
+  of nkBindStmt:
+    putWithSpace(g, tkBind, "bind")
+    gcomma(g, n, c)
+  of nkMixinStmt:
+    putWithSpace(g, tkMixin, "mixin")
+    gcomma(g, n, c)
+  of nkElifBranch:
+    optNL(g)
+    putWithSpace(g, tkElif, "elif")
+    gsub(g, n.sons[0])
+    putWithSpace(g, tkColon, ":")
+    gcoms(g)
+    gstmts(g, n.sons[1], c)
+  of nkElse:
+    optNL(g)
+    put(g, tkElse, "else")
+    putWithSpace(g, tkColon, ":")
+    gcoms(g)
+    gstmts(g, n.sons[0], c)
+  of nkFinally, nkDefer:
+    optNL(g)
+    if n.kind == nkFinally:
+      put(g, tkFinally, "finally")
+    else:
+      put(g, tkDefer, "defer")
+    putWithSpace(g, tkColon, ":")
+    gcoms(g)
+    gstmts(g, n.sons[0], c)
+  of nkExceptBranch:
+    optNL(g)
+    putWithSpace(g, tkExcept, "except")
+    gcomma(g, n, 0, - 2)
+    putWithSpace(g, tkColon, ":")
+    gcoms(g)
+    gstmts(g, lastSon(n), c)
+  of nkGenericParams:
+    put(g, tkBracketLe, "[")
+    gcomma(g, n)
+    put(g, tkBracketRi, "]")
+  of nkFormalParams:
+    put(g, tkParLe, "(")
+    gsemicolon(g, n, 1)
+    put(g, tkParRi, ")")
+    if n.sons[0].kind != nkEmpty:
+      putWithSpace(g, tkColon, ":")
+      gsub(g, n.sons[0])
+  of nkTupleTy:
+    put(g, tkTuple, "tuple")
+    put(g, tkBracketLe, "[")
+    gcomma(g, n)
+    put(g, tkBracketRi, "]")
+  of nkTupleClassTy:
+    put(g, tkTuple, "tuple")
+  of nkMetaNode_Obsolete:
+    put(g, tkParLe, "(META|")
+    gsub(g, n.sons[0])
+    put(g, tkParRi, ")")
+  of nkGotoState, nkState:
+    var c: TContext
+    initContext c
+    putWithSpace g, tkSymbol, if n.kind == nkState: "state" else: "goto"
+    gsons(g, n, c)
+  of nkTypeClassTy:
+    gTypeClassTy(g, n)
+  else:
+    #nkNone, nkExplicitTypeListCall:
+    internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
+
+proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
+  var g: TSrcGen
+  initSrcGen(g, renderFlags)
+  gsub(g, n)
+  result = g.buf
+
+proc renderModule(n: PNode, filename: string,
+                  renderFlags: TRenderFlags = {}) =
+  var
+    f: File
+    g: TSrcGen
+  initSrcGen(g, renderFlags)
+  for i in countup(0, sonsLen(n) - 1):
+    gsub(g, n.sons[i])
+    optNL(g)
+    case n.sons[i].kind
+    of nkTypeSection, nkConstSection, nkVarSection, nkLetSection,
+       nkCommentStmt: putNL(g)
+    else: discard
+  gcoms(g)
+  if optStdout in gGlobalOptions:
+    write(stdout, g.buf)
+  elif open(f, filename, fmWrite):
+    write(f, g.buf)
+    close(f)
+  else:
+    rawMessage(errCannotOpenFile, filename)
+
+proc initTokRender(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
+  initSrcGen(r, renderFlags)
+  gsub(r, n)
+
+proc getNextTok(r: var TSrcGen, kind: var TTokType, literal: var string) =
+  if r.idx < len(r.tokens):
+    kind = r.tokens[r.idx].kind
+    var length = r.tokens[r.idx].length.int
+    literal = substr(r.buf, r.pos, r.pos + length - 1)
+    inc(r.pos, length)
+    inc(r.idx)
+  else:
+    kind = tkEof
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
new file mode 100644
index 000000000..e92f7ecfa
--- /dev/null
+++ b/compiler/rodread.nim
@@ -0,0 +1,1173 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module is responsible for loading of rod files.
+#
+# Reading and writing binary files are really hard to debug. Therefore we use
+# a "creative" text/binary hybrid format. ROD-files are more efficient
+# to process because symbols can be loaded on demand.
+# 
+# A ROD file consists of:
+#
+#  - a header:
+#    NIM:$fileversion\n
+#  - the module's id (even if the module changed, its ID will not!):
+#    ID:Ax3\n
+#  - CRC value of this module:
+#    CRC:CRC-val\n
+#  - a section containing the compiler options and defines this
+#    module has been compiled with:
+#    OPTIONS:options\n
+#    GOPTIONS:options\n # global options
+#    CMD:command\n
+#    DEFINES:defines\n
+#  - FILES(
+#    myfile.inc
+#    lib/mymodA
+#    )
+#  - an include file dependency section:
+#    INCLUDES(
+#    <fileidx> <CRC of myfile.inc>\n # fileidx is the LINE in the file section!
+#    )
+#  - a module dependency section:
+#    DEPS: <fileidx> <fileidx>\n
+#  - an interface section:
+#    INTERF(
+#    identifier1 id\n # id is the symbol's id
+#    identifier2 id\n
+#    )
+#  - a compiler proc section:
+#    COMPILERPROCS(
+#    identifier1 id\n # id is the symbol's id    
+#    )
+#  - an index consisting of (ID, linenumber)-pairs:
+#    INDEX(
+#    id-diff idx-diff\n
+#    id-diff idx-diff\n
+#    )
+#
+#    Since the whole index has to be read in advance, we compress it by 
+#    storing the integer differences to the last entry instead of using the
+#    real numbers.
+#
+#  - an import index consisting of (ID, moduleID)-pairs:
+#    IMPORTS(
+#    id-diff moduleID-diff\n
+#    id-diff moduleID-diff\n
+#    )
+#  - a list of all exported type converters because they are needed for correct
+#    semantic checking:
+#    CONVERTERS:id id\n   # symbol ID
+#
+#    This is a misnomer now; it's really a "load unconditionally" section as
+#    it is also used for pattern templates.
+#
+#  - a list of all (private or exported) methods because they are needed for
+#    correct dispatcher generation:
+#    METHODS: id id\n   # symbol ID
+#  - an AST section that contains the module's AST:
+#    INIT(
+#    idx\n  # position of the node in the DATA section
+#    idx\n
+#    )
+#  - a data section, where each type, symbol or AST is stored.
+#    DATA(
+#    type
+#    (node)
+#    sym
+#    )
+#
+#    The data section MUST be the last section of the file, because processing
+#    stops immediately after ``DATA(`` and the rest is only loaded on demand
+#    by using a mem'mapped file.
+#
+
+import 
+  os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, 
+  ropes, idents, crc, idgen, types, rodutils, memfiles
+
+type 
+  TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
+    rrEmpty,                  # dependencies not yet computed
+    rrNone,                   # no need to recompile
+    rrRodDoesNotExist,        # rod file does not exist
+    rrRodInvalid,             # rod file is invalid
+    rrCrcChange,              # file has been edited since last recompilation
+    rrDefines,                # defines have changed
+    rrOptions,                # options have changed
+    rrInclDeps,               # an include has changed
+    rrModDeps                 # a module this module depends on has been changed
+
+const 
+  reasonToFrmt*: array[TReasonForRecompile, string] = ["", 
+    "no need to recompile: $1", "symbol file for $1 does not exist", 
+    "symbol file for $1 has the wrong version", 
+    "file edited since last compilation: $1", 
+    "list of conditional symbols changed for: $1", 
+    "list of options changed for: $1", 
+    "an include file edited: $1", 
+    "a module $1 depends on has changed"]
+
+type
+  TIndex*{.final.} = object   # an index with compression
+    lastIdxKey*, lastIdxVal*: int
+    tab*: TIITable
+    r*: string                # writers use this
+    offset*: int              # readers use this
+  
+  TRodReader* = object of RootObj
+    pos: int                 # position; used for parsing
+    s: cstring               # mmap'ed file contents
+    options: TOptions
+    reason: TReasonForRecompile
+    modDeps: seq[int32]
+    files: seq[int32]
+    dataIdx: int             # offset of start of data section
+    convertersIdx: int       # offset of start of converters section
+    initIdx, interfIdx, compilerProcsIdx, methodsIdx: int
+    filename: string
+    index, imports: TIndex
+    readerIndex: int
+    line: int            # only used for debugging, but is always in the code
+    moduleID: int
+    syms: TIdTable       # already processed symbols
+    memfile: MemFile     # unfortunately there is no point in time where we
+                         # can close this! XXX
+    methods*: TSymSeq
+    origFile: string
+    inViewMode: bool
+  
+  PRodReader* = ref TRodReader
+
+var rodCompilerprocs*: TStrTable
+
+proc handleSymbolFile*(module: PSym): PRodReader
+# global because this is needed by magicsys
+proc loadInitSection*(r: PRodReader): PNode
+
+# implementation
+
+proc rawLoadStub(s: PSym)
+
+var gTypeTable: TIdTable
+
+proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym
+  # `info` is only used for debugging purposes
+proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType
+
+proc decodeLineInfo(r: PRodReader, info: var TLineInfo) = 
+  if r.s[r.pos] == '?': 
+    inc(r.pos)
+    if r.s[r.pos] == ',': info.col = -1'i16
+    else: info.col = int16(decodeVInt(r.s, r.pos))
+    if r.s[r.pos] == ',': 
+      inc(r.pos)
+      if r.s[r.pos] == ',': info.line = -1'i16
+      else: info.line = int16(decodeVInt(r.s, r.pos))
+      if r.s[r.pos] == ',': 
+        inc(r.pos)
+        info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col)
+
+proc skipNode(r: PRodReader) =
+  assert r.s[r.pos] == '('
+  var par = 0
+  var pos = r.pos+1
+  while true:
+    case r.s[pos]
+    of ')':
+      if par == 0: break
+      dec par
+    of '(': inc par
+    else: discard
+    inc pos
+  r.pos = pos+1 # skip ')'
+
+proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo, 
+                        belongsTo: PSym): PNode = 
+  result = nil
+  if r.s[r.pos] == '(': 
+    inc(r.pos)
+    if r.s[r.pos] == ')': 
+      inc(r.pos)
+      return                  # nil node
+    result = newNodeI(TNodeKind(decodeVInt(r.s, r.pos)), fInfo)
+    decodeLineInfo(r, result.info)
+    if r.s[r.pos] == '$': 
+      inc(r.pos)
+      result.flags = cast[TNodeFlags](int32(decodeVInt(r.s, r.pos)))
+    if r.s[r.pos] == '^': 
+      inc(r.pos)
+      var id = decodeVInt(r.s, r.pos)
+      result.typ = rrGetType(r, id, result.info)
+    case result.kind
+    of nkCharLit..nkInt64Lit: 
+      if r.s[r.pos] == '!': 
+        inc(r.pos)
+        result.intVal = decodeVBiggestInt(r.s, r.pos)
+    of nkFloatLit..nkFloat64Lit: 
+      if r.s[r.pos] == '!': 
+        inc(r.pos)
+        var fl = decodeStr(r.s, r.pos)
+        result.floatVal = parseFloat(fl)
+    of nkStrLit..nkTripleStrLit: 
+      if r.s[r.pos] == '!': 
+        inc(r.pos)
+        result.strVal = decodeStr(r.s, r.pos)
+      else: 
+        result.strVal = ""    # BUGFIX
+    of nkIdent: 
+      if r.s[r.pos] == '!': 
+        inc(r.pos)
+        var fl = decodeStr(r.s, r.pos)
+        result.ident = getIdent(fl)
+      else: 
+        internalError(result.info, "decodeNode: nkIdent")
+    of nkSym: 
+      if r.s[r.pos] == '!': 
+        inc(r.pos)
+        var id = decodeVInt(r.s, r.pos)
+        result.sym = rrGetSym(r, id, result.info)
+      else: 
+        internalError(result.info, "decodeNode: nkSym")
+    else:
+      var i = 0
+      while r.s[r.pos] != ')': 
+        if belongsTo != nil and i == bodyPos:
+          addSonNilAllowed(result, nil)
+          belongsTo.offset = r.pos
+          skipNode(r)
+        else:
+          addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil))
+        inc i
+    if r.s[r.pos] == ')': inc(r.pos)
+    else: internalError(result.info, "decodeNode: ')' missing")
+  else:
+    internalError(fInfo, "decodeNode: '(' missing " & $r.pos)
+
+proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
+  result = decodeNodeLazyBody(r, fInfo, nil)
+  
+proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) = 
+  if r.s[r.pos] == '<': 
+    inc(r.pos)
+    if r.s[r.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: 
+      loc.k = TLocKind(decodeVInt(r.s, r.pos))
+    else: 
+      loc.k = low(loc.k)
+    if r.s[r.pos] == '*': 
+      inc(r.pos)
+      loc.s = TStorageLoc(decodeVInt(r.s, r.pos))
+    else: 
+      loc.s = low(loc.s)
+    if r.s[r.pos] == '$': 
+      inc(r.pos)
+      loc.flags = cast[TLocFlags](int32(decodeVInt(r.s, r.pos)))
+    else: 
+      loc.flags = {}
+    if r.s[r.pos] == '^': 
+      inc(r.pos)
+      loc.t = rrGetType(r, decodeVInt(r.s, r.pos), info)
+    else: 
+      loc.t = nil
+    if r.s[r.pos] == '!': 
+      inc(r.pos)
+      loc.r = rope(decodeStr(r.s, r.pos))
+    else: 
+      loc.r = nil
+    if r.s[r.pos] == '>': inc(r.pos)
+    else: internalError(info, "decodeLoc " & r.s[r.pos])
+  
+proc decodeType(r: PRodReader, info: TLineInfo): PType = 
+  result = nil
+  if r.s[r.pos] == '[': 
+    inc(r.pos)
+    if r.s[r.pos] == ']': 
+      inc(r.pos)
+      return                  # nil type
+  new(result)
+  result.kind = TTypeKind(decodeVInt(r.s, r.pos))
+  if r.s[r.pos] == '+': 
+    inc(r.pos)
+    result.id = decodeVInt(r.s, r.pos)
+    setId(result.id)
+    if debugIds: registerID(result)
+  else: 
+    internalError(info, "decodeType: no id")
+  # here this also avoids endless recursion for recursive type
+  idTablePut(gTypeTable, result, result) 
+  if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
+  if r.s[r.pos] == '$': 
+    inc(r.pos)
+    result.flags = cast[TTypeFlags](int32(decodeVInt(r.s, r.pos)))
+  if r.s[r.pos] == '?': 
+    inc(r.pos)
+    result.callConv = TCallingConvention(decodeVInt(r.s, r.pos))
+  if r.s[r.pos] == '*': 
+    inc(r.pos)
+    result.owner = rrGetSym(r, decodeVInt(r.s, r.pos), info)
+  if r.s[r.pos] == '&': 
+    inc(r.pos)
+    result.sym = rrGetSym(r, decodeVInt(r.s, r.pos), info)
+  if r.s[r.pos] == '/': 
+    inc(r.pos)
+    result.size = decodeVInt(r.s, r.pos)
+  else: 
+    result.size = - 1
+  if r.s[r.pos] == '=': 
+    inc(r.pos)
+    result.align = decodeVInt(r.s, r.pos).int16
+  else: 
+    result.align = 2
+  decodeLoc(r, result.loc, info)
+  while r.s[r.pos] == '^': 
+    inc(r.pos)
+    if r.s[r.pos] == '(': 
+      inc(r.pos)
+      if r.s[r.pos] == ')': inc(r.pos)
+      else: internalError(info, "decodeType ^(" & r.s[r.pos])
+      rawAddSon(result, nil)
+    else: 
+      var d = decodeVInt(r.s, r.pos)
+      rawAddSon(result, rrGetType(r, d, info))
+
+proc decodeLib(r: PRodReader, info: TLineInfo): PLib = 
+  result = nil
+  if r.s[r.pos] == '|': 
+    new(result)
+    inc(r.pos)
+    result.kind = TLibKind(decodeVInt(r.s, r.pos))
+    if r.s[r.pos] != '|': internalError("decodeLib: 1")
+    inc(r.pos)
+    result.name = rope(decodeStr(r.s, r.pos))
+    if r.s[r.pos] != '|': internalError("decodeLib: 2")
+    inc(r.pos)
+    result.path = decodeNode(r, info)
+
+proc decodeSym(r: PRodReader, info: TLineInfo): PSym = 
+  var 
+    id: int
+    ident: PIdent
+  result = nil
+  if r.s[r.pos] == '{': 
+    inc(r.pos)
+    if r.s[r.pos] == '}': 
+      inc(r.pos)
+      return                  # nil sym
+  var k = TSymKind(decodeVInt(r.s, r.pos))
+  if r.s[r.pos] == '+': 
+    inc(r.pos)
+    id = decodeVInt(r.s, r.pos)
+    setId(id)
+  else:
+    internalError(info, "decodeSym: no id")
+  if r.s[r.pos] == '&': 
+    inc(r.pos)
+    ident = getIdent(decodeStr(r.s, r.pos))
+  else:
+    internalError(info, "decodeSym: no ident")
+  #echo "decoding: {", ident.s
+  result = PSym(idTableGet(r.syms, id))
+  if result == nil: 
+    new(result)
+    result.id = id
+    idTablePut(r.syms, result, result)
+    if debugIds: registerID(result)
+  elif result.id != id:
+    internalError(info, "decodeSym: wrong id")
+  elif result.kind != skStub and not r.inViewMode:
+    # we already loaded the symbol
+    return
+  else:
+    reset(result[])
+    result.id = id
+  result.kind = k
+  result.name = ident         # read the rest of the symbol description:
+  if r.s[r.pos] == '^': 
+    inc(r.pos)
+    result.typ = rrGetType(r, decodeVInt(r.s, r.pos), info)
+  decodeLineInfo(r, result.info)
+  if r.s[r.pos] == '*': 
+    inc(r.pos)
+    result.owner = rrGetSym(r, decodeVInt(r.s, r.pos), result.info)
+  if r.s[r.pos] == '$': 
+    inc(r.pos)
+    result.flags = cast[TSymFlags](int32(decodeVInt(r.s, r.pos)))
+  if r.s[r.pos] == '@': 
+    inc(r.pos)
+    result.magic = TMagic(decodeVInt(r.s, r.pos))
+  if r.s[r.pos] == '!': 
+    inc(r.pos)
+    result.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
+  else: 
+    result.options = r.options
+  if r.s[r.pos] == '%': 
+    inc(r.pos)
+    result.position = decodeVInt(r.s, r.pos)
+  elif result.kind notin routineKinds + {skModule}:
+    result.position = 0
+    # this may have been misused as reader index! But we still
+    # need it for routines as the body is loaded lazily.
+  if r.s[r.pos] == '`': 
+    inc(r.pos)
+    result.offset = decodeVInt(r.s, r.pos)
+  else: 
+    result.offset = - 1
+  decodeLoc(r, result.loc, result.info)
+  result.annex = decodeLib(r, info)
+  if r.s[r.pos] == '#':
+    inc(r.pos)
+    result.constraint = decodeNode(r, unknownLineInfo())
+  if r.s[r.pos] == '(':
+    if result.kind in routineKinds:
+      result.ast = decodeNodeLazyBody(r, result.info, result)
+      # since we load the body lazily, we need to set the reader to
+      # be able to reload:
+      result.position = r.readerIndex
+    else:
+      result.ast = decodeNode(r, result.info)
+  #echo "decoded: ", ident.s, "}"
+
+proc skipSection(r: PRodReader) = 
+  if r.s[r.pos] == ':': 
+    while r.s[r.pos] > '\x0A': inc(r.pos)
+  elif r.s[r.pos] == '(': 
+    var c = 0                 # count () pairs
+    inc(r.pos)
+    while true: 
+      case r.s[r.pos]
+      of '\x0A': inc(r.line)
+      of '(': inc(c)
+      of ')': 
+        if c == 0: 
+          inc(r.pos)
+          break 
+        elif c > 0: 
+          dec(c)
+      of '\0': break          # end of file
+      else: discard
+      inc(r.pos)
+  else: 
+    internalError("skipSection " & $r.line)
+  
+proc rdWord(r: PRodReader): string = 
+  result = ""
+  while r.s[r.pos] in {'A'..'Z', '_', 'a'..'z', '0'..'9'}: 
+    add(result, r.s[r.pos])
+    inc(r.pos)
+
+proc newStub(r: PRodReader, name: string, id: int): PSym = 
+  new(result)
+  result.kind = skStub
+  result.id = id
+  result.name = getIdent(name)
+  result.position = r.readerIndex
+  setId(id)                   #MessageOut(result.name.s);
+  if debugIds: registerID(result)
+  
+proc processInterf(r: PRodReader, module: PSym) = 
+  if r.interfIdx == 0: internalError("processInterf")
+  r.pos = r.interfIdx
+  while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): 
+    var w = decodeStr(r.s, r.pos)
+    inc(r.pos)
+    var key = decodeVInt(r.s, r.pos)
+    inc(r.pos)                # #10
+    var s = newStub(r, w, key)
+    s.owner = module
+    strTableAdd(module.tab, s)
+    idTablePut(r.syms, s, s)
+
+proc processCompilerProcs(r: PRodReader, module: PSym) = 
+  if r.compilerProcsIdx == 0: internalError("processCompilerProcs")
+  r.pos = r.compilerProcsIdx
+  while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): 
+    var w = decodeStr(r.s, r.pos)
+    inc(r.pos)
+    var key = decodeVInt(r.s, r.pos)
+    inc(r.pos)                # #10
+    var s = PSym(idTableGet(r.syms, key))
+    if s == nil: 
+      s = newStub(r, w, key)
+      s.owner = module
+      idTablePut(r.syms, s, s)
+    strTableAdd(rodCompilerprocs, s)
+
+proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) = 
+  var key, val, tmp: int
+  inc(r.pos, 2)               # skip "(\10"
+  inc(r.line)
+  while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): 
+    tmp = decodeVInt(r.s, r.pos)
+    if r.s[r.pos] == ' ': 
+      inc(r.pos)
+      key = idx.lastIdxKey + tmp
+      val = decodeVInt(r.s, r.pos) + idx.lastIdxVal
+    else:
+      key = idx.lastIdxKey + 1
+      val = tmp + idx.lastIdxVal
+    iiTablePut(idx.tab, key, val)
+    if not outf.isNil: outf.write(key, " ", val, "\n")
+    idx.lastIdxKey = key
+    idx.lastIdxVal = val
+    setId(key)                # ensure that this id will not be used
+    if r.s[r.pos] == '\x0A': 
+      inc(r.pos)
+      inc(r.line)
+  if r.s[r.pos] == ')': inc(r.pos)
+  
+proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
+  if old == new: return false
+  # we use a 'case' statement without 'else' so that addition of a
+  # new command forces us to consider it here :-)
+  case old
+  of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
+      cmdCompileToJS, cmdCompileToLLVM:
+    if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
+               cmdInteractive}:
+      return false
+  of cmdNone, cmdDoc, cmdInterpret, cmdPretty, cmdGenDepend, cmdDump,
+      cmdCheck, cmdParse, cmdScan, cmdIdeTools, cmdDef, 
+      cmdRst2html, cmdRst2tex, cmdInteractive, cmdRun:
+    discard
+  # else: trigger recompilation:
+  result = true
+  
+proc processRodFile(r: PRodReader, crc: TCrc32) = 
+  var 
+    w: string
+    d, inclCrc: int
+  while r.s[r.pos] != '\0': 
+    var section = rdWord(r)
+    if r.reason != rrNone: 
+      break                   # no need to process this file further
+    case section 
+    of "CRC": 
+      inc(r.pos)              # skip ':'
+      if int(crc) != decodeVInt(r.s, r.pos): r.reason = rrCrcChange
+    of "ID": 
+      inc(r.pos)              # skip ':'
+      r.moduleID = decodeVInt(r.s, r.pos)
+      setId(r.moduleID)
+    of "ORIGFILE":
+      inc(r.pos)
+      r.origFile = decodeStr(r.s, r.pos)
+    of "OPTIONS": 
+      inc(r.pos)              # skip ':'
+      r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
+      if options.gOptions != r.options: r.reason = rrOptions
+    of "GOPTIONS":
+      inc(r.pos)              # skip ':'
+      var dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos)))
+      if gGlobalOptions != dep: r.reason = rrOptions
+    of "CMD":
+      inc(r.pos)              # skip ':'
+      var dep = cast[TCommands](int32(decodeVInt(r.s, r.pos)))
+      if cmdChangeTriggersRecompilation(dep, gCmd): r.reason = rrOptions
+    of "DEFINES":
+      inc(r.pos)              # skip ':'
+      d = 0
+      while r.s[r.pos] > '\x0A': 
+        w = decodeStr(r.s, r.pos)
+        inc(d)
+        if not condsyms.isDefined(getIdent(w)): 
+          r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
+        if r.s[r.pos] == ' ': inc(r.pos)
+      if (d != countDefinedSymbols()): r.reason = rrDefines
+    of "FILES": 
+      inc(r.pos, 2)           # skip "(\10"
+      inc(r.line)
+      while r.s[r.pos] != ')':
+        let relativePath = decodeStr(r.s, r.pos)
+        let resolvedPath = relativePath.findModule(r.origFile)
+        let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
+        r.files.add(finalPath.fileInfoIdx)
+        inc(r.pos)            # skip #10
+        inc(r.line)
+      if r.s[r.pos] == ')': inc(r.pos)
+    of "INCLUDES": 
+      inc(r.pos, 2)           # skip "(\10"
+      inc(r.line)
+      while r.s[r.pos] != ')': 
+        w = r.files[decodeVInt(r.s, r.pos)].toFullPath
+        inc(r.pos)            # skip ' '
+        inclCrc = decodeVInt(r.s, r.pos)
+        if r.reason == rrNone: 
+          if not existsFile(w) or (inclCrc != int(crcFromFile(w))): 
+            r.reason = rrInclDeps
+        if r.s[r.pos] == '\x0A': 
+          inc(r.pos)
+          inc(r.line)
+      if r.s[r.pos] == ')': inc(r.pos)
+    of "DEPS":
+      inc(r.pos)              # skip ':'
+      while r.s[r.pos] > '\x0A':
+        r.modDeps.add(r.files[int32(decodeVInt(r.s, r.pos))])
+        if r.s[r.pos] == ' ': inc(r.pos)
+    of "INTERF": 
+      r.interfIdx = r.pos + 2
+      skipSection(r)
+    of "COMPILERPROCS": 
+      r.compilerProcsIdx = r.pos + 2
+      skipSection(r)
+    of "INDEX": 
+      processIndex(r, r.index)
+    of "IMPORTS": 
+      processIndex(r, r.imports)
+    of "CONVERTERS": 
+      r.convertersIdx = r.pos + 1
+      skipSection(r)
+    of "METHODS":
+      r.methodsIdx = r.pos + 1
+      skipSection(r)
+    of "DATA": 
+      r.dataIdx = r.pos + 2 # "(\10"
+      # We do not read the DATA section here! We read the needed objects on
+      # demand. And the DATA section comes last in the file, so we stop here:
+      break
+    of "INIT": 
+      r.initIdx = r.pos + 2   # "(\10"
+      skipSection(r)
+    else:
+      internalError("invalid section: '" & section &
+                    "' at " & $r.line & " in " & r.filename)
+      #MsgWriteln("skipping section: " & section &
+      #           " at " & $r.line & " in " & r.filename)
+      skipSection(r)
+    if r.s[r.pos] == '\x0A': 
+      inc(r.pos)
+      inc(r.line)
+
+
+proc startsWith(buf: cstring, token: string, pos = 0): bool =
+  var s = 0
+  while s < token.len and buf[pos+s] == token[s]: inc s
+  result = s == token.len
+
+proc newRodReader(modfilename: string, crc: TCrc32, 
+                  readerIndex: int): PRodReader = 
+  new(result)
+  try:
+    result.memfile = memfiles.open(modfilename)
+  except OSError:
+    return nil
+  result.files = @[]
+  result.modDeps = @[]
+  result.methods = @[]
+  var r = result
+  r.reason = rrNone
+  r.pos = 0
+  r.line = 1
+  r.readerIndex = readerIndex
+  r.filename = modfilename
+  initIdTable(r.syms)
+  # we terminate the file explicitly with ``\0``, so the cast to `cstring`
+  # is safe:
+  r.s = cast[cstring](r.memfile.mem)
+  if startsWith(r.s, "NIM:"): 
+    initIiTable(r.index.tab)
+    initIiTable(r.imports.tab) # looks like a ROD file
+    inc(r.pos, 4)
+    var version = ""
+    while r.s[r.pos] notin {'\0', '\x0A'}:
+      add(version, r.s[r.pos])
+      inc(r.pos)
+    if r.s[r.pos] == '\x0A': inc(r.pos)
+    if version != RodFileVersion: 
+      # since ROD files are only for caching, no backwards compatibility is
+      # needed
+      result = nil
+  else:
+    result = nil
+  
+proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType = 
+  result = PType(idTableGet(gTypeTable, id))
+  if result == nil: 
+    # load the type:
+    var oldPos = r.pos
+    var d = iiTableGet(r.index.tab, id)
+    if d == InvalidKey: internalError(info, "rrGetType")
+    r.pos = d + r.dataIdx
+    result = decodeType(r, info)
+    r.pos = oldPos
+
+type 
+  TFileModuleRec{.final.} = object 
+    filename*: string
+    reason*: TReasonForRecompile
+    rd*: PRodReader
+    crc*: TCrc32
+    crcDone*: bool
+
+  TFileModuleMap = seq[TFileModuleRec]
+
+var gMods*: TFileModuleMap = @[]
+
+proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym = 
+  # all compiled modules
+  if rd.dataIdx == 0: internalError(info, "dataIdx == 0")
+  var oldPos = rd.pos
+  rd.pos = offset + rd.dataIdx
+  result = decodeSym(rd, info)
+  rd.pos = oldPos
+
+proc findSomeWhere(id: int) =
+  for i in countup(0, high(gMods)): 
+    var rd = gMods[i].rd
+    if rd != nil: 
+      var d = iiTableGet(rd.index.tab, id)
+      if d != InvalidKey:
+        echo "found id ", id, " in ", gMods[i].filename
+
+proc getReader(moduleId: int): PRodReader =
+  # we can't index 'gMods' here as it's indexed by a *file index* which is not
+  # the module ID! We could introduce a mapping ID->PRodReader but I'll leave
+  # this for later versions if benchmarking shows the linear search causes
+  # problems:
+  for i in 0 .. <gMods.len:
+    result = gMods[i].rd
+    if result != nil and result.moduleID == moduleId: return result
+  return nil
+
+proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym = 
+  result = PSym(idTableGet(r.syms, id))
+  if result == nil: 
+    # load the symbol:
+    var d = iiTableGet(r.index.tab, id)
+    if d == InvalidKey: 
+      # import from other module:
+      var moduleID = iiTableGet(r.imports.tab, id)
+      if moduleID < 0:
+        var x = ""
+        encodeVInt(id, x)
+        internalError(info, "missing from both indexes: +" & x)
+      var rd = getReader(moduleID)
+      d = iiTableGet(rd.index.tab, id)
+      if d != InvalidKey: 
+        result = decodeSymSafePos(rd, d, info)
+      else:
+        var x = ""
+        encodeVInt(id, x)
+        when false: findSomeWhere(id)
+        internalError(info, "rrGetSym: no reader found: +" & x)
+    else: 
+      # own symbol:
+      result = decodeSymSafePos(r, d, info)
+  if result != nil and result.kind == skStub: rawLoadStub(result)
+  
+proc loadInitSection(r: PRodReader): PNode = 
+  if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection")
+  var oldPos = r.pos
+  r.pos = r.initIdx
+  result = newNode(nkStmtList)
+  while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
+    var d = decodeVInt(r.s, r.pos)
+    inc(r.pos)                # #10
+    var p = r.pos
+    r.pos = d + r.dataIdx
+    addSon(result, decodeNode(r, unknownLineInfo()))
+    r.pos = p
+  r.pos = oldPos
+
+proc loadConverters(r: PRodReader) = 
+  # We have to ensure that no exported converter is a stub anymore, and the
+  # import mechanism takes care of the rest.
+  if r.convertersIdx == 0 or r.dataIdx == 0: 
+    internalError("importConverters")
+  r.pos = r.convertersIdx
+  while r.s[r.pos] > '\x0A': 
+    var d = decodeVInt(r.s, r.pos)
+    discard rrGetSym(r, d, unknownLineInfo())
+    if r.s[r.pos] == ' ': inc(r.pos)
+
+proc loadMethods(r: PRodReader) =
+  if r.methodsIdx == 0 or r.dataIdx == 0:
+    internalError("loadMethods")
+  r.pos = r.methodsIdx
+  while r.s[r.pos] > '\x0A':
+    var d = decodeVInt(r.s, r.pos)
+    r.methods.add(rrGetSym(r, d, unknownLineInfo()))
+    if r.s[r.pos] == ' ': inc(r.pos)
+
+proc getCRC*(fileIdx: int32): TCrc32 =
+  internalAssert fileIdx >= 0 and fileIdx < gMods.len
+
+  if gMods[fileIdx].crcDone:
+    return gMods[fileIdx].crc
+  
+  result = crcFromFile(fileIdx.toFilename)
+  gMods[fileIdx].crc = result
+
+template growCache*(cache, pos) =
+  if cache.len <= pos: cache.setLen(pos+1)
+
+proc checkDep(fileIdx: int32): TReasonForRecompile =
+  assert fileIdx != InvalidFileIDX
+  growCache gMods, fileIdx
+  if gMods[fileIdx].reason != rrEmpty: 
+    # reason has already been computed for this module:
+    return gMods[fileIdx].reason
+  let filename = fileIdx.toFilename
+  var crc = getCRC(fileIdx)
+  gMods[fileIdx].reason = rrNone  # we need to set it here to avoid cycles
+  result = rrNone
+  var r: PRodReader = nil
+  var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
+  r = newRodReader(rodfile, crc, fileIdx)
+  if r == nil: 
+    result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
+  else:
+    processRodFile(r, crc)
+    result = r.reason
+    if result == rrNone: 
+      # check modules it depends on
+      # NOTE: we need to process the entire module graph so that no ID will
+      # be used twice! However, compilation speed does not suffer much from
+      # this, since results are cached.
+      var res = checkDep(systemFileIdx)
+      if res != rrNone: result = rrModDeps
+      for i in countup(0, high(r.modDeps)):
+        res = checkDep(r.modDeps[i])
+        if res != rrNone:
+          result = rrModDeps
+          # we cannot break here, because of side-effects of `checkDep`
+  if result != rrNone and gVerbosity > 0:
+    rawMessage(hintProcessing, reasonToFrmt[result] % filename)
+  if result != rrNone or optForceFullMake in gGlobalOptions:
+    # recompilation is necessary:
+    if r != nil: memfiles.close(r.memfile)
+    r = nil
+  gMods[fileIdx].rd = r
+  gMods[fileIdx].reason = result  # now we know better
+  
+proc handleSymbolFile(module: PSym): PRodReader = 
+  let fileIdx = module.fileIdx
+  if optSymbolFiles notin gGlobalOptions: 
+    module.id = getID()
+    return nil
+  idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
+
+  discard checkDep(fileIdx)
+  if gMods[fileIdx].reason == rrEmpty: internalError("handleSymbolFile")
+  result = gMods[fileIdx].rd
+  if result != nil: 
+    module.id = result.moduleID
+    idTablePut(result.syms, module, module)
+    processInterf(result, module)
+    processCompilerProcs(result, module)
+    loadConverters(result)
+    loadMethods(result)
+  else:
+    module.id = getID()
+
+proc rawLoadStub(s: PSym) =
+  if s.kind != skStub: internalError("loadStub")
+  var rd = gMods[s.position].rd
+  var theId = s.id                # used for later check
+  var d = iiTableGet(rd.index.tab, s.id)
+  if d == InvalidKey: internalError("loadStub: invalid key")
+  var rs = decodeSymSafePos(rd, d, unknownLineInfo())
+  if rs != s:
+    #echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
+    #     "\ns:  ", toHex(cast[int](s.position), int.sizeof * 2)
+    internalError(rs.info, "loadStub: wrong symbol")
+  elif rs.id != theId: 
+    internalError(rs.info, "loadStub: wrong ID") 
+  #MessageOut('loaded stub: ' + s.name.s);
+  
+proc loadStub*(s: PSym) =
+  ## loads the stub symbol `s`.
+  
+  # deactivate the GC here because we do a deep recursion and generate no
+  # garbage when restoring parts of the object graph anyway.
+  # Since we die with internal errors if this fails, no try-finally is
+  # necessary.
+  GC_disable()
+  rawLoadStub(s)
+  GC_enable()
+  
+proc getBody*(s: PSym): PNode =
+  ## retrieves the AST's body of `s`. If `s` has been loaded from a rod-file
+  ## it may perform an expensive reload operation. Otherwise it's a simple
+  ## accessor.
+  assert s.kind in routineKinds
+  result = s.ast.sons[bodyPos]
+  if result == nil:
+    assert s.offset != 0
+    var r = gMods[s.position].rd
+    var oldPos = r.pos
+    r.pos = s.offset
+    result = decodeNode(r, s.info)
+    r.pos = oldPos
+    s.ast.sons[bodyPos] = result
+    s.offset = 0
+  
+initIdTable(gTypeTable)
+initStrTable(rodCompilerprocs)
+
+# viewer:
+proc writeNode(f: File; n: PNode) =
+  f.write("(")
+  if n != nil:
+    f.write($n.kind)
+    if n.typ != nil:
+      f.write('^')
+      f.write(n.typ.id)
+    case n.kind
+    of nkCharLit..nkInt64Lit: 
+      if n.intVal != 0:
+        f.write('!')
+        f.write(n.intVal)
+    of nkFloatLit..nkFloat64Lit: 
+      if n.floatVal != 0.0: 
+        f.write('!')
+        f.write($n.floatVal)
+    of nkStrLit..nkTripleStrLit:
+      if n.strVal != "": 
+        f.write('!')
+        f.write(n.strVal.escape)
+    of nkIdent:
+      f.write('!')
+      f.write(n.ident.s)
+    of nkSym:
+      f.write('!')
+      f.write(n.sym.id)
+    else:
+      for i in countup(0, sonsLen(n) - 1): 
+        writeNode(f, n.sons[i])
+  f.write(")")
+
+proc writeSym(f: File; s: PSym) =
+  if s == nil:
+    f.write("{}\n")
+    return
+  f.write("{")
+  f.write($s.kind)
+  f.write('+')
+  f.write(s.id)
+  f.write('&')
+  f.write(s.name.s)
+  if s.typ != nil:
+    f.write('^')
+    f.write(s.typ.id)
+  if s.owner != nil:
+    f.write('*')
+    f.write(s.owner.id)
+  if s.flags != {}:
+    f.write('$')
+    f.write($s.flags)
+  if s.magic != mNone:
+    f.write('@')
+    f.write($s.magic)
+  if s.options != gOptions: 
+    f.write('!')
+    f.write($s.options)
+  if s.position != 0: 
+    f.write('%')
+    f.write($s.position)
+  if s.offset != -1:
+    f.write('`')
+    f.write($s.offset)
+  if s.constraint != nil:
+    f.write('#')
+    f.writeNode(s.constraint)
+  if s.ast != nil:
+    f.writeNode(s.ast)
+  f.write("}\n")
+
+proc writeType(f: File; t: PType) =
+  if t == nil:
+    f.write("[]\n")
+    return
+  f.write('[')
+  f.write($t.kind)
+  f.write('+')
+  f.write($t.id)
+  if t.n != nil: 
+    f.writeNode(t.n)
+  if t.flags != {}:
+    f.write('$')
+    f.write($t.flags)
+  if t.callConv != low(t.callConv): 
+    f.write('?')
+    f.write($t.callConv)
+  if t.owner != nil:
+    f.write('*')
+    f.write($t.owner.id)
+  if t.sym != nil:
+    f.write('&')
+    f.write(t.sym.id)
+  if t.size != -1:
+    f.write('/')
+    f.write($t.size)
+  if t.align != 2:
+    f.write('=')
+    f.write($t.align)
+  for i in countup(0, sonsLen(t) - 1): 
+    if t.sons[i] == nil: 
+      f.write("^()")
+    else:
+      f.write('^') 
+      f.write($t.sons[i].id)
+  f.write("]\n")
+
+proc viewFile(rodfile: string) =
+  var r = newRodReader(rodfile, 0, 0)
+  if r == nil:
+    rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
+       rodfile)
+    return
+  r.inViewMode = true
+  var outf = system.open(rodfile.changeFileExt(".rod.txt"), fmWrite)
+  while r.s[r.pos] != '\0':
+    let section = rdWord(r)
+    case section
+    of "CRC":
+      inc(r.pos)              # skip ':'
+      outf.writeln("CRC:", $decodeVInt(r.s, r.pos))
+    of "ID": 
+      inc(r.pos)              # skip ':'
+      r.moduleID = decodeVInt(r.s, r.pos)
+      setId(r.moduleID)
+      outf.writeln("ID:", $r.moduleID)
+    of "ORIGFILE":
+      inc(r.pos)
+      r.origFile = decodeStr(r.s, r.pos)
+      outf.writeln("ORIGFILE:", r.origFile)
+    of "OPTIONS":
+      inc(r.pos)              # skip ':'
+      r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
+      outf.writeln("OPTIONS:", $r.options)
+    of "GOPTIONS":
+      inc(r.pos)              # skip ':'
+      let dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos)))
+      outf.writeln("GOPTIONS:", $dep)
+    of "CMD":
+      inc(r.pos)              # skip ':'
+      let dep = cast[TCommands](int32(decodeVInt(r.s, r.pos)))
+      outf.writeln("CMD:", $dep)
+    of "DEFINES":
+      inc(r.pos)              # skip ':'
+      var d = 0
+      outf.write("DEFINES:")
+      while r.s[r.pos] > '\x0A':
+        let w = decodeStr(r.s, r.pos)
+        inc(d)
+        outf.write(" ", w)
+        if r.s[r.pos] == ' ': inc(r.pos)
+      outf.write("\n")
+    of "FILES":
+      inc(r.pos, 2)           # skip "(\10"
+      inc(r.line)
+      outf.write("FILES(\n")
+      while r.s[r.pos] != ')':
+        let relativePath = decodeStr(r.s, r.pos)
+        let resolvedPath = relativePath.findModule(r.origFile)
+        let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
+        r.files.add(finalPath.fileInfoIdx)
+        inc(r.pos)            # skip #10
+        inc(r.line)
+        outf.writeln finalPath
+      if r.s[r.pos] == ')': inc(r.pos)
+      outf.write(")\n")
+    of "INCLUDES": 
+      inc(r.pos, 2)           # skip "(\10"
+      inc(r.line)
+      outf.write("INCLUDES(\n")
+      while r.s[r.pos] != ')': 
+        let w = r.files[decodeVInt(r.s, r.pos)]
+        inc(r.pos)            # skip ' '
+        let inclCrc = decodeVInt(r.s, r.pos)
+        if r.s[r.pos] == '\x0A': 
+          inc(r.pos)
+          inc(r.line)
+        outf.write(w, " ", inclCrc, "\n")
+      if r.s[r.pos] == ')': inc(r.pos)
+      outf.write(")\n")
+    of "DEPS":
+      inc(r.pos)              # skip ':'
+      outf.write("DEPS:")
+      while r.s[r.pos] > '\x0A': 
+        let v = int32(decodeVInt(r.s, r.pos))
+        r.modDeps.add(r.files[v])
+        if r.s[r.pos] == ' ': inc(r.pos)
+        outf.write(" ", r.files[v])
+      outf.write("\n")
+    of "INTERF",  "COMPILERPROCS":
+      inc r.pos, 2
+      if section == "INTERF": r.interfIdx = r.pos
+      else: r.compilerProcsIdx = r.pos
+      outf.write(section, "(\n")
+      while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
+        let w = decodeStr(r.s, r.pos)
+        inc(r.pos)
+        let key = decodeVInt(r.s, r.pos)
+        inc(r.pos)                # #10
+        outf.write(w, " ", key, "\n")
+      if r.s[r.pos] == ')': inc r.pos
+      outf.write(")\n")
+    of "INDEX":
+      outf.write(section, "(\n")
+      processIndex(r, r.index, outf)
+      outf.write(")\n")
+    of "IMPORTS":
+      outf.write(section, "(\n")
+      processIndex(r, r.imports, outf)
+      outf.write(")\n")
+    of "CONVERTERS",  "METHODS":
+      inc r.pos
+      if section == "METHODS": r.methodsIdx = r.pos
+      else: r.convertersIdx = r.pos
+      outf.write(section, ":")
+      while r.s[r.pos] > '\x0A': 
+        let d = decodeVInt(r.s, r.pos)
+        outf.write(" ", $d)
+        if r.s[r.pos] == ' ': inc(r.pos)
+      outf.write("\n")
+    of "DATA":
+      inc(r.pos, 2)
+      r.dataIdx = r.pos
+      outf.write("DATA(\n")
+      while r.s[r.pos] != ')':
+        if r.s[r.pos] == '(':
+          outf.writeNode decodeNode(r, unknownLineInfo())
+          outf.write("\n")
+        elif r.s[r.pos] == '[':
+          outf.writeType decodeType(r, unknownLineInfo())
+        else:
+          outf.writeSym decodeSym(r, unknownLineInfo())
+        if r.s[r.pos] == '\x0A':
+          inc(r.pos)
+          inc(r.line)
+      if r.s[r.pos] == ')': inc r.pos
+      outf.write(")\n")
+    of "INIT":
+      outf.write("INIT(\n")
+      inc r.pos, 2
+      r.initIdx = r.pos
+      while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
+        let d = decodeVInt(r.s, r.pos)
+        inc(r.pos)                # #10
+        #let p = r.pos
+        #r.pos = d + r.dataIdx
+        #outf.writeNode decodeNode(r, UnknownLineInfo())
+        #outf.write("\n")
+        #r.pos = p
+      if r.s[r.pos] == ')': inc r.pos
+      outf.write("<not supported by viewer>)\n")
+    else:
+      internalError("invalid section: '" & section &
+                    "' at " & $r.line & " in " & r.filename)
+      skipSection(r)
+    if r.s[r.pos] == '\x0A':
+      inc(r.pos)
+      inc(r.line)
+  outf.close
+
+when isMainModule:
+  viewFile(paramStr(1).addFileExt(rodExt))
diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim
new file mode 100644
index 000000000..e0ef3c397
--- /dev/null
+++ b/compiler/rodutils.nim
@@ -0,0 +1,136 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Serialization utilities for the compiler.
+import strutils
+
+proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", header: "<stdio.h>", nodecl, varargs.}
+
+proc toStrMaxPrecision*(f: BiggestFloat): string = 
+  if f != f:
+    result = "NAN"
+  elif f == 0.0:
+    result = "0.0"
+  elif f == 0.5 * f:
+    if f > 0.0: result = "INF"
+    else: result = "-INF"
+  else:
+    var buf: array [0..80, char]    
+    c_sprintf(buf, "%#.16e", f) 
+    result = $buf
+
+proc encodeStr*(s: string, result: var string) =
+  for i in countup(0, len(s) - 1): 
+    case s[i]
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
+    else: add(result, '\\' & toHex(ord(s[i]), 2))
+
+proc hexChar(c: char, xi: var int) = 
+  case c
+  of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
+  of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
+  else: discard
+
+proc decodeStr*(s: cstring, pos: var int): string =
+  var i = pos
+  result = ""
+  while true: 
+    case s[i]
+    of '\\': 
+      inc(i, 3)
+      var xi = 0
+      hexChar(s[i-2], xi)
+      hexChar(s[i-1], xi)
+      add(result, chr(xi))
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': 
+      add(result, s[i])
+      inc(i)
+    else: break 
+  pos = i
+
+const
+  chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+# since negative numbers require a leading '-' they use up 1 byte. Thus we
+# subtract/add `vintDelta` here to save space for small negative numbers
+# which are common in ROD files:
+const
+  vintDelta = 5
+
+template encodeIntImpl(self: expr) =
+  var d: char
+  var v = x
+  var rem = v mod 190
+  if rem < 0: 
+    add(result, '-')
+    v = - (v div 190)
+    rem = - rem
+  else: 
+    v = v div 190
+  var idx = int(rem)
+  if idx < 62: d = chars[idx]
+  else: d = chr(idx - 62 + 128)
+  if v != 0: self(v, result)
+  add(result, d)
+
+proc encodeVBiggestIntAux(x: BiggestInt, result: var string) =
+  ## encode a biggest int as a variable length base 190 int.
+  encodeIntImpl(encodeVBiggestIntAux)
+
+proc encodeVBiggestInt*(x: BiggestInt, result: var string) =
+  ## encode a biggest int as a variable length base 190 int.
+  encodeVBiggestIntAux(x +% vintDelta, result)
+  #  encodeIntImpl(encodeVBiggestInt)
+
+proc encodeVIntAux(x: int, result: var string) = 
+  ## encode an int as a variable length base 190 int.
+  encodeIntImpl(encodeVIntAux)
+  
+proc encodeVInt*(x: int, result: var string) = 
+  ## encode an int as a variable length base 190 int.
+  encodeVIntAux(x +% vintDelta, result)
+
+template decodeIntImpl() =
+  var i = pos
+  var sign = - 1
+  assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
+  if s[i] == '-': 
+    inc(i)
+    sign = 1
+  result = 0
+  while true: 
+    case s[i]
+    of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0'))
+    of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10)
+    of 'A'..'Z': result = result * 190 - (ord(s[i]) - ord('A') + 36)
+    of '\x80'..'\xFF': result = result * 190 - (ord(s[i]) - 128 + 62)
+    else: break
+    inc(i)
+  result = result * sign -% vintDelta
+  pos = i
+
+proc decodeVInt*(s: cstring, pos: var int): int = 
+  decodeIntImpl()
+
+proc decodeVBiggestInt*(s: cstring, pos: var int): BiggestInt =
+  decodeIntImpl()
+
+iterator decodeVIntArray*(s: cstring): int =
+  var i = 0
+  while s[i] != '\0':
+    yield decodeVInt(s, i)
+    if s[i] == ' ': inc i
+
+iterator decodeStrArray*(s: cstring): string =
+  var i = 0
+  while s[i] != '\0':
+    yield decodeStr(s, i)
+    if s[i] == ' ': inc i
+
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
new file mode 100644
index 000000000..e178b7ce6
--- /dev/null
+++ b/compiler/rodwrite.nim
@@ -0,0 +1,588 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module is responsible for writing of rod files. Note that writing of
+# rod files is a pass, reading of rod files is not! This is why reading and
+# writing of rod files is split into two different modules.
+
+import 
+  intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
+  condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils
+
+# implementation
+
+type 
+  TRodWriter = object of TPassContext
+    module: PSym
+    crc: TCrc32
+    options: TOptions
+    defines: string
+    inclDeps: string
+    modDeps: string
+    interf: string
+    compilerProcs: string
+    index, imports: TIndex
+    converters, methods: string
+    init: string
+    data: string
+    sstack: TSymSeq          # a stack of symbols to process
+    tstack: TTypeSeq         # a stack of types to process
+    files: TStringSeq
+    origFile: string
+
+  PRodWriter = ref TRodWriter
+
+proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter
+proc addModDep(w: PRodWriter, dep: string)
+proc addInclDep(w: PRodWriter, dep: string)
+proc addInterfaceSym(w: PRodWriter, s: PSym)
+proc addStmt(w: PRodWriter, n: PNode)
+proc writeRod(w: PRodWriter)
+
+proc getDefines(): string = 
+  result = ""
+  for d in definedSymbolNames():
+    if result.len != 0: add(result, " ")
+    add(result, d)
+
+proc fileIdx(w: PRodWriter, filename: string): int = 
+  for i in countup(0, high(w.files)): 
+    if w.files[i] == filename: 
+      return i
+  result = len(w.files)
+  setLen(w.files, result + 1)
+  w.files[result] = filename
+
+template filename*(w: PRodWriter): string =
+  w.module.filename
+
+proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter = 
+  new(result)
+  result.sstack = @[]
+  result.tstack = @[]
+  initIiTable(result.index.tab)
+  initIiTable(result.imports.tab)
+  result.index.r = ""
+  result.imports.r = ""
+  result.crc = crc
+  result.module = module
+  result.defines = getDefines()
+  result.options = options.gOptions
+  result.files = @[]
+  result.inclDeps = ""
+  result.modDeps = ""
+  result.interf = newStringOfCap(2_000)
+  result.compilerProcs = ""
+  result.converters = ""
+  result.methods = ""
+  result.init = ""
+  result.origFile = module.info.toFilename
+  result.data = newStringOfCap(12_000)
+  
+proc addModDep(w: PRodWriter, dep: string) =
+  if w.modDeps.len != 0: add(w.modDeps, ' ')
+  encodeVInt(fileIdx(w, dep), w.modDeps)
+
+const 
+  rodNL = "\x0A"
+
+proc addInclDep(w: PRodWriter, dep: string) =
+  var resolved = dep.findModule(w.module.info.toFullPath)
+  encodeVInt(fileIdx(w, dep), w.inclDeps)
+  add(w.inclDeps, " ")
+  encodeVInt(crcFromFile(resolved), w.inclDeps)
+  add(w.inclDeps, rodNL)
+
+proc pushType(w: PRodWriter, t: PType) =
+  # check so that the stack does not grow too large:
+  if iiTableGet(w.index.tab, t.id) == InvalidKey:
+    w.tstack.add(t)
+
+proc pushSym(w: PRodWriter, s: PSym) =
+  # check so that the stack does not grow too large:
+  if iiTableGet(w.index.tab, s.id) == InvalidKey:
+    w.sstack.add(s)
+
+proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, 
+                result: var string) = 
+  if n == nil: 
+    # nil nodes have to be stored too:
+    result.add("()")
+    return
+  result.add('(')
+  encodeVInt(ord(n.kind), result) 
+  # we do not write comments for now
+  # Line information takes easily 20% or more of the filesize! Therefore we
+  # omit line information if it is the same as the father's line information:
+  if fInfo.fileIndex != n.info.fileIndex: 
+    result.add('?')
+    encodeVInt(n.info.col, result)
+    result.add(',')
+    encodeVInt(n.info.line, result)
+    result.add(',')
+    encodeVInt(fileIdx(w, toFilename(n.info)), result)
+  elif fInfo.line != n.info.line:
+    result.add('?')
+    encodeVInt(n.info.col, result)
+    result.add(',')
+    encodeVInt(n.info.line, result)
+  elif fInfo.col != n.info.col:
+    result.add('?')
+    encodeVInt(n.info.col, result)
+  # No need to output the file index, as this is the serialization of one
+  # file.
+  var f = n.flags * PersistentNodeFlags
+  if f != {}: 
+    result.add('$')
+    encodeVInt(cast[int32](f), result)
+  if n.typ != nil:
+    result.add('^')
+    encodeVInt(n.typ.id, result)
+    pushType(w, n.typ)
+  case n.kind
+  of nkCharLit..nkInt64Lit: 
+    if n.intVal != 0:
+      result.add('!')
+      encodeVBiggestInt(n.intVal, result)
+  of nkFloatLit..nkFloat64Lit: 
+    if n.floatVal != 0.0: 
+      result.add('!')
+      encodeStr($n.floatVal, result)
+  of nkStrLit..nkTripleStrLit:
+    if n.strVal != "": 
+      result.add('!')
+      encodeStr(n.strVal, result)
+  of nkIdent:
+    result.add('!')
+    encodeStr(n.ident.s, result)
+  of nkSym:
+    result.add('!')
+    encodeVInt(n.sym.id, result)
+    pushSym(w, n.sym)
+  else:
+    for i in countup(0, sonsLen(n) - 1): 
+      encodeNode(w, n.info, n.sons[i], result)
+  add(result, ')')
+
+proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = 
+  var oldLen = result.len
+  result.add('<')
+  if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
+  if loc.s != low(loc.s): 
+    add(result, '*')
+    encodeVInt(ord(loc.s), result)
+  if loc.flags != {}: 
+    add(result, '$')
+    encodeVInt(cast[int32](loc.flags), result)
+  if loc.t != nil:
+    add(result, '^')
+    encodeVInt(cast[int32](loc.t.id), result)
+    pushType(w, loc.t)
+  if loc.r != nil: 
+    add(result, '!')
+    encodeStr($loc.r, result)
+  if oldLen + 1 == result.len:
+    # no data was necessary, so remove the '<' again:
+    setLen(result, oldLen)
+  else:
+    add(result, '>')
+  
+proc encodeType(w: PRodWriter, t: PType, result: var string) = 
+  if t == nil: 
+    # nil nodes have to be stored too:
+    result.add("[]")
+    return
+  # we need no surrounding [] here because the type is in a line of its own
+  if t.kind == tyForward: internalError("encodeType: tyForward")
+  # for the new rodfile viewer we use a preceding [ so that the data section
+  # can easily be disambiguated:
+  add(result, '[')
+  encodeVInt(ord(t.kind), result)
+  add(result, '+')
+  encodeVInt(t.id, result)
+  if t.n != nil: 
+    encodeNode(w, unknownLineInfo(), t.n, result)
+  if t.flags != {}: 
+    add(result, '$')
+    encodeVInt(cast[int32](t.flags), result)
+  if t.callConv != low(t.callConv): 
+    add(result, '?')
+    encodeVInt(ord(t.callConv), result)
+  if t.owner != nil: 
+    add(result, '*')
+    encodeVInt(t.owner.id, result)
+    pushSym(w, t.owner)
+  if t.sym != nil: 
+    add(result, '&')
+    encodeVInt(t.sym.id, result)
+    pushSym(w, t.sym)
+  if t.size != - 1: 
+    add(result, '/')
+    encodeVBiggestInt(t.size, result)
+  if t.align != 2: 
+    add(result, '=')
+    encodeVInt(t.align, result)
+  encodeLoc(w, t.loc, result)
+  for i in countup(0, sonsLen(t) - 1): 
+    if t.sons[i] == nil: 
+      add(result, "^()")
+    else: 
+      add(result, '^') 
+      encodeVInt(t.sons[i].id, result)
+      pushType(w, t.sons[i])
+
+proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = 
+  add(result, '|')
+  encodeVInt(ord(lib.kind), result)
+  add(result, '|')
+  encodeStr($lib.name, result)
+  add(result, '|')
+  encodeNode(w, info, lib.path, result)
+
+proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
+  if s == nil:
+    # nil nodes have to be stored too:
+    result.add("{}")
+    return
+  # we need no surrounding {} here because the symbol is in a line of its own
+  encodeVInt(ord(s.kind), result)
+  result.add('+')
+  encodeVInt(s.id, result)
+  result.add('&')
+  encodeStr(s.name.s, result)
+  if s.typ != nil:
+    result.add('^')
+    encodeVInt(s.typ.id, result)
+    pushType(w, s.typ)
+  result.add('?')
+  if s.info.col != -1'i16: encodeVInt(s.info.col, result)
+  result.add(',')
+  if s.info.line != -1'i16: encodeVInt(s.info.line, result)
+  result.add(',')
+  encodeVInt(fileIdx(w, toFilename(s.info)), result)
+  if s.owner != nil:
+    result.add('*')
+    encodeVInt(s.owner.id, result)
+    pushSym(w, s.owner)
+  if s.flags != {}:
+    result.add('$')
+    encodeVInt(cast[int32](s.flags), result)
+  if s.magic != mNone:
+    result.add('@')
+    encodeVInt(ord(s.magic), result)
+  if s.options != w.options: 
+    result.add('!')
+    encodeVInt(cast[int32](s.options), result)
+  if s.position != 0: 
+    result.add('%')
+    encodeVInt(s.position, result)
+  if s.offset != - 1:
+    result.add('`')
+    encodeVInt(s.offset, result)
+  encodeLoc(w, s.loc, result)
+  if s.annex != nil: encodeLib(w, s.annex, s.info, result)
+  if s.constraint != nil:
+    add(result, '#')
+    encodeNode(w, unknownLineInfo(), s.constraint, result)
+  # lazy loading will soon reload the ast lazily, so the ast needs to be
+  # the last entry of a symbol:
+  if s.ast != nil:
+    # we used to attempt to save space here by only storing a dummy AST if
+    # it is not necessary, but Nim's heavy compile-time evaluation features
+    # make that unfeasible nowadays:
+    encodeNode(w, s.info, s.ast, result)
+    when false:
+      var codeAst: PNode = nil
+      if not astNeeded(s):
+        codeAst = s.ast.sons[codePos]
+        # ugly hack to not store the AST:
+        s.ast.sons[codePos] = ast.emptyNode
+      encodeNode(w, s.info, s.ast, result)
+      if codeAst != nil:
+        # resore the AST:
+        s.ast.sons[codePos] = codeAst
+  
+proc addToIndex(w: var TIndex, key, val: int) =
+  if key - w.lastIdxKey == 1:
+    # we do not store a key-diff of 1 to safe space
+    encodeVInt(val - w.lastIdxVal, w.r)
+  else:
+    encodeVInt(key - w.lastIdxKey, w.r)
+    add(w.r, ' ')
+    encodeVInt(val - w.lastIdxVal, w.r)
+  add(w.r, rodNL)
+  w.lastIdxKey = key
+  w.lastIdxVal = val
+  iiTablePut(w.tab, key, val)
+
+const debugWrittenIds = false
+
+when debugWrittenIds:
+  var debugWritten = initIntSet()
+
+proc symStack(w: PRodWriter): int =
+  var i = 0
+  while i < len(w.sstack): 
+    var s = w.sstack[i]
+    if sfForward in s.flags:
+      w.sstack[result] = s
+      inc result
+    elif iiTableGet(w.index.tab, s.id) == InvalidKey:
+      var m = getModule(s)
+      if m == nil: internalError("symStack: module nil: " & s.name.s)
+      if (m.id == w.module.id) or (sfFromGeneric in s.flags): 
+        # put definition in here
+        var L = w.data.len
+        addToIndex(w.index, s.id, L) 
+        when debugWrittenIds: incl(debugWritten, s.id)
+        encodeSym(w, s, w.data)
+        add(w.data, rodNL)
+        # put into interface section if appropriate:
+        if {sfExported, sfFromGeneric} * s.flags == {sfExported} and 
+            s.kind in ExportableSymKinds: 
+          encodeStr(s.name.s, w.interf)
+          add(w.interf, ' ')
+          encodeVInt(s.id, w.interf)
+          add(w.interf, rodNL)
+        if sfCompilerProc in s.flags:
+          encodeStr(s.name.s, w.compilerProcs)
+          add(w.compilerProcs, ' ')
+          encodeVInt(s.id, w.compilerProcs)
+          add(w.compilerProcs, rodNL)
+        if s.kind == skConverter or hasPattern(s):
+          if w.converters.len != 0: add(w.converters, ' ')
+          encodeVInt(s.id, w.converters)
+        if s.kind == skMethod and sfDispatcher notin s.flags:
+          if w.methods.len != 0: add(w.methods, ' ')
+          encodeVInt(s.id, w.methods)
+      elif iiTableGet(w.imports.tab, s.id) == InvalidKey: 
+        addToIndex(w.imports, s.id, m.id)
+        when debugWrittenIds:
+          if not Contains(debugWritten, s.id):
+            echo(w.filename)
+            debug(s)
+            debug(s.owner)
+            debug(m)
+            InternalError("Symbol referred to but never written")
+    inc(i)
+  setLen(w.sstack, result)
+
+proc typeStack(w: PRodWriter): int = 
+  var i = 0
+  while i < len(w.tstack): 
+    var t = w.tstack[i]
+    if t.kind == tyForward:
+      w.tstack[result] = t
+      inc result
+    elif iiTableGet(w.index.tab, t.id) == InvalidKey: 
+      var L = w.data.len
+      addToIndex(w.index, t.id, L)
+      encodeType(w, t, w.data)
+      add(w.data, rodNL)
+    inc(i)
+  setLen(w.tstack, result)
+
+proc processStacks(w: PRodWriter, finalPass: bool) =
+  var oldS = 0
+  var oldT = 0
+  while true:
+    var slen = symStack(w)
+    var tlen = typeStack(w)
+    if slen == oldS and tlen == oldT: break
+    oldS = slen
+    oldT = tlen
+  if finalPass and (oldS != 0 or oldT != 0):
+    internalError("could not serialize some forwarded symbols/types")
+
+proc rawAddInterfaceSym(w: PRodWriter, s: PSym) = 
+  pushSym(w, s)
+  processStacks(w, false)
+
+proc addInterfaceSym(w: PRodWriter, s: PSym) = 
+  if w == nil: return 
+  if s.kind in ExportableSymKinds and 
+      {sfExported, sfCompilerProc} * s.flags != {}: 
+    rawAddInterfaceSym(w, s)
+
+proc addStmt(w: PRodWriter, n: PNode) = 
+  encodeVInt(w.data.len, w.init)
+  add(w.init, rodNL)
+  encodeNode(w, unknownLineInfo(), n, w.data)
+  add(w.data, rodNL)
+  processStacks(w, false)
+
+proc writeRod(w: PRodWriter) = 
+  processStacks(w, true)
+  var f: File
+  if not open(f, completeGeneratedFilePath(changeFileExt(
+                      w.filename.withPackageName, RodExt)),
+              fmWrite):
+    #echo "couldn't write rod file for: ", w.filename
+    return
+  # write header:
+  f.write("NIM:")
+  f.write(RodFileVersion)
+  f.write(rodNL)
+  var id = "ID:"
+  encodeVInt(w.module.id, id)
+  f.write(id)
+  f.write(rodNL)
+
+  var orig = "ORIGFILE:"
+  encodeStr(w.origFile, orig)
+  f.write(orig)
+  f.write(rodNL)
+  
+  var crc = "CRC:"
+  encodeVInt(w.crc, crc)
+  f.write(crc)
+  f.write(rodNL)
+  
+  var options = "OPTIONS:"
+  encodeVInt(cast[int32](w.options), options)
+  f.write(options)
+  f.write(rodNL)
+
+  var goptions = "GOPTIONS:"
+  encodeVInt(cast[int32](gGlobalOptions), goptions)
+  f.write(goptions)
+  f.write(rodNL)
+
+  var cmd = "CMD:"
+  encodeVInt(cast[int32](gCmd), cmd)
+  f.write(cmd)
+  f.write(rodNL)  
+  
+  f.write("DEFINES:")
+  f.write(w.defines)
+  f.write(rodNL)
+  
+  var files = "FILES(" & rodNL
+  for i in countup(0, high(w.files)): 
+    encodeStr(w.files[i], files)
+    files.add(rodNL)
+  f.write(files)
+  f.write(')' & rodNL)
+  
+  f.write("INCLUDES(" & rodNL)
+  f.write(w.inclDeps)
+  f.write(')' & rodNL)
+  
+  f.write("DEPS:")
+  f.write(w.modDeps)
+  f.write(rodNL)
+  
+  f.write("INTERF(" & rodNL)
+  f.write(w.interf)
+  f.write(')' & rodNL)
+  
+  f.write("COMPILERPROCS(" & rodNL)
+  f.write(w.compilerProcs)
+  f.write(')' & rodNL)
+
+  f.write("INDEX(" & rodNL)
+  f.write(w.index.r)
+  f.write(')' & rodNL)
+  
+  f.write("IMPORTS(" & rodNL)
+  f.write(w.imports.r)
+  f.write(')' & rodNL)
+  
+  f.write("CONVERTERS:")
+  f.write(w.converters)
+  f.write(rodNL)
+
+  f.write("METHODS:")
+  f.write(w.methods)
+  f.write(rodNL)
+  
+  f.write("INIT(" & rodNL)
+  f.write(w.init)
+  f.write(')' & rodNL)
+  
+  f.write("DATA(" & rodNL)
+  f.write(w.data)
+  f.write(')' & rodNL)
+  # write trailing zero which is necessary because we use memory mapped files
+  # for reading:
+  f.write("\0")
+  f.close()
+  
+  #echo "interf: ", w.interf.len
+  #echo "index:  ", w.index.r.len
+  #echo "init:   ", w.init.len
+  #echo "data:   ", w.data.len
+
+proc process(c: PPassContext, n: PNode): PNode = 
+  result = n
+  if c == nil: return 
+  var w = PRodWriter(c)
+  case n.kind
+  of nkStmtList:
+    for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
+    #var s = n.sons[namePos].sym
+    #addInterfaceSym(w, s)
+  of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef, 
+      nkTemplateDef, nkMacroDef: 
+    var s = n.sons[namePos].sym
+    if s == nil: internalError(n.info, "rodwrite.process")
+    if n.sons[bodyPos] == nil:
+      internalError(n.info, "rodwrite.process: body is nil")
+    if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
+        sfForward notin s.flags:
+      addInterfaceSym(w, s)
+  of nkVarSection, nkLetSection, nkConstSection:
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue
+      addInterfaceSym(w, a.sons[0].sym)
+  of nkTypeSection: 
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
+      var s = a.sons[0].sym
+      addInterfaceSym(w, s) 
+      # this takes care of enum fields too
+      # Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
+      # type aliasing! Otherwise the same enum symbol would be included
+      # several times!
+      #
+      #        if (a.sons[2] <> nil) and (a.sons[2].kind = nkEnumTy) then begin
+      #          a := s.typ.n;
+      #          for j := 0 to sonsLen(a)-1 do 
+      #            addInterfaceSym(w, a.sons[j].sym);        
+      #        end 
+  of nkImportStmt: 
+    for i in countup(0, sonsLen(n) - 1): addModDep(w, getModuleName(n.sons[i]))
+    addStmt(w, n)
+  of nkFromStmt: 
+    addModDep(w, getModuleName(n.sons[0]))
+    addStmt(w, n)
+  of nkIncludeStmt: 
+    for i in countup(0, sonsLen(n) - 1): addInclDep(w, getModuleName(n.sons[i]))
+  of nkPragma: 
+    addStmt(w, n)
+  else: 
+    discard
+
+proc myOpen(module: PSym): PPassContext =
+  if module.id < 0: internalError("rodwrite: module ID not set")
+  var w = newRodWriter(module.fileIdx.getCRC, module)
+  rawAddInterfaceSym(w, module)
+  result = w
+
+proc myClose(c: PPassContext, n: PNode): PNode = 
+  result = process(c, n)
+  var w = PRodWriter(c)
+  writeRod(w)
+  idgen.saveMaxIds(options.gProjectPath / options.gProjectName)
+
+const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)
+
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
new file mode 100644
index 000000000..edac8e9d0
--- /dev/null
+++ b/compiler/ropes.nim
@@ -0,0 +1,350 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Ropes for the C code generator
+#
+#  Ropes are a data structure that represents a very long string
+#  efficiently; especially concatenation is done in O(1) instead of O(N).
+#  Ropes make use a lazy evaluation: They are essentially concatenation
+#  trees that are only flattened when converting to a native Nim
+#  string or when written to disk. The empty string is represented by a
+#  nil pointer.
+#  A little picture makes everything clear:
+#
+#  "this string" & " is internally " & "represented as"
+#
+#             con  -- inner nodes do not contain raw data
+#            /   \
+#           /     \
+#          /       \
+#        con       "represented as"
+#       /   \
+#      /     \
+#     /       \
+#    /         \
+#   /           \
+#"this string"  " is internally "
+#
+#  Note that this is the same as:
+#  "this string" & (" is internally " & "represented as")
+#
+#             con
+#            /   \
+#           /     \
+#          /       \
+# "this string"    con
+#                 /   \
+#                /     \
+#               /       \
+#              /         \
+#             /           \
+#" is internally "        "represented as"
+#
+#  The 'con' operator is associative! This does not matter however for
+#  the algorithms we use for ropes.
+#
+#  Note that the left and right pointers are not needed for leaves.
+#  Leaves have relatively high memory overhead (~30 bytes on a 32
+#  bit machines) and we produce many of them. This is why we cache and
+#  share leaves across different rope trees.
+#  To cache them they are inserted in a `cache` array.
+
+import
+  platform, hashes
+
+type
+  FormatStr* = string  # later we may change it to CString for better
+                       # performance of the code generator (assignments
+                       # copy the format strings
+                       # though it is not necessary)
+  Rope* = ref RopeObj
+  RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
+                                          # by nil to safe space
+    left*, right*: Rope
+    length*: int
+    data*: string             # != nil if a leaf
+
+  RopeSeq* = seq[Rope]
+
+  RopesError* = enum
+    rCannotOpenFile
+    rInvalidFormatStr
+
+# implementation
+
+var errorHandler*: proc(err: RopesError, msg: string, useWarning = false)
+  # avoid dependency on msgs.nim
+
+proc len*(a: Rope): int =
+  ## the rope's length
+  if a == nil: result = 0
+  else: result = a.length
+
+proc newRope(data: string = nil): Rope =
+  new(result)
+  if data != nil:
+    result.length = len(data)
+    result.data = data
+
+proc newMutableRope*(capacity = 30): Rope =
+  ## creates a new rope that supports direct modifications of the rope's
+  ## 'data' and 'length' fields.
+  new(result)
+  result.data = newStringOfCap(capacity)
+
+proc freezeMutableRope*(r: Rope) {.inline.} =
+  r.length = r.data.len
+
+var
+  cache: array[0..2048*2 - 1, Rope]
+
+proc resetRopeCache* =
+  for i in low(cache)..high(cache):
+    cache[i] = nil
+
+proc ropeInvariant(r: Rope): bool =
+  if r == nil:
+    result = true
+  else:
+    result = true #
+                  #    if r.data <> snil then
+                  #      result := true
+                  #    else begin
+                  #      result := (r.left <> nil) and (r.right <> nil);
+                  #      if result then result := ropeInvariant(r.left);
+                  #      if result then result := ropeInvariant(r.right);
+                  #    end
+
+var gCacheTries* = 0
+var gCacheMisses* = 0
+var gCacheIntTries* = 0
+
+proc insertInCache(s: string): Rope =
+  inc gCacheTries
+  var h = hash(s) and high(cache)
+  result = cache[h]
+  if isNil(result) or result.data != s:
+    inc gCacheMisses
+    result = newRope(s)
+    cache[h] = result
+
+proc rope*(s: string): Rope =
+  ## Converts a string to a rope.
+  if s.len == 0:
+    result = nil
+  else:
+    result = insertInCache(s)
+  assert(ropeInvariant(result))
+
+proc rope*(i: BiggestInt): Rope =
+  ## Converts an int to a rope.
+  inc gCacheIntTries
+  result = rope($i)
+
+proc rope*(f: BiggestFloat): Rope =
+  ## Converts a float to a rope.
+  result = rope($f)
+
+proc `&`*(a, b: Rope): Rope =
+  if a == nil:
+    result = b
+  elif b == nil:
+    result = a
+  else:
+    result = newRope()
+    result.length = a.length + b.length
+    result.left = a
+    result.right = b
+
+proc `&`*(a: Rope, b: string): Rope =
+  ## the concatenation operator for ropes.
+  result = a & rope(b)
+
+proc `&`*(a: string, b: Rope): Rope =
+  ## the concatenation operator for ropes.
+  result = rope(a) & b
+
+proc `&`*(a: openArray[Rope]): Rope =
+  ## the concatenation operator for an openarray of ropes.
+  for i in countup(0, high(a)): result = result & a[i]
+
+proc add*(a: var Rope, b: Rope) =
+  ## adds `b` to the rope `a`.
+  a = a & b
+
+proc add*(a: var Rope, b: string) =
+  ## adds `b` to the rope `a`.
+  a = a & b
+
+iterator leaves*(r: Rope): string =
+  ## iterates over any leaf string in the rope `r`.
+  if r != nil:
+    var stack = @[r]
+    while stack.len > 0:
+      var it = stack.pop
+      while isNil(it.data):
+        stack.add(it.right)
+        it = it.left
+        assert(it != nil)
+      assert(it.data != nil)
+      yield it.data
+
+iterator items*(r: Rope): char =
+  ## iterates over any character in the rope `r`.
+  for s in leaves(r):
+    for c in items(s): yield c
+
+proc writeRope*(f: File, r: Rope) =
+  ## writes a rope to a file.
+  for s in leaves(r): write(f, s)
+
+proc writeRope*(head: Rope, filename: string, useWarning = false) =
+  var f: File
+  if open(f, filename, fmWrite):
+    if head != nil: writeRope(f, head)
+    close(f)
+  else:
+    errorHandler(rCannotOpenFile, filename, useWarning)
+
+proc `$`*(r: Rope): string =
+  ## converts a rope back to a string.
+  result = newString(r.len)
+  setLen(result, 0)
+  for s in leaves(r): add(result, s)
+
+proc ropeConcat*(a: varargs[Rope]): Rope =
+  # not overloaded version of concat to speed-up `rfmt` a little bit
+  for i in countup(0, high(a)): result = result & a[i]
+
+proc prepend*(a: var Rope, b: Rope) = a = b & a
+proc prepend*(a: var Rope, b: string) = a = b & a
+
+var
+  rnl* = tnl.newRope
+  softRnl* = tnl.newRope
+
+proc `%`*(frmt: FormatStr, args: openArray[Rope]): Rope =
+  var i = 0
+  var length = len(frmt)
+  result = nil
+  var num = 0
+  while i < length:
+    if frmt[i] == '$':
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '$':
+        add(result, "$")
+        inc(i)
+      of '#':
+        inc(i)
+        add(result, args[num])
+        inc(num)
+      of '0'..'9':
+        var j = 0
+        while true:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+          if frmt[i] notin {'0'..'9'}: break
+        num = j
+        if j > high(args) + 1:
+          errorHandler(rInvalidFormatStr, $(j))
+        else:
+          add(result, args[j-1])
+      of '{':
+        inc(i)
+        var j = 0
+        while frmt[i] in {'0'..'9'}:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+        num = j
+        if frmt[i] == '}': inc(i)
+        else: errorHandler(rInvalidFormatStr, $(frmt[i]))
+
+        if j > high(args) + 1:
+          errorHandler(rInvalidFormatStr, $(j))
+        else:
+          add(result, args[j-1])
+      of 'n':
+        add(result, softRnl)
+        inc(i)
+      of 'N':
+        add(result, rnl)
+        inc(i)
+      else:
+        errorHandler(rInvalidFormatStr, $(frmt[i]))
+    var start = i
+    while i < length:
+      if frmt[i] != '$': inc(i)
+      else: break
+    if i - 1 >= start:
+      add(result, substr(frmt, start, i - 1))
+  assert(ropeInvariant(result))
+
+proc addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
+  ## shortcut for ``add(c, frmt % args)``.
+  add(c, frmt % args)
+
+when true:
+  template `~`*(r: string): Rope = r % []
+else:
+  {.push stack_trace: off, line_trace: off.}
+  proc `~`*(r: static[string]): Rope =
+    # this is the new optimized "to rope" operator
+    # the mnemonic is that `~` looks a bit like a rope :)
+    var r {.global.} = r % []
+    return r
+  {.pop.}
+
+const
+  bufSize = 1024              # 1 KB is reasonable
+
+proc equalsFile*(r: Rope, f: File): bool =
+  ## returns true if the contents of the file `f` equal `r`.
+  var 
+    buf: array[bufSize, char]
+    bpos = buf.len
+    blen = buf.len
+
+  for s in leaves(r):
+    var spos = 0
+    let slen = s.len
+    while spos < slen:
+      if bpos == blen:
+        # Read more data
+        bpos = 0
+        blen = readBuffer(f, addr(buf[0]), buf.len)
+        if blen == 0:  # no more data in file
+          result = false
+          return
+      let n = min(blen - bpos, slen - spos)
+      # TODO There's gotta be a better way of comparing here...
+      if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
+        result = false
+        return
+      spos += n
+      bpos += n
+
+  result = readBuffer(f, addr(buf[0]), 1) == 0  # check that we've read all
+
+proc equalsFile*(r: Rope, filename: string): bool =
+  ## returns true if the contents of the file `f` equal `r`. If `f` does not
+  ## exist, false is returned.
+  var f: File
+  result = open(f, filename)
+  if result:
+    result = equalsFile(r, f)
+    close(f)
+
+proc writeRopeIfNotEqual*(r: Rope, filename: string): bool =
+  # returns true if overwritten
+  if not equalsFile(r, filename):
+    writeRope(r, filename)
+    result = true
+  else:
+    result = false
diff --git a/compiler/saturate.nim b/compiler/saturate.nim
new file mode 100644
index 000000000..f4fe29a20
--- /dev/null
+++ b/compiler/saturate.nim
@@ -0,0 +1,79 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Saturated arithmetic routines. XXX Make part of the stdlib?
+
+proc `|+|`*(a, b: BiggestInt): BiggestInt =
+  ## saturated addition.
+  result = a +% b
+  if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
+    return result
+  if a < 0 or b < 0:
+    result = low(result)
+  else:
+    result = high(result)
+
+proc `|-|`*(a, b: BiggestInt): BiggestInt =
+  result = a -% b
+  if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
+    return result
+  if b > 0:
+    result = low(result)
+  else:
+    result = high(result)
+
+proc `|abs|`*(a: BiggestInt): BiggestInt =
+  if a != low(a):
+    if a >= 0: result = a
+    else: result = -a
+  else:
+    result = low(a)
+
+proc `|div|`*(a, b: BiggestInt): BiggestInt =
+  # (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
+  if b == 0'i64:
+    # make the same as ``div 1``:
+    result = a
+  elif a == low(a) and b == -1'i64:
+    result = high(result)
+  else:
+    result = a div b
+
+proc `|mod|`*(a, b: BiggestInt): BiggestInt =
+  if b == 0'i64:
+    result = a
+  else:
+    result = a mod b
+
+proc `|*|`*(a, b: BiggestInt): BiggestInt =
+  var
+    resAsFloat, floatProd: float64
+  result = a *% b
+  floatProd = toBiggestFloat(a) # conversion
+  floatProd = floatProd * toBiggestFloat(b)
+  resAsFloat = toBiggestFloat(result)
+
+  # Fast path for normal case: small multiplicands, and no info
+  # is lost in either method.
+  if resAsFloat == floatProd: return result
+
+  # Somebody somewhere lost info. Close enough, or way off? Note
+  # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
+  # The difference either is or isn't significant compared to the
+  # true value (of which floatProd is a good approximation).
+
+  # abs(diff)/abs(prod) <= 1/32 iff
+  #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
+  if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+    return result
+  
+  if floatProd >= 0.0:
+    result = high(result)
+  else:
+    result = low(result)
diff --git a/compiler/sem.nim b/compiler/sem.nim
new file mode 100644
index 000000000..346a17df1
--- /dev/null
+++ b/compiler/sem.nim
@@ -0,0 +1,478 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the semantic checking pass.
+
+import
+  ast, strutils, hashes, lists, options, lexer, astalgo, trees, treetab,
+  wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
+  magicsys, parser, nversion, nimsets, semfold, importer,
+  procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
+  intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
+  evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
+  semparallel, lowerings, plugins, plugins.active
+
+when defined(nimfix):
+  import nimfix.prettybase
+
+# implementation
+
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
+proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.
+  procvar.}
+proc semExprNoType(c: PContext, n: PNode): PNode
+proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+proc semProcBody(c: PContext, n: PNode): PNode
+
+proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
+proc changeType(n: PNode, newType: PType, check: bool)
+
+proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
+proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
+proc semStmt(c: PContext, n: PNode): PNode
+proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
+proc addParams(c: PContext, n: PNode, kind: TSymKind)
+proc maybeAddResult(c: PContext, s: PSym, n: PNode)
+proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
+proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+proc activate(c: PContext, n: PNode)
+proc semQuoteAst(c: PContext, n: PNode): PNode
+proc finishMethod(c: PContext, s: PSym)
+
+proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode
+
+template semIdeForTemplateOrGenericCheck(n, requiresCheck) =
+  # we check quickly if the node is where the cursor is
+  when defined(nimsuggest):
+    if n.info.fileIndex == gTrackPos.fileIndex and n.info.line == gTrackPos.line:
+      requiresCheck = true
+
+template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
+                                    requiresCheck: bool) =
+  # use only for idetools support; this is pretty slow so generics and
+  # templates perform some quick check whether the cursor is actually in
+  # the generic or template.
+  when defined(nimsuggest):
+    assert gCmd == cmdIdeTools
+    if requiresCheck:
+      if optIdeDebug in gGlobalOptions:
+        echo "passing to safeSemExpr: ", renderTree(n)
+      discard safeSemExpr(c, n)
+
+proc typeMismatch(n: PNode, formal, actual: PType) =
+  if formal.kind != tyError and actual.kind != tyError:
+    localError(n.info, errGenerated, msgKindToString(errTypeMismatch) &
+        typeToString(actual) & ") " &
+        `%`(msgKindToString(errButExpectedX), [typeToString(formal)]))
+
+proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
+  if arg.typ.isNil:
+    localError(arg.info, errExprXHasNoType,
+               renderTree(arg, {renderNoComments}))
+    # error correction:
+    result = copyNode(arg)
+    result.typ = formal
+  else:
+    result = indexTypesMatch(c, formal, arg.typ, arg)
+    if result == nil:
+      typeMismatch(arg, formal, arg.typ)
+      # error correction:
+      result = copyTree(arg)
+      result.typ = formal
+    else:
+      let x = result.skipConv
+      if x.kind == nkPar and formal.kind != tyExpr:
+        changeType(x, formal, check=true)
+      else:
+        result = skipHiddenSubConv(result)
+        #result.typ = takeType(formal, arg.typ)
+        #echo arg.info, " picked ", result.typ.typeToString
+
+proc inferWithMetatype(c: PContext, formal: PType,
+                       arg: PNode, coerceDistincts = false): PNode
+
+var commonTypeBegin = PType(kind: tyExpr)
+
+proc commonType*(x, y: PType): PType =
+  # new type relation that is used for array constructors,
+  # if expressions, etc.:
+  if x == nil: return x
+  if y == nil: return y
+  var a = skipTypes(x, {tyGenericInst})
+  var b = skipTypes(y, {tyGenericInst})
+  result = x
+  if a.kind in {tyExpr, tyNil}: result = y
+  elif b.kind in {tyExpr, tyNil}: result = x
+  elif a.kind == tyStmt: result = a
+  elif b.kind == tyStmt: result = b
+  elif a.kind == tyTypeDesc:
+    # turn any concrete typedesc into the abstract typedesc type
+    if a.sons == nil: result = a
+    else:
+      result = newType(tyTypeDesc, a.owner)
+      rawAddSon(result, newType(tyNone, a.owner))
+  elif b.kind in {tyArray, tyArrayConstr, tySet, tySequence} and
+      a.kind == b.kind:
+    # check for seq[empty] vs. seq[int]
+    let idx = ord(b.kind in {tyArray, tyArrayConstr})
+    if a.sons[idx].kind == tyEmpty: return y
+  elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
+    var nt: PType
+    for i in 0.. <a.len:
+      let aEmpty = isEmptyContainer(a.sons[i])
+      let bEmpty = isEmptyContainer(b.sons[i])
+      if aEmpty != bEmpty:
+        if nt.isNil: nt = copyType(a, a.owner, false)
+        nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i]
+    if not nt.isNil: result = nt
+    #elif b.sons[idx].kind == tyEmpty: return x
+  elif a.kind == tyRange and b.kind == tyRange:
+    # consider:  (range[0..3], range[0..4]) here. We should make that
+    # range[0..4]. But then why is (range[0..4], 6) not range[0..6]?
+    # But then why is (2,4) not range[2..4]? But I think this would break
+    # too much code. So ... it's the same range or the base type. This means
+    #  type(if b: 0 else 1) == int and not range[0..1]. For now. In the long
+    # run people expect ranges to work properly within a tuple.
+    if not sameType(a, b):
+      result = skipTypes(a, {tyRange}).skipIntLit
+    when false:
+      if a.kind != tyRange and b.kind == tyRange:
+        # XXX This really needs a better solution, but a proper fix now breaks
+        # code.
+        result = a #.skipIntLit
+      elif a.kind == tyRange and b.kind != tyRange:
+        result = b #.skipIntLit
+      elif a.kind in IntegralTypes and a.n != nil:
+        result = a #.skipIntLit
+  else:
+    var k = tyNone
+    if a.kind in {tyRef, tyPtr}:
+      k = a.kind
+      if b.kind != a.kind: return x
+      a = a.lastSon
+      b = b.lastSon
+    if a.kind == tyObject and b.kind == tyObject:
+      result = commonSuperclass(a, b)
+      # this will trigger an error later:
+      if result.isNil or result == a: return x
+      if result == b: return y
+      if k != tyNone:
+        let r = result
+        result = newType(k, r.owner)
+        result.addSonSkipIntLit(r)
+
+proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
+  result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
+
+proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
+  # like newSymS, but considers gensym'ed symbols
+  if n.kind == nkSym:
+    # and sfGenSym in n.sym.flags:
+    result = n.sym
+    internalAssert result.kind == kind
+    # when there is a nested proc inside a template, semtmpl
+    # will assign a wrong owner during the first pass over the
+    # template; we must fix it here: see #909
+    result.owner = getCurrOwner()
+  else:
+    result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
+
+proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
+                 allowed: TSymFlags): PSym
+  # identifier with visability
+proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
+                        allowed: TSymFlags): PSym
+proc semStmtScope(c: PContext, n: PNode): PNode
+
+proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind) =
+  let t = typeAllowed(typ, kind)
+  if t != nil:
+    if t == typ: localError(info, "invalid type: '" & typeToString(typ) & "'")
+    else: localError(info, "invalid type: '" & typeToString(t) &
+                           "' in this context: '" & typeToString(typ) & "'")
+
+proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
+  typeAllowedCheck(typ.n.info, typ, skConst)
+
+proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
+proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
+proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
+proc isOpImpl(c: PContext, n: PNode): PNode
+proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
+                     flags: TExprFlags = {}): PNode
+proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
+                  flags: TExprFlags = {}): PNode
+
+proc symFromType(t: PType, info: TLineInfo): PSym =
+  if t.sym != nil: return t.sym
+  result = newSym(skType, getIdent"AnonType", t.owner, info)
+  result.flags.incl sfAnon
+  result.typ = t
+
+proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
+  result = newSymNode(symFromType(t, info), info)
+  result.typ = makeTypeDesc(c, t)
+
+when false:
+  proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
+    result = newEvalContext(c.module, mode)
+    result.getType = proc (n: PNode): PNode =
+      result = tryExpr(c, n)
+      if result == nil:
+        result = newSymNode(errorSym(c, n))
+      elif result.typ == nil:
+        result = newSymNode(getSysSym"void")
+      else:
+        result.typ = makeTypeDesc(c, result.typ)
+
+    result.handleIsOperator = proc (n: PNode): PNode =
+      result = isOpImpl(c, n)
+
+proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
+  # recompute the types as 'eval' isn't guaranteed to construct types nor
+  # that the types are sound:
+  when true:
+    if eOrig.typ.kind in {tyExpr, tyStmt, tyTypeDesc}:
+      result = semExprWithType(c, evaluated)
+    else:
+      result = evaluated
+      let expectedType = eOrig.typ.skipTypes({tyStatic})
+      semmacrosanity.annotateType(result, expectedType)
+  else:
+    result = semExprWithType(c, evaluated)
+    #result = fitNode(c, e.typ, result) inlined with special case:
+    let arg = result
+    result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
+    if result == nil:
+      result = arg
+      # for 'tcnstseq' we support [] to become 'seq'
+      if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
+         arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
+        arg.typ = eOrig.typ
+
+proc tryConstExpr(c: PContext, n: PNode): PNode =
+  var e = semExprWithType(c, n)
+  if e == nil: return
+
+  result = getConstExpr(c.module, e)
+  if result != nil: return
+
+  let oldErrorCount = msgs.gErrorCounter
+  let oldErrorMax = msgs.gErrorMax
+  let oldErrorOutputs = errorOutputs
+
+  errorOutputs = {}
+  msgs.gErrorMax = high(int)
+
+  try:
+    result = evalConstExpr(c.module, e)
+    if result == nil or result.kind == nkEmpty:
+      result = nil
+    else:
+      result = fixupTypeAfterEval(c, result, e)
+
+  except ERecoverableError:
+    result = nil
+
+  msgs.gErrorCounter = oldErrorCount
+  msgs.gErrorMax = oldErrorMax
+  errorOutputs = oldErrorOutputs
+
+proc semConstExpr(c: PContext, n: PNode): PNode =
+  var e = semExprWithType(c, n)
+  if e == nil:
+    localError(n.info, errConstExprExpected)
+    return n
+  result = getConstExpr(c.module, e)
+  if result == nil:
+    #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
+    result = evalConstExpr(c.module, e)
+    if result == nil or result.kind == nkEmpty:
+      if e.info != n.info:
+        pushInfoContext(n.info)
+        localError(e.info, errConstExprExpected)
+        popInfoContext()
+      else:
+        localError(e.info, errConstExprExpected)
+      # error correction:
+      result = e
+    else:
+      result = fixupTypeAfterEval(c, result, e)
+
+include hlo, seminst, semcall
+
+proc semAfterMacroCall(c: PContext, n: PNode, s: PSym,
+                       flags: TExprFlags): PNode =
+  ## Semantically check the output of a macro.
+  ## This involves processes such as re-checking the macro output for type
+  ## coherence, making sure that variables declared with 'let' aren't
+  ## reassigned, and binding the unbound identifiers that the macro output
+  ## contains.
+  inc(evalTemplateCounter)
+  if evalTemplateCounter > 100:
+    globalError(s.info, errTemplateInstantiationTooNested)
+  c.friendModules.add(s.owner.getModule)
+
+  result = n
+  if s.typ.sons[0] == nil:
+    result = semStmt(c, result)
+  else:
+    case s.typ.sons[0].kind
+    of tyExpr:
+      # BUGFIX: we cannot expect a type here, because module aliases would not
+      # work then (see the ``tmodulealias`` test)
+      # semExprWithType(c, result)
+      result = semExpr(c, result, flags)
+    of tyStmt:
+      result = semStmt(c, result)
+    of tyTypeDesc:
+      if n.kind == nkStmtList: result.kind = nkStmtListType
+      var typ = semTypeNode(c, result, nil)
+      result.typ = makeTypeDesc(c, typ)
+      #result = symNodeFromType(c, typ, n.info)
+    else:
+      result = semExpr(c, result, flags)
+      result = fitNode(c, s.typ.sons[0], result)
+      #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
+  dec(evalTemplateCounter)
+  discard c.friendModules.pop()
+
+proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
+                  flags: TExprFlags = {}): PNode =
+  pushInfoContext(nOrig.info)
+
+  markUsed(n.info, sym)
+  styleCheckUse(n.info, sym)
+  if sym == c.p.owner:
+    globalError(n.info, errRecursiveDependencyX, sym.name.s)
+
+  #if c.evalContext == nil:
+  #  c.evalContext = c.createEvalContext(emStatic)
+
+  result = evalMacroCall(c.module, n, nOrig, sym)
+  if efNoSemCheck notin flags:
+    result = semAfterMacroCall(c, result, sym, flags)
+  popInfoContext()
+
+proc forceBool(c: PContext, n: PNode): PNode =
+  result = fitNode(c, getSysType(tyBool), n)
+  if result == nil: result = n
+
+proc semConstBoolExpr(c: PContext, n: PNode): PNode =
+  let nn = semExprWithType(c, n)
+  result = fitNode(c, getSysType(tyBool), nn)
+  if result == nil:
+    localError(n.info, errConstExprExpected)
+    return nn
+  result = getConstExpr(c.module, result)
+  if result == nil:
+    localError(n.info, errConstExprExpected)
+    result = nn
+
+proc semGenericStmt(c: PContext, n: PNode): PNode
+
+include semtypes, semtempl, semgnrc, semstmts, semexprs
+
+proc addCodeForGenerics(c: PContext, n: PNode) =
+  for i in countup(c.lastGenericIdx, c.generics.len - 1):
+    var prc = c.generics[i].inst.sym
+    if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
+      if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
+        internalError(prc.info, "no code for " & prc.name.s)
+      else:
+        addSon(n, prc.ast)
+  c.lastGenericIdx = c.generics.len
+
+proc myOpen(module: PSym): PPassContext =
+  var c = newContext(module)
+  if c.p != nil: internalError(module.info, "sem.myOpen")
+  c.semConstExpr = semConstExpr
+  c.semExpr = semExpr
+  c.semTryExpr = tryExpr
+  c.semTryConstExpr = tryConstExpr
+  c.semOperand = semOperand
+  c.semConstBoolExpr = semConstBoolExpr
+  c.semOverloadedCall = semOverloadedCall
+  c.semInferredLambda = semInferredLambda
+  c.semGenerateInstance = generateInstance
+  c.semTypeNode = semTypeNode
+  c.instTypeBoundOp = sigmatch.instTypeBoundOp
+
+  pushProcCon(c, module)
+  pushOwner(c.module)
+  c.importTable = openScope(c)
+  c.importTable.addSym(module) # a module knows itself
+  if sfSystemModule in module.flags:
+    magicsys.systemModule = module # set global variable!
+  else:
+    c.importTable.addSym magicsys.systemModule # import the "System" identifier
+    importAllSymbols(c, magicsys.systemModule)
+  c.topLevelScope = openScope(c)
+  result = c
+
+proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
+  result = myOpen(module)
+  for m in items(rd.methods): methodDef(m, true)
+
+proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
+  result = semStmt(c, n)
+  # BUGFIX: process newly generated generics here, not at the end!
+  if c.lastGenericIdx < c.generics.len:
+    var a = newNodeI(nkStmtList, n.info)
+    addCodeForGenerics(c, a)
+    if sonsLen(a) > 0:
+      # a generic has been added to `a`:
+      if result.kind != nkEmpty: addSon(a, result)
+      result = a
+  result = hloStmt(c, result)
+  if gCmd == cmdInteractive and not isEmptyType(result.typ):
+    result = buildEchoStmt(c, result)
+  result = transformStmt(c.module, result)
+
+proc recoverContext(c: PContext) =
+  # clean up in case of a semantic error: We clean up the stacks, etc. This is
+  # faster than wrapping every stack operation in a 'try finally' block and
+  # requires far less code.
+  c.currentScope = c.topLevelScope
+  while getCurrOwner().kind != skModule: popOwner()
+  while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
+
+proc myProcess(context: PPassContext, n: PNode): PNode =
+  var c = PContext(context)
+  # no need for an expensive 'try' if we stop after the first error anyway:
+  if msgs.gErrorMax <= 1:
+    result = semStmtAndGenerateGenerics(c, n)
+  else:
+    let oldContextLen = msgs.getInfoContextLen()
+    let oldInGenericInst = c.inGenericInst
+    try:
+      result = semStmtAndGenerateGenerics(c, n)
+    except ERecoverableError, ESuggestDone:
+      recoverContext(c)
+      c.inGenericInst = oldInGenericInst
+      msgs.setInfoContextLen(oldContextLen)
+      if getCurrentException() of ESuggestDone: result = nil
+      else: result = ast.emptyNode
+      #if gCmd == cmdIdeTools: findSuggest(c, n)
+
+proc myClose(context: PPassContext, n: PNode): PNode =
+  var c = PContext(context)
+  closeScope(c)         # close module's scope
+  rawCloseScope(c)      # imported symbols; don't check for unused ones!
+  result = newNode(nkStmtList)
+  if n != nil:
+    internalError(n.info, "n is not nil") #result := n;
+  addCodeForGenerics(c, result)
+  if c.module.ast != nil:
+    result.add(c.module.ast)
+  popOwner()
+  popProcCon(c)
+
+const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
+
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
new file mode 100644
index 000000000..a1e209263
--- /dev/null
+++ b/compiler/semasgn.nim
@@ -0,0 +1,284 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements lifting for assignments. Later versions of this code
+## will be able to also lift ``=deepCopy`` and ``=destroy``.
+
+# included from sem.nim
+
+type
+  TLiftCtx = object
+    c: PContext
+    info: TLineInfo # for construction
+    kind: TTypeAttachedOp
+    fn: PSym
+    asgnForType: PType
+    recurse: bool
+
+proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
+proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym
+
+proc at(a, i: PNode, elemType: PType): PNode =
+  result = newNodeI(nkBracketExpr, a.info, 2)
+  result.sons[0] = a
+  result.sons[1] = i
+  result.typ = elemType
+
+proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
+  for i in 0 .. <t.len:
+    let lit = lowerings.newIntLit(i)
+    liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
+
+proc dotField(x: PNode, f: PSym): PNode =
+  result = newNodeI(nkDotExpr, x.info, 2)
+  result.sons[0] = x
+  result.sons[1] = newSymNode(f, x.info)
+  result.typ = f.typ
+
+proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
+  case n.kind
+  of nkSym:
+    let f = n.sym
+    liftBodyAux(c, f.typ, body, x.dotField(f), y.dotField(f))
+  of nkNilLit: discard
+  of nkRecCase:
+    # copy the selector:
+    liftBodyObj(c, n[0], body, x, y)
+    # we need to generate a case statement:
+    var caseStmt = newNodeI(nkCaseStmt, c.info)
+    # XXX generate 'if' that checks same branches
+    # generate selector:
+    var access = dotField(x, n[0].sym)
+    caseStmt.add(access)
+    # copy the branches over, but replace the fields with the for loop body:
+    for i in 1 .. <n.len:
+      var branch = copyTree(n[i])
+      let L = branch.len
+      branch.sons[L-1] = newNodeI(nkStmtList, c.info)
+
+      liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
+      caseStmt.add(branch)
+    body.add(caseStmt)
+    localError(c.info, "cannot lift assignment operator to 'case' object")
+  of nkRecList:
+    for t in items(n): liftBodyObj(c, t, body, x, y)
+  else:
+    illFormedAstLocal(n)
+
+proc genAddr(c: PContext; x: PNode): PNode =
+  if x.kind == nkHiddenDeref:
+    checkSonsLen(x, 1)
+    result = x.sons[0]
+  else:
+    result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ))
+    addSon(result, x)
+
+proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
+  if sfError in op.flags:
+    localError(x.info, errWrongSymbolX, op.name.s)
+  result = newNodeI(nkCall, x.info)
+  result.add newSymNode(op)
+  result.add genAddr(c, x)
+  result.add y
+
+proc newAsgnStmt(le, ri: PNode): PNode =
+  result = newNodeI(nkAsgn, le.info, 2)
+  result.sons[0] = le
+  result.sons[1] = ri
+
+proc newDestructorCall(op: PSym; x: PNode): PNode =
+  result = newNodeIT(nkCall, x.info, op.typ.sons[0])
+  result.add(newSymNode(op))
+  result.add x
+
+proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
+  result = newAsgnStmt(x, newDestructorCall(op, y))
+
+proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
+  case c.kind
+  of attachedDestructor:
+    let op = t.destructor
+    if op != nil:
+      markUsed(c.info, op)
+      styleCheckUse(c.info, op)
+      body.add newDestructorCall(op, x)
+      result = true
+  of attachedAsgn:
+    if tfHasAsgn in t.flags:
+      var op: PSym
+      if sameType(t, c.asgnForType):
+        # generate recursive call:
+        if c.recurse:
+          op = c.fn
+        else:
+          c.recurse = true
+          return false
+      else:
+        op = t.assignment
+        if op == nil:
+          op = liftBody(c.c, t, c.info)
+      markUsed(c.info, op)
+      styleCheckUse(c.info, op)
+      body.add newAsgnCall(c.c, op, x, y)
+      result = true
+  of attachedDeepCopy:
+    let op = t.deepCopy
+    if op != nil:
+      markUsed(c.info, op)
+      styleCheckUse(c.info, op)
+      body.add newDeepCopyCall(op, x, y)
+      result = true
+
+proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
+  if c.kind != attachedDestructor:
+    body.add newAsgnStmt(x, y)
+
+proc addVar(father, v, value: PNode) =
+  var vpart = newNodeI(nkIdentDefs, v.info, 3)
+  vpart.sons[0] = v
+  vpart.sons[1] = ast.emptyNode
+  vpart.sons[2] = value
+  addSon(father, vpart)
+
+proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
+  var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info)
+  temp.typ = getSysType(tyInt)
+  incl(temp.flags, sfFromGeneric)
+
+  var v = newNodeI(nkVarSection, c.info)
+  result = newSymNode(temp)
+  v.addVar(result, lowerings.newIntLit(first))
+  body.add v
+
+proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode =
+  result = newNodeI(nkCall, i.info)
+  result.add createMagic(name, magic).newSymNode
+  result.add i
+
+proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
+  result = newNodeI(nkWhileStmt, c.info, 2)
+  let cmp = genBuiltin(mLeI, "<=", i)
+  cmp.add genHigh(dest)
+  cmp.typ = getSysType(tyBool)
+  result.sons[0] = cmp
+  result.sons[1] = newNodeI(nkStmtList, c.info)
+
+proc addIncStmt(body, i: PNode) =
+  let incCall = genBuiltin(mInc, "inc", i)
+  incCall.add lowerings.newIntLit(1)
+  body.add incCall
+
+proc newSeqCall(c: PContext; x, y: PNode): PNode =
+  # don't call genAddr(c, x) here:
+  result = genBuiltin(mNewSeq, "newSeq", x)
+  let lenCall = genBuiltin(mLengthSeq, "len", y)
+  lenCall.typ = getSysType(tyInt)
+  result.add lenCall
+
+proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
+  case t.kind
+  of tyNone, tyEmpty: discard
+  of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
+      tyPtr, tyString, tyRef:
+    defaultOp(c, t, body, x, y)
+  of tyArrayConstr, tyArray, tySequence:
+    if tfHasAsgn in t.flags:
+      if t.kind == tySequence:
+        # XXX add 'nil' handling here
+        body.add newSeqCall(c.c, x, y)
+      let i = declareCounter(c, body, firstOrd(t))
+      let whileLoop = genWhileLoop(c, i, x)
+      let elemType = t.lastSon
+      liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
+                                                  y.at(i, elemType))
+      addIncStmt(whileLoop.sons[1], i)
+      body.add whileLoop
+    else:
+      defaultOp(c, t, body, x, y)
+  of tyObject, tyDistinct:
+    if not considerOverloadedOp(c, t, body, x, y):
+      if t.sons[0] != nil: liftBodyAux(c, t.sons[0], body, x, y)
+      if t.kind == tyObject: liftBodyObj(c, t.n, body, x, y)
+  of tyTuple:
+    liftBodyTup(c, t, body, x, y)
+  of tyProc:
+    if t.callConv != ccClosure or c.kind != attachedDeepCopy:
+      defaultOp(c, t, body, x, y)
+    else:
+      # a big problem is that we don't know the enviroment's type here, so we
+      # have to go through some indirection; we delegate this to the codegen:
+      let call = newNodeI(nkCall, c.info, 2)
+      call.typ = t
+      call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
+      call.sons[1] = y
+      body.add newAsgnStmt(x, call)
+  of tyVarargs, tyOpenArray:
+    localError(c.info, errGenerated, "cannot copy openArray")
+  of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
+     tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
+     tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
+     tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward:
+    internalError(c.info, "assignment requested for type: " & typeToString(t))
+  of tyOrdinal, tyRange,
+     tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
+    liftBodyAux(c, lastSon(t), body, x, y)
+
+proc newProcType(info: TLineInfo; owner: PSym): PType =
+  result = newType(tyProc, owner)
+  result.n = newNodeI(nkFormalParams, info)
+  rawAddSon(result, nil) # return type
+  # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
+  # the effects are now stored in there too ... this is a bit hacky, but as
+  # usual we desperately try to save memory:
+  addSon(result.n, newNodeI(nkEffectList, info))
+
+proc addParam(procType: PType; param: PSym) =
+  param.position = procType.len-1
+  addSon(procType.n, newSymNode(param))
+  rawAddSon(procType, param.typ)
+
+proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
+  var a: TLiftCtx
+  a.info = info
+  let body = newNodeI(nkStmtList, info)
+  result = newSym(skProc, getIdent":lifted=", typ.owner, info)
+  a.fn = result
+  a.asgnForType = typ
+
+  let dest = newSym(skParam, getIdent"dest", result, info)
+  let src = newSym(skParam, getIdent"src", result, info)
+  dest.typ = makeVarType(c, typ)
+  src.typ = typ
+
+  result.typ = newProcType(info, typ.owner)
+  result.typ.addParam dest
+  result.typ.addParam src
+
+  liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
+
+  var n = newNodeI(nkProcDef, info, bodyPos+1)
+  for i in 0 .. < n.len: n.sons[i] = emptyNode
+  n.sons[namePos] = newSymNode(result)
+  n.sons[paramsPos] = result.typ.n
+  n.sons[bodyPos] = body
+  result.ast = n
+
+  # register late as recursion is handled differently
+  typ.assignment = result
+  #echo "Produced this ", n
+
+proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
+  let t = typ.skipTypes({tyGenericInst, tyVar})
+  result = t.assignment
+  if result.isNil:
+    result = liftBody(c, t, info)
+
+proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
+  let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
+  result = newAsgnCall(c, a, dest, src)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
new file mode 100644
index 000000000..c48e761e3
--- /dev/null
+++ b/compiler/semcall.nim
@@ -0,0 +1,403 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements semantic checking for calls.
+# included from sem.nim
+
+proc sameMethodDispatcher(a, b: PSym): bool =
+  result = false
+  if a.kind == skMethod and b.kind == skMethod:
+    var aa = lastSon(a.ast)
+    var bb = lastSon(b.ast)
+    if aa.kind == nkSym and bb.kind == nkSym:
+      if aa.sym == bb.sym:
+        result = true
+    else:
+      discard
+      # generics have no dispatcher yet, so we need to compare the method
+      # names; however, the names are equal anyway because otherwise we
+      # wouldn't even consider them to be overloaded. But even this does
+      # not work reliably! See tmultim6 for an example:
+      # method collide[T](a: TThing, b: TUnit[T]) is instantiated and not
+      # method collide[T](a: TUnit[T], b: TThing)! This means we need to
+      # *instantiate* every candidate! However, we don't keep more than 2-3
+      # candidated around so we cannot implement that for now. So in order
+      # to avoid subtle problems, the call remains ambiguous and needs to
+      # be disambiguated by the programmer; this way the right generic is
+      # instantiated.
+
+proc determineType(c: PContext, s: PSym)
+
+proc pickBestCandidate(c: PContext, headSymbol: PNode,
+                       n, orig: PNode,
+                       initialBinding: PNode,
+                       filter: TSymKinds,
+                       best, alt: var TCandidate,
+                       errors: var CandidateErrors) =
+  var o: TOverloadIter
+  # thanks to the lazy semchecking for operands, we need to iterate over the
+  # symbol table *before* any call to 'initCandidate' which might invoke
+  # semExpr which might modify the symbol table in cases like
+  # 'init(a, 1, (var b = new(Type2); b))'.
+  var symx = initOverloadIter(o, c, headSymbol)
+  let symScope = o.lastOverloadScope
+
+  var syms: seq[tuple[a: PSym, b: int]] = @[]
+  while symx != nil:
+    if symx.kind in filter: syms.add((symx, o.lastOverloadScope))
+    symx = nextOverloadIter(o, c, headSymbol)
+  if syms.len == 0: return
+
+  var z: TCandidate
+  initCandidate(c, best, syms[0][0], initialBinding, symScope)
+  initCandidate(c, alt, syms[0][0], initialBinding, symScope)
+  best.state = csNoMatch
+
+  for i in 0 .. <syms.len:
+    let sym = syms[i][0]
+    determineType(c, sym)
+    initCandidate(c, z, sym, initialBinding, syms[i][1])
+    z.calleeSym = sym
+
+    #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
+    #  gDebug = true
+    matches(c, n, orig, z)
+    if errors != nil:
+      errors.safeAdd(sym)
+      if z.errors != nil:
+        for err in z.errors:
+          errors.add(err)
+    if z.state == csMatch:
+      # little hack so that iterators are preferred over everything else:
+      if sym.kind in skIterators: inc(z.exactMatches, 200)
+      case best.state
+      of csEmpty, csNoMatch: best = z
+      of csMatch:
+        var cmp = cmpCandidates(best, z)
+        if cmp < 0: best = z   # x is better than the best so far
+        elif cmp == 0: alt = z # x is as good as the best so far
+        else: discard
+      #if sym.name.s == "cmp" and (n.info ?? "rstgen.nim") and n.info.line == 516:
+      #  echo "Matches ", n.info, " ", typeToString(sym.typ)
+      #  debug sym
+      #  writeMatches(z)
+      #  for i in 1 .. <len(z.call):
+      #    z.call[i].typ.debug
+      #  quit 1
+
+proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
+  # Gives a detailed error message; this is separated from semOverloadedCall,
+  # as semOverlodedCall is already pretty slow (and we need this information
+  # only in case of an error).
+  if c.inCompilesContext > 0:
+    # fail fast:
+    globalError(n.info, errTypeMismatch, "")
+  if errors.isNil or errors.len == 0:
+    localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
+    return
+
+  # to avoid confusing errors like:
+  #   got (SslPtr, SocketHandle)
+  #   but expected one of:
+  #   openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
+  # we do a pre-analysis. If all types produce the same string, we will add
+  # module information.
+  let proto = describeArgs(c, n, 1, preferName)
+
+  var prefer = preferName
+  for err in errors:
+    var errProto = ""
+    let n = err.typ.n
+    for i in countup(1, n.len - 1):
+      var p = n.sons[i]
+      if p.kind == nkSym:
+        add(errProto, typeToString(p.sym.typ, preferName))
+        if i != n.len-1: add(errProto, ", ")
+      # else: ignore internal error as we're already in error handling mode
+    if errProto == proto:
+      prefer = preferModuleInfo
+      break
+  # now use the information stored in 'prefer' to produce a nice error message:
+  var result = msgKindToString(errTypeMismatch)
+  add(result, describeArgs(c, n, 1, prefer))
+  add(result, ')')
+  var candidates = ""
+  for err in errors:
+    add(candidates, err.getProcHeader(prefer))
+    add(candidates, "\n")
+  if candidates != "":
+    add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
+  localError(n.info, errGenerated, result)
+
+proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
+  for scope in walkScopes(c.currentScope):
+    if scope.usingSyms != nil:
+      for s in scope.usingSyms: usedSyms.safeAdd(s)
+
+proc resolveOverloads(c: PContext, n, orig: PNode,
+                      filter: TSymKinds;
+                      errors: var CandidateErrors): TCandidate =
+  var initialBinding: PNode
+  var alt: TCandidate
+  var f = n.sons[0]
+  if f.kind == nkBracketExpr:
+    # fill in the bindings:
+    initialBinding = f
+    f = f.sons[0]
+  else:
+    initialBinding = nil
+
+  var usedSyms: seq[PNode]
+
+  template pickBest(headSymbol: expr) =
+    pickBestCandidate(c, headSymbol, n, orig, initialBinding,
+                      filter, result, alt, errors)
+
+  gatherUsedSyms(c, usedSyms)
+  if usedSyms != nil:
+    var hiddenArg = if usedSyms.len > 1: newNode(nkClosedSymChoice, n.info, usedSyms)
+                    else: usedSyms[0]
+
+    n.sons.insert(hiddenArg, 1)
+    orig.sons.insert(hiddenArg, 1)
+
+    pickBest(f)
+
+    if result.state != csMatch:
+      n.sons.delete(1)
+      orig.sons.delete(1)
+    else: return
+
+  pickBest(f)
+
+  let overloadsState = result.state
+  if overloadsState != csMatch:
+    if nfDotField in n.flags:
+      internalAssert f.kind == nkIdent and n.sonsLen >= 2
+      let calleeName = newStrNode(nkStrLit, f.ident.s).withInfo(n.info)
+
+      # leave the op head symbol empty,
+      # we are going to try multiple variants
+      n.sons[0..1] = [nil, n[1], calleeName]
+      orig.sons[0..1] = [nil, orig[1], calleeName]
+
+      template tryOp(x) =
+        let op = newIdentNode(getIdent(x), n.info)
+        n.sons[0] = op
+        orig.sons[0] = op
+        pickBest(op)
+
+      if nfExplicitCall in n.flags:
+        tryOp ".()"
+
+      if result.state in {csEmpty, csNoMatch}:
+        tryOp "."
+
+    elif nfDotSetter in n.flags:
+      internalAssert f.kind == nkIdent and n.sonsLen == 3
+      let calleeName = newStrNode(nkStrLit,
+        f.ident.s[0..f.ident.s.len-2]).withInfo(n.info)
+      let callOp = newIdentNode(getIdent".=", n.info)
+      n.sons[0..1] = [callOp, n[1], calleeName]
+      orig.sons[0..1] = [callOp, orig[1], calleeName]
+      pickBest(callOp)
+
+    if overloadsState == csEmpty and result.state == csEmpty:
+      localError(n.info, errUndeclaredIdentifier, considerQuotedIdent(f).s)
+      return
+    elif result.state != csMatch:
+      if nfExprCall in n.flags:
+        localError(n.info, errExprXCannotBeCalled,
+                   renderTree(n, {renderNoComments}))
+      else:
+        if {nfDotField, nfDotSetter} * n.flags != {}:
+          # clean up the inserted ops
+          n.sons.delete(2)
+          n.sons[0] = f
+
+        errors = @[]
+        pickBest(f)
+        #notFoundError(c, n, errors)
+
+      return
+
+  if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
+      not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
+    internalAssert result.state == csMatch
+    #writeMatches(result)
+    #writeMatches(alt)
+    if c.inCompilesContext > 0:
+      # quick error message for performance of 'compiles' built-in:
+      globalError(n.info, errGenerated, "ambiguous call")
+    elif gErrorCounter == 0:
+      # don't cascade errors
+      var args = "("
+      for i in countup(1, sonsLen(n) - 1):
+        if i > 1: add(args, ", ")
+        add(args, typeToString(n.sons[i].typ))
+      add(args, ")")
+
+      localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
+        getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
+        args])
+
+
+proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
+  if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym and
+      isGenericRoutine(a.sons[0].sym):
+    let finalCallee = generateInstance(c, a.sons[0].sym, x.bindings, a.info)
+    a.sons[0].sym = finalCallee
+    a.sons[0].typ = finalCallee.typ
+    #a.typ = finalCallee.typ.sons[0]
+
+proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
+  assert n.kind in nkCallKinds
+  if x.genericConverter:
+    for i in 1 .. <n.len:
+      instGenericConvertersArg(c, n.sons[i], x)
+
+proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
+  var m: TCandidate
+  initCandidate(c, m, f)
+  result = paramTypesMatch(m, f, a, arg, nil)
+  if m.genericConverter and result != nil:
+    instGenericConvertersArg(c, result, m)
+
+proc inferWithMetatype(c: PContext, formal: PType,
+                       arg: PNode, coerceDistincts = false): PNode =
+  var m: TCandidate
+  initCandidate(c, m, formal)
+  m.coerceDistincts = coerceDistincts
+  result = paramTypesMatch(m, formal, arg.typ, arg, nil)
+  if m.genericConverter and result != nil:
+    instGenericConvertersArg(c, result, m)
+  if result != nil:
+    # This almost exactly replicates the steps taken by the compiler during
+    # param matching. It performs an embarrassing amount of back-and-forth
+    # type jugling, but it's the price to pay for consistency and correctness
+    result.typ = generateTypeInstance(c, m.bindings, arg.info,
+                                      formal.skipTypes({tyCompositeTypeClass}))
+  else:
+    typeMismatch(arg, formal, arg.typ)
+    # error correction:
+    result = copyTree(arg)
+    result.typ = formal
+
+proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
+  assert x.state == csMatch
+  var finalCallee = x.calleeSym
+  markUsed(n.sons[0].info, finalCallee)
+  styleCheckUse(n.sons[0].info, finalCallee)
+  if finalCallee.ast == nil:
+    internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
+  if x.hasFauxMatch:
+    result = x.call
+    result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
+    if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
+      result.typ = newTypeS(x.fauxMatch, c)
+    return
+  if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
+    finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
+  result = x.call
+  instGenericConvertersSons(c, result, x)
+  result.sons[0] = newSymNode(finalCallee, result.sons[0].info)
+  result.typ = finalCallee.typ.sons[0]
+
+proc canDeref(n: PNode): bool {.inline.} =
+  result = n.len >= 2 and (let t = n[1].typ;
+    t != nil and t.skipTypes({tyGenericInst}).kind in {tyPtr, tyRef})
+
+proc tryDeref(n: PNode): PNode =
+  result = newNodeI(nkHiddenDeref, n.info)
+  result.typ = n.typ.skipTypes(abstractInst).sons[0]
+  result.addSon(n)
+
+proc semOverloadedCall(c: PContext, n, nOrig: PNode,
+                       filter: TSymKinds): PNode =
+  var errors: CandidateErrors
+
+  var r = resolveOverloads(c, n, nOrig, filter, errors)
+  if r.state == csMatch: result = semResolvedCall(c, n, r)
+  elif experimentalMode(c) and canDeref(n):
+    # try to deref the first argument and then try overloading resolution again:
+    n.sons[1] = n.sons[1].tryDeref
+    var r = resolveOverloads(c, n, nOrig, filter, errors)
+    if r.state == csMatch: result = semResolvedCall(c, n, r)
+    else:
+      # get rid of the deref again for a better error message:
+      n.sons[1] = n.sons[1].sons[0]
+      notFoundError(c, n, errors)
+  else:
+    notFoundError(c, n, errors)
+  # else: result = errorNode(c, n)
+
+proc explicitGenericInstError(n: PNode): PNode =
+  localError(n.info, errCannotInstantiateX, renderTree(n))
+  result = n
+
+proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
+  var m: TCandidate
+  initCandidate(c, m, s, n)
+  var newInst = generateInstance(c, s, m.bindings, n.info)
+  markUsed(n.info, s)
+  styleCheckUse(n.info, s)
+  result = newSymNode(newInst, n.info)
+
+proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
+  assert n.kind == nkBracketExpr
+  for i in 1..sonsLen(n)-1:
+    n.sons[i].typ = semTypeNode(c, n.sons[i], nil)
+  var s = s
+  var a = n.sons[0]
+  if a.kind == nkSym:
+    # common case; check the only candidate has the right
+    # number of generic type parameters:
+    if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
+      let expected = safeLen(s.ast.sons[genericParamsPos])
+      localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
+         "; got " & $(n.len-1) & " type(s) but expected " & $expected)
+      return n
+    result = explicitGenericSym(c, n, s)
+  elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
+    # choose the generic proc with the proper number of type parameters.
+    # XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
+    # It's good enough for now.
+    result = newNodeI(a.kind, n.info)
+    for i in countup(0, len(a)-1):
+      var candidate = a.sons[i].sym
+      if candidate.kind in {skProc, skMethod, skConverter,
+                            skIterator, skClosureIterator}:
+        # it suffices that the candidate has the proper number of generic
+        # type parameters:
+        if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:
+          result.add(explicitGenericSym(c, n, candidate))
+    # get rid of nkClosedSymChoice if not ambiguous:
+    if result.len == 1 and a.kind == nkClosedSymChoice:
+      result = result[0]
+    # candidateCount != 1: return explicitGenericInstError(n)
+  else:
+    result = explicitGenericInstError(n)
+
+proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
+  # Searchs for the fn in the symbol table. If the parameter lists are suitable
+  # for borrowing the sym in the symbol table is returned, else nil.
+  # New approach: generate fn(x, y, z) where x, y, z have the proper types
+  # and use the overloading resolution mechanism:
+  var call = newNodeI(nkCall, fn.info)
+  var hasDistinct = false
+  call.add(newIdentNode(fn.name, fn.info))
+  for i in 1.. <fn.typ.n.len:
+    let param = fn.typ.n.sons[i]
+    let t = skipTypes(param.typ, abstractVar-{tyTypeDesc})
+    if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
+    call.add(newNodeIT(nkEmpty, fn.info, t.baseOfDistinct))
+  if hasDistinct:
+    var resolved = semOverloadedCall(c, call, call, {fn.kind})
+    if resolved != nil:
+      result = resolved.sons[0].sym
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
new file mode 100644
index 000000000..345a8c0d1
--- /dev/null
+++ b/compiler/semdata.nim
@@ -0,0 +1,336 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains the data structures for the semantic checking phase.
+
+import
+  strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
+  wordrecg,
+  ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
+  magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
+
+type
+  TOptionEntry* = object of lists.TListEntry # entries to put on a
+                                             # stack for pragma parsing
+    options*: TOptions
+    defaultCC*: TCallingConvention
+    dynlib*: PLib
+    notes*: TNoteKinds
+    otherPragmas*: PNode      # every pragma can be pushed
+
+  POptionEntry* = ref TOptionEntry
+  PProcCon* = ref TProcCon
+  TProcCon* = object          # procedure context; also used for top-level
+                              # statements
+    owner*: PSym              # the symbol this context belongs to
+    resultSym*: PSym          # the result symbol (if we are in a proc)
+    nestedLoopCounter*: int   # whether we are in a loop or not
+    nestedBlockCounter*: int  # whether we are in a block or not
+    inTryStmt*: int           # whether we are in a try statement; works also
+                              # in standalone ``except`` and ``finally``
+    next*: PProcCon           # used for stacking procedure contexts
+    wasForwarded*: bool       # whether the current proc has a separate header
+    bracketExpr*: PNode       # current bracket expression (for ^ support)
+
+  TInstantiationPair* = object
+    genericSym*: PSym
+    inst*: PInstantiation
+
+  TExprFlag* = enum
+    efLValue, efWantIterator, efInTypeof,
+    efWantStmt, efAllowStmt, efDetermineType,
+    efAllowDestructor, efWantValue, efOperand, efNoSemCheck
+  TExprFlags* = set[TExprFlag]
+
+  TTypeAttachedOp* = enum
+    attachedAsgn,
+    attachedDeepCopy,
+    attachedDestructor
+
+  PContext* = ref TContext
+  TContext* = object of TPassContext # a context represents a module
+    module*: PSym              # the module sym belonging to the context
+    currentScope*: PScope      # current scope
+    importTable*: PScope       # scope for all imported symbols
+    topLevelScope*: PScope     # scope for all top-level symbols
+    p*: PProcCon               # procedure context
+    friendModules*: seq[PSym]  # friend modules; may access private data;
+                               # this is used so that generic instantiations
+                               # can access private object fields
+    instCounter*: int          # to prevent endless instantiations
+
+    ambiguousSymbols*: IntSet  # ids of all ambiguous symbols (cannot
+                               # store this info in the syms themselves!)
+    inTypeClass*: int          # > 0 if we are in a user-defined type class
+    inGenericContext*: int     # > 0 if we are in a generic type
+    inUnrolledContext*: int    # > 0 if we are unrolling a loop
+    inCompilesContext*: int    # > 0 if we are in a ``compiles`` magic
+    inGenericInst*: int        # > 0 if we are instantiating a generic
+    converters*: TSymSeq       # sequence of converters
+    patterns*: TSymSeq         # sequence of pattern matchers
+    optionStack*: TLinkedList
+    symMapping*: TIdTable      # every gensym'ed symbol needs to be mapped
+                               # to some new symbol in a generic instantiation
+    libs*: TLinkedList         # all libs used by this module
+    semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
+    semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
+    semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
+    semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
+    semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
+    semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
+    semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
+                              filter: TSymKinds): PNode {.nimcall.}
+    semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
+    semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
+    semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
+                                info: TLineInfo): PSym
+    includedFiles*: IntSet    # used to detect recursive include files
+    userPragmas*: TStrTable
+    evalContext*: PEvalContext
+    unknownIdents*: IntSet     # ids of all unknown identifiers to prevent
+                               # naming it multiple times
+    generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
+    lastGenericIdx*: int      # used for the generics stack
+    hloLoopDetector*: int     # used to prevent endless loops in the HLO
+    inParallelStmt*: int
+    instTypeBoundOp*: proc (c: PContext; dc: PSym; t: PType; info: TLineInfo;
+                            op: TTypeAttachedOp): PSym {.nimcall.}
+
+
+proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
+  result.genericSym = s
+  result.inst = inst
+
+proc filename*(c: PContext): string =
+  # the module's filename
+  return c.module.filename
+
+proc newContext*(module: PSym): PContext
+
+proc lastOptionEntry*(c: PContext): POptionEntry
+proc newOptionEntry*(): POptionEntry
+proc newLib*(kind: TLibKind): PLib
+proc addToLib*(lib: PLib, sym: PSym)
+proc makePtrType*(c: PContext, baseType: PType): PType
+proc newTypeS*(kind: TTypeKind, c: PContext): PType
+proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext)
+
+proc scopeDepth*(c: PContext): int {.inline.} =
+  result = if c.currentScope != nil: c.currentScope.depthLevel
+           else: 0
+
+# owner handling:
+proc getCurrOwner*(): PSym
+proc pushOwner*(owner: PSym)
+proc popOwner*()
+# implementation
+
+var gOwners*: seq[PSym] = @[]
+
+proc getCurrOwner(): PSym =
+  # owner stack (used for initializing the
+  # owner field of syms)
+  # the documentation comment always gets
+  # assigned to the current owner
+  # BUGFIX: global array is needed!
+  result = gOwners[high(gOwners)]
+
+proc pushOwner(owner: PSym) =
+  add(gOwners, owner)
+
+proc popOwner() =
+  var length = len(gOwners)
+  if length > 0: setLen(gOwners, length - 1)
+  else: internalError("popOwner")
+
+proc lastOptionEntry(c: PContext): POptionEntry =
+  result = POptionEntry(c.optionStack.tail)
+
+proc pushProcCon*(c: PContext, owner: PSym) {.inline.} =
+  if owner == nil:
+    internalError("owner is nil")
+    return
+  var x: PProcCon
+  new(x)
+  x.owner = owner
+  x.next = c.p
+  c.p = x
+
+proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
+
+proc newOptionEntry(): POptionEntry =
+  new(result)
+  result.options = gOptions
+  result.defaultCC = ccDefault
+  result.dynlib = nil
+  result.notes = gNotes
+
+proc newContext(module: PSym): PContext =
+  new(result)
+  result.ambiguousSymbols = initIntSet()
+  initLinkedList(result.optionStack)
+  initLinkedList(result.libs)
+  append(result.optionStack, newOptionEntry())
+  result.module = module
+  result.friendModules = @[module]
+  result.converters = @[]
+  result.patterns = @[]
+  result.includedFiles = initIntSet()
+  initStrTable(result.userPragmas)
+  result.generics = @[]
+  result.unknownIdents = initIntSet()
+
+proc inclSym(sq: var TSymSeq, s: PSym) =
+  var L = len(sq)
+  for i in countup(0, L - 1):
+    if sq[i].id == s.id: return
+  setLen(sq, L + 1)
+  sq[L] = s
+
+proc addConverter*(c: PContext, conv: PSym) =
+  inclSym(c.converters, conv)
+
+proc addPattern*(c: PContext, p: PSym) =
+  inclSym(c.patterns, p)
+
+proc newLib(kind: TLibKind): PLib =
+  new(result)
+  result.kind = kind          #initObjectSet(result.syms)
+
+proc addToLib(lib: PLib, sym: PSym) =
+  #if sym.annex != nil and not isGenericRoutine(sym):
+  #  LocalError(sym.info, errInvalidPragma)
+  sym.annex = lib
+
+proc makePtrType(c: PContext, baseType: PType): PType =
+  result = newTypeS(tyPtr, c)
+  addSonSkipIntLit(result, baseType.assertNotNil)
+
+proc makeVarType*(c: PContext, baseType: PType): PType =
+  if baseType.kind == tyVar:
+    result = baseType
+  else:
+    result = newTypeS(tyVar, c)
+    addSonSkipIntLit(result, baseType.assertNotNil)
+
+proc makeTypeDesc*(c: PContext, typ: PType): PType =
+  result = newTypeS(tyTypeDesc, c)
+  result.addSonSkipIntLit(typ.assertNotNil)
+
+proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
+  let typedesc = makeTypeDesc(c, typ)
+  let sym = newSym(skType, idAnon, getCurrOwner(), info).linkTo(typedesc)
+  return newSymNode(sym, info)
+
+proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
+  result = newTypeS(tyFromExpr, c)
+  assert n != nil
+  result.n = n
+
+proc newTypeWithSons*(c: PContext, kind: TTypeKind,
+                      sons: seq[PType]): PType =
+  result = newType(kind, getCurrOwner())
+  result.sons = sons
+
+proc makeStaticExpr*(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkStaticExpr, n.info)
+  result.sons = @[n]
+  result.typ = newTypeWithSons(c, tyStatic, @[n.typ])
+
+proc makeAndType*(c: PContext, t1, t2: PType): PType =
+  result = newTypeS(tyAnd, c)
+  result.sons = @[t1, t2]
+  propagateToOwner(result, t1)
+  propagateToOwner(result, t2)
+  result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
+  result.flags.incl tfHasMeta
+
+proc makeOrType*(c: PContext, t1, t2: PType): PType =
+  result = newTypeS(tyOr, c)
+  result.sons = @[t1, t2]
+  propagateToOwner(result, t1)
+  propagateToOwner(result, t2)
+  result.flags.incl((t1.flags + t2.flags) * {tfHasStatic})
+  result.flags.incl tfHasMeta
+
+proc makeNotType*(c: PContext, t1: PType): PType =
+  result = newTypeS(tyNot, c)
+  result.sons = @[t1]
+  propagateToOwner(result, t1)
+  result.flags.incl(t1.flags * {tfHasStatic})
+  result.flags.incl tfHasMeta
+
+proc nMinusOne*(n: PNode): PNode =
+  result = newNode(nkCall, n.info, @[
+    newSymNode(getSysMagic("<", mUnaryLt)),
+    n])
+
+# Remember to fix the procs below this one when you make changes!
+proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
+  let intType = getSysType(tyInt)
+  result = newTypeS(tyRange, c)
+  result.sons = @[intType]
+  result.n = newNode(nkRange, n.info, @[
+    newIntTypeNode(nkIntLit, 0, intType),
+    makeStaticExpr(c, n.nMinusOne)])
+
+template rangeHasStaticIf*(t: PType): bool =
+  # this accepts the ranges's node
+  t.n != nil and t.n.len > 1 and t.n[1].kind == nkStaticExpr
+
+template getStaticTypeFromRange*(t: PType): PType =
+  t.n[1][0][1].typ
+
+proc newTypeS(kind: TTypeKind, c: PContext): PType =
+  result = newType(kind, getCurrOwner())
+
+proc errorType*(c: PContext): PType =
+  ## creates a type representing an error state
+  result = newTypeS(tyError, c)
+
+proc errorNode*(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkEmpty, n.info)
+  result.typ = errorType(c)
+
+proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
+  dest.kind = kind
+  dest.owner = getCurrOwner()
+  dest.size = - 1
+
+proc makeRangeType*(c: PContext; first, last: BiggestInt;
+                    info: TLineInfo; intType = getSysType(tyInt)): PType =
+  var n = newNodeI(nkRange, info)
+  addSon(n, newIntTypeNode(nkIntLit, first, intType))
+  addSon(n, newIntTypeNode(nkIntLit, last, intType))
+  result = newTypeS(tyRange, c)
+  result.n = n
+  addSonSkipIntLit(result, intType) # basetype of range
+
+proc markIndirect*(c: PContext, s: PSym) {.inline.} =
+  if s.kind in {skProc, skConverter, skMethod, skIterator, skClosureIterator}:
+    incl(s.flags, sfAddrTaken)
+    # XXX add to 'c' for global analysis
+
+proc illFormedAst*(n: PNode) =
+  globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+
+proc illFormedAstLocal*(n: PNode) =
+  localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
+
+proc checkSonsLen*(n: PNode, length: int) =
+  if sonsLen(n) != length: illFormedAst(n)
+
+proc checkMinSonsLen*(n: PNode, length: int) =
+  if sonsLen(n) < length: illFormedAst(n)
+
+proc isTopLevel*(c: PContext): bool {.inline.} =
+  result = c.currentScope.depthLevel <= 2
+
+proc experimentalMode*(c: PContext): bool {.inline.} =
+  result = gExperimentalMode or sfExperimental in c.module.flags
diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim
new file mode 100644
index 000000000..aaab49a10
--- /dev/null
+++ b/compiler/semdestruct.nim
@@ -0,0 +1,237 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements destructors.
+
+# included from sem.nim
+
+# special marker values that indicates that we are
+# 1) AnalyzingDestructor: currently analyzing the type for destructor
+# generation (needed for recursive types)
+# 2) DestructorIsTrivial: completed the analysis before and determined
+# that the type has a trivial destructor
+var analyzingDestructor, destructorIsTrivial: PSym
+new(analyzingDestructor)
+new(destructorIsTrivial)
+
+var
+  destructorName = getIdent"destroy_"
+  destructorParam = getIdent"this_"
+  destructorPragma = newIdentNode(getIdent"destructor", unknownLineInfo())
+  rangeDestructorProc*: PSym
+
+proc instantiateDestructor(c: PContext, typ: PType): PType
+
+proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
+  var t = s.typ.sons[1].skipTypes({tyVar})
+  if t.kind == tyGenericInvocation:
+    for i in 1 .. <t.sonsLen:
+      if t.sons[i].kind != tyGenericParam:
+        localError(n.info, errDestructorNotGenericEnough)
+        return
+    t = t.base
+  elif t.kind == tyCompositeTypeClass:
+    t = t.base
+    if t.kind != tyGenericBody:
+      localError(n.info, errDestructorNotGenericEnough)
+      return
+
+  t.destructor = s
+  # automatically insert calls to base classes' destructors
+  if n.sons[bodyPos].kind != nkEmpty:
+    for i in countup(0, t.sonsLen - 1):
+      # when inheriting directly from object
+      # there will be a single nil son
+      if t.sons[i] == nil: continue
+      let destructableT = instantiateDestructor(c, t.sons[i])
+      if destructableT != nil:
+        n.sons[bodyPos].addSon(newNode(nkCall, t.sym.info, @[
+            useSym(destructableT.destructor),
+            n.sons[paramsPos][1][0]]))
+
+proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode
+
+proc destroySym(c: PContext, field: PSym, holder: PNode): PNode =
+  let destructableT = instantiateDestructor(c, field.typ)
+  if destructableT != nil:
+    result = newNode(nkCall, field.info, @[
+      useSym(destructableT.destructor),
+      newNode(nkDotExpr, field.info, @[holder, useSym(field)])])
+
+proc destroyCase(c: PContext, n: PNode, holder: PNode): PNode =
+  var nonTrivialFields = 0
+  result = newNode(nkCaseStmt, n.info, @[])
+  # case x.kind
+  result.addSon(newNode(nkDotExpr, n.info, @[holder, n.sons[0]]))
+  for i in countup(1, n.len - 1):
+    # of A, B:
+    let ni = n[i]
+    var caseBranch = newNode(ni.kind, ni.info, ni.sons[0..ni.len-2])
+
+    let stmt = destroyFieldOrFields(c, ni.lastSon, holder)
+    if stmt == nil:
+      caseBranch.addSon(newNode(nkStmtList, ni.info, @[]))
+    else:
+      caseBranch.addSon(stmt)
+      nonTrivialFields += stmt.len
+
+    result.addSon(caseBranch)
+
+  # maybe no fields were destroyed?
+  if nonTrivialFields == 0:
+    result = nil
+
+proc destroyFieldOrFields(c: PContext, field: PNode, holder: PNode): PNode =
+  template maybeAddLine(e: expr): stmt =
+    let stmt = e
+    if stmt != nil:
+      if result == nil: result = newNode(nkStmtList)
+      result.addSon(stmt)
+
+  case field.kind
+  of nkRecCase:
+    maybeAddLine destroyCase(c, field, holder)
+  of nkSym:
+    maybeAddLine destroySym(c, field.sym, holder)
+  of nkRecList:
+    for son in field:
+      maybeAddLine destroyFieldOrFields(c, son, holder)
+  else:
+    internalAssert false
+
+proc generateDestructor(c: PContext, t: PType): PNode =
+  ## generate a destructor for a user-defined object or tuple type
+  ## returns nil if the destructor turns out to be trivial
+
+  # XXX: This may be true for some C-imported types such as
+  # Tposix_spawnattr
+  if t.n == nil or t.n.sons == nil: return
+  internalAssert t.n.kind == nkRecList
+  let destructedObj = newIdentNode(destructorParam, unknownLineInfo())
+  # call the destructods of all fields
+  result = destroyFieldOrFields(c, t.n, destructedObj)
+  # base classes' destructors will be automatically called by
+  # semProcAux for both auto-generated and user-defined destructors
+
+proc instantiateDestructor(c: PContext, typ: PType): PType =
+  # returns nil if a variable of type `typ` doesn't require a
+  # destructor. Otherwise, returns the type, which holds the
+  # destructor that must be used for the varialbe.
+  # The destructor is either user-defined or automatically
+  # generated by the compiler in a member-wise fashion.
+  var t = skipTypes(typ, {tyConst, tyMutable}).skipGenericAlias
+  let typeHoldingUserDefinition = if t.kind == tyGenericInst: t.base else: t
+
+  if typeHoldingUserDefinition.destructor != nil:
+    # XXX: This is not entirely correct for recursive types, but we need
+    # it temporarily to hide the "destroy is already defined" problem
+    if typeHoldingUserDefinition.destructor notin
+        [analyzingDestructor, destructorIsTrivial]:
+      return typeHoldingUserDefinition
+    else:
+      return nil
+
+  t = t.skipTypes({tyGenericInst})
+  case t.kind
+  of tySequence, tyArray, tyArrayConstr, tyOpenArray, tyVarargs:
+    if instantiateDestructor(c, t.sons[0]) != nil:
+      if rangeDestructorProc == nil:
+        rangeDestructorProc = searchInScopes(c, getIdent"nimDestroyRange")
+      t.destructor = rangeDestructorProc
+      return t
+    else:
+      return nil
+  of tyTuple, tyObject:
+    t.destructor = analyzingDestructor
+    let generated = generateDestructor(c, t)
+    if generated != nil:
+      internalAssert t.sym != nil
+      var i = t.sym.info
+      let fullDef = newNode(nkProcDef, i, @[
+        newIdentNode(destructorName, i),
+        emptyNode,
+        emptyNode,
+        newNode(nkFormalParams, i, @[
+          emptyNode,
+          newNode(nkIdentDefs, i, @[
+            newIdentNode(destructorParam, i),
+            symNodeFromType(c, makeVarType(c, t), t.sym.info),
+            emptyNode]),
+          ]),
+        newNode(nkPragma, i, @[destructorPragma]),
+        emptyNode,
+        generated
+        ])
+      let semantizedDef = semProc(c, fullDef)
+      t.destructor = semantizedDef[namePos].sym
+      return t
+    else:
+      t.destructor = destructorIsTrivial
+      return nil
+  else:
+    return nil
+
+proc insertDestructors(c: PContext,
+                       varSection: PNode): tuple[outer, inner: PNode] =
+  # Accepts a var or let section.
+  #
+  # When a var section has variables with destructors
+  # the var section is split up and finally blocks are inserted
+  # immediately after all "destructable" vars
+  #
+  # In case there were no destrucable variables, the proc returns
+  # (nil, nil) and the enclosing stmt-list requires no modifications.
+  #
+  # Otherwise, after the try blocks are created, the rest of the enclosing
+  # stmt-list should be inserted in the most `inner` such block (corresponding
+  # to the last variable).
+  #
+  # `outer` is a statement list that should replace the original var section.
+  # It will include the new truncated var section followed by the outermost
+  # try block.
+  let totalVars = varSection.sonsLen
+  for j in countup(0, totalVars - 1):
+    let
+      varId = varSection[j][0]
+      varTyp = varId.sym.typ
+      info = varId.info
+
+    if varTyp == nil or sfGlobal in varId.sym.flags: continue
+    let destructableT = instantiateDestructor(c, varTyp)
+
+    if destructableT != nil:
+      var tryStmt = newNodeI(nkTryStmt, info)
+
+      if j < totalVars - 1:
+        var remainingVars = newNodeI(varSection.kind, info)
+        remainingVars.sons = varSection.sons[(j+1)..varSection.len-1]
+        let (outer, inner) = insertDestructors(c, remainingVars)
+        if outer != nil:
+          tryStmt.addSon(outer)
+          result.inner = inner
+        else:
+          result.inner = newNodeI(nkStmtList, info)
+          result.inner.addSon(remainingVars)
+          tryStmt.addSon(result.inner)
+      else:
+        result.inner = newNodeI(nkStmtList, info)
+        tryStmt.addSon(result.inner)
+
+      tryStmt.addSon(
+        newNode(nkFinally, info, @[
+          semStmt(c, newNode(nkCall, info, @[
+            useSym(destructableT.destructor),
+            useSym(varId.sym)]))]))
+
+      result.outer = newNodeI(nkStmtList, info)
+      varSection.sons.setLen(j+1)
+      result.outer.addSon(varSection)
+      result.outer.addSon(tryStmt)
+
+      return
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
new file mode 100644
index 000000000..cd6ba3753
--- /dev/null
+++ b/compiler/semexprs.nim
@@ -0,0 +1,2261 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# this module does the semantic checking for expressions
+# included from sem.nim
+
+proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
+                     flags: TExprFlags = {}): PNode =
+  markUsed(n.info, s)
+  styleCheckUse(n.info, s)
+  pushInfoContext(n.info)
+  result = evalTemplate(n, s, getCurrOwner())
+  if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
+  popInfoContext()
+
+proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+
+proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+  # same as 'semExprWithType' but doesn't check for proc vars
+  result = semExpr(c, n, flags + {efOperand})
+  if result.kind == nkEmpty and result.typ.isNil:
+    # do not produce another redundant error message:
+    #raiseRecoverableError("")
+    result = errorNode(c, n)
+  if result.typ != nil:
+    # XXX tyGenericInst here?
+    if result.typ.kind == tyVar: result = newDeref(result)
+  elif {efWantStmt, efAllowStmt} * flags != {}:
+    result.typ = newTypeS(tyEmpty, c)
+  else:
+    localError(n.info, errExprXHasNoType,
+               renderTree(result, {renderNoComments}))
+    result.typ = errorType(c)
+
+proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+  result = semExpr(c, n, flags+{efWantValue})
+  if result.isNil or result.kind == nkEmpty:
+    # do not produce another redundant error message:
+    #raiseRecoverableError("")
+    result = errorNode(c, n)
+  if result.typ == nil or result.typ == enforceVoidContext:
+    # we cannot check for 'void' in macros ...
+    localError(n.info, errExprXHasNoType,
+               renderTree(result, {renderNoComments}))
+    result.typ = errorType(c)
+  else:
+    # XXX tyGenericInst here?
+    semProcvarCheck(c, result)
+    if result.typ.kind == tyVar: result = newDeref(result)
+    semDestructorCheck(c, result, flags)
+
+proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+  result = semExpr(c, n, flags)
+  if result.kind == nkEmpty:
+    # do not produce another redundant error message:
+    result = errorNode(c, n)
+  if result.typ == nil:
+    localError(n.info, errExprXHasNoType,
+               renderTree(result, {renderNoComments}))
+    result.typ = errorType(c)
+  else:
+    semProcvarCheck(c, result)
+    semDestructorCheck(c, result, flags)
+
+proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
+  result = symChoice(c, n, s, scClosed)
+
+proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
+  result = copyTree(s.ast)
+  result.typ = s.typ
+  result.info = n.info
+
+proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
+  case s.kind
+  of skConst:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
+    of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
+        tyTuple, tySet, tyUInt..tyUInt64:
+      if s.magic == mNone: result = inlineConst(n, s)
+      else: result = newSymNode(s, n.info)
+    of tyArrayConstr, tySequence:
+      # Consider::
+      #     const x = []
+      #     proc p(a: openarray[int])
+      #     proc q(a: openarray[char])
+      #     p(x)
+      #     q(x)
+      #
+      # It is clear that ``[]`` means two totally different things. Thus, we
+      # copy `x`'s AST into each context, so that the type fixup phase can
+      # deal with two different ``[]``.
+      if s.ast.len == 0: result = inlineConst(n, s)
+      else: result = newSymNode(s, n.info)
+    else:
+      result = newSymNode(s, n.info)
+  of skMacro: result = semMacroExpr(c, n, n, s, flags)
+  of skTemplate: result = semTemplateExpr(c, n, s, flags)
+  of skParam:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic and s.typ.n != nil:
+      # XXX see the hack in sigmatch.nim ...
+      return s.typ.n
+    elif sfGenSym in s.flags:
+      if c.p.wasForwarded:
+        # gensym'ed parameters that nevertheless have been forward declared
+        # need a special fixup:
+        let realParam = c.p.owner.typ.n[s.position+1]
+        internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
+        return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
+      elif c.p.owner.kind == skMacro:
+        # gensym'ed macro parameters need a similar hack (see bug #1944):
+        var u = searchInScopes(c, s.name)
+        internalAssert u != nil and u.kind == skParam and u.owner == s.owner
+        return newSymNode(u, n.info)
+    result = newSymNode(s, n.info)
+  of skVar, skLet, skResult, skForVar:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    # if a proc accesses a global variable, it is not side effect free:
+    if sfGlobal in s.flags:
+      incl(c.p.owner.flags, sfSideEffect)
+    result = newSymNode(s, n.info)
+    # We cannot check for access to outer vars for example because it's still
+    # not sure the symbol really ends up being used:
+    # var len = 0 # but won't be called
+    # genericThatUsesLen(x) # marked as taking a closure?
+  of skGenericParam:
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic:
+      result = newSymNode(s, n.info)
+      result.typ = s.typ
+    elif s.ast != nil:
+      result = semExpr(c, s.ast)
+    else:
+      n.typ = s.typ
+      return n
+  of skType:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    if s.typ.kind == tyStatic and s.typ.n != nil:
+      return s.typ.n
+    result = newSymNode(s, n.info)
+    result.typ = makeTypeDesc(c, s.typ)
+  else:
+    markUsed(n.info, s)
+    styleCheckUse(n.info, s)
+    result = newSymNode(s, n.info)
+
+type
+  TConvStatus = enum
+    convOK,
+    convNotNeedeed,
+    convNotLegal
+
+proc checkConversionBetweenObjects(castDest, src: PType): TConvStatus =
+  return if inheritanceDiff(castDest, src) == high(int):
+      convNotLegal
+    else:
+      convOK
+
+const
+  IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
+
+proc checkConvertible(c: PContext, castDest, src: PType): TConvStatus =
+  result = convOK
+  if sameType(castDest, src) and castDest.sym == src.sym:
+    # don't annoy conversions that may be needed on another processor:
+    if castDest.kind notin IntegralTypes+{tyRange}:
+      result = convNotNeedeed
+    return
+  var d = skipTypes(castDest, abstractVar)
+  var s = skipTypes(src, abstractVar-{tyTypeDesc})
+  while (d != nil) and (d.kind in {tyPtr, tyRef}) and (d.kind == s.kind):
+    d = d.lastSon
+    s = s.lastSon
+  if d == nil:
+    result = convNotLegal
+  elif d.kind == tyObject and s.kind == tyObject:
+    result = checkConversionBetweenObjects(d, s)
+  elif (skipTypes(castDest, abstractVarRange).kind in IntegralTypes) and
+      (skipTypes(src, abstractVarRange-{tyTypeDesc}).kind in IntegralTypes):
+    # accept conversion between integral types
+    discard
+  else:
+    # we use d, s here to speed up that operation a bit:
+    case cmpTypes(c, d, s)
+    of isNone, isGeneric:
+      if not compareTypes(castDest, src, dcEqIgnoreDistinct):
+        result = convNotLegal
+    else:
+      discard
+
+proc isCastable(dst, src: PType): bool =
+  ## Checks whether the source type can be casted to the destination type.
+  ## Casting is very unrestrictive; casts are allowed as long as
+  ## castDest.size >= src.size, and typeAllowed(dst, skParam)
+  #const
+  #  castableTypeKinds = {tyInt, tyPtr, tyRef, tyCstring, tyString,
+  #                       tySequence, tyPointer, tyNil, tyOpenArray,
+  #                       tyProc, tySet, tyEnum, tyBool, tyChar}
+  if skipTypes(dst, abstractInst-{tyOpenArray}).kind == tyOpenArray:
+    return false
+  var dstSize, srcSize: BiggestInt
+
+  dstSize = computeSize(dst)
+  srcSize = computeSize(src)
+  if dstSize < 0:
+    result = false
+  elif srcSize < 0:
+    result = false
+  elif typeAllowed(dst, skParam) != nil:
+    result = false
+  else:
+    result = (dstSize >= srcSize) or
+        (skipTypes(dst, abstractInst).kind in IntegralTypes) or
+        (skipTypes(src, abstractInst-{tyTypeDesc}).kind in IntegralTypes)
+  if result and src.kind == tyNil:
+    result = dst.size <= platform.ptrSize
+
+proc isSymChoice(n: PNode): bool {.inline.} =
+  result = n.kind in nkSymChoices
+
+proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) =
+  # XXX: liftParamType started to perform addDecl
+  # we could do that instead in semTypeNode by snooping for added
+  # gnrc. params, then it won't be necessary to open a new scope here
+  openScope(c)
+  var lifted = liftParamType(c, skType, newNodeI(nkArgList, info),
+                             t, ":anon", info)
+  closeScope(c)
+  if lifted != nil: t = lifted
+
+proc semConv(c: PContext, n: PNode): PNode =
+  if sonsLen(n) != 2:
+    localError(n.info, errConvNeedsOneArg)
+    return n
+
+  result = newNodeI(nkConv, n.info)
+  var targetType = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
+  maybeLiftType(targetType, c, n[0].info)
+  result.addSon copyTree(n.sons[0])
+  var op = semExprWithType(c, n.sons[1])
+
+  if targetType.isMetaType:
+    let final = inferWithMetatype(c, targetType, op, true)
+    result.addSon final
+    result.typ = final.typ
+    return
+
+  result.typ = targetType
+  addSon(result, op)
+
+  if not isSymChoice(op):
+    let status = checkConvertible(c, result.typ, op.typ)
+    case status
+    of convOK:
+      # handle SomeProcType(SomeGenericProc)
+      # XXX: This needs fixing. checkConvertible uses typeRel internally, but
+      # doesn't bother to perform the work done in paramTypeMatchAux/fitNode
+      # so we are redoing the typeRel work here. Why does semConv exist as a
+      # separate proc from fitNode?
+      if op.kind == nkSym and op.sym.isGenericRoutine:
+        result.sons[1] = fitNode(c, result.typ, result.sons[1])
+    of convNotNeedeed:
+      message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
+    of convNotLegal:
+      localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)%
+        [op.typ.typeToString, result.typ.typeToString])
+  else:
+    for i in countup(0, sonsLen(op) - 1):
+      let it = op.sons[i]
+      let status = checkConvertible(c, result.typ, it.typ)
+      if status in {convOK, convNotNeedeed}:
+        markUsed(n.info, it.sym)
+        styleCheckUse(n.info, it.sym)
+        markIndirect(c, it.sym)
+        return it
+    localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
+
+proc semCast(c: PContext, n: PNode): PNode =
+  ## Semantically analyze a casting ("cast[type](param)")
+  if optSafeCode in gGlobalOptions: localError(n.info, errCastNotInSafeMode)
+  #incl(c.p.owner.flags, sfSideEffect)
+  checkSonsLen(n, 2)
+  result = newNodeI(nkCast, n.info)
+  result.typ = semTypeNode(c, n.sons[0], nil)
+  addSon(result, copyTree(n.sons[0]))
+  addSon(result, semExprWithType(c, n.sons[1]))
+  if not isCastable(result.typ, result.sons[1].typ):
+    localError(result.info, errExprCannotBeCastedToX,
+               typeToString(result.typ))
+
+proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
+  const
+    opToStr: array[mLow..mHigh, string] = ["low", "high"]
+  if sonsLen(n) != 2:
+    localError(n.info, errXExpectsTypeOrValue, opToStr[m])
+  else:
+    n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
+    var typ = skipTypes(n.sons[1].typ, abstractVarRange +
+                                       {tyTypeDesc, tyFieldAccessor})
+    case typ.kind
+    of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
+      n.typ = getSysType(tyInt)
+    of tyArrayConstr, tyArray:
+      n.typ = typ.sons[0] # indextype
+    of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
+      # do not skip the range!
+      n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor})
+    of tyGenericParam:
+      # prepare this for resolving in semtypinst:
+      # we must use copyTree here in order to avoid creating a cycle
+      # that could easily turn into an infinite recursion in semtypinst
+      n.typ = makeTypeFromExpr(c, n.copyTree)
+    else:
+      localError(n.info, errInvalidArgForX, opToStr[m])
+  result = n
+
+proc semSizeof(c: PContext, n: PNode): PNode =
+  if sonsLen(n) != 2:
+    localError(n.info, errXExpectsTypeOrValue, "sizeof")
+  else:
+    n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
+    #restoreOldStyleType(n.sons[1])
+  n.typ = getSysType(tyInt)
+  result = n
+
+proc semOf(c: PContext, n: PNode): PNode =
+  if sonsLen(n) == 3:
+    n.sons[1] = semExprWithType(c, n.sons[1])
+    n.sons[2] = semExprWithType(c, n.sons[2], {efDetermineType})
+    #restoreOldStyleType(n.sons[1])
+    #restoreOldStyleType(n.sons[2])
+    let a = skipTypes(n.sons[1].typ, abstractPtrs)
+    let b = skipTypes(n.sons[2].typ, abstractPtrs)
+    let x = skipTypes(n.sons[1].typ, abstractPtrs-{tyTypeDesc})
+    let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
+
+    if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
+      localError(n.info, errXExpectsObjectTypes, "of")
+    elif b.kind != tyObject or a.kind != tyObject:
+      localError(n.info, errXExpectsObjectTypes, "of")
+    else:
+      let diff = inheritanceDiff(a, b)
+      # | returns: 0 iff `a` == `b`
+      # | returns: -x iff `a` is the x'th direct superclass of `b`
+      # | returns: +x iff `a` is the x'th direct subclass of `b`
+      # | returns: `maxint` iff `a` and `b` are not compatible at all
+      if diff <= 0:
+        # optimize to true:
+        message(n.info, hintConditionAlwaysTrue, renderTree(n))
+        result = newIntNode(nkIntLit, 1)
+        result.info = n.info
+        result.typ = getSysType(tyBool)
+        return result
+      elif diff == high(int):
+        localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
+  else:
+    localError(n.info, errXExpectsTwoArguments, "of")
+  n.typ = getSysType(tyBool)
+  result = n
+
+proc isOpImpl(c: PContext, n: PNode): PNode =
+  internalAssert n.sonsLen == 3 and
+    n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
+    n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
+
+  let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor})
+
+  if n[2].kind in {nkStrLit..nkTripleStrLit}:
+    case n[2].strVal.normalize
+    of "closure":
+      let t = skipTypes(t1, abstractRange)
+      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
+                                        t.callConv == ccClosure and
+                                        tfIterator notin t.flags))
+    else: discard
+  else:
+    var t2 = n[2].typ.skipTypes({tyTypeDesc})
+    maybeLiftType(t2, c, n.info)
+    var m: TCandidate
+    initCandidate(c, m, t2)
+    let match = typeRel(m, t2, t1) >= isSubtype # isNone
+    result = newIntNode(nkIntLit, ord(match))
+
+  result.typ = n.typ
+
+proc semIs(c: PContext, n: PNode): PNode =
+  if sonsLen(n) != 3:
+    localError(n.info, errXExpectsTwoArguments, "is")
+
+  result = n
+  n.typ = getSysType(tyBool)
+
+  n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator})
+  if n[2].kind notin {nkStrLit..nkTripleStrLit}:
+    let t2 = semTypeNode(c, n[2], nil)
+    n.sons[2] = newNodeIT(nkType, n[2].info, t2)
+
+  let lhsType = n[1].typ
+  if lhsType.kind != tyTypeDesc:
+    n.sons[1] = makeTypeSymNode(c, lhsType, n[1].info)
+  elif lhsType.base.kind == tyNone:
+    # this is a typedesc variable, leave for evals
+    return
+
+  # BUGFIX: don't evaluate this too early: ``T is void``
+  if not n[1].typ.base.containsGenericType: result = isOpImpl(c, n)
+
+proc semOpAux(c: PContext, n: PNode) =
+  const flags = {efDetermineType}
+  for i in countup(1, n.sonsLen-1):
+    var a = n.sons[i]
+    if a.kind == nkExprEqExpr and sonsLen(a) == 2:
+      var info = a.sons[0].info
+      a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
+      a.sons[1] = semExprWithType(c, a.sons[1], flags)
+      a.typ = a.sons[1].typ
+    else:
+      n.sons[i] = semExprWithType(c, a, flags)
+
+proc overloadedCallOpr(c: PContext, n: PNode): PNode =
+  # quick check if there is *any* () operator overloaded:
+  var par = getIdent("()")
+  if searchInScopes(c, par) == nil:
+    result = nil
+  else:
+    result = newNodeI(nkCall, n.info)
+    addSon(result, newIdentNode(par, n.info))
+    for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
+    result = semExpr(c, result)
+
+proc changeType(n: PNode, newType: PType, check: bool) =
+  case n.kind
+  of nkCurly, nkBracket:
+    for i in countup(0, sonsLen(n) - 1):
+      changeType(n.sons[i], elemType(newType), check)
+  of nkPar:
+    let tup = newType.skipTypes({tyGenericInst})
+    if tup.kind != tyTuple:
+      if tup.kind == tyObject: return
+      internalError(n.info, "changeType: no tuple type for constructor")
+    elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
+      # named tuple?
+      for i in countup(0, sonsLen(n) - 1):
+        var m = n.sons[i].sons[0]
+        if m.kind != nkSym:
+          internalError(m.info, "changeType(): invalid tuple constr")
+          return
+        if tup.n != nil:
+          var f = getSymFromList(tup.n, m.sym.name)
+          if f == nil:
+            internalError(m.info, "changeType(): invalid identifier")
+            return
+          changeType(n.sons[i].sons[1], f.typ, check)
+        else:
+          changeType(n.sons[i].sons[1], tup.sons[i], check)
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        changeType(n.sons[i], tup.sons[i], check)
+        when false:
+          var m = n.sons[i]
+          var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
+          addSon(a, newSymNode(newType.n.sons[i].sym))
+          addSon(a, m)
+          changeType(m, tup.sons[i], check)
+  of nkCharLit..nkUInt64Lit:
+    if check:
+      let value = n.intVal
+      if value < firstOrd(newType) or value > lastOrd(newType):
+        localError(n.info, errGenerated, "cannot convert " & $value &
+                                         " to " & typeToString(newType))
+  else: discard
+  n.typ = newType
+
+proc arrayConstrType(c: PContext, n: PNode): PType =
+  var typ = newTypeS(tyArrayConstr, c)
+  rawAddSon(typ, nil)     # index type
+  if sonsLen(n) == 0:
+    rawAddSon(typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
+  else:
+    var x = n.sons[0]
+    var lastIndex: BiggestInt = sonsLen(n) - 1
+    var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
+    addSonSkipIntLit(typ, t)
+  typ.sons[0] = makeRangeType(c, 0, sonsLen(n) - 1, n.info)
+  result = typ
+
+proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  result = newNodeI(nkBracket, n.info)
+  result.typ = newTypeS(tyArrayConstr, c)
+  rawAddSon(result.typ, nil)     # index type
+  if sonsLen(n) == 0:
+    rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
+  else:
+    var x = n.sons[0]
+    var lastIndex: BiggestInt = 0
+    var indexType = getSysType(tyInt)
+    if x.kind == nkExprColonExpr and sonsLen(x) == 2:
+      var idx = semConstExpr(c, x.sons[0])
+      lastIndex = getOrdValue(idx)
+      indexType = idx.typ
+      x = x.sons[1]
+
+    let yy = semExprWithType(c, x)
+    var typ = yy.typ
+    addSon(result, yy)
+    #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyOrdinal})
+    for i in countup(1, sonsLen(n) - 1):
+      x = n.sons[i]
+      if x.kind == nkExprColonExpr and sonsLen(x) == 2:
+        var idx = semConstExpr(c, x.sons[0])
+        idx = fitNode(c, indexType, idx)
+        if lastIndex+1 != getOrdValue(idx):
+          localError(x.info, errInvalidOrderInArrayConstructor)
+        x = x.sons[1]
+
+      let xx = semExprWithType(c, x, flags*{efAllowDestructor})
+      result.add xx
+      typ = commonType(typ, xx.typ)
+      #n.sons[i] = semExprWithType(c, x, flags*{efAllowDestructor})
+      #addSon(result, fitNode(c, typ, n.sons[i]))
+      inc(lastIndex)
+    addSonSkipIntLit(result.typ, typ)
+    for i in 0 .. <result.len:
+      result.sons[i] = fitNode(c, typ, result.sons[i])
+  result.typ.sons[0] = makeRangeType(c, 0, sonsLen(result) - 1, n.info)
+
+proc fixAbstractType(c: PContext, n: PNode) =
+  for i in 1 .. < n.len:
+    let it = n.sons[i]
+    # do not get rid of nkHiddenSubConv for OpenArrays, the codegen needs it:
+    if it.kind == nkHiddenSubConv and
+        skipTypes(it.typ, abstractVar).kind notin {tyOpenArray, tyVarargs}:
+      if skipTypes(it.sons[1].typ, abstractVar).kind in
+            {tyNil, tyArrayConstr, tyTuple, tySet}:
+        var s = skipTypes(it.typ, abstractVar)
+        if s.kind != tyExpr:
+          changeType(it.sons[1], s, check=true)
+        n.sons[i] = it.sons[1]
+  when false:
+    # XXX finally rewrite that crap!
+    for i in countup(1, sonsLen(n) - 1):
+      var it = n.sons[i]
+      case it.kind
+      of nkHiddenStdConv, nkHiddenSubConv:
+        if it.sons[1].kind == nkBracket:
+          it.sons[1].typ = arrayConstrType(c, it.sons[1])
+          #it.sons[1] = semArrayConstr(c, it.sons[1])
+        if skipTypes(it.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
+          #if n.sons[0].kind == nkSym and IdentEq(n.sons[0].sym.name, "[]="):
+          #  debug(n)
+
+          var s = skipTypes(it.sons[1].typ, abstractVar)
+          if s.kind == tyArrayConstr and s.sons[1].kind == tyEmpty:
+            s = copyType(s, getCurrOwner(), false)
+            skipTypes(s, abstractVar).sons[1] = elemType(
+                skipTypes(it.typ, abstractVar))
+            it.sons[1].typ = s
+          elif s.kind == tySequence and s.sons[0].kind == tyEmpty:
+            s = copyType(s, getCurrOwner(), false)
+            skipTypes(s, abstractVar).sons[0] = elemType(
+                skipTypes(it.typ, abstractVar))
+            it.sons[1].typ = s
+
+        elif skipTypes(it.sons[1].typ, abstractVar).kind in
+            {tyNil, tyArrayConstr, tyTuple, tySet}:
+          var s = skipTypes(it.typ, abstractVar)
+          if s.kind != tyExpr:
+            changeType(it.sons[1], s, check=true)
+          n.sons[i] = it.sons[1]
+      of nkBracket:
+        # an implicitly constructed array (passed to an open array):
+        n.sons[i] = semArrayConstr(c, it, {})
+      else:
+        discard
+        #if (it.typ == nil):
+        #  InternalError(it.info, "fixAbstractType: " & renderTree(it))
+
+proc skipObjConv(n: PNode): PNode =
+  case n.kind
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    if skipTypes(n.sons[1].typ, abstractPtrs).kind in {tyTuple, tyObject}:
+      result = n.sons[1]
+    else:
+      result = n
+  of nkObjUpConv, nkObjDownConv: result = n.sons[0]
+  else: result = n
+
+proc isAssignable(c: PContext, n: PNode): TAssignableResult =
+  result = parampatterns.isAssignable(c.p.owner, n)
+
+proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
+  if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
+                                      sfCompileToCpp in c.module.flags):
+    checkSonsLen(n, 1)
+    result = n.sons[0]
+  else:
+    result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
+    addSon(result, n)
+    if isAssignable(c, n) notin {arLValue, arLocalLValue}:
+      localError(n.info, errVarForOutParamNeeded)
+
+proc analyseIfAddressTaken(c: PContext, n: PNode): PNode =
+  result = n
+  case n.kind
+  of nkSym:
+    # n.sym.typ can be nil in 'check' mode ...
+    if n.sym.typ != nil and
+        skipTypes(n.sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
+      incl(n.sym.flags, sfAddrTaken)
+      result = newHiddenAddrTaken(c, n)
+  of nkDotExpr:
+    checkSonsLen(n, 2)
+    if n.sons[1].kind != nkSym:
+      internalError(n.info, "analyseIfAddressTaken")
+      return
+    if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind != tyVar:
+      incl(n.sons[1].sym.flags, sfAddrTaken)
+      result = newHiddenAddrTaken(c, n)
+  of nkBracketExpr:
+    checkMinSonsLen(n, 1)
+    if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind != tyVar:
+      if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken)
+      result = newHiddenAddrTaken(c, n)
+  else:
+    result = newHiddenAddrTaken(c, n)
+
+proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
+  checkMinSonsLen(n, 1)
+  const
+    FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
+      mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
+      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
+
+  # get the real type of the callee
+  # it may be a proc var with a generic alias type, so we skip over them
+  var t = n.sons[0].typ.skipTypes({tyGenericInst})
+
+  if n.sons[0].kind == nkSym and n.sons[0].sym.magic in FakeVarParams:
+    # BUGFIX: check for L-Value still needs to be done for the arguments!
+    # note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
+    for i in countup(1, sonsLen(n) - 1):
+      if i < sonsLen(t) and t.sons[i] != nil and
+          skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
+        if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}:
+          if n.sons[i].kind != nkHiddenAddr:
+            localError(n.sons[i].info, errVarForOutParamNeeded)
+    return
+  for i in countup(1, sonsLen(n) - 1):
+    if n.sons[i].kind == nkHiddenCallConv:
+      # we need to recurse explicitly here as converters can create nested
+      # calls and then they wouldn't be analysed otherwise
+      analyseIfAddressTakenInCall(c, n.sons[i])
+    semProcvarCheck(c, n.sons[i])
+    if i < sonsLen(t) and
+        skipTypes(t.sons[i], abstractInst-{tyTypeDesc}).kind == tyVar:
+      if n.sons[i].kind != nkHiddenAddr:
+        n.sons[i] = analyseIfAddressTaken(c, n.sons[i])
+
+include semmagic
+
+proc evalAtCompileTime(c: PContext, n: PNode): PNode =
+  result = n
+  if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
+  var callee = n.sons[0].sym
+
+  # constant folding that is necessary for correctness of semantic pass:
+  if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
+    var call = newNodeIT(nkCall, n.info, n.typ)
+    call.add(n.sons[0])
+    var allConst = true
+    for i in 1 .. < n.len:
+      var a = getConstExpr(c.module, n.sons[i])
+      if a == nil:
+        allConst = false
+        a = n.sons[i]
+        if a.kind == nkHiddenStdConv: a = a.sons[1]
+      call.add(a)
+    if allConst:
+      result = semfold.getConstExpr(c.module, call)
+      if result.isNil: result = n
+      else: return result
+    result.typ = semfold.getIntervalType(callee.magic, call)
+
+  block maybeLabelAsStatic:
+    # XXX: temporary work-around needed for tlateboundstatic.
+    # This is certainly not correct, but it will get the job
+    # done until we have a more robust infrastructure for
+    # implicit statics.
+    if n.len > 1:
+      for i in 1 .. <n.len:
+        # see bug #2113, it's possible that n[i].typ for errornous code:
+        if n[i].typ.isNil or n[i].typ.kind != tyStatic or
+            tfUnresolved notin n[i].typ.flags:
+          break maybeLabelAsStatic
+      n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
+      n.typ.flags.incl tfUnresolved
+
+  # optimization pass: not necessary for correctness of the semantic pass
+  if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
+     {sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
+    if sfCompileTime notin callee.flags and
+        optImplicitStatic notin gOptions: return
+
+    if callee.magic notin ctfeWhitelist: return
+    if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
+      return
+
+    if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
+
+    var call = newNodeIT(nkCall, n.info, n.typ)
+    call.add(n.sons[0])
+    for i in 1 .. < n.len:
+      let a = getConstExpr(c.module, n.sons[i])
+      if a == nil: return n
+      call.add(a)
+    #echo "NOW evaluating at compile time: ", call.renderTree
+    if sfCompileTime in callee.flags:
+      result = evalStaticExpr(c.module, call, c.p.owner)
+      if result.isNil:
+        localError(n.info, errCannotInterpretNodeX, renderTree(call))
+      else: result = fixupTypeAfterEval(c, result, n)
+    else:
+      result = evalConstExpr(c.module, call)
+      if result.isNil: result = n
+      else: result = fixupTypeAfterEval(c, result, n)
+    #if result != n:
+    #  echo "SUCCESS evaluated at compile time: ", call.renderTree
+
+proc semStaticExpr(c: PContext, n: PNode): PNode =
+  let a = semExpr(c, n.sons[0])
+  result = evalStaticExpr(c.module, a, c.p.owner)
+  if result.isNil:
+    localError(n.info, errCannotInterpretNodeX, renderTree(n))
+    result = emptyNode
+  else:
+    result = fixupTypeAfterEval(c, result, a)
+
+proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
+                                     flags: TExprFlags): PNode =
+  if flags*{efInTypeof, efWantIterator} != {}:
+    # consider: 'for x in pReturningArray()' --> we don't want the restriction
+    # to 'skIterators' anymore; skIterators are preferred in sigmatch already
+    # for typeof support.
+    # for ``type(countup(1,3))``, see ``tests/ttoseq``.
+    result = semOverloadedCall(c, n, nOrig,
+      {skProc, skMethod, skConverter, skMacro, skTemplate}+skIterators)
+  else:
+    result = semOverloadedCall(c, n, nOrig,
+      {skProc, skMethod, skConverter, skMacro, skTemplate})
+
+  if result != nil:
+    if result.sons[0].kind != nkSym:
+      internalError("semOverloadedCallAnalyseEffects")
+      return
+    let callee = result.sons[0].sym
+    case callee.kind
+    of skMacro, skTemplate: discard
+    else:
+      if callee.kind in skIterators and callee.id == c.p.owner.id:
+        localError(n.info, errRecursiveDependencyX, callee.name.s)
+        # error correction, prevents endless for loop elimination in transf.
+        # See bug #2051:
+        result.sons[0] = newSymNode(errorSym(c, n))
+      if sfNoSideEffect notin callee.flags:
+        if {sfImportc, sfSideEffect} * callee.flags != {}:
+          incl(c.p.owner.flags, sfSideEffect)
+
+proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
+
+proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
+                         t: PType): TCandidate =
+  initCandidate(c, result, t)
+  matches(c, n, nOrig, result)
+  if result.state != csMatch:
+    # try to deref the first argument:
+    if experimentalMode(c) and canDeref(n):
+      n.sons[1] = n.sons[1].tryDeref
+      initCandidate(c, result, t)
+      matches(c, n, nOrig, result)
+
+proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  result = nil
+  checkMinSonsLen(n, 1)
+  var prc = n.sons[0]
+  if n.sons[0].kind == nkDotExpr:
+    checkSonsLen(n.sons[0], 2)
+    n.sons[0] = semFieldAccess(c, n.sons[0])
+    if n.sons[0].kind == nkDotCall:
+      # it is a static call!
+      result = n.sons[0]
+      result.kind = nkCall
+      result.flags.incl nfExplicitCall
+      for i in countup(1, sonsLen(n) - 1): addSon(result, n.sons[i])
+      return semExpr(c, result, flags)
+  else:
+    n.sons[0] = semExpr(c, n.sons[0])
+  let nOrig = n.copyTree
+  semOpAux(c, n)
+  var t: PType = nil
+  if n.sons[0].typ != nil:
+    t = skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc})
+  if t != nil and t.kind == tyProc:
+    # This is a proc variable, apply normal overload resolution
+    let m = resolveIndirectCall(c, n, nOrig, t)
+    if m.state != csMatch:
+      if c.inCompilesContext > 0:
+        # speed up error generation:
+        globalError(n.info, errTypeMismatch, "")
+        return emptyNode
+      else:
+        var hasErrorType = false
+        var msg = msgKindToString(errTypeMismatch)
+        for i in countup(1, sonsLen(n) - 1):
+          if i > 1: add(msg, ", ")
+          let nt = n.sons[i].typ
+          add(msg, typeToString(nt))
+          if nt.kind == tyError:
+            hasErrorType = true
+            break
+        if not hasErrorType:
+          add(msg, ")\n" & msgKindToString(errButExpected) & "\n" &
+              typeToString(n.sons[0].typ))
+          localError(n.info, errGenerated, msg)
+        return errorNode(c, n)
+      result = nil
+    else:
+      result = m.call
+      instGenericConvertersSons(c, result, m)
+    # we assume that a procedure that calls something indirectly
+    # has side-effects:
+    if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
+  elif t != nil and t.kind == tyTypeDesc:
+    if n.len == 1: return semObjConstr(c, n, flags)
+    return semConv(c, n)
+  else:
+    result = overloadedCallOpr(c, n)
+    # Now that nkSym does not imply an iteration over the proc/iterator space,
+    # the old ``prc`` (which is likely an nkIdent) has to be restored:
+    if result == nil:
+      # XXX: hmm, what kind of symbols will end up here?
+      # do we really need to try the overload resolution?
+      n.sons[0] = prc
+      nOrig.sons[0] = prc
+      n.flags.incl nfExprCall
+      result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
+      if result == nil: return errorNode(c, n)
+    elif result.kind notin nkCallKinds:
+      # the semExpr() in overloadedCallOpr can even break this condition!
+      # See bug #904 of how to trigger it:
+      return result
+  #result = afterCallActions(c, result, nOrig, flags)
+  fixAbstractType(c, result)
+  analyseIfAddressTakenInCall(c, result)
+  if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone:
+    result = magicsAfterOverloadResolution(c, result, flags)
+  result = evalAtCompileTime(c, result)
+
+proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
+  result = n
+  let callee = result.sons[0].sym
+  case callee.kind
+  of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
+  of skTemplate: result = semTemplateExpr(c, result, callee, flags)
+  else:
+    semFinishOperands(c, result)
+    activate(c, result)
+    fixAbstractType(c, result)
+    analyseIfAddressTakenInCall(c, result)
+    if callee.magic != mNone:
+      result = magicsAfterOverloadResolution(c, result, flags)
+  if c.inTypeClass == 0:
+    result = evalAtCompileTime(c, result)
+
+proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # this seems to be a hotspot in the compiler!
+  let nOrig = n.copyTree
+  #semLazyOpAux(c, n)
+  result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
+  if result != nil: result = afterCallActions(c, result, nOrig, flags)
+  else: result = errorNode(c, n)
+
+proc buildEchoStmt(c: PContext, n: PNode): PNode =
+  # we MUST not check 'n' for semantics again here! But for now we give up:
+  result = newNodeI(nkCall, n.info)
+  var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
+  if e != nil:
+    add(result, newSymNode(e))
+  else:
+    localError(n.info, errSystemNeeds, "echo")
+    add(result, errorNode(c, n))
+  add(result, n)
+  result = semExpr(c, result)
+
+proc semExprNoType(c: PContext, n: PNode): PNode =
+  result = semExpr(c, n, {efWantStmt})
+  discardCheck(c, result)
+
+proc isTypeExpr(n: PNode): bool =
+  case n.kind
+  of nkType, nkTypeOfExpr: result = true
+  of nkSym: result = n.sym.kind == skType
+  else: result = false
+
+proc createSetType(c: PContext; baseType: PType): PType =
+  assert baseType != nil
+  result = newTypeS(tySet, c)
+  rawAddSon(result, baseType)
+
+proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent,
+                                 check: var PNode): PSym =
+  # transform in a node that contains the runtime check for the
+  # field, if it is in a case-part...
+  result = nil
+  case r.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(r) - 1):
+      result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check)
+      if result != nil: return
+  of nkRecCase:
+    checkMinSonsLen(r, 2)
+    if (r.sons[0].kind != nkSym): illFormedAst(r)
+    result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check)
+    if result != nil: return
+    let setType = createSetType(c, r.sons[0].typ)
+    var s = newNodeIT(nkCurly, r.info, setType)
+    for i in countup(1, sonsLen(r) - 1):
+      var it = r.sons[i]
+      case it.kind
+      of nkOfBranch:
+        result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
+        if result == nil:
+          for j in 0..sonsLen(it)-2: addSon(s, copyTree(it.sons[j]))
+        else:
+          if check == nil:
+            check = newNodeI(nkCheckedFieldExpr, n.info)
+            addSon(check, ast.emptyNode) # make space for access node
+          s = newNodeIT(nkCurly, n.info, setType)
+          for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j]))
+          var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
+          addSon(inExpr, newSymNode(ast.opContains, n.info))
+          addSon(inExpr, s)
+          addSon(inExpr, copyTree(r.sons[0]))
+          addSon(check, inExpr)
+          #addSon(check, semExpr(c, inExpr))
+          return
+      of nkElse:
+        result = lookupInRecordAndBuildCheck(c, n, lastSon(it), field, check)
+        if result != nil:
+          if check == nil:
+            check = newNodeI(nkCheckedFieldExpr, n.info)
+            addSon(check, ast.emptyNode) # make space for access node
+          var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
+          addSon(inExpr, newSymNode(ast.opContains, n.info))
+          addSon(inExpr, s)
+          addSon(inExpr, copyTree(r.sons[0]))
+          var notExpr = newNodeIT(nkCall, n.info, getSysType(tyBool))
+          addSon(notExpr, newSymNode(ast.opNot, n.info))
+          addSon(notExpr, inExpr)
+          addSon(check, notExpr)
+          return
+      else: illFormedAst(it)
+  of nkSym:
+    if r.sym.name.id == field.id: result = r.sym
+  else: illFormedAst(n)
+
+proc makeDeref(n: PNode): PNode =
+  var t = skipTypes(n.typ, {tyGenericInst})
+  result = n
+  if t.kind == tyVar:
+    result = newNodeIT(nkHiddenDeref, n.info, t.sons[0])
+    addSon(result, n)
+    t = skipTypes(t.sons[0], {tyGenericInst})
+  while t.kind in {tyPtr, tyRef}:
+    var a = result
+    let baseTyp = t.lastSon
+    result = newNodeIT(nkHiddenDeref, n.info, baseTyp)
+    addSon(result, a)
+    t = skipTypes(baseTyp, {tyGenericInst})
+
+const
+  tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass}
+  tyDotOpTransparent = {tyVar, tyPtr, tyRef}
+
+proc readTypeParameter(c: PContext, typ: PType,
+                       paramName: PIdent, info: TLineInfo): PNode =
+  let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
+           else: (internalAssert(typ.kind == tyCompositeTypeClass);
+                  typ.sons[1].skipGenericAlias)
+  let tbody = ty.sons[0]
+  for s in countup(0, tbody.len-2):
+    let tParam = tbody.sons[s]
+    if tParam.sym.name.id == paramName.id:
+      let rawTyp = ty.sons[s + 1]
+      if rawTyp.kind == tyStatic:
+        return rawTyp.n
+      else:
+        let foundTyp = makeTypeDesc(c, rawTyp)
+        return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
+  #echo "came here: returned nil"
+
+proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  ## returns nil if it's not a built-in field access
+  checkSonsLen(n, 2)
+  # tests/bind/tbindoverload.nim wants an early exit here, but seems to
+  # work without now. template/tsymchoicefield doesn't like an early exit
+  # here at all!
+  #if isSymChoice(n.sons[1]): return
+
+  var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
+  if s != nil:
+    if s.kind in OverloadableSyms:
+      result = symChoice(c, n, s, scClosed)
+      if result.kind == nkSym: result = semSym(c, n, s, flags)
+    else:
+      markUsed(n.sons[1].info, s)
+      result = semSym(c, n, s, flags)
+    styleCheckUse(n.sons[1].info, s)
+    return
+
+  n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
+  #restoreOldStyleType(n.sons[0])
+  var i = considerQuotedIdent(n.sons[1])
+  var ty = n.sons[0].typ
+  var f: PSym = nil
+  result = nil
+  if isTypeExpr(n.sons[0]) or (ty.kind == tyTypeDesc and ty.base.kind != tyNone):
+    if ty.kind == tyTypeDesc: ty = ty.base
+    ty = ty.skipTypes(tyDotOpTransparent)
+    case ty.kind
+    of tyEnum:
+      # look up if the identifier belongs to the enum:
+      while ty != nil:
+        f = getSymFromList(ty.n, i)
+        if f != nil: break
+        ty = ty.sons[0]         # enum inheritance
+      if f != nil:
+        result = newSymNode(f)
+        result.info = n.info
+        result.typ = ty
+        markUsed(n.info, f)
+        styleCheckUse(n.info, f)
+        return
+    of tyTypeParamsHolders:
+      return readTypeParameter(c, ty, i, n.info)
+    of tyObject, tyTuple:
+      if ty.n != nil and ty.n.kind == nkRecList:
+        for field in ty.n:
+          if field.sym.name == i:
+            n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.sym.typ])
+            n.typ.n = copyTree(n)
+            return n
+    else:
+      # echo "TYPE FIELD ACCESS"
+      # debug ty
+      return
+    # XXX: This is probably not relevant any more
+    # reset to prevent 'nil' bug: see "tests/reject/tenumitems.nim":
+    ty = n.sons[0].typ
+    return nil
+  ty = skipTypes(ty, {tyGenericInst, tyVar, tyPtr, tyRef})
+  while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
+  var check: PNode = nil
+  if ty.kind == tyObject:
+    while true:
+      check = nil
+      f = lookupInRecordAndBuildCheck(c, n, ty.n, i, check)
+      if f != nil: break
+      if ty.sons[0] == nil: break
+      ty = skipTypes(ty.sons[0], {tyGenericInst})
+    if f != nil:
+      if fieldVisible(c, f):
+        # is the access to a public field or in the same module or in a friend?
+        markUsed(n.sons[1].info, f)
+        styleCheckUse(n.sons[1].info, f)
+        n.sons[0] = makeDeref(n.sons[0])
+        n.sons[1] = newSymNode(f) # we now have the correct field
+        n.typ = f.typ
+        if check == nil:
+          result = n
+        else:
+          check.sons[0] = n
+          check.typ = n.typ
+          result = check
+  elif ty.kind == tyTuple and ty.n != nil:
+    f = getSymFromList(ty.n, i)
+    if f != nil:
+      markUsed(n.sons[1].info, f)
+      styleCheckUse(n.sons[1].info, f)
+      n.sons[0] = makeDeref(n.sons[0])
+      n.sons[1] = newSymNode(f)
+      n.typ = f.typ
+      result = n
+
+  # we didn't find any field, let's look for a generic param
+  if result == nil:
+    let t = n.sons[0].typ.skipTypes(tyDotOpTransparent)
+    if t.kind in tyTypeParamsHolders:
+      result = readTypeParameter(c, t, i, n.info)
+
+proc dotTransformation(c: PContext, n: PNode): PNode =
+  if isSymChoice(n.sons[1]):
+    result = newNodeI(nkDotCall, n.info)
+    addSon(result, n.sons[1])
+    addSon(result, copyTree(n[0]))
+  else:
+    var i = considerQuotedIdent(n.sons[1])
+    result = newNodeI(nkDotCall, n.info)
+    result.flags.incl nfDotField
+    addSon(result, newIdentNode(i, n[1].info))
+    addSon(result, copyTree(n[0]))
+
+proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # this is difficult, because the '.' is used in many different contexts
+  # in Nim. We first allow types in the semantic checking.
+  result = builtinFieldAccess(c, n, flags)
+  if result == nil:
+    result = dotTransformation(c, n)
+
+proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
+  result = newNodeI(nkCall, n.info)
+  result.add(newIdentNode(ident, n.info))
+  for i in 0 .. n.len-1: result.add(n[i])
+
+proc semDeref(c: PContext, n: PNode): PNode =
+  checkSonsLen(n, 1)
+  n.sons[0] = semExprWithType(c, n.sons[0])
+  result = n
+  var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar})
+  case t.kind
+  of tyRef, tyPtr: n.typ = t.lastSon
+  else: result = nil
+  #GlobalError(n.sons[0].info, errCircumNeedsPointer)
+
+proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  ## returns nil if not a built-in subscript operator; also called for the
+  ## checking of assignments
+  if sonsLen(n) == 1:
+    let x = semDeref(c, n)
+    if x == nil: return nil
+    result = newNodeIT(nkDerefExpr, x.info, x.typ)
+    result.add(x[0])
+    return
+  checkMinSonsLen(n, 2)
+  n.sons[0] = semExprWithType(c, n.sons[0])
+  let arr = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+  case arr.kind
+  of tyArray, tyOpenArray, tyVarargs, tyArrayConstr, tySequence, tyString,
+     tyCString:
+    if n.len != 2: return nil
+    n.sons[0] = makeDeref(n.sons[0])
+    c.p.bracketExpr = n.sons[0]
+    for i in countup(1, sonsLen(n) - 1):
+      n.sons[i] = semExprWithType(c, n.sons[i],
+                                  flags*{efInTypeof, efDetermineType})
+    var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt)
+    var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1])
+    if arg != nil:
+      n.sons[1] = arg
+      result = n
+      result.typ = elemType(arr)
+    #GlobalError(n.info, errIndexTypesDoNotMatch)
+  of tyTypeDesc:
+    # The result so far is a tyTypeDesc bound
+    # a tyGenericBody. The line below will substitute
+    # it with the instantiated type.
+    result = n
+    result.typ = makeTypeDesc(c, semTypeNode(c, n, nil))
+    #result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
+  of tyTuple:
+    checkSonsLen(n, 2)
+    n.sons[0] = makeDeref(n.sons[0])
+    c.p.bracketExpr = n.sons[0]
+    # [] operator for tuples requires constant expression:
+    n.sons[1] = semConstExpr(c, n.sons[1])
+    if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
+        {tyInt..tyInt64}:
+      var idx = getOrdValue(n.sons[1])
+      if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)]
+      else: localError(n.info, errInvalidIndexValueForTuple)
+    else:
+      localError(n.info, errIndexTypesDoNotMatch)
+    result = n
+  else:
+    c.p.bracketExpr = n.sons[0]
+
+proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  let oldBracketExpr = c.p.bracketExpr
+  result = semSubscript(c, n, flags)
+  if result == nil:
+    # overloaded [] operator:
+    result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]"))
+  c.p.bracketExpr = oldBracketExpr
+
+proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
+  var id = considerQuotedIdent(a[1])
+  var setterId = newIdentNode(getIdent(id.s & '='), n.info)
+  # a[0] is already checked for semantics, that does ``builtinFieldAccess``
+  # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
+  # nodes?
+  let aOrig = nOrig[0]
+  result = newNode(nkCall, n.info, sons = @[setterId, a[0], semExpr(c, n[1])])
+  result.flags.incl nfDotSetter
+  let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
+  result = semOverloadedCallAnalyseEffects(c, result, orig, {})
+
+  if result != nil:
+    result = afterCallActions(c, result, nOrig, {})
+    #fixAbstractType(c, result)
+    #analyseIfAddressTakenInCall(c, result)
+
+proc takeImplicitAddr(c: PContext, n: PNode): PNode =
+  case n.kind
+  of nkHiddenAddr, nkAddr: return n
+  of nkHiddenDeref, nkDerefExpr: return n.sons[0]
+  of nkBracketExpr:
+    if len(n) == 1: return n.sons[0]
+  else: discard
+  var valid = isAssignable(c, n)
+  if valid != arLValue:
+    if valid == arLocalLValue:
+      localError(n.info, errXStackEscape, renderTree(n, {renderNoComments}))
+    else:
+      localError(n.info, errExprHasNoAddress)
+  result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ))
+  result.add(n)
+
+proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
+  if le.kind == nkHiddenDeref:
+    var x = le.sons[0]
+    if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult:
+      n.sons[0] = x # 'result[]' --> 'result'
+      n.sons[1] = takeImplicitAddr(c, ri)
+      x.typ.flags.incl tfVarIsPtr
+
+template resultTypeIsInferrable(typ: PType): expr =
+  typ.isMetaType and typ.kind != tyTypeDesc
+
+proc semAsgn(c: PContext, n: PNode): PNode =
+  checkSonsLen(n, 2)
+  var a = n.sons[0]
+  case a.kind
+  of nkDotExpr:
+    # r.f = x
+    # --> `f=` (r, x)
+    let nOrig = n.copyTree
+    a = builtinFieldAccess(c, a, {efLValue})
+    if a == nil:
+      a = propertyWriteAccess(c, n, nOrig, n[0])
+      if a != nil: return a
+      # we try without the '='; proc that return 'var' or macros are still
+      # possible:
+      a = dotTransformation(c, n[0])
+      if a.kind == nkDotCall:
+        a.kind = nkCall
+        a = semExprWithType(c, a, {efLValue})
+  of nkBracketExpr:
+    # a[i] = x
+    # --> `[]=`(a, i, x)
+    let oldBracketExpr = c.p.bracketExpr
+    a = semSubscript(c, a, {efLValue})
+    if a == nil:
+      result = buildOverloadedSubscripts(n.sons[0], getIdent"[]=")
+      add(result, n[1])
+      result = semExprNoType(c, result)
+      c.p.bracketExpr = oldBracketExpr
+      return result
+    c.p.bracketExpr = oldBracketExpr
+  of nkCurlyExpr:
+    # a{i} = x -->  `{}=`(a, i, x)
+    result = buildOverloadedSubscripts(n.sons[0], getIdent"{}=")
+    add(result, n[1])
+    return semExprNoType(c, result)
+  else:
+    a = semExprWithType(c, a, {efLValue})
+  n.sons[0] = a
+  # a = b # both are vars, means: a[] = b[]
+  # a = b # b no 'var T' means: a = addr(b)
+  var le = a.typ
+  if skipTypes(le, {tyGenericInst}).kind != tyVar and
+      isAssignable(c, a) == arNone:
+    # Direct assignment to a discriminant is allowed!
+    localError(a.info, errXCannotBeAssignedTo,
+               renderTree(a, {renderNoComments}))
+  else:
+    let
+      lhs = n.sons[0]
+      lhsIsResult = lhs.kind == nkSym and lhs.sym.kind == skResult
+    var
+      rhs = semExprWithType(c, n.sons[1],
+        if lhsIsResult: {efAllowDestructor} else: {})
+    if lhsIsResult:
+      n.typ = enforceVoidContext
+      if c.p.owner.kind != skMacro and resultTypeIsInferrable(lhs.sym.typ):
+        if cmpTypes(c, lhs.typ, rhs.typ) == isGeneric:
+          internalAssert c.p.resultSym != nil
+          lhs.typ = rhs.typ
+          c.p.resultSym.typ = rhs.typ
+          c.p.owner.typ.sons[0] = rhs.typ
+        else:
+          typeMismatch(n, lhs.typ, rhs.typ)
+
+    n.sons[1] = fitNode(c, le, rhs)
+    if tfHasAsgn in lhs.typ.flags and not lhsIsResult:
+      return overloadedAsgn(c, lhs, n.sons[1])
+
+    fixAbstractType(c, n)
+    asgnToResultVar(c, n, n.sons[0], n.sons[1])
+  result = n
+
+proc semReturn(c: PContext, n: PNode): PNode =
+  result = n
+  checkSonsLen(n, 1)
+  if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro,
+                        skClosureIterator}:
+    if n.sons[0].kind != nkEmpty:
+      # transform ``return expr`` to ``result = expr; return``
+      if c.p.resultSym != nil:
+        var a = newNodeI(nkAsgn, n.sons[0].info)
+        addSon(a, newSymNode(c.p.resultSym))
+        addSon(a, n.sons[0])
+        n.sons[0] = semAsgn(c, a)
+        # optimize away ``result = result``:
+        if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym:
+          n.sons[0] = ast.emptyNode
+      else:
+        localError(n.info, errNoReturnTypeDeclared)
+  else:
+    localError(n.info, errXNotAllowedHere, "\'return\'")
+
+proc semProcBody(c: PContext, n: PNode): PNode =
+  openScope(c)
+
+  result = semExpr(c, n)
+  if c.p.resultSym != nil and not isEmptyType(result.typ):
+    # transform ``expr`` to ``result = expr``, but not if the expr is already
+    # ``result``:
+    if result.kind == nkSym and result.sym == c.p.resultSym:
+      discard
+    elif result.kind == nkNilLit:
+      # or ImplicitlyDiscardable(result):
+      # new semantic: 'result = x' triggers the void context
+      result.typ = nil
+    elif result.kind == nkStmtListExpr and result.typ.kind == tyNil:
+      # to keep backwards compatibility bodies like:
+      #   nil
+      #   # comment
+      # are not expressions:
+      fixNilType(result)
+    else:
+      var a = newNodeI(nkAsgn, n.info, 2)
+      a.sons[0] = newSymNode(c.p.resultSym)
+      a.sons[1] = result
+      result = semAsgn(c, a)
+  else:
+    discardCheck(c, result)
+
+  if c.p.owner.kind notin {skMacro, skTemplate} and
+     c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
+    if isEmptyType(result.typ):
+      # we inferred a 'void' return type:
+      c.p.resultSym.typ = nil
+      c.p.owner.typ.sons[0] = nil
+    else:
+      localError(c.p.resultSym.info, errCannotInferReturnType)
+
+  closeScope(c)
+
+proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
+  var t = skipTypes(restype, {tyGenericInst})
+  case t.kind
+  of tyVar:
+    n.sons[0] = takeImplicitAddr(c, n.sons[0])
+  of tyTuple:
+    for i in 0.. <t.sonsLen:
+      var e = skipTypes(t.sons[i], {tyGenericInst})
+      if e.kind == tyVar:
+        if n.sons[0].kind == nkPar:
+          n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i])
+        elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
+             n.sons[0].sons[1].kind == nkPar:
+          var a = n.sons[0].sons[1]
+          a.sons[i] = takeImplicitAddr(c, a.sons[i])
+        else:
+          localError(n.sons[0].info, errXExpected, "tuple constructor")
+  else: discard
+
+proc semYield(c: PContext, n: PNode): PNode =
+  result = n
+  checkSonsLen(n, 1)
+  if c.p.owner == nil or c.p.owner.kind notin skIterators:
+    localError(n.info, errYieldNotAllowedHere)
+  elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline:
+    localError(n.info, errYieldNotAllowedInTryStmt)
+  elif n.sons[0].kind != nkEmpty:
+    n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility:
+    var iterType = c.p.owner.typ
+    let restype = iterType.sons[0]
+    if restype != nil:
+      let adjustedRes = if restype.kind == tyIter: restype.base
+                        else: restype
+      if adjustedRes.kind != tyExpr:
+        n.sons[0] = fitNode(c, adjustedRes, n.sons[0])
+      if n.sons[0].typ == nil: internalError(n.info, "semYield")
+
+      if resultTypeIsInferrable(adjustedRes):
+        let inferred = n.sons[0].typ
+        if restype.kind == tyIter:
+          restype.sons[0] = inferred
+        else:
+          iterType.sons[0] = inferred
+
+      semYieldVarResult(c, n, adjustedRes)
+    else:
+      localError(n.info, errCannotReturnExpr)
+  elif c.p.owner.typ.sons[0] != nil:
+    localError(n.info, errGenerated, "yield statement must yield a value")
+
+proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
+  if onlyCurrentScope:
+    result = localSearchInScope(c, i)
+  else:
+    result = searchInScopes(c, i) # no need for stub loading
+
+proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
+  case n.kind
+  of nkIdent:
+    result = lookUpForDefined(c, n.ident, onlyCurrentScope)
+  of nkDotExpr:
+    result = nil
+    if onlyCurrentScope: return
+    checkSonsLen(n, 2)
+    var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope)
+    if m != nil and m.kind == skModule:
+      let ident = considerQuotedIdent(n[1])
+      if m == c.module:
+        result = strTableGet(c.topLevelScope.symbols, ident)
+      else:
+        result = strTableGet(m.tab, ident)
+  of nkAccQuoted:
+    result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope)
+  of nkSym:
+    result = n.sym
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = n.sons[0].sym
+  else:
+    localError(n.info, errIdentifierExpected, renderTree(n))
+    result = nil
+
+proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode =
+  checkSonsLen(n, 2)
+  # we replace this node by a 'true' or 'false' node:
+  result = newIntNode(nkIntLit, 0)
+  if not onlyCurrentScope and considerQuotedIdent(n[0]).s == "defined":
+    if n.sons[1].kind != nkIdent:
+      localError(n.info, "obsolete usage of 'defined', use 'declared' instead")
+    elif condsyms.isDefined(n.sons[1].ident):
+      result.intVal = 1
+  elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil:
+    result.intVal = 1
+  result.info = n.info
+  result.typ = getSysType(tyBool)
+
+proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym =
+  ## The argument to the proc should be nkCall(...) or similar
+  ## Returns the macro/template symbol
+  if isCallExpr(n):
+    var expandedSym = qualifiedLookUp(c, n[0], {checkUndeclared})
+    if expandedSym == nil:
+      localError(n.info, errUndeclaredIdentifier, n[0].renderTree)
+      return errorSym(c, n[0])
+
+    if expandedSym.kind notin {skMacro, skTemplate}:
+      localError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s)
+      return errorSym(c, n[0])
+
+    result = expandedSym
+  else:
+    localError(n.info, errXisNoMacroOrTemplate, n.renderTree)
+    result = errorSym(c, n)
+
+proc expectString(c: PContext, n: PNode): string =
+  var n = semConstExpr(c, n)
+  if n.kind in nkStrKinds:
+    return n.strVal
+  else:
+    localError(n.info, errStringLiteralExpected)
+
+proc getMagicSym(magic: TMagic): PSym =
+  result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo)
+  result.magic = magic
+
+proc newAnonSym(kind: TSymKind, info: TLineInfo,
+                owner = getCurrOwner()): PSym =
+  result = newSym(kind, idAnon, owner, info)
+  result.flags = {sfGenSym}
+
+proc semUsing(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkEmpty, n.info)
+  if not experimentalMode(c):
+    localError(n.info, "use the {.experimental.} pragma to enable 'using'")
+  for e in n.sons:
+    let usedSym = semExpr(c, e)
+    if usedSym.kind == nkSym:
+      case usedSym.sym.kind
+      of skLocalVars + {skConst}:
+        c.currentScope.usingSyms.safeAdd(usedSym)
+        continue
+      of skProcKinds:
+        addDeclAt(c.currentScope, usedSym.sym)
+        continue
+      else: discard
+
+    localError(e.info, errUsingNoSymbol, e.renderTree)
+
+proc semExpandToAst(c: PContext, n: PNode): PNode =
+  var macroCall = n[1]
+  var expandedSym = expectMacroOrTemplateCall(c, macroCall)
+  if expandedSym.kind == skError: return n
+
+  macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
+  markUsed(n.info, expandedSym)
+  styleCheckUse(n.info, expandedSym)
+
+  for i in countup(1, macroCall.len-1):
+    macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
+
+  # Preserve the magic symbol in order to be handled in evals.nim
+  internalAssert n.sons[0].sym.magic == mExpandToAst
+  #n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
+  n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
+          else: sysTypeFromName"PNimrodNode"
+  result = n
+
+proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
+                    flags: TExprFlags = {}): PNode =
+  if sonsLen(n) == 2:
+    n.sons[0] = newSymNode(magicSym, n.info)
+    result = semExpandToAst(c, n)
+  else:
+    result = semDirectOp(c, n, flags)
+
+proc processQuotations(n: var PNode, op: string,
+                       quotes: var seq[PNode],
+                       ids: var seq[PNode]) =
+  template returnQuote(q) =
+    quotes.add q
+    n = newIdentNode(getIdent($quotes.len), n.info)
+    ids.add n
+    return
+
+  if n.kind == nkPrefix:
+    checkSonsLen(n, 2)
+    if n[0].kind == nkIdent:
+      var examinedOp = n[0].ident.s
+      if examinedOp == op:
+        returnQuote n[1]
+      elif examinedOp.startsWith(op):
+        n.sons[0] = newIdentNode(getIdent(examinedOp.substr(op.len)), n.info)
+  elif n.kind == nkAccQuoted and op == "``":
+    returnQuote n[0]
+
+  for i in 0 .. <n.safeLen:
+    processQuotations(n.sons[i], op, quotes, ids)
+
+proc semQuoteAst(c: PContext, n: PNode): PNode =
+  internalAssert n.len == 2 or n.len == 3
+  # We transform the do block into a template with a param for
+  # each interpolation. We'll pass this template to getAst.
+  var
+    doBlk = n{-1}
+    op = if n.len == 3: expectString(c, n[1]) else: "``"
+    quotes = newSeq[PNode](1)
+      # the quotes will be added to a nkCall statement
+      # leave some room for the callee symbol
+    ids = newSeq[PNode]()
+      # this will store the generated param names
+
+  if doBlk.kind != nkDo:
+    localError(n.info, errXExpected, "block")
+
+  processQuotations(doBlk.sons[bodyPos], op, quotes, ids)
+
+  doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
+  if ids.len > 0:
+    doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
+    doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type
+    ids.add getSysSym("expr").newSymNode # params type
+    ids.add emptyNode # no default value
+    doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
+
+  var tmpl = semTemplateDef(c, doBlk)
+  quotes[0] = tmpl[namePos]
+  result = newNode(nkCall, n.info, @[
+    getMagicSym(mExpandToAst).newSymNode,
+    newNode(nkCall, n.info, quotes)])
+  result = semExpandToAst(c, result)
+
+proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+  # watch out, hacks ahead:
+  let oldErrorCount = msgs.gErrorCounter
+  let oldErrorMax = msgs.gErrorMax
+  inc c.inCompilesContext
+  # do not halt after first error:
+  msgs.gErrorMax = high(int)
+
+  # open a scope for temporary symbol inclusions:
+  let oldScope = c.currentScope
+  openScope(c)
+  let oldOwnerLen = len(gOwners)
+  let oldGenerics = c.generics
+  let oldErrorOutputs = errorOutputs
+  errorOutputs = {}
+  let oldContextLen = msgs.getInfoContextLen()
+
+  let oldInGenericContext = c.inGenericContext
+  let oldInUnrolledContext = c.inUnrolledContext
+  let oldInGenericInst = c.inGenericInst
+  let oldProcCon = c.p
+  c.generics = @[]
+  try:
+    result = semExpr(c, n, flags)
+    if msgs.gErrorCounter != oldErrorCount: result = nil
+  except ERecoverableError:
+    discard
+  # undo symbol table changes (as far as it's possible):
+  c.generics = oldGenerics
+  c.inGenericContext = oldInGenericContext
+  c.inUnrolledContext = oldInUnrolledContext
+  c.inGenericInst = oldInGenericInst
+  c.p = oldProcCon
+  msgs.setInfoContextLen(oldContextLen)
+  setLen(gOwners, oldOwnerLen)
+  c.currentScope = oldScope
+  dec c.inCompilesContext
+  errorOutputs = oldErrorOutputs
+  msgs.gErrorCounter = oldErrorCount
+  msgs.gErrorMax = oldErrorMax
+
+proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # we replace this node by a 'true' or 'false' node:
+  if sonsLen(n) != 2: return semDirectOp(c, n, flags)
+
+  result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil))
+  result.info = n.info
+  result.typ = getSysType(tyBool)
+
+proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  if sonsLen(n) == 3:
+    # XXX ugh this is really a hack: shallowCopy() can be overloaded only
+    # with procs that take not 2 parameters:
+    result = newNodeI(nkFastAsgn, n.info)
+    result.add(n[1])
+    result.add(n[2])
+    result = semAsgn(c, result)
+  else:
+    result = semDirectOp(c, n, flags)
+
+proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
+  result = newType(tyGenericInvocation, c.module)
+  addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ)
+  addSonSkipIntLit(result, t)
+  result = instGenericContainer(c, info, result, allowMetaTypes = false)
+
+proc instantiateCreateFlowVarCall(c: PContext; t: PType;
+                                  info: TLineInfo): PSym =
+  let sym = magicsys.getCompilerProc("nimCreateFlowVar")
+  if sym == nil:
+    localError(info, errSystemNeeds, "nimCreateFlowVar")
+  var bindings: TIdTable
+  initIdTable(bindings)
+  bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t)
+  result = c.semGenerateInstance(c, sym, bindings, info)
+  # since it's an instantiation, we unmark it as a compilerproc. Otherwise
+  # codegen would fail:
+  if sfCompilerProc in result.flags:
+    result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC}
+    result.loc.r = nil
+
+proc setMs(n: PNode, s: PSym): PNode =
+  result = n
+  n.sons[0] = newSymNode(s)
+  n.sons[0].info = n.info
+
+proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
+  # this is a hotspot in the compiler!
+  # DON'T forget to update ast.SpecialSemMagics if you add a magic here!
+  result = n
+  case s.magic # magics that need special treatment
+  of mAddr:
+    checkSonsLen(n, 2)
+    result = semAddr(c, n.sons[1])
+  of mTypeOf:
+    checkSonsLen(n, 2)
+    result = semTypeOf(c, n.sons[1])
+  of mDefined: result = semDefined(c, setMs(n, s), false)
+  of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
+  of mCompiles: result = semCompiles(c, setMs(n, s), flags)
+  of mLow: result = semLowHigh(c, setMs(n, s), mLow)
+  of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
+  of mSizeOf: result = semSizeof(c, setMs(n, s))
+  of mIs: result = semIs(c, setMs(n, s))
+  of mOf: result = semOf(c, setMs(n, s))
+  of mShallowCopy: result = semShallowCopy(c, n, flags)
+  of mExpandToAst: result = semExpandToAst(c, n, s, flags)
+  of mQuoteAst: result = semQuoteAst(c, n)
+  of mAstToStr:
+    checkSonsLen(n, 2)
+    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
+    result.typ = getSysType(tyString)
+  of mParallel:
+    result = setMs(n, s)
+    var x = n.lastSon
+    if x.kind == nkDo: x = x.sons[bodyPos]
+    inc c.inParallelStmt
+    result.sons[1] = semStmt(c, x)
+    dec c.inParallelStmt
+  of mSpawn:
+    result = setMs(n, s)
+    result.sons[1] = semExpr(c, n.sons[1])
+    if not result[1].typ.isEmptyType:
+      if spawnResult(result[1].typ, c.inParallelStmt > 0) == srFlowVar:
+        result.typ = createFlowVar(c, result[1].typ, n.info)
+      else:
+        result.typ = result[1].typ
+      result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
+  of mProcCall:
+    result = setMs(n, s)
+    result.sons[1] = semExpr(c, n.sons[1])
+    result.typ = n[1].typ
+  else: result = semDirectOp(c, n, flags)
+
+proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
+  # If semCheck is set to false, ``when`` will return the verbatim AST of
+  # the correct branch. Otherwise the AST will be passed through semStmt.
+  result = nil
+
+  template setResult(e: expr) =
+    if semCheck: result = semStmt(c, e) # do not open a new scope!
+    else: result = e
+
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    case it.kind
+    of nkElifBranch, nkElifExpr:
+      checkSonsLen(it, 2)
+      var e = semConstExpr(c, it.sons[0])
+      if e.kind != nkIntLit:
+        # can happen for cascading errors, assume false
+        # InternalError(n.info, "semWhen")
+        discard
+      elif e.intVal != 0 and result == nil:
+        setResult(it.sons[1])
+    of nkElse, nkElseExpr:
+      checkSonsLen(it, 1)
+      if result == nil:
+        setResult(it.sons[0])
+    else: illFormedAst(n)
+  if result == nil:
+    result = newNodeI(nkEmpty, n.info)
+  # The ``when`` statement implements the mechanism for platform dependent
+  # code. Thus we try to ensure here consistent ID allocation after the
+  # ``when`` statement.
+  idSynchronizationPoint(200)
+
+proc semSetConstr(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkCurly, n.info)
+  result.typ = newTypeS(tySet, c)
+  if sonsLen(n) == 0:
+    rawAddSon(result.typ, newTypeS(tyEmpty, c))
+  else:
+    # only semantic checking for all elements, later type checking:
+    var typ: PType = nil
+    for i in countup(0, sonsLen(n) - 1):
+      if isRange(n.sons[i]):
+        checkSonsLen(n.sons[i], 3)
+        n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1])
+        n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2])
+        if typ == nil:
+          typ = skipTypes(n.sons[i].sons[1].typ,
+                          {tyGenericInst, tyVar, tyOrdinal})
+        n.sons[i].typ = n.sons[i].sons[2].typ # range node needs type too
+      elif n.sons[i].kind == nkRange:
+        # already semchecked
+        if typ == nil:
+          typ = skipTypes(n.sons[i].sons[0].typ,
+                          {tyGenericInst, tyVar, tyOrdinal})
+      else:
+        n.sons[i] = semExprWithType(c, n.sons[i])
+        if typ == nil:
+          typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyOrdinal})
+    if not isOrdinalType(typ):
+      localError(n.info, errOrdinalTypeExpected)
+      typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
+    elif lengthOrd(typ) > MaxSetElements:
+      typ = makeRangeType(c, 0, MaxSetElements-1, n.info)
+    addSonSkipIntLit(result.typ, typ)
+    for i in countup(0, sonsLen(n) - 1):
+      var m: PNode
+      if isRange(n.sons[i]):
+        m = newNodeI(nkRange, n.sons[i].info)
+        addSon(m, fitNode(c, typ, n.sons[i].sons[1]))
+        addSon(m, fitNode(c, typ, n.sons[i].sons[2]))
+      elif n.sons[i].kind == nkRange: m = n.sons[i] # already semchecked
+      else:
+        m = fitNode(c, typ, n.sons[i])
+      addSon(result, m)
+
+proc semTableConstr(c: PContext, n: PNode): PNode =
+  # we simply transform ``{key: value, key2, key3: value}`` to
+  # ``[(key, value), (key2, value2), (key3, value2)]``
+  result = newNodeI(nkBracket, n.info)
+  var lastKey = 0
+  for i in 0..n.len-1:
+    var x = n.sons[i]
+    if x.kind == nkExprColonExpr and sonsLen(x) == 2:
+      for j in countup(lastKey, i-1):
+        var pair = newNodeI(nkPar, x.info)
+        pair.add(n.sons[j])
+        pair.add(x[1])
+        result.add(pair)
+
+      var pair = newNodeI(nkPar, x.info)
+      pair.add(x[0])
+      pair.add(x[1])
+      result.add(pair)
+
+      lastKey = i+1
+
+  if lastKey != n.len: illFormedAst(n)
+  result = semExpr(c, result)
+
+type
+  TParKind = enum
+    paNone, paSingle, paTupleFields, paTuplePositions
+
+proc checkPar(n: PNode): TParKind =
+  var length = sonsLen(n)
+  if length == 0:
+    result = paTuplePositions # ()
+  elif length == 1:
+    if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
+    else: result = paSingle         # (expr)
+  else:
+    if n.sons[0].kind == nkExprColonExpr: result = paTupleFields
+    else: result = paTuplePositions
+    for i in countup(0, length - 1):
+      if result == paTupleFields:
+        if (n.sons[i].kind != nkExprColonExpr) or
+            not (n.sons[i].sons[0].kind in {nkSym, nkIdent}):
+          localError(n.sons[i].info, errNamedExprExpected)
+          return paNone
+      else:
+        if n.sons[i].kind == nkExprColonExpr:
+          localError(n.sons[i].info, errNamedExprNotAllowed)
+          return paNone
+
+proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  result = newNodeI(nkPar, n.info)
+  var typ = newTypeS(tyTuple, c)
+  typ.n = newNodeI(nkRecList, n.info) # nkIdentDefs
+  var ids = initIntSet()
+  for i in countup(0, sonsLen(n) - 1):
+    if n[i].kind != nkExprColonExpr or n[i][0].kind notin {nkSym, nkIdent}:
+      illFormedAst(n.sons[i])
+    var id: PIdent
+    if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident
+    else: id = n.sons[i].sons[0].sym.name
+    if containsOrIncl(ids, id.id):
+      localError(n.sons[i].info, errFieldInitTwice, id.s)
+    n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1],
+                                        flags*{efAllowDestructor})
+    var f = newSymS(skField, n.sons[i].sons[0], c)
+    f.typ = skipIntLit(n.sons[i].sons[1].typ)
+    f.position = i
+    rawAddSon(typ, f.typ)
+    addSon(typ.n, newSymNode(f))
+    n.sons[i].sons[0] = newSymNode(f)
+    addSon(result, n.sons[i])
+  result.typ = typ
+
+proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  result = n                  # we don't modify n, but compute the type:
+  var typ = newTypeS(tyTuple, c)  # leave typ.n nil!
+  for i in countup(0, sonsLen(n) - 1):
+    n.sons[i] = semExprWithType(c, n.sons[i], flags*{efAllowDestructor})
+    addSonSkipIntLit(typ, n.sons[i].typ)
+  result.typ = typ
+
+proc isTupleType(n: PNode): bool =
+  if n.len == 0:
+    return false # don't interpret () as type
+  for i in countup(0, n.len - 1):
+    if n[i].typ == nil or n[i].typ.kind != tyTypeDesc:
+      return false
+  return true
+
+proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      checkInitialized(n.sons[i], ids, info)
+  of nkRecCase:
+    if (n.sons[0].kind != nkSym): internalError(info, "checkInitialized")
+    checkInitialized(n.sons[0], ids, info)
+    when false:
+      # XXX we cannot check here, as we don't know the branch!
+      for i in countup(1, sonsLen(n) - 1):
+        case n.sons[i].kind
+        of nkOfBranch, nkElse: checkInitialized(lastSon(n.sons[i]), ids, info)
+        else: internalError(info, "checkInitialized")
+  of nkSym:
+    if {tfNotNil, tfNeedsInit} * n.sym.typ.flags != {} and
+        n.sym.name.id notin ids:
+      message(info, errGenerated, "field not initialized: " & n.sym.name.s)
+  else: internalError(info, "checkInitialized")
+
+proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  var t = semTypeNode(c, n.sons[0], nil)
+  result = n
+  result.typ = t
+  result.kind = nkObjConstr
+  t = skipTypes(t, {tyGenericInst})
+  if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst})
+  if t.kind != tyObject:
+    localError(n.info, errGenerated, "object constructor needs an object type")
+    return
+  var objType = t
+  var ids = initIntSet()
+  for i in 1.. <n.len:
+    let it = n.sons[i]
+    if it.kind != nkExprColonExpr:
+      localError(n.info, errNamedExprExpected)
+      break
+    let id = considerQuotedIdent(it.sons[0])
+
+    if containsOrIncl(ids, id.id):
+      localError(it.info, errFieldInitTwice, id.s)
+    var e = semExprWithType(c, it.sons[1], flags*{efAllowDestructor})
+    var
+      check: PNode = nil
+      f: PSym
+    t = objType
+    while true:
+      check = nil
+      f = lookupInRecordAndBuildCheck(c, it, t.n, id, check)
+      if f != nil: break
+      if t.sons[0] == nil: break
+      t = skipTypes(t.sons[0], {tyGenericInst})
+    if f != nil and fieldVisible(c, f):
+      it.sons[0] = newSymNode(f)
+      e = fitNode(c, f.typ, e)
+      # small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have
+      # 3 children the last being the field check
+      if check != nil:
+        check.sons[0] = it.sons[0]
+        it.add(check)
+    else:
+      localError(it.info, errUndeclaredFieldX, id.s)
+    it.sons[1] = e
+    # XXX object field name check for 'case objects' if the kind is static?
+  if tfNeedsInit in objType.flags:
+    while true:
+      checkInitialized(objType.n, ids, n.info)
+      if objType.sons[0] == nil: break
+      objType = skipTypes(objType.sons[0], {tyGenericInst})
+
+proc semBlock(c: PContext, n: PNode): PNode =
+  result = n
+  inc(c.p.nestedBlockCounter)
+  checkSonsLen(n, 2)
+  openScope(c) # BUGFIX: label is in the scope of block!
+  if n.sons[0].kind != nkEmpty:
+    var labl = newSymG(skLabel, n.sons[0], c)
+    if sfGenSym notin labl.flags:
+      addDecl(c, labl)
+      n.sons[0] = newSymNode(labl, n.sons[0].info)
+    suggestSym(n.sons[0].info, labl)
+    styleCheckDef(labl)
+  n.sons[1] = semExpr(c, n.sons[1])
+  n.typ = n.sons[1].typ
+  if isEmptyType(n.typ): n.kind = nkBlockStmt
+  else: n.kind = nkBlockExpr
+  closeScope(c)
+  dec(c.p.nestedBlockCounter)
+
+proc semExport(c: PContext, n: PNode): PNode =
+  var x = newNodeI(n.kind, n.info)
+  #let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
+  for i in 0.. <n.len:
+    let a = n.sons[i]
+    var o: TOverloadIter
+    var s = initOverloadIter(o, c, a)
+    if s == nil:
+      localError(a.info, errGenerated, "cannot export: " & renderTree(a))
+    elif s.kind == skModule:
+      # forward everything from that module:
+      strTableAdd(c.module.tab, s)
+      x.add(newSymNode(s, a.info))
+      var ti: TTabIter
+      var it = initTabIter(ti, s.tab)
+      while it != nil:
+        if it.kind in ExportableSymKinds+{skModule}:
+          strTableAdd(c.module.tab, it)
+        it = nextIter(ti, s.tab)
+    else:
+      while s != nil:
+        if s.kind in ExportableSymKinds+{skModule}:
+          x.add(newSymNode(s, a.info))
+          strTableAdd(c.module.tab, s)
+        s = nextOverloadIter(o, c, a)
+  when false:
+    if c.module.ast.isNil:
+      c.module.ast = newNodeI(nkStmtList, n.info)
+    assert c.module.ast.kind == nkStmtList
+    c.module.ast.add x
+  result = n
+
+proc setGenericParams(c: PContext, n: PNode) =
+  for i in 1 .. <n.len:
+    n[i].typ = semTypeNode(c, n[i], nil)
+
+proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
+  result = n
+  if gCmd == cmdIdeTools: suggestExpr(c, n)
+  if nfSem in n.flags: return
+  case n.kind
+  of nkIdent, nkAccQuoted:
+    var s = lookUp(c, n)
+    if c.inTypeClass == 0: semCaptureSym(s, c.p.owner)
+    result = semSym(c, n, s, flags)
+    if s.kind in {skProc, skMethod, skConverter}+skIterators:
+      #performProcvarCheck(c, n, s)
+      result = symChoice(c, n, s, scClosed)
+      if result.kind == nkSym:
+        markIndirect(c, result.sym)
+        # if isGenericRoutine(result.sym):
+        #   localError(n.info, errInstantiateXExplicitly, s.name.s)
+  of nkSym:
+    # because of the changed symbol binding, this does not mean that we
+    # don't have to check the symbol for semantics here again!
+    result = semSym(c, n, n.sym, flags)
+  of nkEmpty, nkNone, nkCommentStmt:
+    discard
+  of nkNilLit:
+    if result.typ == nil: result.typ = getSysType(tyNil)
+  of nkIntLit:
+    if result.typ == nil: setIntLitType(result)
+  of nkInt8Lit:
+    if result.typ == nil: result.typ = getSysType(tyInt8)
+  of nkInt16Lit:
+    if result.typ == nil: result.typ = getSysType(tyInt16)
+  of nkInt32Lit:
+    if result.typ == nil: result.typ = getSysType(tyInt32)
+  of nkInt64Lit:
+    if result.typ == nil: result.typ = getSysType(tyInt64)
+  of nkUIntLit:
+    if result.typ == nil: result.typ = getSysType(tyUInt)
+  of nkUInt8Lit:
+    if result.typ == nil: result.typ = getSysType(tyUInt8)
+  of nkUInt16Lit:
+    if result.typ == nil: result.typ = getSysType(tyUInt16)
+  of nkUInt32Lit:
+    if result.typ == nil: result.typ = getSysType(tyUInt32)
+  of nkUInt64Lit:
+    if result.typ == nil: result.typ = getSysType(tyUInt64)
+  of nkFloatLit:
+    if result.typ == nil: result.typ = getFloatLitType(result)
+  of nkFloat32Lit:
+    if result.typ == nil: result.typ = getSysType(tyFloat32)
+  of nkFloat64Lit:
+    if result.typ == nil: result.typ = getSysType(tyFloat64)
+  of nkFloat128Lit:
+    if result.typ == nil: result.typ = getSysType(tyFloat128)
+  of nkStrLit..nkTripleStrLit:
+    if result.typ == nil: result.typ = getSysType(tyString)
+  of nkCharLit:
+    if result.typ == nil: result.typ = getSysType(tyChar)
+  of nkDotExpr:
+    result = semFieldAccess(c, n, flags)
+    if result.kind == nkDotCall:
+      result.kind = nkCall
+      result = semExpr(c, result, flags)
+  of nkBind:
+    message(n.info, warnDeprecated, "bind")
+    result = semExpr(c, n.sons[0], flags)
+  of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy:
+    var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
+    result.typ = makeTypeDesc(c, typ)
+    #result = symNodeFromType(c, typ, n.info)
+  of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit:
+    # check if it is an expression macro:
+    checkMinSonsLen(n, 1)
+    let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
+    var s = qualifiedLookUp(c, n.sons[0], mode)
+    if s != nil:
+      #if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
+      #  pretty.checkUse(n.sons[0].sons[1].info, s)
+      case s.kind
+      of skMacro:
+        if sfImmediate notin s.flags:
+          result = semDirectOp(c, n, flags)
+        else:
+          result = semMacroExpr(c, n, n, s, flags)
+      of skTemplate:
+        if sfImmediate notin s.flags:
+          result = semDirectOp(c, n, flags)
+        else:
+          result = semTemplateExpr(c, n, s, flags)
+      of skType:
+        # XXX think about this more (``set`` procs)
+        if n.len == 2:
+          result = semConv(c, n)
+        elif n.len == 1:
+          result = semObjConstr(c, n, flags)
+        elif contains(c.ambiguousSymbols, s.id):
+          localError(n.info, errUseQualifier, s.name.s)
+        elif s.magic == mNone: result = semDirectOp(c, n, flags)
+        else: result = semMagic(c, n, s, flags)
+      of skProc, skMethod, skConverter, skIterators:
+        if s.magic == mNone: result = semDirectOp(c, n, flags)
+        else: result = semMagic(c, n, s, flags)
+      else:
+        #liMessage(n.info, warnUser, renderTree(n));
+        result = semIndirectOp(c, n, flags)
+    elif n[0].kind == nkBracketExpr and isSymChoice(n[0][0]):
+      # indirectOp can deal with explicit instantiations; the fixes
+      # the 'newSeq[T](x)' bug
+      setGenericParams(c, n.sons[0])
+      result = semDirectOp(c, n, flags)
+    elif isSymChoice(n.sons[0]) or nfDotField in n.flags:
+      result = semDirectOp(c, n, flags)
+    else:
+      result = semIndirectOp(c, n, flags)
+  of nkWhen:
+    if efWantStmt in flags:
+      result = semWhen(c, n, true)
+    else:
+      result = semWhen(c, n, false)
+      result = semExpr(c, result, flags)
+  of nkBracketExpr:
+    checkMinSonsLen(n, 1)
+    var s = qualifiedLookUp(c, n.sons[0], {checkUndeclared})
+    if (s != nil and s.kind in {skProc, skMethod, skConverter}+skIterators) or
+        n[0].kind in nkSymChoices:
+      # type parameters: partial generic specialization
+      n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
+      result = explicitGenericInstantiation(c, n, s)
+    elif s != nil and s.kind in {skType}:
+      result = symNodeFromType(c, semTypeNode(c, n, nil), n.info)
+    else:
+      result = semArrayAccess(c, n, flags)
+  of nkCurlyExpr:
+    result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags)
+  of nkPragmaExpr:
+    # which pragmas are allowed for expressions? `likely`, `unlikely`
+    internalError(n.info, "semExpr() to implement") # XXX: to implement
+  of nkPar:
+    case checkPar(n)
+    of paNone: result = errorNode(c, n)
+    of paTuplePositions:
+      var tupexp = semTuplePositionsConstr(c, n, flags)
+      if isTupleType(tupexp):
+        # reinterpret as type
+        var typ = semTypeNode(c, n, nil).skipTypes({tyTypeDesc, tyIter})
+        result.typ = makeTypeDesc(c, typ)
+      else:
+        result = tupexp
+    of paTupleFields: result = semTupleFieldsConstr(c, n, flags)
+    of paSingle: result = semExpr(c, n.sons[0], flags)
+  of nkCurly: result = semSetConstr(c, n)
+  of nkBracket: result = semArrayConstr(c, n, flags)
+  of nkObjConstr: result = semObjConstr(c, n, flags)
+  of nkLambda: result = semLambda(c, n, flags)
+  of nkDo: result = semDo(c, n, flags)
+  of nkDerefExpr: result = semDeref(c, n)
+  of nkAddr:
+    result = n
+    checkSonsLen(n, 1)
+    result = semAddr(c, n.sons[0])
+  of nkHiddenAddr, nkHiddenDeref:
+    checkSonsLen(n, 1)
+    n.sons[0] = semExpr(c, n.sons[0], flags)
+  of nkCast: result = semCast(c, n)
+  of nkIfExpr, nkIfStmt: result = semIf(c, n)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv:
+    checkSonsLen(n, 2)
+  of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv:
+    checkSonsLen(n, 1)
+  of nkChckRangeF, nkChckRange64, nkChckRange:
+    checkSonsLen(n, 3)
+  of nkCheckedFieldExpr:
+    checkMinSonsLen(n, 2)
+  of nkTableConstr:
+    result = semTableConstr(c, n)
+  of nkClosedSymChoice, nkOpenSymChoice:
+    # handling of sym choices is context dependent
+    # the node is left intact for now
+    discard
+  of nkStaticExpr:
+    result = semStaticExpr(c, n)
+  of nkAsgn: result = semAsgn(c, n)
+  of nkBlockStmt, nkBlockExpr: result = semBlock(c, n)
+  of nkStmtList, nkStmtListExpr: result = semStmtList(c, n, flags)
+  of nkRaiseStmt: result = semRaise(c, n)
+  of nkVarSection: result = semVarOrLet(c, n, skVar)
+  of nkLetSection: result = semVarOrLet(c, n, skLet)
+  of nkConstSection: result = semConst(c, n)
+  of nkTypeSection: result = semTypeSection(c, n)
+  of nkDiscardStmt: result = semDiscard(c, n)
+  of nkWhileStmt: result = semWhile(c, n)
+  of nkTryStmt: result = semTry(c, n)
+  of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n)
+  of nkForStmt, nkParForStmt: result = semFor(c, n)
+  of nkCaseStmt: result = semCase(c, n)
+  of nkReturnStmt: result = semReturn(c, n)
+  of nkUsingStmt: result = semUsing(c, n)
+  of nkAsmStmt: result = semAsm(c, n)
+  of nkYieldStmt: result = semYield(c, n)
+  of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
+  of nkIteratorDef: result = semIterator(c, n)
+  of nkProcDef: result = semProc(c, n)
+  of nkMethodDef: result = semMethod(c, n)
+  of nkConverterDef: result = semConverterDef(c, n)
+  of nkMacroDef: result = semMacroDef(c, n)
+  of nkTemplateDef: result = semTemplateDef(c, n)
+  of nkImportStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
+    result = evalImport(c, n)
+  of nkImportExceptStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import")
+    result = evalImportExcept(c, n)
+  of nkFromStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from")
+    result = evalFrom(c, n)
+  of nkIncludeStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include")
+    result = evalInclude(c, n)
+  of nkExportStmt, nkExportExceptStmt:
+    if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export")
+    result = semExport(c, n)
+  of nkPragmaBlock:
+    result = semPragmaBlock(c, n)
+  of nkStaticStmt:
+    result = semStaticStmt(c, n)
+  of nkDefer:
+    localError(n.info, errGenerated, "'defer' not allowed in this context")
+  else:
+    localError(n.info, errInvalidExpressionX,
+               renderTree(n, {renderNoComments}))
+  if result != nil: incl(result.flags, nfSem)
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
new file mode 100644
index 000000000..e086e73f8
--- /dev/null
+++ b/compiler/semfields.nim
@@ -0,0 +1,164 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module does the semantic transformation of the fields* iterators.
+#  included from semstmts.nim
+
+type
+  TFieldInstCtx = object  # either 'tup[i]' or 'field' is valid
+    tupleType: PType      # if != nil we're traversing a tuple
+    tupleIndex: int
+    field: PSym
+    replaceByFieldName: bool
+
+proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
+  case n.kind
+  of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
+  of nkIdent, nkSym:
+    result = n
+    let ident = considerQuotedIdent(n)
+    var L = sonsLen(forLoop)
+    if c.replaceByFieldName:
+      if ident.id == considerQuotedIdent(forLoop[0]).id:
+        let fieldName = if c.tupleType.isNil: c.field.name.s
+                        elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
+                        else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
+        result = newStrNode(nkStrLit, fieldName)
+        return
+    # other fields:
+    for i in ord(c.replaceByFieldName)..L-3:
+      if ident.id == considerQuotedIdent(forLoop[i]).id:
+        var call = forLoop.sons[L-2]
+        var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
+        if c.field.isNil:
+          result = newNodeI(nkBracketExpr, n.info)
+          result.add(tupl)
+          result.add(newIntNode(nkIntLit, c.tupleIndex))
+        else:
+          result = newNodeI(nkDotExpr, n.info)
+          result.add(tupl)
+          result.add(newSymNode(c.field, n.info))
+        break
+  else:
+    if n.kind == nkContinueStmt:
+      localError(n.info, errGenerated,
+                 "'continue' not supported in a 'fields' loop")
+    result = copyNode(n)
+    newSons(result, sonsLen(n))
+    for i in countup(0, sonsLen(n)-1):
+      result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
+
+type
+  TFieldsCtx = object
+    c: PContext
+    m: TMagic
+
+proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
+  case typ.kind
+  of nkSym:
+    var fc: TFieldInstCtx  # either 'tup[i]' or 'field' is valid
+    fc.field = typ.sym
+    fc.replaceByFieldName = c.m == mFieldPairs
+    openScope(c.c)
+    inc c.c.inUnrolledContext
+    let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
+    father.add(semStmt(c.c, body))
+    dec c.c.inUnrolledContext
+    closeScope(c.c)
+  of nkNilLit: discard
+  of nkRecCase:
+    let L = forLoop.len
+    let call = forLoop.sons[L-2]
+    if call.len > 2:
+      localError(forLoop.info, errGenerated, 
+                 "parallel 'fields' iterator does not work for 'case' objects")
+      return
+    # iterate over the selector:
+    semForObjectFields(c, typ[0], forLoop, father)
+    # we need to generate a case statement:
+    var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
+    # generate selector:
+    var access = newNodeI(nkDotExpr, forLoop.info, 2)
+    access.sons[0] = call.sons[1]
+    access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
+    caseStmt.add(semExprWithType(c.c, access))
+    # copy the branches over, but replace the fields with the for loop body:
+    for i in 1 .. <typ.len:
+      var branch = copyTree(typ[i])
+      let L = branch.len
+      branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
+      semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
+      caseStmt.add(branch)
+    father.add(caseStmt)
+  of nkRecList:
+    for t in items(typ): semForObjectFields(c, t, forLoop, father)
+  else:
+    illFormedAstLocal(typ)
+
+proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
+  # so that 'break' etc. work as expected, we produce
+  # a 'while true: stmt; break' loop ...
+  result = newNodeI(nkWhileStmt, n.info, 2)
+  var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
+  if trueSymbol == nil: 
+    localError(n.info, errSystemNeeds, "true")
+    trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
+    trueSymbol.typ = getSysType(tyBool)
+
+  result.sons[0] = newSymNode(trueSymbol, n.info)
+  var stmts = newNodeI(nkStmtList, n.info)
+  result.sons[1] = stmts
+  
+  var length = sonsLen(n)
+  var call = n.sons[length-2]
+  if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
+    localError(n.info, errWrongNumberOfVariables)
+    return result
+  
+  var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
+  if tupleTypeA.kind notin {tyTuple, tyObject}:
+    localError(n.info, errGenerated, "no object or tuple type")
+    return result
+  for i in 1..call.len-1:
+    var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
+    if not sameType(tupleTypeA, tupleTypeB):
+      typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
+  
+  inc(c.p.nestedLoopCounter)
+  if tupleTypeA.kind == tyTuple:
+    var loopBody = n.sons[length-1]
+    for i in 0..sonsLen(tupleTypeA)-1:
+      openScope(c)
+      var fc: TFieldInstCtx
+      fc.tupleType = tupleTypeA
+      fc.tupleIndex = i
+      fc.replaceByFieldName = m == mFieldPairs
+      var body = instFieldLoopBody(fc, loopBody, n)
+      inc c.inUnrolledContext
+      stmts.add(semStmt(c, body))
+      dec c.inUnrolledContext
+      closeScope(c)
+  else:
+    var fc: TFieldsCtx
+    fc.m = m
+    fc.c = c
+    var t = tupleTypeA
+    while t.kind == tyObject:
+      semForObjectFields(fc, t.n, n, stmts)
+      if t.sons[0] == nil: break
+      t = skipTypes(t.sons[0], abstractPtrs)
+  dec(c.p.nestedLoopCounter)
+  # for TR macros this 'while true: ...; break' loop is pretty bad, so
+  # we avoid it now if we can:
+  if containsNode(stmts, {nkBreakStmt}):
+    var b = newNodeI(nkBreakStmt, n.info)
+    b.add(ast.emptyNode)
+    stmts.add(b)
+  else:
+    result = stmts
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
new file mode 100644
index 000000000..da24005c2
--- /dev/null
+++ b/compiler/semfold.nim
@@ -0,0 +1,793 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# this module folds constants; used by semantic checking phase
+# and evaluation phase
+
+import
+  strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
+  nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
+  commands, magicsys, saturate
+
+proc getConstExpr*(m: PSym, n: PNode): PNode
+  # evaluates the constant expression or returns nil if it is no constant
+  # expression
+proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode
+proc leValueConv*(a, b: PNode): bool
+proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
+proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
+proc newStrNodeT*(strVal: string, n: PNode): PNode
+
+# implementation
+
+proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
+  case skipTypes(n.typ, abstractVarRange).kind
+  of tyInt:
+    result = newIntNode(nkIntLit, intVal)
+    result.typ = getIntLitType(result)
+    # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
+    #setIntLitType(result)
+  of tyChar:
+    result = newIntNode(nkCharLit, intVal)
+    result.typ = n.typ
+  else:
+    result = newIntNode(nkIntLit, intVal)
+    result.typ = n.typ
+  result.info = n.info
+
+proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
+  result = newFloatNode(nkFloatLit, floatVal)
+  if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
+    result.typ = getFloatLitType(result)
+  else:
+    result.typ = n.typ
+  result.info = n.info
+
+proc newStrNodeT(strVal: string, n: PNode): PNode =
+  result = newStrNode(nkStrLit, strVal)
+  result.typ = n.typ
+  result.info = n.info
+
+proc ordinalValToString*(a: PNode): string =
+  # because $ has the param ordinal[T], `a` is not necessarily an enum, but an
+  # ordinal
+  var x = getInt(a)
+
+  var t = skipTypes(a.typ, abstractRange)
+  case t.kind
+  of tyChar:
+    result = $chr(int(x) and 0xff)
+  of tyEnum:
+    var n = t.n
+    for i in countup(0, sonsLen(n) - 1):
+      if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
+      var field = n.sons[i].sym
+      if field.position == x:
+        if field.ast == nil:
+          return field.name.s
+        else:
+          return field.ast.strVal
+    internalError(a.info, "no symbol for ordinal value: " & $x)
+  else:
+    result = $x
+
+proc isFloatRange(t: PType): bool {.inline.} =
+  result = t.kind == tyRange and t.sons[0].kind in {tyFloat..tyFloat128}
+
+proc isIntRange(t: PType): bool {.inline.} =
+  result = t.kind == tyRange and t.sons[0].kind in {
+      tyInt..tyInt64, tyUInt8..tyUInt32}
+
+proc pickIntRange(a, b: PType): PType =
+  if isIntRange(a): result = a
+  elif isIntRange(b): result = b
+  else: result = a
+
+proc isIntRangeOrLit(t: PType): bool =
+  result = isIntRange(t) or isIntLit(t)
+
+proc pickMinInt(n: PNode): BiggestInt =
+  if n.kind in {nkIntLit..nkUInt64Lit}:
+    result = n.intVal
+  elif isIntLit(n.typ):
+    result = n.typ.n.intVal
+  elif isIntRange(n.typ):
+    result = firstOrd(n.typ)
+  else:
+    internalError(n.info, "pickMinInt")
+
+proc pickMaxInt(n: PNode): BiggestInt =
+  if n.kind in {nkIntLit..nkUInt64Lit}:
+    result = n.intVal
+  elif isIntLit(n.typ):
+    result = n.typ.n.intVal
+  elif isIntRange(n.typ):
+    result = lastOrd(n.typ)
+  else:
+    internalError(n.info, "pickMaxInt")
+
+proc makeRange(typ: PType, first, last: BiggestInt): PType =
+  let minA = min(first, last)
+  let maxA = max(first, last)
+  let lowerNode = newIntNode(nkIntLit, minA)
+  if typ.kind == tyInt and minA == maxA:
+    result = getIntLitType(lowerNode)
+  elif typ.kind in {tyUint, tyUInt64}:
+    # these are not ordinal types, so you get no subrange type for these:
+    result = typ
+  else:
+    var n = newNode(nkRange)
+    addSon(n, lowerNode)
+    addSon(n, newIntNode(nkIntLit, maxA))
+    result = newType(tyRange, typ.owner)
+    result.n = n
+    addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
+
+proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
+  var n = newNode(nkRange)
+  addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
+  addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
+  result = newType(tyRange, typ.owner)
+  result.n = n
+  addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
+
+proc getIntervalType*(m: TMagic, n: PNode): PType =
+  # Nim requires interval arithmetic for ``range`` types. Lots of tedious
+  # work but the feature is very nice for reducing explicit conversions.
+  const ordIntLit = {nkIntLit..nkUInt64Lit}
+  result = n.typ
+
+  template commutativeOp(opr: expr) {.immediate.} =
+    let a = n.sons[1]
+    let b = n.sons[2]
+    if isIntRangeOrLit(a.typ) and isIntRangeOrLit(b.typ):
+      result = makeRange(pickIntRange(a.typ, b.typ),
+                         opr(pickMinInt(a), pickMinInt(b)),
+                         opr(pickMaxInt(a), pickMaxInt(b)))
+
+  template binaryOp(opr: expr) {.immediate.} =
+    let a = n.sons[1]
+    let b = n.sons[2]
+    if isIntRange(a.typ) and b.kind in {nkIntLit..nkUInt64Lit}:
+      result = makeRange(a.typ,
+                         opr(pickMinInt(a), pickMinInt(b)),
+                         opr(pickMaxInt(a), pickMaxInt(b)))
+
+  case m
+  of mUnaryMinusI, mUnaryMinusI64:
+    let a = n.sons[1].typ
+    if isIntRange(a):
+      # (1..3) * (-1) == (-3.. -1)
+      result = makeRange(a, 0|-|lastOrd(a), 0|-|firstOrd(a))
+  of mUnaryMinusF64:
+    let a = n.sons[1].typ
+    if isFloatRange(a):
+      result = makeRangeF(a, -getFloat(a.n.sons[1]),
+                             -getFloat(a.n.sons[0]))
+  of mAbsF64:
+    let a = n.sons[1].typ
+    if isFloatRange(a):
+      # abs(-5.. 1) == (1..5)
+      if a.n[0].floatVal <= 0.0:
+        result = makeRangeF(a, 0.0, abs(getFloat(a.n.sons[0])))
+      else:
+        result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
+                               abs(getFloat(a.n.sons[0])))
+  of mAbsI, mAbsI64:
+    let a = n.sons[1].typ
+    if isIntRange(a):
+      if a.n[0].intVal <= 0:
+        result = makeRange(a, 0, `|abs|`(getInt(a.n.sons[0])))
+      else:
+        result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
+                              `|abs|`(getInt(a.n.sons[0])))
+  of mSucc:
+    let a = n.sons[1].typ
+    let b = n.sons[2].typ
+    if isIntRange(a) and isIntLit(b):
+      # (-5.. 1) + 6 == (-5 + 6)..(-1 + 6)
+      result = makeRange(a, pickMinInt(n.sons[1]) |+| pickMinInt(n.sons[2]),
+                            pickMaxInt(n.sons[1]) |+| pickMaxInt(n.sons[2]))
+  of mPred:
+    let a = n.sons[1].typ
+    let b = n.sons[2].typ
+    if isIntRange(a) and isIntLit(b):
+      result = makeRange(a, pickMinInt(n.sons[1]) |-| pickMinInt(n.sons[2]),
+                            pickMaxInt(n.sons[1]) |-| pickMaxInt(n.sons[2]))
+  of mAddI, mAddI64, mAddU:
+    commutativeOp(`|+|`)
+  of mMulI, mMulI64, mMulU:
+    commutativeOp(`|*|`)
+  of mSubI, mSubI64, mSubU:
+    binaryOp(`|-|`)
+  of mBitandI, mBitandI64:
+    # since uint64 is still not even valid for 'range' (since it's no ordinal
+    # yet), we exclude it from the list (see bug #1638) for now:
+    var a = n.sons[1]
+    var b = n.sons[2]
+    # symmetrical:
+    if b.kind notin ordIntLit: swap(a, b)
+    if b.kind in ordIntLit:
+      let x = b.intVal|+|1
+      if (x and -x) == x and x >= 0:
+        result = makeRange(a.typ, 0, b.intVal)
+  of mModU:
+    let a = n.sons[1]
+    let b = n.sons[2]
+    if a.kind in ordIntLit:
+      if b.intVal >= 0:
+        result = makeRange(a.typ, 0, b.intVal-1)
+      else:
+        result = makeRange(a.typ, b.intVal+1, 0)
+  of mModI, mModI64:
+    # so ... if you ever wondered about modulo's signedness; this defines it:
+    let a = n.sons[1]
+    let b = n.sons[2]
+    if b.kind in {nkIntLit..nkUInt64Lit}:
+      if b.intVal >= 0:
+        result = makeRange(a.typ, -(b.intVal-1), b.intVal-1)
+      else:
+        result = makeRange(a.typ, b.intVal+1, -(b.intVal+1))
+  of mDivI, mDivI64, mDivU:
+    binaryOp(`|div|`)
+  of mMinI:
+    commutativeOp(min)
+  of mMaxI:
+    commutativeOp(max)
+  else: discard
+
+discard """
+  mShlI, mShlI64,
+  mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
+"""
+
+proc evalIs(n, a: PNode): PNode =
+  # XXX: This should use the standard isOpImpl
+  internalAssert a.kind == nkSym and a.sym.kind == skType
+  internalAssert n.sonsLen == 3 and
+    n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
+
+  let t1 = a.sym.typ
+
+  if n[2].kind in {nkStrLit..nkTripleStrLit}:
+    case n[2].strVal.normalize
+    of "closure":
+      let t = skipTypes(t1, abstractRange)
+      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
+                                        t.callConv == ccClosure and
+                                        tfIterator notin t.flags))
+    of "iterator":
+      let t = skipTypes(t1, abstractRange)
+      result = newIntNode(nkIntLit, ord(t.kind == tyProc and
+                                        t.callConv == ccClosure and
+                                        tfIterator in t.flags))
+    else: discard
+  else:
+    # XXX semexprs.isOpImpl is slightly different and requires a context. yay.
+    let t2 = n[2].typ
+    var match = sameType(t1, t2)
+    result = newIntNode(nkIntLit, ord(match))
+  result.typ = n.typ
+
+proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
+  # b and c may be nil
+  result = nil
+  case m
+  of mOrd: result = newIntNodeT(getOrdValue(a), n)
+  of mChr: result = newIntNodeT(getInt(a), n)
+  of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n)
+  of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n)
+  of mNot: result = newIntNodeT(1 - getInt(a), n)
+  of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
+  of mBitnotI, mBitnotI64: result = newIntNodeT(not getInt(a), n)
+  of mLengthStr, mXLenStr:
+    if a.kind == nkNilLit: result = newIntNodeT(0, n)
+    else: result = newIntNodeT(len(getStr(a)), n)
+  of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
+  of mLengthSeq, mLengthOpenArray, mXLenSeq:
+    if a.kind == nkNilLit: result = newIntNodeT(0, n)
+    else: result = newIntNodeT(sonsLen(a), n) # BUGFIX
+  of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
+  of mToFloat, mToBiggestFloat:
+    result = newFloatNodeT(toFloat(int(getInt(a))), n)
+  of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
+  of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
+  of mAbsI, mAbsI64:
+    if getInt(a) >= 0: result = a
+    else: result = newIntNodeT(- getInt(a), n)
+  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
+    # byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
+    result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
+  of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
+  of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
+  of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
+  of mUnaryLt: result = newIntNodeT(getOrdValue(a) - 1, n)
+  of mSucc: result = newIntNodeT(getOrdValue(a) + getInt(b), n)
+  of mPred: result = newIntNodeT(getOrdValue(a) - getInt(b), n)
+  of mAddI, mAddI64: result = newIntNodeT(getInt(a) + getInt(b), n)
+  of mSubI, mSubI64: result = newIntNodeT(getInt(a) - getInt(b), n)
+  of mMulI, mMulI64: result = newIntNodeT(getInt(a) * getInt(b), n)
+  of mMinI:
+    if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
+    else: result = newIntNodeT(getInt(a), n)
+  of mMaxI:
+    if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
+    else: result = newIntNodeT(getInt(b), n)
+  of mShlI, mShlI64:
+    case skipTypes(n.typ, abstractRange).kind
+    of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
+    of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
+    of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
+    of tyInt64, tyInt, tyUInt..tyUInt64:
+      result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
+    else: internalError(n.info, "constant folding for shl")
+  of mShrI, mShrI64:
+    case skipTypes(n.typ, abstractRange).kind
+    of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
+    of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
+    of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
+    of tyInt64, tyInt, tyUInt..tyUInt64:
+      result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
+    else: internalError(n.info, "constant folding for shr")
+  of mDivI, mDivI64:
+    let y = getInt(b)
+    if y != 0:
+      result = newIntNodeT(getInt(a) div y, n)
+  of mModI, mModI64:
+    let y = getInt(b)
+    if y != 0:
+      result = newIntNodeT(getInt(a) mod y, n)
+  of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
+  of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
+  of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
+  of mDivF64:
+    if getFloat(b) == 0.0:
+      if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
+      else: result = newFloatNodeT(Inf, n)
+    else:
+      result = newFloatNodeT(getFloat(a) / getFloat(b), n)
+  of mMaxF64:
+    if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
+    else: result = newFloatNodeT(getFloat(b), n)
+  of mMinF64:
+    if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
+    else: result = newFloatNodeT(getFloat(a), n)
+  of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
+  of mLtI, mLtI64, mLtB, mLtEnum, mLtCh:
+    result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
+  of mLeI, mLeI64, mLeB, mLeEnum, mLeCh:
+    result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
+  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
+    result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
+  of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
+  of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
+  of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
+  of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
+  of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
+  of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
+  of mLtU, mLtU64:
+    result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
+  of mLeU, mLeU64:
+    result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
+  of mBitandI, mBitandI64, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
+  of mBitorI, mBitorI64, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
+  of mBitxorI, mBitxorI64, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
+  of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
+  of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
+  of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
+  of mModU:
+    let y = getInt(b)
+    if y != 0:
+      result = newIntNodeT(`%%`(getInt(a), y), n)
+  of mDivU:
+    let y = getInt(b)
+    if y != 0:
+      result = newIntNodeT(`/%`(getInt(a), y), n)
+  of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
+  of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
+  of mLtSet:
+    result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
+  of mMulSet:
+    result = nimsets.intersectSets(a, b)
+    result.info = n.info
+  of mPlusSet:
+    result = nimsets.unionSets(a, b)
+    result.info = n.info
+  of mMinusSet:
+    result = nimsets.diffSets(a, b)
+    result.info = n.info
+  of mSymDiffSet:
+    result = nimsets.symdiffSets(a, b)
+    result.info = n.info
+  of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
+  of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
+  of mRepr:
+    # BUGFIX: we cannot eval mRepr here for reasons that I forgot.
+    discard
+  of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
+  of mBoolToStr:
+    if getOrdValue(a) == 0: result = newStrNodeT("false", n)
+    else: result = newStrNodeT("true", n)
+  of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
+  of mCopyStrLast:
+    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
+                                           int(getOrdValue(c))), n)
+  of mFloatToStr: result = newStrNodeT($getFloat(a), n)
+  of mCStrToStr, mCharToStr: result = newStrNodeT(getStrOrChar(a), n)
+  of mStrToStr: result = a
+  of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
+  of mArrToSeq:
+    result = copyTree(a)
+    result.typ = n.typ
+  of mCompileOption:
+    result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
+  of mCompileOptionArg:
+    result = newIntNodeT(ord(
+      testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
+  of mNewString, mNewStringOfCap,
+     mExit, mInc, ast.mDec, mEcho, mSwap, mAppendStrCh,
+     mAppendStrStr, mAppendSeqElem, mSetLengthStr, mSetLengthSeq,
+     mParseExprToAst, mParseStmtToAst, mExpandToAst, mTypeTrait, mDotDot,
+     mNLen..mNError, mEqRef, mSlurp, mStaticExec, mNGenSym, mSpawn,
+     mParallel, mPlugin:
+    discard
+  else: internalError(a.info, "evalOp(" & $m & ')')
+
+proc getConstIfExpr(c: PSym, n: PNode): PNode =
+  result = nil
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    if it.len == 2:
+      var e = getConstExpr(c, it.sons[0])
+      if e == nil: return nil
+      if getOrdValue(e) != 0:
+        if result == nil:
+          result = getConstExpr(c, it.sons[1])
+          if result == nil: return
+    elif it.len == 1:
+      if result == nil: result = getConstExpr(c, it.sons[0])
+    else: internalError(it.info, "getConstIfExpr()")
+
+proc partialAndExpr(c: PSym, n: PNode): PNode =
+  # partial evaluation
+  result = n
+  var a = getConstExpr(c, n.sons[1])
+  var b = getConstExpr(c, n.sons[2])
+  if a != nil:
+    if getInt(a) == 0: result = a
+    elif b != nil: result = b
+    else: result = n.sons[2]
+  elif b != nil:
+    if getInt(b) == 0: result = b
+    else: result = n.sons[1]
+
+proc partialOrExpr(c: PSym, n: PNode): PNode =
+  # partial evaluation
+  result = n
+  var a = getConstExpr(c, n.sons[1])
+  var b = getConstExpr(c, n.sons[2])
+  if a != nil:
+    if getInt(a) != 0: result = a
+    elif b != nil: result = b
+    else: result = n.sons[2]
+  elif b != nil:
+    if getInt(b) != 0: result = b
+    else: result = n.sons[1]
+
+proc leValueConv(a, b: PNode): bool =
+  result = false
+  case a.kind
+  of nkCharLit..nkUInt64Lit:
+    case b.kind
+    of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
+    of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal)
+    else: internalError(a.info, "leValueConv")
+  of nkFloatLit..nkFloat128Lit:
+    case b.kind
+    of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
+    of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
+    else: internalError(a.info, "leValueConv")
+  else: internalError(a.info, "leValueConv")
+
+proc magicCall(m: PSym, n: PNode): PNode =
+  if sonsLen(n) <= 1: return
+
+  var s = n.sons[0].sym
+  var a = getConstExpr(m, n.sons[1])
+  var b, c: PNode
+  if a == nil: return
+  if sonsLen(n) > 2:
+    b = getConstExpr(m, n.sons[2])
+    if b == nil: return
+    if sonsLen(n) > 3:
+      c = getConstExpr(m, n.sons[3])
+      if c == nil: return
+  result = evalOp(s.magic, n, a, b, c)
+
+proc getAppType(n: PNode): PNode =
+  if gGlobalOptions.contains(optGenDynLib):
+    result = newStrNodeT("lib", n)
+  elif gGlobalOptions.contains(optGenStaticLib):
+    result = newStrNodeT("staticlib", n)
+  elif gGlobalOptions.contains(optGenGuiApp):
+    result = newStrNodeT("gui", n)
+  else:
+    result = newStrNodeT("console", n)
+
+proc rangeCheck(n: PNode, value: BiggestInt) =
+  if value < firstOrd(n.typ) or value > lastOrd(n.typ):
+    localError(n.info, errGenerated, "cannot convert " & $value &
+                                     " to " & typeToString(n.typ))
+
+proc foldConv*(n, a: PNode; check = false): PNode =
+  # XXX range checks?
+  case skipTypes(n.typ, abstractRange).kind
+  of tyInt..tyInt64, tyUInt..tyUInt64:
+    case skipTypes(a.typ, abstractRange).kind
+    of tyFloat..tyFloat64:
+      result = newIntNodeT(int(getFloat(a)), n)
+    of tyChar: result = newIntNodeT(getOrdValue(a), n)
+    else:
+      result = a
+      result.typ = n.typ
+    if check: rangeCheck(n, result.intVal)
+  of tyFloat..tyFloat64:
+    case skipTypes(a.typ, abstractRange).kind
+    of tyInt..tyInt64, tyEnum, tyBool, tyChar:
+      result = newFloatNodeT(toFloat(int(getOrdValue(a))), n)
+    else:
+      result = a
+      result.typ = n.typ
+  of tyOpenArray, tyVarargs, tyProc:
+    discard
+  else:
+    result = a
+    result.typ = n.typ
+
+proc getArrayConstr(m: PSym, n: PNode): PNode =
+  if n.kind == nkBracket:
+    result = n
+  else:
+    result = getConstExpr(m, n)
+    if result == nil: result = n
+
+proc foldArrayAccess(m: PSym, n: PNode): PNode =
+  var x = getConstExpr(m, n.sons[0])
+  if x == nil or x.typ.skipTypes({tyGenericInst}).kind == tyTypeDesc: return
+
+  var y = getConstExpr(m, n.sons[1])
+  if y == nil: return
+
+  var idx = getOrdValue(y)
+  case x.kind
+  of nkPar:
+    if idx >= 0 and idx < sonsLen(x):
+      result = x.sons[int(idx)]
+      if result.kind == nkExprColonExpr: result = result.sons[1]
+    else:
+      localError(n.info, errIndexOutOfBounds)
+  of nkBracket:
+    idx = idx - x.typ.firstOrd
+    if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
+    else: localError(n.info, errIndexOutOfBounds)
+  of nkStrLit..nkTripleStrLit:
+    result = newNodeIT(nkCharLit, x.info, n.typ)
+    if idx >= 0 and idx < len(x.strVal):
+      result.intVal = ord(x.strVal[int(idx)])
+    elif idx == len(x.strVal):
+      discard
+    else:
+      localError(n.info, errIndexOutOfBounds)
+  else: discard
+
+proc foldFieldAccess(m: PSym, n: PNode): PNode =
+  # a real field access; proc calls have already been transformed
+  var x = getConstExpr(m, n.sons[0])
+  if x == nil or x.kind notin {nkObjConstr, nkPar}: return
+
+  var field = n.sons[1].sym
+  for i in countup(ord(x.kind == nkObjConstr), sonsLen(x) - 1):
+    var it = x.sons[i]
+    if it.kind != nkExprColonExpr:
+      # lookup per index:
+      result = x.sons[field.position]
+      if result.kind == nkExprColonExpr: result = result.sons[1]
+      return
+    if it.sons[0].sym.name.id == field.name.id:
+      result = x.sons[i].sons[1]
+      return
+  localError(n.info, errFieldXNotFound, field.name.s)
+
+proc foldConStrStr(m: PSym, n: PNode): PNode =
+  result = newNodeIT(nkStrLit, n.info, n.typ)
+  result.strVal = ""
+  for i in countup(1, sonsLen(n) - 1):
+    let a = getConstExpr(m, n.sons[i])
+    if a == nil: return nil
+    result.strVal.add(getStrOrChar(a))
+
+proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
+  result = newSymNode(s, info)
+  result.typ = newType(tyTypeDesc, s.owner)
+  result.typ.addSonSkipIntLit(s.typ)
+
+proc getConstExpr(m: PSym, n: PNode): PNode =
+  result = nil
+  case n.kind
+  of nkSym:
+    var s = n.sym
+    case s.kind
+    of skEnumField:
+      result = newIntNodeT(s.position, n)
+    of skConst:
+      case s.magic
+      of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
+      of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
+      of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
+      of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
+      of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
+      of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
+      of mAppType: result = getAppType(n)
+      of mNaN: result = newFloatNodeT(NaN, n)
+      of mInf: result = newFloatNodeT(Inf, n)
+      of mNegInf: result = newFloatNodeT(NegInf, n)
+      else:
+        if sfFakeConst notin s.flags: result = copyTree(s.ast)
+    of {skProc, skMethod}:
+      result = n
+    of skType:
+      result = newSymNodeTypeDesc(s, n.info)
+    of skGenericParam:
+      if s.typ.kind == tyStatic:
+        if s.typ.n != nil:
+          result = s.typ.n
+          result.typ = s.typ.sons[0]
+      else:
+        result = newSymNodeTypeDesc(s, n.info)
+    else: discard
+  of nkCharLit..nkNilLit:
+    result = copyNode(n)
+  of nkIfExpr:
+    result = getConstIfExpr(m, n)
+  of nkCallKinds:
+    if n.sons[0].kind != nkSym: return
+    var s = n.sons[0].sym
+    if s.kind != skProc: return
+    try:
+      case s.magic
+      of mNone:
+        # If it has no sideEffect, it should be evaluated. But not here.
+        return
+      of mSizeOf:
+        var a = n.sons[1]
+        if computeSize(a.typ) < 0:
+          localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
+                     "sizeof")
+          result = nil
+        elif skipTypes(a.typ, typedescInst).kind in
+             IntegralTypes+NilableTypes+{tySet}:
+          #{tyArray,tyObject,tyTuple}:
+          result = newIntNodeT(getSize(a.typ), n)
+        else:
+          result = nil
+          # XXX: size computation for complex types is still wrong
+      of mLow:
+        result = newIntNodeT(firstOrd(n.sons[1].typ), n)
+      of mHigh:
+        if skipTypes(n.sons[1].typ, abstractVar).kind notin
+            {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
+          result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
+        else:
+          var a = getArrayConstr(m, n.sons[1])
+          if a.kind == nkBracket:
+            # we can optimize it away:
+            result = newIntNodeT(sonsLen(a)-1, n)
+      of mLengthOpenArray:
+        var a = getArrayConstr(m, n.sons[1])
+        if a.kind == nkBracket:
+          # we can optimize it away! This fixes the bug ``len(134)``.
+          result = newIntNodeT(sonsLen(a), n)
+        else:
+          result = magicCall(m, n)
+      of mLengthArray:
+        # It doesn't matter if the argument is const or not for mLengthArray.
+        # This fixes bug #544.
+        result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
+      of mAstToStr:
+        result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
+      of mConStrStr:
+        result = foldConStrStr(m, n)
+      of mIs:
+        let a = getConstExpr(m, n[1])
+        if a != nil and a.kind == nkSym and a.sym.kind == skType:
+          result = evalIs(n, a)
+      else:
+        result = magicCall(m, n)
+    except OverflowError:
+      localError(n.info, errOverOrUnderflow)
+    except DivByZeroError:
+      localError(n.info, errConstantDivisionByZero)
+  of nkAddr:
+    var a = getConstExpr(m, n.sons[0])
+    if a != nil:
+      result = n
+      n.sons[0] = a
+  of nkBracket:
+    result = copyTree(n)
+    for i in countup(0, sonsLen(n) - 1):
+      var a = getConstExpr(m, n.sons[i])
+      if a == nil: return nil
+      result.sons[i] = a
+    incl(result.flags, nfAllConst)
+  of nkRange:
+    var a = getConstExpr(m, n.sons[0])
+    if a == nil: return
+    var b = getConstExpr(m, n.sons[1])
+    if b == nil: return
+    result = copyNode(n)
+    addSon(result, a)
+    addSon(result, b)
+  of nkCurly:
+    result = copyTree(n)
+    for i in countup(0, sonsLen(n) - 1):
+      var a = getConstExpr(m, n.sons[i])
+      if a == nil: return nil
+      result.sons[i] = a
+    incl(result.flags, nfAllConst)
+  of nkObjConstr:
+    result = copyTree(n)
+    for i in countup(1, sonsLen(n) - 1):
+      var a = getConstExpr(m, n.sons[i].sons[1])
+      if a == nil: return nil
+      result.sons[i].sons[1] = a
+    incl(result.flags, nfAllConst)
+  of nkPar:
+    # tuple constructor
+    result = copyTree(n)
+    if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
+      for i in countup(0, sonsLen(n) - 1):
+        var a = getConstExpr(m, n.sons[i].sons[1])
+        if a == nil: return nil
+        result.sons[i].sons[1] = a
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        var a = getConstExpr(m, n.sons[i])
+        if a == nil: return nil
+        result.sons[i] = a
+    incl(result.flags, nfAllConst)
+  of nkChckRangeF, nkChckRange64, nkChckRange:
+    var a = getConstExpr(m, n.sons[0])
+    if a == nil: return
+    if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
+      result = a              # a <= x and x <= b
+      result.typ = n.typ
+    else:
+      localError(n.info, errGenerated, `%`(
+          msgKindToString(errIllegalConvFromXtoY),
+          [typeToString(n.sons[0].typ), typeToString(n.typ)]))
+  of nkStringToCString, nkCStringToString:
+    var a = getConstExpr(m, n.sons[0])
+    if a == nil: return
+    result = a
+    result.typ = n.typ
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    var a = getConstExpr(m, n.sons[1])
+    if a == nil: return
+    result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
+  of nkCast:
+    var a = getConstExpr(m, n.sons[1])
+    if a == nil: return
+    if n.typ.kind in NilableTypes:
+      # we allow compile-time 'cast' for pointer types:
+      result = a
+      result.typ = n.typ
+  of nkBracketExpr: result = foldArrayAccess(m, n)
+  of nkDotExpr: result = foldFieldAccess(m, n)
+  else:
+    discard
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
new file mode 100644
index 000000000..db910600b
--- /dev/null
+++ b/compiler/semgnrc.nim
@@ -0,0 +1,404 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This implements the first pass over the generic body; it resolves some
+# symbols. Thus for generics there is a two-phase symbol lookup just like
+# in C++.
+# A problem is that it cannot be detected if the symbol is introduced
+# as in ``var x = ...`` or used because macros/templates can hide this!
+# So we have to eval templates/macros right here so that symbol
+# lookup can be accurate.
+
+# included from sem.nim
+
+proc getIdentNode(n: PNode): PNode =
+  case n.kind
+  of nkPostfix: result = getIdentNode(n.sons[1])
+  of nkPragmaExpr: result = getIdentNode(n.sons[0])
+  of nkIdent, nkAccQuoted, nkSym: result = n
+  else:
+    illFormedAst(n)
+    result = n
+
+type
+  GenericCtx = object
+    toMixin: IntSet
+    cursorInBody: bool # only for nimsuggest
+
+type
+  TSemGenericFlag = enum
+    withinBind, withinTypeDesc, withinMixin
+  TSemGenericFlags = set[TSemGenericFlag]
+
+proc semGenericStmt(c: PContext, n: PNode,
+                    flags: TSemGenericFlags, ctx: var GenericCtx): PNode
+
+proc semGenericStmtScope(c: PContext, n: PNode, 
+                         flags: TSemGenericFlags,
+                         ctx: var GenericCtx): PNode = 
+  openScope(c)
+  result = semGenericStmt(c, n, flags, ctx)
+  closeScope(c)
+
+template macroToExpand(s: expr): expr =
+  s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
+
+proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
+                          ctx: var GenericCtx): PNode =
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+  incl(s.flags, sfUsed)
+  case s.kind
+  of skUnknown:
+    # Introduced in this pass! Leave it as an identifier.
+    result = n
+  of skProc, skMethod, skIterators, skConverter:
+    result = symChoice(c, n, s, scOpen)
+  of skTemplate:
+    if macroToExpand(s):
+      styleCheckUse(n.info, s)
+      result = semTemplateExpr(c, n, s, {efNoSemCheck})
+      result = semGenericStmt(c, result, {}, ctx)
+    else:
+      result = symChoice(c, n, s, scOpen)
+  of skMacro:
+    if macroToExpand(s):
+      styleCheckUse(n.info, s)
+      result = semMacroExpr(c, n, n, s, {efNoSemCheck})
+      result = semGenericStmt(c, result, {}, ctx)
+    else:
+      result = symChoice(c, n, s, scOpen)
+  of skGenericParam: 
+    if s.typ != nil and s.typ.kind == tyStatic:
+      if s.typ.n != nil:
+        result = s.typ.n
+      else:
+        result = n
+    else:
+      result = newSymNodeTypeDesc(s, n.info)
+    styleCheckUse(n.info, s)
+  of skParam:
+    result = n
+    styleCheckUse(n.info, s)
+  of skType: 
+    if (s.typ != nil) and
+       (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
+      result = newSymNodeTypeDesc(s, n.info)
+    else: 
+      result = n
+    styleCheckUse(n.info, s)
+  else:
+    result = newSymNode(s, n.info)
+    styleCheckUse(n.info, s)
+
+proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
+            ctx: var GenericCtx): PNode =
+  result = n
+  let ident = considerQuotedIdent(n)
+  var s = searchInScopes(c, ident).skipAlias(n)
+  if s == nil:
+    if ident.id notin ctx.toMixin and withinMixin notin flags:
+      localError(n.info, errUndeclaredIdentifier, ident.s)
+  else:
+    if withinBind in flags:
+      result = symChoice(c, n, s, scClosed)
+    elif s.name.id in ctx.toMixin:
+      result = symChoice(c, n, s, scForceOpen)
+    else:
+      result = semGenericStmtSymbol(c, n, s, ctx)
+  # else: leave as nkIdent
+
+proc newDot(n, b: PNode): PNode =
+  result = newNodeI(nkDotExpr, n.info)
+  result.add(n.sons[0])
+  result.add(b)
+
+proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, 
+                 ctx: var GenericCtx; isMacro: var bool): PNode =
+  assert n.kind == nkDotExpr
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+
+  let luf = if withinMixin notin flags: {checkUndeclared} else: {}
+  
+  var s = qualifiedLookUp(c, n, luf)
+  if s != nil:
+    result = semGenericStmtSymbol(c, n, s, ctx)
+  else:
+    n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
+    result = n
+    let n = n[1]
+    let ident = considerQuotedIdent(n)
+    var s = searchInScopes(c, ident).skipAlias(n)
+    if s != nil and s.kind in routineKinds:
+      isMacro = s.kind in {skTemplate, skMacro}
+      if withinBind in flags:
+        result = newDot(result, symChoice(c, n, s, scClosed))
+      elif s.name.id in ctx.toMixin:
+        result = newDot(result, symChoice(c, n, s, scForceOpen))
+      else:
+        let sym = semGenericStmtSymbol(c, n, s, ctx)
+        if sym.kind == nkSym:
+          result = newDot(result, symChoice(c, n, s, scForceOpen))
+        else:
+          result = newDot(result, sym)
+
+proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
+  let s = newSymS(skUnknown, getIdentNode(n), c)
+  addPrelimDecl(c, s)
+  styleCheckDef(n.info, s, kind)
+
+proc semGenericStmt(c: PContext, n: PNode, 
+                    flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
+  result = n
+  #if gCmd == cmdIdeTools: suggestStmt(c, n)
+  semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
+
+  case n.kind
+  of nkIdent, nkAccQuoted:
+    result = lookup(c, n, flags, ctx)
+  of nkDotExpr:
+    #let luf = if withinMixin notin flags: {checkUndeclared} else: {}
+    #var s = qualifiedLookUp(c, n, luf)
+    #if s != nil: result = semGenericStmtSymbol(c, n, s)
+    # XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
+    var dummy: bool
+    result = fuzzyLookup(c, n, flags, ctx, dummy)
+  of nkEmpty, nkSym..nkNilLit:
+    # see tests/compile/tgensymgeneric.nim:
+    # We need to open the gensym'ed symbol again so that the instantiation
+    # creates a fresh copy; but this is wrong the very first reason for gensym
+    # is that scope rules cannot be used! So simply removing 'sfGenSym' does
+    # not work. Copying the symbol does not work either because we're already
+    # the owner of the symbol! What we need to do is to copy the symbol
+    # in the generic instantiation process...
+    discard
+  of nkBind:
+    result = semGenericStmt(c, n.sons[0], flags+{withinBind}, ctx)
+  of nkMixinStmt:
+    result = semMixinStmt(c, n, ctx.toMixin)
+  of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit: 
+    # check if it is an expression macro:
+    checkMinSonsLen(n, 1)
+    let fn = n.sons[0]
+    var s = qualifiedLookUp(c, fn, {})
+    if s == nil and withinMixin notin flags and
+        fn.kind in {nkIdent, nkAccQuoted} and 
+        considerQuotedIdent(fn).id notin ctx.toMixin:
+      localError(n.info, errUndeclaredIdentifier, fn.renderTree)
+    
+    var first = 0
+    var mixinContext = false
+    if s != nil:
+      incl(s.flags, sfUsed)
+      mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
+      let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
+      case s.kind
+      of skMacro:
+        if macroToExpand(s):
+          styleCheckUse(fn.info, s)
+          result = semMacroExpr(c, n, n, s, {efNoSemCheck})
+          result = semGenericStmt(c, result, {}, ctx)
+        else:
+          n.sons[0] = symChoice(c, fn, s, scOption)
+          result = n
+        mixinContext = true
+      of skTemplate:
+        if macroToExpand(s):
+          styleCheckUse(fn.info, s)
+          result = semTemplateExpr(c, n, s, {efNoSemCheck})
+          result = semGenericStmt(c, result, {}, ctx)
+        else:
+          n.sons[0] = symChoice(c, fn, s, scOption)
+          result = n
+        # BUGFIX: we must not return here, we need to do first phase of
+        # symbol lookup. Also since templates and macros can do scope injections
+        # we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
+        # the famous "undeclared identifier: it" bug:
+        mixinContext = true
+      of skUnknown, skParam: 
+        # Leave it as an identifier.
+        discard
+      of skProc, skMethod, skIterators, skConverter:
+        result.sons[0] = symChoice(c, fn, s, scOption)
+        first = 1
+      of skGenericParam:
+        result.sons[0] = newSymNodeTypeDesc(s, fn.info)
+        styleCheckUse(fn.info, s)
+        first = 1
+      of skType: 
+        # bad hack for generics:
+        if (s.typ != nil) and (s.typ.kind != tyGenericParam): 
+          result.sons[0] = newSymNodeTypeDesc(s, fn.info)
+          styleCheckUse(fn.info, s)
+          first = 1
+      else:
+        result.sons[0] = newSymNode(s, fn.info)
+        styleCheckUse(fn.info, s)
+        first = 1
+    elif fn.kind == nkDotExpr:
+      result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
+      first = 1
+    # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
+    # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which 
+    # is not exported and yet the generic 'threadProcWrapper' works correctly.
+    let flags = if mixinContext: flags+{withinMixin} else: flags
+    for i in countup(first, sonsLen(result) - 1):
+      result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
+  of nkIfStmt: 
+    for i in countup(0, sonsLen(n)-1): 
+      n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
+  of nkWhenStmt:
+    for i in countup(0, sonsLen(n)-1):
+      n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
+  of nkWhileStmt: 
+    openScope(c)
+    for i in countup(0, sonsLen(n)-1): 
+      n.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
+    closeScope(c)
+  of nkCaseStmt: 
+    openScope(c)
+    n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
+    for i in countup(1, sonsLen(n)-1): 
+      var a = n.sons[i]
+      checkMinSonsLen(a, 1)
+      var L = sonsLen(a)
+      for j in countup(0, L-2): 
+        a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
+      a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
+    closeScope(c)
+  of nkForStmt, nkParForStmt: 
+    var L = sonsLen(n)
+    openScope(c)
+    n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
+    for i in countup(0, L - 3):
+      addTempDecl(c, n.sons[i], skForVar)
+    n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
+    closeScope(c)
+  of nkBlockStmt, nkBlockExpr, nkBlockType: 
+    checkSonsLen(n, 2)
+    openScope(c)
+    if n.sons[0].kind != nkEmpty: 
+      addTempDecl(c, n.sons[0], skLabel)
+    n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
+    closeScope(c)
+  of nkTryStmt: 
+    checkMinSonsLen(n, 2)
+    n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
+    for i in countup(1, sonsLen(n)-1): 
+      var a = n.sons[i]
+      checkMinSonsLen(a, 1)
+      var L = sonsLen(a)
+      for j in countup(0, L-2): 
+        a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
+      a.sons[L-1] = semGenericStmtScope(c, a.sons[L-1], flags, ctx)
+  of nkVarSection, nkLetSection: 
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
+      checkMinSonsLen(a, 3)
+      var L = sonsLen(a)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
+      a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
+      for j in countup(0, L-3):
+        addTempDecl(c, getIdentNode(a.sons[j]), skVar)
+  of nkGenericParams: 
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if (a.kind != nkIdentDefs): illFormedAst(a)
+      checkMinSonsLen(a, 3)
+      var L = sonsLen(a)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) 
+      # do not perform symbol lookup for default expressions 
+      for j in countup(0, L-3): 
+        addTempDecl(c, getIdentNode(a.sons[j]), skType)
+  of nkConstSection: 
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkConstDef): illFormedAst(a)
+      checkSonsLen(a, 3)
+      addTempDecl(c, getIdentNode(a.sons[0]), skConst)
+      a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
+      a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
+  of nkTypeSection:
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkTypeDef): illFormedAst(a)
+      checkSonsLen(a, 3)
+      addTempDecl(c, getIdentNode(a.sons[0]), skType)
+    for i in countup(0, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue 
+      if (a.kind != nkTypeDef): illFormedAst(a)
+      checkSonsLen(a, 3)
+      if a.sons[1].kind != nkEmpty: 
+        openScope(c)
+        a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
+        a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
+        closeScope(c)
+      else: 
+        a.sons[2] = semGenericStmt(c, a.sons[2], flags+{withinTypeDesc}, ctx)
+  of nkEnumTy: 
+    if n.sonsLen > 0:
+      if n.sons[0].kind != nkEmpty: 
+        n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
+      for i in countup(1, sonsLen(n) - 1): 
+        var a: PNode
+        case n.sons[i].kind
+        of nkEnumFieldDef: a = n.sons[i].sons[0]
+        of nkIdent: a = n.sons[i]
+        else: illFormedAst(n)
+        addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
+  of nkObjectTy, nkTupleTy, nkTupleClassTy:
+    discard
+  of nkFormalParams:
+    checkMinSonsLen(n, 1)
+    if n.sons[0].kind != nkEmpty: 
+      n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
+    for i in countup(1, sonsLen(n) - 1): 
+      var a = n.sons[i]
+      if (a.kind != nkIdentDefs): illFormedAst(a)
+      checkMinSonsLen(a, 3)
+      var L = sonsLen(a)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
+      a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
+      for j in countup(0, L-3): 
+        addTempDecl(c, getIdentNode(a.sons[j]), skParam)
+  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
+     nkIteratorDef, nkLambdaKinds: 
+    checkSonsLen(n, bodyPos + 1)
+    if n.sons[namePos].kind != nkEmpty:
+      addTempDecl(c, getIdentNode(n.sons[0]), skProc)
+    openScope(c)
+    n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], 
+                                              flags, ctx)
+    if n.sons[paramsPos].kind != nkEmpty: 
+      if n.sons[paramsPos].sons[0].kind != nkEmpty:
+        addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
+      n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
+    n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
+    var body: PNode
+    if n.sons[namePos].kind == nkSym: body = n.sons[namePos].sym.getBody
+    else: body = n.sons[bodyPos]
+    n.sons[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
+    closeScope(c)
+  of nkPragma, nkPragmaExpr: discard
+  of nkExprColonExpr, nkExprEqExpr:
+    checkMinSonsLen(n, 2)
+    result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
+  else:
+    for i in countup(0, sonsLen(n) - 1): 
+      result.sons[i] = semGenericStmt(c, n.sons[i], flags, ctx)
+
+proc semGenericStmt(c: PContext, n: PNode): PNode =
+  var ctx: GenericCtx
+  ctx.toMixin = initIntset()
+  result = semGenericStmt(c, n, {}, ctx)
+  semIdeForTemplateOrGeneric(c, result, ctx.cursorInBody)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
new file mode 100644
index 000000000..b2aef63a8
--- /dev/null
+++ b/compiler/seminst.nim
@@ -0,0 +1,270 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the instantiation of generic procs.
+# included from sem.nim
+
+proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
+                                 entry: var TInstantiation) =
+  if n.kind != nkGenericParams:
+    internalError(n.info, "instantiateGenericParamList; no generic params")
+  newSeq(entry.concreteTypes, n.len)
+  for i, a in n.pairs:
+    if a.kind != nkSym:
+      internalError(a.info, "instantiateGenericParamList; no symbol")
+    var q = a.sym
+    if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
+      continue
+    let symKind = if q.typ.kind == tyStatic: skConst else: skType
+    var s = newSym(symKind, q.name, getCurrOwner(), q.info)
+    s.flags = s.flags + {sfUsed, sfFromGeneric}
+    var t = PType(idTableGet(pt, q.typ))
+    if t == nil:
+      if tfRetType in q.typ.flags:
+        # keep the generic type and allow the return type to be bound
+        # later by semAsgn in return type inference scenario
+        t = q.typ
+      else:
+        localError(a.info, errCannotInstantiateX, s.name.s)
+        t = errorType(c)
+    elif t.kind == tyGenericParam:
+      localError(a.info, errCannotInstantiateX, q.name.s)
+      t = errorType(c)
+    elif t.kind == tyGenericInvocation:
+      #t = instGenericContainer(c, a, t)
+      t = generateTypeInstance(c, pt, a, t)
+      #t = ReplaceTypeVarsT(cl, t)
+    s.typ = t
+    if t.kind == tyStatic: s.ast = t.n
+    addDecl(c, s)
+    entry.concreteTypes[i] = t
+
+proc sameInstantiation(a, b: TInstantiation): bool =
+  if a.concreteTypes.len == b.concreteTypes.len:
+    for i in 0..a.concreteTypes.high:
+      if not compareTypes(a.concreteTypes[i], b.concreteTypes[i],
+                          flags = {ExactTypeDescValues}): return
+    result = true
+
+proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
+  if genericSym.procInstCache != nil:
+    for inst in genericSym.procInstCache:
+      if sameInstantiation(entry, inst[]):
+        return inst.sym
+
+proc removeDefaultParamValues(n: PNode) =
+  # we remove default params, because they cannot be instantiated properly
+  # and they are not needed anyway for instantiation (each param is already
+  # provided).
+  when false:
+    for i in countup(1, sonsLen(n)-1):
+      var a = n.sons[i]
+      if a.kind != nkIdentDefs: IllFormedAst(a)
+      var L = a.len
+      if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
+        # ``param: typ = defaultVal``.
+        # We don't need defaultVal for semantic checking and it's wrong for
+        # ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
+        # not possible... XXX We don't solve this issue here.
+        a.sons[L-1] = ast.emptyNode
+
+proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
+  # we need to create a fresh set of gensym'ed symbols:
+  if n.kind == nkSym and sfGenSym in n.sym.flags:
+    let s = n.sym
+    var x = PSym(idTableGet(symMap, s))
+    if x == nil:
+      x = copySym(s, false)
+      x.owner = owner
+      idTablePut(symMap, s, x)
+    n.sym = x
+  else:
+    for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
+
+proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
+
+proc addProcDecls(c: PContext, fn: PSym) =
+  # get the proc itself in scope (e.g. for recursion)
+  addDecl(c, fn)
+
+  for i in 1 .. <fn.typ.n.len:
+    var param = fn.typ.n.sons[i].sym
+    param.owner = fn
+    addParamOrResult(c, param, fn.kind)
+
+  maybeAddResult(c, fn, fn.ast)
+
+proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
+  if n.sons[bodyPos].kind != nkEmpty:
+    inc c.inGenericInst
+    # add it here, so that recursive generic procs are possible:
+    var b = n.sons[bodyPos]
+    var symMap: TIdTable
+    initIdTable symMap
+    if params != nil:
+      for i in 1 .. <params.len:
+        let param = params[i].sym
+        if sfGenSym in param.flags:
+          idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
+    freshGenSyms(b, result, symMap)
+    b = semProcBody(c, b)
+    b = hloBody(c, b)
+    n.sons[bodyPos] = transformBody(c.module, b, result)
+    #echo "code instantiated ", result.name.s
+    excl(result.flags, sfForward)
+    dec c.inGenericInst
+
+proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
+  for i in countup(0, c.generics.len - 1):
+    if c.generics[i].genericSym.id == s.id:
+      var oldPrc = c.generics[i].inst.sym
+      pushInfoContext(oldPrc.info)
+      openScope(c)
+      var n = oldPrc.ast
+      n.sons[bodyPos] = copyTree(s.getBody)
+      instantiateBody(c, n, nil, oldPrc)
+      closeScope(c)
+      popInfoContext()
+
+proc sideEffectsCheck(c: PContext, s: PSym) =
+  if {sfNoSideEffect, sfSideEffect} * s.flags ==
+      {sfNoSideEffect, sfSideEffect}:
+    localError(s.info, errXhasSideEffects, s.name.s)
+
+proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
+                          allowMetaTypes = false): PType =
+  var cl: TReplTypeVars
+  initIdTable(cl.symMap)
+  initIdTable(cl.typeMap)
+  initIdTable(cl.localCache)
+  cl.info = info
+  cl.c = c
+  cl.allowMetaTypes = allowMetaTypes
+  result = replaceTypeVarsT(cl, header)
+
+proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
+  result = instGenericContainer(c, n.info, header)
+
+proc instantiateProcType(c: PContext, pt: TIdTable,
+                          prc: PSym, info: TLineInfo) =
+  # XXX: Instantiates a generic proc signature, while at the same
+  # time adding the instantiated proc params into the current scope.
+  # This is necessary, because the instantiation process may refer to
+  # these params in situations like this:
+  # proc foo[Container](a: Container, b: a.type.Item): type(b.x)
+  #
+  # Alas, doing this here is probably not enough, because another
+  # proc signature could appear in the params:
+  # proc foo[T](a: proc (x: T, b: type(x.y))
+  #
+  # The solution would be to move this logic into semtypinst, but
+  # at this point semtypinst have to become part of sem, because it
+  # will need to use openScope, addDecl, etc.
+  addDecl(c, prc)
+
+  pushInfoContext(info)
+  var cl = initTypeVars(c, pt, info)
+  var result = instCopyType(cl, prc.typ)
+  let originalParams = result.n
+  result.n = originalParams.shallowCopy
+
+  for i in 1 .. <result.len:
+    # twrong_field_caching requires these 'resetIdTable' calls:
+    if i > 1:
+      resetIdTable(cl.symMap)
+      resetIdTable(cl.localCache)
+    result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
+    propagateToOwner(result, result.sons[i])
+    internalAssert originalParams[i].kind == nkSym
+    when true:
+      let oldParam = originalParams[i].sym
+      let param = copySym(oldParam)
+      param.owner = prc
+      param.typ = result.sons[i]
+      if oldParam.ast != nil:
+        param.ast = fitNode(c, param.typ, oldParam.ast)
+
+      # don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
+      result.n.sons[i] = newSymNode(param)
+      addDecl(c, param)
+    else:
+      let param = replaceTypeVarsN(cl, originalParams[i])
+      result.n.sons[i] = param
+      param.sym.owner = prc
+      addDecl(c, result.n.sons[i].sym)
+
+  resetIdTable(cl.symMap)
+  resetIdTable(cl.localCache)
+  result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
+  result.n.sons[0] = originalParams[0].copyTree
+
+  eraseVoidParams(result)
+  skipIntLiteralParams(result)
+
+  prc.typ = result
+  maybeAddResult(c, prc, prc.ast)
+  popInfoContext()
+
+proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
+                      info: TLineInfo): PSym =
+  ## Generates a new instance of a generic procedure.
+  ## The `pt` parameter is a type-unsafe mapping table used to link generic
+  ## parameters to their concrete types within the generic instance.
+  # no need to instantiate generic templates/macros:
+  if fn.kind in {skTemplate, skMacro}: return fn
+  # generates an instantiated proc
+  if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
+  inc(c.instCounter)
+  # careful! we copy the whole AST including the possibly nil body!
+  var n = copyTree(fn.ast)
+  # NOTE: for access of private fields within generics from a different module
+  # we set the friend module:
+  c.friendModules.add(getModule(fn))
+  #let oldScope = c.currentScope
+  #c.currentScope = fn.scope
+  result = copySym(fn, false)
+  incl(result.flags, sfFromGeneric)
+  result.owner = fn
+  result.ast = n
+  pushOwner(result)
+  openScope(c)
+  internalAssert n.sons[genericParamsPos].kind != nkEmpty
+  n.sons[namePos] = newSymNode(result)
+  pushInfoContext(info)
+  var entry = TInstantiation.new
+  entry.sym = result
+  instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
+  pushProcCon(c, result)
+  instantiateProcType(c, pt, result, info)
+  n.sons[genericParamsPos] = ast.emptyNode
+  var oldPrc = genericCacheGet(fn, entry[])
+  if oldPrc == nil:
+    # we MUST not add potentially wrong instantiations to the caching mechanism.
+    # This means recursive instantiations behave differently when in
+    # a ``compiles`` context but this is the lesser evil. See
+    # bug #1055 (tevilcompiles).
+    if c.inCompilesContext == 0: fn.procInstCache.safeAdd(entry)
+    c.generics.add(makeInstPair(fn, entry))
+    if n.sons[pragmasPos].kind != nkEmpty:
+      pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
+    if isNil(n.sons[bodyPos]):
+      n.sons[bodyPos] = copyTree(fn.getBody)
+    instantiateBody(c, n, fn.typ.n, result)
+    sideEffectsCheck(c, result)
+    paramsTypeCheck(c, result.typ)
+  else:
+    result = oldPrc
+  popProcCon(c)
+  popInfoContext()
+  closeScope(c)           # close scope for parameters
+  popOwner()
+  #c.currentScope = oldScope
+  discard c.friendModules.pop()
+  dec(c.instCounter)
+  if result.kind == skMethod: finishMethod(c, result)
diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim
new file mode 100644
index 000000000..bb9814a16
--- /dev/null
+++ b/compiler/semmacrosanity.nim
@@ -0,0 +1,89 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements type sanity checking for ASTs resulting from macros. Lots of
+## room for improvement here.
+
+import ast, astalgo, msgs, types
+
+proc ithField(n: PNode, field: int): PSym =
+  result = nil
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      result = ithField(n.sons[i], field-i)
+      if result != nil: return
+  of nkRecCase:
+    if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
+    result = ithField(n.sons[0], field-1)
+    if result != nil: return
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        result = ithField(lastSon(n.sons[i]), field-1)
+        if result != nil: return
+      else: internalError(n.info, "ithField(record case branch)")
+  of nkSym:
+    if field == 0: result = n.sym
+  else: discard
+
+proc annotateType*(n: PNode, t: PType) =
+  let x = t.skipTypes(abstractInst+{tyRange})
+  # Note: x can be unequal to t and we need to be careful to use 't'
+  # to not to skip tyGenericInst
+  case n.kind
+  of nkPar:
+    if x.kind == tyObject:
+      n.typ = t
+      for i in 0 .. <n.len:
+        let field = x.n.ithField(i)
+        if field.isNil: globalError n.info, "invalid field at index " & $i
+        else: annotateType(n.sons[i], field.typ)
+    elif x.kind == tyTuple:
+      n.typ = t
+      for i in 0 .. <n.len:
+        if i >= x.len: globalError n.info, "invalid field at index " & $i
+        else: annotateType(n.sons[i], x.sons[i])
+    elif x.kind == tyProc and x.callConv == ccClosure:
+      n.typ = t
+    else:
+      globalError(n.info, "() must have an object or tuple type")
+  of nkBracket:
+    if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}:
+      n.typ = t
+      for m in n: annotateType(m, x.elemType)
+    else:
+      globalError(n.info, "[] must have some form of array type")
+  of nkCurly:
+    if x.kind in {tySet}:
+      n.typ = t
+      for m in n: annotateType(m, x.elemType)
+    else:
+      globalError(n.info, "{} must have the set type")
+  of nkFloatLit..nkFloat128Lit:
+    if x.kind in {tyFloat..tyFloat128}:
+      n.typ = t
+    else:
+      globalError(n.info, "float literal must have some float type")
+  of nkCharLit..nkUInt64Lit:
+    if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
+      n.typ = t
+    else:
+      globalError(n.info, "integer literal must have some int type")
+  of nkStrLit..nkTripleStrLit:
+    if x.kind in {tyString, tyCString}:
+      n.typ = t
+    else:
+      globalError(n.info, "string literal must be of some string type")
+  of nkNilLit:
+    if x.kind in NilableTypes:
+      n.typ = t
+    else:
+      globalError(n.info, "nil literal must be of some pointer type")
+  else: discard
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
new file mode 100644
index 000000000..0a7846f1d
--- /dev/null
+++ b/compiler/semmagic.nim
@@ -0,0 +1,177 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include file implements the semantic checking for magics.
+# included from sem.nim
+
+proc semAddr(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkAddr, n.info)
+  let x = semExprWithType(c, n)
+  if isAssignable(c, x) notin {arLValue, arLocalLValue}:
+    localError(n.info, errExprHasNoAddress)
+  result.add x
+  result.typ = makePtrType(c, x.typ)
+
+proc semTypeOf(c: PContext; n: PNode): PNode =
+  result = newNodeI(nkTypeOfExpr, n.info)
+  let typExpr = semExprWithType(c, n, {efInTypeof})
+  result.add typExpr
+  result.typ = makeTypeDesc(c, typExpr.typ.skipTypes({tyTypeDesc, tyIter}))
+
+proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  var r = isPartOf(n[1], n[2])
+  result = newIntNodeT(ord(r), n)
+
+proc expectIntLit(c: PContext, n: PNode): int =
+  let x = c.semConstExpr(c, n)
+  case x.kind
+  of nkIntLit..nkInt64Lit: result = int(x.intVal)
+  else: localError(n.info, errIntLiteralExpected)
+
+proc semInstantiationInfo(c: PContext, n: PNode): PNode =
+  result = newNodeIT(nkPar, n.info, n.typ)
+  let idx = expectIntLit(c, n.sons[1])
+  let useFullPaths = expectIntLit(c, n.sons[2])
+  let info = getInfoContext(idx)
+  var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
+  filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename
+  var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
+  line.intVal = toLinenumber(info)
+  result.add(filename)
+  result.add(line)
+
+proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode =
+  let typ = operand.skipTypes({tyTypeDesc})
+  case trait.sym.name.s.normalize
+  of "name":
+    result = newStrNode(nkStrLit, typ.typeToString(preferName))
+    result.typ = newType(tyString, context)
+    result.info = trait.info
+  of "arity":
+    result = newIntNode(nkIntLit, typ.len - ord(typ.kind==tyProc))
+    result.typ = newType(tyInt, context)
+    result.info = trait.info
+  else:
+    internalAssert false
+
+proc semTypeTraits(c: PContext, n: PNode): PNode =
+  checkMinSonsLen(n, 2)
+  let t = n.sons[1].typ
+  internalAssert t != nil and t.kind == tyTypeDesc
+  if t.sonsLen > 0:
+    # This is either a type known to sem or a typedesc
+    # param to a regular proc (again, known at instantiation)
+    result = evalTypeTrait(n[0], t, getCurrOwner())
+  else:
+    # a typedesc variable, pass unmodified to evals
+    result = n
+
+proc semOrd(c: PContext, n: PNode): PNode =
+  result = n
+  result.typ = makeRangeType(c, firstOrd(n.sons[1].typ),
+                                lastOrd(n.sons[1].typ), n.info)
+
+proc semBindSym(c: PContext, n: PNode): PNode =
+  result = copyNode(n)
+  result.add(n.sons[0])
+
+  let sl = semConstExpr(c, n.sons[1])
+  if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
+    localError(n.sons[1].info, errStringLiteralExpected)
+    return errorNode(c, n)
+
+  let isMixin = semConstExpr(c, n.sons[2])
+  if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
+      isMixin.intVal > high(TSymChoiceRule).int:
+    localError(n.sons[2].info, errConstExprExpected)
+    return errorNode(c, n)
+
+  let id = newIdentNode(getIdent(sl.strVal), n.info)
+  let s = qualifiedLookUp(c, id)
+  if s != nil:
+    # we need to mark all symbols:
+    var sc = symChoice(c, id, s, TSymChoiceRule(isMixin.intVal))
+    result.add(sc)
+  else:
+    localError(n.sons[1].info, errUndeclaredIdentifier, sl.strVal)
+
+proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode
+
+proc isStrangeArray(t: PType): bool =
+  let t = t.skipTypes(abstractInst)
+  result = t.kind == tyArray and t.firstOrd != 0
+
+proc isNegative(n: PNode): bool =
+  let n = n.skipConv
+  if n.kind in {nkCharLit..nkUInt64Lit}:
+    result = n.intVal < 0
+  elif n.kind in nkCallKinds and n.sons[0].kind == nkSym:
+    result = n.sons[0].sym.magic in {mUnaryMinusI, mUnaryMinusI64}
+
+proc magicsAfterOverloadResolution(c: PContext, n: PNode,
+                                   flags: TExprFlags): PNode =
+  case n[0].sym.magic
+  of mAddr:
+    checkSonsLen(n, 2)
+    result = semAddr(c, n.sons[1])
+  of mTypeOf:
+    checkSonsLen(n, 2)
+    result = semTypeOf(c, n.sons[1])
+  of mIsPartOf: result = semIsPartOf(c, n, flags)
+  of mTypeTrait: result = semTypeTraits(c, n)
+  of mAstToStr:
+    result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
+    result.typ = getSysType(tyString)
+  of mInstantiationInfo: result = semInstantiationInfo(c, n)
+  of mOrd: result = semOrd(c, n)
+  of mHigh, mLow: result = semLowHigh(c, n, n[0].sym.magic)
+  of mShallowCopy: result = semShallowCopy(c, n, flags)
+  of mNBindSym: result = semBindSym(c, n)
+  of mProcCall:
+    result = n
+    result.typ = n[1].typ
+  of mDotDot:
+    result = n
+    # disallow negative indexing for now:
+    if not c.p.bracketExpr.isNil:
+      if isNegative(n.sons[1]) or (n.len > 2 and isNegative(n.sons[2])):
+        localError(n.info, "use '^' instead of '-'; negative indexing is obsolete")
+  of mRoof:
+    # error correction:
+    result = n.sons[1]
+    if c.p.bracketExpr.isNil:
+      localError(n.info, "no surrounding array access context for '^'")
+    elif c.p.bracketExpr.checkForSideEffects != seNoSideEffect:
+      localError(n.info, "invalid context for '^' as '$#' has side effects" %
+        renderTree(c.p.bracketExpr))
+    elif c.p.bracketExpr.typ.isStrangeArray:
+      localError(n.info, "invalid context for '^' as len!=high+1 for '$#'" %
+        renderTree(c.p.bracketExpr))
+    else:
+      # ^x  is rewritten to: len(a)-x
+      let lenExpr = newNodeI(nkCall, n.info)
+      lenExpr.add newIdentNode(getIdent"len", n.info)
+      lenExpr.add c.p.bracketExpr
+      let lenExprB = semExprWithType(c, lenExpr)
+      if lenExprB.typ.isNil or not isOrdinalType(lenExprB.typ):
+        localError(n.info, "'$#' has to be of an ordinal type for '^'" %
+          renderTree(lenExpr))
+      else:
+        result = newNodeIT(nkCall, n.info, getSysType(tyInt))
+        result.add newSymNode(createMagic("-", mSubI), n.info)
+        result.add lenExprB
+        result.add n.sons[1]
+  of mPlugin:
+    let plugin = getPlugin(n[0].sym)
+    if plugin.isNil:
+      localError(n.info, "cannot find plugin " & n[0].sym.name.s)
+      result = n
+    else:
+      result = plugin(c, n)
+  else: result = n
diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim
new file mode 100644
index 000000000..fbcd6b6da
--- /dev/null
+++ b/compiler/semparallel.nim
@@ -0,0 +1,486 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Semantic checking for 'parallel'.
+
+# - codegen needs to support mSlice (+)
+# - lowerings must not perform unnecessary copies (+)
+# - slices should become "nocopy" to openArray (+)
+#   - need to perform bound checks (+)
+#
+# - parallel needs to insert a barrier (+)
+# - passed arguments need to be ensured to be "const"
+#   - what about 'f(a)'? --> f shouldn't have side effects anyway
+# - passed arrays need to be ensured not to alias
+# - passed slices need to be ensured to be disjoint (+)
+# - output slices need special logic (+)
+
+import
+  ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
+  renderer, types
+from trees import getMagic
+from strutils import `%`
+
+discard """
+
+one major problem:
+  spawn f(a[i])
+  inc i
+  spawn f(a[i])
+is valid, but
+  spawn f(a[i])
+  spawn f(a[i])
+  inc i
+is not! However,
+  spawn f(a[i])
+  if guard: inc i
+  spawn f(a[i])
+is not valid either! --> We need a flow dependent analysis here.
+
+However:
+  while foo:
+    spawn f(a[i])
+    inc i
+    spawn f(a[i])
+
+Is not valid either! --> We should really restrict 'inc' to loop endings?
+
+The heuristic that we implement here (that has no false positives) is: Usage
+of 'i' in a slice *after* we determined the stride is invalid!
+"""
+
+type
+  TDirection = enum
+    ascending, descending
+  MonotonicVar = object
+    v, alias: PSym        # to support the ordinary 'countup' iterator
+                          # we need to detect aliases
+    lower, upper, stride: PNode
+    dir: TDirection
+    blacklisted: bool     # blacklisted variables that are not monotonic
+  AnalysisCtx = object
+    locals: seq[MonotonicVar]
+    slices: seq[tuple[x,a,b: PNode, spawnId: int, inLoop: bool]]
+    guards: TModel      # nested guards
+    args: seq[PSym]     # args must be deeply immutable
+    spawns: int         # we can check that at last 1 spawn is used in
+                        # the 'parallel' section
+    currentSpawnId: int
+    inLoop: int
+
+let opSlice = createMagic("slice", mSlice)
+
+proc initAnalysisCtx(): AnalysisCtx =
+  result.locals = @[]
+  result.slices = @[]
+  result.args = @[]
+  result.guards = @[]
+
+proc lookupSlot(c: AnalysisCtx; s: PSym): int =
+  for i in 0.. <c.locals.len:
+    if c.locals[i].v == s or c.locals[i].alias == s: return i
+  return -1
+
+proc getSlot(c: var AnalysisCtx; v: PSym): ptr MonotonicVar =
+  let s = lookupSlot(c, v)
+  if s >= 0: return addr(c.locals[s])
+  let L = c.locals.len
+  c.locals.setLen(L+1)
+  c.locals[L].v = v
+  return addr(c.locals[L])
+
+proc gatherArgs(c: var AnalysisCtx; n: PNode) =
+  for i in 0.. <n.safeLen:
+    let root = getRoot n[i]
+    if root != nil:
+      block addRoot:
+        for r in items(c.args):
+          if r == root: break addRoot
+        c.args.add root
+    gatherArgs(c, n[i])
+
+proc isSingleAssignable(n: PNode): bool =
+  n.kind == nkSym and (let s = n.sym;
+    s.kind in {skTemp, skForVar, skLet} and
+          {sfAddrTaken, sfGlobal} * s.flags == {})
+
+proc isLocal(n: PNode): bool =
+  n.kind == nkSym and (let s = n.sym;
+    s.kind in {skResult, skTemp, skForVar, skVar, skLet} and
+          {sfAddrTaken, sfGlobal} * s.flags == {})
+
+proc checkLocal(c: AnalysisCtx; n: PNode) =
+  if isLocal(n):
+    let s = c.lookupSlot(n.sym)
+    if s >= 0 and c.locals[s].stride != nil:
+      localError(n.info, "invalid usage of counter after increment")
+  else:
+    for i in 0 .. <n.safeLen: checkLocal(c, n.sons[i])
+
+template `?`(x): expr = x.renderTree
+
+proc checkLe(c: AnalysisCtx; a, b: PNode) =
+  case proveLe(c.guards, a, b)
+  of impUnknown:
+    localError(a.info, "cannot prove: " & ?a & " <= " & ?b)
+  of impYes: discard
+  of impNo:
+    localError(a.info, "can prove: " & ?a & " > " & ?b)
+
+proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
+  checkLe(c, arr.lowBound, idx)
+  checkLe(c, idx, arr.highBound)
+
+proc addLowerBoundAsFacts(c: var AnalysisCtx) =
+  for v in c.locals:
+    if not v.blacklisted:
+      c.guards.addFactLe(v.lower, newSymNode(v.v))
+
+proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) =
+  checkLocal(c, n)
+  let le = le.canon
+  let ri = ri.canon
+  # perform static bounds checking here; and not later!
+  let oldState = c.guards.len
+  addLowerBoundAsFacts(c)
+  c.checkBounds(x, le)
+  c.checkBounds(x, ri)
+  c.guards.setLen(oldState)
+  c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0))
+
+proc overlap(m: TModel; x,y,c,d: PNode) =
+  #  X..Y and C..D overlap iff (X <= D and C <= Y)
+  case proveLe(m, x, d)
+  of impUnknown:
+    localError(x.info,
+      "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
+        [?x, ?d, ?x, ?y, ?c, ?d])
+  of impYes:
+    case proveLe(m, c, y)
+    of impUnknown:
+      localError(x.info,
+        "cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
+          [?c, ?y, ?x, ?y, ?c, ?d])
+    of impYes:
+      localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" % [?x, ?y, ?c, ?d])
+    of impNo: discard
+  of impNo: discard
+
+proc stride(c: AnalysisCtx; n: PNode): BiggestInt =
+  if isLocal(n):
+    let s = c.lookupSlot(n.sym)
+    if s >= 0 and c.locals[s].stride != nil:
+      result = c.locals[s].stride.intVal
+  else:
+    for i in 0 .. <n.safeLen: result += stride(c, n.sons[i])
+
+proc subStride(c: AnalysisCtx; n: PNode): PNode =
+  # substitute with stride:
+  if isLocal(n):
+    let s = c.lookupSlot(n.sym)
+    if s >= 0 and c.locals[s].stride != nil:
+      result = n +@ c.locals[s].stride.intVal
+    else:
+      result = n
+  elif n.safeLen > 0:
+    result = shallowCopy(n)
+    for i in 0 .. <n.len: result.sons[i] = subStride(c, n.sons[i])
+  else:
+    result = n
+
+proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
+  # this is the only thing that we need to perform after we have traversed
+  # the whole tree so that the strides are available.
+  # First we need to add all the computed lower bounds:
+  addLowerBoundAsFacts(c)
+  # Every slice used in a loop needs to be disjoint with itself:
+  for x,a,b,id,inLoop in items(c.slices):
+    if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b))
+  # Another tricky example is:
+  #   while true:
+  #     spawn f(a[i])
+  #     spawn f(a[i+1])
+  #     inc i  # inc i, 2  would be correct here
+  #
+  # Or even worse:
+  #   while true:
+  #     spawn f(a[i+1 .. i+3])
+  #     spawn f(a[i+4 .. i+5])
+  #     inc i, 4
+  # Prove that i*k*stride + 3 != i*k'*stride + 5
+  # For the correct example this amounts to
+  #   i*k*2 != i*k'*2 + 1
+  # which is true.
+  # For now, we don't try to prove things like that at all, even though it'd
+  # be feasible for many useful examples. Instead we attach the slice to
+  # a spawn and if the attached spawns differ, we bail out:
+  for i in 0 .. high(c.slices):
+    for j in i+1 .. high(c.slices):
+      let x = c.slices[i]
+      let y = c.slices[j]
+      if x.spawnId != y.spawnId and guards.sameTree(x.x, y.x):
+        if not x.inLoop or not y.inLoop:
+          # XXX strictly speaking, 'or' is not correct here and it needs to
+          # be 'and'. However this prevents too many obviously correct programs
+          # like f(a[0..x]); for i in x+1 .. a.high: f(a[i])
+          overlap(c.guards, x.a, x.b, y.a, y.b)
+        elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b);
+              k >= 0 and m >= 0):
+          # ah I cannot resist the temptation and add another sweet heuristic:
+          # if both slices have the form (i+k)..(i+k)  and (i+m)..(i+m) we
+          # check they are disjoint and k < stride and m < stride:
+          overlap(c.guards, x.a, x.b, y.a, y.b)
+          let stride = min(c.stride(x.a), c.stride(y.a))
+          if k < stride and m < stride:
+            discard
+          else:
+            localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
+              [?x.a, ?x.b, ?y.a, ?y.b])
+        else:
+          localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
+            [?x.a, ?x.b, ?y.a, ?y.b])
+
+proc analyse(c: var AnalysisCtx; n: PNode)
+
+proc analyseSons(c: var AnalysisCtx; n: PNode) =
+  for i in 0 .. <safeLen(n): analyse(c, n[i])
+
+proc min(a, b: PNode): PNode =
+  if a.isNil: result = b
+  elif a.intVal < b.intVal: result = a
+  else: result = b
+
+proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
+
+template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
+  inc c.spawns
+  let oldSpawnId = c.currentSpawnId
+  c.currentSpawnId = c.spawns
+  body
+  c.currentSpawnId = oldSpawnId
+
+proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
+  if op.magic == mSpawn:
+    pushSpawnId(c):
+      gatherArgs(c, n[1])
+      analyseSons(c, n)
+  elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
+    if n[1].isLocal:
+      let incr = n[2].skipConv
+      if incr.kind in {nkCharLit..nkUInt32Lit} and incr.intVal > 0:
+        let slot = c.getSlot(n[1].sym)
+        slot.stride = min(slot.stride, incr)
+    analyseSons(c, n)
+  elif op.name.s == "[]" and op.fromSystem:
+    c.addSlice(n, n[1], n[2][1], n[2][2])
+    analyseSons(c, n)
+  elif op.name.s == "[]=" and op.fromSystem:
+    c.addSlice(n, n[1], n[2][1], n[2][2])
+    analyseSons(c, n)
+  else:
+    analyseSons(c, n)
+
+proc analyseCase(c: var AnalysisCtx; n: PNode) =
+  analyse(c, n.sons[0])
+  let oldFacts = c.guards.len
+  for i in 1.. <n.len:
+    let branch = n.sons[i]
+    setLen(c.guards, oldFacts)
+    addCaseBranchFacts(c.guards, n, i)
+    for i in 0 .. <branch.len:
+      analyse(c, branch.sons[i])
+  setLen(c.guards, oldFacts)
+
+proc analyseIf(c: var AnalysisCtx; n: PNode) =
+  analyse(c, n.sons[0].sons[0])
+  let oldFacts = c.guards.len
+  addFact(c.guards, canon(n.sons[0].sons[0]))
+
+  analyse(c, n.sons[0].sons[1])
+  for i in 1.. <n.len:
+    let branch = n.sons[i]
+    setLen(c.guards, oldFacts)
+    for j in 0..i-1:
+      addFactNeg(c.guards, canon(n.sons[j].sons[0]))
+    if branch.len > 1:
+      addFact(c.guards, canon(branch.sons[0]))
+    for i in 0 .. <branch.len:
+      analyse(c, branch.sons[i])
+  setLen(c.guards, oldFacts)
+
+proc analyse(c: var AnalysisCtx; n: PNode) =
+  case n.kind
+  of nkAsgn, nkFastAsgn:
+    let y = n[1].skipConv
+    if n[0].isSingleAssignable and y.isLocal:
+      let slot = c.getSlot(y.sym)
+      slot.alias = n[0].sym
+    elif n[0].isLocal:
+      # since we already ensure sfAddrTaken is not in s.flags, we only need to
+      # prevent direct assignments to the monotonic variable:
+      let slot = c.getSlot(n[0].sym)
+      slot.blacklisted = true
+    invalidateFacts(c.guards, n[0])
+    let value = n[1]
+    if getMagic(value) == mSpawn:
+      pushSpawnId(c):
+        gatherArgs(c, value[1])
+        analyseSons(c, value[1])
+        analyse(c, n[0])
+    else:
+      analyseSons(c, n)
+    addAsgnFact(c.guards, n[0], y)
+  of nkCallKinds:
+    # direct call:
+    if n[0].kind == nkSym: analyseCall(c, n, n[0].sym)
+    else: analyseSons(c, n)
+  of nkBracketExpr:
+    c.addSlice(n, n[0], n[1], n[1])
+    analyseSons(c, n)
+  of nkReturnStmt, nkRaiseStmt, nkTryStmt:
+    localError(n.info, "invalid control flow for 'parallel'")
+    # 'break' that leaves the 'parallel' section is not valid either
+    # or maybe we should generate a 'try' XXX
+  of nkVarSection, nkLetSection:
+    for it in n:
+      let value = it.lastSon
+      let isSpawned = getMagic(value) == mSpawn
+      if isSpawned:
+        pushSpawnId(c):
+          gatherArgs(c, value[1])
+          analyseSons(c, value[1])
+      if value.kind != nkEmpty:
+        for j in 0 .. it.len-3:
+          if it[j].isLocal:
+            let slot = c.getSlot(it[j].sym)
+            if slot.lower.isNil: slot.lower = value
+            else: internalError(it.info, "slot already has a lower bound")
+        if not isSpawned: analyse(c, value)
+  of nkCaseStmt: analyseCase(c, n)
+  of nkIfStmt, nkIfExpr: analyseIf(c, n)
+  of nkWhileStmt:
+    analyse(c, n.sons[0])
+    # 'while true' loop?
+    inc c.inLoop
+    if isTrue(n.sons[0]):
+      analyseSons(c, n.sons[1])
+    else:
+      # loop may never execute:
+      let oldState = c.locals.len
+      let oldFacts = c.guards.len
+      addFact(c.guards, canon(n.sons[0]))
+      analyse(c, n.sons[1])
+      setLen(c.locals, oldState)
+      setLen(c.guards, oldFacts)
+      # we know after the loop the negation holds:
+      if not hasSubnodeWith(n.sons[1], nkBreakStmt):
+        addFactNeg(c.guards, canon(n.sons[0]))
+    dec c.inLoop
+  of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
+      nkMacroDef, nkTemplateDef, nkConstSection, nkPragma:
+    discard
+  else:
+    analyseSons(c, n)
+
+proc transformSlices(n: PNode): PNode =
+  if n.kind in nkCallKinds and n[0].kind == nkSym:
+    let op = n[0].sym
+    if op.name.s == "[]" and op.fromSystem:
+      result = copyNode(n)
+      result.add opSlice.newSymNode
+      result.add n[1]
+      result.add n[2][1]
+      result.add n[2][2]
+      return result
+  if n.safeLen > 0:
+    result = shallowCopy(n)
+    for i in 0 .. < n.len:
+      result.sons[i] = transformSlices(n.sons[i])
+  else:
+    result = n
+
+proc transformSpawn(owner: PSym; n, barrier: PNode): PNode
+proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
+  result = shallowCopy(n)
+  for i in 0 .. < n.len:
+    result.sons[i] = transformSpawn(owner, n.sons[i], barrier)
+
+proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
+  case n.kind
+  of nkVarSection, nkLetSection:
+    result = nil
+    for it in n:
+      let b = it.lastSon
+      if getMagic(b) == mSpawn:
+        if it.len != 3: localError(it.info, "invalid context for 'spawn'")
+        let m = transformSlices(b)
+        if result.isNil:
+          result = newNodeI(nkStmtList, n.info)
+          result.add n
+        let t = b[1][0].typ.sons[0]
+        if spawnResult(t, true) == srByVar:
+          result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
+          it.sons[it.len-1] = emptyNode
+        else:
+          it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil)
+    if result.isNil: result = n
+  of nkAsgn, nkFastAsgn:
+    let b = n[1]
+    if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
+        spawnResult(t, true) == srByVar):
+      let m = transformSlices(b)
+      return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
+    result = transformSpawnSons(owner, n, barrier)
+  of nkCallKinds:
+    if getMagic(n) == mSpawn:
+      result = transformSlices(n)
+      return wrapProcForSpawn(owner, result, n.typ, barrier, nil)
+    result = transformSpawnSons(owner, n, barrier)
+  elif n.safeLen > 0:
+    result = transformSpawnSons(owner, n, barrier)
+  else:
+    result = n
+
+proc checkArgs(a: var AnalysisCtx; n: PNode) =
+  discard "too implement"
+
+proc generateAliasChecks(a: AnalysisCtx; result: PNode) =
+  discard "too implement"
+
+proc liftParallel*(owner: PSym; n: PNode): PNode =
+  # this needs to be called after the 'for' loop elimination
+
+  # first pass:
+  # - detect monotonic local integer variables
+  # - detect used slices
+  # - detect used arguments
+  #echo "PAR ", renderTree(n)
+
+  var a = initAnalysisCtx()
+  let body = n.lastSon
+  analyse(a, body)
+  if a.spawns == 0:
+    localError(n.info, "'parallel' section without 'spawn'")
+  checkSlicesAreDisjoint(a)
+  checkArgs(a, body)
+
+  var varSection = newNodeI(nkVarSection, n.info)
+  var temp = newSym(skTemp, getIdent"barrier", owner, n.info)
+  temp.typ = magicsys.getCompilerProc("Barrier").typ
+  incl(temp.flags, sfFromGeneric)
+  let tempNode = newSymNode(temp)
+  varSection.addVar tempNode
+
+  let barrier = genAddrOf(tempNode)
+  result = newNodeI(nkStmtList, n.info)
+  generateAliasChecks(a, result)
+  result.add varSection
+  result.add callCodegenProc("openBarrier", barrier)
+  result.add transformSpawn(owner, body, barrier)
+  result.add callCodegenProc("closeBarrier", barrier)
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
new file mode 100644
index 000000000..adf03be64
--- /dev/null
+++ b/compiler/sempass2.nim
@@ -0,0 +1,907 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
+  wordrecg, strutils, options, guards
+
+# Second semantic checking pass over the AST. Necessary because the old
+# way had some inherent problems. Performs:
+#
+# * effect+exception tracking
+# * "usage before definition" checking
+# * checks for invalid usages of compiletime magics (not implemented)
+# * checks for invalid usages of PNimNode (not implemented)
+# * later: will do an escape analysis for closures at least
+
+# Predefined effects:
+#   io, time (time dependent), gc (performs GC'ed allocation), exceptions,
+#   side effect (accesses global), store (stores into *type*),
+#   store_unknown (performs some store) --> store(any)|store(x)
+#   load (loads from *type*), recursive (recursive call), unsafe,
+#   endless (has endless loops), --> user effects are defined over *patterns*
+#   --> a TR macro can annotate the proc with user defined annotations
+#   --> the effect system can access these
+
+# Load&Store analysis is performed on *paths*. A path is an access like
+# obj.x.y[i].z; splitting paths up causes some problems:
+#
+# var x = obj.x
+# var z = x.y[i].z
+#
+# Alias analysis is affected by this too! A good solution is *type splitting*:
+# T becomes T1 and T2 if it's known that T1 and T2 can't alias.
+#
+# An aliasing problem and a race condition are effectively the same problem.
+# Type based alias analysis is nice but not sufficient; especially splitting
+# an array and filling it in parallel should be supported but is not easily
+# done: It essentially requires a built-in 'indexSplit' operation and dependent
+# typing.
+
+# ------------------------ exception and tag tracking -------------------------
+
+discard """
+  exception tracking:
+
+  a() # raises 'x', 'e'
+  try:
+    b() # raises 'e'
+  except e:
+    # must not undo 'e' here; hrm
+    c()
+
+ --> we need a stack of scopes for this analysis
+
+  # XXX enhance the algorithm to care about 'dirty' expressions:
+  lock a[i].L:
+    inc i # mark 'i' dirty
+    lock a[j].L:
+      access a[i], a[j]  # --> reject a[i]
+"""
+
+type
+  TEffects = object
+    exc: PNode  # stack of exceptions
+    tags: PNode # list of tags
+    bottom, inTryStmt: int
+    owner: PSym
+    init: seq[int] # list of initialized variables
+    guards: TModel # nested guards
+    locked: seq[PNode] # locked locations
+    gcUnsafe, isRecursive, isToplevel: bool
+    maxLockLevel, currLockLevel: TLockLevel
+  PEffects = var TEffects
+
+proc `<`(a, b: TLockLevel): bool {.borrow.}
+proc `<=`(a, b: TLockLevel): bool {.borrow.}
+proc `==`(a, b: TLockLevel): bool {.borrow.}
+proc max(a, b: TLockLevel): TLockLevel {.borrow.}
+
+proc isLocalVar(a: PEffects, s: PSym): bool =
+  s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner
+
+proc getLockLevel(t: PType): TLockLevel =
+  var t = t
+  # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
+  if t.kind == tyGenericInst and t.len == 3: t = t.sons[1]
+  if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
+    result = t.n.intVal.TLockLevel
+
+proc lockLocations(a: PEffects; pragma: PNode) =
+  if pragma.kind != nkExprColonExpr:
+    localError(pragma.info, errGenerated, "locks pragma without argument")
+    return
+  var firstLL = TLockLevel(-1'i16)
+  for x in pragma[1]:
+    let thisLL = getLockLevel(x.typ)
+    if thisLL != 0.TLockLevel:
+      if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
+        localError(x.info, "invalid lock level: " & $thisLL)
+      elif firstLL < 0.TLockLevel: firstLL = thisLL
+      elif firstLL != thisLL:
+        localError(x.info, errGenerated,
+          "multi-lock requires the same static lock level for every operand")
+      a.maxLockLevel = max(a.maxLockLevel, firstLL)
+    a.locked.add x
+  if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
+    if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
+      localError(pragma.info, errGenerated,
+        "invalid nested locking")
+    a.currLockLevel = firstLL
+
+proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
+  # check whether the corresponding lock is held:
+  for L in a.locked:
+    if L.kind == nkSym and L.sym == guard: return
+  # we allow accesses nevertheless in top level statements for
+  # easier initialization:
+  #if a.isTopLevel:
+  #  message(n.info, warnUnguardedAccess, renderTree(n))
+  #else:
+  if not a.isTopLevel:
+    localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
+
+# 'guard*' are checks which are concerned with 'guard' annotations
+# (var x{.guard: y.}: int)
+proc guardDotAccess(a: PEffects; n: PNode) =
+  let ri = n.sons[1]
+  if ri.kind != nkSym or ri.sym.kind != skField: return
+  var g = ri.sym.guard
+  if g.isNil or a.isTopLevel: return
+  # fixup guard:
+  if g.kind == skUnknown:
+    var field: PSym = nil
+    var ty = n.sons[0].typ.skipTypes(abstractPtrs)
+    if ty.kind == tyTuple and not ty.n.isNil:
+      field = lookupInRecord(ty.n, g.name)
+    else:
+      while ty != nil and ty.kind == tyObject:
+        field = lookupInRecord(ty.n, g.name)
+        if field != nil: break
+        ty = ty.sons[0]
+        if ty == nil: break
+        ty = ty.skipTypes(abstractPtrs)
+    if field == nil:
+      localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
+      return
+    g = field
+    #ri.sym.guard = field
+    # XXX unfortunately this is not correct for generic instantiations!
+  if g.kind == skField:
+    let dot = newNodeI(nkDotExpr, n.info, 2)
+    dot.sons[0] = n.sons[0]
+    dot.sons[1] = newSymNode(g)
+    dot.typ = g.typ
+    for L in a.locked:
+      #if a.guards.sameSubexprs(dot, L): return
+      if guards.sameTree(dot, L): return
+    localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
+  else:
+    guardGlobal(a, n, g)
+
+proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
+  template compileToCpp(a): expr =
+    gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
+  if a.inTryStmt > 0 and not compileToCpp(a):
+    incl(s.flags, sfVolatile)
+
+proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
+  if n.kind != nkSym: return
+  let s = n.sym
+  if isLocalVar(a, s):
+    if volatileCheck: makeVolatile(a, s)
+    for x in a.init:
+      if x == s.id: return
+    a.init.add s.id
+
+proc initVarViaNew(a: PEffects, n: PNode) =
+  if n.kind != nkSym: return
+  let s = n.sym
+  if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
+    # 'x' is not nil, but that doesn't mean its "not nil" children
+    # are initialized:
+    initVar(a, n, volatileCheck=true)
+  elif isLocalVar(a, s):
+    makeVolatile(a, s)
+
+proc warnAboutGcUnsafe(n: PNode) =
+  #assert false
+  message(n.info, warnGcUnsafe, renderTree(n))
+
+proc markGcUnsafe(a: PEffects; reason: PSym) =
+  a.gcUnsafe = true
+  if a.owner.kind in routineKinds: a.owner.gcUnsafetyReason = reason
+
+proc markGcUnsafe(a: PEffects; reason: PNode) =
+  a.gcUnsafe = true
+  if a.owner.kind in routineKinds:
+    if reason.kind == nkSym:
+      a.owner.gcUnsafetyReason = reason.sym
+    else:
+      a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
+                                        a.owner, reason.info)
+
+proc listGcUnsafety(s: PSym; onlyWarning: bool) =
+  let u = s.gcUnsafetyReason
+  if u != nil:
+    let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
+    if u.kind in {skLet, skVar}:
+      message(s.info, msgKind,
+        ("'$#' is not GC-safe as it accesses '$#'" &
+        " which is a global using GC'ed memory") % [s.name.s, u.name.s])
+    elif u.kind in routineKinds:
+      # recursive call *always* produces only a warning so the full error
+      # message is printed:
+      listGcUnsafety(u, true)
+      message(s.info, msgKind,
+        "'$#' is not GC-safe as it calls '$#'" %
+        [s.name.s, u.name.s])
+    else:
+      internalAssert u.kind == skUnknown
+      message(u.info, msgKind,
+        "'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
+
+proc useVar(a: PEffects, n: PNode) =
+  let s = n.sym
+  if isLocalVar(a, s):
+    if s.id notin a.init:
+      if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
+        message(n.info, warnProveInit, s.name.s)
+      else:
+        message(n.info, warnUninit, s.name.s)
+      # prevent superfluous warnings about the same variable:
+      a.init.add s.id
+  if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
+    if s.guard != nil: guardGlobal(a, n, s.guard)
+    if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
+      #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+      markGcUnsafe(a, s)
+
+type
+  TIntersection = seq[tuple[id, count: int]] # a simple count table
+
+proc addToIntersection(inter: var TIntersection, s: int) =
+  for j in 0.. <inter.len:
+    if s == inter[j].id:
+      inc inter[j].count
+      return
+  inter.add((id: s, count: 1))
+
+proc throws(tracked, n: PNode) =
+  if n.typ == nil or n.typ.kind != tyError: tracked.add n
+
+proc getEbase(): PType =
+  result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
+           else: sysTypeFromName"E_Base"
+
+proc excType(n: PNode): PType =
+  # reraise is like raising E_Base:
+  let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
+  result = skipTypes(t, skipPtrs)
+
+proc createRaise(n: PNode): PNode =
+  result = newNode(nkType)
+  result.typ = getEbase()
+  if not n.isNil: result.info = n.info
+
+proc createTag(n: PNode): PNode =
+  result = newNode(nkType)
+  if getCompilerProc("RootEffect") != nil:
+    result.typ = sysTypeFromName"RootEffect"
+  else:
+    result.typ = sysTypeFromName"TEffect"
+  if not n.isNil: result.info = n.info
+
+proc createAnyGlobal(n: PNode): PNode =
+  result = newSymNode(anyGlobal)
+  result.info = n.info
+
+proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
+  assert e.kind != nkRaiseStmt
+  var aa = a.exc
+  for i in a.bottom .. <aa.len:
+    if sameType(aa[i].excType, e.excType):
+      if not useLineInfo or gCmd == cmdDoc: return
+      elif aa[i].info == e.info: return
+  throws(a.exc, e)
+
+proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
+  var aa = a.tags
+  for i in 0 .. <aa.len:
+    if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
+      if not useLineInfo or gCmd == cmdDoc: return
+      elif aa[i].info == e.info: return
+  throws(a.tags, e)
+
+proc mergeEffects(a: PEffects, b, comesFrom: PNode) =
+  if b.isNil:
+    addEffect(a, createRaise(comesFrom))
+  else:
+    for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil)
+
+proc mergeTags(a: PEffects, b, comesFrom: PNode) =
+  if b.isNil:
+    addTag(a, createTag(comesFrom))
+  else:
+    for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
+
+proc listEffects(a: PEffects) =
+  for e in items(a.exc):  message(e.info, hintUser, typeToString(e.typ))
+  for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
+  #if a.maxLockLevel != 0:
+  #  message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
+
+proc catches(tracked: PEffects, e: PType) =
+  let e = skipTypes(e, skipPtrs)
+  var L = tracked.exc.len
+  var i = tracked.bottom
+  while i < L:
+    # r supertype of e?
+    if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0:
+      tracked.exc.sons[i] = tracked.exc.sons[L-1]
+      dec L
+    else:
+      inc i
+  if not isNil(tracked.exc.sons):
+    setLen(tracked.exc.sons, L)
+  else:
+    assert L == 0
+
+proc catchesAll(tracked: PEffects) =
+  if not isNil(tracked.exc.sons):
+    setLen(tracked.exc.sons, tracked.bottom)
+
+proc track(tracked: PEffects, n: PNode)
+proc trackTryStmt(tracked: PEffects, n: PNode) =
+  let oldBottom = tracked.bottom
+  tracked.bottom = tracked.exc.len
+
+  let oldState = tracked.init.len
+  var inter: TIntersection = @[]
+
+  inc tracked.inTryStmt
+  track(tracked, n.sons[0])
+  dec tracked.inTryStmt
+  for i in oldState.. <tracked.init.len:
+    addToIntersection(inter, tracked.init[i])
+
+  var branches = 1
+  var hasFinally = false
+  for i in 1 .. < n.len:
+    let b = n.sons[i]
+    let blen = sonsLen(b)
+    if b.kind == nkExceptBranch:
+      inc branches
+      if blen == 1:
+        catchesAll(tracked)
+      else:
+        for j in countup(0, blen - 2):
+          assert(b.sons[j].kind == nkType)
+          catches(tracked, b.sons[j].typ)
+
+      setLen(tracked.init, oldState)
+      track(tracked, b.sons[blen-1])
+      for i in oldState.. <tracked.init.len:
+        addToIntersection(inter, tracked.init[i])
+    else:
+      assert b.kind == nkFinally
+      setLen(tracked.init, oldState)
+      track(tracked, b.sons[blen-1])
+      hasFinally = true
+
+  tracked.bottom = oldBottom
+  if not hasFinally:
+    setLen(tracked.init, oldState)
+  for id, count in items(inter):
+    if count == branches: tracked.init.add id
+
+proc isIndirectCall(n: PNode, owner: PSym): bool =
+  # we don't count f(...) as an indirect call if 'f' is an parameter.
+  # Instead we track expressions of type tyProc too. See the manual for
+  # details:
+  if n.kind != nkSym:
+    result = true
+  elif n.sym.kind == skParam:
+    result = owner != n.sym.owner or owner == nil
+  elif n.sym.kind notin routineKinds:
+    result = true
+
+proc isForwardedProc(n: PNode): bool =
+  result = n.kind == nkSym and sfForward in n.sym.flags
+
+proc trackPragmaStmt(tracked: PEffects, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    if whichPragma(it) == wEffects:
+      # list the computed effects up to here:
+      listEffects(tracked)
+
+proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
+      result = it.sons[1]
+      if result.kind notin {nkCurly, nkBracket}:
+        result = newNodeI(nkCurly, result.info)
+        result.add(it.sons[1])
+      return
+
+proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
+  let spec = effectSpec(x, effectType)
+  if isNil(spec):
+    let s = n.sons[namePos].sym
+
+    let actual = s.typ.n.sons[0]
+    if actual.len != effectListLen: return
+    let real = actual.sons[idx]
+
+    # warning: hack ahead:
+    var effects = newNodeI(nkBracket, n.info, real.len)
+    for i in 0 .. <real.len:
+      var t = typeToString(real[i].typ)
+      if t.startsWith("ref "): t = substr(t, 4)
+      effects.sons[i] = newIdentNode(getIdent(t), n.info)
+      # set the type so that the following analysis doesn't screw up:
+      effects.sons[i].typ = real[i].typ
+
+    result = newNode(nkExprColonExpr, n.info, @[
+      newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
+
+proc documentRaises*(n: PNode) =
+  if n.sons[namePos].kind != nkSym: return
+  let pragmas = n.sons[pragmasPos]
+  let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
+  let p2 = documentEffect(n, pragmas, wTags, tagEffects)
+
+  if p1 != nil or p2 != nil:
+    if pragmas.kind == nkEmpty:
+      n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
+    if p1 != nil: n.sons[pragmasPos].add p1
+    if p2 != nil: n.sons[pragmasPos].add p2
+
+template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
+
+proc importedFromC(n: PNode): bool =
+  # when imported from C, we assume GC-safety.
+  result = n.kind == nkSym and sfImportc in n.sym.flags
+
+proc getLockLevel(s: PSym): TLockLevel =
+  result = s.typ.lockLevel
+  if result == UnspecifiedLockLevel:
+    if {sfImportc, sfNoSideEffect} * s.flags != {} or
+       tfNoSideEffect in s.typ.flags:
+      result = 0.TLockLevel
+    else:
+      result = UnknownLockLevel
+      #message(s.info, warnUser, "FOR THIS " & s.name.s)
+
+proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
+  if lockLevel >= tracked.currLockLevel:
+    # if in lock section:
+    if tracked.currLockLevel > 0.TLockLevel:
+      localError n.info, errGenerated,
+        "expected lock level < " & $tracked.currLockLevel &
+        " but got lock level " & $lockLevel
+    tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
+
+proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
+  let pragma = s.ast.sons[pragmasPos]
+  let spec = effectSpec(pragma, wRaises)
+  mergeEffects(tracked, spec, n)
+
+  let tagSpec = effectSpec(pragma, wTags)
+  mergeTags(tracked, tagSpec, n)
+
+  if notGcSafe(s.typ) and sfImportc notin s.flags:
+    if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+    markGcUnsafe(tracked, s)
+  mergeLockLevels(tracked, n, s.getLockLevel)
+
+proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
+  let n = n.skipConv
+  if paramType != nil and tfNotNil in paramType.flags and
+      n.typ != nil and tfNotNil notin n.typ.flags:
+    if n.kind == nkAddr:
+      # addr(x[]) can't be proven, but addr(x) can:
+      if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
+    elif (n.kind == nkSym and n.sym.kind in routineKinds) or n.kind in procDefs:
+      # 'p' is not nil obviously:
+      return
+    case impliesNotNil(tracked.guards, n)
+    of impUnknown:
+      message(n.info, errGenerated,
+              "cannot prove '$1' is not nil" % n.renderTree)
+    of impNo:
+      message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
+    of impYes: discard
+
+proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
+  addEffect(tracked, createRaise(n))
+  addTag(tracked, createTag(n))
+  let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
+                  else: op.lockLevel
+  #if lockLevel == UnknownLockLevel:
+  #  message(n.info, warnUser, "had to assume the worst here")
+  mergeLockLevels(tracked, n, lockLevel)
+
+proc isOwnedProcVar(n: PNode; owner: PSym): bool =
+  # XXX prove the soundness of this effect system rule
+  result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner
+
+proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
+  let a = skipConvAndClosure(n)
+  let op = a.typ
+  if op != nil and op.kind == tyProc and n.kind != nkNilLit:
+    internalAssert op.n.sons[0].kind == nkEffectList
+    var effectList = op.n.sons[0]
+    let s = n.skipConv
+    if s.kind == nkSym and s.sym.kind in routineKinds:
+      propagateEffects(tracked, n, s.sym)
+    elif effectList.len == 0:
+      if isForwardedProc(n):
+        # we have no explicit effects but it's a forward declaration and so it's
+        # stated there are no additional effects, so simply propagate them:
+        propagateEffects(tracked, n, n.sym)
+      elif not isOwnedProcVar(a, tracked.owner):
+        # we have no explicit effects so assume the worst:
+        assumeTheWorst(tracked, n, op)
+      # assume GcUnsafe unless in its type; 'forward' does not matter:
+      if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
+        if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+        markGcUnsafe(tracked, a)
+    else:
+      mergeEffects(tracked, effectList.sons[exceptionEffects], n)
+      mergeTags(tracked, effectList.sons[tagEffects], n)
+      if notGcSafe(op):
+        if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
+        markGcUnsafe(tracked, a)
+  notNilCheck(tracked, n, paramType)
+
+proc breaksBlock(n: PNode): bool =
+  case n.kind
+  of nkStmtList, nkStmtListExpr:
+    for c in n:
+      if breaksBlock(c): return true
+  of nkBreakStmt, nkReturnStmt, nkRaiseStmt:
+    return true
+  of nkCallKinds:
+    if n.sons[0].kind == nkSym and sfNoReturn in n.sons[0].sym.flags:
+      return true
+  else:
+    discard
+
+proc trackCase(tracked: PEffects, n: PNode) =
+  track(tracked, n.sons[0])
+  let oldState = tracked.init.len
+  let oldFacts = tracked.guards.len
+  let stringCase = skipTypes(n.sons[0].typ,
+        abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
+  let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
+        warnProveField in gNotes
+  var inter: TIntersection = @[]
+  var toCover = 0
+  for i in 1.. <n.len:
+    let branch = n.sons[i]
+    setLen(tracked.init, oldState)
+    if interesting:
+      setLen(tracked.guards, oldFacts)
+      addCaseBranchFacts(tracked.guards, n, i)
+    for i in 0 .. <branch.len:
+      track(tracked, branch.sons[i])
+    if not breaksBlock(branch.lastSon): inc toCover
+    for i in oldState.. <tracked.init.len:
+      addToIntersection(inter, tracked.init[i])
+
+  setLen(tracked.init, oldState)
+  if not stringCase or lastSon(n).kind == nkElse:
+    for id, count in items(inter):
+      if count >= toCover: tracked.init.add id
+    # else we can't merge
+  setLen(tracked.guards, oldFacts)
+
+proc trackIf(tracked: PEffects, n: PNode) =
+  track(tracked, n.sons[0].sons[0])
+  let oldFacts = tracked.guards.len
+  addFact(tracked.guards, n.sons[0].sons[0])
+  let oldState = tracked.init.len
+
+  var inter: TIntersection = @[]
+  var toCover = 0
+  track(tracked, n.sons[0].sons[1])
+  if not breaksBlock(n.sons[0].sons[1]): inc toCover
+  for i in oldState.. <tracked.init.len:
+    addToIntersection(inter, tracked.init[i])
+
+  for i in 1.. <n.len:
+    let branch = n.sons[i]
+    setLen(tracked.guards, oldFacts)
+    for j in 0..i-1:
+      addFactNeg(tracked.guards, n.sons[j].sons[0])
+    if branch.len > 1:
+      addFact(tracked.guards, branch.sons[0])
+    setLen(tracked.init, oldState)
+    for i in 0 .. <branch.len:
+      track(tracked, branch.sons[i])
+    if not breaksBlock(branch.lastSon): inc toCover
+    for i in oldState.. <tracked.init.len:
+      addToIntersection(inter, tracked.init[i])
+  setLen(tracked.init, oldState)
+  if lastSon(n).len == 1:
+    for id, count in items(inter):
+      if count >= toCover: tracked.init.add id
+    # else we can't merge as it is not exhaustive
+  setLen(tracked.guards, oldFacts)
+
+proc trackBlock(tracked: PEffects, n: PNode) =
+  if n.kind in {nkStmtList, nkStmtListExpr}:
+    var oldState = -1
+    for i in 0.. <n.len:
+      if hasSubnodeWith(n.sons[i], nkBreakStmt):
+        # block:
+        #   x = def
+        #   if ...: ... break # some nested break
+        #   y = def
+        # --> 'y' not defined after block!
+        if oldState < 0: oldState = tracked.init.len
+      track(tracked, n.sons[i])
+    if oldState > 0: setLen(tracked.init, oldState)
+  else:
+    track(tracked, n)
+
+proc isTrue*(n: PNode): bool =
+  n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
+    n.kind == nkIntLit and n.intVal != 0
+
+proc paramType(op: PType, i: int): PType =
+  if op != nil and i < op.len: result = op.sons[i]
+
+proc cstringCheck(tracked: PEffects; n: PNode) =
+  if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
+      a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
+    message(n.info, warnUnsafeCode, renderTree(n))
+
+proc track(tracked: PEffects, n: PNode) =
+  case n.kind
+  of nkSym:
+    useVar(tracked, n)
+  of nkRaiseStmt:
+    n.sons[0].info = n.info
+    #throws(tracked.exc, n.sons[0])
+    addEffect(tracked, n.sons[0], useLineInfo=false)
+    for i in 0 .. <safeLen(n):
+      track(tracked, n.sons[i])
+  of nkCallKinds:
+    # p's effects are ours too:
+    let a = n.sons[0]
+    let op = a.typ
+    # XXX: in rare situations, templates and macros will reach here after
+    # calling getAst(templateOrMacro()). Currently, templates and macros
+    # are indistinguishable from normal procs (both have tyProc type) and
+    # we can detect them only by checking for attached nkEffectList.
+    if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
+      if a.kind == nkSym:
+        if a.sym == tracked.owner: tracked.isRecursive = true
+        # even for recursive calls we need to check the lock levels (!):
+        mergeLockLevels(tracked, n, a.sym.getLockLevel)
+      else:
+        mergeLockLevels(tracked, n, op.lockLevel)
+      var effectList = op.n.sons[0]
+      if a.kind == nkSym and a.sym.kind == skMethod:
+        propagateEffects(tracked, n, a.sym)
+      elif effectList.len == 0:
+        if isForwardedProc(a):
+          propagateEffects(tracked, n, a.sym)
+        elif isIndirectCall(a, tracked.owner):
+          assumeTheWorst(tracked, n, op)
+      else:
+        mergeEffects(tracked, effectList.sons[exceptionEffects], n)
+        mergeTags(tracked, effectList.sons[tagEffects], n)
+        if notGcSafe(op) and not importedFromC(a):
+          # and it's not a recursive call:
+          if not (a.kind == nkSym and a.sym == tracked.owner):
+            warnAboutGcUnsafe(n)
+            markGcUnsafe(tracked, a)
+    for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
+    if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
+      # may not look like an assignment, but it is:
+      initVarViaNew(tracked, n.sons[1])
+    for i in 0 .. <safeLen(n):
+      track(tracked, n.sons[i])
+  of nkDotExpr:
+    guardDotAccess(tracked, n)
+    for i in 0 .. <len(n): track(tracked, n.sons[i])
+  of nkCheckedFieldExpr:
+    track(tracked, n.sons[0])
+    if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
+  of nkTryStmt: trackTryStmt(tracked, n)
+  of nkPragma: trackPragmaStmt(tracked, n)
+  of nkAsgn, nkFastAsgn:
+    track(tracked, n.sons[1])
+    initVar(tracked, n.sons[0], volatileCheck=true)
+    invalidateFacts(tracked.guards, n.sons[0])
+    track(tracked, n.sons[0])
+    addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
+    notNilCheck(tracked, n.sons[1], n.sons[0].typ)
+    when false: cstringCheck(tracked, n)
+  of nkVarSection, nkLetSection:
+    for child in n:
+      let last = lastSon(child)
+      if last.kind != nkEmpty: track(tracked, last)
+      if child.kind == nkIdentDefs and last.kind != nkEmpty:
+        for i in 0 .. child.len-3:
+          initVar(tracked, child.sons[i], volatileCheck=false)
+          addAsgnFact(tracked.guards, child.sons[i], last)
+          notNilCheck(tracked, last, child.sons[i].typ)
+      # since 'var (a, b): T = ()' is not even allowed, there is always type
+      # inference for (a, b) and thus no nil checking is necessary.
+  of nkCaseStmt: trackCase(tracked, n)
+  of nkIfStmt, nkIfExpr: trackIf(tracked, n)
+  of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n.sons[1])
+  of nkWhileStmt:
+    track(tracked, n.sons[0])
+    # 'while true' loop?
+    if isTrue(n.sons[0]):
+      trackBlock(tracked, n.sons[1])
+    else:
+      # loop may never execute:
+      let oldState = tracked.init.len
+      let oldFacts = tracked.guards.len
+      addFact(tracked.guards, n.sons[0])
+      track(tracked, n.sons[1])
+      setLen(tracked.init, oldState)
+      setLen(tracked.guards, oldFacts)
+  of nkForStmt, nkParForStmt:
+    # we are very conservative here and assume the loop is never executed:
+    let oldState = tracked.init.len
+    for i in 0 .. <len(n):
+      track(tracked, n.sons[i])
+    setLen(tracked.init, oldState)
+  of nkObjConstr:
+    track(tracked, n.sons[0])
+    let oldFacts = tracked.guards.len
+    for i in 1 .. <len(n):
+      let x = n.sons[i]
+      track(tracked, x)
+      if sfDiscriminant in x.sons[0].sym.flags:
+        addDiscriminantFact(tracked.guards, x)
+    setLen(tracked.guards, oldFacts)
+  of nkPragmaBlock:
+    let pragmaList = n.sons[0]
+    let oldLocked = tracked.locked.len
+    let oldLockLevel = tracked.currLockLevel
+    for i in 0 .. <pragmaList.len:
+      if whichPragma(pragmaList.sons[i]) == wLocks:
+        lockLocations(tracked, pragmaList.sons[i])
+    track(tracked, n.lastSon)
+    setLen(tracked.locked, oldLocked)
+    tracked.currLockLevel = oldLockLevel
+  of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
+      nkMacroDef, nkTemplateDef, nkLambda, nkDo:
+    discard
+  else:
+    for i in 0 .. <safeLen(n): track(tracked, n.sons[i])
+
+proc subtypeRelation(spec, real: PNode): bool =
+  result = safeInheritanceDiff(real.excType, spec.typ) <= 0
+
+proc symbolPredicate(spec, real: PNode): bool =
+  result = real.sym.id == spec.sym.id
+
+proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
+                     effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
+  # check that any real exception is listed in 'spec'; mark those as used;
+  # report any unused exception
+  var used = initIntSet()
+  for r in items(real):
+    block search:
+      for s in 0 .. <spec.len:
+        if effectPredicate(spec[s], r):
+          used.incl(s)
+          break search
+      # XXX call graph analysis would be nice here!
+      pushInfoContext(spec.info)
+      localError(r.info, errGenerated, msg & typeToString(r.typ))
+      popInfoContext()
+  # hint about unnecessarily listed exception types:
+  if hints:
+    for s in 0 .. <spec.len:
+      if not used.contains(s):
+        message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
+
+proc checkMethodEffects*(disp, branch: PSym) =
+  ## checks for consistent effects for multi methods.
+  let actual = branch.typ.n.sons[0]
+  if actual.len != effectListLen: return
+
+  let p = disp.ast.sons[pragmasPos]
+  let raisesSpec = effectSpec(p, wRaises)
+  if not isNil(raisesSpec):
+    checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects],
+      "can raise an unlisted exception: ", hints=off, subtypeRelation)
+  let tagsSpec = effectSpec(p, wTags)
+  if not isNil(tagsSpec):
+    checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
+      "can have an unlisted effect: ", hints=off, subtypeRelation)
+  if sfThread in disp.flags and notGcSafe(branch.typ):
+    localError(branch.info, "base method is GC-safe, but '$1' is not" %
+                                branch.name.s)
+  if branch.typ.lockLevel > disp.typ.lockLevel:
+    when true:
+      message(branch.info, warnLockLevel,
+        "base method has lock level $1, but dispatcher has $2" %
+          [$branch.typ.lockLevel, $disp.typ.lockLevel])
+    else:
+      # XXX make this an error after bigbreak has been released:
+      localError(branch.info,
+        "base method has lock level $1, but dispatcher has $2" %
+          [$branch.typ.lockLevel, $disp.typ.lockLevel])
+
+proc setEffectsForProcType*(t: PType, n: PNode) =
+  var effects = t.n.sons[0]
+  internalAssert t.kind == tyProc and effects.kind == nkEffectList
+
+  let
+    raisesSpec = effectSpec(n, wRaises)
+    tagsSpec = effectSpec(n, wTags)
+  if not isNil(raisesSpec) or not isNil(tagsSpec):
+    internalAssert effects.len == 0
+    newSeq(effects.sons, effectListLen)
+    if not isNil(raisesSpec):
+      effects.sons[exceptionEffects] = raisesSpec
+    if not isNil(tagsSpec):
+      effects.sons[tagEffects] = tagsSpec
+
+proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
+  newSeq(effects.sons, effectListLen)
+  effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
+  effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
+
+  t.exc = effects.sons[exceptionEffects]
+  t.tags = effects.sons[tagEffects]
+  t.owner = s
+  t.init = @[]
+  t.guards = @[]
+  t.locked = @[]
+
+proc trackProc*(s: PSym, body: PNode) =
+  var effects = s.typ.n.sons[0]
+  internalAssert effects.kind == nkEffectList
+  # effects already computed?
+  if sfForward in s.flags: return
+  if effects.len == effectListLen: return
+
+  var t: TEffects
+  initEffects(effects, s, t)
+  track(t, body)
+  if not isEmptyType(s.typ.sons[0]) and tfNeedsInit in s.typ.sons[0].flags and
+      s.kind in {skProc, skConverter, skMethod}:
+    var res = s.ast.sons[resultPos].sym # get result symbol
+    if res.id notin t.init:
+      message(body.info, warnProveInit, "result")
+  let p = s.ast.sons[pragmasPos]
+  let raisesSpec = effectSpec(p, wRaises)
+  if not isNil(raisesSpec):
+    checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ",
+                    hints=on, subtypeRelation)
+    # after the check, use the formal spec:
+    effects.sons[exceptionEffects] = raisesSpec
+
+  let tagsSpec = effectSpec(p, wTags)
+  if not isNil(tagsSpec):
+    checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
+                    hints=off, subtypeRelation)
+    # after the check, use the formal spec:
+    effects.sons[tagEffects] = tagsSpec
+
+  if sfThread in s.flags and t.gcUnsafe:
+    if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
+      #localError(s.info, "'$1' is not GC-safe" % s.name.s)
+      listGcUnsafety(s, onlyWarning=false)
+    else:
+      listGcUnsafety(s, onlyWarning=true)
+      #localError(s.info, warnGcUnsafe2, s.name.s)
+  if not t.gcUnsafe:
+    s.typ.flags.incl tfGcSafe
+  if s.typ.lockLevel == UnspecifiedLockLevel:
+    s.typ.lockLevel = t.maxLockLevel
+  elif t.maxLockLevel > s.typ.lockLevel:
+    #localError(s.info,
+    message(s.info, warnLockLevel,
+      "declared lock level is $1, but real lock level is $2" %
+        [$s.typ.lockLevel, $t.maxLockLevel])
+
+proc trackTopLevelStmt*(module: PSym; n: PNode) =
+  if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
+                nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
+    return
+  var effects = newNode(nkEffectList, n.info)
+  var t: TEffects
+  initEffects(effects, module, t)
+  t.isToplevel = true
+  track(t, n)
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
new file mode 100644
index 000000000..c355a5bf1
--- /dev/null
+++ b/compiler/semstmts.nim
@@ -0,0 +1,1413 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## this module does the semantic checking of statements
+#  included from sem.nim
+
+var enforceVoidContext = PType(kind: tyStmt)
+
+proc semDiscard(c: PContext, n: PNode): PNode =
+  result = n
+  checkSonsLen(n, 1)
+  if n.sons[0].kind != nkEmpty:
+    n.sons[0] = semExprWithType(c, n.sons[0])
+    if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard)
+
+proc semBreakOrContinue(c: PContext, n: PNode): PNode =
+  result = n
+  checkSonsLen(n, 1)
+  if n.sons[0].kind != nkEmpty:
+    if n.kind != nkContinueStmt:
+      var s: PSym
+      case n.sons[0].kind
+      of nkIdent: s = lookUp(c, n.sons[0])
+      of nkSym: s = n.sons[0].sym
+      else: illFormedAst(n)
+      if s.kind == skLabel and s.owner.id == c.p.owner.id:
+        var x = newSymNode(s)
+        x.info = n.info
+        incl(s.flags, sfUsed)
+        n.sons[0] = x
+        suggestSym(x.info, s)
+        styleCheckUse(x.info, s)
+      else:
+        localError(n.info, errInvalidControlFlowX, s.name.s)
+    else:
+      localError(n.info, errGenerated, "'continue' cannot have a label")
+  elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
+    localError(n.info, errInvalidControlFlowX,
+               renderTree(n, {renderNoComments}))
+
+proc semAsm(con: PContext, n: PNode): PNode =
+  checkSonsLen(n, 2)
+  var marker = pragmaAsm(con, n.sons[0])
+  if marker == '\0': marker = '`' # default marker
+  result = semAsmOrEmit(con, n, marker)
+
+proc semWhile(c: PContext, n: PNode): PNode =
+  result = n
+  checkSonsLen(n, 2)
+  openScope(c)
+  n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0]))
+  inc(c.p.nestedLoopCounter)
+  n.sons[1] = semStmt(c, n.sons[1])
+  dec(c.p.nestedLoopCounter)
+  closeScope(c)
+  if n.sons[1].typ == enforceVoidContext:
+    result.typ = enforceVoidContext
+
+proc toCover(t: PType): BiggestInt =
+  var t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
+  if t2.kind == tyEnum and enumHasHoles(t2):
+    result = sonsLen(t2.n)
+  else:
+    result = lengthOrd(skipTypes(t, abstractVar-{tyTypeDesc}))
+
+proc performProcvarCheck(c: PContext, n: PNode, s: PSym) =
+  ## Checks that the given symbol is a proper procedure variable, meaning
+  ## that it
+  var smoduleId = getModule(s).id
+  if sfProcvar notin s.flags and s.typ.callConv == ccDefault and
+      smoduleId != c.module.id:
+    block outer:
+      for module in c.friendModules:
+        if smoduleId == module.id:
+          break outer
+      localError(n.info, errXCannotBePassedToProcVar, s.name.s)
+
+proc semProcvarCheck(c: PContext, n: PNode) =
+  let n = n.skipConv
+  if n.kind == nkSym and n.sym.kind in {skProc, skMethod, skConverter,
+                                        skIterator, skClosureIterator}:
+    performProcvarCheck(c, n, n.sym)
+
+proc semProc(c: PContext, n: PNode): PNode
+
+include semdestruct
+
+proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
+  if efAllowDestructor notin flags and
+      n.kind in nkCallKinds+{nkObjConstr,nkBracket}:
+    if instantiateDestructor(c, n.typ) != nil:
+      localError(n.info, warnDestructor)
+  # This still breaks too many things:
+  when false:
+    if efDetermineType notin flags and n.typ.kind == tyTypeDesc and
+        c.p.owner.kind notin {skTemplate, skMacro}:
+      localError(n.info, errGenerated, "value expected, but got a type")
+
+proc semExprBranch(c: PContext, n: PNode): PNode =
+  result = semExpr(c, n)
+  if result.typ != nil:
+    # XXX tyGenericInst here?
+    semProcvarCheck(c, result)
+    if result.typ.kind == tyVar: result = newDeref(result)
+    semDestructorCheck(c, result, {})
+
+proc semExprBranchScope(c: PContext, n: PNode): PNode =
+  openScope(c)
+  result = semExprBranch(c, n)
+  closeScope(c)
+
+const
+  skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
+    nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
+    nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr}
+
+proc implicitlyDiscardable(n: PNode): bool =
+  var n = n
+  while n.kind in skipForDiscardable: n = n.lastSon
+  result = isCallExpr(n) and n.sons[0].kind == nkSym and
+           sfDiscardable in n.sons[0].sym.flags
+
+proc fixNilType(n: PNode) =
+  if isAtom(n):
+    if n.kind != nkNilLit and n.typ != nil:
+      localError(n.info, errDiscardValueX, n.typ.typeToString)
+  elif n.kind in {nkStmtList, nkStmtListExpr}:
+    n.kind = nkStmtList
+    for it in n: fixNilType(it)
+  n.typ = nil
+
+proc discardCheck(c: PContext, result: PNode) =
+  if c.inTypeClass > 0: return
+  if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
+    if result.kind == nkNilLit:
+      result.typ = nil
+      message(result.info, warnNilStatement)
+    elif implicitlyDiscardable(result):
+      var n = result
+      result.typ = nil
+      while n.kind in skipForDiscardable:
+        n = n.lastSon
+        n.typ = nil
+    elif result.typ.kind != tyError and gCmd != cmdInteractive:
+      if result.typ.kind == tyNil:
+        fixNilType(result)
+        message(result.info, warnNilStatement)
+      else:
+        var n = result
+        while n.kind in skipForDiscardable: n = n.lastSon
+        localError(n.info, errDiscardValueX, result.typ.typeToString)
+
+proc semIf(c: PContext, n: PNode): PNode =
+  result = n
+  var typ = commonTypeBegin
+  var hasElse = false
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    if it.len == 2:
+      when newScopeForIf: openScope(c)
+      it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
+      when not newScopeForIf: openScope(c)
+      it.sons[1] = semExprBranch(c, it.sons[1])
+      typ = commonType(typ, it.sons[1].typ)
+      closeScope(c)
+    elif it.len == 1:
+      hasElse = true
+      it.sons[0] = semExprBranchScope(c, it.sons[0])
+      typ = commonType(typ, it.sons[0].typ)
+    else: illFormedAst(it)
+  if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
+    for it in n: discardCheck(c, it.lastSon)
+    result.kind = nkIfStmt
+    # propagate any enforced VoidContext:
+    if typ == enforceVoidContext: result.typ = enforceVoidContext
+  else:
+    for it in n:
+      let j = it.len-1
+      it.sons[j] = fitNode(c, typ, it.sons[j])
+    result.kind = nkIfExpr
+    result.typ = typ
+
+proc semCase(c: PContext, n: PNode): PNode =
+  result = n
+  checkMinSonsLen(n, 2)
+  openScope(c)
+  n.sons[0] = semExprWithType(c, n.sons[0])
+  var chckCovered = false
+  var covered: BiggestInt = 0
+  var typ = commonTypeBegin
+  var hasElse = false
+  var notOrdinal = false
+  case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
+  of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
+    chckCovered = true
+  of tyFloat..tyFloat128, tyString, tyError:
+    notOrdinal = true
+  else:
+    localError(n.info, errSelectorMustBeOfCertainTypes)
+    return
+  for i in countup(1, sonsLen(n) - 1):
+    var x = n.sons[i]
+    case x.kind
+    of nkOfBranch:
+      checkMinSonsLen(x, 2)
+      semCaseBranch(c, n, x, i, covered)
+      var last = sonsLen(x)-1
+      x.sons[last] = semExprBranchScope(c, x.sons[last])
+      typ = commonType(typ, x.sons[last].typ)
+    of nkElifBranch:
+      chckCovered = false
+      checkSonsLen(x, 2)
+      when newScopeForIf: openScope(c)
+      x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0]))
+      when not newScopeForIf: openScope(c)
+      x.sons[1] = semExprBranch(c, x.sons[1])
+      typ = commonType(typ, x.sons[1].typ)
+      closeScope(c)
+    of nkElse:
+      chckCovered = false
+      checkSonsLen(x, 1)
+      x.sons[0] = semExprBranchScope(c, x.sons[0])
+      typ = commonType(typ, x.sons[0].typ)
+      hasElse = true
+    else:
+      illFormedAst(x)
+  if notOrdinal and not hasElse:
+    message(n.info, warnDeprecated,
+            "use 'else: discard'; non-ordinal case without 'else'")
+  if chckCovered:
+    if covered == toCover(n.sons[0].typ):
+      hasElse = true
+    else:
+      localError(n.info, errNotAllCasesCovered)
+  closeScope(c)
+  if isEmptyType(typ) or typ.kind == tyNil or not hasElse:
+    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
+    # propagate any enforced VoidContext:
+    if typ == enforceVoidContext:
+      result.typ = enforceVoidContext
+  else:
+    for i in 1..n.len-1:
+      var it = n.sons[i]
+      let j = it.len-1
+      it.sons[j] = fitNode(c, typ, it.sons[j])
+    result.typ = typ
+
+proc semTry(c: PContext, n: PNode): PNode =
+  result = n
+  inc c.p.inTryStmt
+  checkMinSonsLen(n, 2)
+  var typ = commonTypeBegin
+  n.sons[0] = semExprBranchScope(c, n.sons[0])
+  typ = commonType(typ, n.sons[0].typ)
+  var check = initIntSet()
+  var last = sonsLen(n) - 1
+  for i in countup(1, last):
+    var a = n.sons[i]
+    checkMinSonsLen(a, 1)
+    var length = sonsLen(a)
+    if a.kind == nkExceptBranch:
+      # so that ``except [a, b, c]`` is supported:
+      if length == 2 and a.sons[0].kind == nkBracket:
+        a.sons[0..0] = a.sons[0].sons
+        length = a.sonsLen
+
+      for j in countup(0, length-2):
+        var typ = semTypeNode(c, a.sons[j], nil)
+        if typ.kind == tyRef: typ = typ.sons[0]
+        if typ.kind != tyObject:
+          localError(a.sons[j].info, errExprCannotBeRaised)
+        a.sons[j] = newNodeI(nkType, a.sons[j].info)
+        a.sons[j].typ = typ
+        if containsOrIncl(check, typ.id):
+          localError(a.sons[j].info, errExceptionAlreadyHandled)
+    elif a.kind != nkFinally:
+      illFormedAst(n)
+    # last child of an nkExcept/nkFinally branch is a statement:
+    a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
+    if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
+    else: dec last
+  dec c.p.inTryStmt
+  if isEmptyType(typ) or typ.kind == tyNil:
+    discardCheck(c, n.sons[0])
+    for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon)
+    if typ == enforceVoidContext:
+      result.typ = enforceVoidContext
+  else:
+    if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
+    n.sons[0] = fitNode(c, typ, n.sons[0])
+    for i in 1..last:
+      var it = n.sons[i]
+      let j = it.len-1
+      it.sons[j] = fitNode(c, typ, it.sons[j])
+    result.typ = typ
+
+proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
+  result = fitNode(c, typ, n)
+  if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
+    changeType(result.sons[1], typ, check=true)
+    result = result.sons[1]
+  elif not sameType(result.typ, typ):
+    changeType(result, typ, check=false)
+
+proc findShadowedVar(c: PContext, v: PSym): PSym =
+  for scope in walkScopes(c.currentScope.parent):
+    if scope == c.topLevelScope: break
+    let shadowed = strTableGet(scope.symbols, v.name)
+    if shadowed != nil and shadowed.kind in skLocalVars:
+      return shadowed
+
+proc identWithin(n: PNode, s: PIdent): bool =
+  for i in 0 .. n.safeLen-1:
+    if identWithin(n.sons[i], s): return true
+  result = n.kind == nkSym and n.sym.name.id == s.id
+
+proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
+  if isTopLevel(c):
+    result = semIdentWithPragma(c, kind, n, {sfExported})
+    incl(result.flags, sfGlobal)
+  else:
+    result = semIdentWithPragma(c, kind, n, {})
+  suggestSym(n.info, result)
+  styleCheckDef(result)
+
+proc checkNilable(v: PSym) =
+  if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
+    if v.ast.isNil:
+      message(v.info, warnProveInit, v.name.s)
+    elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags:
+      message(v.info, warnProveInit, v.name.s)
+
+include semasgn
+
+proc addToVarSection(c: PContext; result: var PNode; orig, identDefs: PNode) =
+  # consider this:
+  #   var
+  #     x = 0
+  #     withOverloadedAssignment = foo()
+  #     y = use(withOverloadedAssignment)
+  # We need to split this into a statement list with multiple 'var' sections
+  # in order for this transformation to be correct.
+  let L = identDefs.len
+  let value = identDefs[L-1]
+  if value.typ != nil and tfHasAsgn in value.typ.flags:
+    # the spec says we need to rewrite 'var x = T()' to 'var x: T; x = T()':
+    identDefs.sons[L-1] = emptyNode
+    if result.kind != nkStmtList:
+      let oldResult = result
+      oldResult.add identDefs
+      result = newNodeI(nkStmtList, result.info)
+      result.add oldResult
+    else:
+      let o = copyNode(orig)
+      o.add identDefs
+      result.add o
+    for i in 0 .. L-3:
+      result.add overloadedAsgn(c, identDefs[i], value)
+  elif result.kind == nkStmtList:
+    let o = copyNode(orig)
+    o.add identDefs
+    result.add o
+  else:
+    result.add identDefs
+
+proc isDiscardUnderscore(v: PSym): bool =
+  if v.name.s == "_":
+    v.flags.incl(sfGenSym)
+    result = true
+
+proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
+  var b: PNode
+  result = copyNode(n)
+  var hasCompileTime = false
+  for i in countup(0, sonsLen(n)-1):
+    var a = n.sons[i]
+    if gCmd == cmdIdeTools: suggestStmt(c, a)
+    if a.kind == nkCommentStmt: continue
+    if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a)
+    checkMinSonsLen(a, 3)
+    var length = sonsLen(a)
+    var typ: PType
+    if a.sons[length-2].kind != nkEmpty:
+      typ = semTypeNode(c, a.sons[length-2], nil)
+    else:
+      typ = nil
+    var def: PNode
+    if a.sons[length-1].kind != nkEmpty:
+      def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
+      if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
+        # prevent the all too common 'var x = int' bug:
+        localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
+        def.typ = errorType(c)
+      if typ != nil:
+        if typ.isMetaType:
+          def = inferWithMetatype(c, typ, def)
+          typ = def.typ
+        else:
+          # BUGFIX: ``fitNode`` is needed here!
+          # check type compatibility between def.typ and typ
+          def = fitNode(c, typ, def)
+          #changeType(def.skipConv, typ, check=true)
+      else:
+        typ = skipIntLit(def.typ)
+        if typ.kind in {tySequence, tyArray, tySet} and
+           typ.lastSon.kind == tyEmpty:
+          localError(def.info, errCannotInferTypeOfTheLiteral,
+                     ($typ.kind).substr(2).toLower)
+    else:
+      def = ast.emptyNode
+      if symkind == skLet: localError(a.info, errLetNeedsInit)
+
+    # this can only happen for errornous var statements:
+    if typ == nil: continue
+    typeAllowedCheck(a.info, typ, symkind)
+    var tup = skipTypes(typ, {tyGenericInst})
+    if a.kind == nkVarTuple:
+      if tup.kind != tyTuple:
+        localError(a.info, errXExpected, "tuple")
+      elif length-2 != sonsLen(tup):
+        localError(a.info, errWrongNumberOfVariables)
+      else:
+        b = newNodeI(nkVarTuple, a.info)
+        newSons(b, length)
+        b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator
+        b.sons[length-1] = def
+        addToVarSection(c, result, n, b)
+    elif tup.kind == tyTuple and def.kind == nkPar and
+        a.kind == nkIdentDefs and a.len > 3:
+      message(a.info, warnEachIdentIsTuple)
+
+    for j in countup(0, length-3):
+      var v = semIdentDef(c, a.sons[j], symkind)
+      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+        addInterfaceDecl(c, v)
+      when oKeepVariableNames:
+        if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
+        else:
+          let shadowed = findShadowedVar(c, v)
+          if shadowed != nil:
+            shadowed.flags.incl(sfShadowed)
+            if shadowed.kind == skResult and sfGenSym notin v.flags:
+              message(a.info, warnResultShadowed)
+            # a shadowed variable is an error unless it appears on the right
+            # side of the '=':
+            if warnShadowIdent in gNotes and not identWithin(def, v.name):
+              message(a.info, warnShadowIdent, v.name.s)
+      if a.kind != nkVarTuple:
+        if def != nil and def.kind != nkEmpty:
+          # this is needed for the evaluation pass and for the guard checking:
+          v.ast = def
+          if sfThread in v.flags: localError(def.info, errThreadvarCannotInit)
+        v.typ = typ
+        b = newNodeI(nkIdentDefs, a.info)
+        if importantComments():
+          # keep documentation information:
+          b.comment = a.comment
+        addSon(b, newSymNode(v))
+        addSon(b, a.sons[length-2])      # keep type desc for doc generator
+        addSon(b, copyTree(def))
+        addToVarSection(c, result, n, b)
+      else:
+        if def.kind == nkPar: v.ast = def[j]
+        v.typ = tup.sons[j]
+        b.sons[j] = newSymNode(v)
+      checkNilable(v)
+      if sfCompileTime in v.flags: hasCompileTime = true
+  if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
+
+proc semConst(c: PContext, n: PNode): PNode =
+  result = copyNode(n)
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if gCmd == cmdIdeTools: suggestStmt(c, a)
+    if a.kind == nkCommentStmt: continue
+    if (a.kind != nkConstDef): illFormedAst(a)
+    checkSonsLen(a, 3)
+    var v = semIdentDef(c, a.sons[0], skConst)
+    var typ: PType = nil
+    if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
+
+    var def = semConstExpr(c, a.sons[2])
+    if def == nil:
+      localError(a.sons[2].info, errConstExprExpected)
+      continue
+    # check type compatibility between def.typ and typ:
+    if typ != nil:
+      def = fitRemoveHiddenConv(c, typ, def)
+    else:
+      typ = def.typ
+    if typ == nil:
+      localError(a.sons[2].info, errConstExprExpected)
+      continue
+    if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit:
+      localError(a.info, errXisNoType, typeToString(typ))
+      continue
+    v.typ = typ
+    v.ast = def               # no need to copy
+    if sfGenSym notin v.flags: addInterfaceDecl(c, v)
+    var b = newNodeI(nkConstDef, a.info)
+    if importantComments(): b.comment = a.comment
+    addSon(b, newSymNode(v))
+    addSon(b, a.sons[1])
+    addSon(b, copyTree(def))
+    addSon(result, b)
+
+include semfields
+
+proc addForVarDecl(c: PContext, v: PSym) =
+  if warnShadowIdent in gNotes:
+    let shadowed = findShadowedVar(c, v)
+    if shadowed != nil:
+      # XXX should we do this here?
+      #shadowed.flags.incl(sfShadowed)
+      message(v.info, warnShadowIdent, v.name.s)
+  addDecl(c, v)
+
+proc symForVar(c: PContext, n: PNode): PSym =
+  let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
+  result = newSymG(skForVar, m, c)
+  styleCheckDef(result)
+
+proc semForVars(c: PContext, n: PNode): PNode =
+  result = n
+  var length = sonsLen(n)
+  let iterBase = n.sons[length-2].typ.skipTypes({tyIter})
+  var iter = skipTypes(iterBase, {tyGenericInst})
+  # length == 3 means that there is one for loop variable
+  # and thus no tuple unpacking:
+  if iter.kind != tyTuple or length == 3:
+    if length == 3:
+      var v = symForVar(c, n.sons[0])
+      if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
+      # BUGFIX: don't use `iter` here as that would strip away
+      # the ``tyGenericInst``! See ``tests/compile/tgeneric.nim``
+      # for an example:
+      v.typ = iterBase
+      n.sons[0] = newSymNode(v)
+      if sfGenSym notin v.flags: addForVarDecl(c, v)
+    else:
+      localError(n.info, errWrongNumberOfVariables)
+  elif length-2 != sonsLen(iter):
+    localError(n.info, errWrongNumberOfVariables)
+  else:
+    for i in countup(0, length - 3):
+      var v = symForVar(c, n.sons[i])
+      if getCurrOwner().kind == skModule: incl(v.flags, sfGlobal)
+      v.typ = iter.sons[i]
+      n.sons[i] = newSymNode(v)
+      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
+        addForVarDecl(c, v)
+  inc(c.p.nestedLoopCounter)
+  n.sons[length-1] = semStmt(c, n.sons[length-1])
+  dec(c.p.nestedLoopCounter)
+
+proc implicitIterator(c: PContext, it: string, arg: PNode): PNode =
+  result = newNodeI(nkCall, arg.info)
+  result.add(newIdentNode(it.getIdent, arg.info))
+  if arg.typ != nil and arg.typ.kind == tyVar:
+    result.add newDeref(arg)
+  else:
+    result.add arg
+  result = semExprNoDeref(c, result, {efWantIterator})
+
+proc semFor(c: PContext, n: PNode): PNode =
+  result = n
+  checkMinSonsLen(n, 3)
+  var length = sonsLen(n)
+  openScope(c)
+  n.sons[length-2] = semExprNoDeref(c, n.sons[length-2], {efWantIterator})
+  var call = n.sons[length-2]
+  let isCallExpr = call.kind in nkCallKinds
+  if isCallExpr and call[0].kind == nkSym and
+      call[0].sym.magic in {mFields, mFieldPairs, mOmpParFor}:
+    if call.sons[0].sym.magic == mOmpParFor:
+      result = semForVars(c, n)
+      result.kind = nkParForStmt
+    else:
+      result = semForFields(c, n, call.sons[0].sym.magic)
+  elif (isCallExpr and call.sons[0].typ.callConv == ccClosure) or
+      call.typ.kind == tyIter:
+    # first class iterator:
+    result = semForVars(c, n)
+  elif not isCallExpr or call.sons[0].kind != nkSym or
+      call.sons[0].sym.kind notin skIterators:
+    if length == 3:
+      n.sons[length-2] = implicitIterator(c, "items", n.sons[length-2])
+    elif length == 4:
+      n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2])
+    else:
+      localError(n.sons[length-2].info, errIteratorExpected)
+    result = semForVars(c, n)
+  else:
+    result = semForVars(c, n)
+  # propagate any enforced VoidContext:
+  if n.sons[length-1].typ == enforceVoidContext:
+    result.typ = enforceVoidContext
+  closeScope(c)
+
+proc semRaise(c: PContext, n: PNode): PNode =
+  result = n
+  checkSonsLen(n, 1)
+  if n.sons[0].kind != nkEmpty:
+    n.sons[0] = semExprWithType(c, n.sons[0])
+    var typ = n.sons[0].typ
+    if typ.kind != tyRef or typ.sons[0].kind != tyObject:
+      localError(n.info, errExprCannotBeRaised)
+
+proc addGenericParamListToScope(c: PContext, n: PNode) =
+  if n.kind != nkGenericParams: illFormedAst(n)
+  for i in countup(0, sonsLen(n)-1):
+    var a = n.sons[i]
+    if a.kind == nkSym: addDecl(c, a.sym)
+    else: illFormedAst(a)
+
+proc typeSectionLeftSidePass(c: PContext, n: PNode) =
+  # process the symbols on the left side for the whole type section, before
+  # we even look at the type definitions on the right
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if gCmd == cmdIdeTools: suggestStmt(c, a)
+    if a.kind == nkCommentStmt: continue
+    if a.kind != nkTypeDef: illFormedAst(a)
+    checkSonsLen(a, 3)
+    var s = semIdentDef(c, a.sons[0], skType)
+    s.typ = newTypeS(tyForward, c)
+    s.typ.sym = s             # process pragmas:
+    if a.sons[0].kind == nkPragmaExpr:
+      pragma(c, s, a.sons[0].sons[1], typePragmas)
+    # add it here, so that recursive types are possible:
+    if sfGenSym notin s.flags: addInterfaceDecl(c, s)
+    a.sons[0] = newSymNode(s)
+
+proc typeSectionRightSidePass(c: PContext, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if a.kind == nkCommentStmt: continue
+    if (a.kind != nkTypeDef): illFormedAst(a)
+    checkSonsLen(a, 3)
+    if (a.sons[0].kind != nkSym): illFormedAst(a)
+    var s = a.sons[0].sym
+    if s.magic == mNone and a.sons[2].kind == nkEmpty:
+      localError(a.info, errImplOfXexpected, s.name.s)
+    if s.magic != mNone: processMagicType(c, s)
+    if a.sons[1].kind != nkEmpty:
+      # We have a generic type declaration here. In generic types,
+      # symbol lookup needs to be done here.
+      openScope(c)
+      pushOwner(s)
+      if s.magic == mNone: s.typ.kind = tyGenericBody
+      # XXX for generic type aliases this is not correct! We need the
+      # underlying Id really:
+      #
+      # type
+      #   TGObj[T] = object
+      #   TAlias[T] = TGObj[T]
+      #
+      s.typ.n = semGenericParamList(c, a.sons[1], s.typ)
+      a.sons[1] = s.typ.n
+      s.typ.size = -1 # could not be computed properly
+      # we fill it out later. For magic generics like 'seq', it won't be filled
+      # so we use tyEmpty instead of nil to not crash for strange conversions
+      # like: mydata.seq
+      rawAddSon(s.typ, newTypeS(tyNone, c))
+      s.ast = a
+      inc c.inGenericContext
+      var body = semTypeNode(c, a.sons[2], nil)
+      dec c.inGenericContext
+      if body != nil:
+        body.sym = s
+        body.size = -1 # could not be computed properly
+        s.typ.sons[sonsLen(s.typ) - 1] = body
+      popOwner()
+      closeScope(c)
+    elif a.sons[2].kind != nkEmpty:
+      # process the type's body:
+      pushOwner(s)
+      var t = semTypeNode(c, a.sons[2], s.typ)
+      if s.typ == nil:
+        s.typ = t
+      elif t != s.typ:
+        # this can happen for e.g. tcan_alias_specialised_generic:
+        assignType(s.typ, t)
+        #debug s.typ
+      s.ast = a
+      popOwner()
+    let aa = a.sons[2]
+    if aa.kind in {nkRefTy, nkPtrTy} and aa.len == 1 and
+       aa.sons[0].kind == nkObjectTy:
+      # give anonymous object a dummy symbol:
+      var st = s.typ
+      if st.kind == tyGenericBody: st = st.lastSon
+      internalAssert st.kind in {tyPtr, tyRef}
+      internalAssert st.lastSon.sym == nil
+      st.lastSon.sym = newSym(skType, getIdent(s.name.s & ":ObjectType"),
+                              getCurrOwner(), s.info)
+
+proc checkForMetaFields(n: PNode) =
+  template checkMeta(t) =
+    if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
+      localError(n.info, errTIsNotAConcreteType, t.typeToString)
+
+  if n.isNil: return
+  case n.kind
+  of nkRecList, nkRecCase:
+    for s in n: checkForMetaFields(s)
+  of nkOfBranch, nkElse:
+    checkForMetaFields(n.lastSon)
+  of nkSym:
+    let t = n.sym.typ
+    case t.kind
+    of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
+       tyProc, tyGenericInvocation, tyGenericInst:
+      let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
+      for i in start .. <t.sons.len:
+        checkMeta(t.sons[i])
+    else:
+      checkMeta(t)
+  else:
+    internalAssert false
+
+proc typeSectionFinalPass(c: PContext, n: PNode) =
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if a.kind == nkCommentStmt: continue
+    if a.sons[0].kind != nkSym: illFormedAst(a)
+    var s = a.sons[0].sym
+    # compute the type's size and check for illegal recursions:
+    if a.sons[1].kind == nkEmpty:
+      if a.sons[2].kind in {nkSym, nkIdent, nkAccQuoted}:
+        # type aliases are hard:
+        #MessageOut('for type ' + typeToString(s.typ));
+        var t = semTypeNode(c, a.sons[2], nil)
+        if t.kind in {tyObject, tyEnum}:
+          assignType(s.typ, t)
+          s.typ.id = t.id     # same id
+      checkConstructedType(s.info, s.typ)
+      if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
+        checkForMetaFields(s.typ.n)
+
+proc semTypeSection(c: PContext, n: PNode): PNode =
+  ## Processes a type section. This must be done in separate passes, in order
+  ## to allow the type definitions in the section to reference each other
+  ## without regard for the order of their definitions.
+  typeSectionLeftSidePass(c, n)
+  typeSectionRightSidePass(c, n)
+  typeSectionFinalPass(c, n)
+  result = n
+
+proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) =
+  s.typ = semProcTypeNode(c, n, genericParams, nil, s.kind)
+  if s.kind notin {skMacro, skTemplate}:
+    if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt:
+      localError(n.info, errGenerated, "invalid return type: 'stmt'")
+
+proc addParams(c: PContext, n: PNode, kind: TSymKind) =
+  for i in countup(1, sonsLen(n)-1):
+    if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind)
+    else: illFormedAst(n)
+
+proc semBorrow(c: PContext, n: PNode, s: PSym) =
+  # search for the correct alias:
+  var b = searchForBorrowProc(c, c.currentScope.parent, s)
+  if b != nil:
+    # store the alias:
+    n.sons[bodyPos] = newSymNode(b)
+  else:
+    localError(n.info, errNoSymbolToBorrowFromFound)
+
+proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
+  if t != nil:
+    var s = newSym(skResult, getIdent"result", getCurrOwner(), info)
+    s.typ = t
+    incl(s.flags, sfUsed)
+    addParamOrResult(c, s, owner)
+    c.p.resultSym = s
+
+proc addResultNode(c: PContext, n: PNode) =
+  if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym))
+
+proc copyExcept(n: PNode, i: int): PNode =
+  result = copyNode(n)
+  for j in 0.. <n.len:
+    if j != i: result.add(n.sons[j])
+
+proc lookupMacro(c: PContext, n: PNode): PSym =
+  if n.kind == nkSym:
+    result = n.sym
+    if result.kind notin {skMacro, skTemplate}: result = nil
+  else:
+    result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate})
+
+proc semProcAnnotation(c: PContext, prc: PNode;
+                       validPragmas: TSpecialWords): PNode =
+  var n = prc.sons[pragmasPos]
+  if n == nil or n.kind == nkEmpty: return
+  for i in countup(0, <n.len):
+    var it = n.sons[i]
+    var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
+    let m = lookupMacro(c, key)
+    if m == nil:
+      if key.kind == nkIdent and key.ident.id == ord(wDelegator):
+        if considerQuotedIdent(prc.sons[namePos]).s == "()":
+          prc.sons[namePos] = newIdentNode(idDelegator, prc.info)
+          prc.sons[pragmasPos] = copyExcept(n, i)
+        else:
+          localError(prc.info, errOnlyACallOpCanBeDelegator)
+      continue
+    # we transform ``proc p {.m, rest.}`` into ``m(do: proc p {.rest.})`` and
+    # let the semantic checker deal with it:
+    var x = newNodeI(nkCall, n.info)
+    x.add(newSymNode(m))
+    prc.sons[pragmasPos] = copyExcept(n, i)
+    if it.kind == nkExprColonExpr:
+      # pass pragma argument to the macro too:
+      x.add(it.sons[1])
+    x.add(prc)
+    # recursion assures that this works for multiple macro annotations too:
+    result = semStmt(c, x)
+    # since a proc annotation can set pragmas, we process these here again.
+    # This is required for SqueakNim-like export pragmas.
+    if result.kind in procDefs and result[namePos].kind == nkSym and
+        result[pragmasPos].kind != nkEmpty:
+      pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
+    return
+
+proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # XXX semProcAux should be good enough for this now, we will eventually
+  # remove semLambda
+  result = semProcAnnotation(c, n, lambdaPragmas)
+  if result != nil: return result
+  result = n
+  checkSonsLen(n, bodyPos + 1)
+  var s: PSym
+  if n[namePos].kind != nkSym:
+    s = newSym(skProc, idAnon, getCurrOwner(), n.info)
+    s.ast = n
+    n.sons[namePos] = newSymNode(s)
+  else:
+    s = n[namePos].sym
+  pushOwner(s)
+  openScope(c)
+  var gp: PNode
+  if n.sons[genericParamsPos].kind != nkEmpty:
+    n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
+    gp = n.sons[genericParamsPos]
+  else:
+    gp = newNodeI(nkGenericParams, n.info)
+
+  if n.sons[paramsPos].kind != nkEmpty:
+    #if n.kind == nkDo and not experimentalMode(c):
+    #  localError(n.sons[paramsPos].info,
+    #      "use the {.experimental.} pragma to enable 'do' with parameters")
+    semParamList(c, n.sons[paramsPos], gp, s)
+    # paramsTypeCheck(c, s.typ)
+    if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
+      # we have a list of implicit type parameters:
+      n.sons[genericParamsPos] = gp
+  else:
+    s.typ = newProcType(c, n.info)
+  if n.sons[pragmasPos].kind != nkEmpty:
+    pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
+  s.options = gOptions
+  if n.sons[bodyPos].kind != nkEmpty:
+    if sfImportc in s.flags:
+      localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
+    #if efDetermineType notin flags:
+    # XXX not good enough; see tnamedparamanonproc.nim
+    if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
+      pushProcCon(c, s)
+      addResult(c, s.typ.sons[0], n.info, skProc)
+      addResultNode(c, n)
+      let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
+      n.sons[bodyPos] = transformBody(c.module, semBody, s)
+      popProcCon(c)
+    elif efOperand notin flags:
+      localError(n.info, errGenericLambdaNotAllowed)
+    sideEffectsCheck(c, s)
+  else:
+    localError(n.info, errImplOfXexpected, s.name.s)
+  closeScope(c)           # close scope for parameters
+  popOwner()
+  result.typ = s.typ
+
+proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # 'do' without params produces a stmt:
+  if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
+    result = semStmt(c, n[bodyPos])
+  else:
+    result = semLambda(c, n, flags)
+
+proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
+  var n = n
+
+  n = replaceTypesInBody(c, pt, n)
+  result = n
+
+  n.sons[genericParamsPos] = emptyNode
+  n.sons[paramsPos] = n.typ.n
+
+  openScope(c)
+  var s = n.sons[namePos].sym
+  pushOwner(s)
+  addParams(c, n.typ.n, skProc)
+  pushProcCon(c, s)
+  addResult(c, n.typ.sons[0], n.info, skProc)
+  addResultNode(c, n)
+  let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
+  n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
+  popProcCon(c)
+  popOwner()
+  closeScope(c)
+
+  s.ast = result
+
+  # alternative variant (not quite working):
+  # var prc = arg[0].sym
+  # let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
+  # result = inferred.ast
+  # result.kind = arg.kind
+
+proc activate(c: PContext, n: PNode) =
+  # XXX: This proc is part of my plan for getting rid of
+  # forward declarations. stay tuned.
+  when false:
+    # well for now it breaks code ...
+    case n.kind
+    of nkLambdaKinds:
+      discard semLambda(c, n, {})
+    of nkCallKinds:
+      for i in 1 .. <n.len: activate(c, n[i])
+    else:
+      discard
+
+proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
+  if s.typ.sons[0] != nil and s.kind != skIterator:
+    addResult(c, s.typ.sons[0], n.info, s.kind)
+    addResultNode(c, n)
+
+proc semOverride(c: PContext, s: PSym, n: PNode) =
+  case s.name.s.normalize
+  of "destroy", "=destroy":
+    doDestructorStuff(c, s, n)
+    if not experimentalMode(c):
+      localError n.info, "use the {.experimental.} pragma to enable destructors"
+    incl(s.flags, sfUsed)
+  of "deepcopy", "=deepcopy":
+    if s.typ.len == 2 and
+        s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
+        sameType(s.typ.sons[1], s.typ.sons[0]):
+      # Note: we store the deepCopy in the base of the pointer to mitigate
+      # the problem that pointers are structural types:
+      var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
+      while true:
+        if t.kind == tyGenericBody: t = t.lastSon
+        elif t.kind == tyGenericInvocation: t = t.sons[0]
+        else: break
+      if t.kind in {tyObject, tyDistinct, tyEnum}:
+        if t.deepCopy.isNil: t.deepCopy = s
+        else:
+          localError(n.info, errGenerated,
+                     "cannot bind another 'deepCopy' to: " & typeToString(t))
+      else:
+        localError(n.info, errGenerated,
+                   "cannot bind 'deepCopy' to: " & typeToString(t))
+    else:
+      localError(n.info, errGenerated,
+                 "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T")
+    incl(s.flags, sfUsed)
+  of "=":
+    incl(s.flags, sfUsed)
+    let t = s.typ
+    if t.len == 3 and t.sons[0] == nil and t.sons[1].kind == tyVar:
+      var obj = t.sons[1].sons[0]
+      while true:
+        incl(obj.flags, tfHasAsgn)
+        if obj.kind == tyGenericBody: obj = obj.lastSon
+        elif obj.kind == tyGenericInvocation: obj = obj.sons[0]
+        else: break
+      var objB = t.sons[2]
+      while true:
+        if objB.kind == tyGenericBody: objB = objB.lastSon
+        elif objB.kind == tyGenericInvocation: objB = objB.sons[0]
+        else: break
+      if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB):
+        if obj.assignment.isNil:
+          obj.assignment = s
+        else:
+          localError(n.info, errGenerated,
+                     "cannot bind another '=' to: " & typeToString(obj))
+        return
+    localError(n.info, errGenerated,
+               "signature for '=' must be proc[T: object](x: var T; y: T)")
+  else:
+    if sfOverriden in s.flags:
+      localError(n.info, errGenerated,
+                 "'destroy' or 'deepCopy' expected for 'override'")
+
+type
+  TProcCompilationSteps = enum
+    stepRegisterSymbol,
+    stepDetermineType,
+    stepCompileBody
+
+proc isForwardDecl(s: PSym): bool =
+  internalAssert s.kind == skProc
+  result = s.ast[bodyPos].kind != nkEmpty
+
+proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
+                validPragmas: TSpecialWords,
+                phase = stepRegisterSymbol): PNode =
+  result = semProcAnnotation(c, n, validPragmas)
+  if result != nil: return result
+  result = n
+  checkSonsLen(n, bodyPos + 1)
+  var s: PSym
+  var typeIsDetermined = false
+  var isAnon = false
+  if n[namePos].kind != nkSym:
+    assert phase == stepRegisterSymbol
+
+    if n[namePos].kind == nkEmpty:
+      s = newSym(kind, idAnon, getCurrOwner(), n.info)
+      isAnon = true
+    else:
+      s = semIdentDef(c, n.sons[0], kind)
+    n.sons[namePos] = newSymNode(s)
+    s.ast = n
+    #s.scope = c.currentScope
+
+    if sfNoForward in c.module.flags and
+       sfSystemModule notin c.module.flags:
+      addInterfaceOverloadableSymAt(c, c.currentScope, s)
+      s.flags.incl sfForward
+      return
+  else:
+    s = n[namePos].sym
+    s.owner = getCurrOwner()
+    typeIsDetermined = s.typ == nil
+    s.ast = n
+    #s.scope = c.currentScope
+
+    # if typeIsDetermined: assert phase == stepCompileBody
+    # else: assert phase == stepDetermineType
+  # before compiling the proc body, set as current the scope
+  # where the proc was declared
+  let oldScope = c.currentScope
+  #c.currentScope = s.scope
+  pushOwner(s)
+  openScope(c)
+  var gp: PNode
+  if n.sons[genericParamsPos].kind != nkEmpty:
+    n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
+    gp = n.sons[genericParamsPos]
+  else:
+    gp = newNodeI(nkGenericParams, n.info)
+  # process parameters:
+  if n.sons[paramsPos].kind != nkEmpty:
+    semParamList(c, n.sons[paramsPos], gp, s)
+    if sonsLen(gp) > 0:
+      if n.sons[genericParamsPos].kind == nkEmpty:
+        # we have a list of implicit type parameters:
+        n.sons[genericParamsPos] = gp
+        # check for semantics again:
+        # semParamList(c, n.sons[ParamsPos], nil, s)
+  else:
+    s.typ = newProcType(c, n.info)
+  if n.sons[patternPos].kind != nkEmpty:
+    n.sons[patternPos] = semPattern(c, n.sons[patternPos])
+  if s.kind in skIterators:
+    s.typ.flags.incl(tfIterator)
+
+  var proto = searchForProc(c, oldScope, s)
+  if proto == nil:
+    if s.kind == skClosureIterator: s.typ.callConv = ccClosure
+    else: s.typ.callConv = lastOptionEntry(c).defaultCC
+    # add it here, so that recursive procs are possible:
+    if sfGenSym in s.flags: discard
+    elif kind in OverloadableSyms:
+      if not typeIsDetermined:
+        addInterfaceOverloadableSymAt(c, oldScope, s)
+    else:
+      if not typeIsDetermined:
+        addInterfaceDeclAt(c, oldScope, s)
+    if n.sons[pragmasPos].kind != nkEmpty:
+      pragma(c, s, n.sons[pragmasPos], validPragmas)
+    else:
+      implicitPragmas(c, s, n, validPragmas)
+  else:
+    if n.sons[pragmasPos].kind != nkEmpty:
+      localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
+    if sfForward notin proto.flags:
+      wrongRedefinition(n.info, proto.name.s)
+    excl(proto.flags, sfForward)
+    closeScope(c)         # close scope with wrong parameter symbols
+    openScope(c)          # open scope for old (correct) parameter symbols
+    if proto.ast.sons[genericParamsPos].kind != nkEmpty:
+      addGenericParamListToScope(c, proto.ast.sons[genericParamsPos])
+    addParams(c, proto.typ.n, proto.kind)
+    proto.info = s.info       # more accurate line information
+    s.typ = proto.typ
+    s = proto
+    n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos]
+    n.sons[paramsPos] = proto.ast.sons[paramsPos]
+    n.sons[pragmasPos] = proto.ast.sons[pragmasPos]
+    if n.sons[namePos].kind != nkSym: internalError(n.info, "semProcAux")
+    n.sons[namePos].sym = proto
+    if importantComments() and not isNil(proto.ast.comment):
+      n.comment = proto.ast.comment
+    proto.ast = n             # needed for code generation
+    popOwner()
+    pushOwner(s)
+  s.options = gOptions
+  if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n)
+  if n.sons[bodyPos].kind != nkEmpty:
+    # for DLL generation it is annoying to check for sfImportc!
+    if sfBorrow in s.flags:
+      localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
+    let usePseudoGenerics = kind in {skMacro, skTemplate}
+    # Macros and Templates can have generic parameters, but they are
+    # only used for overload resolution (there is no instantiation of
+    # the symbol, so we must process the body now)
+    if n.sons[genericParamsPos].kind == nkEmpty or usePseudoGenerics:
+      if not usePseudoGenerics: paramsTypeCheck(c, s.typ)
+      pushProcCon(c, s)
+      c.p.wasForwarded = proto != nil
+      maybeAddResult(c, s, n)
+      if sfImportc notin s.flags:
+        # no semantic checking for importc:
+        let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
+        # unfortunately we cannot skip this step when in 'system.compiles'
+        # context as it may even be evaluated in 'system.compiles':
+        n.sons[bodyPos] = transformBody(c.module, semBody, s)
+      popProcCon(c)
+    else:
+      if s.typ.sons[0] != nil and kind notin skIterators:
+        addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info))
+      openScope(c)
+      n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos])
+      closeScope(c)
+      fixupInstantiatedSymbols(c, s)
+    if sfImportc in s.flags:
+      # so we just ignore the body after semantic checking for importc:
+      n.sons[bodyPos] = ast.emptyNode
+  else:
+    if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s)
+    if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone:
+      incl(s.flags, sfForward)
+    elif sfBorrow in s.flags: semBorrow(c, n, s)
+  sideEffectsCheck(c, s)
+  closeScope(c)           # close scope for parameters
+  # c.currentScope = oldScope
+  popOwner()
+  if n.sons[patternPos].kind != nkEmpty:
+    c.patterns.add(s)
+  if isAnon: result.typ = s.typ
+
+proc determineType(c: PContext, s: PSym) =
+  if s.typ != nil: return
+  #if s.magic != mNone: return
+  discard semProcAux(c, s.ast, s.kind, {}, stepDetermineType)
+
+proc semIterator(c: PContext, n: PNode): PNode =
+  let kind = if hasPragma(n[pragmasPos], wClosure) or
+                n[namePos].kind == nkEmpty: skClosureIterator
+             else: skIterator
+  # gensym'ed iterator?
+  if n[namePos].kind == nkSym:
+    # gensym'ed iterators might need to become closure iterators:
+    n[namePos].sym.owner = getCurrOwner()
+    n[namePos].sym.kind = kind
+  result = semProcAux(c, n, kind, iteratorPragmas)
+  var s = result.sons[namePos].sym
+  var t = s.typ
+  if t.sons[0] == nil and s.typ.callConv != ccClosure:
+    localError(n.info, errXNeedsReturnType, "iterator")
+  # iterators are either 'inline' or 'closure'; for backwards compatibility,
+  # we require first class iterators to be marked with 'closure' explicitly
+  # -- at least for 0.9.2.
+  if s.typ.callConv == ccClosure:
+    incl(s.typ.flags, tfCapturesEnv)
+  else:
+    s.typ.callConv = ccInline
+  when false:
+    if s.typ.callConv != ccInline:
+      s.typ.callConv = ccClosure
+      # and they always at least use the 'env' for the state field:
+      incl(s.typ.flags, tfCapturesEnv)
+  if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone:
+    localError(n.info, errImplOfXexpected, s.name.s)
+
+proc semProc(c: PContext, n: PNode): PNode =
+  result = semProcAux(c, n, skProc, procPragmas)
+
+proc hasObjParam(s: PSym): bool =
+  var t = s.typ
+  for col in countup(1, sonsLen(t)-1):
+    if skipTypes(t.sons[col], skipPtrs).kind == tyObject:
+      return true
+
+proc finishMethod(c: PContext, s: PSym) =
+  if hasObjParam(s):
+    methodDef(s, false)
+
+proc semMethod(c: PContext, n: PNode): PNode =
+  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
+  result = semProcAux(c, n, skMethod, methodPragmas)
+
+  var s = result.sons[namePos].sym
+  if not isGenericRoutine(s):
+    # why check for the body? bug #2400 has none. Checking for sfForward makes
+    # no sense either.
+    # and result.sons[bodyPos].kind != nkEmpty:
+    if hasObjParam(s):
+      methodDef(s, fromCache=false)
+    else:
+      localError(n.info, errXNeedsParamObjectType, "method")
+
+proc semConverterDef(c: PContext, n: PNode): PNode =
+  if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter")
+  checkSonsLen(n, bodyPos + 1)
+  result = semProcAux(c, n, skConverter, converterPragmas)
+  var s = result.sons[namePos].sym
+  var t = s.typ
+  if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter")
+  if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter")
+  addConverter(c, s)
+
+proc semMacroDef(c: PContext, n: PNode): PNode =
+  checkSonsLen(n, bodyPos + 1)
+  result = semProcAux(c, n, skMacro, macroPragmas)
+  var s = result.sons[namePos].sym
+  var t = s.typ
+  if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro")
+  if n.sons[bodyPos].kind == nkEmpty:
+    localError(n.info, errImplOfXexpected, s.name.s)
+
+proc evalInclude(c: PContext, n: PNode): PNode =
+  result = newNodeI(nkStmtList, n.info)
+  addSon(result, n)
+  for i in countup(0, sonsLen(n) - 1):
+    var f = checkModuleName(n.sons[i])
+    if f != InvalidFileIDX:
+      if containsOrIncl(c.includedFiles, f):
+        localError(n.info, errRecursiveDependencyX, f.toFilename)
+      else:
+        addSon(result, semStmt(c, gIncludeFile(c.module, f)))
+        excl(c.includedFiles, f)
+
+proc setLine(n: PNode, info: TLineInfo) =
+  for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
+  n.info = info
+
+proc semPragmaBlock(c: PContext, n: PNode): PNode =
+  let pragmaList = n.sons[0]
+  pragma(c, nil, pragmaList, exprPragmas)
+  result = semExpr(c, n.sons[1])
+  n.sons[1] = result
+  for i in 0 .. <pragmaList.len:
+    case whichPragma(pragmaList.sons[i])
+    of wLine: setLine(result, pragmaList.sons[i].info)
+    of wLocks:
+      result = n
+      result.typ = n.sons[1].typ
+    else: discard
+
+proc semStaticStmt(c: PContext, n: PNode): PNode =
+  #echo "semStaticStmt"
+  #writeStackTrace()
+  let a = semStmt(c, n.sons[0])
+  n.sons[0] = a
+  evalStaticStmt(c.module, a, c.p.owner)
+  result = newNodeI(nkDiscardStmt, n.info, 1)
+  result.sons[0] = emptyNode
+  when false:
+    result = evalStaticStmt(c.module, a, c.p.owner)
+    if result.isNil:
+      LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
+      result = emptyNode
+    elif result.kind == nkEmpty:
+      result = newNodeI(nkDiscardStmt, n.info, 1)
+      result.sons[0] = emptyNode
+
+proc usesResult(n: PNode): bool =
+  # nkStmtList(expr) properly propagates the void context,
+  # so we don't need to process that all over again:
+  if n.kind notin {nkStmtList, nkStmtListExpr,
+                   nkMacroDef, nkTemplateDef} + procDefs:
+    if isAtom(n):
+      result = n.kind == nkSym and n.sym.kind == skResult
+    elif n.kind == nkReturnStmt:
+      result = true
+    else:
+      for c in n:
+        if usesResult(c): return true
+
+proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
+  # these must be last statements in a block:
+  const
+    LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt}
+  result = n
+  result.kind = nkStmtList
+  var length = sonsLen(n)
+  var voidContext = false
+  var last = length-1
+  # by not allowing for nkCommentStmt etc. we ensure nkStmtListExpr actually
+  # really *ends* in the expression that produces the type: The compiler now
+  # relies on this fact and it's too much effort to change that. And arguably
+  #  'R(); #comment' shouldn't produce R's type anyway.
+  #while last > 0 and n.sons[last].kind in {nkPragma, nkCommentStmt,
+  #                                         nkNilLit, nkEmpty}:
+  #  dec last
+  for i in countup(0, length - 1):
+    let k = n.sons[i].kind
+    case k
+    of nkFinally, nkExceptBranch, nkDefer:
+      # stand-alone finally and except blocks are
+      # transformed into regular try blocks:
+      #
+      # var f = fopen("somefile") | var f = fopen("somefile")
+      # finally: fclose(f)        | try:
+      # ...                       |   ...
+      #                           | finally:
+      #                           |   fclose(f)
+      var deferPart: PNode
+      if k == nkDefer:
+        deferPart = newNodeI(nkFinally, n.sons[i].info)
+        deferPart.add n.sons[i].sons[0]
+      elif k == nkFinally:
+        message(n.info, warnDeprecated,
+                "use 'defer'; standalone 'finally'")
+        deferPart = n.sons[i]
+      else:
+        message(n.info, warnDeprecated,
+                "use an explicit 'try'; standalone 'except'")
+        deferPart = n.sons[i]
+      var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
+      var body = newNodeI(nkStmtList, n.sons[i].info)
+      if i < n.sonsLen - 1:
+        body.sons = n.sons[(i+1)..n.len-1]
+      tryStmt.addSon(body)
+      tryStmt.addSon(deferPart)
+      n.sons[i] = semTry(c, tryStmt)
+      n.sons.setLen(i+1)
+      n.typ = n.sons[i].typ
+      return
+    else:
+      n.sons[i] = semExpr(c, n.sons[i])
+      if c.inTypeClass > 0 and n[i].typ != nil:
+        case n[i].typ.kind
+        of tyBool:
+          let verdict = semConstExpr(c, n[i])
+          if verdict.intVal == 0:
+            localError(result.info, "type class predicate failed")
+        of tyUnknown: continue
+        else: discard
+      if n.sons[i].typ == enforceVoidContext or usesResult(n.sons[i]):
+        voidContext = true
+        n.typ = enforceVoidContext
+      if i == last and (length == 1 or efWantValue in flags):
+        n.typ = n.sons[i].typ
+        if not isEmptyType(n.typ): n.kind = nkStmtListExpr
+      elif i != last or voidContext:
+        discardCheck(c, n.sons[i])
+      else:
+        n.typ = n.sons[i].typ
+        if not isEmptyType(n.typ): n.kind = nkStmtListExpr
+      case n.sons[i].kind
+      of nkVarSection, nkLetSection:
+        let (outer, inner) = insertDestructors(c, n.sons[i])
+        if outer != nil:
+          n.sons[i] = outer
+          var rest = newNode(nkStmtList, n.info, n.sons[i+1 .. length-1])
+          inner.addSon(semStmtList(c, rest, flags))
+          n.sons.setLen(i+1)
+          return
+      of LastBlockStmts:
+        for j in countup(i + 1, length - 1):
+          case n.sons[j].kind
+          of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: discard
+          else: localError(n.sons[j].info, errStmtInvalidAfterReturn)
+      else: discard
+  if result.len == 1:
+    result = result.sons[0]
+  when defined(nimfix):
+    if result.kind == nkCommentStmt and not result.comment.isNil and
+        not (result.comment[0] == '#' and result.comment[1] == '#'):
+      # it is an old-style comment statement: we replace it with 'discard ""':
+      prettybase.replaceComment(result.info)
+  when false:
+    # a statement list (s; e) has the type 'e':
+    if result.kind == nkStmtList and result.len > 0:
+      var lastStmt = lastSon(result)
+      if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt):
+        result.typ = lastStmt.typ
+        #localError(lastStmt.info, errGenerated,
+        #  "Last expression must be explicitly returned if it " &
+        #  "is discardable or discarded")
+
+proc semStmt(c: PContext, n: PNode): PNode =
+  # now: simply an alias:
+  result = semExprNoType(c, n)
+
+proc semStmtScope(c: PContext, n: PNode): PNode =
+  openScope(c)
+  result = semStmt(c, n)
+  closeScope(c)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
new file mode 100644
index 000000000..161d22fc1
--- /dev/null
+++ b/compiler/semtempl.nim
@@ -0,0 +1,679 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# included from sem.nim
+
+discard """
+  hygienic templates:
+
+    template `||` (a, b: expr): expr =
+      let aa = a
+      if aa: aa else: b
+
+    var
+      a, b: T
+
+    a || b || a
+
+  Each evaluation context has to be different and we need to perform
+  some form of preliminary symbol lookup in template definitions. Hygiene is
+  a way to achieve lexical scoping at compile time.
+"""
+
+type
+  TSymBinding = enum
+    spNone, spGenSym, spInject
+
+proc symBinding(n: PNode): TSymBinding =
+  for i in countup(0, sonsLen(n) - 1):
+    var it = n.sons[i]
+    var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
+    if key.kind == nkIdent:
+      case whichKeyword(key.ident)
+      of wGensym: return spGenSym
+      of wInject: return spInject
+      else: discard
+
+type
+  TSymChoiceRule = enum
+    scClosed, scOpen, scForceOpen
+
+proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
+  var
+    a: PSym
+    o: TOverloadIter
+  var i = 0
+  a = initOverloadIter(o, c, n)
+  while a != nil:
+    a = nextOverloadIter(o, c, n)
+    inc(i)
+    if i > 1: break
+  if i <= 1 and r != scForceOpen:
+    # XXX this makes more sense but breaks bootstrapping for now:
+    # (s.kind notin routineKinds or s.magic != mNone):
+    # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
+    result = newSymNode(s, n.info)
+    markUsed(n.info, s)
+  else:
+    # semantic checking requires a type; ``fitNode`` deals with it
+    # appropriately
+    let kind = if r == scClosed or n.kind == nkDotExpr: nkClosedSymChoice
+               else: nkOpenSymChoice
+    result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
+    a = initOverloadIter(o, c, n)
+    while a != nil:
+      incl(a.flags, sfUsed)
+      addSon(result, newSymNode(a, n.info))
+      a = nextOverloadIter(o, c, n)
+
+proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
+  for i in 0 .. < n.len:
+    var a = n.sons[i]
+    # If 'a' is an overloaded symbol, we used to use the first symbol
+    # as a 'witness' and use the fact that subsequent lookups will yield
+    # the same symbol!
+    # This is however not true anymore for hygienic templates as semantic
+    # processing for them changes the symbol table...
+    let s = qualifiedLookUp(c, a)
+    if s != nil:
+      # we need to mark all symbols:
+      let sc = symChoice(c, n, s, scClosed)
+      if sc.kind == nkSym:
+        toBind.incl(sc.sym.id)
+      else:
+        for x in items(sc): toBind.incl(x.sym.id)
+    else:
+      illFormedAst(a)
+  result = newNodeI(nkEmpty, n.info)
+
+proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
+  for i in 0 .. < n.len:
+    toMixin.incl(considerQuotedIdent(n.sons[i]).id)
+  result = newNodeI(nkEmpty, n.info)
+
+proc replaceIdentBySym(n: var PNode, s: PNode) =
+  case n.kind
+  of nkPostfix: replaceIdentBySym(n.sons[1], s)
+  of nkPragmaExpr: replaceIdentBySym(n.sons[0], s)
+  of nkIdent, nkAccQuoted, nkSym: n = s
+  else: illFormedAst(n)
+
+type
+  TemplCtx = object
+    c: PContext
+    toBind, toMixin, toInject: IntSet
+    owner: PSym
+    cursorInBody: bool # only for nimsuggest
+
+proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
+  case n.kind
+  of nkPostfix: result = getIdentNode(c, n.sons[1])
+  of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
+  of nkIdent:
+    result = n
+    let s = qualifiedLookUp(c.c, n, {})
+    if s != nil:
+      if s.owner == c.owner and s.kind == skParam:
+        result = newSymNode(s, n.info)
+  of nkAccQuoted, nkSym: result = n
+  else:
+    illFormedAst(n)
+    result = n
+
+proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
+  result = n.kind == nkSym and n.sym.kind == skParam and
+           n.sym.owner == c.owner and sfGenSym notin n.sym.flags
+
+proc semTemplBody(c: var TemplCtx, n: PNode): PNode
+
+proc openScope(c: var TemplCtx) = openScope(c.c)
+proc closeScope(c: var TemplCtx) = closeScope(c.c)
+
+proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
+  openScope(c)
+  result = semTemplBody(c, n)
+  closeScope(c)
+
+proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
+  result = n
+  if n.kind == nkIdent:
+    let s = qualifiedLookUp(c.c, n, {})
+    if s != nil:
+      if s.owner == c.owner and s.kind == skParam:
+        incl(s.flags, sfUsed)
+        result = newSymNode(s, n.info)
+        styleCheckUse(n.info, s)
+  else:
+    for i in 0 .. <n.safeLen:
+      result.sons[i] = onlyReplaceParams(c, n.sons[i])
+
+proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
+  result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
+  incl(result.flags, sfGenSym)
+  incl(result.flags, sfShadowed)
+
+proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
+  # locals default to 'gensym':
+  if n.kind == nkPragmaExpr and symBinding(n.sons[1]) == spInject:
+    # even if injected, don't produce a sym choice here:
+    #n = semTemplBody(c, n)
+    var x = n[0]
+    while true:
+      case x.kind
+      of nkPostfix: x = x[1]
+      of nkPragmaExpr: x = x[0]
+      of nkIdent: break
+      of nkAccQuoted:
+        # consider:  type `T TemplParam` {.inject.}
+        # it suffices to return to treat it like 'inject':
+        n = onlyReplaceParams(c, n)
+        return
+      else:
+        illFormedAst(x)
+    let ident = getIdentNode(c, x)
+    if not isTemplParam(c, ident):
+      c.toInject.incl(x.ident.id)
+    else:
+      replaceIdentBySym(n, ident)
+  else:
+    let ident = getIdentNode(c, n)
+    if not isTemplParam(c, ident):
+      let local = newGenSym(k, ident, c)
+      addPrelimDecl(c.c, local)
+      styleCheckDef(n.info, local)
+      replaceIdentBySym(n, newSymNode(local, n.info))
+    else:
+      replaceIdentBySym(n, ident)
+
+proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
+  incl(s.flags, sfUsed)
+  # we do not call styleCheckUse here, as the identifier is not really
+  # resolved here. We will fixup the used identifiers later.
+  case s.kind
+  of skUnknown:
+    # Introduced in this pass! Leave it as an identifier.
+    result = n
+  of OverloadableSyms:
+    result = symChoice(c, n, s, scOpen)
+  of skGenericParam:
+    result = newSymNodeTypeDesc(s, n.info)
+  of skParam:
+    result = n
+  of skType:
+    if (s.typ != nil) and (s.typ.kind != tyGenericParam):
+      result = newSymNodeTypeDesc(s, n.info)
+    else:
+      result = n
+  else:
+    result = newSymNode(s, n.info)
+
+proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
+  result = n
+  if n.kind == nkIdent:
+    let s = qualifiedLookUp(c.c, n, {})
+    if s != nil:
+      if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
+        incl(s.flags, sfUsed)
+        result = newSymNode(s, n.info)
+        styleCheckUse(n.info, s)
+  else:
+    for i in countup(0, safeLen(n) - 1):
+      result.sons[i] = semRoutineInTemplName(c, n.sons[i])
+
+proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
+  result = n
+  checkSonsLen(n, bodyPos + 1)
+  # routines default to 'inject':
+  if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym:
+    let ident = getIdentNode(c, n.sons[namePos])
+    if not isTemplParam(c, ident):
+      var s = newGenSym(k, ident, c)
+      s.ast = n
+      addPrelimDecl(c.c, s)
+      styleCheckDef(n.info, s)
+      n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
+    else:
+      n.sons[namePos] = ident
+  else:
+    n.sons[namePos] = semRoutineInTemplName(c, n.sons[namePos])
+  openScope(c)
+  for i in patternPos..bodyPos:
+    n.sons[i] = semTemplBody(c, n.sons[i])
+  closeScope(c)
+
+proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
+  for i in countup(start, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if a.kind == nkCommentStmt: continue
+    if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
+    checkMinSonsLen(a, 3)
+    var L = sonsLen(a)
+    a.sons[L-2] = semTemplBody(c, a.sons[L-2])
+    a.sons[L-1] = semTemplBody(c, a.sons[L-1])
+    for j in countup(0, L-3):
+      addLocalDecl(c, a.sons[j], symKind)
+
+proc semPattern(c: PContext, n: PNode): PNode
+proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
+  result = n
+  semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
+  case n.kind
+  of nkIdent:
+    if n.ident.id in c.toInject: return n
+    let s = qualifiedLookUp(c.c, n, {})
+    if s != nil:
+      if s.owner == c.owner and s.kind == skParam:
+        incl(s.flags, sfUsed)
+        result = newSymNode(s, n.info)
+        styleCheckUse(n.info, s)
+      elif contains(c.toBind, s.id):
+        result = symChoice(c.c, n, s, scClosed)
+      elif contains(c.toMixin, s.name.id):
+        result = symChoice(c.c, n, s, scForceOpen)
+      elif s.owner == c.owner and sfGenSym in s.flags:
+        # template tmp[T](x: var seq[T]) =
+        # var yz: T
+        incl(s.flags, sfUsed)
+        result = newSymNode(s, n.info)
+        styleCheckUse(n.info, s)
+      else:
+        result = semTemplSymbol(c.c, n, s)
+  of nkBind:
+    result = semTemplBody(c, n.sons[0])
+  of nkBindStmt:
+    result = semBindStmt(c.c, n, c.toBind)
+  of nkMixinStmt:
+    result = semMixinStmt(c.c, n, c.toMixin)
+  of nkEmpty, nkSym..nkNilLit:
+    discard
+  of nkIfStmt:
+    for i in countup(0, sonsLen(n)-1):
+      var it = n.sons[i]
+      if it.len == 2:
+        when newScopeForIf: openScope(c)
+        it.sons[0] = semTemplBody(c, it.sons[0])
+        when not newScopeForIf: openScope(c)
+        it.sons[1] = semTemplBody(c, it.sons[1])
+        closeScope(c)
+      else:
+        n.sons[i] = semTemplBodyScope(c, it)
+  of nkWhileStmt:
+    openScope(c)
+    for i in countup(0, sonsLen(n)-1):
+      n.sons[i] = semTemplBody(c, n.sons[i])
+    closeScope(c)
+  of nkCaseStmt:
+    openScope(c)
+    n.sons[0] = semTemplBody(c, n.sons[0])
+    for i in countup(1, sonsLen(n)-1):
+      var a = n.sons[i]
+      checkMinSonsLen(a, 1)
+      var L = sonsLen(a)
+      for j in countup(0, L-2):
+        a.sons[j] = semTemplBody(c, a.sons[j])
+      a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
+    closeScope(c)
+  of nkForStmt, nkParForStmt:
+    var L = sonsLen(n)
+    openScope(c)
+    n.sons[L-2] = semTemplBody(c, n.sons[L-2])
+    for i in countup(0, L - 3):
+      addLocalDecl(c, n.sons[i], skForVar)
+    n.sons[L-1] = semTemplBody(c, n.sons[L-1])
+    closeScope(c)
+  of nkBlockStmt, nkBlockExpr, nkBlockType:
+    checkSonsLen(n, 2)
+    openScope(c)
+    if n.sons[0].kind != nkEmpty:
+      # labels are always 'gensym'ed:
+      let s = newGenSym(skLabel, n.sons[0], c)
+      addPrelimDecl(c.c, s)
+      styleCheckDef(s)
+      n.sons[0] = newSymNode(s, n.sons[0].info)
+    n.sons[1] = semTemplBody(c, n.sons[1])
+    closeScope(c)
+  of nkTryStmt:
+    checkMinSonsLen(n, 2)
+    n.sons[0] = semTemplBodyScope(c, n.sons[0])
+    for i in countup(1, sonsLen(n)-1):
+      var a = n.sons[i]
+      checkMinSonsLen(a, 1)
+      var L = sonsLen(a)
+      for j in countup(0, L-2):
+        a.sons[j] = semTemplBody(c, a.sons[j])
+      a.sons[L-1] = semTemplBodyScope(c, a.sons[L-1])
+  of nkVarSection: semTemplSomeDecl(c, n, skVar)
+  of nkLetSection: semTemplSomeDecl(c, n, skLet)
+  of nkFormalParams:
+    checkMinSonsLen(n, 1)
+    n.sons[0] = semTemplBody(c, n.sons[0])
+    semTemplSomeDecl(c, n, skParam, 1)
+  of nkConstSection:
+    for i in countup(0, sonsLen(n) - 1):
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue
+      if (a.kind != nkConstDef): illFormedAst(a)
+      checkSonsLen(a, 3)
+      addLocalDecl(c, a.sons[0], skConst)
+      a.sons[1] = semTemplBody(c, a.sons[1])
+      a.sons[2] = semTemplBody(c, a.sons[2])
+  of nkTypeSection:
+    for i in countup(0, sonsLen(n) - 1):
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue
+      if (a.kind != nkTypeDef): illFormedAst(a)
+      checkSonsLen(a, 3)
+      addLocalDecl(c, a.sons[0], skType)
+    for i in countup(0, sonsLen(n) - 1):
+      var a = n.sons[i]
+      if a.kind == nkCommentStmt: continue
+      if (a.kind != nkTypeDef): illFormedAst(a)
+      checkSonsLen(a, 3)
+      if a.sons[1].kind != nkEmpty:
+        openScope(c)
+        a.sons[1] = semTemplBody(c, a.sons[1])
+        a.sons[2] = semTemplBody(c, a.sons[2])
+        closeScope(c)
+      else:
+        a.sons[2] = semTemplBody(c, a.sons[2])
+  of nkProcDef, nkLambdaKinds:
+    result = semRoutineInTemplBody(c, n, skProc)
+  of nkMethodDef:
+    result = semRoutineInTemplBody(c, n, skMethod)
+  of nkIteratorDef:
+    let kind = if hasPragma(n[pragmasPos], wClosure): skClosureIterator
+               else: skIterator
+    result = semRoutineInTemplBody(c, n, kind)
+  of nkTemplateDef:
+    result = semRoutineInTemplBody(c, n, skTemplate)
+  of nkMacroDef:
+    result = semRoutineInTemplBody(c, n, skMacro)
+  of nkConverterDef:
+    result = semRoutineInTemplBody(c, n, skConverter)
+  of nkPragmaExpr:
+    result.sons[0] = semTemplBody(c, n.sons[0])
+  of nkPostfix:
+    result.sons[1] = semTemplBody(c, n.sons[1])
+  of nkPragma:
+    result = onlyReplaceParams(c, n)
+  else:
+    # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
+    # so we use the generic code for nkDotExpr too
+    if n.kind == nkDotExpr or n.kind == nkAccQuoted:
+      let s = qualifiedLookUp(c.c, n, {})
+      if s != nil:
+        # do not symchoice a quoted template parameter (bug #2390):
+        if s.owner == c.owner and s.kind == skParam and
+            n.kind == nkAccQuoted and n.len == 1:
+          incl(s.flags, sfUsed)
+          styleCheckUse(n.info, s)
+          return newSymNode(s, n.info)
+        elif contains(c.toBind, s.id):
+          return symChoice(c.c, n, s, scClosed)
+        elif contains(c.toMixin, s.name.id):
+          return symChoice(c.c, n, s, scForceOpen)
+        else:
+          return symChoice(c.c, n, s, scOpen)
+    result = n
+    for i in countup(0, sonsLen(n) - 1):
+      result.sons[i] = semTemplBody(c, n.sons[i])
+
+proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
+  result = n
+  semIdeForTemplateOrGenericCheck(n, c.cursorInBody)
+  case n.kind
+  of nkIdent:
+    let s = qualifiedLookUp(c.c, n, {})
+    if s != nil:
+      if s.owner == c.owner and s.kind == skParam:
+        result = newSymNode(s, n.info)
+      elif contains(c.toBind, s.id):
+        result = symChoice(c.c, n, s, scClosed)
+  of nkBind:
+    result = semTemplBodyDirty(c, n.sons[0])
+  of nkBindStmt:
+    result = semBindStmt(c.c, n, c.toBind)
+  of nkEmpty, nkSym..nkNilLit:
+    discard
+  else:
+    # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
+    # so we use the generic code for nkDotExpr too
+    if n.kind == nkDotExpr or n.kind == nkAccQuoted:
+      let s = qualifiedLookUp(c.c, n, {})
+      if s != nil and contains(c.toBind, s.id):
+        return symChoice(c.c, n, s, scClosed)
+    result = n
+    for i in countup(0, sonsLen(n) - 1):
+      result.sons[i] = semTemplBodyDirty(c, n.sons[i])
+
+proc transformToExpr(n: PNode): PNode =
+  var realStmt: int
+  result = n
+  case n.kind
+  of nkStmtList:
+    realStmt = - 1
+    for i in countup(0, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkCommentStmt, nkEmpty, nkNilLit:
+        discard
+      else:
+        if realStmt == - 1: realStmt = i
+        else: realStmt = - 2
+    if realStmt >= 0: result = transformToExpr(n.sons[realStmt])
+    else: n.kind = nkStmtListExpr
+  of nkBlockStmt:
+    n.kind = nkBlockExpr
+    #nkIfStmt: n.kind = nkIfExpr // this is not correct!
+  else:
+    discard
+
+proc semTemplateDef(c: PContext, n: PNode): PNode =
+  var s: PSym
+  if c.p.owner.kind == skModule:
+    s = semIdentVis(c, skTemplate, n.sons[0], {sfExported})
+    incl(s.flags, sfGlobal)
+  else:
+    s = semIdentVis(c, skTemplate, n.sons[0], {})
+  styleCheckDef(s)
+  # check parameter list:
+  #s.scope = c.currentScope
+  pushOwner(s)
+  openScope(c)
+  n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
+  if n.sons[pragmasPos].kind != nkEmpty:
+    pragma(c, s, n.sons[pragmasPos], templatePragmas)
+
+  var gp: PNode
+  if n.sons[genericParamsPos].kind != nkEmpty:
+    n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
+    gp = n.sons[genericParamsPos]
+  else:
+    gp = newNodeI(nkGenericParams, n.info)
+  # process parameters:
+  if n.sons[paramsPos].kind != nkEmpty:
+    semParamList(c, n.sons[paramsPos], gp, s)
+    # a template's parameters are not gensym'ed even if that was originally the
+    # case as we determine whether it's a template parameter in the template
+    # body by the absence of the sfGenSym flag:
+    for i in 1 .. s.typ.n.len-1:
+      s.typ.n.sons[i].sym.flags.excl sfGenSym
+    if sonsLen(gp) > 0:
+      if n.sons[genericParamsPos].kind == nkEmpty:
+        # we have a list of implicit type parameters:
+        n.sons[genericParamsPos] = gp
+    # no explicit return type? -> use tyStmt
+    if n.sons[paramsPos].sons[0].kind == nkEmpty:
+      # use ``stmt`` as implicit result type
+      s.typ.sons[0] = newTypeS(tyStmt, c)
+      s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
+  else:
+    s.typ = newTypeS(tyProc, c)
+    # XXX why do we need tyStmt as a return type again?
+    s.typ.n = newNodeI(nkFormalParams, n.info)
+    rawAddSon(s.typ, newTypeS(tyStmt, c))
+    addSon(s.typ.n, newNodeIT(nkType, n.info, s.typ.sons[0]))
+  if n.sons[patternPos].kind != nkEmpty:
+    n.sons[patternPos] = semPattern(c, n.sons[patternPos])
+  var ctx: TemplCtx
+  ctx.toBind = initIntSet()
+  ctx.toMixin = initIntSet()
+  ctx.toInject = initIntSet()
+  ctx.c = c
+  ctx.owner = s
+  if sfDirty in s.flags:
+    n.sons[bodyPos] = semTemplBodyDirty(ctx, n.sons[bodyPos])
+  else:
+    n.sons[bodyPos] = semTemplBody(ctx, n.sons[bodyPos])
+  if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
+    n.sons[bodyPos] = transformToExpr(n.sons[bodyPos])
+    # only parameters are resolved, no type checking is performed
+  semIdeForTemplateOrGeneric(c, n.sons[bodyPos], ctx.cursorInBody)
+  closeScope(c)
+  popOwner()
+  s.ast = n
+  result = n
+  if n.sons[bodyPos].kind == nkEmpty:
+    localError(n.info, errImplOfXexpected, s.name.s)
+  var proto = searchForProc(c, c.currentScope, s)
+  if proto == nil:
+    addInterfaceOverloadableSymAt(c, c.currentScope, s)
+  else:
+    symTabReplace(c.currentScope.symbols, proto, s)
+  if n.sons[patternPos].kind != nkEmpty:
+    c.patterns.add(s)
+
+proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
+  template templToExpand(s: expr): expr =
+    s.kind == skTemplate and (s.typ.len == 1 or sfImmediate in s.flags)
+
+  proc newParam(c: var TemplCtx, n: PNode, s: PSym): PNode =
+    # the param added in the current scope is actually wrong here for
+    # macros because they have a shadowed param of type 'PNimNode' (see
+    # semtypes.addParamOrResult). Within the pattern we have to ensure
+    # to use the param with the proper type though:
+    incl(s.flags, sfUsed)
+    styleCheckUse(n.info, s)
+    let x = c.owner.typ.n.sons[s.position+1].sym
+    assert x.name == s.name
+    result = newSymNode(x, n.info)
+
+  proc handleSym(c: var TemplCtx, n: PNode, s: PSym): PNode =
+    result = n
+    if s != nil:
+      if s.owner == c.owner and s.kind == skParam:
+        result = newParam(c, n, s)
+      elif contains(c.toBind, s.id):
+        result = symChoice(c.c, n, s, scClosed)
+      elif templToExpand(s):
+        result = semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
+      else:
+        discard
+        # we keep the ident unbound for matching instantiated symbols and
+        # more flexibility
+
+  proc expectParam(c: var TemplCtx, n: PNode): PNode =
+    let s = qualifiedLookUp(c.c, n, {})
+    if s != nil and s.owner == c.owner and s.kind == skParam:
+      result = newParam(c, n, s)
+    else:
+      localError(n.info, errInvalidExpression)
+      result = n
+
+  result = n
+  case n.kind
+  of nkIdent:
+    let s = qualifiedLookUp(c.c, n, {})
+    result = handleSym(c, n, s)
+  of nkBindStmt:
+    result = semBindStmt(c.c, n, c.toBind)
+  of nkEmpty, nkSym..nkNilLit: discard
+  of nkCurlyExpr:
+    # we support '(pattern){x}' to bind a subpattern to a parameter 'x';
+    # '(pattern){|x}' does the same but the matches will be gathered in 'x'
+    if n.len != 2:
+      localError(n.info, errInvalidExpression)
+    elif n.sons[1].kind == nkIdent:
+      n.sons[0] = semPatternBody(c, n.sons[0])
+      n.sons[1] = expectParam(c, n.sons[1])
+    elif n.sons[1].kind == nkPrefix and n.sons[1].sons[0].kind == nkIdent:
+      let opr = n.sons[1].sons[0]
+      if opr.ident.s == "|":
+        n.sons[0] = semPatternBody(c, n.sons[0])
+        n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1])
+      else:
+        localError(n.info, errInvalidExpression)
+    else:
+      localError(n.info, errInvalidExpression)
+  of nkCallKinds:
+    let s = qualifiedLookUp(c.c, n.sons[0], {})
+    if s != nil:
+      if s.owner == c.owner and s.kind == skParam: discard
+      elif contains(c.toBind, s.id): discard
+      elif templToExpand(s):
+        return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
+
+    if n.kind == nkInfix and n.sons[0].kind == nkIdent:
+      # we interpret `*` and `|` only as pattern operators if they occur in
+      # infix notation, so that '`*`(a, b)' can be used for verbatim matching:
+      let opr = n.sons[0]
+      if opr.ident.s == "*" or opr.ident.s == "**":
+        result = newNodeI(nkPattern, n.info, n.len)
+        result.sons[0] = opr
+        result.sons[1] = semPatternBody(c, n.sons[1])
+        result.sons[2] = expectParam(c, n.sons[2])
+        return
+      elif opr.ident.s == "|":
+        result = newNodeI(nkPattern, n.info, n.len)
+        result.sons[0] = opr
+        result.sons[1] = semPatternBody(c, n.sons[1])
+        result.sons[2] = semPatternBody(c, n.sons[2])
+        return
+
+    if n.kind == nkPrefix and n.sons[0].kind == nkIdent:
+      let opr = n.sons[0]
+      if opr.ident.s == "~":
+        result = newNodeI(nkPattern, n.info, n.len)
+        result.sons[0] = opr
+        result.sons[1] = semPatternBody(c, n.sons[1])
+        return
+
+    for i in countup(0, sonsLen(n) - 1):
+      result.sons[i] = semPatternBody(c, n.sons[i])
+  else:
+    # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
+    # so we use the generic code for nkDotExpr too
+    case n.kind
+    of nkDotExpr, nkAccQuoted:
+      let s = qualifiedLookUp(c.c, n, {})
+      if s != nil:
+        if contains(c.toBind, s.id):
+          return symChoice(c.c, n, s, scClosed)
+        else:
+          return newIdentNode(s.name, n.info)
+    of nkPar:
+      if n.len == 1: return semPatternBody(c, n.sons[0])
+    else: discard
+    for i in countup(0, sonsLen(n) - 1):
+      result.sons[i] = semPatternBody(c, n.sons[i])
+
+proc semPattern(c: PContext, n: PNode): PNode =
+  openScope(c)
+  var ctx: TemplCtx
+  ctx.toBind = initIntSet()
+  ctx.toMixin = initIntSet()
+  ctx.toInject = initIntSet()
+  ctx.c = c
+  ctx.owner = getCurrOwner()
+  result = flattenStmts(semPatternBody(ctx, n))
+  if result.kind in {nkStmtList, nkStmtListExpr}:
+    if result.len == 1:
+      result = result.sons[0]
+    elif result.len == 0:
+      localError(n.info, errInvalidExpression)
+  closeScope(c)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
new file mode 100644
index 000000000..8c7bd7243
--- /dev/null
+++ b/compiler/semtypes.nim
@@ -0,0 +1,1422 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# this module does the semantic checking of type declarations
+# included from sem.nim
+
+proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
+  if prev == nil:
+    result = newTypeS(kind, c)
+  else:
+    result = prev
+    if result.kind == tyForward: result.kind = kind
+
+proc newConstraint(c: PContext, k: TTypeKind): PType =
+  result = newTypeS(tyBuiltInTypeClass, c)
+  result.addSonSkipIntLit(newTypeS(k, c))
+
+proc semEnum(c: PContext, n: PNode, prev: PType): PType =
+  if n.sonsLen == 0: return newConstraint(c, tyEnum)
+  var
+    counter, x: BiggestInt
+    e: PSym
+    base: PType
+  counter = 0
+  base = nil
+  result = newOrPrevType(tyEnum, prev, c)
+  result.n = newNodeI(nkEnumTy, n.info)
+  checkMinSonsLen(n, 1)
+  if n.sons[0].kind != nkEmpty:
+    base = semTypeNode(c, n.sons[0].sons[0], nil)
+    if base.kind != tyEnum:
+      localError(n.sons[0].info, errInheritanceOnlyWithEnums)
+    counter = lastOrd(base) + 1
+  rawAddSon(result, base)
+  let isPure = result.sym != nil and sfPure in result.sym.flags
+  var hasNull = false
+  for i in countup(1, sonsLen(n) - 1):
+    case n.sons[i].kind
+    of nkEnumFieldDef:
+      e = newSymS(skEnumField, n.sons[i].sons[0], c)
+      var v = semConstExpr(c, n.sons[i].sons[1])
+      var strVal: PNode = nil
+      case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
+      of tyTuple:
+        if sonsLen(v) == 2:
+          strVal = v.sons[1] # second tuple part is the string value
+          if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
+            x = getOrdValue(v.sons[0]) # first tuple part is the ordinal
+          else:
+            localError(strVal.info, errStringLiteralExpected)
+        else:
+          localError(v.info, errWrongNumberOfVariables)
+      of tyString, tyCString:
+        strVal = v
+        x = counter
+      else:
+        x = getOrdValue(v)
+      if i != 1:
+        if x != counter: incl(result.flags, tfEnumHasHoles)
+        if x < counter:
+          localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
+          x = counter
+      e.ast = strVal # might be nil
+      counter = x
+    of nkSym:
+      e = n.sons[i].sym
+    of nkIdent, nkAccQuoted:
+      e = newSymS(skEnumField, n.sons[i], c)
+    else:
+      illFormedAst(n[i])
+    e.typ = result
+    e.position = int(counter)
+    if e.position == 0: hasNull = true
+    if result.sym != nil and sfExported in result.sym.flags:
+      incl(e.flags, sfUsed)
+      incl(e.flags, sfExported)
+      if not isPure: strTableAdd(c.module.tab, e)
+    addSon(result.n, newSymNode(e))
+    styleCheckDef(e)
+    if sfGenSym notin e.flags and not isPure: addDecl(c, e)
+    inc(counter)
+  if not hasNull: incl(result.flags, tfNeedsInit)
+
+proc semSet(c: PContext, n: PNode, prev: PType): PType =
+  result = newOrPrevType(tySet, prev, c)
+  if sonsLen(n) == 2:
+    var base = semTypeNode(c, n.sons[1], nil)
+    addSonSkipIntLit(result, base)
+    if base.kind == tyGenericInst: base = lastSon(base)
+    if base.kind != tyGenericParam:
+      if not isOrdinalType(base):
+        localError(n.info, errOrdinalTypeExpected)
+      elif lengthOrd(base) > MaxSetElements:
+        localError(n.info, errSetTooBig)
+  else:
+    localError(n.info, errXExpectsOneTypeParam, "set")
+    addSonSkipIntLit(result, errorType(c))
+
+proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
+                  prev: PType): PType =
+  result = newOrPrevType(kind, prev, c)
+  if sonsLen(n) == 2:
+    var base = semTypeNode(c, n.sons[1], nil)
+    addSonSkipIntLit(result, base)
+  else:
+    localError(n.info, errXExpectsOneTypeParam, kindStr)
+    addSonSkipIntLit(result, errorType(c))
+
+proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
+  result = newOrPrevType(tyVarargs, prev, c)
+  if sonsLen(n) == 2 or sonsLen(n) == 3:
+    var base = semTypeNode(c, n.sons[1], nil)
+    addSonSkipIntLit(result, base)
+    if sonsLen(n) == 3:
+      result.n = newIdentNode(considerQuotedIdent(n.sons[2]), n.sons[2].info)
+  else:
+    localError(n.info, errXExpectsOneTypeParam, "varargs")
+    addSonSkipIntLit(result, errorType(c))
+
+proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
+  if n.len < 1:
+    result = newConstraint(c, kind)
+  else:
+    let isCall = ord(n.kind in nkCallKinds)
+    let n = if n[0].kind == nkBracket: n[0] else: n
+    checkMinSonsLen(n, 1)
+    result = newOrPrevType(kind, prev, c)
+    # check every except the last is an object:
+    for i in isCall .. n.len-2:
+      let region = semTypeNode(c, n[i], nil)
+      if region.skipTypes({tyGenericInst}).kind notin {tyError, tyObject}:
+        message n[i].info, errGenerated, "region needs to be an object type"
+      addSonSkipIntLit(result, region)
+    var base = semTypeNode(c, n.lastSon, nil)
+    addSonSkipIntLit(result, base)
+
+proc semVarType(c: PContext, n: PNode, prev: PType): PType =
+  if sonsLen(n) == 1:
+    result = newOrPrevType(tyVar, prev, c)
+    var base = semTypeNode(c, n.sons[0], nil)
+    if base.kind == tyVar:
+      localError(n.info, errVarVarTypeNotAllowed)
+      base = base.sons[0]
+    addSonSkipIntLit(result, base)
+  else:
+    result = newConstraint(c, tyVar)
+
+proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
+  if n.len == 0: return newConstraint(c, tyDistinct)
+  result = newOrPrevType(tyDistinct, prev, c)
+  addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
+  if n.len > 1: result.n = n[1]
+
+proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
+  assert isRange(n)
+  checkSonsLen(n, 3)
+  result = newOrPrevType(tyRange, prev, c)
+  result.n = newNodeI(nkRange, n.info)
+  if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
+    localError(n.info, errRangeIsEmpty)
+
+  var range: array[2, PNode]
+  range[0] = semExprWithType(c, n[1], {efDetermineType})
+  range[1] = semExprWithType(c, n[2], {efDetermineType})
+
+  var rangeT: array[2, PType]
+  for i in 0..1:
+    rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
+
+  if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
+    localError(n.info, errPureTypeMismatch)
+  elif not rangeT[0].isOrdinalType:
+    localError(n.info, errOrdinalTypeExpected)
+  elif enumHasHoles(rangeT[0]):
+    localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
+
+  for i in 0..1:
+    if hasGenericArguments(range[i]):
+      result.n.addSon makeStaticExpr(c, range[i])
+    else:
+      result.n.addSon semConstExpr(c, range[i])
+
+  if weakLeValue(result.n[0], result.n[1]) == impNo:
+    localError(n.info, errRangeIsEmpty)
+
+  addSonSkipIntLit(result, rangeT[0])
+
+proc semRange(c: PContext, n: PNode, prev: PType): PType =
+  result = nil
+  if sonsLen(n) == 2:
+    if isRange(n[1]):
+      result = semRangeAux(c, n[1], prev)
+      let n = result.n
+      if n.sons[0].kind in {nkCharLit..nkUInt64Lit} and n.sons[0].intVal > 0:
+        incl(result.flags, tfNeedsInit)
+      elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
+        incl(result.flags, tfNeedsInit)
+      elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
+          n.sons[0].floatVal > 0.0:
+        incl(result.flags, tfNeedsInit)
+      elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
+          n.sons[1].floatVal < 0.0:
+        incl(result.flags, tfNeedsInit)
+    else:
+      localError(n.sons[0].info, errRangeExpected)
+      result = newOrPrevType(tyError, prev, c)
+  else:
+    localError(n.info, errXExpectsOneTypeParam, "range")
+    result = newOrPrevType(tyError, prev, c)
+
+proc semArrayIndex(c: PContext, n: PNode): PType =
+  if isRange(n): result = semRangeAux(c, n, nil)
+  else:
+    let e = semExprWithType(c, n, {efDetermineType})
+    if e.typ.kind == tyFromExpr:
+      result = makeRangeWithStaticExpr(c, e.typ.n)
+    elif e.kind in {nkIntLit..nkUInt64Lit}:
+      result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
+    elif e.kind == nkSym and e.typ.kind == tyStatic:
+      if e.sym.ast != nil:
+        return semArrayIndex(c, e.sym.ast)
+      if not isOrdinalType(e.typ.lastSon):
+        localError(n[1].info, errOrdinalTypeExpected)
+      result = makeRangeWithStaticExpr(c, e)
+      if c.inGenericContext > 0: result.flags.incl tfUnresolved
+    elif e.kind in nkCallKinds and hasGenericArguments(e):
+      if not isOrdinalType(e.typ):
+        localError(n[1].info, errOrdinalTypeExpected)
+      # This is an int returning call, depending on an
+      # yet unknown generic param (see tgenericshardcases).
+      # We are going to construct a range type that will be
+      # properly filled-out in semtypinst (see how tyStaticExpr
+      # is handled there).
+      result = makeRangeWithStaticExpr(c, e)
+    elif e.kind == nkIdent:
+      result = e.typ.skipTypes({tyTypeDesc})
+    else:
+      let x = semConstExpr(c, e)
+      if x.kind in {nkIntLit..nkUInt64Lit}:
+        result = makeRangeType(c, 0, x.intVal-1, n.info,
+                             x.typ.skipTypes({tyTypeDesc}))
+      else:
+        result = x.typ.skipTypes({tyTypeDesc})
+        #localError(n[1].info, errConstExprExpected)
+
+proc semArray(c: PContext, n: PNode, prev: PType): PType =
+  var base: PType
+  result = newOrPrevType(tyArray, prev, c)
+  if sonsLen(n) == 3:
+    # 3 = length(array indx base)
+    var indx = semArrayIndex(c, n[1])
+    addSonSkipIntLit(result, indx)
+    if indx.kind == tyGenericInst: indx = lastSon(indx)
+    if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
+      if not isOrdinalType(indx):
+        localError(n.sons[1].info, errOrdinalTypeExpected)
+      elif enumHasHoles(indx):
+        localError(n.sons[1].info, errEnumXHasHoles,
+                   typeToString(indx.skipTypes({tyRange})))
+    base = semTypeNode(c, n.sons[2], nil)
+    addSonSkipIntLit(result, base)
+  else:
+    localError(n.info, errArrayExpectsTwoTypeParams)
+    result = newOrPrevType(tyError, prev, c)
+
+proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
+  result = newOrPrevType(tyOrdinal, prev, c)
+  if sonsLen(n) == 2:
+    var base = semTypeNode(c, n.sons[1], nil)
+    if base.kind != tyGenericParam:
+      if not isOrdinalType(base):
+        localError(n.sons[1].info, errOrdinalTypeExpected)
+    addSonSkipIntLit(result, base)
+  else:
+    localError(n.info, errXExpectsOneTypeParam, "ordinal")
+    result = newOrPrevType(tyError, prev, c)
+
+proc semTypeIdent(c: PContext, n: PNode): PSym =
+  if n.kind == nkSym:
+    result = n.sym
+  else:
+    when defined(nimfix):
+      result = pickSym(c, n, skType)
+      if result.isNil:
+        result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
+    else:
+      result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
+    if result != nil:
+      markUsed(n.info, result)
+      styleCheckUse(n.info, result)
+      if result.kind == skParam and result.typ.kind == tyTypeDesc:
+        # This is a typedesc param. is it already bound?
+        # it's not bound when it's used multiple times in the
+        # proc signature for example
+        if c.inGenericInst > 0:
+          let bound = result.typ.sons[0].sym
+          if bound != nil: return bound
+          return result
+        if result.typ.sym == nil:
+          localError(n.info, errTypeExpected)
+          return errorSym(c, n)
+        result = result.typ.sym.copySym
+        result.typ = copyType(result.typ, result.typ.owner, true)
+        result.typ.flags.incl tfUnresolved
+
+      if result.kind == skGenericParam:
+        if result.typ.kind == tyGenericParam and result.typ.len == 0 and
+           tfWildcard in result.typ.flags:
+          # collapse the wild-card param to a type
+          result.kind = skType
+          result.typ.flags.excl tfWildcard
+          return
+        else:
+          localError(n.info, errTypeExpected)
+          return errorSym(c, n)
+
+      if result.kind != skType:
+        # this implements the wanted ``var v: V, x: V`` feature ...
+        var ov: TOverloadIter
+        var amb = initOverloadIter(ov, c, n)
+        while amb != nil and amb.kind != skType:
+          amb = nextOverloadIter(ov, c, n)
+        if amb != nil: result = amb
+        else:
+          if result.kind != skError: localError(n.info, errTypeExpected)
+          return errorSym(c, n)
+      if result.typ.kind != tyGenericParam:
+        # XXX get rid of this hack!
+        var oldInfo = n.info
+        when defined(useNodeIds):
+          let oldId = n.id
+        reset(n[])
+        when defined(useNodeIds):
+          n.id = oldId
+        n.kind = nkSym
+        n.sym = result
+        n.info = oldInfo
+        n.typ = result.typ
+    else:
+      localError(n.info, errIdentifierExpected)
+      result = errorSym(c, n)
+
+proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
+  if sonsLen(n) == 0:
+    localError(n.info, errTypeExpected)
+  result = newOrPrevType(tyTuple, prev, c)
+  for i in countup(0, sonsLen(n) - 1):
+    addSonSkipIntLit(result, semTypeNode(c, n.sons[i], nil))
+
+proc semTuple(c: PContext, n: PNode, prev: PType): PType =
+  var typ: PType
+  result = newOrPrevType(tyTuple, prev, c)
+  result.n = newNodeI(nkRecList, n.info)
+  var check = initIntSet()
+  var counter = 0
+  for i in countup(0, sonsLen(n) - 1):
+    var a = n.sons[i]
+    if (a.kind != nkIdentDefs): illFormedAst(a)
+    checkMinSonsLen(a, 3)
+    var length = sonsLen(a)
+    if a.sons[length - 2].kind != nkEmpty:
+      typ = semTypeNode(c, a.sons[length - 2], nil)
+    else:
+      localError(a.info, errTypeExpected)
+      typ = errorType(c)
+    if a.sons[length - 1].kind != nkEmpty:
+      localError(a.sons[length - 1].info, errInitHereNotAllowed)
+    for j in countup(0, length - 3):
+      var field = newSymG(skField, a.sons[j], c)
+      field.typ = typ
+      field.position = counter
+      inc(counter)
+      if containsOrIncl(check, field.name.id):
+        localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
+      else:
+        addSon(result.n, newSymNode(field))
+        addSonSkipIntLit(result, typ)
+      if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
+
+proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
+                 allowed: TSymFlags): PSym =
+  # identifier with visibility
+  if n.kind == nkPostfix:
+    if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
+      # for gensym'ed identifiers the identifier may already have been
+      # transformed to a symbol and we need to use that here:
+      result = newSymG(kind, n.sons[1], c)
+      var v = n.sons[0].ident
+      if sfExported in allowed and v.id == ord(wStar):
+        incl(result.flags, sfExported)
+      else:
+        localError(n.sons[0].info, errInvalidVisibilityX, v.s)
+    else:
+      illFormedAst(n)
+  else:
+    result = newSymG(kind, n, c)
+
+proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
+                        allowed: TSymFlags): PSym =
+  if n.kind == nkPragmaExpr:
+    checkSonsLen(n, 2)
+    result = semIdentVis(c, kind, n.sons[0], allowed)
+    case kind
+    of skType:
+      # process pragmas later, because result.typ has not been set yet
+      discard
+    of skField: pragma(c, result, n.sons[1], fieldPragmas)
+    of skVar:   pragma(c, result, n.sons[1], varPragmas)
+    of skLet:   pragma(c, result, n.sons[1], letPragmas)
+    of skConst: pragma(c, result, n.sons[1], constPragmas)
+    else: discard
+  else:
+    result = semIdentVis(c, kind, n, allowed)
+  if gCmd == cmdPretty: styleCheckDef(n.info, result)
+
+proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
+  let ex = t[branchIndex][currentEx].skipConv
+  for i in countup(1, branchIndex):
+    for j in countup(0, sonsLen(t.sons[i]) - 2):
+      if i == branchIndex and j == currentEx: break
+      if overlap(t.sons[i].sons[j].skipConv, ex):
+        localError(ex.info, errDuplicateCaseLabel)
+
+proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
+  checkMinSonsLen(t, 1)
+  let ac = semConstExpr(c, a)
+  let bc = semConstExpr(c, b)
+  let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
+  let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
+
+  result = newNodeI(nkRange, a.info)
+  result.add(at)
+  result.add(bt)
+  if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
+  else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
+
+proc semCaseBranchRange(c: PContext, t, b: PNode,
+                        covered: var BiggestInt): PNode =
+  checkSonsLen(b, 3)
+  result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
+
+proc semCaseBranchSetElem(c: PContext, t, b: PNode,
+                          covered: var BiggestInt): PNode =
+  if isRange(b):
+    checkSonsLen(b, 3)
+    result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
+  elif b.kind == nkRange:
+    checkSonsLen(b, 2)
+    result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
+  else:
+    result = fitNode(c, t.sons[0].typ, b)
+    inc(covered)
+
+proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
+                   covered: var BiggestInt) =
+
+  for i in countup(0, sonsLen(branch) - 2):
+    var b = branch.sons[i]
+    if b.kind == nkRange:
+      branch.sons[i] = b
+    elif isRange(b):
+      branch.sons[i] = semCaseBranchRange(c, t, b, covered)
+    else:
+      # constant sets and arrays are allowed:
+      var r = semConstExpr(c, b)
+      if r.kind in {nkCurly, nkBracket} and len(r) == 0  and sonsLen(branch)==2:
+        # discarding ``{}`` and ``[]`` branches silently
+        delSon(branch, 0)
+        return
+      elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
+        checkMinSonsLen(t, 1)
+        branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
+        inc(covered)
+      else:
+        # first element is special and will overwrite: branch.sons[i]:
+        branch.sons[i] = semCaseBranchSetElem(c, t, r[0], covered)
+        # other elements have to be added to ``branch``
+        for j in 1 .. <r.len:
+          branch.add(semCaseBranchSetElem(c, t, r[j], covered))
+          # caution! last son of branch must be the actions to execute:
+          var L = branch.len
+          swap(branch.sons[L-2], branch.sons[L-1])
+    checkForOverlap(c, t, i, branchIndex)
+
+proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
+                      father: PNode, rectype: PType)
+proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
+                   father: PNode, rectype: PType) =
+  var a = copyNode(n)
+  checkMinSonsLen(n, 2)
+  semRecordNodeAux(c, n.sons[0], check, pos, a, rectype)
+  if a.sons[0].kind != nkSym:
+    internalError("semRecordCase: discriminant is no symbol")
+    return
+  incl(a.sons[0].sym.flags, sfDiscriminant)
+  var covered: BiggestInt = 0
+  var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
+  if not isOrdinalType(typ):
+    localError(n.info, errSelectorMustBeOrdinal)
+  elif firstOrd(typ) < 0:
+    localError(n.info, errOrdXMustNotBeNegative, a.sons[0].sym.name.s)
+  elif lengthOrd(typ) > 0x00007FFF:
+    localError(n.info, errLenXinvalid, a.sons[0].sym.name.s)
+  var chckCovered = true
+  for i in countup(1, sonsLen(n) - 1):
+    var b = copyTree(n.sons[i])
+    addSon(a, b)
+    case n.sons[i].kind
+    of nkOfBranch:
+      checkMinSonsLen(b, 2)
+      semCaseBranch(c, a, b, i, covered)
+    of nkElse:
+      chckCovered = false
+      checkSonsLen(b, 1)
+    else: illFormedAst(n)
+    delSon(b, sonsLen(b) - 1)
+    semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
+  if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
+    localError(a.info, errNotAllCasesCovered)
+  addSon(father, a)
+
+proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
+                      father: PNode, rectype: PType) =
+  if n == nil: return
+  case n.kind
+  of nkRecWhen:
+    var branch: PNode = nil   # the branch to take
+    for i in countup(0, sonsLen(n) - 1):
+      var it = n.sons[i]
+      if it == nil: illFormedAst(n)
+      var idx = 1
+      case it.kind
+      of nkElifBranch:
+        checkSonsLen(it, 2)
+        if c.inGenericContext == 0:
+          var e = semConstBoolExpr(c, it.sons[0])
+          if e.kind != nkIntLit: internalError(e.info, "semRecordNodeAux")
+          elif e.intVal != 0 and branch == nil: branch = it.sons[1]
+        else:
+          it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
+      of nkElse:
+        checkSonsLen(it, 1)
+        if branch == nil: branch = it.sons[0]
+        idx = 0
+      else: illFormedAst(n)
+      if c.inGenericContext > 0:
+        # use a new check intset here for each branch:
+        var newCheck: IntSet
+        assign(newCheck, check)
+        var newPos = pos
+        var newf = newNodeI(nkRecList, n.info)
+        semRecordNodeAux(c, it.sons[idx], newCheck, newPos, newf, rectype)
+        it.sons[idx] = if newf.len == 1: newf[0] else: newf
+    if c.inGenericContext > 0:
+      addSon(father, n)
+    elif branch != nil:
+      semRecordNodeAux(c, branch, check, pos, father, rectype)
+  of nkRecCase:
+    semRecordCase(c, n, check, pos, father, rectype)
+  of nkNilLit:
+    if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
+  of nkRecList:
+    # attempt to keep the nesting at a sane level:
+    var a = if father.kind == nkRecList: father else: copyNode(n)
+    for i in countup(0, sonsLen(n) - 1):
+      semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
+    if a != father: addSon(father, a)
+  of nkIdentDefs:
+    checkMinSonsLen(n, 3)
+    var length = sonsLen(n)
+    var a: PNode
+    if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
+    else: a = ast.emptyNode
+    if n.sons[length-1].kind != nkEmpty:
+      localError(n.sons[length-1].info, errInitHereNotAllowed)
+    var typ: PType
+    if n.sons[length-2].kind == nkEmpty:
+      localError(n.info, errTypeExpected)
+      typ = errorType(c)
+    else:
+      typ = semTypeNode(c, n.sons[length-2], nil)
+      propagateToOwner(rectype, typ)
+    let rec = rectype.sym
+    for i in countup(0, sonsLen(n)-3):
+      var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
+      suggestSym(n.sons[i].info, f)
+      f.typ = typ
+      f.position = pos
+      if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
+          (f.loc.r == nil):
+        f.loc.r = rope(f.name.s)
+        f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
+      inc(pos)
+      if containsOrIncl(check, f.name.id):
+        localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
+      if a.kind == nkEmpty: addSon(father, newSymNode(f))
+      else: addSon(a, newSymNode(f))
+      styleCheckDef(f)
+    if a.kind != nkEmpty: addSon(father, a)
+  of nkEmpty: discard
+  else: illFormedAst(n)
+
+proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
+                           n: PNode) =
+  case n.kind
+  of nkRecCase:
+    if (n.sons[0].kind != nkSym): internalError(n.info, "addInheritedFieldsAux")
+    addInheritedFieldsAux(c, check, pos, n.sons[0])
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
+      else: internalError(n.info, "addInheritedFieldsAux(record case branch)")
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      addInheritedFieldsAux(c, check, pos, n.sons[i])
+  of nkSym:
+    incl(check, n.sym.name.id)
+    inc(pos)
+  else: internalError(n.info, "addInheritedFieldsAux()")
+
+proc skipGenericInvocation(t: PType): PType {.inline.} =
+  result = t
+  if result.kind == tyGenericInvocation:
+    result = result.sons[0]
+  while result.kind in {tyGenericInst, tyGenericBody}:
+    result = lastSon(result)
+
+proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
+                        obj: PType) =
+  assert obj.kind == tyObject
+  if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
+    addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
+  addInheritedFieldsAux(c, check, pos, obj.n)
+
+proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
+  if n.sonsLen == 0: return newConstraint(c, tyObject)
+  var check = initIntSet()
+  var pos = 0
+  var base: PType = nil
+  # n.sons[0] contains the pragmas (if any). We process these later...
+  checkSonsLen(n, 3)
+  if n.sons[1].kind != nkEmpty:
+    base = skipTypesOrNil(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
+    if base.isNil:
+      localError(n.info, errIllegalRecursionInTypeX, "object")
+    else:
+      var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
+      if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
+        addInheritedFields(c, check, pos, concreteBase)
+      else:
+        if concreteBase.kind != tyError:
+          localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
+        base = nil
+  if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
+  result = newOrPrevType(tyObject, prev, c)
+  rawAddSon(result, base)
+  result.n = newNodeI(nkRecList, n.info)
+  semRecordNodeAux(c, n.sons[2], check, pos, result.n, result)
+  if n.sons[0].kind != nkEmpty:
+    # dummy symbol for `pragma`:
+    var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c)
+    s.typ = result
+    pragma(c, s, n.sons[0], typePragmas)
+  if base == nil and tfInheritable notin result.flags:
+    incl(result.flags, tfFinal)
+
+proc findEnforcedStaticType(t: PType): PType =
+  # This handles types such as `static[T] and Foo`,
+  # which are subset of `static[T]`, hence they could
+  # be treated in the same way
+  if t.kind == tyStatic: return t
+  if t.kind == tyAnd:
+    for s in t.sons:
+      let t = findEnforcedStaticType(s)
+      if t != nil: return t
+
+proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
+  if kind == skMacro:
+    let staticType = findEnforcedStaticType(param.typ)
+    if staticType != nil:
+      var a = copySym(param)
+      a.typ = staticType.base
+      addDecl(c, a)
+    elif param.typ.kind == tyTypeDesc:
+      addDecl(c, param)
+    else:
+      # within a macro, every param has the type NimNode!
+      let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode"
+               else: getSysSym"PNimrodNode"
+      var a = copySym(param)
+      a.typ = nn.typ
+      addDecl(c, a)
+  else:
+    if sfGenSym notin param.flags: addDecl(c, param)
+
+let typedescId = getIdent"typedesc"
+
+template shouldHaveMeta(t) =
+  internalAssert tfHasMeta in t.flags
+  # result.lastSon.flags.incl tfHasMeta
+
+proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
+                   paramType: PType, paramName: string,
+                   info: TLineInfo, anon = false): PType =
+  if paramType == nil: return # (e.g. proc return type)
+
+  proc addImplicitGenericImpl(typeClass: PType, typId: PIdent): PType =
+    let finalTypId = if typId != nil: typId
+                     else: getIdent(paramName & ":type")
+    if genericParams == nil:
+      # This happens with anonymous proc types appearing in signatures
+      # XXX: we need to lift these earlier
+      return
+    # is this a bindOnce type class already present in the param list?
+    for i in countup(0, genericParams.len - 1):
+      if genericParams.sons[i].sym.name.id == finalTypId.id:
+        return genericParams.sons[i].typ
+
+    let owner = if typeClass.sym != nil: typeClass.sym
+                else: getCurrOwner()
+    var s = newSym(skType, finalTypId, owner, info)
+    if typId == nil: s.flags.incl(sfAnon)
+    s.linkTo(typeClass)
+    typeClass.flags.incl tfImplicitTypeParam
+    s.position = genericParams.len
+    genericParams.addSon(newSymNode(s))
+    result = typeClass
+    addDecl(c, s)
+
+  # XXX: There are codegen errors if this is turned into a nested proc
+  template liftingWalk(typ: PType, anonFlag = false): expr =
+    liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
+  #proc liftingWalk(paramType: PType, anon = false): PType =
+
+  var paramTypId = if not anon and paramType.sym != nil: paramType.sym.name
+                   else: nil
+
+  template maybeLift(typ: PType): expr =
+    let lifted = liftingWalk(typ)
+    (if lifted != nil: lifted else: typ)
+
+  template addImplicitGeneric(e: expr): expr =
+    addImplicitGenericImpl(e, paramTypId)
+
+  case paramType.kind:
+  of tyAnything:
+    result = addImplicitGeneric(newTypeS(tyGenericParam, c))
+
+  of tyStatic:
+    # proc(a: expr{string}, b: expr{nkLambda})
+    # overload on compile time values and AST trees
+    if paramType.n != nil: return # this is a concrete type
+    if tfUnresolved in paramType.flags: return # already lifted
+    let base = paramType.base.maybeLift
+    if base.isMetaType and procKind == skMacro:
+      localError(info, errMacroBodyDependsOnGenericTypes, paramName)
+    result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
+    result.flags.incl({tfHasStatic, tfUnresolved})
+
+  of tyTypeDesc:
+    if tfUnresolved notin paramType.flags:
+      # naked typedescs are not bindOnce types
+      if paramType.base.kind == tyNone and paramTypId != nil and
+         paramTypId.id == typedescId.id: paramTypId = nil
+      result = addImplicitGeneric(
+        c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
+
+  of tyDistinct:
+    if paramType.sonsLen == 1:
+      # disable the bindOnce behavior for the type class
+      result = liftingWalk(paramType.sons[0], true)
+
+  of tySequence, tySet, tyArray, tyOpenArray,
+     tyVar, tyPtr, tyRef, tyProc:
+    # XXX: this is a bit strange, but proc(s: seq)
+    # produces tySequence(tyGenericParam, tyNone).
+    # This also seems to be true when creating aliases
+    # like: type myseq = distinct seq.
+    # Maybe there is another better place to associate
+    # the seq type class with the seq identifier.
+    if paramType.kind == tySequence and paramType.lastSon.kind == tyNone:
+      let typ = c.newTypeWithSons(tyBuiltInTypeClass,
+                                  @[newTypeS(paramType.kind, c)])
+      result = addImplicitGeneric(typ)
+    else:
+      for i in 0 .. <paramType.len:
+        if paramType.sons[i] == paramType:
+          globalError(info, errIllegalRecursionInTypeX, typeToString(paramType))
+        var lifted = liftingWalk(paramType.sons[i])
+        if lifted != nil:
+          paramType.sons[i] = lifted
+          result = paramType
+
+  of tyGenericBody:
+    result = newTypeS(tyGenericInvocation, c)
+    result.rawAddSon(paramType)
+
+    for i in 0 .. paramType.sonsLen - 2:
+      if paramType.sons[i].kind == tyStatic:
+        var x = copyNode(ast.emptyNode)
+        x.typ = paramType.sons[i]
+        result.rawAddSon makeTypeFromExpr(c, x) # aka 'tyUnknown'
+      else:
+        result.rawAddSon newTypeS(tyAnything, c)
+
+    if paramType.lastSon.kind == tyUserTypeClass:
+      result.kind = tyUserTypeClassInst
+      result.rawAddSon paramType.lastSon
+      return addImplicitGeneric(result)
+
+    result = instGenericContainer(c, paramType.sym.info, result,
+                                  allowMetaTypes = true)
+    result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
+    result = addImplicitGeneric(result)
+
+  of tyIter:
+    if paramType.callConv == ccInline:
+      if procKind notin {skTemplate, skMacro, skIterator}:
+        localError(info, errInlineIteratorsAsProcParams)
+      if paramType.len == 1:
+        let lifted = liftingWalk(paramType.base)
+        if lifted != nil: paramType.sons[0] = lifted
+      result = addImplicitGeneric(paramType)
+
+  of tyGenericInst:
+    if paramType.lastSon.kind == tyUserTypeClass:
+      var cp = copyType(paramType, getCurrOwner(), false)
+      cp.kind = tyUserTypeClassInst
+      return addImplicitGeneric(cp)
+
+    for i in 1 .. paramType.len-2:
+      var lifted = liftingWalk(paramType.sons[i])
+      if lifted != nil:
+        paramType.sons[i] = lifted
+        result = paramType
+        result.lastSon.shouldHaveMeta
+
+    let liftBody = liftingWalk(paramType.lastSon, true)
+    if liftBody != nil:
+      result = liftBody
+      result.shouldHaveMeta
+
+  of tyGenericInvocation:
+    for i in 1 .. <paramType.len:
+      let lifted = liftingWalk(paramType.sons[i])
+      if lifted != nil: paramType.sons[i] = lifted
+    when false:
+      let expanded = instGenericContainer(c, info, paramType,
+                                          allowMetaTypes = true)
+      result = liftingWalk(expanded, true)
+
+  of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
+    result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
+
+  of tyExpr:
+    if procKind notin {skMacro, skTemplate}:
+      result = addImplicitGeneric(newTypeS(tyAnything, c))
+
+  of tyGenericParam:
+    markUsed(info, paramType.sym)
+    styleCheckUse(info, paramType.sym)
+    if tfWildcard in paramType.flags:
+      paramType.flags.excl tfWildcard
+      paramType.sym.kind = skType
+
+  else: discard
+
+  # result = liftingWalk(paramType)
+
+proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
+  if n.kind == nkCurlyExpr:
+    result = semTypeNode(c, n.sons[0], nil)
+    constraint = semNodeKindConstraints(n)
+  else:
+    result = semTypeNode(c, n, nil)
+
+proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
+  result = newOrPrevType(tyProc, prev, c)
+  result.callConv = lastOptionEntry(c).defaultCC
+  result.n = newNodeI(nkFormalParams, info)
+  rawAddSon(result, nil) # return type
+  # result.n[0] used to be `nkType`, but now it's `nkEffectList` because
+  # the effects are now stored in there too ... this is a bit hacky, but as
+  # usual we desperately try to save memory:
+  addSon(result.n, newNodeI(nkEffectList, info))
+
+proc semProcTypeNode(c: PContext, n, genericParams: PNode,
+                     prev: PType, kind: TSymKind; isType=false): PType =
+  # for historical reasons (code grows) this is invoked for parameter
+  # lists too and then 'isType' is false.
+  var cl: IntSet
+  checkMinSonsLen(n, 1)
+  result = newProcType(c, n.info, prev)
+  if genericParams != nil and sonsLen(genericParams) == 0:
+    cl = initIntSet()
+  var check = initIntSet()
+  var counter = 0
+  for i in countup(1, n.len - 1):
+    var a = n.sons[i]
+    if a.kind != nkIdentDefs:
+      # for some generic instantiations the passed ':env' parameter
+      # for closures has already been produced (see bug #898). We simply
+      # skip this parameter here. It'll then be re-generated in another LL
+      # pass over this instantiation:
+      if a.kind == nkSym and sfFromGeneric in a.sym.flags: continue
+      illFormedAst(a)
+    checkMinSonsLen(a, 3)
+    var
+      typ: PType = nil
+      def: PNode = nil
+      constraint: PNode = nil
+      length = sonsLen(a)
+      hasType = a.sons[length-2].kind != nkEmpty
+      hasDefault = a.sons[length-1].kind != nkEmpty
+    if hasType:
+      typ = semParamType(c, a.sons[length-2], constraint)
+
+    if hasDefault:
+      def = semExprWithType(c, a.sons[length-1])
+      # check type compatibility between def.typ and typ:
+      if typ == nil:
+        typ = def.typ
+      elif def != nil:
+        # and def.typ != nil and def.typ.kind != tyNone:
+        # example code that triggers it:
+        # proc sort[T](cmp: proc(a, b: T): int = cmp)
+        if not containsGenericType(typ):
+          def = fitNode(c, typ, def)
+    if not hasType and not hasDefault:
+      if isType: localError(a.info, "':' expected")
+      let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
+      if tdef == tyAnything:
+        message(a.info, warnTypelessParam, renderTree(n))
+      typ = newTypeS(tdef, c)
+
+    if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
+    for j in countup(0, length-3):
+      var arg = newSymG(skParam, a.sons[j], c)
+      let lifted = liftParamType(c, kind, genericParams, typ,
+                                 arg.name.s, arg.info)
+      let finalType = if lifted != nil: lifted else: typ.skipIntLit
+      arg.typ = finalType
+      arg.position = counter
+      arg.constraint = constraint
+      inc(counter)
+      if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
+      if containsOrIncl(check, arg.name.id):
+        localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
+      addSon(result.n, newSymNode(arg))
+      rawAddSon(result, finalType)
+      addParamOrResult(c, arg, kind)
+      if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
+
+  var r: PType
+  if n.sons[0].kind != nkEmpty:
+    r = semTypeNode(c, n.sons[0], nil)
+  elif kind == skIterator:
+    # XXX This is special magic we should likely get rid of
+    r = newTypeS(tyExpr, c)
+
+  if r != nil:
+    # turn explicit 'void' return type into 'nil' because the rest of the
+    # compiler only checks for 'nil':
+    if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
+      # 'auto' as a return type does not imply a generic:
+      if r.kind != tyExpr:
+        if r.sym == nil or sfAnon notin r.sym.flags:
+          let lifted = liftParamType(c, kind, genericParams, r, "result",
+                                     n.sons[0].info)
+          if lifted != nil: r = lifted
+          r.flags.incl tfRetType
+        r = skipIntLit(r)
+        if kind == skIterator:
+          # see tchainediterators
+          # in cases like iterator foo(it: iterator): type(it)
+          # we don't need to change the return type to iter[T]
+          if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
+      result.sons[0] = r
+      result.n.typ = r
+
+  if genericParams != nil:
+    for n in genericParams:
+      if tfWildcard in n.sym.typ.flags:
+        n.sym.kind = skType
+        n.sym.typ.flags.excl tfWildcard
+
+proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
+  checkMinSonsLen(n, 1)
+  var length = sonsLen(n)
+  for i in countup(0, length - 2):
+    n.sons[i] = semStmt(c, n.sons[i])
+  if length > 0:
+    result = semTypeNode(c, n.sons[length - 1], prev)
+    n.typ = result
+    n.sons[length - 1].typ = result
+  else:
+    result = nil
+
+proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
+  inc(c.p.nestedBlockCounter)
+  checkSonsLen(n, 2)
+  openScope(c)
+  if n.sons[0].kind notin {nkEmpty, nkSym}:
+    addDecl(c, newSymS(skLabel, n.sons[0], c))
+  result = semStmtListType(c, n.sons[1], prev)
+  n.sons[1].typ = result
+  n.typ = result
+  closeScope(c)
+  dec(c.p.nestedBlockCounter)
+
+proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
+  result = semTypeNode(c, n, nil)
+
+proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
+  if s.typ == nil:
+    localError(n.info, "cannot instantiate the '$1' $2" %
+                       [s.name.s, ($s.kind).substr(2).toLower])
+    return newOrPrevType(tyError, prev, c)
+
+  var t = s.typ
+  if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
+    t = t.base
+
+  result = newOrPrevType(tyGenericInvocation, prev, c)
+  addSonSkipIntLit(result, t)
+
+  template addToResult(typ) =
+    if typ.isNil:
+      internalAssert false
+      rawAddSon(result, typ)
+    else: addSonSkipIntLit(result, typ)
+
+  if t.kind == tyForward:
+    for i in countup(1, sonsLen(n)-1):
+      var elem = semGenericParamInInvocation(c, n.sons[i])
+      addToResult(elem)
+    return
+  elif t.kind != tyGenericBody:
+    # we likely got code of the form TypeA[TypeB] where TypeA is
+    # not generic.
+    localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
+    return newOrPrevType(tyError, prev, c)
+  else:
+    var m = newCandidate(c, t)
+    matches(c, n, copyTree(n), m)
+
+    if m.state != csMatch and not m.typedescMatched:
+      let err = "cannot instantiate " & typeToString(t) & "\n" &
+                "got: (" & describeArgs(c, n) & ")\n" &
+                "but expected: (" & describeArgs(c, t.n, 0) & ")"
+      localError(n.info, errGenerated, err)
+      return newOrPrevType(tyError, prev, c)
+
+    var isConcrete = true
+
+    for i in 1 .. <m.call.len:
+      var typ = m.call[i].typ
+      if typ.kind == tyTypeDesc and typ.sons[0].kind == tyNone:
+        isConcrete = false
+        addToResult(typ)
+      else:
+        typ = typ.skipTypes({tyTypeDesc})
+        if containsGenericType(typ): isConcrete = false
+        addToResult(typ)
+
+    if isConcrete:
+      if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
+        # XXX: What kind of error is this? is it still relevant?
+        localError(n.info, errCannotInstantiateX, s.name.s)
+        result = newOrPrevType(tyError, prev, c)
+      else:
+        result = instGenericContainer(c, n.info, result,
+                                      allowMetaTypes = false)
+
+proc semTypeExpr(c: PContext, n: PNode): PType =
+  var n = semExprWithType(c, n, {efDetermineType})
+  if n.typ.kind == tyTypeDesc:
+    result = n.typ.base
+  else:
+    localError(n.info, errTypeExpected, n.renderTree)
+
+proc freshType(res, prev: PType): PType {.inline.} =
+  if prev.isNil:
+    result = copyType(res, res.owner, keepId=false)
+  else:
+    result = res
+
+proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
+  # if n.sonsLen == 0: return newConstraint(c, tyTypeClass)
+  if nfBase2 in n.flags:
+    message(n.info, warnDeprecated, "use 'concept' instead; 'generic'")
+  result = newOrPrevType(tyUserTypeClass, prev, c)
+  result.n = n
+
+  let
+    pragmas = n[1]
+    inherited = n[2]
+
+  if inherited.kind != nkEmpty:
+    for n in inherited.sons:
+      let typ = semTypeNode(c, n, nil)
+      result.sons.safeAdd(typ)
+
+proc semProcTypeWithScope(c: PContext, n: PNode,
+                        prev: PType, kind: TSymKind): PType =
+  checkSonsLen(n, 2)
+  openScope(c)
+  result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
+  # dummy symbol for `pragma`:
+  var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
+  s.typ = result
+  if n.sons[1].kind == nkEmpty or n.sons[1].len == 0:
+    if result.callConv == ccDefault:
+      result.callConv = ccClosure
+      #Message(n.info, warnImplicitClosure, renderTree(n))
+  else:
+    pragma(c, s, n.sons[1], procTypePragmas)
+    when useEffectSystem: setEffectsForProcType(result, n.sons[1])
+  closeScope(c)
+
+proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
+  result = nil
+  if gCmd == cmdIdeTools: suggestExpr(c, n)
+  case n.kind
+  of nkEmpty: discard
+  of nkTypeOfExpr:
+    # for ``type(countup(1,3))``, see ``tests/ttoseq``.
+    checkSonsLen(n, 1)
+    let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
+    result = typExpr.typ.skipTypes({tyIter})
+  of nkPar:
+    if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
+    else:
+      result = semAnonTuple(c, n, prev)
+  of nkCallKinds:
+    if isRange(n):
+      result = semRangeAux(c, n, prev)
+    elif n[0].kind notin nkIdentKinds:
+      result = semTypeExpr(c, n)
+    else:
+      let op = considerQuotedIdent(n.sons[0])
+      if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
+        checkSonsLen(n, 3)
+        var
+          t1 = semTypeNode(c, n.sons[1], nil)
+          t2 = semTypeNode(c, n.sons[2], nil)
+        if t1 == nil:
+          localError(n.sons[1].info, errTypeExpected)
+          result = newOrPrevType(tyError, prev, c)
+        elif t2 == nil:
+          localError(n.sons[2].info, errTypeExpected)
+          result = newOrPrevType(tyError, prev, c)
+        else:
+          result = if op.id == ord(wAnd): makeAndType(c, t1, t2)
+                   else: makeOrType(c, t1, t2)
+      elif op.id == ord(wNot):
+        case n.len
+        of 3:
+          result = semTypeNode(c, n.sons[1], prev)
+          if result.skipTypes({tyGenericInst}).kind in NilableTypes+GenericTypes and
+              n.sons[2].kind == nkNilLit:
+            result = freshType(result, prev)
+            result.flags.incl(tfNotNil)
+          else:
+            localError(n.info, errGenerated, "invalid type")
+        of 2:
+          let negated = semTypeNode(c, n.sons[1], prev)
+          result = makeNotType(c, negated)
+        else:
+          localError(n.info, errGenerated, "invalid type")
+      elif op.id == ord(wPtr):
+        result = semAnyRef(c, n, tyPtr, prev)
+      elif op.id == ord(wRef):
+        result = semAnyRef(c, n, tyRef, prev)
+      elif op.id == ord(wType):
+        checkSonsLen(n, 2)
+        let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
+        result = typExpr.typ.skipTypes({tyIter})
+      else:
+        result = semTypeExpr(c, n)
+  of nkWhenStmt:
+    var whenResult = semWhen(c, n, false)
+    if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
+    result = semTypeNode(c, whenResult, prev)
+  of nkBracketExpr:
+    checkMinSonsLen(n, 2)
+    var s = semTypeIdent(c, n.sons[0])
+    case s.magic
+    of mArray: result = semArray(c, n, prev)
+    of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev)
+    of mRange: result = semRange(c, n, prev)
+    of mSet: result = semSet(c, n, prev)
+    of mOrdinal: result = semOrdinal(c, n, prev)
+    of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
+    of mVarargs: result = semVarargs(c, n, prev)
+    of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
+    of mExpr:
+      result = semTypeNode(c, n.sons[0], nil)
+      if result != nil:
+        result = copyType(result, getCurrOwner(), false)
+        for i in countup(1, n.len - 1):
+          result.rawAddSon(semTypeNode(c, n.sons[i], nil))
+    else: result = semGeneric(c, n, s, prev)
+  of nkDotExpr:
+    var typeExpr = semExpr(c, n)
+    if typeExpr.typ.kind != tyTypeDesc:
+      localError(n.info, errTypeExpected)
+      result = errorType(c)
+    else:
+      result = typeExpr.typ.base
+      if result.isMetaType:
+        var preprocessed = semGenericStmt(c, n)
+        result = makeTypeFromExpr(c, preprocessed.copyTree)
+  of nkIdent, nkAccQuoted:
+    var s = semTypeIdent(c, n)
+    if s.typ == nil:
+      if s.kind != skError: localError(n.info, errTypeExpected)
+      result = newOrPrevType(tyError, prev, c)
+    elif s.kind == skParam and s.typ.kind == tyTypeDesc:
+      internalAssert s.typ.base.kind != tyNone and prev == nil
+      result = s.typ.base
+    elif prev == nil:
+      result = s.typ
+    else:
+      assignType(prev, s.typ)
+      # bugfix: keep the fresh id for aliases to integral types:
+      if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
+                           tyUInt..tyUInt64}:
+        prev.id = s.typ.id
+      result = prev
+  of nkSym:
+    if n.sym.kind == skType and n.sym.typ != nil:
+      var t = n.sym.typ
+      if prev == nil:
+        result = t
+      else:
+        assignType(prev, t)
+        result = prev
+      markUsed(n.info, n.sym)
+      styleCheckUse(n.info, n.sym)
+    else:
+      if n.sym.kind != skError: localError(n.info, errTypeExpected)
+      result = newOrPrevType(tyError, prev, c)
+  of nkObjectTy: result = semObjectNode(c, n, prev)
+  of nkTupleTy: result = semTuple(c, n, prev)
+  of nkTupleClassTy: result = newConstraint(c, tyTuple)
+  of nkTypeClassTy: result = semTypeClass(c, n, prev)
+  of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
+  of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
+  of nkVarTy: result = semVarType(c, n, prev)
+  of nkDistinctTy: result = semDistinct(c, n, prev)
+  of nkStaticTy:
+    result = newOrPrevType(tyStatic, prev, c)
+    var base = semTypeNode(c, n.sons[0], nil)
+    result.rawAddSon(base)
+    result.flags.incl tfHasStatic
+  of nkIteratorTy:
+    if n.sonsLen == 0:
+      result = newConstraint(c, tyIter)
+    else:
+      result = semProcTypeWithScope(c, n, prev, skClosureIterator)
+      if n.lastSon.kind == nkPragma and hasPragma(n.lastSon, wInline):
+        result.kind = tyIter
+        result.callConv = ccInline
+      else:
+        result.flags.incl(tfIterator)
+        result.callConv = ccClosure
+  of nkProcTy:
+    if n.sonsLen == 0:
+      result = newConstraint(c, tyProc)
+    else:
+      result = semProcTypeWithScope(c, n, prev, skProc)
+  of nkEnumTy: result = semEnum(c, n, prev)
+  of nkType: result = n.typ
+  of nkStmtListType: result = semStmtListType(c, n, prev)
+  of nkBlockType: result = semBlockType(c, n, prev)
+  of nkSharedTy:
+    checkSonsLen(n, 1)
+    result = semTypeNode(c, n.sons[0], prev)
+    result = freshType(result, prev)
+    result.flags.incl(tfShared)
+  else:
+    localError(n.info, errTypeExpected)
+    result = newOrPrevType(tyError, prev, c)
+  n.typ = result
+
+proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
+  m.typ.kind = kind
+  m.typ.align = size.int16
+  m.typ.size = size
+
+proc processMagicType(c: PContext, m: PSym) =
+  case m.magic
+  of mInt: setMagicType(m, tyInt, intSize)
+  of mInt8: setMagicType(m, tyInt8, 1)
+  of mInt16: setMagicType(m, tyInt16, 2)
+  of mInt32: setMagicType(m, tyInt32, 4)
+  of mInt64: setMagicType(m, tyInt64, 8)
+  of mUInt: setMagicType(m, tyUInt, intSize)
+  of mUInt8: setMagicType(m, tyUInt8, 1)
+  of mUInt16: setMagicType(m, tyUInt16, 2)
+  of mUInt32: setMagicType(m, tyUInt32, 4)
+  of mUInt64: setMagicType(m, tyUInt64, 8)
+  of mFloat: setMagicType(m, tyFloat, floatSize)
+  of mFloat32: setMagicType(m, tyFloat32, 4)
+  of mFloat64: setMagicType(m, tyFloat64, 8)
+  of mFloat128: setMagicType(m, tyFloat128, 16)
+  of mBool: setMagicType(m, tyBool, 1)
+  of mChar: setMagicType(m, tyChar, 1)
+  of mString:
+    setMagicType(m, tyString, ptrSize)
+    rawAddSon(m.typ, getSysType(tyChar))
+  of mCstring:
+    setMagicType(m, tyCString, ptrSize)
+    rawAddSon(m.typ, getSysType(tyChar))
+  of mPointer: setMagicType(m, tyPointer, ptrSize)
+  of mEmptySet:
+    setMagicType(m, tySet, 1)
+    rawAddSon(m.typ, newTypeS(tyEmpty, c))
+  of mIntSetBaseType: setMagicType(m, tyRange, intSize)
+  of mNil: setMagicType(m, tyNil, ptrSize)
+  of mExpr: setMagicType(m, tyExpr, 0)
+  of mStmt: setMagicType(m, tyStmt, 0)
+  of mTypeDesc:
+    setMagicType(m, tyTypeDesc, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
+  of mVoidType: setMagicType(m, tyEmpty, 0)
+  of mArray:
+    setMagicType(m, tyArray, 0)
+  of mOpenArray:
+    setMagicType(m, tyOpenArray, 0)
+  of mVarargs:
+    setMagicType(m, tyVarargs, 0)
+  of mRange:
+    setMagicType(m, tyRange, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
+  of mSet:
+    setMagicType(m, tySet, 0)
+  of mSeq:
+    setMagicType(m, tySequence, 0)
+  of mOrdinal:
+    setMagicType(m, tyOrdinal, 0)
+    rawAddSon(m.typ, newTypeS(tyNone, c))
+  of mPNimrodNode: discard
+  of mShared:
+    setMagicType(m, tyObject, 0)
+    m.typ.n = newNodeI(nkRecList, m.info)
+    incl m.typ.flags, tfShared
+  of mGuarded:
+    setMagicType(m, tyObject, 0)
+    m.typ.n = newNodeI(nkRecList, m.info)
+    incl m.typ.flags, tfShared
+    rawAddSon(m.typ, sysTypeFromName"shared")
+  else: localError(m.info, errTypeExpected)
+
+proc semGenericConstraints(c: PContext, x: PType): PType =
+  result = newTypeWithSons(c, tyGenericParam, @[x])
+
+proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
+  result = copyNode(n)
+  if n.kind != nkGenericParams:
+    illFormedAst(n)
+    return
+  for i in countup(0, sonsLen(n)-1):
+    var a = n.sons[i]
+    if a.kind != nkIdentDefs: illFormedAst(n)
+    let L = a.len
+    var def = a{-1}
+    let constraint = a{-2}
+    var typ: PType
+
+    if constraint.kind != nkEmpty:
+      typ = semTypeNode(c, constraint, nil)
+      if typ.kind != tyStatic or typ.len == 0:
+        if typ.kind == tyTypeDesc:
+          if typ.sons[0].kind == tyNone:
+            typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
+        else:
+          typ = semGenericConstraints(c, typ)
+
+    if def.kind != nkEmpty:
+      def = semConstExpr(c, def)
+      if typ == nil:
+        if def.typ.kind != tyTypeDesc:
+          typ = newTypeWithSons(c, tyStatic, @[def.typ])
+      else:
+        # the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
+        # from manyloc/named_argument_bug/triengine:
+        def.typ = def.typ.skipTypes({tyTypeDesc})
+        if not containsGenericType(def.typ):
+          def = fitNode(c, typ, def)
+
+    if typ == nil:
+      typ = newTypeS(tyGenericParam, c)
+      if father == nil: typ.flags.incl tfWildcard
+
+    typ.flags.incl tfGenericTypeParam
+
+    for j in countup(0, L-3):
+      let finalType = if j == 0: typ
+                      else: copyType(typ, typ.owner, false)
+                      # it's important the we create an unique
+                      # type for each generic param. the index
+                      # of the parameter will be stored in the
+                      # attached symbol.
+      var s = if finalType.kind == tyStatic or tfWildcard in typ.flags:
+          newSymG(skGenericParam, a.sons[j], c).linkTo(finalType)
+        else:
+          newSymG(skType, a.sons[j], c).linkTo(finalType)
+      if def.kind != nkEmpty: s.ast = def
+      if father != nil: addSonSkipIntLit(father, s.typ)
+      s.position = result.len
+      addSon(result, newSymNode(s))
+      if sfGenSym notin s.flags: addDecl(c, s)
+
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
new file mode 100644
index 000000000..c5caf8b92
--- /dev/null
+++ b/compiler/semtypinst.nim
@@ -0,0 +1,485 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module does the instantiation of generic types.
+
+import ast, astalgo, msgs, types, magicsys, semdata, renderer
+
+const
+  tfInstClearedFlags = {tfHasMeta}
+
+proc sharedPtrCheck(info: TLineInfo, t: PType) =
+  if t.kind == tyPtr and t.len > 1:
+    if t.sons[0].sym.magic == mShared:
+      incl(t.flags, tfShared)
+      #if t.sons[0].sym.magic == mGuarded: incl(t.flags, tfGuarded)
+      if tfHasGCedMem in t.flags or t.isGCedMem:
+        localError(info, errGenerated,
+                   "shared memory may not refer to GC'ed thread local memory")
+
+proc checkPartialConstructedType(info: TLineInfo, t: PType) =
+  if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
+    localError(info, errInvalidPragmaX, "acyclic")
+  elif t.kind == tyVar and t.sons[0].kind == tyVar:
+    localError(info, errVarVarTypeNotAllowed)
+  else:
+    sharedPtrCheck(info, t)
+
+proc checkConstructedType*(info: TLineInfo, typ: PType) =
+  var t = typ.skipTypes({tyDistinct})
+  if t.kind in tyTypeClasses: discard
+  elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
+    localError(info, errInvalidPragmaX, "acyclic")
+  elif t.kind == tyVar and t.sons[0].kind == tyVar:
+    localError(info, errVarVarTypeNotAllowed)
+  elif computeSize(t) == szIllegalRecursion:
+    localError(info, errIllegalRecursionInTypeX, typeToString(t))
+  else:
+    sharedPtrCheck(info, t)
+  when false:
+    if t.kind == tyObject and t.sons[0] != nil:
+      if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
+        localError(info, errInheritanceOnlyWithNonFinalObjects)
+
+proc searchInstTypes*(key: PType): PType =
+  let genericTyp = key.sons[0]
+  internalAssert genericTyp.kind == tyGenericBody and
+                 key.sons[0] == genericTyp and
+                 genericTyp.sym != nil
+
+  if genericTyp.sym.typeInstCache == nil:
+    return
+
+  for inst in genericTyp.sym.typeInstCache:
+    if inst.id == key.id: return inst
+    if inst.sons.len < key.sons.len:
+      # XXX: This happens for prematurely cached
+      # types such as TChannel[empty]. Why?
+      # See the notes for PActor in handleGenericInvocation
+      return
+    block matchType:
+      for j in 1 .. high(key.sons):
+        # XXX sameType is not really correct for nested generics?
+        if not compareTypes(inst.sons[j], key.sons[j],
+                            flags = {ExactGenericParams}):
+          break matchType
+
+      return inst
+
+proc cacheTypeInst*(inst: PType) =
+  # XXX: add to module's generics
+  #      update the refcount
+  let genericTyp = inst.sons[0]
+  genericTyp.sym.typeInstCache.safeAdd(inst)
+
+type
+  TReplTypeVars* {.final.} = object
+    c*: PContext
+    typeMap*: TIdTable        # map PType to PType
+    symMap*: TIdTable         # map PSym to PSym
+    localCache*: TIdTable     # local cache for remembering alraedy replaced
+                              # types during instantiation of meta types
+                              # (they are not stored in the global cache)
+    info*: TLineInfo
+    allowMetaTypes*: bool     # allow types such as seq[Number]
+                              # i.e. the result contains unresolved generics
+    skipTypedesc*: bool       # wether we should skip typeDescs
+
+proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
+proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
+proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode): PNode
+
+template checkMetaInvariants(cl: TReplTypeVars, t: PType) =
+  when false:
+    if t != nil and tfHasMeta in t.flags and
+       cl.allowMetaTypes == false:
+      echo "UNEXPECTED META ", t.id, " ", instantiationInfo(-1)
+      debug t
+      writeStackTrace()
+
+proc replaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
+  result = replaceTypeVarsTAux(cl, t)
+  checkMetaInvariants(cl, result)
+
+proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
+  let t = replaceTypeVarsT(cl, n.typ)
+  if t != nil and t.kind == tyStatic and t.n != nil:
+    return t.n
+  result = copyNode(n)
+  result.typ = t
+  if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
+  let isCall = result.kind in nkCallKinds
+  for i in 0 .. <n.safeLen:
+    # XXX HACK: ``f(a, b)``, avoid to instantiate `f`
+    if isCall and i == 0: result.add(n[i])
+    else: result.add(prepareNode(cl, n[i]))
+
+proc isTypeParam(n: PNode): bool =
+  # XXX: generic params should use skGenericParam instead of skType
+  return n.kind == nkSym and
+         (n.sym.kind == skGenericParam or
+           (n.sym.kind == skType and sfFromGeneric in n.sym.flags))
+
+proc hasGenericArguments*(n: PNode): bool =
+  if n.kind == nkSym:
+    return n.sym.kind == skGenericParam or
+           (n.sym.kind == skType and
+            n.sym.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} != {})
+  else:
+    for i in 0.. <n.safeLen:
+      if hasGenericArguments(n.sons[i]): return true
+    return false
+
+proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
+  # This is needed for tgenericshardcases
+  # It's possible that a generic param will be used in a proc call to a
+  # typedesc accepting proc. After generic param substitution, such procs
+  # should be optionally instantiated with the correct type. In order to
+  # perform this instantiation, we need to re-run the generateInstance path
+  # in the compiler, but it's quite complicated to do so at the moment so we
+  # resort to a mild hack; the head symbol of the call is temporary reset and
+  # overload resolution is executed again (which may trigger generateInstance).
+  if n.kind in nkCallKinds and sfFromGeneric in n[0].sym.flags:
+    var needsFixing = false
+    for i in 1 .. <n.safeLen:
+      if isTypeParam(n[i]): needsFixing = true
+    if needsFixing:
+      n.sons[0] = newSymNode(n.sons[0].sym.owner)
+      return cl.c.semOverloadedCall(cl.c, n, n, {skProc})
+
+  for i in 0 .. <n.safeLen:
+    n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])
+
+  return n
+
+proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode): PNode =
+  if n == nil: return
+  result = copyNode(n)
+  if n.typ != nil:
+    result.typ = replaceTypeVarsT(cl, n.typ)
+    checkMetaInvariants(cl, result.typ)
+  case n.kind
+  of nkNone..pred(nkSym), succ(nkSym)..nkNilLit:
+    discard
+  of nkSym:
+    result.sym = replaceTypeVarsS(cl, n.sym)
+    if result.sym.typ.kind == tyEmpty:
+      # don't add the 'void' field
+      result = newNode(nkRecList, n.info)
+  of nkRecWhen:
+    var branch: PNode = nil              # the branch to take
+    for i in countup(0, sonsLen(n) - 1):
+      var it = n.sons[i]
+      if it == nil: illFormedAst(n)
+      case it.kind
+      of nkElifBranch:
+        checkSonsLen(it, 2)
+        var cond = prepareNode(cl, it.sons[0])
+        var e = cl.c.semConstExpr(cl.c, cond)
+        if e.kind != nkIntLit:
+          internalError(e.info, "ReplaceTypeVarsN: when condition not a bool")
+        if e.intVal != 0 and branch == nil: branch = it.sons[1]
+      of nkElse:
+        checkSonsLen(it, 1)
+        if branch == nil: branch = it.sons[0]
+      else: illFormedAst(n)
+    if branch != nil:
+      result = replaceTypeVarsN(cl, branch)
+    else:
+      result = newNodeI(nkRecList, n.info)
+  of nkStaticExpr:
+    var n = prepareNode(cl, n)
+    n = reResolveCallsWithTypedescParams(cl, n)
+    result = if cl.allowMetaTypes: n
+             else: cl.c.semExpr(cl.c, n)
+  else:
+    var length = sonsLen(n)
+    if length > 0:
+      newSons(result, length)
+      for i in countup(0, length - 1):
+        result.sons[i] = replaceTypeVarsN(cl, n.sons[i])
+
+proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
+  if s == nil: return nil
+  result = PSym(idTableGet(cl.symMap, s))
+  if result == nil:
+    result = copySym(s, false)
+    incl(result.flags, sfFromGeneric)
+    idTablePut(cl.symMap, s, result)
+    result.owner = s.owner
+    result.typ = replaceTypeVarsT(cl, s.typ)
+    result.ast = replaceTypeVarsN(cl, s.ast)
+
+proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
+  result = PType(idTableGet(cl.typeMap, t))
+  if result == nil:
+    if cl.allowMetaTypes or tfRetType in t.flags: return
+    localError(t.sym.info, errCannotInstantiateX, typeToString(t))
+    result = errorType(cl.c)
+    # In order to prevent endless recursions, we must remember
+    # this bad lookup and replace it with errorType everywhere.
+    # These code paths are only active in "nim check"
+    idTablePut(cl.typeMap, t, result)
+  elif result.kind == tyGenericParam and not cl.allowMetaTypes:
+    internalError(cl.info, "substitution with generic parameter")
+
+proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
+  # XXX: relying on allowMetaTypes is a kludge
+  result = copyType(t, t.owner, cl.allowMetaTypes)
+  result.flags.incl tfFromGeneric
+  if not (t.kind in tyMetaTypes or
+         (t.kind == tyStatic and t.n == nil)):
+    result.flags.excl tfInstClearedFlags
+
+proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
+  # tyGenericInvocation[A, tyGenericInvocation[A, B]]
+  # is difficult to handle:
+  var body = t.sons[0]
+  if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
+  var header: PType = t
+  # search for some instantiation here:
+  if cl.allowMetaTypes:
+    result = PType(idTableGet(cl.localCache, t))
+  else:
+    result = searchInstTypes(t)
+  if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
+  for i in countup(1, sonsLen(t) - 1):
+    var x = t.sons[i]
+    if x.kind == tyGenericParam:
+      x = lookupTypeVar(cl, x)
+      if x != nil:
+        if header == t: header = instCopyType(cl, t)
+        header.sons[i] = x
+        propagateToOwner(header, x)
+    else:
+      propagateToOwner(header, x)
+
+  if header != t:
+    # search again after first pass:
+    result = searchInstTypes(header)
+    if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
+  else:
+    header = instCopyType(cl, t)
+
+  result = newType(tyGenericInst, t.sons[0].owner)
+  result.flags = header.flags
+  # be careful not to propagate unnecessary flags here (don't use rawAddSon)
+  result.sons = @[header.sons[0]]
+  # ugh need another pass for deeply recursive generic types (e.g. PActor)
+  # we need to add the candidate here, before it's fully instantiated for
+  # recursive instantions:
+  if not cl.allowMetaTypes:
+    cacheTypeInst(result)
+  else:
+    idTablePut(cl.localCache, t, result)
+
+  let oldSkipTypedesc = cl.skipTypedesc
+  cl.skipTypedesc = true
+  for i in countup(1, sonsLen(t) - 1):
+    var x = replaceTypeVarsT(cl, t.sons[i])
+    assert x.kind != tyGenericInvocation
+    header.sons[i] = x
+    propagateToOwner(header, x)
+    idTablePut(cl.typeMap, body.sons[i-1], x)
+
+  for i in countup(1, sonsLen(t) - 1):
+    # if one of the params is not concrete, we cannot do anything
+    # but we already raised an error!
+    rawAddSon(result, header.sons[i])
+
+  var newbody = replaceTypeVarsT(cl, lastSon(body))
+  cl.skipTypedesc = oldSkipTypedesc
+  newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
+  result.flags = result.flags + newbody.flags - tfInstClearedFlags
+  # This is actually wrong: tgeneric_closure fails with this line:
+  #newbody.callConv = body.callConv
+  # This type may be a generic alias and we want to resolve it here.
+  # One step is enough, because the recursive nature of
+  # handleGenericInvocation will handle the alias-to-alias-to-alias case
+  if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
+  rawAddSon(result, newbody)
+  checkPartialConstructedType(cl.info, newbody)
+  let dc = newbody.deepCopy
+  if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
+    # 'deepCopy' needs to be instantiated for
+    # generics *when the type is constructed*:
+    newbody.deepCopy = cl.c.instTypeBoundOp(cl.c, dc, result, cl.info,
+                                            attachedDeepCopy)
+  let asgn = newbody.assignment
+  if asgn != nil and sfFromGeneric notin asgn.flags:
+    # '=' needs to be instantiated for generics when the type is constructed:
+    newbody.assignment = cl.c.instTypeBoundOp(cl.c, asgn, result, cl.info,
+                                              attachedAsgn)
+
+proc eraseVoidParams*(t: PType) =
+  # transform '(): void' into '()' because old parts of the compiler really
+  # don't deal with '(): void':
+  if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
+    t.sons[0] = nil
+
+  for i in 1 .. <t.sonsLen:
+    # don't touch any memory unless necessary
+    if t.sons[i].kind == tyEmpty:
+      var pos = i
+      for j in i+1 .. <t.sonsLen:
+        if t.sons[j].kind != tyEmpty:
+          t.sons[pos] = t.sons[j]
+          t.n.sons[pos] = t.n.sons[j]
+          inc pos
+      setLen t.sons, pos
+      setLen t.n.sons, pos
+      return
+
+proc skipIntLiteralParams*(t: PType) =
+  for i in 0 .. <t.sonsLen:
+    let p = t.sons[i]
+    if p == nil: continue
+    let skipped = p.skipIntLit
+    if skipped != p:
+      t.sons[i] = skipped
+      if i > 0: t.n.sons[i].sym.typ = skipped
+
+  # when the typeof operator is used on a static input
+  # param, the results gets infected with static as well:
+  if t.sons[0] != nil and t.sons[0].kind == tyStatic:
+    t.sons[0] = t.sons[0].base
+
+proc propagateFieldFlags(t: PType, n: PNode) =
+  # This is meant for objects and tuples
+  # The type must be fully instantiated!
+  if n.isNil:
+    return
+  internalAssert n.kind != nkRecWhen
+  case n.kind
+  of nkSym:
+    propagateToOwner(t, n.sym.typ)
+  of nkRecList, nkRecCase, nkOfBranch, nkElse:
+    for son in n:
+      propagateFieldFlags(t, son)
+  else: discard
+
+proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
+  result = t
+  if t == nil: return
+
+  if t.kind in {tyStatic, tyGenericParam, tyIter} + tyTypeClasses:
+    let lookup = PType(idTableGet(cl.typeMap, t))
+    if lookup != nil: return lookup
+
+  case t.kind
+  of tyGenericInvocation:
+    result = handleGenericInvocation(cl, t)
+
+  of tyGenericBody:
+    localError(cl.info, errCannotInstantiateX, typeToString(t))
+    result = errorType(cl.c)
+    #result = replaceTypeVarsT(cl, lastSon(t))
+
+  of tyFromExpr:
+    if cl.allowMetaTypes: return
+    assert t.n.typ != t
+    var n = prepareNode(cl, t.n)
+    if n.kind != nkEmpty:
+      n = cl.c.semConstExpr(cl.c, n)
+    if n.typ.kind == tyTypeDesc:
+      # XXX: sometimes, chained typedescs enter here.
+      # It may be worth investigating why this is happening,
+      # because it may cause other bugs elsewhere.
+      result = n.typ.skipTypes({tyTypeDesc})
+      # result = n.typ.base
+    else:
+      if n.typ.kind != tyStatic:
+        # XXX: In the future, semConstExpr should
+        # return tyStatic values to let anyone make
+        # use of this knowledge. The patching here
+        # won't be necessary then.
+        result = newTypeS(tyStatic, cl.c)
+        result.sons = @[n.typ]
+        result.n = n
+      else:
+        result = n.typ
+
+  of tyInt, tyFloat:
+    result = skipIntLit(t)
+
+  of tyTypeDesc:
+    let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
+    if lookup != nil:
+      result = lookup
+      if tfUnresolved in t.flags or cl.skipTypedesc: result = result.base
+    elif t.sons[0].kind != tyNone:
+      result = makeTypeDesc(cl.c, replaceTypeVarsT(cl, t.sons[0]))
+
+  of tyUserTypeClass:
+    result = t
+
+  of tyGenericInst:
+    result = PType(idTableGet(cl.localCache, t))
+    if result != nil: return result
+    result = instCopyType(cl, t)
+    idTablePut(cl.localCache, t, result)
+    for i in 1 .. <result.sonsLen:
+      result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
+    propagateToOwner(result, result.lastSon)
+
+  else:
+    if containsGenericType(t):
+      #if not cl.allowMetaTypes:
+      result = PType(idTableGet(cl.localCache, t))
+      if result != nil: return result
+      result = instCopyType(cl, t)
+      result.size = -1 # needs to be recomputed
+      #if not cl.allowMetaTypes:
+      idTablePut(cl.localCache, t, result)
+
+      for i in countup(0, sonsLen(result) - 1):
+        if result.sons[i] != nil:
+          result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
+          propagateToOwner(result, result.sons[i])
+
+      result.n = replaceTypeVarsN(cl, result.n)
+
+      case result.kind
+      of tyArray:
+        let idx = result.sons[0]
+        internalAssert idx.kind != tyStatic
+
+      of tyObject, tyTuple:
+        propagateFieldFlags(result, result.n)
+
+      of tyProc:
+        eraseVoidParams(result)
+        skipIntLiteralParams(result)
+
+      else: discard
+
+proc initTypeVars*(p: PContext, pt: TIdTable, info: TLineInfo): TReplTypeVars =
+  initIdTable(result.symMap)
+  copyIdTable(result.typeMap, pt)
+  initIdTable(result.localCache)
+  result.info = info
+  result.c = p
+
+proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode): PNode =
+  var cl = initTypeVars(p, pt, n.info)
+  pushInfoContext(n.info)
+  result = replaceTypeVarsN(cl, n)
+  popInfoContext()
+
+proc generateTypeInstance*(p: PContext, pt: TIdTable, info: TLineInfo,
+                           t: PType): PType =
+  var cl = initTypeVars(p, pt, info)
+  pushInfoContext(info)
+  result = replaceTypeVarsT(cl, t)
+  popInfoContext()
+
+template generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode,
+                               t: PType): expr =
+  generateTypeInstance(p, pt, arg.info, t)
+
diff --git a/compiler/service.nim b/compiler/service.nim
new file mode 100644
index 000000000..7cb9d7d29
--- /dev/null
+++ b/compiler/service.nim
@@ -0,0 +1,87 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements the "compiler as a service" feature.
+
+import
+  times, commands, options, msgs, nimconf,
+  extccomp, strutils, os, platform, parseopt
+
+when useCaas:
+  import net
+
+# We cache modules and the dependency graph. However, we don't check for
+# file changes but expect the client to tell us about them, otherwise the
+# repeated CRC calculations may turn out to be too slow.
+
+var
+  curCaasCmd* = ""
+  lastCaasCmd* = ""
+    # in caas mode, the list of defines and options will be given at start-up?
+    # it's enough to check that the previous compilation command is the same?
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
+  var p = parseopt.initOptParser(cmd)
+  var argsCount = 0
+  while true:
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break
+    of cmdLongoption, cmdShortOption:
+      if p.key == " ":
+        p.key = "-"
+        if processArgument(pass, p, argsCount): break
+      else:
+        processSwitch(pass, p)
+    of cmdArgument:
+      if processArgument(pass, p, argsCount): break
+  if pass == passCmd2:
+    if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
+      rawMessage(errArgsNeedRunOption, [])
+
+proc serve*(action: proc (){.nimcall.}) =
+  template execute(cmd) =
+    curCaasCmd = cmd
+    processCmdLine(passCmd2, cmd)
+    action()
+    gErrorCounter = 0
+
+  let typ = getConfigVar("server.type")
+  case typ
+  of "stdin":
+    while true:
+      var line = stdin.readLine.string
+      if line == "quit": quit()
+      execute line
+      echo ""
+      flushFile(stdout)
+
+  of "tcp", "":
+    when useCaas:
+      var server = newSocket()
+      let p = getConfigVar("server.port")
+      let port = if p.len > 0: parseInt(p).Port else: 6000.Port
+      server.bindAddr(port, getConfigVar("server.address"))
+      var inp = "".TaintedString
+      server.listen()
+      var stdoutSocket = newSocket()
+      msgs.writelnHook = proc (line: string) =
+        stdoutSocket.send(line & "\c\L")
+
+      while true:
+        accept(server, stdoutSocket)
+        stdoutSocket.readLine(inp)
+        execute inp.string
+        stdoutSocket.send("\c\L")
+        stdoutSocket.close()
+    else:
+      msgQuit "server.type not supported; compiler built without caas support"
+  else:
+    echo "Invalid server.type:", typ
+    msgQuit 1
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
new file mode 100644
index 000000000..7ea2c3d6f
--- /dev/null
+++ b/compiler/sigmatch.nim
@@ -0,0 +1,1772 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the signature matching for resolving
+## the call to overloaded procs, generic procs and operators.
+
+import
+  intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
+  magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
+  nimfix.pretty
+
+when not defined(noDocgen):
+  import docgen
+
+type
+  TCandidateState* = enum
+    csEmpty, csMatch, csNoMatch
+
+  CandidateErrors* = seq[PSym]
+  TCandidate* = object
+    c*: PContext
+    exactMatches*: int       # also misused to prefer iters over procs
+    genericMatches: int      # also misused to prefer constraints
+    subtypeMatches: int
+    intConvMatches: int      # conversions to int are not as expensive
+    convMatches: int
+    state*: TCandidateState
+    callee*: PType           # may not be nil!
+    calleeSym*: PSym         # may be nil
+    calleeScope*: int        # scope depth:
+                             # is this a top-level symbol or a nested proc?
+    call*: PNode             # modified call
+    bindings*: TIdTable      # maps types to types
+    baseTypeMatch: bool      # needed for conversions from T to openarray[T]
+                             # for example
+    fauxMatch*: TTypeKind    # the match was successful only due to the use
+                             # of error or wildcard (unknown) types.
+                             # this is used to prevent instantiations.
+    genericConverter*: bool  # true if a generic converter needs to
+                             # be instantiated
+    coerceDistincts*: bool   # this is an explicit coercion that can strip away
+                             # a distrinct type
+    typedescMatched*: bool
+    inheritancePenalty: int  # to prefer closest father object type
+    errors*: CandidateErrors # additional clarifications to be displayed to the
+                             # user if overload resolution fails
+
+  TTypeRelation* = enum      # order is important!
+    isNone, isConvertible,
+    isIntConv,
+    isSubtype,
+    isSubrange,              # subrange of the wanted type; no type conversion
+                             # but apart from that counts as ``isSubtype``
+    isInferred,              # generic proc was matched against a concrete type
+    isInferredConvertible,   # same as above, but requiring proc CC conversion
+    isGeneric,
+    isFromIntLit,            # conversion *from* int literal; proven safe
+    isEqual
+
+const
+  isNilConversion = isConvertible # maybe 'isIntConv' fits better?
+
+proc markUsed*(info: TLineInfo, s: PSym)
+
+template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
+
+proc initCandidateAux(ctx: PContext,
+                      c: var TCandidate, callee: PType) {.inline.} =
+  c.c = ctx
+  c.exactMatches = 0
+  c.subtypeMatches = 0
+  c.convMatches = 0
+  c.intConvMatches = 0
+  c.genericMatches = 0
+  c.state = csEmpty
+  c.callee = callee
+  c.call = nil
+  c.baseTypeMatch = false
+  c.genericConverter = false
+  c.inheritancePenalty = 0
+
+proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
+  initCandidateAux(ctx, c, callee)
+  c.calleeSym = nil
+  initIdTable(c.bindings)
+
+proc put(t: var TIdTable, key, val: PType) {.inline.} =
+  idTablePut(t, key, val.skipIntLit)
+
+proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
+                    binding: PNode, calleeScope = -1) =
+  initCandidateAux(ctx, c, callee.typ)
+  c.calleeSym = callee
+  if callee.kind in skProcKinds and calleeScope == -1:
+    if callee.originatingModule == ctx.module:
+      c.calleeScope = 2
+      var owner = callee
+      while true:
+        owner = owner.skipGenericOwner
+        if owner.kind == skModule: break
+        inc c.calleeScope
+    else:
+      c.calleeScope = 1
+  else:
+    c.calleeScope = calleeScope
+  initIdTable(c.bindings)
+  c.errors = nil
+  if binding != nil and callee.kind in routineKinds:
+    var typeParams = callee.ast[genericParamsPos]
+    for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
+      var formalTypeParam = typeParams.sons[i-1].typ
+      var bound = binding[i].typ
+      internalAssert bound != nil
+      if formalTypeParam.kind == tyTypeDesc:
+        if bound.kind != tyTypeDesc:
+          bound = makeTypeDesc(ctx, bound)
+      else:
+        bound = bound.skipTypes({tyTypeDesc})
+      put(c.bindings, formalTypeParam, bound)
+
+proc newCandidate*(ctx: PContext, callee: PSym,
+                   binding: PNode, calleeScope = -1): TCandidate =
+  initCandidate(ctx, result, callee, binding, calleeScope)
+
+proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
+  initCandidate(ctx, result, callee)
+
+proc copyCandidate(a: var TCandidate, b: TCandidate) =
+  a.c = b.c
+  a.exactMatches = b.exactMatches
+  a.subtypeMatches = b.subtypeMatches
+  a.convMatches = b.convMatches
+  a.intConvMatches = b.intConvMatches
+  a.genericMatches = b.genericMatches
+  a.state = b.state
+  a.callee = b.callee
+  a.calleeSym = b.calleeSym
+  a.call = copyTree(b.call)
+  a.baseTypeMatch = b.baseTypeMatch
+  copyIdTable(a.bindings, b.bindings)
+
+proc sumGeneric(t: PType): int =
+  var t = t
+  var isvar = 1
+  while true:
+    case t.kind
+    of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyArrayConstr,
+        tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody:
+      t = t.lastSon
+      inc result
+    of tyVar:
+      t = t.sons[0]
+      inc result
+      inc isvar
+    of tyGenericInvocation, tyTuple:
+      result += ord(t.kind == tyGenericInvocation)
+      for i in 0 .. <t.len: result += t.sons[i].sumGeneric
+      break
+    of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
+    of tyBool, tyChar, tyEnum, tyObject, tyProc, tyPointer,
+        tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
+        tyUInt..tyUInt64:
+      return isvar
+    else:
+      return 0
+
+#var ggDebug: bool
+
+proc complexDisambiguation(a, b: PType): int =
+  # 'a' matches better if *every* argument matches better or equal than 'b'.
+  var winner = 0
+  for i in 1 .. <min(a.len, b.len):
+    let x = a.sons[i].sumGeneric
+    let y = b.sons[i].sumGeneric
+    #if ggDebug:
+    #  echo "came her ", typeToString(a.sons[i]), " ", typeToString(b.sons[i])
+    if x != y:
+      if winner == 0:
+        if x > y: winner = 1
+        else: winner = -1
+      elif x > y:
+        if winner != 1:
+          # contradiction
+          return 0
+      else:
+        if winner != -1:
+          return 0
+  result = winner
+  when false:
+    var x, y: int
+    for i in 1 .. <a.len: x += a.sons[i].sumGeneric
+    for i in 1 .. <b.len: y += b.sons[i].sumGeneric
+    result = x - y
+
+proc cmpCandidates*(a, b: TCandidate): int =
+  result = a.exactMatches - b.exactMatches
+  if result != 0: return
+  result = a.genericMatches - b.genericMatches
+  if result != 0: return
+  result = a.subtypeMatches - b.subtypeMatches
+  if result != 0: return
+  result = a.intConvMatches - b.intConvMatches
+  if result != 0: return
+  result = a.convMatches - b.convMatches
+  if result != 0: return
+  result = a.calleeScope - b.calleeScope
+  if result != 0: return
+  # the other way round because of other semantics:
+  result = b.inheritancePenalty - a.inheritancePenalty
+  if result != 0: return
+  # prefer more specialized generic over more general generic:
+  result = complexDisambiguation(a.callee, b.callee)
+
+proc writeMatches*(c: TCandidate) =
+  writeln(stdout, "exact matches: " & $c.exactMatches)
+  writeln(stdout, "generic matches: " & $c.genericMatches)
+  writeln(stdout, "subtype matches: " & $c.subtypeMatches)
+  writeln(stdout, "intconv matches: " & $c.intConvMatches)
+  writeln(stdout, "conv matches: " & $c.convMatches)
+  writeln(stdout, "inheritance: " & $c.inheritancePenalty)
+
+proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
+  if arg.kind in nkSymChoices:
+    result = typeToString(arg[0].typ, prefer)
+    for i in 1 .. <arg.len:
+      result.add(" | ")
+      result.add typeToString(arg[i].typ, prefer)
+  else:
+    result = arg.typ.typeToString(prefer)
+
+proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
+                   prefer: TPreferedDesc = preferName): string =
+  result = ""
+  for i in countup(startIdx, n.len - 1):
+    var arg = n.sons[i]
+    if n.sons[i].kind == nkExprEqExpr:
+      add(result, renderTree(n.sons[i].sons[0]))
+      add(result, ": ")
+      if arg.typ.isNil:
+        arg = c.semOperand(c, n.sons[i].sons[1])
+        n.sons[i].typ = arg.typ
+        n.sons[i].sons[1] = arg
+    else:
+      if arg.typ.isNil:
+        arg = c.semOperand(c, n.sons[i])
+        n.sons[i] = arg
+    if arg.typ.kind == tyError: return
+    add(result, argTypeToString(arg, prefer))
+    if i != sonsLen(n) - 1: add(result, ", ")
+
+proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
+proc concreteType(c: TCandidate, t: PType): PType =
+  case t.kind
+  of tyArrayConstr:
+    # make it an array
+    result = newType(tyArray, t.owner)
+    addSonSkipIntLit(result, t.sons[0]) # XXX: t.owner is wrong for ID!
+    addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
+  of tyNil:
+    result = nil              # what should it be?
+  of tySequence, tySet:
+    if t.sons[0].kind == tyEmpty: result = nil
+    else: result = t
+  of tyGenericParam, tyAnything:
+    result = t
+    while true:
+      result = PType(idTableGet(c.bindings, t))
+      if result == nil:
+        break # it's ok, no match
+        # example code that triggers it:
+        # proc sort[T](cmp: proc(a, b: T): int = cmp)
+      if result.kind != tyGenericParam: break
+  of tyGenericInvocation:
+    internalError("cannot resolve type: " & typeToString(t))
+    result = t
+  else:
+    result = t                # Note: empty is valid here
+
+proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
+  if a.kind == f.kind:
+    result = isEqual
+  else:
+    let ab = skipTypes(a, {tyRange})
+    let k = ab.kind
+    if k == f.kind: result = isSubrange
+    elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
+                                   tyUInt..tyUInt64} and
+        isIntLit(ab) and ab.n.intVal >= firstOrd(f) and
+                         ab.n.intVal <= lastOrd(f):
+      # integer literal in the proper range; we want ``i16 + 4`` to stay an
+      # ``int16`` operation so we declare the ``4`` pseudo-equal to int16
+      result = isFromIntLit
+    elif f.kind == tyInt and k in {tyInt8..tyInt32}:
+      result = isIntConv
+    elif k >= min and k <= max:
+      result = isConvertible
+    elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
+                                                  tyUInt8..tyUInt32} and
+                         a.n[0].intVal >= firstOrd(f) and
+                         a.n[1].intVal <= lastOrd(f):
+      result = isConvertible
+    else: result = isNone
+    #elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
+    #elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv
+
+proc isConvertibleToRange(f, a: PType): bool =
+  # be less picky for tyRange, as that it is used for array indexing:
+  if f.kind in {tyInt..tyInt64, tyUInt..tyUInt64} and
+     a.kind in {tyInt..tyInt64, tyUInt..tyUInt64}:
+    result = true
+  elif f.kind in {tyFloat..tyFloat128} and
+       a.kind in {tyFloat..tyFloat128}:
+    result = true
+
+proc handleFloatRange(f, a: PType): TTypeRelation =
+  if a.kind == f.kind:
+    result = isEqual
+  else:
+    let ab = skipTypes(a, {tyRange})
+    var k = ab.kind
+    if k == f.kind: result = isSubrange
+    elif isFloatLit(ab): result = isFromIntLit
+    elif isIntLit(ab): result = isConvertible
+    elif k >= tyFloat and k <= tyFloat128:
+      # conversion to "float32" is not as good:
+      if f.kind == tyFloat32: result = isConvertible
+      else: result = isIntConv
+    else: result = isNone
+
+proc isObjectSubtype(a, f: PType): int =
+  var t = a
+  assert t.kind == tyObject
+  var depth = 0
+  while t != nil and not sameObjectTypes(f, t):
+    assert t.kind == tyObject
+    t = t.sons[0]
+    if t == nil: break
+    t = skipTypes(t, {tyGenericInst})
+    inc depth
+  if t != nil:
+    result = depth
+
+proc minRel(a, b: TTypeRelation): TTypeRelation =
+  if a <= b: result = a
+  else: result = b
+
+proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
+  result = isNone
+  if sameType(f, a):
+    result = isEqual
+  elif sonsLen(a) == sonsLen(f):
+    result = isEqual
+    let firstField = if f.kind == tyTuple: 0
+                     else: 1
+    for i in countup(firstField, sonsLen(f) - 1):
+      var m = typeRel(c, f.sons[i], a.sons[i])
+      if m < isSubtype: return isNone
+      result = minRel(result, m)
+    if f.n != nil and a.n != nil:
+      for i in countup(0, sonsLen(f.n) - 1):
+        # check field names:
+        if f.n.sons[i].kind != nkSym: internalError(f.n.info, "recordRel")
+        elif a.n.sons[i].kind != nkSym: internalError(a.n.info, "recordRel")
+        else:
+          var x = f.n.sons[i].sym
+          var y = a.n.sons[i].sym
+          if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
+            return isNone
+          if x.name.id != y.name.id: return isNone
+
+proc allowsNil(f: PType): TTypeRelation {.inline.} =
+  result = if tfNotNil notin f.flags: isSubtype else: isNone
+
+proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
+  result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
+
+proc procParamTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
+  var f = f
+
+  if a.isMetaType:
+    if f.isMetaType:
+      # We are matching a generic proc (as proc param)
+      # to another generic type appearing in the proc
+      # signature. There is a change that the target
+      # type is already fully-determined, so we are
+      # going to try resolve it
+      f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
+      if f == nil or f.isMetaType:
+        # no luck resolving the type, so the inference fails
+        return isNone
+    let reverseRel = typeRel(c, a, f)
+    if reverseRel >= isGeneric:
+      result = isInferred
+      #inc c.genericMatches
+  else:
+    result = typeRel(c, f, a)
+
+  if result <= isSubtype or inconsistentVarTypes(f, a):
+    result = isNone
+
+  #if result == isEqual:
+  #  inc c.exactMatches
+
+proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
+  case a.kind
+  of tyProc:
+    if sonsLen(f) != sonsLen(a): return
+    result = isEqual      # start with maximum; also correct for no
+                          # params at all
+
+    template checkParam(f, a) =
+      result = minRel(result, procParamTypeRel(c, f, a))
+      if result == isNone: return
+
+    # Note: We have to do unification for the parameters before the
+    # return type!
+    for i in 1 .. <f.sonsLen:
+      checkParam(f.sons[i], a.sons[i])
+
+    if f.sons[0] != nil:
+      if a.sons[0] != nil:
+        checkParam(f.sons[0], a.sons[0])
+      else:
+        return isNone
+    elif a.sons[0] != nil:
+      return isNone
+
+    if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
+      return isNone
+    elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
+        optThreadAnalysis in gGlobalOptions:
+      # noSideEffect implies ``tfThread``!
+      return isNone
+    elif f.flags * {tfIterator} != a.flags * {tfIterator}:
+      return isNone
+    elif f.callConv != a.callConv:
+      # valid to pass a 'nimcall' thingie to 'closure':
+      if f.callConv == ccClosure and a.callConv == ccDefault:
+        result = if result != isInferred: isConvertible
+                 else: isInferredConvertible
+      else:
+        return isNone
+    when useEffectSystem:
+      if not compatibleEffects(f, a): return isNone
+
+  of tyNil:
+    result = f.allowsNil
+  of tyIter:
+    if tfIterator in f.flags: result = typeRel(c, f.base, a.base)
+  else: discard
+
+proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
+  let
+    a0 = firstOrd(a)
+    a1 = lastOrd(a)
+    f0 = firstOrd(f)
+    f1 = lastOrd(f)
+  if a0 == f0 and a1 == f1:
+    result = isEqual
+  elif a0 >= f0 and a1 <= f1:
+    result = isConvertible
+  elif a0 <= f1 and f0 <= a1:
+    # X..Y and C..D overlap iff (X <= D and C <= Y)
+    result = isConvertible
+  else:
+    result = isNone
+
+proc matchUserTypeClass*(c: PContext, m: var TCandidate,
+                         ff, a: PType): TTypeRelation =
+  var body = ff.skipTypes({tyUserTypeClassInst})
+
+  openScope(c)
+  inc c.inTypeClass
+
+  defer:
+    dec c.inTypeClass
+    closeScope(c)
+
+  if ff.kind == tyUserTypeClassInst:
+    for i in 1 .. <(ff.len - 1):
+      var
+        typeParamName = ff.base.sons[i-1].sym.name
+        typ = ff.sons[i]
+        param: PSym
+
+      template paramSym(kind): expr =
+        newSym(kind, typeParamName, body.sym, body.sym.info)
+
+      case typ.kind
+      of tyStatic:
+        param = paramSym skConst
+        param.typ = typ.base
+        param.ast = typ.n
+      of tyUnknown:
+        param = paramSym skVar
+        param.typ = typ
+      else:
+        param = paramSym skType
+        param.typ = makeTypeDesc(c, typ)
+
+      addDecl(c, param)
+      #echo "A ", param.name.s, " ", typeToString(param.typ), " ", param.kind
+
+  for param in body.n[0]:
+    var
+      dummyName: PNode
+      dummyType: PType
+
+    if param.kind == nkVarTy:
+      dummyName = param[0]
+      dummyType = if a.kind != tyVar: makeVarType(c, a) else: a
+    else:
+      dummyName = param
+      dummyType = a
+
+    internalAssert dummyName.kind == nkIdent
+    var dummyParam = newSym(skVar, dummyName.ident, body.sym, body.sym.info)
+    dummyParam.typ = dummyType
+    addDecl(c, dummyParam)
+    #echo "B ", dummyName.ident.s, " ", typeToString(dummyType), " ", dummyparam.kind
+
+  var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
+  if checkedBody == nil: return isNone
+  return isGeneric
+
+proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
+  if rules.kind == nkWith:
+    for r in rules:
+      if r.considerQuotedIdent == callIdent: return true
+    return false
+  else:
+    for r in rules:
+      if r.considerQuotedIdent == callIdent: return false
+    return true
+
+proc maybeSkipDistinct(t: PType, callee: PSym): PType =
+  if t != nil and t.kind == tyDistinct and t.n != nil and
+     shouldSkipDistinct(t.n, callee.name):
+    result = t.base
+  else:
+    result = t
+
+proc tryResolvingStaticExpr(c: var TCandidate, n: PNode): PNode =
+  # Consider this example:
+  #   type Value[N: static[int]] = object
+  #   proc foo[N](a: Value[N], r: range[0..(N-1)])
+  # Here, N-1 will be initially nkStaticExpr that can be evaluated only after
+  # N is bound to a concrete value during the matching of the first param.
+  # This proc is used to evaluate such static expressions.
+  let instantiated = replaceTypesInBody(c.c, c.bindings, n)
+  result = c.c.semExpr(c.c, instantiated)
+
+proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
+  # typeRel can be used to establish various relationships between types:
+  #
+  # 1) When used with concrete types, it will check for type equivalence
+  # or a subtype relationship.
+  #
+  # 2) When used with a concrete type against a type class (such as generic
+  # signature of a proc), it will check whether the concrete type is a member
+  # of the designated type class.
+  #
+  # 3) When used with two type classes, it will check whether the types
+  # matching the first type class are a strict subset of the types matching
+  # the other. This allows us to compare the signatures of generic procs in
+  # order to give preferrence to the most specific one:
+  #
+  # seq[seq[any]] is a strict subset of seq[any] and hence more specific.
+
+  result = isNone
+  assert(f != nil)
+
+  if f.kind == tyExpr:
+    if aOrig != nil: put(c.bindings, f, aOrig)
+    return isGeneric
+
+  assert(aOrig != nil)
+
+  # var and static arguments match regular modifier-free types
+  let a = aOrig.skipTypes({tyStatic, tyVar}).maybeSkipDistinct(c.calleeSym)
+  # XXX: Theoretically, maybeSkipDistinct could be called before we even
+  # start the param matching process. This could be done in `prepareOperand`
+  # for example, but unfortunately `prepareOperand` is not called in certain
+  # situation when nkDotExpr are rotated to nkDotCalls
+
+  if a.kind == tyGenericInst and
+      skipTypes(f, {tyVar}).kind notin {
+        tyGenericBody, tyGenericInvocation,
+        tyGenericInst, tyGenericParam} + tyTypeClasses:
+    return typeRel(c, f, lastSon(a))
+
+  template bindingRet(res) =
+    if doBind:
+      let bound = aOrig.skipTypes({tyRange}).skipIntLit
+      if doBind: put(c.bindings, f, bound)
+    return res
+
+  template considerPreviousT(body: stmt) {.immediate.} =
+    var prev = PType(idTableGet(c.bindings, f))
+    if prev == nil: body
+    else: return typeRel(c, prev, a)
+
+  case a.kind
+  of tyOr:
+    # seq[int|string] vs seq[number]
+    # both int and string must match against number
+    # but ensure that '[T: A|A]' matches as good as '[T: A]' (bug #2219):
+    result = isGeneric
+    for branch in a.sons:
+      let x = typeRel(c, f, branch, false)
+      if x == isNone: return isNone
+      if x < result: result = x
+
+  of tyAnd:
+    # seq[Sortable and Iterable] vs seq[Sortable]
+    # only one match is enough
+    for branch in a.sons:
+      let x = typeRel(c, f, branch, false)
+      if x != isNone:
+        return if x >= isGeneric: isGeneric else: x
+    result = isNone
+
+  of tyNot:
+    case f.kind
+    of tyNot:
+      # seq[!int] vs seq[!number]
+      # seq[float] matches the first, but not the second
+      # we must turn the problem around:
+      # is number a subset of int?
+      return typeRel(c, a.lastSon, f.lastSon)
+
+    else:
+      # negative type classes are essentially infinite,
+      # so only the `any` type class is their superset
+      return if f.kind == tyAnything: isGeneric
+             else: isNone
+
+  of tyAnything:
+    return if f.kind == tyAnything: isGeneric
+           else: isNone
+  else: discard
+
+  case f.kind
+  of tyEnum:
+    if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
+    elif sameEnumTypes(f, skipTypes(a, {tyRange})): result = isSubtype
+  of tyBool, tyChar:
+    if a.kind == f.kind: result = isEqual
+    elif skipTypes(a, {tyRange}).kind == f.kind: result = isSubtype
+  of tyRange:
+    if a.kind == f.kind:
+      if f.base.kind == tyNone: return isGeneric
+      result = typeRel(c, base(f), base(a))
+      # bugfix: accept integer conversions here
+      #if result < isGeneric: result = isNone
+      if result notin {isNone, isGeneric}:
+        # resolve any late-bound static expressions
+        # that may appear in the range:
+        for i in 0..1:
+          if f.n[i].kind == nkStaticExpr:
+            f.n.sons[i] = tryResolvingStaticExpr(c, f.n[i])
+        result = typeRangeRel(f, a)
+    else:
+      if skipTypes(f, {tyRange}).kind == a.kind:
+        result = isIntConv
+      elif isConvertibleToRange(skipTypes(f, {tyRange}), a):
+        result = isConvertible  # a convertible to f
+  of tyInt:      result = handleRange(f, a, tyInt8, tyInt32)
+  of tyInt8:     result = handleRange(f, a, tyInt8, tyInt8)
+  of tyInt16:    result = handleRange(f, a, tyInt8, tyInt16)
+  of tyInt32:    result = handleRange(f, a, tyInt8, tyInt32)
+  of tyInt64:    result = handleRange(f, a, tyInt, tyInt64)
+  of tyUInt:     result = handleRange(f, a, tyUInt8, tyUInt32)
+  of tyUInt8:    result = handleRange(f, a, tyUInt8, tyUInt8)
+  of tyUInt16:   result = handleRange(f, a, tyUInt8, tyUInt16)
+  of tyUInt32:   result = handleRange(f, a, tyUInt8, tyUInt32)
+  of tyUInt64:   result = handleRange(f, a, tyUInt, tyUInt64)
+  of tyFloat:    result = handleFloatRange(f, a)
+  of tyFloat32:  result = handleFloatRange(f, a)
+  of tyFloat64:  result = handleFloatRange(f, a)
+  of tyFloat128: result = handleFloatRange(f, a)
+  of tyVar:
+    if aOrig.kind == tyVar: result = typeRel(c, f.base, aOrig.base)
+    else: result = typeRel(c, f.base, aOrig)
+  of tyArray, tyArrayConstr:
+    # tyArrayConstr cannot happen really, but
+    # we wanna be safe here
+    case a.kind
+    of tyArray, tyArrayConstr:
+      var fRange = f.sons[0]
+      if fRange.kind == tyGenericParam:
+        var prev = PType(idTableGet(c.bindings, fRange))
+        if prev == nil:
+          put(c.bindings, fRange, a.sons[0])
+          fRange = a
+        else:
+          fRange = prev
+      result = typeRel(c, f.sons[1], a.sons[1])
+      if result < isGeneric: return isNone
+      if rangeHasStaticIf(fRange):
+        if tfUnresolved in fRange.flags:
+          # This is a range from an array instantiated with a generic
+          # static param. We must extract the static param here and bind
+          # it to the size of the currently supplied array.
+          var
+            rangeStaticT = fRange.getStaticTypeFromRange
+            replacementT = newTypeWithSons(c.c, tyStatic, @[tyInt.getSysType])
+            inputUpperBound = a.sons[0].n[1].intVal
+          # we must correct for the off-by-one discrepancy between
+          # ranges and static params:
+          replacementT.n = newIntNode(nkIntLit, inputUpperBound + 1)
+          put(c.bindings, rangeStaticT, replacementT)
+          return isGeneric
+
+        let len = tryResolvingStaticExpr(c, fRange.n[1])
+        if len.kind == nkIntLit and len.intVal+1 == lengthOrd(a):
+          return # if we get this far, the result is already good
+        else:
+          return isNone
+      elif lengthOrd(fRange) != lengthOrd(a):
+        result = isNone
+    else: discard
+  of tyOpenArray, tyVarargs:
+    # varargs[expr] is special
+    if f.kind == tyVarargs and f.sons[0].kind == tyExpr: return
+    case a.kind
+    of tyOpenArray, tyVarargs:
+      result = typeRel(c, base(f), base(a))
+      if result < isGeneric: result = isNone
+    of tyArrayConstr:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
+        result = isSubtype    # [] is allowed here
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
+        result = isSubtype
+    of tyArray:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[1].kind == tyEmpty):
+        result = isSubtype
+      elif typeRel(c, base(f), a.sons[1]) >= isGeneric:
+        result = isConvertible
+    of tySequence:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
+        result = isConvertible
+      elif typeRel(c, base(f), a.sons[0]) >= isGeneric:
+        result = isConvertible
+    else: discard
+  of tySequence:
+    case a.kind
+    of tySequence:
+      if (f.sons[0].kind != tyGenericParam) and (a.sons[0].kind == tyEmpty):
+        result = isSubtype
+      else:
+        result = typeRel(c, f.sons[0], a.sons[0])
+        if result < isGeneric: result = isNone
+        elif tfNotNil in f.flags and tfNotNil notin a.flags:
+          result = isNilConversion
+    of tyNil: result = f.allowsNil
+    else: discard
+  of tyOrdinal:
+    if isOrdinalType(a):
+      var x = if a.kind == tyOrdinal: a.sons[0] else: a
+      if f.sons[0].kind == tyNone:
+        result = isGeneric
+      else:
+        result = typeRel(c, f.sons[0], x)
+        if result < isGeneric: result = isNone
+    elif a.kind == tyGenericParam:
+      result = isGeneric
+  of tyForward: internalError("forward type in typeRel()")
+  of tyNil:
+    if a.kind == f.kind: result = isEqual
+  of tyTuple:
+    if a.kind == tyTuple: result = recordRel(c, f, a)
+  of tyObject:
+    if a.kind == tyObject:
+      if sameObjectTypes(f, a):
+        result = isEqual
+        # elif tfHasMeta in f.flags: result = recordRel(c, f, a)
+      else:
+        var depth = isObjectSubtype(a, f)
+        if depth > 0:
+          inc(c.inheritancePenalty, depth)
+          result = isSubtype
+  of tyDistinct:
+    if a.kind == tyDistinct and sameDistinctTypes(f, a): result = isEqual
+    elif c.coerceDistincts: result = typeRel(c, f.base, a)
+  of tySet:
+    if a.kind == tySet:
+      if f.sons[0].kind != tyGenericParam and a.sons[0].kind == tyEmpty:
+        result = isSubtype
+      else:
+        result = typeRel(c, f.sons[0], a.sons[0])
+        if result <= isConvertible:
+          result = isNone     # BUGFIX!
+  of tyPtr, tyRef:
+    if a.kind == f.kind:
+      # ptr[R, T] can be passed to ptr[T], but not the other way round:
+      if a.len < f.len: return isNone
+      for i in 0..f.len-2:
+        if typeRel(c, f.sons[i], a.sons[i]) == isNone: return isNone
+      result = typeRel(c, f.lastSon, a.lastSon)
+      if result <= isConvertible: result = isNone
+      elif tfNotNil in f.flags and tfNotNil notin a.flags:
+        result = isNilConversion
+    elif a.kind == tyNil: result = f.allowsNil
+    else: discard
+  of tyProc:
+    result = procTypeRel(c, f, a)
+    if result != isNone and tfNotNil in f.flags and tfNotNil notin a.flags:
+      result = isNilConversion
+  of tyPointer:
+    case a.kind
+    of tyPointer:
+      if tfNotNil in f.flags and tfNotNil notin a.flags:
+        result = isNilConversion
+      else:
+        result = isEqual
+    of tyNil: result = f.allowsNil
+    of tyProc:
+      if a.callConv != ccClosure: result = isConvertible
+    of tyPtr:
+      # 'pointer' is NOT compatible to regionized pointers
+      # so 'dealloc(regionPtr)' fails:
+      if a.len == 1: result = isConvertible
+    of tyCString: result = isConvertible
+    else: discard
+  of tyString:
+    case a.kind
+    of tyString:
+      if tfNotNil in f.flags and tfNotNil notin a.flags:
+        result = isNilConversion
+      else:
+        result = isEqual
+    of tyNil: result = f.allowsNil
+    else: discard
+  of tyCString:
+    # conversion from string to cstring is automatic:
+    case a.kind
+    of tyCString:
+      if tfNotNil in f.flags and tfNotNil notin a.flags:
+        result = isNilConversion
+      else:
+        result = isEqual
+    of tyNil: result = f.allowsNil
+    of tyString: result = isConvertible
+    of tyPtr:
+      # ptr[Tag, char] is not convertible to 'cstring' for now:
+      if a.len == 1 and a.sons[0].kind == tyChar: result = isConvertible
+    of tyArray:
+      if (firstOrd(a.sons[0]) == 0) and
+          (skipTypes(a.sons[0], {tyRange}).kind in {tyInt..tyInt64}) and
+          (a.sons[1].kind == tyChar):
+        result = isConvertible
+    else: discard
+
+  of tyEmpty:
+    if a.kind == tyEmpty: result = isEqual
+
+  of tyGenericInst:
+    let roota = a.skipGenericAlias
+    let rootf = f.skipGenericAlias
+    if a.kind == tyGenericInst and roota.base == rootf.base:
+      for i in 1 .. rootf.sonsLen-2:
+        let ff = rootf.sons[i]
+        let aa = roota.sons[i]
+        result = typeRel(c, ff, aa)
+        if result == isNone: return
+        if ff.kind == tyRange and result != isEqual: return isNone
+      #result = isGeneric
+      # XXX See bug #2220. A[int] should match A[int] better than some generic X
+    else:
+      result = typeRel(c, lastSon(f), a)
+
+  of tyGenericBody:
+    considerPreviousT:
+      if a.kind == tyGenericInst and a.sons[0] == f:
+        bindingRet isGeneric
+      let ff = lastSon(f)
+      if ff != nil: result = typeRel(c, ff, a)
+
+  of tyGenericInvocation:
+    var x = a.skipGenericAlias
+    if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
+      #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
+      # simply no match for now:
+      discard
+    elif x.kind == tyGenericInst and
+          (f.sons[0] == x.sons[0]) and
+          (sonsLen(x) - 1 == sonsLen(f)):
+      for i in countup(1, sonsLen(f) - 1):
+        if x.sons[i].kind == tyGenericParam:
+          internalError("wrong instantiated type!")
+        elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype: return
+      result = isGeneric
+    else:
+      let genericBody = f.sons[0]
+      result = typeRel(c, genericBody, x)
+      if result != isNone:
+        # see tests/generics/tgeneric3.nim for an example that triggers this
+        # piece of code:
+        #
+        # proc internalFind[T,D](n: PNode[T,D], key: T): ref TItem[T,D]
+        # proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D,
+        #                       Oldvalue: var D): ref TNode[T,D]
+        # var root = internalPut[int, int](nil, 312, 312, oldvalue)
+        # var it1 = internalFind(root, 312) # cannot instantiate: 'D'
+        #
+        # we steal the generic parameters from the tyGenericBody:
+        for i in countup(1, sonsLen(f) - 1):
+          var x = PType(idTableGet(c.bindings, genericBody.sons[i-1]))
+          if x == nil:
+            discard "maybe fine (for eg. a==tyNil)"
+          elif x.kind in {tyGenericInvocation, tyGenericParam}:
+            internalError("wrong instantiated type!")
+          else:
+            put(c.bindings, f.sons[i], x)
+
+  of tyAnd:
+    considerPreviousT:
+      result = isEqual
+      for branch in f.sons:
+        let x = typeRel(c, branch, aOrig)
+        if x < isSubtype: return isNone
+        # 'and' implies minimum matching result:
+        if x < result: result = x
+      bindingRet result
+
+  of tyOr:
+    considerPreviousT:
+      result = isNone
+      for branch in f.sons:
+        let x = typeRel(c, branch, aOrig)
+        # 'or' implies maximum matching result:
+        if x > result: result = x
+      if result >= isSubtype:
+        bindingRet result
+      else:
+        result = isNone
+
+  of tyNot:
+    considerPreviousT:
+      for branch in f.sons:
+        if typeRel(c, branch, aOrig) != isNone:
+          return isNone
+
+      bindingRet isGeneric
+
+  of tyAnything:
+    considerPreviousT:
+      var concrete = concreteType(c, a)
+      if concrete != nil and doBind:
+        put(c.bindings, f, concrete)
+      return isGeneric
+
+  of tyBuiltInTypeClass:
+    considerPreviousT:
+      let targetKind = f.sons[0].kind
+      if targetKind == a.skipTypes({tyRange, tyGenericInst}).kind or
+         (targetKind in {tyProc, tyPointer} and a.kind == tyNil):
+        put(c.bindings, f, a)
+        return isGeneric
+      else:
+        return isNone
+
+  of tyUserTypeClass, tyUserTypeClassInst:
+    considerPreviousT:
+      result = matchUserTypeClass(c.c, c, f, aOrig)
+      if result == isGeneric:
+        put(c.bindings, f, a)
+
+  of tyCompositeTypeClass:
+    considerPreviousT:
+      if typeRel(c, f.sons[1], a) != isNone:
+        put(c.bindings, f, a)
+        return isGeneric
+      else:
+        return isNone
+
+  of tyGenericParam:
+    var x = PType(idTableGet(c.bindings, f))
+    if x == nil:
+      if c.callee.kind == tyGenericBody and
+         f.kind == tyGenericParam and not c.typedescMatched:
+        # XXX: The fact that generic types currently use tyGenericParam for
+        # their parameters is really a misnomer. tyGenericParam means "match
+        # any value" and what we need is "match any type", which can be encoded
+        # by a tyTypeDesc params. Unfortunately, this requires more substantial
+        # changes in semtypinst and elsewhere.
+        if tfWildcard in a.flags:
+          result = isGeneric
+        elif a.kind == tyTypeDesc:
+          if f.sonsLen == 0:
+            result = isGeneric
+          else:
+            internalAssert a.sons != nil and a.sons.len > 0
+            c.typedescMatched = true
+            var aa = a
+            while aa.kind in {tyTypeDesc, tyGenericParam} and
+                aa.len > 0:
+              aa = lastSon(aa)
+            result = typeRel(c, f.base, aa)
+            if result > isGeneric: result = isGeneric
+        else:
+          result = isNone
+      else:
+        if f.sonsLen > 0 and f.sons[0].kind != tyNone:
+          result = typeRel(c, f.lastSon, a)
+          if doBind and result notin {isNone, isGeneric}:
+            let concrete = concreteType(c, a)
+            if concrete == nil: return isNone
+            put(c.bindings, f, concrete)
+        else:
+          result = isGeneric
+
+      if result == isGeneric:
+        var concrete = a
+        if tfWildcard in a.flags:
+          a.sym.kind = skType
+          a.flags.excl tfWildcard
+        else:
+          concrete = concreteType(c, a)
+          if concrete == nil:
+            return isNone
+        if doBind:
+          put(c.bindings, f, concrete)
+      elif result > isGeneric:
+        result = isGeneric
+    elif a.kind == tyEmpty:
+      result = isGeneric
+    elif x.kind == tyGenericParam:
+      result = isGeneric
+    else:
+      result = typeRel(c, x, a) # check if it fits
+      if result > isGeneric: result = isGeneric
+
+  of tyStatic:
+    let prev = PType(idTableGet(c.bindings, f))
+    if prev == nil:
+      if aOrig.kind == tyStatic:
+        result = typeRel(c, f.lastSon, a)
+        if result != isNone and f.n != nil:
+          if not exprStructuralEquivalent(f.n, aOrig.n):
+            result = isNone
+        if result != isNone: put(c.bindings, f, aOrig)
+      else:
+        result = isNone
+    elif prev.kind == tyStatic:
+      if aOrig.kind == tyStatic:
+        result = typeRel(c, prev.lastSon, a)
+        if result != isNone and prev.n != nil:
+          if not exprStructuralEquivalent(prev.n, aOrig.n):
+            result = isNone
+      else: result = isNone
+    else:
+      # XXX endless recursion?
+      #result = typeRel(c, prev, aOrig)
+      result = isNone
+  of tyTypeDesc:
+    var prev = PType(idTableGet(c.bindings, f))
+    if prev == nil:
+      # proc foo(T: typedesc, x: T)
+      # when `f` is an unresolved typedesc, `a` could be any
+      # type, so we should not perform this check earlier
+      if a.kind != tyTypeDesc: return isNone
+
+      if f.base.kind == tyNone:
+        result = isGeneric
+      else:
+        result = typeRel(c, f.base, a.base)
+
+      if result != isNone:
+        put(c.bindings, f, a)
+    else:
+      if tfUnresolved in f.flags:
+        result = typeRel(c, prev.base, a)
+      elif a.kind == tyTypeDesc:
+        result = typeRel(c, prev.base, a.base)
+      else:
+        result = isNone
+
+  of tyIter:
+    if a.kind == tyIter or
+      (a.kind == tyProc and tfIterator in a.flags):
+      result = typeRel(c, f.base, a.base)
+    else:
+      result = isNone
+
+  of tyStmt:
+    result = isGeneric
+
+  of tyProxy:
+    result = isEqual
+
+  of tyFromExpr:
+    # fix the expression, so it contains the already instantiated types
+    if f.n == nil or f.n.kind == nkEmpty: return isGeneric
+    let reevaluated = tryResolvingStaticExpr(c, f.n)
+    case reevaluated.typ.kind
+    of tyTypeDesc:
+      result = typeRel(c, a, reevaluated.typ.base)
+    of tyStatic:
+      result = typeRel(c, a, reevaluated.typ.base)
+      if result != isNone and reevaluated.typ.n != nil:
+        if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
+          result = isNone
+    else:
+      localError(f.n.info, errTypeExpected)
+      result = isNone
+
+  of tyNone:
+    if a.kind == tyNone: result = isEqual
+  else:
+    internalError " unknown type kind " & $f.kind
+
+proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
+  var m: TCandidate
+  initCandidate(c, m, f)
+  result = typeRel(m, f, a)
+
+proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
+                         f: PType): PType =
+  result = PType(idTableGet(m.bindings, f))
+  if result == nil:
+    result = generateTypeInstance(c, m.bindings, arg, f)
+  if result == nil:
+    internalError(arg.info, "getInstantiatedType")
+    result = errorType(c)
+
+proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
+                  c: PContext): PNode =
+  result = newNodeI(kind, arg.info)
+  if containsGenericType(f):
+    if not m.hasFauxMatch:
+      result.typ = getInstantiatedType(c, arg, m, f)
+    else:
+      result.typ = errorType(c)
+  else:
+    result.typ = f
+  if result.typ == nil: internalError(arg.info, "implicitConv")
+  addSon(result, ast.emptyNode)
+  addSon(result, arg)
+
+proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                   arg: PNode): PNode =
+  result = nil
+  for i in countup(0, len(c.converters) - 1):
+    var src = c.converters[i].typ.sons[1]
+    var dest = c.converters[i].typ.sons[0]
+    # for generic type converters we need to check 'src <- a' before
+    # 'f <- dest' in order to not break the unification:
+    # see tests/tgenericconverter:
+    let srca = typeRel(m, src, a)
+    if srca notin {isEqual, isGeneric}: continue
+
+    let destIsGeneric = containsGenericType(dest)
+    if destIsGeneric:
+      dest = generateTypeInstance(c, m.bindings, arg, dest)
+    let fdest = typeRel(m, f, dest)
+    if fdest in {isEqual, isGeneric}:
+      markUsed(arg.info, c.converters[i])
+      var s = newSymNode(c.converters[i])
+      s.typ = c.converters[i].typ
+      s.info = arg.info
+      result = newNodeIT(nkHiddenCallConv, arg.info, dest)
+      addSon(result, s)
+      addSon(result, copyTree(arg))
+      inc(m.convMatches)
+      m.genericConverter = srca == isGeneric or destIsGeneric
+      return result
+
+proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
+                    arg: PNode): PNode =
+  # arg.typ can be nil in 'suggest':
+  if isNil(arg.typ): return nil
+
+  # sem'checking for 'echo' needs to be re-entrant:
+  # XXX we will revisit this issue after 0.10.2 is released
+  if f == arg.typ and arg.kind == nkHiddenStdConv: return arg
+
+  var call = newNodeI(nkCall, arg.info)
+  call.add(f.n.copyTree)
+  call.add(arg.copyTree)
+  result = c.semOverloadedCall(c, call, call, routineKinds)
+  if result != nil:
+    # resulting type must be consistent with the other arguments:
+    var r = typeRel(m, f.sons[0], result.typ)
+    if r < isGeneric: return nil
+    if result.kind == nkCall: result.kind = nkHiddenCallConv
+    inc(m.convMatches)
+    if r == isGeneric:
+      result.typ = getInstantiatedType(c, arg, m, base(f))
+    m.baseTypeMatch = true
+
+proc isInlineIterator*(t: PType): bool =
+  result = t.kind == tyIter or
+          (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
+
+proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
+  case r
+  of isConvertible, isIntConv: inc(m.convMatches, convMatch)
+  of isSubtype, isSubrange: inc(m.subtypeMatches)
+  of isGeneric, isInferred: inc(m.genericMatches)
+  of isFromIntLit: inc(m.intConvMatches, 256)
+  of isInferredConvertible:
+    inc(m.convMatches)
+  of isEqual: inc(m.exactMatches)
+  of isNone: discard
+
+proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
+                        argSemantized, argOrig: PNode): PNode =
+  var
+    fMaybeStatic = f.skipTypes({tyDistinct})
+    arg = argSemantized
+    argType = argType
+    c = m.c
+
+  if tfHasStatic in fMaybeStatic.flags:
+    # XXX: When implicit statics are the default
+    # this will be done earlier - we just have to
+    # make sure that static types enter here
+
+    # XXX: weaken tyGenericParam and call it tyGenericPlaceholder
+    # and finally start using tyTypedesc for generic types properly.
+    if argType.kind == tyGenericParam and tfWildcard in argType.flags:
+      argType.assignType(f)
+      # put(m.bindings, f, argType)
+      return argSemantized
+
+    if argType.kind == tyStatic:
+      if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags:
+        result = newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
+        return
+    else:
+      var evaluated = c.semTryConstExpr(c, arg)
+      if evaluated != nil:
+        arg.typ = newTypeS(tyStatic, c)
+        arg.typ.sons = @[evaluated.typ]
+        arg.typ.n = evaluated
+        argType = arg.typ
+
+  var
+    a = if c.inTypeClass > 0: argType.skipTypes({tyTypeDesc, tyFieldAccessor})
+        else: argType
+
+    r = typeRel(m, f, a)
+
+  if r != isNone and m.calleeSym != nil and
+     m.calleeSym.kind in {skMacro, skTemplate}:
+    # XXX: duplicating this is ugly, but we cannot (!) move this
+    # directly into typeRel using return-like templates
+    incMatches(m, r)
+    if f.kind == tyStmt:
+      return arg
+    elif f.kind == tyTypeDesc:
+      return arg
+    elif f.kind == tyStatic:
+      return arg.typ.n
+    else:
+      return argSemantized # argOrig
+
+  if r != isNone and f.isInlineIterator:
+    var inlined = newTypeS(tyStatic, c)
+    inlined.sons = @[argType]
+    inlined.n = argSemantized
+    put(m.bindings, f, inlined)
+    return argSemantized
+
+  case r
+  of isConvertible:
+    inc(m.convMatches)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isIntConv:
+    # I'm too lazy to introduce another ``*matches`` field, so we conflate
+    # ``isIntConv`` and ``isIntLit`` here:
+    inc(m.intConvMatches)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isSubtype:
+    inc(m.subtypeMatches)
+    if f.kind == tyTypeDesc:
+      result = arg
+    else:
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
+  of isSubrange:
+    inc(m.subtypeMatches)
+    if f.kind == tyVar:
+      result = arg
+    else:
+      result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isInferred, isInferredConvertible:
+    if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
+      result = c.semInferredLambda(c, m.bindings, arg)
+    else:
+      let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
+      result = newSymNode(inferred, arg.info)
+    if r == isInferredConvertible:
+      inc(m.convMatches)
+      result = implicitConv(nkHiddenStdConv, f, result, m, c)
+    else:
+      inc(m.genericMatches)
+  of isGeneric:
+    inc(m.genericMatches)
+    if arg.typ == nil:
+      result = arg
+    elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
+    elif arg.typ.isEmptyContainer:
+      result = arg.copyTree
+      result.typ = getInstantiatedType(c, arg, m, f)
+    else:
+      result = arg
+  of isFromIntLit:
+    # too lazy to introduce another ``*matches`` field, so we conflate
+    # ``isIntConv`` and ``isIntLit`` here:
+    inc(m.intConvMatches, 256)
+    result = implicitConv(nkHiddenStdConv, f, arg, m, c)
+  of isEqual:
+    inc(m.exactMatches)
+    result = arg
+    if skipTypes(f, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
+      result = implicitConv(nkHiddenSubConv, f, arg, m, c)
+  of isNone:
+    # do not do this in ``typeRel`` as it then can't infere T in ``ref T``:
+    if a.kind in {tyProxy, tyUnknown}:
+      inc(m.genericMatches)
+      m.fauxMatch = a.kind
+      return arg
+    result = userConvMatch(c, m, f, a, arg)
+    # check for a base type match, which supports varargs[T] without []
+    # constructor in a call:
+    if result == nil and f.kind == tyVarargs:
+      if f.n != nil:
+        result = localConvMatch(c, m, f, a, arg)
+      else:
+        r = typeRel(m, base(f), a)
+        if r >= isGeneric:
+          inc(m.convMatches)
+          result = copyTree(arg)
+          if r == isGeneric:
+            result.typ = getInstantiatedType(c, arg, m, base(f))
+          m.baseTypeMatch = true
+        else:
+          result = userConvMatch(c, m, base(f), a, arg)
+
+proc paramTypesMatch*(m: var TCandidate, f, a: PType,
+                      arg, argOrig: PNode): PNode =
+  if arg == nil or arg.kind notin nkSymChoices:
+    result = paramTypesMatchAux(m, f, a, arg, argOrig)
+  else:
+    # CAUTION: The order depends on the used hashing scheme. Thus it is
+    # incorrect to simply use the first fitting match. However, to implement
+    # this correctly is inefficient. We have to copy `m` here to be able to
+    # roll back the side effects of the unification algorithm.
+    let c = m.c
+    var x, y, z: TCandidate
+    initCandidate(c, x, m.callee)
+    initCandidate(c, y, m.callee)
+    initCandidate(c, z, m.callee)
+    x.calleeSym = m.calleeSym
+    y.calleeSym = m.calleeSym
+    z.calleeSym = m.calleeSym
+    var best = -1
+    for i in countup(0, sonsLen(arg) - 1):
+      if arg.sons[i].sym.kind in {skProc, skMethod, skConverter}+skIterators:
+        copyCandidate(z, m)
+        z.callee = arg.sons[i].typ
+        z.calleeSym = arg.sons[i].sym
+        #if arg.sons[i].sym.name.s == "cmp":
+        #  ggDebug = true
+        #  echo "CALLLEEEEEEEE A ", typeToString(z.callee)
+        # XXX this is still all wrong: (T, T) should be 2 generic matches
+        # and  (int, int) 2 exact matches, etc. Essentially you cannot call
+        # typeRel here and expect things to work!
+        let r = typeRel(z, f, arg.sons[i].typ)
+        incMatches(z, r, 2)
+        #if arg.sons[i].sym.name.s == "cmp": # and arg.info.line == 606:
+        #  echo "M ", r, " ", arg.info, " ", typeToString(arg.sons[i].sym.typ)
+        #  writeMatches(z)
+        if r != isNone:
+          z.state = csMatch
+          case x.state
+          of csEmpty, csNoMatch:
+            x = z
+            best = i
+          of csMatch:
+            let cmp = cmpCandidates(x, z)
+            if cmp < 0:
+              best = i
+              x = z
+            elif cmp == 0:
+              y = z           # z is as good as x
+    if x.state == csEmpty:
+      result = nil
+    elif y.state == csMatch and cmpCandidates(x, y) == 0:
+      if x.state != csMatch:
+        internalError(arg.info, "x.state is not csMatch")
+      # ambiguous: more than one symbol fits!
+      # See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
+      # anyway:
+      if f.kind == tyExpr: result = arg
+      else: result = nil
+    else:
+      # only one valid interpretation found:
+      markUsed(arg.info, arg.sons[best].sym)
+      styleCheckUse(arg.info, arg.sons[best].sym)
+      result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
+                                  argOrig)
+
+
+proc setSon(father: PNode, at: int, son: PNode) =
+  if sonsLen(father) <= at: setLen(father.sons, at + 1)
+  father.sons[at] = son
+
+# we are allowed to modify the calling node in the 'prepare*' procs:
+proc prepareOperand(c: PContext; formal: PType; a: PNode): PNode =
+  if formal.kind == tyExpr and formal.len != 1:
+    # {tyTypeDesc, tyExpr, tyStmt, tyProxy}:
+    # a.typ == nil is valid
+    result = a
+  elif a.typ.isNil:
+    # XXX This is unsound! 'formal' can differ from overloaded routine to
+    # overloaded routine!
+    let flags = if formal.kind == tyIter: {efDetermineType, efWantIterator}
+                else: {efDetermineType, efAllowStmt}
+                #elif formal.kind == tyStmt: {efDetermineType, efWantStmt}
+                #else: {efDetermineType}
+    result = c.semOperand(c, a, flags)
+  else:
+    result = a
+
+proc prepareOperand(c: PContext; a: PNode): PNode =
+  if a.typ.isNil:
+    result = c.semOperand(c, a, {efDetermineType})
+  else:
+    result = a
+
+proc prepareNamedParam(a: PNode) =
+  if a.sons[0].kind != nkIdent:
+    var info = a.sons[0].info
+    a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
+
+proc arrayConstr(c: PContext, n: PNode): PType =
+  result = newTypeS(tyArrayConstr, c)
+  rawAddSon(result, makeRangeType(c, 0, 0, n.info))
+  addSonSkipIntLit(result, skipTypes(n.typ, {tyGenericInst, tyVar, tyOrdinal}))
+
+proc arrayConstr(c: PContext, info: TLineInfo): PType =
+  result = newTypeS(tyArrayConstr, c)
+  rawAddSon(result, makeRangeType(c, 0, -1, info))
+  rawAddSon(result, newTypeS(tyEmpty, c)) # needs an empty basetype!
+
+proc incrIndexType(t: PType) =
+  assert t.kind == tyArrayConstr
+  inc t.sons[0].n.sons[1].intVal
+
+proc matchesAux(c: PContext, n, nOrig: PNode,
+                m: var TCandidate, marker: var IntSet) =
+  template checkConstraint(n: expr) {.immediate, dirty.} =
+    if not formal.constraint.isNil:
+      if matchNodeKinds(formal.constraint, n):
+        # better match over other routines with no such restriction:
+        inc(m.genericMatches, 100)
+      else:
+        m.state = csNoMatch
+        return
+    if formal.typ.kind == tyVar:
+      if not n.isLValue:
+        m.state = csNoMatch
+        return
+
+  var
+    # iterates over formal parameters
+    f = if m.callee.kind != tyGenericBody: 1
+        else: 0
+    # iterates over the actual given arguments
+    a = 1
+
+  m.state = csMatch # until proven otherwise
+  m.call = newNodeI(n.kind, n.info)
+  m.call.typ = base(m.callee) # may be nil
+  var formalLen = m.callee.n.len
+  addSon(m.call, copyTree(n.sons[0]))
+  var container: PNode = nil # constructed container
+  var formal: PSym = nil
+
+  while a < n.len:
+    if n.sons[a].kind == nkExprEqExpr:
+      # named param
+      # check if m.callee has such a param:
+      prepareNamedParam(n.sons[a])
+      if n.sons[a].sons[0].kind != nkIdent:
+        localError(n.sons[a].info, errNamedParamHasToBeIdent)
+        m.state = csNoMatch
+        return
+      formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
+      if formal == nil:
+        # no error message!
+        m.state = csNoMatch
+        return
+      if containsOrIncl(marker, formal.position):
+        # already in namedParams:
+        localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
+        m.state = csNoMatch
+        return
+      m.baseTypeMatch = false
+      n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
+      n.sons[a].typ = n.sons[a].sons[1].typ
+      var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
+                                n.sons[a].sons[1], nOrig.sons[a].sons[1])
+      if arg == nil:
+        m.state = csNoMatch
+        return
+      checkConstraint(n.sons[a].sons[1])
+      if m.baseTypeMatch:
+        #assert(container == nil)
+        container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
+        addSon(container, arg)
+        setSon(m.call, formal.position + 1, container)
+        if f != formalLen - 1: container = nil
+      else:
+        setSon(m.call, formal.position + 1, arg)
+      inc f
+    else:
+      # unnamed param
+      if f >= formalLen:
+        # too many arguments?
+        if tfVarargs in m.callee.flags:
+          # is ok... but don't increment any counters...
+          # we have no formal here to snoop at:
+          n.sons[a] = prepareOperand(c, n.sons[a])
+          if skipTypes(n.sons[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
+            addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
+                                        copyTree(n.sons[a]), m, c))
+          else:
+            addSon(m.call, copyTree(n.sons[a]))
+        elif formal != nil and formal.typ.kind == tyVarargs:
+          # beware of the side-effects in 'prepareOperand'! So only do it for
+          # varags matching. See tests/metatype/tstatic_overloading.
+          m.baseTypeMatch = false
+          n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
+          var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
+                                    n.sons[a], nOrig.sons[a])
+          if arg != nil and m.baseTypeMatch and container != nil:
+            addSon(container, arg)
+            incrIndexType(container.typ)
+          else:
+            m.state = csNoMatch
+            return
+        else:
+          m.state = csNoMatch
+          return
+      else:
+        if m.callee.n.sons[f].kind != nkSym:
+          internalError(n.sons[a].info, "matches")
+          return
+        formal = m.callee.n.sons[f].sym
+        if containsOrIncl(marker, formal.position) and container.isNil:
+          # already in namedParams:
+          localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
+          m.state = csNoMatch
+          return
+        m.baseTypeMatch = false
+        n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
+        var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
+                                  n.sons[a], nOrig.sons[a])
+        if arg == nil:
+          m.state = csNoMatch
+          return
+        if m.baseTypeMatch:
+          #assert(container == nil)
+          if container.isNil:
+            container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
+          else:
+            incrIndexType(container.typ)
+          addSon(container, arg)
+          setSon(m.call, formal.position + 1,
+                 implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
+          #if f != formalLen - 1: container = nil
+
+          # pick the formal from the end, so that 'x, y, varargs, z' works:
+          f = max(f, formalLen - n.len + a + 1)
+        else:
+          setSon(m.call, formal.position + 1, arg)
+          inc(f)
+          container = nil
+      checkConstraint(n.sons[a])
+    inc(a)
+
+proc semFinishOperands*(c: PContext, n: PNode) =
+  # this needs to be called to ensure that after overloading resolution every
+  # argument has been sem'checked:
+  for i in 1 .. <n.len:
+    n.sons[i] = prepareOperand(c, n.sons[i])
+
+proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
+  # for 'suggest' support:
+  var marker = initIntSet()
+  matchesAux(c, n, nOrig, m, marker)
+
+proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
+  var marker = initIntSet()
+  matchesAux(c, n, nOrig, m, marker)
+  if m.state == csNoMatch: return
+  # check that every formal parameter got a value:
+  var f = 1
+  while f < sonsLen(m.callee.n):
+    var formal = m.callee.n.sons[f].sym
+    if not containsOrIncl(marker, formal.position):
+      if formal.ast == nil:
+        if formal.typ.kind == tyVarargs:
+          var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
+          addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
+                                      container, m, c))
+        else:
+          # no default value
+          m.state = csNoMatch
+          break
+      else:
+        # use default value:
+        setSon(m.call, formal.position + 1, copyTree(formal.ast))
+    inc(f)
+
+proc argtypeMatches*(c: PContext, f, a: PType): bool =
+  var m: TCandidate
+  initCandidate(c, m, f)
+  let res = paramTypesMatch(m, f, a, ast.emptyNode, nil)
+  #instantiateGenericConverters(c, res, m)
+  # XXX this is used by patterns.nim too; I think it's better to not
+  # instantiate generic converters for that
+  result = res != nil
+
+proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
+                      op: TTypeAttachedOp): PSym {.procvar.} =
+  var m: TCandidate
+  initCandidate(c, m, dc.typ)
+  var f = dc.typ.sons[1]
+  if op == attachedDeepCopy:
+    if f.kind in {tyRef, tyPtr}: f = f.lastSon
+  else:
+    if f.kind == tyVar: f = f.lastSon
+  if typeRel(m, f, t) == isNone:
+    localError(info, errGenerated, "cannot instantiate 'deepCopy'")
+  else:
+    result = c.semGenerateInstance(c, dc, m.bindings, info)
+    assert sfFromGeneric in result.flags
+
+include suggest
+
+when not declared(tests):
+  template tests(s: stmt) {.immediate.} = discard
+
+tests:
+  var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
+
+  proc `|` (t1, t2: PType): PType =
+    result = newType(tyOr, dummyOwner)
+    result.rawAddSon(t1)
+    result.rawAddSon(t2)
+
+  proc `&` (t1, t2: PType): PType =
+    result = newType(tyAnd, dummyOwner)
+    result.rawAddSon(t1)
+    result.rawAddSon(t2)
+
+  proc `!` (t: PType): PType =
+    result = newType(tyNot, dummyOwner)
+    result.rawAddSon(t)
+
+  proc seq(t: PType): PType =
+    result = newType(tySequence, dummyOwner)
+    result.rawAddSon(t)
+
+  proc array(x: int, t: PType): PType =
+    result = newType(tyArray, dummyOwner)
+
+    var n = newNodeI(nkRange, UnknownLineInfo())
+    addSon(n, newIntNode(nkIntLit, 0))
+    addSon(n, newIntNode(nkIntLit, x))
+    let range = newType(tyRange, dummyOwner)
+
+    result.rawAddSon(range)
+    result.rawAddSon(t)
+
+  suite "type classes":
+    let
+      int = newType(tyInt, dummyOwner)
+      float = newType(tyFloat, dummyOwner)
+      string = newType(tyString, dummyOwner)
+      ordinal = newType(tyOrdinal, dummyOwner)
+      any = newType(tyAnything, dummyOwner)
+      number = int | float
+
+    var TFoo = newType(tyObject, dummyOwner)
+    TFoo.sym = newSym(skType, getIdent"TFoo", dummyOwner, UnknownLineInfo())
+
+    var T1 = newType(tyGenericParam, dummyOwner)
+    T1.sym = newSym(skType, getIdent"T1", dummyOwner, UnknownLineInfo())
+    T1.sym.position = 0
+
+    var T2 = newType(tyGenericParam, dummyOwner)
+    T2.sym = newSym(skType, getIdent"T2", dummyOwner, UnknownLineInfo())
+    T2.sym.position = 1
+
+    setup:
+      var c: TCandidate
+      initCandidate(nil, c, nil)
+
+    template yes(x, y) =
+      test astToStr(x) & " is " & astToStr(y):
+        check typeRel(c, y, x) == isGeneric
+
+    template no(x, y) =
+      test astToStr(x) & " is not " & astToStr(y):
+        check typeRel(c, y, x) == isNone
+
+    yes seq(any), array(10, int) | seq(any)
+    # Sure, seq[any] is directly included
+
+    yes seq(int), seq(any)
+    yes seq(int), seq(number)
+    # Sure, the int sequence is certainly
+    # part of the number sequences (and all sequences)
+
+    no seq(any), seq(float)
+    # Nope, seq[any] includes types that are not seq[float] (e.g. seq[int])
+
+    yes seq(int|string), seq(any)
+    # Sure
+
+    yes seq(int&string), seq(any)
+    # Again
+
+    yes seq(int&string), seq(int)
+    # A bit more complicated
+    # seq[int&string] is not a real type, but it's analogous to
+    # seq[Sortable and Iterable], which is certainly a subset of seq[Sortable]
+
+    no seq(int|string), seq(int|float)
+    # Nope, seq[string] is not included in not included in
+    # the seq[int|float] set
+
+    no seq(!(int|string)), seq(string)
+    # A sequence that is neither seq[int] or seq[string]
+    # is obviously not seq[string]
+
+    no seq(!int), seq(number)
+    # Now your head should start to hurt a bit
+    # A sequence that is not seq[int] is not necessarily a number sequence
+    # it could well be seq[string] for example
+
+    yes seq(!(int|string)), seq(!string)
+    # all sequnece types besides seq[int] and seq[string]
+    # are subset of all sequence types that are not seq[string]
+
+    no seq(!(int|string)), seq(!(string|TFoo))
+    # Nope, seq[TFoo] is included in the first set, but not in the second
+
+    no seq(!string), seq(!number)
+    # Nope, seq[int] in included in the first set, but not in the second
+
+    yes seq(!number), seq(any)
+    yes seq(!int), seq(any)
+    no seq(any), seq(!any)
+    no seq(!int), seq(!any)
+
+    yes int, ordinal
+    no  string, ordinal
+
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
new file mode 100644
index 000000000..659f1fa16
--- /dev/null
+++ b/compiler/suggest.nim
@@ -0,0 +1,372 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This file implements features required for IDE support.
+
+# included from sigmatch.nim
+
+import algorithm, sequtils
+
+const
+  sep = '\t'
+
+type
+  Suggest* = object
+    section*: IdeCmd
+    qualifiedPath*: seq[string]
+    filePath*: string
+    line*: int                   # Starts at 1
+    column*: int                 # Starts at 0
+    doc*: string           # Not escaped (yet)
+    symkind*: TSymKind
+    forth*: string               # XXX TODO object on symkind
+
+var
+  suggestionResultHook*: proc (result: Suggest) {.closure.}
+
+#template sectionSuggest(): expr = "##begin\n" & getStackTrace() & "##end\n"
+
+template origModuleName(m: PSym): string = m.name.s
+
+proc symToSuggest(s: PSym, isLocal: bool, section: string, li: TLineInfo): Suggest = 
+  result.section = parseIdeCmd(section)
+  if optIdeTerse in gGlobalOptions:
+    result.symkind = s.kind
+    result.filePath = toFullPath(li)
+    result.line = toLinenumber(li)
+    result.column = toColumn(li)
+  else:
+    result.symkind = s.kind
+    result.qualifiedPath = @[]
+    if not isLocal and s.kind != skModule:
+      let ow = s.owner
+      if ow.kind != skModule and ow.owner != nil:
+        let ow2 = ow.owner
+        result.qualifiedPath.add(ow2.origModuleName)
+      result.qualifiedPath.add(ow.origModuleName)
+    result.qualifiedPath.add(s.name.s)
+
+    if s.typ != nil: 
+      result.forth = typeToString(s.typ)
+    else:
+      result.forth = ""
+    result.filePath = toFullPath(li)
+    result.line = toLinenumber(li)
+    result.column = toColumn(li)
+    when not defined(noDocgen):
+      result.doc = s.extractDocComment
+
+proc `$`(suggest: Suggest): string = 
+  result = $suggest.section
+  result.add(sep)
+  result.add($suggest.symkind)
+  result.add(sep)
+  result.add(suggest.qualifiedPath.join("."))
+  result.add(sep)
+  result.add(suggest.forth)
+  result.add(sep)
+  result.add(suggest.filePath)
+  result.add(sep)
+  result.add($suggest.line)
+  result.add(sep)
+  result.add($suggest.column)
+  result.add(sep)
+  when not defined(noDocgen):
+    result.add(suggest.doc.escape)
+
+proc symToSuggest(s: PSym, isLocal: bool, section: string): Suggest = 
+  result = symToSuggest(s, isLocal, section, s.info)
+
+proc suggestResult(s: Suggest) =
+  if not isNil(suggestionResultHook):
+    suggestionResultHook(s)
+  else:
+    suggestWriteln($(s))
+
+proc filterSym(s: PSym): bool {.inline.} =
+  result = s.kind != skModule
+
+proc filterSymNoOpr(s: PSym): bool {.inline.} =
+  result = s.kind != skModule and s.name.s[0] in lexer.SymChars and
+     not isKeyword(s.name)
+
+proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
+  let fmoduleId = getModule(f).id
+  result = sfExported in f.flags or fmoduleId == c.module.id
+  for module in c.friendModules:
+    if fmoduleId == module.id:
+      result = true
+      break
+
+proc suggestField(c: PContext, s: PSym, outputs: var int) = 
+  if filterSym(s) and fieldVisible(c, s):
+    suggestResult(symToSuggest(s, isLocal=true, $ideSug))
+    inc outputs
+
+template wholeSymTab(cond, section: expr) {.immediate.} =
+  var isLocal = true
+  for scope in walkScopes(c.currentScope):
+    if scope == c.topLevelScope: isLocal = false
+    var entries = sequtils.toSeq(items(scope.symbols))
+    sort(entries) do (a,b: PSym) -> int:
+      return cmp(a.name.s, b.name.s)
+    for item in entries:
+      let it {.inject.} = item
+      if cond:
+        suggestResult(symToSuggest(it, isLocal = isLocal, section))
+        inc outputs
+
+proc suggestSymList(c: PContext, list: PNode, outputs: var int) = 
+  for i in countup(0, sonsLen(list) - 1): 
+    if list.sons[i].kind == nkSym:
+      suggestField(c, list.sons[i].sym, outputs)
+    #else: InternalError(list.info, "getSymFromList")
+
+proc suggestObject(c: PContext, n: PNode, outputs: var int) = 
+  case n.kind
+  of nkRecList: 
+    for i in countup(0, sonsLen(n)-1): suggestObject(c, n.sons[i], outputs)
+  of nkRecCase: 
+    var L = sonsLen(n)
+    if L > 0:
+      suggestObject(c, n.sons[0], outputs)
+      for i in countup(1, L-1): suggestObject(c, lastSon(n.sons[i]), outputs)
+  of nkSym: suggestField(c, n.sym, outputs)
+  else: discard
+
+proc nameFits(c: PContext, s: PSym, n: PNode): bool = 
+  var op = n.sons[0]
+  if op.kind in {nkOpenSymChoice, nkClosedSymChoice}: op = op.sons[0]
+  var opr: PIdent
+  case op.kind
+  of nkSym: opr = op.sym.name
+  of nkIdent: opr = op.ident
+  else: return false
+  result = opr.id == s.name.id
+
+proc argsFit(c: PContext, candidate: PSym, n, nOrig: PNode): bool = 
+  case candidate.kind 
+  of OverloadableSyms:
+    var m: TCandidate
+    initCandidate(c, m, candidate, nil)
+    sigmatch.partialMatch(c, n, nOrig, m)
+    result = m.state != csNoMatch
+  else:
+    result = false
+
+proc suggestCall(c: PContext, n, nOrig: PNode, outputs: var int) = 
+  wholeSymTab(filterSym(it) and nameFits(c, it, n) and argsFit(c, it, n, nOrig),
+              $ideCon)
+
+proc typeFits(c: PContext, s: PSym, firstArg: PType): bool {.inline.} = 
+  if s.typ != nil and sonsLen(s.typ) > 1 and s.typ.sons[1] != nil:
+    # special rule: if system and some weird generic match via 'tyExpr'
+    # or 'tyGenericParam' we won't list it either to reduce the noise (nobody
+    # wants 'system.`-|` as suggestion
+    let m = s.getModule()
+    if m != nil and sfSystemModule in m.flags:
+      if s.kind == skType: return
+      var exp = s.typ.sons[1].skipTypes({tyGenericInst, tyVar})
+      if exp.kind == tyVarargs: exp = elemType(exp)
+      if exp.kind in {tyExpr, tyStmt, tyGenericParam, tyAnything}: return
+    result = sigmatch.argtypeMatches(c, s.typ.sons[1], firstArg)
+
+proc suggestOperations(c: PContext, n: PNode, typ: PType, outputs: var int) =
+  assert typ != nil
+  wholeSymTab(filterSymNoOpr(it) and typeFits(c, it, typ), $ideSug)
+
+proc suggestEverything(c: PContext, n: PNode, outputs: var int) =
+  # do not produce too many symbols:
+  var isLocal = true
+  for scope in walkScopes(c.currentScope):
+    if scope == c.topLevelScope: isLocal = false
+    for it in items(scope.symbols):
+      if filterSym(it):
+        suggestResult(symToSuggest(it, isLocal = isLocal, $ideSug))
+        inc outputs
+    if scope == c.topLevelScope: break
+
+proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
+  # special code that deals with ``myObj.``. `n` is NOT the nkDotExpr-node, but
+  # ``myObj``.
+  var typ = n.typ
+  if typ == nil:
+    # a module symbol has no type for example:
+    if n.kind == nkSym and n.sym.kind == skModule: 
+      if n.sym == c.module: 
+        # all symbols accessible, because we are in the current module:
+        for it in items(c.topLevelScope.symbols):
+          if filterSym(it): 
+            suggestResult(symToSuggest(it, isLocal=false, $ideSug))
+            inc outputs
+      else: 
+        for it in items(n.sym.tab): 
+          if filterSym(it): 
+            suggestResult(symToSuggest(it, isLocal=false, $ideSug))
+            inc outputs
+    else:
+      # fallback:
+      suggestEverything(c, n, outputs)
+  elif typ.kind == tyEnum and n.kind == nkSym and n.sym.kind == skType: 
+    # look up if the identifier belongs to the enum:
+    var t = typ
+    while t != nil: 
+      suggestSymList(c, t.n, outputs)
+      t = t.sons[0]
+    suggestOperations(c, n, typ, outputs)
+  else:
+    typ = skipTypes(typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+    if typ.kind == tyObject: 
+      var t = typ
+      while true: 
+        suggestObject(c, t.n, outputs)
+        if t.sons[0] == nil: break 
+        t = skipTypes(t.sons[0], {tyGenericInst})
+      suggestOperations(c, n, typ, outputs)
+    elif typ.kind == tyTuple and typ.n != nil: 
+      suggestSymList(c, typ.n, outputs)
+      suggestOperations(c, n, typ, outputs)
+    else:
+      suggestOperations(c, n, typ, outputs)
+
+type
+  TCheckPointResult = enum 
+    cpNone, cpFuzzy, cpExact
+
+proc inCheckpoint(current: TLineInfo): TCheckPointResult = 
+  if current.fileIndex == gTrackPos.fileIndex:
+    if current.line == gTrackPos.line and
+        abs(current.col-gTrackPos.col) < 4:
+      return cpExact
+    if current.line >= gTrackPos.line:
+      return cpFuzzy
+
+proc findClosestDot(n: PNode): PNode =
+  if n.kind == nkDotExpr and inCheckpoint(n.info) == cpExact:
+    result = n
+  else:
+    for i in 0.. <safeLen(n):
+      result = findClosestDot(n.sons[i])
+      if result != nil: return
+
+proc findClosestCall(n: PNode): PNode = 
+  if n.kind in nkCallKinds and inCheckpoint(n.info) == cpExact: 
+    result = n
+  else:
+    for i in 0.. <safeLen(n):
+      result = findClosestCall(n.sons[i])
+      if result != nil: return
+
+proc isTracked(current: TLineInfo, tokenLen: int): bool =
+  if current.fileIndex == gTrackPos.fileIndex:
+    if current.line == gTrackPos.line:
+      let col = gTrackPos.col
+      if col >= current.col and col <= current.col+tokenLen-1:
+        return true
+
+proc findClosestSym(n: PNode): PNode = 
+  if n.kind == nkSym and inCheckpoint(n.info) == cpExact: 
+    result = n
+  elif n.kind notin {nkNone..nkNilLit}:
+    for i in 0.. <sonsLen(n):
+      result = findClosestSym(n.sons[i])
+      if result != nil: return
+
+var
+  usageSym*: PSym
+  lastLineInfo: TLineInfo
+
+proc findUsages(info: TLineInfo; s: PSym) =
+  if usageSym == nil and isTracked(info, s.name.s.len):
+    usageSym = s
+    suggestResult(symToSuggest(s, isLocal=false, $ideUse))
+  elif s == usageSym:
+    if lastLineInfo != info:
+      suggestResult(symToSuggest(s, isLocal=false, $ideUse, info))
+    lastLineInfo = info
+
+proc findDefinition(info: TLineInfo; s: PSym) =
+  if s.isNil: return
+  if isTracked(info, s.name.s.len):
+    suggestResult(symToSuggest(s, isLocal=false, $ideDef))
+    suggestQuit()
+
+proc ensureIdx[T](x: var T, y: int) =
+  if x.len <= y: x.setLen(y+1)
+
+proc ensureSeq[T](x: var seq[T]) =
+  if x == nil: newSeq(x, 0)
+
+proc suggestSym*(info: TLineInfo; s: PSym) {.inline.} =
+  ## misnamed: should be 'symDeclared'
+  if gIdeCmd == ideUse:
+    findUsages(info, s)
+  elif gIdeCmd == ideDef:
+    findDefinition(info, s)
+
+proc markUsed(info: TLineInfo; s: PSym) =
+  incl(s.flags, sfUsed)
+  if {sfDeprecated, sfError} * s.flags != {}:
+    if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
+    if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
+  suggestSym(info, s)
+
+proc useSym*(sym: PSym): PNode =
+  result = newSymNode(sym)
+  markUsed(result.info, sym)
+
+proc safeSemExpr*(c: PContext, n: PNode): PNode =
+  # use only for idetools support!
+  try:
+    result = c.semExpr(c, n)
+  except ERecoverableError:
+    result = ast.emptyNode
+
+proc suggestExpr*(c: PContext, node: PNode) = 
+  if nfIsCursor notin node.flags:
+    if gTrackPos.line < 0: return
+    var cp = inCheckpoint(node.info)
+    if cp == cpNone: return
+  var outputs = 0
+  # This keeps semExpr() from coming here recursively:
+  if c.inCompilesContext > 0: return
+  inc(c.inCompilesContext)
+
+  if gIdeCmd == ideSug:
+    var n = if nfIsCursor in node.flags: node else: findClosestDot(node)
+    if n == nil: n = node
+    if n.kind == nkDotExpr:
+      var obj = safeSemExpr(c, n.sons[0])
+      suggestFieldAccess(c, obj, outputs)
+      if optIdeDebug in gGlobalOptions:
+        echo "expression ", renderTree(obj), " has type ", typeToString(obj.typ)
+      #writeStackTrace()
+    else:
+      suggestEverything(c, n, outputs)
+  
+  elif gIdeCmd == ideCon:
+    var n = if nfIsCursor in node.flags: node else: findClosestCall(node)
+    if n == nil: n = node
+    if n.kind in nkCallKinds:
+      var a = copyNode(n)
+      var x = safeSemExpr(c, n.sons[0])
+      if x.kind == nkEmpty or x.typ == nil: x = n.sons[0]
+      addSon(a, x)
+      for i in 1..sonsLen(n)-1:
+        # use as many typed arguments as possible:
+        var x = safeSemExpr(c, n.sons[i])
+        if x.kind == nkEmpty or x.typ == nil: break
+        addSon(a, x)
+      suggestCall(c, a, n, outputs)
+          
+  dec(c.inCompilesContext)
+  if outputs > 0 and gIdeCmd != ideUse: suggestQuit()
+
+proc suggestStmt*(c: PContext, n: PNode) = 
+  suggestExpr(c, n)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
new file mode 100644
index 000000000..7f9e25f82
--- /dev/null
+++ b/compiler/syntaxes.nim
@@ -0,0 +1,177 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements the dispatcher for the different parsers.
+
+import 
+  strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, 
+  pbraces, filters, filter_tmpl, renderer
+
+type 
+  TFilterKind* = enum 
+    filtNone, filtTemplate, filtReplace, filtStrip
+  TParserKind* = enum 
+    skinStandard, skinStrongSpaces, skinBraces, skinEndX
+
+const 
+  parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
+                                              "braces", "endx"]
+  filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
+                                              "strip"]
+
+type
+  TParsers*{.final.} = object 
+    skin*: TParserKind
+    parser*: TParser
+
+
+proc parseFile*(fileIdx: int32): PNode{.procvar.}
+proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream)
+proc closeParsers*(p: var TParsers)
+proc parseAll*(p: var TParsers): PNode
+proc parseTopLevelStmt*(p: var TParsers): PNode
+  # implements an iterator. Returns the next top-level statement or nil if end
+  # of stream.
+
+# implementation
+
+proc parseFile(fileIdx: int32): PNode =
+  var 
+    p: TParsers
+    f: File
+  let filename = fileIdx.toFullPathConsiderDirty
+  if not open(f, filename):
+    rawMessage(errCannotOpenFile, filename)
+    return 
+  openParsers(p, fileIdx, llStreamOpen(f))
+  result = parseAll(p)
+  closeParsers(p)
+
+proc parseAll(p: var TParsers): PNode = 
+  case p.skin
+  of skinStandard, skinStrongSpaces:
+    result = parser.parseAll(p.parser)
+  of skinBraces: 
+    result = pbraces.parseAll(p.parser)
+  of skinEndX: 
+    internalError("parser to implement") 
+    result = ast.emptyNode
+  
+proc parseTopLevelStmt(p: var TParsers): PNode = 
+  case p.skin
+  of skinStandard, skinStrongSpaces:
+    result = parser.parseTopLevelStmt(p.parser)
+  of skinBraces: 
+    result = pbraces.parseTopLevelStmt(p.parser)
+  of skinEndX: 
+    internalError("parser to implement") 
+    result = ast.emptyNode
+  
+proc utf8Bom(s: string): int = 
+  if (s[0] == '\xEF') and (s[1] == '\xBB') and (s[2] == '\xBF'): 
+    result = 3
+  else: 
+    result = 0
+  
+proc containsShebang(s: string, i: int): bool = 
+  if (s[i] == '#') and (s[i + 1] == '!'): 
+    var j = i + 2
+    while s[j] in Whitespace: inc(j)
+    result = s[j] == '/'
+
+proc parsePipe(filename: string, inputStream: PLLStream): PNode = 
+  result = ast.emptyNode
+  var s = llStreamOpen(filename, fmRead)
+  if s != nil: 
+    var line = newStringOfCap(80)
+    discard llStreamReadLine(s, line)
+    var i = utf8Bom(line)
+    if containsShebang(line, i):
+      discard llStreamReadLine(s, line)
+      i = 0
+    if line[i] == '#' and line[i+1] == '!':
+      inc(i, 2)
+      while line[i] in Whitespace: inc(i)
+      var q: TParser
+      openParser(q, filename, llStreamOpen(substr(line, i)))
+      result = parser.parseAll(q)
+      closeParser(q)
+    llStreamClose(s)
+
+proc getFilter(ident: PIdent): TFilterKind = 
+  for i in countup(low(TFilterKind), high(TFilterKind)): 
+    if identEq(ident, filterNames[i]): 
+      return i
+  result = filtNone
+
+proc getParser(ident: PIdent): TParserKind = 
+  for i in countup(low(TParserKind), high(TParserKind)): 
+    if identEq(ident, parserNames[i]): 
+      return i
+  rawMessage(errInvalidDirectiveX, ident.s)
+
+proc getCallee(n: PNode): PIdent = 
+  if n.kind in nkCallKinds and n.sons[0].kind == nkIdent: 
+    result = n.sons[0].ident
+  elif n.kind == nkIdent: 
+    result = n.ident
+  else: 
+    rawMessage(errXNotAllowedHere, renderTree(n))
+  
+proc applyFilter(p: var TParsers, n: PNode, filename: string, 
+                 stdin: PLLStream): PLLStream = 
+  var ident = getCallee(n)
+  var f = getFilter(ident)
+  case f
+  of filtNone: 
+    p.skin = getParser(ident)
+    result = stdin
+  of filtTemplate: 
+    result = filterTmpl(stdin, filename, n)
+  of filtStrip: 
+    result = filterStrip(stdin, filename, n)
+  of filtReplace: 
+    result = filterReplace(stdin, filename, n)
+  if f != filtNone: 
+    if gVerbosity >= 2: 
+      rawMessage(hintCodeBegin, [])
+      msgWriteln(result.s)
+      rawMessage(hintCodeEnd, [])
+
+proc evalPipe(p: var TParsers, n: PNode, filename: string, 
+              start: PLLStream): PLLStream = 
+  result = start
+  if n.kind == nkEmpty: return 
+  if n.kind == nkInfix and n.sons[0].kind == nkIdent and
+      identEq(n.sons[0].ident, "|"):
+    for i in countup(1, 2):
+      if n.sons[i].kind == nkInfix:
+        result = evalPipe(p, n.sons[i], filename, result)
+      else:
+        result = applyFilter(p, n.sons[i], filename, result)
+  elif n.kind == nkStmtList:
+    result = evalPipe(p, n.sons[0], filename, result)
+  else:
+    result = applyFilter(p, n, filename, result)
+  
+proc openParsers(p: var TParsers, fileIdx: int32, inputstream: PLLStream) = 
+  var s: PLLStream
+  p.skin = skinStandard
+  let filename = fileIdx.toFullPathConsiderDirty
+  var pipe = parsePipe(filename, inputstream)
+  if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
+  else: s = inputstream
+  case p.skin
+  of skinStandard, skinBraces, skinEndX:
+    parser.openParser(p.parser, fileIdx, s, false)
+  of skinStrongSpaces:
+    parser.openParser(p.parser, fileIdx, s, true)
+  
+proc closeParsers(p: var TParsers) =
+  parser.closeParser(p.parser)
diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim
new file mode 100644
index 000000000..0082dfcbb
--- /dev/null
+++ b/compiler/tccgen.nim
@@ -0,0 +1,76 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  os, strutils, options, msgs, tinyc
+
+{.compile: "../tinyc/libtcc.c".}
+
+proc tinyCErrorHandler(closure: pointer, msg: cstring) {.cdecl.} = 
+  rawMessage(errGenerated, $msg)
+  
+proc initTinyCState: PccState = 
+  result = openCCState()
+  setErrorFunc(result, nil, tinyCErrorHandler)
+
+var
+  gTinyC = initTinyCState()
+  libIncluded = false
+
+proc addFile(filename: string) =  
+  if addFile(gTinyC, filename) != 0'i32:
+    rawMessage(errCannotOpenFile, filename)
+
+proc setupEnvironment = 
+  when defined(amd64):
+    defineSymbol(gTinyC, "__x86_64__", nil)
+  elif defined(i386):
+    defineSymbol(gTinyC, "__i386__", nil)  
+  when defined(linux):
+    defineSymbol(gTinyC, "__linux__", nil)
+    defineSymbol(gTinyC, "__linux", nil)
+  var nimrodDir = getPrefixDir()
+
+  addIncludePath(gTinyC, libpath)
+  when defined(windows): 
+    addSysincludePath(gTinyC, nimrodDir / "tinyc/win32/include")
+  addSysincludePath(gTinyC, nimrodDir / "tinyc/include")
+  when defined(windows): 
+    defineSymbol(gTinyC, "_WIN32", nil)
+    # we need Mingw's headers too:
+    var gccbin = getConfigVar("gcc.path") % ["nimrod", nimrodDir]
+    addSysincludePath(gTinyC, gccbin /../ "include")
+    #addFile(nimrodDir / r"tinyc\win32\wincrt1.o")
+    addFile(nimrodDir / r"tinyc\win32\alloca86.o")
+    addFile(nimrodDir / r"tinyc\win32\chkstk.o")
+    #addFile(nimrodDir / r"tinyc\win32\crt1.o")
+
+    #addFile(nimrodDir / r"tinyc\win32\dllcrt1.o")
+    #addFile(nimrodDir / r"tinyc\win32\dllmain.o")
+    addFile(nimrodDir / r"tinyc\win32\libtcc1.o")
+    
+    #addFile(nimrodDir / r"tinyc\win32\lib\crt1.c")
+    #addFile(nimrodDir / r"tinyc\lib\libtcc1.c")
+  else:
+    addSysincludePath(gTinyC, "/usr/include")
+    when defined(amd64):
+      addSysincludePath(gTinyC, "/usr/include/x86_64-linux-gnu")
+
+proc compileCCode*(ccode: string) = 
+  if not libIncluded:
+    libIncluded = true
+    setupEnvironment()
+  discard compileString(gTinyC, ccode)
+  
+proc run*(args: string) =
+  var s = @[cstring(gProjectName)] & map(split(args), proc(x: string): cstring = cstring(x))
+  var err = tinyc.run(gTinyC, cint(len(s)), cast[cstringArray](addr(s[0]))) != 0'i32
+  closeCCState(gTinyC)
+  if err: rawMessage(errExecutionOfProgramFailed, "")
+
diff --git a/compiler/testability.nim b/compiler/testability.nim
new file mode 100644
index 000000000..4587a5344
--- /dev/null
+++ b/compiler/testability.nim
@@ -0,0 +1,5 @@
+template tests*(body: stmt) {.immediate.} =
+  when defined(selftest):
+    when not declared(unittest): import unittest
+    body
+
diff --git a/compiler/transf.nim b/compiler/transf.nim
new file mode 100644
index 000000000..57547b682
--- /dev/null
+++ b/compiler/transf.nim
@@ -0,0 +1,815 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module implements the transformator. It transforms the syntax tree
+# to ease the work of the code generators. Does some transformations:
+#
+# * inlines iterators
+# * inlines constants
+# * performes constant folding
+# * converts "continue" to "break"; disambiguates "break"
+# * introduces method dispatchers
+# * performs lambda lifting for closure support
+
+import
+  intsets, strutils, lists, options, ast, astalgo, trees, treetab, msgs, os,
+  idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
+  lambdalifting, sempass2, lowerings
+
+# implementation
+
+type
+  PTransNode* = distinct PNode
+
+  PTransCon = ref TTransCon
+  TTransCon{.final.} = object # part of TContext; stackable
+    mapping: TIdNodeTable     # mapping from symbols to nodes
+    owner: PSym               # current owner
+    forStmt: PNode            # current for stmt
+    forLoopBody: PTransNode   # transformed for loop body
+    yieldStmts: int           # we count the number of yield statements,
+                              # because we need to introduce new variables
+                              # if we encounter the 2nd yield statement
+    next: PTransCon           # for stacking
+
+  TTransfContext = object of passes.TPassContext
+    module: PSym
+    transCon: PTransCon      # top of a TransCon stack
+    inlining: int            # > 0 if we are in inlining context (copy vars)
+    nestedProcs: int         # > 0 if we are in a nested proc
+    contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
+  PTransf = ref TTransfContext
+
+proc newTransNode(a: PNode): PTransNode {.inline.} =
+  result = PTransNode(shallowCopy(a))
+
+proc newTransNode(kind: TNodeKind, info: TLineInfo,
+                  sons: int): PTransNode {.inline.} =
+  var x = newNodeI(kind, info)
+  newSeq(x.sons, sons)
+  result = x.PTransNode
+
+proc newTransNode(kind: TNodeKind, n: PNode,
+                  sons: int): PTransNode {.inline.} =
+  var x = newNodeIT(kind, n.info, n.typ)
+  newSeq(x.sons, sons)
+  x.typ = n.typ
+  result = x.PTransNode
+
+proc `[]=`(a: PTransNode, i: int, x: PTransNode) {.inline.} =
+  var n = PNode(a)
+  n.sons[i] = PNode(x)
+
+proc `[]`(a: PTransNode, i: int): PTransNode {.inline.} =
+  var n = PNode(a)
+  result = n.sons[i].PTransNode
+
+proc add(a, b: PTransNode) {.inline.} = addSon(PNode(a), PNode(b))
+proc len(a: PTransNode): int {.inline.} = result = sonsLen(a.PNode)
+
+proc newTransCon(owner: PSym): PTransCon =
+  assert owner != nil
+  new(result)
+  initIdNodeTable(result.mapping)
+  result.owner = owner
+
+proc pushTransCon(c: PTransf, t: PTransCon) =
+  t.next = c.transCon
+  c.transCon = t
+
+proc popTransCon(c: PTransf) =
+  if (c.transCon == nil): internalError("popTransCon")
+  c.transCon = c.transCon.next
+
+proc getCurrOwner(c: PTransf): PSym =
+  if c.transCon != nil: result = c.transCon.owner
+  else: result = c.module
+
+proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PSym =
+  result = newSym(skTemp, getIdent(genPrefix), getCurrOwner(c), info)
+  result.typ = skipTypes(typ, {tyGenericInst})
+  incl(result.flags, sfFromGeneric)
+
+proc transform(c: PTransf, n: PNode): PTransNode
+
+proc transformSons(c: PTransf, n: PNode): PTransNode =
+  result = newTransNode(n)
+  for i in countup(0, sonsLen(n)-1):
+    result[i] = transform(c, n.sons[i])
+
+proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
+  result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
+  result[0] = PTransNode(le)
+  result[1] = ri
+
+proc transformSymAux(c: PTransf, n: PNode): PNode =
+  #if n.sym.kind == skClosureIterator:
+  #  return liftIterSym(n)
+  var b: PNode
+  var tc = c.transCon
+  if sfBorrow in n.sym.flags:
+    # simply exchange the symbol:
+    b = n.sym.getBody
+    if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
+    b = newSymNode(b.sym)
+    b.info = n.info
+  else:
+    b = n
+  while tc != nil:
+    result = idNodeTableGet(tc.mapping, b.sym)
+    if result != nil: return
+    tc = tc.next
+  result = b
+
+proc transformSym(c: PTransf, n: PNode): PTransNode =
+  result = PTransNode(transformSymAux(c, n))
+
+proc transformVarSection(c: PTransf, v: PNode): PTransNode =
+  result = newTransNode(v)
+  for i in countup(0, sonsLen(v)-1):
+    var it = v.sons[i]
+    if it.kind == nkCommentStmt:
+      result[i] = PTransNode(it)
+    elif it.kind == nkIdentDefs:
+      if it.sons[0].kind != nkSym: internalError(it.info, "transformVarSection")
+      internalAssert(it.len == 3)
+      var newVar = copySym(it.sons[0].sym)
+      incl(newVar.flags, sfFromGeneric)
+      # fixes a strange bug for rodgen:
+      #include(it.sons[0].sym.flags, sfFromGeneric);
+      newVar.owner = getCurrOwner(c)
+      idNodeTablePut(c.transCon.mapping, it.sons[0].sym, newSymNode(newVar))
+      var defs = newTransNode(nkIdentDefs, it.info, 3)
+      if importantComments():
+        # keep documentation information:
+        PNode(defs).comment = it.comment
+      defs[0] = newSymNode(newVar).PTransNode
+      defs[1] = it.sons[1].PTransNode
+      defs[2] = transform(c, it.sons[2])
+      newVar.ast = defs[2].PNode
+      result[i] = defs
+    else:
+      if it.kind != nkVarTuple:
+        internalError(it.info, "transformVarSection: not nkVarTuple")
+      var L = sonsLen(it)
+      var defs = newTransNode(it.kind, it.info, L)
+      for j in countup(0, L-3):
+        var newVar = copySym(it.sons[j].sym)
+        incl(newVar.flags, sfFromGeneric)
+        newVar.owner = getCurrOwner(c)
+        idNodeTablePut(c.transCon.mapping, it.sons[j].sym, newSymNode(newVar))
+        defs[j] = newSymNode(newVar).PTransNode
+      assert(it.sons[L-2].kind == nkEmpty)
+      defs[L-2] = ast.emptyNode.PTransNode
+      defs[L-1] = transform(c, it.sons[L-1])
+      result[i] = defs
+
+proc transformConstSection(c: PTransf, v: PNode): PTransNode =
+  result = newTransNode(v)
+  for i in countup(0, sonsLen(v)-1):
+    var it = v.sons[i]
+    if it.kind == nkCommentStmt:
+      result[i] = PTransNode(it)
+    else:
+      if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
+      if it.sons[0].kind != nkSym:
+        internalError(it.info, "transformConstSection")
+      if sfFakeConst in it[0].sym.flags:
+        var b = newNodeI(nkConstDef, it.info)
+        addSon(b, it[0])
+        addSon(b, ast.emptyNode)            # no type description
+        addSon(b, transform(c, it[2]).PNode)
+        result[i] = PTransNode(b)
+      else:
+        result[i] = PTransNode(it)
+
+proc hasContinue(n: PNode): bool =
+  case n.kind
+  of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: discard
+  of nkContinueStmt: result = true
+  else:
+    for i in countup(0, sonsLen(n) - 1):
+      if hasContinue(n.sons[i]): return true
+
+proc newLabel(c: PTransf, n: PNode): PSym =
+  result = newSym(skLabel, nil, getCurrOwner(c), n.info)
+  result.name = getIdent(genPrefix & $result.id)
+
+proc freshLabels(c: PTransf, n: PNode; symMap: var TIdTable) =
+  if n.kind in {nkBlockStmt, nkBlockExpr}:
+    if n.sons[0].kind == nkSym:
+      let x = newLabel(c, n[0])
+      idTablePut(symMap, n[0].sym, x)
+      n.sons[0].sym = x
+  if n.kind == nkSym and n.sym.kind == skLabel:
+    let x = PSym(idTableGet(symMap, n.sym))
+    if x != nil: n.sym = x
+  else:
+    for i in 0 .. <safeLen(n): freshLabels(c, n.sons[i], symMap)
+
+proc transformBlock(c: PTransf, n: PNode): PTransNode =
+  var labl: PSym
+  if n.sons[0].kind != nkEmpty:
+    # already named block? -> Push symbol on the stack:
+    labl = n.sons[0].sym
+  else:
+    labl = newLabel(c, n)
+  c.breakSyms.add(labl)
+  result = transformSons(c, n)
+  discard c.breakSyms.pop
+  result[0] = newSymNode(labl).PTransNode
+
+proc transformLoopBody(c: PTransf, n: PNode): PTransNode =
+  # What if it contains "continue" and "break"? "break" needs
+  # an explicit label too, but not the same!
+
+  # We fix this here by making every 'break' belong to its enclosing loop
+  # and changing all breaks that belong to a 'block' by annotating it with
+  # a label (if it hasn't one already).
+  if hasContinue(n):
+    let labl = newLabel(c, n)
+    c.contSyms.add(labl)
+
+    result = newTransNode(nkBlockStmt, n.info, 2)
+    result[0] = newSymNode(labl).PTransNode
+    result[1] = transform(c, n)
+    discard c.contSyms.pop()
+  else:
+    result = transform(c, n)
+
+proc transformWhile(c: PTransf; n: PNode): PTransNode =
+  if c.inlining > 0:
+    result = transformSons(c, n)
+  else:
+    let labl = newLabel(c, n)
+    c.breakSyms.add(labl)
+    result = newTransNode(nkBlockStmt, n.info, 2)
+    result[0] = newSymNode(labl).PTransNode
+
+    var body = newTransNode(n)
+    for i in 0..n.len-2:
+      body[i] = transform(c, n.sons[i])
+    body[<n.len] = transformLoopBody(c, n.sons[<n.len])
+    result[1] = body
+    discard c.breakSyms.pop
+
+proc transformBreak(c: PTransf, n: PNode): PTransNode =
+  if n.sons[0].kind != nkEmpty or c.inlining > 0:
+    result = n.PTransNode
+    when false:
+      let lablCopy = idNodeTableGet(c.transCon.mapping, n.sons[0].sym)
+      if lablCopy.isNil:
+        result = n.PTransNode
+      else:
+        result = newTransNode(n.kind, n.info, 1)
+        result[0] = lablCopy.PTransNode
+  else:
+    let labl = c.breakSyms[c.breakSyms.high]
+    result = transformSons(c, n)
+    result[0] = newSymNode(labl).PTransNode
+
+proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
+  # XXX: BUG: what if `n` is an expression with side-effects?
+  for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
+    add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
+        transform(c, newTupleAccess(n, i))))
+
+proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
+  case n.kind
+  of nkSym:
+    result = transformSym(c, n)
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
+    # nothing to be done for leaves:
+    result = PTransNode(n)
+  of nkVarSection, nkLetSection:
+    result = transformVarSection(c, n)
+  else:
+    result = newTransNode(n)
+    for i in countup(0, sonsLen(n)-1):
+      result[i] =  introduceNewLocalVars(c, n.sons[i])
+
+proc transformYield(c: PTransf, n: PNode): PTransNode =
+  result = newTransNode(nkStmtList, n.info, 0)
+  var e = n.sons[0]
+  # c.transCon.forStmt.len == 3 means that there is one for loop variable
+  # and thus no tuple unpacking:
+  if skipTypes(e.typ, {tyGenericInst}).kind == tyTuple and
+      c.transCon.forStmt.len != 3:
+    e = skipConv(e)
+    if e.kind == nkPar:
+      for i in countup(0, sonsLen(e) - 1):
+        add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
+                                transform(c, e.sons[i])))
+    else:
+      unpackTuple(c, e, result)
+  else:
+    var x = transform(c, e)
+    add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
+
+  inc(c.transCon.yieldStmts)
+  if c.transCon.yieldStmts <= 1:
+    # common case
+    add(result, c.transCon.forLoopBody)
+  else:
+    # we need to introduce new local variables:
+    add(result, introduceNewLocalVars(c, c.transCon.forLoopBody.PNode))
+
+proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
+  result = transformSons(c, n)
+  if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
+  var n = result.PNode
+  case n.sons[0].kind
+  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
+    var m = n.sons[0].sons[0]
+    if m.kind == a or m.kind == b:
+      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
+      n.sons[0].sons[0] = m.sons[0]
+      result = PTransNode(n.sons[0])
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    var m = n.sons[0].sons[1]
+    if m.kind == a or m.kind == b:
+      # addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
+      n.sons[0].sons[1] = m.sons[0]
+      result = PTransNode(n.sons[0])
+  else:
+    if n.sons[0].kind == a or n.sons[0].kind == b:
+      # addr ( deref ( x )) --> x
+      result = PTransNode(n.sons[0].sons[0])
+
+proc transformConv(c: PTransf, n: PNode): PTransNode =
+  # numeric types need range checks:
+  var dest = skipTypes(n.typ, abstractVarRange)
+  var source = skipTypes(n.sons[1].typ, abstractVarRange)
+  case dest.kind
+  of tyInt..tyInt64, tyEnum, tyChar, tyBool, tyUInt8..tyUInt32:
+    # we don't include uint and uint64 here as these are no ordinal types ;-)
+    if not isOrdinalType(source):
+      # float -> int conversions. ugh.
+      result = transformSons(c, n)
+    elif firstOrd(n.typ) <= firstOrd(n.sons[1].typ) and
+        lastOrd(n.sons[1].typ) <= lastOrd(n.typ):
+      # BUGFIX: simply leave n as it is; we need a nkConv node,
+      # but no range check:
+      result = transformSons(c, n)
+    else:
+      # generate a range check:
+      if dest.kind == tyInt64 or source.kind == tyInt64:
+        result = newTransNode(nkChckRange64, n, 3)
+      else:
+        result = newTransNode(nkChckRange, n, 3)
+      dest = skipTypes(n.typ, abstractVar)
+      result[0] = transform(c, n.sons[1])
+      result[1] = newIntTypeNode(nkIntLit, firstOrd(dest), source).PTransNode
+      result[2] = newIntTypeNode(nkIntLit, lastOrd(dest), source).PTransNode
+  of tyFloat..tyFloat128:
+    # XXX int64 -> float conversion?
+    if skipTypes(n.typ, abstractVar).kind == tyRange:
+      result = newTransNode(nkChckRangeF, n, 3)
+      dest = skipTypes(n.typ, abstractVar)
+      result[0] = transform(c, n.sons[1])
+      result[1] = copyTree(dest.n.sons[0]).PTransNode
+      result[2] = copyTree(dest.n.sons[1]).PTransNode
+    else:
+      result = transformSons(c, n)
+  of tyOpenArray, tyVarargs:
+    result = transform(c, n.sons[1])
+    PNode(result).typ = takeType(n.typ, n.sons[1].typ)
+    #echo n.info, " came here and produced ", typeToString(PNode(result).typ),
+    #   " from ", typeToString(n.typ), " and ", typeToString(n.sons[1].typ)
+  of tyCString:
+    if source.kind == tyString:
+      result = newTransNode(nkStringToCString, n, 1)
+      result[0] = transform(c, n.sons[1])
+    else:
+      result = transformSons(c, n)
+  of tyString:
+    if source.kind == tyCString:
+      result = newTransNode(nkCStringToString, n, 1)
+      result[0] = transform(c, n.sons[1])
+    else:
+      result = transformSons(c, n)
+  of tyRef, tyPtr:
+    dest = skipTypes(dest, abstractPtrs)
+    source = skipTypes(source, abstractPtrs)
+    if source.kind == tyObject:
+      var diff = inheritanceDiff(dest, source)
+      if diff < 0:
+        result = newTransNode(nkObjUpConv, n, 1)
+        result[0] = transform(c, n.sons[1])
+      elif diff > 0 and diff != high(int):
+        result = newTransNode(nkObjDownConv, n, 1)
+        result[0] = transform(c, n.sons[1])
+      else:
+        result = transform(c, n.sons[1])
+    else:
+      result = transformSons(c, n)
+  of tyObject:
+    var diff = inheritanceDiff(dest, source)
+    if diff < 0:
+      result = newTransNode(nkObjUpConv, n, 1)
+      result[0] = transform(c, n.sons[1])
+    elif diff > 0 and diff != high(int):
+      result = newTransNode(nkObjDownConv, n, 1)
+      result[0] = transform(c, n.sons[1])
+    else:
+      result = transform(c, n.sons[1])
+  of tyGenericParam, tyOrdinal:
+    result = transform(c, n.sons[1])
+    # happens sometimes for generated assignments, etc.
+  else:
+    result = transformSons(c, n)
+
+type
+  TPutArgInto = enum
+    paDirectMapping, paFastAsgn, paVarAsgn
+
+proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
+  # This analyses how to treat the mapping "formal <-> arg" in an
+  # inline context.
+  if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
+    return paDirectMapping    # XXX really correct?
+                              # what if ``arg`` has side-effects?
+  case arg.kind
+  of nkEmpty..nkNilLit:
+    result = paDirectMapping
+  of nkPar, nkCurly, nkBracket:
+    result = paFastAsgn
+    for i in countup(0, sonsLen(arg) - 1):
+      if putArgInto(arg.sons[i], formal) != paDirectMapping: return
+    result = paDirectMapping
+  else:
+    if skipTypes(formal, abstractInst).kind == tyVar: result = paVarAsgn
+    else: result = paFastAsgn
+
+proc findWrongOwners(c: PTransf, n: PNode) =
+  if n.kind == nkVarSection:
+    let x = n.sons[0].sons[0]
+    if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
+      internalError(x.info, "bah " & x.sym.name.s & " " &
+        x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
+  else:
+    for i in 0 .. <safeLen(n): findWrongOwners(c, n.sons[i])
+
+proc transformFor(c: PTransf, n: PNode): PTransNode =
+  # generate access statements for the parameters (unless they are constant)
+  # put mapping from formal parameters to actual parameters
+  if n.kind != nkForStmt: internalError(n.info, "transformFor")
+
+  var length = sonsLen(n)
+  var call = n.sons[length - 2]
+
+  let labl = newLabel(c, n)
+  c.breakSyms.add(labl)
+  result = newTransNode(nkBlockStmt, n.info, 2)
+  result[0] = newSymNode(labl).PTransNode
+
+  if call.typ.kind != tyIter and
+    (call.kind notin nkCallKinds or call.sons[0].kind != nkSym or
+      call.sons[0].sym.kind != skIterator):
+    n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
+    result[1] = lambdalifting.liftForLoop(n).PTransNode
+    discard c.breakSyms.pop
+    return result
+
+  #echo "transforming: ", renderTree(n)
+  var stmtList = newTransNode(nkStmtList, n.info, 0)
+
+  var loopBody = transformLoopBody(c, n.sons[length-1])
+
+  result[1] = stmtList
+  discard c.breakSyms.pop
+
+  var v = newNodeI(nkVarSection, n.info)
+  for i in countup(0, length - 3):
+    addVar(v, copyTree(n.sons[i])) # declare new vars
+  add(stmtList, v.PTransNode)
+
+  # Bugfix: inlined locals belong to the invoking routine, not to the invoked
+  # iterator!
+  let iter = call.sons[0].sym
+  var newC = newTransCon(getCurrOwner(c))
+  newC.forStmt = n
+  newC.forLoopBody = loopBody
+  # this can fail for 'nimsuggest' and 'check':
+  if iter.kind != skIterator: return result
+  # generate access statements for the parameters (unless they are constant)
+  pushTransCon(c, newC)
+  for i in countup(1, sonsLen(call) - 1):
+    var arg = transform(c, call.sons[i]).PNode
+    var formal = skipTypes(iter.typ, abstractInst).n.sons[i].sym
+    if arg.typ.kind == tyIter: continue
+    case putArgInto(arg, formal.typ)
+    of paDirectMapping:
+      idNodeTablePut(newC.mapping, formal, arg)
+    of paFastAsgn:
+      # generate a temporary and produce an assignment statement:
+      var temp = newTemp(c, formal.typ, formal.info)
+      addVar(v, newSymNode(temp))
+      add(stmtList, newAsgnStmt(c, newSymNode(temp), arg.PTransNode))
+      idNodeTablePut(newC.mapping, formal, newSymNode(temp))
+    of paVarAsgn:
+      assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
+      idNodeTablePut(newC.mapping, formal, arg)
+      # XXX BUG still not correct if the arg has a side effect!
+  var body = iter.getBody.copyTree
+  pushInfoContext(n.info)
+  # XXX optimize this somehow. But the check "c.inlining" is not correct:
+  var symMap: TIdTable
+  initIdTable symMap
+  freshLabels(c, body, symMap)
+
+  inc(c.inlining)
+  add(stmtList, transform(c, body))
+  #findWrongOwners(c, stmtList.pnode)
+  dec(c.inlining)
+  popInfoContext()
+  popTransCon(c)
+  # echo "transformed: ", stmtList.PNode.renderTree
+
+proc getMagicOp(call: PNode): TMagic =
+  if call.sons[0].kind == nkSym and
+      call.sons[0].sym.kind in {skProc, skMethod, skConverter}:
+    result = call.sons[0].sym.magic
+  else:
+    result = mNone
+
+proc transformCase(c: PTransf, n: PNode): PTransNode =
+  # removes `elif` branches of a case stmt
+  # adds ``else: nil`` if needed for the code generator
+  result = newTransNode(nkCaseStmt, n, 0)
+  var ifs = PTransNode(nil)
+  for i in 0 .. sonsLen(n)-1:
+    var it = n.sons[i]
+    var e = transform(c, it)
+    case it.kind
+    of nkElifBranch:
+      if ifs.PNode == nil:
+        ifs = newTransNode(nkIfStmt, it.info, 0)
+      ifs.add(e)
+    of nkElse:
+      if ifs.PNode == nil: result.add(e)
+      else: ifs.add(e)
+    else:
+      result.add(e)
+  if ifs.PNode != nil:
+    var elseBranch = newTransNode(nkElse, n.info, 1)
+    elseBranch[0] = ifs
+    result.add(elseBranch)
+  elif result.PNode.lastSon.kind != nkElse and not (
+      skipTypes(n.sons[0].typ, abstractVarRange).kind in
+        {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32}):
+    # fix a stupid code gen bug by normalizing:
+    var elseBranch = newTransNode(nkElse, n.info, 1)
+    elseBranch[0] = newTransNode(nkNilLit, n.info, 0)
+    add(result, elseBranch)
+
+proc transformArrayAccess(c: PTransf, n: PNode): PTransNode =
+  # XXX this is really bad; transf should use a proper AST visitor
+  if n.sons[0].kind == nkSym and n.sons[0].sym.kind == skType:
+    result = n.PTransNode
+  else:
+    result = newTransNode(n)
+    for i in 0 .. < n.len:
+      result[i] = transform(c, skipConv(n.sons[i]))
+
+proc getMergeOp(n: PNode): PSym =
+  case n.kind
+  of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
+     nkCallStrLit:
+    if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
+      result = n.sons[0].sym
+  else: discard
+
+proc flattenTreeAux(d, a: PNode, op: PSym) =
+  let op2 = getMergeOp(a)
+  if op2 != nil and
+      (op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
+    for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
+  else:
+    addSon(d, copyTree(a))
+
+proc flattenTree(root: PNode): PNode =
+  let op = getMergeOp(root)
+  if op != nil:
+    result = copyNode(root)
+    addSon(result, copyTree(root.sons[0]))
+    flattenTreeAux(result, root, op)
+  else:
+    result = root
+
+proc transformCall(c: PTransf, n: PNode): PTransNode =
+  var n = flattenTree(n)
+  let op = getMergeOp(n)
+  let magic = getMagic(n)
+  if op != nil and op.magic != mNone and n.len >= 3:
+    result = newTransNode(nkCall, n, 0)
+    add(result, transform(c, n.sons[0]))
+    var j = 1
+    while j < sonsLen(n):
+      var a = transform(c, n.sons[j]).PNode
+      inc(j)
+      if isConstExpr(a):
+        while (j < sonsLen(n)):
+          let b = transform(c, n.sons[j]).PNode
+          if not isConstExpr(b): break
+          a = evalOp(op.magic, n, a, b, nil)
+          inc(j)
+      add(result, a.PTransNode)
+    if len(result) == 2: result = result[1]
+  elif magic == mNBindSym:
+    # for bindSym(myconst) we MUST NOT perform constant folding:
+    result = n.PTransNode
+  elif magic == mProcCall:
+    # but do not change to its dispatcher:
+    result = transformSons(c, n[1])
+  else:
+    let s = transformSons(c, n).PNode
+    # bugfix: check after 'transformSons' if it's still a method call:
+    # use the dispatcher for the call:
+    if s.sons[0].kind == nkSym and s.sons[0].sym.kind == skMethod:
+      let t = lastSon(s.sons[0].sym.ast)
+      if t.kind != nkSym or sfDispatcher notin t.sym.flags:
+        methodDef(s.sons[0].sym, false)
+      result = methodCall(s).PTransNode
+    else:
+      result = s.PTransNode
+
+proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
+  # symbols that expand to a complex constant (array, etc.) should not be
+  # inlined, unless it's the empty array:
+  result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkBracket} and
+      cnst.len != 0
+
+proc commonOptimizations*(c: PSym, n: PNode): PNode =
+  result = n
+  for i in 0 .. < n.safeLen:
+    result.sons[i] = commonOptimizations(c, n.sons[i])
+  var op = getMergeOp(n)
+  if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
+    result = newNodeIT(nkCall, n.info, n.typ)
+    add(result, n.sons[0])
+    var args = newNode(nkArgList)
+    flattenTreeAux(args, n, op)
+    var j = 0
+    while j < sonsLen(args):
+      var a = args.sons[j]
+      inc(j)
+      if isConstExpr(a):
+        while j < sonsLen(args):
+          let b = args.sons[j]
+          if not isConstExpr(b): break
+          a = evalOp(op.magic, result, a, b, nil)
+          inc(j)
+      add(result, a)
+    if len(result) == 2: result = result[1]
+  else:
+    var cnst = getConstExpr(c, n)
+    # we inline constants if they are not complex constants:
+    if cnst != nil and not dontInlineConstant(n, cnst):
+      result = cnst
+    else:
+      result = n
+
+proc transform(c: PTransf, n: PNode): PTransNode =
+  case n.kind
+  of nkSym:
+    result = transformSym(c, n)
+  of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit:
+    # nothing to be done for leaves:
+    result = PTransNode(n)
+  of nkBracketExpr: result = transformArrayAccess(c, n)
+  of procDefs:
+    when false:
+      if n.sons[genericParamsPos].kind == nkEmpty:
+        var s = n.sons[namePos].sym
+        n.sons[bodyPos] = PNode(transform(c, s.getBody))
+        if s.ast.sons[bodyPos] != n.sons[bodyPos]:
+          # somehow this can happen ... :-/
+          s.ast.sons[bodyPos] = n.sons[bodyPos]
+        #n.sons[bodyPos] = liftLambdas(s, n)
+        #if n.kind == nkMethodDef: methodDef(s, false)
+    #if n.kind == nkIteratorDef and n.typ != nil:
+    #  return liftIterSym(n.sons[namePos]).PTransNode
+    result = PTransNode(n)
+  of nkMacroDef:
+    # XXX no proper closure support yet:
+    when false:
+      if n.sons[genericParamsPos].kind == nkEmpty:
+        var s = n.sons[namePos].sym
+        n.sons[bodyPos] = PNode(transform(c, s.getBody))
+        if n.kind == nkMethodDef: methodDef(s, false)
+    result = PTransNode(n)
+  of nkForStmt:
+    result = transformFor(c, n)
+  of nkParForStmt:
+    result = transformSons(c, n)
+  of nkCaseStmt: result = transformCase(c, n)
+  of nkContinueStmt:
+    result = PTransNode(newNodeI(nkBreakStmt, n.info))
+    var labl = c.contSyms[c.contSyms.high]
+    add(result, PTransNode(newSymNode(labl)))
+  of nkBreakStmt: result = transformBreak(c, n)
+  of nkWhileStmt: result = transformWhile(c, n)
+  of nkCallKinds:
+    result = transformCall(c, n)
+  of nkAddr, nkHiddenAddr:
+    result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
+  of nkDerefExpr, nkHiddenDeref:
+    result = transformAddrDeref(c, n, nkAddr, nkHiddenAddr)
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    result = transformConv(c, n)
+  of nkDiscardStmt:
+    result = PTransNode(n)
+    if n.sons[0].kind != nkEmpty:
+      result = transformSons(c, n)
+      if isConstExpr(PNode(result).sons[0]):
+        # ensure that e.g. discard "some comment" gets optimized away
+        # completely:
+        result = PTransNode(newNode(nkCommentStmt))
+  of nkCommentStmt, nkTemplateDef:
+    return n.PTransNode
+  of nkConstSection:
+    # do not replace ``const c = 3`` with ``const 3 = 3``
+    return transformConstSection(c, n)
+  of nkTypeSection:
+    # no need to transform type sections:
+    return PTransNode(n)
+  of nkVarSection, nkLetSection:
+    if c.inlining > 0:
+      # we need to copy the variables for multiple yield statements:
+      result = transformVarSection(c, n)
+    else:
+      result = transformSons(c, n)
+  of nkYieldStmt:
+    if c.inlining > 0:
+      result = transformYield(c, n)
+    else:
+      result = transformSons(c, n)
+  of nkBlockStmt, nkBlockExpr:
+    result = transformBlock(c, n)
+  of nkIdentDefs, nkConstDef:
+    result = transformSons(c, n)
+    # XXX comment handling really sucks:
+    if importantComments():
+      PNode(result).comment = n.comment
+  of nkClosure: return PTransNode(n)
+  else:
+    result = transformSons(c, n)
+  var cnst = getConstExpr(c.module, PNode(result))
+  # we inline constants if they are not complex constants:
+  if cnst != nil and not dontInlineConstant(n, cnst):
+    result = PTransNode(cnst) # do not miss an optimization
+
+proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
+  # Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
+  # this step! We have to rely that the semantic pass transforms too errornous
+  # nodes into an empty node.
+  if c.fromCache or nfTransf in n.flags: return n
+  pushTransCon(c, newTransCon(owner))
+  result = PNode(transform(c, n))
+  popTransCon(c)
+  incl(result.flags, nfTransf)
+
+proc openTransf(module: PSym, filename: string): PTransf =
+  new(result)
+  result.contSyms = @[]
+  result.breakSyms = @[]
+  result.module = module
+
+proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
+  if nfTransf in n.flags or prc.kind in {skTemplate}:
+    result = n
+  else:
+    var c = openTransf(module, "")
+    result = processTransf(c, n, prc)
+    result = liftLambdas(prc, result)
+    #if prc.kind == skClosureIterator:
+    #  result = lambdalifting.liftIterator(prc, result)
+    incl(result.flags, nfTransf)
+    when useEffectSystem: trackProc(prc, result)
+    #if prc.name.s == "testbody":
+    #  echo renderTree(result)
+
+proc transformStmt*(module: PSym, n: PNode): PNode =
+  if nfTransf in n.flags:
+    result = n
+  else:
+    var c = openTransf(module, "")
+    result = processTransf(c, n, module)
+    result = liftLambdasForTopLevel(module, result)
+    incl(result.flags, nfTransf)
+    when useEffectSystem: trackTopLevelStmt(module, result)
+
+proc transformExpr*(module: PSym, n: PNode): PNode =
+  if nfTransf in n.flags:
+    result = n
+  else:
+    var c = openTransf(module, "")
+    result = processTransf(c, n, module)
+    incl(result.flags, nfTransf)
diff --git a/compiler/trees.nim b/compiler/trees.nim
new file mode 100644
index 000000000..2c631af99
--- /dev/null
+++ b/compiler/trees.nim
@@ -0,0 +1,170 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# tree helper routines
+
+import
+  ast, astalgo, lexer, msgs, strutils, wordrecg
+
+proc hasSon(father, son: PNode): bool =
+  for i in countup(0, sonsLen(father) - 1):
+    if father.sons[i] == son:
+      return true
+  result = false
+
+proc cyclicTreeAux(n, s: PNode): bool =
+  if n == nil:
+    return false
+  if hasSon(s, n):
+    return true
+  var m = sonsLen(s)
+  addSon(s, n)
+  if not (n.kind in {nkEmpty..nkNilLit}):
+    for i in countup(0, sonsLen(n) - 1):
+      if cyclicTreeAux(n.sons[i], s):
+        return true
+  result = false
+  delSon(s, m)
+
+proc cyclicTree*(n: PNode): bool =
+  var s = newNodeI(nkEmpty, n.info)
+  result = cyclicTreeAux(n, s)
+
+proc exprStructuralEquivalent*(a, b: PNode): bool =
+  result = false
+  if a == b:
+    result = true
+  elif (a != nil) and (b != nil) and (a.kind == b.kind):
+    case a.kind
+    of nkSym:
+      # don't go nuts here: same symbol as string is enough:
+      result = a.sym.name.id == b.sym.name.id
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkEmpty, nkNilLit, nkType: result = true
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not exprStructuralEquivalent(a.sons[i], b.sons[i]): return
+        result = true
+
+proc sameTree*(a, b: PNode): bool =
+  result = false
+  if a == b:
+    result = true
+  elif a != nil and b != nil and a.kind == b.kind:
+    if a.flags != b.flags: return
+    if a.info.line != b.info.line: return
+    if a.info.col != b.info.col:
+      return                  #if a.info.fileIndex <> b.info.fileIndex then exit;
+    case a.kind
+    of nkSym:
+      # don't go nuts here: same symbol as string is enough:
+      result = a.sym.name.id == b.sym.name.id
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkEmpty, nkNilLit, nkType: result = true
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameTree(a.sons[i], b.sons[i]): return
+        result = true
+
+proc getProcSym*(call: PNode): PSym =
+  result = call.sons[0].sym
+
+proc getOpSym*(op: PNode): PSym =
+  if op.kind notin {nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit}:
+    result = nil
+  else:
+    if sonsLen(op) <= 0: internalError(op.info, "getOpSym")
+    elif op.sons[0].kind == nkSym: result = op.sons[0].sym
+    else: result = nil
+
+proc getMagic*(op: PNode): TMagic =
+  case op.kind
+  of nkCallKinds:
+    case op.sons[0].kind
+    of nkSym: result = op.sons[0].sym.magic
+    else: result = mNone
+  else: result = mNone
+
+proc treeToSym*(t: PNode): PSym =
+  result = t.sym
+
+proc isConstExpr*(n: PNode): bool =
+  result = (n.kind in
+      {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+       nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
+
+proc isDeepConstExpr*(n: PNode): bool =
+  case n.kind
+  of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
+      nkFloatLit..nkFloat64Lit, nkNilLit:
+    result = true
+  of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
+    result = isDeepConstExpr(n.sons[1])
+  of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
+    for i in 0 .. <n.len:
+      if not isDeepConstExpr(n.sons[i]): return false
+    # XXX once constant objects are supported by the codegen this needs to be
+    # weakened:
+    result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
+  else: discard
+
+proc flattenTreeAux(d, a: PNode, op: TMagic) =
+  if (getMagic(a) == op):     # a is a "leaf", so add it:
+    for i in countup(1, sonsLen(a) - 1): # BUGFIX
+      flattenTreeAux(d, a.sons[i], op)
+  else:
+    addSon(d, copyTree(a))
+
+proc flattenTree*(root: PNode, op: TMagic): PNode =
+  result = copyNode(root)
+  if getMagic(root) == op:
+    # BUGFIX: forget to copy prc
+    addSon(result, copyNode(root.sons[0]))
+    flattenTreeAux(result, root, op)
+
+proc swapOperands*(op: PNode) =
+  var tmp = op.sons[1]
+  op.sons[1] = op.sons[2]
+  op.sons[2] = tmp
+
+proc isRange*(n: PNode): bool {.inline.} =
+  if n.kind in nkCallKinds:
+    if n[0].kind == nkIdent and n[0].ident.id == ord(wDotDot) or
+        n[0].kind in {nkClosedSymChoice, nkOpenSymChoice} and
+        n[0][1].sym.name.id == ord(wDotDot):
+      result = true
+
+proc whichPragma*(n: PNode): TSpecialWord =
+  let key = if n.kind == nkExprColonExpr: n.sons[0] else: n
+  if key.kind == nkIdent: result = whichKeyword(key.ident)
+
+proc unnestStmts(n, result: PNode) =
+  if n.kind == nkStmtList:
+    for x in items(n): unnestStmts(x, result)
+  elif n.kind notin {nkCommentStmt, nkNilLit}:
+    result.add(n)
+
+proc flattenStmts*(n: PNode): PNode =
+  ## flattens a nested statement list; used for pattern matching
+  result = newNodeI(nkStmtList, n.info)
+  unnestStmts(n, result)
+  if result.len == 1:
+    result = result.sons[0]
+
+proc extractRange*(k: TNodeKind, n: PNode, a, b: int): PNode =
+  result = newNodeI(k, n.info, b-a+1)
+  for i in 0 .. b-a: result.sons[i] = n.sons[i+a]
diff --git a/compiler/treetab.nim b/compiler/treetab.nim
new file mode 100644
index 000000000..8d66d56c7
--- /dev/null
+++ b/compiler/treetab.nim
@@ -0,0 +1,111 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Implements a table from trees to trees. Does structural equivalence checking.
+
+import 
+  hashes, ast, astalgo, types
+
+proc hashTree(n: PNode): THash = 
+  if n == nil: return 
+  result = ord(n.kind)
+  case n.kind
+  of nkEmpty, nkNilLit, nkType: 
+    discard
+  of nkIdent: 
+    result = result !& n.ident.h
+  of nkSym:
+    result = result !& n.sym.name.h
+  of nkCharLit..nkUInt64Lit: 
+    if (n.intVal >= low(int)) and (n.intVal <= high(int)): 
+      result = result !& int(n.intVal)
+  of nkFloatLit..nkFloat64Lit:
+    if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0): 
+      result = result !& toInt(n.floatVal)
+  of nkStrLit..nkTripleStrLit:
+    if not n.strVal.isNil:
+      result = result !& hash(n.strVal)
+  else: 
+    for i in countup(0, sonsLen(n) - 1): 
+      result = result !& hashTree(n.sons[i])
+  
+proc treesEquivalent(a, b: PNode): bool = 
+  if a == b: 
+    result = true
+  elif (a != nil) and (b != nil) and (a.kind == b.kind): 
+    case a.kind
+    of nkEmpty, nkNilLit, nkType: result = true
+    of nkSym: result = a.sym.id == b.sym.id
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    else: 
+      if sonsLen(a) == sonsLen(b): 
+        for i in countup(0, sonsLen(a) - 1): 
+          if not treesEquivalent(a.sons[i], b.sons[i]): return 
+        result = true
+    if result: result = sameTypeOrNil(a.typ, b.typ)
+  
+proc nodeTableRawGet(t: TNodeTable, k: THash, key: PNode): int = 
+  var h: THash = k and high(t.data)
+  while t.data[h].key != nil: 
+    if (t.data[h].h == k) and treesEquivalent(t.data[h].key, key): 
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+proc nodeTableGet*(t: TNodeTable, key: PNode): int = 
+  var index = nodeTableRawGet(t, hashTree(key), key)
+  if index >= 0: result = t.data[index].val
+  else: result = low(int)
+  
+proc nodeTableRawInsert(data: var TNodePairSeq, k: THash, key: PNode, 
+                        val: int) = 
+  var h: THash = k and high(data)
+  while data[h].key != nil: h = nextTry(h, high(data))
+  assert(data[h].key == nil)
+  data[h].h = k
+  data[h].key = key
+  data[h].val = val
+
+proc nodeTablePut*(t: var TNodeTable, key: PNode, val: int) = 
+  var n: TNodePairSeq
+  var k: THash = hashTree(key)
+  var index = nodeTableRawGet(t, k, key)
+  if index >= 0: 
+    assert(t.data[index].key != nil)
+    t.data[index].val = val
+  else: 
+    if mustRehash(len(t.data), t.counter): 
+      newSeq(n, len(t.data) * GrowthFactor)
+      for i in countup(0, high(t.data)): 
+        if t.data[i].key != nil: 
+          nodeTableRawInsert(n, t.data[i].h, t.data[i].key, t.data[i].val)
+      swap(t.data, n)
+    nodeTableRawInsert(t.data, k, key, val)
+    inc(t.counter)
+
+proc nodeTableTestOrSet*(t: var TNodeTable, key: PNode, val: int): int = 
+  var n: TNodePairSeq
+  var k: THash = hashTree(key)
+  var index = nodeTableRawGet(t, k, key)
+  if index >= 0: 
+    assert(t.data[index].key != nil)
+    result = t.data[index].val
+  else: 
+    if mustRehash(len(t.data), t.counter): 
+      newSeq(n, len(t.data) * GrowthFactor)
+      for i in countup(0, high(t.data)): 
+        if t.data[i].key != nil: 
+          nodeTableRawInsert(n, t.data[i].h, t.data[i].key, t.data[i].val)
+      swap(t.data, n)
+    nodeTableRawInsert(t.data, k, key, val)
+    result = val
+    inc(t.counter)
diff --git a/compiler/types.nim b/compiler/types.nim
new file mode 100644
index 000000000..e205f5722
--- /dev/null
+++ b/compiler/types.nim
@@ -0,0 +1,1483 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# this module contains routines for accessing and iterating over types
+
+import
+  intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
+
+proc firstOrd*(t: PType): BiggestInt
+proc lastOrd*(t: PType): BiggestInt
+proc lengthOrd*(t: PType): BiggestInt
+type
+  TPreferedDesc* = enum
+    preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg
+
+proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string
+proc base*(t: PType): PType
+  # ------------------- type iterator: ----------------------------------------
+type
+  TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop
+  TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it
+  TTypePredicate* = proc (t: PType): bool {.nimcall.}
+
+proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool
+  # Returns result of `iter`.
+proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType
+  # Returns result of `iter`.
+
+type
+  TParamsEquality* = enum     # they are equal, but their
+                              # identifiers or their return
+                              # type differ (i.e. they cannot be
+                              # overloaded)
+                              # this used to provide better error messages
+    paramsNotEqual,           # parameters are not equal
+    paramsEqual,              # parameters are equal
+    paramsIncompatible
+
+proc equalParams*(a, b: PNode): TParamsEquality
+  # returns whether the parameter lists of the procs a, b are exactly the same
+proc isOrdinalType*(t: PType): bool
+proc enumHasHoles*(t: PType): bool
+
+const
+  abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
+                   tyConst, tyMutable, tyTypeDesc}
+  abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
+                  tyConst, tyMutable, tyTypeDesc}
+  abstractRange* = {tyGenericInst, tyRange, tyDistinct, tyOrdinal,
+                    tyConst, tyMutable, tyTypeDesc}
+  abstractVarRange* = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
+                       tyConst, tyMutable, tyTypeDesc}
+  abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal,
+                   tyTypeDesc}
+
+  skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
+               tyTypeDesc}
+  typedescPtrs* = abstractPtrs + {tyTypeDesc}
+  typedescInst* = abstractInst + {tyTypeDesc}
+
+proc containsObject*(t: PType): bool
+proc containsGarbageCollectedRef*(typ: PType): bool
+proc containsHiddenPointer*(typ: PType): bool
+proc canFormAcycle*(typ: PType): bool
+proc isCompatibleToCString*(a: PType): bool
+proc getOrdValue*(n: PNode): BiggestInt
+proc computeSize*(typ: PType): BiggestInt
+proc getSize*(typ: PType): BiggestInt
+proc isPureObject*(typ: PType): bool
+proc invalidGenericInst*(f: PType): bool
+  # for debugging
+type
+  TTypeFieldResult* = enum
+    frNone,                   # type has no object type field
+    frHeader,                 # type has an object type field only in the header
+    frEmbedded                # type has an object type field somewhere embedded
+
+proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
+  # this does a complex analysis whether a call to ``objectInit`` needs to be
+  # made or intializing of the type field suffices or if there is no type field
+  # at all in this type.
+
+proc invalidGenericInst(f: PType): bool =
+  result = f.kind == tyGenericInst and lastSon(f) == nil
+
+proc isPureObject(typ: PType): bool =
+  var t = typ
+  while t.kind == tyObject and t.sons[0] != nil: t = t.sons[0]
+  result = t.sym != nil and sfPure in t.sym.flags
+
+proc getOrdValue(n: PNode): BiggestInt =
+  case n.kind
+  of nkCharLit..nkUInt64Lit: result = n.intVal
+  of nkNilLit: result = 0
+  of nkHiddenStdConv: result = getOrdValue(n.sons[1])
+  else:
+    localError(n.info, errOrdinalTypeExpected)
+    result = 0
+
+proc isIntLit*(t: PType): bool {.inline.} =
+  result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
+
+proc isFloatLit*(t: PType): bool {.inline.} =
+  result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
+
+proc isCompatibleToCString(a: PType): bool =
+  if a.kind == tyArray:
+    if (firstOrd(a.sons[0]) == 0) and
+        (skipTypes(a.sons[0], {tyRange, tyConst,
+                               tyMutable, tyGenericInst}).kind in
+            {tyInt..tyInt64, tyUInt..tyUInt64}) and
+        (a.sons[1].kind == tyChar):
+      result = true
+
+proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
+  result = sym.owner.name.s & '.' & sym.name.s & '('
+  var n = sym.typ.n
+  for i in countup(1, sonsLen(n) - 1):
+    var p = n.sons[i]
+    if p.kind == nkSym:
+      add(result, p.sym.name.s)
+      add(result, ": ")
+      add(result, typeToString(p.sym.typ, prefer))
+      if i != sonsLen(n)-1: add(result, ", ")
+    else:
+      internalError("getProcHeader")
+  add(result, ')')
+  if n.sons[0].typ != nil:
+    result.add(": " & typeToString(n.sons[0].typ, prefer))
+
+proc elemType*(t: PType): PType =
+  assert(t != nil)
+  case t.kind
+  of tyGenericInst, tyDistinct: result = elemType(lastSon(t))
+  of tyArray, tyArrayConstr: result = t.sons[1]
+  else: result = t.lastSon
+  assert(result != nil)
+
+proc skipGeneric(t: PType): PType =
+  result = t
+  while result.kind == tyGenericInst: result = lastSon(result)
+
+proc isOrdinalType(t: PType): bool =
+  assert(t != nil)
+  # caution: uint, uint64 are no ordinal types!
+  result = t.kind in {tyChar,tyInt..tyInt64,tyUInt8..tyUInt32,tyBool,tyEnum} or
+      (t.kind in {tyRange, tyOrdinal, tyConst, tyMutable, tyGenericInst}) and
+       isOrdinalType(t.sons[0])
+
+proc enumHasHoles(t: PType): bool =
+  var b = t
+  while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0]
+  result = b.kind == tyEnum and tfEnumHasHoles in b.flags
+
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
+                     closure: RootRef): bool
+proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter,
+                  closure: RootRef): bool =
+  if n != nil:
+    case n.kind
+    of nkNone..nkNilLit:
+      # a leaf
+      result = iterOverTypeAux(marker, n.typ, iter, closure)
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        result = iterOverNode(marker, n.sons[i], iter, closure)
+        if result: return
+
+proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter,
+                     closure: RootRef): bool =
+  result = false
+  if t == nil: return
+  result = iter(t, closure)
+  if result: return
+  if not containsOrIncl(marker, t.id):
+    case t.kind
+    of tyGenericInst, tyGenericBody:
+      result = iterOverTypeAux(marker, lastSon(t), iter, closure)
+    else:
+      for i in countup(0, sonsLen(t) - 1):
+        result = iterOverTypeAux(marker, t.sons[i], iter, closure)
+        if result: return
+      if t.n != nil: result = iterOverNode(marker, t.n, iter, closure)
+
+proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool =
+  var marker = initIntSet()
+  result = iterOverTypeAux(marker, t, iter, closure)
+
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
+                      marker: var IntSet): bool
+
+proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
+                          marker: var IntSet): bool =
+  result = false
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      result = searchTypeNodeForAux(n.sons[i], p, marker)
+      if result: return
+  of nkRecCase:
+    assert(n.sons[0].kind == nkSym)
+    result = searchTypeNodeForAux(n.sons[0], p, marker)
+    if result: return
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
+        if result: return
+      else: internalError("searchTypeNodeForAux(record case branch)")
+  of nkSym:
+    result = searchTypeForAux(n.sym.typ, p, marker)
+  else: internalError(n.info, "searchTypeNodeForAux()")
+
+proc searchTypeForAux(t: PType, predicate: TTypePredicate,
+                      marker: var IntSet): bool =
+  # iterates over VALUE types!
+  result = false
+  if t == nil: return
+  if containsOrIncl(marker, t.id): return
+  result = predicate(t)
+  if result: return
+  case t.kind
+  of tyObject:
+    result = searchTypeForAux(t.sons[0], predicate, marker)
+    if not result: result = searchTypeNodeForAux(t.n, predicate, marker)
+  of tyGenericInst, tyDistinct:
+    result = searchTypeForAux(lastSon(t), predicate, marker)
+  of tyArray, tyArrayConstr, tySet, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
+      result = searchTypeForAux(t.sons[i], predicate, marker)
+      if result: return
+  else:
+    discard
+
+proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
+  var marker = initIntSet()
+  result = searchTypeForAux(t, predicate, marker)
+
+proc isObjectPredicate(t: PType): bool =
+  result = t.kind == tyObject
+
+proc containsObject(t: PType): bool =
+  result = searchTypeFor(t, isObjectPredicate)
+
+proc isObjectWithTypeFieldPredicate(t: PType): bool =
+  result = t.kind == tyObject and t.sons[0] == nil and
+      not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
+      tfFinal notin t.flags
+
+proc analyseObjectWithTypeFieldAux(t: PType,
+                                   marker: var IntSet): TTypeFieldResult =
+  var res: TTypeFieldResult
+  result = frNone
+  if t == nil: return
+  case t.kind
+  of tyObject:
+    if (t.n != nil):
+      if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
+        return frEmbedded
+    for i in countup(0, sonsLen(t) - 1):
+      res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
+      if res == frEmbedded:
+        return frEmbedded
+      if res == frHeader: result = frHeader
+    if result == frNone:
+      if isObjectWithTypeFieldPredicate(t): result = frHeader
+  of tyGenericInst, tyDistinct, tyConst, tyMutable:
+    result = analyseObjectWithTypeFieldAux(lastSon(t), marker)
+  of tyArray, tyArrayConstr, tyTuple:
+    for i in countup(0, sonsLen(t) - 1):
+      res = analyseObjectWithTypeFieldAux(t.sons[i], marker)
+      if res != frNone:
+        return frEmbedded
+  else:
+    discard
+
+proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
+  var marker = initIntSet()
+  result = analyseObjectWithTypeFieldAux(t, marker)
+
+proc isGCRef(t: PType): bool =
+  result = t.kind in GcTypeKinds or
+    (t.kind == tyProc and t.callConv == ccClosure)
+
+proc containsGarbageCollectedRef(typ: PType): bool =
+  # returns true if typ contains a reference, sequence or string (all the
+  # things that are garbage-collected)
+  result = searchTypeFor(typ, isGCRef)
+
+proc isTyRef(t: PType): bool =
+  result = t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure)
+
+proc containsTyRef*(typ: PType): bool =
+  # returns true if typ contains a 'ref'
+  result = searchTypeFor(typ, isTyRef)
+
+proc isHiddenPointer(t: PType): bool =
+  result = t.kind in {tyString, tySequence}
+
+proc containsHiddenPointer(typ: PType): bool =
+  # returns true if typ contains a string, table or sequence (all the things
+  # that need to be copied deeply)
+  result = searchTypeFor(typ, isHiddenPointer)
+
+proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool
+proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool =
+  result = false
+  if n != nil:
+    result = canFormAcycleAux(marker, n.typ, startId)
+    if not result:
+      case n.kind
+      of nkNone..nkNilLit:
+        discard
+      else:
+        for i in countup(0, sonsLen(n) - 1):
+          result = canFormAcycleNode(marker, n.sons[i], startId)
+          if result: return
+
+proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
+  result = false
+  if typ == nil: return
+  if tfAcyclic in typ.flags: return
+  var t = skipTypes(typ, abstractInst-{tyTypeDesc})
+  if tfAcyclic in t.flags: return
+  case t.kind
+  of tyTuple, tyObject, tyRef, tySequence, tyArray, tyArrayConstr, tyOpenArray,
+     tyVarargs:
+    if not containsOrIncl(marker, t.id):
+      for i in countup(0, sonsLen(t) - 1):
+        result = canFormAcycleAux(marker, t.sons[i], startId)
+        if result: return
+      if t.n != nil: result = canFormAcycleNode(marker, t.n, startId)
+    else:
+      result = t.id == startId
+    # Inheritance can introduce cyclic types, however this is not relevant
+    # as the type that is passed to 'new' is statically known!
+    # er but we use it also for the write barrier ...
+    if t.kind == tyObject and tfFinal notin t.flags:
+      # damn inheritance may introduce cycles:
+      result = true
+  of tyProc: result = typ.callConv == ccClosure
+  else: discard
+
+proc canFormAcycle(typ: PType): bool =
+  var marker = initIntSet()
+  result = canFormAcycleAux(marker, typ, typ.id)
+
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
+                   closure: RootRef): PType
+proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator,
+                closure: RootRef): PNode =
+  result = nil
+  if n != nil:
+    result = copyNode(n)
+    result.typ = mutateTypeAux(marker, n.typ, iter, closure)
+    case n.kind
+    of nkNone..nkNilLit:
+      # a leaf
+      discard
+    else:
+      for i in countup(0, sonsLen(n) - 1):
+        addSon(result, mutateNode(marker, n.sons[i], iter, closure))
+
+proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator,
+                   closure: RootRef): PType =
+  result = nil
+  if t == nil: return
+  result = iter(t, closure)
+  if not containsOrIncl(marker, t.id):
+    for i in countup(0, sonsLen(t) - 1):
+      result.sons[i] = mutateTypeAux(marker, result.sons[i], iter, closure)
+    if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure)
+  assert(result != nil)
+
+proc mutateType(t: PType, iter: TTypeMutator, closure: RootRef): PType =
+  var marker = initIntSet()
+  result = mutateTypeAux(marker, t, iter, closure)
+
+proc valueToString(a: PNode): string =
+  case a.kind
+  of nkCharLit..nkUInt64Lit: result = $a.intVal
+  of nkFloatLit..nkFloat128Lit: result = $a.floatVal
+  of nkStrLit..nkTripleStrLit: result = a.strVal
+  else: result = "<invalid value>"
+
+proc rangeToStr(n: PNode): string =
+  assert(n.kind == nkRange)
+  result = valueToString(n.sons[0]) & ".." & valueToString(n.sons[1])
+
+const
+  typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
+    "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
+    "GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
+    "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
+    "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
+    "pointer", "OpenArray[$1]", "string", "CString", "Forward",
+    "int", "int8", "int16", "int32", "int64",
+    "float", "float32", "float64", "float128",
+    "uint", "uint8", "uint16", "uint32", "uint64",
+    "bignum", "const ",
+    "!", "varargs[$1]", "iter[$1]", "Error Type",
+    "BuiltInTypeClass", "UserTypeClass",
+    "UserTypeClassInst", "CompositeTypeClass",
+    "and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor"]
+
+const preferToResolveSymbols = {preferName, preferModuleInfo, preferGenericArg}
+
+proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
+  var t = typ
+  result = ""
+  if t == nil: return
+  if prefer in preferToResolveSymbols and t.sym != nil and
+       sfAnon notin t.sym.flags:
+    if t.kind == tyInt and isIntLit(t):
+      return t.sym.name.s & " literal(" & $t.n.intVal & ")"
+    if prefer == preferName or t.sym.owner.isNil:
+      return t.sym.name.s
+    else:
+      return t.sym.owner.name.s & '.' & t.sym.name.s
+  case t.kind
+  of tyInt:
+    if not isIntLit(t) or prefer == preferExported:
+      result = typeToStr[t.kind]
+    else:
+      if prefer == preferGenericArg:
+        result = $t.n.intVal
+      else:
+        result = "int literal(" & $t.n.intVal & ")"
+  of tyGenericBody, tyGenericInst, tyGenericInvocation:
+    result = typeToString(t.sons[0]) & '['
+    for i in countup(1, sonsLen(t)-1-ord(t.kind != tyGenericInvocation)):
+      if i > 1: add(result, ", ")
+      add(result, typeToString(t.sons[i], preferGenericArg))
+    add(result, ']')
+  of tyTypeDesc:
+    if t.base.kind == tyNone: result = "typedesc"
+    else: result = "typedesc[" & typeToString(t.base) & "]"
+  of tyStatic:
+    internalAssert t.len > 0
+    if prefer == preferGenericArg and t.n != nil:
+      result = t.n.renderTree
+    else:
+      result = "static[" & typeToString(t.sons[0]) & "]"
+      if t.n != nil: result.add "(" & renderTree(t.n) & ")"
+  of tyUserTypeClass:
+    internalAssert t.sym != nil and t.sym.owner != nil
+    return t.sym.owner.name.s
+  of tyBuiltInTypeClass:
+    result = case t.base.kind:
+      of tyVar: "var"
+      of tyRef: "ref"
+      of tyPtr: "ptr"
+      of tySequence: "seq"
+      of tyArray: "array"
+      of tySet: "set"
+      of tyRange: "range"
+      of tyDistinct: "distinct"
+      of tyProc: "proc"
+      of tyObject: "object"
+      of tyTuple: "tuple"
+      of tyOpenArray: "openarray"
+      else: typeToStr[t.base.kind]
+  of tyUserTypeClassInst:
+    let body = t.base
+    result = body.sym.name.s & "["
+    for i in countup(1, sonsLen(t) - 2):
+      if i > 1: add(result, ", ")
+      add(result, typeToString(t.sons[i]))
+    result.add "]"
+  of tyAnd:
+    result = typeToString(t.sons[0]) & " and " & typeToString(t.sons[1])
+  of tyOr:
+    result = typeToString(t.sons[0]) & " or " & typeToString(t.sons[1])
+  of tyNot:
+    result = "not " & typeToString(t.sons[0])
+  of tyExpr:
+    internalAssert t.len == 0
+    result = "expr"
+  of tyFromExpr, tyFieldAccessor:
+    result = renderTree(t.n)
+  of tyArray:
+    if t.sons[0].kind == tyRange:
+      result = "array[" & rangeToStr(t.sons[0].n) & ", " &
+          typeToString(t.sons[1]) & ']'
+    else:
+      result = "array[" & typeToString(t.sons[0]) & ", " &
+          typeToString(t.sons[1]) & ']'
+  of tyArrayConstr:
+    result = "Array constructor[" & rangeToStr(t.sons[0].n) & ", " &
+        typeToString(t.sons[1]) & ']'
+  of tySequence:
+    result = "seq[" & typeToString(t.sons[0]) & ']'
+  of tyOrdinal:
+    result = "ordinal[" & typeToString(t.sons[0]) & ']'
+  of tySet:
+    result = "set[" & typeToString(t.sons[0]) & ']'
+  of tyOpenArray:
+    result = "openarray[" & typeToString(t.sons[0]) & ']'
+  of tyDistinct:
+    result = "distinct " & typeToString(t.sons[0],
+      if prefer == preferModuleInfo: preferModuleInfo else: preferName)
+  of tyTuple:
+    # we iterate over t.sons here, because t.n may be nil
+    if t.n != nil:
+      result = "tuple["
+      assert(sonsLen(t.n) == sonsLen(t))
+      for i in countup(0, sonsLen(t.n) - 1):
+        assert(t.n.sons[i].kind == nkSym)
+        add(result, t.n.sons[i].sym.name.s & ": " & typeToString(t.sons[i]))
+        if i < sonsLen(t.n) - 1: add(result, ", ")
+      add(result, ']')
+    elif sonsLen(t) == 0:
+      result = "tuple[]"
+    else:
+      result = "("
+      for i in countup(0, sonsLen(t) - 1):
+        add(result, typeToString(t.sons[i]))
+        if i < sonsLen(t) - 1: add(result, ", ")
+      add(result, ')')
+  of tyPtr, tyRef, tyVar, tyMutable, tyConst:
+    result = typeToStr[t.kind]
+    if t.len >= 2:
+      setLen(result, result.len-1)
+      result.add '['
+      for i in countup(0, sonsLen(t) - 1):
+        add(result, typeToString(t.sons[i]))
+        if i < sonsLen(t) - 1: add(result, ", ")
+      result.add ']'
+    else:
+      result.add typeToString(t.sons[0])
+  of tyRange:
+    result = "range " & rangeToStr(t.n)
+    if prefer != preferExported:
+      result.add("(" & typeToString(t.sons[0]) & ")")
+  of tyProc:
+    result = if tfIterator in t.flags: "iterator (" else: "proc ("
+    for i in countup(1, sonsLen(t) - 1):
+      if t.n != nil and i < t.n.len and t.n[i].kind == nkSym:
+        add(result, t.n[i].sym.name.s)
+        add(result, ": ")
+      add(result, typeToString(t.sons[i]))
+      if i < sonsLen(t) - 1: add(result, ", ")
+    add(result, ')')
+    if t.sons[0] != nil: add(result, ": " & typeToString(t.sons[0]))
+    var prag = if t.callConv == ccDefault: "" else: CallingConvToStr[t.callConv]
+    if tfNoSideEffect in t.flags:
+      addSep(prag)
+      add(prag, "noSideEffect")
+    if tfThread in t.flags:
+      addSep(prag)
+      add(prag, "gcsafe")
+    if t.lockLevel.ord != UnspecifiedLockLevel.ord:
+      addSep(prag)
+      add(prag, "locks: " & $t.lockLevel)
+    if len(prag) != 0: add(result, "{." & prag & ".}")
+  of tyVarargs, tyIter:
+    result = typeToStr[t.kind] % typeToString(t.sons[0])
+  else:
+    result = typeToStr[t.kind]
+  if tfShared in t.flags: result = "shared " & result
+  if tfNotNil in t.flags: result.add(" not nil")
+
+proc resultType(t: PType): PType =
+  assert(t.kind == tyProc)
+  result = t.sons[0]          # nil is allowed
+
+proc base(t: PType): PType =
+  result = t.sons[0]
+
+proc firstOrd(t: PType): BiggestInt =
+  case t.kind
+  of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
+    result = 0
+  of tySet, tyVar: result = firstOrd(t.sons[0])
+  of tyArray, tyArrayConstr: result = firstOrd(t.sons[0])
+  of tyRange:
+    assert(t.n != nil)        # range directly given:
+    assert(t.n.kind == nkRange)
+    result = getOrdValue(t.n.sons[0])
+  of tyInt:
+    if platform.intSize == 4: result = - (2147483646) - 2
+    else: result = 0x8000000000000000'i64
+  of tyInt8: result = - 128
+  of tyInt16: result = - 32768
+  of tyInt32: result = - 2147483646 - 2
+  of tyInt64: result = 0x8000000000000000'i64
+  of tyUInt..tyUInt64: result = 0
+  of tyEnum:
+    # if basetype <> nil then return firstOrd of basetype
+    if sonsLen(t) > 0 and t.sons[0] != nil:
+      result = firstOrd(t.sons[0])
+    else:
+      assert(t.n.sons[0].kind == nkSym)
+      result = t.n.sons[0].sym.position
+  of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor:
+    result = firstOrd(lastSon(t))
+  of tyOrdinal:
+    if t.len > 0: result = firstOrd(lastSon(t))
+    else: internalError("invalid kind for first(" & $t.kind & ')')
+  else:
+    internalError("invalid kind for first(" & $t.kind & ')')
+    result = 0
+
+proc lastOrd(t: PType): BiggestInt =
+  case t.kind
+  of tyBool: result = 1
+  of tyChar: result = 255
+  of tySet, tyVar: result = lastOrd(t.sons[0])
+  of tyArray, tyArrayConstr: result = lastOrd(t.sons[0])
+  of tyRange:
+    assert(t.n != nil)        # range directly given:
+    assert(t.n.kind == nkRange)
+    result = getOrdValue(t.n.sons[1])
+  of tyInt:
+    if platform.intSize == 4: result = 0x7FFFFFFF
+    else: result = 0x7FFFFFFFFFFFFFFF'i64
+  of tyInt8: result = 0x0000007F
+  of tyInt16: result = 0x00007FFF
+  of tyInt32: result = 0x7FFFFFFF
+  of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
+  of tyUInt:
+    if platform.intSize == 4: result = 0xFFFFFFFF
+    else: result = 0x7FFFFFFFFFFFFFFF'i64
+  of tyUInt8: result = 0xFF
+  of tyUInt16: result = 0xFFFF
+  of tyUInt32: result = 0xFFFFFFFF
+  of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64
+  of tyEnum:
+    assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
+    result = t.n.sons[sonsLen(t.n) - 1].sym.position
+  of tyGenericInst, tyDistinct, tyConst, tyMutable,
+     tyTypeDesc, tyFieldAccessor:
+    result = lastOrd(lastSon(t))
+  of tyProxy: result = 0
+  of tyOrdinal:
+    if t.len > 0: result = lastOrd(lastSon(t))
+    else: internalError("invalid kind for last(" & $t.kind & ')')
+  else:
+    internalError("invalid kind for last(" & $t.kind & ')')
+    result = 0
+
+proc lengthOrd(t: PType): BiggestInt =
+  case t.kind
+  of tyInt64, tyInt32, tyInt: result = lastOrd(t)
+  of tyDistinct, tyConst, tyMutable: result = lengthOrd(t.sons[0])
+  else: result = lastOrd(t) - firstOrd(t) + 1
+
+# -------------- type equality -----------------------------------------------
+
+type
+  TDistinctCompare* = enum ## how distinct types are to be compared
+    dcEq,                  ## a and b should be the same type
+    dcEqIgnoreDistinct,    ## compare symmetrically: (distinct a) == b, a == b
+                           ## or a == (distinct b)
+    dcEqOrDistinctOf       ## a equals b or a is distinct of b
+
+  TTypeCmpFlag* = enum
+    IgnoreTupleFields      ## NOTE: Only set this flag for backends!
+    IgnoreCC
+    ExactTypeDescValues
+    ExactGenericParams
+    ExactConstraints
+    AllowCommonBase
+
+  TTypeCmpFlags* = set[TTypeCmpFlag]
+
+  TSameTypeClosure = object {.pure.}
+    cmp: TDistinctCompare
+    recCheck: int
+    flags: TTypeCmpFlags
+    s: seq[tuple[a,b: int]] # seq for a set as it's hopefully faster
+                            # (few elements expected)
+
+proc initSameTypeClosure: TSameTypeClosure =
+  # we do the initialization lazily for performance (avoids memory allocations)
+  discard
+
+proc containsOrIncl(c: var TSameTypeClosure, a, b: PType): bool =
+  result = not isNil(c.s) and c.s.contains((a.id, b.id))
+  if not result:
+    if isNil(c.s): c.s = @[]
+    c.s.add((a.id, b.id))
+
+proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool
+proc sameTypeOrNilAux(a, b: PType, c: var TSameTypeClosure): bool =
+  if a == b:
+    result = true
+  else:
+    if a == nil or b == nil: result = false
+    else: result = sameTypeAux(a, b, c)
+
+proc sameType*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
+  var c = initSameTypeClosure()
+  c.flags = flags
+  result = sameTypeAux(a, b, c)
+
+proc sameTypeOrNil*(a, b: PType, flags: TTypeCmpFlags = {}): bool =
+  if a == b:
+    result = true
+  else:
+    if a == nil or b == nil: result = false
+    else: result = sameType(a, b, flags)
+
+proc equalParam(a, b: PSym): TParamsEquality =
+  if sameTypeOrNil(a.typ, b.typ, {ExactTypeDescValues}) and
+      exprStructuralEquivalent(a.constraint, b.constraint):
+    if a.ast == b.ast:
+      result = paramsEqual
+    elif a.ast != nil and b.ast != nil:
+      if exprStructuralEquivalent(a.ast, b.ast): result = paramsEqual
+      else: result = paramsIncompatible
+    elif a.ast != nil:
+      result = paramsEqual
+    elif b.ast != nil:
+      result = paramsIncompatible
+  else:
+    result = paramsNotEqual
+
+proc sameConstraints(a, b: PNode): bool =
+  internalAssert a.len == b.len
+  for i in 1 .. <a.len:
+    if not exprStructuralEquivalent(a[i].sym.constraint,
+                                    b[i].sym.constraint):
+      return false
+  return true
+
+proc equalParams(a, b: PNode): TParamsEquality =
+  result = paramsEqual
+  var length = sonsLen(a)
+  if length != sonsLen(b):
+    result = paramsNotEqual
+  else:
+    for i in countup(1, length - 1):
+      var m = a.sons[i].sym
+      var n = b.sons[i].sym
+      assert((m.kind == skParam) and (n.kind == skParam))
+      case equalParam(m, n)
+      of paramsNotEqual:
+        return paramsNotEqual
+      of paramsEqual:
+        discard
+      of paramsIncompatible:
+        result = paramsIncompatible
+      if (m.name.id != n.name.id):
+        # BUGFIX
+        return paramsNotEqual # paramsIncompatible;
+      # continue traversal! If not equal, we can return immediately; else
+      # it stays incompatible
+    if not sameTypeOrNil(a.sons[0].typ, b.sons[0].typ, {ExactTypeDescValues}):
+      if (a.sons[0].typ == nil) or (b.sons[0].typ == nil):
+        result = paramsNotEqual # one proc has a result, the other not is OK
+      else:
+        result = paramsIncompatible # overloading by different
+                                    # result types does not work
+
+proc sameLiteral(x, y: PNode): bool =
+  if x.kind == y.kind:
+    case x.kind
+    of nkCharLit..nkInt64Lit: result = x.intVal == y.intVal
+    of nkFloatLit..nkFloat64Lit: result = x.floatVal == y.floatVal
+    of nkNilLit: result = true
+    else: assert(false)
+
+proc sameRanges(a, b: PNode): bool =
+  result = sameLiteral(a.sons[0], b.sons[0]) and
+           sameLiteral(a.sons[1], b.sons[1])
+
+proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
+  # two tuples are equivalent iff the names, types and positions are the same;
+  # however, both types may not have any field names (t.n may be nil) which
+  # complicates the matter a bit.
+  if sonsLen(a) == sonsLen(b):
+    result = true
+    for i in countup(0, sonsLen(a) - 1):
+      var x = a.sons[i]
+      var y = b.sons[i]
+      if IgnoreTupleFields in c.flags:
+        x = skipTypes(x, {tyRange, tyGenericInst})
+        y = skipTypes(y, {tyRange, tyGenericInst})
+
+      result = sameTypeAux(x, y, c)
+      if not result: return
+    if a.n != nil and b.n != nil and IgnoreTupleFields notin c.flags:
+      for i in countup(0, sonsLen(a.n) - 1):
+        # check field names:
+        if a.n.sons[i].kind == nkSym and b.n.sons[i].kind == nkSym:
+          var x = a.n.sons[i].sym
+          var y = b.n.sons[i].sym
+          result = x.name.id == y.name.id
+          if not result: break
+        else: internalError(a.n.info, "sameTuple")
+
+template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
+  if tfFromGeneric notin a.flags + b.flags:
+    # fast case: id comparison suffices:
+    result = a.id == b.id
+  else:
+    # expensive structural equality test; however due to the way generic and
+    # objects work, if one of the types does **not** contain tfFromGeneric,
+    # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks
+    # for the same origin and is essential because we don't want "pure"
+    # structural type equivalence:
+    #
+    # type
+    #   TA[T] = object
+    #   TB[T] = object
+    # --> TA[int] != TB[int]
+    if tfFromGeneric in a.flags * b.flags and a.sym.id == b.sym.id:
+      # ok, we need the expensive structural check
+      body
+
+proc sameObjectTypes*(a, b: PType): bool =
+  # specialized for efficiency (sigmatch uses it)
+  ifFastObjectTypeCheckFailed(a, b):
+    var c = initSameTypeClosure()
+    result = sameTypeAux(a, b, c)
+
+proc sameDistinctTypes*(a, b: PType): bool {.inline.} =
+  result = sameObjectTypes(a, b)
+
+proc sameEnumTypes*(a, b: PType): bool {.inline.} =
+  result = a.id == b.id
+
+proc sameObjectTree(a, b: PNode, c: var TSameTypeClosure): bool =
+  if a == b:
+    result = true
+  elif a != nil and b != nil and a.kind == b.kind:
+    var x = a.typ
+    var y = b.typ
+    if IgnoreTupleFields in c.flags:
+      if x != nil: x = skipTypes(x, {tyRange, tyGenericInst})
+      if y != nil: y = skipTypes(y, {tyRange, tyGenericInst})
+    if sameTypeOrNilAux(x, y, c):
+      case a.kind
+      of nkSym:
+        # same symbol as string is enough:
+        result = a.sym.name.id == b.sym.name.id
+      of nkIdent: result = a.ident.id == b.ident.id
+      of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
+      of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+      of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+      of nkEmpty, nkNilLit, nkType: result = true
+      else:
+        if sonsLen(a) == sonsLen(b):
+          for i in countup(0, sonsLen(a) - 1):
+            if not sameObjectTree(a.sons[i], b.sons[i], c): return
+          result = true
+
+proc sameObjectStructures(a, b: PType, c: var TSameTypeClosure): bool =
+  # check base types:
+  if sonsLen(a) != sonsLen(b): return
+  for i in countup(0, sonsLen(a) - 1):
+    if not sameTypeOrNilAux(a.sons[i], b.sons[i], c): return
+  if not sameObjectTree(a.n, b.n, c): return
+  result = true
+
+proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
+  if sonsLen(a) != sonsLen(b): return false
+  result = true
+  for i in countup(0, sonsLen(a) - 1):
+    result = sameTypeOrNilAux(a.sons[i], b.sons[i], c)
+    if not result: return
+
+proc isGenericAlias*(t: PType): bool =
+  return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst
+
+proc skipGenericAlias*(t: PType): PType =
+  return if t.isGenericAlias: t.lastSon else: t
+
+proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
+  template cycleCheck() =
+    # believe it or not, the direct check for ``containsOrIncl(c, a, b)``
+    # increases bootstrapping time from 2.4s to 3.3s on my laptop! So we cheat
+    # again: Since the recursion check is only to not get caught in an endless
+    # recursion, we use a counter and only if it's value is over some
+    # threshold we perform the expensive exact cycle check:
+    if c.recCheck < 3:
+      inc c.recCheck
+    else:
+      if containsOrIncl(c, a, b): return true
+
+  proc sameFlags(a, b: PType): bool {.inline.} =
+    result = eqTypeFlags*a.flags == eqTypeFlags*b.flags
+
+  if x == y: return true
+  var a = skipTypes(x, {tyGenericInst})
+  var b = skipTypes(y, {tyGenericInst})
+  assert(a != nil)
+  assert(b != nil)
+  if a.kind != b.kind:
+    case c.cmp
+    of dcEq: return false
+    of dcEqIgnoreDistinct:
+      while a.kind == tyDistinct: a = a.sons[0]
+      while b.kind == tyDistinct: b = b.sons[0]
+      if a.kind != b.kind: return false
+    of dcEqOrDistinctOf:
+      while a.kind == tyDistinct: a = a.sons[0]
+      if a.kind != b.kind: return false
+
+  if x.kind == tyGenericInst:
+    let
+      lhs = x.skipGenericAlias
+      rhs = y.skipGenericAlias
+    if rhs.kind != tyGenericInst or lhs.base != rhs.base:
+      return false
+    for i in 1 .. lhs.len - 2:
+      let ff = rhs.sons[i]
+      let aa = lhs.sons[i]
+      if not sameTypeAux(ff, aa, c): return false
+    return true
+
+  case a.kind
+  of tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString,
+     tyInt..tyBigNum, tyStmt, tyExpr:
+    result = sameFlags(a, b)
+  of tyStatic, tyFromExpr:
+    result = exprStructuralEquivalent(a.n, b.n) and sameFlags(a, b)
+    if result and a.len == b.len and a.len == 1:
+      cycleCheck()
+      result = sameTypeAux(a.sons[0], b.sons[0], c)
+  of tyObject:
+    ifFastObjectTypeCheckFailed(a, b):
+      cycleCheck()
+      result = sameObjectStructures(a, b, c) and sameFlags(a, b)
+  of tyDistinct:
+    cycleCheck()
+    if c.cmp == dcEq:
+      if sameFlags(a, b):
+        ifFastObjectTypeCheckFailed(a, b):
+          result = sameTypeAux(a.sons[0], b.sons[0], c)
+    else:
+      result = sameTypeAux(a.sons[0], b.sons[0], c) and sameFlags(a, b)
+  of tyEnum, tyForward:
+    # XXX generic enums do not make much sense, but require structural checking
+    result = a.id == b.id and sameFlags(a, b)
+  of tyError:
+    result = b.kind == tyError
+  of tyTuple:
+    cycleCheck()
+    result = sameTuple(a, b, c) and sameFlags(a, b)
+  of tyTypeDesc:
+    if c.cmp == dcEqIgnoreDistinct: result = false
+    elif ExactTypeDescValues in c.flags:
+      cycleCheck()
+      result = sameChildrenAux(x, y, c) and sameFlags(a, b)
+    else:
+      result = sameFlags(a, b)
+  of tyGenericParam:
+    result = sameChildrenAux(a, b, c) and sameFlags(a, b)
+    if result and ExactGenericParams in c.flags:
+      result = a.sym.position == b.sym.position
+  of tyGenericInvocation, tyGenericBody, tySequence,
+     tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
+     tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
+     tyOrdinal, tyTypeClasses, tyFieldAccessor:
+    cycleCheck()
+    if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
+    result = sameChildrenAux(a, b, c) and sameFlags(a, b)
+    if result and a.kind == tyProc:
+      result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and
+               ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n))
+  of tyRange:
+    cycleCheck()
+    result = sameTypeOrNilAux(a.sons[0], b.sons[0], c) and
+        sameValue(a.n.sons[0], b.n.sons[0]) and
+        sameValue(a.n.sons[1], b.n.sons[1])
+  of tyGenericInst: discard
+  of tyNone: result = false
+
+proc sameBackendType*(x, y: PType): bool =
+  var c = initSameTypeClosure()
+  c.flags.incl IgnoreTupleFields
+  result = sameTypeAux(x, y, c)
+
+proc compareTypes*(x, y: PType,
+                   cmp: TDistinctCompare = dcEq,
+                   flags: TTypeCmpFlags = {}): bool =
+  ## compares two type for equality (modulo type distinction)
+  var c = initSameTypeClosure()
+  c.cmp = cmp
+  c.flags = flags
+  result = sameTypeAux(x, y, c)
+
+proc inheritanceDiff*(a, b: PType): int =
+  # | returns: 0 iff `a` == `b`
+  # | returns: -x iff `a` is the x'th direct superclass of `b`
+  # | returns: +x iff `a` is the x'th direct subclass of `b`
+  # | returns: `maxint` iff `a` and `b` are not compatible at all
+  if a == b or a.kind == tyError or b.kind == tyError: return 0
+  assert a.kind == tyObject
+  assert b.kind == tyObject
+  var x = a
+  result = 0
+  while x != nil:
+    x = skipTypes(x, skipPtrs)
+    if sameObjectTypes(x, b): return
+    x = x.sons[0]
+    dec(result)
+  var y = b
+  result = 0
+  while y != nil:
+    y = skipTypes(y, skipPtrs)
+    if sameObjectTypes(y, a): return
+    y = y.sons[0]
+    inc(result)
+  result = high(int)
+
+proc commonSuperclass*(a, b: PType): PType =
+  # quick check: are they the same?
+  if sameObjectTypes(a, b): return a
+
+  # simple algorithm: we store all ancestors of 'a' in a ID-set and walk 'b'
+  # up until the ID is found:
+  assert a.kind == tyObject
+  assert b.kind == tyObject
+  var x = a
+  var ancestors = initIntSet()
+  while x != nil:
+    x = skipTypes(x, skipPtrs)
+    ancestors.incl(x.id)
+    x = x.sons[0]
+  var y = b
+  while y != nil:
+    y = skipTypes(y, skipPtrs)
+    if ancestors.contains(y.id): return y
+    y = y.sons[0]
+
+type
+  TTypeAllowedFlag = enum
+    taField,
+    taHeap
+
+  TTypeAllowedFlags = set[TTypeAllowedFlag]
+
+proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
+                    flags: TTypeAllowedFlags = {}): PType
+
+proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
+                     flags: TTypeAllowedFlags = {}): PType =
+  if n != nil:
+    result = typeAllowedAux(marker, n.typ, kind, flags)
+    #if not result: debug(n.typ)
+    if result == nil:
+      case n.kind
+      of nkNone..nkNilLit:
+        discard
+      else:
+        for i in countup(0, sonsLen(n) - 1):
+          let it = n.sons[i]
+          if it.kind == nkRecCase and kind == skConst: return n.typ
+          result = typeAllowedNode(marker, it, kind, flags)
+          if result != nil: break
+
+proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
+                last: TTypeKind): bool =
+  var a = a
+  for k, i in pattern.items:
+    if a.kind != k: return false
+    if i >= a.sonsLen or a.sons[i] == nil: return false
+    a = a.sons[i]
+  result = a.kind == last
+
+proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
+                    flags: TTypeAllowedFlags = {}): PType =
+  assert(kind in {skVar, skLet, skConst, skParam, skResult})
+  # if we have already checked the type, return true, because we stop the
+  # evaluation if something is wrong:
+  result = nil
+  if typ == nil: return
+  if containsOrIncl(marker, typ.id): return
+  var t = skipTypes(typ, abstractInst-{tyTypeDesc})
+  case t.kind
+  of tyVar:
+    if kind == skConst: return t
+    var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
+    case t2.kind
+    of tyVar:
+      if taHeap notin flags: result = t2 # ``var var`` is illegal on the heap
+    of tyOpenArray:
+      if kind != skParam: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
+    else:
+      if kind notin {skParam, skResult}: result = t
+      else: result = typeAllowedAux(marker, t2, kind, flags)
+  of tyProc:
+    for i in countup(1, sonsLen(t) - 1):
+      result = typeAllowedAux(marker, t.sons[i], skParam, flags)
+      if result != nil: break
+    if result.isNil and t.sons[0] != nil:
+      result = typeAllowedAux(marker, t.sons[0], skResult, flags)
+  of tyTypeDesc:
+    # XXX: This is still a horrible idea...
+    result = nil
+  of tyExpr, tyStmt, tyStatic:
+    if kind notin {skParam, skResult}: result = t
+  of tyEmpty:
+    if taField notin flags: result = t
+  of tyTypeClasses:
+    if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
+  of tyGenericBody, tyGenericParam, tyGenericInvocation,
+     tyNone, tyForward, tyFromExpr, tyFieldAccessor:
+    result = t
+  of tyNil:
+    if kind != skConst: result = t
+  of tyString, tyBool, tyChar, tyEnum, tyInt..tyBigNum, tyCString, tyPointer:
+    result = nil
+  of tyOrdinal:
+    if kind != skParam: result = t
+  of tyGenericInst, tyDistinct:
+    result = typeAllowedAux(marker, lastSon(t), kind, flags)
+  of tyRange:
+    if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
+        {tyChar, tyEnum, tyInt..tyFloat128, tyUInt8..tyUInt32}: result = t
+  of tyOpenArray, tyVarargs:
+    if kind != skParam: result = t
+    else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
+  of tySequence:
+    if t.sons[0].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
+  of tyArray:
+    if t.sons[1].kind != tyEmpty:
+      result = typeAllowedAux(marker, t.sons[1], skVar, flags)
+  of tyRef:
+    if kind == skConst: result = t
+    else: result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
+  of tyPtr:
+    result = typeAllowedAux(marker, t.lastSon, skVar, flags+{taHeap})
+  of tyArrayConstr, tySet, tyConst, tyMutable, tyIter:
+    for i in countup(0, sonsLen(t) - 1):
+      result = typeAllowedAux(marker, t.sons[i], kind, flags)
+      if result != nil: break
+  of tyObject, tyTuple:
+    if kind == skConst and t.kind == tyObject and t.sons[0] != nil: return t
+    let flags = flags+{taField}
+    for i in countup(0, sonsLen(t) - 1):
+      result = typeAllowedAux(marker, t.sons[i], kind, flags)
+      if result != nil: break
+    if result.isNil and t.n != nil:
+      result = typeAllowedNode(marker, t.n, kind, flags)
+  of tyProxy:
+    # for now same as error node; we say it's a valid type as it should
+    # prevent cascading errors:
+    result = nil
+
+proc typeAllowed*(t: PType, kind: TSymKind): PType =
+  # returns 'nil' on success and otherwise the part of the type that is
+  # wrong!
+  var marker = initIntSet()
+  result = typeAllowedAux(marker, t, kind, {})
+
+proc align(address, alignment: BiggestInt): BiggestInt =
+  result = (address + (alignment - 1)) and not (alignment - 1)
+
+const
+  szNonConcreteType* = -3
+  szIllegalRecursion* = -2
+  szUnknownSize* = -1
+
+proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt
+proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
+  var maxAlign, maxSize, b, res: BiggestInt
+  case n.kind
+  of nkRecCase:
+    assert(n.sons[0].kind == nkSym)
+    result = computeRecSizeAux(n.sons[0], a, currOffset)
+    maxSize = 0
+    maxAlign = 1
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        res = computeRecSizeAux(lastSon(n.sons[i]), b, currOffset)
+        if res < 0: return res
+        maxSize = max(maxSize, res)
+        maxAlign = max(maxAlign, b)
+      else: internalError("computeRecSizeAux(record case branch)")
+    currOffset = align(currOffset, maxAlign) + maxSize
+    result = align(result, maxAlign) + maxSize
+    a = maxAlign
+  of nkRecList:
+    result = 0
+    maxAlign = 1
+    for i in countup(0, sonsLen(n) - 1):
+      res = computeRecSizeAux(n.sons[i], b, currOffset)
+      if res < 0: return res
+      currOffset = align(currOffset, b) + res
+      result = align(result, b) + res
+      if b > maxAlign: maxAlign = b
+    a = maxAlign
+  of nkSym:
+    result = computeSizeAux(n.sym.typ, a)
+    n.sym.offset = int(currOffset)
+  else:
+    a = 1
+    result = szNonConcreteType
+
+proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
+  var res, maxAlign, length, currOffset: BiggestInt
+  if typ.size == szIllegalRecursion:
+    # we are already computing the size of the type
+    # --> illegal recursion in type
+    return szIllegalRecursion
+  if typ.size >= 0:
+    # size already computed
+    result = typ.size
+    a = typ.align
+    return
+  typ.size = szIllegalRecursion # mark as being computed
+  case typ.kind
+  of tyInt, tyUInt:
+    result = intSize
+    a = result
+  of tyInt8, tyUInt8, tyBool, tyChar:
+    result = 1
+    a = result
+  of tyInt16, tyUInt16:
+    result = 2
+    a = result
+  of tyInt32, tyUInt32, tyFloat32:
+    result = 4
+    a = result
+  of tyInt64, tyUInt64, tyFloat64:
+    result = 8
+    a = result
+  of tyFloat128:
+    result = 16
+    a = result
+  of tyFloat:
+    result = floatSize
+    a = result
+  of tyProc:
+    if typ.callConv == ccClosure: result = 2 * ptrSize
+    else: result = ptrSize
+    a = ptrSize
+  of tyNil, tyCString, tyString, tySequence, tyPtr, tyRef, tyVar, tyOpenArray,
+     tyBigNum:
+    let base = typ.lastSon
+    if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion):
+      result = szIllegalRecursion
+    else: result = ptrSize
+    a = result
+  of tyArray, tyArrayConstr:
+    let elemSize = computeSizeAux(typ.sons[1], a)
+    if elemSize < 0: return elemSize
+    result = lengthOrd(typ.sons[0]) * elemSize
+  of tyEnum:
+    if firstOrd(typ) < 0:
+      result = 4              # use signed int32
+    else:
+      length = lastOrd(typ)   # BUGFIX: use lastOrd!
+      if length + 1 < `shl`(1, 8): result = 1
+      elif length + 1 < `shl`(1, 16): result = 2
+      elif length + 1 < `shl`(BiggestInt(1), 32): result = 4
+      else: result = 8
+    a = result
+  of tySet:
+    length = lengthOrd(typ.sons[0])
+    if length <= 8: result = 1
+    elif length <= 16: result = 2
+    elif length <= 32: result = 4
+    elif length <= 64: result = 8
+    elif align(length, 8) mod 8 == 0: result = align(length, 8) div 8
+    else: result = align(length, 8) div 8 + 1
+    a = result
+  of tyRange:
+    result = computeSizeAux(typ.sons[0], a)
+  of tyTuple:
+    result = 0
+    maxAlign = 1
+    for i in countup(0, sonsLen(typ) - 1):
+      res = computeSizeAux(typ.sons[i], a)
+      if res < 0: return res
+      maxAlign = max(maxAlign, a)
+      result = align(result, a) + res
+    result = align(result, maxAlign)
+    a = maxAlign
+  of tyObject:
+    if typ.sons[0] != nil:
+      result = computeSizeAux(typ.sons[0], a)
+      if result < 0: return
+      maxAlign = a
+    elif isObjectWithTypeFieldPredicate(typ):
+      result = intSize
+      maxAlign = result
+    else:
+      result = 0
+      maxAlign = 1
+    currOffset = result
+    result = computeRecSizeAux(typ.n, a, currOffset)
+    if result < 0: return
+    if a < maxAlign: a = maxAlign
+    result = align(result, a)
+  of tyGenericInst, tyDistinct, tyGenericBody, tyMutable, tyConst, tyIter:
+    result = computeSizeAux(lastSon(typ), a)
+  of tyTypeDesc:
+    result = computeSizeAux(typ.base, a)
+  of tyForward: return szIllegalRecursion
+  else:
+    #internalError("computeSizeAux()")
+    result = szUnknownSize
+  typ.size = result
+  typ.align = int16(a)
+
+proc computeSize(typ: PType): BiggestInt =
+  var a: BiggestInt = 1
+  result = computeSizeAux(typ, a)
+
+proc getReturnType*(s: PSym): PType =
+  # Obtains the return type of a iterator/proc/macro/template
+  assert s.kind in skProcKinds
+  result = s.typ.sons[0]
+
+proc getSize(typ: PType): BiggestInt =
+  result = computeSize(typ)
+  if result < 0: internalError("getSize: " & $typ.kind)
+
+proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
+  if t.kind == tyStatic:
+    return t.n == nil
+
+  if t.kind == tyTypeDesc:
+    if t.base.kind == tyNone: return true
+    if containsGenericTypeIter(t.base, closure): return true
+    return false
+
+  if t.kind in GenericTypes + tyTypeClasses + {tyFromExpr}:
+    return true
+
+  return false
+
+proc containsGenericType*(t: PType): bool =
+  result = iterOverType(t, containsGenericTypeIter, nil)
+
+proc baseOfDistinct*(t: PType): PType =
+  if t.kind == tyDistinct:
+    result = t.sons[0]
+  else:
+    result = copyType(t, t.owner, false)
+    var parent: PType = nil
+    var it = result
+    while it.kind in {tyPtr, tyRef}:
+      parent = it
+      it = it.lastSon
+    if it.kind == tyDistinct:
+      internalAssert parent != nil
+      parent.sons[0] = it.sons[0]
+
+proc safeInheritanceDiff*(a, b: PType): int =
+  # same as inheritanceDiff but checks for tyError:
+  if a.kind == tyError or b.kind == tyError:
+    result = -1
+  else:
+    result = inheritanceDiff(a, b)
+
+proc compatibleEffectsAux(se, re: PNode): bool =
+  if re.isNil: return false
+  for r in items(re):
+    block search:
+      for s in items(se):
+        if safeInheritanceDiff(r.typ, s.typ) <= 0:
+          break search
+      return false
+  result = true
+
+proc compatibleEffects*(formal, actual: PType): bool =
+  # for proc type compatibility checking:
+  assert formal.kind == tyProc and actual.kind == tyProc
+  internalAssert formal.n.sons[0].kind == nkEffectList
+  internalAssert actual.n.sons[0].kind == nkEffectList
+
+  var spec = formal.n.sons[0]
+  if spec.len != 0:
+    var real = actual.n.sons[0]
+
+    let se = spec.sons[exceptionEffects]
+    # if 'se.kind == nkArgList' it is no formal type really, but a
+    # computed effect and as such no spec:
+    # 'r.msgHandler = if isNil(msgHandler): defaultMsgHandler else: msgHandler'
+    if not isNil(se) and se.kind != nkArgList:
+      # spec requires some exception or tag, but we don't know anything:
+      if real.len == 0: return false
+      result = compatibleEffectsAux(se, real.sons[exceptionEffects])
+      if not result: return
+
+    let st = spec.sons[tagEffects]
+    if not isNil(st) and st.kind != nkArgList:
+      # spec requires some exception or tag, but we don't know anything:
+      if real.len == 0: return false
+      result = compatibleEffectsAux(st, real.sons[tagEffects])
+      if not result: return
+  result = formal.lockLevel.ord < 0 or
+      actual.lockLevel.ord <= formal.lockLevel.ord
+
+proc isCompileTimeOnly*(t: PType): bool {.inline.} =
+  result = t.kind in {tyTypeDesc, tyStatic}
+
+proc containsCompileTimeOnly*(t: PType): bool =
+  if isCompileTimeOnly(t): return true
+  if t.sons != nil:
+    for i in 0 .. <t.sonsLen:
+      if t.sons[i] != nil and isCompileTimeOnly(t.sons[i]):
+        return true
+  return false
+
+type
+  OrdinalType* = enum
+    NoneLike, IntLike, FloatLike
+
+proc classify*(t: PType): OrdinalType =
+  ## for convenient type checking:
+  if t == nil:
+    result = NoneLike
+  else:
+    case skipTypes(t, abstractVarRange).kind
+    of tyFloat..tyFloat128: result = FloatLike
+    of tyInt..tyInt64, tyUInt..tyUInt64, tyBool, tyChar, tyEnum:
+      result = IntLike
+    else: result = NoneLike
+
+proc skipConv*(n: PNode): PNode =
+  result = n
+  case n.kind
+  of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
+    # only skip the conversion if it doesn't lose too important information
+    # (see bug #1334)
+    if n.sons[0].typ.classify == n.typ.classify:
+      result = n.sons[0]
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    if n.sons[1].typ.classify == n.typ.classify:
+      result = n.sons[1]
+  else: discard
+
+proc skipConvTakeType*(n: PNode): PNode =
+  result = n.skipConv
+  result.typ = n.typ
+
+proc isEmptyContainer*(t: PType): bool =
+  case t.kind
+  of tyExpr, tyNil: result = true
+  of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
+  of tySet, tySequence, tyOpenArray, tyVarargs:
+    result = t.sons[0].kind == tyEmpty
+  of tyGenericInst: result = isEmptyContainer(t.lastSon)
+  else: result = false
+
+proc takeType*(formal, arg: PType): PType =
+  # param: openArray[string] = []
+  # [] is an array constructor of length 0 of type string!
+  if arg.kind == tyNil:
+    # and not (formal.kind == tyProc and formal.callConv == ccClosure):
+    result = formal
+  elif formal.kind in {tyOpenArray, tyVarargs, tySequence} and
+      arg.isEmptyContainer:
+    let a = copyType(arg.skipTypes({tyGenericInst}), arg.owner, keepId=false)
+    a.sons[ord(arg.kind in {tyArray, tyArrayConstr})] = formal.sons[0]
+    result = a
+  elif formal.kind in {tyTuple, tySet} and arg.kind == formal.kind:
+    result = formal
+  else:
+    result = arg
+
+proc skipHiddenSubConv*(n: PNode): PNode =
+  if n.kind == nkHiddenSubConv:
+    # param: openArray[string] = []
+    # [] is an array constructor of length 0 of type string!
+    let formal = n.typ
+    result = n.sons[1]
+    let arg = result.typ
+    let dest = takeType(formal, arg)
+    if dest == arg and formal.kind != tyExpr:
+      #echo n.info, " came here for ", formal.typeToString
+      result = n
+    else:
+      result = copyTree(result)
+      result.typ = dest
+  else:
+    result = n
diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim
new file mode 100644
index 000000000..700356ab7
--- /dev/null
+++ b/compiler/typesrenderer.nim
@@ -0,0 +1,119 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import renderer, strutils, ast, msgs, types, astalgo
+
+const defaultParamSeparator* = ","
+
+proc renderPlainSymbolName*(n: PNode): string =
+  ## Returns the first non '*' nkIdent node from the tree.
+  ##
+  ## Use this on documentation name nodes to extract the *raw* symbol name,
+  ## without decorations, parameters, or anything. That can be used as the base
+  ## for the HTML hyperlinks.
+  result = ""
+  case n.kind
+  of nkPostfix:
+    for i in 0 .. <n.len:
+      result = renderPlainSymbolName(n[<n.len])
+      if result.len > 0:
+        return
+  of nkIdent:
+    if n.ident.s != "*":
+      result = n.ident.s
+  of nkSym:
+    result = n.sym.renderDefinitionName(noQuotes = true)
+  of nkPragmaExpr:
+    result = renderPlainSymbolName(n[0])
+  of nkAccQuoted:
+    result = renderPlainSymbolName(n[<n.len])
+  else:
+    internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
+  assert(not result.isNil)
+
+proc renderType(n: PNode): string =
+  ## Returns a string with the node type or the empty string.
+  case n.kind:
+  of nkIdent: result = n.ident.s
+  of nkSym: result = typeToString(n.sym.typ)
+  of nkVarTy:
+    assert len(n) == 1
+    result = renderType(n[0])
+  of nkRefTy:
+    assert len(n) == 1
+    result = "ref." & renderType(n[0])
+  of nkPtrTy:
+    assert len(n) == 1
+    result = "ptr." & renderType(n[0])
+  of nkProcTy:
+    assert len(n) > 1
+    let params = n[0]
+    assert params.kind == nkFormalParams
+    assert len(params) > 0
+    result = "proc("
+    for i in 1 .. <len(params): result.add(renderType(params[i]) & ',')
+    result[<len(result)] = ')'
+  of nkIdentDefs:
+    assert len(n) >= 3
+    let typePos = len(n) - 2
+    let typeStr = renderType(n[typePos])
+    result = typeStr
+    for i in 1 .. <typePos:
+      assert n[i].kind == nkIdent
+      result.add(',' & typeStr)
+  of nkTupleTy:
+    result = "tuple["
+    for i in 0 .. <len(n): result.add(renderType(n[i]) & ',')
+    result[<len(result)] = ']'
+  of nkBracketExpr:
+    assert len(n) >= 2
+    result = renderType(n[0]) & '['
+    for i in 1 .. <len(n): result.add(renderType(n[i]) & ',')
+    result[<len(result)] = ']'
+  else: result = ""
+  assert(not result.isNil)
+
+
+proc renderParamTypes(found: var seq[string], n: PNode) =
+  ## Recursive helper, adds to `found` any types, or keeps diving the AST.
+  ##
+  ## The normal `doc` generator doesn't include .typ information, so the
+  ## function won't render types for parameters with default values. The `doc2`
+  ## generator does include the information.
+  case n.kind
+  of nkFormalParams:
+    for i in 1 .. <len(n): renderParamTypes(found, n[i])
+  of nkIdentDefs:
+    # These are parameter names + type + default value node.
+    let typePos = len(n) - 2
+    assert typePos > 0
+    var typeStr = renderType(n[typePos])
+    if typeStr.len < 1 and n[typePos+1].kind != nkEmpty:
+      # Try with the last node, maybe its a default value.
+      let typ = n[typePos+1].typ
+      if not typ.isNil: typeStr = typeToString(typ, preferExported)
+      if typeStr.len < 1: return
+    for i in 0 .. <typePos:
+      assert ((n[i].kind == nkIdent) or (n[i].kind == nkAccQuoted))
+      found.add(typeStr)
+  else:
+    internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
+
+proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string =
+  ## Returns the types contained in `n` joined by `sep`.
+  ##
+  ## This proc expects to be passed as `n` the parameters of any callable. The
+  ## string output is meant for the HTML renderer. If there are no parameters,
+  ## the empty string is returned. The parameters will be joined by `sep` but
+  ## other characters may appear too, like ``[]`` or ``|``.
+  result = ""
+  var found: seq[string] = @[]
+  renderParamTypes(found, n)
+  if found.len > 0:
+    result = found.join(sep)
diff --git a/compiler/vm.nim b/compiler/vm.nim
new file mode 100644
index 000000000..e49bed522
--- /dev/null
+++ b/compiler/vm.nim
@@ -0,0 +1,1520 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This file implements the new evaluation engine for Nim code.
+## An instruction is 1-3 int32s in memory, it is a register based VM.
+
+const debugEchoCode = false
+
+import ast except getstr
+
+import
+  strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
+  parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
+  vmmarshal
+
+from semfold import leValueConv, ordinalValToString
+from evaltempl import evalTemplate
+
+when hasFFI:
+  import evalffi
+
+type
+  TRegisterKind = enum
+    rkNone, rkNode, rkInt, rkFloat, rkRegisterAddr, rkNodeAddr
+  TFullReg = object   # with a custom mark proc, we could use the same
+                      # data representation as LuaJit (tagged NaNs).
+    case kind: TRegisterKind
+    of rkNone: nil
+    of rkInt: intVal: BiggestInt
+    of rkFloat: floatVal: BiggestFloat
+    of rkNode: node: PNode
+    of rkRegisterAddr: regAddr: ptr TFullReg
+    of rkNodeAddr: nodeAddr: ptr PNode
+
+  PStackFrame* = ref TStackFrame
+  TStackFrame* = object
+    prc: PSym                 # current prc; proc that is evaluated
+    slots: seq[TFullReg]      # parameters passed to the proc + locals;
+                              # parameters come first
+    next: PStackFrame         # for stacking
+    comesFrom: int
+    safePoints: seq[int]      # used for exception handling
+                              # XXX 'break' should perform cleanup actions
+                              # What does the C backend do for it?
+
+proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
+  if x != nil:
+    if recursionLimit == 0:
+      var calls = 0
+      var x = x
+      while x != nil:
+        inc calls
+        x = x.next
+      msgWriteln($calls & " calls omitted\n")
+      return
+    stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
+    var info = c.debug[pc]
+    # we now use the same format as in system/except.nim
+    var s = toFilename(info)
+    var line = toLinenumber(info)
+    if line > 0:
+      add(s, '(')
+      add(s, $line)
+      add(s, ')')
+    if x.prc != nil:
+      for k in 1..max(1, 25-s.len): add(s, ' ')
+      add(s, x.prc.name.s)
+    msgWriteln(s)
+
+proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
+                msg: TMsgKind, arg = "") =
+  msgWriteln("stack trace: (most recent call last)")
+  stackTraceAux(c, tos, pc)
+  # XXX test if we want 'globalError' for every mode
+  if c.mode == emRepl: globalError(c.debug[pc], msg, arg)
+  else: localError(c.debug[pc], msg, arg)
+
+proc bailOut(c: PCtx; tos: PStackFrame) =
+  stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
+             c.currentExceptionA.sons[2].strVal)
+
+when not defined(nimComputedGoto):
+  {.pragma: computedGoto.}
+
+proc myreset(n: var TFullReg) = reset(n)
+
+template ensureKind(k: expr) {.immediate, dirty.} =
+  if regs[ra].kind != k:
+    myreset(regs[ra])
+    regs[ra].kind = k
+
+template decodeB(k: expr) {.immediate, dirty.} =
+  let rb = instr.regB
+  ensureKind(k)
+
+template decodeBC(k: expr) {.immediate, dirty.} =
+  let rb = instr.regB
+  let rc = instr.regC
+  ensureKind(k)
+
+template declBC() {.immediate, dirty.} =
+  let rb = instr.regB
+  let rc = instr.regC
+
+template decodeBImm(k: expr) {.immediate, dirty.} =
+  let rb = instr.regB
+  let imm = instr.regC - byteExcess
+  ensureKind(k)
+
+template decodeBx(k: expr) {.immediate, dirty.} =
+  let rbx = instr.regBx - wordExcess
+  ensureKind(k)
+
+template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
+# XXX fix minor 'shallowCopy' overloading bug in compiler
+
+proc createStrKeepNode(x: var TFullReg) =
+  if x.node.isNil:
+    x.node = newNode(nkStrLit)
+  elif x.node.kind == nkNilLit:
+    when defined(useNodeIds):
+      let id = x.node.id
+    system.reset(x.node[])
+    x.node.kind = nkStrLit
+    when defined(useNodeIds):
+      x.node.id = id
+  elif x.node.kind notin {nkStrLit..nkTripleStrLit} or
+      nfAllConst in x.node.flags:
+    # XXX this is hacky; tests/txmlgen triggers it:
+    x.node = newNode(nkStrLit)
+    # It not only hackey, it is also wrong for tgentemplate. The primary
+    # cause of bugs like these is that the VM does not properly distinguish
+    # between variable defintions (var foo = e) and variable updates (foo = e).
+
+include vmhooks
+
+template createStr(x) =
+  x.node = newNode(nkStrLit)
+
+template createSet(x) =
+  x.node = newNode(nkCurly)
+
+proc moveConst(x: var TFullReg, y: TFullReg) =
+  if x.kind != y.kind:
+    myreset(x)
+    x.kind = y.kind
+  case x.kind
+  of rkNone: discard
+  of rkInt: x.intVal = y.intVal
+  of rkFloat: x.floatVal = y.floatVal
+  of rkNode: x.node = y.node
+  of rkRegisterAddr: x.regAddr = y.regAddr
+  of rkNodeAddr: x.nodeAddr = y.nodeAddr
+
+# this seems to be the best way to model the reference semantics
+# of system.NimNode:
+template asgnRef(x, y: expr) = moveConst(x, y)
+
+proc copyValue(src: PNode): PNode =
+  if src == nil or nfIsRef in src.flags:
+    return src
+  result = newNode(src.kind)
+  result.info = src.info
+  result.typ = src.typ
+  result.flags = src.flags * PersistentNodeFlags
+  when defined(useNodeIds):
+    if result.id == nodeIdToDebug:
+      echo "COMES FROM ", src.id
+  case src.kind
+  of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
+  of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
+  of nkSym: result.sym = src.sym
+  of nkIdent: result.ident = src.ident
+  of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
+  else:
+    newSeq(result.sons, sonsLen(src))
+    for i in countup(0, sonsLen(src) - 1):
+      result.sons[i] = copyValue(src.sons[i])
+
+proc asgnComplex(x: var TFullReg, y: TFullReg) =
+  if x.kind != y.kind:
+    myreset(x)
+    x.kind = y.kind
+  case x.kind
+  of rkNone: discard
+  of rkInt: x.intVal = y.intVal
+  of rkFloat: x.floatVal = y.floatVal
+  of rkNode: x.node = copyValue(y.node)
+  of rkRegisterAddr: x.regAddr = y.regAddr
+  of rkNodeAddr: x.nodeAddr = y.nodeAddr
+
+proc putIntoNode(n: var PNode; x: TFullReg) =
+  case x.kind
+  of rkNone: discard
+  of rkInt: n.intVal = x.intVal
+  of rkFloat: n.floatVal = x.floatVal
+  of rkNode:
+    if nfIsRef in x.node.flags: n = x.node
+    else: n[] = x.node[]
+  of rkRegisterAddr: putIntoNode(n, x.regAddr[])
+  of rkNodeAddr: n[] = x.nodeAddr[][]
+
+proc putIntoReg(dest: var TFullReg; n: PNode) =
+  case n.kind
+  of nkStrLit..nkTripleStrLit:
+    dest.kind = rkNode
+    createStr(dest)
+    dest.node.strVal = n.strVal
+  of nkCharLit..nkUInt64Lit:
+    dest.kind = rkInt
+    dest.intVal = n.intVal
+  of nkFloatLit..nkFloat128Lit:
+    dest.kind = rkFloat
+    dest.floatVal = n.floatVal
+  else:
+    dest.kind = rkNode
+    dest.node = n
+
+proc regToNode(x: TFullReg): PNode =
+  case x.kind
+  of rkNone: result = newNode(nkEmpty)
+  of rkInt: result = newNode(nkIntLit); result.intVal = x.intVal
+  of rkFloat: result = newNode(nkFloatLit); result.floatVal = x.floatVal
+  of rkNode: result = x.node
+  of rkRegisterAddr: result = regToNode(x.regAddr[])
+  of rkNodeAddr: result = x.nodeAddr[]
+
+template getstr(a: expr): expr =
+  (if a.kind == rkNode: a.node.strVal else: $chr(int(a.intVal)))
+
+proc pushSafePoint(f: PStackFrame; pc: int) =
+  if f.safePoints.isNil: f.safePoints = @[]
+  f.safePoints.add(pc)
+
+proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
+
+proc cleanUpOnException(c: PCtx; tos: PStackFrame):
+                                              tuple[pc: int, f: PStackFrame] =
+  let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
+  var f = tos
+  while true:
+    while f.safePoints.isNil or f.safePoints.len == 0:
+      f = f.next
+      if f.isNil: return (-1, nil)
+    var pc2 = f.safePoints[f.safePoints.high]
+
+    var nextExceptOrFinally = -1
+    if c.code[pc2].opcode == opcExcept:
+      nextExceptOrFinally = pc2 + c.code[pc2].regBx - wordExcess
+      inc pc2
+    while c.code[pc2].opcode == opcExcept:
+      let exceptType = c.types[c.code[pc2].regBx-wordExcess].skipTypes(
+                          abstractPtrs)
+      if inheritanceDiff(exceptType, raisedType) <= 0:
+        # mark exception as handled but keep it in B for
+        # the getCurrentException() builtin:
+        c.currentExceptionB = c.currentExceptionA
+        c.currentExceptionA = nil
+        # execute the corresponding handler:
+        while c.code[pc2].opcode == opcExcept: inc pc2
+        return (pc2, f)
+      inc pc2
+      if c.code[pc2].opcode != opcExcept and nextExceptOrFinally >= 0:
+        # we're at the end of the *except list*, but maybe there is another
+        # *except branch*?
+        pc2 = nextExceptOrFinally+1
+        if c.code[pc2].opcode == opcExcept:
+          nextExceptOrFinally = pc2 + c.code[pc2].regBx - wordExcess
+
+    if nextExceptOrFinally >= 0:
+      pc2 = nextExceptOrFinally
+    if c.code[pc2].opcode == opcFinally:
+      # execute the corresponding handler, but don't quit walking the stack:
+      return (pc2, f)
+    # not the right one:
+    discard f.safePoints.pop
+
+proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
+  if f.safePoints.isNil: return -1
+  for s in f.safePoints:
+    var pc = s
+    while c.code[pc].opcode == opcExcept:
+      pc = pc + c.code[pc].regBx - wordExcess
+    if c.code[pc].opcode == opcFinally:
+      return pc
+  return -1
+
+proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
+  if desttyp.kind == tyString:
+    if dest.kind != rkNode:
+      myreset(dest)
+      dest.kind = rkNode
+    dest.node = newNode(nkStrLit)
+    let styp = srctyp.skipTypes(abstractRange)
+    case styp.kind
+    of tyEnum:
+      let n = styp.n
+      let x = src.intVal.int
+      if x <% n.len and (let f = n.sons[x].sym; f.position == x):
+        dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
+      else:
+        for i in 0.. <n.len:
+          if n.sons[i].kind != nkSym: internalError("opConv for enum")
+          let f = n.sons[i].sym
+          if f.position == x:
+            dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
+            return
+        internalError("opConv for enum")
+    of tyInt..tyInt64:
+      dest.node.strVal = $src.intVal
+    of tyUInt..tyUInt64:
+      dest.node.strVal = $uint64(src.intVal)
+    of tyBool:
+      dest.node.strVal = if src.intVal == 0: "false" else: "true"
+    of tyFloat..tyFloat128:
+      dest.node.strVal = $src.floatVal
+    of tyString, tyCString:
+      dest.node.strVal = src.node.strVal
+    of tyChar:
+      dest.node.strVal = $chr(src.intVal)
+    else:
+      internalError("cannot convert to string " & desttyp.typeToString)
+  else:
+    case skipTypes(desttyp, abstractRange).kind
+    of tyInt..tyInt64:
+      if dest.kind != rkInt:
+        myreset(dest); dest.kind = rkInt
+      case skipTypes(srctyp, abstractRange).kind
+      of tyFloat..tyFloat64:
+        dest.intVal = int(src.floatVal)
+      else:
+        dest.intVal = src.intVal
+      if dest.intVal < firstOrd(desttyp) or dest.intVal > lastOrd(desttyp):
+        return true
+    of tyUInt..tyUInt64:
+      if dest.kind != rkInt:
+        myreset(dest); dest.kind = rkInt
+      case skipTypes(srctyp, abstractRange).kind
+      of tyFloat..tyFloat64:
+        dest.intVal = int(src.floatVal)
+      else:
+        dest.intVal = src.intVal and ((1 shl (desttyp.size*8))-1)
+    of tyFloat..tyFloat64:
+      if dest.kind != rkFloat:
+        myreset(dest); dest.kind = rkFloat
+      case skipTypes(srctyp, abstractRange).kind
+      of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyBool, tyChar:
+        dest.floatVal = toFloat(src.intVal.int)
+      else:
+        dest.floatVal = src.floatVal
+    else:
+      asgnComplex(dest, src)
+
+proc compile(c: PCtx, s: PSym): int =
+  result = vmgen.genProc(c, s)
+  when debugEchoCode: c.echoCode result
+  #c.echoCode
+
+template handleJmpBack() {.dirty.} =
+  if c.loopIterations <= 0:
+    if allowInfiniteLoops in c.features:
+      c.loopIterations = MaxLoopIterations
+    else:
+      msgWriteln("stack trace: (most recent call last)")
+      stackTraceAux(c, tos, pc)
+      globalError(c.debug[pc], errTooManyIterations)
+  dec(c.loopIterations)
+
+proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
+  var pc = start
+  var tos = tos
+  var regs: seq[TFullReg] # alias to tos.slots for performance
+  move(regs, tos.slots)
+  #echo "NEW RUN ------------------------"
+  while true:
+    #{.computedGoto.}
+    let instr = c.code[pc]
+    let ra = instr.regA
+    #if c.traceActive:
+    #  echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
+    #  message(c.debug[pc], warnUser, "Trace")
+    case instr.opcode
+    of opcEof: return regs[ra]
+    of opcRet:
+      # XXX perform any cleanup actions
+      pc = tos.comesFrom
+      tos = tos.next
+      let retVal = regs[0]
+      if tos.isNil:
+        #echo "RET ", retVal.rendertree
+        return retVal
+
+      move(regs, tos.slots)
+      assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
+      if c.code[pc].opcode == opcIndCallAsgn:
+        regs[c.code[pc].regA] = retVal
+        #echo "RET2 ", retVal.rendertree, " ", c.code[pc].regA
+    of opcYldYoid: assert false
+    of opcYldVal: assert false
+    of opcAsgnInt:
+      decodeB(rkInt)
+      regs[ra].intVal = regs[rb].intVal
+    of opcAsgnStr:
+      decodeB(rkNode)
+      createStrKeepNode regs[ra]
+      regs[ra].node.strVal = regs[rb].node.strVal
+    of opcAsgnFloat:
+      decodeB(rkFloat)
+      regs[ra].floatVal = regs[rb].floatVal
+    of opcAsgnComplex:
+      asgnComplex(regs[ra], regs[instr.regB])
+    of opcAsgnRef:
+      asgnRef(regs[ra], regs[instr.regB])
+    of opcRegToNode:
+      decodeB(rkNode)
+      putIntoNode(regs[ra].node, regs[rb])
+    of opcNodeToReg:
+      let ra = instr.regA
+      let rb = instr.regB
+      # opcDeref might already have loaded it into a register. XXX Let's hope
+      # this is still correct this way:
+      if regs[rb].kind != rkNode:
+        regs[ra] = regs[rb]
+      else:
+        assert regs[rb].kind == rkNode
+        let nb = regs[rb].node
+        case nb.kind
+        of nkCharLit..nkInt64Lit:
+          ensureKind(rkInt)
+          regs[ra].intVal = nb.intVal
+        of nkFloatLit..nkFloat64Lit:
+          ensureKind(rkFloat)
+          regs[ra].floatVal = nb.floatVal
+        else:
+          ensureKind(rkNode)
+          regs[ra].node = nb
+    of opcLdArr:
+      # a = b[c]
+      decodeBC(rkNode)
+      if regs[rc].intVal > high(int):
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+      let idx = regs[rc].intVal.int
+      let src = regs[rb].node
+      if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
+        regs[ra].node = src.sons[idx]
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+    of opcLdStrIdx:
+      decodeBC(rkInt)
+      let idx = regs[rc].intVal.int
+      let s = regs[rb].node.strVal
+      if s.isNil:
+        stackTrace(c, tos, pc, errNilAccess)
+      elif idx <=% s.len:
+        regs[ra].intVal = s[idx].ord
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+    of opcWrArr:
+      # a[b] = c
+      decodeBC(rkNode)
+      let idx = regs[rb].intVal.int
+      if idx <% regs[ra].node.len:
+        putIntoNode(regs[ra].node.sons[idx], regs[rc])
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+    of opcLdObj:
+      # a = b.c
+      decodeBC(rkNode)
+      let src = regs[rb].node
+      if src.kind notin {nkEmpty..nkNilLit}:
+        let n = src.sons[rc].skipColon
+        regs[ra].node = n
+      else:
+        stackTrace(c, tos, pc, errNilAccess)
+    of opcWrObj:
+      # a.b = c
+      decodeBC(rkNode)
+      putIntoNode(regs[ra].node.sons[rb], regs[rc])
+    of opcWrStrIdx:
+      decodeBC(rkNode)
+      let idx = regs[rb].intVal.int
+      if idx <% regs[ra].node.strVal.len:
+        regs[ra].node.strVal[idx] = chr(regs[rc].intVal)
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+    of opcAddrReg:
+      decodeB(rkRegisterAddr)
+      regs[ra].regAddr = addr(regs[rb])
+    of opcAddrNode:
+      decodeB(rkNodeAddr)
+      regs[ra].nodeAddr = addr(regs[rb].node)
+    of opcLdDeref:
+      # a = b[]
+      let ra = instr.regA
+      let rb = instr.regB
+      case regs[rb].kind
+      of rkNodeAddr:
+        ensureKind(rkNode)
+        regs[ra].node = regs[rb].nodeAddr[]
+      of rkRegisterAddr:
+        ensureKind(regs[rb].regAddr.kind)
+        regs[ra] = regs[rb].regAddr[]
+      of rkNode:
+        if regs[rb].node.kind == nkNilLit:
+          stackTrace(c, tos, pc, errNilAccess)
+        assert regs[rb].node.kind == nkRefTy
+        regs[ra].node = regs[rb].node.sons[0]
+      else:
+        stackTrace(c, tos, pc, errNilAccess)
+    of opcWrDeref:
+      # a[] = c; b unused
+      let ra = instr.regA
+      let rc = instr.regC
+      case regs[ra].kind
+      of rkNodeAddr: putIntoNode(regs[ra].nodeAddr[], regs[rc])
+      of rkRegisterAddr: regs[ra].regAddr[] = regs[rc]
+      of rkNode: putIntoNode(regs[ra].node, regs[rc])
+      else: stackTrace(c, tos, pc, errNilAccess)
+    of opcAddInt:
+      decodeBC(rkInt)
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        sum = bVal +% cVal
+      if (sum xor bVal) >= 0 or (sum xor cVal) >= 0:
+        regs[ra].intVal = sum
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
+    of opcAddImmInt:
+      decodeBImm(rkInt)
+      #message(c.debug[pc], warnUser, "came here")
+      #debug regs[rb].node
+      let
+        bVal = regs[rb].intVal
+        cVal = imm
+        sum = bVal +% cVal
+      if (sum xor bVal) >= 0 or (sum xor cVal) >= 0:
+        regs[ra].intVal = sum
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
+    of opcSubInt:
+      decodeBC(rkInt)
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        diff = bVal -% cVal
+      if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0:
+        regs[ra].intVal = diff
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
+    of opcSubImmInt:
+      decodeBImm(rkInt)
+      let
+        bVal = regs[rb].intVal
+        cVal = imm
+        diff = bVal -% cVal
+      if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0:
+        regs[ra].intVal = diff
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
+    of opcLenSeq:
+      decodeBImm(rkInt)
+      #assert regs[rb].kind == nkBracket
+      # also used by mNLen:
+      regs[ra].intVal = regs[rb].node.safeLen - imm
+    of opcLenStr:
+      decodeBImm(rkInt)
+      assert regs[rb].kind == rkNode
+      regs[ra].intVal = regs[rb].node.strVal.len - imm
+    of opcIncl:
+      decodeB(rkNode)
+      let b = regs[rb].regToNode
+      if not inSet(regs[ra].node, b):
+        addSon(regs[ra].node, copyTree(b))
+    of opcInclRange:
+      decodeBC(rkNode)
+      var r = newNode(nkRange)
+      r.add regs[rb].regToNode
+      r.add regs[rc].regToNode
+      addSon(regs[ra].node, r.copyTree)
+    of opcExcl:
+      decodeB(rkNode)
+      var b = newNodeIT(nkCurly, regs[rb].node.info, regs[rb].node.typ)
+      addSon(b, regs[rb].regToNode)
+      var r = diffSets(regs[ra].node, b)
+      discardSons(regs[ra].node)
+      for i in countup(0, sonsLen(r) - 1): addSon(regs[ra].node, r.sons[i])
+    of opcCard:
+      decodeB(rkInt)
+      regs[ra].intVal = nimsets.cardSet(regs[rb].node)
+    of opcMulInt:
+      decodeBC(rkInt)
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        product = bVal *% cVal
+        floatProd = toBiggestFloat(bVal) * toBiggestFloat(cVal)
+        resAsFloat = toBiggestFloat(product)
+      if resAsFloat == floatProd:
+        regs[ra].intVal = product
+      elif 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+        regs[ra].intVal = product
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
+    of opcDivInt:
+      decodeBC(rkInt)
+      if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
+      else: regs[ra].intVal = regs[rb].intVal div regs[rc].intVal
+    of opcModInt:
+      decodeBC(rkInt)
+      if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
+      else: regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal
+    of opcAddFloat:
+      decodeBC(rkFloat)
+      regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal
+    of opcSubFloat:
+      decodeBC(rkFloat)
+      regs[ra].floatVal = regs[rb].floatVal - regs[rc].floatVal
+    of opcMulFloat:
+      decodeBC(rkFloat)
+      regs[ra].floatVal = regs[rb].floatVal * regs[rc].floatVal
+    of opcDivFloat:
+      decodeBC(rkFloat)
+      regs[ra].floatVal = regs[rb].floatVal / regs[rc].floatVal
+    of opcShrInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal shr regs[rc].intVal
+    of opcShlInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal shl regs[rc].intVal
+    of opcBitandInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal and regs[rc].intVal
+    of opcBitorInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal or regs[rc].intVal
+    of opcBitxorInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal xor regs[rc].intVal
+    of opcAddu:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal +% regs[rc].intVal
+    of opcSubu:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal -% regs[rc].intVal
+    of opcMulu:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal *% regs[rc].intVal
+    of opcDivu:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal /% regs[rc].intVal
+    of opcModu:
+      decodeBC(rkInt)
+      regs[ra].intVal = regs[rb].intVal %% regs[rc].intVal
+    of opcEqInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].intVal == regs[rc].intVal)
+    of opcLeInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].intVal <= regs[rc].intVal)
+    of opcLtInt:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].intVal < regs[rc].intVal)
+    of opcEqFloat:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].floatVal == regs[rc].floatVal)
+    of opcLeFloat:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].floatVal <= regs[rc].floatVal)
+    of opcLtFloat:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].floatVal < regs[rc].floatVal)
+    of opcLeu:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].intVal <=% regs[rc].intVal)
+    of opcLtu:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].intVal <% regs[rc].intVal)
+    of opcEqRef, opcEqNimrodNode:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord((regs[rb].node.kind == nkNilLit and
+                             regs[rc].node.kind == nkNilLit) or
+                             regs[rb].node == regs[rc].node)
+    of opcXor:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].intVal != regs[rc].intVal)
+    of opcNot:
+      decodeB(rkInt)
+      assert regs[rb].kind == rkInt
+      regs[ra].intVal = 1 - regs[rb].intVal
+    of opcUnaryMinusInt:
+      decodeB(rkInt)
+      assert regs[rb].kind == rkInt
+      let val = regs[rb].intVal
+      if val != int64.low:
+        regs[ra].intVal = -val
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
+    of opcUnaryMinusFloat:
+      decodeB(rkFloat)
+      assert regs[rb].kind == rkFloat
+      regs[ra].floatVal = -regs[rb].floatVal
+    of opcBitnotInt:
+      decodeB(rkInt)
+      assert regs[rb].kind == rkInt
+      regs[ra].intVal = not regs[rb].intVal
+    of opcEqStr:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal)
+    of opcLeStr:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal)
+    of opcLtStr:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.strVal < regs[rc].node.strVal)
+    of opcLeSet:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(containsSets(regs[rb].node, regs[rc].node))
+    of opcEqSet:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(equalSets(regs[rb].node, regs[rc].node))
+    of opcLtSet:
+      decodeBC(rkInt)
+      let a = regs[rb].node
+      let b = regs[rc].node
+      regs[ra].intVal = ord(containsSets(a, b) and not equalSets(a, b))
+    of opcMulSet:
+      decodeBC(rkNode)
+      createSet(regs[ra])
+      move(regs[ra].node.sons,
+            nimsets.intersectSets(regs[rb].node, regs[rc].node).sons)
+    of opcPlusSet:
+      decodeBC(rkNode)
+      createSet(regs[ra])
+      move(regs[ra].node.sons,
+           nimsets.unionSets(regs[rb].node, regs[rc].node).sons)
+    of opcMinusSet:
+      decodeBC(rkNode)
+      createSet(regs[ra])
+      move(regs[ra].node.sons,
+           nimsets.diffSets(regs[rb].node, regs[rc].node).sons)
+    of opcSymdiffSet:
+      decodeBC(rkNode)
+      createSet(regs[ra])
+      move(regs[ra].node.sons,
+           nimsets.symdiffSets(regs[rb].node, regs[rc].node).sons)
+    of opcConcatStr:
+      decodeBC(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = getstr(regs[rb])
+      for i in rb+1..rb+rc-1:
+        regs[ra].node.strVal.add getstr(regs[i])
+    of opcAddStrCh:
+      decodeB(rkNode)
+      #createStrKeepNode regs[ra]
+      regs[ra].node.strVal.add(regs[rb].intVal.chr)
+    of opcAddStrStr:
+      decodeB(rkNode)
+      #createStrKeepNode regs[ra]
+      regs[ra].node.strVal.add(regs[rb].node.strVal)
+    of opcAddSeqElem:
+      decodeB(rkNode)
+      if regs[ra].node.kind == nkBracket:
+        regs[ra].node.add(copyTree(regs[rb].regToNode))
+      else:
+        stackTrace(c, tos, pc, errNilAccess)
+    of opcEcho:
+      let rb = instr.regB
+      if rb == 1:
+        msgWriteln(regs[ra].node.strVal)
+      else:
+        var outp = ""
+        for i in ra..ra+rb-1:
+          #if regs[i].kind != rkNode: debug regs[i]
+          outp.add(regs[i].node.strVal)
+        msgWriteln(outp)
+    of opcContainsSet:
+      decodeBC(rkInt)
+      regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
+    of opcSubStr:
+      decodeBC(rkNode)
+      inc pc
+      assert c.code[pc].opcode == opcSubStr
+      let rd = c.code[pc].regA
+      createStr regs[ra]
+      regs[ra].node.strVal = substr(regs[rb].node.strVal,
+                                    regs[rc].intVal.int, regs[rd].intVal.int)
+    of opcParseFloat:
+      decodeBC(rkInt)
+      inc pc
+      assert c.code[pc].opcode == opcParseFloat
+      let rd = c.code[pc].regA
+      var rcAddr = addr(regs[rc])
+      if rcAddr.kind == rkRegisterAddr: rcAddr = rcAddr.regAddr
+      elif regs[rc].kind != rkFloat:
+        myreset(regs[rc])
+        regs[rc].kind = rkFloat
+      regs[ra].intVal = parseBiggestFloat(regs[rb].node.strVal,
+                                          rcAddr.floatVal, regs[rd].intVal.int)
+    of opcRangeChck:
+      let rb = instr.regB
+      let rc = instr.regC
+      if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
+              leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
+        stackTrace(c, tos, pc, errGenerated,
+          msgKindToString(errIllegalConvFromXtoY) % [
+          $regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
+    of opcIndCall, opcIndCallAsgn:
+      # dest = call regStart, n; where regStart = fn, arg1, ...
+      let rb = instr.regB
+      let rc = instr.regC
+      let bb = regs[rb].node
+      let isClosure = bb.kind == nkPar
+      let prc = if not isClosure: bb.sym else: bb.sons[0].sym
+      if prc.offset < -1:
+        # it's a callback:
+        c.callbacks[-prc.offset-2].value(
+          VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs),
+                 currentException: c.currentExceptionB))
+      elif sfImportc in prc.flags:
+        if allowFFI notin c.features:
+          globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
+        # we pass 'tos.slots' instead of 'regs' so that the compiler can keep
+        # 'regs' in a register:
+        when hasFFI:
+          let prcValue = c.globals.sons[prc.position-1]
+          if prcValue.kind == nkEmpty:
+            globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s)
+          let newValue = callForeignFunction(prcValue, prc.typ, tos.slots,
+                                             rb+1, rc-1, c.debug[pc])
+          if newValue.kind != nkEmpty:
+            assert instr.opcode == opcIndCallAsgn
+            putIntoReg(regs[ra], newValue)
+        else:
+          globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
+      elif prc.kind != skTemplate:
+        let newPc = compile(c, prc)
+        # tricky: a recursion is also a jump back, so we use the same
+        # logic as for loops:
+        if newPc < pc: handleJmpBack()
+        #echo "new pc ", newPc, " calling: ", prc.name.s
+        var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
+        newSeq(newFrame.slots, prc.offset)
+        if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
+          putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info))
+        for i in 1 .. rc-1:
+          newFrame.slots[i] = regs[rb+i]
+        if isClosure:
+          newFrame.slots[rc].kind = rkNode
+          newFrame.slots[rc].node = regs[rb].node.sons[1]
+        tos = newFrame
+        move(regs, newFrame.slots)
+        # -1 for the following 'inc pc'
+        pc = newPc-1
+      else:
+        # for 'getAst' support we need to support template expansion here:
+        let genSymOwner = if tos.next != nil and tos.next.prc != nil:
+                            tos.next.prc
+                          else:
+                            c.module
+        var macroCall = newNodeI(nkCall, c.debug[pc])
+        macroCall.add(newSymNode(prc))
+        for i in 1 .. rc-1: macroCall.add(regs[rb+i].regToNode)
+        let a = evalTemplate(macroCall, prc, genSymOwner)
+        ensureKind(rkNode)
+        regs[ra].node = a
+    of opcTJmp:
+      # jump Bx if A != 0
+      let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+      if regs[ra].intVal != 0:
+        inc pc, rbx
+    of opcFJmp:
+      # jump Bx if A == 0
+      let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+      if regs[ra].intVal == 0:
+        inc pc, rbx
+    of opcJmp:
+      # jump Bx
+      let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+      inc pc, rbx
+    of opcJmpBack:
+      let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+      inc pc, rbx
+      handleJmpBack()
+    of opcBranch:
+      # we know the next instruction is a 'fjmp':
+      let branch = c.constants[instr.regBx-wordExcess]
+      var cond = false
+      for j in countup(0, sonsLen(branch) - 2):
+        if overlap(regs[ra].regToNode, branch.sons[j]):
+          cond = true
+          break
+      assert c.code[pc+1].opcode == opcFJmp
+      inc pc
+      # we skip this instruction so that the final 'inc(pc)' skips
+      # the following jump
+      if not cond:
+        let instr2 = c.code[pc]
+        let rbx = instr2.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+        inc pc, rbx
+    of opcTry:
+      let rbx = instr.regBx - wordExcess
+      tos.pushSafePoint(pc + rbx)
+      assert c.code[pc+rbx].opcode in {opcExcept, opcFinally}
+    of opcExcept:
+      # just skip it; it's followed by a jump;
+      # we'll execute in the 'raise' handler
+      let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc'
+      inc pc, rbx
+      assert c.code[pc+1].opcode in {opcExcept, opcFinally}
+    of opcFinally:
+      # just skip it; it's followed by the code we need to execute anyway
+      tos.popSafePoint()
+    of opcFinallyEnd:
+      if c.currentExceptionA != nil:
+        # we are in a cleanup run:
+        let (newPc, newTos) = cleanUpOnException(c, tos)
+        if newPc-1 < 0:
+          bailOut(c, tos)
+          return
+        pc = newPc-1
+        if tos != newTos:
+          tos = newTos
+          move(regs, tos.slots)
+    of opcRaise:
+      let raised = regs[ra].node
+      c.currentExceptionA = raised
+      c.exceptionInstr = pc
+      let (newPc, newTos) = cleanUpOnException(c, tos)
+      # -1 because of the following 'inc'
+      if newPc-1 < 0:
+        bailOut(c, tos)
+        return
+      pc = newPc-1
+      if tos != newTos:
+        tos = newTos
+        move(regs, tos.slots)
+    of opcNew:
+      ensureKind(rkNode)
+      let typ = c.types[instr.regBx - wordExcess]
+      regs[ra].node = getNullValue(typ, c.debug[pc])
+      regs[ra].node.flags.incl nfIsRef
+    of opcNewSeq:
+      let typ = c.types[instr.regBx - wordExcess]
+      inc pc
+      ensureKind(rkNode)
+      let instr2 = c.code[pc]
+      let count = regs[instr2.regA].intVal.int
+      regs[ra].node = newNodeI(nkBracket, c.debug[pc])
+      regs[ra].node.typ = typ
+      newSeq(regs[ra].node.sons, count)
+      for i in 0 .. <count:
+        regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc])
+    of opcNewStr:
+      decodeB(rkNode)
+      regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
+      regs[ra].node.strVal = newString(regs[rb].intVal.int)
+    of opcLdImmInt:
+      # dest = immediate value
+      decodeBx(rkInt)
+      regs[ra].intVal = rbx
+    of opcLdNull:
+      ensureKind(rkNode)
+      let typ = c.types[instr.regBx - wordExcess]
+      regs[ra].node = getNullValue(typ, c.debug[pc])
+      # opcLdNull really is the gist of the VM's problems: should it load
+      # a fresh null to  regs[ra].node  or to regs[ra].node[]? This really
+      # depends on whether regs[ra] represents the variable itself or wether
+      # it holds the indirection! Due to the way registers are re-used we cannot
+      # say for sure here! --> The codegen has to deal with it
+      # via 'genAsgnPatch'.
+    of opcLdNullReg:
+      let typ = c.types[instr.regBx - wordExcess]
+      if typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}).kind in {
+          tyFloat..tyFloat128}:
+        ensureKind(rkFloat)
+        regs[ra].floatVal = 0.0
+      else:
+        ensureKind(rkInt)
+        regs[ra].intVal = 0
+    of opcLdConst:
+      let rb = instr.regBx - wordExcess
+      let cnst = c.constants.sons[rb]
+      if fitsRegister(cnst.typ):
+        myreset(regs[ra])
+        putIntoReg(regs[ra], cnst)
+      else:
+        ensureKind(rkNode)
+        regs[ra].node = cnst
+    of opcAsgnConst:
+      let rb = instr.regBx - wordExcess
+      let cnst = c.constants.sons[rb]
+      if fitsRegister(cnst.typ):
+        putIntoReg(regs[ra], cnst)
+      else:
+        ensureKind(rkNode)
+        regs[ra].node = cnst.copyTree
+    of opcLdGlobal:
+      let rb = instr.regBx - wordExcess - 1
+      ensureKind(rkNode)
+      regs[ra].node = c.globals.sons[rb]
+    of opcLdGlobalAddr:
+      let rb = instr.regBx - wordExcess - 1
+      ensureKind(rkNodeAddr)
+      regs[ra].nodeAddr = addr(c.globals.sons[rb])
+    of opcRepr:
+      decodeB(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments})
+    of opcQuit:
+      if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
+        message(c.debug[pc], hintQuitCalled)
+        msgQuit(int8(getOrdValue(regs[ra].regToNode)))
+      else:
+        return TFullReg(kind: rkNone)
+    of opcSetLenStr:
+      decodeB(rkNode)
+      #createStrKeepNode regs[ra]
+      regs[ra].node.strVal.setLen(regs[rb].intVal.int)
+    of opcOf:
+      decodeBC(rkInt)
+      let typ = c.types[regs[rc].intVal.int]
+      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0)
+    of opcIs:
+      decodeBC(rkInt)
+      let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc})
+      let t2 = c.types[regs[rc].intVal.int]
+      # XXX: This should use the standard isOpImpl
+      let match = if t2.kind == tyUserTypeClass: true
+                  else: sameType(t1, t2)
+      regs[ra].intVal = ord(match)
+    of opcSetLenSeq:
+      decodeB(rkNode)
+      let newLen = regs[rb].intVal.int
+      if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
+      else:
+        let oldLen = regs[ra].node.len
+        setLen(regs[ra].node.sons, newLen)
+        if oldLen < newLen:
+          # XXX This is still not entirely correct
+          # set to default value:
+          for i in oldLen .. <newLen:
+            regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc])
+    of opcSwap:
+      let rb = instr.regB
+      if regs[ra].kind == regs[rb].kind:
+        case regs[ra].kind
+        of rkNone: discard
+        of rkInt: swap regs[ra].intVal, regs[rb].intVal
+        of rkFloat: swap regs[ra].floatVal, regs[rb].floatVal
+        of rkNode: swap regs[ra].node, regs[rb].node
+        of rkRegisterAddr: swap regs[ra].regAddr, regs[rb].regAddr
+        of rkNodeAddr: swap regs[ra].nodeAddr, regs[rb].nodeAddr
+      else:
+        internalError(c.debug[pc], "cannot swap operands")
+    of opcReset:
+      internalError(c.debug[pc], "too implement")
+    of opcNarrowS:
+      decodeB(rkInt)
+      let min = -(1.BiggestInt shl (rb-1))
+      let max = (1.BiggestInt shl (rb-1))-1
+      if regs[ra].intVal < min or regs[ra].intVal > max:
+        stackTrace(c, tos, pc, errGenerated,
+          msgKindToString(errUnhandledExceptionX) % "value out of range")
+    of opcNarrowU:
+      decodeB(rkInt)
+      regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
+    of opcIsNil:
+      decodeB(rkInt)
+      let node = regs[rb].node
+      regs[ra].intVal = ord(node.kind == nkNilLit or
+        (node.kind in {nkStrLit..nkTripleStrLit} and node.strVal.isNil))
+    of opcNBindSym:
+      decodeBx(rkNode)
+      regs[ra].node = copyTree(c.constants.sons[rbx])
+    of opcNChild:
+      decodeBC(rkNode)
+      let idx = regs[rc].intVal.int
+      let src = regs[rb].node
+      if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len:
+        regs[ra].node = src.sons[idx]
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+    of opcNSetChild:
+      decodeBC(rkNode)
+      let idx = regs[rb].intVal.int
+      var dest = regs[ra].node
+      if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len:
+        dest.sons[idx] = regs[rc].node
+      else:
+        stackTrace(c, tos, pc, errIndexOutOfBounds)
+    of opcNAdd:
+      decodeBC(rkNode)
+      var u = regs[rb].node
+      if u.kind notin {nkEmpty..nkNilLit}:
+        u.add(regs[rc].node)
+      else:
+        stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
+      regs[ra].node = u
+    of opcNAddMultiple:
+      decodeBC(rkNode)
+      let x = regs[rc].node
+      var u = regs[rb].node
+      if u.kind notin {nkEmpty..nkNilLit}:
+        # XXX can be optimized:
+        for i in 0.. <x.len: u.add(x.sons[i])
+      else:
+        stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
+      regs[ra].node = u
+    of opcNKind:
+      decodeB(rkInt)
+      regs[ra].intVal = ord(regs[rb].node.kind)
+      c.comesFromHeuristic = regs[rb].node.info
+    of opcNIntVal:
+      decodeB(rkInt)
+      let a = regs[rb].node
+      case a.kind
+      of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
+      else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
+    of opcNFloatVal:
+      decodeB(rkFloat)
+      let a = regs[rb].node
+      case a.kind
+      of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
+      else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
+    of opcNSymbol:
+      decodeB(rkNode)
+      let a = regs[rb].node
+      if a.kind == nkSym:
+        regs[ra].node = copyNode(a)
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
+    of opcNIdent:
+      decodeB(rkNode)
+      let a = regs[rb].node
+      if a.kind == nkIdent:
+        regs[ra].node = copyNode(a)
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "ident")
+    of opcNGetType:
+      let rb = instr.regB
+      let rc = instr.regC
+      if rc == 0:
+        ensureKind(rkNode)
+        if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
+          regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
+        else:
+          stackTrace(c, tos, pc, errGenerated, "node has no type")
+      else:
+        # typeKind opcode:
+        ensureKind(rkInt)
+        if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
+          regs[ra].intVal = ord(regs[rb].node.typ.kind)
+        #else:
+        #  stackTrace(c, tos, pc, errGenerated, "node has no type")
+    of opcNStrVal:
+      decodeB(rkNode)
+      createStr regs[ra]
+      let a = regs[rb].node
+      if a.kind in {nkStrLit..nkTripleStrLit}: regs[ra].node.strVal = a.strVal
+      else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+    of opcSlurp:
+      decodeB(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
+                                     c.module)
+    of opcGorge:
+      decodeBC(rkNode)
+      createStr regs[ra]
+      regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
+                                     regs[rc].node.strVal)
+    of opcNError:
+      stackTrace(c, tos, pc, errUser, regs[ra].node.strVal)
+    of opcNWarning:
+      message(c.debug[pc], warnUser, regs[ra].node.strVal)
+    of opcNHint:
+      message(c.debug[pc], hintUser, regs[ra].node.strVal)
+    of opcParseExprToAst:
+      decodeB(rkNode)
+      # c.debug[pc].line.int - countLines(regs[rb].strVal) ?
+      var error: string
+      let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath,
+                            c.debug[pc].line.int,
+                            proc (info: TLineInfo; msg: TMsgKind; arg: string) =
+                              if error.isNil and msg <= msgs.errMax:
+                                error = formatMsg(info, msg, arg))
+      if not error.isNil:
+        c.errorFlag = error
+      elif sonsLen(ast) != 1:
+        c.errorFlag = formatMsg(c.debug[pc], errExprExpected, "multiple statements")
+      else:
+        regs[ra].node = ast.sons[0]
+    of opcParseStmtToAst:
+      decodeB(rkNode)
+      var error: string
+      let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath,
+                            c.debug[pc].line.int,
+                            proc (info: TLineInfo; msg: TMsgKind; arg: string) =
+                              if error.isNil and msg <= msgs.errMax:
+                                error = formatMsg(info, msg, arg))
+      if not error.isNil:
+        c.errorFlag = error
+      else:
+        regs[ra].node = ast
+    of opcQueryErrorFlag:
+      createStr regs[ra]
+      regs[ra].node.strVal = c.errorFlag
+      c.errorFlag.setLen 0
+    of opcCallSite:
+      ensureKind(rkNode)
+      if c.callsite != nil: regs[ra].node = c.callsite
+      else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
+    of opcNLineInfo:
+      decodeB(rkNode)
+      let n = regs[rb].node
+      createStr regs[ra]
+      regs[ra].node.strVal = n.info.toFileLineCol
+      regs[ra].node.info = c.debug[pc]
+    of opcEqIdent:
+      decodeBC(rkInt)
+      if regs[rb].node.kind == nkIdent and regs[rc].node.kind == nkIdent:
+        regs[ra].intVal = ord(regs[rb].node.ident.id == regs[rc].node.ident.id)
+      else:
+        regs[ra].intVal = 0
+    of opcStrToIdent:
+      decodeB(rkNode)
+      if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
+        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+      else:
+        regs[ra].node = newNodeI(nkIdent, c.debug[pc])
+        regs[ra].node.ident = getIdent(regs[rb].node.strVal)
+    of opcIdentToStr:
+      decodeB(rkNode)
+      let a = regs[rb].node
+      createStr regs[ra]
+      regs[ra].node.info = c.debug[pc]
+      if a.kind == nkSym:
+        regs[ra].node.strVal = a.sym.name.s
+      elif a.kind == nkIdent:
+        regs[ra].node.strVal = a.ident.s
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "ident")
+    of opcSetType:
+      if regs[ra].kind != rkNode:
+        internalError(c.debug[pc], "cannot set type")
+      regs[ra].node.typ = c.types[instr.regBx - wordExcess]
+    of opcConv:
+      let rb = instr.regB
+      inc pc
+      let desttyp = c.types[c.code[pc].regBx - wordExcess]
+      inc pc
+      let srctyp = c.types[c.code[pc].regBx - wordExcess]
+
+      if opConv(regs[ra], regs[rb], desttyp, srctyp):
+        stackTrace(c, tos, pc, errGenerated,
+          msgKindToString(errIllegalConvFromXtoY) % [
+          typeToString(srctyp), typeToString(desttyp)])
+    of opcCast:
+      let rb = instr.regB
+      inc pc
+      let desttyp = c.types[c.code[pc].regBx - wordExcess]
+      inc pc
+      let srctyp = c.types[c.code[pc].regBx - wordExcess]
+
+      when hasFFI:
+        let dest = fficast(regs[rb], desttyp)
+        asgnRef(regs[ra], dest)
+      else:
+        globalError(c.debug[pc], "cannot evaluate cast")
+    of opcNSetIntVal:
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind in {nkCharLit..nkUInt64Lit} and
+         regs[rb].kind in {rkInt}:
+        dest.intVal = regs[rb].intVal
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
+    of opcNSetFloatVal:
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind in {nkFloatLit..nkFloat64Lit} and
+         regs[rb].kind in {rkFloat}:
+        dest.floatVal = regs[rb].floatVal
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
+    of opcNSetSymbol:
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind == nkSym and regs[rb].node.kind == nkSym:
+        dest.sym = regs[rb].node.sym
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
+    of opcNSetIdent:
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
+        dest.ident = regs[rb].node.ident
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "ident")
+    of opcNSetType:
+      decodeB(rkNode)
+      let b = regs[rb].node
+      internalAssert b.kind == nkSym and b.sym.kind == skType
+      internalAssert regs[ra].node != nil
+      regs[ra].node.typ = b.sym.typ
+    of opcNSetStrVal:
+      decodeB(rkNode)
+      var dest = regs[ra].node
+      if dest.kind in {nkStrLit..nkTripleStrLit} and
+         regs[rb].kind in {rkNode}:
+        dest.strVal = regs[rb].node.strVal
+      else:
+        stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
+    of opcNNewNimNode:
+      decodeBC(rkNode)
+      var k = regs[rb].intVal
+      if k < 0 or k > ord(high(TNodeKind)):
+        internalError(c.debug[pc],
+          "request to create a NimNode of invalid kind")
+      let cc = regs[rc].node
+
+      regs[ra].node = newNodeI(TNodeKind(int(k)),
+        if cc.kind != nkNilLit:
+          cc.info
+        elif c.comesFromHeuristic.line > -1:
+          c.comesFromHeuristic
+        elif c.callsite != nil and c.callsite.safeLen > 1:
+          c.callsite[1].info
+        else:
+          c.debug[pc])
+      regs[ra].node.flags.incl nfIsRef
+    of opcNCopyNimNode:
+      decodeB(rkNode)
+      regs[ra].node = copyNode(regs[rb].node)
+    of opcNCopyNimTree:
+      decodeB(rkNode)
+      regs[ra].node = copyTree(regs[rb].node)
+    of opcNDel:
+      decodeBC(rkNode)
+      let bb = regs[rb].intVal.int
+      for i in countup(0, regs[rc].intVal.int-1):
+        delSon(regs[ra].node, bb)
+    of opcGenSym:
+      decodeBC(rkNode)
+      let k = regs[rb].intVal
+      let name = if regs[rc].node.strVal.len == 0: ":tmp"
+                 else: regs[rc].node.strVal
+      if k < 0 or k > ord(high(TSymKind)):
+        internalError(c.debug[pc], "request to create symbol of invalid kind")
+      var sym = newSym(k.TSymKind, name.getIdent, c.module, c.debug[pc])
+      incl(sym.flags, sfGenSym)
+      regs[ra].node = newSymNode(sym)
+    of opcTypeTrait:
+      # XXX only supports 'name' for now; we can use regC to encode the
+      # type trait operation
+      decodeB(rkNode)
+      var typ = regs[rb].node.typ
+      internalAssert typ != nil
+      while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
+      createStr regs[ra]
+      regs[ra].node.strVal = typ.typeToString(preferExported)
+    of opcMarshalLoad:
+      let ra = instr.regA
+      let rb = instr.regB
+      inc pc
+      let typ = c.types[c.code[pc].regBx - wordExcess]
+      putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
+    of opcMarshalStore:
+      decodeB(rkNode)
+      inc pc
+      let typ = c.types[c.code[pc].regBx - wordExcess]
+      createStrKeepNode(regs[ra])
+      if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
+      storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
+    inc pc
+
+proc execute(c: PCtx, start: int): PNode =
+  var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
+  newSeq(tos.slots, c.prc.maxSlots)
+  result = rawExecute(c, start, tos).regToNode
+
+proc evalStmt*(c: PCtx, n: PNode) =
+  let n = transformExpr(c.module, n)
+  let start = genStmt(c, n)
+  # execute new instructions; this redundant opcEof check saves us lots
+  # of allocations in 'execute':
+  if c.code[start].opcode != opcEof:
+    discard execute(c, start)
+
+proc evalExpr*(c: PCtx, n: PNode): PNode =
+  let n = transformExpr(c.module, n)
+  let start = genExpr(c, n)
+  assert c.code[start].opcode != opcEof
+  result = execute(c, start)
+
+include vmops
+
+# for now we share the 'globals' environment. XXX Coming soon: An API for
+# storing&loading the 'globals' environment to get what a component system
+# requires.
+var
+  globalCtx: PCtx
+
+proc setupGlobalCtx(module: PSym) =
+  if globalCtx.isNil:
+    globalCtx = newCtx(module)
+    registerAdditionalOps(globalCtx)
+  else:
+    refresh(globalCtx, module)
+
+proc myOpen(module: PSym): PPassContext =
+  #var c = newEvalContext(module, emRepl)
+  #c.features = {allowCast, allowFFI, allowInfiniteLoops}
+  #pushStackFrame(c, newStackFrame())
+
+  # XXX produce a new 'globals' environment here:
+  setupGlobalCtx(module)
+  result = globalCtx
+  when hasFFI:
+    globalCtx.features = {allowFFI, allowCast}
+
+var oldErrorCount: int
+
+proc myProcess(c: PPassContext, n: PNode): PNode =
+  # don't eval errornous code:
+  if oldErrorCount == msgs.gErrorCounter:
+    evalStmt(PCtx(c), n)
+    result = emptyNode
+  else:
+    result = n
+  oldErrorCount = msgs.gErrorCounter
+
+const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
+
+proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
+  let n = transformExpr(module, n)
+  setupGlobalCtx(module)
+  var c = globalCtx
+  c.mode = mode
+  let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
+  if c.code[start].opcode == opcEof: return emptyNode
+  assert c.code[start].opcode != opcEof
+  when debugEchoCode: c.echoCode start
+  var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
+  newSeq(tos.slots, c.prc.maxSlots)
+  #for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
+  result = rawExecute(c, start, tos).regToNode
+  if result.info.line < 0: result.info = n.info
+
+proc evalConstExpr*(module: PSym, e: PNode): PNode =
+  result = evalConstExprAux(module, nil, e, emConst)
+
+proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
+  result = evalConstExprAux(module, prc, e, emStaticExpr)
+
+proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) =
+  discard evalConstExprAux(module, prc, e, emStaticStmt)
+
+proc setupCompileTimeVar*(module: PSym, n: PNode) =
+  discard evalConstExprAux(module, nil, n, emStaticStmt)
+
+proc setupMacroParam(x: PNode): PNode =
+  result = x
+  if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
+  result = canonValue(result)
+  result.flags.incl nfIsRef
+  result.typ = x.typ
+
+var evalMacroCounter: int
+
+proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
+  # XXX GlobalError() is ugly here, but I don't know a better solution for now
+  inc(evalMacroCounter)
+  if evalMacroCounter > 100:
+    globalError(n.info, errTemplateInstantiationTooNested)
+
+  # immediate macros can bypass any type and arity checking so we check the
+  # arity here too:
+  if sym.typ.len > n.safeLen and sym.typ.len > 1:
+    globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
+        n.renderTree,
+        $ <n.safeLen, $ <sym.typ.len])
+
+  setupGlobalCtx(module)
+  var c = globalCtx
+
+  c.callsite = nOrig
+  let start = genProc(c, sym)
+
+  var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
+  let maxSlots = sym.offset
+  newSeq(tos.slots, maxSlots)
+  # setup arguments:
+  var L = n.safeLen
+  if L == 0: L = 1
+  # This is wrong for tests/reject/tind1.nim where the passed 'else' part
+  # doesn't end up in the parameter:
+  #InternalAssert tos.slots.len >= L
+
+  # return value:
+  tos.slots[0].kind = rkNode
+  tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0])
+  # setup parameters:
+  for i in 1 .. < min(tos.slots.len, L):
+    tos.slots[i].kind = rkNode
+    tos.slots[i].node = setupMacroParam(n.sons[i])
+  # temporary storage:
+  #for i in L .. <maxSlots: tos.slots[i] = newNode(nkEmpty)
+  result = rawExecute(c, start, tos).regToNode
+  if result.info.line < 0: result.info = n.info
+  if cyclicTree(result): globalError(n.info, errCyclicTree)
+  dec(evalMacroCounter)
+  c.callsite = nil
+  #debug result
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
new file mode 100644
index 000000000..047009f01
--- /dev/null
+++ b/compiler/vmdef.nim
@@ -0,0 +1,237 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains the type definitions for the new evaluation engine.
+## An instruction is 1-3 int32s in memory, it is a register based VM.
+
+import ast, passes, msgs, intsets
+
+const
+  byteExcess* = 128 # we use excess-K for immediates
+  wordExcess* = 32768
+
+  MaxLoopIterations* = 1500_000 # max iterations of all loops
+
+
+type
+  TRegister* = range[0..255]
+  TDest* = range[-1 .. 255]
+  TInstr* = distinct uint32
+
+  TOpcode* = enum
+    opcEof,         # end of code
+    opcRet,         # return
+    opcYldYoid,     # yield with no value
+    opcYldVal,      # yield with a value
+
+    opcAsgnInt,
+    opcAsgnStr,
+    opcAsgnFloat,
+    opcAsgnRef,
+    opcAsgnComplex,
+    opcRegToNode,
+    opcNodeToReg,
+
+    opcLdArr,  # a = b[c]
+    opcWrArr,  # a[b] = c
+    opcLdObj,  # a = b.c
+    opcWrObj,  # a.b = c
+    opcAddrReg,
+    opcAddrNode,
+    opcLdDeref,
+    opcWrDeref,
+    opcWrStrIdx,
+    opcLdStrIdx, # a = b[c]
+
+    opcAddInt,
+    opcAddImmInt,
+    opcSubInt,
+    opcSubImmInt,
+    opcLenSeq,
+    opcLenStr,
+
+    opcIncl, opcInclRange, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
+    opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
+    opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu,
+    opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat,
+    opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcEqNimrodNode, opcXor,
+    opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
+    opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
+    opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
+    opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
+    opcSwap, opcIsNil, opcOf, opcIs,
+    opcSubStr, opcParseFloat, opcConv, opcCast,
+    opcQuit, opcReset,
+    opcNarrowS, opcNarrowU,
+
+    opcAddStrCh,
+    opcAddStrStr,
+    opcAddSeqElem,
+    opcRangeChck,
+
+    opcNAdd,
+    opcNAddMultiple,
+    opcNKind,
+    opcNIntVal,
+    opcNFloatVal,
+    opcNSymbol,
+    opcNIdent,
+    opcNGetType,
+    opcNStrVal,
+
+    opcNSetIntVal,
+    opcNSetFloatVal, opcNSetSymbol, opcNSetIdent, opcNSetType, opcNSetStrVal,
+    opcNNewNimNode, opcNCopyNimNode, opcNCopyNimTree, opcNDel, opcGenSym,
+
+    opcSlurp,
+    opcGorge,
+    opcParseExprToAst,
+    opcParseStmtToAst,
+    opcQueryErrorFlag,
+    opcNError,
+    opcNWarning,
+    opcNHint,
+    opcNLineInfo,
+    opcEqIdent,
+    opcStrToIdent,
+    opcIdentToStr,
+
+    opcEcho,
+    opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
+    opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
+
+    opcRaise,
+    opcNChild,
+    opcNSetChild,
+    opcCallSite,
+    opcNewStr,
+
+    opcTJmp,  # jump Bx if A != 0
+    opcFJmp,  # jump Bx if A == 0
+    opcJmp,   # jump Bx
+    opcJmpBack, # jump Bx; resulting from a while loop
+    opcBranch,  # branch for 'case'
+    opcTry,
+    opcExcept,
+    opcFinally,
+    opcFinallyEnd,
+    opcNew,
+    opcNewSeq,
+    opcLdNull,    # dest = nullvalue(types[Bx])
+    opcLdNullReg,
+    opcLdConst,   # dest = constants[Bx]
+    opcAsgnConst, # dest = copy(constants[Bx])
+    opcLdGlobal,  # dest = globals[Bx]
+    opcLdGlobalAddr, # dest = addr(globals[Bx])
+
+    opcLdImmInt,  # dest = immediate value
+    opcNBindSym,
+    opcSetType,   # dest.typ = types[Bx]
+    opcTypeTrait,
+    opcMarshalLoad, opcMarshalStore
+
+  TBlock* = object
+    label*: PSym
+    fixups*: seq[TPosition]
+
+  TEvalMode* = enum           ## reason for evaluation
+    emRepl,                   ## evaluate because in REPL mode
+    emConst,                  ## evaluate for 'const' according to spec
+    emOptimize,               ## evaluate for optimization purposes (same as
+                              ## emConst?)
+    emStaticExpr,             ## evaluate for enforced compile time eval
+                              ## ('static' context)
+    emStaticStmt              ## 'static' as an expression
+
+  TSandboxFlag* = enum        ## what the evaluation engine should allow
+    allowCast,                ## allow unsafe language feature: 'cast'
+    allowFFI,                 ## allow the FFI
+    allowInfiniteLoops        ## allow endless loops
+  TSandboxFlags* = set[TSandboxFlag]
+
+  TSlotKind* = enum   # We try to re-use slots in a smart way to
+                      # minimize allocations; however the VM supports arbitrary
+                      # temporary slot usage. This is required for the parameter
+                      # passing implementation.
+    slotEmpty,        # slot is unused
+    slotFixedVar,     # slot is used for a fixed var/result (requires copy then)
+    slotFixedLet,     # slot is used for a fixed param/let
+    slotTempUnknown,  # slot but type unknown (argument of proc call)
+    slotTempInt,      # some temporary int
+    slotTempFloat,    # some temporary float
+    slotTempStr,      # some temporary string
+    slotTempComplex,  # some complex temporary (s.node field is used)
+    slotTempPerm      # slot is temporary but permanent (hack)
+
+  PProc* = ref object
+    blocks*: seq[TBlock]    # blocks; temp data structure
+    sym*: PSym
+    slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
+    maxSlots*: int
+
+  VmArgs* = object
+    ra*, rb*, rc*: Natural
+    slots*: pointer
+    currentException*: PNode
+  VmCallback* = proc (args: VmArgs) {.closure.}
+
+  PCtx* = ref TCtx
+  TCtx* = object of passes.TPassContext # code gen context
+    code*: seq[TInstr]
+    debug*: seq[TLineInfo]  # line info for every instruction; kept separate
+                            # to not slow down interpretation
+    globals*: PNode         #
+    constants*: PNode       # constant data
+    types*: seq[PType]      # some instructions reference types (e.g. 'except')
+    currentExceptionA*, currentExceptionB*: PNode
+    exceptionInstr*: int # index of instruction that raised the exception
+    prc*: PProc
+    module*: PSym
+    callsite*: PNode
+    mode*: TEvalMode
+    features*: TSandboxFlags
+    traceActive*: bool
+    loopIterations*: int
+    comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces
+    callbacks*: seq[tuple[key: string, value: VmCallback]]
+    errorFlag*: string
+
+  TPosition* = distinct int
+
+  PEvalContext* = PCtx
+
+proc newCtx*(module: PSym): PCtx =
+  PCtx(code: @[], debug: @[],
+    globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
+    prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
+    comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "")
+
+proc refresh*(c: PCtx, module: PSym) =
+  c.module = module
+  c.prc = PProc(blocks: @[])
+  c.loopIterations = MaxLoopIterations
+
+proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
+  c.callbacks.add((name, callback))
+
+const
+  firstABxInstr* = opcTJmp
+  largeInstrs* = { # instructions which use 2 int32s instead of 1:
+    opcSubStr, opcConv, opcCast, opcNewSeq, opcOf,
+    opcMarshalLoad, opcMarshalStore}
+  slotSomeTemp* = slotTempUnknown
+  relativeJumps* = {opcTJmp, opcFJmp, opcJmp, opcJmpBack}
+
+template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
+template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
+template regB*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
+template regC*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 24'u32)
+template regBx*(x: TInstr): int {.immediate.} = (x.uint32 shr 16'u32).int
+
+template jmpDiff*(x: TInstr): int {.immediate.} = regBx(x) - wordExcess
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
new file mode 100644
index 000000000..21ee4967b
--- /dev/null
+++ b/compiler/vmdeps.nim
@@ -0,0 +1,162 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import ast, types, msgs, osproc, streams, options, idents
+
+proc readOutput(p: Process): string =
+  result = ""
+  var output = p.outputStream
+  while not output.atEnd:
+    result.add(output.readLine)
+    result.add("\n")
+  result.setLen(result.len - "\n".len)
+  discard p.waitForExit
+
+proc opGorge*(cmd, input: string): string =
+  try:
+    var p = startProcess(cmd, options={poEvalCommand})
+    if input.len != 0:
+      p.inputStream.write(input)
+      p.inputStream.close()
+    result = p.readOutput
+  except IOError, OSError:
+    result = ""
+
+proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
+  try:
+    let filename = file.findFile
+    result = readFile(filename)
+    # we produce a fake include statement for every slurped filename, so that
+    # the module dependencies are accurate:
+    appendToModule(module, newNode(nkIncludeStmt, info, @[
+      newStrNode(nkStrLit, filename)]))
+  except IOError:
+    localError(info, errCannotOpenFile, file)
+    result = ""
+
+proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
+  let sym = newSym(skType, getIdent(name), t.owner, info)
+  sym.typ = t
+  result = newSymNode(sym)
+  result.typ = t
+
+proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
+
+proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
+  result = newNodeIT(nkBracketExpr, info, t)
+  result.add atomicTypeX(name, t, info)
+  for i in 0 .. < t.len:
+    if t.sons[i] == nil:
+      let void = atomicTypeX("void", t, info)
+      void.typ = newType(tyEmpty, t.owner)
+      result.add void
+    else:
+      result.add mapTypeToAst(t.sons[i], info)
+
+proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
+  template atomicType(name): expr = atomicTypeX(name, t, info)
+
+  case t.kind
+  of tyNone: result = atomicType("none")
+  of tyBool: result = atomicType("bool")
+  of tyChar: result = atomicType("char")
+  of tyNil: result = atomicType("nil")
+  of tyExpr: result = atomicType("expr")
+  of tyStmt: result = atomicType("stmt")
+  of tyEmpty: result = atomicType"void"
+  of tyArrayConstr, tyArray:
+    result = newNodeIT(nkBracketExpr, info, t)
+    result.add atomicType("array")
+    result.add mapTypeToAst(t.sons[0], info)
+    result.add mapTypeToAst(t.sons[1], info)
+  of tyTypeDesc:
+    if t.base != nil:
+      result = newNodeIT(nkBracketExpr, info, t)
+      result.add atomicType("typeDesc")
+      result.add mapTypeToAst(t.base, info)
+    else:
+      result = atomicType"typeDesc"
+  of tyGenericInvocation:
+    result = newNodeIT(nkBracketExpr, info, t)
+    for i in 0 .. < t.len:
+      result.add mapTypeToAst(t.sons[i], info)
+  of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
+    result = mapTypeToAst(t.lastSon, info)
+  of tyDistinct:
+    if allowRecursion:
+      result = mapTypeToBracket("distinct", t, info)
+    else:
+      result = atomicType(t.sym.name.s)
+  of tyGenericParam, tyForward: result = atomicType(t.sym.name.s)
+  of tyObject:
+    if allowRecursion:
+      result = newNodeIT(nkObjectTy, info, t)
+      if t.sons[0] == nil:
+        result.add ast.emptyNode
+      else:
+        result.add mapTypeToAst(t.sons[0], info)
+      result.add copyTree(t.n)
+    else:
+      result = atomicType(t.sym.name.s)
+  of tyEnum:
+    result = newNodeIT(nkEnumTy, info, t)
+    result.add copyTree(t.n)
+  of tyTuple: result = mapTypeToBracket("tuple", t, info)
+  of tySet: result = mapTypeToBracket("set", t, info)
+  of tyPtr: result = mapTypeToBracket("ptr", t, info)
+  of tyRef: result = mapTypeToBracket("ref", t, info)
+  of tyVar: result = mapTypeToBracket("var", t, info)
+  of tySequence: result = mapTypeToBracket("seq", t, info)
+  of tyProc: result = mapTypeToBracket("proc", t, info)
+  of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
+  of tyRange:
+    result = newNodeIT(nkBracketExpr, info, t)
+    result.add atomicType("range")
+    result.add t.n.sons[0].copyTree
+    result.add t.n.sons[1].copyTree
+  of tyPointer: result = atomicType"pointer"
+  of tyString: result = atomicType"string"
+  of tyCString: result = atomicType"cstring"
+  of tyInt: result = atomicType"int"
+  of tyInt8: result = atomicType"int8"
+  of tyInt16: result = atomicType"int16"
+  of tyInt32: result = atomicType"int32"
+  of tyInt64: result = atomicType"int64"
+  of tyFloat: result = atomicType"float"
+  of tyFloat32: result = atomicType"float32"
+  of tyFloat64: result = atomicType"float64"
+  of tyFloat128: result = atomicType"float128"
+  of tyUInt: result = atomicType"uint"
+  of tyUInt8: result = atomicType"uint8"
+  of tyUInt16: result = atomicType"uint16"
+  of tyUInt32: result = atomicType"uint32"
+  of tyUInt64: result = atomicType"uint64"
+  of tyBigNum: result = atomicType"bignum"
+  of tyConst: result = mapTypeToBracket("const", t, info)
+  of tyMutable: result = mapTypeToBracket("mutable", t, info)
+  of tyVarargs: result = mapTypeToBracket("varargs", t, info)
+  of tyIter: result = mapTypeToBracket("iter", t, info)
+  of tyProxy: result = atomicType"error"
+  of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
+  of tyUserTypeClass:
+    result = mapTypeToBracket("concept", t, info)
+    result.add t.n.copyTree
+  of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
+  of tyAnd: result = mapTypeToBracket("and", t, info)
+  of tyOr: result = mapTypeToBracket("or", t, info)
+  of tyNot: result = mapTypeToBracket("not", t, info)
+  of tyAnything: result = atomicType"anything"
+  of tyStatic, tyFromExpr, tyFieldAccessor:
+    result = newNodeIT(nkBracketExpr, info, t)
+    result.add atomicType("static")
+    if t.n != nil:
+      result.add t.n.copyTree
+
+proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
+  result = mapTypeToAst(t, info, true)
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
new file mode 100644
index 000000000..0743a4502
--- /dev/null
+++ b/compiler/vmgen.nim
@@ -0,0 +1,1829 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the code generator for the VM.
+
+# Important things to remember:
+# - The VM does not distinguish between definitions ('var x = y') and
+#   assignments ('x = y'). For simple data types that fit into a register
+#   this doesn't matter. However it matters for strings and other complex
+#   types that use the 'node' field; the reason is that slots are
+#   re-used in a register based VM. Example:
+#
+# .. code-block:: nim
+#   let s = a & b  # no matter what, create fresh node
+#   s = a & b  # no matter what, keep the node
+#
+# Also *stores* into non-temporary memory need to perform deep copies:
+# a.b = x.y
+# We used to generate opcAsgn for the *load* of 'x.y' but this is clearly
+# wrong! We need to produce opcAsgn (the copy) for the *store*. This also
+# solves the opcLdConst vs opcAsgnConst issue. Of course whether we need
+# this copy depends on the involved types.
+
+import
+  unsigned, strutils, ast, astalgo, types, msgs, renderer, vmdef,
+  trees, intsets, rodread, magicsys, options, lowerings
+
+from os import splitFile
+
+when hasFFI:
+  import evalffi
+
+type
+  TGenFlag = enum gfNone, gfAddrOf
+  TGenFlags = set[TGenFlag]
+
+proc debugInfo(info: TLineInfo): string =
+  result = info.toFilename.splitFile.name & ":" & $info.line
+
+proc codeListing(c: PCtx, result: var string, start=0; last = -1) =
+  # first iteration: compute all necessary labels:
+  var jumpTargets = initIntSet()
+  let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1)
+  for i in start..last:
+    let x = c.code[i]
+    if x.opcode in relativeJumps:
+      jumpTargets.incl(i+x.regBx-wordExcess)
+
+  # for debugging purposes
+  var i = start
+  while i <= last:
+    if i in jumpTargets: result.addf("L$1:\n", i)
+    let x = c.code[i]
+
+    result.add($i)
+    let opc = opcode(x)
+    if opc in {opcConv, opcCast}:
+      let y = c.code[i+1]
+      let z = c.code[i+2]
+      result.addf("\t$#\tr$#, r$#, $#, $#", ($opc).substr(3), x.regA, x.regB,
+        c.types[y.regBx-wordExcess].typeToString,
+        c.types[z.regBx-wordExcess].typeToString)
+      inc i, 2
+    elif opc < firstABxInstr:
+      result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
+                  x.regB, x.regC)
+    elif opc in relativeJumps:
+      result.addf("\t$#\tr$#, L$#", ($opc).substr(3), x.regA,
+                  i+x.regBx-wordExcess)
+    elif opc in {opcLdConst, opcAsgnConst}:
+      result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
+        c.constants[x.regBx-wordExcess].renderTree)
+    elif opc in {opcMarshalLoad, opcMarshalStore}:
+      let y = c.code[i+1]
+      result.addf("\t$#\tr$#, r$#, $#", ($opc).substr(3), x.regA, x.regB,
+        c.types[y.regBx-wordExcess].typeToString)
+      inc i
+    else:
+      result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
+    result.add("\t#")
+    result.add(debugInfo(c.debug[i]))
+    result.add("\n")
+    inc i
+
+proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} =
+  var buf = ""
+  codeListing(c, buf, start, last)
+  echo buf
+
+proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) =
+  ## Takes the registers `b` and `c`, applies the operation `opc` to them, and
+  ## stores the result into register `a`
+  ## The node is needed for debug information
+  assert opc.ord < 255
+  let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
+                           (b.uint32 shl 16'u32) or
+                           (c.uint32 shl 24'u32)).TInstr
+  ctx.code.add(ins)
+  ctx.debug.add(n.info)
+
+proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
+  # Takes the `b` register and the immediate `imm`, appies the operation `opc`,
+  # and stores the output value into `a`.
+  # `imm` is signed and must be within [-127, 128]
+  if imm >= -127 and imm <= 128:
+    let ins = (opc.uint32 or (a.uint32 shl 8'u32) or
+                             (b.uint32 shl 16'u32) or
+                             (imm+byteExcess).uint32 shl 24'u32).TInstr
+    c.code.add(ins)
+    c.debug.add(n.info)
+  else:
+    localError(n.info, errGenerated,
+      "VM: immediate value does not fit into an int8")
+
+proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
+  # Applies `opc` to `bx` and stores it into register `a`
+  # `bx` must be signed and in the range [-32767, 32768]
+  if bx >= -32767 and bx <= 32768:
+    let ins = (opc.uint32 or a.uint32 shl 8'u32 or
+              (bx+wordExcess).uint32 shl 16'u32).TInstr
+    c.code.add(ins)
+    c.debug.add(n.info)
+  else:
+    localError(n.info, errGenerated,
+      "VM: immediate value does not fit into an int16")
+
+proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
+  #assert opc in {opcJmp, opcFJmp, opcTJmp}
+  result = TPosition(c.code.len)
+  gABx(c, n, opc, a, 0)
+
+proc genLabel(c: PCtx): TPosition =
+  result = TPosition(c.code.len)
+  #c.jumpTargets.incl(c.code.len)
+
+proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) =
+  let dist = p.int - c.code.len
+  internalAssert(-0x7fff < dist and dist < 0x7fff)
+  gABx(c, n, opcJmpBack, 0, dist)
+
+proc patch(c: PCtx, p: TPosition) =
+  # patch with current index
+  let p = p.int
+  let diff = c.code.len - p
+  #c.jumpTargets.incl(c.code.len)
+  internalAssert(-0x7fff < diff and diff < 0x7fff)
+  let oldInstr = c.code[p]
+  # opcode and regA stay the same:
+  c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
+               uint32(diff+wordExcess) shl 16'u32).TInstr
+
+proc getSlotKind(t: PType): TSlotKind =
+  case t.skipTypes(abstractRange-{tyTypeDesc}).kind
+  of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
+    slotTempInt
+  of tyString, tyCString:
+    slotTempStr
+  of tyFloat..tyFloat128:
+    slotTempFloat
+  else:
+    slotTempComplex
+
+const
+  HighRegisterPressure = 40
+
+proc getTemp(c: PCtx; typ: PType): TRegister =
+  let c = c.prc
+  # we prefer the same slot kind here for efficiency. Unfortunately for
+  # discardable return types we may not know the desired type. This can happen
+  # for e.g. mNAdd[Multiple]:
+  let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
+  for i in 0 .. c.maxSlots-1:
+    if c.slots[i].kind == k and not c.slots[i].inUse:
+      c.slots[i].inUse = true
+      return TRegister(i)
+
+  # if register pressure is high, we re-use more aggressively:
+  if c.maxSlots >= HighRegisterPressure:
+    for i in 0 .. c.maxSlots-1:
+      if not c.slots[i].inUse:
+        c.slots[i] = (inUse: true, kind: k)
+        return TRegister(i)
+  if c.maxSlots >= high(TRegister):
+    internalError("cannot generate code; too many registers required")
+  result = TRegister(c.maxSlots)
+  c.slots[c.maxSlots] = (inUse: true, kind: k)
+  inc c.maxSlots
+
+proc freeTemp(c: PCtx; r: TRegister) =
+  let c = c.prc
+  if c.slots[r].kind in {slotSomeTemp..slotTempComplex}: c.slots[r].inUse = false
+
+proc getTempRange(c: PCtx; n: int; kind: TSlotKind): TRegister =
+  # if register pressure is high, we re-use more aggressively:
+  let c = c.prc
+  if c.maxSlots >= HighRegisterPressure or c.maxSlots+n >= high(TRegister):
+    for i in 0 .. c.maxSlots-n:
+      if not c.slots[i].inUse:
+        block search:
+          for j in i+1 .. i+n-1:
+            if c.slots[j].inUse: break search
+          result = TRegister(i)
+          for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
+          return
+  if c.maxSlots+n >= high(TRegister):
+    internalError("cannot generate code; too many registers required")
+  result = TRegister(c.maxSlots)
+  inc c.maxSlots, n
+  for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
+
+proc freeTempRange(c: PCtx; start: TRegister, n: int) =
+  for i in start .. start+n-1: c.freeTemp(TRegister(i))
+
+template withTemp(tmp, typ: expr, body: stmt) {.immediate, dirty.} =
+  var tmp = getTemp(c, typ)
+  body
+  c.freeTemp(tmp)
+
+proc popBlock(c: PCtx; oldLen: int) =
+  for f in c.prc.blocks[oldLen].fixups:
+    c.patch(f)
+  c.prc.blocks.setLen(oldLen)
+
+template withBlock(labl: PSym; body: stmt) {.immediate, dirty.} =
+  var oldLen {.gensym.} = c.prc.blocks.len
+  c.prc.blocks.add TBlock(label: labl, fixups: @[])
+  body
+  popBlock(c, oldLen)
+
+proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
+proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
+  var d: TDest = dest
+  gen(c, n, d, flags)
+  internalAssert d == dest
+
+proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
+  var tmp: TDest = -1
+  gen(c, n, tmp, flags)
+  #if n.typ.isEmptyType: InternalAssert tmp < 0
+
+proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
+  var tmp: TDest = -1
+  gen(c, n, tmp, flags)
+  internalAssert tmp >= 0
+  result = TRegister(tmp)
+
+proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
+  # stmt is different from 'void' in meta programming contexts.
+  # So we only set dest to -1 if 'void':
+  if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
+    c.freeTemp(dest)
+    dest = -1
+
+proc isNotOpr(n: PNode): bool =
+  n.kind in nkCallKinds and n.sons[0].kind == nkSym and
+    n.sons[0].sym.magic == mNot
+
+proc isTrue(n: PNode): bool =
+  n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
+    n.kind == nkIntLit and n.intVal != 0
+
+proc genWhile(c: PCtx; n: PNode) =
+  # L1:
+  #   cond, tmp
+  #   fjmp tmp, L2
+  #   body
+  #   jmp L1
+  # L2:
+  let L1 = c.genLabel
+  withBlock(nil):
+    if isTrue(n.sons[0]):
+      c.gen(n.sons[1])
+      c.jmpBack(n, L1)
+    elif isNotOpr(n.sons[0]):
+      var tmp = c.genx(n.sons[0].sons[1])
+      let L2 = c.xjmp(n, opcTJmp, tmp)
+      c.freeTemp(tmp)
+      c.gen(n.sons[1])
+      c.jmpBack(n, L1)
+      c.patch(L2)
+    else:
+      var tmp = c.genx(n.sons[0])
+      let L2 = c.xjmp(n, opcFJmp, tmp)
+      c.freeTemp(tmp)
+      c.gen(n.sons[1])
+      c.jmpBack(n, L1)
+      c.patch(L2)
+
+proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
+  withBlock(n.sons[0].sym):
+    c.gen(n.sons[1], dest)
+  c.clearDest(n, dest)
+
+proc genBreak(c: PCtx; n: PNode) =
+  let L1 = c.xjmp(n, opcJmp)
+  if n.sons[0].kind == nkSym:
+    #echo cast[int](n.sons[0].sym)
+    for i in countdown(c.prc.blocks.len-1, 0):
+      if c.prc.blocks[i].label == n.sons[0].sym:
+        c.prc.blocks[i].fixups.add L1
+        return
+    internalError(n.info, "cannot find 'break' target")
+  else:
+    c.prc.blocks[c.prc.blocks.high].fixups.add L1
+
+proc genIf(c: PCtx, n: PNode; dest: var TDest) =
+  #  if (!expr1) goto L1;
+  #    thenPart
+  #    goto LEnd
+  #  L1:
+  #  if (!expr2) goto L2;
+  #    thenPart2
+  #    goto LEnd
+  #  L2:
+  #    elsePart
+  #  Lend:
+  if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
+  var endings: seq[TPosition] = @[]
+  for i in countup(0, len(n) - 1):
+    var it = n.sons[i]
+    if it.len == 2:
+      withTemp(tmp, it.sons[0].typ):
+        var elsePos: TPosition
+        if isNotOpr(it.sons[0]):
+          c.gen(it.sons[0].sons[1], tmp)
+          elsePos = c.xjmp(it.sons[0].sons[1], opcTJmp, tmp) # if true
+        else:
+          c.gen(it.sons[0], tmp)
+          elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
+      c.clearDest(n, dest)
+      c.gen(it.sons[1], dest) # then part
+      if i < sonsLen(n)-1:
+        endings.add(c.xjmp(it.sons[1], opcJmp, 0))
+      c.patch(elsePos)
+    else:
+      c.clearDest(n, dest)
+      c.gen(it.sons[0], dest)
+  for endPos in endings: c.patch(endPos)
+  c.clearDest(n, dest)
+
+proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
+  #   asgn dest, a
+  #   tjmp|fjmp L1
+  #   asgn dest, b
+  # L1:
+  if dest < 0: dest = getTemp(c, n.typ)
+  c.gen(n.sons[1], dest)
+  let L1 = c.xjmp(n, opc, dest)
+  c.gen(n.sons[2], dest)
+  c.patch(L1)
+
+proc canonValue*(n: PNode): PNode =
+  result = n
+
+proc rawGenLiteral(c: PCtx; n: PNode): int =
+  result = c.constants.len
+  assert(n.kind != nkCall)
+  n.flags.incl nfAllConst
+  c.constants.add n.canonValue
+  internalAssert result < 0x7fff
+
+proc sameConstant*(a, b: PNode): bool =
+  result = false
+  if a == b:
+    result = true
+  elif a != nil and b != nil and a.kind == b.kind:
+    case a.kind
+    of nkSym: result = a.sym == b.sym
+    of nkIdent: result = a.ident.id == b.ident.id
+    of nkCharLit..nkUInt64Lit: result = a.intVal == b.intVal
+    of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
+    of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal
+    of nkType, nkNilLit: result = a.typ == b.typ
+    of nkEmpty: result = true
+    else:
+      if sonsLen(a) == sonsLen(b):
+        for i in countup(0, sonsLen(a) - 1):
+          if not sameConstant(a.sons[i], b.sons[i]): return
+        result = true
+
+proc genLiteral(c: PCtx; n: PNode): int =
+  # types do not matter here:
+  for i in 0 .. <c.constants.len:
+    if sameConstant(c.constants[i], n): return i
+  result = rawGenLiteral(c, n)
+
+proc unused(n: PNode; x: TDest) {.inline.} =
+  if x >= 0:
+    #debug(n)
+    internalError(n.info, "not unused")
+
+proc genCase(c: PCtx; n: PNode; dest: var TDest) =
+  #  if (!expr1) goto L1;
+  #    thenPart
+  #    goto LEnd
+  #  L1:
+  #  if (!expr2) goto L2;
+  #    thenPart2
+  #    goto LEnd
+  #  L2:
+  #    elsePart
+  #  Lend:
+  if not isEmptyType(n.typ):
+    if dest < 0: dest = getTemp(c, n.typ)
+  else:
+    unused(n, dest)
+  var endings: seq[TPosition] = @[]
+  withTemp(tmp, n.sons[0].typ):
+    c.gen(n.sons[0], tmp)
+    # branch tmp, codeIdx
+    # fjmp   elseLabel
+    for i in 1 .. <n.len:
+      let it = n.sons[i]
+      if it.len == 1:
+        # else stmt:
+        c.gen(it.sons[0], dest)
+      else:
+        let b = rawGenLiteral(c, it)
+        c.gABx(it, opcBranch, tmp, b)
+        let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
+        c.gen(it.lastSon, dest)
+        if i < sonsLen(n)-1:
+          endings.add(c.xjmp(it.lastSon, opcJmp, 0))
+        c.patch(elsePos)
+      c.clearDest(n, dest)
+  for endPos in endings: c.patch(endPos)
+
+proc genType(c: PCtx; typ: PType): int =
+  for i, t in c.types:
+    if sameType(t, typ): return i
+  result = c.types.len
+  c.types.add(typ)
+  internalAssert(result <= 0x7fff)
+
+proc genTry(c: PCtx; n: PNode; dest: var TDest) =
+  if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
+  var endings: seq[TPosition] = @[]
+  let elsePos = c.xjmp(n, opcTry, 0)
+  c.gen(n.sons[0], dest)
+  c.clearDest(n, dest)
+  c.patch(elsePos)
+  for i in 1 .. <n.len:
+    let it = n.sons[i]
+    if it.kind != nkFinally:
+      var blen = len(it)
+      # first opcExcept contains the end label of the 'except' block:
+      let endExcept = c.xjmp(it, opcExcept, 0)
+      for j in countup(0, blen - 2):
+        assert(it.sons[j].kind == nkType)
+        let typ = it.sons[j].typ.skipTypes(abstractPtrs-{tyTypeDesc})
+        c.gABx(it, opcExcept, 0, c.genType(typ))
+      if blen == 1:
+        # general except section:
+        c.gABx(it, opcExcept, 0, 0)
+      c.gen(it.lastSon, dest)
+      c.clearDest(n, dest)
+      if i < sonsLen(n)-1:
+        endings.add(c.xjmp(it, opcJmp, 0))
+      c.patch(endExcept)
+  for endPos in endings: c.patch(endPos)
+  let fin = lastSon(n)
+  # we always generate an 'opcFinally' as that pops the safepoint
+  # from the stack
+  c.gABx(fin, opcFinally, 0, 0)
+  if fin.kind == nkFinally:
+    c.gen(fin.sons[0])
+    c.clearDest(n, dest)
+  c.gABx(fin, opcFinallyEnd, 0, 0)
+
+proc genRaise(c: PCtx; n: PNode) =
+  let dest = genx(c, n.sons[0])
+  c.gABC(n, opcRaise, dest)
+  c.freeTemp(dest)
+
+proc genReturn(c: PCtx; n: PNode) =
+  if n.sons[0].kind != nkEmpty:
+    gen(c, n.sons[0])
+  c.gABC(n, opcRet)
+
+proc genCall(c: PCtx; n: PNode; dest: var TDest) =
+  if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
+  let x = c.getTempRange(n.len, slotTempUnknown)
+  # varargs need 'opcSetType' for the FFI support:
+  let fntyp = n.sons[0].typ
+  for i in 0.. <n.len:
+    var r: TRegister = x+i
+    c.gen(n.sons[i], r)
+    if i >= fntyp.len:
+      internalAssert tfVarargs in fntyp.flags
+      c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ))
+  if dest < 0:
+    c.gABC(n, opcIndCall, 0, x, n.len)
+  else:
+    c.gABC(n, opcIndCallAsgn, dest, x, n.len)
+  c.freeTempRange(x, n.len)
+
+template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
+proc isGlobal(n: PNode): bool = n.kind == nkSym and isGlobal(n.sym)
+
+proc needsAsgnPatch(n: PNode): bool =
+  n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
+             nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
+
+proc genField(n: PNode): TRegister =
+  if n.kind != nkSym or n.sym.kind != skField:
+    internalError(n.info, "no field symbol")
+  let s = n.sym
+  if s.position > high(result):
+      internalError(n.info,
+        "too large offset! cannot generate code for: " & s.name.s)
+  result = s.position
+
+proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
+  if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(arr);
+      x != 0):
+    let tmp = c.genx(n)
+    # freeing the temporary here means we can produce:  regA = regA - Imm
+    c.freeTemp(tmp)
+    result = c.getTemp(n.typ)
+    c.gABI(n, opcSubImmInt, result, tmp, x.int)
+  else:
+    result = c.genx(n)
+
+proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
+  case le.kind
+  of nkBracketExpr:
+    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let idx = c.genIndex(le.sons[1], le.sons[0].typ)
+    c.gABC(le, opcWrArr, dest, idx, value)
+    c.freeTemp(dest)
+    c.freeTemp(idx)
+  of nkDotExpr, nkCheckedFieldExpr:
+    # XXX field checks here
+    let left = if le.kind == nkDotExpr: le else: le.sons[0]
+    let dest = c.genx(left.sons[0], {gfAddrOf})
+    let idx = genField(left.sons[1])
+    c.gABC(left, opcWrObj, dest, idx, value)
+    c.freeTemp(dest)
+  of nkDerefExpr, nkHiddenDeref:
+    let dest = c.genx(le.sons[0], {gfAddrOf})
+    c.gABC(le, opcWrDeref, dest, 0, value)
+    c.freeTemp(dest)
+  of nkSym:
+    if le.sym.isGlobal:
+      let dest = c.genx(le, {gfAddrOf})
+      c.gABC(le, opcWrDeref, dest, 0, value)
+      c.freeTemp(dest)
+  else:
+    discard
+
+proc genNew(c: PCtx; n: PNode) =
+  let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
+             else: c.genx(n.sons[1])
+  # we use the ref's base type here as the VM conflates 'ref object'
+  # and 'object' since internally we already have a pointer.
+  c.gABx(n, opcNew, dest,
+         c.genType(n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).sons[0]))
+  c.genAsgnPatch(n.sons[1], dest)
+  c.freeTemp(dest)
+
+proc genNewSeq(c: PCtx; n: PNode) =
+  let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
+             else: c.genx(n.sons[1])
+  let tmp = c.genx(n.sons[2])
+  c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(
+                                                  abstractVar-{tyTypeDesc})))
+  c.gABx(n, opcNewSeq, tmp, 0)
+  c.freeTemp(tmp)
+  c.genAsgnPatch(n.sons[1], dest)
+  c.freeTemp(dest)
+
+proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  let tmp = c.genx(n.sons[1])
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABC(n, opc, dest, tmp)
+  c.freeTemp(tmp)
+
+proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  let tmp = c.genx(n.sons[1])
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABI(n, opc, dest, tmp, 0)
+  c.freeTemp(tmp)
+
+proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  let
+    tmp = c.genx(n.sons[1])
+    tmp2 = c.genx(n.sons[2])
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABC(n, opc, dest, tmp, tmp2)
+  c.freeTemp(tmp)
+  c.freeTemp(tmp2)
+
+proc genNarrow(c: PCtx; n: PNode; dest: TDest) =
+  let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
+  # uint is uint64 in the VM, we we only need to mask the result for
+  # other unsigned types:
+  if t.kind in {tyUInt8..tyUInt32}:
+    c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
+  elif t.kind in {tyInt8..tyInt32}:
+    c.gABC(n, opcNarrowS, dest, TRegister(t.size*8))
+
+proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
+  let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
+  # uint is uint64 in the VM, we we only need to mask the result for
+  # other unsigned types:
+  if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
+      (t.kind == tyInt and t.size == 4):
+    c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
+
+proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  genBinaryABC(c, n, dest, opc)
+  genNarrow(c, n, dest)
+
+proc genBinaryABCnarrowU(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  genBinaryABC(c, n, dest, opc)
+  genNarrowU(c, n, dest)
+
+proc genSetType(c: PCtx; n: PNode; dest: TRegister) =
+  let t = skipTypes(n.typ, abstractInst-{tyTypeDesc})
+  if t.kind == tySet:
+    c.gABx(n, opcSetType, dest, c.genType(t))
+
+proc genBinarySet(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  let
+    tmp = c.genx(n.sons[1])
+    tmp2 = c.genx(n.sons[2])
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.genSetType(n.sons[1], tmp)
+  c.genSetType(n.sons[2], tmp2)
+  c.gABC(n, opc, dest, tmp, tmp2)
+  c.freeTemp(tmp)
+  c.freeTemp(tmp2)
+
+proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
+  let
+    dest = c.genx(n.sons[1])
+    tmp = c.genx(n.sons[2])
+  c.gABC(n, opc, dest, tmp, 0)
+  c.freeTemp(tmp)
+
+proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
+  var x = n.sons[1]
+  if x.kind in {nkAddr, nkHiddenAddr}: x = x.sons[0]
+  let
+    dest = c.genx(x)
+    tmp = c.genx(n.sons[2])
+  c.gABC(n, opc, dest, tmp, 0)
+  #c.genAsgnPatch(n.sons[1], dest)
+  c.freeTemp(tmp)
+
+proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
+  let tmp = c.genx(n.sons[1])
+  c.gABC(n, opc, tmp, 0, 0)
+  c.freeTemp(tmp)
+
+proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  if dest < 0: dest = getTemp(c, n.typ)
+  var x = c.getTempRange(n.len-1, slotTempStr)
+  for i in 1..n.len-1:
+    var r: TRegister = x+i-1
+    c.gen(n.sons[i], r)
+  c.gABC(n, opc, dest, x, n.len-1)
+  c.freeTempRange(x, n.len)
+
+proc isInt8Lit(n: PNode): bool =
+  if n.kind in {nkCharLit..nkUInt64Lit}:
+    result = n.intVal >= low(int8) and n.intVal <= high(int8)
+
+proc isInt16Lit(n: PNode): bool =
+  if n.kind in {nkCharLit..nkUInt64Lit}:
+    result = n.intVal >= low(int16) and n.intVal <= high(int16)
+
+proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
+  if n.sons[2].isInt8Lit:
+    let tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABI(n, succ(opc), dest, tmp, n.sons[2].intVal)
+    c.freeTemp(tmp)
+  else:
+    genBinaryABC(c, n, dest, opc)
+  c.genNarrow(n, dest)
+
+proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
+  let tmp = c.genx(arg)
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABC(n, opc, dest, tmp)
+  c.gABx(n, opc, 0, genType(c, n.typ))
+  c.gABx(n, opc, 0, genType(c, arg.typ))
+  c.freeTemp(tmp)
+
+proc genCard(c: PCtx; n: PNode; dest: var TDest) =
+  let tmp = c.genx(n.sons[1])
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.genSetType(n.sons[1], tmp)
+  c.gABC(n, opcCard, dest, tmp)
+  c.freeTemp(tmp)
+
+proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
+  case m
+  of mAnd: c.genAndOr(n, opcFJmp, dest)
+  of mOr:  c.genAndOr(n, opcTJmp, dest)
+  of mUnaryLt:
+    let tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABI(n, opcSubImmInt, dest, tmp, 1)
+    c.freeTemp(tmp)
+  of mPred, mSubI, mSubI64:
+    c.genAddSubInt(n, dest, opcSubInt)
+  of mSucc, mAddI, mAddI64:
+    c.genAddSubInt(n, dest, opcAddInt)
+  of mInc, mDec:
+    unused(n, dest)
+    let opc = if m == mInc: opcAddInt else: opcSubInt
+    let d = c.genx(n.sons[1])
+    if n.sons[2].isInt8Lit:
+      c.gABI(n, succ(opc), d, d, n.sons[2].intVal)
+    else:
+      let tmp = c.genx(n.sons[2])
+      c.gABC(n, opc, d, d, tmp)
+      c.freeTemp(tmp)
+    c.genNarrow(n.sons[1], d)
+    c.genAsgnPatch(n.sons[1], d)
+    c.freeTemp(d)
+  of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest)
+  of mNew, mNewFinalize:
+    unused(n, dest)
+    c.genNew(n)
+  of mNewSeq:
+    unused(n, dest)
+    c.genNewSeq(n)
+  of mNewString:
+    genUnaryABC(c, n, dest, opcNewStr)
+    # XXX buggy
+  of mNewStringOfCap:
+    # we ignore the 'cap' argument and translate it as 'newString(0)'.
+    # eval n.sons[1] for possible side effects:
+    var tmp = c.genx(n.sons[1])
+    c.gABx(n, opcLdImmInt, tmp, 0)
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcNewStr, dest, tmp)
+    c.freeTemp(tmp)
+    # XXX buggy
+  of mLengthOpenArray, mLengthArray, mLengthSeq, mXLenSeq:
+    genUnaryABI(c, n, dest, opcLenSeq)
+  of mLengthStr, mXLenStr:
+    genUnaryABI(c, n, dest, opcLenStr)
+  of mIncl, mExcl:
+    unused(n, dest)
+    var d = c.genx(n.sons[1])
+    var tmp = c.genx(n.sons[2])
+    c.genSetType(n.sons[1], d)
+    c.gABC(n, if m == mIncl: opcIncl else: opcExcl, d, tmp)
+    c.freeTemp(d)
+    c.freeTemp(tmp)
+  of mCard: genCard(c, n, dest)
+  of mMulI, mMulI64: genBinaryABCnarrow(c, n, dest, opcMulInt)
+  of mDivI, mDivI64: genBinaryABCnarrow(c, n, dest, opcDivInt)
+  of mModI, mModI64: genBinaryABCnarrow(c, n, dest, opcModInt)
+  of mAddF64: genBinaryABC(c, n, dest, opcAddFloat)
+  of mSubF64: genBinaryABC(c, n, dest, opcSubFloat)
+  of mMulF64: genBinaryABC(c, n, dest, opcMulFloat)
+  of mDivF64: genBinaryABC(c, n, dest, opcDivFloat)
+  of mShrI, mShrI64: genBinaryABCnarrowU(c, n, dest, opcShrInt)
+  of mShlI, mShlI64: genBinaryABCnarrowU(c, n, dest, opcShlInt)
+  of mBitandI, mBitandI64: genBinaryABCnarrowU(c, n, dest, opcBitandInt)
+  of mBitorI, mBitorI64: genBinaryABCnarrowU(c, n, dest, opcBitorInt)
+  of mBitxorI, mBitxorI64: genBinaryABCnarrowU(c, n, dest, opcBitxorInt)
+  of mAddU: genBinaryABCnarrowU(c, n, dest, opcAddu)
+  of mSubU: genBinaryABCnarrowU(c, n, dest, opcSubu)
+  of mMulU: genBinaryABCnarrowU(c, n, dest, opcMulu)
+  of mDivU: genBinaryABCnarrowU(c, n, dest, opcDivu)
+  of mModU: genBinaryABCnarrowU(c, n, dest, opcModu)
+  of mEqI, mEqI64, mEqB, mEqEnum, mEqCh:
+    genBinaryABC(c, n, dest, opcEqInt)
+  of mLeI, mLeI64, mLeEnum, mLeCh, mLeB:
+    genBinaryABC(c, n, dest, opcLeInt)
+  of mLtI, mLtI64, mLtEnum, mLtCh, mLtB:
+    genBinaryABC(c, n, dest, opcLtInt)
+  of mEqF64: genBinaryABC(c, n, dest, opcEqFloat)
+  of mLeF64: genBinaryABC(c, n, dest, opcLeFloat)
+  of mLtF64: genBinaryABC(c, n, dest, opcLtFloat)
+  of mLePtr, mLeU, mLeU64: genBinaryABC(c, n, dest, opcLeu)
+  of mLtPtr, mLtU, mLtU64: genBinaryABC(c, n, dest, opcLtu)
+  of mEqProc, mEqRef, mEqUntracedRef, mEqCString:
+    genBinaryABC(c, n, dest, opcEqRef)
+  of mXor: genBinaryABCnarrowU(c, n, dest, opcXor)
+  of mNot: genUnaryABC(c, n, dest, opcNot)
+  of mUnaryMinusI, mUnaryMinusI64:
+    genUnaryABC(c, n, dest, opcUnaryMinusInt)
+    genNarrow(c, n, dest)
+  of mUnaryMinusF64: genUnaryABC(c, n, dest, opcUnaryMinusFloat)
+  of mUnaryPlusI, mUnaryPlusF64: gen(c, n.sons[1], dest)
+  of mBitnotI, mBitnotI64:
+    genUnaryABC(c, n, dest, opcBitnotInt)
+    genNarrowU(c, n, dest)
+  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
+     mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt,
+     mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
+     mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
+    genConv(c, n, n.sons[1], dest)
+  of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
+  of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
+  of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
+  of mEqSet: genBinarySet(c, n, dest, opcEqSet)
+  of mLeSet: genBinarySet(c, n, dest, opcLeSet)
+  of mLtSet: genBinarySet(c, n, dest, opcLtSet)
+  of mMulSet: genBinarySet(c, n, dest, opcMulSet)
+  of mPlusSet: genBinarySet(c, n, dest, opcPlusSet)
+  of mMinusSet: genBinarySet(c, n, dest, opcMinusSet)
+  of mSymDiffSet: genBinarySet(c, n, dest, opcSymdiffSet)
+  of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr)
+  of mInSet: genBinarySet(c, n, dest, opcContainsSet)
+  of mRepr: genUnaryABC(c, n, dest, opcRepr)
+  of mExit:
+    unused(n, dest)
+    var tmp = c.genx(n.sons[1])
+    c.gABC(n, opcQuit, tmp)
+    c.freeTemp(tmp)
+  of mSetLengthStr, mSetLengthSeq:
+    unused(n, dest)
+    var d = c.genx(n.sons[1])
+    var tmp = c.genx(n.sons[2])
+    c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
+    c.genAsgnPatch(n.sons[1], d)
+    c.freeTemp(tmp)
+  of mSwap:
+    unused(n, dest)
+    var
+      d1 = c.genx(n.sons[1])
+      d2 = c.genx(n.sons[2])
+    c.gABC(n, opcSwap, d1, d2)
+    c.genAsgnPatch(n.sons[1], d1)
+    c.genAsgnPatch(n.sons[2], d2)
+  of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
+  of mCopyStr:
+    if dest < 0: dest = c.getTemp(n.typ)
+    var
+      tmp1 = c.genx(n.sons[1])
+      tmp2 = c.genx(n.sons[2])
+      tmp3 = c.getTemp(n.sons[2].typ)
+    c.gABC(n, opcLenStr, tmp3, tmp1)
+    c.gABC(n, opcSubStr, dest, tmp1, tmp2)
+    c.gABC(n, opcSubStr, tmp3)
+    c.freeTemp(tmp1)
+    c.freeTemp(tmp2)
+    c.freeTemp(tmp3)
+  of mCopyStrLast:
+    if dest < 0: dest = c.getTemp(n.typ)
+    var
+      tmp1 = c.genx(n.sons[1])
+      tmp2 = c.genx(n.sons[2])
+      tmp3 = c.genx(n.sons[3])
+    c.gABC(n, opcSubStr, dest, tmp1, tmp2)
+    c.gABC(n, opcSubStr, tmp3)
+    c.freeTemp(tmp1)
+    c.freeTemp(tmp2)
+    c.freeTemp(tmp3)
+  of mParseBiggestFloat:
+    if dest < 0: dest = c.getTemp(n.typ)
+    var d2: TRegister
+    # skip 'nkHiddenAddr':
+    let d2AsNode = n.sons[2].sons[0]
+    if needsAsgnPatch(d2AsNode):
+      d2 = c.getTemp(getSysType(tyFloat))
+    else:
+      d2 = c.genx(d2AsNode)
+    var
+      tmp1 = c.genx(n.sons[1])
+      tmp3 = c.genx(n.sons[3])
+    c.gABC(n, opcParseFloat, dest, tmp1, d2)
+    c.gABC(n, opcParseFloat, tmp3)
+    c.freeTemp(tmp1)
+    c.freeTemp(tmp3)
+    c.genAsgnPatch(d2AsNode, d2)
+    c.freeTemp(d2)
+  of mReset:
+    unused(n, dest)
+    var d = c.genx(n.sons[1])
+    c.gABC(n, opcReset, d)
+  of mOf, mIs:
+    if dest < 0: dest = c.getTemp(n.typ)
+    var tmp = c.genx(n.sons[1])
+    var idx = c.getTemp(getSysType(tyInt))
+    var typ = n.sons[2].typ
+    if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
+    c.gABx(n, opcLdImmInt, idx, c.genType(typ))
+    c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
+    c.freeTemp(tmp)
+    c.freeTemp(idx)
+  of mSizeOf:
+    globalError(n.info, errCannotInterpretNodeX, renderTree(n))
+  of mHigh:
+    if dest < 0: dest = c.getTemp(n.typ)
+    let tmp = c.genx(n.sons[1])
+    case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
+    of tyString, tyCString:
+      c.gABI(n, opcLenStr, dest, tmp, 1)
+    else:
+      c.gABI(n, opcLenSeq, dest, tmp, 1)
+    c.freeTemp(tmp)
+  of mEcho:
+    unused(n, dest)
+    let n = n[1].skipConv
+    let x = c.getTempRange(n.len, slotTempUnknown)
+    internalAssert n.kind == nkBracket
+    for i in 0.. <n.len:
+      var r: TRegister = x+i
+      c.gen(n.sons[i], r)
+    c.gABC(n, opcEcho, x, n.len)
+    c.freeTempRange(x, n.len)
+  of mAppendStrCh:
+    unused(n, dest)
+    genBinaryStmtVar(c, n, opcAddStrCh)
+  of mAppendStrStr:
+    unused(n, dest)
+    genBinaryStmtVar(c, n, opcAddStrStr)
+  of mAppendSeqElem:
+    unused(n, dest)
+    genBinaryStmtVar(c, n, opcAddSeqElem)
+  of mParseExprToAst:
+    genUnaryABC(c, n, dest, opcParseExprToAst)
+  of mParseStmtToAst:
+    genUnaryABC(c, n, dest, opcParseStmtToAst)
+  of mTypeTrait:
+    let tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
+    c.gABC(n, opcTypeTrait, dest, tmp)
+    c.freeTemp(tmp)
+  of mSlurp: genUnaryABC(c, n, dest, opcSlurp)
+  of mStaticExec: genBinaryABC(c, n, dest, opcGorge)
+  of mNLen: genUnaryABI(c, n, dest, opcLenSeq)
+  of mNChild: genBinaryABC(c, n, dest, opcNChild)
+  of mNSetChild, mNDel:
+    unused(n, dest)
+    var
+      tmp1 = c.genx(n.sons[1])
+      tmp2 = c.genx(n.sons[2])
+      tmp3 = c.genx(n.sons[3])
+    c.gABC(n, if m == mNSetChild: opcNSetChild else: opcNDel, tmp1, tmp2, tmp3)
+    c.freeTemp(tmp1)
+    c.freeTemp(tmp2)
+    c.freeTemp(tmp3)
+  of mNAdd: genBinaryABC(c, n, dest, opcNAdd)
+  of mNAddMultiple: genBinaryABC(c, n, dest, opcNAddMultiple)
+  of mNKind: genUnaryABC(c, n, dest, opcNKind)
+  of mNIntVal: genUnaryABC(c, n, dest, opcNIntVal)
+  of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
+  of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
+  of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
+  of mNGetType:
+    let tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
+    c.freeTemp(tmp)
+    #genUnaryABC(c, n, dest, opcNGetType)
+  of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
+  of mNSetIntVal:
+    unused(n, dest)
+    genBinaryStmt(c, n, opcNSetIntVal)
+  of mNSetFloatVal:
+    unused(n, dest)
+    genBinaryStmt(c, n, opcNSetFloatVal)
+  of mNSetSymbol:
+    unused(n, dest)
+    genBinaryStmt(c, n, opcNSetSymbol)
+  of mNSetIdent:
+    unused(n, dest)
+    genBinaryStmt(c, n, opcNSetIdent)
+  of mNSetType:
+    unused(n, dest)
+    genBinaryStmt(c, n, opcNSetType)
+  of mNSetStrVal:
+    unused(n, dest)
+    genBinaryStmt(c, n, opcNSetStrVal)
+  of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
+  of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
+  of mNCopyNimTree: genUnaryABC(c, n, dest, opcNCopyNimTree)
+  of mNBindSym:
+    if n[1].kind in {nkClosedSymChoice, nkOpenSymChoice, nkSym}:
+      let idx = c.genLiteral(n[1])
+      if dest < 0: dest = c.getTemp(n.typ)
+      c.gABx(n, opcNBindSym, dest, idx)
+    else:
+      internalError(n.info, "invalid bindSym usage")
+  of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
+  of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
+  of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
+  of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
+  of mNLineInfo: genUnaryABC(c, n, dest, opcNLineInfo)
+  of mNHint:
+    unused(n, dest)
+    genUnaryStmt(c, n, opcNHint)
+  of mNWarning:
+    unused(n, dest)
+    genUnaryStmt(c, n, opcNWarning)
+  of mNError:
+    if n.len <= 1:
+      # query error condition:
+      c.gABC(n, opcQueryErrorFlag, dest)
+    else:
+      # setter
+      unused(n, dest)
+      genUnaryStmt(c, n, opcNError)
+  of mNCallSite:
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcCallSite, dest)
+  of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
+  of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
+     mAbsI64, mDotDot:
+    c.genCall(n, dest)
+  of mExpandToAst:
+    if n.len != 2:
+      globalError(n.info, errGenerated, "expandToAst requires 1 argument")
+    let arg = n.sons[1]
+    if arg.kind in nkCallKinds:
+      #if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
+      #      "ExpandToAst: expanded symbol is no macro or template"
+      if dest < 0: dest = c.getTemp(n.typ)
+      c.genCall(arg, dest)
+      # do not call clearDest(n, dest) here as getAst has a meta-type as such
+      # produces a value
+    else:
+      globalError(n.info, "expandToAst requires a call expression")
+  else:
+    # mGCref, mGCunref,
+    internalError(n.info, "cannot generate code for: " & $m)
+
+proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
+  ## Signature: proc to*[T](data: string): T
+  if dest < 0: dest = c.getTemp(n.typ)
+  var tmp = c.genx(n.sons[1])
+  c.gABC(n, opcMarshalLoad, dest, tmp)
+  c.gABx(n, opcMarshalLoad, 0, c.genType(n.typ))
+  c.freeTemp(tmp)
+
+proc genMarshalStore(c: PCtx, n: PNode, dest: var TDest) =
+  ## Signature: proc `$$`*[T](x: T): string
+  if dest < 0: dest = c.getTemp(n.typ)
+  var tmp = c.genx(n.sons[1])
+  c.gABC(n, opcMarshalStore, dest, tmp)
+  c.gABx(n, opcMarshalStore, 0, c.genType(n.sons[1].typ))
+  c.freeTemp(tmp)
+
+const
+  atomicTypes = {tyBool, tyChar,
+    tyExpr, tyStmt, tyTypeDesc, tyStatic,
+    tyEnum,
+    tyOrdinal,
+    tyRange,
+    tyProc,
+    tyPointer, tyOpenArray,
+    tyString, tyCString,
+    tyInt, tyInt8, tyInt16, tyInt32, tyInt64,
+    tyFloat, tyFloat32, tyFloat64, tyFloat128,
+    tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64}
+
+proc fitsRegister*(t: PType): bool =
+  t.skipTypes(abstractInst-{tyTypeDesc}).kind in {
+    tyRange, tyEnum, tyBool, tyInt..tyUInt64, tyChar}
+
+proc requiresCopy(n: PNode): bool =
+  if n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind in atomicTypes:
+    result = false
+  elif n.kind in ({nkCurly, nkBracket, nkPar, nkObjConstr}+nkCallKinds):
+    result = false
+  else:
+    result = true
+
+proc unneededIndirection(n: PNode): bool =
+  n.typ.skipTypes(abstractInst-{tyTypeDesc}).kind == tyRef
+
+proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
+                  flags: TGenFlags) =
+  # a nop for certain types
+  let isAddr = opc in {opcAddrNode, opcAddrReg}
+  let newflags = if isAddr: flags+{gfAddrOf} else: flags
+  # consider:
+  # proc foo(f: var ref int) =
+  #   f = new(int)
+  # proc blah() =
+  #   var x: ref int
+  #   foo x
+  #
+  # The type of 'f' is 'var ref int' and of 'x' is 'ref int'. Hence for
+  # nkAddr we must not use 'unneededIndirection', but for deref we use it.
+  if not isAddr and unneededIndirection(n.sons[0]):
+    gen(c, n.sons[0], dest, newflags)
+  elif isAddr and isGlobal(n.sons[0]):
+    gen(c, n.sons[0], dest, flags+{gfAddrOf})
+  else:
+    let tmp = c.genx(n.sons[0], newflags)
+    if dest < 0: dest = c.getTemp(n.typ)
+    if not isAddr:
+      gABC(c, n, opc, dest, tmp)
+      if gfAddrOf notin flags and fitsRegister(n.typ):
+        c.gABC(n, opcNodeToReg, dest, dest)
+    elif c.prc.slots[tmp].kind >= slotTempUnknown:
+      gABC(c, n, opcAddrNode, dest, tmp)
+      # hack ahead; in order to fix bug #1781 we mark the temporary as
+      # permanent, so that it's not used for anything else:
+      c.prc.slots[tmp].kind = slotTempPerm
+      # XXX this is still a hack
+      #message(n.info, warnUser, "suspicious opcode used")
+    else:
+      gABC(c, n, opcAddrReg, dest, tmp)
+    c.freeTemp(tmp)
+
+proc whichAsgnOpc(n: PNode): TOpcode =
+  case n.typ.skipTypes(abstractRange-{tyTypeDesc}).kind
+  of tyBool, tyChar, tyEnum, tyOrdinal, tyInt..tyInt64, tyUInt..tyUInt64:
+    opcAsgnInt
+  of tyString, tyCString:
+    opcAsgnStr
+  of tyFloat..tyFloat128:
+    opcAsgnFloat
+  of tyRef, tyNil, tyVar:
+    opcAsgnRef
+  else:
+    opcAsgnComplex
+
+proc isRef(t: PType): bool = t.skipTypes(abstractRange-{tyTypeDesc}).kind == tyRef
+
+proc whichAsgnOpc(n: PNode; opc: TOpcode): TOpcode = opc
+
+proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
+  let tmp = c.genx(ri)
+  assert dest >= 0
+  gABC(c, ri, whichAsgnOpc(ri), dest, tmp)
+  c.freeTemp(tmp)
+
+proc setSlot(c: PCtx; v: PSym) =
+  # XXX generate type initialization here?
+  if v.position == 0:
+    if c.prc.maxSlots == 0: c.prc.maxSlots = 1
+    if c.prc.maxSlots >= high(TRegister):
+      internalError(v.info, "cannot generate code; too many registers required")
+    v.position = c.prc.maxSlots
+    c.prc.slots[v.position] = (inUse: true,
+        kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
+    inc c.prc.maxSlots
+
+proc cannotEval(n: PNode) {.noinline.} =
+  globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
+    n.renderTree)
+
+proc isOwnedBy(a, b: PSym): bool =
+  var a = a.owner
+  while a != nil and a.kind != skModule:
+    if a == b: return true
+    a = a.owner
+
+proc getOwner(c: PCtx): PSym =
+  result = c.prc.sym
+  if result.isNil: result = c.module
+
+proc checkCanEval(c: PCtx; n: PNode) =
+  # we need to ensure that we don't evaluate 'x' here:
+  # proc foo() = var x ...
+  let s = n.sym
+  if {sfCompileTime, sfGlobal} <= s.flags: return
+  if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
+      not s.isOwnedBy(c.prc.sym) and s.owner != c.module:
+    cannotEval(n)
+
+proc isTemp(c: PCtx; dest: TDest): bool =
+  result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
+
+template needsAdditionalCopy(n): expr =
+  not c.isTemp(dest) and not fitsRegister(n.typ)
+
+proc skipDeref(n: PNode): PNode =
+  result = if n.kind in {nkDerefExpr, nkHiddenDeref}: n.sons[0] else: n
+
+proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode;
+                       dest, idx, value: TRegister) =
+  # opcLdObj et al really means "load address". We sometimes have to create a
+  # copy in order to not introduce false aliasing:
+  # mylocal = a.b  # needs a copy of the data!
+  if needsAdditionalCopy(n):
+    var cc = c.getTemp(n.typ)
+    c.gABC(n, whichAsgnOpc(n), cc, value)
+    c.gABC(n, opc, dest, idx, cc)
+    c.freeTemp(cc)
+  else:
+    c.gABC(n, opc, dest, idx, value)
+
+proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
+  case le.kind
+  of nkBracketExpr:
+    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let idx = c.genIndex(le.sons[1], le.sons[0].typ)
+    let tmp = c.genx(ri)
+    if le.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
+        tyString, tyCString}:
+      c.preventFalseAlias(le, opcWrStrIdx, dest, idx, tmp)
+    else:
+      c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
+    c.freeTemp(tmp)
+  of nkDotExpr, nkCheckedFieldExpr:
+    # XXX field checks here
+    let left = if le.kind == nkDotExpr: le else: le.sons[0]
+    let dest = c.genx(left.sons[0], {gfAddrOf})
+    let idx = genField(left.sons[1])
+    let tmp = c.genx(ri)
+    c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
+    c.freeTemp(tmp)
+  of nkDerefExpr, nkHiddenDeref:
+    let dest = c.genx(le.sons[0], {gfAddrOf})
+    let tmp = c.genx(ri)
+    c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
+    c.freeTemp(tmp)
+  of nkSym:
+    let s = le.sym
+    checkCanEval(c, le)
+    if s.isGlobal:
+      withTemp(tmp, le.typ):
+        c.gen(le, tmp, {gfAddrOf})
+        let val = c.genx(ri)
+        c.preventFalseAlias(le, opcWrDeref, tmp, 0, val)
+        c.freeTemp(val)
+    else:
+      if s.kind == skForVar: c.setSlot s
+      internalAssert s.position > 0 or (s.position == 0 and
+                                        s.kind in {skParam,skResult})
+      var dest: TRegister = s.position + ord(s.kind == skParam)
+      if needsAdditionalCopy(le) and s.kind in {skResult, skVar, skParam}:
+        var cc = c.getTemp(le.typ)
+        gen(c, ri, cc)
+        c.gABC(le, whichAsgnOpc(le), dest, cc)
+        c.freeTemp(cc)
+      else:
+        gen(c, ri, dest)
+  else:
+    let dest = c.genx(le, {gfAddrOf})
+    genAsgn(c, dest, ri, requiresCopy)
+
+proc genLit(c: PCtx; n: PNode; dest: var TDest) =
+  # opcLdConst is now always valid. We produce the necessary copy in the
+  # assignments now:
+  #var opc = opcLdConst
+  if dest < 0: dest = c.getTemp(n.typ)
+  #elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
+  let lit = genLiteral(c, n)
+  c.gABx(n, opcLdConst, dest, lit)
+
+proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
+  var n = newNode(nkType)
+  n.typ = t
+  genLit(c, n, dest)
+
+proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
+  when hasFFI:
+    if allowFFI in c.features:
+      c.globals.add(importcSymbol(s))
+      s.position = c.globals.len
+    else:
+      localError(info, errGenerated, "VM is not allowed to 'importc'")
+  else:
+    localError(info, errGenerated,
+               "cannot 'importc' variable at compile time")
+
+proc getNullValue*(typ: PType, info: TLineInfo): PNode
+
+proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
+  c.globals.add(getNullValue(s.typ, n.info))
+  s.position = c.globals.len
+  # This is rather hard to support, due to the laziness of the VM code
+  # generator. See tests/compile/tmacro2 for why this is necessary:
+  #   var decls{.compileTime.}: seq[NimNode] = @[]
+  let dest = c.getTemp(s.typ)
+  c.gABx(n, opcLdGlobal, dest, s.position)
+  let tmp = c.genx(s.ast)
+  c.preventFalseAlias(n, opcWrDeref, dest, 0, tmp)
+  c.freeTemp(dest)
+  c.freeTemp(tmp)
+
+proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
+  let s = n.sym
+  if s.isGlobal:
+    if sfCompileTime in s.flags or c.mode == emRepl:
+      discard
+    elif s.position == 0:
+      cannotEval(n)
+    if s.position == 0:
+      if sfImportc in s.flags: c.importcSym(n.info, s)
+      else: genGlobalInit(c, n, s)
+    if dest < 0: dest = c.getTemp(n.typ)
+    if gfAddrOf notin flags and fitsRegister(s.typ):
+      var cc = c.getTemp(n.typ)
+      c.gABx(n, opcLdGlobal, cc, s.position)
+      c.gABC(n, opcNodeToReg, dest, cc)
+      c.freeTemp(cc)
+    elif gfAddrOf in flags:
+      c.gABx(n, opcLdGlobalAddr, dest, s.position)
+    else:
+      c.gABx(n, opcLdGlobal, dest, s.position)
+  else:
+    if s.kind == skForVar and c.mode == emRepl: c.setSlot(s)
+    if s.position > 0 or (s.position == 0 and
+                          s.kind in {skParam,skResult}):
+      if dest < 0:
+        dest = s.position + ord(s.kind == skParam)
+        internalAssert(c.prc.slots[dest].kind < slotSomeTemp)
+      else:
+        # we need to generate an assignment:
+        genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp)
+    else:
+      # see tests/t99bott for an example that triggers it:
+      cannotEval(n)
+
+template needsRegLoad(): expr =
+  gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar}))
+
+proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
+                   flags: TGenFlags) =
+  let a = c.genx(n.sons[0], flags)
+  let b = c.genIndex(n.sons[1], n.sons[0].typ)
+  if dest < 0: dest = c.getTemp(n.typ)
+  if needsRegLoad():
+    var cc = c.getTemp(n.typ)
+    c.gABC(n, opc, cc, a, b)
+    c.gABC(n, opcNodeToReg, dest, cc)
+    c.freeTemp(cc)
+  else:
+    #message(n.info, warnUser, "argh")
+    #echo "FLAGS ", flags, " ", fitsRegister(n.typ), " ", typeToString(n.typ)
+    c.gABC(n, opc, dest, a, b)
+  c.freeTemp(a)
+  c.freeTemp(b)
+
+proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
+  let a = c.genx(n.sons[0], flags)
+  let b = genField(n.sons[1])
+  if dest < 0: dest = c.getTemp(n.typ)
+  if needsRegLoad():
+    var cc = c.getTemp(n.typ)
+    c.gABC(n, opcLdObj, cc, a, b)
+    c.gABC(n, opcNodeToReg, dest, cc)
+    c.freeTemp(cc)
+  else:
+    c.gABC(n, opcLdObj, dest, a, b)
+  c.freeTemp(a)
+
+proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
+  # XXX implement field checks!
+  genObjAccess(c, n.sons[0], dest, flags)
+
+proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
+  if n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind in {
+      tyString, tyCString}:
+    genArrAccess2(c, n, dest, opcLdStrIdx, {})
+  else:
+    genArrAccess2(c, n, dest, opcLdArr, flags)
+
+proc getNullValueAux(obj: PNode, result: PNode) =
+  case obj.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
+  of nkRecCase:
+    getNullValueAux(obj.sons[0], result)
+    for i in countup(1, sonsLen(obj) - 1):
+      getNullValueAux(lastSon(obj.sons[i]), result)
+  of nkSym:
+    addSon(result, getNullValue(obj.sym.typ, result.info))
+  else: internalError(result.info, "getNullValueAux")
+
+proc getNullValue(typ: PType, info: TLineInfo): PNode =
+  var t = skipTypes(typ, abstractRange-{tyTypeDesc})
+  result = emptyNode
+  case t.kind
+  of tyBool, tyEnum, tyChar, tyInt..tyInt64:
+    result = newNodeIT(nkIntLit, info, t)
+  of tyUInt..tyUInt64:
+    result = newNodeIT(nkUIntLit, info, t)
+  of tyFloat..tyFloat128:
+    result = newNodeIT(nkFloatLit, info, t)
+  of tyCString, tyString:
+    result = newNodeIT(nkStrLit, info, t)
+  of tyVar, tyPointer, tyPtr, tySequence, tyExpr,
+     tyStmt, tyTypeDesc, tyStatic, tyRef, tyNil:
+    result = newNodeIT(nkNilLit, info, t)
+  of tyProc:
+    if t.callConv != ccClosure:
+      result = newNodeIT(nkNilLit, info, t)
+    else:
+      result = newNodeIT(nkPar, info, t)
+      result.add(newNodeIT(nkNilLit, info, t))
+      result.add(newNodeIT(nkNilLit, info, t))
+  of tyObject:
+    result = newNodeIT(nkPar, info, t)
+    getNullValueAux(t.n, result)
+    # initialize inherited fields:
+    var base = t.sons[0]
+    while base != nil:
+      getNullValueAux(skipTypes(base, skipPtrs).n, result)
+      base = base.sons[0]
+  of tyArray, tyArrayConstr:
+    result = newNodeIT(nkBracket, info, t)
+    for i in countup(0, int(lengthOrd(t)) - 1):
+      addSon(result, getNullValue(elemType(t), info))
+  of tyTuple:
+    result = newNodeIT(nkPar, info, t)
+    for i in countup(0, sonsLen(t) - 1):
+      addSon(result, getNullValue(t.sons[i], info))
+  of tySet:
+    result = newNodeIT(nkCurly, info, t)
+  else: internalError(info, "getNullValue: " & $t.kind)
+
+proc ldNullOpcode(t: PType): TOpcode =
+  if fitsRegister(t): opcLdNullReg else: opcLdNull
+
+proc genVarSection(c: PCtx; n: PNode) =
+  for a in n:
+    if a.kind == nkCommentStmt: continue
+    #assert(a.sons[0].kind == nkSym) can happen for transformed vars
+    if a.kind == nkVarTuple:
+      for i in 0 .. a.len-3:
+        setSlot(c, a[i].sym)
+        checkCanEval(c, a[i])
+      c.gen(lowerTupleUnpacking(a, c.getOwner))
+    elif a.sons[0].kind == nkSym:
+      let s = a.sons[0].sym
+      checkCanEval(c, a.sons[0])
+      if s.isGlobal:
+        if s.position == 0:
+          if sfImportc in s.flags: c.importcSym(a.info, s)
+          else:
+            let sa = getNullValue(s.typ, a.info)
+            #if s.ast.isNil: getNullValue(s.typ, a.info)
+            #else: canonValue(s.ast)
+            assert sa.kind != nkCall
+            c.globals.add(sa)
+            s.position = c.globals.len
+        if a.sons[2].kind != nkEmpty:
+          let tmp = c.genx(a.sons[0], {gfAddrOf})
+          let val = c.genx(a.sons[2])
+          c.preventFalseAlias(a, opcWrDeref, tmp, 0, val)
+          c.freeTemp(val)
+          c.freeTemp(tmp)
+      else:
+        setSlot(c, s)
+        if a.sons[2].kind == nkEmpty:
+          c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
+        else:
+          if not fitsRegister(s.typ):
+            c.gABx(a, ldNullOpcode(s.typ), s.position, c.genType(s.typ))
+          let le = a.sons[0]
+          if not fitsRegister(le.typ) and s.kind in {skResult, skVar, skParam}:
+            var cc = c.getTemp(le.typ)
+            gen(c, a.sons[2], cc)
+            c.gABC(le, whichAsgnOpc(le), s.position.TRegister, cc)
+            c.freeTemp(cc)
+          else:
+            gen(c, a.sons[2], s.position.TRegister)
+    else:
+      # assign to a.sons[0]; happens for closures
+      if a.sons[2].kind == nkEmpty:
+        let tmp = genx(c, a.sons[0])
+        c.gABx(a, ldNullOpcode(a[0].typ), tmp, c.genType(a.sons[0].typ))
+        c.freeTemp(tmp)
+      else:
+        genAsgn(c, a.sons[0], a.sons[2], true)
+
+proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+
+  let intType = getSysType(tyInt)
+  let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
+  if seqType.kind == tySequence:
+    var tmp = c.getTemp(intType)
+    c.gABx(n, opcLdImmInt, tmp, n.len)
+    c.gABx(n, opcNewSeq, dest, c.genType(seqType))
+    c.gABx(n, opcNewSeq, tmp, 0)
+    c.freeTemp(tmp)
+
+  if n.len > 0:
+    var tmp = getTemp(c, intType)
+    c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
+    for x in n:
+      let a = c.genx(x)
+      c.preventFalseAlias(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a)
+      c.gABI(n, opcAddImmInt, tmp, tmp, 1)
+      c.freeTemp(a)
+    c.freeTemp(tmp)
+
+proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  for x in n:
+    if x.kind == nkRange:
+      let a = c.genx(x.sons[0])
+      let b = c.genx(x.sons[1])
+      c.gABC(n, opcInclRange, dest, a, b)
+      c.freeTemp(b)
+      c.freeTemp(a)
+    else:
+      let a = c.genx(x)
+      c.gABC(n, opcIncl, dest, a)
+      c.freeTemp(a)
+
+proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  let t = n.typ.skipTypes(abstractRange-{tyTypeDesc})
+  if t.kind == tyRef:
+    c.gABx(n, opcNew, dest, c.genType(t.sons[0]))
+  else:
+    c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  for i in 1.. <n.len:
+    let it = n.sons[i]
+    if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
+      let idx = genField(it.sons[0])
+      let tmp = c.genx(it.sons[1])
+      c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
+                          dest, idx, tmp)
+      c.freeTemp(tmp)
+    else:
+      internalError(n.info, "invalid object constructor")
+
+proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
+  if dest < 0: dest = c.getTemp(n.typ)
+  c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  # XXX x = (x.old, 22)  produces wrong code ... stupid self assignments
+  for i in 0.. <n.len:
+    let it = n.sons[i]
+    if it.kind == nkExprColonExpr:
+      let idx = genField(it.sons[0])
+      let tmp = c.genx(it.sons[1])
+      c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
+                          dest, idx, tmp)
+      c.freeTemp(tmp)
+    else:
+      let tmp = c.genx(it)
+      c.preventFalseAlias(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
+      c.freeTemp(tmp)
+
+proc genProc*(c: PCtx; s: PSym): int
+
+proc matches(s: PSym; x: string): bool =
+  let y = x.split('.')
+  var s = s
+  var L = y.len-1
+  while L >= 0:
+    if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false
+    s = s.owner
+    dec L
+  result = true
+
+proc matches(s: PSym; y: varargs[string]): bool =
+  var s = s
+  var L = y.len-1
+  while L >= 0:
+    if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false
+    s = if sfFromGeneric in s.flags: s.owner.owner else: s.owner
+    dec L
+  result = true
+
+proc procIsCallback(c: PCtx; s: PSym): bool =
+  if s.offset < -1: return true
+  var i = -2
+  for key, value in items(c.callbacks):
+    if s.matches(key):
+      doAssert s.offset == -1
+      s.offset = i
+      return true
+    dec i
+
+proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
+  case n.kind
+  of nkSym:
+    let s = n.sym
+    checkCanEval(c, n)
+    case s.kind
+    of skVar, skForVar, skTemp, skLet, skParam, skResult:
+      genRdVar(c, n, dest, flags)
+    of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators:
+      # 'skTemplate' is only allowed for 'getAst' support:
+      if procIsCallback(c, s): discard
+      elif sfImportc in s.flags: c.importcSym(n.info, s)
+      genLit(c, n, dest)
+    of skConst:
+      gen(c, s.ast, dest)
+    of skEnumField:
+      if dest < 0: dest = c.getTemp(n.typ)
+      if s.position >= low(int16) and s.position <= high(int16):
+        c.gABx(n, opcLdImmInt, dest, s.position)
+      else:
+        var lit = genLiteral(c, newIntNode(nkIntLit, s.position))
+        c.gABx(n, opcLdConst, dest, lit)
+    of skType:
+      genTypeLit(c, s.typ, dest)
+    else:
+      internalError(n.info, "cannot generate code for: " & s.name.s)
+  of nkCallKinds:
+    if n.sons[0].kind == nkSym:
+      let s = n.sons[0].sym
+      if s.magic != mNone:
+        genMagic(c, n, dest, s.magic)
+      elif matches(s, "stdlib", "marshal", "to"):
+        genMarshalLoad(c, n, dest)
+      elif matches(s, "stdlib", "marshal", "$$"):
+        genMarshalStore(c, n, dest)
+      else:
+        genCall(c, n, dest)
+        clearDest(c, n, dest)
+    else:
+      genCall(c, n, dest)
+      clearDest(c, n, dest)
+  of nkCharLit..nkInt64Lit:
+    if isInt16Lit(n):
+      if dest < 0: dest = c.getTemp(n.typ)
+      c.gABx(n, opcLdImmInt, dest, n.intVal.int)
+    else:
+      genLit(c, n, dest)
+  of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
+  of nkNilLit:
+    if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info), dest)
+    else: unused(n, dest)
+  of nkAsgn, nkFastAsgn:
+    unused(n, dest)
+    genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
+  of nkDotExpr: genObjAccess(c, n, dest, flags)
+  of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
+  of nkBracketExpr: genArrAccess(c, n, dest, flags)
+  of nkDerefExpr, nkHiddenDeref: genAddrDeref(c, n, dest, opcLdDeref, flags)
+  of nkAddr, nkHiddenAddr: genAddrDeref(c, n, dest, opcAddrNode, flags)
+  of nkWhenStmt, nkIfStmt, nkIfExpr: genIf(c, n, dest)
+  of nkCaseStmt: genCase(c, n, dest)
+  of nkWhileStmt:
+    unused(n, dest)
+    genWhile(c, n)
+  of nkBlockExpr, nkBlockStmt: genBlock(c, n, dest)
+  of nkReturnStmt:
+    unused(n, dest)
+    genReturn(c, n)
+  of nkRaiseStmt:
+    unused(n, dest)
+    genRaise(c, n)
+  of nkBreakStmt:
+    unused(n, dest)
+    genBreak(c, n)
+  of nkTryStmt: genTry(c, n, dest)
+  of nkStmtList:
+    #unused(n, dest)
+    # XXX Fix this bug properly, lexim triggers it
+    for x in n: gen(c, x)
+  of nkStmtListExpr:
+    let L = n.len-1
+    for i in 0 .. <L: gen(c, n.sons[i])
+    gen(c, n.sons[L], dest, flags)
+  of nkPragmaBlock:
+    gen(c, n.lastSon, dest, flags)
+  of nkDiscardStmt:
+    unused(n, dest)
+    gen(c, n.sons[0])
+  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
+    genConv(c, n, n.sons[1], dest)
+  of nkObjDownConv:
+    genConv(c, n, n.sons[0], dest)
+  of nkVarSection, nkLetSection:
+    unused(n, dest)
+    genVarSection(c, n)
+  of declarativeDefs:
+    unused(n, dest)
+  of nkLambdaKinds:
+    let s = n.sons[namePos].sym
+    discard genProc(c, s)
+    genLit(c, n.sons[namePos], dest)
+  of nkChckRangeF, nkChckRange64, nkChckRange:
+    let
+      tmp0 = c.genx(n.sons[0])
+      tmp1 = c.genx(n.sons[1])
+      tmp2 = c.genx(n.sons[2])
+    c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
+    c.freeTemp(tmp1)
+    c.freeTemp(tmp2)
+    if dest >= 0:
+      gABC(c, n, whichAsgnOpc(n), dest, tmp0)
+      c.freeTemp(tmp0)
+    else:
+      dest = tmp0
+  of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
+     nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt:
+    unused(n, dest)
+  of nkStringToCString, nkCStringToString:
+    gen(c, n.sons[0], dest)
+  of nkBracket: genArrayConstr(c, n, dest)
+  of nkCurly: genSetConstr(c, n, dest)
+  of nkObjConstr: genObjConstr(c, n, dest)
+  of nkPar, nkClosure: genTupleConstr(c, n, dest)
+  of nkCast:
+    if allowCast in c.features:
+      genConv(c, n, n.sons[1], dest, opcCast)
+    else:
+      globalError(n.info, errGenerated, "VM is not allowed to 'cast'")
+  else:
+    internalError n.info, "cannot generate VM code for " & n.renderTree
+
+proc removeLastEof(c: PCtx) =
+  let last = c.code.len-1
+  if last >= 0 and c.code[last].opcode == opcEof:
+    # overwrite last EOF:
+    assert c.code.len == c.debug.len
+    c.code.setLen(last)
+    c.debug.setLen(last)
+
+proc genStmt*(c: PCtx; n: PNode): int =
+  c.removeLastEof
+  result = c.code.len
+  var d: TDest = -1
+  c.gen(n, d)
+  c.gABC(n, opcEof)
+  if d >= 0: internalError(n.info, "some destination set")
+
+proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
+  c.removeLastEof
+  result = c.code.len
+  var d: TDest = -1
+  c.gen(n, d)
+  if d < 0:
+    if requiresValue: internalError(n.info, "no destination set")
+    d = 0
+  c.gABC(n, opcEof, d)
+
+proc genParams(c: PCtx; params: PNode) =
+  # res.sym.position is already 0
+  c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
+  for i in 1.. <params.len:
+    let param = params.sons[i].sym
+    c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
+  c.prc.maxSlots = max(params.len, 1)
+
+proc finalJumpTarget(c: PCtx; pc, diff: int) =
+  internalAssert(-0x7fff < diff and diff < 0x7fff)
+  let oldInstr = c.code[pc]
+  # opcode and regA stay the same:
+  c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
+                uint32(diff+wordExcess) shl 16'u32).TInstr
+
+proc optimizeJumps(c: PCtx; start: int) =
+  const maxIterations = 10
+  for i in start .. <c.code.len:
+    let opc = c.code[i].opcode
+    case opc
+    of opcTJmp, opcFJmp:
+      var reg = c.code[i].regA
+      var d = i + c.code[i].jmpDiff
+      for iters in countdown(maxIterations, 0):
+        case c.code[d].opcode
+        of opcJmp, opcJmpBack:
+          d = d + c.code[d].jmpDiff
+        of opcTJmp, opcFJmp:
+          if c.code[d].regA != reg: break
+          # tjmp x, 23
+          # ...
+          # tjmp x, 12
+          # -- we know 'x' is true, and so can jump to 12+13:
+          if c.code[d].opcode == opc:
+            d = d + c.code[d].jmpDiff
+          else:
+            # tjmp x, 23
+            # fjmp x, 22
+            # We know 'x' is true so skip to the next instruction:
+            d = d + 1
+        else: break
+      if d != i + c.code[i].jmpDiff:
+        c.finalJumpTarget(i, d - i)
+    of opcJmp, opcJmpBack:
+      var d = i + c.code[i].jmpDiff
+      var iters = maxIterations
+      while c.code[d].opcode == opcJmp and iters > 0:
+        d = d + c.code[d].jmpDiff
+        dec iters
+      if c.code[d].opcode == opcRet:
+        # optimize 'jmp to ret' to 'ret' here
+        c.code[i] = c.code[d]
+      elif d != i + c.code[i].jmpDiff:
+        c.finalJumpTarget(i, d - i)
+    else: discard
+
+proc genProc(c: PCtx; s: PSym): int =
+  let x = s.ast.sons[optimizedCodePos]
+  if x.kind == nkEmpty:
+    #if s.name.s == "outterMacro" or s.name.s == "innerProc":
+    #  echo "GENERATING CODE FOR ", s.name.s
+    let last = c.code.len-1
+    var eofInstr: TInstr
+    if last >= 0 and c.code[last].opcode == opcEof:
+      eofInstr = c.code[last]
+      c.code.setLen(last)
+      c.debug.setLen(last)
+    #c.removeLastEof
+    result = c.code.len+1 # skip the jump instruction
+    s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
+    # thanks to the jmp we can add top level statements easily and also nest
+    # procs easily:
+    let body = s.getBody
+    let procStart = c.xjmp(body, opcJmp, 0)
+    var p = PProc(blocks: @[], sym: s)
+    let oldPrc = c.prc
+    c.prc = p
+    # iterate over the parameters and allocate space for them:
+    genParams(c, s.typ.n)
+    if tfCapturesEnv in s.typ.flags:
+      #let env = s.ast.sons[paramsPos].lastSon.sym
+      #assert env.position == 2
+      c.prc.slots[c.prc.maxSlots] = (inUse: true, kind: slotFixedLet)
+      inc c.prc.maxSlots
+    gen(c, body)
+    # generate final 'return' statement:
+    c.gABC(body, opcRet)
+    c.patch(procStart)
+    c.gABC(body, opcEof, eofInstr.regA)
+    c.optimizeJumps(result)
+    s.offset = c.prc.maxSlots
+    #if s.name.s == "calc":
+    #  echo renderTree(body)
+    #  c.echoCode(result)
+    c.prc = oldPrc
+  else:
+    c.prc.maxSlots = s.offset
+    result = x.intVal.int
diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim
new file mode 100644
index 000000000..6ec5f6044
--- /dev/null
+++ b/compiler/vmhooks.nim
@@ -0,0 +1,45 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+template setX(k, field) {.immediate, dirty.} =
+  var s: seq[TFullReg]
+  move(s, cast[seq[TFullReg]](a.slots))
+  if s[a.ra].kind != k:
+    myreset(s[a.ra])
+    s[a.ra].kind = k
+  s[a.ra].field = v
+
+proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal)
+proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal)
+proc setResult*(a: VmArgs; v: bool) = 
+  let v = v.ord
+  setX(rkInt, intVal)
+
+proc setResult*(a: VmArgs; v: string) =
+  var s: seq[TFullReg]
+  move(s, cast[seq[TFullReg]](a.slots))
+  if s[a.ra].kind != rkNode:
+    myreset(s[a.ra])
+    s[a.ra].kind = rkNode
+  s[a.ra].node = newNode(nkStrLit)
+  s[a.ra].node.strVal = v
+
+template getX(k, field) {.immediate, dirty.} =
+  doAssert i < a.rc-1
+  let s = cast[seq[TFullReg]](a.slots)
+  doAssert s[i+a.rb+1].kind == k
+  result = s[i+a.rb+1].field
+
+proc getInt*(a: VmArgs; i: Natural): BiggestInt = getX(rkInt, intVal)
+proc getFloat*(a: VmArgs; i: Natural): BiggestFloat = getX(rkFloat, floatVal)
+proc getString*(a: VmArgs; i: Natural): string =
+  doAssert i < a.rc-1
+  let s = cast[seq[TFullReg]](a.slots)
+  doAssert s[i+a.rb+1].kind == rkNode
+  result = s[i+a.rb+1].node.strVal
diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim
new file mode 100644
index 000000000..293d0d949
--- /dev/null
+++ b/compiler/vmmarshal.nim
@@ -0,0 +1,283 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements marshaling for the VM.
+
+import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
+
+proc ptrToInt(x: PNode): int {.inline.} =
+  result = cast[int](x) # don't skip alignment
+
+proc getField(n: PNode; position: int): PSym =
+  case n.kind
+  of nkRecList:
+    for i in countup(0, sonsLen(n) - 1):
+      result = getField(n.sons[i], position)
+      if result != nil: return
+  of nkRecCase:
+    result = getField(n.sons[0], position)
+    if result != nil: return
+    for i in countup(1, sonsLen(n) - 1):
+      case n.sons[i].kind
+      of nkOfBranch, nkElse:
+        result = getField(lastSon(n.sons[i]), position)
+        if result != nil: return
+      else: internalError(n.info, "getField(record case branch)")
+  of nkSym:
+    if n.sym.position == position: result = n.sym
+  else: discard
+
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
+
+proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
+  internalAssert x.kind in {nkObjConstr, nkPar}
+  let start = ord(x.kind == nkObjConstr)
+  for i in countup(start, sonsLen(x) - 1):
+    if i > start: s.add(", ")
+    var it = x.sons[i]
+    if it.kind == nkExprColonExpr:
+      internalAssert it.sons[0].kind == nkSym
+      let field = it.sons[0].sym
+      s.add(escapeJson(field.name.s))
+      s.add(": ")
+      storeAny(s, field.typ, it.sons[1], stored)
+    elif typ.n != nil:
+      let field = getField(typ.n, i)
+      s.add(escapeJson(field.name.s))
+      s.add(": ")
+      storeAny(s, field.typ, it, stored)
+
+proc skipColon*(n: PNode): PNode =
+  result = n
+  if n.kind == nkExprColonExpr:
+    result = n.sons[1]
+
+proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
+  case t.kind
+  of tyNone: assert false
+  of tyBool: s.add($(a.intVal != 0))
+  of tyChar:
+    let ch = char(a.intVal)
+    if ch < '\128':
+      s.add(escapeJson($ch))
+    else:
+      s.add($int(ch))
+  of tyArray, tySequence:
+    if t.kind == tySequence and a.kind == nkNilLit: s.add("null")
+    else:
+      s.add("[")
+      for i in 0 .. a.len-1:
+        if i > 0: s.add(", ")
+        storeAny(s, t.elemType, a[i], stored)
+      s.add("]")
+  of tyTuple:
+    s.add("{")
+    for i in 0.. <t.len:
+      if i > 0: s.add(", ")
+      s.add("\"Field" & $i)
+      s.add("\": ")
+      storeAny(s, t.sons[i], a[i].skipColon, stored)
+    s.add("}")
+  of tyObject:
+    s.add("{")
+    storeObj(s, t, a, stored)
+    s.add("}")
+  of tySet:
+    s.add("[")
+    for i in 0.. <a.len:
+      if i > 0: s.add(", ")
+      if a[i].kind == nkRange:
+        var x = copyNode(a[i][0])
+        storeAny(s, t.lastSon, x, stored)
+        while x.intVal+1 <= a[i][1].intVal:
+          s.add(", ")
+          storeAny(s, t.lastSon, x, stored)
+          inc x.intVal
+      else:
+        storeAny(s, t.lastSon, a[i], stored)
+    s.add("]")
+  of tyRange, tyGenericInst: storeAny(s, t.lastSon, a, stored)
+  of tyEnum:
+    # we need a slow linear search because of enums with holes:
+    for e in items(t.n):
+      if e.sym.position == a.intVal:
+        s.add e.sym.name.s.escapeJson
+        break
+  of tyPtr, tyRef:
+    var x = a
+    if isNil(x) or x.kind == nkNilLit: s.add("null")
+    elif stored.containsOrIncl(x.ptrToInt):
+      # already stored, so we simply write out the pointer as an int:
+      s.add($x.ptrToInt)
+    else:
+      # else as a [value, key] pair:
+      # (reversed order for convenient x[0] access!)
+      s.add("[")
+      s.add($x.ptrToInt)
+      s.add(", ")
+      storeAny(s, t.lastSon, a, stored)
+      s.add("]")
+  of tyString, tyCString:
+    if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
+    else: s.add(escapeJson(a.strVal))
+  of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
+  of tyFloat..tyFloat128: s.add($a.floatVal)
+  else:
+    internalError a.info, "cannot marshal at compile-time " & t.typeToString
+
+proc storeAny*(s: var string; t: PType; a: PNode) =
+  var stored = initIntSet()
+  storeAny(s, t, a, stored)
+
+proc loadAny(p: var JsonParser, t: PType,
+             tab: var Table[BiggestInt, PNode]): PNode =
+  case t.kind
+  of tyNone: assert false
+  of tyBool:
+    case p.kind
+    of jsonFalse: result = newIntNode(nkIntLit, 0)
+    of jsonTrue: result = newIntNode(nkIntLit, 1)
+    else: raiseParseErr(p, "'true' or 'false' expected for a bool")
+    next(p)
+  of tyChar:
+    if p.kind == jsonString:
+      var x = p.str
+      if x.len == 1:
+        result = newIntNode(nkIntLit, ord(x[0]))
+        next(p)
+        return
+    elif p.kind == jsonInt:
+      result = newIntNode(nkIntLit, getInt(p))
+      next(p)
+      return
+    raiseParseErr(p, "string of length 1 expected for a char")
+  of tyEnum:
+    if p.kind == jsonString:
+      for e in items(t.n):
+        if e.sym.name.s == p.str:
+          result = newIntNode(nkIntLit, e.sym.position)
+          next(p)
+          return
+    raiseParseErr(p, "string expected for an enum")
+  of tyArray:
+    if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array")
+    next(p)
+    result = newNode(nkBracket)
+    while p.kind != jsonArrayEnd and p.kind != jsonEof:
+      result.add loadAny(p, t.elemType, tab)
+    if p.kind == jsonArrayEnd: next(p)
+    else: raiseParseErr(p, "']' end of array expected")
+  of tySequence:
+    case p.kind
+    of jsonNull:
+      result = newNode(nkNilLit)
+      next(p)
+    of jsonArrayStart:
+      next(p)
+      result = newNode(nkBracket)
+      while p.kind != jsonArrayEnd and p.kind != jsonEof:
+        result.add loadAny(p, t.elemType, tab)
+      if p.kind == jsonArrayEnd: next(p)
+      else: raiseParseErr(p, "")
+    else:
+      raiseParseErr(p, "'[' expected for a seq")
+  of tyTuple:
+    if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+    next(p)
+    result = newNode(nkPar)
+    var i = 0
+    while p.kind != jsonObjectEnd and p.kind != jsonEof:
+      if p.kind != jsonString:
+        raiseParseErr(p, "string expected for a field name")
+      next(p)
+      if i >= t.len:
+        raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
+      result.add loadAny(p, t.sons[i], tab)
+      inc i
+    if p.kind == jsonObjectEnd: next(p)
+    else: raiseParseErr(p, "'}' end of object expected")
+  of tyObject:
+    if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+    next(p)
+    result = newNode(nkPar)
+    result.sons = @[]
+    while p.kind != jsonObjectEnd and p.kind != jsonEof:
+      if p.kind != jsonString:
+        raiseParseErr(p, "string expected for a field name")
+      let field = lookupInRecord(t.n, getIdent(p.str))
+      if field.isNil:
+        raiseParseErr(p, "unknown field for object of type " & typeToString(t))
+      next(p)
+      if field.position >= result.sons.len:
+        setLen(result.sons, field.position+1)
+      result.sons[field.position] = loadAny(p, field.typ, tab)
+    if p.kind == jsonObjectEnd: next(p)
+    else: raiseParseErr(p, "'}' end of object expected")
+  of tySet:
+    if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set")
+    next(p)
+    result = newNode(nkCurly)
+    while p.kind != jsonArrayEnd and p.kind != jsonEof:
+      result.add loadAny(p, t.lastSon, tab)
+      next(p)
+    if p.kind == jsonArrayEnd: next(p)
+    else: raiseParseErr(p, "']' end of array expected")
+  of tyPtr, tyRef:
+    case p.kind
+    of jsonNull:
+      result = newNode(nkNilLit)
+      next(p)
+    of jsonInt:
+      result = tab[p.getInt]
+      if result.isNil:
+        raiseParseErr(p, "cannot load object with address " & $p.getInt)
+      next(p)
+    of jsonArrayStart:
+      next(p)
+      if p.kind == jsonInt:
+        let idx = p.getInt
+        next(p)
+        result = loadAny(p, t.lastSon, tab)
+        tab[idx] = result
+      else: raiseParseErr(p, "index for ref type expected")
+      if p.kind == jsonArrayEnd: next(p)
+      else: raiseParseErr(p, "']' end of ref-address pair expected")
+    else: raiseParseErr(p, "int for pointer type expected")
+  of tyString, tyCString:
+    case p.kind
+    of jsonNull:
+      result = newNode(nkNilLit)
+      next(p)
+    of jsonString:
+      result = newStrNode(nkStrLit, p.str)
+      next(p)
+    else: raiseParseErr(p, "string expected")
+  of tyInt..tyInt64, tyUInt..tyUInt64:
+    if p.kind == jsonInt:
+      result = newIntNode(nkIntLit, getInt(p))
+      next(p)
+      return
+    raiseParseErr(p, "int expected")
+  of tyFloat..tyFloat128:
+    if p.kind == jsonFloat:
+      result = newFloatNode(nkFloatLit, getFloat(p))
+      next(p)
+      return
+    raiseParseErr(p, "float expected")
+  of tyRange, tyGenericInst: result = loadAny(p, t.lastSon, tab)
+  else:
+    internalError "cannot marshal at compile-time " & t.typeToString
+
+proc loadAny*(s: string; t: PType): PNode =
+  var tab = initTable[BiggestInt, PNode]()
+  var p: JsonParser
+  open(p, newStringStream(s), "unknown file")
+  next(p)
+  result = loadAny(p, t, tab)
+  close(p)
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
new file mode 100644
index 000000000..1023d4783
--- /dev/null
+++ b/compiler/vmops.nim
@@ -0,0 +1,80 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Unforunately this cannot be a module yet:
+#import vmdeps, vm
+from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
+  arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
+  floor, ceil, fmod
+
+from os import getEnv, existsEnv, dirExists, fileExists
+
+template mathop(op) {.immediate, dirty.} =
+  registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
+
+template osop(op) {.immediate, dirty.} =
+  registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
+
+template systemop(op) {.immediate, dirty.} =
+  registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
+
+template wrap1f(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getFloat(a, 0)))
+  mathop op
+
+template wrap2f(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getFloat(a, 0), getFloat(a, 1)))
+  mathop op
+
+template wrap1s(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, op(getString(a, 0)))
+  osop op
+
+template wrap2svoid(op) {.immediate, dirty.} =
+  proc `op Wrapper`(a: VmArgs) {.nimcall.} =
+    op(getString(a, 0), getString(a, 1))
+  systemop op
+
+proc getCurrentExceptionMsgWrapper(a: VmArgs) {.nimcall.} =
+  setResult(a, if a.currentException.isNil: ""
+               else: a.currentException.sons[2].strVal)
+
+proc registerAdditionalOps*(c: PCtx) =
+  wrap1f(sqrt)
+  wrap1f(ln)
+  wrap1f(log10)
+  wrap1f(log2)
+  wrap1f(exp)
+  wrap1f(round)
+  wrap1f(arccos)
+  wrap1f(arcsin)
+  wrap1f(arctan)
+  wrap2f(arctan2)
+  wrap1f(cos)
+  wrap1f(cosh)
+  wrap2f(hypot)
+  wrap1f(sinh)
+  wrap1f(sin)
+  wrap1f(tan)
+  wrap1f(tanh)
+  wrap2f(pow)
+  wrap1f(trunc)
+  wrap1f(floor)
+  wrap1f(ceil)
+  wrap2f(fmod)
+
+  wrap1s(getEnv)
+  wrap1s(existsEnv)
+  wrap1s(dirExists)
+  wrap1s(fileExists)
+  wrap2svoid(writeFile)
+  systemop getCurrentExceptionMsg
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
new file mode 100644
index 000000000..63fd995c4
--- /dev/null
+++ b/compiler/wordrecg.nim
@@ -0,0 +1,190 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This module contains a word recognizer, i.e. a simple
+# procedure which maps special words to an enumeration.
+# It is primarily needed because Pascal's case statement
+# does not support strings. Without this the code would
+# be slow and unreadable.
+
+import
+  hashes, strutils, idents
+
+# Keywords must be kept sorted and within a range
+
+type
+  TSpecialWord* = enum
+    wInvalid,
+
+    wAddr, wAnd, wAs, wAsm, wAtomic,
+    wBind, wBlock, wBreak, wCase, wCast, wConcept, wConst,
+    wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo,
+    wElif, wElse, wEnd, wEnum, wExcept, wExport,
+    wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn,
+    wInclude, wInterface, wIs, wIsnot, wIterator, wLet,
+    wMacro, wMethod, wMixin, wMod, wNil,
+    wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
+    wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
+    wWhen, wWhile, wWith, wWithout, wXor, wYield,
+
+    wColon, wColonColon, wEquals, wDot, wDotDot,
+    wStar, wMinus,
+    wMagic, wThread, wFinal, wProfiler, wObjChecks,
+
+    wDestroy,
+
+    wImmediate, wConstructor, wDestructor, wDelegator, wOverride,
+    wImportCpp, wImportObjC,
+    wImportCompilerProc,
+    wImportc, wExportc, wIncompleteStruct, wRequiresInit,
+    wAlign, wNodecl, wPure, wSideeffect, wHeader,
+    wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
+    wCompilerproc, wProcVar,
+    wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
+    wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
+    wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
+    wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
+    wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
+    wBoundchecks, wOverflowchecks, wNilchecks,
+    wFloatchecks, wNanChecks, wInfChecks,
+    wAssertions, wPatterns, wWarnings,
+    wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects, wTags,
+    wDeadCodeElim, wSafecode, wNoForward,
+    wPragma,
+    wCompileTime, wNoInit,
+    wPassc, wPassl, wBorrow, wDiscardable,
+    wFieldChecks,
+    wWatchPoint, wSubsChar,
+    wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
+    wInjectStmt, wExperimental,
+    wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
+    wAsmNoStackFrame,
+    wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
+
+    wAuto, wBool, wCatch, wChar, wClass,
+    wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
+    wExplicit, wExtern, wFalse, wFloat, wFriend,
+    wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator,
+    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
+    wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
+    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
+    wUnion, wPacked, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t,
+
+    wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
+    wThread_local, wStatic_assert, wChar16_t, wChar32_t,
+
+    wStdIn, wStdOut, wStdErr,
+
+    wInOut, wByCopy, wByRef, wOneWay,
+
+  TSpecialWords* = set[TSpecialWord]
+
+const
+  oprLow* = ord(wColon)
+  oprHigh* = ord(wDotDot)
+
+  nimKeywordsLow* = ord(wAsm)
+  nimKeywordsHigh* = ord(wYield)
+
+  ccgKeywordsLow* = ord(wAuto)
+  ccgKeywordsHigh* = ord(wOneWay)
+
+  cppNimSharedKeywords* = {
+    wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
+    wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing}
+
+  specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
+
+    "addr", "and", "as", "asm", "atomic",
+    "bind", "block", "break", "case", "cast",
+    "concept", "const", "continue", "converter",
+    "defer", "discard", "distinct", "div", "do",
+    "elif", "else", "end", "enum", "except", "export",
+    "finally", "for", "from", "func", "generic", "if",
+    "import", "in", "include", "interface", "is", "isnot", "iterator",
+    "let",
+    "macro", "method", "mixin", "mod", "nil", "not", "notin",
+    "object", "of", "or",
+    "out", "proc", "ptr", "raise", "ref", "return",
+    "shl", "shr", "static",
+    "template", "try", "tuple", "type", "using", "var",
+    "when", "while", "with", "without", "xor",
+    "yield",
+
+    ":", "::", "=", ".", "..",
+    "*", "-",
+    "magic", "thread", "final", "profiler", "objchecks",
+
+    "destroy",
+
+    "immediate", "constructor", "destructor", "delegator", "override",
+    "importcpp", "importobjc",
+    "importcompilerproc", "importc", "exportc", "incompletestruct",
+    "requiresinit", "align", "nodecl", "pure", "sideeffect",
+    "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
+    "compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
+    "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
+    "link", "compile", "linksys", "deprecated", "varargs",
+    "callconv", "breakpoint", "debugger", "nimcall", "stdcall",
+    "cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
+    "noconv", "on", "off", "checks", "rangechecks", "boundchecks",
+    "overflowchecks", "nilchecks",
+    "floatchecks", "nanchecks", "infchecks",
+
+    "assertions", "patterns", "warnings", "hints",
+    "optimization", "raises", "writes", "reads", "size", "effects", "tags",
+    "deadcodeelim", "safecode", "noforward",
+    "pragma",
+    "compiletime", "noinit",
+    "passc", "passl", "borrow", "discardable", "fieldchecks",
+    "watchpoint",
+    "subschar", "acyclic", "shallow", "unroll", "linearscanend",
+    "computedgoto", "injectstmt", "experimental",
+    "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
+    "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
+    "guard", "locks",
+
+    "auto", "bool", "catch", "char", "class",
+    "const_cast", "default", "delete", "double",
+    "dynamic_cast", "explicit", "extern", "false",
+    "float", "friend", "goto", "int", "long", "mutable",
+    "namespace", "new", "operator",
+    "private", "protected", "public", "register", "reinterpret_cast",
+    "short", "signed", "sizeof", "static_cast", "struct", "switch",
+    "this", "throw", "true", "typedef", "typeid",
+    "typename", "union", "packed", "unsigned", "virtual", "void", "volatile",
+    "wchar_t",
+
+    "alignas", "alignof", "constexpr", "decltype", "nullptr", "noexcept",
+    "thread_local", "static_assert", "char16_t", "char32_t",
+
+    "stdin", "stdout", "stderr",
+
+    "inout", "bycopy", "byref", "oneway",
+    ]
+
+proc findStr*(a: openArray[string], s: string): int =
+  for i in countup(low(a), high(a)):
+    if cmpIgnoreStyle(a[i], s) == 0:
+      return i
+  result = - 1
+
+proc whichKeyword*(id: PIdent): TSpecialWord =
+  if id.id < 0: result = wInvalid
+  else: result = TSpecialWord(id.id)
+
+proc whichKeyword*(id: string): TSpecialWord =
+  result = whichKeyword(getIdent(id))
+
+proc initSpecials() =
+  # initialize the keywords:
+  for s in countup(succ(low(specialWords)), high(specialWords)):
+    getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
+
+initSpecials()
diff --git a/config/nim.cfg b/config/nim.cfg
new file mode 100644
index 000000000..0c3ffef4e
--- /dev/null
+++ b/config/nim.cfg
@@ -0,0 +1,180 @@
+# Configuration file for the Nim Compiler.
+# (c) 2015 Andreas Rumpf
+
+# Feel free to edit the default values as you need.
+
+# You may set environment variables with
+# @putenv "key" "val"
+# Environment variables can be accessed like so:
+#  gcc.path %= "$CC_PATH"
+
+cc = gcc
+
+# additional options always passed to the compiler:
+--parallel_build: "0" # 0 to auto-detect number of processors
+
+hint[LineTooLong]=off
+#hint[XDeclaredButNotUsed]=off
+
+# example of how to setup a cross-compiler:
+arm.linux.gcc.exe = "arm-linux-gcc"
+arm.linux.gcc.linkerexe = "arm-linux-gcc"
+
+mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
+mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
+
+@if not nimfix:
+  cs:partial
+@end
+
+path="$lib/core"
+
+path="$lib/pure"
+path="$lib/pure/collections"
+path="$lib/pure/concurrency"
+path="$lib/impure"
+path="$lib/wrappers"
+# path="$lib/wrappers/cairo"
+# path="$lib/wrappers/gtk"
+# path="$lib/wrappers/lua"
+# path="$lib/wrappers/opengl"
+path="$lib/wrappers/pcre"
+path="$lib/wrappers/readline"
+path="$lib/wrappers/sdl"
+# path="$lib/wrappers/x11"
+path="$lib/wrappers/zip"
+path="$lib/wrappers/libffi"
+path="$lib/windows"
+path="$lib/posix"
+path="$lib/js"
+path="$lib/pure/unidecode"
+
+@if nimbabel:
+  babelpath="$home/.babel/pkgs/"
+  nimblepath="$home/.nimble/pkgs/"
+@end
+
+@if release or quick:
+  obj_checks:off
+  field_checks:off
+  range_checks:off
+  bound_checks:off
+  overflow_checks:off
+  assertions:off
+  stacktrace:off
+  linetrace:off
+  debugger:off
+  line_dir:off
+  dead_code_elim:on
+@end
+
+@if release:
+  opt:speed
+@end
+
+@if unix:
+  @if not bsd:
+    # -fopenmp
+    gcc.options.linker = "-ldl"
+    gcc.cpp.options.linker = "-ldl"
+    clang.options.linker = "-ldl"
+    clang.cpp.options.linker = "-ldl"
+    tcc.options.linker = "-ldl"
+  @end
+  @if bsd or haiku:
+    # BSD got posix_spawn only recently, so we deactivate it for osproc:
+    define:useFork
+    # at least NetBSD has problems with thread local storage:
+    tlsEmulation:on
+  @end
+@end
+
+# Configuration for the Intel C/C++ compiler:
+@if windows:
+  icl.options.speed = "/Ox /arch:SSE2"
+  icl.options.always = "/nologo"
+@end
+
+# Configuration for the GNU C/C++ compiler:
+@if windows:
+  #gcc.path = r"$nim\dist\mingw\bin"
+  @if gcc:
+    tlsEmulation:on
+  @end
+@end
+
+@if macosx or freebsd:
+  cc = clang
+  tlsEmulation:on
+  gcc.options.always = "-w"
+  gcc.cpp.options.always = "-w -fpermissive"
+@else:
+  gcc.options.always = "-w"
+  gcc.cpp.options.always = "-w -fpermissive"
+@end
+
+# Configuration for Objective-C compiler:
+#
+# Options for GNUStep. GNUStep configuration varies wildly, so you'll probably
+# have to add additional compiler and linker flags on a per-project basis.
+gcc.objc.options.linker = "-lobjc -lgnustep-base"
+llvm_gcc.objc.options.linker = "-lobjc -lgnustep-base"
+clang.objc.options.linker = "-lobjc -lgnustep-base"
+
+# Options for Mac OS X. Mac OS X uses its own Objective-C stack that is
+# totally different from GNUStep.
+@if macosx:
+  gcc.objc.options.linker = "-framework Foundation"
+  llvm_gcc.objc.options.linker = "-framework Foundation"
+  clang.objc.options.linker = "-framework Foundation"
+@end
+
+# Configuration for the VxWorks
+# This has been tested with VxWorks 6.9 only
+@if vxworks:
+  # For now we only support compiling RTPs applications (i.e. no DKMs)
+  gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
+  # The linker config must add the VxWorks common library for the selected
+  # processor which is usually found in:
+  # "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common",
+  # where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks
+  # compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc)
+  # For now we only support the PowerPC CPU
+  gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
+@end
+
+gcc.options.speed = "-O3 -fno-strict-aliasing"
+gcc.options.size = "-Os"
+gcc.options.debug = "-g3 -O0"
+
+gcc.cpp.options.speed = "-O3 -fno-strict-aliasing"
+gcc.cpp.options.size = "-Os"
+gcc.cpp.options.debug = "-g3 -O0"
+#passl = "-pg"
+
+# Configuration for the LLVM GCC compiler:
+llvm_gcc.options.debug = "-g"
+llvm_gcc.options.always = "-w"
+llvm_gcc.options.speed = "-O2"
+llvm_gcc.options.size = "-Os"
+
+# Configuration for the LLVM CLang compiler:
+clang.options.debug = "-g"
+clang.options.always = "-w"
+clang.options.speed = "-O3"
+clang.options.size = "-Os"
+
+# Configuration for the Visual C/C++ compiler:
+vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
+vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
+vcc.options.always = "/nologo"
+vcc.options.speed = "/O2 /arch:SSE2"
+vcc.options.size = "/O1"
+
+# Configuration for the Digital Mars C/C++ compiler:
+@if windows:
+  dmc.path = r"$nimrod\dist\dm\bin"
+@end
+
+# Configuration for the Tiny C Compiler:
+tcc.options.always = "-w"
diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg
new file mode 100644
index 000000000..e036c3b9a
--- /dev/null
+++ b/config/nimdoc.cfg
@@ -0,0 +1,1251 @@
+# This is the config file for the documentation generator.
+# (c) 2012 Andreas Rumpf
+# Feel free to edit the templates as you need. If you modify this file, it
+# might be worth updating the hardcoded values in packages/docutils/rstgen.nim
+
+split.item.toc = "20"
+# too long entries in the table of contents wrap around
+# after this number of characters
+
+doc.section = """
+<div class="section" id="$sectionID">
+<h1><a class="toc-backref" href="#$sectionID">$sectionTitle</a></h1>
+<dl class="item">
+$content
+</dl></div>
+"""
+
+doc.section.toc = """
+<li>
+  <a class="reference reference-toplevel" href="#$sectionID" id="$sectionTitleID">$sectionTitle</a>
+  <ul class="simple simple-toc-section">
+    $content
+  </ul>
+</li>
+"""
+
+# Chunk of HTML emitted for each entry in the HTML table of contents.
+# Available variables are:
+# * $desc: the actual docstring of the item.
+# * $header: the full version of name, including types, pragmas, tags, etc.
+# * $header_plain: like header but without HTML, for attribute embedding.
+# * $itemID: numerical unique entry of the item in the HTML.
+# * $itemSym: short symbolic name of the item for easier hyperlinking.
+# * $itemSymEnc: quoted version for URLs or attributes.
+# * $itemSymOrID: the symbolic name or the ID if that is not unique.
+# * $itemSymOrIDEnc: quoted version for URLs or attributes.
+# * $name: reduced name of the item.
+# * $seeSrc: generated HTML from doc.item.seesrc (if some switches are used).
+
+doc.item = """
+<dt id="$itemSym"><a name="$itemSymOrID"></a><pre>$header</pre></dt>
+<dd>
+$desc
+$seeSrc
+</dd>
+"""
+
+# Chunk of HTML emitted for each entry in the HTML table of contents.
+# See doc.item for available substitution variables.
+doc.item.toc = """
+  <li><a class="reference" href="#$itemSymOrID"
+    title="$header_plain">$name</a></li>
+"""
+
+# HTML rendered for doc.item's seeSrc variable. Note that this will render to
+# the empty string if you don't pass anything through --docSeeSrcURL. Available
+# substitutaion variables here are:
+# * $path: relative path to the file being processed.
+# * $line: line of the item in the original source file.
+# * $url: whatever you did pass through the --docSeeSrcUrl switch (which also
+#   gets variables path/line replaced!)
+doc.item.seesrc = """&nbsp;&nbsp;<a
+href="${url}/${path}#L${line}"
+class="link-seesrc" target="_blank">Source</a>"""
+
+doc.toc = """
+<ul class="simple simple-toc" id="toc-list">
+$content
+</ul>
+"""
+
+doc.body_toc = """
+<div class="row">
+  <div class="three columns">
+  $tableofcontents
+  </div>
+  <div class="nine columns" id="content">
+  <p class="module-desc">$moduledesc</p>
+  $content
+  </div>
+</div>
+"""
+
+doc.body_no_toc = """
+$moduledesc
+$content
+"""
+
+# * $analytics: Google analytics location, includes <script> tags
+doc.file = """<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--  This file is generated by Nimrod. -->
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<!-- Favicon -->
+<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="/>
+
+<!-- Google fonts -->
+<link href='http://fonts.googleapis.com/css?family=Raleway:400,600,900' rel='stylesheet' type='text/css'>
+<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'>
+
+<!-- CSS -->
+<title>$title</title>
+<style type="text/css" >
+/*
+Stylesheet for use with Docutils/rst2html.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+
+Modified from Chad Skeeters' rst2html-style
+https://bitbucket.org/cskeeters/rst2html-style/
+
+Modified by Boyd Greenfield
+*/
+/* SCSS variables */
+/* Text weights */
+/* Body colors */
+/* Text colors */
+/* Link colors */
+/* Syntax highlighting colors */
+/* Pct changes */
+/* Mixins */
+/* Body/layout */
+html {
+  font-size: 100%;
+  -webkit-text-size-adjust: 100%;
+  -ms-text-size-adjust: 100%; }
+
+/* Where we want fancier font if available */
+h1, h2, h3, h4, h5, h6, p.module-desc, table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
+  font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; }
+
+h1.title {
+  font-weight: 900; }
+
+body {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: 400;
+  font-size: 14px;
+  line-height: 20px;
+  color: #2d2d2d;
+  background-color: rgba(252, 248, 244, 0.75); }
+
+/* Skeleton grid */
+.container {
+  position: relative;
+  width: 100%;
+  max-width: 960px;
+  margin: 0 auto;
+  padding: 0 20px;
+  box-sizing: border-box; }
+
+.column,
+.columns {
+  width: 100%;
+  float: left;
+  box-sizing: border-box; }
+
+/* For devices larger than 400px */
+@media (min-width: 400px) {
+  .container {
+    width: 100%;
+    padding: 0; } }
+/* For devices larger than 650px */
+@media (min-width: 650px) {
+  .container {
+    width: 100%; }
+
+  .column,
+  .columns {
+    margin-left: 4%; }
+
+  .column:first-child,
+  .columns:first-child {
+    margin-left: 0; }
+
+  .one.column,
+  .one.columns {
+    width: 4.66666666667%; }
+
+  .two.columns {
+    width: 13.3333333333%; }
+
+  .three.columns {
+    width: 22%; }
+
+  .four.columns {
+    width: 30.6666666667%; }
+
+  .five.columns {
+    width: 39.3333333333%; }
+
+  .six.columns {
+    width: 48%; }
+
+  .seven.columns {
+    width: 56.6666666667%; }
+
+  .eight.columns {
+    width: 65.3333333333%; }
+
+  .nine.columns {
+    width: 74.0%; }
+
+  .ten.columns {
+    width: 82.6666666667%; }
+
+  .eleven.columns {
+    width: 91.3333333333%; }
+
+  .twelve.columns {
+    width: 100%;
+    margin-left: 0; }
+
+  .one-third.column {
+    width: 30.6666666667%; }
+
+  .two-thirds.column {
+    width: 65.3333333333%; } }
+/* Customer Overrides */
+.footer {
+  text-align: center;
+  color: #969696;
+  padding-top: 10%; }
+
+p.module-desc {
+  font-size: 1.1em;
+  color: #666666; }
+
+a.link-seesrc {
+  color: #aec7d2;
+  font-style: italic; }
+
+a.link-seesrc:hover {
+  color: #6c9aae; }
+
+#toc-list {
+  word-wrap: break-word; }
+
+ul.simple-toc {
+  list-style: none; }
+
+ul.simple-toc a.reference-toplevel {
+  font-weight: bold;
+  color: #0077b3; }
+
+ul.simple-toc-section {
+  list-style-type: circle;
+  color: #6c9aae; }
+
+ul.simple-toc-section a.reference {
+  color: #0077b3; }
+
+cite {
+  font-style: italic !important; }
+
+dt > pre {
+  border-color: rgba(0, 0, 0, 0.15);
+  background-color: transparent;
+  margin: 15px 0px 5px; }
+
+dd > pre {
+  border-color: rgba(0, 0, 0, 0.1);
+  background-color: whitesmoke;
+  margin-top: 8px; }
+
+.item > dd {
+  margin-left: 10px;
+  margin-bottom: 30px; }
+
+/* Nim line-numbered tables */
+.line-nums-table {
+  width: 100%;
+  table-layout: fixed; }
+
+table.line-nums-table {
+  border-radius: 4px;
+  border: 1px solid #cccccc;
+  background-color: whitesmoke;
+  border-collapse: separate;
+  margin-top: 15px;
+  margin-bottom: 25px; }
+
+.line-nums-table tbody {
+  border: none; }
+
+.line-nums-table td pre {
+  border: none;
+  background-color: transparent; }
+
+.line-nums-table td.blob-line-nums {
+  width: 28px; }
+
+.line-nums-table td.blob-line-nums pre {
+  color: #b0b0b0;
+  -webkit-filter: opacity(75%);
+  text-align: right;
+  border-color: transparent;
+  background-color: transparent;
+  padding-left: 0px;
+  margin-left: 0px;
+  padding-right: 0px;
+  margin-right: 0px; }
+
+/* Docgen styles */
+/* Links */
+a {
+  color: #0077b3;
+  text-decoration: none; }
+
+a:hover,
+a:focus {
+  color: #00334d;
+  text-decoration: underline; }
+
+a:visited {
+  color: #00334d; }
+
+a:focus {
+  outline: thin dotted #2d2d2d;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px; }
+
+a:hover,
+a:active {
+  outline: 0; }
+
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline; }
+
+sup {
+  top: -0.5em; }
+
+sub {
+  bottom: -0.25em; }
+
+img {
+  width: auto;
+  height: auto;
+  max-width: 100%;
+  vertical-align: middle;
+  border: 0;
+  -ms-interpolation-mode: bicubic; }
+
+@media print {
+  * {
+    color: black !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    box-shadow: none !important; }
+
+  a,
+  a:visited {
+    text-decoration: underline; }
+
+  a[href]:after {
+    content: " (" attr(href) ")"; }
+
+  abbr[title]:after {
+    content: " (" attr(title) ")"; }
+
+  .ir a:after,
+  a[href^="javascript:"]:after,
+  a[href^="#"]:after {
+    content: ""; }
+
+  pre,
+  blockquote {
+    border: 1px solid #999;
+    page-break-inside: avoid; }
+
+  thead {
+    display: table-header-group; }
+
+  tr,
+  img {
+    page-break-inside: avoid; }
+
+  img {
+    max-width: 100% !important; }
+
+  @page {
+    margin: 0.5cm; }
+
+  h1 {
+    page-break-before: always; }
+
+  h1.title {
+    page-break-before: avoid; }
+
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3; }
+
+  h2,
+  h3 {
+    page-break-after: avoid; } }
+.img-rounded {
+  -webkit-border-radius: 6px;
+  -moz-border-radius: 6px;
+  border-radius: 6px; }
+
+.img-polaroid {
+  padding: 4px;
+  background-color: rgba(252, 248, 244, 0.75);
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, 0.2);
+  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }
+
+p {
+  margin: 0 0 12px; }
+
+small {
+  font-size: 85%; }
+
+strong {
+  font-weight: 600; }
+
+em {
+  font-style: italic; }
+
+cite {
+  font-style: normal; }
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: 600;
+  line-height: 20px;
+  color: inherit;
+  text-rendering: optimizelegibility; }
+
+h1 {
+  font-size: 2em;
+  padding-bottom: .15em;
+  border-bottom: 1px solid #aaaaaa;
+  margin-top: 1.0em;
+  line-height: 1.2em; }
+
+h1.title {
+  padding-bottom: 1em;
+  border-bottom: 0px;
+  font-size: 2.75em; }
+
+h2 {
+  font-size: 1.5em;
+  margin-top: 1.5em; }
+
+h3 {
+  font-size: 1.3em;
+  font-style: italic;
+  margin-top: 0.75em; }
+
+h4 {
+  font-size: 1.3em;
+  margin-top: 0.5em; }
+
+h5 {
+  font-size: 1.2em;
+  margin-top: 0.25em; }
+
+h6 {
+  font-size: 1.1em; }
+
+ul,
+ol {
+  padding: 0;
+  margin: 0 0 0px 15px; }
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin-bottom: 0; }
+
+li {
+  line-height: 20px; }
+
+dl {
+  margin-bottom: 20px; }
+
+dt,
+dd {
+  line-height: 20px; }
+
+dt {
+  font-weight: bold; }
+
+dd {
+  margin-left: 10px;
+  margin-bottom: 26px; }
+
+hr {
+  margin: 20px 0;
+  border: 0;
+  border-top: 1px solid #eeeeee;
+  border-bottom: 1px solid #ffffff; }
+
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #999999; }
+
+abbr.initialism {
+  font-size: 90%;
+  text-transform: uppercase; }
+
+blockquote {
+  padding: 0 0 0 15px;
+  margin: 0 0 20px;
+  border-left: 5px solid #EFEBE0; }
+
+table.docinfo + blockquote, table.docinfo blockquote, h1 + blockquote {
+  border-left: 5px solid #c9c9c9;
+}
+
+table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p {
+  margin-bottom: 0;
+  font-size: 15px;
+  font-weight: 200;
+  line-height: 1.5;
+  font-style: italic; }
+
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+  content: ""; }
+
+address {
+  display: block;
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 20px; }
+
+code,
+pre {
+  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
+  padding: 0 3px 2px;
+  font-weight: 500;
+  font-size: 12px;
+  color: #444444;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px; }
+
+.pre {
+  font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace;
+  font-weight: 600;
+  /*color: #504da6;*/
+}
+
+code {
+  padding: 2px 4px;
+  color: #444444;
+  white-space: nowrap;
+  background-color: white;
+  border: 1px solid #777777; }
+
+pre {
+  display: inline-block;
+  box-sizing: border-box;
+  min-width: calc(100% - 19.5px);
+  padding: 9.5px;
+  margin: 0 10px 0px 10px;
+  font-size: 14px;
+  line-height: 20px;
+  white-space: pre !important;
+  overflow-y: hidden;
+  overflow-x: visible;
+  background-color: whitesmoke;
+  border: 1px solid #cccccc;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px; }
+
+pre.prettyprint {
+  margin-bottom: 20px; }
+
+pre code {
+  padding: 0;
+  color: inherit;
+  white-space: pre;
+  overflow-x: visible;
+  background-color: transparent;
+  border: 0; }
+
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll; }
+
+table {
+  max-width: 100%;
+  background-color: transparent;
+  border-collapse: collapse;
+  border-spacing: 0; }
+
+table th, table td {
+  padding: 0px 8px 0px;
+}
+
+.table {
+  width: 100%;
+  margin-bottom: 20px; }
+
+.table th,
+.table td {
+  padding: 8px;
+  line-height: 20px;
+  text-align: left;
+  vertical-align: top;
+  border-top: 1px solid #444444; }
+
+.table th {
+  font-weight: bold; }
+
+.table thead th {
+  vertical-align: bottom; }
+
+.table caption + thead tr:first-child th,
+.table caption + thead tr:first-child td,
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+  border-top: 0; }
+
+.table tbody + tbody {
+  border-top: 2px solid #444444; }
+
+.table .table {
+  background-color: rgba(252, 248, 244, 0.75); }
+
+.table-condensed th,
+.table-condensed td {
+  padding: 4px 5px; }
+
+.table-bordered {
+  border: 1px solid #444444;
+  border-collapse: separate;
+  *border-collapse: collapse;
+  border-left: 0;
+  -webkit-border-radius: 4px;
+  -moz-border-radius: 4px;
+  border-radius: 4px; }
+
+.table-bordered th,
+.table-bordered td {
+  border-left: 1px solid #444444; }
+
+.table-bordered caption + thead tr:first-child th,
+.table-bordered caption + tbody tr:first-child th,
+.table-bordered caption + tbody tr:first-child td,
+.table-bordered colgroup + thead tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child th,
+.table-bordered colgroup + tbody tr:first-child td,
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+  border-top: 0; }
+
+.table-bordered thead:first-child tr:first-child > th:first-child,
+.table-bordered tbody:first-child tr:first-child > td:first-child,
+.table-bordered tbody:first-child tr:first-child > th:first-child {
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px; }
+
+.table-bordered thead:first-child tr:first-child > th:last-child,
+.table-bordered tbody:first-child tr:first-child > td:last-child,
+.table-bordered tbody:first-child tr:first-child > th:last-child {
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px; }
+
+.table-bordered thead:last-child tr:last-child > th:first-child,
+.table-bordered tbody:last-child tr:last-child > td:first-child,
+.table-bordered tbody:last-child tr:last-child > th:first-child,
+.table-bordered tfoot:last-child tr:last-child > td:first-child,
+.table-bordered tfoot:last-child tr:last-child > th:first-child {
+  -webkit-border-bottom-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+  -moz-border-radius-bottomleft: 4px; }
+
+.table-bordered thead:last-child tr:last-child > th:last-child,
+.table-bordered tbody:last-child tr:last-child > td:last-child,
+.table-bordered tbody:last-child tr:last-child > th:last-child,
+.table-bordered tfoot:last-child tr:last-child > td:last-child,
+.table-bordered tfoot:last-child tr:last-child > th:last-child {
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomright: 4px; }
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:first-child {
+  -webkit-border-bottom-left-radius: 0;
+  border-bottom-left-radius: 0;
+  -moz-border-radius-bottomleft: 0; }
+
+.table-bordered tfoot + tbody:last-child tr:last-child td:last-child {
+  -webkit-border-bottom-right-radius: 0;
+  border-bottom-right-radius: 0;
+  -moz-border-radius-bottomright: 0; }
+
+.table-bordered caption + thead tr:first-child th:first-child,
+.table-bordered caption + tbody tr:first-child td:first-child,
+.table-bordered colgroup + thead tr:first-child th:first-child,
+.table-bordered colgroup + tbody tr:first-child td:first-child {
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+  -moz-border-radius-topleft: 4px; }
+
+.table-bordered caption + thead tr:first-child th:last-child,
+.table-bordered caption + tbody tr:first-child td:last-child,
+.table-bordered colgroup + thead tr:first-child th:last-child,
+.table-bordered colgroup + tbody tr:first-child td:last-child {
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+  -moz-border-radius-topright: 4px; }
+
+table.docutils th {
+  background-color: #e8e8e8; }
+
+table.docutils tr:hover {
+  background-color: whitesmoke; }
+
+.table-striped tbody > tr:nth-child(odd) > td,
+.table-striped tbody > tr:nth-child(odd) > th {
+  background-color: rgba(252, 248, 244, 0.75); }
+
+.table-hover tbody tr:hover > td,
+.table-hover tbody tr:hover > th {
+  background-color: rgba(241, 222, 204, 0.75); }
+
+table td[class*="span"],
+table th[class*="span"],
+.row-fluid table td[class*="span"],
+.row-fluid table th[class*="span"] {
+  display: table-cell;
+  float: none;
+  margin-left: 0; }
+
+.hero-unit {
+  padding: 60px;
+  margin-bottom: 30px;
+  font-size: 18px;
+  font-weight: 200;
+  line-height: 30px;
+  color: inherit;
+  background-color: rgba(230, 197, 164, 0.75);
+  -webkit-border-radius: 6px;
+  -moz-border-radius: 6px;
+  border-radius: 6px; }
+
+.hero-unit h1 {
+  margin-bottom: 0;
+  font-size: 60px;
+  line-height: 1;
+  letter-spacing: -1px;
+  color: inherit; }
+
+.hero-unit li {
+  line-height: 30px; }
+
+/* rst2html default used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0; }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 !important; }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 !important; }
+
+.last, .with-subtitle {
+  margin-bottom: 0 !important; }
+
+.hidden {
+  display: none; }
+
+a.toc-backref {
+  text-decoration: none;
+  color: #444444; }
+
+blockquote.epigraph {
+  margin: 2em 5em; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em; }
+
+object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
+  overflow: hidden; }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+div.abstract {
+  margin: 2em 5em; }
+
+div.abstract p.topic-title {
+  font-weight: bold;
+  text-align: center; }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em;
+  border: medium outset;
+  padding: 1em; }
+
+div.note, div.warning {
+  margin: 1.5em 0px;
+  border: none; }
+
+div.note p.admonition-title,
+div.warning p.admonition-title {
+  display: none; }
+
+/* Clearfix
+ * http://css-tricks.com/snippets/css/clear-fix/
+ */
+div.note:after,
+div.warning:after {
+  content: "";
+  display: table;
+  clear: both; }
+
+div.note p:before,
+div.warning p:before {
+  display: block;
+  float: left;
+  font-size: 4em;
+  line-height: 1em;
+  margin-right: 20px;
+  margin-left: 0em;
+  margin-top: -10px;
+  content: '\0270D';
+  /*handwriting*/ }
+
+div.warning p:before {
+  content: '\026A0';
+  /*warning*/ }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold;
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title, .code .error {
+  color: #b30000;
+  font-weight: bold;
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+div.dedication {
+  margin: 2em 5em;
+  text-align: center;
+  font-style: italic; }
+
+div.dedication p.topic-title {
+  font-weight: bold;
+  font-style: normal; }
+
+div.figure {
+  margin-left: 2em;
+  margin-right: 2em; }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller; }
+
+div.line-block {
+  display: block;
+  margin-top: 1em;
+  margin-bottom: 1em; }
+
+div.line-block div.line-block {
+  margin-top: 0;
+  margin-bottom: 0;
+  margin-left: 1.5em; }
+
+div.sidebar {
+  margin: 0 0 0.5em 1em;
+  border: medium outset;
+  padding: 1em;
+  background-color: rgba(252, 248, 244, 0.75);
+  width: 40%;
+  float: right;
+  clear: right; }
+
+div.sidebar p.rubric {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-size: medium; }
+
+div.system-messages {
+  margin: 5em; }
+
+div.system-messages h1 {
+  color: #b30000; }
+
+div.system-message {
+  border: medium outset;
+  padding: 1em; }
+
+div.system-message p.system-message-title {
+  color: #b30000;
+  font-weight: bold; }
+
+div.topic {
+  margin: 2em; }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em; }
+
+h1.title {
+  text-align: center; }
+
+h2.subtitle {
+  text-align: center; }
+
+hr.docutils {
+  width: 75%; }
+
+img.align-left, .figure.align-left, object.align-left {
+  clear: left;
+  float: left;
+  margin-right: 1em; }
+
+img.align-right, .figure.align-right, object.align-right {
+  clear: right;
+  float: right;
+  margin-left: 1em; }
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto; }
+
+.align-left {
+  text-align: left; }
+
+.align-center {
+  clear: both;
+  text-align: center; }
+
+.align-right {
+  text-align: right; }
+
+/* reset inner alignment in figures */
+div.align-right {
+  text-align: inherit; }
+
+/* div.align-center * { */
+/*   text-align: left } */
+ol.simple, ul.simple {
+  margin-bottom: 1em; }
+
+ol.arabic {
+  list-style: decimal; }
+
+ol.loweralpha {
+  list-style: lower-alpha; }
+
+ol.upperalpha {
+  list-style: upper-alpha; }
+
+ol.lowerroman {
+  list-style: lower-roman; }
+
+ol.upperroman {
+  list-style: upper-roman; }
+
+p.attribution {
+  text-align: right;
+  margin-left: 50%; }
+
+p.caption {
+  font-style: italic; }
+
+p.credits {
+  font-style: italic;
+  font-size: smaller; }
+
+p.label {
+  white-space: nowrap; }
+
+p.rubric {
+  font-weight: bold;
+  font-size: larger;
+  color: maroon;
+  text-align: center; }
+
+p.sidebar-title {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: bold;
+  font-size: larger; }
+
+p.sidebar-subtitle {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: bold; }
+
+p.topic-title {
+  font-weight: bold; }
+
+pre.address {
+  margin-bottom: 0;
+  margin-top: 0;
+  font: inherit; }
+
+pre.literal-block, pre.doctest-block, pre.math, pre.code {
+  margin-left: 2em;
+  margin-right: 2em; }
+
+pre.code .ln {
+  color: grey; }
+
+/* line numbers */
+pre.code, code {
+  background-color: #eeeeee; }
+
+pre.code .comment, code .comment {
+  color: #5c6576; }
+
+pre.code .keyword, code .keyword {
+  color: #3B0D06;
+  font-weight: bold; }
+
+pre.code .literal.string, code .literal.string {
+  color: #0c5404; }
+
+pre.code .name.builtin, code .name.builtin {
+  color: #352b84; }
+
+pre.code .deleted, code .deleted {
+  background-color: #DEB0A1; }
+
+pre.code .inserted, code .inserted {
+  background-color: #A3D289; }
+
+span.classifier {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-style: oblique; }
+
+span.classifier-delimiter {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif;
+  font-weight: bold; }
+
+span.interpreted {
+  font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; }
+
+span.option {
+  white-space: nowrap; }
+
+span.pre {
+  white-space: pre; }
+
+span.problematic {
+  color: #b30000; }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80%; }
+
+table.citation {
+  border-left: solid 1px #666666;
+  margin-left: 1px; }
+
+table.docinfo {
+  margin: 0em;
+  margin-top: 2em;
+  margin-bottom: 2em;
+  font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important;
+  color: #444444; }
+
+table.docutils {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em; }
+
+table.footnote {
+  border-left: solid 1px #2d2d2d;
+  margin-left: 1px; }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  vertical-align: top; }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: 700;
+  text-align: left;
+  white-space: nowrap;
+  padding-left: 0; }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100%; }
+
+ul.auto-toc {
+  list-style-type: none; }
+
+span.DecNumber {
+  color: #252dbe; }
+
+span.BinNumber {
+  color: #252dbe; }
+
+span.HexNumber {
+  color: #252dbe; }
+
+span.OctNumber {
+  color: #252dbe; }
+
+span.FloatNumber {
+  color: #252dbe; }
+
+span.Identifier {
+  color: #3b3b3b; }
+
+span.Keyword {
+  font-weight: 600;
+  color: #5e8f60; }
+
+span.StringLit {
+  color: #a4255b; }
+
+span.LongStringLit {
+  color: #a4255b; }
+
+span.CharLit {
+  color: #a4255b; }
+
+span.EscapeSequence {
+  color: black; }
+
+span.Operator {
+  color: black; }
+
+span.Punctuation {
+  color: black; }
+
+span.Comment, span.LongComment {
+  font-style: italic;
+  font-weight: 400;
+  color: #484a86; }
+
+span.RegularExpression {
+  color: darkviolet; }
+
+span.TagStart {
+  color: darkviolet; }
+
+span.TagEnd {
+  color: darkviolet; }
+
+span.Key {
+  color: #252dbe; }
+
+span.Value {
+  color: #252dbe; }
+
+span.RawData {
+  color: #a4255b; }
+
+span.Assembler {
+  color: #252dbe; }
+
+span.Preprocessor {
+  color: #252dbe; }
+
+span.Directive {
+  color: #252dbe; }
+
+span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference,
+span.Other {
+  color: black; }
+
+/* Pop type, const, proc, and iterator defs in nim def blocks */
+dt pre > span.Identifier, dt pre > span.Operator {
+  color: #155da4;
+  font-weight: 700; }
+
+dt pre > span.Identifier ~ span.Identifier, dt pre > span.Operator ~ span.Identifier {
+  color: inherit;
+  font-weight: inherit; }
+
+dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator {
+  color: inherit;
+  font-weight: inherit; }
+
+/* Nim sprite for the footer (taken from main page favicon) */
+.nim-sprite {
+  display: inline-block;
+  height: 12px;
+  width: 12px;
+  background-position: 0 0;
+  background-size: 12px 12px;
+  -webkit-filter: opacity(50%);
+  background-repeat: no-repeat;
+  background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA==");
+  margin-bottom: -5px; }
+</style>
+
+</head>
+<body>
+<div class="document" id="documentId">
+  <div class="container">
+    <h1 class="title">$title</h1>
+    $content
+    <div class="row">
+      <div class="twelve-columns footer">
+        <span class="nim-sprite"></span>
+        <br>
+        <small>Made with Nim. Generated: $date $time UTC</small>
+      </div>
+    </div>
+  </div>
+</div>
+$analytics
+</body>
+</html>
+"""
diff --git a/config/nimdoc.tex.cfg b/config/nimdoc.tex.cfg
new file mode 100644
index 000000000..599ede345
--- /dev/null
+++ b/config/nimdoc.tex.cfg
@@ -0,0 +1,123 @@
+# This is the config file for the documentation generator that produces TeX
+# output.
+# (c) 2012 Andreas Rumpf
+# Feel free to edit the templates as you need.
+
+split.item.toc = "20"  
+# too long entries in the table of contents wrap around
+# after this number of characters
+
+doc.section = """
+\chapter{$sectionTitle}\label{$sectionID}
+\begin{description}
+$content
+\end{description}
+"""
+
+doc.section.toc = ""
+# $sectionID $sectionTitleID $sectionTitle $content
+
+doc.item = """
+\item[\texttt{$header}\label{$itemID}]\mbox{~}\\*
+$desc
+"""
+
+doc.item.toc = ""
+#  \item $name\ref{$itemID}
+
+doc.toc = r"\tableofcontents \newpage"
+
+doc.body_toc = """
+$tableofcontents
+$moduledesc
+$content
+"""
+
+doc.body_no_toc = """
+$moduledesc
+$content
+"""
+
+doc.file = """
+% This file was generated by Nimrod.
+% Generated: $date $time UTC
+\documentclass[a4paper]{article}
+\usepackage[left=2cm,right=3cm,top=3cm,bottom=3cm]{geometry}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage{graphicx}
+\usepackage{lmodern}
+\usepackage{fancyvrb, courier}
+\usepackage{tabularx}
+\usepackage{hyperref}
+
+\begin{document}
+\title{$title $version}
+\author{$author}
+
+\tolerance 1414 
+\hbadness 1414 
+\emergencystretch 1.5em 
+\hfuzz 0.3pt 
+\widowpenalty=10000 
+\vfuzz \hfuzz 
+\raggedbottom 
+
+\maketitle
+
+\newenvironment{rstpre}{\VerbatimEnvironment\begingroup\begin{Verbatim}[fontsize=\footnotesize , commandchars=\\\{\}]}{\end{Verbatim}\endgroup}
+
+% to pack tabularx into a new environment, special syntax is needed :-(
+\newenvironment{rsttab}[1]{\tabularx{\linewidth}{#1}}{\endtabularx}
+
+\newcommand{\rstsub}[1]{\raisebox{-0.5ex}{\scriptsize{#1}}}
+\newcommand{\rstsup}[1]{\raisebox{0.5ex}{\scriptsize{#1}}}
+
+\newcommand{\rsthA}[1]{\section{#1}}
+\newcommand{\rsthB}[1]{\subsection{#1}}
+\newcommand{\rsthC}[1]{\subsubsection{#1}}
+\newcommand{\rsthD}[1]{\paragraph{#1}}
+\newcommand{\rsthE}[1]{\paragraph{#1}}
+
+\newcommand{\rstovA}[1]{\section*{#1}}
+\newcommand{\rstovB}[1]{\subsection*{#1}}
+\newcommand{\rstovC}[1]{\subsubsection*{#1}}
+\newcommand{\rstovD}[1]{\paragraph*{#1}}
+\newcommand{\rstovE}[1]{\paragraph*{#1}}
+
+% Syntax highlighting:
+\newcommand{\spanDecNumber}[1]{#1}
+\newcommand{\spanBinNumber}[1]{#1}
+\newcommand{\spanHexNumber}[1]{#1}
+\newcommand{\spanOctNumber}[1]{#1}
+\newcommand{\spanFloatNumber}[1]{#1}
+\newcommand{\spanIdentifier}[1]{#1}
+\newcommand{\spanKeyword}[1]{\textbf{#1}}
+\newcommand{\spanStringLit}[1]{#1}
+\newcommand{\spanLongStringLit}[1]{#1}
+\newcommand{\spanCharLit}[1]{#1}
+\newcommand{\spanEscapeSequence}[1]{#1}
+\newcommand{\spanOperator}[1]{#1}
+\newcommand{\spanPunctuation}[1]{#1}
+\newcommand{\spanComment}[1]{\emph{#1}}
+\newcommand{\spanLongComment}[1]{\emph{#1}}
+\newcommand{\spanRegularExpression}[1]{#1}
+\newcommand{\spanTagStart}[1]{#1}
+\newcommand{\spanTagEnd}[1]{#1}
+\newcommand{\spanKey}[1]{#1}
+\newcommand{\spanValue}[1]{#1}
+\newcommand{\spanRawData}[1]{#1}
+\newcommand{\spanAssembler}[1]{#1}
+\newcommand{\spanPreprocessor}[1]{#1}
+\newcommand{\spanDirective}[1]{#1}
+\newcommand{\spanCommand}[1]{#1}
+\newcommand{\spanRule}[1]{#1}
+\newcommand{\spanHyperlink}[1]{#1}
+\newcommand{\spanLabel}[1]{#1}
+\newcommand{\spanReference}[1]{#1}
+\newcommand{\spanOther}[1]{#1}
+\newcommand{\spantok}[1]{\frame{#1}}
+
+$content
+\end{document}
+"""
diff --git a/config/rename.rules.cfg b/config/rename.rules.cfg
new file mode 100644
index 000000000..7b0a3a106
--- /dev/null
+++ b/config/rename.rules.cfg
@@ -0,0 +1,9 @@
+TSignedInt
+TUnsignedInt
+TOrdinal
+TReal
+TNumber
+TEnum
+TObject
+TResult
+TOpenArray
diff --git a/contributors.txt b/contributors.txt
new file mode 100644
index 000000000..e9909c677
--- /dev/null
+++ b/contributors.txt
@@ -0,0 +1,13 @@
+Comex
+Eric Doughty-Papassideris
+Simon Hafner
+Keita Haga
+Grzegorz Adam Hankiewicz
+Philippe Lhoste
+Zahary Karadjov
+Mario Ray Mahardhika
+Alex Mitchell
+Dominik Picheta
+Jonathan Plona
+Alexander Rødseth
+
diff --git a/copying.txt b/copying.txt
new file mode 100644
index 000000000..d89bace0b
--- /dev/null
+++ b/copying.txt
@@ -0,0 +1,24 @@
+=====================================================
+Nim -- a Compiler for Nim. http://nim-lang.org/
+
+Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
+ 
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+ 
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
\ No newline at end of file
diff --git a/doc/advopt.txt b/doc/advopt.txt
new file mode 100644
index 000000000..195122cc7
--- /dev/null
+++ b/doc/advopt.txt
@@ -0,0 +1,78 @@
+Advanced commands:
+  //compileToC, cc          compile project with C code generator
+  //compileToCpp, cpp       compile project to C++ code
+  //compileToOC, objc       compile project to Objective C code
+  //js                      compile project to Javascript
+  //rst2html                convert a reStructuredText file to HTML
+  //rst2tex                 convert a reStructuredText file to TeX
+  //jsondoc                 extract the documentation to a json file
+  //buildIndex              build an index for the whole documentation
+  //run                     run the project (with Tiny C backend; buggy!)
+  //genDepend               generate a DOT file containing the
+                            module dependency graph
+  //dump                    dump all defined conditionals and search paths
+  //check                   checks the project for syntax and semantic
+
+Advanced options:
+  -o, --out:FILE            set the output filename
+  --stdout                  output to stdout
+  --listFullPaths           list full paths in messages
+  -w, --warnings:on|off     turn all warnings on|off
+  --warning[X]:on|off       turn specific warning X on|off
+  --hints:on|off            turn all hints on|off
+  --hint[X]:on|off          turn specific hint X on|off
+  --lib:PATH                set the system library path
+  --import:PATH             add an automatically imported module
+  --include:PATH            add an automatically included module
+  --nimcache:PATH           set the path used for generated files
+  --header:FILE             the compiler should produce a .h file (FILE
+                            is optional)
+  -c, --compileOnly         compile only; do not assemble or link
+  --noLinking               compile but do not link
+  --noMain                  do not generate a main procedure
+  --genScript               generate a compile script (in the 'nimcache'
+                            subdirectory named 'compile_$project$scriptext')
+  --os:SYMBOL               set the target operating system (cross-compilation)
+  --cpu:SYMBOL              set the target processor (cross-compilation)
+  --debuginfo               enables debug information
+  -t, --passC:OPTION        pass an option to the C compiler
+  -l, --passL:OPTION        pass an option to the linker
+  --cincludes:DIR           modify the C compiler header search path
+  --clibdir:DIR             modify the linker library search path
+  --clib:LIBNAME            link an additional C library
+                            (you should omit platform-specific extensions)
+  --genMapping              generate a mapping file containing
+                            (Nim, mangled) identifier pairs
+  --project                 document the whole project (doc2)
+  --docSeeSrcUrl:url        activate 'see source' for doc and doc2 commands
+                            (see doc.item.seesrc in config/nimdoc.cfg)
+  --lineDir:on|off          generation of #line directive on|off
+  --embedsrc                embeds the original source code as comments
+                            in the generated output
+  --threadanalysis:on|off   turn thread analysis on|off
+  --tlsEmulation:on|off     turn thread local storage emulation on|off
+  --taintMode:on|off        turn taint mode on|off
+  --implicitStatic:on|off   turn implicit compile time evaluation on|off
+  --patterns:on|off         turn pattern matching on|off
+  --skipCfg                 do not read the general configuration file
+  --skipUserCfg             do not read the user's configuration file
+  --skipParentCfg           do not read the parent dirs' configuration files
+  --skipProjCfg             do not read the project's configuration file
+  --gc:refc|v2|markAndSweep|boehm|none
+                            select the GC to use; default is 'refc'
+  --index:on|off            turn index file generation on|off
+  --putenv:key=value        set an environment variable
+  --NimblePath:PATH         add a path for Nimble support
+  --noNimblePath            deactivate the Nimble path
+  --excludePath:PATH        exclude a path from the list of search paths
+  --dynlibOverride:SYMBOL   marks SYMBOL so that dynlib:SYMBOL
+                            has no effect and can be statically linked instead;
+                            symbol matching is fuzzy so
+                            that --dynlibOverride:lua matches
+                            dynlib: "liblua.so.3"
+  --listCmd                 list the commands used to execute external programs
+  --parallelBuild:0|1|...   perform a parallel build
+                            value = number of processors (0 for auto-detect)
+  --verbosity:0|1|2|3       set Nim's verbosity level (1 is default)
+  --experimental            enable experimental language features
+  -v, --version             show detailed version information
diff --git a/doc/apis.txt b/doc/apis.txt
new file mode 100644
index 000000000..165279490
--- /dev/null
+++ b/doc/apis.txt
@@ -0,0 +1,81 @@
+=================
+API naming design
+=================
+
+The API is designed to be **easy to use** and consistent. Ease of use is
+measured by the number of calls to achieve a concrete high level action.
+
+
+Naming scheme
+=============
+
+The library uses a simple naming scheme that makes use of common abbreviations
+to keep the names short but meaningful. Since version 0.8.2 many symbols have
+been renamed to fit this scheme. The ultimate goal is that the programmer can
+*guess* a name.
+
+
+-------------------     ------------   --------------------------------------
+English word            To use         Notes
+-------------------     ------------   --------------------------------------
+initialize              initT          ``init`` is used to create a
+                                       value type ``T``
+new                     newP           ``new`` is used to create a 
+                                       reference type ``P``
+find                    find           should return the position where
+                                       something was found; for a bool result
+                                       use ``contains``
+contains                contains       often short for ``find() >= 0``
+append                  add            use ``add`` instead of ``append``
+compare                 cmp            should return an int with the
+                                       ``< 0`` ``== 0`` or ``> 0`` semantics;
+                                       for a bool result use ``sameXYZ``
+put                     put, ``[]=``   consider overloading ``[]=`` for put
+get                     get, ``[]``    consider overloading ``[]`` for get;
+                                       consider to not use ``get`` as a
+                                       prefix: ``len`` instead of ``getLen``
+length                  len            also used for *number of elements*
+size                    size, len      size should refer to a byte size
+capacity                cap
+memory                  mem            implies a low-level operation
+items                   items          default iterator over a collection
+pairs                   pairs          iterator over (key, value) pairs
+delete                  delete, del    del is supposed to be faster than
+                                       delete, because it does not keep
+                                       the order; delete keeps the order
+remove                  delete, del    inconsistent right now
+include                 incl
+exclude                 excl
+command                 cmd
+execute                 exec
+environment             env
+variable                var
+value                   value, val     val is preferred, inconsistent right
+                                       now
+executable              exe
+directory               dir
+path                    path           path is the string "/usr/bin" (for
+                                       example), dir is the content of
+                                       "/usr/bin"; inconsistent right now
+extension               ext
+separator               sep
+column                  col, column    col is preferred, inconsistent right
+                                       now
+application             app
+configuration           cfg
+message                 msg
+argument                arg
+object                  obj
+parameter               param
+operator                opr
+procedure               proc
+function                func
+coordinate              coord
+rectangle               rect
+point                   point
+symbol                  sym
+literal                 lit
+string                  str
+identifier              ident
+indentation             indent
+-------------------     ------------   --------------------------------------
diff --git a/doc/astspec.txt b/doc/astspec.txt
new file mode 100644
index 000000000..68bb9f1cd
--- /dev/null
+++ b/doc/astspec.txt
@@ -0,0 +1,572 @@
+The AST in Nim
+=================
+This section describes how the AST is modelled with Nim's type system.
+The AST consists of nodes (``NimNode``) with a variable number of
+children. Each node has a field named ``kind`` which describes what the node
+contains:
+
+.. code-block:: nim
+
+  type
+    NimNodeKind = enum     ## kind of a node; only explanatory
+      nnkNone,             ## invalid node kind
+      nnkEmpty,            ## empty node
+      nnkIdent,            ## node contains an identifier
+      nnkIntLit,           ## node contains an int literal (example: 10)
+      nnkStrLit,           ## node contains a string literal (example: "abc")
+      nnkNilLit,           ## node contains a nil literal (example: nil)
+      nnkCaseStmt,         ## node represents a case statement
+      ...                  ## many more
+
+    NimNode = ref NimNodeObj
+    NimNodeObj = object
+      case kind: NimNodeKind           ## the node's kind
+      of nnkNone, nnkEmpty, nnkNilLit:
+        discard                        ## node contains no additional fields
+      of nnkCharLit..nnkUInt64Lit:
+        intVal: biggestInt             ## the int literal
+      of nnkFloatLit..nnkFloat64Lit:
+        floatVal: biggestFloat         ## the float literal
+      of nnkStrLit..nnkTripleStrLit:
+        strVal: string                 ## the string literal
+      of nnkIdent:
+        ident: NimIdent                ## the identifier
+      of nnkSym:
+        symbol: NimSymbol              ## the symbol (after symbol lookup phase)
+      else:
+        sons: seq[NimNode]             ## the node's sons (or children)
+
+For the ``NimNode`` type, the ``[]`` operator has been overloaded:
+``n[i]`` is ``n``'s ``i``-th child.
+
+To specify the AST for the different Nim constructs, the notation
+``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or 
+``nodekind(field=value)`` is used.
+
+Some child may be missing. A missing child is a node of kind ``nnkEmpty``; 
+a child can never be nil.
+
+
+Leaf nodes/Atoms
+================
+A leaf of the AST often corresponds to a terminal symbol in the concrete 
+syntax.
+
+-----------------                ---------------------------------------------
+Nim expression                   corresponding AST
+-----------------                ---------------------------------------------
+``42``                           ``nnkIntLit(intVal = 42)``
+``42'i8``                        ``nnkInt8Lit(intVal = 42)``
+``42'i16``                       ``nnkInt16Lit(intVal = 42)``
+``42'i32``                       ``nnkInt32Lit(intVal = 42)``
+``42'i64``                       ``nnkInt64Lit(intVal = 42)``
+``42.0``                         ``nnkFloatLit(floatVal = 42.0)``
+``42.0'f32``                     ``nnkFloat32Lit(floatVal = 42.0)``
+``42.0'f64``                     ``nnkFloat64Lit(floatVal = 42.0)``
+``"abc"``                        ``nnkStrLit(strVal = "abc")``
+``r"abc"``                       ``nnkRStrLit(strVal = "abc")``
+``"""abc"""``                    ``nnkTripleStrLit(strVal = "abc")``
+``' '``                          ``nnkCharLit(intVal = 32)``
+``nil``                          ``nnkNilLit()``
+``myIdentifier``                 ``nnkIdent(ident = !"myIdentifier")``
+``myIdentifier``                 after lookup pass: ``nnkSym(symbol = ...)``
+-----------------                ---------------------------------------------
+
+Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes
+get transferred into ``nnkSym`` nodes.
+
+
+Calls/expressions
+=================
+
+Command call
+------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  echo "abc", "xyz"
+
+AST:
+
+.. code-block:: nim
+  nnkCommand(nnkIdent(!"echo"), nnkStrLit("abc"), nnkStrLit("xyz"))
+
+
+Call with ``()``
+----------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  echo("abc", "xyz")
+
+AST:
+
+.. code-block:: nim
+  nnkCall(nnkIdent(!"echo"), nnkStrLit("abc"), nnkStrLit("xyz"))
+
+
+Infix operator call
+-------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  "abc" & "xyz"
+
+AST:
+
+.. code-block:: nim
+  nnkInfix(nnkIdent(!"&"), nnkStrLit("abc"), nnkStrLit("xyz"))
+
+
+Prefix operator call
+--------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  ? "xyz"
+
+AST:
+
+.. code-block:: nim
+  nnkPrefix(nnkIdent(!"?"), nnkStrLit("abc"))
+
+
+Postfix operator call
+---------------------
+
+**Note:** There are no postfix operators in Nim. However, the 
+``nnkPostfix`` node is used for the *asterisk export marker* ``*``:
+
+Concrete syntax:
+
+.. code-block:: nim
+  identifier*
+
+AST:
+
+.. code-block:: nim
+  nnkPostfix(nnkIdent(!"*"), nnkIdent(!"identifier"))
+
+
+Call with named arguments
+-------------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  writeln(file=stdout, "hallo")
+
+AST:
+
+.. code-block:: nim
+  nnkCall(nnkIdent(!"writeln"), 
+          nnkExprEqExpr(nnkIdent(!"file"), nnkIdent(!"stdout")), 
+          nnkStrLit("hallo"))
+
+
+Dereference operator ``[]``
+---------------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  x[]
+
+AST:
+
+.. code-block:: nim
+  nnkDerefExpr(nnkIdent(!"x"))
+
+
+Addr operator
+-------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  addr(x)
+
+AST:
+
+.. code-block:: nim
+  nnkAddr(nnkIdent(!"x"))
+
+
+Cast operator
+-------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  cast[T](x)
+
+AST:
+
+.. code-block:: nim
+  nnkCast(nnkIdent(!"T"), nnkIdent(!"x"))
+
+
+Object access operator ``.``
+----------------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  x.y
+
+AST:
+
+.. code-block:: nim
+  nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y"))
+
+
+Array access operator ``[]``
+----------------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  x[y]
+
+AST:
+
+.. code-block:: nim
+  nnkBracketExpr(nnkIdent(!"x"), nnkIdent(!"y"))
+
+
+Parentheses
+-----------
+
+Parentheses for affecting operator precedence or tuple construction 
+are built with the ``nnkPar`` node.
+
+Concrete syntax:
+
+.. code-block:: nim
+  (1, 2, (3))
+
+AST:
+
+.. code-block:: nim
+  nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3)))
+  
+  
+Curly braces
+------------
+
+Curly braces are used as the set constructor. 
+
+Concrete syntax:
+
+.. code-block:: nim
+  {1, 2, 3}
+
+AST:
+
+.. code-block:: nim
+  nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
+
+
+Brackets
+--------
+
+Brackets are used as the array constructor.  
+
+Concrete syntax:
+
+.. code-block:: nim
+  [1, 2, 3]
+
+AST:
+
+.. code-block:: nim
+  nnkBracket(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
+
+
+Ranges
+------
+
+Ranges occur in set constructors, case statement branches or array slices.
+
+Concrete syntax:
+
+.. code-block:: nim
+  1..3
+
+AST:
+
+.. code-block:: nim
+  nnkRange(nnkIntLit(1), nnkIntLit(3))
+
+
+If expression
+-------------
+
+The representation of the if expression is subtle, but easy to traverse.
+
+Concrete syntax:
+
+.. code-block:: nim
+  if cond1: expr1 elif cond2: expr2 else: expr3
+
+AST:
+
+.. code-block:: nim
+  nnkIfExpr(
+    nnkElifExpr(cond1, expr1),
+    nnkElifExpr(cond2, expr2),
+    nnkElseExpr(expr3)
+  )
+
+
+Statements
+==========
+
+If statement
+------------
+
+The representation of the if statement is subtle, but easy to traverse. If
+there is no ``else`` branch, no ``nnkElse`` child exists.
+
+Concrete syntax:
+
+.. code-block:: nim
+  if cond1: 
+    stmt1
+  elif cond2:
+    stmt2
+  elif cond3:
+    stmt3
+  else:
+    stmt4
+
+AST:
+
+.. code-block:: nim
+  nnkIfStmt(
+    nnkElifBranch(cond1, stmt1),
+    nnkElifBranch(cond2, stmt2),
+    nnkElifBranch(cond3, stmt3),
+    nnkElse(stmt4)
+  )
+
+
+When statement
+--------------
+
+Like the ``if`` statement, but the root has the kind ``nnkWhenStmt``.
+
+
+Assignment
+----------
+
+Concrete syntax:
+
+.. code-block:: nim
+  x = 42
+
+AST:
+
+.. code-block:: nim
+  nnkAsgn(nnkIdent(!"x"), nnkIntLit(42))
+
+
+Statement list
+--------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  stmt1
+  stmt2
+  stmt3
+
+AST:
+
+.. code-block:: nim
+  nnkStmtList(stmt1, stmt2, stmt3)
+
+  
+Case statement
+--------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  case expr1
+  of expr2, expr3..expr4: 
+    stmt1
+  of expr5:
+    stmt2
+  elif cond1:
+    stmt3
+  else:
+    stmt4
+
+AST:
+
+.. code-block:: nim
+  nnkCaseStmt(
+    expr1,
+    nnkOfBranch(expr2, nnkRange(expr3, expr4), stmt1),
+    nnkOfBranch(expr5, stmt2),
+    nnkElifBranch(cond1, stmt3),
+    nnkElse(stmt4)
+  )
+
+The ``nnkElifBranch`` and ``nnkElse`` parts may be missing.
+
+
+While statement
+---------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  while expr1:
+    stmt1
+
+AST:
+
+.. code-block:: nim
+  nnkWhileStmt(expr1, stmt1)
+
+
+For statement
+-------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  for ident1, ident2 in expr1:
+    stmt1
+
+AST:
+
+.. code-block:: nim
+  nnkForStmt(ident1, ident2, expr1, stmt1)
+
+
+Try statement
+-------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  try:
+    stmt1
+  except e1, e2: 
+    stmt2
+  except e3:
+    stmt3
+  except: 
+    stmt4
+  finally:
+    stmt5
+
+AST:
+
+.. code-block:: nim
+  nnkTryStmt(
+    stmt1, 
+    nnkExceptBranch(e1, e2, stmt2), 
+    nnkExceptBranch(e3, stmt3), 
+    nnkExceptBranch(stmt4),
+    nnkFinally(stmt5)
+  )
+
+
+Return statement
+----------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  return expr1
+
+AST:
+
+.. code-block:: nim
+  nnkReturnStmt(expr1)
+
+
+Yield statement
+---------------
+
+Like ``return``, but with ``nnkYieldStmt`` kind.
+
+
+Discard statement
+-----------------
+
+Like ``return``, but with ``nnkDiscardStmt`` kind.
+
+
+Continue statement
+------------------
+
+Concrete syntax:
+
+.. code-block:: nim
+  continue
+
+AST:
+
+.. code-block:: nim
+  nnkContinueStmt()
+
+Var section
+-----------
+
+To be written.
+
+
+Const section
+-------------
+
+To be written.
+
+
+Type section
+------------
+
+To be written.
+
+
+Procedure declaration
+---------------------
+
+To be written.
+
+
+Iterator declaration
+--------------------
+
+To be written.
+
+
+Template declaration
+--------------------
+
+To be written.
+
+
+Macro declaration
+-----------------
+
+To be written.
+
+
+Special node kinds
+==================
+
+There are several node kinds that are used for semantic checking or code 
+generation. These are accessible from this module, but should not be used.
+Other node kinds are especially designed to make AST manipulations easier.
+These are explained here. 
+
+To be written.
diff --git a/doc/backends.txt b/doc/backends.txt
new file mode 100644
index 000000000..c7939baec
--- /dev/null
+++ b/doc/backends.txt
@@ -0,0 +1,463 @@
+================================
+   Nim Backend Integration
+================================
+
+:Author: Puppet Master
+:Version: |nimversion|
+
+.. contents::
+  "Heresy grows from idleness." -- Unknown.
+
+
+Introduction
+============
+
+The `Nim Compiler User Guide <nimc.html>`_ documents the typical
+compiler invocation, using the ``compile`` or ``c`` command to transform a
+``.nim`` file into one or more ``.c`` files which are then compiled with the
+platform's C compiler into a static binary. However there are other commands
+to compile to C++, Objective-C or JavaScript. This document tries to
+concentrate in a single place all the backend and interfacing options.
+
+The Nim compiler supports mainly two backend families: the C, C++ and
+Objective-C targets and the JavaScript target. `The C like targets`_ creates
+source files which can be compiled into a library or a final executable. `The
+JavaScript target`_ can generate a ``.js`` file which you reference from an
+HTML file or create a `standalone nodejs program <http://nodejs.org>`_.
+
+On top of generating libraries or standalone applications, Nim offers
+bidirectional interfacing with the backend targets through generic and
+specific pragmas.
+
+
+Backends
+========
+
+The C like targets
+------------------
+
+The commands to compile to either C, C++ or Objective-C are:
+
+  //compileToC, cc          compile project with C code generator
+  //compileToCpp, cpp       compile project to C++ code
+  //compileToOC, objc       compile project to Objective C code
+
+The most significant difference between these commands is that if you look
+into the ``nimcache`` directory you will find ``.c``, ``.cpp`` or ``.m``
+files, other than that all of them will produce a native binary for your
+project.  This allows you to take the generated code and place it directly
+into a project using any of these languages. Here are some typical command
+line invocations::
+
+    $ nim c hallo.nim
+    $ nim cpp hallo.nim
+    $ nim objc hallo.nim
+
+The compiler commands select the target backend, but if needed you can
+`specify additional switches for cross compilation
+<nimc.html#cross-compilation>`_ to select the target CPU, operative system
+or compiler/linker commands.
+
+
+The JavaScript target
+---------------------
+
+Nim can also generate `JavaScript`:idx: code through the ``js`` command.
+However, the JavaScript code generator is experimental!
+
+Nim targets JavaScript 1.5 which is supported by any widely used browser.
+Since JavaScript does not have a portable means to include another module,
+Nim just generates a long ``.js`` file.
+
+Features or modules that the JavaScript platform does not support are not
+available. This includes:
+
+* manual memory management (``alloc``, etc.)
+* casting and other unsafe operations (``cast`` operator, ``zeroMem``, etc.)
+* file management
+* most modules of the Standard library
+* proper 64 bit integer arithmetic
+* unsigned integer arithmetic
+
+However, the modules `strutils <strutils.html>`_, `math <math.html>`_, and
+`times <times.html>`_ are available! To access the DOM, use the `dom
+<dom.html>`_ module that is only available for the JavaScript platform.
+
+To compile a Nim module into a ``.js`` file use the ``js`` command; the
+default is a ``.js`` file that is supposed to be referenced in an ``.html``
+file. However, you can also run the code with `nodejs`:idx:, a `software
+platform for easily building fast, scalable network applications
+<http://nodejs.org>`_::
+
+  nim js -d:nodejs -r examples/hallo.nim
+
+
+Interfacing
+===========
+
+Nim offers bidirectional interfacing with the target backend. This means
+that you can call backend code from Nim and Nim code can be called by
+the backend code. Usually the direction of which calls which depends on your
+software architecture (is Nim your main program or is Nim providing a
+component?).
+
+
+Nim code calling the backend
+----------------------------
+
+Nim code can interface with the backend through the `Foreign function
+interface <manual.html#foreign-function-interface>`_ mainly through the
+`importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the
+*generic* way of making backend symbols available in Nim and is available
+in all the target backends (JavaScript too).  The C++ or Objective-C backends
+have their respective `ImportCpp <nimc.html#importcpp-pragma>`_ and
+`ImportObjC <nimc.html#importobjc-pragma>`_ pragmas to call methods from
+classes.
+
+Whenever you use any of these pragmas you need to integrate native code into
+your final binary. In the case of JavaScript this is no problem at all, the
+same html file which hosts the generated JavaScript will likely provide other
+JavaScript functions which you are importing with ``importc``.
+
+However, for the C like targets you need to link external code either
+statically or dynamically. The preferred way of integrating native code is to
+use dynamic linking because it allows you to compile Nim programs without
+the need for having the related development libraries installed. This is done
+through the `dynlib pragma for import
+<manual.html#dynlib-pragma-for-import>`_, though more specific control can be
+gained using the `dynlib module <dynlib.html>`_.
+
+The `dynlibOverride <nimc.html#dynliboverride>`_ command line switch allows
+to avoid dynamic linking if you need to statically link something instead.
+Nim wrappers designed to statically link source files can use the `compile
+pragma <nimc.html#compile-pragma>`_ if there are few sources or providing
+them along the Nim code is easier than using a system library. Libraries
+installed on the host system can be linked in with the `PassL pragma
+<nimc.html#passl-pragma>`_.
+
+To wrap native code, take a look at the `c2nim tool <c2nim.html>`_ which helps
+with the process of scanning and transforming header files into a Nim
+interface.
+
+C invocation example
+~~~~~~~~~~~~~~~~~~~~
+
+Create a ``logic.c`` file with the following content:
+
+.. code-block:: c
+  int addTwoIntegers(int a, int b)
+  {
+    return a + b;
+  }
+
+Create a ``calculator.nim`` file with the following content:
+
+.. code-block:: nim
+
+  {.compile: "logic.c".}
+  proc addTwoIntegers(a, b: cint): cint {.importc.}
+
+  when isMainModule:
+    echo addTwoIntegers(3, 7)
+
+With these two files in place, you can run ``nim c -r calculator.nim`` and
+the Nim compiler will compile the ``logic.c`` file in addition to
+``calculator.nim`` and link both into an executable, which outputs ``10`` when
+run. Another way to link the C file statically and get the same effect would
+be remove the line with the ``compile`` pragma and run the following typical
+Unix commands::
+
+    $ gcc -c logic.c
+    $ ar rvs mylib.a logic.o
+    $ nim c --passL:mylib.a -r calculator.nim
+
+Just like in this example we pass the path to the ``mylib.a`` library (and we
+could as well pass ``logic.o``) we could be passing switches to link any other
+static C library.
+
+
+JavaScript invocation example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a ``host.html`` file with the following content:
+
+.. code-block::
+
+  <html><body>
+  <script type="text/javascript">
+  function addTwoIntegers(a, b)
+  {
+    return a + b;
+  }
+  </script>
+  <script type="text/javascript" src="calculator.js"></script>
+  </body></html>
+
+Create a ``calculator.nim`` file with the following content (or reuse the one
+from the previous section):
+
+.. code-block:: nim
+
+  proc addTwoIntegers(a, b: int): int {.importc.}
+
+  when isMainModule:
+    echo addTwoIntegers(3, 7)
+
+Compile the Nim code to JavaScript with ``nim js -o:calculator.js
+calculator.nim`` and open ``host.html`` in a browser. If the browser supports
+javascript, you should see the value ``10``. In JavaScript the `echo proc
+<system.html#echo>`_ will modify the HTML DOM and append the string. Use the
+`dom module <dom.html>`_ for specific DOM querying and modification procs.
+
+
+Backend code calling Nim
+------------------------
+
+Backend code can interface with Nim code exposed through the `exportc
+pragma <manual.html#exportc-pragma>`_. The ``exportc`` pragma is the *generic*
+way of making Nim symbols available to the backends. By default the Nim
+compiler will mangle all the Nim symbols to avoid any name collision, so
+the most significant thing the ``exportc`` pragma does is maintain the Nim
+symbol name, or if specified, use an alternative symbol for the backend in
+case the symbol rules don't match.
+
+The JavaScript target doesn't have any further interfacing considerations
+since it also has garbage collection, but the C targets require you to
+initialize Nim's internals, which is done calling a ``NimMain`` function.
+Also, C code requires you to specify a forward declaration for functions or
+the compiler will assume certain types for the return value and parameters
+which will likely make your program crash at runtime.
+
+The Nim compiler can generate a C interface header through the ``--header``
+command line switch. The generated header will contain all the exported
+symbols and the ``NimMain`` proc which you need to call before any other
+Nim code.
+
+
+Nim invocation example from C
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a ``fib.nim`` file with the following content:
+
+.. code-block:: nim
+
+  proc fib(a: cint): cint {.exportc.} =
+    if a <= 2:
+      result = 1
+    else:
+      result = fib(a - 1) + fib(a - 2)
+
+Create a ``maths.c`` file with the following content:
+
+.. code-block:: c
+
+  #include "fib.h"
+  #include <stdio.h>
+
+  int main(void)
+  {
+    NimMain();
+    for (int f = 0; f < 10; f++)
+      printf("Fib of %d is %d\n", f, fib(f));
+    return 0;
+  }
+
+Now you can run the following Unix like commands to first generate C sources
+form the Nim code, then link them into a static binary along your main C
+program::
+
+  $ nim c --noMain --noLinking --header:fib.h fib.nim
+  $ gcc -o m -Inimcache -Ipath/to/nim/lib nimcache/*.c maths.c
+
+The first command runs the Nim compiler with three special options to avoid
+generating a ``main()`` function in the generated files, avoid linking the
+object files into a final binary, and explicitly generate a header file for C
+integration. All the generated files are placed into the ``nimcache``
+directory. That's why the next command compiles the ``maths.c`` source plus
+all the ``.c`` files form ``nimcache``. In addition to this path, you also
+have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
+
+Instead of depending on the generation of the individual ``.c`` files you can
+also ask the Nim compiler to generate a statically linked library::
+
+  $ nim c --app:staticLib --noMain --header fib.nim
+  $ gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c
+
+The Nim compiler will handle linking the source files generated in the
+``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
+then link into your C program.  Note that these commands are generic and will
+vary for each system. For instance, on Linux systems you will likely need to
+use ``-ldl`` too to link in required dlopen functionality.
+
+
+Nim invocation example from JavaScript
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Create a ``mhost.html`` file with the following content:
+
+.. code-block::
+
+  <html><body>
+  <script type="text/javascript" src="fib.js"></script>
+  <script type="text/javascript">
+  alert("Fib for 9 is " + fib(9));
+  </script>
+  </body></html>
+
+Create a ``fib.nim`` file with the following content (or reuse the one
+from the previous section):
+
+.. code-block:: nim
+
+  proc fib(a: cint): cint {.exportc.} =
+    if a <= 2:
+      result = 1
+    else:
+      result = fib(a - 1) + fib(a - 2)
+
+Compile the Nim code to JavaScript with ``nim js -o:fib.js fib.nim`` and
+open ``mhost.html`` in a browser. If the browser supports javascript, you
+should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned
+earlier, JavaScript doesn't require an initialisation call to ``NimMain`` or
+similar function and you can call the exported Nim proc directly.
+
+
+Nimcache naming logic
+---------------------
+
+The `nimcache`:idx: directory is generated during compilation and will hold
+either temporary or final files depending on your backend target. The default
+name for the directory is ``nimcache`` but you can use the ``--nimcache``
+`compiler switch <nimc.html#command-line-switches>`_ to change it.
+
+Nimcache and C like targets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The C like backends will place their temporary ``.c``, ``.cpp`` or ``.m`` files
+in the ``nimcache`` directory. The naming of these files follows the pattern
+``nimblePackageName_`` + ``nimSource``:
+
+* Filenames for modules imported from `nimble packages
+  <https://github.com/nim-lang/nimble>`_ will end up with
+  ``nimblePackageName_module.c``. For example, if you import the
+  ``argument_parser`` module from the same name nimble package you
+  will end up with a ``argument_parser_argument_parser.c`` file
+  under ``nimcache``.  The name of the nimble package comes from the
+  ``proj.nimble`` file, the actual contents are not read by the
+  compiler.
+
+* Filenames for non nimble packages (like your project) will be
+  renamed from ``.nim`` to have the extension of your target backend
+  (from now on ``.c`` for these examples), but otherwise nothing
+  else will change. This will quickly break if your project consists
+  of a main ``proj.nim`` file which includes a ``utils/proj.nim``
+  file: both ``proj.nim`` files will generate the same name ``proj.c``
+  output in the ``nimcache`` directory overwriting themselves!
+
+* Filenames for modules found in the standard library will be named
+  ``stdlib_module.c``. Unless you are doing something special, you
+  will end up with at least ``stdlib_system.c``, since the `system
+  module <system.html>`_ is always imported automatically. Same for
+  the `hashes module <hashes.html>`_ which will be named
+  ``stdlib_hashes.c``. The ``stdlib_`` prefix comes from the *fake*
+  ``lib/stdlib.nimble`` file.
+
+To find the name of a nimble package the compiler searches for a ``*.nimble``
+file in the parent directory hierarchy of whatever module you are compiling.
+Even if you are in a subdirectory of your project, a parent ``*.nimble`` file
+will influence the naming of the nimcache name. This means that on Unix systems
+creating the file ``~/foo.nimble`` will automatically prefix all nimcache files
+not part of another package with the string ``foo_``.
+
+
+Nimcache and the Javascript target
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Unless you explicitly use the ``-o:filename.js`` switch as mentioned in the
+previous examples, the compiler will create a ``filename.js`` file in the
+``nimcache`` directory using the name of your input nim file. There are no
+other temporary files generated, the output is always a single self contained
+``.js`` file.
+
+
+Memory management
+=================
+
+In the previous sections the ``NimMain()`` function reared its head. Since
+JavaScript already provides automatic memory management, you can freely pass
+objects between the two language without problems. In C and derivate languages
+you need to be careful about what you do and how you share memory. The
+previous examples only dealt with simple scalar values, but passing a Nim
+string to C, or reading back a C string in Nim already requires you to be
+aware of who controls what to avoid crashing.
+
+
+Strings and C strings
+---------------------
+
+The manual mentions that `Nim strings are implicitly convertible to
+cstrings <manual.html#cstring-type>`_ which makes interaction usually
+painless. Most C functions accepting a Nim string converted to a
+``cstring`` will likely not need to keep this string around and by the time
+they return the string won't be needed any more. However, for the rare cases
+where a Nim string has to be preserved and made available to the C backend
+as a ``cstring``, you will need to manually prevent the string data from being
+freed with `GC_ref <system.html#GC_ref>`_ and `GC_unref
+<system.html#GC_unref>`_.
+
+A similar thing happens with C code invoking Nim code which returns a
+``cstring``. Consider the following proc:
+
+.. code-block:: nim
+
+  proc gimme(): cstring {.exportc.} =
+    result = "Hey there C code! " & $random(100)
+
+Since Nim's garbage collector is not aware of the C code, once the
+``gimme`` proc has finished it can reclaim the memory of the ``cstring``.
+However, from a practical standpoint, the C code invoking the ``gimme``
+function directly will be able to use it since Nim's garbage collector has
+not had a chance to run *yet*. This gives you enough time to make a copy for
+the C side of the program, as calling any further Nim procs *might* trigger
+garbage collection making the previously returned string garbage. Or maybe you
+are `triggering yourself the collection <gc.html>`_.
+
+
+Custom data types
+-----------------
+
+Just like strings, custom data types that are to be shared between Nim and
+the backend will need careful consideration of who controls who. If you want
+to hand a Nim reference to C code, you will need to use `GC_ref
+<system.html#GC_ref>`_ to mark the reference as used, so it does not get
+freed. And for the C backend you will need to expose the `GC_unref
+<system.html#GC_unref>`_ proc to clean up this memory when it is not required
+any more.
+
+Again, if you are wrapping a library which *mallocs* and *frees* data
+structures, you need to expose the appropriate *free* function to Nim so
+you can clean it up. And of course, once cleaned you should avoid accessing it
+from Nim (or C for that matter). Typically C data structures have their own
+``malloc_structure`` and ``free_structure`` specific functions, so wrapping
+these for the Nim side should be enough.
+
+
+Thread coordination
+-------------------
+
+When the ``NimMain()`` function is called Nim initializes the garbage
+collector to the current thread, which is usually the main thread of your
+application. If your C code later spawns a different thread and calls Nim
+code, the garbage collector will fail to work properly and you will crash.
+
+As long as you don't use the threadvar emulation Nim uses native thread
+variables, of which you get a fresh version whenever you create a thread. You
+can then attach a GC to this thread via
+
+.. code-block:: nim
+
+  system.setupForeignThreadGc()
+
+It is **not** safe to disable the garbage collector and enable it after the
+call from your background thread even if the code you are calling is short
+lived.
diff --git a/doc/basicopt.txt b/doc/basicopt.txt
new file mode 100644
index 000000000..6a905bd53
--- /dev/null
+++ b/doc/basicopt.txt
@@ -0,0 +1,40 @@
+::
+
+    nim command [options] [projectfile] [arguments]
+
+Command:
+  //compile, c                compile project with default code generator (C)
+  //doc                       generate the documentation for inputfile
+  //doc2                      generate the documentation for the whole project
+
+Arguments:
+  arguments are passed to the program being run (if --run option is selected)
+Options:
+  -p, --path:PATH           add path to search paths
+  -d, --define:SYMBOL       define a conditional symbol
+  -u, --undef:SYMBOL        undefine a conditional symbol
+  -f, --forceBuild          force rebuilding of all modules
+  --stackTrace:on|off       turn stack tracing on|off
+  --lineTrace:on|off        turn line tracing on|off
+  --threads:on|off          turn support for multi-threading on|off
+  -x, --checks:on|off       turn all runtime checks on|off
+  --objChecks:on|off        turn obj conversion checks on|off
+  --fieldChecks:on|off      turn case variant field checks on|off
+  --rangeChecks:on|off      turn range checks on|off
+  --boundChecks:on|off      turn bound checks on|off
+  --overflowChecks:on|off   turn int over-/underflow checks on|off
+  -a, --assertions:on|off   turn assertions on|off
+  --floatChecks:on|off      turn all floating point (NaN/Inf) checks on|off
+  --nanChecks:on|off        turn NaN checks on|off
+  --infChecks:on|off        turn Inf checks on|off
+  --deadCodeElim:on|off     whole program dead code elimination on|off
+  --opt:none|speed|size     optimize not at all or for speed|size
+                            Note: use -d:release for a release build!
+  --debugger:native|endb    use native debugger (gdb) | ENDB (experimental)
+  --app:console|gui|lib|staticlib
+                            generate a console app|GUI app|DLL|static library
+  -r, --run                 run the compiled program with given arguments
+  --advanced                show advanced command line switches
+  -h, --help                show this help
+
+Note, single letter options that take an argument require a colon. E.g. -p:PATH.
diff --git a/doc/docgen.txt b/doc/docgen.txt
new file mode 100644
index 000000000..40c464ebd
--- /dev/null
+++ b/doc/docgen.txt
@@ -0,0 +1,355 @@
+===================================
+   Nim DocGen Tools Guide
+===================================
+
+:Author: Erik O'Leary
+:Version: |nimversion|
+
+.. contents::
+
+
+Introduction
+============
+
+This document describes the `documentation generation tools`:idx: built into
+the `Nim compiler <nimc.html>`_, which can generate HTML and JSON output
+from input .nim files and projects, as well as HTML and LaTeX from input RST
+(reStructuredText) files. The output documentation will include module
+dependencies (``import``), any top-level documentation comments (##), and
+exported symbols (*), including procedures, types, and variables.
+
+
+Documentation Comments
+----------------------
+
+Any comments which are preceded by a double-hash (##), are interpreted as
+documentation.  Comments are parsed as RST (see `reference
+<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_), providing
+Nim module authors the ability to easily generate richly formatted
+documentation with only their well-documented code.
+
+Example:
+
+.. code-block:: nim
+  type Person* = object
+    ## This type contains a description of a person
+    name: string
+    age: int
+
+Outputs::
+  Person* = object
+    name: string
+    age: int
+
+This type contains a description of a person
+
+Field documentation comments can be added to fields like so:
+
+.. code-block:: nim
+  var numValues: int ## \
+    ## `numValues` stores the number of values
+
+Note that without the `*` following the name of the type, the documentation for
+this type would not be generated. Documentation will only be generated for
+*exported* types/procedures/etc.
+
+
+Nim file input
+-----------------
+
+The following examples will generate documentation for the below contrived
+*Nim* module, aptly named 'sample.nim'
+
+sample.nim:
+
+.. code-block:: nim
+  ## This module is a sample.
+
+  import strutils
+
+  proc helloWorld*(times: int) =
+    ## Takes an integer and outputs
+    ## as many "hello world!"s
+
+    for i in 0 .. times-1:
+      echo "hello world!"
+
+  helloWorld(5)
+
+
+Document Types
+==============
+
+
+HTML
+----
+
+Generation of HTML documents is done via both the ``doc`` and ``doc2``
+commands. These command take either a single .nim file, outputting a single
+.html file with the same base filename, or multiple .nim files, outputting
+multiple .html files and, optionally, an index file.
+
+The ``doc`` command::
+  nim doc sample
+
+Partial Output::
+  ...
+  proc helloWorld*(times: int)
+  ...
+
+Output can be viewed in full here: `docgen_sample.html <docgen_sample.html>`_.
+The next command, called ``doc2``, is very similar to the ``doc`` command, but
+will be run after the compiler performs semantic checking on the input nim
+module(s), which allows it to process macros.
+
+The ``doc2`` command::
+  nim doc2 sample
+
+Partial Output::
+  ...
+  proc helloWorld(times: int) {.raises: [], tags: [].}
+  ...
+
+The full output can be seen here: `docgen_sample2.html <docgen_sample2.html>`_.
+As you can see, the tool has extracted additional information provided to it by
+the compiler beyond what the ``doc`` command provides, such as pragmas attached
+implicitly by the compiler. This type of information is not available from
+looking at the AST (Abstract Syntax Tree) prior to semantic checking, as the
+``doc`` command does.
+
+
+JSON
+----
+
+Generation of JSON documents is done via the ``jsondoc`` command. This command
+takes in a .nim file, and outputs a .json file with the same base filename.
+Note that this tool is built off of the ``doc`` command, and therefore is
+performed before semantic checking.
+
+The ``jsondoc`` command::
+  nim jsondoc sample
+
+Output::
+  [
+    {
+      "comment": "This module is a sample."
+    },
+    {
+      "name": "helloWorld",
+      "type": "skProc",
+      "description": "Takes an integer and outputs as many &quot;hello world!&quot;s",
+      "code": "proc helloWorld*(times: int)"
+    }
+  ]
+
+
+Related Options
+===============
+
+Project switch
+--------------
+
+::
+  nim doc2 --project filename.nim
+
+This will recursively generate documentation of all nim modules imported
+into the input module, including system modules. Be careful with this command,
+as it may end up sprinkling html files all over your filesystem!
+
+
+Index switch
+------------
+
+::
+  nim doc2 --index:on filename.nim
+
+This will generate an index of all the exported symbols in the input Nim
+module, and put it into a neighboring file with the extension of ``.idx``. The
+index file is line oriented (newlines have to be escaped). Each line
+represents a tab separated record of several columns, the first two mandatory,
+the rest optional. See the `Index (idx) file format`_ section for details.
+
+Once index files have been generated for one or more modules, the Nim
+compiler command ``buildIndex directory`` can be run to go over all the index
+files in the specified directory to generate a `theindex.html <theindex.html>`_
+file.
+
+See source switch
+-----------------
+
+::
+  nim doc2 --docSeeSrcUrl:txt filename.nim
+
+When you pass the ``docSeeSrcUrl`` switch to docgen, after each documented item
+in your source code the hyper link *See source* will appear pointing to the
+implementation of that item on a GitHub repository. You can click the link to
+see the implementation of the item.
+
+If you want to reuse this feature in your own documentation you will have to
+modify ``config/nimdoc.cfg`` to contain a ``doc.item.seesrc`` value with a
+hyper link to your own code repository. As you will see by the comments in that
+file, the value ``txt`` passed on the command line will be used in the HTML
+template along others like ``$path`` and ``$line``.
+
+In the case of Nim's own documentation, the ``txt`` value is just a commit
+hash to append to a formatted URL to https://github.com/Araq/Nim. The
+``tools/nimweb.nim`` helper queries the current git commit hash during doc
+generation, but since you might be working on an unpublished repository, it
+also allows specifying a ``githash`` value in ``web/website.ini`` to force a
+specific commit in the output.
+
+
+Other Input Formats
+===================
+
+The *Nim compiler* also has support for RST (reStructuredText) files with
+the ``rst2html`` and ``rst2tex`` commands. Documents like this one are
+initially written in a dialect of RST which adds support for nim sourcecode
+highlighting with the ``.. code-block:: nim`` prefix. ``code-block`` also
+supports highlighting of C++ and some other c-like languages.
+
+Usage::
+  nim rst2html docgen.txt
+
+Output::
+  You're reading it!
+
+The input can be viewed here `docgen.txt <docgen.txt>`_. The ``rst2tex``
+command is invoked identically to ``rst2html``, but outputs a .tex file instead
+of .html.
+
+
+HTML anchor generation
+======================
+
+When you run the ``rst2html`` command, all sections in the RST document will
+get an anchor you can hyper link to. Usually you can guess the anchor lower
+casing the section title and replacing spaces with dashes, and in any case you
+can get it from the table of contents. But when you run the ``doc`` or ``doc2``
+commands to generate API documentation, some symbol get one or two anchors at
+the same time: a numerical identifier, or a plain name plus a complex name.
+
+The numerical identifier is just a random number. The number gets assigned
+according to the section and position of the symbol in the file being processed
+and you should not rely on it being constant: if you add or remove a symbol the
+numbers may shuffle around.
+
+The plain name of a symbol is a simplified version of its fully exported
+signature. Variables or constants have the same plain name symbol as their
+complex name. The plain name for procs, templates, and other callable types
+will be their unquoted value after removing parameters, return types and
+pragmas. The plain name allows short and nice linking of symbols which works
+unless you have a module with collisions due to overloading.
+
+If you hyper link a plain name symbol and there are other matches on the same
+HTML file, most browsers will go to the first one. To differentiate the rest,
+you will need to use the complex name. A complex name for a callable type is
+made up from several parts:
+
+    (**plain symbol**)(**.type**),(**first param**)?(**,param type**)\*
+
+The first thing to note is that all callable types have at least a comma, even
+if they don't have any parameters. If there are parameters, they are
+represented by their types and will be comma separated. To the plain symbol a
+suffix may be added depending on the type of the callable:
+
+-------------   --------------
+Callable type   Suffix
+-------------   --------------
+proc            *empty string*
+macro           ``.m``
+method          ``.e``
+iterator        ``.i``
+template        ``.t``
+converter       ``.c``
+-------------   --------------
+
+The relationship of type to suffix is made by the proc ``complexName`` in the
+``compiler/docgen.nim`` file. Here are some examples of complex names for
+symbols in the `system module <system.html>`_.
+
+* ``type SignedInt = int | int8 | int16 | int32 | int64`` **=>**
+  `#SignedInt <system.html#SignedInt>`_
+* ``var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}`` **=>**
+  `#globalRaiseHook <system.html#globalRaiseHook>`_
+* ``const NimVersion = "0.0.0"`` **=>**
+  `#NimVersion <system.html#NimVersion>`_
+* ``proc getTotalMem(): int {.rtl, raises: [], tags: [].}`` **=>**
+  `#getTotalMem, <system.html#getTotalMem,>`_
+* ``proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}`` **=>**
+  `#len,seq[T] <system.html#len,seq[T]>`_
+* ``iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}`` **=>**
+  `#pairs.i,seq[T] <system.html#pairs.i,seq[T]>`_
+* ``template newException[](exceptn: typedesc; message: string): expr`` **=>**
+  `#newException.t,typedesc,string
+  <system.html#newException.t,typedesc,string>`_
+
+
+Index (idx) file format
+=======================
+
+Files with the ``.idx`` extension are generated when you use the `Index
+switch`_ along with commands to generate documentation from source or text
+files. You can programatically generate indices with the `setIndexTerm()
+<rstgen.html#setIndexTerm>`_ and `writeIndexFile()
+<rstgen.html#writeIndexFile>`_ procs. The purpose of ``idx`` files is to hold
+the interesting symbols and their HTML references so they can be later
+concatenated into a big index file with `mergeIndexes()
+<rstgen.html#mergeIndexes>`_.  This section documents the file format in
+detail.
+
+Index files are line oriented and tab separated (newline and tab characters
+have to be escaped). Each line represents a record with at least two fields,
+but can have up to four (additional columns are ignored). The content of these
+columns is:
+
+1. Mandatory term being indexed. Terms can include quoting according to
+   Nim's rules (eg. \`^\` like in `the actors module
+   <actors.html#^,ptr.TChannel[T]>`_).
+2. Base filename plus anchor hyper link (eg.
+   ``algorithm.html#*,int,SortOrder``).
+3. Optional human readable string to display as hyper link. If the value is not
+   present or is the empty string, the hyper link will be rendered
+   using the term. Prefix whitespace indicates that this entry is
+   not for an API symbol but for a TOC entry.
+4. Optional title or description of the hyper link. Browsers usually display
+   this as a tooltip after hovering a moment over the hyper link.
+
+The index generation tools try to differentiate between documentation
+generated from ``.nim`` files and documentation generated from ``.txt`` or
+``.rst`` files. The former are always closely related to source code and
+consist mainly of API entries. The latter are generic documents meant for
+human reading.
+
+To differentiate both types (documents and APIs), the index generator will add
+to the index of documents an entry with the title of the document. Since the
+title is the topmost element, it will be added with a second field containing
+just the filename without any HTML anchor.  By convention this entry without
+anchor is the *title entry*, and since entries in the index file are added as
+they are scanned, the title entry will be the first line. The title for APIs
+is not present because it can be generated concatenating the name of the file
+to the word **Module**.
+
+Normal symbols are added to the index with surrounding whitespaces removed. An
+exception to this are table of content (TOC) entries. TOC entries are added to
+the index file with their third column having as much prefix spaces as their
+level is in the TOC (at least 1 character). The prefix whitespace helps to
+filter TOC entries from API or text symbols. This is important because the
+amount of spaces is used to replicate the hiearchy for document TOCs in the
+final index, and TOC entries found in ``.nim`` files are discarded.
+
+
+Additional resources
+====================
+
+`Nim Compiler User Guide <nimc.html#command-line-switches>`_
+
+`RST Quick Reference
+<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
+
+The output for HTML and LaTeX comes from the ``config/nimdoc.cfg`` and
+``config/nimdoc.tex.cfg`` configuration files. You can add and modify these
+files to your project to change the look of docgen output.
+
+You can import the `packages/docutils/rstgen module <rstgen.html>`_ in your
+programs if you want to reuse the compiler's documentation generation procs.
diff --git a/doc/docgen_sample.nim b/doc/docgen_sample.nim
new file mode 100644
index 000000000..875993187
--- /dev/null
+++ b/doc/docgen_sample.nim
@@ -0,0 +1,12 @@
+## This module is a sample.
+
+import strutils
+
+proc helloWorld*(times: int) =
+  ## Takes an integer and outputs
+  ## as many "hello world!"s
+
+  for i in 0 .. times-1:
+    echo "hello world!"
+
+helloWorld(5)
diff --git a/doc/docs.txt b/doc/docs.txt
new file mode 100644
index 000000000..ecf0cc268
--- /dev/null
+++ b/doc/docs.txt
@@ -0,0 +1,40 @@
+The documentation consists of several documents:
+
+- | `Tutorial (part I) <tut1.html>`_
+  | The Nim tutorial part one deals with the basics.
+
+- | `Tutorial (part II) <tut2.html>`_
+  | The Nim tutorial part two deals with the advanced language constructs.
+
+- | `Language Manual <manual.html>`_
+  | The Nim manual is a draft that will evolve into a proper specification.
+
+- | `Library documentation <lib.html>`_
+  | This document describes Nim's standard library.
+
+- | `Compiler user guide <nimc.html>`_
+  | The user guide lists command line arguments, special features of the
+    compiler, etc.
+
+- | `Tools documentation <tools.html>`_
+  | Description of some tools that come with the standard distribution.
+
+- | `GC <gc.html>`_
+  | Additional documentation about Nim's GC and how to operate it in a
+  | realtime setting.
+
+- | `Source code filters <filters.html>`_
+  | The Nim compiler supports source code filters as a simple yet powerful
+    builtin templating system.
+
+- | `Term rewriting macros <trmacros.html>`_
+  | Term rewriting macros enhance the compilation process with user defined 
+    optimizations.
+
+- | `Internal documentation <intern.html>`_
+  | The internal documentation describes how the compiler is implemented. Read
+    this if you want to hack the compiler.
+
+- | `Index <theindex.html>`_
+  | The generated index. **Index + (Ctrl+F) == Joy**
+
diff --git a/doc/effects.txt b/doc/effects.txt
new file mode 100644
index 000000000..4ed1d09f1
--- /dev/null
+++ b/doc/effects.txt
@@ -0,0 +1,41 @@
+=====================================================================
+               Side effects in Nim
+=====================================================================
+
+Note: Side effects are implicit produced values! Maybe they should be
+explicit like in Haskell?
+
+
+The idea is that side effects and partial evaluation belong together:
+Iff a proc is side effect free and all its argument are evaluable at
+compile time, it can be evaluated by the compiler. However, really
+difficult is the ``newString`` proc: If it is simply wrapped, it
+should not be evaluated at compile time! On other occasions it can
+and should be evaluted:
+
+.. code-block:: nim
+  proc toUpper(s: string): string =
+    result = newString(len(s))
+    for i in 0..len(s) - 1:
+      result[i] = toUpper(s[i])
+
+No, it really can always be evaluated. The code generator should transform
+``s = "\0\0\0..."`` back into ``s = newString(...)``.
+
+
+``new`` cannot be evaluated at compile time either.
+
+
+Raise statement
+===============
+
+It is impractical to consider ``raise`` as a statement with side effects.
+
+
+Solution
+========
+
+Being side effect free does not suffice for compile time evaluation. However,
+the evaluator can attempt to evaluate at compile time.
+
+
diff --git a/doc/endb.txt b/doc/endb.txt
new file mode 100644
index 000000000..049f9d40d
--- /dev/null
+++ b/doc/endb.txt
@@ -0,0 +1,203 @@
+==============================================

+  Embedded Nim Debugger (ENDB) User Guide

+==============================================

+

+:Author: Andreas Rumpf

+:Version: |nimversion|

+

+.. contents::

+

+**WARNING**: ENDB is not maintained anymore! Please help if you're interested
+in this tool.
+

+Nim comes with a platform independent debugger -

+the Embedded Nim Debugger (ENDB). The debugger is

+*embedded* into your executable if it has been

+compiled with the ``--debugger:on`` command line option.

+This also defines the conditional symbol ``ENDB`` for you.

+

+Note: You must not compile your program with the ``--app:gui``

+command line option because then there would be no console

+available for the debugger.

+

+If you start your program the debugger will immediately show

+a prompt on the console. You can now enter a command. The next sections

+deal with the possible commands. As usual in Nim in all commands

+underscores and case do not matter. Optional components of a command

+are listed in brackets ``[...]`` here.

+

+

+General Commands

+================

+

+``h``, ``help``

+    Display a quick reference of the possible commands.

+

+``q``, ``quit``

+    Quit the debugger and the program.

+

+<ENTER>

+    (Without any typed command) repeat the previous debugger command.

+    If there is no previous command, ``step_into`` is assumed.

+

+Executing Commands

+==================

+

+``s``, ``step_into``

+    Single step, stepping into routine calls.

+

+``n``, ``step_over``

+    Single step, without stepping into routine calls.

+

+``f``, ``skip_current``

+    Continue execution until the current routine finishes.

+

+``c``, ``continue``

+    Continue execution until the next breakpoint.

+

+``i``, ``ignore``

+    Continue execution, ignore all breakpoints. This effectively quits

+    the debugger and runs the program until it finishes.

+

+

+Breakpoint Commands

+===================

+

+``b``, ``setbreak`` [fromline [toline]] [file]

+    Set a new breakpoint for the given file

+    and line numbers. If no file is given, the current execution point's

+    filename is used. If the filename has no extension, ``.nim`` is

+    appended for your convenience.

+    If no line numbers are given, the current execution point's

+    line is used. If both ``fromline`` and ``toline`` are given the

+    breakpoint contains a line number range. Some examples if it is still

+    unclear:

+

+    * ``b 12 15 thallo`` creates a breakpoint that

+      will be triggered if the instruction pointer reaches one of the

+      lines 12-15 in the file ``thallo.nim``.

+    * ``b 12 thallo`` creates a breakpoint that

+      will be triggered if the instruction pointer reaches the

+      line 12 in the file ``thallo.nim``.

+    * ``b 12`` creates a breakpoint that

+      will be triggered if the instruction pointer reaches the

+      line 12 in the current file.

+    * ``b`` creates a breakpoint that

+      will be triggered if the instruction pointer reaches the

+      current line in the current file again.

+

+``breakpoints``

+    Display the entire breakpoint list.

+

+``disable`` <identifier>

+    Disable a breakpoint. It remains disabled until you turn it on again

+    with the ``enable`` command.

+

+``enable`` <identifier>

+    Enable a breakpoint.

+

+Often it happens when debugging that you keep retyping the breakpoints again

+and again because they are lost when you restart your program. This is not

+necessary: A special pragma has been defined for this:

+

+

+The ``breakpoint`` pragma

+-------------------------

+

+The ``breakpoint`` pragma is syntactically a statement. It can be used

+to mark the *following line* as a breakpoint:

+

+.. code-block:: Nim

+  write("1")

+  {.breakpoint: "before_write_2".}

+  write("2")

+

+The name of the breakpoint here is ``before_write_2``. Of course the

+breakpoint's name is optional - the compiler will generate one for you

+if you leave it out.

+

+Code for the ``breakpoint`` pragma is only generated if the debugger

+is turned on, so you don't need to remove it from your source code after

+debugging.

+

+

+The ``watchpoint`` pragma

+-------------------------

+

+The ``watchpoint`` pragma is syntactically a statement. It can be used

+to mark a location as a watchpoint:

+

+.. code-block:: Nim

+  var a: array [0..20, int]

+  

+  {.watchpoint: a[3].}

+  for i in 0 .. 20: a[i] = i

+

+ENDB then writes a stack trace whenever the content of the location ``a[3]``

+changes. The current implementation only tracks a hash value of the location's

+contents and so locations that are not word sized may encounter false

+negatives in very rare cases.

+

+Code for the ``watchpoint`` pragma is only generated if the debugger

+is turned on, so you don't need to remove it from your source code after

+debugging.

+

+Due to the primitive implementation watchpoints are even slower than

+breakpoints: After *every* executed Nim code line it is checked whether the

+location changed.

+

+

+Data Display Commands

+=====================

+

+``e``, ``eval`` <exp>

+    Evaluate the expression <exp>. Note that ENDB has no full-blown expression

+    evaluator built-in. So expressions are limited:

+

+    * To display global variables prefix their names with their

+      owning module: ``nim1.globalVar``

+    * To display local variables or parameters just type in

+      their name: ``localVar``. If you want to inspect variables that are not

+      in the current stack frame, use the ``up`` or ``down`` command.

+

+    Unfortunately, only inspecting variables is possible at the moment. Maybe

+    a future version will implement a full-blown Nim expression evaluator,

+    but this is not easy to do and would bloat the debugger's code.

+

+    Since displaying the whole data structures is often not needed and

+    painfully slow, the debugger uses a *maximal display depth* concept for

+    displaying.

+

+    You can alter the maximal display depth with the ``maxdisplay``

+    command.

+

+``maxdisplay`` <natural>

+    Sets the maximal display depth to the given integer value. A value of 0

+    means there is no maximal display depth. Default is 3.

+

+``o``, ``out`` <filename> <exp>

+    Evaluate the expression <exp> and store its string representation into a

+    file named <filename>. If the file does not exist, it will be created,

+    otherwise it will be opened for appending.

+

+``w``, ``where``

+    Display the current execution point.

+

+``u``, ``up``

+    Go up in the call stack.

+

+``d``, ``down``

+    Go down in the call stack.

+

+``stackframe`` [file]

+    Displays the content of the current stack frame in ``stdout`` or

+    appends it to the file, depending on whether a file is given.

+

+``callstack``

+    Display the entire call stack (but not its content).

+

+``l``, ``locals``

+    Display the available local variables in the current stack frame.

+

+``g``, ``globals``

+    Display all the global variables that are available for inspection.

diff --git a/doc/estp.txt b/doc/estp.txt
new file mode 100644
index 000000000..500ee52a5
--- /dev/null
+++ b/doc/estp.txt
@@ -0,0 +1,195 @@
+===================================================

+  Embedded Stack Trace Profiler (ESTP) User Guide

+===================================================

+

+:Author: Andreas Rumpf

+:Version: |nimversion|

+

+

+Nim comes with a platform independent profiler -

+the Embedded Stack Trace Profiler (ESTP). The profiler 
+is *embedded* into your executable. To activate the profiler you need to do: 
+
+* compile your program with the ``--profiler:on --stackTrace:on`` command 
+  line options
+* import the ``nimprof`` module
+* run your program as usual.
+
+You can in fact look at ``nimprof``'s source code to see how to implement 
+your own profiler.
+

+The setting ``--profiler:on`` defines the conditional symbol ``profiler``.

+

+After your program has finished the profiler will create a 
+file ``profile_results.txt`` containing the profiling results.
+
+Since the profiler works by examining stack traces, it's essential that
+the option ``--stackTrace:on`` is active! Unfortunately this means that a 
+profiling build is much slower than a release build.
+
+
+Memory profiler
+===============
+
+You can also use ESTP as a memory profiler to see which stack traces allocate
+the most memory and thus create the most GC pressure. It may also help to 
+find memory leaks. To activate the memory profiler you need to do:
+
+* compile your program with the ``--profiler:off --stackTrace:on -d:memProfiler``
+  command line options. Yes it's ``--profiler:off``.
+* import the ``nimprof`` module
+* run your program as usual.
+
+Define the symbol ``ignoreAllocationSize`` so that only the number of 
+allocations is counted and the sizes of the memory allocations do not matter.
+
+
+Example results file
+====================
+
+The results file lists stack traces ordered by significance. 
+
+The following example file has been generated by profiling the Nim compiler
+itself: It shows that in total 5.4% of the runtime has been spent 
+in ``crcFromRope`` or its children.
+
+In general the stack traces show you immediately where the problem is because
+the trace acts like an explanation; in traditional profilers you can only find
+expensive leaf functions easily but the *reason* why they are invoked 
+often remains mysterious.
+
+::
+  total executions of each stack trace:
+  Entry: 0/3391 Calls: 84/4160 = 2.0% [sum: 84; 84/4160 = 2.0%]
+    newCrcFromRopeAux
+    crcFromRope
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    nim
+  Entry: 1/3391 Calls: 46/4160 = 1.1% [sum: 130; 130/4160 = 3.1%]
+    updateCrc32
+    newCrcFromRopeAux
+    crcFromRope
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    nim
+  Entry: 2/3391 Calls: 41/4160 = 0.99% [sum: 171; 171/4160 = 4.1%]
+    updateCrc32
+    updateCrc32
+    newCrcFromRopeAux
+    crcFromRope
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    nim
+  Entry: 3/3391 Calls: 41/4160 = 0.99% [sum: 212; 212/4160 = 5.1%]
+    crcFromFile
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    nim
+  Entry: 4/3391 Calls: 41/4160 = 0.99% [sum: 253; 253/4160 = 6.1%]
+    updateCrc32
+    crcFromFile
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    nim
+  Entry: 5/3391 Calls: 32/4160 = 0.77% [sum: 285; 285/4160 = 6.9%]
+    pop
+    newCrcFromRopeAux
+    crcFromRope
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    nim
+  Entry: 6/3391 Calls: 17/4160 = 0.41% [sum: 302; 302/4160 = 7.3%]
+    doOperation
+    forAllChildrenAux
+    pop
+    newCrcFromRopeAux
+    crcFromRope
+    writeRopeIfNotEqual
+    shouldRecompile
+    writeModule
+    myClose
+    closePasses
+    processModule
+    CompileModule
+    CompileProject
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
+    ...
+    nim
+  Entry: 7/3391 Calls: 14/4160 = 0.34% [sum: 316; 316/4160 = 7.6%]
+    Contains
+    isAccessible
+    interiorAllocatedPtr
+    gcMark
+    markStackAndRegisters
+    collectCTBody
+    collectCT
+    rawNewObj
+    newObj
+    newNode
+    copyTree
+    matchesAux
+    matches
+    resolveOverloads
+    semOverloadedCall
+    semOverloadedCallAnalyseEffects
+    ...
+    CommandCompileToC
+    MainCommand
+    HandleCmdLine
diff --git a/doc/exception_hierarchy_fragment.txt b/doc/exception_hierarchy_fragment.txt
new file mode 100644
index 000000000..f4a419fc4
--- /dev/null
+++ b/doc/exception_hierarchy_fragment.txt
@@ -0,0 +1,28 @@
+* `Exception <system.html#Exception>`_
+  * `AccessViolationError <system.html#AccessViolationError>`_
+  * `ArithmeticError <system.html#ArithmeticError>`_
+    * `DivByZeroError <system.html#DivByZeroError>`_
+    * `OverflowError <system.html#OverflowError>`_
+  * `AssertionError <system.html#AssertionError>`_
+  * `DeadThreadError <system.html#DeadThreadError>`_
+  * `FloatingPointError <system.html#FloatingPointError>`_
+    * `FloatDivByZeroError <system.html#FloatDivByZeroError>`_
+    * `FloatInexactError <system.html#FloatInexactError>`_
+    * `FloatInvalidOpError <system.html#FloatInvalidOpError>`_
+    * `FloatOverflowError <system.html#FloatOverflowError>`_
+    * `FloatUnderflowError <system.html#FloatUnderflowError>`_
+  * `FieldError <system.html#InvalidFieldError>`_
+  * `IndexError <system.html#InvalidIndexError>`_
+  * `ObjectAssignmentError <system.html#ObjectAssignmentError>`_
+  * `ObjectConversionError <system.html#ObjectConversionError>`_
+  * `ValueError <system.html#ValueError>`_
+    * `KeyError <system.html#KeyError>`_
+  * `ReraiseError <system.html#ReraiseError>`_
+  * `RangeError <system.html#RangeError>`_
+  * `OutOfMemoryError <system.html#OutOfMemoryError>`_
+  * `ResourceExhaustedError <system.html#ResourceExhaustedError>`_
+  * `StackOverflowError <system.html#StackOverflowError>`_
+  * `SystemError <system.html#SystemError>`_
+    * `IOError <system.html#IOError>`_
+    * `OSError <system.html#OSError>`_
+      * `LibraryError <system.html#LibraryError>`_
diff --git a/doc/filelist.txt b/doc/filelist.txt
new file mode 100644
index 000000000..beff8f6c8
--- /dev/null
+++ b/doc/filelist.txt
@@ -0,0 +1,54 @@
+Short description of Nim's modules
+-------------------------------------
+
+==============  ==========================================================
+Module          Description
+==============  ==========================================================
+nim          main module: parses the command line and calls
+                ``main.MainCommand``
+main            implements the top-level command dispatching
+nimconf         implements the config file reader
+syntaxes        dispatcher for the different parsers and filters
+filter_tmpl     standard template filter (``#! stdtempl``)
+lexbase         buffer handling of the lexical analyser
+lexer           lexical analyser
+parser          Nim's parser
+renderer        Nim code renderer (AST back to its textual form)
+options         contains global and local compiler options
+ast             type definitions of the abstract syntax tree (AST) and
+                node constructors
+astalgo         algorithms for containers of AST nodes; converting the
+                AST to YAML; the symbol table
+passes          implement the passes manager for passes over the AST
+trees           some algorithms for nodes; this module is less important
+types           module for traversing type graphs; also contain several
+                helpers for dealing with types
+
+sigmatch        contains the matching algorithm that is used for proc
+                calls
+semexprs        contains the semantic checking phase for expressions
+semstmts        contains the semantic checking phase for statements
+semtypes        contains the semantic checking phase for types
+seminst         instantiation of generic procs and types
+semfold         contains code to deal with constant folding
+semthreads      deep program analysis for threads
+evals           contains an AST interpreter for compile time evaluation
+pragmas         semantic checking of pragmas
+
+idents          implements a general mapping from identifiers to an internal
+                representation (``PIdent``) that is used so that a simple
+                id-comparison suffices to say whether two Nim identifiers
+                are equivalent
+ropes           implements long strings represented as trees for
+                lazy evaluation; used mainly by the code generators
+
+transf          transformations on the AST that need to be done before
+                code generation
+cgen            main file of the C code generator
+ccgutils        contains helpers for the C code generator
+ccgtypes        the generator for C types
+ccgstmts        the generator for statements
+ccgexprs        the generator for expressions
+extccomp        this module calls the C compiler and linker; interesting
+                if you want to add support for a new C compiler
+==============  ==========================================================
diff --git a/doc/filters.txt b/doc/filters.txt
new file mode 100644
index 000000000..e725321e6
--- /dev/null
+++ b/doc/filters.txt
@@ -0,0 +1,196 @@
+===================
+Source Code Filters
+===================
+
+.. contents::
+
+A `Source Code Filter` transforms the input character stream to an in-memory 
+output stream before parsing. A filter can be used to provide templating 
+systems or preprocessors.
+
+To use a filter for a source file the *shebang* notation is used::
+
+  #! stdtmpl(subsChar = '$', metaChar = '#')
+  #proc generateXML(name, age: string): string =
+  #  result = ""
+  <xml>
+    <name>$name</name>
+    <age>$age</age>
+  </xml>
+
+As the example shows, passing arguments to a filter can be done
+just like an ordinary procedure call with named or positional arguments. The
+available parameters depend on the invoked filter.
+
+
+Pipe operator
+=============
+
+Filters can be combined with the ``|`` pipe operator::
+
+  #! strip(startswith="<") | stdtmpl
+  #proc generateXML(name, age: string): string =
+  #  result = ""
+  <xml>
+    <name>$name</name>
+    <age>$age</age>
+  </xml>
+
+
+Available filters
+=================
+
+**Hint:** With ``--verbosity:2`` (or higher) Nim lists the processed code
+after each filter application.
+
+Replace filter
+--------------
+
+The replace filter replaces substrings in each line.
+
+Parameters and their defaults:
+
+  ``sub: string = ""``
+    the substring that is searched for
+  
+  ``by: string = ""``
+    the string the substring is replaced with
+
+
+Strip filter
+------------
+
+The strip filter simply removes leading and trailing whitespace from
+each line.
+
+Parameters and their defaults:
+
+  ``startswith: string = ""``
+    strip only the lines that start with *startswith* (ignoring leading
+    whitespace). If empty every line is stripped.
+
+  ``leading: bool = true``
+    strip leading whitespace
+  
+  ``trailing: bool = true``
+    strip trailing whitespace
+
+
+StdTmpl filter
+--------------
+
+The stdtmpl filter provides a simple templating engine for Nim. The
+filter uses a line based parser: Lines prefixed with a *meta character*
+(default: ``#``) contain Nim code, other lines are verbatim. Because
+indentation-based parsing is not suited for a templating engine, control flow
+statements need ``end X`` delimiters.
+
+Parameters and their defaults:
+
+  ``metaChar: char = '#'``
+    prefix for a line that contains Nim code
+  
+  ``subsChar: char = '$'``
+    prefix for a Nim expression within a template line
+    
+  ``conc: string = " & "``
+    the operation for concatenation
+    
+  ``emit: string = "result.add"``
+    the operation to emit a string literal
+    
+  ``toString: string = "$"``
+    the operation that is applied to each expression
+
+Example::
+
+  #! stdtmpl | standard
+  #proc generateHTMLPage(title, currentTab, content: string,
+  #                      tabs: openArray[string]): string = 
+  #  result = ""
+  <head><title>$title</title></head>
+  <body>
+    <div id="menu">
+      <ul>
+    #for tab in items(tabs):
+      #if currentTab == tab:
+      <li><a id="selected" 
+      #else:
+      <li><a
+      #end if
+      href="${tab}.html">$tab</a></li>
+    #end for
+      </ul>
+    </div>
+    <div id="content">
+      $content
+      A dollar: $$.
+    </div>
+  </body>
+
+The filter transforms this into:
+
+.. code-block:: nim
+  proc generateHTMLPage(title, currentTab, content: string,
+                        tabs: openArray[string]): string = 
+    result = ""
+    result.add("<head><title>" & $(title) & "</title></head>\n" & 
+      "<body>\n" & 
+      "  <div id=\"menu\">\n" & 
+      "    <ul>\n")
+    for tab in items(tabs):
+      if currentTab == tab:
+        result.add("    <li><a id=\"selected\" \n")
+      else:
+        result.add("    <li><a\n")
+      #end
+      result.add("    href=\"" & $(tab) & ".html\">" & $(tab) & "</a></li>\n")
+    #end
+    result.add("    </ul>\n" & 
+      "  </div>\n" & 
+      "  <div id=\"content\">\n" & 
+      "    " & $(content) & "\n" & 
+      "    A dollar: $.\n" & 
+      "  </div>\n" & 
+      "</body>\n")
+
+  
+Each line that does not start with the meta character (ignoring leading
+whitespace) is converted to a string literal that is added to ``result``. 
+
+The substitution character introduces a Nim expression *e* within the
+string literal. *e* is converted to a string with the *toString* operation
+which defaults to ``$``. For strong type checking, set ``toString`` to the
+empty string. *e* must match this PEG pattern::
+
+  e <- [a-zA-Z\128-\255][a-zA-Z0-9\128-\255_.]* / '{' x '}'
+  x <- '{' x+ '}' / [^}]*
+
+To produce a single substitution character it has to be doubled: ``$$``
+produces ``$``.
+
+The template engine is quite flexible. It is easy to produce a procedure that
+writes the template code directly to a file::
+
+  #! stdtmpl(emit="f.write") | standard
+  #proc writeHTMLPage(f: File, title, currentTab, content: string,
+  #                   tabs: openArray[string]) = 
+  <head><title>$title</title></head>
+  <body>
+    <div id="menu">
+      <ul>
+    #for tab in items(tabs):
+      #if currentTab == tab:
+      <li><a id="selected" 
+      #else:
+      <li><a
+      #end if
+      href="${tab}.html" title = "$title - $tab">$tab</a></li>
+    #end for
+      </ul>
+    </div>
+    <div id="content">
+      $content
+      A dollar: $$.
+    </div>
+  </body>
diff --git a/doc/gc.txt b/doc/gc.txt
new file mode 100644
index 000000000..f51421bcd
--- /dev/null
+++ b/doc/gc.txt
@@ -0,0 +1,131 @@
+==========================
+Nim's Garbage Collector
+==========================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+..
+
+
+  "The road to hell is paved with good intentions."
+
+
+Introduction
+============
+
+This document describes how the GC works and how to tune it for
+(soft) `realtime systems`:idx:.
+
+The basic algorithm is *Deferred Reference Counting* with cycle detection.
+References on the stack are not counted for better performance (and easier C
+code generation). The GC **never** scans the whole heap but it may scan the
+delta-subgraph of the heap that changed since its last run.
+
+
+The GC is only triggered in a memory allocation operation. It is not triggered
+by some timer and does not run in a background thread.
+
+To force a full collection call ``GC_fullCollect``. Note that it is generally
+better to let the GC do its work and not enforce a full collection.
+
+
+Cycle collector
+===============
+
+The cycle collector can be en-/disabled independently from the other parts of
+the GC with ``GC_enableMarkAndSweep`` and ``GC_disableMarkAndSweep``. The
+compiler analyses the types for their possibility to build cycles, but often
+it is necessary to help this analysis with the ``acyclic`` pragma (see
+`acyclic <manual.html#acyclic-pragma>`_ for further information). 
+
+You can also use the ``acyclic`` pragma for data that is cyclic in reality and 
+then break up the cycles explicitly with ``GC_addCycleRoot``. This can be a
+very valuable optimization; the Nim compiler itself relies on this 
+optimization trick to improve performance. Note that ``GC_addCycleRoot`` is
+a quick operation; the root is only registered for the next run of the 
+cycle collector.
+
+
+Realtime support
+================
+
+To enable realtime support, the symbol `useRealtimeGC`:idx: needs to be
+defined via ``--define:useRealtimeGC`` (you can put this into your config 
+file as well). With this switch the GC supports the following operations:
+
+.. code-block:: nim
+  proc GC_setMaxPause*(MaxPauseInUs: int)
+  proc GC_step*(us: int, strongAdvice = false)
+
+The unit of the parameters ``MaxPauseInUs`` and ``us`` is microseconds.
+
+These two procs are the two modus operandi of the realtime GC: 
+
+(1) GC_SetMaxPause Mode
+
+    You can call ``GC_SetMaxPause`` at program startup and then each triggered
+    GC run tries to not take longer than ``MaxPause`` time. However, it is 
+    possible (and common) that the work is nevertheless not evenly distributed 
+    as each call to ``new`` can trigger the GC and thus take  ``MaxPause`` 
+    time.
+
+(2) GC_step Mode
+
+    This allows the GC to perform some work for up to ``us`` time. This is
+    useful to call in a main loop to ensure the GC can do its work. To    
+    bind all GC activity to a ``GC_step`` call, deactivate the GC with 
+    ``GC_disable`` at program startup.
+
+These procs provide a "best effort" realtime guarantee; in particular the
+cycle collector is not aware of deadlines yet. Deactivate it to get more
+predictable realtime behaviour. Tests show that a 2ms max pause
+time will be met in almost all cases on modern CPUs unless the cycle collector
+is triggered.
+
+
+Time measurement
+----------------
+
+The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the 
+implementation):
+
+1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows.
+2) ``mach_absolute_time`` on Mac OS X.
+3) ``gettimeofday`` on Posix systems.
+
+As such it supports a resolution of nanoseconds internally; however the API
+uses microseconds for convenience. 
+
+
+Define the symbol ``reportMissedDeadlines`` to make the GC output whenever it
+missed a deadline. The reporting will be enhanced and supported by the API in
+later versions of the collector.
+
+
+Tweaking the GC
+---------------
+
+The collector checks whether there is still time left for its work after 
+every ``workPackage``'th iteration. This is currently set to 100 which means
+that up to 100 objects are traversed and freed before it checks again. Thus
+``workPackage`` affects the timing granularity and may need to be tweaked in
+highly specialized environments or for older hardware.
+
+
+Keeping track of memory
+-----------------------
+
+If you need to pass around memory allocated by Nim to C, you can use the
+procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them
+being freed by the GC. Other useful procs from `system <system.html>`_ you can
+use to keep track of memory are:
+
+* getTotalMem(): returns the amount of total memory managed by the GC.
+* getOccupiedMem(): bytes reserved by the GC and used by objects.
+* getFreeMem(): bytes reserved by the GC and not in use.
+
+In addition to ``GC_ref`` and ``GC_unref`` you can avoid the GC by manually
+allocating memory with procs like ``alloc``, ``allocShared``, or
+``allocCStringArray``. The GC won't try to free them, you need to call their
+respective *dealloc* pairs when you are done with them or they will leak.
diff --git a/doc/grammar.txt b/doc/grammar.txt
new file mode 100644
index 000000000..72dc6c974
--- /dev/null
+++ b/doc/grammar.txt
@@ -0,0 +1,196 @@
+module = stmt ^* (';' / IND{=})
+comma = ',' COMMENT?
+semicolon = ';' COMMENT?
+colon = ':' COMMENT?
+colcom = ':' COMMENT?
+operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
+         | 'or' | 'xor' | 'and'
+         | 'is' | 'isnot' | 'in' | 'notin' | 'of'
+         | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
+prefixOperator = operator
+optInd = COMMENT?
+optPar = (IND{>} | IND{=})?
+simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
+arrowExpr = assignExpr (OP1 optInd assignExpr)*
+assignExpr = orExpr (OP2 optInd orExpr)*
+orExpr = andExpr (OP3 optInd andExpr)*
+andExpr = cmpExpr (OP4 optInd cmpExpr)*
+cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
+sliceExpr = ampExpr (OP6 optInd ampExpr)*
+ampExpr = plusExpr (OP7 optInd plusExpr)*
+plusExpr = mulExpr (OP8 optInd mulExpr)*
+mulExpr = dollarExpr (OP9 optInd dollarExpr)*
+dollarExpr = primary (OP10 optInd primary)*
+symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`'
+       | IDENT | 'addr' | 'type'
+indexExpr = expr
+indexExprList = indexExpr ^+ comma
+exprColonEqExpr = expr (':'|'=' expr)?
+exprList = expr ^+ comma
+dotExpr = expr '.' optInd symbol
+qualifiedIdent = symbol ('.' optInd symbol)?
+exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)?
+setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}'
+castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')'
+parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try'
+        | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let'
+        | 'when' | 'var' | 'mixin'
+par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';'
+                 | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )?
+                            | (':' expr)? (',' (exprColonEqExpr comma?)*)?  )?
+        optPar ')'
+literal = | INT_LIT | INT8_LIT | INT16_LIT | INT32_LIT | INT64_LIT
+          | UINT_LIT | UINT8_LIT | UINT16_LIT | UINT32_LIT | UINT64_LIT
+          | FLOAT_LIT | FLOAT32_LIT | FLOAT64_LIT
+          | STR_LIT | RSTR_LIT | TRIPLESTR_LIT
+          | CHAR_LIT
+          | NIL
+generalizedLit = GENERALIZED_STR_LIT | GENERALIZED_TRIPLESTR_LIT
+identOrLiteral = generalizedLit | symbol | literal
+               | par | arrayConstr | setOrTableConstr
+               | castExpr
+tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
+arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
+primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks?
+      | doBlocks
+      | '.' optInd symbol generalizedLit?
+      | '[' optInd indexExprList optPar ']'
+      | '{' optInd indexExprList optPar '}'
+      | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax
+condExpr = expr colcom expr optInd
+        ('elif' expr colcom expr optInd)*
+         'else' colcom expr
+ifExpr = 'if' condExpr
+whenExpr = 'when' condExpr
+pragma = '{.' optInd (exprColonExpr comma?)* optPar ('.}' | '}')
+identVis = symbol opr?  # postfix position
+identWithPragma = identVis pragma?
+declColonEquals = identWithPragma (comma identWithPragma)* comma?
+                  (':' optInd typeDesc)? ('=' optInd expr)?
+identColonEquals = ident (comma ident)* comma?
+     (':' optInd typeDesc)? ('=' optInd expr)?)
+inlTupleDecl = 'tuple'
+    [' optInd  (identColonEquals (comma/semicolon)?)*  optPar ']'
+extTupleDecl = 'tuple'
+    COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)?
+tupleClass = 'tuple'
+paramList = '(' declColonEquals ^* (comma/semicolon) ')'
+paramListArrow = paramList? ('->' optInd typeDesc)?
+paramListColon = paramList? (':' optInd typeDesc)?
+doBlock = 'do' paramListArrow pragmas? colcom stmt
+doBlocks = doBlock ^* IND{=}
+procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
+distinct = 'distinct' optInd typeDesc
+expr = (ifExpr
+      | whenExpr
+      | caseExpr
+      | tryExpr)
+      / simpleExpr
+typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'tuple'
+         | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
+primary = typeKeyw typeDescK
+        /  prefixOperator* identOrLiteral primarySuffix*
+        / 'static' primary
+        / 'bind' primary
+typeDesc = simpleExpr
+typeDefAux = simpleExpr
+           | 'concept' typeClass
+macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt
+                       | IND{=} 'elif' expr ':' stmt
+                       | IND{=} 'except' exprList ':' stmt
+                       | IND{=} 'else' ':' stmt )*
+exprStmt = simpleExpr
+         (( '=' optInd expr )
+         / ( expr ^+ comma
+             doBlocks
+              / macroColon
+           ))?
+importStmt = 'import' optInd expr
+              ((comma expr)*
+              / 'except' optInd (expr ^+ comma))
+includeStmt = 'include' optInd expr ^+ comma
+fromStmt = 'from' moduleName 'import' optInd expr (comma expr)*
+returnStmt = 'return' optInd expr?
+raiseStmt = 'raise' optInd expr?
+yieldStmt = 'yield' optInd expr?
+discardStmt = 'discard' optInd expr?
+breakStmt = 'break' optInd expr?
+continueStmt = 'break' optInd expr?
+condStmt = expr colcom stmt COMMENT?
+           (IND{=} 'elif' expr colcom stmt)*
+           (IND{=} 'else' colcom stmt)?
+ifStmt = 'if' condStmt
+whenStmt = 'when' condStmt
+whileStmt = 'while' expr colcom stmt
+ofBranch = 'of' exprList colcom stmt
+ofBranches = ofBranch (IND{=} ofBranch)*
+                      (IND{=} 'elif' expr colcom stmt)*
+                      (IND{=} 'else' colcom stmt)?
+caseStmt = 'case' expr ':'? COMMENT?
+            (IND{>} ofBranches DED
+            | IND{=} ofBranches)
+tryStmt = 'try' colcom stmt &(IND{=}? 'except'|'finally')
+           (IND{=}? 'except' exprList colcom stmt)*
+           (IND{=}? 'finally' colcom stmt)?
+tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
+           (optInd 'except' exprList colcom stmt)*
+           (optInd 'finally' colcom stmt)?
+exceptBlock = 'except' colcom stmt
+forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
+blockStmt = 'block' symbol? colcom stmt
+staticStmt = 'static' colcom stmt
+deferStmt = 'defer' colcom stmt
+asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
+genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
+genericParamList = '[' optInd
+  genericParam ^* (comma/semicolon) optPar ']'
+pattern = '{' stmt '}'
+indAndComment = (IND{>} COMMENT)? | COMMENT?
+routine = optInd identVis pattern? genericParamList?
+  paramListColon pragma? ('=' COMMENT? stmt)? indAndComment
+commentStmt = COMMENT
+section(p) = COMMENT? p / (IND{>} (p / COMMENT)^+IND{=} DED)
+constant = identWithPragma (colon typedesc)? '=' optInd expr indAndComment
+enum = 'enum' optInd (symbol optInd ('=' optInd expr COMMENT?)? comma?)+
+objectWhen = 'when' expr colcom objectPart COMMENT?
+            ('elif' expr colcom objectPart COMMENT?)*
+            ('else' colcom objectPart COMMENT?)?
+objectBranch = 'of' exprList colcom objectPart
+objectBranches = objectBranch (IND{=} objectBranch)*
+                      (IND{=} 'elif' expr colcom objectPart)*
+                      (IND{=} 'else' colcom objectPart)?
+objectCase = 'case' identWithPragma ':' typeDesc ':'? COMMENT?
+            (IND{>} objectBranches DED
+            | IND{=} objectBranches)
+objectPart = IND{>} objectPart^+IND{=} DED
+           / objectWhen / objectCase / 'nil' / 'discard' / declColonEquals
+object = 'object' pragma? ('of' typeDesc)? COMMENT? objectPart
+typeClassParam = ('var')? symbol
+typeClass = typeClassParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
+              &IND{>} stmt
+typeDef = identWithPragma genericParamList? '=' optInd typeDefAux
+            indAndComment?
+varTuple = '(' optInd identWithPragma ^+ comma optPar ')' '=' optInd expr
+variable = (varTuple / identColonEquals) indAndComment
+bindStmt = 'bind' optInd qualifiedIdent ^+ comma
+mixinStmt = 'mixin' optInd qualifiedIdent ^+ comma
+pragmaStmt = pragma (':' COMMENT? stmt)?
+simpleStmt = ((returnStmt | raiseStmt | yieldStmt | discardStmt | breakStmt
+           | continueStmt | pragmaStmt | importStmt | exportStmt | fromStmt
+           | includeStmt | commentStmt) / exprStmt) COMMENT?
+complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
+                    | tryStmt | forStmt
+                    | blockStmt | staticStmt | deferStmt | asmStmt
+                    | 'proc' routine
+                    | 'method' routine
+                    | 'iterator' routine
+                    | 'macro' routine
+                    | 'template' routine
+                    | 'converter' routine
+                    | 'type' section(typeDef)
+                    | 'const' section(constant)
+                    | ('let' | 'var') section(variable)
+                    | bindStmt | mixinStmt)
+                    / simpleStmt
+stmt = (IND{>} complexOrSimpleStmt^+(IND{=} / ';') DED)
+     / simpleStmt ^+ ';'
diff --git a/doc/idetools.txt b/doc/idetools.txt
new file mode 100644
index 000000000..2ffe46d4b
--- /dev/null
+++ b/doc/idetools.txt
@@ -0,0 +1,588 @@
+================================
+  Nim IDE Integration Guide
+================================
+
+:Author: Britney Spears
+:Version: |nimversion|
+
+.. contents::
+
+
+.. raw:: html
+  <blockquote><p>
+  "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
+  </p></blockquote>
+
+Nim differs from many other compilers in that it is really fast,
+and being so fast makes it suited to provide external queries for
+text editors about the source code being written. Through the
+``idetools`` command of `the compiler <nimc.html>`_, any IDE
+can query a ``.nim`` source file and obtain useful information like
+definition of symbols or suggestions for completion.
+
+This document will guide you through the available options. If you
+want to look at practical examples of idetools support you can look
+at the test files found in the `Test suite`_ or `various editor
+integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
+already available.
+
+
+Idetools invocation
+===================
+
+Specifying the location of the query
+------------------------------------
+
+All of the available idetools commands require you to specify a
+query location through the ``--track`` or ``--trackDirty`` switches.
+The general idetools invocations are::
+
+    nim idetools --track:FILE,LINE,COL <switches> proj.nim
+
+Or::
+
+    nim idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL <switches> proj.nim
+
+``proj.nim``
+    This is the main *project* filename. Most of the time you will
+    pass in the same as **FILE**, but for bigger projects this is
+    the file which is used as main entry point for the program, the
+    one which users compile to generate a final binary.
+
+``<switches>``
+    This would be any of the other idetools available options, like
+    ``--def`` or ``--suggest`` explained in the following sections.
+
+``COL``
+    An integer with the column you are going to query. For the
+    compiler columns start at zero, so the first column will be
+    **0** and the last in an 80 column terminal will be **79**.
+
+``LINE``
+    An integer with the line you are going to query. For the compiler
+    lines start at **1**.
+
+``FILE``
+    The file you want to perform the query on. Usually you will
+    pass in the same value as **proj.nim**.
+
+``DIRTY_FILE``
+    The **FILE** paramater is enough for static analysis, but IDEs
+    tend to have *unsaved buffers* where the user may still be in
+    the middle of typing a line. In such situations the IDE can
+    save the current contents to a temporary file and then use the
+    ``--trackDirty`` switch.
+
+    Dirty files are likely to contain errors and they are usually
+    compiled partially only to the point needed to service the
+    idetool request. The compiler discriminates them to ensure that
+    **a)** they won't be cached and **b)** they won't invalidate
+    the cached contents of the original module.
+
+    The other reason is that the dirty file can appear anywhere on
+    disk (e.g. in tmpfs), but it must be treated as having a path
+    matching the original module when it comes to usage of relative
+    paths, etc. Queries, however, will refer to the dirty module
+    name in their answers instead of the normal filename.
+
+
+Definitions
+-----------
+
+The ``--def`` idetools switch performs a query about the definition
+of a specific symbol. If available, idetools will answer with the
+type, source file, line/column information and other accessory data
+if available like a docstring. With this information an IDE can
+provide the typical *Jump to definition* where a user puts the
+cursor on a symbol or uses the mouse to select it and is redirected
+to the place where the symbol is located.
+
+Since Nim is implemented in Nim, one of the nice things of
+this feature is that any user with an IDE supporting it can quickly
+jump around the standard library implementation and see exactly
+what a proc does, learning about the language and seeing real life
+examples of how to write/implement specific features.
+
+Idetools will always answer with a single definition or none if it
+can't find any valid symbol matching the position of the query.
+
+
+Suggestions
+-----------
+
+The ``--suggest`` idetools switch performs a query about possible
+completion symbols at some point in the file. IDEs can easily provide
+an autocompletion feature where the IDE scans the current file (and
+related ones, if it knows about the language being edited and follows
+includes/imports) and when the user starts typing something a
+completion box with different options appears.
+
+However such features are not context sensitive and work simply on
+string matching, which can be problematic in Nim especially due
+to the case insensitiveness of the language (plus underscores as
+separators!).
+
+The typical usage scenario for this option is to call it after the
+user has typed the dot character for `the object oriented call
+syntax <tut2.html#method-call-syntax>`_. Idetools will try to return
+the suggestions sorted first by scope (from innermost to outermost)
+and then by item name.
+
+
+Invocation context
+------------------
+
+The ``--context`` idetools switch is very similar to the suggestions
+switch, but instead of being used after the user has typed a dot
+character, this one is meant to be used after the user has typed
+an opening brace to start typing parameters.
+
+
+Symbol usages
+-------------
+
+The ``--usages`` idetools switch lists all usages of the symbol at
+a position. IDEs can use this to find all the places in the file
+where the symbol is used and offer the user to rename it in all
+places at the same time. Again, a pure string based search and
+replace may catch symbols out of the scope of a function/loop.
+
+For this kind of query the IDE will most likely ignore all the
+type/signature info provided by idetools and concentrate on the
+filename, line and column position of the multiple returned answers.
+
+
+Expression evaluation
+---------------------
+
+This feature is still under development. In the future it will allow
+an IDE to evaluate an expression in the context of the currently
+running/debugged user project.
+
+
+Compiler as a service (CAAS)
+============================
+
+The occasional use of idetools is acceptable for things like
+definitions, where the user puts the cursor on a symbol or double
+clicks it and after a second or two the IDE displays where that
+symbol is defined. Such latencies would be terrible for features
+like symbol suggestion, plus why wait at all if we can avoid it?
+
+The idetools command can be run as a compiler service (CAAS),
+where you first launch the compiler and it will stay online as a
+server, accepting queries in a telnet like fashion. The advantage
+of staying on is that for many queries the compiler can cache the
+results of the compilation, and subsequent queries should be fast
+in the millisecond range, thus being responsive enough for IDEs.
+
+If you want to start the server using stdin/stdout as communication
+you need to type::
+
+    nim serve --server.type:stdin proj.nim
+
+If you want to start the server using tcp and a port, you need to type::
+
+    nim serve --server.type:tcp --server.port:6000 \
+      --server.address:hostname proj.nim
+
+In both cases the server will start up and await further commands.
+The syntax of the commands you can now send to the server is
+practically the same as running the nim compiler on the commandline,
+you only need to remove the name of the compiler since you are
+already talking to it. The server will answer with as many lines
+of text it thinks necessary plus an empty line to indicate the end
+of the answer.
+
+You can find examples of client/server communication in the idetools
+tests found in the `Test suite`_.
+
+
+Parsing idetools output
+=======================
+
+Idetools outputs is always returned on single lines separated by
+tab characters (``\t``). The values of each column are:
+
+1. Three characters indicating the type of returned answer (e.g.
+   def for definition, ``sug`` for suggestion, etc).
+2. Type of the symbol. This can be ``skProc``, ``skLet``, and just
+   about any of the enums defined in the module ``compiler/ast.nim``.
+3. Full qualitifed path of the symbol. If you are querying a symbol
+   defined in the ``proj.nim`` file, this would have the form
+   ``proj.symbolName``.
+4. Type/signature. For variables and enums this will contain the
+   type of the symbol, for procs, methods and templates this will
+   contain the full unique signature (e.g. ``proc (File)``).
+5. Full path to the file containing the symbol.
+6. Line where the symbol is located in the file. Lines start to
+   count at **1**.
+7. Column where the symbol is located in the file. Columns start
+   to count at **0**.
+8. Docstring for the symbol if available or the empty string. To
+   differentiate the docstring from end of answer in server mode,
+   the docstring is always provided enclosed in double quotes, and
+   if the docstring spans multiple lines, all following lines of the
+   docstring will start with a blank space to align visually with
+   the starting quote.
+
+   Also, you won't find raw ``\n`` characters breaking the one
+   answer per line format. Instead you will need to parse sequences
+   in the form ``\xHH``, where *HH* is a hexadecimal value (e.g.
+   newlines generate the sequence ``\x0A``).
+
+The following sections define the expected output for each kind of
+symbol for which idetools returns valid output.
+
+
+skConst
+-------
+
+| **Third column**: module + [n scope nesting] + const name.
+| **Fourth column**: the type of the const value.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    const SOME_SEQUENCE = @[1, 2]
+    --> col 2: $MODULE.SOME_SEQUENCE
+        col 3: seq[int]
+        col 7: ""
+
+
+skEnumField
+-----------
+
+| **Third column**: module + [n scope nesting] + enum type + enum field name.
+| **Fourth column**: enum type grouping other enum fields.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    Open(filename, fmWrite)
+    --> col 2: system.FileMode.fmWrite
+        col 3: FileMode
+        col 7: ""
+
+
+skForVar
+--------
+
+| **Third column**: module + [n scope nesting] + var name.
+| **Fourth column**: type of the var.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    proc looper(filename = "tests.nim") =
+      for letter in filename:
+        echo letter
+    --> col 2: $MODULE.looper.letter
+        col 3: char
+        col 7: ""
+
+
+skIterator, skClosureIterator
+-----------------------------
+
+The fourth column will be the empty string if the iterator is being
+defined, since at that point in the file the parser hasn't processed
+the full line yet. The signature will be returned complete in
+posterior instances of the iterator.
+
+| **Third column**: module + [n scope nesting] + iterator name.
+| **Fourth column**: signature of the iterator including return type.
+| **Docstring**: docstring if available.
+
+.. code-block:: nim
+    let
+      text = "some text"
+      letters = toSeq(runes(text))
+    --> col 2: unicode.runes
+        col 3: iterator (string): Rune
+        col 7: "iterates over any unicode character of the string `s`."
+
+
+skLabel
+-------
+
+| **Third column**: module + [n scope nesting] + name.
+| **Fourth column**: always the empty string.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    proc test(text: string) =
+      var found = -1
+      block loops:
+    --> col 2: $MODULE.test.loops
+        col 3: ""
+        col 7: ""
+
+
+skLet
+-----
+
+| **Third column**: module + [n scope nesting] + let name.
+| **Fourth column**: the type of the let variable.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    let
+      text = "some text"
+    --> col 2: $MODULE.text
+        col 3: TaintedString
+        col 7: ""
+
+
+skMacro
+-------
+
+The fourth column will be the empty string if the macro is being
+defined, since at that point in the file the parser hasn't processed
+the full line yet. The signature will be returned complete in
+posterior instances of the macro.
+
+| **Third column**: module + [n scope nesting] + macro name.
+| **Fourth column**: signature of the macro including return type.
+| **Docstring**: docstring if available.
+
+.. code-block:: nim
+    proc testMacro() =
+      expect(EArithmetic):
+    --> col 2: idetools_api.expect
+        col 3: proc (varargs[expr], stmt): stmt
+        col 7: ""
+
+
+skMethod
+--------
+
+The fourth column will be the empty string if the method is being
+defined, since at that point in the file the parser hasn't processed
+the full line yet. The signature will be returned complete in
+posterior instances of the method.
+
+Methods imply `dynamic dispatch <tut2.html#dynamic-dispatch>`_ and
+idetools performs a static analysis on the code. For this reason
+idetools may not return the definition of the correct method you
+are querying because it may be impossible to know until the code
+is executed. It will try to return the method which covers the most
+possible cases (i.e. for variations of different classes in a
+hierarchy it will prefer methods using the base class).
+
+While at the language level a method is differentiated from others
+by the parameters and return value, the signature of the method
+returned by idetools returns also the pragmas for the method.
+
+Note that at the moment the word ``proc`` is returned for the
+signature of the found method instead of the expected ``method``.
+This may change in the future.
+
+| **Third column**: module + [n scope nesting] + method name.
+| **Fourth column**: signature of the method including return type.
+| **Docstring**: docstring if available.
+
+.. code-block:: nim
+    method eval(e: PExpr): int = quit "to override!"
+    method eval(e: PLiteral): int = e.x
+    method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
+    echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
+    --> col 2: $MODULE.eval
+        col 3: proc (PPlusExpr): int
+        col 7: ""
+
+
+skParam
+-------
+
+| **Third column**: module + [n scope nesting] + param name.
+| **Fourth column**: the type of the parameter.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    proc reader(filename = "tests.nim") =
+      let text = readFile(filename)
+    --> col 2: $MODULE.reader.filename
+        col 3: string
+        col 7: ""
+
+
+skProc
+------
+
+The fourth column will be the empty string if the proc is being
+defined, since at that point in the file the parser hasn't processed
+the full line yet. The signature will be returned complete in
+posterior instances of the proc.
+
+While at the language level a proc is differentiated from others
+by the parameters and return value, the signature of the proc
+returned by idetools returns also the pragmas for the proc.
+
+| **Third column**: module + [n scope nesting] + proc name.
+| **Fourth column**: signature of the proc including return type.
+| **Docstring**: docstring if available.
+
+.. code-block:: nim
+    open(filename, fmWrite)
+    --> col 2: system.Open
+        col 3: proc (var File, string, FileMode, int): bool
+        col 7:
+    "Opens a file named `filename` with given `mode`.
+
+     Default mode is readonly. Returns true iff the file could be opened.
+     This throws no exception if the file could not be opened."
+
+
+skResult
+--------
+
+| **Third column**: module + [n scope nesting] + result.
+| **Fourth column**: the type of the result.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    proc getRandomValue() : int =
+      return 4
+    --> col 2: $MODULE.getRandomValue.result
+        col 3: int
+        col 7: ""
+
+
+skTemplate
+----------
+
+The fourth column will be the empty string if the template is being
+defined, since at that point in the file the parser hasn't processed
+the full line yet. The signature will be returned complete in
+posterior instances of the template.
+
+| **Third column**: module + [n scope nesting] + template name.
+| **Fourth column**: signature of the template including return type.
+| **Docstring**: docstring if available.
+
+.. code-block:: nim
+    let
+      text = "some text"
+      letters = toSeq(runes(text))
+    --> col 2: sequtils.toSeq
+        col 3: proc (expr): expr
+        col 7:
+    "Transforms any iterator into a sequence.
+
+     Example:
+
+     .. code-block:: nim
+       let
+         numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+         odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+           if x mod 2 == 1:
+             result = true)
+       assert odd_numbers == @[1, 3, 5, 7, 9]"
+
+
+skType
+------
+
+| **Third column**: module + [n scope nesting] + type name.
+| **Fourth column**: the type.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    proc writeTempFile() =
+      var output: File
+    --> col 2: system.File
+        col 3: File
+        col 7: ""
+
+
+skVar
+-----
+
+| **Third column**: module + [n scope nesting] + var name.
+| **Fourth column**: the type of the var.
+| **Docstring**: always the empty string.
+
+.. code-block:: nim
+    proc writeTempFile() =
+      var output: File
+      output.open("/tmp/somefile", fmWrite)
+      output.write("test")
+    --> col 2: $MODULE.writeTempFile.output
+        col 3: File
+        col 7: ""
+
+
+Test suite
+==========
+
+To verify that idetools is working properly there are files in the
+``tests/caas/`` directory which provide unit testing. If you find
+odd idetools behaviour and are able to reproduce it, you are welcome
+to report it as a bug and add a test to the suite to avoid future
+regressions.
+
+
+Running the test suite
+----------------------
+
+At the moment idetools support is still in development so the test
+suite is not integrated with the main test suite and you have to
+run it manually. First you have to compile the tester::
+
+	$ cd my/nim/checkout/tests
+	$ nim c testament/caasdriver.nim
+
+Running the ``caasdriver`` without parameters will attempt to process
+all the test cases in all three operation modes. If a test succeeds
+nothing will be printed and the process will exit with zero. If any
+test fails, the specific line of the test preceding the failure
+and the failure itself will be dumped to stdout, along with a final
+indicator of the success state and operation mode. You can pass the
+parameter ``verbose`` to force all output even on successful tests.
+
+The normal operation mode is called ``ProcRun`` and it involves
+starting a process for each command or query, similar to running
+manually the Nim compiler from the commandline. The ``CaasRun``
+mode starts a server process to answer all queries. The ``SymbolProcRun``
+mode is used by compiler developers.  This means that running all
+tests involves processing all ``*.txt`` files three times, which
+can be quite time consuming.
+
+If you don't want to run all the test case files you can pass any
+substring as a parameter to ``caasdriver``. Only files matching the
+passed substring will be run. The filtering doesn't use any globbing
+metacharacters, it's a plain match. For example, to run only
+``*-compile*.txt`` tests in verbose mode::
+
+	./caasdriver verbose -compile
+
+
+Test case file format
+---------------------
+
+All the ``tests/caas/*.txt`` files encode a session with the compiler:
+
+* The first line indicates the main project file.
+
+* Lines starting with ``>`` indicate a command to be sent to the
+  compiler and the lines following a command include checks for
+  expected or forbidden output (``!`` for forbidden).
+
+* If a line starts with ``#`` it will be ignored completely, so you
+  can use that for comments.
+
+* Since some cases are specific to either ``ProcRun`` or ``CaasRun``
+  modes, you can prefix a line with the mode and the line will be
+  processed only in that mode.
+
+* The rest of the line is treated as a `regular expression <re.html>`_,
+  so be careful escaping metacharacters like parenthesis.
+
+Before the line is processed as a regular expression, some basic
+variables are searched for and replaced in the tests. The variables
+which will be replaced are:
+
+* **$TESTNIM**: filename specified in the first line of the script.
+* **$MODULE**: like $TESTNIM but without extension, useful for
+  expected output.
+
+When adding a test case to the suite it is a good idea to write a
+few comments about what the test is meant to verify.
diff --git a/doc/intern.txt b/doc/intern.txt
new file mode 100644
index 000000000..9582fc96f
--- /dev/null
+++ b/doc/intern.txt
@@ -0,0 +1,568 @@
+=========================================
+    Internals of the Nim Compiler
+=========================================
+
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+  "Abstraction is layering ignorance on top of reality." -- unknown
+
+
+Directory structure
+===================
+
+The Nim project's directory structure is:
+
+============   ==============================================
+Path           Purpose
+============   ==============================================
+``bin``        generated binary files
+``build``      generated C code for the installation
+``compiler``   the Nim compiler itself; note that this
+               code has been translated from a bootstrapping 
+               version written in Pascal, so the code is **not** 
+               a poster child of good Nim code
+``config``     configuration files for Nim
+``dist``       additional packages for the distribution
+``doc``        the documentation; it is a bunch of
+               reStructuredText files
+``lib``        the Nim library
+``web``        website of Nim; generated by ``nimweb``
+               from the ``*.txt`` and ``*.tmpl`` files
+============   ==============================================
+
+
+Bootstrapping the compiler
+==========================
+
+As of version 0.8.5 the compiler is maintained in Nim. (The first versions 
+have been implemented in Object Pascal.) The Python-based build system has 
+been rewritten in Nim too.
+
+Compiling the compiler is a simple matter of running::
+
+  nim c koch.nim
+  ./koch boot
+
+For a release version use::
+
+  nim c koch.nim
+  ./koch boot -d:release
+
+And for a debug version compatible with GDB::
+
+  nim c koch.nim
+  ./koch boot --debuginfo --linedir:on
+
+The ``koch`` program is Nim's maintenance script. It is a replacement for
+make and shell scripting with the advantage that it is much more portable.
+More information about its options can be found in the `koch <koch.html>`_
+documentation.
+
+
+Coding Guidelines
+=================
+
+* Use CamelCase, not underscored_identifiers.
+* Indent with two spaces.
+* Max line length is 80 characters.
+* Provide spaces around binary operators if that enhances readability.
+* Use a space after a colon, but not before it.
+* Start types with a capital ``T``, unless they are pointers/references which
+  start with ``P``.
+
+See also the `API naming design <apis.html>`_ document.
+
+
+Porting to new platforms
+========================
+
+Porting Nim to a new architecture is pretty easy, since C is the most
+portable programming language (within certain limits) and Nim generates
+C code, porting the code generator is not necessary.
+
+POSIX-compliant systems on conventional hardware are usually pretty easy to
+port: Add the platform to ``platform`` (if it is not already listed there),
+check that the OS, System modules work and recompile Nim.
+
+The only case where things aren't as easy is when the garbage
+collector needs some assembler tweaking to work. The standard
+version of the GC uses C's ``setjmp`` function to store all registers
+on the hardware stack. It may be necessary that the new platform needs to
+replace this generic code by some assembler code.
+
+
+Runtime type information
+========================
+
+*Runtime type information* (RTTI) is needed for several aspects of the Nim
+programming language:
+
+Garbage collection
+  The most important reason for RTTI. Generating
+  traversal procedures produces bigger code and is likely to be slower on
+  modern hardware as dynamic procedure binding is hard to predict.
+
+Complex assignments
+  Sequences and strings are implemented as
+  pointers to resizeable buffers, but Nim requires copying for
+  assignments. Apart from RTTI the compiler could generate copy procedures
+  for any type that needs one. However, this would make the code bigger and
+  the RTTI is likely already there for the GC.
+
+We already know the type information as a graph in the compiler.
+Thus we need to serialize this graph as RTTI for C code generation.
+Look at the file ``lib/system/hti.nim`` for more information.
+
+
+Debugging the compiler
+======================
+
+You can of course use GDB or Visual Studio to debug the 
+compiler (via ``--debuginfo --lineDir:on``). However, there
+are also lots of procs that aid in debugging:
+
+
+.. code-block:: nim
+  # pretty prints the Nim AST
+  echo renderTree(someNode)
+  # outputs some JSON representation
+  debug(someNode)
+  # pretty prints some type
+  echo typeToString(someType)
+  debug(someType)
+  echo symbol.name.s
+  debug(symbol)
+  # pretty prints the Nim ast, but annotates symbol IDs:
+  echo renderTree(someNode, {renderIds})
+  if n.info ?? "temp.nim":
+    # only output when it comes from "temp.nim"
+    echo renderTree(n)
+  if n.info ?? "temp.nim":
+    # why does it process temp.nim here?
+    writeStackTrace()
+
+To create a new compiler for each run, use ``koch temp``::
+
+  ./koch temp c /tmp/test.nim
+
+``koch temp`` creates a debug build of the compiler, which is useful
+to create stacktraces for compiler debugging.
+
+``koch temp`` returns 125 as the exit code in case the compiler
+compilation fails. This exit code tells ``git bisect`` to skip the
+current commit.::
+
+  git bisect start bad-commit good-commit
+  git bisect ./koch -r c test-source.nim
+
+The compiler's architecture
+===========================
+
+Nim uses the classic compiler architecture: A lexer/scanner feds tokens to a
+parser. The parser builds a syntax tree that is used by the code generator.
+This syntax tree is the interface between the parser and the code generator.
+It is essential to understand most of the compiler's code.
+
+In order to compile Nim correctly, type-checking has to be separated from
+parsing. Otherwise generics cannot work.
+
+.. include:: filelist.txt
+
+
+The syntax tree
+---------------
+The syntax tree consists of nodes which may have an arbitrary number of
+children. Types and symbols are represented by other nodes, because they
+may contain cycles. The AST changes its shape after semantic checking. This
+is needed to make life easier for the code generators. See the "ast" module
+for the type definitions. The `macros <macros.html>`_ module contains many
+examples how the AST represents each syntactic structure. 
+
+
+How the RTL is compiled
+=======================
+
+The ``system`` module contains the part of the RTL which needs support by
+compiler magic (and the stuff that needs to be in it because the spec
+says so). The C code generator generates the C code for it just like any other
+module. However, calls to some procedures like ``addInt`` are inserted by
+the CCG. Therefore the module ``magicsys`` contains a table (``compilerprocs``)
+with all symbols that are marked as ``compilerproc``. ``compilerprocs`` are
+needed by the code generator. A ``magic`` proc is not the same as a
+``compilerproc``: A ``magic`` is a proc that needs compiler magic for its
+semantic checking, a ``compilerproc`` is a proc that is used by the code
+generator.
+
+
+Compilation cache
+=================
+
+The implementation of the compilation cache is tricky: There are lots
+of issues to be solved for the front- and backend. In the following 
+sections *global* means *shared between modules* or *property of the whole
+program*.
+
+
+Frontend issues
+---------------
+
+Methods and type converters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Nim contains language features that are *global*. The best example for that
+are multi methods: Introducing a new method with the same name and some 
+compatible object parameter means that the method's dispatcher needs to take
+the new method into account. So the dispatching logic is only completely known
+after the whole program has been translated!
+
+Other features that are *implicitly* triggered cause problems for modularity 
+too. Type converters fall into this category:
+
+.. code-block:: nim
+  # module A
+  converter toBool(x: int): bool =
+    result = x != 0
+    
+.. code-block:: nim
+  # module B
+  import A
+  
+  if 1:
+    echo "ugly, but should work"
+
+If in the above example module ``B`` is re-compiled, but ``A`` is not then
+``B`` needs to be aware of ``toBool`` even though  ``toBool`` is not referenced
+in ``B`` *explicitly*. 
+
+Both the multi method and the type converter problems are solved by storing 
+them in special sections in the ROD file that are loaded *unconditionally*
+when the ROD file is read.
+
+Generics
+~~~~~~~~
+
+If we generate an instance of a generic, we'd like to re-use that
+instance if possible across module boundaries. However, this is not
+possible if the compilation cache is enabled. So we give up then and use
+the caching of generics only per module, not per project. This means that
+``--symbolFiles:on`` hurts a bit for efficiency. A better solution would
+be to persist the instantiations in a global cache per project. This might be
+implemented in later versions.
+
+
+Backend issues
+--------------
+
+- Init procs must not be "forgotten" to be called.
+- Files must not be "forgotten" to be linked.
+- Anything that is contained in ``nim__dat.c`` is shared between modules
+  implicitly.
+- Method dispatchers are global.
+- DLL loading via ``dlsym`` is global.
+- Emulated thread vars are global.
+
+
+However the biggest problem is that dead code elimination breaks modularity! 
+To see why, consider this scenario: The module ``G`` (for example the huge
+Gtk2 module...) is compiled with dead code elimination turned on. So none
+of ``G``'s procs is generated at all.
+
+Then module ``B`` is compiled that requires ``G.P1``. Ok, no problem,
+``G.P1`` is loaded from the symbol file and ``G.c`` now contains ``G.P1``.
+
+Then module ``A`` (that depends onto ``B`` and ``G``) is compiled and ``B`` 
+and ``G`` are left unchanged. ``A`` requires ``G.P2``.
+
+So now ``G.c`` MUST contain both ``P1`` and ``P2``, but we haven't even 
+loaded ``P1`` from the symbol file, nor do we want to because we then quickly 
+would restore large parts of the whole program. But we also don't want to 
+store ``P1`` in ``B.c`` because that would mean to store every symbol where 
+it is referred from which ultimately means the main module and putting
+everything in a single C file.
+
+There is however another solution: The old file ``G.c`` containing ``P1`` is
+**merged** with the new file ``G.c`` containing ``P2``. This is the solution
+that is implemented in the C code generator (have a look at the ``ccgmerge``
+module). The merging may lead to *cruft* (aka dead code) in generated C code
+which can only be removed by recompiling a project with the compilation cache
+turned off. Nevertheless the merge solution is way superior to the
+cheap solution "turn off dead code elimination if the compilation cache is 
+turned on".
+
+
+
+Debugging Nim's memory management
+=================================
+
+The following paragraphs are mostly a reminder for myself. Things to keep
+in mind:
+
+* If an assertion in Nim's memory manager or GC fails, the stack trace
+  keeps allocating memory! Thus a stack overflow may happen, hiding the
+  real issue.
+* What seem to be C code generation problems is often a bug resulting from
+  not producing prototypes, so that some types default to ``cint``. Testing
+  without the ``-w`` option helps!
+
+
+The Garbage Collector
+=====================
+
+Introduction
+------------
+
+I use the term *cell* here to refer to everything that is traced
+(sequences, refs, strings).
+This section describes how the new GC works.
+
+The basic algorithm is *Deferrent Reference Counting* with cycle detection.
+References on the stack are not counted for better performance and easier C
+code generation.
+
+Each cell has a header consisting of a RC and a pointer to its type
+descriptor. However the program does not know about these, so they are placed at
+negative offsets. In the GC code the type ``PCell`` denotes a pointer
+decremented by the right offset, so that the header can be accessed easily. It
+is extremely important that ``pointer`` is not confused with a ``PCell``
+as this would lead to a memory corruption.
+
+
+The CellSet data structure
+--------------------------
+
+The GC depends on an extremely efficient datastructure for storing a
+set of pointers - this is called a ``TCellSet`` in the source code.
+Inserting, deleting and searching are done in constant time. However,
+modifying a ``TCellSet`` during traversation leads to undefined behaviour.
+
+.. code-block:: Nim
+  type
+    TCellSet # hidden
+
+  proc cellSetInit(s: var TCellSet) # initialize a new set
+  proc cellSetDeinit(s: var TCellSet) # empty the set and free its memory
+  proc incl(s: var TCellSet, elem: PCell) # include an element
+  proc excl(s: var TCellSet, elem: PCell) # exclude an element
+
+  proc `in`(elem: PCell, s: TCellSet): bool # tests membership
+
+  iterator elements(s: TCellSet): (elem: PCell)
+
+
+All the operations have to perform efficiently. Because a Cellset can
+become huge a hash table alone is not suitable for this.
+
+We use a mixture of bitset and hash table for this. The hash table maps *pages*
+to a page descriptor. The page descriptor contains a bit for any possible cell
+address within this page. So including a cell is done as follows:
+
+- Find the page descriptor for the page the cell belongs to.
+- Set the appropriate bit in the page descriptor indicating that the
+  cell points to the start of a memory block.
+
+Removing a cell is analogous - the bit has to be set to zero.
+Single page descriptors are never deleted from the hash table. This is not
+needed as the data structures needs to be rebuilt periodically anyway.
+
+Complete traversal is done in this way::
+
+  for each page descriptor d:
+    for each bit in d:
+      if bit == 1:
+        traverse the pointer belonging to this bit
+
+
+Further complications
+---------------------
+
+In Nim the compiler cannot always know if a reference
+is stored on the stack or not. This is caused by var parameters.
+Consider this example:
+
+.. code-block:: Nim
+  proc setRef(r: var ref TNode) =
+    new(r)
+
+  proc usage =
+    var
+      r: ref TNode
+    setRef(r) # here we should not update the reference counts, because
+              # r is on the stack
+    setRef(r.left) # here we should update the refcounts!
+
+We have to decide at runtime whether the reference is on the stack or not. 
+The generated code looks roughly like this:
+
+.. code-block:: C
+  void setref(TNode** ref) {
+    unsureAsgnRef(ref, newObj(TNode_TI, sizeof(TNode)))
+  }
+  void usage(void) {
+    setRef(&r)
+    setRef(&r->left)
+  }
+
+Note that for systems with a continuous stack (which most systems have)
+the check whether the ref is on the stack is very cheap (only two
+comparisons).
+
+
+Code generation for closures
+============================
+
+Code generation for closures is implemented by `lambda lifting`:idx:.
+
+Design
+------
+
+A ``closure`` proc var can call ordinary procs of the default Nim calling
+convention. But not the other way round! A closure is implemented as a
+``tuple[prc, env]``. ``env`` can be nil implying a call without a closure.
+This means that a call through a closure generates an ``if`` but the 
+interoperability is worth the cost of the ``if``. Thunk generation would be
+possible too, but it's slightly more effort to implement.
+
+Tests with GCC on Amd64 showed that it's really beneficical if the
+'environment' pointer is passed as the last argument, not as the first argument.
+
+Proper thunk generation is harder because the proc that is to wrap
+could stem from a complex expression: 
+
+.. code-block:: nim
+  receivesClosure(returnsDefaultCC[i])
+
+A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require
+an *additional* closure generation... Ok, not really, but it requires to pass
+the function to call. So we'd end up with 2 indirect calls instead of one.
+Another much more severe problem which this solution is that it's not GC-safe 
+to pass a proc pointer around via a generic ``ref`` type.
+
+
+Example code:
+
+.. code-block:: nim
+  proc add(x: int): proc (y: int): int {.closure.} = 
+    return proc (y: int): int = 
+      return x + y
+
+  var add2 = add(2)
+  echo add2(5) #OUT 7
+
+This should produce roughly this code:
+
+.. code-block:: nim
+  type
+    PEnv = ref object
+      x: int # data
+  
+  proc anon(y: int, c: PClosure): int = 
+    return y + c.x
+  
+  proc add(x: int): tuple[prc, data] =
+    var env: PEnv
+    new env
+    env.x = x
+    result = (anon, env)
+  
+  var add2 = add(2)
+  let tmp = if add2.data == nil: add2.prc(5) else: add2.prc(5, add2.data)
+  echo tmp
+
+
+Beware of nesting:
+
+.. code-block:: nim
+  proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = 
+    return lamba (y: int): proc (z: int): int {.closure.} = 
+      return lambda (z: int): int = 
+        return x + y + z
+
+  var add24 = add(2)(4)
+  echo add24(5) #OUT 11
+
+This should produce roughly this code:
+
+.. code-block:: nim
+  type
+    PEnvX = ref object
+      x: int # data
+      
+    PEnvY = ref object
+      y: int
+      ex: PEnvX
+      
+  proc lambdaZ(z: int, ey: PEnvY): int =
+    return ey.ex.x + ey.y + z
+  
+  proc lambdaY(y: int, ex: PEnvX): tuple[prc, data: PEnvY] =
+    var ey: PEnvY
+    new ey
+    ey.y = y
+    ey.ex = ex
+    result = (lambdaZ, ey)
+  
+  proc add(x: int): tuple[prc, data: PEnvX] =
+    var ex: PEnvX
+    ex.x = x
+    result = (labmdaY, ex)
+  
+  var tmp = add(2)
+  var tmp2 = tmp.fn(4, tmp.data)
+  var add24 = tmp2.fn(4, tmp2.data)
+  echo add24(5)
+
+
+We could get rid of nesting environments by always inlining inner anon procs.
+More useful is escape analysis and stack allocation of the environment, 
+however.
+
+
+Alternative
+-----------
+
+Process the closure of all inner procs in one pass and accumulate the 
+environments. This is however not always possible.
+
+
+Accumulator
+-----------
+
+.. code-block:: nim
+  proc getAccumulator(start: int): proc (): int {.closure} = 
+    var i = start
+    return lambda: int = 
+      inc i
+      return i
+      
+  proc p =
+    var delta = 7
+    proc accumulator(start: int): proc(): int =
+      var x = start-1
+      result = proc (): int = 
+        x = x + delta
+        inc delta
+        return x
+    
+    var a = accumulator(3)
+    var b = accumulator(4)
+    echo a() + b()
+
+
+Internals
+---------
+
+Lambda lifting is implemented as part of the ``transf`` pass. The ``transf``
+pass generates code to setup the environment and to pass it around. However,
+this pass does not change the types! So we have some kind of mismatch here; on
+the one hand the proc expression becomes an explicit tuple, on the other hand
+the tyProc(ccClosure) type is not changed. For C code generation it's also
+important the hidden formal param is ``void*`` and not something more 
+specialized. However the more specialized env type needs to passed to the
+backend somehow. We deal with this by modifying ``s.ast[paramPos]`` to contain
+the formal hidden parameter, but not ``s.typ``!
+
+
diff --git a/doc/keywords.txt b/doc/keywords.txt
new file mode 100644
index 000000000..405bf1981
--- /dev/null
+++ b/doc/keywords.txt
@@ -0,0 +1,21 @@
+addr and as asm atomic
+bind block break
+case cast concept const continue converter
+defer discard distinct div do
+elif else end enum except export
+finally for from func
+generic
+if import in include interface is isnot iterator
+let
+macro method mixin mod
+nil not notin
+object of or out
+proc ptr
+raise ref return
+shl shr static
+template try tuple type
+using
+var
+when while with without
+xor
+yield
diff --git a/doc/koch.txt b/doc/koch.txt
new file mode 100644
index 000000000..7da137458
--- /dev/null
+++ b/doc/koch.txt
@@ -0,0 +1,151 @@
+===============================
+   Nim maintenance script
+===============================
+
+:Version: |nimversion|
+
+.. contents::
+
+.. raw:: html
+  <blockquote><p>
+  "A great chef is an artist that I truly respect" -- Robert Stack.
+  </p></blockquote>
+
+
+Introduction
+============
+
+The `koch`:idx: program is Nim's maintenance script. It is a replacement
+for make and shell scripting with the advantage that it is much more portable.
+The word *koch* means *cook* in German. ``koch`` is used mainly to build the
+Nim compiler, but it can also be used for other tasks. This document
+describes the supported commands and their options.
+
+
+Commands
+========
+
+boot command
+------------
+
+The `boot`:idx: command bootstraps the compiler, and it accepts different
+options:
+
+-d:release
+  By default a debug version is created, passing this option will
+  force a release build, which is much faster and should be preferred
+  unless you are debugging the compiler.
+-d:tinyc
+  Include the `Tiny C <http://bellard.org/tcc/>`_ backend. This
+  option is not supported on Windows.
+-d:useGnuReadline
+  Includes the `rdstdin module <rdstdin.html>`_ for `interactive
+  mode <nimc.html#nim-interactive-mode>`_ (aka ``nim i``).
+  This is not needed on Windows. On other platforms this may
+  incorporate the GNU readline library.
+-d:nativeStacktrace
+  Use native stack traces (only for Mac OS X or Linux).
+-d:noCaas
+  Builds Nim without compiler as a service (CAAS) support. CAAS
+  support is required for functionality like Nim's `idetool
+  <idetools.html>`_ command used to integrate the compiler with
+  `external IDEs <https://github.com/Araq/Nim/wiki/Editor-Support>`_.
+-d:avoidTimeMachine
+  Only for Mac OS X, activating this switch will force excluding
+  the generated ``nimcache`` directories from Time Machine backups.
+  By default ``nimcache`` directories will be included in backups,
+  and just for the Nim compiler itself it means backing up 20MB
+  of generated files each time you update the compiler. Using this
+  option will make the compiler invoke the `tmutil
+  <https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man8/tmutil.8.html>`_
+  command on all ``nimcache`` directories, setting their backup
+  exclusion bit.
+
+  You can use the following command to locate all ``nimcache``
+  directories and check their backup exclusion bit::
+
+    $ find . -type d -name nimcache -exec tmutil isexcluded \{\} \;
+-d:useFFI
+  Nim code can use the `foreign function interface (FFI)
+  <manual.html#foreign-function-interface>`_ at runtime, but macros
+  are limited to pure Nim code at compilation time.  Enabling
+  this switch will allow macros to execute non-nim code at
+  compilation time (eg. open a file and write to it).
+--gc:refc|v2|markAndSweep|boehm|none
+  Selects which garbage collection strategy to use for the compiler
+  and generated code. See the `Nim's Garbage Collector <gc.html>`_
+  documentation for more information.
+
+After compilation is finished you will hopefully end up with the nim
+compiler in the ``bin`` directory. You can add Nim's ``bin`` directory to
+your ``$PATH`` or use the `install command`_ to place it where it will be
+found.
+
+clean command
+-------------
+
+The `clean`:idx: command removes all generated files.
+
+csource command
+---------------
+
+The `csource`:idx: command builds the C sources for installation. It accepts
+the same options as you would pass to the `boot command`_.
+
+inno command
+------------
+
+The `inno`:idx: command builds the `Inno Setup installer for Windows
+<http://www.jrsoftware.org/isinfo.php>`_.
+
+install command
+---------------
+
+The `install`:idx: command installs Nim to the specified directory, which
+is required as a parameter. For example, on Unix platforms you could run::
+
+  $ ./koch install /usr/local/bin
+
+temp command
+------------
+
+The temp command builds the Nim compiler but with a different final name
+(``nim_temp``), so it doesn't overwrite your normal compiler. You can use
+this command to test different options, the same you would issue for the `boot
+command`_.
+
+test command
+------------
+
+The `test`:idx: command can also be invoked with the alias ``tests``. This
+command will compile and run ``tests/testament/tester.nim``, which is the main
+driver of Nim's test suite. You can pass options to the ``test`` command,
+they will be forwarded to the tester. See its source code for available
+options.
+
+update command
+--------------
+
+The `update`:idx: command updates nim to the latest version from github.
+For this command to work you need to have compiled ``koch`` itself with the
+``-d:withUpdate`` switch.
+
+web command
+-----------
+
+The `web`:idx: command converts the documentation in the ``doc`` directory
+from rst to HTML. It also repeats the same operation but places the result in
+the ``web/upload`` which can be used to update the website at
+http://nim-lang.org.
+
+By default the documentation will be built in parallel using the number of
+available CPU cores. If any documentation build sub commands fail, they will
+be rerun in serial fashion so that meaninful error output can be gathered for
+inspection. The ``--parallelBuild:n`` switch or configuration option can be
+used to force a specific number of parallel jobs or run everything serially
+from the start (``n == 1``).
+
+zip command
+-----------
+
+The `zip`:idx: command builds the installation ZIP package.
diff --git a/doc/lib.txt b/doc/lib.txt
new file mode 100644
index 000000000..f43228151
--- /dev/null
+++ b/doc/lib.txt
@@ -0,0 +1,610 @@
+====================
+Nim Standard Library
+====================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+  "The good thing about reinventing the wheel is that you can get a round one."
+
+Though the Nim Standard Library is still evolving, it is already quite
+usable. It is divided into *pure libraries*, *impure libraries* and *wrappers*.
+
+Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary
+while impure libraries do. A wrapper is an impure library that is a very
+low-level interface to a C library.
+
+Read this `document <apis.html>`_ for a quick overview of the API design.
+
+The `bottom <#nimble>`_ of this page includes a list of 3rd party packages
+created by the Nim community. These packages are a useful addition to the
+modules in the standard library.
+
+
+Pure libraries
+==============
+
+Core
+----
+
+* `system <system.html>`_
+  Basic procs and operators that every program needs. It also provides IO
+  facilities for reading and writing text and binary files. It is imported
+  implicitly by the compiler. Do not import it directly. It relies on compiler
+  magic to work.
+
+* `unsigned <unsigned.html>`_
+  This module implements basic arithmetic operators for unsigned integers.
+  To discourage users from using unsigned integers, it's not part
+  of ``system``, but an extra import.
+
+* `threads <threads.html>`_
+  Nim thread support. **Note**: This is part of the system module. Do not
+  import it explicitly.
+
+* `channels <channels.html>`_
+  Nim message passing support for threads. **Note**: This is part of the
+  system module. Do not import it explicitly.
+
+* `locks <locks.html>`_
+  Locks and condition variables for Nim.
+
+* `macros <macros.html>`_
+  Contains the AST API and documentation of Nim for writing macros.
+
+* `typeinfo <typeinfo.html>`_
+  Provides (unsafe) access to Nim's run time type information.
+
+* `typetraits <typetraits.html>`_
+  This module defines compile-time reflection procs for working with types.
+
+* `threadpool <threadpool.html>`_
+  Implements Nim's `spawn <manual.html#spawn>`_.
+
+* `cpuinfo <cpuinfo.html>`_
+  This module implements procs to determine the number of CPUs / cores.
+
+
+Collections and algorithms
+--------------------------
+
+* `algorithm <algorithm.html>`_
+  Implements some common generic algorithms like sort or binary search.
+* `tables <tables.html>`_
+  Nim hash table support. Contains tables, ordered tables and count tables.
+* `sets <sets.html>`_
+  Nim hash and bit set support.
+* `lists <lists.html>`_
+  Nim linked list support. Contains singly and doubly linked lists and
+  circular lists ("rings").
+* `queues <queues.html>`_
+  Implementation of a queue. The underlying implementation uses a ``seq``.
+* `intsets <intsets.html>`_
+  Efficient implementation of a set of ints as a sparse bit set.
+* `critbits <critbits.html>`_
+  This module implements a *crit bit tree* which is an efficient
+  container for a set or a mapping of strings.
+* `sequtils <sequtils.html>`_
+  This module implements operations for the built-in seq type
+  which were inspired by functional programming languages.
+
+
+String handling
+---------------
+
+* `strutils <strutils.html>`_
+  This module contains common string handling operations like changing
+  case of a string, splitting a string into substrings, searching for
+  substrings, replacing substrings.
+
+* `parseutils <parseutils.html>`_
+  This module contains helpers for parsing tokens, numbers, identifiers, etc.
+
+* `strtabs <strtabs.html>`_
+  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.
+
+* `unicode <unicode.html>`_
+  This module provides support to handle the Unicode UTF-8 encoding.
+
+* `encodings <encodings.html>`_
+  Converts between different character encodings. On UNIX, this uses
+  the ``iconv`` library, on Windows the Windows API.
+
+* `pegs <pegs.html>`_
+  This module contains procedures and operators for handling PEGs.
+
+* `ropes <ropes.html>`_
+  This module contains support for a *rope* data type.
+  Ropes can represent very long strings efficiently; especially concatenation
+  is done in O(1) instead of O(n).
+
+* `unidecode <unidecode.html>`_
+  This module provides Unicode to ASCII transliterations:
+  It finds the sequence of ASCII characters that is the closest approximation
+  to the Unicode string.
+
+* `matchers <matchers.html>`_
+  This module contains various string matchers for email addresses, etc.
+
+* `subexes <subexes.html>`_
+  This module implements advanted string substitution operations.
+
+
+Generic Operating System Services
+---------------------------------
+
+* `os <os.html>`_
+  Basic operating system facilities like retrieving environment variables,
+  reading command line arguments, working with directories, running shell
+  commands, etc.
+
+* `osproc <osproc.html>`_
+  Module for process communication beyond ``os.execShellCmd``.
+
+* `times <times.html>`_
+  The ``times`` module contains basic support for working with time.
+
+* `dynlib <dynlib.html>`_
+  This module implements the ability to access symbols from shared libraries.
+
+* `streams <streams.html>`_
+  This module provides a stream interface and two implementations thereof:
+  the `FileStream` and the `StringStream` which implement the stream
+  interface for Nim file objects (`File`) and strings. Other modules
+  may provide other implementations for this standard stream interface.
+
+* `marshal <marshal.html>`_
+  Contains procs for serialization and deseralization of arbitrary Nim
+  data structures.
+
+* `terminal <terminal.html>`_
+  This module contains a few procedures to control the *terminal*
+  (also called *console*). The implementation simply uses ANSI escape
+  sequences and does not depend on any other module.
+
+* `memfiles <memfiles.html>`_
+  This module provides support for memory mapped files (Posix's ``mmap``)
+  on the different operating systems.
+
+* `fsmonitor <fsmonitor.html>`_
+  This module implements the ability to monitor a directory/file for changes
+  using Posix's inotify API.
+
+* `asyncfile <asyncfile.html>`_
+  This module implements asynchronous file reading and writing using
+  ``asyncdispatch``.
+
+Math libraries
+--------------
+
+* `math <math.html>`_
+  Mathematical operations like cosine, square root.
+
+* `complex <complex.html>`_
+  This module implements complex numbers and their mathematical operations.
+
+* `rationals <rationals.html>`_
+  This module implements rational numbers and their mathematical operations.
+
+* `fenv <fenv.html>`_
+  Floating-point environment. Handling of floating-point rounding and
+  exceptions (overflow, zero-devide, etc.).
+
+* `basic2d <basic2d.html>`_
+  Basic 2d support with vectors, points, matrices and some basic utilities.
+
+* `basic3d <basic3d.html>`_
+  Basic 3d support with vectors, points, matrices and some basic utilities.
+
+
+Internet Protocols and Support
+------------------------------
+
+* `cgi <cgi.html>`_
+  This module implements helpers for CGI applications.
+
+* `scgi <scgi.html>`_
+  This module implements helpers for SCGI applications.
+
+* `sockets <sockets.html>`_
+  This module implements a simple portable type-safe sockets layer.
+
+* `asyncio <asyncio.html>`_
+  This module implements an asynchronous event loop for sockets.
+
+* `browsers <browsers.html>`_
+  This module implements procs for opening URLs with the user's default
+  browser.
+
+* `httpserver <httpserver.html>`_
+  This module implements a simple HTTP server.
+
+* `httpclient <httpclient.html>`_
+  This module implements a simple HTTP client.
+
+* `smtp <smtp.html>`_
+  This module implement a simple SMTP client.
+
+* `ftpclient <ftpclient.html>`_
+  This module implements an FTP client.
+
+* `cookies <cookies.html>`_
+  This module contains helper procs for parsing and generating cookies.
+
+* `mimetypes <mimetypes.html>`_
+  This module implements a mimetypes database.
+
+* `uri <uri.html>`_
+  This module provides functions for working with URIs.
+
+* `asyncdispatch <asyncdispatch.html>`_
+  This module implements an asynchronous dispatcher for IO operations.
+
+  **Note:** This module is still largely experimental.
+
+* `asyncnet <asyncnet.html>`_
+  This module implements asynchronous sockets based on the ``asyncdispatch``
+  module.
+
+  **Note:** This module is still largely experimental.
+
+* `asynchttpserver <asynchttpserver.html>`_
+  This module implements an asynchronous HTTP server using the ``asyncnet``
+  module.
+
+  **Note:** This module is still largely experimental.
+
+* `net <net.html>`_
+  This module implements a high-level sockets API. It will replace the
+  ``sockets`` module in the future.
+
+* `rawsockets <rawsockets.html>`_
+  This module implements a low-level sockets API.
+
+* `selectors <selectors.html>`_
+  This module implements a selector API with backends specific to each OS.
+  Currently epoll on Linux and select on other operating systems.
+
+Parsers
+-------
+
+* `parseopt <parseopt.html>`_
+  The ``parseopt`` module implements a command line option parser.
+  **Deprecated since version 0.9.3:** Use the `parseopt2
+  <parseopt2.html>`_ module instead.
+
+* `parseopt2 <parseopt2.html>`_
+  The ``parseopt2`` module implements a command line option parser. This
+  supports long and short command options with optional values and command line
+  arguments.
+
+* `parsecfg <parsecfg.html>`_
+  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 Nim programming language.
+
+* `parsexml <parsexml.html>`_
+  The ``parsexml`` module implements a simple high performance XML/HTML parser.
+  The only encoding that is supported is UTF-8. The parser has been designed
+  to be somewhat error correcting, so that even some "wild HTML" found on the
+  Web can be parsed with it.
+
+* `parsecsv <parsecsv.html>`_
+  The ``parsecsv`` module implements a simple high performance CSV parser.
+
+* `parsesql <parsesql.html>`_
+  The ``parsesql`` module implements a simple high performance SQL parser.
+
+* `json <json.html>`_
+  High performance JSON parser.
+
+* `lexbase <lexbase.html>`_
+  This is a low level module that implements an extremely efficient buffering
+  scheme for lexers and parsers. This is used by the diverse parsing modules.
+
+* `highlite <highlite.html>`_
+  Source highlighter for programming or markup languages.  Currently
+  only few languages are supported, other languages may be added.
+  The interface supports one language nested in another.
+
+* `rst <rst.html>`_
+  This module implements a reStructuredText parser. A large subset
+  is implemented. Some features of the markdown wiki syntax are
+  also supported.
+
+* `rstast <rstast.html>`_
+  This module implements an AST for the reStructuredText parser.
+
+* `rstgen <rstgen.html>`_
+  This module implements a generator of HTML/Latex from reStructuredText.
+
+* `sexp <sexp.html>`_
+  High performance sexp parser and generator, mainly for communication
+  with emacs.
+
+
+XML Processing
+--------------
+
+* `xmldom <xmldom.html>`_
+  This module implements the XML DOM Level 2.
+
+* `xmldomparser <xmldomparser.html>`_
+  This module parses an XML Document into a XML DOM Document representation.
+
+* `xmltree <xmltree.html>`_
+  A simple XML tree. More efficient and simpler than the DOM. It also
+  contains a macro for XML/HTML code generation.
+
+* `xmlparser <xmlparser.html>`_
+  This module parses an XML document and creates its XML tree representation.
+
+* `htmlparser <htmlparser.html>`_
+  This module parses an HTML document and creates its XML tree representation.
+
+* `htmlgen <htmlgen.html>`_
+  This module implements a simple XML and HTML code
+  generator. Each commonly used HTML tag has a corresponding macro
+  that generates a string with its HTML representation.
+
+Cryptography and Hashing
+------------------------
+
+* `hashes <hashes.html>`_
+  This module implements efficient computations of hash values for diverse
+  Nim types.
+
+* `md5 <md5.html>`_
+  This module implements the MD5 checksum algorithm.
+
+* `base64 <base64.html>`_
+  This module implements a base64 encoder and decoder.
+
+
+Multimedia support
+------------------
+
+* `colors <colors.html>`_
+  This module implements color handling for Nim. It is used by
+  the ``graphics`` module.
+
+
+Miscellaneous
+-------------
+
+* `events <events.html>`_
+  This module implements an event system that is not dependent on external
+  graphical toolkits.
+
+* `oids <oids.html>`_
+  An OID is a global ID that consists of a timestamp,
+  a unique counter and a random value. This combination should suffice to
+  produce a globally distributed unique ID. This implementation was extracted
+  from the Mongodb interface and it thus binary compatible with a Mongo OID.
+
+* `endians <endians.html>`_
+  This module contains helpers that deal with different byte orders.
+
+* `logging <logging.html>`_
+  This module implements a simple logger.
+
+* `future <future.html>`_
+  This module implements new experimental features. Currently the syntax
+  sugar for anonymous procedures.
+
+Database support
+----------------
+
+* `redis <redis.html>`_
+  This module implements a redis client. It allows you to connect to a
+  redis-server instance, send commands and receive replies.
+
+
+Modules for JS backend
+---------------------------
+
+* `dom <dom.html>`_
+  Declaration of the Document Object Model for the JS backend.
+
+
+Impure libraries
+================
+
+Regular expressions
+-------------------
+
+* `re <re.html>`_
+  This module contains procedures and operators for handling regular
+  expressions. The current implementation uses PCRE.
+
+
+Database support
+----------------
+
+* `db_postgres <db_postgres.html>`_
+  A higher level PostgreSQL database wrapper. The same interface is implemented
+  for other databases too.
+
+* `db_mysql <db_mysql.html>`_
+  A higher level MySQL database wrapper. The same interface is implemented
+  for other databases too.
+
+* `db_sqlite <db_sqlite.html>`_
+  A higher level SQLite database wrapper. The same interface is implemented
+  for other databases too.
+
+
+Other
+-----
+
+* `graphics <graphics.html>`_
+  This module implements graphical output for Nim; the current
+  implementation uses SDL but the interface is meant to support multiple
+  backends some day.
+
+* `dialogs <dialogs.html>`_
+  This module implements portable dialogs for Nim; the implementation
+  builds on the GTK interface. On Windows, native dialogs are shown if
+  appropriate.
+
+* `zipfiles <zipfiles.html>`_
+  This module implements a zip archive creator/reader/modifier.
+
+* `ssl <ssl.html>`_
+  This module provides an easy to use sockets-style
+  Nim interface to the OpenSSL library.
+
+* `rdstdin <rdstdin.html>`_
+  This module contains code for reading from `stdin`:idx:. On UNIX the GNU
+  readline library is wrapped and set up.
+
+
+Wrappers
+========
+
+The generated HTML for some of these wrappers is so huge that it is
+not contained in the distribution. You can then find them on the website.
+
+Windows specific
+----------------
+
+* `windows <windows.html>`_
+  Contains a wrapper for the Win32 API.
+* `winlean <winlean.html>`_
+  Contains a wrapper for a small subset of the Win32 API.
+* `shellapi <shellapi.html>`_
+  Contains a wrapper for the ``shellapi.h`` header.
+* `shfolder <shfolder.html>`_
+  Contains a wrapper for the ``shfolder.h`` header.
+* `mmsystem <mmsystem.html>`_
+  Contains a wrapper for the ``mmsystem.h`` header.
+* `psapi <psapi.html>`_
+  Contains a wrapper for the ``psapi.h`` header.
+* `nb30 <nb30.html>`_
+  This module contains the definitions for portable NetBIOS 3.0 support.
+
+
+UNIX specific
+-------------
+
+* `posix <posix.html>`_
+  Contains a wrapper for the POSIX standard.
+* `readline <readline.html>`_
+  Part of the wrapper for the GNU readline library.
+* `history <history.html>`_
+  Part of the wrapper for the GNU readline library.
+* `rltypedefs <rltypedefs.html>`_
+  Part of the wrapper for the GNU readline library.
+
+
+Regular expressions
+-------------------
+
+* `pcre <pcre.html>`_
+  Wrapper for the PCRE library.
+* `tre <tre.html>`_
+  Wrapper for the TRE library.
+
+
+GUI libraries
+-------------
+
+* `iup <iup.html>`_
+  Wrapper of the IUP GUI library.
+
+
+Database support
+----------------
+
+* `postgres <postgres.html>`_
+  Contains a wrapper for the PostgreSQL API.
+* `mysql <mysql.html>`_
+  Contains a wrapper for the mySQL API.
+* `sqlite3 <sqlite3.html>`_
+  Contains a wrapper for SQLite 3 API.
+* `odbcsql <odbcsql.html>`_
+  interface to the ODBC driver.
+* `sphinx <sphinx.html>`_
+  Nim wrapper for ``sphinx``.
+
+
+XML Processing
+--------------
+
+* `expat <expat.html>`_
+  Wrapper of the expat XML parser.
+
+
+Network Programming and Internet Protocols
+------------------------------------------
+
+* `libuv <libuv.html>`_
+  Wrapper for the libuv library used for async I/O programming.
+
+* `joyent_http_parser <joyent_http_parser.html>`_
+  Wrapper for the joyent's high-performance HTTP parser.
+
+* `libcurl <libcurl.html>`_
+  Wrapper for the libcurl library.
+
+* `openssl <openssl.html>`_
+  Wrapper for OpenSSL.
+
+
+Data Compression and Archiving
+------------------------------
+
+* `zlib <zlib.html>`_
+  Wrapper for the zlib library.
+
+* `libzip <libzip.html>`_
+  Interface to the `lib zip <http://www.nih.at/libzip/index.html>`_ library by
+  Dieter Baron and Thomas Klausner.
+
+
+Scientific computing
+--------------------
+
+* `libsvm <libsvm.html>`_
+  Low level wrapper for `lib svm <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_.
+
+Nimble
+====================
+
+Nimble is a package manager for the Nim programming language.
+For instructions on how to install Nimble packages see
+`its README <https://github.com/nim-lang/nimble#readme>`_.
+
+Official packages
+-----------------
+
+These packages are officially supported and will therefore be continually
+maintained to ensure that they work with the latest versions of the Nim
+compiler.
+
+.. raw:: html
+
+  <div id="officialPkgList"><b>If you are reading this you are missing
+  nimblepkglist.js or have javascript disabled in your browser.</b></div>
+
+Unofficial packages
+-------------------
+
+These packages have been developed by independent Nim developers and as
+such may not always be up to date with the latest developments in the
+Nim programming language.
+
+.. raw:: html
+
+  <div id="unofficialPkgList"><b>If you are reading this you are missing
+  nimblepkglist.js or have javascript disabled in your browser.</b></div>
+
+  <script type="text/javascript" src="nimblepkglist.js"></script>
+  <script type="text/javascript" src="http://irclogs.nim-lang.org/packages?callback=gotPackageList"></script>
diff --git a/doc/manual.txt b/doc/manual.txt
new file mode 100644
index 000000000..2dbbf0447
--- /dev/null
+++ b/doc/manual.txt
@@ -0,0 +1,39 @@
+==========
+Nim Manual
+==========
+
+:Authors: Andreas Rumpf, Zahary Karadjov
+:Version: |nimversion|
+
+.. contents::
+
+
+  "Complexity" seems to be a lot like "energy": you can transfer it from the end
+  user to one/some of the other players, but the total amount seems to remain
+  pretty much constant for a given task. -- Ran
+
+
+.. include:: manual/about.txt
+.. include:: manual/definitions.txt
+.. include:: manual/lexing.txt
+.. include:: manual/syntax.txt
+.. include:: manual/types.txt
+.. include:: manual/type_rel.txt
+.. include:: manual/stmts.txt
+.. include:: manual/procs.txt
+.. include:: manual/type_sections.txt
+.. include:: manual/exceptions.txt
+.. include:: manual/effects.txt
+.. include:: manual/generics.txt
+.. include:: manual/templates.txt
+.. include:: manual/typedesc.txt
+.. include:: manual/special_ops.txt
+.. include:: manual/type_bound_ops.txt
+.. include:: manual/trmacros.txt
+.. include:: manual/modules.txt
+.. include:: manual/compiler_msgs.txt
+.. include:: manual/pragmas.txt
+.. include:: manual/ffi.txt
+.. include:: manual/threads.txt
+.. include:: manual/locking.txt
+.. include:: manual/taint.txt
diff --git a/doc/manual/about.txt b/doc/manual/about.txt
new file mode 100644
index 000000000..8528ff978
--- /dev/null
+++ b/doc/manual/about.txt
@@ -0,0 +1,37 @@
+About this document
+===================
+
+**Note**: This document is a draft! Several of Nim's features may need more
+precise wording. This manual is constantly evolving until the 1.0 release and is
+not to be considered as the final proper specification.
+
+This document describes the lexis, the syntax, and the semantics of Nim.
+
+The language constructs are explained using an extended BNF, in which ``(a)*``
+means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and ``(a)?`` means an
+optional *a*. Parentheses may be used to group elements.
+
+``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but
+not consumed. It will be consumed in the following rule.
+
+The ``|``, ``/`` symbols are used to mark alternatives and have the lowest 
+precedence. ``/`` is the ordered choice that requires the parser to try the 
+alternatives in the given order. ``/`` is often used to ensure the grammar
+is not ambiguous. 
+
+Non-terminals start with a lowercase letter, abstract terminal symbols are in
+UPPERCASE. Verbatim terminal symbols (including keywords) are quoted
+with ``'``. An example::
+
+  ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
+  
+The binary ``^*`` operator is used as a shorthand for 0 or more occurrences
+separated by its second argument; likewise ``^+`` means 1 or more 
+occurrences: ``a ^+ b`` is short for ``a (b a)*`` 
+and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
+
+  arrayConstructor = '[' expr ^* ',' ']'
+
+Other parts of Nim - like scoping rules or runtime semantics are only
+described in the, more easily comprehensible, informal manner for now.
+
diff --git a/doc/manual/compiler_msgs.txt b/doc/manual/compiler_msgs.txt
new file mode 100644
index 000000000..3cf8417b0
--- /dev/null
+++ b/doc/manual/compiler_msgs.txt
@@ -0,0 +1,7 @@
+Compiler Messages
+=================
+
+The Nim compiler emits different kinds of messages: `hint`:idx:,
+`warning`:idx:, and `error`:idx: messages. An *error* message is emitted if
+the compiler encounters any static error.
+
diff --git a/doc/manual/definitions.txt b/doc/manual/definitions.txt
new file mode 100644
index 000000000..9004ce658
--- /dev/null
+++ b/doc/manual/definitions.txt
@@ -0,0 +1,49 @@
+
+Definitions
+===========
+
+A Nim program specifies a computation that acts on a memory consisting of
+components called `locations`:idx:. A variable is basically a name for a
+location. Each variable and location is of a certain `type`:idx:. The
+variable's type is called `static type`:idx:, the location's type is called
+`dynamic type`:idx:. If the static type is not the same as the dynamic type,
+it is a super-type or subtype of the dynamic type.
+
+An `identifier`:idx: is a symbol declared as a name for a variable, type,
+procedure, etc. The region of the program over which a declaration applies is
+called the `scope`:idx: of the declaration. Scopes can be nested. The meaning
+of an identifier is determined by the smallest enclosing scope in which the
+identifier is declared unless overloading resolution rules suggest otherwise.
+
+An expression specifies a computation that produces a value or location.
+Expressions that produce locations are called `l-values`:idx:. An l-value
+can denote either a location or the value the location contains, depending on
+the context. Expressions whose values can be determined statically are called
+`constant expressions`:idx:; they are never l-values.
+
+A `static error`:idx: is an error that the implementation detects before
+program execution. Unless explicitly classified, an error is a static error.
+
+A `checked runtime error`:idx: is an error that the implementation detects
+and reports at runtime. The method for reporting such errors is via *raising
+exceptions* or *dying with a fatal error*. However, the implementation 
+provides a means to disable these runtime checks. See the section pragmas_
+for details. 
+
+Whether a checked runtime error results in an exception or in a fatal error at
+runtime is implementation specific. Thus the following program is always
+invalid:
+
+.. code-block:: nim
+  var a: array[0..1, char]
+  let i = 5
+  try:
+    a[i] = 'N'
+  except IndexError:
+    echo "invalid index"
+
+An `unchecked runtime error`:idx: is an error that is not guaranteed to be
+detected, and can cause the subsequent behavior of the computation to
+be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx:
+language features are used.
+
diff --git a/doc/manual/effects.txt b/doc/manual/effects.txt
new file mode 100644
index 000000000..40532b080
--- /dev/null
+++ b/doc/manual/effects.txt
@@ -0,0 +1,129 @@
+Effect system
+=============
+
+Exception tracking
+------------------
+
+Nim supports exception tracking. The `raises`:idx: pragma can be used
+to explicitly define which exceptions a proc/iterator/method/converter is 
+allowed to raise. The compiler verifies this:
+
+.. code-block:: nim
+  proc p(what: bool) {.raises: [IOError, OSError].} =
+    if what: raise newException(IOError, "IO")
+    else: raise newException(OSError, "OS")
+
+An empty ``raises`` list (``raises: []``) means that no exception may be raised:
+
+.. code-block:: nim
+  proc p(): bool {.raises: [].} =
+    try:
+      unsafeCall()
+      result = true
+    except:
+      result = false
+
+
+A ``raises`` list can also be attached to a proc type. This affects type 
+compatibility:
+
+.. code-block:: nim
+  type
+    Callback = proc (s: string) {.raises: [IOError].}
+  var
+    c: Callback
+
+  proc p(x: string) =
+    raise newException(OSError, "OS")
+  
+  c = p # type error
+
+
+For a routine ``p`` the compiler uses inference rules to determine the set of
+possibly raised exceptions; the algorithm operates on ``p``'s call graph:
+
+1. Every indirect call via some proc type ``T`` is assumed to
+   raise ``system.Exception`` (the base type of the exception hierarchy) and
+   thus any exception unless ``T`` has an explicit ``raises`` list.
+   However if the call is of the form ``f(...)`` where ``f`` is a parameter
+   of the currently analysed routine it is ignored. The call is optimistically 
+   assumed to have no effect. Rule 2 compensates for this case.
+2. Every expression of some proc type within a call that is not a call 
+   itself (and not nil) is assumed to be called indirectly somehow and thus 
+   its raises list is added to ``p``'s raises list.
+3. Every call to a proc ``q`` which has an unknown body (due to a forward 
+   declaration or an ``importc`` pragma) is assumed to 
+   raise ``system.Exception`` unless ``q`` has an explicit ``raises`` list.
+4. Every call to a method ``m`` is assumed to 
+   raise ``system.Exception`` unless ``m`` has an explicit ``raises`` list.
+5. For every other call the analysis can determine an exact ``raises`` list.
+6. For determining a ``raises`` list, the ``raise`` and ``try`` statements 
+   of ``p`` are taken into consideration.
+
+Rules 1-2 ensure the following works: 
+
+.. code-block:: nim
+  proc noRaise(x: proc()) {.raises: [].} =
+    # unknown call that might raise anything, but valid:
+    x()
+    
+  proc doRaise() {.raises: [IOError].} =
+    raise newException(IOError, "IO")
+  
+  proc use() {.raises: [].} =
+    # doesn't compile! Can raise IOError!
+    noRaise(doRaise)
+
+So in many cases a callback does not cause the compiler to be overly
+conservative in its effect analysis.
+
+
+Tag tracking
+------------
+
+The exception tracking is part of Nim's `effect system`:idx:. Raising an
+exception is an *effect*. Other effects can also be defined. A user defined 
+effect is a means to *tag* a routine and to perform checks against this tag:
+
+.. code-block:: nim
+  type IO = object ## input/output effect
+  proc readLine(): string {.tags: [IO].}
+  
+  proc no_IO_please() {.tags: [].} =
+    # the compiler prevents this:
+    let x = readLine()
+
+A tag has to be a type name. A ``tags`` list - like a ``raises`` list - can 
+also be attached to a proc type. This affects type compatibility.
+
+The inference for tag tracking is analogous to the inference for 
+exception tracking.
+
+
+Read/Write tracking
+-------------------
+
+**Note**: Read/write tracking is not yet implemented!
+
+The inference for read/write tracking is analogous to the inference for 
+exception tracking.
+
+
+Effects pragma
+--------------
+
+The ``effects`` pragma has been designed to assist the programmer with the
+effects analysis. It is a statement that makes the compiler output all inferred
+effects up to the ``effects``'s position:
+
+.. code-block:: nim
+  proc p(what: bool) =
+    if what:
+      raise newException(IOError, "IO")
+      {.effects.}
+    else:
+      raise newException(OSError, "OS")
+
+The compiler produces a hint message that ``IOError`` can be raised. ``OSError``
+is not listed as it cannot be raised in the branch the ``effects`` pragma
+appears in.
diff --git a/doc/manual/exceptions.txt b/doc/manual/exceptions.txt
new file mode 100644
index 000000000..0010d5d09
--- /dev/null
+++ b/doc/manual/exceptions.txt
@@ -0,0 +1,158 @@
+Exception handling
+==================
+
+Try statement
+-------------
+
+Example:
+
+.. code-block:: nim
+  # read the first two lines of a text file that should contain numbers
+  # and tries to add them
+  var
+    f: File
+  if open(f, "numbers.txt"):
+    try:
+      var a = readLine(f)
+      var b = readLine(f)
+      echo("sum: " & $(parseInt(a) + parseInt(b)))
+    except OverflowError:
+      echo("overflow!")
+    except ValueError:
+      echo("could not convert string to integer")
+    except IOError:
+      echo("IO error!")
+    except:
+      echo("Unknown exception!")
+    finally:
+      close(f)
+
+
+The statements after the ``try`` are executed in sequential order unless
+an exception ``e`` is raised. If the exception type of ``e`` matches any
+listed in an ``except`` clause the corresponding statements are executed.
+The statements following the ``except`` clauses are called
+`exception handlers`:idx:.
+
+The empty `except`:idx: clause is executed if there is an exception that is
+not listed otherwise. It is similar to an ``else`` clause in ``if`` statements.
+
+If there is a `finally`:idx: clause, it is always executed after the
+exception handlers.
+
+The exception is *consumed* in an exception handler. However, an
+exception handler may raise another exception. If the exception is not
+handled, it is propagated through the call stack. This means that often
+the rest of the procedure - that is not within a ``finally`` clause -
+is not executed (if an exception occurs).
+
+
+Try expression
+--------------
+
+Try can also be used as an expression; the type of the ``try`` branch then
+needs to fit the types of ``except`` branches, but the type of the ``finally``
+branch always has to be ``void``:
+
+.. code-block:: nim
+  let x = try: parseInt("133a")
+          except: -1
+          finally: echo "hi"
+
+
+To prevent confusing code there is a parsing limitation; if the ``try``
+follows a ``(`` it has to be written as a one liner:
+
+.. code-block:: nim
+  let x = (try: parseInt("133a") except: -1)
+
+
+Except clauses
+--------------
+
+Within an ``except`` clause, it is possible to use
+``getCurrentException`` to retrieve the exception that has been
+raised:
+
+.. code-block:: nim
+  try:
+    # ...
+  except IOError:
+    let e = getCurrentException()
+    # Now use "e"
+
+Note that ``getCurrentException`` always returns a ``ref Exception``
+type. If a variable of the proper type is needed (in the example
+above, ``IOError``), one must convert it explicitly:
+
+.. code-block:: nim
+  try:
+    # ...
+  except IOError:
+    let e = (ref IOError)(getCurrentException())
+    # "e" is now of the proper type
+
+However, this is seldom needed. The most common case is to extract an
+error message from ``e``, and for such situations it is enough to use
+``getCurrentExceptionMsg``:
+
+.. code-block:: nim
+  try:
+    # ...
+  except IOError:
+    echo "I/O error: " & getCurrentExceptionMsg()
+
+
+Defer statement
+---------------
+
+Instead of a ``try finally`` statement a ``defer`` statement can be used.
+
+Any statements following the ``defer`` in the current block will be considered
+to be in an implicit try block:
+
+.. code-block:: nim
+  var f = open("numbers.txt")
+  defer: close(f)
+  f.write "abc"
+  f.write "def"
+
+Is rewritten to:
+
+.. code-block:: nim
+  var f = open("numbers.txt")
+  try:
+    f.write "abc"
+    f.write "def"
+  finally:
+    close(f)
+
+Top level ``defer`` statements are not supported
+since it's unclear what such a statement should refer to.
+
+
+Raise statement
+---------------
+
+Example:
+
+.. code-block:: nim
+  raise newEOS("operating system failed")
+
+Apart from built-in operations like array indexing, memory allocation, etc.
+the ``raise`` statement is the only way to raise an exception.
+
+.. XXX document this better!
+
+If no exception name is given, the current exception is `re-raised`:idx:. The
+`ReraiseError`:idx: exception is raised if there is no exception to
+re-raise. It follows that the ``raise`` statement *always* raises an
+exception (unless a raise hook has been provided).
+
+
+Exception hierarchy
+-------------------
+
+The exception tree is defined in the `system <system.html>`_ module:
+
+.. include:: exception_hierarchy_fragment.txt
diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt
new file mode 100644
index 000000000..4a4e0316f
--- /dev/null
+++ b/doc/manual/ffi.txt
@@ -0,0 +1,209 @@
+Foreign function interface
+==========================
+
+Nim's `FFI`:idx: (foreign function interface) is extensive and only the
+parts that scale to other future backends (like the LLVM/JavaScript backends)
+are documented here.
+
+
+Importc pragma
+--------------
+The ``importc`` pragma provides a means to import a proc or a variable
+from C. The optional argument is a string containing the C identifier. If
+the argument is missing, the C name is the Nim identifier *exactly as
+spelled*:
+
+.. code-block::
+  proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
+
+Note that this pragma is somewhat of a misnomer: Other backends will provide
+the same feature under the same name. Also, if one is interfacing with C++
+the `ImportCpp pragma <nimc.html#importcpp-pragma>`_ and
+interfacing with Objective-C the `ImportObjC pragma
+<nimc.html#importobjc-pragma>`_ can be used.
+
+
+Exportc pragma
+--------------
+The ``exportc`` pragma provides a means to export a type, a variable, or a
+procedure to C. Enums and constants can't be exported. The optional argument
+is a string containing the C identifier.  If the argument is missing, the C
+name is the Nim identifier *exactly as spelled*:
+
+.. code-block:: Nim
+  proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
+
+Note that this pragma is somewhat of a misnomer: Other backends will provide
+the same feature under the same name.
+
+
+Extern pragma
+-------------
+Like ``exportc`` or ``importc``, the ``extern`` pragma affects name
+mangling. The string literal passed to ``extern`` can be a format string:
+
+.. code-block:: Nim
+  proc p(s: string) {.extern: "prefix$1".} =
+    echo s
+
+In the example the external name of ``p`` is set to ``prefixp``.
+
+
+Bycopy pragma
+-------------
+
+The ``bycopy`` pragma can be applied to an object or tuple type and
+instructs the compiler to pass the type by value to procs:
+
+.. code-block:: nim
+  type
+    Vector {.bycopy, pure.} = object
+      x, y, z: float
+
+
+Byref pragma
+------------
+
+The ``byref`` pragma can be applied to an object or tuple type and instructs
+the compiler to pass the type by reference (hidden pointer) to procs.
+
+
+Varargs pragma
+--------------
+The ``varargs`` pragma can be applied to procedures only (and procedure 
+types). It tells Nim that the proc can take a variable number of parameters 
+after the last specified parameter. Nim string values will be converted to C
+strings automatically:
+
+.. code-block:: Nim
+  proc printf(formatstr: cstring) {.nodecl, varargs.}
+
+  printf("hallo %s", "world") # "world" will be passed as C string
+
+
+Union pragma
+------------
+The ``union`` pragma can be applied to any ``object`` type. It means all
+of the object's fields are overlaid in memory. This produces a ``union``
+instead of a ``struct`` in the generated C/C++ code. The object declaration
+then must not use inheritance or any GC'ed memory but this is currently not
+checked.
+
+**Future directions**: GC'ed memory should be allowed in unions and the GC
+should scan unions conservatively.
+
+Packed pragma
+-------------
+The ``packed`` pragma can be applied to any ``object`` type. It ensures 
+that the fields of an object are packed back-to-back in memory. It is useful 
+to store packets or messages from/to network or hardware drivers, and for 
+interoperability with C. Combining packed pragma with inheritance is not 
+defined, and it should not be used with GC'ed memory (ref's).  
+
+**Future directions**: Using GC'ed memory in packed pragma will result in 
+compile-time error. Usage with inheritance should be defined and documented.
+
+Unchecked pragma
+----------------
+The ``unchecked`` pragma can be used to mark a named array as ``unchecked``
+meaning its bounds are not checked. This is often useful when one wishes to
+implement his own flexibly sized arrays. Additionally an unchecked array is
+translated into a C array of undetermined size:
+
+.. code-block:: nim
+  type
+    ArrayPart{.unchecked.} = array[0..0, int]
+    MySeq = object
+      len, cap: int
+      data: ArrayPart
+
+Produces roughly this C code:
+
+.. code-block:: C
+  typedef struct {
+    NI len;
+    NI cap;
+    NI data[];
+  } MySeq;
+
+The bounds checking done at compile time is not disabled for now, so to access
+``s.data[C]`` (where ``C`` is a constant) the array's index needs needs to
+include ``C``.
+
+The base type of the unchecked array may not contain any GC'ed memory but this
+is currently not checked.
+
+**Future directions**: GC'ed memory should be allowed in unchecked arrays and
+there should be an explicit annotation of how the GC is to determine the
+runtime size of the array.
+
+
+Dynlib pragma for import
+------------------------
+With the ``dynlib`` pragma a procedure or a variable can be imported from
+a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). 
+The non-optional argument has to be the name of the dynamic library:
+
+.. code-block:: Nim
+  proc gtk_image_new(): PGtkWidget
+    {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.}
+
+In general, importing a dynamic library does not require any special linker
+options or linking with import libraries. This also implies that no *devel*
+packages need to be installed.
+
+The ``dynlib`` import mechanism supports a versioning scheme: 
+
+.. code-block:: nim 
+  proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl, 
+    importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".}
+
+At runtime the dynamic library is searched for (in this order)::
+  
+  libtcl.so.1
+  libtcl.so.0
+  libtcl8.5.so.1  
+  libtcl8.5.so.0
+  libtcl8.4.so.1
+  libtcl8.4.so.0
+  libtcl8.3.so.1
+  libtcl8.3.so.0
+
+The ``dynlib`` pragma supports not only constant strings as argument but also
+string expressions in general:
+
+.. code-block:: nim
+  import os
+
+  proc getDllName: string = 
+    result = "mylib.dll"
+    if existsFile(result): return
+    result = "mylib2.dll"
+    if existsFile(result): return
+    quit("could not load dynamic library")
+  
+  proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}
+
+**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant
+strings, because they are precompiled.
+
+**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime 
+because of order of initialization problems.
+
+**Note**: A ``dynlib`` import can be overriden with 
+the ``--dynlibOverride:name`` command line option. The Compiler User Guide
+contains further information.
+
+
+Dynlib pragma for export
+------------------------
+
+With the ``dynlib`` pragma a procedure can also be exported to
+a dynamic library. The pragma then has no argument and has to be used in
+conjunction with the ``exportc`` pragma:
+
+.. code-block:: Nim
+  proc exportme(): int {.cdecl, exportc, dynlib.}
+
+This is only useful if the program is compiled as a dynamic library via the
+``--app:lib`` command line option.
diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt
new file mode 100644
index 000000000..2736f88fb
--- /dev/null
+++ b/doc/manual/generics.txt
@@ -0,0 +1,321 @@
+Generics
+========
+
+Generics are Nim's means to parametrize procs, iterators or types with
+`type parameters`:idx:. Depending on context, the brackets are used either to
+introduce type parameters or to instantiate a generic proc, iterator or type.
+
+The following example shows a generic binary tree can be modelled:
+
+.. code-block:: nim
+  type
+    BinaryTreeObj[T] = object    # BinaryTreeObj is a generic type with
+                                 # with generic param ``T``
+      le, ri: BinaryTree[T]      # left and right subtrees; may be nil
+      data: T                    # the data stored in a node
+    BinaryTree[T] = ref BinaryTreeObj[T] # a shorthand for notational convenience
+
+  proc newNode[T](data: T): BinaryTree[T] = # constructor for a node
+    new(result)
+    result.data = data
+
+  proc add[T](root: var BinaryTree[T], n: BinaryTree[T]) =
+    if root == nil:
+      root = n
+    else:
+      var it = root
+      while it != nil:
+        var c = cmp(it.data, n.data) # compare the data items; uses
+                                     # the generic ``cmp`` proc that works for
+                                     # any type that has a ``==`` and ``<``
+                                     # operator
+        if c < 0:
+          if it.le == nil:
+            it.le = n
+            return
+          it = it.le
+        else:
+          if it.ri == nil:
+            it.ri = n
+            return
+          it = it.ri
+
+  iterator inorder[T](root: BinaryTree[T]): T =
+    # inorder traversal of a binary tree
+    # recursive iterators are not yet implemented, so this does not work in
+    # the current compiler!
+    if root.le != nil: yield inorder(root.le)
+    yield root.data
+    if root.ri != nil: yield inorder(root.ri)
+
+  var
+    root: BinaryTree[string]  # instantiate a BinaryTree with the type string
+  add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and
+  add(root, newNode("world")) # ``add``
+  for str in inorder(root):
+    writeln(stdout, str)
+
+
+Is operator
+-----------
+
+The ``is`` operator checks for type equivalence at compile time. It is
+therefore very useful for type specialization within generic code:
+
+.. code-block:: nim
+  type
+    Table[Key, Value] = object
+      keys: seq[Key]
+      values: seq[Value]
+      when not (Key is string): # nil value for strings used for optimization
+        deletedKeys: seq[bool]
+
+
+Type operator
+-------------
+
+The ``type`` (in many other languages called `typeof`:idx:) operator can
+be used to get the type of an expression:
+
+.. code-block:: nim
+  var x = 0
+  var y: type(x) # y has type int
+
+If ``type`` is used to determine the result type of a proc/iterator/converter
+call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the
+interpretation where ``c`` is an iterator is preferred over the
+other interpretations:
+
+.. code-block:: nim
+  import strutils
+
+  # strutils contains both a ``split`` proc and iterator, but since an
+  # an iterator is the preferred interpretation, `y` has the type ``string``:
+  var y: type("a b c".split)
+
+
+Type Classes
+------------
+
+A type class is a special pseudo-type that can be used to match against
+types in the context of overload resolution or the ``is`` operator.
+Nim supports the following built-in type classes:
+
+==================   ===================================================
+type class           matches
+==================   ===================================================
+``object``           any object type
+``tuple``            any tuple type
+
+``enum``             any enumeration
+``proc``             any proc type
+``ref``              any ``ref`` type
+``ptr``              any ``ptr`` type
+``var``              any ``var`` type
+``distinct``         any distinct type
+``array``            any array type
+``set``              any set type
+``seq``              any seq type
+``auto``             any type
+==================   ===================================================
+
+Furthermore, every generic type automatically creates a type class of the same
+name that will match any instantiation of the generic type.
+
+Type classes can be combined using the standard boolean operators to form
+more complex type classes:
+
+.. code-block:: nim
+  # create a type class that will match all tuple and object types
+  type RecordType = tuple or object
+
+  proc printFields(rec: RecordType) =
+    for key, value in fieldPairs(rec):
+      echo key, " = ", value
+
+Procedures utilizing type classes in such manner are considered to be
+`implicitly generic`:idx:. They will be instantiated once for each unique
+combination of param types used within the program.
+
+Nim also allows for type classes and regular types to be specified
+as `type constraints`:idx: of the generic type parameter:
+
+.. code-block:: nim
+  proc onlyIntOrString[T: int|string](x, y: T) = discard
+
+  onlyIntOrString(450, 616) # valid
+  onlyIntOrString(5.0, 0.0) # type mismatch
+  onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time
+
+By default, during overload resolution each named type class will bind to
+exactly one concrete type. Here is an example taken directly from the system
+module to illustrate this:
+
+.. code-block:: nim
+  proc `==`*(x, y: tuple): bool =
+    ## requires `x` and `y` to be of the same tuple type
+    ## generic ``==`` operator for tuples that is lifted from the components
+    ## of `x` and `y`.
+    result = true
+    for a, b in fields(x, y):
+      if a != b: result = false
+
+Alternatively, the ``distinct`` type modifier can be applied to the type class
+to allow each param matching the type class to bind to a different type.
+
+If a proc param doesn't have a type specified, Nim will use the
+``distinct auto`` type class (also known as ``any``):
+
+.. code-block:: nim
+  # allow any combination of param types
+  proc concat(a, b): string = $a & $b
+
+Procs written with the implicitly generic style will often need to refer to the
+type parameters of the matched generic type. They can be easily accessed using
+the dot syntax:
+
+.. code-block:: nim
+  type Matrix[T, Rows, Columns] = object
+    ...
+
+  proc `[]`(m: Matrix, row, col: int): Matrix.T =
+    m.data[col * high(Matrix.Columns) + row]
+
+Alternatively, the `type` operator can be used over the proc params for similar
+effect when anonymous or distinct type classes are used.
+
+When a generic type is instantiated with a type class instead of a concrete
+type, this results in another more specific type class:
+
+.. code-block:: nim
+  seq[ref object]  # Any sequence storing references to any object type
+
+  type T1 = auto
+  proc foo(s: seq[T1], e: T1)
+    # seq[T1] is the same as just `seq`, but T1 will be allowed to bind
+    # to a single type, while the signature is being matched
+
+  Matrix[Ordinal] # Any Matrix instantiation using integer values
+
+As seen in the previous example, in such instantiations, it's not necessary to
+supply all type parameters of the generic type, because any missing ones will
+be inferred to have the equivalent of the `any` type class and thus they will
+match anything without discrimination.
+
+
+Concepts
+--------
+
+**Note**: Concepts are still in development.
+
+Concepts, also known as "user-defined type classes", are used to specify an
+arbitrary set of requirements that the matched type must satisfy.
+
+Concepts are written in the following form:
+
+.. code-block:: nim
+  type
+    Comparable = concept x, y
+      (x < y) is bool
+
+    Container[T] = concept c
+      c.len is Ordinal
+      items(c) is iterator
+      for value in c:
+        type(value) is T
+
+The concept is a match if:
+
+a) all of the expressions within the body can be compiled for the tested type
+b) all statically evaluatable boolean expressions in the body must be true
+
+The identifiers following the ``concept`` keyword represent instances of the
+currently matched type. These instances can act both as variables of the type,
+when used in contexts where a value is expected, and as the type itself when
+used in contexts where a type is expected.
+
+Please note that the ``is`` operator allows one to easily verify the precise
+type signatures of the required operations, but since type inference and
+default parameters are still applied in the provided block, it's also possible
+to encode usage protocols that do not reveal implementation details.
+
+As a special rule providing further convenience when writing concepts, any
+type value appearing in a callable expression will be treated as a variable of
+the designated type for overload resolution purposes, unless the type value was
+passed in its explicit ``typedesc[T]`` form:
+
+.. code-block:: nim
+  type
+    OutputStream = concept s
+      write(var s, string)
+
+Much like generics, concepts are instantiated exactly
+once for each tested type and any static code included within them is also
+executed once.
+
+
+Symbol lookup in generics
+-------------------------
+
+The symbol binding rules in generics are slightly subtle: There are "open" and
+"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
+context, an "open" symbol can. Per default overloaded symbols are open
+and every other symbol is closed.
+
+Open symbols are looked up in two different contexts: Both the context
+at definition and the context at instantiation are considered:
+
+.. code-block:: nim
+  type
+    Index = distinct int
+
+  proc `==` (a, b: Index): bool {.borrow.}
+
+  var a = (0, 0.Index)
+  var b = (0, 0.Index)
+
+  echo a == b # works!
+
+In the example the generic ``==`` for tuples (as defined in the system module)
+uses the ``==`` operators of the tuple's components. However, the ``==`` for
+the ``Index`` type is defined *after* the ``==`` for tuples; yet the example
+compiles as the instantiation takes the currently defined symbols into account
+too.
+
+A symbol can be forced to be open by a `mixin`:idx: declaration:
+
+.. code-block:: nim
+  proc create*[T](): ref T =
+    # there is no overloaded 'init' here, so we need to state that it's an
+    # open symbol explicitly:
+    mixin init
+    new result
+    init result
+
+
+Bind statement
+--------------
+
+The ``bind`` statement is the counterpart to the ``mixin`` statement. It
+can be used to explicitly declare identifiers that should be bound early (i.e.
+the identifiers should be looked up in the scope of the template/generic
+definition):
+
+.. code-block:: nim
+  # Module A
+  var
+    lastId = 0
+
+  template genId*: expr =
+    bind lastId
+    inc(lastId)
+    lastId
+
+.. code-block:: nim
+  # Module B
+  import A
+
+  echo genId()
+
+But a ``bind`` is rarely useful because symbol binding from the definition
+scope is the default.
diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt
new file mode 100644
index 000000000..ab1cd632d
--- /dev/null
+++ b/doc/manual/lexing.txt
@@ -0,0 +1,375 @@
+Lexical Analysis
+================
+
+Encoding
+--------
+
+All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other
+encodings are not supported. Any of the standard platform line termination
+sequences can be used - the Unix form using ASCII LF (linefeed), the Windows
+form using the ASCII sequence CR LF (return followed by linefeed), or the old
+Macintosh form using the ASCII CR (return) character. All of these forms can be
+used equally, regardless of platform.
+
+
+Indentation
+-----------
+
+Nim's standard grammar describes an `indentation sensitive`:idx: language.
+This means that all the control structures are recognized by indentation.
+Indentation consists only of spaces; tabulators are not allowed.
+
+The indentation handling is implemented as follows: The lexer annotates the
+following token with the preceding number of spaces; indentation is not
+a separate token. This trick allows parsing of Nim with only 1 token of
+lookahead.
+
+The parser uses a stack of indentation levels: the stack consists of integers
+counting the spaces. The indentation information is queried at strategic
+places in the parser but ignored otherwise: The pseudo terminal ``IND{>}``
+denotes an indentation that consists of more spaces than the entry at the top
+of the stack; IND{=} an indentation that has the same number of spaces. ``DED``
+is another pseudo terminal that describes the *action* of popping a value
+from the stack, ``IND{>}`` then implies to push onto the stack.
+
+With this notation we can now easily define the core of the grammar: A block of
+statements (simplified example)::
+
+  ifStmt = 'if' expr ':' stmt
+           (IND{=} 'elif' expr ':' stmt)* 
+           (IND{=} 'else' ':' stmt)?
+
+  simpleStmt = ifStmt / ...
+
+  stmt = IND{>} stmt ^+ IND{=} DED  # list of statements
+       / simpleStmt                 # or a simple statement
+
+
+
+Comments
+--------
+
+Comments start anywhere outside a string or character literal with the
+hash character ``#``.
+Comments consist of a concatenation of `comment pieces`:idx:. A comment piece
+starts with ``#`` and runs until the end of the line. The end of line characters
+belong to the piece. If the next line only consists of a comment piece with
+no other tokens between it and the preceding one, it does not start a new
+comment:
+
+
+.. code-block:: nim
+  i = 0     # This is a single comment over multiple lines.
+    # The scanner merges these two pieces.
+    # The comment continues here.
+
+
+`Documentation comments`:idx: are comments that start with two ``##``.
+Documentation comments are tokens; they are only allowed at certain places in
+the input file as they belong to the syntax tree!
+
+
+Identifiers & Keywords
+----------------------
+
+Identifiers in Nim can be any string of letters, digits
+and underscores, beginning with a letter. Two immediate following
+underscores ``__`` are not allowed::
+
+  letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff'
+  digit ::= '0'..'9'
+  IDENTIFIER ::= letter ( ['_'] (letter | digit) )*
+
+Currently any Unicode character with an ordinal value > 127 (non ASCII) is
+classified as a ``letter`` and may thus be part of an identifier but later
+versions of the language may assign some Unicode characters to belong to the
+operator characters instead.
+
+The following keywords are reserved and cannot be used as identifiers:
+
+.. code-block:: nim
+   :file: keywords.txt
+
+Some keywords are unused; they are reserved for future developments of the
+language.
+
+
+Identifier equality
+-------------------
+
+Two identifiers are considered equal if the following algorithm returns true:
+
+.. code-block:: nim
+  proc sameIdentifier(a, b: string): bool =
+    a[0] == b[0] and a.replace("_", "").toLower == b.replace("_", "").toLower
+
+That means only the first letters are compared in a case sensitive manner. Other
+letters are compared case insensitively and underscores are ignored.
+
+This rather strange way to do identifier comparisons is called
+`partial case insensitivity`:idx: and has some advantages over the conventional
+case sensitivity:
+
+It allows programmers to mostly use their own preferred
+spelling style and libraries written by different programmers cannot use
+incompatible conventions. A Nim-aware editor or IDE can show the identifiers as
+preferred. Another advantage is that it frees the programmer from remembering
+the exact spelling of an identifier. The exception with respect to the first
+letter allows common code like ``var foo: Foo`` to be parsed unambiguously.
+
+Historically, Nim was a `style-insensitive`:idx: language. This means that it
+was not case-sensitive and underscores were ignored and there was no distinction
+between ``foo`` and ``Foo``.
+
+
+String literals
+---------------
+
+Terminal symbol in the grammar: ``STR_LIT``.
+
+String literals can be delimited by matching double quotes, and can
+contain the following `escape sequences`:idx:\ :
+
+==================         ===================================================
+  Escape sequence          Meaning
+==================         ===================================================
+  ``\n``                   `newline`:idx:
+  ``\r``, ``\c``           `carriage return`:idx:
+  ``\l``                   `line feed`:idx:
+  ``\f``                   `form feed`:idx:
+  ``\t``                   `tabulator`:idx:
+  ``\v``                   `vertical tabulator`:idx:
+  ``\\``                   `backslash`:idx:
+  ``\"``                   `quotation mark`:idx:
+  ``\'``                   `apostrophe`:idx:
+  ``\`` '0'..'9'+          `character with decimal value d`:idx:;
+                           all decimal digits directly
+                           following are used for the character
+  ``\a``                   `alert`:idx:
+  ``\b``                   `backspace`:idx:
+  ``\e``                   `escape`:idx: `[ESC]`:idx:
+  ``\x`` HH                `character with hex value HH`:idx:;
+                           exactly two hex digits are allowed
+==================         ===================================================
+
+
+Strings in Nim may contain any 8-bit value, even embedded zeros. However 
+some operations may interpret the first binary zero as a terminator.
+
+
+Triple quoted string literals
+-----------------------------
+
+Terminal symbol in the grammar: ``TRIPLESTR_LIT``.
+
+String literals can also be delimited by three double quotes
+``"""`` ... ``"""``.
+Literals in this form may run for several lines, may contain ``"`` and do not
+interpret any escape sequences.
+For convenience, when the opening ``"""`` is followed by a newline (there may
+be whitespace between the opening ``"""`` and the newline),
+the newline (and the preceding whitespace) is not included in the string. The
+ending of the string literal is defined by the pattern ``"""[^"]``, so this:
+
+.. code-block:: nim 
+  """"long string within quotes""""
+
+Produces::
+
+  "long string within quotes"
+
+
+Raw string literals
+-------------------
+
+Terminal symbol in the grammar: ``RSTR_LIT``.
+
+There are also raw string literals that are preceded with the 
+letter ``r`` (or ``R``) and are delimited by matching double quotes (just 
+like ordinary string literals) and do not interpret the escape sequences. 
+This is especially convenient for regular expressions or Windows paths:
+
+.. code-block:: nim
+
+  var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab
+
+To produce a single ``"`` within a raw string literal, it has to be doubled:
+
+.. code-block:: nim
+
+  r"a""b"
+  
+Produces::
+  
+  a"b
+
+``r""""`` is not possible with this notation, because the three leading 
+quotes introduce a triple quoted string literal. ``r"""`` is the same 
+as ``"""`` since triple quoted string literals do not interpret escape 
+sequences either.
+
+
+Generalized raw string literals
+-------------------------------
+
+Terminal symbols in the grammar: ``GENERALIZED_STR_LIT``, 
+``GENERALIZED_TRIPLESTR_LIT``.
+
+The construct ``identifier"string literal"`` (without whitespace between the
+identifier and the opening quotation mark) is a
+generalized raw string literal. It is a shortcut for the construct
+``identifier(r"string literal")``, so it denotes a procedure call with a
+raw string literal as its only argument. Generalized raw string literals
+are especially convenient for embedding mini languages directly into Nim
+(for example regular expressions).
+
+The construct ``identifier"""string literal"""`` exists too. It is a shortcut
+for ``identifier("""string literal""")``.
+
+
+Character literals
+------------------
+
+Character literals are enclosed in single quotes ``''`` and can contain the
+same escape sequences as strings - with one exception: `newline`:idx: (``\n``)
+is not allowed as it may be wider than one character (often it is the pair
+CR/LF for example).  Here are the valid `escape sequences`:idx: for character
+literals:
+
+==================         ===================================================
+  Escape sequence          Meaning
+==================         ===================================================
+  ``\r``, ``\c``           `carriage return`:idx:
+  ``\l``                   `line feed`:idx:
+  ``\f``                   `form feed`:idx:
+  ``\t``                   `tabulator`:idx:
+  ``\v``                   `vertical tabulator`:idx:
+  ``\\``                   `backslash`:idx:
+  ``\"``                   `quotation mark`:idx:
+  ``\'``                   `apostrophe`:idx:
+  ``\`` '0'..'9'+          `character with decimal value d`:idx:;
+                           all decimal digits directly
+                           following are used for the character
+  ``\a``                   `alert`:idx:
+  ``\b``                   `backspace`:idx:
+  ``\e``                   `escape`:idx: `[ESC]`:idx:
+  ``\x`` HH                `character with hex value HH`:idx:;
+                           exactly two hex digits are allowed
+==================         ===================================================
+
+A character is not an Unicode character but a single byte. The reason for this
+is efficiency: for the overwhelming majority of use-cases, the resulting
+programs will still handle UTF-8 properly as UTF-8 was specially designed for
+this. Another reason is that Nim can thus support ``array[char, int]`` or
+``set[char]`` efficiently as many algorithms rely on this feature.  The `Rune`
+type is used for Unicode characters, it can represent any Unicode character.
+``Rune`` is declared in the `unicode module <unicode.html>`_.
+
+
+Numerical constants
+-------------------
+
+Numerical constants are of a single type and have the form::
+
+  hexdigit = digit | 'A'..'F' | 'a'..'f'
+  octdigit = '0'..'7'
+  bindigit = '0'..'1'
+  HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
+  DEC_LIT = digit ( ['_'] digit )*
+  OCT_LIT = '0o' octdigit ( ['_'] octdigit )*
+  BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
+  
+  INT_LIT = HEX_LIT
+          | DEC_LIT
+          | OCT_LIT
+          | BIN_LIT
+
+  INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8'
+  INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16'
+  INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
+  INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
+
+  UINT_LIT = INT_LIT ['\''] ('u' | 'U')
+  UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
+  UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
+  UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
+  UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64'
+
+  exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
+  FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent)
+  FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32'
+              | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32'
+  FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64'
+              | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64'
+
+
+As can be seen in the productions, numerical constants can contain underscores
+for readability. Integer and floating point literals may be given in decimal (no
+prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal
+(prefix ``0x``) notation.
+
+There exists a literal for each numerical type that is
+defined. The suffix starting with an apostrophe ('\'') is called a
+`type suffix`:idx:. Literals without a type suffix are of the type ``int``,
+unless the literal contains a dot or ``E|e`` in which case it is of
+type ``float``. For notational convenience the apostrophe of a type suffix
+is optional if it is not ambiguous (only hexadecimal floating point literals
+with a type suffix can be ambiguous).
+
+
+The type suffixes are:
+
+=================    =========================
+  Type Suffix        Resulting type of literal
+=================    =========================
+  ``'i8``            int8
+  ``'i16``           int16
+  ``'i32``           int32
+  ``'i64``           int64
+  ``'u``             uint
+  ``'u8``            uint8
+  ``'u16``           uint16
+  ``'u32``           uint32
+  ``'u64``           uint64
+  ``'f32``           float32
+  ``'f64``           float64
+=================    =========================
+
+Floating point literals may also be in binary, octal or hexadecimal
+notation:
+``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64``
+is approximately 1.72826e35 according to the IEEE floating point standard.
+
+
+Operators
+---------
+
+In Nim one can define his own operators. An operator is any
+combination of the following characters::
+
+       =     +     -     *     /     <     >
+       @     $     ~     &     %     |
+       !     ?     ^     .     :     \
+
+These keywords are also operators:
+``and or not xor shl shr div mod in notin is isnot of``.
+
+`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they
+are used for other notational purposes. 
+
+``*:`` is as a special case the two tokens `*`:tok: and `:`:tok:
+(to support ``var v*: T``).
+
+
+Other tokens
+------------
+
+The following strings denote other tokens::
+
+    `   (     )     {     }     [     ]     ,  ;   [.    .]  {.   .}  (.  .)
+
+
+The `slice`:idx: operator `..`:tok: takes precedence over other tokens that 
+contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: 
+and not the two tokens `{.`:tok:, `.}`:tok:.
+
diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt
new file mode 100644
index 000000000..864eeccb5
--- /dev/null
+++ b/doc/manual/locking.txt
@@ -0,0 +1,200 @@
+Guards and locks
+================
+
+Apart from ``spawn`` and ``parallel`` Nim also provides all the common low level
+concurrency mechanisms like locks, atomic intristics or condition variables.
+
+Nim significantly improves on the safety of these features via additional
+pragmas:
+
+1) A `guard`:idx: annotation is introduced to prevent data races.
+2) Every access of a guarded memory location needs to happen in an
+   appropriate `locks`:idx: statement.
+3) Locks and routines can be annotated with `lock levels`:idx: to prevent
+   deadlocks at compile time.
+
+
+Guards and the locks section
+----------------------------
+
+Protecting global variables
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Object fields and global variables can be annotated via a ``guard`` pragma:
+
+.. code-block:: nim
+  var glock: TLock
+  var gdata {.guard: glock.}: int
+
+The compiler then ensures that every access of ``gdata`` is within a ``locks``
+section:
+
+.. code-block:: nim
+  proc invalid =
+    # invalid: unguarded access:
+    echo gdata
+
+  proc valid =
+    # valid access:
+    {.locks: [glock].}:
+      echo gdata
+
+Top level accesses to ``gdata`` are always allowed so that it can be initialized
+conveniently. It is *assumed* (but not enforced) that every top level statement
+is executed before any concurrent action happens.
+
+The ``locks`` section deliberately looks ugly because it has no runtime
+semantics and should not be used directly! It should only be used in templates
+that also implement some form of locking at runtime:
+
+.. code-block:: nim
+  template lock(a: TLock; body: stmt) =
+    pthread_mutex_lock(a)
+    {.locks: [a].}:
+      try:
+        body
+      finally:
+        pthread_mutex_unlock(a)
+
+
+The guard does not need to be of any particular type. It is flexible enough to
+model low level lockfree mechanisms:
+
+.. code-block:: nim
+  var dummyLock {.compileTime.}: int
+  var atomicCounter {.guard: dummyLock.}: int
+  
+  template atomicRead(x): expr =
+    {.locks: [dummyLock].}:
+      memoryReadBarrier()
+      x
+
+  echo atomicRead(atomicCounter)
+
+
+The ``locks`` pragma takes a list of lock expressions ``locks: [a, b, ...]``
+in order to support *multi lock* statements. Why these are essential is
+explained in the `lock levels`_ section.
+
+
+Protecting general locations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``guard`` annotation can also be used to protect fields within an object.
+The guard then needs to be another field within the same object or a
+global variable.
+
+Since objects can reside on the heap or on the stack this greatly enhances the
+expressivity of the language:
+
+.. code-block:: nim
+  type
+    ProtectedCounter = object
+      v {.guard: L.}: int
+      L: TLock
+
+  proc incCounters(counters: var openArray[ProtectedCounter]) =
+    for i in 0..counters.high:
+      lock counters[i].L:
+        inc counters[i].v
+
+The access to field ``x.v`` is allowed since its guard ``x.L``  is active.
+After template expansion, this amounts to:
+
+.. code-block:: nim
+  proc incCounters(counters: var openArray[ProtectedCounter]) =
+    for i in 0..counters.high:
+      pthread_mutex_lock(counters[i].L)
+      {.locks: [counters[i].L].}:
+        try:
+          inc counters[i].v
+        finally:
+          pthread_mutex_unlock(counters[i].L)
+
+There is an analysis that checks that ``counters[i].L`` is the lock that
+corresponds to the protected location ``counters[i].v``. This analysis is called
+`path analysis`:idx: because it deals with paths to locations
+like ``obj.field[i].fieldB[j]``.
+
+The path analysis is **currently unsound**, but that doesn't make it useless.
+Two paths are considered equivalent if they are syntactically the same.
+
+This means the following compiles (for now) even though it really should not:
+
+.. code-block:: nim
+  {.locks: [a[i].L].}:
+    inc i
+    access a[i].v
+
+
+
+Lock levels
+-----------
+
+Lock levels are used to enforce a global locking order in order to prevent
+deadlocks at compile-time. A lock level is an constant integer in the range
+0..1_000. Lock level 0 means that no lock is acquired at all.
+
+If a section of code holds a lock of level ``M`` than it can also acquire any 
+lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks
+of the same level can only be acquired *at the same time* within a 
+single ``locks`` section:
+
+.. code-block:: nim
+  var a, b: TLock[2]
+  var x: TLock[1]
+  # invalid locking order: TLock[1] cannot be acquired before TLock[2]:
+  {.locks: [x].}: 
+    {.locks: [a].}:
+      ...
+  # valid locking order: TLock[2] acquired before TLock[1]:
+  {.locks: [a].}: 
+    {.locks: [x].}:
+      ...
+
+  # invalid locking order: TLock[2] acquired before TLock[2]:
+  {.locks: [a].}: 
+    {.locks: [b].}:
+      ...
+
+  # valid locking order, locks of the same level acquired at the same time:
+  {.locks: [a, b].}: 
+    ...
+
+
+Here is how a typical multilock statement can be implemented in Nim. Note how
+the runtime check is required to ensure a global ordering for two locks ``a``
+and ``b`` of the same lock level:
+
+.. code-block:: nim
+  template multilock(a, b: ptr TLock; body: stmt) =
+    if cast[ByteAddress](a) < cast[ByteAddress](b):
+      pthread_mutex_lock(a)
+      pthread_mutex_lock(b)
+    else:
+      pthread_mutex_lock(b)
+      pthread_mutex_lock(a)
+    {.locks: [a, b].}:
+      try:
+        body
+      finally:
+        pthread_mutex_unlock(a)
+        pthread_mutex_unlock(b)
+
+
+Whole routines can also be annotated with a ``locks`` pragma that takes a lock
+level. This then means that the routine may acquire locks of up to this level.
+This is essential so that procs can be called within a ``locks`` section:
+
+.. code-block:: nim
+  proc p() {.locks: 3.} = discard 
+
+  var a: TLock[4]
+  {.locks: [a].}:
+    # p's locklevel (3) is strictly less than a's (4) so the call is allowed:
+    p()
+
+
+As usual ``locks`` is an inferred effect and there is a subtype 
+relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}``
+iff (M <= N).
diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt
new file mode 100644
index 000000000..fe3360773
--- /dev/null
+++ b/doc/manual/modules.txt
@@ -0,0 +1,202 @@
+Modules
+=======
+Nim supports splitting a program into pieces by a module concept.
+Each module needs to be in its own file and has its own `namespace`:idx:.
+Modules enable `information hiding`:idx: and `separate compilation`:idx:.
+A module may gain access to symbols of another module by the `import`:idx:
+statement. `Recursive module dependencies`:idx: are allowed, but slightly
+subtle. Only top-level symbols that are marked with an asterisk (``*``) are
+exported. A valid module name can only be a valid Nim identifier (and thus its
+filename is ``identifier.nim``).
+
+The algorithm for compiling modules is:
+
+- compile the whole module as usual, following import statements recursively
+
+- if there is a cycle only import the already parsed symbols (that are
+  exported); if an unknown identifier occurs then abort
+
+This is best illustrated by an example:
+
+.. code-block:: nim
+  # Module A
+  type
+    T1* = int  # Module A exports the type ``T1``
+  import B     # the compiler starts parsing B
+
+  proc main() =
+    var i = p(3) # works because B has been parsed completely here
+
+  main()
+
+
+.. code-block:: nim
+  # Module B
+  import A  # A is not parsed here! Only the already known symbols
+            # of A are imported.
+
+  proc p*(x: A.T1): A.T1 =
+    # this works because the compiler has already
+    # added T1 to A's interface symbol table
+    result = x + 1
+
+
+Import statement
+~~~~~~~~~~~~~~~~
+
+After the ``import`` statement a list of module names can follow or a single
+module name followed by an ``except`` list to prevent some symbols to be
+imported:
+
+.. code-block:: nim
+  import strutils except `%`, toUpper
+
+  # doesn't work then:
+  echo "$1" % "abc".toUpper
+
+
+It is not checked that the ``except`` list is really exported from the module.
+This feature allows to compile against an older version of the module that
+does not export these identifiers.
+
+
+Include statement
+~~~~~~~~~~~~~~~~~
+The ``include`` statement does something fundamentally different than
+importing a module: it merely includes the contents of a file. The ``include``
+statement is useful to split up a large module into several files:
+
+.. code-block:: nim
+  include fileA, fileB, fileC
+
+
+
+Module names in imports
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A module alias can be introduced via the ``as`` keyword:
+
+.. code-block:: nim
+  import strutils as su, sequtils as qu
+
+  echo su.format("$1", "lalelu")
+
+The original module name is then not accessible. The 
+notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` 
+can be used to refer to a module in subdirectories:
+
+.. code-block:: nim
+  import lib.pure.strutils, lib/pure/os, "lib/pure/times"
+
+Note that the module name is still ``strutils`` and not ``lib.pure.strutils``
+and so one **cannot** do:
+
+.. code-block:: nim
+  import lib.pure.strutils
+  echo lib.pure.strutils
+
+Likewise the following does not make sense as the name is ``strutils`` already:
+
+.. code-block:: nim
+  import lib.pure.strutils as strutils
+
+
+From import statement
+~~~~~~~~~~~~~~~~~~~~~
+
+After the ``from`` statement a module name follows followed by 
+an ``import`` to list the symbols one likes to use without explict
+full qualification:
+
+.. code-block:: nim
+  from strutils import `%`
+
+  echo "$1" % "abc"
+  # always possible: full qualification:
+  echo strutils.replace("abc", "a", "z")
+
+It's also possible to use ``from module import nil`` if one wants to import 
+the module but wants to enforce fully qualified access to every symbol 
+in ``module``.
+
+
+Export statement
+~~~~~~~~~~~~~~~~
+
+An ``export`` statement can be used for symbol fowarding so that client
+modules don't need to import a module's dependencies:
+
+.. code-block:: nim
+  # module B
+  type MyObject* = object
+
+.. code-block:: nim
+  # module A
+  import B
+  export B.MyObject
+  
+  proc `$`*(x: MyObject): string = "my object"
+
+
+.. code-block:: nim
+  # module C
+  import A
+  
+  # B.MyObject has been imported implicitly here: 
+  var x: MyObject
+  echo($x)
+
+
+Scope rules
+-----------
+Identifiers are valid from the point of their declaration until the end of
+the block in which the declaration occurred. The range where the identifier
+is known is the scope of the identifier. The exact scope of an
+identifier depends on the way it was declared.
+
+Block scope
+~~~~~~~~~~~
+The *scope* of a variable declared in the declaration part of a block
+is valid from the point of declaration until the end of the block. If a
+block contains a second block, in which the identifier is redeclared,
+then inside this block, the second declaration will be valid. Upon
+leaving the inner block, the first declaration is valid again. An
+identifier cannot be redefined in the same block, except if valid for
+procedure or iterator overloading purposes.
+
+
+Tuple or object scope
+~~~~~~~~~~~~~~~~~~~~~
+The field identifiers inside a tuple or object definition are valid in the
+following places:
+
+* To the end of the tuple/object definition.
+* Field designators of a variable of the given tuple/object type.
+* In all descendant types of the object type.
+
+Module scope
+~~~~~~~~~~~~
+All identifiers of a module are valid from the point of declaration until
+the end of the module. Identifiers from indirectly dependent modules are *not* 
+available. The `system`:idx: module is automatically imported in every module.
+
+If a module imports an identifier by two different modules, each occurrence of
+the identifier has to be qualified, unless it is an overloaded procedure or
+iterator in which case the overloading resolution takes place:
+
+.. code-block:: nim
+  # Module A
+  var x*: string
+
+.. code-block:: nim
+  # Module B
+  var x*: int
+
+.. code-block:: nim
+  # Module C
+  import A, B
+  write(stdout, x) # error: x is ambiguous
+  write(stdout, A.x) # no error: qualifier used
+
+  var x = 4
+  write(stdout, x) # not ambiguous: uses the module C's x
diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt
new file mode 100644
index 000000000..51125f576
--- /dev/null
+++ b/doc/manual/pragmas.txt
@@ -0,0 +1,513 @@
+Pragmas
+=======
+
+Pragmas are Nim's method to give the compiler additional information /
+commands without introducing a massive number of new keywords. Pragmas are
+processed on the fly during semantic checking. Pragmas are enclosed in the
+special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a
+first implementation to play with a language feature before a nicer syntax
+to access the feature becomes available.
+
+
+deprecated pragma
+-----------------
+
+The deprecated pragma is used to mark a symbol as deprecated:
+
+.. code-block:: nim
+  proc p() {.deprecated.}
+  var x {.deprecated.}: char
+
+It can also be used as a statement, in that case it takes a list of *renamings*.
+
+.. code-block:: nim
+  type
+    File = object
+    Stream = ref object
+  {.deprecated: [TFile: File, PStream: Stream].}
+
+The ``nimfix`` tool can be used to, without effort, automatically update your
+code and refactor it by performing these renamings.
+
+
+noSideEffect pragma
+-------------------
+The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
+effects. This means that the proc/iterator only changes locations that are
+reachable from its parameters and the return value only depends on the
+arguments. If none of its parameters have the type ``var T``
+or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
+error to mark a proc/iterator to have no side effect if the compiler cannot
+verify this.
+
+As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_
+pretends to be free of side effects, so that it can be used for debugging
+routines marked as ``noSideEffect``.
+
+**Future directions**: ``func`` may become a keyword and syntactic sugar for a
+proc with no side effects:
+
+.. code-block:: nim
+  func `+` (x, y: int): int
+
+
+destructor pragma
+-----------------
+
+The ``destructor`` pragma is used to mark a proc to act as a type destructor.
+Its usage is deprecated, See `type bound operations`_ instead.
+
+override pragma
+---------------
+
+See `type bound operations`_ instead.
+
+procvar pragma
+--------------
+The ``procvar`` pragma is used to mark a proc that it can be passed to a
+procedural variable.
+
+
+compileTime pragma
+------------------
+The ``compileTime`` pragma is used to mark a proc or variable to be used at
+compile time only. No code will be generated for it. Compile time procs are
+useful as helpers for macros.
+
+noReturn pragma
+---------------
+The ``noreturn`` pragma is used to mark a proc that never returns.
+
+
+acyclic pragma
+--------------
+The ``acyclic`` pragma can be used for object types to mark them as acyclic
+even though they seem to be cyclic. This is an **optimization** for the garbage
+collector to not consider objects of this type as part of a cycle:
+
+.. code-block:: nim
+  type
+    Node = ref NodeObj
+    NodeObj {.acyclic, final.} = object
+      left, right: Node
+      data: string
+
+In the example a tree structure is declared with the ``Node`` type. Note that
+the type definition is recursive and the GC has to assume that objects of
+this type may form a cyclic graph. The ``acyclic`` pragma passes the
+information that this cannot happen to the GC. If the programmer uses the
+``acyclic`` pragma for data types that are in reality cyclic, the GC may leak
+memory, but nothing worse happens.
+
+**Future directions**: The ``acyclic`` pragma may become a property of a
+``ref`` type:
+
+.. code-block:: nim
+  type
+    Node = acyclic ref NodeObj
+    NodeObj = object
+      left, right: Node
+      data: string
+
+
+final pragma
+------------
+The ``final`` pragma can be used for an object type to specify that it
+cannot be inherited from.
+
+
+shallow pragma
+--------------
+The ``shallow`` pragma affects the semantics of a type: The compiler is
+allowed to make a shallow copy. This can cause serious semantic issues and
+break memory safety! However, it can speed up assignments considerably,
+because the semantics of Nim require deep copying of sequences and strings.
+This can be expensive, especially if sequences are used to build a tree
+structure:
+
+.. code-block:: nim
+  type
+    NodeKind = enum nkLeaf, nkInner
+    Node {.final, shallow.} = object
+      case kind: NodeKind
+      of nkLeaf:
+        strVal: string
+      of nkInner:
+        children: seq[Node]
+
+
+pure pragma
+-----------
+An object type can be marked with the ``pure`` pragma so that its type
+field which is used for runtime type identification is omitted. This used to be
+necessary for binary compatibility with other compiled languages.
+
+An enum type can be marked as ``pure``. Then access of its fields always
+requires full qualification.
+
+
+asmNoStackFrame pragma
+----------------------
+A proc can be marked with the ``AsmNoStackFrame`` pragma to tell the compiler
+it should not generate a stack frame for the proc. There are also no exit
+statements like ``return result;`` generated and the generated C function is
+declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on
+the used C compiler).
+
+**Note**: This pragma should only be used by procs which consist solely of
+assembler statements.
+
+error pragma
+------------
+The ``error`` pragma is used to make the compiler output an error message
+with the given content. Compilation does not necessarily abort after an error
+though.
+
+The ``error`` pragma can also be used to
+annotate a symbol (like an iterator or proc). The *usage* of the symbol then
+triggers a compile-time error. This is especially useful to rule out that some
+operation is valid due to overloading and type conversions:
+
+.. code-block:: nim
+  ## check that underlying int values are compared and not the pointers:
+  proc `==`(x, y: ptr int): bool {.error.}
+
+
+fatal pragma
+------------
+The ``fatal`` pragma is used to make the compiler output an error message
+with the given content. In contrast to the ``error`` pragma, compilation
+is guaranteed to be aborted by this pragma. Example:
+
+.. code-block:: nim
+  when not defined(objc):
+    {.fatal: "Compile this program with the objc command!".}
+
+warning pragma
+--------------
+The ``warning`` pragma is used to make the compiler output a warning message
+with the given content. Compilation continues after the warning.
+
+hint pragma
+-----------
+The ``hint`` pragma is used to make the compiler output a hint message with
+the given content. Compilation continues after the hint.
+
+line pragma
+-----------
+The ``line`` pragma can be used to affect line information of the annotated
+statement as seen in stack backtraces:
+
+.. code-block:: nim
+
+  template myassert*(cond: expr, msg = "") =
+    if not cond:
+      # change run-time line information of the 'raise' statement:
+      {.line: InstantiationInfo().}:
+        raise newException(EAssertionFailed, msg)
+
+If the ``line`` pragma is used with a parameter, the parameter needs be a
+``tuple[filename: string, line: int]``. If it is used without a parameter,
+``system.InstantiationInfo()`` is used.
+
+
+linearScanEnd pragma
+--------------------
+The ``linearScanEnd`` pragma can be used to tell the compiler how to
+compile a Nim `case`:idx: statement. Syntactically it has to be used as a
+statement:
+
+.. code-block:: nim
+  case myInt
+  of 0:
+    echo "most common case"
+  of 1:
+    {.linearScanEnd.}
+    echo "second most common case"
+  of 2: echo "unlikely: use branch table"
+  else: echo "unlikely too: use branch table for ", myInt
+
+In the example, the case branches ``0`` and ``1`` are much more common than
+the other cases. Therefore the generated assembler code should test for these
+values first, so that the CPU's branch predictor has a good chance to succeed
+(avoiding an expensive CPU pipeline stall). The other cases might be put into a
+jump table for O(1) overhead, but at the cost of a (very likely) pipeline
+stall.
+
+The ``linearScanEnd`` pragma should be put into the last branch that should be
+tested against via linear scanning. If put into the last branch of the
+whole ``case`` statement, the whole ``case`` statement uses linear scanning.
+
+
+computedGoto pragma
+-------------------
+The ``computedGoto`` pragma can be used to tell the compiler how to
+compile a Nim `case`:idx: in a ``while true`` statement.
+Syntactically it has to be used as a statement inside the loop:
+
+.. code-block:: nim
+
+  type
+    MyEnum = enum
+      enumA, enumB, enumC, enumD, enumE
+
+  proc vm() =
+    var instructions: array [0..100, MyEnum]
+    instructions[2] = enumC
+    instructions[3] = enumD
+    instructions[4] = enumA
+    instructions[5] = enumD
+    instructions[6] = enumC
+    instructions[7] = enumA
+    instructions[8] = enumB
+
+    instructions[12] = enumE
+    var pc = 0
+    while true:
+      {.computedGoto.}
+      let instr = instructions[pc]
+      case instr
+      of enumA:
+        echo "yeah A"
+      of enumC, enumD:
+        echo "yeah CD"
+      of enumB:
+        echo "yeah B"
+      of enumE:
+        break
+      inc(pc)
+
+  vm()
+
+As the example shows ``computedGoto`` is mostly useful for interpreters. If
+the underlying backend (C compiler) does not support the computed goto
+extension the pragma is simply ignored.
+
+
+unroll pragma
+-------------
+The ``unroll`` pragma can be used to tell the compiler that it should unroll
+a `for`:idx: or `while`:idx: loop for runtime efficiency:
+
+.. code-block:: nim
+  proc searchChar(s: string, c: char): int =
+    for i in 0 .. s.high:
+      {.unroll: 4.}
+      if s[i] == c: return i
+    result = -1
+
+In the above example, the search loop is unrolled by a factor 4. The unroll
+factor can be left out too; the compiler then chooses an appropriate unroll
+factor.
+
+**Note**: Currently the compiler recognizes but ignores this pragma.
+
+
+immediate pragma
+----------------
+
+See `Ordinary vs immediate templates`_.
+
+
+compilation option pragmas
+--------------------------
+The listed pragmas here can be used to override the code generation options
+for a proc/method/converter.
+
+The implementation currently provides the following possible options (various
+others may be added later).
+
+===============  ===============  ============================================
+pragma           allowed values   description
+===============  ===============  ============================================
+checks           on|off           Turns the code generation for all runtime
+                                  checks on or off.
+boundChecks      on|off           Turns the code generation for array bound
+                                  checks on or off.
+overflowChecks   on|off           Turns the code generation for over- or
+                                  underflow checks on or off.
+nilChecks        on|off           Turns the code generation for nil pointer
+                                  checks on or off.
+assertions       on|off           Turns the code generation for assertions
+                                  on or off.
+warnings         on|off           Turns the warning messages of the compiler
+                                  on or off.
+hints            on|off           Turns the hint messages of the compiler
+                                  on or off.
+optimization     none|speed|size  Optimize the code for speed or size, or
+                                  disable optimization.
+patterns         on|off           Turns the term rewriting templates/macros
+                                  on or off.
+callconv         cdecl|...        Specifies the default calling convention for
+                                  all procedures (and procedure types) that
+                                  follow.
+===============  ===============  ============================================
+
+Example:
+
+.. code-block:: nim
+  {.checks: off, optimization: speed.}
+  # compile without runtime checks and optimize for speed
+
+
+push and pop pragmas
+--------------------
+The `push/pop`:idx: pragmas are very similar to the option directive,
+but are used to override the settings temporarily. Example:
+
+.. code-block:: nim
+  {.push checks: off.}
+  # compile this section without runtime checks as it is
+  # speed critical
+  # ... some code ...
+  {.pop.} # restore old settings
+
+
+register pragma
+---------------
+The ``register`` pragma is for variables only. It declares the variable as
+``register``, giving the compiler a hint that the variable should be placed
+in a hardware register for faster access. C compilers usually ignore this
+though and for good reasons: Often they do a better job without it anyway.
+
+In highly specific cases (a dispatch loop of a bytecode interpreter for
+example) it may provide benefits, though.
+
+
+global pragma
+-------------
+The ``global`` pragma can be applied to a variable within a proc to instruct
+the compiler to store it in a global location and initialize it once at program
+startup.
+
+.. code-block:: nim
+  proc isHexNumber(s: string): bool =
+    var pattern {.global.} = re"[0-9a-fA-F]+"
+    result = s.match(pattern)
+
+When used within a generic proc, a separate unique global variable will be
+created for each instantiation of the proc. The order of initialization of
+the created global variables within a module is not defined, but all of them
+will be initialized after any top-level variables in their originating module
+and before any variable in a module that imports it.
+
+deadCodeElim pragma
+-------------------
+The ``deadCodeElim`` pragma only applies to whole modules: It tells the
+compiler to activate (or deactivate) dead code elimination for the module the
+pragma appears in.
+
+The ``--deadCodeElim:on`` command line switch has the same effect as marking
+every module with ``{.deadCodeElim:on}``. However, for some modules such as
+the GTK wrapper it makes sense to *always* turn on dead code elimination -
+no matter if it is globally active or not.
+
+Example:
+
+.. code-block:: nim
+  {.deadCodeElim: on.}
+
+
+..
+  NoForward pragma
+  ----------------
+  The ``noforward`` pragma can be used to turn on and off a special compilation
+  mode that to large extent eliminates the need for forward declarations. In this
+  mode, the proc definitions may appear out of order and the compiler will postpone
+  their semantic analysis and compilation until it actually needs to generate code
+  using the definitions. In this regard, this mode is similar to the modus operandi
+  of dynamic scripting languages, where the function calls are not resolved until
+  the code is executed. Here is the detailed algorithm taken by the compiler:
+
+  1. When a callable symbol is first encountered, the compiler will only note the
+  symbol callable name and it will add it to the appropriate overload set in the
+  current scope. At this step, it won't try to resolve any of the type expressions
+  used in the signature of the symbol (so they can refer to other not yet defined
+  symbols).
+
+  2. When a top level call is encountered (usually at the very end of the module),
+  the compiler will try to determine the actual types of all of the symbols in the
+  matching overload set. This is a potentially recursive process as the signatures
+  of the symbols may include other call expressions, whose types will be resolved
+  at this point too.
+
+  3. Finally, after the best overload is picked, the compiler will start
+  compiling the body of the respective symbol. This in turn will lead the
+  compiler to discover more call expressions that need to be resolved and steps
+  2 and 3 will be repeated as necessary.
+
+  Please note that if a callable symbol is never used in this scenario, its body
+  will never be compiled. This is the default behavior leading to best compilation
+  times, but if exhaustive compilation of all definitions is required, using
+  ``nim check`` provides this option as well.
+
+  Example:
+
+  .. code-block:: nim
+
+    {.noforward: on.}
+
+    proc foo(x: int) =
+      bar x
+
+    proc bar(x: int) =
+      echo x
+
+    foo(10)
+
+
+pragma pragma
+-------------
+
+The ``pragma`` pragma can be used to declare user defined pragmas. This is
+useful because Nim's templates and macros do not affect pragmas. User
+defined pragmas are in a different module-wide scope than all other symbols.
+They cannot be imported from a module.
+
+Example:
+
+.. code-block:: nim
+  when appType == "lib":
+    {.pragma: rtl, exportc, dynlib, cdecl.}
+  else:
+    {.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
+
+  proc p*(a, b: int): int {.rtl.} =
+    result = a+b
+
+In the example a new pragma named ``rtl`` is introduced that either imports
+a symbol from a dynamic library or exports the symbol for dynamic library
+generation.
+
+
+Disabling certain messages
+--------------------------
+Nim generates some warnings and hints ("line too long") that may annoy the
+user. A mechanism for disabling certain messages is provided: Each hint
+and warning message contains a symbol in brackets. This is the message's
+identifier that can be used to enable or disable it:
+
+.. code-block:: Nim
+  {.hint[LineTooLong]: off.} # turn off the hint about too long lines
+
+This is often better than disabling all warnings at once.
+
+
+experimental pragma
+-------------------
+
+The ``experimental`` pragma enables experimental language features. Depending
+on the concrete feature this means that the feature is either considered
+too unstable for an otherwise stable release or that the future of the feature
+is uncertain (it may be removed any time).
+
+Example:
+
+.. code-block:: nim
+  {.experimental.}
+
+  proc useUsing(dest: var string) =
+    using dest
+    add "foo"
+    add "bar"
+
diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt
new file mode 100644
index 000000000..38e343686
--- /dev/null
+++ b/doc/manual/procs.txt
@@ -0,0 +1,667 @@
+Procedures
+==========
+
+What most programming languages call `methods`:idx: or `functions`:idx: are
+called `procedures`:idx: in Nim (which is the correct terminology). A procedure
+declaration consists of an identifier, zero or more formal parameters, a return
+value type and a block of code. Formal parameters are declared as a list of
+identifiers separated by either comma or semicolon. A parameter is given a type
+by ``: typename``. The type applies to all parameters immediately before it,
+until either the beginning of the parameter list, a semicolon separator or an
+already typed parameter, is reached. The semicolon can be used to make
+separation of types and subsequent identifiers more distinct.
+
+.. code-block:: nim
+  # Using only commas
+  proc foo(a, b: int, c, d: bool): int
+
+  # Using semicolon for visual distinction
+  proc foo(a, b: int; c, d: bool): int
+
+  # Will fail: a is untyped since ';' stops type propagation.
+  proc foo(a; b: int; c, d: bool): int
+
+A parameter may be declared with a default value which is used if the caller
+does not provide a value for the argument.
+
+.. code-block:: nim
+  # b is optional with 47 as its default value
+  proc foo(a: int, b: int = 47): int
+
+Parameters can be declared mutable and so allow the proc to modify those
+arguments, by using the type modifier `var`.
+
+.. code-block:: nim
+  # "returning" a value to the caller through the 2nd argument
+  # Notice that the function uses no actual return value at all (ie void)
+  proc foo(inp: int, outp: var int) =
+    outp = inp + 47
+
+If the proc declaration has no body, it is a `forward`:idx: declaration. If the
+proc returns a value, the procedure body can access an implicitly declared
+variable named `result`:idx: that represents the return value. Procs can be
+overloaded. The overloading resolution algorithm determines which proc is the
+best match for the arguments. Example:
+
+.. code-block:: nim
+
+  proc toLower(c: char): char = # toLower for characters
+    if c in {'A'..'Z'}:
+      result = chr(ord(c) + (ord('a') - ord('A')))
+    else:
+      result = c
+
+  proc toLower(s: string): string = # toLower for strings
+    result = newString(len(s))
+    for i in 0..len(s) - 1:
+      result[i] = toLower(s[i]) # calls toLower for characters; no recursion!
+
+Calling a procedure can be done in many different ways:
+
+.. code-block:: nim
+  proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ...
+
+  # call with positional arguments # parameter bindings:
+  callme(0, 1, "abc", '\t', true)  # (x=0, y=1, s="abc", c='\t', b=true)
+  # call with named and positional arguments:
+  callme(y=1, x=0, "abd", '\t')    # (x=0, y=1, s="abd", c='\t', b=false)
+  # call with named arguments (order is not relevant):
+  callme(c='\t', y=1, x=0)         # (x=0, y=1, s="", c='\t', b=false)
+  # call as a command statement: no () needed:
+  callme 0, 1, "abc", '\t'
+
+A procedure may call itself recursively.
+
+
+`Operators`:idx: are procedures with a special operator symbol as identifier:
+
+.. code-block:: nim
+  proc `$` (x: int): string =
+    # converts an integer to a string; this is a prefix operator.
+    result = intToStr(x)
+
+Operators with one parameter are prefix operators, operators with two
+parameters are infix operators. (However, the parser distinguishes these from
+the operator's position within an expression.) There is no way to declare
+postfix operators: all postfix operators are built-in and handled by the
+grammar explicitly.
+
+Any operator can be called like an ordinary proc with the '`opr`'
+notation. (Thus an operator can have more than two parameters):
+
+.. code-block:: nim
+  proc `*+` (a, b, c: int): int =
+    # Multiply and add
+    result = a * b + c
+
+  assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
+
+
+Export marker
+-------------
+
+If a declared symbol is marked with an `asterisk`:idx: it is exported from the
+current module:
+
+.. code-block:: nim
+
+  proc exportedEcho*(s: string) = echo s
+  proc `*`*(a: string; b: int): string =
+    result = newStringOfCap(a.len * b)
+    for i in 1..b: result.add a
+
+  var exportedVar*: int
+  const exportedConst* = 78
+  type
+    ExportedType* = object
+      exportedField*: int
+
+
+Method call syntax
+------------------
+
+For object oriented programming, the syntax ``obj.method(args)`` can be used 
+instead of ``method(obj, args)``. The parentheses can be omitted if there are no
+remaining arguments: ``obj.len`` (instead of ``len(obj)``).
+
+This method call syntax is not restricted to objects, it can be used
+to supply any type of first argument for procedures:
+
+.. code-block:: nim
+  
+  echo("abc".len) # is the same as echo(len("abc"))
+  echo("abc".toUpper())
+  echo({'a', 'b', 'c'}.card)
+  stdout.writeln("Hallo") # the same as writeln(stdout, "Hallo")
+
+Another way to look at the method call syntax is that it provides the missing
+postfix notation.
+
+See also: `Limitations of the method call syntax`_.
+
+
+Properties
+----------
+Nim has no need for *get-properties*: Ordinary get-procedures that are called
+with the *method call syntax* achieve the same. But setting a value is 
+different; for this a special setter syntax is needed:
+
+.. code-block:: nim
+  
+  type
+    Socket* = ref object of RootObj
+      FHost: int # cannot be accessed from the outside of the module
+                 # the `F` prefix is a convention to avoid clashes since
+                 # the accessors are named `host`
+
+  proc `host=`*(s: var Socket, value: int) {.inline.} =
+    ## setter of hostAddr
+    s.FHost = value
+  
+  proc host*(s: Socket): int {.inline.} =
+    ## getter of hostAddr
+    s.FHost
+
+  var s: Socket
+  new s
+  s.host = 34  # same as `host=`(s, 34)
+
+
+Command invocation syntax
+-------------------------
+
+Routines can be invoked without the ``()`` if the call is syntatically
+a statement. This command invocation syntax also works for
+expressions, but then only a single argument may follow. This restriction
+means ``echo f 1, f 2`` is parsed as ``echo(f(1), f(2))`` and not as
+``echo(f(1, f(2)))``. The method call syntax may be used to provide one
+more argument in this case:
+
+.. code-block:: nim
+  proc optarg(x: int, y: int = 0): int = x + y
+  proc singlearg(x: int): int = 20*x
+  
+  echo optarg 1, " ", singlearg 2  # prints "1 40"
+  
+  let fail = optarg 1, optarg 8   # Wrong. Too many arguments for a command call
+  let x = optarg(1, optarg 8)  # traditional procedure call with 2 arguments
+  let y = 1.optarg optarg 8    # same thing as above, w/o the parenthesis
+  assert x == y
+
+The command invocation syntax also can't have complex expressions as arguments. 
+For example: (`anonymous procs`_), ``if``, ``case`` or ``try``. The (`do 
+notation`_) is limited, but usable for a single proc (see the example in the 
+corresponding section). Function calls with no arguments still needs () to 
+distinguish between a call and the function itself as a first class value.
+
+
+Closures
+--------
+
+Procedures can appear at the top level in a module as well as inside other
+scopes, in which case they are called nested procs. A nested proc can access
+local variables from its enclosing scope and if it does so it becomes a
+closure. Any captured variables are stored in a hidden additional argument
+to the closure (its environment) and they are accessed by reference by both
+the closure and its enclosing scope (i.e. any modifications made to them are
+visible in both places). The closure environment may be allocated on the heap
+or on the stack if the compiler determines that this would be safe.
+
+
+Anonymous Procs
+---------------
+
+Procs can also be treated as expressions, in which case it's allowed to omit
+the proc's name.
+
+.. code-block:: nim
+  var cities = @["Frankfurt", "Tokyo", "New York"]
+
+  cities.sort(proc (x,y: string): int =
+      cmp(x.len, y.len))
+
+
+Procs as expressions can appear both as nested procs and inside top level 
+executable code.
+
+
+Do notation
+-----------
+
+**Note:** The future of the ``do`` notation is uncertain.
+
+As a special more convenient notation, proc expressions involved in procedure
+calls can use the ``do`` keyword:
+
+.. code-block:: nim
+  sort(cities) do (x,y: string) -> int:
+    cmp(x.len, y.len)
+  # Less parenthesis using the method plus command syntax:
+  cities = cities.map do (x:string) -> string:  
+    "City of " & x
+
+``do`` is written after the parentheses enclosing the regular proc params. 
+The proc expression represented by the do block is appended to them.
+
+More than one ``do`` block can appear in a single call:
+
+.. code-block:: nim
+  proc performWithUndo(task: proc(), undo: proc()) = ...
+
+  performWithUndo do:
+    # multiple-line block of code
+    # to perform the task
+  do:
+    # code to undo it
+
+
+Nonoverloadable builtins
+------------------------
+
+The following builtin procs cannot be overloaded for reasons of implementation
+simplicity (they require specialized semantic checking)::
+
+  declared, defined, definedInScope, compiles, low, high, sizeOf, 
+  is, of, shallowCopy, getAst, astToStr, spawn, procCall
+
+Thus they act more like keywords than like ordinary identifiers; unlike a 
+keyword however, a redefinition may `shadow`:idx: the definition in 
+the ``system`` module. From this list the following should not be written in dot
+notation ``x.f`` since ``x`` cannot be type checked before it gets passed
+to ``f``::
+
+  declared, defined, definedInScope, compiles, getAst, astToStr
+
+
+Var parameters
+--------------
+The type of a parameter may be prefixed with the ``var`` keyword:
+
+.. code-block:: nim
+  proc divmod(a, b: int; res, remainder: var int) =
+    res = a div b
+    remainder = a mod b
+
+  var
+    x, y: int
+
+  divmod(8, 5, x, y) # modifies x and y
+  assert x == 1
+  assert y == 3
+
+In the example, ``res`` and ``remainder`` are `var parameters`.
+Var parameters can be modified by the procedure and the changes are
+visible to the caller. The argument passed to a var parameter has to be
+an l-value. Var parameters are implemented as hidden pointers. The
+above example is equivalent to:
+
+.. code-block:: nim
+  proc divmod(a, b: int; res, remainder: ptr int) =
+    res[] = a div b
+    remainder[] = a mod b
+
+  var
+    x, y: int
+  divmod(8, 5, addr(x), addr(y))
+  assert x == 1
+  assert y == 3
+
+In the examples, var parameters or pointers are used to provide two
+return values. This can be done in a cleaner way by returning a tuple:
+
+.. code-block:: nim
+  proc divmod(a, b: int): tuple[res, remainder: int] =
+    (a div b, a mod b)
+
+  var t = divmod(8, 5)
+
+  assert t.res == 1
+  assert t.remainder == 3
+
+One can use `tuple unpacking`:idx: to access the tuple's fields:
+
+.. code-block:: nim
+  var (x, y) = divmod(8, 5) # tuple unpacking
+  assert x == 1
+  assert y == 3
+
+
+**Note**: ``var`` parameters are never necessary for efficient parameter
+passing. Since non-var parameters cannot be modified the compiler is always
+free to pass arguments by reference if it considers it can speed up execution.
+
+
+Var return type
+---------------
+
+A proc, converter or iterator may return a ``var`` type which means that the
+returned value is an l-value and can be modified by the caller:
+
+.. code-block:: nim
+  var g = 0
+
+  proc WriteAccessToG(): var int =
+    result = g
+  
+  WriteAccessToG() = 6
+  assert g == 6
+
+It is a compile time error if the implicitly introduced pointer could be 
+used to access a location beyond its lifetime:
+
+.. code-block:: nim
+  proc WriteAccessToG(): var int =
+    var g = 0
+    result = g # Error!
+
+For iterators, a component of a tuple return type can have a ``var`` type too: 
+
+.. code-block:: nim
+  iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] =
+    for i in 0..a.high:
+      yield (i, a[i])
+
+In the standard library every name of a routine that returns a ``var`` type
+starts with the prefix ``m`` per convention.
+
+
+Overloading of the subscript operator
+-------------------------------------
+
+The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded.
+
+
+Multi-methods
+=============
+
+Procedures always use static dispatch. Multi-methods use dynamic
+dispatch.
+
+.. code-block:: nim
+  type
+    Expression = ref object of RootObj ## abstract base class for an expression
+    Literal = ref object of Expression
+      x: int
+    PlusExpr = ref object of Expression
+      a, b: Expression
+  
+  method eval(e: Expression): int =
+    # override this base method
+    quit "to override!"
+  
+  method eval(e: Literal): int = return e.x
+  
+  method eval(e: PlusExpr): int =
+    # watch out: relies on dynamic binding
+    result = eval(e.a) + eval(e.b)
+  
+  proc newLit(x: int): Literal =
+    new(result)
+    result.x = x
+  
+  proc newPlus(a, b: Expression): PlusExpr =
+    new(result)
+    result.a = a
+    result.b = b
+
+echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
+  
+In the example the constructors ``newLit`` and ``newPlus`` are procs
+because they should use static binding, but ``eval`` is a method because it
+requires dynamic binding.
+
+In a multi-method all parameters that have an object type are used for the
+dispatching:
+
+.. code-block:: nim
+  type
+    Thing = ref object of RootObj
+    Unit = ref object of Thing
+      x: int
+      
+  method collide(a, b: Thing) {.inline.} =
+    quit "to override!"
+    
+  method collide(a: Thing, b: Unit) {.inline.} =
+    echo "1"
+  
+  method collide(a: Unit, b: Thing) {.inline.} =
+    echo "2"
+  
+  var a, b: Unit
+  new a
+  new b
+  collide(a, b) # output: 2
+
+
+Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over 
+collide 1 because the resolution works from left to right. 
+In the example ``Unit, Thing`` is preferred over ``Thing, Unit``.
+
+**Performance note**: Nim does not produce a virtual method table, but
+generates dispatch trees. This avoids the expensive indirect branch for method
+calls and enables inlining. However, other optimizations like compile time
+evaluation or dead code elimination do not work with methods.
+
+
+Iterators and the for statement
+===============================
+
+The `for`:idx: statement is an abstract mechanism to iterate over the elements
+of a container. It relies on an `iterator`:idx: to do so. Like ``while``
+statements, ``for`` statements open an `implicit block`:idx:, so that they
+can be left with a ``break`` statement. 
+
+The ``for`` loop declares iteration variables - their scope reaches until the
+end of the loop body. The iteration variables' types are inferred by the
+return type of the iterator.
+
+An iterator is similar to a procedure, except that it can be called in the
+context of a ``for`` loop. Iterators provide a way to specify the iteration over
+an abstract type. A key role in the execution of a ``for`` loop plays the
+``yield`` statement in the called iterator. Whenever a ``yield`` statement is
+reached the data is bound to the ``for`` loop variables and control continues
+in the body of the ``for`` loop. The iterator's local variables and execution
+state are automatically saved between calls. Example:
+
+.. code-block:: nim
+  # this definition exists in the system module
+  iterator items*(a: string): char {.inline.} =
+    var i = 0
+    while i < len(a):
+      yield a[i]
+      inc(i)
+
+  for ch in items("hello world"): # `ch` is an iteration variable
+    echo(ch)
+
+The compiler generates code as if the programmer would have written this:
+
+.. code-block:: nim
+  var i = 0
+  while i < len(a):
+    var ch = a[i]
+    echo(ch)
+    inc(i)
+
+If the iterator yields a tuple, there can be as many iteration variables
+as there are components in the tuple. The i'th iteration variable's type is
+the type of the i'th component. In other words, implicit tuple unpacking in a 
+for loop context is supported.
+
+Implict items/pairs invocations
+-------------------------------
+
+If the for loop expression ``e`` does not denote an iterator and the for loop
+has exactly 1 variable, the for loop expression is rewritten to ``items(e)``;
+ie. an ``items`` iterator is implicitly invoked:
+
+.. code-block:: nim
+  for x in [1,2,3]: echo x
+  
+If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly
+invoked.
+
+Symbol lookup of the identifiers ``items``/``pairs`` is performed after 
+the rewriting step, so that all overloads of ``items``/``pairs`` are taken
+into account.
+
+
+First class iterators
+---------------------
+
+There are 2 kinds of iterators in Nim: *inline* and *closure* iterators.
+An `inline iterator`:idx: is an iterator that's always inlined by the compiler 
+leading to zero overhead for the abstraction, but may result in a heavy
+increase in code size. Inline iterators are second class citizens;
+They can be passed as parameters only to other inlining code facilities like
+templates, macros and other inline iterators.
+
+In contrast to that, a `closure iterator`:idx: can be passed around more freely:
+
+.. code-block:: nim
+  iterator count0(): int {.closure.} =
+    yield 0
+   
+  iterator count2(): int {.closure.} =
+    var x = 1
+    yield x
+    inc x
+    yield x
+
+  proc invoke(iter: iterator(): int {.closure.}) =
+    for x in iter(): echo x
+
+  invoke(count0)
+  invoke(count2)
+
+Closure iterators have other restrictions than inline iterators:
+
+1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
+2. For now, a closure iterator cannot be evaluated at compile time.
+3. ``return`` is allowed in a closure iterator (but rarely useful) and ends 
+   iteration.
+4. Neither inline nor closure iterators can be recursive.
+
+Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly
+default to being inline, but this may change in future versions of the
+implementation.
+
+The ``iterator`` type is always of the calling convention ``closure`` 
+implicitly; the following example shows how to use iterators to implement
+a `collaborative tasking`:idx: system:
+
+.. code-block:: nim
+  # simple tasking:
+  type
+    Task = iterator (ticker: int)
+
+  iterator a1(ticker: int) {.closure.} =
+    echo "a1: A"
+    yield
+    echo "a1: B"
+    yield
+    echo "a1: C"
+    yield
+    echo "a1: D"
+
+  iterator a2(ticker: int) {.closure.} =
+    echo "a2: A"
+    yield
+    echo "a2: B"
+    yield
+    echo "a2: C"
+
+  proc runTasks(t: varargs[Task]) =
+    var ticker = 0
+    while true:
+      let x = t[ticker mod t.len]
+      if finished(x): break
+      x(ticker)
+      inc ticker
+
+  runTasks(a1, a2)
+
+The builtin ``system.finished`` can be used to determine if an iterator has
+finished its operation; no exception is raised on an attempt to invoke an
+iterator that has already finished its work.
+
+Note that ``system.finished`` is error prone to use because it only returns
+``true`` one iteration after the iterator has finished:
+
+.. code-block:: nim
+  iterator mycount(a, b: int): int {.closure.} =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+
+  var c = mycount # instantiate the iterator
+  while not finished(c):
+    echo c(1, 3)
+
+  # Produces
+  1
+  2
+  3
+  0
+
+Instead this code has be used:
+
+.. code-block:: nim
+  var c = mycount # instantiate the iterator
+  while true:
+    let value = c(1, 3)
+    if finished(c): break # and discard 'value'!
+    echo value
+
+It helps to think that the iterator actually returns a
+pair ``(value, done)`` and ``finished`` is used to access the hidden ``done``
+field.
+
+
+Closure iterators are *resumable functions* and so one has to provide the
+arguments to every call. To get around this limitation one can capture
+parameters of an outer factory proc:
+
+.. code-block:: nim
+  proc mycount(a, b: int): iterator (): int =
+    result = iterator (): int =
+      var x = a
+      while x <= b:
+        yield x
+        inc x
+
+  let foo = mycount(1, 4)
+
+  for f in foo():
+    echo f
+
+..
+  Implicit return type
+  --------------------
+
+  Since inline iterators must always produce values that will be consumed in
+  a for loop, the compiler will implicitly use the ``auto`` return type if no
+  type is given by the user. In contrast, since closure iterators can be used
+  as a collaborative tasking system, ``void`` is a valid return type for them.
+
+
+Converters
+==========
+
+A converter is like an ordinary proc except that it enhances 
+the "implicitly convertible" type relation (see `Convertible relation`_):
+
+.. code-block:: nim
+  # bad style ahead: Nim is not C.
+  converter toBool(x: int): bool = x != 0
+
+  if 4:
+    echo "compiles"
+
+
+A converter can also be explicitly invoked for improved readability. Note that
+implicit converter chaining is not supported: If there is a converter from
+type A to type B and from type B to type C the implicit conversion from A to C
+is not provided.
diff --git a/doc/manual/special_ops.txt b/doc/manual/special_ops.txt
new file mode 100644
index 000000000..46135f129
--- /dev/null
+++ b/doc/manual/special_ops.txt
@@ -0,0 +1,54 @@
+Special Operators
+=================
+
+dot operators
+-------------
+
+Nim offers a special family of dot operators that can be used to
+intercept and rewrite proc call and field access attempts, referring
+to previously undeclared symbol names. They can be used to provide a
+fluent interface to objects lying outside the static confines of the
+type system such as values from dynamic scripting languages
+or dynamic file formats such as JSON or XML.
+
+When Nim encounters an expression that cannot be resolved by the
+standard overload resolution rules, the current scope will be searched
+for a dot operator that can be matched against a re-written form of
+the expression, where the unknown field or proc name is converted to
+an additional static string parameter:
+
+.. code-block:: nim
+  a.b # becomes `.`(a, "b")
+  a.b(c, d) # becomes `.`(a, "b", c, d)
+
+The matched dot operators can be symbols of any callable kind (procs,
+templates and macros), depending on the desired effect:
+
+.. code-block:: nim
+  proc `.` (js: PJsonNode, field: string): JSON = js[field]
+
+  var js = parseJson("{ x: 1, y: 2}")
+  echo js.x # outputs 1
+  echo js.y # outputs 2
+
+The following dot operators are available:
+
+operator `.`
+------------ 
+This operator will be matched against both field accesses and method calls.
+
+operator `.()`
+---------------
+This operator will be matched exclusively against method calls. It has higher
+precedence than the `.` operator and this allows one to handle expressions like
+`x.y` and `x.y()` differently if one is interfacing with a scripting language
+for example.
+
+operator `.=`
+-------------
+This operator will be matched against assignments to missing fields.
+
+.. code-block:: nim
+  a.b = c # becomes `.=`(a, "b", c)
+
+
diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt
new file mode 100644
index 000000000..32c01dccb
--- /dev/null
+++ b/doc/manual/stmts.txt
@@ -0,0 +1,660 @@
+Statements and expressions
+==========================
+
+Nim uses the common statement/expression paradigm: Statements do not
+produce a value in contrast to expressions. However, some expressions are
+statements.
+
+Statements are separated into `simple statements`:idx: and
+`complex statements`:idx:.
+Simple statements are statements that cannot contain other statements like
+assignments, calls or the ``return`` statement; complex statements can
+contain other statements. To avoid the `dangling else problem`:idx:, complex
+statements always have to be indented. The details can be found in the grammar.
+
+
+Statement list expression
+-------------------------
+
+Statements can also occur in an expression context that looks
+like ``(stmt1; stmt2; ...; ex)``. This is called
+an statement list expression or ``(;)``. The type
+of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements
+must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.)
+``(;)`` does not introduce a new scope.
+
+
+Discard statement
+-----------------
+
+Example:
+
+.. code-block:: nim
+  proc p(x, y: int): int =
+    result = x + y
+
+  discard p(3, 4) # discard the return value of `p`
+
+The ``discard`` statement evaluates its expression for side-effects and
+throws the expression's resulting value away.
+
+Ignoring the return value of a procedure without using a discard statement is
+a static error.
+
+The return value can be ignored implicitly if the called proc/iterator has
+been declared with the `discardable`:idx: pragma:
+
+.. code-block:: nim
+  proc p(x, y: int): int {.discardable.} =
+    result = x + y
+
+  p(3, 4) # now valid
+
+An empty ``discard`` statement is often used as a null statement:
+
+.. code-block:: nim
+  proc classify(s: string) =
+    case s[0]
+    of SymChars, '_': echo "an identifier"
+    of '0'..'9': echo "a number"
+    else: discard
+
+
+Var statement
+-------------
+
+Var statements declare new local and global variables and
+initialize them. A comma separated list of variables can be used to specify
+variables of the same type:
+
+.. code-block:: nim
+
+  var
+    a: int = 0
+    x, y, z: int
+
+If an initializer is given the type can be omitted: the variable is then of the
+same type as the initializing expression. Variables are always initialized
+with a default value if there is no initializing expression. The default
+value depends on the type and is always a zero in binary.
+
+============================    ==============================================
+Type                            default value
+============================    ==============================================
+any integer type                0
+any float                       0.0
+char                            '\\0'
+bool                            false
+ref or pointer type             nil
+procedural type                 nil
+sequence                        nil (*not* ``@[]``)
+string                          nil (*not* "")
+tuple[x: A, y: B, ...]          (default(A), default(B), ...)
+                                (analogous for objects)
+array[0..., T]                  [default(T), ...]
+range[T]                        default(T); this may be out of the valid range
+T = enum                        cast[T](0); this may be an invalid value
+============================    ==============================================
+
+
+The implicit initialization can be avoided for optimization reasons with the
+`noinit`:idx: pragma:
+
+.. code-block:: nim
+  var
+    a {.noInit.}: array [0..1023, char]
+
+If a proc is annotated with the ``noinit`` pragma this refers to its implicit
+``result`` variable:
+
+.. code-block:: nim
+  proc returnUndefinedValue: int {.noinit.} = discard
+
+
+The implicit initialization can be also prevented by the `requiresInit`:idx:
+type pragma. The compiler requires an explicit initialization then. However
+it does a `control flow analysis`:idx: to prove the variable has been
+initialized and does not rely on syntactic properties:
+
+.. code-block:: nim
+  type
+    MyObject = object {.requiresInit.}
+
+  proc p() =
+    # the following is valid:
+    var x: MyObject
+    if someCondition():
+      x = a()
+    else:
+      x = a()
+    use x
+
+
+let statement
+-------------
+
+A ``let`` statement declares new local and global `single assignment`:idx:
+variables and binds a value to them. The syntax is the same as that of the ``var``
+statement, except that the keyword ``var`` is replaced by the keyword ``let``.
+Let variables are not l-values and can thus not be passed to ``var`` parameters
+nor can their address be taken. They cannot be assigned new values.
+
+For let variables the same pragmas are available as for ordinary variables.
+
+
+Tuple unpacking
+---------------
+
+In a ``var`` or ``let`` statement tuple unpacking can be performed. The special
+identifier ``_`` can be used to ignore some parts of the tuple:
+
+.. code-block:: nim
+    proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+    let (x, _, z) = returnsTuple()
+
+
+
+Const section
+-------------
+
+`Constants`:idx: are symbols which are bound to a value. The constant's value
+cannot change. The compiler must be able to evaluate the expression in a
+constant declaration at compile time.
+
+Nim contains a sophisticated compile-time evaluator, so procedures which
+have no side-effect can be used in constant expressions too:
+
+.. code-block:: nim
+  import strutils
+  const
+    constEval = contains("abc", 'b') # computed at compile time!
+
+
+The rules for compile-time computability are:
+
+1. Literals are compile-time computable.
+2. Type conversions are compile-time computable.
+3. Procedure calls of the form ``p(X)`` are compile-time computable if
+   ``p`` is a proc without side-effects (see the `noSideEffect pragma 
+   <#pragmas-nosideeffect-pragma>`_ for details) and if ``X`` is a 
+   (possibly empty) list of compile-time computable arguments.
+
+
+Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can
+they contain such a type.
+
+
+Static statement/expression
+---------------------------
+
+A static statement/expression can be used to enforce compile
+time evaluation explicitly. Enforced compile time evaluation can even evaluate
+code that has side effects:
+
+.. code-block::
+
+  static:
+    echo "echo at compile time"
+
+It's a static error if the compiler cannot perform the evaluation at compile
+time.
+
+The current implementation poses some restrictions for compile time
+evaluation: Code which contains ``cast`` or makes use of the foreign function
+interface cannot be evaluated at compile time. Later versions of Nim will
+support the FFI at compile time.
+
+
+If statement
+------------
+
+Example:
+
+.. code-block:: nim
+
+  var name = readLine(stdin)
+
+  if name == "Andreas":
+    echo("What a nice name!")
+  elif name == "":
+    echo("Don't you have a name?")
+  else:
+    echo("Boring name...")
+
+The ``if`` statement is a simple way to make a branch in the control flow:
+The expression after the keyword ``if`` is evaluated, if it is true
+the corresponding statements after the ``:`` are executed. Otherwise
+the expression after the ``elif`` is evaluated (if there is an
+``elif`` branch), if it is true the corresponding statements after
+the ``:`` are executed. This goes on until the last ``elif``. If all
+conditions fail, the ``else`` part is executed. If there is no ``else``
+part, execution continues with the next statement.
+
+In ``if`` statements new scopes begin immediately after the ``if``/``elif``/``else`` keywords and ends after the corresponding *then* block.
+For visualization purposes the scopes have been enclosed in ``{|  |}`` in the following example:
+
+.. code-block:: nim
+  if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch):
+    echo "key ", m[0], " value ", m[1]  |}
+  elif {| (let m = input =~ re""; m.isMatch):
+    echo "new m in this scope"  |}
+  else: {|
+    echo "m not declared here"  |}
+
+Case statement
+--------------
+
+Example:
+
+.. code-block:: nim
+
+  case readline(stdin)
+  of "delete-everything", "restart-computer":
+    echo("permission denied")
+  of "go-for-a-walk":     echo("please yourself")
+  else:                   echo("unknown command")
+
+  # indentation of the branches is also allowed; and so is an optional colon
+  # after the selecting expression:
+  case readline(stdin):
+    of "delete-everything", "restart-computer":
+      echo("permission denied")
+    of "go-for-a-walk":     echo("please yourself")
+    else:                   echo("unknown command")
+
+
+The ``case`` statement is similar to the if statement, but it represents
+a multi-branch selection. The expression after the keyword ``case`` is
+evaluated and if its value is in a *slicelist* the corresponding statements
+(after the ``of`` keyword) are executed. If the value is not in any
+given *slicelist* the ``else`` part is executed. If there is no ``else``
+part and not all possible values that ``expr`` can hold occur in a
+``slicelist``, a static error occurs. This holds only for expressions of
+ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s
+type. To suppress the static error an ``else`` part with an
+empty ``discard`` statement should be used.
+
+For non ordinal types it is not possible to list every possible value and so
+these always require an ``else`` part.
+
+As a special semantic extension, an expression in an ``of`` branch of a case
+statement may evaluate to a set or array constructor; the set or array is then
+expanded into a list of its elements:
+
+.. code-block:: nim
+  const
+    SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
+
+  proc classify(s: string) =
+    case s[0]
+    of SymChars, '_': echo "an identifier"
+    of '0'..'9': echo "a number"
+    else: echo "other"
+
+  # is equivalent to:
+  proc classify(s: string) =
+    case s[0]
+    of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': echo "an identifier"
+    of '0'..'9': echo "a number"
+    else: echo "other"
+
+
+When statement
+--------------
+
+Example:
+
+.. code-block:: nim
+
+  when sizeof(int) == 2:
+    echo("running on a 16 bit system!")
+  elif sizeof(int) == 4:
+    echo("running on a 32 bit system!")
+  elif sizeof(int) == 8:
+    echo("running on a 64 bit system!")
+  else:
+    echo("cannot happen!")
+
+The ``when`` statement is almost identical to the ``if`` statement with some
+exceptions:
+
+* Each condition (``expr``) has to be a constant expression (of type ``bool``).
+* The statements do not open a new scope.
+* The statements that belong to the expression that evaluated to true are
+  translated by the compiler, the other statements are not checked for
+  semantics! However, each condition is checked for semantics.
+
+The ``when`` statement enables conditional compilation techniques. As
+a special syntactic extension, the ``when`` construct is also available
+within ``object`` definitions.
+
+
+Return statement
+----------------
+
+Example:
+
+.. code-block:: nim
+  return 40+2
+
+The ``return`` statement ends the execution of the current procedure.
+It is only allowed in procedures. If there is an ``expr``, this is syntactic
+sugar for:
+
+.. code-block:: nim
+  result = expr
+  return result
+
+
+``return`` without an expression is a short notation for ``return result`` if
+the proc has a return type. The `result`:idx: variable is always the return
+value of the procedure. It is automatically declared by the compiler. As all
+variables, ``result`` is initialized to (binary) zero:
+
+.. code-block:: nim
+  proc returnZero(): int =
+    # implicitly returns 0
+
+
+Yield statement
+---------------
+
+Example:
+
+.. code-block:: nim
+  yield (1, 2, 3)
+
+The ``yield`` statement is used instead of the ``return`` statement in
+iterators. It is only valid in iterators. Execution is returned to the body
+of the for loop that called the iterator. Yield does not end the iteration
+process, but execution is passed back to the iterator if the next iteration
+starts. See the section about iterators (`Iterators and the for statement`_)
+for further information.
+
+
+Block statement
+---------------
+
+Example:
+
+.. code-block:: nim
+  var found = false
+  block myblock:
+    for i in 0..3:
+      for j in 0..3:
+        if a[j][i] == 7:
+          found = true
+          break myblock # leave the block, in this case both for-loops
+  echo(found)
+
+The block statement is a means to group statements to a (named) ``block``.
+Inside the block, the ``break`` statement is allowed to leave the block
+immediately. A ``break`` statement can contain a name of a surrounding
+block to specify which block is to leave.
+
+
+Break statement
+---------------
+
+Example:
+
+.. code-block:: nim
+  break
+
+The ``break`` statement is used to leave a block immediately. If ``symbol``
+is given, it is the name of the enclosing block that is to leave. If it is
+absent, the innermost block is left.
+
+
+While statement
+---------------
+
+Example:
+
+.. code-block:: nim
+  echo("Please tell me your password: \n")
+  var pw = readLine(stdin)
+  while pw != "12345":
+    echo("Wrong password! Next try: \n")
+    pw = readLine(stdin)
+
+
+The ``while`` statement is executed until the ``expr`` evaluates to false.
+Endless loops are no error. ``while`` statements open an `implicit block`,
+so that they can be left with a ``break`` statement.
+
+
+Continue statement
+------------------
+
+A ``continue`` statement leads to the immediate next iteration of the
+surrounding loop construct. It is only allowed within a loop. A continue
+statement is syntactic sugar for a nested block:
+
+.. code-block:: nim
+  while expr1:
+    stmt1
+    continue
+    stmt2
+
+Is equivalent to:
+
+.. code-block:: nim
+  while expr1:
+    block myBlockName:
+      stmt1
+      break myBlockName
+      stmt2
+
+
+Assembler statement
+-------------------
+
+The direct embedding of assembler code into Nim code is supported
+by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to
+Nim identifiers shall be enclosed in a special character which can be
+specified in the statement's pragmas. The default special character is ``'`'``:
+
+.. code-block:: nim
+  {.push stackTrace:off.}
+  proc addInt(a, b: int): int =
+    # a in eax, and b in edx
+    asm """
+        mov eax, `a`
+        add eax, `b`
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+    """
+  {.pop.}
+
+If the GNU assembler is used, quotes and newlines are inserted automatically:
+
+.. code-block:: nim
+  proc addInt(a, b: int): int =
+    asm """
+      addl %%ecx, %%eax
+      jno 1
+      call `raiseOverflow`
+      1:
+      :"=a"(`result`)
+      :"a"(`a`), "c"(`b`)
+    """
+
+Instead of:
+
+.. code-block:: nim
+  proc addInt(a, b: int): int =
+    asm """
+      "addl %%ecx, %%eax\n"
+      "jno 1\n"
+      "call `raiseOverflow`\n"
+      "1: \n"
+      :"=a"(`result`)
+      :"a"(`a`), "c"(`b`)
+    """
+
+Using statement
+---------------
+
+**Warning**: The ``using`` statement is highly experimental and has to be
+explicitly enabled with the `experimental`:idx: pragma or command line option!
+
+The using statement provides syntactic convenience for procs that
+heavily use a single contextual parameter. When applied to a variable or a
+constant, it will instruct Nim to automatically consider the used symbol as
+a hidden leading parameter for any procedure calls, following the using
+statement in the current scope. Thus, it behaves much like the hidden `this`
+parameter available in some object-oriented programming languages.
+
+.. code-block:: nim
+
+  var s = socket()
+  using s
+
+  connect(host, port)
+  send(data)
+
+  while true:
+    let line = readLine(timeout)
+    ...
+
+
+When applied to a callable symbol, it brings the designated symbol in the
+current scope. Thus, it can be used to disambiguate between imported symbols
+from different modules having the same name.
+
+.. code-block:: nim
+  import windows, sdl
+  using sdl.SetTimer
+
+Note that ``using`` only *adds* to the current context, it doesn't remove or
+replace, **neither** does it create a new scope. What this means is that if one
+applies this to multiple variables the compiler will find conflicts in what
+variable to use:
+
+.. code-block:: nim
+  var a, b = "kill it"
+  using a
+  add(" with fire")
+  using b
+  add(" with water")
+  echo a
+  echo b
+
+When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could
+be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or
+is ambiguous)``. To solve this one would need to nest ``using`` with a
+``block`` statement so as to control the reach of the ``using`` statement.
+
+If expression
+-------------
+
+An `if expression` is almost like an if statement, but it is an expression.
+Example:
+
+.. code-block:: nim
+  var y = if x > 8: 9 else: 10
+
+An if expression always results in a value, so the ``else`` part is
+required. ``Elif`` parts are also allowed.
+
+When expression
+---------------
+
+Just like an `if expression`, but corresponding to the when statement.
+
+Case expression
+---------------
+
+The `case expression` is again very similar to the case statement:
+
+.. code-block:: nim
+  var favoriteFood = case animal
+    of "dog": "bones"
+    of "cat": "mice"
+    elif animal.endsWith"whale": "plankton"
+    else:
+      echo "I'm not sure what to serve, but everybody loves ice cream"
+      "ice cream"
+
+As seen in the above example, the case expression can also introduce side
+effects. When multiple statements are given for a branch, Nim will use
+the last expression as the result value, much like in an `expr` template.
+
+Table constructor
+-----------------
+
+A table constructor is syntactic sugar for an array constructor:
+
+.. code-block:: nim
+  {"key1": "value1", "key2", "key3": "value2"}
+
+  # is the same as:
+  [("key1", "value1"), ("key2", "value2"), ("key3", "value2")]
+
+
+The empty table can be written ``{:}`` (in contrast to the empty set
+which is ``{}``) which is thus another way to write as the empty array
+constructor ``[]``. This slightly unusual way of supporting tables
+has lots of advantages:
+
+* The order of the (key,value)-pairs is preserved, thus it is easy to
+  support ordered dicts with for example ``{key: val}.newOrderedTable``.
+* A table literal can be put into a ``const`` section and the compiler
+  can easily put it into the executable's data section just like it can
+  for arrays and the generated data section requires a minimal amount
+  of memory.
+* Every table implementation is treated equal syntactically.
+* Apart from the minimal syntactic sugar the language core does not need to
+  know about tables.
+
+
+Type conversions
+----------------
+Syntactically a `type conversion` is like a procedure call, but a
+type name replaces the procedure name. A type conversion is always
+safe in the sense that a failure to convert a type to another
+results in an exception (if it cannot be determined statically).
+
+Ordinary procs are often preferred over type conversions in Nim: For instance,
+``$`` is the ``toString`` operator by convention and ``toFloat`` and ``toInt``
+can be used to convert from floating point to integer or vice versa.
+
+
+Type casts
+----------
+Example:
+
+.. code-block:: nim
+  cast[int](x)
+
+Type casts are a crude mechanism to interpret the bit pattern of
+an expression as if it would be of another type. Type casts are
+only needed for low-level programming and are inherently unsafe.
+
+
+The addr operator
+-----------------
+The ``addr`` operator returns the address of an l-value. If the type of the
+location is ``T``, the `addr` operator result is of the type ``ptr T``. An
+address is always an untraced reference. Taking the address of an object that
+resides on the stack is **unsafe**, as the pointer may live longer than the
+object on the stack and can thus reference a non-existing object. One can get
+the address of variables, but one can't use it on variables declared through
+``let`` statements:
+
+.. code-block:: nim
+
+  let t1 = "Hello"
+  var
+    t2 = t1
+    t3 : pointer = addr(t2)
+  echo repr(addr(t2))
+  # --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello"
+  echo cast[ptr string](t3)[]
+  # --> Hello
+  # The following line doesn't compile:
+  echo repr(addr(t1))
+  # Error: expression has no address
diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt
new file mode 100644
index 000000000..24644bce2
--- /dev/null
+++ b/doc/manual/syntax.txt
@@ -0,0 +1,109 @@
+Syntax
+======
+
+This section lists Nim's standard syntax. How the parser handles
+the indentation is already described in the `Lexical Analysis`_ section.
+
+Nim allows user-definable operators.
+Binary operators have 11 different levels of precedence.
+
+
+
+Associativity
+-------------
+
+Binary operators whose first character is ``^`` are right-associative, all
+other binary operators are left-associative.
+
+
+
+Precedence
+----------
+
+Unary operators always bind stronger than any binary 
+operator: ``$a + b`` is ``($a) + b`` and not ``$(a + b)``.
+
+If an unary operator's first character is ``@`` it is a `sigil-like`:idx: 
+operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed
+as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``.
+
+
+For binary operators that are not keywords the precedence is determined by the
+following rules:
+
+Operators ending in either ``->``, ``~>`` or ``=>`` are called
+`arrow like`:idx:, and have the lowest precedence of all operators.
+
+If the operator ends with ``=`` and its first character is none of 
+``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which
+has the second lowest precedence.
+
+Otherwise precedence is determined by the first character.
+
+================  ===============================================  ==================  ===============
+Precedence level    Operators                                      First character     Terminal symbol
+================  ===============================================  ==================  ===============
+ 10 (highest)                                                      ``$  ^``            OP10
+  9               ``*    /    div   mod   shl  shr  %``            ``*  %  \  /``      OP9
+  8               ``+    -``                                       ``+  -  ~  |``      OP8
+  7               ``&``                                            ``&``               OP7
+  6               ``..``                                           ``.``               OP6
+  5               ``==  <= < >= > !=  in notin is isnot not of``   ``=  <  >  !``      OP5
+  4               ``and``                                                              OP4
+  3               ``or xor``                                                           OP3
+  2                                                                ``@  :  ?``         OP2
+  1               *assignment operator* (like ``+=``, ``*=``)                          OP1
+  0 (lowest)      *arrow like operator* (like ``->``, ``=>``)                          OP0
+================  ===============================================  ==================  ===============
+
+
+Strong spaces
+-------------
+
+The number of spaces preceding a non-keyword operator affects precedence
+if the experimental parser directive ``#!strongSpaces`` is used. Indentation
+is not used to determine the number of spaces. If 2 or more operators have the
+same number of preceding spaces the precedence table applies, so ``1 + 3 * 4``
+is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``:
+
+.. code-block:: nim
+  #! strongSpaces
+  if foo+4 * 4 == 8  and  b&c | 9  ++
+      bar:
+    echo ""
+  # is parsed as
+  if ((foo+4)*4 == 8) and (((b&c) | 9) ++ bar): echo ""
+
+
+Furthermore whether an operator is used a prefix operator is affected by the
+number of spaces: 
+
+.. code-block:: nim
+  #! strongSpaces
+  echo $foo
+  # is parsed as
+  echo($foo)
+
+This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors
+or as accessors:
+
+.. code-block:: nim
+  #! strongSpaces
+  echo (1,2)
+  # is parsed as
+  echo((1,2))
+
+Only 0, 1, 2, 4 or 8 spaces are allowed to specify precedence and it is
+enforced that infix operators have the same amount of spaces before and after
+them. This rules does not apply when a newline follows after the operator,
+then only the preceding spaces are considered.
+
+
+Grammar
+-------
+
+The grammar's start symbol is ``module``.
+
+.. include:: grammar.txt
+   :literal:
+
diff --git a/doc/manual/taint.txt b/doc/manual/taint.txt
new file mode 100644
index 000000000..84f0c68b1
--- /dev/null
+++ b/doc/manual/taint.txt
@@ -0,0 +1,20 @@
+Taint mode
+==========
+
+The Nim compiler and most parts of the standard library support 
+a taint mode. Input strings are declared with the `TaintedString`:idx: 
+string type declared in the ``system`` module.
+
+If the taint mode is turned on (via the ``--taintMode:on`` command line 
+option) it is a distinct string type which helps to detect input
+validation errors:
+
+.. code-block:: nim
+  echo "your name: "
+  var name: TaintedString = stdin.readline
+  # it is safe here to output the name without any input validation, so
+  # we simply convert `name` to string to make the compiler happy: 
+  echo "hi, ", name.string
+
+If the taint mode is turned off, ``TaintedString`` is simply an alias for
+``string``.
diff --git a/doc/manual/templates.txt b/doc/manual/templates.txt
new file mode 100644
index 000000000..eeb907ce0
--- /dev/null
+++ b/doc/manual/templates.txt
@@ -0,0 +1,436 @@
+Templates
+=========
+
+A template is a simple form of a macro: It is a simple substitution
+mechanism that operates on Nim's abstract syntax trees. It is processed in
+the semantic pass of the compiler.
+
+The syntax to *invoke* a template is the same as calling a procedure.
+
+Example:
+
+.. code-block:: nim
+  template `!=` (a, b: expr): expr =
+    # this definition exists in the System module
+    not (a == b)
+
+  assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
+
+The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact 
+templates:
+
+| ``a > b`` is transformed into ``b < a``.
+| ``a in b`` is transformed into ``contains(b, a)``. 
+| ``notin`` and ``isnot`` have the obvious meanings.
+
+The "types" of templates can be the symbols ``expr`` (stands for *expression*), 
+``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type 
+description*). These are "meta types", they can only be used in certain 
+contexts. Real types can be used too; this implies that expressions are 
+expected.
+
+
+Ordinary vs immediate templates
+-------------------------------
+
+There are two different kinds of templates: immediate templates and
+ordinary templates. Ordinary templates take part in overloading resolution. As
+such their arguments need to be type checked before the template is invoked.
+So ordinary templates cannot receive undeclared identifiers:
+
+.. code-block:: nim
+
+  template declareInt(x: expr) = 
+    var x: int
+
+  declareInt(x) # error: unknown identifier: 'x'
+
+An ``immediate`` template does not participate in overload resolution and so
+its arguments are not checked for semantics before invocation. So they can
+receive undeclared identifiers:
+
+.. code-block:: nim
+
+  template declareInt(x: expr) {.immediate.} = 
+    var x: int
+
+  declareInt(x) # valid
+
+
+Passing a code block to a template
+----------------------------------
+
+If there is a ``stmt`` parameter it should be the last in the template
+declaration, because statements are passed to a template via a
+special ``:`` syntax:
+
+.. code-block:: nim
+
+  template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
+    var f: File
+    if open(f, fn, mode):
+      try:
+        actions
+      finally:
+        close(f)
+    else:
+      quit("cannot open: " & fn)
+      
+  withFile(txt, "ttempl3.txt", fmWrite):
+    txt.writeln("line 1")
+    txt.writeln("line 2")
+  
+In the example the two ``writeln`` statements are bound to the ``actions``
+parameter.
+
+
+Symbol binding in templates
+---------------------------
+
+A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are
+bound from the definition scope of the template:
+
+.. code-block:: nim
+  # Module A
+  var 
+    lastId = 0
+  
+  template genId*: expr =
+    inc(lastId)
+    lastId
+
+.. code-block:: nim
+  # Module B
+  import A
+  
+  echo genId() # Works as 'lastId' has been bound in 'genId's defining scope
+
+As in generics symbol binding can be influenced via ``mixin`` or ``bind`` 
+statements.
+
+
+
+Identifier construction
+-----------------------
+
+In templates identifiers can be constructed with the backticks notation:
+
+.. code-block:: nim
+
+  template typedef(name: expr, typ: typedesc) {.immediate.} = 
+    type
+      `T name`* {.inject.} = typ
+      `P name`* {.inject.} = ref `T name`
+      
+  typedef(myint, int)
+  var x: PMyInt
+
+In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes
+``Tmyint``.
+
+
+Lookup rules for template parameters
+------------------------------------
+
+A parameter ``p`` in a template is even substituted in the expression ``x.p``.
+Thus template arguments can be used as field names and a global symbol can be
+shadowed by the same argument name even when fully qualified:
+
+.. code-block:: nim
+  # module 'm'
+
+  type
+    Lev = enum
+      levA, levB
+
+  var abclev = levB
+
+  template tstLev(abclev: Lev) =
+    echo abclev, " ", m.abclev
+
+  tstLev(levA)
+  # produces: 'levA levA'
+  
+But the global symbol can properly be captured by a ``bind`` statement:
+
+.. code-block:: nim
+  # module 'm'
+
+  type
+    Lev = enum
+      levA, levB
+
+  var abclev = levB
+
+  template tstLev(abclev: Lev) =
+    bind m.abclev
+    echo abclev, " ", m.abclev
+
+  tstLev(levA)
+  # produces: 'levA levB'
+
+
+Hygiene in templates
+--------------------
+
+Per default templates are `hygienic`:idx:\: Local identifiers declared in a
+template cannot be accessed in the instantiation context:
+
+.. code-block:: nim
+  
+  template newException*(exceptn: typedesc, message: string): expr =
+    var
+      e: ref exceptn  # e is implicitly gensym'ed here
+    new(e)
+    e.msg = message
+    e
+    
+  # so this works:
+  let e = "message"
+  raise newException(EIO, e)
+
+
+Whether a symbol that is declared in a template is exposed to the instantiation
+scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas: gensym'ed
+symbols are not exposed but inject'ed are.
+
+The default for symbols of entity ``type``, ``var``, ``let`` and ``const``
+is ``gensym`` and for ``proc``, ``iterator``, ``converter``, ``template``,
+``macro`` is ``inject``. However, if the name of the entity is passed as a 
+template parameter, it is an inject'ed symbol:
+
+.. code-block:: nim
+  template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
+    block:
+      var f: File  # since 'f' is a template param, it's injected implicitly
+      ...
+      
+  withFile(txt, "ttempl3.txt", fmWrite):
+    txt.writeln("line 1")
+    txt.writeln("line 2")
+
+
+The ``inject`` and ``gensym`` pragmas are second class annotations; they have
+no semantics outside of a template definition and cannot be abstracted over:
+
+.. code-block:: nim
+  {.pragma myInject: inject.}
+  
+  template t() =
+    var x {.myInject.}: int # does NOT work
+
+
+To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for
+a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates.
+
+
+
+Limitations of the method call syntax
+-------------------------------------
+
+The expression ``x`` in ``x.f`` needs to be semantically checked (that means
+symbol lookup and type checking) before it can be decided that it needs to be
+rewritten to ``f(x)``. Therefore the dot syntax has some limiations when it
+is used to invoke templates/macros:
+
+.. code-block:: nim
+  template declareVar(name: expr): stmt =
+    const name {.inject.} = 45
+
+  # Doesn't compile:
+  unknownIdentifier.declareVar
+
+
+Another common example is this:
+
+.. code-block:: nim
+  from sequtils import toSeq
+
+  iterator something: string =
+    yield "Hello"
+    yield "World"
+
+  var info = toSeq(something())
+
+The problem here is that the compiler already decided that ``something()`` as
+an iterator is not callable in this context before ``toSeq`` gets its
+chance to convert it into a sequence.
+
+
+Macros
+======
+
+A macro is a special kind of low level template. Macros can be used
+to implement `domain specific languages`:idx:. Like templates, macros come in
+the 2 flavors *immediate* and *ordinary*.
+
+While macros enable advanced compile-time code transformations, they
+cannot change Nim's syntax. However, this is no real restriction because
+Nim's syntax is flexible enough anyway.
+
+To write macros, one needs to know how the Nim concrete syntax is converted
+to an abstract syntax tree.
+
+There are two ways to invoke a macro:
+(1) invoking a macro like a procedure call (`expression macros`)
+(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`)
+
+
+Expression Macros
+-----------------
+
+The following example implements a powerful ``debug`` command that accepts a
+variable number of arguments:
+
+.. code-block:: nim
+  # to work with Nim syntax trees, we need an API that is defined in the
+  # ``macros`` module:
+  import macros
+
+  macro debug(n: varargs[expr]): stmt =
+    # `n` is a Nim AST that contains the whole macro invocation
+    # this macro returns a list of statements:
+    result = newNimNode(nnkStmtList, n)
+    # iterate over any argument that is passed to this macro:
+    for i in 0..n.len-1:
+      # add a call to the statement list that writes the expression;
+      # `toStrLit` converts an AST to its string representation:
+      add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+      # add a call to the statement list that writes ": "
+      add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+      # add a call to the statement list that writes the expressions value:
+      add(result, newCall("writeln", newIdentNode("stdout"), n[i]))
+
+  var
+    a: array [0..10, int]
+    x = "some string"
+  a[0] = 42
+  a[1] = 45
+
+  debug(a[0], a[1], x)
+
+The macro call expands to:
+
+.. code-block:: nim
+  write(stdout, "a[0]")
+  write(stdout, ": ")
+  writeln(stdout, a[0])
+
+  write(stdout, "a[1]")
+  write(stdout, ": ")
+  writeln(stdout, a[1])
+
+  write(stdout, "x")
+  write(stdout, ": ")
+  writeln(stdout, x)
+
+
+Arguments that are passed to a ``varargs`` parameter are wrapped in an array
+constructor expression. This is why ``debug`` iterates over all of ``n``'s
+children.
+
+
+BindSym
+-------
+
+The above ``debug`` macro relies on the fact that ``write``, ``writeln`` and
+``stdout`` are declared in the system module and thus visible in the 
+instantiating context. There is a way to use bound identifiers
+(aka `symbols`:idx:) instead of using unbound identifiers. The ``bindSym`` 
+builtin can be used for that:
+
+.. code-block:: nim
+  import macros
+
+  macro debug(n: varargs[expr]): stmt =
+    result = newNimNode(nnkStmtList, n)
+    for i in 0..n.len-1:
+      # we can bind symbols in scope via 'bindSym':
+      add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i])))
+      add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": ")))
+      add(result, newCall(bindSym"writeln", bindSym"stdout", n[i]))
+
+  var
+    a: array [0..10, int]
+    x = "some string"
+  a[0] = 42
+  a[1] = 45
+
+  debug(a[0], a[1], x)
+
+The macro call expands to:
+
+.. code-block:: nim
+  write(stdout, "a[0]")
+  write(stdout, ": ")
+  writeln(stdout, a[0])
+
+  write(stdout, "a[1]")
+  write(stdout, ": ")
+  writeln(stdout, a[1])
+
+  write(stdout, "x")
+  write(stdout, ": ")
+  writeln(stdout, x)
+
+However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound
+and are not looked up again. As the example shows, ``bindSym`` does work with
+overloaded symbols implicitly.
+
+
+Statement Macros
+----------------
+
+Statement macros are defined just as expression macros. However, they are
+invoked by an expression following a colon.
+
+The following example outlines a macro that generates a lexical analyzer from
+regular expressions:
+
+.. code-block:: nim
+  import macros
+
+  macro case_token(n: stmt): stmt =
+    # creates a lexical analyzer from regular expressions
+    # ... (implementation is an exercise for the reader :-)
+    discard
+
+  case_token: # this colon tells the parser it is a macro statement
+  of r"[A-Za-z_]+[A-Za-z_0-9]*":
+    return tkIdentifier
+  of r"0-9+":
+    return tkInteger
+  of r"[\+\-\*\?]+":
+    return tkOperator
+  else:
+    return tkUnknown
+
+
+**Style note**: For code readability, it is the best idea to use the least
+powerful programming construct that still suffices. So the "check list" is:
+
+(1) Use an ordinary proc/iterator, if possible.
+(2) Else: Use a generic proc/iterator, if possible.
+(3) Else: Use a template, if possible.
+(4) Else: Use a macro.
+
+
+Macros as pragmas
+-----------------
+
+Whole routines (procs, iterators etc.) can also be passed to a template or 
+a macro via the pragma notation: 
+
+.. code-block:: nim
+  template m(s: stmt) = discard
+
+  proc p() {.m.} = discard
+
+This is a simple syntactic transformation into:
+
+.. code-block:: nim
+  template m(s: stmt) = discard
+
+  m:
+    proc p() = discard
+
diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt
new file mode 100644
index 000000000..f2b79a34f
--- /dev/null
+++ b/doc/manual/threads.txt
@@ -0,0 +1,208 @@
+Threads
+=======
+
+To enable thread support the ``--threads:on`` command line switch needs to
+be used. The ``system`` module then contains several threading primitives.
+See the `threads <threads.html>`_ and `channels <channels.html>`_ modules
+for the low level thread API. There are also high level parallelism constructs
+available. See `spawn`_ for further details.
+
+Nim's memory model for threads is quite different than that of other common
+programming languages (C, Pascal, Java): Each thread has its own (garbage
+collected) heap and sharing of memory is restricted to global variables. This
+helps to prevent race conditions. GC efficiency is improved quite a lot,
+because the GC never has to stop other threads and see what they reference.
+Memory allocation requires no lock at all! This design easily scales to massive
+multicore processors that are becoming the norm.
+
+
+Thread pragma
+-------------
+
+A proc that is executed as a new thread of execution should be marked by the
+``thread`` pragma for reasons of readability. The compiler checks for
+violations of the `no heap sharing restriction`:idx:\: This restriction implies
+that it is invalid to construct a data structure that consists of memory
+allocated from different (thread local) heaps.
+
+A thread proc is passed to ``createThread`` or ``spawn`` and invoked
+indirectly; so the ``thread`` pragma implies ``procvar``.
+
+
+GC safety
+---------
+
+We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable
+that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either
+directly or indirectly through a call to a GC unsafe proc.
+
+The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe,
+otherwise this property is inferred by the compiler. Note that ``noSideEffect``
+implies ``gcsafe``. The only way to create a thread is via ``spawn`` or
+``createThead``. ``spawn`` is usually the preferable method. Either way
+the invoked proc must not use ``var`` parameters nor must any of its parameters
+contain a ``ref`` or ``closure`` type. This enforces
+the *no heap sharing restriction*.
+
+Routines that are imported from C are always assumed to be ``gcsafe``.
+To disable the GC-safety checking the ``--threadAnalysis:off`` command line
+switch can be used. This is a temporary workaround to ease the porting effort
+from old code to the new threading model.
+
+
+Future directions:
+
+- A shared GC'ed heap might be provided.
+
+
+Threadvar pragma
+----------------
+
+A global variable can be marked with the ``threadvar`` pragma; it is
+a `thread-local`:idx: variable then:
+
+.. code-block:: nim
+  var checkpoints* {.threadvar.}: seq[string]
+
+Due to implementation restrictions thread local variables cannot be
+initialized within the ``var`` section. (Every thread local variable needs to
+be replicated at thread creation.)
+
+
+Threads and exceptions
+----------------------
+
+The interaction between threads and exceptions is simple: A *handled* exception
+in one thread cannot affect any other thread. However, an *unhandled* exception
+in one thread terminates the whole *process*!
+
+
+
+Parallel & Spawn
+================
+
+Nim has two flavors of parallelism:
+1) `Structured`:idx: parallelism via the ``parallel`` statement.
+2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement.
+
+Nim has a builtin thread pool that can be used for CPU intensive tasks. For
+IO intensive tasks the ``async`` and ``await`` features should be
+used instead. Both parallel and spawn need the `threadpool <threadpool.html>`_
+module to work.
+
+Somewhat confusingly, ``spawn`` is also used in the ``parallel`` statement
+with slightly different semantics. ``spawn`` always takes a call expression of
+the form ``f(a, ...)``. Let ``T`` be ``f``'s return type. If ``T`` is ``void``
+then ``spawn``'s return type is also ``void`` otherwise it is ``FlowVar[T]``.
+
+Within a ``parallel`` section sometimes the ``FlowVar[T]`` is eliminated
+to ``T``. This happens when ``T`` does not contain any GC'ed memory.
+The compiler can ensure the location in ``location = spawn f(...)`` is not
+read prematurely within a ``parallel`` section and so there is no need for
+the overhead of an indirection via ``FlowVar[T]`` to ensure correctness.
+
+**Note**: Currently exceptions are not propagated between ``spawn``'ed tasks!
+
+
+Spawn statement
+---------------
+
+`spawn`:idx: can be used to pass a task to the thread pool:
+
+.. code-block:: nim
+  import threadpool
+
+  proc processLine(line: string) =
+    discard "do some heavy lifting here"
+
+  for x in lines("myinput.txt"):
+    spawn processLine(x)
+  sync()
+
+For reasons of type safety and implementation simplicity the expression
+that ``spawn`` takes is restricted:
+
+* It must be a call expression ``f(a, ...)``.
+* ``f`` must be ``gcsafe``.
+* ``f`` must not have the calling convention ``closure``.
+* ``f``'s parameters may not be of type ``var``.
+  This means one has to use raw ``ptr``'s for data passing reminding the
+  programmer to be careful.
+* ``ref`` parameters are deeply copied which is a subtle semantic change and
+  can cause performance problems but ensures memory safety. This deep copy
+  is performed via ``system.deepCopy`` and so can be overriden.
+* For *safe* data exchange between ``f`` and the caller a global ``TChannel``
+  needs to be used. However, since spawn can return a result, often no further
+  communication is required.
+
+
+``spawn`` executes the passed expression on the thread pool and returns
+a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading
+with the ``^`` operator is **blocking**. However, one can use ``awaitAny`` to
+wait on multiple flow variables at the same time:
+
+.. code-block:: nim
+  import threadpool, ...
+
+  # wait until 2 out of 3 servers received the update:
+  proc main =
+    var responses = newSeq[FlowVarBase](3)
+    for i in 0..2:
+      responses[i] = spawn tellServer(Update, "key", "value")
+    var index = awaitAny(responses)
+    assert index >= 0
+    responses.del(index)
+    discard awaitAny(responses)
+
+Data flow variables ensure that no data races
+are possible. Due to technical limitations not every type ``T`` is possible in
+a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq``
+or of a type that doesn't contain a type that is garbage collected. This
+restriction is not hard to work-around in practice.
+
+
+
+Parallel statement
+------------------
+
+Example:
+
+.. code-block:: nim
+  # Compute PI in an inefficient way
+  import strutils, math, threadpool
+
+  proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1)
+
+  proc pi(n: int): float =
+    var ch = newSeq[float](n+1)
+    parallel:
+      for k in 0..ch.high:
+        ch[k] = spawn term(float(k))
+    for k in 0..ch.high:
+      result += ch[k]
+
+  echo formatFloat(pi(5000))
+
+
+The parallel statement is the preferred mechanism to introduce parallelism
+in a Nim program. A subset of the Nim language is valid within a
+``parallel`` section. This subset is checked to be free of data races at
+compile time. A sophisticated `disjoint checker`:idx: ensures that no data
+races are possible even though shared memory is extensively supported!
+
+The subset is in fact the full language with the following
+restrictions / changes:
+
+* ``spawn`` within a ``parallel`` section has special semantics.
+* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where
+  ``dest`` is part of the pattern ``dest = spawn f(...)`` has to be
+  provably disjoint. This is called the *disjoint check*.
+* Every other complex location ``loc`` that is used in a spawned
+  proc (``spawn f(loc)``) has to be immutable for the duration of
+  the ``parallel`` section. This is called the *immutability check*. Currently
+  it is not specified what exactly "complex location" means. We need to make
+  this an optimization!
+* Every array access has to be provably within bounds. This is called
+  the *bounds check*.
+* Slices are optimized so that no copy is performed. This optimization is not
+  yet performed for ordinary slices outside of a ``parallel`` section.
diff --git a/doc/manual/trmacros.txt b/doc/manual/trmacros.txt
new file mode 100644
index 000000000..5ff24a36a
--- /dev/null
+++ b/doc/manual/trmacros.txt
@@ -0,0 +1,367 @@
+Term rewriting macros
+=====================
+
+Term rewriting macros are macros or templates that have not only
+a *name* but also a *pattern* that is searched for after the semantic checking
+phase of the compiler: This means they provide an easy way to enhance the 
+compilation pipeline with user defined optimizations:
+
+.. code-block:: nim
+  template optMul{`*`(a, 2)}(a: int): int = a+a
+  
+  let x = 3
+  echo x * 2
+
+The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the
+curlies is the pattern to match against. The operators ``*``,  ``**``,
+``|``, ``~`` have a special meaning in patterns if they are written in infix 
+notation, so to match verbatim against ``*`` the ordinary function call syntax
+needs to be used.
+
+
+Unfortunately optimizations are hard to get right and even the tiny example
+is **wrong**: 
+
+.. code-block:: nim
+  template optMul{`*`(a, 2)}(a: int): int = a+a
+  
+  proc f(): int =
+    echo "side effect!"
+    result = 55
+  
+  echo f() * 2
+
+We cannot duplicate 'a' if it denotes an expression that has a side effect!
+Fortunately Nim supports side effect analysis:
+
+.. code-block:: nim
+  template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a
+  
+  proc f(): int =
+    echo "side effect!"
+    result = 55
+  
+  echo f() * 2 # not optimized ;-)
+
+You can make one overload matching with a constraint and one without, and the
+one with a constraint will have precedence, and so you can handle both cases
+differently.
+
+So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We
+cannot really do that however as the following code only swaps arguments
+blindly:
+
+.. code-block:: nim
+  template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a
+  
+What optimizers really need to do is a *canonicalization*:
+
+.. code-block:: nim
+  template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a
+
+The ``int{lit}`` parameter pattern matches against an expression of 
+type ``int``, but only if it's a literal.
+
+
+
+Parameter constraints
+---------------------
+
+The `parameter constraint`:idx: expression can use the operators ``|`` (or), 
+``&`` (and) and ``~`` (not) and the following predicates:
+
+===================      =====================================================
+Predicate                Meaning
+===================      =====================================================
+``atom``                 The matching node has no children.
+``lit``                  The matching node is a literal like "abc", 12.
+``sym``                  The matching node must be a symbol (a bound 
+                         identifier).
+``ident``                The matching node must be an identifier (an unbound
+                         identifier).
+``call``                 The matching AST must be a call/apply expression.
+``lvalue``               The matching AST must be an lvalue.
+``sideeffect``           The matching AST must have a side effect.
+``nosideeffect``         The matching AST must have no side effect.
+``param``                A symbol which is a parameter.
+``genericparam``         A symbol which is a generic parameter.
+``module``               A symbol which is a module.
+``type``                 A symbol which is a type.
+``var``                  A symbol which is a variable.
+``let``                  A symbol which is a ``let`` variable.
+``const``                A symbol which is a constant.
+``result``               The special ``result`` variable.
+``proc``                 A symbol which is a proc.
+``method``               A symbol which is a method.
+``iterator``             A symbol which is an iterator.
+``converter``            A symbol which is a converter.
+``macro``                A symbol which is a macro.
+``template``             A symbol which is a template.
+``field``                A symbol which is a field in a tuple or an object.
+``enumfield``            A symbol which is a field in an enumeration.
+``forvar``               A for loop variable.
+``label``                A label (used in ``block`` statements).
+``nk*``                  The matching AST must have the specified kind. 
+                         (Example: ``nkIfStmt`` denotes an ``if`` statement.)
+``alias``                States that the marked parameter needs to alias 
+                         with *some* other parameter.
+``noalias``              States that *every* other parameter must not alias
+                         with the marked parameter.
+===================      =====================================================
+
+Predicates that share their name with a keyword have to be escaped with 
+backticks: `` `const` ``.
+The ``alias`` and ``noalias`` predicates refer not only to the matching AST,
+but also to every other bound parameter; syntactically they need to occur after
+the ordinary AST predicates:
+
+.. code-block:: nim
+  template ex{a = b + c}(a: int{noalias}, b, c: int) =
+    # this transformation is only valid if 'b' and 'c' do not alias 'a':
+    a = b
+    inc a, c
+
+
+Pattern operators
+-----------------
+
+The operators ``*``,  ``**``, ``|``, ``~`` have a special meaning in patterns
+if they are written in infix notation.
+
+
+The ``|`` operator
+~~~~~~~~~~~~~~~~~~
+
+The ``|`` operator if used as infix operator creates an ordered choice:
+
+.. code-block:: nim
+  template t{0|1}(): expr = 3
+  let a = 1
+  # outputs 3:
+  echo a
+
+The matching is performed after the compiler performed some optimizations like
+constant folding, so the following does not work:
+
+.. code-block:: nim
+  template t{0|1}(): expr = 3
+  # outputs 1:
+  echo 1
+
+The reason is that the compiler already transformed the 1 into "1" for
+the ``echo`` statement. However, a term rewriting macro should not change the
+semantics anyway. In fact they can be deactivated with the ``--patterns:off``
+command line option or temporarily with the ``patterns`` pragma. 
+
+
+The ``{}`` operator
+~~~~~~~~~~~~~~~~~~~
+
+A pattern expression can be bound to a pattern parameter via the ``expr{param}``
+notation: 
+
+.. code-block:: nim
+  template t{(0|1|2){x}}(x: expr): expr = x+1
+  let a = 1
+  # outputs 2:
+  echo a
+
+
+The ``~`` operator
+~~~~~~~~~~~~~~~~~~
+
+The ``~`` operator is the **not** operator in patterns:
+
+.. code-block:: nim
+  template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt =
+    x = y
+    if x: x = z
+  
+  var
+    a = false
+    b = true
+    c = false
+  a = b and c
+  echo a
+
+
+The ``*`` operator
+~~~~~~~~~~~~~~~~~~
+
+The ``*`` operator can *flatten* a nested binary expression like ``a & b & c``
+to ``&(a, b, c)``: 
+
+.. code-block:: nim
+  var
+    calls = 0
+    
+  proc `&&`(s: varargs[string]): string =
+    result = s[0]
+    for i in 1..len(s)-1: result.add s[i]
+    inc calls
+
+  template optConc{ `&&` * a }(a: string): expr = &&a
+
+  let space = " "
+  echo "my" && (space & "awe" && "some " ) && "concat"
+
+  # check that it's been optimized properly:
+  doAssert calls == 1
+
+
+The second operator of `*` must be a parameter; it is used to gather all the
+arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"``
+is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) 
+which is flattened into a call expression; thus the invocation of ``optConc`` 
+produces:
+
+.. code-block:: nim
+   `&&`("my", space & "awe", "some ", "concat")
+
+
+The ``**`` operator
+~~~~~~~~~~~~~~~~~~~
+
+The ``**`` is much like the ``*`` operator, except that it gathers not only
+all the arguments, but also the matched operators in reverse polish notation:
+
+.. code-block:: nim
+  import macros
+
+  type
+    Matrix = object
+      dummy: int
+
+  proc `*`(a, b: Matrix): Matrix = discard
+  proc `+`(a, b: Matrix): Matrix = discard
+  proc `-`(a, b: Matrix): Matrix = discard
+  proc `$`(a: Matrix): string = result = $a.dummy
+  proc mat21(): Matrix =
+    result.dummy = 21
+
+  macro optM{ (`+`|`-`|`*`) ** a }(a: Matrix): expr =
+    echo treeRepr(a)
+    result = newCall(bindSym"mat21")
+
+  var x, y, z: Matrix
+
+  echo x + y * z - x 
+
+This passes the expression ``x + y * z - x`` to the ``optM`` macro as
+an ``nnkArgList`` node containing::
+
+  Arglist
+    Sym "x"
+    Sym "y"
+    Sym "z"
+    Sym "*"
+    Sym "+"
+    Sym "x"
+    Sym "-"
+
+(Which is the reverse polish notation of ``x + y * z - x``.)
+
+
+Parameters
+----------
+
+Parameters in a pattern are type checked in the matching process. If a 
+parameter is of the type ``varargs`` it is treated specially and it can match
+0 or more arguments in the AST to be matched against:
+
+.. code-block:: nim
+  template optWrite{
+    write(f, x)
+    ((write|writeln){w})(f, y)
+  }(x, y: varargs[expr], f: File, w: expr) =
+    w(f, x, y)
+  
+
+
+Example: Partial evaluation
+---------------------------
+
+The following example shows how some simple partial evaluation can be
+implemented with term rewriting:
+
+.. code-block:: nim
+  proc p(x, y: int; cond: bool): int =
+    result = if cond: x + y else: x - y
+
+  template optP1{p(x, y, true)}(x, y: expr): expr = x + y
+  template optP2{p(x, y, false)}(x, y: expr): expr = x - y
+
+
+Example: Hoisting
+-----------------
+
+The following example shows how some form of hoisting can be implemented:
+
+.. code-block:: nim
+  import pegs
+
+  template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
+    var gl {.global, gensym.} = peg(pattern)
+    gl
+
+  for i in 0 .. 3:
+    echo match("(a b c)", peg"'(' @ ')'")
+    echo match("W_HI_Le", peg"\y 'while'")
+
+The ``optPeg`` template optimizes the case of a peg constructor with a string
+literal, so that the pattern will only be parsed once at program startup and
+stored in a global ``gl`` which is then re-used. This optimization is called 
+hoisting because it is comparable to classical loop hoisting.
+
+
+AST based overloading
+=====================
+
+Parameter constraints can also be used for ordinary routine parameters; these
+constraints affect ordinary overloading resolution then:
+
+.. code-block:: nim
+  proc optLit(a: string{lit|`const`}) =
+    echo "string literal"
+  proc optLit(a: string) =
+    echo "no string literal"
+
+  const
+    constant = "abc"
+
+  var
+    variable = "xyz"
+
+  optLit("literal")
+  optLit(constant)
+  optLit(variable)
+
+However, the constraints ``alias`` and ``noalias`` are not available in
+ordinary routines.
+
+
+Move optimization
+-----------------
+
+The ``call`` constraint is particularly useful to implement a move 
+optimization for types that have copying semantics:
+
+.. code-block:: nim
+  proc `[]=`*(t: var Table, key: string, val: string) =
+    ## puts a (key, value)-pair into `t`. The semantics of string require
+    ## a copy here:
+    let idx = findInsertionPosition(key)
+    t[idx].key = key
+    t[idx].val = val
+
+  proc `[]=`*(t: var Table, key: string{call}, val: string{call}) =
+    ## puts a (key, value)-pair into `t`. Optimized version that knows that
+    ## the strings are unique and thus don't need to be copied:
+    let idx = findInsertionPosition(key)
+    shallowCopy t[idx].key, key
+    shallowCopy t[idx].val, val
+
+  var t: Table
+  # overloading resolution ensures that the optimized []= is called here:
+  t[f()] = g()
+
diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt
new file mode 100644
index 000000000..c707979fe
--- /dev/null
+++ b/doc/manual/type_bound_ops.txt
@@ -0,0 +1,134 @@
+Type bound operations
+=====================
+
+There are 3 operations that are bound to a type:
+
+1. Assignment
+2. Destruction
+3. Deep copying for communication between threads
+
+These operations can be *overriden* instead of *overloaded*. This means the
+implementation is automatically lifted to structured types. For instance if type
+``T`` has an overriden assignment operator ``=`` this operator is also used
+for assignments of the type ``seq[T]``. Since these operations are bound to a
+type they have to be bound to a nominal type for reasons of simplicity of
+implementation: This means an overriden ``deepCopy`` for ``ref T`` is really
+bound to ``T`` and not to ``ref T``. This also means that one cannot override
+``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a
+helper distinct or object type has to be used for one pointer type.
+
+
+operator `=`
+------------
+
+This operator is the assignment operator. Note that in the contexts
+``result = expr``, ``parameter = defaultValue`` or for
+parameter passing no assignment is performed. For a type ``T`` that has an
+overloaded assignment operator ``var v = T()`` is rewritten
+to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count
+as assignments.
+
+The assignment operator needs to be attached to an object or distinct
+type ``T``. Its signature has to be ``(var T, T)``. Example:
+
+.. code-block:: nim
+  type
+    Concrete = object
+      a, b: string
+
+  proc `=`(d: var Concrete; src: Concrete) =
+    shallowCopy(d.a, src.a)
+    shallowCopy(d.b, src.b)
+    echo "Concrete '=' called"
+
+  var x, y: array[0..2, Concrete]
+  var cA, cB: Concrete
+
+  var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+  x = y
+  cA = cB
+  cATup = cBTup
+
+
+
+destructors
+-----------
+
+A destructor must have a single parameter with a concrete type (the name of a
+generic type is allowed too). The name of the destructor has to be ``=destroy``.
+
+``=destroy(v)`` will be automatically invoked for every local stack
+variable ``v`` that goes out of scope.
+
+If a structured type features a field with destructable type and
+the user has not provided an explicit implementation, a destructor for the
+structured type will be automatically generated. Calls to any base class
+destructors in both user-defined and generated destructors will be inserted.
+
+A destructor is attached to the type it destructs; expressions of this type
+can then only be used in *destructible contexts* and as parameters:
+
+.. code-block:: nim
+  type
+    MyObj = object
+      x, y: int
+      p: pointer
+
+  proc `=destroy`(o: var MyObj) =
+    if o.p != nil: dealloc o.p
+
+  proc open: MyObj =
+    result = MyObj(x: 1, y: 2, p: alloc(3))
+
+  proc work(o: MyObj) =
+    echo o.x
+    # No destructor invoked here for 'o' as 'o' is a parameter.
+
+  proc main() =
+    # destructor automatically invoked at the end of the scope:
+    var x = open()
+    # valid: pass 'x' to some other proc:
+    work(x)
+
+    # Error: usage of a type with a destructor in a non destructible context
+    echo open()
+
+A destructible context is currently only the following:
+
+1. The ``expr`` in ``var x = expr``.
+2. The ``expr`` in ``let x = expr``.
+3. The ``expr`` in ``return expr``.
+4. The ``expr`` in ``result = expr`` where ``result`` is the special symbol
+   introduced by the compiler.
+
+These rules ensure that the construction is tied to a variable and can easily
+be destructed at its scope exit. Later versions of the language will improve
+the support of destructors.
+
+Be aware that destructors are not called for objects allocated with ``new``.
+This may change in future versions of language, but for now the `finalizer`:idx:
+parameter to ``new`` has to be used.
+
+**Note**: Destructors are still experimental and the spec might change
+significantly in order to incorporate an escape analysis.
+
+
+deepCopy
+--------
+
+``=deepCopy`` is a builtin that is invoked whenever data is passed to
+a ``spawn``'ed proc to ensure memory safety. The programmer can override its
+behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the
+language may weaken this restriction.)
+
+The signature has to be:
+
+.. code-block:: nim
+  proc `=deepCopy`(x: T): T
+
+This mechanism will be used by most data structures that support shared memory
+like channels to implement thread safe automatic memory management.
+
+The builtin ``deepCopy`` can even clone closures and their environments. See
+the documentation of `spawn`_ for details.
diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt
new file mode 100644
index 000000000..5c8372e1e
--- /dev/null
+++ b/doc/manual/type_rel.txt
@@ -0,0 +1,342 @@
+Type relations
+==============
+
+The following section defines several relations on types that are needed to
+describe the type checking done by the compiler.
+
+
+Type equality
+-------------
+Nim uses structural type equivalence for most types. Only for objects,
+enumerations and distinct types name equivalence is used. The following
+algorithm, *in pseudo-code*, determines type equality:
+
+.. code-block:: nim
+  proc typeEqualsAux(a, b: PType,
+                     s: var HashSet[(PType, PType)]): bool =
+    if (a,b) in s: return true
+    incl(s, (a,b))
+    if a.kind == b.kind:
+      case a.kind
+      of int, intXX, float, floatXX, char, string, cstring, pointer,
+          bool, nil, void:
+        # leaf type: kinds identical; nothing more to check
+        result = true
+      of ref, ptr, var, set, seq, openarray:
+        result = typeEqualsAux(a.baseType, b.baseType, s)
+      of range:
+        result = typeEqualsAux(a.baseType, b.baseType, s) and
+          (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB)
+      of array:
+        result = typeEqualsAux(a.baseType, b.baseType, s) and
+                 typeEqualsAux(a.indexType, b.indexType, s)
+      of tuple:
+        if a.tupleLen == b.tupleLen:
+          for i in 0..a.tupleLen-1:
+            if not typeEqualsAux(a[i], b[i], s): return false
+          result = true
+      of object, enum, distinct:
+        result = a == b
+      of proc:
+        result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and
+                 typeEqualsAux(a.resultType, b.resultType, s) and
+                 a.callingConvention == b.callingConvention
+
+  proc typeEquals(a, b: PType): bool =
+    var s: HashSet[(PType, PType)] = {}
+    result = typeEqualsAux(a, b, s)
+
+Since types are graphs which can have cycles, the above algorithm needs an
+auxiliary set ``s`` to detect this case.
+
+
+Type equality modulo type distinction
+-------------------------------------
+
+The following algorithm (in pseudo-code) determines whether two types
+are equal with no respect to ``distinct`` types. For brevity the cycle check
+with an auxiliary set ``s`` is omitted:
+
+.. code-block:: nim
+  proc typeEqualsOrDistinct(a, b: PType): bool =
+    if a.kind == b.kind:
+      case a.kind
+      of int, intXX, float, floatXX, char, string, cstring, pointer,
+          bool, nil, void:
+        # leaf type: kinds identical; nothing more to check
+        result = true
+      of ref, ptr, var, set, seq, openarray:
+        result = typeEqualsOrDistinct(a.baseType, b.baseType)
+      of range:
+        result = typeEqualsOrDistinct(a.baseType, b.baseType) and
+          (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB)
+      of array:
+        result = typeEqualsOrDistinct(a.baseType, b.baseType) and
+                 typeEqualsOrDistinct(a.indexType, b.indexType)
+      of tuple:
+        if a.tupleLen == b.tupleLen:
+          for i in 0..a.tupleLen-1:
+            if not typeEqualsOrDistinct(a[i], b[i]): return false
+          result = true
+      of distinct:
+        result = typeEqualsOrDistinct(a.baseType, b.baseType)
+      of object, enum:
+        result = a == b
+      of proc:
+        result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and
+                 typeEqualsOrDistinct(a.resultType, b.resultType) and
+                 a.callingConvention == b.callingConvention
+    elif a.kind == distinct:
+      result = typeEqualsOrDistinct(a.baseType, b)
+    elif b.kind == distinct:
+      result = typeEqualsOrDistinct(a, b.baseType)
+
+
+Subtype relation
+----------------
+If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype
+relation is extended to the types ``var``, ``ref``, ``ptr``:
+
+.. code-block:: nim
+  proc isSubtype(a, b: PType): bool =
+    if a.kind == b.kind:
+      case a.kind
+      of object:
+        var aa = a.baseType
+        while aa != nil and aa != b: aa = aa.baseType
+        result = aa == b
+      of var, ref, ptr:
+        result = isSubtype(a.baseType, b.baseType)
+
+.. XXX nil is a special value!
+
+
+Convertible relation
+--------------------
+A type ``a`` is **implicitly** convertible to type ``b`` iff the following
+algorithm returns true:
+
+.. code-block:: nim
+  # XXX range types?
+  proc isImplicitlyConvertible(a, b: PType): bool =
+    case a.kind
+    of int:     result = b in {int8, int16, int32, int64, uint, uint8, uint16,
+                               uint32, uint64, float, float32, float64}
+    of int8:    result = b in {int16, int32, int64, int}
+    of int16:   result = b in {int32, int64, int}
+    of int32:   result = b in {int64, int}
+    of uint:    result = b in {uint32, uint64}
+    of uint8:   result = b in {uint16, uint32, uint64}
+    of uint16:  result = b in {uint32, uint64}
+    of uint32:  result = b in {uint64}
+    of float:   result = b in {float32, float64}
+    of float32: result = b in {float64, float}
+    of float64: result = b in {float32, float}
+    of seq:
+      result = b == openArray and typeEquals(a.baseType, b.baseType)
+    of array:
+      result = b == openArray and typeEquals(a.baseType, b.baseType)
+      if a.baseType == char and a.indexType.rangeA == 0:
+        result = b = cstring
+    of cstring, ptr:
+      result = b == pointer
+    of string:
+      result = b == cstring
+
+A type ``a`` is **explicitly** convertible to type ``b`` iff the following
+algorithm returns true:
+
+.. code-block:: nim
+  proc isIntegralType(t: PType): bool =
+    result = isOrdinal(t) or t.kind in {float, float32, float64}
+
+  proc isExplicitlyConvertible(a, b: PType): bool =
+    result = false
+    if isImplicitlyConvertible(a, b): return true
+    if typeEqualsOrDistinct(a, b): return true
+    if isIntegralType(a) and isIntegralType(b): return true
+    if isSubtype(a, b) or isSubtype(b, a): return true
+
+The convertible relation can be relaxed by a user-defined type
+`converter`:idx:.
+
+.. code-block:: nim
+  converter toInt(x: char): int = result = ord(x)
+
+  var
+    x: int
+    chr: char = 'a'
+
+  # implicit conversion magic happens here
+  x = chr
+  echo x # => 97
+  # you can use the explicit form too
+  x = chr.toInt
+  echo x # => 97
+
+The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and
+``typeEqualsOrDistinct(T, type(a))`` holds.
+
+
+Assignment compatibility
+------------------------
+
+An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an
+`l-value` and ``isImplicitlyConvertible(b.typ, a.typ)`` holds.
+
+
+Overloading resolution
+======================
+
+In a call ``p(args)`` the routine ``p`` that matches best is selected. If
+multiple routines match equally well, the ambiguity is reported at compiletime.
+
+Every arg in args needs to match. There are multiple different category how an
+argument can match. Let ``f`` be the formal parameter's type and ``a`` the type
+of the argument.
+
+1. Exact match: ``a`` and ``f`` are of the same type.
+2. Literal match: ``a`` is an integer literal of value ``v``
+   and ``f`` is a signed or unsigned integer type and ``v`` is in ``f``'s
+   range. Or:  ``a`` is a floating point literal of value ``v``
+   and ``f`` is a floating point type and ``v`` is in ``f``'s
+   range.
+3. Generic match: ``f`` is a generic type and ``a`` matches, for
+   instance ``a`` is ``int`` and ``f`` is a generic (constrained) parameter
+   type (like in ``[T]`` or ``[T: int|char]``.
+4. Subrange or subtype match: ``a`` is a ``range[T]`` and ``T``
+   matches ``f`` exactly. Or: ``a`` is a subtype of ``f``.
+5. Integral conversion match: ``a`` is convertible to ``f`` and ``f`` and ``a``
+   is some integer or floating point type.
+6. Conversion match: ``a`` is convertible to ``f``, possibly via a user
+   defined ``converter``.
+
+These matching categories have a priority: An exact match is better than a
+literal match and that is better than a generic match etc. In the following
+``count(p, m)`` counts the number of matches of the matching category ``m``
+for the routine ``p``.
+
+A routine ``p`` matches better than a routine ``q`` if the following
+algorithm returns true::
+
+  for each matching category m in ["exact match", "literal match",
+                                  "generic match", "subtype match",
+                                  "integral match", "conversion match"]:
+    if count(p, m) > count(q, m): return true
+    elif count(p, m) == count(q, m):
+      discard "continue with next category m"
+    else:
+      return false
+  return "ambiguous"
+
+
+Some examples:
+
+.. code-block:: nim
+  proc takesInt(x: int) = echo "int"
+  proc takesInt[T](x: T) = echo "T"
+  proc takesInt(x: int16) = echo "int16"
+
+  takesInt(4) # "int"
+  var x: int32
+  takesInt(x) # "T"
+  var y: int16
+  takesInt(y) # "int16"
+  var z: range[0..4] = 0
+  takesInt(z) # "T"
+
+
+If this algorithm returns "ambiguous" further disambiguation is performed:
+If the argument ``a`` matches both the parameter type ``f`` of ``p``
+and ``g`` of ``q`` via a subtyping relation, the inheritance depth is taken
+into account:
+
+.. code-block:: nim
+  type
+    A = object of RootObj
+    B = object of A
+    C = object of B
+
+  proc p(obj: A) =
+    echo "A"
+
+  proc p(obj: B) =
+    echo "B"
+
+  var c = C()
+  # not ambiguous, calls 'B', not 'A' since B is a subtype of A
+  # but not vice versa:
+  p(c)
+
+  proc pp(obj: A, obj2: B) = echo "A B"
+  proc pp(obj: B, obj2: A) = echo "B A"
+
+  # but this is ambiguous:
+  pp(c, c)
+
+
+Likewise for generic matches the most specialized generic type (that still
+matches) is preferred:
+
+.. code-block:: nim
+  proc gen[T](x: ref ref T) = echo "ref ref T"
+  proc gen[T](x: ref T) = echo "ref T"
+  proc gen[T](x: T) = echo "T"
+
+  var ri: ref int
+  gen(ri) # "ref T"
+
+
+Overloading based on 'var T'
+----------------------------
+
+If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary
+type checking, the argument is checked to be an `l-value`:idx:. ``var T``
+matches better than just ``T`` then.
+
+
+Automatic dereferencing
+-----------------------
+
+If the `experimental mode <experimental pragma>`_ is active and no other match
+is found, the first argument ``a`` is dereferenced automatically if it's a
+pointer type and overloading resolution is tried with ``a[]`` instead.
+
+
+Lazy type resolution for expr
+-----------------------------
+
+**Note**: An `unresolved`:idx: expression is an expression for which no symbol
+lookups and no type checking have been performed.
+
+Since templates and macros that are not declared as ``immediate`` participate
+in overloading resolution it's essential to have a way to pass unresolved
+expressions to a template or macro. This is what the meta-type ``expr``
+accomplishes:
+
+.. code-block:: nim
+  template rem(x: expr) = discard
+
+  rem unresolvedExpression(undeclaredIdentifier)
+
+A parameter of type ``expr`` always matches any argument (as long as there is
+any argument passed to it).
+
+But one has to watch out because other overloads might trigger the
+argument's resolution:
+
+.. code-block:: nim
+  template rem(x: expr) = discard
+  proc rem[T](x: T) = discard
+
+  # undeclared identifier: 'unresolvedExpression'
+  rem unresolvedExpression(undeclaredIdentifier)
+
+``expr`` is the only metatype that is lazy in this sense, the other
+metatypes ``stmt`` and ``typedesc`` are not lazy.
+
+
+Varargs matching
+----------------
+
+See `Varargs`_.
diff --git a/doc/manual/type_sections.txt b/doc/manual/type_sections.txt
new file mode 100644
index 000000000..8420a0098
--- /dev/null
+++ b/doc/manual/type_sections.txt
@@ -0,0 +1,23 @@
+Type sections
+=============
+
+Example:
+
+.. code-block:: nim
+  type # example demonstrating mutually recursive types
+    Node = ref NodeObj # a traced pointer to a NodeObj
+    NodeObj = object
+      le, ri: Node     # left and right subtrees
+      sym: ref Sym     # leaves contain a reference to a Sym
+
+    Sym = object       # a symbol
+      name: string     # the symbol's name
+      line: int        # the line the symbol was declared in
+      code: Node      # the symbol's abstract syntax tree
+
+A type section begins with the ``type`` keyword. It contains multiple
+type definitions. A type definition binds a type to a name. Type definitions
+can be recursive or even mutually recursive. Mutually recursive types are only
+possible within a single ``type`` section. Nominal types like ``objects`` 
+or ``enums`` can only be defined in a ``type`` section.
+
diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt
new file mode 100644
index 000000000..de1d84d7d
--- /dev/null
+++ b/doc/manual/typedesc.txt
@@ -0,0 +1,127 @@
+Special Types
+=============
+
+static[T]
+---------
+
+**Note**: static[T] is still in development.
+
+As their name suggests, static parameters must be known at compile-time:
+
+.. code-block:: nim
+
+  proc precompiledRegex(pattern: static[string]): RegEx =
+    var res {.global.} = re(pattern)
+    return res
+
+  precompiledRegex("/d+") # Replaces the call with a precompiled
+                          # regex, stored in a global variable
+
+  precompiledRegex(paramStr(1)) # Error, command-line options
+                                # are not known at compile-time
+
+
+For the purposes of code generation, all static params are treated as
+generic params - the proc will be compiled separately for each unique
+supplied value (or combination of values).
+
+Static params can also appear in the signatures of generic types:
+
+.. code-block:: nim
+
+  type
+    Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T]
+      # Note how `Number` is just a type constraint here, while
+      # `static[int]` requires us to supply a compile-time int value
+
+    AffineTransform2D[T] = Matrix[3, 3, T]
+    AffineTransform3D[T] = Matrix[4, 4, T]
+
+  var m1: AffineTransform3D[float]  # OK
+  var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
+
+
+typedesc
+--------
+
+`typedesc` is a special type allowing one to treat types as compile-time values
+(i.e. if types are compile-time values and all values have a type, then
+typedesc must be their type).
+
+When used as a regular proc param, typedesc acts as a type class. The proc
+will be instantiated for each unique type parameter and one can refer to the
+instantiation type using the param name:
+
+.. code-block:: nim
+
+  proc new(T: typedesc): ref T =
+    echo "allocating ", T.name
+    new(result)
+
+  var n = Node.new
+  var tree = new(BinaryTree[int])
+
+When multiple typedesc params are present, they act like a distinct type class
+(i.e. they will bind freely to different types). To force a bind-once behavior
+one can use a named alias or an explicit `typedesc` generic param:
+
+.. code-block:: nim
+  proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U)
+
+Once bound, typedesc params can appear in the rest of the proc signature:
+
+.. code-block:: nim
+
+  template declareVariableWithType(T: typedesc, value: T) =
+    var x: T = value
+
+  declareVariableWithType int, 42
+
+When used with macros and .compileTime. procs on the other hand, the compiler
+does not need to instantiate the code multiple times, because types then can be
+manipulated using the unified internal symbol representation. In such context
+typedesc acts as any other type. One can create variables, store typedesc
+values inside containers and so on. For example, here is how one can create
+a type-safe wrapper for the unsafe `printf` function from C:
+
+.. code-block:: nim
+  macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr =
+    var i = 0
+    for c in formatChars(formatString):
+      var expectedType = case c
+        of 'c': char
+        of 'd', 'i', 'x', 'X': int
+        of 'f', 'e', 'E', 'g', 'G': float
+        of 's': string
+        of 'p': pointer
+        else: EOutOfRange
+
+      var actualType = args[i].getType
+      inc i
+
+      if expectedType == EOutOfRange:
+        error c & " is not a valid format character"
+      elif expectedType != actualType:
+        error "type mismatch for argument ", i, ". expected type: ",
+              expectedType.name, ", actual type: ", actualType.name
+
+    # keep the original callsite, but use cprintf instead
+    result = callsite()
+    result[0] = newIdentNode(!"cprintf")
+
+
+Overload resolution can be further influenced by constraining the set of
+types that will match the typedesc param:
+
+.. code-block:: nim
+
+  template maxval(T: typedesc[int]): int = high(int)
+  template maxval(T: typedesc[float]): float = Inf
+
+  var i = int.maxval
+  var f = float.maxval
+  var s = string.maxval # error, maxval is not implemented for string
+
+The constraint can be a concrete type or a type class.
+
+
diff --git a/doc/manual/types.txt b/doc/manual/types.txt
new file mode 100644
index 000000000..81ae9d6b4
--- /dev/null
+++ b/doc/manual/types.txt
@@ -0,0 +1,1199 @@
+Types
+=====
+
+All expressions have a type which is known at compile time. Nim
+is statically typed. One can declare new types, which is in essence defining
+an identifier that can be used to denote this custom type.
+
+These are the major type classes:
+
+* ordinal types (consist of integer, bool, character, enumeration
+  (and subranges thereof) types)
+* floating point types
+* string type
+* structured types
+* reference (pointer) type
+* procedural type
+* generic type
+
+
+Ordinal types
+-------------
+Ordinal types have the following characteristics:
+
+- Ordinal types are countable and ordered. This property allows
+  the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to
+  be defined.
+- Ordinal values have a smallest possible value. Trying to count further
+  down than the smallest value gives a checked runtime or static error.
+- Ordinal values have a largest possible value. Trying to count further
+  than the largest value gives a checked runtime or static error.
+
+Integers, bool, characters and enumeration types (and subranges of these
+types) belong to ordinal types. For reasons of simplicity of implementation
+the types ``uint`` and ``uint64`` are not ordinal types.
+
+
+Pre-defined integer types
+-------------------------
+These integer types are pre-defined:
+
+``int``
+  the generic signed integer type; its size is platform dependent and has the
+  same size as a pointer. This type should be used in general. An integer
+  literal that has no type suffix is of this type.
+
+intXX
+  additional signed integer types of XX bits use this naming scheme
+  (example: int16 is a 16 bit wide integer).
+  The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``.
+  Literals of these types have the suffix 'iXX.
+
+``uint``
+  the generic `unsigned integer`:idx: type; its size is platform dependent and
+  has the same size as a pointer. An integer literal with the type
+  suffix ``'u`` is of this type.
+
+uintXX
+  additional signed integer types of XX bits use this naming scheme
+  (example: uint16 is a 16 bit wide unsigned integer).
+  The current implementation supports ``uint8``, ``uint16``, ``uint32``,
+  ``uint64``. Literals of these types have the suffix 'uXX.
+  Unsigned operations all wrap around; they cannot lead to over- or
+  underflow errors.
+
+
+In addition to the usual arithmetic operators for signed and unsigned integers
+(``+ - *`` etc.) there are also operators that formally work on *signed*
+integers but treat their arguments as *unsigned*: They are mostly provided
+for backwards compatibility with older versions of the language that lacked
+unsigned integer types. These unsigned operations for signed integers use
+the ``%`` suffix as convention:
+
+
+======================   ======================================================
+operation                meaning
+======================   ======================================================
+``a +% b``               unsigned integer addition
+``a -% b``               unsigned integer subtraction
+``a *% b``               unsigned integer multiplication
+``a /% b``               unsigned integer division
+``a %% b``               unsigned integer modulo operation
+``a <% b``               treat ``a`` and ``b`` as unsigned and compare
+``a <=% b``              treat ``a`` and ``b`` as unsigned and compare
+``ze(a)``                extends the bits of ``a`` with zeros until it has the
+                         width of the ``int`` type
+``toU8(a)``              treats ``a`` as unsigned and converts it to an
+                         unsigned integer of 8 bits (but still the
+                         ``int8`` type)
+``toU16(a)``             treats ``a`` as unsigned and converts it to an
+                         unsigned integer of 16 bits (but still the
+                         ``int16`` type)
+``toU32(a)``             treats ``a`` as unsigned and converts it to an
+                         unsigned integer of 32 bits (but still the
+                         ``int32`` type)
+======================   ======================================================
+
+`Automatic type conversion`:idx: is performed in expressions where different
+kinds of integer types are used: the smaller type is converted to the larger.
+
+A `narrowing type conversion`:idx: converts a larger to a smaller type (for
+example ``int32 -> int16``. A `widening type conversion`:idx: converts a
+smaller type to a larger type (for example ``int16 -> int32``). In Nim only
+widening type conversions are *implicit*:
+
+.. code-block:: nim
+  var myInt16 = 5i16
+  var myInt: int
+  myInt16 + 34     # of type ``int16``
+  myInt16 + myInt  # of type ``int``
+  myInt16 + 2i32   # of type ``int32``
+
+However, ``int`` literals are implicitly convertible to a smaller integer type
+if the literal's value fits this smaller type and such a conversion is less
+expensive than other implicit conversions, so ``myInt16 + 34`` produces
+an ``int16`` result.
+
+For further details, see `Convertible relation`_.
+
+
+Subrange types
+--------------
+A subrange type is a range of values from an ordinal type (the base
+type). To define a subrange type, one must specify it's limiting values: the
+lowest and highest value of the type:
+
+.. code-block:: nim
+  type
+    Subrange = range[0..5]
+
+
+``Subrange`` is a subrange of an integer which can only hold the values 0
+to 5. Assigning any other value to a variable of type ``Subrange`` is a
+checked runtime error (or static error if it can be statically
+determined). Assignments from the base type to one of its subrange types
+(and vice versa) are allowed.
+
+A subrange type has the same size as its base type (``int`` in the example).
+
+Nim requires `interval arithmetic`:idx: for subrange types over a set
+of built-in operators that involve constants: ``x %% 3`` is of
+type ``range[0..2]``. The following built-in operators for integers are
+affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``,
+``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``).
+
+Bitwise ``and`` only produces a ``range`` if one of its operands is a
+constant *x* so that (x+1) is a number of two.
+(Bitwise ``and`` is then a ``%%`` operation.)
+
+This means that the following code is accepted:
+
+.. code-block:: nim
+  case (x and 3) + 7
+  of 7: echo "A"
+  of 8: echo "B"
+  of 9: echo "C"
+  of 10: echo "D"
+  # note: no ``else`` required as (x and 3) + 7 has the type: range[7..10]
+
+
+Pre-defined floating point types
+--------------------------------
+
+The following floating point types are pre-defined:
+
+``float``
+  the generic floating point type; its size is platform dependent
+  (the compiler chooses the processor's fastest floating point type).
+  This type should be used in general.
+
+floatXX
+  an implementation may define additional floating point types of XX bits using
+  this naming scheme (example: float64 is a 64 bit wide float). The current
+  implementation supports ``float32`` and ``float64``. Literals of these types
+  have the suffix 'fXX.
+
+
+Automatic type conversion in expressions with different kinds
+of floating point types is performed: See `Convertible relation`_ for further
+details. Arithmetic performed on floating point types follows the IEEE
+standard. Integer types are not converted to floating point types automatically
+and vice versa.
+
+The IEEE standard defines five types of floating-point exceptions:
+
+* Invalid: operations with mathematically invalid operands,
+  for example 0.0/0.0, sqrt(-1.0), and log(-37.8).
+* Division by zero: divisor is zero and dividend is a finite nonzero number,
+  for example 1.0/0.0.
+* Overflow: operation produces a result that exceeds the range of the exponent,
+  for example MAXDOUBLE+0.0000000000001e308.
+* Underflow: operation produces a result that is too small to be represented
+  as a normal number, for example, MINDOUBLE * MINDOUBLE.
+* Inexact: operation produces a result that cannot be represented with infinite
+  precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
+
+The IEEE exceptions are either ignored at runtime or mapped to the
+Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
+`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
+and `FloatInexactError`:idx:.
+These exceptions inherit from the `FloatingPointError`:idx: base class.
+
+Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control
+whether the IEEE exceptions are ignored or trap a Nim exception:
+
+.. code-block:: nim
+  {.NanChecks: on, InfChecks: on.}
+  var a = 1.0
+  var b = 0.0
+  echo b / b # raises FloatInvalidOpError
+  echo a / b # raises FloatOverflowError
+
+In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError``
+are never raised. ``FloatOverflowError`` is raised instead of
+``FloatDivByZeroError``.
+There is also a `floatChecks`:idx: pragma that is a short-cut for the
+combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are
+turned off as default.
+
+The only operations that are affected by the ``floatChecks`` pragma are
+the ``+``, ``-``, ``*``, ``/`` operators for floating point types.
+
+An implementation should always use the maximum precision available to evaluate
+floating pointer values at compile time; this means expressions like
+``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` are true.
+
+
+Boolean type
+------------
+The boolean type is named `bool`:idx: in Nim and can be one of the two
+pre-defined values ``true`` and ``false``. Conditions in while,
+if, elif, when statements need to be of type bool.
+
+This condition holds::
+
+  ord(false) == 0 and ord(true) == 1
+
+The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined
+for the bool type. The ``and`` and ``or`` operators perform short-cut
+evaluation. Example:
+
+.. code-block:: nim
+
+  while p != nil and p.name != "xyz":
+    # p.name is not evaluated if p == nil
+    p = p.next
+
+
+The size of the bool type is one byte.
+
+
+Character type
+--------------
+The character type is named ``char`` in Nim. Its size is one byte.
+Thus it cannot represent an UTF-8 character, but a part of it.
+The reason for this is efficiency: for the overwhelming majority of use-cases,
+the resulting programs will still handle UTF-8 properly as UTF-8 was specially
+designed for this.
+Another reason is that Nim can support ``array[char, int]`` or
+``set[char]`` efficiently as many algorithms rely on this feature. The
+`Rune` type is used for Unicode characters, it can represent any Unicode
+character. ``Rune`` is declared in the `unicode module <unicode.html>`_.
+
+
+
+
+Enumeration types
+-----------------
+Enumeration types define a new type whose values consist of the ones
+specified. The values are ordered. Example:
+
+.. code-block:: nim
+
+  type
+    Direction = enum
+      north, east, south, west
+
+
+Now the following holds::
+
+  ord(north) == 0
+  ord(east) == 1
+  ord(south) == 2
+  ord(west) == 3
+
+Thus, north < east < south < west. The comparison operators can be used
+with enumeration types.
+
+For better interfacing to other programming languages, the fields of enum
+types can be assigned an explicit ordinal value. However, the ordinal values
+have to be in ascending order. A field whose ordinal value is not
+explicitly given is assigned the value of the previous field + 1.
+
+An explicit ordered enum can have *holes*:
+
+.. code-block:: nim
+  type
+    TokenType = enum
+      a = 2, b = 4, c = 89 # holes are valid
+
+However, it is then not an ordinal anymore, so it is not possible to use these
+enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ``
+and ``pred`` are not available for them either.
+
+
+The compiler supports the built-in stringify operator ``$`` for enumerations.
+The stringify's result can be controlled by explicitly giving the string
+values to use:
+
+.. code-block:: nim
+
+  type
+    MyEnum = enum
+      valueA = (0, "my value A"),
+      valueB = "value B",
+      valueC = 2,
+      valueD = (3, "abc")
+
+As can be seen from the example, it is possible to both specify a field's
+ordinal value and its string value by using a tuple. It is also
+possible to only specify one of them.
+
+An enum can be marked with the ``pure`` pragma so that it's fields are not
+added to the current scope, so they always need to be accessed
+via ``MyEnum.value``:
+
+.. code-block:: nim
+
+  type
+    MyEnum {.pure.} = enum
+      valueA, valueB, valueC, valueD
+
+  echo valueA # error: Unknown identifier
+  echo MyEnum.valueA # works
+
+
+String type
+-----------
+All string literals are of the type ``string``. A string in Nim is very
+similar to a sequence of characters. However, strings in Nim are both
+zero-terminated and have a length field. One can retrieve the length with the
+builtin ``len`` procedure; the length never counts the terminating zero.
+The assignment operator for strings always copies the string.
+The ``&`` operator concatenates strings.
+
+Strings are compared by their lexicographical order. All comparison operators
+are available. Strings can be indexed like arrays (lower bound is 0). Unlike
+arrays, they can be used in case statements:
+
+.. code-block:: nim
+
+  case paramStr(i)
+  of "-v": incl(options, optVerbose)
+  of "-h", "-?": incl(options, optHelp)
+  else: write(stdout, "invalid command line option!\n")
+
+Per convention, all strings are UTF-8 strings, but this is not enforced. For
+example, when reading strings from binary files, they are merely a sequence of
+bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the
+i-th *unichar*. The iterator ``runes`` from the `unicode module
+<unicode.html>`_ can be used for iteration over all Unicode characters.
+
+
+cstring type
+------------
+The ``cstring`` type represents a pointer to a zero-terminated char array
+compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy
+interfacing with C. The index operation ``s[i]`` means the i-th *char* of
+``s``; however no bounds checking for ``cstring`` is performed making the
+index operation unsafe.
+
+A Nim ``string`` is implicitly convertible
+to ``cstring`` for convenience. If a Nim string is passed to a C-style
+variadic proc, it is implicitly converted to ``cstring`` too:
+
+.. code-block:: nim
+  proc printf(formatstr: cstring) {.importc: "printf", varargs,
+                                    header: "<stdio.h>".}
+
+  printf("This works %s", "as expected")
+
+Even though the conversion is implicit, it is not *safe*: The garbage collector
+does not consider a ``cstring`` to be a root and may collect the underlying
+memory. However in practice this almost never happens as the GC considers
+stack roots conservatively. One can use the builtin procs ``GC_ref`` and
+``GC_unref`` to keep the string data alive for the rare cases where it does
+not work.
+
+A `$` proc is defined for cstrings that returns a string. Thus to get a nim
+string from a cstring:
+
+.. code-block:: nim
+  var str: string = "Hello!"
+  var cstr: cstring = str
+  var newstr: string = $cstr
+
+
+Structured types
+----------------
+A variable of a structured type can hold multiple values at the same
+time. Structured types can be nested to unlimited levels. Arrays, sequences,
+tuples, objects and sets belong to the structured types.
+
+Array and sequence types
+------------------------
+Arrays are a homogeneous type, meaning that each element in the array
+has the same type. Arrays always have a fixed length which is specified at
+compile time (except for open arrays). They can be indexed by any ordinal type.
+A parameter ``A`` may be an *open array*, in which case it is indexed by
+integers from 0 to ``len(A)-1``. An array expression may be constructed by the
+array constructor ``[]``.
+
+Sequences are similar to arrays but of dynamic length which may change
+during runtime (like strings). Sequences are implemented as growable arrays,
+allocating pieces of memory as items are added. A sequence ``S`` is always
+indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
+Sequences can be constructed by the array constructor ``[]`` in conjunction
+with the array to sequence operator ``@``. Another way to allocate space for a
+sequence is to call the built-in ``newSeq`` procedure.
+
+A sequence may be passed to a parameter that is of type *open array*.
+
+Example:
+
+.. code-block:: nim
+
+  type
+    IntArray = array[0..5, int] # an array that is indexed with 0..5
+    IntSeq = seq[int] # a sequence of integers
+  var
+    x: IntArray
+    y: IntSeq
+  x = [1, 2, 3, 4, 5, 6]  # [] is the array constructor
+  y = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence
+
+The lower bound of an array or sequence may be received by the built-in proc
+``low()``, the higher bound by ``high()``. The length may be
+received by ``len()``. ``low()`` for a sequence or an open array always returns
+0, as this is the first valid index.
+One can append elements to a sequence with the ``add()`` proc or the ``&``
+operator, and remove (and get) the last element of a sequence with the
+``pop()`` proc.
+
+The notation ``x[i]`` can be used to access the i-th element of ``x``.
+
+Arrays are always bounds checked (at compile-time or at runtime). These
+checks can be disabled via pragmas or invoking the compiler with the
+``--boundChecks:off`` command line switch.
+
+
+Open arrays
+-----------
+
+Often fixed size arrays turn out to be too inflexible; procedures should
+be able to deal with arrays of different sizes. The `openarray`:idx: type
+allows this; it can only be used for parameters. Openarrays are always
+indexed with an ``int`` starting at position 0. The ``len``, ``low``
+and ``high`` operations are available for open arrays too. Any array with
+a compatible base type can be passed to an openarray parameter, the index
+type does not matter. In addition to arrays sequences can also be passed
+to an open array parameter.
+
+The openarray type cannot be nested: multidimensional openarrays are not
+supported because this is seldom needed and cannot be done efficiently.
+
+
+Varargs
+-------
+
+A ``varargs`` parameter is an openarray parameter that additionally
+allows to pass a variable number of arguments to a procedure. The compiler
+converts the list of arguments to an array implicitly:
+
+.. code-block:: nim
+  proc myWriteln(f: File, a: varargs[string]) =
+    for s in items(a):
+      write(f, s)
+    write(f, "\n")
+
+  myWriteln(stdout, "abc", "def", "xyz")
+  # is transformed to:
+  myWriteln(stdout, ["abc", "def", "xyz"])
+
+This transformation is only done if the varargs parameter is the
+last parameter in the procedure header. It is also possible to perform
+type conversions in this context:
+
+.. code-block:: nim
+  proc myWriteln(f: File, a: varargs[string, `$`]) =
+    for s in items(a):
+      write(f, s)
+    write(f, "\n")
+
+  myWriteln(stdout, 123, "abc", 4.0)
+  # is transformed to:
+  myWriteln(stdout, [$123, $"def", $4.0])
+
+In this example ``$`` is applied to any argument that is passed to the
+parameter ``a``. (Note that ``$`` applied to strings is a nop.)
+
+Note that an explicit array constructor passed to a ``varargs`` parameter is
+not wrapped in another implicit array construction:
+
+.. code-block:: nim
+  proc takeV[T](a: varargs[T]) = discard
+
+  takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
+
+
+``varargs[expr]`` is treated specially: It matches a variable list of arguments
+of arbitrary type but *always* constructs an implicit array. This is required
+so that the builtin ``echo`` proc does what is expected:
+
+.. code-block:: nim
+  proc echo*(x: varargs[expr, `$`]) {...}
+
+  echo(@[1, 2, 3])
+  # prints "@[1, 2, 3]" and not "123"
+
+
+Tuples and object types
+-----------------------
+A variable of a tuple or object type is a heterogeneous storage
+container.
+A tuple or object defines various named *fields* of a type. A tuple also
+defines an *order* of the fields. Tuples are meant for heterogeneous storage
+types with no overhead and few abstraction possibilities. The constructor ``()``
+can be used to construct tuples. The order of the fields in the constructor
+must match the order of the tuple's definition. Different tuple-types are
+*equivalent* if they specify the same fields of the same type in the same
+order. The *names* of the fields also have to be identical.
+
+The assignment operator for tuples copies each component.
+The default assignment operator for objects copies each component. Overloading
+of the assignment operator for objects is not possible, but this will change
+in future versions of the compiler.
+
+.. code-block:: nim
+
+  type
+    Person = tuple[name: string, age: int] # type representing a person:
+                                           # a person consists of a name
+                                           # and an age
+  var
+    person: Person
+  person = (name: "Peter", age: 30)
+  # the same, but less readable:
+  person = ("Peter", 30)
+
+The implementation aligns the fields for best access performance. The alignment
+is compatible with the way the C compiler does it.
+
+For consistency  with ``object`` declarations, tuples in a ``type`` section
+can also be defined with indentation instead of ``[]``:
+
+.. code-block:: nim
+  type
+    Person = tuple   # type representing a person
+      name: string   # a person consists of a name
+      age: natural   # and an age
+
+Objects provide many features that tuples do not. Object provide inheritance
+and information hiding. Objects have access to their type at runtime, so that
+the ``of`` operator can be used to determine the object's type.
+
+.. code-block:: nim
+  type
+    Person {.inheritable.} = object
+      name*: string   # the * means that `name` is accessible from other modules
+      age: int        # no * means that the field is hidden
+
+    Student = ref object of Person # a student is a person
+      id: int                  # with an id field
+
+  var
+    student: Student
+    person: Person
+  assert(student of Student) # is true
+
+Object fields that should be visible from outside the defining module, have to
+be marked by ``*``. In contrast to tuples, different object types are
+never *equivalent*. Objects that have no ancestor are implicitly ``final``
+and thus have no hidden type field. One can use the ``inheritable`` pragma to
+introduce new object roots apart from ``system.RootObj``.
+
+
+Object construction
+-------------------
+
+Objects can also be created with an `object construction expression`:idx: that
+has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
+an ``object`` type or a ``ref object`` type:
+
+.. code-block:: nim
+  var student = Student(name: "Anton", age: 5, id: 3)
+
+For a ``ref object`` type ``system.new`` is invoked implicitly.
+
+
+Object variants
+---------------
+Often an object hierarchy is overkill in certain situations where simple
+variant types are needed.
+
+An example:
+
+.. code-block:: nim
+
+  # This is an example how an abstract syntax tree could be modelled in Nim
+  type
+    NodeKind = enum  # the different node types
+      nkInt,          # a leaf with an integer value
+      nkFloat,        # a leaf with a float value
+      nkString,       # a leaf with a string value
+      nkAdd,          # an addition
+      nkSub,          # a subtraction
+      nkIf            # an if statement
+    Node = ref NodeObj
+    NodeObj = object
+      case kind: NodeKind  # the ``kind`` field is the discriminator
+      of nkInt: intVal: int
+      of nkFloat: floatVal: float
+      of nkString: strVal: string
+      of nkAdd, nkSub:
+        leftOp, rightOp: Node
+      of nkIf:
+        condition, thenPart, elsePart: Node
+
+  # create a new case object:
+  var n = Node(kind: nkIf, condition: nil)
+  # accessing n.thenPart is valid because the ``nkIf`` branch is active:
+  n.thenPart = Node(kind: nkFloat, floatVal: 2.0)
+
+  # the following statement raises an `FieldError` exception, because
+  # n.kind's value does not fit and the ``nkString`` branch is not active:
+  n.strVal = ""
+
+  # invalid: would change the active object branch:
+  n.kind = nkInt
+
+  var x = Node(kind: nkAdd, leftOp: Node(kind: nkInt, intVal: 4),
+                            rightOp: Node(kind: nkInt, intVal: 2))
+  # valid: does not change the active object branch:
+  x.kind = nkSub
+
+As can been seen from the example, an advantage to an object hierarchy is that
+no casting between different object types is needed. Yet, access to invalid
+object fields raises an exception.
+
+The syntax of ``case`` in an object declaration follows closely the syntax of
+the ``case`` statement: The branches in a ``case`` section may be indented too.
+
+In the example the ``kind`` field is called the `discriminator`:idx:\: For
+safety its address cannot be taken and assignments to it are restricted: The
+new value must not lead to a change of the active object branch. For an object
+branch switch ``system.reset`` has to be used.
+
+
+Set type
+--------
+
+.. include:: sets_fragment.txt
+
+Reference and pointer types
+---------------------------
+References (similar to pointers in other programming languages) are a
+way to introduce many-to-one relationships. This means different references can
+point to and modify the same location in memory (also called `aliasing`:idx:).
+
+Nim distinguishes between `traced`:idx: and `untraced`:idx: references.
+Untraced references are also called *pointers*. Traced references point to
+objects of a garbage collected heap, untraced references point to
+manually allocated objects or to objects somewhere else in memory. Thus
+untraced references are *unsafe*. However for certain low-level operations
+(accessing the hardware) untraced references are unavoidable.
+
+Traced references are declared with the **ref** keyword, untraced references
+are declared with the **ptr** keyword.
+
+An empty subscript ``[]`` notation can be used to derefer a reference,
+the ``addr`` procedure returns the address of an item. An address is always
+an untraced reference.
+Thus the usage of ``addr`` is an *unsafe* feature.
+
+The ``.`` (access a tuple/object field operator)
+and ``[]`` (array/string/sequence index operator) operators perform implicit
+dereferencing operations for reference types:
+
+.. code-block:: nim
+
+  type
+    Node = ref NodeObj
+    NodeObj = object
+      le, ri: Node
+      data: int
+
+  var
+    n: Node
+  new(n)
+  n.data = 9
+  # no need to write n[].data; in fact n[].data is highly discouraged!
+
+Automatic dereferencing is also performed for the first argument of a routine
+call. But currently this feature has to be only enabled
+via ``{.experimental.}``:
+
+.. code-block:: nim
+  {.experimental.}
+
+  proc depth(x: NodeObj): int = ...
+
+  var
+    n: Node
+  new(n)
+  echo n.depth
+  # no need to write n[].depth either
+
+
+
+In order to simplify structural type checking, recursive tuples are not valid:
+
+.. code-block:: nim
+  # invalid recursion
+  type MyTuple = tuple[a: ref MyTuple]
+
+Likewise ``T = ref T`` is an invalid type.
+
+As a syntactical extension ``object`` types can be anonymous if
+declared in a type section via the ``ref object`` or ``ptr object`` notations.
+This feature is useful if an object should only gain reference semantics:
+
+.. code-block:: nim
+
+  type
+    Node = ref object
+      le, ri: Node
+      data: int
+
+
+To allocate a new traced object, the built-in procedure ``new`` has to be used.
+To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and
+``realloc`` can be used. The documentation of the system module contains
+further information.
+
+If a reference points to *nothing*, it has the value ``nil``.
+
+Special care has to be taken if an untraced object contains traced objects like
+traced references, strings or sequences: in order to free everything properly,
+the built-in procedure ``GCunref`` has to be called before freeing the untraced
+memory manually:
+
+.. code-block:: nim
+  type
+    Data = tuple[x, y: int, s: string]
+
+  # allocate memory for Data on the heap:
+  var d = cast[ptr Data](alloc0(sizeof(Data)))
+
+  # create a new string on the garbage collected heap:
+  d.s = "abc"
+
+  # tell the GC that the string is not needed anymore:
+  GCunref(d.s)
+
+  # free the memory:
+  dealloc(d)
+
+Without the ``GCunref`` call the memory allocated for the ``d.s`` string would
+never be freed. The example also demonstrates two important features for low
+level programming: the ``sizeof`` proc returns the size of a type or value
+in bytes. The ``cast`` operator can circumvent the type system: the compiler
+is forced to treat the result of the ``alloc0`` call (which returns an untyped
+pointer) as if it would have the type ``ptr Data``. Casting should only be
+done if it is unavoidable: it breaks type safety and bugs can lead to
+mysterious crashes.
+
+**Note**: The example only works because the memory is initialized to zero
+(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to
+``nil`` which the string assignment can handle. One needs to know low level
+details like this when mixing garbage collected data with unmanaged memory.
+
+.. XXX finalizers for traced objects
+
+
+Not nil annotation
+------------------
+
+All types for that ``nil`` is a valid value can be annotated to
+exclude ``nil`` as a valid value with the ``not nil`` annotation:
+
+.. code-block:: nim
+  type
+    PObject = ref TObj not nil
+    TProc = (proc (x, y: int)) not nil
+
+  proc p(x: PObject) =
+    echo "not nil"
+
+  # compiler catches this:
+  p(nil)
+
+  # and also this:
+  var x: PObject
+  p(x)
+
+The compiler ensures that every code path initializes variables which contain
+non nilable pointers. The details of this analysis are still to be specified
+here.
+
+
+Memory regions
+--------------
+
+The types ``ref`` and ``ptr`` can get an optional ``region`` annotation.
+A region has to be an object type.
+
+Regions are very useful to separate user space and kernel memory in the
+development of OS kernels:
+
+.. code-block:: nim
+  type
+    Kernel = object
+    Userspace = object
+
+  var a: Kernel ptr Stat
+  var b: Userspace ptr Stat
+
+  # the following does not compile as the pointer types are incompatible:
+  a = b
+
+As the example shows ``ptr`` can also be used as a binary
+operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``.
+
+In order to make generic code easier to write ``ptr T`` is a subtype
+of ``ptr[R, T]`` for any ``R``.
+
+Furthermore the subtype relation of the region object types is lifted to
+the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be
+used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is
+not compatible to ``pointer`` to prevent the following from compiling:
+
+.. code-block:: nim
+  # from system
+  proc dealloc(p: pointer)
+
+  # wrap some scripting language
+  type
+    PythonsHeap = object
+    PyObjectHeader = object
+      rc: int
+      typ: pointer
+    PyObject = ptr[PythonsHeap, PyObjectHeader]
+
+  proc createPyObject(): PyObject {.importc: "...".}
+  proc destroyPyObject(x: PyObject) {.importc: "...".}
+
+  var foo = createPyObject()
+  # type error here, how convenient:
+  dealloc(foo)
+
+
+Future directions:
+
+* Memory regions might become available for  ``string`` and ``seq`` too.
+* Builtin regions like ``private``, ``global`` and ``local`` will
+  prove very useful for the upcoming OpenCL target.
+* Builtin "regions" can model ``lent`` and ``unique`` pointers.
+* An assignment operator can be attached to a region so that proper write
+  barriers can be generated. This would imply that the GC can be implemented
+  completely in user-space.
+
+
+Procedural type
+---------------
+A procedural type is internally a pointer to a procedure. ``nil`` is
+an allowed value for variables of a procedural type. Nim uses procedural
+types to achieve `functional`:idx: programming techniques.
+
+Examples:
+
+.. code-block:: nim
+
+  proc printItem(x: int) = ...
+
+  proc forEach(c: proc (x: int) {.cdecl.}) =
+    ...
+
+  forEach(printItem)  # this will NOT compile because calling conventions differ
+
+
+.. code-block:: nim
+
+  type
+    OnMouseMove = proc (x, y: int) {.closure.}
+
+  proc onMouseMove(mouseX, mouseY: int) =
+    # has default calling convention
+    echo "x: ", mouseX, " y: ", mouseY
+
+  proc setOnMouseMove(mouseMoveEvent: OnMouseMove) = discard
+
+  # ok, 'onMouseMove' has the default calling convention, which is compatible
+  # to 'closure':
+  setOnMouseMove(onMouseMove)
+
+
+A subtle issue with procedural types is that the calling convention of the
+procedure influences the type compatibility: procedural types are only
+compatible if they have the same calling convention. As a special extension,
+a procedure of the calling convention ``nimcall`` can be passed to a parameter
+that expects a proc of the calling convention ``closure``.
+
+Nim supports these `calling conventions`:idx:\:
+
+`nimcall`:idx:
+    is the default convention used for a Nim **proc**. It is the
+    same as ``fastcall``, but only for C compilers that support ``fastcall``.
+
+`closure`:idx:
+    is the default calling convention for a **procedural type** that lacks
+    any pragma annotations. It indicates that the procedure has a hidden
+    implicit parameter (an *environment*). Proc vars that have the calling
+    convention ``closure`` take up two machine words: One for the proc pointer
+    and another one for the pointer to implicitly passed environment.
+
+`stdcall`:idx:
+    This the stdcall convention as specified by Microsoft. The generated C
+    procedure is declared with the ``__stdcall`` keyword.
+
+`cdecl`:idx:
+    The cdecl convention means that a procedure shall use the same convention
+    as the C compiler. Under windows the generated C procedure is declared with
+    the ``__cdecl`` keyword.
+
+`safecall`:idx:
+    This is the safecall convention as specified by Microsoft. The generated C
+    procedure is declared with the ``__safecall`` keyword. The word *safe*
+    refers to the fact that all hardware registers shall be pushed to the
+    hardware stack.
+
+`inline`:idx:
+    The inline convention means the the caller should not call the procedure,
+    but inline its code directly. Note that Nim does not inline, but leaves
+    this to the C compiler; it generates ``__inline`` procedures. This is
+    only a hint for the compiler: it may completely ignore it and
+    it may inline procedures that are not marked as ``inline``.
+
+`fastcall`:idx:
+    Fastcall means different things to different C compilers. One gets whatever
+    the C ``__fastcall`` means.
+
+`syscall`:idx:
+    The syscall convention is the same as ``__syscall`` in C. It is used for
+    interrupts.
+
+`noconv`:idx:
+    The generated C code will not have any explicit calling convention and thus
+    use the C compiler's default calling convention. This is needed because
+    Nim's default calling convention for procedures is ``fastcall`` to
+    improve speed.
+
+Most calling conventions exist only for the Windows 32-bit platform.
+
+Assigning/passing a procedure to a procedural variable is only allowed if one
+of the following conditions hold:
+1) The procedure that is accessed resides in the current module.
+2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma <#pragmas-procvar-pragma>`_).
+3) The procedure has a calling convention that differs from ``nimcall``.
+4) The procedure is anonymous.
+
+The rules' purpose is to prevent the case that extending a non-``procvar``
+procedure with default parameters breaks client code.
+
+The default calling convention is ``nimcall``, unless it is an inner proc (a
+proc inside of a proc). For an inner proc an analysis is performed whether it
+accesses its environment. If it does so, it has the calling convention
+``closure``, otherwise it has the calling convention ``nimcall``.
+
+
+Distinct type
+-------------
+
+A ``distinct`` type is new type derived from a `base type`:idx: that is
+incompatible with its base type. In particular, it is an essential property
+of a distinct type that it **does not** imply a subtype relation between it
+and its base type. Explicit type conversions from a distinct type to its
+base type and vice versa are allowed.
+
+
+Modelling currencies
+~~~~~~~~~~~~~~~~~~~~
+
+A distinct type can be used to model different physical `units`:idx: with a
+numerical base type, for example. The following example models currencies.
+
+Different currencies should not be mixed in monetary calculations. Distinct
+types are a perfect tool to model different currencies:
+
+.. code-block:: nim
+  type
+    Dollar = distinct int
+    Euro = distinct int
+
+  var
+    d: Dollar
+    e: Euro
+
+  echo d + 12
+  # Error: cannot add a number with no unit and a ``Dollar``
+
+Unfortunately, ``d + 12.Dollar`` is not allowed either,
+because ``+`` is defined for ``int`` (among others), not for ``Dollar``. So
+a ``+`` for dollars needs to be defined:
+
+.. code-block::
+  proc `+` (x, y: Dollar): Dollar =
+    result = Dollar(int(x) + int(y))
+
+It does not make sense to multiply a dollar with a dollar, but with a
+number without unit; and the same holds for division:
+
+.. code-block::
+  proc `*` (x: Dollar, y: int): Dollar =
+    result = Dollar(int(x) * y)
+
+  proc `*` (x: int, y: Dollar): Dollar =
+    result = Dollar(x * int(y))
+
+  proc `div` ...
+
+This quickly gets tedious. The implementations are trivial and the compiler
+should not generate all this code only to optimize it away later - after all
+``+`` for dollars should produce the same binary code as ``+`` for ints.
+The pragma `borrow`:idx: has been designed to solve this problem; in principle
+it generates the above trivial implementations:
+
+.. code-block:: nim
+  proc `*` (x: Dollar, y: int): Dollar {.borrow.}
+  proc `*` (x: int, y: Dollar): Dollar {.borrow.}
+  proc `div` (x: Dollar, y: int): Dollar {.borrow.}
+
+The ``borrow`` pragma makes the compiler use the same implementation as
+the proc that deals with the distinct type's base type, so no code is
+generated.
+
+But it seems all this boilerplate code needs to be repeated for the ``Euro``
+currency. This can be solved with templates_.
+
+.. code-block:: nim
+  template additive(typ: typedesc): stmt =
+    proc `+` *(x, y: typ): typ {.borrow.}
+    proc `-` *(x, y: typ): typ {.borrow.}
+
+    # unary operators:
+    proc `+` *(x: typ): typ {.borrow.}
+    proc `-` *(x: typ): typ {.borrow.}
+
+  template multiplicative(typ, base: typedesc): stmt =
+    proc `*` *(x: typ, y: base): typ {.borrow.}
+    proc `*` *(x: base, y: typ): typ {.borrow.}
+    proc `div` *(x: typ, y: base): typ {.borrow.}
+    proc `mod` *(x: typ, y: base): typ {.borrow.}
+
+  template comparable(typ: typedesc): stmt =
+    proc `<` * (x, y: typ): bool {.borrow.}
+    proc `<=` * (x, y: typ): bool {.borrow.}
+    proc `==` * (x, y: typ): bool {.borrow.}
+
+  template defineCurrency(typ, base: expr): stmt =
+    type
+      typ* = distinct base
+    additive(typ)
+    multiplicative(typ, base)
+    comparable(typ)
+
+  defineCurrency(Dollar, int)
+  defineCurrency(Euro, int)
+
+
+The borrow pragma can also be used to annotate the distinct type to allow
+certain builtin operations to be lifted:
+
+.. code-block:: nim
+  type
+    Foo = object
+      a, b: int
+      s: string
+
+    Bar {.borrow: `.`.} = distinct Foo
+
+  var bb: ref Bar
+  new bb
+  # field access now valid
+  bb.a = 90
+  bb.s = "abc"
+
+Currently only the dot accessor can be borrowed in this way.
+
+
+Avoiding SQL injection attacks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+An SQL statement that is passed from Nim to an SQL database might be
+modelled as a string. However, using string templates and filling in the
+values is vulnerable to the famous `SQL injection attack`:idx:\:
+
+.. code-block:: nim
+  import strutils
+
+  proc query(db: DbHandle, statement: string) = ...
+
+  var
+    username: string
+
+  db.query("SELECT FROM users WHERE name = '$1'" % username)
+  # Horrible security hole, but the compiler does not mind!
+
+This can be avoided by distinguishing strings that contain SQL from strings
+that don't. Distinct types provide a means to introduce a new string type
+``SQL`` that is incompatible with ``string``:
+
+.. code-block:: nim
+  type
+    SQL = distinct string
+
+  proc query(db: DbHandle, statement: SQL) = ...
+
+  var
+    username: string
+
+  db.query("SELECT FROM users WHERE name = '$1'" % username)
+  # Error at compile time: `query` expects an SQL string!
+
+
+It is an essential property of abstract types that they **do not** imply a
+subtype relation between the abstract type and its base type. Explicit type
+conversions from ``string`` to ``SQL`` are allowed:
+
+.. code-block:: nim
+  import strutils, sequtils
+
+  proc properQuote(s: string): SQL =
+    # quotes a string properly for an SQL statement
+    return SQL(s)
+
+  proc `%` (frmt: SQL, values: openarray[string]): SQL =
+    # quote each argument:
+    let v = values.mapIt(SQL, properQuote(it))
+    # we need a temporary type for the type conversion :-(
+    type StrSeq = seq[string]
+    # call strutils.`%`:
+    result = SQL(string(frmt) % StrSeq(v))
+
+  db.query("SELECT FROM users WHERE name = '$1'".SQL % [username])
+
+Now we have compile-time checking against SQL injection attacks.  Since
+``"".SQL`` is transformed to ``SQL("")`` no new syntax is needed for nice
+looking ``SQL`` string literals. The hypothetical ``SQL`` type actually
+exists in the library as the `TSqlQuery type <db_sqlite.html#TSqlQuery>`_ of
+modules like `db_sqlite <db_sqlite.html>`_.
+
+
+Void type
+---------
+
+The ``void`` type denotes the absence of any type. Parameters of
+type ``void`` are treated as non-existent, ``void`` as a return type means that
+the procedure does not return a value:
+
+.. code-block:: nim
+  proc nothing(x, y: void): void =
+    echo "ha"
+
+  nothing() # writes "ha" to stdout
+
+The ``void`` type is particularly useful for generic code:
+
+.. code-block:: nim
+  proc callProc[T](p: proc (x: T), x: T) =
+    when T is void:
+      p()
+    else:
+      p(x)
+
+  proc intProc(x: int) = discard
+  proc emptyProc() = discard
+
+  callProc[int](intProc, 12)
+  callProc[void](emptyProc)
+
+However, a ``void`` type cannot be inferred in generic code:
+
+.. code-block:: nim
+  callProc(emptyProc)
+  # Error: type mismatch: got (proc ())
+  # but expected one of:
+  # callProc(p: proc (T), x: T)
+
+The ``void`` type is only valid for parameters and return types; other symbols
+cannot have the type ``void``.
diff --git a/doc/mytest.cfg b/doc/mytest.cfg
new file mode 100644
index 000000000..be1118c46
--- /dev/null
+++ b/doc/mytest.cfg
@@ -0,0 +1,20 @@
+# This is a comment.
+; this too.
+
+[Common]
+cc=gcc     # '=' and ':' are the same
+--verbose
+
+[Windows]
+isConsoleApplication=False ; another comment
+
+[Posix]
+isConsoleApplication=True
+
+key1: "in this string backslash escapes are interpreted\n"
+key2: r"in this string not"
+key3: """triple quotes strings
+are also supported. They may span
+multiple lines."""
+
+--"long option with spaces": r"c:\myfiles\test.txt" 
diff --git a/doc/nimc.txt b/doc/nimc.txt
new file mode 100644
index 000000000..fb1873539
--- /dev/null
+++ b/doc/nimc.txt
@@ -0,0 +1,921 @@
+===================================
+   Nim Compiler User Guide
+===================================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+  "Look at you, hacker. A pathetic creature of meat and bone, panting and
+  sweating as you run through my corridors. How can you challenge a perfect,
+  immortal machine?"
+
+
+Introduction
+============
+
+This document describes the usage of the *Nim compiler*
+on the different supported platforms. It is not a definition of the Nim
+programming language (therefore is the `manual <manual.html>`_).
+
+Nim is free software; it is licensed under the
+`MIT License <http://www.opensource.org/licenses/mit-license.php>`_.
+
+
+Compiler Usage
+==============
+
+Command line switches
+---------------------
+Basic command line switches are:
+
+Usage:
+
+.. include:: basicopt.txt
+
+----
+
+Advanced command line switches are:
+
+.. include:: advopt.txt
+
+
+
+List of warnings
+----------------
+
+Each warning can be activated individually with ``--warning[NAME]:on|off`` or
+in a ``push`` pragma.
+
+==========================       ============================================
+Name                             Description
+==========================       ============================================
+CannotOpenFile                   Some file not essential for the compiler's
+                                 working could not be opened.
+OctalEscape                      The code contains an unsupported octal
+                                 sequence.
+Deprecated                       The code uses a deprecated symbol.
+ConfigDeprecated                 The project makes use of a deprecated config
+                                 file.
+SmallLshouldNotBeUsed            The letter 'l' should not be used as an
+                                 identifier.
+EachIdentIsTuple                 The code contains a confusing ``var``
+                                 declaration.
+ShadowIdent                      A local variable shadows another local
+                                 variable of an outer scope.
+User                             Some user defined warning.
+==========================       ============================================
+
+
+Verbosity levels
+----------------
+
+=====  ============================================
+Level  Description
+=====  ============================================
+0      Minimal output level for the compiler.
+1      Displays compilation of all the compiled files, including those imported
+       by other modules or through the `compile pragma<#compile-pragma>`_.
+       This is the default level.
+2      Displays compilation statistics, enumerates the dynamic
+       libraries that will be loaded by the final binary and dumps to
+       standard output the result of applying `a filter to the source code
+       <filters.html>`_ if any filter was used during compilation.
+3      In addition to the previous levels dumps a debug stack trace
+       for compiler developers.
+=====  ============================================
+
+
+Compile time symbols
+--------------------
+
+Through the ``-d:x`` or ``--define:x`` switch you can define compile time
+symbols for conditional compilation. The defined switches can be checked in
+source code with the `when statement <manual.html#when-statement>`_ and
+`defined proc <system.html#defined>`_. The typical use of this switch is to
+enable builds in release mode (``-d:release``) where certain safety checks are
+omitted for better performance. Another common use is the ``-d:ssl`` switch to
+activate `SSL sockets <sockets.html>`_.
+
+
+Configuration files
+-------------------
+
+**Note:** The *project file name* is the name of the ``.nim`` file that is
+passed as a command line argument to the compiler.
+
+
+The ``nim`` executable processes configuration files in the following
+directories (in this order; later files overwrite previous settings):
+
+1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option.
+2) ``/home/$user/.config/nim.cfg`` (UNIX) or  ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option.
+3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent  directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option.
+4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project  file's path. This file can be skipped with the ``--skipProjCfg`` command line option.
+5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option.
+
+
+Command line settings have priority over configuration file settings.
+
+The default build of a project is a `debug build`:idx:. To compile a
+`release build`:idx: define the ``release`` symbol::
+
+  nim c -d:release myproject.nim
+
+
+Search path handling
+--------------------
+
+Nim has the concept of a global search path (PATH) that is queried to
+determine where to find imported modules or include files. If multiple files are
+found an ambiguity error is produced.
+
+``nim dump`` shows the contents of the PATH.
+
+However before the PATH is used the current directory is checked for the
+file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the
+directory structure looks like this::
+
+  $lib/x.nim
+  $lib/bar/x.nim
+  foo/x.nim
+  foo/main.nim
+  other.nim
+
+And ``main`` imports ``x``, ``foo/x`` is imported. If ``other`` imports ``x``
+then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match and so the compiler
+should reject it. Currently however this check is not implemented and instead
+the first matching file is used.
+
+
+Generated C code directory
+--------------------------
+The generated files that Nim produces all go into a subdirectory called
+``nimcache`` in your project directory. This makes it easy to delete all
+generated files. Files generated in this directory follow a naming logic which
+you can read about in the `Nim Backend Integration document
+<backends.html#nimcache-naming-logic>`_.
+
+However, the generated C code is not platform independent. C code generated for
+Linux does not compile on Windows, for instance. The comment on top of the
+C file lists the OS, CPU and CC the file has been compiled for.
+
+
+Compilation cache
+=================
+
+**Warning**: The compilation cache is still highly experimental!
+
+The ``nimcache`` directory may also contain so called `rod`:idx:
+or `symbol files`:idx:. These files are pre-compiled modules that are used by
+the compiler to perform `incremental compilation`:idx:. This means that only
+modules that have changed since the last compilation (or the modules depending
+on them etc.) are re-compiled. However, per default no symbol files are
+generated; use the ``--symbolFiles:on`` command line switch to activate them.
+
+Unfortunately due to technical reasons the ``--symbolFiles:on`` needs
+to *aggregate* some generated C code. This means that the resulting executable
+might contain some cruft even when dead code elimination is turned on. So
+the final release build should be done with ``--symbolFiles:off``.
+
+Due to the aggregation of C code it is also recommended that each project
+resides in its own directory so that the generated ``nimcache`` directory
+is not shared between different projects.
+
+
+Cross compilation
+=================
+
+To cross compile, use for example::
+
+  nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim
+
+Then move the C code and the compile script ``compile_myproject.sh`` to your
+Linux i386 machine and run the script.
+
+Another way is to make Nim invoke a cross compiler toolchain::
+
+  nim c --cpu:arm --os:linux myproject.nim
+
+For cross compilation, the compiler invokes a C compiler named
+like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration
+system is used to provide meaningful defaults. For example for ``ARM`` your
+configuration file should contain something like::
+
+  arm.linux.gcc.path = "/usr/bin"
+  arm.linux.gcc.exe = "arm-linux-gcc"
+  arm.linux.gcc.linkerexe = "arm-linux-gcc"
+
+
+DLL generation
+==============
+
+Nim supports the generation of DLLs. However, there must be only one
+instance of the GC per process/address space. This instance is contained in
+``nimrtl.dll``. This means that every generated Nim DLL depends
+on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command::
+
+  nim c -d:release lib/nimrtl.nim
+
+To link against ``nimrtl.dll`` use the command::
+
+  nim c -d:useNimRtl myprog.nim
+
+**Note**: Currently the creation of ``nimrtl.dll`` with thread support has
+never been tested and is unlikely to work!
+
+
+Additional compilation switches
+===============================
+
+The standard library supports a growing number of ``useX`` conditional defines
+affecting how some features are implemented. This section tries to give a
+complete list.
+
+==================   =========================================================
+Define               Effect
+==================   =========================================================
+``release``          Turns off runtime checks and turns on the optimizer.
+``useWinAnsi``       Modules like ``os`` and ``osproc`` use the Ansi versions
+                     of the Windows API. The default build uses the Unicode
+                     version.
+``useFork``          Makes ``osproc`` use ``fork`` instead of ``posix_spawn``.
+``useNimRtl``        Compile and link against ``nimrtl.dll``.
+``useMalloc``        Makes Nim use C's `malloc`:idx: instead of Nim's
+                     own memory manager. This only works with ``gc:none``.
+``useRealtimeGC``    Enables support of Nim's GC for *soft* realtime
+                     systems. See the documentation of the `gc <gc.html>`_
+                     for further information.
+``nodejs``           The JS target is actually ``node.js``.
+``ssl``              Enables OpenSSL support for the sockets module.
+``memProfiler``      Enables memory profiling for the native GC.
+``uClibc``           Use uClibc instead of libc. (Relevant for Unix-like OSes)
+==================   =========================================================
+
+
+
+Additional Features
+===================
+
+This section describes Nim's additional features that are not listed in the
+Nim manual. Some of the features here only make sense for the C code
+generator and are subject to change.
+
+
+NoDecl pragma
+-------------
+The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,
+type, etc.) and is sometimes useful for interoperability with C:
+It tells Nim that it should not generate a declaration for the symbol in
+the C code. For example:
+
+.. code-block:: Nim
+  var
+    EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as
+                                     # Nim does not know its value
+
+However, the ``header`` pragma is often the better alternative.
+
+**Note**: This will not work for the LLVM backend.
+
+
+Header pragma
+-------------
+The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be
+applied to almost any symbol and specifies that it should not be declared
+and instead the generated code should contain an ``#include``:
+
+.. code-block:: Nim
+  type
+    PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
+      # import C's FILE* type; Nim will treat it as a new pointer type
+
+The ``header`` pragma always expects a string constant. The string contant
+contains the header file: As usual for C, a system header file is enclosed
+in angle brackets: ``<>``. If no angle brackets are given, Nim
+encloses the header file in ``""`` in the generated C code.
+
+**Note**: This will not work for the LLVM backend.
+
+
+IncompleteStruct pragma
+-----------------------
+The ``incompleteStruct`` pragma tells the compiler to not use the
+underlying C ``struct`` in a ``sizeof`` expression:
+
+.. code-block:: Nim
+  type
+    DIR* {.importc: "DIR", header: "<dirent.h>",
+           final, pure, incompleteStruct.} = object
+
+
+Compile pragma
+--------------
+The ``compile`` pragma can be used to compile and link a C/C++ source file
+with the project:
+
+.. code-block:: Nim
+  {.compile: "myfile.cpp".}
+
+**Note**: Nim computes a CRC checksum and only recompiles the file if it
+has changed. You can use the ``-f`` command line option to force recompilation
+of the file.
+
+
+Link pragma
+-----------
+The ``link`` pragma can be used to link an additional file with the project:
+
+.. code-block:: Nim
+  {.link: "myfile.o".}
+
+
+PassC pragma
+------------
+The ``passC`` pragma can be used to pass additional parameters to the C
+compiler like you would using the commandline switch ``--passC``:
+
+.. code-block:: Nim
+  {.passC: "-Wall -Werror".}
+
+Note that you can use ``gorge`` from the `system module <system.html>`_ to
+embed parameters from an external command at compile time:
+
+.. code-block:: Nim
+  {.passC: gorge("pkg-config --cflags sdl").}
+
+PassL pragma
+------------
+The ``passL`` pragma can be used to pass additional parameters to the linker
+like you would using the commandline switch ``--passL``:
+
+.. code-block:: Nim
+  {.passL: "-lSDLmain -lSDL".}
+
+Note that you can use ``gorge`` from the `system module <system.html>`_ to
+embed parameters from an external command at compile time:
+
+.. code-block:: Nim
+  {.passL: gorge("pkg-config --libs sdl").}
+
+
+Emit pragma
+-----------
+The ``emit`` pragma can be used to directly affect the output of the
+compiler's code generator. So it makes your code unportable to other code
+generators/backends. Its usage is highly discouraged! However, it can be
+extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
+
+Example:
+
+.. code-block:: Nim
+  {.emit: """
+  static int cvariable = 420;
+  """.}
+
+  {.push stackTrace:off.}
+  proc embedsC() =
+    var nimVar = 89
+    # use backticks to access Nim symbols within an emit section:
+    {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}
+  {.pop.}
+
+  embedsC()
+
+As can be seen from the example, to Nim symbols can be referred via backticks.
+Use two backticks to produce a single verbatim backtick.
+
+For a toplevel emit statement the section where in the generated C/C++ file
+the code should be emitted can be influenced via the
+prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/``:
+
+.. code-block:: Nim
+  {.emit: """/*TYPESECTION*/
+  struct Vector3 {
+  public:
+    Vector3(): x(5) {}
+    Vector3(float x_): x(x_) {}
+    float x;
+  };
+  """.}
+
+  type Vector3 {.importcpp: "Vector3", nodecl} = object
+    x: cfloat
+
+  proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+
+ImportCpp pragma
+----------------
+
+**Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows
+about the ``importcpp`` pragma pattern language. It is not necessary
+to know all the details described here.
+
+
+Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
+``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols
+in general. The generated code then uses the C++ method calling
+syntax: ``obj->method(arg)``.  In combination with the ``header`` and ``emit``
+pragmas this allows *sloppy* interfacing with libraries written in C++:
+
+.. code-block:: Nim
+  # Horrible example of how to interface with a C++ engine ... ;-)
+
+  {.link: "/usr/lib/libIrrlicht.so".}
+
+  {.emit: """
+  using namespace irr;
+  using namespace core;
+  using namespace scene;
+  using namespace video;
+  using namespace io;
+  using namespace gui;
+  """.}
+
+  const
+    irr = "<irrlicht/irrlicht.h>"
+
+  type
+    IrrlichtDeviceObj {.final, header: irr,
+                        importcpp: "IrrlichtDevice".} = object
+    IrrlichtDevice = ptr IrrlichtDeviceObj
+
+  proc createDevice(): IrrlichtDevice {.
+    header: irr, importcpp: "createDevice(@)".}
+  proc run(device: IrrlichtDevice): bool {.
+    header: irr, importcpp: "#.run(@)".}
+
+The compiler needs to be told to generate C++ (command ``cpp``) for
+this to work. The conditional symbol ``cpp`` is defined when the compiler
+emits C++ code.
+
+
+Namespaces
+~~~~~~~~~~
+
+The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace``
+declarations. It is usually much better to instead refer to the imported name
+via the ``namespace::identifier`` notation:
+
+.. code-block:: nim
+  type
+    IrrlichtDeviceObj {.final, header: irr,
+                        importcpp: "irr::IrrlichtDevice".} = object
+
+
+Importcpp for enums
+~~~~~~~~~~~~~~~~~~~
+
+When ``importcpp`` is applied to an enum type the numerical enum values are
+annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``.
+(This turned out to be the simplest way to implement it.)
+
+
+Importcpp for procs
+~~~~~~~~~~~~~~~~~~~
+
+Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern
+language for maximum flexibility:
+
+- A hash ``#`` symbol is replaced by the first or next argument.
+- A dot following the hash ``#.`` indicates that the call should use C++'s dot
+  or arrow notation.
+- An at symbol ``@`` is replaced by the remaining arguments, separated by
+  commas.
+
+For example:
+
+.. code-block:: nim
+  proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".}
+  var x: ptr CppObj
+  cppMethod(x[], 1, 2, 3)
+
+Produces:
+
+.. code-block:: C
+  x->CppMethod(1, 2, 3)
+
+As a special rule to keep backwards compatibility with older versions of the
+``importcpp`` pragma, if there is no special pattern
+character (any of ``# ' @``) at all, C++'s
+dot or arrow notation is assumed, so the above example can also be written as:
+
+.. code-block:: nim
+  proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}
+
+Note that the pattern language naturally also covers C++'s operator overloading
+capabilities:
+
+.. code-block:: nim
+  proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".}
+  proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
+
+
+- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9
+  is replaced by the i'th parameter *type*. The 0th position is the result
+  type. This can be used to pass types to C++ function templates. Between
+  the ``'`` and the digit an asterisk can be used to get to the base type
+  of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.)
+  Two stars can be used to get to the element type of the element type etc.
+
+For example:
+
+.. code-block:: nim
+
+  type Input {.importcpp: "System::Input".} = object
+  proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+  let x: ptr Input = getSubsystem[Input]()
+
+Produces:
+
+.. code-block:: C
+  x = SystemManager::getSubsystem<System::Input>()
+
+
+- ``#@`` is a special case to support a ``cnew`` operation. It is required so
+  that the call expression is inlined directly, without going through a
+  temporary location. This is only required to circumvent a limitation of the
+  current code generator.
+
+For example C++'s ``new`` operator can be "imported" like this:
+
+.. code-block:: nim
+  proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
+
+  # constructor of 'Foo':
+  proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".}
+
+  let x = cnew constructFoo(3, 4)
+
+Produces:
+
+.. code-block:: C
+  x = new Foo(3, 4)
+
+However, depending on the use case ``new Foo`` can also be wrapped like this
+instead:
+
+.. code-block:: nim
+  proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
+
+  let x = newFoo(3, 4)
+
+
+Wrapping constructors
+~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes a C++ class has a private copy constructor and so code like
+``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``.
+For this purpose the Nim proc that wraps a C++ constructor needs to be
+annotated with the `constructor`:idx: pragma. This pragma also helps to generate
+faster C++ code since construction then doesn't invoke the copy constructor:
+
+.. code-block:: nim
+  # a better constructor of 'Foo':
+  proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
+
+
+Wrapping destructors
+~~~~~~~~~~~~~~~~~~~~
+
+Since Nim generates C++ directly, any destructor is called implicitly by the
+C++ compiler at the scope exits. This means that often one can get away with
+not wrapping the destructor at all! However when it needs to be invoked
+explicitly, it needs to be wrapped. But the pattern language already provides
+everything that is required for that:
+
+.. code-block:: nim
+  proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}
+
+
+Importcpp for objects
+~~~~~~~~~~~~~~~~~~~~~
+
+Generic ``importcpp``'ed objects are mapped to C++ templates. This means that
+you can import C++'s templates rather easily without the need for a pattern
+language for object types:
+
+.. code-block:: nim
+  type
+    StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
+  proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
+    importcpp: "#[#] = #", header: "<map>".}
+
+  var x: StdMap[cint, cdouble]
+  x[6] = 91.4
+
+
+Produces:
+
+.. code-block:: C
+  std::map<int, double> x;
+  x[6] = 91.4;
+
+
+- If more precise control is needed, the apostrophe ``'`` can be used in the
+  supplied pattern to denote the concrete type parameters of the generic type.
+  See the usage of the apostrophe operator in proc patterns for more details.
+
+.. code-block:: nim
+
+  type
+    VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
+
+  var x: VectorIterator[cint]
+
+
+Produces:
+
+.. code-block:: C
+
+  std::vector<int>::iterator x;
+
+
+ImportObjC pragma
+-----------------
+Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
+``importobjc`` pragma can be used to import `Objective C`:idx: methods.  The
+generated code then uses the Objective C method calling syntax: ``[obj method
+param1: arg]``.  In addition with the ``header`` and ``emit`` pragmas this
+allows *sloppy* interfacing with libraries written in Objective C:
+
+.. code-block:: Nim
+  # horrible example of how to interface with GNUStep ...
+
+  {.passL: "-lobjc".}
+  {.emit: """
+  #include <objc/Object.h>
+  @interface Greeter:Object
+  {
+  }
+
+  - (void)greet:(long)x y:(long)dummy;
+  @end
+
+  #include <stdio.h>
+  @implementation Greeter
+
+  - (void)greet:(long)x y:(long)dummy
+  {
+    printf("Hello, World!\n");
+  }
+  @end
+
+  #include <stdlib.h>
+  """.}
+
+  type
+    Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
+
+  proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}
+  proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}
+  proc free(self: Id) {.importobjc: "free", nodecl.}
+
+  var g = newGreeter()
+  g.greet(12, 34)
+  g.free()
+
+The compiler needs to be told to generate Objective C (command ``objc``) for
+this to work. The conditional symbol ``objc`` is defined when the compiler
+emits Objective C code.
+
+
+CodegenDecl pragma
+------------------
+
+The ``codegenDecl`` pragma can be used to directly influence Nim's code
+generator. It receives a format string that determines how the variable or
+proc is declared in the generated code:
+
+.. code-block:: nim
+  var
+    a {.codegenDecl: "$# progmem $#".}: int
+
+  proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
+    echo "realistic interrupt handler"
+
+
+InjectStmt pragma
+-----------------
+
+The ``injectStmt`` pragma can be used to inject a statement before every
+other statement in the current module. It is only supposed to be used for
+debugging:
+
+.. code-block:: nim
+  {.injectStmt: gcInvariants().}
+
+  # ... complex code here that produces crashes ...
+
+
+LineDir option
+--------------
+The ``lineDir`` option can be turned on or off. If turned on the
+generated C code contains ``#line`` directives. This may be helpful for
+debugging with GDB.
+
+
+StackTrace option
+-----------------
+If the ``stackTrace`` option is turned on, the generated C contains code to
+ensure that proper stack traces are given if the program crashes or an
+uncaught exception is raised.
+
+
+LineTrace option
+----------------
+The ``lineTrace`` option implies the ``stackTrace`` option. If turned on,
+the generated C contains code to ensure that proper stack traces with line
+number information are given if the program crashes or an uncaught exception
+is raised.
+
+Debugger option
+---------------
+The ``debugger`` option enables or disables the *Embedded Nim Debugger*.
+See the documentation of endb_ for further information.
+
+
+Breakpoint pragma
+-----------------
+The *breakpoint* pragma was specially added for the sake of debugging with
+ENDB. See the documentation of `endb <endb.html>`_ for further information.
+
+
+Volatile pragma
+---------------
+The ``volatile`` pragma is for variables only. It declares the variable as
+``volatile``, whatever that means in C/C++ (its semantics are not well defined
+in C/C++).
+
+**Note**: This pragma will not exist for the LLVM backend.
+
+
+DynlibOverride
+==============
+
+By default Nim's ``dynlib`` pragma causes the compiler to generate
+``GetProcAddress`` (or their Unix counterparts)
+calls to bind to a DLL. With the ``dynlibOverride`` command line switch this
+can be prevented and then via ``--passL`` the static library can be linked
+against. For instance, to link statically against Lua this command might work
+on Linux::
+
+  nim c --dynlibOverride:lua --passL:liblua.lib program.nim
+
+
+Backend language options
+========================
+
+The typical compiler usage involves using the ``compile`` or ``c`` command to
+transform a ``.nim`` file into one or more ``.c`` files which are then
+compiled with the platform's C compiler into a static binary. However there
+are other commands to compile to C++, Objective-C or Javascript. More details
+can be read in the `Nim Backend Integration document <backends.html>`_.
+
+
+Nim documentation tools
+=======================
+
+Nim provides the `doc`:idx: and `doc2`:idx: commands to generate HTML
+documentation from ``.nim`` source files. Only exported symbols will appear in
+the output. For more details `see the docgen documentation <docgen.html>`_.
+
+Nim idetools integration
+========================
+
+Nim provides language integration with external IDEs through the
+idetools command. See the documentation of `idetools <idetools.html>`_
+for further information.
+
+
+Nim interactive mode
+====================
+
+The Nim compiler supports an interactive mode. This is also known as
+a `REPL`:idx: (*read eval print loop*). If Nim has been built with the
+``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal
+input management. To start Nim in interactive mode use the command
+``nim i``. To quit use the ``quit()`` command. To determine whether an input
+line is an incomplete statement to be continued these rules are used:
+
+1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace).
+2. The line starts with a space (indentation).
+3. The line is within a triple quoted string literal. However, the detection
+   does not work if the line contains more than one ``"""``.
+
+
+Nim for embedded systems
+========================
+
+The standard library can be avoided to a point where C code generation
+for 16bit micro controllers is feasible. Use the `standalone`:idx: target
+(``--os:standalone``) for a bare bones standard library that lacks any
+OS features.
+
+To make the compiler output code for a 16bit target use the ``--cpu:avr``
+target.
+
+For example, to generate code for an `AVR`:idx: processor use this command::
+
+  nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim
+
+For the ``standalone`` target one needs to provide
+a file ``panicoverride.nim``.
+See ``tests/manyloc/standalone/panicoverride.nim`` for an example
+implementation.
+
+
+Nim for realtime systems
+========================
+
+See the documentation of Nim's soft realtime `GC <gc.html>`_ for further
+information.
+
+
+Debugging with Nim
+==================
+
+Nim comes with its own *Embedded Nim Debugger*. See
+the documentation of endb_ for further information.
+
+
+Optimizing for Nim
+==================
+
+Nim has no separate optimizer, but the C code that is produced is very
+efficient. Most C compilers have excellent optimizers, so usually it is
+not needed to optimize one's code. Nim has been designed to encourage
+efficient code: The most readable code in Nim is often the most efficient
+too.
+
+However, sometimes one has to optimize. Do it in the following order:
+
+1. switch off the embedded debugger (it is **slow**!)
+2. turn on the optimizer and turn off runtime checks
+3. profile your code to find where the bottlenecks are
+4. try to find a better algorithm
+5. do low-level optimizations
+
+This section can only help you with the last item.
+
+
+Optimizing string handling
+--------------------------
+
+String assignments are sometimes expensive in Nim: They are required to
+copy the whole string. However, the compiler is often smart enough to not copy
+strings. Due to the argument passing semantics, strings are never copied when
+passed to subroutines. The compiler does not copy strings that are a result from
+a procedure call, because the callee returns a new string anyway.
+Thus it is efficient to do:
+
+.. code-block:: Nim
+  var s = procA() # assignment will not copy the string; procA allocates a new
+                  # string already
+
+However it is not efficient to do:
+
+.. code-block:: Nim
+  var s = varA    # assignment has to copy the whole string into a new buffer!
+
+For ``let`` symbols a copy is not always necessary:
+
+.. code-block:: Nim
+  let s = varA    # may only copy a pointer if it safe to do so
+
+
+If you know what you're doing, you can also mark single string (or sequence)
+objects as `shallow`:idx:\:
+
+.. code-block:: Nim
+  var s = "abc"
+  shallow(s) # mark 's' as shallow string
+  var x = s  # now might not copy the string!
+
+Usage of ``shallow`` is always safe once you know the string won't be modified
+anymore, similar to Ruby's `freeze`:idx:.
+
+
+The compiler optimizes string case statements: A hashing scheme is used for them
+if several different string constants are used. So code like this is reasonably
+efficient:
+
+.. code-block:: Nim
+  case normalize(k.key)
+  of "name": c.name = v
+  of "displayname": c.displayName = v
+  of "version": c.version = v
+  of "os": c.oses = split(v, {';'})
+  of "cpu": c.cpus = split(v, {';'})
+  of "authors": c.authors = split(v, {';'})
+  of "description": c.description = v
+  of "app":
+    case normalize(v)
+    of "console": c.app = appConsole
+    of "gui": c.app = appGUI
+    else: quit(errorStr(p, "expected: console or gui"))
+  of "license": c.license = UnixToNativePath(k.value)
+  else: quit(errorStr(p, "unknown variable: " & k.key))
diff --git a/doc/nimdoc.css b/doc/nimdoc.css
new file mode 100644
index 000000000..e3bab07de
--- /dev/null
+++ b/doc/nimdoc.css
@@ -0,0 +1,300 @@
+/*

+:Author: David Goodger

+:Contact: goodger@python.org

+:Date: $Date: 2006-05-21 22:44:42 +0200 (Sun, 21 May 2006) $

+:Revision: $Revision: 4564 $

+:Copyright: This stylesheet has been placed in the public domain.

+

+Default cascading style sheet for the HTML output of Docutils.

+

+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to

+customize this style sheet.

+*/

+

+/*

+   Modified for the Nimrod Documenation by

+   Andreas Rumpf

+*/

+

+body {

+  color: black;

+  background: white;

+}

+

+/* used to remove borders from tables and images */

+.borderless, table.borderless td, table.borderless th {

+  border: 0 }

+

+table.borderless td, table.borderless th {

+  /* Override padding for "table.docutils td" with "! important".

+     The right padding separates the table cells. */

+  padding: 0 0.5em 0 0 ! important }

+

+.first {

+  /* Override more specific margin styles with "! important". */

+  margin-top: 0 ! important }

+

+.last, .with-subtitle {

+  margin-bottom: 0 ! important }

+

+.hidden {

+  display: none }

+

+a.toc-backref {

+  text-decoration: none ;

+  color: black }

+

+blockquote.epigraph {

+  margin: 2em 5em ; }

+

+dl.docutils dd {

+  margin-bottom: 0.5em }

+

+/* Uncomment (and remove this text!) to get bold-faced definition list terms

+dl.docutils dt {

+  font-weight: bold }

+*/

+

+div.abstract {

+  margin: 2em 5em }

+

+div.abstract p.topic-title {

+  font-weight: bold ;

+  text-align: center }

+

+div.admonition, div.attention, div.caution, div.danger, div.error,

+div.hint, div.important, div.note, div.tip, div.warning {

+  margin: 2em ;

+  border: medium outset ;

+  padding: 1em }

+

+div.admonition p.admonition-title, div.hint p.admonition-title,

+div.important p.admonition-title, div.note p.admonition-title,

+div.tip p.admonition-title {

+  font-weight: bold ;

+  font-family: sans-serif }

+

+div.attention p.admonition-title, div.caution p.admonition-title,

+div.danger p.admonition-title, div.error p.admonition-title,

+div.warning p.admonition-title {

+  color: red ;

+  font-weight: bold ;

+  font-family: sans-serif }

+

+/* Uncomment (and remove this text!) to get reduced vertical space in

+   compound paragraphs.

+div.compound .compound-first, div.compound .compound-middle {

+  margin-bottom: 0.5em }

+

+div.compound .compound-last, div.compound .compound-middle {

+  margin-top: 0.5em }

+*/

+

+div.dedication {

+  margin: 2em 5em ;

+  text-align: center ;

+  font-style: italic }

+

+div.dedication p.topic-title {

+  font-weight: bold ;

+  font-style: normal }

+

+div.figure {

+  margin-left: 2em ;

+  margin-right: 2em }

+

+div.footer, div.header {

+  clear: both;

+  font-size: smaller }

+

+div.line-block {

+  display: block ;

+  margin-top: 1em ;

+  margin-bottom: 1em }

+

+div.line-block div.line-block {

+  margin-top: 0 ;

+  margin-bottom: 0 ;

+  margin-left: 1.5em }

+

+div.sidebar {

+  margin-left: 1em ;

+  border: medium outset ;

+  padding: 1em ;

+  background-color: #ffffee ;

+  width: 40% ;

+  float: right ;

+  clear: right }

+

+div.sidebar p.rubric {

+  font-family: sans-serif ;

+  font-size: medium }

+

+div.system-messages {

+  margin: 5em }

+

+div.system-messages h1 {

+  color: red }

+

+div.system-message {

+  border: medium outset ;

+  padding: 1em }

+

+div.system-message p.system-message-title {

+  color: red ;

+  font-weight: bold }

+

+div.topic {

+  margin: 2em;

+}

+

+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,

+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {

+  margin-top: 0.4em }

+

+h1.title { text-align: center }

+h2.subtitle { text-align: center }

+hr.docutils { width: 75% }

+img.align-left { clear: left }

+img.align-right { clear: right }

+

+ol.simple, ul.simple {

+  margin-bottom: 1em }

+

+ol.arabic {

+  list-style: decimal }

+

+ol.loweralpha {

+  list-style: lower-alpha }

+

+ol.upperalpha {

+  list-style: upper-alpha }

+

+ol.lowerroman {

+  list-style: lower-roman }

+

+ol.upperroman {

+  list-style: upper-roman }

+

+p.attribution {

+  text-align: right ;

+  margin-left: 50% }

+

+p.caption {

+  font-style: italic }

+

+p.credits {

+  font-style: italic ;

+  font-size: smaller }

+

+p.label {

+  white-space: nowrap }

+

+p.rubric {

+  font-weight: bold ;

+  font-size: larger ;

+  color: maroon ;

+  text-align: center }

+

+p.sidebar-title {

+  font-family: sans-serif ;

+  font-weight: bold ;

+  font-size: larger }

+

+p.sidebar-subtitle {

+  font-family: sans-serif ;

+  font-weight: bold }

+

+p.topic-title {

+  font-weight: bold }

+

+pre.address {

+  margin-bottom: 0 ;

+  margin-top: 0 ;

+  font-family: serif ;

+  font-size: 100% }

+

+pre, span.pre {

+  background-color:#F9F9F9;

+  border:1px dotted #2F6FAB;

+  color:black;

+}

+

+pre {padding:1em;}

+

+pre.literal-block, pre.doctest-block {

+  margin-left: 2em ;

+  margin-right: 2em }

+

+span.classifier {

+  font-family: sans-serif ;

+  font-style: oblique }

+

+span.classifier-delimiter {

+  font-family: sans-serif ;

+  font-weight: bold }

+

+span.interpreted {

+  font-family: sans-serif }

+

+span.option {

+  white-space: nowrap }

+

+span.pre { white-space: pre }

+

+span.problematic {

+  color: red }

+

+span.section-subtitle {

+  /* font-size relative to parent (h1..h6 element) */

+  font-size: 80% }

+

+table.citation {

+  border-left: solid 1px gray;

+  margin-left: 1px }

+

+table.docinfo {

+  margin: 2em 4em }

+

+table.docutils {

+  margin-top: 0.5em ;

+  margin-bottom: 0.5em }

+

+table.footnote {

+  border-left: solid 1px black;

+  margin-left: 1px }

+

+table.docutils td, table.docutils th,

+table.docinfo td, table.docinfo th {

+  padding-left: 0.5em ;

+  padding-right: 0.5em ;

+  vertical-align: top }

+

+table.docutils th.field-name, table.docinfo th.docinfo-name {

+  font-weight: bold ;

+  text-align: left ;

+  white-space: nowrap ;

+  padding-left: 0 }

+

+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,

+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {

+  font-size: 100% }

+

+ul.auto-toc {

+  list-style-type: none }

+

+a.reference {

+  color: #E00000;

+  font-weight:bold;

+}

+

+a.reference:hover {

+  color: #E00000;

+  background-color: #ffff00;

+  display: margin;

+  font-weight:bold;

+}

+

+div.topic ul {

+  list-style-type: none;

+}

diff --git a/doc/nimfix.txt b/doc/nimfix.txt
new file mode 100644
index 000000000..6d78f3e3f
--- /dev/null
+++ b/doc/nimfix.txt
@@ -0,0 +1,56 @@
+=====================

+  Nimfix User Guide

+=====================

+

+:Author: Andreas Rumpf

+:Version: |nimversion|

+

+**WARNING**: Nimfix is currently beta-quality.
+

+Nimfix is a tool to help you upgrade from Nimrod (<= version 0.9.6) to
+Nim (=> version 0.10.0).
+
+It performs 3 different actions:
+
+1. It makes your code case consistent.
+2. It renames every symbol that has a deprecation rule. So if a module has a
+   rule ``{.deprecated: [TFoo: Foo].}`` then ``TFoo`` is replaced by ``Foo``.
+3. It can also check that your identifiers adhere to the official style guide
+   and optionally modify them to do so (via ``--styleCheck:auto``).
+
+Note that ``nimfix`` defaults to **overwrite** your code unless you
+use ``--overwriteFiles:off``! But hey, if you do not use a version control
+system by this day and age, your project is already in big trouble.
+
+
+Installation
+------------
+
+Nimfix is part of the compiler distribution. Compile via::
+
+  nim c compiler/nimfix/nimfix.nim
+  mv compiler/nimfix/nimfix bin
+
+Or on windows::
+
+  nim c compiler\nimfix\nimfix.nim
+  move compiler\nimfix\nimfix.exe bin
+
+Usage
+-----
+
+Usage:
+  nimfix [options] projectfile.nim
+
+Options:
+
+  --overwriteFiles:on|off       overwrite the original nim files. DEFAULT is ON!
+  --wholeProject                overwrite every processed file.
+  --checkExtern:on|off          style check also extern names
+  --styleCheck:on|off|auto      performs style checking for identifiers
+                                and suggests an alternative spelling; 
+                                'auto' corrects the spelling.
+
+In addition, all command line options of Nim are supported.
+
+
diff --git a/doc/nimgrep.txt b/doc/nimgrep.txt
new file mode 100644
index 000000000..2d429e8b5
--- /dev/null
+++ b/doc/nimgrep.txt
@@ -0,0 +1,50 @@
+=========================
+  nimgrep User's manual
+=========================
+
+:Author: Andreas Rumpf
+:Version: 0.9
+
+
+Nimgrep is a command line tool for search&replace tasks. It can search for
+regex or peg patterns and can search whole directories at once. User 
+confirmation for every single replace operation can be requested.
+
+Nimgrep has particularly good support for Nim's 
+eccentric *style insensitivity*. Apart from that it is a generic text 
+manipulation tool.
+
+
+Installation
+============
+
+Compile nimgrep with the command::
+
+  nim c -d:release tools/nimgrep.nim
+
+And copy the executable somewhere in your ``$PATH``.
+
+
+Command line switches
+=====================
+
+Usage:
+  nimgrep [options] [pattern] [replacement] (file/directory)*
+Options:
+  --find, -f          find the pattern (default)
+  --replace, -r       replace the pattern
+  --peg               pattern is a peg
+  --re                pattern is a regular expression (default); extended 
+                      syntax for the regular expression is always turned on
+  --recursive         process directories recursively
+  --confirm           confirm each occurrence/replacement; there is a chance 
+                      to abort any time without touching the file
+  --stdin             read pattern from stdin (to avoid the shell's confusing
+                      quoting rules)
+  --word, -w          the match should have word boundaries (buggy for pegs!)
+  --ignoreCase, -i    be case insensitive
+  --ignoreStyle, -y   be style insensitive
+  --ext:EX1|EX2|...   only search the files with the given extension(s)
+  --verbose           be verbose: list every processed file
+  --help, -h          shows this help
+  --version, -v       shows the version
diff --git a/doc/niminst.txt b/doc/niminst.txt
new file mode 100644
index 000000000..ca05cc514
--- /dev/null
+++ b/doc/niminst.txt
@@ -0,0 +1,195 @@
+=========================
+  niminst User's manual
+=========================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+Introduction
+============
+
+niminst is a tool to generate an installer for a Nim program. Currently
+it can create an installer for Windows 
+via `Inno Setup <http://www.jrsoftware.org/isinfo.php>`_ as well as
+installation/deinstallation scripts for UNIX. Later versions will support 
+Linux' package management systems.
+
+niminst works by reading a configuration file that contains all the 
+information that it needs to generate an installer for the different operating
+systems.
+
+
+Configuration file
+==================
+
+niminst uses the Nim `parsecfg <parsecfg.html>`_ module to parse the 
+configuration file. Here's an example of how the syntax looks like:
+
+.. include:: doc/mytest.cfg
+     :literal:
+
+The value of a key-value pair can reference user-defined variables via
+the ``$variable`` notation: They can be defined in the command line with the
+``--var:name=value`` switch. This is useful to not hard-coding the
+program's version number into the configuration file, for instance.
+
+It follows a description of each possible section and how it affects the
+generated installers.
+
+
+Project section
+---------------
+The project section gathers general information about your project. It must
+contain the following key-value pairs:
+
+====================   =======================================================
+Key                    description
+====================   =======================================================
+``Name``               the project's name; this needs to be a single word
+``DisplayName``        the project's long name; this can contain spaces. If
+                       not specified, this is the same as ``Name``.
+``Version``            the project's version
+``OS``                 the OSes to generate C code for; for example:
+                       ``"windows;linux;macosx"``
+``CPU``                the CPUs to generate C code for; for example:
+                       ``"i386;amd64;powerpc"`` 
+``Authors``            the project's authors
+``Description``        the project's description
+``App``                the application's type: "Console" or "GUI". If 
+                       "Console", niminst generates a special batch file
+                       for Windows to open up the command line shell.
+``License``            the filename of the application's license
+====================   =======================================================
+
+
+``files`` key
+-------------
+
+Many sections support the ``files`` key. Listed filenames
+can be separated by semicolon or the ``files`` key can be repeated. Wildcards
+in filenames are supported. If it is a directory name, all files in the 
+directory are used::
+
+  [Config]
+  Files: "configDir"
+  Files: "otherconfig/*.conf;otherconfig/*.cfg"
+
+
+Config section
+--------------
+
+The ``config`` section currently only supports the ``files`` key. Listed files
+will be installed into the OS's configuration directory.
+
+
+Documentation section
+---------------------
+
+The ``documentation`` section supports the ``files`` key. 
+Listed files will be installed into the OS's native documentation directory 
+(which might be ``$appdir/doc``).
+
+There is a ``start`` key which determines whether the Windows installer 
+generates a link to e.g. the ``index.html`` of your documentation.
+
+
+Other section
+-------------
+
+The ``other`` section currently only supports the ``files`` key. 
+Listed files will be installed into the application installation directory 
+(``$appdir``).
+
+
+Lib section
+-----------
+
+The ``lib`` section currently only supports the ``files`` key. 
+Listed files will be installed into the OS's native library directory 
+(which might be ``$appdir/lib``).
+
+
+Windows section
+---------------
+
+The ``windows`` section supports the ``files`` key for Windows specific files. 
+Listed files will be installed into the application installation directory 
+(``$appdir``).
+
+Other possible options are:
+
+====================   =======================================================
+Key                    description
+====================   =======================================================
+``BinPath``            paths to add to the Windows ``%PATH%`` environment
+                       variable. Example: ``BinPath: r"bin;dist\mingw\bin"``
+``InnoSetup``          boolean flag whether an Inno Setup installer should be
+                       generated for Windows. Example: ``InnoSetup: "Yes"``
+====================   =======================================================
+
+
+UnixBin section
+---------------
+
+The ``UnixBin`` section currently only supports the ``files`` key. 
+Listed files will be installed into the OS's native bin directory 
+(e.g. ``/usr/local/bin``). The exact location depends on the
+installation path the user specifies when running the ``install.sh`` script.
+
+
+Unix section
+------------
+
+Possible options are:
+
+====================   =======================================================
+Key                    description
+====================   =======================================================
+``InstallScript``      boolean flag whether an installation shell script
+                       should be generated. Example: ``InstallScript: "Yes"``
+``UninstallScript``    boolean flag whether a deinstallation shell script
+                       should be generated. 
+                       Example: ``UninstallScript: "Yes"``
+====================   =======================================================
+
+
+InnoSetup section
+-----------------
+
+Possible options are:
+
+====================   =======================================================
+Key                    description
+====================   =======================================================
+``path``               Path to Inno Setup. 
+                       Example: ``path = r"c:\inno setup 5\iscc.exe"``
+``flags``              Flags to pass to Inno Setup.
+                       Example: ``flags = "/Q"``
+====================   =======================================================
+
+
+C_Compiler section
+------------------
+
+Possible options are:
+
+====================   =======================================================
+Key                    description
+====================   =======================================================
+``path``               Path to the C compiler. 
+``flags``              Flags to pass to the C Compiler.
+                       Example: ``flags = "-w"``
+====================   =======================================================
+
+
+Real world example
+==================
+
+The installers for the Nim compiler itself are generated by niminst. Have a
+look at its configuration file:
+
+.. include:: compiler/installer.ini
+     :literal:
+
diff --git a/doc/nimsuggest.txt b/doc/nimsuggest.txt
new file mode 100644
index 000000000..2b52196b9
--- /dev/null
+++ b/doc/nimsuggest.txt
@@ -0,0 +1,174 @@
+================================
+  Nim IDE Integration Guide
+================================
+
+:Author: Unknown
+:Version: |nimversion|
+
+.. contents::
+
+
+Nim differs from many other compilers in that it is really fast,
+and being so fast makes it suited to provide external queries for
+text editors about the source code being written. Through the
+``nimsuggest`` tool, any IDE
+can query a ``.nim`` source file and obtain useful information like
+definition of symbols or suggestions for completion.
+
+This document will guide you through the available options. If you
+want to look at practical examples of nimsuggest support you can look
+at the
+`various editor integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
+already available.
+
+
+Installation
+============
+
+Nimsuggest is available as a Nimble package but currently does not install
+properly via Nimble. As nimsuggest is part of the compiler it also doesn't make
+too much sense as a Nimble package. Instead we will do the building manually::
+
+  cd compiler/nimsuggest
+  nim c -d:release nimsuggest
+  cp nimsuggest ../../bin
+  # OR: copy the nimsuggest binary to where your 'nim' binary is
+  cd ../..
+
+
+
+Nimsuggest invocation
+=====================
+
+Run it via ``nimsuggest --stdin myproject.nim``. Nimsuggest is a server that
+takes queries that are related to ``myproject``. There is some support so that
+you can throw random ``.nim`` files which are not part of ``myproject`` at
+Nimsuggest too, but usually the query refer to modules/files that are part of
+``myproject``.
+
+``--stdin`` means that Nimsuggest reads the query from ``stdin``. This is great
+for testing things out and playing with it but for an editor communication
+via sockets is more reasonable so that is the default. It listens to port 6000
+by default.
+
+
+Specifying the location of the query
+------------------------------------
+
+Nimsuggest than waits for queries to process. A query consists of a
+cryptic 3 letter "command" ``def`` or ``con`` or ``sug`` or ``use`` followed by
+a location. A query location consists of:
+
+
+``file.nim``
+    This is the name of the module or include file the query refers to.
+
+``dirtyfile.nim``
+    This is optional.
+
+    The ``file`` paramater is enough for static analysis, but IDEs
+    tend to have *unsaved buffers* where the user may still be in
+    the middle of typing a line. In such situations the IDE can
+    save the current contents to a temporary file and then use the
+    ``dirtyfile.nim`` option to tell Nimsuggest that ``foobar.nim`` should
+    be taken from ``temporary/foobar.nim``.
+
+
+``line``
+    An integer with the line you are going to query. For the compiler
+    lines start at **1**.
+
+``col``
+    An integer with the column you are going to query. For the
+    compiler columns start at **1**.
+
+
+Definitions
+-----------
+
+The ``def`` Nimsuggest command performs a query about the definition
+of a specific symbol. If available, Nimsuggest will answer with the
+type, source file, line/column information and other accessory data
+if available like a docstring. With this information an IDE can
+provide the typical *Jump to definition* where a user puts the
+cursor on a symbol or uses the mouse to select it and is redirected
+to the place where the symbol is located.
+
+Since Nim is implemented in Nim, one of the nice things of
+this feature is that any user with an IDE supporting it can quickly
+jump around the standard library implementation and see exactly
+what a proc does, learning about the language and seeing real life
+examples of how to write/implement specific features.
+
+Nimsuggest will always answer with a single definition or none if it
+can't find any valid symbol matching the position of the query.
+
+
+Suggestions
+-----------
+
+The ``sug`` Nimsuggest command performs a query about possible
+completion symbols at some point in the file.
+
+The typical usage scenario for this option is to call it after the
+user has typed the dot character for `the object oriented call
+syntax <tut2.html#method-call-syntax>`_. Nimsuggest will try to return
+the suggestions sorted first by scope (from innermost to outermost)
+and then by item name.
+
+
+Invocation context
+------------------
+
+The ``con`` Nimsuggest command is very similar to the suggestions
+command, but instead of being used after the user has typed a dot
+character, this one is meant to be used after the user has typed
+an opening brace to start typing parameters.
+
+
+Symbol usages
+-------------
+
+The ``use`` Nimsuggest command lists all usages of the symbol at
+a position. IDEs can use this to find all the places in the file
+where the symbol is used and offer the user to rename it in all
+places at the same time.
+
+For this kind of query the IDE will most likely ignore all the
+type/signature info provided by Nimsuggest and concentrate on the
+filename, line and column position of the multiple returned answers.
+
+
+
+Parsing nimsuggest output
+=========================
+
+Nimsuggest output is always returned on single lines separated by
+tab characters (``\t``). The values of each column are:
+
+1. Three characters indicating the type of returned answer (e.g.
+   ``def`` for definition, ``sug`` for suggestion, etc).
+2. Type of the symbol. This can be ``skProc``, ``skLet``, and just
+   about any of the enums defined in the module ``compiler/ast.nim``.
+3. Full qualitifed path of the symbol. If you are querying a symbol
+   defined in the ``proj.nim`` file, this would have the form
+   ``proj.symbolName``.
+4. Type/signature. For variables and enums this will contain the
+   type of the symbol, for procs, methods and templates this will
+   contain the full unique signature (e.g. ``proc (File)``).
+5. Full path to the file containing the symbol.
+6. Line where the symbol is located in the file. Lines start to
+   count at **1**.
+7. Column where the symbol is located in the file. Columns start
+   to count at **1**.
+8. Docstring for the symbol if available or the empty string. To
+   differentiate the docstring from end of answer,
+   the docstring is always provided enclosed in double quotes, and
+   if the docstring spans multiple lines, all following lines of the
+   docstring will start with a blank space to align visually with
+   the starting quote.
+
+   Also, you won't find raw ``\n`` characters breaking the one
+   answer per line format. Instead you will need to parse sequences
+   in the form ``\xHH``, where *HH* is a hexadecimal value (e.g.
+   newlines generate the sequence ``\x0A``).
diff --git a/doc/overview.txt b/doc/overview.txt
new file mode 100644
index 000000000..5b41752ae
--- /dev/null
+++ b/doc/overview.txt
@@ -0,0 +1,9 @@
+=============================
+Nim Documentation Overview
+=============================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. include:: ../doc/docs.txt
+
diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt
new file mode 100644
index 000000000..118949cad
--- /dev/null
+++ b/doc/pegdocs.txt
@@ -0,0 +1,222 @@
+PEG syntax and semantics
+========================
+
+A PEG (Parsing expression grammar) is a simple deterministic grammar, that can
+be directly used for parsing. The current implementation has been designed as
+a more powerful replacement for regular expressions. UTF-8 is supported.
+
+The notation used for a PEG is similar to that of EBNF:
+
+===============    ============================================================
+notation           meaning
+===============    ============================================================
+``A / ... / Z``    Ordered choice: Apply expressions `A`, ..., `Z`, in this
+                   order, to the text ahead, until one of them succeeds and
+                   possibly consumes some text. Indicate success if one of
+                   expressions succeeded. Otherwise do not consume any text
+                   and indicate failure. 
+``A ... Z``        Sequence: Apply expressions `A`, ..., `Z`, in this order,
+                   to consume consecutive portions of the text ahead, as long
+                   as they succeed. Indicate success if all succeeded.
+                   Otherwise do not consume any text and indicate failure.
+                   The sequence's precedence is higher than that of ordered
+                   choice: ``A B / C`` means ``(A B) / Z`` and
+                   not ``A (B / Z)``.
+``(E)``            Grouping: Parenthesis can be used to change
+                   operator priority.
+``{E}``            Capture: Apply expression `E` and store the substring
+                   that matched `E` into a *capture* that can be accessed
+                   after the matching process.
+``$i``             Back reference to the ``i``th capture. ``i`` counts from 1. 
+``$``              Anchor: Matches at the end of the input. No character 
+                   is consumed. Same as ``!.``. 
+``^``              Anchor: Matches at the start of the input. No character 
+                   is consumed. 
+``&E``             And predicate: Indicate success if expression `E` matches
+                   the text ahead; otherwise indicate failure. Do not consume
+                   any text.
+``!E``             Not predicate: Indicate failure if expression E matches the
+                   text ahead; otherwise indicate success. Do not consume any
+                   text.
+``E+``             One or more: Apply expression `E` repeatedly to match
+                   the text ahead, as long as it succeeds. Consume the matched
+                   text (if any) and indicate success if there was at least
+                   one match. Otherwise indicate failure. 
+``E*``             Zero or more: Apply expression `E` repeatedly to match
+                   the text ahead, as long as it succeeds. Consume the matched
+                   text (if any). Always indicate success. 
+``E?``             Zero or one: If expression `E` matches the text ahead,
+                   consume it. Always indicate success. 
+``[s]``            Character class: If the character ahead appears in the
+                   string `s`, consume it and indicate success. Otherwise
+                   indicate failure. 
+``[a-b]``          Character range: If the character ahead is one from the
+                   range `a` through `b`, consume it and indicate success.
+                   Otherwise indicate failure.
+``'s'``            String: If the text ahead is the string `s`, consume it
+                   and indicate success. Otherwise indicate failure.
+``i's'``           String match ignoring case.
+``y's'``           String match ignoring style.
+``v's'``           Verbatim string match: Use this to override a global
+                   ``\i`` or ``\y`` modifier.
+``i$j``            String match ignoring case for back reference.
+``y$j``            String match ignoring style for back reference.
+``v$j``            Verbatim string match for back reference.
+``.``              Any character: If there is a character ahead, consume it
+                   and indicate success. Otherwise (that is, at the end of
+                   input) indicate failure.
+``_``              Any Unicode character: If there is an UTF-8 character
+                   ahead, consume it and indicate success. Otherwise indicate
+                   failure.
+``@E``             Search: Shorthand for ``(!E .)* E``. (Search loop for the
+                   pattern `E`.)
+``{@} E``          Captured Search: Shorthand for ``{(!E .)*} E``. (Search 
+                   loop for the pattern `E`.) Everything until and exluding
+                   `E` is captured.
+``@@ E``           Same as ``{@} E``.
+``A <- E``         Rule: Bind the expression `E` to the *nonterminal symbol*
+                   `A`. **Left recursive rules are not possible and crash the
+                   matching engine.**
+``\identifier``    Built-in macro for a longer expression.
+``\ddd``           Character with decimal code *ddd*.
+``\"``, etc        Literal ``"``, etc. 
+===============    ============================================================
+
+
+Built-in macros
+---------------
+
+==============     ============================================================
+macro              meaning
+==============     ============================================================
+``\d``             any decimal digit: ``[0-9]``
+``\D``             any character that is not a decimal digit: ``[^0-9]``
+``\s``             any whitespace character: ``[ \9-\13]``
+``\S``             any character that is not a whitespace character:
+                   ``[^ \9-\13]``
+``\w``             any "word" character: ``[a-zA-Z0-9_]``
+``\W``             any "non-word" character: ``[^a-zA-Z0-9_]``
+``\a``             same as ``[a-zA-Z]``
+``\A``             same as ``[^a-zA-Z]``
+``\n``             any newline combination: ``\10 / \13\10 / \13``
+``\i``             ignore case for matching; use this at the start of the PEG
+``\y``             ignore style for matching; use this at the start of the PEG
+``\skip`` pat      skip pattern *pat* before trying to match other tokens; 
+                   this is useful for whitespace skipping, for example:
+                   ``\skip(\s*) {\ident} ':' {\ident}`` matches key value 
+                   pairs ignoring whitespace around the ``':'``.
+``\ident``         a standard ASCII identifier: ``[a-zA-Z_][a-zA-Z_0-9]*``
+``\letter``        any Unicode letter
+``\upper``         any Unicode uppercase letter
+``\lower``         any Unicode lowercase letter
+``\title``         any Unicode title letter
+``\white``         any Unicode whitespace character
+==============     ============================================================
+
+A backslash followed by a letter is a built-in macro, otherwise it
+is used for ordinary escaping:
+
+==============     ============================================================
+notation           meaning
+==============     ============================================================
+``\\``             a single backslash
+``\*``             same as ``'*'``
+``\t``             not a tabulator, but an (unknown) built-in
+==============     ============================================================
+
+
+Supported PEG grammar
+---------------------
+
+The PEG parser implements this grammar (written in PEG syntax)::
+
+  # Example grammar of PEG in PEG syntax.
+  # Comments start with '#'.
+  # First symbol is the start symbol.
+  
+  grammar <- rule* / expr
+  
+  identifier <- [A-Za-z][A-Za-z0-9_]*
+  charsetchar <- "\\" . / [^\]]
+  charset <- "[" "^"? (charsetchar ("-" charsetchar)?)+ "]"
+  stringlit <- identifier? ("\"" ("\\" . / [^"])* "\"" /
+                            "'" ("\\" . / [^'])* "'")
+  builtin <- "\\" identifier / [^\13\10]
+  
+  comment <- '#' @ \n
+  ig <- (\s / comment)* # things to ignore
+  
+  rule <- identifier \s* "<-" expr ig
+  identNoArrow <- identifier !(\s* "<-")
+  prefixOpr <- ig '&' / ig '!' / ig '@' / ig '{@}' / ig '@@'
+  literal <- ig identifier? '$' [0-9]+ / '$' / '^' /
+             ig identNoArrow / 
+             ig charset / 
+             ig stringlit / 
+             ig builtin / 
+             ig '.' / 
+             ig '_' / 
+             (ig "(" expr ig ")")
+  postfixOpr <- ig '?' / ig '*' / ig '+'
+  primary <- prefixOpr* (literal postfixOpr*)
+  
+  # Concatenation has higher priority than choice:
+  # ``a b / c`` means ``(a b) / c``
+  
+  seqExpr <- primary+
+  expr <- seqExpr (ig "/" expr)*
+
+
+**Note**: As a special syntactic extension if the whole PEG is only a single 
+expression, identifiers are not interpreted as non-terminals, but are 
+interpreted as verbatim string:
+
+.. code-block:: nim
+  abc =~ peg"abc" # is true
+
+So it is not necessary to write ``peg" 'abc' "`` in the above example.
+
+
+Examples
+--------
+
+Check if `s` matches Nim's "while" keyword:
+
+.. code-block:: nim
+  s =~ peg" y'while'"
+
+Exchange (key, val)-pairs: 
+
+.. code-block:: nim
+  "key: val; key2: val2".replace(peg"{\ident} \s* ':' \s* {\ident}", "$2: $1")
+
+Determine the ``#include``'ed files of a C file:
+
+.. code-block:: nim
+  for line in lines("myfile.c"):
+    if line =~ peg"""s <- ws '#include' ws '"' {[^"]+} '"' ws
+                     comment <- '/*' @ '*/' / '//' .*
+                     ws <- (comment / \s+)* """:
+      echo matches[0]
+
+PEG vs regular expression
+-------------------------
+As a regular expression ``\[.*\]`` matches the longest possible text between
+``'['`` and ``']'``. As a PEG it never matches anything, because a PEG is
+deterministic: ``.*`` consumes the rest of the input, so ``\]`` never matches.
+As a PEG this needs to be written as: ``\[ ( !\] . )* \]`` (or ``\[ @ \]``).
+
+Note that the regular expression does not behave as intended either: in the
+example ``*`` should not be greedy, so ``\[.*?\]`` should be used instead.
+
+
+PEG construction
+----------------
+There are two ways to construct a PEG in Nim code:
+(1) Parsing a string into an AST which consists of `Peg` nodes with the
+    `peg` proc.
+(2) Constructing the AST directly with proc calls. This method does not
+    support constructing rules, only simple expressions and is not as
+    convenient. Its only advantage is that it does not pull in the whole PEG
+    parser into your executable.
+
diff --git a/doc/readme.txt b/doc/readme.txt
new file mode 100644
index 000000000..e5d9e2c27
--- /dev/null
+++ b/doc/readme.txt
@@ -0,0 +1,7 @@
+============================

+Nim's documenation system

+============================

+

+This folder contains Nim's documentation. The documentation

+is written in a format called *reStructuredText*, a markup language that reads

+like ASCII and can be converted to HTML automatically!

diff --git a/doc/regexprs.txt b/doc/regexprs.txt
new file mode 100644
index 000000000..d912c623e
--- /dev/null
+++ b/doc/regexprs.txt
@@ -0,0 +1,274 @@
+Licence of the PCRE library
+===========================
+
+PCRE is a library of functions to support regular expressions whose
+syntax and semantics are as close as possible to those of the Perl 5
+language.
+
+| Written by Philip Hazel
+| Copyright (c) 1997-2005 University of Cambridge
+
+----------------------------------------------------------------------
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of the University of Cambridge nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+Regular expression syntax and semantics
+=======================================
+
+As the regular expressions supported by this module are enormous,
+the reader is referred to http://perldoc.perl.org/perlre.html for the
+full documentation of Perl's regular expressions.
+
+Because the backslash ``\`` is a meta character both in the Nim
+programming language and in regular expressions, it is strongly
+recommended that one uses the *raw* strings of Nim, so that
+backslashes are interpreted by the regular expression engine::
+
+  r"\S"  # matches any character that is not whitespace
+
+A regular expression is a pattern that is matched against a subject string
+from left to right. Most characters stand for themselves in a pattern, and
+match the corresponding characters in the subject. As a trivial example,
+the pattern::
+
+  The quick brown fox
+
+matches a portion of a subject string that is identical to itself.
+The power of regular expressions comes from the ability to include
+alternatives and repetitions in the pattern. These are encoded in
+the pattern by the use of metacharacters, which do not stand for
+themselves but instead are interpreted in some special way.
+
+There are two different sets of metacharacters: those that are recognized
+anywhere in the pattern except within square brackets, and those that are
+recognized in square brackets. Outside square brackets, the metacharacters
+are as follows:
+
+==============     ============================================================
+meta character     meaning
+==============     ============================================================
+``\``              general escape character with several uses
+``^``              assert start of string (or line, in multiline mode)
+``$``              assert end of string (or line, in multiline mode)
+``.``              match any character except newline (by default)
+``[``              start character class definition
+``|``              start of alternative branch
+``(``              start subpattern
+``)``              end subpattern
+``?``              extends the meaning of ``(``
+                   also 0 or 1 quantifier
+                   also quantifier minimizer
+``*``              0 or more quantifier
+``+``              1 or more quantifier
+                   also "possessive quantifier"
+``{``              start min/max quantifier
+==============     ============================================================
+
+
+Part of a pattern that is in square brackets is called a "character class".
+In a character class the only metacharacters are:
+
+==============     ============================================================
+meta character     meaning
+==============     ============================================================
+``\``              general escape character
+``^``              negate the class, but only if the first character
+``-``              indicates character range
+``[``              POSIX character class (only if followed by POSIX syntax)
+``]``              terminates the character class
+==============     ============================================================
+
+
+The following sections describe the use of each of the metacharacters.
+
+
+Backslash
+---------
+The `backslash`:idx: character has several uses. Firstly, if it is followed
+by a non-alphanumeric character, it takes away any special meaning that
+character may have. This use of backslash as an escape character applies
+both inside and outside character classes.
+
+For example, if you want to match a ``*`` character, you write ``\*`` in
+the pattern. This escaping action applies whether or not the following
+character would otherwise be interpreted as a metacharacter, so it is always
+safe to precede a non-alphanumeric with backslash to specify that it stands
+for itself. In particular, if you want to match a backslash, you write ``\\``.
+
+
+Non-printing characters
+-----------------------
+A second use of backslash provides a way of encoding non-printing characters
+in patterns in a visible manner. There is no restriction on the appearance of
+non-printing characters, apart from the binary zero that terminates a pattern,
+but when a pattern is being prepared by text editing, it is usually easier to
+use one of the following escape sequences than the binary character it
+represents::
+
+==============     ============================================================
+character          meaning
+==============     ============================================================
+``\a``             alarm, that is, the BEL character (hex 07)
+``\e``             escape (hex 1B)
+``\f``             formfeed (hex 0C)
+``\n``             newline (hex 0A)
+``\r``             carriage return (hex 0D)
+``\t``             tab (hex 09)
+``\ddd``           character with octal code ddd, or backreference
+``\xhh``           character with hex code hh
+==============     ============================================================
+
+After ``\x``, from zero to two hexadecimal digits are read (letters can be in
+upper or lower case). In UTF-8 mode, any number of hexadecimal digits may
+appear between ``\x{`` and ``}``, but the value of the character code must be
+less than 2**31 (that is, the maximum hexadecimal value is 7FFFFFFF). If
+characters other than hexadecimal digits appear between ``\x{`` and ``}``, or
+if there is no terminating ``}``, this form of escape is not recognized.
+Instead, the initial ``\x`` will be interpreted as a basic hexadecimal escape,
+with no following digits, giving a character whose value is zero.
+
+After ``\0`` up to two further octal digits are read. In both cases, if there
+are fewer than two digits, just those that are present are used. Thus the
+sequence ``\0\x\07`` specifies two binary zeros followed by a BEL character
+(code value 7). Make sure you supply two digits after the initial zero if
+the pattern character that follows is itself an octal digit.
+
+The handling of a backslash followed by a digit other than 0 is complicated.
+Outside a character class, PCRE reads it and any following digits as a
+decimal number. If the number is less than 10, or if there have been at least
+that many previous capturing left parentheses in the expression, the entire
+sequence is taken as a back reference. A description of how this works is
+given later, following the discussion of parenthesized subpatterns.
+
+Inside a character class, or if the decimal number is greater than 9 and
+there have not been that many capturing subpatterns, PCRE re-reads up to
+three octal digits following the backslash, and generates a single byte
+from the least significant 8 bits of the value. Any subsequent digits stand
+for themselves. For example:
+
+==============     ============================================================
+example            meaning
+==============     ============================================================
+``\040``           is another way of writing a space
+``\40``            is the same, provided there are fewer than 40 previous 
+                   capturing subpatterns
+``\7``             is always a back reference
+``\11``            might be a back reference, or another way of writing a tab
+``\011``           is always a tab
+``\0113``          is a tab followed by the character "3"
+``\113``           might be a back reference, otherwise the character with 
+                   octal code 113
+``\377``           might be a back reference, otherwise the byte consisting 
+                   entirely of 1 bits
+``\81``            is either a back reference, or a binary zero followed by 
+                   the two characters "8" and "1"
+==============     ============================================================
+
+Note that octal values of 100 or greater must not be introduced by a leading
+zero, because no more than three octal digits are ever read.
+
+All the sequences that define a single byte value or a single UTF-8 character
+(in UTF-8 mode) can be used both inside and outside character classes. In
+addition, inside a character class, the sequence ``\b`` is interpreted as the
+backspace character (hex 08), and the sequence ``\X`` is interpreted as the
+character "X". Outside a character class, these sequences have different
+meanings (see below).
+
+Generic character types
+-----------------------
+The third use of backslash is for specifying `generic character types`:idx:.
+The following are always recognized:
+
+==============     ============================================================
+character type     meaning
+==============     ============================================================
+``\d``             any decimal digit
+``\D``             any character that is not a decimal digit
+``\s``             any whitespace character
+``\S``             any character that is not a whitespace character
+``\w``             any "word" character
+``\W``             any "non-word" character
+==============     ============================================================
+
+Each pair of escape sequences partitions the complete set of characters into
+two disjoint sets. Any given character matches one, and only one, of each pair.
+
+These character type sequences can appear both inside and outside character
+classes. They each match one character of the appropriate type. If the
+current matching point is at the end of the subject string, all of them fail,
+since there is no character to match.
+
+For compatibility with Perl, ``\s`` does not match the VT character (code 11).
+This makes it different from the the POSIX "space" class. The ``\s`` characters
+are HT (9), LF (10), FF (12), CR (13), and space (32).
+
+A "word" character is an underscore or any character less than 256 that is
+a letter or digit. The definition of letters and digits is controlled by
+PCRE's low-valued character tables, and may vary if locale-specific matching
+is taking place (see "Locale support" in the pcreapi page). For example,
+in the "fr_FR" (French) locale, some character codes greater than 128 are
+used for accented letters, and these are matched by ``\w``.
+
+In UTF-8 mode, characters with values greater than 128 never match ``\d``,
+``\s``, or ``\w``, and always match ``\D``, ``\S``, and ``\W``. This is true
+even when Unicode character property support is available.
+
+Simple assertions
+-----------------
+The fourth use of backslash is for certain `simple assertions`:idx:. An 
+assertion specifies a condition that has to be met at a particular point in
+a match, without consuming any characters from the subject string. The use of
+subpatterns for more complicated assertions is described below. The
+backslashed assertions are::
+
+==============     ============================================================
+assertion          meaning
+==============     ============================================================
+``\b``             matches at a word boundary
+``\B``             matches when not at a word boundary
+``\A``             matches at start of subject
+``\Z``             matches at end of subject or before newline at end
+``\z``             matches at end of subject
+``\G``             matches at first matching position in subject
+==============     ============================================================
+
+These assertions may not appear in character classes (but note that ``\b``
+has a different meaning, namely the backspace character, inside a character
+class).
+
+A word boundary is a position in the subject string where the current
+character and the previous character do not both match ``\w`` or ``\W`` (i.e.
+one matches ``\w`` and the other matches ``\W``), or the start or end of the
+string if the first or last character matches ``\w``, respectively.
+
+The ``\A``, ``\Z``, and ``\z`` assertions differ from the traditional
+circumflex and dollar in that they only ever match at the very start and
+end of the subject string, whatever options are set.
+The difference between ``\Z`` and ``\z`` is that ``\Z`` matches before
+a newline that is the last character of the string as well as at the end
+of the string, whereas ``\z`` matches only at the end.
diff --git a/doc/sets_fragment.txt b/doc/sets_fragment.txt
new file mode 100644
index 000000000..84b13e672
--- /dev/null
+++ b/doc/sets_fragment.txt
@@ -0,0 +1,39 @@
+The set type models the mathematical notion of a set. The set's
+basetype can only be an ordinal type. The reason is that sets are implemented
+as high performance bit vectors.
+
+Sets can be constructed via the set constructor: ``{}`` is the empty set. The
+empty set is type compatible with any concrete set type. The constructor
+can also be used to include elements (and ranges of elements):
+
+.. code-block:: nim
+  type
+    CharSet = set[char]
+  var
+    x: CharSet
+  x = {'a'..'z', '0'..'9'} # This constructs a set that contains the
+                           # letters from 'a' to 'z' and the digits
+                           # from '0' to '9'
+
+These operations are supported by sets:
+
+==================    ========================================================
+operation             meaning
+==================    ========================================================
+``A + B``             union of two sets
+``A * B``             intersection of two sets
+``A - B``             difference of two sets (A without B's elements)
+``A == B``            set equality
+``A <= B``            subset relation (A is subset of B or equal to B)
+``A < B``             strong subset relation (A is a real subset of B)
+``e in A``            set membership (A contains element e)
+``e notin A``         A does not contain element e
+``contains(A, e)``    A contains element e
+``card(A)``           the cardinality of A (number of elements in A)
+``incl(A, elem)``     same as ``A = A + {elem}``
+``excl(A, elem)``     same as ``A = A - {elem}``
+==================    ========================================================
+
+Sets are often used to define a type for the *flags* of a procedure. This is
+a much cleaner (and type safe) solution than just defining integer
+constants that should be ``or``'ed together.
diff --git a/doc/spawn.txt b/doc/spawn.txt
new file mode 100644
index 000000000..36bd02e96
--- /dev/null
+++ b/doc/spawn.txt
@@ -0,0 +1,96 @@
+==========================================================
+                  Parallel & Spawn
+==========================================================
+
+Nim has two flavors of parallelism: 
+1) `Structured`:idx parallelism via the ``parallel`` statement.
+2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement.
+
+Both need the `threadpool <threadpool.html>`_ module to work.
+
+Somewhat confusingly, ``spawn`` is also used in the ``parallel`` statement
+with slightly different semantics. ``spawn`` always takes a call expression of
+the form ``f(a, ...)``. Let ``T`` be ``f``'s return type. If ``T`` is ``void``
+then ``spawn``'s return type is also ``void``. Within a ``parallel`` section
+``spawn``'s return type is ``T``, otherwise it is ``FlowVar[T]``.
+
+The compiler can ensure the location in ``location = spawn f(...)`` is not
+read prematurely within a ``parallel`` section and so there is no need for
+the overhead of an indirection via ``FlowVar[T]`` to ensure correctness.
+
+
+Spawn statement
+===============
+
+A standalone ``spawn`` statement is a simple construct. It executes
+the passed expression on the thread pool and returns a `data flow variable`:idx:
+``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is
+**blocking**. However, one can use ``awaitAny`` to wait on multiple flow
+variables at the same time:
+
+.. code-block:: nim
+  import threadpool, ...
+  
+  # wait until 2 out of 3 servers received the update:
+  proc main =
+    var responses = newSeq[FlowVarBase](3)
+    for i in 0..2:
+      responses[i] = spawn tellServer(Update, "key", "value")
+    var index = awaitAny(responses)
+    assert index >= 0
+    responses.del(index)
+    discard awaitAny(responses)
+
+Data flow variables ensure that no data races
+are possible. Due to technical limitations not every type ``T`` is possible in
+a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq``
+or of a type that doesn't contain a type that is garbage collected. This
+restriction will be removed in the future.
+
+
+
+Parallel statement
+==================
+
+Example:
+
+.. code-block:: nim
+  # Compute PI in an inefficient way
+  import strutils, math, threadpool
+
+  proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1)
+
+  proc pi(n: int): float =
+    var ch = newSeq[float](n+1)
+    parallel:
+      for k in 0..ch.high:
+        ch[k] = spawn term(float(k))
+    for k in 0..ch.high:
+      result += ch[k]
+
+  echo formatFloat(pi(5000))
+
+
+The parallel statement is the preferred mechanism to introduce parallelism
+in a Nim program. A subset of the Nim language is valid within a
+``parallel`` section. This subset is checked to be free of data races at
+compile time. A sophisticated `disjoint checker`:idx: ensures that no data
+races are possible even though shared memory is extensively supported!
+
+The subset is in fact the full language with the following
+restrictions / changes:
+
+* ``spawn`` within a ``parallel`` section has special semantics.
+* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where
+  ``dest`` is part of the pattern ``dest = spawn f(...)`` has to be
+  provably disjoint. This is called the *disjoint check*.
+* Every other complex location ``loc`` that is used in a spawned
+  proc (``spawn f(loc)``) has to be immutable for the duration of
+  the ``parallel`` section. This is called the *immutability check*. Currently
+  it is not specified what exactly "complex location" means. We need to make
+  this an optimization!
+* Every array access has to be provably within bounds. This is called 
+  the *bounds check*.
+* Slices are optimized so that no copy is performed. This optimization is not
+  yet performed for ordinary slices outside of a ``parallel`` section. Slices
+  are also special in that they currently do not support negative indexes!
diff --git a/doc/subexes.txt b/doc/subexes.txt
new file mode 100644
index 000000000..decf30eef
--- /dev/null
+++ b/doc/subexes.txt
@@ -0,0 +1,61 @@
+Substitution Expressions (subex)
+================================
+
+A *subex* (*Substitution Expression*) represents an advanted string 
+substitution. In contrast to a `regex`:idx: which deals with string analysis, a
+*subex* deals with string synthesis.
+
+Thanks to its conditional construct ``$[0|1|2|else]`` it supports 
+`internationalization`:idx: of format string literals quite well.
+
+
+=====================   =====================================================
+Notation                meaning
+=====================   =====================================================
+``$#``                  use first or next argument
+``$name``               use named argument, you can wrap the named argument
+                        in curly braces (eg. ``${name}``) to separate it from
+                        the next characters.
+``$$``                  produces a single ``$``
+``$1``                  use first argument
+``$-1``                 use last argument
+``${1..3}``             use arguments 1 to 3
+``${..}``               use all arguments
+``$*``                  use all arguments (same as ``${..}``)
+``${#..}``              use all remaining arguments
+``${..-2}``             use all arguments except the last argument
+``${$1}``               use argument X where ``X = parseInt(arg[1])``
+``${$1..$2}``           use arguments X to Y where ``X = parseInt(arg[1])``
+                        and ``Y = parseInt(arg[2])``
+``$','{1..3}``          use arguments 1 to 3 and join them with ','
+``$','80c'\n'{..}``     use all arguments, join them with ','. Insert '\\n'
+                        before the resulting string exceeds 80 chars.
+``$','8i'\n'{..}``      use all arguments, join them with ','. Insert '\\n'
+                        after every 8th item.
+``$' '~{1..3}``         use arguments 1 to 3 with a leading space if the
+                        concatenation of ``1..3`` is not the empty string
+``$[zero|one|def]1``    use ``X = parseInt(arg[1])`` to determine which
+                        branch to use. If ``X == 0`` the 'zero' branch is
+                        selected, if ``X == 1`` the 'one' branch is
+                        selected, etc. Otherwise the 'def' branch is 
+                        selected. ``$x`` is interpreted in branches too.
+                        If a branch needs to contain ``|``, ``]`` put
+                        them in single quotes. To produce a verbatim single
+                        quote, use ``''``.
+=====================   =====================================================
+
+Examples
+========
+
+.. code-block:: nim
+
+  subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
+  
+  subex"$1 $[files|file|files]{1} copied" % ["1"] == "1 file copied"
+  
+  subex"$['''|'|''''|']']#" % "0" == "'|"
+  
+  subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
+    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
+    
+
diff --git a/doc/tools.txt b/doc/tools.txt
new file mode 100644
index 000000000..b0a45c575
--- /dev/null
+++ b/doc/tools.txt
@@ -0,0 +1,29 @@
+========================
+Tools available with Nim
+========================
+
+The standard distribution ships with the following tools:
+
+- | `Nimsuggest for IDE support <nimsuggest.html>`_
+  | Through the ``nimsuggest`` tool, any IDE can query a ``.nim`` source file
+    and obtain useful information like definition of symbols or suggestions for
+    completion.
+
+- | `Nim Installation Generator <niminst.html>`_
+  | How to generate a nice installer for your Nim program.
+
+- | `C2nim <c2nim.html>`_
+  | C to Nim source converter. Translates C header files to Nim.
+
+- | `nimgrep <nimgrep.html>`_
+  | Nim search and replace utility.
+
+- | `endb <endb.html>`_
+  | Nim's slow platform independent embedded debugger.
+
+- | `estp <estp.html>`_
+  | Nim's slow platform independent embedded stack trace profiler.
+
+- | `nimfix <nimfix.html>`_
+  | Nimfix is a tool to help you upgrade from Nimrod (<= version 0.9.6) to
+    Nim (=> version 0.10.0).
diff --git a/doc/tut1.txt b/doc/tut1.txt
new file mode 100644
index 000000000..1fa495054
--- /dev/null
+++ b/doc/tut1.txt
@@ -0,0 +1,1670 @@
+=====================
+Nim Tutorial (Part I)
+=====================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+Introduction
+============
+
+.. raw:: html
+  <blockquote><p>
+  "Der Mensch ist doch ein Augentier -- sch&ouml;ne Dinge w&uuml;nsch ich mir."
+  </p></blockquote>
+
+
+This document is a tutorial for the programming language *Nim*.
+This tutorial assumes that you are familiar with basic programming concepts
+like variables, types or statements but is kept very basic. The `manual
+<manual.html>`_ contains many more examples of the advanced language features.
+
+
+
+The first program
+=================
+
+We start the tour with a modified "hello world" program:
+
+.. code-block:: Nim
+  # This is a comment
+  echo("What's your name? ")
+  var name: string = readLine(stdin)
+  echo("Hi, ", name, "!")
+
+
+Save this code to the file "greetings.nim". Now compile and run it::
+
+  nim compile --run greetings.nim
+
+With the ``--run`` `switch <nimc.html#command-line-switches>`_ Nim
+executes the file automatically after compilation. You can give your program
+command line arguments by appending them after the filename::
+
+  nim compile --run greetings.nim arg1 arg2
+
+Commonly used commands and switches have abbreviations, so you can also use::
+
+  nim c -r greetings.nim
+
+To compile a release version use::
+
+  nim c -d:release greetings.nim
+
+By default the Nim compiler generates a large amount of runtime checks
+aiming for your debugging pleasure. With ``-d:release`` these checks are
+`turned off and optimizations are turned on
+<nimc.html#compile-time-symbols>`_.
+
+Though it should be pretty obvious what the program does, I will explain the
+syntax: statements which are not indented are executed when the program
+starts. Indentation is Nim's way of grouping statements. Indentation is
+done with spaces only, tabulators are not allowed.
+
+String literals are enclosed in double quotes. The ``var`` statement declares
+a new variable named ``name`` of type ``string`` with the value that is
+returned by the `readLine <system.html#readLine,File>`_ procedure. Since the
+compiler knows that `readLine <system.html#readLine,File>`_ returns a string,
+you can leave out the type in the declaration (this is called `local type
+inference`:idx:). So this will work too:
+
+.. code-block:: Nim
+  var name = readLine(stdin)
+
+Note that this is basically the only form of type inference that exists in
+Nim: it is a good compromise between brevity and readability.
+
+The "hello world" program contains several identifiers that are already known
+to the compiler: ``echo``, `readLine <system.html#readLine,File>`_, etc.
+These built-ins are declared in the system_ module which is implicitly
+imported by any other module.
+
+
+Lexical elements
+================
+
+Let us look at Nim's lexical elements in more detail: like other
+programming languages Nim consists of (string) literals, identifiers,
+keywords, comments, operators, and other punctuation marks.
+
+
+String and character literals
+-----------------------------
+
+String literals are enclosed in double quotes; character literals in single
+quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t``
+means tabulator, etc. There are also *raw* string literals:
+
+.. code-block:: Nim
+  r"C:\program files\nim"
+
+In raw literals the backslash is not an escape character.
+
+The third and last way to write string literals are *long string literals*.
+They are written with three quotes: ``""" ... """``; they can span over
+multiple lines and the ``\`` is not an escape character either. They are very
+useful for embedding HTML code templates for example.
+
+
+Comments
+--------
+
+Comments start anywhere outside a string or character literal with the
+hash character ``#``. Documentation comments start with ``##``:
+
+.. code-block:: nim
+  # A comment.
+
+  var myVariable: int ## a documentation comment
+
+
+Documentation comments are tokens; they are only allowed at certain places in
+the input file as they belong to the syntax tree! This feature enables simpler
+documentation generators.
+
+You can also use the `discard statement`_ together with *long string
+literals* to create block comments:
+
+.. code-block:: nim
+  discard """ You can have any Nim code text commented
+  out inside this with no indentation restrictions.
+        yes("May I ask a pointless question?") """
+
+
+Numbers
+-------
+
+Numerical literals are written as in most other languages. As a special twist,
+underscores are allowed for better readability: ``1_000_000`` (one million).
+A number that contains a dot (or 'e' or 'E') is a floating point literal:
+``1.0e9`` (one billion). Hexadecimal literals are prefixed with ``0x``,
+binary literals with ``0b`` and octal literals with ``0o``. A leading zero
+alone does not produce an octal.
+
+
+The var statement
+=================
+The var statement declares a new local or global variable:
+
+.. code-block::
+  var x, y: int # declares x and y to have the type ``int``
+
+Indentation can be used after the ``var`` keyword to list a whole section of
+variables:
+
+.. code-block::
+  var
+    x, y: int
+    # a comment can occur here too
+    a, b, c: string
+
+
+The assignment statement
+========================
+
+The assignment statement assigns a new value to a variable or more generally
+to a storage location:
+
+.. code-block::
+  var x = "abc" # introduces a new variable `x` and assigns a value to it
+  x = "xyz"     # assigns a new value to `x`
+
+``=`` is the *assignment operator*. The assignment operator cannot be
+overloaded, overwritten or forbidden, but this might change in a future version
+of Nim. You can declare multiple variables with a single assignment
+statement and all the variables will have the same value:
+
+.. code-block::
+  var x, y = 3  # assigns 3 to the variables `x` and `y`
+  echo "x ", x  # outputs "x 3"
+  echo "y ", y  # outputs "y 3"
+  x = 42        # changes `x` to 42 without changing `y`
+  echo "x ", x  # outputs "x 42"
+  echo "y ", y  # outputs "y 3"
+
+Note that declaring multiple variables with a single assignment which calls a
+procedure can have unexpected results: the compiler will *unroll* the
+assignments and end up calling the procedure several times. If the result of
+the procedure depends on side effects, your variables may end up having
+different values! For safety use only constant values.
+
+
+Constants
+=========
+
+Constants are symbols which are bound to a value. The constant's value
+cannot change. The compiler must be able to evaluate the expression in a
+constant declaration at compile time:
+
+.. code-block:: nim
+  const x = "abc" # the constant x contains the string "abc"
+
+Indentation can be used after the ``const`` keyword to list a whole section of
+constants:
+
+.. code-block::
+  const
+    x = 1
+    # a comment can occur here too
+    y = 2
+    z = y + 5 # computations are possible
+
+
+The let statement
+=================
+The ``let`` statement works like the ``var`` statement but the declared
+symbols are *single assignment* variables: After the initialization their
+value cannot change:
+
+.. code-block::
+  let x = "abc" # introduces a new variable `x` and binds a value to it
+  x = "xyz"     # Illegal: assignment to `x`
+
+The difference between ``let`` and ``const`` is: ``let`` introduces a variable
+that can not be re-assigned, ``const`` means "enforce compile time evaluation
+and put it into a data section":
+
+.. code-block::
+  const input = readLine(stdin) # Error: constant expression expected
+
+.. code-block::
+  let input = readLine(stdin)   # works
+
+
+Control flow statements
+=======================
+
+The greetings program consists of 3 statements that are executed sequentially.
+Only the most primitive programs can get away with that: branching and looping
+are needed too.
+
+
+If statement
+------------
+
+The if statement is one way to branch the control flow:
+
+.. code-block:: nim
+  let name = readLine(stdin)
+  if name == "":
+    echo("Poor soul, you lost your name?")
+  elif name == "name":
+    echo("Very funny, your name is name.")
+  else:
+    echo("Hi, ", name, "!")
+
+There can be zero or more ``elif`` parts, and the ``else`` part is optional.
+The keyword ``elif`` is short for ``else if``, and is useful to avoid
+excessive indentation. (The ``""`` is the empty string. It contains no
+characters.)
+
+
+Case statement
+--------------
+
+Another way to branch is provided by the case statement. A case statement is
+a multi-branch:
+
+.. code-block:: nim
+  let name = readLine(stdin)
+  case name
+  of "":
+    echo("Poor soul, you lost your name?")
+  of "name":
+    echo("Very funny, your name is name.")
+  of "Dave", "Frank":
+    echo("Cool name!")
+  else:
+    echo("Hi, ", name, "!")
+
+As it can be seen, for an ``of`` branch a comma separated list of values is also
+allowed.
+
+The case statement can deal with integers, other ordinal types and strings.
+(What an ordinal type is will be explained soon.)
+For integers or other ordinal types value ranges are also possible:
+
+.. code-block:: nim
+  # this statement will be explained later:
+  from strutils import parseInt
+
+  echo("A number please: ")
+  let n = parseInt(readLine(stdin))
+  case n
+  of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
+  of 3, 8: echo("The number is 3 or 8")
+
+However, the above code does not compile: the reason is that you have to cover
+every value that ``n`` may contain, but the code only handles the values
+``0..8``. Since it is not very practical to list every other possible integer
+(though it is possible thanks to the range notation), we fix this by telling
+the compiler that for every other value nothing should be done:
+
+.. code-block:: nim
+  ...
+  case n
+  of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}")
+  of 3, 8: echo("The number is 3 or 8")
+  else: discard
+
+The empty `discard statement`_ is a *do nothing* statement. The compiler knows
+that a case statement with an else part cannot fail and thus the error
+disappears. Note that it is impossible to cover all possible string values:
+that is why string cases always need an ``else`` branch.
+
+In general the case statement is used for subrange types or enumerations where
+it is of great help that the compiler checks that you covered any possible
+value.
+
+
+While statement
+---------------
+
+The while statement is a simple looping construct:
+
+.. code-block:: nim
+
+  echo("What's your name? ")
+  var name = readLine(stdin)
+  while name == "":
+    echo("Please tell me your name: ")
+    name = readLine(stdin)
+    # no ``var``, because we do not declare a new variable here
+
+The example uses a while loop to keep asking the user for his name, as long as
+he types in nothing (only presses RETURN).
+
+
+For statement
+-------------
+
+The ``for`` statement is a construct to loop over any element an *iterator*
+provides. The example uses the built-in `countup <system.html#countup>`_
+iterator:
+
+.. code-block:: nim
+  echo("Counting to ten: ")
+  for i in countup(1, 10):
+    echo($i)
+  # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
+
+The built-in `$ <system.html#$>`_ operator turns an integer (``int``) and many
+other types into a string. The variable ``i`` is implicitly declared by the
+``for`` loop and has the type ``int``, because that is what `countup
+<system.html#countup>`_ returns. ``i`` runs through the values 1, 2, .., 10.
+Each value is ``echo``-ed. This code does the same:
+
+.. code-block:: nim
+  echo("Counting to 10: ")
+  var i = 1
+  while i <= 10:
+    echo($i)
+    inc(i) # increment i by 1
+  # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
+
+Counting down can be achieved as easily (but is less often needed):
+
+.. code-block:: nim
+  echo("Counting down from 10 to 1: ")
+  for i in countdown(10, 1):
+    echo($i)
+  # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
+
+Since counting up occurs so often in programs, Nim also has a `..
+<system.html#...i,S,T>`_ iterator that does the same:
+
+.. code-block:: nim
+  for i in 1..10:
+    ...
+
+
+Scopes and the block statement
+------------------------------
+Control flow statements have a feature not covered yet: they open a
+new scope. This means that in the following example, ``x`` is not accessible
+outside the loop:
+
+.. code-block:: nim
+  while false:
+    var x = "hi"
+  echo(x) # does not work
+
+A while (for) statement introduces an implicit block. Identifiers
+are only visible within the block they have been declared. The ``block``
+statement can be used to open a new block explicitly:
+
+.. code-block:: nim
+  block myblock:
+    var x = "hi"
+  echo(x) # does not work either
+
+The block's *label* (``myblock`` in the example) is optional.
+
+
+Break statement
+---------------
+A block can be left prematurely with a ``break`` statement. The break statement
+can leave a ``while``, ``for``, or a ``block`` statement. It leaves the
+innermost construct, unless a label of a block is given:
+
+.. code-block:: nim
+  block myblock:
+    echo("entering block")
+    while true:
+      echo("looping")
+      break # leaves the loop, but not the block
+    echo("still in block")
+
+  block myblock2:
+    echo("entering block")
+    while true:
+      echo("looping")
+      break myblock2 # leaves the block (and the loop)
+    echo("still in block")
+
+
+Continue statement
+------------------
+Like in many other programming languages, a ``continue`` statement starts
+the next iteration immediately:
+
+.. code-block:: nim
+  while true:
+    let x = readLine(stdin)
+    if x == "": continue
+    echo(x)
+
+
+When statement
+--------------
+
+Example:
+
+.. code-block:: nim
+
+  when system.hostOS == "windows":
+    echo("running on Windows!")
+  elif system.hostOS == "linux":
+    echo("running on Linux!")
+  elif system.hostOS == "macosx":
+    echo("running on Mac OS X!")
+  else:
+    echo("unknown operating system")
+
+The ``when`` statement is almost identical to the ``if`` statement with some
+differences:
+
+* Each condition has to be a constant expression since it is evaluated by the
+  compiler.
+* The statements within a branch do not open a new scope.
+* The compiler checks the semantics and produces code *only* for the statements
+  that belong to the first condition that evaluates to ``true``.
+
+The ``when`` statement is useful for writing platform specific code, similar to
+the ``#ifdef`` construct in the C programming language.
+
+**Note**: To comment out a large piece of code, it is often better to use a
+``when false:`` statement than to use real comments. This way nesting is
+possible.
+
+
+Statements and indentation
+==========================
+
+Now that we covered the basic control flow statements, let's return to Nim
+indentation rules.
+
+In Nim there is a distinction between *simple statements* and *complex
+statements*. *Simple statements* cannot contain other statements:
+Assignment, procedure calls or the ``return`` statement belong to the simple
+statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can
+contain other statements. To avoid ambiguities, complex statements always have
+to be indented, but single simple statements do not:
+
+.. code-block:: nim
+  # no indentation needed for single assignment statement:
+  if x: x = false
+
+  # indentation needed for nested if statement:
+  if x:
+    if y:
+      y = false
+    else:
+      y = true
+
+  # indentation needed, because two statements follow the condition:
+  if x:
+    x = false
+    y = false
+
+
+*Expressions* are parts of a statement which usually result in a value. The
+condition in an if statement is an example for an expression. Expressions can
+contain indentation at certain places for better readability:
+
+.. code-block:: nim
+
+  if thisIsaLongCondition() and
+      thisIsAnotherLongCondition(1,
+         2, 3, 4):
+    x = true
+
+As a rule of thumb, indentation within expressions is allowed after operators,
+an open parenthesis and after commas.
+
+With parenthesis and semicolons ``(;)`` you can use statements where only
+an expression is allowed:
+
+.. code-block:: nim
+  # computes fac(4) at compile time:
+  const fac4 = (var x = 1; for i in 1..4: x *= i; x)
+
+
+Procedures
+==========
+
+To define new commands like `echo <system.html#echo>`_ and `readLine
+<system.html#readLine,File>`_ in the examples, the concept of a `procedure`
+is needed. (Some languages call them *methods* or *functions*.) In Nim new
+procedures are defined with the ``proc`` keyword:
+
+.. code-block:: nim
+  proc yes(question: string): bool =
+    echo(question, " (y/n)")
+    while true:
+      case readLine(stdin)
+      of "y", "Y", "yes", "Yes": return true
+      of "n", "N", "no", "No": return false
+      else: echo("Please be clear: yes or no")
+
+  if yes("Should I delete all your important files?"):
+    echo("I'm sorry Dave, I'm afraid I can't do that.")
+  else:
+    echo("I think you know what the problem is just as well as I do.")
+
+This example shows a procedure named ``yes`` that asks the user a ``question``
+and returns true if he answered "yes" (or something similar) and returns
+false if he answered "no" (or something similar). A ``return`` statement leaves
+the procedure (and therefore the while loop) immediately. The
+``(question: string): bool`` syntax describes that the procedure expects a
+parameter named ``question`` of type ``string`` and returns a value of type
+``bool``. ``Bool`` is a built-in type: the only valid values for ``bool`` are
+``true`` and ``false``.
+The conditions in if or while statements should be of the type ``bool``.
+
+Some terminology: in the example ``question`` is called a (formal) *parameter*,
+``"Should I..."`` is called an *argument* that is passed to this parameter.
+
+
+Result variable
+---------------
+A procedure that returns a value has an implicit ``result`` variable declared
+that represents the return value. A ``return`` statement with no expression is a
+shorthand for ``return result``. The ``result`` value is always returned
+automatically at the end a procedure if there is no ``return`` statement at
+the exit.
+
+.. code-block:: nim
+  proc sumTillNegative(x: varargs[int]): int =
+    for i in x:
+      if i < 0:
+        return
+      result = result + i
+
+  echo sumTillNegative() # echos 0
+  echo sumTillNegative(3, 4, 5) # echos 12
+  echo sumTillNegative(3, 4 , -1 , 6) # echos 7
+
+The ``result`` variable is already implicitly declared at the start of the
+function, so declaring it again with 'var result', for example, would shadow it
+with a normal variable of the same name. The result variable is also already
+initialised with the type's default value. Note that referential data types will
+be ``nil`` at the start of the procedure, and thus may require manual
+initialisation.
+
+
+Parameters
+----------
+Parameters are constant in the procedure body. By default, their value cannot be
+changed because this allows the compiler to implement parameter passing in the
+most efficient way. If a mutable variable is needed inside the procedure, it has
+to be declared with ``var`` in the procedure body. Shadowing the parameter name
+is possible, and actually an idiom:
+
+.. code-block:: nim
+  proc printSeq(s: seq, nprinted: int = -1) =
+    var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
+    for i in 0 .. <nprinted:
+      echo s[i]
+
+If the procedure needs to modify the argument for the
+caller, a ``var`` parameter can be used:
+
+.. code-block:: nim
+  proc divmod(a, b: int; res, remainder: var int) =
+    res = a div b        # integer division
+    remainder = a mod b  # integer modulo operation
+
+  var
+    x, y: int
+  divmod(8, 5, x, y) # modifies x and y
+  echo(x)
+  echo(y)
+
+In the example, ``res`` and ``remainder`` are `var parameters`.
+Var parameters can be modified by the procedure and the changes are
+visible to the caller. Note that the above example would better make use of
+a tuple as a return value instead of using var parameters.
+
+
+Discard statement
+-----------------
+To call a procedure that returns a value just for its side effects and ignoring
+its return value, a ``discard`` statement **has** to be used. Nim does not
+allow to silently throw away a return value:
+
+.. code-block:: nim
+  discard yes("May I ask a pointless question?")
+
+
+The return value can be ignored implicitly if the called proc/iterator has
+been declared with the ``discardable`` pragma:
+
+.. code-block:: nim
+  proc p(x, y: int): int {.discardable.} =
+    return x + y
+
+  p(3, 4) # now valid
+
+The ``discard`` statement can also be used to create block comments as
+described in the `Comments`_ section.
+
+
+Named arguments
+---------------
+
+Often a procedure has many parameters and it is not clear in which order the
+parameters appear. This is especially true for procedures that construct a
+complex data type. Therefore the arguments to a procedure can be named, so
+that it is clear which argument belongs to which parameter:
+
+.. code-block:: nim
+  proc createWindow(x, y, width, height: int; title: string;
+                    show: bool): Window =
+     ...
+
+  var w = createWindow(show = true, title = "My Application",
+                       x = 0, y = 0, height = 600, width = 800)
+
+Now that we use named arguments to call ``createWindow`` the argument order
+does not matter anymore. Mixing named arguments with ordered arguments is
+also possible, but not very readable:
+
+.. code-block:: nim
+  var w = createWindow(0, 0, title = "My Application",
+                       height = 600, width = 800, true)
+
+The compiler checks that each parameter receives exactly one argument.
+
+
+Default values
+--------------
+To make the ``createWindow`` proc easier to use it should provide `default
+values`, these are values that are used as arguments if the caller does not
+specify them:
+
+.. code-block:: nim
+  proc createWindow(x = 0, y = 0, width = 500, height = 700,
+                    title = "unknown",
+                    show = true): Window =
+     ...
+
+  var w = createWindow(title = "My Application", height = 600, width = 800)
+
+Now the call to ``createWindow`` only needs to set the values that differ
+from the defaults.
+
+Note that type inference works for parameters with default values; there is
+no need to write ``title: string = "unknown"``, for example.
+
+
+Overloaded procedures
+---------------------
+Nim provides the ability to overload procedures similar to C++:
+
+.. code-block:: nim
+  proc toString(x: int): string = ...
+  proc toString(x: bool): string =
+    if x: result = "true"
+    else: result = "false"
+
+  echo(toString(13))   # calls the toString(x: int) proc
+  echo(toString(true)) # calls the toString(x: bool) proc
+
+(Note that ``toString`` is usually the `$ <system.html#$>`_ operator in
+Nim.) The compiler chooses the most appropriate proc for the ``toString``
+calls. How this overloading resolution algorithm works exactly is not
+discussed here (it will be specified in the manual soon).  However, it does
+not lead to nasty surprises and is based on a quite simple unification
+algorithm. Ambiguous calls are reported as errors.
+
+
+Operators
+---------
+The Nim library makes heavy use of overloading - one reason for this is that
+each operator like ``+`` is a just an overloaded proc. The parser lets you
+use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``).
+An infix operator always receives two arguments, a prefix operator always one.
+Postfix operators are not possible, because this would be ambiguous: does
+``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means
+``(a) @ (@b)``, because there are no postfix operators in Nim.
+
+Apart from a few built-in keyword operators such as ``and``, ``or``, ``not``,
+operators always consist of these characters:
+``+  -  *  \  /  <  >  =  @  $  ~  &  %  !  ?  ^  .  |``
+
+User defined operators are allowed. Nothing stops you from defining your own
+``@!?+~`` operator, but readability can suffer.
+
+The operator's precedence is determined by its first character. The details
+can be found in the manual.
+
+To define a new operator enclose the operator in backticks "``":
+
+.. code-block:: nim
+  proc `$` (x: myDataType): string = ...
+  # now the $ operator also works with myDataType, overloading resolution
+  # ensures that $ works for built-in types just like before
+
+The "``" notation can also be used to call an operator just like any other
+procedure:
+
+.. code-block:: nim
+  if `==`( `+`(3, 4), 7): echo("True")
+
+
+Forward declarations
+--------------------
+
+Every variable, procedure, etc. needs to be declared before it can be used.
+(The reason for this is that it is non-trivial to do better than that in a
+language that supports meta programming as extensively as Nim does.)
+However, this cannot be done for mutually recursive procedures:
+
+.. code-block:: nim
+  # forward declaration:
+  proc even(n: int): bool
+
+  proc odd(n: int): bool =
+    n == 1 or even(n-1)
+
+  proc even(n: int): bool =
+    n == 0 or odd(n-1)
+
+Here ``odd`` depends on ``even`` and vice versa. Thus ``even`` needs to be
+introduced to the compiler before it is completely defined. The syntax for
+such a forward declaration is simple: just omit the ``=`` and the
+procedure's body.
+
+Later versions of the language will weaken the requirements for forward
+declarations.
+
+The example also shows that a proc's body can consist of a single expression
+whose value is then returned implicitly.
+
+
+Iterators
+=========
+
+Let's return to the boring counting example:
+
+.. code-block:: nim
+  echo("Counting to ten: ")
+  for i in countup(1, 10):
+    echo($i)
+
+Can a `countup <system.html#countup>`_ proc be written that supports this
+loop? Lets try:
+
+.. code-block:: nim
+  proc countup(a, b: int): int =
+    var res = a
+    while res <= b:
+      return res
+      inc(res)
+
+However, this does not work. The problem is that the procedure should not
+only ``return``, but return and **continue** after an iteration has
+finished. This *return and continue* is called a `yield` statement. Now
+the only thing left to do is to replace the ``proc`` keyword by ``iterator``
+and there it is - our first iterator:
+
+.. code-block:: nim
+  iterator countup(a, b: int): int =
+    var res = a
+    while res <= b:
+      yield res
+      inc(res)
+
+Iterators look very similar to procedures, but there are several
+important differences:
+
+* Iterators can only be called from for loops.
+* Iterators cannot contain a ``return`` statement and procs cannot contain a
+  ``yield`` statement.
+* Iterators have no implicit ``result`` variable.
+* Iterators do not support recursion.
+* Iterators cannot be forward declared, because the compiler must be able
+  to inline an iterator. (This restriction will be gone in a
+  future version of the compiler.)
+
+However, you can also use a ``closure`` iterator to get a different set of
+restrictions. See `first class iterators <manual.html#first-class-iterators>`_
+for details. Iterators can have the same name and parameters as a proc,
+essentially they have their own namespace. Therefore it is common practice to
+wrap iterators in procs of the same name which accumulate the result of the
+iterator and return it as a sequence, like ``split`` from the `strutils module
+<strutils.html>`_.
+
+
+Basic types
+===========
+
+This section deals with the basic built-in types and the operations
+that are available for them in detail.
+
+Booleans
+--------
+
+The boolean type is named ``bool`` in Nim and consists of the two
+pre-defined values ``true`` and ``false``. Conditions in while,
+if, elif, when statements need to be of type bool.
+
+The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined
+for the bool type. The ``and`` and ``or`` operators perform short-cut
+evaluation. Example:
+
+.. code-block:: nim
+
+  while p != nil and p.name != "xyz":
+    # p.name is not evaluated if p == nil
+    p = p.next
+
+
+Characters
+----------
+The `character type` is named ``char`` in Nim. Its size is one byte.
+Thus it cannot represent an UTF-8 character, but a part of it.
+The reason for this is efficiency: for the overwhelming majority of use-cases,
+the resulting programs will still handle UTF-8 properly as UTF-8 was specially
+designed for this.
+Character literals are enclosed in single quotes.
+
+Chars can be compared with the ``==``, ``<``, ``<=``, ``>``, ``>=`` operators.
+The ``$`` operator converts a ``char`` to a ``string``. Chars cannot be mixed
+with integers; to get the ordinal value of a ``char`` use the ``ord`` proc.
+Converting from an integer to a ``char`` is done with the ``chr`` proc.
+
+
+Strings
+-------
+String variables in Nim are **mutable**, so appending to a string
+is quite efficient. Strings in Nim are both zero-terminated and have a
+length field. One can retrieve a string's length with the builtin ``len``
+procedure; the length never counts the terminating zero. Accessing the
+terminating zero is no error and often leads to simpler code:
+
+.. code-block:: nim
+  if s[i] == 'a' and s[i+1] == 'b':
+    # no need to check whether ``i < len(s)``!
+    ...
+
+The assignment operator for strings copies the string. You can use the ``&``
+operator to concatenate strings and ``add`` to append to a string.
+
+Strings are compared by their lexicographical order. All comparison operators
+are available. Per convention, all strings are UTF-8 strings, but this is not
+enforced. For example, when reading strings from binary files, they are merely
+a sequence of bytes. The index operation ``s[i]`` means the i-th *char* of
+``s``, not the i-th *unichar*.
+
+String variables are initialized with a special value, called ``nil``. However,
+most string operations cannot deal with ``nil`` (leading to an exception being
+raised) for performance reasons. One should use empty strings ``""``
+rather than ``nil`` as the *empty* value. But ``""`` often creates a string
+object on the heap, so there is a trade-off to be made here.
+
+
+Integers
+--------
+Nim has these integer types built-in:
+``int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64``.
+
+The default integer type is ``int``. Integer literals can have a *type suffix*
+to mark them to be of another integer type:
+
+
+.. code-block:: nim
+  let
+    x = 0     # x is of type ``int``
+    y = 0'i8  # y is of type ``int8``
+    z = 0'i64 # z is of type ``int64``
+    u = 0'u   # u is of type ``uint``
+
+Most often integers are used for counting objects that reside in memory, so
+``int`` has the same size as a pointer.
+
+The common operators ``+ - * div mod  <  <=  ==  !=  >  >=`` are defined for
+integers. The ``and or xor not`` operators are defined for integers too and
+provide *bitwise* operations. Left bit shifting is done with the ``shl``, right
+shifting with the ``shr`` operator. Bit shifting operators always treat their
+arguments as *unsigned*. For `arithmetic bit shifts`:idx: ordinary
+multiplication or division can be used.
+
+Unsigned operations all wrap around; they cannot lead to over- or underflow
+errors.
+
+`Automatic type conversion`:idx: is performed in expressions where different
+kinds of integer types are used. However, if the type conversion
+loses information, the `EOutOfRange`:idx: exception is raised (if the error
+cannot be detected at compile time).
+
+
+Floats
+------
+Nim has these floating point types built-in: ``float float32 float64``.
+
+The default float type is ``float``. In the current implementation,
+``float`` is always 64 bit wide.
+
+Float literals can have a *type suffix* to mark them to be of another float
+type:
+
+.. code-block:: nim
+  var
+    x = 0.0      # x is of type ``float``
+    y = 0.0'f32  # y is of type ``float32``
+    z = 0.0'f64  # z is of type ``float64``
+
+The common operators ``+ - * /  <  <=  ==  !=  >  >=`` are defined for
+floats and follow the IEEE standard.
+
+Automatic type conversion in expressions with different kinds of floating
+point types is performed: the smaller type is converted to the larger. Integer
+types are **not** converted to floating point types automatically and vice
+versa. The `toInt <system.html#toInt>`_ and `toFloat <system.html#toFloat>`_
+procs can be used for these conversions.
+
+
+Type Conversion
+---------------
+Conversion between basic types in nim is performed by using the
+type as a function:
+
+.. code-block:: nim
+  var
+    x: int32 = 1.int32   # same as calling int32(1)
+    y: int8  = int8('a') # 'a' == 97'i8
+    z: float = 2.5       # int(2.5) rounds down to 2
+    sum: int = int(x) + int(y) + int(z) # sum == 100
+
+
+Internal type representation
+============================
+
+As mentioned earlier, the built-in `$ <system.html#$>`_ (stringify) operator
+turns any basic type into a string, which you can then print to the screen
+with the ``echo`` proc. However, advanced types, or types you may define
+yourself won't work with the ``$`` operator until you define one for them.
+Sometimes you just want to debug the current value of a complex type without
+having to write its ``$`` operator.  You can use then the `repr
+<system.html#repr>`_ proc which works with any type and even complex data
+graphs with cycles. The following example shows that even for basic types
+there is a difference between the ``$`` and ``repr`` outputs:
+
+.. code-block:: nim
+  var
+    myBool = true
+    myCharacter = 'n'
+    myString = "nim"
+    myInteger = 42
+    myFloat = 3.14
+  echo($myBool, ":", repr(myBool))
+  # --> true:true
+  echo($myCharacter, ":", repr(myCharacter))
+  # --> n:'n'
+  echo($myString, ":", repr(myString))
+  # --> nim:0x10fa8c050"nim"
+  echo($myInteger, ":", repr(myInteger))
+  # --> 42:42
+  echo($myFloat, ":", repr(myFloat))
+  # --> 3.1400000000000001e+00:3.1400000000000001e+00
+
+
+Advanced types
+==============
+
+In Nim new types can be defined within a ``type`` statement:
+
+.. code-block:: nim
+  type
+    biggestInt = int64      # biggest integer type that is available
+    biggestFloat = float64  # biggest float type that is available
+
+Enumeration and object types cannot be defined on the fly, but only within a
+``type`` statement.
+
+
+Enumerations
+------------
+A variable of an enumeration type can only be assigned a value of a
+limited set. This set consists of ordered symbols. Each symbol is mapped
+to an integer value internally. The first symbol is represented
+at runtime by 0, the second by 1 and so on. Example:
+
+.. code-block:: nim
+
+  type
+    Direction = enum
+      north, east, south, west
+
+  var x = south      # `x` is of type `Direction`; its value is `south`
+  echo($x)           # writes "south" to `stdout`
+
+All comparison operators can be used with enumeration types.
+
+An enumeration's symbol can be qualified to avoid ambiguities:
+``Direction.south``.
+
+The ``$`` operator can convert any enumeration value to its name, the ``ord``
+proc to its underlying integer value.
+
+For better interfacing to other programming languages, the symbols of enum
+types can be assigned an explicit ordinal value. However, the ordinal values
+have to be in ascending order. A symbol whose ordinal value is not
+explicitly given is assigned the value of the previous symbol + 1.
+
+An explicit ordered enum can have *holes*:
+
+.. code-block:: nim
+  type
+    MyEnum = enum
+      a = 2, b = 4, c = 89
+
+
+Ordinal types
+-------------
+Enumerations without holes, integer types, ``char`` and ``bool`` (and
+subranges) are called ordinal types. Ordinal types have quite
+a few special operations:
+
+-----------------     --------------------------------------------------------
+Operation             Comment
+-----------------     --------------------------------------------------------
+``ord(x)``            returns the integer value that is used to
+                      represent `x`'s value
+``inc(x)``            increments `x` by one
+``inc(x, n)``         increments `x` by `n`; `n` is an integer
+``dec(x)``            decrements `x` by one
+``dec(x, n)``         decrements `x` by `n`; `n` is an integer
+``succ(x)``           returns the successor of `x`
+``succ(x, n)``        returns the `n`'th successor of `x`
+``pred(x)``           returns the predecessor of `x`
+``pred(x, n)``        returns the `n`'th predecessor of `x`
+-----------------     --------------------------------------------------------
+
+The `inc <system.html#inc>`_, `dec <system.html#dec>`_, `succ
+<system.html#succ>`_ and `pred <system.html#pred>`_ operations can fail by
+raising an `EOutOfRange` or `EOverflow` exception. (If the code has been
+compiled with the proper runtime checks turned on.)
+
+
+Subranges
+---------
+A subrange type is a range of values from an integer or enumeration type
+(the base type). Example:
+
+.. code-block:: nim
+  type
+    Subrange = range[0..5]
+
+
+``Subrange`` is a subrange of ``int`` which can only hold the values 0
+to 5. Assigning any other value to a variable of type ``Subrange`` is a
+compile-time or runtime error. Assignments from the base type to one of its
+subrange types (and vice versa) are allowed.
+
+The ``system`` module defines the important `Natural <system.html#Natural>`_
+type as ``range[0..high(int)]`` (`high <system.html#high>`_ returns the
+maximal value). Other programming languages mandate the usage of unsigned
+integers for natural numbers. This is often **wrong**: you don't want unsigned
+arithmetic (which wraps around) just because the numbers cannot be negative.
+Nim's ``Natural`` type helps to avoid this common programming error.
+
+
+Sets
+----
+
+.. include:: sets_fragment.txt
+
+Arrays
+------
+An array is a simple fixed length container. Each element in
+the array has the same type. The array's index type can be any ordinal type.
+
+Arrays can be constructed via ``[]``:
+
+.. code-block:: nim
+
+  type
+    IntArray = array[0..5, int] # an array that is indexed with 0..5
+  var
+    x: IntArray
+  x = [1, 2, 3, 4, 5, 6]
+  for i in low(x)..high(x):
+    echo(x[i])
+
+The notation ``x[i]`` is used to access the i-th element of ``x``.
+Array access is always bounds checked (at compile-time or at runtime). These
+checks can be disabled via pragmas or invoking the compiler with the
+``--bound_checks:off`` command line switch.
+
+Arrays are value types, like any other Nim type. The assignment operator
+copies the whole array contents.
+
+The built-in `len <system.html#len,TOpenArray>`_ proc returns the array's
+length. `low(a) <system.html#low>`_ returns the lowest valid index for the
+array `a` and `high(a) <system.html#high>`_ the highest valid index.
+
+.. code-block:: nim
+  type
+    Direction = enum
+      north, east, south, west
+    BlinkLights = enum
+      off, on, slowBlink, mediumBlink, fastBlink
+    LevelSetting = array[north..west, BlinkLights]
+  var
+    level: LevelSetting
+  level[north] = on
+  level[south] = slowBlink
+  level[east] = fastBlink
+  echo repr(level)  # --> [on, fastBlink, slowBlink, off]
+  echo low(level)   # --> north
+  echo len(level)   # --> 4
+  echo high(level)  # --> west
+
+The syntax for nested arrays (multidimensional) in other languages is a matter
+of appending more brackets because usually each dimension is restricted to the
+same index type as the others. In Nim you can have different dimensions with
+different index types, so the nesting syntax is slightly different. Building on
+the previous example where a level is defined as an array of enums indexed by
+yet another enum, we can add the following lines to add a light tower type
+subdivided in height levels accessed through their integer index:
+
+.. code-block:: nim
+  type
+    LightTower = array[1..10, LevelSetting]
+  var
+    tower: LightTower
+  tower[1][north] = slowBlink
+  tower[1][east] = mediumBlink
+  echo len(tower)     # --> 10
+  echo len(tower[1])  # --> 4
+  echo repr(tower)    # --> [[slowBlink, mediumBlink, ...more output..
+  # The following lines don't compile due to type mismatch errors
+  #tower[north][east] = on
+  #tower[0][1] = on
+
+Note how the built-in ``len`` proc returns only the array's first dimension
+length.  Another way of defining the ``LightTower`` to show better its
+nested nature would be to omit the previous definition of the ``LevelSetting``
+type and instead write it embedded directly as the type of the first dimension:
+
+.. code-block:: nim
+  type
+    LightTower = array[1..10, array[north..west, BlinkLights]]
+
+It is quite frequent to have arrays start at zero, so there's a shortcut syntax
+to specify a range from zero to the specified index minus one:
+
+.. code-block:: nim
+  type
+    IntArray = array[0..5, int] # an array that is indexed with 0..5
+    QuickArray = array[6, int]  # an array that is indexed with 0..5
+  var
+    x: IntArray
+    y: QuickArray
+  x = [1, 2, 3, 4, 5, 6]
+  y = x
+  for i in low(x)..high(x):
+    echo(x[i], y[i])
+
+
+Sequences
+---------
+Sequences are similar to arrays but of dynamic length which may change
+during runtime (like strings). Since sequences are resizable they are always
+allocated on the heap and garbage collected.
+
+Sequences are always indexed with an ``int`` starting at position 0.  The `len
+<system.html#len,seq[T]>`_, `low <system.html#low>`_ and `high
+<system.html#high>`_ operations are available for sequences too.  The notation
+``x[i]`` can be used to access the i-th element of ``x``.
+
+Sequences can be constructed by the array constructor ``[]`` in conjunction
+with the array to sequence operator ``@``. Another way to allocate space for
+a sequence is to call the built-in `newSeq <system.html#newSeq>`_ procedure.
+
+A sequence may be passed to an openarray parameter.
+
+Example:
+
+.. code-block:: nim
+
+  var
+    x: seq[int] # a sequence of integers
+  x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence
+
+Sequence variables are initialized with ``nil``. However, most sequence
+operations cannot deal with ``nil`` (leading to an exception being
+raised) for performance reasons. Thus one should use empty sequences ``@[]``
+rather than ``nil`` as the *empty* value. But ``@[]`` creates a sequence
+object on the heap, so there is a trade-off to be made here.
+
+The ``for`` statement can be used with one or two variables when used with a
+sequence. When you use the one variable form, the variable will hold the value
+provided by the sequence. The ``for`` statement is looping over the results
+from the `items() <system.html#items.i,seq[T]>`_ iterator from the `system
+<system.html>`_ module.  But if you use the two variable form, the first
+variable will hold the index position and the second variable will hold the
+value. Here the ``for`` statement is looping over the results from the
+`pairs() <system.html#pairs.i,seq[T]>`_ iterator from the `system
+<system.html>`_ module.  Examples:
+
+.. code-block:: nim
+  for i in @[3, 4, 5]:
+    echo($i)
+  # --> 3
+  # --> 4
+  # --> 5
+
+  for i, value in @[3, 4, 5]:
+    echo("index: ", $i, ", value:", $value)
+  # --> index: 0, value:3
+  # --> index: 1, value:4
+  # --> index: 2, value:5
+
+
+Open arrays
+-----------
+**Note**: Openarrays can only be used for parameters.
+
+Often fixed size arrays turn out to be too inflexible; procedures should be
+able to deal with arrays of different sizes. The `openarray`:idx: type allows
+this. Openarrays are always indexed with an ``int`` starting at position 0.
+The `len <system.html#len,TOpenArray>`_, `low <system.html#low>`_ and `high
+<system.html#high>`_ operations are available for open arrays too.  Any array
+with a compatible base type can be passed to an openarray parameter, the index
+type does not matter.
+
+The openarray type cannot be nested: multidimensional openarrays are not
+supported because this is seldom needed and cannot be done efficiently.
+
+
+Varargs
+-------
+
+A ``varargs`` parameter is like an openarray parameter. However, it is
+also a means to implement passing a variable number of
+arguments to a procedure. The compiler converts the list of arguments
+to an array automatically:
+
+.. code-block:: nim
+  proc myWriteln(f: File, a: varargs[string]) =
+    for s in items(a):
+      write(f, s)
+    write(f, "\n")
+
+  myWriteln(stdout, "abc", "def", "xyz")
+  # is transformed by the compiler to:
+  myWriteln(stdout, ["abc", "def", "xyz"])
+
+This transformation is only done if the varargs parameter is the
+last parameter in the procedure header. It is also possible to perform
+type conversions in this context:
+
+.. code-block:: nim
+  proc myWriteln(f: File, a: varargs[string, `$`]) =
+    for s in items(a):
+      write(f, s)
+    write(f, "\n")
+
+  myWriteln(stdout, 123, "abc", 4.0)
+  # is transformed by the compiler to:
+  myWriteln(stdout, [$123, $"abc", $4.0])
+
+In this example `$ <system.html#$>`_ is applied to any argument that is passed
+to the parameter ``a``. Note that `$ <system.html#$>`_ applied to strings is a
+nop.
+
+
+Slices
+------
+
+Slices look similar to subranges types in syntax but are used in a different
+context. A slice is just an object of type Slice which contains two bounds,
+`a` and `b`. By itself a slice is not very useful, but other collection types
+define operators which accept Slice objects to define ranges.
+
+.. code-block:: nim
+
+  var
+    a = "Nim is a progamming language"
+    b = "Slices are useless."
+
+  echo a[7..12] # --> 'a prog'
+  b[11.. ^2] = "useful"
+  echo b # --> 'Slices are useful.'
+
+In the previous example slices are used to modify a part of a string, and even
+a negative index is used. The slice's bounds can hold any value supported by
+their type, but it is the proc using the slice object which defines what values
+are accepted.
+
+
+Tuples
+------
+
+A tuple type defines various named *fields* and an *order* of the fields.
+The constructor ``()`` can be used to construct tuples. The order of the
+fields in the constructor must match the order in the tuple's definition.
+Different tuple-types are *equivalent* if they specify fields of
+the same type and of the same name in the same order.
+
+The assignment operator for tuples copies each component. The notation
+``t.field`` is used to access a tuple's field. Another notation is
+``t[i]`` to access the ``i``'th field. Here ``i`` needs to be a constant
+integer.
+
+.. code-block:: nim
+
+  type
+    Person = tuple[name: string, age: int] # type representing a person:
+                                           # a person consists of a name
+                                           # and an age
+  var
+    person: Person
+  person = (name: "Peter", age: 30)
+  # the same, but less readable:
+  person = ("Peter", 30)
+
+  echo(person.name) # "Peter"
+  echo(person.age)  # 30
+
+  echo(person[0]) # "Peter"
+  echo(person[1]) # 30
+
+  # You don't need to declare tuples in a separate type section.
+  var building: tuple[street: string, number: int]
+  building = ("Rue del Percebe", 13)
+  echo(building.street)
+
+  # The following line does not compile, they are different tuples!
+  #person = building
+  # --> Error: type mismatch: got (tuple[street: string, number: int])
+  #     but expected 'Person'
+
+  # The following works because the field names and types are the same.
+  var teacher: tuple[name: string, age: int] = ("Mark", 42)
+  person = teacher
+
+Even though you don't need to declare a type for a tuple to use it, tuples
+created with different field names will be considered different objects despite
+having the same field types.
+
+Tuples can be *unpacked* during variable assignment (and only then!). This can
+be handy to assign directly the fields of the tuples to individually named
+variables. An example of this is the `splitFile <os.html#splitFile>`_ proc
+from the `os module <os.html>`_ which returns the directory, name and
+extension of a path at the same time. For tuple unpacking to work you have to
+use parenthesis around the values you want to assign the unpacking to,
+otherwise you will be assigning the same value to all the individual
+variables! Example:
+
+.. code-block:: nim
+
+  import os
+
+  let
+    path = "usr/local/nimc.html"
+    (dir, name, ext) = splitFile(path)
+    baddir, badname, badext = splitFile(path)
+  echo dir      # outputs `usr/local`
+  echo name     # outputs `nimc`
+  echo ext      # outputs `.html`
+  # All the following output the same line:
+  # `(dir: usr/local, name: nimc, ext: .html)`
+  echo baddir
+  echo badname
+  echo badext
+
+Tuple unpacking **only** works in ``var`` or ``let`` blocks. The following code
+won't compile:
+
+.. code-block:: nim
+
+  import os
+
+  var
+    path = "usr/local/nimc.html"
+    dir, name, ext = ""
+
+  (dir, name, ext) = splitFile(path)
+  # --> Error: '(dir, name, ext)' cannot be assigned to
+
+
+Reference and pointer types
+---------------------------
+References (similar to pointers in other programming languages) are a
+way to introduce many-to-one relationships. This means different references can
+point to and modify the same location in memory.
+
+Nim distinguishes between `traced`:idx: and `untraced`:idx: references.
+Untraced references are also called *pointers*. Traced references point to
+objects of a garbage collected heap, untraced references point to
+manually allocated objects or to objects somewhere else in memory. Thus
+untraced references are *unsafe*. However for certain low-level operations
+(accessing the hardware) untraced references are unavoidable.
+
+Traced references are declared with the **ref** keyword, untraced references
+are declared with the **ptr** keyword.
+
+The empty ``[]`` subscript notation can be used to *derefer* a reference,
+meaning to retrieve the item the reference points to. The ``.`` (access a
+tuple/object field operator) and ``[]`` (array/string/sequence index operator)
+operators perform implicit dereferencing operations for reference types:
+
+.. code-block:: nim
+
+  type
+    Node = ref NodeObj
+    NodeObj = object
+      le, ri: Node
+      data: int
+  var
+    n: Node
+  new(n)
+  n.data = 9
+  # no need to write n[].data; in fact n[].data is highly discouraged!
+
+To allocate a new traced object, the built-in procedure ``new`` has to be used.
+To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and
+``realloc`` can be used. The documentation of the `system <system.html>`_
+module contains further information.
+
+If a reference points to *nothing*, it has the value ``nil``.
+
+
+Procedural type
+---------------
+A procedural type is a (somewhat abstract) pointer to a procedure.
+``nil`` is an allowed value for a variable of a procedural type.
+Nim uses procedural types to achieve `functional`:idx: programming
+techniques.
+
+Example:
+
+.. code-block:: nim
+  proc echoItem(x: int) = echo(x)
+
+  proc forEach(action: proc (x: int)) =
+    const
+      data = [2, 3, 5, 7, 11]
+    for d in items(data):
+      action(d)
+
+  forEach(echoItem)
+
+A subtle issue with procedural types is that the calling convention of the
+procedure influences the type compatibility: procedural types are only compatible
+if they have the same calling convention. The different calling conventions are
+listed in the `manual <manual.html>`_.
+
+
+Modules
+=======
+Nim supports splitting a program into pieces with a module concept.
+Each module is in its own file. Modules enable `information hiding`:idx: and
+`separate compilation`:idx:. A module may gain access to symbols of another
+module by the `import`:idx: statement. Only top-level symbols that are marked
+with an asterisk (``*``) are exported:
+
+.. code-block:: nim
+  # Module A
+  var
+    x*, y: int
+
+  proc `*` *(a, b: seq[int]): seq[int] =
+    # allocate a new sequence:
+    newSeq(result, len(a))
+    # multiply two int sequences:
+    for i in 0..len(a)-1: result[i] = a[i] * b[i]
+
+  when isMainModule:
+    # test the new ``*`` operator for sequences:
+    assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
+
+The above module exports ``x`` and ``*``, but not ``y``.
+
+The top-level statements of a module are executed at the start of the program.
+This can be used to initialize complex data structures for example.
+
+Each module has a special magic constant ``isMainModule`` that is true if the
+module is compiled as the main file. This is very useful to embed tests within
+the module as shown by the above example.
+
+Modules that depend on each other are possible, but strongly discouraged,
+because then one module cannot be reused without the other.
+
+The algorithm for compiling modules is:
+
+- Compile the whole module as usual, following import statements recursively.
+- If there is a cycle only import the already parsed symbols (that are
+  exported); if an unknown identifier occurs then abort.
+
+This is best illustrated by an example:
+
+.. code-block:: nim
+  # Module A
+  type
+    T1* = int  # Module A exports the type ``T1``
+  import B     # the compiler starts parsing B
+
+  proc main() =
+    var i = p(3) # works because B has been parsed completely here
+
+  main()
+
+.. code-block:: nim
+  # Module B
+  import A  # A is not parsed here! Only the already known symbols
+            # of A are imported.
+
+  proc p*(x: A.T1): A.T1 =
+    # this works because the compiler has already
+    # added T1 to A's interface symbol table
+    result = x + 1
+
+
+A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
+the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous
+if it is defined in two (or more) different modules and both modules are
+imported by a third one:
+
+.. code-block:: nim
+  # Module A
+  var x*: string
+
+.. code-block:: nim
+  # Module B
+  var x*: int
+
+.. code-block:: nim
+  # Module C
+  import A, B
+  write(stdout, x) # error: x is ambiguous
+  write(stdout, A.x) # no error: qualifier used
+
+  var x = 4
+  write(stdout, x) # not ambiguous: uses the module C's x
+
+
+But this rule does not apply to procedures or iterators. Here the overloading
+rules apply:
+
+.. code-block:: nim
+  # Module A
+  proc x*(a: int): string = $a
+
+.. code-block:: nim
+  # Module B
+  proc x*(a: string): string = $a
+
+.. code-block:: nim
+  # Module C
+  import A, B
+  write(stdout, x(3))   # no error: A.x is called
+  write(stdout, x(""))  # no error: B.x is called
+
+  proc x*(a: int): string = nil
+  write(stdout, x(3))   # ambiguous: which `x` is to call?
+
+
+Excluding symbols
+-----------------
+
+The normal ``import`` statement will bring in all exported symbols.
+These can be limited by naming symbols which should be excluded with
+the ``except`` qualifier.
+
+.. code-block:: nim
+  import mymodule except y
+
+
+From statement
+--------------
+
+We have already seen the simple ``import`` statement that just imports all
+exported symbols. An alternative that only imports listed symbols is the
+``from import`` statement:
+
+.. code-block:: nim
+  from mymodule import x, y, z
+
+The ``from`` statement can also force namespace qualification on
+symbols, thereby making symbols available, but needing to be qualified
+to be used.
+
+.. code-block:: nim
+  from mymodule import x, y, z
+
+  x()           # use x without any qualification
+
+.. code-block:: nim
+  from mymodule import nil
+
+  mymodule.x()  # must qualify x with the module name as prefix
+
+  x()           # using x here without qualification is a compile error
+
+Since module names are generally long to be descriptive, you can also
+define a shorter alias to use when qualifying symbols.
+
+.. code-block:: nim
+  from mymodule as m import nil
+
+  m.x()         # m is aliasing mymodule
+
+
+Include statement
+-----------------
+The ``include`` statement does something fundamentally different than
+importing a module: it merely includes the contents of a file. The ``include``
+statement is useful to split up a large module into several files:
+
+.. code-block:: nim
+  include fileA, fileB, fileC
+
+
+
+Part 2
+======
+
+So, now that we are done with the basics, let's see what Nim offers apart
+from a nice syntax for procedural programming: `Part II <tut2.html>`_
+
+
+.. _strutils: strutils.html
+.. _system: system.html
diff --git a/doc/tut2.txt b/doc/tut2.txt
new file mode 100644
index 000000000..e1ac20074
--- /dev/null
+++ b/doc/tut2.txt
@@ -0,0 +1,994 @@
+======================
+Nim Tutorial (Part II)
+======================
+
+:Author: Andreas Rumpf
+:Version: |nimversion|
+
+.. contents::
+
+
+Introduction
+============
+
+  "Repetition renders the ridiculous reasonable." -- Norman Wildberger
+
+
+This document is a tutorial for the advanced constructs of the *Nim*
+programming language. **Note that this document is somewhat obsolete as the**
+`manual <manual.html>`_ **contains many more examples of the advanced language
+features.**
+
+
+Pragmas
+=======
+
+Pragmas are Nim's method to give the compiler additional information/
+commands without introducing a massive number of new keywords. Pragmas are
+enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial
+does not cover pragmas. See the `manual <manual.html#pragmas>`_ or `user guide
+<nimc.html#additional-features>`_ for a description of the available
+pragmas.
+
+
+Object Oriented Programming
+===========================
+
+While Nim's support for object oriented programming (OOP) is minimalistic,
+powerful OOP techniques can be used. OOP is seen as *one* way to design a
+program, not *the only* way. Often a procedural approach leads to simpler
+and more efficient code. In particular, preferring composition over inheritance
+is often the better design.
+
+
+Objects
+-------
+
+Like tuples, objects are a means to pack different values together in a
+structured way. However, objects provide many features that tuples do not:
+They provide inheritance and information hiding. Because objects encapsulate
+data, the ``T()`` object constructor should only be used internally and the
+programmer should provide a proc to initialize the object (this is called
+a *constructor*).
+
+Objects have access to their type at runtime. There is an
+``of`` operator that can be used to check the object's type:
+
+.. code-block:: nim
+  type
+    Person = ref object of RootObj
+      name*: string  # the * means that `name` is accessible from other modules
+      age: int       # no * means that the field is hidden from other modules
+
+    Student = ref object of Person # Student inherits from Person
+      id: int                      # with an id field
+
+  var
+    student: Student
+    person: Person
+  assert(student of Student) # is true
+  # object construction:
+  student = Student(name: "Anton", age: 5, id: 2)
+  echo student[]
+
+Object fields that should be visible from outside the defining module have to
+be marked by ``*``. In contrast to tuples, different object types are
+never *equivalent*. New object types can only be defined within a type
+section.
+
+Inheritance is done with the ``object of`` syntax. Multiple inheritance is
+currently not supported. If an object type has no suitable ancestor, ``RootObj``
+can be used as its ancestor, but this is only a convention. Objects that have
+no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma
+to introduce new object roots apart from ``system.RootObj``. (This is used
+in the GTK wrapper for instance.)
+
+Ref objects should be used whenever inheritance is used. It isn't strictly
+necessary, but with non-ref objects assignments such as ``let person: Person =
+Student(id: 123)`` will truncate subclass fields.
+
+**Note**: Composition (*has-a* relation) is often preferable to inheritance
+(*is-a* relation) for simple code reuse. Since objects are value types in
+Nim, composition is as efficient as inheritance.
+
+
+Mutually recursive types
+------------------------
+
+Objects, tuples and references can model quite complex data structures which
+depend on each other; they are *mutually recursive*. In Nim
+these types can only be declared within a single type section. (Anything else
+would require arbitrary symbol lookahead which slows down compilation.)
+
+Example:
+
+.. code-block:: nim
+  type
+    Node = ref NodeObj # a traced reference to a NodeObj
+    NodeObj = object
+      le, ri: Node     # left and right subtrees
+      sym: ref Sym     # leaves contain a reference to a Sym
+
+    Sym = object       # a symbol
+      name: string     # the symbol's name
+      line: int        # the line the symbol was declared in
+      code: PNode      # the symbol's abstract syntax tree
+
+
+Type conversions
+----------------
+Nim distinguishes between `type casts`:idx: and `type conversions`:idx:.
+Casts are done with the ``cast`` operator and force the compiler to
+interpret a bit pattern to be of another type.
+
+Type conversions are a much more polite way to convert a type into another:
+They preserve the abstract *value*, not necessarily the *bit-pattern*. If a
+type conversion is not possible, the compiler complains or an exception is
+raised.
+
+The syntax for type conversions is ``destination_type(expression_to_convert)``
+(like an ordinary call):
+
+.. code-block:: nim
+  proc getID(x: Person): int =
+    Student(x).id
+
+The ``InvalidObjectConversionError`` exception is raised if ``x`` is not a
+``Student``.
+
+
+Object variants
+---------------
+Often an object hierarchy is overkill in certain situations where simple
+variant types are needed.
+
+An example:
+
+.. code-block:: nim
+
+  # This is an example how an abstract syntax tree could be modelled in Nim
+  type
+    NodeKind = enum  # the different node types
+      nkInt,          # a leaf with an integer value
+      nkFloat,        # a leaf with a float value
+      nkString,       # a leaf with a string value
+      nkAdd,          # an addition
+      nkSub,          # a subtraction
+      nkIf            # an if statement
+    Node = ref NodeObj
+    NodeObj = object
+      case kind: NodeKind  # the ``kind`` field is the discriminator
+      of nkInt: intVal: int
+      of nkFloat: floatVal: float
+      of nkString: strVal: string
+      of nkAdd, nkSub:
+        leftOp, rightOp: PNode
+      of nkIf:
+        condition, thenPart, elsePart: PNode
+
+  var n = PNode(kind: nkFloat, floatVal: 1.0)
+  # the following statement raises an `FieldError` exception, because
+  # n.kind's value does not fit:
+  n.strVal = ""
+
+As can been seen from the example, an advantage to an object hierarchy is that
+no conversion between different object types is needed. Yet, access to invalid
+object fields raises an exception.
+
+
+Methods
+-------
+In ordinary object oriented languages, procedures (also called *methods*) are
+bound to a class. This has disadvantages:
+
+* Adding a method to a class the programmer has no control over is
+  impossible or needs ugly workarounds.
+* Often it is unclear where the method should belong to: is
+  ``join`` a string method or an array method?
+
+Nim avoids these problems by not assigning methods to a class. All methods
+in Nim are multi-methods. As we will see later, multi-methods are
+distinguished from procs only for dynamic binding purposes.
+
+
+Method call syntax
+------------------
+
+There is a syntactic sugar for calling routines:
+The syntax ``obj.method(args)`` can be used instead of ``method(obj, args)``.
+If there are no remaining arguments, the parentheses can be omitted:
+``obj.len`` (instead of ``len(obj)``).
+
+This method call syntax is not restricted to objects, it can be used
+for any type:
+
+.. code-block:: nim
+
+  echo("abc".len) # is the same as echo(len("abc"))
+  echo("abc".toUpper())
+  echo({'a', 'b', 'c'}.card)
+  stdout.writeln("Hallo") # the same as writeln(stdout, "Hallo")
+
+(Another way to look at the method call syntax is that it provides the missing
+postfix notation.)
+
+So "pure object oriented" code is easy to write:
+
+.. code-block:: nim
+  import strutils
+
+  stdout.writeln("Give a list of numbers (separated by spaces): ")
+  stdout.write(stdin.readLine.split.map(parseInt).max.`$`)
+  stdout.writeln(" is the maximum!")
+
+
+Properties
+----------
+As the above example shows, Nim has no need for *get-properties*:
+Ordinary get-procedures that are called with the *method call syntax* achieve
+the same. But setting a value is different; for this a special setter syntax
+is needed:
+
+.. code-block:: nim
+
+  type
+    Socket* = ref object of RootObj
+      FHost: int # cannot be accessed from the outside of the module
+                 # the `F` prefix is a convention to avoid clashes since
+                 # the accessors are named `host`
+
+  proc `host=`*(s: var Socket, value: int) {.inline.} =
+    ## setter of hostAddr
+    s.FHost = value
+
+  proc host*(s: Socket): int {.inline.} =
+    ## getter of hostAddr
+    s.FHost
+
+  var s: Socket
+  new s
+  s.host = 34  # same as `host=`(s, 34)
+
+(The example also shows ``inline`` procedures.)
+
+
+The ``[]`` array access operator can be overloaded to provide
+`array properties`:idx:\ :
+
+.. code-block:: nim
+  type
+    Vector* = object
+      x, y, z: float
+
+  proc `[]=`* (v: var Vector, i: int, value: float) =
+    # setter
+    case i
+    of 0: v.x = value
+    of 1: v.y = value
+    of 2: v.z = value
+    else: assert(false)
+
+  proc `[]`* (v: Vector, i: int): float =
+    # getter
+    case i
+    of 0: result = v.x
+    of 1: result = v.y
+    of 2: result = v.z
+    else: assert(false)
+
+The example is silly, since a vector is better modelled by a tuple which
+already provides ``v[]`` access.
+
+
+Dynamic dispatch
+----------------
+
+Procedures always use static dispatch. For dynamic dispatch replace the
+``proc`` keyword by ``method``:
+
+.. code-block:: nim
+  type
+    PExpr = ref object of RootObj ## abstract base class for an expression
+    PLiteral = ref object of PExpr
+      x: int
+    PPlusExpr = ref object of PExpr
+      a, b: PExpr
+
+  # watch out: 'eval' relies on dynamic binding
+  method eval(e: PExpr): int =
+    # override this base method
+    quit "to override!"
+
+  method eval(e: PLiteral): int = e.x
+  method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
+
+  proc newLit(x: int): PLiteral = PLiteral(x: x)
+  proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
+
+  echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
+
+Note that in the example the constructors ``newLit`` and ``newPlus`` are procs
+because it makes more sense for them to use static binding, but ``eval`` is a
+method because it requires dynamic binding.
+
+In a multi-method all parameters that have an object type are used for the
+dispatching:
+
+.. code-block:: nim
+
+  type
+    Thing = ref object of RootObj
+    Unit = ref object of Thing
+      x: int
+
+  method collide(a, b: Thing) {.inline.} =
+    quit "to override!"
+
+  method collide(a: Thing, b: Unit) {.inline.} =
+    echo "1"
+
+  method collide(a: Unit, b: Thing) {.inline.} =
+    echo "2"
+
+  var a, b: Unit
+  new a
+  new b
+  collide(a, b) # output: 2
+
+
+As the example demonstrates, invocation of a multi-method cannot be ambiguous:
+Collide 2 is preferred over collide 1 because the resolution works from left to
+right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``.
+
+**Performance note**: Nim does not produce a virtual method table, but
+generates dispatch trees. This avoids the expensive indirect branch for method
+calls and enables inlining. However, other optimizations like compile time
+evaluation or dead code elimination do not work with methods.
+
+
+Exceptions
+==========
+
+In Nim exceptions are objects. By convention, exception types are
+suffixed with 'Error'. The `system <system.html>`_ module defines an
+exception hierarchy that you might want to stick to. Exceptions derive from
+``system.Exception``, which provides the common interface.
+
+Exceptions have to be allocated on the heap because their lifetime is unknown.
+The compiler will prevent you from raising an exception created on the stack.
+All raised exceptions should at least specify the reason for being raised in
+the ``msg`` field.
+
+A convention is that exceptions should be raised in *exceptional* cases:
+For example, if a file cannot be opened, this should not raise an
+exception since this is quite common (the file may not exist).
+
+
+Raise statement
+---------------
+Raising an exception is done with the ``raise`` statement:
+
+.. code-block:: nim
+  var
+    e: ref OSError
+  new(e)
+  e.msg = "the request to the OS failed"
+  raise e
+
+If the ``raise`` keyword is not followed by an expression, the last exception
+is *re-raised*. For the purpose of avoiding repeating this common code pattern,
+the template ``newException`` in the ``system`` module can be used:
+
+.. code-block:: nim
+  raise newException(OSError, "the request to the OS failed")
+
+
+Try statement
+-------------
+
+The ``try`` statement handles exceptions:
+
+.. code-block:: nim
+  # read the first two lines of a text file that should contain numbers
+  # and tries to add them
+  var
+    f: File
+  if open(f, "numbers.txt"):
+    try:
+      let a = readLine(f)
+      let b = readLine(f)
+      echo "sum: ", parseInt(a) + parseInt(b)
+    except OverflowError:
+      echo "overflow!"
+    except ValueError:
+      echo "could not convert string to integer"
+    except IOError:
+      echo "IO error!"
+    except:
+      echo "Unknown exception!"
+      # reraise the unknown exception:
+      raise
+    finally:
+      close(f)
+
+The statements after the ``try`` are executed unless an exception is
+raised. Then the appropriate ``except`` part is executed.
+
+The empty ``except`` part is executed if there is an exception that is
+not explicitly listed. It is similar to an ``else`` part in ``if``
+statements.
+
+If there is a ``finally`` part, it is always executed after the
+exception handlers.
+
+The exception is *consumed* in an ``except`` part. If an exception is not
+handled, it is propagated through the call stack. This means that often
+the rest of the procedure - that is not within a ``finally`` clause -
+is not executed (if an exception occurs).
+
+If you need to *access* the actual exception object or message inside an
+``except`` branch you can use the `getCurrentException()
+<system.html#getCurrentException>`_ and `getCurrentExceptionMsg()
+<system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_
+module. Example:
+
+.. code-block:: nim
+  try:
+    doSomethingHere()
+  except:
+    let
+      e = getCurrentException()
+      msg = getCurrentExceptionMsg()
+    echo "Got exception ", repr(e), " with message ", msg
+
+
+Annotating procs with raised exceptions
+---------------------------------------
+
+Through the use of the optional ``{.raises.}`` pragma you can specify that a
+proc is meant to raise a specific set of exceptions, or none at all. If the
+``{.raises.}`` pragma is used, the compiler will verify that this is true. For
+instance, if you specify that a proc raises ``IOError``, and at some point it
+(or one of the procs it calls) starts raising a new exception the compiler will
+prevent that proc from compiling. Usage example:
+
+.. code-block:: nim
+  proc complexProc() {.raises: [IOError, ArithmeticError].} =
+    ...
+
+  proc simpleProc() {.raises: [].} =
+    ...
+
+Once you have code like this in place, if the list of raised exception changes
+the compiler will stop with an error specifying the line of the proc which
+stopped validating the pragma and the raised exception not being caught, along
+with the file and line where the uncaught exception is being raised, which may
+help you locate the offending code which has changed.
+
+If you want to add the ``{.raises.}`` pragma to existing code, the compiler can
+also help you. You can add the ``{.effects.}`` pragma statement to your proc and
+the compiler will output all inferred effects up to that point (exception
+tracking is part of Nim's effect system). Another more roundabout way to
+find out the list of exceptions raised by a proc is to use the Nim ``doc2``
+command which generates documentation for a whole module and decorates all
+procs with the list of raised exceptions. You can read more about Nim's
+`effect system and related pragmas in the manual <manual.html#effect-system>`_.
+
+
+Generics
+========
+
+Generics are Nim's means to parametrize procs, iterators or types
+with `type parameters`:idx:. They are most useful for efficient type safe
+containers:
+
+.. code-block:: nim
+  type
+    BinaryTreeObj[T] = object # BinaryTree is a generic type with
+                              # with generic param ``T``
+      le, ri: BinaryTree[T]   # left and right subtrees; may be nil
+      data: T                 # the data stored in a node
+    BinaryTree*[T] = ref BinaryTreeObj[T] # type that is exported
+
+  proc newNode*[T](data: T): BinaryTree[T] =
+    # constructor for a node
+    new(result)
+    result.data = data
+
+  proc add*[T](root: var BinaryTree[T], n: BinaryTree[T]) =
+    # insert a node into the tree
+    if root == nil:
+      root = n
+    else:
+      var it = root
+      while it != nil:
+        # compare the data items; uses the generic ``cmp`` proc
+        # that works for any type that has a ``==`` and ``<`` operator
+        var c = cmp(it.data, n.data)
+        if c < 0:
+          if it.le == nil:
+            it.le = n
+            return
+          it = it.le
+        else:
+          if it.ri == nil:
+            it.ri = n
+            return
+          it = it.ri
+
+  proc add*[T](root: var BinaryTree[T], data: T) =
+    # convenience proc:
+    add(root, newNode(data))
+
+  iterator preorder*[T](root: BinaryTree[T]): T =
+    # Preorder traversal of a binary tree.
+    # Since recursive iterators are not yet implemented,
+    # this uses an explicit stack (which is more efficient anyway):
+    var stack: seq[BinaryTree[T]] = @[root]
+    while stack.len > 0:
+      var n = stack.pop()
+      while n != nil:
+        yield n.data
+        add(stack, n.ri)  # push right subtree onto the stack
+        n = n.le          # and follow the left pointer
+
+  var
+    root: BinaryTree[string] # instantiate a BinaryTree with ``string``
+  add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
+  add(root, "world")          # instantiates the second ``add`` proc
+  for str in preorder(root):
+    stdout.writeln(str)
+
+The example shows a generic binary tree. Depending on context, the brackets are
+used either to introduce type parameters or to instantiate a generic proc,
+iterator or type. As the example shows, generics work with overloading: the
+best match of ``add`` is used. The built-in ``add`` procedure for sequences
+is not hidden and is used in the ``preorder`` iterator.
+
+
+Templates
+=========
+
+Templates are a simple substitution mechanism that operates on Nim's
+abstract syntax trees. Templates are processed in the semantic pass of the
+compiler. They integrate well with the rest of the language and share none
+of C's preprocessor macros flaws.
+
+To *invoke* a template, call it like a procedure.
+
+Example:
+
+.. code-block:: nim
+  template `!=` (a, b: expr): expr =
+    # this definition exists in the System module
+    not (a == b)
+
+  assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6))
+
+The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact
+templates: this has the benefit that if you overload the ``==`` operator,
+the ``!=`` operator is available automatically and does the right thing. (Except
+for IEEE floating point numbers - NaN breaks basic boolean logic.)
+
+``a > b`` is transformed into ``b < a``.
+``a in b`` is transformed into ``contains(b, a)``.
+``notin`` and ``isnot`` have the obvious meanings.
+
+Templates are especially useful for lazy evaluation purposes. Consider a
+simple proc for logging:
+
+.. code-block:: nim
+  const
+    debug = true
+
+  proc log(msg: string) {.inline.} =
+    if debug: stdout.writeln(msg)
+
+  var
+    x = 4
+  log("x has the value: " & $x)
+
+This code has a shortcoming: if ``debug`` is set to false someday, the quite
+expensive ``$`` and ``&`` operations are still performed! (The argument
+evaluation for procedures is *eager*).
+
+Turning the ``log`` proc into a template solves this problem:
+
+.. code-block:: nim
+  const
+    debug = true
+
+  template log(msg: string) =
+    if debug: stdout.writeln(msg)
+
+  var
+    x = 4
+  log("x has the value: " & $x)
+
+The parameters' types can be ordinary types or the meta types ``expr``
+(stands for *expression*), ``stmt`` (stands for *statement*) or ``typedesc``
+(stands for *type description*). If the template has no explicit return type,
+``stmt`` is used for consistency with procs and methods.
+
+If there is a ``stmt`` parameter it should be the last in the template
+declaration. The reason is that statements can be passed to a template
+via a special ``:`` syntax:
+
+.. code-block:: nim
+
+  template withFile(f: expr, filename: string, mode: FileMode,
+                    body: stmt): stmt {.immediate.} =
+    let fn = filename
+    var f: File
+    if open(f, fn, mode):
+      try:
+        body
+      finally:
+        close(f)
+    else:
+      quit("cannot open: " & fn)
+
+  withFile(txt, "ttempl3.txt", fmWrite):
+    txt.writeln("line 1")
+    txt.writeln("line 2")
+
+In the example the two ``writeln`` statements are bound to the ``body``
+parameter. The ``withFile`` template contains boilerplate code and helps to
+avoid a common bug: to forget to close the file. Note how the
+``let fn = filename`` statement ensures that ``filename`` is evaluated only
+once.
+
+
+Macros
+======
+
+Macros enable advanced compile-time code transformations, but they cannot
+change Nim's syntax. However, this is no real restriction because Nim's
+syntax is flexible enough anyway. Macros have to be implemented in pure Nim
+code if the `foreign function interface (FFI)
+<manual.html#foreign-function-interface>`_ is not enabled in the compiler, but
+other than that restriction (which at some point in the future will go away)
+you can write any kind of Nim code and the compiler will run it at compile
+time.
+
+There are two ways to write a macro, either *generating* Nim source code and
+letting the compiler parse it, or creating manually an abstract syntax tree
+(AST) which you feed to the compiler. In order to build the AST one needs to
+know how the Nim concrete syntax is converted to an abstract syntax tree
+(AST). The AST is documented in the `macros <macros.html>`_ module.
+
+Once your macro is finished, there are two ways to invoke it:
+(1) invoking a macro like a procedure call (expression macros)
+(2) invoking a macro with the special ``macrostmt``
+    syntax (statement macros)
+
+
+Expression Macros
+-----------------
+
+The following example implements a powerful ``debug`` command that accepts a
+variable number of arguments:
+
+.. code-block:: nim
+  # to work with Nim syntax trees, we need an API that is defined in the
+  # ``macros`` module:
+  import macros
+
+  macro debug(n: varargs[expr]): stmt =
+    # `n` is a Nim AST that contains a list of expressions;
+    # this macro returns a list of statements:
+    result = newNimNode(nnkStmtList, n)
+    # iterate over any argument that is passed to this macro:
+    for i in 0..n.len-1:
+      # add a call to the statement list that writes the expression;
+      # `toStrLit` converts an AST to its string representation:
+      result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+      # add a call to the statement list that writes ": "
+      result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+      # add a call to the statement list that writes the expressions value:
+      result.add(newCall("writeln", newIdentNode("stdout"), n[i]))
+
+  var
+    a: array[0..10, int]
+    x = "some string"
+  a[0] = 42
+  a[1] = 45
+
+  debug(a[0], a[1], x)
+
+The macro call expands to:
+
+.. code-block:: nim
+  write(stdout, "a[0]")
+  write(stdout, ": ")
+  writeln(stdout, a[0])
+
+  write(stdout, "a[1]")
+  write(stdout, ": ")
+  writeln(stdout, a[1])
+
+  write(stdout, "x")
+  write(stdout, ": ")
+  writeln(stdout, x)
+
+
+
+Statement Macros
+----------------
+
+Statement macros are defined just as expression macros. However, they are
+invoked by an expression following a colon.
+
+The following example outlines a macro that generates a lexical analyzer from
+regular expressions:
+
+.. code-block:: nim
+
+  macro case_token(n: stmt): stmt =
+    # creates a lexical analyzer from regular expressions
+    # ... (implementation is an exercise for the reader :-)
+    discard
+
+  case_token: # this colon tells the parser it is a macro statement
+  of r"[A-Za-z_]+[A-Za-z_0-9]*":
+    return tkIdentifier
+  of r"0-9+":
+    return tkInteger
+  of r"[\+\-\*\?]+":
+    return tkOperator
+  else:
+    return tkUnknown
+
+
+Building your first macro
+-------------------------
+
+To give a footstart to writing macros we will show now how to turn your typical
+dynamic code into something that compiles statically. For the exercise we will
+use the following snippet of code as the starting point:
+
+.. code-block:: nim
+
+  import strutils, tables
+
+  proc readCfgAtRuntime(cfgFilename: string): Table[string, string] =
+    let
+      inputString = readFile(cfgFilename)
+    var
+      source = ""
+
+    result = initTable[string, string]()
+    for line in inputString.splitLines:
+      # Ignore empty lines
+      if line.len < 1: continue
+      var chunks = split(line, ',')
+      if chunks.len != 2:
+        quit("Input needs comma split values, got: " & line)
+      result[chunks[0]] = chunks[1]
+
+    if result.len < 1: quit("Input file empty!")
+
+  let info = readCfgAtRuntime("data.cfg")
+
+  when isMainModule:
+    echo info["licenseOwner"]
+    echo info["licenseKey"]
+    echo info["version"]
+
+Presumably this snippet of code could be used in a commercial software, reading
+a configuration file to display information about the person who bought the
+software. This external file would be generated by an online web shopping cart
+to be included along the program containing the license information::
+
+  version,1.1
+  licenseOwner,Hyori Lee
+  licenseKey,M1Tl3PjBWO2CC48m
+
+The ``readCfgAtRuntime`` proc will open the given filename and return a
+``Table`` from the `tables module <tables.html>`_. The parsing of the file is
+done (without much care for handling invalid data or corner cases) using the
+`splitLines proc from the strutils module <strutils.html#splitLines>`_. There
+are many things which can fail; mind the purpose is explaining how to make
+this run at compile time, not how to properly implement a DRM scheme.
+
+The reimplementation of this code as a compile time proc will allow us to get
+rid of the ``data.cfg`` file we would need to distribute along the binary, plus
+if the information is really constant, it doesn't make from a logical point of
+view to have it *mutable* in a global variable, it would be better if it was a
+constant. Finally, and likely the most valuable feature, we can implement some
+verification at compile time. You could think of this as a *better unit
+testing*, since it is impossible to obtain a binary unless everything is
+correct, preventing you to ship to users a broken program which won't start
+because a small critical file is missing or its contents changed by mistake to
+something invalid.
+
+
+Generating source code
+++++++++++++++++++++++
+
+Our first attempt will start by modifying the program to generate a compile
+time string with the *generated source code*, which we then pass to the
+``parseStmt`` proc from the `macros module <macros.html>`_. Here is the
+modified source code implementing the macro:
+
+.. code-block:: nim
+   :number-lines:
+
+  import macros, strutils
+
+  macro readCfgAndBuildSource(cfgFilename: string): stmt =
+    let
+      inputString = slurp(cfgFilename.strVal)
+    var
+      source = ""
+
+    for line in inputString.splitLines:
+      # Ignore empty lines
+      if line.len < 1: continue
+      var chunks = split(line, ',')
+      if chunks.len != 2:
+        error("Input needs comma split values, got: " & line)
+      source &= "const cfg" & chunks[0] & "= \"" & chunks[1] & "\"\n"
+
+    if source.len < 1: error("Input file empty!")
+    result = parseStmt(source)
+
+  readCfgAndBuildSource("data.cfg")
+
+  when isMainModule:
+    echo cfglicenseOwner
+    echo cfglicenseKey
+    echo cfgversion
+
+The good news is not much has changed! First, we need to change the handling
+of the input parameter (line 3). In the dynamic version the
+``readCfgAtRuntime`` proc receives a string parameter. However, in the macro
+version it is also declared as string, but this is the *outside* interface of
+the macro.  When the macro is run, it actually gets a ``PNimNode`` object
+instead of a string, and we have to call the `strVal proc
+<macros.html#strVal>`_ (line 5) from the `macros module <macros.html>`_ to
+obtain the string being passed in to the macro.
+
+Second, we cannot use the `readFile proc <system.html#readFile>`_ from the
+`system module <system.html>`_ due to FFI restriction at compile time. If we
+try to use this proc, or any other which depends on FFI, the compiler will
+error with the message ``cannot evaluate`` and a dump of the macro's source
+code, along with a stack trace where the compiler reached before bailing out.
+We can get around this limitation by using the `slurp proc
+<system.html#slurp>`_ from the `system module <system.html>`_, which was
+precisely made for compilation time (just like `gorge <system.html#gorge>`_
+which executes an external program and captures its output).
+
+The interesting thing is that our macro does not return a runtime `Table
+<tables.html#Table>`_ object. Instead, it builds up Nim source code into
+the ``source`` variable.  For each line of the configuration file a ``const``
+variable will be generated (line 15).  To avoid conflicts we prefix these
+variables with ``cfg``. In essence, what the compiler is doing is replacing
+the line calling the macro with the following snippet of code:
+
+.. code-block:: nim
+  const cfgversion= "1.1"
+  const cfglicenseOwner= "Hyori Lee"
+  const cfglicenseKey= "M1Tl3PjBWO2CC48m"
+
+You can verify this yourself adding the line ``echo source`` somewhere at the
+end of the macro and compiling the program. Another difference is that instead
+of calling the usual `quit proc <system.html#quit>`_ to abort (which we could
+still call) this version calls the `error proc <macros.html#error>`_ (line
+14). The ``error`` proc has the same behavior as ``quit`` but will dump also
+the source and file line information where the error happened, making it
+easier for the programmer to find where compilation failed. In this situation
+it would point to the line invoking the macro, but **not** the line of
+``data.cfg`` we are processing, that's something the macro itself would need
+to control.
+
+
+Generating AST by hand
+++++++++++++++++++++++
+
+To generate an AST we would need to intimately know the structures used by the
+Nim compiler exposed in the `macros module <macros.html>`_, which at first
+look seems a daunting task. But we can use as helper shortcut the `dumpTree
+macro <macros.html#dumpTree>`_, which is used as a statement macro instead of
+an expression macro.  Since we know that we want to generate a bunch of
+``const`` symbols we can create the following source file and compile it to
+see what the compiler *expects* from us:
+
+.. code-block:: nim
+  import macros
+
+  dumpTree:
+    const cfgversion: string = "1.1"
+    const cfglicenseOwner= "Hyori Lee"
+    const cfglicenseKey= "M1Tl3PjBWO2CC48m"
+
+During compilation of the source code we should see the following lines in the
+output (again, since this is a macro, compilation is enough, you don't have to
+run any binary)::
+
+  StmtList
+    ConstSection
+      ConstDef
+        Ident !"cfgversion"
+        Ident !"string"
+        StrLit 1.1
+    ConstSection
+      ConstDef
+        Ident !"cfglicenseOwner"
+        Empty
+        StrLit Hyori Lee
+    ConstSection
+      ConstDef
+        Ident !"cfglicenseKey"
+        Empty
+        StrLit M1Tl3PjBWO2CC48m
+
+With this output we have a better idea of what kind of input the compiler
+expects. We need to generate a list of statements. For each constant the source
+code generates a ``ConstSection`` and a ``ConstDef``. If we were to move all
+the constants to a single ``const`` block we would see only a single
+``ConstSection`` with three children.
+
+Maybe you didn't notice, but in the ``dumpTree`` example the first constant
+explicitly specifies the type of the constant.  That's why in the tree output
+the two last constants have their second child ``Empty`` but the first has a
+string identifier. So basically a ``const`` definition is made up from an
+identifier, optionally a type (can be an *empty* node) and the value. Armed
+with this knowledge, let's look at the finished version of the AST building
+macro:
+
+.. code-block:: nim
+   :number-lines:
+
+  import macros, strutils
+
+  macro readCfgAndBuildAST(cfgFilename: string): stmt =
+    let
+      inputString = slurp(cfgFilename.strVal)
+
+    result = newNimNode(nnkStmtList)
+    for line in inputString.splitLines:
+      # Ignore empty lines
+      if line.len < 1: continue
+      var chunks = split(line, ',')
+      if chunks.len != 2:
+        error("Input needs comma split values, got: " & line)
+      var
+        section = newNimNode(nnkConstSection)
+        constDef = newNimNode(nnkConstDef)
+      constDef.add(newIdentNode("cfg" & chunks[0]))
+      constDef.add(newEmptyNode())
+      constDef.add(newStrLitNode(chunks[1]))
+      section.add(constDef)
+      result.add(section)
+
+    if result.len < 1: error("Input file empty!")
+
+  readCfgAndBuildAST("data.cfg")
+
+  when isMainModule:
+    echo cfglicenseOwner
+    echo cfglicenseKey
+    echo cfgversion
+
+Since we are building on the previous example generating source code, we will
+only mention the differences to it. Instead of creating a temporary ``string``
+variable and writing into it source code as if it were written *by hand*, we
+use the ``result`` variable directly and create a statement list node
+(``nnkStmtList``) which will hold our children (line 7).
+
+For each input line we have to create a constant definition (``nnkConstDef``)
+and wrap it inside a constant section (``nnkConstSection``). Once these
+variables are created, we fill them hierarchichally (line 17) like the
+previous AST dump tree showed: the constant definition is a child of the
+section definition, and the constant definition has an identifier node, an
+empty node (we let the compiler figure out the type), and a string literal
+with the value.
+
+A last tip when writing a macro: if you are not sure the AST you are building
+looks ok, you may be tempted to use the ``dumpTree`` macro. But you can't use
+it *inside* the macro you are writting/debugging. Instead ``echo`` the string
+generated by `treeRepr <macros.html#treeRepr>`_. If at the end of the this
+example you add ``echo treeRepr(result)`` you should get the same output as
+using the ``dumpTree`` macro, but of course you can call that at any point of
+the macro where you might be having troubles.
diff --git a/examples/allany.nim b/examples/allany.nim
new file mode 100644
index 000000000..de36a1d9b
--- /dev/null
+++ b/examples/allany.nim
@@ -0,0 +1,26 @@
+# All and any
+
+template all(container, cond: expr): expr {.immediate.} =
+  block:
+    var result = true
+    for it in items(container):
+      if not cond(it):
+        result = false
+        break
+    result
+
+template any(container, cond: expr): expr {.immediate.} =
+  block:
+    var result = false
+    for it in items(container):
+      if cond(it):
+        result = true
+        break
+    result
+
+if all("mystring", {'a'..'z'}.contains) and any("myohmy", 'y'.`==`): 
+  echo "works"
+else: 
+  echo "does not work"
+
+
diff --git a/examples/c++iface/irrlichtex.nim b/examples/c++iface/irrlichtex.nim
new file mode 100644
index 000000000..4dd1d79ee
--- /dev/null
+++ b/examples/c++iface/irrlichtex.nim
@@ -0,0 +1,114 @@
+# Horrible example of how to interface with a C++ engine ... ;-)
+
+{.link: "/usr/lib/libIrrlicht.so".}
+
+{.emit: """
+using namespace irr;
+using namespace core;
+using namespace scene;
+using namespace video;
+using namespace io;
+using namespace gui;
+""".}
+
+const
+  irr = "<irrlicht/irrlicht.h>"
+
+type
+  TDimension2d {.final, header: irr, importc: "dimension2d".} = object
+  Tvector3df {.final, header: irr, importc: "vector3df".} = object
+  TColor {.final, header: irr, importc: "SColor".} = object
+  
+  TIrrlichtDevice {.final, header: irr, importc: "IrrlichtDevice".} = object
+  TIVideoDriver {.final, header: irr, importc: "IVideoDriver".} = object
+  TISceneManager {.final, header: irr, importc: "ISceneManager".} = object
+  TIGUIEnvironment {.final, header: irr, importc: "IGUIEnvironment".} = object
+  TIAnimatedMesh {.final, header: irr, importc: "IAnimatedMesh".} = object
+  TIAnimatedMeshSceneNode {.final, header: irr, 
+    importc: "IAnimatedMeshSceneNode".} = object
+  TITexture {.final, header: irr, importc: "ITexture".} = object
+
+  PIrrlichtDevice = ptr TIrrlichtDevice
+  PIVideoDriver = ptr TIVideoDriver
+  PISceneManager = ptr TISceneManager
+  PIGUIEnvironment = ptr TIGUIEnvironment
+  PIAnimatedMesh = ptr TIAnimatedMesh
+  PIAnimatedMeshSceneNode = ptr TIAnimatedMeshSceneNode
+  PITexture = ptr TITexture
+
+proc dimension2d(x, y: cint): TDimension2d {.
+  header: irr, importc: "dimension2d<u32>".}
+proc vector3df(x,y,z: cint): Tvector3df {.
+  header: irr, importc: "vector3df".}
+proc SColor(r,g,b,a: cint): TColor {.
+  header: irr, importc: "SColor".}
+
+proc createDevice(): PIrrlichtDevice {.
+  header: irr, importc: "createDevice".}
+proc run(device: PIrrlichtDevice): bool {.
+  header: irr, importcpp: "run".}
+
+proc getVideoDriver(dev: PIrrlichtDevice): PIVideoDriver {.
+  header: irr, importcpp: "getVideoDriver".}
+proc getSceneManager(dev: PIrrlichtDevice): PISceneManager {.
+  header: irr, importcpp: "getSceneManager".}
+proc getGUIEnvironment(dev: PIrrlichtDevice): PIGUIEnvironment {.
+  header: irr, importcpp: "getGUIEnvironment".}
+
+proc getMesh(smgr: PISceneManager, path: cstring): PIAnimatedMesh {.
+  header: irr, importcpp: "getMesh".}
+
+proc drawAll(smgr: PISceneManager) {.
+  header: irr, importcpp: "drawAll".}
+proc drawAll(guienv: PIGUIEnvironment) {.
+  header: irr, importcpp: "drawAll".}
+
+proc drop(dev: PIrrlichtDevice) {.
+  header: irr, importcpp: "drop".}
+
+proc getTexture(driver: PIVideoDriver, path: cstring): PITexture {.
+  header: irr, importcpp: "getTexture".}
+proc endScene(driver: PIVideoDriver) {.
+  header: irr, importcpp: "endScene".}
+proc beginScene(driver: PIVideoDriver, a, b: bool, c: TColor) {.
+  header: irr, importcpp: "beginScene".}
+
+proc addAnimatedMeshSceneNode(
+  smgr: PISceneManager, mesh: PIAnimatedMesh): PIAnimatedMeshSceneNode {.
+  header: irr, importcpp: "addAnimatedMeshSceneNode".}
+
+proc setMaterialTexture(n: PIAnimatedMeshSceneNode, x: cint, t: PITexture) {.
+  header: irr, importcpp: "setMaterialTexture".}
+proc addCameraSceneNode(smgr: PISceneManager, x: cint, a, b: TVector3df) {.
+  header: irr, importcpp: "addCameraSceneNode".}
+
+
+var device = createDevice()
+if device == nil: quit "device is nil"
+
+var driver = device.getVideoDriver()
+var smgr = device.getSceneManager()
+var guienv = device.getGUIEnvironment()
+
+var mesh = smgr.getMesh("/home/andreas/download/irrlicht-1.7.2/media/sydney.md2")
+if mesh == nil:
+  device.drop()
+  quit "no mesh!"
+
+var node = smgr.addAnimatedMeshSceneNode(mesh)
+
+if node != nil:
+  #node->setMaterialFlag(EMF_LIGHTING, false)
+  #node->setMD2Animation(scene::EMAT_STAND)
+  node.setMaterialTexture(0, 
+    driver.getTexture(
+      "/home/andreas/download/irrlicht-1.7.2/media/media/sydney.bmp"))
+
+smgr.addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0))
+while device.run():
+  driver.beginScene(true, true, SColor(255,100,101,140))
+  smgr.drawAll()
+  guienv.drawAll()
+  driver.endScene()
+device.drop()
+
diff --git a/examples/cgi/cgi_server.py b/examples/cgi/cgi_server.py
new file mode 100644
index 000000000..1907515e8
--- /dev/null
+++ b/examples/cgi/cgi_server.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+import BaseHTTPServer
+import CGIHTTPServer
+
+server = BaseHTTPServer.HTTPServer
+handler = CGIHTTPServer.CGIHTTPRequestHandler
+server_address = ('localhost', 8008)
+handler.cgi_directories = ['/']
+
+httpd = server(server_address, handler)
+httpd.serve_forever()
diff --git a/examples/cgi/cgi_stacktrace.nim b/examples/cgi/cgi_stacktrace.nim
new file mode 100644
index 000000000..e9f2f567c
--- /dev/null
+++ b/examples/cgi/cgi_stacktrace.nim
@@ -0,0 +1,5 @@
+import cgi
+cgi.setStackTraceStdout()
+
+var a: string = nil
+a.add "foobar"
diff --git a/examples/cgi/example.nim b/examples/cgi/example.nim
new file mode 100644
index 000000000..17629982a
--- /dev/null
+++ b/examples/cgi/example.nim
@@ -0,0 +1,7 @@
+import cgi
+
+write(stdout, "Content-type: text/html\n\n")
+write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
+write(stdout, "<html><head><title>Test</title></head><body>\n")
+write(stdout, "Hello!")
+writeln(stdout, "</body></html>")
diff --git a/examples/cgiex.nim b/examples/cgiex.nim
new file mode 100644
index 000000000..7e3292f35
--- /dev/null
+++ b/examples/cgiex.nim
@@ -0,0 +1,12 @@
+# Test/show CGI module
+import strtabs, cgi
+
+var myData = readData()
+validateData(myData, "name", "password")
+writeContentType()
+
+write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
+write(stdout, "<html><head><title>Test</title></head><body>\n")
+writeln(stdout, "name: " & myData["name"])
+writeln(stdout, "password: " & myData["password"])
+writeln(stdout, "</body></html>")
diff --git a/examples/cross_calculator/.gitignore b/examples/cross_calculator/.gitignore
new file mode 100644
index 000000000..e521bf338
--- /dev/null
+++ b/examples/cross_calculator/.gitignore
@@ -0,0 +1,12 @@
+# Android specific absolute paths.
+android/bin/
+android/gen/
+android/jni/backend-jni.h
+android/libs/
+android/local.properties
+android/obj/
+android/tags
+# iOS specific absolute paths
+ios/resources/ui/*.m
+ios/tags
+
diff --git a/examples/cross_calculator/android/AndroidManifest.xml b/examples/cross_calculator/android/AndroidManifest.xml
new file mode 100644
index 000000000..05b96fb50
--- /dev/null
+++ b/examples/cross_calculator/android/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+		package="com.github.nimrod.crosscalculator"
+		android:versionCode="1"
+		android:versionName="1.0">
+
+	<uses-sdk android:minSdkVersion="3" />
+
+	<application android:label="@string/app_name" android:debuggable="true">
+		<activity android:name=".CrossCalculator"
+			android:label="@string/app_name">
+			<intent-filter>
+				<action android:name="android.intent.action.MAIN" />
+				<category android:name="android.intent.category.LAUNCHER" />
+			</intent-filter>
+		</activity>
+	</application>
+</manifest>
diff --git a/examples/cross_calculator/android/build.xml b/examples/cross_calculator/android/build.xml
new file mode 100644
index 000000000..d7c88432a
--- /dev/null
+++ b/examples/cross_calculator/android/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="CrossCalculator" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
diff --git a/examples/cross_calculator/android/custom_rules.xml b/examples/cross_calculator/android/custom_rules.xml
new file mode 100644
index 000000000..91783a50e
--- /dev/null
+++ b/examples/cross_calculator/android/custom_rules.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="custom_rules" default="debug">
+	<target name="nim">
+		<exec executable="scripts/nimbuild.sh" failonerror="true">
+		</exec>
+	</target>
+	<target name="jni">
+		<exec executable="scripts/jnibuild.sh" failonerror="true">
+		</exec>
+	</target>
+	<target name="ndk">
+		<exec executable="ndk-build" failonerror="true">
+		</exec>
+	</target>
+	<target name="-post-compile" depends="nim, jni, ndk">
+	</target>
+</project>
diff --git a/examples/cross_calculator/android/jni/Android.mk b/examples/cross_calculator/android/jni/Android.mk
new file mode 100644
index 000000000..c1a0feac3
--- /dev/null
+++ b/examples/cross_calculator/android/jni/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := nimrod
+LOCAL_SRC_FILES := nimcache/backend.c nimcache/system.c
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/nimcache
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := backend-jni
+LOCAL_SRC_FILES := backend-jni.c
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
+LOCAL_STATIC_LIBRARIES := nimrod
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/examples/cross_calculator/android/jni/backend-jni.c b/examples/cross_calculator/android/jni/backend-jni.c
new file mode 100644
index 000000000..3d65458ec
--- /dev/null
+++ b/examples/cross_calculator/android/jni/backend-jni.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <android/log.h>
+#include <string.h>
+#include "backend-jni.h"
+#include "backend.h"
+
+#define TAG		"backend-jni.c"
+
+jint JNICALL Java_com_github_nimrod_crosscalculator_CrossCalculator_myAdd
+	(JNIEnv *env, jobject thiz, jint a, jint b)
+{
+	char buf[256];
+	const jint ret = myAdd(a, b);
+	// Using logging from inside the native bridge to log-debug.
+	sprintf(buf, "a %d + b %d = ret %d", a, b, ret);
+	__android_log_write(ANDROID_LOG_DEBUG, TAG, buf);
+	return ret;
+}
+
+void JNICALL Java_com_github_nimrod_crosscalculator_CrossCalculator_initNimMain
+	(JNIEnv *env, jclass thiz)
+{
+	NimMain();
+	__android_log_write(ANDROID_LOG_DEBUG, TAG, "Nimrod initialised");
+}
+
+// vim:tabstop=2 shiftwidth=2 syntax=c
diff --git a/examples/cross_calculator/android/project.properties b/examples/cross_calculator/android/project.properties
new file mode 100644
index 000000000..9fb894d9b
--- /dev/null
+++ b/examples/cross_calculator/android/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-3
diff --git a/examples/cross_calculator/android/readme.txt b/examples/cross_calculator/android/readme.txt
new file mode 100644
index 000000000..51fa9c6fd
--- /dev/null
+++ b/examples/cross_calculator/android/readme.txt
@@ -0,0 +1,30 @@
+In this directory you will find the Android platform cross-calculator sample.
+
+Due to the nature of Android being java and Nim generating C code, the build
+process is slightly more complex because jni code has to be written to bridge
+both languages. In a distant future it may be possible for Nim to generate
+the whole jni bridge, but for the moment this is manual work.
+
+For the jni bridge to work first the java code is compiled with the Nim code
+just declared as a native method which will be resolved at runtime. The scripts
+nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
+generating the jni bridge from the java code respectively. Finally, the
+ndk-build command from the android ndk tools has to be run to build the binary
+library which will be installed along the final apk.
+
+All these steps are wrapped in the ant build script through the customization
+of the -post-compile rule. If you have the android ndk tools installed and you
+modify scripts/nimbuild.sh to point to the directory where you have Nim
+installed on your system, you can simply run "ant debug" to build everything.
+
+Once the apk is built you can install it on your device or emulator with the
+command "adb install bin/CrossCalculator-debug.apk".
+
+You can use this example as a starting point for your project or look at the
+history of the github project at https://github.com/gradha/nimrod-on-android.
+That repository documents the individual integration steps you would take for
+any Android project (note it uses Eclipse rather than ant to build and
+therefore the build process requires more manual fiddling).
+
+This example runs against the Android level 3 API, meaning devices from
+Android 1.5 and above should be able to run the generated binary.
diff --git a/examples/cross_calculator/android/res/layout/cross_calculator.xml b/examples/cross_calculator/android/res/layout/cross_calculator.xml
new file mode 100644
index 000000000..11531334c
--- /dev/null
+++ b/examples/cross_calculator/android/res/layout/cross_calculator.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/RelativeLayout1"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:text="Crossplatform Nimrod calculator"
+        android:textSize="20dip" >
+
+    </TextView>
+
+    <TextView
+        android:id="@+id/value_a"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/title"
+        android:text="Value A: " >
+    </TextView>
+
+    <EditText
+        android:id="@+id/edit_text_a"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_below="@+id/title"
+        android:ems="10"
+        android:inputType="number" />
+
+    <TextView
+        android:id="@+id/value_b"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/edit_text_a"
+        android:text="Value B: " >
+    </TextView>
+
+    <EditText
+        android:id="@+id/edit_text_b"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_below="@+id/edit_text_a"
+        android:ems="10"
+        android:inputType="number" />
+
+    <Button
+        android:id="@+id/add_button"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_below="@+id/edit_text_b"
+        android:scrollbarAlwaysDrawVerticalTrack="false"
+        android:selectAllOnFocus="false"
+        android:text="Add!"
+        android:visibility="visible" />
+
+    <TextView
+        android:id="@+id/result_text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_below="@+id/add_button" />
+
+</RelativeLayout>
diff --git a/examples/cross_calculator/android/res/values/strings.xml b/examples/cross_calculator/android/res/values/strings.xml
new file mode 100644
index 000000000..05cd3ac93
--- /dev/null
+++ b/examples/cross_calculator/android/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">CrossCalculator</string>
+</resources>
diff --git a/examples/cross_calculator/android/scripts/jnibuild.sh b/examples/cross_calculator/android/scripts/jnibuild.sh
new file mode 100644
index 000000000..8b61f20f7
--- /dev/null
+++ b/examples/cross_calculator/android/scripts/jnibuild.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Force errors to fail script.
+set -e
+
+# If we are running from inside the scripts subdir, get out.
+if [ ! -d src ]
+then
+	cd ..
+fi
+
+# Ok, are we out now?
+if [ -d src ]
+then
+	javah -classpath bin/classes \
+		-o jni/backend-jni.h \
+		com.github.nimrod.crosscalculator.CrossCalculator
+else
+	echo "Uh oh, bin/classes directory not found?"
+	echo "Try compiling your java code, or opening in eclipse."
+	exit 1
+fi
diff --git a/examples/cross_calculator/android/scripts/nimbuild.sh b/examples/cross_calculator/android/scripts/nimbuild.sh
new file mode 100644
index 000000000..97130b8dd
--- /dev/null
+++ b/examples/cross_calculator/android/scripts/nimbuild.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Set this to the local or full path of your nimrod compiler
+PATH_TO_NIMROD=~/project/nimrod/bin/nimrod
+# Set this to the location of the nimbase.h file so
+# the script can update it if it changes.
+PATH_TO_NIMBASE=~/project/nimrod/lib/nimbase.h
+
+# Force errors to fail script.
+set -e
+
+# If we are running from inside the scripts subdir, get out.
+if [ ! -d src ]
+then
+	cd ..
+fi
+
+DEST_NIMBASE=jni/nimcache/nimbase.h
+
+# Ok, are we out now?
+if [ -d src ]
+then
+	$PATH_TO_NIMROD c --noMain  --app:lib \
+		--nimcache:jni/nimcache --cpu:arm --os:linux \
+		--compileOnly --header ../nimrod_backend/*.nim
+	if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
+	then
+		echo "Updating nimbase.h"
+		cp "${PATH_TO_NIMBASE}" "${DEST_NIMBASE}"
+	fi
+else
+	echo "Uh oh, src directory not found?"
+	exit 1
+fi
diff --git a/examples/cross_calculator/android/scripts/tags.sh b/examples/cross_calculator/android/scripts/tags.sh
new file mode 100644
index 000000000..95507064f
--- /dev/null
+++ b/examples/cross_calculator/android/scripts/tags.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+if [ ! -d src ]
+then
+	cd ..
+fi
+
+if [ -d src ]
+then
+	~/bin/objctags -R \
+		jni \
+		src
+fi
diff --git a/examples/cross_calculator/android/src/com/github/nimrod/crosscalculator/CrossCalculator.java b/examples/cross_calculator/android/src/com/github/nimrod/crosscalculator/CrossCalculator.java
new file mode 100644
index 000000000..df2eed5ea
--- /dev/null
+++ b/examples/cross_calculator/android/src/com/github/nimrod/crosscalculator/CrossCalculator.java
@@ -0,0 +1,80 @@
+package com.github.nimrod.crosscalculator;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class CrossCalculator extends Activity
+{
+	private static final String TAG = "CrossCalculator";
+	private TextView result_text;
+	private EditText edit_text_a, edit_text_b;
+	/** Called when the activity is first created. */
+	@Override
+	public void onCreate(Bundle savedInstanceState)
+	{
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.cross_calculator);
+
+		final Button button = (Button)findViewById(R.id.add_button);
+		button.setOnClickListener(new View.OnClickListener() {
+			public void onClick(View v) { addButtonClicked(); } });
+
+		result_text = (TextView)findViewById(R.id.result_text);
+		edit_text_a = (EditText)findViewById(R.id.edit_text_a);
+		edit_text_b = (EditText)findViewById(R.id.edit_text_b);
+	}
+
+	/** Handles clicks on the addition button.
+	 * Reads the values form the input fields and performs the calculation.
+	 */
+	private void addButtonClicked()
+	{
+		int a = 0, b = 0;
+		String errors = "";
+		final String a_text = edit_text_a.getText().toString();
+		final String b_text = edit_text_b.getText().toString();
+		try {
+			a = Integer.valueOf(a_text, 10);
+		} catch (NumberFormatException e) {
+			errors += "Can't parse a value '" + a_text + "'. ";
+		}
+		try {
+			b = Integer.valueOf(b_text, 10);
+		} catch (NumberFormatException e) {
+			errors += "Can't parse b value '" + b_text + "'";
+		}
+		final int c = myAdd(a, b);
+		result_text.setText("myAdd(" + a + ", " + b + ") = " + c);
+
+		if (errors.length() > 0) {
+			Log.e(TAG, errors);
+			Toast.makeText(this, errors, Toast.LENGTH_SHORT).show();
+		}
+	}
+
+	/* A native method that is implemented by the
+	 * 'backend-jni' native library, which is packaged
+	 * with this application. Adds to integers.
+	 */
+	public native int myAdd(int a, int b);
+
+	/* A native method used to initialise Nimrod.
+	 */
+	static public native void initNimMain();
+
+	/* this is used to load the 'backend-jni' library on application
+	 * startup. The library has already been unpacked into
+	 * /data/data/com.github.nimrod.backendjni/lib/libbackend-jni.so at
+	 * installation time by the package manager.
+	 */
+	static {
+		System.loadLibrary("backend-jni");
+		initNimMain();
+	}
+}
diff --git a/examples/cross_calculator/ios/cross-calculator.xcodeproj/project.pbxproj b/examples/cross_calculator/ios/cross-calculator.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..71cebc18a
--- /dev/null
+++ b/examples/cross_calculator/ios/cross-calculator.xcodeproj/project.pbxproj
@@ -0,0 +1,337 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		D531422A15BC8611005EFF20 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D531422915BC8611005EFF20 /* UIKit.framework */; };
+		D531422C15BC8611005EFF20 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D531422B15BC8611005EFF20 /* Foundation.framework */; };
+		D531422E15BC8611005EFF20 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D531422D15BC8611005EFF20 /* CoreGraphics.framework */; };
+		D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424A15BC87B6005EFF20 /* AppDelegate.m */; };
+		D531424E15BC87B6005EFF20 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D531424B15BC87B6005EFF20 /* main.m */; };
+		D531427215BC94B1005EFF20 /* backend.m in Sources */ = {isa = PBXBuildFile; fileRef = D531426F15BC94B1005EFF20 /* backend.m */; };
+		D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */ = {isa = PBXBuildFile; fileRef = D531427115BC94B1005EFF20 /* stdlib_system.m */; };
+		D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B6F94615FA8D4C0084A85B /* NRViewController.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		D531422515BC8611005EFF20 /* cross-calculator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "cross-calculator.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		D531422915BC8611005EFF20 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+		D531422B15BC8611005EFF20 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		D531422D15BC8611005EFF20 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+		D531424715BC87A5005EFF20 /* cross-calculator-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "cross-calculator-Info.plist"; path = "resources/plist/cross-calculator-Info.plist"; sourceTree = "<group>"; };
+		D531424915BC87B6005EFF20 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = src/AppDelegate.h; sourceTree = "<group>"; };
+		D531424A15BC87B6005EFF20 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = src/AppDelegate.m; sourceTree = "<group>"; };
+		D531424B15BC87B6005EFF20 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = src/main.m; sourceTree = "<group>"; };
+		D531424C15BC87B6005EFF20 /* cross-calculator-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cross-calculator-Prefix.pch"; path = "src/cross-calculator-Prefix.pch"; sourceTree = "<group>"; };
+		D531426715BC91EF005EFF20 /* tags.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = tags.sh; path = scripts/tags.sh; sourceTree = "<group>"; };
+		D531426815BC91EF005EFF20 /* xcode_prebuild.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = xcode_prebuild.sh; path = scripts/xcode_prebuild.sh; sourceTree = "<group>"; };
+		D531426F15BC94B1005EFF20 /* backend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = backend.m; path = build/nimcache/backend.m; sourceTree = "<group>"; };
+		D531427115BC94B1005EFF20 /* stdlib_system.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = stdlib_system.m; path = build/nimcache/stdlib_system.m; sourceTree = "<group>"; };
+		D592E19015C7120F005258EA /* backend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = backend.h; path = build/nimcache/backend.h; sourceTree = "<group>"; };
+		D592E19115C71415005258EA /* nimbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nimbase.h; path = build/nimcache/nimbase.h; sourceTree = "<group>"; };
+		D5B6F94515FA8D4C0084A85B /* NRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NRViewController.h; path = src/NRViewController.h; sourceTree = "<group>"; };
+		D5B6F94615FA8D4C0084A85B /* NRViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NRViewController.m; path = src/NRViewController.m; sourceTree = "<group>"; };
+		D5B6F96315FB448D0084A85B /* NRViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = NRViewController.xib; path = resources/ui/NRViewController.xib; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		D531422215BC8610005EFF20 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D531422A15BC8611005EFF20 /* UIKit.framework in Frameworks */,
+				D531422C15BC8611005EFF20 /* Foundation.framework in Frameworks */,
+				D531422E15BC8611005EFF20 /* CoreGraphics.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		D531421A15BC8610005EFF20 = {
+			isa = PBXGroup;
+			children = (
+				D531426A15BC93D5005EFF20 /* build */,
+				D531424515BC874E005EFF20 /* resources */,
+				D531426615BC91E1005EFF20 /* scripts */,
+				D531424815BC87AD005EFF20 /* src */,
+				D531422815BC8611005EFF20 /* Frameworks */,
+				D531422615BC8611005EFF20 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		D531422615BC8611005EFF20 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				D531422515BC8611005EFF20 /* cross-calculator.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		D531422815BC8611005EFF20 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				D531422915BC8611005EFF20 /* UIKit.framework */,
+				D531422B15BC8611005EFF20 /* Foundation.framework */,
+				D531422D15BC8611005EFF20 /* CoreGraphics.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		D531424515BC874E005EFF20 /* resources */ = {
+			isa = PBXGroup;
+			children = (
+				D531424615BC8756005EFF20 /* plist */,
+				D5B6F96115FB447C0084A85B /* ui */,
+			);
+			name = resources;
+			sourceTree = "<group>";
+		};
+		D531424615BC8756005EFF20 /* plist */ = {
+			isa = PBXGroup;
+			children = (
+				D531424715BC87A5005EFF20 /* cross-calculator-Info.plist */,
+			);
+			name = plist;
+			sourceTree = "<group>";
+		};
+		D531424815BC87AD005EFF20 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				D531424915BC87B6005EFF20 /* AppDelegate.h */,
+				D531424A15BC87B6005EFF20 /* AppDelegate.m */,
+				D531424C15BC87B6005EFF20 /* cross-calculator-Prefix.pch */,
+				D531424B15BC87B6005EFF20 /* main.m */,
+				D5B6F94515FA8D4C0084A85B /* NRViewController.h */,
+				D5B6F94615FA8D4C0084A85B /* NRViewController.m */,
+			);
+			name = src;
+			sourceTree = "<group>";
+		};
+		D531426615BC91E1005EFF20 /* scripts */ = {
+			isa = PBXGroup;
+			children = (
+				D531426715BC91EF005EFF20 /* tags.sh */,
+				D531426815BC91EF005EFF20 /* xcode_prebuild.sh */,
+			);
+			name = scripts;
+			sourceTree = "<group>";
+		};
+		D531426A15BC93D5005EFF20 /* build */ = {
+			isa = PBXGroup;
+			children = (
+				D531426E15BC94A6005EFF20 /* nimrod */,
+			);
+			name = build;
+			sourceTree = "<group>";
+		};
+		D531426E15BC94A6005EFF20 /* nimrod */ = {
+			isa = PBXGroup;
+			children = (
+				D592E19015C7120F005258EA /* backend.h */,
+				D531426F15BC94B1005EFF20 /* backend.m */,
+				D592E19115C71415005258EA /* nimbase.h */,
+				D531427115BC94B1005EFF20 /* stdlib_system.m */,
+			);
+			name = nimrod;
+			sourceTree = "<group>";
+		};
+		D5B6F96115FB447C0084A85B /* ui */ = {
+			isa = PBXGroup;
+			children = (
+				D5B6F96315FB448D0084A85B /* NRViewController.xib */,
+			);
+			name = ui;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		D531422415BC8610005EFF20 /* cross-calculator */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = D531423D15BC8611005EFF20 /* Build configuration list for PBXNativeTarget "cross-calculator" */;
+			buildPhases = (
+				D531426915BC926C005EFF20 /* ShellScript */,
+				D531422115BC8610005EFF20 /* Sources */,
+				D531422215BC8610005EFF20 /* Frameworks */,
+				D531422315BC8610005EFF20 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "cross-calculator";
+			productName = "cross-calculator";
+			productReference = D531422515BC8611005EFF20 /* cross-calculator.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		D531421C15BC8610005EFF20 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0420;
+				ORGANIZATIONNAME = "Electric Hands Software";
+			};
+			buildConfigurationList = D531421F15BC8610005EFF20 /* Build configuration list for PBXProject "cross-calculator" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = D531421A15BC8610005EFF20;
+			productRefGroup = D531422615BC8611005EFF20 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				D531422415BC8610005EFF20 /* cross-calculator */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		D531422315BC8610005EFF20 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		D531426915BC926C005EFF20 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = scripts/xcode_prebuild.sh;
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		D531422115BC8610005EFF20 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				D531424D15BC87B6005EFF20 /* AppDelegate.m in Sources */,
+				D531424E15BC87B6005EFF20 /* main.m in Sources */,
+				D531427215BC94B1005EFF20 /* backend.m in Sources */,
+				D531427415BC94B1005EFF20 /* stdlib_system.m in Sources */,
+				D5B6F94815FA8D4C0084A85B /* NRViewController.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		D531423B15BC8611005EFF20 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = (
+					armv7,
+					armv6,
+				);
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = "";
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		D531423C15BC8611005EFF20 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = (
+					armv7,
+					armv6,
+				);
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_VERSION = "";
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 4.3;
+				OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		D531423E15BC8611005EFF20 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "src/cross-calculator-Prefix.pch";
+				INFOPLIST_FILE = "resources/plist/cross-calculator-Info.plist";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Debug;
+		};
+		D531423F15BC8611005EFF20 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "src/cross-calculator-Prefix.pch";
+				INFOPLIST_FILE = "resources/plist/cross-calculator-Info.plist";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				WRAPPER_EXTENSION = app;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		D531421F15BC8610005EFF20 /* Build configuration list for PBXProject "cross-calculator" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				D531423B15BC8611005EFF20 /* Debug */,
+				D531423C15BC8611005EFF20 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		D531423D15BC8611005EFF20 /* Build configuration list for PBXNativeTarget "cross-calculator" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				D531423E15BC8611005EFF20 /* Debug */,
+				D531423F15BC8611005EFF20 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = D531421C15BC8610005EFF20 /* Project object */;
+}
diff --git a/examples/cross_calculator/ios/readme.txt b/examples/cross_calculator/ios/readme.txt
new file mode 100644
index 000000000..83538aad7
--- /dev/null
+++ b/examples/cross_calculator/ios/readme.txt
@@ -0,0 +1,17 @@
+In this directory you will find the iOS platform cross-calculator sample.
+
+The iOS version of the code builds a view controller in charge of displaying
+the interface to the user. The Nim backend code is compiled into C code and
+put into build/nimrod as a pre-build phase of the project.
+
+When the calculate button is used the view controller calls the Nim code to
+delegate the logic of the operation and puts the result in a label for display.
+All interface error checks are implemented in the view controller.
+
+You can use this as a starting point for your project or look at the history of
+the github project at https://github.com/gradha/nimrod-on-ios. That repository
+documents the individual integration steps you would take for any iOS project.
+
+This version of the iOS project is known to work with Xcode 4.2 and Xcode
+4.4.1. The final binary can be deployed on iOS 3.x to 5.x supporting all iOS
+platforms and versions available at the moment.
diff --git a/examples/cross_calculator/ios/resources/plist/cross-calculator-Info.plist b/examples/cross_calculator/ios/resources/plist/cross-calculator-Info.plist
new file mode 100644
index 000000000..758f20e38
--- /dev/null
+++ b/examples/cross_calculator/ios/resources/plist/cross-calculator-Info.plist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFiles</key>
+	<array/>
+	<key>CFBundleIdentifier</key>
+	<string>com.github.nimrod.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>UIApplicationExitsOnSuspend</key>
+	<true/>
+</dict>
+</plist>
diff --git a/examples/cross_calculator/ios/resources/ui/NRViewController.xib b/examples/cross_calculator/ios/resources/ui/NRViewController.xib
new file mode 100644
index 000000000..b260db2af
--- /dev/null
+++ b/examples/cross_calculator/ios/resources/ui/NRViewController.xib
@@ -0,0 +1,479 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
+	<data>
+		<int key="IBDocument.SystemTarget">0</int>
+		<string key="IBDocument.SystemVersion">11E53</string>
+		<string key="IBDocument.InterfaceBuilderVersion">2549</string>
+		<string key="IBDocument.AppKitVersion">1138.47</string>
+		<string key="IBDocument.HIToolboxVersion">569.00</string>
+		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+			<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+			<string key="NS.object.0">1498</string>
+		</object>
+		<array key="IBDocument.IntegratedClassDependencies">
+			<string>IBProxyObject</string>
+			<string>IBUIButton</string>
+			<string>IBUILabel</string>
+			<string>IBUITextField</string>
+			<string>IBUIView</string>
+		</array>
+		<array key="IBDocument.PluginDependencies">
+			<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+		</array>
+		<object class="NSMutableDictionary" key="IBDocument.Metadata">
+			<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
+			<integer value="1" key="NS.object.0"/>
+		</object>
+		<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+			<object class="IBProxyObject" id="372490531">
+				<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
+				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+			</object>
+			<object class="IBProxyObject" id="975951072">
+				<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
+				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+			</object>
+			<object class="IBUIView" id="191373211">
+				<reference key="NSNextResponder"/>
+				<int key="NSvFlags">274</int>
+				<array class="NSMutableArray" key="NSSubviews">
+					<object class="IBUIButton" id="467453084">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">292</int>
+						<string key="NSFrame">{{0, -10}, {320, 480}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<int key="IBUITag">1</int>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<int key="IBUIContentHorizontalAlignment">0</int>
+						<int key="IBUIContentVerticalAlignment">0</int>
+						<object class="NSColor" key="IBUIHighlightedTitleColor" id="95215378">
+							<int key="NSColorSpace">3</int>
+							<bytes key="NSWhite">MQA</bytes>
+						</object>
+						<object class="NSColor" key="IBUINormalTitleColor">
+							<int key="NSColorSpace">1</int>
+							<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
+						</object>
+						<object class="NSColor" key="IBUINormalTitleShadowColor" id="1056499111">
+							<int key="NSColorSpace">3</int>
+							<bytes key="NSWhite">MC41AA</bytes>
+						</object>
+						<object class="IBUIFontDescription" key="IBUIFontDescription" id="686052398">
+							<int key="type">2</int>
+							<double key="pointSize">15</double>
+						</object>
+						<object class="NSFont" key="IBUIFont" id="594372787">
+							<string key="NSName">Helvetica-Bold</string>
+							<double key="NSSize">15</double>
+							<int key="NSfFlags">16</int>
+						</object>
+					</object>
+					<object class="IBUILabel" id="353054360">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">306</int>
+						<string key="NSFrameSize">{320, 34}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="525225214"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUIContentMode">7</int>
+						<int key="IBUITag">2</int>
+						<bool key="IBUIUserInteractionEnabled">NO</bool>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<string key="IBUIText">Nimrod Crossplatform Calculator</string>
+						<object class="NSColor" key="IBUITextColor" id="128895179">
+							<int key="NSColorSpace">1</int>
+							<bytes key="NSRGB">MCAwIDAAA</bytes>
+						</object>
+						<nil key="IBUIHighlightedColor"/>
+						<int key="IBUIBaselineAdjustment">0</int>
+						<float key="IBUIMinimumFontSize">10</float>
+						<int key="IBUITextAlignment">1</int>
+						<object class="IBUIFontDescription" key="IBUIFontDescription">
+							<int key="type">2</int>
+							<double key="pointSize">18</double>
+						</object>
+						<object class="NSFont" key="IBUIFont">
+							<string key="NSName">Helvetica-Bold</string>
+							<double key="NSSize">18</double>
+							<int key="NSfFlags">16</int>
+						</object>
+					</object>
+					<object class="IBUILabel" id="525225214">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">294</int>
+						<string key="NSFrame">{{20, 42}, {165, 31}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="1040444341"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUIContentMode">7</int>
+						<int key="IBUITag">3</int>
+						<bool key="IBUIUserInteractionEnabled">NO</bool>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<string key="IBUIText">Value A:</string>
+						<reference key="IBUITextColor" ref="128895179"/>
+						<nil key="IBUIHighlightedColor"/>
+						<int key="IBUIBaselineAdjustment">0</int>
+						<float key="IBUIMinimumFontSize">10</float>
+						<object class="IBUIFontDescription" key="IBUIFontDescription" id="768572949">
+							<int key="type">1</int>
+							<double key="pointSize">17</double>
+						</object>
+						<object class="NSFont" key="IBUIFont" id="972319481">
+							<string key="NSName">Helvetica</string>
+							<double key="NSSize">17</double>
+							<int key="NSfFlags">16</int>
+						</object>
+					</object>
+					<object class="IBUILabel" id="904781109">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">294</int>
+						<string key="NSFrame">{{20, 81}, {165, 31}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="1041721572"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUIContentMode">7</int>
+						<int key="IBUITag">4</int>
+						<bool key="IBUIUserInteractionEnabled">NO</bool>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<string key="IBUIText">Value B:</string>
+						<reference key="IBUITextColor" ref="128895179"/>
+						<nil key="IBUIHighlightedColor"/>
+						<int key="IBUIBaselineAdjustment">0</int>
+						<float key="IBUIMinimumFontSize">10</float>
+						<reference key="IBUIFontDescription" ref="768572949"/>
+						<reference key="IBUIFont" ref="972319481"/>
+					</object>
+					<object class="IBUIButton" id="557594991">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">291</int>
+						<string key="NSFrame">{{193, 124}, {107, 37}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<int key="IBUITag">5</int>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<int key="IBUIContentHorizontalAlignment">0</int>
+						<int key="IBUIContentVerticalAlignment">0</int>
+						<int key="IBUIButtonType">1</int>
+						<string key="IBUINormalTitle">Add!</string>
+						<reference key="IBUIHighlightedTitleColor" ref="95215378"/>
+						<object class="NSColor" key="IBUINormalTitleColor">
+							<int key="NSColorSpace">1</int>
+							<bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes>
+						</object>
+						<reference key="IBUINormalTitleShadowColor" ref="1056499111"/>
+						<reference key="IBUIFontDescription" ref="686052398"/>
+						<reference key="IBUIFont" ref="594372787"/>
+					</object>
+					<object class="IBUILabel" id="360864196">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">292</int>
+						<string key="NSFrame">{{20, 124}, {60, 37}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="521073831"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUIContentMode">7</int>
+						<int key="IBUITag">6</int>
+						<bool key="IBUIUserInteractionEnabled">NO</bool>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<string key="IBUIText">Result:</string>
+						<reference key="IBUITextColor" ref="128895179"/>
+						<nil key="IBUIHighlightedColor"/>
+						<int key="IBUIBaselineAdjustment">0</int>
+						<float key="IBUIMinimumFontSize">10</float>
+						<reference key="IBUIFontDescription" ref="768572949"/>
+						<reference key="IBUIFont" ref="972319481"/>
+					</object>
+					<object class="IBUILabel" id="521073831">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">294</int>
+						<string key="NSFrame">{{88, 124}, {97, 37}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="557594991"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUIContentMode">7</int>
+						<int key="IBUITag">7</int>
+						<bool key="IBUIUserInteractionEnabled">NO</bool>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<string key="IBUIText"/>
+						<reference key="IBUITextColor" ref="128895179"/>
+						<nil key="IBUIHighlightedColor"/>
+						<int key="IBUIBaselineAdjustment">0</int>
+						<float key="IBUIMinimumFontSize">10</float>
+						<reference key="IBUIFontDescription" ref="768572949"/>
+						<reference key="IBUIFont" ref="972319481"/>
+					</object>
+					<object class="IBUITextField" id="1040444341">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">291</int>
+						<string key="NSFrame">{{193, 42}, {107, 31}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="904781109"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUITag">8</int>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<int key="IBUIContentVerticalAlignment">0</int>
+						<string key="IBUIText"/>
+						<int key="IBUIBorderStyle">3</int>
+						<string key="IBUIPlaceholder">Integer</string>
+						<object class="NSColor" key="IBUITextColor">
+							<int key="NSColorSpace">3</int>
+							<bytes key="NSWhite">MAA</bytes>
+							<object class="NSColorSpace" key="NSCustomColorSpace" id="433120901">
+								<int key="NSID">2</int>
+							</object>
+						</object>
+						<int key="IBUITextAlignment">1</int>
+						<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
+						<float key="IBUIMinimumFontSize">17</float>
+						<object class="IBUITextInputTraits" key="IBUITextInputTraits">
+							<int key="IBUIKeyboardType">4</int>
+							<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						</object>
+						<int key="IBUIClearButtonMode">1</int>
+						<object class="IBUIFontDescription" key="IBUIFontDescription" id="836805198">
+							<int key="type">1</int>
+							<double key="pointSize">14</double>
+						</object>
+						<object class="NSFont" key="IBUIFont" id="700927782">
+							<string key="NSName">Helvetica</string>
+							<double key="NSSize">14</double>
+							<int key="NSfFlags">16</int>
+						</object>
+					</object>
+					<object class="IBUITextField" id="1041721572">
+						<reference key="NSNextResponder" ref="191373211"/>
+						<int key="NSvFlags">291</int>
+						<string key="NSFrame">{{193, 81}, {107, 31}}</string>
+						<reference key="NSSuperview" ref="191373211"/>
+						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="360864196"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<bool key="IBUIClipsSubviews">YES</bool>
+						<int key="IBUITag">9</int>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<int key="IBUIContentVerticalAlignment">0</int>
+						<string key="IBUIText"/>
+						<int key="IBUIBorderStyle">3</int>
+						<string key="IBUIPlaceholder">Integer</string>
+						<object class="NSColor" key="IBUITextColor">
+							<int key="NSColorSpace">3</int>
+							<bytes key="NSWhite">MAA</bytes>
+							<reference key="NSCustomColorSpace" ref="433120901"/>
+						</object>
+						<int key="IBUITextAlignment">1</int>
+						<bool key="IBUIAdjustsFontSizeToFit">YES</bool>
+						<float key="IBUIMinimumFontSize">17</float>
+						<object class="IBUITextInputTraits" key="IBUITextInputTraits">
+							<int key="IBUIKeyboardType">4</int>
+							<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						</object>
+						<int key="IBUIClearButtonMode">1</int>
+						<reference key="IBUIFontDescription" ref="836805198"/>
+						<reference key="IBUIFont" ref="700927782"/>
+					</object>
+				</array>
+				<string key="NSFrame">{{0, 20}, {320, 460}}</string>
+				<reference key="NSSuperview"/>
+				<reference key="NSWindow"/>
+				<reference key="NSNextKeyView" ref="353054360"/>
+				<object class="NSColor" key="IBUIBackgroundColor">
+					<int key="NSColorSpace">3</int>
+					<bytes key="NSWhite">MQA</bytes>
+					<reference key="NSCustomColorSpace" ref="433120901"/>
+				</object>
+				<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
+				<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+			</object>
+		</array>
+		<object class="IBObjectContainer" key="IBDocument.Objects">
+			<array class="NSMutableArray" key="connectionRecords"/>
+			<object class="IBMutableOrderedSet" key="objectRecords">
+				<array key="orderedObjects">
+					<object class="IBObjectRecord">
+						<int key="objectID">0</int>
+						<array key="object" id="0"/>
+						<reference key="children" ref="1000"/>
+						<nil key="parent"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">1</int>
+						<reference key="object" ref="191373211"/>
+						<array class="NSMutableArray" key="children">
+							<reference ref="353054360"/>
+							<reference ref="525225214"/>
+							<reference ref="904781109"/>
+							<reference ref="557594991"/>
+							<reference ref="360864196"/>
+							<reference ref="521073831"/>
+							<reference ref="1040444341"/>
+							<reference ref="1041721572"/>
+							<reference ref="467453084"/>
+						</array>
+						<reference key="parent" ref="0"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-1</int>
+						<reference key="object" ref="372490531"/>
+						<reference key="parent" ref="0"/>
+						<string key="objectName">File's Owner</string>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">-2</int>
+						<reference key="object" ref="975951072"/>
+						<reference key="parent" ref="0"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">14</int>
+						<reference key="object" ref="1041721572"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">13</int>
+						<reference key="object" ref="1040444341"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">12</int>
+						<reference key="object" ref="521073831"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">11</int>
+						<reference key="object" ref="360864196"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">10</int>
+						<reference key="object" ref="557594991"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">8</int>
+						<reference key="object" ref="904781109"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">7</int>
+						<reference key="object" ref="525225214"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">4</int>
+						<reference key="object" ref="353054360"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">22</int>
+						<reference key="object" ref="467453084"/>
+						<reference key="parent" ref="191373211"/>
+					</object>
+				</array>
+			</object>
+			<dictionary class="NSMutableDictionary" key="flattenedProperties">
+				<string key="-1.CustomClassName">NRViewController</string>
+				<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="-2.CustomClassName">UIResponder</string>
+				<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="10.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="11.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="12.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="13.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="14.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="22.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="7.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="8.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+			</dictionary>
+			<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
+			<nil key="activeLocalization"/>
+			<dictionary class="NSMutableDictionary" key="localizations"/>
+			<nil key="sourceID"/>
+			<int key="maxID">22</int>
+		</object>
+		<object class="IBClassDescriber" key="IBDocument.Classes">
+			<array class="NSMutableArray" key="referencedPartialClassDescriptions">
+				<object class="IBPartialClassDescription">
+					<string key="className">NRViewController</string>
+					<string key="superclassName">UIViewController</string>
+					<dictionary class="NSMutableDictionary" key="actions">
+						<string key="backgroundTouched">id</string>
+						<string key="calculateButtonTouched">id</string>
+					</dictionary>
+					<dictionary class="NSMutableDictionary" key="actionInfosByName">
+						<object class="IBActionInfo" key="backgroundTouched">
+							<string key="name">backgroundTouched</string>
+							<string key="candidateClassName">id</string>
+						</object>
+						<object class="IBActionInfo" key="calculateButtonTouched">
+							<string key="name">calculateButtonTouched</string>
+							<string key="candidateClassName">id</string>
+						</object>
+					</dictionary>
+					<dictionary class="NSMutableDictionary" key="outlets">
+						<string key="aText">UITextField</string>
+						<string key="bText">UITextField</string>
+						<string key="calculateButton">UIButton</string>
+						<string key="resultLabel">UILabel</string>
+					</dictionary>
+					<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName">
+						<object class="IBToOneOutletInfo" key="aText">
+							<string key="name">aText</string>
+							<string key="candidateClassName">UITextField</string>
+						</object>
+						<object class="IBToOneOutletInfo" key="bText">
+							<string key="name">bText</string>
+							<string key="candidateClassName">UITextField</string>
+						</object>
+						<object class="IBToOneOutletInfo" key="calculateButton">
+							<string key="name">calculateButton</string>
+							<string key="candidateClassName">UIButton</string>
+						</object>
+						<object class="IBToOneOutletInfo" key="resultLabel">
+							<string key="name">resultLabel</string>
+							<string key="candidateClassName">UILabel</string>
+						</object>
+					</dictionary>
+					<object class="IBClassDescriptionSource" key="sourceIdentifier">
+						<string key="majorKey">IBProjectSource</string>
+						<string key="minorKey">./Classes/NRViewController.h</string>
+					</object>
+				</object>
+			</array>
+		</object>
+		<int key="IBDocument.localizationMode">0</int>
+		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
+		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
+			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
+			<real value="0.0" key="NS.object.0"/>
+		</object>
+		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+		<int key="IBDocument.defaultPropertyAccessControl">3</int>
+		<string key="IBCocoaTouchPluginVersion">1498</string>
+	</data>
+</archive>
diff --git a/examples/cross_calculator/ios/scripts/tags.sh b/examples/cross_calculator/ios/scripts/tags.sh
new file mode 100644
index 000000000..111e7a1c0
--- /dev/null
+++ b/examples/cross_calculator/ios/scripts/tags.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+if [ ! -d src ]
+then
+	cd ..
+fi
+
+if [ -d src ]
+then
+	~/bin/objctags -R \
+		build/nimcache \
+		src
+fi
diff --git a/examples/cross_calculator/ios/scripts/xcode_prebuild.sh b/examples/cross_calculator/ios/scripts/xcode_prebuild.sh
new file mode 100644
index 000000000..90bafd74e
--- /dev/null
+++ b/examples/cross_calculator/ios/scripts/xcode_prebuild.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# Set this to the full path of your nimrod compiler
+# since Xcode doesn't inherit your user environment.
+PATH_TO_NIMROD=~/project/nimrod/bin/nimrod
+# Set this to the location of the nimbase.h file so
+# the script can update it if it changes.
+PATH_TO_NIMBASE=~/project/nimrod/lib/nimbase.h
+
+# Force errors to fail script.
+set -e
+
+# If we are running from inside the scripts subdir, get out.
+if [ ! -d src ]
+then
+	cd ..
+fi
+
+DEST_NIMBASE=build/nimcache/nimbase.h
+
+# Ok, are we out now?
+if [ -d src ]
+then
+	$PATH_TO_NIMROD objc --noMain  --app:lib \
+		--nimcache:./build/nimcache --compileOnly \
+		--header --cpu:i386 ../nimrod_backend/backend.nim
+	if [ "${PATH_TO_NIMBASE}" -nt "${DEST_NIMBASE}" ]
+	then
+		echo "Updating nimbase.h"
+		cp "${PATH_TO_NIMBASE}" "${DEST_NIMBASE}"
+	fi
+else
+	echo "Uh oh, src directory not found?"
+	exit 1
+fi
diff --git a/examples/cross_calculator/ios/src/AppDelegate.h b/examples/cross_calculator/ios/src/AppDelegate.h
new file mode 100644
index 000000000..a5a8b3852
--- /dev/null
+++ b/examples/cross_calculator/ios/src/AppDelegate.h
@@ -0,0 +1,7 @@
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/examples/cross_calculator/ios/src/AppDelegate.m b/examples/cross_calculator/ios/src/AppDelegate.m
new file mode 100644
index 000000000..53e7f6188
--- /dev/null
+++ b/examples/cross_calculator/ios/src/AppDelegate.m
@@ -0,0 +1,39 @@
+#import "AppDelegate.h"
+
+#import "NRViewController.h"
+
+
+@interface AppDelegate ()
+@property (nonatomic, retain) NRViewController *viewController;
+@end
+
+
+@implementation AppDelegate
+
+@synthesize viewController = _viewController;
+@synthesize window = _window;
+
+- (BOOL)application:(UIApplication *)application
+	didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+	self.window = [[[UIWindow alloc]
+		initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
+
+	self.viewController = [[NRViewController new] autorelease];
+	if ([self.window respondsToSelector:@selector(setRootViewController:)])
+		self.window.rootViewController = self.viewController;
+	else
+		[self.window addSubview:self.viewController.view];
+	[self.window makeKeyAndVisible];
+
+	return YES;
+}
+
+- (void)dealloc
+{
+	[_window release];
+	[_viewController release];
+	[super dealloc];
+}
+
+@end
diff --git a/examples/cross_calculator/ios/src/NRViewController.h b/examples/cross_calculator/ios/src/NRViewController.h
new file mode 100644
index 000000000..36ba37758
--- /dev/null
+++ b/examples/cross_calculator/ios/src/NRViewController.h
@@ -0,0 +1,11 @@
+@interface NRViewController : UIViewController
+
+@property (nonatomic, retain) IBOutlet UIButton *calculateButton;
+@property (nonatomic, retain) IBOutlet UITextField *aText;
+@property (nonatomic, retain) IBOutlet UITextField *bText;
+@property (nonatomic, retain) IBOutlet UILabel *resultLabel;
+
+- (IBAction)calculateButtonTouched;
+- (IBAction)backgroundTouched;
+
+@end
\ No newline at end of file
diff --git a/examples/cross_calculator/ios/src/NRViewController.m b/examples/cross_calculator/ios/src/NRViewController.m
new file mode 100644
index 000000000..f629bfc09
--- /dev/null
+++ b/examples/cross_calculator/ios/src/NRViewController.m
@@ -0,0 +1,210 @@
+#import "NRViewController.h"
+
+#import "backend.h"
+
+
+@implementation NRViewController
+
+@synthesize aText = _aText;
+@synthesize bText = _bText;
+@synthesize calculateButton = _calculateButton;
+@synthesize resultLabel = _resultLabel;
+
+- (void)dealloc
+{
+	[_aText release];
+	[_bText release];
+	[_calculateButton release];
+	[_resultLabel release];
+	[super dealloc];
+}
+
+- (void)viewDidUnload
+{
+	self.calculateButton = nil;
+	self.aText = nil;
+	self.bText = nil;
+	self.resultLabel = nil;
+	[super viewDidUnload];
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:
+	(UIInterfaceOrientation)interfaceOrientation
+{
+	return YES;
+}
+
+/// User wants to calculate the inputs. Well, do it!
+- (IBAction)calculateButtonTouched
+{
+	// Dismiss all keyboards.
+	[self backgroundTouched];
+
+	// Call Nim code, store the result and display it.
+	const int a = [self.aText.text intValue];
+	const int b = [self.bText.text intValue];
+	const int c = myAdd(a, b);
+	self.resultLabel.text = [NSString stringWithFormat:@"%d + %d = %d",
+		a, b, c];
+}
+
+/// If the user touches the background, dismiss any visible keyboard.
+- (IBAction)backgroundTouched
+{
+	[self.aText resignFirstResponder];
+	[self.bText resignFirstResponder];
+}
+
+/** Custom loadView method for backwards compatibility.
+ * Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
+ * which are compatible with my trusty iOS 3.0 ipod touch so in order to be
+ * fully compatible for all devices we have to build the interface manually in
+ * code rather than through the keyed archivers provided by the interface
+ * builder.
+ *
+ * Rather than recreating the user interface manually in code the tool nib2obj
+ * was used on the xib file and slightly modified to fit the original property
+ * names. Which means here is a lot of garbage you would never write in real
+ * life. Please ignore the following "wall of code" for the purposes of
+ * learning Nim, this is all just because Apple can't be bothered to
+ * maintain backwards compatibility properly.
+ */
+- (void)loadView
+{
+	[super loadView];
+
+	self.calculateButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+	self.calculateButton.autoresizesSubviews = YES;
+	self.calculateButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
+	self.calculateButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
+	self.calculateButton.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	self.calculateButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
+	self.calculateButton.frame = CGRectMake(193.0, 124.0, 107.0, 37.0);
+	self.calculateButton.tag = 5;
+	[self.calculateButton setTitle:@"Add!" forState:UIControlStateNormal];
+	[self.calculateButton addTarget:self
+		action:@selector(calculateButtonTouched)
+		forControlEvents:UIControlEventTouchUpInside];
+
+	UILabel *label11 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 124.0, 60.0, 37.0)];
+	label11.adjustsFontSizeToFitWidth = YES;
+	label11.autoresizesSubviews = YES;
+	label11.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
+	label11.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	label11.frame = CGRectMake(20.0, 124.0, 60.0, 37.0);
+	label11.tag = 6;
+	label11.text = @"Result:";
+
+	UILabel *label4 = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 34.0)];
+	label4.adjustsFontSizeToFitWidth = YES;
+	label4.autoresizesSubviews = YES;
+	label4.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
+	label4.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	label4.frame = CGRectMake(0.0, 0.0, 320.0, 34.0);
+	label4.tag = 2;
+	label4.text = @"Nim Crossplatform Calculator";
+	label4.textAlignment = UITextAlignmentCenter;
+
+	UIButton *background_button = [UIButton buttonWithType:UIButtonTypeCustom];
+	background_button.autoresizesSubviews = YES;
+	background_button.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
+	background_button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
+	background_button.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	background_button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
+	background_button.frame = CGRectMake(0.0, -10.0, 320.0, 480.0);
+	background_button.tag = 1;
+	[background_button addTarget:self action:@selector(backgroundTouched)
+		forControlEvents:UIControlEventTouchDown];
+
+	self.resultLabel = [[[UILabel alloc] initWithFrame:CGRectMake(88.0, 124.0, 97.0, 37.0)] autorelease];
+	self.resultLabel.adjustsFontSizeToFitWidth = YES;
+	self.resultLabel.autoresizesSubviews = YES;
+	self.resultLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
+	self.resultLabel.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	self.resultLabel.frame = CGRectMake(88.0, 124.0, 97.0, 37.0);
+	self.resultLabel.tag = 7;
+	self.resultLabel.text = @"";
+
+	self.aText = [[[UITextField alloc] initWithFrame:CGRectMake(193.0, 42.0, 107.0, 31.0)] autorelease];
+	self.aText.adjustsFontSizeToFitWidth = YES;
+	self.aText.autocapitalizationType = UITextAutocapitalizationTypeNone;
+	self.aText.autocorrectionType = UITextAutocorrectionTypeDefault;
+	self.aText.autoresizesSubviews = YES;
+	self.aText.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
+	self.aText.borderStyle = UITextBorderStyleRoundedRect;
+	self.aText.clearButtonMode = UITextFieldViewModeWhileEditing;
+	self.aText.clearsOnBeginEditing = NO;
+	self.aText.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
+	self.aText.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	self.aText.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
+	self.aText.enablesReturnKeyAutomatically = NO;
+	self.aText.frame = CGRectMake(193.0, 42.0, 107.0, 31.0);
+	self.aText.keyboardAppearance = UIKeyboardAppearanceDefault;
+	self.aText.keyboardType = UIKeyboardTypeNumberPad;
+	self.aText.placeholder = @"Integer";
+	self.aText.returnKeyType = UIReturnKeyDefault;
+	self.aText.tag = 8;
+	self.aText.text = @"";
+	self.aText.textAlignment = UITextAlignmentCenter;
+
+	UILabel *label7 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 42.0, 165.0, 31.0)];
+	label7.adjustsFontSizeToFitWidth = YES;
+	label7.autoresizesSubviews = YES;
+	label7.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
+	label7.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	label7.frame = CGRectMake(20.0, 42.0, 165.0, 31.0);
+	label7.tag = 3;
+	label7.text = @"Value A:";
+
+	UILabel *label8 = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 81.0, 165.0, 31.0)];
+	label8.adjustsFontSizeToFitWidth = YES;
+	label8.autoresizesSubviews = YES;
+	label8.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
+	label8.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	label8.frame = CGRectMake(20.0, 81.0, 165.0, 31.0);
+	label8.tag = 4;
+	label8.text = @"Value B:";
+
+	self.bText = [[[UITextField alloc]
+		initWithFrame:CGRectMake(193.0, 81.0, 107.0, 31.0)] autorelease];
+	self.bText.adjustsFontSizeToFitWidth = YES;
+	self.bText.autocapitalizationType = UITextAutocapitalizationTypeNone;
+	self.bText.autocorrectionType = UITextAutocorrectionTypeDefault;
+	self.bText.autoresizesSubviews = YES;
+	self.bText.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
+	self.bText.borderStyle = UITextBorderStyleRoundedRect;
+	self.bText.clearButtonMode = UITextFieldViewModeWhileEditing;
+	self.bText.clearsOnBeginEditing = NO;
+	self.bText.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
+	self.bText.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	self.bText.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
+	self.bText.enablesReturnKeyAutomatically = NO;
+	self.bText.frame = CGRectMake(193.0, 81.0, 107.0, 31.0);
+	self.bText.keyboardAppearance = UIKeyboardAppearanceDefault;
+	self.bText.keyboardType = UIKeyboardTypeNumberPad;
+	self.bText.placeholder = @"Integer";
+	self.bText.returnKeyType = UIReturnKeyDefault;
+	self.bText.tag = 9;
+	self.bText.text = @"";
+	self.bText.textAlignment = UITextAlignmentCenter;
+
+	self.view.frame = CGRectMake(0.0, 20.0, 320.0, 460.0);
+	self.view.autoresizesSubviews = YES;
+	self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+	self.view.backgroundColor = [UIColor colorWithWhite:1.000 alpha:1.000];
+	self.view.contentStretch = CGRectFromString(@"{{0, 0}, {1, 1}}");
+	self.view.frame = CGRectMake(0.0, 20.0, 320.0, 460.0);
+	self.view.tag = 0;
+
+	[self.view addSubview:background_button];
+	[self.view addSubview:label4];
+	[self.view addSubview:label7];
+	[self.view addSubview:label8];
+	[self.view addSubview:self.calculateButton];
+	[self.view addSubview:label11];
+	[self.view addSubview:self.resultLabel];
+	[self.view addSubview:self.aText];
+	[self.view addSubview:self.bText];
+}
+
+@end
diff --git a/examples/cross_calculator/ios/src/cross-calculator-Prefix.pch b/examples/cross_calculator/ios/src/cross-calculator-Prefix.pch
new file mode 100644
index 000000000..2f331ed43
--- /dev/null
+++ b/examples/cross_calculator/ios/src/cross-calculator-Prefix.pch
@@ -0,0 +1,10 @@
+#import <Availability.h>
+
+#ifndef __IPHONE_3_0
+#warning "This project uses features only available in iOS SDK 3.0 and later."
+#endif
+
+#ifdef __OBJC__
+	#import <UIKit/UIKit.h>
+	#import <Foundation/Foundation.h>
+#endif
diff --git a/examples/cross_calculator/ios/src/main.m b/examples/cross_calculator/ios/src/main.m
new file mode 100644
index 000000000..7866684fe
--- /dev/null
+++ b/examples/cross_calculator/ios/src/main.m
@@ -0,0 +1,13 @@
+#import <UIKit/UIKit.h>
+
+#import "AppDelegate.h"
+#import "backend.h"
+
+int main(int argc, char *argv[])
+{
+	@autoreleasepool {
+		NimMain();
+		return UIApplicationMain(argc, argv, nil,
+			NSStringFromClass([AppDelegate class]));
+	}
+}
diff --git a/examples/cross_calculator/lazarus/nimlaz.lpi b/examples/cross_calculator/lazarus/nimlaz.lpi
new file mode 100644
index 000000000..3b9abd129
--- /dev/null
+++ b/examples/cross_calculator/lazarus/nimlaz.lpi
@@ -0,0 +1,140 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="7"/>
+    <General>
+      <Flags>
+        <LRSInOutputDirectory Value="False"/>
+      </Flags>
+      <MainUnit Value="0"/>
+      <TargetFileExt Value=".exe"/>
+      <UseXPManifest Value="True"/>
+      <ActiveEditorIndexAtStart Value="1"/>
+    </General>
+    <VersionInfo>
+      <ProjectVersion Value=""/>
+      <Language Value=""/>
+      <CharSet Value=""/>
+    </VersionInfo>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IgnoreBinaries Value="False"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <RequiredPackages Count="1">
+      <Item1>
+        <PackageName Value="LCL"/>
+      </Item1>
+    </RequiredPackages>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="nimlaz.lpr"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="nimlaz"/>
+        <CursorPos X="17" Y="21"/>
+        <TopLine Value="1"/>
+        <EditorIndex Value="1"/>
+        <UsageCount Value="21"/>
+        <Loaded Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="unit1.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="Form1"/>
+        <ResourceBaseClass Value="Form"/>
+        <UnitName Value="Unit1"/>
+        <CursorPos X="26" Y="27"/>
+        <TopLine Value="2"/>
+        <EditorIndex Value="0"/>
+        <UsageCount Value="21"/>
+        <Loaded Value="True"/>
+      </Unit1>
+    </Units>
+    <JumpHistory Count="12" HistoryIndex="11">
+      <Position1>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="27" Column="1" TopLine="1"/>
+      </Position1>
+      <Position2>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="15" Column="3" TopLine="1"/>
+      </Position2>
+      <Position3>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="17" Column="26" TopLine="1"/>
+      </Position3>
+      <Position4>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="16" Column="18" TopLine="1"/>
+      </Position4>
+      <Position5>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="20" Column="43" TopLine="2"/>
+      </Position5>
+      <Position6>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="21" Column="48" TopLine="16"/>
+      </Position6>
+      <Position7>
+        <Filename Value="nimlaz.lpr"/>
+        <Caret Line="1" Column="1" TopLine="1"/>
+      </Position7>
+      <Position8>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="52" Column="17" TopLine="9"/>
+      </Position8>
+      <Position9>
+        <Filename Value="unit1.pas"/>
+        <Caret Line="51" Column="12" TopLine="9"/>
+      </Position9>
+      <Position10>
+        <Filename Value="nimlaz.lpr"/>
+        <Caret Line="21" Column="3" TopLine="1"/>
+      </Position10>
+      <Position11>
+        <Filename Value="nimlaz.lpr"/>
+        <Caret Line="20" Column="1" TopLine="1"/>
+      </Position11>
+      <Position12>
+        <Filename Value="nimlaz.lpr"/>
+        <Caret Line="21" Column="7" TopLine="1"/>
+      </Position12>
+    </JumpHistory>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="8"/>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)/"/>
+    </SearchPaths>
+    <Linking>
+      <Options>
+        <Win32>
+          <GraphicApplication Value="True"/>
+        </Win32>
+      </Options>
+    </Linking>
+    <Other>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>
diff --git a/examples/cross_calculator/lazarus/nimlaz.lpr b/examples/cross_calculator/lazarus/nimlaz.lpr
new file mode 100644
index 000000000..4457209d1
--- /dev/null
+++ b/examples/cross_calculator/lazarus/nimlaz.lpr
@@ -0,0 +1,21 @@
+program nimlaz;

+

+{$mode objfpc}{$H+}

+

+uses

+  {$IFDEF UNIX}{$IFDEF UseCThreads}

+  cthreads,

+  {$ENDIF}{$ENDIF}

+  Interfaces, // this includes the LCL widgetset

+  Forms

+  { you can add units after this }, Unit1, LResources;

+

+{$IFDEF WINDOWS}{$R nimlaz.rc}{$ENDIF}

+

+begin

+  {$I nimlaz.lrs}

+  Application.Initialize;

+  Application.CreateForm(TForm1, Form1);

+  Application.Run;

+end.

+

diff --git a/examples/cross_calculator/lazarus/nimlaz.lrs b/examples/cross_calculator/lazarus/nimlaz.lrs
new file mode 100644
index 000000000..234df82bd
--- /dev/null
+++ b/examples/cross_calculator/lazarus/nimlaz.lrs
@@ -0,0 +1,5222 @@
+LazarusResources.Add('MAINICON','ICO',[

+  #0#0#1#0#6#0#0#0#0#0#1#0' '#0#226#145#0#0'f'#0#0#0#128#128#0#0#1#0' '#0'('#8#1

+  +#0'H'#146#0#0'@@'#0#0#1#0' '#0'(B'#0#0'p'#154#1#0'00'#0#0#1#0' '#0#168'%'#0#0

+  +#152#220#1#0'  '#0#0#1#0' '#0#168#16#0#0'@'#2#2#0#16#16#0#0#1#0' '#0'h'#4#0#0

+  +#232#18#2#0#137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#1#0#0#0#1#0#8#6#0#0#0'\r'

+  +#168'f'#0#0#145#169'IDATx'#218#236']'#5#128#28#245#213''#235'n'#231'w9I.N'

+  +#136#144#4#139#17#220'['#220#221#138';!'#184'|'#180#148#2#197'Kq'#13'R('#20

+  +'(V'#180#197#3#9'!'#144#144#16#187#156#219#202#173#251'~'#239#253'gfo'#246'r'

+  +'~'#187';{'#242#131#201#236#173#204#204#202#251#253#159'?'#25#140'a'#12'c'#24

+  +#181#144'I}'#1'c'#24#195#24#164#195#24#1#140'a'#12#163#24'c'#4'0'#134'1'#140

+  +'b'#140#17#192#24#198'0'#138'1F'#0'c'#24#195'('#198#24#1#140'"'#140#155'}2}'

+  +#223#6#220'L'#184#25'q'#11#227#230#161#173#225#167#21#17#169#175'o'#12#217

+  +#199#24#1#12'c'#160'@'#155'q7'#21#183'i'#184'M'#198#173#8'8'#225'N'#217'd2'

+  +#153'p'#155#132#191#167#239'<'#132#155''''#145'H0B'#224'7'#175#232'v'#7'n'

+  +#219'p'#219#128#219'F'#220'j'#145'4'#18'R'#6'c'#24#26#198#8' '#199#129'B.'

+  +#199#221'x'#224#132'|'#170#176#161'P'#211#223'%='#189'N'#214#195'7+'#235#230

+  +'+O@'#207'r'#156#232#249#161#0#146#197'&'#232'$'#132#228#134#196#224#145#250

+  +'s'#27'C'#255'0F'#0'9'#6#20'x'#18#234#189'q'#219#7#183'=P'#208'ie'#215#136

+  +#159'#'#22'nA'#160'e'#194#157#226#199'DO'#20'nwG'#12'b!O'#240'$R'#238#236

+  +#230'q'#209#157']I'#2#159#211#136#187#181#184'}'#198'o'#171#145#20'bR'#182

+  +'c'#216#17'c'#4' 1P'#224#11'p'#183#20'8'#161#223#27#5'u'#186#240'X'#167'L'

+  +#239'('#228't'#155#219#0#228#244#12#185#140'{'#158#140'{'#157#140#191'!'#235

+  +#250'|'#232'<'#166' '#196#130#252#146'ps'#27'pRM'#255#203#184#191#197#143#209

+  +#235#196#247'AbGb'#232'B'#10#29#248#248#255#160#147#16'~'#26'3'#31'r'#3'c'#4

+  +#144'e'#160#192'[p'#183#23#240#171'<'#10#229'L'#224#191#7#177#192#203'8)'#6

+  +#185'\'#158#20'h'#185#156#187'_.'#227#4#158#30#163#219#10'z'#142#188#203#227

+  +#252#30'D'#247#201#21#10#220'+AF{P@\'#22#135'D,'#134#194#26#131'8'#238#227

+  +#241#24'/'#216'qn'#31'O'#0#222#194#251#241#223'8@'#28#255#137#199#185#191#227

+  +#137#4#187#157#224#239'#'#2#136''''#186''''#134'nH'#193#129#247''#14'<! '#25

+  +#172#147#250'{'#25#173#24'#'#128','#0#133#158#28'p'#199#224'v'#26#10#227'b'

+  +#220'+'#232#254#174#2'/'#19#11#171#188'S'#176'i'#175'P'#200#153#192'''o'#227

+  +#166'R'#169'A'#173'1'#128'Z'#173#3#149'V'#15'J'#165#26#31'S'#226'cJ~'#143#130

+  +'.W'#224'm'#5'w'#155'i'#10#144#212#20'8'#1#5'v'#131#9'6'#9'q,'#202#136' '#22

+  +#231'H!'#22#141#178#219#177'H'#4'"'#17'?'#132#131#1#8#135'|'#16#9#7'!F'#143

+  +'#'#25#196'bqF'#10#220'>'#193#238#139#11'['#146'(R'#9#161#139#217'A&'#195#10

+  +#220#158'G2'#248'E'#234#239'k4a'#140#0'2'#4#20'z%'#238#246#7'N'#232''#143'{'

+  +#29#221'/'#172#230#226#21'^,'#240'$'#172'$'#224'J'#165#2#148#180'W)A'#163#214

+  +'3'#1#215#144#176'ku'#160#209#242'B'#175'V'#129#10#159#175'T'#202#217's'#233

+  +'u'#10#185'p'#172'.'#26#129#130'3'#21#184#251#216#149'p'#23#202'Vn'#224'Vo'

+  +#129#4#226#156#128#198'x'#1#142#197'8'#161#142'E'#19#16'E!'#143'D'#227#16'Eb'

+  +#8'!'#9#132#131'~n'#11's'#251#16'#'#135'0>/'#134#207#225'6'#129#16#24'A'#136

+  +#8#129#206#215'U;'#192#251#215#224#238#5#220'^B2h'#150#250'{'#28#233#24'#'

+  +#128'4'#3#5'.'#238'N'#197#237'D'#20#190'b'#186'O,'#244#130#170#174#144#209

+  +'*.c'#2#175#228#133'^'#173'T'#162'P'#171'Ao'#178#130'^o'#3#157#209#10'Z'#29

+  +#10#187'J'#129#171'=nL'#208#233#182#156#221'V)'#21#201'=#'#11'%G'#0'D$r9g'

+  +#247#211#185#146'&'#3#179#8'd)'#206'AnE'#134#20'5'#30'e'#149#187#29#231'6"'

+  +#128'h'#156#132'9'#158'$'#128'H'#132#246'1'#238#182'h'#31#198'}8'#24#130#128

+  +#175#3#252'^'''#248'}N'#8#5'}'#236'1'#129#16#162#177#174#132#16'g'#218#1#153

+  +#24#220'5'#177']'#12#175#225'c'#224#200#224'M$'#3#191#212#223#237'H'#196#24#1

+  +#164#1'('#244#21#184';'#25#183'SQ'#184'v'#162#251#186#21'z~'#133#231'Vv'#18

+  +'^'#20'x'#149#10#244'('#232'z'#163#13#12#6#220#27#204#184#226#227#170#175'Q'

+  +#130'V'#173'`'#194'O'#171'U'#188#192#171':'#133'^'#197#142#195#173#254't'#31

+  +'g&p'#171''#210#148#160#235#224#29#132#130#250#159#18#9#224#205#0#178#245

+  +#133#21#153#217#251#252#223'$'#155'$'#160#209'8'#183#250'w'#146#0#10'2'#145#0

+  +#222#14'G8'#2#160'=m'#161'H'#20#205#132#24#4#195#220#237'@ '#0'~'#143#139#145

+  +#1#145'B'#136#204#8#188#159'#'#131#24'gJ'#224'qbq'#193#223#176#131#153#224'E'

+  +'2'#248'''pd@>'#131#184#212#223#249'H'#193#24#1#12#1'('#248#243'pw='#10#219

+  +#17#192'-'#174#12'rN'#210'8'#149'\&O'#170#244'*'#21#9#178#146#9#188#193'd'

+  +#195'}'#30'nf'#208'jT'#160#19#132#30'7'#29#19'~%G'#4'<'#9#168#149#220#202'O'

+  +#171'<'#169#253#10#165#12#148'ra'#213#167's'#164#10'>]'#2'wA'#188#192#11#209

+  +#129'D*'#1'$U'#239#164'g'#159#255#139#183#215#227#188'3P'#16#206'(o'#14#16#9

+  +#196#4'2Hj'#5#164#1#160#208#147#224#135#163'l'#31#8'E!('#222'P'#240#253'>'#31

+  +#4#188'.'#240'!'#25#248'<'#14'4'#27#130#248#218'(#'#5'F'#4#140#12'x"'#232#226

+  +'3'#192#191')'#25#233'/'#184'='#131'D'#16#146#250'70'#220'1F'#0#131#0#10#254

+  +'"'#220#221#128#194'v'#16#253#157'\'#237'y'#207'<S'#195#153#208'+'#217'J'#205

+  ,#132#30'Wv'#163#181#24#204#184#233#13':'#20'x'#21'h'#181'x'#191'H'#232'5'#188

+  +#224#179#219'$'#252'*A'#221'W$Wx'#177#176#11#231'JQ'#239#229'"'#129#23#9'{JN'

+  +#128#232#189'$xg '#187#157#232'b'#143#11#130#199#251#8#4'3!'#198#251#10#216

+  +'>'#198#147'BLl'#30#136#136#0#133'>'#16'N%'#1#250';'#16#196'-'#20#129'` '#2

+  +#30#183#3'<'#174'f'#240'x'#218'Q;'#8'32 '#13'C'#236'd'#20'L'#4#17#17#144#227

+  +#240'^'#220#30'C"'#240'I'#253#155#24#174#24'#'#128#1#0#5#159#156'z7'#162'0-'

+  +#161#191#185#24'<-'#181#220'j'#159'j'#203#163'0'#235't`'#182#20#131#201'V'#2

+  +'F'#147#25#244'Z'#21#24'p'#163#189'^G'#130#174'b'#194#175#21'V|'#141#130#9'='

+  +#17#6#19#252#164#131#143#183#229#153#195#16'D6='''#224#178#174#241#254'.'#215

+  +'-'#147#13#236'k'#22''''#1#137's'#4#128#251#159'#'#2#193'THtF'#16#146#132'@'

+  +#26'B$'#158'4'#11'B'#145'N'#141' '#200#147'A '#24#1'?'#146#128#31'I'#192#239

+  +#167#219#184#5#130#224'v'#181#129#219#217#194'i'#6','#242#16'c'#14#199#164

+  +#137#16#139#167'h'#5'x'#187#29'/'#233'~'#220#30'F"'#232#144#250'72'#220'0F'#0

+  +'}'#128'/'#160#249#29'p+'#254#174't'#31#23'^'#239#12#209'1!Ur'#234#189'V'#171

+  +#1#147#165#136#173#244'&K'#30'/'#236'j0'#232'T'#201'M'#199#147#128'V'#195#169

+  +#248#156#208'+83A'#201#31'O.'#178#231'{'#17'v'#254'&'#183#239'A'#208#7'"'#255

+  +'='#165#254'v%'#133'D'#167#154#176#3')p^'#255#4#243#27#196'D'#142'C'#210#10

+  +#194#188'_'#128#153#7'A'#142#8'|'#129'0n'#17#182#249'i'#143'Z'#128#23#205#4

+  +#15#18#1#145#129#223#239#193#215'E'#153'f'#192#162#11#188#19#177#139#175#128

+  +#146#141#30#193#253'}H'#4#237'R'#255'n'#134#11#198#8#160#7#240'9'#248#199#1

+  +'g'#227'S'#178#206#14#130#175#18#236'z\'#189#13'&+X'#243#199#161#224#23#162

+  +#144#235'P'#232'U`'#228#5#158#8#192#168#231#132'^'''#8'>'#9#189'Z'#145't'#230

+  +'q'#26#132'8'#254'/J'#254#17'.'#170#15'u>['#232#202#17']'#201#128#249#14#4#13

+  +'A'#228'?`'#209#4'2'#17'b'#228','#140'32 '#159#0#167#13#136#8#0'5'#2'/'#146

+  +#130#159#255#219#227'qA'#135#179#25':'#28#141'hR'#132'92Hj'#5';'#16#129#31

+  +#207#255#24#238#239'A"h'#148#224#227#25'V'#24'#'#128'n'#128#194#191#27#238#30

+  +'EA'#163#144'^'#138#224'+yU_'#141'6'#188#6'7'#163'9'#15'l'#133#149'`'#177#230

+  +#163#176#227'J'#143#130'n'#212#171#217'mN'#232#213'('#244'h'#235'k95_'#205'<'

+  +#250#188#7'_'#217#25#183#239'N'#173'g'#231#22'.j8|S]'#202#7'RR'#135'E'#230'B'

+  +','#193#231#20#240#161'Cf"'#136'|'#3'$'#244'^A+'#240#163'6 '#236'}~p'#180#213

+  +'!'#17'4'#224#243#130#140#8':#'#9#169'D'#128#231#14#224'%'#220#137#219'_'#198

+  +#156#133'=c8'#252#172#178#6#20#252'<'#220#221#137#194'w.'#240'2'#152'"'#248

+  +#188#154#175'A'#219#221'd)`'#130'oE5'#223'hP3'#161'7'#25'4L'#232#13#188#202

+  +#159#180#241#153#224#139#156'y'#188'z/'#8#190'8?'#165#208'g'#128#182'{'#174

+  +#161''''#167'b2'#225#136'O2'#226#180#2'!'#140'H>'#130'X'#167#143#0#137#192'C'

+  +#194#207#8' '#12'n'#220'{'#188'~p'#182#215#131#203'^'#15'A'#144#249#10'z!'#2

+  +#170'X'#188#24'I'#224'?R'#30#185#136#225#253#11'K'#19'x;'#255','#220#238'B'

+  +#161#203#23#156'{2'#133#160#234's+'#183#22'W|'#147#181#8#242#138'+'#193'l'

+  +#182#129#137#9'='''#248'&#'#238'Q'#240'uL'#229'W'#177#24#190#134'9'#243'RU|q'

+  +'r'#14#8#222'z'#254':d#'#248#235#216#161'z0'#25'f'#228'3'#17#197'&'#2'i'#5'Q'

+  +'^+ '#18#8'F'#152#22#224#245#133#192'C$'#224'#R'#8#129#215#27#0#167#189#1#156

+  +#168#21'P'#174'A('#140'D@9'#9'T'#215#192';'#11#227#157#213#141#175#225#238#10

+  +'$'#130#6#169'?'#139'\'#194#200#253#197#245#19'('#252#187#224#238'o('#152'{'

+  +#136#195'y,'#227#142'6'#18'|T'#227'-'#214#18#176#21'U'#160#224'['#153#208#155

+  +'I'#232'y'#225'g'#26#128#150#19'|q'#248'N'#156#158'+'#8'>'#147#249#212'z'#222

+  +#209#9'Q'#232'1'#233'7'#224#137#128#204#132#8#159'tDQ'#0#166#17#132#200'9'

+  +#136#155#143#211#8#220'H'#6'D'#4#28')'#4#145#8#26#145#8'j'#193#239#247'!qt'

+  +#18#1#167'm'#196#5'm'#128#26#156#220#138#219#3'H'#4'Q'#169'?'#130'\'#192'h'

+  +#253#249#9'Uyw'#160'0^'#128'{'#133#160#238#179'"'#27#222#185'G'#9':'#228#205

+  +'/('#169'F'#193'71a'#239'I'#240#5#199#30'K'#203'U'#202'S'#236'zN'#232#187#177

+  +#235#199#176'C'#30'BB'#172#25#176#236'CN+'#8'G'#163#157'D'#192#251#4'8m'#128

+  +'#'#2#143'@'#4'm'#13#224'h'#169'A'#205'!'#192#136' '#194#155#6']'#204#2'*8'

+  +#186#16'I'#224#11#169#223#191#212#24#149#191'E'#20#254'Spw'#15#229#234'''Km'

+  +#21'|J-+'#190'A;'#222'hB'#193#159#4#182#252'"&'#244'f#'''#252'f^'#240#13#188

+  +'W_'#219'e'#197'O&'#231#240'R'#223#25#162#147#250']'#231'>D'#193#4'n/'#242#21

+  +'$S'#144'{'#210#8#188'!'#232' '#18#160'}'#135#23#218#155#183#130#203#217#4

+  +#193'`'#152#249#21#136#8#226#172#246' %'#153#232'y'#220']'#141'D'#208'&'#245

+  +'{'#151#10#163#234'g'#137#130'O'#141'0'#31'G'#193'?'#145#254#22'Vh'#5#191#234

+  +#171'U*'#180#225'5'#204#185'WP2'#30','#6#29'XL'#26#176#24'9'#2#160'U'#159#9

+  +#190'F'#136#225'+9'#167#30#139#219#11'y'#255'\'#213']'#231'''<'#170'>'#226

+  +#244'A'#228'@L@gM'#2#249#9'"'#2#17#136#162#6#130'Y'#208#225#9'22'#160#205#225

+  +'h'#135#246#166'MH'#10#29#156'6'#192#242#8#226#156''#160'S'#27#160'P'#225

+  +#137'H'#2#255#147#250'-K'#129'Q'#243#235'D'#225#159#141#187''#160#144'N'#17

+  +'V}'#5#159'i'#199#169#251'h'#215'['#11#160#176't2'#218#251'f&'#244'V'#163#22

+  ,#204'D'#0#6'-S'#251'){'#143#4#159#203#244#227#146'u'#196'e'#183'];'#248#140

+  +'a'#232#16#151#11#11#230'A,'#193#167#30'G'#184#228'"'#230','#196#205#195#155

+  +#5#29#222' '#18'A'#136#237#221'H'#8#237#173#181#224'l'#217#14#254'`'#16'B'

+  +#225'0'#159'f'#28'Oj'#24#192'U'#30#222#130#251';G['#161#209#168#248#165#162

+  +#240#159#135#187#7'PH'#181'2'#190#6'_H'#217#165#144#158#222'`'#196#21'"'#228

+  +#229#151#178#149#158'V}+['#249'9'#193'7'#232#213'l'#213#167#172'='#242#234's'

+  +#9';\'#201#173'Pp'#195'>'#204'Q'#241'iJ'#131#206'DDn'#229'N'#166#31#147'F'#16

+  +#229#170#16')'#143#128#210#138#189#188'I'#224#18#17'A'#135#219#11'mM'#155#161

+  +#195#209#130'&'#4#146#0'%'#19#9#209#130'Nm'#224'#<'#193')H'#2#173'R'#191#223

+  +'laD'#255'd'#249'N<'#143#137'U~'#193#214#167'D'#30#29#174#250'yE'#168#238#23

+  +'O'#0#179'Y'#199#4'>'#185#242#27'9[_H'#217'e'#169#186#138#212#226#155#222#26

+  +'m'#142'!3'#224#139#21#147#14#195'd>A'#148'K7'#230'2'#11'9"'#224#28#132'H'#4

+  +'n$'#0#242#13#144'Y`o'#133#246#230'M'#224#243'x:'#181#129'h\'#28')h'#194'3'

+  +#156#140'$'#240#153#212#239'5'#27#24#177'?]^'#229''#141#186#234#138'='#252

+  +#172#180'VEN>#'#148#148#239#4'V[>'#191#226'k'#25#1#144#202'O'#241'}'#178#245

+  +'uj~'#213#23'j'#237'E^}'#246#225#141#216'O/'#247#145'$'#2#232#236'AH)'#199'Q'

+  +#190#0#137#10#142#168#208#200#231#227#136#128#132#223#229#9'2'#31'A'#135''''

+  +#0#173#13#191#177#208'a'#144'O-'#142'&C'#134#236#200#184'K'#220#142#251#255

+  +#27#233'&'#193#136#252#9#163#240#255#1'w'#247#139'U~'#174#147#14#197#244'U`'

+  +#177#21'Cq'#249'4'#176#153#13'('#252'Z&'#252#164#242's'#153'|\'#234'.'#173

+  +#250'\5'#30#223'aG&'#235'6'#23''#12#210'"'#145'd'#1#224#27#152#242'D'#16#137

+  +#179#162'#"'#2#31#239'$'#228#132'?'#4'N'#158#8#236'm'#13#208#214#248#27'j'#11

+  +'A'#150'D$D'#10'D&'#193#167#192'i'#3'#'#182'5'#217#136#250'%'#243'*?y'#249'O'

+  +#160#191#197'*'#191'FM'#130#173#129#252#210'j(,'#169'bj'#190#213#162#5#155'I'

+  +#155#12#241#137#227#249'B'#18'Ogn>$k'#236#199#144'['#160#214#229#157#185#4

+  +#188'Y'#192#218#152'qY'#133#212#153'('#192#215#23'0'#223#0#145#128';'#128#166

+  +#1#238#157'Nh'#169'_'#15'^O'#7#231#27#216#209'$h'#1#206'/'#240#177#212#239'3'

+  +#19#24'1'#191'f'#20'~'#26#139#245#30#10#255#188#174'I=\\'#159'T'#254#25'`'

+  +#203#207'c+'#190#205#164#3#171'Y'#203#135#247#212#172'XGH'#221'e'#13'7'#146

+  +#234#190'h'#229#151#250'M'#142#161'G'#136'|'#132#220','#131'8'#223#201'('#193

+  +'7)'#9'sNB'#210#6#220#188'9@'#190#1#167#155#246#254#164'I'#16#224#27#146'DY'

+  +#155#244'$'#9'P'#214#224#217'H'#2#207'K'#253'>'#211#141#17#241#155'F'#225#159

+  +#128#187#255#160#240'O'#18#132#159'b'#243#228#229'gi'#188#182'"T'#249#167#163

+  +#192#163#202#143'B'#159#135#155#133'_'#249#141'|}'#190#154'o'#192'A'#141':'

+  +#229'2Q'#231#220#17#241#9#141'B'#240#13'L'#200#128#23'Z'#153#9#185#3'T['#224

+  +#241#134#185'('#1'j'#1#14#212#6#220#168#21#180#183#212'C['#243'&'#214#152#132

+  +#202#142#133#156#1#222'/'#128'<'#144'X'#134'$p'#143#212'o-'#157#24#246'?o'

+  +#222#217#247#1#10''#137#216#222#167#226#29#157'V'#203#210'x'#11'H'#229''';'

+  +#223#204#169#252't'#155'e'#243#233':='#252#201#10'='#161':O'#234'76'#134#161

+  +'#'#193#165#26#11'-'#200#163#188#147#144#186#19#177#188#1'_8'#169#13'8'#153

+  +'F'#16'@'#147#160#3'Z'#234#214'1'#147#128#146#135'('#5'YD'#2't'#172#187'qw'

+  +#237'H'#153'l4'#172''#231'('#252'4a'#231'-'#20'~'#139' '#252','#163#143'T~'

+  +#131#1#138'+f@^^A'#167#224#155#185'0'#31#9'?+'#213#229#227#250'B'#231#29#232

+  +'R'#142';'#134#145#1'q'#163#211'd'#164' '#202#165#19#11#225'Br'#14':'#220#28

+  +#9#208#214'Z'#191#1'\'#246'&'#212#24#194','#170#16''''#191#0'$M'#130#231#240

+  +#128#231#140#132#130#162'a'#251'sG'#225'?'#10'w/'#161#240'k'#132#240#28#169

+  +#252'j'#170#213'7'#153#160#164'r6'#216'lff'#235#219#204#218#164#189'/'#180

+  +#228'R'#243#173#183#200#209''''#212#225#143#9#255#200#133#144'H'#148'lJ'#130

+  +'&A'#24#237#252#16'_n'#204#162#4'nN'#27' '#147#128#162#4'-'#13#155#192#209'Z'

+  +#203#234#9'('#162' '#174'%@'#18#248'7'#30#238'8$'#129#128#212#239'm('#24#150

+  +'?y>'#204'G%'#188'r'#193#211'/8'#251#168#15'_i'#213'L'#176'YM'#144'G'#206'>'

+  +#139'.'#25#226#211#179'&'#29#202'd'#223'='#161'D'#151#251' '#134#229'G1'#134

+  +#1'B<'#216'Th^J+'#188'@'#2'd'#18#144'c'#208#217#17'`'#251#182#230#237#208#214

+  +#180#9#130#129'03'#7#186'D'#8#190#194'C'#30#142'$'#224#148#250'}'#13#22#195

+  +#238'W'#143#194'3'#10#238'mt['#16'~5_'#193'g'#177#22'@i'#229'L'#176'Z'#245

+  +'L'#240#137#0#200#233#199#132#159'o'#201'%'#30#160#193'>'#128#177'e'#212'A<'

+  +#2']'#156'<D~'#1#175#136#4#28#29#1#22')hk'#173'G'#147'`#'#4#130'!|^'#164'+'#9

+  +'Pi'#241'A'#195#181#209#200#176#250#245#163#240#255#5#5#246#26#186#205#166

+  +#226'*'#185#250'{*'#228#177#229#149'@Q'#229'N'#144'g&'#149'_'#199'b'#252'V'

+  +#163'P'#196#163#226'b'#251#226':}'#217#152#240#143'f'#8'$'#16#231'{'#21#198

+  +#248#150'd'#20'%`$'#224#225'5'#1#182#5#160#189#189#5'Z'#235#214#131#207#31

+  +#224#194#132#148'4'#212'I'#2'5x'#168'E'#195#145#4#134#141#4#160#240'_'#5'\'

+  +#13'R'#248#201'{'#207#132#191#160#2#138#203#167#160#170#143#171#190'E'#155

+  +#20'~'#202#234'#'#225#23#242#248#147'^~'#24#157#246#190#215#235#134#143#222

+  ,''#19#190#253#234#19#216'^'#179#25#206'8'#247'J8'#232#208'c'#164#190',I'#209

+  +#217#180#148#139#18'DDEEIs'#192#205#153#3'v'#135#29'Zj'#6#159#207#151'lH'

+  +#218'E'#19'X2'#220#204#129'a!'#6'|'#3#143#231'ed'#244'w'#17#254#252#226'j(*'

+  +#171'f'#161#189'<f'#239'kYn'#191#144#210'+.'#226#1#217#232#246#242#31#184'x'

+  +#10#174't'#169#142#235'Ysv'#131'?'#223#255'<'#168#213'j'#169'/O2p='#10';['

+  +#146'Q'#203'r'#150'/ J'#26'b&'#1#31'&l'#222#190#150#145'i7$@>'#129#253#135

+  +#147'c0'#231#197#1#133#159#198'o'#189#141#178#175#18#219#252':'#173#26#10#203

+  +#166'@Aq%'#243#240''''#133#159'<'#253'$'#252#201#10'>'#174'tW6'#22#219#135

+  +#223#29'0'#11#2#254#29#167'hi'#181':'#184#231#161#151'`'#234#244'YR_'#162'd'

+  +#224'9 '#233#23#136'D'#184#209'f'#228#28'd'#21#133#148''''#208#17'd'#161'B'

+  +#167#203#141'$'#240#19'x<'#29#221#145#192';x'#168'#'#145#4'bR'#191#167#254' '

+  +#167'e'#130#239#207#255')'#10#191'A,'#252#180#242#23#148'N'#130#162#210#241

+  +'I'#225#23'r'#250#5#225#231'Fi'#203'E='#249'r'#250#173'f'#5''''#31#181#16#218

+  +#219#186#175'kQ('#148'p'#239'#'#175#192#244#25#187'H}'#153#146'AhP'#10#2#9'D'

+  +#185#225'%b'#18'pv'#8#155#27#154'j'#214#128#215#227'fm'#201#187'8'#6#159'F'#2

+  +'8['#234#247#211#31#228#172'T'#160#240'O'#193#221'W('#184#5'B'#146#143' '#252

+  +#249'EU'#156#205#207#132#159#203#235'gi'#189'z.'#179#143#28#131#138#148#148

+  +'^'#24#157'F'#23','#191#252#20#248'i'#245#183'=>N$p'#215#131'/'#194#140#153

+  +#243#165#190'T'#233#144#28'f'#2#201#129#167'D'#2#212''#144#230#18#8'$@'#230

+  +#128#195#233'B'#18#248#17'|>2:'#192'&'#21'q'#14#198'?#'#9'\'''#245#219#233

+  +#11'9)'#21'('#252#165#184#251#26#133''#188'8'#195#143'9'#252#10#199'AI'#197

+  +'N,'#185''''#143#247#246#179#236'>'#157#154#13#215'd'#194'/j'#211#149#179'oR'

+  +#2#216#219'Z'#224#180#227#150#224#15#180#231#18'w'#185'B'#1'w'#222#251'<'#204

+  +#156#179#155#212#151'+'#9#196#195'P'#133#206'CD'#2'!VC'#16'e'#221#135#133'""'

+  +#202#21' '#199' i'#2#1#170#31#160#241#230#204#28'H'#8'$@s'#8#238#151#250'='

+  +#245#134#156#147#13#190']'#247#255'Pxg%'#133#31''#148#26#190#168#167#140#226

+  +#252#164#242'S'#156#223',R'#251#213'JP'#170#184'>}c!'#190#158'q'#255']'#215

+  +#194''''#31#190#217#235's'#228'r'#5#252#249#129#21'h'#14#204#149#250'r%'#133

+  +#16'*'#20'r'#5'h'#132#25#149#21#139#205#1#210#4#236#237#173#208#178#253'g'#8

+  +#132#130#140'('#132#218#129#4'7R'#249#148#134#159'^zI'#234#247#210#19'rJJP'

+  +#248#201#21#253#17#141#223#22#170#250#148'|'#134#159#217#146#7'%'#19'fC'#158

+  +#201#0'6'#171#150#197#250#217#202#143#194#175#213'(S'#187#246#228#212#187#202

+  +'-'#196#227'Q8'#254#176'y'#16#194#31'ko'#208'hu'#240#220'k_'#130'^o'#148#250

+  +#146'%'#133#216'1('#152#3#204''''#224#237'L'#27'&'#231' '#151','#180#129#235

+  +'0'#20'I!'#129#8#30#225'0$'#129#156#28'M'#150'S'#162#130#4#240#16#10#255#197

+  +#226#146'^'#141#138'r'#251'-P:a'#23'\'#249#141'l'#213'g'#194'o'#226'V~-'#133

+  +#250'D'#243#246'r'#234#13#229'('#222#254#231#179#240#244#223#255#220#231#243

+  +#202'+'#171#225#225#167#222#147#250'r%Grr'#17#175#9#4#187#144#128#144''''#208

+  +#218'T'#3#246#166#205#157'$'#208#217'O'#192#145'H'#196'vi\'#251'J'#173#212

+  +#239#165'+rF^'#248#226#158''#138#19'}'#168'A'#7'5'#242'('#173#154#11'y63W'

+  +#213#199#215#242#147#195#143'*'#250#132#129#28#178#177#149'@8'#251#132'%'

+  +#224't'#244'='#15'c'#191#131#143#133#11#175#184']'#234#203#149#28'B1'#17'9'

+  +#249'"|'#187'1.O '#204'J'#137#137#4':P'#19'hi'#220#4#246#214#237#16#162#198

+  +'"'#169'ME'#190#142#4#28'K[{?"'#245'{'#17'#''D'#134'o'#232#241'#'#149#245#10

+  +#225'>'#18'~'#157'^'#15#165#227'w'#1#155#205#154't'#248'Y'#153#218#175#225

+  +#235#248';'#213'~!'#183''#12#253#195'/?}'#7#183',;'#163'_'#207#189#234#134

+  +#251'`'#193#146#131#164#190'd'#201#145#28'Y'#22#227#204#1#210#4'|B'#155#177

+  +'dw'#161' 4'#213#173#131#14#190#148'85<'#24#191#27'M'#129'k!e'#144#186#180

+  +#144'\jx'#187#255'K'#20#254']'#187#134#251#138'+w'#134#130#130#210'd'#172#191

+  +#179'}'#151#138#235#207#207#183#232#22#6'}'#140'a`8'#239#228#165#168#5#244

+  +#221#2#159#194#131#15'='#253#1#20#22#149'I}'#201#146#131'K'#27#230'5'#1#190

+  +#185#8'M.'#166#218#1#18'~'#135''''#192'Z'#140'5m'#253#17'<ng'#215#200'@'#130

+  +#247#7#188#15'9B'#2#146'K'#13#18#192'}('#252#151#167'8'#253'P'#181'O'#198#250

+  +'M'#156#205'/.'#233'U'#11's'#248'd|'#168'O'#226'wq'#238#137#139'Y'#7#25'6/@'

+  +#174#128'3'#254#176#28'U'#231#227#164#254'h'#251#196'#'#247'\'#7#255#251#244

+  +#237'~='#215'j+'#128'G_'#248#140#17#244#168'G'#2'R'#134#146'P'#218#176#143'u'

+  +#29#230':'#14'S'#21#161#147'r'#4#182#173'b'#237#197#186'8'#5#219#19#241#216

+  +'.'#141'?'#191'R/'#245#219' H*:('#252#191#199#221#191'R'#236'~'#230#241#183

+  +'A'#217#248#185#184#242's'#225'>'#202#242'3'#25#185#149#159#230#241'q'#133'='

+  +'\'#168'Oj'#6#251#237#215#31#225#230'kNM'#185#143'H'#224#222#199#222#134#210

+  +#210'*'#137#175#174'wl\'#183#26'n'#185#246#180'~?'#238#174'{'#193#178'['#30

+  +#145#250#178's'#2#180'|s-'#200#169#187#16#154#3'An"'#17#235','#212#17#20#149

+  +#17#175'Ov'#27#22#249#3#190#12'y['#246'n'#223#242#177#228#29#133'$'#147#31#20

+  +'~'#146#14#178#251'm'#226'4_='#218#253'e'#19#230#161#221'oa'#130#207'9'#253

+  ,'h'#229'W'#179#22'^\I'#175'<9r[j'#220'y'#243'y'#240#243#143#223#236'pqi'#5

+  +#220#247'xnz'#208#219'['#155#224#213#23#30#128'5?|'#1'>'#175'{@'#175'='#243

+  +#130#27'`'#255'CN'#144#250'-H'#14'![0'#193#135#7'I'#192'i"'#145#208'^'#140'5'

+  +#20'Am'#160#185#238'Wp'#182#215'C8'#196'u'#26'&'#194#224#15'pg'#253'O+n'#0

+  +#137'M'#1'ID'#8#133'_'#5'\'#178#207#30#226'L?'#157'F'#3'E'#21';'#163#250'_'

+  +#146'l'#229'%T'#246'Q3'#15#214#194'K)'#227#166#239#230#130#244'#'#206'8z.D#;'

+  +':v'#149'J'#21'<'#251#198'j'#169'//'#137'p8'#12#239#188#254#4#252#247#227'7'

+  +#193#209#222'2'#232#227#200#240#187':'#253#188#235'`'#191'1'#18'H'#166#13#11

+  +#227#203'Y'#162#144'P7'#144#236'%'#224'GS`5x'#221#174#29#252#1'h1'#30'R'#183

+  +'f'#197#135' !'#9'HE'#0'w'#161#240'/'#163#219#10#161#139#175'F'#9#249#133#227

+  +#161#168'|2o'#247'wv'#239'e'#225#190'd'''#159#220'q'#248#213'l^'#15'7]'#221

+  +#179' <'#241#202#183#160#213#234'%'#189#198'`'#208#15''#185#245#15#176'y'

+  +#227#207#189#166#0#15#20#147#167#205#134#229#183'?'#1'j'#181'V'#210#247'''5'

+  +#18#162'a'#165'\'#142#0'?{'#128'H'#128#138#134'<\'#205'@'#179#216#31#208'i'

+  +#10#180'i'#212#138#217'['#191''#190#25'$"'#129#172'K'#18#10#255#28#220#253

+  +#128#4#160#16#199#251#141'f'#206#238#183#176#6#158#188#221'o'#224'j'#250#233

+  +'q*'#238#145#201'd9'#21#239''#255'_'#207#193'+'#207#253#181#199#199#175#189

+  +#237'q'#216'i'#214#238#146']'#223#166#13'?'#193#221'('#252#161'Pf'#202#211

+  +#213#26'-\t'#245#221'0g'#254#18#201#222#163#212'H$'''#18#9#21#132#220'\'#194

+  +'dk1'#26'C'#198'g'#10#182'5n`'#13'F'#187#148#15#191#220#240#211#10#234'w'#193

+  +#15'8'#203'.'#178'*J('#252't'#190#175#197#170#191'`'#247#151#140'G'#187#223

+  +'jN'#246#239#167'Q]'#212#193'W'#173#22'M'#229#205#21#201#231#241#183'{'#151

+  +#193#247'_'#247#156#225'y'#197#13#15#195#172#185#139'$'#185#182#230#198#237

+  +'p'#253#165'G'#166'u'#213#239#9#187'.'#216#31'.'#188#234'nI'#222'g'#174'@('

+  +#30'bN'#193#8#231#15#160'Qd'#212'i'#216#201#166#19#147'?`='#184#218#27'v('#26

+  +#146#203#18#251#213#173'y'#137#166#17'g'#157#4#178'M'#0#231#2'7'#187#143#169

+  +#254#148#234#171'U'#171'Q'#237#223#9#237#254'q,'#212'G'#4'@'#19'z'#141#186'N'

+  +#187'_'#220#202'+'#151'p'#203'U'#199'A}'#237#166#30#31'?'#245#188#27'a'#233

+  +#254'GKrm'#203'/:'#12'W'#157#236#181#168'3'#154#173'p'#205#205#143'Cy'#213'd'

+  +'I'#222'o.@p'#10'F'#226#220'(2'#214'iX(!&'#18#240#248#161'q'#235#15#224#247

+  +'y'#216'0R'#145')'#176#161#208#28#223'e'#205#23'/'#135'`'#164#18#0#10''#1

+  +#238'6'#162#240#231#145',+'#168#194#15#5#220'l-'#130#210#170#217#220#136'nQ'

+  +#129#15#169#254#201#210#222#28#136#245'w'#135#171#207';'#0':\'#237'=>>{'#222

+  +#18#184#248#218#236'W'#131#174#250#246#19#248#251'_'#175#201#250'y'#169#148

+  +#248#162'k'#254#138'Z'#207#226#172#159';W@>'#129'x'#12#152#199#159':'#10#249

+  +#168#183#160#159's'#10#18#17#216#219'['#160#165'v-'#155':'#20#21'B'#131'@?'

+  +#239#196#245'{L'#14#255#229#181#215'^'#139'C'#22'I '#155#4#240'4'#10#255#153

+  +'B'#194#15'e'#242'i'#181#26'('#171#222#21'l'#22'+X-'#26#150#227'o'#210#11#241

+  +'~E'#206'W'#247']y'#206#190#224#245#184'z|'#220'`'#180#192'}O}'#154#245#235

+  +'z'#230'o'#183#192'7'#255#253#183'$'#159#9'iw'''#156#185#12#246'>0'#247#19

+  +#161'2'#1'nE'#231'z'#11'R'#166' '#181#26'gIB'#194'@R'#26'8R'#251#11#184#28'M'

+  +']K'#135'}'#10'Yd'#230'YG'#236#180#253#214'[o'#205#154')'#144#21#209'B'#225

+  +'_'#136#187'/'#196'M=)'#225''''#191'x'#2#20#150'M'#228#236'~'#190#159#31#27

+  +#209#205''''#251#200#20'|'#154'o'#142#142#228#190#242#156#165'L'#157#235#13

+  +#203'n'#22#170''''#207#204#234'u'#253#241#186#147#160#174'f'#163#148#31#13

+  +#236'{'#200#201'p'#236#169'WJz'#13'R!'#217'e'#152'2'#5'Q'#19#160#162'!'#174

+  +#155#16'_='#232'rC'#211#214#239'!'#16#12'tI'#16#138#191'5'#217#214'x'#204#231

+  +#159'.h'#1#25''''#129#140'K'#22#10#191#18'w'#171'Q'#246'g'#138#29''#6#163#9

+  +'W'#255#221'P'#232'u'#220#234'o'#20'B~'#156#221#175#148'Q?'#191#172'\'#226

+  +#160'q'#229'YKX'#152#173'7L'#156':'#27#174#186#229')v'#155#190#232#141#235

+  +#190#135'_~'#252#2'j6'#255#2#173'-u'#16#14#5#161#176#184#28'f'#238#178#24#150

+  +#236','#216#242#139#135'|]w\{<4'#214'm'#145#250#227#129'='#150#28#6#167#157

+  +''#171#212#151'!'#13'(*'#144#224#187#9#133'R'#203#135'iko'#222#14#237'M'#155

+  +' '#28#230'M'#1#222'!'#168#144#197#143#216'}r'#244#223#217'2'#5#178'A'#0#201

+  +'~'#254#130#227#143'V'#255#226#138'Y'#144'_X'#194#170#251#204#204#235#175'f3'

+  +#251'4'#194#164'^'#5#191#242#231#174#252#195#21'g.'#198'/0'#216#231#243'*''L'

+  +#135#246#214#6'^['#232#253';'#173#154'8'#3'.^'#246' '#232#141#230'A_'#215#223

+  +#239#189#18'~^'#253#133#212#31#15#195#137'g]'#7#139#246'=J'#234#203#200':'

+  +#196#249#1#194#172#1#242#7'P4'#192#229#14#129#27'I'#160'q'#219#15#204#132#236

+  +#146#27#176#173#196#26#155'S]'#20#243'e'#131#4'2*^('#252#229#184#251#21#133

+  +#223'(8'#254'h'#245'7'#219#138#161#164'r&'#179#249#201#243'o'#22#169#254#148

+  +#240#195#138'j'#134#193#140#238'+'#206'\'#4#209'H8'#237#199#165#234#187#227

+  +#207#188#22#246'\'#250#251'A'#189#254#173#151#31#130#143#223'}A'#234#143#135

+  +#129'4'#190#229'Z'#1#165#229#19#165#190#148#172'#9'#131#144'R'#133#249#209

+  ,'cn'#26'I'#206#180#128#16'8'#236'm'#208'R'#187#134#213#10#136#27#138#202'e'

+  +#137'?'#21')6'#222#186'j'#213'*j-'#158'QS '#211#4#240','#238'N'#231#194'x\'

+  +#165#159'N'#167#129#210#9#187#162#218'o'#6'3o'#247#155'x'#213'_'#165'Rt'#198

+  +#251's\'#248#9'W'#158#177'p'#135'A'#27#233#2'}'#6'W'#160#233'@'#26#193'@'#225

+  +#180#183#192#173#151#255'N'#234#143''''#9#157#222#8'w<'#244'>(G'#227#240#145

+  +#132#184#167' '#167#5#176#198#162#158#16#155'@'#220'Z'#255'+t8'#26#152'C0'#22

+  +#139#9#164#17#210'(";W'#154'[k>'#255#252's'#129#4'2'#130#140#137#25'_'#236

+  +#179#25''#200#202'd'#147#15'\'#225#243'J&Aa'#201#4'&'#248#22'>'#219#143#188

+  +#254'B'#194#143#208#214'K6'#28'4'#128'3'#22#160#234#150#185#249#15#148'F'#252

+  +#199'G>'#4#165'j'#224#130#243#199'k'#143#131#214#166#237'R~<)'#168#24'?'#13

+  +#174#190#253'9'#169'/#'#171'H'#206#31#20'G'#5#130'\'#150' E'#5#152'&'#224#246

+  +'A'#211#182#149#16#240#7#146#25#130'd6'#160#22#240#216#30#147'#'#151#226#203

+  +'c'#153'4'#5'2I'#0''#195#221#5#194#234'O'#171#187#222'`'#198#213'>'#174#252

+  +#186#164#234'O1'#13#175#250#11#173#188's5'#236#215#21'W"'#1'd:'#211'n'#206

+  +'n'#251#194#233#23#253'q'#192#175'['#245#205#135#240#226#223'o'#145#234#163

+  +#233#22'{'#29'x'#2#28'q'#210#229'R_FV'#145'L'#21'&_'#0#223'T4'#16#226#18#132

+  +'H'#3' "ho'#169#5'{'#211#198#174'a'#193#160'Y'#23#157#174#143'ln'#200#164')'

+  +#144#17'Q'#227#251#250'oCa'#214#8#171#191#150#194'~'#227'v'#130#130#194'q,'

+  +#233#135'R}'#169#198#159#10'}'#146#173#189#134'Y['#175#171#207'^'#136'_lf'#9

+  +'@'#173#209#193#157''#31'\.'#193'u'#231#239#3#225#12#213#1#12#22#231'^y'#31

+  +'L'#155#185#135#212#151#145'u'#136'G'#145'S'#130#16#171#21#224'K'#135'I'#19

+  +' -'#192#231#245'$'#147#131#226#156'/'#224#129#137#214#198#229#133#133#133

+  +#145'Li'#1#153'"'#128'{pw'#149#216#246'7'#24'q'#245#175#222#21'W}m'#146#0'('

+  +#215'_'#163'Q'#138'r'#253'3'#253'5'#164#23#203#206'Y'#196#190#172'L'#131#132

+  +'f'#234#206#3'/*'#250#199'3'#130#149'_H'#147#16#212#19#242#10'J'#225#250#191

+  +#252'S'#234#203#200':'#132#4'!'#161'V'#128#229#6#8#166'@W-'#128#250#8#178'(B'

+  +#194'k'#209#248#166#203'|'#155'Z'#143'='#246#216'h&'#18#132#210'.r('#252#249

+  +#184#219'.'#158#231'G*~~'#233'4(('#174'`'#182#191'9'#153#238#171'J'#233#231

+  +'?'#220#176#252#188#197#25#245#1#8#152#188#211#174'H'#2#15#12#248'u~'#159#27

+  +'n'#187#252#224#164'-'#154'+'#184#244#198#167#161'|'#252'4'#169'/#'#235'`i'

+  +#194#162#178'a'#214'U'#152#143#10'Px'#176'i'#203'w'#224#247#251#152#22' D'#4

+  +#20#178#248'_'#198#233'jn'#213'h4'#145'L8'#4'3A'#0#255#135#187#27#133#184'?'

+  +#173#254'z'#189#1#202'&'#238#193#4#159'<'#255#20#243#167#176#31#149#249#178

+  +'b'#31#190#189#207'p'#226#128#166#186#205'p'#255'm'#167'g'#229'\&K>'#220'xo'

+  +#255'z'#247'u'#197#227#247'\'#10'[6'#172#202#230'G'#211'''*'#171'w'#134#139

+  +#174'L'#234#203'H'#162'v'#235'z'#248#224#141#191#179'U'#248#202#219'^'#4'm'

+  +#6#134#161#236'P6LZ'#0's'#8#134'Xkq'#242#7#216'['#182#131#189'y'#19#203#11#16

+  +'E'#4':'#10#13#222#25#165#150'p'#187#209'h'#140#166#219#20'H'#171#200#161#240

+  +'S'#246#10#173#254#214'd'#193#15#10'y^'#233#20#200'/'#170'd'#4'`'#225'+'#253

+  +#132#213'_.'#204#241'K'#251'G'#158'Y<'#245#192#149#176'i'#221#202#172#156#139

+  +#138'l'#254#244#232''#7#245'Z'#183#171#13#238#188#246#168#156#210#2'hq'#184

+  +#225#158'w'#192'h'#178'Jz'#29'?'#175#250#12#222'z'#233#175#224#245'8'#147#247

+  +'Yl'#133'p'#237#157#175#225'oR'#153#246#243#9'#'#200#147#29#132#216#188#193#8

+  +'x<H'#0'>'#242#5'P'#181#224'w'#16#164#136'@'#172'S'#11'P'#202#227#255'7'#181

+  +#208'~'#151#221'n'#15#167#219'!'#152'n'#2#184#30'w'#20#175#254#172#183''

+  +#245#238#184#234#235'p'#245'Ws'#157'}'#249'b'#159'd'#216'o8-'#253#192#133'tn'

+  +#190'x'#31#136'g('#7#160';\'#247#151#183#152'&0'#24'<Cd'#181'>;d'#213'_'#204

+  +#156#191#15#156'x'#174#180#3'G'#222'|'#225'.'#248#254#203'wv'#184#191'x\5\v'

+  +#243#243#25'9'#167'0'#130'<'#22#19#194#130#145'd'#243#16#210#4#218#155#183

+  +#130#179'uk'#215'r'#225#246#170'<'#255',u'#194#233'L'#183'C0m'#146#135#194'O'

+  +#189#175'jP'#152#11#133#156'J'#249#205'+'#158#4#249#197#227'q'#245'Ws'#131

+  +'<uj~'#168#7#151#244#3#195'p'#144#231#23#31#190#4#31#190#249'hV'#207#249#251

+  +'S'#174#129']'#23#13'.'#185#199#231'q'#193#159#151#253'.'#167#180#0#202'v'

+  +#188#229#161#143'2'#178#210#246#23'_}'#252'*'#188#255#250#195#221'>6'#209

+  +#225'p'#196')'#203'2r^'#241#152'1'#234'#'#232#167#228' >*@Z@'#211#150'o!'#24

+  +#10'B4'#210'Y#'#160'R'#196'o'#24#167#171'}'#200#229'r'#133#210#233#16'L'''#1

+  +'\'#134#187#251#133#22#223'JV'#238#171#195#213''#15'0'#25#185')'#190#228#249

+  +#215#137'W'#255'af'#247#11#248#203'uG'#130#167#195#158#213's'#206#156#191'/'

+  +#28'w'#214#224#227#250#143#254#249'\h'#172#149#182'B'#176'+'#14':'#234'"X'

+  +#184#223#241#146#157''#235#198#213#168#29'u'#159#151' '#147#201#225#218#187

+  +#254#5#6'cf'#204#148#148#185#2'4v<'#16#6#143#151'#'#129#246#166#205#224'j'

+  +#171'I'#169#17#192''#154'&'#216#218#230'DC'#30'O:'#29#130#233'$'#128#159#196

+  +'#'#189')'#231#223'VT'#13#249'%'#213','#219#143'y'#254'u'#157#147'|'#5#219''

+  +#184#161#177#246'7x'#236#174's'#179'~'#222#130#226'J'#184#228#230#193#231#247

+  ,'?'#250#167#179#160#185'A'#250#10'A1'#170#167#205#131#211'/'#249#235#208#15

+  +'4H'#4#253'^'#184#243#154'C{|'#188'j'#210'l8'#235#138#7'3rn'#161'N'#128#204#0

+  +'J'#14#242#5#195#172'd'#152#204#0#183#199#11#205#219'V'#162#22#16'Ji'#29#166

+  +'SFO'#221'i\'#224'-$'#128#208#140#25'3'#210#162#5#164'E'#2#199#205':q'#14#200

+  +#228'?'#166#14#248'PC'#217#196'='#193'h'#212'%'#195'~]mv'#1#195'L'#5'x'#246

+  +#129#203#160'f'#211#154#172#159'W'#161'T'#193'M'#247'<'#232#215'?p'#203#9

+  +#224#180'7e'#253#186'{'#131#209#156#15'W'#255#233#13'I'#175#225#214'K'#150'v'

+  +#186#232#187#193'y'#203#158#128#178#202')i='#167'`'#138'u'#230#5#196'Y#Qj'#28

+  +'Bu'#2#20#26'lk'#218#8#238#246':'#22'-'#16#210#131#21#242#196#191''''#231#181

+  +#156#145#151#151#231'okkK'#139#22#144#30#2#152'}'#242#189#184#187'R'#156#248

+  +'c'#206'+'#133#162#242#25'l'#245#167#141'l'#255#174#5'?'#195'L'#246#25#238

+  +#184'|'#191#140#21#0#245#133#195'O'#186#6#230#238'y'#232#160'^{'#207#245'G0_'

+  +'@.'#129'4'#197#155#30#200'~'#199'$1'#250#250'>+&'#236#12'g]'#249#240#0#142

+  +#216'?'#8#26'@gD'#160#179#135' +'#22'r9'#160#173'v'#245#14'EB'#165'F'#215#156

+  +'Bs'#188#209'h4'#6#211#161#5#12'Y'#4#11'&'#238#167#212#24#139#235'P'#160'K'

+  +#196#206#191#194#242'Y`'#205'+J'#18#0'7'#211'O'#148#243#159#246#143'4'#243

+  +#168#223#182#14#158#185#255'b'#201#206'o+('#131#139'oZ1'#168#215#222'u'#237

+  +#161#16#238#163'y'#137#20#184#225#222#143'@'#174#148#206#17'x'#247#242#195'!'

+  +#24#240#246#248'8'#249#2#150#223#243'>.j'#233#175'd'#20#198#139#209#198':'#9

+  +#135'"\'#15'A$'#0'2'#7#154'k'#190'g'#201'\bg'#160'F'#17#185'~'#130#205#254'x'

+  +#186#180#128'!'#203#225#184#217''''#29#130#135'yW'#172#254#235'tz('#157#184#7

+  +#152#244#26#214#229#135'e'#253#241#171'?'#169#255#220#7#155#246#207'3'#227'x'

+  +'g'#197#159'a'#237#247#255#25#250#129#134#128'E'#7#158#10'{'#29'|'#230#128'_'

+  +#247#231#171#15'D{2'#167'F'#211'3\q'#199#27#160#207#144#163#173'?x'#232#182

+  +#19#192#237#236'}B'#242#194#253'N'#130#165#135#157#147#145#243''''#135#138

+  +#196'83'#128#178#3'='#188')`o'#169#1'g'#203#230'd'#219'0'#190'Jp'#213#228#188

+  +#230#223#163#6#224'N'#135'/`'#168'b(C'#245#255'%'#220#159' '#174#250#179#20

+  +'TAA'#233'd'#182#242#147#240#179#156'a'#180#215'0'#140#251#11'x'#152'~,'#174

+  +#190#199'ig'#18#244#217#157'q'#249'#PZ9'#176'T'#218';'#175#220'/+3'#2#6#138

+  +#11#174''#1'l'#133#227'$;'#255'S'#247#156#7'-'#13#155'{}'#142#193'd'#131#203

+  +'n'#207'L'#253#2#203#11#192#175'%'#154#156'''@y'#1'\'#207#0#143#199#3#205#219

+  +#190#235'j'#6'$'#242#180#158#189#139#140#190'_'#210#161#5#12'I'#18'Kw>'#214

+  +'"W'#168#155#240'G'#169#19'w'#252')'#170#154#7#22#139#141#9#191#208#231'O'

+  +#205#175#254#178'a'#24#247#23'p'#215'5'#251'g'#188#250#175'?'#208'h'#13'p'

+  +#217'mo'#12'Hu'#206#149'k'#239#138#11'oz'#5#204#214'B'#201#206#255#226#195

+  +#151#161'i'#247'K'#159#207';'#227#138'G'#161#164'<'#189#206'@'#1#226'J'#193#0

+  +#211#2#194'L'#11' 3'#160#165'n'#13#248#220#246#20'3@'#173#136'>2)'#223#241

+  +''''#157'N'#231#25#170#22'0'#20'I'#148#141#155'u'#210'Y('#205'O'#138'c'#255

+  +':'#189#25'J&'#236#202'B~F'#3#183#250'k'#133#138'?'#129#0'2'#242'1f'#30'w]'

+  +#189#159#212#151#144'DE'#245',8'#233#194#254#135#208#238'^v@V*'#23#7#2#250

+  +#221','#187#251#163#172#159#215#209'V'#7#171#190#252#23'4'#213'n'#128#182#230

+  +'m'#253'j'#235'V5i'#23'8'#225#252#244'O?'#18'$'#150#141#26#143'u:'#3'}'#228

+  +#12'D"p'#182'7'#128#189#241#215#20'3@&K'#212'M'#201'k'#222#27'??'#215'P'#181

+  +#128#161#17#192#236#147'?'#199#253#18'.'#166#207'M'#248#181#22'q'#153'$'#248

+  +#194'`O'#173#134'k'#244#169#16#226#254#195'P'#3#8#6#189#240#208'MGH}'#25')'

+  +#216#231'w'#23#194#188#197#253'k'#184'y'#239#181#7'f'#165'rq '#160'^'#7#151

+  +#221#241#206#208#15#212#7#162#209'0'#252#188#242#3#216#176#230'S'#166#238'G'

+  +#250#209#200#181'+'#228'r'#5'\q'#231#251#236'w'#158'v'#240#209#0#193#25#200

+  +'B'#130#188'/'#192#231#11'@'#243#214'o'#184#190#129#157'f'#0'X'#181#129'S'

+  +#202#173#190'OQ'#3#240'644'#4#15'?'#252#240#216'`'#180#128'AKb'#217#204#227

+  +#170'er'#21#181#252#146#137#213#255#226#234#221#209#246'7'#166#172#254#164

+  +#254#211#7''''#31#198#234'['#211'Vx'#238#190'?H}'#25') '#15#245'YW?'#133'6t'

+  +'y'#159#207#253#235#242#131'r'#142#0#242#138'*'#217#245'g'#18#159#189#243'wX'

+  +#245#5#229#26#12'='#13'z'#241'Ag'#194#238#251#156#148#145#235'$'#225#23#18

+  +#131#184'"!./'#128#234#4#218#234#215#131#167#163#169'Kjp'#236#141')'#5#142

+  +#171'U*'#149#203#135',1'#216#26#129#193'J'#163#172'|'#246#201'7'#226#153'n'

+  +#23'{'#255#141#230#2'('#172#152#205#173#254'z'#21#232#209#12#160'6'#223'*'

+  +#149#144#246';<'#133#159#176'm'#195'w'#240#230#179'7I}'#25';'#128'<'#232#231

+  +#223#248#143'>'#159'w'#255#13#135'd'#181'x'#169'?'#216#251#240#11'`'#151#133

+  +'Gf'#236#248#219'6'#174#132'7'#159#185'1m'#199#179#228#149#194#217#203'2'#211

+  +#215'P'#152'+'#200':'#8'G'#185#225#162'>'#161'i'#136#179#21#218#235#215#166

+  +'$'#5#201' '#209'19'#191'u'#145'\'#150'h'#195#197#215'+'#170#20#28#144#157'7'

+  +'h'#2'@'#245#159#234'S'#23#139'+'#255#242'J'#167#131'-'#191#12#244'zU2'#244

+  +#199#138'~'#134'q'#222#191#128#159#191''#31'>~#'#251's'#254#250#131'I;/'#130

+  ,#195'O'#238#157#156#30#188#241'P'#201#18#152#186#3#149'8_v'#251#191'I'#183

+  +#206#200#241#253'^'#23'<y'#215')i'#14'}'#202#224#162'['#222#0#181'V'#159#145

+  +'k'#238#172#15#232','#21'&G'#160'/'#16'ff@('#20'L1'#3#242#245#254'S'#138#12

+  +#30#26#0#209#129#154'@p0'#253#2#6'#'#146#178#162#169#135#234'UZ'#171#3#133'_'

+  +'-'#206#253'/'#174'^'#128#170#191'.'#153#246'+'#228#253''''#157'9>'#232#163

+  +'7|'#247#217#10#248#230#163#204#148#136#166#3#135#156'p=L'#153#181'W'#143#143

+  +'?q'#231#137#224#243'8'#164#190#204'$'#170'&'#207#131'#'#207#252'S'#198#142

+  +#255#244#221#167#129#219#217#146#246#227#238#182#247#137#176'`'#255'3'#210'~'

+  +'\'#241' '#145#168#168'y('#133#4'I'#19'ho\'#7#30'gsJm'#128'^'#21'y'#180#210

+  +'b'#191#31'I'#193#129'&'#128'o0'#206#192'A'#17'@'#197#156#147#247#195#235#252

+  +#143'X'#253#215#234#200#251'?'#159#9#190#1'5'#0#193#249#199#133#254#134'o'

+  +#234#175#128#207#223'y'#4#214'~'#155'y'#135#213'`'#161'Ti'#224#194'['#223#234

+  +#241#241#247'^'#186#3'6'#175#251'R'#234#203#228#175'U'#13#231',%c+'#233#251

+  +#175#222#9#155#214#14#174#129'J'#223#215#174#129#243'o~3#'#206'@ae'#167'h@'

+  +#152#31'$B'#137'AD'#0'N{=8'#155'6'#166#180#11'S'#202'c'#223'O'#202'k;'#7#175

+  +#165'='#18#137#184'='#30'Oh'#160#13'C'#6'E'#0'h'#255#255#9#143#190'\'#28#254

+  +'3'#219'*'#209#4#152#204#236''#218'h'#188#183'Z'#24#243'5'#12#171#254#186

+  +#226#235#15#159#130#213'_'#190'.'#245'e'#244#138#5#7#156#9's'#23'w?'#149'w'

+  +#203#250#175#224#253#151#239#144#250#18#25#14';'#229'6'#24'?u'#183#140#28';'

+  +#232'w'#195#147'>'#161#215#2#159#161'b'#202#172#189#225#128'c3'#215'+'#128

+  +#181#12#19#204#0#158#0'|^/'#180#212'|'#151','#17#230#252#0#16#156'\'#208#182

+  +#31#138'Y'#227'`'#157#129#3#149'L'#217#173#183#222'*{'#226#205'M_'#225#237'='

+  +#196#197'?y'#227'v'#6#171#173#152#23'~n'#245#231#188#255#178'a'#217#240#179

+  +'+'#182#172#255#18'>x%s*k:'#160#213#153#224#236#235'^'#237#254'A'#252#209#252

+  +#237#182#195'%o'#10'2e'#246#222#176#255#209#215'd'#236#248#159#188'q/lX'#243

+  +'IF'#223#3'-|''_'#246'$s'#10#166#27'I3 '#206#153#1','''#0#9#128#136#128#8' '

+  +#24#240#165#248#1#10#244#254'K'#11#13#158#143'Q'#11#176'SH'#16#181#128#240'@'

+  +#204#128#1#19#192#148#221'N2'#251'B'#178'v'#154#248#211'i'#255#171#160#164'z'

+  +'O'#208#235'u'#172#232#135#156'Z>'#245'W>'#12#219'}w'#7'ZY'#158#185#235'D'

+  +#169'/'#163'O'#236'{'#212#213'L'#200#186#195#11#247#158#14'^w'#187'd'#215'V4'

+  +'n2'#28'}^f'#29#169'O'#220'q'#20'D#'#161#140#191#23'K'#254'88'#233#210#199

+  +#211'~'#220#174#237#195')'#26'@$'#16' ?@'#211#6#240'8'#27#187#250#1'^'#172'0'

+  +#183#223#135'ZA'#171'N'#167's'#15#180'Jp'#160#162')/'#159'}'#226'!'#9#144#191

+  +'#'#216#244#20#255#215#27#172'PX9'#151#9'?'#249#0#152#250#175'$'#239#191#208

+  +#244'cd'#144#192'cl'#5#205#173'l'#186#174'(.'#159#6'G'#158'so'#183#143#173

+  +#252#228'9X'#253'E'#223'!'#195'L '#191'x'#2#28'{A'#250#203'j'#197#248'u'#213

+  +#7#240#223'w'#30#202#218'{Zt'#240#249#176#243#238#135#167#245#152'|'#247#31

+  +#212#0#184'nA'#194'hq6^'#220#209#4#142#166'_'#187#250#1#214'M'#206'o?'#31#9

+  +#160#9#205#0'g('#20#242#15#196#12#24#136'X2I.'#159's'#242#221'x'#222'+'#197

+  +#14'@s~%'#235#253'G'#194#175'G'#225#167'a'#31'D'#0'r'#133'l'#216#135#255#196

+  +'x'#225#222'S'#193#239'u'#14#253'@'#25#132'Zk'#128'3'#175'}'#181#199#199#223

+  +'x'#252'rhk'#218'<'#128'#'#14#29#214#130'r8'#254'"'#154#20#151#153#144#159

+  +#128#151#30'8'#27'<'#174#244'{'#254'{'#2#245'5<c'#249#171#168#233'j'#210'v'

+  +#204'd'#159#0#22#13'H0'#155#223#31#136#242'EB~h'#221#246'M'#151'|'#0#136'T'

+  +#219'Z'#143'R'#200#162#219#200#25'H9'#1#225'p8'#132'f'#0#17'@'#159#171#213

+  +#128#8#224#216'c'#143#149''#253#155#154#218#203#206#21#226#255#10'T'#243#243

+  +#199#205#6#147#165#128#9'?'#179#255#169#235#15'S'#255#249#158#255'#'#4#159

+  +#191'u'#31'lZ+m'#3#139#254#224#204#235'^'#239#241'GIi'#177'+'#238';'#13#194

+  +'A_V'#174#165'l'#252'L8'#244'Tr>fV'#248#219#26'7'#193#191#158#186'2+'#239'I'

+  +#140#25#187#30#6#11#14'Jo'#134'hgRPg'#159#0#193#20'h'#175#253#129#245#8#16'u'

+  +#12#134'|'#157#247#230'b'#147#255'}'#148#201#22'$'#128#14'2'#3'P'#3#136'B?'

+  +#162#1#3#17'O'#249#132'9G'#230#133#19#250'f'#188#173'H'#150#255#170')'#254

+  +#191#16#237'~'#174#233#7#197#254'5|'#242#15#215#245'w'#228'0'#128#179'm;'#188

+  +#241#152't'#13'A'#250#139#197#135']'#10'S'#230#236#223#235#251'x'#243#241'K3'

+  +'n'#206#204'^x'#28#204#223#251#212#172#188#231#183#159#190#10'I'#224#183#172

+  +#156'K'#12#149'Z'#11#167'-{-'#189#7'Mp9'#1#228#8#140'D'#184'h'#128#16#18't'

+  +#182'lBS'#160'N<D'#20#244#170#240'['#149#22#199#189#177'X'#172'I'#163#209'8'

+  +#6'b'#6#244'W:'#153#250'_'#185#203#201#191#199#243#190'!'#216#255#180#194#235

+  +#141'yPP1'#135'9'#254#184#216#191#146#13#251'd'#171#191#156#31#243'='#130#240

+  +#194'='#199'C$'#156'['#3'7'#187'b'#225#193#23#193#212']'#14#236#245'9['#215

+  +#253#23#190'|'#239#225#140'8'#204#228#168#26#239's'#212'r'#168#156#156#153'P'

+  +'_W'#248#189#14'x'#229'Aj'#146'"M'#132'c'#209#161'H'#184#179#211'[)'#26#231

+  +#11#132#136#0#132'>'#1'D'#2'd'#226#216#27#215#165'8'#2'U'#242#216'&4'#3'.'

+  +#198#219#13']'#204#128'>'#163#1#253'&'#0'R'#255#191#217#164#186')'#145#144

+  ,#221'"'#216#255'4'#247#207#156'?'#30#172'E'#19#152#240#147#243#143'&'#1#177

+  +#220''#249#200#178#255#5'|'#251#225'c'#240#235#170#247#164#190#140'^ '#195

+  +#21#233#31'h'#154#245#175#133#213#170#207'_'#128'u+'#223#198#31'T'#223'%'#177

+  +'}'#158#25'5'#194#9#211#23#194'B'#212'@2'#209'B'#171'''|'#242#250#157'P'#251

+  +#219#183'Y;_W'#152'l%p'#204#5#233#27'u&D'#2#132#226' V'#27#16#138'23 '#16#8

+  +'B'#203#182#175#240#251#138''''#29#129'2Y'#194'7'#173#160#245'd4'#11#234'('

+  +#26'`6'#155';'#182'l'#217#18'Z'#183'n'#29#153#1#189#170'y'#253'&'#128#165'K'

+  +#151'*6'#187#198#189#128#231';A'#236#0#180#149'L'#7#147#181#132#9'?'#167#254

+  +'wv'#254'aC?F'#152#6#16#143'Ga'#5'j'#1#180#207'E'#232#12'68'#238#146'g'#7#250

+  +#174#224#251'O'#158#133#223#214'|0@'#141'@'#198#178#250'4:3'#20#148'N'#130#5

+  +#7'_'#12'jm'#250#231#234#245'z'#229#236#251'8N'#210'JG'#146#135#211#174#253

+  +'WZ'#143#201'R'#131'y?'#0#155#29#128#4'@'#27#17'A'#235#182#239' '#28#246#167

+  +#248#1#198'['#237#231'j'#20#225#245'J'#165#178#9'W'#167'N'#167#11#244#167'6'

+  +#160#191#210')'#159'7o'#158#162'9:'#141'hv'#174#152#0#10'*'#230#130#201'le'

+  +#194#175#213't'#134#255#134's'#235#175#190#240#213'{'#15#194#230#28'u'#6#142

+  +#199#21'x'#175#223#15'>'#209#134#242#29#234'6}'#7'M'#219#215#178'N4'#241'X'

+  +#132'U'#17#146#160#145#160'['#242#203#153#176#23'W'#236#4#230'<'#233'Zy'#9

+  +#248#254#147#167'a'#253#247#131#27#156#154'N,='#234'Z'#168#154#178'g'#218#142

+  +#215'u'#132#24'5'#10#9#242'Z@{'#253'Oh'#246#216'S'#8#160#216#232#249#147'M'

+  +#235#251#24#239'k'#196#191#237#161'P'#200#215#159#1'"'#253#145'Pf'#255#31'|'

+  +#240#193#170#181#141'ymx'#219'$'#142#0#20'MX'#8#6#157#134'['#253#133#226#31

+  +#249#200'I'#0#234#14'$'#12#175'=tF'#214'<'#233#253#6'~'#224'G'#254#225'Q0Z'

+  +#138#165#190#146#172#225#229#191#158#136'Z'#203#192#27'|'#164#27#21#147'wC'

+  +#18#184'.m'#199'K'#13#7'v'#18#0#141#21'w4'#253#6'^WC'#151#6'!'#254#23#139#244

+  +#174#151#209#254#175#139'F'#163'mj'#181#218#211#159#18#225'~'#17#0#217#255

+  +#171'6'#199'+Cq'#237#214#164#3#16#237'='#181'F'#143#4#176#27#203#250'c'#171

+  +#191'Z'#193#186#2')'#21'#'''#249#167''''#216'['#182#192#7'/,'#203'h'#206#249

+  +'@Q9e'#15'X'#252#251#204#228#168#231'"6'#253#248#1#172#252'8'#253#217'x'#131

+  +#129'Vo'#129#163'/z&'#173#199#20#210#130#201#214''''#2#16#162#1#29#246':'#232

+  +'h'#221#156#18#9'0'#168'C'#159'UZ\'#15#163'|'#214#14'$'#28#216#31#17#149#163

+  +#253'/'#175'q'#151#238#23#137#201#223'O'#137#0#24#242'!'#191'b'#22#155#3'@'

+  +#177'F'#0#138#206#8#192'H'#199#154#255#189#0#235'W'#190')'#245'e0'#144#231

+  +#253#152'K^'#204#170#243'Mj'#188#249#232#217#16#240#229'Fb'#150#12''#240''''

+  +'^'#153#222'b1a'#148'x'#140#207#7' '#2#8#134'#'#224#235#176#131#189#241#231

+  +#148'H'#128'F'#25#253#181#218'f'#191#3#229's;'#254#221#20#12#6#157'J'#165#178

+  +#207#226#160'~'#17#192#140#25'3'#148'n'#213#172#11#226#9#249#253'b'#2'0'#217

+  +#202#193'V<'#25'U'#255'N'#2'H'#142#252#30#225#26#128#128#207'^'#191#29#154'j'

+  +#178'?*L'#12#242#190#239'}'#204'MPR5['#234#143'#kh'#220#182#26'>'#255'gnT7'

+  +#10'8'#225#242'W@'#158'&'#2'f'#170'='#223'#@'#240#3#176'~'#129#148#16#228#247

+  +'B'#235#246#149')'#4#160#148#199#237#147#242'Z'#175'E'#185#164#9#221#13#129

+  +'@'#192#238#247#251'}&'#147#169#215#226#160#190'D'#148#169#255'^'#175'W'#249

+  +'K'#147#237#190'xBv'#129#152#0#172#197'S'#192#130'$'#160#161#8#128'J!'#234

+  +#254#3#204#30#29#13#4'@'#248#238#195'G`'#235'/'#210'8'#5#233#251'Xr'#228#245

+  +'P6a'#174#212#31'CV'#241#239#167'/'#6#143'3'#183'f'#29#238'{'#252#237'l'#28

+  +'^'#186#144#236#15' '#26'%N&@'#24'5'#129#230'-_B4'#18'I'#18#0'">5'#191#229'r'

+  +#20#203#173#248'w]8'#28#166'Va'#30'Q'#143#128'n'#253#0#253'"'#128#182#182'6'

+  +#213'fW'#217';'#137#132'l?q'#17'P'#222#184#153'`4'#23#178#213#159#171#254#235

+  +','#0#26'%'#178#159#196'/'#223#252#3#183'W'#135'~'#160#1#128':'#213'.8'#236

+  +'*('#159#180#187#212'o?'#171'p'#182'l'#133#15'Wd'#174#164'x'#176#152#179#228

+  +'t'#152'6'#255'wi;'#30'_'#23#196'|'#0#177'(?D'#20'M'#0'r'#6#182'm'#255#1#194

+  +'A/'#171#9#16#136#162#210#226#252#139'A'#29#254#142#252#0#161'P'#168#197'`0t'

+  +#212#214#214#6'{'#203#7#232#147#0'('#254#143'j'#132#250#199'Z'#243'z<O'#149

+  +'8'#9#168'h'#252#238#160#211#25#184#8#0#159#255'O'#17#0'N'#1#24'm'#20#0#176

+  +'m'#221#167#240#253'G'#203'J'#205#189#181'p<'#170#253#183#128'Zk'#150#250'm'

+  +'g'#29#31#189#180#12#28'-'#185'5'#234#156'0q'#214#1'0'#223#244#213#5#8#161

+  +'@'#202#7#136#196#249'p`'#8#9' '#24#3'{'#227'/'#16#240#180#165#16'@'#161#222

+  +#243'b'#129#193#255'~<'#30#175#161'|'#0'4'#1'\('#187#254#222#242#1#250#146'R'

+  +#22#255'Oh'#138#205'->'#27#205#196#146'wv'#1'RB'#209#132'E'#160#165#236'?u'

+  +#151#177#223#195#184#253#247'PA'#171#211#234'O'#30#3'G3'#253'@'#211'O'#4'*'

+  +#181#30'v^t'#18'L'#154's'#176#212'oU'#18#248#221'm'#240#238#147#231'K}'#25

+  +#221'b'#210#156#131'`'#151'}'#206'M'#235'1'#217'b'#194#143#14#139#242'&'#0

+  +#249#1'\'#246'm'#224'm'#175'I!'#0#139'6'#240'q'#153#201'M'#163#250#182#225

+  +#223#141#184'''?'#128#191#188#188'<<h'#2' '#7'`'#212'0c'#170'7'#164'Z'#203'^'

+  +#192#19#128'ZoB{g>g'#255#167'$'#0#201'G'#141#237#223#27#130'~'#23#172#254#244

+  ,'Ih'#216#250'=2'#248#208#179#212#244'hj'#237#188#231#9'0~'#250'^C>'#214'p'

+  +#198''#223#248'?h'#169#253'I'#234#203#232#22'S'#230#30#206#204#128'tB'#136#4

+  +'P80'#18#163'\'#0#218'"'#172'1'#136#171'ecJ2'#16#170#255'?V'#152#29#143#201

+  +#229#242'mx='#154#233#237'}u'#9#234'MTY'#251#175#239#190#251'N'#245'['#171

+  +'q~0'#170#254'R'#198#229#246'2'#2#208#26#242#160#160'|6'#18#0'7'#248'S'#171

+  +#230#186#255#202'y'#239#255#232#243#2't'#15#250#130'~'#254#250'%'#168#221#240

+  +'?'#22#178#234'o'#5#30'y'#246#13#150'"('#169#154#3#147#231#28#2'f'#155#244'Y'

+  +'wR#'#26#14#194#27#143#158'"y['#179#158'0}'#215#163'`'#214#194#147#211'v<!'

+  +#10'@{65'#136#252#0'|.'#128#183#163#13#28#141'?'#167#16#128'N'#25#222'Peu<'

+  +#138'/'#221#138'[m'#28#129#189#18#128#224#0#172#243#20#239#19#140'*'#223#21

+  +#212'z'#5#254'8'#181#166#2#200#31#183'3'#174#254'|'#251'o'#214#0#20#197'^'#14

+  +#163#214#7#208#31#184#218'j'#160#254#183'o'#160#195'^'#11#177'H'#8'b'#177'0+'

+  +#196'Qi'#12'`'#180#150#128'%'#191#10'l'#197#213#144'_'#154#153'A'#148#195#25

+  +'k'#191'x'#1'6'#254#240#214#208#15#148'!'#204#216#243'x'#216'i'#143'c'#211'z'

+  +#204#206#148'`.'#31' '#20#226#250#2#248'='#14#176'7'#172'I!'#0#173'2'#178'm'

+  +#188#213#254#8#222#166'H@-n-'#145'H'#164'#'#136#24'4'#1#212#215#215#171#155

+  +'C'#149#191#11#199#148#175#164#16#128#185#24''#164#211'A'#175'U'#163#22#192

+  +#141#5#147#141#144#6#160'c'#200'M'#188#251#228'y'#16#240#218#165#190#140#30

+  +#177#243#162'S`'#218#252#244'O:'#18'R'#130')'#245#151'B'#129#212#23#192#239

+  +#237#128#246#186'U)'#4#160'QD'#27''''#216#218#169#239#218'Vr'#4#162#188'6'

+  +#163'9'#224#178#217'l'#129#158#250#4#246'J'#0'B'#4#224#151#6#195#201#225#152

+  +#226'q'#193#4' '#2#208#163'Jj+'#158#194#170#0#169#11#144'P'#1#152#201#16' '

+  +#133'='#26#182#172'D'#27'p-L'#156'y '#20#150'O'#207#208#153#198#144'k'#8#162

+  +#249#244#246#227#233'u'#176#165#27#187',='#11'&'#239'rHZ'#143#201#133#2#249#6

+  +'!T'#19'@'#131'C'#169','#216#235#131#182#218'oS'#8'@'#165#136#181'O'#180#181

+  +'QSDJ'#217#175#193'}#e'#4#246#22#9#232'MVY'#4#0'_'#172#217#238'.'#249#3#18

+  +#192'=b'#31#128'1'#175#10#172'E'#19'Y'#27'p'#174#7#160#156#133#6#217'A3'#192

+  +#0#31'<{)s|$/'#28'O2k'#241#169'0e^'#250#226#174'c'#200']'#172#254#228'q'#216

+  +#178#246'?R_F'#175'8'#240#180#251#192#156'_'#145#246#227'2'#1#231'K'#131#169

+  +#24#136'5'#7#241#7#161#181#230#171#20#2'P'#202#227#238#201#249'm'#15#2#231#3

+  +'HF'#2'Ps'#240#245#148#18#220''''#1'h'#17#245#254#138#171#163'q'#197#205#236

+  +#5'|'#20#192'T0'#17#172#5'U'#160#215#171'Y'#18#144'0'#0'4SC@'#222'|'#228#148

+  +'n;'#241#236'y'#232'UP1eAF'#206'9'#134#220#193#219#143#159#141'Z'#128'K'#234

+  +#203#232#17'r'#133#10#142#185#244#149#140#28';Y'#21#136'{6+ '#16'fm'#194'['

+  +#182#254'/'#133#0#20#178'x`J'#1'G'#0#248#247'6'#148#213#250#190#230#5#244'$'

+  +#173','#2#176'n'#221':'#165#211#233#212'm'#178#23#220#138#4'p9{'#128''''#0's'

+  +#209'dd'#187'r'#212#0#144#0'P'#11'P%K'#128'3'#147#2#252#250#3#199'w;'#221#150

+  +#28'g'#135#156#245'HF>'#248'1'#228#14#254#249#192#9'h'#3#167's'#208'gzA+'#255

+  +'A'#167#167''#230'A'#178',8'#193'E'#148#136#0'hX('#245#5'h'#221#250#5#27#248

+  +'*<G&KD'#167#230#183'<'#128#183'k'#20#10#5'K'#9#22'J'#131'{j'#17#214'#'#1#8

+  +'5'#0#200#28#250':_'#197#221#209#184#252'l'#246'@'#146#0#166#130#165'`'#28#24

+  +'H'#3#208#168'X'#31#0'Y2'#4#152'~'#188'v'#255'1='#134''#14':'#237#254#140

+  +#168'^c'#200#29#252#3#191#255'\*'#189#238#138')s'#15#131'9{'#157#153#145'c'

+  +#11'~'#0#214#29'('#18'e'#3'C'#3#193'0'#180'm'#251#154'uy'#22#8#128'0'#173#160

+  +#249#1#178#255'qc'#161'@'#220'Z'#187#204#13'L'#137#4#244'J'#0#20#2'D'#245'A'

+  +#191#161'5'#239'Q$'#0'6tN '#0'K'#201'N'#172#21#152#201#200'5'#3#161#230' '#10

+  +#25#215#7' '#19#12#240#218'_'#143#134#158'2'#235#138'*g'#194'^'#199#220#182

+  +#195#253'[~'#250#0#218#27'~'#5#183#163#30#2#30';'#132'C\'#3#15#210#26#202#170

+  +'w'#133#201's'#15#5#157'1?#_'#218#24#210#7#250#145#191#249#224#9'R_F'#175'8'

+  +#240#244#7'2'#183#8#145#6' '#228#2'Db'#224#245#134'9'#2#168#249#14#162#145'@'

+  +#10#1'L'#206'k}\'#169'H'#208#224#7'r'#4'nW*'#149#205'*'#149#170#163#161#161

+  +'!8`'#2#160#16' '#18#128'a'#171#171#244#249'XB'#206'rO'#5#2#176#150#206'DA*'

+  +#4#147'A'#195'G'#1'd,y%SQ@'#166#2#246#208#184#146#206'{'#228#197#207#131'R'

+  +#205'M'#155#165't'#209'O^'#185#158#9'}_Pi'#244'P2~.'#236'~'#200#229#25#153

+  +#248':'#134#161#195#217#188#25'>Z'#145#187#141'N'#20'*'#13#28'}'#233#203#25

+  +';'#190#160#248'PYp'#8'5'#0#31#18#128'?D3'#2'VA$'#232'N!'#128#234'<'#251#11

+  +#26'Et='#222#220#138#191#231#237'h'#2#244#26#10#236#145#0'('#4'XXX'#168'B3'

+  +#192#248'K'#147#237#159#241#132'l1{@ '#128'q'#179#193'h'#202#7#147#137''''#0

+  +#26#3#206#183#1#207#4#9#188#243#216#185#224#239'E'#160#199#207#216#27'v?'#248

+  +#18#230')^'#245#241#19#3'N'#191'U'#170#180#176#199'!'#151#193#184#201#163#171

+  +#178'n8'#128'l'#223#215#239';6g3'#0#231#238's6'#211'&3'#5'!'#29#152'"'#1#212

+  +#25#200#235#11#177'\'#0'J'#4#10#251#157')'#4'0'#222#234#248#135'N'#21'YK&'#0

+  +#229#2#224#234'O'#205'A\'#212'$t'#247#221'w'#143#12#136#0'('#7' '#20#10#25''

+  +'m-x'#27#9#128'IF'''#1#204#5#163#217#10'f'#163#22#180'H'#0#212#9'H'#166#200

+  ,'\'#15#128#143'W,'#7'{'#227#198#30#31'''/l'#193#184'i'#208'Z'#251#243#144#206

+  +'SX1'#3#150#28'u#j'#19#218#204#188#145'1'#12#10#239'>q'#1'x]'#205'R_'#198#14

+  +#160#26#141#195#255#144#217#182'd'#9'^d'#217#192#208'p'#20'<^'#158#0#234#215

+  +'B8`O!'#128'J'#139#227#13#189'*L'#197#18#201'\'#0#212#226#157'H'#6#221#230#2

+  +#244'J'#0'j'#181'Z'#19#139#197#140#155#28'E'#175#196#226#242#165#236#1#222

+  +#203'o+'#157#131'&@>'#243#1'P$@'#145't'#2'f'#134#1'V~'#240' l'#203'R'#211#13

+  +#5#146#201#220#253#206#131#234#153#251#15#253'`cH'#11#214'|'#254'LN'#166#1#31

+  +'p'#234'=`+'#158#148#209's'#8#233#192'q'#158#0#220'D'#0#254'0'#18#192#26'4'#1

+  +'\)'#4'0'#193#230'x]'#171#140#172#3'>'#27#144#186#4#247'6-'#168'O'#2#8#135

+  +#195#166'm'#29#165'OF'#227'r'#166#227#8#4'`)'#153#9'f['#17#24'y'#2#160'f '

+  +#178#12'N'#2'j'#174'Y'#3#255'}'#237#214#140'~'#208']a+'#158#8'K'#143#187'-'

+  +#235#189#238#199#176'#'#130#254#14'x'#251'og'#230#212't'#230#146#9#187#192'^'

+  +#199#220#146#241#243#8'EAqf'#2'D'#192#235#14#129#151#8#160'n'#21'DB'#30#238

+  +'9<'#1'L'#180#181#189#162'R'#196'6Q='#128#208#30#12'I'#192#209'S2PO'#210#154

+  +#204#2'D'#152'6'#180#218#238#143#198#21#201'('#0#17#128#185#136#250#194#151

+  +#128#201#164#3#131'^'#197#17'@'#134#235#0'^'#187#247'('#180#131#178#251#3#144

+  +#203#149'0{'#233#25'0y'#222'aY='#239#24'v'#196#166#213#239#194#143#159'<!'

+  +#245'e0'#208#140#132'C'#207#251'{'#210#241#156#13#196#248'T`'#143''''#8'>$'#0

+  +'J'#5#142#133#131')'#190#145')'#249'-+'#208#26#175#1'>'#25#8#247#13'('#252

+  +#164#1#248#186#235#11#208''''#1#168'T*'#243'f{'#254#31#195'1'#197#25#236#5'<'

+  +#1#152#10#166#176'D '#179'Y'#139#4#160'a'#4#192'f'#1'f'#144#4#200#14#244'8'

+  +#26#135'~'#160'A'#192'RP'#9'{'#31''#27'h'#141'y'#146#156''#12#28'>}'#233#6

+  +'h'#173#251'E'#210'k'#208#155#242#225#16#18#254',u`f&@'#28'X'#243#15'J'#0'r'

+  +#187#3#204#7#208'F'#169#192#209#136#152#0#18#211#11'[^'#196#191#235'I'#3'P('

+  +#20#219'"'#145'H'#3#222#223'>h'#2'@5'#194'R'#227'*'#188'>'#20'S^'#200'^'#192

+  +#11#184')"'#152#11#171#192'l'#210#128#209#160#3#165#138'k'#6#154#201'>'#0

+  +#171'>~'#156#173#2'R'#129'Z?'#239#188#240'$'#152#177'gzK>'#135#27#220#246'zh'

+  +#216#252#29#11#183#6'|.'#8#5#220#172'V_'#165#214#129'Zg'#2#173#222#12'Fk)TN['

+  +#12'zsAZ'#207'MCY'#222'J'#186#134#160#244#190#14'9'#231'a'#166#25'f'#11#156

+  +#15#144'/'#7#14'F'#160#163'#'#192#178#1#219#182#254#143'/'#20#226#228'Y.KDP'

+  +#3'x'#149'R'#128#129#171#5'`'#233#192#184#136#183#187'\.ow'#147#130'z%'#0#170

+  +#3#192#23'['#234#189#197#151#6'"'#202'd'#23'F"'#1#131#181#10#172'%'#19#193'd'

+  +#208#130#201#172'I'#154#0#178#12#134#210'i '#194#7'OH?'#158#219'd+'#133#165

+  +''''#252#31#232'-'#133'R_J'#198'A'#130']'#187#225'Kh'#218#242#3'ks'#22#244

+  +#216#7'4'#135#143#134#148#26#172#197'P1u'#1#236#180#240#184#180#9#206#215'o'

+  +#221#13'u'#191'~'#153#213#207#194'Z4'#30#14'<'#235'>'#188#149#253'|'#17#166#1

+  +#160#249#27'@'#193'w'#185#209#4#240#5#161'}'#235#23#220'c<'#1'('#229#241#224

+  +#164#188#214''#226'M'#154#18'L'#234#255#214#190':'#3#245'J'#0#227#198#141

+  +#211#6#131'Ak'#141#211'r'#182'/'#172'Nz;H'#208#245#214'r'#176'P='#0#154#0'&'

+  +#147'6'#217#15' '#211'x'#253#158'c'#210'2'#201'v'#168#160#228#163'Is'#15#129

+  +#185#251#159''''#245#165#164#21'm'#245#235#161'n'#195'W'#208'^'#183#142#173

+  +#178#209'4'#142'B'#167#207#172#160'b'''#152#179#247#153#144'W:y'#200#199#219

+  +#188#250'='#248#241#227'''3>'#168#149#186'/O'#158'8'#204#217#231#172#140#158

+  +#167'W$'#184#17'a'#1#180#253']'#164#1'x}`'#223#254#13#255#16''''#207'*E'#204

+  +';)'#175#157#6'%'#146#218#207'4'#0#154#24'L#'#195#245'z'#189#167#191#4#192#10

+  +#129#208'VPVVVjc'#177#152'e'#187#211'|'#162'7'#172#185'+'#249#4'j'#9'f*'#5'['

+  +#201'4\'#253#181','#23'@'#165'Qr'#149#128#221#229'j'#164#145#23#254#243#236

+  +#149',3,W@'#17#130'=w5'#148'T'#15#207#190#252'q$'#211#205'?~'#0'5'#235'>'

+  +#135#142#182#154'n'#11#174'2'#129#252#178#169#176#232#152#27#217'H'#173'!]?'

+  +#10#255#143#31'?'#1'['#250#152#13'2M+'#240'w^>y'#15#216#253#176'+'#178#155

+  +#23#210#141#12'%d'#192'f'#3#4#252'!'#232'p'#5#192#235'q'#131#163'ne'#138#3'P'

+  +#163#140'vT'#219#236'4'#187#190#129#132#159'6'#165'RY'#135'2'#220'6h'#2#136

+  +'D"'#214#6#183#249'w'#238#144#238'!'#241#147#180#166'b'#176#149#206'`y'#0'&'

+  +#139#142'M'#7'b'#29#129'2'#252#217#172#251#250#31#240#243'_'#200#222#151#209

+  +'O'#20#148'O'#135'%'#199#222'<,B'#134'^\'#217'7'#174#252#23#218#241#223#131

+  +#223#211'.Y'#145#13#249'T'#166#237'~$'#139#178#12#29'qX'#243#201'3Hd'#255'e'

+  +#205'C'#134#2#133#146#146#202#166#163#224'_'#206#18'}r'#1'T'#13#24#141#198'P'

+  +#245#15#129#219#229#7#175#219#1#206#134#31'S'#8'@'#167#140#216#171#172#246

+  +#143#128#215#0#168'"'#16#247#140#0#240#182#183#187#138#192'~'#17'@'#179#199

+  +#184#175'3hxZ'#252'$'#141#161#0#242#198#237#12'F'#163#14#205#0#29'k'#14#154

+  +#169'^'#0'b'#208'D'#222'7'#239#203#205#194#16#25#170#138';-8'#22'v^'#156#190

+  +#198#144#233'BG{'#29#252#244#233#211#208#142'*~$'#228#151#250'rR`-'#154#0#251

+  +#159'y'#218'j1(g`'#195'7'#175'C'#253#198#175#193#215'A'#3#173#251'&8r`'#22

+  +'V'#238#12'Sw;'#2#138#170'fI'#253#145#236#0'z'#7#17'j'#7#230#9#162#9#224#199

+  ,#247#213#14#206#198#212#238#200'zU'#184#165#210#226#248#12':}'#0#228#4#172#29

+  +#18#1#144#9#208#234#209#237#209#230'7'#254'#'#229#3#211'Z!'#191'b'#14#24'P'

+  +#253#183#152#245#172''''#0'u'#4#202'F3'#208''#221'w'#18#251#146's'#21'Z'#163

+  +#13#22#163'z'#155'?n'#154#212#151#2#174#214#26#248#238#223#247#129#179')w'

+  +#204#166#238'@'#159#217'!'#231#254#13#212#250#244#14':!'#19#193#217#188#21':'

+  +'Z'#183#129#27'I'#208#227'jfu"F['#25'X'#11'+Y'#178#151#165#184':'#183#11#193

+  +'X'#166#31#215#11#192#235#13#176'('#128#199#209#12#238#150'u)O3'#170'C'#141

+  +#21#22#215''#249'N@d'#2'l'#29#148#9'@'#155#216#9#232#244#171'f6z'#172')'#241

+  +'7'#133'J'#7#5'U'#187#131#193#160#1'3'#154#0':'#150#11' '#239#182#31'X'#186

+  +')'#225#203''#222#153'u'#15#240'`0e'#215#195'a'#222#129#210#12#177#8#251#221

+  +#240#217#203'7'#131#163'i'#147#212#31'C'#191'A'#5'Y'#135#156#255'(k'#135'>'

+  +#154#209#157#190'B'#9'pa>'#9#168#3'M'#0'w'#251'v'#240#218'S'#167'#Y'#180#193

+  +#154'2S'#7'y'#6#27#248'$ F'#0#209'ht@N@BJ'#24'P'#169'R'#149'nh-'#250#2'_'#165

+  +'I>'#3#5#189'p'#194'"$'#0#29'X'#172'z'#208#27'5'#172'5x'#159'y'#0'i`'#131#230

+  +'mk'#224#211#23#174#207#202#151'1T'#152#11'*'#224#128#179#238#205#170'o`'#235

+  +#154#255#192#202'w'#31#206#154'C/'#157#160'<'#130#163#174'x!mSv'#135#5#250

+  +#180'P'#184#28#128'`0'#2#30'w'#0#220#168#1#184'Z6@'#160'#5)'#174#208#224']W'

+  +#160#247#253'D'#137'@d'#2#240#142#192#186'A'#135#1#137#0#240#133#164#147#21

+  +'ov'#20#191#30'K'#200'''$'#159#129#4#144'W1'#15'L'#22#27'j'#0#6'V'#19#160#226

+  +'C'#129']'#223'O&'#140#130'W'#238'8l@'#241'h)A'#177#240#189'N'#184'%+'#145

+  +#130'O'#158'_'#14'-5'#185'99'#167#191#176#20#141#135'C'#207'T'#234#203#144#4

+  +'='#5#209'('#2#16#12#132'Q'#248#253#168#5#4#192'Q'#207#149#2#139'Qnv'#174'D3'

+  +'`'#19'%'#255#8#26#128#144#8#132#154#128'o'#192#4' '#164#2#227#193#138#183'8'

+  +#10#30#12#199#20#139#196#151'E]'#129','#249'e`'#178#234#192'd'#212#129'ZC~'

+  +#128#236#204#5'x'#239#209#11#192#217#178'-+'#231'J'#23#166#237'q$'#204';(}'

+  +#195'#S'#128'6'#226'{'#191'h'#216'}&=a'#194#236'}a'#193#145#185'7'#1'X'#10

+  +'P'#18#16'E'#0'('#4#200#17'@'#16#218#183'}'#3#177'h0'#229'y'#19#243#218'>U+'

+  +#226#164#254#215#163#224'3'' j'#2#245#129'@'#192#142'f'#128'w'#208#181#0#248

+  +'wQ'#141#211'v'#173'?'#162'Jq'#191#27#242#171#217#20#27#179'Y'#159#12#5#210

+  +'x'#176#158'k'#12#211#247#161#172#253#244'yX'#251#249#138#236''#27'C'#196'n'

+  +#135']'#12'Sv;<'#189#7'E'#251#240#237#135#207'cN'#174#145#3#25#28'~'#201'c`)'

+  +#172#146#250'B'#178#131'^'#204#0'j'#6#18#165'n'#192'>'#206#254#247'z'#252#208

+  +#182#245#139#148#16#160'\'#150#136'N'#201'o'#249#8#5#159#194#30'uB'#30#0'nD'

+  +#8#246#129#214#2'$'#203#129#241#128'fd'#143#194'F'#143#229#20'wH'#151'B'#201

+  +'ZS'#9#228#143#155#1'&'#179#14#204'V=h'#132#178#224',('#1'>W'#11#188'q'#239

+  +#169#153'?Q'#154'AYeG]'#189#2't'#166#244#21#21#189#247#247'K'#192#222#176'q'

+  +#232#7#202'1'#152#242#199#193#17#151'?#'#245'eH'#10'a&'#0#245#1#240'y'#3','#7

+  +#192#237'p'#160#9#240'Cj'#18#144'"'#234#169#206#179''#129#247#181#161#204

+  +#210'J'#192'f'#3#12#182#28'8'#165#31#0#218#15#133#142#128'ai'#139#215#248#160

+  +#248'Ij'#141#5#10#198#207#3'#O'#0','#18#160'R'#176#142'A'#137','#12#7'}'#233

+  +#214'Cr"-x'#160'`?'#236'+'#158'K'#203#177'H'#19#250#9#183#145#138'='#143#184

+  +#10'&'#205#31#157#163#208'9$ '#30#163#8#0#239#0't'#250#193#213#214#0#238#214

+  +#245')'#4#128#182'K'#133#197#245#3#222'l%'#199#31#240#229#192#168#193#147

+  +#167'pp'#13'A'#168'%'#152#223#239'7!'#131#20'D'#19#170#201'['#157#133'o'#136

+  +'_'#163'P*'#161#176'z1K'#6#162'H'#128#206#168'ERP'#246'/'#23' '#13#252#240

+  +#206#131#231#177#24#239'p'#196#188#131#207#131#25#139#143#27#210'1'#236#13

+  +#191#193'{'#187'(g{'#229#165#3'r'#133#18#142#185#246#21#208#26#173'R_J'#250

+  +#209#143#175#141'u'#2'B'#251#159#28#128#140#0'P'#3'p6o'#1#175'c[J'#6'g'#158

+  +#206#191#173#200#224#166#196#128'VJ'#254#17'z'#2#146#6'0'#232#150'`BO@T'#31

+  +#10#240'GV'#190#201'Q'#242'J<!'#179'%'#159'$'#151'AA'#213#2#180#255'M'#168#1

+  +#24#152'&'#160'V+'#185#17'a'#252#140#192'LF'#4#214'|'#252#28#219#134'#J'''

+  +#205#133#3#207#185'gH'#199'x'#227#238'S'#193'mo'#144#250#173'd'#28#230#194#10

+  +'8'#234#170#225#249'='#247#7'='#201'H'#130#31#6#18'#'#2#240'q'#14'@'#234#5'`'

+  +#175#255#5#130#238#212#254#136#165'&'#247'z'#171'6'#176#25#229#148#8'`;'#240

+  +'-'#193'P{oB-'#222'IMA'#7'D'#0#212#22#28#247#234#182#182'6'#3#238#11'P'#149

+  +#24#183#201#158#255'P$'#166'HN'#228#164#149#222'6n'#14#152#243#138':'#9#128

+  +#250#3#138':'#4'g'#18#164#254#191'x'#227#193'9'#213'&'#170#191'0'#229#151#193

+  +#209#203#6#239#196'l'#173'Y'#7#239'=*}it'#182'0c'#241#177#176#235'a'#23'J}'

+  +#25'YE'#130#239#4#28'A'#251#159#28#128#180#250#251#144#0#218'j~'#128'p05'#19

+  +#182#202'j'#255'^'#167#140#144#186'O'#204#192#8#128#136#0'I'#160'iPm'#193#133

+  +#193' '#10#133#194#128#7#200#195#139#25'W'#227#202#187')'#16'Q'#237#147'|'#18

+  +'M'#8'*'#156#2#150#162'*'#230#3'0RJ'#176'^'#205#252#0'T'#232#145#141#128#224

+  +';'#15#254#1#218#235#135#159#3#140#230#17#156#242''#239#13#250#245'o'#222'{'

+  +'&'#184'FH'#200#175''#144#193'.'#7#156#9's'#246';M'#234#11#201#26#136#0'b'

+  ,#188#253#239#247'p'#234#191#207#19#132#214#173#255#195#197'/5'#201'kj~'#203

+  +#231'2Y'#194#137'2'#217#132#175'c'#4#128#219'v'#148#223'f'#220':jkk'#131'('

+  +#211#3'#'#0#26#13#134#194#175#15#4#2'y'#184'/'#173'w['#206#243#132#180#157

+  +#174'w'#234#11'`.'#131#188'q'#211#209#12#208#179#141#252#0'*'#181#146'o'#29

+  +'&'#154#18'$'#214's'#210#200#12#219''#249#2'>}'#246'F)'#191#167'A'#129'j'

+  +#227#207#184#251#179'A'#189'6'#28#244#195#138#27'G'#167'c'#172#176'r''8'#248

+  +#194#7'Xr'#213#136'@'#143#250'?O'#0#188#253'O+'#191#199#229'C'#18'p'#130#189

+  +'v%'#211#12#4'('#229#177#224#228#252#246#175#240#249#2#1#212#0#231#4#164#209

+  +'`-h'#198#187#131#136#1'M'#6#18#15#7#141'F'#163'6'#180'%J'#28'~'#221#190'->'

+  +#243#29#226''''#170#212'z('#172#222#19#140'&'#29#152'mD'#0'\B'#144#208'&<'#27

+  +'j'#192#11#215#31#8#145'P'#250#26'Wd'#3#244#3'>'#253#174#143#7#245#218'_'#254

+  +#251'*'#172'|{'#244#14'DUi'#13#176#223#153'd~'#148#145#138#4'_'#0'D'#241#255

+  +#160'?'#4#30#180#255#189#184'9[j'#192#221#250'['#138#227#215#160#14#219'+'

+  +#204#142#213'('#252#14#138#251#211'<'#0'>'#19#144'*'#1'['#7'3'#28#148' G'#155

+  +#129'U'#4#250'|>'#139'F'#163')'#142#199'a'#194'F{'#225#243#137#132','#217#29

+  +#129#170#168#24#1'X,'#204#15'`'#160#210'`'#230#7'P$'#29#129';'#156'-'#205'N'

+  +#235'_'#191'z'#19#190#249#231'_%'#249#162#6#11's'#193'88'#230#250#193#141#147

+  +#254#247#131#23'@k'#141#180#141'1s'#1'TA8m'#193#239'a'#206#1#167'g'#181'G_Z'

+  +#209#131#134'L+<'#133#255#200#254#15#160#253'/'#16'@{'#221'Z'#8#186'[S'#8#160

+  +#208#224#221'R'#160#247'Q'#185'g;'#17'@'#235#0#196#167#239#14';d'#3#226'V'

+  +#185#197#158#255#167'PL1#'#249'$'#20'rK'#241'N`-'#174#0#147'U'#143#4'`'#0#173

+  +'A'#13'*%'#154#1#138#204#205#10#236#138'Wn;'#10'|'#206#214#236#156','#13#152

+  +'0go'#216#231#140#255#27#212'k'#159'_~'#0'D'#130#185'U'#211'/%'#168#15'C'#233

+  +#164']'#160'z'#151'}'#161'j'#230#226'a'#31'2dFz'#156'S'#255'#A'#222#254#167

+  +#30#0#184'o'#222#252#5#196'#'#225#20#2#24'o'#181#175#210#169#162'-x'#179#29#6

+  +#144#5#200'>'#187#222'>W'#241't d'#146'B4'#5'*'#154#188#182#179#221'!'#237

+  +#209#201'''Q'#131'PK)'#228'W'#206'dQ'#0#163#197#0':'#147#150#21#6#201#149#217

+  +#233#15'@h'#217#250#19#252#251#129#225#227'%^t'#194'r'#152#186#231#224'R'#130

+  +#159#185'b'#201#176')'#132#146#2#148';'#160'3'#231#225#162'4'#30'J'#170'g'

+  +#195#196'y'#251#131#9'5'#174'a'#131#4'7'#9#184#211#254#199#213#159'e'#0#182

+  +#131#189#230#7'6"L'#144'c'#133'<'#30#153#146#223#246'5'#10#186#7'e'#141'V@'

+  +#178#251#5#2'h'#196#197#219#217'S'#18#16#161'W'#2#16'&'#4#163#253'o'#212#233

+  +'t'#249#241'x'#188#188'#'#168']'#220#232#177#220#156'|'#18#10#184'R'#163#131

+  +#226#137#11#153#31#192'h3'#128#158#18#130#180#252#184#176#12'N'#12#238#138

+  +#183#239#251#3#180'n'#27#218'l'#192'l'#225#212'?'#0#154'A6'#191'x'#242#210

+  +#133#144'v;j'#132#131'HAo)'#128#252#242')P>mw'#152#186#224#240#156'4'#27#216

+  +#234#159#224#212#255'('#170#255'd'#255#147#240'3'#251#191'y+'#218#255#155'Xn'

+  +#128#0#163':'#212'^aq'#145'='#216#129#178#216#140#143#17#1#176#8#0'.'#220#212

+  +';'#189#199#193#160#132'>'#9'@'#28#10#196#251#202#240#160#213#155#28'%'#143

+  +#196#19'2'#29'{'#18'k'#5'.'#135#194#9'{'#128#201'f'#227#205#0#174'.@AZ'#0#171

+  +#14#236'>)'#168#219#147#14#225#195#11#184#29#240#210#141#135#231'|^@~'#197'T'

+  +'8r'#217#179#131'z-E'#0#158#191'f_'#169#223#194#176#135'J'#171#135#165#167

+  +#222#2'U'#179#150'd'#252'\'#253#253#221#211#243'h'#177#140#199'x'#245'?'#20

+  +#129#128'7'#136#194#239#227#226#255#219''#132#128#167'-%'#2'Pd'#240'l'#201

+  +#211#249#182#163#28#186#144'8'#154#132'$ '#218#227#202#223'b0'#24'X'#8'p'#221

+  +#186'u'#20'7'#140'ww'#222#30#175#137'"'#1#223'}'#247#157'*'#16#8#232#208#20

+  +#176#161#9'P'#138'D0~'#155'3'#255#250'`T9C8'#4#249#1#172#165#211'Q'#229#170#2

+  +#163'@'#0'z'#13#168#132'h@'#182'T'#0#196#202'='#12'k?z1k'#231#27'('#232#179

+  +'8'#254#246'7'#192#152'W:'#168#215#7#189'Nx'#241#218#209#25#2#204#4#138#170

+  +'g'#194#129#23#220';hm,'#221'`'#222'Z'#253#163'Q'#8#163#250'O'#246#191#151

+  +'%'#0#249#161#5#237#255'h'#23#251#191#218#214#190'J'#173#136'R'#248#207#129

+  +'6R'#8#144#239#7'H'#154'@k$'#18'q{<'#158'Pw!@B'#175#4'@'#155#16#9#160#230

+  +#160#212#23#0#239#171'j'#246'ZNv'#5'uG'#8'O$'#2#208'['#202' '#175'b&'#18#0

+  +#154#1'f'#3'W'#23'@'#141'B'#217#200'0'#25'd'#205#14'@'#188#255#224'%'#208#176

+  +'ae'#214#206'7'#16'L'#156#191'?'#236'}'#214#29'C:'#198#147#23#238'.'#245#219

+  +#24'Q '#243'`'#223's'#239#204#138'6'#208#27'HB'#168#244'7'#30'E'#2#8#161#250

+  +#31#8#129#223#205#169#255'n{+'#180'o_'#197'Z'#131'u'#14#2#137#133'&'#229#181

+  +'}'#143#194#239#195'?'#237'|'#8#144#217#255#168#181#215#247#214#12'T|'#206'^'

+  +'?'#27#161'3'#144'^'#175'7'#1#31#9#240#132#212'{'#214'uX'#151''''#15'"''?'

+  +#128#22#138'''.b'#171'?e'#4#234'L|8'#144#175#13'`'#166'B'#22'?'#204'Wo>'#10

+  +#220'm'#245'Y<c'#223#160#216#255#25#247'}'#142#164'84'#219#243#169#139#23#12

+  +#203'v_'#185#12#234#251''#250#189#159#14#249#187#25','#18#252'?d'#190#10#222

+  +''#10#255#249'X'#7'`?8'#154'6'#131#167'u+'#155#15'('#20#1#153'5'#193#214'2'

+  +#147'k'#3#202#150#151'/'#3#174#23'"'#0#168#177'7'#4#131#193'^#'#0#132#190'd2'

+  ,'%'#18#160'T*'#11'('#18#128''''#154#176#177#189#232#238'xBf`OB'#225'&!'#167

+  +'&'#161#198#252'<F'#0'z'#150#22#140'f'#128#150#239#22#204'r'#2#178'G'#1#209

+  +#144#31'V,?'#20#213'(o'#214#206#217#23#22#157#180#28#166'/9z'#200#199'y'#238

+  +#138#189's'#234'}'#141#20#140#159#179#20#246'?'#255'niN'#158#224#230#255#177

+  +#226#159'p'#20'B'#168#254#7#188#1#240#241#249#255#237#181#171#248#177'l'#157

+  +'2\bto'#182'j'#253#212#253#199'ME@'#192'G'#0'('#17'H'#165'R5'#225#177'z'#141

+  +#0#16#250'$'#0'!'#18#160#209'h'#12#168'N'#144'#p'#28#158'`|'#141'3'#239#202

+  +'@T'#181'3'#247','#25'('#228'r0'#21'V'#131#173'l2'#232'id'#184#5#9#192#160'e'

+  +'Z'#128#156'z'#4'p'#163#131#179'i'#9#160#6#208#0#175#221'|tN'#172#150#187#31

+  +'s'#25#204': ='#13'L'#158#191'b_'#8#249'r'#183'-'#250'p'#198#239#151'?'#195

+  +#252#2'Y'#5#231#250#231#212'J'#254#9'E '#228''''#245'?'#0'~'#150#0#228#134

+  +#214'-_A'#12''#199'b'#7#224#196#188#182#31'T'#242#152#155'w'#0#178'" >'#3'p'

+  +';'#202#27#253#221#209'S'#17#144#128'~'#17#0#213#4'x<'#30#180#2#244'Vr'#4'"'

+  +#17'T5{'#244'G8'#2#198'dA;'#9#184'Zg'#132#162#137'{2'#2' '#13'@'#199#178#2'5'

+  +#172'6@'#208#2#178#146#27',B'#243#230'5'#240#254'}'#23'B4'#18#202#234'y'#197

+  +#216#237#168'K`'#246'Ag'#164#237'x/\'#181#31#174#6'C'#155'~3'#134#238'A'#157

+  +#154'N'#185#247#163#172#159#151#171#252#227#212#255'p0'#12'Ao'#144#9'?'#173

+  +#254'T'#244#229'j'#222#200#156#131#130#253#175'VD'#253#19#243#236'?'#226#223

+  +#148#17#230'@'#18'`'#14'@'#222#254#167#134' }:'#0#9#253#145'F9'#146#128#18'I'

+  +#128#210''#205'h'#10#20'#'#9'T'#198#19#138')'#155#157#133#183''''#18'2V'#149

+  +'A'#194'M'#13'B'#10'*'#231#161#25'P'#8#6#19#18#0#211#2#136#0'T'#160#16'*'#4

+  +'3<B'#188';'#132#253'^x'#235#174'3'#192#217#152#253#230'!'#187#29'y1'#204'9$'

+  +#189'C%_'#188#250#0#252'q'#180'g'#253#189#140#22#28'}'#211'K'#144'_'#153#165

+  +#161'.'#178#4'_'#247#207#173#254#156#250#31#130#128''''#192#28#128#20#5'h'

+  +#223#246'='#254#237'J'#177#255#11#244#190#218#2#189#135'B~^'#20#254'v'#222

+  +#254#23'j'#0#26#250'J'#1'N'#158#190#31#151#200#28#129#249#249#249'j'#161'='

+  +#24'%'#4#145#31#160#182'#'#239'|D'#205#244'%'#230#228#195'U'#222#148'W'#9'y'

+  +#21#211'Q'#11#224#252#0',+PK%'#194#157#206'@.'#190#144']'#18' |'#243#242#221

+  +#240#203#199'/C6'#146'h'#200#169#180#224#164'e0u'#241#145'i?'#246'KW'#31#4'>'

+  +'gK'#198#223#195'h'#197#180'%G'#193#226#211'o'#202#206#201#184#170#31#142#0

+  +#248#216''#208#23'd'#130#207#212''#167#19#9#224';'#212#12'"b'#251'?1)'#191

+  +'}'#21#170#255#228#8'"'#251#159#26#129#214'R'#248#15#23'h'#234#1#208#136#194

+  +#239#232#203#254''''#244'G'#10#153'#'#16#15#166'"?'#0#10'p>'#158#168#140#252

+  +#0#206#128'vi'#179#215#194#21'h'#147'#PFf'#128#14#205#128#5#140#0'H'#3#224

+  +#162#1#252#244'`j'#24'*'#151'u'#27#17#200#240'P'#225'$'#26']'#9#31'>|%D'#130

+  +#190'L|'#157'L'#203#153#186#232#8'Xr'#234#13'd'#23'e'#228#28'O'#253'a7'#246

+  +#131#24'Cf`*('#131#19#239'zw'#200#199#233#235'7-<'#206#21#254#196#208'LE'#2

+  +' '#231#31#18'@'#160#131'['#253#157'M'#155#192'M'#222#255'h4'#169#254#235'U'

+  +#225#142'J'#139'c'#29#202'Q'#0#239's'#1#215#4#164'V'#176#255'qk'#17#154#128

+  +#160#240'G'#249'S'#13#158#0#186#250#1#144'eJ'#240'~'#234#215'\'#189#201'Q'

+  +#180'<'#22#151'S'#136#144#17#0'e'#255#217#202'g'#130#185#176#140'#'#1'3o'#6

+  +'h'#133#204#192#206'nA;'#148'Bw'#185#154'L'#182#186#219#248#191'7'#224#199'w'

+  +#159#2'O['#250'Zj'#149'M'#155#15#251'^xOF'#139'Q'#234#214'~'#9#31#220'?z:'#1

+  +'I'#1'J_?'#231#137#31#134'D'#224#221')'#184']'#207','#251'/'#193'y'#254#185

+  +#213'?'#138#230'j'#136'y'#255'I'#253#15'P'#243#143'-'#223'@'#200#239'I'#137

+  +#255#151#24#221'[l'#186#0#165#249#250#241'>'#150#0'$'#148#0#227#177#234'PKo'

+  +#235#143#253'/\C'#192#252#0#168#5'h'#220'n'#183#5#217#165#8'OXIf@'#131#219

+  +'r'#130';'#164#221#141#29#140#198#131'+'#20#172'8('#175'j&o'#6#232#144#0't'

+  +#160#210#169#147'Z'#128#16#17#200#5'8'#27#182#194#183'/'#255#5#26'~]'#201#134

+  +'F'#14#4'T'#133'f-'#29#15#19#230#239#15';'#239'2h'#12#153#207'&{'#239#238'?'

+  +'@'#195#250'o'#165#250#184'F'#13#246#189#240'n'#168#222#245#128#140#158'#!'

+  +#168#255#148#249#23#137'B4'#200#169#255'd'#255#7#220'T'#252#211#10#142#237

+  +#171'!'#134#143#197#249#231#202'e'#137#216#228#252#182#213'2'#136#7#248#248

+  +'?9'#131'X'#252#31#229#170#6'o7'#160#156#182'['#173'V__'#246'?'#161#223#4#128

+  +'f'#128'\'#156#15#128#251'rd'#155#9#193#152'v'#238'v'#151#237'\v02'#3'P'#184

+  +#149#26'5'#20#146#25'`6'#161#9#192#145#128'Z'#199#229#4#144'/@&'#242#5#236

+  +#176#234#15#225'"'#135#2'R'#177#234'~'#254#10#26#214'}'#11'm'#219#214'1'#205

+  +#128'&'#203#138#175#130'VvKq'#5's'#16#149'M'#159#15'e;e?#'#239#233'sw'#131'h'

+  +'X'#186#136#198'hA'#213'.K'#225#192#203#31#24#212'k'#251'j'#132#155'L'#250

+  +#137'sC?c'#164#254#211#234#31#8'A'#136#188#255'l'#245'G'#245#191'a=x'#237#245

+  +')'#225'?'#179'&'#216'^fr'#209#196'W'#26#11#228#22'*'#0#137#0#132#30#128#129

+  +'@'#192#137#230'z'#159#246'w'#215#214#227#243#132'|'#0#178#1#168'0('#26#141

+  +#150'Q8'#16#31#155#176#197#145'a8'#166','#226#252#0'\4'#192'R6'#13#204'EU,$'

+  +'H~'#0#202#9' -@'#201#198#135')'#144#4#184#196#160#28'Q'#4#134#5'>z'#248'*'

+  ,#216#246'}'#246'CT'#163#17#182#242'Ip'#236#31#223#200#216#241')'#233''''#17#3

+  +'V'#214'M+<e'#254#133'|!'#8'2'#245#31'5'#0#175#31#218#182'|'#9#225'`0%'#252

+  +'Wnv'#254'j'#210#132#169#243#15'i'#0#20#11'n'#166#30#128#148#2#204#183#3'o'

+  +#161#30#128'F'#163'1'#216#151#253'O'#232'7'#1#8#133'Ah[h'#145'e'#168'.'#160

+  +'D0'#3'Z}'#166'C'#28#1#195'^'#236#137#188#25'@'#241#212#252#170#249','#10'@Z'

+  +#0#17#128#218#160'a'#218#1#27#30'"'#20#9#245#196#0#217#152'0:'#140#176#253

+  +#199#207#225'?'#247']"'#245'e'#140#26#232','#5'p'#202'C'#3#236#217#216#31#245

+  +'5'#1#201#142'?$'#216#204#249#199#135#254'h'#245''''#2#8#184#131#224'io@'#13

+  +#224#231#20#245'_)'#143#135'Q'#253#167#216'?M'#195'a'#249#255#184#177#22'`'

+  +#212#2#156#230#0#226#194#220'F-'#192#236'v{'#184'/'#251#191#187#203#235#13')'

+  +#29#130'h\'#24'2M9^'#204#248'h\9m'#139#163#224#194#4#249#1'y3@'#161'V1'#2'0'

+  +#216#242'QuF'#13#128'i'#1'd'#6#16#9'(QK'#16#21#9#141#169#1#189'"'#26#244#195

+  +#11#23'-'#193#31'Jp'#232#7#27'C'#191'@'#181'-g>'#249'C'#250#15#156#224#226

+  +#254'@'#158#255'8'#231#249#143#6#195','#243#143#169#255#168#250#19#9#216'kV'

+  +#163#25'`gY'#172#130#250'o'#211#249#27'K'#140#30'R'#247#131'|'#250'/'#27#3'F'

+  +#241'R'#255#169#1#8#154#19#142#190#242#255#197#24#136#228'%'#195#129'V'#171

+  +#213#24#12#6#169'Sp'#25#17#0#238#171'j'#156'yg'#4#162#170'*'#193#12#160#162

+  +#10#163#173#4'l'#21#179#144#0#180'<'#9'hy_'#128#154'9'#3#169'T'#24'dBX'#176

+  +#135#14#194#144'$'#205'~^e'#250#191'3)A~'#136#215#151#31#1#174#198#209#212#2

+  +'\zP'#133#224'9'#207#241'c'#214#135#26#141#226#139#253#19#252#129#216#234#207

+  +'l'#170#250#139#176#208#31'9'#255'H'#240#131'H'#0'>G'#27'8jWC$'#28'I'#241

+  +#254'O'#176#182#175#213#170'b'#30'R'#255#241'O'#23'5'#0#1#222#254''''#239'?'

+  +#223#16#164#163#183#6' '#221']Z'#191#223#134#16#14#164#254#0#248#183#21'U'#13

+  +#150#21'H='#2':'#130#186#5#141#30'3+'#17'f'#177'~'#185#2'Tj5'#20'T'#239#10'z'

+  +#139#141'E'#2#136#0'4d'#10#176'f!*'#166#5'0_'#128#140#159'(<'#194#132'w'#168

+  +#160#130#159#215#151#253#14''#16'cI?'#217#134'B'#165#129#179#158']'#157#222

+  +#131#242#131'>'#133#142'?'#204#246'G'#2#8'3'#225#231#9#0#247#142#186#159#192

+  +#239'la'#142'iA'#253#215#169'"'#238#241'V'#199#175#188#250'O'#9'@'#164#254

+  +#179#240#31'%'#255#144#250'O'#225'?\'#160'='#253#9#255#9#24#16#1#208'&'#152#1

+  +#8#19#153#1#148#21'H'#4#128#143'Umu'#22#156#25#142')'#11#133'.A'#20#247'7'

+  +#228#149#129'm'#220#206'I-@C$@CDY'#179#16'!/'#128'F'#137'e?E8'#151'AQ'#136'7'

+  +#174';r'#172#234'O"'#168'tF8'#227#201#244#246#148#16#135#253'('#238'O'#158

+  +#255'H'#16'U"'#0#15'n>'#170#254#179#163#250#191#10#205#189'0'#243#15#8#234

+  +''#185#217#185#193#168#14#145#211#143#169#255#192#13#1#173#23#17'@'#147#160

+  +#254#163'lF'#250#10#255#9#24#168#196'13'#160#176#176'PE#'#195#168':'#144#6

+  +#134#224#133'T'#145')'#224#10#234#23'4{'#205#7#2#175#210'S'#21' '#211#2#198

+  +#239#14':'#139#5'4F'#29's'#10#170#13'|'#207'@'#181#138'=G!'#231'g'#9#202#248

+  +'K'#234'O'#154#224'`'#223#193'0@'#235#166#159#224#223#183#159'6,'''#31#143#20

+  +'h'#205'yp'#234'c_u'#255'`_b'#213#205#239#151#21#251#240#163#190'H'#176#227

+  +#201#213#191#211#249'G'#171#191#179#254'g\'#253#155'8'#231#31#175#254'k'#149

+  +#17#239'x'#171'}='#10'{'#132#138''#200#251'O'#237#191#240#200#181'|'#2#16

+  +#169#255#164'&v'#168'T'#170'`w3'#0#251'{'#169'}>_0'#3'('#26#128'['#168'K'#16

+  +#158#188#130#8#0#168'm'#184#179#240#244'HLa'#21'j'#3#148#168#234#27#243#202

+  +#193':n:'#168'Q'#11#160#193'!D'#4'j'#22#18'$'#18'P'#240'aA9?V|'#16'W5'#130

+  +#176#229#235#247#224#243'G'#174'a'#182#223#24#164#3#133#1#143#190#251#157#244

+  +#28#140#15#252'S."'#202#175#254'h'#223'G'#130'a^'#253#15#176#172#191'@'#135

+  +#19'W'#255#239#185#213'?'#130'$'#193'1'#7#140'3w'#252'f'#214#4')'#244#23'F'

+  +#185#242#240#201'?'#228#253#167#240'_'#13#202'"'#205#4'l'#31#136#247'_'#192

+  +'`D-'#165'8'#8#184#193#161#204#25'H'#154#128'#`X'#208#234'3-'#21'F'#131#145

+  +'3P'#169#209'@'#225#132#221'@k'#178'0'#19#128#242#2'Th'#6#8'Z'#0#171#20'Lv'

+  +#16#150'%'#157'&'#253'm$:R'#176#254'?+'#224#235'g'#239#200'l'#14#244#24#250

+  +#133#233#251#159#8#11#207#186'eP'#175'M'#249#221#242'!?'#230#253#143'q'#5'?'

+  +#156#237#31#134#8#31#250#163#212'_'#218';'#27#214#129#223#209#8#209'H$'#25

+  +#251#215'('#162#254#9#182'v'#234#250'K1}'#10#3'Q'#247#223#22'~'#213#175#193

+  +#191'k)'#249#167#175#246#223#189']'#235#128#223#159#208'-'#24'm'#13'='#178

+  +#143#141#204#0#188#191#146'i'#1'2Y'#229#22'{'#193'I'#145#184#194#196'r'#2#228

+  +#10'P'#170#149'`'#200#175#2'k'#233'T\'#253#181'H'#2#168#5#232#185#196' V)H'

+  +#179#4'),'#168#232#140#10#176#19#245#148'" zk'#178#228'?'#195#27#171'^{'#8'V'

+  +#191#254#176#212#151'1'#6#30#135#223#186#2'J'#166#207#239#246#177#148#223'_/'

+  +#191#189#4#223#232'#E'#245#167#213'?'#24'a5'#255#17'?'#231#252#11#177#216''

+  +#7#180'o['#9'Q$'#6'z'#14#181#6#163#215#149#153':'#182'X'#180'A'#154#248#19

+  +#225'{'#255#145'&@+>'#9'>'#133#255#234'q'#223#170#211#233#220'='#13#0#237#13

+  +#131'"'#0'J'#10'B'#150'a'#205'B'#3#129#128#153'J'#132'c'#177'X'#5'e'#6'rZ'

+  +#128#17#181#0#227#158#130'3'#144'T|'#138#255#231'O'#216#3'W'#19'G'#2#212'4T'

+  ,#207#151#10#147'CP'#221#233#16#148#241#166#128'l'#7#233#30#204#202#152#251

+  +#236#240#213#147#183#192#175#31#189','#245'e'#140#129#7#253#6#207'~'#249#215

+  +#129#190'Jt;'#145#12']'''#189#254'd'#207'Gx'#199#31#173#254#254'P'#210#251'O'

+  +'{W'#227#175#224'u'#212#177'~'#0#148#31'@i'#194'jE4Pmk'#251#5#229'!'#138#199

+  +#160#252'o'#15'nT'#250'['#207''''#255'lG'#217'#2p'#244#167#246#191#175#171#30

+  +#208#187'%g'#160#201'dR'#163#218'a'#196#191'Yj0'#229#3#224#237'*|'#175#228#11

+  +'8>'#154'P'#232#153'3'#16'Ww'#188'P0'#20#146#22'0'#133'9'#1'Y8'#144'6=_)H)'

+  +#194'h'#6'P'#18#145'L('#22#202#206'lQIa'#175#217#0'o.'#251#157#212#151'1'#6

+  +#17'J'#166#205#135#195'niH'#199#232'n'#245#143#161#240#179#184'0'#196'9'

+  +#255'|A'#206#1#232'qC{'#205'w'#168#25#132'x'#207'?'#183#250#151#24#221#219

+  +#172'Z'#155#200#249#151','#253'%'#225'GY'#169'C'#185'k'#182'Z'#173'.'#148

+  +#195#192'@'#156''#2#6'M'#0#130'3'#16#153'G'#231'r'#185#200#233'W'#140#23'T'

+  +#1'\'#153'pe'#155#207#184#208#30'0'#206'Kj'#1'H'#2'*'#141#22#242'(='#216'bE'

+  +#2#208'$'#137#128#180#3#133'P($T'#11#138#251#6#140'`'#22'x'#251#250'c'#161'u'

+  +#211#26#169'/c'#12'"'#28'q'#215#155'PP'#189#243#160'_'#207#249#252'D'#141'>H'

+  +#168'#'#188#227'/'#192#173#254'L'#248'}AF'#4#174'z'#180#253#157'h'#251'S'#211

+  +#15'z.'#190'T%'#139#134'&'#230#183#255','#227'l'#255#16#18#0#139#253#163'l4'

+  +#144#240#227'mr'#0#178#206'?]b'#255#253'V'#255#9#131'&'#0#232#146#19#128#23

+  +'H'#163#195'h'#0'[%nU1'#210#2#28#133#199#198'P'#180#217#160'p'#210#2'P'#192

+  +'u'#150'"'#176'U'#204'fu'#1'I'#2'`'#14'A$'#1'V.'#204#153#2#192'L'#7#254#242

+  +'Fh'#170#176#223#217#10'/'#159#183'p'#204#233#151'C0'#20#148#194#9''#255'b'

+  +#208#175#151#241#169#190#204#8#136'w'#198#252#185#130#31'A'#245#199#205#31'`'

+  +#197'?'#1#23'e'#253#173#225'<'#255#209#206#213#191#216#232#169#177'i}'#173

+  +#252#234'O'#153''#212#5#150'B}'#245'T'#246'KN@Z'#253#145#0#156'~DSw'#184

+  +#222'!|V'#201#10'A'#179#217#172'#g '#222#199'B'#130#184#175#162'=j'#1#11#218

+  +#253#134#185#204#169'Ge'#194'D'#2'j'#13'X'#199#205#0'}~)S'#255#213#6#29#211#6

+  +'Tz'#13#31#22#228'{'#6'$'#253#1#248#142'd'#217'm)'#158'-|'#244#231's'#161#246

+  +#135'O'#165#190#140'1'#136'p'#240#205#207'C'#217#172#133#131'|5'#159#236#203

+  +#219#253'B'#177'O'#156#217#254#188#234'O'#4#224#193#149'?'#192#217#254#142

+  +#237'?@'#200#211#193'&'#1'1'#2#192#255'T'#242'hp'#162#205#142#182'"'#202#135

+  +#254#216#234'/'#196#254#129#235#250'['#143'2'#215'N'#206'?'#170#252#235#173

+  +#243'oo'#24#18#1#144'3p'#221#186'u'#172'QH '#16'0'#161#6'P'#128#23'Im'#195

+  +#153#22#128'W2n'#155#179#224#247#225#184#202'"h'#1#148#2#172#209#27#208#20

+  +#216#13#212#148#19' '#242#5'(u'#184'Qr'#16#159#27' h'#2'2'#161#157'xOq'#193

+  +#158#222'E'#142'/'#172#207#158#176#19#174#12'c'#181#253#185#130#202#249#251

+  +#192#254#215'='#193#253'1'#136#223#148'X'#248'i'#229#135'8'#151#238'K'#142'='

+  +#177#227'/B'#234'?'#222#246#180#214#128#167'e'#243#14#171''#185#197#181#209

+  +#168#10'R'#184#143#250#190#177#208#31'n'#173'(_'#245'|'#209#15'%'#0'5S'#230

+  +#31'j'#224#254#193'8'#255#4#12'uYMf'#6':'#28#14#189'R'#169#180#225'E'#22#227

+  +'F'#137'AL'#11#240#133'5'#211#235#220#182'}'#4'-@'#193#180#0'5'#24#11''''#128

+  +#185'x"'#175#5'p$'#192#180#0#161'u'#24#223'>'#172#147#4#248#203#29'A'#138#192

+  +'sD'#0'c'#21'~9'#1#26#22'z'#242#243#171'Q'#251'T'#15#238#0#188#25#215#185#242

+  +#243#170''#152's'#252#145#131#143#179#253#3#16#246'"'#17'x=,'#233''''#18#12

+  +'B'#140#250#253'E'#185#196#31#20'|G'#133#197#181#5#15#21#19'V'#161#237#23

+  +#169#253#192#245#252'k'#224#203'~'#221'}'#245#253#239#11'C&'#0'A'#11#160#182

+  +#225#168#9#144'/'#160#0#137#128#249#2#144#8'H'#19'(k'#240#216#246#246#132#181

+  +#149'r'#150#29#168'`5'#0#10#10#11'V'#206#3#141#201#10#26'#g'#10#168#146#17#1

+  +'5'#243#7#176'b!'#218#152'#'#145'+'#27#30'I'#166#192#138#211'v'#129#144#215

+  +'%'#245'e'#140'zP'#225#218#161'w'#188#10'E'#211#230#13#234#245#9#174#212#143

+  +#247#250#199#217'l'#191#4#223#230'+'#30#140'$W'#138#251'3'#199#31#222'v5'

+  +#252#2'AWK'#202#234'/C'#218#168'F'#213'_)'#143#134'zZ'#253#5#207'?n'#142#254

+  +#182#253#234#245#189#167#227#243#19#215#7'h4'#26#214'4'#148'O'#15#166#188#128

+  +#242'h\^'#177#213'Yxp'#2#215'uA'#11'P'#168#212#160#181#20#176'ra'#181#174'S'

+  +#3'P'#11'Z'#0#229#6#8'Q'#1#190#155'0'#136#202#134'G'#130'_'#240#213's'#22#130

+  +#175#189'Q'#234#203#24#213#160#197'e'#191#27#158#132#10'T'#255#7#140#132'x'

+  +#166#31#231#244'#Afv?'#173#252#225#8'K'#250#137#6'B'#172#221'W'#132#247#250

+  +'S'#165#159#139#154'}'#160#240#211' '#16'a'#245'/'#212'{'#234#10#244'>'#10

+  +#243'u]'#253'i'#236'7'#181#253#222#142#130#223'@UH'#8#238#129#230#253'w'#251

+  +#254#211#241#25'v'#213#2#240#194#10#132#136#128#160#5'8'#2#198'9'#173'~'#211

+  +'l'#210#2'@'#161'`'#14'A'#5#154#2#150#178#157'@'#159'W'#202#146#130#152#240

+  +#147#22#160#227'H'#128#181#15'S'#241#237#196'EY'#130'2y'#186'.]Z'#252#235#210

+  +#3#193'Y'#187'Q'#234#203#24#189#192#223#210#146#203#255#10#19#247#26#194#236

+  +#6#22#231#7#214#224#143#229#250#243'N'#191'X'#132#19#254#8#175#250'G|'#156#6

+  +#16#246#243#142'?'#159#155#21#4#9'q'#149'<'#26#168#206'k_'#143#199#139#241

+  ,#171'?y'#254'Y'#213#31#173#254#184#175'U('#20#181#180#250'k'#181'Z'#7#146#192

+  +#144'W'#246#17#164#235#163#236'N'#11' _'#0'p'#17#1#26'$R'#180#213#153#191''

+  +'8'#166#178#10#217#129'$'#220'j'#189#145#229#6#168#13'z.)'#136'O'#17'V'#178

+  +#220#0#222#20'`'#141'D'#249#14'Bra'#196#24'$'#213#128#225'J'#5#31#222'r24'

+  +#174#249'R'#234#203#24#149' '#13't'#191#27#159#134#178'9'#139#7#252'Za'#213

+  +#231#179'}x'#187#159#19'~Z'#209'i'#245#143#133'"'#201#176#31#229#252'GI'#248

+  +'q'#239'i'#217#10#222#214'm'#140' '#152#237'O9'#255#248'_'#165#217#177#193

+  +#160#14'S'#166#31#9'4y'#134#133#145#223'Md'#251#147#240#163'L'#213#167's'#245

+  +''''#164#141#0#186#243#5#0'7H'#180#146#15#13#150#249'#'#234#9#181#238#252'%l'

+  +#29'Wt'#154#2#134#252'r0'#151'N'#229'j'#3#152#6' r'#8'R'#247' '#149#146'+'#24

+  +#18#154#137#178','#193#225#239#24'l\'#243#5#252#231#230#147#165#190#140'Q'#7

+  +'CA'#25#28'~'#223#187'h'#130#230#15#252#197#157#195'y:'#139'|'#226#156#205'O'

+  +#182'?'#173#234'L'#245#167#132#31'a'#245#199'-'#26#8#254'{_'#22'kYv'#158#181

+  +#246'x'#230's'#238'XsWwW'#187#219'v'#187#227')'#241#0'v'#136#193#145#8#194'F'

+  +#8#5#148#4')'#145#176'P'#132#132#20#241#18'!9'#188#0'/H'#188'!'#224#1'x'#2#9

+  +#17#144#128'XHH$`x'#128#7#144#172'$'#216#198#221#158#186'k'#174'[w:'#243#176

+  +#7#254#239'_'#255'Z{'#237'}'#207#173#186#213']w'#170#190'K'#218'w'#15#247#12

+  +#251#236#189#191#239#159#255#165#166#253'='#181#243#222'wT2'#155#209'k'#23'\'

+  +#25#8#159'A;'#158'n'#223#232#238#161#229#19#192#159#152#184'?:'#254#162#230

+  +'_'#233'Yn/'#145#254#0#255#7'*'#27'}'#158#208')E'#4#136#173'V'#137#165'.'

+  +#139#22#128#174'A'#215'Q:|o'#208#251'b'#214'x'#153'+'#255'B"'#129' d'#144

+  +#247#174#146')'#176'zUH@'#8#160#225#248#3#184'V@'#155#2'l'#14#248#158'T'#15

+  +#150'I'#158#23'?'#201#243#206'x'#28#144#198#191#254#181'O'#169#217#197'D'

+  +#159'''3'#232'ay'#245#203'_S'#191#240#219#255#248'H/_'#250','#229#198#225'/'

+  +#137'>'#22#252#186#208''''#227'2_m'#247'c'#129#218#191#24'C'#19#152'p'#155

+  +#175#249#184#207#182#191'Q'#253'=z'#247'k'#171'['#28'x)'#138'}JY'#180'_<'

+  +#255'h'#251'u'#239'yK'#254']'#207#243#242'.'#203#11#160#31'q'#21'~'#0#163#5

+  +'dyp'#229'G{'#27#191#152#229'~'#13#0#246'E'#11#136#234#13#181#242#210'gT'#173

+  +#211#213'&'#128#144#0#182#131'Z'#173'0'#5#196#31'P'#174#28'<'#191'Z'#192'w'

+  +#254#229'?P'#244#187#23'U'#128#199'=z/}D'#253#153'o'#254#11#213#189'~'#235

+  +#253''#8'W'#248#228',ssW'#242'['#187#159'l'#250#217'\KV'#253#167'"'#253#231

+  +'j'#255#222#247#213'd'#239'>{'#253'a&(N'#249'e'#199#223'{'#235#205#17'z'#251

+  +'C'#250#163#3#12#247#251#163#5'Y'#128','#253#197#7#240'p>'#159#239':'#158#255

+  +#15','#253'1'#158'7ll'#227'Pd'#7#146#22#128'9'#178'.!'#18' Q'#1#172'/'#239'O'

+  +'ko'#220#31#174'~'#206#19#135#160'1'#5#226#246#138'Z}'#233#211'l'#2'@'#250'G'

+  +'-q'#8'J'#243#16'?'#150'Ta3'#211#176';'#229#184#167'='#186#207#214'A'#244#244

+  +'G'#150#204#213#191#250'K'#175'?'#243#172'D'#23#227'h'#163#181'y]'#253#220'_'

+  +#251#166'z'#229#231#223'g'#193#149#17#252'z'#30#175#178#211#15#246#187#145

+  +#252'H'#248#129#228'g'#2#152#217#176#31'r'#255'G'#219'w'#200#246''#135'$'

+  +#255#140'I"Ou'#185'o=\'#244'_'#233'm'#191#157#231#252#137'\'#239'o'#26'~@'

+  +#250#211#254'm4'#251#132#244#199#12#192#181'Z'#13'>'#130#217'Q'#27'~'#30'e<w'

+  +#2'0'#165#194'd'#10'`'#18#145'6i'#2'0'#180#174#144#9'pC'#180#0'D'#7'6'#239#15

+  +#186#159#221#159'7_e5'#222#15'X'#186'C'#213'o'#174#222'P'#157'+o'#20'Z@C'#155

+  +#2'Q'#3#25#130#226#15'0'#165#195#156'#P'#20#14#217'_t'#206'b'#132#255#229'w~'

+  +'U'#221#255#206#255'8'#237#211'xq'#6#221#255#205#143'~V}'#254'7'#255#158'Z'

+  +#227'S'#31#236#179'rG'#245'W'#134#0#164#179'O'#166#139'|'#24#252#28#242'+'

+  +#164'?l~'#238#246#219#223'U'#251'w'#255#144#247'a'#247's'#216#143#136#195#247

+  +#211#197#173#149#199#223#13#253#12#30#255#212#244#250#151'v_'#8#5'b'#210'J'

+  +#164#253#222#165'}h'#3'{'#200#249''#150'~G'#186'T'#199'q'#249'M'#195#144'$'

+  +'I'#26'q'#28'w'#137#197'6'#209'5'#8#254#0'D'#4#232#7']'#165#179'_w'#227#203

+  +#179'$^'#209'*'#189'N'#19'F'#135#160#238#213#143#171#230#218#21#142#4#128#4

+  +#160#1#128#8'8*'#0#240#219'.B'#1#147#7#28#131'6G'#192'w'#136' '#247#158#173

+  +#155#0#212#187#252#228#201'c'#255#246#15#213#239#253#141'_'#184'('#10#250#128

+  +#195'''-'#242#229'/}M}'#238'7'#255#174#170'u'#215#138''#28#225#190'.}N<'#29

+  +#232#231#2#31'%'#157'}8'#214#159#234'L?'#168#252#0#255'L'#171#254#139#169#145

+  +#254#180#158#234#148#223#221#219#223#161#253'>'#251#6'x'#138'/'#237#248#203

+  +'otw'#223'i'#199'3'#132#249#172#227#143#176#129#164#159'-H|'#241#252#179#227

+  +#143'0'#180'3'#164#177#183#183'7{'#214#134#31'O'#27#199'B'#0'J*'#5#209'6'#140

+  +#206#187#213'h4`'#10'\VZ'#250#223#148#245#165'E'#26'\!'#18#248'R'#166#194#136

+  +'I'#128#147'~"'#235#15#136#219#29#173#1#136'C'#16#25#130'a='#226#181'o'#138

+  +#134'l'#142#128#152#3'b'#18#148#148#128'e'#191#242#164#177#246#148'+'#253'?'

+  +#255#225'o'#169#31#253#193#191'='#225#147'z1'#6#188#249#31#251#139']'#253

+  +#204'_'#254#155#207'>'#163#239#147#158#13#145#250#182#194#207#218#252#162#250

+  +'/t'#184#143#19'z&s'#209#0'D'#253#167#237'>'#236#254#253#251#252#154'<Ix'#14

+  ,'@'#152#14'k'#141#209#189'K'#205#193'=Q'#253'M'#216#15#234#253#142'8'#254'P'

+  +#241#7#231#31'&'#250#216'B'#193#207'h4'#154'<k'#187#175#247#251#243#159#203

+  +#231#154'~'#1#180']CX'#144'~'#216':'#28#130#240#3#208#177#155#178#189'1X4_'

+  +#185'7'#232'}'#6#0'F'#251'0'#246#7#144#132#143#218#171'j'#229#198#167'8"'#192

+  +#154#0#231#6#196#188#246'k'#210'@'#132'5'#6#9#15'J~'#128#206#24#244#139'l'

+  +#193'\'#251#7'Nk'#210#209#163#14'<\'#191#251'W>'#174#230#163#254'i'#159#202

+  +#185#25'+/T}'#246#27'G]'#255#220'W'#223#215#251#151#206'>g5'#254#188'P'#251

+  +#179'\l~'#29#235#207#165#188'W'#199#251#181#218#159#10#248#19'&'#130#153#26

+  +'o'#223'S'#253#135'?`'#211' [,'#172#215#191#17#206#251'/'#147#221'/'#223#4

+  +#213#31'&'#192#152#22#132#130#224#12#180#170'?-'#152#231#15#14#193#145#211

+  +#236#243#185'I'#251#155#143'iX'#135' &'#20'%'#192'cZ'#241'Mt'#14#130'/'#0

+  +#166#0#189#230#10'-k'#15'G'#189#183'v'''#205#151#141'w_;'#250'b'#213'\'#135

+  +'?'#224'u'#21#213'$1'#168#17'["'#240'M[q'#19#30#180'='#5'i'#9#138#217#134'r'

+  +#201#21'8'#15'n'#129'{'#255#231#191#169#255#250';'#191'z'#218#167'q'#166'Gs'

+  +#253#138'z'#233#203'_S?'#243'+'#191#165#234#171#155#207#245#179'M#'#15'//'#8

+  +#0#21'}'#153#16#0#219#253#146#230#11#149#30'E> '#0#150#254#0#255'Tk'#1#179

+  +#193#158#218#187#253#135#244#191#194#238'W'#176#251#189'd'#241#234#202#246

+  +#247'B'#178#255#149#168#254#180'L'#137#4'0'#203'/:'#253#222#147'f'#159'w$'#1

+  +'h'#219'8'#254#158'W'#216#175':'#142#149#0#224#16#252#214#183#190#197'MC'#136

+  +#201'Z'#244#195'`'#152']'#22'-'#0'$pM!J'#160#188#149'w'#247#214#190'0Kk=eH'#0

+  +#210#157'H'#160's'#249'5'#186#233'/IRP'#205'j'#1#8#13#194#28#240'b'#157'#'

+  +#160#195#131#18'"4'#25#131#158''''#10#192#249#9#19#254#254#223#254'e'#245#240

+  +'";'#176'4'#26'kW'#212#205#159#255#154'z'#235#24'@_'#26#206#196#157'6'#209'G'

+  +'&'#241#204#165#161'g.'#177'~V'#253#167#218#238'O'#5#252')'#183#249#30#178

+  +#211'o1'#30'j'#233#159'&'#186'4'#152#237#254#189'w'#218#209#180'oTz>9'#230

+  +'Ok4'#250#228'f'#31' '#0#244#249#203#178#12#190#128#253#227'p'#252#185#227

+  +#184'aa'#29#130#244#163'j'#164#1'tMn'#0'H@'#136#0#29#133#215#147'<'#218#248

+  +#233#222#250#23'3'#130#189'q'#10#194#31#0'{'#191's'#245#227#170#209#187','

+  +#192#143#181'?'#192'5'#7'b]>\'#20#14'A'#11#208'D'#144#151#10#136#156#159#251

+  +#164'_~'#18#254#129'C'#190#31's'#1#254#222#175'A'#141#30#221'9'#129#147'8'

+  +#187#163#177'vYK'#250'_'#251'['#31#12#244'O{'#194#141#202#159#231#142#237'o'

+  +#192#159#217#226#158'\'#178#252'8'#140'7[X'#192'C'#242#167'Sc'#255#143#9#252

+  +''#164'f'#163'}Q'#253#19#235'7Xo'#142#238'm6'#251#144#240#244'Hz'#166#216'g'

+  +#12#144'#'#227'O'#21#210#255'.'#225#4#181#254#187#180' '#230'?'#251#250#215

+  +#191#158'>O'#199#223#179'\'#158#231#241#249#236#16#188'v'#237'ZD?'#166'I?'

+  +#142'M'#1':~]'#242#2#224#16#132'V'#176#218#159'7n'#222#31#174'|'#138#253#1

+  +#220#16'$'#212#243#6#196#177#234'^{K'#213'z'#235'L'#0'69'#168')'#249#1'5m'#10

+  +#232'D'#161'P'#207'1`'#252#2#158'8'#6#13#1'x:'#195#235','#155#4#217'|'#170

+  +#254#227'o|^M'#182#31#156#246#169#156#232#208#160#255#243#234#19#4'zl'#31#247

+  +'0A'#23#207#216#251#210#196#147#255'!'#192'5Y~'#185#128#31#146'?'#19#181'!$'

+  +#144'Ng'#236#245#239#223#253#174#154#13'w4'#248#209#223#15#170''#134'x?'#236

+  +#254#157#183#229#27'!'#253#145#245'7'#161#239#178'1I'#246'A'#143'?T'#254'm#'

+  +#227#143#204#229#217'q8'#254#220'q'#18'0`-'#128#214#193#189'{'#247'0'#181'x'

+  +#11#141'C'#148#6#189'!'#1#248#5'6i{e{'#210'}'#227#241#164#253#154'.'#24#242

+  +#25#208' '#129#176#214'P'#221#171'oq'#255#128'@'#204#129#192#248#3#140'S'#208

+  +'!'#1#27#29'p'#27#140'B#p'#253#1'v6'#226#167'\'#134#147'L)'#150's'#193#148

+  +#224#223#250#245#159'S'#211#189#173#147#251#238#19#30'A\S'#221#151'^W'#215

+  +#190#240#139#234#245#191#240#13#213'XN'#160'?'#202#253't<'#253'&'#191'7wm'

+  +#254#212'H'#254#2#252#25#131'_'''#251'X'#181#31#14#192#217'L'#245#31'|_M'#247

+  +#183#216'<p'#237#254'0XL'#9#252'?'#8#189'tQI'#248#225'R_'#153#225#23#141'>'

+  +#239#186#170''#179#217#156#16'^'#22#199#225#248'+]'#138#227#248#208'e'#223

+  +'cL'#1#218#174#199'q'#220'Y,'#22'k'#196'vp'#2#26#18#192#246#6#189#180#247'`'

+  +#216'{s'#214#188'a'#253#1'a'#164'g'#24#170#183'T'#239#198'[*nuu'#211#16'h'#2

+  +#13#153'h'#148#246#217#31'P3'#230'@A'#2'z'#242'Q_'#151#17'{^'#209'r</'#251#6

+  +#242#202#229#240'N'#185#167'XBv'#228''#250#198#159'T'#227#199#247'O'#245'<'

+  +#158#215#128'F'#215#190#246#138#186#242#179'Z}'#228'k'#191#161'z/'#244#216

+  +#190#235'i'#247#210#230#243#155'F'#30#166#176'G'#156'}'#214#219#15#135'_R'

+  +#128#159#157'~'#211'"'#236#135#253#193#131#183#9#252#247#11#143'?'#252#4'Y'

+  +#170'B/'#153#223'$'#240#199'~2sC~2'#193#7#167#251'*'#173#250#223#145'\'#255

+  +'GF'#245''''#201#143#196#160#244'8'#165#191#190'.''3'#216#20#248#202'W'#190

+  +#226#147#25#16#175#172#172'4'#8#252']'#250#161#27'2'#185'('#204#0#16#1'G'#5#8

+  +#176#157#187#131#149'O'#14#231#141'K'#202')'#29#230#28#129'f['#245#174''#146

+  +#236#255#150#245#9'0'#17#196#146#31' '#154#128'I'#27'6'#181#3#158#211'_'#176

+  +#152's@'#251#8#220'^'#131'O'#157#233#229#20#198'w'#254#233'7'#213';'#255#254

+  ,#159')'#253#12#157#159#1#226'mn^W'#151'>'#253'e'#245#234'/'#253'U'#181#249

+  +#214#23#143#241#203#158#208#198'/'#175#188#206'H{'''#179'O'#247#242'3'#224

+  +#207'X'#234'g'#21#201#207#241'~'#2'}'#6'{_'#136#0#165#189#147#157#247#24#252

+  +#186#181#151#158#212#211#207#210#228#229#149#237#31#212#130#197#196#181#251

+  +#149#14#249#193#238#223#18#213#31's'#252'q'#200#143#182'w'#8#15#195#231'Y'

+  +#236's'#132#203'vb'#195#166#9'_'#191'~'#29#154'@'#11#181#2#240#7#208#15#191

+  +'*aA'#204'1'#8'=p5'#247#252#206#157#254#234#167#198'I}'#213#23#167#160#23#232

+  +','#192#184#217'c'#18#8#26'uM'#0'l'#18'D'#146')'#136#16#161'4'#18'A'#152#208

+  +#180#21#243#29#18'0'#221#133'<!'#0#229#2#255'9D'#12#142'a6'#227#225#253#159

+  +#168#255#254#219#191#172#134#247'~z'#130#183#236#217#6#8#186#190#178#169#214

+  +'>'#254#179#234#213'?'#251'+'#234#218#159#248#165#163#191#249#176'k'#246'<'

+  +#158'PG'#218'kG'#191#201#231#207'm#'#143#194#230'/'#210'{y'#153#27#169#191

+  +#208#192#135#148#135#250'O'#132'0'#217#190#163'F[?"'#146#152'Ks'#15']'#223

+  +#143'?7'#187'{o7'#194#217#208#177#251#231#244'l'#163#197#23#18'='#182'%'#215

+  +#159#193'O8'#128#25#176#141#132#159#157#157#157#169'x'#253#13#248'_'#24#2#224

+  +#239's'#19#132#8#248#173'$I'#216#31'@'#11'B'#130#208#4#216#31'@'#235#149'\'

+  +#249#157'w'#247#214'?='#205#162#14#146#132#152#4#184'7'#0#145'@gMu'#174#189

+  +'%'#229#194#162#1#152#252#0'h'#1#146'-X8'#6#203#154'@a'#18#248#197#228'#N1'

+  +#209'Y'#237'='#248#255#254#205'?R?'#248'w'#255'DMw'#30#158#234'y'#4#245#166

+  +'jn\S+'#175'}'#130'$'#252#159'R7'#190#244#231'T}'#253#202'i_'#158#202#200#203

+  +#210'_Rz='#227#236#147'r^'#6#191#163#246'['#240#139#202#15#224#179'z'#207'*'

+  +#191#246#1#204'v'#31#168#193#195#183#233'usn'#238#193#239'Cyo'#154#229'W'#187

+  +'{?'#236#196#147#190#168'l'#214#238#23#167#223'.'#236'~ZX'#245#135#211#143'0'

+  +#240#152#222#187'O'#166#241#4#9'?'#199#233#245#175#142#211'x'#202'}'#152#2

+  +#180#6#9'X'#0#217'?'#151#29'S'#0#26#1#252#1#221'$'#243#187#239#246#215'?'

+  +#179#200#163#134'o'#204#1#216#247'$'#233#153#4#174'|'#156'H'#160'nA'#207'f'

+  +#128'h'#4'L'#2#145'&'#1#21#233#168#2#147'@h'#8'@r'#5'|'#129';'#214'2)'#225'Y'

+  +#159#166'|'#240#222#219#234#143#255#249#223'W'#15#254#247#31#208'C99'#190'/'

+  +#162'k'#17#183'{'#170'u'#245'e'#181#250#209#207#168'+'#159#251#170#186#250

+  +#249#175#210#245#175#159#246'%x'#250'03L'#219#130#30'c'#231#23#253#251#140

+  +#167#223'H~V'#225#231'I'#1'x'#6#255#156#155'{'#178'&@'#255#155#238#222'U'#163

+  +'G'#210#206'{Q'#168#253' '#146#203#173'}L'#231#181#131'/q'#156'~H'#245'E'#188

+  +''#15#133'='#180#141'F'#144'P'#251#225#244'{D'#207#245#222'I'#218#253#238'8'

+  +#141'G|'#169'?@f'#22'b'#167#160#210'Z'#0#182#215#233#1#236#204#147'`'#229#189

+  +#254#250#167#19#21#198'<w`'#16'J'#235#240'HE'#173#158#234'^}'#147#204#129#166

+  +#206#12't4'#128#192#201#22#132#230#224#217#254#130'E'#132#128#9'AL'#129'R'

+  +#171'1[S'#228'-'#255#5#238'8'#229#26#158'{'#255#235'?'#171';'#223#254#15'j'

+  +#239'G'#255'W'#141#31#222'V'#139#241#224#169#14#11#238#197#16#197','#201#163

+  +'v'#151'C'#172#245#181#203#170'y'#233#6#131#189's'#253'#'#170#251#202'Gy'#251

+  +#204#141#167'\'#255#220#252#205#197#225'o[w)V'#249'mr'#15'@+'#9'>'#28#234'#p'

+  +#231'R'#217#151'I'#184#15#142'>'#14#251#137#31'`'#188#253#30'-'#239'jR'#224

+  +'i'#188'S'#142#22#0#252#27#205#193#237#245#198#240#145#11'~z'#182#140#221#15

+  +#240'o'#153'J?z'#230#239#201'4'#223#232#240#131#6' '#199#150#237#247','#151

+  +#242#196#190#215#245#7#208#197'h'#18#248'{'#164#10'm'#18#192#175'Hx'#144#179

+  +#4'iY'#3#9#204#210'x'#237#246#254#250'''3'#207#15'Yr#<'#24'j'#18#8#27'm'#213

+  +'!'#18#136#154#29#2'~h'#181#0#228#8'x'#236#20',H'#128#181#129'J'#152#208#212

+  +#17#24#18'`'#231' t'#148#220#153#144#164'`'#132#234#147#246#244'+y'#10#4'1'

+  +#219'{'#172#230#253#29'5'#31#236#210'zO-'#134#251'\9'#217'}'#249#13#213#185

+  +#249#250#217#149#224'G'#189#142'K'#239'C'#17#222's[u'#219#16#159#11#254#170

+  +#212#151#220#254'L'#154'z'#148#9'@K'#255#209#214#143#213'd'#239#30#189'n'#206

+  +#145#1'~'#159#228#248#175#214'F'#15#174#180#251'w'#243#2#252#200#244#131#221

+  +#15#240#195#238',!'#191'{R'#223#15#27'n{:'#157#14#136#0#160#194'%''e'#247#31

+  +#245'r'#31#251'wW'#243#3#200#28'@3'#209'Md'#10'*'#237#16#196#26'$'#176'J m'

+  +#141#23#181#205#187#253#213#183#136#4#2'm'#207#11#9'p'#4#160#201#230'@D'#234

+  +#170#213#4#156#181#23#11#17#24'M'#128'L'#2#21'j'#191#130'2s'#17#26's'#192'M'

+  +#30'2UEn'#163#145'3l'#26'|'#232'F^'#10#226#8#224'M'#21#159#210#158'}'#137#239

+  +#187'i'#189#218#230#215#128#207#13#248#173#228'_0'#200#217#241'7'#211#161#190

+  +#225#163#183#213#172#255'H'#146'|'#140#218#175'k'#251#187#209'd'#235'zw'#239

+  +'=m]d'#153'x'#252#145#236#3#240'#'#151'['#233'y'#253#24#252#216'F'#178#207

+  +'I'#198#251#15#27#167#253'('#151'R'#133'I'#11'h#'#25#136#180#128'K'#208#4'h'

+  +#31'Z'#0'H'#0#164#176'B@lM'#147'x'#237'N'#245#19#169#23#198#218#179'/>'#1

+  +#174#12#172#17#9'|L'#197#157'uM'#10#198#15'`'#192'/m'#198'=!'#2'_z'#10'('#19

+  +'%'#16#231#160'2'#230#128#239#21#4'`'#174#214#139'>]'#241'y'#25'.'#234']sGl|'

+  +'O'#202'wm'#3#143#170#179#207'8'#250#0'f'#212#243'/'#28#240#27#231#31#175#167

+  ,'j'#240#240#7#164'ImK'#140'?'#209#196#145'j'#240#175#213'F'#247'/'#183#145

+  +#226'k'#193#159'I'#154'/g'#250')]'#226#251'H'#230#245#131#228#199#164#30#143

+  +'1'#171#207'|>'#31#31'w'#170#239'Q.'#227'i'#223'F'#207'8'#5#209'@'#4']'#132

+  +#208'P'#212#9#15'"O'#224#138#201#20#4#9'$y'#220#189#189#191#250#214'BE'#245

+  +#18#9#136's'#176's'#249#13#21'w/'#177'/'#192'3'#181#2#177#244#16#176'&A'#164

+  +#253#2'b'#14#168#208'/'#146#134#140'i '#13'F'#172'F`'#175#152#163#10#156#159

+  +':'#163#23'f'#148#146'xl'#171'.}'#140#193#159'i'#201'oc'#251#169'n'#226#1#240

+  +'+'''#204#151'K'#190'>'#171#244'3'#241#250#211#177'\B'#201't'#162#6#247#191

+  +#175#18#228#246'''s'#157#21#232#128''#163'1'#184#189#217#28'>'#210#138'F'

+  +#150';'#146#31'*={'#252#149#238#237#7#240#223#151'p'#223'cH'#254#197'b1'#186

+  +'v'#237#26#156#131''''#234#244#171#142#179#240#236'Z'#18#232't:1'#177'b'#157

+  +'.T'#27#149#131#232'$'#4#2'0$ '#173#198'A'#2#205'L'#133#237#219#253#181'7gY'

+  +#220#214'}'#0#196#174#143't)qk'#243#150'j'#172'^'#215#146#222#1#189#217'f-'

+  +#160#166#147#139'8Dh'#219#142#7#133's0'#240#10#141#192'I rs'#137#205'f~'#224

+  +'''='#225#10'?'#211#173'>'#175']'#130#142#248'h='#245#250','#191#178#185#211

+  +#151#223#5#191#246#238#235#248#190'J'#181#202#175#4#176#156#155#159':'#246

+  +#254'\'#131'?'#183'j'#191'd'#242#17#25'$'#147#161#234#223#255#158'Ji]H~'#157

+  +#225#167#210','#191#220#217#255#201'j<'#217#21#193'o'#193#175#138#190'~'#166

+  +#190#255#1#164#191#132#254#30#163#190#159#198#168#209'h'#204#143';'#207#255

+  +'9'#222#165#227'?'#15'S:'#140#162#161#241'x'#140#134#162#29#169#25#184'd4'#1

+  +#165#251#7#160#177'H'#143#174'X'#147#16#218#188#211'_'#251#216'8'#173#173'x2'

+  +#239#160#206#254#211#18#191#190'rU'#181#214'oiM'#192#250#1'B'#157',$d'#224'I'

+  +'%'#161#138#138#190#2#166#152'Hq'#132#192#244#23#240#203#145#2#167#243'P.'

+  +#161#195#234#21#245#202''#158'q'#228'O'#220'='#179#195'{'#234#129#167#255

+  +#238'|'#201#207#21#144#27#129#175#14#11#237'9'#133'<*-b'#251#197#162#129#207

+  +#210''#190#144'p'#223'B'#180#129#5#255'o>'#216'a'#155'?'#157#142'u'''#31'Z'

+  +#148#128#223'#'#241''#181#187#247#163'n8'#27','#3#191#210#225'>'#128#31'-'

+  +#188#31#144'&'#203#14'?'#228#248'#'#220'G'#175#27#161#200'G'#157#146#211#239

+  +#131#222#157'c='#23#248#3'~'#252#227#31#251'h%F'#154'@'#195#228#8'`V!'#164#12

+  +#131#8'h'#141#164'!4'#26#237#210'Uk'#17#240#234#247#6'k'#175#15#23#245#13'c'

+  +#14'0'#17'DP'#241#145':'#220'Sm2'#9'PG'#224'K?'#193#2#252#142'6'#192#254#0'c'

+  +#14#232'm'#155'8Ti9f'#195#134#158#201'(tr'#207#171#253#7#204#173'=KW'#250','

+  +#143#202#245#202#157#166#156'%'#208#27#162#200#164'eW'#150#29'H'#231'Ui'#1'z'

+  +#227#237'O%'#212#151#207#231#142#195'O|'#0'D'#2#147#221#219'j'#178#253#158

+  +#222'w$?>'#223#167#15#184#222#219'{'#167#21#204#199'K'#192'ob'#253'h'#234#137

+  +'4_+'#249#233#153'}L'#160#223#165#231#23'5'#0' '#137'3'#1'~'#231'2'#159#153

+  +#193'$'#240#189#239'}/@x'#16'$@Z@W'#26#137#184#154#0'"'#3#235'('#28#162#27

+  +#129#18#227#248#254#160'wko'#222#188#234'['#245']k'#2#200#26#244#227#26#153#4

+  +#31'Q'#181#206#166#150#248#174#244#23#223#128#206#17'0'#249#2#129#205#30'TN'

+  +#6#161#237'@'#236#251#5#1'8m'#201#221#26#3#235#164#170#22#27#157#181'+~F'#134

+  +'Wr'#228#185#155#249#1#240'k'''#159'H'#251#180#144#250#165't^'#168#251#137

+  +#238#215#175#9'@<'#254#226#237'7'#26#0#19#0#166#233#154'N'#213#136#164#254'|'

+  +#180#171#227#251'IR'#2''#160#146#217'K'#221#221#31#214#131#197'T'#192'o'#28

+  +'~F'#242's'#129#15'r'#252#209#220#3#146#31#26#0#212#254'('#138'v'#7#131#193

+  +#136#180#218#19'M'#243'='#210'u?'#237#19'XvN&<'#184#181#181#21#211'Ek'#208#5

+  +'4$'#128'lA'#180#24#135')'#192'$@'#251']'#248#4#232'X'#237#209#168#243#210

+  +#246#180'}SO8bH@2'#0#137#8#234#189#171#170#185#241'*'#131#222's'#181#129'H'

+  +#147#129'''-'#199#149'q'#14'F'#21'm'#192'u'#16#154'z'#2'&'#3'eg)'#202#29'2p'

+  +#181#255#220'!'#133#15'f'#26#188'(C'#210'u\'#137#159#23#181#249#202'sT}'#199

+  +#201'W'#168#249'"'#245#197#214#231'2'#222#180'p'#242'1'#232#165#148#215'z'

+  +#252#141#234'/'#170'>'#219#254#201'B-'#250#187'j'#184#245#14#29#27#219#200

+  +#128#174#229#151#137';'#189#249#228#165#238#222#15#185#170#143#235#8'l'#168

+  +#143'S|'#149'd'#249')'#237#224'C'#184#15'R'#255#1#212'~'#178#249'w'#233#249

+  +#29'6'#155#205')i'#183#201'iz'#252#151#141#179#250#4#150'H'#160'Ac2'#153#160

+  +#145#8#155#3'B'#2' '#3#209#4'T'#151#128#136#190#131#181#253'Yc'#243#225#168

+  +#251'Z'#166#194'PKn'#169'!'#8'C1'#9#186#164#13#188#193#213#132#0'>'#28#129

+  +#158'D'#4#220#16#161#155'9'#168#156'Z'#2#229#18#129#231#23#179#22#251#198'I'

+  +#232'j'#3'E'#30'a'#238#148#25'z'#213#146#195#3#153'mg'#245#182#188#223#187

+  +#249#4''#134#233#191#167#156#198#28'|'#188#2'zP'#168#3'~'#211#173#135'U}'#9

+  +#239')'#167'O?'#188#245#249#28#251#11'+'#249's)'#238#201'%'#207'?'''#240#143

+  +'wn'#171')-'#153'y]*R_f'#238'iG'#147#237#171#173#253#219#129#151'&:'#151'(3e'

+  +#189#240#246'3'#248#149#206#242'CO?'#246#248#195#230'G'#168#15#224#167'eH'

+  +#166#236#20#177#254#179#6'~}'#205#207#238#176#133'C'#4#254#136'.b'#147'L'#130

+  +'.H@:'#10']6'#225'A%$'#128#16'!H`'#158#133#237#187#131#222#235#179#172#214

+  ,#230'y'#3#140'o'#192#132#10#163#186'j_zM'#197#221#205#2#248'f1'#4#16'W'#142#7

+  +#186#211#144#178#243#19#6'em@'#26#143#148'#'#6#158#149#244#172#29','#137#30

+  +#152#249#11#142'zG'#206#204#147#227#222#168#167#189' ?'#252#128'i'#197#229'y'

+  +#14#248'3'''#150#175#28#27#223'Q'#247'y'#31#182#190#27#222'K'#11#137#159#27

+  +#208''':'#181'7/'#145'@'#194#245#19'#'#146#250#243#225#142'h'#11':'#188#167

+  +#138#30'~'#217#165'F'#255#246'Zc'#244#152'S{%'#212#167'tz/O'#223'-s'#248'A'

+  +#237'7'#137'>'#15#207#19#248#143't'#239'N'#251#252#12#9#244#251#253#184#213

+  +'j5'#232#226#162#197#248#154#132#4#225#16#188#12#173'@i'#18#232'1'#9'('#175

+  +#158#7'~'#252'p'#208#189#185'?o]-'#146'|t'#184#15'&'#129'oL'#130#245'W'#8#236

+  +#177#205#9#240'L'#5'a'#172'5'#6#171#9'p'#10'qPT'#21#210':'#15#220')'#202#140

+  +'V'#224#21'D'#160#138#237'"JP'#172'K%'#200#206'f^9'#236'='#235#173'z'#158'w'

+  +#245#153#31#215#188#152'>'#219'='#149#188#188#145';/'#178#245#249'n'#18#143

+  +#177#243'MG^'#145#250'*u$'#191'c'#235#27'/?'#219#237#12#244'E'#161#254#207#11

+  +'R'#192#255#23#240#242'?'#254'!i'#1#19#177#247'u|'#223'|n'#228'/&'#215#218'{'

+  +'?i'#132's'#174#229#23'G'#4#236'}'#147#222';'#145'P'#31#171#253'J'#194'}'#178

+  +'F'#169#239#222'y'#0''#233#254#156#209#193#231'W%'#1'd'#12'"Y'#136'.'#178'!'

+  +#1#152#5#151'0'#247#128#210'y'#2'm'#186#212'u'#146#184#241'p'#222'X{0^'#185

+  +#149#145#236#215'@-'#155#4'H!'#6#9#196#157#13#201#7#144#136#128#1#191')$'#10

+  +'+$ '#11#147#138'h'#6#156'N,'#145#130'\'#162#6'V'#27'x'#26#17'8'#221#137'rG;'

+  +#240#202'^'#196''''#220#177#147#184#149#249#225#135'+'#167'i'#140'{'#175#244

+  +'6'#167'<'#23#0'WO'#0'~^'#150#248#202#22#239'8N>c'#239#187'v'#191#149#252#139

+  +#18#240'Y'#19#152'N'#213'd'#251#167'j6'#220'b'#130'@'#179#15'+'#241'3=__'''

+  +#154'<'#190#210#234#223'!'#149'?'#205'm'#147'@]'#210#235'd'#248#245#165#178

+  +#15#222#254'G'#146#215#255'H4'#129'}8'#252'666'#206'<'#248#237#253'9'#227#195

+  +#146#128#18#159#128#146'2b"'#130#21'h'#2#146'%h'#178#5'9Y'#136'$r'#155#192

+  +#211#160';'#23'''Y'#212#184';'#236#189'6Kk'#29'S'#0'd'#27#140#8#184#163#214

+  +#26#19'APo'#21#17#1#167#138#208's'#251#10'<'#137#8#220#148'b'#153#194#220#134

+  +#14#205#196'%'#165')'#204#202'k7'#132'h'#230'4'#176#135#14#132#20#143'n:<'

+  +#151'q'#152'*o'#156'v'#246#144#145#236#230''#249#146#216#189'~'#157#14#227

+  +'I'#230#158'!'#2'k'#227'/Q'#247'S'#145#248#2'|'#181#208#149'|J'#236'w'#215

+  +#222'7'#206'?E'#251#147#254'=5'#221#189#173#19''#210'%*?}'#209#229#198#224

+  +#189#149#198'h'#199#203'MI'#143#14#243')'#1'?'#173#199#180#223#151#154'~4k'

+  +#132#196'GE'#31#182#183'I('#161#145'''{'#251#201'\=s'#14#191'e'#227'<'#16#128

+  +'=OC'#2#251#251#251#17']'#228':]x'#174#29#136#162'h'#157#246'a'#6'\'#18''''

+  +#225#134#212#14'th'#27'}'#4'b'#210#0#162'G'#195#206'K{U'#147' '#212#201'C'

+  +#138#171#11'#U'#235']S'#245#181#27#156'M'#200#14'@'#199#4#0#1'(''Dh'#136#192

+  +#148#24'+'#153#181'X'#249#229#198'#'#182#21'Y%'#179'P'#231#15'-'''#3#207#209

+  +#255#139#222#4#166#151#161'{UN'#136#4#170#143#176#19#182'+m'#229#5'Y'#149'Cx'

+  +'N'#165#158#27#198'3N='''#150'oA'#159#154'm'#0'>#b'#0#160'u'#17#143'Z'#20#13

+  +';'#173#199'?IJ>'#0#132#0#147#209#158#154#236#252'D-&'#131'B'#213#135#169#128

+  +#207'pU'#254#238#238'O'#234'^2'#245't'#229'@'#213#211'?'#147#22#222#168#234

+  +#219'q'#193#15'O'#24#134#232#235#223'_,'#22#227#25#141#243#2'~'#140#243'B'#0

+  +#246'\'#221'<'#1'8'#252#232#194#183#232'p'#143'.'#254#186'8'#7'A'#4#156','

+  +#132'V'#227'$'#129';$u'#27#180'_#'#240'E'#131'i}'#237#193#164#247'j'#150#235

+  +#249#7#180#147'0`'#21#222#244#16#132'Y'#208'X{'#133#139#138#188#208#137#6#200

+  +#220#3#134#8'4q'#4#162#29#136'&`{'#13'8]'#137#131#138#163'P'#8#161'hF"'#19

+  +#152#28'H76'#161#195#162','#185#240#15'T='#3'G'#200'1'#248#160'%'#203'y^yi'

+  +#25#240'z'#229'4'#218'TE|'#159'%'#189#153'l'#195#190#230#160#154#207#246'~'

+  +#154#149#218'r+'#150#250#153#6#173#0'_'#137'='#175#164#131#143'2'#4#144'h'

+  +#239':''u'#231']5'#239'?'#210#173#186'L'#26'p'#146#10#209'h'#149#31#149'|'

+  +#151'['#253#187'P'#249'9'#188#143#254'}'#160'!m'#239#219#24#191#1#191#210'e'

+  +#189#15'e'#198#222#199'R'#207'? '#1'4>K'#25'~G'#29#231#137#0#236'9'#155#180

+  +'a'#218#142#26#141'F'#13#17#2#164#7#27#231#160'8'#5'/'#217#218#1#29'&'#132's'

+  +#176#6#147' Sa'#252'h'#220'~'#169'?onz@'#166#137#20#216'f!Z'#226#195',h'#192

+  +', B'#176'R'#223#1#188'Bd '#22'B'#16'M@9'#25#132#214'I'#24'>A+8'#204'GP'#154

+  +#242#188#186'v:'#26'['#13#193#161#130#165#190#130'CB'#143'O'#200#187#183#160

+  +'.%'#224#23#26'H.'#234'})Q'#199'%'#0#215#147'/'#158'}'#163#226#219'p'#158'q'

+  +#240'Y'#208#167'b'#231';'#158'}l'#11#192#181#202#175#215':'#175#223'8'#2'%vO'

+  +#235#217#222'}5'#222#131#186'?'#211#199#229'3y'#157#167'"'#245#147#201#149

+  +#230#254#237'f<'#27'z'#26#247'8'#15#146#250'%{'#223'&'#248#208#178'C'#210#254

+  +'1'#9#153'G'#210#213'g'#155#128#191'K'#160#31#160#149#23#13#152#8#231#10#252

+  +'K'#158#138's3,'#9#208#197#15'k4'#200#12'h"B'#16#4#193#170#227#23#128'F'#0#18

+  +'X'#5'A B &A'#148#19#196''''#139#176#253'p'#178#242#202','#141'ZE'#235#240

+  +#162'('#200#147'9'#10'k'#221'+'#170#182'rM'#5'h'#162#17#154'y'#8#3#199#28'pM'

+  ,#3#9#17#134'RK`'#10#140'l'#14'A Z'#129#201'$t'#218#146'U'#137#160'j*'#148#202

+  +#146'+'#21#137#21'G'#162';'#242''''#146'A'#165#216'f'#217'c'#235'Jw'#222#168

+  +#172'e;7'#137'<'#153#27#190'3'#137'<'#142#164'wc'#249#2'|'#29#203'/'#192#175

+  +#137#192#9#241#217't^'#13'r'#237#3'H'#10''' -'#139#225#14#219#249#9#171#251

+  +#186'I'#167#146'L>'#179#246#232#207'j}t'#189'1x'#228#177#180#207'3'#147#214

+  +#171'$'#190'O'#203'\j'#249#135#226#233#135's'#15#210#30#249#252'['#178#191'O'

+  +#207#220#160#223#239'O'#187#221#238#156#8' =o'#224#175'>'#9#231'm'#148'J'#137

+  +'I'#19#136'%u'#152#157#131't'#140#181#1#144#0#250#11#210'z'#141#253#2#202'k#'

+  +'}'#152#182'czDc rw'#218#186#180'=m_'#207'H'#164#235#226#31#237'$'#132'fP'

+  +#168#249#145#170#181'/'#169#6#17#129#31'7'#180#244'7j'#191'k'#14#24'@'#224

+  +#164#17#187#166#129#201'!p'#29#133#198'<'#176#4#224'W'#18#139#180'G'#192#246

+  +'.'#180'='#11#141'iP'#152#3'n'#194'Q'#217';'#239#29'XU"s'#202'Az'#217#181#144

+  +#187#161'='#137#215#231'y'#197#214#151'B'#29#163#226'gy'#145#167'oSu'#139')'

+  +#183'\'#201'_H'#253#20'M5'#197'VO-'#9#184'a'#190#220#170#251#198'!H'#18''

+  +#184#173#166'{wU:'#27#22'f'#129#11'~'#241')'#180#162#217'.I'#253';'#152#156

+  +#211'C/`}n'#172#242'+'#221#187#207#228#244#143#140#167#159#182#183#197#219

+  +#191'Ej'#254'6'#9#24'h'#2'}'#147#215#239#244#241'3'#192'?7'#224'w'#30#135's;'

+  +','#9#16#1#4#8#19#18#27#195'9'#216#154#205'f=h'#3#244''#244#26'D'#171'1h'#2

+  +#240#11#160'r'#144#211#135#17'% '#192'D'#244#17'A'#146#249#241#163'I'#247#230

+  +'`'#214'X'#247'l'#241'O'#1'^?0 '#142#184#166#0#206'B'#244#211'3'#166#0#167#13

+  +'['#208#23#161'A'#27'!'#136#180#244#207#131#224'@wb'#235'#p*'#15#11'"P:'#164

+  +'h'#211#139#165']'#153'*L'#4#151#24#150'^"'#175'r'#197#170#26#192'!'#14#190

+  +#18#15#184#245#246#216#204#242#146#189'o5'#0'7W'#223#128#221'z'#244#141#202

+  +'/'#246'~'#166#167#219'V'#226#228#179#128#183#29'{'#202#224#183#197'='#236

+  +#253'_'#168#217'`K'#205#246#239#17#240#199#146#16#148'X'#147#1#251'J:'#246'D'

+  +'^2'#187#212#26#220'n'#215#166'}'#248#28'<'#143'U~V'#252#233#146#177#163'Oz'

+  +#247'Me'#178'Nk'#239'C'#237#151#153'{9'#190#15#149#159#20#206'1b'#252#245'z'

+  +#29#164'a'#234#249#237'U:O'#227#188#19#128#249#13'H'#24#194#154'#'#4'p'#14#18

+  +#1'4E'#27'X5'#190#1'!'#1'6'#9'h'#191#7#191#0'm'#195'A'#8'm'#128#222#231#251

+  +#163'$'#238'>'#28'uo.'#178#168#233#154#5#202'I+V'#226''''#136#219#27#170#222

+  +#187#174#130'F'#235#160#212'7'#170#191'C'#4#134'L'#148'K'#2#2'z'#229'U'#157

+  +#133#14')x'#166#10'Q9~'#130'J7cq$'#30#152#241#232#176#154#3'[m'#231#188#196

+  +'m'#180'a6'#189'B+'#240#158#2'zW'#213#247'*'#222'|'#29#215#207#172'Df'#7'`R'

+  +#168#251#158#1'}'#226'H~'#163#13'd'#134#8'2'#142#223#207#6#143#24#248#217'bb'

+  +#237'~'#227#216#203'\u'#159#132#252'J}'#252'p'#179'9x'#224#209#142#199#165

+  +#130#224#29#218'f%'#198':'#250'f'#210#187#207't'#238#133#167#223#130#31#19'v'

+  +#160#137#7#254#143#254'}'#163#209'h^'#241#244'+u'#14#193''#200#147'q.'#135

+  +#141#16#160#156#248#214#173'['#225#214#214'V'#141#14#213#137#173#17'*'#236

+  +#145#250#134'b'#162'u''u'#24#251#200'#hC'#27#160#237#26#251#6'</'#204'r'#143

+  +#204#130#246#229#221'Y'#243'J'#154#135#145'1'#11#236':'#8#172#175#0'N'#191

+  +#184#181#166#234'+D'#4#245'N'#17#1'p{'#10#28#0#190#16#131#235#24'tk'#11'l'

+  +#152'R'#230'3t'#29#134'Nv!k'#7'jIU'#162'\'#17#175#148'\T'#190#213#182#143'A'

+  +#245'B'#26#233'_r'#240')I'#218#145'}3}'#182#19#194#179#224#183#251#6#240'N"O'

+  +#213#203'/'#241'}'#227#236'c'#144#27#147'@r'#251#141'6'#144'%s'#246#232'O'#25

+  +#248'3'#171#254'g'#198#163#239'F'#17'h'#187'I'#234#254#229'F'#255'^'#28#192

+  +'3O'#146#158#5'>'#199#245'3'#201#231#183'R'#159#22#19#226'c'#149#31#160#199#2

+  +#149'_'#8#1#29'|'#198#244#182')'#217#253' '#140#132#180#206#236'<'#132#249

+  +#142#4#156#23'h'#176's'#240#219#223#254'6'#251#5#232#166'E'#4#234':'#28#132

+  +'259'#155#4'XD'#27'0$'#208#165#183#146'>'#175#26#4#167#24'f'#1#129'='#160#199

+  +'%'#220#157#183'6'#247'&'#173#203#137#10#226#3'D'#224#23#246'>4'#130#176#209

+  +'!'#173'`'#147#8'a]'#249'a,m'#198#140#3#240'0'#167#224'!'#5'F'#146'3'#224#149

+  +'|'#3#166#23'A1'#169#137'%'#2#153#224#196'LuV'#10#18#10'7'#148#156#132#14#3

+  +'xF'#210'Wd'#153#145#246#7#28'{N'#252#222#149#252#182'B'#207#237#200'c'#192

+  +'/'#132#160'\'#167#159#149#242#142#211#207#233#224#131#255'-'#166#251'j1'#220

+  +#162'e'#155'I w'#205#128','#147#150'_'#236#220#195'~'#222#138'g'#187#27#141

+  +#193#131'Z'#184#152#150#212'}'#199#214#151#182']'#166'c/l'#249'}i'#226#193

+  +#158'~Z?Fl'#159#164#252'>='''#3'2/'#199#244','#205'{'#189#30#192'n'#237#253

+  +#165#128'9'#237#19'8'#166#223'T2'#9'h N'#211'diO'#128#167#155'j'#137'@'#204#3

+  +#236#19#9#168#14#1#174'A'#251'u:'#30#25#179#128'@'#21#236#205'Z'#27#187#227

+  +#230#229#133#10#235#218'F'#247#203#211#141#17#1'('#223#183'ZA'#173#177#170'"'

+  +'"'#131#176#185#162#163#4#230#181#142'3'#208'H~'#255'0-'#192#152#8'&'#147#208

+  +#248#7#248#23'V2'#12#221#28#130#220#137#12#8#27#152#196#220#131#209#130'Jz'

+  +#174#167#172'j/'#255'V'#226#245'+Iyc'#227#27'{'#223'4'#227#176'Z'#128#1#186

+  +#172#165#192#166't'#220'M'#237'u'#215'('#203#157#13#31'3'#240'S'#132#242'2'''

+  ,']W'#166#220#206'e'#209#192'O'#243'vm'#182#189#217#24'>'#140'|H|'#28#23#191

+  +'>'#171#251#220'%'#208#205#232#227#240#30#242#249'i'#189'/'#237#187#182#205

+  +'"'#206'?'#28#199'k'#166'F'#229''''#205'2;'#207#246#254'a`y'#17'G'#201'$@'

+  +#168#176#213'j'#197#2'lT'#12'v'#197#25#184'J'#140#143#232#0#22#248#5'D'#27'P'

+  +'-!'#2#152#5'a'#206'd'#128#174#225#190#191'7k'#174#237#142'[W'#230'y'#216#176

+  +#206':'#3'|'#207'H'#242#162#2#17#154'@'#212#222' '#173'`C'#5#141#142#227#252

+  +#11#184#231#160#231'8'#2#139#168'@u'#10'3'#207#2#222'F'#5#2#209#4'\'#237#192

+  +#151#144#161#149#252'U'#7'`%'#159#192#12#183#149'6'#239'+'#235#28#176#213'zF'

+  +#229'O'#171#234'~&fA'#230'T'#234#21#206'?~'#189#209#0'*a'#191#18#9','#230'j6'

+  +#218'f'#208''''#211'A'#161'!'#152'L@'#199'l0}'#0#16#210#235#198#147#199#27#4

+  +'|x'#246'M'#190#241#19#212'}k'#235#211#210#151#238'='#12'~'#186#207#144#254

+  +#216#222#15#130#128#19'{h'#153#145#244'_ '#196#247#162#168#252'K'#129#242#2

+  +#15'k'#18' J'#128#178'b'#186#185'54'#25'!R@'#227'Q'#152#5'+ '#1#133'Y'#137'5'

+  +#9'@'#27#232#209#210#17#179#160#238'{~Lk'#16'A'#8'"'#240#9'}'#251#179#250#234

+  +#206#164'ue'#150'!'#135#192#128#177#144#218#5#176#3'K'#10'a'#212'Tq'#7'Z'#193

+  +#154#10'j'#141'2'#184#157#210'bo'#9'!'#184#9'C'#133#25#224#21'~'#2'''R`o'#173

+  +'u'#11'H'#180#192'M$'#146'W'#185'~'#128#210#172#185#178'*'#194'}'#174#244#207

+  +#156#233#180#225#240#203'd'#178#205#138#183#191'*'#245#179#188#18#1'H'#212'b'

+  +#178#175#230'P'#241#199#187#156#216#147';6'#189#251'~K '#244'}>1B'#183'6f'

+  +#224#7#200#15'6'#192#231#138#221'2'#240#149#6'?'#128#143'N'#189'#'#201#229

+  +#223#23#240#195#185#135#25'y'#25#248#240#240'+M'#14#211'N'#167'3G'#3#143'7'

+  +#223'|'#243#133'R'#249#15#0#228#180'O'#224#132'~#'#155#4#208#6'h;Z]]'#141#160

+  +#13#200#140'D0'#11'z'#162#17#172#233#244'aM'#4#180'&'#18'Pm'#186#235#220'l'#4

+  +'&'#129'o'#136' '#131'F'#224'y'#195#164#209#219#153'4/O'#211'Z'#7#200#180#192

+  +'tH'#160'4'#231#128#152#0#232'I'#16#212'z*jt'#201#168#232#210'~'#173#210'[`I'

+  +#231'!G'#213'/'#171#254'x'#173#18#159#128#241#234'{'#182#152#168#8#4'x'#149

+  +#181'*7'#222'PE'#218#190#178#13'8'#157#146#221#204#13#241#21#234#190'w'#192

+  +#23'P'#201#233'7'#145#0#2'v2'#27#170#20'v'#253#164'O'#219#131'"'#219#207'x'

+  +#239#197#137#231#153#254'~v;'#231'p^'#167'6'#217'^'#175#143#182'|'#143'sy'

+  +#213'2'#224';'#237#185#173#147'O'#233#9':'#160#214#239#25#240#3#248'$'#12#246

+  +#200#222#135#3#16'z'#254#132'l'#253#217#139#230#232'{'#26'8>,'#227#128'6P'

+  +#171#213'bz^0G'#22#166'*G'#159#129#30#28#133#240#17#28#212#6'T'#211#152#5#4

+  +#180#18#17'(.'#25#11#163#253'yc}0k'#172#205#210#168'Y'#0#180#172#198#27#245

+  +'>'#247#202#196#0'B'#8#27'+*'#170'wT'#0'B'#128#19#209'!'#0#27#14#148#162#162

+  +'jc'#210#146#9#224'4"'#177'w'#185#218#140'D'#194'~n'#233'n)'#12#232'j'#2#198

+  +#9#232#168#251'n'#184'/'#207'+I?yA'#0'H'#206'I'#166'}'#150#244#201'tH'#255'J'

+  +#10''' '#155#20'i)4'#200'Q'#0'K&'#184#184'Y'#138#4#158#149#218'x'#167#25#209

+  +#135'i'#204#231#154#160#24#248#0'<'#235#252'b'#231'/*'#234#254'H'#226#250#198

+  +#214'G'#136'oW'#188#251'}'#186#215'C'#168#251#176#245'www'#23'd'#231'sl'#255

+  +#19#159#248'D'#254#162#131#223'yB>4'#163#164#13#192'7'#176#178#178#18#17#25

+  +#208'f'#204'}'#6'h'#1#216#225'(\1'#218#128#210#26#2#250#18'"'#164'h'#136#0'Y'

+  +#132'1a.'#160'g=dg!'#20'r'#210#11#166'i'#220#216#155'5'#215'G'#179#218'Z'#162

+  +#130#200'S'#5#25#20#146#220#169#7#240#141#243#207#28#15#148#31'7Y;'#8#226#22

+  +'}B'#131#9#130#29#141#202'5'#3#156#181#141#18#136#170#159#171#194'$'#200#171

+  +#209#1'U'#16#130#155#244#227'6'#222'4'#7#149#201#4#212'$'#192' u'#18'}'#12

+  +#232#177'dp'#188#211#146'/'#198'l'#199'c'#201#200'4/'#1#190#186'm'#181#137

+  +#204#250#20'`'#195'7'#195'y'#191'S'#159#236't'#163#233#158#199'I'#5'b'#143

+  +#232#188#131'Ll|l'#1#244#236#224's'#128#143#134#29'#'#153#153#135#195'{'#198

+  +#222'7'#14'>'#216#249't'#175#199't'#159#167'('#224'[b'#235';W'#224#197#29#31

+  +'6'#2#176#191#217'h'#3#155#155#155#254't:'#13'1S1'#252#3'0'#11#232#223'-'#178

+  +#7#225#12'D6'#225#138'8'#7'W'#196'y'#168#157#132#158#215#164#199#177'A'#159

+  +'V;@'#4#30#224#166'Q:'#152#215#187#253'Yc}'#148#196'+'#185#22#233'V'#133'7)'

+  +#191'E'#135#225#162#243#176'K'#8#185#152#0#164'x'#16#25#212#153#28#130#176

+  +#206')'#201'>'#214'd>'#148#10#139'J'#191#244'`'#219#242'"G'#160#236#237#247

+  +'Jf@^$'#7#25'3'#1#248'K'#209'H'#19'@'#159'p'#197']'#150#152#245#212#206#198

+  +#163#242#195#0#15#252'f%'#147#1#239'1'#251#181'`1&'#21''#167'GK'#232#193'!'

+  +#160'L'#237'0'#147'B'#154'iu'#223#177#241#171#18#223#216#249#3#1'?'#146'w'#0

+  +'~^'#144#194'K'#210#30#197';'#172#238'w'#187#221#217#214#214'V'#226'x'#248'_'

+  +'X['#255#176#241'a$'#128#210'o_f'#22#208#225#26#217#130#28'6$'#2#128'F'#208

+  +'s'#23#209#6#208'k'#160'm'#136#128#128#140'(CL'#251#16#211'Rc'#204#157#238'|'

+  +#180'*O'#9#206#251#179#198#234'h^'#235'M'#211#168#157#230#162#25#24#199#158

+  +'r'#10#131'J'#132'`'#156''#190'>ig'#187#152#199#16']'#144#27'*'#8'"q:'#134

+  +'tX"'#17#158#164'"'#243#233#232#181'/Z'#134#150#190#137#216#218'R)'#151'9'

+  +#139's'#28#146#28#18#158'_'#207#225'7'#7#196#182#196#183#240#1#184#0'W'#165

+  ,#130' 1#8T'#167#242#154#191#24#213#163#249#176'G*>Zn'#23#17#8#145#246'8'#3#2

+  +'>x'#18#206'}''o'#223#134#244#164'K'#207#184#2'|'#187#208'=d'#224'#'#172#135

+  +'L>"'#2#246#238'#'#149#151#8' '#251#176'I}w|'#152#9#192#140#3'f'#1'B'#244'p'

+  +#196#198'QH'#255'o'#9#216#187#244' '#245#184#150#128#136'@4'#2'v'#20'*'#204

+  +'T'#164#188':4'#2')4'#10#173'V'#224'#'#29'E'#251#10#176#13#208#18#9#212#137

+  +#12#186#147'E'#220#157'$q'#139#224#16#26'S'#161#232''''#232';'#205'D+'#246

+  +#190#152#2#150','#148#155'*l~'#150#252'@.'#30':$$'#232#216#255#182'EW'#169'1'

+  +#191#201#250'S'#165'\'#0'['#221#167#138#148'`'#6'u'#166'T'#158'/'#7'<'#214

+  +#181' '#25#215#131#249#176#25#207#251#237'h6'#242#149'8'#243'<61'#140'moA'

+  +#175't'#202'.'#24#133#213'|Y'#230#198#179'oT}'#19#211#151#5#158#254'>'#128'O'

+  +'D>'#140#162'h'#12#137'O'#199#167't'#23't<'#249'0'#170#251#203#198#5#1#20

+  +#195's'#205#130';w'#238#4#198'?'#128'9'#7#232'!B'#205'@'#203#241#19#244'$'

+  +#140#200'k'#248#7#20'"'#6'9W'#26#214#161#209#18#216#17'm@BQ'#24#248#30#200' '

+  +#160'c>'#180'^F'#165'/'#229'<'#244'wL$@'#132#208#153'.'#162#206'4'#141#219

+  +#153#14#8#138#237'^T'#4#22'e'#194#170#168#10'T'#254'R'#240#219#191'U'#207''

+  +#241#207'J'#246'_'#197#7'`Gn'#205#0#3'z'#183#145'g'#225'G(^g'#0#31#251#201

+  +#164#22#206#135#173'h>h'#147#164#15#252'4)^c'#153#197#128'^Y'#21#255#160#180

+  +'/'#169#250#144#248'p'#224')'#1#187#164#242#150#164#189#1'~'#171#213#154#141

+  +'F#'#246#236#147#169#151'~X'#213#253'e'#227#130#0#202#227#128''#192#16#1'=H'

+  +#28':'#164's2'#17#173'['#244#0#162#216#168'+'#26#129#171#13#176#143#0#175

+  +#229#228'#'#223#135'Ya'#200' 8@'#6#128#174#158'`'#132'a'#142'|<"'#132#246'x'

+  +#17#183#146'4'#168#207#179#176#190'H'#131'Z'#170#160#219'k'#251#221'8'#245

+  +#140'K'#191'T'#13#184'$'#239#223#141#8#228#203'~t5'#20'h'#134'['#251#239#185

+  +#210#221#253#191#6'n'#228#167#211#208#207'fQ'#144#204#234#225'bL'#18'~'#16'.'

+  +#3#188#233#18'"'#182'C'#174''#145#168#248'E'#214#30'-'#11'g'#218'-'#171#234

+  +'+'#157#190#203#224#167'{'#224#18#192#144'#'#179'I'#194#210#254#2#248'O'#31

+  +#23#4#176'|,%'#2'Z'#135#244'@'#177'F'#0'`'#211#186'I*f'#139#236'J'#214#10#132

+  +#16#12#9'X"@'#19#18#218#6'y'#212'@'#6' '#2#218#14#133#12'|'#218#151#194#2#206

+  +#177#169#16#130#178#128'N'#179' '#154'fQm'#158#16')'#164'!'#19'C'#146#250#181

+  +'E'#22#214'r'#195#2'y'#17#247#207#221#219#235#29#248'y2'#242#165#155#252#170

+  +'R'#11'0'#253'7'#240#178'E'#236#167#179#200'O'#166'Q'#152#206#226' '#153#214

+  +'BZ'#252'd^'#10#31#28#4#188#212#222#235#20']Ro'#178#220#168#19#185'JM'''#30

+  +'U'#150#246'('#207#157'J?>'#11'|'#168#251't'#157#135#0#191#0#30'j>&'#221#132

+  +'I0E'#6#159#249#172'%'#192'_'#242'K?'#188#227#130#0#158'<'#150#18#1'|'#4#237

+  +'6'#201#183#217#140';'#20#19#1#160#203#144#169'5h'#201#186'm'#246#141#198#0

+  +#243'@i'#13#2#4#2'2`"'#144#133#181#2'!'#4#175'B'#8#162#229#235'F'#0'E*'#191

+  +#201#243#247#2'"'#129'('#205#252' '#205#149#159#229'~'#0#19'"'#203#184#160')'

+  +#160#181#143#207'&'#158#241#233'8'#142#249'x'#15' '#233'{y'#202#139#162'Wy'

+  +#10#219#153'g'#142'y'#244#137'~'#158#6#4'N'#218'N#?K0C'#14''#181#237#249#167

+  +#247#204'1}Z'#185#20#11'j'#213#222#145#240#12'B'#237#197#183'q{+'#237'Mi'#174

+  +#210#192#159'HW'#158#145'*'#128#15#169#143#184'='#239#147#186#143#10#189'1'

+  +#173'!'#241#209#140'snl'#252'G'#143#30'e'#23#192''#250#184' '#128#163#13'K'

+  +#4#223#253#238'w=4%'#5#25#208#161#144#164'N'#212'l6'#1'd'#214#10#232#129'lxz'

+  +#174'B'#180'('#3#240#153#4'h'#223#144'C'#211#209#10'jB'#6#136#30'DJG'#16't'

+  +#20'A'#19#2#242#10#8#139#220#2'Dr'#130#217'y^'#164#249#225#143#239#219'm'#140

+  +#220'sN'#250#224#207#240#14#252'#?'#176#225#202#240#138#242' '#249#0'z;/'#210

+  +#133'9'#25#152#147'!3'#237'P'#212#21'x'#158#199#217#3'.'#224#233'X"'#221'vy'

+  +#150#29#167'@'#7#224#7#152'a'#223#143' '#229#165' '#135#215't|'#4#208'C'#210

+  +#3#244#240#230'c!'#2'^'#192#171'O'#199#211#11#224'?'#219#184' '#128'g'#27'%"'

+  +'@'#212#224#210#165'K>I'#164#144#30'D&'#3#180''''#4#168#145'a'#8'2'#192#2'2P'

+  +#152#202#220'Y'#132#8#140'i'#192#230#1'k'#5#30';'#14']B`2'#160'c'#1'b'#8#162

+  +#29'0'#17#152#22' '#24'y'#145#223#167'r'#183#11'`'#165#17#192#129'y'#9#151

+  +#254'J'#227#225'We'#253'_)'#227#164#211'h'#215'L$'#130']'#25#231#157#150#242

+  +#136#238#231'6Vo='#248#6#240'R'#142'k'#194'x'#0#255'd'#137#212#231'E'#18'vX'

+  +#189#23#21''#14#208'c'#166']'#196#241'WVV2x'#245#137#148#243#11#224'?'#219

+  +#184' '#128#247'7l^-'#194#135#244#16'z'#198'<'#160#135#18#128'E'#143'B6'#17

+  +#224'/'#160'}'#16'B'#131#164#22#8#129'5'#0#172'}'#157'Q'#216#144'F'#165'L'#4

+  +'R'#177#200#239#177'D'#160#29#136#161#199'A}'#144#129'v '#210#182#246#31'(]'

+  +#151' '#219#170#152'}'#132#165's'#209'4'#200#156#244'!, '#160'Vy^v'#3'j'#183

+  +#164'W'#184#253#10'U>7'#157't'#217#129''''#222'{'#165#165#188#5#190'S'#207

+  +'^|'#165#165'=/p'#236#161#209#6#253'~'#168#243#19#172'%'#166'?!'#160'c'#31

+  +#196'0C=>'#169#247' '#142#132#142'!y'#7#128#207#156'8'#190#156#253#5#232#159

+  +'e\'#16#192#7#27#150#8#240#0#186'Z'#1'I'#168'`gg'#7'R;'#132#137#0#243#20'd'#0

+  +'p'#139#218'_'#23#240'#'#215#192#128#159'5'#2'G30D`4'#3#215'g`'#9'Ai'#13#1'$'

+  ,#16'pI?'#231#28's'#242#156'''`'#247#12#17'('#19';8D'#19'p'#192#207#0'/'#8'AK'

+  +'~'#165'{'#230#27#213'>'#173#0#222#196#233#141#138'o'#156'y'#0#191#241#228'O'

+  +#5#220'v'#27#199#1'~'#243''#168#245'x}'#20'Es'#0#31#210#30#234'='#17'jz'#227

+  +#198#141#20#160#135#180'w'#242#245#249'|O'#251'a8'#143#227#130#0#158#223'8'

+  +#160#21#12#6#3#175#211#233#4#180#248#244#0#179#153#0'I'#14'S'#129#30#234#152

+  +#30'n'#164#31'C'#202#215#232'X'#141#142#25'S'#192#152#5#150#4#232#189#186'eY'

+  +#161#21#132'UBP'#154#20'x'#246'$!'#4#156#147'/'#224#247'DK'#176#219#149#243

+  +#182#170#188'2'#210#221#181#225's''>/'#210']z'#234#25#208'/'#28#208'W'#213'|'

+  +'+'#245'E'#221#231#181#144#194#12'*=IwH'#249#5'@O@_'#200'g&'#0'=T|c'#219#11

+  +#232#205'y'#186#235#139#241'>'#198#5#1#28#207'Xj"'#208#218#7#25'@3'#160#7#157

+  +'M'#5','#4'nL'#142#233#206'"'#151#16'|'#157'?`4'#6#248#22'P'#189#24#11#17'D'

+  +#134#16'@*'#244#186'RD'#1'D@'#175'E'#196#194#19'2`"'#192#182#28#243#212#146

+  +'x`'#201#142'/'#0#159#27#21'_'#21'j=7'#212#196'B'#223#195#192#167#207#157#211

+  +#246#1#2#192'B'#191'k'#230#2#158#200#14#210#29#239'Y@'#194#131'H'#232'xj$'

+  +#189#1'=]'#175#188#162#226#187#235#139#241#1#199#5#1#28#239#176#215#215'8'#14

+  +#141'f'#0'3aoo'#143#9'!@i'#218'`'#16#192'l'#160#151#134' '#3#172'A'#8' '#7':'

+  +#206'k'#128#158'^'#202'k9'#30#154#227'J'#252#4#202'1'#13#180'I'#192'f'#128'o'

+  +'H'#0#231#148'!.X'#144'@q'#178#5#208'sQ'#237'-'#240#177#166#247'X'#201#175

+  +#196#161''''#4#176'0'#251#134#0'd!<'''#6#228#144#236#176#223#23'Fk'#0#224#137

+  +#3#210#181#181#181#148'~?'#212#250#140'L'#168#28#160#191'p'#232#157#204#184

+  +' '#128#147#27#165'D\'#233'Y'#168'@'#8#208#12'n'#222#188#233'-#'#4#12#2'M '

+  +#160#14#5#212'au'#219#172#149'&'#14#214#0'0'#0'v'#1'<k'#0#206#218#19#141'@r'

+  +#141'<'#211'T'#131'%?'#182#245#219#249#205#25'}fN'#167'bl'#254'$/'#231#230

+  +''''#6#212#244'r6'#11'2]'#166#155#212'j5k*'#0#240#147#201'$3'#128'o4'#26#185

+  +#145#242#142'M'#143#211#185#0#253#9#141#11#2'8'#189'q$B'#216#216#216#128#198

+  +#128'jE'#159#192#227#19#160'|'#146#164'L'#18'D'#16#216'f'#130#192#2#174#152

+  +#207#231#188'&'#172#225#0#131#29'=3'#176#157'qk'#252#220#163#247'yf'#187'tB'

+  +#4'~'#240#3'Im'#128#157'5'#1'l'#227#24#246'IZ'#231'd'#186#0#199'<y&i*P'#217

+  +#193#17')'#22#218#207#232#251#179'V'#171#5'5>k6'#155#217't:'#205#232#156#243

+  +'e'#18'~'#9#224#171#219#23#227#152#199#5#1#156#141'Q'#186#15#198'\'#192#182

+  +'1'#25#8'H'#30'H'#129'H'#192'#py'#134#24#8#148#30#200#129#128#232#25'r'#160

+  +'}'#143'@j'#23':'#206#128#199'6>'#19#219#4'V'#187#141#181#207#253'L'#148'"'#0

+  +#27#192#243'>}/o'#155#133#190'?'#7#208#137'Dr'#128#156#190'+'#235#247#251'9'

+  +#129#222#2#29#146#189#221'n'#231#6#236#248#156#11#192#159#205'qA'#0'gsT'#239

+  +#139''''#192'Q.1`'#13'r'#184'u'#235#150'7'#28#14'-9'#224'8'#8#2'k'#179'O'#192

+  +#230'5'#8#3#235#245#245'u'#187'm'#6#128#140'5Iy'#11'J'#2';o'#3#220'X?~'#252

+  +'8'#199'6@'#142#253'e@'#199#250#16#176'/'#219#191#24#167'8.'#8#224'|'#141'e'

+  +#247#235#0'9`'#24#130'0'#3'D'#177#236#3#161'Y`]'#175#215#15#0#211#128#218#29

+  +#6#224#24#0'9'#214#135#0#253#176'c'#23#227#12#141#11#2'x1'#198#179#220#199

+  +#163#190#246#168#224#189#0#249'9'#30#23#4'p1.'#198#135'x'#252'p'#251'ut'#3

+  +#215#244'"'#0#0#0#0'IEND'#174'B`'#130'('#0#0#0#128#0#0#0#0#1#0#0#1#0' '#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1

+  +#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1#0#0#0#1#0#0

+  +#0#1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#1#0#0#0#2#128#128#128#2'UUU'#3

+  +'@@@'#4'333'#5'III'#7'@@@'#8'999'#9'999'#9'MMM'#10'FFF'#11'FFF'#11'FFF'#11'M'

+  +'MM'#10'999'#9'@@@'#8'@@@'#8'UUU'#6'333'#5'UUU'#3#128#128#128#2#0#0#0#2#0#0#0

+  +#1#0#0#0#1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#1#128#128#128#2'UUU'#3'UUU'

+  +#6'@@@'#8'FFF'#11'III'#14'<<<'#17'III'#21'EEE'#26'DDD'#30'DDD"EEE%AAA''DDD)A'

+  +'AA+AAA+AAA+DDD)AAA''GGG$FFF!DDD'#30'==='#25'@@@'#20'@@@'#16';;;'#13'FFF'#11

+  +'@@@'#8'333'#5'UUU'#3#128#128#128#2#0#0#0#1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#1#0#0#0#2'UUU'#3'+++'#6'999'#9'NNN'#13'CCC'#19'BBB'#27'GGG$'

+  +'DDD-CCC5DDD<DDDDBBBMCCCTDDDZEEE]DDDaBBBdDDDfCCCgDDDfBBBdBBB`EEE]BBBYDDDSDDD'

+  +'KEEECAAA;AAA3AAA+DDD"GGG'#25'GGG'#18';;;'#13'@@@'#8'333'#5'UUU'#3#0#0#0#2#0

+  +#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#1#0#0#0#2'UUU'#3'UUU'#6'@@@'#12'GGG'#18'BBB'#27'CCC&BBB2DDD@EEENCCC\DDDiDDD'

+  +'tCCC~DDD'#136'DDD'#143'CCC'#149'DCC'#153'DCC'#155'EED'#158'DDC'#160'EED'#162

+  +'EED'#162'EDD'#161'DCC'#160'EDD'#157'CCC'#155'CCC'#152'CCC'#148'BBB'#142'CCC'

+  +#134'DDD|CCCrDDDfEEEYDDDKCCC=EEE0GGG$EEE'#26'<<<'#17'MMM'#10'UUU'#6'UUU'#3#0

+  +#0#0#1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'UUU'#3'+++'#6'FFF'#11'GGG'#18

+  +'FFF'#29'FFF,DDD<AAANCCC_DDDpCCC'#129'DDD'#142'EED'#154'DDC'#163'DDC'#171'DD'

+  +'C'#178'DDC'#183'EDB'#188'EDB'#190'EDB'#192'FFE'#192'FFE'#192'EED'#193'EED'

+  +#194'EED'#194'EED'#193'EEB'#193'FEC'#192'FEC'#192'DDC'#190'DDC'#189'DDC'#187

+  +'DDC'#182'EED'#177'EDD'#169'DDD'#162'CCC'#152'CCC'#140'CCC~DDDmCCC\DDDKBBB:D'

+  +'DD)BBB'#27'@@@'#16'UUU'#9'333'#5#128#128#128#2#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'UUU'#3'III'#7'DDD'#15

+  +'EEE'#26'DDD)EEE;DDDODDDfBBB{CCC'#141'DDC'#156'DDC'#168'DDC'#178'EDB'#187'EE'

+  +'D'#192'FEC'#195'FFC'#198'HFD'#200'HFD'#201'GGC'#202'HFC'#203'IGD'#203'IGD'

+  +#203'JHC'#203'IHD'#204'IHD'#204'IHD'#204'IHC'#204'IGD'#204'IGD'#203'IGD'#203

+  +'GEC'#203'GEC'#203'FFC'#202'GFD'#201'FEC'#199'FFE'#196'EDB'#194'DDC'#190'EED'

+  ,#185'EDD'#177'DDD'#166'DDD'#153'DDD'#139'DDDxDDDbDDDKFFF7CCC&CCC'#23';;;'#13

+  +'UUU'#6'UUU'#3#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'UUU'#3'@@'

+  +'@'#8'@@@'#16'BBB'#31'BBB2BBBIBBBaCCCyDDD'#142'DDC'#160'DDC'#175'FEC'#186'FF'

+  +'E'#192'GFD'#197'HFD'#200'HFC'#202'IGD'#203'JID'#204'OF>'#211'SC6'#219'W@0'

+  +#227'[>+'#235']<('#238'^<'''#240'_<%'#243'`<#'#245'a;"'#247'a:!'#248'a;"'#246

+  +'`<$'#245'_<%'#242'^='''#240'\=)'#237'Z=,'#233'V@1'#225'RD8'#217'NG?'#210'JH'

+  +'D'#204'IHC'#204'HHD'#204'GEC'#203'FEC'#202'EED'#198'EED'#195'DDC'#190'DDC'

+  +#183'DDD'#172'DDD'#157'DDD'#138'DDDtCCC\DDDDCCC.@@@'#28'DDD'#15'III'#7'UUU'#3

+  +#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#1'UUU'#3'@@@'#8'KKK'#17'HHH CCC5CCCPDDDlCCC'#134'DDC'#156

+  +'EED'#172'FEC'#185'GFD'#193'GFC'#198'HFC'#202'IGD'#203'PE;'#213'VA0'#227']<('

+  +#239'a;#'#246'd9'#30#254'g:'#29#255'g:'#30#255'i<'#30#255'j='#31#255'j>'#30

+  +#255'k>'#30#255'l?'#31#255'l@'#31#255'mA'#31#255'nA'#31#255'm@'#31#255'l@'#31

+  +#255'l?'#31#255'k>'#30#255'j>'#30#255'j='#31#255'i<'#30#255'g:'#30#255'f:'#29

+  +#255'd9'#31#252'`<#'#245'[=*'#236'UA3'#223'MF?'#210'IHC'#204'HFD'#204'FFC'

+  +#203'FFE'#200'DDC'#197'EED'#191'DCC'#182'DDD'#170'CCC'#152'CCC'#129'DDDfDDDK'

+  +'DDD1FFF'#29'@@@'#16'III'#7'UUU'#3#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#1'UUU'#3'III'#7'@@@'#16'@@@ FFF7DDDRCCCoCCC'#140'DDC'

+  +#163'EED'#180'EED'#191'FFC'#198'IGD'#201'ME?'#208'UA2'#224'\<('#238'b9 '#250

+  +'f:'#29#255'h;'#30#255'j>'#30#255'm@'#31#255'oB '#255'qD '#255'sF '#255'uH!'

+  +#255'|L#'#255#128'O$'#255#133'Q%'#255#136'S&'#255#139'V'''#255#143'X('#255

+  +#145'Y)'#255#142'W('#255#139'U'''#255#135'S&'#255#131'Q%'#255#128'O$'#255'yK'

+  +'"'#255'tG!'#255'rE '#255'pD '#255'nA '#255'l@'#31#255'j='#31#255'g;'#30#255

+  +'e9'#29#255'a;!'#247'Z=+'#234'RB5'#221'JGC'#207'HFD'#204'FEC'#203'FFE'#200'E'

+  +'ED'#196'DDC'#189'DDD'#177'CCC'#159'DDD'#135'CCCjBBBMBBB2FFF'#29'III'#14'UUU'

+  +#6#128#128#128#2#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'333'#5';;;'#13'BBB'

+  +#27'AAA3BBBQDDDqDDD'#142'EED'#165'EDB'#183'FEC'#194'HFD'#200'IFB'#205'SA3'

+  +#223'^;&'#242'e8'#29#255'g;'#30#255'j>'#31#255'mA'#31#255'pD!'#255'tG!'#255

+  +'~M#'#255#141'W('#255#151']*'#255#160'c-'#255#169'i0'#255#178'n1'#255#181'q2'

+  +#255#182's3'#255#183't3'#255#184't3'#255#184'v3'#255#185'v4'#255#186'w3'#255

+  +#185'v3'#255#184'u3'#255#184't3'#255#183't3'#255#182'r3'#255#181'q2'#255#175

+  +'l1'#255#166'h/'#255#158'a,'#255#149'\*'#255#138'U('#255'zK"'#255'sF '#255'p'

+  +'C '#255'l@'#31#255'i='#31#255'g;'#30#255'c8'#31#252'[<*'#237'RC8'#218'IGD'

+  +#205'HFD'#204'EED'#201'DDC'#198'EED'#191'DDD'#179'CCC'#161'DDD'#136'CCCkEEEJ'

+  +'DDD-@@@'#24'FFF'#11'@@@'#4#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'UUU'#3'999'#9'FFF'#22'CCC*DDDGDDD'

+  +'iCCC'#138'EED'#165'FEC'#184'FEC'#194'HHD'#200'QC9'#216'[<*'#237'c8'#31#253

+  +'g;'#30#255'j>'#31#255'nA '#255'sF!'#255'|M#'#255#141'W('#255#158'a,'#255#173

+  +'k1'#255#181'r3'#255#185'v4'#255#187'y4'#255#189'{4'#255#191'~5'#255#193#129

+  +'5'#255#195#131'5'#255#196#132'6'#255#197#134'6'#255#198#134'6'#255#199#136

+  +'6'#255#200#136'6'#255#200#137'6'#255#199#136'6'#255#198#135'6'#255#198#134

+  +'6'#255#197#133'5'#255#196#132'6'#255#195#131'5'#255#193#128'5'#255#191'~4'

+  +#255#188'z4'#255#186'x4'#255#184'u3'#255#181'q2'#255#168'i/'#255#153'_+'#255

+  +#137'T'''#255'yJ"'#255'rE '#255'm@'#31#255'i<'#31#255'f:'#30#255'b9!'#249'X>'

+  +'.'#232'MD>'#212'HFD'#204'EED'#202'EED'#198'EED'#192'CCC'#180'CCC'#160'DDD'

+  +#132'DDDbCCCACCC&CCC'#19'@@@'#8'UUU'#3#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'333'#5'III'#14'>>>!DDD<DDD^CCC'#129'EED'#158

+  +'DDC'#180'FEC'#194'IGD'#200'RB7'#219'^9%'#244'e8'#29#255'i<'#31#255'mA '#255

+  +'rE!'#255'|L#'#255#149'[+'#255#170'j1'#255#181'r3'#255#185'v4'#255#188'z4'

+  +#255#192'6'#255#196#132'6'#255#199#136'6'#255#202#138'7'#255#204#142'7'#255

+  +#206#145'7'#255#209#147'8'#255#211#150'8'#255#212#152'9'#255#213#152'9'#255

+  +#213#153'9'#255#214#154'9'#255#215#155':'#255#215#155'9'#255#215#155':'#255

+  +#214#154'9'#255#213#153'9'#255#212#152'9'#255#211#151'9'#255#210#149'9'#255

+  +#208#147'8'#255#206#143'8'#255#203#141'8'#255#201#138'7'#255#198#135'7'#255

+  +#195#131'5'#255#191'~5'#255#188'y4'#255#184'u3'#255#180'q3'#255#165'f/'#255

+  +#142'W('#255'xJ"'#255'pD!'#255'l?'#31#255'h;'#30#255'd7'#30#255'Z<)'#239'NC<'

+  +#214'HFD'#204'EED'#202'DDC'#198'EDD'#191'DDD'#176'DDD'#153'CCCzCCCXBBB6FFF'

+  +#29'@@@'#12'@@@'#4#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#128#128#128#2

+  +'@@@'#8'@@@'#20'FFF,AAANBBBtDCC'#149'DDC'#174'EED'#191'GEC'#199'R@5'#220'_9#'

+  +#245'e9'#30#255'i='#31#255'nB!'#255'wI#'#255#142'W)'#255#165'f/'#255#181'q3'

+  +#255#186'x4'#255#191'~5'#255#195#131'6'#255#199#136'7'#255#203#140'8'#255#207

+  +#145'9'#255#211#150'9'#255#214#154':'#255#216#157':'#255#219#160';'#255#221

+  +#162';'#255#223#164';'#255#225#167'<'#255#226#168'<'#255#226#169'='#255#227

+  +#170'<'#255#228#171'<'#255#228#171'='#255#228#172'='#255#228#171'='#255#227

+  +#170'<'#255#227#169'<'#255#226#169'='#255#226#168'<'#255#224#167';'#255#222

+  +#164';'#255#220#162';'#255#218#159':'#255#216#157':'#255#213#154':'#255#210

+  +#149'9'#255#206#144'8'#255#202#139'8'#255#198#134'7'#255#194#129'7'#255#189

+  +'|6'#255#184'v4'#255#178'n2'#255#159'b.'#255#135'T'''#255'tF!'#255'mA '#255

+  +'h;'#31#255'd8'#30#255'\;('#240'OC;'#216'GGD'#204'EDD'#201'DDC'#197'DDD'#187

+  +'DDD'#170'DDD'#143'BBBlDDDGAAA''KKK'#17'UUU'#6#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'U'

+  +'UU'#3'FFF'#11'BBB'#27'FFF7EEE]DDD'#132'DDC'#164'FEE'#186'GGD'#197'OA8'#216

+  +'_8#'#246'e9'#30#255'j= '#255'oB!'#255'zK$'#255#151'^,'#255#176'n4'#255#184

+  +'v5'#255#189'|6'#255#194#131'7'#255#200#137'8'#255#205#144':'#255#210#149';'

+  +#255#214#154';'#255#217#158';'#255#221#163'<'#255#225#167'='#255#227#171'='

+  +#255#229#173'='#255#231#175'>'#255#232#177'>'#255#234#179'?'#255#236#181'>'

+  +#255#236#182'?'#255#237#183'?'#255#237#183'?'#255#238#183'@'#255#238#184'?'

+  +#255#238#185'?'#255#238#184'?'#255#238#183'@'#255#237#182'?'#255#237#183'?'

+  +#255#236#182'?'#255#236#181'>'#255#234#179'>'#255#232#176'>'#255#230#175'>'

+  +#255#229#172'='#255#227#169'='#255#224#167'='#255#220#161'<'#255#217#157'<'

+  +#255#213#153';'#255#209#148':'#255#204#142'9'#255#198#135'8'#255#193#129'7'

+  +#255#188'{6'#255#183't5'#255#171'k2'#255#142'W)'#255'tH"'#255'nA '#255'h<'#31

+  +#255'd7'#30#255'[:('#240'KD?'#211'GFD'#204'DDC'#201'EDD'#195'CCC'#182'CCC'

+  +#159'CCC}EEEUBBB2@@@'#24'999'#9'UUU'#3#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'333'#5'III'#14'BBB#EEECCCCkEEE'

+  +#145'DDC'#174'FFE'#192'KE@'#206'Z;)'#238'c8'#30#255'i<'#31#255'oB!'#255'|M%'

+  +#255#153'_-'#255#178'o4'#255#186'x6'#255#192#128'7'#255#198#135'9'#255#204

+  +#142':'#255#209#149';'#255#214#155'='#255#219#161'>'#255#223#167'>'#255#227

+  +#170'>'#255#230#174'?'#255#232#177'@'#255#235#181'A'#255#237#183'A'#255#238

+  +#185'A'#255#240#187'A'#255#241#188'A'#255#242#189'B'#255#243#190'A'#255#244

+  +#191'B'#255#244#192'B'#255#244#191'B'#255#244#192'B'#255#244#192'B'#255#245

+  +#193'A'#255#244#192'B'#255#244#192'B'#255#244#191'B'#255#244#192'B'#255#244

+  +#191'B'#255#243#190'A'#255#242#189'B'#255#240#187'A'#255#239#186'A'#255#238

+  +#184'@'#255#237#183'A'#255#235#179'@'#255#232#176'?'#255#229#173'?'#255#226

+  +#169'?'#255#223#165'>'#255#218#160'='#255#213#153'<'#255#208#147';'#255#202

+  +#140':'#255#196#133'9'#255#190'~7'#255#184'v6'#255#173'l3'#255#145'Y+'#255'u'

+  +'H$'#255'm@ '#255'g;'#31#255'b7'#31#253'U>/'#230'IEC'#206'FFE'#202'EED'#199

+  +'CCC'#189'DDD'#170'DDD'#139'BBBdCCC=BBB'#31'@@@'#12'UUU'#3#0#0#0#1#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'UUU'#6'KKK'#17'DDD)EEENDDDxDC'

+  +'C'#157'DDC'#182'GGC'#197'T=1'#225'a7 '#252'g;'#31#255'l@ '#255'wI$'#255#154

+  +'^.'#255#179'o6'#255#186'x7'#255#193#128'9'#255#200#137':'#255#207#146'<'#255

+  +#212#153'>'#255#217#159'>'#255#222#166'?'#255#227#170'@'#255#231#175'A'#255

+  +#234#180'B'#255#236#182'B'#255#238#185'B'#255#240#187'B'#255#242#190'D'#255

+  +#243#191'C'#255#244#192'D'#255#245#193'C'#255#246#194'D'#255#247#194'D'#255

+  +#247#196'E'#255#247#196'D'#255#247#196'D'#255#248#197'D'#255#248#197'D'#255

+  +#248#197'D'#255#248#197'D'#255#248#197'D'#255#248#197'D'#255#248#196'D'#255

+  +#247#196'D'#255#247#196'D'#255#247#195'E'#255#246#195'D'#255#245#193'D'#255

+  +#245#193'C'#255#244#192'D'#255#243#191'C'#255#242#189'C'#255#240#186'C'#255

+  +#238#184'C'#255#236#182'B'#255#233#179'B'#255#230#174'A'#255#226#169'@'#255

+  +#221#164'?'#255#216#157'>'#255#211#151'='#255#205#143'<'#255#198#135':'#255

+  +#191'8'#255#184'w7'#255#174'l4'#255#144'X+'#255'rE"'#255'j> '#255'e9'#30#255

+  +'_8"'#247'O@8'#219'GFD'#204'DDC'#201'CCC'#194'CCC'#178'DDD'#151'DDDqDDDGGGG$'

+  +'III'#14'@@@'#4#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'III'#7'@@@'#20

+  +'CCC.DDDVCCC'#130'EED'#165'DDC'#189'LB='#207']7$'#244'd7'#31#255'j> '#255'qE'

+  +'"'#255#140'W+'#255#174'l5'#255#186'x8'#255#193#129':'#255#200#138'<'#255#207

+  +#146'>'#255#213#155'?'#255#220#163'@'#255#225#169'A'#255#229#174'B'#255#233

+  +#179'D'#255#236#182'D'#255#239#185'D'#255#241#189'E'#255#242#190'E'#255#244

+  +#192'E'#255#245#194'E'#255#246#195'F'#255#247#195'F'#255#247#196'G'#255#247

+  +#197'F'#255#248#197'F'#255#248#197'F'#255#249#198'F'#255#249#198'G'#255#249

+  +#198'G'#255#249#198'G'#255#249#198'G'#255#249#198'G'#255#249#198'G'#255#249

+  +#198'G'#255#249#198'G'#255#249#198'G'#255#249#198'G'#255#249#198'G'#255#249

+  +#198'F'#255#248#197'F'#255#248#197'F'#255#247#196'F'#255#247#196'F'#255#247

+  +#195'F'#255#246#194'F'#255#244#193'F'#255#243#191'E'#255#242#190'E'#255#240

+  +#188'E'#255#238#185'D'#255#235#181'D'#255#232#178'C'#255#228#172'C'#255#223

+  +#167'B'#255#218#161'@'#255#212#153'?'#255#205#144'='#255#198#135';'#255#191

+  +'9'#255#183'u7'#255#167'g3'#255#130'P('#255'oB"'#255'h< '#255'c7'#30#255'X:'

+  +'*'#237'HFB'#207'EEE'#202'DCC'#197'DDD'#184'CCC'#160'CCCzEEENFFF(@@@'#16'333'

+  +#5#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'III'#7'FFF'#22'BBB2CCC\DDD'#136'DDC'#171

+  +'EED'#192'Q?5'#219'a6'#31#252'f:'#31#255'mA!'#255'N'''#255#164'f3'#255#182

+  +'u8'#255#190':'#255#199#138'='#255#207#147'?'#255#213#155'A'#255#220#163'B'

+  +#255#225#170'D'#255#230#177'E'#255#234#181'E'#255#237#184'F'#255#240#188'G'

+  +#255#242#189'G'#255#243#192'G'#255#244#193'H'#255#245#194'H'#255#246#195'H'

+  ,#255#247#196'H'#255#247#197'H'#255#247#197'H'#255#248#198'H'#255#248#198'H'

+  +#255#248#197'H'#255#248#198'H'#255#248#198'I'#255#249#198'I'#255#249#198'I'

+  +#255#249#198'I'#255#249#198'I'#255#249#198'I'#255#249#198'I'#255#249#198'I'

+  +#255#249#198'I'#255#249#198'I'#255#249#198'I'#255#249#198'I'#255#248#198'I'

+  +#255#248#198'H'#255#248#198'H'#255#248#198'H'#255#248#198'H'#255#247#197'H'

+  +#255#247#196'I'#255#247#195'H'#255#246#195'H'#255#245#195'H'#255#244#193'H'

+  +#255#243#191'G'#255#241#189'G'#255#239#186'G'#255#236#183'F'#255#233#180'F'

+  +#255#229#175'D'#255#224#168'D'#255#218#161'B'#255#211#153'@'#255#205#144'?'

+  +#255#196#134'='#255#188'{:'#255#180'r8'#255#155'_/'#255'wJ$'#255'j? '#255'e8'

+  +#30#255']8#'#246'LB<'#213'FEE'#203'EED'#199'DDD'#188'DDD'#165'DDD'#128'DDDSF'

+  +'FF,GGG'#18'+++'#6#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'III'#7'CCC'#23'BBB6DDDaCCC'#141'DDC'#174

+  +'GDB'#196'V:+'#233'c7'#30#255'h; '#255'pC#'#255#146'Z-'#255#179'p7'#255#187

+  +'{;'#255#196#133'='#255#204#144'?'#255#212#154'B'#255#219#163'E'#255#225#170

+  +'E'#255#230#176'G'#255#234#181'H'#255#238#185'I'#255#240#189'I'#255#242#190

+  +'J'#255#243#192'J'#255#244#193'J'#255#245#195'J'#255#246#195'J'#255#246#196

+  +'J'#255#247#196'K'#255#247#196'K'#255#247#197'K'#255#247#197'K'#255#247#197

+  +'K'#255#247#197'J'#255#247#197'J'#255#247#198'J'#255#247#198'J'#255#247#198

+  +'J'#255#247#198'J'#255#247#198'J'#255#247#198'J'#255#247#198'J'#255#247#198

+  +'J'#255#247#198'J'#255#247#198'J'#255#247#198'J'#255#247#198'J'#255#247#198

+  +'J'#255#247#198'J'#255#247#197'J'#255#247#197'J'#255#247#197'J'#255#247#197

+  +'K'#255#247#197'K'#255#247#197'K'#255#247#196'K'#255#246#196'K'#255#246#196

+  +'J'#255#246#195'J'#255#245#195'J'#255#244#194'J'#255#243#191'I'#255#241#189

+  +'I'#255#239#188'I'#255#236#184'H'#255#233#180'H'#255#228#174'G'#255#223#168

+  +'E'#255#217#160'C'#255#210#151'B'#255#202#141'?'#255#193#130'<'#255#185'x:'

+  +#255#174'm6'#255#134'S*'#255'mA"'#255'f:'#31#255'a6'#30#253'R>4'#224'FFE'#203

+  +'EED'#200'CCC'#190'DDD'#169'CCC'#133'CCCXAAA/CCC'#19'+++'#6#0#0#0#1#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'III'#7'CCC'#23'BB'

+  +'B6CCCcCCC'#144'EED'#177'JC>'#202'[6"'#244'c8'#31#255'j?!'#255'xI&'#255#162

+  +'d2'#255#183'u:'#255#192#129'='#255#200#140'@'#255#209#150'B'#255#217#160'E'

+  +#255#223#169'G'#255#229#176'H'#255#233#181'J'#255#236#185'J'#255#239#188'K'

+  +#255#241#190'K'#255#242#192'K'#255#243#193'L'#255#244#194'L'#255#245#195'L'

+  +#255#245#195'L'#255#245#195'L'#255#246#196'L'#255#246#196'L'#255#246#196'L'

+  +#255#246#196'L'#255#246#196'M'#255#246#196'M'#255#246#197'M'#255#246#197'M'

+  +#255#246#197'M'#255#246#197'M'#255#246#197'M'#255#246#197'M'#255#246#197'M'

+  +#255#246#197'M'#255#246#197'M'#255#246#197'M'#255#246#197'M'#255#246#197'M'

+  +#255#246#197'M'#255#246#197'M'#255#246#197'M'#255#246#197'M'#255#246#197'M'

+  +#255#246#197'M'#255#246#196'M'#255#246#196'M'#255#246#196'M'#255#246#196'L'

+  +#255#246#196'L'#255#246#196'L'#255#246#196'L'#255#245#195'L'#255#245#196'L'

+  +#255#244#195'M'#255#244#194'L'#255#243#193'L'#255#242#192'L'#255#241#190'K'

+  +#255#238#188'K'#255#236#184'J'#255#232#179'I'#255#228#173'H'#255#222#166'F'

+  +#255#215#158'E'#255#207#148'B'#255#198#137'?'#255#190'~<'#255#180'r9'#255#150

+  +']/'#255'qE$'#255'h< '#255'b6'#30#255'W9*'#235'GED'#204'DDC'#201'DDD'#192'CC'

+  +'C'#172'CCC'#137'DDDZAAA/GGG'#18'333'#5#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#1'+++'#6'III'#21'CCC5DDDbCCC'#145'DDC'#178'LB;'#206'^6 '

+  +#249'd8'#31#255'l@!'#255#131'Q*'#255#172'k7'#255#186'z;'#255#196#133'?'#255

+  +#205#146'C'#255#213#156'E'#255#220#165'G'#255#227#173'I'#255#232#180'K'#255

+  +#236#184'L'#255#238#187'L'#255#240#189'N'#255#241#191'N'#255#242#192'N'#255

+  +#243#193'N'#255#244#194'N'#255#244#194'N'#255#244#194'O'#255#244#195'O'#255

+  +#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255

+  +#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255

+  +#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255

+  +#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255

+  +#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255

+  +#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255

+  ,#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#195'O'#255#244#194'O'#255

+  +#244#195'N'#255#244#194'N'#255#243#193'N'#255#242#192'M'#255#241#190'N'#255

+  +#240#189'M'#255#237#186'M'#255#235#182'L'#255#230#178'K'#255#225#171'I'#255

+  +#219#163'G'#255#211#153'D'#255#202#143'B'#255#192#130'>'#255#183'u:'#255#164

+  +'f4'#255'yK&'#255'i=!'#255'c7'#30#255'Z8%'#241'GEC'#205'DDC'#201'CCC'#193'DD'

+  +'D'#173'DDD'#136'BBBYDDD-KKK'#17'333'#5#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#1'333'#5'CCC'#19'BBB2CCC_DDD'#143'DDC'#178'M@8'#211'_5'#31#251'e9'#31

+  +#255'lA"'#255#144'Y/'#255#179'r9'#255#188'}='#255#198#138'B'#255#208#149'D'

+  +#255#217#161'H'#255#223#170'K'#255#229#177'L'#255#234#181'M'#255#236#186'N'

+  +#255#239#188'O'#255#240#190'P'#255#241#191'P'#255#242#192'P'#255#242#192'P'

+  +#255#242#193'P'#255#243#193'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'#255#243#194'P'

+  +#255#243#194'P'#255#243#193'P'#255#242#193'P'#255#242#192'O'#255#242#192'P'

+  +#255#241#192'P'#255#240#190'P'#255#238#188'O'#255#236#185'N'#255#232#180'M'

+  +#255#228#175'L'#255#222#167'I'#255#215#159'H'#255#205#147'D'#255#196#134'@'

+  +#255#186'y<'#255#173'm7'#255#130'O*'#255'j?!'#255'c8'#31#255'[7#'#245'HDA'

+  +#208'DDC'#201'CCC'#193'CCC'#172'CCC'#134'AAAVAAA+@@@'#16'@@@'#4#0#0#0#1#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#1'@@@'#4'<<<'#17'CCC.CCC[CCC'#140'EED'#176'O>5'#213'_5'#30#253

+  +'e9'#31#255'nB#'#255#151'\1'#255#181's:'#255#191#129'@'#255#201#142'C'#255

+  +#211#154'G'#255#219#164'K'#255#226#173'M'#255#231#179'O'#255#234#184'P'#255

+  +#237#187'Q'#255#239#189'Q'#255#240#190'R'#255#240#191'Q'#255#241#192'R'#255

+  +#241#192'R'#255#241#192'R'#255#242#192'R'#255#242#192'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#193'R'#255

+  +#242#193'R'#255#242#193'R'#255#242#193'R'#255#242#192'R'#255#242#192'R'#255

+  +#241#192'R'#255#241#192'R'#255#241#192'R'#255#240#191'Q'#255#240#190'R'#255

+  +#238#189'Q'#255#236#186'P'#255#234#182'O'#255#230#177'N'#255#224#171'L'#255

+  +#217#162'J'#255#208#150'F'#255#198#138'C'#255#188'}>'#255#177'o:'#255#136'S,'

+  +#255'k?"'#255'c8'#31#255'\6!'#248'JC?'#211'DCC'#201'CCC'#193'CCC'#171'BBB'

+  +#131'DDDRAAA''777'#14'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3';;;'#13'AAA''CCCTBBB'#135'DD'

+  +'C'#174'N=5'#213'`4'#29#254'e9'#31#255'oC$'#255#156'`3'#255#181'u<'#255#193

+  +#131'A'#255#204#146'E'#255#213#157'I'#255#221#167'M'#255#227#175'O'#255#232

+  +#180'Q'#255#235#184'R'#255#237#187'S'#255#238#189'S'#255#239#190'S'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#234#187'R'#255#202#161'G'#255#232

+  +#185'R'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240#191'T'#255#240

+  +#191'T'#255#240#191'T'#255#240#191'T'#255#239#189'S'#255#238#188'R'#255#236

+  ,#186'R'#255#234#184'Q'#255#231#179'Q'#255#226#173'O'#255#219#165'L'#255#211

+  +#154'H'#255#201#142'E'#255#190#128'@'#255#179'q:'#255#140'V.'#255'l@"'#255'c'

+  +'8'#31#255'\4'#31#250'JC>'#211'CCC'#201'DDD'#192'CCC'#168'CCC~DDDKFFF!MMM'#10

+  +#128#128#128#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#128#128#128#2'333'#10'@@@ EEEJCCC~EDD'#169'L?8'#208'^4'#30#253'd8'

+  +' '#255'pD%'#255#159'b4'#255#182'v='#255#194#132'C'#255#205#147'H'#255#215

+  +#160'L'#255#222#169'O'#255#228#176'Q'#255#232#181'S'#255#235#185'T'#255#236

+  +#187'T'#255#237#188'U'#255#238#189'U'#255#238#190'U'#255#238#190'U'#255#238

+  +#191'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#181#144'@'#255';/'#21#255#21#16#7#255#9#7#3#255#2

+  +#2#1#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#7#6#3#255#17#14#6#255#31#25

+  +#11#255'2'''#18#255'SB'#29#255#157'}8'#255#233#186'S'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#238#190'U'#255#238#190'U'#255#238#190'U'#255#238#189'U'#255#237

+  +#188'U'#255#236#186'T'#255#234#184'T'#255#231#180'S'#255#226#175'Q'#255#220

+  +#166'N'#255#212#156'K'#255#202#143'F'#255#190#129'A'#255#179'r<'#255#145'Y0'

+  +#255'k?"'#255'c7'#31#255'[4 '#248'IC@'#209'DDD'#200'CCC'#190'CCC'#163'DDDtCC'

+  +'CAEEE'#26'III'#7#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#1'III'#7'==='#25'AAA?CCCsBBB'#162'K?;'#202'^4'#30#252'c8 '#255'oB'

+  +'%'#255#160'b5'#255#183'v>'#255#194#134'D'#255#205#148'J'#255#215#161'M'#255

+  +#223#171'Q'#255#228#177'T'#255#232#182'U'#255#234#185'V'#255#236#187'V'#255

+  +#236#187'V'#255#237#188'W'#255#237#189'W'#255#237#188'W'#255#237#188'W'#255

+  +#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255

+  +#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255

+  +#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255

+  +#159'~:'#255#16#13#6#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#1#0#0#255#16#13#6#255'9-'#21#255'y`,'#255#208#165'M'

+  +#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'

+  +#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'

+  +#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'#255#237#188'W'

+  +#255#237#188'W'#255#237#189'W'#255#237#188'W'#255#236#187'V'#255#235#186'V'

+  +#255#234#184'U'#255#231#180'U'#255#227#175'R'#255#221#169'Q'#255#213#157'L'

+  +#255#202#144'H'#255#191#129'C'#255#180's='#255#145'X0'#255'j>#'#255'b6'#31

+  +#255'Z5#'#245'GDB'#206'DDD'#200'CCC'#186'DDD'#154'EEEhBBB6@@@'#20'333'#5#0#0

+  +#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'@@@'#4'GGG'#18'AAA3DDDf'

+  +'CCC'#152'IA>'#195'\4 '#250'c7'#31#255'm@#'#255#156'_5'#255#182'v?'#255#194

+  +#134'E'#255#206#148'K'#255#215#161'O'#255#223#171'S'#255#228#178'V'#255#232

+  +#182'V'#255#233#185'X'#255#234#186'X'#255#235#187'X'#255#236#187'X'#255#236

+  +#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236

+  +#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236

+  +#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236

+  +#188'X'#255#236#188'X'#255#236#188'X'#255'9-'#21#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#6#5#2#255'$'#29#14#255'ZH"'#255

+  +#169#135'@'#255#234#186'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255

+  +#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255

+  +#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#187'X'#255

+  +#235#187'Y'#255#235#186'X'#255#234#186'X'#255#233#184'W'#255#231#180'W'#255

+  +#227#176'T'#255#221#169'R'#255#213#158'N'#255#203#145'J'#255#192#130'D'#255

+  +#179's='#255#139'U/'#255'i="'#255'a5'#30#255'X7%'#242'FDC'#204'CCC'#198'DDD'

+  +#180'CCC'#144'CCC[AAA+III'#14'UUU'#3#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#128#128#128#2'@@@'#12'AAA''CCCWCCC'#140'GB?'#185'Z4!'#247'a6'#30#255'j?"'

+  +#255#151']2'#255#181't>'#255#194#133'F'#255#206#149'M'#255#215#161'Q'#255#223

+  +#170'T'#255#228#178'W'#255#231#181'Y'#255#232#183'Y'#255#233#185'Z'#255#234

+  +#185'Y'#255#234#186'Y'#255#234#186'Y'#255#234#186'Z'#255#234#186'Z'#255#234

+  +#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234

+  +#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234

+  +#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255'C5'

+  +#26#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#20#16#8#255'K;'#29

+  +#255#189#150'I'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'

+  +#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'#255#234#186'Z'

+  +#255#234#186'Z'#255#234#186'Y'#255#234#186'Y'#255#234#185'Y'#255#233#185'Z'

+  +#255#232#183'Y'#255#230#181'X'#255#226#176'W'#255#221#169'T'#255#213#159'O'

+  +#255#203#145'K'#255#190#129'D'#255#178'p='#255#134'Q-'#255'g;"'#255'`4'#29

+  +#255'U7('#238'CCC'#202'DDD'#195'DDD'#173'BBB'#131'CCCL@@@ 999'#9#0#0#0#2#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#1'III'#7'BBB'#27'CCCEDDD|DDD'#170'V6%'#238'`5'#30

+  +#255'h<"'#255#145'Y1'#255#179's?'#255#192#132'F'#255#205#148'M'#255#215#161

+  +'R'#255#222#171'U'#255#227#176'X'#255#230#181'Z'#255#231#183'Z'#255#232#183

+  +'['#255#232#184'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185

+  +'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185

+  +'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185

+  +'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185

+  +'['#255'd1'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#13#11#5#255'N>'#31#255#193#153'L'#255#233

+  +#185'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233

+  +#185'['#255#233#185'['#255#233#185'['#255#233#185'['#255#233#184'['#255#232

+  +#184'['#255#232#183'Z'#255#231#182'Z'#255#229#180'Y'#255#226#175'X'#255#220

+  +#168'U'#255#213#158'R'#255#201#144'K'#255#189'D'#255#175'n<'#255#128'N+'#255

+  +'e9 '#255'_3'#29#255'Q;1'#227'CCC'#201'CCC'#191'CCC'#163'CCCrAAA;FFF'#22'333'

+  +#5#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#1'@@@'#4'<<<'#17'AAA3EEEhCCC'#156'R:/'#220'_3'#29

+  +#255'e: '#255#134'Q-'#255#178'p>'#255#190#130'F'#255#203#145'M'#255#213#161

+  +'S'#255#221#170'W'#255#226#176'Z'#255#229#180'Z'#255#230#182'\'#255#231#182

+  +'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183

+  +'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183

+  +'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183

+  +'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183

+  +'\'#255#180#142'G'#255#1#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#15#12#6#255'VE"'#255#215#171'V'#255#231#183'\'#255#231#183'\'#255#231

+  +#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231

+  +#183'\'#255#231#183'\'#255#231#182'\'#255#230#181'['#255#228#178'['#255#225

+  +#175'Y'#255#219#168'W'#255#211#156'Q'#255#200#142'K'#255#187'|D'#255#172'k<'

+  +#255'wF('#255'c7 '#255'^1'#30#254'K@:'#214'DDD'#199'CCC'#184'CCC'#148'AAA^GG'

+  +'G+NNN'#13'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'MMM'#10'@@@$DDDSDDD'#139'L?8'#197'^1'#29#254

+  +'c7 '#255'wG)'#255#173'l<'#255#188'E'#255#201#144'N'#255#212#158'T'#255#220

+  +#169'X'#255#225#175'['#255#228#179'\'#255#229#180'\'#255#230#181']'#255#230

+  +#181']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230

+  +#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230

+  +#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230

+  ,#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#221

+  +#175'Y'#255#10#8#4#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#1#1#1#255'4)'#21#255#184#146'J'#255#230#182']'#255

+  +#230#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255#230#182']'#255

+  +#230#182']'#255#230#181']'#255#229#182']'#255#228#180']'#255#227#178'\'#255

+  +#224#174'['#255#218#166'W'#255#209#155'R'#255#198#139'K'#255#184'zC'#255#162

+  +'d8'#255'l@$'#255'a5'#30#255'Z3 '#249'FBA'#206'DDD'#196'CCC'#174'CCC'#129'BB'

+  +'BIFFF'#29'@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#1'333'#5'FFF'#22'BBB>CCCvFA?'#174'Z3'#31#248'`5'#30

+  +#255'l@$'#255#163'd9'#255#184'{D'#255#199#142'N'#255#210#156'T'#255#218#167

+  +'Y'#255#223#174'\'#255#226#177'^'#255#228#179'^'#255#228#179'^'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255'bM)'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#27#21#11#255#140

+  +'o;'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#228#179'^'#255#227#179'^'#255#226#176

+  +']'#255#222#172'['#255#216#164'X'#255#207#152'R'#255#195#137'K'#255#181'tA'

+  +#255#149'Z3'#255'g<"'#255'_3'#29#255'V6'''#239'CCC'#201'CCC'#190'CCC'#159'CC'

+  +'CkCCC5GGG'#18'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#2'@@@'#12'CCC*DDD^DDD'#150'U6('#230'^2'#28#255'f:!'#255

+  +#149'Z3'#255#181'uB'#255#195#137'K'#255#208#154'T'#255#216#165'Y'#255#221#172

+  +']'#255#225#176'^'#255#226#178'_'#255#227#178'_'#255#227#178'_'#255#227#179

+  +'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179

+  +'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179

+  +'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179

+  +'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179

+  +'_'#255#13#10#6#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255'&'#30#16#255#208#164'W'#255#227#179'_'#255#227#179'_'#255#227#179'_'

+  +#255#227#179'_'#255#227#178'_'#255#227#178'_'#255#226#179'`'#255#226#177'_'

+  +#255#224#176'^'#255#220#170'\'#255#214#162'X'#255#205#149'R'#255#191#131'I'

+  +#255#177'p?'#255#131'O.'#255'c7 '#255']1'#29#255'N;3'#222'DDD'#199'DDD'#181

+  +'CCC'#140'DDDSDDD"999'#9#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#1'+++'#6'@@@'#24'EEECCCC~K=7'#193']0'#28#255'b6'#31#255#129'M'

+  +','#255#177'o@'#255#191#131'J'#255#204#149'S'#255#214#163'Z'#255#220#171']'

+  +#255#223#174'_'#255#225#176'`'#255#225#177'`'#255#226#177'`'#255#226#177'`'

+  +#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'

+  +#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'

+  +#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'

+  +#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'#255#226#177'`'

+  +#255#161'~D'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  ,#255#0#0#0#255#0#0#0#255#4#3#2#255#134'i9'#255#226#177'`'#255#226#177'`'#255

+  +#226#177'`'#255#226#177'`'#255#226#177'`'#255#225#178'`'#255#225#177'`'#255

+  +#224#176'_'#255#222#174'^'#255#219#169']'#255#212#159'X'#255#200#144'Q'#255

+  +#187'~G'#255#170'j<'#255'qB%'#255'`5'#30#255'Z2'#31#250'FBA'#205'CCC'#193'DD'

+  +'D'#166'CCCsCCC9CCC'#19'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#2'@@@'#12'AAA+BBBaDBB'#155'Y3!'#244'_3'#29#255'l?$'#255#167'f;'

+  +#255#186'}H'#255#200#144'R'#255#211#158'Y'#255#218#168']'#255#221#172'`'#255

+  +#223#174'a'#255#223#176'a'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255

+  +#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255

+  +#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255

+  +#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255

+  +#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255

+  +'hR.'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'qY2'#255#224#176'b'#255#224#176'b'#255

+  +#224#176'b'#255#224#176'b'#255#224#176'b'#255#224#176'b'#255#223#176'a'#255

+  +#223#174'`'#255#221#172'_'#255#217#166']'#255#208#155'W'#255#196#139'O'#255

+  +#182'wE'#255#152'\5'#255'e9!'#255'^2'#29#255'S7*'#233'DDD'#200'CCC'#183'DDD'

+  +#143'EEEUDDD"UUU'#9#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'333'#5

+  +'@@@'#24'DDDDCCC~P8-'#211']0'#29#255'c8!'#255#144'V2'#255#180'uD'#255#196#138

+  +'P'#255#207#155'X'#255#215#165']'#255#220#171'`'#255#221#173'b'#255#222#174

+  +'a'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175

+  +'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175

+  +'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175

+  +'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175

+  +'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255'VD&'#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255#166#132'J'#255#222#175'b'#255#222#175

+  +'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#175'b'#255#222#174

+  +'a'#255#221#173'a'#255#219#170'`'#255#213#163'\'#255#205#150'V'#255#192#132

+  +'M'#255#176'oA'#255'}K,'#255'a5'#31#255'\0'#28#254'I?;'#212'CCC'#194'DDD'#166

+  +'CCCrDDD8GGG'#18'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'FFF'#11'D'

+  +'DD)BBB`G@<'#164'[1'#29#252'_3'#29#255'uD)'#255#174'l?'#255#189#130'L'#255

+  +#204#150'V'#255#213#162'^'#255#217#168'`'#255#220#172'b'#255#221#173'b'#255

+  +#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255

+  +#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255

+  +#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255

+  +#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255

+  +#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255

+  +'gQ.'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#6#4#255#207#163']'#255#221

+  +#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221#173'c'#255#221

+  +#173'c'#255#221#172'b'#255#219#171'b'#255#217#167'`'#255#211#159'['#255#200

+  +#145'T'#255#185'{H'#255#164'd;'#255'h<#'#255'^1'#29#255'X3#'#244'DDD'#200'CC'

+  +'C'#183'DDD'#142'DDDSFFF!@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4'II'

+  +'I'#21'EEE?DDD|S5'''#222'\1'#28#255'c8!'#255#158'_8'#255#183'yH'#255#198#142

+  ,'S'#255#209#158'\'#255#215#166'`'#255#218#170'b'#255#219#171'c'#255#219#171

+  +'d'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172

+  +'d'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172

+  +'d'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172

+  +'d'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172

+  +'d'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172

+  +'d'#255#213#168'b'#255#3#3#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'M<#'#255

+  +#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255#219#172'd'#255

+  +#219#172'd'#255#219#171'd'#255#219#170'c'#255#217#168'b'#255#214#164'`'#255

+  +#207#153'Z'#255#194#136'P'#255#178'rD'#255#139'R1'#255'a4'#31#255'\0'#28#255

+  +'L<5'#219'CCC'#193'DDD'#164'CCCoCCC5@@@'#16'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#1'@@@'#8'BBB#CCCWHA='#158'\0'#28#253'_3'#29#255'~I+'#255#175'nB'#255#191#133

+  +'O'#255#205#151'Z'#255#213#163'a'#255#216#167'c'#255#217#169'c'#255#218#170

+  +'d'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170

+  +'d'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170

+  +'d'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170

+  +'d'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170

+  +'d'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170

+  +'d'#255#218#170'd'#255#218#170'd'#255'YF)'#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#15#12#7#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#170'd'

+  +#255#218#170'd'#255#218#170'd'#255#218#170'd'#255#218#169'c'#255#217#168'c'

+  +#255#215#166'b'#255#211#160'_'#255#201#147'W'#255#187'L'#255#169'h>'#255'l='

+  +'$'#255'^1'#29#255'W3"'#244'DDD'#199'DDD'#180'DDD'#136'DDDKBBB'#27'UUU'#6#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0'UUU'#3'DDD'#15'EEE4BBBpS6)'#215'\1'#28#255'b7!'#255#158'_9'

+  +#255#184'{J'#255#199#144'W'#255#209#158'_'#255#214#165'c'#255#216#168'd'#255

+  +#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255

+  +#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255

+  +#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255

+  +#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255

+  +#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255

+  +#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255

+  +'YD)'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#189#147'W'#255#217#168'd'

+  +#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'#255#217#168'd'

+  +#255#217#168'd'#255#216#168'd'#255#215#167'c'#255#213#164'a'#255#207#154']'

+  +#255#195#138'S'#255#179'tF'#255#139'R1'#255'`5'#30#255'\0'#28#255'K=7'#216'D'

+  +'DD'#191'DDD'#157'CCCcAAA+FFF'#11#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'+++'#6'EEE'#26'BBBIE?='

+  +#144'Z0'#28#252'^2'#29#255'zF*'#255#174'mB'#255#192#135'R'#255#205#152'\'#255

+  +#211#161'b'#255#214#165'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255

+  +#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255

+  +#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255

+  +#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255

+  +#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255

+  +#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255

+  ,#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255'jR1'#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255'fN/'#255#215#166'd'#255#215#166'd'#255#215#166'd'

+  +#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'#255#215#166'd'

+  +#255#215#167'e'#255#214#164'c'#255#210#159'a'#255#202#148'Z'#255#187#128'N'

+  +#255#168'f='#255'i;#'#255'\1'#28#255'V3#'#242'CCC'#197'DDD'#173'BBB{FFF>@@@'

+  +#20'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#1'MMM'#10'FFF(CCC_R6*'#206'\0'#28#255'`5'#31#255#154'\8'

+  +#255#182'yJ'#255#199#144'Y'#255#208#156'`'#255#212#163'd'#255#213#165'd'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255

+  +#214#165'e'#255#214#165'e'#255#214#165'e'#255#135'h@'#255#2#1#1#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'b'

+  +'L/'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#214#165

+  +'e'#255#214#165'e'#255#214#165'e'#255#214#165'e'#255#213#165'e'#255#213#164

+  +'d'#255#211#161'c'#255#206#154'^'#255#194#139'U'#255#177'sF'#255#135'P/'#255

+  +'^3'#29#255'[/'#27#255'J>9'#213'DDD'#185'CCC'#144'DDDSHHH III'#7#0#0#0#1#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3

+  +'<<<'#17'DDD8DBAyZ0'#29#248'\1'#28#255'uB'''#255#172'lA'#255#190#132'Q'#255

+  +#203#151'^'#255#209#160'c'#255#211#162'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255

+  +#212#163'e'#255#212#163'e'#255#212#163'e'#255#156'xK'#255#1#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'jQ2'#255#212

+  +#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212

+  +#163'e'#255#212#163'e'#255#212#163'e'#255#212#163'e'#255#212#162'e'#255#211

+  +#162'd'#255#208#158'b'#255#200#147'['#255#186'~M'#255#165'd<'#255'd8!'#255'\'

+  +'0'#28#255'T5'''#237'CCC'#193'DDD'#162'CCCjCCC.@@@'#12#0#0#0#2#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'333'#5'GGG'#25'BB'

+  +'BIN:1'#174'[/'#27#255'^2'#29#255#145'T3'#255#180'vI'#255#196#142'Y'#255#206

+  +#155'a'#255#209#161'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255'O=&'#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  ,#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'sX7'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211

+  +#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#210

+  +#161'f'#255#209#159'd'#255#204#153'`'#255#192#135'U'#255#175'pE'#255'~H+'#255

+  +']0'#29#255'Z0'#28#253'FBA'#201'DDD'#176'CCC~FFF>CCC'#19'@@@'#4#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'999'#9'EEE%CCC[V3'

+  +'$'#222'\0'#27#255'f7!'#255#167'd>'#255#187#128'Q'#255#200#148'^'#255#207#156

+  +'d'#255#209#159'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160

+  +'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160

+  +'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160

+  +'e'#255#209#160'e'#255#209#160'e'#255#151'tI'#255'2&'#25#255#27#21#13#255#15

+  +#12#7#255#7#5#3#255#7#5#3#255' '#25#16#255'P='''#255#151'tI'#255#209#160'e'

+  +#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'

+  +#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'

+  +#255#209#160'e'#255#209#160'e'#255#6#5#3#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#146'pF'#255#209#160'e'#255#209#160'e'#255

+  +#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255

+  +#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#160'e'#255#209#159'e'#255

+  +#206#155'c'#255#198#143'['#255#182'zM'#255#151'Y6'#255'^3'#29#255'[/'#27#255

+  +'N:1'#222'DDD'#185'DDD'#142'DDDOIII'#28'+++'#6#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2';;;'#13'DDD1F@=x[/'#28#253'\1'#28

+  +#255'~G+'#255#174'oE'#255#193#137'X'#255#203#151'b'#255#207#156'e'#255#207

+  +#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208

+  +#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208

+  +#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255'x[;'

+  +#255#15#12#8#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#4#3#2#255'bJ0'#255#208#158'f'#255#208#158'f'

+  +#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'

+  +#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255'3'''#25#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#2#1#255#208#158'f'

+  +#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'

+  +#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'#255#208#158'f'

+  +#255#208#158'f'#255#207#158'e'#255#206#156'd'#255#201#149'_'#255#189#131'T'

+  +#255#169'h@'#255'j:#'#255'\0'#28#255'V3#'#242'DDD'#191'CCC'#156'BBB`AAA''333'

+  +#10#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4'C'

+  +'CC'#19'EEE?Q7+'#179'[/'#27#255'^1'#29#255#152'X6'#255#181'yM'#255#197#144']'

+  +#255#204#153'c'#255#206#155'f'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#202#154'c'#255'6)'#27#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#14#10#7#255#178#135'W'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#206#156'e'#255'WB+'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#29#22#14#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'

+  +#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#206#156'e'#255#205#156'e'

+  ,#255#203#151'c'#255#194#139'Z'#255#176'qH'#255#131'K-'#255'\1'#28#255'[/'#27

+  +#255'HA='#204'DDD'#169'DDDqEEE4III'#14#128#128#128#2#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'+++'#6'BBB'#27'EEENW2!'#228'[/'#27#255'i9!'

+  +#255#168'e?'#255#187#130'T'#255#200#147'`'#255#203#153'e'#255#205#154'e'#255

+  +#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255

+  +#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255

+  +#205#154'e'#255#205#154'e'#255#199#150'a'#255#19#14#9#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#7#6#4#255#178#133'W'

+  +#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'

+  +#255#205#154'e'#255#205#154'e'#255#205#154'e'#255'S>)'#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#128'a?'#255#205#154'e'#255#205#154'e'

+  +#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'

+  +#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'#255#205#154'e'

+  +#255#205#154'e'#255#204#154'e'#255#203#152'd'#255#197#145'^'#255#182'zO'#255

+  +#157'Z8'#255']1'#29#255'[/'#27#255'P9.'#226'CCC'#179'CCC'#129'CCCA@@@'#20'@@'

+  +'@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'999'#9'EEE%EA?'

+  +'b[/'#27#253'\0'#27#255'F*'#255#173'nG'#255#191#136'Z'#255#200#149'c'#255

+  +#202#152'e'#255#202#152'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255

+  +#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255

+  +#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255#31#24#16#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#11#8#6#255#200#151'e'#255#202#153'e'#255#202#153'e'#255#202

+  +#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255'O;'''

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255''''#29#19#255#202#153'e'#255

+  +#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255

+  +#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#153'e'#255

+  +#202#153'e'#255#202#153'e'#255#202#153'e'#255#202#152'e'#255#202#151'd'#255

+  +#199#147'b'#255#188#130'U'#255#168'e@'#255'k:"'#255'[/'#27#255'V3$'#241'CCC'

+  +#186'BBB'#142'EEENBBB'#27'+++'#6#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#2'@@@'#12'DDD-O:0'#146'[/'#27#255'\0'#28#255#145'R2'#255#179'wM'

+  +#255#194#141'^'#255#200#148'c'#255#201#150'e'#255#201#150'e'#255#201#150'e'

+  +#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'

+  +#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'

+  +#255';,'#30#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'S>*'#255#201#150'e'

+  +#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'

+  +#255#201#150'e'#255'K8&'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#29#22#14#255

+  +#184#138']'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255

+  +#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255

+  +#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255#201#150'e'#255

+  +#201#150'e'#255#200#149'd'#255#199#148'c'#255#191#136'['#255#173'mG'#255'}D('

+  +#255'\0'#27#255'Z0'#28#253'DBB'#192'CCC'#152'DDDZBBB#@@@'#8#0#0#0#1#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#128#128#128#2'III'#14'CCC5T5'''#190'[/'#27#255

+  +'_2'#29#255#162'^:'#255#184'}S'#255#195#142'`'#255#198#147'd'#255#199#148'd'

+  +#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'

+  +#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'

+  ,#255#199#148'd'#255#147'mJ'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#3#2#1#255#195#144'b'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255

+  +#199#148'd'#255#199#148'd'#255#199#148'd'#255'H6$'#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#3#2#1#255#23#17#12

+  +#255'qT8'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199

+  +#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199

+  +#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#199

+  +#148'd'#255#199#148'd'#255#199#148'd'#255#199#148'd'#255#198#146'c'#255#193

+  +#140'^'#255#178'uN'#255#143'O1'#255'\0'#28#255'[/'#27#255'J=7'#208'CCC'#161

+  +'DDDfAAA+FFF'#11#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'<<<'

+  +#17'CCC=X1 '#227'[/'#27#255'm:"'#255#167'eA'#255#187#130'X'#255#195#143'a'

+  +#255#196#144'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'

+  +#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'

+  +#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#19#14#10#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#135'cD'#255#197#145'c'#255#197

+  +#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255'I5$'

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#19#14#10#255'4&'#26#255'cI2'#255

+  +#161'vP'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197

+  +#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197

+  +#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197

+  +#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197#145'c'#255#197

+  +#145'c'#255#197#145'b'#255#196#144'c'#255#194#140'`'#255#182'|S'#255#159'\:'

+  +#255']2'#28#255'[/'#27#255'Q8-'#226'DDD'#168'DDDqAAA3NNN'#13#128#128#128#2#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4':::'#22'G@<N[/'#27#253'[/'#27

+  +#255'~D('#255#172'lF'#255#189#133'['#255#194#141'a'#255#194#142'b'#255#195

+  +#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195

+  +#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195

+  +#142'b'#255'oQ8'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255'N9'''#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142

+  +'b'#255#195#142'b'#255#195#142'b'#255#145'jI'#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255'7('#28

+  +#255#166'yS'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255

+  +#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255

+  +#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255

+  +#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255

+  +#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255#195#142'b'#255

+  +#195#142'b'#255#194#142'a'#255#193#140'`'#255#185#128'X'#255#166'c?'#255'k8!'

+  +#255'[/'#27#255'V3#'#241'DDD'#175'DDD{BBB:@@@'#16#128#128#128#2#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#1'333'#5'EEE'#26'Q:/z[/'#27#255'\0'#27#255#142'M/'

+  +#255#176'rM'#255#189#135']'#255#192#139'a'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#26#19#13#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255'D1"'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192

+  +#139'`'#255#192#139'`'#255#192#139'`'#255#11#8#6#255#0#0#0#255#0#0#0#255#0#0

+  ,#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#6#4#255#143'hH'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255#192#139'`'#255

+  +#192#139'`'#255#192#139'`'#255#192#138'a'#255#187#131'Z'#255#170'iE'#255'{B'

+  +''''#255'[/'#27#255'Z0'#28#253'DDD'#182'DDD'#132'CCCACCC'#19'UUU'#3#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'III'#7'BBB'#31'S5('#154'[/'#27#255'\0'#28#255

+  +#153'W5'#255#179'wQ'#255#189#133'^'#255#190#136'_'#255#190#136'_'#255#190#136

+  +'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136

+  +'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#184#132

+  +']'#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255'dH2'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255

+  +#190#136'_'#255#190#136'_'#255#190#136'_'#255'G3#'#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#2#1#1#255#165'wS'#255#190#136'_'#255#190

+  +#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190

+  +#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190

+  +#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190

+  +#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190

+  +#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#190

+  +#136'_'#255#190#136'_'#255#190#136'_'#255#190#136'_'#255#187#131'\'#255#173

+  +'nJ'#255#134'H,'#255'[/'#27#255'[/'#27#255'HA='#194'DDD'#139'CCCHCCC'#23'@@@'

+  +#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'@@@'#8'DDD"V4$'#182'[/'#27#255'`2'

+  +#29#255#160'\9'#255#181'zT'#255#187#132']'#255#188#133'^'#255#188#134'^'#255

+  +#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255

+  +#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255

+  +'hK4'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#2#1#1#255#163'uR'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#180#128'Z'#255#13#9

+  +#6#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'cF1'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188

+  +#134'^'#255#188#134'^'#255#188#134'^'#255#188#134'^'#255#188#133'^'#255#186

+  +#131'\'#255#176'sO'#255#144'O/'#255'[/'#27#255'[/'#27#255'L=6'#206'DDD'#143

+  +'BBBMEEE'#26'333'#5#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'999'#9'EEE%X2 '

+  +#209'[/'#27#255'j8 '#255#163'_='#255#181'{V'#255#186#130'\'#255#186#130'\'

+  +#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'

+  +#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'

+  +#255#186#130'\'#255'#'#25#17#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255'_B/'#255#186#130'\'#255#186#130'\'#255#186#130'\'

+  +#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'

+  +#255#186#130'\'#255#163'rQ'#255#5#3#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'$'#26#18#255

+  ,#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255

+  +#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255

+  +#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255

+  +#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255

+  +#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255

+  +#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255#186#130'\'#255

+  +#186#130'\'#255#186#130'\'#255#185#129'\'#255#177'vR'#255#155'V5'#255'\0'#28

+  +#255'[/'#27#255'P9/'#217'DDD'#146'BBBQ@@@'#28'UUU'#6#0#0#0#1#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#1'MMM'#10'@@@(Z0'#29#234'[/'#27#255't<$'#255#165'b@'#255#181

+  +'{V'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'

+  +#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255

+  +#184'Z'#255#4#3#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1

+  +#255'Q8('#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184

+  +'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#142'bE'

+  +#255#3#2#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#6#4#3#255#174'yV'#255#184'Z'#255#184'Z'#255#184'Z'#255

+  +#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184

+  +'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'

+  +#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255

+  +#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#184

+  +'Z'#255#184'Z'#255#184'Z'#255#184'Z'#255#183'~Z'#255#178'wT'#255#159'Y8'

+  +#255'b3'#30#255'[/'#27#255'S6)'#228'CCC'#149'CCCTBBB'#31'III'#7#0#0#0#1#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#1'FFF'#11'F@>/[/'#27#254'[/'#27#255'}A&'#255#167'gD'

+  +#255#180'zW'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255

+  +#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181

+  +'|Y'#255#136']C'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#19#13#9

+  +#255#151'gJ'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255

+  +#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181

+  +'|Y'#255#181'|Y'#255#171'vU'#255'1"'#24#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#1#0#0#255'}V>'#255#181'|Y'#255#181'|Y'#255#181'|Y'

+  +#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255

+  +#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181

+  +'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'

+  +#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255

+  +#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#181'|Y'#255#178

+  +'wT'#255#161'];'#255'k8 '#255'[/'#27#255'V3#'#238'DDD'#151'CCCWFFF!@@@'#8#0#0

+  +#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'FFF'#11'K:3?[/'#27#255'[/'#27#255#131'F'

+  +'*'#255#169'iH'#255#179'xV'#255#180'zW'#255#180'{W'#255#180'{W'#255#180'{W'

+  +#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255

+  +#180'{W'#255#180'{W'#255'<)'#29#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255'O'

+  +'6&'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'

+  +#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255

+  +#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#142'aE'#255#27

+  +#19#13#255#2#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#5#4#255#135']A'#255#180'{W'#255#180

+  +'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'

+  +#255#180'{W'#255'pL6'#255'+'#29#20#255'('#28#19#255'*'#28#20#255'+'#29#21#255

+  +'-'#30#21#255'fF2'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{'

+  +'W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'

+  +#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255#180'{W'#255

+  +#180'{W'#255#180'zX'#255#178'vU'#255#163'_>'#255'r<"'#255'[/'#27#255'X2!'#243

+  +'CCC'#152'BBBYDDD"@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'FFF'#11'N8.'

+  +'J[/'#27#255'[/'#27#255#135'H,'#255#170'kI'#255#178'wV'#255#179'yX'#255#179

+  ,'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'

+  +#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#16#11#8#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#19#13#10#255#150'fJ'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'

+  +#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255

+  +#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179

+  +'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255'~V>'#255'=)'#30#255

+  +#19#13#9#255#1#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'$'#24#17

+  +#255#172'uT'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255

+  +#179'yX'#255#179'yX'#255#158'kN'#255'=)'#30#255#6#4#3#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#6#4#3#255'?+'#31#255#164

+  +'oP'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'

+  +#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255

+  +#179'yX'#255#179'yX'#255#179'yX'#255#179'yX'#255#177'uU'#255#164'b@'#255'v?%'

+  +#255'[/'#27#255'Y1'#31#246'CCC'#152'BBBYDDD"@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#1'FFF'#11'Q7+U[/'#27#255'\0'#28#255#139'J-'#255#171'lL'#255#177

+  +'wW'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'

+  +#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#172'sT'#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#1#1#1#255'O5&'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255

+  +#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178

+  +'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'

+  +#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255

+  +#178'wV'#255#178'wV'#255#178'wV'#255#176'wV'#255'vO9'#255'7%'#27#255#16#10#8

+  +#255#1#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#11#8#6#255

+  +'9&'#28#255#137'\C'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178

+  +'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255'M3%'#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#1#0#0#255'4"'#25#255#178'wV'#255#178'wV'#255#178'wV'#255

+  +#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178

+  +'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#178'wV'#255#176'tT'

+  +#255#165'cC'#255'yA'''#255'[/'#27#255'Z0'#29#250'DDD'#150'CCCWFFF!III'#7#0#0

+  +#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'MMM'#10'R4''^[/'#27#255'\0'#28#255#142

+  +'M.'#255#171'nN'#255#177'uV'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'

+  +#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255

+  +#177'wX'#255'gF3'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#23#16#12#255#152'fK'#255#177'wX'#255#177'wX'#255#177'wX'

+  +#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255

+  +#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177

+  +'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'

+  +#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255

+  +#177'wX'#255#177'wX'#255#177'wX'#255#173'uV'#255#136'\D'#255#133'YB'#255#131

+  +'XA'#255#128'V@'#255#153'gL'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'

+  +#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255

+  +'S8)'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255'"'#23#17#255#175'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'

+  +#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255#177'wX'#255

+  +#177'wX'#255#177'wX'#255#177'wX'#255#175'tU'#255#166'eE'#255'}B)'#255'\0'#28

+  +#255'[/'#28#253'CCC'#148'CCCTBBB'#31'III'#7#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#1'999'#9'V4%h[/'#27#255'\0'#28#255#145'O0'#255#171'mN'#255#175'sU'#255

+  +#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175

+  +'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255'*'#29#21#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#1#1#255'X;,'#255#175'uW'

+  +#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255

+  +#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175

+  +'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'

+  +#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255

+  +#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175

+  ,'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'

+  +#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255

+  +#175'uW'#255#175'uW'#255#175'uW'#255'^?/'#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'$'#24#18#255

+  +#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175

+  +'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'#255#175'uW'

+  +#255#175'sT'#255#166'eE'#255#128'D*'#255'\0'#28#255'[/'#27#255'ECB'#149'CCCP'

+  +'@@@'#28'UUU'#6#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'@@@'#8'W3#q[/'#27#255

+  +'\1'#29#255#150'Q1'#255#171'mN'#255#174'sU'#255#175'uV'#255#175'uV'#255#175

+  +'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'

+  +#255#175'uV'#255#175'uV'#255#15#10#8#255#0#0#0#255#0#0#0#255#0#0#0#255#4#3#2

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#29#19#14#255#156'iM'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'

+  +#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255

+  +#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175

+  +'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'

+  +#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255

+  +#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175

+  +'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'

+  +#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255

+  +#175'uV'#255#11#7#6#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'sM9'#255#175'uV'#255#175

+  +'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'#255#175'uV'

+  +#255#175'uV'#255#175'uV'#255#175'uV'#255#175'tV'#255#174'rS'#255#167'fG'#255

+  +#131'G,'#255'\0'#28#255'[/'#27#255'GA?'#150'CCCLGGG'#25'333'#5#0#0#0#1#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#1'III'#7'W3#k[/'#27#255'\1'#29#255#149'P2'#255#169

+  +'lM'#255#174'qT'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'

+  +#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255

+  +#9#6#4#255#0#0#0#255#0#0#0#255#0#0#0#255#136'ZC'#255'T8*'#255#1#1#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#7#5#3#255'bA0'#255#175'tV'#255#175'tV'#255

+  +#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175

+  +'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'

+  +#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255

+  +#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175

+  +'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'

+  +#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255

+  +#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175

+  +'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#165'nR'#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#10#7#5#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255

+  +#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175'tV'#255#175

+  +'tV'#255#174'sU'#255#173'qR'#255#166'eG'#255#131'F,'#255'\0'#28#255'[/'#27

+  +#255'EA?'#145'DDDGFFF'#22'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'333'

+  +#5'W3#\[/'#27#255'\1'#29#255#146'P3'#255#168'jM'#255#173'pT'#255#173'rU'#255

+  +#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173

+  +'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#4#3#2#255#0#0#0#255#0#0#0#255#21

+  +#14#10#255#173'rU'#255#173'rU'#255#152'dK'#255'dB1'#255'A+ '#255'D-!'#255#141

+  +']E'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'

+  +#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255

+  +#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173

+  +'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'

+  +#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255

+  +#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173

+  +'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'

+  +#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255

+  +#173'rU'#255#173'rU'#255#169'pS'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#139'\D'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'

+  +#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'rU'#255#173'qT'#255

+  +#172'oR'#255#165'cF'#255#128'E+'#255'\0'#28#255'[/'#27#255'CBA'#132'DDD@CCC'

+  ,#19'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4'U2"L[/'#27#255'\1'

+  +#29#255#143'N3'#255#168'hK'#255#172'oT'#255#173'qU'#255#173'rV'#255#173'rV'

+  +#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255

+  +#173'rV'#255#173'rV'#255#1#1#1#255#0#0#0#255#0#0#0#255'nI7'#255#173'rV'#255

+  +#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173

+  +'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'

+  +#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255

+  +#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173

+  +'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'

+  +#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255

+  +#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173

+  +'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'

+  +#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255

+  +#173'rV'#255#173'rV'#255#2#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'H'

+  +'0$'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'

+  +#255#173'rV'#255#173'rV'#255#173'rV'#255#173'rV'#255#173'qU'#255#171'nQ'#255

+  +#165'dF'#255'~D+'#255'\1'#29#255'Z0'#28#252'CCCzCCC9@@@'#16#128#128#128#2#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'T2#=[/'#27#255'\1'#29#255#140'N1'

+  +#255#166'gI'#255#171'oR'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255

+  +#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173

+  +'qU'#255#1#1#1#255#27#18#13#255'a@0'#255#173'qU'#255#173'qU'#255#173'qU'#255

+  +#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173

+  +'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'

+  +#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255

+  +#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173

+  +'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'

+  +#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255

+  +#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173

+  +'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'

+  +#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255

+  +#173'qU'#255'$'#24#18#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#31#20#15#255

+  +#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#173

+  +'qU'#255#173'qU'#255#173'qU'#255#173'qU'#255#172'pT'#255#169'lP'#255#164'aD'

+  +#255'{C*'#255'\1'#29#255'Y0'#30#247'CCCoBBB2;;;'#13#0#0#0#2#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#128#128#128#2'V6''-[/'#27#255'\1'#29#255#137'L0'#255

+  +#165'fH'#255#170'mQ'#255#172'pT'#255#172'pU'#255#172'pU'#255#172'pU'#255#172

+  +'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'

+  +#255#166'lS'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255

+  +#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172

+  +'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'

+  +#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255

+  +#168'nS'#255#134'WB'#255'b@0'#255'tK9'#255#166'lS'#255#172'pU'#255#172'pU'

+  +#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255

+  +#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172

+  +'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'

+  +#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255

+  +#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172

+  +'pU'#255#129'T@'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#22#14#11#255#172

+  +'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'#255#172'pU'

+  +#255#172'pU'#255#172'pU'#255#172'pU'#255#172'oT'#255#170'mP'#255#163'`C'#255

+  +'xB*'#255'\1'#29#255'Y1'#31#241'BBBdCCC*MMM'#10#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#2'T7*'#29'[/'#27#255'\1'#29#255#134'J0'#255#165'dG'

+  +#255#169'lQ'#255#171'pU'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255

+  +#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172

+  +'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'

+  +#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255

+  +#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172

+  +'qW'#255#172'qW'#255#172'qW'#255#135'YD'#255'$'#24#18#255#3#2#2#255#0#0#0#255

+  ,#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#5#4#255#30#20#16#255'xO='#255#172

+  +'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'

+  +#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255

+  +#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172

+  +'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'

+  +#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255

+  +#14#9#7#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#20#13#10#255#172'qW'#255#172'qW'#255

+  +#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172'qW'#255#172

+  +'qW'#255#172'qW'#255#171'oT'#255#169'jM'#255#162'_A'#255's>'''#255'\1'#29#255

+  +'X2 '#234'CCCXDDD"@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#1'C><'#9'[/'#27#247'\1'#29#255'}F-'#255#164'bE'#255#169'lO'#255#171'pT'

+  +#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255

+  +#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172

+  +'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'

+  +#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255

+  +#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#154'eM'#255#22

+  +#15#11#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#25#17#13#255#136'ZE'#255#172'qV'

+  +#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255

+  +#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172

+  +'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'

+  +#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255

+  +#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255'U7*'#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#17#11#9#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'

+  +#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#172'qV'#255#171'oT'#255

+  +#168'jM'#255#161'^@'#255'k;%'#255'\0'#28#255'V3#'#220'CCCLEEE'#26'333'#5#0#0

+  +#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'+++'#6'[/'#28#214'\1'#29

+  +#255't@)'#255#162'`B'#255#168'jO'#255#172'pV'#255#173'rX'#255#173'rX'#255#173

+  +'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'

+  +#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255

+  +#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173

+  +'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'

+  +#255#173'rX'#255#144'_I'#255#6#4#3#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255'Z;-'#255#173'rX'#255#173'rX'#255#173'rX'#255#173

+  +'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'

+  +#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255

+  +#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173

+  +'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'

+  +#255#171'pV'#255#3#2#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'!'#22#17#255#173'rX'#255#173'rX'

+  +#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255#173'rX'#255

+  +#173'rX'#255#172'qX'#255#171'oU'#255#167'hM'#255#160'[>'#255'b5!'#255'\0'#28

+  +#255'S5'''#196'EEE?CCC'#19'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0'UUU'#3'Z0'#29#176'\1'#29#255'k:%'#255#162'^A'#255#169'jN'#255

+  +#173'qV'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174

+  +'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'

+  +#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255

+  +#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174

+  +'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#151'dM'#255#4#2#2#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255

+  +#136'YF'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174

+  +'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'

+  +#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255

+  +#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174

+  +'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255'5#'#27#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  ,#0#0#255'G.$'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255

+  +#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#172'pV'#255#167

+  +'gK'#255#153'X:'#255'^3'#31#255'\0'#28#255'Q7+'#166'BBB2777'#14#0#0#0#2#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'Z0'#29#137'\0'#28

+  +#255'a5!'#255#160']>'#255#168'jN'#255#173'sY'#255#175'v\'#255#175'v\'#255#175

+  +'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'

+  +#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255

+  +#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175

+  +'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'

+  +#255#29#20#15#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#8#5#4#255#169'rX'#255#175'v\'#255#175'v\'

+  +#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255

+  +#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175

+  +'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'

+  +#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255

+  +#175'v\'#255#156'jR'#255#1#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'yQ?'#255#175'v\'#255#175'v\'#255

+  +#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175'v\'#255#175

+  +'v\'#255#174'u['#255#172'qV'#255#166'gJ'#255#143'S6'#255'^2'#31#255'[/'#27

+  +#255'O;2'#130'CCC&999'#9#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#1'Z0'#29'a\0'#28#255'^3'#31#255#153'W;'#255#168'jN'#255

+  +#174'tZ'#255#176'x_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176

+  +'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'

+  +#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255

+  +#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176

+  +'y_'#255#176'y_'#255#176'y_'#255'oL='#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255']@2'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176

+  +'y_'#255'Z=1'#255')'#28#22#255#26#18#14#255#14#10#8#255#10#7#5#255#23#16#12

+  +#255'+'#30#23#255'E0&'#255#138'_J'#255#176'y_'#255#176'y_'#255#176'y_'#255

+  +#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176

+  +'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255'#'#24#19#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#172'w]'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255

+  +#176'y_'#255#176'y_'#255#176'y_'#255#176'y_'#255#175'w^'#255#172'rW'#255#165

+  +'fI'#255#134'K2'#255']1'#30#255'[/'#27#255'H?:ZBBB'#27'+++'#6#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'X/'#29'7[/'#27#255

+  +'^2'#31#255#141'P5'#255#167'hK'#255#174'sY'#255#177'x_'#255#177'za'#255#177

+  +'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'

+  +#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255

+  +#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177

+  +'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#9#6#5

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'%'#25#20#255#177'za'#255#177'za'

+  +#255#177'za'#255#177'za'#255'bD6'#255#8#6#4#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'>+"'#255#175'za'

+  +#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255

+  +#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#136

+  +'^K'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#16#11#9#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'

+  +#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#177'za'#255#176'x^'#255

+  +#172'qV'#255#164'cF'#255'{E,'#255']1'#30#255'Z0'#29#245'DDD<GGG'#18'UUU'#3#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'X?4'#7

+  +'[/'#27#243']1'#30#255'}G/'#255#165'eH'#255#174'sY'#255#178'zb'#255#179'}d'

+  +#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255

+  +#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179

+  +'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'

+  +#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#158'oX'#255

+  ,#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'&'#26#21#255#179'}d'#255#179

+  +'}d'#255#179'}d'#255'kK;'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#12

+  +#8#6#255#137'_L'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'

+  +#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255

+  +#179'}d'#255#20#14#11#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255'vRB'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179

+  +'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#179'}d'#255#177'y`'

+  +#255#172'pU'#255#163'aC'#255'i;&'#255'\1'#29#255'W2!'#206'FFF,@@@'#12#0#0#0#2

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#1'[/'#27#184'\1'#29#255'l<'''#255#164'bE'#255#173'rX'#255#179'|c'#255#180

+  +'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'

+  +#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255

+  +#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181

+  +'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255'_C6'#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'Q9.'#255#181'g'#255#181'g'

+  +#255#152'kW'#255#2#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#3#2#2#255#151'jV'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255

+  +#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181

+  +'g'#255'sPA'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#23#16

+  +#13#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#181'g'

+  +#255#181'g'#255#181'g'#255#181'g'#255#181'g'#255#180'g'#255#177'za'#255

+  +#171'nS'#255#156'[>'#255'`5!'#255'\0'#28#255'T5'''#155'DDD'#30'III'#7#0#0#0#1

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0'Z/'#28'w\0'#28#255'`5!'#255#157'\?'#255#172'pU'#255#179'}d'#255#181#129

+  +'i'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129

+  +'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129

+  +'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129

+  +'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129

+  +'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255'.!'#27

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#1#1#255#166'va'#255#182#129'j'

+  +#255#182#129'j'#255'A.&'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#9#6#5#255#170'yd'#255#182#129'j'#255#182#129'j'

+  +#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'

+  +#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#8#6#5#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#135'`O'#255#182#129'j'#255#182

+  +#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#182

+  +#129'j'#255#182#129'j'#255#182#129'j'#255#182#129'j'#255#181#128'h'#255#177

+  +'za'#255#169'kP'#255#139'Q7'#255'^3'#31#255'\0'#28#255'N9/\GGG'#18'UUU'#3#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0'X.'#26'4\0'#28#255'^3'#31#255#141'S8'#255#170'mQ'#255#179'|c'#255

+  +#182#130'k'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255

+  +#20#15#12#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'N8.'#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#22#16#13#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#21#15#13#255#182#130'm'

+  +#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'

+  ,#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'

+  +#255'N8.'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#23#17#13#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255

+  +#184#132'm'#255#184#132'm'#255#184#132'm'#255#184#132'm'#255#183#131'l'#255

+  +#182#129'j'#255#177'x_'#255#167'hK'#255'zG/'#255']1'#30#255'Z0'#28#241'@@@(M'

+  +'MM'#10#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0'='#31#18#3'[/'#27#238']1'#30#255'{G/'#255#167'hL'

+  +#255#177'za'#255#183#131'l'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255

+  +#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255

+  +#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255

+  +#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255

+  +#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255

+  +#185#134'p'#255#26#19#16#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#12#9#7#255#185#134

+  +'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#3#2#2#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255'U>4'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185

+  +#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185

+  +#134'p'#255#185#134'p'#255#25#18#15#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'xWI'#255#185

+  +#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185

+  +#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#185#134'p'#255#184

+  +#134'o'#255#182#129'j'#255#175'v\'#255#165'dG'#255'h;&'#255'\1'#29#255'X2 '

+  +#193'==='#25'+++'#6#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#170'\1'#29#255'f9%'#255

+  +#164'bG'#255#175'v]'#255#183#131'l'#255#186#135'r'#255#186#137's'#255#186#137

+  +'s'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137

+  +'s'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137

+  +'s'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137

+  +'s'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137

+  +'s'#255#186#137's'#255'$'#27#23#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#129'_P'#255

+  +#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#1#1#1#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255' '#23#19#255#186#137's'#255#186#137's'#255#186#137's'#255#186

+  +#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186

+  +#137's'#255#186#137's'#255#186#137's'#255#172'j'#255#7#5#4#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#12#9#7#255

+  +#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255

+  +#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255#186#137's'#255

+  +#186#137's'#255#185#135'q'#255#181#129'i'#255#173'qW'#255#149'X='#255'`5!'

+  +#255'\0'#28#255'V4%333'#15#0#0#0#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'Z/'#27'O\0'#28

+  +#255'_4 '#255#144'U:'#255#172'qV'#255#182#130'k'#255#187#137't'#255#188#139

+  +'u'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255#188#140'v'#255#188#140'v'#255'1$'#31#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255':+$'#255

+  +#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#1

+  +#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#4#3#3#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140

+  +'v'#255'}]N'#255'6("'#255#14#11#9#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255'S>5'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'

+  ,#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'#255#188#140'v'

+  +#255#188#140'v'#255#188#139'u'#255#186#136'r'#255#180'~f'#255#169'kP'#255'|H'

+  +'1'#255'^2'#31#255'[/'#27#249'L=6+III'#7#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +'[/'#27#5'[/'#27#235']1'#30#255'wD/'#255#169'jO'#255#180'g'#255#187#137'u'

+  +#255#189#141'x'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'

+  +#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'

+  +#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'

+  +#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'

+  +#255#189#142'y'#255#189#142'y'#255#189#142'y'#255'J7/'#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#16#12#11

+  +#255#187#140'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'

+  +#255#189#142'y'#255#1#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#181#136'u'#255#189

+  +#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189

+  +#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189

+  +#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#11#8

+  +#7#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#181#136's'#255#189#142'y'#255

+  +#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255

+  +#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#142'y'#255#189#141'x'#255

+  +#186#136'q'#255#177'za'#255#164'dG'#255'f:&'#255'\1'#29#255'Y1'#31#186'@@@'

+  +#16'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'Z/'#27#147'\1'#29#255

+  +'b8$'#255#160'bF'#255#177'y`'#255#186#137's'#255#190#143'z'#255#191#145'|'

+  +#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'

+  +#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'

+  +#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'

+  +#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'

+  +#255#191#145'|'#255#162'{i'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#162'{i'#255#191#145'|'#255#191#145'|'

+  +#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#2#1#1#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#1#1#1#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191

+  +#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191

+  +#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191

+  +#145'|'#255#191#145'|'#255#191#145'|'#255#5#4#3#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255'&'#29#25#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255

+  +#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255#191#145'|'#255

+  +#191#145'|'#255#191#145'|'#255#189#142'y'#255#184#134'o'#255#174'sY'#255#143

+  +'U;'#255'`5!'#255'\0'#28#255'U3$`@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0'Z.'#27'5\0'#28#255'_4 '#255#137'Q8'#255#173'rX'#255#184#134'o'

+  +#255#190#144'{'#255#192#147''#255#192#147''#255#192#147''#255#192#147''

+  +#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147''

+  +#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147''

+  +#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147''

+  +#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#14#11#9#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255' '#24#21#255

+  +#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255

+  +#192#147''#255#192#147''#255#4#3#3#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#6#5#255#192#147

+  +''#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147

+  +''#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147

+  +''#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147

+  +''#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#137'iZ'#255#192#147''#255

+  +#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#147''#255

+  +#192#147''#255#192#147''#255#192#147''#255#192#147''#255#192#146'~'#255

+  +#189#142'y'#255#182#129'j'#255#169'lP'#255'uD.'#255'^2'#31#255'[/'#28#237'NF'

+  ,'B'#21'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'

+  +#27#211']1'#30#255'l>)'#255#167'iM'#255#181'g'#255#190#143'z'#255#193#148

+  +#128#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194

+  +#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255

+  +#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130

+  +#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149

+  +#130#255#194#149#130#255#194#149#130#255#194#149#130#255'G60'#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'ZE<'#255#194#149#130

+  +#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149

+  +#130#255#194#149#130#255#7#6#5#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#23#17#15#255#194#149

+  +#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194

+  +#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255

+  +#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130

+  +#255#179#137'x'#255#0#0#0#255#0#0#0#255#0#0#0#255'-#'#30#255#194#149#130#255

+  +#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130

+  +#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149#130#255#194#149

+  +#130#255#192#147''#255#188#140'v'#255#177'za'#255#156'_D'#255'a6#'#255'\1'

+  +#29#255'Y1'#31#153'@@@'#8#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0'Z/'#27']\0'#28#255'`5!'#255#143'V='#255#175'v]'#255#187#138

+  +'u'#255#193#149#129#255#195#152#132#255#195#152#133#255#195#152#133#255#195

+  +#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255

+  +#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133

+  +#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152

+  +#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#170

+  +#133't'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#172#133'u'#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133

+  +#255#195#152#133#255#195#152#133#255#146'rd'#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255'_JA'#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255

+  +#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133

+  +#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152

+  +#133#255#195#152#133#255#140'm`'#255#0#0#0#255#0#0#0#255#6#5#4#255#186#145''

+  +#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152

+  +#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195#152#133#255#195

+  +#152#133#255#195#152#132#255#192#147''#255#185#134'p'#255#172'pU'#255'|I2'

+  +#255'^3'#31#255'\0'#28#250'R5()UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#3'[/'#27#221']1'#30#255'oA,'#255#169'lP'

+  +#255#183#131'l'#255#192#147''#255#196#154#135#255#197#155#136#255#197#155

+  +#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197

+  +#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255

+  +#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136

+  +#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155

+  +#136#255#197#155#136#255#26#20#18#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#8#6#5#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136

+  +#255#197#155#136#255#197#155#136#255#197#155#136#255#28#22#19#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#4#3#3#255#193#153#134#255#197#155#136#255#197#155#136#255#197#155

+  +#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197

+  +#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255

+  +#197#155#136#255#197#155#136#255#197#155#136#255#182#143'~'#255'=0*'#255#7#5

+  +#5#255#130'fY'#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155

+  +#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197#155#136#255#197

+  +#155#136#255#197#155#136#255#196#154#136#255#195#152#133#255#190#144'{'#255

+  +#180'~f'#255#159'bG'#255'c8%'#255'\1'#29#255'Z0'#30#163'III'#7#0#0#0#1#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +'g\0'#28#255'a6#'#255#147'Y@'#255#177'za'#255#190#143'z'#255#196#154#135#255

+  +#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139

+  +#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157

+  +#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198

+  +#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255

+  +#198#157#139#255#198#157#139#255#198#157#139#255'<0+'#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255'*!'#29#255#198#157#139#255#198#157#139#255#198#157

+  +#139#255#198#157#139#255#198#157#139#255#198#157#139#255#164#130's'#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255'?2,'#255#198#157#139#255#198#157#139#255#198#157#139

+  +#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157

+  +#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198

+  +#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255

+  +#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139

+  +#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#157

+  +#139#255#198#157#139#255#198#157#139#255#198#157#139#255#198#156#138#255#195

+  +#152#132#255#187#138't'#255#173'sY'#255'L5'#255'^3'#31#255'\0'#28#252'U3$,'

+  +#128#128#128#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0'[/'#27#7'[/'#27#229'^2'#31#255'qB.'#255#171'nS'#255

+  +#185#134'p'#255#194#151#131#255#198#158#140#255#200#160#142#255#200#160#142

+  +#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160

+  +#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200

+  +#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255

+  +#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142

+  +#255'9.)'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'hSJ'#255#200#160#142

+  +#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160

+  +#142#255'6+'''#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#6#5#5#255#184#148#131#255#200#160#142

+  +#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160

+  +#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200

+  +#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255

+  +#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142

+  +#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160

+  +#142#255#200#160#142#255#200#160#142#255#200#160#142#255#200#160#142#255#199

+  +#159#141#255#198#157#139#255#192#147''#255#181'g'#255#161'dI'#255'd:&'#255

+  +'\1'#29#255'Z0'#29#171'@@@'#4#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27'q\1'#29#255'a6#'

+  +#255#143'W?'#255#177'za'#255#191#144'|'#255#198#157#139#255#200#161#144#255

+  +#201#162#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145

+  +#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163

+  +#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201

+  +#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255

+  +#201#163#145#255'=2,'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'!'#27#24#255#197

+  +#161#143#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255

+  +#201#163#145#255#197#161#143#255#3#2#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#149'zl'#255#201

+  +#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255

+  +#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145

+  +#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163

+  +#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201

+  +#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255

+  +#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145#255#201#163#145

+  +#255#201#162#145#255#200#161#143#255#197#155#136#255#187#138'u'#255#173'rX'

+  +#255'|I3'#255'_4 '#255'\0'#28#253'W1 2'#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +#6'\0'#28#216'^2'#31#255'i=)'#255#165'jP'#255#184#133'n'#255#196#152#134#255

+  +#201#162#145#255#202#164#148#255#202#165#148#255#202#165#148#255#202#165#148

+  +#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165

+  +#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202

+  +#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255

+  +#202#165#148#255#202#165#148#255'E82'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#2#2#2#255#1#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'.&"'#255#202

+  +#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255

+  +#202#165#148#255#202#165#148#255#146'wk'#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'eRI'#255#202

+  +#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255

+  +#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148

+  +#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165

+  +#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202

+  +#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255

+  +#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148#255#202#165#148

+  +#255#202#165#148#255#202#164#147#255#200#160#143#255#193#148#128#255#180'~f'

+  +#255#151'^D'#255'a7$'#255'\1'#29#255'Z0'#28#156'UUU'#3#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0'[/'#27'D\0'#28#255'`5!'#255#128'N8'#255#175'v]'#255#190

+  +#143'{'#255#200#159#142#255#203#165#150#255#204#167#151#255#204#167#151#255

+  +#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151

+  +#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167

+  +#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204

+  +#167#151#255#204#167#151#255#204#167#151#255'N?9'#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255'vaW'#255#204#167#151#255#160#131'w'#255'cRI'#255'WG@'#255

+  +#168#137'|'#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151

+  +#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#145'wk'

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255'G:4'#255#204#167#151#255#204#167#151#255#204#167#151#255#204

+  +#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255

+  +#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151

+  +#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167

+  +#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204

+  +#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255#204#167#151#255

+  +#204#167#151#255#204#167#151#255#204#167#151#255#204#167#150#255#202#165#148

+  +#255#198#155#138#255#186#137's'#255#171'nU'#255'oB.'#255'^2'#31#255'\0'#28

+  +#235'V2"'#21#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +#169'\1'#29#255'c9&'#255#155'aH'#255#182#128'j'#255#195#152#133#255#202#164

+  +#148#255#205#169#154#255#206#169#155#255#206#169#155#255#206#169#155#255#206

+  +#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255

+  +#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155

+  +#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169

+  +#155#255'VGA'#255#0#0#0#255#0#0#0#255#0#0#0#255#5#4#4#255#206#169#155#255#206

+  +#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255

+  +#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155

+  +#255#206#169#155#255#206#169#155#255#206#169#155#255#152'}r'#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#1#1#255'vaY'#255#206

+  +#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255

+  +#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155

+  +#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169

+  +#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206

+  +#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255

+  +#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155#255#206#169#155

+  +#255#206#169#155#255#206#169#155#255#205#167#152#255#201#162#145#255#192#147

+  +''#255#177'za'#255#138'T='#255'`6"'#255'\1'#29#255'[0'#29'e'#0#0#0#1#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#27'\0'#28#243'^3'#31

+  +#255'pC/'#255#171'oU'#255#188#138'u'#255#199#158#141#255#205#169#154#255#207

+  +#171#157#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255

+  +#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158

+  +#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172

+  +#158#255#207#172#158#255#207#172#158#255#207#172#158#255'~i`'#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#22#18#16#255#207#172#158#255#207#172#158#255#207#172#158

+  +#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172

+  +#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207

+  +#172#158#255#207#172#158#255#207#172#158#255'/''$'#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#9#7#7#255#164#136'~'#255#207#172#158#255#207#172#158

+  +#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172

+  +#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207

+  +#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255

+  +#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158

+  +#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172

+  +#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207

+  +#172#158#255#207#171#157#255#204#167#151#255#196#153#136#255#183#131'l'#255

+  +#160'fK'#255'f;('#255']1'#30#255'[/'#27#199'te^'#3#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27'q\0'#28#255'`6"'#255

+  +#130'P9'#255#177'x`'#255#192#146''#255#203#164#149#255#208#173#159#255#209

+  +#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255

+  +#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161

+  +#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175

+  +#161#255#209#175#161#255#209#175#161#255#199#167#153#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255'.&#'#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175

+  +#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209

+  +#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255

+  +#209#175#161#255#209#175#161#255#209#175#161#255'*$!'#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255'"'#28#26#255#197#165#153#255#209#175#161#255#209#175#161#255#209#175#161

+  +#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175

+  +#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209

+  +#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255

+  +#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161

+  +#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175

+  +#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209#175#161#255#209

+  +#174#160#255#207#171#157#255#200#160#144#255#188#139'w'#255#171'pV'#255'rD0'

+  +#255'^3'#31#255'\0'#28#250'\2'#30'1'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#1'[/'#27#184']1'#30#255'c9&'

+  +#255#148'^E'#255#182#128'j'#255#197#154#136#255#206#170#155#255#210#176#163

+  +#255#211#178#164#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178

+  +#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211

+  +#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255

+  +#211#178#165#255#211#178#165#255#211#178#165#255#12#10#9#255#0#0#0#255#0#0#0

+  +#255'MA<'#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255

+  +#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165

+  +#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178

+  +#165#255#211#178#165#255#211#178#165#255#211#178#165#255#178#150#139#255'D95'

+  +#255#9#7#7#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'V'

+  +'IC'#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211

+  +#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255

+  +#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165

+  +#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178

+  +#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211

+  +#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255

+  +#211#178#165#255#211#178#165#255#211#178#165#255#211#178#165#255#211#178#164

+  ,#255#209#176#162#255#204#167#151#255#193#148#129#255#177'x`'#255#129'P9'#255

+  +'`6"'#255'\0'#28#255'[0'#28't'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#21'\0'#28#229'^2'

+  +#31#255'i?+'#255#163'jP'#255#186#136's'#255#200#160#144#255#209#174#160#255

+  +#212#180#167#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169

+  +#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181

+  +#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213

+  +#181#169#255#213#181#169#255#213#181#169#255'.''%'#255#0#0#0#255',%#'#255#200

+  +#170#159#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255

+  +#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169

+  +#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181

+  +#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213

+  +#181#169#255#139'vo'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'.'

+  +'''$'#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213

+  +#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255

+  +#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169

+  +#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181

+  +#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213

+  +#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255

+  +#213#181#169#255#213#181#169#255#213#181#169#255#213#181#169#255#212#180#168

+  +#255#211#178#165#255#207#171#157#255#197#155#137#255#182#128'j'#255#148']E'

+  +#255'c9&'#255']1'#30#255'[/'#27#179#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +'?\0'#28#252'_4 '#255'tF1'#255#172'sY'#255#190#142'z'#255#203#165#150#255#211

+  +#178#164#255#213#183#170#255#214#184#172#255#214#184#172#255#214#184#172#255

+  +#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172

+  +#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184

+  +#172#255#214#184#172#255#214#184#172#255'ng'#255'{ib'#255#214#184#172#255

+  +#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172

+  +#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184

+  +#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214

+  +#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255

+  +#214#184#172#255' '#28#26#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#14#12

+  +#11#255#209#180#168#255#214#184#172#255#214#184#172#255#214#184#172#255#214

+  +#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255

+  +#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172

+  +#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184

+  +#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214

+  +#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255

+  +#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172#255#214#184#172

+  +#255#213#182#169#255#209#176#161#255#200#161#143#255#186#135'q'#255#161'gO'

+  +#255'h=*'#255'^2'#31#255'\0'#28#226'W-'#26#19#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0'[/'#27'}\1'#29#255'`6"'#255'|M8'#255#175'x^'#255#192#147''#255

+  +#205#170#154#255#213#181#169#255#215#185#173#255#216#187#175#255#216#187#175

+  +#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187

+  +#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216

+  +#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255

+  +#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175

+  +#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187

+  +#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216

+  +#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255

+  +#216#187#175#255#187#162#151#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#2

+  +#2#255#180#156#146#255#216#187#175#255#216#187#175#255#216#187#175#255#216

+  +#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255

+  +#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175

+  +#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187

+  +#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216

+  ,#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255

+  +#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175#255#216#187#175

+  +#255#215#185#173#255#211#179#166#255#202#165#148#255#188#139'w'#255#167'mU'

+  +#255'nC/'#255'^3'#31#255'\0'#28#251'Z.'#27';'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0'[/'#27#2'[/'#27#170'\1'#29#255'a7$'#255#130'Q<'#255#178

+  +'{c'#255#195#151#132#255#208#173#159#255#215#185#173#255#217#189#178#255#217

+  +#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255

+  +#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178

+  +#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189

+  +#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217

+  +#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255

+  +#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178

+  +#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189

+  +#178#255#217#189#178#255'.(&'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#128

+  +'oi'#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217

+  +#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255

+  +#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178

+  +#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189

+  +#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217

+  +#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255

+  +#217#189#178#255#217#189#178#255#217#189#178#255#217#189#178#255#217#188#177

+  +#255#213#183#170#255#205#168#153#255#191#144'|'#255#170'rZ'#255'sF2'#255'`5!'

+  +#255'\0'#28#255'Z/'#27'g'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0'[/'#27#6'[/'#27#188']1'#30#255'c9&'#255#136'V?'#255#180'~g'

+  +#255#197#154#136#255#209#176#162#255#216#187#176#255#219#192#181#255#219#192

+  +#182#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219

+  +#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255

+  +#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183

+  +#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193

+  +#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219

+  +#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255

+  +#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#158#138#131

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#131'sm'#255#219#193#183#255#219

+  +#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255

+  +#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183

+  +#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193

+  +#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219

+  +#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255

+  +#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183#255#219#193#183

+  +#255#219#193#183#255#219#192#182#255#218#191#180#255#215#185#173#255#207#172

+  +#156#255#193#147#128#255#174'v^'#255'wJ6'#255'`6"'#255'\1'#29#255'[/'#27'~'#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0'[/'#27#12'[/'#27#203']1'#30#255'c:'''#255#141'YC'#255#181#128'h'#255

+  +#198#155#138#255#210#177#164#255#217#190#178#255#220#194#184#255#221#195#185

+  +#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196

+  +#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221

+  +#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255

+  +#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186

+  +#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196

+  +#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221

+  +#196#186#255#221#196#186#255#221#196#186#255're_'#255#0#0#0#255#0#0#0#255#4#4

+  +#4#255#160#142#134#255#221#196#186#255#221#196#186#255#221#196#186#255#221

+  +#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255

+  +#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186

+  +#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196

+  ,#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221

+  +#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255

+  +#221#196#186#255#221#196#186#255#221#196#186#255#221#196#186#255#221#195#185

+  +#255#219#193#183#255#216#187#175#255#207#172#158#255#194#148#130#255#176'x_'

+  +#255'{M8'#255'a6#'#255'\1'#29#255'[/'#27#148#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +#21'\0'#28#217']1'#30#255'c:'''#255#138'XB'#255#181'h'#255#197#156#137#255

+  +#211#178#164#255#218#191#180#255#221#196#187#255#222#198#188#255#223#198#189

+  +#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198

+  +#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223

+  +#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255

+  +#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189

+  +#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198

+  +#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223

+  +#198#189#255#221#196#187#255#6#6#5#255#10#9#8#255#188#167#159#255#223#198#189

+  +#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198

+  +#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223

+  +#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255

+  +#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189

+  +#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198

+  +#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223#198#189#255#223

+  +#198#189#255#223#198#189#255#222#198#188#255#221#196#186#255#217#188#177#255

+  +#208#173#159#255#193#149#129#255#174'w^'#255'zM8'#255'a7$'#255'\1'#29#255'[/'

+  +#27#170'[/'#27#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27' \0'#28#223']1'#30

+  +#255'c:'''#255#132'T?'#255#180'~g'#255#197#155#136#255#211#178#164#255#219

+  +#193#181#255#223#198#189#255#224#201#192#255#224#201#192#255#224#201#192#255

+  +#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192

+  +#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201

+  +#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224

+  +#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255

+  +#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192

+  +#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#134'xr'

+  +#255#205#184#176#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201

+  +#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224

+  +#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255

+  +#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192

+  +#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201

+  +#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#224

+  +#201#192#255#224#201#192#255#224#201#192#255#224#201#192#255#223#200#191#255

+  +#222#197#187#255#217#189#178#255#207#172#158#255#192#147''#255#171'u\'#255

+  +'vI6'#255'a6#'#255'\1'#29#255'[/'#27#179'[/'#27#6#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0'[/'#27#25'\0'#28#209']1'#30#255'c9&'#255#128'Q='#255#177

+  +'{c'#255#195#151#133#255#209#176#162#255#219#192#181#255#223#200#191#255#225

+  +#203#194#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255

+  +#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196

+  +#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204

+  +#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226

+  +#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255

+  +#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196

+  +#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204

+  +#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226

+  +#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255

+  +#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196

+  ,#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204

+  +#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226

+  +#204#196#255#226#204#196#255#226#204#196#255#226#204#196#255#226#203#195#255

+  +#225#202#193#255#222#198#188#255#217#188#177#255#206#169#155#255#191#144'|'

+  +#255#168'qY'#255'rG3'#255'`6"'#255'\1'#29#255'[/'#27#159'[/'#27#4#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#15'\0'#28#193']1'

+  +#30#255'b8%'#255'yM8'#255#170'u\'#255#192#146'~'#255#207#171#156#255#217#189

+  +#178#255#223#200#191#255#226#205#197#255#227#206#198#255#228#207#199#255#228

+  +#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255

+  +#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199

+  +#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207

+  +#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228

+  +#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255

+  +#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199

+  +#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207

+  +#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228

+  +#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255

+  +#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199

+  +#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207#199#255#228#207

+  +#199#255#228#207#199#255#228#207#199#255#228#207#199#255#227#206#198#255#226

+  +#204#196#255#222#198#188#255#215#185#173#255#202#165#148#255#187#137'u'#255

+  +#159'jR'#255'nD0'#255'`6"'#255'\1'#29#255'[/'#27#137#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#8'[/'

+  +#27#175'\1'#29#255'`6"'#255'nD0'#255#158'iR'#255#187#137'u'#255#202#165#148

+  +#255#215#186#174#255#223#199#190#255#227#205#198#255#229#208#201#255#229#209

+  +#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229

+  +#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255

+  +#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202

+  +#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210

+  +#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229

+  +#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255

+  +#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202

+  +#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210

+  +#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229

+  +#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255

+  +#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202#255#229#210#202

+  +#255#229#210#202#255#229#209#202#255#228#207#201#255#226#204#197#255#221#196

+  +#187#255#212#180#168#255#198#157#140#255#183#130'l'#255#143'^G'#255'g>+'#255

+  +'_4 '#255'\1'#29#254'[/'#27'q'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#3'[/'#27

+  +#132'\1'#29#254'_4 '#255'g>+'#255#140'[F'#255#181#129'j'#255#198#155#138#255

+  +#211#178#165#255#221#195#185#255#227#204#197#255#230#209#203#255#230#212#205

+  +#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212

+  +#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231

+  +#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255

+  +#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206

+  +#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212

+  +#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231

+  +#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255

+  +#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206

+  +#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212

+  +#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231#212#206#255#231

+  ,#212#206#255#231#212#206#255#231#212#206#255#231#211#206#255#230#211#205#255

+  +#229#209#201#255#225#203#194#255#219#191#181#255#208#173#159#255#193#149#129

+  +#255#173'w`'#255'~Q='#255'c:'''#255'^2'#31#255'\0'#28#238'[/'#27'O'#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27'F\0'#28#234'^2'#31#255'c:'

+  +''''#255'zN:'#255#168's['#255#190#143'{'#255#205#167#152#255#217#187#177#255

+  +#225#201#193#255#229#209#202#255#232#213#207#255#232#214#209#255#233#215#210

+  +#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215

+  +#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233

+  +#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255

+  +#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210

+  +#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215

+  +#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233

+  +#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255

+  +#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210

+  +#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215#210#255#233#215

+  +#210#255#233#215#210#255#233#215#210#255#232#215#209#255#232#214#208#255#231

+  +#212#206#255#228#207#201#255#223#198#189#255#213#182#170#255#200#160#144#255

+  +#186#136'r'#255#158'iR'#255'pE2'#255'a7$'#255']1'#30#255'\0'#28#201'[/'#27#31

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +#26'\0'#28#193']1'#30#255'`6"'#255'iA.'#255#142']H'#255#179#128'h'#255#196

+  +#153#135#255#210#176#163#255#220#194#184#255#227#205#198#255#231#212#206#255

+  +#233#216#211#255#234#217#212#255#234#218#213#255#234#218#213#255#234#218#213

+  +#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218

+  +#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234

+  +#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255

+  +#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213

+  +#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218

+  +#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234

+  +#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255

+  +#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213#255#234#218#213

+  +#255#234#218#213#255#234#217#212#255#234#216#211#255#233#215#210#255#230#211

+  +#205#255#226#203#195#255#218#190#179#255#206#170#155#255#192#146''#255#172

+  +'v`'#255#129'S?'#255'e<)'#255'_4 '#255'\1'#29#255'[/'#27#143'[/'#27#5#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +'[/'#27#3'[/'#27'\0'#28#248'^3'#31#255'c:'''#255'sI6'#255#158'kT'#255#186

+  +#136's'#255#200#160#143#255#213#180#169#255#222#197#187#255#229#208#201#255

+  +#232#214#209#255#234#218#213#255#235#219#215#255#236#220#215#255#236#220#216

+  +#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220

+  +#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236

+  +#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255

+  +#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216

+  +#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220

+  +#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236

+  +#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255#236#220#216#255

+  +#236#220#216#255#236#220#216#255#236#220#216#255#236#220#215#255#235#219#215

+  +#255#234#217#212#255#232#213#207#255#227#205#198#255#219#193#183#255#209#176

+  +#162#255#196#153#136#255#181#129'l'#255#145'`K'#255'lB0'#255'a7$'#255']1'#30

+  +#255'\0'#28#231'[/'#27'O'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27'$\0'

+  +#28#185'\1'#29#255'`5!'#255'f=*'#255#128'S>'#255#166'r['#255#188#139'v'#255

+  +#201#161#145#255#213#181#169#255#223#197#189#255#229#209#202#255#233#216#210

+  +#255#235#219#215#255#236#221#217#255#237#222#219#255#238#223#220#255#238#223

+  +#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238

+  +#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255

+  +#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220

+  +#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223

+  +#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238

+  +#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255#238#223#220#255

+  +#238#223#220#255#238#223#220#255#237#222#219#255#237#222#218#255#236#221#217

+  +#255#235#218#214#255#232#214#208#255#228#206#199#255#220#193#184#255#210#176

+  +#163#255#197#155#137#255#184#134'o'#255#155'iR'#255'uI7'#255'c:'''#255'^3'#31

+  +#255'\1'#29#252'[/'#27#144'[/'#27#14#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27'U\0'#28#228']1'#30#255'`6"'#255'g>,'#255'R?'

+  +#255#164'qZ'#255#188#139'v'#255#200#159#144#255#211#179#166#255#220#194#184

+  +#255#228#206#199#255#232#214#209#255#235#219#215#255#237#222#219#255#238#225

+  +#221#255#239#225#222#255#239#225#222#255#239#226#223#255#239#226#223#255#239

+  +#226#223#255#239#226#223#255#239#226#223#255#239#226#223#255#239#226#223#255

+  +#239#226#223#255#239#226#223#255#239#226#223#255#239#226#223#255#239#226#223

+  +#255#239#226#223#255#239#226#223#255#239#226#223#255#239#226#223#255#239#226

+  +#223#255#239#226#223#255#239#226#223#255#239#226#223#255#239#226#223#255#239

+  +#226#223#255#239#226#223#255#239#226#223#255#239#226#223#255#239#225#222#255

+  +#238#225#221#255#238#224#220#255#237#222#218#255#235#218#214#255#231#212#206

+  +#255#226#203#195#255#218#191#180#255#209#174#160#255#197#154#136#255#184#132

+  +'o'#255#154'hR'#255'uK8'#255'e;('#255'_4 '#255'\1'#29#255'\0'#28#197'[/'#27

+  +'/'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0'[/'#27#12'[/'#27#134'\0'#28#242'^2'#31#255'a5#'#255'g>+'#255

+  +'|Q='#255#160'lV'#255#184#133'p'#255#196#152#134#255#207#170#156#255#216#187

+  +#175#255#224#200#192#255#230#210#203#255#234#216#211#255#236#220#216#255#238

+  +#224#220#255#239#226#223#255#240#227#225#255#240#228#225#255#240#228#225#255

+  +#241#229#226#255#241#229#226#255#241#229#226#255#241#229#226#255#241#229#227

+  +#255#241#229#227#255#241#229#227#255#241#229#227#255#241#229#227#255#241#229

+  +#227#255#241#229#227#255#241#229#227#255#241#229#227#255#241#229#226#255#241

+  +#229#226#255#241#229#226#255#241#229#226#255#240#228#225#255#240#228#225#255

+  +#240#227#224#255#239#225#222#255#238#223#220#255#236#220#215#255#233#215#210

+  +#255#228#207#201#255#222#196#187#255#213#183#170#255#204#166#150#255#192#147

+  +''#255#179'i'#255#150'fO'#255'tI7'#255'e;('#255'`5!'#255']1'#30#255'\0'#28

+  +#223'[/'#27'`[/'#27#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#17'[/'#27'\'

+  +'0'#28#238']1'#30#255'`6"'#255'e<)'#255'rI6'#255#142'_J'#255#170'wa'#255#188

+  +#140'w'#255#199#158#141#255#208#173#159#255#216#186#175#255#222#196#187#255

+  ,#227#206#198#255#232#213#208#255#235#219#214#255#237#222#218#255#238#224#220

+  +#255#239#226#223#255#240#227#225#255#241#229#226#255#242#230#228#255#242#230

+  +#228#255#242#231#229#255#242#231#229#255#242#231#229#255#242#231#229#255#242

+  +#231#229#255#242#231#229#255#242#231#229#255#242#230#228#255#241#229#227#255

+  +#241#229#226#255#240#227#225#255#239#225#222#255#238#224#220#255#236#221#217

+  +#255#234#218#213#255#231#211#206#255#226#204#196#255#220#194#184#255#214#183

+  +#171#255#206#169#155#255#196#153#135#255#185#135'r'#255#162'q['#255#134'XD'

+  +#255'lC1'#255'c:'''#255'_4 '#255']0'#30#255'\0'#28#217'[/'#27'`[/'#27#4#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#13'[/'

+  +#27'w\0'#28#233']1'#30#255'_4 '#255'b8%'#255'h?-'#255'zN;'#255#149'dP'#255

+  +#170'xa'#255#187#137't'#255#194#150#131#255#202#164#148#255#210#176#163#255

+  +#216#187#175#255#220#194#184#255#224#200#192#255#228#207#199#255#231#212#206

+  +#255#234#217#211#255#236#220#215#255#236#222#217#255#237#222#219#255#238#223

+  +#220#255#238#223#220#255#238#224#220#255#238#223#220#255#237#223#219#255#237

+  +#223#218#255#236#221#217#255#235#219#215#255#233#216#210#255#230#211#204#255

+  +#227#204#197#255#223#199#190#255#219#192#183#255#215#185#173#255#208#173#159

+  +#255#200#160#144#255#192#146''#255#183#133'o'#255#164's\'#255#142']J'#255'r'

+  +'I7'#255'f=*'#255'a6#'#255'^3'#31#255'\1'#29#255'\0'#28#210'[/'#27'X[/'#27#2

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#5'[/'#27'P\0'#28#173'\1'#29#249']1'#30#255'`'

+  +'5!'#255'c9&'#255'g>,'#255'qH6'#255#133'YE'#255#153'iT'#255#172'yd'#255#186

+  +#136'q'#255#191#144'}'#255#196#153#136#255#202#162#146#255#207#171#156#255

+  +#211#178#165#255#214#183#171#255#216#186#175#255#217#188#177#255#218#190#179

+  +#255#219#191#182#255#219#192#182#255#219#192#181#255#218#189#179#255#217#187

+  +#177#255#215#185#173#255#213#182#169#255#210#176#163#255#205#169#154#255#200

+  +#160#144#255#195#151#133#255#190#142'z'#255#183#132'o'#255#167'u_'#255#148'e'

+  +'P'#255'S@'#255'mE2'#255'f=*'#255'b7%'#255'_4 '#255']1'#30#255'\0'#28#235'['

+  +'/'#27#147'[/'#27'5'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0'[/'#27#18'[/'#27'i\0'#28#199'\1'#29#254']1'#30#255'_4 '#255

+  +'a6#'#255'd9('#255'g>,'#255'oF3'#255'}Q>'#255#138'[G'#255#149'fQ'#255#160'oZ'

+  +#255#170'xa'#255#176'}h'#255#180#128'l'#255#183#133'p'#255#186#136's'#255#188

+  +#138'u'#255#188#139'v'#255#187#138'u'#255#186#135'r'#255#183#132'n'#255#178

+  +#128'j'#255#174'|e'#255#168'v`'#255#158'mW'#255#146'bN'#255#133'YE'#255'yM;'

+  +#255'mC1'#255'g>+'#255'c9&'#255'`6"'#255'^3'#31#255']1'#30#255'\0'#28#248'\0'

+  +#28#173'[/'#27'O[/'#27#5#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#20'[/'#27

+  +'V\0'#28#153'\0'#28#220'\1'#29#255']1'#30#255'^3'#31#255'`5!'#255'a7$'#255'c'

+  +'9&'#255'e;('#255'f=*'#255'g>,'#255'i@.'#255'jB0'#255'mE2'#255'qH5'#255'tJ7'

+  +#255'qG5'#255'lC1'#255'jA0'#255'h?-'#255'g>+'#255'e<)'#255'd:('#255'c9&'#255

+  +'a6#'#255'`5!'#255'^2'#31#255']1'#30#255'\1'#29#252'\0'#28#201'[/'#27#134'[/'

+  +#27'C[/'#27#8#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#31'[/'#27'_[/'#27#138'\0'#28#176'\0'#28

+  +#213'\0'#28#248'\1'#29#255'\1'#29#255'\1'#29#255']1'#30#255'^2'#31#255'^2'#31

+  +#255'^3'#31#255'^3'#31#255'^3'#31#255'^2'#31#255']1'#30#255']1'#30#255'\1'#29

+  +#255'\1'#29#255'\1'#29#255'\0'#28#241'\0'#28#203'\0'#28#165'[/'#27'[/'#27'N'

+  +'[/'#27#15#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0'[/'#27#2'[/'#27'![/'#27'E[/'#27'U[/'#27'a[/'#27'm[/'

+  +#27'y[/'#27#134'\0'#29#141'[/'#27#130'[/'#27'v[/'#27'j[/'#27'^[/'#27'Q[/'#27

+  +'=[/'#27#23#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#255#255#255#128#0

+  +#255#255#255#255#255#255#255#255#255#255#255#255#255#224#0#0#3#255#255#255

+  +#255#255#255#255#255#255#255#255#254#0#0#0#0'?'#255#255#255#255#255#255#255

+  +#255#255#255#240#0#0#0#0#7#255#255#255#255#255#255#255#255#255#255#128#0#0#0

+  +#0#0#255#255#255#255#255#255#255#255#255#254#0#0#0#0#0#0'?'#255#255#255#255

+  +#255#255#255#255#248#0#0#0#0#0#0#15#255#255#255#255#255#255#255#255#224#0#0#0

+  +#0#0#0#3#255#255#255#255#255#255#255#255#128#0#0#0#0#0#0#0#255#255#255#255

+  +#255#255#255#254#0#0#0#0#0#0#0#0'?'#255#255#255#255#255#255#252#0#0#0#0#0#0#0

+  +#0#31#255#255#255#255#255#255#240#0#0#0#0#0#0#0#0#7#255#255#255#255#255#255

+  +#224#0#0#0#0#0#0#0#0#3#255#255#255#255#255#255#128#0#0#0#0#0#0#0#0#1#255#255

+  +#255#255#255#255#0#0#0#0#0#0#0#0#0#0''#255#255#255#255#254#0#0#0#0#0#0#0#0#0

+  +#0'?'#255#255#255#255#252#0#0#0#0#0#0#0#0#0#0#31#255#255#255#255#248#0#0#0#0

+  +#0#0#0#0#0#0#15#255#255#255#255#240#0#0#0#0#0#0#0#0#0#0#7#255#255#255#255#224

+  +#0#0#0#0#0#0#0#0#0#0#3#255#255#255#255#192#0#0#0#0#0#0#0#0#0#0#1#255#255#255

+  +#255#128#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#0#0#0#0#0#0#0#0#0#0#0#0''#255

+  +#255#254#0#0#0#0#0#0#0#0#0#0#0#0''#255#255#254#0#0#0#0#0#0#0#0#0#0#0#0'?'

+  +#255#255#252#0#0#0#0#0#0#0#0#0#0#0#0#31#255#255#248#0#0#0#0#0#0#0#0#0#0#0#0

+  +#15#255#255#240#0#0#0#0#0#0#0#0#0#0#0#0#7#255#255#240#0#0#0#0#0#0#0#0#0#0#0#0

+  +#7#255#255#224#0#0#0#0#0#0#0#0#0#0#0#0#3#255#255#192#0#0#0#0#0#0#0#0#0#0#0#0

+  +#3#255#255#192#0#0#0#0#0#0#0#0#0#0#0#0#1#255#255#128#0#0#0#0#0#0#0#0#0#0#0#0

+  +#1#255#255#128#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#255#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0''#254#0#0#0#0#0#0#0#0#0#0#0#0#0#0''

+  +#254#0#0#0#0#0#0#0#0#0#0#0#0#0#0'?'#254#0#0#0#0#0#0#0#0#0#0#0#0#0#0'?'#252#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0'?'#252#0#0#0#0#0#0#0#0#0#0#0#0#0#0#31#252#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#31#248#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#248#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#15#248#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#240#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#7#240#0#0#0#0#0#0#0#0#0#0#0#0#0#0#7#240#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#7#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#7#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#3#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#192#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#3#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#192#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#192

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#192#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#192#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#1#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#192#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3

+  +#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#224#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#3#240#0#0#0#0#0#0#0#0#0#0#0#0#0#0#7#240#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#7#240#0#0#0#0#0#0#0#0#0#0#0#0#0#0#7#240#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#15#248#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#248#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#248

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#15#252#0#0#0#0#0#0#0#0#0#0#0#0#0#0#31#252#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#31#252#0#0#0#0#0#0#0#0#0#0#0#0#0#0'?'#254#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0'?'#254#0#0#0#0#0#0#0#0#0#0#0#0#0#0'?'#254#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0''#255#0#0#0#0#0#0#0#0#0#0#0#0#0#0''#255#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#255#255#128#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#128#0#0#0#0#0#0#0#0#0#0#0

+  +#0#1#255#255#128#0#0#0#0#0#0#0#0#0#0#0#0#1#255#255#192#0#0#0#0#0#0#0#0#0#0#0

+  +#0#3#255#255#192#0#0#0#0#0#0#0#0#0#0#0#0#3#255#255#224#0#0#0#0#0#0#0#0#0#0#0

+  +#0#7#255#255#224#0#0#0#0#0#0#0#0#0#0#0#0#15#255#255#240#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#15#255#255#248#0#0#0#0#0#0#0#0#0#0#0#0#31#255#255#248#0#0#0#0#0#0#0#0#0#0

+  +#0#0'?'#255#255#252#0#0#0#0#0#0#0#0#0#0#0#0''#255#255#252#0#0#0#0#0#0#0#0#0

+  +#0#0#0#255#255#255#254#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#0#0#0#0#0#0#0

+  +#0#0#0#0#1#255#255#255#255#128#0#0#0#0#0#0#0#0#0#0#3#255#255#255#255#128#0#0

+  +#0#0#0#0#0#0#0#0#7#255#255#255#255#192#0#0#0#0#0#0#0#0#0#0#15#255#255#255#255

+  +#224#0#0#0#0#0#0#0#0#0#0#31#255#255#255#255#240#0#0#0#0#0#0#0#0#0#0#31#255

+  +#255#255#255#248#0#0#0#0#0#0#0#0#0#0'?'#255#255#255#255#252#0#0#0#0#0#0#0#0#0

+  +#0''#255#255#255#255#254#0#0#0#0#0#0#0#0#0#1#255#255#255#255#255#255#0#0#0#0

+  +#0#0#0#0#0#3#255#255#255#255#255#255#128#0#0#0#0#0#0#0#0#7#255#255#255#255

+  +#255#255#224#0#0#0#0#0#0#0#0#15#255#255#255#255#255#255#240#0#0#0#0#0#0#0#0

+  +#31#255#255#255#255#255#255#248#0#0#0#0#0#0#0#0''#255#255#255#255#255#255

+  +#254#0#0#0#0#0#0#0#0#255#255#255#255#255#255#255#255#128#0#0#0#0#0#0#3#255

+  +#255#255#255#255#255#255#255#192#0#0#0#0#0#0#7#255#255#255#255#255#255#255

+  +#255#240#0#0#0#0#0#0#31#255#255#255#255#255#255#255#255#252#0#0#0#0#0#0''

+  +#255#255#255#255#255#255#255#255#255#0#0#0#0#0#3#255#255#255#255#255#255#255

+  +#255#255#255#224#0#0#0#0#15#255#255#255#255#255#255#255#255#255#255#252#0#0#0

+  +#0''#255#255#255#255#255#255#255#255#255#255#255#192#0#0#7#255#255#255#255

+  +#255#255#255#255#255#255#255#255#254#0#1#255#255#255#255#255#255#255#255#255

+  +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255

+  +#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255

+  +#255#255#255#255#255#255#255#255'('#0#0#0'@'#0#0#0#128#0#0#0#1#0' '#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'@@@'#4'III'#7'III'#7'33'

+  +'3'#5#128#128#128#2#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'UUU'#6'DDD'#15

+  +'FFF'#22'EEE'#26'DDD'#30'III#GGG/DDD<DDD@CCC5FFF(BBB'#31'BBB'#27'@@@'#24'GGG'

+  +#18'999'#9#128#128#128#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#128#128#128

+  +#2'999'#9'GGG'#18'DDD'#30'CCC9FFF_DDDEDD'#146'DDC'#159'EED'#170'DDC'#175'DD'

+  +'C'#178'DDC'#179'EED'#177'EED'#173'DCC'#164'EDD'#151'BBB'#136'CCCoCCCHCCC&CC'

+  +'C'#23';;;'#13'@@@'#4#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#128#128#128#2'777'#14'DDD"EEEFCCCoEDD'#150'DDC'#175'FFC'

+  +#187'GGC'#195'IFC'#200'LD<'#208'OB:'#215'RA6'#221'WA0'#226'TA3'#223'PB9'#218

+  +'MD<'#212'JD@'#206'IGD'#200'HGD'#197'EED'#191'DDC'#180'CCC'#163'DDD'#128'DDD'

+  +'VGGG/III'#21'+++'#6#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#128#128#128

+  +#2'FFF'#11'BBB#CCCXEED'#149'EEB'#179'GFC'#191'MC<'#208'W?.'#228'd=%'#246'i?!'

+  +#252'j?'#30#255'l?'#31#255'nA'#31#255'sF!'#253'zL%'#253'wG#'#253'oB!'#254'm@'

+  +#31#255'k>'#30#255'j>'#31#253'g>#'#249'[>+'#235'PB8'#218'HEC'#203'FEC'#195'E'

+  +'ED'#184'DDD'#166'DDDqEEE4@@@'#20'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'999'#9'BBB'#31

+  +'CCCPEDD'#143'FFE'#182'NB:'#211'Z?-'#231'g>#'#249'l?'#31#255'zK$'#253#150']*'

+  +#255#165'h.'#255#172'm0'#255#180's2'#255#186'x4'#255#189'{4'#255#192'5'#255

+  +#190'|4'#255#187'x4'#255#182'u3'#255#175'p1'#255#167'j/'#255#156'b+'#255#131

+  +'R&'#254'oB '#255'i>!'#253'_>)'#238'S@6'#222'FEB'#203'DDC'#190'DDD'#164'CCCk'

+  +'CCC.PPP'#16'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#128#128#128#2'CCC'#19'BBBBDDD'#136'EED'#179'LA9'#209'`=&'#243'k?'#31

+  +#255'N&'#254#154'`,'#255#176'q1'#255#191'~5'#255#200#138'7'#255#207#145'8'

+  +#255#210#149'9'#255#213#153'9'#255#217#157':'#255#219#160';'#255#221#162';'

+  +#255#220#162':'#255#217#158':'#255#215#155':'#255#211#151'9'#255#208#146'8'

+  +#255#203#141'8'#255#194#129'6'#255#183'v4'#255#163'f.'#255#137'U('#254'qC"'

+  +#254'f<!'#250'T?4'#224'GDB'#202'CCB'#188'DDD'#158'BBB`>>>!+++'#6#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4'BBB'#27'CCC[CCB'#165'LD='#203']<'

+  +'('#238'j> '#255#135'R('#254#176'p3'#255#193#128'7'#255#202#139'9'#255#211

+  +#151';'#255#220#162'<'#255#227#170'>'#255#232#176'?'#255#234#180'?'#255#237

+  +#182'?'#255#239#185'@'#255#241#187'@'#255#242#188'A'#255#241#187'@'#255#240

+  +#185'A'#255#238#183'@'#255#235#180'@'#255#233#178'?'#255#229#173'>'#255#222

+  +#165'='#255#215#156'<'#255#205#144':'#255#196#133'8'#255#185'x5'#255#152'^-'

+  +#255'oC"'#254'd<#'#247'QA7'#220'FFE'#200'CCC'#180'CCC}AAA/UUU'#9#0#0#0#1#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#1'III'#7'CCC&DDDpECC'#180'X<,'#232'i=!'#254#128'O('#254

+  +#170'l3'#255#194#130':'#255#210#150'>'#255#220#163'?'#255#227#171'A'#255#234

+  +#180'B'#255#240#187'D'#255#242#190'D'#255#244#193'E'#255#246#194'D'#255#247

+  +#195'E'#255#248#197'E'#255#249#197'E'#255#249#198'E'#255#249#197'E'#255#248

+  +#196'E'#255#247#195'E'#255#246#195'E'#255#245#194'D'#255#243#191'D'#255#240

+  +#188'C'#255#236#183'C'#255#230#174'B'#255#223#165'@'#255#215#156'?'#255#200

+  +#137';'#255#182'u6'#255#146'[,'#255'm@!'#254'`:%'#244'KA;'#211'CCC'#189'CCC'

+  +#144'BBB>PPP'#16#128#128#128#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'999'#9'@@@4CCC'#133'HD@'#192'_9$'#244

+  +'rE%'#254#164'h3'#255#191';'#255#206#146'?'#255#219#163'C'#255#232#178'F'

+  +#255#238#185'G'#255#241#189'H'#255#244#193'H'#255#246#195'I'#255#247#196'I'

+  +#255#247#197'J'#255#247#197'I'#255#247#198'I'#255#248#198'I'#255#248#198'I'

+  +#255#248#197'I'#255#248#198'I'#255#248#198'I'#255#248#198'I'#255#247#197'I'

+  +#255#247#197'I'#255#247#196'I'#255#246#196'I'#255#245#194'H'#255#242#190'H'

+  +#255#239#187'H'#255#235#182'G'#255#224#168'D'#255#211#153'A'#255#196#134'='

+  +#255#177'q7'#255#133'Q)'#254'e: '#253'N?7'#218'DDC'#195'CCC'#160'FFFP@@@'#20

+  +#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +'III'#7'FFF3CCC'#145'LB;'#204'd:"'#250'|L('#254#180's9'#255#202#143'A'#255

+  +#216#159'F'#255#228#174'I'#255#236#184'K'#255#241#191'L'#255#243#193'M'#255

+  +#244#194'M'#255#244#195'M'#255#245#196'M'#255#245#195'M'#255#245#195'M'#255

+  +#245#195'M'#255#245#195'M'#255#245#195'M'#255#245#195'M'#255#245#195'M'#255

+  +#245#195'M'#255#245#195'M'#255#245#195'M'#255#245#195'M'#255#245#195'M'#255

+  +#245#195'M'#255#245#196'M'#255#245#195'M'#255#244#194'M'#255#243#194'M'#255

+  +#242#192'M'#255#238#186'L'#255#232#179'J'#255#220#165'F'#255#208#150'C'#255

+  +#190'<'#255#147'[.'#255'h< '#255'S=1'#228'EED'#199'DDD'#168'BBBUGGG'#18#0#0

+  +#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4'FFF(EEE'#134

+  +'P?5'#212'e:!'#254#137'U,'#254#186'z='#255#208#150'E'#255#224#171'L'#255#233

+  +#181'O'#255#238#187'P'#255#240#191'P'#255#242#192'Q'#255#242#193'Q'#255#242

+  +#193'Q'#255#242#193'P'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242

+  +#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242

+  +#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242

+  +#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242#193'Q'#255#242

+  +#193'Q'#255#241#192'Q'#255#239#189'P'#255#234#184'O'#255#228#175'M'#255#215

+  +#159'I'#255#194#132'@'#255#160'd3'#255'k?"'#254'X:*'#236'FDC'#201'CCC'#164'A'

+  +'AAG;;;'#13#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'BBB'#31'CCCvO='

+  +'3'#211'f:'#31#255#150']2'#255#190#128'A'#255#211#155'I'#255#226#175'Q'#255

+  +#234#185'S'#255#237#188'T'#255#238#190'T'#255#239#191'U'#255#239#191'U'#255

+  +#239#191'U'#255#239#191'U'#255#239#191'U'#255#239#191'U'#255#239#191'U'#255

+  +#239#191'U'#255#235#189'S'#255'|d,'#255'N>'#28#255'4*'#19#255'=1'#22#255'WE'

+  +#31#255'w_*'#255#173#139'='#255#239#191'U'#255#239#191'U'#255#239#191'U'#255

+  +#239#191'U'#255#239#191'U'#255#239#191'U'#255#239#191'U'#255#239#191'U'#255

+  +#239#191'U'#255#239#190'T'#255#238#189'U'#255#236#187'S'#255#230#179'R'#255

+  +#217#162'L'#255#198#138'D'#255#170'l8'#255'pC$'#254'Z8'''#240'DBB'#197'CCC'

+  ,#153'FFF:@@@'#8#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'FFF'#22'BBBeJ?9'#195'b8 '

+  +#254#150']2'#255#194#133'E'#255#213#158'N'#255#226#176'T'#255#233#185'W'#255

+  +#236#187'W'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255

+  +#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255

+  +'cO%'#255#4#3#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#1#1#0#255#18#14#7#255'A4'#24#255#134'k2'#255#218#174'R'#255

+  +#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255#236#188'X'#255

+  +#236#188'X'#255#236#187'W'#255#234#186'W'#255#229#180'U'#255#218#165'P'#255

+  +#201#143'H'#255#173'o<'#255'k>#'#254'S;-'#231'CCC'#193'CCC'#141'DDD-fff'#5#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0'@@@'#12'DDDKFA='#179'`7 '#251#137'S-'#255#192#131'E'#255

+  +#214#161'Q'#255#226#176'W'#255#231#183'Y'#255#233#185'['#255#233#186'['#255

+  +#234#185'Z'#255#234#185'Z'#255#234#185'Z'#255#234#185'Z'#255#234#185'Z'#255

+  +#234#185'Z'#255#234#185'Z'#255#234#185'Z'#255'L<'#29#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#7#3#255'P?'#31#255#203#161'N'

+  +#255#234#185'Z'#255#234#185'Z'#255#234#185'Z'#255#234#185'Z'#255#233#186'['

+  +#255#232#183'Z'#255#228#178'Y'#255#219#167'T'#255#201#143'K'#255#163'g8'#255

+  +'f: '#255'O=4'#222'DDD'#188'CCCzBBB'#27#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'GGG$D@@'#147'\6#'

+  +#245'{I*'#254#185'{C'#255#211#157'R'#255#225#175'Z'#255#229#181'\'#255#230

+  +#183']'#255#230#183']'#255#230#183']'#255#230#183']'#255#230#183']'#255#230

+  +#183']'#255#230#183']'#255#230#183']'#255#230#183']'#255#230#183']'#255#138

+  +'m8'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#24#20#10#255'x_0'#255#226#181'['#255

+  +#230#183']'#255#230#183']'#255#230#183']'#255#230#181'\'#255#227#177'['#255

+  +#217#165'V'#255#196#136'J'#255#151']4'#255'b8 '#254'K@9'#214'CCC'#175'AAAJ..'

+  +'.'#11#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0'@@@'#16'CCC\V6'''#228'nA&'#254#178'tA'#255#205#151'R'#255#221#172

+  +'\'#255#226#179'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180'_'#255#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255#17#13#7#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#2#1#1#255'H9'#30#255#224#178']'#255#228#180'_'#255

+  +#228#180'_'#255#227#179'^'#255#224#175']'#255#213#160'W'#255#190#129'H'#255

+  +#137'T/'#255'^4 '#252'FB?'#201'CCC'#140'DDD"'#0#0#0#3#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#4'FFF,J=7'#175'`4'#30#255#165

+  +'g;'#255#200#144'Q'#255#217#166'\'#255#223#176'`'#255#225#177'`'#255#225#177

+  +'a'#255#225#177'a'#255#225#177'a'#255#225#177'a'#255#225#177'a'#255#225#177

+  +'a'#255#225#177'a'#255#225#177'a'#255#225#177'a'#255#225#177'a'#255#218#171

+  +'^'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#11#9#5#255#196#154'U'#255#225#177'a'#255#225#177'`'#255#224#177'a'

+  +#255#220#171'^'#255#208#154'W'#255#184'{F'#255'nA%'#254'T8*'#233'DDD'#180'CC'

+  +'CX333'#15#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'C'

+  +'CC'#19'CCCjY5#'#239'~J,'#254#191#132'M'#255#213#162']'#255#220#171'a'#255

+  +#221#173'c'#255#222#174'b'#255#222#174'b'#255#222#174'b'#255#222#174'b'#255

+  +#222#174'b'#255#222#174'b'#255#222#174'b'#255#222#174'b'#255#222#174'b'#255

+  +#222#174'b'#255#222#174'b'#255#154'yC'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#15#11#6#255#218#172'`'

+  +#255#222#174'b'#255#222#174'b'#255#221#173'b'#255#217#167'_'#255#202#146'T'

+  +#255#156'a9'#255'^4'#30#254'G@='#206'DDD'#151'>>>)@@@'#4#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'AAA+L;4'#188'b6 '#254#170'l@'#255#206#152

+  +'Z'#255#217#168'b'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171

+  +'d'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171

+  +'d'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171

+  +'d'#255#26#20#12#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  ,#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255'oW3'#255#219#171'd'#255#219#171'd'#255#219

+  +#171'd'#255#218#169'c'#255#212#161'_'#255#187'L'#255'uD)'#254'W6('#238'CCC'

+  +#182'CCC[III'#14#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#12'EBB'

+  +'S[3'#31#244#134'O/'#255#192#134'Q'#255#212#162'b'#255#215#167'd'#255#216#168

+  +'d'#255#216#168'd'#255#216#168'd'#255#216#168'd'#255#216#168'd'#255#216#168

+  +'d'#255#216#168'd'#255#216#168'd'#255#216#168'd'#255#216#168'd'#255#216#168

+  +'d'#255#216#168'd'#255#216#168'd'#255#216#168'd'#255#198#154'\'#255#5#4#2#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255'!'#25#15#255#216#168'd'#255#216#168'd'#255#216#168'd'#255#216#168'd'#255

+  +#214#166'd'#255#202#147'Y'#255#161'e='#255'^2'#29#255'J?:'#208'CCC'#137'EEE'

+  +#26#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'CCC'#23'O9/'#171'`3'#31

+  +#254#174'pD'#255#203#150']'#255#212#163'e'#255#213#164'e'#255#213#164'e'#255

+  +#213#164'e'#255#213#164'e'#255#213#164'e'#255#213#164'e'#255#213#164'e'#255

+  +#213#164'e'#255#213#164'e'#255#213#164'e'#255#213#164'e'#255#213#164'e'#255

+  +#213#164'e'#255#213#164'e'#255#213#164'e'#255#213#164'e'#255#173#133'R'#255#3

+  +#2#1#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#22#17#11#255#213#164'e'#255#213#164'e'#255#213#164'e'#255#213#164'e'#255

+  +#213#164'f'#255#209#158'a'#255#187#128'O'#255'yD)'#254'W4$'#241'BBB'#169'DDD'

+  +'1@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#2'FFF(W4$'#229'{E)'#255#191

+  +#134'T'#255#207#157'c'#255#210#160'f'#255#210#160'f'#255#210#160'f'#255#210

+  +#160'f'#255#210#160'f'#255#210#160'f'#255#210#160'f'#255#210#160'f'#255#152

+  +'tJ'#255'[E,'#255'K9$'#255'{]<'#255#196#149'_'#255#210#160'f'#255#210#160'f'

+  +#255#210#160'f'#255#210#160'f'#255#210#160'f'#255#159'yM'#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'"'#26#17#255#210#160

+  +'f'#255#210#160'f'#255#210#160'f'#255#210#160'f'#255#210#160'f'#255#209#160

+  +'e'#255#199#146']'#255#156'_;'#255'\1'#28#254'FBA'#188'FFFXNNN'#13#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0'FFF'#11'F@=T\/'#28#253#151'\9'#255#200#147'_'#255#207

+  +#156'e'#255#207#156'e'#255#207#156'e'#255#207#156'e'#255#207#156'e'#255#207

+  +#156'e'#255#207#156'e'#255#178#135'W'#255'$'#27#17#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255'N:&'#255#207#156'e'#255#207#156'e'#255#207#156

+  +'e'#255#207#156'e'#255#207#156'e'#255#3#2#1#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255'uX9'#255#207#156'e'#255#207#156'e'#255#207#156

+  +'e'#255#207#156'e'#255#207#156'e'#255#207#157'e'#255#204#153'b'#255#180'wK'

+  +#255'a4'#30#254'M;3'#216'DDD'#132'==='#25#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'CC'

+  +'C'#19'N9.'#159'^2'#30#254#176'rI'#255#202#150'c'#255#203#153'e'#255#203#153

+  +'f'#255#203#153'f'#255#203#153'f'#255#203#153'f'#255#203#153'f'#255#163'zQ'

+  +#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#29#22#15#255#203#153'f'#255#203#153'f'#255#203#153'f'#255#203#153'f'

+  +#255#14#10#7#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#4#3#2#255

+  +#203#153'f'#255#203#153'f'#255#203#153'f'#255#203#153'f'#255#203#153'f'#255

+  +#203#153'f'#255#203#153'f'#255#203#152'e'#255#190#134'X'#255'yC)'#254'V5&'

+  +#239'DDD'#165'FFF('#128#128#128#2#0#0#0#0#0#0#0#0#0#0#0#0'GGG'#25'V4%'#212's'

+  +'@&'#254#186#128'U'#255#199#148'd'#255#200#148'd'#255#200#148'd'#255#200#148

+  +'d'#255#200#148'd'#255#200#148'd'#255#198#146'd'#255#12#9#6#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#138'fE'#255#200#148'd'#255#200#148'd'#255#200#148'd'#255#15#11#7#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#1#0#0#255'&'#28#19#255#145'kH'#255#200#148'd'#255

+  +#200#148'd'#255#200#148'd'#255#200#148'd'#255#200#148'd'#255#200#148'd'#255

+  +#200#148'd'#255#200#148'd'#255#194#141'^'#255#146'W6'#255'[0'#28#254'EBB'#178

+  +'CCC9UUU'#6#0#0#0#0#0#0#0#0#0#0#0#0'JAA'#31'\1'#29#249#140'P2'#255#190#135'\'

+  +#255#196#143'c'#255#196#143'c'#255#196#143'c'#255#196#143'c'#255#196#143'c'

+  ,#255#196#143'c'#255'>-'#31#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'&'#28#19#255#196#143

+  +'c'#255#196#143'c'#255#196#143'c'#255#25#18#12#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#2#1#255'*'#31#21#255'kM6'

+  +#255#187#137'_'#255#196#143'c'#255#196#143'c'#255#196#143'c'#255#196#143'c'

+  +#255#196#143'c'#255#196#143'c'#255#196#143'c'#255#196#143'c'#255#196#143'c'

+  +#255#196#143'c'#255#194#141'b'#255#170'kF'#255'\0'#28#254'L<5'#203'CCCH333'

+  +#10#0#0#0#0#0#0#0#0#0#0#0#1'K3+@[/'#27#255#160'`>'#255#190#136'_'#255#191#137

+  +'`'#255#191#137'`'#255#191#137'`'#255#191#137'`'#255#191#137'`'#255#189#135

+  +'`'#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#30#21#15#255#191#137'`'#255#191#137

+  +'`'#255#191#137'`'#255'aF1'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#5#3#2#255#165'vS'#255#191#137'`'#255#191#137'`'#255#191

+  +#137'`'#255#191#137'`'#255#191#137'`'#255#191#137'`'#255#191#137'`'#255#191

+  +#137'`'#255#191#137'`'#255#191#137'`'#255#191#137'`'#255#191#137'`'#255#191

+  +#137'`'#255#191#136'`'#255#178'vQ'#255'h7 '#253'Q8,'#220'DDDV;;;'#13#0#0#0#0

+  +#0#0#0#0'UUU'#3'R4''^[/'#27#255#169'hF'#255#187#131']'#255#187#132'^'#255#187

+  +#132'^'#255#187#132'^'#255#187#132'^'#255#187#132'^'#255'uS;'#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255'{W>'#255#187#132'^'#255#187#132'^'#255#187#132'^'

+  +#255#185#130'^'#255#19#14#10#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#1#1#1#255#158'oO'#255#187#132'^'#255#187#132'^'#255#187#132'^'#255#187#132

+  +'^'#255#187#132'^'#255#187#132'^'#255#187#132'^'#255#187#132'^'#255#187#132

+  +'^'#255#187#132'^'#255#187#132'^'#255#187#132'^'#255#187#132'^'#255#187#132

+  +'^'#255#187#132'^'#255#181'{V'#255'r<"'#255'T6'''#228'BBBd@@@'#16#0#0#0#0#0#0

+  +#0#0'UUU'#6'T5''}_2'#30#253#171'kI'#255#183'}Z'#255#183'~Z'#255#183'~Z'#255

+  +#183'~Z'#255#183'~Z'#255#183'~Z'#255'. '#23#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255'S9)'

+  +#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#173'xV'#255

+  +#31#21#15#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'bC0'#255#183'~Z'#255#183'~Z'

+  +#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255

+  +#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183'~Z'#255#183

+  +'~Z'#255#183'~Z'#255#181'zV'#255'zA%'#255'X4$'#237'DDDqCCC'#19#0#0#0#0#0#0#0

+  +#0'@@@'#8'U4%'#149'f5'#31#252#172'mK'#255#180'yX'#255#180'yX'#255#180'yX'#255

+  +#180'yX'#255#180'yX'#255#180'yX'#255#6#4#3#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#19#13#9#255#153'gK'#255

+  +#180'yX'#255#180'yX'#255#180'yX'#255#180'yX'#255#180'yX'#255#180'yX'#255#180

+  +'yX'#255#180'yX'#255'{S<'#255'+'#29#21#255#7#4#3#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255'gF3'#255#180'yX'#255#180'yX'

+  +#255#180'yX'#255#139']D'#255'+'#29#21#255#8#6#4#255#8#6#4#255#16#11#8#255'W:'

+  +'*'#255#178'wV'#255#180'yX'#255#180'yX'#255#180'yX'#255#180'yX'#255#180'yX'

+  +#255#180'yX'#255#180'yX'#255#179'yV'#255#131'F+'#255'[3!'#245'CCCyIII'#21#0#0

+  +#0#0#0#0#0#0'UUU'#6'X3"'#165'n:"'#253#172'pO'#255#177'wW'#255#177'wW'#255#177

+  +'wW'#255#177'wW'#255#177'wW'#255#173'uU'#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255'P6'''#255#177'wW'#255#177'w'

+  +'W'#255#177'wW'#255#177'wW'#255#177'wW'#255#177'wW'#255#177'wW'#255#177'wW'

+  +#255#177'wW'#255#177'wW'#255#177'wW'#255#177'wW'#255#177'wW'#255#158'jM'#255

+  +'W;+'#255''''#26#19#255'"'#23#17#255'%'#25#18#255'W:+'#255#167'qS'#255#177'w'

+  +'W'#255#177'wW'#255#177'wW'#255'@+'#31#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#3#2#1#255#149'dI'#255#177'wW'#255#177'wW'#255#177

+  +'wW'#255#177'wW'#255#177'wW'#255#177'wW'#255#177'vV'#255#139'M0'#255'[1'#30

+  +#250'DDDpCCC'#19#0#0#0#0#0#0#0#0'UUU'#3'Y1'#31#182'v>%'#255#172'oQ'#255#175

+  +'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255'}S?'#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#26#17#13#255#150'cK'#255#175

+  +'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'

+  +#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255

+  +#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175

+  +'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255'dC2'#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#9#6#4#255#169'pU'

+  +#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#174'sU'#255

+  ,#145'S6'#255']0'#28#254'DBBd@@@'#16#0#0#0#0#0#0#0#0#0#0#0#0'Z0'#30#175'v=%'

+  +#255#171'nP'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255

+  +'L2&'#255#0#0#0#255'/'#31#23#255'}R>'#255' '#21#16#255'!'#22#17#255#139'[E'

+  +#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255

+  +#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174

+  +'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'

+  +#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255

+  +'?*'#31#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255'6#'#27#255#174'rV'#255#174'rV'#255#174'rV'#255#174

+  +'rV'#255#174'rV'#255#173'qT'#255#145'S7'#255'\1'#29#254'AAAV;;;'#13#0#0#0#0#0

+  +#0#0#0#0#0#0#0'Z1'#30#150'n;$'#252#169'jM'#255#172'qU'#255#172'qU'#255#172'q'

+  +'U'#255#172'qU'#255#172'qU'#255#149'bI'#255'@* '#255#170'qU'#255#172'qU'#255

+  +#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172

+  +'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'

+  +#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255

+  +#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172

+  +'qU'#255#172'qU'#255#172'qU'#255'G/#'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#24#16#12#255#172'qU'

+  +#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#171'oS'#255#138'N3'#255

+  +'\2'#31#249'DDDG999'#9#0#0#0#0#0#0#0#0#0#0#0#0'X1!|g7#'#250#167'gI'#255#172

+  +'pT'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'

+  +#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255

+  +#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255'P5('#255')'#27#20#255#27#18

+  +#13#255'5#'#26#255'pJ8'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255

+  +#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172

+  +'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#162'jO'#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#9#6#4#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'#255#172'qU'

+  +#255#170'mR'#255#131'I.'#255'[4"'#241'FFF7UUU'#6#0#0#0#0#0#0#0#0#0#0#0#0'Y1!'

+  +'`b5 '#251#164'cG'#255#172'pU'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'r'

+  +'W'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'

+  +#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255'}S?'#255#9#6#5#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#16#11#8#255#152'dM'#255#173'rW'

+  +#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255

+  +#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173'rW'#255#173

+  +'rW'#255'$'#24#18#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#4#3#2#255#173'rW'#255#173'rW'#255#173'rW'#255#173'r'

+  +'W'#255#173'rW'#255#170'mQ'#255'|C*'#255'W4$'#229'CCC&'#0#0#0#2#0#0#0#0#0#0#0

+  +#0#0#0#0#0'X5!A^2'#31#254#162'bE'#255#173'rV'#255#175'tY'#255#175'tY'#255#175

+  +'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'

+  +#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255'{Q?'#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#14#9#7#255

+  +#173'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175

+  +'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'#255#175'tY'

+  +#255#175'tY'#255#132'XC'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#21#14#11#255#175'tY'#255#175'tY'#255#175

+  +'tY'#255#175'tY'#255#174'tY'#255#170'mP'#255't?('#254'U5&'#203'@@@'#24#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0'X0'#24' ^2'#31#255#156'\A'#255#175'v\'#255#177'y`'

+  +#255#177'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255

+  +#177'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255#11#8

+  +#6#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#136']J'#255#177'y`'#255#177'y`'#255'7%'#30#255#9#6#5#255

+  +#13#9#7#255#16#11#9#255#26#18#14#255#139'_K'#255#177'y`'#255#177'y`'#255#177

+  +'y`'#255#177'y`'#255#177'y`'#255#177'y`'#255#18#12#9#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'<)!'#255#177'y`'#255#177

+  +'y`'#255#177'y`'#255#177'y`'#255#176'x^'#255#169'kP'#255'j<&'#253'U4%'#168';'

+  +';;'#13#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'^2'#29#234#136'O4'#255#176'x'

+  +'^'#255#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'

+  +#255#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'#255

+  +#146'gS'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#139'bO'#255#170'x`'#255#20#14#11#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255']A4'#255#180'~f'#255

+  +#180'~f'#255#180'~f'#255#180'~f'#255#180'~f'#255'qO@'#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255#165't^'#255#180'~f'#255

+  ,#180'~f'#255#180'~f'#255#180'~f'#255#178'zb'#255#162'dH'#255'_3'#31#254'R6)c'

+  +'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#29#153'r?)'#252#174'sZ'

+  +#255#182#129'j'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183#131'l'

+  +#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183#131'l'

+  +#255#183#131'l'#255#183#131'l'#255'ZA5'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#5#3#3#255#179'j'

+  +#255'uTE'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255'{XI'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183

+  +#131'l'#255#183#131'l'#255#20#15#12#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255':)"'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183#131

+  +'l'#255#183#131'l'#255#179'|c'#255#140'R9'#255'\2'#31#248'@@6'#28#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#29'E`5 '#252#166'iO'#255#183#131'l'

+  +#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#186#136'q'

+  +#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#186#136'q'

+  +#255#186#136'q'#255'\D8'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'oQC'#255#186#136'q'#255'X@6'#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#12#9#7#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#186#136'q'#255

+  +#186#136'q'#255#148'lZ'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#169'|g'#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#186#136'q'#255#185

+  +#134'q'#255#177'y`'#255'tB+'#254'W2!'#194'III'#14#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0'@@'#0#4'^3'#30#245#144'W='#255#184#134'o'#255#189#141'x'

+  +#255#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141'x'

+  +#255#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141'x'

+  +#255'tWJ'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255'('#30#26#255#189#141'x'#255#189#141'x'#255'?/('#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#187#139'v'#255#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141

+  +'x'#255#189#141'x'#255#172#128'm'#255'_G<'#255#1#0#0#255#0#0#0#255'-"'#28#255

+  +#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141'x'#255#189#141'x'#255

+  +#186#137's'#255#171'oU'#255'a6"'#253'T5$jUUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0'\/'#27#170'vD,'#252#181#128'h'#255#190#144'{'#255

+  +#192#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255

+  +#192#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255

+  +#186#142'z'#255#1#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#2#1#1#255#186#142'z'#255#192#146'~'#255#192#146'~'#255'=.('#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#192

+  +#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#0#0#0#255#0#0#0#255

+  +#167'n'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#192#146'~'#255#191

+  +#145'}'#255#186#137's'#255#149'[A'#255'^1'#31#250'F:.'#22#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'\.'#28'H`5 '#252#164'jP'#255#190

+  +#143'z'#255#194#151#131#255#194#151#131#255#194#151#131#255#194#151#131#255

+  +#194#151#131#255#194#151#131#255#194#151#131#255#194#151#131#255#194#151#131

+  +#255#194#151#131#255#194#151#131#255#27#21#18#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255' '#25#21#255#194#151#131#255#194#151#131

+  +#255#194#151#131#255'7*%'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#12#9#8#255#194#151#131#255#194#151#131#255

+  +#194#151#131#255#194#151#131#255#194#151#131#255#194#151#131#255#194#151#131

+  +#255#190#149#129#255#0#0#0#255'0% '#255#194#151#131#255#194#151#131#255#194

+  +#151#131#255#194#151#131#255#194#151#131#255#192#147''#255#180'~f'#255'q@+'

+  +#252'Z0'#29#180#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0']0'#28#199'{H2'#252#184#134'o'#255#196#153#134#255#197#156

+  +#137#255#197#156#137#255#197#156#137#255#197#156#137#255#197#156#137#255#197

+  +#156#137#255#197#156#137#255#197#156#137#255#197#156#137#255#197#156#137#255

+  +'G81'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'WE='

+  +#255#197#156#137#255#197#156#137#255#191#152#133#255#1#1#1#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#135'k^'

+  +#255#197#156#137#255#197#156#137#255#197#156#137#255#197#156#137#255#197#156

+  +#137#255#197#156#137#255#197#156#137#255#197#156#137#255#16#12#11#255#174#138

+  +'y'#255#197#156#137#255#197#156#137#255#197#156#137#255#197#156#137#255#197

+  +#155#136#255#191#145'|'#255#151'_F'#255'^3'#31#253'T2!-'#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[0'#29'5_4 '#254

+  +#161'hP'#255#195#152#132#255#200#161#143#255#200#161#144#255#200#161#144#255

+  ,#200#161#144#255#200#161#144#255#200#161#144#255#200#161#144#255#200#161#144

+  +#255#200#161#144#255#200#161#144#255'xaW'#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#1#1#1#255#171#138'{'#255#200#161#144#255#200#161#144#255

+  +'f\'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255')!'#30#255#200#161#144#255#200#161#144#255#200#161#144#255#200

+  +#161#144#255#200#161#144#255#200#161#144#255#200#161#144#255#200#161#144#255

+  +#200#161#144#255#153'{n'#255#200#161#144#255#200#161#144#255#200#161#144#255

+  +#200#161#144#255#200#161#144#255#198#156#138#255#181#128'h'#255'l>*'#252'Z1'

+  +#30#159#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0'^0'#27#173'uE/'#249#186#136'r'#255#201#162#145#255

+  +#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150

+  +#255#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150#255#163#132

+  +'x'#255#0#0#0#255#0#0#0#255#26#21#19#255',$!'#255'-%!'#255#156'~s'#255#203

+  +#165#150#255#203#165#150#255#203#165#150#255'@4/'#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#4#3#3#255#186#151#138#255#203

+  +#165#150#255#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150#255

+  +#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150

+  +#255#203#165#150#255#203#165#150#255#203#165#150#255#203#165#150#255#203#164

+  +#149#255#195#152#132#255#146'\D'#255'_3'#31#247'R3'#30#25#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +'Z-'#30'"^4 '#252#155'cK'#255#196#153#136#255#206#169#155#255#207#171#156#255

+  +#207#171#156#255#207#171#156#255#207#171#156#255#207#171#156#255#207#171#156

+  +#255#207#171#156#255#207#171#156#255#203#167#152#255#0#0#0#255#0#0#0#255#193

+  +#159#145#255#207#171#156#255#207#171#156#255#207#171#156#255#207#171#156#255

+  +#207#171#156#255#207#171#156#255'E94'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#15#12#11#255#182#150#137#255#207#171#156#255#207#171

+  +#156#255#207#171#156#255#207#171#156#255#207#171#156#255#207#171#156#255#207

+  +#171#156#255#207#171#156#255#207#171#156#255#207#171#156#255#207#171#156#255

+  +#207#171#156#255#207#171#156#255#207#171#156#255#206#170#155#255#201#162#145

+  +#255#178'}f'#255'h<('#250'[0'#28#129#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0']1'

+  +#29#130'f:&'#250#171'u^'#255#202#164#148#255#210#176#163#255#210#177#164#255

+  +#210#177#164#255#210#177#164#255#210#177#164#255#210#177#164#255#210#177#164

+  +#255#210#177#164#255#210#177#164#255#2#1#1#255#27#22#21#255#210#177#164#255

+  +#210#177#164#255#210#177#164#255#210#177#164#255#210#177#164#255#210#177#164

+  +#255#210#177#164#255#210#177#164#255'I=8'#255#6#5#4#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255'''!'#31#255#206#175#162#255#210#177#164#255#210#177#164#255#210#177

+  +#164#255#210#177#164#255#210#177#164#255#210#177#164#255#210#177#164#255#210

+  +#177#164#255#210#177#164#255#210#177#164#255#210#177#164#255#210#177#164#255

+  +#210#177#164#255#210#177#164#255#210#176#163#255#206#170#155#255#188#139'w'

+  +#255'zI4'#252'^2'#29#222']/'#23#11#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#1'^1'#29#181'oA-'#249#182#132'n'#255#208#173#159#255#213#182#169#255#213#183

+  +#170#255#213#183#170#255#213#183#170#255#213#183#170#255#213#183#170#255#213

+  +#183#170#255#213#183#170#255#12#10#9#255#159#136''#255#213#183#170#255#213

+  +#183#170#255#213#183#170#255#213#183#170#255#213#183#170#255#213#183#170#255

+  +#213#183#170#255#213#183#170#255#213#183#170#255#139'xo'#255#0#0#0#255#0#0#0

+  +#255'% '#30#255#213#183#170#255#213#183#170#255#213#183#170#255#213#183#170

+  +#255#213#183#170#255#213#183#170#255#213#183#170#255#213#183#170#255#213#183

+  +#170#255#213#183#170#255#213#183#170#255#213#183#170#255#213#183#170#255#213

+  +#183#170#255#213#183#170#255#213#183#170#255#211#178#165#255#196#152#134#255

+  +#136'T?'#254'`1 '#243'U+'#28'$'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0'U+'#21#12']2'#30#218'zK5'#251#192#146''#255#212#180#168#255#216#187

+  +#176#255#217#188#177#255#217#188#177#255#217#188#177#255#217#188#177#255#217

+  +#188#177#255#217#188#177#255'o`Z'#255#217#188#177#255#217#188#177#255#217#188

+  +#177#255#217#188#177#255#217#188#177#255#217#188#177#255#217#188#177#255#217

+  +#188#177#255#217#188#177#255#217#188#177#255#27#24#22#255#0#0#0#255#9#8#7#255

+  +#209#180#171#255#217#188#177#255#217#188#177#255#217#188#177#255#217#188#177

+  +#255#217#188#177#255#217#188#177#255#217#188#177#255#217#188#177#255#217#188

+  +#177#255#217#188#177#255#217#188#177#255#217#188#177#255#217#188#177#255#217

+  +#188#177#255#217#188#177#255#215#185#173#255#202#163#147#255#152'cM'#255'`5 '

+  +#252'X.'#27'B'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0'].'#23'!_3 '#241#135'V@'#254#197#155#137#255#215#185#173#255#219#193

+  +#183#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220

+  +#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255

+  +#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184

+  +#255#220#194#184#255#220#194#184#255#4#4#4#255#13#11#11#255#197#173#164#255

+  +#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184

+  +#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194

+  +#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220#194#184#255#220

+  +#194#183#255#218#190#179#255#205#169#154#255#165'pY'#255'b8$'#252'[/'#27'h'#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0'Y1'#28'?_3!'#249#132'T?'#252#193#148#130#255#215#186#174#255#223#198

+  +#189#255#223#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255#223

+  +#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255

+  +#223#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255#223#200#191

+  +#255#223#200#191#255#199#179#171#255#215#192#183#255#223#200#191#255#223#200

+  +#191#255#223#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255#223

+  +#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255#223#200#191#255

+  +#223#200#191#255#223#200#191#255#223#200#191#255#223#199#190#255#219#192#183

+  +#255#203#165#150#255#158'kS'#255'c9%'#251']0'#30#147#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +'Z-'#25'3_3'#30#234'wI5'#250#185#138'v'#255#215#186#174#255#225#203#194#255

+  +#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197

+  +#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205

+  +#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227

+  +#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255

+  +#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197

+  +#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205#197#255#227#205

+  +#197#255#226#204#196#255#220#194#183#255#200#159#143#255#144'_H'#254'a6"'#253

+  +'\1'#30'y'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'\3'#31#25'^2'#29#207'nB.'

+  +#249#175'~i'#255#213#182#169#255#225#202#193#255#230#209#203#255#230#211#205

+  +#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211

+  +#205#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211#205#255#230

+  +#211#205#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211#205#255

+  +#230#211#205#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211#205

+  +#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211#205#255#230#211

+  +#205#255#230#210#204#255#227#205#198#255#219#191#181#255#193#149#131#255#131

+  +'R='#251'_4 '#247'Z0'#26'O'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0'`  '#8']0'#28#169'e:'''#250#148'aL'#255#196#153#136#255#220#193#183

+  +#255#229#209#202#255#233#216#210#255#234#216#211#255#234#216#211#255#234#216

+  +#211#255#234#216#211#255#234#216#211#255#234#216#211#255#234#216#211#255#234

+  +#216#211#255#234#216#211#255#234#216#211#255#234#216#211#255#234#216#211#255

+  +#234#216#211#255#234#216#211#255#234#216#211#255#234#216#211#255#234#216#211

+  +#255#234#216#211#255#234#216#211#255#234#216#211#255#234#216#211#255#233#216

+  +#211#255#231#212#206#255#224#200#192#255#207#171#156#255#168'va'#255'rE1'#249

+  +'^3'#31#230'Y,'#28'.'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0'^1'#29'h`3'#31#237'nA/'#249#158'mW'#255#203#165#150

+  +#255#224#201#192#255#232#213#208#255#235#219#215#255#237#222#218#255#237#222

+  +#218#255#237#222#218#255#237#222#218#255#237#222#218#255#237#222#218#255#237

+  +#222#218#255#237#222#218#255#237#222#218#255#237#222#218#255#237#222#218#255

+  +#237#222#218#255#237#222#218#255#237#222#218#255#237#222#218#255#237#222#218

+  +#255#237#222#218#255#236#220#216#255#233#216#211#255#228#206#200#255#213#182

+  +#170#255#177#131'n'#255'}M:'#250'a6"'#253']1'#29#155'U1'#24#21#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0'].'#23#11']1'#29'~`5!'#246'tF5'#249#166'u`'#255#202#164#148#255#221

+  ,#195#186#255#230#210#203#255#234#218#213#255#238#224#220#255#240#227#224#255

+  +#240#227#225#255#240#227#225#255#240#227#225#255#240#227#225#255#240#227#225

+  +#255#240#227#225#255#240#227#225#255#240#227#225#255#240#227#225#255#240#227

+  +#225#255#239#225#222#255#236#220#215#255#232#213#207#255#225#203#194#255#210

+  +#176#164#255#183#138'u'#255#133'UA'#252'c9&'#254'^2'#30#178'\.'#26''''#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'U1'#24#21']0'#30#147'`7"'#251

+  +'jA-'#249#133'UA'#253#169'zf'#255#201#162#146#255#220#194#184#255#230#211#205

+  +#255#233#215#210#255#234#217#212#255#236#220#215#255#237#222#218#255#238#223

+  +#220#255#237#222#219#255#236#220#216#255#234#219#213#255#233#216#211#255#231

+  +#213#206#255#225#203#194#255#209#174#160#255#181#136'u'#255#145'`L'#255'sG4'

+  +#249'c9&'#255'_2'#30#198'].'#28'7'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'U+'#28#18'\.'#27'^_1'#30#179'c7$'

+  +#248'h?,'#251'Q;'#251#148'dN'#255#163't_'#255#175#129'n'#255#186#143'~'#255

+  +#198#157#141#255#204#167#151#255#201#161#145#255#191#149#132#255#179#135'u'

+  +#255#167'ye'#255#153'iT'#255#136'WC'#254'pE2'#249'c9&'#255'_3'#31#212'Z/'#27

+  +'|].'#29','#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'U9'#28#9'\.'#26'N'

+  +'^0'#29#157'`4 '#203'c6#'#230'c7%'#249'd:('#255'f=*'#255'i?-'#252'g>+'#255'e'

+  +';('#255'd9&'#253'b7$'#237'a5!'#214'_1'#30#180'\/'#26'lX,'#26#29#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'`0 '#16'[1'#24'*].'#27'B]1'#29'4\3'#31#25'U'

+  +'U'#0#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255

+  +#255#248#15#255#255#255#255#255#254#0#0''#255#255#255#255#240#0#0#7#255#255

+  +#255#255#192#0#0#1#255#255#255#255#0#0#0#0#255#255#255#252#0#0#0#0'?'#255#255

+  +#248#0#0#0#0#31#255#255#240#0#0#0#0#7#255#255#192#0#0#0#0#3#255#255#128#0#0#0

+  +#0#1#255#255#128#0#0#0#0#0#255#255#0#0#0#0#0#0''#254#0#0#0#0#0#0''#252#0#0

+  +#0#0#0#0'?'#252#0#0#0#0#0#0#31#248#0#0#0#0#0#0#31#248#0#0#0#0#0#0#15#240#0#0

+  +#0#0#0#0#15#240#0#0#0#0#0#0#7#224#0#0#0#0#0#0#7#224#0#0#0#0#0#0#7#224#0#0#0#0

+  +#0#0#3#192#0#0#0#0#0#0#3#192#0#0#0#0#0#0#3#192#0#0#0#0#0#0#1#192#0#0#0#0#0#0

+  +#1#192#0#0#0#0#0#0#1#128#0#0#0#0#0#0#1#128#0#0#0#0#0#0#1#128#0#0#0#0#0#0#1

+  +#128#0#0#0#0#0#0#1#128#0#0#0#0#0#0#1#128#0#0#0#0#0#0#1#192#0#0#0#0#0#0#1#192

+  +#0#0#0#0#0#0#1#192#0#0#0#0#0#0#1#192#0#0#0#0#0#0#1#192#0#0#0#0#0#0#3#192#0#0

+  +#0#0#0#0#3#224#0#0#0#0#0#0#3#224#0#0#0#0#0#0#7#224#0#0#0#0#0#0#7#224#0#0#0#0

+  +#0#0#7#240#0#0#0#0#0#0#15#240#0#0#0#0#0#0#15#248#0#0#0#0#0#0#31#248#0#0#0#0#0

+  +#0#31#252#0#0#0#0#0#0'?'#252#0#0#0#0#0#0''#254#0#0#0#0#0#0''#254#0#0#0#0#0

+  +#0#255#255#0#0#0#0#0#1#255#255#128#0#0#0#0#3#255#255#192#0#0#0#0#7#255#255

+  +#224#0#0#0#0#15#255#255#240#0#0#0#0#31#255#255#248#0#0#0#0'?'#255#255#254#0#0

+  +#0#0''#255#255#255#0#0#0#1#255#255#255#255#192#0#0#7#255#255#255#255#240#0#0

+  +#31#255#255#255#255#254#0#0#255#255#255#255#255#255#248#31#255#255#255#255

+  +#255#255#255#255#255#255#255'('#0#0#0'0'#0#0#0'`'#0#0#0#1#0' '#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'333'#5'UUU'#6'III'#7'@@@'#8'@@@'

+  +#8'III'#7'UUU'#6'333'#5'UUU'#3#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#1'@@@'#4'@@@'#8'@@@'#16'DDD1BBBMCCC_FCCrDBB'#129'FDD'#133'CCCvCCCcDDDRD'

+  +'DD<FFF'#22'333'#10'333'#5#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'III'#7'FFF'#22'CCCEDAA|CCB'#173'FEC'

+  +#194'IGC'#198'KE?'#204'QD:'#211'TC4'#218'SD6'#216'OD<'#209'JD@'#201'HGD'#197

+  +'FEC'#195'DDC'#184'DDD'#139'EEEUDDD"999'#9#0#0#0#2#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#1'+++'#6'FFF'#22'BBBaDDC'#175'JEA'#198'TB5'#218'a>('#240

+  +'l@!'#252'qE!'#253'yJ$'#252#129'R&'#252#138'X)'#253#134'T('#253'}N%'#252'uG#'

+  +#252'oC"'#253'h=#'#248'Z>.'#230'OC;'#211'FEC'#198'DDC'#187'BBB|CCC&999'#9#0#0

+  +#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#2'<<<'#17'CCCWEED'#170'OB9'#211'd=&'#244'qE"'#253

+  +#137'V)'#253#164'h.'#255#186'y3'#255#194#130'5'#255#198#135'6'#255#203#140'7'

+  +#255#207#145'8'#255#205#143'7'#255#201#137'7'#255#196#132'6'#255#192'5'#255

+  +#177'r1'#255#152'_+'#254'{L%'#252'k?"'#251'[>-'#233'IEA'#203'EDD'#184'DDDq<<'

+  +'<'#30'@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0'@@@'#4'BBB#EDD'#146'KB<'#205'a='''#242'yK&'#252#166'i/'#255#192

+  +#128'6'#255#205#143'9'#255#217#159'<'#255#226#169'>'#255#230#173'>'#255#232

+  +#176'>'#255#235#180'?'#255#237#182'@'#255#236#181'?'#255#234#178'>'#255#231

+  +#175'>'#255#228#171'>'#255#223#165'<'#255#211#150':'#255#199#136'8'#255#182

+  +'v5'#255#146'\,'#253'k@"'#252'W?1'#227'GFE'#199'CCC'#171'???=@@@'#8#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'III'#7'DDD8ECB'#170'[>,'

+  +#234'sF$'#252#160'e0'#255#196#133';'#255#216#158'@'#255#227#170'A'#255#234

+  +#180'C'#255#241#189'D'#255#245#193'E'#255#246#195'F'#255#247#195'F'#255#247

+  +#196'E'#255#248#197'F'#255#248#197'E'#255#247#195'F'#255#247#194'F'#255#246

+  +#194'E'#255#244#192'E'#255#238#184'C'#255#230#176'C'#255#223#166'A'#255#207

+  +#147'='#255#182'w7'#255#138'V+'#253'h>#'#250'NA9'#215'CCC'#186'@@@[;;;'#13#0

+  +#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'#8'EEENGC?'#189'b;%'#245#139

+  +'W-'#253#190';'#255#212#153'B'#255#227#172'F'#255#239#186'I'#255#242#191'J'

+  +#255#244#193'K'#255#246#195'K'#255#247#196'K'#255#247#196'K'#255#247#196'L'

+  +#255#247#196'L'#255#247#196'L'#255#247#196'L'#255#247#196'L'#255#247#196'K'

+  +#255#247#196'K'#255#246#196'K'#255#245#195'J'#255#243#193'J'#255#242#190'J'

+  +#255#234#180'H'#255#221#165'E'#255#202#142'@'#255#173'o5'#255'oC$'#252'T?3'

+  +#225'CCC'#193'AAAy@@@'#16#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'+++'#6'DDD@K@<'#198'g<"'

+  +#250#154'a2'#254#200#141'B'#255#222#168'J'#255#234#183'N'#255#239#189'P'#255

+  +#242#192'P'#255#242#193'P'#255#243#193'P'#255#243#193'P'#255#243#193'P'#255

+  +#243#193'P'#255#243#193'P'#255#243#193'P'#255#243#193'P'#255#243#193'P'#255

+  +#243#193'P'#255#243#193'P'#255#243#193'P'#255#243#193'P'#255#243#193'P'#255

+  +#242#193'P'#255#242#193'P'#255#241#191'P'#255#238#187'N'#255#229#176'L'#255

+  +#214#158'G'#255#183'y;'#255'yJ)'#252'[=,'#236'CCB'#195'EEEoFFF'#11#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0'UUU'#3'CCC.J?;'#190'g=#'#252#167'k7'#255#205#147'H'#255#226#173'P'#255#235

+  +#186'T'#255#238#189'T'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239

+  +#190'U'#255#239#190'U'#255#239#190'U'#255#191#152'D'#255'A4'#23#255'>1'#22

+  +#255'D6'#24#255'H9'#26#255'RA'#29#255#146's4'#255#228#182'Q'#255#239#190'U'

+  +#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#239#190'U'#255#238#190'U'

+  +#255#237#187'T'#255#232#182'S'#255#217#162'M'#255#191#129'B'#255#132'R-'#253

+  +'[9('#240'DDD'#191'CCCW@@@'#8#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'>>>'#29'F@='#169'd9#'#250#165'i8'#255#208

+  +#151'L'#255#226#174'U'#255#233#184'Y'#255#235#186'Y'#255#235#187'Y'#255#235

+  +#187'Y'#255#235#187'Y'#255#235#187'Y'#255#235#187'Y'#255#235#187'Y'#255'<0'

+  +#23#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255

+  ,#0#0#0#255#6#5#2#255'*!'#16#255'w^-'#255#227#181'W'#255#235#187'Y'#255#235

+  +#187'Y'#255#235#186'Y'#255#234#186'Y'#255#231#181'X'#255#218#164'Q'#255#194

+  +#133'E'#255'{J*'#252'U=/'#230'CCC'#186'EEE?@@@'#4#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'333'#10'DAAw_9%'#244#150'^4'#254#204#148

+  +'N'#255#225#175'Y'#255#230#181'\'#255#231#183'\'#255#231#183'\'#255#231#183

+  +'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255#231#183'\'#255'hR*'#255

+  +#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255#1#1#0#255'*!'#17#255#164#130'B'

+  +#255#231#183'\'#255#231#183'\'#255#231#182']'#255#228#179'['#255#217#165'V'

+  +#255#185'|C'#255'nA'''#252'N>5'#219'CCC'#163'@@@'#20#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#128#128#128#2'@@@,W8*'#227#132'P/'#253#196

+  +#139'M'#255#220#170'['#255#226#179'_'#255#227#179'_'#255#227#179'_'#255#227

+  +#179'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227#179'_'#255#227

+  +#179'_'#255#4#3#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#1#1#0#255#7#6#3#255#178#141'J'#255#227#179'_'#255#227#179'_'#255#225

+  +#176'^'#255#211#158'U'#255#174'q?'#255'c9"'#252'GA>'#203'BBB]III'#7#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'FFF'#11'H>:'#150'e:#'#252#186'~H'#255

+  +#214#164'\'#255#222#174'a'#255#223#175'b'#255#223#175'b'#255#223#175'b'#255

+  +#223#175'b'#255#223#175'b'#255#223#175'b'#255#223#175'b'#255#223#175'b'#255

+  +#188#148'S'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#154'yC'#255#223#175'b'#255#223

+  +#175'a'#255#220#171'`'#255#204#150'U'#255#145'Y5'#254'Y8('#238'CCC'#175'FFF'

+  +#29#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'UUU'#3'AAA3Z7'''#236#148'\6'#255

+  +#207#154'Z'#255#218#170'b'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255

+  +#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255#219#171'd'#255

+  +#219#171'd'#255#211#165'`'#255#6#5#3#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2#2#1#255#219#171

+  +'d'#255#219#171'd'#255#219#171'd'#255#215#166'`'#255#189#129'M'#255'h=$'#252

+  +'H>;'#207'EEEhIII'#7#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'III'#7'K<5'#137'h;$'#252

+  +#188#130'O'#255#213#164'b'#255#215#167'd'#255#215#167'd'#255#215#167'd'#255

+  +#215#167'd'#255#215#167'd'#255#215#167'd'#255#215#167'd'#255#215#167'd'#255

+  +#215#167'd'#255#215#167'd'#255#215#167'd'#255#168#130'N'#255#1#1#1#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#200#155']'#255#215#167'd'#255#215#167'd'#255#215#166'd'#255

+  +#205#153']'#255#153'`:'#255'[6$'#243'CCC'#164';;;'#13#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0'777'#14'Z5%'#229#150'[8'#255#203#150'^'#255#211#162'e'#255#211#162

+  +'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162

+  +'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162'e'#255#211#162

+  +'e'#255#211#162'e'#255#142'mD'#255#1#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255#145'pF'#255#211#162'e'

+  +#255#211#162'e'#255#211#162'e'#255#210#159'd'#255#189#131'R'#255'f9#'#252'I@'

+  +';'#202'===.'#128#128#128#2#0#0#0#0#0#0#0#0#128#128#128#2'D??4]3'#30#252#181

+  +'yM'#255#206#155'd'#255#207#157'f'#255#207#157'f'#255#207#157'f'#255#207#157

+  +'f'#255#205#155'f'#255'S?('#255#1#1#1#255#1#0#0#255#3#2#1#255#15#11#7#255#169

+  +#128'S'#255#207#157'f'#255#207#157'f'#255#207#157'f'#255#16#12#8#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0

+  +#255#186#141'\'#255#207#157'f'#255#207#157'f'#255#207#157'f'#255#207#157'e'

+  +#255#201#148'`'#255#135'O0'#254'R9-'#226'BBBeIII'#7#0#0#0#0#0#0#0#0'UUU'#6'O'

+  +'8/'#141'o>'''#251#193#139'['#255#203#151'e'#255#203#152'e'#255#203#152'e'

+  +#255#203#152'e'#255#203#152'e'#255#23#17#11#255#1#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#1#1#1#255#153'rL'#255#203#152'e'#255#203#152'e'#255',!'

+  +#22#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0

+  +#255' '#24#16#255#203#152'e'#255#203#152'e'#255#203#152'e'#255#203#152'e'#255

+  +#203#152'e'#255#202#150'd'#255#165'jC'#255'\3!'#247'DDD'#151'MMM'#10#0#0#0#0

+  +#0#0#0#0'@@@'#8'Z6%'#206#142'T5'#255#195#142'a'#255#198#145'c'#255#198#145'c'

+  +#255#198#145'c'#255#198#145'c'#255'W@,'#255#1#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255'%'#27#19#255#198#145'c'#255#198#145'c'

+  ,#255'U>+'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255#1#1#1#255#27#20#13

+  +#255'vW;'#255#198#145'c'#255#198#145'c'#255#198#145'c'#255#198#145'c'#255#198

+  +#145'c'#255#198#145'c'#255#198#145'c'#255#184'}S'#255'`4 '#252'FA>'#183'@@@'

+  +#12#0#0#0#0#0#0#0#0'999'#9']2'#30#243#166'gD'#255#192#138'`'#255#192#139'a'

+  +#255#192#139'a'#255#192#139'a'#255#190#137'a'#255#1#1#1#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#8#6#4#255#192#139'a'

+  +#255#192#139'a'#255#129']B'#255#1#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255'Q;)'#255#192

+  +#139'a'#255#192#139'a'#255#192#139'a'#255#192#139'a'#255#192#139'a'#255#192

+  +#139'a'#255#192#139'a'#255#192#139'a'#255#192#139'a'#255#192#139'a'#255#188

+  +#132'['#255'u@'''#252'M;3'#212'999'#18#0#0#0#0#0#0#0#0'FFF'#11'^1'#29#250#174

+  +'oK'#255#186#131'\'#255#186#131'\'#255#186#131'\'#255#186#131'\'#255'vS:'#255

+  +#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0

+  +#255'S:)'#255#186#131'\'#255#186#131'\'#255#184#129'\'#255'('#28#20#255#1#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255'Q9('#255#186#131'\'#255#186#131'\'#255#186#131'\'#255#186#131'\'#255

+  +#186#131'\'#255#186#131'\'#255#186#131'\'#255#186#131'\'#255#186#131'\'#255

+  +#186#131'\'#255#186#131'\'#255#186#130'['#255#131'I-'#255'Q9-'#221'FFF!'#0#0

+  +#0#1#0#0#0#0'M33'#20'_2'#30#251#173'pN'#255#180'{X'#255#180'{X'#255#180'{X'

+  +#255#180'{X'#255'-'#30#22#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#2#1#1#255'dE1'#255#180'{X'#255#180'{X'#255#180'{X'#255#180'{X'

+  +#255#180'{X'#255'O6&'#255#2#1#1#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255'G0#'#255#180'{X'#255#180'{X'#255#178'{X'#255'hH3'#255'U:)'

+  +#255'mK5'#255#180'{X'#255#180'{X'#255#180'{X'#255#180'{X'#255#180'{X'#255#180

+  +'{X'#255#180'{X'#255#139'P3'#255'U7)'#231'BBB2UUU'#3#0#0#0#0'T1&,c5 '#249#174

+  +'rQ'#255#178'wW'#255#178'wW'#255#178'wW'#255#178'wW'#255#8#5#4#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255#27#18#13#255#164'nQ'#255#178'wW'#255

+  +#178'wW'#255#178'wW'#255#178'wW'#255#178'wW'#255#178'wW'#255#178'wW'#255#178

+  +'wW'#255#142'_F'#255'H0#'#255#20#13#10#255#25#16#12#255'9'''#28#255'lI5'#255

+  +#178'wW'#255#178'wW'#255'kG4'#255#1#1#1#255#1#1#0#255#1#0#0#255#1#0#0#255#3#2

+  +#1#255'zQ<'#255#178'wW'#255#178'wW'#255#178'wW'#255#178'wW'#255#178'wW'#255

+  +#149'W9'#255'Z5%'#238'DDD-'#128#128#128#2#0#0#0#0'Y3 Bj8#'#248#173'qS'#255

+  +#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#1#0#0#255#1#1#1#255#0#0#0

+  +#255#0#0#0#255#5#3#3#255'cB2'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'

+  +#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255

+  +#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175

+  +'tW'#255#173'rU'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#2#1#1#255#152'eL'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255

+  +#155'[>'#255'\4"'#244'@@@'#28#0#0#0#1#0#0#0#0'X0!3g7"'#246#172'oR'#255#174'r'

+  +'V'#255#174'rV'#255#174'rV'#255#166'lR'#255#7#5#3#255#131'VA'#255#155'fM'#255

+  +'oI7'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'

+  +#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255

+  +#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174'rV'#255#174

+  +'rV'#255#153'dL'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255'<'''#29#255#174'rV'#255#174'rV'#255#174'rV'#255#173'qU'#255

+  +#151'Y='#255']6%'#239'333'#15#0#0#0#0#0#0#0#0'O1'''#25'b3'#31#247#168'jN'#255

+  +#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172

+  +'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#136'XD'

+  +#255'U7*'#255'^=/'#255'kE5'#255#170'oU'#255#172'oU'#255#172'oU'#255#172'oU'

+  +#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oU'#255

+  +#172'oU'#255#172'oU'#255#5#3#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255'!'#21#16#255#172'oU'#255#172'oU'#255#172'oU'#255#172'oT'

+  +#255#143'R7'#255'Y6('#225'@@@'#12#0#0#0#0#0#0#0#0'333'#5'_2'#31#248#167'hL'

+  +#255#172'qW'#255#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255

+  +#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255':&'#30#255#1#0#0

+  +#255#1#1#0#255#1#1#1#255#1#1#0#255#4#2#2#255#133'WD'#255#172'qX'#255#172'qX'

+  +#255#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255#172'qX'#255

+  +#172'qX'#255#172'qX'#255'E.$'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#30#20#15#255#172'qX'#255#172'qX'#255#172'qX'#255#172'pV'#255

+  +#134'K2'#255'V8)'#199'999'#9#0#0#0#0#0#0#0#0#0#0#0#1'_3'#30#239#164'fJ'#255

+  +#175'w]'#255#175'w^'#255#175'w^'#255#175'w^'#255#175'w^'#255#175'w^'#255#175

+  +'w^'#255#175'w^'#255#175'w^'#255#175'w^'#255'hF7'#255#1#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#7#5#4#255#175'w^'#255#175'w^'#255'{TB'

+  ,#255'X;/'#255']?2'#255'VD'#255#175'w^'#255#175'w^'#255#175'w^'#255#175'w^'

+  +#255#165'qY'#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255

+  +'fF7'#255#175'w^'#255#175'w^'#255#175'w^'#255#175'v\'#255'{D-'#253'S5('#154

+  +'333'#5#0#0#0#0#0#0#0#0#0#0#0#0'a3'#30#200#149'Z?'#255#179'|c'#255#179'}e'

+  +#255#179'}e'#255#179'}e'#255#179'}e'#255#179'}e'#255#179'}e'#255#179'}e'#255

+  +#179'}e'#255#179'}e'#255#19#13#11#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255#2#1#1#255#179'}e'#255'E0'''#255#1#0#0#255#1#1#0#255#1#1

+  +#0#255#0#0#0#255'R:/'#255#179'}e'#255#179'}e'#255#179'}e'#255#179'}e'#255'.!'

+  +#26#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#177'}e'#255#179'}e'

+  +#255#179'}e'#255#179'}e'#255#175'v\'#255'g8$'#251'W7*O'#0#0#0#1#0#0#0#0#0#0#0

+  +#0#0#0#0#0'[0'#29'lyD-'#249#181#128'i'#255#183#131'l'#255#183#131'l'#255#183

+  +#131'l'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183

+  +#131'l'#255#183#131'l'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#0#0#0#255#0#0#0#255'"'#25#20#255#183#131'l'#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255'B/'''#255#183#131'l'#255#183#131'l'#255

+  +#183#131'l'#255#169'yd'#255#1#1#1#255#0#0#0#255#0#0#0#255#0#0#0#255'#'#25#21

+  +#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#183#131'l'#255#167'lQ'#255

+  +'^3'#31#248'@@@'#12#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'Y1'#30#26'b5 '#244#178'z'

+  +'c'#255#187#138't'#255#187#138'u'#255#187#138'u'#255#187#138'u'#255#187#138

+  +'u'#255#187#138'u'#255#187#138'u'#255#187#138'u'#255#187#138'u'#255#2#2#1#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255#170'~j'#255#177

+  +#130'o'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#4#3#3

+  +#255#187#138'u'#255#187#138'u'#255#187#138'u'#255#187#138'u'#255'jNB'#255#11

+  +#8#7#255#0#0#0#255#0#0#0#255#152'p`'#255#187#138'u'#255#187#138'u'#255#187

+  +#138'u'#255#186#136'r'#255#144'W?'#255']6#'#193'333'#5#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0'`4'#31#217#160'gN'#255#190#143'{'#255#191#145'}'#255#191

+  +#145'}'#255#191#145'}'#255#191#145'}'#255#191#145'}'#255#191#145'}'#255#191

+  +#145'}'#255#191#145'}'#255#19#14#12#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255'7*$'#255#191#145'}'#255#164'|k'#255#1#1#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#2#2#1#255#191#145'}'#255#191#145'}'#255

+  +#191#145'}'#255#191#145'}'#255#191#145'}'#255#191#145'}'#255#0#0#0#255#30#23

+  +#20#255#191#145'}'#255#191#145'}'#255#191#145'}'#255#191#145'}'#255#187#138

+  +'t'#255'p>('#249'Y2#U'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27

+  +'huB+'#244#190#142'z'#255#195#152#132#255#195#152#132#255#195#152#132#255#195

+  +#152#132#255#195#152#132#255#195#152#132#255#195#152#132#255#195#152#132#255

+  +'A3,'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255#183#142'|'#255

+  +#195#152#132#255#138'k]'#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#9#7#6#255#195#152#132#255#195#152#132#255#195#152#132#255#195

+  +#152#132#255#195#152#132#255#195#152#132#255#1#1#1#255#160'}m'#255#195#152

+  +#132#255#195#152#132#255#195#152#132#255#194#150#131#255#167'pW'#255'`4 '#240

+  +'M33'#10#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@'#0#4'`3'#30#229

+  +#164'nU'#255#197#156#137#255#199#159#141#255#199#159#141#255#199#159#141#255

+  +#199#159#141#255#199#159#141#255#199#159#141#255#199#159#141#255'x`U'#255#1#1

+  +#1#255#0#0#0#255#0#0#0#255#0#0#0#255#18#14#13#255#199#159#141#255#199#159#141

+  +#255' '#26#23#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255

+  +#139'oc'#255#199#159#141#255#199#159#141#255#199#159#141#255#199#159#141#255

+  +#199#159#141#255#199#159#141#255'^KC'#255#199#159#141#255#199#159#141#255#199

+  +#159#141#255#199#159#141#255#192#147''#255'rB-'#249'\1 k'#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'\.'#28'Sn>('#243#194#149#131

+  +#255#202#165#148#255#203#165#149#255#203#165#149#255#203#165#149#255#203#165

+  +#149#255#203#165#149#255#203#165#149#255#169#138'|'#255#0#0#0#255#1#1#1#255

+  +#16#13#11#255#23#19#17#255#171#139'~'#255#203#165#149#255#203#165#149#255#3#3

+  +#2#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255'*"'#31#255#203#165

+  +#149#255#203#165#149#255#203#165#149#255#203#165#149#255#203#165#149#255#203

+  +#165#149#255#203#165#149#255#203#165#149#255#203#165#149#255#203#165#149#255

+  +#203#165#149#255#201#162#145#255#163'mU'#255'_3'#31#227'U'#0#0#3#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'a3'#30#213#153

+  +'eM'#254#204#167#151#255#207#172#158#255#207#172#158#255#207#172#158#255#207

+  +#172#158#255#207#172#158#255#207#172#158#255#205#170#156#255#0#0#0#255'<1.'

+  +#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172

+  +#158#255#20#16#15#255#1#0#0#255#0#0#0#255#0#0#0#255#1#0#0#255'?40'#255#207

+  +#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255

+  +#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158#255#207#172#158

+  +#255#207#172#158#255#207#171#156#255#192#147''#255'k<'''#244'Z.'#29'L'#0#0#0

+  ,#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'^'

+  +'/'#27'&b5!'#240#174'{f'#255#209#176#162#255#212#180#167#255#212#180#167#255

+  +#212#180#167#255#212#180#167#255#212#180#167#255#212#180#167#255#6#5#5#255

+  +#179#151#140#255#212#180#167#255#212#180#167#255#212#180#167#255#212#180#167

+  +#255#212#180#167#255#212#180#167#255'gXR'#255#0#0#0#255#0#0#0#255'gXR'#255

+  +#212#180#167#255#212#180#167#255#212#180#167#255#212#180#167#255#212#180#167

+  +#255#212#180#167#255#212#180#167#255#212#180#167#255#212#180#167#255#212#180

+  +#167#255#212#180#167#255#211#179#166#255#202#162#146#255'M7'#248'`2'#31#169

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0'[/'#26'Fg:#'#242#190#145''#255#214#184#172#255#216#187

+  +#176#255#216#187#176#255#216#187#176#255#216#187#176#255#216#187#176#255'k]X'

+  +#255#216#187#176#255#216#187#176#255#216#187#176#255#216#187#176#255#216#187

+  +#176#255#216#187#176#255#216#187#176#255'E<8'#255#0#0#0#255'>63'#255#216#187

+  +#176#255#216#187#176#255#216#187#176#255#216#187#176#255#216#187#176#255#216

+  +#187#176#255#216#187#176#255#216#187#176#255#216#187#176#255#216#187#176#255

+  +#216#187#176#255#216#187#175#255#210#176#163#255#147'_H'#252'`4'#31#210'U++'

+  +#6#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'\0'#29'trB-'#242#198#157#140#255#218#191#180

+  +#255#221#195#185#255#221#195#185#255#221#195#185#255#221#195#185#255#221#195

+  +#185#255#221#195#185#255#221#195#185#255#221#195#185#255#221#195#185#255#221

+  +#195#185#255#221#195#185#255#221#195#185#255',''%'#255'920'#255#221#195#185

+  +#255#221#195#185#255#221#195#185#255#221#195#185#255#221#195#185#255#221#195

+  +#185#255#221#195#185#255#221#195#185#255#221#195#185#255#221#195#185#255#221

+  +#195#185#255#220#194#184#255#213#183#170#255#162'oW'#255'b5 '#232'].'#23#22#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'_1'#30#138'l>)'#242#187#143'|'#255

+  +#221#196#186#255#225#202#193#255#225#203#194#255#225#203#194#255#225#203#194

+  +#255#225#203#194#255#225#203#194#255#225#203#194#255#225#203#194#255#225#203

+  +#194#255#225#203#194#255#225#203#194#255#225#203#194#255#225#203#194#255#225

+  +#203#194#255#225#203#194#255#225#203#194#255#225#203#194#255#225#203#194#255

+  +#225#203#194#255#225#203#194#255#225#203#194#255#225#203#194#255#225#203#194

+  +#255#224#201#192#255#212#180#168#255#149'aK'#252'a5!'#230']2'#25')'#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#28'\d9$'#241#172'|h'

+  +#255#222#197#187#255#228#206#200#255#230#209#203#255#230#209#203#255#230#209

+  +#203#255#230#209#203#255#230#209#203#255#230#209#203#255#230#209#203#255#230

+  +#209#203#255#230#209#203#255#230#209#203#255#230#209#203#255#230#209#203#255

+  +#230#209#203#255#230#209#203#255#230#209#203#255#230#209#203#255#230#209#203

+  +#255#230#209#203#255#230#209#203#255#229#209#202#255#226#204#197#255#208#173

+  +#159#255#131'R;'#245'a3'#31#207'Y3'#26#20#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'].'#28'7a5!'#236#137'WB'#248#201#163

+  +#148#255#229#210#202#255#233#215#210#255#234#217#212#255#234#217#212#255#234

+  +#217#212#255#234#217#212#255#234#217#212#255#234#217#212#255#234#217#212#255

+  +#234#217#212#255#234#217#212#255#234#217#212#255#234#217#212#255#234#217#212

+  +#255#234#217#212#255#234#217#212#255#234#217#212#255#234#216#211#255#231#212

+  +#206#255#221#195#185#255#174#128'm'#255'm>*'#242'`1'#29#163'f33'#5#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0'b'''#20#13'`2'#29#140'd8$'#241#151'hR'#251#211#179#167#255#233#215#210

+  +#255#236#220#215#255#237#222#219#255#238#225#221#255#238#225#221#255#238#225

+  +#221#255#238#225#221#255#238#225#221#255#238#225#221#255#238#225#221#255#238

+  +#225#221#255#238#225#221#255#238#223#220#255#236#221#217#255#234#219#213#255

+  +#227#205#198#255#188#146#128#255'wH2'#242'b5 '#219'].'#27'B'#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'X1'#29#26'a3'#30#168'f:$'#242#134'T?'#246

+  +#179#136'v'#255#214#183#172#255#235#218#214#255#238#225#221#255#239#226#223

+  +#255#240#227#224#255#240#227#225#255#240#227#225#255#239#226#223#255#239#225

+  +#222#255#238#224#220#255#226#204#196#255#199#161#145#255#158'o['#254'rD-'#239

+  +'b4"'#232'^2'#30'\'#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0'`+ '#24']/'#30'fd6#'#197'c8#'#243'vE0'#240#140'ZF'#247

+  ,#156'mY'#255#171'm'#255#184#143''#255#178#136'v'#255#164'wd'#255#148'dP'

+  +#252#130'Q;'#243'l<('#239'b6"'#234'b5!'#151'Z-'#29'>UU'#0#3#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0'].'#23#11'Z/'#29'G^4 fa4!'#130'd6!'#166'd7#'#194'd7"'#182

+  +'c6"'#150'_3'#31's\0'#29'YY/'#30'+'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#224#3#255#255#255#255#255#254

+  +#0#0''#255#255#255#255#248#0#0#31#255#255#255#255#224#0#0#7#255#255#255#255

+  +#192#0#0#3#255#255#255#255#128#0#0#1#255#255#255#255#0#0#0#0''#255#255#254#0

+  +#0#0#0''#255#255#252#0#0#0#0'?'#255#255#248#0#0#0#0#31#255#255#240#0#0#0#0

+  +#15#255#255#240#0#0#0#0#15#255#255#224#0#0#0#0#7#255#255#224#0#0#0#0#3#255

+  +#255#192#0#0#0#0#3#255#255#192#0#0#0#0#3#255#255#192#0#0#0#0#1#255#255#128#0

+  +#0#0#0#1#255#255#128#0#0#0#0#1#255#255#128#0#0#0#0#1#255#255#128#0#0#0#0#1

+  +#255#255#128#0#0#0#0#0#255#255#128#0#0#0#0#0#255#255#128#0#0#0#0#0#255#255

+  +#128#0#0#0#0#0#255#255#128#0#0#0#0#1#255#255#128#0#0#0#0#1#255#255#128#0#0#0

+  +#0#1#255#255#128#0#0#0#0#1#255#255#192#0#0#0#0#1#255#255#192#0#0#0#0#3#255

+  +#255#192#0#0#0#0#3#255#255#224#0#0#0#0#7#255#255#224#0#0#0#0#7#255#255#224#0

+  +#0#0#0#15#255#255#240#0#0#0#0#15#255#255#248#0#0#0#0#31#255#255#248#0#0#0#0

+  +'?'#255#255#252#0#0#0#0'?'#255#255#254#0#0#0#0''#255#255#255#0#0#0#0#255#255

+  +#255#255#128#0#0#1#255#255#255#255#192#0#0#3#255#255#255#255#224#0#0#15#255

+  +#255#255#255#248#0#0#31#255#255#255#255#254#0#0''#255#255#255#255#255#192#7

+  +#255#255#255#255#255#255#255#255#255#255#255#255'('#0#0#0' '#0#0#0'@'#0#0#0#1

+  +#0' '#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#2'CCC'#19'FFF'#22'UUU'#3#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0'@@@'#12'EAAGDDB'#133'DDC'#181'HC?'#205'LA;'#213'JB='#212'FC@'#204'E'

+  +'ED'#185'DDC'#145'DDDSFFF'#22#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0'III'#14'EEBoLA;'#208'eE-'#235'xK('#246#131'R)'#250#139

+  +'W*'#251#149'_,'#252#145'\+'#252#136'V*'#250#128'Q('#249'rI)'#244'\D2'#227'F'

+  +'B?'#207'CCC'#134'DDD'#30#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'EEENMA9'

+  +#206'oF)'#245#147']-'#252#187'}4'#255#211#150'9'#255#224#167';'#255#230#174

+  +'='#255#234#179'>'#255#233#178'>'#255#228#171'='#255#221#163'<'#255#205#143

+  +'8'#255#175'r2'#255#131'R*'#250'eC,'#238'FB?'#205'CCCoUUU'#3#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'@@@'

+  +#4'GEA|dB+'#239#142'[.'#252#198#137'<'#255#227#172'C'#255#236#183'E'#255#242

+  +#190'F'#255#246#195'G'#255#248#198'G'#255#249#199'H'#255#249#198'H'#255#247

+  +#196'G'#255#245#193'G'#255#240#188'F'#255#234#180'D'#255#220#163'A'#255#183

+  +'y8'#255'}O*'#250'WA4'#225'CCC'#152'<<<'#17#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1'G@='#148'lD*'#245#175'u8'#254

+  +#221#166'I'#255#234#182'M'#255#242#193'P'#255#243#194'O'#255#244#195'O'#255

+  +#244#195'P'#255#244#195'P'#255#244#195'P'#255#244#195'P'#255#244#195'P'#255

+  +#244#195'P'#255#243#194'O'#255#243#194'O'#255#240#190'O'#255#230#179'L'#255

+  +#212#155'F'#255#148'^1'#252'`A.'#234'CCC'#171'@@@'#12#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'FA>vmB)'#247#189#130'A'#255#224#172

+  +'P'#255#236#187'U'#255#238#189'W'#255#238#190'V'#255#238#190'V'#255#238#190

+  +'V'#255'fQ%'#255#17#14#6#255#17#13#6#255#16#13#6#255',#'#16#255#155'|8'#255

+  +#238#190'V'#255#238#190'V'#255#238#189'V'#255#238#189'W'#255#233#184'U'#255

+  +#217#163'M'#255#164'l8'#254'_>+'#238'DDD'#147#128#128#128#2#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'FDD=e?*'#243#183'}B'#255#223#171'W'#255#232

+  +#183'['#255#232#183'\'#255#232#183'\'#255#232#183'\'#255#232#183'\'#255'>1'

+  +#25#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1#255#5#4#2#255

+  +#22#17#9#255'pX,'#255#218#171'V'#255#232#183'\'#255#230#182'['#255#217#164'T'

+  +#255#152'a7'#252'V=1'#228'DDDb'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#128

+  ,#128#128#2'Z<-'#215#163'k='#254#217#166'['#255#226#178'`'#255#226#179'a'#255

+  +#226#179'a'#255#226#179'a'#255#226#179'a'#255#226#179'a'#255#5#4#2#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#3#3#1#255',#'#19#255#226#179'a'#255#225#177'_'#255#208#154'T'#255

+  +#129'O1'#251'H?;'#205'@@@'#20#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'J@<[vF,'#249

+  +#206#153'Y'#255#220#172'b'#255#220#172'c'#255#220#172'c'#255#220#172'c'#255

+  +#220#172'c'#255#220#172'c'#255#205#160']'#255#4#3#2#255#0#0#0#255#0#0#0#255#0

+  +#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#1#0#0#255'.$'#21#255#220#172'c'#255#218#170'a'#255#190#132'N'#255'c=)'

+  +#242'CCCz'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'\9('#218#177'vG'#255#213#164'c'

+  +#255#214#166'e'#255#214#166'e'#255#214#166'e'#255#214#166'e'#255#214#166'e'

+  +#255#214#166'e'#255#214#166'e'#255'v\8'#255#2#2#1#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255

+  +#11#9#5#255#214#166'e'#255#214#166'e'#255#209#159'a'#255#139'Y6'#252'K>7'#206

+  +'333'#5#0#0#0#0#0#0#0#0'?;9'#19'mA+'#247#201#148'^'#255#209#159'e'#255#209

+  +#159'e'#255#209#159'e'#255#146'oF'#255#18#14#9#255#21#16#10#255'O<&'#255#209

+  +#159'e'#255#209#159'e'#255'$'#27#17#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#11#8#5#255

+  +#209#159'e'#255#209#159'e'#255#208#158'e'#255#185#128'Q'#255'^9)'#240'BBB6'#0

+  +#0#0#0#0#0#0#0'P8-q'#144'Z:'#252#201#150'd'#255#202#151'd'#255#202#151'd'#255

+  +'uW:'#255#2#1#1#255#0#0#0#255#0#0#0#255#1#0#0#255'-!'#22#255#202#151'd'#255

+  +'ZC-'#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#1#1#0#255#5#4#3#255'gM3'#255#202#151'd'#255#202#151'd'#255#202

+  +#151'd'#255#197#145'`'#255'l@*'#248'CCBo'#0#0#0#0#0#0#0#0'^7$'#194#171'pK'

+  +#255#194#140'a'#255#194#140'a'#255#194#140'a'#255#6#4#3#255#0#0#0#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#7#5#4#255#194#140'a'#255#139'eE'#255#1#1#1#255#0#0#0

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#13#9#6#255'wV<'#255

+  +#192#138'a'#255#194#140'a'#255#194#140'a'#255#194#140'a'#255#194#140'a'#255

+  +#193#140'a'#255#137'T7'#252'K=6'#158#0#0#0#0#0#0#0#0'a6#'#220#177'uQ'#255#185

+  +#129'['#255#185#129'['#255'Y>'#255#1#1#0#255#0#0#0#255#0#0#0#255#0#0#0#255#2

+  +#1#1#255'8'''#27#255#185#129'['#255#185#129'['#255'+'#30#21#255#2#1#1#255#0#0

+  +#0#255#0#0#0#255#0#0#0#255#0#0#0#255#13#9#6#255#179'}Y'#255#185#129'['#255

+  +#185#129'['#255#185#129'['#255#185#129'['#255#185#129'['#255#185#129'['#255

+  +#185#129'['#255#152'^>'#255'P:1'#190#0#0#0#0#0#0#0#0'c7#'#227#175'sS'#255#178

+  +'xW'#255#178'xW'#255','#30#21#255#0#0#0#255#0#0#0#255#0#0#0#255#5#4#3#255'uO'

+  +':'#255#178'xW'#255#178'xW'#255#178'xW'#255#178'xW'#255'xP:'#255'('#26#19#255

+  +#10#7#5#255#10#7#5#255#28#19#13#255#168'rS'#255#163'nO'#255#25#17#12#255#6#4

+  +#3#255#17#11#8#255'bB/'#255#178'xW'#255#178'xW'#255#178'xW'#255#158'aB'#255

+  +'V9,'#210#0#0#0#0#0#0#0#0'f7"'#227#173'sT'#255#175'tW'#255#175'tW'#255#15#10

+  +#7#255#13#8#6#255#5#4#3#255'+'#29#21#255#169'pU'#255#175'tW'#255#175'tW'#255

+  +#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175'tW'#255#175

+  +'tW'#255#175'tW'#255#175'tW'#255#17#11#8#255#0#0#0#255#0#0#0#255#0#0#0#255#2

+  +#2#1#255#136'ZD'#255#175'tW'#255#175'tW'#255#161'dG'#255'[8('#211#0#0#0#0#0#0

+  +#0#0'e6"'#218#171'nR'#255#173'qV'#255#173'qV'#255#136'YC'#255#173'qV'#255#173

+  +'qV'#255#173'qV'#255#173'qV'#255#173'qV'#255'sK9'#255'uM:'#255#159'gN'#255

+  +#173'qV'#255#173'qV'#255#173'qV'#255#173'qV'#255#173'qV'#255#173'qV'#255#173

+  +'qV'#255'5"'#27#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255'H/$'#255#173'qV'

+  +#255#173'qV'#255#153'^D'#255'Y8*'#188#0#0#0#0#0#0#0#0'c5 '#203#170'kQ'#255

+  +#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#164

+  +'mU'#255#11#7#6#255#1#1#1#255#1#1#1#255#5#3#2#255'TA'#255#174'sY'#255#174's'

+  +'Y'#255#174'sY'#255#174'sY'#255#174'sY'#255#174'sY'#255#128'UA'#255#2#1#1#255

+  +#0#0#0#255#0#0#0#255#0#0#0#255'J1&'#255#174'sY'#255#174'sY'#255#147'X?'#255

+  +'S8,'#140#0#0#0#0#0#0#0#0'd4'#30#153#162'gM'#255#178'{c'#255#178'{c'#255#178

+  +'{c'#255#178'{c'#255#178'{c'#255#178'{c'#255'A-$'#255#0#0#0#255#0#0#0#255#0#0

+  +#0#255#0#0#0#255#20#14#11#255'xSB'#255#6#4#3#255#5#4#3#255#18#12#10#255#170

+  +'u_'#255#178'{c'#255#178'{c'#255#9#6#5#255#0#0#0#255#0#0#0#255#3#2#2#255#166

+  +'s]'#255#178'{c'#255#178'{c'#255#131'P8'#252'S3$>'#0#0#0#0#0#0#0#0'[/'#27'3'

+  +#137'T='#247#184#134'o'#255#184#134'o'#255#184#134'o'#255#184#134'o'#255#184

+  +#134'o'#255#184#134'o'#255#14#10#9#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#1

+  +#255'\C7'#255#14#10#8#255#0#0#0#255#0#0#0#255#0#0#0#255#14#10#8#255#184#134

+  +'o'#255#184#134'o'#255'xWI'#255#2#1#1#255#0#0#0#255#18#14#11#255#184#134'o'

+  +#255#184#134'o'#255#183#131'l'#255'h:&'#240#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +'n<%'#218#189#140'x'#255#190#143'z'#255#190#143'z'#255#190#143'z'#255#190#143

+  +'z'#255#190#143'z'#255',!'#28#255#0#0#0#255#0#0#0#255#0#0#0#255#9#7#6#255#190

+  ,#143'z'#255#9#7#6#255#0#0#0#255#0#0#0#255#0#0#0#255#5#4#3#255#190#143'z'#255

+  +#190#143'z'#255#190#143'z'#255#159'xe'#255#0#0#0#255#140'jZ'#255#190#143'z'

+  +#255#190#143'z'#255#175'yc'#255'b6"'#193#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'd4'

+  +#30#151#167's\'#254#196#154#135#255#196#154#135#255#196#154#135#255#196#154

+  +#135#255#196#154#135#255'qYN'#255#0#0#0#255#0#0#0#255#1#1#1#255'v]R'#255#194

+  +#152#133#255#5#4#4#255#0#0#0#255#0#0#0#255#0#0#0#255#10#8#7#255#196#154#135

+  +#255#196#154#135#255#196#154#135#255#196#154#135#255'"'#27#24#255#196#154#135

+  +#255#196#154#135#255#196#154#135#255#131'R<'#248'^1'#28'1'#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0'[/'#27#14'o>('#224#198#157#140#255#202#163#146#255#202#163#146

+  +#255#202#163#146#255#202#163#146#255#170#138'{'#255#0#0#0#255#8#6#6#255#26#21

+  +#19#255#202#163#146#255#143'th'#255#1#1#1#255#0#0#0#255#0#0#0#255#2#2#2#255

+  +#143'sg'#255#202#163#146#255#202#163#146#255#202#163#146#255#202#163#146#255

+  +#191#155#138#255#202#163#146#255#202#163#146#255#183#135'r'#255'd5 '#193#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'd3'#30'{'#156'jS'#248#209#174

+  +#160#255#209#174#160#255#209#174#160#255#209#174#160#255#209#174#160#255#2#2

+  +#2#255#205#172#158#255#209#174#160#255#209#174#160#255#169#140#129#255#11#9#9

+  +#255#1#1#0#255#4#3#3#255#132'oe'#255#209#174#160#255#209#174#160#255#209#174

+  +#160#255#209#174#160#255#209#174#160#255#209#174#160#255#209#174#160#255#205

+  +#167#152#255'yG3'#235'[/'#27'"'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0'd4'#30#181#179#134'r'#254#215#185#173#255#215#185#173#255#215#185

+  +#173#255#215#185#173#255'm^X'#255#215#185#173#255#215#185#173#255#215#185#173

+  +#255#215#185#173#255#133'sk'#255#0#0#0#255#156#134'}'#255#215#185#173#255#215

+  +#185#173#255#215#185#173#255#215#185#173#255#215#185#173#255#215#185#173#255

+  +#215#185#173#255#214#183#172#255#143'^I'#243'b3'#29'`'#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#8'f6 '#205#189#148#131#254

+  +#222#197#187#255#222#197#187#255#222#197#187#255#222#197#187#255#222#197#187

+  +#255#222#197#187#255#222#197#187#255#222#197#187#255'qk'#255#134'wq'#255#222

+  +#197#187#255#222#197#187#255#222#197#187#255#222#197#187#255#222#197#187#255

+  +#222#197#187#255#222#197#187#255#220#193#183#255#159'o['#247'd3'#30#147#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'['

+  +'/'#27#15'c3'#30#193#176#132'q'#248#228#206#199#255#228#208#201#255#228#208

+  +#201#255#228#208#201#255#228#208#201#255#228#208#201#255#228#208#201#255#228

+  +#208#201#255#228#208#201#255#228#208#201#255#228#208#201#255#228#208#201#255

+  +#228#208#201#255#228#208#201#255#228#208#201#255#221#196#186#255#141']I'#237

+  +'c3'#29#129#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#2'c3'#29#150#135'XD'#231#208#176#164

+  +#255#235#219#215#255#235#219#215#255#235#219#215#255#235#219#215#255#235#219

+  +#215#255#235#219#215#255#235#219#215#255#235#219#215#255#235#219#215#255#235

+  +#219#215#255#235#219#215#255#232#214#209#255#189#149#133#253'qA+'#220'a2'#29

+  +'O'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27'"e4'#30#185#144'cO'#235

+  +#195#158#144#254#230#209#203#255#242#231#229#255#242#231#229#255#242#231#229

+  +#255#242#231#229#255#242#231#229#255#241#230#226#255#220#193#184#255#180#141

+  +'|'#251'zK6'#226'd3'#30#142'[/'#27#10#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#28'b3'#29'{g5'#30#198'xH2'#218#137']J'

+  +#229#156'r`'#236#151'mZ'#234#132'VB'#227'q?)'#213'f4'#30#182'_1'#28'W[/'#27

+  +#11#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#5'[/'#27#30'[/'#27#22'[/'

+  +#27#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#252'?'#255#255#192#3#255#255#0#0

+  +#255#254#0#0'?'#248#0#0#31#240#0#0#15#240#0#0#7#224#0#0#7#192#0#0#3#192#0#0#3

+  +#192#0#0#1#128#0#0#1#128#0#0#1#128#0#0#1#128#0#0#1#128#0#0#1#128#0#0#1#128#0

+  +#0#1#128#0#0#1#128#0#0#1#128#0#0#3#192#0#0#3#192#0#0#3#192#0#0#7#224#0#0#7

+  +#240#0#0#15#240#0#0#31#248#0#0'?'#252#0#0''#255#0#0#255#255#192#3#255#255

+  +#252'?'#255'('#0#0#0#16#0#0#0' '#0#0#0#1#0' '#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0';;;'#13'ICB7M=4zL'

+  +'>6xFBA;@@@'#16#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0'III'#7'W;,'#171'nC('#245#145'`+'#250#181'2'#253#175'z1'#253#139'\*'#250

+  +'h?&'#244'P=3'#159'@@@'#12#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'K921d;'''

+  +#235#191#137'7'#254#249#198'E'#255#251#199'F'#255#251#200'F'#255#251#200'F'

+  +#255#251#199'F'#255#246#194'E'#255#173'y3'#253'\9)'#229'E>;2'#0#0#0#0#0#0#0#0

+  +#0#0#0#0'>2,'#7'nC'''#238#223#171'N'#255#239#191'U'#255#240#192'U'#255#164

+  ,#131':'#255'@3'#23#255'J;'#26#255'~e-'#255#196#157'E'#255#239#191'U'#255#212

+  +#159'J'#255'a<('#231'MMM'#10#0#0#0#0#0#0#0#0'[7('#183#195#145'N'#254#228#180

+  +'_'#255#228#180'_'#255#228#180'_'#255'</'#25#255#0#0#0#255#0#0#0#255#0#0#0

+  +#255#4#3#1#255'9-'#24#255#205#163'U'#255#175'~E'#253'Q:0'#168#0#0#0#0'[/'#27

+  +#10#143'd@'#248#219#174'l'#255#219#173'l'#255#159'~N'#255#206#163'f'#255'qY7'

+  +#255#0#0#0#255#0#0#0#255#0#0#0#255#0#0#0#255#1#1#0#255#152'xK'#255#218#172'k'

+  +#255'zQ5'#246'UUU'#3'W4$H'#178#134'_'#254#213#169'x'#255'YF2'#255#0#0#0#255

+  +'L<+'#255#200#158'p'#255#8#6#4#255#0#0#0#255#0#0#0#255#18#15#10#255'pY?'#255

+  +#213#169'x'#255#213#169'x'#255#157'tR'#251'M=74^6$'#154#193#151'x'#255#179

+  +#144's'#255#6#5#4#255#27#21#17#255#155'|c'#255#206#165#132#255#130'hS'#255'='

+  +'1'''#255':/%'#255#170#137'm'#255#141'q['#255#166#133'j'#255#206#165#132#255

+  +#178#135'l'#253'Q8,{c5 '#167#195#154#133#255#163#130'q'#255#153'zj'#255#192

+  +#152#132#255#199#159#138#255#200#159#138#255#201#160#139#255#201#160#139#255

+  +#201#160#139#255#154'zj'#255#1#1#1#255#29#23#20#255#197#157#136#255#181#139

+  +'v'#255'X5%|_1'#28'V'#176#132'r'#254#199#159#141#255#199#159#141#255#184#147

+  +#130#255'#'#28#25#255#27#22#19#255#167#133'v'#255'fZ'#255#172#137'z'#255#197

+  +#157#139#255' '#26#23#255#15#12#11#255#187#150#133#255#156'tb'#251'W1 0[/'#27

+  +#30#160'zk'#246#210#176#163#255#210#176#163#255#154#129'x'#255#0#0#0#255' '

+  +#27#25#255#152#128'v'#255#4#3#3#255'>40'#255#210#176#163#255#148'|s'#255'RD?'

+  +#255#210#176#163#255#140'fW'#243'[/'#27#2#0#0#0#0'tI6'#209#216#188#178#255

+  +#221#195#185#255#213#188#178#255'$'#31#30#255#131'sn'#255'sf`'#255#0#0#0#255

+  +'eYU'#255#221#195#185#255#221#195#185#255#204#180#170#255#207#178#166#255'k>'

+  +'+'#182#0#0#0#0#0#0#0#0'[/'#27#31#156'xi'#240#232#213#207#255#232#213#207#255

+  +#180#165#161#255#232#213#207#255#182#167#162#255'ICA'#255#226#207#201#255#232

+  +#213#207#255#232#213#207#255#231#213#206#255#134'_O'#233'[/'#27#12#0#0#0#0#0

+  +#0#0#0#0#0#0#0'd3'#30'e'#171#139'~'#240#239#226#224#255#242#231#229#255#242

+  +#231#229#255#240#229#227#255#242#231#229#255#242#231#229#255#242#231#229#255

+  +#235#221#216#255#153'uh'#236'a2'#29'?'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0

+  +#0'\0'#27'*'#131'\I'#215#212#191#183#252#239#229#226#255#253#250#252#255#253

+  +#249#250#255#236#223#220#255#204#180#172#250'yM;'#196'[/'#27#23#0#0#0#0#0#0#0

+  +#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'[/'#27#3'[/'#27'>c3'#29#131'uI4'

+  +#190'oA-'#183'b2'#29'v[/'#27'4'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#248

+  +#31#172'A'#224#7#172'A'#192#3#172'A'#128#1#172'A'#128#1#172'A'#0#0#172'A'#0#0

+  +#172'A'#0#0#172'A'#0#0#172'A'#0#0#172'A'#0#0#172'A'#128#1#172'A'#128#1#172'A'

+  +#192#3#172'A'#224#7#172'A'#240#31#172'A'

+]);

+

diff --git a/examples/cross_calculator/lazarus/nimlaz.rc b/examples/cross_calculator/lazarus/nimlaz.rc
new file mode 100644
index 000000000..d66bb817c
--- /dev/null
+++ b/examples/cross_calculator/lazarus/nimlaz.rc
@@ -0,0 +1,6 @@
+#define RT_MANIFEST  24

+#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1

+#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2

+#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3

+

+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "nimlaz.manifest"
diff --git a/examples/cross_calculator/lazarus/readme.txt b/examples/cross_calculator/lazarus/readme.txt
new file mode 100644
index 000000000..2d5048445
--- /dev/null
+++ b/examples/cross_calculator/lazarus/readme.txt
@@ -0,0 +1,8 @@
+This example demonstrates how to use Nim with Lazarus. The GUI is generated

+with Lazarus, while the "backend" is written in Nim. To compile the example,

+use this command:

+

+  nim c --app:gui --no_main --no_linking backend.nim

+

+Open the ``nimlaz.lpi`` file in Lazarus and run the program.

+

diff --git a/examples/cross_calculator/lazarus/unit1.lfm b/examples/cross_calculator/lazarus/unit1.lfm
new file mode 100644
index 000000000..bf60ff715
--- /dev/null
+++ b/examples/cross_calculator/lazarus/unit1.lfm
@@ -0,0 +1,46 @@
+object Form1: TForm1
+  Left = 553
+  Height = 111
+  Top = 464
+  Width = 448
+  ActiveControl = SpinEdit1
+  Caption = 'Sum'
+  ClientHeight = 111
+  ClientWidth = 448
+  OnCreate = FormCreate
+  LCLVersion = '0.9.28.2'
+  object Label1: TLabel
+    Left = 8
+    Height = 18
+    Top = 72
+    Width = 34
+    Caption = 'Sum:'
+    ParentColor = False
+  end
+  object SpinEdit1: TSpinEdit
+    Left = 8
+    Height = 27
+    Top = 8
+    Width = 436
+    Anchors = [akTop, akLeft, akRight]
+    OnChange = SpinEdit1Change
+    TabOrder = 0
+  end
+  object SpinEdit2: TSpinEdit
+    Left = 8
+    Height = 27
+    Top = 40
+    Width = 436
+    Anchors = [akTop, akLeft, akRight]
+    OnChange = SpinEdit1Change
+    TabOrder = 1
+  end
+  object Edit1: TEdit
+    Left = 48
+    Height = 27
+    Top = 72
+    Width = 396
+    Anchors = [akTop, akLeft, akRight]
+    TabOrder = 2
+  end
+end
diff --git a/examples/cross_calculator/lazarus/unit1.pas b/examples/cross_calculator/lazarus/unit1.pas
new file mode 100644
index 000000000..aa0ef6cf7
--- /dev/null
+++ b/examples/cross_calculator/lazarus/unit1.pas
@@ -0,0 +1,58 @@
+unit Unit1; 
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
+  Spin, StdCtrls;
+
+type
+
+  { TForm1 }
+
+  TForm1 = class(TForm)
+    Edit1: TEdit;
+    Label1: TLabel;
+    SpinEdit1: TSpinEdit;
+    SpinEdit2: TSpinEdit;
+    procedure FormCreate(Sender: TObject);
+    procedure SpinEdit1Change(Sender: TObject);
+  private
+    { private declarations }
+  public
+    { public declarations }
+  end; 
+
+var
+  Form1: TForm1; 
+
+implementation
+
+{ TForm1 }
+
+{$link nimcache/lib/system.o}
+{$link nimcache/backend.o}
+{$link nimcache/nim__dat.o}
+{$linklib c}
+
+procedure NimMain; cdecl; external;
+function myAdd(x, y: longint): longint; cdecl; external;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+  // we initialize the Nimrod data structures here:
+  NimMain();
+end;
+
+procedure TForm1.SpinEdit1Change(Sender: TObject);
+begin
+  Edit1.text := IntToStr(myAdd(SpinEdit1.Value, SpinEdit2.Value));
+end;
+
+initialization
+  {$I unit1.lrs}
+
+end.
+
diff --git a/examples/cross_calculator/nim_backend/backend.nim b/examples/cross_calculator/nim_backend/backend.nim
new file mode 100644
index 000000000..ffa4311f9
--- /dev/null
+++ b/examples/cross_calculator/nim_backend/backend.nim
@@ -0,0 +1,5 @@
+# Backend for the different user interfaces.

+

+proc myAdd*(x, y: int): int {.cdecl, exportc.} = 

+  result = x + y

+

diff --git a/examples/cross_calculator/nim_commandline/nim.cfg b/examples/cross_calculator/nim_commandline/nim.cfg
new file mode 100644
index 000000000..41c034430
--- /dev/null
+++ b/examples/cross_calculator/nim_commandline/nim.cfg
@@ -0,0 +1,4 @@
+# Nimrod configuration file.
+# The file is used only to add the path of the backend to the compiler options.
+
+path="../nim_backend"
diff --git a/examples/cross_calculator/nim_commandline/nimcalculator.nim b/examples/cross_calculator/nim_commandline/nimcalculator.nim
new file mode 100644
index 000000000..69d62a90c
--- /dev/null
+++ b/examples/cross_calculator/nim_commandline/nimcalculator.nim
@@ -0,0 +1,109 @@
+# Implements a command line interface against the backend.
+
+import backend, parseopt, strutils
+
+const
+  USAGE = """nimcalculator - Nimrod cross platform calculator
+  (beta version, only integer addition is supported!)
+
+Usage:
+  nimcalculator [options] [-a=value -b=value]
+Options:
+  -a=value    sets the integer value of the a parameter
+  -b=value    sets the integer value of the b parameter
+  -h, --help  shows this help
+
+If no options are used, an interactive mode is entered.
+"""
+
+type
+  TCommand = enum       # The possible types of operation
+    cmdParams,          # Two valid parameters were provided
+    cmdInteractive      # No parameters were provided, run interactive mode
+
+  TParamConfig = object of RootObj
+    action: TCommand      # store the type of operation
+    paramA, paramB: int   # possibly store the valid parameters
+
+
+proc parseCmdLine(): TParamConfig =
+  ## Parses the commandline.
+  ##
+  ## Returns a TParamConfig structure filled with the proper values or directly
+  ## calls quit() with the appropriate error message.
+  var
+    hasA = false
+    hasB = false
+    p = initOptParser()
+    key, val: TaintedString
+
+  result.action = cmdInteractive # By default presume interactive mode.
+  try:
+    while true:
+      next p
+      key = p.key
+      val = p.val
+
+      case p.kind
+      of cmdArgument:
+        stdout.write USAGE
+        quit "Erroneous argument detected: " & key, 1
+      of cmdLongOption, cmdShortOption:
+        case key.normalize
+        of "help", "h":
+          stdout.write USAGE
+          quit 0
+        of "a":
+          result.paramA = val.parseInt
+          hasA = true
+        of "b":
+          result.paramB = val.parseInt
+          hasB = true
+        else:
+          stdout.write USAGE
+          quit "Unexpected option: " & key, 2
+      of cmdEnd: break
+  except ValueError:
+    stdout.write USAGE
+    quit "Invalid value " & val &  " for parameter " & key, 3
+
+  if hasA and hasB:
+    result.action = cmdParams
+  elif hasA or hasB:
+    stdout.write USAGE
+    quit "Error: provide both A and B to operate in param mode", 4
+
+
+proc parseUserInput(question: string): int =
+  ## Parses a line of user input, showing question to the user first.
+  ##
+  ## If the user input is an empty line quit() is called. Returns the value
+  ## parsed as an integer.
+  while true:
+    echo question
+    let input = stdin.readLine
+    try:
+      result = input.parseInt
+      break
+    except ValueError:
+      if input.len < 1: quit "Blank line detected, quitting.", 0
+      echo "Sorry, `$1' doesn't seem to be a valid integer" % input
+
+proc interactiveMode() =
+  ## Asks the user for two integer values, adds them and exits.
+  let
+    paramA = parseUserInput("Enter the first parameter (blank to exit):")
+    paramB = parseUserInput("Enter the second parameter (blank to exit):")
+  echo "Calculating... $1 + $2 = $3" % [$paramA, $paramB,
+    $backend.myAdd(paramA, paramB)]
+
+
+when isMainModule:
+  ## Main entry point.
+  let opt = parseCmdLine()
+  if cmdParams == opt.action:
+    echo "Param mode: $1 + $2 = $3" % [$opt.paramA, $opt.paramB,
+      $backend.myAdd(opt.paramA, opt.paramB)]
+  else:
+    echo "Entering interactive addition mode"
+    interactiveMode()
diff --git a/examples/cross_calculator/nim_commandline/readme.txt b/examples/cross_calculator/nim_commandline/readme.txt
new file mode 100644
index 000000000..f95bd962e
--- /dev/null
+++ b/examples/cross_calculator/nim_commandline/readme.txt
@@ -0,0 +1,10 @@
+In this directory you will find the nim commandline version of the
+cross-calculator sample.
+
+The commandline interface can be used non interactively through switches, or
+interactively when running the command without parameters.
+
+Compilation is fairly easy despite having the source split in different
+directories. Thanks to the nim.cfg file, which adds the ../nim_backend
+directory as a search path, you can compile and run the example just fine from
+the command line with 'nim c -r nimcalculator.nim'.
diff --git a/examples/cross_calculator/readme.txt b/examples/cross_calculator/readme.txt
new file mode 100644
index 000000000..12ad558d4
--- /dev/null
+++ b/examples/cross_calculator/readme.txt
@@ -0,0 +1,13 @@
+The cross platform calculator illustrates how to use Nim to create a backend

+called by different native user interfaces.

+

+Since the purpose of the example is to show how the cross platform code

+interacts with Nimrod the actual backend code is just a simple addition proc.

+By keeping your program logic in Nim you can easily reuse it in different

+platforms.

+

+To avoid duplication of code, the backend code lies in a separate directory and

+each platform compiles it with a different custom build process, usually

+generating C code in a temporary build directory.

+

+For a more elaborate and useful example see the cross_todo example.

diff --git a/examples/cross_todo/nim_backend/backend.nim b/examples/cross_todo/nim_backend/backend.nim
new file mode 100644
index 000000000..5b49bc4a9
--- /dev/null
+++ b/examples/cross_todo/nim_backend/backend.nim
@@ -0,0 +1,219 @@
+# Backend for a simple todo program with sqlite persistence.
+#
+# Most procs dealing with a TDbConn object may raise an EDb exception.
+
+import db_sqlite, parseutils, strutils, times
+
+
+type
+  TTodo* = object
+    ## A todo object holding the information serialized to the database.
+    id: int64                 ## Unique identifier of the object in the
+                              ## database, use the getId() accessor to read it.
+    text*: string             ## Description of the task to do.
+    priority*: int            ## The priority can be any user defined integer.
+    isDone*: bool             ## Done todos are still kept marked.
+    modificationDate: Time    ## The modification time can't be modified from
+                              ## outside of this module, use the
+                              ## getModificationDate accessor.
+
+  TPagedParams* = object
+    ## Contains parameters for a query, initialize default values with
+    ## initDefaults().
+    pageSize*: int64          ## Lines per returned query page, -1 for
+                              ## unlimited.
+    priorityAscending*: bool  ## Sort results by ascending priority.
+    dateAscending*: bool      ## Sort results by ascending modification date.
+    showUnchecked*: bool      ## Get unchecked objects.
+    showChecked*: bool        ## Get checked objects.
+
+
+# - General procs
+#
+proc initDefaults*(params: var TPagedParams) =
+  ## Sets sane defaults for a TPagedParams object.
+  ##
+  ## Note that you should always provide a non zero pageSize, either a specific
+  ## positive value or negative for unbounded query results.
+  params.pageSize = high(int64)
+  params.priorityAscending = false
+  params.dateAscending = false
+  params.showUnchecked = true
+  params.showChecked = false
+
+
+proc openDatabase*(path: string): TDbConn =
+  ## Creates or opens the sqlite3 database.
+  ##
+  ## Pass the path to the sqlite database, if the database doesn't exist it
+  ## will be created. The proc may raise a EDB exception
+  let
+    conn = db_sqlite.open(path, "user", "pass", "db")
+    query = sql"""CREATE TABLE IF NOT EXISTS Todos (
+      id INTEGER PRIMARY KEY,
+      priority INTEGER NOT NULL,
+      is_done BOOLEAN NOT NULL,
+      desc TEXT NOT NULL,
+      modification_date INTEGER NOT NULL,
+      CONSTRAINT Todos UNIQUE (id))"""
+
+  db_sqlite.exec(conn, query)
+  result = conn
+
+
+# - Procs related to TTodo objects
+#
+proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
+               modificationDate: Time): TTodo =
+  ## Returns an initialized TTodo object created from database parameters.
+  ##
+  ## The proc assumes all values are right. Note this proc is NOT exported.
+  assert(id >= 0, "Identity identifiers should not be negative")
+  result.id = id
+  result.text = text
+  result.priority = priority
+  result.isDone = isDone
+  result.modificationDate = modificationDate
+
+
+proc getId*(todo: TTodo): int64 =
+  ## Accessor returning the value of the private id property.
+  return todo.id
+
+
+proc getModificationDate*(todo: TTodo): Time =
+  ## Returns the last modification date of a TTodo entry.
+  return todo.modificationDate
+
+
+proc update*(todo: var TTodo; conn: TDbConn): bool =
+  ## Checks the database for the object and refreshes its variables.
+  ##
+  ## Use this method if you (or another entity) have modified the database and
+  ## want to update the object you have with whatever the database has stored.
+  ## Returns true if the update succeeded, or false if the object was not found
+  ## in the database any more, in which case you should probably get rid of the
+  ## TTodo object.
+  assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
+  let query = sql"""SELECT desc, priority, is_done, modification_date
+    FROM Todos WHERE id = ?"""
+
+  try:
+    let rows = conn.getAllRows(query, $todo.id)
+    if len(rows) < 1:
+      return
+    assert(1 == len(rows), "Woah, didn't expect so many rows")
+    todo.text = rows[0][0]
+    todo.priority = rows[0][1].parseInt
+    todo.isDone = rows[0][2].parseBool
+    todo.modificationDate = Time(rows[0][3].parseInt)
+    result = true
+  except:
+    echo("Something went wrong selecting for id " & $todo.id)
+
+
+proc save*(todo: var TTodo; conn: TDbConn): bool =
+  ## Saves the current state of text, priority and isDone to the database.
+  ##
+  ## Returns true if the database object was updated (in which case the
+  ## modification date will have changed). The proc can return false if the
+  ## object wasn't found, for instance, in which case you should drop that
+  ## object anyway and create a new one with addTodo(). Also EDb can be raised.
+  assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
+  let
+    currentDate = getTime()
+    query = sql"""UPDATE Todos
+      SET desc = ?, priority = ?, is_done = ?, modification_date = ?
+      WHERE id = ?"""
+    rowsUpdated = conn.execAffectedRows(query, $todo.text,
+      $todo.priority, $todo.isDone, $int(currentDate), $todo.id)
+
+  if 1 == rowsUpdated:
+    todo.modificationDate = currentDate
+    result = true
+
+
+# - Procs dealing directly with the database
+#
+proc addTodo*(conn: TDbConn; priority: int; text: string): TTodo =
+  ## Inserts a new todo into the database.
+  ##
+  ## Returns the generated todo object. If there is an error EDb will be raised.
+  let
+    currentDate = getTime()
+    query = sql"""INSERT INTO Todos
+      (priority, is_done, desc, modification_date)
+      VALUES (?, 'false', ?, ?)"""
+    todoId = conn.insertId(query, priority, text, $int(currentDate))
+
+  result = initFromDB(todoId, text, priority, false, currentDate)
+
+
+proc deleteTodo*(conn: TDbConn; todoId: int64): int64 {.discardable.} =
+  ## Deletes the specified todo identifier.
+  ##
+  ## Returns the number of rows which were affected (1 or 0)
+  let query = sql"""DELETE FROM Todos WHERE id = ?"""
+  result = conn.execAffectedRows(query, $todoId)
+
+
+proc getNumEntries*(conn: TDbConn): int =
+  ## Returns the number of entries in the Todos table.
+  ##
+  ## If the function succeeds, returns the zero or positive value, if something
+  ## goes wrong a negative value is returned.
+  let query = sql"""SELECT COUNT(id) FROM Todos"""
+  try:
+    let row = conn.getRow(query)
+    result = row[0].parseInt
+  except:
+    echo("Something went wrong retrieving number of Todos entries")
+    result = -1
+
+
+proc getPagedTodos*(conn: TDbConn; params: TPagedParams;
+                    page = 0'i64): seq[TTodo] =
+  ## Returns the todo entries for a specific page.
+  ##
+  ## Pages are calculated based on the params.pageSize parameter, which can be
+  ## set to a negative value to specify no limit at all.  The query will be
+  ## affected by the TPagedParams, which should have sane values (call
+  ## initDefaults).
+  assert(page >= 0, "You should request a page zero or bigger than zero")
+  result = @[]
+
+  # Well, if you don't want to see anything, there's no point in asking the db.
+  if not params.showUnchecked and not params.showChecked: return
+
+  let
+    order_by = [
+      if params.priorityAscending: "ASC" else: "DESC",
+      if params.dateAscending: "ASC" else: "DESC"]
+
+    query = sql("""SELECT id, desc, priority, is_done, modification_date
+      FROM Todos
+      WHERE is_done = ? OR is_done = ?
+      ORDER BY priority $1, modification_date $2, id DESC
+      LIMIT ? * ?,?""" % order_by)
+
+    args = @[$params.showChecked, $(not params.showUnchecked),
+      $params.pageSize, $page, $params.pageSize]
+
+  #echo("Query " & string(query))
+  #echo("args: " & args.join(", "))
+
+  var newId: BiggestInt
+  for row in conn.fastRows(query, args):
+    let numChars = row[0].parseBiggestInt(newId)
+    assert(numChars > 0, "Huh, couldn't parse identifier from database?")
+    result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
+        row[3].parseBool, Time(row[4].parseInt)))
+
+
+proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo =
+  ## Returns a reference to a TTodo or nil if the todo could not be found.
+  var tempTodo: TTodo
+  tempTodo.id = todoId
+  if tempTodo.update(conn):
+    new(result)
+    result[] = tempTodo
diff --git a/examples/cross_todo/nim_backend/readme.txt b/examples/cross_todo/nim_backend/readme.txt
new file mode 100644
index 000000000..16cb592fc
--- /dev/null
+++ b/examples/cross_todo/nim_backend/readme.txt
@@ -0,0 +1,14 @@
+This directory contains the nim backend code for the todo cross platform

+example.

+

+Unlike the cross platform calculator example, this backend features more code,

+using an sqlite database for storage. Also a basic test module is provided, not

+to be included with the final program but to test the exported functionality.

+The test is not embedded directly in the backend.nim file to avoid being able

+to access internal data types and procs not exported and replicate the

+environment of client code.

+

+In a bigger project with several people you could run `nim doc backend.nim`

+(or use the doc2 command for a whole project) and provide the generated html

+documentation to another programer for her to implement an interface without

+having to look at the source code.

diff --git a/examples/cross_todo/nim_backend/testbackend.nim b/examples/cross_todo/nim_backend/testbackend.nim
new file mode 100644
index 000000000..131dda1cf
--- /dev/null
+++ b/examples/cross_todo/nim_backend/testbackend.nim
@@ -0,0 +1,83 @@
+# Tests the backend code.
+
+import backend, db_sqlite, strutils, times
+
+
+proc showPagedResults(conn: TDbConn; params: TPagedParams) =
+  ## Shows the contents of the database in pages of specified size.
+  ##
+  ## Hmm... I guess this is more of a debug proc which should be moved outside,
+  ## or to a commandline interface (hint).
+  var
+    page = 0'i64
+    rows = conn.getPagedTodos(params)
+
+  while rows.len > 0:
+    echo("page " & $page)
+    for row in rows:
+      echo("row id:$1, text:$2, priority:$3, done:$4, date:$5" % [$row.getId,
+        $row.text, $row.priority, $row.isDone,
+        $row.getModificationDate])
+    # Query the database for the next page or quit.
+    if params.pageSize > 0:
+      page = page + 1
+      rows = conn.getPagedTodos(params, page)
+    else:
+      break
+
+
+proc dumTest() =
+  let conn = openDatabase("todo.sqlite3")
+  try:
+    let numTodos = conn.getNumEntries
+    echo("Current database contains " & $numTodos & " todo items.")
+    if numTodos < 10:
+      # Fill some dummy rows if there are not many entries yet.
+      discard conn.addTodo(3, "Filler1")
+      discard conn.addTodo(4, "Filler2")
+
+    var todo = conn.addTodo(2, "Testing")
+    echo("New todo added with id " & $todo.getId)
+
+    # Try changing it and updating the database.
+    var clonedTodo = conn.getTodo(todo.getId)[]
+    assert(clonedTodo.text == todo.text, "Should be equal")
+    todo.text = "Updated!"
+    todo.priority = 7
+    todo.isDone = true
+    if todo.save(conn):
+      echo("Updated priority $1, done $2" % [$todo.priority, $todo.isDone])
+    else:
+      assert(false, "Uh oh, I wasn't expecting that!")
+
+    # Verify our cloned copy is different but can be updated.
+    assert(clonedTodo.text != todo.text, "Should be different")
+    discard clonedTodo.update(conn)
+    assert(clonedTodo.text == todo.text, "Should be equal")
+
+    var params: TPagedParams
+    params.initDefaults
+    conn.showPagedResults(params)
+    conn.deleteTodo(todo.getId)
+    echo("Deleted rows for id 3? ")
+    let res = conn.deleteTodo(todo.getId)
+    echo("Deleted rows for id 3? " & $res)
+    if todo.update(conn):
+      echo("Later priority $1, done $2" % [$todo.priority, $todo.isDone])
+    else:
+      echo("Can't update object $1 from db!" % $todo.getId)
+
+    # Try to list content in a different way.
+    params.pageSize = 5
+    params.priorityAscending = true
+    params.dateAscending = true
+    params.showChecked = true
+    conn.showPagedResults(params)
+  finally:
+    conn.close
+    echo("Database closed")
+
+
+# Code that will be run only on the commandline.
+when isMainModule:
+  dumTest()
diff --git a/examples/cross_todo/nim_commandline/nim.cfg b/examples/cross_todo/nim_commandline/nim.cfg
new file mode 100644
index 000000000..41c034430
--- /dev/null
+++ b/examples/cross_todo/nim_commandline/nim.cfg
@@ -0,0 +1,4 @@
+# Nimrod configuration file.
+# The file is used only to add the path of the backend to the compiler options.
+
+path="../nim_backend"
diff --git a/examples/cross_todo/nim_commandline/nimtodo.nim b/examples/cross_todo/nim_commandline/nimtodo.nim
new file mode 100644
index 000000000..4ab17e7a2
--- /dev/null
+++ b/examples/cross_todo/nim_commandline/nimtodo.nim
@@ -0,0 +1,327 @@
+# Implements a command line interface against the backend.
+
+import backend, db_sqlite, os, parseopt, parseutils, strutils, times
+
+const
+  USAGE = """nimtodo - Nimrod cross platform todo manager
+
+Usage:
+  nimtodo [command] [list options]
+
+Commands:
+  -a=int text Adds a todo entry with the specified priority and text.
+  -c=int      Marks the specified todo entry as done.
+  -u=int      Marks the specified todo entry as not done.
+  -d=int|all  Deletes a single entry from the database, or all entries.
+  -g          Generates some rows with values for testing.
+  -l          Lists the contents of the database.
+  -h, --help  shows this help
+
+List options (optional):
+  -p=+|-      Sorts list by ascending|desdencing priority. Default:desdencing.
+  -m=+|-      Sorts list by ascending|desdencing date. Default:desdencing.
+  -t          Show checked entries. By default they are not shown.
+  -z          Hide unchecked entries. By default they are shown.
+
+Examples:
+  nimtodo -a=4 Water the plants
+  nimtodo -c:87
+  nimtodo -d:2
+  nimtodo -d:all
+  nimtodo -l -p=+ -m=- -t
+
+"""
+
+type
+  TCommand = enum     # The possible types of commands
+    cmdAdd            # The user wants to add a new todo entry.
+    cmdCheck          # User wants to check a todo entry.
+    cmdUncheck        # User wants to uncheck a todo entry.
+    cmdDelete         # User wants to delete a single todo entry.
+    cmdNuke           # User wants to purge all database entries.
+    cmdGenerate       # Add random rows to the database, for testing.
+    cmdList           # User wants to list contents.
+
+  TParamConfig = object
+    # Structure containing the parsed options from the commandline.
+    command: TCommand         # Store the type of operation
+    addPriority: int          # Only valid with cmdAdd, stores priority.
+    addText: seq[string]      # Only valid with cmdAdd, stores todo text.
+    todoId: int64             # The todo id for operations like check or delete.
+    listParams: TPagedParams  # Uses the backend structure directly for params.
+
+
+proc initDefaults(params: var TParamConfig) =
+  ## Initialises defaults value in the structure.
+  ##
+  ## Most importantly we want to have an empty list for addText.
+  params.listParams.initDefaults
+  params.addText = @[]
+
+
+proc abort(message: string, value: int) =
+  # Simple wrapper to abort also displaying the help to the user.
+  stdout.write(USAGE)
+  quit(message, value)
+
+
+template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
+  ## Helper to parse a big todo identifier into todoId and set command.
+  try:
+    let numChars = val.parseBiggestInt(newId)
+    if numChars < 1: raise newException(ValueError, "Empty string?")
+    result.command = newCommand
+    result.todoId = newId
+  except OverflowError:
+    raise newException(ValueError, "Value $1 too big" % val)
+
+
+template verifySingleCommand(actions: stmt): stmt =
+  ## Helper to make sure only one command has been specified so far.
+  if specifiedCommand:
+    abort("Only one command can be specified at a time! (extra:$1)" % [key], 2)
+  else:
+    actions
+    specifiedCommand = true
+
+
+proc parsePlusMinus(val: string, debugText: string): bool =
+  ## Helper to process a plus or minus character from the commandline.
+  ##
+  ## Pass the string to parse and the type of parameter for debug errors.
+  ## The processed parameter will be returned as true for a '+' and false for a
+  ## '-'. The proc aborts with a debug message if the passed parameter doesn't
+  ## contain one of those values.
+  case val
+  of "+":
+    return true
+  of "-":
+    return false
+  else:
+    abort("$1 parameter should be + or - but was '$2'." % [debugText, val], 4)
+
+
+proc parseCmdLine(): TParamConfig =
+  ## Parses the commandline.
+  ##
+  ## Returns a TParamConfig structure filled with the proper values or directly
+  ## calls quit() with the appropriate error message.
+  var
+    specifiedCommand = false
+    usesListParams = false
+    p = initOptParser()
+    key, val: TaintedString
+    newId: BiggestInt
+
+  result.initDefaults
+
+  try:
+    while true:
+      next(p)
+      key = p.key
+      val = p.val
+
+      case p.kind
+      of cmdArgument:
+        if specifiedCommand and cmdAdd == result.command:
+          result.addText.add(key)
+        else:
+          abort("Argument ($1) detected without add command." % [key], 1)
+      of cmdLongOption, cmdShortOption:
+        case normalize(key)
+        of "help", "h":
+          stdout.write(USAGE)
+          quit(0)
+        of "a":
+          verifySingleCommand:
+            result.command = cmdAdd
+            result.addPriority = val.parseInt
+        of "c":
+          verifySingleCommand:
+            parseTodoIdAndSetCommand(cmdCheck)
+        of "u":
+          verifySingleCommand:
+            parseTodoIdAndSetCommand cmdUncheck
+        of "d":
+          verifySingleCommand:
+            if "all" == val:
+              result.command = cmdNuke
+            else:
+              parseTodoIdAndSetCommand cmdDelete
+        of "g":
+          verifySingleCommand:
+            if val.len > 0:
+              abort("Unexpected value '$1' for switch l." % [val], 3)
+            result.command = cmdGenerate
+        of "l":
+          verifySingleCommand:
+            if val.len > 0:
+              abort("Unexpected value '$1' for switch l." % [val], 3)
+            result.command = cmdList
+        of "p":
+          usesListParams = true
+          result.listParams.priorityAscending = parsePlusMinus(val, "Priority")
+        of "m":
+          usesListParams = true
+          result.listParams.dateAscending = parsePlusMinus(val, "Date")
+        of "t":
+          usesListParams = true
+          if val.len > 0:
+            abort("Unexpected value '$1' for switch t." % [val], 5)
+          result.listParams.showChecked = true
+        of "z":
+          usesListParams = true
+          if val.len > 0:
+            abort("Unexpected value '$1' for switch z." % [val], 5)
+          result.listParams.showUnchecked = false
+        else:
+          abort("Unexpected option '$1'." % [key], 6)
+      of cmdEnd:
+        break
+  except ValueError:
+    abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
+
+  if not specifiedCommand:
+    abort("Didn't specify any command.", 8)
+
+  if cmdAdd == result.command and result.addText.len < 1:
+    abort("Used the add command, but provided no text/description.", 9)
+
+  if usesListParams and cmdList != result.command:
+    abort("Used list options, but didn't specify the list command.", 10)
+
+
+proc generateDatabaseRows(conn: TDbConn) =
+  ## Adds some rows to the database ignoring errors.
+  discard conn.addTodo(1, "Watch another random youtube video")
+  discard conn.addTodo(2, "Train some starcraft moves for the league")
+  discard conn.addTodo(3, "Spread the word about Nimrod")
+  discard conn.addTodo(4, "Give fruit superavit to neighbours")
+  var todo = conn.addTodo(4, "Send tax form through snail mail")
+  todo.isDone = true
+  discard todo.save(conn)
+  discard conn.addTodo(1, "Download new anime to watch")
+  todo = conn.addTodo(2, "Build train model from scraps")
+  todo.isDone = true
+  discard todo.save(conn)
+  discard conn.addTodo(5, "Buy latest Britney Spears album")
+  discard conn.addTodo(6, "Learn a functional programming language")
+  echo("Generated some entries, they were added to your database.")
+
+
+proc listDatabaseContents(conn: TDbConn; listParams: TPagedParams) =
+  ## Dumps the database contents formatted to the standard output.
+  ##
+  ## Pass the list/filter parameters parsed from the commandline.
+  var params = listParams
+  params.pageSize = -1
+
+  let todos = conn.getPagedTodos(params)
+  if todos.len < 1:
+    echo("Database empty")
+    return
+
+  echo("Todo id, is done, priority, last modification date, text:")
+  # First detect how long should be our columns for formatting.
+  var cols: array[0..2, int]
+  for todo in todos:
+    cols[0] = max(cols[0], ($todo.getId).len)
+    cols[1] = max(cols[1], ($todo.priority).len)
+    cols[2] = max(cols[2], ($todo.getModificationDate).len)
+
+  # Now dump all the rows using the calculated alignment sizes.
+  for todo in todos:
+    echo("$1 $2 $3, $4, $5" % [
+      ($todo.getId).align(cols[0]),
+      if todo.isDone: "[X]" else: "[-]",
+      ($todo.priority).align(cols[1]),
+      ($todo.getModificationDate).align(cols[2]),
+      todo.text])
+
+
+proc deleteOneTodo(conn: TDbConn; todoId: int64) =
+  ## Deletes a single todo entry from the database.
+  let numDeleted = conn.deleteTodo(todoId)
+  if numDeleted > 0:
+    echo("Deleted todo id " & $todoId)
+  else:
+    quit("Couldn't delete todo id " & $todoId, 11)
+
+
+proc deleteAllTodos(conn: TDbConn) =
+  ## Deletes all the contents from the database.
+  ##
+  ## Note that it would be more optimal to issue a direct DELETE sql statement
+  ## on the database, but for the sake of the example we will restrict
+  ## ourselfves to the API exported by backend.
+  var
+    counter: int64
+    params: TPagedParams
+
+  params.initDefaults
+  params.pageSize = -1
+  params.showUnchecked = true
+  params.showChecked = true
+
+  let todos = conn.getPagedTodos(params)
+  for todo in todos:
+    if conn.deleteTodo(todo.getId) > 0:
+      counter += 1
+    else:
+      quit("Couldn't delete todo id " & $todo.getId, 12)
+
+  echo("Deleted $1 todo entries from database." % $counter)
+
+
+proc setTodoCheck(conn: TDbConn; todoId: int64; value: bool) =
+  ## Changes the check state of a todo entry to the specified value.
+  let
+    newState = if value: "checked" else: "unchecked"
+    todo = conn.getTodo(todoId)
+
+  if todo == nil:
+    quit("Can't modify todo id $1, its not in the database." % $todoId, 13)
+
+  if todo[].isDone == value:
+    echo("Todo id $1 was already set to $2." % [$todoId, newState])
+    return
+
+  todo[].isDone = value
+  if todo[].save(conn):
+    echo("Todo id $1 set to $2." % [$todoId, newState])
+  else:
+    quit("Error updating todo id $1 to $2." % [$todoId, newState])
+
+
+proc addTodo(conn: TDbConn; priority: int; tokens: seq[string]) =
+  ## Adds to the database a todo with the specified priority.
+  ##
+  ## The tokens are joined as a single string using the space character. The
+  ## created id will be displayed to the user.
+  let todo = conn.addTodo(priority, tokens.join(" "))
+  echo("Created todo entry with id:$1 for priority $2 and text '$3'." % [
+    $todo.getId, $todo.priority, todo.text])
+
+
+when isMainModule:
+  ## Main entry point.
+  let
+    opt = parseCmdLine()
+    dbPath = getConfigDir() / "nimtodo.sqlite3"
+
+  if not dbPath.existsFile:
+    createDir(getConfigDir())
+    echo("No database found at $1, it will be created for you." % dbPath)
+
+  let conn = openDatabase(dbPath)
+  try:
+    case opt.command
+    of cmdAdd: addTodo(conn, opt.addPriority, opt.addText)
+    of cmdCheck: setTodoCheck(conn, opt.todoId, true)
+    of cmdUncheck: setTodoCheck(conn, opt.todoId, false)
+    of cmdDelete: deleteOneTodo(conn, opt.todoId)
+    of cmdNuke: deleteAllTodos(conn)
+    of cmdGenerate: generateDatabaseRows(conn)
+    of cmdList: listDatabaseContents(conn, opt.listParams)
+  finally:
+    conn.close
diff --git a/examples/cross_todo/nim_commandline/readme.txt b/examples/cross_todo/nim_commandline/readme.txt
new file mode 100644
index 000000000..ca4b67521
--- /dev/null
+++ b/examples/cross_todo/nim_commandline/readme.txt
@@ -0,0 +1,19 @@
+This directory contains the Nim commandline version of the todo cross
+platform example.
+
+The commandline interface can be used only through switches, running the binary
+once will spit out the basic help. The commands you can use are the typical on
+such an application: add, check/uncheck and delete (further could be added,
+like modification at expense of parsing/option complexity). The list command is
+the only one which dumps the contents of the database. The output can be
+filtered and sorted through additional parameters.
+
+When you run the program for the first time the todo database will be generated
+in your user's data directory. To cope with an empty database, a special
+generation switch can be used to fill the database with some basic todo entries
+you can play with.
+
+Compilation is fairly easy despite having the source split in different
+directories. Thanks to the Nim.cfg file, which adds the ../Nim_backend
+directory as a search path, you can compile and run the example just fine from
+the command line with 'nim c -r nimtodo.nim'.
diff --git a/examples/cross_todo/readme.txt b/examples/cross_todo/readme.txt
new file mode 100644
index 000000000..2e648a35a
--- /dev/null
+++ b/examples/cross_todo/readme.txt
@@ -0,0 +1,7 @@
+The cross platform todo illustrates how to use Nim to create a backend

+called by different native user interfaces.

+

+This example builds on the knowledge learned from the cross_calculator example.

+Check it out first to learn how to set up Nim on different platforms.

+Additional implementations are provided at the external

+https://github.com/gradha/nimrod-crossplatform-todo github repository.

diff --git a/examples/curlex.nim b/examples/curlex.nim
new file mode 100644
index 000000000..017956818
--- /dev/null
+++ b/examples/curlex.nim
@@ -0,0 +1,10 @@
+import 
+  libcurl
+
+var hCurl = easy_init()
+if hCurl != nil: 
+  discard easy_setopt(hCurl, OPT_VERBOSE, true)
+  discard easy_setopt(hCurl, OPT_URL, "http://nim-lang.org/")
+  discard easy_perform(hCurl)
+  easy_cleanup(hCurl)
+
diff --git a/examples/debugging.nim b/examples/debugging.nim
new file mode 100644
index 000000000..89cdd3b2a
--- /dev/null
+++ b/examples/debugging.nim
@@ -0,0 +1,17 @@
+# Simple program to test the debugger
+# compile with --debugger:on
+
+proc someComp(x, y: int): int =
+  let a = x+y
+  if a > 7:
+    let b = a*90
+    {.breakpoint.}
+    result = b
+  {.breakpoint.}
+
+proc pp() =
+  var aa = 45
+  var bb = "abcdef"
+  echo someComp(23, 45)
+
+pp()
diff --git a/examples/filterex.nim b/examples/filterex.nim
new file mode 100644
index 000000000..3713f4b64
--- /dev/null
+++ b/examples/filterex.nim
@@ -0,0 +1,23 @@
+#! stdtmpl | standard
+#proc generateHTMLPage(title, currentTab, content: string,
+#                      tabs: openArray[string]): string = 
+#  result = ""
+<head><title>$title</title></head>
+<body>
+  <div id="menu">
+    <ul>
+  #for tab in items(tabs):
+    #if currentTab == tab:
+    <li><a id="selected" 
+    #else:
+    <li><a
+    #end if
+    href="${tab}.html" title = "$title - $tab">$tab</a></li>
+  #end for
+    </ul>
+  </div>
+  <div id="content">
+    $content
+    A dollar: $$.
+  </div>
+</body>
diff --git a/examples/fizzbuzz.nim b/examples/fizzbuzz.nim
new file mode 100644
index 000000000..4b203512c
--- /dev/null
+++ b/examples/fizzbuzz.nim
@@ -0,0 +1,14 @@
+# Fizz Buzz program
+
+const f = "Fizz"
+const b = "Buzz"
+for i in 1..100:
+  if i mod 15 == 0:
+    echo f, b
+  elif i mod 5 == 0:
+    echo b
+  elif i mod 3 == 0:
+    echo f
+  else:
+    echo i
+
diff --git a/examples/hallo.nim b/examples/hallo.nim
new file mode 100644
index 000000000..d94da8c1f
--- /dev/null
+++ b/examples/hallo.nim
@@ -0,0 +1,3 @@
+# Hello world program
+
+echo "Hello World"
diff --git a/examples/htmlrefs.nim b/examples/htmlrefs.nim
new file mode 100644
index 000000000..5364d61b6
--- /dev/null
+++ b/examples/htmlrefs.nim
@@ -0,0 +1,57 @@
+# Example program to show the new parsexml module
+# This program reads an HTML file and writes all its used links to stdout.
+# Errors and whitespace are ignored.
+
+import os, streams, parsexml, strutils
+
+proc `=?=` (a, b: string): bool = 
+  # little trick: define our own comparator that ignores case
+  return cmpIgnoreCase(a, b) == 0
+
+if paramCount() < 1: 
+  quit("Usage: htmlrefs filename[.html]")
+
+var links = 0 # count the number of links
+var filename = addFileExt(paramStr(1), "html")
+var s = newFileStream(filename, fmRead)
+if s == nil: quit("cannot open the file " & filename)
+var x: XmlParser
+open(x, s, filename)
+next(x) # get first event
+block mainLoop:
+  while true:
+    case x.kind
+    of xmlElementOpen: 
+      # the <a href = "xyz"> tag we are interested in always has an attribute,
+      # thus we search for ``xmlElementOpen`` and not for ``xmlElementStart``
+      if x.elementName =?= "a": 
+        x.next()
+        if x.kind == xmlAttribute: 
+          if x.attrKey =?= "href":
+            var link = x.attrValue
+            inc(links)
+            # skip until we have an ``xmlElementClose`` event
+            while true: 
+              x.next()
+              case x.kind
+              of xmlEof: break mainLoop
+              of xmlElementClose: break
+              else: discard
+            x.next() # skip ``xmlElementClose``
+            # now we have the description for the ``a`` element
+            var desc = ""
+            while x.kind == xmlCharData: 
+              desc.add(x.charData)
+              x.next()
+            echo(desc & ": " & link)
+      else:
+        x.next()      
+    of xmlEof: break # end of file reached
+    of xmlError: 
+      echo(errorMsg(x))
+      x.next()
+    else: x.next() # skip other events
+
+echo($links & " link(s) found!")
+x.close()
+
diff --git a/examples/htmltitle.nim b/examples/htmltitle.nim
new file mode 100644
index 000000000..7e66fabaa
--- /dev/null
+++ b/examples/htmltitle.nim
@@ -0,0 +1,36 @@
+# Example program to show the parsexml module
+# This program reads an HTML file and writes its title to stdout.
+# Errors and whitespace are ignored.
+
+import os, streams, parsexml, strutils
+
+if paramCount() < 1:
+  quit("Usage: htmltitle filename[.html]")
+
+var filename = addFileExt(paramStr(1), "html")
+var s = newFileStream(filename, fmRead)
+if s == nil: quit("cannot open the file " & filename)
+var x: XmlParser
+open(x, s, filename)
+while true:
+  x.next()
+  case x.kind
+  of xmlElementStart: 
+    if cmpIgnoreCase(x.elementName, "title") == 0: 
+      var title = ""
+      x.next()  # skip "<title>"
+      while x.kind == xmlCharData: 
+        title.add(x.charData)
+        x.next()
+      if x.kind == xmlElementEnd and cmpIgnoreCase(x.elementName, "title") == 0:
+        echo("Title: " & title)
+        quit(0) # Success!
+      else:
+        echo(x.errorMsgExpected("/title"))
+  
+  of xmlEof: break # end of file reached
+  else: discard # ignore other events
+
+x.close()
+quit("Could not determine title!")
+
diff --git a/examples/httpserver2.nim b/examples/httpserver2.nim
new file mode 100644
index 000000000..13fea9e21
--- /dev/null
+++ b/examples/httpserver2.nim
@@ -0,0 +1,247 @@
+import strutils, os, osproc, strtabs, streams, sockets
+
+const
+  wwwNL* = "\r\L"
+  ServerSig = "Server: httpserver.nim/1.0.0" & wwwNL
+
+type
+  TRequestMethod = enum reqGet, reqPost
+  TServer* = object       ## contains the current server state
+    s: Socket
+    job: seq[TJob]
+  TJob* = object
+    client: Socket
+    process: Process
+
+# --------------- output messages --------------------------------------------
+
+proc sendTextContentType(client: Socket) =
+  send(client, "Content-type: text/html" & wwwNL)
+  send(client, wwwNL)
+
+proc badRequest(client: Socket) =
+  # Inform the client that a request it has made has a problem.
+  send(client, "HTTP/1.0 400 BAD REQUEST" & wwwNL)
+  sendTextContentType(client)
+  send(client, "<p>Your browser sent a bad request, " &
+               "such as a POST without a Content-Length.</p>" & wwwNL)
+
+
+proc cannotExec(client: Socket) =
+  send(client, "HTTP/1.0 500 Internal Server Error" & wwwNL)
+  sendTextContentType(client)
+  send(client, "<P>Error prohibited CGI execution.</p>" & wwwNL)
+
+
+proc headers(client: Socket, filename: string) =
+  # XXX could use filename to determine file type
+  send(client, "HTTP/1.0 200 OK" & wwwNL)
+  send(client, ServerSig)
+  sendTextContentType(client)
+
+proc notFound(client: Socket, path: string) =
+  send(client, "HTTP/1.0 404 NOT FOUND" & wwwNL)
+  send(client, ServerSig)
+  sendTextContentType(client)
+  send(client, "<html><title>Not Found</title>" & wwwNL)
+  send(client, "<body><p>The server could not fulfill" & wwwNL)
+  send(client, "your request because the resource <b>" & path & "</b>" & wwwNL)
+  send(client, "is unavailable or nonexistent.</p>" & wwwNL)
+  send(client, "</body></html>" & wwwNL)
+
+
+proc unimplemented(client: Socket) =
+  send(client, "HTTP/1.0 501 Method Not Implemented" & wwwNL)
+  send(client, ServerSig)
+  sendTextContentType(client)
+  send(client, "<html><head><title>Method Not Implemented" &
+               "</title></head>" &
+               "<body><p>HTTP request method not supported.</p>" &
+               "</body></HTML>" & wwwNL)
+
+
+# ----------------- file serving ---------------------------------------------
+
+proc discardHeaders(client: Socket) = skip(client)
+
+proc serveFile(client: Socket, filename: string) =
+  discardHeaders(client)
+
+  var f: File
+  if open(f, filename):
+    headers(client, filename)
+    const bufSize = 8000 # != 8K might be good for memory manager
+    var buf = alloc(bufsize)
+    while true:
+      var bytesread = readBuffer(f, buf, bufsize)
+      if bytesread > 0:
+        var byteswritten = send(client, buf, bytesread)
+        if bytesread != bytesWritten:
+          let err = osLastError()
+          dealloc(buf)
+          close(f)
+          raiseOSError(err)
+      if bytesread != bufSize: break
+    dealloc(buf)
+    close(f)
+    client.close()
+  else:
+    notFound(client, filename)
+
+# ------------------ CGI execution -------------------------------------------
+
+proc executeCgi(server: var TServer, client: Socket, path, query: string, 
+                meth: TRequestMethod) =
+  var env = newStringTable(modeCaseInsensitive)
+  var contentLength = -1
+  case meth
+  of reqGet:
+    discardHeaders(client)
+
+    env["REQUEST_METHOD"] = "GET"
+    env["QUERY_STRING"] = query
+  of reqPost:
+    var buf = ""
+    var dataAvail = true
+    while dataAvail:
+      dataAvail = recvLine(client, buf)
+      if buf.len == 0:
+        break
+      var L = toLower(buf)
+      if L.startsWith("content-length:"):
+        var i = len("content-length:")
+        while L[i] in Whitespace: inc(i)
+        contentLength = parseInt(substr(L, i))
+
+    if contentLength < 0:
+      badRequest(client)
+      return
+
+    env["REQUEST_METHOD"] = "POST"
+    env["CONTENT_LENGTH"] = $contentLength
+
+  send(client, "HTTP/1.0 200 OK" & wwwNL)
+
+  var process = startProcess(command=path, env=env)
+ 
+  var job: TJob
+  job.process = process
+  job.client = client
+  server.job.add(job)
+ 
+  if meth == reqPost:
+    # get from client and post to CGI program:
+    var buf = alloc(contentLength)
+    if recv(client, buf, contentLength) != contentLength:
+      let err = osLastError()
+      dealloc(buf)
+      raiseOSError(err)
+    var inp = process.inputStream
+    inp.writeData(buf, contentLength)
+    dealloc(buf)
+
+proc animate(server: var TServer) =
+  # checks list of jobs, removes finished ones (pretty sloppy by seq copying)
+  var active_jobs: seq[TJob] = @[]
+  for i in 0..server.job.len-1:
+    var job = server.job[i]
+    if running(job.process):
+      active_jobs.add(job)
+    else:
+      # read process output stream and send it to client
+      var outp = job.process.outputStream
+      while true:
+        var line = outp.readstr(1024)
+        if line.len == 0:
+          break
+        else:
+          try:
+            send(job.client, line)
+          except:
+            echo("send failed, client diconnected")
+      close(job.client)
+
+  server.job = active_jobs
+
+# --------------- Server Setup -----------------------------------------------
+
+proc acceptRequest(server: var TServer, client: Socket) =
+  var cgi = false
+  var query = ""
+  var buf = ""
+  discard recvLine(client, buf)
+  var path = ""
+  var data = buf.split()
+  var meth = reqGet
+  var q = find(data[1], '?')
+
+  # extract path
+  if q >= 0:
+    # strip "?..." from path, this may be found in both POST and GET
+    path = data[1].substr(0, q-1)
+  else:
+    path = data[1]
+  # path starts with "/", by adding "." in front of it we serve files from cwd
+  path = "." & path
+
+  echo("accept: " & path)
+
+  if cmpIgnoreCase(data[0], "GET") == 0:
+    if q >= 0:
+      cgi = true
+      query = data[1].substr(q+1)
+  elif cmpIgnoreCase(data[0], "POST") == 0:
+    cgi = true
+    meth = reqPost
+  else:
+    unimplemented(client)
+
+  if path[path.len-1] == '/' or existsDir(path):
+    path = path / "index.html"
+
+  if not existsFile(path):
+    discardHeaders(client)
+    notFound(client, path)
+    client.close()
+  else:
+    when defined(Windows):
+      var ext = splitFile(path).ext.toLower
+      if ext == ".exe" or ext == ".cgi":
+        # XXX: extract interpreter information here?
+        cgi = true
+    else:
+      if {fpUserExec, fpGroupExec, fpOthersExec} * path.getFilePermissions != {}:
+        cgi = true
+    if not cgi:
+      serveFile(client, path)
+    else:
+      executeCgi(server, client, path, query, meth)
+
+when isMainModule:
+  var port = 80
+
+  var server: TServer
+  server.job = @[]
+  server.s = socket(AF_INET)
+  if server.s == invalidSocket: raiseOSError(osLastError())
+  server.s.bindAddr(port=Port(port))
+  listen(server.s)
+  echo("server up on port " & $port)
+
+  while true:
+    # check for new new connection & handle it
+    var list: seq[Socket] = @[server.s]
+    if select(list, 10) > 0:
+      var client: Socket
+      new(client)
+      accept(server.s, client)
+      try:
+        acceptRequest(server, client)
+      except:
+        echo("failed to accept client request")
+
+    # pooling events
+    animate(server)
+    # some slack for CPU
+    sleep(10)
+  server.s.close()
diff --git a/examples/iupex1.nim b/examples/iupex1.nim
new file mode 100644
index 000000000..f768fb23f
--- /dev/null
+++ b/examples/iupex1.nim
@@ -0,0 +1,37 @@
+# Example IUP program
+
+# iupTabs: Creates a iupTabs control.
+
+import iup
+
+discard iup.open(nil, nil)
+
+var vbox1 = iup.vbox(iup.label("Inside Tab A"), iup.button("Button A", ""), nil)
+var vbox2 = iup.vbox(iup.label("Inside Tab B"), iup.button("Button B", ""), nil)
+
+iup.setAttribute(vbox1, "TABTITLE", "Tab A")
+iup.setAttribute(vbox2, "TABTITLE", "Tab B")
+
+var tabs1 = iup.tabs(vbox1, vbox2, nil)
+
+vbox1 = iup.vbox(iup.label("Inside Tab C"), iup.button("Button C", ""), nil)
+vbox2 = iup.vbox(iup.label("Inside Tab D"), iup.button("Button D", ""), nil)
+
+iup.setAttribute(vbox1, "TABTITLE", "Tab C")
+iup.setAttribute(vbox2, "TABTITLE", "Tab D")
+
+var tabs2 = iup.tabs(vbox1, vbox2, nil)
+iup.setAttribute(tabs2, "TABTYPE", "LEFT")
+
+var box = iup.hbox(tabs1, tabs2, nil)
+iup.setAttribute(box, "MARGIN", "10x10")
+iup.setAttribute(box, "GAP", "10")
+
+var dlg = iup.dialog(box)
+iup.setAttribute(dlg, "TITLE", "iupTabs")
+iup.setAttribute(dlg, "SIZE", "200x100")
+
+discard showXY(dlg, IUP_CENTER, IUP_CENTER)
+discard mainLoop()
+close()
+
diff --git a/examples/keyval.nim b/examples/keyval.nim
new file mode 100644
index 000000000..ae8cb8f08
--- /dev/null
+++ b/examples/keyval.nim
@@ -0,0 +1,9 @@
+# Filter key=value pairs from "myfile.txt"
+import re
+
+for x in lines("myfile.txt"):
+  if x =~ re"(\w+)=(.*)":
+    echo "Key: ", matches[0],
+         " Value: ", matches[1]
+
+
diff --git a/examples/keyval2.nim b/examples/keyval2.nim
new file mode 100644
index 000000000..2a5643276
--- /dev/null
+++ b/examples/keyval2.nim
@@ -0,0 +1,7 @@
+# Filter key=value pairs from "myfile.txt"
+import pegs
+
+for x in lines("myfile.txt"):
+  if x =~ peg"{\ident} \s* '=' \s* {.*}":
+    echo "Key: ", matches[0],
+         " Value: ", matches[1]
diff --git a/examples/maximum.nim b/examples/maximum.nim
new file mode 100644
index 000000000..ac6160f76
--- /dev/null
+++ b/examples/maximum.nim
@@ -0,0 +1,6 @@
+# Test high level features

+

+import strutils

+

+echo "Give a list of numbers (separated by spaces): "

+stdin.readLine.split.map(parseInt).max.`$`.echo(" is the maximum!")

diff --git a/examples/myfile.txt b/examples/myfile.txt
new file mode 100644
index 000000000..fb7cda984
--- /dev/null
+++ b/examples/myfile.txt
@@ -0,0 +1,11 @@
+kladsfa
+
+asdflksadlfasf
+
+
+adsfljksadfl
+
+
+key=/usr/bin/value
+key2=/ha/ha
+
diff --git a/examples/objciface/gnustepex.nim b/examples/objciface/gnustepex.nim
new file mode 100644
index 000000000..d961d3087
--- /dev/null
+++ b/examples/objciface/gnustepex.nim
@@ -0,0 +1,40 @@
+# horrible example of how to interface with GNUStep ...
+
+{.passL: "-lobjc".}
+{.emit: """
+
+#include <objc/Object.h>
+
+@interface Greeter:Object
+{
+}
+
+- (void)greet:(long)x y:(long)dummy;
+
+@end
+
+#include <stdio.h>
+
+@implementation Greeter
+
+- (void)greet:(long)x y:(long)dummy
+{
+	printf("Hello, World!\n");
+}
+
+@end
+
+#include <stdlib.h>
+""".}
+
+type
+  TId {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
+
+proc newGreeter: TId {.importobjc: "Greeter new", nodecl.}
+proc greet(self: TId, x, y: int) {.importobjc: "greet", nodecl.}
+proc free(self: TId) {.importobjc: "free", nodecl.}
+
+var g = newGreeter()
+g.greet(12, 34)
+g.free()
+
diff --git a/examples/parsecfgex.nim b/examples/parsecfgex.nim
new file mode 100644
index 000000000..0f37a0378
--- /dev/null
+++ b/examples/parsecfgex.nim
@@ -0,0 +1,25 @@
+
+import
+  os, parsecfg, strutils, streams
+  
+var f = newFileStream(paramStr(1), fmRead)
+if f != nil:
+  var p: CfgParser
+  open(p, f, paramStr(1))
+  while true:
+    var e = next(p)
+    case e.kind
+    of cfgEof: 
+      echo("EOF!")
+      break
+    of cfgSectionStart:   ## a ``[section]`` has been parsed
+      echo("new section: " & e.section)
+    of cfgKeyValuePair:
+      echo("key-value-pair: " & e.key & ": " & e.value)
+    of cfgOption:
+      echo("command: " & e.key & ": " & e.value)
+    of cfgError:
+      echo(e.msg)
+  close(p)
+else:
+  echo("cannot open: " & paramStr(1))
diff --git a/examples/readme.txt b/examples/readme.txt
new file mode 100644
index 000000000..8cfd4f82b
--- /dev/null
+++ b/examples/readme.txt
@@ -0,0 +1,5 @@
+In this directory you will find several examples for how to use the Nimrod 
+library. 
+
+Copyright (c) 2004-2012 Andreas Rumpf.
+All rights reserved.
diff --git a/examples/sdlex.nim b/examples/sdlex.nim
new file mode 100644
index 000000000..3dd474d8e
--- /dev/null
+++ b/examples/sdlex.nim
@@ -0,0 +1,52 @@
+# Test the SDL interface:

+

+import

+  sdl, sdl_image, colors

+

+var

+  screen, greeting: PSurface

+  r: TRect

+  event: TEvent

+  bgColor = colChocolate.int32

+

+if init(INIT_VIDEO) != 0:

+  quit "SDL failed to initialize!"

+

+screen = setVideoMode(640, 480, 16, SWSURFACE or ANYFORMAT)

+if screen.isNil:

+  quit($sdl.getError())

+

+greeting = imgLoad("tux.png")

+if greeting.isNil:

+  echo "Failed to load tux.png"

+else:

+  ## convert the image to alpha and free the old one

+  var s = greeting.displayFormatAlpha()

+  swap(greeting, s)

+  s.freeSurface()

+

+r.x = 0

+r.y = 0

+

+block game_loop:

+  while true:

+    

+    while pollEvent(addr event) > 0:

+      case event.kind

+      of QUITEV:

+        break game_loop

+      of KEYDOWN:

+        if evKeyboard(addr event).keysym.sym == K_ESCAPE:

+          break game_loop

+      else:

+        discard

+    

+    discard fillRect(screen, nil, bgColor) 

+    discard blitSurface(greeting, nil, screen, addr r)

+    discard flip(screen)

+

+greeting.freeSurface()

+screen.freeSurface()

+sdl.quit()

+

+## fowl wuz here 10/2012
\ No newline at end of file
diff --git a/examples/statcsv.nim b/examples/statcsv.nim
new file mode 100644
index 000000000..cd1de62af
--- /dev/null
+++ b/examples/statcsv.nim
@@ -0,0 +1,60 @@
+# Example program to show the parsecsv module
+# This program reads a CSV file and computes sum, mean, minimum, maximum and
+# the standard deviation of its columns.
+# The CSV file can have a header which is then used for the output.
+
+import os, streams, parsecsv, strutils, math
+
+if paramCount() < 1:
+  quit("Usage: statcsv filename[.csv]")
+
+var filename = addFileExt(paramStr(1), "csv")
+var s = newFileStream(filename, fmRead)
+if s == nil: quit("cannot open the file " & filename)
+
+var
+  x: CsvParser
+  header: seq[string]
+  res: seq[RunningStat]
+open(x, s, filename, separator=';', skipInitialSpace = true)
+while readRow(x):
+  if processedRows(x) == 1:
+    newSeq(res, x.row.len) # allocate space for the result
+    if validIdentifier(x.row[0]):
+      # header line:
+      header = x.row
+    else:
+      newSeq(header, x.row.len)
+      for i in 0..x.row.len-1: header[i] = "Col " & $(i+1)
+  else:
+    # data line:
+    for i in 0..x.row.len-1: 
+      push(res[i], parseFloat(x.row[i]))
+x.close()
+
+# Write results:
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(header[i])
+stdout.write("\nSum")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].sum)
+stdout.write("\nMean")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].mean)
+stdout.write("\nMin")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].min)
+stdout.write("\nMax")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].max)
+stdout.write("\nStdDev")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].standardDeviation)
+stdout.write("\n")
+
diff --git a/examples/talk/dsl.nim b/examples/talk/dsl.nim
new file mode 100644
index 000000000..4dfab5cd7
--- /dev/null
+++ b/examples/talk/dsl.nim
@@ -0,0 +1,33 @@
+
+import strutils
+
+template html(name: expr, matter: stmt) {.immediate.} =
+  proc name(): string =
+    result = "<html>"
+    matter
+    result.add("</html>")
+
+template nestedTag(tag: expr) {.immediate.} =
+  template tag(matter: stmt) {.immediate.} =
+    result.add("<" & astToStr(tag) & ">")
+    matter
+    result.add("</" & astToStr(tag) & ">")
+
+template simpleTag(tag: expr) {.immediate.} =
+  template tag(matter: expr) {.immediate.} =
+    result.add("<$1>$2</$1>" % [astToStr(tag), matter])
+
+nestedTag body
+nestedTag head
+nestedTag ul
+simpleTag title
+simpleTag li
+
+html mainPage:
+  head:
+    title "now look at this"
+  body:
+    ul:
+      li "Nimrod is quite capable"
+
+echo mainPage()
diff --git a/examples/talk/formatoptimizer.nim b/examples/talk/formatoptimizer.nim
new file mode 100644
index 000000000..db11d112d
--- /dev/null
+++ b/examples/talk/formatoptimizer.nim
@@ -0,0 +1,55 @@
+## This is the example that optimizes a modified "hello world"
+
+import macros
+
+proc invalidFormatString() =
+  echo "invalidFormatString"
+
+template formatImpl(handleChar: expr) =
+  var i = 0
+  while i < f.len:
+    if f[i] == '$':
+      case f[i+1]
+      of '1'..'9':
+        var j = 0
+        i += 1
+        while f[i] in {'0'..'9'}:
+          j = j * 10 + ord(f[i]) - ord('0')
+          i += 1
+        result.add(a[j-1])
+      else:
+        invalidFormatString()
+    else:
+      result.add(handleChar(f[i]))
+      i += 1
+
+proc `%`*(f: string, a: openArray[string]): string =
+  template identity(x: expr): expr = x
+  result = ""
+  formatImpl(identity)
+
+macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): expr =
+  result = newNimNode(nnkBracket)
+  #newCall("&")
+  let f = f.strVal
+  formatImpl(newLit)
+  result = nestList(!"&", result)
+
+template optAdd1{x = y; add(x, z)}(x, y, z: string) =
+  x = y & z
+
+#template optAdd2{x.add(y); x.add(z)}(x, y, z: string) =
+#  x.add(y & z)
+
+proc `/&` [T: object](x: T): string =
+  result = "("
+  for name, value in fieldPairs(x):
+    result.add("$1: $2\n" % [name, $value])
+  result.add(")")
+
+type
+  MyObject = object
+    a, b: int
+    s: string
+let obj = MyObject(a: 3, b: 4, s: "abc")
+echo(/&obj)
diff --git a/examples/talk/hoisting.nim b/examples/talk/hoisting.nim
new file mode 100644
index 000000000..54e00884f
--- /dev/null
+++ b/examples/talk/hoisting.nim
@@ -0,0 +1,23 @@
+type
+  Regex = distinct string
+
+const maxSubpatterns = 10
+
+proc re(x: string): Regex =
+  result = Regex(x)
+
+proc match(s: string, pattern: Regex, captures: var openArray[string]): bool =
+  true
+
+template optRe{re(x)}(x: string{lit}): Regex =
+  var g {.global.} = re(x)
+  g
+
+template `=~`(s: string, pattern: Regex): bool =
+  when not declaredInScope(matches):
+    var matches {.inject.}: array[maxSubPatterns, string]
+  match(s, pattern, matches)
+
+for line in lines("input.txt"):
+  if line =~ re"(\w+)=(\w+)":
+    echo "key-value pair; key: ", matches[0], " value: ", matches[1]
diff --git a/examples/talk/lazyeval.nim b/examples/talk/lazyeval.nim
new file mode 100644
index 000000000..77d963834
--- /dev/null
+++ b/examples/talk/lazyeval.nim
@@ -0,0 +1,12 @@
+
+const
+  debug = true
+
+template log(msg: string) =
+  if debug:
+    echo msg
+var
+  x = 1
+  y = 2
+
+log("x: " & $x & ", y: " & $y)
diff --git a/examples/talk/quasiquote.nim b/examples/talk/quasiquote.nim
new file mode 100644
index 000000000..df4003e6e
--- /dev/null
+++ b/examples/talk/quasiquote.nim
@@ -0,0 +1,11 @@
+
+import macros
+
+macro check(ex: expr): stmt =
+  var info = ex.lineinfo
+  var expString = ex.toStrLit
+  result = quote do:
+    if not `ex`:
+      echo `info`, ": Check failed: ", `expString`
+
+check 1 < 2
diff --git a/examples/talk/tags.nim b/examples/talk/tags.nim
new file mode 100644
index 000000000..d47b09e07
--- /dev/null
+++ b/examples/talk/tags.nim
@@ -0,0 +1,8 @@
+
+template htmlTag(tag: expr) {.immediate.} =
+  proc tag(): string = "<" & astToStr(tag) & ">"
+  
+htmlTag(br)
+htmlTag(html)
+
+echo br()
diff --git a/examples/transff.nim b/examples/transff.nim
new file mode 100644
index 000000000..32d17e52c
--- /dev/null
+++ b/examples/transff.nim
@@ -0,0 +1,8 @@
+# Shows how to transform a file
+
+import pegs
+
+transformFile("infile.txt", "outfile.txt",
+  [(peg"""S <- {typedesc} \s* {\ident} \s* ','
+         typedesc <- \ident '*'* """, r"$2: $1")])
+
diff --git a/examples/tunit.nim b/examples/tunit.nim
new file mode 100644
index 000000000..d0e975119
--- /dev/null
+++ b/examples/tunit.nim
@@ -0,0 +1,47 @@
+import

+  unittest, macros

+

+var

+    a = 1

+    b = 22

+    c = 1

+    d = 3

+

+suite "my suite":

+  setup:

+    echo "suite setup"

+    var testVar = "from setup"

+    

+  teardown:

+    echo "suite teardown"

+

+  test "first suite test":

+    testVar = "modified"

+    echo "test var: " & testVar

+    check a > b

+

+  test "second suite test":

+    echo "test var: " & testVar

+

+proc foo: bool =

+  echo "running foo"

+  return true

+

+proc err =

+  raise newException(EArithmetic, "some exception")

+

+test "final test":

+  echo "inside suite-less test"

+

+  check:

+    a == c

+    foo()

+    d > 10

+

+test "arithmetic failure":

+  expect(EArithmetic):

+    err()

+

+  expect(EArithmetic, ESystem):

+    discard foo()

+

diff --git a/examples/wingui.nim b/examples/wingui.nim
new file mode 100644
index 000000000..2c2c387bb
--- /dev/null
+++ b/examples/wingui.nim
@@ -0,0 +1,9 @@
+# test a Windows GUI application
+
+import
+  windows, shellapi, nb30, mmsystem, shfolder
+
+#proc MessageBox(hWnd: int, lpText, lpCaption: CString, uType: uint): int
+#  {stdcall, import: "MessageBox", header: "<windows.h>"}
+
+discard MessageBox(0, "Hello World!", "Nimrod GUI Application", 0)
diff --git a/icons/koch.ico b/icons/koch.ico
new file mode 100644
index 000000000..24cdb73a9
--- /dev/null
+++ b/icons/koch.ico
Binary files differdiff --git a/icons/koch.rc b/icons/koch.rc
new file mode 100644
index 000000000..2e5d884dc
--- /dev/null
+++ b/icons/koch.rc
@@ -0,0 +1,3 @@
+kochicon ICON "koch.ico"
+
+
diff --git a/icons/koch.res b/icons/koch.res
new file mode 100644
index 000000000..3b38f7da4
--- /dev/null
+++ b/icons/koch.res
Binary files differdiff --git a/icons/koch_icon.o b/icons/koch_icon.o
new file mode 100644
index 000000000..b780f4d88
--- /dev/null
+++ b/icons/koch_icon.o
Binary files differdiff --git a/icons/nim.ico b/icons/nim.ico
new file mode 100644
index 000000000..58cc4314c
--- /dev/null
+++ b/icons/nim.ico
Binary files differdiff --git a/icons/nim.rc b/icons/nim.rc
new file mode 100644
index 000000000..c053e08e9
--- /dev/null
+++ b/icons/nim.rc
@@ -0,0 +1,3 @@
+nimicon ICON "nim.ico"
+
+
diff --git a/icons/nim.res b/icons/nim.res
new file mode 100644
index 000000000..6eddd053b
--- /dev/null
+++ b/icons/nim.res
Binary files differdiff --git a/icons/nim_icon.o b/icons/nim_icon.o
new file mode 100644
index 000000000..c8c364412
--- /dev/null
+++ b/icons/nim_icon.o
Binary files differdiff --git a/install.sh.template b/install.sh.template
new file mode 100644
index 000000000..1292abdab
--- /dev/null
+++ b/install.sh.template
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -e
+set -x
+
+if [ "$1" != "" ]; then
+	exec ./koch install "$1"
+else
+	exec ./koch install
+fi
diff --git a/install.txt b/install.txt
new file mode 100644
index 000000000..deca55599
--- /dev/null
+++ b/install.txt
@@ -0,0 +1,68 @@
+Installation
+============
+
+Installation on Linux/UNIX
+--------------------------
+
+The GNU C Compiler is fully supported, other compilers may work. The C compiler
+should be in your ``$PATH`` (most likely the case). Note that some few Linux
+distributions do not ship with a GCC compiler preinstalled - then you have to
+install it.
+
+Install Nim by downloading the appropriate ``.zip`` file and extracting it 
+to a directory of your choice. The Nim Compiler will stay in this
+directory (unless you copy it somewhere else). The compiler does not need 
+write access to its directory, so copying the nim folder to ``/opt`` 
+works.
+
+Then run the following command::
+
+  sh build.sh
+
+Unlike other software, Nim does not distribute its files over the whole file
+hierarchy. This has the advantage that you can deinstall it by just deleting
+its folder. The disadvantage is that you have to add it to your ``PATH``
+manually. An alternative is to create a symbolic link in ``/usr/bin``::
+
+  [sudo] ln -s $your_install_dir/bin/nim  /usr/bin/nim
+
+There are also ``install.sh`` and ``deinstall.sh`` scripts for distributing 
+the files over the UNIX hierarchy. However, updating your Nim installation
+is more cumbersome then.
+
+
+Installation on the Macintosh
+-----------------------------
+
+Only MacOS X is supported.
+Since MacOS X is UNIX based too, it works like the installation on Linux. 
+However, for unknown reasons the symbolic link method does not work on MacOS X. 
+You need to install Apple's developer's tools for the GNU Compiler Collection.
+
+
+Installation on Windows
+-----------------------
+
+Install Nim by downloading and running the ``nim_$version.exe`` file.
+As default, the ``GCC`` compiler is used that is bundled with this installer.
+You can change the configuration file ``config/nim.cfg`` to use
+another C compiler or change the path to GCC.
+
+Currently, the following C compilers are supported under Windows:
+
+- | Microsoft's Visual C++
+  | http://msdn.microsoft.com/visualc
+  | (You need the SDK too - but not the full one: Only
+    the win32api header files and import libraries are essential.)
+- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
+  | http://www.mingw.org/download.shtml
+- | LLVM with Clang or GNU C/C++ frontend
+  | http://llvm.org/releases/download.html
+
+However, most testing is done with GCC.
+
+Bootstrapping from Github
+-------------------------
+
+Take a look at the readme file on github `here <https://github.com/Araq/Nim#readme>`_
+for instructions.
diff --git a/koch.nim b/koch.nim
new file mode 100644
index 000000000..fc292401a
--- /dev/null
+++ b/koch.nim
@@ -0,0 +1,383 @@
+#
+#
+#         Maintenance program for Nim
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+#    See doc/koch.txt for documentation.
+#
+
+when defined(gcc) and defined(windows):
+  when defined(x86):
+    {.link: "icons/koch.res".}
+  else:
+    {.link: "icons/koch_icon.o".}
+
+import
+  os, strutils, parseopt, osproc, streams
+
+const VersionAsString = system.NimVersion #"0.10.2"
+
+when defined(withUpdate):
+  import httpclient
+when defined(haveZipLib):
+  import zipfiles
+
+const
+  HelpText = """
++-----------------------------------------------------------------+
+|         Maintenance program for Nim                             |
+|             Version $1|
+|             (c) 2015 Andreas Rumpf                              |
++-----------------------------------------------------------------+
+Build time: $2, $3
+
+Usage:
+  koch [options] command [options for command]
+Options:
+  --help, -h               shows this help and quits
+Possible Commands:
+  boot [options]           bootstraps with given command line options
+  install [bindir]         installs to given directory; Unix only!
+  clean                    cleans Nim project; removes generated files
+  web [options]            generates the website and the full documentation
+  website [options]        generates only the website
+  csource [options]        builds the C sources for installation
+  pdf                      builds the PDF documentation
+  zip                      builds the installation ZIP package
+  xz                       builds the installation XZ package
+  nsis [options]           builds the NSIS Setup installer (for Windows)
+  tests [options]          run the testsuite
+  update                   updates nim to the latest version from github
+                           (compile koch with -d:withUpdate to enable)
+  temp options             creates a temporary compiler for testing
+  winrelease               creates a release (for coredevs only)
+Boot options:
+  -d:release               produce a release version of the compiler
+  -d:tinyc                 include the Tiny C backend (not supported on Windows)
+  -d:useGnuReadline        use the GNU readline library for interactive mode
+                           (not needed on Windows)
+  -d:nativeStacktrace      use native stack traces (only for Mac OS X or Linux)
+  -d:noCaas                build Nim without CAAS support
+  -d:avoidTimeMachine      only for Mac OS X, excludes nimcache dir from backups
+Web options:
+  --googleAnalytics:UA-... add the given google analytics code to the docs. To
+                           build the official docs, use UA-48159761-1
+"""
+
+proc exe(f: string): string = return addFileExt(f, ExeExt)
+
+proc findNim(): string =
+  var nim = "nim".exe
+  result = "bin" / nim
+  if existsFile(result): return
+  for dir in split(getEnv("PATH"), PathSep):
+    if existsFile(dir / nim): return dir / nim
+  # assume there is a symlink to the exe or something:
+  return nim
+
+proc exec(cmd: string, errorcode: int = QuitFailure) =
+  echo(cmd)
+  if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
+
+proc tryExec(cmd: string): bool =
+  echo(cmd)
+  result = execShellCmd(cmd) == 0
+
+proc safeRemove(filename: string) =
+  if existsFile(filename): removeFile(filename)
+
+proc copyExe(source, dest: string) =
+  safeRemove(dest)
+  copyFile(dest=dest, source=source)
+  inclFilePermissions(dest, {fpUserExec})
+
+const
+  compileNimInst = "-d:useLibzipSrc tools/niminst/niminst"
+
+proc csource(args: string) =
+  exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource --main:compiler/nim.nim compiler/installer.ini $1" %
+       [args, VersionAsString, compileNimInst, findNim()])
+
+proc zip(args: string) =
+  exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
+       [VersionAsString, compileNimInst, findNim()])
+  exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim zip compiler/installer.ini" %
+       ["tools/niminst/niminst".exe, VersionAsString])
+
+proc xz(args: string) =
+  exec("$3 cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
+       [VersionAsString, compileNimInst, findNim()])
+  exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim xz compiler/installer.ini" %
+       ["tools" / "niminst" / "niminst".exe, VersionAsString])
+
+proc buildTool(toolname, args: string) =
+  exec("$# cc $# $#" % [findNim(), args, toolname])
+  copyFile(dest="bin"/ splitFile(toolname).name.exe, source=toolname.exe)
+
+proc nsis(args: string) =
+  # make sure we have generated the niminst executables:
+  buildTool("tools/niminst/niminst", args)
+  #buildTool("tools/nimgrep", args)
+  # produce 'nim_debug.exe':
+  #exec "nim c compiler" / "nim.nim"
+  #copyExe("compiler/nim".exe, "bin/nim_debug".exe)
+  exec(("tools" / "niminst" / "niminst --var:version=$# --var:mingw=mingw$#" &
+        " nsis compiler/installer.ini") % [VersionAsString, $(sizeof(pointer)*8)])
+
+proc install(args: string) =
+  exec("$# cc -r $# --var:version=$# --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
+       [findNim(), compileNimInst, VersionAsString])
+  exec("sh ./install.sh $#" % args)
+
+proc web(args: string) =
+  exec("$# cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" %
+       [findNim(), args, VersionAsString])
+
+proc website(args: string) =
+  exec("$# cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" %
+       [findNim(), args, VersionAsString])
+
+proc pdf(args="") =
+  exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" %
+       [findNim(), args, VersionAsString])
+
+# -------------- boot ---------------------------------------------------------
+
+proc findStartNim: string =
+  # we try several things before giving up:
+  # * bin/nim
+  # * $PATH/nim
+  # If these fail, we try to build nim with the "build.(sh|bat)" script.
+  var nim = "nim".exe
+  result = "bin" / nim
+  if existsFile(result): return
+  for dir in split(getEnv("PATH"), PathSep):
+    if existsFile(dir / nim): return dir / nim
+
+  when defined(Posix):
+    const buildScript = "build.sh"
+    if existsFile(buildScript):
+      if tryExec("./" & buildScript): return "bin" / nim
+  else:
+    const buildScript = "build.bat"
+    if existsFile(buildScript):
+      if tryExec(buildScript): return "bin" / nim
+
+  echo("Found no nim compiler and every attempt to build one failed!")
+  quit("FAILURE")
+
+proc thVersion(i: int): string =
+  result = ("compiler" / "nim" & $i).exe
+
+proc boot(args: string) =
+  var output = "compiler" / "nim".exe
+  var finalDest = "bin" / "nim".exe
+  # default to use the 'c' command:
+  let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: ""
+
+  copyExe(findStartNim(), 0.thVersion)
+  for i in 0..2:
+    echo "iteration: ", i+1
+    exec i.thVersion & " $# $# compiler" / "nim.nim" % [bootOptions, args]
+    if sameFileContent(output, i.thVersion):
+      copyExe(output, finalDest)
+      echo "executables are equal: SUCCESS!"
+      return
+    copyExe(output, (i+1).thVersion)
+  copyExe(output, finalDest)
+  when not defined(windows): echo "[Warning] executables are still not equal"
+
+# -------------- clean --------------------------------------------------------
+
+const
+  cleanExt = [
+    ".ppu", ".o", ".obj", ".dcu", ".~pas", ".~inc", ".~dsk", ".~dpr",
+    ".map", ".tds", ".err", ".bak", ".pyc", ".exe", ".rod", ".pdb", ".idb",
+    ".idx", ".ilk"
+  ]
+  ignore = [
+    ".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore"
+  ]
+
+proc cleanAux(dir: string) =
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile:
+      var (dir, name, ext) = splitFile(path)
+      if ext == "" or cleanExt.contains(ext):
+        if not ignore.contains(name):
+          echo "removing: ", path
+          removeFile(path)
+    of pcDir:
+      case splitPath(path).tail
+      of "nimcache":
+        echo "removing dir: ", path
+        removeDir(path)
+      of "dist", ".git", "icons": discard
+      else: cleanAux(path)
+    else: discard
+
+proc removePattern(pattern: string) =
+  for f in walkFiles(pattern):
+    echo "removing: ", f
+    removeFile(f)
+
+proc clean(args: string) =
+  if existsFile("koch.dat"): removeFile("koch.dat")
+  removePattern("web/*.html")
+  removePattern("doc/*.html")
+  cleanAux(getCurrentDir())
+  for kind, path in walkDir(getCurrentDir() / "build"):
+    if kind == pcDir:
+      echo "removing dir: ", path
+      removeDir(path)
+
+# -------------- update -------------------------------------------------------
+
+when defined(withUpdate):
+  when defined(windows):
+    {.warning: "Windows users: Make sure to run 'koch update' in Bash.".}
+
+  proc update(args: string) =
+    when defined(windows):
+      echo("Windows users: Make sure to be running this in Bash. ",
+           "If you aren't, press CTRL+C now.")
+
+    var thisDir = getAppDir()
+    var git = findExe("git")
+    echo("Checking for git repo and git executable...")
+    if existsDir(thisDir & "/.git") and git != "":
+      echo("Git repo found!")
+      # use git to download latest source
+      echo("Checking for updates...")
+      discard startCmd(git & " fetch origin master")
+      var procs = startCmd(git & " diff origin/master master")
+      var errcode = procs.waitForExit()
+      var output = readLine(procs.outputStream)
+      echo(output)
+      if errcode == 0:
+        if output == "":
+          # No changes
+          echo("No update. Exiting...")
+          return
+        else:
+          echo("Fetching updates from repo...")
+          var pullout = execCmdEx(git & " pull origin master")
+          if pullout[1] != 0:
+            quit("An error has occurred.")
+          else:
+            if pullout[0].startsWith("Already up-to-date."):
+              quit("No new changes fetched from the repo. " &
+                   "Local branch must be ahead of it. Exiting...")
+      else:
+        quit("An error has occurred.")
+
+    else:
+      echo("No repo or executable found!")
+      when defined(haveZipLib):
+        echo("Falling back.. Downloading source code from repo...")
+        # use dom96's httpclient to download zip
+        downloadFile("https://github.com/Araq/Nim/zipball/master",
+                     thisDir / "update.zip")
+        try:
+          echo("Extracting source code from archive...")
+          var zip: TZipArchive
+          discard open(zip, thisDir & "/update.zip", fmRead)
+          extractAll(zip, thisDir & "/")
+        except:
+          quit("Error reading archive.")
+      else:
+        quit("No failback available. Exiting...")
+
+    echo("Starting update...")
+    boot(args)
+    echo("Update complete!")
+
+# -------------- builds a release ---------------------------------------------
+
+proc run7z(platform: string, patterns: varargs[string]) =
+  const tmpDir = "nim-" & VersionAsString
+  createDir tmpDir
+  try:
+    for pattern in patterns:
+      for f in walkFiles(pattern):
+        if "nimcache" notin f:
+          copyFile(f, tmpDir / f)
+    exec("7z a -tzip $1-$2.zip $1" % [tmpDir, platform])
+  finally:
+    removeDir tmpDir
+
+proc winRelease() =
+  boot(" -d:release")
+  #buildTool("tools/niminst/niminst", " -d:release")
+  buildTool("tools/nimgrep", " -d:release")
+  buildTool("compiler/nimfix/nimfix", " -d:release")
+  buildTool("compiler/nimsuggest/nimsuggest", " -d:release")
+
+  #run7z("win32", "bin/nim.exe", "bin/c2nim.exe", "bin/nimgrep.exe",
+  #      "bin/nimfix.exe",
+  #      "bin/nimble.exe", "bin/*.dll",
+  #      "config", "dist/*.dll", "examples", "lib",
+  #      "readme.txt", "contributors.txt", "copying.txt")
+
+  # second step: XXX build 64 bit version
+
+# -------------- tests --------------------------------------------------------
+
+template `|`(a, b): expr = (if a.len > 0: a else: b)
+
+proc tests(args: string) =
+  # we compile the tester with taintMode:on to have a basic
+  # taint mode test :-)
+  exec "nim cc --taintMode:on tests/testament/tester"
+  let tester = quoteShell(getCurrentDir() / "tests/testament/tester".exe)
+  let success = tryExec tester & " " & (args|"all")
+  exec tester & " html"
+  if not success:
+    quit("tests failed", QuitFailure)
+
+proc temp(args: string) =
+  var output = "compiler" / "nim".exe
+  var finalDest = "bin" / "nim_temp".exe
+  # 125 is the magic number to tell git bisect to skip the current
+  # commit.
+  exec("nim c compiler" / "nim", 125)
+  copyExe(output, finalDest)
+  if args.len > 0: exec(finalDest & " " & args)
+
+proc showHelp() =
+  quit(HelpText % [VersionAsString & spaces(44-len(VersionAsString)),
+                   CompileDate, CompileTime], QuitSuccess)
+
+var op = initOptParser()
+op.next()
+case op.kind
+of cmdLongOption, cmdShortOption: showHelp()
+of cmdArgument:
+  case normalize(op.key)
+  of "boot": boot(op.cmdLineRest)
+  of "clean": clean(op.cmdLineRest)
+  of "web": web(op.cmdLineRest)
+  of "website": website(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
+  of "web0":
+    # undocumented command for Araq-the-merciful:
+    web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1")
+  of "pdf": pdf()
+  of "csource", "csources": csource(op.cmdLineRest)
+  of "zip": zip(op.cmdLineRest)
+  of "xz": xz(op.cmdLineRest)
+  of "nsis": nsis(op.cmdLineRest)
+  of "install": install(op.cmdLineRest)
+  of "test", "tests": tests(op.cmdLineRest)
+  of "update":
+    when defined(withUpdate):
+      update(op.cmdLineRest)
+    else:
+      quit "this Koch has not been compiled with -d:withUpdate"
+  of "temp": temp(op.cmdLineRest)
+  of "winrelease": winRelease()
+  else: showHelp()
+of cmdEnd: showHelp()
diff --git a/koch.nim.cfg b/koch.nim.cfg
new file mode 100644
index 000000000..1d7acf579
--- /dev/null
+++ b/koch.nim.cfg
@@ -0,0 +1 @@
+-d:booting
\ No newline at end of file
diff --git a/lib/core/locks.nim b/lib/core/locks.nim
new file mode 100644
index 000000000..8a809fc84
--- /dev/null
+++ b/lib/core/locks.nim
@@ -0,0 +1,67 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains Nim's support for locks and condition vars.
+
+include "system/syslocks"
+
+type
+  TLock* = TSysLock ## Nim lock; whether this is re-entrant
+                    ## or not is unspecified!
+  TCond* = TSysCond ## Nim condition variable
+  
+  LockEffect* {.deprecated.} = object of RootEffect ## \
+    ## effect that denotes that some lock operation
+    ## is performed. Deprecated, do not use anymore!
+  AquireEffect* {.deprecated.} = object of LockEffect  ## \
+    ## effect that denotes that some lock is
+    ## acquired. Deprecated, do not use anymore!
+  ReleaseEffect* {.deprecated.} = object of LockEffect ## \
+    ## effect that denotes that some lock is
+    ## released. Deprecated, do not use anymore!
+{.deprecated: [FLock: LockEffect, FAquireLock: AquireEffect, 
+    FReleaseLock: ReleaseEffect].}
+
+proc initLock*(lock: var TLock) {.inline.} =
+  ## Initializes the given lock.
+  initSysLock(lock)
+
+proc deinitLock*(lock: var TLock) {.inline.} =
+  ## Frees the resources associated with the lock.
+  deinitSys(lock)
+
+proc tryAcquire*(lock: var TLock): bool = 
+  ## Tries to acquire the given lock. Returns `true` on success.
+  result = tryAcquireSys(lock)
+
+proc acquire*(lock: var TLock) =
+  ## Acquires the given lock.
+  acquireSys(lock)
+  
+proc release*(lock: var TLock) =
+  ## Releases the given lock.
+  releaseSys(lock)
+
+
+proc initCond*(cond: var TCond) {.inline.} =
+  ## Initializes the given condition variable.
+  initSysCond(cond)
+
+proc deinitCond*(cond: var TCond) {.inline.} =
+  ## Frees the resources associated with the lock.
+  deinitSysCond(cond)
+
+proc wait*(cond: var TCond, lock: var TLock) {.inline.} =
+  ## waits on the condition variable `cond`. 
+  waitSysCond(cond, lock)
+  
+proc signal*(cond: var TCond) {.inline.} =
+  ## sends a signal to the condition variable `cond`. 
+  signalSysCond(cond)
+
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
new file mode 100644
index 000000000..7e6e4ccc9
--- /dev/null
+++ b/lib/core/macros.nim
@@ -0,0 +1,845 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+include "system/inclrtl"
+
+## This module contains the interface to the compiler's abstract syntax
+## tree (`AST`:idx:). Macros operate on this tree.
+
+## .. include:: ../doc/astspec.txt
+
+type
+  NimNodeKind* = enum
+    nnkNone, nnkEmpty, nnkIdent, nnkSym,
+    nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
+    nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
+    nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
+    nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
+    nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
+    nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
+    nnkPrefix, nnkPostfix, nnkHiddenCallConv,
+    nnkExprEqExpr,
+    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
+    nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
+    nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
+    nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
+    nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,
+    nnkTableConstr, nnkBind,
+    nnkClosedSymChoice,
+    nnkOpenSymChoice,
+    nnkHiddenStdConv,
+    nnkHiddenSubConv, nnkConv, nnkCast, nnkStaticExpr,
+    nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
+    nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
+    nnkStringToCString, nnkCStringToString, nnkAsgn,
+    nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
+    nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef,
+    nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
+    nnkElifBranch, nnkExceptBranch, nnkElse,
+    nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
+    nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
+    nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
+    nnkConstDef, nnkTypeDef,
+    nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
+    nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
+    nnkDiscardStmt, nnkStmtList,
+    nnkImportStmt,
+    nnkImportExceptStmt,
+    nnkExportStmt,
+    nnkExportExceptStmt,
+    nnkFromStmt,
+    nnkIncludeStmt,
+    nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
+    nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
+    nnkStmtListType, nnkBlockType,
+    nnkWith, nnkWithout,
+    nnkTypeOfExpr, nnkObjectTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
+    nnkRecList, nnkRecCase, nnkRecWhen,
+    nnkRefTy, nnkPtrTy, nnkVarTy,
+    nnkConstTy, nnkMutableTy,
+    nnkDistinctTy,
+    nnkProcTy,
+    nnkIteratorTy,         # iterator type
+    nnkSharedTy,           # 'shared T'
+    nnkEnumTy,
+    nnkEnumFieldDef,
+    nnkArglist, nnkPattern
+    nnkReturnToken
+  NimNodeKinds* = set[NimNodeKind]
+  NimTypeKind* = enum
+    ntyNone, ntyBool, ntyChar, ntyEmpty,
+    ntyArrayConstr, ntyNil, ntyExpr, ntyStmt,
+    ntyTypeDesc, ntyGenericInvocation, ntyGenericBody, ntyGenericInst,
+    ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal,
+    ntyArray, ntyObject, ntyTuple, ntySet,
+    ntyRange, ntyPtr, ntyRef, ntyVar,
+    ntySequence, ntyProc, ntyPointer, ntyOpenArray,
+    ntyString, ntyCString, ntyForward, ntyInt,
+    ntyInt8, ntyInt16, ntyInt32, ntyInt64,
+    ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128,
+    ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64,
+    ntyBigNum,
+    ntyConst, ntyMutable, ntyVarargs,
+    ntyIter,
+    ntyError,
+    ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite,
+    ntyAnd, ntyOr, ntyNot
+
+  TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
+  NimSymKind* = enum
+    nskUnknown, nskConditional, nskDynLib, nskParam,
+    nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet,
+    nskConst, nskResult,
+    nskProc, nskMethod, nskIterator, nskClosureIterator,
+    nskConverter, nskMacro, nskTemplate, nskField,
+    nskEnumField, nskForVar, nskLabel,
+    nskStub
+
+  TNimSymKinds* {.deprecated.} = set[NimSymKind]
+
+type
+  NimIdent* = object of RootObj
+    ## represents a Nim identifier in the AST
+
+  NimSymObj = object # hidden
+  NimSym* = ref NimSymObj
+    ## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
+    ## *ident*.
+
+{.deprecated: [TNimrodNodeKind: NimNodeKind, TNimNodeKinds: NimNodeKinds,
+    TNimrodTypeKind: NimTypeKind, TNimrodSymKind: NimSymKind,
+    TNimrodIdent: NimIdent, PNimrodSymbol: NimSym].}
+
+const
+  nnkLiterals* = {nnkCharLit..nnkNilLit}
+  nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
+                   nnkCallStrLit}
+
+proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
+  ## get `n`'s `i`'th child.
+
+proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
+  noSideEffect.}
+  ## set `n`'s `i`'th child to `child`.
+
+proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
+  ## constructs an identifier from the string `s`
+
+proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.}
+  ## converts a Nim identifier to a string
+
+proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.}
+  ## converts a Nim symbol to a string
+
+proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.}
+  ## compares two Nim identifiers
+
+proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
+  ## compares two Nim nodes
+
+proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
+  ## returns the number of children of `n`.
+
+proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
+  noSideEffect, locks: 0.}
+  ## Adds the `child` to the `father` node. Returns the
+  ## father node so that calls can be nested.
+
+proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
+  magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
+  ## Adds each child of `children` to the `father` node.
+  ## Returns the `father` node so that calls can be nested.
+
+proc del*(father: NimNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
+  ## deletes `n` children of `father` starting at index `idx`.
+
+proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
+  ## returns the `kind` of the node `n`.
+
+proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
+proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = n.intVal != 0
+proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
+proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
+proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
+
+proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
+  ## with 'getType' you can access the node's `type`:idx:. A Nim type is
+  ## mapped to a Nim AST too, so it's slightly confusing but it means the same
+  ## API can be used to traverse types. Recursive types are flattened for you
+  ## so there is no danger of infinite recursions during traversal. To
+  ## resolve recursive types, you have to call 'getType' again. To see what
+  ## kind of type it is, call `typeKind` on getType's result.
+
+proc getType*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
+  ## Returns the Nim type node for given type. This can be used to turn macro
+  ## typedesc parameter into proper NimNode representing type, since typedesc
+  ## are an exception in macro calls - they are not mapped implicitly to
+  ## NimNode like any other arguments.
+
+proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
+  ## Returns the type kind of the node 'n' that should represent a type, that
+  ## means the node should have been obtained via `getType`.
+
+proc strVal*(n: NimNode): string  {.magic: "NStrVal", noSideEffect.}
+
+proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
+proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
+proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.}
+proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
+#proc `typ=`*(n: NimNode, typ: typedesc) {.magic: "NSetType".}
+# this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
+# can easily do:
+#   let bracket = semCheck([1, 2])
+#   let fake = semCheck(2.0)
+#   bracket[0] = fake  # constructs a mixed array with ints and floats!
+
+proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
+
+proc newNimNode*(kind: NimNodeKind,
+                 n: NimNode=nil): NimNode {.magic: "NNewNimNode", noSideEffect.}
+
+proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
+proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
+
+proc error*(msg: string) {.magic: "NError", benign.}
+  ## writes an error message at compile time
+
+proc warning*(msg: string) {.magic: "NWarning", benign.}
+  ## writes a warning message at compile time
+
+proc hint*(msg: string) {.magic: "NHint", benign.}
+  ## writes a hint message at compile time
+
+proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
+  ## creates a string literal node from `s`
+  result = newNimNode(nnkStrLit)
+  result.strVal = s
+
+proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
+  ## creates a int literal node from `i`
+  result = newNimNode(nnkIntLit)
+  result.intVal = i
+
+proc newFloatLitNode*(f: BiggestFloat): NimNode {.compileTime.} =
+  ## creates a float literal node from `f`
+  result = newNimNode(nnkFloatLit)
+  result.floatVal = f
+
+proc newIdentNode*(i: NimIdent): NimNode {.compileTime.} =
+  ## creates an identifier node from `i`
+  result = newNimNode(nnkIdent)
+  result.ident = i
+
+proc newIdentNode*(i: string): NimNode {.compileTime.} =
+  ## creates an identifier node from `i`
+  result = newNimNode(nnkIdent)
+  result.ident = !i
+
+type
+  BindSymRule* = enum    ## specifies how ``bindSym`` behaves
+    brClosed,            ## only the symbols in current scope are bound
+    brOpen,              ## open wrt overloaded symbols, but may be a single
+                         ## symbol if not ambiguous (the rules match that of
+                         ## binding in generics)
+    brForceOpen          ## same as brOpen, but it will always be open even
+                         ## if not ambiguous (this cannot be achieved with
+                         ## any other means in the language currently)
+
+{.deprecated: [TBindSymRule: BindSymRule].}
+
+proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {.
+              magic: "NBindSym", noSideEffect.}
+  ## creates a node that binds `ident` to a symbol node. The bound symbol
+  ## may be an overloaded symbol.
+  ## If ``rule == brClosed`` either an ``nkClosedSymChoice`` tree is
+  ## returned or ``nkSym`` if the symbol is not ambiguous.
+  ## If ``rule == brOpen`` either an ``nkOpenSymChoice`` tree is
+  ## returned or ``nkSym`` if the symbol is not ambiguous.
+  ## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
+  ## returned even if the symbol is not ambiguous.
+
+proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
+  magic: "NGenSym", noSideEffect.}
+  ## generates a fresh symbol that is guaranteed to be unique. The symbol
+  ## needs to occur in a declaration context.
+
+proc callsite*(): NimNode {.magic: "NCallSite", benign.}
+  ## returns the AST of the invocation expression that invoked this macro.
+
+proc toStrLit*(n: NimNode): NimNode {.compileTime.} =
+  ## converts the AST `n` to the concrete Nim code and wraps that
+  ## in a string literal node
+  return newStrLitNode(repr(n))
+
+proc lineinfo*(n: NimNode): string {.magic: "NLineInfo", noSideEffect.}
+  ## returns the position the node appears in the original source file
+  ## in the form filename(line, col)
+
+proc internalParseExpr(s: string): NimNode {.
+  magic: "ParseExprToAst", noSideEffect.}
+
+proc internalParseStmt(s: string): NimNode {.
+  magic: "ParseStmtToAst", noSideEffect.}
+
+proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.}
+  ## Some builtins set an error flag. This is then turned into a proper
+  ## exception. **Note**: Ordinary application code should not call this.
+
+proc parseExpr*(s: string): NimNode {.noSideEffect, compileTime.} =
+  ## Compiles the passed string to its AST representation.
+  ## Expects a single expression. Raises ``ValueError`` for parsing errors.
+  result = internalParseExpr(s)
+  let x = internalErrorFlag()
+  if x.len > 0: raise newException(ValueError, x)
+
+proc parseStmt*(s: string): NimNode {.noSideEffect, compileTime.} =
+  ## Compiles the passed string to its AST representation.
+  ## Expects one or more statements. Raises ``ValueError`` for parsing errors.
+  result = internalParseStmt(s)
+  let x = internalErrorFlag()
+  if x.len > 0: raise newException(ValueError, x)
+
+proc getAst*(macroOrTemplate: expr): NimNode {.magic: "ExpandToAst", noSideEffect.}
+  ## Obtains the AST nodes returned from a macro or template invocation.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   macro FooMacro() =
+  ##     var ast = getAst(BarTemplate())
+
+proc quote*(bl: stmt, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
+  ## Quasi-quoting operator.
+  ## Accepts an expression or a block and returns the AST that represents it.
+  ## Within the quoted AST, you are able to interpolate NimNode expressions
+  ## from the surrounding scope. If no operator is given, quoting is done using
+  ## backticks. Otherwise, the given operator must be used as a prefix operator
+  ## for any interpolated expression. The original meaning of the interpolation
+  ## operator may be obtained by escaping it (by prefixing it with itself):
+  ## e.g. `@` is escaped as `@@`, `@@` is escaped as `@@@` and so on.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   macro check(ex: expr): stmt =
+  ##     # this is a simplified version of the check macro from the
+  ##     # unittest module.
+  ##
+  ##     # If there is a failed check, we want to make it easy for
+  ##     # the user to jump to the faulty line in the code, so we
+  ##     # get the line info here:
+  ##     var info = ex.lineinfo
+  ##
+  ##     # We will also display the code string of the failed check:
+  ##     var expString = ex.toStrLit
+  ##
+  ##     # Finally we compose the code to implement the check:
+  ##     result = quote do:
+  ##       if not `ex`:
+  ##         echo `info` & ": Check failed: " & `expString`
+
+proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} =
+  ## checks that `n` is of kind `k`. If this is not the case,
+  ## compilation aborts with an error message. This is useful for writing
+  ## macros that check the AST that is passed to them.
+  if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind)
+
+proc expectMinLen*(n: NimNode, min: int) {.compileTime.} =
+  ## checks that `n` has at least `min` children. If this is not the case,
+  ## compilation aborts with an error message. This is useful for writing
+  ## macros that check its number of arguments.
+  if n.len < min: error("macro expects a node with " & $min & " children")
+
+proc expectLen*(n: NimNode, len: int) {.compileTime.} =
+  ## checks that `n` has exactly `len` children. If this is not the case,
+  ## compilation aborts with an error message. This is useful for writing
+  ## macros that check its number of arguments.
+  if n.len != len: error("macro expects a node with " & $len & " children")
+
+proc newTree*(kind: NimNodeKind,
+              children: varargs[NimNode]): NimNode {.compileTime.} =
+  ## produces a new node with children.
+  result = newNimNode(kind)
+  result.add(children)
+
+proc newCall*(theProc: NimNode,
+              args: varargs[NimNode]): NimNode {.compileTime.} =
+  ## produces a new call node. `theProc` is the proc that is called with
+  ## the arguments ``args[0..]``.
+  result = newNimNode(nnkCall)
+  result.add(theProc)
+  result.add(args)
+
+proc newCall*(theProc: NimIdent,
+              args: varargs[NimNode]): NimNode {.compileTime.} =
+  ## 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)
+
+proc newCall*(theProc: string,
+              args: varargs[NimNode]): NimNode {.compileTime.} =
+  ## 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)
+
+proc newLit*(c: char): NimNode {.compileTime.} =
+  ## produces a new character literal node.
+  result = newNimNode(nnkCharLit)
+  result.intVal = ord(c)
+
+proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
+  ## produces a new integer literal node.
+  result = newNimNode(nnkIntLit)
+  result.intVal = i
+
+proc newLit*(b: bool): NimNode {.compileTime.} =
+  ## produces a new boolean literal node.
+  result = newNimNode(nnkIntLit)
+  result.intVal = ord(b)
+
+proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
+  ## produces a new float literal node.
+  result = newNimNode(nnkFloatLit)
+  result.floatVal = f
+
+proc newLit*(s: string): NimNode {.compileTime.} =
+  ## produces a new string literal node.
+  result = newNimNode(nnkStrLit)
+  result.strVal = s
+
+proc nestList*(theProc: NimIdent,
+               x: NimNode): NimNode {.compileTime.} =
+  ## nests the list `x` into a tree of call expressions:
+  ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
+  var L = x.len
+  result = newCall(theProc, x[L-2], x[L-1])
+  for i in countdown(L-3, 0):
+    # XXX the 'copyNimTree' here is necessary due to a bug in the evaluation
+    # engine that would otherwise create an endless loop here. :-(
+    # This could easily user code and so should be fixed in evals.nim somehow.
+    result = newCall(theProc, x[i], copyNimTree(result))
+
+proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
+  ## Convert the AST `n` to a human-readable tree-like string.
+  ##
+  ## See also `repr` and `lispRepr`.
+  proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
+    for i in 0..level-1: res.add "  "
+    res.add(($n.kind).substr(3))
+
+    case n.kind
+    of nnkEmpty: discard # same as nil node in this representation
+    of nnkNilLit: res.add(" nil")
+    of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
+    of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
+    of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
+    of nnkIdent: res.add(" !\"" & $n.ident & '"')
+    of nnkSym: res.add(" \"" & $n.symbol & '"')
+    of nnkNone: assert false
+    else:
+      for j in 0..n.len-1:
+        res.add "\n"
+        traverse(res, level + 1, n[j])
+
+  result = ""
+  traverse(result, 0, n)
+
+proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
+  ## Convert the AST `n` to a human-readable lisp-like string,
+  ##
+  ## See also `repr` and `treeRepr`.
+
+  result = ($n.kind).substr(3)
+  add(result, "(")
+
+  case n.kind
+  of nnkEmpty: discard # same as nil node in this representation
+  of nnkNilLit: add(result, "nil")
+  of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
+  of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
+  of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
+  of nnkIdent: add(result, "!\"" & $n.ident & '"')
+  of nnkSym: add(result, $n.symbol)
+  of nnkNone: assert false
+  else:
+    if n.len > 0:
+      add(result, lispRepr(n[0]))
+      for j in 1..n.len-1:
+        add(result, ", ")
+        add(result, lispRepr(n[j]))
+
+  add(result, ")")
+
+macro dumpTree*(s: stmt): stmt {.immediate.} = echo s.treeRepr
+  ## Accepts a block of nim code and prints the parsed abstract syntax
+  ## tree using the `toTree` function. Printing is done *at compile time*.
+  ##
+  ## You can use this as a tool to explore the Nimrod's abstract syntax
+  ## tree and to discover what kind of nodes must be created to represent
+  ## a certain expression/statement.
+
+macro dumpLisp*(s: stmt): stmt {.immediate.} = echo s.lispRepr
+  ## Accepts a block of nim code and prints the parsed abstract syntax
+  ## tree using the `toLisp` function. Printing is done *at compile time*.
+  ##
+  ## See `dumpTree`.
+
+macro dumpTreeImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.treeRepr
+  ## The ``immediate`` version of `dumpTree`.
+
+macro dumpLispImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.lispRepr
+  ## The ``immediate`` version of `dumpLisp`.
+
+
+proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
+  ## Create a new empty node
+  result = newNimNode(nnkEmpty)
+
+proc newStmtList*(stmts: varargs[NimNode]): NimNode {.compileTime.}=
+  ## Create a new statement list
+  result = newNimNode(nnkStmtList).add(stmts)
+
+proc newPar*(exprs: varargs[NimNode]): NimNode {.compileTime.}=
+  ## Create a new parentheses-enclosed expression
+  newNimNode(nnkPar).add(exprs)
+
+proc newBlockStmt*(label, body: NimNode): NimNode {.compileTime.} =
+  ## Create a new block statement with label
+  return newNimNode(nnkBlockStmt).add(label, body)
+
+proc newBlockStmt*(body: NimNode): NimNode {.compiletime.} =
+  ## Create a new block: stmt
+  return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
+
+proc newVarStmt*(name, value: NimNode): NimNode {.compiletime.} =
+  ## Create a new var stmt
+  return newNimNode(nnkVarSection).add(
+    newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
+
+proc newLetStmt*(name, value: NimNode): NimNode {.compiletime.} =
+  ## Create a new let stmt
+  return newNimNode(nnkLetSection).add(
+    newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
+
+proc newConstStmt*(name, value: NimNode): NimNode {.compileTime.} =
+  ## Create a new const stmt
+  newNimNode(nnkConstSection).add(
+    newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
+
+proc newAssignment*(lhs, rhs: NimNode): NimNode {.compileTime.} =
+  return newNimNode(nnkAsgn).add(lhs, rhs)
+
+proc newDotExpr*(a, b: NimNode): NimNode {.compileTime.} =
+  ## Create new dot expression
+  ## a.dot(b) ->  `a.b`
+  return newNimNode(nnkDotExpr).add(a, b)
+
+proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} =
+  ## Create new colon expression
+  ## newColonExpr(a, b) ->  `a: b`
+  newNimNode(nnkExprColonExpr).add(a, b)
+
+proc newIdentDefs*(name, kind: NimNode;
+                   default = newEmptyNode()): NimNode {.compileTime.} =
+  ## Creates a new ``nnkIdentDefs`` node of a specific kind and value.
+  ##
+  ## ``nnkIdentDefs`` need to have at least three children, but they can have
+  ## more: first comes a list of identifiers followed by a type and value
+  ## nodes. This helper proc creates a three node subtree, the first subnode
+  ## being a single identifier name. Both the ``kind`` node and ``default``
+  ## (value) nodes may be empty depending on where the ``nnkIdentDefs``
+  ## appears: tuple or object definitions will have an empty ``default`` node,
+  ## ``let`` or ``var`` blocks may have an empty ``kind`` node if the
+  ## identifier is being assigned a value. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   var varSection = newNimNode(nnkVarSection).add(
+  ##     newIdentDefs(ident("a"), ident("string")),
+  ##     newIdentDefs(ident("b"), newEmptyNode(), newLit(3)))
+  ##   # --> var
+  ##   #       a: string
+  ##   #       b = 3
+  ##
+  ## If you need to create multiple identifiers you need to use the lower level
+  ## ``newNimNode``:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   result = newNimNode(nnkIdentDefs).add(
+  ##     ident("a"), ident("b"), ident("c"), ident("string"),
+  ##       newStrLitNode("Hello"))
+  newNimNode(nnkIdentDefs).add(name, kind, default)
+
+proc newNilLit*(): NimNode {.compileTime.} =
+  ## New nil literal shortcut
+  result = newNimNode(nnkNilLit)
+
+proc high*(node: NimNode): int {.compileTime.} = len(node) - 1
+  ## Return the highest index available for a node
+proc last*(node: NimNode): NimNode {.compileTime.} = node[node.high]
+  ## Return the last item in nodes children. Same as `node[node.high()]`
+
+
+const
+  RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef}
+  AtomicNodes* = {nnkNone..nnkNilLit}
+  CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
+    nnkCallStrLit, nnkHiddenCallConv}
+
+proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
+  assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind
+
+proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()];
+    body: NimNode = newStmtList(), procType = nnkProcDef): NimNode {.compileTime.} =
+  ## shortcut for creating a new proc
+  ##
+  ## The ``params`` array must start with the return type of the proc,
+  ## followed by a list of IdentDefs which specify the params.
+  assert procType in RoutineNodes
+  result = newNimNode(procType).add(
+    name,
+    newEmptyNode(),
+    newEmptyNode(),
+    newNimNode(nnkFormalParams).add(params), ##params
+    newEmptyNode(),  ## pragmas
+    newEmptyNode(),
+    body)
+
+proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
+                NimNode {.compiletime.} =
+  ## Constructor for ``if`` statements.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##    newIfStmt(
+  ##      (Ident, StmtList),
+  ##      ...
+  ##    )
+  ##
+  result = newNimNode(nnkIfStmt)
+  for i in branches:
+    result.add(newNimNode(nnkElifBranch).add(i.cond, i.body))
+
+
+proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
+  ## Copy all children from `src` to `dest`
+  for i in 0 .. < src.len:
+    dest.add src[i].copyNimTree
+
+template expectRoutine(node: NimNode): stmt =
+  expectKind(node, RoutineNodes)
+
+proc name*(someProc: NimNode): NimNode {.compileTime.} =
+  someProc.expectRoutine
+  result = someProc[0]
+proc `name=`*(someProc: NimNode; val: NimNode) {.compileTime.} =
+  someProc.expectRoutine
+  someProc[0] = val
+
+proc params*(someProc: NimNode): NimNode {.compileTime.} =
+  someProc.expectRoutine
+  result = someProc[3]
+proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}=
+  someProc.expectRoutine
+  assert params.kind == nnkFormalParams
+  someProc[3] = params
+
+proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
+  ## Get the pragma of a proc type
+  ## These will be expanded
+  someProc.expectRoutine
+  result = someProc[4]
+proc `pragma=`*(someProc: NimNode; val: NimNode){.compileTime.}=
+  ## Set the pragma of a proc type
+  someProc.expectRoutine
+  assert val.kind in {nnkEmpty, nnkPragma}
+  someProc[4] = val
+
+
+template badNodeKind(k; f): stmt{.immediate.} =
+  assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`"
+
+proc body*(someProc: NimNode): NimNode {.compileTime.} =
+  case someProc.kind:
+  of RoutineNodes:
+    return someProc[6]
+  of nnkBlockStmt, nnkWhileStmt:
+    return someProc[1]
+  of nnkForStmt:
+    return someProc.last
+  else:
+    badNodeKind someProc.kind, "body"
+
+proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
+  case someProc.kind
+  of RoutineNodes:
+    someProc[6] = val
+  of nnkBlockStmt, nnkWhileStmt:
+    someProc[1] = val
+  of nnkForStmt:
+    someProc[high(someProc)] = val
+  else:
+    badNodeKind someProc.kind, "body="
+
+proc basename*(a: NimNode): NimNode {.compiletime, benign.}
+
+
+proc `$`*(node: NimNode): string {.compileTime.} =
+  ## Get the string of an identifier node
+  case node.kind
+  of nnkIdent:
+    result = $node.ident
+  of nnkPostfix:
+    result = $node.basename.ident & "*"
+  of nnkStrLit..nnkTripleStrLit:
+    result = node.strVal
+  of nnkSym:
+    result = $node.symbol
+  else:
+    badNodeKind node.kind, "$"
+
+proc ident*(name: string): NimNode {.compileTime,inline.} = newIdentNode(name)
+  ## Create a new ident node from a string
+
+iterator children*(n: NimNode): NimNode {.inline.}=
+  for i in 0 .. high(n):
+    yield n[i]
+
+template findChild*(n: NimNode; cond: expr): NimNode {.
+  immediate, dirty.} =
+  ## Find the first child node matching condition (or nil).
+  ##
+  ## .. code-block:: nim
+  ##   var res = findChild(n, it.kind == nnkPostfix and
+  ##                          it.basename.ident == !"foo")
+  block:
+    var result: NimNode
+    for it in n.children:
+      if cond:
+        result = it
+        break
+    result
+
+proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
+  ## Insert node B into A at pos
+  if high(a) < pos:
+    ## add some empty nodes first
+    for i in high(a)..pos-2:
+      a.add newEmptyNode()
+    a.add b
+  else:
+    ## push the last item onto the list again
+    ## and shift each item down to pos up one
+    a.add(a[a.high])
+    for i in countdown(high(a) - 2, pos):
+      a[i + 1] = a[i]
+    a[pos] = b
+
+proc basename*(a: NimNode): NimNode =
+  ## Pull an identifier from prefix/postfix expressions
+  case a.kind
+  of nnkIdent: return a
+  of nnkPostfix, nnkPrefix: return a[1]
+  else:
+    quit "Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a)
+
+proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
+  case a.kind
+  of nnkIdent: macros.`ident=`(a,  !val)
+  of nnkPostfix, nnkPrefix: a[1] = ident(val)
+  else:
+    quit "Do not know how to get basename of (" & treeRepr(a) & ")\n" & repr(a)
+
+proc postfix*(node: NimNode; op: string): NimNode {.compileTime.} =
+  newNimNode(nnkPostfix).add(ident(op), node)
+
+proc prefix*(node: NimNode; op: string): NimNode {.compileTime.} =
+  newNimNode(nnkPrefix).add(ident(op), node)
+
+proc infix*(a: NimNode; op: string;
+            b: NimNode): NimNode {.compileTime.} =
+  newNimNode(nnkInfix).add(ident(op), a, b)
+
+proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
+  compileTime.} =
+  node.expectKind nnkPostfix
+  result = (node[0], $node[1])
+
+proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
+  compileTime.} =
+  node.expectKind nnkPrefix
+  result = (node[0], $node[1])
+
+proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
+                                        right: NimNode] {.compileTime.} =
+  assert node.kind == nnkInfix
+  result = (node[0], $node[1], node[2])
+
+proc copy*(node: NimNode): NimNode {.compileTime.} =
+  ## An alias for copyNimTree().
+  return node.copyNimTree()
+
+proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
+  proc toLower(c: char): char {.inline.} =
+    if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
+    else: result = c
+  var i = 0
+  var j = 0
+  while true:
+    while a[i] == '_': inc(i)
+    while b[j] == '_': inc(j) # BUGFIX: typo
+    var aa = toLower(a[i])
+    var bb = toLower(b[j])
+    result = ord(aa) - ord(bb)
+    if result != 0 or aa == '\0': break
+    inc(i)
+    inc(j)
+
+proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
+  ## Check if two idents are identical.
+
+proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
+  ## Search nnkFormalParams for an argument.
+  assert params.kind == nnkFormalParams
+  for i in 1 .. <params.len:
+    template node: expr = params[i]
+    if name.eqIdent( $ node[0]):
+      return true
+
+proc addIdentIfAbsent*(dest: NimNode, ident: string) {.compiletime.} =
+  ## Add ident to dest if it is not present. This is intended for use
+  ## with pragmas.
+  for node in dest.children:
+    case node.kind
+    of nnkIdent:
+      if ident.eqIdent($node): return
+    of nnkExprColonExpr:
+      if ident.eqIdent($node[0]): return
+    else: discard
+  dest.add(ident(ident))
+
+when not defined(booting):
+  template emit*(e: static[string]): stmt =
+    ## accepts a single string argument and treats it as nim code
+    ## that should be inserted verbatim in the program
+    ## Example:
+    ##
+    ## .. code-block:: nim
+    ##   emit("echo " & '"' & "hello world".toUpper & '"')
+    ##
+    macro payload: stmt {.gensym.} =
+      result = parseStmt(e)
+    payload()
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
new file mode 100644
index 000000000..c3ff66591
--- /dev/null
+++ b/lib/core/typeinfo.nim
@@ -0,0 +1,702 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Dominik Picheta, Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements an interface to Nim's `runtime type information`:idx:
+## (`RTTI`:idx:).
+## Note that even though ``TAny`` and its operations hide the nasty low level
+## details from its clients, it remains inherently unsafe!
+##
+## See the `marshal <marshal.html>`_ module for what this module allows you
+## to do. 
+
+{.push hints: off.}
+
+include "system/inclrtl.nim"
+include "system/hti.nim"
+
+{.pop.}
+
+type
+  TAnyKind* = enum      ## what kind of ``any`` it is
+    akNone = 0,         ## invalid any
+    akBool = 1,         ## any represents a ``bool``
+    akChar = 2,         ## any represents a ``char``
+    akEnum = 14,        ## any represents an enum
+    akArray = 16,       ## any represents an array
+    akObject = 17,      ## any represents an object
+    akTuple = 18,       ## any represents a tuple
+    akSet = 19,         ## any represents a set
+    akRange = 20,       ## any represents a range
+    akPtr = 21,         ## any represents a ptr
+    akRef = 22,         ## any represents a ref
+    akSequence = 24,    ## any represents a sequence
+    akProc = 25,        ## any represents a proc
+    akPointer = 26,     ## any represents a pointer
+    akString = 28,      ## any represents a string
+    akCString = 29,     ## any represents a cstring
+    akInt = 31,         ## any represents an int
+    akInt8 = 32,        ## any represents an int8
+    akInt16 = 33,       ## any represents an int16
+    akInt32 = 34,       ## any represents an int32
+    akInt64 = 35,       ## any represents an int64
+    akFloat = 36,       ## any represents a float
+    akFloat32 = 37,     ## any represents a float32
+    akFloat64 = 38,     ## any represents a float64
+    akFloat128 = 39,    ## any represents a float128
+    akUInt = 40,        ## any represents an unsigned int
+    akUInt8 = 41,       ## any represents an unsigned int8
+    akUInt16 = 42,      ## any represents an unsigned in16
+    akUInt32 = 43,      ## any represents an unsigned int32
+    akUInt64 = 44,      ## any represents an unsigned int64
+    
+  TAny* = object          ## can represent any nim value; NOTE: the wrapped
+                          ## value can be modified with its wrapper! This means
+                          ## that ``TAny`` keeps a non-traced pointer to its
+                          ## wrapped value and **must not** live longer than
+                          ## its wrapped value.
+    value: pointer
+    rawType: PNimType
+
+  ppointer = ptr pointer
+  pbyteArray = ptr array[0.. 0xffff, int8]
+
+  TGenericSeq {.importc.} = object
+    len, space: int
+  PGenSeq = ptr TGenericSeq
+
+const
+  GenericSeqSize = (2 * sizeof(int))
+
+proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.}
+proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.
+  importCompilerProc.}
+proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importCompilerProc.}
+proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
+proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
+proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.}
+
+template `+!!`(a, b: expr): expr = cast[pointer](cast[ByteAddress](a) + b)
+
+proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
+  assert(n.kind == nkCase)
+  var d: int
+  var a = cast[ByteAddress](aa)
+  case n.typ.size
+  of 1: d = ze(cast[ptr int8](a +% n.offset)[])
+  of 2: d = ze(cast[ptr int16](a +% n.offset)[])
+  of 4: d = int(cast[ptr int32](a +% n.offset)[])
+  else: assert(false)
+  return d
+
+proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
+  var discr = getDiscriminant(aa, n)
+  if discr <% n.len:
+    result = n.sons[discr]
+    if result == nil: result = n.sons[n.len]
+    # n.sons[n.len] contains the ``else`` part (but may be nil)
+  else:
+    result = n.sons[n.len]
+
+proc newAny(value: pointer, rawType: PNimType): TAny =
+  result.value = value
+  result.rawType = rawType
+
+when declared(system.TVarSlot):
+  proc toAny*(x: TVarSlot): TAny {.inline.} =
+    ## constructs a ``TAny`` object from a variable slot ``x``. 
+    ## This captures `x`'s address, so `x` can be modified with its
+    ## ``TAny`` wrapper! The client needs to ensure that the wrapper
+    ## **does not** live longer than `x`!
+    ## This is provided for easier reflection capabilities of a debugger.
+    result.value = x.address
+    result.rawType = x.typ
+
+proc toAny*[T](x: var T): TAny {.inline.} =
+  ## constructs a ``TAny`` object from `x`. This captures `x`'s address, so
+  ## `x` can be modified with its ``TAny`` wrapper! The client needs to ensure
+  ## that the wrapper **does not** live longer than `x`!
+  result.value = addr(x)
+  result.rawType = cast[PNimType](getTypeInfo(x))
+  
+proc kind*(x: TAny): TAnyKind {.inline.} = 
+  ## get the type kind
+  result = TAnyKind(ord(x.rawType.kind))
+
+proc size*(x: TAny): int {.inline.} =
+  ## returns the size of `x`'s type.
+  result = x.rawType.size
+  
+proc baseTypeKind*(x: TAny): TAnyKind {.inline.} = 
+  ## get the base type's kind; ``akNone`` is returned if `x` has no base type.
+  if x.rawType.base != nil:
+    result = TAnyKind(ord(x.rawType.base.kind))
+
+proc baseTypeSize*(x: TAny): int {.inline.} =
+  ## returns the size of `x`'s basetype.
+  if x.rawType.base != nil:
+    result = x.rawType.base.size
+  
+proc invokeNew*(x: TAny) =
+  ## performs ``new(x)``. `x` needs to represent a ``ref``.
+  assert x.rawType.kind == tyRef
+  var z = newObj(x.rawType, x.rawType.base.size)
+  genericAssign(x.value, addr(z), x.rawType)
+
+proc invokeNewSeq*(x: TAny, len: int) =
+  ## performs ``newSeq(x, len)``. `x` needs to represent a ``seq``.
+  assert x.rawType.kind == tySequence
+  var z = newSeq(x.rawType, len)
+  genericShallowAssign(x.value, addr(z), x.rawType)
+
+proc extendSeq*(x: TAny) =
+  ## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
+  assert x.rawType.kind == tySequence
+  var y = cast[ptr PGenSeq](x.value)[]
+  var z = incrSeq(y, x.rawType.base.size)
+  # 'incrSeq' already freed the memory for us and copied over the RC!
+  # So we simply copy the raw pointer into 'x.value':
+  cast[ppointer](x.value)[] = z
+  #genericShallowAssign(x.value, addr(z), x.rawType)
+
+proc setObjectRuntimeType*(x: TAny) =
+  ## this needs to be called to set `x`'s runtime object type field.
+  assert x.rawType.kind == tyObject
+  objectInit(x.value, x.rawType)
+
+proc skipRange(x: PNimType): PNimType {.inline.} =
+  result = x
+  if result.kind == tyRange: result = result.base
+
+proc `[]`*(x: TAny, i: int): TAny =
+  ## accessor for an any `x` that represents an array or a sequence.
+  case x.rawType.kind
+  of tyArray:
+    var bs = x.rawType.base.size
+    if i >=% x.rawType.size div bs: 
+      raise newException(IndexError, "index out of bounds")
+    return newAny(x.value +!! i*bs, x.rawType.base)
+  of tySequence:
+    var s = cast[ppointer](x.value)[]
+    if s == nil: raise newException(ValueError, "sequence is nil")
+    var bs = x.rawType.base.size
+    if i >=% cast[PGenSeq](s).len:
+      raise newException(IndexError, "index out of bounds")
+    return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
+  else: assert false
+
+proc `[]=`*(x: TAny, i: int, y: TAny) =
+  ## accessor for an any `x` that represents an array or a sequence.
+  case x.rawType.kind
+  of tyArray:
+    var bs = x.rawType.base.size
+    if i >=% x.rawType.size div bs: 
+      raise newException(IndexError, "index out of bounds")
+    assert y.rawType == x.rawType.base
+    genericAssign(x.value +!! i*bs, y.value, y.rawType)
+  of tySequence:
+    var s = cast[ppointer](x.value)[]
+    if s == nil: raise newException(ValueError, "sequence is nil")
+    var bs = x.rawType.base.size
+    if i >=% cast[PGenSeq](s).len:
+      raise newException(IndexError, "index out of bounds")
+    assert y.rawType == x.rawType.base
+    genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
+  else: assert false
+
+proc len*(x: TAny): int =
+  ## len for an any `x` that represents an array or a sequence.
+  case x.rawType.kind
+  of tyArray: result = x.rawType.size div x.rawType.base.size
+  of tySequence: result = cast[PGenSeq](cast[ppointer](x.value)[]).len
+  else: assert false
+
+
+proc base*(x: TAny): TAny =
+  ## returns base TAny (useful for inherited object types).
+  result.rawType = x.rawType.base
+  result.value = x.value
+
+
+proc isNil*(x: TAny): bool =
+  ## `isNil` for an any `x` that represents a sequence, string, cstring,
+  ## proc or some pointer type.
+  assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, 
+                            tySequence, tyProc}
+  result = isNil(cast[ppointer](x.value)[])
+
+proc getPointer*(x: TAny): pointer =
+  ## retrieve the pointer value out of `x`. ``x`` needs to be of kind
+  ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, 
+  ## ``akPointer``, ``akSequence``.
+  assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, 
+                            tySequence, tyProc}
+  result = cast[ppointer](x.value)[]
+
+proc setPointer*(x: TAny, y: pointer) =
+  ## sets the pointer value of `x`. ``x`` needs to be of kind
+  ## ``akString``, ``akCString``, ``akProc``, ``akRef``, ``akPtr``, 
+  ## ``akPointer``, ``akSequence``.
+  assert x.rawType.kind in {tyString, tyCString, tyRef, tyPtr, tyPointer, 
+                            tySequence, tyProc}
+  cast[ppointer](x.value)[] = y
+
+proc fieldsAux(p: pointer, n: ptr TNimNode,
+               ret: var seq[tuple[name: cstring, any: TAny]]) =
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    ret.add((n.name, newAny(p +!! n.offset, n.typ)))
+    assert ret[ret.len()-1][0] != nil
+  of nkList:
+    for i in 0..n.len-1: fieldsAux(p, n.sons[i], ret)
+  of nkCase:
+    var m = selectBranch(p, n)
+    ret.add((n.name, newAny(p +!! n.offset, n.typ)))
+    if m != nil: fieldsAux(p, m, ret)
+
+iterator fields*(x: TAny): tuple[name: string, any: TAny] =
+  ## iterates over every active field of the any `x` that represents an object
+  ## or a tuple.
+  assert x.rawType.kind in {tyTuple, tyObject}
+  var p = x.value
+  var t = x.rawType
+  # XXX BUG: does not work yet, however is questionable anyway
+  when false:
+    if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
+  var ret: seq[tuple[name: cstring, any: TAny]] = @[]
+  if t.kind == tyObject:
+    while true:
+      fieldsAux(p, t.node, ret)
+      t = t.base
+      if t.isNil: break
+  else:
+    fieldsAux(p, t.node, ret)
+  for name, any in items(ret):
+    yield ($name, any)
+
+proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
+  proc toLower(c: char): char {.inline.} =
+    if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A')))
+    else: result = c
+  var i = 0
+  var j = 0
+  while true:
+    while a[i] == '_': inc(i)
+    while b[j] == '_': inc(j) # BUGFIX: typo
+    var aa = toLower(a[i])
+    var bb = toLower(b[j])
+    result = ord(aa) - ord(bb)
+    if result != 0 or aa == '\0': break
+    inc(i)
+    inc(j)
+
+proc getFieldNode(p: pointer, n: ptr TNimNode,
+                  name: cstring): ptr TNimNode =
+  case n.kind
+  of nkNone: assert(false)
+  of nkSlot:
+    if cmpIgnoreStyle(n.name, name) == 0:
+      result = n
+  of nkList:
+    for i in 0..n.len-1: 
+      result = getFieldNode(p, n.sons[i], name)
+      if result != nil: break
+  of nkCase:
+    if cmpIgnoreStyle(n.name, name) == 0:
+      result = n
+    else:
+      var m = selectBranch(p, n)
+      if m != nil: result = getFieldNode(p, m, name)
+
+proc `[]=`*(x: TAny, fieldName: string, value: TAny) =
+  ## sets a field of `x`; `x` represents an object or a tuple.
+  var t = x.rawType
+  # XXX BUG: does not work yet, however is questionable anyway
+  when false:
+    if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
+  assert x.rawType.kind in {tyTuple, tyObject}
+  var n = getFieldNode(x.value, t.node, fieldName)
+  if n != nil:
+    assert n.typ == value.rawType
+    genericAssign(x.value +!! n.offset, value.value, value.rawType)
+  else:
+    raise newException(ValueError, "invalid field name: " & fieldName)
+
+proc `[]`*(x: TAny, fieldName: string): TAny =
+  ## gets a field of `x`; `x` represents an object or a tuple.
+  var t = x.rawType
+  # XXX BUG: does not work yet, however is questionable anyway
+  when false:
+    if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[]
+  assert x.rawType.kind in {tyTuple, tyObject}
+  var n = getFieldNode(x.value, t.node, fieldName)
+  if n != nil:
+    result.value = x.value +!! n.offset
+    result.rawType = n.typ
+  else:
+    raise newException(ValueError, "invalid field name: " & fieldName)
+
+proc `[]`*(x: TAny): TAny =
+  ## dereference operation for the any `x` that represents a ptr or a ref.
+  assert x.rawType.kind in {tyRef, tyPtr}
+  result.value = cast[ppointer](x.value)[]
+  result.rawType = x.rawType.base
+
+proc `[]=`*(x, y: TAny) =
+  ## dereference operation for the any `x` that represents a ptr or a ref.
+  assert x.rawType.kind in {tyRef, tyPtr}
+  assert y.rawType == x.rawType.base
+  genericAssign(cast[ppointer](x.value)[], y.value, y.rawType)
+
+proc getInt*(x: TAny): int =
+  ## retrieve the int value out of `x`. `x` needs to represent an int.
+  assert skipRange(x.rawType).kind == tyInt
+  result = cast[ptr int](x.value)[]
+
+proc getInt8*(x: TAny): int8 = 
+  ## retrieve the int8 value out of `x`. `x` needs to represent an int8.
+  assert skipRange(x.rawType).kind == tyInt8
+  result = cast[ptr int8](x.value)[]
+
+proc getInt16*(x: TAny): int16 = 
+  ## retrieve the int16 value out of `x`. `x` needs to represent an int16.
+  assert skipRange(x.rawType).kind == tyInt16
+  result = cast[ptr int16](x.value)[]
+  
+proc getInt32*(x: TAny): int32 = 
+  ## retrieve the int32 value out of `x`. `x` needs to represent an int32.
+  assert skipRange(x.rawType).kind == tyInt32
+  result = cast[ptr int32](x.value)[]
+
+proc getInt64*(x: TAny): int64 = 
+  ## retrieve the int64 value out of `x`. `x` needs to represent an int64.
+  assert skipRange(x.rawType).kind == tyInt64
+  result = cast[ptr int64](x.value)[]
+
+proc getBiggestInt*(x: TAny): BiggestInt =
+  ## retrieve the integer value out of `x`. `x` needs to represent
+  ## some integer, a bool, a char, an enum or a small enough bit set.
+  ## The value might be sign-extended to ``BiggestInt``.
+  var t = skipRange(x.rawType)
+  case t.kind
+  of tyInt: result = BiggestInt(cast[ptr int](x.value)[])
+  of tyInt8: result = BiggestInt(cast[ptr int8](x.value)[])
+  of tyInt16: result = BiggestInt(cast[ptr int16](x.value)[])
+  of tyInt32: result = BiggestInt(cast[ptr int32](x.value)[])
+  of tyInt64, tyUInt64: result = BiggestInt(cast[ptr int64](x.value)[])
+  of tyBool: result = BiggestInt(cast[ptr bool](x.value)[])
+  of tyChar: result = BiggestInt(cast[ptr char](x.value)[])
+  of tyEnum, tySet:
+    case t.size
+    of 1: result = ze64(cast[ptr int8](x.value)[])
+    of 2: result = ze64(cast[ptr int16](x.value)[])
+    of 4: result = BiggestInt(cast[ptr int32](x.value)[])
+    of 8: result = BiggestInt(cast[ptr int64](x.value)[])
+    else: assert false
+  of tyUInt: result = BiggestInt(cast[ptr uint](x.value)[])
+  of tyUInt8: result = BiggestInt(cast[ptr uint8](x.value)[])
+  of tyUInt16: result = BiggestInt(cast[ptr uint16](x.value)[])
+  of tyUInt32: result = BiggestInt(cast[ptr uint32](x.value)[])
+  else: assert false
+
+proc setBiggestInt*(x: TAny, y: BiggestInt) =
+  ## sets the integer value of `x`. `x` needs to represent
+  ## some integer, a bool, a char, an enum or a small enough bit set.
+  var t = skipRange(x.rawType)
+  case t.kind
+  of tyInt: cast[ptr int](x.value)[] = int(y)
+  of tyInt8: cast[ptr int8](x.value)[] = int8(y)
+  of tyInt16: cast[ptr int16](x.value)[] = int16(y)
+  of tyInt32: cast[ptr int32](x.value)[] = int32(y)
+  of tyInt64, tyUInt64: cast[ptr int64](x.value)[] = int64(y)
+  of tyBool: cast[ptr bool](x.value)[] = y != 0
+  of tyChar: cast[ptr char](x.value)[] = chr(y.int)
+  of tyEnum, tySet:
+    case t.size
+    of 1: cast[ptr int8](x.value)[] = toU8(y.int)
+    of 2: cast[ptr int16](x.value)[] = toU16(y.int)
+    of 4: cast[ptr int32](x.value)[] = int32(y)
+    of 8: cast[ptr int64](x.value)[] = y
+    else: assert false
+  of tyUInt: cast[ptr uint](x.value)[] = uint(y)
+  of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y)
+  of tyUInt16: cast[ptr uint16](x.value)[] = uint16(y)
+  of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
+  else: assert false
+
+proc getUInt*(x: TAny): uint =
+  ## retrieve the uint value out of `x`, `x` needs to represent an uint.
+  assert skipRange(x.rawType).kind == tyUInt
+  result = cast[ptr uint](x.value)[]
+
+proc getUInt8*(x: TAny): uint8 =
+  ## retrieve the uint8 value out of `x`, `x` needs to represent an
+  ## uint8.
+  assert skipRange(x.rawType).kind == tyUInt8
+  result = cast[ptr uint8](x.value)[]
+
+proc getUInt16*(x: TAny): uint16 =
+  ## retrieve the uint16 value out of `x`, `x` needs to represent an
+  ## uint16.
+  assert skipRange(x.rawType).kind == tyUInt16
+  result = cast[ptr uint16](x.value)[]
+
+proc getUInt32*(x: TAny): uint32 =
+  ## retrieve the uint32 value out of `x`, `x` needs to represent an
+  ## uint32.
+  assert skipRange(x.rawType).kind == tyUInt32
+  result = cast[ptr uint32](x.value)[]
+
+proc getUInt64*(x: TAny): uint64 =
+  ## retrieve the uint64 value out of `x`, `x` needs to represent an
+  ## uint64.
+  assert skipRange(x.rawType).kind == tyUInt64
+  result = cast[ptr uint64](x.value)[]
+
+proc getBiggestUint*(x: TAny): uint64 =
+  ## retrieve the unsigned integer value out of `x`. `x` needs to
+  ## represent an unsigned integer.
+  var t = skipRange(x.rawType)
+  case t.kind
+  of tyUInt: result = uint64(cast[ptr uint](x.value)[])
+  of tyUInt8: result = uint64(cast[ptr uint8](x.value)[])
+  of tyUInt16: result = uint64(cast[ptr uint16](x.value)[])
+  of tyUInt32: result = uint64(cast[ptr uint32](x.value)[])
+  of tyUInt64: result = uint64(cast[ptr uint64](x.value)[])
+  else: assert false
+
+proc setBiggestUint*(x: TAny; y: uint64) =
+  ## sets the unsigned integer value of `c`. `c` needs to represent an
+  ## unsigned integer.
+  var t = skipRange(x.rawType)
+  case t.kind:
+  of tyUInt: cast[ptr uint](x.value)[] = uint(y)
+  of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y)
+  of tyUInt16: cast[ptr uint16](x.value)[] = uint16(y)
+  of tyUInt32: cast[ptr uint32](x.value)[] = uint32(y)
+  of tyUInt64: cast[ptr uint64](x.value)[] = uint64(y)
+  else: assert false
+
+proc getChar*(x: TAny): char =
+  ## retrieve the char value out of `x`. `x` needs to represent a char.
+  var t = skipRange(x.rawType)
+  assert t.kind == tyChar
+  result = cast[ptr char](x.value)[]
+
+proc getBool*(x: TAny): bool =
+  ## retrieve the bool value out of `x`. `x` needs to represent a bool.
+  var t = skipRange(x.rawType)
+  assert t.kind == tyBool
+  result = cast[ptr bool](x.value)[]
+
+proc skipRange*(x: TAny): TAny =
+  ## skips the range information of `x`.
+  assert x.rawType.kind == tyRange
+  result.rawType = x.rawType.base
+  result.value = x.value
+
+proc getEnumOrdinal*(x: TAny, name: string): int =
+  ## gets the enum field ordinal from `name`. `x` needs to represent an enum
+  ## but is only used to access the type information. In case of an error
+  ## ``low(int)`` is returned.
+  var typ = skipRange(x.rawType)
+  assert typ.kind == tyEnum
+  var n = typ.node
+  var s = n.sons
+  for i in 0 .. n.len-1:
+    if cmpIgnoreStyle($s[i].name, name) == 0: 
+      if ntfEnumHole notin typ.flags:
+        return i
+      else:
+        return s[i].offset
+  result = low(int)
+
+proc getEnumField*(x: TAny, ordinalValue: int): string =
+  ## gets the enum field name as a string. `x` needs to represent an enum
+  ## but is only used to access the type information. The field name of
+  ## `ordinalValue` is returned. 
+  var typ = skipRange(x.rawType)
+  assert typ.kind == tyEnum
+  var e = ordinalValue
+  if ntfEnumHole notin typ.flags:
+    if e <% typ.node.len:
+      return $typ.node.sons[e].name
+  else:
+    # ugh we need a slow linear search:
+    var n = typ.node
+    var s = n.sons
+    for i in 0 .. n.len-1:
+      if s[i].offset == e: return $s[i].name
+  result = $e
+
+proc getEnumField*(x: TAny): string =
+  ## gets the enum field name as a string. `x` needs to represent an enum.
+  result = getEnumField(x, getBiggestInt(x).int)
+
+proc getFloat*(x: TAny): float = 
+  ## retrieve the float value out of `x`. `x` needs to represent an float.  
+  assert skipRange(x.rawType).kind == tyFloat
+  result = cast[ptr float](x.value)[]
+
+proc getFloat32*(x: TAny): float32 = 
+  ## retrieve the float32 value out of `x`. `x` needs to represent an float32.
+  assert skipRange(x.rawType).kind == tyFloat32
+  result = cast[ptr float32](x.value)[]
+  
+proc getFloat64*(x: TAny): float64 = 
+  ## retrieve the float64 value out of `x`. `x` needs to represent an float64.
+  assert skipRange(x.rawType).kind == tyFloat64
+  result = cast[ptr float64](x.value)[]
+
+proc getBiggestFloat*(x: TAny): BiggestFloat =
+  ## retrieve the float value out of `x`. `x` needs to represent
+  ## some float. The value is extended to ``BiggestFloat``.
+  case skipRange(x.rawType).kind
+  of tyFloat: result = BiggestFloat(cast[ptr float](x.value)[])
+  of tyFloat32: result = BiggestFloat(cast[ptr float32](x.value)[])
+  of tyFloat64: result = BiggestFloat(cast[ptr float64](x.value)[])
+  else: assert false
+
+proc setBiggestFloat*(x: TAny, y: BiggestFloat) =
+  ## sets the float value of `x`. `x` needs to represent
+  ## some float.
+  case skipRange(x.rawType).kind
+  of tyFloat: cast[ptr float](x.value)[] = y
+  of tyFloat32: cast[ptr float32](x.value)[] = y.float32
+  of tyFloat64: cast[ptr float64](x.value)[] = y
+  else: assert false
+
+proc getString*(x: TAny): string = 
+  ## retrieve the string value out of `x`. `x` needs to represent a string.
+  assert x.rawType.kind == tyString
+  if not isNil(cast[ptr pointer](x.value)[]):
+    result = cast[ptr string](x.value)[]
+
+proc setString*(x: TAny, y: string) = 
+  ## sets the string value of `x`. `x` needs to represent a string.
+  assert x.rawType.kind == tyString
+  cast[ptr string](x.value)[] = y
+
+proc getCString*(x: TAny): cstring = 
+  ## retrieve the cstring value out of `x`. `x` needs to represent a cstring.
+  assert x.rawType.kind == tyCString
+  result = cast[ptr cstring](x.value)[]
+
+proc assign*(x, y: TAny) = 
+  ## copies the value of `y` to `x`. The assignment operator for ``TAny``
+  ## does NOT do this; it performs a shallow copy instead!
+  assert y.rawType == x.rawType
+  genericAssign(x.value, y.value, y.rawType)
+
+iterator elements*(x: TAny): int =
+  ## iterates over every element of `x` that represents a Nim bitset.
+  assert x.rawType.kind == tySet
+  var typ = x.rawType
+  var p = x.value
+  # "typ.slots.len" field is for sets the "first" field
+  var u: int64
+  case typ.size
+  of 1: u = ze64(cast[ptr int8](p)[])
+  of 2: u = ze64(cast[ptr int16](p)[])
+  of 4: u = ze64(cast[ptr int32](p)[])
+  of 8: u = cast[ptr int64](p)[]
+  else:
+    var a = cast[pbyteArray](p)
+    for i in 0 .. typ.size*8-1:
+      if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
+        yield i+typ.node.len
+  if typ.size <= 8:
+    for i in 0..sizeof(int64)*8-1:
+      if (u and (1'i64 shl int64(i))) != 0'i64:
+        yield i+typ.node.len
+
+proc inclSetElement*(x: TAny, elem: int) =
+  ## includes an element `elem` in `x`. `x` needs to represent a Nim bitset.
+  assert x.rawType.kind == tySet
+  var typ = x.rawType
+  var p = x.value
+  # "typ.slots.len" field is for sets the "first" field
+  var e = elem - typ.node.len
+  case typ.size
+  of 1:
+    var a = cast[ptr int8](p)
+    a[] = a[] or (1'i8 shl int8(e))
+  of 2:
+    var a = cast[ptr int16](p)
+    a[] = a[] or (1'i16 shl int16(e))
+  of 4: 
+    var a = cast[ptr int32](p)
+    a[] = a[] or (1'i32 shl int32(e))
+  of 8:
+    var a = cast[ptr int64](p)
+    a[] = a[] or (1'i64 shl e)
+  else:
+    var a = cast[pbyteArray](p)
+    a[e shr 3] = toU8(a[e shr 3] or (1 shl (e and 7)))
+
+when isMainModule:
+  type
+    TE = enum
+      blah, blah2
+  
+    TestObj = object
+      test, asd: int
+      case test2: TE
+      of blah:
+        help: string
+      else:
+        nil
+
+  var test = @[0,1,2,3,4]
+  var x = toAny(test)
+  var y = 78
+  x[4] = toAny(y)
+  assert cast[ptr int](x[2].value)[] == 2
+  
+  var test2: tuple[name: string, s: int] = ("test", 56)
+  var x2 = toAny(test2)
+  var i = 0
+  for n, a in fields(x2):
+    case i
+    of 0: assert n == "name" and $a.kind == "akString"
+    of 1: assert n == "s" and $a.kind == "akInt"
+    else: assert false
+    inc i
+    
+  var test3: TestObj
+  test3.test = 42
+  test3.test2 = blah2
+  var x3 = toAny(test3)
+  i = 0
+  for n, a in fields(x3):
+    case i
+    of 0: assert n == "test" and $a.kind == "akInt" 
+    of 1: assert n == "asd" and $a.kind == "akInt"
+    of 2: assert n == "test2" and $a.kind == "akEnum"
+    else: assert false
+    inc i
+  
+  var test4: ref string
+  new(test4)
+  test4[] = "test"
+  var x4 = toAny(test4)
+  assert($x4[].kind() == "akString")
+  
+  block:
+    # gimme a new scope dammit
+    var myarr: array[0..4, array[0..4, string]] = [
+      ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 
+      ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], 
+      ["test", "1", "2", "3", "4"]]
+    var m = toAny(myArr)
+    for i in 0 .. m.len-1:
+      for j in 0 .. m[i].len-1:
+        echo getString(m[i][j])
+      
+
diff --git a/lib/core/unsigned.nim b/lib/core/unsigned.nim
new file mode 100644
index 000000000..20fcd03aa
--- /dev/null
+++ b/lib/core/unsigned.nim
@@ -0,0 +1,57 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements basic arithmetic operators for unsigned integers.
+## To discourage users from using ``unsigned``, it's not part of ``system``,
+## but an extra import.
+
+proc `not`*[T: SomeUnsignedInt](x: T): T {.magic: "BitnotI", noSideEffect.}
+  ## computes the `bitwise complement` of the integer `x`.
+
+proc `shr`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShrI", noSideEffect.}
+  ## computes the `shift right` operation of `x` and `y`.
+
+proc `shl`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShlI", noSideEffect.}
+  ## computes the `shift left` operation of `x` and `y`.
+
+proc `and`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitandI", noSideEffect.}
+  ## computes the `bitwise and` of numbers `x` and `y`.
+
+proc `or`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitorI", noSideEffect.}
+  ## computes the `bitwise or` of numbers `x` and `y`.
+
+proc `xor`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitxorI", noSideEffect.}
+  ## computes the `bitwise xor` of numbers `x` and `y`.
+
+proc `==`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "EqI", noSideEffect.}
+  ## Compares two unsigned integers for equality.
+
+proc `+`*[T: SomeUnsignedInt](x, y: T): T {.magic: "AddU", noSideEffect.}
+  ## Binary `+` operator for unsigned integers.
+
+proc `-`*[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.}
+  ## Binary `-` operator for unsigned integers.
+
+proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.}
+  ## Binary `*` operator for unsigned integers.
+
+proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
+  ## computes the integer division. This is roughly the same as
+  ## ``floor(x/y)``.
+
+proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.}
+  ## computes the integer modulo operation. This is the same as
+  ## ``x - (x div y) * y``.
+
+proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.}
+  ## Returns true iff ``x <= y``.
+
+proc `<`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LtU", noSideEffect.}
+  ## Returns true iff ``unsigned(x) < unsigned(y)``.
+
diff --git a/lib/cycle.h b/lib/cycle.h
new file mode 100644
index 000000000..4d714ba3f
--- /dev/null
+++ b/lib/cycle.h
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2003, 2007 Matteo Frigo
+ * Copyright (c) 2003, 2007 Massachusetts Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+/* machine-dependent cycle counters code. Needs to be inlined. */
+
+/***************************************************************************/
+/* To use the cycle counters in your code, simply #include "cycle.h" (this
+   file), and then use the functions/macros:
+
+                 ticks getticks(void);
+
+   ticks is an opaque typedef defined below, representing the current time.
+   You extract the elapsed time between two calls to gettick() via:
+
+                 double elapsed(ticks t1, ticks t0);
+
+   which returns a double-precision variable in arbitrary units.  You
+   are not expected to convert this into human units like seconds; it
+   is intended only for *comparisons* of time intervals.
+
+   (In order to use some of the OS-dependent timer routines like
+   Solaris' gethrtime, you need to paste the autoconf snippet below
+   into your configure.ac file and #include "config.h" before cycle.h,
+   or define the relevant macros manually if you are not using autoconf.)
+*/
+
+/***************************************************************************/
+/* This file uses macros like HAVE_GETHRTIME that are assumed to be
+   defined according to whether the corresponding function/type/header
+   is available on your system.  The necessary macros are most
+   conveniently defined if you are using GNU autoconf, via the tests:
+   
+   dnl ---------------------------------------------------------------------
+
+   AC_C_INLINE
+   AC_HEADER_TIME
+   AC_CHECK_HEADERS([sys/time.h c_asm.h intrinsics.h mach/mach_time.h])
+
+   AC_CHECK_TYPE([hrtime_t],[AC_DEFINE(HAVE_HRTIME_T, 1, [Define to 1 if hrtime_t is defined in <sys/time.h>])],,[#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif])
+
+   AC_CHECK_FUNCS([gethrtime read_real_time time_base_to_time clock_gettime mach_absolute_time])
+
+   dnl Cray UNICOS _rtc() (real-time clock) intrinsic
+   AC_MSG_CHECKING([for _rtc intrinsic])
+   rtc_ok=yes
+   AC_TRY_LINK([#ifdef HAVE_INTRINSICS_H
+#include <intrinsics.h>
+#endif], [_rtc()], [AC_DEFINE(HAVE__RTC,1,[Define if you have the UNICOS _rtc() intrinsic.])], [rtc_ok=no])
+   AC_MSG_RESULT($rtc_ok)
+
+   dnl ---------------------------------------------------------------------
+*/
+
+/***************************************************************************/
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#define INLINE_ELAPSED(INL) static INL double elapsed(ticks t1, ticks t0) \
+{									  \
+     return (double)t1 - (double)t0;					  \
+}
+
+/*----------------------------------------------------------------*/
+/* Solaris */
+#if defined(HAVE_GETHRTIME) && defined(HAVE_HRTIME_T) && !defined(HAVE_TICK_COUNTER)
+typedef hrtime_t ticks;
+
+#define getticks gethrtime
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* AIX v. 4+ routines to read the real-time clock or time-base register */
+#if defined(HAVE_READ_REAL_TIME) && defined(HAVE_TIME_BASE_TO_TIME) && !defined(HAVE_TICK_COUNTER)
+typedef timebasestruct_t ticks;
+
+static __inline ticks getticks(void)
+{
+     ticks t;
+     read_real_time(&t, TIMEBASE_SZ);
+     return t;
+}
+
+static __inline double elapsed(ticks t1, ticks t0) /* time in nanoseconds */
+{
+     time_base_to_time(&t1, TIMEBASE_SZ);
+     time_base_to_time(&t0, TIMEBASE_SZ);
+     return (((double)t1.tb_high - (double)t0.tb_high) * 1.0e9 + 
+	     ((double)t1.tb_low - (double)t0.tb_low));
+}
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * PowerPC ``cycle'' counter using the time base register.
+ */
+#if ((((defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))) || (defined(__MWERKS__) && defined(macintosh)))) || (defined(__IBM_GCC_ASM) && (defined(__powerpc__) || defined(__ppc__))))  && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void)
+{
+     unsigned int tbl, tbu0, tbu1;
+
+     do {
+	  __asm__ __volatile__ ("mftbu %0" : "=r"(tbu0));
+	  __asm__ __volatile__ ("mftb %0" : "=r"(tbl));
+	  __asm__ __volatile__ ("mftbu %0" : "=r"(tbu1));
+     } while (tbu0 != tbu1);
+
+     return (((unsigned long long)tbu0) << 32) | tbl;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* MacOS/Mach (Darwin) time-base register interface (unlike UpTime,
+   from Carbon, requires no additional libraries to be linked). */
+#if defined(HAVE_MACH_ABSOLUTE_TIME) && defined(HAVE_MACH_MACH_TIME_H) && !defined(HAVE_TICK_COUNTER)
+#include <mach/mach_time.h>
+typedef uint64_t ticks;
+#define getticks mach_absolute_time
+INLINE_ELAPSED(__inline__)
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * Pentium cycle counter 
+ */
+#if (defined(__GNUC__) || defined(__ICC)) && defined(__i386__)  && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void)
+{
+     ticks ret;
+
+     __asm__ __volatile__("rdtsc": "=A" (ret));
+     /* no input, nothing else clobbered */
+     return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0   /* unreliable pentium IV cycle counter */
+#endif
+
+/* Visual C++ -- thanks to Morten Nissov for his help with this */
+#if _MSC_VER >= 1200 && _M_IX86 >= 500 && !defined(HAVE_TICK_COUNTER)
+#include <windows.h>
+typedef LARGE_INTEGER ticks;
+#define RDTSC __asm __emit 0fh __asm __emit 031h /* hack for VC++ 5.0 */
+
+static __inline ticks getticks(void)
+{
+     ticks retval;
+
+     __asm {
+	  RDTSC
+	  mov retval.HighPart, edx
+	  mov retval.LowPart, eax
+     }
+     return retval;
+}
+
+static __inline double elapsed(ticks t1, ticks t0)
+{  
+     return (double)t1.QuadPart - (double)t0.QuadPart;
+}  
+
+#define HAVE_TICK_COUNTER
+#define TIME_MIN 5000.0   /* unreliable pentium IV cycle counter */
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * X86-64 cycle counter
+ */
+#if (defined(__GNUC__) || defined(__ICC) || defined(__SUNPRO_C)) && defined(__x86_64__)  && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void)
+{
+     unsigned a, d; 
+     asm volatile("rdtsc" : "=a" (a), "=d" (d)); 
+     return ((ticks)a) | (((ticks)d) << 32); 
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* PGI compiler, courtesy Cristiano Calonaci, Andrea Tarsi, & Roberto Gori.
+   NOTE: this code will fail to link unless you use the -Masmkeyword compiler
+   option (grrr). */
+#if defined(__PGI) && defined(__x86_64__) && !defined(HAVE_TICK_COUNTER) 
+typedef unsigned long long ticks;
+static ticks getticks(void)
+{
+    asm(" rdtsc; shl    $0x20,%rdx; mov    %eax,%eax; or     %rdx,%rax;    ");
+}
+INLINE_ELAPSED(__inline__)
+#define HAVE_TICK_COUNTER
+#endif
+
+/* Visual C++, courtesy of Dirk Michaelis */
+#if _MSC_VER >= 1400 && (defined(_M_AMD64) || defined(_M_X64)) && !defined(HAVE_TICK_COUNTER)
+
+#include <intrin.h>
+#pragma intrinsic(__rdtsc)
+typedef unsigned __int64 ticks;
+#define getticks __rdtsc
+INLINE_ELAPSED(__inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * IA64 cycle counter
+ */
+
+/* intel's icc/ecc compiler */
+#if (defined(__EDG_VERSION) || defined(__ECC)) && defined(__ia64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+#include <ia64intrin.h>
+
+static __inline__ ticks getticks(void)
+{
+     return __getReg(_IA64_REG_AR_ITC);
+}
+ 
+INLINE_ELAPSED(__inline__)
+ 
+#define HAVE_TICK_COUNTER
+#endif
+
+/* gcc */
+#if defined(__GNUC__) && defined(__ia64__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+
+static __inline__ ticks getticks(void)
+{
+     ticks ret;
+
+     __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret));
+     return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* HP/UX IA64 compiler, courtesy Teresa L. Johnson: */
+#if defined(__hpux) && defined(__ia64) && !defined(HAVE_TICK_COUNTER)
+#include <machine/sys/inline.h>
+typedef unsigned long ticks;
+
+static inline ticks getticks(void)
+{
+     ticks ret;
+
+     ret = _Asm_mov_from_ar (_AREG_ITC);
+     return ret;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/* Microsoft Visual C++ */
+#if defined(_MSC_VER) && defined(_M_IA64) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned __int64 ticks;
+
+#  ifdef __cplusplus
+extern "C"
+#  endif
+ticks __getReg(int whichReg);
+#pragma intrinsic(__getReg)
+
+static __inline ticks getticks(void)
+{
+     volatile ticks temp;
+     temp = __getReg(3116);
+     return temp;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/*
+ * PA-RISC cycle counter 
+ */
+#if defined(__hppa__) || defined(__hppa) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+
+#  ifdef __GNUC__
+static __inline__ ticks getticks(void)
+{
+     ticks ret;
+
+     __asm__ __volatile__("mfctl 16, %0": "=r" (ret));
+     /* no input, nothing else clobbered */
+     return ret;
+}
+#  else
+#  include <machine/inline.h>
+static inline unsigned long getticks(void)
+{
+     register ticks ret;
+     _MFCTL(16, ret);
+     return ret;
+}
+#  endif
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* S390, courtesy of James Treacy */
+#if defined(__GNUC__) && defined(__s390__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long long ticks;
+
+static __inline__ ticks getticks(void)
+{
+     ticks cycles;
+     __asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
+     return cycles;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+/*----------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__alpha__) && !defined(HAVE_TICK_COUNTER)
+/*
+ * The 32-bit cycle counter on alpha overflows pretty quickly, 
+ * unfortunately.  A 1GHz machine overflows in 4 seconds.
+ */
+typedef unsigned int ticks;
+
+static __inline__ ticks getticks(void)
+{
+     unsigned long cc;
+     __asm__ __volatile__ ("rpcc %0" : "=r"(cc));
+     return (cc & 0xFFFFFFFF);
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+#if defined(__GNUC__) && defined(__sparc_v9__) && !defined(HAVE_TICK_COUNTER)
+typedef unsigned long ticks;
+
+static __inline__ ticks getticks(void)
+{
+     ticks ret;
+     __asm__ __volatile__("rd %%tick, %0" : "=r" (ret));
+     return ret;
+}
+
+INLINE_ELAPSED(__inline__)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+#if (defined(__DECC) || defined(__DECCXX)) && defined(__alpha) && defined(HAVE_C_ASM_H) && !defined(HAVE_TICK_COUNTER)
+#  include <c_asm.h>
+typedef unsigned int ticks;
+
+static __inline ticks getticks(void)
+{
+     unsigned long cc;
+     cc = asm("rpcc %v0");
+     return (cc & 0xFFFFFFFF);
+}
+
+INLINE_ELAPSED(__inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+/*----------------------------------------------------------------*/
+/* SGI/Irix */
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE) && !defined(HAVE_TICK_COUNTER)
+typedef struct timespec ticks;
+
+static inline ticks getticks(void)
+{
+     struct timespec t;
+     clock_gettime(CLOCK_SGI_CYCLE, &t);
+     return t;
+}
+
+static inline double elapsed(ticks t1, ticks t0)
+{
+     return ((double)t1.tv_sec - (double)t0.tv_sec) * 1.0E9 +
+	  ((double)t1.tv_nsec - (double)t0.tv_nsec);
+}
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* Cray UNICOS _rtc() intrinsic function */
+#if defined(HAVE__RTC) && !defined(HAVE_TICK_COUNTER)
+#ifdef HAVE_INTRINSICS_H
+#  include <intrinsics.h>
+#endif
+
+typedef long long ticks;
+
+#define getticks _rtc
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+
+/*----------------------------------------------------------------*/
+/* MIPS ZBus */
+#if HAVE_MIPS_ZBUS_TIMER
+#if defined(__mips__) && !defined(HAVE_TICK_COUNTER)
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+typedef uint64_t ticks;
+
+static inline ticks getticks(void)
+{
+  static uint64_t* addr = 0;
+
+  if (addr == 0)
+  {
+    uint32_t rq_addr = 0x10030000;
+    int fd;
+    int pgsize;
+
+    pgsize = getpagesize();
+    fd = open ("/dev/mem", O_RDONLY | O_SYNC, 0);
+    if (fd < 0) {
+      perror("open");
+      return NULL;
+    }
+    addr = mmap(0, pgsize, PROT_READ, MAP_SHARED, fd, rq_addr);
+    close(fd);
+    if (addr == (uint64_t *)-1) {
+      perror("mmap");
+      return NULL;
+    }
+  }
+
+  return *addr;
+}
+
+INLINE_ELAPSED(inline)
+
+#define HAVE_TICK_COUNTER
+#endif
+#endif /* HAVE_MIPS_ZBUS_TIMER */
+
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
new file mode 100644
index 000000000..b8180cd87
--- /dev/null
+++ b/lib/impure/db_mysql.nim
@@ -0,0 +1,237 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## A higher level `mySQL`:idx: database wrapper. The same interface is 
+## implemented for other databases too.
+
+import strutils, mysql
+
+type
+  TDbConn* = PMySQL    ## encapsulates a database connection
+  TRow* = seq[string]  ## a row of a dataset. NULL database values will be
+                       ## transformed always to the empty string.
+  EDb* = object of IOError ## exception that is raised if a database error occurs
+
+  TSqlQuery* = distinct string ## an SQL query string
+
+  FDb* = object of IOEffect ## effect that denotes a database operation
+  FReadDb* = object of FDb   ## effect that denotes a read operation
+  FWriteDb* = object of FDb  ## effect that denotes a write operation
+
+proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =
+  ## constructs a TSqlQuery from the string `query`. This is supposed to be 
+  ## used as a raw-string-literal modifier:
+  ## ``sql"update user set counter = counter + 1"``
+  ##
+  ## If assertions are turned off, it does nothing. If assertions are turned 
+  ## on, later versions will check the string for valid syntax.
+  result = TSqlQuery(query)
+
+proc dbError(db: TDbConn) {.noreturn.} = 
+  ## raises an EDb exception.
+  var e: ref EDb
+  new(e)
+  e.msg = $mysql.error(db)
+  raise e
+
+proc dbError*(msg: string) {.noreturn.} = 
+  ## raises an EDb exception with message `msg`.
+  var e: ref EDb
+  new(e)
+  e.msg = msg
+  raise e
+
+when false:
+  proc dbQueryOpt*(db: TDbConn, query: string, args: varargs[string, `$`]) =
+    var stmt = mysql_stmt_init(db)
+    if stmt == nil: dbError(db)
+    if mysql_stmt_prepare(stmt, query, len(query)) != 0: 
+      dbError(db)
+    var 
+      binding: seq[MYSQL_BIND]
+    discard mysql_stmt_close(stmt)
+
+proc dbQuote*(s: string): string =
+  ## DB quotes the string.
+  result = "'"
+  for c in items(s):
+    if c == '\'': add(result, "''")
+    else: add(result, c)
+  add(result, '\'')
+
+proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
+  result = ""
+  var a = 0
+  for c in items(string(formatstr)):
+    if c == '?':
+      if args[a] == nil:
+        add(result, "NULL")
+      else:
+        add(result, dbQuote(args[a]))
+      inc(a)
+    else: 
+      add(result, c)
+  
+proc tryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.
+  tags: [FReadDB, FWriteDb].} =
+  ## tries to execute the query and returns true if successful, false otherwise.
+  var q = dbFormat(query, args)
+  return mysql.realQuery(db, q, q.len) == 0'i32
+
+proc rawExec(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
+  var q = dbFormat(query, args)
+  if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db)
+
+proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
+  tags: [FReadDB, FWriteDb].} =
+  ## executes the query and raises EDB if not successful.
+  var q = dbFormat(query, args)
+  if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db)
+    
+proc newRow(L: int): TRow = 
+  newSeq(result, L)
+  for i in 0..L-1: result[i] = ""
+  
+proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) =  
+  if row != nil:
+    while mysql.fetchRow(sqlres) != nil: discard
+  mysql.freeResult(sqlres)
+  
+iterator fastRows*(db: TDbConn, query: TSqlQuery,
+                   args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## executes the query and iterates over the result dataset. This is very 
+  ## fast, but potenially dangerous: If the for-loop-body executes another
+  ## query, the results can be undefined. For MySQL this is the case!.
+  rawExec(db, query, args)
+  var sqlres = mysql.useResult(db)
+  if sqlres != nil:
+    var L = int(mysql.numFields(sqlres))
+    var result = newRow(L)
+    var row: cstringArray
+    while true:
+      row = mysql.fetchRow(sqlres)
+      if row == nil: break
+      for i in 0..L-1: 
+        setLen(result[i], 0)
+        if row[i] == nil:
+          result[i] = nil
+        else:
+          add(result[i], row[i])
+      yield result
+    properFreeResult(sqlres, row)
+
+proc getRow*(db: TDbConn, query: TSqlQuery,
+             args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## retrieves a single row. If the query doesn't return any rows, this proc
+  ## will return a TRow with empty strings for each column.
+  rawExec(db, query, args)
+  var sqlres = mysql.useResult(db)
+  if sqlres != nil:
+    var L = int(mysql.numFields(sqlres))
+    result = newRow(L)
+    var row = mysql.fetchRow(sqlres)
+    if row != nil: 
+      for i in 0..L-1: 
+        setLen(result[i], 0)
+        if row[i] == nil:
+          result[i] = nil
+        else:
+          add(result[i], row[i])
+    properFreeResult(sqlres, row)
+
+proc getAllRows*(db: TDbConn, query: TSqlQuery, 
+                 args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
+  ## executes the query and returns the whole result dataset.
+  result = @[]
+  rawExec(db, query, args)
+  var sqlres = mysql.useResult(db)
+  if sqlres != nil:
+    var L = int(mysql.numFields(sqlres))
+    var row: cstringArray
+    var j = 0
+    while true:
+      row = mysql.fetchRow(sqlres)
+      if row == nil: break
+      setLen(result, j+1)
+      newSeq(result[j], L)
+      for i in 0..L-1:
+        if row[i] == nil:
+          result[j][i] = nil
+        else:
+          result[j][i] = $row[i]
+      inc(j)
+    mysql.freeResult(sqlres)
+
+iterator rows*(db: TDbConn, query: TSqlQuery, 
+               args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## same as `fastRows`, but slower and safe.
+  for r in items(getAllRows(db, query, args)): yield r
+
+proc getValue*(db: TDbConn, query: TSqlQuery, 
+               args: varargs[string, `$`]): string {.tags: [FReadDB].} = 
+  ## executes the query and returns the first column of the first row of the
+  ## result dataset. Returns "" if the dataset contains no rows or the database
+  ## value is NULL.
+  result = ""
+  for row in fastRows(db, query, args): 
+    result = row[0]
+    break
+
+proc tryInsertId*(db: TDbConn, query: TSqlQuery, 
+                  args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
+  ## executes the query (typically "INSERT") and returns the 
+  ## generated ID for the row or -1 in case of an error.
+  var q = dbFormat(query, args)
+  if mysql.realQuery(db, q, q.len) != 0'i32: 
+    result = -1'i64
+  else:
+    result = mysql.insertId(db)
+  
+proc insertId*(db: TDbConn, query: TSqlQuery, 
+               args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} = 
+  ## executes the query (typically "INSERT") and returns the 
+  ## generated ID for the row.
+  result = tryInsertID(db, query, args)
+  if result < 0: dbError(db)
+
+proc execAffectedRows*(db: TDbConn, query: TSqlQuery, 
+                       args: varargs[string, `$`]): int64 {.
+                       tags: [FReadDB, FWriteDb].} = 
+  ## runs the query (typically "UPDATE") and returns the
+  ## number of affected rows
+  rawExec(db, query, args)
+  result = mysql.affectedRows(db)
+
+proc close*(db: TDbConn) {.tags: [FDb].} = 
+  ## closes the database connection.
+  if db != nil: mysql.close(db)
+
+proc open*(connection, user, password, database: string): TDbConn {.
+  tags: [FDb].} =
+  ## opens a database connection. Raises `EDb` if the connection could not
+  ## be established.
+  result = mysql.init(nil)
+  if result == nil: dbError("could not open database connection") 
+  let
+    colonPos = connection.find(':')
+    host = if colonPos < 0: connection
+           else: substr(connection, 0, colonPos-1)
+    port: int32 = if colonPos < 0: 0'i32
+                  else: substr(connection, colonPos+1).parseInt.int32
+  if mysql.realConnect(result, host, user, password, database, 
+                       port, nil, 0) == nil:
+    var errmsg = $mysql.error(result)
+    db_mysql.close(result)
+    dbError(errmsg)
+
+proc setEncoding*(connection: TDbConn, encoding: string): bool {.
+  tags: [FDb].} =
+  ## sets the encoding of a database connection, returns true for 
+  ## success, false for failure.
+  result = mysql.set_character_set(connection, encoding) == 0
\ No newline at end of file
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
new file mode 100644
index 000000000..ffb8bbcda
--- /dev/null
+++ b/lib/impure/db_postgres.nim
@@ -0,0 +1,268 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## A higher level `PostgreSQL`:idx: database wrapper. This interface 
+## is implemented for other databases too.
+
+import strutils, postgres
+
+type
+  TDbConn* = PPGconn   ## encapsulates a database connection
+  TRow* = seq[string]  ## a row of a dataset. NULL database values will be
+                       ## transformed always to the empty string.
+  EDb* = object of IOError ## exception that is raised if a database error occurs
+  
+  TSqlQuery* = distinct string ## an SQL query string
+  TSqlPrepared* = distinct string ## a identifier for the prepared queries
+
+  FDb* = object of IOEffect ## effect that denotes a database operation
+  FReadDb* = object of FDb   ## effect that denotes a read operation
+  FWriteDb* = object of FDb  ## effect that denotes a write operation
+
+proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =  
+  ## constructs a TSqlQuery from the string `query`. This is supposed to be 
+  ## used as a raw-string-literal modifier:
+  ## ``sql"update user set counter = counter + 1"``
+  ##
+  ## If assertions are turned off, it does nothing. If assertions are turned 
+  ## on, later versions will check the string for valid syntax.
+  result = TSqlQuery(query)
+ 
+proc dbError*(db: TDbConn) {.noreturn.} =
+  ## raises an EDb exception.
+  var e: ref EDb
+  new(e)
+  e.msg = $pqErrorMessage(db)
+  raise e
+
+proc dbError*(msg: string) {.noreturn.} =
+  ## raises an EDb exception with message `msg`.
+  var e: ref EDb
+  new(e)
+  e.msg = msg
+  raise e
+
+proc dbQuote*(s: string): string =
+  ## DB quotes the string.
+  result = "'"
+  for c in items(s):
+    if c == '\'': add(result, "''")
+    else: add(result, c)
+  add(result, '\'')
+
+proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
+  result = ""
+  var a = 0
+  for c in items(string(formatstr)):
+    if c == '?':
+      if args[a] == nil:
+        add(result, "NULL")
+      else:
+        add(result, dbQuote(args[a]))
+      inc(a)
+    else:
+      add(result, c)
+  
+proc tryExec*(db: TDbConn, query: TSqlQuery,
+              args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
+  ## tries to execute the query and returns true if successful, false otherwise.
+  var arr = allocCStringArray(args)
+  var res = pqexecParams(db, query.string, int32(args.len), nil, arr,
+                        nil, nil, 0)
+  deallocCStringArray(arr)
+  result = pqresultStatus(res) == PGRES_COMMAND_OK
+  pqclear(res)
+
+proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
+  tags: [FReadDB, FWriteDb].} =
+  ## executes the query and raises EDB if not successful.
+  var arr = allocCStringArray(args)
+  var res = pqexecParams(db, query.string, int32(args.len), nil, arr,
+                        nil, nil, 0)
+  deallocCStringArray(arr)
+  if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
+  pqclear(res)
+
+proc exec*(db: TDbConn, stmtName: TSqlPrepared,
+          args: varargs[string]) {.tags: [FReadDB, FWriteDb].} =
+  var arr = allocCStringArray(args)
+  var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
+                           nil, nil, 0)
+  deallocCStringArray(arr)
+  if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
+  pqclear(res)
+
+proc newRow(L: int): TRow =
+  newSeq(result, L)
+  for i in 0..L-1: result[i] = ""
+  
+proc setupQuery(db: TDbConn, query: TSqlQuery,
+                args: varargs[string]): PPGresult =
+  var arr = allocCStringArray(args)
+  result = pqexecParams(db, query.string, int32(args.len), nil, arr,
+                        nil, nil, 0)
+  deallocCStringArray(arr)
+  if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
+
+proc setupQuery(db: TDbConn, stmtName: TSqlPrepared,
+                 args: varargs[string]): PPGresult =
+  var arr = allocCStringArray(args)
+  result = pqexecPrepared(db, stmtName.string, int32(args.len), arr,
+                          nil, nil, 0)
+  deallocCStringArray(arr)
+  if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db)
+
+proc prepare*(db: TDbConn; stmtName: string, query: TSqlQuery;
+              nParams: int): TSqlPrepared =
+  var res = pqprepare(db, stmtName, query.string, int32(nParams), nil)
+  if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db)
+  return TSqlPrepared(stmtName)
+   
+proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
+  for col in 0..cols-1:
+    setLen(r[col], 0)
+    let x = pqgetvalue(res, line, col)
+    if x.isNil:
+      r[col] = nil
+    else:
+      add(r[col], x)
+
+iterator fastRows*(db: TDbConn, query: TSqlQuery,
+                   args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## executes the query and iterates over the result dataset. This is very 
+  ## fast, but potenially dangerous: If the for-loop-body executes another
+  ## query, the results can be undefined. For Postgres it is safe though.
+  var res = setupQuery(db, query, args)
+  var L = pqnfields(res)
+  var result = newRow(L)
+  for i in 0..pqntuples(res)-1:
+    setRow(res, result, i, L)
+    yield result
+  pqclear(res)
+
+iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared,
+                   args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## executes the prepared query and iterates over the result dataset.
+  var res = setupQuery(db, stmtName, args)
+  var L = pqNfields(res)
+  var result = newRow(L)
+  for i in 0..pqNtuples(res)-1:
+    setRow(res, result, i, L)
+    yield result
+  pqClear(res)
+
+proc getRow*(db: TDbConn, query: TSqlQuery,
+             args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## retrieves a single row. If the query doesn't return any rows, this proc
+  ## will return a TRow with empty strings for each column.
+  var res = setupQuery(db, query, args)
+  var L = pqnfields(res)
+  result = newRow(L)
+  setRow(res, result, 0, L)
+  pqclear(res)
+
+proc getRow*(db: TDbConn, stmtName: TSqlPrepared,
+             args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  var res = setupQuery(db, stmtName, args)
+  var L = pqNfields(res)
+  result = newRow(L)
+  setRow(res, result, 0, L)
+  pqClear(res)
+
+proc getAllRows*(db: TDbConn, query: TSqlQuery,
+                 args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
+  ## executes the query and returns the whole result dataset.
+  result = @[]
+  for r in fastRows(db, query, args):
+    result.add(r)
+
+proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared,
+                 args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
+  ## executes the prepared query and returns the whole result dataset.
+  result = @[]
+  for r in fastRows(db, stmtName, args):
+    result.add(r)
+
+iterator rows*(db: TDbConn, query: TSqlQuery,
+               args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
+  ## same as `fastRows`, but slower and safe.
+  for r in items(getAllRows(db, query, args)): yield r
+
+proc getValue*(db: TDbConn, query: TSqlQuery,
+               args: varargs[string, `$`]): string {.tags: [FReadDB].} =
+  ## executes the query and returns the first column of the first row of the
+  ## result dataset. Returns "" if the dataset contains no rows or the database
+  ## value is NULL.
+  var x = pqgetvalue(setupQuery(db, query, args), 0, 0)
+  result = if isNil(x): "" else: $x
+  
+proc tryInsertID*(db: TDbConn, query: TSqlQuery,
+                  args: varargs[string, `$`]): int64  {.tags: [FWriteDb].}=
+  ## executes the query (typically "INSERT") and returns the 
+  ## generated ID for the row or -1 in case of an error. For Postgre this adds
+  ## ``RETURNING id`` to the query, so it only works if your primary key is
+  ## named ``id``. 
+  var x = pqgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"), 
+    args), 0, 0)
+  if not isNil(x):
+    result = parseBiggestInt($x)
+  else:
+    result = -1
+
+proc insertID*(db: TDbConn, query: TSqlQuery,
+               args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
+  ## executes the query (typically "INSERT") and returns the 
+  ## generated ID for the row. For Postgre this adds
+  ## ``RETURNING id`` to the query, so it only works if your primary key is
+  ## named ``id``. 
+  result = tryInsertID(db, query, args)
+  if result < 0: dbError(db)
+  
+proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
+                       args: varargs[string, `$`]): int64 {.tags: [
+                       FReadDB, FWriteDb].} =
+  ## executes the query (typically "UPDATE") and returns the
+  ## number of affected rows.
+  var q = dbFormat(query, args)
+  var res = pqExec(db, q)
+  if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db)
+  result = parseBiggestInt($pqcmdTuples(res))
+  pqclear(res)
+
+proc close*(db: TDbConn) {.tags: [FDb].} =
+  ## closes the database connection.
+  if db != nil: pqfinish(db)
+
+proc open*(connection, user, password, database: string): TDbConn {.
+  tags: [FDb].} =
+  ## opens a database connection. Raises `EDb` if the connection could not
+  ## be established.
+  ##
+  ## Clients can also use Postgres keyword/value connection strings to
+  ## connect.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##      con = open("", "", "", "host=localhost port=5432 dbname=mydb")
+  ##
+  ## See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
+  ## for more information.
+  ##
+  ## Note that the connection parameter is not used but exists to maintain
+  ## the nim db api.
+  result = pqsetdbLogin(nil, nil, nil, nil, database, user, password)
+  if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil
+
+proc setEncoding*(connection: TDbConn, encoding: string): bool {.
+  tags: [FDb].} =
+  ## sets the encoding of a database connection, returns true for 
+  ## success, false for failure.
+  return pqsetClientEncoding(connection, encoding) == 0
\ No newline at end of file
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
new file mode 100644
index 000000000..8536ab6f2
--- /dev/null
+++ b/lib/impure/db_sqlite.nim
@@ -0,0 +1,219 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## A higher level `SQLite`:idx: database wrapper. This interface 
+## is implemented for other databases too.
+
+import strutils, sqlite3
+
+type
+  TDbConn* = PSqlite3  ## encapsulates a database connection
+  TRow* = seq[string]  ## a row of a dataset. NULL database values will be
+                       ## transformed always to the empty string.
+  EDb* = object of IOError ## exception that is raised if a database error occurs
+  
+  TSqlQuery* = distinct string ## an SQL query string
+  
+  FDb* = object of IOEffect ## effect that denotes a database operation
+  FReadDb* = object of FDb   ## effect that denotes a read operation
+  FWriteDb* = object of FDb  ## effect that denotes a write operation
+  
+proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} =  
+  ## constructs a TSqlQuery from the string `query`. This is supposed to be 
+  ## used as a raw-string-literal modifier:
+  ## ``sql"update user set counter = counter + 1"``
+  ##
+  ## If assertions are turned off, it does nothing. If assertions are turned 
+  ## on, later versions will check the string for valid syntax.
+  result = TSqlQuery(query)
+ 
+proc dbError(db: TDbConn) {.noreturn.} = 
+  ## raises an EDb exception.
+  var e: ref EDb
+  new(e)
+  e.msg = $sqlite3.errmsg(db)
+  raise e
+
+proc dbError*(msg: string) {.noreturn.} = 
+  ## raises an EDb exception with message `msg`.
+  var e: ref EDb
+  new(e)
+  e.msg = msg
+  raise e
+
+proc dbQuote(s: string): string =
+  if s.isNil: return "NULL"
+  result = "'"
+  for c in items(s):
+    if c == '\'': add(result, "''")
+    else: add(result, c)
+  add(result, '\'')
+
+proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
+  result = ""
+  var a = 0
+  for c in items(string(formatstr)):
+    if c == '?':
+      add(result, dbQuote(args[a]))
+      inc(a)
+    else:
+      add(result, c)
+  
+proc tryExec*(db: TDbConn, query: TSqlQuery, 
+              args: varargs[string, `$`]): bool {.tags: [FReadDb, FWriteDb].} =
+  ## tries to execute the query and returns true if successful, false otherwise.
+  var q = dbFormat(query, args)
+  var stmt: sqlite3.Pstmt
+  if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
+    if step(stmt) == SQLITE_DONE:
+      result = finalize(stmt) == SQLITE_OK
+
+proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`])  {.
+  tags: [FReadDb, FWriteDb].} =
+  ## executes the query and raises EDB if not successful.
+  if not tryExec(db, query, args): dbError(db)
+  
+proc newRow(L: int): TRow =
+  newSeq(result, L)
+  for i in 0..L-1: result[i] = ""
+  
+proc setupQuery(db: TDbConn, query: TSqlQuery, 
+                args: varargs[string]): Pstmt = 
+  var q = dbFormat(query, args)
+  if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db)
+  
+proc setRow(stmt: Pstmt, r: var TRow, cols: cint) =
+  for col in 0..cols-1:
+    setLen(r[col], column_bytes(stmt, col)) # set capacity
+    setLen(r[col], 0)
+    let x = column_text(stmt, col)
+    if not isNil(x): add(r[col], x)
+  
+iterator fastRows*(db: TDbConn, query: TSqlQuery,
+                   args: varargs[string, `$`]): TRow  {.tags: [FReadDb].} =
+  ## executes the query and iterates over the result dataset. This is very 
+  ## fast, but potenially dangerous: If the for-loop-body executes another
+  ## query, the results can be undefined. For Sqlite it is safe though.
+  var stmt = setupQuery(db, query, args)
+  var L = (column_count(stmt))
+  var result = newRow(L)
+  while step(stmt) == SQLITE_ROW: 
+    setRow(stmt, result, L)
+    yield result
+  if finalize(stmt) != SQLITE_OK: dbError(db)
+
+proc getRow*(db: TDbConn, query: TSqlQuery,
+             args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
+  ## retrieves a single row. If the query doesn't return any rows, this proc
+  ## will return a TRow with empty strings for each column.
+  var stmt = setupQuery(db, query, args)
+  var L = (column_count(stmt))
+  result = newRow(L)
+  if step(stmt) == SQLITE_ROW: 
+    setRow(stmt, result, L)
+  if finalize(stmt) != SQLITE_OK: dbError(db)
+
+proc getAllRows*(db: TDbConn, query: TSqlQuery, 
+                 args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDb].} =
+  ## executes the query and returns the whole result dataset.
+  result = @[]
+  for r in fastRows(db, query, args):
+    result.add(r)
+
+iterator rows*(db: TDbConn, query: TSqlQuery, 
+               args: varargs[string, `$`]): TRow {.tags: [FReadDb].} =
+  ## same as `FastRows`, but slower and safe.
+  for r in fastRows(db, query, args): yield r
+
+proc getValue*(db: TDbConn, query: TSqlQuery, 
+               args: varargs[string, `$`]): string {.tags: [FReadDb].} = 
+  ## executes the query and returns the first column of the first row of the
+  ## result dataset. Returns "" if the dataset contains no rows or the database
+  ## value is NULL.
+  var stmt = setupQuery(db, query, args)
+  if step(stmt) == SQLITE_ROW:
+    let cb = column_bytes(stmt, 0)
+    if cb == 0: 
+      result = ""
+    else:
+      result = newStringOfCap(cb)
+      add(result, column_text(stmt, 0))
+  else:
+    result = ""
+  if finalize(stmt) != SQLITE_OK: dbError(db)
+  
+proc tryInsertID*(db: TDbConn, query: TSqlQuery, 
+                  args: varargs[string, `$`]): int64
+                  {.tags: [FWriteDb], raises: [].} =
+  ## executes the query (typically "INSERT") and returns the 
+  ## generated ID for the row or -1 in case of an error. 
+  var q = dbFormat(query, args)
+  var stmt: sqlite3.Pstmt
+  result = -1
+  if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
+    if step(stmt) == SQLITE_DONE:
+      result = last_insert_rowid(db)
+    if finalize(stmt) != SQLITE_OK:
+      result = -1
+
+proc insertID*(db: TDbConn, query: TSqlQuery, 
+               args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} = 
+  ## executes the query (typically "INSERT") and returns the 
+  ## generated ID for the row. For Postgre this adds
+  ## ``RETURNING id`` to the query, so it only works if your primary key is
+  ## named ``id``. 
+  result = tryInsertID(db, query, args)
+  if result < 0: dbError(db)
+  
+proc execAffectedRows*(db: TDbConn, query: TSqlQuery, 
+                       args: varargs[string, `$`]): int64 {.
+                       tags: [FReadDb, FWriteDb].} = 
+  ## executes the query (typically "UPDATE") and returns the
+  ## number of affected rows.
+  exec(db, query, args)
+  result = changes(db)
+
+proc close*(db: TDbConn) {.tags: [FDb].} = 
+  ## closes the database connection.
+  if sqlite3.close(db) != SQLITE_OK: dbError(db)
+    
+proc open*(connection, user, password, database: string): TDbConn {.
+  tags: [FDb].} =
+  ## opens a database connection. Raises `EDb` if the connection could not
+  ## be established. Only the ``connection`` parameter is used for ``sqlite``.
+  var db: TDbConn
+  if sqlite3.open(connection, db) == SQLITE_OK:
+    result = db
+  else:
+    dbError(db)
+
+proc setEncoding*(connection: TDbConn, encoding: string): bool {.
+  tags: [FDb].} =
+  ## sets the encoding of a database connection, returns true for 
+  ## success, false for failure.
+  ##
+  ## Note that the encoding cannot be changed once it's been set.
+  ## According to SQLite3 documentation, any attempt to change 
+  ## the encoding after the database is created will be silently 
+  ## ignored.
+  exec(connection, sql"PRAGMA encoding = ?", [encoding])
+  result = connection.getValue(sql"PRAGMA encoding") == encoding
+
+when not defined(testing) and isMainModule:
+  var db = open("db.sql", "", "", "")
+  exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
+  exec(db, sql"insert into tbl1 values('hello!',10)", [])
+  exec(db, sql"insert into tbl1 values('goodbye', 20)", [])
+  #db.query("create table tbl1(one varchar(10), two smallint)")
+  #db.query("insert into tbl1 values('hello!',10)")
+  #db.query("insert into tbl1 values('goodbye', 20)")
+  for r in db.rows(sql"select * from tbl1", []):
+    echo(r[0], r[1])
+  
+  db_sqlite.close(db)
diff --git a/lib/impure/dialogs.nim b/lib/impure/dialogs.nim
new file mode 100644
index 000000000..4ea66a6e6
--- /dev/null
+++ b/lib/impure/dialogs.nim
@@ -0,0 +1,226 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## This module implements portable dialogs for Nim; the implementation
+## builds on the GTK interface. On Windows, native dialogs are shown instead.
+
+import
+  glib2, gtk2
+
+when defined(Windows):
+  import windows, ShellAPI, os
+
+proc info*(window: PWindow, msg: string) =
+  ## Shows an information message to the user. The process waits until the
+  ## user presses the OK button.
+  when defined(Windows):
+    discard MessageBoxA(0, msg, "Information", MB_OK or MB_ICONINFORMATION)
+  else:
+    var dialog = message_dialog_new(window,
+                DIALOG_MODAL or DIALOG_DESTROY_WITH_PARENT,
+                MESSAGE_INFO, BUTTONS_OK, "%s", cstring(msg))
+    setTitle(dialog, "Information")
+    discard run(dialog)
+    destroy(PWidget(dialog))
+
+proc warning*(window: PWindow, msg: string) =
+  ## Shows a warning message to the user. The process waits until the user
+  ## presses the OK button.
+  when defined(Windows):
+    discard MessageBoxA(0, msg, "Warning", MB_OK or MB_ICONWARNING)
+  else:
+    var dialog = DIALOG(message_dialog_new(window,
+                DIALOG_MODAL or DIALOG_DESTROY_WITH_PARENT,
+                MESSAGE_WARNING, BUTTONS_OK, "%s", cstring(msg)))
+    setTitle(dialog, "Warning")
+    discard run(dialog)
+    destroy(PWidget(dialog))
+
+proc error*(window: PWindow, msg: string) =
+  ## Shows an error message to the user. The process waits until the user
+  ## presses the OK button.
+  when defined(Windows):
+    discard MessageBoxA(0, msg, "Error", MB_OK or MB_ICONERROR)
+  else:
+    var dialog = DIALOG(message_dialog_new(window,
+                DIALOG_MODAL or DIALOG_DESTROY_WITH_PARENT,
+                MESSAGE_ERROR, BUTTONS_OK, "%s", cstring(msg)))
+    setTitle(dialog, "Error")
+    discard run(dialog)
+    destroy(PWidget(dialog))
+
+
+proc chooseFileToOpen*(window: PWindow, root: string = ""): string =
+  ## Opens a dialog that requests a filename from the user. Returns ""
+  ## if the user closed the dialog without selecting a file. On Windows,
+  ## the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      opf: TOPENFILENAME
+      buf: array [0..2047, char]
+    opf.lStructSize = sizeof(opf).int32
+    if root.len > 0:
+      opf.lpstrInitialDir = root
+    opf.lpstrFilter = "All Files\0*.*\0\0"
+    opf.flags = OFN_FILEMUSTEXIST
+    opf.lpstrFile = buf
+    opf.nMaxFile = sizeof(buf).int32
+    var res = GetOpenFileName(addr(opf))
+    if res != 0:
+      result = $buf
+    else:
+      result = ""
+  else:
+    var chooser = file_chooser_dialog_new("Open File", window,
+                FILE_CHOOSER_ACTION_OPEN, 
+                STOCK_CANCEL, RESPONSE_CANCEL,
+                STOCK_OPEN, RESPONSE_OK, nil)
+    if root.len > 0:
+      discard set_current_folder(chooser, root)
+    if run(chooser) == cint(RESPONSE_OK):
+      var x = get_filename(chooser)
+      result = $x
+      g_free(x)
+    else:
+      result = ""
+    destroy(PWidget(chooser))
+
+proc chooseFilesToOpen*(window: PWindow, root: string = ""): seq[string] =
+  ## Opens a dialog that requests filenames from the user. Returns ``@[]``
+  ## if the user closed the dialog without selecting a file. On Windows,
+  ## the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      opf: TOPENFILENAME
+      buf: array [0..2047*4, char]
+    opf.lStructSize = sizeof(opf).int32
+    if root.len > 0:
+      opf.lpstrInitialDir = root
+    opf.lpstrFilter = "All Files\0*.*\0\0"
+    opf.flags = OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT or OFN_EXPLORER
+    opf.lpstrFile = buf
+    opf.nMaxFile = sizeof(buf).int32
+    var res = GetOpenFileName(addr(opf))
+    result = @[]
+    if res != 0:
+      # parsing the result is horrible:
+      var
+        i = 0
+        s: string
+        path = ""
+      while buf[i] != '\0':
+        add(path, buf[i])
+        inc(i)
+      inc(i)
+      if buf[i] != '\0':
+        while true:
+          s = ""
+          while buf[i] != '\0':
+            add(s, buf[i])
+            inc(i)
+          add(result, s)
+          inc(i)
+          if buf[i] == '\0': break
+        for i in 0..result.len-1: result[i] = os.joinPath(path, result[i])
+      else:
+        # only one file selected --> gosh, what an ungly thing 
+        # the windows API is
+        add(result, path) 
+  else:
+    var chooser = file_chooser_dialog_new("Open Files", window,
+                FILE_CHOOSER_ACTION_OPEN,
+                STOCK_CANCEL, RESPONSE_CANCEL,
+                STOCK_OPEN, RESPONSE_OK, nil)
+    if root.len > 0:
+      discard set_current_folder(chooser, root)
+    set_select_multiple(chooser, true)
+    result = @[]
+    if run(chooser) == cint(RESPONSE_OK):
+      var L = get_filenames(chooser)
+      var it = L
+      while it != nil:
+        add(result, $cast[cstring](it.data))
+        g_free(it.data)
+        it = it.next
+      free(L)
+    destroy(PWidget(chooser))
+
+
+proc chooseFileToSave*(window: PWindow, root: string = ""): string =
+  ## Opens a dialog that requests a filename to save to from the user.
+  ## Returns "" if the user closed the dialog without selecting a file.
+  ## On Windows, the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      opf: TOPENFILENAME
+      buf: array [0..2047, char]
+    opf.lStructSize = sizeof(opf).int32
+    if root.len > 0:
+      opf.lpstrInitialDir = root
+    opf.lpstrFilter = "All Files\0*.*\0\0"
+    opf.flags = OFN_OVERWRITEPROMPT
+    opf.lpstrFile = buf
+    opf.nMaxFile = sizeof(buf).int32
+    var res = GetSaveFileName(addr(opf))
+    if res != 0:
+      result = $buf
+    else:
+      result = ""
+  else:
+    var chooser = file_chooser_dialog_new("Save File", window,
+                FILE_CHOOSER_ACTION_SAVE,
+                STOCK_CANCEL, RESPONSE_CANCEL,
+                STOCK_SAVE, RESPONSE_OK, nil)
+    if root.len > 0:
+      discard set_current_folder(chooser, root)
+    set_do_overwrite_confirmation(chooser, true)
+    if run(chooser) == cint(RESPONSE_OK):
+      var x = get_filename(chooser)
+      result = $x
+      g_free(x)
+    else:
+      result = ""
+    destroy(PWidget(chooser))
+
+
+proc chooseDir*(window: PWindow, root: string = ""): string =
+  ## Opens a dialog that requests a directory from the user.
+  ## Returns "" if the user closed the dialog without selecting a directory.
+  ## On Windows, the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      lpItemID: PItemIDList
+      BrowseInfo: TBrowseInfo
+      DisplayName: array [0..MAX_PATH, char]
+      TempPath: array [0..MAX_PATH, char]
+    result = ""
+    #BrowseInfo.hwndOwner = Application.Handle
+    BrowseInfo.pszDisplayName = DisplayName
+    BrowseInfo.ulFlags = 1 #BIF_RETURNONLYFSDIRS
+    lpItemID = SHBrowseForFolder(cast[LPBrowseInfo](addr(BrowseInfo)))
+    if lpItemId != nil:
+      discard SHGetPathFromIDList(lpItemID, TempPath)
+      result = $TempPath
+      discard GlobalFreePtr(lpItemID)
+  else:
+    var chooser = file_chooser_dialog_new("Select Directory", window,
+                FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                STOCK_CANCEL, RESPONSE_CANCEL,
+                STOCK_OPEN, RESPONSE_OK, nil)
+    if root.len > 0:
+      discard set_current_folder(chooser, root)
+    if run(chooser) == cint(RESPONSE_OK):
+      var x = get_filename(chooser)
+      result = $x
+      g_free(x)
+    else:
+      result = ""
+    destroy(PWidget(chooser))
+
diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim
new file mode 100644
index 000000000..814c0ebe1
--- /dev/null
+++ b/lib/impure/graphics.nim
@@ -0,0 +1,575 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements graphical output for Nim; the current
+## implementation uses SDL but the interface is meant to support multiple
+## backends some day. There is no need to init SDL as this module does that 
+## implicitly.
+
+import colors, math
+from sdl import PSurface # Bug
+from sdl_ttf import openFont, closeFont
+
+type
+  TRect* = tuple[x, y, width, height: int]
+  TPoint* = tuple[x, y: int]
+
+  PSurface* = ref TSurface ## a surface to draw onto
+  TSurface* {.pure, final.} = object
+    w*, h*: Natural
+    s*: sdl.PSurface
+  
+  EGraphics* = object of IOError
+
+  TFont {.pure, final.} = object
+    f: sdl_ttf.PFont
+    color: sdl.TColor
+  PFont* = ref TFont ## represents a font
+
+proc toSdlColor*(c: Color): sdl.TColor =
+  ## Convert colors.TColor to sdl.TColor
+  var x = c.extractRGB  
+  result.r = x.r and 0xff
+  result.g = x.g and 0xff
+  result.b = x.b and 0xff
+
+proc createSdlColor*(sur: PSurface, c: Color, alpha: int = 0): int32 =
+  ## Creates a color using ``sdl.MapRGBA``.
+  var x = c.extractRGB
+  return sdl.mapRGBA(sur.s.format, x.r and 0xff, x.g and 0xff, 
+                     x.b and 0xff, alpha and 0xff)
+
+proc toSdlRect*(r: TRect): sdl.TRect =
+  ## Convert ``graphics.TRect`` to ``sdl.TRect``.
+  result.x = int16(r.x)
+  result.y = int16(r.y)
+  result.w = uint16(r.width)
+  result.h = uint16(r.height)
+
+proc raiseEGraphics = 
+  raise newException(EGraphics, $sdl.getError())
+  
+proc surfaceFinalizer(s: PSurface) = sdl.freeSurface(s.s)
+  
+proc newSurface*(width, height: int): PSurface =
+  ## creates a new surface.
+  new(result, surfaceFinalizer)
+  result.w = width
+  result.h = height
+  result.s = sdl.createRGBSurface(sdl.SWSURFACE, width, height, 
+      32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0)
+  if result.s == nil:
+    raiseEGraphics()
+  
+  assert(not sdl.mustLock(result.s))
+
+proc fontFinalizer(f: PFont) = closeFont(f.f)
+
+proc newFont*(name = "VeraMono.ttf", size = 9, color = colBlack): PFont =  
+  ## Creates a new font object. Raises ``EIO`` if the font cannot be loaded.
+  new(result, fontFinalizer)
+  result.f = openFont(name, size.cint)
+  if result.f == nil:
+    raise newException(IOError, "Could not open font file: " & name)
+  result.color = toSdlColor(color)
+
+var
+  defaultFont*: PFont ## default font that is used; this needs to initialized
+                      ## by the client!
+
+proc initDefaultFont*(name = "VeraMono.ttf", size = 9, color = colBlack) = 
+  ## initializes the `defaultFont` var.
+  defaultFont = newFont(name, size, color)
+
+proc newScreenSurface*(width, height: int): PSurface =
+  ## Creates a new screen surface
+  new(result, surfaceFinalizer)
+  result.w = width
+  result.h = height
+  result.s = sdl.setVideoMode(width, height, 0, 0)
+  if result.s == nil:
+    raiseEGraphics()
+
+proc writeToBMP*(sur: PSurface, filename: string) =
+  ## Saves the contents of the surface `sur` to the file `filename` as a 
+  ## BMP file.
+  if sdl.saveBMP(sur.s, filename) != 0:
+    raise newException(IOError, "cannot write: " & filename)
+
+type
+  TPixels = array[0..1000_000-1, int32]
+  PPixels = ptr TPixels
+
+template setPix(video, pitch, x, y, col: expr): stmt =
+  video[y * pitch + x] = int32(col)
+
+template getPix(video, pitch, x, y: expr): expr = 
+  colors.Color(video[y * pitch + x])
+
+const
+  ColSize = 4
+
+proc getPixel(sur: PSurface, x, y: Natural): colors.Color {.inline.} =
+  assert x <% sur.w
+  assert y <% sur.h
+  result = getPix(cast[PPixels](sur.s.pixels), sur.s.pitch.int div ColSize, 
+                  x, y)
+
+proc setPixel(sur: PSurface, x, y: Natural, col: colors.Color) {.inline.} =
+  assert x <% sur.w
+  assert y <% sur.h
+  var pixs = cast[PPixels](sur.s.pixels)
+  #pixs[y * (sur.s.pitch div colSize) + x] = int(col)
+  setPix(pixs, sur.s.pitch.int div ColSize, x, y, col)
+
+proc `[]`*(sur: PSurface, p: TPoint): Color =
+  ## get pixel at position `p`. No range checking is done!
+  result = getPixel(sur, p.x, p.y)
+
+proc `[]`*(sur: PSurface, x, y: int): Color =
+  ## get pixel at position ``(x, y)``. No range checking is done!
+  result = getPixel(sur, x, y)
+
+proc `[]=`*(sur: PSurface, p: TPoint, col: Color) =
+  ## set the pixel at position `p`. No range checking is done!
+  setPixel(sur, p.x, p.y, col)
+
+proc `[]=`*(sur: PSurface, x, y: int, col: Color) =
+  ## set the pixel at position ``(x, y)``. No range checking is done!
+  setPixel(sur, x, y, col)
+
+proc blit*(destSurf: PSurface, destRect: TRect, srcSurf: PSurface, 
+           srcRect: TRect) =
+  ## Copies ``srcSurf`` into ``destSurf``
+  var destTRect, srcTRect: sdl.TRect
+
+  destTRect.x = int16(destRect.x)
+  destTRect.y = int16(destRect.y)
+  destTRect.w = uint16(destRect.width)
+  destTRect.h = uint16(destRect.height)
+
+  srcTRect.x = int16(srcRect.x)
+  srcTRect.y = int16(srcRect.y)
+  srcTRect.w = uint16(srcRect.width)
+  srcTRect.h = uint16(srcRect.height)
+
+  if sdl.blitSurface(srcSurf.s, addr(srcTRect), destSurf.s, addr(destTRect)) != 0:
+    raiseEGraphics()
+
+proc textBounds*(text: string, font = defaultFont): tuple[width, height: int] =
+  var w, h: cint
+  if sdl_ttf.sizeUTF8(font.f, text, w, h) < 0: raiseEGraphics()
+  result.width = int(w)
+  result.height = int(h)
+
+proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) =
+  ## Draws text with a transparent background, at location ``p`` with the given
+  ## font.
+  var textSur: PSurface # This surface will have the text drawn on it
+  new(textSur, surfaceFinalizer)
+  
+  # Render the text
+  textSur.s = sdl_ttf.renderTextBlended(font.f, text, font.color)
+  # Merge the text surface with sur
+  sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
+
+proc drawText*(sur: PSurface, p: TPoint, text: string,
+               bg: Color, font = defaultFont) =
+  ## Draws text, at location ``p`` with font ``font``. ``bg`` 
+  ## is the background color.
+  var textSur: PSurface # This surface will have the text drawn on it
+  new(textSur, surfaceFinalizer)
+  textSur.s = sdl_ttf.renderTextShaded(font.f, text, font.color, toSdlColor(bg))
+  # Merge the text surface with sur
+  sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h))
+  
+proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: Color) =
+  ## draws a circle with center `p` and radius `r` with the given color
+  ## onto the surface `sur`.
+  var video = cast[PPixels](sur.s.pixels)
+  var pitch = sur.s.pitch.int div ColSize
+  var a = 1 - r
+  var py = r
+  var px = 0
+  var x = p.x
+  var y = p.y
+  while px <= py + 1:
+    if x+px <% sur.w:
+      if y+py <% sur.h: setPix(video, pitch, x+px, y+py, color)
+      if y-py <% sur.h: setPix(video, pitch, x+px, y-py, color)
+    
+    if x-px <% sur.w:
+      if y+py <% sur.h: setPix(video, pitch, x-px, y+py, color)
+      if y-py <% sur.h: setPix(video, pitch, x-px, y-py, color)
+
+    if x+py <% sur.w:
+      if y+px <% sur.h: setPix(video, pitch, x+py, y+px, color)
+      if y-px <% sur.h: setPix(video, pitch, x+py, y-px, color)
+      
+    if x-py <% sur.w:
+      if y+px <% sur.h: setPix(video, pitch, x-py, y+px, color)
+      if y-px <% sur.h: setPix(video, pitch, x-py, y-px, color)
+
+    if a < 0:
+      a = a + (2 * px + 3)
+    else:
+      a = a + (2 * (px - py) + 5)
+      py = py - 1
+    px = px + 1
+
+proc `>-<`(val: int, s: PSurface): int {.inline.} = 
+  return if val < 0: 0 elif val >= s.w: s.w-1 else: val
+
+proc `>|<`(val: int, s: PSurface): int {.inline.} = 
+  return if val < 0: 0 elif val >= s.h: s.h-1 else: val
+
+proc drawLine*(sur: PSurface, p1, p2: TPoint, color: Color) =
+  ## draws a line between the two points `p1` and `p2` with the given color
+  ## onto the surface `sur`.
+  var stepx, stepy: int = 0
+  var x0 = p1.x >-< sur
+  var x1 = p2.x >-< sur
+  var y0 = p1.y >|< sur
+  var y1 = p2.y >|< sur
+  var dy = y1 - y0
+  var dx = x1 - x0
+  if dy < 0:
+    dy = -dy 
+    stepy = -1
+  else:
+    stepy = 1
+  if dx < 0:
+    dx = -dx
+    stepx = -1
+  else:
+    stepx = 1
+  dy = dy * 2 
+  dx = dx * 2
+  var video = cast[PPixels](sur.s.pixels)
+  var pitch = sur.s.pitch.int div ColSize
+  setPix(video, pitch, x0, y0, color)
+  if dx > dy:
+    var fraction = dy - (dx div 2)
+    while x0 != x1:
+      if fraction >= 0:
+        y0 = y0 + stepy
+        fraction = fraction - dx
+      x0 = x0 + stepx
+      fraction = fraction + dy
+      setPix(video, pitch, x0, y0, color)
+  else:
+    var fraction = dx - (dy div 2)
+    while y0 != y1:
+      if fraction >= 0:
+        x0 = x0 + stepx
+        fraction = fraction - dy
+      y0 = y0 + stepy
+      fraction = fraction + dx
+      setPix(video, pitch, x0, y0, color)
+
+proc drawHorLine*(sur: PSurface, x, y, w: Natural, color: Color) =
+  ## draws a horizontal line from (x,y) to (x+w-1, y).
+  var video = cast[PPixels](sur.s.pixels)
+  var pitch = sur.s.pitch.int div ColSize
+
+  if y >= 0 and y <= sur.s.h:
+    for i in 0 .. min(sur.s.w-x, w)-1:
+      setPix(video, pitch, x + i, y, color)
+
+proc drawVerLine*(sur: PSurface, x, y, h: Natural, color: Color) =
+  ## draws a vertical line from (x,y) to (x, y+h-1).
+  var video = cast[PPixels](sur.s.pixels)
+  var pitch = sur.s.pitch.int div ColSize
+
+  if x >= 0 and x <= sur.s.w:
+    for i in 0 .. min(sur.s.h-y, h)-1:
+      setPix(video, pitch, x, y + i, color)
+
+proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: Color) =
+  ## draws a circle with center `p` and radius `r` with the given color
+  ## onto the surface `sur` and fills it.
+  var a = 1 - r
+  var py: int = r
+  var px = 0
+  var x = p.x
+  var y = p.y
+  while px <= py:
+    # Fill up the middle half of the circle
+    drawVerLine(s, x + px, y, py + 1, color)
+    drawVerLine(s, x + px, y - py, py, color)
+    if px != 0:
+      drawVerLine(s, x - px, y, py + 1, color)
+      drawVerLine(s, x - px, y - py, py, color)
+    if a < 0:
+      a = a + (2 * px + 3)
+    else:
+      a = a + (2 * (px - py) + 5)
+      py = py - 1
+      # Fill up the left/right half of the circle
+      if py >= px:
+        drawVerLine(s, x + py + 1, y, px + 1, color)
+        drawVerLine(s, x + py + 1, y - px, px, color)
+        drawVerLine(s, x - py - 1, y, px + 1, color)
+        drawVerLine(s, x - py - 1, y - px,  px, color)
+    px = px + 1
+
+proc drawRect*(sur: PSurface, r: TRect, color: Color) =
+  ## draws a rectangle.
+  var video = cast[PPixels](sur.s.pixels)
+  var pitch = sur.s.pitch.int div ColSize
+  if (r.x >= 0 and r.x <= sur.s.w) and (r.y >= 0 and r.y <= sur.s.h):
+    var minW = min(sur.s.w - r.x, r.width)
+    var minH = min(sur.s.h - r.y, r.height)
+    
+    # Draw Top
+    for i in 0 .. minW - 1:
+      setPix(video, pitch, r.x + i, r.y, color)
+      setPix(video, pitch, r.x + i, r.y + minH - 1, color) # Draw bottom
+      
+    # Draw left side
+    for i in 0 .. minH - 1:
+      setPix(video, pitch, r.x, r.y + i, color)
+      setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side
+    
+proc fillRect*(sur: PSurface, r: TRect, col: Color) =
+  ## Fills a rectangle using sdl's ``FillRect`` function.
+  var rect = toSdlRect(r)
+  if sdl.fillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1:
+    raiseEGraphics()
+
+proc plot4EllipsePoints(sur: PSurface, cx, cy, x, y: Natural, col: Color) =
+  var video = cast[PPixels](sur.s.pixels)
+  var pitch = sur.s.pitch.int div ColSize
+  if cx+x <= sur.s.w-1:
+    if cy+y <= sur.s.h-1: setPix(video, pitch, cx+x, cy+y, col)
+    if cy-y <= sur.s.h-1: setPix(video, pitch, cx+x, cy-y, col)    
+  if cx-x <= sur.s.w-1:
+    if cy+y <= sur.s.h-1: setPix(video, pitch, cx-x, cy+y, col)
+    if cy-y <= sur.s.h-1: setPix(video, pitch, cx-x, cy-y, col)
+
+proc drawEllipse*(sur: PSurface, cx, cy, xRadius, yRadius: Natural, 
+                  col: Color) =
+  ## Draws an ellipse, ``CX`` and ``CY`` specify the center X and Y of the 
+  ## ellipse, ``XRadius`` and ``YRadius`` specify half the width and height
+  ## of the ellipse.
+  var 
+    x, y: Natural
+    xChange, yChange: int
+    ellipseError: Natural
+    twoASquare, twoBSquare: Natural
+    stoppingX, stoppingY: Natural
+    
+  twoASquare = 2 * xRadius * xRadius
+  twoBSquare = 2 * yRadius * yRadius
+  x = xRadius
+  y = 0
+  xChange = yRadius * yRadius * (1 - 2 * xRadius)
+  yChange = xRadius * xRadius
+  ellipseError = 0
+  stoppingX = twoBSquare * xRadius
+  stoppingY = 0
+  
+  while stoppingX >=  stoppingY: # 1st set of points, y` > - 1
+    sur.plot4EllipsePoints(cx, cy, x, y, col)
+    inc(y)
+    inc(stoppingY, twoASquare)
+    inc(ellipseError, yChange)
+    inc(yChange, twoASquare)
+    if (2 * ellipseError + xChange) > 0 :
+      dec(x)
+      dec(stoppingX, twoBSquare)
+      inc(ellipseError, xChange)
+      inc(xChange, twoBSquare)
+      
+  # 1st point set is done; start the 2nd set of points
+  x = 0
+  y = yRadius
+  xChange = yRadius * yRadius
+  yChange = xRadius * xRadius * (1 - 2 * yRadius)
+  ellipseError = 0
+  stoppingX = 0
+  stoppingY = twoASquare * yRadius
+  while stoppingX <= stoppingY:
+    sur.plot4EllipsePoints(cx, cy, x, y, col)
+    inc(x)
+    inc(stoppingX, twoBSquare)
+    inc(ellipseError, xChange)
+    inc(xChange,twoBSquare)
+    if (2 * ellipseError + yChange) > 0:
+      dec(y)
+      dec(stoppingY, twoASquare)
+      inc(ellipseError, yChange)
+      inc(yChange,twoASquare)
+  
+
+proc plotAA(sur: PSurface, x, y: int, c: float, color: Color) =
+  if (x > 0 and x < sur.s.w) and (y > 0 and y < sur.s.h):
+    var video = cast[PPixels](sur.s.pixels)
+    var pitch = sur.s.pitch.int div ColSize
+
+    var pixColor = getPix(video, pitch, x, y)
+
+    setPix(video, pitch, x, y,
+           pixColor.intensity(1.0 - c) + color.intensity(c))
+ 
+
+template ipart(x: expr): expr = floor(x) 
+template cround(x: expr): expr = ipart(x + 0.5)
+template fpart(x: expr): expr = x - ipart(x)
+template rfpart(x: expr): expr = 1.0 - fpart(x)
+
+proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: Color) =
+  ## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's 
+  ## line algorithm
+  var (x1, x2, y1, y2) = (p1.x.toFloat(), p2.x.toFloat(), 
+                          p1.y.toFloat(), p2.y.toFloat())
+  var dx = x2 - x1
+  var dy = y2 - y1
+  
+  var ax = dx
+  if ax < 0'f64:
+    ax = 0'f64 - ax
+  var ay = dy
+  if ay < 0'f64:
+    ay = 0'f64 - ay
+  
+  if ax < ay:
+    swap(x1, y1)
+    swap(x2, y2)
+    swap(dx, dy)
+  
+  template doPlot(x, y: int, c: float, color: Color): stmt =
+    if ax < ay:
+      sur.plotAA(y, x, c, color)
+    else:
+      sur.plotAA(x, y, c, color)
+  
+  if x2 < x1:
+    swap(x1, x2)
+    swap(y1, y2)
+  
+  var gradient = dy / dx
+  # handle first endpoint
+  var xend = cround(x1)
+  var yend = y1 + gradient * (xend - x1)
+  var xgap = rfpart(x1 + 0.5)
+  var xpxl1 = int(xend) # this will be used in the main loop
+  var ypxl1 = int(ipart(yend))
+  doPlot(xpxl1, ypxl1, rfpart(yend)*xgap, color)
+  doPlot(xpxl1, ypxl1 + 1, fpart(yend)*xgap, color)
+  var intery = yend + gradient # first y-intersection for the main loop
+
+  # handle second endpoint
+  xend = cround(x2)
+  yend = y2 + gradient * (xend - x2)
+  xgap = fpart(x2 + 0.5)
+  var xpxl2 = int(xend) # this will be used in the main loop
+  var ypxl2 = int(ipart(yend))
+  doPlot(xpxl2, ypxl2, rfpart(yend) * xgap, color)
+  doPlot(xpxl2, ypxl2 + 1, fpart(yend) * xgap, color)
+
+  # main loop
+  var x = xpxl1 + 1
+  while x <= xpxl2-1:
+    doPlot(x, int(ipart(intery)), rfpart(intery), color)
+    doPlot(x, int(ipart(intery)) + 1, fpart(intery), color)
+    intery = intery + gradient
+    inc(x)
+
+proc fillSurface*(sur: PSurface, color: Color) =
+  ## Fills the entire surface with ``color``.
+  if sdl.fillRect(sur.s, nil, sur.createSdlColor(color)) == -1:
+    raiseEGraphics()
+
+template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
+  immediate.} =
+  ## Simple template which creates an event loop. ``Event`` is the name of the
+  ## variable containing the TEvent object.
+  while true:
+    var event: sdl.TEvent
+    if sdl.waitEvent(addr(event)) == 1:
+      actions
+
+if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
+if sdl_ttf.init() < 0: raiseEGraphics()
+
+when not defined(testing) and isMainModule:
+  var surf = newScreenSurface(800, 600)
+
+  surf.fillSurface(colWhite)
+
+  # Draw the shapes
+  surf.drawLineAA((150, 170), (400, 471), colTan)
+  surf.drawLine((100, 170), (400, 471), colRed)
+  
+  surf.drawEllipse(200, 300, 200, 30, colSeaGreen)
+  surf.drawHorLine(1, 300, 400, colViolet) 
+  # Check if the ellipse is the size it's suppose to be.
+  surf.drawVerLine(200, 300 - 30 + 1, 60, colViolet) # ^^ | i suppose it is
+  
+  surf.drawEllipse(400, 300, 300, 300, colOrange)
+  surf.drawEllipse(5, 5, 5, 5, colGreen)
+  
+  surf.drawHorLine(5, 5, 900, colRed)
+  surf.drawVerLine(5, 60, 800, colRed)
+  surf.drawCircle((600, 500), 60, colRed)
+  
+  surf.fillRect((50, 50, 100, 100), colFuchsia)
+  surf.fillRect((150, 50, 100, 100), colGreen)
+  surf.drawRect((50, 150, 100, 100), colGreen)
+  surf.drawRect((150, 150, 100, 100), colAqua)
+  surf.drawRect((250, 150, 100, 100), colBlue)
+  surf.drawHorLine(250, 150, 100, colRed)
+
+  surf.drawLineAA((592, 160), (592, 280), colPurple)
+  
+  #surf.drawText((300, 300), "TEST", colMidnightBlue)
+  #var textSize = textBounds("TEST")
+  #surf.drawText((300, 300 + textSize.height), $textSize.width & ", " &
+  #  $textSize.height, colDarkGreen)
+  
+  var mouseStartX = -1
+  var mouseStartY = -1
+  withEvents(surf, event):
+    var eventp = addr(event)
+    case event.kind:
+    of sdl.QUITEV:
+      break
+    of sdl.KEYDOWN:
+      var evk = sdl.evKeyboard(eventp)
+      if evk.keysym.sym == sdl.K_LEFT:
+        surf.drawHorLine(395, 300, 50, colBlack)
+        echo("Drawing")
+      elif evk.keysym.sym == sdl.K_ESCAPE:
+        break
+      else:
+        echo(evk.keysym.sym)
+    of sdl.MOUSEBUTTONDOWN:
+      var mbd = sdl.evMouseButton(eventp)
+      if mouseStartX == -1 or mouseStartY == -1:
+        mouseStartX = int(mbd.x)
+        mouseStartY = int(mbd.y)
+      else:
+        surf.drawLineAA((mouseStartX, mouseStartY), (int(mbd.x), int(mbd.y)), colPurple)
+        mouseStartX = -1
+        mouseStartY = -1
+        
+    of sdl.MOUSEMOTION:
+      var mm = sdl.evMouseMotion(eventp)
+      if mouseStartX != -1 and mouseStartY != -1:
+        surf.drawLineAA((mouseStartX, mouseStartY), (int(mm.x), int(mm.y)), colPurple)
+      #echo(mm.x, " ", mm.y, " ", mm.yrel)
+    
+    else:
+      discard "echo(event.kind)"
+      
+    sdl.updateRect(surf.s, 0, 0, 800, 600)
+    
+  surf.writeToBMP("test.bmp")
+  sdl.quit()
diff --git a/lib/impure/nre/.gitignore b/lib/impure/nre/.gitignore
new file mode 100644
index 000000000..3d647a25e
--- /dev/null
+++ b/lib/impure/nre/.gitignore
@@ -0,0 +1,9 @@
+# all executables
+*
+!*/
+!*.*
+*.exe
+
+# Wildcard patterns.
+*.swp
+nimcache
diff --git a/LICENCE b/lib/impure/nre/LICENCE
index 561f818ac..561f818ac 100644
--- a/LICENCE
+++ b/lib/impure/nre/LICENCE
diff --git a/README.rst b/lib/impure/nre/README.rst
index c767038db..c767038db 100644
--- a/README.rst
+++ b/lib/impure/nre/README.rst
diff --git a/circle.yml b/lib/impure/nre/circle.yml
index b6105af65..b6105af65 100644
--- a/circle.yml
+++ b/lib/impure/nre/circle.yml
diff --git a/nre.nimble b/lib/impure/nre/nre.nimble
index b007ff617..b007ff617 100644
--- a/nre.nimble
+++ b/lib/impure/nre/nre.nimble
diff --git a/runtests.sh b/lib/impure/nre/runtests.sh
index 51dbcaf35..51dbcaf35 100755
--- a/runtests.sh
+++ b/lib/impure/nre/runtests.sh
diff --git a/src/nre.nim b/lib/impure/nre/src/nre.nim
index 2706398ee..2706398ee 100644
--- a/src/nre.nim
+++ b/lib/impure/nre/src/nre.nim
diff --git a/src/private/pcre.h b/lib/impure/nre/src/private/pcre.h
index b2d9c05e5..b2d9c05e5 100644
--- a/src/private/pcre.h
+++ b/lib/impure/nre/src/private/pcre.h
diff --git a/src/private/pcre.nim b/lib/impure/nre/src/private/pcre.nim
index 3d619d268..3d619d268 100644
--- a/src/private/pcre.nim
+++ b/lib/impure/nre/src/private/pcre.nim
diff --git a/src/private/pcre_src/config.h b/lib/impure/nre/src/private/pcre_src/config.h
index 55c8a27c2..55c8a27c2 100644
--- a/src/private/pcre_src/config.h
+++ b/lib/impure/nre/src/private/pcre_src/config.h
diff --git a/src/private/pcre_src/pcre.h b/lib/impure/nre/src/private/pcre_src/pcre.h
index 9216d55b0..9216d55b0 100644
--- a/src/private/pcre_src/pcre.h
+++ b/lib/impure/nre/src/private/pcre_src/pcre.h
diff --git a/src/private/pcre_src/pcre_byte_order.c b/lib/impure/nre/src/private/pcre_src/pcre_byte_order.c
index cf5f12b04..cf5f12b04 100644
--- a/src/private/pcre_src/pcre_byte_order.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_byte_order.c
diff --git a/src/private/pcre_src/pcre_chartables.c b/lib/impure/nre/src/private/pcre_src/pcre_chartables.c
index 1e20ec29d..1e20ec29d 100644
--- a/src/private/pcre_src/pcre_chartables.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_chartables.c
diff --git a/src/private/pcre_src/pcre_compile.c b/lib/impure/nre/src/private/pcre_src/pcre_compile.c
index efc0b21fd..efc0b21fd 100644
--- a/src/private/pcre_src/pcre_compile.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_compile.c
diff --git a/src/private/pcre_src/pcre_config.c b/lib/impure/nre/src/private/pcre_src/pcre_config.c
index 1cbdd9c96..1cbdd9c96 100644
--- a/src/private/pcre_src/pcre_config.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_config.c
diff --git a/src/private/pcre_src/pcre_dfa_exec.c b/lib/impure/nre/src/private/pcre_src/pcre_dfa_exec.c
index 87f4aef9a..87f4aef9a 100644
--- a/src/private/pcre_src/pcre_dfa_exec.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_dfa_exec.c
diff --git a/src/private/pcre_src/pcre_exec.c b/lib/impure/nre/src/private/pcre_src/pcre_exec.c
index 654eb9e27..654eb9e27 100644
--- a/src/private/pcre_src/pcre_exec.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_exec.c
diff --git a/src/private/pcre_src/pcre_fullinfo.c b/lib/impure/nre/src/private/pcre_src/pcre_fullinfo.c
index a6c2ece6c..a6c2ece6c 100644
--- a/src/private/pcre_src/pcre_fullinfo.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_fullinfo.c
diff --git a/src/private/pcre_src/pcre_get.c b/lib/impure/nre/src/private/pcre_src/pcre_get.c
index 8094b34bb..8094b34bb 100644
--- a/src/private/pcre_src/pcre_get.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_get.c
diff --git a/src/private/pcre_src/pcre_globals.c b/lib/impure/nre/src/private/pcre_src/pcre_globals.c
index 0f106aa90..0f106aa90 100644
--- a/src/private/pcre_src/pcre_globals.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_globals.c
diff --git a/src/private/pcre_src/pcre_internal.h b/lib/impure/nre/src/private/pcre_src/pcre_internal.h
index 02d3ab17c..02d3ab17c 100644
--- a/src/private/pcre_src/pcre_internal.h
+++ b/lib/impure/nre/src/private/pcre_src/pcre_internal.h
diff --git a/src/private/pcre_src/pcre_jit_compile.c b/lib/impure/nre/src/private/pcre_src/pcre_jit_compile.c
index 256e3a45b..256e3a45b 100644
--- a/src/private/pcre_src/pcre_jit_compile.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_jit_compile.c
diff --git a/src/private/pcre_src/pcre_maketables.c b/lib/impure/nre/src/private/pcre_src/pcre_maketables.c
index a44a6eaa9..a44a6eaa9 100644
--- a/src/private/pcre_src/pcre_maketables.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_maketables.c
diff --git a/src/private/pcre_src/pcre_newline.c b/lib/impure/nre/src/private/pcre_src/pcre_newline.c
index b8f5a4de1..b8f5a4de1 100644
--- a/src/private/pcre_src/pcre_newline.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_newline.c
diff --git a/src/private/pcre_src/pcre_ord2utf8.c b/lib/impure/nre/src/private/pcre_src/pcre_ord2utf8.c
index 95f1beb96..95f1beb96 100644
--- a/src/private/pcre_src/pcre_ord2utf8.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_ord2utf8.c
diff --git a/src/private/pcre_src/pcre_refcount.c b/lib/impure/nre/src/private/pcre_src/pcre_refcount.c
index 79efa90f2..79efa90f2 100644
--- a/src/private/pcre_src/pcre_refcount.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_refcount.c
diff --git a/src/private/pcre_src/pcre_string_utils.c b/lib/impure/nre/src/private/pcre_src/pcre_string_utils.c
index 25eacc850..25eacc850 100644
--- a/src/private/pcre_src/pcre_string_utils.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_string_utils.c
diff --git a/src/private/pcre_src/pcre_study.c b/lib/impure/nre/src/private/pcre_src/pcre_study.c
index f19d9fbb9..f19d9fbb9 100644
--- a/src/private/pcre_src/pcre_study.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_study.c
diff --git a/src/private/pcre_src/pcre_tables.c b/lib/impure/nre/src/private/pcre_src/pcre_tables.c
index 4960af57c..4960af57c 100644
--- a/src/private/pcre_src/pcre_tables.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_tables.c
diff --git a/src/private/pcre_src/pcre_ucd.c b/lib/impure/nre/src/private/pcre_src/pcre_ucd.c
index 69c4fd42c..69c4fd42c 100644
--- a/src/private/pcre_src/pcre_ucd.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_ucd.c
diff --git a/src/private/pcre_src/pcre_valid_utf8.c b/lib/impure/nre/src/private/pcre_src/pcre_valid_utf8.c
index 3b0f6464a..3b0f6464a 100644
--- a/src/private/pcre_src/pcre_valid_utf8.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_valid_utf8.c
diff --git a/src/private/pcre_src/pcre_version.c b/lib/impure/nre/src/private/pcre_src/pcre_version.c
index ae86ff28b..ae86ff28b 100644
--- a/src/private/pcre_src/pcre_version.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_version.c
diff --git a/src/private/pcre_src/pcre_xclass.c b/lib/impure/nre/src/private/pcre_src/pcre_xclass.c
index c2b61f0f9..c2b61f0f9 100644
--- a/src/private/pcre_src/pcre_xclass.c
+++ b/lib/impure/nre/src/private/pcre_src/pcre_xclass.c
diff --git a/src/private/pcre_src/ucp.h b/lib/impure/nre/src/private/pcre_src/ucp.h
index 2fa00296e..2fa00296e 100644
--- a/src/private/pcre_src/ucp.h
+++ b/lib/impure/nre/src/private/pcre_src/ucp.h
diff --git a/src/private/util.nim b/lib/impure/nre/src/private/util.nim
index 00fd40fac..00fd40fac 100644
--- a/src/private/util.nim
+++ b/lib/impure/nre/src/private/util.nim
diff --git a/test/captures.nim b/lib/impure/nre/test/captures.nim
index 4f3f15444..4f3f15444 100644
--- a/test/captures.nim
+++ b/lib/impure/nre/test/captures.nim
diff --git a/test/escape.nim b/lib/impure/nre/test/escape.nim
index db5e8a001..db5e8a001 100644
--- a/test/escape.nim
+++ b/lib/impure/nre/test/escape.nim
diff --git a/test/find.nim b/lib/impure/nre/test/find.nim
index 05bfb848a..05bfb848a 100644
--- a/test/find.nim
+++ b/lib/impure/nre/test/find.nim
diff --git a/test/init.nim b/lib/impure/nre/test/init.nim
index 76ffaba19..76ffaba19 100644
--- a/test/init.nim
+++ b/lib/impure/nre/test/init.nim
diff --git a/test/match.nim b/lib/impure/nre/test/match.nim
index 38ee5214b..38ee5214b 100644
--- a/test/match.nim
+++ b/lib/impure/nre/test/match.nim
diff --git a/test/misc.nim b/lib/impure/nre/test/misc.nim
index f4a88b639..f4a88b639 100644
--- a/test/misc.nim
+++ b/lib/impure/nre/test/misc.nim
diff --git a/test/optional_nonstrict.nim b/lib/impure/nre/test/optional_nonstrict.nim
index d13f4fab7..d13f4fab7 100644
--- a/test/optional_nonstrict.nim
+++ b/lib/impure/nre/test/optional_nonstrict.nim
diff --git a/test/replace.nim b/lib/impure/nre/test/replace.nim
index 516fd4328..516fd4328 100644
--- a/test/replace.nim
+++ b/lib/impure/nre/test/replace.nim
diff --git a/test/split.nim b/lib/impure/nre/test/split.nim
index 8064e40b7..8064e40b7 100644
--- a/test/split.nim
+++ b/lib/impure/nre/test/split.nim
diff --git a/test/testall.nim b/lib/impure/nre/test/testall.nim
index f7fe8892a..f7fe8892a 100644
--- a/test/testall.nim
+++ b/lib/impure/nre/test/testall.nim
diff --git a/web/logo.png b/lib/impure/nre/web/logo.png
index ca41ec7b7..ca41ec7b7 100644
--- a/web/logo.png
+++ b/lib/impure/nre/web/logo.png
Binary files differdiff --git a/web/logo.svg b/lib/impure/nre/web/logo.svg
index 41d142b2a..41d142b2a 100644
--- a/web/logo.svg
+++ b/lib/impure/nre/web/logo.svg
diff --git a/lib/impure/osinfo_posix.nim b/lib/impure/osinfo_posix.nim
new file mode 100644
index 000000000..0362fca12
--- /dev/null
+++ b/lib/impure/osinfo_posix.nim
@@ -0,0 +1,10 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.error: "This module has been moved to the 'osinfo' nimble package.".}
diff --git a/lib/impure/osinfo_win.nim b/lib/impure/osinfo_win.nim
new file mode 100644
index 000000000..0362fca12
--- /dev/null
+++ b/lib/impure/osinfo_win.nim
@@ -0,0 +1,10 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.error: "This module has been moved to the 'osinfo' nimble package.".}
diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim
new file mode 100644
index 000000000..f4d00979c
--- /dev/null
+++ b/lib/impure/rdstdin.nim
@@ -0,0 +1,148 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains code for reading from `stdin`:idx:. On UNIX the GNU
+## readline library is wrapped and set up to provide default key bindings
+## (e.g. you can navigate with the arrow keys). On Windows ``system.readLine``
+## is used. This suffices because Windows' console already provides the
+## wanted functionality.
+
+{.deadCodeElim: on.}
+
+when defined(Windows):
+  proc readLineFromStdin*(prompt: string): TaintedString {.
+                          tags: [ReadIOEffect, WriteIOEffect].} =
+    ## Reads a line from stdin.
+    stdout.write(prompt)
+    result = readLine(stdin)
+
+  proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
+                          tags: [ReadIOEffect, WriteIOEffect].} =
+    ## Reads a `line` from stdin. `line` must not be
+    ## ``nil``! May throw an IO exception.
+    ## A line of text may be delimited by ``CR``, ``LF`` or
+    ## ``CRLF``. The newline character(s) are not part of the returned string.
+    ## Returns ``false`` if the end of the file has been reached, ``true``
+    ## otherwise. If ``false`` is returned `line` contains no new data.
+    stdout.write(prompt)
+    result = readLine(stdin, line)
+
+  import winlean
+
+  const
+    VK_SHIFT* = 16
+    VK_CONTROL* = 17
+    VK_MENU* = 18
+    KEY_EVENT* = 1
+
+  type
+    KEY_EVENT_RECORD = object
+      bKeyDown: WinBool
+      wRepeatCount: uint16
+      wVirtualKeyCode: uint16
+      wVirtualScanCode: uint16
+      unicodeChar: uint16
+      dwControlKeyState: uint32
+    INPUT_RECORD = object
+      eventType*: int16
+      reserved*: int16
+      event*: KEY_EVENT_RECORD
+      safetyBuffer: array[0..5, DWORD]
+
+  proc readConsoleInputW*(hConsoleInput: THANDLE, lpBuffer: var INPUTRECORD,
+                          nLength: uint32,
+                          lpNumberOfEventsRead: var uint32): WINBOOL{.
+      stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}
+
+  proc getch(): uint16 =
+    let hStdin = getStdHandle(STD_INPUT_HANDLE)
+    var
+      irInputRecord: INPUT_RECORD
+      dwEventsRead: uint32
+
+    while readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead) != 0:
+      if irInputRecord.eventType == KEY_EVENT and
+          irInputRecord.event.wVirtualKeyCode notin {VK_SHIFT, VK_MENU, VK_CONTROL}:
+         result = irInputRecord.event.unicodeChar
+         discard readConsoleInputW(hStdin, irInputRecord, 1, dwEventsRead)
+         return result
+
+  from unicode import toUTF8, Rune, runeLenAt
+
+  proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
+                              bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+    ## Reads a `password` from stdin without printing it. `password` must not
+    ## be ``nil``! Returns ``false`` if the end of the file has been reached,
+    ## ``true`` otherwise.
+    password.setLen(0)
+    stdout.write(prompt)
+    while true:
+      let c = getch()
+      case c.char
+      of '\r', chr(0xA):
+        break
+      of '\b':
+        # ensure we delete the whole UTF-8 character:
+        var i = 0
+        var x = 1
+        while i < password.len:
+          x = runeLenAt(password, i)
+          inc i, x
+        password.setLen(password.len - x)
+      else:
+        password.add(toUTF8(c.Rune))
+    stdout.write "\n"
+
+else:
+  import readline, history, termios, unsigned
+
+  proc readLineFromStdin*(prompt: string): TaintedString {.
+                          tags: [ReadIOEffect, WriteIOEffect].} =
+    var buffer = readline.readLine(prompt)
+    if isNil(buffer): quit(0)
+    result = TaintedString($buffer)
+    if result.string.len > 0:
+      add_history(buffer)
+    readline.free(buffer)
+
+  proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
+                          tags: [ReadIOEffect, WriteIOEffect].} =
+    var buffer = readline.readLine(prompt)
+    if isNil(buffer): quit(0)
+    line = TaintedString($buffer)
+    if line.string.len > 0:
+      add_history(buffer)
+    readline.free(buffer)
+    # XXX how to determine CTRL+D?
+    result = true
+
+  # initialization:
+  # disable auto-complete:
+  proc doNothing(a, b: cint): cint {.cdecl, procvar.} = discard
+
+  discard readline.bind_key('\t'.ord, doNothing)
+
+  proc readPasswordFromStdin*(prompt: string, password: var TaintedString):
+                              bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+    password.setLen(0)
+    let fd = stdin.getFileHandle()
+    var cur, old: Termios
+    discard fd.tcgetattr(cur.addr)
+    old = cur
+    cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
+    discard fd.tcsetattr(TCSADRAIN, cur.addr)
+    stdout.write prompt
+    result = stdin.readLine(password)
+    stdout.write "\n"
+    discard fd.tcsetattr(TCSADRAIN, old.addr)
+
+proc readPasswordFromStdin*(prompt: string): TaintedString =
+  ## Reads a password from stdin without printing it.
+  result = TaintedString("")
+  discard readPasswordFromStdin(prompt, result)
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
new file mode 100644
index 000000000..279f8aadd
--- /dev/null
+++ b/lib/impure/re.nim
@@ -0,0 +1,510 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Regular expression support for Nim. Consider using the pegs module instead.
+##
+## There is an alternative regular expressions library with a more unified API:
+## `nre <https://github.com/flaviut/nre>`_. It may be added to the standard
+## library in the future, instead of `re`.
+##
+## **Note:** The 're' proc defaults to the **extended regular expression
+## syntax** which lets you use whitespace freely to make your regexes readable.
+## However, this means to match whitespace ``\s`` or something similar has
+## to be used.
+##
+## This module is implemented by providing a wrapper around the
+## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_
+## C library. This means that your application will depend on the PRCE
+## library's licence when using this module, which should not be a problem
+## though.
+## PRCE's licence follows:
+##
+## .. include:: ../doc/regexprs.txt
+##
+
+import
+  pcre, strutils, rtarrays
+
+const
+  MaxSubpatterns* = 20
+    ## defines the maximum number of subpatterns that can be captured.
+    ## This limit still exists for ``replacef`` and ``parallelReplace``.
+
+type
+  RegexFlag* = enum     ## options for regular expressions
+    reIgnoreCase = 0,    ## do caseless matching
+    reMultiLine = 1,     ## ``^`` and ``$`` match newlines within data
+    reDotAll = 2,        ## ``.`` matches anything including NL
+    reExtended = 3,      ## ignore whitespace and ``#`` comments
+    reStudy = 4          ## study the expression (may be omitted if the
+                         ## expression will be used only once)
+  
+  RegexDesc = object 
+    h: ptr Pcre
+    e: ptr ExtraData
+  
+  Regex* = ref RegexDesc ## a compiled regular expression
+
+  RegexError* = object of ValueError
+    ## is raised if the pattern is no valid regular expression.
+
+{.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex,
+    EInvalidRegEx: RegexError].}
+
+proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
+  var e: ref RegexError
+  new(e)
+  e.msg = msg
+  raise e
+
+proc rawCompile(pattern: string, flags: cint): ptr Pcre =
+  var
+    msg: cstring
+    offset: cint
+  result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil)
+  if result == nil:
+    raiseInvalidRegex($msg & "\n" & pattern & "\n" & spaces(offset) & "^\n")
+
+proc finalizeRegEx(x: Regex) =
+  # XXX This is a hack, but PCRE does not export its "free" function properly.
+  # Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``).
+  # Fortunately the implementation is unlikely to change.
+  pcre.free_substring(cast[cstring](x.h))
+  if not isNil(x.e):
+    pcre.free_substring(cast[cstring](x.e))
+
+proc re*(s: string, flags = {reExtended, reStudy}): Regex =
+  ## Constructor of regular expressions. Note that Nim's
+  ## extended raw string literals support this syntax ``re"[abc]"`` as
+  ## a short form for ``re(r"[abc]")``.
+  new(result, finalizeRegEx)
+  result.h = rawCompile(s, cast[cint](flags - {reStudy}))
+  if reStudy in flags:
+    var msg: cstring
+    result.e = pcre.study(result.h, 0, addr msg)
+    if not isNil(msg): raiseInvalidRegex($msg)
+
+proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
+                 start, flags: cint): cint =
+  var
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
+    res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags,
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
+  if res < 0'i32: return res
+  for i in 1..int(res)-1:
+    var a = rawMatches[i * 2]
+    var b = rawMatches[i * 2 + 1]
+    if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
+    else: matches[i-1] = nil
+  return rawMatches[1] - rawMatches[0]
+
+proc findBounds*(s: string, pattern: Regex, matches: var openArray[string],
+                 start = 0): tuple[first, last: int] =
+  ## returns the starting position and end position of `pattern` in `s`
+  ## and the captured
+  ## substrings in the array `matches`. If it does not match, nothing
+  ## is written into `matches` and ``(-1,0)`` is returned.
+  var
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
+    res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32,
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
+  if res < 0'i32: return (-1, 0)
+  for i in 1..int(res)-1:
+    var a = rawMatches[i * 2]
+    var b = rawMatches[i * 2 + 1]
+    if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
+    else: matches[i-1] = nil
+  return (rawMatches[0].int, rawMatches[1].int - 1)
+
+proc findBounds*(s: string, pattern: Regex,
+                 matches: var openArray[tuple[first, last: int]],
+                 start = 0): tuple[first, last: int] =
+  ## returns the starting position and end position of ``pattern`` in ``s``
+  ## and the captured substrings in the array `matches`.
+  ## If it does not match, nothing is written into `matches` and
+  ## ``(-1,0)`` is returned.
+  var
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
+    res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32,
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
+  if res < 0'i32: return (-1, 0)
+  for i in 1..int(res)-1:
+    var a = rawMatches[i * 2]
+    var b = rawMatches[i * 2 + 1]
+    if a >= 0'i32: matches[i-1] = (int(a), int(b)-1)
+    else: matches[i-1] = (-1,0)
+  return (rawMatches[0].int, rawMatches[1].int - 1)
+
+proc findBounds*(s: string, pattern: Regex,
+                 start = 0): tuple[first, last: int] =
+  ## returns the starting position and end position of ``pattern`` in ``s``.
+  ## If it does not match, ``(-1,0)`` is returned.
+  var
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
+    res = pcre.exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32,
+      cast[ptr cint](rawMatches), 3)
+  if res < 0'i32: return (int(res), 0)
+  return (int(rawMatches[0]), int(rawMatches[1]-1))
+
+proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint =
+  var
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
+  result = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags,
+                    cast[ptr cint](rawMatches), 3)
+  if result >= 0'i32:
+    result = rawMatches[1] - rawMatches[0]
+
+proc matchLen*(s: string, pattern: Regex, matches: var openArray[string],
+              start = 0): int =
+  ## the same as ``match``, but it returns the length of the match,
+  ## if there is no match, -1 is returned. Note that a match length
+  ## of zero can happen.
+  return matchOrFind(s, pattern, matches, start.cint, pcre.ANCHORED)
+
+proc matchLen*(s: string, pattern: Regex, start = 0): int =
+  ## the same as ``match``, but it returns the length of the match,
+  ## if there is no match, -1 is returned. Note that a match length
+  ## of zero can happen.
+  return matchOrFind(s, pattern, start.cint, pcre.ANCHORED)
+
+proc match*(s: string, pattern: Regex, start = 0): bool =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern``.
+  result = matchLen(s, pattern, start) != -1
+
+proc match*(s: string, pattern: Regex, matches: var openArray[string],
+           start = 0): bool =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
+  ## the captured substrings in the array ``matches``. If it does not
+  ## match, nothing is written into ``matches`` and ``false`` is
+  ## returned.
+  result = matchLen(s, pattern, matches, start) != -1
+
+proc find*(s: string, pattern: Regex, matches: var openArray[string],
+           start = 0): int =
+  ## returns the starting position of ``pattern`` in ``s`` and the captured
+  ## substrings in the array ``matches``. If it does not match, nothing
+  ## is written into ``matches`` and -1 is returned.
+  var
+    rtarray = initRtArray[cint]((matches.len+1)*3)
+    rawMatches = rtarray.getRawData
+    res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32,
+      cast[ptr cint](rawMatches), (matches.len+1).cint*3)
+  if res < 0'i32: return res
+  for i in 1..int(res)-1:
+    var a = rawMatches[i * 2]
+    var b = rawMatches[i * 2 + 1]
+    if a >= 0'i32: matches[i-1] = substr(s, int(a), int(b)-1)
+    else: matches[i-1] = nil
+  return rawMatches[0]
+
+proc find*(s: string, pattern: Regex, start = 0): int =
+  ## returns the starting position of ``pattern`` in ``s``. If it does not
+  ## match, -1 is returned.
+  var
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
+    res = pcre.exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32,
+      cast[ptr cint](rawMatches), 3)
+  if res < 0'i32: return res
+  return rawMatches[0]
+
+iterator findAll*(s: string, pattern: Regex, start = 0): string =
+  ## Yields all matching *substrings* of `s` that match `pattern`.
+  ##
+  ## Note that since this is an iterator you should not modify the string you
+  ## are iterating over: bad things could happen.
+  var
+    i = int32(start)
+    rtarray = initRtArray[cint](3)
+    rawMatches = rtarray.getRawData
+  while true:
+    let res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, i, 0'i32,
+      cast[ptr cint](rawMatches), 3)
+    if res < 0'i32: break
+    let a = rawMatches[0]
+    let b = rawMatches[1]
+    if a == b and a == i: break
+    yield substr(s, int(a), int(b)-1)
+    i = b
+
+proc findAll*(s: string, pattern: Regex, start = 0): seq[string] =
+  ## returns all matching *substrings* of `s` that match `pattern`.
+  ## If it does not match, @[] is returned.
+  accumulateResult(findAll(s, pattern, start))
+
+when not defined(nimhygiene):
+  {.pragma: inject.}
+
+template `=~` *(s: string, pattern: Regex): expr =
+  ## This calls ``match`` with an implicit declared ``matches`` array that
+  ## can be used in the scope of the ``=~`` call:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   if line =~ re"\s*(\w+)\s*\=\s*(\w+)":
+  ##     # matches a key=value pair:
+  ##     echo("Key: ", matches[0])
+  ##     echo("Value: ", matches[1])
+  ##   elif line =~ re"\s*(\#.*)":
+  ##     # matches a comment
+  ##     # note that the implicit ``matches`` array is different from the
+  ##     # ``matches`` array of the first branch
+  ##     echo("comment: ", matches[0])
+  ##   else:
+  ##     echo("syntax error")
+  ##
+  bind MaxSubpatterns
+  when not declaredInScope(matches):
+    var matches {.inject.}: array[MaxSubpatterns, string]
+  match(s, pattern, matches)
+
+# ------------------------- more string handling ------------------------------
+
+proc contains*(s: string, pattern: Regex, start = 0): bool =
+  ## same as ``find(s, pattern, start) >= 0``
+  return find(s, pattern, start) >= 0
+
+proc contains*(s: string, pattern: Regex, matches: var openArray[string],
+              start = 0): bool =
+  ## same as ``find(s, pattern, matches, start) >= 0``
+  return find(s, pattern, matches, start) >= 0
+
+proc startsWith*(s: string, prefix: Regex): bool =
+  ## returns true if `s` starts with the pattern `prefix`
+  result = matchLen(s, prefix) >= 0
+
+proc endsWith*(s: string, suffix: Regex): bool =
+  ## returns true if `s` ends with the pattern `prefix`
+  for i in 0 .. s.len-1:
+    if matchLen(s, suffix, i) == s.len - i: return true
+
+proc replace*(s: string, sub: Regex, by = ""): string =
+  ## Replaces `sub` in `s` by the string `by`. Captures cannot be
+  ## accessed in `by`. Examples:
+  ##
+  ## .. code-block:: nim
+  ##   "var1=key; var2=key2".replace(re"(\w+)=(\w+)")
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   "; "
+  result = ""
+  var prev = 0
+  while true:
+    var match = findBounds(s, sub, prev)
+    if match.first < 0: break
+    add(result, substr(s, prev, match.first-1))
+    add(result, by)
+    prev = match.last + 1
+  add(result, substr(s, prev))
+
+proc replacef*(s: string, sub: Regex, by: string): string =
+  ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
+  ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
+  ##
+  ## .. code-block:: nim
+  ##   "var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2")
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##
+  ## "var1<-keykey; val2<-key2key2"
+  result = ""
+  var caps: array[MaxSubpatterns, string]
+  var prev = 0
+  while true:
+    var match = findBounds(s, sub, caps, prev)
+    if match.first < 0: break
+    assert result != nil
+    assert s != nil
+    add(result, substr(s, prev, match.first-1))
+    addf(result, by, caps)
+    prev = match.last + 1
+  add(result, substr(s, prev))
+
+proc parallelReplace*(s: string, subs: openArray[
+                      tuple[pattern: Regex, repl: string]]): string =
+  ## Returns a modified copy of `s` with the substitutions in `subs`
+  ## applied in parallel.
+  result = ""
+  var i = 0
+  var caps: array[MaxSubpatterns, string]
+  while i < s.len:
+    block searchSubs:
+      for j in 0..high(subs):
+        var x = matchLen(s, subs[j][0], caps, i)
+        if x > 0:
+          addf(result, subs[j][1], caps)
+          inc(i, x)
+          break searchSubs
+      add(result, s[i])
+      inc(i)
+  # copy the rest:
+  add(result, substr(s, i))
+
+proc transformFile*(infile, outfile: string,
+                    subs: openArray[tuple[pattern: Regex, repl: string]]) =
+  ## reads in the file `infile`, performs a parallel replacement (calls
+  ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
+  ## error occurs. This is supposed to be used for quick scripting.
+  var x = readFile(infile).string
+  writeFile(outfile, x.parallelReplace(subs))
+
+iterator split*(s: string, sep: Regex): string =
+  ## Splits the string `s` into substrings.
+  ##
+  ## Substrings are separated by the regular expression `sep`.
+  ## Examples:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split("00232this02939is39an22example111", re"\d+"):
+  ##     writeln(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   ""
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   "example"
+  ##   ""
+  ##
+  var
+    first = -1
+    last = -1
+  while last < len(s):
+    var x = matchLen(s, sep, last)
+    if x > 0: inc(last, x)
+    first = last
+    if x == 0: inc(last)
+    while last < len(s):
+      x = matchLen(s, sep, last)
+      if x >= 0: break
+      inc(last)
+    if first <= last:
+      yield substr(s, first, last-1)
+
+proc split*(s: string, sep: Regex): seq[string] =
+  ## Splits the string `s` into substrings.
+  accumulateResult(split(s, sep))
+
+proc escapeRe*(s: string): string =
+  ## escapes `s` so that it is matched verbatim when used as a regular
+  ## expression.
+  result = ""
+  for c in items(s):
+    case c
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_':
+      result.add(c)
+    else:
+      result.add("\\x")
+      result.add(toHex(ord(c), 2))
+
+const ## common regular expressions
+  reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
+    ## describes an identifier
+  reNatural* {.deprecated.} = r"\b\d+\b"
+    ## describes a natural number
+  reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
+    ## describes an integer
+  reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
+    ## describes a hexadecimal number
+  reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
+    ## describes a binary number (example: 0b11101)
+  reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
+    ## describes an octal number (example: 0o777)
+  reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
+    ## describes a floating point number
+  reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
+                            r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
+                            r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
+                            r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
+                            r"info|mobi|name|aero|jobs|museum)\b"
+    ## describes a common email address
+  reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
+                          r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
+    ## describes an URL
+
+when isMainModule:
+  assert match("(a b c)", re"\( .* \)")
+  assert match("WHiLe", re("while", {reIgnoreCase}))
+
+  assert "0158787".match(re"\d+")
+  assert "ABC 0232".match(re"\w+\s+\d+")
+  assert "ABC".match(re"\d+ | \w+")
+
+  assert matchLen("key", re(reIdentifier)) == 3
+
+  var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
+  assert matchLen("key1=  cal9", pattern) == 11
+
+  assert find("_____abc_______", re"abc") == 5
+
+  var matches: array[6, string]
+  if match("abcdefg", re"c(d)ef(g)", matches, 2):
+    assert matches[0] == "d"
+    assert matches[1] == "g"
+  else:
+    assert false
+
+  if "abc" =~ re"(a)bcxyz|(\w+)":
+    assert matches[1] == "abc"
+  else:
+    assert false
+
+  if "abc" =~ re"(cba)?.*":
+    assert matches[0] == nil
+  else: assert false
+
+  if "abc" =~ re"().*":
+    assert matches[0] == ""
+  else: assert false
+
+  assert "var1=key; var2=key2".endsWith(re"\w+=\w+")
+  assert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
+         "var1<-keykey; var2<-key2key2")
+  assert("var1=key; var2=key2".replace(re"(\w+)=(\w+)", "$1<-$2$2") ==
+         "$1<-$2$2; $1<-$2$2")
+
+  var accum: seq[string] = @[]
+  for word in split("00232this02939is39an22example111", re"\d+"):
+    accum.add(word)
+  assert(accum == @["", "this", "is", "an", "example", ""])
+
+  accum = @[]
+  for word in split("AAA :   : BBB", re"\s*:\s*"):
+    accum.add(word)
+  assert(accum == @["AAA", "", "BBB"])
+
+  for x in findAll("abcdef", re"^{.}", 3):
+    assert x == "d"
+  accum = @[]
+  for x in findAll("abcdef", re".", 3):
+    accum.add(x)
+  assert(accum == @["d", "e", "f"])
+
+  assert("XYZ".find(re"^\d*") == 0)
+  assert("XYZ".match(re"^\d*") == true)
+
+  block:
+    var matches: array[16, string]
+    if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
+      for i in 0..matches.high:
+        assert matches[i] == $chr(i + 'a'.ord)
+    else:
+      assert false
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
new file mode 100644
index 000000000..d318a1979
--- /dev/null
+++ b/lib/impure/ssl.nim
@@ -0,0 +1,96 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides an easy to use sockets-style 
+## nim interface to the OpenSSL library.
+
+{.deprecated.}
+
+import openssl, strutils, os
+
+type
+  TSecureSocket* = object
+    ssl: SslPtr
+    bio: BIO
+
+proc connect*(sock: var TSecureSocket, address: string, 
+    port: int): int =
+  ## Connects to the specified `address` on the specified `port`.
+  ## Returns the result of the certificate validation.
+  SslLoadErrorStrings()
+  ERR_load_BIO_strings()
+  
+  if SSL_library_init() != 1:
+    raiseOSError(osLastError())
+  
+  var ctx = SSL_CTX_new(SSLv23_client_method())
+  if ctx == nil:
+    ERR_print_errors_fp(stderr)
+    raiseOSError(osLastError())
+    
+  #if SSL_CTX_load_verify_locations(ctx, 
+  #   "/tmp/openssl-0.9.8e/certs/vsign1.pem", NIL) == 0:
+  #  echo("Failed load verify locations")
+  #  ERR_print_errors_fp(stderr)
+  
+  sock.bio = BIO_new_ssl_connect(ctx)
+  if BIO_get_ssl(sock.bio, addr(sock.ssl)) == 0:
+    raiseOSError(osLastError())
+
+  if BIO_set_conn_hostname(sock.bio, address & ":" & $port) != 1:
+    raiseOSError(osLastError())
+  
+  if BIO_do_connect(sock.bio) <= 0:
+    ERR_print_errors_fp(stderr)
+    raiseOSError(osLastError())
+  
+  result = SSL_get_verify_result(sock.ssl)
+
+proc recvLine*(sock: TSecureSocket, line: var TaintedString): bool =
+  ## Acts in a similar fashion to the `recvLine` in the sockets module.
+  ## Returns false when no data is available to be read.
+  ## `Line` must be initialized and not nil!
+  setLen(line.string, 0)
+  while true:
+    var c: array[0..0, char]
+    var n = BIO_read(sock.bio, c, c.len.cint)
+    if n <= 0: return false
+    if c[0] == '\r':
+      n = BIO_read(sock.bio, c, c.len.cint)
+      if n > 0 and c[0] == '\L':
+        return true
+      elif n <= 0:
+        return false
+    elif c[0] == '\L': return true
+    add(line.string, c)
+
+
+proc send*(sock: TSecureSocket, data: string) =
+  ## Writes `data` to the socket.
+  if BIO_write(sock.bio, data, data.len.cint) <= 0:
+    raiseOSError(osLastError())
+
+proc close*(sock: TSecureSocket) =
+  ## Closes the socket
+  if BIO_free(sock.bio) <= 0:
+    ERR_print_errors_fp(stderr)
+    raiseOSError(osLastError())
+
+when not defined(testing) and isMainModule:
+  var s: TSecureSocket
+  echo connect(s, "smtp.gmail.com", 465)
+  
+  #var buffer: array[0..255, char]
+  #echo BIO_read(bio, buffer, buffer.len)
+  var buffer: string = ""
+  
+  echo s.recvLine(buffer)
+  echo buffer 
+  echo buffer.len
+  
diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim
new file mode 100644
index 000000000..b41ca1e4b
--- /dev/null
+++ b/lib/impure/zipfiles.nim
@@ -0,0 +1,183 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a zip archive creator/reader/modifier.
+
+import
+  streams, libzip, times, os, strutils
+
+type
+  TZipArchive* = object of RootObj ## represents a zip archive
+    mode: FileMode
+    w: PZip
+
+
+proc zipError(z: var TZipArchive) =
+  var e: ref IOError
+  new(e)
+  e.msg = $zip_strerror(z.w)
+  raise e
+
+proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
+  ## Opens a zip file for reading, writing or appending. All file modes are
+  ## supported. Returns true iff successful, false otherwise.
+  var err, flags: int32
+  case mode
+  of fmRead, fmReadWriteExisting, fmAppend: flags = 0
+  of fmWrite:
+    if existsFile(filename): removeFile(filename)
+    flags = ZIP_CREATE or ZIP_EXCL
+  of fmReadWrite: flags = ZIP_CREATE
+  z.w = zip_open(filename, flags, addr(err))
+  z.mode = mode
+  result = z.w != nil
+
+proc close*(z: var TZipArchive) =
+  ## Closes a zip file.
+  zip_close(z.w)
+
+proc createDir*(z: var TZipArchive, dir: string) =
+  ## Creates a directory within the `z` archive. This does not fail if the
+  ## directory already exists. Note that for adding a file like
+  ## ``"path1/path2/filename"`` it is not necessary
+  ## to create the ``"path/path2"`` subdirectories - it will be done
+  ## automatically by ``addFile``.
+  assert(z.mode != fmRead)
+  discard zip_add_dir(z.w, dir)
+  zip_error_clear(z.w)
+
+proc addFile*(z: var TZipArchive, dest, src: string) =
+  ## Adds the file `src` to the archive `z` with the name `dest`. `dest`
+  ## may contain a path that will be created.
+  assert(z.mode != fmRead)
+  if not fileExists(src):
+    raise newException(IOError, "File '" & src & "' does not exist")
+  var zipsrc = zip_source_file(z.w, src, 0, -1)
+  if zipsrc == nil:
+    #echo("Dest: " & dest)
+    #echo("Src: " & src)
+    zipError(z)
+  if zip_add(z.w, dest, zipsrc) < 0'i32:
+    zip_source_free(zipsrc)
+    zipError(z)
+
+proc addFile*(z: var TZipArchive, file: string) =
+  ## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
+  ## the name of the destination.
+  addFile(z, file, file)
+
+proc mySourceCallback(state, data: pointer, len: int,
+                      cmd: TZipSourceCmd): int {.cdecl.} =
+  var src = cast[Stream](state)
+  case cmd
+  of ZIP_SOURCE_OPEN:
+    if src.setPositionImpl != nil: setPosition(src, 0) # reset
+  of ZIP_SOURCE_READ:
+    result = readData(src, data, len)
+  of ZIP_SOURCE_CLOSE: close(src)
+  of ZIP_SOURCE_STAT:
+    var stat = cast[PZipStat](data)
+    zip_stat_init(stat)
+    stat.size = high(int32)-1 # we don't know the size
+    stat.mtime = getTime()
+    result = sizeof(TZipStat)
+  of ZIP_SOURCE_ERROR:
+    var err = cast[ptr array[0..1, cint]](data)
+    err[0] = ZIP_ER_INTERNAL
+    err[1] = 0
+    result = 2*sizeof(cint)
+  of constZIP_SOURCE_FREE: GC_unref(src)
+  else: assert(false)
+
+proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
+  ## Adds a file named with `dest` to the archive `z`. `dest`
+  ## may contain a path. The file's content is read from the `src` stream.
+  assert(z.mode != fmRead)
+  GC_ref(src)
+  var zipsrc = zip_source_function(z.w, mySourceCallback, cast[pointer](src))
+  if zipsrc == nil: zipError(z)
+  if zip_add(z.w, dest, zipsrc) < 0'i32:
+    zip_source_free(zipsrc)
+    zipError(z)
+
+# -------------- zip file stream ---------------------------------------------
+
+type
+  TZipFileStream = object of StreamObj
+    f: PZipFile
+    atEnd: bool
+
+  PZipFileStream* =
+    ref TZipFileStream ## a reader stream of a file within a zip archive
+
+proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
+proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd
+proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
+  result = zip_fread(PZipFileStream(s).f, buffer, bufLen)
+  if result == 0:
+    PZipFileStream(s).atEnd = true
+
+proc newZipFileStream(f: PZipFile): PZipFileStream =
+  new(result)
+  result.f = f
+  result.atEnd = false
+  result.closeImpl = fsClose
+  result.readDataImpl = fsReadData
+  result.atEndImpl = fsAtEnd
+  # other methods are nil!
+
+# ----------------------------------------------------------------------------
+
+proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
+  ## returns a stream that can be used to read the file named `filename`
+  ## from the archive `z`. Returns nil in case of an error.
+  ## The returned stream does not support the `setPosition`, `getPosition`,
+  ## `writeData` or `atEnd` methods.
+  var x = zip_fopen(z.w, filename, 0'i32)
+  if x != nil: result = newZipFileStream(x)
+
+iterator walkFiles*(z: var TZipArchive): string =
+  ## walks over all files in the archive `z` and returns the filename
+  ## (including the path).
+  var i = 0'i32
+  var num = zip_get_num_files(z.w)
+  while i < num:
+    yield $zip_get_name(z.w, i, 0'i32)
+    inc(i)
+
+
+proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
+  ## extracts a file from the zip archive `z` to the destination stream.
+  var strm = getStream(z, srcFile)
+  while true:
+    if not strm.atEnd:
+        dest.write(strm.readStr(1))
+    else: break
+  dest.flush()
+  strm.close()
+
+proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
+  ## extracts a file from the zip archive `z` to the destination filename.
+  var file = newFileStream(dest, fmWrite)
+  extractFile(z, srcFile, file)
+  file.close()
+
+proc extractAll*(z: var TZipArchive, dest: string) =
+  ## extracts all files from archive `z` to the destination directory.
+  for file in walkFiles(z):
+    if file.endsWith("/"):
+      createDir(dest / file)
+    else:
+      extractFile(z, file, dest / file)
+
+when not defined(testing) and isMainModule:
+  var zip: TZipArchive
+  if not zip.open("nim-0.11.0.zip"):
+    raise newException(IOError, "opening zip failed")
+  zip.extractAll("test")
diff --git a/lib/js/dom.nim b/lib/js/dom.nim
new file mode 100644
index 000000000..b063fa838
--- /dev/null
+++ b/lib/js/dom.nim
@@ -0,0 +1,487 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Declaration of the Document Object Model for the `JavaScript backend
+## <backends.html#the-javascript-target>`_.
+
+when not defined(js) and not defined(Nimdoc):
+  {.error: "This module only works on the JavaScript platform".}
+
+type
+  TEventHandlers* {.importc.} = object of RootObj
+    onabort*: proc (event: ref TEvent) {.nimcall.}
+    onblur*: proc (event: ref TEvent) {.nimcall.}
+    onchange*: proc (event: ref TEvent) {.nimcall.}
+    onclick*: proc (event: ref TEvent) {.nimcall.}
+    ondblclick*: proc (event: ref TEvent) {.nimcall.}
+    onerror*: proc (event: ref TEvent) {.nimcall.}
+    onfocus*: proc (event: ref TEvent) {.nimcall.}
+    onkeydown*: proc (event: ref TEvent) {.nimcall.}
+    onkeypress*: proc (event: ref TEvent) {.nimcall.}
+    onkeyup*: proc (event: ref TEvent) {.nimcall.}
+    onload*: proc (event: ref TEvent) {.nimcall.}
+    onmousedown*: proc (event: ref TEvent) {.nimcall.}
+    onmousemove*: proc (event: ref TEvent) {.nimcall.}
+    onmouseout*: proc (event: ref TEvent) {.nimcall.}
+    onmouseover*: proc (event: ref TEvent) {.nimcall.}
+    onmouseup*: proc (event: ref TEvent) {.nimcall.}
+    onreset*: proc (event: ref TEvent) {.nimcall.}
+    onselect*: proc (event: ref TEvent) {.nimcall.}
+    onsubmit*: proc (event: ref TEvent) {.nimcall.}
+    onunload*: proc (event: ref TEvent) {.nimcall.}
+
+    addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent), useCapture: bool = false) {.nimcall.}
+
+  Window* = ref WindowObj
+  WindowObj {.importc.} = object of TEventHandlers
+    document*: Document
+    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) {.nimcall.}
+    back*: proc () {.nimcall.}
+    blur*: proc () {.nimcall.}
+    captureEvents*: proc (eventMask: int) {.nimcall.}
+    clearInterval*: proc (interval: ref TInterval) {.nimcall.}
+    clearTimeout*: proc (timeout: ref TTimeOut) {.nimcall.}
+    close*: proc () {.nimcall.}
+    confirm*: proc (msg: cstring): bool {.nimcall.}
+    disableExternalCapture*: proc () {.nimcall.}
+    enableExternalCapture*: proc () {.nimcall.}
+    find*: proc (text: cstring, caseSensitive = false,
+                 backwards = false) {.nimcall.}
+    focus*: proc () {.nimcall.}
+    forward*: proc () {.nimcall.}
+    handleEvent*: proc (e: ref TEvent) {.nimcall.}
+    home*: proc () {.nimcall.}
+    moveBy*: proc (x, y: int) {.nimcall.}
+    moveTo*: proc (x, y: int) {.nimcall.}
+    open*: proc (uri, windowname: cstring,
+                 properties: cstring = nil): Window {.nimcall.}
+    print*: proc () {.nimcall.}
+    prompt*: proc (text, default: cstring): cstring {.nimcall.}
+    releaseEvents*: proc (eventMask: int) {.nimcall.}
+    resizeBy*: proc (x, y: int) {.nimcall.}
+    resizeTo*: proc (x, y: int) {.nimcall.}
+    routeEvent*: proc (event: ref TEvent) {.nimcall.}
+    scrollBy*: proc (x, y: int) {.nimcall.}
+    scrollTo*: proc (x, y: int) {.nimcall.}
+    setInterval*: proc (code: cstring, pause: int): ref TInterval {.nimcall.}
+    setTimeout*: proc (code: cstring, pause: int): ref TTimeOut {.nimcall.}
+    stop*: proc () {.nimcall.}
+    frames*: seq[TFrame]
+
+  Frame* = ref FrameObj
+  FrameObj {.importc.} = object of WindowObj
+
+  ClassList* {.importc.} = object of RootObj
+    add*: proc (class: cstring) {.nimcall.}
+    remove*: proc (class: cstring) {.nimcall.}
+    contains*: proc (class: cstring):bool {.nimcall.}
+    toggle*: proc (class: cstring) {.nimcall.}
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+
+  Node* = ref NodeObj
+  NodeObj {.importc.} = object of TEventHandlers
+    attributes*: seq[Node]
+    childNodes*: seq[Node]
+    children*: seq[Node]
+    data*: cstring
+    firstChild*: Node
+    lastChild*: Node
+    nextSibling*: Node
+    nodeName*: cstring
+    nodeType*: TNodeType
+    nodeValue*: cstring
+    parentNode*: Node
+    previousSibling*: Node
+    appendChild*: proc (child: Node) {.nimcall.}
+    appendData*: proc (data: cstring) {.nimcall.}
+    cloneNode*: proc (copyContent: bool): Node {.nimcall.}
+    deleteData*: proc (start, len: int) {.nimcall.}
+    getAttribute*: proc (attr: cstring): cstring {.nimcall.}
+    getAttributeNode*: proc (attr: cstring): Node {.nimcall.}
+    hasChildNodes*: proc (): bool {.nimcall.}
+    innerHTML*: cstring
+    insertBefore*: proc (newNode, before: Node) {.nimcall.}
+    insertData*: proc (position: int, data: cstring) {.nimcall.}
+    removeAttribute*: proc (attr: cstring) {.nimcall.}
+    removeAttributeNode*: proc (attr: Node) {.nimcall.}
+    removeChild*: proc (child: Node) {.nimcall.}
+    replaceChild*: proc (newNode, oldNode: Node) {.nimcall.}
+    replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
+    scrollIntoView*: proc () {.nimcall.}
+    setAttribute*: proc (name, value: cstring) {.nimcall.}
+    setAttributeNode*: proc (attr: Node) {.nimcall.}
+    style*: ref TStyle
+
+  Document* = ref DocumentObj
+  DocumentObj {.importc.} = object of NodeObj
+    alinkColor*: cstring
+    bgColor*: cstring
+    body*: Element
+    charset*: cstring
+    cookie*: cstring
+    defaultCharset*: cstring
+    fgColor*: cstring
+    head*: Element
+    lastModified*: cstring
+    linkColor*: cstring
+    referrer*: cstring
+    title*: cstring
+    URL*: cstring
+    vlinkColor*: cstring
+    captureEvents*: proc (eventMask: int) {.nimcall.}
+    createAttribute*: proc (identifier: cstring): Node {.nimcall.}
+    createElement*: proc (identifier: cstring): Element {.nimcall.}
+    createTextNode*: proc (identifier: cstring): Node {.nimcall.}
+    getElementById*: proc (id: cstring): Element {.nimcall.}
+    getElementsByName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getSelection*: proc (): cstring {.nimcall.}
+    handleEvent*: proc (event: ref TEvent) {.nimcall.}
+    open*: proc () {.nimcall.}
+    releaseEvents*: proc (eventMask: int) {.nimcall.}
+    routeEvent*: proc (event: ref TEvent) {.nimcall.}
+    write*: proc (text: cstring) {.nimcall.}
+    writeln*: proc (text: cstring) {.nimcall.}
+    anchors*: seq[AnchorElement]
+    forms*: seq[FormElement]
+    images*: seq[ImageElement]
+    applets*: seq[ref TApplet]
+    embeds*: seq[EmbedElement]
+    links*: seq[LinkElement]
+
+  Element* = ref ElementObj
+  ElementObj {.importc.} = object of NodeObj
+    classList*: ref Classlist
+    checked*: bool
+    defaultChecked*: bool
+    defaultValue*: cstring
+    disabled*: bool
+    form*: FormElement
+    name*: cstring
+    readOnly*: bool
+    blur*: proc () {.nimcall.}
+    click*: proc () {.nimcall.}
+    focus*: proc () {.nimcall.}
+    handleEvent*: proc (event: ref TEvent) {.nimcall.}
+    select*: proc () {.nimcall.}
+    options*: seq[OptionElement]
+    getElementsByTagName*: proc (name: cstring): seq[Element] {.nimcall.}
+    getElementsByClassName*: proc (name: cstring): seq[Element] {.nimcall.}
+
+  LinkElement* = ref LinkObj
+  LinkObj {.importc.} = object of ElementObj
+    target*: cstring
+    text*: cstring
+    x*: int
+    y*: int
+
+  EmbedElement* = ref EmbedObj
+  EmbedObj {.importc.} = object of ElementObj
+    height*: int
+    hspace*: int
+    src*: cstring
+    width*: int
+    `type`*: cstring
+    vspace*: int
+    play*: proc () {.nimcall.}
+    stop*: proc () {.nimcall.}
+
+  AnchorElement* = ref AnchorObj
+  AnchorObj {.importc.} = object of ElementObj
+    text*: cstring
+    x*, y*: int
+
+  TApplet* {.importc.} = object of RootObj
+
+  OptionElement* = ref OptionObj
+  OptionObj {.importc.} = object of ElementObj
+    defaultSelected*: bool
+    selected*: bool
+    selectedIndex*: int
+    text*: cstring
+    value*: cstring
+
+  FormElement* = ref FormObj
+  FormObj {.importc.} = object of ElementObj
+    action*: cstring
+    encoding*: cstring
+    `method`*: cstring
+    target*: cstring
+    reset*: proc () {.nimcall.}
+    submit*: proc () {.nimcall.}
+    elements*: seq[Element]
+
+  ImageElement* = ref ImageObj
+  ImageObj {.importc.} = object of ElementObj
+    border*: int
+    complete*: bool
+    height*: int
+    hspace*: int
+    lowsrc*: cstring
+    src*: cstring
+    vspace*: int
+    width*: int
+
+
+  TStyle* {.importc.} = object of RootObj
+    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 {.nimcall.}
+    removeAttribute*: proc (attr: cstring, caseSensitive=false) {.nimcall.}
+    setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.}
+
+  TEvent* {.importc.} = object of RootObj
+    target*: Node
+    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 RootObj
+    hash*: cstring
+    host*: cstring
+    hostname*: cstring
+    href*: cstring
+    pathname*: cstring
+    port*: cstring
+    protocol*: cstring
+    search*: cstring
+    reload*: proc () {.nimcall.}
+    replace*: proc (s: cstring) {.nimcall.}
+
+  THistory* {.importc.} = object of RootObj
+    length*: int
+    back*: proc () {.nimcall.}
+    forward*: proc () {.nimcall.}
+    go*: proc (pagesToJump: int) {.nimcall.}
+
+  TNavigator* {.importc.} = object of RootObj
+    appCodeName*: cstring
+    appName*: cstring
+    appVersion*: cstring
+    cookieEnabled*: bool
+    language*: cstring
+    platform*: cstring
+    userAgent*: cstring
+    javaEnabled*: proc (): bool {.nimcall.}
+    mimeTypes*: seq[ref TMimeType]
+
+  TPlugin* {.importc.} = object of RootObj
+    description*: cstring
+    filename*: cstring
+    name*: cstring
+
+  TMimeType* {.importc.} = object of RootObj
+    description*: cstring
+    enabledPlugin*: ref TPlugin
+    suffixes*: seq[cstring]
+    `type`*: cstring
+
+  TLocationBar* {.importc.} = object of RootObj
+    visible*: bool
+  TMenuBar* = TLocationBar
+  TPersonalBar* = TLocationBar
+  TScrollBars* = TLocationBar
+  TToolBar* = TLocationBar
+  TStatusBar* = TLocationBar
+
+  TScreen* {.importc.} = object of RootObj
+    availHeight*: int
+    availWidth*: int
+    colorDepth*: int
+    height*: int
+    pixelDepth*: int
+    width*: int
+
+  TTimeOut* {.importc.} = object of RootObj
+  TInterval* {.importc.} = object of RootObj
+
+var
+  window* {.importc, nodecl.}: Window
+  document* {.importc, nodecl.}: Document
+  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.}
+proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.}
+
+
+type
+  TWindow* {.deprecated.} = WindowObj
+  TFrame* {.deprecated.} = FrameObj
+  TNode* {.deprecated.} = NodeObj
+  TDocument* {.deprecated.} = DocumentObj
+  TElement* {.deprecated.} = ElementObj
+  TLink* {.deprecated.} = LinkObj
+  TEmbed* {.deprecated.} = EmbedObj
+  TAnchor* {.deprecated.} = AnchorObj
+  TOption* {.deprecated.} = OptionObj
+  TForm* {.deprecated.} = FormObj
+  TImage* {.deprecated.} = ImageObj
diff --git a/lib/nimbase.h b/lib/nimbase.h
new file mode 100644
index 000000000..eea618bac
--- /dev/null
+++ b/lib/nimbase.h
@@ -0,0 +1,411 @@
+/*
+
+            Nim's Runtime Library
+        (c) Copyright 2015 Andreas Rumpf
+
+    See the file "copying.txt", included in this
+    distribution, for details about the copyright.
+*/
+
+/* compiler symbols:
+__BORLANDC__
+_MSC_VER
+__WATCOMC__
+__LCC__
+__GNUC__
+__DMC__
+__POCC__
+__TINYC__
+__clang__
+*/
+
+
+#ifndef NIMBASE_H
+#define NIMBASE_H
+
+#if defined(__GNUC__)
+#  define _GNU_SOURCE 1
+#endif
+
+#if defined(__TINYC__)
+/*#  define __GNUC__ 3
+#  define GCC_MAJOR 4
+#  define __GNUC_MINOR__ 4
+#  define __GNUC_PATCHLEVEL__ 5 */
+#  define __DECLSPEC_SUPPORTED 1
+#endif
+
+/* calling convention mess ----------------------------------------------- */
+#if defined(__GNUC__) || defined(__LCC__) || defined(__POCC__) \
+                      || defined(__TINYC__)
+  /* these should support C99's inline */
+  /* the test for __POCC__ has to come before the test for _MSC_VER,
+     because PellesC defines _MSC_VER too. This is brain-dead. */
+#  define N_INLINE(rettype, name) inline rettype name
+#elif defined(__BORLANDC__) || defined(_MSC_VER)
+/* Borland's compiler is really STRANGE here; note that the __fastcall
+   keyword cannot be before the return type, but __inline cannot be after
+   the return type, so we do not handle this mess in the code generator
+   but rather here. */
+#  define N_INLINE(rettype, name) __inline rettype name
+#elif defined(__DMC__)
+#  define N_INLINE(rettype, name) inline rettype name
+#elif defined(__WATCOMC__)
+#  define N_INLINE(rettype, name) __inline rettype name
+#else /* others are less picky: */
+#  define N_INLINE(rettype, name) rettype __inline name
+#endif
+
+#if defined(__POCC__)
+#  define NIM_CONST /* PCC is really picky with const modifiers */
+#  undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is
+                     not that compatible. Well done. */
+#elif defined(__cplusplus)
+#  define NIM_CONST /* C++ is picky with const modifiers */
+#else
+#  define NIM_CONST  const
+#endif
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+#  define NIM_THREADVAR __declspec(thread)
+#else
+#  define NIM_THREADVAR __thread
+#endif
+
+/* --------------- how int64 constants should be declared: ----------- */
+#if defined(__GNUC__) || defined(__LCC__) || \
+    defined(__POCC__) || defined(__DMC__) || defined(_MSC_VER)
+#  define IL64(x) x##LL
+#else /* works only without LL */
+#  define IL64(x) ((NI64)x)
+#endif
+
+/* ---------------- casting without correct aliasing rules ----------- */
+
+#if defined(__GNUC__)
+#  define NIM_CAST(type, ptr) (((union{type __x__;}*)(ptr))->__x__)
+#else
+#  define NIM_CAST(type, ptr) ((type)(ptr))
+#endif
+
+/* ------------------------------------------------------------------- */
+
+#if defined(WIN32) || defined(_WIN32) /* only Windows has this mess... */
+#  define N_CDECL(rettype, name) rettype __cdecl name
+#  define N_STDCALL(rettype, name) rettype __stdcall name
+#  define N_SYSCALL(rettype, name) rettype __syscall name
+#  define N_FASTCALL(rettype, name) rettype __fastcall name
+#  define N_SAFECALL(rettype, name) rettype __safecall name
+/* function pointers with calling convention: */
+#  define N_CDECL_PTR(rettype, name) rettype (__cdecl *name)
+#  define N_STDCALL_PTR(rettype, name) rettype (__stdcall *name)
+#  define N_SYSCALL_PTR(rettype, name) rettype (__syscall *name)
+#  define N_FASTCALL_PTR(rettype, name) rettype (__fastcall *name)
+#  define N_SAFECALL_PTR(rettype, name) rettype (__safecall *name)
+
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C" __declspec(dllexport)
+#  else
+#    define N_LIB_EXPORT  extern __declspec(dllexport)
+#  endif
+#  define N_LIB_IMPORT  extern __declspec(dllimport)
+#else
+#  define N_CDECL(rettype, name) rettype name
+#  define N_STDCALL(rettype, name) rettype name
+#  define N_SYSCALL(rettype, name) rettype name
+#  define N_FASTCALL(rettype, name) rettype name
+#  define N_SAFECALL(rettype, name) rettype name
+/* function pointers with calling convention: */
+#  define N_CDECL_PTR(rettype, name) rettype (*name)
+#  define N_STDCALL_PTR(rettype, name) rettype (*name)
+#  define N_SYSCALL_PTR(rettype, name) rettype (*name)
+#  define N_FASTCALL_PTR(rettype, name) rettype (*name)
+#  define N_SAFECALL_PTR(rettype, name) rettype (*name)
+
+#  ifdef __cplusplus
+#    define N_LIB_EXPORT  extern "C"
+#  else
+#    define N_LIB_EXPORT  extern
+#  endif
+#  define N_LIB_IMPORT  extern
+#endif
+
+#define N_NOCONV(rettype, name) rettype name
+/* specify no calling convention */
+#define N_NOCONV_PTR(rettype, name) rettype (*name)
+
+#if defined(__GNUC__) || defined(__ICC__)
+#  define N_NOINLINE(rettype, name) rettype __attribute__((noinline)) name
+#elif defined(_MSC_VER)
+#  define N_NOINLINE(rettype, name) __declspec(noinline) rettype name
+#else
+#  define N_NOINLINE(rettype, name) rettype name
+#endif
+
+#define N_NOINLINE_PTR(rettype, name) rettype (*name)
+
+#if defined(__BORLANDC__) || defined(__WATCOMC__) || \
+    defined(__POCC__) || defined(_MSC_VER) || defined(WIN32) || defined(_WIN32)
+/* these compilers have a fastcall so use it: */
+#  define N_NIMCALL(rettype, name) rettype __fastcall name
+#  define N_NIMCALL_PTR(rettype, name) rettype (__fastcall *name)
+#  define N_RAW_NIMCALL __fastcall
+#else
+#  define N_NIMCALL(rettype, name) rettype name /* no modifier */
+#  define N_NIMCALL_PTR(rettype, name) rettype (*name)
+#  define N_RAW_NIMCALL
+#endif
+
+#define N_CLOSURE(rettype, name) N_NIMCALL(rettype, name)
+#define N_CLOSURE_PTR(rettype, name) N_NIMCALL_PTR(rettype, name)
+
+/* ----------------------------------------------------------------------- */
+
+#include <limits.h>
+#include <stddef.h>
+
+/* C99 compiler? */
+#if (defined(__STD_VERSION__) && (__STD_VERSION__ >= 199901))
+#  define HAVE_STDINT_H
+#endif
+
+#if defined(__LCC__) || defined(__DMC__) || defined(__POCC__)
+#  define HAVE_STDINT_H
+#endif
+
+/* bool types (C++ has it): */
+#ifdef __cplusplus
+#  ifndef NIM_TRUE
+#    define NIM_TRUE true
+#  endif
+#  ifndef NIM_FALSE
+#    define NIM_FALSE false
+#  endif
+#  define NIM_BOOL bool
+#  define NIM_NIL 0
+struct NimException
+{
+  NimException(struct Exception* exp, const char* msg): exp(exp), msg(msg) {}
+
+  struct Exception* exp;
+  const char* msg;
+};
+#else
+#  ifdef bool
+#    define NIM_BOOL bool
+#  else
+  typedef unsigned char NIM_BOOL;
+#  endif
+#  ifndef NIM_TRUE
+#    define NIM_TRUE ((NIM_BOOL) 1)
+#  endif
+#  ifndef NIM_FALSE
+#    define NIM_FALSE ((NIM_BOOL) 0)
+#  endif
+#  define NIM_NIL ((void*)0) /* C's NULL is fucked up in some C compilers, so
+                              the generated code does not rely on it anymore */
+#endif
+
+#if defined(__BORLANDC__) || defined(__DMC__) \
+   || defined(__WATCOMC__) || defined(_MSC_VER)
+typedef signed char NI8;
+typedef signed short int NI16;
+typedef signed int NI32;
+/* XXX: Float128? */
+typedef unsigned char NU8;
+typedef unsigned short int NU16;
+typedef unsigned __int64 NU64;
+typedef __int64 NI64;
+typedef unsigned int NU32;
+#elif defined(HAVE_STDINT_H)
+#  include <stdint.h>
+typedef int8_t NI8;
+typedef int16_t NI16;
+typedef int32_t NI32;
+typedef int64_t NI64;
+typedef uint64_t NU64;
+typedef uint8_t NU8;
+typedef uint16_t NU16;
+typedef uint32_t NU32;
+#else
+typedef signed char NI8;
+typedef signed short int NI16;
+typedef signed int NI32;
+/* XXX: Float128? */
+typedef unsigned char NU8;
+typedef unsigned short int NU16;
+typedef unsigned long long int NU64;
+typedef long long int NI64;
+typedef unsigned int NU32;
+#endif
+
+#ifdef NIM_INTBITS
+#  if NIM_INTBITS == 64
+typedef NI64 NI;
+typedef NU64 NU;
+#  elif NIM_INTBITS == 32
+typedef NI32 NI;
+typedef NU32 NU;
+#  elif NIM_INTBITS == 16
+typedef NI16 NI;
+typedef NU16 NU;
+#  elif NIM_INTBITS == 8
+typedef NI8 NI;
+typedef NU8 NU;
+#  else
+#    error "invalid bit width for int"
+#  endif
+#endif
+
+extern NI nim_program_result;
+
+typedef float NF32;
+typedef double NF64;
+typedef double NF;
+
+typedef char NIM_CHAR;
+typedef char* NCSTRING;
+
+#ifdef NIM_BIG_ENDIAN
+#  define NIM_IMAN 1
+#else
+#  define NIM_IMAN 0
+#endif
+
+static N_INLINE(NI, float64ToInt32)(double x) {
+  /* nowadays no hack necessary anymore */
+  return x >= 0 ? (NI)(x+0.5) : (NI)(x-0.5);
+}
+
+static N_INLINE(NI32, float32ToInt32)(float x) {
+  /* nowadays no hack necessary anymore */
+  return x >= 0 ? (NI32)(x+0.5) : (NI32)(x-0.5);
+}
+
+#define float64ToInt64(x) ((NI64) (x))
+
+#define zeroMem(a, size) memset(a, 0, size)
+#define equalMem(a, b, size) (memcmp(a, b, size) == 0)
+
+#define STRING_LITERAL(name, str, length) \
+  static const struct {                   \
+    TGenericSeq Sup;                      \
+    NIM_CHAR data[(length) + 1];          \
+  } name = {{length, length}, str}
+
+typedef struct TStringDesc* string;
+
+/* declared size of a sequence/variable length array: */
+#if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER)
+#  define SEQ_DECL_SIZE /* empty is correct! */
+#else
+#  define SEQ_DECL_SIZE 1000000
+#endif
+
+#define ALLOC_0(size)  calloc(1, size)
+#define DL_ALLOC_0(size) dlcalloc(1, size)
+
+#define GenericSeqSize sizeof(TGenericSeq)
+#define paramCount() cmdCount
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__i386__)
+#  ifndef NAN
+static unsigned long nimNaN[2]={0xffffffff, 0x7fffffff};
+#    define NAN (*(double*) nimNaN)
+#  endif
+#endif
+
+#ifndef NAN
+#  define NAN (0.0 / 0.0)
+#endif
+
+#ifndef INF
+#  ifdef INFINITY
+#    define INF INFINITY
+#  elif defined(HUGE_VAL)
+#    define INF  HUGE_VAL
+#  elif defined(_MSC_VER)
+#    include <float.h>
+#    define INF (DBL_MAX+DBL_MAX)
+#  else
+#    define INF (1.0 / 0.0)
+#  endif
+#endif
+
+typedef struct TFrame TFrame;
+struct TFrame {
+  TFrame* prev;
+  NCSTRING procname;
+  NI line;
+  NCSTRING filename;
+  NI16 len;
+  NI16 calldepth;
+};
+
+#define nimfr(proc, file) \
+  TFrame FR; \
+  FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = 0; nimFrame(&FR);
+
+#define nimfrs(proc, file, slots, length) \
+  struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} FR; \
+  FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = length; nimFrame((TFrame*)&FR);
+
+#define nimln(n, file) \
+  FR.line = n; FR.filename = file;
+
+#define NIM_POSIX_INIT  __attribute__((constructor))
+
+#if defined(_MSCVER) && defined(__i386__)
+__declspec(naked) int __fastcall NimXadd(volatile int* pNum, int val) {
+  __asm {
+    lock xadd dword ptr [ECX], EDX
+    mov EAX, EDX
+    ret
+  }
+}
+#endif
+
+#ifdef __GNUC__
+#  define likely(x) __builtin_expect(x, 1)
+#  define unlikely(x) __builtin_expect(x, 0)
+/* We need the following for the posix wrapper. In particular it will give us
+   POSIX_SPAWN_USEVFORK: */
+#  ifndef _GNU_SOURCE
+#    define _GNU_SOURCE
+#  endif
+#else
+#  define likely(x) (x)
+#  define unlikely(x) (x)
+#endif
+
+#if 0 // defined(__GNUC__) || defined(__clang__)
+// not needed anymore because the stack marking cares about
+// interior pointers now
+static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
+#  define GC_GUARD __attribute__ ((cleanup(GCGuard)))
+#else
+#  define GC_GUARD
+#endif
+
+/* Test to see if Nim and the C compiler agree on the size of a pointer.
+   On disagreement, your C compiler will say something like:
+   "error: 'assert_numbits' declared as an array with a negative size" */
+typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
+#endif
+
+#ifdef  __cplusplus
+#  define NIM_EXTERNC extern "C"
+#else
+#  define NIM_EXTERNC
+#endif
+
+/* ---------------- platform specific includes ----------------------- */
+
+/* VxWorks related includes */
+#if defined(__VXWORKS__)
+#  include <sys/types.h>
+#  include <types/vxWind.h>
+#  include <tool/gnu/toolMacros.h>
+#elif defined(__FreeBSD__)
+#  include <sys/types.h>
+#endif
diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim
new file mode 100644
index 000000000..96dab1284
--- /dev/null
+++ b/lib/nimrtl.nim
@@ -0,0 +1,36 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Main file to generate a DLL from the standard library. 
+## The default Nimrtl does not only contain the ``system`` module, but these 
+## too:
+##
+## * parseutils
+## * strutils
+## * parseopt
+## * parsecfg
+## * strtabs
+## * times
+## * os
+## * osproc
+## * unicode
+## * pegs
+## * ropes
+## 
+
+when system.appType != "lib":
+  {.error: "This file has to be compiled as a library!".}
+
+when not defined(createNimRtl): 
+  {.error: "This file has to be compiled with '-d:createNimRtl'".}
+
+import
+  parseutils, strutils, parseopt, parsecfg, strtabs, unicode, pegs, ropes,
+  os, osproc, times
+
diff --git a/lib/nimrtl.nim.cfg b/lib/nimrtl.nim.cfg
new file mode 100644
index 000000000..b60de183a
--- /dev/null
+++ b/lib/nimrtl.nim.cfg
@@ -0,0 +1,5 @@
+# The RTL.dll needs to be compiled with these options!
+
+--app:lib
+--define:createNimRtl
+
diff --git a/lib/packages/docutils/docutils.babel b/lib/packages/docutils/docutils.babel
new file mode 100644
index 000000000..1ed86ca05
--- /dev/null
+++ b/lib/packages/docutils/docutils.babel
@@ -0,0 +1,6 @@
+[Package]
+name          = "docutils"
+version       = "0.9.0"
+author        = "Andreas Rumpf"
+description   = "Nimrod's reStructuredText processor."
+license       = "MIT"
diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim
new file mode 100644
index 000000000..9485f3912
--- /dev/null
+++ b/lib/packages/docutils/highlite.nim
@@ -0,0 +1,567 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Source highlighter for programming or markup languages.
+## Currently only few languages are supported, other languages may be added.
+## The interface supports one language nested in another.
+
+import
+  strutils
+
+type
+  TTokenClass* = enum
+    gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber,
+    gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit,
+    gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff
+    gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression,
+    gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler,
+    gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel,
+    gtReference, gtOther
+  TGeneralTokenizer* = object of RootObj
+    kind*: TTokenClass
+    start*, length*: int
+    buf: cstring
+    pos: int
+    state: TTokenClass
+
+  TSourceLanguage* = enum
+    langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava
+
+const
+  sourceLanguageToStr*: array[TSourceLanguage, string] = ["none",
+    "Nim", "Nimrod", "C++", "C#", "C", "Java"]
+  tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace",
+    "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber",
+    "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit",
+    "EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment",
+    "RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData",
+    "Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink",
+    "Label", "Reference", "Other"]
+
+  # The following list comes from doc/keywords.txt, make sure it is
+  # synchronized with this array by running the module itself as a test case.
+  nimKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block",
+    "break", "case", "cast", "concept", "const", "continue", "converter",
+    "defer", "discard", "distinct", "div", "do",
+    "elif", "else", "end", "enum", "except", "export",
+    "finally", "for", "from", "func",
+    "generic", "if", "import", "in", "include",
+    "interface", "is", "isnot", "iterator", "let", "macro", "method",
+    "mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc",
+    "ptr", "raise", "ref", "return", "shl", "shr", "static",
+    "template", "try", "tuple", "type", "using", "var", "when", "while", "with",
+    "without", "xor", "yield"]
+
+proc getSourceLanguage*(name: string): TSourceLanguage =
+  for i in countup(succ(low(TSourceLanguage)), high(TSourceLanguage)):
+    if cmpIgnoreStyle(name, sourceLanguageToStr[i]) == 0:
+      return i
+  result = langNone
+
+proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: cstring) =
+  g.buf = buf
+  g.kind = low(TTokenClass)
+  g.start = 0
+  g.length = 0
+  g.state = low(TTokenClass)
+  var pos = 0                     # skip initial whitespace:
+  while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
+  g.pos = pos
+
+proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
+  initGeneralTokenizer(g, cstring(buf))
+
+proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
+  discard
+
+proc nimGetKeyword(id: string): TTokenClass =
+  for k in nimKeywords:
+    if cmpIgnoreStyle(id, k) == 0: return gtKeyword
+  result = gtIdentifier
+  when false:
+    var i = getIdent(id)
+    if (i.id >= ord(tokKeywordLow) - ord(tkSymbol)) and
+        (i.id <= ord(tokKeywordHigh) - ord(tkSymbol)):
+      result = gtKeyword
+    else:
+      result = gtIdentifier
+
+proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
+  var pos = position
+  if g.buf[pos] == '\'':
+    inc(pos)
+    case g.buf[pos]
+    of 'f', 'F':
+      g.kind = gtFloatNumber
+      inc(pos)
+      if g.buf[pos] in {'0'..'9'}: inc(pos)
+      if g.buf[pos] in {'0'..'9'}: inc(pos)
+    of 'i', 'I':
+      inc(pos)
+      if g.buf[pos] in {'0'..'9'}: inc(pos)
+      if g.buf[pos] in {'0'..'9'}: inc(pos)
+    else:
+      discard
+  result = pos
+
+proc nimNumber(g: var TGeneralTokenizer, position: int): int =
+  const decChars = {'0'..'9', '_'}
+  var pos = position
+  g.kind = gtDecNumber
+  while g.buf[pos] in decChars: inc(pos)
+  if g.buf[pos] == '.':
+    g.kind = gtFloatNumber
+    inc(pos)
+    while g.buf[pos] in decChars: inc(pos)
+  if g.buf[pos] in {'e', 'E'}:
+    g.kind = gtFloatNumber
+    inc(pos)
+    if g.buf[pos] in {'+', '-'}: inc(pos)
+    while g.buf[pos] in decChars: inc(pos)
+  result = nimNumberPostfix(g, pos)
+
+const
+  OpChars  = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
+              '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
+
+proc nimNextToken(g: var TGeneralTokenizer) =
+  const
+    hexChars = {'0'..'9', 'A'..'F', 'a'..'f', '_'}
+    octChars = {'0'..'7', '_'}
+    binChars = {'0'..'1', '_'}
+    SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
+  var pos = g.pos
+  g.start = g.pos
+  if g.state == gtStringLit:
+    g.kind = gtStringLit
+    while true:
+      case g.buf[pos]
+      of '\\':
+        g.kind = gtEscapeSequence
+        inc(pos)
+        case g.buf[pos]
+        of 'x', 'X':
+          inc(pos)
+          if g.buf[pos] in hexChars: inc(pos)
+          if g.buf[pos] in hexChars: inc(pos)
+        of '0'..'9':
+          while g.buf[pos] in {'0'..'9'}: inc(pos)
+        of '\0':
+          g.state = gtNone
+        else: inc(pos)
+        break
+      of '\0', '\x0D', '\x0A':
+        g.state = gtNone
+        break
+      of '\"':
+        inc(pos)
+        g.state = gtNone
+        break
+      else: inc(pos)
+  else:
+    case g.buf[pos]
+    of ' ', '\x09'..'\x0D':
+      g.kind = gtWhitespace
+      while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
+    of '#':
+      g.kind = gtComment
+      while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
+    of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
+      var id = ""
+      while g.buf[pos] in SymChars + {'_'}:
+        add(id, g.buf[pos])
+        inc(pos)
+      if (g.buf[pos] == '\"'):
+        if (g.buf[pos + 1] == '\"') and (g.buf[pos + 2] == '\"'):
+          inc(pos, 3)
+          g.kind = gtLongStringLit
+          while true:
+            case g.buf[pos]
+            of '\0':
+              break
+            of '\"':
+              inc(pos)
+              if g.buf[pos] == '\"' and g.buf[pos+1] == '\"' and
+                  g.buf[pos+2] != '\"':
+                inc(pos, 2)
+                break
+            else: inc(pos)
+        else:
+          g.kind = gtRawData
+          inc(pos)
+          while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}):
+            if g.buf[pos] == '"' and g.buf[pos+1] != '"': break
+            inc(pos)
+          if g.buf[pos] == '\"': inc(pos)
+      else:
+        g.kind = nimGetKeyword(id)
+    of '0':
+      inc(pos)
+      case g.buf[pos]
+      of 'b', 'B':
+        inc(pos)
+        while g.buf[pos] in binChars: inc(pos)
+        pos = nimNumberPostfix(g, pos)
+      of 'x', 'X':
+        inc(pos)
+        while g.buf[pos] in hexChars: inc(pos)
+        pos = nimNumberPostfix(g, pos)
+      of 'o', 'O':
+        inc(pos)
+        while g.buf[pos] in octChars: inc(pos)
+        pos = nimNumberPostfix(g, pos)
+      else: pos = nimNumber(g, pos)
+    of '1'..'9':
+      pos = nimNumber(g, pos)
+    of '\'':
+      inc(pos)
+      g.kind = gtCharLit
+      while true:
+        case g.buf[pos]
+        of '\0', '\x0D', '\x0A':
+          break
+        of '\'':
+          inc(pos)
+          break
+        of '\\':
+          inc(pos, 2)
+        else: inc(pos)
+    of '\"':
+      inc(pos)
+      if (g.buf[pos] == '\"') and (g.buf[pos + 1] == '\"'):
+        inc(pos, 2)
+        g.kind = gtLongStringLit
+        while true:
+          case g.buf[pos]
+          of '\0':
+            break
+          of '\"':
+            inc(pos)
+            if g.buf[pos] == '\"' and g.buf[pos+1] == '\"' and
+                g.buf[pos+2] != '\"':
+              inc(pos, 2)
+              break
+          else: inc(pos)
+      else:
+        g.kind = gtStringLit
+        while true:
+          case g.buf[pos]
+          of '\0', '\x0D', '\x0A':
+            break
+          of '\"':
+            inc(pos)
+            break
+          of '\\':
+            g.state = g.kind
+            break
+          else: inc(pos)
+    of '(', ')', '[', ']', '{', '}', '`', ':', ',', ';':
+      inc(pos)
+      g.kind = gtPunctuation
+    of '\0':
+      g.kind = gtEof
+    else:
+      if g.buf[pos] in OpChars:
+        g.kind = gtOperator
+        while g.buf[pos] in OpChars: inc(pos)
+      else:
+        inc(pos)
+        g.kind = gtNone
+  g.length = pos - g.pos
+  if g.kind != gtEof and g.length <= 0:
+    assert false, "nimNextToken: produced an empty token"
+  g.pos = pos
+
+proc generalNumber(g: var TGeneralTokenizer, position: int): int =
+  const decChars = {'0'..'9'}
+  var pos = position
+  g.kind = gtDecNumber
+  while g.buf[pos] in decChars: inc(pos)
+  if g.buf[pos] == '.':
+    g.kind = gtFloatNumber
+    inc(pos)
+    while g.buf[pos] in decChars: inc(pos)
+  if g.buf[pos] in {'e', 'E'}:
+    g.kind = gtFloatNumber
+    inc(pos)
+    if g.buf[pos] in {'+', '-'}: inc(pos)
+    while g.buf[pos] in decChars: inc(pos)
+  result = pos
+
+proc generalStrLit(g: var TGeneralTokenizer, position: int): int =
+  const
+    decChars = {'0'..'9'}
+    hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
+  var pos = position
+  g.kind = gtStringLit
+  var c = g.buf[pos]
+  inc(pos)                    # skip " or '
+  while true:
+    case g.buf[pos]
+    of '\0':
+      break
+    of '\\':
+      inc(pos)
+      case g.buf[pos]
+      of '\0':
+        break
+      of '0'..'9':
+        while g.buf[pos] in decChars: inc(pos)
+      of 'x', 'X':
+        inc(pos)
+        if g.buf[pos] in hexChars: inc(pos)
+        if g.buf[pos] in hexChars: inc(pos)
+      else: inc(pos, 2)
+    else:
+      if g.buf[pos] == c:
+        inc(pos)
+        break
+      else:
+        inc(pos)
+  result = pos
+
+proc isKeyword(x: openArray[string], y: string): int =
+  var a = 0
+  var b = len(x) - 1
+  while a <= b:
+    var mid = (a + b) div 2
+    var c = cmp(x[mid], y)
+    if c < 0:
+      a = mid + 1
+    elif c > 0:
+      b = mid - 1
+    else:
+      return mid
+  result = - 1
+
+proc isKeywordIgnoreCase(x: openArray[string], y: string): int =
+  var a = 0
+  var b = len(x) - 1
+  while a <= b:
+    var mid = (a + b) div 2
+    var c = cmpIgnoreCase(x[mid], y)
+    if c < 0:
+      a = mid + 1
+    elif c > 0:
+      b = mid - 1
+    else:
+      return mid
+  result = - 1
+
+type
+  TTokenizerFlag = enum
+    hasPreprocessor, hasNestedComments
+  TTokenizerFlags = set[TTokenizerFlag]
+
+proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
+                    flags: TTokenizerFlags) =
+  const
+    hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
+    octChars = {'0'..'7'}
+    binChars = {'0'..'1'}
+    symChars = {'A'..'Z', 'a'..'z', '0'..'9', '_', '\x80'..'\xFF'}
+  var pos = g.pos
+  g.start = g.pos
+  if g.state == gtStringLit:
+    g.kind = gtStringLit
+    while true:
+      case g.buf[pos]
+      of '\\':
+        g.kind = gtEscapeSequence
+        inc(pos)
+        case g.buf[pos]
+        of 'x', 'X':
+          inc(pos)
+          if g.buf[pos] in hexChars: inc(pos)
+          if g.buf[pos] in hexChars: inc(pos)
+        of '0'..'9':
+          while g.buf[pos] in {'0'..'9'}: inc(pos)
+        of '\0':
+          g.state = gtNone
+        else: inc(pos)
+        break
+      of '\0', '\x0D', '\x0A':
+        g.state = gtNone
+        break
+      of '\"':
+        inc(pos)
+        g.state = gtNone
+        break
+      else: inc(pos)
+  else:
+    case g.buf[pos]
+    of ' ', '\x09'..'\x0D':
+      g.kind = gtWhitespace
+      while g.buf[pos] in {' ', '\x09'..'\x0D'}: inc(pos)
+    of '/':
+      inc(pos)
+      if g.buf[pos] == '/':
+        g.kind = gtComment
+        while not (g.buf[pos] in {'\0', '\x0A', '\x0D'}): inc(pos)
+      elif g.buf[pos] == '*':
+        g.kind = gtLongComment
+        var nested = 0
+        inc(pos)
+        while true:
+          case g.buf[pos]
+          of '*':
+            inc(pos)
+            if g.buf[pos] == '/':
+              inc(pos)
+              if nested == 0: break
+          of '/':
+            inc(pos)
+            if g.buf[pos] == '*':
+              inc(pos)
+              if hasNestedComments in flags: inc(nested)
+          of '\0':
+            break
+          else: inc(pos)
+    of '#':
+      inc(pos)
+      if hasPreprocessor in flags:
+        g.kind = gtPreprocessor
+        while g.buf[pos] in {' ', '\t'}: inc(pos)
+        while g.buf[pos] in symChars: inc(pos)
+      else:
+        g.kind = gtOperator
+    of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
+      var id = ""
+      while g.buf[pos] in symChars:
+        add(id, g.buf[pos])
+        inc(pos)
+      if isKeyword(keywords, id) >= 0: g.kind = gtKeyword
+      else: g.kind = gtIdentifier
+    of '0':
+      inc(pos)
+      case g.buf[pos]
+      of 'b', 'B':
+        inc(pos)
+        while g.buf[pos] in binChars: inc(pos)
+        if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
+      of 'x', 'X':
+        inc(pos)
+        while g.buf[pos] in hexChars: inc(pos)
+        if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
+      of '0'..'7':
+        inc(pos)
+        while g.buf[pos] in octChars: inc(pos)
+        if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
+      else:
+        pos = generalNumber(g, pos)
+        if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
+    of '1'..'9':
+      pos = generalNumber(g, pos)
+      if g.buf[pos] in {'A'..'Z', 'a'..'z'}: inc(pos)
+    of '\'':
+      pos = generalStrLit(g, pos)
+      g.kind = gtCharLit
+    of '\"':
+      inc(pos)
+      g.kind = gtStringLit
+      while true:
+        case g.buf[pos]
+        of '\0':
+          break
+        of '\"':
+          inc(pos)
+          break
+        of '\\':
+          g.state = g.kind
+          break
+        else: inc(pos)
+    of '(', ')', '[', ']', '{', '}', ':', ',', ';', '.':
+      inc(pos)
+      g.kind = gtPunctuation
+    of '\0':
+      g.kind = gtEof
+    else:
+      if g.buf[pos] in OpChars:
+        g.kind = gtOperator
+        while g.buf[pos] in OpChars: inc(pos)
+      else:
+        inc(pos)
+        g.kind = gtNone
+  g.length = pos - g.pos
+  if g.kind != gtEof and g.length <= 0:
+    assert false, "clikeNextToken: produced an empty token"
+  g.pos = pos
+
+proc cNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..36, string] = ["_Bool", "_Complex", "_Imaginary", "auto",
+      "break", "case", "char", "const", "continue", "default", "do", "double",
+      "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int",
+      "long", "register", "restrict", "return", "short", "signed", "sizeof",
+      "static", "struct", "switch", "typedef", "union", "unsigned", "void",
+      "volatile", "while"]
+  clikeNextToken(g, keywords, {hasPreprocessor})
+
+proc cppNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..47, string] = ["asm", "auto", "break", "case", "catch",
+      "char", "class", "const", "continue", "default", "delete", "do", "double",
+      "else", "enum", "extern", "float", "for", "friend", "goto", "if",
+      "inline", "int", "long", "new", "operator", "private", "protected",
+      "public", "register", "return", "short", "signed", "sizeof", "static",
+      "struct", "switch", "template", "this", "throw", "try", "typedef",
+      "union", "unsigned", "virtual", "void", "volatile", "while"]
+  clikeNextToken(g, keywords, {hasPreprocessor})
+
+proc csharpNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..76, string] = ["abstract", "as", "base", "bool", "break",
+      "byte", "case", "catch", "char", "checked", "class", "const", "continue",
+      "decimal", "default", "delegate", "do", "double", "else", "enum", "event",
+      "explicit", "extern", "false", "finally", "fixed", "float", "for",
+      "foreach", "goto", "if", "implicit", "in", "int", "interface", "internal",
+      "is", "lock", "long", "namespace", "new", "null", "object", "operator",
+      "out", "override", "params", "private", "protected", "public", "readonly",
+      "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc",
+      "static", "string", "struct", "switch", "this", "throw", "true", "try",
+      "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using",
+      "virtual", "void", "volatile", "while"]
+  clikeNextToken(g, keywords, {hasPreprocessor})
+
+proc javaNextToken(g: var TGeneralTokenizer) =
+  const
+    keywords: array[0..52, string] = ["abstract", "assert", "boolean", "break",
+      "byte", "case", "catch", "char", "class", "const", "continue", "default",
+      "do", "double", "else", "enum", "extends", "false", "final", "finally",
+      "float", "for", "goto", "if", "implements", "import", "instanceof", "int",
+      "interface", "long", "native", "new", "null", "package", "private",
+      "protected", "public", "return", "short", "static", "strictfp", "super",
+      "switch", "synchronized", "this", "throw", "throws", "transient", "true",
+      "try", "void", "volatile", "while"]
+  clikeNextToken(g, keywords, {})
+
+proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) =
+  case lang
+  of langNone: assert false
+  of langNim, langNimrod: nimNextToken(g)
+  of langCpp: cppNextToken(g)
+  of langCsharp: csharpNextToken(g)
+  of langC: cNextToken(g)
+  of langJava: javaNextToken(g)
+
+when isMainModule:
+  var keywords: seq[string]
+  # Try to work running in both the subdir or at the root.
+  for filename in ["doc/keywords.txt", "../../../doc/keywords.txt"]:
+    try:
+      let input = string(readFile(filename))
+      keywords = input.split()
+      break
+    except:
+      echo filename, " not found"
+  doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!")
+  doAssert keywords.len == nimKeywords.len, "No matching lengths"
+  for i in 0..keywords.len-1:
+    #echo keywords[i], " == ", nimKeywords[i]
+    doAssert keywords[i] == nimKeywords[i], "Unexpected keyword"
diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim
new file mode 100644
index 000000000..2ee94ba13
--- /dev/null
+++ b/lib/packages/docutils/rst.nim
@@ -0,0 +1,1708 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a `reStructuredText`:idx: parser. A large
+## subset is implemented. Some features of the `markdown`:idx: wiki syntax are
+## also supported.
+
+import
+  os, strutils, rstast
+
+type
+  TRstParseOption* = enum     ## options for the RST parser
+    roSkipPounds,             ## skip ``#`` at line beginning (documentation
+                              ## embedded in Nim comments)
+    roSupportSmilies,         ## make the RST parser support smilies like ``:)``
+    roSupportRawDirective,    ## support the ``raw`` directive (don't support
+                              ## it for sandboxing)
+    roSupportMarkdown         ## support additional features of markdown
+
+  TRstParseOptions* = set[TRstParseOption]
+
+  TMsgClass* = enum
+    mcHint = "Hint",
+    mcWarning = "Warning",
+    mcError = "Error"
+
+  TMsgKind* = enum          ## the possible messages
+    meCannotOpenFile,
+    meExpected,
+    meGridTableNotImplemented,
+    meNewSectionExpected,
+    meGeneralParseError,
+    meInvalidDirective,
+    mwRedefinitionOfLabel,
+    mwUnknownSubstitution,
+    mwUnsupportedLanguage,
+    mwUnsupportedField
+
+  TMsgHandler* = proc (filename: string, line, col: int, msgKind: TMsgKind,
+                       arg: string) {.nimcall.} ## what to do in case of an error
+  TFindFileHandler* = proc (filename: string): string {.nimcall.}
+
+const
+  messages: array [TMsgKind, string] = [
+    meCannotOpenFile: "cannot open '$1'",
+    meExpected: "'$1' expected",
+    meGridTableNotImplemented: "grid table is not implemented",
+    meNewSectionExpected: "new section expected",
+    meGeneralParseError: "general parse error",
+    meInvalidDirective: "invalid directive: '$1'",
+    mwRedefinitionOfLabel: "redefinition of label '$1'",
+    mwUnknownSubstitution: "unknown substitution '$1'",
+    mwUnsupportedLanguage: "language '$1' not supported",
+    mwUnsupportedField: "field '$1' not supported"
+  ]
+
+proc rstnodeToRefname*(n: PRstNode): string
+proc addNodes*(n: PRstNode): string
+proc getFieldValue*(n: PRstNode, fieldname: string): string
+proc getArgument*(n: PRstNode): string
+
+# ----------------------------- scanner part --------------------------------
+
+const
+  SymChars: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
+  SmileyStartChars: set[char] = {':', ';', '8'}
+  Smilies = {
+    ":D": "icon_e_biggrin",
+    ":-D": "icon_e_biggrin",
+    ":)": "icon_e_smile",
+    ":-)": "icon_e_smile",
+    ";)": "icon_e_wink",
+    ";-)": "icon_e_wink",
+    ":(": "icon_e_sad",
+    ":-(": "icon_e_sad",
+    ":o": "icon_e_surprised",
+    ":-o": "icon_e_surprised",
+    ":shock:": "icon_eek",
+    ":?": "icon_e_confused",
+    ":-?": "icon_e_confused",
+    ":-/": "icon_e_confused",
+
+    "8-)": "icon_cool",
+
+    ":lol:": "icon_lol",
+    ":x": "icon_mad",
+    ":-x": "icon_mad",
+    ":P": "icon_razz",
+    ":-P": "icon_razz",
+    ":oops:": "icon_redface",
+    ":cry:": "icon_cry",
+    ":evil:": "icon_evil",
+    ":twisted:": "icon_twisted",
+    ":roll:": "icon_rolleyes",
+    ":!:": "icon_exclaim",
+
+    ":?:": "icon_question",
+    ":idea:": "icon_idea",
+    ":arrow:": "icon_arrow",
+    ":|": "icon_neutral",
+    ":-|": "icon_neutral",
+    ":mrgreen:": "icon_mrgreen",
+    ":geek:": "icon_e_geek",
+    ":ugeek:": "icon_e_ugeek"
+  }
+
+type
+  TTokType = enum
+    tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther
+  TToken = object             # a RST token
+    kind*: TTokType           # the type of the token
+    ival*: int                # the indentation or parsed integer value
+    symbol*: string           # the parsed symbol as string
+    line*, col*: int          # line and column of the token
+
+  TTokenSeq = seq[TToken]
+  TLexer = object of RootObj
+    buf*: cstring
+    bufpos*: int
+    line*, col*, baseIndent*: int
+    skipPounds*: bool
+
+
+proc getThing(L: var TLexer, tok: var TToken, s: set[char]) =
+  tok.kind = tkWord
+  tok.line = L.line
+  tok.col = L.col
+  var pos = L.bufpos
+  while true:
+    add(tok.symbol, L.buf[pos])
+    inc(pos)
+    if L.buf[pos] notin s: break
+  inc(L.col, pos - L.bufpos)
+  L.bufpos = pos
+
+proc getAdornment(L: var TLexer, tok: var TToken) =
+  tok.kind = tkAdornment
+  tok.line = L.line
+  tok.col = L.col
+  var pos = L.bufpos
+  var c = L.buf[pos]
+  while true:
+    add(tok.symbol, L.buf[pos])
+    inc(pos)
+    if L.buf[pos] != c: break
+  inc(L.col, pos - L.bufpos)
+  L.bufpos = pos
+
+proc getIndentAux(L: var TLexer, start: int): int =
+  var pos = start
+  var buf = L.buf
+  # skip the newline (but include it in the token!)
+  if buf[pos] == '\x0D':
+    if buf[pos + 1] == '\x0A': inc(pos, 2)
+    else: inc(pos)
+  elif buf[pos] == '\x0A':
+    inc(pos)
+  if L.skipPounds:
+    if buf[pos] == '#': inc(pos)
+    if buf[pos] == '#': inc(pos)
+  while true:
+    case buf[pos]
+    of ' ', '\x0B', '\x0C':
+      inc(pos)
+      inc(result)
+    of '\x09':
+      inc(pos)
+      result = result - (result mod 8) + 8
+    else:
+      break                   # EndOfFile also leaves the loop
+  if buf[pos] == '\0':
+    result = 0
+  elif (buf[pos] == '\x0A') or (buf[pos] == '\x0D'):
+    # look at the next line for proper indentation:
+    result = getIndentAux(L, pos)
+  L.bufpos = pos              # no need to set back buf
+
+proc getIndent(L: var TLexer, tok: var TToken) =
+  tok.col = 0
+  tok.kind = tkIndent         # skip the newline (but include it in the token!)
+  tok.ival = getIndentAux(L, L.bufpos)
+  inc L.line
+  tok.line = L.line
+  L.col = tok.ival
+  tok.ival = max(tok.ival - L.baseIndent, 0)
+  tok.symbol = "\n" & spaces(tok.ival)
+
+proc rawGetTok(L: var TLexer, tok: var TToken) =
+  tok.symbol = ""
+  tok.ival = 0
+  var c = L.buf[L.bufpos]
+  case c
+  of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '0'..'9':
+    getThing(L, tok, SymChars)
+  of ' ', '\x09', '\x0B', '\x0C':
+    getThing(L, tok, {' ', '\x09'})
+    tok.kind = tkWhite
+    if L.buf[L.bufpos] in {'\x0D', '\x0A'}:
+      rawGetTok(L, tok)       # ignore spaces before \n
+  of '\x0D', '\x0A':
+    getIndent(L, tok)
+  of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
+     '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
+     '|', '}', '~':
+    getAdornment(L, tok)
+    if len(tok.symbol) <= 3: tok.kind = tkPunct
+  else:
+    tok.line = L.line
+    tok.col = L.col
+    if c == '\0':
+      tok.kind = tkEof
+    else:
+      tok.kind = tkOther
+      add(tok.symbol, c)
+      inc(L.bufpos)
+      inc(L.col)
+  tok.col = max(tok.col - L.baseIndent, 0)
+
+proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
+  var L: TLexer
+  var length = len(tokens)
+  L.buf = cstring(buffer)
+  L.line = 0                  # skip UTF-8 BOM
+  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
+    inc(L.bufpos, 3)
+  L.skipPounds = skipPounds
+  if skipPounds:
+    if L.buf[L.bufpos] == '#':
+      inc(L.bufpos)
+      inc(result)
+    if L.buf[L.bufpos] == '#':
+      inc(L.bufpos)
+      inc(result)
+    L.baseIndent = 0
+    while L.buf[L.bufpos] == ' ':
+      inc(L.bufpos)
+      inc(L.baseIndent)
+      inc(result)
+  while true:
+    inc(length)
+    setLen(tokens, length)
+    rawGetTok(L, tokens[length - 1])
+    if tokens[length - 1].kind == tkEof: break
+  if tokens[0].kind == tkWhite:
+    # BUGFIX
+    tokens[0].ival = len(tokens[0].symbol)
+    tokens[0].kind = tkIndent
+
+type
+  TLevelMap = array[char, int]
+  TSubstitution = object
+    key*: string
+    value*: PRstNode
+
+  TSharedState = object
+    options: TRstParseOptions   # parsing options
+    uLevel, oLevel: int         # counters for the section levels
+    subs: seq[TSubstitution]    # substitutions
+    refs: seq[TSubstitution]    # references
+    underlineToLevel: TLevelMap # Saves for each possible title adornment
+                                # character its level in the
+                                # current document.
+                                # This is for single underline adornments.
+    overlineToLevel: TLevelMap  # Saves for each possible title adornment
+                                # character its level in the current
+                                # document.
+                                # This is for over-underline adornments.
+    msgHandler: TMsgHandler     # How to handle errors.
+    findFile: TFindFileHandler  # How to find files.
+
+  PSharedState = ref TSharedState
+  TRstParser = object of RootObj
+    idx*: int
+    tok*: TTokenSeq
+    s*: PSharedState
+    indentStack*: seq[int]
+    filename*: string
+    line*, col*: int
+    hasToc*: bool
+
+  EParseError* = object of ValueError
+
+proc whichMsgClass*(k: TMsgKind): TMsgClass =
+  ## returns which message class `k` belongs to.
+  case ($k)[1]
+  of 'e', 'E': result = mcError
+  of 'w', 'W': result = mcWarning
+  of 'h', 'H': result = mcHint
+  else: assert false, "msgkind does not fit naming scheme"
+
+proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
+                        arg: string) {.procvar.} =
+  let mc = msgkind.whichMsgClass
+  let a = messages[msgkind] % arg
+  let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a]
+  if mc == mcError: raise newException(EParseError, message)
+  else: writeln(stdout, message)
+
+proc defaultFindFile*(filename: string): string {.procvar.} =
+  if existsFile(filename): result = filename
+  else: result = ""
+
+proc newSharedState(options: TRstParseOptions,
+                    findFile: TFindFileHandler,
+                    msgHandler: TMsgHandler): PSharedState =
+  new(result)
+  result.subs = @[]
+  result.refs = @[]
+  result.options = options
+  result.msgHandler = if not isNil(msgHandler): msgHandler else: defaultMsgHandler
+  result.findFile = if not isNil(findFile): findFile else: defaultFindFile
+
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string) =
+  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
+                             p.col + p.tok[p.idx].col, msgKind, arg)
+
+proc rstMessage(p: TRstParser, msgKind: TMsgKind, arg: string, line, col: int) =
+  p.s.msgHandler(p.filename, p.line + line,
+                             p.col + col, msgKind, arg)
+
+proc rstMessage(p: TRstParser, msgKind: TMsgKind) =
+  p.s.msgHandler(p.filename, p.line + p.tok[p.idx].line,
+                             p.col + p.tok[p.idx].col, msgKind,
+                             p.tok[p.idx].symbol)
+
+when false:
+  proc corrupt(p: TRstParser) =
+    assert p.indentStack[0] == 0
+    for i in 1 .. high(p.indentStack): assert p.indentStack[i] < 1_000
+
+proc currInd(p: TRstParser): int =
+  result = p.indentStack[high(p.indentStack)]
+
+proc pushInd(p: var TRstParser, ind: int) =
+  add(p.indentStack, ind)
+
+proc popInd(p: var TRstParser) =
+  if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
+
+proc initParser(p: var TRstParser, sharedState: PSharedState) =
+  p.indentStack = @[0]
+  p.tok = @[]
+  p.idx = 0
+  p.filename = ""
+  p.hasToc = false
+  p.col = 0
+  p.line = 1
+  p.s = sharedState
+
+proc addNodesAux(n: PRstNode, result: var string) =
+  if n.kind == rnLeaf:
+    add(result, n.text)
+  else:
+    for i in countup(0, len(n) - 1): addNodesAux(n.sons[i], result)
+
+proc addNodes(n: PRstNode): string =
+  result = ""
+  addNodesAux(n, result)
+
+proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
+  if n.kind == rnLeaf:
+    for i in countup(0, len(n.text) - 1):
+      case n.text[i]
+      of '0'..'9':
+        if b:
+          add(r, '-')
+          b = false
+        if len(r) == 0: add(r, 'Z')
+        add(r, n.text[i])
+      of 'a'..'z':
+        if b:
+          add(r, '-')
+          b = false
+        add(r, n.text[i])
+      of 'A'..'Z':
+        if b:
+          add(r, '-')
+          b = false
+        add(r, chr(ord(n.text[i]) - ord('A') + ord('a')))
+      else:
+        if (len(r) > 0): b = true
+  else:
+    for i in countup(0, len(n) - 1): rstnodeToRefnameAux(n.sons[i], r, b)
+
+proc rstnodeToRefname(n: PRstNode): string =
+  result = ""
+  var b = false
+  rstnodeToRefnameAux(n, result, b)
+
+proc findSub(p: var TRstParser, n: PRstNode): int =
+  var key = addNodes(n)
+  # the spec says: if no exact match, try one without case distinction:
+  for i in countup(0, high(p.s.subs)):
+    if key == p.s.subs[i].key:
+      return i
+  for i in countup(0, high(p.s.subs)):
+    if cmpIgnoreStyle(key, p.s.subs[i].key) == 0:
+      return i
+  result = -1
+
+proc setSub(p: var TRstParser, key: string, value: PRstNode) =
+  var length = len(p.s.subs)
+  for i in countup(0, length - 1):
+    if key == p.s.subs[i].key:
+      p.s.subs[i].value = value
+      return
+  setLen(p.s.subs, length + 1)
+  p.s.subs[length].key = key
+  p.s.subs[length].value = value
+
+proc setRef(p: var TRstParser, key: string, value: PRstNode) =
+  var length = len(p.s.refs)
+  for i in countup(0, length - 1):
+    if key == p.s.refs[i].key:
+      if p.s.refs[i].value.addNodes != value.addNodes:
+        rstMessage(p, mwRedefinitionOfLabel, key)
+
+      p.s.refs[i].value = value
+      return
+  setLen(p.s.refs, length + 1)
+  p.s.refs[length].key = key
+  p.s.refs[length].value = value
+
+proc findRef(p: var TRstParser, key: string): PRstNode =
+  for i in countup(0, high(p.s.refs)):
+    if key == p.s.refs[i].key:
+      return p.s.refs[i].value
+
+proc newLeaf(p: var TRstParser): PRstNode =
+  result = newRstNode(rnLeaf, p.tok[p.idx].symbol)
+
+proc getReferenceName(p: var TRstParser, endStr: string): PRstNode =
+  var res = newRstNode(rnInner)
+  while true:
+    case p.tok[p.idx].kind
+    of tkWord, tkOther, tkWhite:
+      add(res, newLeaf(p))
+    of tkPunct:
+      if p.tok[p.idx].symbol == endStr:
+        inc(p.idx)
+        break
+      else:
+        add(res, newLeaf(p))
+    else:
+      rstMessage(p, meExpected, endStr)
+      break
+    inc(p.idx)
+  result = res
+
+proc untilEol(p: var TRstParser): PRstNode =
+  result = newRstNode(rnInner)
+  while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+    add(result, newLeaf(p))
+    inc(p.idx)
+
+proc expect(p: var TRstParser, tok: string) =
+  if p.tok[p.idx].symbol == tok: inc(p.idx)
+  else: rstMessage(p, meExpected, tok)
+
+proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
+  result = p.tok[p.idx].symbol == markup
+  if not result:
+    return                    # Rule 3:
+  result = not (p.tok[p.idx - 1].kind in {tkIndent, tkWhite})
+  if not result:
+    return                    # Rule 4:
+  result = (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof}) or
+      (p.tok[p.idx + 1].symbol[0] in
+      {'\'', '\"', ')', ']', '}', '>', '-', '/', '\\', ':', '.', ',', ';', '!',
+       '?', '_'})
+  if not result:
+    return                    # Rule 7:
+  if p.idx > 0:
+    if (markup != "``") and (p.tok[p.idx - 1].symbol == "\\"):
+      result = false
+
+proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
+  var d: char
+  result = p.tok[p.idx].symbol == markup
+  if not result:
+    return                    # Rule 1:
+  result = (p.idx == 0) or (p.tok[p.idx - 1].kind in {tkIndent, tkWhite}) or
+      (p.tok[p.idx - 1].symbol[0] in
+      {'\'', '\"', '(', '[', '{', '<', '-', '/', ':', '_'})
+  if not result:
+    return                    # Rule 2:
+  result = not (p.tok[p.idx + 1].kind in {tkIndent, tkWhite, tkEof})
+  if not result:
+    return                    # Rule 5 & 7:
+  if p.idx > 0:
+    if p.tok[p.idx - 1].symbol == "\\":
+      result = false
+    else:
+      var c = p.tok[p.idx - 1].symbol[0]
+      case c
+      of '\'', '\"': d = c
+      of '(': d = ')'
+      of '[': d = ']'
+      of '{': d = '}'
+      of '<': d = '>'
+      else: d = '\0'
+      if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
+
+proc match(p: TRstParser, start: int, expr: string): bool =
+  # regular expressions are:
+  # special char     exact match
+  # 'w'              tkWord
+  # ' '              tkWhite
+  # 'a'              tkAdornment
+  # 'i'              tkIndent
+  # 'p'              tkPunct
+  # 'T'              always true
+  # 'E'              whitespace, indent or eof
+  # 'e'              tkWord or '#' (for enumeration lists)
+  var i = 0
+  var j = start
+  var last = len(expr) - 1
+  while i <= last:
+    case expr[i]
+    of 'w': result = p.tok[j].kind == tkWord
+    of ' ': result = p.tok[j].kind == tkWhite
+    of 'i': result = p.tok[j].kind == tkIndent
+    of 'p': result = p.tok[j].kind == tkPunct
+    of 'a': result = p.tok[j].kind == tkAdornment
+    of 'o': result = p.tok[j].kind == tkOther
+    of 'T': result = true
+    of 'E': result = p.tok[j].kind in {tkEof, tkWhite, tkIndent}
+    of 'e':
+      result = (p.tok[j].kind == tkWord) or (p.tok[j].symbol == "#")
+      if result:
+        case p.tok[j].symbol[0]
+        of 'a'..'z', 'A'..'Z': result = len(p.tok[j].symbol) == 1
+        of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'})
+        else: discard
+    else:
+      var c = expr[i]
+      var length = 0
+      while (i <= last) and (expr[i] == c):
+        inc(i)
+        inc(length)
+      dec(i)
+      result = (p.tok[j].kind in {tkPunct, tkAdornment}) and
+          (len(p.tok[j].symbol) == length) and (p.tok[j].symbol[0] == c)
+    if not result: return
+    inc(j)
+    inc(i)
+  result = true
+
+proc fixupEmbeddedRef(n, a, b: PRstNode) =
+  var sep = - 1
+  for i in countdown(len(n) - 2, 0):
+    if n.sons[i].text == "<":
+      sep = i
+      break
+  var incr = if (sep > 0) and (n.sons[sep - 1].text[0] == ' '): 2 else: 1
+  for i in countup(0, sep - incr): add(a, n.sons[i])
+  for i in countup(sep + 1, len(n) - 2): add(b, n.sons[i])
+
+proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
+  result = n
+  if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
+    inc(p.idx)
+    if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">":
+      var a = newRstNode(rnInner)
+      var b = newRstNode(rnInner)
+      fixupEmbeddedRef(n, a, b)
+      if len(a) == 0:
+        result = newRstNode(rnStandaloneHyperlink)
+        add(result, b)
+      else:
+        result = newRstNode(rnHyperlink)
+        add(result, a)
+        add(result, b)
+        setRef(p, rstnodeToRefname(a), b)
+    elif n.kind == rnInterpretedText:
+      n.kind = rnRef
+    else:
+      result = newRstNode(rnRef)
+      add(result, n)
+  elif match(p, p.idx, ":w:"):
+    # a role:
+    if p.tok[p.idx + 1].symbol == "idx":
+      n.kind = rnIdx
+    elif p.tok[p.idx + 1].symbol == "literal":
+      n.kind = rnInlineLiteral
+    elif p.tok[p.idx + 1].symbol == "strong":
+      n.kind = rnStrongEmphasis
+    elif p.tok[p.idx + 1].symbol == "emphasis":
+      n.kind = rnEmphasis
+    elif (p.tok[p.idx + 1].symbol == "sub") or
+        (p.tok[p.idx + 1].symbol == "subscript"):
+      n.kind = rnSub
+    elif (p.tok[p.idx + 1].symbol == "sup") or
+        (p.tok[p.idx + 1].symbol == "supscript"):
+      n.kind = rnSup
+    else:
+      result = newRstNode(rnGeneralRole)
+      n.kind = rnInner
+      add(result, n)
+      add(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
+    inc(p.idx, 3)
+
+proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
+  result = start
+  var j = 0
+  while j < expr.len and result < p.tok.len and
+        continuesWith(expr, p.tok[result].symbol, j):
+    inc j, p.tok[result].symbol.len
+    inc result
+  if j < expr.len: result = 0
+
+proc parseSmiley(p: var TRstParser): PRstNode =
+  if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
+  for key, val in items(Smilies):
+    let m = matchVerbatim(p, p.idx, key)
+    if m > 0:
+      p.idx = m
+      result = newRstNode(rnSmiley)
+      result.text = val
+      return
+
+when false:
+  const
+    urlChars = {'A'..'Z', 'a'..'z', '0'..'9', ':', '#', '@', '%', '/', ';',
+                 '$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&',
+                 '\128'..'\255'}
+
+proc isUrl(p: TRstParser, i: int): bool =
+  result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
+    (p.tok[i+3].kind == tkWord) and
+    (p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
+
+proc parseUrl(p: var TRstParser, father: PRstNode) =
+  #if p.tok[p.idx].symbol[strStart] == '<':
+  if isUrl(p, p.idx):
+    var n = newRstNode(rnStandaloneHyperlink)
+    while true:
+      case p.tok[p.idx].kind
+      of tkWord, tkAdornment, tkOther: discard
+      of tkPunct:
+        if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
+          break
+      else: break
+      add(n, newLeaf(p))
+      inc(p.idx)
+    add(father, n)
+  else:
+    var n = newLeaf(p)
+    inc(p.idx)
+    if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
+    add(father, n)
+
+proc parseBackslash(p: var TRstParser, father: PRstNode) =
+  assert(p.tok[p.idx].kind == tkPunct)
+  if p.tok[p.idx].symbol == "\\\\":
+    add(father, newRstNode(rnLeaf, "\\"))
+    inc(p.idx)
+  elif p.tok[p.idx].symbol == "\\":
+    # XXX: Unicode?
+    inc(p.idx)
+    if p.tok[p.idx].kind != tkWhite: add(father, newLeaf(p))
+    if p.tok[p.idx].kind != tkEof: inc(p.idx)
+  else:
+    add(father, newLeaf(p))
+    inc(p.idx)
+
+when false:
+  proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
+    if not verbatim and isURL(p, p.idx):
+      var n = newRstNode(rnStandaloneHyperlink)
+      while true:
+        case p.tok[p.idx].kind
+        of tkWord, tkAdornment, tkOther: nil
+        of tkPunct:
+          if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
+            break
+        else: break
+        add(n, newLeaf(p))
+        inc(p.idx)
+      add(father, n)
+    elif not verbatim and roSupportSmilies in p.sharedState.options:
+      let n = parseSmiley(p)
+      if s != nil:
+        add(father, n)
+    else:
+      var n = newLeaf(p)
+      inc(p.idx)
+      if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
+      add(father, n)
+
+proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
+                interpretBackslash: bool) =
+  let
+    line = p.tok[p.idx].line
+    col = p.tok[p.idx].col
+  inc p.idx
+  while true:
+    case p.tok[p.idx].kind
+    of tkPunct:
+      if isInlineMarkupEnd(p, postfix):
+        inc(p.idx)
+        break
+      elif interpretBackslash:
+        parseBackslash(p, father)
+      else:
+        add(father, newLeaf(p))
+        inc(p.idx)
+    of tkAdornment, tkWord, tkOther:
+      add(father, newLeaf(p))
+      inc(p.idx)
+    of tkIndent:
+      add(father, newRstNode(rnLeaf, " "))
+      inc(p.idx)
+      if p.tok[p.idx].kind == tkIndent:
+        rstMessage(p, meExpected, postfix, line, col)
+        break
+    of tkWhite:
+      add(father, newRstNode(rnLeaf, " "))
+      inc(p.idx)
+    else: rstMessage(p, meExpected, postfix, line, col)
+
+proc parseMarkdownCodeblock(p: var TRstParser): PRstNode =
+  var args = newRstNode(rnDirArg)
+  if p.tok[p.idx].kind == tkWord:
+    add(args, newLeaf(p))
+    inc(p.idx)
+  else:
+    args = nil
+  var n = newRstNode(rnLeaf, "")
+  while true:
+    case p.tok[p.idx].kind
+    of tkEof:
+      rstMessage(p, meExpected, "```")
+      break
+    of tkPunct:
+      if p.tok[p.idx].symbol == "```":
+        inc(p.idx)
+        break
+      else:
+        add(n.text, p.tok[p.idx].symbol)
+        inc(p.idx)
+    else:
+      add(n.text, p.tok[p.idx].symbol)
+      inc(p.idx)
+  var lb = newRstNode(rnLiteralBlock)
+  add(lb, n)
+  result = newRstNode(rnCodeBlock)
+  add(result, args)
+  add(result, nil)
+  add(result, lb)
+
+proc parseInline(p: var TRstParser, father: PRstNode) =
+  case p.tok[p.idx].kind
+  of tkPunct:
+    if isInlineMarkupStart(p, "***"):
+      var n = newRstNode(rnTripleEmphasis)
+      parseUntil(p, n, "***", true)
+      add(father, n)
+    elif isInlineMarkupStart(p, "**"):
+      var n = newRstNode(rnStrongEmphasis)
+      parseUntil(p, n, "**", true)
+      add(father, n)
+    elif isInlineMarkupStart(p, "*"):
+      var n = newRstNode(rnEmphasis)
+      parseUntil(p, n, "*", true)
+      add(father, n)
+    elif roSupportMarkdown in p.s.options and p.tok[p.idx].symbol == "```":
+      inc(p.idx)
+      add(father, parseMarkdownCodeblock(p))
+    elif isInlineMarkupStart(p, "``"):
+      var n = newRstNode(rnInlineLiteral)
+      parseUntil(p, n, "``", false)
+      add(father, n)
+    elif isInlineMarkupStart(p, "`"):
+      var n = newRstNode(rnInterpretedText)
+      parseUntil(p, n, "`", true)
+      n = parsePostfix(p, n)
+      add(father, n)
+    elif isInlineMarkupStart(p, "|"):
+      var n = newRstNode(rnSubstitutionReferences)
+      parseUntil(p, n, "|", false)
+      add(father, n)
+    else:
+      if roSupportSmilies in p.s.options:
+        let n = parseSmiley(p)
+        if n != nil:
+          add(father, n)
+          return
+      parseBackslash(p, father)
+  of tkWord:
+    if roSupportSmilies in p.s.options:
+      let n = parseSmiley(p)
+      if n != nil:
+        add(father, n)
+        return
+    parseUrl(p, father)
+  of tkAdornment, tkOther, tkWhite:
+    if roSupportSmilies in p.s.options:
+      let n = parseSmiley(p)
+      if n != nil:
+        add(father, n)
+        return
+    add(father, newLeaf(p))
+    inc(p.idx)
+  else: discard
+
+proc getDirective(p: var TRstParser): string =
+  if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
+    var j = p.idx
+    inc(p.idx)
+    result = p.tok[p.idx].symbol
+    inc(p.idx)
+    while p.tok[p.idx].kind in {tkWord, tkPunct, tkAdornment, tkOther}:
+      if p.tok[p.idx].symbol == "::": break
+      add(result, p.tok[p.idx].symbol)
+      inc(p.idx)
+    if p.tok[p.idx].kind == tkWhite: inc(p.idx)
+    if p.tok[p.idx].symbol == "::":
+      inc(p.idx)
+      if (p.tok[p.idx].kind == tkWhite): inc(p.idx)
+    else:
+      p.idx = j               # set back
+      result = ""             # error
+  else:
+    result = ""
+
+proc parseComment(p: var TRstParser): PRstNode =
+  case p.tok[p.idx].kind
+  of tkIndent, tkEof:
+    if p.tok[p.idx].kind != tkEof and p.tok[p.idx + 1].kind == tkIndent:
+      inc(p.idx)              # empty comment
+    else:
+      var indent = p.tok[p.idx].ival
+      while true:
+        case p.tok[p.idx].kind
+        of tkEof:
+          break
+        of tkIndent:
+          if (p.tok[p.idx].ival < indent): break
+        else:
+          discard
+        inc(p.idx)
+  else:
+    while p.tok[p.idx].kind notin {tkIndent, tkEof}: inc(p.idx)
+  result = nil
+
+type
+  TDirKind = enum             # must be ordered alphabetically!
+    dkNone, dkAuthor, dkAuthors, dkCode, dkCodeBlock, dkContainer, dkContents,
+    dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
+
+const
+  DirIds: array[0..12, string] = ["", "author", "authors", "code",
+    "code-block", "container", "contents", "figure", "image", "include",
+    "index", "raw", "title"]
+
+proc getDirKind(s: string): TDirKind =
+  let i = find(DirIds, s)
+  if i >= 0: result = TDirKind(i)
+  else: result = dkNone
+
+proc parseLine(p: var TRstParser, father: PRstNode) =
+  while true:
+    case p.tok[p.idx].kind
+    of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
+    else: break
+
+proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
+  while true:
+    case p.tok[p.idx].kind
+    of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
+    of tkEof, tkIndent: break
+
+proc parseSection(p: var TRstParser, result: PRstNode) {.gcsafe.}
+proc parseField(p: var TRstParser): PRstNode =
+  ## Returns a parsed rnField node.
+  ##
+  ## rnField nodes have two children nodes, a rnFieldName and a rnFieldBody.
+  result = newRstNode(rnField)
+  var col = p.tok[p.idx].col
+  var fieldname = newRstNode(rnFieldName)
+  parseUntil(p, fieldname, ":", false)
+  var fieldbody = newRstNode(rnFieldBody)
+  if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody)
+  if p.tok[p.idx].kind == tkIndent:
+    var indent = p.tok[p.idx].ival
+    if indent > col:
+      pushInd(p, indent)
+      parseSection(p, fieldbody)
+      popInd(p)
+  add(result, fieldname)
+  add(result, fieldbody)
+
+proc parseFields(p: var TRstParser): PRstNode =
+  ## Parses fields for a section or directive block.
+  ##
+  ## This proc may return nil if the parsing doesn't find anything of value,
+  ## otherwise it will return a node of rnFieldList type with children.
+  result = nil
+  var atStart = p.idx == 0 and p.tok[0].symbol == ":"
+  if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx + 1].symbol == ":") or
+      atStart:
+    var col = if atStart: p.tok[p.idx].col else: p.tok[p.idx].ival
+    result = newRstNode(rnFieldList)
+    if not atStart: inc(p.idx)
+    while true:
+      add(result, parseField(p))
+      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
+          (p.tok[p.idx + 1].symbol == ":"):
+        inc(p.idx)
+      else:
+        break
+
+proc getFieldValue*(n: PRstNode): string =
+  ## Returns the value of a specific ``rnField`` node.
+  ##
+  ## This proc will assert if the node is not of the expected type. The empty
+  ## string will be returned as a minimum. Any value in the rst will be
+  ## stripped form leading/trailing whitespace.
+  assert n.kind == rnField
+  assert n.len == 2
+  assert n.sons[0].kind == rnFieldName
+  assert n.sons[1].kind == rnFieldBody
+  result = addNodes(n.sons[1]).strip
+
+proc getFieldValue(n: PRstNode, fieldname: string): string =
+  result = ""
+  if n.sons[1] == nil: return
+  if (n.sons[1].kind != rnFieldList):
+    #InternalError("getFieldValue (2): " & $n.sons[1].kind)
+    # We don't like internal errors here anymore as that would break the forum!
+    return
+  for i in countup(0, len(n.sons[1]) - 1):
+    var f = n.sons[1].sons[i]
+    if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
+      result = addNodes(f.sons[1])
+      if result == "": result = "\x01\x01" # indicates that the field exists
+      return
+
+proc getArgument(n: PRstNode): string =
+  if n.sons[0] == nil: result = ""
+  else: result = addNodes(n.sons[0])
+
+proc parseDotDot(p: var TRstParser): PRstNode {.gcsafe.}
+proc parseLiteralBlock(p: var TRstParser): PRstNode =
+  result = newRstNode(rnLiteralBlock)
+  var n = newRstNode(rnLeaf, "")
+  if p.tok[p.idx].kind == tkIndent:
+    var indent = p.tok[p.idx].ival
+    inc(p.idx)
+    while true:
+      case p.tok[p.idx].kind
+      of tkEof:
+        break
+      of tkIndent:
+        if (p.tok[p.idx].ival < indent):
+          break
+        else:
+          add(n.text, "\n")
+          add(n.text, spaces(p.tok[p.idx].ival - indent))
+          inc(p.idx)
+      else:
+        add(n.text, p.tok[p.idx].symbol)
+        inc(p.idx)
+  else:
+    while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+      add(n.text, p.tok[p.idx].symbol)
+      inc(p.idx)
+  add(result, n)
+
+proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
+  if map[c] == 0:
+    inc(lvl)
+    map[c] = lvl
+  result = map[c]
+
+proc tokenAfterNewline(p: TRstParser): int =
+  result = p.idx
+  while true:
+    case p.tok[result].kind
+    of tkEof:
+      break
+    of tkIndent:
+      inc(result)
+      break
+    else: inc(result)
+
+proc isLineBlock(p: TRstParser): bool =
+  var j = tokenAfterNewline(p)
+  result = (p.tok[p.idx].col == p.tok[j].col) and (p.tok[j].symbol == "|") or
+      (p.tok[j].col > p.tok[p.idx].col)
+
+proc predNL(p: TRstParser): bool =
+  result = true
+  if p.idx > 0:
+    result = p.tok[p.idx-1].kind == tkIndent and
+        p.tok[p.idx-1].ival == currInd(p)
+
+proc isDefList(p: TRstParser): bool =
+  var j = tokenAfterNewline(p)
+  result = (p.tok[p.idx].col < p.tok[j].col) and
+      (p.tok[j].kind in {tkWord, tkOther, tkPunct}) and
+      (p.tok[j - 2].symbol != "::")
+
+proc isOptionList(p: TRstParser): bool =
+  result = match(p, p.idx, "-w") or match(p, p.idx, "--w") or
+           match(p, p.idx, "/w") or match(p, p.idx, "//w")
+
+proc whichSection(p: TRstParser): TRstNodeKind =
+  case p.tok[p.idx].kind
+  of tkAdornment:
+    if match(p, p.idx + 1, "ii"): result = rnTransition
+    elif match(p, p.idx + 1, " a"): result = rnTable
+    elif match(p, p.idx + 1, "i"): result = rnOverline
+    else: result = rnLeaf
+  of tkPunct:
+    if match(p, tokenAfterNewline(p), "ai"):
+      result = rnHeadline
+    elif p.tok[p.idx].symbol == "::":
+      result = rnLiteralBlock
+    elif predNL(p) and
+        ((p.tok[p.idx].symbol == "+") or (p.tok[p.idx].symbol == "*") or
+        (p.tok[p.idx].symbol == "-")) and (p.tok[p.idx + 1].kind == tkWhite):
+      result = rnBulletList
+    elif (p.tok[p.idx].symbol == "|") and isLineBlock(p):
+      result = rnLineBlock
+    elif (p.tok[p.idx].symbol == "..") and predNL(p):
+      result = rnDirective
+    elif match(p, p.idx, ":w:") and predNL(p):
+      # (p.tok[p.idx].symbol == ":")
+      result = rnFieldList
+    elif match(p, p.idx, "(e) "):
+      result = rnEnumList
+    elif match(p, p.idx, "+a+"):
+      result = rnGridTable
+      rstMessage(p, meGridTableNotImplemented)
+    elif isDefList(p):
+      result = rnDefList
+    elif isOptionList(p):
+      result = rnOptionList
+    else:
+      result = rnParagraph
+  of tkWord, tkOther, tkWhite:
+    if match(p, tokenAfterNewline(p), "ai"): result = rnHeadline
+    elif match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList
+    elif isDefList(p): result = rnDefList
+    else: result = rnParagraph
+  else: result = rnLeaf
+
+proc parseLineBlock(p: var TRstParser): PRstNode =
+  result = nil
+  if p.tok[p.idx + 1].kind == tkWhite:
+    var col = p.tok[p.idx].col
+    result = newRstNode(rnLineBlock)
+    pushInd(p, p.tok[p.idx + 2].col)
+    inc(p.idx, 2)
+    while true:
+      var item = newRstNode(rnLineBlockItem)
+      parseSection(p, item)
+      add(result, item)
+      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
+          (p.tok[p.idx + 1].symbol == "|") and
+          (p.tok[p.idx + 2].kind == tkWhite):
+        inc(p.idx, 3)
+      else:
+        break
+    popInd(p)
+
+proc parseParagraph(p: var TRstParser, result: PRstNode) =
+  while true:
+    case p.tok[p.idx].kind
+    of tkIndent:
+      if p.tok[p.idx + 1].kind == tkIndent:
+        inc(p.idx)
+        break
+      elif (p.tok[p.idx].ival == currInd(p)):
+        inc(p.idx)
+        case whichSection(p)
+        of rnParagraph, rnLeaf, rnHeadline, rnOverline, rnDirective:
+          add(result, newRstNode(rnLeaf, " "))
+        of rnLineBlock:
+          addIfNotNil(result, parseLineBlock(p))
+        else: break
+      else:
+        break
+    of tkPunct:
+      if (p.tok[p.idx].symbol == "::") and
+          (p.tok[p.idx + 1].kind == tkIndent) and
+          (currInd(p) < p.tok[p.idx + 1].ival):
+        add(result, newRstNode(rnLeaf, ":"))
+        inc(p.idx)            # skip '::'
+        add(result, parseLiteralBlock(p))
+        break
+      else:
+        parseInline(p, result)
+    of tkWhite, tkWord, tkAdornment, tkOther:
+      parseInline(p, result)
+    else: break
+
+proc parseHeadline(p: var TRstParser): PRstNode =
+  result = newRstNode(rnHeadline)
+  parseUntilNewline(p, result)
+  assert(p.tok[p.idx].kind == tkIndent)
+  assert(p.tok[p.idx + 1].kind == tkAdornment)
+  var c = p.tok[p.idx + 1].symbol[0]
+  inc(p.idx, 2)
+  result.level = getLevel(p.s.underlineToLevel, p.s.uLevel, c)
+
+type
+  TIntSeq = seq[int]
+
+proc tokEnd(p: TRstParser): int =
+  result = p.tok[p.idx].col + len(p.tok[p.idx].symbol) - 1
+
+proc getColumns(p: var TRstParser, cols: var TIntSeq) =
+  var L = 0
+  while true:
+    inc(L)
+    setLen(cols, L)
+    cols[L - 1] = tokEnd(p)
+    assert(p.tok[p.idx].kind == tkAdornment)
+    inc(p.idx)
+    if p.tok[p.idx].kind != tkWhite: break
+    inc(p.idx)
+    if p.tok[p.idx].kind != tkAdornment: break
+  if p.tok[p.idx].kind == tkIndent: inc(p.idx)
+  # last column has no limit:
+  cols[L - 1] = 32000
+
+proc parseDoc(p: var TRstParser): PRstNode {.gcsafe.}
+
+proc parseSimpleTable(p: var TRstParser): PRstNode =
+  var
+    cols: TIntSeq
+    row: seq[string]
+    i, last, line: int
+    c: char
+    q: TRstParser
+    a, b: PRstNode
+  result = newRstNode(rnTable)
+  cols = @[]
+  row = @[]
+  a = nil
+  c = p.tok[p.idx].symbol[0]
+  while true:
+    if p.tok[p.idx].kind == tkAdornment:
+      last = tokenAfterNewline(p)
+      if p.tok[last].kind in {tkEof, tkIndent}:
+        # skip last adornment line:
+        p.idx = last
+        break
+      getColumns(p, cols)
+      setLen(row, len(cols))
+      if a != nil:
+        for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell
+    if p.tok[p.idx].kind == tkEof: break
+    for j in countup(0, high(row)): row[j] = ""
+    # the following while loop iterates over the lines a single cell may span:
+    line = p.tok[p.idx].line
+    while true:
+      i = 0
+      while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+        if (tokEnd(p) <= cols[i]):
+          add(row[i], p.tok[p.idx].symbol)
+          inc(p.idx)
+        else:
+          if p.tok[p.idx].kind == tkWhite: inc(p.idx)
+          inc(i)
+      if p.tok[p.idx].kind == tkIndent: inc(p.idx)
+      if tokEnd(p) <= cols[0]: break
+      if p.tok[p.idx].kind in {tkEof, tkAdornment}: break
+      for j in countup(1, high(row)): add(row[j], '\x0A')
+    a = newRstNode(rnTableRow)
+    for j in countup(0, high(row)):
+      initParser(q, p.s)
+      q.col = cols[j]
+      q.line = line - 1
+      q.filename = p.filename
+      q.col += getTokens(row[j], false, q.tok)
+      b = newRstNode(rnTableDataCell)
+      add(b, parseDoc(q))
+      add(a, b)
+    add(result, a)
+
+proc parseTransition(p: var TRstParser): PRstNode =
+  result = newRstNode(rnTransition)
+  inc(p.idx)
+  if p.tok[p.idx].kind == tkIndent: inc(p.idx)
+  if p.tok[p.idx].kind == tkIndent: inc(p.idx)
+
+proc parseOverline(p: var TRstParser): PRstNode =
+  var c = p.tok[p.idx].symbol[0]
+  inc(p.idx, 2)
+  result = newRstNode(rnOverline)
+  while true:
+    parseUntilNewline(p, result)
+    if p.tok[p.idx].kind == tkIndent:
+      inc(p.idx)
+      if p.tok[p.idx - 1].ival > currInd(p):
+        add(result, newRstNode(rnLeaf, " "))
+      else:
+        break
+    else:
+      break
+  result.level = getLevel(p.s.overlineToLevel, p.s.oLevel, c)
+  if p.tok[p.idx].kind == tkAdornment:
+    inc(p.idx)                # XXX: check?
+    if p.tok[p.idx].kind == tkIndent: inc(p.idx)
+
+proc parseBulletList(p: var TRstParser): PRstNode =
+  result = nil
+  if p.tok[p.idx + 1].kind == tkWhite:
+    var bullet = p.tok[p.idx].symbol
+    var col = p.tok[p.idx].col
+    result = newRstNode(rnBulletList)
+    pushInd(p, p.tok[p.idx + 2].col)
+    inc(p.idx, 2)
+    while true:
+      var item = newRstNode(rnBulletItem)
+      parseSection(p, item)
+      add(result, item)
+      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
+          (p.tok[p.idx + 1].symbol == bullet) and
+          (p.tok[p.idx + 2].kind == tkWhite):
+        inc(p.idx, 3)
+      else:
+        break
+    popInd(p)
+
+proc parseOptionList(p: var TRstParser): PRstNode =
+  result = newRstNode(rnOptionList)
+  while true:
+    if isOptionList(p):
+      var a = newRstNode(rnOptionGroup)
+      var b = newRstNode(rnDescription)
+      var c = newRstNode(rnOptionListItem)
+      if match(p, p.idx, "//w"): inc(p.idx)
+      while not (p.tok[p.idx].kind in {tkIndent, tkEof}):
+        if (p.tok[p.idx].kind == tkWhite) and (len(p.tok[p.idx].symbol) > 1):
+          inc(p.idx)
+          break
+        add(a, newLeaf(p))
+        inc(p.idx)
+      var j = tokenAfterNewline(p)
+      if (j > 0) and (p.tok[j - 1].kind == tkIndent) and
+          (p.tok[j - 1].ival > currInd(p)):
+        pushInd(p, p.tok[j - 1].ival)
+        parseSection(p, b)
+        popInd(p)
+      else:
+        parseLine(p, b)
+      if (p.tok[p.idx].kind == tkIndent): inc(p.idx)
+      add(c, a)
+      add(c, b)
+      add(result, c)
+    else:
+      break
+
+proc parseDefinitionList(p: var TRstParser): PRstNode =
+  result = nil
+  var j = tokenAfterNewline(p) - 1
+  if (j >= 1) and (p.tok[j].kind == tkIndent) and
+      (p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
+    var col = p.tok[p.idx].col
+    result = newRstNode(rnDefList)
+    while true:
+      j = p.idx
+      var a = newRstNode(rnDefName)
+      parseLine(p, a)
+      if (p.tok[p.idx].kind == tkIndent) and
+          (p.tok[p.idx].ival > currInd(p)) and
+          (p.tok[p.idx + 1].symbol != "::") and
+          not (p.tok[p.idx + 1].kind in {tkIndent, tkEof}):
+        pushInd(p, p.tok[p.idx].ival)
+        var b = newRstNode(rnDefBody)
+        parseSection(p, b)
+        var c = newRstNode(rnDefItem)
+        add(c, a)
+        add(c, b)
+        add(result, c)
+        popInd(p)
+      else:
+        p.idx = j
+        break
+      if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col):
+        inc(p.idx)
+        j = tokenAfterNewline(p) - 1
+        if j >= 1 and p.tok[j].kind == tkIndent and p.tok[j].ival > col and
+            p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent:
+          discard
+        else:
+          break
+    if len(result) == 0: result = nil
+
+proc parseEnumList(p: var TRstParser): PRstNode =
+  const
+    wildcards: array[0..2, string] = ["(e) ", "e) ", "e. "]
+    wildpos: array[0..2, int] = [1, 0, 0]
+  result = nil
+  var w = 0
+  while w <= 2:
+    if match(p, p.idx, wildcards[w]): break
+    inc(w)
+  if w <= 2:
+    var col = p.tok[p.idx].col
+    result = newRstNode(rnEnumList)
+    inc(p.idx, wildpos[w] + 3)
+    var j = tokenAfterNewline(p)
+    if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
+      pushInd(p, p.tok[p.idx].col)
+      while true:
+        var item = newRstNode(rnEnumItem)
+        parseSection(p, item)
+        add(result, item)
+        if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col) and
+            match(p, p.idx + 1, wildcards[w]):
+          inc(p.idx, wildpos[w] + 4)
+        else:
+          break
+      popInd(p)
+    else:
+      dec(p.idx, wildpos[w] + 3)
+      result = nil
+
+proc sonKind(father: PRstNode, i: int): TRstNodeKind =
+  result = rnLeaf
+  if i < len(father): result = father.sons[i].kind
+
+proc parseSection(p: var TRstParser, result: PRstNode) =
+  while true:
+    var leave = false
+    assert(p.idx >= 0)
+    while p.tok[p.idx].kind == tkIndent:
+      if currInd(p) == p.tok[p.idx].ival:
+        inc(p.idx)
+      elif p.tok[p.idx].ival > currInd(p):
+        pushInd(p, p.tok[p.idx].ival)
+        var a = newRstNode(rnBlockQuote)
+        parseSection(p, a)
+        add(result, a)
+        popInd(p)
+      else:
+        leave = true
+        break
+    if leave or p.tok[p.idx].kind == tkEof: break
+    var a: PRstNode = nil
+    var k = whichSection(p)
+    case k
+    of rnLiteralBlock:
+      inc(p.idx)              # skip '::'
+      a = parseLiteralBlock(p)
+    of rnBulletList: a = parseBulletList(p)
+    of rnLineBlock: a = parseLineBlock(p)
+    of rnDirective: a = parseDotDot(p)
+    of rnEnumList: a = parseEnumList(p)
+    of rnLeaf: rstMessage(p, meNewSectionExpected)
+    of rnParagraph: discard
+    of rnDefList: a = parseDefinitionList(p)
+    of rnFieldList:
+      if p.idx > 0: dec(p.idx)
+      a = parseFields(p)
+    of rnTransition: a = parseTransition(p)
+    of rnHeadline: a = parseHeadline(p)
+    of rnOverline: a = parseOverline(p)
+    of rnTable: a = parseSimpleTable(p)
+    of rnOptionList: a = parseOptionList(p)
+    else:
+      #InternalError("rst.parseSection()")
+      discard
+    if a == nil and k != rnDirective:
+      a = newRstNode(rnParagraph)
+      parseParagraph(p, a)
+    addIfNotNil(result, a)
+  if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
+    result.sons[0].kind = rnInner
+
+proc parseSectionWrapper(p: var TRstParser): PRstNode =
+  result = newRstNode(rnInner)
+  parseSection(p, result)
+  while (result.kind == rnInner) and (len(result) == 1):
+    result = result.sons[0]
+
+proc `$`(t: TToken): string =
+  result = $t.kind & ' ' & (if isNil(t.symbol): "NIL" else: t.symbol)
+
+proc parseDoc(p: var TRstParser): PRstNode =
+  result = parseSectionWrapper(p)
+  if p.tok[p.idx].kind != tkEof:
+    when false:
+      assert isAllocatedPtr(cast[pointer](p.tok))
+      for i in 0 .. high(p.tok):
+        assert isNil(p.tok[i].symbol) or
+               isAllocatedPtr(cast[pointer](p.tok[i].symbol))
+      echo "index: ", p.idx, " length: ", high(p.tok), "##",
+          p.tok[p.idx-1], p.tok[p.idx], p.tok[p.idx+1]
+    #assert isAllocatedPtr(cast[pointer](p.indentStack))
+    rstMessage(p, meGeneralParseError)
+
+type
+  TDirFlag = enum
+    hasArg, hasOptions, argIsFile, argIsWord
+  TDirFlags = set[TDirFlag]
+  TSectionParser = proc (p: var TRstParser): PRstNode {.nimcall.}
+
+proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
+  ## Parses arguments and options for a directive block.
+  ##
+  ## A directive block will always have three sons: the arguments for the
+  ## directive (rnDirArg), the options (rnFieldList) and the block
+  ## (rnLineBlock). This proc parses the two first nodes, the block is left to
+  ## the outer `parseDirective` call.
+  ##
+  ## Both rnDirArg and rnFieldList children nodes might be nil, so you need to
+  ## check them before accessing.
+  result = newRstNode(rnDirective)
+  var args: PRstNode = nil
+  var options: PRstNode = nil
+  if hasArg in flags:
+    args = newRstNode(rnDirArg)
+    if argIsFile in flags:
+      while true:
+        case p.tok[p.idx].kind
+        of tkWord, tkOther, tkPunct, tkAdornment:
+          add(args, newLeaf(p))
+          inc(p.idx)
+        else: break
+    elif argIsWord in flags:
+      while p.tok[p.idx].kind == tkWhite: inc(p.idx)
+      if p.tok[p.idx].kind == tkWord:
+        add(args, newLeaf(p))
+        inc(p.idx)
+      else:
+        args = nil
+    else:
+      parseLine(p, args)
+  add(result, args)
+  if hasOptions in flags:
+    if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival >= 3) and
+        (p.tok[p.idx + 1].symbol == ":"):
+      options = parseFields(p)
+  add(result, options)
+
+proc indFollows(p: TRstParser): bool =
+  result = p.tok[p.idx].kind == tkIndent and p.tok[p.idx].ival > currInd(p)
+
+proc parseDirective(p: var TRstParser, flags: TDirFlags,
+                    contentParser: TSectionParser): PRstNode =
+  ## Returns a generic rnDirective tree.
+  ##
+  ## The children are rnDirArg, rnFieldList and rnLineBlock. Any might be nil.
+  result = parseDirective(p, flags)
+  if not isNil(contentParser) and indFollows(p):
+    pushInd(p, p.tok[p.idx].ival)
+    var content = contentParser(p)
+    popInd(p)
+    add(result, content)
+  else:
+    add(result, nil)
+
+proc parseDirBody(p: var TRstParser, contentParser: TSectionParser): PRstNode =
+  if indFollows(p):
+    pushInd(p, p.tok[p.idx].ival)
+    result = contentParser(p)
+    popInd(p)
+
+proc dirInclude(p: var TRstParser): PRstNode =
+  #
+  #The following options are recognized:
+  #
+  #start-after : text to find in the external data file
+  #    Only the content after the first occurrence of the specified text will
+  #    be included.
+  #end-before : text to find in the external data file
+  #    Only the content before the first occurrence of the specified text
+  #    (but after any after text) will be included.
+  #literal : flag (empty)
+  #    The entire included text is inserted into the document as a single
+  #    literal block (useful for program listings).
+  #encoding : name of text encoding
+  #    The text encoding of the external data file. Defaults to the document's
+  #    encoding (if specified).
+  #
+  result = nil
+  var n = parseDirective(p, {hasArg, argIsFile, hasOptions}, nil)
+  var filename = strip(addNodes(n.sons[0]))
+  var path = p.s.findFile(filename)
+  if path == "":
+    rstMessage(p, meCannotOpenFile, filename)
+  else:
+    # XXX: error handling; recursive file inclusion!
+    if getFieldValue(n, "literal") != "":
+      result = newRstNode(rnLiteralBlock)
+      add(result, newRstNode(rnLeaf, readFile(path)))
+    else:
+      var q: TRstParser
+      initParser(q, p.s)
+      q.filename = filename
+      q.col += getTokens(readFile(path), false, q.tok)
+      # workaround a GCC bug; more like the interior pointer bug?
+      #if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
+      #  InternalError("Too many binary zeros in include file")
+      result = parseDoc(q)
+
+proc dirCodeBlock(p: var TRstParser, nimrodExtension = false): PRstNode =
+  ## Parses a code block.
+  ##
+  ## Code blocks are rnDirective trees with a `kind` of rnCodeBlock. See the
+  ## description of ``parseDirective`` for further structure information.
+  ##
+  ## Code blocks can come in two forms, the standard `code directive
+  ## <http://docutils.sourceforge.net/docs/ref/rst/directives.html#code>`_ and
+  ## the nimrod extension ``.. code-block::``. If the block is an extension, we
+  ## want the default language syntax highlighting to be Nimrod, so we create a
+  ## fake internal field to comminicate with the generator. The field is named
+  ## ``default-language``, which is unlikely to collide with a field specified
+  ## by any random rst input file.
+  ##
+  ## As an extension this proc will process the ``file`` extension field and if
+  ## present will replace the code block with the contents of the referenced
+  ## file.
+  result = parseDirective(p, {hasArg, hasOptions}, parseLiteralBlock)
+  var filename = strip(getFieldValue(result, "file"))
+  if filename != "":
+    var path = p.s.findFile(filename)
+    if path == "": rstMessage(p, meCannotOpenFile, filename)
+    var n = newRstNode(rnLiteralBlock)
+    add(n, newRstNode(rnLeaf, readFile(path)))
+    result.sons[2] = n
+
+  # Extend the field block if we are using our custom extension.
+  if nimrodExtension:
+    # Create a field block if the input block didn't have any.
+    if result.sons[1].isNil: result.sons[1] = newRstNode(rnFieldList)
+    assert result.sons[1].kind == rnFieldList
+    # Hook the extra field and specify the Nimrod language as value.
+    var extraNode = newRstNode(rnField)
+    extraNode.add(newRstNode(rnFieldName))
+    extraNode.add(newRstNode(rnFieldBody))
+    extraNode.sons[0].add(newRstNode(rnLeaf, "default-language"))
+    extraNode.sons[1].add(newRstNode(rnLeaf, "Nimrod"))
+    result.sons[1].add(extraNode)
+
+  result.kind = rnCodeBlock
+
+proc dirContainer(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasArg}, parseSectionWrapper)
+  assert(result.kind == rnDirective)
+  assert(len(result) == 3)
+  result.kind = rnContainer
+
+proc dirImage(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasOptions, hasArg, argIsFile}, nil)
+  result.kind = rnImage
+
+proc dirFigure(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasOptions, hasArg, argIsFile},
+                          parseSectionWrapper)
+  result.kind = rnFigure
+
+proc dirTitle(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasArg}, nil)
+  result.kind = rnTitle
+
+proc dirContents(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {hasArg}, nil)
+  result.kind = rnContents
+
+proc dirIndex(p: var TRstParser): PRstNode =
+  result = parseDirective(p, {}, parseSectionWrapper)
+  result.kind = rnIndex
+
+proc dirRawAux(p: var TRstParser, result: var PRstNode, kind: TRstNodeKind,
+               contentParser: TSectionParser) =
+  var filename = getFieldValue(result, "file")
+  if filename.len > 0:
+    var path = p.s.findFile(filename)
+    if path.len == 0:
+      rstMessage(p, meCannotOpenFile, filename)
+    else:
+      var f = readFile(path)
+      result = newRstNode(kind)
+      add(result, newRstNode(rnLeaf, f))
+  else:
+    result.kind = kind
+    add(result, parseDirBody(p, contentParser))
+
+proc dirRaw(p: var TRstParser): PRstNode =
+  #
+  #The following options are recognized:
+  #
+  #file : string (newlines removed)
+  #    The local filesystem path of a raw data file to be included.
+  #
+  # html
+  # latex
+  result = parseDirective(p, {hasOptions, hasArg, argIsWord})
+  if result.sons[0] != nil:
+    if cmpIgnoreCase(result.sons[0].sons[0].text, "html") == 0:
+      dirRawAux(p, result, rnRawHtml, parseLiteralBlock)
+    elif cmpIgnoreCase(result.sons[0].sons[0].text, "latex") == 0:
+      dirRawAux(p, result, rnRawLatex, parseLiteralBlock)
+    else:
+      rstMessage(p, meInvalidDirective, result.sons[0].sons[0].text)
+  else:
+    dirRawAux(p, result, rnRaw, parseSectionWrapper)
+
+proc parseDotDot(p: var TRstParser): PRstNode =
+  result = nil
+  var col = p.tok[p.idx].col
+  inc(p.idx)
+  var d = getDirective(p)
+  if d != "":
+    pushInd(p, col)
+    case getDirKind(d)
+    of dkInclude: result = dirInclude(p)
+    of dkImage: result = dirImage(p)
+    of dkFigure: result = dirFigure(p)
+    of dkTitle: result = dirTitle(p)
+    of dkContainer: result = dirContainer(p)
+    of dkContents: result = dirContents(p)
+    of dkRaw:
+      if roSupportRawDirective in p.s.options:
+        result = dirRaw(p)
+      else:
+        rstMessage(p, meInvalidDirective, d)
+    of dkCode: result = dirCodeBlock(p)
+    of dkCodeBlock: result = dirCodeBlock(p, nimrodExtension = true)
+    of dkIndex: result = dirIndex(p)
+    else: rstMessage(p, meInvalidDirective, d)
+    popInd(p)
+  elif match(p, p.idx, " _"):
+    # hyperlink target:
+    inc(p.idx, 2)
+    var a = getReferenceName(p, ":")
+    if p.tok[p.idx].kind == tkWhite: inc(p.idx)
+    var b = untilEol(p)
+    setRef(p, rstnodeToRefname(a), b)
+  elif match(p, p.idx, " |"):
+    # substitution definitions:
+    inc(p.idx, 2)
+    var a = getReferenceName(p, "|")
+    var b: PRstNode
+    if p.tok[p.idx].kind == tkWhite: inc(p.idx)
+    if cmpIgnoreStyle(p.tok[p.idx].symbol, "replace") == 0:
+      inc(p.idx)
+      expect(p, "::")
+      b = untilEol(p)
+    elif cmpIgnoreStyle(p.tok[p.idx].symbol, "image") == 0:
+      inc(p.idx)
+      b = dirImage(p)
+    else:
+      rstMessage(p, meInvalidDirective, p.tok[p.idx].symbol)
+    setSub(p, addNodes(a), b)
+  elif match(p, p.idx, " ["):
+    # footnotes, citations
+    inc(p.idx, 2)
+    var a = getReferenceName(p, "]")
+    if p.tok[p.idx].kind == tkWhite: inc(p.idx)
+    var b = untilEol(p)
+    setRef(p, rstnodeToRefname(a), b)
+  else:
+    result = parseComment(p)
+
+proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
+  result = n
+  if n == nil: return
+  case n.kind
+  of rnSubstitutionReferences:
+    var x = findSub(p, n)
+    if x >= 0:
+      result = p.s.subs[x].value
+    else:
+      var key = addNodes(n)
+      var e = getEnv(key)
+      if e != "": result = newRstNode(rnLeaf, e)
+      else: rstMessage(p, mwUnknownSubstitution, key)
+  of rnRef:
+    var y = findRef(p, rstnodeToRefname(n))
+    if y != nil:
+      result = newRstNode(rnHyperlink)
+      n.kind = rnInner
+      add(result, n)
+      add(result, y)
+  of rnLeaf:
+    discard
+  of rnContents:
+    p.hasToc = true
+  else:
+    for i in countup(0, len(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
+
+proc rstParse*(text, filename: string,
+               line, column: int, hasToc: var bool,
+               options: TRstParseOptions,
+               findFile: TFindFileHandler = nil,
+               msgHandler: TMsgHandler = nil): PRstNode =
+  var p: TRstParser
+  initParser(p, newSharedState(options, findFile, msgHandler))
+  p.filename = filename
+  p.line = line
+  p.col = column + getTokens(text, roSkipPounds in options, p.tok)
+  result = resolveSubs(p, parseDoc(p))
+  hasToc = p.hasToc
diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim
new file mode 100644
index 000000000..c3956ab8b
--- /dev/null
+++ b/lib/packages/docutils/rstast.nim
@@ -0,0 +1,313 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements an AST for the `reStructuredText`:idx: parser.
+
+import strutils, json
+
+type
+  TRstNodeKind* = enum        ## the possible node kinds of an PRstNode
+    rnInner,                  # an inner node or a root
+    rnHeadline,               # a headline
+    rnOverline,               # an over- and underlined headline
+    rnTransition,             # a transition (the ------------- <hr> thingie)
+    rnParagraph,              # a paragraph
+    rnBulletList,             # a bullet list
+    rnBulletItem,             # a bullet item
+    rnEnumList,               # an enumerated list
+    rnEnumItem,               # an enumerated item
+    rnDefList,                # a definition list
+    rnDefItem,                # an item of a definition list consisting of ...
+    rnDefName,                # ... a name part ...
+    rnDefBody,                # ... and a body part ...
+    rnFieldList,              # a field list
+    rnField,                  # a field item
+    rnFieldName,              # consisting of a field name ...
+    rnFieldBody,              # ... and a field body
+    rnOptionList, rnOptionListItem, rnOptionGroup, rnOption, rnOptionString,
+    rnOptionArgument, rnDescription, rnLiteralBlock, rnQuotedLiteralBlock,
+    rnLineBlock,              # the | thingie
+    rnLineBlockItem,          # sons of the | thing
+    rnBlockQuote,             # text just indented
+    rnTable, rnGridTable, rnTableRow, rnTableHeaderCell, rnTableDataCell,
+    rnLabel,                  # used for footnotes and other things
+    rnFootnote,               # a footnote
+    rnCitation,               # similar to footnote
+    rnStandaloneHyperlink, rnHyperlink, rnRef, rnDirective, # a directive
+    rnDirArg, rnRaw, rnTitle, rnContents, rnImage, rnFigure, rnCodeBlock,
+    rnRawHtml, rnRawLatex,
+    rnContainer,              # ``container`` directive
+    rnIndex,                  # index directve:
+                              # .. index::
+                              #   key
+                              #     * `file#id <file#id>`_
+                              #     * `file#id <file#id>'_
+    rnSubstitutionDef,        # a definition of a substitution
+    rnGeneralRole,            # Inline markup:
+    rnSub, rnSup, rnIdx,
+    rnEmphasis,               # "*"
+    rnStrongEmphasis,         # "**"
+    rnTripleEmphasis,         # "***"
+    rnInterpretedText,        # "`"
+    rnInlineLiteral,          # "``"
+    rnSubstitutionReferences, # "|"
+    rnSmiley,                 # some smiley
+    rnLeaf                    # a leaf; the node's text field contains the
+                              # leaf val
+
+
+  PRstNode* = ref TRstNode    ## an RST node
+  TRstNodeSeq* = seq[PRstNode]
+  TRstNode* {.acyclic, final.} = object ## an RST node's description
+    kind*: TRstNodeKind       ## the node's kind
+    text*: string             ## valid for leafs in the AST; and the title of
+                              ## the document or the section
+    level*: int               ## valid for some node kinds
+    sons*: TRstNodeSeq        ## the node's sons
+
+proc len*(n: PRstNode): int =
+  result = len(n.sons)
+
+proc newRstNode*(kind: TRstNodeKind): PRstNode =
+  new(result)
+  result.sons = @[]
+  result.kind = kind
+
+proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode =
+  result = newRstNode(kind)
+  result.text = s
+
+proc lastSon*(n: PRstNode): PRstNode =
+  result = n.sons[len(n.sons)-1]
+
+proc add*(father, son: PRstNode) =
+  add(father.sons, son)
+
+proc addIfNotNil*(father, son: PRstNode) =
+  if son != nil: add(father, son)
+
+
+type
+  TRenderContext {.pure.} = object
+    indent: int
+    verbatim: int
+
+proc renderRstToRst(d: var TRenderContext, n: PRstNode,
+                    result: var string) {.gcsafe.}
+
+proc renderRstSons(d: var TRenderContext, n: PRstNode, result: var string) =
+  for i in countup(0, len(n) - 1):
+    renderRstToRst(d, n.sons[i], result)
+
+proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
+  # this is needed for the index generation; it may also be useful for
+  # debugging, but most code is already debugged...
+  const
+    lvlToChar: array[0..8, char] = ['!', '=', '-', '~', '`', '<', '*', '|', '+']
+  if n == nil: return
+  var ind = spaces(d.indent)
+  case n.kind
+  of rnInner:
+    renderRstSons(d, n, result)
+  of rnHeadline:
+    result.add("\n")
+    result.add(ind)
+
+    let oldLen = result.len
+    renderRstSons(d, n, result)
+    let headlineLen = result.len - oldLen
+
+    result.add("\n")
+    result.add(ind)
+    result.add repeat(lvlToChar[n.level], headlineLen)
+  of rnOverline:
+    result.add("\n")
+    result.add(ind)
+
+    var headline = ""
+    renderRstSons(d, n, headline)
+
+    let lvl = repeat(lvlToChar[n.level], headline.len - d.indent)
+    result.add(lvl)
+    result.add("\n")
+    result.add(headline)
+
+    result.add("\n")
+    result.add(ind)
+    result.add(lvl)
+  of rnTransition:
+    result.add("\n\n")
+    result.add(ind)
+    result.add repeat('-', 78-d.indent)
+    result.add("\n\n")
+  of rnParagraph:
+    result.add("\n\n")
+    result.add(ind)
+    renderRstSons(d, n, result)
+  of rnBulletItem:
+    inc(d.indent, 2)
+    var tmp = ""
+    renderRstSons(d, n, tmp)
+    if tmp.len > 0:
+      result.add("\n")
+      result.add(ind)
+      result.add("* ")
+      result.add(tmp)
+    dec(d.indent, 2)
+  of rnEnumItem:
+    inc(d.indent, 4)
+    var tmp = ""
+    renderRstSons(d, n, tmp)
+    if tmp.len > 0:
+      result.add("\n")
+      result.add(ind)
+      result.add("(#) ")
+      result.add(tmp)
+    dec(d.indent, 4)
+  of rnOptionList, rnFieldList, rnDefList, rnDefItem, rnLineBlock, rnFieldName,
+     rnFieldBody, rnStandaloneHyperlink, rnBulletList, rnEnumList:
+    renderRstSons(d, n, result)
+  of rnDefName:
+    result.add("\n\n")
+    result.add(ind)
+    renderRstSons(d, n, result)
+  of rnDefBody:
+    inc(d.indent, 2)
+    if n.sons[0].kind != rnBulletList:
+      result.add("\n")
+      result.add(ind)
+      result.add("  ")
+    renderRstSons(d, n, result)
+    dec(d.indent, 2)
+  of rnField:
+    var tmp = ""
+    renderRstToRst(d, n.sons[0], tmp)
+
+    var L = max(tmp.len + 3, 30)
+    inc(d.indent, L)
+
+    result.add "\n"
+    result.add ind
+    result.add ':'
+    result.add tmp
+    result.add ':'
+    result.add spaces(L - tmp.len - 2)
+    renderRstToRst(d, n.sons[1], result)
+
+    dec(d.indent, L)
+  of rnLineBlockItem:
+    result.add("\n")
+    result.add(ind)
+    result.add("| ")
+    renderRstSons(d, n, result)
+  of rnBlockQuote:
+    inc(d.indent, 2)
+    renderRstSons(d, n, result)
+    dec(d.indent, 2)
+  of rnRef:
+    result.add("`")
+    renderRstSons(d, n, result)
+    result.add("`_")
+  of rnHyperlink:
+    result.add('`')
+    renderRstToRst(d, n.sons[0], result)
+    result.add(" <")
+    renderRstToRst(d, n.sons[1], result)
+    result.add(">`_")
+  of rnGeneralRole:
+    result.add('`')
+    renderRstToRst(d, n.sons[0],result)
+    result.add("`:")
+    renderRstToRst(d, n.sons[1],result)
+    result.add(':')
+  of rnSub:
+    result.add('`')
+    renderRstSons(d, n, result)
+    result.add("`:sub:")
+  of rnSup:
+    result.add('`')
+    renderRstSons(d, n, result)
+    result.add("`:sup:")
+  of rnIdx:
+    result.add('`')
+    renderRstSons(d, n, result)
+    result.add("`:idx:")
+  of rnEmphasis:
+    result.add("*")
+    renderRstSons(d, n, result)
+    result.add("*")
+  of rnStrongEmphasis:
+    result.add("**")
+    renderRstSons(d, n, result)
+    result.add("**")
+  of rnTripleEmphasis:
+    result.add("***")
+    renderRstSons(d, n, result)
+    result.add("***")
+  of rnInterpretedText:
+    result.add('`')
+    renderRstSons(d, n, result)
+    result.add('`')
+  of rnInlineLiteral:
+    inc(d.verbatim)
+    result.add("``")
+    renderRstSons(d, n, result)
+    result.add("``")
+    dec(d.verbatim)
+  of rnSmiley:
+    result.add(n.text)
+  of rnLeaf:
+    if d.verbatim == 0 and n.text == "\\":
+      result.add("\\\\") # XXX: escape more special characters!
+    else:
+      result.add(n.text)
+  of rnIndex:
+    result.add("\n\n")
+    result.add(ind)
+    result.add(".. index::\n")
+
+    inc(d.indent, 3)
+    if n.sons[2] != nil: renderRstSons(d, n.sons[2], result)
+    dec(d.indent, 3)
+  of rnContents:
+    result.add("\n\n")
+    result.add(ind)
+    result.add(".. contents::")
+  else:
+    result.add("Error: cannot render: " & $n.kind)
+
+proc renderRstToRst*(n: PRstNode, result: var string) =
+  ## renders `n` into its string representation and appends to `result`.
+  var d: TRenderContext
+  renderRstToRst(d, n, result)
+
+proc renderRstToJsonNode(node: PRstNode): JsonNode =
+  result =
+    %[
+      (key: "kind", val: %($node.kind)),
+      (key: "level", val: %BiggestInt(node.level))
+     ]
+  if node.text != nil:
+    result.add("text", %node.text)
+  if node.sons != nil and len(node.sons) > 0:
+    var accm = newSeq[JsonNode](len(node.sons))
+    for i, son in node.sons:
+      accm[i] = renderRstToJsonNode(son)
+    result.add("sons", %accm)
+
+proc renderRstToJson*(node: PRstNode): string =
+  ## Writes the given RST node as JSON that is in the form
+  ## ::
+  ##   {
+  ##     "kind":string node.kind,
+  ##     "text":optional string node.text,
+  ##     "level":optional int node.level,
+  ##     "sons":optional node array
+  ##   }
+  renderRstToJsonNode(node).pretty
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim
new file mode 100644
index 000000000..9e96d8a63
--- /dev/null
+++ b/lib/packages/docutils/rstgen.nim
@@ -0,0 +1,1256 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a generator of HTML/Latex from
+## `reStructuredText`:idx: (see http://docutils.sourceforge.net/rst.html for
+## information on this markup syntax) and is used by the compiler's `docgen
+## tools <docgen.html>`_.
+##
+## You can generate HTML output through the convenience proc ``rstToHtml``,
+## which provided an input string with rst markup returns a string with the
+## generated HTML. The final output is meant to be embedded inside a full
+## document you provide yourself, so it won't contain the usual ``<header>`` or
+## ``<body>`` parts.
+##
+## You can also create a ``TRstGenerator`` structure and populate it with the
+## other lower level methods to finally build complete documents. This requires
+## many options and tweaking, but you are not limited to snippets and can
+## generate `LaTeX documents <https://en.wikipedia.org/wiki/LaTeX>`_ too.
+
+import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
+  algorithm, parseutils
+
+const
+  HtmlExt = "html"
+  IndexExt* = ".idx"
+
+type
+  TOutputTarget* = enum ## which document type to generate
+    outHtml,            # output is HTML
+    outLatex            # output is Latex
+
+  TTocEntry = object
+    n*: PRstNode
+    refname*, header*: string
+
+  TMetaEnum* = enum
+    metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
+
+  TRstGenerator* = object of RootObj
+    target*: TOutputTarget
+    config*: StringTableRef
+    splitAfter*: int          # split too long entries in the TOC
+    tocPart*: seq[TTocEntry]
+    hasToc*: bool
+    theIndex: string # Contents of the index file to be dumped at the end.
+    options*: TRstParseOptions
+    findFile*: TFindFileHandler
+    msgHandler*: TMsgHandler
+    filename*: string
+    meta*: array[TMetaEnum, string]
+    currentSection: string ## \
+    ## Stores the empty string or the last headline/overline found in the rst
+    ## document, so it can be used as a prettier name for term index generation.
+    seenIndexTerms: Table[string, int] ## \
+    ## Keeps count of same text index terms to generate different identifiers
+    ## for hyperlinks. See renderIndexTerm proc for details.
+
+  PDoc = var TRstGenerator ## Alias to type less.
+
+  CodeBlockParams = object ## Stores code block params.
+    numberLines: bool ## True if the renderer has to show line numbers.
+    startLine: int ## The starting line of the code block, by default 1.
+    langStr: string ## Input string used to specify the language.
+    lang: TSourceLanguage ## Type of highlighting, by default none.
+
+
+proc init(p: var CodeBlockParams) =
+  ## Default initialisation of CodeBlockParams to sane values.
+  p.startLine = 1
+  p.lang = langNone
+  p.langStr = ""
+
+proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
+                       config: StringTableRef, filename: string,
+                       options: TRstParseOptions,
+                       findFile: TFindFileHandler=nil,
+                       msgHandler: TMsgHandler=nil) =
+  ## Initializes a ``TRstGenerator``.
+  ##
+  ## You need to call this before using a ``TRstGenerator`` with any other
+  ## procs in this module. Pass a non ``nil`` ``StringTableRef`` value as
+  ## `config` with parameters used by the HTML output generator.  If you don't
+  ## know what to use, pass the results of the `defaultConfig()
+  ## <#defaultConfig>_` proc.
+  ##
+  ## The `filename` parameter will be used for error reporting and creating
+  ## index hyperlinks to the file, but you can pass an empty string here if you
+  ## are parsing a stream in memory. If `filename` ends with the ``.nim``
+  ## extension, the title for the document will be set by default to ``Module
+  ## filename``.  This default title can be overriden by the embedded rst, but
+  ## it helps to prettify the generated index if no title is found.
+  ##
+  ## The ``TRstParseOptions``, ``TFindFileHandler`` and ``TMsgHandler`` types
+  ## are defined in the the `packages/docutils/rst module <rst.html>`_.
+  ## ``options`` selects the behaviour of the rst parser.
+  ##
+  ## ``findFile`` is a proc used by the rst ``include`` directive among others.
+  ## The purpose of this proc is to mangle or filter paths. It receives paths
+  ## specified in the rst document and has to return a valid path to existing
+  ## files or the empty string otherwise.  If you pass ``nil``, a default proc
+  ## will be used which given a path returns the input path only if the file
+  ## exists. One use for this proc is to transform relative paths found in the
+  ## document to absolute path, useful if the rst file and the resources it
+  ## references are not in the same directory as the current working directory.
+  ##
+  ## The ``msgHandler`` is a proc used for user error reporting. It will be
+  ## called with the filename, line, col, and type of any error found during
+  ## parsing. If you pass ``nil``, a default message handler will be used which
+  ## writes the messages to the standard output.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   import packages/docutils/rstgen
+  ##
+  ##   var gen: TRstGenerator
+  ##   gen.initRstGenerator(outHtml, defaultConfig(), "filename", {})
+  g.config = config
+  g.target = target
+  g.tocPart = @[]
+  g.filename = filename
+  g.splitAfter = 20
+  g.theIndex = ""
+  g.options = options
+  g.findFile = findFile
+  g.currentSection = ""
+  let fileParts = filename.splitFile
+  if fileParts.ext == ".nim":
+    g.currentSection = "Module " & fileParts.name
+  g.seenIndexTerms = initTable[string, int]()
+  g.msgHandler = msgHandler
+
+  let s = config["split.item.toc"]
+  if s != "": g.splitAfter = parseInt(s)
+  for i in low(g.meta)..high(g.meta): g.meta[i] = ""
+
+proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
+  ## Writes the current index buffer to the specified output file.
+  ##
+  ## You previously need to add entries to the index with the `setIndexTerm()
+  ## <#setIndexTerm>`_ proc. If the index is empty the file won't be created.
+  if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
+
+proc addXmlChar(dest: var string, c: char) =
+  case c
+  of '&': add(dest, "&amp;")
+  of '<': add(dest, "&lt;")
+  of '>': add(dest, "&gt;")
+  of '\"': add(dest, "&quot;")
+  else: add(dest, c)
+
+proc addRtfChar(dest: var string, c: char) =
+  case c
+  of '{': add(dest, "\\{")
+  of '}': add(dest, "\\}")
+  of '\\': add(dest, "\\\\")
+  else: add(dest, c)
+
+proc addTexChar(dest: var string, c: char) =
+  case c
+  of '_': add(dest, "\\_")
+  of '{': add(dest, "\\symbol{123}")
+  of '}': add(dest, "\\symbol{125}")
+  of '[': add(dest, "\\symbol{91}")
+  of ']': add(dest, "\\symbol{93}")
+  of '\\': add(dest, "\\symbol{92}")
+  of '$': add(dest, "\\$")
+  of '&': add(dest, "\\&")
+  of '#': add(dest, "\\#")
+  of '%': add(dest, "\\%")
+  of '~': add(dest, "\\symbol{126}")
+  of '@': add(dest, "\\symbol{64}")
+  of '^': add(dest, "\\symbol{94}")
+  of '`': add(dest, "\\symbol{96}")
+  else: add(dest, c)
+
+var splitter*: string = "<wbr />"
+
+proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
+  case target
+  of outHtml:  addXmlChar(dest, c)
+  of outLatex: addTexChar(dest, c)
+
+proc nextSplitPoint*(s: string, start: int): int =
+  result = start
+  while result < len(s) + 0:
+    case s[result]
+    of '_': return
+    of 'a'..'z':
+      if result + 1 < len(s) + 0:
+        if s[result + 1] in {'A'..'Z'}: return
+    else: discard
+    inc(result)
+  dec(result)                 # last valid index
+
+proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
+  result = ""
+  if splitAfter >= 0:
+    var partLen = 0
+    var j = 0
+    while j < len(s):
+      var k = nextSplitPoint(s, j)
+      if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
+        partLen = 0
+        add(result, splitter)
+      for i in countup(j, k): escChar(target, result, s[i])
+      inc(partLen, k - j + 1)
+      j = k + 1
+  else:
+    for i in countup(0, len(s) - 1): escChar(target, result, s[i])
+
+
+proc disp(target: TOutputTarget, xml, tex: string): string =
+  if target != outLatex: result = xml
+  else: result = tex
+
+proc dispF(target: TOutputTarget, xml, tex: string,
+           args: varargs[string]): string =
+  if target != outLatex: result = xml % args
+  else: result = tex % args
+
+proc dispA(target: TOutputTarget, dest: var string,
+           xml, tex: string, args: varargs[string]) =
+  if target != outLatex: addf(dest, xml, args)
+  else: addf(dest, tex, args)
+
+proc `or`(x, y: string): string {.inline.} =
+  result = if x.isNil: y else: x
+
+proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
+  ## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
+  ##
+  ## Before using this proc you need to initialise a ``TRstGenerator`` with
+  ## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the
+  ## `packages/docutils/rst module <rst.html>`_. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   # ...configure gen and rst vars...
+  ##   var generatedHTML = ""
+  ##   renderRstToOut(gen, rst, generatedHTML)
+  ##   echo generatedHTML
+
+proc renderAux(d: PDoc, n: PRstNode, result: var string) =
+  for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
+
+proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
+  var tmp = ""
+  for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], tmp)
+  if d.target != outLatex:
+    result.addf(frmtA, [tmp])
+  else:
+    result.addf(frmtB, [tmp])
+
+# ---------------- index handling --------------------------------------------
+
+proc quoteIndexColumn(text: string): string =
+  ## Returns a safe version of `text` for serialization to the ``.idx`` file.
+  ##
+  ## The returned version can be put without worries in a line based tab
+  ## separated column text file. The following character sequence replacements
+  ## will be performed for that goal:
+  ##
+  ## * ``"\\"`` => ``"\\\\"``
+  ## * ``"\n"`` => ``"\\n"``
+  ## * ``"\t"`` => ``"\\t"``
+  result = text.replace("\\", "\\\\").replace("\n", "\\n").replace("\t", "\\t")
+
+proc unquoteIndexColumn(text: string): string =
+  ## Returns the unquoted version generated by ``quoteIndexColumn``.
+  result = text.replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\")
+
+proc setIndexTerm*(d: var TRstGenerator, id, term: string,
+                   linkTitle, linkDesc = "") =
+  ## Adds a `term` to the index using the specified hyperlink identifier.
+  ##
+  ## A new entry will be added to the index using the format
+  ## ``term<tab>file#id``. The file part will come from the `filename`
+  ## parameter used in a previous call to the `initRstGenerator()
+  ## <#initRstGenerator>`_ proc.
+  ##
+  ## The `id` will be appended with a hash character only if its length is not
+  ## zero, otherwise no specific anchor will be generated. In general you
+  ## should only pass an empty `id` value for the title of standalone rst
+  ## documents (they are special for the `mergeIndexes() <#mergeIndexes>`_
+  ## proc, see `Index (idx) file format <docgen.html#index-idx-file-format>`_
+  ## for more information). Unlike other index terms, title entries are
+  ## inserted at the beginning of the accumulated buffer to maintain a logical
+  ## order of entries.
+  ##
+  ## If `linkTitle` or `linkDesc` are not the empty string, two additional
+  ## columns with their contents will be added.
+  ##
+  ## The index won't be written to disk unless you call `writeIndexFile()
+  ## <#writeIndexFile>`_. The purpose of the index is documented in the `docgen
+  ## tools guide <docgen.html#index-switch>`_.
+  assert(not d.theIndex.isNil)
+  var
+    entry = term
+    isTitle = false
+  entry.add('\t')
+  let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
+  entry.add(htmlFile)
+  if id.len > 0:
+    entry.add('#')
+    entry.add(id)
+  else:
+    isTitle = true
+  if linkTitle.len > 0 or linkDesc.len > 0:
+    entry.add('\t' & linkTitle.quoteIndexColumn)
+    entry.add('\t' & linkDesc.quoteIndexColumn)
+  entry.add("\n")
+
+  if isTitle: d.theIndex.insert(entry)
+  else: d.theIndex.add(entry)
+
+proc hash(n: PRstNode): int =
+  if n.kind == rnLeaf:
+    result = hash(n.text)
+  elif n.len > 0:
+    result = hash(n.sons[0])
+    for i in 1 .. <len(n):
+      result = result !& hash(n.sons[i])
+    result = !$result
+
+proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
+  ## Renders the string decorated within \`foobar\`\:idx\: markers.
+  ##
+  ## Additionally adds the encosed text to the index as a term. Since we are
+  ## interested in different instances of the same term to have different
+  ## entries, a table is used to keep track of the amount of times a term has
+  ## previously appeared to give a different identifier value for each.
+  let refname = n.rstnodeToRefname
+  if d.seenIndexTerms.hasKey(refname):
+    d.seenIndexTerms[refname] = d.seenIndexTerms[refname] + 1
+  else:
+    d.seenIndexTerms[refname] = 1
+  let id = refname & '_' & $d.seenIndexTerms[refname]
+
+  var term = ""
+  renderAux(d, n, term)
+  setIndexTerm(d, id, term, d.currentSection)
+  dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
+        [id, term])
+
+type
+  TIndexEntry = object
+    keyword: string
+    link: string
+    linkTitle: string ## If not nil, contains a prettier text for the href
+    linkDesc: string ## If not nil, the title attribute of the final href
+
+  TIndexedDocs = Table[TIndexEntry, seq[TIndexEntry]] ## \
+    ## Contains the index sequences for doc types.
+    ##
+    ## The key is a *fake* TIndexEntry which will contain the title of the
+    ## document in the `keyword` field and `link` will contain the html
+    ## filename for the document. `linkTitle` and `linkDesc` will be nil.
+    ##
+    ## The value indexed by this TIndexEntry is a sequence with the real index
+    ## entries found in the ``.idx`` file.
+
+
+proc cmp(a, b: TIndexEntry): int =
+  ## Sorts two ``TIndexEntry`` first by `keyword` field, then by `link`.
+  result = cmpIgnoreStyle(a.keyword, b.keyword)
+  if result == 0:
+    result = cmpIgnoreStyle(a.link, b.link)
+
+proc hash(x: TIndexEntry): THash =
+  ## Returns the hash for the combined fields of the type.
+  ##
+  ## The hash is computed as the chained hash of the individual string hashes.
+  assert(not x.keyword.isNil)
+  assert(not x.link.isNil)
+  result = x.keyword.hash !& x.link.hash
+  result = result !& (x.linkTitle or "").hash
+  result = result !& (x.linkDesc or "").hash
+  result = !$result
+
+proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
+  shallowCopy a.keyword, b.keyword
+  shallowCopy a.link, b.link
+  if b.linkTitle.isNil: a.linkTitle = nil
+  else: shallowCopy a.linkTitle, b.linkTitle
+  if b.linkDesc.isNil: a.linkDesc = nil
+  else: shallowCopy a.linkDesc, b.linkDesc
+
+proc sortIndex(a: var openArray[TIndexEntry]) =
+  # we use shellsort here; fast and simple
+  let n = len(a)
+  var h = 1
+  while true:
+    h = 3 * h + 1
+    if h > n: break
+  while true:
+    h = h div 3
+    for i in countup(h, n - 1):
+      var v: TIndexEntry
+      v <- a[i]
+      var j = i
+      while cmp(a[j-h], v) >= 0:
+        a[j] <- a[j-h]
+        j = j-h
+        if j < h: break
+      a[j] <- v
+    if h == 1: break
+
+proc generateSymbolIndex(symbols: seq[TIndexEntry]): string =
+  result = ""
+  var i = 0
+  while i < symbols.len:
+    let keyword= symbols[i].keyword
+    let cleaned_keyword = keyword[1..keyword.high - 1]
+    result.addf("<dt><a name=\"$2\" href=\"#$2\"><span>$1:</span></a></dt><ul class=\"simple\"><dd>\n",
+                [keyword, cleaned_keyword])
+    var j = i
+    while j < symbols.len and keyword == symbols[j].keyword:
+      let
+        url = symbols[j].link
+        text = if not symbols[j].linkTitle.isNil: symbols[j].linkTitle else: url
+        desc = if not symbols[j].linkDesc.isNil: symbols[j].linkDesc else: ""
+      if desc.len > 0:
+        result.addf("""<li><a class="reference external"
+          title="$3" href="$1">$2</a></li>
+          """, [url, text, desc])
+      else:
+        result.addf("""<li><a class="reference external" href="$1">$2</a></li>
+          """, [url, text])
+      inc j
+    result.add("</ul></dd>\n")
+    i = j
+
+proc isDocumentationTitle(hyperlink: string): bool =
+  ## Returns true if the hyperlink is actually a documentation title.
+  ##
+  ## Documentation titles lack the hash. See `mergeIndexes() <#mergeIndexes>`_
+  ## for a more detailed explanation.
+  result = hyperlink.find('#') < 0
+
+proc stripTOCLevel(s: string): tuple[level: int, text: string] =
+  ## Returns the *level* of the toc along with the text without it.
+  for c in 0 .. <s.len:
+    result.level = c
+    if s[c] != ' ': break
+  result.text = s[result.level .. <s.len]
+
+proc indentToLevel(level: var int, newLevel: int): string =
+  ## Returns the sequence of <ul>|</ul> characters to switch to `newLevel`.
+  ##
+  ## The amount of lists added/removed will be based on the `level` variable,
+  ## which will be reset to `newLevel` at the end of the proc.
+  result = ""
+  if level == newLevel:
+    return
+  if newLevel > level:
+    result = repeat("<ul>", newLevel - level)
+  else:
+    result = repeat("</ul>", level - newLevel)
+  level = newLevel
+
+proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
+  ## Returns the sequence of index entries in an HTML hierarchical list.
+  result = ""
+  # Build a list of levels and extracted titles to make processing easier.
+  var
+    titleRef: string
+    levels: seq[tuple[level: int, text: string]]
+    L = 0
+    level = 1
+  levels.newSeq(entries.len)
+  for entry in entries:
+    let (rawLevel, rawText) = stripTOCLevel(entry.linkTitle or entry.keyword)
+    if rawLevel < 1:
+      # This is a normal symbol, push it *inside* one level from the last one.
+      levels[L].level = level + 1
+      # Also, ignore the linkTitle and use directly the keyword.
+      levels[L].text = entry.keyword
+    else:
+      # The level did change, update the level indicator.
+      level = rawLevel
+      levels[L].level = rawLevel
+      levels[L].text = rawText
+    inc L
+
+  # Now generate hierarchical lists based on the precalculated levels.
+  result = "<ul>\n"
+  level = 1
+  L = 0
+  while L < entries.len:
+    let link = entries[L].link
+    if link.isDocumentationTitle:
+      titleRef = link
+    else:
+      result.add(level.indentToLevel(levels[L].level))
+      result.add("<li><a href=\"" & link & "\">" &
+        levels[L].text & "</a>\n")
+    inc L
+  result.add(level.indentToLevel(1) & "</ul>\n")
+  assert(not titleRef.isNil,
+    "Can't use this proc on an API index, docs always have a title entry")
+
+proc generateDocumentationIndex(docs: TIndexedDocs): string =
+  ## Returns all the documentation TOCs in an HTML hierarchical list.
+  result = ""
+
+  # Sort the titles to generate their toc in alphabetical order.
+  var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
+  sort(titles, cmp)
+
+  for title in titles:
+    let tocList = generateDocumentationTOC(docs[title])
+    result.add("<ul><li><a href=\"" &
+      title.link & "\">" & title.keyword & "</a>\n" & tocList & "</ul>\n")
+
+proc generateDocumentationJumps(docs: TIndexedDocs): string =
+  ## Returns a plain list of hyperlinks to documentation TOCs in HTML.
+  result = "Documents: "
+
+  # Sort the titles to generate their toc in alphabetical order.
+  var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
+  sort(titles, cmp)
+
+  var chunks: seq[string] = @[]
+  for title in titles:
+    chunks.add("<a href=\"" & title.link & "\">" & title.keyword & "</a>")
+
+  result.add(chunks.join(", ") & ".<br>")
+
+proc generateModuleJumps(modules: seq[string]): string =
+  ## Returns a plain list of hyperlinks to the list of modules.
+  result = "Modules: "
+
+  var chunks: seq[string] = @[]
+  for name in modules:
+    chunks.add("<a href=\"" & name & ".html\">" & name & "</a>")
+
+  result.add(chunks.join(", ") & ".<br>")
+
+proc readIndexDir(dir: string):
+    tuple[modules: seq[string], symbols: seq[TIndexEntry], docs: TIndexedDocs] =
+  ## Walks `dir` reading ``.idx`` files converting them in TIndexEntry items.
+  ##
+  ## Returns the list of found module names, the list of free symbol entries
+  ## and the different documentation indexes. The list of modules is sorted.
+  ## See the documentation of ``mergeIndexes`` for details.
+  result.modules = @[]
+  result.docs = initTable[TIndexEntry, seq[TIndexEntry]](32)
+  newSeq(result.symbols, 15_000)
+  setLen(result.symbols, 0)
+  var L = 0
+  # Scan index files and build the list of symbols.
+  for kind, path in walkDir(dir):
+    if kind == pcFile and path.endsWith(IndexExt):
+      var
+        fileEntries: seq[TIndexEntry]
+        title: TIndexEntry
+        F = 0
+      newSeq(fileEntries, 500)
+      setLen(fileEntries, 0)
+      for line in lines(path):
+        let s = line.find('\t')
+        if s < 0: continue
+        setLen(fileEntries, F+1)
+        fileEntries[F].keyword = line.substr(0, s-1)
+        fileEntries[F].link = line.substr(s+1)
+        # See if we detect a title, a link without a `#foobar` trailing part.
+        if title.keyword.isNil and fileEntries[F].link.isDocumentationTitle:
+          title.keyword = fileEntries[F].keyword
+          title.link = fileEntries[F].link
+
+        if fileEntries[F].link.find('\t') > 0:
+          let extraCols = fileEntries[F].link.split('\t')
+          fileEntries[F].link = extraCols[0]
+          assert extraCols.len == 3
+          fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
+          fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
+        else:
+          fileEntries[F].linkTitle = nil
+          fileEntries[F].linkDesc = nil
+        inc F
+      # Depending on type add this to the list of symbols or table of APIs.
+      if title.keyword.isNil:
+        for i in 0 .. <F:
+          # Don't add to symbols TOC entries (they start with a whitespace).
+          let toc = fileEntries[i].linkTitle
+          if not toc.isNil and toc.len > 0 and toc[0] == ' ':
+            continue
+          # Ok, non TOC entry, add it.
+          setLen(result.symbols, L + 1)
+          result.symbols[L] = fileEntries[i]
+          inc L
+        result.modules.add(path.splitFile.name)
+      else:
+        # Generate the symbolic anchor for index quickjumps.
+        title.linkTitle = "doc_toc_" & $result.docs.len
+        result.docs[title] = fileEntries
+
+  sort(result.modules, system.cmp)
+
+proc mergeIndexes*(dir: string): string =
+  ## Merges all index files in `dir` and returns the generated index as HTML.
+  ##
+  ## This proc will first scan `dir` for index files with the ``.idx``
+  ## extension previously created by commands like ``nim doc|rst2html``
+  ## which use the ``--index:on`` switch. These index files are the result of
+  ## calls to `setIndexTerm() <#setIndexTerm>`_ and `writeIndexFile()
+  ## <#writeIndexFile>`_, so they are simple tab separated files.
+  ##
+  ## As convention this proc will split index files into two categories:
+  ## documentation and API. API indices will be all joined together into a
+  ## single big sorted index, making the bulk of the final index. This is good
+  ## for API documentation because many symbols are repated in different
+  ## modules. On the other hand, documentation indices are essentially table of
+  ## contents plus a few special markers. These documents will be rendered in a
+  ## separate section which tries to maintain the order and hierarchy of the
+  ## symbols in the index file.
+  ##
+  ## To differentiate between a documentation and API file a convention is
+  ## used: indices which contain one entry without the HTML hash character (#)
+  ## will be considered `documentation`, since this hash-less entry is the
+  ## explicit title of the document.  Indices without this explicit entry will
+  ## be considered `generated API` extracted out of a source ``.nim`` file.
+  ##
+  ## Returns the merged and sorted indices into a single HTML block which can
+  ## be further embedded into nimdoc templates.
+  var (modules, symbols, docs) = readIndexDir(dir)
+  assert(not symbols.isNil)
+
+  result = ""
+  # Generate a quick jump list of documents.
+  if docs.len > 0:
+    result.add(generateDocumentationJumps(docs))
+    result.add("<p />")
+
+  # Generate hyperlinks to all the linked modules.
+  if modules.len > 0:
+    result.add(generateModuleJumps(modules))
+    result.add("<p />")
+
+  # Generate the HTML block with API documents.
+  if docs.len > 0:
+    result.add("<h2>Documentation files</h2>\n")
+    result.add(generateDocumentationIndex(docs))
+
+  # Generate the HTML block with symbols.
+  if symbols.len > 0:
+    sortIndex(symbols)
+    result.add("<h2>API symbols</h2>\n")
+    result.add(generateSymbolIndex(symbols))
+
+
+# ----------------------------------------------------------------------------
+
+proc stripTOCHTML(s: string): string =
+  ## Ugly quick hack to remove HTML tags from TOC titles.
+  ##
+  ## A TTocEntry.header field already contains rendered HTML tags. Instead of
+  ## implementing a proper version of renderRstToOut() which recursively
+  ## renders an rst tree to plain text, we simply remove text found between
+  ## angled brackets. Given the limited possibilities of rst inside TOC titles
+  ## this should be enough.
+  result = s
+  var first = result.find('<')
+  while first >= 0:
+    let last = result.find('>', first)
+    if last < 0:
+      # Abort, since we didn't found a closing angled bracket.
+      return
+    result.delete(first, last)
+    first = result.find('<', first)
+
+proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
+  var tmp = ""
+  for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
+  d.currentSection = tmp
+  # Find the last higher level section for unique reference name
+  var sectionPrefix = ""
+  for i in countdown(d.tocPart.high, 0):
+    let n2 = d.tocPart[i].n
+    if n2.level < n.level:
+      sectionPrefix = rstnodeToRefname(n2) & "-"
+      break
+  var refname = sectionPrefix & rstnodeToRefname(n)
+  if d.hasToc:
+    var length = len(d.tocPart)
+    setLen(d.tocPart, length + 1)
+    d.tocPart[length].refname = refname
+    d.tocPart[length].n = n
+    d.tocPart[length].header = tmp
+
+    dispA(d.target, result, "\n<h$1><a class=\"toc-backref\" " &
+      "id=\"$2\" href=\"#$2\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
+      [$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
+  else:
+    dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
+                            "\\rsth$4{$3}\\label{$2}\n", [
+        $n.level, refname, tmp,
+        $chr(n.level - 1 + ord('A'))])
+
+  # Generate index entry using spaces to indicate TOC level for the output HTML.
+  assert n.level >= 0
+  setIndexTerm(d, refname, tmp.stripTOCHTML,
+    spaces(max(0, n.level)) & tmp)
+
+proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
+  if d.meta[metaTitle].len == 0:
+    for i in countup(0, len(n)-1):
+      renderRstToOut(d, n.sons[i], d.meta[metaTitle])
+    d.currentSection = d.meta[metaTitle]
+  elif d.meta[metaSubtitle].len == 0:
+    for i in countup(0, len(n)-1):
+      renderRstToOut(d, n.sons[i], d.meta[metaSubtitle])
+    d.currentSection = d.meta[metaSubtitle]
+  else:
+    var tmp = ""
+    for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
+    d.currentSection = tmp
+    dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
+                   "\\rstov$4{$3}\\label{$2}\n", [$n.level,
+        rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
+
+
+proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
+  dispA(d.target, result,
+    "<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
+    "\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
+
+proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
+                       result: var string) =
+  var tmp = ""
+  while j <= high(d.tocPart):
+    var a = abs(d.tocPart[j].n.level)
+    if a == lvl:
+      renderTocEntry(d, d.tocPart[j], tmp)
+      inc(j)
+    elif a > lvl:
+      renderTocEntries(d, j, a, tmp)
+    else:
+      break
+  if lvl > 1:
+    dispA(d.target, result, "<ul class=\"simple\">$1</ul>",
+                            "\\begin{enumerate}$1\\end{enumerate}", [tmp])
+  else:
+    result.add(tmp)
+
+proc renderImage(d: PDoc, n: PRstNode, result: var string) =
+  template valid(s): expr =
+    s.len > 0 and allCharsInSet(s, {'/',':','%','_','\\','\128'..'\xFF'} +
+                                   Digits + Letters + WhiteSpace)
+
+  var options = ""
+  var s = getFieldValue(n, "scale")
+  if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
+
+  s = getFieldValue(n, "height")
+  if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
+
+  s = getFieldValue(n, "width")
+  if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
+
+  s = getFieldValue(n, "alt")
+  if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
+
+  s = getFieldValue(n, "align")
+  if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
+
+  if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
+
+  let arg = getArgument(n)
+  if arg.valid:
+    dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
+          [arg, options])
+  if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
+
+proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
+  dispA(d.target, result,
+    """<img src="$1" width="15"
+        height="17" hspace="2" vspace="2" class="smiley" />""",
+    "\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
+
+proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
+  ## Parses useful fields which can appear before a code block.
+  ##
+  ## This supports the special ``default-language`` internal string generated
+  ## by the ``rst`` module to communicate a specific default language.
+  case n.getArgument.toLower
+  of "number-lines":
+    params.numberLines = true
+    # See if the field has a parameter specifying a different line than 1.
+    var number: int
+    if parseInt(n.getFieldValue, number) > 0:
+      params.startLine = number
+  of "file":
+    # The ``file`` option is a Nimrod extension to the official spec, it acts
+    # like it would for other directives like ``raw`` or ``cvs-table``. This
+    # field is dealt with in ``rst.nim`` which replaces the existing block with
+    # the referenced file, so we only need to ignore it here to avoid incorrect
+    # warning messages.
+    discard
+  of "default-language":
+    params.langStr = n.getFieldValue.strip
+    params.lang = params.langStr.getSourceLanguage
+  else:
+    d.msgHandler(d.filename, 1, 0, mwUnsupportedField, n.getArgument)
+
+proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams =
+  ## Iterates over all code block fields and returns processed params.
+  ##
+  ## Also processes the argument of the directive as the default language. This
+  ## is done last so as to override any internal communication field variables.
+  result.init
+  if n.isNil:
+    return
+  assert n.kind == rnCodeBlock
+  assert(not n.sons[2].isNil)
+
+  # Parse the field list for rendering parameters if there are any.
+  if not n.sons[1].isNil:
+    for son in n.sons[1].sons: d.parseCodeBlockField(son, result)
+
+  # Parse the argument and override the language.
+  result.langStr = strip(getArgument(n))
+  if result.langStr != "":
+    result.lang = getSourceLanguage(result.langStr)
+
+proc buildLinesHTMLTable(params: CodeBlockParams, code: string):
+    tuple[beginTable, endTable: string] =
+  ## Returns the necessary tags to start/end a code block in HTML.
+  ##
+  ## If the numberLines has not been used, the tags will default to a simple
+  ## <pre> pair. Otherwise it will build a table and insert an initial column
+  ## with all the line numbers, which requires you to pass the `code` to detect
+  ## how many lines have to be generated (and starting at which point!).
+  if not params.numberLines:
+    result = ("<pre>", "</pre>")
+    return
+
+  var codeLines = 1 + code.strip.countLines
+  assert codeLines > 0
+  result.beginTable = """<table class="line-nums-table"><tbody><tr><td class="blob-line-nums"><pre>"""
+  var line = params.startLine
+  while codeLines > 0:
+    result.beginTable.add($line & "\n")
+    line.inc
+    codeLines.dec
+  result.beginTable.add("</pre></td><td><pre>")
+  result.endTable = "</pre></td></tr></tbody></table>"
+
+proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
+  ## Renders a code block, appending it to `result`.
+  ##
+  ## If the code block uses the ``number-lines`` option, a table will be
+  ## generated with two columns, the first being a list of numbers and the
+  ## second the code block itself. The code block can use syntax highlighting,
+  ## which depends on the directive argument specified by the rst input, and
+  ## may also come from the parser through the internal ``default-language``
+  ## option to differentiate between a plain code block and nimrod's code block
+  ## extension.
+  assert n.kind == rnCodeBlock
+  if n.sons[2] == nil: return
+  var params = d.parseCodeBlockParams(n)
+  var m = n.sons[2].sons[0]
+  assert m.kind == rnLeaf
+
+  let (blockStart, blockEnd) = params.buildLinesHTMLTable(m.text)
+
+  dispA(d.target, result, blockStart, "\\begin{rstpre}\n", [])
+  if params.lang == langNone:
+    if len(params.langStr) > 0:
+      d.msgHandler(d.filename, 1, 0, mwUnsupportedLanguage, params.langStr)
+    for letter in m.text: escChar(d.target, result, letter)
+  else:
+    var g: TGeneralTokenizer
+    initGeneralTokenizer(g, m.text)
+    while true:
+      getNextToken(g, params.lang)
+      case g.kind
+      of gtEof: break
+      of gtNone, gtWhitespace:
+        add(result, substr(m.text, g.start, g.length + g.start - 1))
+      else:
+        dispA(d.target, result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
+          esc(d.target, substr(m.text, g.start, g.length+g.start-1)),
+          tokenClassToStr[g.kind]])
+    deinitGeneralTokenizer(g)
+  dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n")
+
+proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
+  var tmp = ""
+  renderRstToOut(d, n.sons[2], tmp)
+  var arg = strip(getArgument(n))
+  if arg == "":
+    dispA(d.target, result, "<div>$1</div>", "$1", [tmp])
+  else:
+    dispA(d.target, result, "<div class=\"$1\">$2</div>", "$2", [arg, tmp])
+
+proc texColumns(n: PRstNode): string =
+  result = ""
+  for i in countup(1, len(n)): add(result, "|X")
+
+proc renderField(d: PDoc, n: PRstNode, result: var string) =
+  var b = false
+  if d.target == outLatex:
+    var fieldname = addNodes(n.sons[0])
+    var fieldval = esc(d.target, strip(addNodes(n.sons[1])))
+    if cmpIgnoreStyle(fieldname, "author") == 0 or
+       cmpIgnoreStyle(fieldname, "authors") == 0:
+      if d.meta[metaAuthor].len == 0:
+        d.meta[metaAuthor] = fieldval
+        b = true
+    elif cmpIgnoreStyle(fieldname, "version") == 0:
+      if d.meta[metaVersion].len == 0:
+        d.meta[metaVersion] = fieldval
+        b = true
+  if not b:
+    renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
+
+proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
+  if n == nil: return
+  case n.kind
+  of rnInner: renderAux(d, n, result)
+  of rnHeadline: renderHeadline(d, n, result)
+  of rnOverline: renderOverline(d, n, result)
+  of rnTransition: renderAux(d, n, "<hr />\n", "\\hrule\n", result)
+  of rnParagraph: renderAux(d, n, "<p>$1</p>\n", "$1\n\n", result)
+  of rnBulletList:
+    renderAux(d, n, "<ul class=\"simple\">$1</ul>\n",
+                    "\\begin{itemize}$1\\end{itemize}\n", result)
+  of rnBulletItem, rnEnumItem:
+    renderAux(d, n, "<li>$1</li>\n", "\\item $1\n", result)
+  of rnEnumList:
+    renderAux(d, n, "<ol class=\"simple\">$1</ol>\n",
+                    "\\begin{enumerate}$1\\end{enumerate}\n", result)
+  of rnDefList:
+    renderAux(d, n, "<dl class=\"docutils\">$1</dl>\n",
+                       "\\begin{description}$1\\end{description}\n", result)
+  of rnDefItem: renderAux(d, n, result)
+  of rnDefName: renderAux(d, n, "<dt>$1</dt>\n", "\\item[$1] ", result)
+  of rnDefBody: renderAux(d, n, "<dd>$1</dd>\n", "$1\n", result)
+  of rnFieldList:
+    var tmp = ""
+    for i in countup(0, len(n) - 1):
+      renderRstToOut(d, n.sons[i], tmp)
+    if tmp.len != 0:
+      dispA(d.target, result,
+          "<table class=\"docinfo\" frame=\"void\" rules=\"none\">" &
+          "<col class=\"docinfo-name\" />" &
+          "<col class=\"docinfo-content\" />" &
+          "<tbody valign=\"top\">$1" &
+          "</tbody></table>",
+          "\\begin{description}$1\\end{description}\n",
+          [tmp])
+  of rnField: renderField(d, n, result)
+  of rnFieldName:
+    renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
+                    "\\item[$1:]", result)
+  of rnFieldBody:
+    renderAux(d, n, "<td>$1</td>", " $1\n", result)
+  of rnIndex:
+    renderRstToOut(d, n.sons[2], result)
+  of rnOptionList:
+    renderAux(d, n, "<table frame=\"void\">$1</table>",
+      "\\begin{description}\n$1\\end{description}\n", result)
+  of rnOptionListItem:
+    renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
+  of rnOptionGroup:
+    renderAux(d, n, "<th align=\"left\">$1</th>", "\\item[$1]", result)
+  of rnDescription:
+    renderAux(d, n, "<td align=\"left\">$1</td>\n", " $1\n", result)
+  of rnOption, rnOptionString, rnOptionArgument:
+    doAssert false, "renderRstToOut"
+  of rnLiteralBlock:
+    renderAux(d, n, "<pre>$1</pre>\n",
+                    "\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
+  of rnQuotedLiteralBlock:
+    doAssert false, "renderRstToOut"
+  of rnLineBlock:
+    renderAux(d, n, "<p>$1</p>", "$1\n\n", result)
+  of rnLineBlockItem:
+    renderAux(d, n, "$1<br />", "$1\\\\\n", result)
+  of rnBlockQuote:
+    renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
+                    "\\begin{quote}$1\\end{quote}\n", result)
+  of rnTable, rnGridTable:
+    renderAux(d, n,
+      "<table border=\"1\" class=\"docutils\">$1</table>",
+      "\\begin{table}\\begin{rsttab}{" &
+        texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
+  of rnTableRow:
+    if len(n) >= 1:
+      if d.target == outLatex:
+        #var tmp = ""
+        renderRstToOut(d, n.sons[0], result)
+        for i in countup(1, len(n) - 1):
+          result.add(" & ")
+          renderRstToOut(d, n.sons[i], result)
+        result.add("\\\\\n\\hline\n")
+      else:
+        result.add("<tr>")
+        renderAux(d, n, result)
+        result.add("</tr>\n")
+  of rnTableDataCell:
+    renderAux(d, n, "<td>$1</td>", "$1", result)
+  of rnTableHeaderCell:
+    renderAux(d, n, "<th>$1</th>", "\\textbf{$1}", result)
+  of rnLabel:
+    doAssert false, "renderRstToOut" # used for footnotes and other
+  of rnFootnote:
+    doAssert false, "renderRstToOut" # a footnote
+  of rnCitation:
+    doAssert false, "renderRstToOut" # similar to footnote
+  of rnRef:
+    var tmp = ""
+    renderAux(d, n, tmp)
+    dispA(d.target, result,
+      "<a class=\"reference external\" href=\"#$2\">$1</a>",
+      "$1\\ref{$2}", [tmp, rstnodeToRefname(n)])
+  of rnStandaloneHyperlink:
+    renderAux(d, n,
+      "<a class=\"reference external\" href=\"$1\">$1</a>",
+      "\\href{$1}{$1}", result)
+  of rnHyperlink:
+    var tmp0 = ""
+    var tmp1 = ""
+    renderRstToOut(d, n.sons[0], tmp0)
+    renderRstToOut(d, n.sons[1], tmp1)
+    dispA(d.target, result,
+      "<a class=\"reference external\" href=\"$2\">$1</a>",
+      "\\href{$2}{$1}", [tmp0, tmp1])
+  of rnDirArg, rnRaw: renderAux(d, n, result)
+  of rnRawHtml:
+    if d.target != outLatex:
+      result.add addNodes(lastSon(n))
+  of rnRawLatex:
+    if d.target == outLatex:
+      result.add addNodes(lastSon(n))
+
+  of rnImage, rnFigure: renderImage(d, n, result)
+  of rnCodeBlock: renderCodeBlock(d, n, result)
+  of rnContainer: renderContainer(d, n, result)
+  of rnSubstitutionReferences, rnSubstitutionDef:
+    renderAux(d, n, "|$1|", "|$1|", result)
+  of rnDirective:
+    renderAux(d, n, "", "", result)
+  of rnGeneralRole:
+    var tmp0 = ""
+    var tmp1 = ""
+    renderRstToOut(d, n.sons[0], tmp0)
+    renderRstToOut(d, n.sons[1], tmp1)
+    dispA(d.target, result, "<span class=\"$2\">$1</span>", "\\span$2{$1}",
+          [tmp0, tmp1])
+  of rnSub: renderAux(d, n, "<sub>$1</sub>", "\\rstsub{$1}", result)
+  of rnSup: renderAux(d, n, "<sup>$1</sup>", "\\rstsup{$1}", result)
+  of rnEmphasis: renderAux(d, n, "<em>$1</em>", "\\emph{$1}", result)
+  of rnStrongEmphasis:
+    renderAux(d, n, "<strong>$1</strong>", "\\textbf{$1}", result)
+  of rnTripleEmphasis:
+    renderAux(d, n, "<strong><em>$1</em></strong>",
+                    "\\textbf{emph{$1}}", result)
+  of rnInterpretedText:
+    renderAux(d, n, "<cite>$1</cite>", "\\emph{$1}", result)
+  of rnIdx:
+    renderIndexTerm(d, n, result)
+  of rnInlineLiteral:
+    renderAux(d, n,
+      "<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
+      "\\texttt{$1}", result)
+  of rnSmiley: renderSmiley(d, n, result)
+  of rnLeaf: result.add(esc(d.target, n.text))
+  of rnContents: d.hasToc = true
+  of rnTitle:
+    d.meta[metaTitle] = ""
+    renderRstToOut(d, n.sons[0], d.meta[metaTitle])
+
+# -----------------------------------------------------------------------------
+
+proc getVarIdx(varnames: openArray[string], id: string): int =
+  for i in countup(0, high(varnames)):
+    if cmpIgnoreStyle(varnames[i], id) == 0:
+      return i
+  result = -1
+
+proc formatNamedVars*(frmt: string, varnames: openArray[string],
+                      varvalues: openArray[string]): string =
+  var i = 0
+  var L = len(frmt)
+  result = ""
+  var num = 0
+  while i < L:
+    if frmt[i] == '$':
+      inc(i)                  # skip '$'
+      case frmt[i]
+      of '#':
+        add(result, varvalues[num])
+        inc(num)
+        inc(i)
+      of '$':
+        add(result, "$")
+        inc(i)
+      of '0'..'9':
+        var j = 0
+        while true:
+          j = (j * 10) + ord(frmt[i]) - ord('0')
+          inc(i)
+          if i > L-1 or frmt[i] notin {'0'..'9'}: break
+        if j > high(varvalues) + 1:
+          raise newException(ValueError, "invalid index: " & $j)
+        num = j
+        add(result, varvalues[j - 1])
+      of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
+        var id = ""
+        while true:
+          add(id, frmt[i])
+          inc(i)
+          if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
+        var idx = getVarIdx(varnames, id)
+        if idx >= 0:
+          add(result, varvalues[idx])
+        else:
+          raise newException(ValueError, "unknown substitution var: " & id)
+      of '{':
+        var id = ""
+        inc(i)
+        while frmt[i] != '}':
+          if frmt[i] == '\0':
+            raise newException(ValueError, "'}' expected")
+          add(id, frmt[i])
+          inc(i)
+        inc(i)                # skip }
+                              # search for the variable:
+        var idx = getVarIdx(varnames, id)
+        if idx >= 0: add(result, varvalues[idx])
+        else:
+          raise newException(ValueError, "unknown substitution var: " & id)
+      else:
+        raise newException(ValueError, "unknown substitution: $" & $frmt[i])
+    var start = i
+    while i < L:
+      if frmt[i] != '$': inc(i)
+      else: break
+    if i-1 >= start: add(result, substr(frmt, start, i - 1))
+
+
+proc defaultConfig*(): StringTableRef =
+  ## Returns a default configuration for embedded HTML generation.
+  ##
+  ## The returned ``StringTableRef`` contains the parameters used by the HTML
+  ## engine to build the final output. For information on what these parameters
+  ## are and their purpose, please look up the file ``config/nimdoc.cfg``
+  ## bundled with the compiler.
+  ##
+  ## The only difference between the contents of that file and the values
+  ## provided by this proc is the ``doc.file`` variable. The ``doc.file``
+  ## variable of the configuration file contains HTML to build standalone
+  ## pages, while this proc returns just the content for procs like
+  ## ``rstToHtml`` to generate the bare minimum HTML.
+  result = newStringTable(modeStyleInsensitive)
+
+  template setConfigVar(key, val: expr) =
+    result[key] = val
+
+  # If you need to modify these values, it might be worth updating the template
+  # file in config/nimdoc.cfg.
+  setConfigVar("split.item.toc", "20")
+  setConfigVar("doc.section", """
+<div class="section" id="$sectionID">
+<h1><a class="toc-backref" href="#$sectionTitleID">$sectionTitle</a></h1>
+<dl class="item">
+$content
+</dl></div>
+""")
+  setConfigVar("doc.section.toc", """
+<li>
+  <a class="reference" href="#$sectionID" id="$sectionTitleID">$sectionTitle</a>
+  <ul class="simple">
+    $content
+  </ul>
+</li>
+""")
+  setConfigVar("doc.item", """
+<dt id="$itemID"><a name="$itemSymOrIDEnc"></a><pre>$header</pre></dt>
+<dd>
+$desc
+</dd>
+""")
+  setConfigVar("doc.item.toc", """
+  <li><a class="reference" href="#$itemSymOrIDEnc"
+    title="$header_plain">$name</a></li>
+""")
+  setConfigVar("doc.toc", """
+<div class="navigation" id="navigation">
+<ul class="simple">
+$content
+</ul>
+</div>""")
+  setConfigVar("doc.body_toc", """
+$tableofcontents
+<div class="content" id="content">
+$moduledesc
+$content
+</div>
+""")
+  setConfigVar("doc.body_no_toc", "$moduledesc $content")
+  setConfigVar("doc.file", "$content")
+  setConfigVar("doc.smiley_format", "/images/smilies/$1.gif")
+
+# ---------- forum ---------------------------------------------------------
+
+proc rstToHtml*(s: string, options: TRstParseOptions,
+                config: StringTableRef): string =
+  ## Converts an input rst string into embeddable HTML.
+  ##
+  ## This convenience proc parses any input string using rst markup (it doesn't
+  ## have to be a full document!) and returns an embeddable piece of HTML. The
+  ## proc is meant to be used in *online* environments without access to a
+  ## meaningful filesystem, and therefore rst ``include`` like directives won't
+  ## work. For an explanation of the ``config`` parameter see the
+  ## ``initRstGenerator`` proc. Example:
+  ##
+  ## .. code-block:: nim
+  ##   import packages/docutils/rstgen, strtabs
+  ##
+  ##   echo rstToHtml("*Hello* **world**!", {},
+  ##     newStringTable(modeStyleInsensitive))
+  ##   # --> <em>Hello</em> <strong>world</strong>!
+  ##
+  ## If you need to allow the rst ``include`` directive or tweak the generated
+  ## output you have to create your own ``TRstGenerator`` with
+  ## ``initRstGenerator`` and related procs.
+
+  proc myFindFile(filename: string): string =
+    # we don't find any files in online mode:
+    result = ""
+
+  const filen = "input"
+  var d: TRstGenerator
+  initRstGenerator(d, outHtml, config, filen, options, myFindFile,
+                   rst.defaultMsgHandler)
+  var dummyHasToc = false
+  var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
+  result = ""
+  renderRstToOut(d, rst, result)
+
+
+when isMainModule:
+  assert rstToHtml("*Hello* **world**!", {},
+    newStringTable(modeStyleInsensitive)) ==
+    "<em>Hello</em> <strong>world</strong>!"
diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim
new file mode 100644
index 000000000..bc84611a6
--- /dev/null
+++ b/lib/posix/epoll.nim
@@ -0,0 +1,92 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim:on.}
+
+from posix import SocketHandle
+
+const
+  EPOLLIN* = 0x00000001
+  EPOLLPRI* = 0x00000002
+  EPOLLOUT* = 0x00000004
+  EPOLLERR* = 0x00000008
+  EPOLLHUP* = 0x00000010
+  EPOLLRDNORM* = 0x00000040
+  EPOLLRDBAND* = 0x00000080
+  EPOLLWRNORM* = 0x00000100
+  EPOLLWRBAND* = 0x00000200
+  EPOLLMSG* = 0x00000400
+  EPOLLRDHUP* = 0x00002000
+  EPOLLWAKEUP* = 1 shl 29
+  EPOLLONESHOT* = 1 shl 30
+  EPOLLET* = 1 shl 31
+
+# Valid opcodes ( "op" parameter ) to issue to epoll_ctl().
+
+const 
+  EPOLL_CTL_ADD* = 1          # Add a file descriptor to the interface.  
+  EPOLL_CTL_DEL* = 2          # Remove a file descriptor from the interface.  
+  EPOLL_CTL_MOD* = 3          # Change file descriptor epoll_event structure.  
+
+type 
+  epoll_data* {.importc: "union epoll_data", 
+      header: "<sys/epoll.h>", pure, final.} = object # TODO: This is actually a union.
+    #thePtr* {.importc: "ptr".}: pointer
+    fd* {.importc: "fd".}: cint # \
+    #u32*: uint32
+    #u64*: uint64
+
+  epoll_event* {.importc: "struct epoll_event", header: "<sys/epoll.h>", pure, final.} = object 
+    events*: uint32 # Epoll events 
+    data*: epoll_data # User data variable 
+
+proc epoll_create*(size: cint): cint {.importc: "epoll_create", 
+    header: "<sys/epoll.h>".}
+  ## Creates an epoll instance.  Returns an fd for the new instance.
+  ##   The "size" parameter is a hint specifying the number of file
+  ##   descriptors to be associated with the new instance.  The fd
+  ##   returned by epoll_create() should be closed with close().  
+
+proc epoll_create1*(flags: cint): cint {.importc: "epoll_create1", 
+    header: "<sys/epoll.h>".}
+  ## Same as epoll_create but with an FLAGS parameter.  The unused SIZE
+  ##   parameter has been dropped.  
+
+proc epoll_ctl*(epfd: cint; op: cint; fd: cint | SocketHandle; event: ptr epoll_event): cint {.
+    importc: "epoll_ctl", header: "<sys/epoll.h>".}
+  ## Manipulate an epoll instance "epfd". Returns 0 in case of success,
+  ##   -1 in case of error ( the "errno" variable will contain the
+  ##   specific error code ) The "op" parameter is one of the EPOLL_CTL_*
+  ##   constants defined above. The "fd" parameter is the target of the
+  ##   operation. The "event" parameter describes which events the caller
+  ##   is interested in and any associated user data.  
+
+proc epoll_wait*(epfd: cint; events: ptr epoll_event; maxevents: cint; 
+                 timeout: cint): cint {.importc: "epoll_wait", 
+    header: "<sys/epoll.h>".}
+  ## Wait for events on an epoll instance "epfd". Returns the number of
+  ##   triggered events returned in "events" buffer. Or -1 in case of
+  ##   error with the "errno" variable set to the specific error code. The
+  ##   "events" parameter is a buffer that will contain triggered
+  ##   events. The "maxevents" is the maximum number of events to be
+  ##   returned ( usually size of "events" ). The "timeout" parameter
+  ##   specifies the maximum wait time in milliseconds (-1 == infinite).
+  ##
+  ##   This function is a cancellation point and therefore not marked with
+  ##   __THROW.
+
+
+#proc epoll_pwait*(epfd: cint; events: ptr epoll_event; maxevents: cint; 
+#                  timeout: cint; ss: ptr sigset_t): cint {.
+#    importc: "epoll_pwait", header: "<sys/epoll.h>".}
+# Same as epoll_wait, but the thread's signal mask is temporarily
+#   and atomically replaced with the one provided as parameter.
+#
+#   This function is a cancellation point and therefore not marked with
+#   __THROW.  
diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim
new file mode 100644
index 000000000..c6f0633ff
--- /dev/null
+++ b/lib/posix/inotify.nim
@@ -0,0 +1,72 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim:on.}
+
+# Get the platform-dependent flags.  
+# Structure describing an inotify event.  
+type 
+  Tinotify_event*{.pure, final, importc: "struct inotify_event", 
+                   header: "<sys/inotify.h>".} = object 
+    wd*{.importc: "wd".}: cint # Watch descriptor.  
+    mask*{.importc: "mask".}: uint32 # Watch mask.  
+    cookie*{.importc: "cookie".}: uint32 # Cookie to synchronize two events.  
+    len*{.importc: "len".}: uint32 # Length (including NULs) of name.  
+    name*{.importc: "name".}: char # Name.  
+    
+# Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.  
+const 
+  IN_ACCESS* = 0x00000001   # File was accessed.  
+  IN_MODIFY* = 0x00000002   # File was modified.  
+  IN_ATTRIB* = 0x00000004   # Metadata changed.  
+  IN_CLOSE_WRITE* = 0x00000008 # Writtable file was closed.  
+  IN_CLOSE_NOWRITE* = 0x00000010 # Unwrittable file closed.  
+  IN_CLOSE* = (IN_CLOSE_WRITE or IN_CLOSE_NOWRITE) # Close.  
+  IN_OPEN* = 0x00000020     # File was opened.  
+  IN_MOVED_FROM* = 0x00000040 # File was moved from X.  
+  IN_MOVED_TO* = 0x00000080 # File was moved to Y.  
+  IN_MOVE* = (IN_MOVED_FROM or IN_MOVED_TO) # Moves.  
+  IN_CREATE* = 0x00000100   # Subfile was created.  
+  IN_DELETE* = 0x00000200   # Subfile was deleted.  
+  IN_DELETE_SELF* = 0x00000400 # Self was deleted.  
+  IN_MOVE_SELF* = 0x00000800 # Self was moved.  
+# Events sent by the kernel.  
+const 
+  IN_UNMOUNT* = 0x00002000  # Backing fs was unmounted.  
+  IN_Q_OVERFLOW* = 0x00004000 # Event queued overflowed.  
+  IN_IGNORED* = 0x00008000  # File was ignored.   
+# Special flags.  
+const 
+  IN_ONLYDIR* = 0x01000000  # Only watch the path if it is a
+                            #        directory.  
+  IN_DONT_FOLLOW* = 0x02000000 # Do not follow a sym link.  
+  IN_EXCL_UNLINK* = 0x04000000 # Exclude events on unlinked
+                               #        objects.  
+  IN_MASK_ADD* = 0x20000000 # Add to the mask of an already
+                            #        existing watch.  
+  IN_ISDIR* = 0x40000000    # Event occurred against dir.  
+  IN_ONESHOT* = 0x80000000  # Only send event once.  
+# All events which a program can wait on.  
+const 
+  IN_ALL_EVENTS* = (IN_ACCESS or IN_MODIFY or IN_ATTRIB or IN_CLOSE_WRITE or
+      IN_CLOSE_NOWRITE or IN_OPEN or IN_MOVED_FROM or IN_MOVED_TO or
+      IN_CREATE or IN_DELETE or IN_DELETE_SELF or IN_MOVE_SELF)
+# Create and initialize inotify instance.
+proc inotify_init*(): cint{.cdecl, importc: "inotify_init", 
+                            header: "<sys/inotify.h>".}
+# Create and initialize inotify instance.  
+proc inotify_init1*(flags: cint): cint{.cdecl, importc: "inotify_init1", 
+    header: "<sys/inotify.h>".}
+# Add watch of object NAME to inotify instance FD.  Notify about
+#   events specified by MASK.  
+proc inotify_add_watch*(fd: cint; name: cstring; mask: uint32): cint{.
+    cdecl, importc: "inotify_add_watch", header: "<sys/inotify.h>".}
+# Remove the watch specified by WD from the inotify instance FD.  
+proc inotify_rm_watch*(fd: cint; wd: cint): cint{.cdecl, 
+    importc: "inotify_rm_watch", header: "<sys/inotify.h>".}
\ No newline at end of file
diff --git a/lib/posix/linux.nim b/lib/posix/linux.nim
new file mode 100644
index 000000000..be591e29a
--- /dev/null
+++ b/lib/posix/linux.nim
@@ -0,0 +1,28 @@
+{.deadCodeElim:on.}
+
+import posix
+
+const
+  CSIGNAL* = 0x000000FF
+  CLONE_VM* = 0x00000100
+  CLONE_FS* = 0x00000200
+  CLONE_FILES* = 0x00000400
+  CLONE_SIGHAND* = 0x00000800
+  CLONE_PTRACE* = 0x00002000
+  CLONE_VFORK* = 0x00004000
+  CLONE_PARENT* = 0x00008000
+  CLONE_THREAD* = 0x00010000
+  CLONE_NEWNS* = 0x00020000
+  CLONE_SYSVSEM* = 0x00040000
+  CLONE_SETTLS* = 0x00080000
+  CLONE_PARENT_SETTID* = 0x00100000
+  CLONE_CHILD_CLEARTID* = 0x00200000
+  CLONE_DETACHED* = 0x00400000
+  CLONE_UNTRACED* = 0x00800000
+  CLONE_CHILD_SETTID* = 0x01000000
+  CLONE_STOPPED* = 0x02000000
+
+# fn should be of type proc (a2: pointer): void {.cdecl.}
+proc clone*(fn: pointer; child_stack: pointer; flags: cint;
+            arg: pointer; ptid: ptr TPid; tls: pointer; 
+            ctid: ptr TPid): cint {.importc, header: "<sched.h>".}
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
new file mode 100644
index 000000000..0c7b84090
--- /dev/null
+++ b/lib/posix/posix.nim
@@ -0,0 +1,2585 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Until std_arg!!
+# done: ipc, pwd, stat, semaphore, sys/types, sys/utsname, pthread, unistd,
+# statvfs, mman, time, wait, signal, nl_types, sched, spawn, select, ucontext,
+# net/if, sys/socket, sys/uio, netinet/in, netinet/tcp, netdb
+
+## This is a raw POSIX interface module. It does not not provide any
+## convenience: cstrings are used instead of proper Nim strings and
+## return codes indicate errors. If you want exceptions
+## and a proper Nim-like interface, use the OS module or write a wrapper.
+
+## Coding conventions:
+## ALL types are named the same as in the POSIX standard except that they start
+## with 'T' or 'P' (if they are pointers) and without the '_t' suffix to be
+## consistent with Nim conventions. If an identifier is a Nim keyword
+## the \`identifier\` notation is used.
+##
+## This library relies on the header files of your C compiler. The
+## resulting C code will just ``#include <XYZ.h>`` and *not* define the
+## symbols declared here.
+
+{.deadCodeElim:on.}
+
+from times import Time
+
+const
+  hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays
+  hasAioH = defined(linux)
+
+when false:
+  const
+    C_IRUSR = 0c000400 ## Read by owner.
+    C_IWUSR = 0c000200 ## Write by owner.
+    C_IXUSR = 0c000100 ## Execute by owner.
+    C_IRGRP = 0c000040 ## Read by group.
+    C_IWGRP = 0c000020 ## Write by group.
+    C_IXGRP = 0c000010 ## Execute by group.
+    C_IROTH = 0c000004 ## Read by others.
+    C_IWOTH = 0c000002 ## Write by others.
+    C_IXOTH = 0c000001 ## Execute by others.
+    C_ISUID = 0c004000 ## Set user ID.
+    C_ISGID = 0c002000 ## Set group ID.
+    C_ISVTX = 0c001000 ## On directories, restricted deletion flag.
+    C_ISDIR = 0c040000 ## Directory.
+    C_ISFIFO = 0c010000 ##FIFO.
+    C_ISREG = 0c100000 ## Regular file.
+    C_ISBLK = 0c060000 ## Block special.
+    C_ISCHR = 0c020000 ## Character special.
+    C_ISCTG = 0c110000 ## Reserved.
+    C_ISLNK = 0c120000 ## Symbolic link.</p>
+    C_ISSOCK = 0c140000 ## Socket.
+
+const
+  MM_NULLLBL* = nil
+  MM_NULLSEV* = 0
+  MM_NULLMC* = 0
+  MM_NULLTXT* = nil
+  MM_NULLACT* = nil
+  MM_NULLTAG* = nil
+
+  STDERR_FILENO* = 2 ## File number of stderr;
+  STDIN_FILENO* = 0  ## File number of stdin;
+  STDOUT_FILENO* = 1 ## File number of stdout;
+
+  DT_UNKNOWN* = 0 ## Unknown file type.
+  DT_FIFO* = 1    ## Named pipe, or FIFO.
+  DT_CHR* = 2     ## Character device.
+  DT_DIR* = 4     ## Directory.
+  DT_BLK* = 6     ## Block device.
+  DT_REG* = 8     ## Regular file.
+  DT_LNK* = 10    ## Symbolic link.
+  DT_SOCK* = 12   ## UNIX domain socket.
+  DT_WHT* = 14
+
+type
+  TDIR* {.importc: "DIR", header: "<dirent.h>",
+          incompleteStruct.} = object
+    ## A type representing a directory stream.
+
+type
+  SocketHandle* = distinct cint # The type used to represent socket descriptors
+
+{.deprecated: [TSocketHandle: SocketHandle].}
+
+type
+  Tdirent* {.importc: "struct dirent",
+             header: "<dirent.h>", final, pure.} = object ## dirent_t struct
+    d_ino*: Tino  ## File serial number.
+    when defined(linux) or defined(macosx) or defined(bsd):
+      d_reclen*: cshort ## Length of this record. (not POSIX)
+      d_type*: int8 ## Type of file; not supported by all filesystem types.
+                    ## (not POSIX)
+      when defined(linux) or defined(bsd):
+        d_off*: TOff  ## Not an offset. Value that ``telldir()`` would return.
+    d_name*: array [0..255, char] ## Name of entry.
+
+  Tflock* {.importc: "struct flock", final, pure,
+            header: "<fcntl.h>".} = object ## flock type
+    l_type*: cshort   ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.
+    l_whence*: cshort ## Flag for starting offset.
+    l_start*: TOff    ## Relative offset in bytes.
+    l_len*: TOff      ## Size; if 0 then until EOF.
+    l_pid*: TPid      ## Process ID of the process holding the lock;
+                      ## returned with F_GETLK.
+
+  TFTW* {.importc: "struct FTW", header: "<ftw.h>", final, pure.} = object
+    base*: cint
+    level*: cint
+
+  TGlob* {.importc: "glob_t", header: "<glob.h>",
+           final, pure.} = object ## glob_t
+    gl_pathc*: int          ## Count of paths matched by pattern.
+    gl_pathv*: cstringArray ## Pointer to a list of matched pathnames.
+    gl_offs*: int           ## Slots to reserve at the beginning of gl_pathv.
+
+  TGroup* {.importc: "struct group", header: "<grp.h>",
+            final, pure.} = object ## struct group
+    gr_name*: cstring     ## The name of the group.
+    gr_gid*: TGid         ## Numerical group ID.
+    gr_mem*: cstringArray ## Pointer to a null-terminated array of character
+                          ## pointers to member names.
+
+  Ticonv* {.importc: "iconv_t", header: "<iconv.h>", final, pure.} =
+    object ## Identifies the conversion from one codeset to another.
+
+  Tlconv* {.importc: "struct lconv", header: "<locale.h>", final,
+            pure.} = object
+    currency_symbol*: cstring
+    decimal_point*: cstring
+    frac_digits*: char
+    grouping*: cstring
+    int_curr_symbol*: cstring
+    int_frac_digits*: char
+    int_n_cs_precedes*: char
+    int_n_sep_by_space*: char
+    int_n_sign_posn*: char
+    int_p_cs_precedes*: char
+    int_p_sep_by_space*: char
+    int_p_sign_posn*: char
+    mon_decimal_point*: cstring
+    mon_grouping*: cstring
+    mon_thousands_sep*: cstring
+    negative_sign*: cstring
+    n_cs_precedes*: char
+    n_sep_by_space*: char
+    n_sign_posn*: char
+    positive_sign*: cstring
+    p_cs_precedes*: char
+    p_sep_by_space*: char
+    p_sign_posn*: char
+    thousands_sep*: cstring
+
+  TMqd* {.importc: "mqd_t", header: "<mqueue.h>", final, pure.} = object
+  TMqAttr* {.importc: "struct mq_attr",
+             header: "<mqueue.h>",
+             final, pure.} = object ## message queue attribute
+    mq_flags*: int   ## Message queue flags.
+    mq_maxmsg*: int  ## Maximum number of messages.
+    mq_msgsize*: int ## Maximum message size.
+    mq_curmsgs*: int ## Number of messages currently queued.
+
+  TPasswd* {.importc: "struct passwd", header: "<pwd.h>",
+             final, pure.} = object ## struct passwd
+    pw_name*: cstring   ## User's login name.
+    pw_uid*: Tuid       ## Numerical user ID.
+    pw_gid*: TGid       ## Numerical group ID.
+    pw_dir*: cstring    ## Initial working directory.
+    pw_shell*: cstring  ## Program to use as shell.
+
+  Tblkcnt* {.importc: "blkcnt_t", header: "<sys/types.h>".} = int
+    ## used for file block counts
+  Tblksize* {.importc: "blksize_t", header: "<sys/types.h>".} = int
+    ## used for block sizes
+  TClock* {.importc: "clock_t", header: "<sys/types.h>".} = int
+  TClockId* {.importc: "clockid_t", header: "<sys/types.h>".} = int
+  TDev* {.importc: "dev_t", header: "<sys/types.h>".} = int
+  Tfsblkcnt* {.importc: "fsblkcnt_t", header: "<sys/types.h>".} = int
+  Tfsfilcnt* {.importc: "fsfilcnt_t", header: "<sys/types.h>".} = int
+  TGid* {.importc: "gid_t", header: "<sys/types.h>".} = int
+  Tid* {.importc: "id_t", header: "<sys/types.h>".} = int
+  Tino* {.importc: "ino_t", header: "<sys/types.h>".} = int
+  TKey* {.importc: "key_t", header: "<sys/types.h>".} = int
+  TMode* {.importc: "mode_t", header: "<sys/types.h>".} = cint
+  TNlink* {.importc: "nlink_t", header: "<sys/types.h>".} = int
+  TOff* {.importc: "off_t", header: "<sys/types.h>".} = int64
+  TPid* {.importc: "pid_t", header: "<sys/types.h>".} = int
+  Tpthread_attr* {.importc: "pthread_attr_t", header: "<sys/types.h>".} = int
+  Tpthread_barrier* {.importc: "pthread_barrier_t",
+                      header: "<sys/types.h>".} = int
+  Tpthread_barrierattr* {.importc: "pthread_barrierattr_t",
+                          header: "<sys/types.h>".} = int
+  Tpthread_cond* {.importc: "pthread_cond_t", header: "<sys/types.h>".} = int
+  Tpthread_condattr* {.importc: "pthread_condattr_t",
+                       header: "<sys/types.h>".} = int
+  Tpthread_key* {.importc: "pthread_key_t", header: "<sys/types.h>".} = int
+  Tpthread_mutex* {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
+  Tpthread_mutexattr* {.importc: "pthread_mutexattr_t",
+                        header: "<sys/types.h>".} = int
+  Tpthread_once* {.importc: "pthread_once_t", header: "<sys/types.h>".} = int
+  Tpthread_rwlock* {.importc: "pthread_rwlock_t",
+                     header: "<sys/types.h>".} = int
+  Tpthread_rwlockattr* {.importc: "pthread_rwlockattr_t",
+                         header: "<sys/types.h>".} = int
+  Tpthread_spinlock* {.importc: "pthread_spinlock_t",
+                       header: "<sys/types.h>".} = int
+  Tpthread* {.importc: "pthread_t", header: "<sys/types.h>".} = int
+  Tsuseconds* {.importc: "suseconds_t", header: "<sys/types.h>".} = int
+  #Ttime* {.importc: "time_t", header: "<sys/types.h>".} = int
+  Ttimer* {.importc: "timer_t", header: "<sys/types.h>".} = int
+  Ttrace_attr* {.importc: "trace_attr_t", header: "<sys/types.h>".} = int
+  Ttrace_event_id* {.importc: "trace_event_id_t",
+                     header: "<sys/types.h>".} = int
+  Ttrace_event_set* {.importc: "trace_event_set_t",
+                      header: "<sys/types.h>".} = int
+  Ttrace_id* {.importc: "trace_id_t", header: "<sys/types.h>".} = int
+  Tuid* {.importc: "uid_t", header: "<sys/types.h>".} = int
+  Tuseconds* {.importc: "useconds_t", header: "<sys/types.h>".} = int
+
+  Tutsname* {.importc: "struct utsname",
+              header: "<sys/utsname.h>",
+              final, pure.} = object ## struct utsname
+    sysname*,      ## Name of this implementation of the operating system.
+      nodename*,   ## Name of this node within the communications
+                   ## network to which this node is attached, if any.
+      release*,    ## Current release level of this implementation.
+      version*,    ## Current version level of this release.
+      machine*: array [0..255, char] ## Name of the hardware type on which the
+                                     ## system is running.
+
+  TSem* {.importc: "sem_t", header: "<semaphore.h>", final, pure.} = object
+  Tipc_perm* {.importc: "struct ipc_perm",
+               header: "<sys/ipc.h>", final, pure.} = object ## struct ipc_perm
+    uid*: Tuid    ## Owner's user ID.
+    gid*: TGid    ## Owner's group ID.
+    cuid*: Tuid   ## Creator's user ID.
+    cgid*: TGid   ## Creator's group ID.
+    mode*: TMode  ## Read/write permission.
+
+  TStat* {.importc: "struct stat",
+           header: "<sys/stat.h>", final, pure.} = object ## struct stat
+    st_dev*: TDev          ## Device ID of device containing file.
+    st_ino*: Tino          ## File serial number.
+    st_mode*: TMode        ## Mode of file (see below).
+    st_nlink*: TNlink      ## Number of hard links to the file.
+    st_uid*: Tuid          ## User ID of file.
+    st_gid*: TGid          ## Group ID of file.
+    st_rdev*: TDev         ## Device ID (if file is character or block special).
+    st_size*: TOff         ## For regular files, the file size in bytes.
+                           ## For symbolic links, the length in bytes of the
+                           ## pathname contained in the symbolic link.
+                           ## For a shared memory object, the length in bytes.
+                           ## For a typed memory object, the length in bytes.
+                           ## For other file types, the use of this field is
+                           ## unspecified.
+    st_atime*: Time        ## Time of last access.
+    st_mtime*: Time        ## Time of last data modification.
+    st_ctime*: Time        ## Time of last status change.
+    st_blksize*: Tblksize  ## A file system-specific preferred I/O block size
+                           ## for this object. In some file system types, this
+                           ## may vary from file to file.
+    st_blocks*: Tblkcnt    ## Number of blocks allocated for this object.
+
+
+  TStatvfs* {.importc: "struct statvfs", header: "<sys/statvfs.h>",
+              final, pure.} = object ## struct statvfs
+    f_bsize*: int        ## File system block size.
+    f_frsize*: int       ## Fundamental file system block size.
+    f_blocks*: Tfsblkcnt ## Total number of blocks on file system
+                         ## in units of f_frsize.
+    f_bfree*: Tfsblkcnt  ## Total number of free blocks.
+    f_bavail*: Tfsblkcnt ## Number of free blocks available to
+                         ## non-privileged process.
+    f_files*: Tfsfilcnt  ## Total number of file serial numbers.
+    f_ffree*: Tfsfilcnt  ## Total number of free file serial numbers.
+    f_favail*: Tfsfilcnt ## Number of file serial numbers available to
+                         ## non-privileged process.
+    f_fsid*: int         ## File system ID.
+    f_flag*: int         ## Bit mask of f_flag values.
+    f_namemax*: int      ## Maximum filename length.
+
+  Tposix_typed_mem_info* {.importc: "struct posix_typed_mem_info",
+                           header: "<sys/mman.h>", final, pure.} = object
+    posix_tmi_length*: int
+
+  Ttm* {.importc: "struct tm", header: "<time.h>",
+         final, pure.} = object ## struct tm
+    tm_sec*: cint   ## Seconds [0,60].
+    tm_min*: cint   ## Minutes [0,59].
+    tm_hour*: cint  ## Hour [0,23].
+    tm_mday*: cint  ## Day of month [1,31].
+    tm_mon*: cint   ## Month of year [0,11].
+    tm_year*: cint  ## Years since 1900.
+    tm_wday*: cint  ## Day of week [0,6] (Sunday =0).
+    tm_yday*: cint  ## Day of year [0,365].
+    tm_isdst*: cint ## Daylight Savings flag.
+  Ttimespec* {.importc: "struct timespec",
+               header: "<time.h>", final, pure.} = object ## struct timespec
+    tv_sec*: Time  ## Seconds.
+    tv_nsec*: int  ## Nanoseconds.
+  titimerspec* {.importc: "struct itimerspec", header: "<time.h>",
+                 final, pure.} = object ## struct itimerspec
+    it_interval*: Ttimespec ## Timer period.
+    it_value*: Ttimespec    ## Timer expiration.
+
+  Tsig_atomic* {.importc: "sig_atomic_t", header: "<signal.h>".} = cint
+    ## Possibly volatile-qualified integer type of an object that can be
+    ## accessed as an atomic entity, even in the presence of asynchronous
+    ## interrupts.
+  Tsigset* {.importc: "sigset_t", header: "<signal.h>", final, pure.} = object
+
+  TsigEvent* {.importc: "struct sigevent",
+               header: "<signal.h>", final, pure.} = object ## struct sigevent
+    sigev_notify*: cint           ## Notification type.
+    sigev_signo*: cint            ## Signal number.
+    sigev_value*: TsigVal         ## Signal value.
+    sigev_notify_function*: proc (x: TsigVal) {.noconv.} ## Notification func.
+    sigev_notify_attributes*: ptr Tpthread_attr ## Notification attributes.
+
+  TsigVal* {.importc: "union sigval",
+             header: "<signal.h>", final, pure.} = object ## struct sigval
+    sival_ptr*: pointer ## pointer signal value;
+                        ## integer signal value not defined!
+  TSigaction* {.importc: "struct sigaction",
+                header: "<signal.h>", final, pure.} = object ## struct sigaction
+    sa_handler*: proc (x: cint) {.noconv.}  ## Pointer to a signal-catching
+                                            ## function or one of the macros
+                                            ## SIG_IGN or SIG_DFL.
+    sa_mask*: Tsigset ## Set of signals to be blocked during execution of
+                      ## the signal handling function.
+    sa_flags*: cint   ## Special flags.
+    sa_sigaction*: proc (x: cint, y: var TsigInfo, z: pointer) {.noconv.}
+
+  TStack* {.importc: "stack_t",
+            header: "<signal.h>", final, pure.} = object ## stack_t
+    ss_sp*: pointer  ## Stack base or pointer.
+    ss_size*: int    ## Stack size.
+    ss_flags*: cint  ## Flags.
+
+  TSigStack* {.importc: "struct sigstack",
+               header: "<signal.h>", final, pure.} = object ## struct sigstack
+    ss_onstack*: cint ## Non-zero when signal stack is in use.
+    ss_sp*: pointer   ## Signal stack pointer.
+
+  TsigInfo* {.importc: "siginfo_t",
+              header: "<signal.h>", final, pure.} = object ## siginfo_t
+    si_signo*: cint    ## Signal number.
+    si_code*: cint     ## Signal code.
+    si_errno*: cint    ## If non-zero, an errno value associated with
+                       ## this signal, as defined in <errno.h>.
+    si_pid*: TPid      ## Sending process ID.
+    si_uid*: Tuid      ## Real user ID of sending process.
+    si_addr*: pointer  ## Address of faulting instruction.
+    si_status*: cint   ## Exit value or signal.
+    si_band*: int      ## Band event for SIGPOLL.
+    si_value*: TsigVal ## Signal value.
+
+  Tnl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint
+  Tnl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = cint
+
+  Tsched_param* {.importc: "struct sched_param",
+                  header: "<sched.h>",
+                  final, pure.} = object ## struct sched_param
+    sched_priority*: cint
+    sched_ss_low_priority*: cint     ## Low scheduling priority for
+                                     ## sporadic server.
+    sched_ss_repl_period*: Ttimespec ## Replenishment period for
+                                     ## sporadic server.
+    sched_ss_init_budget*: Ttimespec ## Initial budget for sporadic server.
+    sched_ss_max_repl*: cint         ## Maximum pending replenishments for
+                                     ## sporadic server.
+
+  Timeval* {.importc: "struct timeval", header: "<sys/select.h>",
+             final, pure.} = object ## struct timeval
+    tv_sec*: int       ## Seconds.
+    tv_usec*: int ## Microseconds.
+  TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
+           final, pure.} = object
+  Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>",
+               final, pure.} = object
+  Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>",
+               final, pure.} = object ## ucontext_t
+    uc_link*: ptr Tucontext ## Pointer to the context that is resumed
+                            ## when this context returns.
+    uc_sigmask*: Tsigset    ## The set of signals that are blocked when this
+                            ## context is active.
+    uc_stack*: TStack       ## The stack used by this context.
+    uc_mcontext*: Tmcontext ## A machine-specific representation of the saved
+                            ## context.
+
+when hasAioH:
+  type
+    Taiocb* {.importc: "struct aiocb", header: "<aio.h>",
+              final, pure.} = object ## struct aiocb
+      aio_fildes*: cint         ## File descriptor.
+      aio_offset*: TOff         ## File offset.
+      aio_buf*: pointer         ## Location of buffer.
+      aio_nbytes*: int          ## Length of transfer.
+      aio_reqprio*: cint        ## Request priority offset.
+      aio_sigevent*: TsigEvent  ## Signal number and value.
+      aio_lio_opcode: cint      ## Operation to be performed.
+
+when hasSpawnH:
+  type
+    Tposix_spawnattr* {.importc: "posix_spawnattr_t",
+                        header: "<spawn.h>", final, pure.} = object
+    Tposix_spawn_file_actions* {.importc: "posix_spawn_file_actions_t",
+                                 header: "<spawn.h>", final, pure.} = object
+
+type
+  Socklen* {.importc: "socklen_t", header: "<sys/socket.h>".} = cuint
+  TSa_Family* {.importc: "sa_family_t", header: "<sys/socket.h>".} = cint
+
+  SockAddr* {.importc: "struct sockaddr", header: "<sys/socket.h>",
+              pure, final.} = object ## struct sockaddr
+    sa_family*: TSa_Family         ## Address family.
+    sa_data*: array [0..255, char] ## Socket address (variable-length data).
+
+  Tsockaddr_storage* {.importc: "struct sockaddr_storage",
+                       header: "<sys/socket.h>",
+                       pure, final.} = object ## struct sockaddr_storage
+    ss_family*: TSa_Family ## Address family.
+
+  Tif_nameindex* {.importc: "struct if_nameindex", final,
+                   pure, header: "<net/if.h>".} = object ## struct if_nameindex
+    if_index*: cint   ## Numeric index of the interface.
+    if_name*: cstring ## Null-terminated name of the interface.
+
+
+  TIOVec* {.importc: "struct iovec", pure, final,
+            header: "<sys/uio.h>".} = object ## struct iovec
+    iov_base*: pointer ## Base address of a memory region for input or output.
+    iov_len*: int    ## The size of the memory pointed to by iov_base.
+
+  Tmsghdr* {.importc: "struct msghdr", pure, final,
+             header: "<sys/socket.h>".} = object  ## struct msghdr
+    msg_name*: pointer  ## Optional address.
+    msg_namelen*: Socklen  ## Size of address.
+    msg_iov*: ptr TIOVec    ## Scatter/gather array.
+    msg_iovlen*: cint   ## Members in msg_iov.
+    msg_control*: pointer  ## Ancillary data; see below.
+    msg_controllen*: Socklen ## Ancillary data buffer len.
+    msg_flags*: cint ## Flags on received message.
+
+
+  Tcmsghdr* {.importc: "struct cmsghdr", pure, final,
+              header: "<sys/socket.h>".} = object ## struct cmsghdr
+    cmsg_len*: Socklen ## Data byte count, including the cmsghdr.
+    cmsg_level*: cint   ## Originating protocol.
+    cmsg_type*: cint    ## Protocol-specific type.
+
+  TLinger* {.importc: "struct linger", pure, final,
+             header: "<sys/socket.h>".} = object ## struct linger
+    l_onoff*: cint  ## Indicates whether linger option is enabled.
+    l_linger*: cint ## Linger time, in seconds.
+
+  TInPort* = int16 ## unsigned!
+  TInAddrScalar* = int32 ## unsigned!
+
+  TInAddrT* {.importc: "in_addr_t", pure, final,
+             header: "<netinet/in.h>".} = int32 ## unsigned!
+
+  InAddr* {.importc: "struct in_addr", pure, final,
+             header: "<netinet/in.h>".} = object ## struct in_addr
+    s_addr*: TInAddrScalar
+
+  Sockaddr_in* {.importc: "struct sockaddr_in", pure, final,
+                  header: "<netinet/in.h>".} = object ## struct sockaddr_in
+    sin_family*: TSa_Family ## AF_INET.
+    sin_port*: TInPort      ## Port number.
+    sin_addr*: InAddr      ## IP address.
+
+  TIn6Addr* {.importc: "struct in6_addr", pure, final,
+              header: "<netinet/in.h>".} = object ## struct in6_addr
+    s6_addr*: array [0..15, char]
+
+  Tsockaddr_in6* {.importc: "struct sockaddr_in6", pure, final,
+                   header: "<netinet/in.h>".} = object ## struct sockaddr_in6
+    sin6_family*: TSa_Family ## AF_INET6.
+    sin6_port*: TInPort      ## Port number.
+    sin6_flowinfo*: int32    ## IPv6 traffic class and flow information.
+    sin6_addr*: TIn6Addr     ## IPv6 address.
+    sin6_scope_id*: int32    ## Set of interfaces for a scope.
+
+  Tipv6_mreq* {.importc: "struct ipv6_mreq", pure, final,
+                header: "<netinet/in.h>".} = object ## struct ipv6_mreq
+    ipv6mr_multiaddr*: TIn6Addr ## IPv6 multicast address.
+    ipv6mr_interface*: cint     ## Interface index.
+
+  Hostent* {.importc: "struct hostent", pure, final,
+              header: "<netdb.h>".} = object ## struct hostent
+    h_name*: cstring           ## Official name of the host.
+    h_aliases*: cstringArray   ## A pointer to an array of pointers to
+                               ## alternative host names, terminated by a
+                               ## null pointer.
+    h_addrtype*: cint          ## Address type.
+    h_length*: cint            ## The length, in bytes, of the address.
+    h_addr_list*: cstringArray ## A pointer to an array of pointers to network
+                               ## addresses (in network byte order) for the
+                               ## host, terminated by a null pointer.
+
+  Tnetent* {.importc: "struct netent", pure, final,
+              header: "<netdb.h>".} = object ## struct netent
+    n_name*: cstring         ## Official, fully-qualified (including the
+                             ## domain) name of the host.
+    n_aliases*: cstringArray ## A pointer to an array of pointers to
+                             ## alternative network names, terminated by a
+                             ## null pointer.
+    n_addrtype*: cint        ## The address type of the network.
+    n_net*: int32            ## The network number, in host byte order.
+
+  TProtoent* {.importc: "struct protoent", pure, final,
+              header: "<netdb.h>".} = object ## struct protoent
+    p_name*: cstring         ## Official name of the protocol.
+    p_aliases*: cstringArray ## A pointer to an array of pointers to
+                             ## alternative protocol names, terminated by
+                             ## a null pointer.
+    p_proto*: cint           ## The protocol number.
+
+  Servent* {.importc: "struct servent", pure, final,
+             header: "<netdb.h>".} = object ## struct servent
+    s_name*: cstring         ## Official name of the service.
+    s_aliases*: cstringArray ## A pointer to an array of pointers to
+                             ## alternative service names, terminated by
+                             ## a null pointer.
+    s_port*: cint            ## The port number at which the service
+                             ## resides, in network byte order.
+    s_proto*: cstring        ## The name of the protocol to use when
+                             ## contacting the service.
+
+  AddrInfo* {.importc: "struct addrinfo", pure, final,
+              header: "<netdb.h>".} = object ## struct addrinfo
+    ai_flags*: cint         ## Input flags.
+    ai_family*: cint        ## Address family of socket.
+    ai_socktype*: cint      ## Socket type.
+    ai_protocol*: cint      ## Protocol of socket.
+    ai_addrlen*: Socklen   ## Length of socket address.
+    ai_addr*: ptr SockAddr ## Socket address of socket.
+    ai_canonname*: cstring  ## Canonical name of service location.
+    ai_next*: ptr AddrInfo ## Pointer to next in list.
+
+  TPollfd* {.importc: "struct pollfd", pure, final,
+             header: "<poll.h>".} = object ## struct pollfd
+    fd*: cint        ## The following descriptor being polled.
+    events*: cshort  ## The input event flags (see below).
+    revents*: cshort ## The output event flags (see below).
+
+  Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = cint
+
+{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
+    TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
+    Thostent: Hostent, TServent: Servent,
+    TInAddr: InAddr].}
+
+var
+  errno* {.importc, header: "<errno.h>".}: cint ## error variable
+  h_errno* {.importc, header: "<netdb.h>".}: cint
+  daylight* {.importc, header: "<time.h>".}: cint
+  timezone* {.importc, header: "<time.h>".}: int
+
+# Constants as variables:
+when hasAioH:
+  var
+    AIO_ALLDONE* {.importc, header: "<aio.h>".}: cint
+      ## A return value indicating that none of the requested operations
+      ## could be canceled since they are already complete.
+    AIO_CANCELED* {.importc, header: "<aio.h>".}: cint
+      ## A return value indicating that all requested operations have
+      ## been canceled.
+    AIO_NOTCANCELED* {.importc, header: "<aio.h>".}: cint
+      ## A return value indicating that some of the requested operations could
+      ## not be canceled since they are in progress.
+    LIO_NOP* {.importc, header: "<aio.h>".}: cint
+      ## A lio_listio() element operation option indicating that no transfer is
+      ## requested.
+    LIO_NOWAIT* {.importc, header: "<aio.h>".}: cint
+      ## A lio_listio() synchronization operation indicating that the calling
+      ## thread is to continue execution while the lio_listio() operation is
+      ## being performed, and no notification is given when the operation is
+      ## complete.
+    LIO_READ* {.importc, header: "<aio.h>".}: cint
+      ## A lio_listio() element operation option requesting a read.
+    LIO_WAIT* {.importc, header: "<aio.h>".}: cint
+      ## A lio_listio() synchronization operation indicating that the calling
+      ## thread is to suspend until the lio_listio() operation is complete.
+    LIO_WRITE* {.importc, header: "<aio.h>".}: cint
+      ## A lio_listio() element operation option requesting a write.
+
+var
+  RTLD_LAZY* {.importc, header: "<dlfcn.h>".}: cint
+    ## Relocations are performed at an implementation-defined time.
+  RTLD_NOW* {.importc, header: "<dlfcn.h>".}: cint
+    ## Relocations are performed when the object is loaded.
+  RTLD_GLOBAL* {.importc, header: "<dlfcn.h>".}: cint
+    ## All symbols are available for relocation processing of other modules.
+  RTLD_LOCAL* {.importc, header: "<dlfcn.h>".}: cint
+    ## All symbols are not made available for relocation processing by
+    ## other modules.
+
+  E2BIG* {.importc, header: "<errno.h>".}: cint
+      ## Argument list too long.
+  EACCES* {.importc, header: "<errno.h>".}: cint
+      ## Permission denied.
+  EADDRINUSE* {.importc, header: "<errno.h>".}: cint
+      ## Address in use.
+  EADDRNOTAVAIL* {.importc, header: "<errno.h>".}: cint
+      ## Address not available.
+  EAFNOSUPPORT* {.importc, header: "<errno.h>".}: cint
+      ## Address family not supported.
+  EAGAIN* {.importc, header: "<errno.h>".}: cint
+      ## Resource unavailable, try again (may be the same value as EWOULDBLOCK).
+  EALREADY* {.importc, header: "<errno.h>".}: cint
+      ## Connection already in progress.
+  EBADF* {.importc, header: "<errno.h>".}: cint
+      ## Bad file descriptor.
+  EBADMSG* {.importc, header: "<errno.h>".}: cint
+      ## Bad message.
+  EBUSY* {.importc, header: "<errno.h>".}: cint
+      ## Device or resource busy.
+  ECANCELED* {.importc, header: "<errno.h>".}: cint
+      ## Operation canceled.
+  ECHILD* {.importc, header: "<errno.h>".}: cint
+      ## No child processes.
+  ECONNABORTED* {.importc, header: "<errno.h>".}: cint
+      ## Connection aborted.
+  ECONNREFUSED* {.importc, header: "<errno.h>".}: cint
+      ## Connection refused.
+  ECONNRESET* {.importc, header: "<errno.h>".}: cint
+      ## Connection reset.
+  EDEADLK* {.importc, header: "<errno.h>".}: cint
+      ## Resource deadlock would occur.
+  EDESTADDRREQ* {.importc, header: "<errno.h>".}: cint
+      ## Destination address required.
+  EDOM* {.importc, header: "<errno.h>".}: cint
+      ## Mathematics argument out of domain of function.
+  EDQUOT* {.importc, header: "<errno.h>".}: cint
+      ## Reserved.
+  EEXIST* {.importc, header: "<errno.h>".}: cint
+      ## File exists.
+  EFAULT* {.importc, header: "<errno.h>".}: cint
+      ## Bad address.
+  EFBIG* {.importc, header: "<errno.h>".}: cint
+      ## File too large.
+  EHOSTUNREACH* {.importc, header: "<errno.h>".}: cint
+      ## Host is unreachable.
+  EIDRM* {.importc, header: "<errno.h>".}: cint
+      ## Identifier removed.
+  EILSEQ* {.importc, header: "<errno.h>".}: cint
+      ## Illegal byte sequence.
+  EINPROGRESS* {.importc, header: "<errno.h>".}: cint
+      ## Operation in progress.
+  EINTR* {.importc, header: "<errno.h>".}: cint
+      ## Interrupted function.
+  EINVAL* {.importc, header: "<errno.h>".}: cint
+      ## Invalid argument.
+  EIO* {.importc, header: "<errno.h>".}: cint
+      ## I/O error.
+  EISCONN* {.importc, header: "<errno.h>".}: cint
+      ## Socket is connected.
+  EISDIR* {.importc, header: "<errno.h>".}: cint
+      ## Is a directory.
+  ELOOP* {.importc, header: "<errno.h>".}: cint
+      ## Too many levels of symbolic links.
+  EMFILE* {.importc, header: "<errno.h>".}: cint
+      ## Too many open files.
+  EMLINK* {.importc, header: "<errno.h>".}: cint
+      ## Too many links.
+  EMSGSIZE* {.importc, header: "<errno.h>".}: cint
+      ## Message too large.
+  EMULTIHOP* {.importc, header: "<errno.h>".}: cint
+      ## Reserved.
+  ENAMETOOLONG* {.importc, header: "<errno.h>".}: cint
+      ## Filename too long.
+  ENETDOWN* {.importc, header: "<errno.h>".}: cint
+      ## Network is down.
+  ENETRESET* {.importc, header: "<errno.h>".}: cint
+      ## Connection aborted by network.
+  ENETUNREACH* {.importc, header: "<errno.h>".}: cint
+      ## Network unreachable.
+  ENFILE* {.importc, header: "<errno.h>".}: cint
+      ## Too many files open in system.
+  ENOBUFS* {.importc, header: "<errno.h>".}: cint
+      ## No buffer space available.
+  ENODATA* {.importc, header: "<errno.h>".}: cint
+      ## No message is available on the STREAM head read queue.
+  ENODEV* {.importc, header: "<errno.h>".}: cint
+      ## No such device.
+  ENOENT* {.importc, header: "<errno.h>".}: cint
+      ## No such file or directory.
+  ENOEXEC* {.importc, header: "<errno.h>".}: cint
+      ## Executable file format error.
+  ENOLCK* {.importc, header: "<errno.h>".}: cint
+      ## No locks available.
+  ENOLINK* {.importc, header: "<errno.h>".}: cint
+      ## Reserved.
+  ENOMEM* {.importc, header: "<errno.h>".}: cint
+      ## Not enough space.
+  ENOMSG* {.importc, header: "<errno.h>".}: cint
+      ## No message of the desired type.
+  ENOPROTOOPT* {.importc, header: "<errno.h>".}: cint
+      ## Protocol not available.
+  ENOSPC* {.importc, header: "<errno.h>".}: cint
+      ## No space left on device.
+  ENOSR* {.importc, header: "<errno.h>".}: cint
+      ## No STREAM resources.
+  ENOSTR* {.importc, header: "<errno.h>".}: cint
+      ## Not a STREAM.
+  ENOSYS* {.importc, header: "<errno.h>".}: cint
+      ## Function not supported.
+  ENOTCONN* {.importc, header: "<errno.h>".}: cint
+      ## The socket is not connected.
+  ENOTDIR* {.importc, header: "<errno.h>".}: cint
+      ## Not a directory.
+  ENOTEMPTY* {.importc, header: "<errno.h>".}: cint
+      ## Directory not empty.
+  ENOTSOCK* {.importc, header: "<errno.h>".}: cint
+      ## Not a socket.
+  ENOTSUP* {.importc, header: "<errno.h>".}: cint
+      ## Not supported.
+  ENOTTY* {.importc, header: "<errno.h>".}: cint
+      ## Inappropriate I/O control operation.
+  ENXIO* {.importc, header: "<errno.h>".}: cint
+      ## No such device or address.
+  EOPNOTSUPP* {.importc, header: "<errno.h>".}: cint
+      ## Operation not supported on socket.
+  EOVERFLOW* {.importc, header: "<errno.h>".}: cint
+      ## Value too large to be stored in data type.
+  EPERM* {.importc, header: "<errno.h>".}: cint
+      ## Operation not permitted.
+  EPIPE* {.importc, header: "<errno.h>".}: cint
+      ## Broken pipe.
+  EPROTO* {.importc, header: "<errno.h>".}: cint
+      ## Protocol error.
+  EPROTONOSUPPORT* {.importc, header: "<errno.h>".}: cint
+      ## Protocol not supported.
+  EPROTOTYPE* {.importc, header: "<errno.h>".}: cint
+      ## Protocol wrong type for socket.
+  ERANGE* {.importc, header: "<errno.h>".}: cint
+      ## Result too large.
+  EROFS* {.importc, header: "<errno.h>".}: cint
+      ## Read-only file system.
+  ESPIPE* {.importc, header: "<errno.h>".}: cint
+      ## Invalid seek.
+  ESRCH* {.importc, header: "<errno.h>".}: cint
+      ## No such process.
+  ESTALE* {.importc, header: "<errno.h>".}: cint
+      ## Reserved.
+  ETIME* {.importc, header: "<errno.h>".}: cint
+      ## Stream ioctl() timeout.
+  ETIMEDOUT* {.importc, header: "<errno.h>".}: cint
+      ## Connection timed out.
+  ETXTBSY* {.importc, header: "<errno.h>".}: cint
+      ## Text file busy.
+  EWOULDBLOCK* {.importc, header: "<errno.h>".}: cint
+      ## Operation would block (may be the same value as [EAGAIN]).
+  EXDEV* {.importc, header: "<errno.h>".}: cint
+      ## Cross-device link.
+
+  F_DUPFD* {.importc, header: "<fcntl.h>".}: cint
+    ## Duplicate file descriptor.
+  F_GETFD* {.importc, header: "<fcntl.h>".}: cint
+    ## Get file descriptor flags.
+  F_SETFD* {.importc, header: "<fcntl.h>".}: cint
+    ## Set file descriptor flags.
+  F_GETFL* {.importc, header: "<fcntl.h>".}: cint
+    ## Get file status flags and file access modes.
+  F_SETFL* {.importc, header: "<fcntl.h>".}: cint
+    ## Set file status flags.
+  F_GETLK* {.importc, header: "<fcntl.h>".}: cint
+    ## Get record locking information.
+  F_SETLK* {.importc, header: "<fcntl.h>".}: cint
+    ## Set record locking information.
+  F_SETLKW* {.importc, header: "<fcntl.h>".}: cint
+    ## Set record locking information; wait if blocked.
+  F_GETOWN* {.importc, header: "<fcntl.h>".}: cint
+    ## Get process or process group ID to receive SIGURG signals.
+  F_SETOWN* {.importc, header: "<fcntl.h>".}: cint
+    ## Set process or process group ID to receive SIGURG signals.
+  FD_CLOEXEC* {.importc, header: "<fcntl.h>".}: cint
+    ## Close the file descriptor upon execution of an exec family function.
+  F_RDLCK* {.importc, header: "<fcntl.h>".}: cint
+    ## Shared or read lock.
+  F_UNLCK* {.importc, header: "<fcntl.h>".}: cint
+    ## Unlock.
+  F_WRLCK* {.importc, header: "<fcntl.h>".}: cint
+    ## Exclusive or write lock.
+  O_CREAT* {.importc, header: "<fcntl.h>".}: cint
+    ## Create file if it does not exist.
+  O_EXCL* {.importc, header: "<fcntl.h>".}: cint
+    ## Exclusive use flag.
+  O_NOCTTY* {.importc, header: "<fcntl.h>".}: cint
+    ## Do not assign controlling terminal.
+  O_TRUNC* {.importc, header: "<fcntl.h>".}: cint
+    ## Truncate flag.
+  O_APPEND* {.importc, header: "<fcntl.h>".}: cint
+    ## Set append mode.
+  O_DSYNC* {.importc, header: "<fcntl.h>".}: cint
+    ## Write according to synchronized I/O data integrity completion.
+  O_NONBLOCK* {.importc, header: "<fcntl.h>".}: cint
+    ## Non-blocking mode.
+  O_RSYNC* {.importc, header: "<fcntl.h>".}: cint
+    ## Synchronized read I/O operations.
+  O_SYNC* {.importc, header: "<fcntl.h>".}: cint
+    ## Write according to synchronized I/O file integrity completion.
+  O_ACCMODE* {.importc, header: "<fcntl.h>".}: cint
+    ## Mask for file access modes.
+  O_RDONLY* {.importc, header: "<fcntl.h>".}: cint
+    ## Open for reading only.
+  O_RDWR* {.importc, header: "<fcntl.h>".}: cint
+    ## Open for reading and writing.
+  O_WRONLY* {.importc, header: "<fcntl.h>".}: cint
+    ## Open for writing only.
+  POSIX_FADV_NORMAL* {.importc, header: "<fcntl.h>".}: cint
+    ## The application has no advice to give on its behavior with
+    ## respect to the specified data. It is the default characteristic
+    ## if no advice is given for an open file.
+  POSIX_FADV_SEQUENTIAL* {.importc, header: "<fcntl.h>".}: cint
+    ## The application expects to access the specified data
+    # sequentially from lower offsets to higher offsets.
+  POSIX_FADV_RANDOM* {.importc, header: "<fcntl.h>".}: cint
+    ## The application expects to access the specified data in a random order.
+  POSIX_FADV_WILLNEED* {.importc, header: "<fcntl.h>".}: cint
+    ## The application expects to access the specified data in the near future.
+  POSIX_FADV_DONTNEED* {.importc, header: "<fcntl.h>".}: cint
+    ## The application expects that it will not access the specified data
+    ## in the near future.
+  POSIX_FADV_NOREUSE* {.importc, header: "<fcntl.h>".}: cint
+    ## The application expects to access the specified data once and
+    ## then not reuse it thereafter.
+
+when not defined(haiku) and not defined(OpenBSD):
+  var
+    MM_HARD* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Source of the condition is hardware.
+    MM_SOFT* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Source of the condition is software.
+    MM_FIRM* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Source of the condition is firmware.
+    MM_APPL* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Condition detected by application.
+    MM_UTIL* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Condition detected by utility.
+    MM_OPSYS* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Condition detected by operating system.
+    MM_RECOVER* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Recoverable error.
+    MM_NRECOV* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Non-recoverable error.
+    MM_HALT* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Error causing application to halt.
+    MM_ERROR* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Application has encountered a non-fatal fault.
+    MM_WARNING* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Application has detected unusual non-error condition.
+    MM_INFO* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Informative message.
+    MM_NOSEV* {.importc, header: "<fmtmsg.h>".}: cint
+      ## No severity level provided for the message.
+    MM_PRINT* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Display message on standard error.
+    MM_CONSOLE* {.importc, header: "<fmtmsg.h>".}: cint
+      ## Display message on system console.
+
+    MM_OK* {.importc, header: "<fmtmsg.h>".}: cint
+      ## The function succeeded.
+    MM_NOTOK* {.importc, header: "<fmtmsg.h>".}: cint
+      ## The function failed completely.
+    MM_NOMSG* {.importc, header: "<fmtmsg.h>".}: cint
+      ## The function was unable to generate a message on standard error,
+      ## but otherwise succeeded.
+    MM_NOCON* {.importc, header: "<fmtmsg.h>".}: cint
+      ## The function was unable to generate a console message, but
+      ## otherwise succeeded.
+
+var
+  FNM_NOMATCH* {.importc, header: "<fnmatch.h>".}: cint
+    ## The string does not match the specified pattern.
+  FNM_PATHNAME* {.importc, header: "<fnmatch.h>".}: cint
+    ## Slash in string only matches slash in pattern.
+  FNM_PERIOD* {.importc, header: "<fnmatch.h>".}: cint
+    ## Leading period in string must be exactly matched by period in pattern.
+  FNM_NOESCAPE* {.importc, header: "<fnmatch.h>".}: cint
+    ## Disable backslash escaping.
+  FNM_NOSYS* {.importc, header: "<fnmatch.h>".}: cint
+    ## Reserved.
+
+  FTW_F* {.importc, header: "<ftw.h>".}: cint
+    ## File.
+  FTW_D* {.importc, header: "<ftw.h>".}: cint
+    ## Directory.
+  FTW_DNR* {.importc, header: "<ftw.h>".}: cint
+    ## Directory without read permission.
+  FTW_DP* {.importc, header: "<ftw.h>".}: cint
+    ## Directory with subdirectories visited.
+  FTW_NS* {.importc, header: "<ftw.h>".}: cint
+    ## Unknown type; stat() failed.
+  FTW_SL* {.importc, header: "<ftw.h>".}: cint
+    ## Symbolic link.
+  FTW_SLN* {.importc, header: "<ftw.h>".}: cint
+    ## Symbolic link that names a nonexistent file.
+
+  FTW_PHYS* {.importc, header: "<ftw.h>".}: cint
+    ## Physical walk, does not follow symbolic links. Otherwise, nftw()
+    ## follows links but does not walk down any path that crosses itself.
+  FTW_MOUNT* {.importc, header: "<ftw.h>".}: cint
+    ## The walk does not cross a mount point.
+  FTW_DEPTH* {.importc, header: "<ftw.h>".}: cint
+    ## All subdirectories are visited before the directory itself.
+  FTW_CHDIR* {.importc, header: "<ftw.h>".}: cint
+    ## The walk changes to each directory before reading it.
+
+  GLOB_APPEND* {.importc, header: "<glob.h>".}: cint
+    ## Append generated pathnames to those previously obtained.
+  GLOB_DOOFFS* {.importc, header: "<glob.h>".}: cint
+    ## Specify how many null pointers to add to the beginning of gl_pathv.
+  GLOB_ERR* {.importc, header: "<glob.h>".}: cint
+    ## Cause glob() to return on error.
+  GLOB_MARK* {.importc, header: "<glob.h>".}: cint
+    ## Each pathname that is a directory that matches pattern has a
+    ## slash appended.
+  GLOB_NOCHECK* {.importc, header: "<glob.h>".}: cint
+    ## If pattern does not match any pathname, then return a list
+    ## consisting of only pattern.
+  GLOB_NOESCAPE* {.importc, header: "<glob.h>".}: cint
+    ## Disable backslash escaping.
+  GLOB_NOSORT* {.importc, header: "<glob.h>".}: cint
+    ## Do not sort the pathnames returned.
+  GLOB_ABORTED* {.importc, header: "<glob.h>".}: cint
+    ## The scan was stopped because GLOB_ERR was set or errfunc()
+    ## returned non-zero.
+  GLOB_NOMATCH* {.importc, header: "<glob.h>".}: cint
+    ## The pattern does not match any existing pathname, and GLOB_NOCHECK
+    ## was not set in flags.
+  GLOB_NOSPACE* {.importc, header: "<glob.h>".}: cint
+    ## An attempt to allocate memory failed.
+  GLOB_NOSYS* {.importc, header: "<glob.h>".}: cint
+    ## Reserved
+
+  CODESET* {.importc, header: "<langinfo.h>".}: cint
+    ## Codeset name.
+  D_T_FMT* {.importc, header: "<langinfo.h>".}: cint
+    ## String for formatting date and time.
+  D_FMT * {.importc, header: "<langinfo.h>".}: cint
+    ## Date format string.
+  T_FMT* {.importc, header: "<langinfo.h>".}: cint
+    ## Time format string.
+  T_FMT_AMPM* {.importc, header: "<langinfo.h>".}: cint
+    ## a.m. or p.m. time format string.
+  AM_STR* {.importc, header: "<langinfo.h>".}: cint
+    ## Ante-meridiem affix.
+  PM_STR* {.importc, header: "<langinfo.h>".}: cint
+    ## Post-meridiem affix.
+  DAY_1* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the first day of the week (for example, Sunday).
+  DAY_2* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the second day of the week (for example, Monday).
+  DAY_3* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the third day of the week (for example, Tuesday).
+  DAY_4* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the fourth day of the week (for example, Wednesday).
+  DAY_5* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the fifth day of the week (for example, Thursday).
+  DAY_6* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the sixth day of the week (for example, Friday).
+  DAY_7* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the seventh day of the week (for example, Saturday).
+  ABDAY_1* {.importc, header: "<langinfo.h>".}: cint
+    ## Abbreviated name of the first day of the week.
+  ABDAY_2* {.importc, header: "<langinfo.h>".}: cint
+  ABDAY_3* {.importc, header: "<langinfo.h>".}: cint
+  ABDAY_4* {.importc, header: "<langinfo.h>".}: cint
+  ABDAY_5* {.importc, header: "<langinfo.h>".}: cint
+  ABDAY_6* {.importc, header: "<langinfo.h>".}: cint
+  ABDAY_7* {.importc, header: "<langinfo.h>".}: cint
+  MON_1* {.importc, header: "<langinfo.h>".}: cint
+    ## Name of the first month of the year.
+  MON_2* {.importc, header: "<langinfo.h>".}: cint
+  MON_3* {.importc, header: "<langinfo.h>".}: cint
+  MON_4* {.importc, header: "<langinfo.h>".}: cint
+  MON_5* {.importc, header: "<langinfo.h>".}: cint
+  MON_6* {.importc, header: "<langinfo.h>".}: cint
+  MON_7* {.importc, header: "<langinfo.h>".}: cint
+  MON_8* {.importc, header: "<langinfo.h>".}: cint
+  MON_9* {.importc, header: "<langinfo.h>".}: cint
+  MON_10* {.importc, header: "<langinfo.h>".}: cint
+  MON_11* {.importc, header: "<langinfo.h>".}: cint
+  MON_12* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_1* {.importc, header: "<langinfo.h>".}: cint
+    ## Abbreviated name of the first month.
+  ABMON_2* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_3* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_4* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_5* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_6* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_7* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_8* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_9* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_10* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_11* {.importc, header: "<langinfo.h>".}: cint
+  ABMON_12* {.importc, header: "<langinfo.h>".}: cint
+  ERA* {.importc, header: "<langinfo.h>".}: cint
+    ## Era description segments.
+  ERA_D_FMT* {.importc, header: "<langinfo.h>".}: cint
+    ## Era date format string.
+  ERA_D_T_FMT* {.importc, header: "<langinfo.h>".}: cint
+    ## Era date and time format string.
+  ERA_T_FMT* {.importc, header: "<langinfo.h>".}: cint
+    ## Era time format string.
+  ALT_DIGITS* {.importc, header: "<langinfo.h>".}: cint
+    ## Alternative symbols for digits.
+  RADIXCHAR* {.importc, header: "<langinfo.h>".}: cint
+    ## Radix character.
+  THOUSEP* {.importc, header: "<langinfo.h>".}: cint
+    ## Separator for thousands.
+  YESEXPR* {.importc, header: "<langinfo.h>".}: cint
+    ## Affirmative response expression.
+  NOEXPR* {.importc, header: "<langinfo.h>".}: cint
+    ## Negative response expression.
+  CRNCYSTR* {.importc, header: "<langinfo.h>".}: cint
+    ## Local currency symbol, preceded by '-' if the symbol
+    ## should appear before the value, '+' if the symbol should appear
+    ## after the value, or '.' if the symbol should replace the radix
+    ## character. If the local currency symbol is the empty string,
+    ## implementations may return the empty string ( "" ).
+
+  LC_ALL* {.importc, header: "<locale.h>".}: cint
+  LC_COLLATE* {.importc, header: "<locale.h>".}: cint
+  LC_CTYPE* {.importc, header: "<locale.h>".}: cint
+  LC_MESSAGES* {.importc, header: "<locale.h>".}: cint
+  LC_MONETARY* {.importc, header: "<locale.h>".}: cint
+  LC_NUMERIC* {.importc, header: "<locale.h>".}: cint
+  LC_TIME* {.importc, header: "<locale.h>".}: cint
+
+  PTHREAD_BARRIER_SERIAL_THREAD* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CANCEL_ASYNCHRONOUS* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CANCEL_ENABLE* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CANCEL_DEFERRED* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CANCEL_DISABLE* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CANCELED* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_COND_INITIALIZER* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CREATE_DETACHED* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_CREATE_JOINABLE* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_EXPLICIT_SCHED* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_INHERIT_SCHED* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_MUTEX_DEFAULT* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_MUTEX_ERRORCHECK* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_MUTEX_INITIALIZER* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_MUTEX_NORMAL* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_MUTEX_RECURSIVE* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_ONCE_INIT* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_PRIO_INHERIT* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_PRIO_NONE* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_PRIO_PROTECT* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_PROCESS_SHARED* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_PROCESS_PRIVATE* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_SCOPE_PROCESS* {.importc, header: "<pthread.h>".}: cint
+  PTHREAD_SCOPE_SYSTEM* {.importc, header: "<pthread.h>".}: cint
+
+  POSIX_ASYNC_IO* {.importc: "_POSIX_ASYNC_IO", header: "<unistd.h>".}: cint
+  POSIX_PRIO_IO* {.importc: "_POSIX_PRIO_IO", header: "<unistd.h>".}: cint
+  POSIX_SYNC_IO* {.importc: "_POSIX_SYNC_IO", header: "<unistd.h>".}: cint
+  F_OK* {.importc: "F_OK", header: "<unistd.h>".}: cint
+  R_OK* {.importc: "R_OK", header: "<unistd.h>".}: cint
+  W_OK* {.importc: "W_OK", header: "<unistd.h>".}: cint
+  X_OK* {.importc: "X_OK", header: "<unistd.h>".}: cint
+
+  CS_PATH* {.importc: "_CS_PATH", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_ILP32_OFF32_CFLAGS* {.importc: "_CS_POSIX_V6_ILP32_OFF32_CFLAGS",
+    header: "<unistd.h>".}: cint
+  CS_POSIX_V6_ILP32_OFF32_LDFLAGS* {.
+    importc: "_CS_POSIX_V6_ILP32_OFF32_LDFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_ILP32_OFF32_LIBS* {.importc: "_CS_POSIX_V6_ILP32_OFF32_LIBS",
+    header: "<unistd.h>".}: cint
+  CS_POSIX_V6_ILP32_OFFBIG_CFLAGS* {.
+    importc: "_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS* {.
+    importc: "_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_ILP32_OFFBIG_LIBS* {.
+    importc: "_CS_POSIX_V6_ILP32_OFFBIG_LIBS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_LP64_OFF64_CFLAGS* {.
+    importc: "_CS_POSIX_V6_LP64_OFF64_CFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_LP64_OFF64_LDFLAGS* {.
+    importc: "_CS_POSIX_V6_LP64_OFF64_LDFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_LP64_OFF64_LIBS* {.
+    importc: "_CS_POSIX_V6_LP64_OFF64_LIBS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS* {.
+    importc: "_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS* {.
+    importc: "_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_LPBIG_OFFBIG_LIBS* {.
+    importc: "_CS_POSIX_V6_LPBIG_OFFBIG_LIBS", header: "<unistd.h>".}: cint
+  CS_POSIX_V6_WIDTH_RESTRICTED_ENVS* {.
+    importc: "_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS", header: "<unistd.h>".}: cint
+  F_LOCK* {.importc: "F_LOCK", header: "<unistd.h>".}: cint
+  F_TEST* {.importc: "F_TEST", header: "<unistd.h>".}: cint
+  F_TLOCK* {.importc: "F_TLOCK", header: "<unistd.h>".}: cint
+  F_ULOCK* {.importc: "F_ULOCK", header: "<unistd.h>".}: cint
+  PC_2_SYMLINKS* {.importc: "_PC_2_SYMLINKS", header: "<unistd.h>".}: cint
+  PC_ALLOC_SIZE_MIN* {.importc: "_PC_ALLOC_SIZE_MIN",
+    header: "<unistd.h>".}: cint
+  PC_ASYNC_IO* {.importc: "_PC_ASYNC_IO", header: "<unistd.h>".}: cint
+  PC_CHOWN_RESTRICTED* {.importc: "_PC_CHOWN_RESTRICTED",
+    header: "<unistd.h>".}: cint
+  PC_FILESIZEBITS* {.importc: "_PC_FILESIZEBITS", header: "<unistd.h>".}: cint
+  PC_LINK_MAX* {.importc: "_PC_LINK_MAX", header: "<unistd.h>".}: cint
+  PC_MAX_CANON* {.importc: "_PC_MAX_CANON", header: "<unistd.h>".}: cint
+
+  PC_MAX_INPUT*{.importc: "_PC_MAX_INPUT", header: "<unistd.h>".}: cint
+  PC_NAME_MAX*{.importc: "_PC_NAME_MAX", header: "<unistd.h>".}: cint
+  PC_NO_TRUNC*{.importc: "_PC_NO_TRUNC", header: "<unistd.h>".}: cint
+  PC_PATH_MAX*{.importc: "_PC_PATH_MAX", header: "<unistd.h>".}: cint
+  PC_PIPE_BUF*{.importc: "_PC_PIPE_BUF", header: "<unistd.h>".}: cint
+  PC_PRIO_IO*{.importc: "_PC_PRIO_IO", header: "<unistd.h>".}: cint
+  PC_REC_INCR_XFER_SIZE*{.importc: "_PC_REC_INCR_XFER_SIZE",
+    header: "<unistd.h>".}: cint
+  PC_REC_MIN_XFER_SIZE*{.importc: "_PC_REC_MIN_XFER_SIZE",
+    header: "<unistd.h>".}: cint
+  PC_REC_XFER_ALIGN*{.importc: "_PC_REC_XFER_ALIGN", header: "<unistd.h>".}: cint
+  PC_SYMLINK_MAX*{.importc: "_PC_SYMLINK_MAX", header: "<unistd.h>".}: cint
+  PC_SYNC_IO*{.importc: "_PC_SYNC_IO", header: "<unistd.h>".}: cint
+  PC_VDISABLE*{.importc: "_PC_VDISABLE", header: "<unistd.h>".}: cint
+  SC_2_C_BIND*{.importc: "_SC_2_C_BIND", header: "<unistd.h>".}: cint
+  SC_2_C_DEV*{.importc: "_SC_2_C_DEV", header: "<unistd.h>".}: cint
+  SC_2_CHAR_TERM*{.importc: "_SC_2_CHAR_TERM", header: "<unistd.h>".}: cint
+  SC_2_FORT_DEV*{.importc: "_SC_2_FORT_DEV", header: "<unistd.h>".}: cint
+  SC_2_FORT_RUN*{.importc: "_SC_2_FORT_RUN", header: "<unistd.h>".}: cint
+  SC_2_LOCALEDEF*{.importc: "_SC_2_LOCALEDEF", header: "<unistd.h>".}: cint
+  SC_2_PBS*{.importc: "_SC_2_PBS", header: "<unistd.h>".}: cint
+  SC_2_PBS_ACCOUNTING*{.importc: "_SC_2_PBS_ACCOUNTING",
+    header: "<unistd.h>".}: cint
+  SC_2_PBS_CHECKPOINT*{.importc: "_SC_2_PBS_CHECKPOINT",
+    header: "<unistd.h>".}: cint
+  SC_2_PBS_LOCATE*{.importc: "_SC_2_PBS_LOCATE", header: "<unistd.h>".}: cint
+  SC_2_PBS_MESSAGE*{.importc: "_SC_2_PBS_MESSAGE", header: "<unistd.h>".}: cint
+  SC_2_PBS_TRACK*{.importc: "_SC_2_PBS_TRACK", header: "<unistd.h>".}: cint
+  SC_2_SW_DEV*{.importc: "_SC_2_SW_DEV", header: "<unistd.h>".}: cint
+  SC_2_UPE*{.importc: "_SC_2_UPE", header: "<unistd.h>".}: cint
+  SC_2_VERSION*{.importc: "_SC_2_VERSION", header: "<unistd.h>".}: cint
+  SC_ADVISORY_INFO*{.importc: "_SC_ADVISORY_INFO", header: "<unistd.h>".}: cint
+  SC_AIO_LISTIO_MAX*{.importc: "_SC_AIO_LISTIO_MAX", header: "<unistd.h>".}: cint
+  SC_AIO_MAX*{.importc: "_SC_AIO_MAX", header: "<unistd.h>".}: cint
+  SC_AIO_PRIO_DELTA_MAX*{.importc: "_SC_AIO_PRIO_DELTA_MAX",
+    header: "<unistd.h>".}: cint
+  SC_ARG_MAX*{.importc: "_SC_ARG_MAX", header: "<unistd.h>".}: cint
+  SC_ASYNCHRONOUS_IO*{.importc: "_SC_ASYNCHRONOUS_IO",
+    header: "<unistd.h>".}: cint
+  SC_ATEXIT_MAX*{.importc: "_SC_ATEXIT_MAX", header: "<unistd.h>".}: cint
+  SC_BARRIERS*{.importc: "_SC_BARRIERS", header: "<unistd.h>".}: cint
+  SC_BC_BASE_MAX*{.importc: "_SC_BC_BASE_MAX", header: "<unistd.h>".}: cint
+  SC_BC_DIM_MAX*{.importc: "_SC_BC_DIM_MAX", header: "<unistd.h>".}: cint
+  SC_BC_SCALE_MAX*{.importc: "_SC_BC_SCALE_MAX", header: "<unistd.h>".}: cint
+  SC_BC_STRING_MAX*{.importc: "_SC_BC_STRING_MAX", header: "<unistd.h>".}: cint
+  SC_CHILD_MAX*{.importc: "_SC_CHILD_MAX", header: "<unistd.h>".}: cint
+  SC_CLK_TCK*{.importc: "_SC_CLK_TCK", header: "<unistd.h>".}: cint
+  SC_CLOCK_SELECTION*{.importc: "_SC_CLOCK_SELECTION",
+    header: "<unistd.h>".}: cint
+  SC_COLL_WEIGHTS_MAX*{.importc: "_SC_COLL_WEIGHTS_MAX",
+    header: "<unistd.h>".}: cint
+  SC_CPUTIME*{.importc: "_SC_CPUTIME", header: "<unistd.h>".}: cint
+  SC_DELAYTIMER_MAX*{.importc: "_SC_DELAYTIMER_MAX", header: "<unistd.h>".}: cint
+  SC_EXPR_NEST_MAX*{.importc: "_SC_EXPR_NEST_MAX", header: "<unistd.h>".}: cint
+  SC_FSYNC*{.importc: "_SC_FSYNC", header: "<unistd.h>".}: cint
+  SC_GETGR_R_SIZE_MAX*{.importc: "_SC_GETGR_R_SIZE_MAX",
+    header: "<unistd.h>".}: cint
+  SC_GETPW_R_SIZE_MAX*{.importc: "_SC_GETPW_R_SIZE_MAX",
+    header: "<unistd.h>".}: cint
+  SC_HOST_NAME_MAX*{.importc: "_SC_HOST_NAME_MAX", header: "<unistd.h>".}: cint
+  SC_IOV_MAX*{.importc: "_SC_IOV_MAX", header: "<unistd.h>".}: cint
+  SC_IPV6*{.importc: "_SC_IPV6", header: "<unistd.h>".}: cint
+  SC_JOB_CONTROL*{.importc: "_SC_JOB_CONTROL", header: "<unistd.h>".}: cint
+  SC_LINE_MAX*{.importc: "_SC_LINE_MAX", header: "<unistd.h>".}: cint
+  SC_LOGIN_NAME_MAX*{.importc: "_SC_LOGIN_NAME_MAX", header: "<unistd.h>".}: cint
+  SC_MAPPED_FILES*{.importc: "_SC_MAPPED_FILES", header: "<unistd.h>".}: cint
+  SC_MEMLOCK*{.importc: "_SC_MEMLOCK", header: "<unistd.h>".}: cint
+  SC_MEMLOCK_RANGE*{.importc: "_SC_MEMLOCK_RANGE", header: "<unistd.h>".}: cint
+  SC_MEMORY_PROTECTION*{.importc: "_SC_MEMORY_PROTECTION",
+    header: "<unistd.h>".}: cint
+  SC_MESSAGE_PASSING*{.importc: "_SC_MESSAGE_PASSING",
+    header: "<unistd.h>".}: cint
+  SC_MONOTONIC_CLOCK*{.importc: "_SC_MONOTONIC_CLOCK",
+    header: "<unistd.h>".}: cint
+  SC_MQ_OPEN_MAX*{.importc: "_SC_MQ_OPEN_MAX", header: "<unistd.h>".}: cint
+  SC_MQ_PRIO_MAX*{.importc: "_SC_MQ_PRIO_MAX", header: "<unistd.h>".}: cint
+  SC_NGROUPS_MAX*{.importc: "_SC_NGROUPS_MAX", header: "<unistd.h>".}: cint
+  SC_OPEN_MAX*{.importc: "_SC_OPEN_MAX", header: "<unistd.h>".}: cint
+  SC_PAGE_SIZE*{.importc: "_SC_PAGE_SIZE", header: "<unistd.h>".}: cint
+  SC_PRIORITIZED_IO*{.importc: "_SC_PRIORITIZED_IO", header: "<unistd.h>".}: cint
+  SC_PRIORITY_SCHEDULING*{.importc: "_SC_PRIORITY_SCHEDULING",
+    header: "<unistd.h>".}: cint
+  SC_RAW_SOCKETS*{.importc: "_SC_RAW_SOCKETS", header: "<unistd.h>".}: cint
+  SC_RE_DUP_MAX*{.importc: "_SC_RE_DUP_MAX", header: "<unistd.h>".}: cint
+  SC_READER_WRITER_LOCKS*{.importc: "_SC_READER_WRITER_LOCKS",
+    header: "<unistd.h>".}: cint
+  SC_REALTIME_SIGNALS*{.importc: "_SC_REALTIME_SIGNALS",
+    header: "<unistd.h>".}: cint
+  SC_REGEXP*{.importc: "_SC_REGEXP", header: "<unistd.h>".}: cint
+  SC_RTSIG_MAX*{.importc: "_SC_RTSIG_MAX", header: "<unistd.h>".}: cint
+  SC_SAVED_IDS*{.importc: "_SC_SAVED_IDS", header: "<unistd.h>".}: cint
+  SC_SEM_NSEMS_MAX*{.importc: "_SC_SEM_NSEMS_MAX", header: "<unistd.h>".}: cint
+  SC_SEM_VALUE_MAX*{.importc: "_SC_SEM_VALUE_MAX", header: "<unistd.h>".}: cint
+  SC_SEMAPHORES*{.importc: "_SC_SEMAPHORES", header: "<unistd.h>".}: cint
+  SC_SHARED_MEMORY_OBJECTS*{.importc: "_SC_SHARED_MEMORY_OBJECTS",
+    header: "<unistd.h>".}: cint
+  SC_SHELL*{.importc: "_SC_SHELL", header: "<unistd.h>".}: cint
+  SC_SIGQUEUE_MAX*{.importc: "_SC_SIGQUEUE_MAX", header: "<unistd.h>".}: cint
+  SC_SPAWN*{.importc: "_SC_SPAWN", header: "<unistd.h>".}: cint
+  SC_SPIN_LOCKS*{.importc: "_SC_SPIN_LOCKS", header: "<unistd.h>".}: cint
+  SC_SPORADIC_SERVER*{.importc: "_SC_SPORADIC_SERVER",
+    header: "<unistd.h>".}: cint
+  SC_SS_REPL_MAX*{.importc: "_SC_SS_REPL_MAX", header: "<unistd.h>".}: cint
+  SC_STREAM_MAX*{.importc: "_SC_STREAM_MAX", header: "<unistd.h>".}: cint
+  SC_SYMLOOP_MAX*{.importc: "_SC_SYMLOOP_MAX", header: "<unistd.h>".}: cint
+  SC_SYNCHRONIZED_IO*{.importc: "_SC_SYNCHRONIZED_IO",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_ATTR_STACKADDR*{.importc: "_SC_THREAD_ATTR_STACKADDR",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_ATTR_STACKSIZE*{.importc: "_SC_THREAD_ATTR_STACKSIZE",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_CPUTIME*{.importc: "_SC_THREAD_CPUTIME", header: "<unistd.h>".}: cint
+  SC_THREAD_DESTRUCTOR_ITERATIONS*{.importc: "_SC_THREAD_DESTRUCTOR_ITERATIONS",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_KEYS_MAX*{.importc: "_SC_THREAD_KEYS_MAX",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_PRIO_INHERIT*{.importc: "_SC_THREAD_PRIO_INHERIT",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_PRIO_PROTECT*{.importc: "_SC_THREAD_PRIO_PROTECT",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_PRIORITY_SCHEDULING*{.importc: "_SC_THREAD_PRIORITY_SCHEDULING",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_PROCESS_SHARED*{.importc: "_SC_THREAD_PROCESS_SHARED",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_SAFE_FUNCTIONS*{.importc: "_SC_THREAD_SAFE_FUNCTIONS",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_SPORADIC_SERVER*{.importc: "_SC_THREAD_SPORADIC_SERVER",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_STACK_MIN*{.importc: "_SC_THREAD_STACK_MIN",
+    header: "<unistd.h>".}: cint
+  SC_THREAD_THREADS_MAX*{.importc: "_SC_THREAD_THREADS_MAX",
+    header: "<unistd.h>".}: cint
+  SC_THREADS*{.importc: "_SC_THREADS", header: "<unistd.h>".}: cint
+  SC_TIMEOUTS*{.importc: "_SC_TIMEOUTS", header: "<unistd.h>".}: cint
+  SC_TIMER_MAX*{.importc: "_SC_TIMER_MAX", header: "<unistd.h>".}: cint
+  SC_TIMERS*{.importc: "_SC_TIMERS", header: "<unistd.h>".}: cint
+  SC_TRACE*{.importc: "_SC_TRACE", header: "<unistd.h>".}: cint
+  SC_TRACE_EVENT_FILTER*{.importc: "_SC_TRACE_EVENT_FILTER", header: "<unistd.h>".}: cint
+  SC_TRACE_EVENT_NAME_MAX*{.importc: "_SC_TRACE_EVENT_NAME_MAX", header: "<unistd.h>".}: cint
+  SC_TRACE_INHERIT*{.importc: "_SC_TRACE_INHERIT", header: "<unistd.h>".}: cint
+  SC_TRACE_LOG*{.importc: "_SC_TRACE_LOG", header: "<unistd.h>".}: cint
+  SC_TRACE_NAME_MAX*{.importc: "_SC_TRACE_NAME_MAX", header: "<unistd.h>".}: cint
+  SC_TRACE_SYS_MAX*{.importc: "_SC_TRACE_SYS_MAX", header: "<unistd.h>".}: cint
+  SC_TRACE_USER_EVENT_MAX*{.importc: "_SC_TRACE_USER_EVENT_MAX", header: "<unistd.h>".}: cint
+  SC_TTY_NAME_MAX*{.importc: "_SC_TTY_NAME_MAX", header: "<unistd.h>".}: cint
+  SC_TYPED_MEMORY_OBJECTS*{.importc: "_SC_TYPED_MEMORY_OBJECTS", header: "<unistd.h>".}: cint
+  SC_TZNAME_MAX*{.importc: "_SC_TZNAME_MAX", header: "<unistd.h>".}: cint
+  SC_V6_ILP32_OFF32*{.importc: "_SC_V6_ILP32_OFF32", header: "<unistd.h>".}: cint
+  SC_V6_ILP32_OFFBIG*{.importc: "_SC_V6_ILP32_OFFBIG", header: "<unistd.h>".}: cint
+  SC_V6_LP64_OFF64*{.importc: "_SC_V6_LP64_OFF64", header: "<unistd.h>".}: cint
+  SC_V6_LPBIG_OFFBIG*{.importc: "_SC_V6_LPBIG_OFFBIG", header: "<unistd.h>".}: cint
+  SC_VERSION*{.importc: "_SC_VERSION", header: "<unistd.h>".}: cint
+  SC_XBS5_ILP32_OFF32*{.importc: "_SC_XBS5_ILP32_OFF32", header: "<unistd.h>".}: cint
+  SC_XBS5_ILP32_OFFBIG*{.importc: "_SC_XBS5_ILP32_OFFBIG", header: "<unistd.h>".}: cint
+  SC_XBS5_LP64_OFF64*{.importc: "_SC_XBS5_LP64_OFF64", header: "<unistd.h>".}: cint
+  SC_XBS5_LPBIG_OFFBIG*{.importc: "_SC_XBS5_LPBIG_OFFBIG",
+                         header: "<unistd.h>".}: cint
+  SC_XOPEN_CRYPT*{.importc: "_SC_XOPEN_CRYPT", header: "<unistd.h>".}: cint
+  SC_XOPEN_ENH_I18N*{.importc: "_SC_XOPEN_ENH_I18N", header: "<unistd.h>".}: cint
+  SC_XOPEN_LEGACY*{.importc: "_SC_XOPEN_LEGACY", header: "<unistd.h>".}: cint
+  SC_XOPEN_REALTIME*{.importc: "_SC_XOPEN_REALTIME", header: "<unistd.h>".}: cint
+  SC_XOPEN_REALTIME_THREADS*{.importc: "_SC_XOPEN_REALTIME_THREADS",
+                              header: "<unistd.h>".}: cint
+  SC_XOPEN_SHM*{.importc: "_SC_XOPEN_SHM", header: "<unistd.h>".}: cint
+  SC_XOPEN_STREAMS*{.importc: "_SC_XOPEN_STREAMS", header: "<unistd.h>".}: cint
+  SC_XOPEN_UNIX*{.importc: "_SC_XOPEN_UNIX", header: "<unistd.h>".}: cint
+  SC_XOPEN_VERSION*{.importc: "_SC_XOPEN_VERSION", header: "<unistd.h>".}: cint
+  SC_NPROCESSORS_ONLN*{.importc: "_SC_NPROCESSORS_ONLN",
+                        header: "<unistd.h>".}: cint
+
+  SEM_FAILED* {.importc, header: "<semaphore.h>".}: pointer
+  IPC_CREAT* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Create entry if key does not exist.
+  IPC_EXCL* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Fail if key exists.
+  IPC_NOWAIT* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Error if request must wait.
+
+  IPC_PRIVATE* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Private key.
+
+  IPC_RMID* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Remove identifier.
+  IPC_SET* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Set options.
+  IPC_STAT* {.importc, header: "<sys/ipc.h>".}: cint
+    ## Get options.
+
+  S_IFMT* {.importc, header: "<sys/stat.h>".}: cint
+    ## Type of file.
+  S_IFBLK* {.importc, header: "<sys/stat.h>".}: cint
+    ## Block special.
+  S_IFCHR* {.importc, header: "<sys/stat.h>".}: cint
+    ## Character special.
+  S_IFIFO* {.importc, header: "<sys/stat.h>".}: cint
+    ## FIFO special.
+  S_IFREG* {.importc, header: "<sys/stat.h>".}: cint
+    ## Regular.
+  S_IFDIR* {.importc, header: "<sys/stat.h>".}: cint
+    ## Directory.
+  S_IFLNK* {.importc, header: "<sys/stat.h>".}: cint
+    ## Symbolic link.
+  S_IFSOCK* {.importc, header: "<sys/stat.h>".}: cint
+    ## Socket.
+  S_IRWXU* {.importc, header: "<sys/stat.h>".}: cint
+    ## Read, write, execute/search by owner.
+  S_IRUSR* {.importc, header: "<sys/stat.h>".}: cint
+    ## Read permission, owner.
+  S_IWUSR* {.importc, header: "<sys/stat.h>".}: cint
+    ## Write permission, owner.
+  S_IXUSR* {.importc, header: "<sys/stat.h>".}: cint
+    ## Execute/search permission, owner.
+  S_IRWXG* {.importc, header: "<sys/stat.h>".}: cint
+    ## Read, write, execute/search by group.
+  S_IRGRP* {.importc, header: "<sys/stat.h>".}: cint
+    ## Read permission, group.
+  S_IWGRP* {.importc, header: "<sys/stat.h>".}: cint
+    ## Write permission, group.
+  S_IXGRP* {.importc, header: "<sys/stat.h>".}: cint
+    ## Execute/search permission, group.
+  S_IRWXO* {.importc, header: "<sys/stat.h>".}: cint
+    ## Read, write, execute/search by others.
+  S_IROTH* {.importc, header: "<sys/stat.h>".}: cint
+    ## Read permission, others.
+  S_IWOTH* {.importc, header: "<sys/stat.h>".}: cint
+    ## Write permission, others.
+  S_IXOTH* {.importc, header: "<sys/stat.h>".}: cint
+    ## Execute/search permission, others.
+  S_ISUID* {.importc, header: "<sys/stat.h>".}: cint
+    ## Set-user-ID on execution.
+  S_ISGID* {.importc, header: "<sys/stat.h>".}: cint
+    ## Set-group-ID on execution.
+  S_ISVTX* {.importc, header: "<sys/stat.h>".}: cint
+    ## On directories, restricted deletion flag.
+
+  ST_RDONLY* {.importc, header: "<sys/statvfs.h>".}: cint
+    ## Read-only file system.
+  ST_NOSUID* {.importc, header: "<sys/statvfs.h>".}: cint
+    ## Does not support the semantics of the ST_ISUID and ST_ISGID file mode bits.
+
+  PROT_READ* {.importc, header: "<sys/mman.h>".}: cint
+    ## Page can be read.
+  PROT_WRITE* {.importc, header: "<sys/mman.h>".}: cint
+    ## Page can be written.
+  PROT_EXEC* {.importc, header: "<sys/mman.h>".}: cint
+    ## Page can be executed.
+  PROT_NONE* {.importc, header: "<sys/mman.h>".}: cint
+    ## Page cannot be accessed.
+  MAP_SHARED* {.importc, header: "<sys/mman.h>".}: cint
+    ## Share changes.
+  MAP_PRIVATE* {.importc, header: "<sys/mman.h>".}: cint
+    ## Changes are private.
+  MAP_FIXED* {.importc, header: "<sys/mman.h>".}: cint
+    ## Interpret addr exactly.
+  MS_ASYNC* {.importc, header: "<sys/mman.h>".}: cint
+    ## Perform asynchronous writes.
+  MS_SYNC* {.importc, header: "<sys/mman.h>".}: cint
+    ## Perform synchronous writes.
+  MS_INVALIDATE* {.importc, header: "<sys/mman.h>".}: cint
+    ## Invalidate mappings.
+  MCL_CURRENT* {.importc, header: "<sys/mman.h>".}: cint
+    ## Lock currently mapped pages.
+  MCL_FUTURE* {.importc, header: "<sys/mman.h>".}: cint
+    ## Lock pages that become mapped.
+  MAP_FAILED* {.importc, header: "<sys/mman.h>".}: cint
+  POSIX_MADV_NORMAL* {.importc, header: "<sys/mman.h>".}: cint
+    ## The application has no advice to give on its behavior with
+    ## respect to the specified range. It is the default characteristic
+    ## if no advice is given for a range of memory.
+  POSIX_MADV_SEQUENTIAL* {.importc, header: "<sys/mman.h>".}: cint
+    ## The application expects to access the specified range sequentially
+    ## from lower addresses to higher addresses.
+  POSIX_MADV_RANDOM* {.importc, header: "<sys/mman.h>".}: cint
+    ## The application expects to access the specified range in a random order.
+  POSIX_MADV_WILLNEED* {.importc, header: "<sys/mman.h>".}: cint
+    ## The application expects to access the specified range in the near future.
+  POSIX_MADV_DONTNEED* {.importc, header: "<sys/mman.h>".}: cint
+  POSIX_TYPED_MEM_ALLOCATE* {.importc, header: "<sys/mman.h>".}: cint
+  POSIX_TYPED_MEM_ALLOCATE_CONTIG* {.importc, header: "<sys/mman.h>".}: cint
+  POSIX_TYPED_MEM_MAP_ALLOCATABLE* {.importc, header: "<sys/mman.h>".}: cint
+
+
+  CLOCKS_PER_SEC* {.importc, header: "<time.h>".}: int
+    ## A number used to convert the value returned by the clock() function
+    ## into seconds.
+  CLOCK_PROCESS_CPUTIME_ID* {.importc, header: "<time.h>".}: cint
+    ## The identifier of the CPU-time clock associated with the process
+    ## making a clock() or timer*() function call.
+  CLOCK_THREAD_CPUTIME_ID* {.importc, header: "<time.h>".}: cint
+  CLOCK_REALTIME* {.importc, header: "<time.h>".}: cint
+    ## The identifier of the system-wide realtime clock.
+  TIMER_ABSTIME* {.importc, header: "<time.h>".}: cint
+    ## Flag indicating time is absolute. For functions taking timer
+    ## objects, this refers to the clock associated with the timer.
+  CLOCK_MONOTONIC* {.importc, header: "<time.h>".}: cint
+
+  WNOHANG* {.importc, header: "<sys/wait.h>".}: cint
+    ## Do not hang if no status is available; return immediately.
+  WUNTRACED* {.importc, header: "<sys/wait.h>".}: cint
+    ## Report status of stopped child process.
+  WEXITSTATUS* {.importc, header: "<sys/wait.h>".}: cint
+    ## Return exit status.
+  WSTOPSIG* {.importc, header: "<sys/wait.h>".}: cint
+    ## Return signal number that caused process to stop.
+  WTERMSIG* {.importc, header: "<sys/wait.h>".}: cint
+    ## Return signal number that caused process to terminate.
+  WEXITED* {.importc, header: "<sys/wait.h>".}: cint
+    ## Wait for processes that have exited.
+  WSTOPPED* {.importc, header: "<sys/wait.h>".}: cint
+    ## Status is returned for any child that has stopped upon receipt
+    ## of a signal.
+  WCONTINUED* {.importc, header: "<sys/wait.h>".}: cint
+    ## Status is returned for any child that was stopped and has been continued.
+  WNOWAIT* {.importc, header: "<sys/wait.h>".}: cint
+    ## Keep the process whose status is returned in infop in a waitable state.
+  P_ALL* {.importc, header: "<sys/wait.h>".}: cint
+  P_PID* {.importc, header: "<sys/wait.h>".}: cint
+  P_PGID* {.importc, header: "<sys/wait.h>".}: cint
+
+  SIG_DFL* {.importc, header: "<signal.h>".}: proc (x: cint) {.noconv.}
+    ## Request for default signal handling.
+  SIG_ERR* {.importc, header: "<signal.h>".}: proc (x: cint) {.noconv.}
+    ## Return value from signal() in case of error.
+  cSIG_HOLD* {.importc: "SIG_HOLD",
+    header: "<signal.h>".}: proc (x: cint) {.noconv.}
+    ## Request that signal be held.
+  SIG_IGN* {.importc, header: "<signal.h>".}: proc (x: cint) {.noconv.}
+    ## Request that signal be ignored.
+
+  SIGEV_NONE* {.importc, header: "<signal.h>".}: cint
+  SIGEV_SIGNAL* {.importc, header: "<signal.h>".}: cint
+  SIGEV_THREAD* {.importc, header: "<signal.h>".}: cint
+  SIGABRT* {.importc, header: "<signal.h>".}: cint
+  SIGALRM* {.importc, header: "<signal.h>".}: cint
+  SIGBUS* {.importc, header: "<signal.h>".}: cint
+  SIGCHLD* {.importc, header: "<signal.h>".}: cint
+  SIGCONT* {.importc, header: "<signal.h>".}: cint
+  SIGFPE* {.importc, header: "<signal.h>".}: cint
+  SIGHUP* {.importc, header: "<signal.h>".}: cint
+  SIGILL* {.importc, header: "<signal.h>".}: cint
+  SIGINT* {.importc, header: "<signal.h>".}: cint
+  SIGKILL* {.importc, header: "<signal.h>".}: cint
+  SIGPIPE* {.importc, header: "<signal.h>".}: cint
+  SIGQUIT* {.importc, header: "<signal.h>".}: cint
+  SIGSEGV* {.importc, header: "<signal.h>".}: cint
+  SIGSTOP* {.importc, header: "<signal.h>".}: cint
+  SIGTERM* {.importc, header: "<signal.h>".}: cint
+  SIGTSTP* {.importc, header: "<signal.h>".}: cint
+  SIGTTIN* {.importc, header: "<signal.h>".}: cint
+  SIGTTOU* {.importc, header: "<signal.h>".}: cint
+  SIGUSR1* {.importc, header: "<signal.h>".}: cint
+  SIGUSR2* {.importc, header: "<signal.h>".}: cint
+  SIGPOLL* {.importc, header: "<signal.h>".}: cint
+  SIGPROF* {.importc, header: "<signal.h>".}: cint
+  SIGSYS* {.importc, header: "<signal.h>".}: cint
+  SIGTRAP* {.importc, header: "<signal.h>".}: cint
+  SIGURG* {.importc, header: "<signal.h>".}: cint
+  SIGVTALRM* {.importc, header: "<signal.h>".}: cint
+  SIGXCPU* {.importc, header: "<signal.h>".}: cint
+  SIGXFSZ* {.importc, header: "<signal.h>".}: cint
+  SA_NOCLDSTOP* {.importc, header: "<signal.h>".}: cint
+  SIG_BLOCK* {.importc, header: "<signal.h>".}: cint
+  SIG_UNBLOCK* {.importc, header: "<signal.h>".}: cint
+  SIG_SETMASK* {.importc, header: "<signal.h>".}: cint
+  SA_ONSTACK* {.importc, header: "<signal.h>".}: cint
+  SA_RESETHAND* {.importc, header: "<signal.h>".}: cint
+  SA_RESTART* {.importc, header: "<signal.h>".}: cint
+  SA_SIGINFO* {.importc, header: "<signal.h>".}: cint
+  SA_NOCLDWAIT* {.importc, header: "<signal.h>".}: cint
+  SA_NODEFER* {.importc, header: "<signal.h>".}: cint
+  SS_ONSTACK* {.importc, header: "<signal.h>".}: cint
+  SS_DISABLE* {.importc, header: "<signal.h>".}: cint
+  MINSIGSTKSZ* {.importc, header: "<signal.h>".}: cint
+  SIGSTKSZ* {.importc, header: "<signal.h>".}: cint
+
+  NL_SETD* {.importc, header: "<nl_types.h>".}: cint
+  NL_CAT_LOCALE* {.importc, header: "<nl_types.h>".}: cint
+
+  SCHED_FIFO* {.importc, header: "<sched.h>".}: cint
+  SCHED_RR* {.importc, header: "<sched.h>".}: cint
+  SCHED_SPORADIC* {.importc, header: "<sched.h>".}: cint
+  SCHED_OTHER* {.importc, header: "<sched.h>".}: cint
+  FD_SETSIZE* {.importc, header: "<sys/select.h>".}: cint
+
+  SEEK_SET* {.importc, header: "<unistd.h>".}: cint
+  SEEK_CUR* {.importc, header: "<unistd.h>".}: cint
+  SEEK_END* {.importc, header: "<unistd.h>".}: cint
+
+  SCM_RIGHTS* {.importc, header: "<sys/socket.h>".}: cint
+    ## Indicates that the data array contains the access rights
+    ## to be sent or received.
+
+  SOCK_DGRAM* {.importc, header: "<sys/socket.h>".}: cint ## Datagram socket.
+  SOCK_RAW* {.importc, header: "<sys/socket.h>".}: cint
+    ## Raw Protocol Interface.
+  SOCK_SEQPACKET* {.importc, header: "<sys/socket.h>".}: cint
+    ## Sequenced-packet socket.
+  SOCK_STREAM* {.importc, header: "<sys/socket.h>".}: cint
+    ## Byte-stream socket.
+
+  SOL_SOCKET* {.importc, header: "<sys/socket.h>".}: cint
+    ## Options to be accessed at socket level, not protocol level.
+
+  SO_ACCEPTCONN* {.importc, header: "<sys/socket.h>".}: cint
+    ## Socket is accepting connections.
+  SO_BROADCAST* {.importc, header: "<sys/socket.h>".}: cint
+    ## Transmission of broadcast messages is supported.
+  SO_DEBUG* {.importc, header: "<sys/socket.h>".}: cint
+    ## Debugging information is being recorded.
+  SO_DONTROUTE* {.importc, header: "<sys/socket.h>".}: cint
+    ## Bypass normal routing.
+  SO_ERROR* {.importc, header: "<sys/socket.h>".}: cint
+    ## Socket error status.
+  SO_KEEPALIVE* {.importc, header: "<sys/socket.h>".}: cint
+    ## Connections are kept alive with periodic messages.
+  SO_LINGER* {.importc, header: "<sys/socket.h>".}: cint
+    ## Socket lingers on close.
+  SO_OOBINLINE* {.importc, header: "<sys/socket.h>".}: cint
+    ## Out-of-band data is transmitted in line.
+  SO_RCVBUF* {.importc, header: "<sys/socket.h>".}: cint
+    ## Receive buffer size.
+  SO_RCVLOWAT* {.importc, header: "<sys/socket.h>".}: cint
+    ## Receive *low water mark*.
+  SO_RCVTIMEO* {.importc, header: "<sys/socket.h>".}: cint
+    ## Receive timeout.
+  SO_REUSEADDR* {.importc, header: "<sys/socket.h>".}: cint
+    ## Reuse of local addresses is supported.
+  SO_SNDBUF* {.importc, header: "<sys/socket.h>".}: cint
+    ## Send buffer size.
+  SO_SNDLOWAT* {.importc, header: "<sys/socket.h>".}: cint
+    ## Send *low water mark*.
+  SO_SNDTIMEO* {.importc, header: "<sys/socket.h>".}: cint
+    ## Send timeout.
+  SO_TYPE* {.importc, header: "<sys/socket.h>".}: cint
+    ## Socket type.
+
+  SOMAXCONN* {.importc, header: "<sys/socket.h>".}: cint
+    ## The maximum backlog queue length.
+
+  MSG_CTRUNC* {.importc, header: "<sys/socket.h>".}: cint
+    ## Control data truncated.
+  MSG_DONTROUTE* {.importc, header: "<sys/socket.h>".}: cint
+    ## Send without using routing tables.
+  MSG_EOR* {.importc, header: "<sys/socket.h>".}: cint
+    ## Terminates a record (if supported by the protocol).
+  MSG_OOB* {.importc, header: "<sys/socket.h>".}: cint
+    ## Out-of-band data.
+
+proc WIFCONTINUED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child has been continued.
+proc WIFEXITED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child exited normally.
+proc WIFSIGNALED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child exited due to uncaught signal.
+proc WIFSTOPPED*(s:cint) : bool {.importc, header: "<sys/wait.h>".}
+  ## True if child is currently stopped.
+
+when defined(linux):
+  var
+    MAP_POPULATE* {.importc, header: "<sys/mman.h>".}: cint
+      ## Populate (prefault) page tables for a mapping.
+else:
+  var
+    MAP_POPULATE*: cint = 0
+
+
+when defined(macosx):
+  # We can't use the NOSIGNAL flag in the ``send`` function, it has no effect
+  # Instead we should use SO_NOSIGPIPE in setsockopt
+  const
+    MSG_NOSIGNAL* = 0'i32
+  var
+    SO_NOSIGPIPE* {.importc, header: "<sys/socket.h>".}: cint
+else:
+  var
+    MSG_NOSIGNAL* {.importc, header: "<sys/socket.h>".}: cint
+      ## No SIGPIPE generated when an attempt to send is made on a stream-oriented socket that is no longer connected.
+
+var
+  MSG_PEEK* {.importc, header: "<sys/socket.h>".}: cint
+    ## Leave received data in queue.
+  MSG_TRUNC* {.importc, header: "<sys/socket.h>".}: cint
+    ## Normal data truncated.
+  MSG_WAITALL* {.importc, header: "<sys/socket.h>".}: cint
+    ## Attempt to fill the read buffer.
+
+  AF_INET* {.importc, header: "<sys/socket.h>".}: cint
+    ## Internet domain sockets for use with IPv4 addresses.
+  AF_INET6* {.importc, header: "<sys/socket.h>".}: cint
+    ## Internet domain sockets for use with IPv6 addresses.
+  AF_UNIX* {.importc, header: "<sys/socket.h>".}: cint
+    ## UNIX domain sockets.
+  AF_UNSPEC* {.importc, header: "<sys/socket.h>".}: cint
+    ## Unspecified.
+
+  SHUT_RD* {.importc, header: "<sys/socket.h>".}: cint
+    ## Disables further receive operations.
+  SHUT_RDWR* {.importc, header: "<sys/socket.h>".}: cint
+    ## Disables further send and receive operations.
+  SHUT_WR* {.importc, header: "<sys/socket.h>".}: cint
+    ## Disables further send operations.
+
+  IF_NAMESIZE* {.importc, header: "<net/if.h>".}: cint
+
+  IPPROTO_IP* {.importc, header: "<netinet/in.h>".}: cint
+    ## Internet protocol.
+  IPPROTO_IPV6* {.importc, header: "<netinet/in.h>".}: cint
+    ## Internet Protocol Version 6.
+  IPPROTO_ICMP* {.importc, header: "<netinet/in.h>".}: cint
+    ## Control message protocol.
+  IPPROTO_RAW* {.importc, header: "<netinet/in.h>".}: cint
+    ## Raw IP Packets Protocol.
+  IPPROTO_TCP* {.importc, header: "<netinet/in.h>".}: cint
+    ## Transmission control protocol.
+  IPPROTO_UDP* {.importc, header: "<netinet/in.h>".}: cint
+    ## User datagram protocol.
+
+  INADDR_ANY* {.importc, header: "<netinet/in.h>".}: TInAddrScalar
+    ## IPv4 local host address.
+  INADDR_BROADCAST* {.importc, header: "<netinet/in.h>".}: TInAddrScalar
+    ## IPv4 broadcast address.
+
+  INET_ADDRSTRLEN* {.importc, header: "<netinet/in.h>".}: cint
+    ## 16. Length of the string form for IP.
+
+  IPV6_JOIN_GROUP* {.importc, header: "<netinet/in.h>".}: cint
+    ## Join a multicast group.
+  IPV6_LEAVE_GROUP* {.importc, header: "<netinet/in.h>".}: cint
+    ## Quit a multicast group.
+  IPV6_MULTICAST_HOPS* {.importc, header: "<netinet/in.h>".}: cint
+    ## Multicast hop limit.
+  IPV6_MULTICAST_IF* {.importc, header: "<netinet/in.h>".}: cint
+    ## Interface to use for outgoing multicast packets.
+  IPV6_MULTICAST_LOOP* {.importc, header: "<netinet/in.h>".}: cint
+    ## Multicast packets are delivered back to the local application.
+  IPV6_UNICAST_HOPS* {.importc, header: "<netinet/in.h>".}: cint
+    ## Unicast hop limit.
+  IPV6_V6ONLY* {.importc, header: "<netinet/in.h>".}: cint
+    ## Restrict AF_INET6 socket to IPv6 communications only.
+
+  TCP_NODELAY* {.importc, header: "<netinet/tcp.h>".}: cint
+    ## Avoid coalescing of small segments.
+
+  IPPORT_RESERVED* {.importc, header: "<netdb.h>".}: cint
+
+  HOST_NOT_FOUND* {.importc, header: "<netdb.h>".}: cint
+  NO_DATA* {.importc, header: "<netdb.h>".}: cint
+  NO_RECOVERY* {.importc, header: "<netdb.h>".}: cint
+  TRY_AGAIN* {.importc, header: "<netdb.h>".}: cint
+
+  AI_PASSIVE* {.importc, header: "<netdb.h>".}: cint
+    ## Socket address is intended for bind().
+  AI_CANONNAME* {.importc, header: "<netdb.h>".}: cint
+    ## Request for canonical name.
+  AI_NUMERICHOST* {.importc, header: "<netdb.h>".}: cint
+    ## Return numeric host address as name.
+  AI_NUMERICSERV* {.importc, header: "<netdb.h>".}: cint
+    ## Inhibit service name resolution.
+  AI_V4MAPPED* {.importc, header: "<netdb.h>".}: cint
+     ## If no IPv6 addresses are found, query for IPv4 addresses and
+     ## return them to the caller as IPv4-mapped IPv6 addresses.
+  AI_ALL* {.importc, header: "<netdb.h>".}: cint
+    ## Query for both IPv4 and IPv6 addresses.
+  AI_ADDRCONFIG* {.importc, header: "<netdb.h>".}: cint
+    ## Query for IPv4 addresses only when an IPv4 address is configured;
+    ## query for IPv6 addresses only when an IPv6 address is configured.
+
+  NI_NOFQDN* {.importc, header: "<netdb.h>".}: cint
+    ## Only the nodename portion of the FQDN is returned for local hosts.
+  NI_NUMERICHOST* {.importc, header: "<netdb.h>".}: cint
+    ## The numeric form of the node's address is returned instead of its name.
+  NI_NAMEREQD* {.importc, header: "<netdb.h>".}: cint
+    ## Return an error if the node's name cannot be located in the database.
+  NI_NUMERICSERV* {.importc, header: "<netdb.h>".}: cint
+    ## The numeric form of the service address is returned instead of its name.
+  NI_NUMERICSCOPE* {.importc, header: "<netdb.h>".}: cint
+    ## For IPv6 addresses, the numeric form of the scope identifier is
+    ## returned instead of its name.
+  NI_DGRAM* {.importc, header: "<netdb.h>".}: cint
+    ## Indicates that the service is a datagram service (SOCK_DGRAM).
+
+  EAI_AGAIN* {.importc, header: "<netdb.h>".}: cint
+    ## The name could not be resolved at this time. Future attempts may succeed.
+  EAI_BADFLAGS* {.importc, header: "<netdb.h>".}: cint
+    ## The flags had an invalid value.
+  EAI_FAIL* {.importc, header: "<netdb.h>".}: cint
+    ## A non-recoverable error occurred.
+  EAI_FAMILY* {.importc, header: "<netdb.h>".}: cint
+    ## The address family was not recognized or the address length
+    ## was invalid for the specified family.
+  EAI_MEMORY* {.importc, header: "<netdb.h>".}: cint
+    ## There was a memory allocation failure.
+  EAI_NONAME* {.importc, header: "<netdb.h>".}: cint
+    ## The name does not resolve for the supplied parameters.
+    ## NI_NAMEREQD is set and the host's name cannot be located,
+    ## or both nodename and servname were null.
+  EAI_SERVICE* {.importc, header: "<netdb.h>".}: cint
+    ## The service passed was not recognized for the specified socket type.
+  EAI_SOCKTYPE* {.importc, header: "<netdb.h>".}: cint
+    ## The intended socket type was not recognized.
+  EAI_SYSTEM* {.importc, header: "<netdb.h>".}: cint
+    ## A system error occurred. The error code can be found in errno.
+  EAI_OVERFLOW* {.importc, header: "<netdb.h>".}: cint
+    ## An argument buffer overflowed.
+
+  POLLIN* {.importc, header: "<poll.h>".}: cshort
+    ## Data other than high-priority data may be read without blocking.
+  POLLRDNORM* {.importc, header: "<poll.h>".}: cshort
+    ## Normal data may be read without blocking.
+  POLLRDBAND* {.importc, header: "<poll.h>".}: cshort
+    ## Priority data may be read without blocking.
+  POLLPRI* {.importc, header: "<poll.h>".}: cshort
+    ## High priority data may be read without blocking.
+  POLLOUT* {.importc, header: "<poll.h>".}: cshort
+    ## Normal data may be written without blocking.
+  POLLWRNORM* {.importc, header: "<poll.h>".}: cshort
+    ## Equivalent to POLLOUT.
+  POLLWRBAND* {.importc, header: "<poll.h>".}: cshort
+    ## Priority data may be written.
+  POLLERR* {.importc, header: "<poll.h>".}: cshort
+    ## An error has occurred (revents only).
+  POLLHUP* {.importc, header: "<poll.h>".}: cshort
+    ## Device has been disconnected (revents only).
+  POLLNVAL* {.importc, header: "<poll.h>".}: cshort
+    ## Invalid fd member (revents only).
+
+
+when hasSpawnH:
+  var
+    POSIX_SPAWN_RESETIDS* {.importc, header: "<spawn.h>".}: cint
+    POSIX_SPAWN_SETPGROUP* {.importc, header: "<spawn.h>".}: cint
+    POSIX_SPAWN_SETSCHEDPARAM* {.importc, header: "<spawn.h>".}: cint
+    POSIX_SPAWN_SETSCHEDULER* {.importc, header: "<spawn.h>".}: cint
+    POSIX_SPAWN_SETSIGDEF* {.importc, header: "<spawn.h>".}: cint
+    POSIX_SPAWN_SETSIGMASK* {.importc, header: "<spawn.h>".}: cint
+
+  when defined(linux):
+    # better be safe than sorry; Linux has this flag, macosx doesn't, don't
+    # know about the other OSes
+
+    # Non-GNU systems like TCC and musl-libc  don't define __USE_GNU, so we
+    # can't get the magic number from spawn.h
+    const POSIX_SPAWN_USEVFORK* = cint(0x40)
+  else:
+    # macosx lacks this, so we define the constant to be 0 to not affect
+    # OR'ing of flags:
+    const POSIX_SPAWN_USEVFORK* = cint(0)
+
+when hasAioH:
+  proc aio_cancel*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "<aio.h>".}
+  proc aio_error*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
+  proc aio_fsync*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "<aio.h>".}
+  proc aio_read*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
+  proc aio_return*(a1: ptr Taiocb): int {.importc, header: "<aio.h>".}
+  proc aio_suspend*(a1: ptr ptr Taiocb, a2: cint, a3: ptr Ttimespec): cint {.
+                   importc, header: "<aio.h>".}
+  proc aio_write*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
+  proc lio_listio*(a1: cint, a2: ptr ptr Taiocb, a3: cint,
+               a4: ptr TsigEvent): cint {.importc, header: "<aio.h>".}
+
+# arpa/inet.h
+proc htonl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
+proc htons*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
+proc ntohl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
+proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".}
+
+proc inet_addr*(a1: cstring): TInAddrT {.importc, header: "<arpa/inet.h>".}
+proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".}
+proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {.
+  importc, header: "<arpa/inet.h>".}
+proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {.
+  importc, header: "<arpa/inet.h>".}
+
+var
+  in6addr_any* {.importc, header: "<netinet/in.h>".}: TIn6Addr
+  in6addr_loopback* {.importc, header: "<netinet/in.h>".}: TIn6Addr
+
+proc IN6ADDR_ANY_INIT* (): TIn6Addr {.importc, header: "<netinet/in.h>".}
+proc IN6ADDR_LOOPBACK_INIT* (): TIn6Addr {.importc, header: "<netinet/in.h>".}
+
+# dirent.h
+proc closedir*(a1: ptr TDIR): cint  {.importc, header: "<dirent.h>".}
+proc opendir*(a1: cstring): ptr TDIR {.importc, header: "<dirent.h>".}
+proc readdir*(a1: ptr TDIR): ptr Tdirent  {.importc, header: "<dirent.h>".}
+proc readdir_r*(a1: ptr TDIR, a2: ptr Tdirent, a3: ptr ptr Tdirent): cint  {.
+                importc, header: "<dirent.h>".}
+proc rewinddir*(a1: ptr TDIR)  {.importc, header: "<dirent.h>".}
+proc seekdir*(a1: ptr TDIR, a2: int)  {.importc, header: "<dirent.h>".}
+proc telldir*(a1: ptr TDIR): int {.importc, header: "<dirent.h>".}
+
+# dlfcn.h
+proc dlclose*(a1: pointer): cint {.importc, header: "<dlfcn.h>".}
+proc dlerror*(): cstring {.importc, header: "<dlfcn.h>".}
+proc dlopen*(a1: cstring, a2: cint): pointer {.importc, header: "<dlfcn.h>".}
+proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
+
+proc creat*(a1: cstring, a2: TMode): cint {.importc, header: "<fcntl.h>".}
+proc fcntl*(a1: cint | SocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
+proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
+proc posix_fadvise*(a1: cint, a2, a3: TOff, a4: cint): cint {.
+  importc, header: "<fcntl.h>".}
+proc posix_fallocate*(a1: cint, a2, a3: TOff): cint {.
+  importc, header: "<fcntl.h>".}
+
+when not defined(haiku) and not defined(OpenBSD):
+  proc fmtmsg*(a1: int, a2: cstring, a3: cint,
+              a4, a5, a6: cstring): cint {.importc, header: "<fmtmsg.h>".}
+
+proc fnmatch*(a1, a2: cstring, a3: cint): cint {.importc, header: "<fnmatch.h>".}
+proc ftw*(a1: cstring,
+         a2: proc (x1: cstring, x2: ptr TStat, x3: cint): cint {.noconv.},
+         a3: cint): cint {.importc, header: "<ftw.h>".}
+proc nftw*(a1: cstring,
+          a2: proc (x1: cstring, x2: ptr TStat,
+                    x3: cint, x4: ptr TFTW): cint {.noconv.},
+          a3: cint,
+          a4: cint): cint {.importc, header: "<ftw.h>".}
+
+proc glob*(a1: cstring, a2: cint,
+          a3: proc (x1: cstring, x2: cint): cint {.noconv.},
+          a4: ptr TGlob): cint {.importc, header: "<glob.h>".}
+proc globfree*(a1: ptr TGlob) {.importc, header: "<glob.h>".}
+
+proc getgrgid*(a1: TGid): ptr TGroup {.importc, header: "<grp.h>".}
+proc getgrnam*(a1: cstring): ptr TGroup {.importc, header: "<grp.h>".}
+proc getgrgid_r*(a1: TGid, a2: ptr TGroup, a3: cstring, a4: int,
+                 a5: ptr ptr TGroup): cint {.importc, header: "<grp.h>".}
+proc getgrnam_r*(a1: cstring, a2: ptr TGroup, a3: cstring,
+                  a4: int, a5: ptr ptr TGroup): cint {.
+                 importc, header: "<grp.h>".}
+proc getgrent*(): ptr TGroup {.importc, header: "<grp.h>".}
+proc endgrent*() {.importc, header: "<grp.h>".}
+proc setgrent*() {.importc, header: "<grp.h>".}
+
+
+proc iconv_open*(a1, a2: cstring): Ticonv {.importc, header: "<iconv.h>".}
+proc iconv*(a1: Ticonv, a2: var cstring, a3: var int, a4: var cstring,
+            a5: var int): int {.importc, header: "<iconv.h>".}
+proc iconv_close*(a1: Ticonv): cint {.importc, header: "<iconv.h>".}
+
+proc nl_langinfo*(a1: Tnl_item): cstring {.importc, header: "<langinfo.h>".}
+
+proc basename*(a1: cstring): cstring {.importc, header: "<libgen.h>".}
+proc dirname*(a1: cstring): cstring {.importc, header: "<libgen.h>".}
+
+proc localeconv*(): ptr Tlconv {.importc, header: "<locale.h>".}
+proc setlocale*(a1: cint, a2: cstring): cstring {.
+                importc, header: "<locale.h>".}
+
+proc strfmon*(a1: cstring, a2: int, a3: cstring): int {.varargs,
+   importc, header: "<monetary.h>".}
+
+proc mq_close*(a1: TMqd): cint {.importc, header: "<mqueue.h>".}
+proc mq_getattr*(a1: TMqd, a2: ptr TMqAttr): cint {.
+  importc, header: "<mqueue.h>".}
+proc mq_notify*(a1: TMqd, a2: ptr TsigEvent): cint {.
+  importc, header: "<mqueue.h>".}
+proc mq_open*(a1: cstring, a2: cint): TMqd {.
+  varargs, importc, header: "<mqueue.h>".}
+proc mq_receive*(a1: TMqd, a2: cstring, a3: int, a4: var int): int {.
+  importc, header: "<mqueue.h>".}
+proc mq_send*(a1: TMqd, a2: cstring, a3: int, a4: int): cint {.
+  importc, header: "<mqueue.h>".}
+proc mq_setattr*(a1: TMqd, a2, a3: ptr TMqAttr): cint {.
+  importc, header: "<mqueue.h>".}
+
+proc mq_timedreceive*(a1: TMqd, a2: cstring, a3: int, a4: int,
+                      a5: ptr Ttimespec): int {.importc, header: "<mqueue.h>".}
+proc mq_timedsend*(a1: TMqd, a2: cstring, a3: int, a4: int,
+                   a5: ptr Ttimespec): cint {.importc, header: "<mqueue.h>".}
+proc mq_unlink*(a1: cstring): cint {.importc, header: "<mqueue.h>".}
+
+
+proc getpwnam*(a1: cstring): ptr TPasswd {.importc, header: "<pwd.h>".}
+proc getpwuid*(a1: Tuid): ptr TPasswd {.importc, header: "<pwd.h>".}
+proc getpwnam_r*(a1: cstring, a2: ptr TPasswd, a3: cstring, a4: int,
+                 a5: ptr ptr TPasswd): cint {.importc, header: "<pwd.h>".}
+proc getpwuid_r*(a1: Tuid, a2: ptr TPasswd, a3: cstring,
+      a4: int, a5: ptr ptr TPasswd): cint {.importc, header: "<pwd.h>".}
+proc endpwent*() {.importc, header: "<pwd.h>".}
+proc getpwent*(): ptr TPasswd {.importc, header: "<pwd.h>".}
+proc setpwent*() {.importc, header: "<pwd.h>".}
+
+proc uname*(a1: var Tutsname): cint {.importc, header: "<sys/utsname.h>".}
+
+proc pthread_atfork*(a1, a2, a3: proc () {.noconv.}): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_destroy*(a1: ptr Tpthread_attr): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_getdetachstate*(a1: ptr Tpthread_attr, a2: cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_getguardsize*(a1: ptr Tpthread_attr, a2: var cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_getinheritsched*(a1: ptr Tpthread_attr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_getschedparam*(a1: ptr Tpthread_attr,
+          a2: ptr Tsched_param): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_getschedpolicy*(a1: ptr Tpthread_attr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_getscope*(a1: ptr Tpthread_attr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_getstack*(a1: ptr Tpthread_attr,
+         a2: var pointer, a3: var int): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_getstackaddr*(a1: ptr Tpthread_attr,
+          a2: var pointer): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_getstacksize*(a1: ptr Tpthread_attr,
+          a2: var int): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_init*(a1: ptr Tpthread_attr): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setdetachstate*(a1: ptr Tpthread_attr, a2: cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setguardsize*(a1: ptr Tpthread_attr, a2: int): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setinheritsched*(a1: ptr Tpthread_attr, a2: cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setschedparam*(a1: ptr Tpthread_attr,
+          a2: ptr Tsched_param): cint {.importc, header: "<pthread.h>".}
+proc pthread_attr_setschedpolicy*(a1: ptr Tpthread_attr, a2: cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setscope*(a1: ptr Tpthread_attr, a2: cint): cint {.importc,
+  header: "<pthread.h>".}
+proc pthread_attr_setstack*(a1: ptr Tpthread_attr, a2: pointer, a3: int): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setstackaddr*(a1: ptr Tpthread_attr, a2: pointer): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_attr_setstacksize*(a1: ptr Tpthread_attr, a2: int): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_barrier_destroy*(a1: ptr Tpthread_barrier): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_barrier_init*(a1: ptr Tpthread_barrier,
+         a2: ptr Tpthread_barrierattr, a3: cint): cint {.
+         importc, header: "<pthread.h>".}
+proc pthread_barrier_wait*(a1: ptr Tpthread_barrier): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_barrierattr_destroy*(a1: ptr Tpthread_barrierattr): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_barrierattr_getpshared*(
+          a1: ptr Tpthread_barrierattr, a2: var cint): cint {.
+          importc, header: "<pthread.h>".}
+proc pthread_barrierattr_init*(a1: ptr Tpthread_barrierattr): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_barrierattr_setpshared*(a1: ptr Tpthread_barrierattr,
+  a2: cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_cancel*(a1: Tpthread): cint {.importc, header: "<pthread.h>".}
+proc pthread_cleanup_push*(a1: proc (x: pointer) {.noconv.}, a2: pointer) {.
+  importc, header: "<pthread.h>".}
+proc pthread_cleanup_pop*(a1: cint) {.importc, header: "<pthread.h>".}
+proc pthread_cond_broadcast*(a1: ptr Tpthread_cond): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_cond_destroy*(a1: ptr Tpthread_cond): cint {.importc, header: "<pthread.h>".}
+proc pthread_cond_init*(a1: ptr Tpthread_cond,
+          a2: ptr Tpthread_condattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_cond_signal*(a1: ptr Tpthread_cond): cint {.importc, header: "<pthread.h>".}
+proc pthread_cond_timedwait*(a1: ptr Tpthread_cond,
+          a2: ptr Tpthread_mutex, a3: ptr Ttimespec): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_cond_wait*(a1: ptr Tpthread_cond,
+          a2: ptr Tpthread_mutex): cint {.importc, header: "<pthread.h>".}
+proc pthread_condattr_destroy*(a1: ptr Tpthread_condattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_condattr_getclock*(a1: ptr Tpthread_condattr,
+          a2: var TClockId): cint {.importc, header: "<pthread.h>".}
+proc pthread_condattr_getpshared*(a1: ptr Tpthread_condattr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_condattr_init*(a1: ptr Tpthread_condattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_condattr_setclock*(a1: ptr Tpthread_condattr,a2: TClockId): cint {.importc, header: "<pthread.h>".}
+proc pthread_condattr_setpshared*(a1: ptr Tpthread_condattr, a2: cint): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_create*(a1: ptr Tpthread, a2: ptr Tpthread_attr,
+          a3: proc (x: pointer): pointer {.noconv.}, a4: pointer): cint {.importc, header: "<pthread.h>".}
+proc pthread_detach*(a1: Tpthread): cint {.importc, header: "<pthread.h>".}
+proc pthread_equal*(a1, a2: Tpthread): cint {.importc, header: "<pthread.h>".}
+proc pthread_exit*(a1: pointer) {.importc, header: "<pthread.h>".}
+proc pthread_getconcurrency*(): cint {.importc, header: "<pthread.h>".}
+proc pthread_getcpuclockid*(a1: Tpthread, a2: var TClockId): cint {.importc, header: "<pthread.h>".}
+proc pthread_getschedparam*(a1: Tpthread,  a2: var cint,
+          a3: ptr Tsched_param): cint {.importc, header: "<pthread.h>".}
+proc pthread_getspecific*(a1: Tpthread_key): pointer {.importc, header: "<pthread.h>".}
+proc pthread_join*(a1: Tpthread, a2: ptr pointer): cint {.importc, header: "<pthread.h>".}
+proc pthread_key_create*(a1: ptr Tpthread_key, a2: proc (x: pointer) {.noconv.}): cint {.importc, header: "<pthread.h>".}
+proc pthread_key_delete*(a1: Tpthread_key): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_mutex_destroy*(a1: ptr Tpthread_mutex): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_getprioceiling*(a1: ptr Tpthread_mutex,
+         a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_init*(a1: ptr Tpthread_mutex,
+          a2: ptr Tpthread_mutexattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_lock*(a1: ptr Tpthread_mutex): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_setprioceiling*(a1: ptr Tpthread_mutex,a2: cint,
+          a3: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_timedlock*(a1: ptr Tpthread_mutex,
+          a2: ptr Ttimespec): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_trylock*(a1: ptr Tpthread_mutex): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutex_unlock*(a1: ptr Tpthread_mutex): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_destroy*(a1: ptr Tpthread_mutexattr): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_mutexattr_getprioceiling*(
+          a1: ptr Tpthread_mutexattr, a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_getprotocol*(a1: ptr Tpthread_mutexattr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_getpshared*(a1: ptr Tpthread_mutexattr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_gettype*(a1: ptr Tpthread_mutexattr,
+          a2: var cint): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_mutexattr_init*(a1: ptr Tpthread_mutexattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_setprioceiling*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_setprotocol*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_setpshared*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_mutexattr_settype*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_once*(a1: ptr Tpthread_once, a2: proc () {.noconv.}): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_rwlock_destroy*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_init*(a1: ptr Tpthread_rwlock,
+          a2: ptr Tpthread_rwlockattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_rdlock*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_timedrdlock*(a1: ptr Tpthread_rwlock,
+          a2: ptr Ttimespec): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_timedwrlock*(a1: ptr Tpthread_rwlock,
+          a2: ptr Ttimespec): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_rwlock_tryrdlock*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_trywrlock*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_unlock*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlock_wrlock*(a1: ptr Tpthread_rwlock): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlockattr_destroy*(a1: ptr Tpthread_rwlockattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlockattr_getpshared*(
+          a1: ptr Tpthread_rwlockattr, a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlockattr_init*(a1: ptr Tpthread_rwlockattr): cint {.importc, header: "<pthread.h>".}
+proc pthread_rwlockattr_setpshared*(a1: ptr Tpthread_rwlockattr, a2: cint): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_self*(): Tpthread {.importc, header: "<pthread.h>".}
+proc pthread_setcancelstate*(a1: cint, a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_setcanceltype*(a1: cint, a2: var cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_setconcurrency*(a1: cint): cint {.importc, header: "<pthread.h>".}
+proc pthread_setschedparam*(a1: Tpthread, a2: cint,
+          a3: ptr Tsched_param): cint {.importc, header: "<pthread.h>".}
+
+proc pthread_setschedprio*(a1: Tpthread, a2: cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_setspecific*(a1: Tpthread_key, a2: pointer): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_spin_destroy*(a1: ptr Tpthread_spinlock): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_spin_init*(a1: ptr Tpthread_spinlock, a2: cint): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_spin_lock*(a1: ptr Tpthread_spinlock): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_spin_trylock*(a1: ptr Tpthread_spinlock): cint{.
+  importc, header: "<pthread.h>".}
+proc pthread_spin_unlock*(a1: ptr Tpthread_spinlock): cint {.
+  importc, header: "<pthread.h>".}
+proc pthread_testcancel*() {.importc, header: "<pthread.h>".}
+
+
+proc exitnow*(code: int): void {.importc: "_exit", header: "<unistd.h>".}
+proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
+proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
+proc chown*(a1: cstring, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".}
+proc close*(a1: cint | SocketHandle): cint {.importc, header: "<unistd.h>".}
+proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
+proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
+proc ctermid*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
+proc dup*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc dup2*(a1, a2: cint): cint {.importc, header: "<unistd.h>".}
+proc encrypt*(a1: array[0..63, char], a2: cint) {.importc, header: "<unistd.h>".}
+
+proc execl*(a1, a2: cstring): cint {.varargs, importc, header: "<unistd.h>".}
+proc execle*(a1, a2: cstring): cint {.varargs, importc, header: "<unistd.h>".}
+proc execlp*(a1, a2: cstring): cint {.varargs, importc, header: "<unistd.h>".}
+proc execv*(a1: cstring, a2: cstringArray): cint {.importc, header: "<unistd.h>".}
+proc execve*(a1: cstring, a2, a3: cstringArray): cint {.
+  importc, header: "<unistd.h>".}
+proc execvp*(a1: cstring, a2: cstringArray): cint {.importc, header: "<unistd.h>".}
+proc execvpe*(a1: cstring, a2: cstringArray, a3: cstringArray): cint {.importc, header: "<unistd.h>".}
+proc fchown*(a1: cint, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".}
+proc fchdir*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc fdatasync*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc fork*(): TPid {.importc, header: "<unistd.h>".}
+proc fpathconf*(a1, a2: cint): int {.importc, header: "<unistd.h>".}
+proc fsync*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc ftruncate*(a1: cint, a2: TOff): cint {.importc, header: "<unistd.h>".}
+proc getcwd*(a1: cstring, a2: int): cstring {.importc, header: "<unistd.h>".}
+proc getegid*(): TGid {.importc, header: "<unistd.h>".}
+proc geteuid*(): Tuid {.importc, header: "<unistd.h>".}
+proc getgid*(): TGid {.importc, header: "<unistd.h>".}
+
+proc getgroups*(a1: cint, a2: ptr array[0..255, TGid]): cint {.
+  importc, header: "<unistd.h>".}
+proc gethostid*(): int {.importc, header: "<unistd.h>".}
+proc gethostname*(a1: cstring, a2: int): cint {.importc, header: "<unistd.h>".}
+proc getlogin*(): cstring {.importc, header: "<unistd.h>".}
+proc getlogin_r*(a1: cstring, a2: int): cint {.importc, header: "<unistd.h>".}
+
+proc getopt*(a1: cint, a2: cstringArray, a3: cstring): cint {.
+  importc, header: "<unistd.h>".}
+proc getpgid*(a1: TPid): TPid {.importc, header: "<unistd.h>".}
+proc getpgrp*(): TPid {.importc, header: "<unistd.h>".}
+proc getpid*(): TPid {.importc, header: "<unistd.h>".}
+proc getppid*(): TPid {.importc, header: "<unistd.h>".}
+proc getsid*(a1: TPid): TPid {.importc, header: "<unistd.h>".}
+proc getuid*(): Tuid {.importc, header: "<unistd.h>".}
+proc getwd*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
+proc isatty*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc lchown*(a1: cstring, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".}
+proc link*(a1, a2: cstring): cint {.importc, header: "<unistd.h>".}
+
+proc lockf*(a1, a2: cint, a3: TOff): cint {.importc, header: "<unistd.h>".}
+proc lseek*(a1: cint, a2: TOff, a3: cint): TOff {.importc, header: "<unistd.h>".}
+proc nice*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc pathconf*(a1: cstring, a2: cint): int {.importc, header: "<unistd.h>".}
+
+proc pause*(): cint {.importc, header: "<unistd.h>".}
+proc pipe*(a: array[0..1, cint]): cint {.importc, header: "<unistd.h>".}
+proc pread*(a1: cint, a2: pointer, a3: int, a4: TOff): int {.
+  importc, header: "<unistd.h>".}
+proc pwrite*(a1: cint, a2: pointer, a3: int, a4: TOff): int {.
+  importc, header: "<unistd.h>".}
+proc read*(a1: cint, a2: pointer, a3: int): int {.importc, header: "<unistd.h>".}
+proc readlink*(a1, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
+
+proc rmdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
+proc setegid*(a1: TGid): cint {.importc, header: "<unistd.h>".}
+proc seteuid*(a1: Tuid): cint {.importc, header: "<unistd.h>".}
+proc setgid*(a1: TGid): cint {.importc, header: "<unistd.h>".}
+
+proc setpgid*(a1, a2: TPid): cint {.importc, header: "<unistd.h>".}
+proc setpgrp*(): TPid {.importc, header: "<unistd.h>".}
+proc setregid*(a1, a2: TGid): cint {.importc, header: "<unistd.h>".}
+proc setreuid*(a1, a2: Tuid): cint {.importc, header: "<unistd.h>".}
+proc setsid*(): TPid {.importc, header: "<unistd.h>".}
+proc setuid*(a1: Tuid): cint {.importc, header: "<unistd.h>".}
+proc sleep*(a1: cint): cint {.importc, header: "<unistd.h>".}
+proc swab*(a1, a2: pointer, a3: int) {.importc, header: "<unistd.h>".}
+proc symlink*(a1, a2: cstring): cint {.importc, header: "<unistd.h>".}
+proc sync*() {.importc, header: "<unistd.h>".}
+proc sysconf*(a1: cint): int {.importc, header: "<unistd.h>".}
+proc tcgetpgrp*(a1: cint): TPid {.importc, header: "<unistd.h>".}
+proc tcsetpgrp*(a1: cint, a2: TPid): cint {.importc, header: "<unistd.h>".}
+proc truncate*(a1: cstring, a2: TOff): cint {.importc, header: "<unistd.h>".}
+proc ttyname*(a1: cint): cstring {.importc, header: "<unistd.h>".}
+proc ttyname_r*(a1: cint, a2: cstring, a3: int): cint {.
+  importc, header: "<unistd.h>".}
+proc ualarm*(a1, a2: Tuseconds): Tuseconds {.importc, header: "<unistd.h>".}
+proc unlink*(a1: cstring): cint {.importc, header: "<unistd.h>".}
+proc usleep*(a1: Tuseconds): cint {.importc, header: "<unistd.h>".}
+proc vfork*(): TPid {.importc, header: "<unistd.h>".}
+proc write*(a1: cint, a2: pointer, a3: int): int {.importc, header: "<unistd.h>".}
+
+proc sem_close*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
+proc sem_destroy*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
+proc sem_getvalue*(a1: ptr TSem, a2: var cint): cint {.
+  importc, header: "<semaphore.h>".}
+proc sem_init*(a1: ptr TSem, a2: cint, a3: cint): cint {.
+  importc, header: "<semaphore.h>".}
+proc sem_open*(a1: cstring, a2: cint): ptr TSem {.
+  varargs, importc, header: "<semaphore.h>".}
+proc sem_post*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
+proc sem_timedwait*(a1: ptr TSem, a2: ptr Ttimespec): cint {.
+  importc, header: "<semaphore.h>".}
+proc sem_trywait*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
+proc sem_unlink*(a1: cstring): cint {.importc, header: "<semaphore.h>".}
+proc sem_wait*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
+
+proc ftok*(a1: cstring, a2: cint): TKey {.importc, header: "<sys/ipc.h>".}
+
+proc statvfs*(a1: cstring, a2: var TStatvfs): cint {.
+  importc, header: "<sys/statvfs.h>".}
+proc fstatvfs*(a1: cint, a2: var TStatvfs): cint {.
+  importc, header: "<sys/statvfs.h>".}
+
+proc chmod*(a1: cstring, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
+proc fchmod*(a1: cint, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
+proc fstat*(a1: cint, a2: var TStat): cint {.importc, header: "<sys/stat.h>".}
+proc lstat*(a1: cstring, a2: var TStat): cint {.importc, header: "<sys/stat.h>".}
+proc mkdir*(a1: cstring, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
+proc mkfifo*(a1: cstring, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
+proc mknod*(a1: cstring, a2: TMode, a3: TDev): cint {.
+  importc, header: "<sys/stat.h>".}
+proc stat*(a1: cstring, a2: var TStat): cint {.importc, header: "<sys/stat.h>".}
+proc umask*(a1: TMode): TMode {.importc, header: "<sys/stat.h>".}
+
+proc S_ISBLK*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a block special file.
+proc S_ISCHR*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a character special file.
+proc S_ISDIR*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a directory.
+proc S_ISFIFO*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a pipe or FIFO special file.
+proc S_ISREG*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a regular file.
+proc S_ISLNK*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a symbolic link.
+proc S_ISSOCK*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a socket.
+
+proc S_TYPEISMQ*(buf: var TStat): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a message queue.
+proc S_TYPEISSEM*(buf: var TStat): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a semaphore.
+proc S_TYPEISSHM*(buf: var TStat): bool {.importc, header: "<sys/stat.h>".}
+  ## Test for a shared memory object.
+
+proc S_TYPEISTMO*(buf: var TStat): bool {.importc, header: "<sys/stat.h>".}
+  ## Test macro for a typed memory object.
+
+proc mlock*(a1: pointer, a2: int): cint {.importc, header: "<sys/mman.h>".}
+proc mlockall*(a1: cint): cint {.importc, header: "<sys/mman.h>".}
+proc mmap*(a1: pointer, a2: int, a3, a4, a5: cint, a6: TOff): pointer {.
+  importc, header: "<sys/mman.h>".}
+proc mprotect*(a1: pointer, a2: int, a3: cint): cint {.
+  importc, header: "<sys/mman.h>".}
+proc msync*(a1: pointer, a2: int, a3: cint): cint {.importc, header: "<sys/mman.h>".}
+proc munlock*(a1: pointer, a2: int): cint {.importc, header: "<sys/mman.h>".}
+proc munlockall*(): cint {.importc, header: "<sys/mman.h>".}
+proc munmap*(a1: pointer, a2: int): cint {.importc, header: "<sys/mman.h>".}
+proc posix_madvise*(a1: pointer, a2: int, a3: cint): cint {.
+  importc, header: "<sys/mman.h>".}
+proc posix_mem_offset*(a1: pointer, a2: int, a3: var TOff,
+           a4: var int, a5: var cint): cint {.importc, header: "<sys/mman.h>".}
+proc posix_typed_mem_get_info*(a1: cint,
+  a2: var Tposix_typed_mem_info): cint {.importc, header: "<sys/mman.h>".}
+proc posix_typed_mem_open*(a1: cstring, a2, a3: cint): cint {.
+  importc, header: "<sys/mman.h>".}
+proc shm_open*(a1: cstring, a2: cint, a3: TMode): cint {.
+  importc, header: "<sys/mman.h>".}
+proc shm_unlink*(a1: cstring): cint {.importc, header: "<sys/mman.h>".}
+
+proc asctime*(a1: var Ttm): cstring{.importc, header: "<time.h>".}
+
+proc asctime_r*(a1: var Ttm, a2: cstring): cstring {.importc, header: "<time.h>".}
+proc clock*(): TClock {.importc, header: "<time.h>".}
+proc clock_getcpuclockid*(a1: TPid, a2: var TClockId): cint {.
+  importc, header: "<time.h>".}
+proc clock_getres*(a1: TClockId, a2: var Ttimespec): cint {.
+  importc, header: "<time.h>".}
+proc clock_gettime*(a1: TClockId, a2: var Ttimespec): cint {.
+  importc, header: "<time.h>".}
+proc clock_nanosleep*(a1: TClockId, a2: cint, a3: var Ttimespec,
+               a4: var Ttimespec): cint {.importc, header: "<time.h>".}
+proc clock_settime*(a1: TClockId, a2: var Ttimespec): cint {.
+  importc, header: "<time.h>".}
+
+proc ctime*(a1: var Time): cstring {.importc, header: "<time.h>".}
+proc ctime_r*(a1: var Time, a2: cstring): cstring {.importc, header: "<time.h>".}
+proc difftime*(a1, a2: Time): cdouble {.importc, header: "<time.h>".}
+proc getdate*(a1: cstring): ptr Ttm {.importc, header: "<time.h>".}
+
+proc gmtime*(a1: var Time): ptr Ttm {.importc, header: "<time.h>".}
+proc gmtime_r*(a1: var Time, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".}
+proc localtime*(a1: var Time): ptr Ttm {.importc, header: "<time.h>".}
+proc localtime_r*(a1: var Time, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".}
+proc mktime*(a1: var Ttm): Time  {.importc, header: "<time.h>".}
+proc timegm*(a1: var Ttm): Time  {.importc, header: "<time.h>".}
+proc nanosleep*(a1, a2: var Ttimespec): cint {.importc, header: "<time.h>".}
+proc strftime*(a1: cstring, a2: int, a3: cstring,
+           a4: var Ttm): int {.importc, header: "<time.h>".}
+proc strptime*(a1, a2: cstring, a3: var Ttm): cstring {.importc, header: "<time.h>".}
+proc time*(a1: var Time): Time {.importc, header: "<time.h>".}
+proc timer_create*(a1: var TClockId, a2: var TsigEvent,
+               a3: var Ttimer): cint {.importc, header: "<time.h>".}
+proc timer_delete*(a1: var Ttimer): cint {.importc, header: "<time.h>".}
+proc timer_gettime*(a1: Ttimer, a2: var titimerspec): cint {.
+  importc, header: "<time.h>".}
+proc timer_getoverrun*(a1: Ttimer): cint {.importc, header: "<time.h>".}
+proc timer_settime*(a1: Ttimer, a2: cint, a3: var titimerspec,
+               a4: var titimerspec): cint {.importc, header: "<time.h>".}
+proc tzset*() {.importc, header: "<time.h>".}
+
+
+proc wait*(a1: var cint): TPid {.importc, header: "<sys/wait.h>".}
+proc waitid*(a1: cint, a2: Tid, a3: var TsigInfo, a4: cint): cint {.
+  importc, header: "<sys/wait.h>".}
+proc waitpid*(a1: TPid, a2: var cint, a3: cint): TPid {.
+  importc, header: "<sys/wait.h>".}
+
+proc bsd_signal*(a1: cint, a2: proc (x: pointer) {.noconv.}) {.
+  importc, header: "<signal.h>".}
+proc kill*(a1: TPid, a2: cint): cint {.importc, header: "<signal.h>".}
+proc killpg*(a1: TPid, a2: cint): cint {.importc, header: "<signal.h>".}
+proc pthread_kill*(a1: Tpthread, a2: cint): cint {.importc, header: "<signal.h>".}
+proc pthread_sigmask*(a1: cint, a2, a3: var Tsigset): cint {.
+  importc, header: "<signal.h>".}
+proc `raise`*(a1: cint): cint {.importc, header: "<signal.h>".}
+proc sigaction*(a1: cint, a2, a3: var TSigaction): cint {.
+  importc, header: "<signal.h>".}
+proc sigaddset*(a1: var Tsigset, a2: cint): cint {.importc, header: "<signal.h>".}
+proc sigaltstack*(a1, a2: var TStack): cint {.importc, header: "<signal.h>".}
+proc sigdelset*(a1: var Tsigset, a2: cint): cint {.importc, header: "<signal.h>".}
+proc sigemptyset*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
+proc sigfillset*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
+proc sighold*(a1: cint): cint {.importc, header: "<signal.h>".}
+proc sigignore*(a1: cint): cint {.importc, header: "<signal.h>".}
+proc siginterrupt*(a1, a2: cint): cint {.importc, header: "<signal.h>".}
+proc sigismember*(a1: var Tsigset, a2: cint): cint {.importc, header: "<signal.h>".}
+proc signal*(a1: cint, a2: proc (x: cint) {.noconv.}) {.
+  importc, header: "<signal.h>".}
+proc sigpause*(a1: cint): cint {.importc, header: "<signal.h>".}
+proc sigpending*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
+proc sigprocmask*(a1: cint, a2, a3: var Tsigset): cint {.
+  importc, header: "<signal.h>".}
+proc sigqueue*(a1: TPid, a2: cint, a3: TsigVal): cint {.
+  importc, header: "<signal.h>".}
+proc sigrelse*(a1: cint): cint {.importc, header: "<signal.h>".}
+proc sigset*(a1: int, a2: proc (x: cint) {.noconv.}) {.
+  importc, header: "<signal.h>".}
+proc sigsuspend*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
+proc sigtimedwait*(a1: var Tsigset, a2: var TsigInfo,
+                   a3: var Ttimespec): cint {.importc, header: "<signal.h>".}
+proc sigwait*(a1: var Tsigset, a2: var cint): cint {.
+  importc, header: "<signal.h>".}
+proc sigwaitinfo*(a1: var Tsigset, a2: var TsigInfo): cint {.
+  importc, header: "<signal.h>".}
+
+
+proc catclose*(a1: Tnl_catd): cint {.importc, header: "<nl_types.h>".}
+proc catgets*(a1: Tnl_catd, a2, a3: cint, a4: cstring): cstring {.
+  importc, header: "<nl_types.h>".}
+proc catopen*(a1: cstring, a2: cint): Tnl_catd {.
+  importc, header: "<nl_types.h>".}
+
+proc sched_get_priority_max*(a1: cint): cint {.importc, header: "<sched.h>".}
+proc sched_get_priority_min*(a1: cint): cint {.importc, header: "<sched.h>".}
+proc sched_getparam*(a1: TPid, a2: var Tsched_param): cint {.
+  importc, header: "<sched.h>".}
+proc sched_getscheduler*(a1: TPid): cint {.importc, header: "<sched.h>".}
+proc sched_rr_get_interval*(a1: TPid, a2: var Ttimespec): cint {.
+  importc, header: "<sched.h>".}
+proc sched_setparam*(a1: TPid, a2: var Tsched_param): cint {.
+  importc, header: "<sched.h>".}
+proc sched_setscheduler*(a1: TPid, a2: cint, a3: var Tsched_param): cint {.
+  importc, header: "<sched.h>".}
+proc sched_yield*(): cint {.importc, header: "<sched.h>".}
+
+proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
+proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
+
+proc FD_CLR*(a1: cint, a2: var TFdSet) {.importc, header: "<sys/select.h>".}
+proc FD_ISSET*(a1: cint | SocketHandle, a2: var TFdSet): cint {.
+  importc, header: "<sys/select.h>".}
+proc FD_SET*(a1: cint | SocketHandle, a2: var TFdSet) {.
+  importc: "FD_SET", header: "<sys/select.h>".}
+proc FD_ZERO*(a1: var TFdSet) {.importc, header: "<sys/select.h>".}
+
+proc pselect*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimespec,
+         a6: var Tsigset): cint  {.importc, header: "<sys/select.h>".}
+proc select*(a1: cint | SocketHandle, a2, a3, a4: ptr TFdSet, a5: ptr Timeval): cint {.
+             importc, header: "<sys/select.h>".}
+
+when hasSpawnH:
+  proc posix_spawn*(a1: var TPid, a2: cstring,
+            a3: var Tposix_spawn_file_actions,
+            a4: var Tposix_spawnattr,
+            a5, a6: cstringArray): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawn_file_actions_addclose*(a1: var Tposix_spawn_file_actions,
+            a2: cint): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawn_file_actions_adddup2*(a1: var Tposix_spawn_file_actions,
+            a2, a3: cint): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawn_file_actions_addopen*(a1: var Tposix_spawn_file_actions,
+            a2: cint, a3: cstring, a4: cint, a5: TMode): cint {.
+            importc, header: "<spawn.h>".}
+  proc posix_spawn_file_actions_destroy*(
+    a1: var Tposix_spawn_file_actions): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawn_file_actions_init*(
+    a1: var Tposix_spawn_file_actions): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_destroy*(a1: var Tposix_spawnattr): cint {.
+    importc, header: "<spawn.h>".}
+  proc posix_spawnattr_getsigdefault*(a1: var Tposix_spawnattr,
+            a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_getflags*(a1: var Tposix_spawnattr,
+            a2: var cshort): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_getpgroup*(a1: var Tposix_spawnattr,
+            a2: var TPid): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_getschedparam*(a1: var Tposix_spawnattr,
+            a2: var Tsched_param): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_getschedpolicy*(a1: var Tposix_spawnattr,
+            a2: var cint): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_getsigmask*(a1: var Tposix_spawnattr,
+            a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
+
+  proc posix_spawnattr_init*(a1: var Tposix_spawnattr): cint {.
+    importc, header: "<spawn.h>".}
+  proc posix_spawnattr_setsigdefault*(a1: var Tposix_spawnattr,
+            a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_setflags*(a1: var Tposix_spawnattr, a2: cint): cint {.
+    importc, header: "<spawn.h>".}
+  proc posix_spawnattr_setpgroup*(a1: var Tposix_spawnattr, a2: TPid): cint {.
+    importc, header: "<spawn.h>".}
+
+  proc posix_spawnattr_setschedparam*(a1: var Tposix_spawnattr,
+            a2: var Tsched_param): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnattr_setschedpolicy*(a1: var Tposix_spawnattr,
+                                       a2: cint): cint {.
+                                       importc, header: "<spawn.h>".}
+  proc posix_spawnattr_setsigmask*(a1: var Tposix_spawnattr,
+            a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
+  proc posix_spawnp*(a1: var TPid, a2: cstring,
+            a3: var Tposix_spawn_file_actions,
+            a4: var Tposix_spawnattr,
+            a5, a6: cstringArray): cint {.importc, header: "<spawn.h>".}
+
+proc getcontext*(a1: var Tucontext): cint {.importc, header: "<ucontext.h>".}
+proc makecontext*(a1: var Tucontext, a4: proc (){.noconv.}, a3: cint) {.
+  varargs, importc, header: "<ucontext.h>".}
+proc setcontext*(a1: var Tucontext): cint {.importc, header: "<ucontext.h>".}
+proc swapcontext*(a1, a2: var Tucontext): cint {.importc, header: "<ucontext.h>".}
+
+proc readv*(a1: cint, a2: ptr TIOVec, a3: cint): int {.
+  importc, header: "<sys/uio.h>".}
+proc writev*(a1: cint, a2: ptr TIOVec, a3: cint): int {.
+  importc, header: "<sys/uio.h>".}
+
+proc CMSG_DATA*(cmsg: ptr Tcmsghdr): cstring {.
+  importc, header: "<sys/socket.h>".}
+
+proc CMSG_NXTHDR*(mhdr: ptr Tmsghdr, cmsg: ptr Tcmsghdr): ptr Tcmsghdr {.
+  importc, header: "<sys/socket.h>".}
+
+proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {.
+  importc, header: "<sys/socket.h>".}
+
+const
+  INVALID_SOCKET* = SocketHandle(-1)
+
+proc `==`*(x, y: SocketHandle): bool {.borrow.}
+
+proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr Socklen): SocketHandle {.
+  importc, header: "<sys/socket.h>".}
+
+proc bindSocket*(a1: SocketHandle, a2: ptr SockAddr, a3: Socklen): cint {.
+  importc: "bind", header: "<sys/socket.h>".}
+  ## is Posix's ``bind``, because ``bind`` is a reserved word
+
+proc connect*(a1: SocketHandle, a2: ptr SockAddr, a3: Socklen): cint {.
+  importc, header: "<sys/socket.h>".}
+proc getpeername*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr Socklen): cint {.
+  importc, header: "<sys/socket.h>".}
+proc getsockname*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr Socklen): cint {.
+  importc, header: "<sys/socket.h>".}
+
+proc getsockopt*(a1: SocketHandle, a2, a3: cint, a4: pointer, a5: ptr Socklen): cint {.
+  importc, header: "<sys/socket.h>".}
+
+proc listen*(a1: SocketHandle, a2: cint): cint {.
+  importc, header: "<sys/socket.h>".}
+proc recv*(a1: SocketHandle, a2: pointer, a3: int, a4: cint): int {.
+  importc, header: "<sys/socket.h>".}
+proc recvfrom*(a1: SocketHandle, a2: pointer, a3: int, a4: cint,
+        a5: ptr SockAddr, a6: ptr Socklen): int {.
+  importc, header: "<sys/socket.h>".}
+proc recvmsg*(a1: SocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
+  importc, header: "<sys/socket.h>".}
+proc send*(a1: SocketHandle, a2: pointer, a3: int, a4: cint): int {.
+  importc, header: "<sys/socket.h>".}
+proc sendmsg*(a1: SocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
+  importc, header: "<sys/socket.h>".}
+proc sendto*(a1: SocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr SockAddr,
+             a6: Socklen): int {.
+  importc, header: "<sys/socket.h>".}
+proc setsockopt*(a1: SocketHandle, a2, a3: cint, a4: pointer, a5: Socklen): cint {.
+  importc, header: "<sys/socket.h>".}
+proc shutdown*(a1: SocketHandle, a2: cint): cint {.
+  importc, header: "<sys/socket.h>".}
+proc socket*(a1, a2, a3: cint): SocketHandle {.
+  importc, header: "<sys/socket.h>".}
+proc sockatmark*(a1: cint): cint {.
+  importc, header: "<sys/socket.h>".}
+proc socketpair*(a1, a2, a3: cint, a4: var array[0..1, cint]): cint {.
+  importc, header: "<sys/socket.h>".}
+
+proc if_nametoindex*(a1: cstring): cint {.importc, header: "<net/if.h>".}
+proc if_indextoname*(a1: cint, a2: cstring): cstring {.
+  importc, header: "<net/if.h>".}
+proc if_nameindex*(): ptr Tif_nameindex {.importc, header: "<net/if.h>".}
+proc if_freenameindex*(a1: ptr Tif_nameindex) {.importc, header: "<net/if.h>".}
+
+proc IN6_IS_ADDR_UNSPECIFIED* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Unspecified address.
+proc IN6_IS_ADDR_LOOPBACK* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Loopback address.
+proc IN6_IS_ADDR_MULTICAST* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Multicast address.
+proc IN6_IS_ADDR_LINKLOCAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Unicast link-local address.
+proc IN6_IS_ADDR_SITELOCAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Unicast site-local address.
+proc IN6_IS_ADDR_V4MAPPED* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## IPv4 mapped address.
+proc IN6_IS_ADDR_V4COMPAT* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## IPv4-compatible address.
+proc IN6_IS_ADDR_MC_NODELOCAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Multicast node-local address.
+proc IN6_IS_ADDR_MC_LINKLOCAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Multicast link-local address.
+proc IN6_IS_ADDR_MC_SITELOCAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Multicast site-local address.
+proc IN6_IS_ADDR_MC_ORGLOCAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Multicast organization-local address.
+proc IN6_IS_ADDR_MC_GLOBAL* (a1: ptr TIn6Addr): cint {.
+  importc, header: "<netinet/in.h>".}
+  ## Multicast global address.
+
+proc endhostent*() {.importc, header: "<netdb.h>".}
+proc endnetent*() {.importc, header: "<netdb.h>".}
+proc endprotoent*() {.importc, header: "<netdb.h>".}
+proc endservent*() {.importc, header: "<netdb.h>".}
+proc freeaddrinfo*(a1: ptr AddrInfo) {.importc, header: "<netdb.h>".}
+
+proc gai_strerror*(a1: cint): cstring {.importc, header: "<netdb.h>".}
+
+proc getaddrinfo*(a1, a2: cstring, a3: ptr AddrInfo,
+                  a4: var ptr AddrInfo): cint {.importc, header: "<netdb.h>".}
+
+proc gethostbyaddr*(a1: pointer, a2: Socklen, a3: cint): ptr Hostent {.
+                    importc, header: "<netdb.h>".}
+proc gethostbyname*(a1: cstring): ptr Hostent {.importc, header: "<netdb.h>".}
+proc gethostent*(): ptr Hostent {.importc, header: "<netdb.h>".}
+
+proc getnameinfo*(a1: ptr SockAddr, a2: Socklen,
+                  a3: cstring, a4: Socklen, a5: cstring,
+                  a6: Socklen, a7: cint): cint {.importc, header: "<netdb.h>".}
+
+proc getnetbyaddr*(a1: int32, a2: cint): ptr Tnetent {.importc, header: "<netdb.h>".}
+proc getnetbyname*(a1: cstring): ptr Tnetent {.importc, header: "<netdb.h>".}
+proc getnetent*(): ptr Tnetent {.importc, header: "<netdb.h>".}
+
+proc getprotobyname*(a1: cstring): ptr TProtoent {.importc, header: "<netdb.h>".}
+proc getprotobynumber*(a1: cint): ptr TProtoent {.importc, header: "<netdb.h>".}
+proc getprotoent*(): ptr TProtoent {.importc, header: "<netdb.h>".}
+
+proc getservbyname*(a1, a2: cstring): ptr Servent {.importc, header: "<netdb.h>".}
+proc getservbyport*(a1: cint, a2: cstring): ptr Servent {.
+  importc, header: "<netdb.h>".}
+proc getservent*(): ptr Servent {.importc, header: "<netdb.h>".}
+
+proc sethostent*(a1: cint) {.importc, header: "<netdb.h>".}
+proc setnetent*(a1: cint) {.importc, header: "<netdb.h>".}
+proc setprotoent*(a1: cint) {.importc, header: "<netdb.h>".}
+proc setservent*(a1: cint) {.importc, header: "<netdb.h>".}
+
+proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {.
+  importc, header: "<poll.h>".}
+
+proc realpath*(name, resolved: cstring): cstring {.
+  importc: "realpath", header: "<stdlib.h>".}
+
+proc utimes*(path: cstring, times: ptr array [2, Timeval]): int {.
+  importc: "utimes", header: "<sys/time.h>".}
+  ## Sets file access and modification times.
+  ##
+  ## Pass the filename and an array of times to set the access and modification
+  ## times respectively. If you pass nil as the array both attributes will be
+  ## set to the current time.
+  ##
+  ## Returns zero on success.
+  ##
+  ## For more information read http://www.unix.com/man-page/posix/3/utimes/.
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim
new file mode 100644
index 000000000..710b2fa6b
--- /dev/null
+++ b/lib/posix/termios.nim
@@ -0,0 +1,261 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim: on.}
+import posix
+
+type
+  Speed* = cuint
+  Tcflag* = cuint
+
+const
+  NCCS* = 32
+
+type
+  Termios* {.importc: "struct termios", header: "<termios.h>".} = object
+    c_iflag*: Tcflag        # input mode flags
+    c_oflag*: Tcflag        # output mode flags
+    c_cflag*: Tcflag        # control mode flags
+    c_lflag*: Tcflag        # local mode flags
+    c_line*: cuchar         # line discipline
+    c_cc*: array[NCCS, cuchar]  # control characters
+
+# cc characters
+
+const
+  VINTR* = 0
+  VQUIT* = 1
+  VERASE* = 2
+  VKILL* = 3
+  VEOF* = 4
+  VTIME* = 5
+  VMIN* = 6
+  VSWTC* = 7
+  VSTART* = 8
+  VSTOP* = 9
+  VSUSP* = 10
+  VEOL* = 11
+  VREPRINT* = 12
+  VDISCARD* = 13
+  VWERASE* = 14
+  VLNEXT* = 15
+  VEOL2* = 16
+
+# iflag bits
+
+const
+  IGNBRK* = 1
+  BRKINT* = 2
+  IGNPAR* = 4
+  PARMRK* = 10
+  INPCK* = 20
+  ISTRIP* = 40
+  INLCR* = 100
+  IGNCR* = 200
+  ICRNL* = 400
+  IUCLC* = 1000
+  IXON* = 2000
+  IXANY* = 4000
+  IXOFF* = 10000
+  IMAXBEL* = 20000
+  IUTF8* = 40000
+
+# oflag bits
+
+const
+  OPOST* = 1
+  OLCUC* = 2
+  ONLCR* = 4
+  OCRNL* = 10
+  ONOCR* = 20
+  ONLRET* = 40
+  OFILL* = 100
+  OFDEL* = 200
+  NLDLY* = 400
+  NL0* = 0
+  NL1* = 400
+  CRDLY* = 3000
+  CR0* = 0
+  CR1* = 1000
+  CR2* = 2000
+  CR3* = 3000
+  TABDLY* = 14000
+  TAB0* = 0
+  TAB1* = 4000
+  TAB2* = 10000
+  TAB3* = 14000
+  BSDLY* = 20000
+  BS0* = 0
+  BS1* = 20000
+  FFDLY* = 0o000000100000
+  FF0* = 0
+  FF1* = 0o000000100000
+  VTDLY* = 40000
+  VT0* = 0
+  VT1* = 40000
+  XTABS* = 14000
+
+# cflag bit meaning
+
+const
+  CBAUD* = 10017
+  B0* = 0
+  B50* = 1
+  B75* = 2
+  B110* = 3
+  B134* = 4
+  B150* = 5
+  B200* = 6
+  B300* = 7
+  B600* = 10
+  B1200* = 11
+  B1800* = 12
+  B2400* = 13
+  B4800* = 14
+  B9600* = 15
+  B19200* = 16
+  B38400* = 17
+  EXTA* = B19200
+  EXTB* = B38400
+  CSIZE* = 60
+  CS5* = 0
+  CS6* = 20
+  CS7* = 40
+  CS8* = 60
+  CSTOPB* = 100
+  CREAD* = 200
+  PARENB* = 400
+  PARODD* = 1000
+  HUPCL* = 2000
+  CLOCAL* = 4000
+  CBAUDEX* = 10000
+  B57600* = 10001
+  B115200* = 10002
+  B230400* = 10003
+  B460800* = 10004
+  B500000* = 10005
+  B576000* = 10006
+  B921600* = 10007
+  B1000000* = 10010
+  B1152000* = 10011
+  B1500000* = 10012
+  B2000000* = 10013
+  B2500000* = 10014
+  B3000000* = 10015
+  B3500000* = 10016
+  B4000000* = 10017
+  MAX_BAUD* = B4000000
+  CIBAUD* = 2003600000
+  CMSPAR* = 0o010000000000
+  CRTSCTS* = 0o020000000000
+
+# lflag bits
+
+const
+  ISIG* = 1
+  ICANON* = 2
+  XCASE* = 4
+  ECHO* = 10
+  ECHOE* = 20
+  ECHOK* = 40
+  ECHONL* = 100
+  NOFLSH* = 200
+  TOSTOP* = 400
+  ECHOCTL* = 1000
+  ECHOPRT* = 2000
+  ECHOKE* = 4000
+  FLUSHO* = 10000
+  PENDIN* = 40000
+  IEXTEN* = 0o000000100000
+  EXTPROC* = 0o000000200000
+
+# tcflow() and TCXONC use these
+
+const
+  TCOOFF* = 0
+  TCOON* = 1
+  TCIOFF* = 2
+  TCION* = 3
+
+# tcflush() and TCFLSH use these
+
+const
+  TCIFLUSH* = 0
+  TCOFLUSH* = 1
+  TCIOFLUSH* = 2
+
+# tcsetattr uses these
+
+const
+  TCSANOW* = 0
+  TCSADRAIN* = 1
+  TCSAFLUSH* = 2
+
+# Compare a character C to a value VAL from the `cc' array in a
+#   `struct termios'.  If VAL is _POSIX_VDISABLE, no character can match it.
+
+template cceq*(val, c: expr): expr =
+  c == val and val != POSIX_VDISABLE
+
+# Return the output baud rate stored in *TERMIOS_P.
+
+proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
+    header: "<termios.h>".}
+# Return the input baud rate stored in *TERMIOS_P.
+
+proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
+    header: "<termios.h>".}
+# Set the output baud rate stored in *TERMIOS_P to SPEED.
+
+proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {.
+    importc: "cfsetospeed", header: "<termios.h>".}
+# Set the input baud rate stored in *TERMIOS_P to SPEED.
+
+proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {.
+    importc: "cfsetispeed", header: "<termios.h>".}
+# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
+
+proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {.
+    importc: "cfsetspeed", header: "<termios.h>".}
+# Put the state of FD into *TERMIOS_P.
+
+proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {.
+    importc: "tcgetattr", header: "<termios.h>".}
+# Set the state of FD to *TERMIOS_P.
+#   Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.
+
+proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {.
+    importc: "tcsetattr", header: "<termios.h>".}
+# Set *TERMIOS_P to indicate raw mode.
+
+proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
+    header: "<termios.h>".}
+# Send zero bits on FD.
+
+proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
+    header: "<termios.h>".}
+# Wait for pending output to be written on FD.
+#
+#   This function is a cancellation point and therefore not marked with
+#  .
+
+proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "<termios.h>".}
+# Flush pending data on FD.
+#   Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.
+
+proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
+    header: "<termios.h>".}
+# Suspend or restart transmission on FD.
+#   Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.
+
+proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
+    header: "<termios.h>".}
+# Get process group ID for session leader for controlling terminal FD.
+
+proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
diff --git a/lib/prelude.nim b/lib/prelude.nim
new file mode 100644
index 000000000..940864207
--- /dev/null
+++ b/lib/prelude.nim
@@ -0,0 +1,23 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This is an include file that simply imports common modules for your
+## convenience:
+##
+## .. code-block:: nim
+##   include prelude
+##
+## Same as:
+##
+## .. code-block:: nim
+##   import os, strutils, times, parseutils, parseopt, hashes, tables, sets
+
+import os, strutils, times, parseutils, parseopt, hashes, tables, sets
+
+
diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
new file mode 100644
index 000000000..294c24741
--- /dev/null
+++ b/lib/pure/actors.nim
@@ -0,0 +1,239 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## `Actor`:idx: support for Nim. An actor is implemented as a thread with
+## a channel as its inbox. This module requires the ``--threads:on``
+## command line switch.
+##
+## Example:
+##
+## .. code-block:: nim
+##
+##      var
+##        a: TActorPool[int, void]
+##      createActorPool(a)
+##      for i in 0 .. < 300:
+##        a.spawn(i, proc (x: int) {.thread.} = echo x)
+##      a.join()
+##
+## **Note**: This whole module is deprecated. Use `threadpool` and ``spawn``
+## instead.
+
+{.deprecated.}
+
+from os import sleep
+
+type
+  TTask*[TIn, TOut] = object{.pure, final.} ## a task
+    when TOut isnot void:
+      receiver*: ptr TChannel[TOut] ## the receiver channel of the response
+    action*: proc (x: TIn): TOut {.thread.} ## action to execute;
+                                            ## sometimes useful
+    shutDown*: bool ## set to tell an actor to shut-down
+    data*: TIn ## the data to process
+
+  TActor[TIn, TOut] = object{.pure, final.}
+    i: TChannel[TTask[TIn, TOut]]
+    t: TThread[ptr TActor[TIn, TOut]]
+    
+  PActor*[TIn, TOut] = ptr TActor[TIn, TOut] ## an actor
+  
+proc spawn*[TIn, TOut](action: proc(
+    self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
+  ## creates an actor; that is a thread with an inbox. The caller MUST call
+  ## ``join`` because that also frees the actor's associated resources.
+  result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
+  open(result.i)
+  createThread(result.t, action, result)
+
+proc inbox*[TIn, TOut](self: PActor[TIn, TOut]): ptr TChannel[TIn] =
+  ## gets a pointer to the associated inbox of the actor `self`.
+  result = addr(self.i)
+
+proc running*[TIn, TOut](a: PActor[TIn, TOut]): bool =
+  ## returns true if the actor `a` is running.
+  result = running(a.t)
+
+proc ready*[TIn, TOut](a: PActor[TIn, TOut]): bool =
+  ## returns true if the actor `a` is ready to process new messages.
+  result = ready(a.i)
+
+proc join*[TIn, TOut](a: PActor[TIn, TOut]) =
+  ## joins an actor.
+  joinThread(a.t)
+  close(a.i)
+  deallocShared(a)
+
+proc recv*[TIn, TOut](a: PActor[TIn, TOut]): TTask[TIn, TOut] =
+  ## receives a task from `a`'s inbox.
+  result = recv(a.i)
+
+proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
+                            sender: PActor[X, Y]) =
+  ## sends a message to `a`'s inbox.
+  var t: TTask[TIn, TOut]
+  t.receiver = addr(sender.i)
+  shallowCopy(t.data, msg)
+  send(receiver.i, t)
+
+proc send*[TIn, TOut](receiver: PActor[TIn, TOut], msg: TIn, 
+                      sender: ptr TChannel[TOut] = nil) =
+  ## sends a message to `receiver`'s inbox.
+  var t: TTask[TIn, TOut]
+  t.receiver = sender
+  shallowCopy(t.data, msg)
+  send(receiver.i, t)
+
+proc sendShutdown*[TIn, TOut](receiver: PActor[TIn, TOut]) =
+  ## send a shutdown message to `receiver`.
+  var t: TTask[TIn, TOut]
+  t.shutdown = true
+  send(receiver.i, t)
+
+proc reply*[TIn, TOut](t: TTask[TIn, TOut], m: TOut) =
+  ## sends a message to io's output message box.
+  when TOut is void:
+    {.error: "you cannot reply to a void outbox".}
+  assert t.receiver != nil
+  send(t.receiver[], m)
+
+
+# ----------------- actor pools ----------------------------------------------
+
+type
+  TActorPool*[TIn, TOut] = object{.pure, final.}  ## an actor pool
+    actors: seq[PActor[TIn, TOut]]
+    when TOut isnot void:
+      outputs: TChannel[TOut]
+
+proc `^`*[T](f: ptr TChannel[T]): T =
+  ## alias for 'recv'.
+  result = recv(f[])
+
+proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
+  while true:
+    var m = self.recv
+    if m.shutDown: break
+    when TOut is void:
+      m.action(m.data)
+    else:
+      send(m.receiver[], m.action(m.data))
+      #self.reply()
+
+proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
+  ## creates an actor pool.
+  newSeq(a.actors, poolSize)
+  when TOut isnot void:
+    open(a.outputs)
+  for i in 0 .. < a.actors.len:
+    a.actors[i] = spawn(poolWorker[TIn, TOut])
+
+proc sync*[TIn, TOut](a: var TActorPool[TIn, TOut], polling=50) =
+  ## waits for every actor of `a` to finish with its work. Currently this is
+  ## implemented as polling every `polling` ms and has a slight chance 
+  ## of failing since we check for every actor to be in `ready` state and not
+  ## for messages still in ether. This will change in a later
+  ## version, however.
+  var allReadyCount = 0
+  while true:
+    var wait = false
+    for i in 0..high(a.actors):
+      if not a.actors[i].i.ready: 
+        wait = true
+        allReadyCount = 0
+        break
+    if not wait:
+      # it's possible that some actor sent a message to some other actor but
+      # both appeared to be non-working as the message takes some time to
+      # arrive. We assume that this won't take longer than `polling` and
+      # simply attempt a second time and declare victory then. ;-)
+      inc allReadyCount
+      if allReadyCount > 1: break
+    sleep(polling)
+
+proc terminate*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
+  ## terminates each actor in the actor pool `a` and frees the
+  ## resources attached to `a`.
+  var t: TTask[TIn, TOut]
+  t.shutdown = true
+  for i in 0.. <a.actors.len: send(a.actors[i].i, t)
+  for i in 0.. <a.actors.len: join(a.actors[i])
+  when TOut isnot void:
+    close(a.outputs)
+  a.actors = nil
+
+proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
+  ## short-cut for `sync` and then `terminate`.
+  sync(a)
+  terminate(a)
+
+template setupTask =
+  t.action = action
+  shallowCopy(t.data, input)
+
+template schedule =
+  # extremely simple scheduler: We always try the first thread first, so that
+  # it remains 'hot' ;-). Round-robin hurts for keeping threads hot.
+  for i in 0..high(p.actors):
+    if p.actors[i].i.ready:
+      p.actors[i].i.send(t)
+      return
+  # no thread ready :-( --> send message to the thread which has the least
+  # messages pending:
+  var minIdx = -1
+  var minVal = high(int)
+  for i in 0..high(p.actors):
+    var curr = p.actors[i].i.peek
+    if curr == 0:
+      # ok, is ready now:
+      p.actors[i].i.send(t)
+      return
+    if curr < minVal and curr >= 0:
+      minVal = curr
+      minIdx = i
+  if minIdx >= 0:
+    p.actors[minIdx].i.send(t)
+  else:
+    raise newException(DeadThreadError, "cannot send message; thread died")
+
+proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
+                       action: proc (input: TIn): TOut {.thread.}
+                       ): ptr TChannel[TOut] =
+  ## uses the actor pool to run ``action(input)`` concurrently.
+  ## `spawn` is guaranteed to not block.
+  var t: TTask[TIn, TOut]
+  setupTask()
+  result = addr(p.outputs)
+  t.receiver = result
+  schedule()
+
+proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
+                 action: proc (input: TIn) {.thread.}) =
+  ## uses the actor pool to run ``action(input)`` concurrently.
+  ## `spawn` is guaranteed to not block.
+  var t: TTask[TIn, void]
+  setupTask()
+  schedule()
+  
+when not defined(testing) and isMainModule:
+  var
+    a: TActorPool[int, void]
+  createActorPool(a)
+  for i in 0 .. < 300:
+    a.spawn(i, proc (x: int) {.thread.} = echo x)
+
+  when false:
+    proc treeDepth(n: PNode): int {.thread.} =
+      var x = a.spawn(treeDepth, n.le)
+      var y = a.spawn(treeDepth, n.ri)
+      result = max(^x, ^y) + 1
+
+  a.join()
+
+
diff --git a/lib/pure/actors.nim.cfg b/lib/pure/actors.nim.cfg
new file mode 100644
index 000000000..c6bb9c545
--- /dev/null
+++ b/lib/pure/actors.nim.cfg
@@ -0,0 +1,3 @@
+# to shut up the tester:
+--threads:on
+
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
new file mode 100644
index 000000000..0eafb316a
--- /dev/null
+++ b/lib/pure/algorithm.nim
@@ -0,0 +1,333 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements some common generic algorithms.
+
+type
+  SortOrder* = enum   ## sort order
+    Descending, Ascending
+
+{.deprecated: [TSortOrder: SortOrder].}
+
+
+proc `*`*(x: int, order: SortOrder): int {.inline.} =
+  ## flips `x` if ``order == Descending``;
+  ## if ``order == Ascending`` then `x` is returned.
+  ## `x` is supposed to be the result of a comparator, ie ``< 0`` for
+  ## *less than*, ``== 0`` for *equal*, ``> 0`` for *greater than*.
+  var y = order.ord - 1
+  result = (x xor y) - y
+
+proc fill*[T](a: var openArray[T], first, last: Natural, value: T) =
+  ## fills the array ``a[first..last]`` with `value`.
+  var x = first
+  while x <= last:
+    a[x] = value
+    inc(x)
+
+proc fill*[T](a: var openArray[T], value: T) =
+  ## fills the array `a` with `value`.
+  fill(a, 0, a.high, value)
+
+proc reverse*[T](a: var openArray[T], first, last: Natural) =
+  ## reverses the array ``a[first..last]``.
+  var x = first
+  var y = last
+  while x < y:
+    swap(a[x], a[y])
+    dec(y)
+    inc(x)
+
+proc reverse*[T](a: var openArray[T]) =
+  ## reverses the array `a`.
+  reverse(a, 0, a.high)
+
+proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
+  ## returns the reverse of the array `a[first..last]`.
+  result = newSeq[T](last - first + 1)
+  var x = first.int
+  var y = last.int
+  while x <= last:
+    result[x] = a[y]
+    dec(y)
+    inc(x)
+
+proc reversed*[T](a: openArray[T]): seq[T] =
+  ## returns the reverse of the array `a`.
+  reversed(a, 0, a.high)
+
+proc binarySearch*[T](a: openArray[T], key: T): int =
+  ## binary search for `key` in `a`. Returns -1 if not found.
+  var b = len(a)
+  while result < b:
+    var mid = (result + b) div 2
+    if a[mid] < key: result = mid + 1
+    else: b = mid
+  if result >= len(a) or a[result] != key: result = -1
+
+proc smartBinarySearch*[T](a: openArray[T], key: T): int =
+  ## ``a.len`` must be a power of 2 for this to work.
+  var step = a.len div 2
+  while step > 0:
+    if a[result or step] <= key:
+      result = result or step
+    step = step shr 1
+  if a[result] != key: result = -1
+
+const
+  onlySafeCode = true
+
+proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int =
+  ## same as binarySearch except that if key is not in `a` then this
+  ## returns the location where `key` would be if it were. In other
+  ## words if you have a sorted sequence and you call
+  ## insert(thing, elm, lowerBound(thing, elm))
+  ## the sequence will still be sorted.
+  ##
+  ## `cmp` is the comparator function to use, the expected return values are
+  ## the same as that of system.cmp.
+  ##
+  ## example::
+  ##
+  ##   var arr = @[1,2,3,5,6,7,8,9]
+  ##   arr.insert(4, arr.lowerBound(4))
+  ## `after running the above arr is `[1,2,3,4,5,6,7,8,9]`
+  result = a.low
+  var pos = result
+  var count, step: int
+  count = a.high - a.low + 1
+  while count != 0:
+    pos = result
+    step = count div 2
+    pos += step
+    if cmp(a[pos], key) < 0:
+      pos.inc
+      result = pos
+      count -= step + 1
+    else:
+      count = step
+
+proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T])
+proc merge[T](a, b: var openArray[T], lo, m, hi: int,
+              cmp: proc (x, y: T): int {.closure.}, order: SortOrder) =
+  template `<-` (a, b: expr) =
+    when false:
+      a = b
+    elif onlySafeCode:
+      shallowCopy(a, b)
+    else:
+      copyMem(addr(a), addr(b), sizeof(T))
+  # optimization: If max(left) <= min(right) there is nothing to do!
+  # 1 2 3 4  ## 5 6 7 8
+  # -> O(n) for sorted arrays.
+  # On random data this safes up to 40% of merge calls
+  if cmp(a[m], a[m+1]) * order <= 0: return
+  var j = lo
+  # copy a[j..m] into b:
+  assert j <= m
+  when onlySafeCode:
+    var bb = 0
+    while j <= m:
+      b[bb] <- a[j]
+      inc(bb)
+      inc(j)
+  else:
+    copyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1))
+    j = m+1
+  var i = 0
+  var k = lo
+  # copy proper element back:
+  while k < j and j <= hi:
+    if cmp(b[i], a[j]) * order <= 0:
+      a[k] <- b[i]
+      inc(i)
+    else:
+      a[k] <- a[j]
+      inc(j)
+    inc(k)
+  # copy rest of b:
+  when onlySafeCode:
+    while k < j:
+      a[k] <- b[i]
+      inc(k)
+      inc(i)
+  else:
+    if k < j: copyMem(addr(a[k]), addr(b[i]), sizeof(T)*(j-k))
+
+proc sort*[T](a: var openArray[T],
+              cmp: proc (x, y: T): int {.closure.},
+              order = SortOrder.Ascending) =
+  ## Default Nim sort. The sorting is guaranteed to be stable and
+  ## the worst case is guaranteed to be O(n log n).
+  ## The current implementation uses an iterative
+  ## mergesort to achieve this. It uses a temporary sequence of
+  ## length ``a.len div 2``. Currently Nim does not support a
+  ## sensible default argument for ``cmp``, so you have to provide one
+  ## of your own. However, the ``system.cmp`` procs can be used:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##    sort(myIntArray, system.cmp[int])
+  ##
+  ##    # do not use cmp[string] here as we want to use the specialized
+  ##    # overload:
+  ##    sort(myStrArray, system.cmp)
+  ##
+  ## You can inline adhoc comparison procs with the `do notation
+  ## <manual.html#do-notation>`_. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   people.sort do (x, y: Person) -> int:
+  ##     result = cmp(x.surname, y.surname)
+  ##     if result == 0:
+  ##       result = cmp(x.name, y.name)
+  var n = a.len
+  var b: seq[T]
+  newSeq(b, n div 2)
+  var s = 1
+  while s < n:
+    var m = n-1-s
+    while m >= 0:
+      merge(a, b, max(m-s+1, 0), m, m+s, cmp, order)
+      dec(m, s*2)
+    s = s*2
+
+proc sorted*[T](a: openArray[T], cmp: proc(x, y: T): int {.closure.},
+                order = SortOrder.Ascending): seq[T] =
+  ## returns `a` sorted by `cmp` in the specified `order`.
+  result = newSeq[T](a.len)
+  for i in 0 .. a.high:
+    result[i] = a[i]
+  sort(result, cmp, order)
+
+template sortedByIt*(seq1, op: expr): expr =
+  ## Convenience template around the ``sorted`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   type Person = tuple[name: string, age: int]
+  ##   var
+  ##     p1: Person = (name: "p1", age: 60)
+  ##     p2: Person = (name: "p2", age: 20)
+  ##     p3: Person = (name: "p3", age: 30)
+  ##     p4: Person = (name: "p4", age: 30)
+  ##     people = @[p1,p2,p4,p3]
+  ##
+  ##   echo people.sortedByIt(it.name)
+  ##
+  ## Because the underlying ``cmp()`` is defined for tuples you can do
+  ## a nested sort like in the following example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   echo people.sortedByIt((it.age, it.name))
+  ##
+  var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
+    var it {.inject.} = x
+    let a = op
+    it = y
+    let b = op
+    result = cmp(a, b))
+  result
+
+proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
+  ## produces the Cartesian product of the array. Warning: complexity
+  ## may explode.
+  result = newSeq[seq[T]]()
+  if x.len == 0:
+    return
+  if x.len == 1:
+    result = @x
+    return
+  var
+    indexes = newSeq[int](x.len)
+    initial = newSeq[int](x.len)
+    index = 0
+  var next = newSeq[T]()
+  next.setLen(x.len)
+  for i in 0..(x.len-1):
+    if len(x[i]) == 0: return
+    initial[i] = len(x[i])-1
+  indexes = initial
+  while true:
+    while indexes[index] == -1:
+      indexes[index] = initial[index]
+      index += 1
+      if index == x.len: return
+      indexes[index] -= 1
+    for ni, i in indexes:
+      next[ni] = x[ni][i]
+    var res: seq[T]
+    shallowCopy(res, next)
+    result.add(res)
+    index = 0
+    indexes[index] -= 1
+
+proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} =
+  ## Calculates the next lexicographic permutation, directly modifying ``x``.
+  ## The result is whether a permutation happened, otherwise we have reached
+  ## the last-ordered permutation.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##     var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+  ##     v.nextPermutation()
+  ##     echo v
+  if x.len < 2:
+    return false
+
+  var i = x.high
+  while i > 0 and x[i-1] >= x[i]:
+    dec i
+
+  if i == 0:
+    return false
+
+  var j = x.high
+  while j >= i and x[j] <= x[i-1]:
+    dec j
+
+  swap x[j], x[i-1]
+  x.reverse(i, x.high)
+
+  result = true
+
+proc prevPermutation*[T](x: var openarray[T]): bool {.discardable.} =
+  ## Calculates the previous lexicographic permutation, directly modifying
+  ## ``x``.  The result is whether a permutation happened, otherwise we have
+  ## reached the first-ordered permutation.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##     var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8]
+  ##     v.prevPermutation()
+  ##     echo v
+  if x.len < 2:
+    return false
+
+  var i = x.high
+  while i > 0 and x[i-1] <= x[i]:
+    dec i
+
+  if i == 0:
+    return false
+
+  x.reverse(i, x.high)
+
+  var j = x.high
+  while j >= i and x[j-1] < x[i-1]:
+    dec j
+
+  swap x[i-1], x[j]
+
+  result = true
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
new file mode 100644
index 000000000..8010e9ebc
--- /dev/null
+++ b/lib/pure/asyncdispatch.nim
@@ -0,0 +1,1547 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+include "system/inclrtl"
+
+import os, oids, tables, strutils, macros, times
+
+import rawsockets, net
+
+export Port, SocketFlag
+
+#{.injectStmt: newGcInvariant().}
+
+## AsyncDispatch
+## *************
+##
+## This module implements asynchronous IO. This includes a dispatcher,
+## a ``Future`` type implementation, and an ``async`` macro which allows
+## asynchronous code to be written in a synchronous style with the ``await``
+## keyword.
+##
+## The dispatcher acts as a kind of event loop. You must call ``poll`` on it
+## (or a function which does so for you such as ``waitFor`` or ``runForever``)
+## in order to poll for any outstanding events. The underlying implementation
+## is based on epoll on Linux, IO Completion Ports on Windows and select on
+## other operating systems.
+##
+## The ``poll`` function will not, on its own, return any events. Instead
+## an appropriate ``Future`` object will be completed. A ``Future`` is a
+## type which holds a value which is not yet available, but which *may* be
+## available in the future. You can check whether a future is finished
+## by using the ``finished`` function. When a future is finished it means that
+## either the value that it holds is now available or it holds an error instead.
+## The latter situation occurs when the operation to complete a future fails
+## with an exception. You can distinguish between the two situations with the
+## ``failed`` function.
+##
+## Future objects can also store a callback procedure which will be called
+## automatically once the future completes.
+##
+## Futures therefore can be thought of as an implementation of the proactor
+## pattern. In this
+## pattern you make a request for an action, and once that action is fulfilled
+## a future is completed with the result of that action. Requests can be
+## made by calling the appropriate functions. For example: calling the ``recv``
+## function will create a request for some data to be read from a socket. The
+## future which the ``recv`` function returns will then complete once the
+## requested amount of data is read **or** an exception occurs.
+##
+## Code to read some data from a socket may look something like this:
+##
+##   .. code-block::nim
+##      var future = socket.recv(100)
+##      future.callback =
+##        proc () =
+##          echo(future.read)
+##
+## All asynchronous functions returning a ``Future`` will not block. They
+## will not however return immediately. An asynchronous function will have
+## code which will be executed before an asynchronous request is made, in most
+## cases this code sets up the request.
+##
+## In the above example, the ``recv`` function will return a brand new
+## ``Future`` instance once the request for data to be read from the socket
+## is made. This ``Future`` instance will complete once the requested amount
+## of data is read, in this case it is 100 bytes. The second line sets a
+## callback on this future which will be called once the future completes.
+## All the callback does is write the data stored in the future to ``stdout``.
+## The ``read`` function is used for this and it checks whether the future
+## completes with an error for you (if it did it will simply raise the
+## error), if there is no error however it returns the value of the future.
+##
+## Asynchronous procedures
+## -----------------------
+##
+## Asynchronous procedures remove the pain of working with callbacks. They do
+## this by allowing you to write asynchronous code the same way as you would
+## write synchronous code.
+##
+## An asynchronous procedure is marked using the ``{.async.}`` pragma.
+## When marking a procedure with the ``{.async.}`` pragma it must have a
+## ``Future[T]`` return type or no return type at all. If you do not specify
+## a return type then ``Future[void]`` is assumed.
+##
+## Inside asynchronous procedures ``await`` can be used to call any
+## procedures which return a
+## ``Future``; this includes asynchronous procedures. When a procedure is
+## "awaited", the asynchronous procedure it is awaited in will
+## suspend its execution
+## until the awaited procedure's Future completes. At which point the
+## asynchronous procedure will resume its execution. During the period
+## when an asynchronous procedure is suspended other asynchronous procedures
+## will be run by the dispatcher.
+##
+## The ``await`` call may be used in many contexts. It can be used on the right
+## hand side of a variable declaration: ``var data = await socket.recv(100)``,
+## in which case the variable will be set to the value of the future
+## automatically. It can be used to await a ``Future`` object, and it can
+## be used to await a procedure returning a ``Future[void]``:
+## ``await socket.send("foobar")``.
+##
+## Discarding futures
+## ------------------
+##
+## Futures should **never** be discarded. This is because they may contain
+## errors. If you do not care for the result of a Future then you should
+## use the ``asyncCheck`` procedure instead of the ``discard`` keyword.
+##
+## Examples
+## --------
+##
+## For examples take a look at the documentation for the modules implementing
+## asynchronous IO. A good place to start is the
+## `asyncnet module <asyncnet.html>`_.
+##
+## Limitations/Bugs
+## ----------------
+##
+## * ``except`` statement (without `try`) does not work inside async procedures.
+## * The effect system (``raises: []``) does not work with async procedures.
+## * Can't await in a ``except`` body
+
+
+# TODO: Check if yielded future is nil and throw a more meaningful exception
+
+# -- Futures
+
+type
+  FutureBase* = ref object of RootObj ## Untyped future.
+    cb: proc () {.closure,gcsafe.}
+    finished: bool
+    error*: ref Exception ## Stored exception
+    errorStackTrace*: string
+    when not defined(release):
+      stackTrace: string ## For debugging purposes only.
+      id: int
+      fromProc: string
+
+  Future*[T] = ref object of FutureBase ## Typed future.
+    value: T ## Stored value
+
+{.deprecated: [PFutureBase: FutureBase, PFuture: Future].}
+
+
+var currentID = 0
+proc newFuture*[T](fromProc: string = "unspecified"): Future[T] =
+  ## Creates a new future.
+  ##
+  ## Specifying ``fromProc``, which is a string specifying the name of the proc
+  ## that this future belongs to, is a good habit as it helps with debugging.
+  new(result)
+  result.finished = false
+  when not defined(release):
+    result.stackTrace = getStackTrace()
+    result.id = currentID
+    result.fromProc = fromProc
+    currentID.inc()
+
+proc checkFinished[T](future: Future[T]) =
+  when not defined(release):
+    if future.finished:
+      echo("<-----> ", future.id, " ", future.fromProc)
+      echo(future.stackTrace)
+      echo("-----")
+      when T is string:
+        echo("Contents: ", future.value.repr)
+      echo("<----->")
+      echo("Future already finished, cannot finish twice.")
+      echo getStackTrace()
+      assert false
+
+proc complete*[T](future: Future[T], val: T) =
+  ## Completes ``future`` with value ``val``.
+  #assert(not future.finished, "Future already finished, cannot finish twice.")
+  checkFinished(future)
+  assert(future.error == nil)
+  future.value = val
+  future.finished = true
+  if future.cb != nil:
+    future.cb()
+
+proc complete*(future: Future[void]) =
+  ## Completes a void ``future``.
+  #assert(not future.finished, "Future already finished, cannot finish twice.")
+  checkFinished(future)
+  assert(future.error == nil)
+  future.finished = true
+  if future.cb != nil:
+    future.cb()
+
+proc fail*[T](future: Future[T], error: ref Exception) =
+  ## Completes ``future`` with ``error``.
+  #assert(not future.finished, "Future already finished, cannot finish twice.")
+  checkFinished(future)
+  future.finished = true
+  future.error = error
+  future.errorStackTrace =
+    if getStackTrace(error) == "": getStackTrace() else: getStackTrace(error)
+  if future.cb != nil:
+    future.cb()
+  else:
+    # This is to prevent exceptions from being silently ignored when a future
+    # is discarded.
+    # TODO: This may turn out to be a bad idea.
+    # Turns out this is a bad idea.
+    #raise error
+    discard
+
+proc `callback=`*(future: FutureBase, cb: proc () {.closure,gcsafe.}) =
+  ## Sets the callback proc to be called when the future completes.
+  ##
+  ## If future has already completed then ``cb`` will be called immediately.
+  ##
+  ## **Note**: You most likely want the other ``callback`` setter which
+  ## passes ``future`` as a param to the callback.
+  future.cb = cb
+  if future.finished:
+    future.cb()
+
+proc `callback=`*[T](future: Future[T],
+    cb: proc (future: Future[T]) {.closure,gcsafe.}) =
+  ## Sets the callback proc to be called when the future completes.
+  ##
+  ## If future has already completed then ``cb`` will be called immediately.
+  future.callback = proc () = cb(future)
+
+proc echoOriginalStackTrace[T](future: Future[T]) =
+  # TODO: Come up with something better.
+  when not defined(release):
+    echo("Original stack trace in ", future.fromProc, ":")
+    if not future.errorStackTrace.isNil and future.errorStackTrace != "":
+      echo(future.errorStackTrace)
+    else:
+      echo("Empty or nil stack trace.")
+    echo("Continuing...")
+
+proc read*[T](future: Future[T]): T =
+  ## Retrieves the value of ``future``. Future must be finished otherwise
+  ## this function will fail with a ``ValueError`` exception.
+  ##
+  ## If the result of the future is an error then that error will be raised.
+  if future.finished:
+    if future.error != nil:
+      echoOriginalStackTrace(future)
+      raise future.error
+    when T isnot void:
+      return future.value
+  else:
+    # TODO: Make a custom exception type for this?
+    raise newException(ValueError, "Future still in progress.")
+
+proc readError*[T](future: Future[T]): ref Exception =
+  ## Retrieves the exception stored in ``future``.
+  ##
+  ## An ``ValueError`` exception will be thrown if no exception exists
+  ## in the specified Future.
+  if future.error != nil: return future.error
+  else:
+    raise newException(ValueError, "No error in future.")
+
+proc finished*[T](future: Future[T]): bool =
+  ## Determines whether ``future`` has completed.
+  ##
+  ## ``True`` may indicate an error or a value. Use ``failed`` to distinguish.
+  future.finished
+
+proc failed*(future: FutureBase): bool =
+  ## Determines whether ``future`` completed with an error.
+  return future.error != nil
+
+proc asyncCheck*[T](future: Future[T]) =
+  ## Sets a callback on ``future`` which raises an exception if the future
+  ## finished with an error.
+  ##
+  ## This should be used instead of ``discard`` to discard void futures.
+  future.callback =
+    proc () =
+      if future.failed:
+        echoOriginalStackTrace(future)
+        raise future.error
+
+proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
+  ## Returns a future which will complete once both ``fut1`` and ``fut2``
+  ## complete.
+  var retFuture = newFuture[void]("asyncdispatch.`and`")
+  fut1.callback =
+    proc () =
+      if fut2.finished: retFuture.complete()
+  fut2.callback =
+    proc () =
+      if fut1.finished: retFuture.complete()
+  return retFuture
+
+proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
+  ## Returns a future which will complete once either ``fut1`` or ``fut2``
+  ## complete.
+  var retFuture = newFuture[void]("asyncdispatch.`or`")
+  proc cb() =
+    if not retFuture.finished: retFuture.complete()
+  fut1.callback = cb
+  fut2.callback = cb
+  return retFuture
+
+type
+  PDispatcherBase = ref object of RootRef
+    timers: seq[tuple[finishAt: float, fut: Future[void]]]
+
+proc processTimers(p: PDispatcherBase) =
+  var oldTimers = p.timers
+  p.timers = @[]
+  for t in oldTimers:
+    if epochTime() >= t.finishAt:
+      t.fut.complete()
+    else:
+      p.timers.add(t)
+
+when defined(windows) or defined(nimdoc):
+  import winlean, sets, hashes
+  type
+    TCompletionKey = Dword
+
+    TCompletionData* = object
+      fd*: TAsyncFD # TODO: Rename this.
+      cb*: proc (fd: TAsyncFD, bytesTransferred: Dword,
+                errcode: OSErrorCode) {.closure,gcsafe.}
+
+    PDispatcher* = ref object of PDispatcherBase
+      ioPort: THandle
+      handles: HashSet[TAsyncFD]
+
+    TCustomOverlapped = object of TOVERLAPPED
+      data*: TCompletionData
+
+    PCustomOverlapped* = ref TCustomOverlapped
+
+    TAsyncFD* = distinct int
+
+  proc hash(x: TAsyncFD): THash {.borrow.}
+  proc `==`*(x: TAsyncFD, y: TAsyncFD): bool {.borrow.}
+
+  proc newDispatcher*(): PDispatcher =
+    ## Creates a new Dispatcher instance.
+    new result
+    result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)
+    result.handles = initSet[TAsyncFD]()
+    result.timers = @[]
+
+  var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
+  proc getGlobalDispatcher*(): PDispatcher =
+    ## Retrieves the global thread-local dispatcher.
+    if gDisp.isNil: gDisp = newDispatcher()
+    result = gDisp
+
+  proc register*(fd: TAsyncFD) =
+    ## Registers ``fd`` with the dispatcher.
+    let p = getGlobalDispatcher()
+    if createIoCompletionPort(fd.THandle, p.ioPort,
+                              cast[TCompletionKey](fd), 1) == 0:
+      raiseOSError(osLastError())
+    p.handles.incl(fd)
+
+  proc verifyPresence(fd: TAsyncFD) =
+    ## Ensures that file descriptor has been registered with the dispatcher.
+    let p = getGlobalDispatcher()
+    if fd notin p.handles:
+      raise newException(ValueError,
+        "Operation performed on a socket which has not been registered with" &
+        " the dispatcher yet.")
+
+  proc poll*(timeout = 500) =
+    ## Waits for completion events and processes them.
+    let p = getGlobalDispatcher()
+    if p.handles.len == 0 and p.timers.len == 0:
+      raise newException(ValueError,
+        "No handles or timers registered in dispatcher.")
+
+    let llTimeout =
+      if timeout ==  -1: winlean.INFINITE
+      else: timeout.int32
+    var lpNumberOfBytesTransferred: Dword
+    var lpCompletionKey: ULONG
+    var customOverlapped: PCustomOverlapped
+    let res = getQueuedCompletionStatus(p.ioPort,
+        addr lpNumberOfBytesTransferred, addr lpCompletionKey,
+        cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool
+
+    # http://stackoverflow.com/a/12277264/492186
+    # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html
+    if res:
+      # This is useful for ensuring the reliability of the overlapped struct.
+      assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD
+
+      customOverlapped.data.cb(customOverlapped.data.fd,
+          lpNumberOfBytesTransferred, OSErrorCode(-1))
+      GC_unref(customOverlapped)
+    else:
+      let errCode = osLastError()
+      if customOverlapped != nil:
+        assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD
+        customOverlapped.data.cb(customOverlapped.data.fd,
+            lpNumberOfBytesTransferred, errCode)
+        GC_unref(customOverlapped)
+      else:
+        if errCode.int32 == WAIT_TIMEOUT:
+          # Timed out
+          discard
+        else: raiseOSError(errCode)
+
+    # Timer processing.
+    processTimers(p)
+
+  var connectExPtr: pointer = nil
+  var acceptExPtr: pointer = nil
+  var getAcceptExSockAddrsPtr: pointer = nil
+
+  proc initPointer(s: SocketHandle, fun: var pointer, guid: var TGUID): bool =
+    # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c
+    var bytesRet: Dword
+    fun = nil
+    result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid,
+                      sizeof(TGUID).Dword, addr fun, sizeof(pointer).Dword,
+                      addr bytesRet, nil, nil) == 0
+
+  proc initAll() =
+    let dummySock = newRawSocket()
+    if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX):
+      raiseOSError(osLastError())
+    if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX):
+      raiseOSError(osLastError())
+    if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS):
+      raiseOSError(osLastError())
+
+  proc connectEx(s: SocketHandle, name: ptr SockAddr, namelen: cint,
+                  lpSendBuffer: pointer, dwSendDataLength: Dword,
+                  lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool =
+    if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().")
+    let fun =
+      cast[proc (s: SocketHandle, name: ptr SockAddr, namelen: cint,
+         lpSendBuffer: pointer, dwSendDataLength: Dword,
+         lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr)
+
+    result = fun(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent,
+         lpOverlapped)
+
+  proc acceptEx(listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer,
+                 dwReceiveDataLength, dwLocalAddressLength,
+                 dwRemoteAddressLength: Dword, lpdwBytesReceived: PDword,
+                 lpOverlapped: POVERLAPPED): bool =
+    if acceptExPtr.isNil: raise newException(ValueError, "Need to initialise AcceptEx().")
+    let fun =
+      cast[proc (listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer,
+                 dwReceiveDataLength, dwLocalAddressLength,
+                 dwRemoteAddressLength: Dword, lpdwBytesReceived: PDword,
+                 lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](acceptExPtr)
+    result = fun(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength,
+        dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived,
+        lpOverlapped)
+
+  proc getAcceptExSockaddrs(lpOutputBuffer: pointer,
+      dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword,
+      LocalSockaddr: ptr ptr SockAddr, LocalSockaddrLength: LPInt,
+      RemoteSockaddr: ptr ptr SockAddr, RemoteSockaddrLength: LPInt) =
+    if getAcceptExSockAddrsPtr.isNil:
+      raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().")
+
+    let fun =
+      cast[proc (lpOutputBuffer: pointer,
+                 dwReceiveDataLength, dwLocalAddressLength,
+                 dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr SockAddr,
+                 LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr SockAddr,
+                RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr)
+
+    fun(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,
+                  dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength,
+                  RemoteSockaddr, RemoteSockaddrLength)
+
+  proc connect*(socket: TAsyncFD, address: string, port: Port,
+    af = AF_INET): Future[void] =
+    ## Connects ``socket`` to server at ``address:port``.
+    ##
+    ## Returns a ``Future`` which will complete when the connection succeeds
+    ## or an error occurs.
+    verifyPresence(socket)
+    var retFuture = newFuture[void]("connect")
+    # Apparently ``ConnectEx`` expects the socket to be initially bound:
+    var saddr: Sockaddr_in
+    saddr.sin_family = int16(toInt(af))
+    saddr.sin_port = 0
+    saddr.sin_addr.s_addr = INADDR_ANY
+    if bindAddr(socket.SocketHandle, cast[ptr SockAddr](addr(saddr)),
+                  sizeof(saddr).SockLen) < 0'i32:
+      raiseOSError(osLastError())
+
+    var aiList = getAddrInfo(address, port, af)
+    var success = false
+    var lastError: OSErrorCode
+    var it = aiList
+    while it != nil:
+      # "the OVERLAPPED structure must remain valid until the I/O completes"
+      # http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx
+      var ol = PCustomOverlapped()
+      GC_ref(ol)
+      ol.data = TCompletionData(fd: socket, cb:
+        proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+          if not retFuture.finished:
+            if errcode == OSErrorCode(-1):
+              retFuture.complete()
+            else:
+              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+      )
+
+      var ret = connectEx(socket.SocketHandle, it.ai_addr,
+                          sizeof(Sockaddr_in).cint, nil, 0, nil,
+                          cast[POVERLAPPED](ol))
+      if ret:
+        # Request to connect completed immediately.
+        success = true
+        retFuture.complete()
+        # We don't deallocate ``ol`` here because even though this completed
+        # immediately poll will still be notified about its completion and it will
+        # free ``ol``.
+        break
+      else:
+        lastError = osLastError()
+        if lastError.int32 == ERROR_IO_PENDING:
+          # In this case ``ol`` will be deallocated in ``poll``.
+          success = true
+          break
+        else:
+          GC_unref(ol)
+          success = false
+      it = it.ai_next
+
+    dealloc(aiList)
+    if not success:
+      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+    return retFuture
+
+  proc recv*(socket: TAsyncFD, size: int,
+             flags = {SocketFlag.SafeDisconn}): Future[string] =
+    ## Reads **up to** ``size`` bytes from ``socket``. Returned future will
+    ## complete once all the data requested is read, a part of the data has been
+    ## read, or the socket has disconnected in which case the future will
+    ## complete with a value of ``""``.
+    ##
+    ## **Warning**: The ``Peek`` socket flag is not supported on Windows.
+
+
+    # Things to note:
+    #   * When WSARecv completes immediately then ``bytesReceived`` is very
+    #     unreliable.
+    #   * Still need to implement message-oriented socket disconnection,
+    #     '\0' in the message currently signifies a socket disconnect. Who
+    #     knows what will happen when someone sends that to our socket.
+    verifyPresence(socket)
+    assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
+
+    var retFuture = newFuture[string]("recv")
+    var dataBuf: TWSABuf
+    dataBuf.buf = cast[cstring](alloc0(size))
+    dataBuf.len = size
+
+    var bytesReceived: Dword
+    var flagsio = flags.toOSFlags().Dword
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: socket, cb:
+      proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            if bytesCount == 0 and dataBuf.buf[0] == '\0':
+              retFuture.complete("")
+            else:
+              var data = newString(bytesCount)
+              assert bytesCount <= size
+              copyMem(addr data[0], addr dataBuf.buf[0], bytesCount)
+              retFuture.complete($data)
+          else:
+            if flags.isDisconnectionError(errcode):
+              retFuture.complete("")
+            else:
+              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+        if dataBuf.buf != nil:
+          dealloc dataBuf.buf
+          dataBuf.buf = nil
+    )
+
+    let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
+                      addr flagsio, cast[POVERLAPPED](ol), nil)
+    if ret == -1:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        if dataBuf.buf != nil:
+          dealloc dataBuf.buf
+          dataBuf.buf = nil
+        GC_unref(ol)
+        if flags.isDisconnectionError(err):
+          retFuture.complete("")
+        else:
+          retFuture.fail(newException(OSError, osErrorMsg(err)))
+    elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
+      # We have to ensure that the buffer is empty because WSARecv will tell
+      # us immediately when it was disconnected, even when there is still
+      # data in the buffer.
+      # We want to give the user as much data as we can. So we only return
+      # the empty string (which signals a disconnection) when there is
+      # nothing left to read.
+      retFuture.complete("")
+      # TODO: "For message-oriented sockets, where a zero byte message is often
+      # allowable, a failure with an error code of WSAEDISCON is used to
+      # indicate graceful closure."
+      # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
+    else:
+      # Request to read completed immediately.
+      # From my tests bytesReceived isn't reliable.
+      let realSize =
+        if bytesReceived == 0:
+          size
+        else:
+          bytesReceived
+      var data = newString(realSize)
+      assert realSize <= size
+      copyMem(addr data[0], addr dataBuf.buf[0], realSize)
+      #dealloc dataBuf.buf
+      retFuture.complete($data)
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+    return retFuture
+
+  proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
+                flags = {SocketFlag.SafeDisconn}): Future[int] =
+    ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
+    ## at least be of that size. Returned future will complete once all the
+    ## data requested is read, a part of the data has been read, or the socket
+    ## has disconnected in which case the future will complete with a value of
+    ## ``0``.
+    ##
+    ## **Warning**: The ``Peek`` socket flag is not supported on Windows.
+
+
+    # Things to note:
+    #   * When WSARecv completes immediately then ``bytesReceived`` is very
+    #     unreliable.
+    #   * Still need to implement message-oriented socket disconnection,
+    #     '\0' in the message currently signifies a socket disconnect. Who
+    #     knows what will happen when someone sends that to our socket.
+    verifyPresence(socket)
+    assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
+
+    var retFuture = newFuture[int]("recvInto")
+
+    #buf[] = '\0'
+    var dataBuf: TWSABuf
+    dataBuf.buf = buf
+    dataBuf.len = size
+
+    var bytesReceived: Dword
+    var flagsio = flags.toOSFlags().Dword
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: socket, cb:
+      proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            if bytesCount == 0 and dataBuf.buf[0] == '\0':
+              retFuture.complete(0)
+            else:
+              retFuture.complete(bytesCount)
+          else:
+            if flags.isDisconnectionError(errcode):
+              retFuture.complete(0)
+            else:
+              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+        if dataBuf.buf != nil:
+          dataBuf.buf = nil
+    )
+
+    let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
+                      addr flagsio, cast[POVERLAPPED](ol), nil)
+    if ret == -1:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        if dataBuf.buf != nil:
+          dataBuf.buf = nil
+        GC_unref(ol)
+        if flags.isDisconnectionError(err):
+          retFuture.complete(0)
+        else:
+          retFuture.fail(newException(OSError, osErrorMsg(err)))
+    elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
+      # We have to ensure that the buffer is empty because WSARecv will tell
+      # us immediately when it was disconnected, even when there is still
+      # data in the buffer.
+      # We want to give the user as much data as we can. So we only return
+      # the empty string (which signals a disconnection) when there is
+      # nothing left to read.
+      retFuture.complete(0)
+      # TODO: "For message-oriented sockets, where a zero byte message is often
+      # allowable, a failure with an error code of WSAEDISCON is used to
+      # indicate graceful closure."
+      # ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
+    else:
+      # Request to read completed immediately.
+      # From my tests bytesReceived isn't reliable.
+      let realSize =
+        if bytesReceived == 0:
+          size
+        else:
+          bytesReceived
+      assert realSize <= size
+      retFuture.complete(realSize)
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+    return retFuture
+
+  proc send*(socket: TAsyncFD, data: string,
+             flags = {SocketFlag.SafeDisconn}): Future[void] =
+    ## Sends ``data`` to ``socket``. The returned future will complete once all
+    ## data has been sent.
+    verifyPresence(socket)
+    var retFuture = newFuture[void]("send")
+
+    var dataBuf: TWSABuf
+    dataBuf.buf = data # since this is not used in a callback, this is fine
+    dataBuf.len = data.len
+
+    var bytesReceived, lowFlags: Dword
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: socket, cb:
+      proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            retFuture.complete()
+          else:
+            if flags.isDisconnectionError(errcode):
+              retFuture.complete()
+            else:
+              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+    )
+
+    let ret = WSASend(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
+                      lowFlags, cast[POVERLAPPED](ol), nil)
+    if ret == -1:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        GC_unref(ol)
+        if flags.isDisconnectionError(err):
+          retFuture.complete()
+        else:
+          retFuture.fail(newException(OSError, osErrorMsg(err)))
+    else:
+      retFuture.complete()
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+    return retFuture
+
+  proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
+      Future[tuple[address: string, client: TAsyncFD]] =
+    ## Accepts a new connection. Returns a future containing the client socket
+    ## corresponding to that connection and the remote address of the client.
+    ## The future will complete when the connection is successfully accepted.
+    ##
+    ## The resulting client socket is automatically registered to the
+    ## dispatcher.
+    ##
+    ## The ``accept`` call may result in an error if the connecting socket
+    ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
+    ## flag is specified then this error will not be raised and instead
+    ## accept will be called again.
+    verifyPresence(socket)
+    var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr")
+
+    var clientSock = newRawSocket()
+    if clientSock == osInvalidSocket: raiseOSError(osLastError())
+
+    const lpOutputLen = 1024
+    var lpOutputBuf = newString(lpOutputLen)
+    var dwBytesReceived: Dword
+    let dwReceiveDataLength = 0.Dword # We don't want any data to be read.
+    let dwLocalAddressLength = Dword(sizeof (Sockaddr_in) + 16)
+    let dwRemoteAddressLength = Dword(sizeof(Sockaddr_in) + 16)
+
+    template completeAccept(): stmt {.immediate, dirty.} =
+      var listenSock = socket
+      let setoptRet = setsockopt(clientSock, SOL_SOCKET,
+          SO_UPDATE_ACCEPT_CONTEXT, addr listenSock,
+          sizeof(listenSock).SockLen)
+      if setoptRet != 0: raiseOSError(osLastError())
+
+      var localSockaddr, remoteSockaddr: ptr SockAddr
+      var localLen, remoteLen: int32
+      getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength,
+                           dwLocalAddressLength, dwRemoteAddressLength,
+                           addr localSockaddr, addr localLen,
+                           addr remoteSockaddr, addr remoteLen)
+      register(clientSock.TAsyncFD)
+      # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186
+      retFuture.complete(
+        (address: $inet_ntoa(cast[ptr Sockaddr_in](remoteSockAddr).sin_addr),
+         client: clientSock.TAsyncFD)
+      )
+
+    template failAccept(errcode): stmt =
+      if flags.isDisconnectionError(errcode):
+        var newAcceptFut = acceptAddr(socket, flags)
+        newAcceptFut.callback =
+          proc () =
+            if newAcceptFut.failed:
+              retFuture.fail(newAcceptFut.readError)
+            else:
+              retFuture.complete(newAcceptFut.read)
+      else:
+        retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: socket, cb:
+      proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            completeAccept()
+          else:
+            failAccept(errcode)
+    )
+
+    # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx
+    let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0],
+                       dwReceiveDataLength,
+                       dwLocalAddressLength,
+                       dwRemoteAddressLength,
+                       addr dwBytesReceived, cast[POVERLAPPED](ol))
+
+    if not ret:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        failAccept(err)
+        GC_unref(ol)
+    else:
+      completeAccept()
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it will
+      # free ``ol``.
+
+    return retFuture
+
+  proc newAsyncRawSocket*(domain, typ, protocol: cint): TAsyncFD =
+    ## Creates a new socket and registers it with the dispatcher implicitly.
+    result = newRawSocket(domain, typ, protocol).TAsyncFD
+    result.SocketHandle.setBlocking(false)
+    register(result)
+
+  proc newAsyncRawSocket*(domain: Domain = AF_INET,
+               typ: SockType = SOCK_STREAM,
+               protocol: Protocol = IPPROTO_TCP): TAsyncFD =
+    ## Creates a new socket and registers it with the dispatcher implicitly.
+    result = newRawSocket(domain, typ, protocol).TAsyncFD
+    result.SocketHandle.setBlocking(false)
+    register(result)
+
+  proc closeSocket*(socket: TAsyncFD) =
+    ## Closes a socket and ensures that it is unregistered.
+    socket.SocketHandle.close()
+    getGlobalDispatcher().handles.excl(socket)
+
+  proc unregister*(fd: TAsyncFD) =
+    ## Unregisters ``fd``.
+    getGlobalDispatcher().handles.excl(fd)
+
+  initAll()
+else:
+  import selectors
+  when defined(windows):
+    import winlean
+    const
+      EINTR = WSAEINPROGRESS
+      EINPROGRESS = WSAEINPROGRESS
+      EWOULDBLOCK = WSAEWOULDBLOCK
+      EAGAIN = EINPROGRESS
+      MSG_NOSIGNAL = 0
+  else:
+    from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
+                      MSG_NOSIGNAL
+
+  type
+    TAsyncFD* = distinct cint
+    TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.}
+
+    PData* = ref object of RootRef
+      fd: TAsyncFD
+      readCBs: seq[TCallback]
+      writeCBs: seq[TCallback]
+
+    PDispatcher* = ref object of PDispatcherBase
+      selector: Selector
+
+  proc `==`*(x, y: TAsyncFD): bool {.borrow.}
+
+  proc newDispatcher*(): PDispatcher =
+    new result
+    result.selector = newSelector()
+    result.timers = @[]
+
+  var gDisp{.threadvar.}: PDispatcher ## Global dispatcher
+  proc getGlobalDispatcher*(): PDispatcher =
+    if gDisp.isNil: gDisp = newDispatcher()
+    result = gDisp
+
+  proc update(fd: TAsyncFD, events: set[Event]) =
+    let p = getGlobalDispatcher()
+    assert fd.SocketHandle in p.selector
+    discard p.selector.update(fd.SocketHandle, events)
+
+  proc register*(fd: TAsyncFD) =
+    let p = getGlobalDispatcher()
+    var data = PData(fd: fd, readCBs: @[], writeCBs: @[])
+    p.selector.register(fd.SocketHandle, {}, data.RootRef)
+
+  proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD =
+    result = newRawSocket(domain, typ, protocol).TAsyncFD
+    result.SocketHandle.setBlocking(false)
+    when defined(macosx):
+        result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
+    register(result)
+
+  proc newAsyncRawSocket*(domain: Domain = AF_INET,
+               typ: SockType = SOCK_STREAM,
+               protocol: Protocol = IPPROTO_TCP): TAsyncFD =
+    result = newRawSocket(domain, typ, protocol).TAsyncFD
+    result.SocketHandle.setBlocking(false)
+    when defined(macosx):
+        result.SocketHandle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
+    register(result)
+
+  proc closeSocket*(sock: TAsyncFD) =
+    let disp = getGlobalDispatcher()
+    sock.SocketHandle.close()
+    disp.selector.unregister(sock.SocketHandle)
+
+  proc unregister*(fd: TAsyncFD) =
+    getGlobalDispatcher().selector.unregister(fd.SocketHandle)
+
+  proc addRead*(fd: TAsyncFD, cb: TCallback) =
+    let p = getGlobalDispatcher()
+    if fd.SocketHandle notin p.selector:
+      raise newException(ValueError, "File descriptor not registered.")
+    p.selector[fd.SocketHandle].data.PData.readCBs.add(cb)
+    update(fd, p.selector[fd.SocketHandle].events + {EvRead})
+
+  proc addWrite*(fd: TAsyncFD, cb: TCallback) =
+    let p = getGlobalDispatcher()
+    if fd.SocketHandle notin p.selector:
+      raise newException(ValueError, "File descriptor not registered.")
+    p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb)
+    update(fd, p.selector[fd.SocketHandle].events + {EvWrite})
+
+  proc poll*(timeout = 500) =
+    let p = getGlobalDispatcher()
+    for info in p.selector.select(timeout):
+      let data = PData(info.key.data)
+      assert data.fd == info.key.fd.TAsyncFD
+      #echo("In poll ", data.fd.cint)
+      if EvError in info.events:
+        closeSocket(data.fd)
+        continue
+
+      if EvRead in info.events:
+        # Callback may add items to ``data.readCBs`` which causes issues if
+        # we are iterating over ``data.readCBs`` at the same time. We therefore
+        # make a copy to iterate over.
+        let currentCBs = data.readCBs
+        data.readCBs = @[]
+        for cb in currentCBs:
+          if not cb(data.fd):
+            # Callback wants to be called again.
+            data.readCBs.add(cb)
+
+      if EvWrite in info.events:
+        let currentCBs = data.writeCBs
+        data.writeCBs = @[]
+        for cb in currentCBs:
+          if not cb(data.fd):
+            # Callback wants to be called again.
+            data.writeCBs.add(cb)
+
+      if info.key in p.selector:
+        var newEvents: set[Event]
+        if data.readCBs.len != 0: newEvents = {EvRead}
+        if data.writeCBs.len != 0: newEvents = newEvents + {EvWrite}
+        if newEvents != info.key.events:
+          update(data.fd, newEvents)
+      else:
+        # FD no longer a part of the selector. Likely been closed
+        # (e.g. socket disconnected).
+        discard
+
+    processTimers(p)
+
+  proc connect*(socket: TAsyncFD, address: string, port: Port,
+    af = AF_INET): Future[void] =
+    var retFuture = newFuture[void]("connect")
+
+    proc cb(fd: TAsyncFD): bool =
+      # We have connected.
+      retFuture.complete()
+      return true
+
+    var aiList = getAddrInfo(address, port, af)
+    var success = false
+    var lastError: OSErrorCode
+    var it = aiList
+    while it != nil:
+      var ret = connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen)
+      if ret == 0:
+        # Request to connect completed immediately.
+        success = true
+        retFuture.complete()
+        break
+      else:
+        lastError = osLastError()
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+          success = true
+          addWrite(socket, cb)
+          break
+        else:
+          success = false
+      it = it.ai_next
+
+    dealloc(aiList)
+    if not success:
+      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+    return retFuture
+
+  proc recv*(socket: TAsyncFD, size: int,
+             flags = {SocketFlag.SafeDisconn}): Future[string] =
+    var retFuture = newFuture[string]("recv")
+
+    var readBuffer = newString(size)
+
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
+                     flags.toOSFlags())
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          if flags.isDisconnectionError(lastError):
+            retFuture.complete("")
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      elif res == 0:
+        # Disconnected
+        retFuture.complete("")
+      else:
+        readBuffer.setLen(res)
+        retFuture.complete(readBuffer)
+    # TODO: The following causes a massive slowdown.
+    #if not cb(socket):
+    addRead(socket, cb)
+    return retFuture
+
+  proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
+                  flags = {SocketFlag.SafeDisconn}): Future[int] =
+    var retFuture = newFuture[int]("recvInto")
+
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      let res = recv(sock.SocketHandle, buf, size.cint,
+                     flags.toOSFlags())
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          if flags.isDisconnectionError(lastError):
+            retFuture.complete(0)
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      else:
+        retFuture.complete(res)
+    # TODO: The following causes a massive slowdown.
+    #if not cb(socket):
+    addRead(socket, cb)
+    return retFuture
+
+  proc send*(socket: TAsyncFD, data: string,
+             flags = {SocketFlag.SafeDisconn}): Future[void] =
+    var retFuture = newFuture[void]("send")
+
+    var written = 0
+
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      let netSize = data.len-written
+      var d = data.cstring
+      let res = send(sock.SocketHandle, addr d[written], netSize.cint,
+                     MSG_NOSIGNAL)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
+          if flags.isDisconnectionError(lastError):
+            retFuture.complete()
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      else:
+        written.inc(res)
+        if res != netSize:
+          result = false # We still have data to send.
+        else:
+          retFuture.complete()
+    # TODO: The following causes crashes.
+    #if not cb(socket):
+    addWrite(socket, cb)
+    return retFuture
+
+  proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}):
+      Future[tuple[address: string, client: TAsyncFD]] =
+    var retFuture = newFuture[tuple[address: string,
+        client: TAsyncFD]]("acceptAddr")
+    proc cb(sock: TAsyncFD): bool =
+      result = true
+      var sockAddress: SockAddr_in
+      var addrLen = sizeof(sockAddress).Socklen
+      var client = accept(sock.SocketHandle,
+                          cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
+      if client == osInvalidSocket:
+        let lastError = osLastError()
+        assert lastError.int32 notin {EWOULDBLOCK, EAGAIN}
+        if lastError.int32 == EINTR:
+          return false
+        else:
+          if flags.isDisconnectionError(lastError):
+            return false
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+      else:
+        register(client.TAsyncFD)
+        retFuture.complete(($inet_ntoa(sockAddress.sin_addr), client.TAsyncFD))
+    addRead(socket, cb)
+    return retFuture
+
+proc sleepAsync*(ms: int): Future[void] =
+  ## Suspends the execution of the current async procedure for the next
+  ## ``ms`` milliseconds.
+  var retFuture = newFuture[void]("sleepAsync")
+  let p = getGlobalDispatcher()
+  p.timers.add((epochTime() + (ms / 1000), retFuture))
+  return retFuture
+
+proc accept*(socket: TAsyncFD,
+    flags = {SocketFlag.SafeDisconn}): Future[TAsyncFD] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection.
+  ## The future will complete when the connection is successfully accepted.
+  var retFut = newFuture[TAsyncFD]("accept")
+  var fut = acceptAddr(socket, flags)
+  fut.callback =
+    proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
+      assert future.finished
+      if future.failed:
+        retFut.fail(future.error)
+      else:
+        retFut.complete(future.read.client)
+  return retFut
+
+# -- Await Macro
+
+proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
+  # Skips a nest of StmtList's.
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = skipUntilStmtList(node[0])
+
+proc skipStmtList(node: NimNode): NimNode {.compileTime.} =
+  result = node
+  if node[0].kind == nnkStmtList:
+    result = node[0]
+
+template createCb(retFutureSym, iteratorNameSym,
+                   name: expr): stmt {.immediate.} =
+  var nameIterVar = iteratorNameSym
+  #{.push stackTrace: off.}
+  proc cb {.closure,gcsafe.} =
+    try:
+      if not nameIterVar.finished:
+        var next = nameIterVar()
+        if next == nil:
+          assert retFutureSym.finished, "Async procedure's (" &
+                 name & ") return Future was not finished."
+        else:
+          next.callback = cb
+    except:
+      if retFutureSym.finished:
+        # Take a look at tasyncexceptions for the bug which this fixes.
+        # That test explains it better than I can here.
+        raise
+      else:
+        retFutureSym.fail(getCurrentException())
+  cb()
+  #{.pop.}
+proc generateExceptionCheck(futSym,
+    tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
+  if tryStmt.kind == nnkNilLit:
+    result = rootReceiver
+  else:
+    var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
+    let errorNode = newDotExpr(futSym, newIdentNode("error"))
+    for i in 1 .. <tryStmt.len:
+      let exceptBranch = tryStmt[i]
+      if exceptBranch[0].kind == nnkStmtList:
+        exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
+      else:
+        var exceptIdentCount = 0
+        var ifCond: NimNode
+        for i in 0 .. <exceptBranch.len:
+          let child = exceptBranch[i]
+          if child.kind == nnkIdent:
+            let cond = infix(errorNode, "of", child)
+            if exceptIdentCount == 0:
+              ifCond = cond
+            else:
+              ifCond = infix(ifCond, "or", cond)
+          else:
+            break
+          exceptIdentCount.inc
+
+        expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
+        exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
+    # -> -> else: raise futSym.error
+    exceptionChecks.add((newIdentNode("true"),
+        newNimNode(nnkRaiseStmt).add(errorNode)))
+    # Read the future if there is no error.
+    # -> else: futSym.read
+    let elseNode = newNimNode(nnkElse, fromNode)
+    elseNode.add newNimNode(nnkStmtList, fromNode)
+    elseNode[0].add rootReceiver
+
+    let ifBody = newStmtList()
+    ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
+    ifBody.add newIfStmt(exceptionChecks)
+    ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
+
+    result = newIfStmt(
+      (newDotExpr(futSym, newIdentNode("failed")), ifBody)
+    )
+    result.add elseNode
+
+template createVar(result: var NimNode, futSymName: string,
+                   asyncProc: NimNode,
+                   valueReceiver, rootReceiver: expr,
+                   fromNode: NimNode) =
+  result = newNimNode(nnkStmtList, fromNode)
+  var futSym = genSym(nskVar, "future")
+  result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
+  result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x>
+  valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
+  result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
+
+proc processBody(node, retFutureSym: NimNode,
+                 subTypeIsVoid: bool,
+                 tryStmt: NimNode): NimNode {.compileTime.} =
+  #echo(node.treeRepr)
+  result = node
+  case node.kind
+  of nnkReturnStmt:
+    result = newNimNode(nnkStmtList, node)
+    if node[0].kind == nnkEmpty:
+      if not subTypeIsVoid:
+        result.add newCall(newIdentNode("complete"), retFutureSym,
+            newIdentNode("result"))
+      else:
+        result.add newCall(newIdentNode("complete"), retFutureSym)
+    else:
+      result.add newCall(newIdentNode("complete"), retFutureSym,
+        node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt))
+
+    result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
+    return # Don't process the children of this return stmt
+  of nnkCommand, nnkCall:
+    if node[0].kind == nnkIdent and node[0].ident == !"await":
+      case node[1].kind
+      of nnkIdent, nnkInfix:
+        # await x
+        result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
+      of nnkCall, nnkCommand:
+        # await foo(p, x)
+        var futureValue: NimNode
+        result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
+                  futureValue, node)
+      else:
+        error("Invalid node kind in 'await', got: " & $node[1].kind)
+    elif node.len > 1 and node[1].kind == nnkCommand and
+         node[1][0].kind == nnkIdent and node[1][0].ident == !"await":
+      # foo await x
+      var newCommand = node
+      result.createVar("future" & $node[0].toStrLit, node[1][1], newCommand[1],
+                newCommand, node)
+
+  of nnkVarSection, nnkLetSection:
+    case node[0][2].kind
+    of nnkCommand:
+      if node[0][2][0].kind == nnkIdent and node[0][2][0].ident == !"await":
+        # var x = await y
+        var newVarSection = node # TODO: Should this use copyNimNode?
+        result.createVar("future" & $node[0][0].ident, node[0][2][1],
+          newVarSection[0][2], newVarSection, node)
+    else: discard
+  of nnkAsgn:
+    case node[1].kind
+    of nnkCommand:
+      if node[1][0].ident == !"await":
+        # x = await y
+        var newAsgn = node
+        result.createVar("future" & $node[0].toStrLit, node[1][1], newAsgn[1], newAsgn, node)
+    else: discard
+  of nnkDiscardStmt:
+    # discard await x
+    if node[0].kind == nnkCommand and node[0][0].kind == nnkIdent and
+          node[0][0].ident == !"await":
+      var newDiscard = node
+      result.createVar("futureDiscard_" & $toStrLit(node[0][1]), node[0][1],
+                newDiscard[0], newDiscard, node)
+  of nnkTryStmt:
+    # try: await x; except: ...
+    result = newNimNode(nnkStmtList, node)
+    template wrapInTry(n, tryBody: expr) =
+      var temp = n
+      n[0] = tryBody
+      tryBody = temp
+
+      # Transform ``except`` body.
+      # TODO: Could we perform some ``await`` transformation here to get it
+      # working in ``except``?
+      tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
+
+    proc processForTry(n: NimNode, i: var int,
+                       res: NimNode): bool {.compileTime.} =
+      ## Transforms the body of the tryStmt. Does not transform the
+      ## body in ``except``.
+      ## Returns true if the tryStmt node was transformed into an ifStmt.
+      result = false
+      var skipped = n.skipStmtList()
+      while i < skipped.len:
+        var processed = processBody(skipped[i], retFutureSym,
+                                    subTypeIsVoid, n)
+
+        # Check if we transformed the node into an exception check.
+        # This suggests skipped[i] contains ``await``.
+        if processed.kind != skipped[i].kind or processed.len != skipped[i].len:
+          processed = processed.skipUntilStmtList()
+          expectKind(processed, nnkStmtList)
+          expectKind(processed[2][1], nnkElse)
+          i.inc
+
+          if not processForTry(n, i, processed[2][1][0]):
+            # We need to wrap the nnkElse nodes back into a tryStmt.
+            # As they are executed if an exception does not happen
+            # inside the awaited future.
+            # The following code will wrap the nodes inside the
+            # original tryStmt.
+            wrapInTry(n, processed[2][1][0])
+
+          res.add processed
+          result = true
+        else:
+          res.add skipped[i]
+          i.inc
+    var i = 0
+    if not processForTry(node, i, result):
+      # If the tryStmt hasn't been transformed we can just put the body
+      # back into it.
+      wrapInTry(node, result)
+    return
+  else: discard
+
+  for i in 0 .. <result.len:
+    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, nil)
+
+proc getName(node: NimNode): string {.compileTime.} =
+  case node.kind
+  of nnkPostfix:
+    return $node[1].ident
+  of nnkIdent:
+    return $node.ident
+  of nnkEmpty:
+    return "anonymous"
+  else:
+    error("Unknown name.")
+
+macro async*(prc: stmt): stmt {.immediate.} =
+  ## Macro which processes async procedures into the appropriate
+  ## iterators and yield statements.
+  if prc.kind notin {nnkProcDef, nnkLambda}:
+    error("Cannot transform this node kind into an async proc." &
+          " Proc definition or lambda node expected.")
+
+  hint("Processing " & prc[0].getName & " as an async proc.")
+
+  let returnType = prc[3][0]
+  # Verify that the return type is a Future[T]
+  if returnType.kind == nnkIdent:
+    error("Expected return type of 'Future' got '" & $returnType & "'")
+  elif returnType.kind == nnkBracketExpr:
+    if $returnType[0] != "Future":
+      error("Expected return type of 'Future' got '" & $returnType[0] & "'")
+
+  let subtypeIsVoid = returnType.kind == nnkEmpty or
+        (returnType.kind == nnkBracketExpr and
+         returnType[1].kind == nnkIdent and returnType[1].ident == !"void")
+
+  var outerProcBody = newNimNode(nnkStmtList, prc[6])
+
+  # -> var retFuture = newFuture[T]()
+  var retFutureSym = genSym(nskVar, "retFuture")
+  var subRetType =
+    if returnType.kind == nnkEmpty: newIdentNode("void")
+    else: returnType[1]
+  outerProcBody.add(
+    newVarStmt(retFutureSym,
+      newCall(
+        newNimNode(nnkBracketExpr, prc[6]).add(
+          newIdentNode(!"newFuture"), # TODO: Strange bug here? Remove the `!`.
+          subRetType),
+      newLit(prc[0].getName)))) # Get type from return type of this proc
+
+  # -> iterator nameIter(): FutureBase {.closure.} =
+  # ->   {.push warning[resultshadowed]: off.}
+  # ->   var result: T
+  # ->   {.pop.}
+  # ->   <proc_body>
+  # ->   complete(retFuture, result)
+  var iteratorNameSym = genSym(nskIterator, $prc[0].getName & "Iter")
+  var procBody = prc[6].processBody(retFutureSym, subtypeIsVoid, nil)
+  if not subtypeIsVoid:
+    procBody.insert(0, newNimNode(nnkPragma).add(newIdentNode("push"),
+      newNimNode(nnkExprColonExpr).add(newNimNode(nnkBracketExpr).add(
+        newIdentNode("warning"), newIdentNode("resultshadowed")),
+      newIdentNode("off")))) # -> {.push warning[resultshadowed]: off.}
+
+    procBody.insert(1, newNimNode(nnkVarSection, prc[6]).add(
+      newIdentDefs(newIdentNode("result"), returnType[1]))) # -> var result: T
+
+    procBody.insert(2, newNimNode(nnkPragma).add(
+      newIdentNode("pop"))) # -> {.pop.})
+
+    procBody.add(
+      newCall(newIdentNode("complete"),
+        retFutureSym, newIdentNode("result"))) # -> complete(retFuture, result)
+  else:
+    # -> complete(retFuture)
+    procBody.add(newCall(newIdentNode("complete"), retFutureSym))
+
+  var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
+                                procBody, nnkIteratorDef)
+  closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure"))
+  outerProcBody.add(closureIterator)
+
+  # -> createCb(retFuture)
+  #var cbName = newIdentNode("cb")
+  var procCb = newCall(bindSym"createCb", retFutureSym, iteratorNameSym,
+                       newStrLitNode(prc[0].getName))
+  outerProcBody.add procCb
+
+  # -> return retFuture
+  outerProcBody.add newNimNode(nnkReturnStmt, prc[6][prc[6].len-1]).add(retFutureSym)
+
+  result = prc
+
+  # Remove the 'async' pragma.
+  for i in 0 .. <result[4].len:
+    if result[4][i].kind == nnkIdent and result[4][i].ident == !"async":
+      result[4].del(i)
+  if subtypeIsVoid:
+    # Add discardable pragma.
+    if returnType.kind == nnkEmpty:
+      # Add Future[void]
+      result[3][0] = parseExpr("Future[void]")
+
+  result[6] = outerProcBody
+
+  #echo(treeRepr(result))
+  #if prc[0].getName == "test":
+  #  echo(toStrLit(result))
+
+proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
+  ## Reads a line of data from ``socket``. Returned future will complete once
+  ## a full line is read or an error occurs.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ##
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## If the socket is disconnected in the middle of a line (before ``\r\L``
+  ## is read) then line will be set to ``""``.
+  ## The partial line **will be lost**.
+  ##
+  ## **Warning**: This assumes that lines are delimited by ``\r\L``.
+  ##
+  ## **Note**: This procedure is mostly used for testing. You likely want to
+  ## use ``asyncnet.recvLine`` instead.
+
+  template addNLIfEmpty(): stmt =
+    if result.len == 0:
+      result.add("\c\L")
+
+  result = ""
+  var c = ""
+  while true:
+    c = await recv(socket, 1)
+    if c.len == 0:
+      return ""
+    if c == "\r":
+      c = await recv(socket, 1)
+      assert c == "\l"
+      addNLIfEmpty()
+      return
+    elif c == "\L":
+      addNLIfEmpty()
+      return
+    add(result, c)
+
+proc runForever*() =
+  ## Begins a never ending global dispatcher poll loop.
+  while true:
+    poll()
+
+proc waitFor*[T](fut: Future[T]): T =
+  ## **Blocks** the current thread until the specified future completes.
+  while not fut.finished:
+    poll()
+
+  fut.read
diff --git a/lib/pure/asyncdispatch.nim.cfg b/lib/pure/asyncdispatch.nim.cfg
new file mode 100644
index 000000000..e88f8eec3
--- /dev/null
+++ b/lib/pure/asyncdispatch.nim.cfg
@@ -0,0 +1,3 @@
+@if nimdoc:
+  --os:linux
+@end
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
new file mode 100644
index 000000000..25e121183
--- /dev/null
+++ b/lib/pure/asyncfile.nim
@@ -0,0 +1,325 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements asynchronous file reading and writing.
+##
+## .. code-block:: Nim
+##    import asyncfile, asyncdispatch, os
+##
+##    proc main() {.async.} =
+##      var file = openAsync(getTempDir() / "foobar.txt", fmReadWrite)
+##      await file.write("test")
+##      file.setFilePos(0)
+##      let data = await file.readAll()
+##      doAssert data == "test"
+##      file.close()
+##
+##    waitFor main()
+
+import asyncdispatch, os
+
+when defined(windows) or defined(nimdoc):
+  import winlean
+else:
+  import posix
+
+type
+  AsyncFile* = ref object
+    fd: TAsyncFd
+    offset: int64
+
+when defined(windows) or defined(nimdoc):
+  proc getDesiredAccess(mode: FileMode): int32 =
+    case mode
+    of fmRead:
+      result = GENERIC_READ
+    of fmWrite, fmAppend:
+      result = GENERIC_WRITE
+    of fmReadWrite, fmReadWriteExisting:
+      result = GENERIC_READ or GENERIC_WRITE
+
+  proc getCreationDisposition(mode: FileMode, filename: string): int32 =
+    case mode
+    of fmRead, fmReadWriteExisting:
+      OPEN_EXISTING
+    of fmAppend, fmReadWrite, fmWrite:
+      if fileExists(filename):
+        OPEN_EXISTING
+      else:
+        CREATE_NEW
+else:
+  proc getPosixFlags(mode: FileMode): cint =
+    case mode
+    of fmRead:
+      result = O_RDONLY
+    of fmWrite:
+      result = O_WRONLY or O_CREAT
+    of fmAppend:
+      result = O_WRONLY or O_CREAT or O_APPEND
+    of fmReadWrite:
+      result = O_RDWR or O_CREAT
+    of fmReadWriteExisting:
+      result = O_RDWR
+    result = result or O_NONBLOCK
+
+proc getFileSize(f: AsyncFile): int64 =
+  ## Retrieves the specified file's size.
+  when defined(windows) or defined(nimdoc):
+    var high: DWord
+    let low = getFileSize(f.fd.THandle, addr high)
+    if low == INVALID_FILE_SIZE:
+      raiseOSError(osLastError())
+    return (high shl 32) or low
+
+proc openAsync*(filename: string, mode = fmRead): AsyncFile =
+  ## Opens a file specified by the path in ``filename`` using
+  ## the specified ``mode`` asynchronously.
+  new result
+  when defined(windows) or defined(nimdoc):
+    let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL
+    let desiredAccess = getDesiredAccess(mode)
+    let creationDisposition = getCreationDisposition(mode, filename)
+    when useWinUnicode:
+      result.fd = createFileW(newWideCString(filename), desiredAccess,
+          FILE_SHARE_READ,
+          nil, creationDisposition, flags, 0).TAsyncFd
+    else:
+      result.fd = createFileA(filename, desiredAccess,
+          FILE_SHARE_READ,
+          nil, creationDisposition, flags, 0).TAsyncFd
+
+    if result.fd.THandle == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+
+    register(result.fd)
+
+    if mode == fmAppend:
+      result.offset = getFileSize(result)
+
+  else:
+    let flags = getPosixFlags(mode)
+    # RW (Owner), RW (Group), R (Other)
+    let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH
+    result.fd = open(filename, flags, perm).TAsyncFD
+    if result.fd.cint == -1:
+      raiseOSError(osLastError())
+
+    register(result.fd)
+
+proc read*(f: AsyncFile, size: int): Future[string] =
+  ## Read ``size`` bytes from the specified file asynchronously starting at
+  ## the current position of the file pointer.
+  ##
+  ## If the file pointer is past the end of the file then an empty string is
+  ## returned.
+  var retFuture = newFuture[string]("asyncfile.read")
+
+  when defined(windows) or defined(nimdoc):
+    var buffer = alloc0(size)
+
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: f.fd, cb:
+      proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            assert bytesCount > 0
+            assert bytesCount <= size
+            var data = newString(bytesCount)
+            copyMem(addr data[0], buffer, bytesCount)
+            f.offset.inc bytesCount
+            retFuture.complete($data)
+          else:
+            if errcode.int32 == ERROR_HANDLE_EOF:
+              retFuture.complete("")
+            else:
+              retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+        if buffer != nil:
+          dealloc buffer
+          buffer = nil
+    )
+    ol.offset = DWord(f.offset and 0xffffffff)
+    ol.offsetHigh = DWord(f.offset shr 32)
+
+    # According to MSDN we're supposed to pass nil to lpNumberOfBytesRead.
+    let ret = readFile(f.fd.THandle, buffer, size.int32, nil,
+                       cast[POVERLAPPED](ol))
+    if not ret.bool:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        if buffer != nil:
+          dealloc buffer
+          buffer = nil
+        GC_unref(ol)
+        retFuture.fail(newException(OSError, osErrorMsg(err)))
+    else:
+      # Request completed immediately.
+      var bytesRead: DWord
+      let overlappedRes = getOverlappedResult(f.fd.THandle,
+          cast[POverlapped](ol)[], bytesRead, false.WinBool)
+      if not overlappedRes.bool:
+        let err = osLastError()
+        if err.int32 == ERROR_HANDLE_EOF:
+          retFuture.complete("")
+        else:
+          retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
+      else:
+        assert bytesRead > 0
+        assert bytesRead <= size
+        var data = newString(bytesRead)
+        copyMem(addr data[0], buffer, bytesRead)
+        f.offset.inc bytesRead
+        retFuture.complete($data)
+  else:
+    var readBuffer = newString(size)
+
+    proc cb(fd: TAsyncFD): bool =
+      result = true
+      let res = read(fd.cint, addr readBuffer[0], size.cint)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 != EAGAIN:
+          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      elif res == 0:
+        # EOF
+        retFuture.complete("")
+      else:
+        readBuffer.setLen(res)
+        f.offset.inc(res)
+        retFuture.complete(readBuffer)
+    
+    if not cb(f.fd):
+      addRead(f.fd, cb)
+  
+  return retFuture
+
+proc readLine*(f: AsyncFile): Future[string] {.async.} =
+  ## Reads a single line from the specified file asynchronously.
+  result = ""
+  while true:
+    var c = await read(f, 1)
+    if c[0] == '\c':
+      c = await read(f, 1)
+      break
+    if c[0] == '\L' or c == "":
+      break
+    else:
+      result.add(c)
+
+proc getFilePos*(f: AsyncFile): int64 =
+  ## Retrieves the current position of the file pointer that is
+  ## used to read from the specified file. The file's first byte has the
+  ## index zero.
+  f.offset
+
+proc setFilePos*(f: AsyncFile, pos: int64) =
+  ## Sets the position of the file pointer that is used for read/write
+  ## operations. The file's first byte has the index zero. 
+  f.offset = pos
+  when not defined(windows) and not defined(nimdoc):
+    let ret = lseek(f.fd.cint, pos, SEEK_SET)
+    if ret == -1:
+      raiseOSError(osLastError())
+
+proc readAll*(f: AsyncFile): Future[string] {.async.} =
+  ## Reads all data from the specified file.
+  result = ""
+  while true:
+    let data = await read(f, 4000)
+    if data.len == 0:
+      return
+    result.add data
+
+proc write*(f: AsyncFile, data: string): Future[void] =
+  ## Writes ``data`` to the file specified asynchronously.
+  ##
+  ## The returned Future will complete once all data has been written to the
+  ## specified file.
+  var retFuture = newFuture[void]("asyncfile.write")
+  var copy = data
+  when defined(windows) or defined(nimdoc):
+    var buffer = alloc0(data.len)
+    copyMem(buffer, addr copy[0], data.len)
+
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = TCompletionData(fd: f.fd, cb:
+      proc (fd: TAsyncFD, bytesCount: DWord, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            assert bytesCount == data.len.int32
+            f.offset.inc(data.len)
+            retFuture.complete()
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+        if buffer != nil:
+          dealloc buffer
+          buffer = nil
+    )
+    ol.offset = DWord(f.offset and 0xffffffff)
+    ol.offsetHigh = DWord(f.offset shr 32)
+
+    # According to MSDN we're supposed to pass nil to lpNumberOfBytesWritten.
+    let ret = writeFile(f.fd.THandle, buffer, data.len.int32, nil,
+                       cast[POVERLAPPED](ol))
+    if not ret.bool:
+      let err = osLastError()
+      if err.int32 != ERROR_IO_PENDING:
+        if buffer != nil:
+          dealloc buffer
+          buffer = nil
+        GC_unref(ol)
+        retFuture.fail(newException(OSError, osErrorMsg(err)))
+    else:
+      # Request completed immediately.
+      var bytesWritten: DWord
+      let overlappedRes = getOverlappedResult(f.fd.THandle,
+          cast[POverlapped](ol)[], bytesWritten, false.WinBool)
+      if not overlappedRes.bool:
+        retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
+      else:
+        assert bytesWritten == data.len.int32
+        f.offset.inc(data.len)
+        retFuture.complete()
+  else:
+    var written = 0
+    
+    proc cb(fd: TAsyncFD): bool =
+      result = true
+      let remainderSize = data.len-written
+      let res = write(fd.cint, addr copy[written], remainderSize.cint)
+      if res < 0:
+        let lastError = osLastError()
+        if lastError.int32 != EAGAIN:
+          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+        else:
+          result = false # We still want this callback to be called.
+      else:
+        written.inc res
+        f.offset.inc res
+        if res != remainderSize:
+          result = false # We still have data to write.
+        else:
+          retFuture.complete()
+    
+    if not cb(f.fd):
+      addWrite(f.fd, cb)
+  return retFuture
+
+proc close*(f: AsyncFile) =
+  ## Closes the file specified.
+  when defined(windows) or defined(nimdoc):
+    if not closeHandle(f.fd.THandle).bool:
+      raiseOSError(osLastError())
+  else:
+    if close(f.fd.cint) == -1:
+      raiseOSError(osLastError())
+
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
new file mode 100644
index 000000000..daf69d59f
--- /dev/null
+++ b/lib/pure/asyncftpclient.nim
@@ -0,0 +1,313 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implement an asynchronous FTP client.
+##
+## Examples
+## --------
+##
+## .. code-block::nim
+##
+##      var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
+##      proc main(ftp: AsyncFtpClient) {.async.} =
+##        await ftp.connect()
+##        echo await ftp.pwd()
+##        echo await ftp.listDirs()
+##        await ftp.store("payload.jpg", "payload.jpg")
+##        await ftp.retrFile("payload.jpg", "payload2.jpg")
+##        echo("Finished")
+##
+##      waitFor main(ftp)
+
+import asyncdispatch, asyncnet, strutils, parseutils, os, times
+
+from ftpclient import FtpBaseObj, ReplyError, FtpEvent
+from net import BufferSize
+
+type
+  AsyncFtpClientObj* = FtpBaseObj[AsyncSocket]
+  AsyncFtpClient* = ref AsyncFtpClientObj
+
+  ProgressChangedProc* =
+    proc (total, progress: BiggestInt, speed: float):
+      Future[void] {.closure, gcsafe.}
+
+proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] =
+  result = ftp.csock.recvLine()
+
+proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} =
+  ## Send a message to the server, and wait for a primary reply.
+  ## ``\c\L`` is added for you.
+  await ftp.csock.send(m & "\c\L")
+  return await ftp.expectReply()
+
+proc assertReply(received: TaintedString, expected: varargs[string]) =
+  for i in items(expected):
+    if received.string.startsWith(i): return
+  raise newException(ReplyError,
+                     "Expected reply '$1' got: $2" %
+                     [expected.join("' or '"), received.string])
+
+proc pasv(ftp: AsyncFtpClient) {.async.} =
+  ## Negotiate a data connection.
+  ftp.dsock = newAsyncSocket()
+
+  var pasvMsg = (await ftp.send("PASV")).string.strip.TaintedString
+  assertReply(pasvMsg, "227")
+  var betweenParens = captureBetween(pasvMsg.string, '(', ')')
+  var nums = betweenParens.split(',')
+  var ip = nums[0.. ^3]
+  var port = nums[^2.. ^1]
+  var properPort = port[0].parseInt()*256+port[1].parseInt()
+  await ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
+  ftp.dsockConnected = true
+
+proc normalizePathSep(path: string): string =
+  return replace(path, '\\', '/')
+
+proc connect*(ftp: AsyncFtpClient) {.async.} =
+  ## Connect to the FTP server specified by ``ftp``.
+  await ftp.csock.connect(ftp.address, ftp.port)
+
+  var reply = await ftp.expectReply()
+  if reply.startsWith("120"):
+    # 120 Service ready in nnn minutes.
+    # We wait until we receive 220.
+    reply = await ftp.expectReply()
+  assertReply(reply, "220")
+
+  if ftp.user != "":
+    assertReply(await(ftp.send("USER " & ftp.user)), "230", "331")
+
+  if ftp.pass != "":
+    assertReply(await(ftp.send("PASS " & ftp.pass)), "230")
+
+proc pwd*(ftp: AsyncFtpClient): Future[TaintedString] {.async.} =
+  ## Returns the current working directory.
+  let wd = await ftp.send("PWD")
+  assertReply wd, "257"
+  return wd.string.captureBetween('"').TaintedString # "
+
+proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} =
+  ## Changes the current directory on the remote FTP server to ``dir``.
+  assertReply(await(ftp.send("CWD " & dir.normalizePathSep)), "250")
+
+proc cdup*(ftp: AsyncFtpClient) {.async.} =
+  ## Changes the current directory to the parent of the current directory.
+  assertReply(await(ftp.send("CDUP")), "200")
+
+proc getLines(ftp: AsyncFtpClient): Future[string] {.async.} =
+  ## Downloads text data in ASCII mode
+  result = ""
+  assert ftp.dsockConnected
+  while ftp.dsockConnected:
+    let r = await ftp.dsock.recvLine()
+    if r.string == "":
+      ftp.dsockConnected = false
+    else:
+      result.add(r.string & "\n")
+
+  assertReply(await(ftp.expectReply()), "226")
+
+proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} =
+  ## Returns a list of filenames in the given directory. If ``dir`` is "",
+  ## the current directory is used. If ``async`` is true, this
+  ## function will return immediately and it will be your job to
+  ## use asyncio's ``poll`` to progress this operation.
+  await ftp.pasv()
+
+  assertReply(await(ftp.send("NLST " & dir.normalizePathSep)), ["125", "150"])
+
+  result = splitLines(await ftp.getLines())
+
+proc existsFile*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} =
+  ## Determines whether ``file`` exists.
+  var files = await ftp.listDirs()
+  for f in items(files):
+    if f.normalizePathSep == file.normalizePathSep: return true
+
+proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} =
+  ## Creates a directory ``dir``. If ``recursive`` is true, the topmost
+  ## subdirectory of ``dir`` will be created first, following the secondmost...
+  ## etc. this allows you to give a full path as the ``dir`` without worrying
+  ## about subdirectories not existing.
+  if not recursive:
+    assertReply(await(ftp.send("MKD " & dir.normalizePathSep)), "257")
+  else:
+    var reply = TaintedString""
+    var previousDirs = ""
+    for p in split(dir, {os.DirSep, os.AltSep}):
+      if p != "":
+        previousDirs.add(p)
+        reply = await ftp.send("MKD " & previousDirs)
+        previousDirs.add('/')
+    assertReply reply, "257"
+
+proc chmod*(ftp: AsyncFtpClient, path: string,
+            permissions: set[FilePermission]) {.async.} =
+  ## Changes permission of ``path`` to ``permissions``.
+  var userOctal = 0
+  var groupOctal = 0
+  var otherOctal = 0
+  for i in items(permissions):
+    case i
+    of fpUserExec: userOctal.inc(1)
+    of fpUserWrite: userOctal.inc(2)
+    of fpUserRead: userOctal.inc(4)
+    of fpGroupExec: groupOctal.inc(1)
+    of fpGroupWrite: groupOctal.inc(2)
+    of fpGroupRead: groupOctal.inc(4)
+    of fpOthersExec: otherOctal.inc(1)
+    of fpOthersWrite: otherOctal.inc(2)
+    of fpOthersRead: otherOctal.inc(4)
+
+  var perm = $userOctal & $groupOctal & $otherOctal
+  assertReply(await(ftp.send("SITE CHMOD " & perm &
+                    " " & path.normalizePathSep)), "200")
+
+proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} =
+  ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current
+  ## working directory.
+  await ftp.pasv()
+
+  let reply = await ftp.send("LIST" & " " & dir.normalizePathSep)
+  assertReply(reply, ["125", "150"])
+
+  result = await ftp.getLines()
+
+proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} =
+  ## Retrieves ``file``. File must be ASCII text.
+  await ftp.pasv()
+  let reply = await ftp.send("RETR " & file.normalizePathSep)
+  assertReply(reply, ["125", "150"])
+
+  result = await ftp.getLines()
+
+proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt,
+             onProgressChanged: ProgressChangedProc) {.async.} =
+  assert ftp.dsockConnected
+  var progress = 0
+  var progressInSecond = 0
+  var countdownFut = sleepAsync(1000)
+  var dataFut = ftp.dsock.recv(BufferSize)
+  while ftp.dsockConnected:
+    await dataFut or countdownFut
+    if countdownFut.finished:
+      asyncCheck onProgressChanged(total, progress,
+          progressInSecond.float)
+      progressInSecond = 0
+      countdownFut = sleepAsync(1000)
+
+    if dataFut.finished:
+      let data = dataFut.read
+      if data != "":
+        progress.inc(data.len)
+        progressInSecond.inc(data.len)
+        file.write(data)
+        dataFut = ftp.dsock.recv(BufferSize)
+      else:
+        ftp.dsockConnected = false
+
+  assertReply(await(ftp.expectReply()), "226")
+
+proc defaultOnProgressChanged*(total, progress: BiggestInt,
+    speed: float): Future[void] {.nimcall,gcsafe.} =
+  ## Default FTP ``onProgressChanged`` handler. Does nothing.
+  result = newFuture[void]()
+  #echo(total, " ", progress, " ", speed)
+  result.complete()
+
+proc retrFile*(ftp: AsyncFtpClient, file, dest: string,
+               onProgressChanged = defaultOnProgressChanged) {.async.} =
+  ## Downloads ``file`` and saves it to ``dest``.
+  ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function
+  ## when the download is finished. The event's ``filename`` field will be equal
+  ## to ``file``.
+  var destFile = open(dest, mode = fmWrite)
+  await ftp.pasv()
+  var reply = await ftp.send("RETR " & file.normalizePathSep)
+  assertReply reply, ["125", "150"]
+  if {'(', ')'} notin reply.string:
+    raise newException(ReplyError, "Reply has no file size.")
+  var fileSize: BiggestInt
+  if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0:
+    raise newException(ReplyError, "Reply has no file size.")
+
+  await getFile(ftp, destFile, fileSize, onProgressChanged)
+
+proc doUpload(ftp: AsyncFtpClient, file: File,
+              onProgressChanged: ProgressChangedProc) {.async.} =
+  assert ftp.dsockConnected
+
+  let total = file.getFileSize()
+  var data = newStringOfCap(4000)
+  var progress = 0
+  var progressInSecond = 0
+  var countdownFut = sleepAsync(1000)
+  var sendFut: Future[void] = nil
+  while ftp.dsockConnected:
+    if sendFut == nil or sendFut.finished:
+      progress.inc(data.len)
+      progressInSecond.inc(data.len)
+      # TODO: Async file reading.
+      let len = file.readBuffer(addr(data[0]), 4000)
+      setLen(data, len)
+      if len == 0:
+        # File finished uploading.
+        ftp.dsock.close()
+        ftp.dsockConnected = false
+
+        assertReply(await(ftp.expectReply()), "226")
+      else:
+        sendFut = ftp.dsock.send(data)
+
+    if countdownFut.finished:
+      asyncCheck onProgressChanged(total, progress, progressInSecond.float)
+      progressInSecond = 0
+      countdownFut = sleepAsync(1000)
+
+    await countdownFut or sendFut
+
+proc store*(ftp: AsyncFtpClient, file, dest: string,
+            onProgressChanged = defaultOnProgressChanged) {.async.} =
+  ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this
+  ## function asynchronously is recommended to view the progress of
+  ## the download.
+  ## The ``EvStore`` event is passed to the specified ``handleEvent`` function
+  ## when the upload is finished, and the ``filename`` field will be
+  ## equal to ``file``.
+  var destFile = open(file)
+  await ftp.pasv()
+
+  let reply = await ftp.send("STOR " & dest.normalizePathSep)
+  assertReply reply, ["125", "150"]
+
+  await doUpload(ftp, destFile, onProgressChanged)
+
+proc newAsyncFtpClient*(address: string, port = Port(21),
+    user, pass = ""): AsyncFtpClient =
+  ## Creates a new ``AsyncFtpClient`` object.
+  new result
+  result.user = user
+  result.pass = pass
+  result.address = address
+  result.port = port
+  result.dsockConnected = false
+  result.csock = newAsyncSocket()
+
+when not defined(testing) and isMainModule:
+  var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
+  proc main(ftp: AsyncFtpClient) {.async.} =
+    await ftp.connect()
+    echo await ftp.pwd()
+    echo await ftp.listDirs()
+    await ftp.store("payload.jpg", "payload.jpg")
+    await ftp.retrFile("payload.jpg", "payload2.jpg")
+    echo("Finished")
+
+  waitFor main(ftp)
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
new file mode 100644
index 000000000..279cedb5d
--- /dev/null
+++ b/lib/pure/asynchttpserver.nim
@@ -0,0 +1,277 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a high performance asynchronous HTTP server.
+##
+## Examples
+## --------
+##
+## This example will create an HTTP server on port 8080. The server will
+## respond to all requests with a ``200 OK`` response code and "Hello World"
+## as the response body.
+##
+## .. code-block::nim
+##    import asynchttpserver, asyncdispatch
+##
+##    var server = newAsyncHttpServer()
+##    proc cb(req: Request) {.async.} =
+##      await req.respond(Http200, "Hello World")
+##
+##    waitFor server.serve(Port(8080), cb)
+
+import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
+type
+  Request* = object
+    client*: AsyncSocket # TODO: Separate this into a Response object?
+    reqMethod*: string
+    headers*: StringTableRef
+    protocol*: tuple[orig: string, major, minor: int]
+    url*: Uri
+    hostname*: string ## The hostname of the client that made the request.
+    body*: string
+
+  AsyncHttpServer* = ref object
+    socket: AsyncSocket
+    reuseAddr: bool
+
+  HttpCode* = enum
+    Http100 = "100 Continue",
+    Http101 = "101 Switching Protocols",
+    Http200 = "200 OK",
+    Http201 = "201 Created",
+    Http202 = "202 Accepted",
+    Http204 = "204 No Content",
+    Http205 = "205 Reset Content",
+    Http206 = "206 Partial Content",
+    Http300 = "300 Multiple Choices",
+    Http301 = "301 Moved Permanently",
+    Http302 = "302 Found",
+    Http303 = "303 See Other",
+    Http304 = "304 Not Modified",
+    Http305 = "305 Use Proxy",
+    Http307 = "307 Temporary Redirect",
+    Http400 = "400 Bad Request",
+    Http401 = "401 Unauthorized",
+    Http403 = "403 Forbidden",
+    Http404 = "404 Not Found",
+    Http405 = "405 Method Not Allowed",
+    Http406 = "406 Not Acceptable",
+    Http407 = "407 Proxy Authentication Required",
+    Http408 = "408 Request Timeout",
+    Http409 = "409 Conflict",
+    Http410 = "410 Gone",
+    Http411 = "411 Length Required",
+    Http418 = "418 I'm a teapot",
+    Http500 = "500 Internal Server Error",
+    Http501 = "501 Not Implemented",
+    Http502 = "502 Bad Gateway",
+    Http503 = "503 Service Unavailable",
+    Http504 = "504 Gateway Timeout",
+    Http505 = "505 HTTP Version Not Supported"
+
+  HttpVersion* = enum
+    HttpVer11,
+    HttpVer10
+
+{.deprecated: [TRequest: Request, PAsyncHttpServer: AsyncHttpServer,
+  THttpCode: HttpCode, THttpVersion: HttpVersion].}
+
+proc `==`*(protocol: tuple[orig: string, major, minor: int],
+           ver: HttpVersion): bool =
+  let major =
+    case ver
+    of HttpVer11, HttpVer10: 1
+  let minor =
+    case ver
+    of HttpVer11: 1
+    of HttpVer10: 0
+  result = protocol.major == major and protocol.minor == minor
+
+proc newAsyncHttpServer*(reuseAddr = true): AsyncHttpServer =
+  ## Creates a new ``AsyncHttpServer`` instance.
+  new result
+  result.reuseAddr = reuseAddr
+
+proc addHeaders(msg: var string, headers: StringTableRef) =
+  for k, v in headers:
+    msg.add(k & ": " & v & "\c\L")
+
+proc sendHeaders*(req: Request, headers: StringTableRef): Future[void] =
+  ## Sends the specified headers to the requesting client.
+  var msg = ""
+  addHeaders(msg, headers)
+  return req.client.send(msg)
+
+proc respond*(req: Request, code: HttpCode, content: string,
+              headers: StringTableRef = nil): Future[void] =
+  ## Responds to the request with the specified ``HttpCode``, headers and
+  ## content.
+  ##
+  ## This procedure will **not** close the client socket.
+  var msg = "HTTP/1.1 " & $code & "\c\L"
+
+  if headers != nil:
+    msg.addHeaders(headers)
+  msg.add("Content-Length: " & $content.len & "\c\L\c\L")
+  msg.add(content)
+  result = req.client.send(msg)
+
+proc parseHeader(line: string): tuple[key, value: string] =
+  var i = 0
+  i = line.parseUntil(result.key, ':')
+  inc(i) # skip :
+  i += line.skipWhiteSpace(i)
+  i += line.parseUntil(result.value, {'\c', '\L'}, i)
+
+proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] =
+  var i = protocol.skipIgnoreCase("HTTP/")
+  if i != 5:
+    raise newException(ValueError, "Invalid request protocol. Got: " &
+        protocol)
+  result.orig = protocol
+  i.inc protocol.parseInt(result.major, i)
+  i.inc # Skip .
+  i.inc protocol.parseInt(result.minor, i)
+
+proc sendStatus(client: AsyncSocket, status: string): Future[void] =
+  client.send("HTTP/1.1 " & status & "\c\L")
+
+proc processClient(client: AsyncSocket, address: string,
+                   callback: proc (request: Request):
+                      Future[void] {.closure, gcsafe.}) {.async.} =
+  var request: Request
+  request.url = initUri()
+  request.headers = newStringTable(modeCaseInsensitive)
+  var line = newStringOfCap(80)
+  var key, value = ""
+
+  while not client.isClosed:
+    # GET /path HTTP/1.1
+    # Header: val
+    # \n
+    request.headers.clear(modeCaseInsensitive)
+    request.hostname.shallowCopy(address)
+    assert client != nil
+    request.client = client
+
+    # First line - GET /path HTTP/1.1
+    line.setLen(0)
+    await client.recvLineInto(addr line) # TODO: Timeouts.
+    if line == "":
+      client.close()
+      return
+
+    var i = 0
+    for linePart in line.split(' '):
+      case i
+      of 0: request.reqMethod.shallowCopy(linePart.normalize)
+      of 1: parseUri(linePart, request.url)
+      of 2:
+        try:
+          request.protocol = parseProtocol(linePart)
+        except ValueError:
+          asyncCheck request.respond(Http400,
+            "Invalid request protocol. Got: " & linePart)
+          continue
+      else:
+        await request.respond(Http400, "Invalid request. Got: " & line)
+        continue
+      inc i
+
+    # Headers
+    while true:
+      i = 0
+      line.setLen(0)
+      await client.recvLineInto(addr line)
+
+      if line == "":
+        client.close(); return
+      if line == "\c\L": break
+      let (key, value) = parseHeader(line)
+      request.headers[key] = value
+
+    if request.reqMethod == "post":
+      # Check for Expect header
+      if request.headers.hasKey("Expect"):
+        if request.headers["Expect"].toLower == "100-continue":
+          await client.sendStatus("100 Continue")
+        else:
+          await client.sendStatus("417 Expectation Failed")
+
+      # Read the body
+      # - Check for Content-length header
+      if request.headers.hasKey("Content-Length"):
+        var contentLength = 0
+        if parseInt(request.headers["Content-Length"], contentLength) == 0:
+          await request.respond(Http400, "Bad Request. Invalid Content-Length.")
+        else:
+          request.body = await client.recv(contentLength)
+          assert request.body.len == contentLength
+      else:
+        await request.respond(Http400, "Bad Request. No Content-Length.")
+        continue
+
+    case request.reqMethod
+    of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
+      await callback(request)
+    else:
+      await request.respond(Http400, "Invalid request method. Got: " & request.reqMethod)
+
+    # Persistent connections
+    if (request.protocol == HttpVer11 and
+        request.headers["connection"].normalize != "close") or
+       (request.protocol == HttpVer10 and
+        request.headers["connection"].normalize == "keep-alive"):
+      # In HTTP 1.1 we assume that connection is persistent. Unless connection
+      # header states otherwise.
+      # In HTTP 1.0 we assume that the connection should not be persistent.
+      # Unless the connection header states otherwise.
+      discard
+    else:
+      request.client.close()
+      break
+
+proc serve*(server: AsyncHttpServer, port: Port,
+            callback: proc (request: Request): Future[void] {.closure,gcsafe.},
+            address = "") {.async.} =
+  ## Starts the process of listening for incoming HTTP connections on the
+  ## specified address and port.
+  ##
+  ## When a request is made by a client the specified callback will be called.
+  server.socket = newAsyncSocket()
+  if server.reuseAddr:
+    server.socket.setSockOpt(OptReuseAddr, true)
+  server.socket.bindAddr(port, address)
+  server.socket.listen()
+
+  while true:
+    # TODO: Causes compiler crash.
+    #var (address, client) = await server.socket.acceptAddr()
+    var fut = await server.socket.acceptAddr()
+    asyncCheck processClient(fut.client, fut.address, callback)
+    #echo(f.isNil)
+    #echo(f.repr)
+
+proc close*(server: AsyncHttpServer) =
+  ## Terminates the async http server instance.
+  server.socket.close()
+
+when not defined(testing) and isMainModule:
+  proc main =
+    var server = newAsyncHttpServer()
+    proc cb(req: Request) {.async.} =
+      #echo(req.reqMethod, " ", req.url)
+      #echo(req.headers)
+      let headers = {"Date": "Tue, 29 Apr 2014 23:40:08 GMT",
+          "Content-type": "text/plain; charset=utf-8"}
+      await req.respond(Http200, "Hello World", headers.newStringTable())
+
+    asyncCheck server.serve(Port(5555), cb)
+    runForever()
+  main()
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
new file mode 100644
index 000000000..6ae2c608b
--- /dev/null
+++ b/lib/pure/asyncio.nim
@@ -0,0 +1,712 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+include "system/inclrtl"
+
+import sockets, os
+
+##
+## **Warning:** This module is deprecated since version 0.10.2.
+## Use the brand new `asyncdispatch <asyncdispatch.html>`_ module together
+## with the `asyncnet <asyncnet.html>`_ module.
+
+## This module implements an asynchronous event loop together with asynchronous
+## sockets which use this event loop.
+## It is akin to Python's asyncore module. Many modules that use sockets
+## have an implementation for this module, those modules should all have a
+## ``register`` function which you should use to add the desired objects to a
+## dispatcher which you created so
+## that you can receive the events associated with that module's object.
+##
+## Once everything is registered in a dispatcher, you need to call the ``poll``
+## function in a while loop.
+##
+## **Note:** Most modules have tasks which need to be ran regularly, this is
+## why you should not call ``poll`` with a infinite timeout, or even a
+## very long one. In most cases the default timeout is fine.
+##
+## **Note:** This module currently only supports select(), this is limited by
+## FD_SETSIZE, which is usually 1024. So you may only be able to use 1024
+## sockets at a time.
+##
+## Most (if not all) modules that use asyncio provide a userArg which is passed
+## on with the events. The type that you set userArg to must be inheriting from
+## ``RootObj``!
+##
+## **Note:** If you want to provide async ability to your module please do not
+## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible
+## that in the future this type's fields will not be exported therefore breaking
+## your code.
+##
+## **Warning:** The API of this module is unstable, and therefore is subject
+## to change.
+##
+## Asynchronous sockets
+## ====================
+##
+## For most purposes you do not need to worry about the ``Delegate`` type. The
+## ``AsyncSocket`` is what you are after. It's a reference to
+## the ``AsyncSocketObj`` object. This object defines events which you should
+## overwrite by your own procedures.
+##
+## For server sockets the only event you need to worry about is the ``handleAccept``
+## event, in your handleAccept proc you should call ``accept`` on the server
+## socket which will give you the client which is connecting. You should then
+## set any events that you want to use on that client and add it to your dispatcher
+## using the ``register`` procedure.
+##
+## An example ``handleAccept`` follows:
+##
+## .. code-block:: nim
+##
+##    var disp = newDispatcher()
+##    ...
+##    proc handleAccept(s: AsyncSocket) =
+##      echo("Accepted client.")
+##      var client: AsyncSocket
+##      new(client)
+##      s.accept(client)
+##      client.handleRead = ...
+##      disp.register(client)
+##    ...
+##
+## For client sockets you should only be interested in the ``handleRead`` and
+## ``handleConnect`` events. The former gets called whenever the socket has
+## received messages and can be read from and the latter gets called whenever
+## the socket has established a connection to a server socket; from that point
+## it can be safely written to.
+##
+## Getting a blocking client from an AsyncSocket
+## =============================================
+##
+## If you need a asynchronous server socket but you wish to process the clients
+## synchronously then you can use the ``getSocket`` converter to get
+## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined
+## with ``accept`` like so:
+##
+## .. code-block:: nim
+##
+##    proc handleAccept(s: AsyncSocket) =
+##      var client: Socket
+##      getSocket(s).accept(client)
+
+{.deprecated.}
+
+when defined(windows):
+  from winlean import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
+    FD_ISSET, select
+else:
+  from posix import TimeVal, SocketHandle, FD_SET, FD_ZERO, TFdSet,
+    FD_ISSET, select
+
+type
+  DelegateObj* = object
+    fd*: SocketHandle
+    deleVal*: RootRef
+
+    handleRead*: proc (h: RootRef) {.nimcall, gcsafe.}
+    handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.}
+    handleError*: proc (h: RootRef) {.nimcall, gcsafe.}
+    hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.}
+
+    open*: bool
+    task*: proc (h: RootRef) {.nimcall, gcsafe.}
+    mode*: FileMode
+
+  Delegate* = ref DelegateObj
+
+  Dispatcher* = ref DispatcherObj
+  DispatcherObj = object
+    delegates: seq[Delegate]
+
+  AsyncSocket* = ref AsyncSocketObj
+  AsyncSocketObj* = object of RootObj
+    socket: Socket
+    info: SocketStatus
+
+    handleRead*: proc (s: AsyncSocket) {.closure, gcsafe.}
+    handleWrite: proc (s: AsyncSocket) {.closure, gcsafe.}
+    handleConnect*: proc (s:  AsyncSocket) {.closure, gcsafe.}
+
+    handleAccept*: proc (s:  AsyncSocket) {.closure, gcsafe.}
+
+    handleTask*: proc (s: AsyncSocket) {.closure, gcsafe.}
+
+    lineBuffer: TaintedString ## Temporary storage for ``readLine``
+    sendBuffer: string ## Temporary storage for ``send``
+    sslNeedAccept: bool
+    proto: Protocol
+    deleg: Delegate
+
+  SocketStatus* = enum
+    SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
+    SockUDPBound
+
+{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
+  TInfo: SocketStatus, PAsyncSocket: AsyncSocket, TAsyncSocket: AsyncSocketObj,
+  TDispatcher: DispatcherObj, PDispatcher: Dispatcher,
+  ].}
+
+
+proc newDelegate*(): Delegate =
+  ## Creates a new delegate.
+  new(result)
+  result.handleRead = (proc (h: RootRef) = discard)
+  result.handleWrite = (proc (h: RootRef) = discard)
+  result.handleError = (proc (h: RootRef) = discard)
+  result.hasDataBuffered = (proc (h: RootRef): bool = return false)
+  result.task = (proc (h: RootRef) = discard)
+  result.mode = fmRead
+
+proc newAsyncSocket(): AsyncSocket =
+  new(result)
+  result.info = SockIdle
+
+  result.handleRead = (proc (s: AsyncSocket) = discard)
+  result.handleWrite = nil
+  result.handleConnect = (proc (s: AsyncSocket) = discard)
+  result.handleAccept = (proc (s: AsyncSocket) = discard)
+  result.handleTask = (proc (s: AsyncSocket) = discard)
+
+  result.lineBuffer = "".TaintedString
+  result.sendBuffer = ""
+
+proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+                  protocol: Protocol = IPPROTO_TCP,
+                  buffered = true): AsyncSocket =
+  ## Initialises an AsyncSocket object. If a socket cannot be initialised
+  ## EOS is raised.
+  result = newAsyncSocket()
+  result.socket = socket(domain, typ, protocol, buffered)
+  result.proto = protocol
+  if result.socket == invalidSocket: raiseOSError(osLastError())
+  result.socket.setBlocking(false)
+
+proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): AsyncSocket =
+  ## Wraps an already initialized ``TSocket`` into a AsyncSocket.
+  ## This is useful if you want to use an already connected TSocket as an
+  ## asynchronous AsyncSocket in asyncio's event loop.
+  ##
+  ## ``state`` may be overriden, i.e. if ``sock`` is not connected it should be
+  ## adjusted properly. By default it will be assumed that the socket is
+  ## connected. Please note this is only applicable to TCP client sockets, if
+  ## ``sock`` is a different type of socket ``state`` needs to be adjusted!!!
+  ##
+  ## ================  ================================================================
+  ## Value             Meaning
+  ## ================  ================================================================
+  ##  SockIdle          Socket has only just been initialised, not connected or closed.
+  ##  SockConnected     Socket is connected to a server.
+  ##  SockConnecting    Socket is in the process of connecting to a server.
+  ##  SockListening     Socket is a server socket and is listening for connections.
+  ##  SockClosed        Socket has been closed.
+  ##  SockUDPBound      Socket is a UDP socket which is listening for data.
+  ## ================  ================================================================
+  ##
+  ## **Warning**: If ``state`` is set incorrectly the resulting ``AsyncSocket``
+  ## object may not work properly.
+  ##
+  ## **Note**: This will set ``sock`` to be non-blocking.
+  result = newAsyncSocket()
+  result.socket = sock
+  result.proto = if state == SockUDPBound: IPPROTO_UDP else: IPPROTO_TCP
+  result.socket.setBlocking(false)
+  result.info = state
+
+proc asyncSockHandleRead(h: RootRef) =
+  when defined(ssl):
+    if AsyncSocket(h).socket.isSSL and not
+         AsyncSocket(h).socket.gotHandshake:
+      return
+
+  if AsyncSocket(h).info != SockListening:
+    if AsyncSocket(h).info != SockConnecting:
+      AsyncSocket(h).handleRead(AsyncSocket(h))
+  else:
+    AsyncSocket(h).handleAccept(AsyncSocket(h))
+
+proc close*(sock: AsyncSocket) {.gcsafe.}
+proc asyncSockHandleWrite(h: RootRef) =
+  when defined(ssl):
+    if AsyncSocket(h).socket.isSSL and not
+         AsyncSocket(h).socket.gotHandshake:
+      return
+
+  if AsyncSocket(h).info == SockConnecting:
+    AsyncSocket(h).handleConnect(AsyncSocket(h))
+    AsyncSocket(h).info = SockConnected
+    # Stop receiving write events if there is no handleWrite event.
+    if AsyncSocket(h).handleWrite == nil:
+      AsyncSocket(h).deleg.mode = fmRead
+    else:
+      AsyncSocket(h).deleg.mode = fmReadWrite
+  else:
+    if AsyncSocket(h).sendBuffer != "":
+      let sock = AsyncSocket(h)
+      try:
+        let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
+        if bytesSent == 0:
+          # Apparently the socket cannot be written to. Even though select
+          # just told us that it can be... This used to be an assert. Just
+          # do nothing instead.
+          discard
+        elif bytesSent != sock.sendBuffer.len:
+          sock.sendBuffer = sock.sendBuffer[bytesSent .. ^1]
+        elif bytesSent == sock.sendBuffer.len:
+          sock.sendBuffer = ""
+
+        if AsyncSocket(h).handleWrite != nil:
+          AsyncSocket(h).handleWrite(AsyncSocket(h))
+      except OSError:
+        # Most likely the socket closed before the full buffer could be sent to it.
+        sock.close() # TODO: Provide a handleError for users?
+    else:
+      if AsyncSocket(h).handleWrite != nil:
+        AsyncSocket(h).handleWrite(AsyncSocket(h))
+      else:
+        AsyncSocket(h).deleg.mode = fmRead
+
+when defined(ssl):
+  proc asyncSockDoHandshake(h: PObject) {.gcsafe.} =
+    if AsyncSocket(h).socket.isSSL and not
+         AsyncSocket(h).socket.gotHandshake:
+      if AsyncSocket(h).sslNeedAccept:
+        var d = ""
+        let ret = AsyncSocket(h).socket.acceptAddrSSL(AsyncSocket(h).socket, d)
+        assert ret != AcceptNoClient
+        if ret == AcceptSuccess:
+          AsyncSocket(h).info = SockConnected
+      else:
+        # handshake will set socket's ``sslNoHandshake`` field.
+        discard AsyncSocket(h).socket.handshake()
+
+
+proc asyncSockTask(h: RootRef) =
+  when defined(ssl):
+    h.asyncSockDoHandshake()
+
+  AsyncSocket(h).handleTask(AsyncSocket(h))
+
+proc toDelegate(sock: AsyncSocket): Delegate =
+  result = newDelegate()
+  result.deleVal = sock
+  result.fd = getFD(sock.socket)
+  # We need this to get write events, just to know when the socket connects.
+  result.mode = fmReadWrite
+  result.handleRead = asyncSockHandleRead
+  result.handleWrite = asyncSockHandleWrite
+  result.task = asyncSockTask
+  # TODO: Errors?
+  #result.handleError = (proc (h: PObject) = assert(false))
+
+  result.hasDataBuffered =
+    proc (h: RootRef): bool {.nimcall.} =
+      return AsyncSocket(h).socket.hasDataBuffered()
+
+  sock.deleg = result
+  if sock.info notin {SockIdle, SockClosed}:
+    sock.deleg.open = true
+  else:
+    sock.deleg.open = false
+
+proc connect*(sock: AsyncSocket, name: string, port = Port(0),
+                   af: Domain = AF_INET) =
+  ## Begins connecting ``sock`` to ``name``:``port``.
+  sock.socket.connectAsync(name, port, af)
+  sock.info = SockConnecting
+  if sock.deleg != nil:
+    sock.deleg.open = true
+
+proc close*(sock: AsyncSocket) =
+  ## Closes ``sock``. Terminates any current connections.
+  sock.socket.close()
+  sock.info = SockClosed
+  if sock.deleg != nil:
+    sock.deleg.open = false
+
+proc bindAddr*(sock: AsyncSocket, port = Port(0), address = "") =
+  ## Equivalent to ``sockets.bindAddr``.
+  sock.socket.bindAddr(port, address)
+  if sock.proto == IPPROTO_UDP:
+    sock.info = SockUDPBound
+    if sock.deleg != nil:
+      sock.deleg.open = true
+
+proc listen*(sock: AsyncSocket) =
+  ## Equivalent to ``sockets.listen``.
+  sock.socket.listen()
+  sock.info = SockListening
+  if sock.deleg != nil:
+    sock.deleg.open = true
+
+proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket,
+                 address: var string) =
+  ## Equivalent to ``sockets.acceptAddr``. This procedure should be called in
+  ## a ``handleAccept`` event handler **only** once.
+  ##
+  ## **Note**: ``client`` needs to be initialised.
+  assert(client != nil)
+  client = newAsyncSocket()
+  var c: Socket
+  new(c)
+  when defined(ssl):
+    if server.socket.isSSL:
+      var ret = server.socket.acceptAddrSSL(c, address)
+      # The following shouldn't happen because when this function is called
+      # it is guaranteed that there is a client waiting.
+      # (This should be called in handleAccept)
+      assert(ret != AcceptNoClient)
+      if ret == AcceptNoHandshake:
+        client.sslNeedAccept = true
+      else:
+        client.sslNeedAccept = false
+        client.info = SockConnected
+    else:
+      server.socket.acceptAddr(c, address)
+      client.sslNeedAccept = false
+      client.info = SockConnected
+  else:
+    server.socket.acceptAddr(c, address)
+    client.sslNeedAccept = false
+    client.info = SockConnected
+
+  if c == invalidSocket: raiseSocketError(server.socket)
+  c.setBlocking(false) # TODO: Needs to be tested.
+
+  # deleg.open is set in ``toDelegate``.
+
+  client.socket = c
+  client.lineBuffer = "".TaintedString
+  client.sendBuffer = ""
+  client.info = SockConnected
+
+proc accept*(server: AsyncSocket, client: var AsyncSocket) =
+  ## Equivalent to ``sockets.accept``.
+  var dummyAddr = ""
+  server.acceptAddr(client, dummyAddr)
+
+proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket,
+                                              address: string] {.deprecated.} =
+  ## Equivalent to ``sockets.acceptAddr``.
+  ##
+  ## **Deprecated since version 0.9.0:** Please use the function above.
+  var client = newAsyncSocket()
+  var address: string = ""
+  acceptAddr(server, client, address)
+  return (client, address)
+
+proc accept*(server: AsyncSocket): AsyncSocket {.deprecated.} =
+  ## Equivalent to ``sockets.accept``.
+  ##
+  ## **Deprecated since version 0.9.0:** Please use the function above.
+  new(result)
+  var address = ""
+  server.acceptAddr(result, address)
+
+proc newDispatcher*(): Dispatcher =
+  new(result)
+  result.delegates = @[]
+
+proc register*(d: Dispatcher, deleg: Delegate) =
+  ## Registers delegate ``deleg`` with dispatcher ``d``.
+  d.delegates.add(deleg)
+
+proc register*(d: Dispatcher, sock: AsyncSocket): Delegate {.discardable.} =
+  ## Registers async socket ``sock`` with dispatcher ``d``.
+  result = sock.toDelegate()
+  d.register(result)
+
+proc unregister*(d: Dispatcher, deleg: Delegate) =
+  ## Unregisters deleg ``deleg`` from dispatcher ``d``.
+  for i in 0..len(d.delegates)-1:
+    if d.delegates[i] == deleg:
+      d.delegates.del(i)
+      return
+  raise newException(IndexError, "Could not find delegate.")
+
+proc isWriteable*(s: AsyncSocket): bool =
+  ## Determines whether socket ``s`` is ready to be written to.
+  var writeSock = @[s.socket]
+  return selectWrite(writeSock, 1) != 0 and s.socket notin writeSock
+
+converter getSocket*(s: AsyncSocket): Socket =
+  return s.socket
+
+proc isConnected*(s: AsyncSocket): bool =
+  ## Determines whether ``s`` is connected.
+  return s.info == SockConnected
+proc isListening*(s: AsyncSocket): bool =
+  ## Determines whether ``s`` is listening for incoming connections.
+  return s.info == SockListening
+proc isConnecting*(s: AsyncSocket): bool =
+  ## Determines whether ``s`` is connecting.
+  return s.info == SockConnecting
+proc isClosed*(s: AsyncSocket): bool =
+  ## Determines whether ``s`` has been closed.
+  return s.info == SockClosed
+proc isSendDataBuffered*(s: AsyncSocket): bool =
+  ## Determines whether ``s`` has data waiting to be sent, i.e. whether this
+  ## socket's sendBuffer contains data.
+  return s.sendBuffer.len != 0
+
+proc setHandleWrite*(s: AsyncSocket,
+    handleWrite: proc (s: AsyncSocket) {.closure, gcsafe.}) =
+  ## Setter for the ``handleWrite`` event.
+  ##
+  ## To remove this event you should use the ``delHandleWrite`` function.
+  ## It is advised to use that function instead of just setting the event to
+  ## ``proc (s: AsyncSocket) = nil`` as that would mean that that function
+  ## would be called constantly.
+  s.deleg.mode = fmReadWrite
+  s.handleWrite = handleWrite
+
+proc delHandleWrite*(s: AsyncSocket) =
+  ## Removes the ``handleWrite`` event handler on ``s``.
+  s.handleWrite = nil
+
+{.push warning[deprecated]: off.}
+proc recvLine*(s: AsyncSocket, line: var TaintedString): bool {.deprecated.} =
+  ## Behaves similar to ``sockets.recvLine``, however it handles non-blocking
+  ## sockets properly. This function guarantees that ``line`` is a full line,
+  ## if this function can only retrieve some data; it will save this data and
+  ## add it to the result when a full line is retrieved.
+  ##
+  ## Unlike ``sockets.recvLine`` this function will raise an EOS or ESSL
+  ## exception if an error occurs.
+  ##
+  ## **Deprecated since version 0.9.2**: This function has been deprecated in
+  ## favour of readLine.
+  setLen(line.string, 0)
+  var dataReceived = "".TaintedString
+  var ret = s.socket.recvLineAsync(dataReceived)
+  case ret
+  of RecvFullLine:
+    if s.lineBuffer.len > 0:
+      string(line).add(s.lineBuffer.string)
+      setLen(s.lineBuffer.string, 0)
+    string(line).add(dataReceived.string)
+    if string(line) == "":
+      line = "\c\L".TaintedString
+    result = true
+  of RecvPartialLine:
+    string(s.lineBuffer).add(dataReceived.string)
+    result = false
+  of RecvDisconnected:
+    result = true
+  of RecvFail:
+    s.raiseSocketError(async = true)
+    result = false
+{.pop.}
+
+proc readLine*(s: AsyncSocket, line: var TaintedString): bool =
+  ## Behaves similar to ``sockets.readLine``, however it handles non-blocking
+  ## sockets properly. This function guarantees that ``line`` is a full line,
+  ## if this function can only retrieve some data; it will save this data and
+  ## add it to the result when a full line is retrieved, when this happens
+  ## False will be returned. True will only be returned if a full line has been
+  ## retrieved or the socket has been disconnected in which case ``line`` will
+  ## be set to "".
+  ##
+  ## This function will raise an EOS exception when a socket error occurs.
+  setLen(line.string, 0)
+  var dataReceived = "".TaintedString
+  var ret = s.socket.readLineAsync(dataReceived)
+  case ret
+  of ReadFullLine:
+    if s.lineBuffer.len > 0:
+      string(line).add(s.lineBuffer.string)
+      setLen(s.lineBuffer.string, 0)
+    string(line).add(dataReceived.string)
+    if string(line) == "":
+      line = "\c\L".TaintedString
+    result = true
+  of ReadPartialLine:
+    string(s.lineBuffer).add(dataReceived.string)
+    result = false
+  of ReadNone:
+    result = false
+  of ReadDisconnected:
+    result = true
+
+proc send*(sock: AsyncSocket, data: string) =
+  ## Sends ``data`` to socket ``sock``. This is basically a nicer implementation
+  ## of ``sockets.sendAsync``.
+  ##
+  ## If ``data`` cannot be sent immediately it will be buffered and sent
+  ## when ``sock`` becomes writeable (during the ``handleWrite`` event).
+  ## It's possible that only a part of ``data`` will be sent immediately, while
+  ## the rest of it will be buffered and sent later.
+  if sock.sendBuffer.len != 0:
+    sock.sendBuffer.add(data)
+    return
+  let bytesSent = sock.socket.sendAsync(data)
+  assert bytesSent >= 0
+  if bytesSent == 0:
+    sock.sendBuffer.add(data)
+    sock.deleg.mode = fmReadWrite
+  elif bytesSent != data.len:
+    sock.sendBuffer.add(data[bytesSent .. ^1])
+    sock.deleg.mode = fmReadWrite
+
+proc timeValFromMilliseconds(timeout = 500): Timeval =
+  if timeout != -1:
+    var seconds = timeout div 1000
+    result.tv_sec = seconds.int32
+    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) =
+  FD_ZERO(fd)
+  for i in items(s):
+    m = max(m, int(i.fd))
+    FD_SET(i.fd, fd)
+
+proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) =
+  var i = 0
+  var L = s.len
+  while i < L:
+    if FD_ISSET(s[i].fd, fd) != 0'i32:
+      s[i] = s[L-1]
+      dec(L)
+    else:
+      inc(i)
+  setLen(s, L)
+
+proc select(readfds, writefds, exceptfds: var seq[Delegate],
+             timeout = 500): int =
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+
+  var rd, wr, ex: TFdSet
+  var m = 0
+  createFdSet(rd, readfds, m)
+  createFdSet(wr, writefds, m)
+  createFdSet(ex, exceptfds, m)
+
+  if timeout != -1:
+    result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
+  else:
+    result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), nil))
+
+  pruneSocketSet(readfds, (rd))
+  pruneSocketSet(writefds, (wr))
+  pruneSocketSet(exceptfds, (ex))
+
+proc poll*(d: Dispatcher, timeout: int = 500): bool =
+  ## This function checks for events on all the delegates in the `PDispatcher`.
+  ## It then proceeds to call the correct event handler.
+  ##
+  ## This function returns ``True`` if there are file descriptors that are still
+  ## open, otherwise ``False``. File descriptors that have been
+  ## closed are immediately removed from the dispatcher automatically.
+  ##
+  ## **Note:** Each delegate has a task associated with it. This gets called
+  ## after each select() call, if you set timeout to ``-1`` the tasks will
+  ## only be executed after one or more file descriptors becomes readable or
+  ## writeable.
+  result = true
+  var readDg, writeDg, errorDg: seq[Delegate] = @[]
+  var len = d.delegates.len
+  var dc = 0
+
+  while dc < len:
+    let deleg = d.delegates[dc]
+    if (deleg.mode != fmWrite or deleg.mode != fmAppend) and deleg.open:
+      readDg.add(deleg)
+    if (deleg.mode != fmRead) and deleg.open:
+      writeDg.add(deleg)
+    if deleg.open:
+      errorDg.add(deleg)
+      inc dc
+    else:
+      # File/socket has been closed. Remove it from dispatcher.
+      d.delegates[dc] = d.delegates[len-1]
+      dec len
+
+  d.delegates.setLen(len)
+
+  var hasDataBufferedCount = 0
+  for d in d.delegates:
+    if d.hasDataBuffered(d.deleVal):
+      hasDataBufferedCount.inc()
+      d.handleRead(d.deleVal)
+  if hasDataBufferedCount > 0: return true
+
+  if readDg.len() == 0 and writeDg.len() == 0:
+    ## TODO: Perhaps this shouldn't return if errorDg has something?
+    return false
+
+  if select(readDg, writeDg, errorDg, timeout) != 0:
+    for i in 0..len(d.delegates)-1:
+      if i > len(d.delegates)-1: break # One delegate might've been removed.
+      let deleg = d.delegates[i]
+      if not deleg.open: continue # This delegate might've been closed.
+      if (deleg.mode != fmWrite or deleg.mode != fmAppend) and
+          deleg notin readDg:
+        deleg.handleRead(deleg.deleVal)
+      if (deleg.mode != fmRead) and deleg notin writeDg:
+        deleg.handleWrite(deleg.deleVal)
+      if deleg notin errorDg:
+        deleg.handleError(deleg.deleVal)
+
+  # Execute tasks
+  for i in items(d.delegates):
+    i.task(i.deleVal)
+
+proc len*(disp: Dispatcher): int =
+  ## Retrieves the amount of delegates in ``disp``.
+  return disp.delegates.len
+
+when not defined(testing) and isMainModule:
+
+  proc testConnect(s: AsyncSocket, no: int) =
+    echo("Connected! " & $no)
+
+  proc testRead(s: AsyncSocket, no: int) =
+    echo("Reading! " & $no)
+    var data = ""
+    if not s.readLine(data): return
+    if data == "":
+      echo("Closing connection. " & $no)
+      s.close()
+    echo(data)
+    echo("Finished reading! " & $no)
+
+  proc testAccept(s: AsyncSocket, disp: Dispatcher, no: int) =
+    echo("Accepting client! " & $no)
+    var client: AsyncSocket
+    new(client)
+    var address = ""
+    s.acceptAddr(client, address)
+    echo("Accepted ", address)
+    client.handleRead =
+      proc (s: AsyncSocket) =
+        testRead(s, 2)
+    disp.register(client)
+
+  proc main =
+    var d = newDispatcher()
+
+    var s = asyncSocket()
+    s.connect("amber.tenthbit.net", Port(6667))
+    s.handleConnect =
+      proc (s: AsyncSocket) =
+        testConnect(s, 1)
+    s.handleRead =
+      proc (s: AsyncSocket) =
+        testRead(s, 1)
+    d.register(s)
+
+    var server = asyncSocket()
+    server.handleAccept =
+      proc (s: AsyncSocket) =
+        testAccept(s, d, 78)
+    server.bindAddr(Port(5555))
+    server.listen()
+    d.register(server)
+
+    while d.poll(-1): discard
+  main()
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
new file mode 100644
index 000000000..aadbde824
--- /dev/null
+++ b/lib/pure/asyncnet.nim
@@ -0,0 +1,548 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a high-level asynchronous sockets API based on the
+## asynchronous dispatcher defined in the ``asyncdispatch`` module.
+##
+## SSL
+## ---
+##
+## SSL can be enabled by compiling with the ``-d:ssl`` flag.
+##
+## You must create a new SSL context with the ``newContext`` function defined
+## in the ``net`` module. You may then call ``wrapSocket`` on your socket using
+## the newly created SSL context to get an SSL socket.
+##
+## Examples
+## --------
+##
+## Chat server
+## ^^^^^^^^^^^
+##
+## The following example demonstrates a simple chat server.
+##
+## .. code-block::nim
+##
+##   import asyncnet, asyncdispatch
+##
+##   var clients {.threadvar.}: seq[AsyncSocket]
+##
+##   proc processClient(client: AsyncSocket) {.async.} =
+##     while true:
+##       let line = await client.recvLine()
+##       for c in clients:
+##         await c.send(line & "\c\L")
+##
+##   proc serve() {.async.} =
+##     clients = @[]
+##     var server = newAsyncSocket()
+##     server.bindAddr(Port(12345))
+##     server.listen()
+##
+##     while true:
+##       let client = await server.accept()
+##       clients.add client
+##
+##       asyncCheck processClient(client)
+##
+##   asyncCheck serve()
+##   runForever()
+##
+
+import asyncdispatch
+import rawsockets
+import net
+import os
+
+export SOBool
+
+when defined(ssl):
+  import openssl
+
+type
+  # TODO: I would prefer to just do:
+  # AsyncSocket* {.borrow: `.`.} = distinct Socket. But that doesn't work.
+  AsyncSocketDesc  = object
+    fd: SocketHandle
+    closed: bool ## determines whether this socket has been closed
+    case isBuffered: bool ## determines whether this socket is buffered.
+    of true:
+      buffer: array[0..BufferSize, char]
+      currPos: int # current index in buffer
+      bufLen: int # current length of buffer
+    of false: nil
+    case isSsl: bool
+    of true:
+      when defined(ssl):
+        sslHandle: SslPtr
+        sslContext: SslContext
+        bioIn: BIO
+        bioOut: BIO
+    of false: nil
+  AsyncSocket* = ref AsyncSocketDesc
+
+{.deprecated: [PAsyncSocket: AsyncSocket].}
+
+# TODO: Save AF, domain etc info and reuse it in procs which need it like connect.
+
+proc newAsyncSocket*(fd: TAsyncFD, isBuff: bool): AsyncSocket =
+  ## Creates a new ``AsyncSocket`` based on the supplied params.
+  assert fd != osInvalidSocket.TAsyncFD
+  new(result)
+  result.fd = fd.SocketHandle
+  result.isBuffered = isBuff
+  if isBuff:
+    result.currPos = 0
+
+proc newAsyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+    protocol: Protocol = IPPROTO_TCP, buffered = true): AsyncSocket =
+  ## Creates a new asynchronous socket.
+  ##
+  ## This procedure will also create a brand new file descriptor for
+  ## this socket.
+  result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+
+proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): AsyncSocket =
+  ## Creates a new asynchronous socket.
+  ##
+  ## This procedure will also create a brand new file descriptor for
+  ## this socket.
+  result = newAsyncSocket(newAsyncRawSocket(domain, typ, protocol), buffered)
+
+when defined(ssl):
+  proc getSslError(handle: SslPtr, err: cint): cint =
+    assert err < 0
+    var ret = SSLGetError(handle, err.cint)
+    case ret
+    of SSL_ERROR_ZERO_RETURN:
+      raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+    of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+      return ret
+    of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
+      return ret
+    of SSL_ERROR_WANT_X509_LOOKUP:
+      raiseSSLError("Function for x509 lookup has been called.")
+    of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+      raiseSSLError()
+    else: raiseSSLError("Unknown Error")
+
+  proc sendPendingSslData(socket: AsyncSocket,
+      flags: set[SocketFlag]) {.async.} =
+    let len = bioCtrlPending(socket.bioOut)
+    if len > 0:
+      var data = newStringOfCap(len)
+      let read = bioRead(socket.bioOut, addr data[0], len)
+      assert read != 0
+      if read < 0:
+        raiseSslError()
+      data.setLen(read)
+      await socket.fd.TAsyncFd.send(data, flags)
+
+  proc appeaseSsl(socket: AsyncSocket, flags: set[SocketFlag],
+                  sslError: cint) {.async.} =
+    case sslError
+    of SSL_ERROR_WANT_WRITE:
+      await sendPendingSslData(socket, flags)
+    of SSL_ERROR_WANT_READ:
+      var data = await recv(socket.fd.TAsyncFD, BufferSize, flags)
+      let ret = bioWrite(socket.bioIn, addr data[0], data.len.cint)
+      if ret < 0:
+        raiseSSLError()
+    else:
+      raiseSSLError("Cannot appease SSL.")
+
+  template sslLoop(socket: AsyncSocket, flags: set[SocketFlag],
+                   op: expr) =
+    var opResult {.inject.} = -1.cint
+    while opResult < 0:
+      opResult = op
+      # Bit hackish here.
+      # TODO: Introduce an async template transformation pragma?
+      yield sendPendingSslData(socket, flags)
+      if opResult < 0:
+        let err = getSslError(socket.sslHandle, opResult.cint)
+        yield appeaseSsl(socket, flags, err.cint)
+
+proc connect*(socket: AsyncSocket, address: string, port: Port,
+    af = AF_INET) {.async.} =
+  ## Connects ``socket`` to server at ``address:port``.
+  ##
+  ## Returns a ``Future`` which will complete when the connection succeeds
+  ## or an error occurs.
+  await connect(socket.fd.TAsyncFD, address, port, af)
+  if socket.isSsl:
+    when defined(ssl):
+      let flags = {SocketFlag.SafeDisconn}
+      sslSetConnectState(socket.sslHandle)
+      sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
+
+template readInto(buf: cstring, size: int, socket: AsyncSocket,
+                  flags: set[SocketFlag]): int =
+  ## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that
+  ## this is a template and not a proc.
+  var res = 0
+  if socket.isSsl:
+    when defined(ssl):
+      # SSL mode.
+      sslLoop(socket, flags,
+        sslRead(socket.sslHandle, buf, size.cint))
+      res = opResult
+  else:
+    var recvIntoFut = recvInto(socket.fd.TAsyncFD, buf, size, flags)
+    yield recvIntoFut
+    # Not in SSL mode.
+    res = recvIntoFut.read()
+  res
+
+template readIntoBuf(socket: AsyncSocket,
+    flags: set[SocketFlag]): int =
+  var size = readInto(addr socket.buffer[0], BufferSize, socket, flags)
+  socket.currPos = 0
+  socket.bufLen = size
+  size
+
+proc recv*(socket: AsyncSocket, size: int,
+           flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
+  ## Reads **up to** ``size`` bytes from ``socket``.
+  ##
+  ## For buffered sockets this function will attempt to read all the requested
+  ## data. It will read this data in ``BufferSize`` chunks.
+  ##
+  ## For unbuffered sockets this function makes no effort to read
+  ## all the data requested. It will return as much data as the operating system
+  ## gives it.
+  ##
+  ## If socket is disconnected during the
+  ## recv operation then the future may complete with only a part of the
+  ## requested data.
+  ##
+  ## If socket is disconnected and no data is available
+  ## to be read then the future will complete with a value of ``""``.
+  if socket.isBuffered:
+    result = newString(size)
+    shallow(result)
+    let originalBufPos = socket.currPos
+
+    if socket.bufLen == 0:
+      let res = socket.readIntoBuf(flags - {SocketFlag.Peek})
+      if res == 0:
+        result.setLen(0)
+        return
+
+    var read = 0
+    while read < size:
+      if socket.currPos >= socket.bufLen:
+        if SocketFlag.Peek in flags:
+          # We don't want to get another buffer if we're peeking.
+          break
+        let res = socket.readIntoBuf(flags - {SocketFlag.Peek})
+        if res == 0:
+          break
+
+      let chunk = min(socket.bufLen-socket.currPos, size-read)
+      copyMem(addr(result[read]), addr(socket.buffer[socket.currPos]), chunk)
+      read.inc(chunk)
+      socket.currPos.inc(chunk)
+
+    if SocketFlag.Peek in flags:
+      # Restore old buffer cursor position.
+      socket.currPos = originalBufPos
+    result.setLen(read)
+  else:
+    result = newString(size)
+    let read = readInto(addr result[0], size, socket, flags)
+    result.setLen(read)
+
+proc send*(socket: AsyncSocket, data: string,
+           flags = {SocketFlag.SafeDisconn}) {.async.} =
+  ## Sends ``data`` to ``socket``. The returned future will complete once all
+  ## data has been sent.
+  assert socket != nil
+  if socket.isSsl:
+    when defined(ssl):
+      var copy = data
+      sslLoop(socket, flags,
+        sslWrite(socket.sslHandle, addr copy[0], copy.len.cint))
+      await sendPendingSslData(socket, flags)
+  else:
+    await send(socket.fd.TAsyncFD, data, flags)
+
+proc acceptAddr*(socket: AsyncSocket, flags = {SocketFlag.SafeDisconn}):
+      Future[tuple[address: string, client: AsyncSocket]] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection and the remote address of the client.
+  ## The future will complete when the connection is successfully accepted.
+  var retFuture = newFuture[tuple[address: string, client: AsyncSocket]]("asyncnet.acceptAddr")
+  var fut = acceptAddr(socket.fd.TAsyncFD, flags)
+  fut.callback =
+    proc (future: Future[tuple[address: string, client: TAsyncFD]]) =
+      assert future.finished
+      if future.failed:
+        retFuture.fail(future.readError)
+      else:
+        let resultTup = (future.read.address,
+                         newAsyncSocket(future.read.client, socket.isBuffered))
+        retFuture.complete(resultTup)
+  return retFuture
+
+proc accept*(socket: AsyncSocket,
+    flags = {SocketFlag.SafeDisconn}): Future[AsyncSocket] =
+  ## Accepts a new connection. Returns a future containing the client socket
+  ## corresponding to that connection.
+  ## The future will complete when the connection is successfully accepted.
+  var retFut = newFuture[AsyncSocket]("asyncnet.accept")
+  var fut = acceptAddr(socket, flags)
+  fut.callback =
+    proc (future: Future[tuple[address: string, client: AsyncSocket]]) =
+      assert future.finished
+      if future.failed:
+        retFut.fail(future.readError)
+      else:
+        retFut.complete(future.read.client)
+  return retFut
+
+proc recvLineInto*(socket: AsyncSocket, resString: ptr string,
+    flags = {SocketFlag.SafeDisconn}) {.async.} =
+  ## Reads a line of data from ``socket`` into ``resString``.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ##
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## If the socket is disconnected in the middle of a line (before ``\r\L``
+  ## is read) then line will be set to ``""``.
+  ## The partial line **will be lost**.
+  ##
+  ## **Warning**: The ``Peek`` flag is not yet implemented.
+  ##
+  ## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
+  ## protocol uses ``\r\L`` to delimit a new line.
+  ##
+  ## **Warning**: ``recvLineInto`` currently uses a raw pointer to a string for
+  ## performance reasons. This will likely change soon to use FutureVars.
+  assert SocketFlag.Peek notin flags ## TODO:
+  result = newFuture[void]("asyncnet.recvLineInto")
+
+  template addNLIfEmpty(): stmt =
+    if resString[].len == 0:
+      resString[].add("\c\L")
+
+  if socket.isBuffered:
+    if socket.bufLen == 0:
+      let res = socket.readIntoBuf(flags)
+      if res == 0:
+        return
+
+    var lastR = false
+    while true:
+      if socket.currPos >= socket.bufLen:
+        let res = socket.readIntoBuf(flags)
+        if res == 0:
+          resString[].setLen(0)
+          return
+
+      case socket.buffer[socket.currPos]
+      of '\r':
+        lastR = true
+        addNLIfEmpty()
+      of '\L':
+        addNLIfEmpty()
+        socket.currPos.inc()
+        return
+      else:
+        if lastR:
+          socket.currPos.inc()
+          return
+        else:
+          resString[].add socket.buffer[socket.currPos]
+      socket.currPos.inc()
+  else:
+    var c = ""
+    while true:
+      let recvFut = recv(socket, 1, flags)
+      c = recvFut.read()
+      if c.len == 0:
+        resString[].setLen(0)
+        return
+      if c == "\r":
+        let recvFut = recv(socket, 1, flags) # Skip \L
+        c = recvFut.read()
+        assert c == "\L"
+        addNLIfEmpty()
+        return
+      elif c == "\L":
+        addNLIfEmpty()
+        return
+      resString[].add c
+
+proc recvLine*(socket: AsyncSocket,
+    flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
+  ## Reads a line of data from ``socket``. Returned future will complete once
+  ## a full line is read or an error occurs.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ##
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## If the socket is disconnected in the middle of a line (before ``\r\L``
+  ## is read) then line will be set to ``""``.
+  ## The partial line **will be lost**.
+  ##
+  ## **Warning**: The ``Peek`` flag is not yet implemented.
+  ##
+  ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
+  ## uses ``\r\L`` to delimit a new line.
+  template addNLIfEmpty(): stmt =
+    if result.len == 0:
+      result.add("\c\L")
+  assert SocketFlag.Peek notin flags ## TODO:
+
+  result = ""
+  await socket.recvLineInto(addr result, flags)
+
+proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
+  ## Marks ``socket`` as accepting connections.
+  ## ``Backlog`` specifies the maximum length of the
+  ## queue of pending connections.
+  ##
+  ## Raises an EOS error upon failure.
+  if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError())
+
+proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
+  tags: [ReadIOEffect].} =
+  ## Binds ``address``:``port`` to the socket.
+  ##
+  ## If ``address`` is "" then ADDR_ANY will be bound.
+
+  if address == "":
+    var name: Sockaddr_in
+    when defined(Windows) or defined(nimdoc):
+      name.sin_family = toInt(AF_INET).int16
+    else:
+      name.sin_family = toInt(AF_INET)
+    name.sin_port = htons(int16(port))
+    name.sin_addr.s_addr = htonl(INADDR_ANY)
+    if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)),
+                  sizeof(name).Socklen) < 0'i32:
+      raiseOSError(osLastError())
+  else:
+    var aiList = getAddrInfo(address, port, AF_INET)
+    if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+      dealloc(aiList)
+      raiseOSError(osLastError())
+    dealloc(aiList)
+
+proc close*(socket: AsyncSocket) =
+  ## Closes the socket.
+  defer:
+    socket.fd.TAsyncFD.closeSocket()
+  when defined(ssl):
+    if socket.isSSL:
+      let res = SslShutdown(socket.sslHandle)
+      if res == 0:
+        discard
+      elif res != 1:
+        raiseSslError()
+  socket.closed = true # TODO: Add extra debugging checks for this.
+
+when defined(ssl):
+  proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) =
+    ## Wraps a socket in an SSL context. This function effectively turns
+    ## ``socket`` into an SSL socket.
+    ##
+    ## **Disclaimer**: This code is not well tested, may be very unsafe and
+    ## prone to security vulnerabilities.
+    socket.isSsl = true
+    socket.sslContext = ctx
+    socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
+    if socket.sslHandle == nil:
+      raiseSslError()
+
+    socket.bioIn = bioNew(bio_s_mem())
+    socket.bioOut = bioNew(bio_s_mem())
+    sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut)
+
+proc getSockOpt*(socket: AsyncSocket, opt: SOBool, level = SOL_SOCKET): bool {.
+  tags: [ReadIOEffect].} =
+  ## Retrieves option ``opt`` as a boolean value.
+  var res = getSockOptInt(socket.fd, cint(level), toCInt(opt))
+  result = res != 0
+
+proc setSockOpt*(socket: AsyncSocket, opt: SOBool, value: bool,
+    level = SOL_SOCKET) {.tags: [WriteIOEffect].} =
+  ## Sets option ``opt`` to a boolean value specified by ``value``.
+  var valuei = cint(if value: 1 else: 0)
+  setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
+
+proc isSsl*(socket: AsyncSocket): bool =
+  ## Determines whether ``socket`` is a SSL socket.
+  socket.isSsl
+
+proc getFd*(socket: AsyncSocket): SocketHandle =
+  ## Returns the socket's file descriptor.
+  return socket.fd
+
+proc isClosed*(socket: AsyncSocket): bool =
+  ## Determines whether the socket has been closed.
+  return socket.closed
+
+when not defined(testing) and isMainModule:
+  type
+    TestCases = enum
+      HighClient, LowClient, LowServer
+
+  const test = HighClient
+
+  when test == HighClient:
+    proc main() {.async.} =
+      var sock = newAsyncSocket()
+      await sock.connect("irc.freenode.net", Port(6667))
+      while true:
+        let line = await sock.recvLine()
+        if line == "":
+          echo("Disconnected")
+          break
+        else:
+          echo("Got line: ", line)
+    asyncCheck main()
+  elif test == LowClient:
+    var sock = newAsyncSocket()
+    var f = connect(sock, "irc.freenode.net", Port(6667))
+    f.callback =
+      proc (future: Future[void]) =
+        echo("Connected in future!")
+        for i in 0 .. 50:
+          var recvF = recv(sock, 10)
+          recvF.callback =
+            proc (future: Future[string]) =
+              echo("Read ", future.read.len, ": ", future.read.repr)
+  elif test == LowServer:
+    var sock = newAsyncSocket()
+    sock.bindAddr(Port(6667))
+    sock.listen()
+    proc onAccept(future: Future[AsyncSocket]) =
+      let client = future.read
+      echo "Accepted ", client.fd.cint
+      var t = send(client, "test\c\L")
+      t.callback =
+        proc (future: Future[void]) =
+          echo("Send")
+          client.close()
+
+      var f = accept(sock)
+      f.callback = onAccept
+
+    var f = accept(sock)
+    f.callback = onAccept
+  runForever()
+
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
new file mode 100644
index 000000000..41d19dc0f
--- /dev/null
+++ b/lib/pure/base64.nim
@@ -0,0 +1,128 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a base64 encoder and decoder.
+
+const 
+  cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} = 
+  ## encodes `s` into base64 representation. After `lineLen` characters, a 
+  ## `newline` is added.
+  var total = ((len(s) + 2) div 3) * 4
+  var numLines = (total + lineLen - 1) div lineLen
+  if numLines > 0: inc(total, (numLines-1) * newLine.len)
+
+  result = newString(total)
+  var i = 0
+  var r = 0
+  var currLine = 0
+  while i < s.len - 2:
+    var a = ord(s[i])
+    var b = ord(s[i+1])
+    var c = ord(s[i+2])
+    result[r] = cb64[a shr 2]
+    result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
+    result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] 
+    result[r+3] = cb64[c and 0x3F] 
+    inc(r, 4)
+    inc(i, 3)
+    inc(currLine, 4)
+    if currLine >= lineLen and i != s.len-2: 
+      for x in items(newLine): 
+        result[r] = x
+        inc(r)
+      currLine = 0
+
+  if i < s.len-1:
+    var a = ord(s[i])
+    var b = ord(s[i+1])
+    result[r] = cb64[a shr 2]
+    result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
+    result[r+2] = cb64[((b and 0x0F) shl 2)] 
+    result[r+3] = '='
+    if r+4 != result.len:
+      setLen(result, r+4)
+  elif i < s.len:
+    var a = ord(s[i])
+    result[r] = cb64[a shr 2]
+    result[r+1] = cb64[(a and 3) shl 4]
+    result[r+2] = '='
+    result[r+3] = '='
+    if r+4 != result.len:
+      setLen(result, r+4)
+  else:
+    #assert(r == result.len)
+    discard
+
+proc encode*[T:SomeInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string = 
+  ## encodes `s` into base64 representation. After `lineLen` characters, a 
+  ## `newline` is added.
+  encodeInternal(s, lineLen, newLine)
+    
+proc encode*(s: string, lineLen = 75, newLine="\13\10"): string = 
+  ## encodes `s` into base64 representation. After `lineLen` characters, a 
+  ## `newline` is added.
+  encodeInternal(s, lineLen, newLine)
+  
+proc decodeByte(b: char): int {.inline.} = 
+  case b
+  of '+': result = ord('>')
+  of '0'..'9': result = ord(b) + 4
+  of 'A'..'Z': result = ord(b) - ord('A')
+  of 'a'..'z': result = ord(b) - 71
+  else: result = 63
+
+proc decode*(s: string): string = 
+  ## decodes a string in base64 representation back into its original form.
+  ## Whitespace is skipped.
+  const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
+  var total = ((len(s) + 3) div 4) * 3
+  # total is an upper bound, as we will skip arbitrary whitespace:
+  result = newString(total)
+
+  var i = 0
+  var r = 0
+  while true:
+    while s[i] in Whitespace: inc(i)
+    if i < s.len-3:
+      var a = s[i].decodeByte
+      var b = s[i+1].decodeByte
+      var c = s[i+2].decodeByte
+      var d = s[i+3].decodeByte
+      
+      result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
+      result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
+      result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
+      inc(r, 3)
+      inc(i, 4)
+    else: break
+  assert i == s.len
+  # adjust the length:
+  if i > 0 and s[i-1] == '=': 
+    dec(r)
+    if i > 1 and s[i-2] == '=': dec(r)
+  setLen(result, r)
+  
+when isMainModule:
+  assert encode("leasure.") == "bGVhc3VyZS4="
+  assert encode("easure.") == "ZWFzdXJlLg=="
+  assert encode("asure.") == "YXN1cmUu"
+  assert encode("sure.") == "c3VyZS4="
+  
+  const longText = """Man is distinguished, not only by his reason, but by this
+    singular passion from other animals, which is a lust of the mind, 
+    that by a perseverance of delight in the continued and indefatigable
+    generation of knowledge, exceeds the short vehemence of any carnal
+    pleasure."""
+  const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
+                 "asure.", longText]
+  for t in items(tests):
+    assert decode(encode(t)) == t
+
diff --git a/lib/pure/basic2d.nim b/lib/pure/basic2d.nim
new file mode 100644
index 000000000..a344cd053
--- /dev/null
+++ b/lib/pure/basic2d.nim
@@ -0,0 +1,855 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Robert Persson
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import math
+import strutils
+
+
+## Basic 2d support with vectors, points, matrices and some basic utilities.
+## Vectors are implemented as direction vectors, ie. when transformed with a matrix
+## the translation part of matrix is ignored. 
+## Operators `+` , `-` , `*` , `/` , `+=` , `-=` , `*=` and `/=` are implemented for vectors and scalars.
+##
+## Quick start example:
+##   
+##   # Create a matrix which first rotates, then scales and at last translates
+##   
+##   var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0)
+##   
+##   # Create a 2d point at (100,0) and a vector (5,2)
+##   
+##   var pt:TPoint2d=point2d(100.0,0.0) 
+##   
+##   var vec:TVector2d=vector2d(5.0,2.0)
+##   
+##   
+##   pt &= m # transforms pt in place
+##   
+##   var pt2:TPoint2d=pt & m #concatenates pt with m and returns a new point
+##   
+##   var vec2:TVector2d=vec & m #concatenates vec with m and returns a new vector
+
+
+const
+  DEG360* = PI * 2.0
+    ## 360 degrees in radians.
+  DEG270* = PI * 1.5
+    ## 270 degrees in radians.
+  DEG180* = PI
+    ## 180 degrees in radians.
+  DEG90* = PI / 2.0
+    ## 90 degrees in radians.
+  DEG60* = PI / 3.0
+    ## 60 degrees in radians.
+  DEG45* = PI / 4.0
+    ## 45 degrees in radians.
+  DEG30* = PI / 6.0
+    ## 30 degrees in radians.
+  DEG15* = PI / 12.0
+    ## 15 degrees in radians.
+  RAD2DEGCONST = 180.0 / PI
+    ## used internally by DegToRad and RadToDeg
+
+type
+    TMatrix2d* = object
+      ## Implements a row major 2d matrix, which means
+      ## transformations are applied the order they are concatenated.
+      ## The rightmost column of the 3x3 matrix is left out since normally
+      ## not used for geometric transformations in 2d.
+      ax*,ay*,bx*,by*,tx*,ty*:float
+    TPoint2d* = object
+      ## Implements a non-homegeneous 2d point stored as 
+      ## an `x` coordinate and an `y` coordinate.
+      x*,y*:float
+    TVector2d* = object 
+      ## Implements a 2d **direction vector** stored as 
+      ## an `x` coordinate and an `y` coordinate. Direction vector means, 
+      ## that when transforming a vector with a matrix, the translational
+      ## part of the matrix is ignored.
+      x*,y*:float
+ 
+
+
+# Some forward declarations...
+proc matrix2d*(ax,ay,bx,by,tx,ty:float):TMatrix2d {.noInit.}
+  ## Creates a new matrix. 
+  ## `ax`,`ay` is the local x axis
+  ## `bx`,`by` is the local y axis
+  ## `tx`,`ty` is the translation
+proc vector2d*(x,y:float):TVector2d {.noInit,inline.}
+  ## Returns a new vector (`x`,`y`)
+proc point2d*(x,y:float):TPoint2d {.noInit,inline.}
+  ## Returns a new point (`x`,`y`)
+
+
+
+let
+  IDMATRIX*:TMatrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0)
+    ## Quick access to an identity matrix
+  ORIGO*:TPoint2d=point2d(0.0,0.0)
+    ## Quick acces to point (0,0)
+  XAXIS*:TVector2d=vector2d(1.0,0.0)
+    ## Quick acces to an 2d x-axis unit vector
+  YAXIS*:TVector2d=vector2d(0.0,1.0)
+    ## Quick acces to an 2d y-axis unit vector
+
+  
+# ***************************************
+#     Private utils
+# ***************************************
+
+proc rtos(val:float):string=
+  return formatFloat(val,ffDefault,0)
+
+proc safeArccos(v:float):float=
+  ## assumes v is in range 0.0-1.0, but clamps
+  ## the value to avoid out of domain errors
+  ## due to rounding issues
+  return arccos(clamp(v,-1.0,1.0))
+
+
+template makeBinOpVector(s:expr)= 
+  ## implements binary operators + , - , * and / for vectors
+  proc s*(a,b:TVector2d):TVector2d {.inline,noInit.} = vector2d(s(a.x,b.x),s(a.y,b.y))
+  proc s*(a:TVector2d,b:float):TVector2d {.inline,noInit.}  = vector2d(s(a.x,b),s(a.y,b))
+  proc s*(a:float,b:TVector2d):TVector2d {.inline,noInit.}  = vector2d(s(a,b.x),s(a,b.y))
+  
+template makeBinOpAssignVector(s:expr)= 
+  ## implements inplace binary operators += , -= , /= and *= for vectors
+  proc s*(a:var TVector2d,b:TVector2d) {.inline.} = s(a.x,b.x) ; s(a.y,b.y)
+  proc s*(a:var TVector2d,b:float) {.inline.} = s(a.x,b) ; s(a.y,b)
+
+
+# ***************************************
+#     TMatrix2d implementation
+# ***************************************
+
+proc setElements*(t:var TMatrix2d,ax,ay,bx,by,tx,ty:float) {.inline.}=
+  ## Sets arbitrary elements in an existing matrix.
+  t.ax=ax
+  t.ay=ay
+  t.bx=bx
+  t.by=by
+  t.tx=tx
+  t.ty=ty
+
+proc matrix2d*(ax,ay,bx,by,tx,ty:float):TMatrix2d =
+  result.setElements(ax,ay,bx,by,tx,ty)
+
+proc `&`*(a,b:TMatrix2d):TMatrix2d {.noInit.} = #concatenate matrices
+  ## Concatenates matrices returning a new matrix.
+  
+  # | a.AX a.AY 0 |   | b.AX b.AY 0 |
+  # | a.BX a.BY 0 | * | b.BX b.BY 0 |
+  # | a.TX a.TY 1 |   | b.TX b.TY 1 |
+  result.setElements(
+    a.ax * b.ax + a.ay * b.bx,
+    a.ax * b.ay + a.ay * b.by,
+    a.bx * b.ax + a.by * b.bx,
+    a.bx * b.ay + a.by * b.by,
+    a.tx * b.ax + a.ty * b.bx + b.tx, 
+    a.tx * b.ay + a.ty * b.by + b.ty)
+
+
+proc scale*(s:float):TMatrix2d {.noInit.} =
+  ## Returns a new scale matrix.
+  result.setElements(s,0,0,s,0,0)
+
+proc scale*(s:float,org:TPoint2d):TMatrix2d {.noInit.} =
+  ## Returns a new scale matrix using, `org` as scale origin.
+  result.setElements(s,0,0,s,org.x-s*org.x,org.y-s*org.y)
+
+proc stretch*(sx,sy:float):TMatrix2d {.noInit.} =
+  ## Returns new a stretch matrix, which is a
+  ## scale matrix with non uniform scale in x and y.
+  result.setElements(sx,0,0,sy,0,0)
+    
+proc stretch*(sx,sy:float,org:TPoint2d):TMatrix2d {.noInit.} =
+  ## Returns a new stretch matrix, which is a
+  ## scale matrix with non uniform scale in x and y.
+  ## `org` is used as stretch origin.
+  result.setElements(sx,0,0,sy,org.x-sx*org.x,org.y-sy*org.y)
+    
+proc move*(dx,dy:float):TMatrix2d {.noInit.} =
+  ## Returns a new translation matrix.
+  result.setElements(1,0,0,1,dx,dy)
+
+proc move*(v:TVector2d):TMatrix2d {.noInit.} =
+  ## Returns a new translation matrix from a vector.
+  result.setElements(1,0,0,1,v.x,v.y)
+
+proc rotate*(rad:float):TMatrix2d {.noInit.} =
+  ## Returns a new rotation matrix, which
+  ## represents a rotation by `rad` radians
+  let 
+    s=sin(rad)
+    c=cos(rad)
+  result.setElements(c,s,-s,c,0,0)
+
+proc rotate*(rad:float,org:TPoint2d):TMatrix2d {.noInit.} =
+  ## Returns a new rotation matrix, which
+  ## represents a rotation by `rad` radians around
+  ## the origin `org`
+  let
+    s=sin(rad)
+    c=cos(rad)
+  result.setElements(c,s,-s,c,org.x+s*org.y-c*org.x,org.y-c*org.y-s*org.x)
+  
+proc mirror*(v:TVector2d):TMatrix2d {.noInit.} =
+  ## Returns a new mirror matrix, mirroring
+  ## around the line that passes through origo and
+  ## has the direction of `v`
+  let
+    sqx=v.x*v.x
+    sqy=v.y*v.y
+    nd=1.0/(sqx+sqy) #used to normalize invector
+    xy2=v.x*v.y*2.0*nd
+    sqd=nd*(sqx-sqy)
+    
+  if nd==Inf or nd==NegInf:
+    return IDMATRIX #mirroring around a zero vector is arbitrary=>just use identity
+
+  result.setElements(
+    sqd,xy2,
+    xy2,-sqd,
+    0.0,0.0)
+
+proc mirror*(org:TPoint2d,v:TVector2d):TMatrix2d {.noInit.} =
+  ## Returns a new mirror matrix, mirroring
+  ## around the line that passes through `org` and
+  ## has the direction of `v`
+  let
+    sqx=v.x*v.x
+    sqy=v.y*v.y
+    nd=1.0/(sqx+sqy) #used to normalize invector
+    xy2=v.x*v.y*2.0*nd
+    sqd=nd*(sqx-sqy)
+    
+  if nd==Inf or nd==NegInf:
+    return IDMATRIX #mirroring around a zero vector is arbitrary=>just use identity
+
+  result.setElements(
+    sqd,xy2,
+    xy2,-sqd,
+    org.x-org.y*xy2-org.x*sqd,org.y-org.x*xy2+org.y*sqd)
+  
+
+
+proc skew*(xskew,yskew:float):TMatrix2d {.noInit.} =
+  ## Returns a new skew matrix, which has its 
+  ## x axis rotated `xskew` radians from the local x axis, and
+  ## y axis rotated `yskew` radians from the local y axis
+  result.setElements(cos(yskew),sin(yskew),-sin(xskew),cos(xskew),0,0)
+  
+
+proc `$`* (t:TMatrix2d):string {.noInit.} =
+  ## Returns a string representation of the matrix
+  return rtos(t.ax) & "," & rtos(t.ay) &
+    "," & rtos(t.bx) & "," & rtos(t.by) & 
+    "," & rtos(t.tx) & "," & rtos(t.ty)
+
+proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool=
+  ## Checks if the transform is uniform, that is 
+  ## perpendicular axes of equal length, which means (for example)
+  ## it cannot transform a circle into an ellipse.
+  ## `tol` is used as tolerance for both equal length comparison 
+  ## and perp. comparison.
+  
+  #dot product=0 means perpendicular coord. system:
+  if abs(t.ax*t.bx+t.ay*t.by)<=tol:   
+    #subtract squared lengths of axes to check if uniform scaling:
+    if abs((t.ax*t.ax+t.ay*t.ay)-(t.bx*t.bx+t.by*t.by))<=tol:
+      return true
+  return false
+    
+proc determinant*(t:TMatrix2d):float=
+  ## Computes the determinant of the matrix.
+  
+  #NOTE: equivalent with perp.dot product for two 2d vectors
+  return t.ax*t.by-t.bx*t.ay  
+
+proc isMirroring* (m:TMatrix2d):bool=
+  ## Checks if the `m` is a mirroring matrix,
+  ## which means it will reverse direction of a curve transformed with it
+  return m.determinant<0.0
+  
+proc inverse*(m:TMatrix2d):TMatrix2d {.noInit.} =
+  ## Returns a new matrix, which is the inverse of the matrix
+  ## If the matrix is not invertible (determinant=0), an EDivByZero
+  ## will be raised.
+  let d=m.determinant
+  if d==0.0:
+    raise newException(DivByZeroError,"Cannot invert a zero determinant matrix")
+    
+  result.setElements(
+    m.by/d,-m.ay/d,
+    -m.bx/d,m.ax/d,
+    (m.bx*m.ty-m.by*m.tx)/d,
+    (m.ay*m.tx-m.ax*m.ty)/d)
+
+proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool=
+  ## Checks if all elements of `m1`and `m2` is equal within
+  ## a given tolerance `tol`.
+  return 
+    abs(m1.ax-m2.ax)<=tol and
+    abs(m1.ay-m2.ay)<=tol and
+    abs(m1.bx-m2.bx)<=tol and
+    abs(m1.by-m2.by)<=tol and
+    abs(m1.tx-m2.tx)<=tol and
+    abs(m1.ty-m2.ty)<=tol
+    
+proc `=~`*(m1,m2:TMatrix2d):bool=
+  ## Checks if `m1`and `m2` is approximately equal, using a
+  ## tolerance of 1e-6.
+  equals(m1,m2)
+
+proc isIdentity*(m:TMatrix2d,tol=1.0e-6):bool=
+  ## Checks is a matrix is approximately an identity matrix,
+  ## using `tol` as tolerance for each element.
+  return equals(m,IDMATRIX,tol)
+
+proc apply*(m:TMatrix2d,x,y:var float,translate=false)=
+  ## Applies transformation `m` onto `x`,`y`, optionally
+  ## using the translation part of the matrix.
+  if translate: # positional style transform
+    let newx=x*m.ax+y*m.bx+m.tx
+    y=x*m.ay+y*m.by+m.ty
+    x=newx
+  else: # delta style transform
+    let newx=x*m.ax+y*m.bx
+    y=x*m.ay+y*m.by
+    x=newx
+
+
+
+# ***************************************
+#     TVector2d implementation
+# ***************************************
+proc vector2d*(x,y:float):TVector2d = #forward decl.
+  result.x=x
+  result.y=y
+
+proc polarVector2d*(ang:float,len:float):TVector2d {.noInit.} =
+  ## Returns a new vector with angle `ang` and magnitude `len`
+  result.x=cos(ang)*len
+  result.y=sin(ang)*len
+
+proc slopeVector2d*(slope:float,len:float):TVector2d {.noInit.} =
+  ## Returns a new vector having slope (dy/dx) given by
+  ## `slope`, and a magnitude of `len`
+  let ang=arctan(slope)
+  result.x=cos(ang)*len
+  result.y=sin(ang)*len
+
+proc len*(v:TVector2d):float {.inline.}=
+  ## Returns the length of the vector.
+  sqrt(v.x*v.x+v.y*v.y)
+  
+proc `len=`*(v:var TVector2d,newlen:float) {.noInit.} =
+  ## Sets the length of the vector, keeping its angle.
+  let fac=newlen/v.len
+  
+  if newlen==0.0:
+    v.x=0.0
+    v.y=0.0
+    return
+  
+  if fac==Inf or fac==NegInf:
+    #to short for float accuracy
+    #do as good as possible:
+    v.x=newlen
+    v.y=0.0
+  else:
+    v.x*=fac
+    v.y*=fac
+  
+proc sqrLen*(v:TVector2d):float {.inline.}=
+  ## Computes the squared length of the vector, which is
+  ## faster than computing the absolute length.
+  v.x*v.x+v.y*v.y
+  
+proc angle*(v:TVector2d):float=
+  ## Returns the angle of the vector. 
+  ## (The counter clockwise plane angle between posetive x axis and `v`)
+  result=arctan2(v.y,v.x)
+  if result<0.0: result+=DEG360
+  
+proc `$` *(v:TVector2d):string=
+  ## String representation of `v`
+  result=rtos(v.x)
+  result.add(",")
+  result.add(rtos(v.y))
+  
+  
+proc `&` *(v:TVector2d,m:TMatrix2d):TVector2d {.noInit.} =
+  ## Concatenate vector `v` with a transformation matrix.
+  ## Transforming a vector ignores the translational part
+  ## of the matrix.
+  
+  #             | AX AY 0 |
+  # | X Y 1 | * | BX BY 0 |
+  #             | 0  0  1 |
+  result.x=v.x*m.ax+v.y*m.bx
+  result.y=v.x*m.ay+v.y*m.by
+
+
+proc `&=`*(v:var TVector2d,m:TMatrix2d) {.inline.}=
+  ## Applies transformation `m` onto `v` in place.
+  ## Transforming a vector ignores the translational part
+  ## of the matrix.
+  
+  #             | AX AY 0 |
+  # | X Y 1 | * | BX BY 0 |
+  #             | 0  0  1 |
+  let newx=v.x*m.ax+v.y*m.bx
+  v.y=v.x*m.ay+v.y*m.by
+  v.x=newx
+
+
+proc tryNormalize*(v:var TVector2d):bool= 
+  ## Modifies `v` to have a length of 1.0, keeping its angle.
+  ## If `v` has zero length (and thus no angle), it is left unmodified and 
+  ## false is returned, otherwise true is returned.
+
+  let mag=v.len
+
+  if mag==0.0:
+    return false
+  
+  v.x/=mag
+  v.y/=mag
+  return true
+
+
+proc normalize*(v:var TVector2d) {.inline.}= 
+  ## Modifies `v` to have a length of 1.0, keeping its angle.
+  ## If  `v` has zero length, an EDivByZero will be raised.
+  if not tryNormalize(v):
+    raise newException(DivByZeroError,"Cannot normalize zero length vector")
+  
+proc transformNorm*(v:var TVector2d,t:TMatrix2d)=
+  ## Applies a normal direction transformation `t` onto `v` in place.
+  ## The resulting vector is *not* normalized.  Transforming a vector ignores the 
+  ## translational part of the matrix. If the matrix is not invertible 
+  ## (determinant=0), an EDivByZero will be raised.
+
+  # transforming a normal is done by transforming
+  # by the transpose of the inverse of the original matrix
+  # this can be heavily optimized by precompute and inline
+  #             | | AX AY 0 | ^-1| ^T
+  # | X Y 1 | * | | BX BY 0 |    |
+  #             | | 0  0  1 |    |
+  let d=t.determinant
+  if(d==0.0):
+    raise newException(DivByZeroError,"Matrix is not invertible")
+  let newx = (t.by*v.x-t.ay*v.y)/d
+  v.y = (t.ax*v.y-t.bx*v.x)/d
+  v.x = newx
+
+proc transformInv*(v:var TVector2d,t:TMatrix2d)=
+  ## Applies inverse of a transformation `t` to `v` in place.
+  ## This is faster than creating an inverse matrix and apply() it.
+  ## Transforming a vector ignores the translational part
+  ## of the matrix. If the matrix is not invertible (determinant=0), an EDivByZero
+  ## will be raised.
+  let d=t.determinant
+
+  if(d==0.0):
+    raise newException(DivByZeroError,"Matrix is not invertible")
+
+  let newx=(t.by*v.x-t.bx*v.y)/d
+  v.y = (t.ax*v.y-t.ay*v.x)/d
+  v.x = newx
+
+proc transformNormInv*(v:var TVector2d,t:TMatrix2d)=
+  ## Applies an inverse normal direction transformation `t` onto `v` in place.
+  ## This is faster than creating an inverse 
+  ## matrix and transformNorm(...) it. Transforming a vector ignores the 
+  ## translational part of the matrix.
+
+  # normal inverse transform is done by transforming
+  # by the inverse of the transpose of the inverse of the org. matrix
+  # which is equivalent with transforming with the transpose.
+  #             | | | AX AY 0 |^-1|^T|^-1                | AX BX 0 |
+  # | X Y 1 | * | | | BX BY 0 |   |  |    =  | X Y 1 | * | AY BY 0 | 
+  #             | | | 0  0  1 |   |  |                   | 0  0  1 | 
+  # This can be heavily reduced to:
+  let newx=t.ay*v.y+t.ax*v.x
+  v.y=t.by*v.y+t.bx*v.x
+  v.x=newx
+
+proc rotate90*(v:var TVector2d) {.inline.}=
+  ## Quickly rotates vector `v` 90 degrees counter clockwise,
+  ## without using any trigonometrics.
+  swap(v.x,v.y)
+  v.x= -v.x
+  
+proc rotate180*(v:var TVector2d){.inline.}=
+  ## Quickly rotates vector `v` 180 degrees counter clockwise,
+  ## without using any trigonometrics.
+  v.x= -v.x
+  v.y= -v.y
+  
+proc rotate270*(v:var TVector2d) {.inline.}=
+  ## Quickly rotates vector `v` 270 degrees counter clockwise,
+  ## without using any trigonometrics.
+  swap(v.x,v.y)
+  v.y= -v.y
+  
+proc rotate*(v:var TVector2d,rad:float) =
+  ## Rotates vector `v` `rad` radians in place.
+  let
+    s=sin(rad)
+    c=cos(rad)
+    newx=c*v.x-s*v.y
+  v.y=c*v.y+s*v.x
+  v.x=newx
+  
+proc scale*(v:var TVector2d,fac:float){.inline.}=
+  ## Scales vector `v` `rad` radians in place.
+  v.x*=fac
+  v.y*=fac
+  
+proc stretch*(v:var TVector2d,facx,facy:float){.inline.}=
+  ## Stretches vector `v` `facx` times horizontally,
+  ## and `facy` times vertically.
+  v.x*=facx
+  v.y*=facy
+  
+proc mirror*(v:var TVector2d,mirrvec:TVector2d)=
+  ## Mirrors vector `v` using `mirrvec` as mirror direction.
+  let
+    sqx=mirrvec.x*mirrvec.x
+    sqy=mirrvec.y*mirrvec.y
+    nd=1.0/(sqx+sqy) #used to normalize invector
+    xy2=mirrvec.x*mirrvec.y*2.0*nd
+    sqd=nd*(sqx-sqy)
+    
+  if nd==Inf or nd==NegInf:
+    return #mirroring around a zero vector is arbitrary=>keep as is is fastest
+  
+  let newx=xy2*v.y+sqd*v.x
+  v.y=v.x*xy2-sqd*v.y
+  v.x=newx
+    
+ 
+proc `-` *(v:TVector2d):TVector2d=
+  ## Negates a vector
+  result.x= -v.x
+  result.y= -v.y
+    
+# declare templated binary operators
+makeBinOpVector(`+`)
+makeBinOpVector(`-`)
+makeBinOpVector(`*`)
+makeBinOpVector(`/`)
+makeBinOpAssignVector(`+=`)
+makeBinOpAssignVector(`-=`)
+makeBinOpAssignVector(`*=`)
+makeBinOpAssignVector(`/=`)
+
+
+proc dot*(v1,v2:TVector2d):float=
+  ## Computes the dot product of two vectors. 
+  ## Returns 0.0 if the vectors are perpendicular.
+  return v1.x*v2.x+v1.y*v2.y
+  
+proc cross*(v1,v2:TVector2d):float=
+  ## Computes the cross product of two vectors, also called
+  ## the 'perpendicular dot product' in 2d. Returns 0.0 if the vectors
+  ## are parallel.
+  return v1.x*v2.y-v1.y*v2.x
+  
+proc equals*(v1,v2:TVector2d,tol=1.0e-6):bool=
+  ## Checks if two vectors approximately equals with a tolerance.
+  return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol
+  
+proc `=~` *(v1,v2:TVector2d):bool=
+  ## Checks if two vectors approximately equals with a 
+  ## hardcoded tolerance 1e-6
+  equals(v1,v2)
+  
+proc angleTo*(v1,v2:TVector2d):float=
+  ## Returns the smallest of the two possible angles 
+  ## between `v1` and `v2` in radians.
+  var
+    nv1=v1
+    nv2=v2
+  if not nv1.tryNormalize or not nv2.tryNormalize:
+    return 0.0 # zero length vector has zero angle to any other vector
+  return safeArccos(dot(nv1,nv2))
+  
+proc angleCCW*(v1,v2:TVector2d):float=
+  ## Returns the counter clockwise plane angle from `v1` to `v2`,
+  ## in range 0 - 2*PI
+  let a=v1.angleTo(v2)
+  if v1.cross(v2)>=0.0:
+    return a
+  return DEG360-a
+  
+proc angleCW*(v1,v2:TVector2d):float=
+  ## Returns the clockwise plane angle from `v1` to `v2`,
+  ## in range 0 - 2*PI
+  let a=v1.angleTo(v2)
+  if v1.cross(v2)<=0.0:
+    return a
+  return DEG360-a
+
+proc turnAngle*(v1,v2:TVector2d):float=
+  ## Returns the amount v1 should be rotated (in radians) to equal v2,
+  ## in range -PI to PI
+  let a=v1.angleTo(v2)
+  if v1.cross(v2)<=0.0:
+    return -a
+  return a
+
+proc bisect*(v1,v2:TVector2d):TVector2d {.noInit.}=
+  ## Computes the bisector between v1 and v2 as a normalized vector.
+  ## If one of the input vectors has zero length, a normalized version
+  ## of the other is returned. If both input vectors has zero length, 
+  ## an arbitrary normalized vector is returned.
+  var
+    vmag1=v1.len
+    vmag2=v2.len
+    
+  # zero length vector equals arbitrary vector, just change to magnitude to one to
+  # avoid zero division
+  if vmag1==0.0: 
+    if vmag2==0: #both are zero length return any normalized vector
+      return XAXIS
+    vmag1=1.0
+  if vmag2==0.0: vmag2=1.0    
+    
+  let
+    x1=v1.x/vmag1
+    y1=v1.y/vmag1
+    x2=v2.x/vmag2
+    y2=v2.y/vmag2
+    
+  result.x=(x1 + x2) * 0.5
+  result.y=(y1 + y2) * 0.5
+  
+  if not result.tryNormalize():
+    # This can happen if vectors are colinear. In this special case
+    # there are actually two bisectors, we select just 
+    # one of them (x1,y1 rotated 90 degrees ccw).
+    result.x = -y1
+    result.y = x1
+
+
+
+# ***************************************
+#     TPoint2d implementation
+# ***************************************
+
+proc point2d*(x,y:float):TPoint2d =
+  result.x=x
+  result.y=y
+  
+proc sqrDist*(a,b:TPoint2d):float=
+  ## Computes the squared distance between `a` and `b`
+  let dx=b.x-a.x
+  let dy=b.y-a.y
+  result=dx*dx+dy*dy
+  
+proc dist*(a,b:TPoint2d):float {.inline.}=
+  ## Computes the absolute distance between `a` and `b`
+  result=sqrt(sqrDist(a,b))
+
+proc angle*(a,b:TPoint2d):float=
+  ## Computes the angle of the vector `b`-`a`
+  let dx=b.x-a.x
+  let dy=b.y-a.y
+  result=arctan2(dy,dx)
+  if result<0:
+    result += DEG360
+
+proc `$` *(p:TPoint2d):string=
+  ## String representation of `p`
+  result=rtos(p.x)
+  result.add(",")
+  result.add(rtos(p.y))
+  
+proc `&`*(p:TPoint2d,t:TMatrix2d):TPoint2d {.noInit,inline.} =
+  ## Concatenates a point `p` with a transform `t`,
+  ## resulting in a new, transformed point.
+  
+  #             | AX AY 0 |
+  # | X Y 1 | * | BX BY 0 |
+  #             | TX TY 1 |
+  result.x=p.x*t.ax+p.y*t.bx+t.tx
+  result.y=p.x*t.ay+p.y*t.by+t.ty
+
+proc `&=` *(p:var TPoint2d,t:TMatrix2d) {.inline.}=
+  ## Applies transformation `t` onto `p` in place.
+  let newx=p.x*t.ax+p.y*t.bx+t.tx
+  p.y=p.x*t.ay+p.y*t.by+t.ty
+  p.x=newx
+
+
+proc transformInv*(p:var TPoint2d,t:TMatrix2d){.inline.}=
+  ## Applies the inverse of transformation `t` onto `p` in place.
+  ## If the matrix is not invertable (determinant=0) , EDivByZero will
+  ## be raised.
+  
+  #             | AX AY 0 | ^-1
+  # | X Y 1 | * | BX BY 0 |
+  #             | TX TY 1 |
+  let d=t.determinant
+  if d==0.0:
+    raise newException(DivByZeroError,"Cannot invert a zero determinant matrix")
+  let 
+    newx= (t.bx*t.ty-t.by*t.tx+p.x*t.by-p.y*t.bx)/d
+  p.y = -(t.ax*t.ty-t.ay*t.tx+p.x*t.ay-p.y*t.ax)/d
+  p.x=newx
+  
+  
+proc `+`*(p:TPoint2d,v:TVector2d):TPoint2d {.noInit,inline.} =
+  ## Adds a vector `v` to a point `p`, resulting 
+  ## in a new point.
+  result.x=p.x+v.x
+  result.y=p.y+v.y
+
+proc `+=`*(p:var TPoint2d,v:TVector2d) {.noInit,inline.} =
+  ## Adds a vector `v` to a point `p` in place.
+  p.x+=v.x
+  p.y+=v.y
+
+proc `-`*(p:TPoint2d,v:TVector2d):TPoint2d {.noInit,inline.} =
+  ## Subtracts a vector `v` from a point `p`, resulting 
+  ## in a new point.
+  result.x=p.x-v.x
+  result.y=p.y-v.y
+
+proc `-`*(p1,p2:TPoint2d):TVector2d {.noInit,inline.} =
+  ## Subtracts `p2`from `p1` resulting in a difference vector.
+  result.x=p1.x-p2.x
+  result.y=p1.y-p2.y
+
+proc `-=`*(p:var TPoint2d,v:TVector2d) {.noInit,inline.} =
+  ## Subtracts a vector `v` from a point `p` in place.
+  p.x-=v.x
+  p.y-=v.y
+  
+proc equals(p1,p2:TPoint2d,tol=1.0e-6):bool {.inline.}=
+  ## Checks if two points approximately equals with a tolerance.
+  return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol
+
+proc `=~`*(p1,p2:TPoint2d):bool {.inline.}=
+  ## Checks if two vectors approximately equals with a 
+  ## hardcoded tolerance 1e-6
+  equals(p1,p2)
+
+proc polar*(p:TPoint2d,ang,dist:float):TPoint2d {.noInit.} =
+  ## Returns a point with a given angle and distance away from `p`
+  result.x=p.x+cos(ang)*dist
+  result.y=p.y+sin(ang)*dist
+
+proc rotate*(p:var TPoint2d,rad:float)=
+  ## Rotates a point in place `rad` radians around origo.
+  let
+    c=cos(rad)
+    s=sin(rad)
+    newx=p.x*c-p.y*s
+  p.y=p.y*c+p.x*s
+  p.x=newx
+    
+proc rotate*(p:var TPoint2d,rad:float,org:TPoint2d)=
+  ## Rotates a point in place `rad` radians using `org` as
+  ## center of rotation.
+  let
+    c=cos(rad)
+    s=sin(rad)
+    newx=(p.x - org.x) * c - (p.y - org.y) * s + org.x
+  p.y=(p.y - org.y) * c + (p.x - org.x) * s + org.y
+  p.x=newx
+  
+proc scale*(p:var TPoint2d,fac:float) {.inline.}=
+  ## Scales a point in place `fac` times with world origo as origin.
+  p.x*=fac
+  p.y*=fac
+  
+proc scale*(p:var TPoint2d,fac:float,org:TPoint2d){.inline.}=
+  ## Scales the point in place `fac` times with `org` as origin.
+  p.x=(p.x - org.x) * fac + org.x
+  p.y=(p.y - org.y) * fac + org.y
+
+proc stretch*(p:var TPoint2d,facx,facy:float){.inline.}=
+  ## Scales a point in place non uniformly `facx` and `facy` times with 
+  ## world origo as origin.
+  p.x*=facx
+  p.y*=facy
+
+proc stretch*(p:var TPoint2d,facx,facy:float,org:TPoint2d){.inline.}=
+  ## Scales the point in place non uniformly `facx` and `facy` times with 
+  ## `org` as origin.
+  p.x=(p.x - org.x) * facx + org.x
+  p.y=(p.y - org.y) * facy + org.y
+
+proc move*(p:var TPoint2d,dx,dy:float){.inline.}=
+  ## Translates a point `dx`, `dy` in place.
+  p.x+=dx
+  p.y+=dy
+
+proc move*(p:var TPoint2d,v:TVector2d){.inline.}=
+  ## Translates a point with vector `v` in place.
+  p.x+=v.x
+  p.y+=v.y
+
+proc sgnArea*(a,b,c:TPoint2d):float=
+  ## Computes the signed area of the triangle thru points `a`,`b` and `c`
+  ## result>0.0 for counter clockwise triangle
+  ## result<0.0 for clockwise triangle
+  ## This is commonly used to determinate side of a point with respect to a line.
+  return ((b.x - c.x) * (b.y - a.y)-(b.y - c.y) * (b.x - a.x))*0.5
+
+proc area*(a,b,c:TPoint2d):float=
+  ## Computes the area of the triangle thru points `a`,`b` and `c`
+  return abs(sgnArea(a,b,c))
+
+proc closestPoint*(p:TPoint2d,pts:varargs[TPoint2d]):TPoint2d=
+  ## Returns a point selected from `pts`, that has the closest 
+  ## euclidean distance to `p`
+  assert(pts.len>0) # must have at least one point
+  
+  var 
+    bestidx=0
+    bestdist=p.sqrDist(pts[0])
+    curdist:float
+    
+  for idx in 1..high(pts):
+    curdist=p.sqrDist(pts[idx])
+    if curdist<bestdist:
+      bestidx=idx
+      bestdist=curdist
+  
+  result=pts[bestidx]
+
+
+# ***************************************
+#     Misc. math utilities that should
+#     probably be in another module.
+# ***************************************
+proc normAngle*(ang:float):float=
+  ## Returns an angle in radians, that is equal to `ang`,
+  ## but in the range 0 to <2*PI
+  if ang>=0.0 and ang<DEG360:
+    return ang
+
+  return ang mod DEG360
+  
+proc degToRad*(deg:float):float {.inline.}=
+  ## converts `deg` degrees to radians
+  deg / RAD2DEGCONST
+
+proc radToDeg*(rad:float):float {.inline.}=
+  ## converts `rad` radians to degrees
+  rad * RAD2DEGCONST
+
+  
diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim
new file mode 100644
index 000000000..5a943dd05
--- /dev/null
+++ b/lib/pure/basic3d.nim
@@ -0,0 +1,1040 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Robert Persson
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import math
+import strutils
+import times
+
+
+## Basic 3d support with vectors, points, matrices and some basic utilities.
+## Vectors are implemented as direction vectors, ie. when transformed with a matrix
+## the translation part of matrix is ignored. The coordinate system used is
+## right handed, because its compatible with 2d coordinate system (rotation around
+## zaxis equals 2d rotation).
+## Operators `+` , `-` , `*` , `/` , `+=` , `-=` , `*=` and `/=` are implemented
+## for vectors and scalars.
+##
+##
+## Quick start example:
+##
+##   # Create a matrix which first rotates, then scales and at last translates
+##
+##   var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
+##
+##   # Create a 3d point at (100,150,200) and a vector (5,2,3)
+##
+##   var pt:TPoint3d=point3d(100.0,150.0,200.0)
+##
+##   var vec:TVector3d=vector3d(5.0,2.0,3.0)
+##
+##
+##   pt &= m # transforms pt in place
+##
+##   var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
+##
+##   var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
+
+
+
+type
+  TMatrix3d* =object
+    ## Implements a row major 3d matrix, which means
+    ## transformations are applied the order they are concatenated.
+    ## This matrix is stored as an 4x4 matrix:
+    ## [ ax ay az aw ]
+    ## [ bx by bz bw ]
+    ## [ cx cy cz cw ]
+    ## [ tx ty tz tw ]
+    ax*,ay*,az*,aw*,  bx*,by*,bz*,bw*,  cx*,cy*,cz*,cw*,  tx*,ty*,tz*,tw*:float
+  TPoint3d* = object
+    ## Implements a non-homegeneous 2d point stored as
+    ## an `x` , `y` and `z` coordinate.
+    x*,y*,z*:float
+  TVector3d* = object
+    ## Implements a 3d **direction vector** stored as
+    ## an `x` , `y` and `z` coordinate. Direction vector means,
+    ## that when transforming a vector with a matrix, the translational
+    ## part of the matrix is ignored.
+    x*,y*,z*:float
+
+
+
+# Some forward declarations
+proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
+  ## Creates a new 4x4 3d transformation matrix.
+  ## `ax` , `ay` , `az` is the local x axis.
+  ## `bx` , `by` , `bz` is the local y axis.
+  ## `cx` , `cy` , `cz` is the local z axis.
+  ## `tx` , `ty` , `tz` is the translation.
+proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
+  ## Returns a new 3d vector (`x`,`y`,`z`)
+proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
+  ## Returns a new 4d point (`x`,`y`,`z`)
+proc tryNormalize*(v:var TVector3d):bool
+  ## Modifies `v` to have a length of 1.0, keeping its angle.
+  ## If `v` has zero length (and thus no angle), it is left unmodified and false is
+  ## returned, otherwise true is returned.
+
+
+
+let
+  IDMATRIX*:TMatrix3d=matrix3d(
+    1.0,0.0,0.0,0.0,
+    0.0,1.0,0.0,0.0,
+    0.0,0.0,1.0,0.0,
+    0.0,0.0,0.0,1.0)
+    ## Quick access to a 3d identity matrix
+  ORIGO*:TPoint3d=point3d(0.0,0.0,0.0)
+    ## Quick access to point (0,0)
+  XAXIS*:TVector3d=vector3d(1.0,0.0,0.0)
+    ## Quick access to an 3d x-axis unit vector
+  YAXIS*:TVector3d=vector3d(0.0,1.0,0.0)
+    ## Quick access to an 3d y-axis unit vector
+  ZAXIS*:TVector3d=vector3d(0.0,0.0,1.0)
+    ## Quick access to an 3d z-axis unit vector
+
+
+
+# ***************************************
+#     Private utils
+# ***************************************
+
+proc rtos(val:float):string=
+  return formatFloat(val,ffDefault,0)
+
+proc safeArccos(v:float):float=
+  ## assumes v is in range 0.0-1.0, but clamps
+  ## the value to avoid out of domain errors
+  ## due to rounding issues
+  return arccos(clamp(v,-1.0,1.0))
+
+template makeBinOpVector(s:expr)=
+  ## implements binary operators + , - , * and / for vectors
+  proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
+    vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
+  proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.}  =
+    vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
+  proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.}  =
+    vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
+
+template makeBinOpAssignVector(s:expr)=
+  ## implements inplace binary operators += , -= , /= and *= for vectors
+  proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
+    s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
+  proc s*(a:var TVector3d,b:float) {.inline.} =
+    s(a.x,b) ; s(a.y,b) ; s(a.z,b)
+
+
+
+# ***************************************
+#     TMatrix3d implementation
+# ***************************************
+
+proc setElements*(t:var TMatrix3d,ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float) {.inline.}=
+  ## Sets arbitrary elements in an exisitng matrix.
+  t.ax=ax
+  t.ay=ay
+  t.az=az
+  t.aw=aw
+  t.bx=bx
+  t.by=by
+  t.bz=bz
+  t.bw=bw
+  t.cx=cx
+  t.cy=cy
+  t.cz=cz
+  t.cw=cw
+  t.tx=tx
+  t.ty=ty
+  t.tz=tz
+  t.tw=tw
+
+proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d =
+  result.setElements(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw)
+
+proc `&`*(a,b:TMatrix3d):TMatrix3d {.noinit.} =
+  ## Concatenates matrices returning a new matrix.
+  result.setElements(
+    a.aw*b.tx+a.az*b.cx+a.ay*b.bx+a.ax*b.ax,
+    a.aw*b.ty+a.az*b.cy+a.ay*b.by+a.ax*b.ay,
+    a.aw*b.tz+a.az*b.cz+a.ay*b.bz+a.ax*b.az,
+    a.aw*b.tw+a.az*b.cw+a.ay*b.bw+a.ax*b.aw,
+
+    a.bw*b.tx+a.bz*b.cx+a.by*b.bx+a.bx*b.ax,
+    a.bw*b.ty+a.bz*b.cy+a.by*b.by+a.bx*b.ay,
+    a.bw*b.tz+a.bz*b.cz+a.by*b.bz+a.bx*b.az,
+    a.bw*b.tw+a.bz*b.cw+a.by*b.bw+a.bx*b.aw,
+
+    a.cw*b.tx+a.cz*b.cx+a.cy*b.bx+a.cx*b.ax,
+    a.cw*b.ty+a.cz*b.cy+a.cy*b.by+a.cx*b.ay,
+    a.cw*b.tz+a.cz*b.cz+a.cy*b.bz+a.cx*b.az,
+    a.cw*b.tw+a.cz*b.cw+a.cy*b.bw+a.cx*b.aw,
+
+    a.tw*b.tx+a.tz*b.cx+a.ty*b.bx+a.tx*b.ax,
+    a.tw*b.ty+a.tz*b.cy+a.ty*b.by+a.tx*b.ay,
+    a.tw*b.tz+a.tz*b.cz+a.ty*b.bz+a.tx*b.az,
+    a.tw*b.tw+a.tz*b.cw+a.ty*b.bw+a.tx*b.aw)
+
+
+proc scale*(s:float):TMatrix3d {.noInit.} =
+  ## Returns a new scaling matrix.
+  result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0, 0,0,0,1)
+
+proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
+  ## Returns a new scaling matrix using, `org` as scale origin.
+  result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
+    org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
+
+proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
+  ## Returns new a stretch matrix, which is a
+  ## scale matrix with non uniform scale in x,y and z.
+  result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
+
+proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
+  ## Returns a new stretch matrix, which is a
+  ## scale matrix with non uniform scale in x,y and z.
+  ## `org` is used as stretch origin.
+  result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
+
+proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
+  ## Returns a new translation matrix.
+  result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
+
+proc move*(v:TVector3d):TMatrix3d {.noInit.} =
+  ## Returns a new translation matrix from a vector.
+  result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, v.x,v.y,v.z,1)
+
+
+proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
+  ## Creates a rotation matrix that rotates `angle` radians over
+  ## `axis`, which passes through origo.
+
+  # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
+  # for how this is computed
+
+  var normax=axis
+  if not normax.tryNormalize: #simplifies matrix computation below a lot
+    raise newException(DivByZeroError,"Cannot rotate around zero length axis")
+
+  let
+    cs=cos(angle)
+    si=sin(angle)
+    omc=1.0-cs
+    usi=normax.x*si
+    vsi=normax.y*si
+    wsi=normax.z*si
+    u2=normax.x*normax.x
+    v2=normax.y*normax.y
+    w2=normax.z*normax.z
+    uvomc=normax.x*normax.y*omc
+    uwomc=normax.x*normax.z*omc
+    vwomc=normax.y*normax.z*omc
+
+  result.setElements(
+    u2+(1.0-u2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
+    uvomc-wsi, v2+(1.0-v2)*cs, vwomc+usi, 0.0,
+    uwomc+vsi, vwomc-usi, w2+(1.0-w2)*cs, 0.0,
+    0.0,0.0,0.0,1.0)
+
+proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
+  ## Creates a rotation matrix that rotates `angle` radians over
+  ## `axis`, which passes through `org`.
+
+  # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
+  # for how this is computed
+
+  var normax=axis
+  if not normax.tryNormalize: #simplifies matrix computation below a lot
+    raise newException(DivByZeroError,"Cannot rotate around zero length axis")
+
+  let
+    u=normax.x
+    v=normax.y
+    w=normax.z
+    u2=u*u
+    v2=v*v
+    w2=w*w
+    cs=cos(angle)
+    omc=1.0-cs
+    si=sin(angle)
+    a=org.x
+    b=org.y
+    c=org.z
+    usi=u*si
+    vsi=v*si
+    wsi=w*si
+    uvomc=normax.x*normax.y*omc
+    uwomc=normax.x*normax.z*omc
+    vwomc=normax.y*normax.z*omc
+
+  result.setElements(
+    u2+(v2+w2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
+    uvomc-wsi, v2+(u2+w2)*cs, vwomc+usi, 0.0,
+    uwomc+vsi, vwomc-usi, w2+(u2+v2)*cs, 0.0,
+    (a*(v2+w2)-u*(b*v+c*w))*omc+(b*w-c*v)*si,
+    (b*(u2+w2)-v*(a*u+c*w))*omc+(c*u-a*w)*si,
+    (c*(u2+v2)-w*(a*u+b*v))*omc+(a*v-b*u)*si,1.0)
+
+
+proc rotateX*(angle:float):TMatrix3d {.noInit.}=
+  ## Creates a matrix that rotates around the x-axis with `angle` radians,
+  ## which is also called a 'roll' matrix.
+  let
+    c=cos(angle)
+    s=sin(angle)
+  result.setElements(
+    1,0,0,0,
+    0,c,s,0,
+    0,-s,c,0,
+    0,0,0,1)
+
+proc rotateY*(angle:float):TMatrix3d {.noInit.}=
+  ## Creates a matrix that rotates around the y-axis with `angle` radians,
+  ## which is also called a 'pitch' matrix.
+  let
+    c=cos(angle)
+    s=sin(angle)
+  result.setElements(
+    c,0,-s,0,
+    0,1,0,0,
+    s,0,c,0,
+    0,0,0,1)
+
+proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
+  ## Creates a matrix that rotates around the z-axis with `angle` radians,
+  ## which is also called a 'yaw' matrix.
+  let
+    c=cos(angle)
+    s=sin(angle)
+  result.setElements(
+    c,s,0,0,
+    -s,c,0,0,
+    0,0,1,0,
+    0,0,0,1)
+
+proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
+  ## Checks if the transform is uniform, that is
+  ## perpendicular axes of equal length, which means (for example)
+  ## it cannot transform a sphere into an ellipsoid.
+  ## `tol` is used as tolerance for both equal length comparison
+  ## and perpendicular comparison.
+
+  #dot product=0 means perpendicular coord. system, check xaxis vs yaxis and  xaxis vs zaxis
+  if abs(m.ax*m.bx+m.ay*m.by+m.az*m.bz)<=tol and # x vs y
+    abs(m.ax*m.cx+m.ay*m.cy+m.az*m.cz)<=tol and #x vs z
+    abs(m.bx*m.cx+m.by*m.cy+m.bz*m.cz)<=tol: #y vs z
+
+    #subtract squared lengths of axes to check if uniform scaling:
+    let
+      sqxlen=(m.ax*m.ax+m.ay*m.ay+m.az*m.az)
+      sqylen=(m.bx*m.bx+m.by*m.by+m.bz*m.bz)
+      sqzlen=(m.cx*m.cx+m.cy*m.cy+m.cz*m.cz)
+    if abs(sqxlen-sqylen)<=tol and abs(sqxlen-sqzlen)<=tol:
+      return true
+  return false
+
+
+
+proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
+  ## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
+  ## and passes through origo. `planeperp` does not need to be normalized.
+
+  # https://en.wikipedia.org/wiki/Transformation_matrix
+  var n=planeperp
+  if not n.tryNormalize:
+    raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
+
+  let
+    a=n.x
+    b=n.y
+    c=n.z
+    ab=a*b
+    ac=a*c
+    bc=b*c
+
+  result.setElements(
+    1-2*a*a , -2*ab,-2*ac,0,
+    -2*ab , 1-2*b*b, -2*bc, 0,
+    -2*ac, -2*bc, 1-2*c*c,0,
+    0,0,0,1)
+
+
+proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
+  ## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
+  ## and passes through `org`. `planeperp` does not need to be normalized.
+
+  # constructs a mirror M like the simpler mirror matrix constructor
+  # above but premultiplies with the inverse traslation of org
+  # and postmultiplies with the translation of org.
+  # With some fiddling this becomes reasonably simple:
+  var n=planeperp
+  if not n.tryNormalize:
+    raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
+
+  let
+    a=n.x
+    b=n.y
+    c=n.z
+    ab=a*b
+    ac=a*c
+    bc=b*c
+    aa=a*a
+    bb=b*b
+    cc=c*c
+    tx=org.x
+    ty=org.y
+    tz=org.z
+
+  result.setElements(
+    1-2*aa , -2*ab,-2*ac,0,
+    -2*ab , 1-2*bb, -2*bc, 0,
+    -2*ac, -2*bc, 1-2*cc,0,
+    2*(ac*tz+ab*ty+aa*tx),
+    2*(bc*tz+bb*ty+ab*tx),
+    2*(cc*tz+bc*ty+ac*tx) ,1)
+
+
+proc determinant*(m:TMatrix3d):float=
+  ## Computes the determinant of matrix `m`.
+
+  # This computation is gotten from ratsimp(optimize(determinant(m)))
+  # in maxima CAS
+  let
+    O1=m.cx*m.tw-m.cw*m.tx
+    O2=m.cy*m.tw-m.cw*m.ty
+    O3=m.cx*m.ty-m.cy*m.tx
+    O4=m.cz*m.tw-m.cw*m.tz
+    O5=m.cx*m.tz-m.cz*m.tx
+    O6=m.cy*m.tz-m.cz*m.ty
+
+  return (O1*m.ay-O2*m.ax-O3*m.aw)*m.bz+
+    (-O1*m.az+O4*m.ax+O5*m.aw)*m.by+
+    (O2*m.az-O4*m.ay-O6*m.aw)*m.bx+
+    (O3*m.az-O5*m.ay+O6*m.ax)*m.bw
+
+
+proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
+  ## Computes the inverse of matrix `m`. If the matrix
+  ## determinant is zero, thus not invertible, a EDivByZero
+  ## will be raised.
+
+  # this computation comes from optimize(invert(m)) in maxima CAS
+
+  let
+    det=m.determinant
+    O2=m.cy*m.tw-m.cw*m.ty
+    O3=m.cz*m.tw-m.cw*m.tz
+    O4=m.cy*m.tz-m.cz*m.ty
+    O5=m.by*m.tw-m.bw*m.ty
+    O6=m.bz*m.tw-m.bw*m.tz
+    O7=m.by*m.tz-m.bz*m.ty
+    O8=m.by*m.cw-m.bw*m.cy
+    O9=m.bz*m.cw-m.bw*m.cz
+    O10=m.by*m.cz-m.bz*m.cy
+    O11=m.cx*m.tw-m.cw*m.tx
+    O12=m.cx*m.tz-m.cz*m.tx
+    O13=m.bx*m.tw-m.bw*m.tx
+    O14=m.bx*m.tz-m.bz*m.tx
+    O15=m.bx*m.cw-m.bw*m.cx
+    O16=m.bx*m.cz-m.bz*m.cx
+    O17=m.cx*m.ty-m.cy*m.tx
+    O18=m.bx*m.ty-m.by*m.tx
+    O19=m.bx*m.cy-m.by*m.cx
+
+  if det==0.0:
+    raise newException(DivByZeroError,"Cannot normalize zero length vector")
+
+  result.setElements(
+    (m.bw*O4+m.by*O3-m.bz*O2)/det    , (-m.aw*O4-m.ay*O3+m.az*O2)/det,
+    (m.aw*O7+m.ay*O6-m.az*O5)/det    , (-m.aw*O10-m.ay*O9+m.az*O8)/det,
+    (-m.bw*O12-m.bx*O3+m.bz*O11)/det , (m.aw*O12+m.ax*O3-m.az*O11)/det,
+    (-m.aw*O14-m.ax*O6+m.az*O13)/det , (m.aw*O16+m.ax*O9-m.az*O15)/det,
+    (m.bw*O17+m.bx*O2-m.by*O11)/det  , (-m.aw*O17-m.ax*O2+m.ay*O11)/det,
+    (m.aw*O18+m.ax*O5-m.ay*O13)/det  , (-m.aw*O19-m.ax*O8+m.ay*O15)/det,
+    (-m.bx*O4+m.by*O12-m.bz*O17)/det , (m.ax*O4-m.ay*O12+m.az*O17)/det,
+    (-m.ax*O7+m.ay*O14-m.az*O18)/det , (m.ax*O10-m.ay*O16+m.az*O19)/det)
+
+
+proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
+  ## Checks if all elements of `m1`and `m2` is equal within
+  ## a given tolerance `tol`.
+  return
+    abs(m1.ax-m2.ax)<=tol and
+    abs(m1.ay-m2.ay)<=tol and
+    abs(m1.az-m2.az)<=tol and
+    abs(m1.aw-m2.aw)<=tol and
+    abs(m1.bx-m2.bx)<=tol and
+    abs(m1.by-m2.by)<=tol and
+    abs(m1.bz-m2.bz)<=tol and
+    abs(m1.bw-m2.bw)<=tol and
+    abs(m1.cx-m2.cx)<=tol and
+    abs(m1.cy-m2.cy)<=tol and
+    abs(m1.cz-m2.cz)<=tol and
+    abs(m1.cw-m2.cw)<=tol and
+    abs(m1.tx-m2.tx)<=tol and
+    abs(m1.ty-m2.ty)<=tol and
+    abs(m1.tz-m2.tz)<=tol and
+    abs(m1.tw-m2.tw)<=tol
+
+proc `=~`*(m1,m2:TMatrix3d):bool=
+  ## Checks if `m1` and `m2` is approximately equal, using a
+  ## tolerance of 1e-6.
+  equals(m1,m2)
+
+proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
+  ## Returns the transpose of `m`
+  result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
+
+proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
+  ## Gets the local x axis of `m`
+  result.x=m.ax
+  result.y=m.ay
+  result.z=m.az
+
+proc getYAxis*(m:TMatrix3d):TVector3d {.noInit.}=
+  ## Gets the local y axis of `m`
+  result.x=m.bx
+  result.y=m.by
+  result.z=m.bz
+
+proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
+  ## Gets the local y axis of `m`
+  result.x=m.cx
+  result.y=m.cy
+  result.z=m.cz
+
+
+proc `$`*(m:TMatrix3d):string=
+  ## String representation of `m`
+  return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
+    "\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
+    "\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
+    "\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
+
+proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
+  ## Applies transformation `m` onto `x` , `y` , `z` , optionally
+  ## using the translation part of the matrix.
+  let
+    oldx=x
+    oldy=y
+    oldz=z
+
+  x=m.cx*oldz+m.bx*oldy+m.ax*oldx
+  y=m.cy*oldz+m.by*oldy+m.ay*oldx
+  z=m.cz*oldz+m.bz*oldy+m.az*oldx
+
+  if translate:
+    x+=m.tx
+    y+=m.ty
+    z+=m.tz
+
+# ***************************************
+#     TVector3d implementation
+# ***************************************
+proc vector3d*(x,y,z:float):TVector3d=
+  result.x=x
+  result.y=y
+  result.z=z
+
+proc len*(v:TVector3d):float=
+  ## Returns the length of the vector `v`.
+  sqrt(v.x*v.x+v.y*v.y+v.z*v.z)
+
+proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
+  ## Sets the length of the vector, keeping its direction.
+  ## If the vector has zero length before changing it's length,
+  ## an arbitrary vector of the requested length is returned.
+
+  let fac=newlen/v.len
+
+  if newlen==0.0:
+    v.x=0.0
+    v.y=0.0
+    v.z=0.0
+    return
+
+  if fac==Inf or fac==NegInf:
+    #to short for float accuracy
+    #do as good as possible:
+    v.x=newlen
+    v.y=0.0
+    v.z=0.0
+  else:
+    v.x*=fac
+    v.y*=fac
+    v.z*=fac
+
+
+proc sqrLen*(v:TVector3d):float {.inline.}=
+  ## Computes the squared length of the vector, which is
+  ## faster than computing the absolute length.
+  return v.x*v.x+v.y*v.y+v.z*v.z
+
+proc `$` *(v:TVector3d):string=
+  ## String representation of `v`
+  result=rtos(v.x)
+  result.add(",")
+  result.add(rtos(v.y))
+  result.add(",")
+  result.add(rtos(v.z))
+
+proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
+  ## Concatenate vector `v` with a transformation matrix.
+  ## Transforming a vector ignores the translational part
+  ## of the matrix.
+
+  #               | AX AY AZ AW |
+  # | X Y Z 1 | * | BX BY BZ BW |
+  #               | CX CY CZ CW |
+  #               | 0  0  0  1 |
+  let
+    newx=m.cx*v.z+m.bx*v.y+m.ax*v.x
+    newy=m.cy*v.z+m.by*v.y+m.ay*v.x
+  result.z=m.cz*v.z+m.bz*v.y+m.az*v.x
+  result.y=newy
+  result.x=newx
+
+
+proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
+  ## Applies transformation `m` onto `v` in place.
+  ## Transforming a vector ignores the translational part
+  ## of the matrix.
+
+  #               | AX AY AZ AW |
+  # | X Y Z 1 | * | BX BY BZ BW |
+  #               | CX CY CZ CW |
+  #               | 0  0  0  1  |
+
+  let
+    newx=m.cx*v.z+m.bx*v.y+m.ax*v.x
+    newy=m.cy*v.z+m.by*v.y+m.ay*v.x
+  v.z=m.cz*v.z+m.bz*v.y+m.az*v.x
+  v.y=newy
+  v.x=newx
+
+proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
+  ## Applies a normal direction transformation `m` onto `v` in place.
+  ## The resulting vector is *not* normalized.  Transforming a vector ignores the
+  ## translational part of the matrix. If the matrix is not invertible
+  ## (determinant=0), an EDivByZero will be raised.
+
+  # transforming a normal is done by transforming
+  # by the transpose of the inverse of the original matrix
+
+  # Major reason this simple function is here is that this function can be optimized in the future,
+  # (possibly by hardware) as well as having a consistent API with the 2d version.
+  v&=transpose(inverse(m))
+
+proc transformInv*(v:var TVector3d,m:TMatrix3d)=
+  ## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
+  ## the translational part of the matrix.  Transforming a vector ignores the
+  ## translational part of the matrix.
+  ## If the matrix is not invertible (determinant=0), an EDivByZero
+  ## will be raised.
+
+  # Major reason this simple function is here is that this function can be optimized in the future,
+  # (possibly by hardware) as well as having a consistent API with the 2d version.
+  v&=m.inverse
+
+proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
+  ## Applies an inverse normal direction transformation `m` onto `v` in place.
+  ## This is faster than creating an inverse
+  ## matrix and transformNorm(...) it. Transforming a vector ignores the
+  ## translational part of the matrix.
+
+  # see vector2d:s equivalent for a deeper look how/why this works
+  vec&=m.transpose
+
+proc tryNormalize*(v:var TVector3d):bool=
+  ## Modifies `v` to have a length of 1.0, keeping its angle.
+  ## If `v` has zero length (and thus no angle), it is left unmodified and false is
+  ## returned, otherwise true is returned.
+  let mag=v.len
+
+  if mag==0.0:
+    return false
+
+  v.x/=mag
+  v.y/=mag
+  v.z/=mag
+
+  return true
+
+proc normalize*(v:var TVector3d) {.inline.}=
+  ## Modifies `v` to have a length of 1.0, keeping its angle.
+  ## If  `v` has zero length, an EDivByZero will be raised.
+  if not tryNormalize(v):
+    raise newException(DivByZeroError,"Cannot normalize zero length vector")
+
+proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
+  ## Rotates `vec` in place, with `angle` radians over `axis`, which passes
+  ## through origo.
+
+  # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
+  # for how this is computed
+
+  var normax=axis
+  if not normax.tryNormalize:
+    raise newException(DivByZeroError,"Cannot rotate around zero length axis")
+
+  let
+    cs=cos(angle)
+    si=sin(angle)
+    omc=1.0-cs
+    u=normax.x
+    v=normax.y
+    w=normax.z
+    x=vec.x
+    y=vec.y
+    z=vec.z
+    uxyzomc=(u*x+v*y+w*z)*omc
+
+  vec.x=u*uxyzomc+x*cs+(v*z-w*y)*si
+  vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
+  vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
+
+proc scale*(v:var TVector3d,s:float)=
+  ## Scales the vector in place with factor `s`
+  v.x*=s
+  v.y*=s
+  v.z*=s
+
+proc stretch*(v:var TVector3d,sx,sy,sz:float)=
+  ## Scales the vector non uniformly with factors `sx` , `sy` , `sz`
+  v.x*=sx
+  v.y*=sy
+  v.z*=sz
+
+proc mirror*(v:var TVector3d,planeperp:TVector3d)=
+  ## Computes the mirrored vector of `v` over the plane
+  ## that has `planeperp` as normal direction.
+  ## `planeperp` does not need to be normalized.
+
+  var n=planeperp
+  n.normalize
+
+  let
+    x=v.x
+    y=v.y
+    z=v.z
+    a=n.x
+    b=n.y
+    c=n.z
+    ac=a*c
+    ab=a*b
+    bc=b*c
+
+  v.x= -2*(ac*z+ab*y+a*a*x)+x
+  v.y= -2*(bc*z+b*b*y+ab*x)+y
+  v.z= -2*(c*c*z+bc*y+ac*x)+z
+
+
+proc `-` *(v:TVector3d):TVector3d=
+  ## Negates a vector
+  result.x= -v.x
+  result.y= -v.y
+  result.z= -v.z
+
+# declare templated binary operators
+makeBinOpVector(`+`)
+makeBinOpVector(`-`)
+makeBinOpVector(`*`)
+makeBinOpVector(`/`)
+makeBinOpAssignVector(`+=`)
+makeBinOpAssignVector(`-=`)
+makeBinOpAssignVector(`*=`)
+makeBinOpAssignVector(`/=`)
+
+proc dot*(v1,v2:TVector3d):float {.inline.}=
+  ## Computes the dot product of two vectors.
+  ## Returns 0.0 if the vectors are perpendicular.
+  return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
+
+proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
+  ## Computes the cross product of two vectors.
+  ## The result is a vector which is perpendicular
+  ## to the plane of `v1` and `v2`, which means
+  ## cross(xaxis,yaxis)=zaxis. The magnitude of the result is
+  ## zero if the vectors are colinear.
+  result.x = (v1.y * v2.z) - (v2.y * v1.z)
+  result.y = (v1.z * v2.x) - (v2.z * v1.x)
+  result.z = (v1.x * v2.y) - (v2.x * v1.y)
+
+proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
+  ## Checks if two vectors approximately equals with a tolerance.
+  return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
+
+proc `=~` *(v1,v2:TVector3d):bool=
+  ## Checks if two vectors approximately equals with a
+  ## hardcoded tolerance 1e-6
+  equals(v1,v2)
+
+proc angleTo*(v1,v2:TVector3d):float=
+  ## Returns the smallest angle between v1 and v2,
+  ## which is in range 0-PI
+  var
+    nv1=v1
+    nv2=v2
+  if not nv1.tryNormalize or not nv2.tryNormalize:
+    return 0.0 # zero length vector has zero angle to any other vector
+  return safeArccos(dot(nv1,nv2))
+
+proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
+  ## Computes the rotation matrix that would transform
+  ## world z vector into `norm`. The inverse of this matrix
+  ## is useful to transform a planar 3d object to 2d space.
+  ## This is the same algorithm used to interpret DXF and DWG files.
+  const lim=1.0/64.0
+  var ax,ay,az:TVector3d
+  if abs(norm.x)<lim and abs(norm.y)<lim:
+    ax=cross(YAXIS,norm)
+  else:
+    ax=cross(ZAXIS,norm)
+
+  ax.normalize()
+  ay=cross(norm,ax)
+  ay.normalize()
+  az=cross(ax,ay)
+
+  result.setElements(
+    ax.x,ax.y,ax.z,0.0,
+    ay.x,ay.y,ay.z,0.0,
+    az.x,az.y,az.z,0.0,
+    0.0,0.0,0.0,1.0)
+
+proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
+  ## Computes the bisector between v1 and v2 as a normalized vector.
+  ## If one of the input vectors has zero length, a normalized version
+  ## of the other is returned. If both input vectors has zero length,
+  ## an arbitrary normalized vector `v1` is returned.
+  var
+    vmag1=v1.len
+    vmag2=v2.len
+
+  # zero length vector equals arbitrary vector, just change
+  # magnitude to one to avoid zero division
+  if vmag1==0.0:
+    if vmag2==0: #both are zero length return any normalized vector
+      return XAXIS
+    vmag1=1.0
+  if vmag2==0.0: vmag2=1.0
+
+  let
+    x1=v1.x/vmag1
+    y1=v1.y/vmag1
+    z1=v1.z/vmag1
+    x2=v2.x/vmag2
+    y2=v2.y/vmag2
+    z2=v2.z/vmag2
+
+  result.x=(x1 + x2) * 0.5
+  result.y=(y1 + y2) * 0.5
+  result.z=(z1 + z2) * 0.5
+
+  if not result.tryNormalize():
+    # This can happen if vectors are colinear. In this special case
+    # there are actually inifinitely many bisectors, we select just
+    # one of them.
+    result=v1.cross(XAXIS)
+    if result.sqrLen<1.0e-9:
+      result=v1.cross(YAXIS)
+      if result.sqrLen<1.0e-9:
+        result=v1.cross(ZAXIS) # now we should be guaranteed to have succeeded
+    result.normalize
+
+
+
+# ***************************************
+#     TPoint3d implementation
+# ***************************************
+proc point3d*(x,y,z:float):TPoint3d=
+  result.x=x
+  result.y=y
+  result.z=z
+
+proc sqrDist*(a,b:TPoint3d):float=
+  ## Computes the squared distance between `a`and `b`
+  let dx=b.x-a.x
+  let dy=b.y-a.y
+  let dz=b.z-a.z
+  result=dx*dx+dy*dy+dz*dz
+
+proc dist*(a,b:TPoint3d):float {.inline.}=
+  ## Computes the absolute distance between `a`and `b`
+  result=sqrt(sqrDist(a,b))
+
+proc `$` *(p:TPoint3d):string=
+  ## String representation of `p`
+  result=rtos(p.x)
+  result.add(",")
+  result.add(rtos(p.y))
+  result.add(",")
+  result.add(rtos(p.z))
+
+proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
+  ## Concatenates a point `p` with a transform `m`,
+  ## resulting in a new, transformed point.
+  result.z=m.cz*p.z+m.bz*p.y+m.az*p.x+m.tz
+  result.y=m.cy*p.z+m.by*p.y+m.ay*p.x+m.ty
+  result.x=m.cx*p.z+m.bx*p.y+m.ax*p.x+m.tx
+
+proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
+  ## Applies transformation `m` onto `p` in place.
+  let
+    x=p.x
+    y=p.y
+    z=p.z
+  p.x=m.cx*z+m.bx*y+m.ax*x+m.tx
+  p.y=m.cy*z+m.by*y+m.ay*x+m.ty
+  p.z=m.cz*z+m.bz*y+m.az*x+m.tz
+
+proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
+  ## Applies the inverse of transformation `m` onto `p` in place.
+  ## If the matrix is not invertable (determinant=0) , EDivByZero will
+  ## be raised.
+
+  # can possibly be more optimized in the future so use this function when possible
+  p&=inverse(m)
+
+
+proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
+  ## Adds a vector `v` to a point `p`, resulting
+  ## in a new point.
+  result.x=p.x+v.x
+  result.y=p.y+v.y
+  result.z=p.z+v.z
+
+proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
+  ## Adds a vector `v` to a point `p` in place.
+  p.x+=v.x
+  p.y+=v.y
+  p.z+=v.z
+
+proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
+  ## Subtracts a vector `v` from a point `p`, resulting
+  ## in a new point.
+  result.x=p.x-v.x
+  result.y=p.y-v.y
+  result.z=p.z-v.z
+
+proc `-`*(p1,p2:TPoint3d):TVector3d {.noInit,inline.} =
+  ## Subtracts `p2`from `p1` resulting in a difference vector.
+  result.x=p1.x-p2.x
+  result.y=p1.y-p2.y
+  result.z=p1.z-p2.z
+
+proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
+  ## Subtracts a vector `v` from a point `p` in place.
+  p.x-=v.x
+  p.y-=v.y
+  p.z-=v.z
+
+proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
+  ## Checks if two points approximately equals with a tolerance.
+  return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
+
+proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
+  ## Checks if two vectors approximately equals with a
+  ## hardcoded tolerance 1e-6
+  equals(p1,p2)
+
+proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
+  ## Rotates point `p` in place `rad` radians about an axis
+  ## passing through origo.
+
+  var v=vector3d(p.x,p.y,p.z)
+  v.rotate(rad,axis) # reuse this code here since doing the same thing and quite complicated
+  p.x=v.x
+  p.y=v.y
+  p.z=v.z
+
+proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
+  ## Rotates point `p` in place `rad` radians about an axis
+  ## passing through `org`
+
+  # see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
+  # for how this is computed
+
+  var normax=axis
+  normax.normalize
+
+  let
+    cs=cos(angle)
+    omc=1.0-cs
+    si=sin(angle)
+    u=normax.x
+    v=normax.y
+    w=normax.z
+    a=org.x
+    b=org.y
+    c=org.z
+    x=p.x
+    y=p.y
+    z=p.z
+    uu=u*u
+    vv=v*v
+    ww=w*w
+    ux=u*p.x
+    vy=v*p.y
+    wz=w*p.z
+    au=a*u
+    bv=b*v
+    cw=c*w
+    uxmvymwz=ux-vy-wz
+
+  p.x=(a*(vv+ww)-u*(bv+cw-uxmvymwz))*omc + x*cs + (b*w+v*z-c*v-w*y)*si
+  p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
+  p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
+
+proc scale*(p:var TPoint3d,fac:float) {.inline.}=
+  ## Scales a point in place `fac` times with world origo as origin.
+  p.x*=fac
+  p.y*=fac
+  p.z*=fac
+
+proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
+  ## Scales the point in place `fac` times with `org` as origin.
+  p.x=(p.x - org.x) * fac + org.x
+  p.y=(p.y - org.y) * fac + org.y
+  p.z=(p.z - org.z) * fac + org.z
+
+proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
+  ## Scales a point in place non uniformly `facx` , `facy` , `facz` times
+  ## with world origo as origin.
+  p.x*=facx
+  p.y*=facy
+  p.z*=facz
+
+proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
+  ## Scales the point in place non uniformly `facx` , `facy` , `facz` times
+  ## with `org` as origin.
+  p.x=(p.x - org.x) * facx + org.x
+  p.y=(p.y - org.y) * facy + org.y
+  p.z=(p.z - org.z) * facz + org.z
+
+
+proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
+  ## Translates a point `dx` , `dy` , `dz` in place.
+  p.x+=dx
+  p.y+=dy
+  p.z+=dz
+
+proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
+  ## Translates a point with vector `v` in place.
+  p.x+=v.x
+  p.y+=v.y
+  p.z+=v.z
+
+proc area*(a,b,c:TPoint3d):float {.inline.}=
+  ## Computes the area of the triangle thru points `a` , `b` and `c`
+
+  # The area of a planar 3d quadliteral is the magnitude of the cross
+  # product of two edge vectors. Taking this time 0.5 gives the triangle area.
+  return cross(b-a,c-a).len*0.5
+
diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim
new file mode 100644
index 000000000..c6a603318
--- /dev/null
+++ b/lib/pure/browsers.nim
@@ -0,0 +1,48 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple proc for opening URLs with the user's
+## default browser.
+
+import strutils
+
+when defined(windows):
+  import winlean
+else:
+  import os, osproc
+
+proc openDefaultBrowser*(url: string) =
+  ## opens `url` with the user's default browser. This does not block.
+  ##
+  ## Under Windows, ``ShellExecute`` is used. Under Mac OS X the ``open``
+  ## command is used. Under Unix, it is checked if ``gnome-open`` exists and
+  ## used if it does. Next attempt is ``kde-open``, then ``xdg-open``.
+  ## Otherwise the environment variable ``BROWSER`` is used to determine the
+  ## default browser to use.
+  when defined(windows):
+    when useWinUnicode:
+      var o = newWideCString("open")
+      var u = newWideCString(url)
+      discard shellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL)
+    else:
+      discard shellExecuteA(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
+  elif defined(macosx):
+    discard execShellCmd("open " & quoteShell(url))
+  else:
+    const attempts = ["gnome-open ", "kde-open ", "xdg-open "]
+    var u = quoteShell(url)
+    for a in items(attempts):
+      if execShellCmd(a & u) == 0: return
+    for b in getEnv("BROWSER").string.split(PathSep):
+      try:
+        # we use ``startProcess`` here because we don't want to block!
+        discard startProcess(command=b, args=[url], options={poUsePath})
+        return
+      except OSError:
+        discard
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
new file mode 100644
index 000000000..e8977b80b
--- /dev/null
+++ b/lib/pure/cgi.nim
@@ -0,0 +1,400 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements helper procs for CGI applications. Example:
+##
+## .. code-block:: Nim
+##
+##    import strtabs, cgi
+##
+##    # Fill the values when debugging:
+##    when debug:
+##      setTestData("name", "Klaus", "password", "123456")
+##    # read the data into `myData`
+##    var myData = readData()
+##    # check that the data's variable names are "name" or "password"
+##    validateData(myData, "name", "password")
+##    # start generating content:
+##    writeContentType()
+##    # generate content:
+##    write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
+##    write(stdout, "<html><head><title>Test</title></head><body>\n")
+##    writeln(stdout, "your name: " & myData["name"])
+##    writeln(stdout, "your password: " & myData["password"])
+##    writeln(stdout, "</body></html>")
+
+import strutils, os, strtabs, cookies
+
+proc encodeUrl*(s: string): string =
+  ## Encodes a value to be HTTP safe: This means that characters in the set
+  ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
+  ## a space is converted to ``'+'`` and every other character is encoded as
+  ## ``'%xx'`` where ``xx`` denotes its hexadecimal value.
+  result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
+  for i in 0..s.len-1:
+    case s[i]
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
+    of ' ': add(result, '+')
+    else:
+      add(result, '%')
+      add(result, toHex(ord(s[i]), 2))
+
+proc handleHexChar(c: char, x: var int) {.inline.} =
+  case c
+  of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
+  of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
+  else: assert(false)
+
+proc decodeUrl*(s: string): string =
+  ## Decodes a value from its HTTP representation: This means that a ``'+'``
+  ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
+  ## value) is converted to the character with ordinal number ``xx``, and
+  ## and every other character is carried over.
+  result = newString(s.len)
+  var i = 0
+  var j = 0
+  while i < s.len:
+    case s[i]
+    of '%':
+      var x = 0
+      handleHexChar(s[i+1], x)
+      handleHexChar(s[i+2], x)
+      inc(i, 2)
+      result[j] = chr(x)
+    of '+': result[j] = ' '
+    else: result[j] = s[i]
+    inc(i)
+    inc(j)
+  setLen(result, j)
+
+{.deprecated: [URLDecode: decodeUrl, URLEncode: encodeUrl].}
+
+proc addXmlChar(dest: var string, c: char) {.inline.} =
+  case c
+  of '&': add(dest, "&amp;")
+  of '<': add(dest, "&lt;")
+  of '>': add(dest, "&gt;")
+  of '\"': add(dest, "&quot;")
+  else: add(dest, c)
+
+proc xmlEncode*(s: string): string =
+  ## Encodes a value to be XML safe:
+  ## * ``"`` is replaced by ``&quot;``
+  ## * ``<`` is replaced by ``&lt;``
+  ## * ``>`` is replaced by ``&gt;``
+  ## * ``&`` is replaced by ``&amp;``
+  ## * every other character is carried over.
+  result = newStringOfCap(s.len + s.len shr 2)
+  for i in 0..len(s)-1: addXmlChar(result, s[i])
+
+type
+  CgiError* = object of IOError  ## exception that is raised if a CGI error occurs
+  RequestMethod* = enum  ## the used request method
+    methodNone,          ## no REQUEST_METHOD environment variable
+    methodPost,          ## query uses the POST method
+    methodGet            ## query uses the GET method
+
+{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError,
+  XMLencode: xmlEncode].}
+
+proc cgiError*(msg: string) {.noreturn.} =
+  ## raises an ECgi exception with message `msg`.
+  var e: ref CgiError
+  new(e)
+  e.msg = msg
+  raise e
+
+proc getEncodedData(allowedMethods: set[RequestMethod]): string =
+  case getEnv("REQUEST_METHOD").string
+  of "POST":
+    if methodPost notin allowedMethods:
+      cgiError("'REQUEST_METHOD' 'POST' is not supported")
+    var L = parseInt(getEnv("CONTENT_LENGTH").string)
+    result = newString(L)
+    if readBuffer(stdin, addr(result[0]), L) != L:
+      cgiError("cannot read from stdin")
+  of "GET":
+    if methodGet notin allowedMethods:
+      cgiError("'REQUEST_METHOD' 'GET' is not supported")
+    result = getEnv("QUERY_STRING").string
+  else:
+    if methodNone notin allowedMethods:
+      cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'")
+
+iterator decodeData*(data: string): tuple[key, value: TaintedString] =
+  ## Reads and decodes CGI data and yields the (name, value) pairs the
+  ## data consists of.
+  var i = 0
+  var name = ""
+  var value = ""
+  # decode everything in one pass:
+  while data[i] != '\0':
+    setLen(name, 0) # reuse memory
+    while true:
+      case data[i]
+      of '\0': break
+      of '%':
+        var x = 0
+        handleHexChar(data[i+1], x)
+        handleHexChar(data[i+2], x)
+        inc(i, 2)
+        add(name, chr(x))
+      of '+': add(name, ' ')
+      of '=', '&': break
+      else: add(name, data[i])
+      inc(i)
+    if data[i] != '=': cgiError("'=' expected")
+    inc(i) # skip '='
+    setLen(value, 0) # reuse memory
+    while true:
+      case data[i]
+      of '%':
+        var x = 0
+        handleHexChar(data[i+1], x)
+        handleHexChar(data[i+2], x)
+        inc(i, 2)
+        add(value, chr(x))
+      of '+': add(value, ' ')
+      of '&', '\0': break
+      else: add(value, data[i])
+      inc(i)
+    yield (name.TaintedString, value.TaintedString)
+    if data[i] == '&': inc(i)
+    elif data[i] == '\0': break
+    else: cgiError("'&' expected")
+
+iterator decodeData*(allowedMethods: set[RequestMethod] =
+       {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] =
+  ## Reads and decodes CGI data and yields the (name, value) pairs the
+  ## data consists of. If the client does not use a method listed in the
+  ## `allowedMethods` set, an `ECgi` exception is raised.
+  var data = getEncodedData(allowedMethods)
+  if not isNil(data):
+    for key, value in decodeData(data):
+      yield (key, value)
+
+proc readData*(allowedMethods: set[RequestMethod] =
+               {methodNone, methodPost, methodGet}): StringTableRef =
+  ## Read CGI data. If the client does not use a method listed in the
+  ## `allowedMethods` set, an `ECgi` exception is raised.
+  result = newStringTable()
+  for name, value in decodeData(allowedMethods):
+    result[name.string] = value.string
+
+proc validateData*(data: StringTableRef, validKeys: varargs[string]) =
+  ## validates data; raises `ECgi` if this fails. This checks that each variable
+  ## name of the CGI `data` occurs in the `validKeys` array.
+  for key, val in pairs(data):
+    if find(validKeys, key) < 0:
+      cgiError("unknown variable name: " & key)
+
+proc getContentLength*(): string =
+  ## returns contents of the ``CONTENT_LENGTH`` environment variable
+  return getEnv("CONTENT_LENGTH").string
+
+proc getContentType*(): string =
+  ## returns contents of the ``CONTENT_TYPE`` environment variable
+  return getEnv("CONTENT_Type").string
+
+proc getDocumentRoot*(): string =
+  ## returns contents of the ``DOCUMENT_ROOT`` environment variable
+  return getEnv("DOCUMENT_ROOT").string
+
+proc getGatewayInterface*(): string =
+  ## returns contents of the ``GATEWAY_INTERFACE`` environment variable
+  return getEnv("GATEWAY_INTERFACE").string
+
+proc getHttpAccept*(): string =
+  ## returns contents of the ``HTTP_ACCEPT`` environment variable
+  return getEnv("HTTP_ACCEPT").string
+
+proc getHttpAcceptCharset*(): string =
+  ## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable
+  return getEnv("HTTP_ACCEPT_CHARSET").string
+
+proc getHttpAcceptEncoding*(): string =
+  ## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable
+  return getEnv("HTTP_ACCEPT_ENCODING").string
+
+proc getHttpAcceptLanguage*(): string =
+  ## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable
+  return getEnv("HTTP_ACCEPT_LANGUAGE").string
+
+proc getHttpConnection*(): string =
+  ## returns contents of the ``HTTP_CONNECTION`` environment variable
+  return getEnv("HTTP_CONNECTION").string
+
+proc getHttpCookie*(): string =
+  ## returns contents of the ``HTTP_COOKIE`` environment variable
+  return getEnv("HTTP_COOKIE").string
+
+proc getHttpHost*(): string =
+  ## returns contents of the ``HTTP_HOST`` environment variable
+  return getEnv("HTTP_HOST").string
+
+proc getHttpReferer*(): string =
+  ## returns contents of the ``HTTP_REFERER`` environment variable
+  return getEnv("HTTP_REFERER").string
+
+proc getHttpUserAgent*(): string =
+  ## returns contents of the ``HTTP_USER_AGENT`` environment variable
+  return getEnv("HTTP_USER_AGENT").string
+
+proc getPathInfo*(): string =
+  ## returns contents of the ``PATH_INFO`` environment variable
+  return getEnv("PATH_INFO").string
+
+proc getPathTranslated*(): string =
+  ## returns contents of the ``PATH_TRANSLATED`` environment variable
+  return getEnv("PATH_TRANSLATED").string
+
+proc getQueryString*(): string =
+  ## returns contents of the ``QUERY_STRING`` environment variable
+  return getEnv("QUERY_STRING").string
+
+proc getRemoteAddr*(): string =
+  ## returns contents of the ``REMOTE_ADDR`` environment variable
+  return getEnv("REMOTE_ADDR").string
+
+proc getRemoteHost*(): string =
+  ## returns contents of the ``REMOTE_HOST`` environment variable
+  return getEnv("REMOTE_HOST").string
+
+proc getRemoteIdent*(): string =
+  ## returns contents of the ``REMOTE_IDENT`` environment variable
+  return getEnv("REMOTE_IDENT").string
+
+proc getRemotePort*(): string =
+  ## returns contents of the ``REMOTE_PORT`` environment variable
+  return getEnv("REMOTE_PORT").string
+
+proc getRemoteUser*(): string =
+  ## returns contents of the ``REMOTE_USER`` environment variable
+  return getEnv("REMOTE_USER").string
+
+proc getRequestMethod*(): string =
+  ## returns contents of the ``REQUEST_METHOD`` environment variable
+  return getEnv("REQUEST_METHOD").string
+
+proc getRequestURI*(): string =
+  ## returns contents of the ``REQUEST_URI`` environment variable
+  return getEnv("REQUEST_URI").string
+
+proc getScriptFilename*(): string =
+  ## returns contents of the ``SCRIPT_FILENAME`` environment variable
+  return getEnv("SCRIPT_FILENAME").string
+
+proc getScriptName*(): string =
+  ## returns contents of the ``SCRIPT_NAME`` environment variable
+  return getEnv("SCRIPT_NAME").string
+
+proc getServerAddr*(): string =
+  ## returns contents of the ``SERVER_ADDR`` environment variable
+  return getEnv("SERVER_ADDR").string
+
+proc getServerAdmin*(): string =
+  ## returns contents of the ``SERVER_ADMIN`` environment variable
+  return getEnv("SERVER_ADMIN").string
+
+proc getServerName*(): string =
+  ## returns contents of the ``SERVER_NAME`` environment variable
+  return getEnv("SERVER_NAME").string
+
+proc getServerPort*(): string =
+  ## returns contents of the ``SERVER_PORT`` environment variable
+  return getEnv("SERVER_PORT").string
+
+proc getServerProtocol*(): string =
+  ## returns contents of the ``SERVER_PROTOCOL`` environment variable
+  return getEnv("SERVER_PROTOCOL").string
+
+proc getServerSignature*(): string =
+  ## returns contents of the ``SERVER_SIGNATURE`` environment variable
+  return getEnv("SERVER_SIGNATURE").string
+
+proc getServerSoftware*(): string =
+  ## returns contents of the ``SERVER_SOFTWARE`` environment variable
+  return getEnv("SERVER_SOFTWARE").string
+
+proc setTestData*(keysvalues: varargs[string]) =
+  ## fills the appropriate environment variables to test your CGI application.
+  ## This can only simulate the 'GET' request method. `keysvalues` should
+  ## provide embedded (name, value)-pairs. Example:
+  ##
+  ## .. code-block:: Nim
+  ##    setTestData("name", "Hanz", "password", "12345")
+  putEnv("REQUEST_METHOD", "GET")
+  var i = 0
+  var query = ""
+  while i < keysvalues.len:
+    add(query, encodeUrl(keysvalues[i]))
+    add(query, '=')
+    add(query, encodeUrl(keysvalues[i+1]))
+    add(query, '&')
+    inc(i, 2)
+  putEnv("QUERY_STRING", query)
+
+proc writeContentType*() =
+  ## call this before starting to send your HTML data to `stdout`. This
+  ## implements this part of the CGI protocol:
+  ##
+  ## .. code-block:: Nim
+  ##     write(stdout, "Content-type: text/html\n\n")
+  write(stdout, "Content-type: text/html\n\n")
+
+proc resetForStacktrace() =
+  stdout.write """<!--: spam
+Content-Type: text/html
+
+<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> -->
+<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> -->
+</font> </font> </font> </script> </object> </blockquote> </pre>
+</table> </table> </table> </table> </table> </font> </font> </font>
+"""
+
+proc writeErrorMessage*(data: string) =
+  ## Tries to reset browser state and writes `data` to stdout in
+  ## <plaintext> tag.
+  resetForStacktrace()
+  # We use <plaintext> here, instead of escaping, so stacktrace can
+  # be understood by human looking at source.
+  stdout.write("<plaintext>\n")
+  stdout.write(data)
+
+proc setStackTraceStdout*() =
+  ## Makes Nim output stacktraces to stdout, instead of server log.
+  errorMessageWriter = writeErrorMessage
+
+proc setStackTraceNewLine*() {.deprecated.} =
+  ## Makes Nim output stacktraces to stdout, instead of server log.
+  ## Depracated alias for setStackTraceStdout.
+  setStackTraceStdout()
+
+proc setCookie*(name, value: string) =
+  ## Sets a cookie.
+  write(stdout, "Set-Cookie: ", name, "=", value, "\n")
+
+var
+  gcookies {.threadvar.}: StringTableRef
+
+proc getCookie*(name: string): TaintedString =
+  ## Gets a cookie. If no cookie of `name` exists, "" is returned.
+  if gcookies == nil: gcookies = parseCookies(getHttpCookie())
+  result = TaintedString(gcookies[name])
+
+proc existsCookie*(name: string): bool =
+  ## Checks if a cookie of `name` exists.
+  if gcookies == nil: gcookies = parseCookies(getHttpCookie())
+  result = hasKey(gcookies, name)
+
+when isMainModule:
+  const test1 = "abc\L+def xyz"
+  assert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
+  assert decodeUrl(encodeUrl(test1)) == test1
diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim
new file mode 100644
index 000000000..0df97c685
--- /dev/null
+++ b/lib/pure/collections/LockFreeHash.nim
@@ -0,0 +1,607 @@
+#nim c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
+
+import unsigned, math, hashes
+
+#------------------------------------------------------------------------------
+## Memory Utility Functions
+
+proc newHeap*[T](): ptr T =
+  result = cast[ptr T](alloc0(sizeof(T))) 
+
+proc copyNew*[T](x: var T): ptr T =
+  var 
+    size = sizeof(T)    
+    mem = alloc(size)  
+  copyMem(mem, x.addr, size)  
+  return cast[ptr T](mem)
+
+proc copyTo*[T](val: var T, dest: int) = 
+  copyMem(pointer(dest), val.addr, sizeof(T))    
+
+proc allocType*[T](): pointer = alloc(sizeof(T)) 
+
+proc newShared*[T](): ptr T =
+  result = cast[ptr T](allocShared0(sizeof(T))) 
+
+proc copyShared*[T](x: var T): ptr T =
+  var 
+    size = sizeof(T)    
+    mem = allocShared(size)  
+  copyMem(mem, x.addr, size)  
+  return cast[ptr T](mem)
+
+#------------------------------------------------------------------------------
+## Pointer arithmetic 
+
+proc `+`*(p: pointer, i: int): pointer {.inline.} =
+  cast[pointer](cast[int](p) + i)
+
+const
+  minTableSize = 8
+  reProbeLimit = 12
+  minCopyWork = 4096
+  intSize = sizeof(int)
+  
+
+
+when sizeof(int) == 4: # 32bit
+  type 
+    TRaw = range[0..1073741823]
+    ## The range of uint values that can be stored directly in a value slot
+    ## when on a 32 bit platform
+
+elif sizeof(int) == 8: # 64bit
+  type
+    TRaw = range[0..4611686018427387903]
+    ## The range of uint values that can be stored directly in a value slot
+    ## when on a 64 bit platform
+else: 
+  {.error: "unsupported platform".}
+  
+type  
+  TEntry = tuple
+    key: int
+    value: int
+
+  TEntryArr = ptr array[0..10_000_000, TEntry]
+  
+  PConcTable[K,V] = ptr object {.pure.}
+    len: int
+    used: int
+    active: int
+    copyIdx: int
+    copyDone: int
+    next: PConcTable[K,V]    
+    data: TEntryArr
+
+
+proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
+  expVal: int, match: bool): int 
+
+#------------------------------------------------------------------------------
+
+# Create a new table
+proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V]  =
+  let 
+    dataLen = max(nextPowerOfTwo(size), minTableSize)   
+    dataSize = dataLen*sizeof(TEntry) 
+    dataMem = allocShared0(dataSize) 
+    tableSize = 7 * intSize
+    tableMem = allocShared0(tableSize)
+    table = cast[PConcTable[K,V]](tableMem) 
+  table.len = dataLen
+  table.used = 0
+  table.active = 0
+  table.copyIdx = 0
+  table.copyDone = 0
+  table.next = nil
+  table.data = cast[TEntryArr](dataMem)
+  result = table
+
+#------------------------------------------------------------------------------  
+
+# Delete a table
+proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
+  deallocShared(tbl.data) 
+  deallocShared(tbl)
+
+#------------------------------------------------------------------------------  
+
+proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
+  table.data[i]
+
+#------------------------------------------------------------------------------
+# State flags stored in ptr
+
+
+proc pack[T](x: T): int {.inline.} =
+  result = (cast[int](x) shl 2)
+  #echo("packKey ",cast[int](x) , " -> ", result)
+
+# Pop the flags off returning a 4 byte aligned ptr to our Key or Val 
+proc pop(x: int): int  {.inline.} =
+  result = x and 0xFFFFFFFC'i32
+
+# Pop the raw value off of our Key or Val 
+proc popRaw(x: int): int  {.inline.} =
+  result = x shr 2  
+
+# Pop the flags off returning a 4 byte aligned ptr to our Key or Val 
+proc popPtr[V](x: int): ptr V  {.inline.} =
+  result = cast[ptr V](pop(x))
+  #echo("popPtr " & $x & " -> " & $cast[int](result))
+
+# Ghost (sentinel)
+# K or V is no longer valid use new table
+const Ghost = 0xFFFFFFFC
+proc isGhost(x: int): bool {.inline.} =
+  result = x == 0xFFFFFFFC  
+
+# Tombstone 
+# applied to V = K is dead 
+proc isTomb(x: int): bool {.inline.} = 
+  result = (x and 0x00000002) != 0
+
+proc setTomb(x: int): int {.inline.} =
+  result = x or 0x00000002
+
+# Prime
+# K or V is in new table copied from old  
+proc isPrime(x: int): bool {.inline.} = 
+  result = (x and 0x00000001) != 0
+
+proc setPrime(x: int): int {.inline.} =
+  result = x or 0x00000001
+
+#------------------------------------------------------------------------------  
+
+##This is for i32 only need to override for i64
+proc hashInt(x: int):int {.inline.} = 
+  var h = uint32(x) #shr 2'u32  
+  h = h xor (h shr 16'u32)
+  h *= 0x85ebca6b'u32
+  h = h xor (h shr 13'u32)
+  h *= 0xc2b2ae35'u32
+  h = h xor (h shr 16'u32)  
+  result = int(h)
+
+#------------------------------------------------------------------------------
+
+proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
+  var next = atomic_load_n(self.next.addr, ATOMIC_RELAXED)
+  #echo("next = " & $cast[int](next))
+  if next != nil:
+    #echo("A new table already exists, copy in progress")
+    return next
+  var
+    oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)     
+    newTable = newLFTable[K,V](oldLen*2)
+    success = atomic_compare_exchange_n(self.next.addr, next.addr, newTable,
+                  false, ATOMIC_RELAXED, ATOMIC_RELAXED)
+  if not success:
+    echo("someone beat us to it! delete table we just created and return his " & $cast[int](next))
+    deleteConcTable(newTable) 
+    return next     
+  else:
+    echo("Created New Table! " & $cast[int](newTable) & " Size = " & $newTable.len)
+    return newTable
+  
+
+#------------------------------------------------------------------------------
+#proc keyEQ[K](key1: ptr K, key2: ptr K): bool {.inline.} = 
+proc keyEQ[K](key1: int, key2: int): bool {.inline.} = 
+  result = false
+  when K is TRaw:
+    if key1 == key2: 
+      result = true
+  else:
+    var 
+      p1 = popPtr[K](key1)
+      p2 = popPtr[K](key2)
+    if p1 != nil and p2 != nil:  
+      if cast[int](p1) == cast[int](p2):
+        return true
+      if p1[] == p2[]:
+        return true
+
+#------------------------------------------------------------------------------
+
+#proc tableFull(self: var PConcTable[K,V]) : bool {.inline.} =
+
+
+#------------------------------------------------------------------------------
+
+proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable[K,V]): bool =
+  #echo("Copy idx " & $idx)
+  var 
+    oldVal = 0
+    oldkey = 0   
+    ok = false
+  result = false
+  #Block the key so no other threads waste time here
+  while not ok:
+    ok = atomic_compare_exchange_n(oldTbl[idx].key.addr, oldKey.addr, 
+      setTomb(oldKey), false, ATOMIC_RELAXED, ATOMIC_RELAXED)
+  #echo("oldKey was = " & $oldKey & "  set it to tomb " & $setTomb(oldKey)) 
+  #Prevent new values from appearing in the old table by priming 
+  oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
+  while not isPrime(oldVal):
+    var box = if oldVal == 0 or isTomb(oldVal) : oldVal.setTomb.setPrime 
+      else: oldVal.setPrime 
+    if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr, 
+      box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
+      if isPrime(box) and isTomb(box):     
+        return true
+      oldVal = box
+      break
+  #echo("oldVal was = ", oldVal, "  set it to prime ", box)
+  if isPrime(oldVal) and isTomb(oldVal): 
+    #when not (K is TRaw):
+    #  deallocShared(popPtr[K](oldKey)) 
+    return false
+  if isTomb(oldVal): 
+    echo("oldVal is Tomb!!!, should not happen")
+  if pop(oldVal) != 0:  
+    result = setVal(newTbl, pop(oldKey), pop(oldVal), 0, true) == 0
+  if result: 
+    #echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)    
+  else: 
+    #echo("copy slot failed")    
+  # Our copy is done so we disable the old slot
+  while not ok:
+    ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr, 
+      oldVal.setTomb.setPrime , false, ATOMIC_RELAXED, ATOMIC_RELAXED)
+  #echo("disabled old slot") 
+  #echo"---------------------" 
+
+#------------------------------------------------------------------------------
+
+proc promote[K,V](table: var PConcTable[K,V]) =
+  var
+    newData = atomic_load_n(table.next.data.addr, ATOMIC_RELAXED)
+    newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED) 
+    newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
+
+  deallocShared(table.data)
+  atomic_store_n(table.data.addr, newData, ATOMIC_RELAXED)
+  atomic_store_n(table.len.addr, newLen, ATOMIC_RELAXED)
+  atomic_store_n(table.used.addr, newUsed, ATOMIC_RELAXED)
+  atomic_store_n(table.copyIdx.addr, 0, ATOMIC_RELAXED)
+  atomic_store_n(table.copyDone.addr, 0, ATOMIC_RELAXED)
+  deallocShared(table.next)
+  atomic_store_n(table.next.addr, nil, ATOMIC_RELAXED) 
+  echo("new table swapped!")
+
+#------------------------------------------------------------------------------
+ 
+proc checkAndPromote[K,V](table: var PConcTable[K,V], workDone: int): bool =  
+  var 
+    oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
+    copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
+    ok: bool
+  result = false  
+  if workDone > 0:
+    #echo("len to copy =" & $oldLen)
+    #echo("copyDone + workDone = " & $copyDone & " + " & $workDone) 
+    while not ok:
+      ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr, 
+        copyDone + workDone, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
+    #if ok: echo("set copyDone")                 
+    # If the copy is done we can promote this table 
+    if copyDone + workDone >= oldLen:
+      # Swap new data
+      #echo("work is done!")        
+      table.promote
+      result = true
+    
+#------------------------------------------------------------------------------
+
+proc copySlotAndCheck[K,V](table: var PConcTable[K,V], idx: int):
+  PConcTable[K,V] =
+  var
+    newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
+  result = newTable  
+  if newTable != nil and copySlot(idx, table, newTable): 
+    #echo("copied a single slot, idx = " & $idx)   
+    if checkAndPromote(table, 1): return table
+  
+
+#------------------------------------------------------------------------------
+  
+proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
+  var
+    newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED)) 
+  result = newTable   
+  if newTable != nil:     
+    var 
+      oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED) 
+      copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
+      copyIdx = 0
+      work = min(oldLen, minCopyWork)
+      #panicStart = -1
+      workDone = 0
+    if copyDone < oldLen:
+      var ok: bool
+      while not ok:
+        ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr, 
+          copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
+      #echo("copy idx = ", copyIdx)  
+      for i in 0..work-1:
+        var idx = (copyIdx + i) and (oldLen - 1)        
+        if copySlot(idx, table, newTable):
+          workDone += 1
+      if workDone > 0:
+        #echo("did work ", workDone, " on thread ", cast[int](myThreadID[pointer]()))
+        if checkAndPromote(table, workDone): return table
+    # In case a thread finished all the work then got stalled before promotion 
+    if checkAndPromote(table, 0): return table
+    
+  
+
+#------------------------------------------------------------------------------
+
+proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
+  expVal: int, match: bool): int =
+  #echo("-try set- in table ", " key = ", (popPtr[K](key)[]), " val = ", val)   
+  when K is TRaw: 
+    var idx = hashInt(key)    
+  else:
+    var idx = popPtr[K](key)[].hash                
+  var    
+    nextTable: PConcTable[K,V]   
+    probes = 1
+  # spin until we find a key slot or build and jump to next table    
+  while true:     
+    idx = idx and (table.len - 1) 
+    #echo("try set idx = " & $idx & "for" & $key)
+    var
+      probedKey = 0     
+      openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr, 
+        key, false, ATOMIC_RELAXED, ATOMIC_RELAXED) 
+    if openKey:
+      if val.isTomb:
+        #echo("val was tomb, bail, no reason to set an open slot to tomb")
+        return val
+      #increment used slots 
+      #echo("found an open slot, total used = " & 
+      #$atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED))
+      discard atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED)
+      break # We found an open slot 
+    #echo("set idx ", idx, " key = ", key, " probed = ", probedKey)       
+    if keyEQ[K](probedKey, key):
+      #echo("we found the matching slot")    
+      break # We found a matching slot      
+    if (not(expVal != 0 and match)) and (probes >= reProbeLimit or key.isTomb):
+      if key.isTomb: echo("Key is Tombstone")
+      #if probes >= reProbeLimit: echo("Too much probing " & $probes)
+      #echo("try to resize")
+      #create next bigger table
+      nextTable = resize(table)
+      #help do some copying
+      #echo("help copy old table to new")       
+      nextTable = helpCopy(table)      
+      #now setVal in the new table instead
+      #echo("jumping to next table to set val")       
+      return setVal(nextTable, key, val, expVal, match)      
+    else:
+      idx += 1
+      probes += 1
+  # Done spinning for a new slot
+  var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)     
+  if val == oldVal:
+    #echo("this val is alredy in the slot") 
+    return oldVal
+  nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)  
+  if nextTable == nil and 
+    ((oldVal == 0 and 
+    (probes >= reProbeLimit or table.used / table.len > 0.8)) or
+    (isPrime(oldVal))):
+    if table.used / table.len > 0.8: echo("resize because usage ratio = " &
+      $(table.used / table.len))
+    if isPrime(oldVal): echo("old val isPrime, should be a rare mem ordering event")
+    nextTable = resize(table)
+  if nextTable != nil:
+    #echo("tomb old slot then set in new table") 
+    nextTable = copySlotAndCheck(table,idx)
+    return setVal(nextTable, key, val, expVal, match)
+  # Finally ready to add new val to table
+  while true:
+    if match and oldVal != expVal:
+      #echo("set failed, no match  oldVal= " & $oldVal & " expVal= " & $expVal)
+      return oldVal
+    if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr, 
+        val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
+      #echo("val set at table " & $cast[int](table))
+      if expVal != 0:
+        if (oldVal == 0 or isTomb(oldVal)) and not isTomb(val):
+          discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
+        elif not (oldVal == 0 or isTomb(oldVal)) and isTomb(val):
+          discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
+      if oldVal == 0 and expVal != 0:
+        return setTomb(oldVal)
+      else: return oldVal
+    if isPrime(oldVal):
+      nextTable = copySlotAndCheck(table, idx)
+      return setVal(nextTable, key, val, expVal, match)
+
+#------------------------------------------------------------------------------
+
+proc getVal[K,V](table: var PConcTable[K,V], key: int): int = 
+  #echo("-try get-  key = " & $key)
+  when K is TRaw: 
+    var idx = hashInt(key)
+  else:
+    var idx = popPtr[K](key)[].hash 
+    #echo("get idx ", idx)    
+  var    
+    probes = 0
+    val: int  
+  while true:
+    idx = idx and (table.len - 1)        
+    var 
+      newTable: PConcTable[K,V] # = atomic_load_n(table.next.addr, ATOMIC_ACQUIRE)
+      probedKey = atomic_load_n(table[idx].key.addr, ATOMIC_SEQ_CST)    
+    if keyEQ[K](probedKey, key):
+      #echo("found key after ", probes+1)
+      val = atomic_load_n(table[idx].value.addr, ATOMIC_ACQUIRE)
+      if not isPrime(val):
+        if isTomb(val):
+          #echo("val was tomb but not prime") 
+          return 0
+        else:
+          #echo("-GotIt- idx = ", idx, " key = ", key, " val ", val ) 
+          return val
+      else:
+        newTable = copySlotAndCheck(table, idx)
+        return getVal(newTable, key) 
+    else:
+      #echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )    
+      if probes >= reProbeLimit*4 or key.isTomb:
+        if newTable == nil:
+          #echo("too many probes and no new table ", key, "  ", idx )
+          return 0
+        else: 
+          newTable = helpCopy(table)
+          return getVal(newTable, key)
+      idx += 1
+      probes += 1
+
+#------------------------------------------------------------------------------
+   
+#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
+#  discard setVal(table, pack(key), pack(key), 0, false)
+
+#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
+#  discard setVal(table, pack(key), cast[int](val), 0, false)
+
+proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
+  when not (K is TRaw): 
+    var newKey = cast[int](copyShared(key))
+  else: 
+    var newKey = pack(key)
+  when not (V is TRaw): 
+    var newVal = cast[int](copyShared(val))
+  else: 
+    var newVal = pack(val)
+  var oldPtr = pop(setVal(table, newKey, newVal, 0, false))
+    #echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
+  when not (V is TRaw): 
+    if newVal != oldPtr and oldPtr != 0: 
+      deallocShared(cast[ptr V](oldPtr))
+  
+ 
+
+proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
+  when not (V is TRaw):
+    when not (K is TRaw):
+      return popPtr[V](getVal(table, cast[int](key.addr)))[]
+    else: 
+      return popPtr[V](getVal(table, pack(key)))[]
+  else:
+    when not (K is TRaw):
+      return popRaw(getVal(table, cast[int](key.addr)))
+    else: 
+      return popRaw(getVal(table, pack(key)))   
+
+
+
+
+
+
+
+
+
+    
+
+#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
+#  getVal(table, key)
+
+#proc `[]=`[K,V](table: var PConcTable[K,V], key: K, val: V): PEntry[K,V] {.inline.} =
+#  setVal(table, key, val)
+
+
+
+
+
+
+#Tests ----------------------------
+when not defined(testing) and isMainModule:
+  import locks, times, mersenne
+  
+  const 
+    numTests  = 100000
+    numThreads = 10
+
+
+    
+  type
+    TTestObj = tuple
+      thr: int      
+      f0: int
+      f1: int
+
+    TData = tuple[k: string,v: TTestObj]
+    PDataArr = array[0..numTests-1, TData]
+    Dict = PConcTable[string,TTestObj]
+    
+  var 
+    thr: array[0..numThreads-1, TThread[Dict]]
+    
+    table = newLFTable[string,TTestObj](8)        
+    rand = newMersenneTwister(2525)
+
+  proc createSampleData(len: int): PDataArr = 
+    #result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))             
+    for i in 0..len-1:
+      result[i].k = "mark" & $(i+1)
+      #echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))      
+      result[i].v.thr = 0
+      result[i].v.f0 = i+1 
+      result[i].v.f1 = 0       
+      #echo("key = " & $(i+1) & " Val ptr = " & $cast[int](result[i].v.addr))
+
+
+
+  proc threadProc(tp: Dict) {.thread.} = 
+    var t = cpuTime();     
+    for i in 1..numTests:
+      var key = "mark" & $(i)
+      var got = table.get(key)                         
+      got.thr = cast[int](myThreadID[pointer]())
+      got.f1 = got.f1 + 1                
+      table.set(key, got)
+    t = cpuTime() - t
+    echo t             
+  
+
+  var testData = createSampleData(numTests)
+
+  for i in 0..numTests-1:
+    table.set(testData[i].k, testData[i].v)
+    
+  var i = 0
+  while i < numThreads:
+    createThread(thr[i], threadProc, table)
+    i += 1
+
+  joinThreads(thr) 
+
+
+
+    
+
+  var fails = 0
+
+  for i in 0..numTests-1: 
+    var got = table.get(testData[i].k) 
+    if got.f0 != i+1 or got.f1 != numThreads:
+      fails += 1
+      echo(got)
+
+  echo("Failed read or write = ", fails)
+     
+
+  #for i in 1..numTests:
+  #  echo(i, " = ", hashInt(i) and 8191)
+
+  deleteConcTable(table)
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
new file mode 100644
index 000000000..7e3f23851
--- /dev/null
+++ b/lib/pure/collections/critbits.nim
@@ -0,0 +1,304 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a `crit bit tree`:idx: which is an efficient
+## container for a set or a mapping of strings. Based on the excellent paper
+## by Adam Langley.
+
+type
+  NodeObj[T] = object {.acyclic.}
+    byte: int ## byte index of the difference
+    otherbits: char
+    case isLeaf: bool
+    of false: child: array[0..1, ref NodeObj[T]]
+    of true: 
+      key: string
+      when T isnot void:
+        val: T
+    
+  Node[T] = ref NodeObj[T]
+  CritBitTree*[T] = object ## The crit bit tree can either be used
+                           ## as a mapping from strings to
+                           ## some type ``T`` or as a set of
+                           ## strings if ``T`` is void.
+    root: Node[T]
+    count: int
+
+{.deprecated: [TCritBitTree: CritBitTree].}
+
+proc len*[T](c: CritBitTree[T]): int =
+  ## returns the number of elements in `c` in O(1).
+  result = c.count
+
+proc rawGet[T](c: CritBitTree[T], key: string): Node[T] =
+  var it = c.root
+  while it != nil:
+    if not it.isLeaf:
+      let ch = if it.byte < key.len: key[it.byte] else: '\0'
+      let dir = (1 + (ch.ord or it.otherBits.ord)) shr 8
+      it = it.child[dir]
+    else:
+      return if it.key == key: it else: nil
+
+proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} =
+  ## returns true iff `c` contains the given `key`.
+  result = rawGet(c, key) != nil
+
+proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} =
+  ## alias for `contains`.
+  result = rawGet(c, key) != nil
+
+proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] =
+  if c.root == nil:
+    new c.root
+    c.root.isleaf = true
+    c.root.key = key
+    result = c.root
+  else:
+    var it = c.root
+    while not it.isLeaf:
+      let ch = if it.byte < key.len: key[it.byte] else: '\0'
+      let dir = (1 + (ch.ord or it.otherBits.ord)) shr 8
+      it = it.child[dir]
+    
+    var newOtherBits = 0
+    var newByte = 0
+    block blockX:
+      while newbyte < key.len:
+        if it.key[newbyte] != key[newbyte]:
+          newotherbits = it.key[newbyte].ord xor key[newbyte].ord
+          break blockX
+        inc newbyte
+      if it.key[newbyte] != '\0':
+        newotherbits = it.key[newbyte].ord
+      else:
+        return it
+    while (newOtherBits and (newOtherBits-1)) != 0:
+      newOtherBits = newOtherBits and (newOtherBits-1)
+    newOtherBits = newOtherBits xor 255
+    let ch = it.key[newByte]
+    let dir = (1 + (ord(ch) or newOtherBits)) shr 8
+    
+    var inner: Node[T]
+    new inner
+    new result
+    result.isLeaf = true
+    result.key = key
+    inner.otherBits = chr(newOtherBits)
+    inner.byte = newByte
+    inner.child[1 - dir] = result
+    
+    var wherep = addr(c.root)
+    while true:
+      var p = wherep[]
+      if p.isLeaf: break
+      if p.byte > newByte: break
+      if p.byte == newByte and p.otherBits.ord > newOtherBits: break
+      let ch = if p.byte < key.len: key[p.byte] else: '\0'
+      let dir = (1 + (ch.ord or p.otherBits.ord)) shr 8
+      wherep = addr(p.child[dir])
+    inner.child[dir] = wherep[]
+    wherep[] = inner
+  inc c.count
+
+proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool =
+  ## returns true iff `c` contains the given `key`. If the key does not exist
+  ## ``c[key] = val`` is performed.
+  let oldCount = c.count
+  var n = rawInsert(c, key)
+  result = c.count == oldCount
+  when T isnot void:
+    if not result: n.val = val
+
+proc containsOrIncl*(c: var CritBitTree[void], key: string): bool =
+  ## returns true iff `c` contains the given `key`. If the key does not exist
+  ## it is inserted into `c`.
+  let oldCount = c.count
+  var n = rawInsert(c, key)
+  result = c.count == oldCount
+
+proc incl*(c: var CritBitTree[void], key: string) =
+  ## includes `key` in `c`.
+  discard rawInsert(c, key)
+
+proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) =
+  ## puts a (key, value)-pair into `t`.
+  var n = rawInsert(c, key)
+  n.val = val
+
+proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} =
+  ## retrieves the value at ``c[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  let n = rawGet(c, key)
+  if n != nil: result = n.val
+
+proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline.} =
+  ## retrieves the value at ``c[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``KeyError`` exception is raised.
+  let n = rawGet(c, key)
+  if n != nil: result = n.val
+  else: raise newException(KeyError, "key not found: " & $key)
+
+proc excl*[T](c: var CritBitTree[T], key: string) =
+  ## removes `key` (and its associated value) from the set `c`.
+  ## If the `key` does not exist, nothing happens.
+  var p = c.root
+  var wherep = addr(c.root)
+  var whereq: ptr Node[T] = nil
+  if p == nil: return
+  var dir = 0
+  var q: Node[T]
+  while not p.isLeaf:
+    whereq = wherep
+    q = p
+    let ch = if p.byte < key.len: key[p.byte] else: '\0'
+    dir = (1 + (ch.ord or p.otherBits.ord)) shr 8
+    wherep = addr(p.child[dir])
+    p = wherep[]
+  if p.key == key:
+    # else: not in tree at all
+    if whereq == nil:
+      c.root = nil
+    else:
+      whereq[] = q.child[1 - dir]
+    dec c.count
+
+iterator leaves[T](n: Node[T]): Node[T] =
+  if n != nil:
+    # XXX actually we could compute the necessary stack size in advance:
+    # it's roughly log2(c.count).
+    var stack = @[n]
+    while stack.len > 0: 
+      var it = stack.pop
+      while not it.isLeaf:
+        stack.add(it.child[1])
+        it = it.child[0]
+        assert(it != nil)
+      yield it
+
+iterator keys*[T](c: CritBitTree[T]): string =
+  ## yields all keys in lexicographical order.
+  for x in leaves(c.root): yield x.key
+
+iterator values*[T](c: CritBitTree[T]): T =
+  ## yields all values of `c` in the lexicographical order of the
+  ## corresponding keys.
+  for x in leaves(c.root): yield x.val
+
+iterator mvalues*[T](c: var CritBitTree[T]): var T =
+  ## yields all values of `c` in the lexicographical order of the
+  ## corresponding keys. The values can be modified.
+  for x in leaves(c.root): yield x.val
+
+iterator items*[T](c: CritBitTree[T]): string =
+  ## yields all keys in lexicographical order.
+  for x in leaves(c.root): yield x.key
+
+iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] =
+  ## yields all (key, value)-pairs of `c`.
+  for x in leaves(c.root): yield (x.key, x.val)
+  
+iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] =
+  ## yields all (key, value)-pairs of `c`. The yielded values can be modified.
+  for x in leaves(c.root): yield (x.key, x.val)
+
+proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] =
+  var p = c.root
+  var top = p
+  if p != nil:
+    while not p.isLeaf:
+      var q = p
+      let ch = if p.byte < key.len: key[p.byte] else: '\0'
+      let dir = (1 + (ch.ord or p.otherBits.ord)) shr 8
+      p = p.child[dir]
+      if q.byte < key.len: top = p
+    for i in 0 .. <key.len:
+      if p.key[i] != key[i]: return
+    result = top
+
+iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string): string =
+  ## yields all keys starting with `prefix`.
+  let top = allprefixedAux(c, prefix)
+  for x in leaves(top): yield x.key
+
+iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string): string =
+  ## yields all keys starting with `prefix`.
+  let top = allprefixedAux(c, prefix)
+  for x in leaves(top): yield x.key
+
+iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): T =
+  ## yields all values of `c` starting with `prefix` of the
+  ## corresponding keys.
+  let top = allprefixedAux(c, prefix)
+  for x in leaves(top): yield x.val
+
+iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string): var T =
+  ## yields all values of `c` starting with `prefix` of the
+  ## corresponding keys. The values can be modified.
+  let top = allprefixedAux(c, prefix)
+  for x in leaves(top): yield x.val
+
+iterator pairsWithPrefix*[T](c: CritBitTree[T],
+                             prefix: string): tuple[key: string, val: T] =
+  ## yields all (key, value)-pairs of `c` starting with `prefix`.
+  let top = allprefixedAux(c, prefix)
+  for x in leaves(top): yield (x.key, x.val)
+  
+iterator mpairsWithPrefix*[T](c: var CritBitTree[T],
+                              prefix: string): tuple[key: string, val: var T] =
+  ## yields all (key, value)-pairs of `c` starting with `prefix`.
+  ## The yielded values can be modified.
+  let top = allprefixedAux(c, prefix)
+  for x in leaves(top): yield (x.key, x.val)
+
+proc `$`*[T](c: CritBitTree[T]): string =
+  ## turns `c` into a string representation. Example outputs:
+  ## ``{keyA: value, keyB: value}``, ``{:}``
+  ## If `T` is void the outputs look like:
+  ## ``{keyA, keyB}``, ``{}``.
+  if c.len == 0:
+    when T is void:
+      result = "{}"
+    else:
+      result = "{:}"
+  else:
+    # an educated guess is better than nothing:
+    when T is void:
+      const avgItemLen = 8
+    else:
+      const avgItemLen = 16
+    result = newStringOfCap(c.count * avgItemLen)
+    result.add("{")
+    for key, val in pairs(c):
+      if result.len > 1: result.add(", ")
+      result.add($key)
+      when T isnot void:
+        result.add(": ")
+        result.add($val)
+    result.add("}")
+
+when isMainModule:
+  import sequtils
+
+  var r: CritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+
+  doAssert r.contains"def"
+
+  r.excl "def"
+
+  assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
+
+  assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
new file mode 100644
index 000000000..25f6616a6
--- /dev/null
+++ b/lib/pure/collections/intsets.nim
@@ -0,0 +1,218 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The ``intsets`` module implements an efficient int set implemented as a
+## `sparse bit set`:idx:.
+## **Note**: Since Nim currently does not allow the assignment operator to
+## be overloaded, ``=`` for int sets performs some rather meaningless shallow
+## copy; use ``assign`` to get a deep copy.
+
+import
+  hashes, math
+
+type
+  BitScalar = int
+
+const
+  InitIntSetSize = 8         # must be a power of two!
+  TrunkShift = 9
+  BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and
+                                  # divisible by 64
+  TrunkMask = BitsPerTrunk - 1
+  IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8)
+  IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width
+  IntMask = 1 shl IntShift - 1
+
+type
+  PTrunk = ref TTrunk
+  TTrunk {.final.} = object
+    next: PTrunk             # all nodes are connected with this pointer
+    key: int                 # start address at bit 0
+    bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector
+
+  TTrunkSeq = seq[PTrunk]
+  IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set
+    counter, max: int
+    head: PTrunk
+    data: TTrunkSeq
+
+{.deprecated: [TIntSet: IntSet].}
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+proc intSetGet(t: IntSet, key: int): PTrunk =
+  var h = key and t.max
+  while t.data[h] != nil:
+    if t.data[h].key == key:
+      return t.data[h]
+    h = nextTry(h, t.max)
+  result = nil
+
+proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) =
+  var h = desc.key and t.max
+  while data[h] != nil:
+    assert(data[h] != desc)
+    h = nextTry(h, t.max)
+  assert(data[h] == nil)
+  data[h] = desc
+
+proc intSetEnlarge(t: var IntSet) =
+  var n: TTrunkSeq
+  var oldMax = t.max
+  t.max = ((t.max + 1) * 2) - 1
+  newSeq(n, t.max + 1)
+  for i in countup(0, oldMax):
+    if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
+  swap(t.data, n)
+
+proc intSetPut(t: var IntSet, key: int): PTrunk =
+  var h = key and t.max
+  while t.data[h] != nil:
+    if t.data[h].key == key:
+      return t.data[h]
+    h = nextTry(h, t.max)
+  if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
+  inc(t.counter)
+  h = key and t.max
+  while t.data[h] != nil: h = nextTry(h, t.max)
+  assert(t.data[h] == nil)
+  new(result)
+  result.next = t.head
+  result.key = key
+  t.head = result
+  t.data[h] = result
+
+proc contains*(s: IntSet, key: int): bool =
+  ## returns true iff `key` is in `s`.
+  var t = intSetGet(s, `shr`(key, TrunkShift))
+  if t != nil:
+    var u = key and TrunkMask
+    result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
+  else:
+    result = false
+
+proc incl*(s: var IntSet, key: int) =
+  ## includes an element `key` in `s`.
+  var t = intSetPut(s, `shr`(key, TrunkShift))
+  var u = key and TrunkMask
+  t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
+      `shl`(1, u and IntMask)
+
+proc excl*(s: var IntSet, key: int) =
+  ## excludes `key` from the set `s`.
+  var t = intSetGet(s, `shr`(key, TrunkShift))
+  if t != nil:
+    var u = key and TrunkMask
+    t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
+        not `shl`(1, u and IntMask)
+
+proc containsOrIncl*(s: var IntSet, key: int): bool =
+  ## returns true if `s` contains `key`, otherwise `key` is included in `s`
+  ## and false is returned.
+  var t = intSetGet(s, `shr`(key, TrunkShift))
+  if t != nil:
+    var u = key and TrunkMask
+    result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
+    if not result:
+      t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
+          `shl`(1, u and IntMask)
+  else:
+    incl(s, key)
+    result = false
+
+proc initIntSet*: IntSet =
+  ## creates a new int set that is empty.
+  newSeq(result.data, InitIntSetSize)
+  result.max = InitIntSetSize-1
+  result.counter = 0
+  result.head = nil
+
+proc assign*(dest: var IntSet, src: IntSet) =
+  ## copies `src` to `dest`. `dest` does not need to be initialized by
+  ## `initIntSet`.
+  dest.counter = src.counter
+  dest.max = src.max
+  newSeq(dest.data, src.data.len)
+
+  var it = src.head
+  while it != nil:
+
+    var h = it.key and dest.max
+    while dest.data[h] != nil: h = nextTry(h, dest.max)
+    assert(dest.data[h] == nil)
+
+    var n: PTrunk
+    new(n)
+    n.next = dest.head
+    n.key = it.key
+    n.bits = it.bits
+    dest.head = n
+    dest.data[h] = n
+
+    it = it.next
+
+iterator items*(s: IntSet): int {.inline.} =
+  ## iterates over any included element of `s`.
+  var r = s.head
+  while r != nil:
+    var i = 0
+    while i <= high(r.bits):
+      var w = r.bits[i]
+      # taking a copy of r.bits[i] here is correct, because
+      # modifying operations are not allowed during traversation
+      var j = 0
+      while w != 0:         # test all remaining bits for zero
+        if (w and 1) != 0:  # the bit is set!
+          yield (r.key shl TrunkShift) or (i shl IntShift +% j)
+        inc(j)
+        w = w shr 1
+      inc(i)
+    r = r.next
+
+template dollarImpl(): stmt =
+  result = "{"
+  for key in items(s):
+    if result.len > 1: result.add(", ")
+    result.add($key)
+  result.add("}")
+
+proc `$`*(s: IntSet): string =
+  ## The `$` operator for int sets.
+  dollarImpl()
+
+proc empty*(s: IntSet): bool {.inline, deprecated.} =
+  ## returns true if `s` is empty. This is safe to call even before
+  ## the set has been initialized with `initIntSet`. Note this never
+  ## worked reliably and so is deprecated.
+  result = s.counter == 0
+
+when isMainModule:
+  import sequtils, algorithm
+
+  var x = initIntSet()
+  x.incl(1)
+  x.incl(2)
+  x.incl(7)
+  x.incl(1056)
+
+  var xs = toSeq(items(x))
+  xs.sort(cmp[int])
+  assert xs == @[1, 2, 7, 1056]
+
+  var y: IntSet
+  assign(y, x)
+  var ys = toSeq(items(y))
+  ys.sort(cmp[int])
+  assert ys == @[1, 2, 7, 1056]
+
diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
new file mode 100644
index 000000000..535d5e21d
--- /dev/null
+++ b/lib/pure/collections/lists.nim
@@ -0,0 +1,343 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implementation of singly and doubly linked lists. Because it makes no sense
+## to do so, the 'next' and 'prev' pointers are not hidden from you and can
+## be manipulated directly for efficiency.
+
+when not defined(nimhygiene):
+  {.pragma: dirty.}
+
+type
+  DoublyLinkedNodeObj*[T] = object ## a node a doubly linked list consists of
+    next*, prev*: ref DoublyLinkedNodeObj[T]
+    value*: T
+  DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T]
+
+  SinglyLinkedNodeObj*[T] = object ## a node a singly linked list consists of
+    next*: ref SinglyLinkedNodeObj[T]
+    value*: T
+  SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T]
+
+  SinglyLinkedList*[T] = object ## a singly linked list
+    head*, tail*: SinglyLinkedNode[T]
+  
+  DoublyLinkedList*[T] = object ## a doubly linked list
+    head*, tail*: DoublyLinkedNode[T]
+
+  SinglyLinkedRing*[T] = object ## a singly linked ring
+    head*, tail*: SinglyLinkedNode[T]
+  
+  DoublyLinkedRing*[T] = object ## a doubly linked ring
+    head*: DoublyLinkedNode[T]
+
+{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj,
+    PDoublyLinkedNode: DoublyLinkedNode, 
+    TSinglyLinkedNode: SinglyLinkedNodeObj,
+    PSinglyLinkedNode: SinglyLinkedNode,
+    TDoublyLinkedList: DoublyLinkedList,
+    TSinglyLinkedRing: SinglyLinkedRing,
+    TDoublyLinkedRing: DoublyLinkedRing,
+    TSinglyLinkedList: SinglyLinkedList].}
+
+proc initSinglyLinkedList*[T](): SinglyLinkedList[T] =
+  ## creates a new singly linked list that is empty.
+  discard
+
+proc initDoublyLinkedList*[T](): DoublyLinkedList[T] =
+  ## creates a new doubly linked list that is empty.
+  discard
+
+proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] =
+  ## creates a new singly linked ring that is empty.
+  discard
+
+proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] =
+  ## creates a new doubly linked ring that is empty.
+  discard
+
+proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] =
+  ## creates a new doubly linked node with the given `value`.
+  new(result)
+  result.value = value
+
+proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] =
+  ## creates a new singly linked node with the given `value`.
+  new(result)
+  result.value = value
+
+template itemsListImpl() {.dirty.} =
+  var it = L.head
+  while it != nil:
+    yield it.value
+    it = it.next
+
+template itemsRingImpl() {.dirty.} =
+  var it = L.head
+  if it != nil:
+    while true:
+      yield it.value
+      it = it.next
+      if it == L.head: break
+
+template nodesListImpl() {.dirty.} =
+  var it = L.head
+  while it != nil:
+    var nxt = it.next
+    yield it
+    it = nxt
+
+template nodesRingImpl() {.dirty.} =
+  var it = L.head
+  if it != nil:
+    while true:
+      var nxt = it.next
+      yield it
+      it = nxt
+      if it == L.head: break
+
+template findImpl() {.dirty.} =
+  for x in nodes(L):
+    if x.value == value: return x
+
+iterator items*[T](L: DoublyLinkedList[T]): T = 
+  ## yields every value of `L`.
+  itemsListImpl()
+
+iterator items*[T](L: SinglyLinkedList[T]): T = 
+  ## yields every value of `L`.
+  itemsListImpl()
+
+iterator items*[T](L: SinglyLinkedRing[T]): T = 
+  ## yields every value of `L`.
+  itemsRingImpl()
+
+iterator items*[T](L: DoublyLinkedRing[T]): T = 
+  ## yields every value of `L`.
+  itemsRingImpl()
+
+iterator mitems*[T](L: var DoublyLinkedList[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsListImpl()
+
+iterator mitems*[T](L: var SinglyLinkedList[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsListImpl()
+
+iterator mitems*[T](L: var SinglyLinkedRing[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsRingImpl()
+
+iterator mitems*[T](L: var DoublyLinkedRing[T]): var T =
+  ## yields every value of `L` so that you can modify it.
+  itemsRingImpl()
+
+iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] = 
+  ## iterates over every node of `x`. Removing the current node from the
+  ## list during traversal is supported.
+  nodesListImpl()
+
+iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] = 
+  ## iterates over every node of `x`. Removing the current node from the
+  ## list during traversal is supported.
+  nodesListImpl()
+
+iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] = 
+  ## iterates over every node of `x`. Removing the current node from the
+  ## list during traversal is supported.
+  nodesRingImpl()
+
+iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] = 
+  ## iterates over every node of `x`. Removing the current node from the
+  ## list during traversal is supported.
+  nodesRingImpl()
+
+template dollarImpl() {.dirty.} =
+  result = "["
+  for x in nodes(L):
+    if result.len > 1: result.add(", ")
+    result.add($x.value)
+  result.add("]")
+
+proc `$`*[T](L: SinglyLinkedList[T]): string = 
+  ## turns a list into its string representation.
+  dollarImpl()
+
+proc `$`*[T](L: DoublyLinkedList[T]): string = 
+  ## turns a list into its string representation.
+  dollarImpl()
+
+proc `$`*[T](L: SinglyLinkedRing[T]): string = 
+  ## turns a list into its string representation.
+  dollarImpl()
+
+proc `$`*[T](L: DoublyLinkedRing[T]): string = 
+  ## turns a list into its string representation.
+  dollarImpl()
+
+proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] = 
+  ## searches in the list for a value. Returns nil if the value does not
+  ## exist.
+  findImpl()
+
+proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] = 
+  ## searches in the list for a value. Returns nil if the value does not
+  ## exist.
+  findImpl()
+
+proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] = 
+  ## searches in the list for a value. Returns nil if the value does not
+  ## exist.
+  findImpl()
+
+proc find*[T](L: DoublyLinkedRing[T], value: T): DoublyLinkedNode[T] = 
+  ## searches in the list for a value. Returns nil if the value does not
+  ## exist.
+  findImpl()
+
+proc contains*[T](L: SinglyLinkedList[T], value: T): bool {.inline.} = 
+  ## searches in the list for a value. Returns false if the value does not
+  ## exist, true otherwise.
+  result = find(L, value) != nil
+
+proc contains*[T](L: DoublyLinkedList[T], value: T): bool {.inline.} = 
+  ## searches in the list for a value. Returns false if the value does not
+  ## exist, true otherwise.
+  result = find(L, value) != nil
+
+proc contains*[T](L: SinglyLinkedRing[T], value: T): bool {.inline.} = 
+  ## searches in the list for a value. Returns false if the value does not
+  ## exist, true otherwise.
+  result = find(L, value) != nil
+
+proc contains*[T](L: DoublyLinkedRing[T], value: T): bool {.inline.} = 
+  ## searches in the list for a value. Returns false if the value does not
+  ## exist, true otherwise.
+  result = find(L, value) != nil
+
+proc prepend*[T](L: var SinglyLinkedList[T], 
+                 n: SinglyLinkedNode[T]) {.inline.} = 
+  ## prepends a node to `L`. Efficiency: O(1).
+  n.next = L.head
+  L.head = n
+
+proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = 
+  ## prepends a node to `L`. Efficiency: O(1).
+  prepend(L, newSinglyLinkedNode(value))
+  
+proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = 
+  ## appends a node `n` to `L`. Efficiency: O(1).
+  n.next = nil
+  n.prev = L.tail
+  if L.tail != nil: 
+    assert(L.tail.next == nil)
+    L.tail.next = n
+  L.tail = n
+  if L.head == nil: L.head = n
+
+proc append*[T](L: var DoublyLinkedList[T], value: T) = 
+  ## appends a value to `L`. Efficiency: O(1).
+  append(L, newDoublyLinkedNode(value))
+
+proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = 
+  ## prepends a node `n` to `L`. Efficiency: O(1).
+  n.prev = nil
+  n.next = L.head
+  if L.head != nil:
+    assert(L.head.prev == nil)
+    L.head.prev = n
+  L.head = n
+  if L.tail == nil: L.tail = n
+
+proc prepend*[T](L: var DoublyLinkedList[T], value: T) = 
+  ## prepends a value to `L`. Efficiency: O(1).
+  prepend(L, newDoublyLinkedNode(value))
+  
+proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = 
+  ## removes `n` from `L`. Efficiency: O(1).
+  if n == L.tail: L.tail = n.prev
+  if n == L.head: L.head = n.next
+  if n.next != nil: n.next.prev = n.prev
+  if n.prev != nil: n.prev.next = n.next
+
+
+proc append*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = 
+  ## appends a node `n` to `L`. Efficiency: O(1).
+  if L.head != nil:
+    n.next = L.head
+    assert(L.tail != nil)
+    L.tail.next = n
+    L.tail = n
+  else:
+    n.next = n
+    L.head = n
+    L.tail = n
+
+proc append*[T](L: var SinglyLinkedRing[T], value: T) = 
+  ## appends a value to `L`. Efficiency: O(1).
+  append(L, newSinglyLinkedNode(value))
+
+proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = 
+  ## prepends a node `n` to `L`. Efficiency: O(1).
+  if L.head != nil:
+    n.next = L.head
+    assert(L.tail != nil)
+    L.tail.next = n
+  else:
+    n.next = n
+    L.tail = n
+  L.head = n
+
+proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = 
+  ## prepends a value to `L`. Efficiency: O(1).
+  prepend(L, newSinglyLinkedNode(value))
+
+proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = 
+  ## appends a node `n` to `L`. Efficiency: O(1).
+  if L.head != nil:
+    n.next = L.head
+    n.prev = L.head.prev
+    L.head.prev.next = n
+    L.head.prev = n
+  else:
+    n.prev = n
+    n.next = n
+    L.head = n
+
+proc append*[T](L: var DoublyLinkedRing[T], value: T) = 
+  ## appends a value to `L`. Efficiency: O(1).
+  append(L, newDoublyLinkedNode(value))
+
+proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = 
+  ## prepends a node `n` to `L`. Efficiency: O(1).
+  if L.head != nil: 
+    n.next = L.head
+    n.prev = L.head.prev
+    L.head.prev.next = n
+    L.head.prev = n
+  else:
+    n.prev = n
+    n.next = n
+  L.head = n
+
+proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = 
+  ## prepends a value to `L`. Efficiency: O(1).
+  prepend(L, newDoublyLinkedNode(value))
+  
+proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = 
+  ## removes `n` from `L`. Efficiency: O(1).
+  n.next.prev = n.prev
+  n.prev.next = n.next
+  if n == L.head: 
+    var p = L.head.prev
+    if p == L.head: 
+      # only one element left:
+      L.head = nil
+    else:
+      L.head = L.head.prev
diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim
new file mode 100644
index 000000000..af5e7b6cd
--- /dev/null
+++ b/lib/pure/collections/queues.nim
@@ -0,0 +1,102 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implementation of a `queue`:idx:. The underlying implementation uses a ``seq``.
+## Note: For inter thread communication use
+## a `TChannel <channels.html>`_ instead.
+
+import math
+
+type
+  Queue*[T] = object ## a queue
+    data: seq[T]
+    rd, wr, count, mask: int
+
+{.deprecated: [TQueue: Queue].}
+
+proc initQueue*[T](initialSize=4): Queue[T] =
+  ## creates a new queue. `initialSize` needs to be a power of 2.
+  assert isPowerOfTwo(initialSize)
+  result.mask = initialSize-1
+  newSeq(result.data, initialSize)
+
+proc len*[T](q: Queue[T]): int =
+  ## returns the number of elements of `q`.
+  result = q.count
+
+iterator items*[T](q: Queue[T]): T =
+  ## yields every element of `q`.
+  var i = q.rd
+  var c = q.count
+  while c > 0:
+    dec c
+    yield q.data[i]
+    i = (i + 1) and q.mask
+
+iterator mitems*[T](q: var Queue[T]): var T =
+  ## yields every element of `q`.
+  var i = q.rd
+  var c = q.count
+  while c > 0:
+    dec c
+    yield q.data[i]
+    i = (i + 1) and q.mask
+
+proc add*[T](q: var Queue[T], item: T) =
+  ## adds an `item` to the end of the queue `q`.
+  var cap = q.mask+1
+  if q.count >= cap:
+    var n: seq[T]
+    newSeq(n, cap*2)
+    var i = 0
+    for x in items(q):
+      shallowCopy(n[i], x)
+      inc i
+    shallowCopy(q.data, n)
+    q.mask = cap*2 - 1
+    q.wr = q.count
+    q.rd = 0
+  inc q.count
+  q.data[q.wr] = item
+  q.wr = (q.wr + 1) and q.mask
+
+proc enqueue*[T](q: var Queue[T], item: T) =
+  ## alias for the ``add`` operation.
+  add(q, item)
+
+proc dequeue*[T](q: var Queue[T]): T =
+  ## removes and returns the first element of the queue `q`.
+  assert q.count > 0
+  dec q.count
+  result = q.data[q.rd]
+  q.rd = (q.rd + 1) and q.mask
+
+proc `$`*[T](q: Queue[T]): string = 
+  ## turns a queue into its string representation.
+  result = "["
+  for x in items(q):
+    if result.len > 1: result.add(", ")
+    result.add($x)
+  result.add("]")
+
+when isMainModule:
+  var q = initQueue[int]()
+  q.add(123)
+  q.add(9)
+  q.add(4)
+  var first = q.dequeue
+  q.add(56)
+  q.add(6)
+  var second = q.dequeue
+  q.add(789)
+  
+  assert first == 123
+  assert second == 9
+  assert($q == "[4, 56, 6, 789]")
+
diff --git a/lib/pure/collections/rtarrays.nim b/lib/pure/collections/rtarrays.nim
new file mode 100644
index 000000000..9d8085643
--- /dev/null
+++ b/lib/pure/collections/rtarrays.nim
@@ -0,0 +1,36 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## Module that implements a fixed length array whose size
+## is determined at runtime. Note: This is not ready for other people to use!
+
+const
+  ArrayPartSize = 10
+
+type
+  RtArray*[T] = object  ##
+    L: Natural
+    spart: seq[T]
+    apart: array [ArrayPartSize, T]
+  UncheckedArray* {.unchecked.}[T] = array[0..100_000_000, T]
+
+template usesSeqPart(x): expr = x.L > ArrayPartSize
+
+proc initRtArray*[T](len: Natural): RtArray[T] =
+  result.L = len
+  if usesSeqPart(result):
+    newSeq(result.spart, len)
+
+proc getRawData*[T](x: var RtArray[T]): ptr UncheckedArray[T] =
+  if usesSeqPart(x): cast[ptr UncheckedArray[T]](addr(x.spart[0]))
+  else: cast[ptr UncheckedArray[T]](addr(x.apart[0]))
+
+#proc len*[T](x: RtArray[T]): int = x.L
+
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
new file mode 100644
index 000000000..e9cd2cb3c
--- /dev/null
+++ b/lib/pure/collections/sequtils.nim
@@ -0,0 +1,619 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2011 Alex Mitchell
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## :Author: Alex Mitchell
+##
+## This module implements operations for the built-in `seq`:idx: type which
+## were inspired by functional programming languages. If you are looking for
+## the typical `map` function which applies a function to every element in a
+## sequence, it already exists in the `system <system.html>`_ module in both
+## mutable and immutable styles.
+##
+## Also, for functional style programming you may want to pass `anonymous procs
+## <manual.html#anonymous-procs>`_ to procs like ``filter`` to reduce typing.
+## Anonymous procs can use `the special do notation <manual.html#do-notation>`_
+## which is more convenient in certain situations.
+##
+## **Note**: This interface will change as soon as the compiler supports
+## closures and proper coroutines.
+
+when not defined(nimhygiene):
+  {.pragma: dirty.}
+
+proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
+  ## Takes several sequences' items and returns them inside a new sequence.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     s1 = @[1, 2, 3]
+  ##     s2 = @[4, 5]
+  ##     s3 = @[6, 7]
+  ##     total = concat(s1, s2, s3)
+  ##   assert total == @[1, 2, 3, 4, 5, 6, 7]
+  var L = 0
+  for seqitm in items(seqs): inc(L, len(seqitm))
+  newSeq(result, L)
+  var i = 0
+  for s in items(seqs):
+    for itm in items(s):
+      result[i] = itm
+      inc(i)
+
+proc repeat*[T](s: seq[T], n: Natural): seq[T] =
+  ## Returns a new sequence with the items of `s` repeated `n` times.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:
+  ##
+  ##   let
+  ##     s = @[1, 2, 3]
+  ##     total = s.repeat(3)
+  ##   assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  result = newSeq[T](n * s.len)
+  var o = 0
+  for x in 1..n:
+    for e in s:
+      result[o] = e
+      inc o
+
+proc deduplicate*[T](seq1: seq[T]): seq[T] =
+  ## Returns a new sequence without duplicates.
+  ##
+  ## .. code-block::
+  ##   let
+  ##     dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+  ##     dup2 = @["a", "a", "c", "d", "d"]
+  ##     unique1 = deduplicate(dup1)
+  ##     unique2 = deduplicate(dup2)
+  ##   assert unique1 == @[1, 3, 4, 2, 8]
+  ##   assert unique2 == @["a", "c", "d"]
+  result = @[]
+  for itm in items(seq1):
+    if not result.contains(itm): result.add(itm)
+
+{.deprecated: [distnct: deduplicate].}
+
+proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] =
+  ## Returns a new sequence with a combination of the two input sequences.
+  ##
+  ## For convenience you can access the returned tuples through the named
+  ## fields `a` and `b`. If one sequence is shorter, the remaining items in the
+  ## longer sequence are discarded. Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     short = @[1, 2, 3]
+  ##     long = @[6, 5, 4, 3, 2, 1]
+  ##     words = @["one", "two", "three"]
+  ##     zip1 = zip(short, long)
+  ##     zip2 = zip(short, words)
+  ##   assert zip1 == @[(1, 6), (2, 5), (3, 4)]
+  ##   assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+  ##   assert zip1[2].b == 4
+  ##   assert zip2[2].b == "three"
+  var m = min(seq1.len, seq2.len)
+  newSeq(result, m)
+  for i in 0 .. m-1: result[i] = (seq1[i], seq2[i])
+
+proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
+  ## Splits and distributes a sequence `s` into `num` sub sequences.
+  ##
+  ## Returns a sequence of `num` sequences. For some input values this is the
+  ## inverse of the `concat <#concat>`_ proc.  The proc will assert in debug
+  ## builds if `s` is nil or `num` is less than one, and will likely crash on
+  ## release builds.  The input sequence `s` can be empty, which will produce
+  ## `num` empty sequences.
+  ##
+  ## If `spread` is false and the length of `s` is not a multiple of `num`, the
+  ## proc will max out the first sub sequences with ``1 + len(s) div num``
+  ## entries, leaving the remainder of elements to the last sequence.
+  ##
+  ## On the other hand, if `spread` is true, the proc will distribute evenly
+  ## the remainder of the division across all sequences, which makes the result
+  ## more suited to multithreading where you are passing equal sized work units
+  ## to a thread pool and want to maximize core usage.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   let numbers = @[1, 2, 3, 4, 5, 6, 7]
+  ##   assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+  ##   assert numbers.distribute(3, false)  == @[@[1, 2, 3], @[4, 5, 6], @[7]]
+  ##   assert numbers.distribute(6)[0] == @[1, 2]
+  ##   assert numbers.distribute(6)[5] == @[7]
+  assert(not s.isNil, "`s` can't be nil")
+  if num < 2:
+    result = @[s]
+    return
+
+  let num = int(num) # XXX probably only needed because of .. bug
+
+  # Create the result and calculate the stride size and the remainder if any.
+  result = newSeq[seq[T]](num)
+  var
+    stride = s.len div num
+    first = 0
+    last = 0
+    extra = s.len mod num
+
+  if extra == 0 or spread == false:
+    # Use an algorithm which overcounts the stride and minimizes reading limits.
+    if extra > 0: inc(stride)
+
+    for i in 0 .. <num:
+      result[i] = newSeq[T]()
+      for g in first .. <min(s.len, first + stride):
+        result[i].add(s[g])
+      first += stride
+
+  else:
+    # Use an undercounting algorithm which *adds* the remainder each iteration.
+    for i in 0 .. <num:
+      last = first + stride
+      if extra > 0:
+        extra -= 1
+        inc(last)
+
+      result[i] = newSeq[T]()
+      for g in first .. <last:
+        result[i].add(s[g])
+      first = last
+
+
+
+iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T =
+  ## Iterates through a sequence and yields every item that fulfills the
+  ## predicate.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
+  ##   for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
+  ##     echo($n)
+  ##   # echoes 4, 8, 4 in separate lines
+  for i in countup(0, len(seq1)-1):
+    var item = seq1[i]
+    if pred(item): yield seq1[i]
+
+proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] =
+  ## Returns a new sequence with all the items that fulfilled the predicate.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     colors = @["red", "yellow", "black"]
+  ##     f1 = filter(colors, proc(x: string): bool = x.len < 6)
+  ##     f2 = filter(colors) do (x: string) -> bool : x.len > 5
+  ##   assert f1 == @["red", "black"]
+  ##   assert f2 == @["yellow"]
+  accumulateResult(filter(seq1, pred))
+
+proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
+  ## Keeps the items in the passed sequence if they fulfilled the predicate.
+  ## Same as the ``filter`` proc, but modifies the sequence directly.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+  ##   keepIf(floats, proc(x: float): bool = x > 10)
+  ##   assert floats == @[13.0, 12.5, 10.1]
+  var pos = 0
+  for i in 0 .. <len(seq1):
+    if pred(seq1[i]):
+      if pos != i:
+        seq1[pos] = seq1[i]
+      inc(pos)
+  setLen(seq1, pos)
+
+proc delete*[T](s: var seq[T], first=0, last=0) =
+  ## Deletes in `s` the items at position `first` .. `last`. This modifies
+  ## `s` itself, it does not return a copy.
+  ##
+  ## Example:
+  ##
+  ##.. code-block::
+  ##   let outcome = @[1,1,1,1,1,1,1,1]
+  ##   var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+  ##   dest.delete(3, 8)
+  ##   assert outcome == dest
+
+  var i = first
+  var j = last+1
+  var newLen = len(s)-j+i
+  while i < newLen:
+    s[i].shallowCopy(s[j])
+    inc(i)
+    inc(j)
+  setLen(s, newLen)
+
+proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
+  ## Inserts items from `src` into `dest` at position `pos`. This modifies
+  ## `dest` itself, it does not return a copy.
+  ##
+  ## Example:
+  ##
+  ##.. code-block::
+  ##   var dest = @[1,1,1,1,1,1,1,1]
+  ##   let
+  ##     src = @[2,2,2,2,2,2]
+  ##     outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+  ##   dest.insert(src, 3)
+  ##   assert dest == outcome
+
+  var j = len(dest) - 1
+  var i = len(dest) + len(src) - 1
+  dest.setLen(i + 1)
+
+  # Move items after `pos` to the end of the sequence.
+  while j >= pos:
+    dest[i].shallowCopy(dest[j])
+    dec(i)
+    dec(j)
+  # Insert items from `dest` into `dest` at `pos`
+  inc(j)
+  for item in src:
+    dest[j] = item
+    inc(j)
+
+
+template filterIt*(seq1, pred: expr): expr {.immediate.} =
+  ## Returns a new sequence with all the items that fulfilled the predicate.
+  ##
+  ## Unlike the `proc` version, the predicate needs to be an expression using
+  ## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
+  ## Example:
+  ##
+  ## .. code-block::
+  ##    let
+  ##      temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+  ##      acceptable = filterIt(temperatures, it < 50 and it > -10)
+  ##      notAcceptable = filterIt(temperatures, it > 50 or it < -10)
+  ##    assert acceptable == @[-2.0, 24.5, 44.31]
+  ##    assert notAcceptable == @[-272.15, 99.9, -113.44]
+  var result {.gensym.}: type(seq1) = @[]
+  for it {.inject.} in items(seq1):
+    if pred: result.add(it)
+  result
+
+template keepItIf*(varSeq, pred: expr) =
+  ## Convenience template around the ``keepIf`` proc to reduce typing.
+  ##
+  ## Unlike the `proc` version, the predicate needs to be an expression using
+  ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var candidates = @["foo", "bar", "baz", "foobar"]
+  ##   keepItIf(candidates, it.len == 3 and it[0] == 'b')
+  ##   assert candidates == @["bar", "baz"]
+  var pos = 0
+  for i in 0 .. <len(varSeq):
+    let it {.inject.} = varSeq[i]
+    if pred:
+      if pos != i:
+        varSeq[pos] = varSeq[i]
+      inc(pos)
+  setLen(varSeq, pos)
+
+
+template toSeq*(iter: expr): expr {.immediate.} =
+  ## Transforms any iterator into a sequence.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+  ##     odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+  ##       if x mod 2 == 1:
+  ##         result = true)
+  ##   assert odd_numbers == @[1, 3, 5, 7, 9]
+  ##
+  ## **Note**: Since this is an immediate macro, you cannot always invoke this
+  ## as ``x.toSeq``, depending on the ``x``.
+  ## See `this <manual.html#limitations-of-the-method-call-syntax>`_
+  ## for an explanation.
+  var result {.gensym.}: seq[type(iter)] = @[]
+  for x in iter: add(result, x)
+  result
+
+template foldl*(sequence, operation: expr): expr =
+  ## Template to fold a sequence from left to right, returning the accumulation.
+  ##
+  ## The sequence is required to have at least a single element. Debug versions
+  ## of your program will assert in this situation but release versions will
+  ## happily go ahead. If the sequence has a single element it will be returned
+  ## without applying ``operation``.
+  ##
+  ## The ``operation`` parameter should be an expression which uses the
+  ## variables ``a`` and ``b`` for each step of the fold. Since this is a left
+  ## fold, for non associative binary operations like subtraction think that
+  ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
+  ## 3).  Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     numbers = @[5, 9, 11]
+  ##     addition = foldl(numbers, a + b)
+  ##     subtraction = foldl(numbers, a - b)
+  ##     multiplication = foldl(numbers, a * b)
+  ##     words = @["nim", "is", "cool"]
+  ##     concatenation = foldl(words, a & b)
+  ##   assert addition == 25, "Addition is (((5)+9)+11)"
+  ##   assert subtraction == -15, "Subtraction is (((5)-9)-11)"
+  ##   assert multiplication == 495, "Multiplication is (((5)*9)*11)"
+  ##   assert concatenation == "nimiscool"
+  assert sequence.len > 0, "Can't fold empty sequences"
+  var result {.gensym.}: type(sequence[0])
+  result = sequence[0]
+  for i in countup(1, sequence.len - 1):
+    let
+      a {.inject.} = result
+      b {.inject.} = sequence[i]
+    result = operation
+  result
+
+template foldr*(sequence, operation: expr): expr =
+  ## Template to fold a sequence from right to left, returning the accumulation.
+  ##
+  ## The sequence is required to have at least a single element. Debug versions
+  ## of your program will assert in this situation but release versions will
+  ## happily go ahead. If the sequence has a single element it will be returned
+  ## without applying ``operation``.
+  ##
+  ## The ``operation`` parameter should be an expression which uses the
+  ## variables ``a`` and ``b`` for each step of the fold. Since this is a right
+  ## fold, for non associative binary operations like subtraction think that
+  ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
+  ## (3))). Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     numbers = @[5, 9, 11]
+  ##     addition = foldr(numbers, a + b)
+  ##     subtraction = foldr(numbers, a - b)
+  ##     multiplication = foldr(numbers, a * b)
+  ##     words = @["nim", "is", "cool"]
+  ##     concatenation = foldr(words, a & b)
+  ##   assert addition == 25, "Addition is (5+(9+(11)))"
+  ##   assert subtraction == 7, "Subtraction is (5-(9-(11)))"
+  ##   assert multiplication == 495, "Multiplication is (5*(9*(11)))"
+  ##   assert concatenation == "nimiscool"
+  assert sequence.len > 0, "Can't fold empty sequences"
+  var result {.gensym.}: type(sequence[0])
+  result = sequence[sequence.len - 1]
+  for i in countdown(sequence.len - 2, 0):
+    let
+      a {.inject.} = sequence[i]
+      b {.inject.} = result
+    result = operation
+  result
+
+template mapIt*(seq1, typ, op: expr): expr =
+  ## Convenience template around the ``map`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. You also need to pass as `typ` the type of the expression,
+  ## since the new returned sequence can have a different type than the
+  ## original.  Example:
+  ##
+  ## .. code-block::
+  ##   let
+  ##     nums = @[1, 2, 3, 4]
+  ##     strings = nums.mapIt(string, $(4 * it))
+  ##   assert strings == @["4", "8", "12", "16"]
+  var result {.gensym.}: seq[typ] = @[]
+  for it {.inject.} in items(seq1):
+    result.add(op)
+  result
+
+template mapIt*(varSeq, op: expr) =
+  ## Convenience template around the mutable ``map`` proc to reduce typing.
+  ##
+  ## The template injects the ``it`` variable which you can use directly in an
+  ## expression. The expression has to return the same type as the sequence you
+  ## are mutating. Example:
+  ##
+  ## .. code-block::
+  ##   var nums = @[1, 2, 3, 4]
+  ##   nums.mapIt(it * 3)
+  ##   assert nums[0] + nums[3] == 15
+  for i in 0 .. <len(varSeq):
+    let it {.inject.} = varSeq[i]
+    varSeq[i] = op
+
+template newSeqWith*(len: int, init: expr): expr =
+  ## creates a new sequence, calling `init` to initialize each value. Example:
+  ##
+  ## .. code-block::
+  ##   var seq2D = newSeqWith(20, newSeq[bool](10))
+  ##   seq2D[0][0] = true
+  ##   seq2D[1][0] = true
+  ##   seq2D[0][1] = true
+  ##
+  ##   import math
+  ##   var seqRand = newSeqWith(20, random(10))
+  ##   echo seqRand
+  var result {.gensym.} = newSeq[type(init)](len)
+  for i in 0 .. <len:
+    result[i] = init
+  result
+
+when isMainModule:
+  import strutils
+  block: # concat test
+    let
+      s1 = @[1, 2, 3]
+      s2 = @[4, 5]
+      s3 = @[6, 7]
+      total = concat(s1, s2, s3)
+    assert total == @[1, 2, 3, 4, 5, 6, 7]
+
+  block: # duplicates test
+    let
+      dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+      dup2 = @["a", "a", "c", "d", "d"]
+      unique1 = deduplicate(dup1)
+      unique2 = deduplicate(dup2)
+    assert unique1 == @[1, 3, 4, 2, 8]
+    assert unique2 == @["a", "c", "d"]
+
+  block: # zip test
+    let
+      short = @[1, 2, 3]
+      long = @[6, 5, 4, 3, 2, 1]
+      words = @["one", "two", "three"]
+      zip1 = zip(short, long)
+      zip2 = zip(short, words)
+    assert zip1 == @[(1, 6), (2, 5), (3, 4)]
+    assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+    assert zip1[2].b == 4
+    assert zip2[2].b == "three"
+
+  block: # filter proc test
+    let
+      colors = @["red", "yellow", "black"]
+      f1 = filter(colors, proc(x: string): bool = x.len < 6)
+      f2 = filter(colors) do (x: string) -> bool : x.len > 5
+    assert f1 == @["red", "black"]
+    assert f2 == @["yellow"]
+
+  block: # filter iterator test
+    let numbers = @[1, 4, 5, 8, 9, 7, 4]
+    assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+      @[4, 8, 4]
+
+  block: # keepIf test
+    var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+    keepIf(floats, proc(x: float): bool = x > 10)
+    assert floats == @[13.0, 12.5, 10.1]
+
+  block: # filterIt test
+    let
+      temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+      acceptable = filterIt(temperatures, it < 50 and it > -10)
+      notAcceptable = filterIt(temperatures, it > 50 or it < -10)
+    assert acceptable == @[-2.0, 24.5, 44.31]
+    assert notAcceptable == @[-272.15, 99.9, -113.44]
+
+  block: # keepItIf test
+    var candidates = @["foo", "bar", "baz", "foobar"]
+    keepItIf(candidates, it.len == 3 and it[0] == 'b')
+    assert candidates == @["bar", "baz"]
+
+  block: # toSeq test
+    let
+      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+        if x mod 2 == 1:
+          result = true)
+    assert odd_numbers == @[1, 3, 5, 7, 9]
+
+  block: # foldl tests
+    let
+      numbers = @[5, 9, 11]
+      addition = foldl(numbers, a + b)
+      subtraction = foldl(numbers, a - b)
+      multiplication = foldl(numbers, a * b)
+      words = @["nim", "is", "cool"]
+      concatenation = foldl(words, a & b)
+    assert addition == 25, "Addition is (((5)+9)+11)"
+    assert subtraction == -15, "Subtraction is (((5)-9)-11)"
+    assert multiplication == 495, "Multiplication is (((5)*9)*11)"
+    assert concatenation == "nimiscool"
+
+  block: # foldr tests
+    let
+      numbers = @[5, 9, 11]
+      addition = foldr(numbers, a + b)
+      subtraction = foldr(numbers, a - b)
+      multiplication = foldr(numbers, a * b)
+      words = @["nim", "is", "cool"]
+      concatenation = foldr(words, a & b)
+    assert addition == 25, "Addition is (5+(9+(11)))"
+    assert subtraction == 7, "Subtraction is (5-(9-(11)))"
+    assert multiplication == 495, "Multiplication is (5*(9*(11)))"
+    assert concatenation == "nimiscool"
+
+  block: # delete tests
+    let outcome = @[1,1,1,1,1,1,1,1]
+    var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+    dest.delete(3, 8)
+    assert outcome == dest, """\
+    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+    is [1,1,1,1,1,1,1,1]"""
+
+  block: # insert tests
+    var dest = @[1,1,1,1,1,1,1,1]
+    let
+      src = @[2,2,2,2,2,2]
+      outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+    dest.insert(src, 3)
+    assert dest == outcome, """\
+    Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
+    at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
+
+  block: # mapIt tests
+    var
+      nums = @[1, 2, 3, 4]
+      strings = nums.mapIt(string, $(4 * it))
+    nums.mapIt(it * 3)
+    assert nums[0] + nums[3] == 15
+
+  block: # distribute tests
+    let numbers = @[1, 2, 3, 4, 5, 6, 7]
+    doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+    doAssert numbers.distribute(6)[0] == @[1, 2]
+    doAssert numbers.distribute(6)[5] == @[7]
+    let a = @[1, 2, 3, 4, 5, 6, 7]
+    doAssert a.distribute(1, true)   == @[@[1, 2, 3, 4, 5, 6, 7]]
+    doAssert a.distribute(1, false)  == @[@[1, 2, 3, 4, 5, 6, 7]]
+    doAssert a.distribute(2, true)   == @[@[1, 2, 3, 4], @[5, 6, 7]]
+    doAssert a.distribute(2, false)  == @[@[1, 2, 3, 4], @[5, 6, 7]]
+    doAssert a.distribute(3, true)   == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+    doAssert a.distribute(3, false)  == @[@[1, 2, 3], @[4, 5, 6], @[7]]
+    doAssert a.distribute(4, true)   == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
+    doAssert a.distribute(4, false)  == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
+    doAssert a.distribute(5, true)   == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
+    doAssert a.distribute(5, false)  == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
+    doAssert a.distribute(6, true)   == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
+    doAssert a.distribute(6, false)  == @[
+      @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
+    doAssert a.distribute(8, false)  == a.distribute(8, true)
+    doAssert a.distribute(90, false) == a.distribute(90, true)
+    var b = @[0]
+    for f in 1 .. 25: b.add(f)
+    doAssert b.distribute(5, true)[4].len == 5
+    doAssert b.distribute(5, false)[4].len == 2
+
+  block: # newSeqWith tests
+    var seq2D = newSeqWith(4, newSeq[bool](2))
+    seq2D[0][0] = true
+    seq2D[1][0] = true
+    seq2D[0][1] = true
+    doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
+
+  block: # repeat tests
+    let
+      a = @[1, 2, 3]
+      b: seq[int] = @[]
+
+    doAssert a.repeat(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+    doAssert a.repeat(0) == @[]
+    #doAssert a.repeat(-1) == @[] # will not compile!
+    doAssert b.repeat(3) == @[]
+
+  when not defined(testing):
+    echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
new file mode 100644
index 000000000..280e0eeba
--- /dev/null
+++ b/lib/pure/collections/sets.nim
@@ -0,0 +1,976 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The ``sets`` module implements an efficient `hash set`:idx: and
+## ordered hash set.
+##
+## Hash sets are different from the `built in set type
+## <manual.html#set-type>`_. Sets allow you to store any value that can be
+## `hashed <hashes.html>`_ and they don't contain duplicate entries.
+##
+## **Note**: The data types declared here have *value semantics*: This means
+## that ``=`` performs a copy of the set.
+
+import
+  os, hashes, math
+
+{.pragma: myShallow.}
+when not defined(nimhygiene):
+  {.pragma: dirty.}
+
+# For "integer-like A" that are too big for intsets/bit-vectors to be practical,
+# it would be best to shrink hcode to the same size as the integer.  Larger
+# codes should never be needed, and this can pack more entries per cache-line.
+# Losing hcode entirely is also possible - if some element value is forbidden.
+type
+  KeyValuePair[A] = tuple[hcode: THash, key: A]
+  KeyValuePairSeq[A] = seq[KeyValuePair[A]]
+  HashSet* {.myShallow.}[A] = object ## \
+    ## A generic hash set.
+    ##
+    ## Use `init() <#init,HashSet[A],int>`_ or `initSet[type]() <#initSet>`_
+    ## before calling other procs on it.
+    data: KeyValuePairSeq[A]
+    counter: int
+
+{.deprecated: [TSet: HashSet].}
+
+# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
+# two procs retain clarity of that encoding without the space cost of an enum.
+proc isEmpty(hcode: THash): bool {.inline.} =
+  result = hcode == 0
+
+proc isFilled(hcode: THash): bool {.inline.} =
+  result = hcode != 0
+
+proc isValid*[A](s: HashSet[A]): bool =
+  ## Returns `true` if the set has been initialized with `initSet <#initSet>`_.
+  ##
+  ## Most operations over an uninitialized set will crash at runtime and
+  ## `assert <system.html#assert>`_ in debug builds. You can use this proc in
+  ## your own procs to verify that sets passed to your procs are correctly
+  ## initialized. Example:
+  ##
+  ## .. code-block ::
+  ##   proc savePreferences(options: TSet[string]) =
+  ##     assert options.isValid, "Pass an initialized set!"
+  ##     # Do stuff here, may crash in release builds!
+  result = not s.data.isNil
+
+proc len*[A](s: HashSet[A]): int =
+  ## Returns the number of keys in `s`.
+  ##
+  ## Due to an implementation detail you can call this proc on variables which
+  ## have not been initialized yet. The proc will return zero as the length
+  ## then. Example:
+  ##
+  ## .. code-block::
+  ##
+  ##   var values: TSet[int]
+  ##   assert(not values.isValid)
+  ##   assert values.len == 0
+  result = s.counter
+
+proc card*[A](s: HashSet[A]): int =
+  ## Alias for `len() <#len,TSet[A]>`_.
+  ##
+  ## Card stands for the `cardinality
+  ## <http://en.wikipedia.org/wiki/Cardinality>`_ of a set.
+  result = s.counter
+
+iterator items*[A](s: HashSet[A]): A =
+  ## Iterates over keys in the set `s`.
+  ##
+  ## If you need a sequence with the keys you can use `sequtils.toSeq()
+  ## <sequtils.html#toSeq>`_ on the iterator. Usage example:
+  ##
+  ## .. code-block::
+  ##   type
+  ##     pair = tuple[a, b: int]
+  ##   var
+  ##     a, b = initSet[pair]()
+  ##   a.incl((2, 3))
+  ##   a.incl((3, 2))
+  ##   a.incl((2, 3))
+  ##   for x, y in a.items:
+  ##     b.incl((x - 2, y + 1))
+  ##   assert a.len == 2
+  ##   echo b
+  ##   # --> {(a: 1, b: 3), (a: 0, b: 4)}
+  assert s.isValid, "The set needs to be initialized."
+  for h in 0..high(s.data):
+    if isFilled(s.data[h].hcode): yield s.data[h].key
+
+const
+  growthFactor = 2
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc rightSize*(count: Natural): int {.inline.} =
+  ## Return the value of `initialSize` to support `count` items.
+  ##
+  ## If more items are expected to be added, simply add that
+  ## expected extra amount to the parameter before calling this.
+  ##
+  ## Internally, we want mustRehash(rightSize(x), x) == false.
+  result = nextPowerOfTwo(count * 3 div 2  +  4)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = (h + 1) and maxHash
+
+template rawGetKnownHCImpl() {.dirty.} =
+  var h: THash = hc and high(s.data)  # start with real hash value
+  while isFilled(s.data[h].hcode):
+    # Compare hc THEN key with boolean short circuit. This makes the common case
+    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
+    # It does slow down succeeding lookups by one extra THash cmp&and..usually
+    # just a few clock cycles, generally worth it for any non-integer-like A.
+    if s.data[h].hcode == hc and s.data[h].key == key:  # compare hc THEN key
+      return h
+    h = nextTry(h, high(s.data))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+template rawGetImpl() {.dirty.} =
+  hc = hash(key)
+  if hc == 0:       # This almost never taken branch should be very predictable.
+    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
+  rawGetKnownHCImpl()
+
+template rawInsertImpl() {.dirty.} =
+  data[h].key = key
+  data[h].hcode = hc
+
+proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} =
+  rawGetImpl()
+
+proc mget*[A](s: var HashSet[A], key: A): var A =
+  ## returns the element that is actually stored in 's' which has the same
+  ## value as 'key' or raises the ``EInvalidKey`` exception. This is useful
+  ## when one overloaded 'hash' and '==' but still needs reference semantics
+  ## for sharing.
+  assert s.isValid, "The set needs to be initialized."
+  var hc: THash
+  var index = rawGet(s, key, hc)
+  if index >= 0: result = s.data[index].key
+  else: raise newException(KeyError, "key not found: " & $key)
+
+proc contains*[A](s: HashSet[A], key: A): bool =
+  ## Returns true iff `key` is in `s`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var values = initSet[int]()
+  ##   assert(not values.contains(2))
+  ##   values.incl(2)
+  ##   assert values.contains(2)
+  ##   values.excl(2)
+  ##   assert(not values.contains(2))
+  assert s.isValid, "The set needs to be initialized."
+  var hc: THash
+  var index = rawGet(s, key, hc)
+  result = index >= 0
+
+proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
+                  hc: THash, h: THash) =
+  rawInsertImpl()
+
+proc enlarge[A](s: var HashSet[A]) =
+  var n: KeyValuePairSeq[A]
+  newSeq(n, len(s.data) * growthFactor)
+  swap(s.data, n)                   # n is now old seq
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode)
+      rawInsert(s, s.data, n[i].key, n[i].hcode, j)
+
+template inclImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(s, key, hc)
+  if index < 0:
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
+    inc(s.counter)
+
+template containsOrInclImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(s, key, hc)
+  if index >= 0:
+    result = true
+  else:
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
+    inc(s.counter)
+
+proc incl*[A](s: var HashSet[A], key: A) =
+  ## Includes an element `key` in `s`.
+  ##
+  ## This doesn't do anything if `key` is already in `s`. Example:
+  ##
+  ## .. code-block::
+  ##   var values = initSet[int]()
+  ##   values.incl(2)
+  ##   values.incl(2)
+  ##   assert values.len == 1
+  assert s.isValid, "The set needs to be initialized."
+  inclImpl()
+
+proc incl*[A](s: var HashSet[A], other: HashSet[A]) =
+  ## Includes all elements from `other` into `s`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var values = initSet[int]()
+  ##   values.incl(2)
+  ##   var others = toSet([6, 7])
+  ##   values.incl(others)
+  ##   assert values.len == 3
+  assert s.isValid, "The set `s` needs to be initialized."
+  assert other.isValid, "The set `other` needs to be initialized."
+  for item in other: incl(s, item)
+
+template doWhile(a: expr, b: stmt): stmt =
+  while true:
+    b
+    if not a: break
+
+proc excl*[A](s: var HashSet[A], key: A) =
+  ## Excludes `key` from the set `s`.
+  ##
+  ## This doesn't do anything if `key` is not found in `s`. Example:
+  ##
+  ## .. code-block::
+  ##   var s = toSet([2, 3, 6, 7])
+  ##   s.excl(2)
+  ##   s.excl(2)
+  ##   assert s.len == 3
+  assert s.isValid, "The set needs to be initialized."
+  var hc: THash
+  var i = rawGet(s, key, hc)
+  var msk = high(s.data)
+  if i >= 0:
+    s.data[i].hcode = 0
+    dec(s.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      s.data[i].hcode = 0              # mark current EMPTY
+      doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = s.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(s.data[j], s.data[i]) # data[j] will be marked EMPTY next loop
+
+proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
+  ## Excludes everything in `other` from `s`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     numbers = toSet([1, 2, 3, 4, 5])
+  ##     even = toSet([2, 4, 6, 8])
+  ##   numbers.excl(even)
+  ##   echo numbers
+  ##   # --> {1, 3, 5}
+  assert s.isValid, "The set `s` needs to be initialized."
+  assert other.isValid, "The set `other` needs to be initialized."
+  for item in other: excl(s, item)
+
+proc containsOrIncl*[A](s: var HashSet[A], key: A): bool =
+  ## Includes `key` in the set `s` and tells if `key` was added to `s`.
+  ##
+  ## The difference with regards to the `incl() <#incl,TSet[A],A>`_ proc is
+  ## that this proc returns `true` if `key` was already present in `s`. The
+  ## proc will return false if `key` was added as a new value to `s` during
+  ## this call. Example:
+  ##
+  ## .. code-block::
+  ##   var values = initSet[int]()
+  ##   assert values.containsOrIncl(2) == false
+  ##   assert values.containsOrIncl(2) == true
+  assert s.isValid, "The set needs to be initialized."
+  containsOrInclImpl()
+
+proc init*[A](s: var HashSet[A], initialSize=64) =
+  ## Initializes a hash set.
+  ##
+  ## The `initialSize` parameter needs to be a power of two. You can use
+  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
+  ## guarantee that at runtime. All set variables must be initialized before
+  ## use with other procs from this module with the exception of `isValid()
+  ## <#isValid,TSet[A]>`_ and `len() <#len,TSet[A]>`_.
+  ##
+  ## You can call this proc on a previously initialized hash set, which will
+  ## discard all its values. This might be more convenient than iterating over
+  ## existing values and calling `excl() <#excl,TSet[A],A>`_ on them. Example:
+  ##
+  ## .. code-block ::
+  ##   var a: TSet[int]
+  ##   a.init(4)
+  ##   a.incl(2)
+  ##   a.init
+  ##   assert a.len == 0 and a.isValid
+  assert isPowerOfTwo(initialSize)
+  s.counter = 0
+  newSeq(s.data, initialSize)
+
+proc initSet*[A](initialSize=64): HashSet[A] =
+  ## Wrapper around `init() <#init,TSet[A],int>`_ for initialization of hash
+  ## sets.
+  ##
+  ## Returns an empty hash set you can assign directly in ``var`` blocks in a
+  ## single line. Example:
+  ##
+  ## .. code-block ::
+  ##   var a = initSet[int](4)
+  ##   a.incl(2)
+  result.init(initialSize)
+
+proc toSet*[A](keys: openArray[A]): HashSet[A] =
+  ## Creates a new hash set that contains the given `keys`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var numbers = toSet([1, 2, 3, 4, 5])
+  ##   assert numbers.contains(2)
+  ##   assert numbers.contains(4)
+  result = initSet[A](rightSize(keys.len))
+  for key in items(keys): result.incl(key)
+
+template dollarImpl(): stmt {.dirty.} =
+  result = "{"
+  for key in items(s):
+    if result.len > 1: result.add(", ")
+    result.add($key)
+  result.add("}")
+
+proc `$`*[A](s: HashSet[A]): string =
+  ## Converts the set `s` to a string, mostly for logging purposes.
+  ##
+  ## Don't use this proc for serialization, the representation may change at
+  ## any moment and values are not escaped. Example:
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   echo toSet([2, 4, 5])
+  ##   # --> {2, 4, 5}
+  ##   echo toSet(["no", "esc'aping", "is \" provided"])
+  ##   # --> {no, esc'aping, is " provided}
+  assert s.isValid, "The set needs to be initialized."
+  dollarImpl()
+
+proc union*[A](s1, s2: HashSet[A]): HashSet[A] =
+  ## Returns the union of the sets `s1` and `s2`.
+  ##
+  ## The union of two sets is represented mathematically as *A ∪ B* and is the
+  ## set of all objects that are members of `s1`, `s2` or both. Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##     c = union(a, b)
+  ##   assert c == toSet(["a", "b", "c"])
+  assert s1.isValid, "The set `s1` needs to be initialized."
+  assert s2.isValid, "The set `s2` needs to be initialized."
+  result = s1
+  incl(result, s2)
+
+proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] =
+  ## Returns the intersection of the sets `s1` and `s2`.
+  ##
+  ## The intersection of two sets is represented mathematically as *A ∩ B* and
+  ## is the set of all objects that are members of `s1` and `s2` at the same
+  ## time. Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##     c = intersection(a, b)
+  ##   assert c == toSet(["b"])
+  assert s1.isValid, "The set `s1` needs to be initialized."
+  assert s2.isValid, "The set `s2` needs to be initialized."
+  result = initSet[A](min(s1.data.len, s2.data.len))
+  for item in s1:
+    if item in s2: incl(result, item)
+
+proc difference*[A](s1, s2: HashSet[A]): HashSet[A] =
+  ## Returns the difference of the sets `s1` and `s2`.
+  ##
+  ## The difference of two sets is represented mathematically as *A \ B* and is
+  ## the set of all objects that are members of `s1` and not members of `s2`.
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##     c = difference(a, b)
+  ##   assert c == toSet(["a"])
+  assert s1.isValid, "The set `s1` needs to be initialized."
+  assert s2.isValid, "The set `s2` needs to be initialized."
+  result = initSet[A]()
+  for item in s1:
+    if not contains(s2, item):
+      incl(result, item)
+
+proc symmetricDifference*[A](s1, s2: HashSet[A]): HashSet[A] =
+  ## Returns the symmetric difference of the sets `s1` and `s2`.
+  ##
+  ## The symmetric difference of two sets is represented mathematically as *A â–³
+  ## B* or *A ⊖ B* and is the set of all objects that are members of `s1` or
+  ## `s2` but not both at the same time. Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##     c = symmetricDifference(a, b)
+  ##   assert c == toSet(["a", "c"])
+  assert s1.isValid, "The set `s1` needs to be initialized."
+  assert s2.isValid, "The set `s2` needs to be initialized."
+  result = s1
+  for item in s2:
+    if containsOrIncl(result, item): excl(result, item)
+
+proc `+`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} =
+  ## Alias for `union(s1, s2) <#union>`_.
+  result = union(s1, s2)
+
+proc `*`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} =
+  ## Alias for `intersection(s1, s2) <#intersection>`_.
+  result = intersection(s1, s2)
+
+proc `-`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} =
+  ## Alias for `difference(s1, s2) <#difference>`_.
+  result = difference(s1, s2)
+
+proc `-+-`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} =
+  ## Alias for `symmetricDifference(s1, s2) <#symmetricDifference>`_.
+  result = symmetricDifference(s1, s2)
+
+proc disjoint*[A](s1, s2: HashSet[A]): bool =
+  ## Returns true iff the sets `s1` and `s2` have no items in common.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##   assert disjoint(a, b) == false
+  ##   assert disjoint(a, b - a) == true
+  assert s1.isValid, "The set `s1` needs to be initialized."
+  assert s2.isValid, "The set `s2` needs to be initialized."
+  for item in s1:
+    if item in s2: return false
+  return true
+
+proc `<`*[A](s, t: HashSet[A]): bool =
+  ## Returns true if `s` is a strict or proper subset of `t`.
+  ##
+  ## A strict or proper subset `s` has all of its members in `t` but `t` has
+  ## more elements than `s`. Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##     c = intersection(a, b)
+  ##   assert c < a and c < b
+  ##   assert((a < a) == false)
+  s.counter != t.counter and s <= t
+
+proc `<=`*[A](s, t: HashSet[A]): bool =
+  ## Returns true if `s` is subset of `t`.
+  ##
+  ## A subset `s` has all of its members in `t` and `t` doesn't necessarily
+  ## have more members than `s`. That is, `s` can be equal to `t`. Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet(["a", "b"])
+  ##     b = toSet(["b", "c"])
+  ##     c = intersection(a, b)
+  ##   assert c <= a and c <= b
+  ##   assert((a <= a))
+  result = false
+  if s.counter > t.counter: return
+  result = true
+  for item in s:
+    if not(t.contains(item)):
+      result = false
+      return
+
+proc `==`*[A](s, t: HashSet[A]): bool =
+  ## Returns true if both `s` and `t` have the same members and set size.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     a = toSet([1, 2])
+  ##     b = toSet([1])
+  ##   b.incl(2)
+  ##   assert a == b
+  s.counter == t.counter and s <= t
+
+proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
+  ## Returns a new set after applying `op` on each of the elements of `data`.
+  ##
+  ## You can use this proc to transform the elements from a set. Example:
+  ##
+  ## .. code-block::
+  ##   var a = toSet([1, 2, 3])
+  ##   var b = a.map(proc (x: int): string = $x)
+  ##   assert b == toSet(["1", "2", "3"])
+  result = initSet[B]()
+  for item in data: result.incl(op(item))
+
+# ------------------------------ ordered set ------------------------------
+
+type
+  OrderedKeyValuePair[A] = tuple[
+    hcode: THash, next: int, key: A]
+  OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
+  OrderedSet* {.myShallow.}[A] = object ## \
+    ## A generic hash set that remembers insertion order.
+    ##
+    ## Use `init() <#init,OrderedSet[A],int>`_ or `initOrderedSet[type]()
+    ## <#initOrderedSet>`_ before calling other procs on it.
+    data: OrderedKeyValuePairSeq[A]
+    counter, first, last: int
+
+{.deprecated: [TOrderedSet: OrderedSet].}
+
+proc isValid*[A](s: OrderedSet[A]): bool =
+  ## Returns `true` if the ordered set has been initialized with `initSet
+  ## <#initOrderedSet>`_.
+  ##
+  ## Most operations over an uninitialized ordered set will crash at runtime
+  ## and `assert <system.html#assert>`_ in debug builds. You can use this proc
+  ## in your own procs to verify that ordered sets passed to your procs are
+  ## correctly initialized. Example:
+  ##
+  ## .. code-block::
+  ##   proc saveTarotCards(cards: TOrderedSet[int]) =
+  ##     assert cards.isValid, "Pass an initialized set!"
+  ##     # Do stuff here, may crash in release builds!
+  result = not s.data.isNil
+
+proc len*[A](s: OrderedSet[A]): int {.inline.} =
+  ## Returns the number of keys in `s`.
+  ##
+  ## Due to an implementation detail you can call this proc on variables which
+  ## have not been initialized yet. The proc will return zero as the length
+  ## then. Example:
+  ##
+  ## .. code-block::
+  ##
+  ##   var values: TOrderedSet[int]
+  ##   assert(not values.isValid)
+  ##   assert values.len == 0
+  result = s.counter
+
+proc card*[A](s: OrderedSet[A]): int {.inline.} =
+  ## Alias for `len() <#len,TOrderedSet[A]>`_.
+  ##
+  ## Card stands for the `cardinality
+  ## <http://en.wikipedia.org/wiki/Cardinality>`_ of a set.
+  result = s.counter
+
+template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
+  var h = s.first
+  while h >= 0:
+    var nxt = s.data[h].next
+    if isFilled(s.data[h].hcode): yieldStmt
+    h = nxt
+
+iterator items*[A](s: OrderedSet[A]): A =
+  ## Iterates over keys in the ordered set `s` in insertion order.
+  ##
+  ## If you need a sequence with the keys you can use `sequtils.toSeq()
+  ## <sequtils.html#toSeq>`_ on the iterator. Usage example:
+  ##
+  ## .. code-block::
+  ##   var a = initOrderedSet[int]()
+  ##   for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+  ##     a.incl(value)
+  ##   for value in a.items:
+  ##     echo "Got ", value
+  ##   # --> Got 9
+  ##   # --> Got 2
+  ##   # --> Got 1
+  ##   # --> Got 5
+  ##   # --> Got 8
+  ##   # --> Got 4
+  assert s.isValid, "The set needs to be initialized."
+  forAllOrderedPairs:
+    yield s.data[h].key
+
+proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} =
+  rawGetImpl()
+
+proc contains*[A](s: OrderedSet[A], key: A): bool =
+  ## Returns true iff `key` is in `s`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var values = initOrderedSet[int]()
+  ##   assert(not values.contains(2))
+  ##   values.incl(2)
+  ##   assert values.contains(2)
+  assert s.isValid, "The set needs to be initialized."
+  var hc: THash
+  var index = rawGet(s, key, hc)
+  result = index >= 0
+
+proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
+                  key: A, hc: THash, h: THash) =
+  rawInsertImpl()
+  data[h].next = -1
+  if s.first < 0: s.first = h
+  if s.last >= 0: data[s.last].next = h
+  s.last = h
+
+proc enlarge[A](s: var OrderedSet[A]) =
+  var n: OrderedKeyValuePairSeq[A]
+  newSeq(n, len(s.data) * growthFactor)
+  var h = s.first
+  s.first = -1
+  s.last = -1
+  swap(s.data, n)
+  while h >= 0:
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
+      rawInsert(s, s.data, n[h].key, n[h].hcode, j)
+    h = nxt
+
+proc incl*[A](s: var OrderedSet[A], key: A) =
+  ## Includes an element `key` in `s`.
+  ##
+  ## This doesn't do anything if `key` is already in `s`. Example:
+  ##
+  ## .. code-block::
+  ##   var values = initOrderedSet[int]()
+  ##   values.incl(2)
+  ##   values.incl(2)
+  ##   assert values.len == 1
+  assert s.isValid, "The set needs to be initialized."
+  inclImpl()
+
+proc incl*[A](s: var HashSet[A], other: OrderedSet[A]) =
+  ## Includes all elements from `other` into `s`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var values = initOrderedSet[int]()
+  ##   values.incl(2)
+  ##   var others = toOrderedSet([6, 7])
+  ##   values.incl(others)
+  ##   assert values.len == 3
+  assert s.isValid, "The set `s` needs to be initialized."
+  assert other.isValid, "The set `other` needs to be initialized."
+  for item in other: incl(s, item)
+
+proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
+  ## Includes `key` in the set `s` and tells if `key` was added to `s`.
+  ##
+  ## The difference with regards to the `incl() <#incl,TOrderedSet[A],A>`_ proc
+  ## is that this proc returns `true` if `key` was already present in `s`. The
+  ## proc will return false if `key` was added as a new value to `s` during
+  ## this call. Example:
+  ##
+  ## .. code-block::
+  ##   var values = initOrderedSet[int]()
+  ##   assert values.containsOrIncl(2) == false
+  ##   assert values.containsOrIncl(2) == true
+  assert s.isValid, "The set needs to be initialized."
+  containsOrInclImpl()
+
+proc init*[A](s: var OrderedSet[A], initialSize=64) =
+  ## Initializes an ordered hash set.
+  ##
+  ## The `initialSize` parameter needs to be a power of two. You can use
+  ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to
+  ## guarantee that at runtime. All set variables must be initialized before
+  ## use with other procs from this module with the exception of `isValid()
+  ## <#isValid,TOrderedSet[A]>`_ and `len() <#len,TOrderedSet[A]>`_.
+  ##
+  ## You can call this proc on a previously initialized ordered hash set to
+  ## discard its values. At the moment this is the only proc to remove elements
+  ## from an ordered hash set. Example:
+  ##
+  ## .. code-block ::
+  ##   var a: TOrderedSet[int]
+  ##   a.init(4)
+  ##   a.incl(2)
+  ##   a.init
+  ##   assert a.len == 0 and a.isValid
+  assert isPowerOfTwo(initialSize)
+  s.counter = 0
+  s.first = -1
+  s.last = -1
+  newSeq(s.data, initialSize)
+
+proc initOrderedSet*[A](initialSize=64): OrderedSet[A] =
+  ## Wrapper around `init() <#init,TOrderedSet[A],int>`_ for initialization of
+  ## ordered hash sets.
+  ##
+  ## Returns an empty ordered hash set you can assign directly in ``var``
+  ## blocks in a single line. Example:
+  ##
+  ## .. code-block ::
+  ##   var a = initOrderedSet[int](4)
+  ##   a.incl(2)
+  result.init(initialSize)
+
+proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
+  ## Creates a new ordered hash set that contains the given `keys`.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   var numbers = toOrderedSet([1, 2, 3, 4, 5])
+  ##   assert numbers.contains(2)
+  ##   assert numbers.contains(4)
+  result = initOrderedSet[A](rightSize(keys.len))
+  for key in items(keys): result.incl(key)
+
+proc `$`*[A](s: OrderedSet[A]): string =
+  ## Converts the ordered hash set `s` to a string, mostly for logging purposes.
+  ##
+  ## Don't use this proc for serialization, the representation may change at
+  ## any moment and values are not escaped. Example:
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##   echo toOrderedSet([2, 4, 5])
+  ##   # --> {2, 4, 5}
+  ##   echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+  ##   # --> {no, esc'aping, is " provided}
+  assert s.isValid, "The set needs to be initialized."
+  dollarImpl()
+
+proc `==`*[A](s, t: OrderedSet[A]): bool =
+  ## Equality for ordered sets.
+  if s.counter != t.counter: return false
+  var h = s.first
+  var g = s.first
+  var compared = 0
+  while h >= 0 and g >= 0:
+    var nxh = s.data[h].next
+    var nxg = t.data[g].next
+    if isFilled(s.data[h].hcode) and isFilled(s.data[g].hcode):
+      if s.data[h].key == s.data[g].key:
+        inc compared
+      else:
+        return false
+    h = nxh
+    g = nxg
+  result = compared == s.counter
+
+when isMainModule and not defined(release):
+  proc testModule() =
+    ## Internal micro test to validate docstrings and such.
+    block isValidTest:
+      var options: HashSet[string]
+      proc savePreferences(options: HashSet[string]) =
+        assert options.isValid, "Pass an initialized set!"
+      options = initSet[string]()
+      options.savePreferences
+
+    block lenTest:
+      var values: HashSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+      #echo b
+
+    block setContains:
+      var values = initSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+      values.excl(2)
+      assert(not values.contains(2))
+
+      values.incl(4)
+      var others = toSet([6, 7])
+      values.incl(others)
+      assert values.len == 3
+
+      values.init
+      assert values.containsOrIncl(2) == false
+      assert values.containsOrIncl(2) == true
+      var
+        a = toSet([1, 2])
+        b = toSet([1])
+      b.incl(2)
+      assert a == b
+
+    block exclusions:
+      var s = toSet([2, 3, 6, 7])
+      s.excl(2)
+      s.excl(2)
+      assert s.len == 3
+
+      var
+        numbers = toSet([1, 2, 3, 4, 5])
+        even = toSet([2, 4, 6, 8])
+      numbers.excl(even)
+      #echo numbers
+      # --> {1, 3, 5}
+
+    block toSeqAndString:
+      var a = toSet([2, 4, 5])
+      var b = initSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      #echo a
+      #echo toSet(["no", "esc'aping", "is \" provided"])
+
+    #block orderedToSeqAndString:
+    #  echo toOrderedSet([2, 4, 5])
+    #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+
+    block setOperations:
+      var
+        a = toSet(["a", "b"])
+        b = toSet(["b", "c"])
+        c = union(a, b)
+      assert c == toSet(["a", "b", "c"])
+      var d = intersection(a, b)
+      assert d == toSet(["b"])
+      var e = difference(a, b)
+      assert e == toSet(["a"])
+      var f = symmetricDifference(a, b)
+      assert f == toSet(["a", "c"])
+      assert d < a and d < b
+      assert((a < a) == false)
+      assert d <= a and d <= b
+      assert((a <= a))
+      # Alias test.
+      assert a + b == toSet(["a", "b", "c"])
+      assert a * b == toSet(["b"])
+      assert a - b == toSet(["a"])
+      assert a -+- b == toSet(["a", "c"])
+      assert disjoint(a, b) == false
+      assert disjoint(a, b - a) == true
+
+    block mapSet:
+      var a = toSet([1, 2, 3])
+      var b = a.map(proc (x: int): string = $x)
+      assert b == toSet(["1", "2", "3"])
+
+    block isValidTest:
+      var cards: OrderedSet[string]
+      proc saveTarotCards(cards: OrderedSet[string]) =
+        assert cards.isValid, "Pass an initialized set!"
+      cards = initOrderedSet[string]()
+      cards.saveTarotCards
+
+    block lenTest:
+      var values: OrderedSet[int]
+      assert(not values.isValid)
+      assert values.len == 0
+      assert values.card == 0
+
+    block setIterator:
+      type pair = tuple[a, b: int]
+      var a, b = initOrderedSet[pair]()
+      a.incl((2, 3))
+      a.incl((3, 2))
+      a.incl((2, 3))
+      for x, y in a.items:
+        b.incl((x - 2, y + 1))
+      assert a.len == b.card
+      assert a.len == 2
+
+    #block orderedSetIterator:
+    #  var a = initOrderedSet[int]()
+    #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+    #    a.incl(value)
+    #  for value in a.items:
+    #    echo "Got ", value
+
+    block setContains:
+      var values = initOrderedSet[int]()
+      assert(not values.contains(2))
+      values.incl(2)
+      assert values.contains(2)
+
+    block toSeqAndString:
+      var a = toOrderedSet([2, 4, 5])
+      var b = initOrderedSet[int]()
+      for x in [2, 4, 5]: b.incl(x)
+      assert($a == $b)
+      assert(a == b) # https://github.com/Araq/Nimrod/issues/1413
+
+    block initBlocks:
+      var a: OrderedSet[int]
+      a.init(4)
+      a.incl(2)
+      a.init
+      assert a.len == 0 and a.isValid
+      a = initOrderedSet[int](4)
+      a.incl(2)
+      assert a.len == 1
+
+      var b: HashSet[int]
+      b.init(4)
+      b.incl(2)
+      b.init
+      assert b.len == 0 and b.isValid
+      b = initSet[int](4)
+      b.incl(2)
+      assert b.len == 1
+
+    for i in 0 .. 32:
+      var s = rightSize(i)
+      if s <= i or mustRehash(s, i):
+        echo "performance issue: rightSize() will not elide enlarge() at ", i
+
+    when not defined(testing):
+      echo "Micro tests run successfully."
+
+  testModule()
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
new file mode 100644
index 000000000..9496fa2fe
--- /dev/null
+++ b/lib/pure/collections/tables.nim
@@ -0,0 +1,1102 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The ``tables`` module implements variants of an efficient `hash table`:idx:
+## (also often named `dictionary`:idx: in other programming languages) that is
+## a mapping from keys to values. ``Table`` is the usual hash table,
+## ``OrderedTable`` is like ``Table`` but remembers insertion order
+## and ``CountTable`` is a mapping from a key to its number of occurrences.
+## For consistency with every other data type in Nim these have **value**
+## semantics, this means that ``=`` performs a copy of the hash table.
+## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
+## ``OrderedTableRef``, ``CountTableRef``.
+##
+## If you are using simple standard types like ``int`` or ``string`` for the
+## keys of the table you won't have any problems, but as soon as you try to use
+## a more complex object as a key you will be greeted by a strange compiler
+## error::
+##
+##   Error: type mismatch: got (Person)
+##   but expected one of:
+##   hashes.hash(x: openarray[A]): THash
+##   hashes.hash(x: int): THash
+##   hashes.hash(x: float): THash
+##   …
+##
+## What is happening here is that the types used for table keys require to have
+## a ``hash()`` proc which will convert them to a `THash <hashes.html#THash>`_
+## value, and the compiler is listing all the hash functions it knows.
+## Additionally there has to be a ``==`` operator that provides the same
+## semantics as its corresponding ``hash`` proc.
+##
+## After you add ``hash`` and ``==`` for your custom type everything will work.
+## Currently however ``hash`` for objects is not defined, whereas
+## ``system.==`` for objects does exist and performs a "deep" comparison (every
+## field is compared) which is usually what you want. So in the following
+## example implementing only ``hash`` suffices:
+##
+## .. code-block::
+##   type
+##     Person = object
+##       firstName, lastName: string
+##
+##   proc hash(x: Person): THash =
+##     ## Piggyback on the already available string hash proc.
+##     ##
+##     ## Without this proc nothing works!
+##     result = x.firstName.hash !& x.lastName.hash
+##     result = !$result
+##
+##   var
+##     salaries = initTable[Person, int]()
+##     p1, p2: Person
+##
+##   p1.firstName = "Jon"
+##   p1.lastName = "Ross"
+##   salaries[p1] = 30_000
+##
+##   p2.firstName = "소진"
+##   p2.lastName = "ë°•"
+##   salaries[p2] = 45_000
+
+import
+  hashes, math
+
+{.pragma: myShallow.}
+
+type
+  KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B]
+  KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]]
+  Table* {.myShallow.}[A, B] = object ## generic hash table
+    data: KeyValuePairSeq[A, B]
+    counter: int
+  TableRef*[A,B] = ref Table[A, B]
+
+{.deprecated: [TTable: Table, PTable: TableRef].}
+
+when not defined(nimhygiene):
+  {.pragma: dirty.}
+
+# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
+# two procs retain clarity of that encoding without the space cost of an enum.
+proc isEmpty(hcode: THash): bool {.inline.} =
+  result = hcode == 0
+
+proc isFilled(hcode: THash): bool {.inline.} =
+  result = hcode != 0
+
+proc len*[A, B](t: Table[A, B]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A, B](t: Table[A, B]): (A, B) =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) =
+  ## iterates over any (key, value) pair in the table `t`. The values
+  ## can be modified.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: Table[A, B]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].key
+
+iterator values*[A, B](t: Table[A, B]): B =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].val
+
+iterator mvalues*[A, B](t: var Table[A, B]): var B =
+  ## iterates over any value in the table `t`. The values can be modified.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].val
+
+const
+  growthFactor = 2
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc rightSize*(count: Natural): int {.inline.} =
+  ## Return the value of `initialSize` to support `count` items.
+  ##
+  ## If more items are expected to be added, simply add that
+  ## expected extra amount to the parameter before calling this.
+  ##
+  ## Internally, we want mustRehash(rightSize(x), x) == false.
+  result = nextPowerOfTwo(count * 3 div 2  +  4)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = (h + 1) and maxHash
+
+template rawGetKnownHCImpl() {.dirty.} =
+  var h: THash = hc and high(t.data)   # start with real hash value
+  while isFilled(t.data[h].hcode):
+    # Compare hc THEN key with boolean short circuit. This makes the common case
+    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
+    # It does slow down succeeding lookups by one extra THash cmp&and..usually
+    # just a few clock cycles, generally worth it for any non-integer-like A.
+    if t.data[h].hcode == hc and t.data[h].key == key:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+template rawGetImpl() {.dirty.} =
+  hc = hash(key)
+  if hc == 0:       # This almost never taken branch should be very predictable.
+    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
+  rawGetKnownHCImpl()
+
+template rawGetDeepImpl() {.dirty.} =   # Search algo for unconditional add
+  hc = hash(key)
+  if hc == 0:
+    hc = 314159265
+  var h: THash = hc and high(t.data)
+  while isFilled(t.data[h].hcode):
+    h = nextTry(h, high(t.data))
+  result = h
+
+template rawInsertImpl() {.dirty.} =
+  data[h].key = key
+  data[h].val = val
+  data[h].hcode = hc
+
+proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetDeepImpl()
+
+proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: Table[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index >= 0: result = t.data[index].val
+
+proc mget*[A, B](t: var Table[A, B], key: A): var B =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``KeyError`` exception is raised.
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index >= 0: result = t.data[index].val
+  else:
+    when compiles($key):
+      raise newException(KeyError, "key not found: " & $key)
+    else:
+      raise newException(KeyError, "key not found")
+
+iterator allValues*[A, B](t: Table[A, B]; key: A): B =
+  ## iterates over any value in the table `t` that belongs to the given `key`.
+  var h: THash = hash(key) and high(t.data)
+  while isFilled(t.data[h].hcode):
+    if t.data[h].key == key:
+      yield t.data[h].val
+    h = nextTry(h, high(t.data))
+
+proc hasKey*[A, B](t: Table[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  var hc: THash
+  result = rawGet(t, key, hc) >= 0
+
+proc contains*[A, B](t: Table[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
+proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B],
+                     key: A, val: B, hc: THash, h: THash) =
+  rawInsertImpl()
+
+proc enlarge[A, B](t: var Table[A, B]) =
+  var n: KeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  swap(t.data, n)
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(t, n[i].key, n[i].hcode)
+      rawInsert(t, t.data, n[i].key, n[i].val, n[i].hcode, j)
+
+template addImpl() {.dirty.} =
+  if mustRehash(len(t.data), t.counter): enlarge(t)
+  var hc: THash
+  var j = rawGetDeep(t, key, hc)
+  rawInsert(t, t.data, key, val, hc, j)
+  inc(t.counter)
+
+template maybeRehashPutImpl() {.dirty.} =
+  if mustRehash(len(t.data), t.counter):
+    enlarge(t)
+    index = rawGetKnownHC(t, key, hc)
+  index = -1 - index                  # important to transform for mgetOrPutImpl
+  rawInsert(t, t.data, key, val, hc, index)
+  inc(t.counter)
+
+template putImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index >= 0: t.data[index].val = val
+  else: maybeRehashPutImpl()
+
+template mgetOrPutImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index < 0: maybeRehashPutImpl()    # not present: insert (flipping index)
+  result = t.data[index].val            # either way return modifiable val
+
+template hasKeyOrPutImpl() {.dirty.} =
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index < 0:
+    result = false
+    maybeRehashPutImpl()
+  else: result = true
+
+proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  mgetOrPutImpl()
+
+proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `value`.
+  hasKeyOrPutImpl()
+
+proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc add*[A, B](t: var Table[A, B], key: A, val: B) =
+  ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
+  addImpl()
+
+template doWhile(a: expr, b: stmt): stmt =
+  while true:
+    b
+    if not a: break
+
+proc del*[A, B](t: var Table[A, B], key: A) =
+  ## deletes `key` from hash table `t`.
+  var hc: THash
+  var i = rawGet(t, key, hc)
+  let msk = high(t.data)
+  if i >= 0:
+    t.data[i].hcode = 0
+    dec(t.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      t.data[i].hcode = 0              # mark current EMPTY
+      doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(t.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = t.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
+
+proc initTable*[A, B](initialSize=64): Table[A, B] =
+  ## creates a new hash table that is empty.
+  ##
+  ## `initialSize` needs to be a power of two. If you need to accept runtime
+  ## values for this you could use the ``nextPowerOfTwo`` proc from the
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toTable*[A, B](pairs: openArray[(A,
+                    B)]): Table[A, B] =
+  ## creates a new hash table that contains the given `pairs`.
+  result = initTable[A, B](rightSize(pairs.len))
+  for key, val in items(pairs): result[key] = val
+
+template dollarImpl(): stmt {.dirty.} =
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.add($key)
+      result.add(": ")
+      result.add($val)
+    result.add("}")
+
+proc `$`*[A, B](t: Table[A, B]): string =
+  ## The `$` operator for hash tables.
+  dollarImpl()
+
+template equalsImpl() =
+  if s.counter == t.counter:
+    # different insertion orders mean different 'data' seqs, so we have
+    # to use the slow route here:
+    for key, val in s:
+      # prefix notation leads to automatic dereference in case of PTable
+      if not t.hasKey(key): return false
+      if t[key] != val: return false
+    return true
+
+proc `==`*[A, B](s, t: Table[A, B]): bool =
+  equalsImpl()
+
+proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] =
+  ## Index the collection with the proc provided.
+  # TODO: As soon as supported, change collection: A to collection: A[B]
+  result = initTable[C, B]()
+  for item in collection:
+    result[index(item)] = item
+
+proc len*[A, B](t: TableRef[A, B]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A, B](t: TableRef[A, B]): (A, B) =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) =
+  ## iterates over any (key, value) pair in the table `t`. The values
+  ## can be modified.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: TableRef[A, B]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].key
+
+iterator values*[A, B](t: TableRef[A, B]): B =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].val
+
+iterator mvalues*[A, B](t: TableRef[A, B]): var B =
+  ## iterates over any value in the table `t`. The values can be modified.
+  for h in 0..high(t.data):
+    if isFilled(t.data[h].hcode): yield t.data[h].val
+
+proc `[]`*[A, B](t: TableRef[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  result = t[][key]
+
+proc mget*[A, B](t: TableRef[A, B], key: A): var B =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  t[].mget(key)
+
+proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  t[].mgetOrPut(key, val)
+
+proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `value`.
+  t[].hasKeyOrPut(key, val)
+
+proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = t[].hasKey(key)
+
+proc contains*[A, B](t: TableRef[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
+proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  t[][key] = val
+
+proc add*[A, B](t: TableRef[A, B], key: A, val: B) =
+  ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
+  t[].add(key, val)
+
+proc del*[A, B](t: TableRef[A, B], key: A) =
+  ## deletes `key` from hash table `t`.
+  t[].del(key)
+
+proc newTable*[A, B](initialSize=64): TableRef[A, B] =
+  new(result)
+  result[] = initTable[A, B](initialSize)
+
+proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] =
+  ## creates a new hash table that contains the given `pairs`.
+  new(result)
+  result[] = toTable[A, B](pairs)
+
+proc `$`*[A, B](t: TableRef[A, B]): string =
+  ## The `$` operator for hash tables.
+  dollarImpl()
+
+proc `==`*[A, B](s, t: TableRef[A, B]): bool =
+  if isNil(s): result = isNil(t)
+  elif isNil(t): result = false
+  else: equalsImpl()
+
+proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
+  ## Index the collection with the proc provided.
+  # TODO: As soon as supported, change collection: A to collection: A[B]
+  result = newTable[C, B]()
+  for item in collection:
+    result[index(item)] = item
+
+# ------------------------------ ordered table ------------------------------
+
+type
+  OrderedKeyValuePair[A, B] = tuple[
+    hcode: THash, next: int, key: A, val: B]
+  OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]]
+  OrderedTable* {.
+      myShallow.}[A, B] = object ## table that remembers insertion order
+    data: OrderedKeyValuePairSeq[A, B]
+    counter, first, last: int
+  OrderedTableRef*[A, B] = ref OrderedTable[A, B]
+
+{.deprecated: [TOrderedTable: OrderedTable, POrderedTable: OrderedTableRef].}
+
+proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
+  var h = t.first
+  while h >= 0:
+    var nxt = t.data[h].next
+    if isFilled(t.data[h].hcode): yieldStmt
+    h = nxt
+
+iterator pairs*[A, B](t: OrderedTable[A, B]): (A, B) =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order. The values can be modified.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: OrderedTable[A, B]): A =
+  ## iterates over any key in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].key
+
+iterator values*[A, B](t: OrderedTable[A, B]): B =
+  ## iterates over any value in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
+  ## iterates over any value in the table `t` in insertion order. The values
+  ## can be modified.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int =
+  rawGetKnownHCImpl()
+
+proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} =
+  rawGetDeepImpl()
+
+proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index >= 0: result = t.data[index].val
+
+proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  var hc: THash
+  var index = rawGet(t, key, hc)
+  if index >= 0: result = t.data[index].val
+  else: raise newException(KeyError, "key not found: " & $key)
+
+proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  var hc: THash
+  result = rawGet(t, key, hc) >= 0
+
+proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
+proc rawInsert[A, B](t: var OrderedTable[A, B],
+                     data: var OrderedKeyValuePairSeq[A, B],
+                     key: A, val: B, hc: THash, h: THash) =
+  rawInsertImpl()
+  data[h].next = -1
+  if t.first < 0: t.first = h
+  if t.last >= 0: data[t.last].next = h
+  t.last = h
+
+proc enlarge[A, B](t: var OrderedTable[A, B]) =
+  var n: OrderedKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  var h = t.first
+  t.first = -1
+  t.last = -1
+  swap(t.data, n)
+  while h >= 0:
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode)
+      rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j)
+    h = nxt
+
+proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
+  ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
+  addImpl()
+
+proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``value`` if not present, either way
+  ## returning a value which can be modified.
+  mgetOrPutImpl()
+
+proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `value`.
+  hasKeyOrPutImpl()
+
+proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
+  ## creates a new ordered hash table that is empty.
+  ##
+  ## `initialSize` needs to be a power of two. If you need to accept runtime
+  ## values for this you could use the ``nextPowerOfTwo`` proc from the
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  result.first = -1
+  result.last = -1
+  newSeq(result.data, initialSize)
+
+proc toOrderedTable*[A, B](pairs: openArray[(A,
+                           B)]): OrderedTable[A, B] =
+  ## creates a new ordered hash table that contains the given `pairs`.
+  result = initOrderedTable[A, B](rightSize(pairs.len))
+  for key, val in items(pairs): result[key] = val
+
+proc `$`*[A, B](t: OrderedTable[A, B]): string =
+  ## The `$` operator for ordered hash tables.
+  dollarImpl()
+
+proc sort*[A, B](t: var OrderedTable[A, B],
+                 cmp: proc (x,y: (A, B)): int) =
+  ## sorts `t` according to `cmp`. This modifies the internal list
+  ## that kept the insertion order, so insertion order is lost after this
+  ## call but key lookup and insertions remain possible after `sort` (in
+  ## contrast to the `sort` for count tables).
+  var list = t.first
+  var
+    p, q, e, tail, oldhead: int
+    nmerges, psize, qsize, i: int
+  if t.counter == 0: return
+  var insize = 1
+  while true:
+    p = list; oldhead = list
+    list = -1; tail = -1; nmerges = 0
+    while p >= 0:
+      inc(nmerges)
+      q = p
+      psize = 0
+      i = 0
+      while i < insize:
+        inc(psize)
+        q = t.data[q].next
+        if q < 0: break
+        inc(i)
+      qsize = insize
+      while psize > 0 or (qsize > 0 and q >= 0):
+        if psize == 0:
+          e = q; q = t.data[q].next; dec(qsize)
+        elif qsize == 0 or q < 0:
+          e = p; p = t.data[p].next; dec(psize)
+        elif cmp((t.data[p].key, t.data[p].val),
+                 (t.data[q].key, t.data[q].val)) <= 0:
+          e = p; p = t.data[p].next; dec(psize)
+        else:
+          e = q; q = t.data[q].next; dec(qsize)
+        if tail >= 0: t.data[tail].next = e
+        else: list = e
+        tail = e
+      p = q
+    t.data[tail].next = -1
+    if nmerges <= 1: break
+    insize = insize * 2
+  t.first = list
+  t.last = tail
+
+proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
+  var h = t.first
+  while h >= 0:
+    var nxt = t.data[h].next
+    if isFilled(t.data[h].hcode): yieldStmt
+    h = nxt
+
+iterator pairs*[A, B](t: OrderedTableRef[A, B]): (A, B) =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order. The values can be modified.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: OrderedTableRef[A, B]): A =
+  ## iterates over any key in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].key
+
+iterator values*[A, B](t: OrderedTableRef[A, B]): B =
+  ## iterates over any value in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
+  ## iterates over any value in the table `t` in insertion order. The values
+  ## can be modified.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  result = t[][key]
+
+proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  result = t[].mget(key)
+
+proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
+  ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
+  ## returning a value which can be modified.
+  result = t[].mgetOrPut(key, val)
+
+proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
+  ## returns true iff `key` is in the table, otherwise inserts `val`.
+  result = t[].hasKeyOrPut(key, val)
+
+proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = t[].hasKey(key)
+
+proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A, B](t, key)
+
+proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  t[][key] = val
+
+proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
+  ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
+  t[].add(key, val)
+
+proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
+  ## creates a new ordered hash table that is empty.
+  ##
+  ## `initialSize` needs to be a power of two. If you need to accept runtime
+  ## values for this you could use the ``nextPowerOfTwo`` proc from the
+  ## `math <math.html>`_ module or the ``rightSize`` proc from this module.
+  new(result)
+  result[] = initOrderedTable[A, B]()
+
+proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
+  ## creates a new ordered hash table that contains the given `pairs`.
+  result = newOrderedTable[A, B](rightSize(pairs.len))
+  for key, val in items(pairs): result[key] = val
+
+proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
+  ## The `$` operator for ordered hash tables.
+  dollarImpl()
+
+proc sort*[A, B](t: OrderedTableRef[A, B],
+                 cmp: proc (x,y: (A, B)): int) =
+  ## sorts `t` according to `cmp`. This modifies the internal list
+  ## that kept the insertion order, so insertion order is lost after this
+  ## call but key lookup and insertions remain possible after `sort` (in
+  ## contrast to the `sort` for count tables).
+  t[].sort(cmp)
+
+# ------------------------------ count tables -------------------------------
+
+type
+  CountTable* {.myShallow.}[
+      A] = object ## table that counts the number of each key
+    data: seq[tuple[key: A, val: int]]
+    counter: int
+  CountTableRef*[A] = ref CountTable[A]
+
+{.deprecated: [TCountTable: CountTable, PCountTable: CountTableRef].}
+
+proc len*[A](t: CountTable[A]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A](t: CountTable[A]): (A, int) =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A](t: var CountTable[A]): (A, var int) =
+  ## iterates over any (key, value) pair in the table `t`. The values can
+  ## be modified.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A](t: CountTable[A]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].key
+
+iterator values*[A](t: CountTable[A]): int =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+iterator mvalues*[A](t: CountTable[A]): var int =
+  ## iterates over any value in the table `t`. The values can be modified.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+proc rawGet[A](t: CountTable[A], key: A): int =
+  var h: THash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].val != 0:
+    if t.data[h].key == key: return h
+    h = nextTry(h, high(t.data))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+proc `[]`*[A](t: CountTable[A], key: A): int =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## 0 is returned. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc mget*[A](t: var CountTable[A], key: A): var int =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: raise newException(KeyError, "key not found: " & $key)
+
+proc hasKey*[A](t: CountTable[A], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc contains*[A](t: CountTable[A], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A](t, key)
+
+proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
+                  key: A, val: int) =
+  var h: THash = hash(key) and high(data)
+  while data[h].val != 0: h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+
+proc enlarge[A](t: var CountTable[A]) =
+  var n: seq[tuple[key: A, val: int]]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
+  ## puts a (key, value)-pair into `t`.
+  assert val > 0
+  var h = rawGet(t, key)
+  if h >= 0:
+    t.data[h].val = val
+  else:
+    if mustRehash(len(t.data), t.counter): enlarge(t)
+    rawInsert(t, t.data, key, val)
+    inc(t.counter)
+    #h = -1 - h
+    #t.data[h].key = key
+    #t.data[h].val = val
+
+proc initCountTable*[A](initialSize=64): CountTable[A] =
+  ## creates a new count table that is empty.
+  ##
+  ## `initialSize` needs to be a power of two. If you need to accept runtime
+  ## values for this you could use the ``nextPowerOfTwo`` proc from the
+  ## `math <math.html>`_ module or the ``rightSize`` proc in this module.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
+  ## creates a new count table with every key in `keys` having a count of 1.
+  result = initCountTable[A](rightSize(keys.len))
+  for key in items(keys): result[key] = 1
+
+proc `$`*[A](t: CountTable[A]): string =
+  ## The `$` operator for count tables.
+  dollarImpl()
+
+proc inc*[A](t: var CountTable[A], key: A, val = 1) =
+  ## increments `t[key]` by `val`.
+  var index = rawGet(t, key)
+  if index >= 0:
+    inc(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 smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
+  ## returns the largest (key,val)-pair. Efficiency: O(n)
+  assert t.len > 0
+  var minIdx = 0
+  for h in 1..high(t.data):
+    if t.data[h].val > 0 and t.data[minIdx].val > t.data[h].val: minIdx = h
+  result.key = t.data[minIdx].key
+  result.val = t.data[minIdx].val
+
+proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] =
+  ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
+  assert t.len > 0
+  var maxIdx = 0
+  for h in 1..high(t.data):
+    if t.data[maxIdx].val < t.data[h].val: maxIdx = h
+  result.key = t.data[maxIdx].key
+  result.val = t.data[maxIdx].val
+
+proc sort*[A](t: var CountTable[A]) =
+  ## sorts the count table so that the entry with the highest counter comes
+  ## first. This is destructive! You must not modify `t` afterwards!
+  ## You can use the iterators `pairs`,  `keys`, and `values` to iterate over
+  ## `t` in the sorted order.
+
+  # we use shellsort here; fast enough and simple
+  var h = 1
+  while true:
+    h = 3 * h + 1
+    if h >= high(t.data): break
+  while true:
+    h = h div 3
+    for i in countup(h, high(t.data)):
+      var j = i
+      while t.data[j-h].val <= t.data[j].val:
+        swap(t.data[j], t.data[j-h])
+        j = j-h
+        if j < h: break
+    if h == 1: break
+
+proc len*[A](t: CountTableRef[A]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A](t: CountTableRef[A]): (A, int) =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A](t: CountTableRef[A]): (A, var int) =
+  ## iterates over any (key, value) pair in the table `t`. The values can
+  ## be modified.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A](t: CountTableRef[A]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].key
+
+iterator values*[A](t: CountTableRef[A]): int =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+iterator mvalues*[A](t: CountTableRef[A]): var int =
+  ## iterates over any value in the table `t`. The values can be modified.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+proc `[]`*[A](t: CountTableRef[A], key: A): int =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## 0 is returned. One can check with ``hasKey`` whether the key
+  ## exists.
+  result = t[][key]
+
+proc mget*[A](t: CountTableRef[A], key: A): var int =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  result = t[].mget(key)
+
+proc hasKey*[A](t: CountTableRef[A], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = t[].hasKey(key)
+
+proc contains*[A](t: CountTableRef[A], key: A): bool =
+  ## alias of `hasKey` for use with the `in` operator.
+  return hasKey[A](t, key)
+
+proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) =
+  ## puts a (key, value)-pair into `t`. `val` has to be positive.
+  assert val > 0
+  t[][key] = val
+
+proc newCountTable*[A](initialSize=64): CountTableRef[A] =
+  ## creates a new count table that is empty.
+  ##
+  ## `initialSize` needs to be a power of two. If you need to accept runtime
+  ## values for this you could use the ``nextPowerOfTwo`` proc from the
+  ## `math <math.html>`_ module or the ``rightSize`` method in this module.
+  new(result)
+  result[] = initCountTable[A](initialSize)
+
+proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
+  ## creates a new count table with every key in `keys` having a count of 1.
+  result = newCountTable[A](rightSize(keys.len))
+  for key in items(keys): result[key] = 1
+
+proc `$`*[A](t: CountTableRef[A]): string =
+  ## The `$` operator for count tables.
+  dollarImpl()
+
+proc inc*[A](t: CountTableRef[A], key: A, val = 1) =
+  ## increments `t[key]` by `val`.
+  t[].inc(key, val)
+
+proc smallest*[A](t: CountTableRef[A]): (A, int) =
+  ## returns the largest (key,val)-pair. Efficiency: O(n)
+  t[].smallest
+
+proc largest*[A](t: CountTableRef[A]): (A, int) =
+  ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
+  t[].largest
+
+proc sort*[A](t: CountTableRef[A]) =
+  ## sorts the count table so that the entry with the highest counter comes
+  ## first. This is destructive! You must not modify `t` afterwards!
+  ## You can use the iterators `pairs`,  `keys`, and `values` to iterate over
+  ## `t` in the sorted order.
+  t[].sort
+
+proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
+  ## merges the second table into the first one
+  for key, value in t:
+    s.inc(key, value)
+
+proc merge*[A](s, t: CountTable[A]): CountTable[A] =
+  ## merges the two tables into a new one
+  result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
+  for table in @[s, t]:
+    for key, value in table:
+      result.inc(key, value)
+
+proc merge*[A](s, t: CountTableRef[A]) =
+  ## merges the second table into the first one
+  s[].merge(t[])
+
+when isMainModule:
+  type
+    Person = object
+      firstName, lastName: string
+
+  proc hash(x: Person): THash =
+    ## Piggyback on the already available string hash proc.
+    ##
+    ## Without this proc nothing works!
+    result = x.firstName.hash !& x.lastName.hash
+    result = !$result
+
+  var
+    salaries = initTable[Person, int]()
+    p1, p2: Person
+  p1.firstName = "Jon"
+  p1.lastName = "Ross"
+  salaries[p1] = 30_000
+  p2.firstName = "소진"
+  p2.lastName = "ë°•"
+  salaries[p2] = 45_000
+  var
+    s2 = initOrderedTable[Person, int]()
+    s3 = initCountTable[Person]()
+  s2[p1] = 30_000
+  s2[p2] = 45_000
+  s3[p1] = 30_000
+  s3[p2] = 45_000
+
+  var
+    t1 = initCountTable[string]()
+    t2 = initCountTable[string]()
+  t1.inc("foo")
+  t1.inc("bar", 2)
+  t1.inc("baz", 3)
+  t2.inc("foo", 4)
+  t2.inc("bar")
+  t2.inc("baz", 11)
+  merge(t1, t2)
+  assert(t1["foo"] == 5)
+  assert(t1["bar"] == 3)
+  assert(t1["baz"] == 14)
+
+  let
+    t1r = newCountTable[string]()
+    t2r = newCountTable[string]()
+  t1r.inc("foo")
+  t1r.inc("bar", 2)
+  t1r.inc("baz", 3)
+  t2r.inc("foo", 4)
+  t2r.inc("bar")
+  t2r.inc("baz", 11)
+  merge(t1r, t2r)
+  assert(t1r["foo"] == 5)
+  assert(t1r["bar"] == 3)
+  assert(t1r["baz"] == 14)
+
+  var
+    t1l = initCountTable[string]()
+    t2l = initCountTable[string]()
+  t1l.inc("foo")
+  t1l.inc("bar", 2)
+  t1l.inc("baz", 3)
+  t2l.inc("foo", 4)
+  t2l.inc("bar")
+  t2l.inc("baz", 11)
+  let
+    t1merging = t1l
+    t2merging = t2l
+  let merged = merge(t1merging, t2merging)
+  assert(merged["foo"] == 5)
+  assert(merged["bar"] == 3)
+  assert(merged["baz"] == 14)
diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim
new file mode 100644
index 000000000..f24cc0072
--- /dev/null
+++ b/lib/pure/colors.nim
@@ -0,0 +1,411 @@
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements color handling for Nimrod. It is used by 
+## the ``graphics`` module.
+
+import strutils
+
+type
+  Color* = distinct int ## a color stored as RGB
+
+{.deprecated: [TColor: Color].}
+
+proc `==` *(a, b: Color): bool {.borrow.}
+  ## compares two colors.
+  
+template extract(a: Color, r, g, b: expr) {.immediate.}=
+  var r = a.int shr 16 and 0xff
+  var g = a.int shr 8 and 0xff
+  var b = a.int and 0xff
+  
+template rawRGB(r, g, b: int): expr =
+  Color(r shl 16 or g shl 8 or b)
+  
+template colorOp(op: expr) {.immediate.} =
+  extract(a, ar, ag, ab)
+  extract(b, br, bg, bb)
+  result = rawRGB(op(ar, br), op(ag, bg), op(ab, bb))
+
+proc satPlus(a, b: int): int {.inline.} =
+  result = a +% b
+  if result > 255: result = 255
+
+proc satMinus(a, b: int): int {.inline.} =
+  result = a -% b
+  if result < 0: result = 0
+  
+proc `+`*(a, b: Color): Color =
+  ## adds two colors: This uses saturated artithmetic, so that each color
+  ## component cannot overflow (255 is used as a maximum).
+  colorOp(satPlus)
+  
+proc `-`*(a, b: Color): Color =
+  ## subtracts two colors: This uses saturated artithmetic, so that each color
+  ## component cannot overflow (255 is used as a maximum).
+  colorOp(satMinus)
+  
+proc extractRGB*(a: Color): tuple[r, g, b: range[0..255]] =
+  ## extracts the red/green/blue components of the color `a`.
+  result.r = a.int shr 16 and 0xff
+  result.g = a.int shr 8 and 0xff
+  result.b = a.int and 0xff
+  
+proc intensity*(a: Color, f: float): Color = 
+  ## returns `a` with intensity `f`. `f` should be a float from 0.0 (completely
+  ## dark) to 1.0 (full color intensity).
+  var r = toInt(toFloat(a.int shr 16 and 0xff) * f)
+  var g = toInt(toFloat(a.int shr 8 and 0xff) * f)
+  var b = toInt(toFloat(a.int and 0xff) * f)
+  if r >% 255: r = 255
+  if g >% 255: g = 255
+  if b >% 255: b = 255
+  result = rawRGB(r, g, b)
+  
+template mix*(a, b: Color, fn: expr): expr =
+  ## uses `fn` to mix the colors `a` and `b`. `fn` is invoked for each component
+  ## R, G, and B. This is a template because `fn` should be inlined and the
+  ## compiler cannot inline proc pointers yet. If `fn`'s result is not in the
+  ## range[0..255], it will be saturated to be so.
+  template `><` (x: expr): expr =
+    # keep it in the range 0..255
+    block:
+      var y = x # eval only once
+      if y >% 255:
+        y = if y < 0: 0 else: 255
+      y
+  
+  (bind extract)(a, ar, ag, ab)
+  (bind extract)(b, br, bg, bb)
+  (bind rawRGB)(><fn(ar, br), ><fn(ag, bg), ><fn(ab, bb))
+
+
+const
+  colAliceBlue* = Color(0xF0F8FF)
+  colAntiqueWhite* = Color(0xFAEBD7)
+  colAqua* = Color(0x00FFFF)
+  colAquamarine* = Color(0x7FFFD4)
+  colAzure* = Color(0xF0FFFF)
+  colBeige* = Color(0xF5F5DC)
+  colBisque* = Color(0xFFE4C4)
+  colBlack* = Color(0x000000)
+  colBlanchedAlmond* = Color(0xFFEBCD)
+  colBlue* = Color(0x0000FF)
+  colBlueViolet* = Color(0x8A2BE2)
+  colBrown* = Color(0xA52A2A)
+  colBurlyWood* = Color(0xDEB887)
+  colCadetBlue* = Color(0x5F9EA0)
+  colChartreuse* = Color(0x7FFF00)
+  colChocolate* = Color(0xD2691E)
+  colCoral* = Color(0xFF7F50)
+  colCornflowerBlue* = Color(0x6495ED)
+  colCornsilk* = Color(0xFFF8DC)
+  colCrimson* = Color(0xDC143C)
+  colCyan* = Color(0x00FFFF)
+  colDarkBlue* = Color(0x00008B)
+  colDarkCyan* = Color(0x008B8B)
+  colDarkGoldenRod* = Color(0xB8860B)
+  colDarkGray* = Color(0xA9A9A9)
+  colDarkGreen* = Color(0x006400)
+  colDarkKhaki* = Color(0xBDB76B)
+  colDarkMagenta* = Color(0x8B008B)
+  colDarkOliveGreen* = Color(0x556B2F)
+  colDarkorange* = Color(0xFF8C00)
+  colDarkOrchid* = Color(0x9932CC)
+  colDarkRed* = Color(0x8B0000)
+  colDarkSalmon* = Color(0xE9967A)
+  colDarkSeaGreen* = Color(0x8FBC8F)
+  colDarkSlateBlue* = Color(0x483D8B)
+  colDarkSlateGray* = Color(0x2F4F4F)
+  colDarkTurquoise* = Color(0x00CED1)
+  colDarkViolet* = Color(0x9400D3)
+  colDeepPink* = Color(0xFF1493)
+  colDeepSkyBlue* = Color(0x00BFFF)
+  colDimGray* = Color(0x696969)
+  colDodgerBlue* = Color(0x1E90FF)
+  colFireBrick* = Color(0xB22222)
+  colFloralWhite* = Color(0xFFFAF0)
+  colForestGreen* = Color(0x228B22)
+  colFuchsia* = Color(0xFF00FF)
+  colGainsboro* = Color(0xDCDCDC)
+  colGhostWhite* = Color(0xF8F8FF)
+  colGold* = Color(0xFFD700)
+  colGoldenRod* = Color(0xDAA520)
+  colGray* = Color(0x808080)
+  colGreen* = Color(0x008000)
+  colGreenYellow* = Color(0xADFF2F)
+  colHoneyDew* = Color(0xF0FFF0)
+  colHotPink* = Color(0xFF69B4)
+  colIndianRed* = Color(0xCD5C5C)
+  colIndigo* = Color(0x4B0082)
+  colIvory* = Color(0xFFFFF0)
+  colKhaki* = Color(0xF0E68C)
+  colLavender* = Color(0xE6E6FA)
+  colLavenderBlush* = Color(0xFFF0F5)
+  colLawnGreen* = Color(0x7CFC00)
+  colLemonChiffon* = Color(0xFFFACD)
+  colLightBlue* = Color(0xADD8E6)
+  colLightCoral* = Color(0xF08080)
+  colLightCyan* = Color(0xE0FFFF)
+  colLightGoldenRodYellow* = Color(0xFAFAD2)
+  colLightGrey* = Color(0xD3D3D3)
+  colLightGreen* = Color(0x90EE90)
+  colLightPink* = Color(0xFFB6C1)
+  colLightSalmon* = Color(0xFFA07A)
+  colLightSeaGreen* = Color(0x20B2AA)
+  colLightSkyBlue* = Color(0x87CEFA)
+  colLightSlateGray* = Color(0x778899)
+  colLightSteelBlue* = Color(0xB0C4DE)
+  colLightYellow* = Color(0xFFFFE0)
+  colLime* = Color(0x00FF00)
+  colLimeGreen* = Color(0x32CD32)
+  colLinen* = Color(0xFAF0E6)
+  colMagenta* = Color(0xFF00FF)
+  colMaroon* = Color(0x800000)
+  colMediumAquaMarine* = Color(0x66CDAA)
+  colMediumBlue* = Color(0x0000CD)
+  colMediumOrchid* = Color(0xBA55D3)
+  colMediumPurple* = Color(0x9370D8)
+  colMediumSeaGreen* = Color(0x3CB371)
+  colMediumSlateBlue* = Color(0x7B68EE)
+  colMediumSpringGreen* = Color(0x00FA9A)
+  colMediumTurquoise* = Color(0x48D1CC)
+  colMediumVioletRed* = Color(0xC71585)
+  colMidnightBlue* = Color(0x191970)
+  colMintCream* = Color(0xF5FFFA)
+  colMistyRose* = Color(0xFFE4E1)
+  colMoccasin* = Color(0xFFE4B5)
+  colNavajoWhite* = Color(0xFFDEAD)
+  colNavy* = Color(0x000080)
+  colOldLace* = Color(0xFDF5E6)
+  colOlive* = Color(0x808000)
+  colOliveDrab* = Color(0x6B8E23)
+  colOrange* = Color(0xFFA500)
+  colOrangeRed* = Color(0xFF4500)
+  colOrchid* = Color(0xDA70D6)
+  colPaleGoldenRod* = Color(0xEEE8AA)
+  colPaleGreen* = Color(0x98FB98)
+  colPaleTurquoise* = Color(0xAFEEEE)
+  colPaleVioletRed* = Color(0xD87093)
+  colPapayaWhip* = Color(0xFFEFD5)
+  colPeachPuff* = Color(0xFFDAB9)
+  colPeru* = Color(0xCD853F)
+  colPink* = Color(0xFFC0CB)
+  colPlum* = Color(0xDDA0DD)
+  colPowderBlue* = Color(0xB0E0E6)
+  colPurple* = Color(0x800080)
+  colRed* = Color(0xFF0000)
+  colRosyBrown* = Color(0xBC8F8F)
+  colRoyalBlue* = Color(0x4169E1)
+  colSaddleBrown* = Color(0x8B4513)
+  colSalmon* = Color(0xFA8072)
+  colSandyBrown* = Color(0xF4A460)
+  colSeaGreen* = Color(0x2E8B57)
+  colSeaShell* = Color(0xFFF5EE)
+  colSienna* = Color(0xA0522D)
+  colSilver* = Color(0xC0C0C0)
+  colSkyBlue* = Color(0x87CEEB)
+  colSlateBlue* = Color(0x6A5ACD)
+  colSlateGray* = Color(0x708090)
+  colSnow* = Color(0xFFFAFA)
+  colSpringGreen* = Color(0x00FF7F)
+  colSteelBlue* = Color(0x4682B4)
+  colTan* = Color(0xD2B48C)
+  colTeal* = Color(0x008080)
+  colThistle* = Color(0xD8BFD8)
+  colTomato* = Color(0xFF6347)
+  colTurquoise* = Color(0x40E0D0)
+  colViolet* = Color(0xEE82EE)
+  colWheat* = Color(0xF5DEB3)
+  colWhite* = Color(0xFFFFFF)
+  colWhiteSmoke* = Color(0xF5F5F5)
+  colYellow* = Color(0xFFFF00)
+  colYellowGreen* = Color(0x9ACD32)
+  
+  colorNames = [
+    ("aliceblue", colAliceBlue),
+    ("antiquewhite", colAntiqueWhite),
+    ("aqua", colAqua),
+    ("aquamarine", colAquamarine),
+    ("azure", colAzure),
+    ("beige", colBeige),
+    ("bisque", colBisque),
+    ("black", colBlack),
+    ("blanchedalmond", colBlanchedAlmond),
+    ("blue", colBlue),
+    ("blueviolet", colBlueViolet),
+    ("brown", colBrown),
+    ("burlywood", colBurlyWood),
+    ("cadetblue", colCadetBlue),
+    ("chartreuse", colChartreuse),
+    ("chocolate", colChocolate),
+    ("coral", colCoral),
+    ("cornflowerblue", colCornflowerBlue),
+    ("cornsilk", colCornsilk),
+    ("crimson", colCrimson),
+    ("cyan", colCyan),
+    ("darkblue", colDarkBlue),
+    ("darkcyan", colDarkCyan),
+    ("darkgoldenrod", colDarkGoldenRod),
+    ("darkgray", colDarkGray),
+    ("darkgreen", colDarkGreen),
+    ("darkkhaki", colDarkKhaki),
+    ("darkmagenta", colDarkMagenta),
+    ("darkolivegreen", colDarkOliveGreen),
+    ("darkorange", colDarkorange),
+    ("darkorchid", colDarkOrchid),
+    ("darkred", colDarkRed),
+    ("darksalmon", colDarkSalmon),
+    ("darkseagreen", colDarkSeaGreen),
+    ("darkslateblue", colDarkSlateBlue),
+    ("darkslategray", colDarkSlateGray),
+    ("darkturquoise", colDarkTurquoise),
+    ("darkviolet", colDarkViolet),
+    ("deeppink", colDeepPink),
+    ("deepskyblue", colDeepSkyBlue),
+    ("dimgray", colDimGray),
+    ("dodgerblue", colDodgerBlue),
+    ("firebrick", colFireBrick),
+    ("floralwhite", colFloralWhite),
+    ("forestgreen", colForestGreen),
+    ("fuchsia", colFuchsia),
+    ("gainsboro", colGainsboro),
+    ("ghostwhite", colGhostWhite),
+    ("gold", colGold),
+    ("goldenrod", colGoldenRod),
+    ("gray", colGray),
+    ("green", colGreen),
+    ("greenyellow", colGreenYellow),
+    ("honeydew", colHoneyDew),
+    ("hotpink", colHotPink),
+    ("indianred", colIndianRed),
+    ("indigo", colIndigo),
+    ("ivory", colIvory),
+    ("khaki", colKhaki),
+    ("lavender", colLavender),
+    ("lavenderblush", colLavenderBlush),
+    ("lawngreen", colLawnGreen),
+    ("lemonchiffon", colLemonChiffon),
+    ("lightblue", colLightBlue),
+    ("lightcoral", colLightCoral),
+    ("lightcyan", colLightCyan),
+    ("lightgoldenrodyellow", colLightGoldenRodYellow),
+    ("lightgrey", colLightGrey),
+    ("lightgreen", colLightGreen),
+    ("lightpink", colLightPink),
+    ("lightsalmon", colLightSalmon),
+    ("lightseagreen", colLightSeaGreen),
+    ("lightskyblue", colLightSkyBlue),
+    ("lightslategray", colLightSlateGray),
+    ("lightsteelblue", colLightSteelBlue),
+    ("lightyellow", colLightYellow),
+    ("lime", colLime),
+    ("limegreen", colLimeGreen),
+    ("linen", colLinen),
+    ("magenta", colMagenta),
+    ("maroon", colMaroon),
+    ("mediumaquamarine", colMediumAquaMarine),
+    ("mediumblue", colMediumBlue),
+    ("mediumorchid", colMediumOrchid),
+    ("mediumpurple", colMediumPurple),
+    ("mediumseagreen", colMediumSeaGreen),
+    ("mediumslateblue", colMediumSlateBlue),
+    ("mediumspringgreen", colMediumSpringGreen),
+    ("mediumturquoise", colMediumTurquoise),
+    ("mediumvioletred", colMediumVioletRed),
+    ("midnightblue", colMidnightBlue),
+    ("mintcream", colMintCream),
+    ("mistyrose", colMistyRose),
+    ("moccasin", colMoccasin),
+    ("navajowhite", colNavajoWhite),
+    ("navy", colNavy),
+    ("oldlace", colOldLace),
+    ("olive", colOlive),
+    ("olivedrab", colOliveDrab),
+    ("orange", colOrange),
+    ("orangered", colOrangeRed),
+    ("orchid", colOrchid),
+    ("palegoldenrod", colPaleGoldenRod),
+    ("palegreen", colPaleGreen),
+    ("paleturquoise", colPaleTurquoise),
+    ("palevioletred", colPaleVioletRed),
+    ("papayawhip", colPapayaWhip),
+    ("peachpuff", colPeachPuff),
+    ("peru", colPeru),
+    ("pink", colPink),
+    ("plum", colPlum),
+    ("powderblue", colPowderBlue),
+    ("purple", colPurple),
+    ("red", colRed),
+    ("rosybrown", colRosyBrown),
+    ("royalblue", colRoyalBlue),
+    ("saddlebrown", colSaddleBrown),
+    ("salmon", colSalmon),
+    ("sandybrown", colSandyBrown),
+    ("seagreen", colSeaGreen),
+    ("seashell", colSeaShell),
+    ("sienna", colSienna),
+    ("silver", colSilver),
+    ("skyblue", colSkyBlue),
+    ("slateblue", colSlateBlue),
+    ("slategray", colSlateGray),
+    ("snow", colSnow),
+    ("springgreen", colSpringGreen),
+    ("steelblue", colSteelBlue),
+    ("tan", colTan),
+    ("teal", colTeal),
+    ("thistle", colThistle),
+    ("tomato", colTomato),
+    ("turquoise", colTurquoise),
+    ("violet", colViolet),
+    ("wheat", colWheat),
+    ("white", colWhite),
+    ("whitesmoke", colWhiteSmoke),
+    ("yellow", colYellow),
+    ("yellowgreen", colYellowGreen)]
+
+proc `$`*(c: Color): string = 
+  ## converts a color into its textual representation. Example: ``#00FF00``.
+  result = '#' & toHex(int(c), 6)
+
+proc binaryStrSearch(x: openArray[tuple[name: string, col: Color]], 
+                     y: string): int = 
+  var a = 0
+  var b = len(x) - 1
+  while a <= b: 
+    var mid = (a + b) div 2
+    var c = cmp(x[mid].name, y)
+    if c < 0: a = mid + 1
+    elif c > 0: b = mid - 1
+    else: return mid
+  result = - 1
+  
+proc parseColor*(name: string): Color = 
+  ## parses `name` to a color value. If no valid color could be 
+  ## parsed ``EInvalidValue`` is raised.
+  if name[0] == '#':
+    result = Color(parseHexInt(name))
+  else:
+    var idx = binaryStrSearch(colorNames, name)
+    if idx < 0: raise newException(ValueError, "unknown color: " & name)
+    result = colorNames[idx][1]
+
+proc isColor*(name: string): bool =
+  ## returns true if `name` is a known color name or a hexadecimal color 
+  ## prefixed with ``#``.
+  if name[0] == '#': 
+    for i in 1 .. name.len-1: 
+      if name[i] notin {'0'..'9', 'a'..'f', 'A'..'F'}: return false
+    result = true
+  else:
+    result = binaryStrSearch(colorNames, name) >= 0
+
+proc rgb*(r, g, b: range[0..255]): Color =
+  ## constructs a color from RGB values.
+  result = rawRGB(r, g, b)
+
diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim
new file mode 100644
index 000000000..8577bf7a1
--- /dev/null
+++ b/lib/pure/complex.nim
@@ -0,0 +1,443 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+
+## This module implements complex numbers.
+{.push checks:off, line_dir:off, stack_trace:off, debugger:off.}
+# the user does not want to trace a part
+# of the standard library!
+
+
+import
+  math
+ 
+const
+  EPS = 1.0e-7 ## Epsilon used for float comparisons.
+
+type
+  Complex* = tuple[re, im: float]
+    ## a complex number, consisting of a real and an imaginary part
+
+{.deprecated: [TComplex: Complex].}
+
+proc toComplex*(x: SomeInteger): Complex =
+  ## Convert some integer ``x`` to a complex number.
+  result.re = x
+  result.im = 0
+
+proc `==` *(x, y: Complex): bool =
+  ## Compare two complex numbers `x` and `y` for equality.
+  result = x.re == y.re and x.im == y.im
+
+proc `=~` *(x, y: Complex): bool =
+  ## Compare two complex numbers `x` and `y` approximately.
+  result = abs(x.re-y.re)<EPS and abs(x.im-y.im)<EPS
+
+proc `+` *(x, y: Complex): Complex =
+  ## Add two complex numbers.
+  result.re = x.re + y.re
+  result.im = x.im + y.im
+
+proc `+` *(x: Complex, y: float): Complex =
+  ## Add complex `x` to float `y`.
+  result.re = x.re + y
+  result.im = x.im
+
+proc `+` *(x: float, y: Complex): Complex =
+  ## Add float `x` to complex `y`.
+  result.re = x + y.re
+  result.im = y.im
+
+
+proc `-` *(z: Complex): Complex =
+  ## Unary minus for complex numbers.
+  result.re = -z.re
+  result.im = -z.im
+
+proc `-` *(x, y: Complex): Complex =
+  ## Subtract two complex numbers.
+  result.re = x.re - y.re
+  result.im = x.im - y.im
+
+proc `-` *(x: Complex, y: float): Complex =
+  ## Subtracts float `y` from complex `x`.
+  result = x + (-y)
+
+proc `-` *(x: float, y: Complex): Complex =
+  ## Subtracts complex `y` from float `x`.
+  result = x + (-y)
+
+
+proc `/` *(x, y: Complex): Complex =
+  ## Divide `x` by `y`.
+  var
+    r, den: float
+  if abs(y.re) < abs(y.im):
+    r = y.re / y.im
+    den = y.im + r * y.re
+    result.re = (x.re * r + x.im) / den
+    result.im = (x.im * r - x.re) / den
+  else:
+    r = y.im / y.re
+    den = y.re + r * y.im
+    result.re = (x.re + r * x.im) / den
+    result.im = (x.im - r * x.re) / den
+
+proc `/` *(x : Complex, y: float ): Complex =
+  ## Divide complex `x` by float `y`.
+  result.re = x.re/y
+  result.im = x.im/y
+
+proc `/` *(x : float, y: Complex ): Complex =
+  ## Divide float `x` by complex `y`.
+  var num : Complex = (x, 0.0)
+  result = num/y
+
+
+proc `*` *(x, y: Complex): Complex =
+  ## Multiply `x` with `y`.
+  result.re = x.re * y.re - x.im * y.im
+  result.im = x.im * y.re + x.re * y.im
+
+proc `*` *(x: float, y: Complex): Complex =
+  ## Multiply float `x` with complex `y`.
+  result.re = x * y.re
+  result.im = x * y.im
+
+proc `*` *(x: Complex, y: float): Complex =
+  ## Multiply complex `x` with float `y`.
+  result.re = x.re * y
+  result.im = x.im * y
+
+
+proc `+=` *(x: var Complex, y: Complex) =
+  ## Add `y` to `x`.
+  x.re += y.re
+  x.im += y.im
+
+proc `+=` *(x: var Complex, y: float) =
+  ## Add `y` to the complex number `x`.
+  x.re += y
+
+proc `-=` *(x: var Complex, y: Complex) =
+  ## Subtract `y` from `x`.
+  x.re -= y.re
+  x.im -= y.im
+
+proc `-=` *(x: var Complex, y: float) =
+  ## Subtract `y` from the complex number `x`.
+  x.re -= y
+
+proc `*=` *(x: var Complex, y: Complex) =
+  ## Multiply `y` to `x`.
+  let im = x.im * y.re + x.re * y.im
+  x.re = x.re * y.re - x.im * y.im
+  x.im = im
+
+proc `*=` *(x: var Complex, y: float) =
+  ## Multiply `y` to the complex number `x`.
+  x.re *= y
+  x.im *= y
+
+proc `/=` *(x: var Complex, y: Complex) =
+  ## Divide `x` by `y` in place.
+  x = x / y
+
+proc `/=` *(x : var Complex, y: float) =
+  ## Divide complex `x` by float `y` in place.
+  x.re /= y
+  x.im /= y
+
+
+proc abs*(z: Complex): float =
+  ## Return the distance from (0,0) to `z`.
+
+  # optimized by checking special cases (sqrt is expensive)
+  var x, y, temp: float
+
+  x = abs(z.re)
+  y = abs(z.im)
+  if x == 0.0:
+    result = y
+  elif y == 0.0:
+    result = x
+  elif x > y:
+    temp = y / x
+    result = x * sqrt(1.0 + temp * temp)
+  else:
+    temp = x / y
+    result = y * sqrt(1.0 + temp * temp)
+
+
+proc conjugate*(z: Complex): Complex =
+  ## Conjugate of complex number `z`.
+  result.re = z.re
+  result.im = -z.im
+
+
+proc sqrt*(z: Complex): Complex =
+  ## Square root for a complex number `z`.
+  var x, y, w, r: float
+
+  if z.re == 0.0 and z.im == 0.0:
+    result = z
+  else:
+    x = abs(z.re)
+    y = abs(z.im)
+    if x >= y:
+      r = y / x
+      w = sqrt(x) * sqrt(0.5 * (1.0 + sqrt(1.0 + r * r)))
+    else:
+      r = x / y
+      w = sqrt(y) * sqrt(0.5 * (r + sqrt(1.0 + r * r)))
+    if z.re >= 0.0:
+      result.re = w
+      result.im = z.im / (w * 2.0)
+    else:
+      if z.im >= 0.0: result.im = w
+      else:           result.im = -w
+      result.re = z.im / (result.im + result.im)
+
+
+proc exp*(z: Complex): Complex =
+  ## e raised to the power `z`.
+  var rho   = exp(z.re)
+  var theta = z.im
+  result.re = rho*cos(theta)
+  result.im = rho*sin(theta)
+
+
+proc ln*(z: Complex): Complex =
+  ## Returns the natural log of `z`.
+  result.re = ln(abs(z))
+  result.im = arctan2(z.im,z.re)
+
+proc log10*(z: Complex): Complex =
+  ## Returns the log base 10 of `z`.
+  result = ln(z)/ln(10.0)
+
+proc log2*(z: Complex): Complex =
+  ## Returns the log base 2 of `z`.
+  result = ln(z)/ln(2.0)
+
+
+proc pow*(x, y: Complex): Complex =
+  ## `x` raised to the power `y`.
+  if x.re == 0.0  and  x.im == 0.0:
+    if y.re == 0.0  and  y.im == 0.0:
+      result.re = 1.0
+      result.im = 0.0
+    else:
+      result.re = 0.0
+      result.im = 0.0
+  elif y.re == 1.0  and  y.im == 0.0:
+    result = x
+  elif y.re == -1.0  and  y.im == 0.0:
+    result = 1.0/x
+  else:
+    var rho   = sqrt(x.re*x.re + x.im*x.im)
+    var theta = arctan2(x.im,x.re)
+    var s     = pow(rho,y.re) * exp(-y.im*theta)
+    var r     = y.re*theta + y.im*ln(rho)
+    result.re = s*cos(r)
+    result.im = s*sin(r)
+           
+
+proc sin*(z: Complex): Complex =
+  ## Returns the sine of `z`.
+  result.re = sin(z.re)*cosh(z.im)
+  result.im = cos(z.re)*sinh(z.im)
+
+proc arcsin*(z: Complex): Complex =
+  ## Returns the inverse sine of `z`.
+  var i: Complex = (0.0,1.0)
+  result = -i*ln(i*z + sqrt(1.0-z*z))
+
+proc cos*(z: Complex): Complex =
+  ## Returns the cosine of `z`.
+  result.re = cos(z.re)*cosh(z.im)
+  result.im = -sin(z.re)*sinh(z.im)
+
+proc arccos*(z: Complex): Complex =
+  ## Returns the inverse cosine of `z`.
+  var i: Complex = (0.0,1.0)
+  result = -i*ln(z + sqrt(z*z-1.0))
+
+proc tan*(z: Complex): Complex =
+  ## Returns the tangent of `z`.
+  result = sin(z)/cos(z)
+
+proc arctan*(z: Complex): Complex =
+  ## Returns the inverse tangent of `z`.
+  var i: Complex = (0.0,1.0)
+  result = 0.5*i*(ln(1-i*z)-ln(1+i*z))
+
+proc cot*(z: Complex): Complex =
+  ## Returns the cotangent of `z`.
+  result = cos(z)/sin(z)
+
+proc arccot*(z: Complex): Complex =
+  ## Returns the inverse cotangent of `z`.
+  var i: Complex = (0.0,1.0)
+  result = 0.5*i*(ln(1-i/z)-ln(1+i/z))
+
+proc sec*(z: Complex): Complex =
+  ## Returns the secant of `z`.
+  result = 1.0/cos(z)
+
+proc arcsec*(z: Complex): Complex =
+  ## Returns the inverse secant of `z`.
+  var i: Complex = (0.0,1.0)
+  result = -i*ln(i*sqrt(1-1/(z*z))+1/z)
+
+proc csc*(z: Complex): Complex =
+  ## Returns the cosecant of `z`.
+  result = 1.0/sin(z)
+
+proc arccsc*(z: Complex): Complex =
+  ## Returns the inverse cosecant of `z`.
+  var i: Complex = (0.0,1.0)
+  result = -i*ln(sqrt(1-1/(z*z))+i/z)
+
+
+proc sinh*(z: Complex): Complex =
+  ## Returns the hyperbolic sine of `z`.
+  result = 0.5*(exp(z)-exp(-z))
+
+proc arcsinh*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic sine of `z`.
+  result = ln(z+sqrt(z*z+1))
+
+proc cosh*(z: Complex): Complex =
+  ## Returns the hyperbolic cosine of `z`.
+  result = 0.5*(exp(z)+exp(-z))
+
+proc arccosh*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic cosine of `z`.
+  result = ln(z+sqrt(z*z-1))
+
+proc tanh*(z: Complex): Complex =
+  ## Returns the hyperbolic tangent of `z`.
+  result = sinh(z)/cosh(z)
+
+proc arctanh*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic tangent of `z`.
+  result = 0.5*(ln((1+z)/(1-z)))
+
+proc sech*(z: Complex): Complex =
+  ## Returns the hyperbolic secant of `z`.
+  result = 2/(exp(z)+exp(-z))
+
+proc arcsech*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic secant of `z`.
+  result = ln(1/z+sqrt(1/z+1)*sqrt(1/z-1))
+
+proc csch*(z: Complex): Complex =
+  ## Returns the hyperbolic cosecant of `z`.
+  result = 2/(exp(z)-exp(-z))
+
+proc arccsch*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic cosecant of `z`.
+  result = ln(1/z+sqrt(1/(z*z)+1))
+
+proc coth*(z: Complex): Complex =
+  ## Returns the hyperbolic cotangent of `z`.
+  result = cosh(z)/sinh(z)
+
+proc arccoth*(z: Complex): Complex =
+  ## Returns the inverse hyperbolic cotangent of `z`.
+  result = 0.5*(ln(1+1/z)-ln(1-1/z))
+
+proc phase*(z: Complex): float =
+  ## Returns the phase of `z`.
+  arctan2(z.im, z.re)
+
+proc polar*(z: Complex): tuple[r, phi: float] =
+  ## Returns `z` in polar coordinates.
+  result.r = abs(z)
+  result.phi = phase(z)
+
+proc rect*(r: float, phi: float): Complex =
+  ## Returns the complex number with polar coordinates `r` and `phi`.
+  result.re = r * cos(phi)
+  result.im = r * sin(phi)
+
+
+proc `$`*(z: Complex): string =
+  ## Returns `z`'s string representation as ``"(re, im)"``.
+  result = "(" & $z.re & ", " & $z.im & ")"
+
+{.pop.}
+
+
+when isMainModule:
+  var z = (0.0, 0.0)
+  var oo = (1.0,1.0)
+  var a = (1.0, 2.0)
+  var b = (-1.0, -2.0)
+  var m1 = (-1.0, 0.0)
+  var i = (0.0,1.0)
+  var one = (1.0,0.0)
+  var tt = (10.0, 20.0)
+  var ipi = (0.0, -PI)
+ 
+  assert( a == a )
+  assert( (a-a) == z )
+  assert( (a+b) == z )
+  assert( (a/b) == m1 )
+  assert( (1.0/a) == (0.2, -0.4) )
+  assert( (a*b) == (3.0, -4.0) )
+  assert( 10.0*a == tt )
+  assert( a*10.0 == tt )
+  assert( tt/10.0 == a )
+  assert( oo+(-1.0) == i )
+  assert( (-1.0)+oo == i )
+  assert( abs(oo) == sqrt(2.0) )
+  assert( conjugate(a) == (1.0, -2.0) )
+  assert( sqrt(m1) == i )
+  assert( exp(ipi) =~ m1 )
+ 
+  assert( pow(a,b) =~ (-3.72999124927876, -1.68815826725068) )
+  assert( pow(z,a) =~ (0.0, 0.0) )
+  assert( pow(z,z) =~ (1.0, 0.0) )
+  assert( pow(a,one) =~ a )
+  assert( pow(a,m1) =~ (0.2, -0.4) )
+
+  assert( ln(a) =~ (0.804718956217050, 1.107148717794090) )
+  assert( log10(a) =~ (0.349485002168009, 0.480828578784234) )
+  assert( log2(a) =~ (1.16096404744368, 1.59727796468811) )
+
+  assert( sin(a) =~ (3.16577851321617, 1.95960104142161) )
+  assert( cos(a) =~ (2.03272300701967, -3.05189779915180) )
+  assert( tan(a) =~ (0.0338128260798967, 1.0147936161466335) )
+  assert( cot(a) =~ 1.0/tan(a) )
+  assert( sec(a) =~ 1.0/cos(a) )
+  assert( csc(a) =~ 1.0/sin(a) )
+  assert( arcsin(a) =~ (0.427078586392476, 1.528570919480998) )
+  assert( arccos(a) =~ (1.14371774040242, -1.52857091948100) )
+  assert( arctan(a) =~ (1.338972522294494, 0.402359478108525) )
+
+  assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) )
+  assert( sinh(a) =~ (-0.489056259041294, 1.403119250622040) )
+  assert( tanh(a) =~ (1.1667362572409199,-0.243458201185725) )
+  assert( sech(a) =~ 1/cosh(a) )
+  assert( csch(a) =~ 1/sinh(a) )
+  assert( coth(a) =~ 1/tanh(a) )
+  assert( arccosh(a) =~ (1.528570919480998, 1.14371774040242) )
+  assert( arcsinh(a) =~ (1.469351744368185, 1.06344002357775) )
+  assert( arctanh(a) =~ (0.173286795139986, 1.17809724509617) )
+  assert( arcsech(a) =~ arccosh(1/a) )
+  assert( arccsch(a) =~ arcsinh(1/a) )
+  assert( arccoth(a) =~ arctanh(1/a) )
+
+  assert( phase(a) == 1.1071487177940904 )
+  var t = polar(a)
+  assert( rect(t.r, t.phi) =~ a )
+  assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim
new file mode 100644
index 000000000..6f2bc4491
--- /dev/null
+++ b/lib/pure/concurrency/cpuinfo.nim
@@ -0,0 +1,67 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements procs to determine the number of CPUs / cores.
+
+include "system/inclrtl"
+
+import strutils, os
+
+when not defined(windows):
+  import posix
+
+when defined(linux):
+  import linux
+  
+when defined(freebsd) or defined(macosx):
+  {.emit:"#include <sys/types.h>".}
+
+when defined(openbsd) or defined(netbsd):
+  {.emit:"#include <sys/param.h>".}
+
+when defined(macosx) or defined(bsd):
+  # we HAVE to emit param.h before sysctl.h so we cannot use .header here
+  # either. The amount of archaic bullshit in Poonix based OSes is just insane.
+  {.emit:"#include <sys/sysctl.h>".}
+  const
+    CTL_HW = 6
+    HW_AVAILCPU = 25
+    HW_NCPU = 3
+  proc sysctl(x: ptr array[0..3, cint], y: cint, z: pointer,
+              a: var csize, b: pointer, c: int): cint {.
+              importc: "sysctl", nodecl.}
+
+proc countProcessors*(): int {.rtl, extern: "ncpi$1".} =
+  ## returns the numer of the processors/cores the machine has.
+  ## Returns 0 if it cannot be detected.
+  when defined(windows):
+    var x = getEnv("NUMBER_OF_PROCESSORS")
+    if x.len > 0: result = parseInt(x.string)
+  elif defined(macosx) or defined(bsd):
+    var
+      mib: array[0..3, cint]
+      numCPU: int
+      len: csize
+    mib[0] = CTL_HW
+    mib[1] = HW_AVAILCPU
+    len = sizeof(numCPU)
+    discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0)
+    if numCPU < 1:
+      mib[1] = HW_NCPU
+      discard sysctl(addr(mib), 2, addr(numCPU), len, nil, 0)
+    result = numCPU
+  elif defined(hpux):
+    result = mpctl(MPC_GETNUMSPUS, nil, nil)
+  elif defined(irix):
+    var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint
+    result = sysconf(SC_NPROC_ONLN)
+  else:
+    result = sysconf(SC_NPROCESSORS_ONLN)
+  if result <= 0: result = 1
+
diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim
new file mode 100644
index 000000000..7ce5e01b7
--- /dev/null
+++ b/lib/pure/concurrency/cpuload.nim
@@ -0,0 +1,96 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a helper for a thread pool to determine whether
+## creating a thread is a good idea.
+
+when defined(windows):
+  import winlean, os, strutils, math
+
+  proc `-`(a, b: TFILETIME): int64 = a.rdFileTime - b.rdFileTime
+elif defined(linux):
+  from cpuinfo import countProcessors
+
+type
+  ThreadPoolAdvice* = enum
+    doNothing,
+    doCreateThread,  # create additional thread for throughput
+    doShutdownThread # too many threads are busy, shutdown one
+
+  ThreadPoolState* = object
+    when defined(windows):
+      prevSysKernel, prevSysUser, prevProcKernel, prevProcUser: TFILETIME
+    calls*: int
+
+proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
+  when defined(windows):
+    var
+      sysIdle, sysKernel, sysUser,
+        procCreation, procExit, procKernel, procUser: TFILETIME
+    if getSystemTimes(sysIdle, sysKernel, sysUser) == 0 or
+        getProcessTimes(THandle(-1), procCreation, procExit, 
+                        procKernel, procUser) == 0:
+      return doNothing
+    if s.calls > 0:
+      let
+        sysKernelDiff = sysKernel - s.prevSysKernel
+        sysUserDiff = sysUser - s.prevSysUser
+
+        procKernelDiff = procKernel - s.prevProcKernel
+        procUserDiff = procUser - s.prevProcUser
+
+        sysTotal = int(sysKernelDiff + sysUserDiff)
+        procTotal = int(procKernelDiff + procUserDiff)
+      # total CPU usage < 85% --> create a new worker thread.
+      # Measurements show that 100% and often even 90% is not reached even
+      # if all my cores are busy.
+      if sysTotal == 0 or procTotal / sysTotal < 0.85:
+        result = doCreateThread
+    s.prevSysKernel = sysKernel
+    s.prevSysUser = sysUser
+    s.prevProcKernel = procKernel
+    s.prevProcUser = procUser
+  elif defined(linux):
+    proc fscanf(c: File, frmt: cstring) {.varargs, importc, 
+      header: "<stdio.h>".}
+
+    var f = open("/proc/loadavg")
+    var b: float
+    var busy, total: int
+    fscanf(f,"%lf %lf %lf %ld/%ld",
+           addr b, addr b, addr b, addr busy, addr total)
+    f.close()
+    let cpus = countProcessors()
+    if busy-1 < cpus:
+      result = doCreateThread
+    elif busy-1 >= cpus*2:
+      result = doShutdownThread
+    else:
+      result = doNothing
+  else:
+    # XXX implement this for other OSes
+    result = doNothing
+  inc s.calls
+
+when not defined(testing) and isMainModule:
+  proc busyLoop() =
+    while true:
+      discard random(80)
+      os.sleep(100)
+
+  spawn busyLoop()
+  spawn busyLoop()
+  spawn busyLoop()
+  spawn busyLoop()
+
+  var s: ThreadPoolState
+
+  for i in 1 .. 70:
+    echo advice(s)
+    os.sleep(1000)
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
new file mode 100644
index 000000000..a431691ad
--- /dev/null
+++ b/lib/pure/concurrency/threadpool.nim
@@ -0,0 +1,401 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements Nim's 'spawn'.
+
+when not compileOption("threads"):
+  {.error: "Threadpool requires --threads:on option.".}
+
+import cpuinfo, cpuload, locks
+
+{.push stackTrace:off.}
+
+type
+  Semaphore = object
+    c: TCond
+    L: TLock
+    counter: int
+
+proc createSemaphore(): Semaphore =
+  initCond(result.c)
+  initLock(result.L)
+
+proc destroySemaphore(cv: var Semaphore) {.inline.} =
+  deinitCond(cv.c)
+  deinitLock(cv.L)
+
+proc await(cv: var Semaphore) =
+  acquire(cv.L)
+  while cv.counter <= 0:
+    wait(cv.c, cv.L)
+  dec cv.counter
+  release(cv.L)
+
+proc signal(cv: var Semaphore) =
+  acquire(cv.L)
+  inc cv.counter
+  release(cv.L)
+  signal(cv.c)
+
+const CacheLineSize = 32 # true for most archs
+
+type
+  Barrier {.compilerProc.} = object
+    entered: int
+    cv: Semaphore # Semaphore takes 3 words at least
+    when sizeof(int) < 8:
+      cacheAlign: array[CacheLineSize-4*sizeof(int), byte]
+    left: int
+    cacheAlign2: array[CacheLineSize-sizeof(int), byte]
+    interest: bool ## wether the master is interested in the "all done" event
+
+proc barrierEnter(b: ptr Barrier) {.compilerProc, inline.} =
+  # due to the signaling between threads, it is ensured we are the only
+  # one with access to 'entered' so we don't need 'atomicInc' here:
+  inc b.entered
+  # also we need no 'fence' instructions here as soon 'nimArgsPassingDone'
+  # will be called which already will perform a fence for us.
+
+proc barrierLeave(b: ptr Barrier) {.compilerProc, inline.} =
+  atomicInc b.left
+  when not defined(x86): fence()
+  # We may not have seen the final value of b.entered yet,
+  # so we need to check for >= instead of ==.
+  if b.interest and b.left >= b.entered: signal(b.cv)
+
+proc openBarrier(b: ptr Barrier) {.compilerProc, inline.} =
+  b.entered = 0
+  b.left = 0
+  b.interest = false
+
+proc closeBarrier(b: ptr Barrier) {.compilerProc.} =
+  fence()
+  if b.left != b.entered:
+    b.cv = createSemaphore()
+    fence()
+    b.interest = true
+    fence()
+    while b.left != b.entered: await(b.cv)
+    destroySemaphore(b.cv)
+
+{.pop.}
+
+# ----------------------------------------------------------------------------
+
+type
+  foreign* = object ## a region that indicates the pointer comes from a
+                    ## foreign thread heap.
+  AwaitInfo = object
+    cv: Semaphore
+    idx: int
+
+  FlowVarBase* = ref FlowVarBaseObj ## untyped base class for 'FlowVar[T]'
+  FlowVarBaseObj = object of RootObj
+    ready, usesSemaphore, awaited: bool
+    cv: Semaphore #\
+    # for 'awaitAny' support
+    ai: ptr AwaitInfo
+    idx: int
+    data: pointer  # we incRef and unref it to keep it alive; note this MUST NOT
+                   # be RootRef here otherwise the wrong GC keeps track of it!
+    owner: pointer # ptr Worker
+
+  FlowVarObj[T] = object of FlowVarBaseObj
+    blob: T
+
+  FlowVar*{.compilerProc.}[T] = ref FlowVarObj[T] ## a data flow variable
+
+  ToFreeQueue = object
+    len: int
+    lock: TLock
+    empty: Semaphore
+    data: array[128, pointer]
+
+  WorkerProc = proc (thread, args: pointer) {.nimcall, gcsafe.}
+  Worker = object
+    taskArrived: Semaphore
+    taskStarted: Semaphore #\
+    # task data:
+    f: WorkerProc
+    data: pointer
+    ready: bool # put it here for correct alignment!
+    initialized: bool # whether it has even been initialized
+    shutdown: bool # the pool requests to shut down this worker thread
+    q: ToFreeQueue
+
+proc await*(fv: FlowVarBase) =
+  ## waits until the value for the flowVar arrives. Usually it is not necessary
+  ## to call this explicitly.
+  if fv.usesSemaphore and not fv.awaited:
+    fv.awaited = true
+    await(fv.cv)
+    destroySemaphore(fv.cv)
+
+proc selectWorker(w: ptr Worker; fn: WorkerProc; data: pointer): bool =
+  if cas(addr w.ready, true, false):
+    w.data = data
+    w.f = fn
+    signal(w.taskArrived)
+    await(w.taskStarted)
+    result = true
+
+proc cleanFlowVars(w: ptr Worker) =
+  let q = addr(w.q)
+  acquire(q.lock)
+  for i in 0 .. <q.len:
+    GC_unref(cast[RootRef](q.data[i]))
+    #echo "GC_unref"
+  q.len = 0
+  release(q.lock)
+
+proc wakeupWorkerToProcessQueue(w: ptr Worker) =
+  # we have to ensure it's us who wakes up the owning thread.
+  # This is quite horrible code, but it runs so rarely that it doesn't matter:
+  while not cas(addr w.ready, true, false):
+    cpuRelax()
+    discard
+  w.data = nil
+  w.f = proc (w, a: pointer) {.nimcall.} =
+    let w = cast[ptr Worker](w)
+    cleanFlowVars(w)
+    signal(w.q.empty)
+  signal(w.taskArrived)
+
+proc finished(fv: FlowVarBase) =
+  doAssert fv.ai.isNil, "flowVar is still attached to an 'awaitAny'"
+  # we have to protect against the rare cases where the owner of the flowVar
+  # simply disregards the flowVar and yet the "flowVar" has not yet written
+  # anything to it:
+  await(fv)
+  if fv.data.isNil: return
+  let owner = cast[ptr Worker](fv.owner)
+  let q = addr(owner.q)
+  acquire(q.lock)
+  while not (q.len < q.data.len):
+    #echo "EXHAUSTED!"
+    release(q.lock)
+    wakeupWorkerToProcessQueue(owner)
+    await(q.empty)
+    acquire(q.lock)
+  q.data[q.len] = cast[pointer](fv.data)
+  inc q.len
+  release(q.lock)
+  fv.data = nil
+
+proc fvFinalizer[T](fv: FlowVar[T]) = finished(fv)
+
+proc nimCreateFlowVar[T](): FlowVar[T] {.compilerProc.} =
+  new(result, fvFinalizer)
+
+proc nimFlowVarCreateSemaphore(fv: FlowVarBase) {.compilerProc.} =
+  fv.cv = createSemaphore()
+  fv.usesSemaphore = true
+
+proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} =
+  if fv.ai != nil:
+    acquire(fv.ai.cv.L)
+    fv.ai.idx = fv.idx
+    inc fv.ai.cv.counter
+    release(fv.ai.cv.L)
+    signal(fv.ai.cv.c)
+  if fv.usesSemaphore:
+    signal(fv.cv)
+
+proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) =
+  ## blocks until the ``fv`` is available and then passes its value
+  ## to ``action``. Note that due to Nim's parameter passing semantics this
+  ## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can
+  ## sometimes be more efficient than ``^``.
+  await(fv)
+  when T is string or T is seq:
+    action(cast[T](fv.data))
+  elif T is ref:
+    {.error: "'awaitAndThen' not available for FlowVar[ref]".}
+  else:
+    action(fv.blob)
+  finished(fv)
+
+proc `^`*[T](fv: FlowVar[ref T]): foreign ptr T =
+  ## blocks until the value is available and then returns this value.
+  await(fv)
+  result = cast[foreign ptr T](fv.data)
+
+proc `^`*[T](fv: FlowVar[T]): T =
+  ## blocks until the value is available and then returns this value.
+  await(fv)
+  when T is string or T is seq:
+    # XXX closures? deepCopy?
+    result = cast[T](fv.data)
+  else:
+    result = fv.blob
+
+proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
+  ## awaits any of the given flowVars. Returns the index of one flowVar for
+  ## which a value arrived. A flowVar only supports one call to 'awaitAny' at
+  ## the same time. That means if you await([a,b]) and await([b,c]) the second
+  ## call will only await 'c'. If there is no flowVar left to be able to wait
+  ## on, -1 is returned.
+  ## **Note**: This results in non-deterministic behaviour and so should be
+  ## avoided.
+  var ai: AwaitInfo
+  ai.cv = createSemaphore()
+  var conflicts = 0
+  for i in 0 .. flowVars.high:
+    if cas(addr flowVars[i].ai, nil, addr ai):
+      flowVars[i].idx = i
+    else:
+      inc conflicts
+  if conflicts < flowVars.len:
+    await(ai.cv)
+    result = ai.idx
+    for i in 0 .. flowVars.high:
+      discard cas(addr flowVars[i].ai, addr ai, nil)
+  else:
+    result = -1
+  destroySemaphore(ai.cv)
+
+proc nimArgsPassingDone(p: pointer) {.compilerProc.} =
+  let w = cast[ptr Worker](p)
+  signal(w.taskStarted)
+
+const
+  MaxThreadPoolSize* = 256 ## maximal size of the thread pool. 256 threads
+                           ## should be good enough for anybody ;-)
+
+var
+  currentPoolSize: int
+  maxPoolSize = MaxThreadPoolSize
+  minPoolSize = 4
+  gSomeReady = createSemaphore()
+  readyWorker: ptr Worker
+
+proc slave(w: ptr Worker) {.thread.} =
+  while true:
+    when declared(atomicStoreN):
+      atomicStoreN(addr(w.ready), true, ATOMIC_SEQ_CST)
+    else:
+      w.ready = true
+    readyWorker = w
+    signal(gSomeReady)
+    await(w.taskArrived)
+    assert(not w.ready)
+    w.f(w, w.data)
+    if w.q.len != 0: w.cleanFlowVars
+    if w.shutdown:
+      w.shutdown = false
+      atomicDec currentPoolSize
+
+var
+  workers: array[MaxThreadPoolSize, TThread[ptr Worker]]
+  workersData: array[MaxThreadPoolSize, Worker]
+
+proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) =
+  ## sets the minimal thread pool size. The default value of this is 4.
+  minPoolSize = size
+
+proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) =
+  ## sets the maximal thread pool size. The default value of this
+  ## is ``MaxThreadPoolSize``.
+  maxPoolSize = size
+  if currentPoolSize > maxPoolSize:
+    for i in maxPoolSize..currentPoolSize-1:
+      let w = addr(workersData[i])
+      w.shutdown = true
+
+proc activateThread(i: int) {.noinline.} =
+  workersData[i].taskArrived = createSemaphore()
+  workersData[i].taskStarted = createSemaphore()
+  workersData[i].initialized = true
+  workersData[i].q.empty = createSemaphore()
+  initLock(workersData[i].q.lock)
+  createThread(workers[i], slave, addr(workersData[i]))
+
+proc setup() =
+  currentPoolSize = min(countProcessors(), MaxThreadPoolSize)
+  readyWorker = addr(workersData[0])
+  for i in 0.. <currentPoolSize: activateThread(i)
+
+proc preferSpawn*(): bool =
+  ## Use this proc to determine quickly if a 'spawn' or a direct call is
+  ## preferable. If it returns 'true' a 'spawn' may make sense. In general
+  ## it is not necessary to call this directly; use 'spawnX' instead.
+  result = gSomeReady.counter > 0
+
+proc spawn*(call: expr): expr {.magic: "Spawn".}
+  ## always spawns a new task, so that the 'call' is never executed on
+  ## the calling thread. 'call' has to be proc call 'p(...)' where 'p'
+  ## is gcsafe and has a return type that is either 'void' or compatible
+  ## with ``FlowVar[T]``.
+
+template spawnX*(call: expr): expr =
+  ## spawns a new task if a CPU core is ready, otherwise executes the
+  ## call in the calling thread. Usually it is advised to
+  ## use 'spawn' in order to not block the producer for an unknown
+  ## amount of time. 'call' has to be proc call 'p(...)' where 'p'
+  ## is gcsafe and has a return type that is either 'void' or compatible
+  ## with ``FlowVar[T]``.
+  (if preferSpawn(): spawn call else: call)
+
+proc parallel*(body: stmt) {.magic: "Parallel".}
+  ## a parallel section can be used to execute a block in parallel. ``body``
+  ## has to be in a DSL that is a particular subset of the language. Please
+  ## refer to the manual for further information.
+
+var
+  state: ThreadPoolState
+  stateLock: TLock
+
+initLock stateLock
+
+proc nimSpawn(fn: WorkerProc; data: pointer) {.compilerProc.} =
+  # implementation of 'spawn' that is used by the code generator.
+  while true:
+    if selectWorker(readyWorker, fn, data): return
+    for i in 0.. <currentPoolSize:
+      if selectWorker(addr(workersData[i]), fn, data): return
+    # determine what to do, but keep in mind this is expensive too:
+    # state.calls < maxPoolSize: warmup phase
+    # (state.calls and 127) == 0: periodic check
+    if state.calls < maxPoolSize or (state.calls and 127) == 0:
+      # ensure the call to 'advice' is atomic:
+      if tryAcquire(stateLock):
+        case advice(state)
+        of doNothing: discard
+        of doCreateThread:
+          if currentPoolSize < maxPoolSize:
+            if not workersData[currentPoolSize].initialized:
+              activateThread(currentPoolSize)
+            let w = addr(workersData[currentPoolSize])
+            atomicInc currentPoolSize
+            if selectWorker(w, fn, data):
+              release(stateLock)
+              return
+            # else we didn't succeed but some other thread, so do nothing.
+        of doShutdownThread:
+          if currentPoolSize > minPoolSize:
+            let w = addr(workersData[currentPoolSize-1])
+            w.shutdown = true
+          # we don't free anything here. Too dangerous.
+        release(stateLock)
+      # else the acquire failed, but this means some
+      # other thread succeeded, so we don't need to do anything here.
+    await(gSomeReady)
+
+proc sync*() =
+  ## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate
+  ## waiting, you have to use an explicit barrier.
+  while true:
+    var allReady = true
+    for i in 0 .. <currentPoolSize:
+      if not allReady: break
+      allReady = allReady and workersData[i].ready
+    if allReady: break
+    await(gSomeReady)
+
+setup()
diff --git a/lib/pure/concurrency/threadpool.nim.cfg b/lib/pure/concurrency/threadpool.nim.cfg
new file mode 100644
index 000000000..aed303eef
--- /dev/null
+++ b/lib/pure/concurrency/threadpool.nim.cfg
@@ -0,0 +1 @@
+--threads:on
diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim
new file mode 100644
index 000000000..9983c4a04
--- /dev/null
+++ b/lib/pure/cookies.nim
@@ -0,0 +1,67 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements helper procs for parsing Cookies.
+
+import strtabs, times
+
+proc parseCookies*(s: string): StringTableRef = 
+  ## parses cookies into a string table.
+  result = newStringTable(modeCaseInsensitive)
+  var i = 0
+  while true:
+    while s[i] == ' ' or s[i] == '\t': inc(i)
+    var keystart = i
+    while s[i] != '=' and s[i] != '\0': inc(i)
+    var keyend = i-1
+    if s[i] == '\0': break
+    inc(i) # skip '='
+    var valstart = i
+    while s[i] != ';' and s[i] != '\0': inc(i)
+    result[substr(s, keystart, keyend)] = substr(s, valstart, i-1)
+    if s[i] == '\0': break
+    inc(i) # skip ';'
+
+proc setCookie*(key, value: string, domain = "", path = "",
+                expires = "", noName = false,
+                secure = false, httpOnly = false): string =
+  ## Creates a command in the format of 
+  ## ``Set-Cookie: key=value; Domain=...; ...``
+  result = ""
+  if not noName: result.add("Set-Cookie: ")
+  result.add key & "=" & value
+  if domain != "": result.add("; Domain=" & domain)
+  if path != "": result.add("; Path=" & path)
+  if expires != "": result.add("; Expires=" & expires)
+  if secure: result.add("; secure")
+  if httpOnly: result.add("; HttpOnly")
+
+proc setCookie*(key, value: string, expires: TimeInfo,
+                domain = "", path = "", noName = false,
+                secure = false, httpOnly = false): string =
+  ## Creates a command in the format of 
+  ## ``Set-Cookie: key=value; Domain=...; ...``
+  ##
+  ## **Note:** UTC is assumed as the timezone for ``expires``.  
+  return setCookie(key, value, domain, path,
+                   format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"),
+                   noname, secure, httpOnly)
+
+when isMainModule:
+  var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
+
+  let cookie = setCookie("test", "value", tim.getGMTime())
+  when not defined(testing):
+    echo cookie
+  let start = "Set-Cookie: test=value; Expires="
+  assert cookie[0..start.high] == start
+  
+  let table = parseCookies("uid=1; kp=2")
+  assert table["uid"] == "1"
+  assert table["kp"] == "2"
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
new file mode 100644
index 000000000..c6794be67
--- /dev/null
+++ b/lib/pure/dynlib.nim
@@ -0,0 +1,100 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the ability to access symbols from shared
+## libraries. On POSIX this uses the ``dlsym`` mechanism, on 
+## Windows ``LoadLibrary``. 
+
+type
+  LibHandle* = pointer ## a handle to a dynamically loaded library
+
+{.deprecated: [TLibHandle: LibHandle].}
+
+proc loadLib*(path: string, global_symbols=false): LibHandle
+  ## loads a library from `path`. Returns nil if the library could not 
+  ## be loaded.
+
+proc loadLib*(): LibHandle
+  ## gets the handle from the current executable. Returns nil if the 
+  ## library could not be loaded.
+
+proc unloadLib*(lib: LibHandle)
+  ## unloads the library `lib`
+
+proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} =
+  ## raises an `EInvalidLibrary` exception.
+  var e: ref LibraryError
+  new(e)
+  e.msg = "could not find symbol: " & $name
+  raise e
+
+proc symAddr*(lib: LibHandle, name: cstring): pointer
+  ## retrieves the address of a procedure/variable from `lib`. Returns nil
+  ## if the symbol could not be found.
+
+proc checkedSymAddr*(lib: LibHandle, name: cstring): pointer =
+  ## retrieves the address of a procedure/variable from `lib`. Raises
+  ## `EInvalidLibrary` if the symbol could not be found.
+  result = symAddr(lib, name)
+  if result == nil: raiseInvalidLibrary(name)
+
+when defined(posix):
+  #
+  # =========================================================================
+  # This is an implementation based on the dlfcn interface.
+  # The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+  # NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+  # as an emulation layer on top of native functions.
+  # =========================================================================
+  #
+  var
+    RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
+    RTLD_GLOBAL {.importc: "RTLD_GLOBAL", header: "<dlfcn.h>".}: int
+
+  proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".}
+  proc dlopen(path: cstring, mode: int): LibHandle {.
+      importc, header: "<dlfcn.h>".}
+  proc dlsym(lib: LibHandle, name: cstring): pointer {.
+      importc, header: "<dlfcn.h>".}
+
+  proc loadLib(path: string, global_symbols=false): LibHandle = 
+    var flags = RTLD_NOW
+    if global_symbols: flags = flags or RTLD_GLOBAL
+    return dlopen(path, flags)
+  proc loadLib(): LibHandle = return dlopen(nil, RTLD_NOW)
+  proc unloadLib(lib: LibHandle) = dlclose(lib)
+  proc symAddr(lib: LibHandle, name: cstring): pointer = 
+    return dlsym(lib, name)
+
+elif defined(windows) or defined(dos):
+  #
+  # =======================================================================
+  # Native Windows Implementation
+  # =======================================================================
+  #
+  type
+    THINSTANCE {.importc: "HINSTANCE".} = pointer
+
+  proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
+  proc winLoadLibrary(path: cstring): THINSTANCE {.
+      importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
+  proc getProcAddress(lib: THINSTANCE, name: cstring): pointer {.
+      importc: "GetProcAddress", header: "<windows.h>", stdcall.}
+
+  proc loadLib(path: string, global_symbols=false): LibHandle =
+    result = cast[LibHandle](winLoadLibrary(path))
+  proc loadLib(): LibHandle =
+    result = cast[LibHandle](winLoadLibrary(nil))
+  proc unloadLib(lib: LibHandle) = FreeLibrary(cast[THINSTANCE](lib))
+
+  proc symAddr(lib: LibHandle, name: cstring): pointer =
+    result = getProcAddress(cast[THINSTANCE](lib), name)
+
+else:
+  {.error: "no implementation for dynlib".}
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
new file mode 100644
index 000000000..2a6134615
--- /dev/null
+++ b/lib/pure/encodings.nim
@@ -0,0 +1,464 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Converts between different character encodings. On UNIX, this uses 
+## the `iconv`:idx: library, on Windows the Windows API.
+
+import os, parseutils, strutils
+
+when not defined(windows):
+  type
+    ConverterObj = object
+    EncodingConverter* = ptr ConverterObj ## can convert between two character sets
+
+else:
+  type
+    CodePage = distinct int32
+    EncodingConverter* = object
+      dest, src: CodePage
+
+type
+  EncodingError* = object of ValueError ## exception that is raised
+                                        ## for encoding errors
+
+{.deprecated: [EInvalidEncoding: EncodingError, PConverter: EncodingConverter].}
+
+when defined(windows):
+  proc eqEncodingNames(a, b: string): bool =
+    var i = 0
+    var j = 0
+    while i < a.len and j < b.len:
+      if a[i] in {'-', '_'}: inc i
+      if b[j] in {'-', '_'}: inc j
+      if a[i].toLower != b[j].toLower: return false
+      inc i
+      inc j
+    result = i == a.len and j == b.len
+
+  const 
+    winEncodings = [
+      (1,   "OEMCP"), # current OEM codepage
+      (037, "IBM037"), # IBM EBCDIC US-Canada 
+      (437, "IBM437"), # OEM United States 
+      (500, "IBM500"), # IBM EBCDIC International 
+      (708, "ASMO-708"), # Arabic (ASMO 708) 
+      (709, "ASMO_449"), # Arabic (ASMO-449+, BCON V4) 
+      (710, ""), # Arabic - Transparent Arabic 
+      (720, "DOS-720"), # Arabic (Transparent ASMO); Arabic (DOS) 
+      (737, "ibm737"), # OEM Greek (formerly 437G); Greek (DOS) 
+      (775, "ibm775"), # OEM Baltic; Baltic (DOS) 
+      (850, "ibm850"), # OEM Multilingual Latin 1; Western European (DOS) 
+      (852, "ibm852"), # OEM Latin 2; Central European (DOS) 
+      (855, "IBM855"), # OEM Cyrillic (primarily Russian) 
+      (857, "ibm857"), # OEM Turkish; Turkish (DOS) 
+      (858, "IBM00858"), # OEM Multilingual Latin 1 + Euro symbol 
+      (860, "IBM860"), # OEM Portuguese; Portuguese (DOS) 
+      (861, "ibm861"), # OEM Icelandic; Icelandic (DOS) 
+      (862, "DOS-862"), # OEM Hebrew; Hebrew (DOS) 
+      (863, "IBM863"), # OEM French Canadian; French Canadian (DOS) 
+      (864, "IBM864"), # OEM Arabic; Arabic (864) 
+      (865, "IBM865"), # OEM Nordic; Nordic (DOS) 
+      (866, "cp866"), # OEM Russian; Cyrillic (DOS) 
+      (869, "ibm869"), # OEM Modern Greek; Greek, Modern (DOS) 
+      (870, "IBM870"), # IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 
+      (874, "windows-874"), # ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) 
+      (875, "cp875"), # IBM EBCDIC Greek Modern 
+      (932, "shift_jis"), # ANSI/OEM Japanese; Japanese (Shift-JIS) 
+      (936, "gb2312"), # ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) 
+      (949, "ks_c_5601-1987"), # ANSI/OEM Korean (Unified Hangul Code) 
+      (950, "big5"), # ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) 
+      (1026, "IBM1026"), # IBM EBCDIC Turkish (Latin 5) 
+      (1047, "IBM01047"), # IBM EBCDIC Latin 1/Open System 
+      (1140, "IBM01140"), # IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) 
+      (1141, "IBM01141"), # IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) 
+      (1142, "IBM01142"), # IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) 
+      (1143, "IBM01143"), # IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) 
+      (1144, "IBM01144"), # IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) 
+      (1145, "IBM01145"), # IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) 
+      (1146, "IBM01146"), # IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) 
+      (1147, "IBM01147"), # IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) 
+      (1148, "IBM01148"), # IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) 
+      (1149, "IBM01149"), # IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) 
+      (1200, "utf-16"), # Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications 
+      (1201, "unicodeFFFE"), # Unicode UTF-16, big endian byte order; available only to managed applications 
+      (1250, "windows-1250"), # ANSI Central European; Central European (Windows) 
+      (1251, "windows-1251"), # ANSI Cyrillic; Cyrillic (Windows) 
+      (1252, "windows-1252"), # ANSI Latin 1; Western European (Windows) 
+      (1253, "windows-1253"), # ANSI Greek; Greek (Windows) 
+      (1254, "windows-1254"), # ANSI Turkish; Turkish (Windows) 
+      (1255, "windows-1255"), # ANSI Hebrew; Hebrew (Windows) 
+      (1256, "windows-1256"), # ANSI Arabic; Arabic (Windows) 
+      (1257, "windows-1257"), # ANSI Baltic; Baltic (Windows) 
+      (1258, "windows-1258"), # ANSI/OEM Vietnamese; Vietnamese (Windows) 
+
+      (1250, "cp-1250"), # ANSI Central European; Central European (Windows) 
+      (1251, "cp-1251"), # ANSI Cyrillic; Cyrillic (Windows) 
+      (1252, "cp-1252"), # ANSI Latin 1; Western European (Windows) 
+      (1253, "cp-1253"), # ANSI Greek; Greek (Windows) 
+      (1254, "cp-1254"), # ANSI Turkish; Turkish (Windows) 
+      (1255, "cp-1255"), # ANSI Hebrew; Hebrew (Windows) 
+      (1256, "cp-1256"), # ANSI Arabic; Arabic (Windows) 
+      (1257, "cp-1257"), # ANSI Baltic; Baltic (Windows) 
+      (1258, "cp-1258"), # ANSI/OEM Vietnamese; Vietnamese (Windows) 
+
+      (1361, "Johab"), # Korean (Johab) 
+      (10000, "macintosh"), # MAC Roman; Western European (Mac) 
+      (10001, "x-mac-japanese"), # Japanese (Mac) 
+      (10002, "x-mac-chinesetrad"), # MAC Traditional Chinese (Big5); Chinese Traditional (Mac) 
+      (10003, "x-mac-korean"), # Korean (Mac) 
+      (10004, "x-mac-arabic"), # Arabic (Mac) 
+      (10005, "x-mac-hebrew"), # Hebrew (Mac) 
+      (10006, "x-mac-greek"), # Greek (Mac) 
+      (10007, "x-mac-cyrillic"), # Cyrillic (Mac) 
+      (10008, "x-mac-chinesesimp"), # MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) 
+      (10010, "x-mac-romanian"), # Romanian (Mac) 
+      (10017, "x-mac-ukrainian"), # Ukrainian (Mac) 
+      (10021, "x-mac-thai"), # Thai (Mac) 
+      (10029, "x-mac-ce"), # MAC Latin 2; Central European (Mac) 
+      (10079, "x-mac-icelandic"), # Icelandic (Mac) 
+      (10081, "x-mac-turkish"), # Turkish (Mac) 
+      (10082, "x-mac-croatian"), # Croatian (Mac) 
+      (12000, "utf-32"), # Unicode UTF-32, little endian byte order; available only to managed applications 
+      (12001, "utf-32BE"), # Unicode UTF-32, big endian byte order; available only to managed applications 
+      (20000, "x-Chinese_CNS"), # CNS Taiwan; Chinese Traditional (CNS) 
+      (20001, "x-cp20001"), # TCA Taiwan 
+      (20002, "x_Chinese-Eten"), # Eten Taiwan; Chinese Traditional (Eten) 
+      (20003, "x-cp20003"), # IBM5550 Taiwan 
+      (20004, "x-cp20004"), # TeleText Taiwan 
+      (20005, "x-cp20005"), # Wang Taiwan 
+      (20105, "x-IA5"), # IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) 
+      (20106, "x-IA5-German"), # IA5 German (7-bit) 
+      (20107, "x-IA5-Swedish"), # IA5 Swedish (7-bit) 
+      (20108, "x-IA5-Norwegian"), # IA5 Norwegian (7-bit) 
+      (20127, "us-ascii"), # US-ASCII (7-bit) 
+      (20261, "x-cp20261"), # T.61 
+      (20269, "x-cp20269"), # ISO 6937 Non-Spacing Accent 
+      (20273, "IBM273"), # IBM EBCDIC Germany 
+      (20277, "IBM277"), # IBM EBCDIC Denmark-Norway 
+      (20278, "IBM278"), # IBM EBCDIC Finland-Sweden 
+      (20280, "IBM280"), # IBM EBCDIC Italy 
+      (20284, "IBM284"), # IBM EBCDIC Latin America-Spain 
+      (20285, "IBM285"), # IBM EBCDIC United Kingdom 
+      (20290, "IBM290"), # IBM EBCDIC Japanese Katakana Extended 
+      (20297, "IBM297"), # IBM EBCDIC France 
+      (20420, "IBM420"), # IBM EBCDIC Arabic 
+      (20423, "IBM423"), # IBM EBCDIC Greek 
+      (20424, "IBM424"), # IBM EBCDIC Hebrew 
+      (20833, "x-EBCDIC-KoreanExtended"), # IBM EBCDIC Korean Extended 
+      (20838, "IBM-Thai"), # IBM EBCDIC Thai 
+      (20866, "koi8-r"), # Russian (KOI8-R); Cyrillic (KOI8-R) 
+      (20871, "IBM871"), # IBM EBCDIC Icelandic 
+      (20880, "IBM880"), # IBM EBCDIC Cyrillic Russian 
+      (20905, "IBM905"), # IBM EBCDIC Turkish 
+      (20924, "IBM00924"), # IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) 
+      (20932, "EUC-JP"), # Japanese (JIS 0208-1990 and 0121-1990) 
+      (20936, "x-cp20936"), # Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) 
+      (20949, "x-cp20949"), # Korean Wansung 
+      (21025, "cp1025"), # IBM EBCDIC Cyrillic Serbian-Bulgarian 
+      (21027, ""), # (deprecated) 
+      (21866, "koi8-u"), # Ukrainian (KOI8-U); Cyrillic (KOI8-U) 
+      (28591, "iso-8859-1"), # ISO 8859-1 Latin 1; Western European (ISO) 
+      (28592, "iso-8859-2"), # ISO 8859-2 Central European; Central European (ISO) 
+      (28593, "iso-8859-3"), # ISO 8859-3 Latin 3 
+      (28594, "iso-8859-4"), # ISO 8859-4 Baltic 
+      (28595, "iso-8859-5"), # ISO 8859-5 Cyrillic 
+      (28596, "iso-8859-6"), # ISO 8859-6 Arabic 
+      (28597, "iso-8859-7"), # ISO 8859-7 Greek 
+      (28598, "iso-8859-8"), # ISO 8859-8 Hebrew; Hebrew (ISO-Visual) 
+      (28599, "iso-8859-9"), # ISO 8859-9 Turkish 
+      (28603, "iso-8859-13"), # ISO 8859-13 Estonian 
+      (28605, "iso-8859-15"), # ISO 8859-15 Latin 9 
+      (29001, "x-Europa"), # Europa 3 
+      (38598, "iso-8859-8-i"), # ISO 8859-8 Hebrew; Hebrew (ISO-Logical) 
+      (50220, "iso-2022-jp"), # ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) 
+      (50221, "csISO2022JP"), # ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) 
+      (50222, "iso-2022-jp"), # ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) 
+      (50225, "iso-2022-kr"), # ISO 2022 Korean 
+      (50227, "x-cp50227"), # ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) 
+      (50229, ""), # ISO 2022 Traditional Chinese 
+      (50930, ""), # EBCDIC Japanese (Katakana) Extended 
+      (50931, ""), # EBCDIC US-Canada and Japanese 
+      (50933, ""), # EBCDIC Korean Extended and Korean 
+      (50935, ""), # EBCDIC Simplified Chinese Extended and Simplified Chinese 
+      (50936, ""), # EBCDIC Simplified Chinese 
+      (50937, ""), # EBCDIC US-Canada and Traditional Chinese 
+      (50939, ""), # EBCDIC Japanese (Latin) Extended and Japanese 
+      (51932, "euc-jp"), # EUC Japanese 
+      (51936, "EUC-CN"), # EUC Simplified Chinese; Chinese Simplified (EUC) 
+      (51949, "euc-kr"), # EUC Korean 
+      (51950, ""), # EUC Traditional Chinese 
+      (52936, "hz-gb-2312"), # HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) 
+      (54936, "GB18030"), # Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) 
+      (57002, "x-iscii-de"), # ISCII Devanagari 
+      (57003, "x-iscii-be"), # ISCII Bengali 
+      (57004, "x-iscii-ta"), # ISCII Tamil 
+      (57005, "x-iscii-te"), # ISCII Telugu 
+      (57006, "x-iscii-as"), # ISCII Assamese 
+      (57007, "x-iscii-or"), # ISCII Oriya 
+      (57008, "x-iscii-ka"), # ISCII Kannada 
+      (57009, "x-iscii-ma"), # ISCII Malayalam 
+      (57010, "x-iscii-gu"), # ISCII Gujarati 
+      (57011, "x-iscii-pa"), # ISCII Punjabi 
+      (65000, "utf-7"), # Unicode (UTF-7) 
+      (65001, "utf-8")] # Unicode (UTF-8) 
+  
+  when false:
+    # not needed yet:
+    type
+      TCpInfo = object
+        maxCharSize: int32
+        defaultChar: array[0..1, char]
+        leadByte: array[0..12-1, char]
+
+    proc getCPInfo(codePage: CodePage, lpCPInfo: var TCpInfo): int32 {.
+      stdcall, importc: "GetCPInfo", dynlib: "kernel32".}
+  
+  proc nameToCodePage(name: string): CodePage =
+    var nameAsInt: int
+    if parseInt(name, nameAsInt) == 0: nameAsInt = -1
+    for no, na in items(winEncodings):
+      if no == nameAsInt or eqEncodingNames(na, name): return CodePage(no)
+    result = CodePage(-1)
+    
+  proc codePageToName(c: CodePage): string =
+    for no, na in items(winEncodings):
+      if no == int(c):
+        return if na.len != 0: na else: $no
+    result = ""
+  
+  proc getACP(): CodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".}
+  
+  proc multiByteToWideChar(
+    codePage: CodePage,
+    dwFlags: int32,
+    lpMultiByteStr: cstring,
+    cbMultiByte: cint,
+    lpWideCharStr: cstring,
+    cchWideChar: cint): cint {.
+      stdcall, importc: "MultiByteToWideChar", dynlib: "kernel32".}
+
+  proc wideCharToMultiByte(
+    codePage: CodePage,
+    dwFlags: int32,
+    lpWideCharStr: cstring,
+    cchWideChar: cint,
+    lpMultiByteStr: cstring,
+    cbMultiByte: cint,
+    lpDefaultChar: cstring=nil,
+    lpUsedDefaultChar: pointer=nil): cint {.
+      stdcall, importc: "WideCharToMultiByte", dynlib: "kernel32".}
+  
+else:
+  when defined(haiku):
+    const iconvDll = "(libc.so.6|libiconv.so|libtextencoding.so)"
+  elif defined(macosx):
+    const iconvDll = "libiconv.dylib"
+  else:
+    const iconvDll = "(libc.so.6|libiconv.so)"
+
+  when defined(macosx) and defined(powerpc):
+    const prefix = "lib"
+  else:
+    const prefix = ""
+
+  const
+    E2BIG = 7.cint
+    EINVAL = 22.cint
+  when defined(linux):
+    const EILSEQ = 84.cint
+  elif defined(macosx):
+    const EILSEQ = 92.cint
+  elif defined(bsd):
+    const EILSEQ = 86.cint
+  elif defined(solaris):
+    const EILSEQ = 88.cint
+
+  var errno {.importc, header: "<errno.h>".}: cint
+
+  proc iconvOpen(tocode, fromcode: cstring): EncodingConverter {.
+    importc: prefix & "iconv_open", cdecl, dynlib: iconvDll.}
+  proc iconvClose(c: EncodingConverter) {.
+    importc: prefix & "iconv_close", cdecl, dynlib: iconvDll.}
+  proc iconv(c: EncodingConverter, inbuf: var cstring, inbytesLeft: var int,
+             outbuf: var cstring, outbytesLeft: var int): int {.
+    importc: prefix & "iconv", cdecl, dynlib: iconvDll.}
+  proc iconv(c: EncodingConverter, inbuf: pointer, inbytesLeft: pointer,
+             outbuf: var cstring, outbytesLeft: var int): int {.
+    importc: prefix & "iconv", cdecl, dynlib: iconvDll.}
+  
+proc getCurrentEncoding*(): string =
+  ## retrieves the current encoding. On Unix, always "UTF-8" is returned.
+  when defined(windows):
+    result = codePageToName(getACP())
+  else:
+    result = "UTF-8"
+  
+proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter =
+  ## opens a converter that can convert from `srcEncoding` to `destEncoding`.
+  ## Raises `EIO` if it cannot fulfill the request.
+  when not defined(windows):
+    result = iconvOpen(destEncoding, srcEncoding)
+    if result == nil:
+      raise newException(EncodingError, 
+        "cannot create encoding converter from " & 
+        srcEncoding & " to " & destEncoding)
+  else:
+    result.dest = nameToCodePage(destEncoding)
+    result.src = nameToCodePage(srcEncoding)
+    if int(result.dest) == -1:
+      raise newException(EncodingError, 
+        "cannot find encoding " & destEncoding)
+    if int(result.src) == -1:
+      raise newException(EncodingError, 
+        "cannot find encoding " & srcEncoding)
+
+proc close*(c: EncodingConverter) =
+  ## frees the resources the converter `c` holds.
+  when not defined(windows):
+    iconvClose(c)
+
+when defined(windows):
+  proc convert*(c: EncodingConverter, s: string): string =
+    ## converts `s` to `destEncoding` that was given to the converter `c`. It
+    ## assumed that `s` is in `srcEncoding`.
+    
+    # special case: empty string: needed because MultiByteToWideChar
+    # return 0 in case of error:
+    if s.len == 0: return ""
+    # educated guess of capacity:
+    var cap = s.len + s.len shr 2
+    result = newStringOfCap(cap*2)
+    # convert to utf-16 LE
+    var m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32, 
+                                lpMultiByteStr = cstring(s),
+                                cbMultiByte = cint(s.len),
+                                lpWideCharStr = cstring(result),
+                                cchWideChar = cint(cap))
+    if m == 0: 
+      # try again; ask for capacity:
+      cap = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32, 
+                                lpMultiByteStr = cstring(s),
+                                cbMultiByte = cint(s.len),
+                                lpWideCharStr = nil,
+                                cchWideChar = cint(0))
+      # and do the conversion properly:
+      result = newStringOfCap(cap*2)
+      m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32, 
+                              lpMultiByteStr = cstring(s),
+                              cbMultiByte = cint(s.len),
+                              lpWideCharStr = cstring(result),
+                              cchWideChar = cint(cap))
+      if m == 0: raiseOSError(osLastError())
+      setLen(result, m*2)
+    elif m <= cap:
+      setLen(result, m*2)
+    else:
+      assert(false) # cannot happen
+    
+    # if already utf-16 LE, no further need to do something:
+    if int(c.dest) == 1200: return
+    # otherwise the fun starts again:
+    cap = s.len + s.len shr 2
+    var res = newStringOfCap(cap)
+    m = wideCharToMultiByte(
+      codePage = c.dest,
+      dwFlags = 0'i32,
+      lpWideCharStr = cstring(result),
+      cchWideChar = cint(result.len div 2),
+      lpMultiByteStr = cstring(res),
+      cbMultiByte = cap.cint)
+    if m == 0:
+      # try again; ask for capacity:
+      cap = wideCharToMultiByte(
+        codePage = c.dest,
+        dwFlags = 0'i32,
+        lpWideCharStr = cstring(result),
+        cchWideChar = cint(result.len div 2),
+        lpMultiByteStr = nil,
+        cbMultiByte = cint(0))
+      # and do the conversion properly:
+      res = newStringOfCap(cap)
+      m = wideCharToMultiByte(
+        codePage = c.dest,
+        dwFlags = 0'i32,
+        lpWideCharStr = cstring(result),
+        cchWideChar = cint(result.len div 2),
+        lpMultiByteStr = cstring(res),
+        cbMultiByte = cap.cint)
+      if m == 0: raiseOSError(osLastError())
+      setLen(res, m)
+      result = res
+    elif m <= cap:
+      setLen(res, m)
+      result = res
+    else:
+      assert(false) # cannot happen
+
+else:
+  proc convert*(c: EncodingConverter, s: string): string =
+    result = newString(s.len)
+    var inLen = len(s)
+    var outLen = len(result)
+    var src = cstring(s)
+    var dst = cstring(result)
+    var iconvres: int
+    while inLen > 0:
+      iconvres = iconv(c, src, inLen, dst, outLen)
+      if iconvres == -1:
+        var lerr = errno
+        if lerr == EILSEQ or lerr == EINVAL:
+          # unknown char, skip
+          dst[0] = src[0]
+          src = cast[cstring](cast[int](src) + 1)
+          dst = cast[cstring](cast[int](dst) + 1)
+          dec(inLen)
+          dec(outLen)
+        elif lerr == E2BIG:
+          var offset = cast[int](dst) - cast[int](cstring(result))
+          setLen(result, len(result)+inLen*2+5)
+          # 5 is minimally one utf-8 char
+          dst = cast[cstring](cast[int](cstring(result)) + offset)
+          outLen = len(result) - offset
+        else:
+          raiseOSError(lerr.OSErrorCode)
+    # iconv has a buffer that needs flushing, specially if the last char is 
+    # not '\0'
+    discard iconv(c, nil, nil, dst, outLen)
+    if iconvres == cint(-1) and errno == E2BIG:
+      var offset = cast[int](dst) - cast[int](cstring(result))
+      setLen(result, len(result)+inLen*2+5)
+      # 5 is minimally one utf-8 char
+      dst = cast[cstring](cast[int](cstring(result)) + offset)
+      outLen = len(result) - offset
+      discard iconv(c, nil, nil, dst, outLen)
+    # trim output buffer
+    setLen(result, len(result) - outLen)
+
+proc convert*(s: string, destEncoding = "UTF-8", 
+                         srcEncoding = "CP1252"): string =
+  ## converts `s` to `destEncoding`. It assumed that `s` is in `srcEncoding`.
+  ## This opens a converter, uses it and closes it again and is thus more
+  ## convienent but also likely less efficient than re-using a converter.
+  var c = open(destEncoding, srcEncoding)
+  try:
+    result = convert(c, s)
+  finally:
+    close(c)
+
+when not defined(testing) and isMainModule:
+  let
+    orig = "öäüß"
+    cp1252 = convert(orig, "CP1252", "UTF-8")
+    ibm850 = convert(cp1252, "ibm850", "CP1252")
+    current = getCurrentEncoding()
+  echo "Original string from source code: ", orig
+  echo "Forced ibm850 encoding: ", ibm850
+  echo "Current encoding: ", current
+  echo "From ibm850 to current: ", convert(ibm850, current, "ibm850")
+
diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim
new file mode 100644
index 000000000..6e33d4624
--- /dev/null
+++ b/lib/pure/endians.nim
@@ -0,0 +1,59 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains helpers that deal with different byte orders
+## (`endian`:idx:).
+
+proc swapEndian64*(outp, inp: pointer) =
+  ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
+  ## contain at least 8 bytes.
+  var i = cast[cstring](inp)
+  var o = cast[cstring](outp)
+  o[0] = i[7]
+  o[1] = i[6]
+  o[2] = i[5]
+  o[3] = i[4]
+  o[4] = i[3]
+  o[5] = i[2]
+  o[6] = i[1]
+  o[7] = i[0]
+
+proc swapEndian32*(outp, inp: pointer) = 
+  ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
+  ## contain at least 4 bytes.
+  var i = cast[cstring](inp)
+  var o = cast[cstring](outp)
+  o[0] = i[3]
+  o[1] = i[2]
+  o[2] = i[1]
+  o[3] = i[0]
+
+proc swapEndian16*(outp, inp: pointer) = 
+  ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
+  ## contain at least 2 bytes.
+  var
+    i = cast[cstring](inp)
+    o = cast[cstring](outp)
+  o[0] = i[1]
+  o[1] = i[0]
+
+when system.cpuEndian == bigEndian:
+  proc littleEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp)
+  proc littleEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp)
+  proc littleEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp)
+  proc bigEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8)
+  proc bigEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4)
+  proc bigEndian16*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2)
+else: 
+  proc littleEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8)
+  proc littleEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4)
+  proc littleEndian16*(outp, inp: pointer){.inline.} = copyMem(outp, inp, 2)
+  proc bigEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp)
+  proc bigEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp)
+  proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp)
diff --git a/lib/pure/events.nim b/lib/pure/events.nim
new file mode 100644
index 000000000..44e9ed286
--- /dev/null
+++ b/lib/pure/events.nim
@@ -0,0 +1,103 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2011 Alex Mitchell
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## :Author: Alex Mitchell
+##
+## This module implements an event system that is not dependent on external
+## graphical toolkits. It was originally called ``NimEE`` because 
+## it was inspired by Python's PyEE module. There are two ways you can use
+## events: one is a python-inspired way; the other is more of a C-style way.
+##
+## .. code-block:: Nim
+##    var ee = initEventEmitter()
+##    var genericargs: EventArgs
+##    proc handleevent(e: EventArgs) =
+##        echo("Handled!")
+##
+##    # Python way
+##    ee.on("EventName", handleevent)
+##    ee.emit("EventName", genericargs)
+## 
+##    # C/Java way
+##    # Declare a type
+##    type
+##        SomeObject = object of RootObj
+##            SomeEvent: EventHandler
+##    var myobj: SomeObject
+##    myobj.SomeEvent = initEventHandler("SomeEvent")
+##    myobj.SomeEvent.addHandler(handleevent)
+##    ee.emit(myobj.SomeEvent, genericargs)
+
+type
+  EventArgs* = object of RootObj ## Base object for event arguments that are passed to callback functions.
+  EventHandler* = tuple[name: string, handlers: seq[proc(e: EventArgs) {.closure.}]] ## An eventhandler for an event.
+
+type
+  EventEmitter* = object ## An object that fires events and holds event handlers for an object.
+    s: seq[EventHandler]
+  EventError* = object of ValueError
+
+{.deprecated: [TEventArgs: EventArgs, TEventHandler: EventHandler,
+  TEventEmitter: EventEmitter, EInvalidEvent: EventError].}
+    
+proc initEventHandler*(name: string): EventHandler =
+  ## Initializes an EventHandler with the specified name and returns it.
+  result.handlers = @[]
+  result.name = name
+
+proc addHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}) =
+  ## Adds the callback to the specified event handler.
+  handler.handlers.add(fn)
+
+proc removeHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}) =
+  ## Removes the callback from the specified event handler.
+  for i in countup(0, len(handler.handlers) -1):
+    if fn == handler.handlers[i]:
+      handler.handlers.del(i)
+      break
+    
+proc containsHandler*(handler: var EventHandler, fn: proc(e: EventArgs) {.closure.}): bool =
+  ## Checks if a callback is registered to this event handler.
+  return handler.handlers.contains(fn)
+
+
+proc clearHandlers*(handler: var EventHandler) =
+  ## Clears all of the callbacks from the event handler.
+  setLen(handler.handlers, 0)
+
+proc getEventHandler(emitter: var EventEmitter, event: string): int =
+  for k in 0..high(emitter.s):
+    if emitter.s[k].name == event: return k
+  return -1
+
+proc on*(emitter: var EventEmitter, event: string, fn: proc(e: EventArgs) {.closure.}) =
+  ## Assigns a event handler with the specified callback. If the event
+  ## doesn't exist, it will be created.
+  var i = getEventHandler(emitter, event)
+  if i < 0:
+    var eh = initEventHandler(event)
+    addHandler(eh, fn)
+    emitter.s.add(eh)
+  else:
+    addHandler(emitter.s[i], fn)
+  
+proc emit*(emitter: var EventEmitter, eventhandler: var EventHandler, 
+           args: EventArgs) =
+  ## Fires an event handler with specified event arguments.
+  for fn in items(eventhandler.handlers): fn(args)
+
+proc emit*(emitter: var EventEmitter, event: string, args: EventArgs) =
+  ## Fires an event handler with specified event arguments.
+  var i = getEventHandler(emitter, event)
+  if i >= 0:
+    emit(emitter, emitter.s[i], args)
+
+proc initEventEmitter*(): EventEmitter =
+  ## Creates and returns a new EventEmitter.
+  result.s = @[]
diff --git a/lib/pure/fenv.nim b/lib/pure/fenv.nim
new file mode 100644
index 000000000..f8f115ecc
--- /dev/null
+++ b/lib/pure/fenv.nim
@@ -0,0 +1,181 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Floating-point environment. Handling of floating-point rounding and
+## exceptions (overflow, division by zero, etc.).
+
+{.deadCodeElim:on.}
+
+when defined(Posix) and not defined(haiku):
+  {.passl: "-lm".}
+
+var
+  FE_DIVBYZERO* {.importc, header: "<fenv.h>".}: cint
+    ## division by zero
+  FE_INEXACT* {.importc, header: "<fenv.h>".}: cint
+    ## inexact result
+  FE_INVALID* {.importc, header: "<fenv.h>".}: cint
+    ## invalid operation
+  FE_OVERFLOW* {.importc, header: "<fenv.h>".}: cint
+    ## result not representable due to overflow
+  FE_UNDERFLOW* {.importc, header: "<fenv.h>".}: cint
+    ## result not representable due to underflow
+  FE_ALL_EXCEPT* {.importc, header: "<fenv.h>".}: cint
+    ## bitwise OR of all supported exceptions
+  FE_DOWNWARD* {.importc, header: "<fenv.h>".}: cint
+    ## round toward -Inf
+  FE_TONEAREST* {.importc, header: "<fenv.h>".}: cint
+    ## round to nearest
+  FE_TOWARDZERO* {.importc, header: "<fenv.h>".}: cint
+    ## round toward 0
+  FE_UPWARD* {.importc, header: "<fenv.h>".}: cint
+    ## round toward +Inf
+  FE_DFL_ENV* {.importc, header: "<fenv.h>".}: cint
+    ## macro of type pointer to fenv_t to be used as the argument
+    ## to functions taking an argument of type fenv_t; in this
+    ## case the default environment will be used
+
+type
+  Tfenv* {.importc: "fenv_t", header: "<fenv.h>", final, pure.} =
+    object ## Represents the entire floating-point environment. The
+           ## floating-point environment refers collectively to any
+           ## floating-point status flags and control modes supported
+           ## by the implementation.
+  Tfexcept* {.importc: "fexcept_t", header: "<fenv.h>", final, pure.} =
+    object ## Represents the floating-point status flags collectively,
+           ## including any status the implementation associates with the
+           ## flags. A floating-point status flag is a system variable
+           ## whose value is set (but never cleared) when a floating-point
+           ## exception is raised, which occurs as a side effect of
+           ## exceptional floating-point arithmetic to provide auxiliary
+           ## information. A floating-point control mode is a system variable
+           ## whose value may be set by the user to affect the subsequent
+           ## behavior of floating-point arithmetic.
+
+proc feclearexcept*(excepts: cint): cint {.importc, header: "<fenv.h>".}
+  ## Clear the supported exceptions represented by `excepts`.
+
+proc fegetexceptflag*(flagp: ptr Tfexcept, excepts: cint): cint {.
+  importc, header: "<fenv.h>".}
+  ## Store implementation-defined representation of the exception flags
+  ## indicated by `excepts` in the object pointed to by `flagp`.
+
+proc feraiseexcept*(excepts: cint): cint {.importc, header: "<fenv.h>".}
+  ## Raise the supported exceptions represented by `excepts`.
+
+proc fesetexceptflag*(flagp: ptr Tfexcept, excepts: cint): cint {.
+  importc, header: "<fenv.h>".}
+  ## Set complete status for exceptions indicated by `excepts` according to
+  ## the representation in the object pointed to by `flagp`.
+
+proc fetestexcept*(excepts: cint): cint {.importc, header: "<fenv.h>".}
+  ## Determine which of subset of the exceptions specified by `excepts` are
+  ## currently set.
+
+proc fegetround*(): cint {.importc, header: "<fenv.h>".}
+  ## Get current rounding direction.
+
+proc fesetround*(roundingDirection: cint): cint {.importc, header: "<fenv.h>".}
+  ## Establish the rounding direction represented by `roundingDirection`.
+
+proc fegetenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
+  ## Store the current floating-point environment in the object pointed
+  ## to by `envp`.
+
+proc feholdexcept*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
+  ## Save the current environment in the object pointed to by `envp`, clear
+  ## exception flags and install a non-stop mode (if available) for all
+  ## exceptions.
+
+proc fesetenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
+  ## Establish the floating-point environment represented by the object
+  ## pointed to by `envp`.
+
+proc feupdateenv*(envp: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
+  ## Save current exceptions in temporary storage, install environment
+  ## represented by object pointed to by `envp` and raise exceptions
+  ## according to saved exceptions.
+
+var FP_RADIX_INTERNAL {. importc: "FLT_RADIX" header: "<float.h>" .} : int
+
+template fpRadix* : int = FP_RADIX_INTERNAL
+  ## The (integer) value of the radix used to represent any floating
+  ## point type on the architecture used to build the program.
+
+var FLT_MANT_DIG {. importc: "FLT_MANT_DIG" header: "<float.h>" .} : int
+var FLT_DIG {. importc: "FLT_DIG" header: "<float.h>" .} : int
+var FLT_MIN_EXP {. importc: "FLT_MIN_EXP" header: "<float.h>" .} : int
+var FLT_MAX_EXP {. importc: "FLT_MAX_EXP" header: "<float.h>" .} : int
+var FLT_MIN_10_EXP {. importc: "FLT_MIN_10_EXP" header: "<float.h>" .} : int
+var FLT_MAX_10_EXP {. importc: "FLT_MAX_10_EXP" header: "<float.h>" .} : int
+var FLT_MIN {. importc: "FLT_MIN" header: "<float.h>" .} : cfloat
+var FLT_MAX {. importc: "FLT_MAX" header: "<float.h>" .} : cfloat
+var FLT_EPSILON {. importc: "FLT_EPSILON" header: "<float.h>" .} : cfloat
+
+var DBL_MANT_DIG {. importc: "DBL_MANT_DIG" header: "<float.h>" .} : int
+var DBL_DIG {. importc: "DBL_DIG" header: "<float.h>" .} : int
+var DBL_MIN_EXP {. importc: "DBL_MIN_EXP" header: "<float.h>" .} : int
+var DBL_MAX_EXP {. importc: "DBL_MAX_EXP" header: "<float.h>" .} : int
+var DBL_MIN_10_EXP {. importc: "DBL_MIN_10_EXP" header: "<float.h>" .} : int
+var DBL_MAX_10_EXP {. importc: "DBL_MAX_10_EXP" header: "<float.h>" .} : int
+var DBL_MIN {. importc: "DBL_MIN" header: "<float.h>" .} : cdouble
+var DBL_MAX {. importc: "DBL_MAX" header: "<float.h>" .} : cdouble
+var DBL_EPSILON {. importc: "DBL_EPSILON" header: "<float.h>" .} : cdouble
+
+template mantissaDigits*(T : typedesc[float32]) : int = FLT_MANT_DIG
+  ## Number of digits (in base ``floatingPointRadix``) in the mantissa
+  ## of 32-bit floating-point numbers.
+template digits*(T : typedesc[float32]) : int = FLT_DIG
+  ## Number of decimal digits that can be represented in a
+  ## 32-bit floating-point type without losing precision.
+template minExponent*(T : typedesc[float32]) : int = FLT_MIN_EXP
+  ## Minimum (negative) exponent for 32-bit floating-point numbers.
+template maxExponent*(T : typedesc[float32]) : int = FLT_MAX_EXP
+  ## Maximum (positive) exponent for 32-bit floating-point numbers.
+template min10Exponent*(T : typedesc[float32]) : int = FLT_MIN_10_EXP
+  ## Minimum (negative) exponent in base 10 for 32-bit floating-point
+  ## numbers.
+template max10Exponent*(T : typedesc[float32]) : int = FLT_MAX_10_EXP
+  ## Maximum (positive) exponent in base 10 for 32-bit floating-point
+  ## numbers.
+template minimumPositiveValue*(T : typedesc[float32]) : float32 = FLT_MIN
+  ## The smallest positive (nonzero) number that can be represented in a
+  ## 32-bit floating-point type.
+template maximumPositiveValue*(T : typedesc[float32]) : float32 = FLT_MAX
+  ## The largest positive number that can be represented in a 32-bit
+  ## floating-point type.
+template epsilon*(T : typedesc[float32]): float32 = FLT_EPSILON
+  ## The difference between 1.0 and the smallest number greater than
+  ## 1.0 that can be represented in a 32-bit floating-point type.
+
+template mantissaDigits*(T : typedesc[float64]) : int = DBL_MANT_DIG
+  ## Number of digits (in base ``floatingPointRadix``) in the mantissa
+  ## of 64-bit floating-point numbers.
+template digits*(T : typedesc[float64]) : int = DBL_DIG
+  ## Number of decimal digits that can be represented in a
+  ## 64-bit floating-point type without losing precision.
+template minExponent*(T : typedesc[float64]) : int = DBL_MIN_EXP
+  ## Minimum (negative) exponent for 64-bit floating-point numbers.
+template maxExponent*(T : typedesc[float64]) : int = DBL_MAX_EXP
+  ## Maximum (positive) exponent for 64-bit floating-point numbers.
+template min10Exponent*(T : typedesc[float64]) : int = DBL_MIN_10_EXP
+  ## Minimum (negative) exponent in base 10 for 64-bit floating-point
+  ## numbers.
+template max10Exponent*(T : typedesc[float64]) : int = DBL_MAX_10_EXP
+  ## Maximum (positive) exponent in base 10 for 64-bit floating-point
+  ## numbers.
+template minimumPositiveValue*(T : typedesc[float64]) : float64 = DBL_MIN
+  ## The smallest positive (nonzero) number that can be represented in a
+  ## 64-bit floating-point type.
+template maximumPositiveValue*(T : typedesc[float64]) : float64 = DBL_MAX
+  ## The largest positive number that can be represented in a 64-bit
+  ## floating-point type.
+template epsilon*(T : typedesc[float64]): float64 = DBL_EPSILON
+  ## The difference between 1.0 and the smallest number greater than
+  ## 1.0 that can be represented in a 64-bit floating-point type.
diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim
new file mode 100644
index 000000000..83779eb9c
--- /dev/null
+++ b/lib/pure/fsmonitor.nim
@@ -0,0 +1,217 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module allows you to monitor files or directories for changes using
+## asyncio.
+##
+## Windows support is not yet implemented.
+##
+## **Note:** This module uses ``inotify`` on Linux (Other Unixes are not yet
+## supported). ``inotify`` was merged into the 2.6.13 Linux kernel, this
+## module will therefore not work with any Linux kernel prior to that, unless
+## it has been patched to support inotify.
+
+when defined(linux) or defined(nimdoc):
+  from posix import read
+else:
+  {.error: "Your platform is not supported.".}
+
+import inotify, os, asyncio, tables
+
+type
+  FSMonitor* = ref FSMonitorObj
+  FSMonitorObj = object of RootObj
+    fd: cint
+    handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
+    targets: Table[cint, string]
+  
+  MonitorEventType* = enum ## Monitor event type
+    MonitorAccess,       ## File was accessed.
+    MonitorAttrib,       ## Metadata changed.
+    MonitorCloseWrite,   ## Writtable file was closed.
+    MonitorCloseNoWrite, ## Unwrittable file closed.
+    MonitorCreate,       ## Subfile was created.
+    MonitorDelete,       ## Subfile was deleted.
+    MonitorDeleteSelf,   ## Watched file/directory was itself deleted.
+    MonitorModify,       ## File was modified.
+    MonitorMoveSelf,     ## Self was moved.
+    MonitorMoved,        ## File was moved.
+    MonitorOpen,         ## File was opened.
+    MonitorAll           ## Filter for all event types.
+  
+  MonitorEvent* = object
+    case kind*: MonitorEventType  ## Type of the event.
+    of MonitorMoveSelf, MonitorMoved:
+      oldPath*: string          ## Old absolute location
+      newPath*: string          ## New absolute location
+    else:
+      fullname*: string         ## Absolute filename of the file/directory affected.
+    name*: string             ## Non absolute filepath of the file/directory
+                              ## affected relative to the directory watched.
+                              ## "" if this event refers to the file/directory
+                              ## watched.
+    wd*: cint                 ## Watch descriptor.
+
+{.deprecated: [PFSMonitor: FSMonitor, TFSMonitor: FSMonitorObj,
+  TMonitorEventType: MonitorEventType, TMonitorEvent: MonitorEvent].}
+
+const
+  MaxEvents = 100
+
+proc newMonitor*(): FSMonitor =
+  ## Creates a new file system monitor.
+  new(result)
+  result.targets = initTable[cint, string]()
+  result.fd = inotifyInit()
+  if result.fd < 0:
+    raiseOSError(osLastError())
+
+proc add*(monitor: FSMonitor, target: string,
+               filters = {MonitorAll}): cint {.discardable.} =
+  ## Adds ``target`` which may be a directory or a file to the list of
+  ## watched paths of ``monitor``.
+  ## You can specify the events to report using the ``filters`` parameter.
+  
+  var INFilter = -1
+  for f in filters:
+    case f
+    of MonitorAccess: INFilter = INFilter and IN_ACCESS
+    of MonitorAttrib: INFilter = INFilter and IN_ATTRIB
+    of MonitorCloseWrite: INFilter = INFilter and IN_CLOSE_WRITE
+    of MonitorCloseNoWrite: INFilter = INFilter and IN_CLOSE_NO_WRITE
+    of MonitorCreate: INFilter = INFilter and IN_CREATE
+    of MonitorDelete: INFilter = INFilter and IN_DELETE
+    of MonitorDeleteSelf: INFilter = INFilter and IN_DELETE_SELF
+    of MonitorModify: INFilter = INFilter and IN_MODIFY
+    of MonitorMoveSelf: INFilter = INFilter and IN_MOVE_SELF
+    of MonitorMoved: INFilter = INFilter and IN_MOVED_FROM and IN_MOVED_TO
+    of MonitorOpen: INFilter = INFilter and IN_OPEN
+    of MonitorAll: INFilter = INFilter and IN_ALL_EVENTS
+  
+  result = inotifyAddWatch(monitor.fd, target, INFilter.uint32)
+  if result < 0:
+    raiseOSError(osLastError())
+  monitor.targets.add(result, target)
+
+proc del*(monitor: FSMonitor, wd: cint) =
+  ## Removes watched directory or file as specified by ``wd`` from ``monitor``.
+  ##
+  ## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
+  if inotifyRmWatch(monitor.fd, wd) < 0:
+    raiseOSError(osLastError())
+
+proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
+  result = @[]
+  let size = (sizeof(TINotifyEvent)+2000)*MaxEvents
+  var buffer = newString(size)
+
+  let le = read(fd, addr(buffer[0]), size)
+
+  var movedFrom = initTable[cint, tuple[wd: cint, old: string]]()
+
+  var i = 0
+  while i < le:
+    var event = cast[ptr TINotifyEvent](addr(buffer[i]))
+    var mev: MonitorEvent
+    mev.wd = event.wd
+    if event.len.int != 0:
+      let cstr = event.name.addr.cstring
+      mev.name = $cstr
+    else:
+      mev.name = ""
+    
+    if (event.mask.int and IN_MOVED_FROM) != 0: 
+      # Moved from event, add to m's collection
+      movedFrom.add(event.cookie.cint, (mev.wd, mev.name))
+      inc(i, sizeof(TINotifyEvent) + event.len.int)
+      continue
+    elif (event.mask.int and IN_MOVED_TO) != 0: 
+      mev.kind = MonitorMoved
+      assert movedFrom.hasKey(event.cookie.cint)
+      # Find the MovedFrom event.
+      mev.oldPath = movedFrom[event.cookie.cint].old
+      mev.newPath = "" # Set later
+      # Delete it from the Table
+      movedFrom.del(event.cookie.cint)
+    elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess
+    elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib
+    elif (event.mask.int and IN_CLOSE_WRITE) != 0: 
+      mev.kind = MonitorCloseWrite
+    elif (event.mask.int and IN_CLOSE_NOWRITE) != 0: 
+      mev.kind = MonitorCloseNoWrite
+    elif (event.mask.int and IN_CREATE) != 0: mev.kind = MonitorCreate
+    elif (event.mask.int and IN_DELETE) != 0: 
+      mev.kind = MonitorDelete
+    elif (event.mask.int and IN_DELETE_SELF) != 0: 
+      mev.kind = MonitorDeleteSelf
+    elif (event.mask.int and IN_MODIFY) != 0: mev.kind = MonitorModify
+    elif (event.mask.int and IN_MOVE_SELF) != 0: 
+      mev.kind = MonitorMoveSelf
+    elif (event.mask.int and IN_OPEN) != 0: mev.kind = MonitorOpen
+    
+    if mev.kind != MonitorMoved:
+      mev.fullname = ""
+    
+    result.add(mev)
+    inc(i, sizeof(TINotifyEvent) + event.len.int)
+
+  # If movedFrom events have not been matched with a moveTo. File has
+  # been moved to an unwatched location, emit a MonitorDelete.
+  for cookie, t in pairs(movedFrom):
+    var mev: MonitorEvent
+    mev.kind = MonitorDelete
+    mev.wd = t.wd
+    mev.name = t.old
+    result.add(mev)
+
+proc FSMonitorRead(h: RootRef) =
+  var events = FSMonitor(h).getEvent(FSMonitor(h).fd)
+  #var newEv: MonitorEvent
+  for ev in events:
+    var target = FSMonitor(h).targets[ev.wd]
+    var newEv = ev
+    if newEv.kind == MonitorMoved:
+      newEv.oldPath = target / newEv.oldPath
+      newEv.newPath = target / newEv.name
+    else:
+      newEv.fullName = target / newEv.name
+    FSMonitor(h).handleEvent(FSMonitor(h), newEv)
+
+proc toDelegate(m: FSMonitor): Delegate =
+  result = newDelegate()
+  result.deleVal = m
+  result.fd = (type(result.fd))(m.fd)
+  result.mode = fmRead
+  result.handleRead = FSMonitorRead
+  result.open = true
+
+proc register*(d: Dispatcher, monitor: FSMonitor,
+               handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}) =
+  ## Registers ``monitor`` with dispatcher ``d``.
+  monitor.handleEvent = handleEvent
+  var deleg = toDelegate(monitor)
+  d.register(deleg)
+
+when not defined(testing) and isMainModule:
+  proc main =
+    var disp = newDispatcher()
+    var monitor = newMonitor()
+    echo monitor.add("/home/dom/inotifytests/")
+    disp.register(monitor,
+      proc (m: FSMonitor, ev: MonitorEvent) =
+        echo("Got event: ", ev.kind)
+        if ev.kind == MonitorMoved:
+          echo("From ", ev.oldPath, " to ", ev.newPath)
+          echo("Name is ", ev.name)
+        else:
+          echo("Name ", ev.name, " fullname ", ev.fullName))
+        
+    while true:
+      if not disp.poll(): break
+  main()
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
new file mode 100644
index 000000000..dd141eb01
--- /dev/null
+++ b/lib/pure/ftpclient.nim
@@ -0,0 +1,646 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+include "system/inclrtl"
+
+import sockets, strutils, parseutils, times, os, asyncio
+
+from asyncnet import nil
+from rawsockets import nil
+from asyncdispatch import PFuture
+
+## This module **partially** implements an FTP client as specified
+## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_.
+##
+## This module provides both a synchronous and asynchronous implementation.
+## The asynchronous implementation requires you to use the ``asyncFTPClient``
+## function. You are then required to register the ``AsyncFTPClient`` with a
+## asyncio dispatcher using the ``register`` function. Take a look at the
+## asyncio module documentation for more information.
+##
+## **Note**: The asynchronous implementation is only asynchronous for long
+## file transfers, calls to functions which use the command socket will block.
+##
+## Here is some example usage of this module:
+##
+## .. code-block:: Nim
+##    var ftp = ftpClient("example.org", user = "user", pass = "pass")
+##    ftp.connect()
+##    ftp.retrFile("file.ext", "file.ext")
+##
+## **Warning:** The API of this module is unstable, and therefore is subject
+## to change.
+
+type
+  FtpBase*[SockType] = ref FtpBaseObj[SockType]
+  FtpBaseObj*[SockType] = object
+    csock*: SockType
+    dsock*: SockType
+    when SockType is asyncio.AsyncSocket:
+      handleEvent*: proc (ftp: AsyncFTPClient, ev: FTPEvent){.closure,gcsafe.}
+      disp: Dispatcher
+      asyncDSockID: Delegate
+    user*, pass*: string
+    address*: string
+    when SockType is asyncnet.AsyncSocket:
+      port*: rawsockets.Port
+    else:
+      port*: Port
+
+    jobInProgress*: bool
+    job*: FTPJob[SockType]
+
+    dsockConnected*: bool
+
+  FTPJobType* = enum
+    JRetrText, JRetr, JStore
+
+  FtpJob[T] = ref FtpJobObj[T]
+  FTPJobObj[T] = object
+    prc: proc (ftp: FTPBase[T], async: bool): bool {.nimcall, gcsafe.}
+    case typ*: FTPJobType
+    of JRetrText:
+      lines: string
+    of JRetr, JStore:
+      file: File
+      filename: string
+      total: BiggestInt # In bytes.
+      progress: BiggestInt # In bytes.
+      oneSecond: BiggestInt # Bytes transferred in one second.
+      lastProgressReport: float # Time
+      toStore: string # Data left to upload (Only used with async)
+    else: nil
+
+  FtpClientObj* = FtpBaseObj[Socket]
+  FtpClient* = ref FtpClientObj
+
+  AsyncFtpClient* = ref AsyncFtpClientObj ## Async alternative to TFTPClient.
+  AsyncFtpClientObj* = FtpBaseObj[asyncio.AsyncSocket]
+
+  FTPEventType* = enum
+    EvTransferProgress, EvLines, EvRetr, EvStore
+
+  FTPEvent* = object ## Event
+    filename*: string
+    case typ*: FTPEventType
+    of EvLines:
+      lines*: string ## Lines that have been transferred.
+    of EvRetr, EvStore: ## Retr/Store operation finished.
+      nil
+    of EvTransferProgress:
+      bytesTotal*: BiggestInt     ## Bytes total.
+      bytesFinished*: BiggestInt  ## Bytes transferred.
+      speed*: BiggestInt          ## Speed in bytes/s
+      currentJob*: FTPJobType     ## The current job being performed.
+
+  ReplyError* = object of IOError
+  FTPError* = object of IOError
+
+{.deprecated: [
+  TFTPClient: FTPClientObj, TFTPJob: FTPJob, PAsyncFTPClient: AsyncFTPClient,
+  TAsyncFTPClient: AsyncFTPClientObj, TFTPEvent: FTPEvent,
+  EInvalidReply: ReplyError, EFTP: FTPError
+].}
+
+proc ftpClient*(address: string, port = Port(21),
+                user, pass = ""): FtpClient =
+  ## Create a ``FtpClient`` object.
+  new(result)
+  result.user = user
+  result.pass = pass
+  result.address = address
+  result.port = port
+
+  result.dsockConnected = false
+  result.csock = socket()
+  if result.csock == invalidSocket: raiseOSError(osLastError())
+
+template blockingOperation(sock: Socket, body: stmt) {.immediate.} =
+  body
+
+template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} =
+  sock.setBlocking(true)
+  body
+  sock.setBlocking(false)
+
+proc expectReply[T](ftp: FtpBase[T]): TaintedString =
+  result = TaintedString""
+  blockingOperation(ftp.csock):
+    when T is Socket:
+      ftp.csock.readLine(result)
+    else:
+      discard ftp.csock.readLine(result)
+
+proc send*[T](ftp: FtpBase[T], m: string): TaintedString =
+  ## Send a message to the server, and wait for a primary reply.
+  ## ``\c\L`` is added for you.
+  blockingOperation(ftp.csock):
+    ftp.csock.send(m & "\c\L")
+  return ftp.expectReply()
+
+proc assertReply(received: TaintedString, expected: string) =
+  if not received.string.startsWith(expected):
+    raise newException(ReplyError,
+                       "Expected reply '$1' got: $2" % [
+                       expected, received.string])
+
+proc assertReply(received: TaintedString, expected: varargs[string]) =
+  for i in items(expected):
+    if received.string.startsWith(i): return
+  raise newException(ReplyError,
+                     "Expected reply '$1' got: $2" %
+                     [expected.join("' or '"), received.string])
+
+proc createJob[T](ftp: FtpBase[T],
+               prc: proc (ftp: FtpBase[T], async: bool): bool {.
+                          nimcall,gcsafe.},
+               cmd: FTPJobType) =
+  if ftp.jobInProgress:
+    raise newException(FTPError, "Unable to do two jobs at once.")
+  ftp.jobInProgress = true
+  new(ftp.job)
+  ftp.job.prc = prc
+  ftp.job.typ = cmd
+  case cmd
+  of JRetrText:
+    ftp.job.lines = ""
+  of JRetr, JStore:
+    ftp.job.toStore = ""
+
+proc deleteJob[T](ftp: FtpBase[T]) =
+  assert ftp.jobInProgress
+  ftp.jobInProgress = false
+  case ftp.job.typ
+  of JRetrText:
+    ftp.job.lines = ""
+  of JRetr, JStore:
+    ftp.job.file.close()
+  ftp.dsock.close()
+
+proc handleTask(s: AsyncSocket, ftp: AsyncFTPClient) =
+  if ftp.jobInProgress:
+    if ftp.job.typ in {JRetr, JStore}:
+      if epochTime() - ftp.job.lastProgressReport >= 1.0:
+        var r: FTPEvent
+        ftp.job.lastProgressReport = epochTime()
+        r.typ = EvTransferProgress
+        r.bytesTotal = ftp.job.total
+        r.bytesFinished = ftp.job.progress
+        r.speed = ftp.job.oneSecond
+        r.filename = ftp.job.filename
+        r.currentJob = ftp.job.typ
+        ftp.job.oneSecond = 0
+        ftp.handleEvent(ftp, r)
+
+proc handleWrite(s: AsyncSocket, ftp: AsyncFTPClient) =
+  if ftp.jobInProgress:
+    if ftp.job.typ == JStore:
+      assert (not ftp.job.prc(ftp, true))
+
+proc handleConnect(s: AsyncSocket, ftp: AsyncFTPClient) =
+  ftp.dsockConnected = true
+  assert(ftp.jobInProgress)
+  if ftp.job.typ == JStore:
+    s.setHandleWrite(proc (s: AsyncSocket) = handleWrite(s, ftp))
+  else:
+    s.delHandleWrite()
+
+proc handleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
+  assert ftp.jobInProgress
+  assert ftp.job.typ != JStore
+  # This can never return true, because it shouldn't check for code
+  # 226 from csock.
+  assert(not ftp.job.prc(ftp, true))
+
+proc pasv[T](ftp: FtpBase[T]) =
+  ## Negotiate a data connection.
+  when T is Socket:
+    ftp.dsock = socket()
+    if ftp.dsock == invalidSocket: raiseOSError(osLastError())
+  elif T is AsyncSocket:
+    ftp.dsock = asyncSocket()
+    ftp.dsock.handleRead =
+      proc (s: AsyncSocket) =
+        handleRead(s, ftp)
+    ftp.dsock.handleConnect =
+      proc (s: AsyncSocket) =
+        handleConnect(s, ftp)
+    ftp.dsock.handleTask =
+      proc (s: AsyncSocket) =
+        handleTask(s, ftp)
+    ftp.disp.register(ftp.dsock)
+  else:
+    {.fatal: "Incorrect socket instantiation".}
+
+  var pasvMsg = ftp.send("PASV").string.strip.TaintedString
+  assertReply(pasvMsg, "227")
+  var betweenParens = captureBetween(pasvMsg.string, '(', ')')
+  var nums = betweenParens.split(',')
+  var ip = nums[0.. ^3]
+  var port = nums[^2.. ^1]
+  var properPort = port[0].parseInt()*256+port[1].parseInt()
+  ftp.dsock.connect(ip.join("."), Port(properPort.toU16))
+  when T is AsyncSocket:
+    ftp.dsockConnected = false
+  else:
+    ftp.dsockConnected = true
+
+proc normalizePathSep(path: string): string =
+  return replace(path, '\\', '/')
+
+proc connect*[T](ftp: FtpBase[T]) =
+  ## Connect to the FTP server specified by ``ftp``.
+  when T is AsyncSocket:
+    blockingOperation(ftp.csock):
+      ftp.csock.connect(ftp.address, ftp.port)
+  elif T is Socket:
+    ftp.csock.connect(ftp.address, ftp.port)
+  else:
+    {.fatal: "Incorrect socket instantiation".}
+
+  # TODO: Handle 120? or let user handle it.
+  assertReply ftp.expectReply(), "220"
+
+  if ftp.user != "":
+    assertReply(ftp.send("USER " & ftp.user), "230", "331")
+
+  if ftp.pass != "":
+    assertReply ftp.send("PASS " & ftp.pass), "230"
+
+proc pwd*[T](ftp: FtpBase[T]): string =
+  ## Returns the current working directory.
+  var wd = ftp.send("PWD")
+  assertReply wd, "257"
+  return wd.string.captureBetween('"') # "
+
+proc cd*[T](ftp: FtpBase[T], dir: string) =
+  ## Changes the current directory on the remote FTP server to ``dir``.
+  assertReply ftp.send("CWD " & dir.normalizePathSep), "250"
+
+proc cdup*[T](ftp: FtpBase[T]) =
+  ## Changes the current directory to the parent of the current directory.
+  assertReply ftp.send("CDUP"), "200"
+
+proc getLines[T](ftp: FtpBase[T], async: bool = false): bool =
+  ## Downloads text data in ASCII mode
+  ## Returns true if the download is complete.
+  ## It doesn't if `async` is true, because it doesn't check for 226 then.
+  if ftp.dsockConnected:
+    var r = TaintedString""
+    when T is AsyncSocket:
+      if ftp.asyncDSock.readLine(r):
+        if r.string == "":
+          ftp.dsockConnected = false
+        else:
+          ftp.job.lines.add(r.string & "\n")
+    elif T is Socket:
+      assert(not async)
+      ftp.dsock.readLine(r)
+      if r.string == "":
+        ftp.dsockConnected = false
+      else:
+        ftp.job.lines.add(r.string & "\n")
+    else:
+      {.fatal: "Incorrect socket instantiation".}
+
+  if not async:
+    var readSocks: seq[Socket] = @[ftp.csock]
+    # This is only needed here. Asyncio gets this socket...
+    blockingOperation(ftp.csock):
+      if readSocks.select(1) != 0 and ftp.csock in readSocks:
+        assertReply ftp.expectReply(), "226"
+        return true
+
+proc listDirs*[T](ftp: FtpBase[T], dir: string = "",
+               async = false): seq[string] =
+  ## Returns a list of filenames in the given directory. If ``dir`` is "",
+  ## the current directory is used. If ``async`` is true, this
+  ## function will return immediately and it will be your job to
+  ## use asyncio's ``poll`` to progress this operation.
+
+  ftp.createJob(getLines[T], JRetrText)
+  ftp.pasv()
+
+  assertReply ftp.send("NLST " & dir.normalizePathSep), ["125", "150"]
+
+  if not async:
+    while not ftp.job.prc(ftp, false): discard
+    result = splitLines(ftp.job.lines)
+    ftp.deleteJob()
+  else: return @[]
+
+proc fileExists*(ftp: FtpClient, file: string): bool {.deprecated.} =
+  ## **Deprecated since version 0.9.0:** Please use ``existsFile``.
+  ##
+  ## Determines whether ``file`` exists.
+  ##
+  ## Warning: This function may block. Especially on directories with many
+  ## files, because a full list of file names must be retrieved.
+  var files = ftp.listDirs()
+  for f in items(files):
+    if f.normalizePathSep == file.normalizePathSep: return true
+
+proc existsFile*(ftp: FtpClient, file: string): bool =
+  ## Determines whether ``file`` exists.
+  ##
+  ## Warning: This function may block. Especially on directories with many
+  ## files, because a full list of file names must be retrieved.
+  var files = ftp.listDirs()
+  for f in items(files):
+    if f.normalizePathSep == file.normalizePathSep: return true
+
+proc createDir*[T](ftp: FtpBase[T], dir: string, recursive: bool = false) =
+  ## Creates a directory ``dir``. If ``recursive`` is true, the topmost
+  ## subdirectory of ``dir`` will be created first, following the secondmost...
+  ## etc. this allows you to give a full path as the ``dir`` without worrying
+  ## about subdirectories not existing.
+  if not recursive:
+    assertReply ftp.send("MKD " & dir.normalizePathSep), "257"
+  else:
+    var reply = TaintedString""
+    var previousDirs = ""
+    for p in split(dir, {os.DirSep, os.AltSep}):
+      if p != "":
+        previousDirs.add(p)
+        reply = ftp.send("MKD " & previousDirs)
+        previousDirs.add('/')
+    assertReply reply, "257"
+
+proc chmod*[T](ftp: FtpBase[T], path: string,
+            permissions: set[FilePermission]) =
+  ## Changes permission of ``path`` to ``permissions``.
+  var userOctal = 0
+  var groupOctal = 0
+  var otherOctal = 0
+  for i in items(permissions):
+    case i
+    of fpUserExec: userOctal.inc(1)
+    of fpUserWrite: userOctal.inc(2)
+    of fpUserRead: userOctal.inc(4)
+    of fpGroupExec: groupOctal.inc(1)
+    of fpGroupWrite: groupOctal.inc(2)
+    of fpGroupRead: groupOctal.inc(4)
+    of fpOthersExec: otherOctal.inc(1)
+    of fpOthersWrite: otherOctal.inc(2)
+    of fpOthersRead: otherOctal.inc(4)
+
+  var perm = $userOctal & $groupOctal & $otherOctal
+  assertReply ftp.send("SITE CHMOD " & perm &
+                       " " & path.normalizePathSep), "200"
+
+proc list*[T](ftp: FtpBase[T], dir: string = "", async = false): string =
+  ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current
+  ## working directory. If ``async`` is true, this function will return
+  ## immediately and it will be your job to call asyncio's
+  ## ``poll`` to progress this operation.
+  ftp.createJob(getLines[T], JRetrText)
+  ftp.pasv()
+
+  assertReply(ftp.send("LIST" & " " & dir.normalizePathSep), ["125", "150"])
+
+  if not async:
+    while not ftp.job.prc(ftp, false): discard
+    result = ftp.job.lines
+    ftp.deleteJob()
+  else:
+    return ""
+
+proc retrText*[T](ftp: FtpBase[T], file: string, async = false): string =
+  ## Retrieves ``file``. File must be ASCII text.
+  ## If ``async`` is true, this function will return immediately and
+  ## it will be your job to call asyncio's ``poll`` to progress this operation.
+  ftp.createJob(getLines[T], JRetrText)
+  ftp.pasv()
+  assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
+
+  if not async:
+    while not ftp.job.prc(ftp, false): discard
+    result = ftp.job.lines
+    ftp.deleteJob()
+  else:
+    return ""
+
+proc getFile[T](ftp: FtpBase[T], async = false): bool =
+  if ftp.dsockConnected:
+    var r = "".TaintedString
+    var bytesRead = 0
+    var returned = false
+    if async:
+      when T is Socket:
+        raise newException(FTPError, "FTPClient must be async.")
+      else:
+        bytesRead = ftp.dsock.recvAsync(r, BufferSize)
+        returned = bytesRead != -1
+    else:
+      bytesRead = ftp.dsock.recv(r, BufferSize)
+      returned = true
+    let r2 = r.string
+    if r2 != "":
+      ftp.job.progress.inc(r2.len)
+      ftp.job.oneSecond.inc(r2.len)
+      ftp.job.file.write(r2)
+    elif returned and r2 == "":
+      ftp.dsockConnected = false
+
+  when T is Socket:
+    if not async:
+      var readSocks: seq[Socket] = @[ftp.csock]
+      blockingOperation(ftp.csock):
+        if readSocks.select(1) != 0 and ftp.csock in readSocks:
+          assertReply ftp.expectReply(), "226"
+          return true
+
+proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) =
+  ## Downloads ``file`` and saves it to ``dest``. Usage of this function
+  ## asynchronously is recommended to view the progress of the download.
+  ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function
+  ## when the download is finished, and the ``filename`` field will be equal
+  ## to ``file``.
+  ftp.createJob(getFile[T], JRetr)
+  ftp.job.file = open(dest, mode = fmWrite)
+  ftp.pasv()
+  var reply = ftp.send("RETR " & file.normalizePathSep)
+  assertReply reply, ["125", "150"]
+  if {'(', ')'} notin reply.string:
+    raise newException(ReplyError, "Reply has no file size.")
+  var fileSize: BiggestInt
+  if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0:
+    raise newException(ReplyError, "Reply has no file size.")
+
+  ftp.job.total = fileSize
+  ftp.job.lastProgressReport = epochTime()
+  ftp.job.filename = file.normalizePathSep
+
+  if not async:
+    while not ftp.job.prc(ftp, false): discard
+    ftp.deleteJob()
+
+proc doUpload[T](ftp: FtpBase[T], async = false): bool =
+  if ftp.dsockConnected:
+    if ftp.job.toStore.len() > 0:
+      assert(async)
+      let bytesSent = ftp.dsock.sendAsync(ftp.job.toStore)
+      if bytesSent == ftp.job.toStore.len:
+        ftp.job.toStore = ""
+      elif bytesSent != ftp.job.toStore.len and bytesSent != 0:
+        ftp.job.toStore = ftp.job.toStore[bytesSent .. ^1]
+      ftp.job.progress.inc(bytesSent)
+      ftp.job.oneSecond.inc(bytesSent)
+    else:
+      var s = newStringOfCap(4000)
+      var len = ftp.job.file.readBuffer(addr(s[0]), 4000)
+      setLen(s, len)
+      if len == 0:
+        # File finished uploading.
+        ftp.dsock.close()
+        ftp.dsockConnected = false
+
+        if not async:
+          assertReply ftp.expectReply(), "226"
+          return true
+        return false
+
+      if not async:
+        ftp.dsock.send(s)
+      else:
+        let bytesSent = ftp.dsock.sendAsync(s)
+        if bytesSent == 0:
+          ftp.job.toStore.add(s)
+        elif bytesSent != s.len:
+          ftp.job.toStore.add(s[bytesSent .. ^1])
+        len = bytesSent
+
+      ftp.job.progress.inc(len)
+      ftp.job.oneSecond.inc(len)
+
+proc store*[T](ftp: FtpBase[T], file, dest: string, async = false) =
+  ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this
+  ## function asynchronously is recommended to view the progress of
+  ## the download.
+  ## The ``EvStore`` event is passed to the specified ``handleEvent`` function
+  ## when the upload is finished, and the ``filename`` field will be
+  ## equal to ``file``.
+  ftp.createJob(doUpload[T], JStore)
+  ftp.job.file = open(file)
+  ftp.job.total = ftp.job.file.getFileSize()
+  ftp.job.lastProgressReport = epochTime()
+  ftp.job.filename = file
+  ftp.pasv()
+
+  assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
+
+  if not async:
+    while not ftp.job.prc(ftp, false): discard
+    ftp.deleteJob()
+
+proc close*[T](ftp: FtpBase[T]) =
+  ## Terminates the connection to the server.
+  assertReply ftp.send("QUIT"), "221"
+  if ftp.jobInProgress: ftp.deleteJob()
+  ftp.csock.close()
+  ftp.dsock.close()
+
+proc csockHandleRead(s: AsyncSocket, ftp: AsyncFTPClient) =
+  if ftp.jobInProgress:
+    assertReply ftp.expectReply(), "226" # Make sure the transfer completed.
+    var r: FTPEvent
+    case ftp.job.typ
+    of JRetrText:
+      r.typ = EvLines
+      r.lines = ftp.job.lines
+    of JRetr:
+      r.typ = EvRetr
+      r.filename = ftp.job.filename
+      if ftp.job.progress != ftp.job.total:
+        raise newException(FTPError, "Didn't download full file.")
+    of JStore:
+      r.typ = EvStore
+      r.filename = ftp.job.filename
+      if ftp.job.progress != ftp.job.total:
+        raise newException(FTPError, "Didn't upload full file.")
+    ftp.deleteJob()
+
+    ftp.handleEvent(ftp, r)
+
+proc asyncFTPClient*(address: string, port = Port(21),
+                     user, pass = "",
+    handleEvent: proc (ftp: AsyncFTPClient, ev: FTPEvent) {.closure,gcsafe.} =
+      (proc (ftp: AsyncFTPClient, ev: FTPEvent) = discard)): AsyncFTPClient =
+  ## Create a ``AsyncFTPClient`` object.
+  ##
+  ## Use this if you want to use asyncio's dispatcher.
+  var dres: AsyncFtpClient
+  new(dres)
+  dres.user = user
+  dres.pass = pass
+  dres.address = address
+  dres.port = port
+  dres.dsockConnected = false
+  dres.handleEvent = handleEvent
+  dres.csock = asyncSocket()
+  dres.csock.handleRead =
+    proc (s: AsyncSocket) =
+      csockHandleRead(s, dres)
+  result = dres
+
+proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} =
+  ## Registers ``ftp`` with dispatcher ``d``.
+  ftp.disp = d
+  return ftp.disp.register(ftp.csock)
+
+when not defined(testing) and isMainModule:
+  proc main =
+    var d = newDispatcher()
+    let hev =
+      proc (ftp: AsyncFTPClient, event: FTPEvent) =
+        case event.typ
+        of EvStore:
+          echo("Upload finished!")
+          ftp.retrFile("payload.jpg", "payload2.jpg", async = true)
+        of EvTransferProgress:
+          var time: int64 = -1
+          if event.speed != 0:
+            time = (event.bytesTotal - event.bytesFinished) div event.speed
+          echo(event.currentJob)
+          echo(event.speed div 1000, " kb/s. - ",
+               event.bytesFinished, "/", event.bytesTotal,
+               " - ", time, " seconds")
+          echo(d.len)
+        of EvRetr:
+          echo("Download finished!")
+          ftp.close()
+          echo d.len
+        else: assert(false)
+    var ftp = asyncFTPClient("example.com", user = "foo", pass = "bar", handleEvent = hev)
+
+    d.register(ftp)
+    d.len.echo()
+    ftp.connect()
+    echo "connected"
+    ftp.store("payload.jpg", "payload.jpg", async = true)
+    d.len.echo()
+    echo "uploading..."
+    while true:
+      if not d.poll(): break
+  main()
+
+when not defined(testing) and isMainModule:
+  var ftp = ftpClient("example.com", user = "foo", pass = "bar")
+  ftp.connect()
+  echo ftp.pwd()
+  echo ftp.list()
+  echo("uploading")
+  ftp.store("payload.jpg", "payload.jpg", async = false)
+
+  echo("Upload complete")
+  ftp.retrFile("payload.jpg", "payload2.jpg", async = false)
+
+  echo("Download complete")
+  sleep(5000)
+  ftp.close()
+  sleep(200)
diff --git a/lib/pure/future.nim b/lib/pure/future.nim
new file mode 100644
index 000000000..661afd7b3
--- /dev/null
+++ b/lib/pure/future.nim
@@ -0,0 +1,183 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements experimental features which may soon be moved to
+## the system module (or other more appropriate modules).
+
+import macros
+
+proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
+  #echo treeRepr(p)
+  #echo treeRepr(b)
+  result = newNimNode(nnkProcTy)
+  var formalParams = newNimNode(nnkFormalParams)
+
+  formalParams.add b
+
+  case p.kind
+  of nnkPar:
+    for i in 0 .. <p.len:
+      let ident = p[i]
+      var identDefs = newNimNode(nnkIdentDefs)
+      case ident.kind
+      of nnkExprColonExpr:
+        identDefs.add ident[0]
+        identDefs.add ident[1]
+      of nnkIdent:
+        identDefs.add newIdentNode("i" & $i)
+        identDefs.add(ident)
+      else:
+        error("Incorrect type list in proc type declaration.")
+      identDefs.add newEmptyNode()
+      formalParams.add identDefs
+  of nnkIdent:
+    var identDefs = newNimNode(nnkIdentDefs)
+    identDefs.add newIdentNode("i0")
+    identDefs.add(p)
+    identDefs.add newEmptyNode()
+    formalParams.add identDefs
+  else:
+    error("Incorrect type list in proc type declaration.")
+
+  result.add formalParams
+  result.add newEmptyNode()
+  #echo(treeRepr(result))
+  #echo(result.toStrLit())
+
+macro `=>`*(p, b: expr): expr {.immediate.} =
+  ## Syntax sugar for anonymous procedures.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   proc passTwoAndTwo(f: (int, int) -> int): int =
+  ##     f(2, 2)
+  ##
+  ##   passTwoAndTwo((x, y) => x + y) # 4
+
+  #echo treeRepr(p)
+  #echo(treeRepr(b))
+  var params: seq[NimNode] = @[newIdentNode("auto")]
+
+  case p.kind
+  of nnkPar:
+    for c in children(p):
+      var identDefs = newNimNode(nnkIdentDefs)
+      case c.kind
+      of nnkExprColonExpr:
+        identDefs.add(c[0])
+        identDefs.add(c[1])
+        identDefs.add(newEmptyNode())
+      of nnkIdent:
+        identDefs.add(c)
+        identDefs.add(newEmptyNode())
+        identDefs.add(newEmptyNode())
+      of nnkInfix:
+        if c[0].kind == nnkIdent and c[0].ident == !"->":
+          var procTy = createProcType(c[1], c[2])
+          params[0] = procTy[0][0]
+          for i in 1 .. <procTy[0].len:
+            params.add(procTy[0][i])
+        else:
+          error("Expected proc type (->) got (" & $c[0].ident & ").")
+        break
+      else:
+        echo treeRepr c
+        error("Incorrect procedure parameter list.")
+      params.add(identDefs)
+  of nnkIdent:
+    var identDefs = newNimNode(nnkIdentDefs)
+    identDefs.add(p)
+    identDefs.add(newEmptyNode())
+    identDefs.add(newEmptyNode())
+    params.add(identDefs)
+  of nnkInfix:
+    if p[0].kind == nnkIdent and p[0].ident == !"->":
+      var procTy = createProcType(p[1], p[2])
+      params[0] = procTy[0][0]
+      for i in 1 .. <procTy[0].len:
+        params.add(procTy[0][i])
+    else:
+      error("Expected proc type (->) got (" & $p[0].ident & ").")
+  else:
+    error("Incorrect procedure parameter list.")
+  result = newProc(params = params, body = b, procType = nnkLambda)
+  #echo(result.treeRepr)
+  #echo(result.toStrLit())
+  #return result # TODO: Bug?
+
+macro `->`*(p, b: expr): expr {.immediate.} =
+  ## Syntax sugar for procedure types.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   proc pass2(f: (float, float) -> float): float =
+  ##     f(2, 2)
+  ##
+  ##   # is the same as:
+  ##
+  ##   proc pass2(f: proc (x, y: float): float): float =
+  ##     f(2, 2)
+
+  result = createProcType(p, b)
+
+type ListComprehension = object
+var lc*: ListComprehension
+
+macro `[]`*(lc: ListComprehension, comp, typ: expr): expr =
+  ## List comprehension, returns a sequence. `comp` is the actual list
+  ## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is
+  ## the type that will be stored inside the result seq.
+  ##
+  ## .. code-block:: nimrod
+  ##
+  ##   echo lc[x | (x <- 1..10, x mod 2 == 0), int]
+  ##
+  ##   const n = 20
+  ##   echo lc[(x,y,z) | (x <- 1..n, y <- x..n, z <- y..n, x*x + y*y == z*z),
+  ##           tuple[a,b,c: int]]
+
+  expectLen(comp, 3)
+  expectKind(comp, nnkInfix)
+  expectKind(comp[0], nnkIdent)
+  assert($comp[0].ident == "|")
+
+  result = newCall(
+    newDotExpr(
+      newIdentNode("result"),
+      newIdentNode("add")),
+    comp[1])
+
+  for i in countdown(comp[2].len-1, 0):
+    let x = comp[2][i]
+    expectMinLen(x, 1)
+    if x[0].kind == nnkIdent and $x[0].ident == "<-":
+      expectLen(x, 3)
+      result = newNimNode(nnkForStmt).add(x[1], x[2], result)
+    else:
+      result = newIfStmt((x, result))
+
+  result = newNimNode(nnkCall).add(
+    newNimNode(nnkPar).add(
+      newNimNode(nnkLambda).add(
+        newEmptyNode(),
+        newEmptyNode(),
+        newEmptyNode(),
+        newNimNode(nnkFormalParams).add(
+          newNimNode(nnkBracketExpr).add(
+            newIdentNode("seq"),
+            typ)),
+        newEmptyNode(),
+        newEmptyNode(),
+        newStmtList(
+          newAssignment(
+            newIdentNode("result"),
+            newNimNode(nnkPrefix).add(
+              newIdentNode("@"),
+              newNimNode(nnkBracket))),
+          result))))
diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim
new file mode 100644
index 000000000..84d0a44de
--- /dev/null
+++ b/lib/pure/gentabs.nim
@@ -0,0 +1,206 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The ``gentabs`` module implements an efficient hash table that is a
+## key-value mapping. The keys are required to be strings, but the values
+## may be any Nim or user defined type. This module supports matching
+## of keys in case-sensitive, case-insensitive and style-insensitive modes.
+
+{.deprecated.}
+
+import
+  os, hashes, strutils
+
+type
+  TGenTableMode* = enum    ## describes the table's key matching mode
+    modeCaseSensitive,     ## case sensitive matching of keys
+    modeCaseInsensitive,   ## case insensitive matching of keys
+    modeStyleInsensitive   ## style sensitive matching of keys
+
+  TGenKeyValuePair[T] = tuple[key: string, val: T]
+  TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
+  TGenTable*[T] = object of RootObj
+    counter: int
+    data: TGenKeyValuePairSeq[T]
+    mode: TGenTableMode
+
+  PGenTable*[T] = ref TGenTable[T]     ## use this type to declare hash tables
+
+
+const
+  growthFactor = 2
+  startSize = 64
+
+
+proc len*[T](tbl: PGenTable[T]): int {.inline.} =
+  ## returns the number of keys in `tbl`.
+  result = tbl.counter
+
+iterator pairs*[T](tbl: PGenTable[T]): tuple[key: string, value: T] =
+  ## iterates over any (key, value) pair in the table `tbl`.
+  for h in 0..high(tbl.data):
+    if not isNil(tbl.data[h].key):
+      yield (tbl.data[h].key, tbl.data[h].val)
+
+proc myhash[T](tbl: PGenTable[T], key: string): THash =
+  case tbl.mode
+  of modeCaseSensitive: result = hashes.hash(key)
+  of modeCaseInsensitive: result = hashes.hashIgnoreCase(key)
+  of modeStyleInsensitive: result = hashes.hashIgnoreStyle(key)
+
+proc myCmp[T](tbl: PGenTable[T], a, b: string): bool =
+  case tbl.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)
+
+proc newGenTable*[T](mode: TGenTableMode): PGenTable[T] =
+  ## creates a new generic hash table that is empty.
+  new(result)
+  result.mode = mode
+  result.counter = 0
+  newSeq(result.data, startSize)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+proc rawGet[T](tbl: PGenTable[T], key: string): int =
+  var h: THash
+  h = myhash(tbl, key) and high(tbl.data) # start with real hash value
+  while not isNil(tbl.data[h].key):
+    if myCmp(tbl, tbl.data[h].key, key):
+      return h
+    h = nextTry(h, high(tbl.data))
+  result = - 1
+
+proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
+                  key: string, val: T) =
+  var h: THash
+  h = myhash(tbl, 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](tbl: PGenTable[T]) =
+  var n: TGenKeyValuePairSeq[T]
+  newSeq(n, len(tbl.data) * growthFactor)
+  for i in countup(0, high(tbl.data)):
+    if not isNil(tbl.data[i].key):
+      rawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val)
+  swap(tbl.data, n)
+
+proc hasKey*[T](tbl: PGenTable[T], key: string): bool =
+  ## returns true iff `key` is in the table `tbl`.
+  result = rawGet(tbl, key) >= 0
+
+proc `[]`*[T](tbl: PGenTable[T], key: string): T =
+  ## retrieves the value at ``tbl[key]``. If `key` is not in `tbl`,
+  ## default(T) is returned and no exception is raised. One can check
+  ## with ``hasKey`` whether the key exists.
+  var index = rawGet(tbl, key)
+  if index >= 0: result = tbl.data[index].val
+
+proc `[]=`*[T](tbl: PGenTable[T], key: string, val: T) =
+  ## puts a (key, value)-pair into `tbl`.
+  var index = rawGet(tbl, key)
+  if index >= 0:
+    tbl.data[index].val = val
+  else:
+    if mustRehash(len(tbl.data), tbl.counter): enlarge(tbl)
+    rawInsert(tbl, tbl.data, key, val)
+    inc(tbl.counter)
+
+
+when isMainModule:
+  #
+  # Verify tables of integer values (string keys)
+  #
+  var x = newGenTable[int](modeCaseInsensitive)
+  x["one"]   = 1
+  x["two"]   = 2
+  x["three"] = 3
+  x["four"]  = 4
+  x["five"]  = 5
+  assert(len(x) == 5)             # length procedure works
+  assert(x["one"] == 1)           # case-sensitive lookup works
+  assert(x["ONE"] == 1)           # case-insensitive should work for this table
+  assert(x["one"]+x["two"] == 3)  # make sure we're getting back ints
+  assert(x.hasKey("one"))         # hasKey should return 'true' for a key
+                                  # of "one"...
+  assert(not x.hasKey("NOPE"))    # ...but key "NOPE" is not in the table.
+  for k,v in pairs(x):            # make sure the 'pairs' iterator works
+    assert(x[k]==v)
+
+  #
+  # Verify a table of user-defined types
+  #
+  type
+    TMyType = tuple[first, second: string] # a pair of strings
+
+  var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
+                                                    # value is TMyType tuple
+
+  #var junk: TMyType = ("OK", "Here")
+
+  #echo junk.first, " ", junk.second
+
+  y["Hello"] = ("Hello", "World")
+  y["Goodbye"] = ("Goodbye", "Everyone")
+  #y["Hello"] = TMyType( ("Hello", "World") )
+  #y["Goodbye"] = TMyType( ("Goodbye", "Everyone") )
+
+  assert( not isNil(y["Hello"].first) )
+  assert( y["Hello"].first == "Hello" )
+  assert( y["Hello"].second == "World" )
+
+  #
+  # Verify table of tables
+  #
+  var z: PGenTable[ PGenTable[int] ] # hash table where each value is
+                                     # a hash table of ints
+
+  z = newGenTable[PGenTable[int]](modeCaseInsensitive)
+  z["first"] = newGenTable[int](modeCaseInsensitive)
+  z["first"]["one"] = 1
+  z["first"]["two"] = 2
+  z["first"]["three"] = 3
+
+  z["second"] = newGenTable[int](modeCaseInsensitive)
+  z["second"]["red"] = 10
+  z["second"]["blue"] = 20
+
+  assert(len(z) == 2)               # length of outer table
+  assert(len(z["first"]) == 3)      # length of "first" table
+  assert(len(z["second"]) == 2)     # length of "second" table
+  assert( z["first"]["one"] == 1)   # retrieve from first inner table
+  assert( z["second"]["red"] == 10) # retrieve from second inner table
+
+  when false:
+    # disabled: depends on hash order:
+    var output = ""
+    for k, v in pairs(z):
+      output.add( "$# ($#) ->\L" % [k,$len(v)] )
+      for k2,v2 in pairs(v):
+        output.add( "  $# <-> $#\L" % [k2,$v2] )
+
+    let expected = unindent """
+      first (3) ->
+        two <-> 2
+        three <-> 3
+        one <-> 1
+      second (2) ->
+        red <-> 10
+        blue <-> 20
+    """
+    assert output == expected
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
new file mode 100644
index 000000000..2ce8ac796
--- /dev/null
+++ b/lib/pure/hashes.nim
@@ -0,0 +1,170 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 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
+## Nim types. All the procs are based on these two building blocks: the `!&
+## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_
+## used to *finish* the hash value.  If you want to implement hash procs for
+## your custom types you will end up writing the following kind of skeleton of
+## code:
+##
+## .. code-block:: Nim
+##  proc hash(x: Something): THash =
+##    ## Computes a THash from `x`.
+##    var h: THash = 0
+##    # Iterate over parts of `x`.
+##    for xAtom in x:
+##      # Mix the atom with the partial hash.
+##      h = h !& xAtom
+##    # Finish the hash.
+##    result = !$h
+##
+## If your custom types contain fields for which there already is a hash proc,
+## like for example objects made up of ``strings``, you can simply hash
+## together the hash value of the individual fields:
+##
+## .. code-block:: Nim
+##  proc hash(x: Something): THash =
+##    ## Computes a THash from `x`.
+##    var h: THash = 0
+##    h = h !& hash(x.foo)
+##    h = h !& hash(x.bar)
+##    result = !$h
+
+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 `!&`*(h: THash, val: int): THash {.inline.} =
+  ## mixes a hash value `h` with `val` to produce a new hash value. This is
+  ## only needed if you need to implement a hash proc for a new datatype.
+  result = h +% val
+  result = result +% result shl 10
+  result = result xor (result shr 6)
+
+proc `!$`*(h: THash): THash {.inline.} =
+  ## finishes the computation of the hash value. This is
+  ## only needed if you need to implement a hash proc for a new datatype.
+  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 = 0
+  when defined(js):
+    var p: cstring
+    asm """`p` = `Data`;"""
+  else:
+    var p = cast[cstring](data)
+  var i = 0
+  var s = size
+  while s > 0:
+    h = h !& ord(p[i])
+    inc(i)
+    dec(s)
+  result = !$h
+
+when defined(js):
+  var objectID = 0
+
+proc hash*(x: pointer): THash {.inline.} =
+  ## efficient hashing of pointers
+  when defined(js):
+    asm """
+      if (typeof `x` == "object") {
+        if ("_NimID" in `x`)
+          `result` = `x`["_NimID"];
+        else {
+          `result` = ++`objectID`;
+          `x`["_NimID"] = `result`;
+        }
+      }
+    """
+  else:
+    result = (cast[THash](x)) shr 3 # skip the alignment
+
+when not defined(booting):
+  proc hash*[T: proc](x: T): THash {.inline.} =
+    ## efficient hashing of proc vars; closures are supported too.
+    when T is "closure":
+      result = hash(rawProc(x)) !& hash(rawEnv(x))
+    else:
+      result = hash(pointer(x))
+
+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 = 0
+  for i in 0..x.len-1:
+    h = h !& ord(x[i])
+  result = !$h
+
+proc hashIgnoreStyle*(x: string): THash =
+  ## efficient hashing of strings; style is ignored
+  var h: THash = 0
+  for i in 0..x.len-1:
+    var c = x[i]
+    if c == '_':
+      continue                # skip _
+    if c in {'A'..'Z'}:
+      c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
+    h = h !& ord(c)
+  result = !$h
+
+proc hashIgnoreCase*(x: string): THash =
+  ## efficient hashing of strings; case is ignored
+  var h: THash = 0
+  for i in 0..x.len-1:
+    var c = x[i]
+    if c in {'A'..'Z'}:
+      c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
+    h = h !& ord(c)
+  result = !$h
+
+proc hash*(x: float): THash {.inline.} =
+  var y = x + 1.0
+  result = cast[ptr THash](addr(y))[]
+
+
+# Forward declarations before methods that hash containers. This allows
+# containers to contain other containers
+proc hash*[A](x: openArray[A]): THash
+proc hash*[A](x: set[A]): THash
+
+
+proc hash*[T: tuple](x: T): THash =
+  ## efficient hashing of tuples.
+  for f in fields(x):
+    result = result !& hash(f)
+  result = !$result
+
+proc hash*[A](x: openArray[A]): THash =
+  for it in items(x): result = result !& hash(it)
+  result = !$result
+
+proc hash*[A](x: set[A]): THash =
+  for it in items(x): result = result !& hash(it)
+  result = !$result
+
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
new file mode 100644
index 000000000..e6c15371e
--- /dev/null
+++ b/lib/pure/htmlgen.nim
@@ -0,0 +1,490 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## **Warning**: This module uses ``immediate`` macros which are known to
+## cause problems. Do yourself a favor and import the module
+## as ``from htmlgen import nil`` and then fully qualify the macros.
+##
+##
+## This module implements a simple `XML`:idx: and `HTML`:idx: code
+## generator. Each commonly used HTML tag has a corresponding macro
+## that generates a string with its HTML representation.
+##
+## Example:
+##
+## .. code-block:: Nim
+##   var nim = "Nim"
+##   echo h1(a(href="http://nim-lang.org", nim))
+##
+## Writes the string::
+##
+##   <h1><a href="http://nim-lang.org">Nim</a></h1>
+##
+
+import
+  macros, strutils
+
+const
+  coreAttr* = " id class title style "
+  eventAttr* = " onclick ondblclick onmousedown onmouseup " &
+    "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup "
+  commonAttr* = coreAttr & eventAttr
+
+proc getIdent(e: NimNode): string {.compileTime.} =
+  case e.kind
+  of nnkIdent: result = normalize($e.ident)
+  of nnkAccQuoted:
+    result = getIdent(e[0])
+    for i in 1 .. e.len-1:
+      result.add getIdent(e[i])
+  else: error("cannot extract identifier from node: " & toStrLit(e).strVal)
+
+proc delete[T](s: var seq[T], attr: T): bool =
+  var idx = find(s, attr)
+  if idx >= 0:
+    var L = s.len
+    s[idx] = s[L-1]
+    setLen(s, L-1)
+    result = true
+
+proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "",
+    isLeaf = false): NimNode {.compileTime.} =
+  ## use this procedure to define a new XML tag
+
+  # copy the attributes; when iterating over them these lists
+  # will be modified, so that each attribute is only given one value
+  var req = split(reqAttr)
+  var opt = split(optAttr)
+  result = newNimNode(nnkBracket, e)
+  result.add(newStrLitNode("<"))
+  result.add(newStrLitNode(tag))
+  # first pass over attributes:
+  for i in 1..e.len-1:
+    if e[i].kind == nnkExprEqExpr:
+      var name = getIdent(e[i][0])
+      if delete(req, name) or delete(opt, name):
+        result.add(newStrLitNode(" "))
+        result.add(newStrLitNode(name))
+        result.add(newStrLitNode("=\""))
+        result.add(e[i][1])
+        result.add(newStrLitNode("\""))
+      else:
+        error("invalid attribute for '" & tag & "' element: " & name)
+  # check each required attribute exists:
+  if req.len > 0:
+    error(req[0] & " attribute for '" & tag & "' element expected")
+  if isLeaf:
+    for i in 1..e.len-1:
+      if e[i].kind != nnkExprEqExpr:
+        error("element " & tag & " cannot be nested")
+    result.add(newStrLitNode(" />"))
+  else:
+    result.add(newStrLitNode(">"))
+    # second pass over elements:
+    for i in 1..e.len-1:
+      if e[i].kind != nnkExprEqExpr: result.add(e[i])
+    result.add(newStrLitNode("</"))
+    result.add(newStrLitNode(tag))
+    result.add(newStrLitNode(">"))
+  result = nestList(!"&", result)
+
+
+macro a*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``a`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " &
+    "accesskey tabindex" & commonAttr)
+
+macro acronym*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``acronym`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "acronym", commonAttr)
+
+macro address*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``address`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "address", commonAttr)
+
+macro area*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``area`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "area", "shape coords href nohref" &
+    " accesskey tabindex" & commonAttr, "alt", true)
+
+macro b*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``b`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "b", commonAttr)
+
+macro base*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``base`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "base", "", "href", true)
+
+macro big*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``big`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "big", commonAttr)
+
+macro blockquote*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``blockquote`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr)
+
+macro body*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``body`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "body", commonAttr)
+
+macro br*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``br`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "br", "", "", true)
+
+macro button*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``button`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "button", "accesskey tabindex " &
+    "disabled name type value" & commonAttr)
+
+macro caption*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``caption`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "caption", commonAttr)
+
+macro cite*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``cite`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "cite", commonAttr)
+
+macro code*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``code`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "code", commonAttr)
+
+macro col*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``col`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true)
+
+macro colgroup*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``colgroup`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr)
+
+macro dd*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``dd`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "dd", commonAttr)
+
+macro del*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``del`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr)
+
+macro dfn*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``dfn`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "dfn", commonAttr)
+
+macro `div`*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``div`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "div", commonAttr)
+
+macro dl*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``dl`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "dl", commonAttr)
+
+macro dt*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``dt`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "dt", commonAttr)
+
+macro em*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``em`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "em", commonAttr)
+
+macro fieldset*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``fieldset`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "fieldset", commonAttr)
+
+macro form*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``form`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "form", "method encype accept accept-charset" &
+    commonAttr, "action")
+
+macro h1*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``h1`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "h1", commonAttr)
+
+macro h2*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``h2`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "h2", commonAttr)
+
+macro h3*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``h3`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "h3", commonAttr)
+
+macro h4*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``h4`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "h4", commonAttr)
+
+macro h5*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``h5`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "h5", commonAttr)
+
+macro h6*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``h6`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "h6", commonAttr)
+
+macro head*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``head`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "head", "profile")
+
+macro html*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``html`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "html", "xmlns", "")
+
+macro hr*(): expr {.immediate.} =
+  ## generates the HTML ``hr`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "hr", commonAttr, "", true)
+
+macro i*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``i`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "i", commonAttr)
+
+macro img*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``img`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true)
+
+macro input*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``input`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "input", "name type value checked maxlength src" &
+    " alt accept disabled readonly accesskey tabindex" & commonAttr, "", true)
+
+macro ins*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``ins`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr)
+
+macro kbd*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``kbd`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "kbd", commonAttr)
+
+macro label*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``label`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr)
+
+macro legend*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``legend`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr)
+
+macro li*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``li`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "li", commonAttr)
+
+macro link*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``link`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" &
+    commonAttr, "", true)
+
+macro map*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``map`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false)
+
+macro meta*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``meta`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true)
+
+macro noscript*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``noscript`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "noscript", commonAttr)
+
+macro `object`*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``object`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "object", "classid data codebase declare type " &
+    "codetype archive standby width height name tabindex" & commonAttr)
+
+macro ol*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``ol`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "ol", commonAttr)
+
+macro optgroup*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``optgroup`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false)
+
+macro option*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``option`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "option", "selected value" & commonAttr)
+
+macro p*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``p`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "p", commonAttr)
+
+macro param*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``param`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true)
+
+macro pre*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``pre`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "pre", commonAttr)
+
+macro q*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``q`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "q", "cite" & commonAttr)
+
+macro samp*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``samp`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "samp", commonAttr)
+
+macro script*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``script`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "script", "src charset defer", "type", false)
+
+macro select*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``select`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" &
+    commonAttr)
+
+macro small*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``small`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "small", commonAttr)
+
+macro span*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``span`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "span", commonAttr)
+
+macro strong*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``strong`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "strong", commonAttr)
+
+macro style*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``style`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "style", "media title", "type")
+
+macro sub*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``sub`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "sub", commonAttr)
+
+macro sup*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``sup`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "sup", commonAttr)
+
+macro table*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``table`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" &
+    " frame rules width" & commonAttr)
+
+macro tbody*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``tbody`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr)
+
+macro td*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``td`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" &
+    " align valign" & commonAttr)
+
+macro textarea*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``textarea`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" &
+    " tabindex" & commonAttr, "rows cols", false)
+
+macro tfoot*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``tfoot`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr)
+
+macro th*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``th`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" &
+    " align valign" & commonAttr)
+
+macro thead*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``thead`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "thead", "align valign" & commonAttr)
+
+macro title*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``title`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "title")
+
+macro tr*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``tr`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "tr", "align valign" & commonAttr)
+
+macro tt*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``tt`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "tt", commonAttr)
+
+macro ul*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``ul`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "ul", commonAttr)
+
+macro `var`*(e: expr): expr {.immediate.} =
+  ## generates the HTML ``var`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "var", commonAttr)
+
+when isMainModule:
+  let nim = "Nim"
+  assert h1(a(href="http://nim-lang.org", nim)) ==
+    """<h1><a href="http://nim-lang.org">Nim</a></h1>"""
+  assert form(action="test", `accept-charset` = "Content-Type") ==
+    """<form action="test" accept-charset="Content-Type"></form>"""
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
new file mode 100644
index 000000000..9719181b8
--- /dev/null
+++ b/lib/pure/htmlparser.nim
@@ -0,0 +1,608 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module parses an HTML document and creates its XML tree representation.
+## It is supposed to handle the *wild* HTML the real world uses.
+## 
+## It can be used to parse a wild HTML document and output it as valid XHTML
+## document (well, if you are lucky):
+##
+## .. code-block:: Nim
+##
+##   echo loadHtml("mydirty.html")
+##
+## Every tag in the resulting tree is in lower case.
+##
+## **Note:** The resulting ``PXmlNode`` already uses the ``clientData`` field, 
+## so it cannot be used by clients of this library.
+##
+## Example: Transforming hyperlinks
+## ================================
+##
+## This code demonstrates how you can iterate over all the tags in an HTML file
+## and write back the modified version. In this case we look for hyperlinks
+## ending with the extension ``.rst`` and convert them to ``.html``.
+##
+## .. code-block:: Nim
+##
+##   import htmlparser
+##   import xmltree  # To use '$' for PXmlNode
+##   import strtabs  # To access PXmlAttributes
+##   import os       # To use splitFile
+##   import strutils # To use cmpIgnoreCase
+##
+##   proc transformHyperlinks() =
+##     let html = loadHTML("input.html")
+##
+##     for a in html.findAll("a"):
+##       let href = a.attrs["href"]
+##       if not href.isNil:
+##         let (dir, filename, ext) = splitFile(href)
+##         if cmpIgnoreCase(ext, ".rst") == 0:
+##           a.attrs["href"] = dir / filename & ".html"
+##
+##     writeFile("output.html", $html)
+
+import strutils, streams, parsexml, xmltree, unicode, strtabs
+
+type
+  THtmlTag* = enum ## list of all supported HTML tags; order will always be
+                   ## alphabetically
+    tagUnknown,    ## unknown HTML element
+    tagA,          ## the HTML ``a`` element
+    tagAbbr,       ## the deprecated HTML ``abbr`` element
+    tagAcronym,    ## the HTML ``acronym`` element
+    tagAddress,    ## the HTML ``address`` element
+    tagApplet,     ## the deprecated HTML ``applet`` element
+    tagArea,       ## the HTML ``area`` element
+    tagArticle,    ## the HTML ``article`` element
+    tagAside,      ## the HTML ``aside`` element
+    tagAudio,      ## the HTML ``audio`` element
+    tagB,          ## the HTML ``b`` element
+    tagBase,       ## the HTML ``base`` element
+    tagBdi,        ## the HTML ``bdi`` element
+    tagBdo,        ## the deprecated HTML ``dbo`` element
+    tagBasefont,   ## the deprecated HTML ``basefont`` element
+    tagBig,        ## the HTML ``big`` element
+    tagBlockquote, ## the HTML ``blockquote`` element
+    tagBody,       ## the HTML ``body`` element
+    tagBr,         ## the HTML ``br`` element
+    tagButton,     ## the HTML ``button`` element
+    tagCanvas,     ## the HTML ``canvas`` element
+    tagCaption,    ## the HTML ``caption`` element
+    tagCenter,     ## the deprecated HTML ``center`` element
+    tagCite,       ## the HTML ``cite`` element
+    tagCode,       ## the HTML ``code`` element
+    tagCol,        ## the HTML ``col`` element
+    tagColgroup,   ## the HTML ``colgroup`` element
+    tagCommand,    ## the HTML ``command`` element
+    tagDatalist,   ## the HTML ``datalist`` element
+    tagDd,         ## the HTML ``dd`` element
+    tagDel,        ## the HTML ``del`` element
+    tagDetails,    ## the HTML ``details`` element
+    tagDfn,        ## the HTML ``dfn`` element
+    tagDialog,     ## the HTML ``dialog`` element
+    tagDiv,        ## the HTML ``div`` element
+    tagDir,        ## the deprecated HTLM ``dir`` element
+    tagDl,         ## the HTML ``dl`` element
+    tagDt,         ## the HTML ``dt`` element
+    tagEm,         ## the HTML ``em`` element
+    tagEmbed,      ## the HTML ``embed`` element
+    tagFieldset,   ## the HTML ``fieldset`` element
+    tagFigcaption, ## the HTML ``figcaption`` element
+    tagFigure,     ## the HTML ``figure`` element
+    tagFont,       ## the deprecated HTML ``font`` element
+    tagFooter,     ## the HTML ``footer`` element
+    tagForm,       ## the HTML ``form`` element
+    tagFrame,      ## the HTML ``frame`` element
+    tagFrameset,   ## the deprecated HTML ``frameset`` element
+    tagH1,         ## the HTML ``h1`` element
+    tagH2,         ## the HTML ``h2`` element
+    tagH3,         ## the HTML ``h3`` element
+    tagH4,         ## the HTML ``h4`` element
+    tagH5,         ## the HTML ``h5`` element
+    tagH6,         ## the HTML ``h6`` element
+    tagHead,       ## the HTML ``head`` element
+    tagHeader,     ## the HTML ``header`` element
+    tagHgroup,     ## the HTML ``hgroup`` element
+    tagHtml,       ## the HTML ``html`` element
+    tagHr,         ## the HTML ``hr`` element
+    tagI,          ## the HTML ``i`` element
+    tagIframe,     ## the deprecated HTML ``iframe`` element
+    tagImg,        ## the HTML ``img`` element
+    tagInput,      ## the HTML ``input`` element
+    tagIns,        ## the HTML ``ins`` element
+    tagIsindex,    ## the deprecated HTML ``isindex`` element
+    tagKbd,        ## the HTML ``kbd`` element
+    tagKeygen,     ## the HTML ``keygen`` element
+    tagLabel,      ## the HTML ``label`` element
+    tagLegend,     ## the HTML ``legend`` element
+    tagLi,         ## the HTML ``li`` element
+    tagLink,       ## the HTML ``link`` element
+    tagMap,        ## the HTML ``map`` element
+    tagMark,       ## the HTML ``mark`` element
+    tagMenu,       ## the deprecated HTML ``menu`` element
+    tagMeta,       ## the HTML ``meta`` element
+    tagMeter,      ## the HTML ``meter`` element
+    tagNav,        ## the HTML ``nav`` element
+    tagNobr,       ## the deprecated HTML ``nobr`` element
+    tagNoframes,   ## the deprecated HTML ``noframes`` element
+    tagNoscript,   ## the HTML ``noscript`` element
+    tagObject,     ## the HTML ``object`` element
+    tagOl,         ## the HTML ``ol`` element
+    tagOptgroup,   ## the HTML ``optgroup`` element
+    tagOption,     ## the HTML ``option`` element
+    tagOutput,     ## the HTML ``output`` element
+    tagP,          ## the HTML ``p`` element
+    tagParam,      ## the HTML ``param`` element
+    tagPre,        ## the HTML ``pre`` element
+    tagProgress,   ## the HTML ``progress`` element
+    tagQ,          ## the HTML ``q`` element
+    tagRp,         ## the HTML ``rp`` element
+    tagRt,         ## the HTML ``rt`` element
+    tagRuby,       ## the HTML ``ruby`` element
+    tagS,          ## the deprecated HTML ``s`` element
+    tagSamp,       ## the HTML ``samp`` element
+    tagScript,     ## the HTML ``script`` element
+    tagSection,    ## the HTML ``section`` element
+    tagSelect,     ## the HTML ``select`` element
+    tagSmall,      ## the HTML ``small`` element
+    tagSource,     ## the HTML ``source`` element
+    tagSpan,       ## the HTML ``span`` element
+    tagStrike,     ## the deprecated HTML ``strike`` element
+    tagStrong,     ## the HTML ``strong`` element
+    tagStyle,      ## the HTML ``style`` element
+    tagSub,        ## the HTML ``sub`` element
+    tagSummary,    ## the HTML ``summary`` element
+    tagSup,        ## the HTML ``sup`` element
+    tagTable,      ## the HTML ``table`` element
+    tagTbody,      ## the HTML ``tbody`` element
+    tagTd,         ## the HTML ``td`` element
+    tagTextarea,   ## the HTML ``textarea`` element
+    tagTfoot,      ## the HTML ``tfoot`` element
+    tagTh,         ## the HTML ``th`` element
+    tagThead,      ## the HTML ``thead`` element
+    tagTime,       ## the HTML ``time`` element
+    tagTitle,      ## the HTML ``title`` element
+    tagTr,         ## the HTML ``tr`` element
+    tagTrack,      ## the HTML ``track`` element
+    tagTt,         ## the HTML ``tt`` element
+    tagU,          ## the deprecated HTML ``u`` element
+    tagUl,         ## the HTML ``ul`` element
+    tagVar,        ## the HTML ``var`` element
+    tagVideo,      ## the HTML ``video`` element
+    tagWbr         ## the HTML ``wbr`` element
+
+const
+  tagToStr* = [
+    "a", "abbr", "acronym", "address", "applet", "area", "article", 
+    "aside", "audio",
+    "b", "base", "basefont", "bdi", "bdo", "big", "blockquote", "body", 
+    "br", "button", "canvas", "caption", "center", "cite", "code", 
+    "col", "colgroup", "command",
+    "datalist", "dd", "del", "details", "dfn", "dialog", "div", 
+    "dir", "dl", "dt", "em", "embed", "fieldset", 
+    "figcaption", "figure", "font", "footer",
+    "form", "frame", "frameset", "h1", "h2", "h3", 
+    "h4", "h5", "h6", "head", "header", "hgroup", "html", "hr", 
+    "i", "iframe", "img", "input", "ins", "isindex", 
+    "kbd", "keygen", "label", "legend", "li", "link", "map", "mark",
+    "menu", "meta", "meter", "nav", "nobr", "noframes", "noscript", 
+    "object", "ol", 
+    "optgroup", "option", "output", "p", "param", "pre", "progress", "q", 
+    "rp", "rt", "ruby", "s", "samp", "script", "section", "select", "small", 
+    "source", "span", "strike", "strong", "style", 
+    "sub", "summary", "sup", "table", 
+    "tbody", "td", "textarea", "tfoot", "th", "thead", "time",
+    "title", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]
+  InlineTags* = {tagA, tagAbbr, tagAcronym, tagApplet, tagB, tagBasefont,
+    tagBdo, tagBig, tagBr, tagButton, tagCite, tagCode, tagDel, tagDfn,
+    tagEm, tagFont, tagI, tagImg, tagIns, tagInput, tagIframe, tagKbd,
+    tagLabel, tagMap, tagObject, tagQ, tagSamp, tagScript, tagSelect,
+    tagSmall, tagSpan, tagStrong, tagSub, tagSup, tagTextarea, tagTt,
+    tagVar, tagApplet, tagBasefont, tagFont, tagIframe, tagU, tagS, 
+    tagStrike, tagWbr}
+  BlockTags* = {tagAddress, tagBlockquote, tagCenter, tagDel, tagDir, tagDiv, 
+    tagDl, tagFieldset, tagForm, tagH1, tagH2, tagH3, tagH4, 
+    tagH5, tagH6, tagHr, tagIns, tagIsindex, tagMenu, tagNoframes, tagNoscript, 
+    tagOl, tagP, tagPre, tagTable, tagUl, tagCenter, tagDir, tagIsindex, 
+    tagMenu, tagNoframes}
+  SingleTags* = {tagArea, tagBase, tagBasefont, 
+    tagBr, tagCol, tagFrame, tagHr, tagImg, tagIsindex,
+    tagLink, tagMeta, tagParam, tagWbr}
+  
+  Entities = [
+    ("nbsp", 0x00A0), ("iexcl", 0x00A1), ("cent", 0x00A2), ("pound", 0x00A3),
+    ("curren", 0x00A4), ("yen", 0x00A5), ("brvbar", 0x00A6), ("sect", 0x00A7),
+    ("uml", 0x00A8), ("copy", 0x00A9), ("ordf", 0x00AA), ("laquo", 0x00AB),
+    ("not", 0x00AC), ("shy", 0x00AD), ("reg", 0x00AE), ("macr", 0x00AF),
+    ("deg", 0x00B0), ("plusmn", 0x00B1), ("sup2", 0x00B2), ("sup3", 0x00B3),
+    ("acute", 0x00B4), ("micro", 0x00B5), ("para", 0x00B6), ("middot", 0x00B7),
+    ("cedil", 0x00B8), ("sup1", 0x00B9), ("ordm", 0x00BA), ("raquo", 0x00BB),
+    ("frac14", 0x00BC), ("frac12", 0x00BD), ("frac34", 0x00BE), 
+    ("iquest", 0x00BF), ("Agrave", 0x00C0), ("Aacute", 0x00C1),
+    ("Acirc", 0x00C2), ("Atilde", 0x00C3), ("Auml", 0x00C4), ("Aring", 0x00C5),
+    ("AElig", 0x00C6), ("Ccedil", 0x00C7), ("Egrave", 0x00C8),
+    ("Eacute", 0x00C9), ("Ecirc", 0x00CA), ("Euml", 0x00CB), ("Igrave", 0x00CC),
+    ("Iacute", 0x00CD), ("Icirc", 0x00CE), ("Iuml", 0x00CF), ("ETH", 0x00D0),
+    ("Ntilde", 0x00D1), ("Ograve", 0x00D2), ("Oacute", 0x00D3), 
+    ("Ocirc", 0x00D4), ("Otilde", 0x00D5), ("Ouml", 0x00D6), ("times", 0x00D7),
+    ("Oslash", 0x00D8), ("Ugrave", 0x00D9), ("Uacute", 0x00DA),
+    ("Ucirc", 0x00DB), ("Uuml", 0x00DC), ("Yacute", 0x00DD), ("THORN", 0x00DE),
+    ("szlig", 0x00DF), ("agrave", 0x00E0), ("aacute", 0x00E1),
+    ("acirc", 0x00E2), ("atilde", 0x00E3), ("auml", 0x00E4), ("aring", 0x00E5),
+    ("aelig", 0x00E6), ("ccedil", 0x00E7), ("egrave", 0x00E8),
+    ("eacute", 0x00E9), ("ecirc", 0x00EA), ("euml", 0x00EB), ("igrave", 0x00EC),
+    ("iacute", 0x00ED), ("icirc", 0x00EE), ("iuml", 0x00EF), ("eth", 0x00F0),
+    ("ntilde", 0x00F1), ("ograve", 0x00F2), ("oacute", 0x00F3),
+    ("ocirc", 0x00F4), ("otilde", 0x00F5), ("ouml", 0x00F6), ("divide", 0x00F7),
+    ("oslash", 0x00F8), ("ugrave", 0x00F9), ("uacute", 0x00FA),
+    ("ucirc", 0x00FB), ("uuml", 0x00FC), ("yacute", 0x00FD), ("thorn", 0x00FE),
+    ("yuml", 0x00FF), ("OElig", 0x0152), ("oelig", 0x0153), ("Scaron", 0x0160),
+    ("scaron", 0x0161), ("Yuml", 0x0178), ("fnof", 0x0192), ("circ", 0x02C6),
+    ("tilde", 0x02DC), ("Alpha", 0x0391), ("Beta", 0x0392), ("Gamma", 0x0393),
+    ("Delta", 0x0394), ("Epsilon", 0x0395), ("Zeta", 0x0396), ("Eta", 0x0397),
+    ("Theta", 0x0398), ("Iota", 0x0399), ("Kappa", 0x039A), ("Lambda", 0x039B),
+    ("Mu", 0x039C), ("Nu", 0x039D), ("Xi", 0x039E), ("Omicron", 0x039F),
+    ("Pi", 0x03A0), ("Rho", 0x03A1), ("Sigma", 0x03A3), ("Tau", 0x03A4),
+    ("Upsilon", 0x03A5), ("Phi", 0x03A6), ("Chi", 0x03A7), ("Psi", 0x03A8),
+    ("Omega", 0x03A9), ("alpha", 0x03B1), ("beta", 0x03B2), ("gamma", 0x03B3),
+    ("delta", 0x03B4), ("epsilon", 0x03B5), ("zeta", 0x03B6), ("eta", 0x03B7),
+    ("theta", 0x03B8), ("iota", 0x03B9), ("kappa", 0x03BA), ("lambda", 0x03BB),
+    ("mu", 0x03BC), ("nu", 0x03BD), ("xi", 0x03BE), ("omicron", 0x03BF),
+    ("pi", 0x03C0), ("rho", 0x03C1), ("sigmaf", 0x03C2), ("sigma", 0x03C3),
+    ("tau", 0x03C4), ("upsilon", 0x03C5), ("phi", 0x03C6), ("chi", 0x03C7),
+    ("psi", 0x03C8), ("omega", 0x03C9), ("thetasym", 0x03D1), ("upsih", 0x03D2),
+    ("piv", 0x03D6), ("ensp", 0x2002), ("emsp", 0x2003), ("thinsp", 0x2009),
+    ("zwnj", 0x200C), ("zwj", 0x200D), ("lrm", 0x200E), ("rlm", 0x200F),
+    ("ndash", 0x2013), ("mdash", 0x2014), ("lsquo", 0x2018), ("rsquo", 0x2019),
+    ("sbquo", 0x201A), ("ldquo", 0x201C), ("rdquo", 0x201D), ("bdquo", 0x201E),
+    ("dagger", 0x2020), ("Dagger", 0x2021), ("bull", 0x2022), 
+    ("hellip", 0x2026), ("permil", 0x2030), ("prime", 0x2032),
+    ("Prime", 0x2033), ("lsaquo", 0x2039), ("rsaquo", 0x203A),
+    ("oline", 0x203E), ("frasl", 0x2044), ("euro", 0x20AC),
+    ("image", 0x2111), ("weierp", 0x2118), ("real", 0x211C),
+    ("trade", 0x2122), ("alefsym", 0x2135), ("larr", 0x2190),
+    ("uarr", 0x2191), ("rarr", 0x2192), ("darr", 0x2193),
+    ("harr", 0x2194), ("crarr", 0x21B5), ("lArr", 0x21D0),
+    ("uArr", 0x21D1), ("rArr", 0x21D2), ("dArr", 0x21D3),
+    ("hArr", 0x21D4), ("forall", 0x2200), ("part", 0x2202),
+    ("exist", 0x2203), ("empty", 0x2205), ("nabla", 0x2207),
+    ("isin", 0x2208), ("notin", 0x2209), ("ni", 0x220B),
+    ("prod", 0x220F), ("sum", 0x2211), ("minus", 0x2212),
+    ("lowast", 0x2217), ("radic", 0x221A), ("prop", 0x221D),
+    ("infin", 0x221E), ("ang", 0x2220), ("and", 0x2227),
+    ("or", 0x2228), ("cap", 0x2229), ("cup", 0x222A),
+    ("int", 0x222B), ("there4", 0x2234), ("sim", 0x223C),
+    ("cong", 0x2245), ("asymp", 0x2248), ("ne", 0x2260),
+    ("equiv", 0x2261), ("le", 0x2264), ("ge", 0x2265),
+    ("sub", 0x2282), ("sup", 0x2283), ("nsub", 0x2284),
+    ("sube", 0x2286), ("supe", 0x2287), ("oplus", 0x2295),
+    ("otimes", 0x2297), ("perp", 0x22A5), ("sdot", 0x22C5),
+    ("lceil", 0x2308), ("rceil", 0x2309), ("lfloor", 0x230A),
+    ("rfloor", 0x230B), ("lang", 0x2329), ("rang", 0x232A),
+    ("loz", 0x25CA), ("spades", 0x2660), ("clubs", 0x2663),
+    ("hearts", 0x2665), ("diams", 0x2666)]
+
+proc allLower(s: string): bool =
+  for c in s:
+    if c < 'a' or c > 'z': return false
+  return true
+
+proc toHtmlTag(s: string): THtmlTag =
+  case s
+  of "a": tagA
+  of "abbr": tagAbbr
+  of "acronym": tagAcronym
+  of "address": tagAddress
+  of "applet": tagApplet
+  of "area": tagArea
+  of "article": tagArticle
+  of "aside": tagAside
+  of "audio": tagAudio
+  of "b": tagB
+  of "base": tagBase
+  of "basefont": tagBasefont
+  of "bdi": tagBdi
+  of "bdo": tagBdo
+  of "big": tagBig
+  of "blockquote": tagBlockquote
+  of "body": tagBody
+  of "br": tagBr
+  of "button": tagButton
+  of "canvas": tagCanvas
+  of "caption": tagCaption
+  of "center": tagCenter
+  of "cite": tagCite
+  of "code": tagCode
+  of "col": tagCol
+  of "colgroup": tagColgroup
+  of "command": tagCommand
+  of "datalist": tagDatalist
+  of "dd": tagDd
+  of "del": tagDel
+  of "details": tagDetails
+  of "dfn": tagDfn
+  of "dialog": tagDialog
+  of "div": tagDiv
+  of "dir": tagDir
+  of "dl": tagDl
+  of "dt": tagDt
+  of "em": tagEm
+  of "embed": tagEmbed
+  of "fieldset": tagFieldset
+  of "figcaption": tagFigcaption
+  of "figure": tagFigure
+  of "font": tagFont
+  of "footer": tagFooter
+  of "form": tagForm
+  of "frame": tagFrame
+  of "frameset": tagFrameset
+  of "h1": tagH1
+  of "h2": tagH2
+  of "h3": tagH3
+  of "h4": tagH4
+  of "h5": tagH5
+  of "h6": tagH6
+  of "head": tagHead
+  of "header": tagHeader
+  of "hgroup": tagHgroup
+  of "html": tagHtml
+  of "hr": tagHr
+  of "i": tagI
+  of "iframe": tagIframe
+  of "img": tagImg
+  of "input": tagInput
+  of "ins": tagIns
+  of "isindex": tagIsindex
+  of "kbd": tagKbd
+  of "keygen": tagKeygen
+  of "label": tagLabel
+  of "legend": tagLegend
+  of "li": tagLi
+  of "link": tagLink
+  of "map": tagMap
+  of "mark": tagMark
+  of "menu": tagMenu
+  of "meta": tagMeta
+  of "meter": tagMeter
+  of "nav": tagNav
+  of "nobr": tagNobr
+  of "noframes": tagNoframes
+  of "noscript": tagNoscript
+  of "object": tagObject
+  of "ol": tagOl
+  of "optgroup": tagOptgroup
+  of "option": tagOption
+  of "output": tagOutput
+  of "p": tagP
+  of "param": tagParam
+  of "pre": tagPre
+  of "progress": tagProgress
+  of "q": tagQ
+  of "rp": tagRp
+  of "rt": tagRt
+  of "ruby": tagRuby
+  of "s": tagS
+  of "samp": tagSamp
+  of "script": tagScript
+  of "section": tagSection
+  of "select": tagSelect
+  of "small": tagSmall
+  of "source": tagSource
+  of "span": tagSpan
+  of "strike": tagStrike
+  of "strong": tagStrong
+  of "style": tagStyle
+  of "sub": tagSub
+  of "summary": tagSummary
+  of "sup": tagSup
+  of "table": tagTable
+  of "tbody": tagTbody
+  of "td": tagTd
+  of "textarea": tagTextarea
+  of "tfoot": tagTfoot
+  of "th": tagTh
+  of "thead": tagThead
+  of "time": tagTime
+  of "title": tagTitle
+  of "tr": tagTr
+  of "track": tagTrack
+  of "tt": tagTt
+  of "u": tagU
+  of "ul": tagUl
+  of "var": tagVar
+  of "video": tagVideo
+  of "wbr": tagWbr
+  else: tagUnknown
+
+proc htmlTag*(n: XmlNode): THtmlTag = 
+  ## gets `n`'s tag as a ``THtmlTag``.
+  if n.clientData == 0:
+    n.clientData = toHtmlTag(n.tag).ord
+  result = THtmlTag(n.clientData)
+
+proc htmlTag*(s: string): THtmlTag =
+  ## converts `s` to a ``THtmlTag``. If `s` is no HTML tag, ``tagUnknown`` is
+  ## returned.
+  let s = if allLower(s): s else: s.toLower
+  result = toHtmlTag(s)
+
+proc entityToUtf8*(entity: string): string = 
+  ## converts an HTML entity name like ``&Uuml;`` to its UTF-8 equivalent.
+  ## "" is returned if the entity name is unknown. The HTML parser
+  ## already converts entities to UTF-8.
+  for name, val in items(Entities):
+    if name == entity: return toUTF8(Rune(val))
+  result = ""
+
+proc addNode(father, son: XmlNode) = 
+  if son != nil: add(father, son)
+
+proc parse(x: var XmlParser, errors: var seq[string]): XmlNode
+
+proc expected(x: var XmlParser, n: XmlNode): string =
+  result = errorMsg(x, "</" & n.tag & "> expected")
+
+template elemName(x: expr): expr = rawData(x)
+
+proc untilElementEnd(x: var XmlParser, result: XmlNode, 
+                     errors: var seq[string]) =
+  # we parsed e.g. ``<br>`` and don't really expect a ``</br>``: 
+  if result.htmlTag in SingleTags:
+    if x.kind != xmlElementEnd or cmpIgnoreCase(x.elemName, result.tag) != 0:
+      return
+  while true:
+    case x.kind
+    of xmlElementStart, xmlElementOpen:
+      case result.htmlTag
+      of tagLi, tagP, tagDt, tagDd, tagInput, tagOption:
+        # some tags are common to have no ``</end>``, like ``<li>``:
+        if htmlTag(x.elemName) in {tagLi, tagP, tagDt, tagDd, tagInput,
+                                   tagOption}:
+          errors.add(expected(x, result))
+          break
+      of tagTd, tagTh, tagTfoot, tagThead:
+        if htmlTag(x.elemName) in {tagTr, tagTd, tagTh, tagTfoot, tagThead}:
+          errors.add(expected(x, result))
+          break
+      of tagTr:
+        if htmlTag(x.elemName) == tagTr:
+          errors.add(expected(x, result))
+          break
+      of tagOptgroup:
+        if htmlTag(x.elemName) in {tagOption, tagOptgroup}:
+          errors.add(expected(x, result))
+          break
+      else: discard
+      result.addNode(parse(x, errors))
+    of xmlElementEnd: 
+      if cmpIgnoreCase(x.elemName, result.tag) == 0: 
+        next(x)
+      else:
+        #echo "5; expected: ", result.htmltag, " ", x.elemName 
+        errors.add(expected(x, result))
+        # do not skip it here!
+      break
+    of xmlEof:
+      errors.add(expected(x, result))
+      break
+    else:
+      result.addNode(parse(x, errors))
+
+proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
+  case x.kind
+  of xmlComment: 
+    result = newComment(x.rawData)
+    next(x)
+  of xmlCharData, xmlWhitespace:
+    result = newText(x.rawData)
+    next(x)
+  of xmlPI, xmlSpecial:
+    # we just ignore processing instructions for now
+    next(x)
+  of xmlError:
+    errors.add(errorMsg(x))
+    next(x)
+  of xmlElementStart:
+    result = newElement(x.elemName.toLower)
+    next(x)
+    untilElementEnd(x, result, errors)
+  of xmlElementEnd:
+    errors.add(errorMsg(x, "unexpected ending tag: " & x.elemName))
+  of xmlElementOpen: 
+    result = newElement(x.elemName.toLower)
+    next(x)
+    result.attrs = newStringTable()
+    while true: 
+      case x.kind
+      of xmlAttribute:
+        result.attrs[x.rawData] = x.rawData2
+        next(x)
+      of xmlElementClose:
+        next(x)
+        break
+      of xmlError:
+        errors.add(errorMsg(x))
+        next(x)
+        break
+      else:
+        errors.add(errorMsg(x, "'>' expected"))
+        next(x)
+        break
+    untilElementEnd(x, result, errors)
+  of xmlAttribute, xmlElementClose:
+    errors.add(errorMsg(x, "<some_tag> expected"))
+    next(x)
+  of xmlCData: 
+    result = newCData(x.rawData)
+    next(x)
+  of xmlEntity:
+    var u = entityToUtf8(x.rawData)
+    if u.len != 0: result = newText(u)
+    next(x)
+  of xmlEof: discard
+
+proc parseHtml*(s: Stream, filename: string, 
+                errors: var seq[string]): XmlNode = 
+  ## parses the XML from stream `s` and returns a ``PXmlNode``. Every
+  ## occurred parsing error is added to the `errors` sequence.
+  var x: XmlParser
+  open(x, s, filename, {reportComments, reportWhitespace})
+  next(x)
+  # skip the DOCTYPE:
+  if x.kind == xmlSpecial: next(x)
+  
+  result = newElement("document")
+  result.addNode(parse(x, errors))
+  #if x.kind != xmlEof:
+  #  errors.add(errorMsg(x, "EOF expected"))
+  while x.kind != xmlEof:
+    var oldPos = x.bufpos # little hack to see if we made any progess
+    result.addNode(parse(x, errors))
+    if x.bufpos == oldPos:
+      # force progress!
+      next(x)
+  close(x)
+  if result.len == 1:
+    result = result[0]
+
+proc parseHtml*(s: Stream): XmlNode = 
+  ## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
+  ## errors are ignored.
+  var errors: seq[string] = @[]
+  result = parseHtml(s, "unknown_html_doc", errors)
+
+proc loadHtml*(path: string, errors: var seq[string]): XmlNode = 
+  ## Loads and parses HTML from file specified by ``path``, and returns 
+  ## a ``PXmlNode``.  Every occurred parsing error is added to
+  ## the `errors` sequence.
+  var s = newFileStream(path, fmRead)
+  if s == nil: raise newException(IOError, "Unable to read file: " & path)
+  result = parseHtml(s, path, errors)
+
+proc loadHtml*(path: string): XmlNode = 
+  ## Loads and parses HTML from file specified by ``path``, and returns 
+  ## a ``PXmlNode``. All parsing errors are ignored.
+  var errors: seq[string] = @[]
+  result = loadHtml(path, errors)
+
+when not defined(testing) and isMainModule:
+  import os
+
+  var errors: seq[string] = @[]  
+  var x = loadHtml(paramStr(1), errors)
+  for e in items(errors): echo e
+  
+  var f: File
+  if open(f, "test.txt", fmWrite):
+    f.write($x)
+    f.close()
+  else:
+    quit("cannot write test.txt")
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
new file mode 100644
index 000000000..e083d44ea
--- /dev/null
+++ b/lib/pure/httpclient.nim
@@ -0,0 +1,861 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Dominik Picheta, Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple HTTP client that can be used to retrieve
+## webpages/other data.
+##
+##
+## **Note**: This module is not ideal, connection is not kept alive so sites with
+## many redirects are expensive. As such in the future this module may change,
+## and the current procedures will be deprecated.
+##
+## Retrieving a website
+## ====================
+##
+## This example uses HTTP GET to retrieve
+## ``http://google.com``
+##
+## .. code-block:: Nim
+##   echo(getContent("http://google.com"))
+##
+## Using HTTP POST
+## ===============
+##
+## This example demonstrates the usage of the W3 HTML Validator, it
+## uses ``multipart/form-data`` as the ``Content-Type`` to send the HTML to
+## the server.
+##
+## .. code-block:: Nim
+##   var data = newMultipartData()
+##   data["output"] = "soap12"
+##   data["uploaded_file"] = ("test.html", "text/html",
+##     "<html><head></head><body><p>test</p></body></html>")
+##
+##   echo postContent("http://validator.w3.org/check", multipart=data)
+##
+## Asynchronous HTTP requests
+## ==========================
+##
+## You simply have to create a new instance of the ``AsyncHttpClient`` object.
+## You may then use ``await`` on the functions defined for that object.
+## Keep in mind that the following code needs to be inside an asynchronous
+## procedure.
+##
+## .. code-block::nim
+##
+##    var client = newAsyncHttpClient()
+##    var resp = await client.request("http://google.com")
+##
+## SSL/TLS support
+## ===============
+## This requires the OpenSSL library, fortunately it's widely used and installed
+## on many operating systems. httpclient will use SSL automatically if you give
+## any of the functions a url with the ``https`` schema, for example:
+## ``https://github.com/``, you also have to compile with ``ssl`` defined like so:
+## ``nim c -d:ssl ...``.
+##
+## Timeouts
+## ========
+## Currently all functions support an optional timeout, by default the timeout is set to
+## `-1` which means that the function will never time out. The timeout is
+## measured in milliseconds, once it is set any call on a socket which may
+## block will be susceptible to this timeout, however please remember that the
+## function as a whole can take longer than the specified timeout, only
+## individual internal calls on the socket are affected. In practice this means
+## that as long as the server is sending data an exception will not be raised,
+## if however data does not reach client within the specified timeout an ETimeout
+## exception will then be raised.
+##
+## Proxy
+## =====
+##
+## A proxy can be specified as a param to any of these procedures, the ``newProxy``
+## constructor should be used for this purpose. However,
+## currently only basic authentication is supported.
+
+import net, strutils, uri, parseutils, strtabs, base64, os, mimetypes, math
+import asyncnet, asyncdispatch
+import rawsockets
+
+type
+  Response* = tuple[
+    version: string,
+    status: string,
+    headers: StringTableRef,
+    body: string]
+
+  Proxy* = ref object
+    url*: Uri
+    auth*: string
+
+  MultipartEntries* = openarray[tuple[name, content: string]]
+  MultipartData* = ref object
+    content: seq[string]
+
+  ProtocolError* = object of IOError   ## exception that is raised when server
+                                       ## does not conform to the implemented
+                                       ## protocol
+
+  HttpRequestError* = object of IOError ## Thrown in the ``getContent`` proc
+                                        ## and ``postContent`` proc,
+                                        ## when the server returns an error
+
+{.deprecated: [TResponse: Response, PProxy: Proxy,
+  EInvalidProtocol: ProtocolError, EHttpRequestErr: HttpRequestError
+].}
+
+const defUserAgent* = "Nim httpclient/0.1"
+
+proc httpError(msg: string) =
+  var e: ref ProtocolError
+  new(e)
+  e.msg = msg
+  raise e
+
+proc fileError(msg: string) =
+  var e: ref IOError
+  new(e)
+  e.msg = msg
+  raise e
+
+proc parseChunks(s: Socket, timeout: int): string =
+  result = ""
+  var ri = 0
+  while true:
+    var chunkSizeStr = ""
+    var chunkSize = 0
+    s.readLine(chunkSizeStr, timeout)
+    var i = 0
+    if chunkSizeStr == "":
+      httpError("Server terminated connection prematurely")
+    while true:
+      case chunkSizeStr[i]
+      of '0'..'9':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
+      of 'a'..'f':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
+      of 'A'..'F':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
+      of '\0':
+        break
+      of ';':
+        # http://tools.ietf.org/html/rfc2616#section-3.6.1
+        # We don't care about chunk-extensions.
+        break
+      else:
+        httpError("Invalid chunk size: " & chunkSizeStr)
+      inc(i)
+    if chunkSize <= 0:
+      s.skip(2, timeout) # Skip \c\L
+      break
+    result.setLen(ri+chunkSize)
+    var bytesRead = 0
+    while bytesRead != chunkSize:
+      let ret = recv(s, addr(result[ri]), chunkSize-bytesRead, timeout)
+      ri += ret
+      bytesRead += ret
+    s.skip(2, timeout) # Skip \c\L
+    # Trailer headers will only be sent if the request specifies that we want
+    # them: http://tools.ietf.org/html/rfc2616#section-3.6.1
+
+proc parseBody(s: Socket, headers: StringTableRef, timeout: int): string =
+  result = ""
+  if headers["Transfer-Encoding"] == "chunked":
+    result = parseChunks(s, timeout)
+  else:
+    # -REGION- Content-Length
+    # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
+    var contentLengthHeader = headers["Content-Length"]
+    if contentLengthHeader != "":
+      var length = contentLengthHeader.parseint()
+      if length > 0:
+        result = newString(length)
+        var received = 0
+        while true:
+          if received >= length: break
+          let r = s.recv(addr(result[received]), length-received, timeout)
+          if r == 0: break
+          received += r
+        if received != length:
+          httpError("Got invalid content length. Expected: " & $length &
+                    " got: " & $received)
+    else:
+      # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
+
+      # -REGION- Connection: Close
+      # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
+      if headers["Connection"] == "close":
+        var buf = ""
+        while true:
+          buf = newString(4000)
+          let r = s.recv(addr(buf[0]), 4000, timeout)
+          if r == 0: break
+          buf.setLen(r)
+          result.add(buf)
+
+proc parseResponse(s: Socket, getBody: bool, timeout: int): Response =
+  var parsedStatus = false
+  var linei = 0
+  var fullyRead = false
+  var line = ""
+  result.headers = newStringTable(modeCaseInsensitive)
+  while true:
+    line = ""
+    linei = 0
+    s.readLine(line, timeout)
+    if line == "": break # We've been disconnected.
+    if line == "\c\L":
+      fullyRead = true
+      break
+    if not parsedStatus:
+      # Parse HTTP version info and status code.
+      var le = skipIgnoreCase(line, "HTTP/", linei)
+      if le <= 0: httpError("invalid http version")
+      inc(linei, le)
+      le = skipIgnoreCase(line, "1.1", linei)
+      if le > 0: result.version = "1.1"
+      else:
+        le = skipIgnoreCase(line, "1.0", linei)
+        if le <= 0: httpError("unsupported http version")
+        result.version = "1.0"
+      inc(linei, le)
+      # Status code
+      linei.inc skipWhitespace(line, linei)
+      result.status = line[linei .. ^1]
+      parsedStatus = true
+    else:
+      # Parse headers
+      var name = ""
+      var le = parseUntil(line, name, ':', linei)
+      if le <= 0: httpError("invalid headers")
+      inc(linei, le)
+      if line[linei] != ':': httpError("invalid headers")
+      inc(linei) # Skip :
+
+      result.headers[name] = line[linei.. ^1].strip()
+  if not fullyRead:
+    httpError("Connection was closed before full request has been made")
+  if getBody:
+    result.body = parseBody(s, result.headers, timeout)
+  else:
+    result.body = ""
+
+type
+  HttpMethod* = enum  ## the requested HttpMethod
+    httpHEAD,         ## Asks for the response identical to the one that would
+                      ## correspond to a GET request, but without the response
+                      ## body.
+    httpGET,          ## Retrieves the specified resource.
+    httpPOST,         ## Submits data to be processed to the identified
+                      ## resource. The data is included in the body of the
+                      ## request.
+    httpPUT,          ## Uploads a representation of the specified resource.
+    httpDELETE,       ## Deletes the specified resource.
+    httpTRACE,        ## Echoes back the received request, so that a client
+                      ## can see what intermediate servers are adding or
+                      ## changing in the request.
+    httpOPTIONS,      ## Returns the HTTP methods that the server supports
+                      ## for specified address.
+    httpCONNECT       ## Converts the request connection to a transparent
+                      ## TCP/IP tunnel, usually used for proxies.
+
+{.deprecated: [THttpMethod: HttpMethod].}
+
+when not defined(ssl):
+  type SSLContext = ref object
+  let defaultSSLContext: SSLContext = nil
+else:
+  let defaultSSLContext = newContext(verifyMode = CVerifyNone)
+
+proc newProxy*(url: string, auth = ""): Proxy =
+  ## Constructs a new ``TProxy`` object.
+  result = Proxy(url: parseUri(url), auth: auth)
+
+proc newMultipartData*: MultipartData =
+  ## Constructs a new ``MultipartData`` object.
+  MultipartData(content: @[])
+
+proc add*(p: var MultipartData, name, content: string, filename: string = nil,
+          contentType: string = nil) =
+  ## Add a value to the multipart data. Raises a `ValueError` exception if
+  ## `name`, `filename` or `contentType` contain newline characters.
+
+  if {'\c','\L'} in name:
+    raise newException(ValueError, "name contains a newline character")
+  if filename != nil and {'\c','\L'} in filename:
+    raise newException(ValueError, "filename contains a newline character")
+  if contentType != nil and {'\c','\L'} in contentType:
+    raise newException(ValueError, "contentType contains a newline character")
+
+  var str = "Content-Disposition: form-data; name=\"" & name & "\""
+  if filename != nil:
+    str.add("; filename=\"" & filename & "\"")
+  str.add("\c\L")
+  if contentType != nil:
+    str.add("Content-Type: " & contentType & "\c\L")
+  str.add("\c\L" & content & "\c\L")
+
+  p.content.add(str)
+
+proc add*(p: var MultipartData, xs: MultipartEntries): MultipartData
+         {.discardable.} =
+  ## Add a list of multipart entries to the multipart data `p`. All values are
+  ## added without a filename and without a content type.
+  ##
+  ## .. code-block:: Nim
+  ##   data.add({"action": "login", "format": "json"})
+  for name, content in xs.items:
+    p.add(name, content)
+  result = p
+
+proc newMultipartData*(xs: MultipartEntries): MultipartData =
+  ## Create a new multipart data object and fill it with the entries `xs`
+  ## directly.
+  ##
+  ## .. code-block:: Nim
+  ##   var data = newMultipartData({"action": "login", "format": "json"})
+  result = MultipartData(content: @[])
+  result.add(xs)
+
+proc addFiles*(p: var MultipartData, xs: openarray[tuple[name, file: string]]):
+              MultipartData {.discardable.} =
+  ## Add files to a multipart data object. The file will be opened from your
+  ## disk, read and sent with the automatically determined MIME type. Raises an
+  ## `IOError` if the file cannot be opened or reading fails. To manually
+  ## specify file content, filename and MIME type, use `[]=` instead.
+  ##
+  ## .. code-block:: Nim
+  ##   data.addFiles({"uploaded_file": "public/test.html"})
+  var m = newMimetypes()
+  for name, file in xs.items:
+    var contentType: string
+    let (dir, fName, ext) = splitFile(file)
+    if ext.len > 0:
+      contentType = m.getMimetype(ext[1..ext.high], nil)
+    p.add(name, readFile(file), fName & ext, contentType)
+  result = p
+
+proc `[]=`*(p: var MultipartData, name, content: string) =
+  ## Add a multipart entry to the multipart data `p`. The value is added
+  ## without a filename and without a content type.
+  ##
+  ## .. code-block:: Nim
+  ##   data["username"] = "NimUser"
+  p.add(name, content)
+
+proc `[]=`*(p: var MultipartData, name: string,
+            file: tuple[name, contentType, content: string]) =
+  ## Add a file to the multipart data `p`, specifying filename, contentType and
+  ## content manually.
+  ##
+  ## .. code-block:: Nim
+  ##   data["uploaded_file"] = ("test.html", "text/html",
+  ##     "<html><head></head><body><p>test</p></body></html>")
+  p.add(name, file.content, file.name, file.contentType)
+
+proc format(p: MultipartData): tuple[header, body: string] =
+  if p == nil or p.content == nil or p.content.len == 0:
+    return ("", "")
+
+  # Create boundary that is not in the data to be formatted
+  var bound: string
+  while true:
+    bound = $random(int.high)
+    var found = false
+    for s in p.content:
+      if bound in s:
+        found = true
+    if not found:
+      break
+
+  result.header = "Content-Type: multipart/form-data; boundary=" & bound & "\c\L"
+  result.body = ""
+  for s in p.content:
+    result.body.add("--" & bound & "\c\L" & s)
+  result.body.add("--" & bound & "--\c\L")
+
+proc request*(url: string, httpMethod: string, extraHeaders = "",
+              body = "", sslContext = defaultSSLContext, timeout = -1,
+              userAgent = defUserAgent, proxy: Proxy = nil): Response =
+  ## | Requests ``url`` with the custom method string specified by the
+  ## | ``httpMethod`` parameter.
+  ## | Extra headers can be specified and must be separated by ``\c\L``
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  var r = if proxy == nil: parseUri(url) else: proxy.url
+  var headers = substr(httpMethod, len("http"))
+  # TODO: Use generateHeaders further down once it supports proxies.
+  if proxy == nil:
+    headers.add ' '
+    if r.path[0] != '/': headers.add '/'
+    headers.add(r.path)
+    if r.query.len > 0:
+      headers.add("?" & r.query)
+  else:
+    headers.add(" " & url)
+
+  headers.add(" HTTP/1.1\c\L")
+
+  add(headers, "Host: " & r.hostname & "\c\L")
+  if userAgent != "":
+    add(headers, "User-Agent: " & userAgent & "\c\L")
+  if proxy != nil and proxy.auth != "":
+    let auth = base64.encode(proxy.auth, newline = "")
+    add(headers, "Proxy-Authorization: basic " & auth & "\c\L")
+  add(headers, extraHeaders)
+  add(headers, "\c\L")
+
+  var s = newSocket()
+  if s == nil: raiseOSError(osLastError())
+  var port = net.Port(80)
+  if r.scheme == "https":
+    when defined(ssl):
+      sslContext.wrapSocket(s)
+      port = net.Port(443)
+    else:
+      raise newException(HttpRequestError,
+                "SSL support is not available. Cannot connect over SSL.")
+  if r.port != "":
+    port = net.Port(r.port.parseInt)
+
+  if timeout == -1:
+    s.connect(r.hostname, port)
+  else:
+    s.connect(r.hostname, port, timeout)
+  s.send(headers)
+  if body != "":
+    s.send(body)
+
+  result = parseResponse(s, httpMethod != "httpHEAD", timeout)
+  s.close()
+
+proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
+              body = "", sslContext = defaultSSLContext, timeout = -1,
+              userAgent = defUserAgent, proxy: Proxy = nil): Response =
+  ## | Requests ``url`` with the specified ``httpMethod``.
+  ## | Extra headers can be specified and must be separated by ``\c\L``
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout,
+                   userAgent, proxy)
+
+proc redirection(status: string): bool =
+  const redirectionNRs = ["301", "302", "303", "307"]
+  for i in items(redirectionNRs):
+    if status.startsWith(i):
+      return true
+
+proc getNewLocation(lastUrl: string, headers: StringTableRef): string =
+  result = headers["Location"]
+  if result == "": httpError("location header expected")
+  # Relative URLs. (Not part of the spec, but soon will be.)
+  let r = parseUri(result)
+  if r.hostname == "" and r.path != "":
+    let origParsed = parseUri(lastUrl)
+    result = origParsed.hostname & "/" & r.path
+
+proc get*(url: string, extraHeaders = "", maxRedirects = 5,
+          sslContext: SSLContext = defaultSSLContext,
+          timeout = -1, userAgent = defUserAgent,
+          proxy: Proxy = nil): Response =
+  ## | GETs the ``url`` and returns a ``Response`` object
+  ## | This proc also handles redirection
+  ## | Extra headers can be specified and must be separated by ``\c\L``.
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  result = request(url, httpGET, extraHeaders, "", sslContext, timeout,
+                   userAgent, proxy)
+  var lastURL = url
+  for i in 1..maxRedirects:
+    if result.status.redirection():
+      let redirectTo = getNewLocation(lastURL, result.headers)
+      result = request(redirectTo, httpGET, extraHeaders, "", sslContext,
+                       timeout, userAgent, proxy)
+      lastUrl = redirectTo
+
+proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
+                 sslContext: SSLContext = defaultSSLContext,
+                 timeout = -1, userAgent = defUserAgent,
+                 proxy: Proxy = nil): string =
+  ## | GETs the body and returns it as a string.
+  ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
+  ## | Extra headers can be specified and must be separated by ``\c\L``.
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
+              proxy)
+  if r.status[0] in {'4','5'}:
+    raise newException(HttpRequestError, r.status)
+  else:
+    return r.body
+
+proc post*(url: string, extraHeaders = "", body = "",
+           maxRedirects = 5,
+           sslContext: SSLContext = defaultSSLContext,
+           timeout = -1, userAgent = defUserAgent,
+           proxy: Proxy = nil,
+           multipart: MultipartData = nil): Response =
+  ## | POSTs ``body`` to the ``url`` and returns a ``Response`` object.
+  ## | This proc adds the necessary Content-Length header.
+  ## | This proc also handles redirection.
+  ## | Extra headers can be specified and must be separated by ``\c\L``.
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  ## | The optional ``multipart`` parameter can be used to create
+  ## ``multipart/form-data`` POSTs comfortably.
+  let (mpHeaders, mpBody) = format(multipart)
+
+  template withNewLine(x): expr =
+    if x.len > 0 and not x.endsWith("\c\L"):
+      x & "\c\L"
+    else:
+      x
+
+  var xb = mpBody.withNewLine() & body
+
+  var xh = extraHeaders.withNewLine() & mpHeaders.withNewLine() &
+    withNewLine("Content-Length: " & $len(xb))
+
+  result = request(url, httpPOST, xh, xb, sslContext, timeout, userAgent,
+                   proxy)
+  var lastUrl = ""
+  for i in 1..maxRedirects:
+    if result.status.redirection():
+      let redirectTo = getNewLocation(lastURL, result.headers)
+      var meth = if result.status != "307": httpGet else: httpPost
+      result = request(redirectTo, meth, xh, xb, sslContext, timeout,
+                       userAgent, proxy)
+      lastUrl = redirectTo
+
+proc postContent*(url: string, extraHeaders = "", body = "",
+                  maxRedirects = 5,
+                  sslContext: SSLContext = defaultSSLContext,
+                  timeout = -1, userAgent = defUserAgent,
+                  proxy: Proxy = nil,
+                  multipart: MultipartData = nil): string =
+  ## | POSTs ``body`` to ``url`` and returns the response's body as a string
+  ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
+  ## | Extra headers can be specified and must be separated by ``\c\L``.
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  ## | The optional ``multipart`` parameter can be used to create
+  ## ``multipart/form-data`` POSTs comfortably.
+  var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
+               userAgent, proxy, multipart)
+  if r.status[0] in {'4','5'}:
+    raise newException(HttpRequestError, r.status)
+  else:
+    return r.body
+
+proc downloadFile*(url: string, outputFilename: string,
+                   sslContext: SSLContext = defaultSSLContext,
+                   timeout = -1, userAgent = defUserAgent,
+                   proxy: Proxy = nil) =
+  ## | Downloads ``url`` and saves it to ``outputFilename``
+  ## | An optional timeout can be specified in milliseconds, if reading from the
+  ## server takes longer than specified an ETimeout exception will be raised.
+  var f: File
+  if open(f, outputFilename, fmWrite):
+    f.write(getContent(url, sslContext = sslContext, timeout = timeout,
+            userAgent = userAgent, proxy = proxy))
+    f.close()
+  else:
+    fileError("Unable to open file")
+
+proc generateHeaders(r: Uri, httpMethod: string,
+                     headers: StringTableRef): string =
+  # TODO: Use this in the blocking HttpClient once it supports proxies.
+  result = substr(httpMethod, len("http"))
+  # TODO: Proxies
+  result.add ' '
+  if r.path[0] != '/': result.add '/'
+  result.add(r.path)
+  if r.query.len > 0:
+    result.add("?" & r.query)
+  result.add(" HTTP/1.1\c\L")
+
+  add(result, "Host: " & r.hostname & "\c\L")
+  add(result, "Connection: Keep-Alive\c\L")
+  for key, val in headers:
+    add(result, key & ": " & val & "\c\L")
+
+  add(result, "\c\L")
+
+type
+  AsyncHttpClient* = ref object
+    socket: AsyncSocket
+    connected: bool
+    currentURL: Uri ## Where we are currently connected.
+    headers*: StringTableRef
+    maxRedirects: int
+    userAgent: string
+    when defined(ssl):
+      sslContext: net.SslContext
+
+{.deprecated: [PAsyncHttpClient: AsyncHttpClient].}
+
+proc newAsyncHttpClient*(userAgent = defUserAgent,
+    maxRedirects = 5, sslContext = defaultSslContext): AsyncHttpClient =
+  ## Creates a new AsyncHttpClient instance.
+  ##
+  ## ``userAgent`` specifies the user agent that will be used when making
+  ## requests.
+  ##
+  ## ``maxRedirects`` specifies the maximum amount of redirects to follow,
+  ## default is 5.
+  ##
+  ## ``sslContext`` specifies the SSL context to use for HTTPS requests.
+  new result
+  result.headers = newStringTable(modeCaseInsensitive)
+  result.userAgent = defUserAgent
+  result.maxRedirects = maxRedirects
+  when defined(ssl):
+    result.sslContext = net.SslContext(sslContext)
+
+proc close*(client: AsyncHttpClient) =
+  ## Closes any connections held by the HTTP client.
+  if client.connected:
+    client.socket.close()
+    client.connected = false
+
+proc recvFull(socket: AsyncSocket, size: int): Future[string] {.async.} =
+  ## Ensures that all the data requested is read and returned.
+  result = ""
+  while true:
+    if size == result.len: break
+    let data = await socket.recv(size - result.len)
+    if data == "": break # We've been disconnected.
+    result.add data
+
+proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
+  result = ""
+  while true:
+    var chunkSize = 0
+    var chunkSizeStr = await client.socket.recvLine()
+    var i = 0
+    if chunkSizeStr == "":
+      httpError("Server terminated connection prematurely")
+    while true:
+      case chunkSizeStr[i]
+      of '0'..'9':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('0'))
+      of 'a'..'f':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('a') + 10)
+      of 'A'..'F':
+        chunkSize = chunkSize shl 4 or (ord(chunkSizeStr[i]) - ord('A') + 10)
+      of '\0':
+        break
+      of ';':
+        # http://tools.ietf.org/html/rfc2616#section-3.6.1
+        # We don't care about chunk-extensions.
+        break
+      else:
+        httpError("Invalid chunk size: " & chunkSizeStr)
+      inc(i)
+    if chunkSize <= 0:
+      discard await recvFull(client.socket, 2) # Skip \c\L
+      break
+    result.add await recvFull(client.socket, chunkSize)
+    discard await recvFull(client.socket, 2) # Skip \c\L
+    # Trailer headers will only be sent if the request specifies that we want
+    # them: http://tools.ietf.org/html/rfc2616#section-3.6.1
+
+proc parseBody(client: AsyncHttpClient,
+               headers: StringTableRef): Future[string] {.async.} =
+  result = ""
+  if headers["Transfer-Encoding"] == "chunked":
+    result = await parseChunks(client)
+  else:
+    # -REGION- Content-Length
+    # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
+    var contentLengthHeader = headers["Content-Length"]
+    if contentLengthHeader != "":
+      var length = contentLengthHeader.parseint()
+      if length > 0:
+        result = await client.socket.recvFull(length)
+        if result == "":
+          httpError("Got disconnected while trying to read body.")
+        if result.len != length:
+          httpError("Received length doesn't match expected length. Wanted " &
+                    $length & " got " & $result.len)
+    else:
+      # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO
+
+      # -REGION- Connection: Close
+      # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
+      if headers["Connection"] == "close":
+        var buf = ""
+        while true:
+          buf = await client.socket.recvFull(4000)
+          if buf == "": break
+          result.add(buf)
+
+proc parseResponse(client: AsyncHttpClient,
+                   getBody: bool): Future[Response] {.async.} =
+  var parsedStatus = false
+  var linei = 0
+  var fullyRead = false
+  var line = ""
+  result.headers = newStringTable(modeCaseInsensitive)
+  while true:
+    linei = 0
+    line = await client.socket.recvLine()
+    if line == "": break # We've been disconnected.
+    if line == "\c\L":
+      fullyRead = true
+      break
+    if not parsedStatus:
+      # Parse HTTP version info and status code.
+      var le = skipIgnoreCase(line, "HTTP/", linei)
+      if le <= 0:
+        httpError("invalid http version, " & line.repr)
+      inc(linei, le)
+      le = skipIgnoreCase(line, "1.1", linei)
+      if le > 0: result.version = "1.1"
+      else:
+        le = skipIgnoreCase(line, "1.0", linei)
+        if le <= 0: httpError("unsupported http version")
+        result.version = "1.0"
+      inc(linei, le)
+      # Status code
+      linei.inc skipWhitespace(line, linei)
+      result.status = line[linei .. ^1]
+      parsedStatus = true
+    else:
+      # Parse headers
+      var name = ""
+      var le = parseUntil(line, name, ':', linei)
+      if le <= 0: httpError("invalid headers")
+      inc(linei, le)
+      if line[linei] != ':': httpError("invalid headers")
+      inc(linei) # Skip :
+
+      result.headers[name] = line[linei.. ^1].strip()
+  if not fullyRead:
+    httpError("Connection was closed before full request has been made")
+  if getBody:
+    result.body = await parseBody(client, result.headers)
+  else:
+    result.body = ""
+
+proc newConnection(client: AsyncHttpClient, url: Uri) {.async.} =
+  if client.currentURL.hostname != url.hostname or
+      client.currentURL.scheme != url.scheme:
+    if client.connected: client.close()
+    client.socket = newAsyncSocket()
+
+    # TODO: I should be able to write 'net.Port' here...
+    let port =
+      if url.port == "":
+        if url.scheme.toLower() == "https":
+          rawsockets.Port(443)
+        else:
+          rawsockets.Port(80)
+      else: rawsockets.Port(url.port.parseInt)
+
+    if url.scheme.toLower() == "https":
+      when defined(ssl):
+        client.sslContext.wrapSocket(client.socket)
+      else:
+        raise newException(HttpRequestError,
+                  "SSL support is not available. Cannot connect over SSL.")
+
+    await client.socket.connect(url.hostname, port)
+    client.currentURL = url
+    client.connected = true
+
+proc request*(client: AsyncHttpClient, url: string, httpMethod: string,
+              body = ""): Future[Response] {.async.} =
+  ## Connects to the hostname specified by the URL and performs a request
+  ## using the custom method string specified by ``httpMethod``.
+  ##
+  ## Connection will kept alive. Further requests on the same ``client`` to
+  ## the same hostname will not require a new connection to be made. The
+  ## connection can be closed by using the ``close`` procedure.
+  ##
+  ## The returned future will complete once the request is completed.
+  let r = parseUri(url)
+  await newConnection(client, r)
+
+  if not client.headers.hasKey("user-agent") and client.userAgent != "":
+    client.headers["User-Agent"] = client.userAgent
+
+  var headers = generateHeaders(r, $httpMethod, client.headers)
+
+  await client.socket.send(headers)
+  if body != "":
+    await client.socket.send(body)
+
+  result = await parseResponse(client, httpMethod != "httpHEAD")
+
+proc request*(client: AsyncHttpClient, url: string, httpMethod = httpGET,
+              body = ""): Future[Response] =
+  ## Connects to the hostname specified by the URL and performs a request
+  ## using the method specified.
+  ##
+  ## Connection will kept alive. Further requests on the same ``client`` to
+  ## the same hostname will not require a new connection to be made. The
+  ## connection can be closed by using the ``close`` procedure.
+  ##
+  ## The returned future will complete once the request is completed.
+  result = request(client, url, $httpMethod, body)
+
+proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
+  ## Connects to the hostname specified by the URL and performs a GET request.
+  ##
+  ## This procedure will follow redirects up to a maximum number of redirects
+  ## specified in ``newAsyncHttpClient``.
+  result = await client.request(url, httpGET)
+  var lastURL = url
+  for i in 1..client.maxRedirects:
+    if result.status.redirection():
+      let redirectTo = getNewLocation(lastURL, result.headers)
+      result = await client.request(redirectTo, httpGET)
+      lastUrl = redirectTo
+
+when not defined(testing) and isMainModule:
+  when true:
+    # Async
+    proc main() {.async.} =
+      var client = newAsyncHttpClient()
+      var resp = await client.request("http://picheta.me")
+
+      echo("Got response: ", resp.status)
+      echo("Body:\n")
+      echo(resp.body)
+
+      resp = await client.request("http://picheta.me/asfas.html")
+      echo("Got response: ", resp.status)
+
+      resp = await client.request("http://picheta.me/aboutme.html")
+      echo("Got response: ", resp.status)
+
+      resp = await client.request("http://nim-lang.org/")
+      echo("Got response: ", resp.status)
+
+      resp = await client.request("http://nim-lang.org/download.html")
+      echo("Got response: ", resp.status)
+
+    waitFor main()
+
+  else:
+    #downloadFile("http://force7.de/nim/index.html", "nimindex.html")
+    #downloadFile("http://www.httpwatch.com/", "ChunkTest.html")
+    #downloadFile("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com",
+    # "validator.html")
+
+    #var r = get("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com&
+    #  charset=%28detect+automatically%29&doctype=Inline&group=0")
+
+    var data = newMultipartData()
+    data["output"] = "soap12"
+    data["uploaded_file"] = ("test.html", "text/html",
+      "<html><head></head><body><p>test</p></body></html>")
+
+    echo postContent("http://validator.w3.org/check", multipart=data)
diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim
new file mode 100644
index 000000000..dc76c9228
--- /dev/null
+++ b/lib/pure/httpserver.nim
@@ -0,0 +1,532 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple HTTP-Server.
+##
+## Example:
+##
+## .. code-block:: nim
+##  import strutils, sockets, httpserver
+##
+##  var counter = 0
+##  proc handleRequest(client: Socket, path, query: string): bool {.procvar.} =
+##    inc(counter)
+##    client.send("Hello for the $#th time." % $counter & wwwNL)
+##    return false # do not stop processing
+##
+##  run(handleRequest, Port(80))
+##
+
+import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio
+
+const
+  wwwNL* = "\r\L"
+  ServerSig = "Server: httpserver.nim/1.0.0" & wwwNL
+
+# --------------- output messages --------------------------------------------
+
+proc sendTextContentType(client: Socket) =
+  send(client, "Content-type: text/html" & wwwNL)
+  send(client, wwwNL)
+
+proc sendStatus(client: Socket, status: string) =
+  send(client, "HTTP/1.1 " & status & wwwNL)
+
+proc badRequest(client: Socket) =
+  # Inform the client that a request it has made has a problem.
+  send(client, "HTTP/1.1 400 Bad Request" & wwwNL)
+  sendTextContentType(client)
+  send(client, "<p>Your browser sent a bad request, " &
+               "such as a POST without a Content-Length.</p>" & wwwNL)
+
+when false:
+  proc cannotExec(client: Socket) =
+    send(client, "HTTP/1.1 500 Internal Server Error" & wwwNL)
+    sendTextContentType(client)
+    send(client, "<P>Error prohibited CGI execution." & wwwNL)
+
+proc headers(client: Socket, filename: string) =
+  # XXX could use filename to determine file type
+  send(client, "HTTP/1.1 200 OK" & wwwNL)
+  send(client, ServerSig)
+  sendTextContentType(client)
+
+proc notFound(client: Socket) =
+  send(client, "HTTP/1.1 404 NOT FOUND" & wwwNL)
+  send(client, ServerSig)
+  sendTextContentType(client)
+  send(client, "<html><title>Not Found</title>" & wwwNL)
+  send(client, "<body><p>The server could not fulfill" & wwwNL)
+  send(client, "your request because the resource specified" & wwwNL)
+  send(client, "is unavailable or nonexistent.</p>" & wwwNL)
+  send(client, "</body></html>" & wwwNL)
+
+proc unimplemented(client: Socket) =
+  send(client, "HTTP/1.1 501 Method Not Implemented" & wwwNL)
+  send(client, ServerSig)
+  sendTextContentType(client)
+  send(client, "<html><head><title>Method Not Implemented" &
+               "</title></head>" &
+               "<body><p>HTTP request method not supported.</p>" &
+               "</body></HTML>" & wwwNL)
+
+# ----------------- file serving ---------------------------------------------
+
+when false:
+  proc discardHeaders(client: Socket) = skip(client)
+
+proc serveFile*(client: Socket, filename: string) =
+  ## serves a file to the client.
+  var f: File
+  if open(f, filename):
+    headers(client, filename)
+    const bufSize = 8000 # != 8K might be good for memory manager
+    var buf = alloc(bufsize)
+    while true:
+      var bytesread = readBuffer(f, buf, bufsize)
+      if bytesread > 0:
+        var byteswritten = send(client, buf, bytesread)
+        if bytesread != bytesWritten:
+          dealloc(buf)
+          close(f)
+          raiseOSError(osLastError())
+      if bytesread != bufSize: break
+    dealloc(buf)
+    close(f)
+  else:
+    notFound(client)
+
+# ------------------ CGI execution -------------------------------------------
+when false:
+  # TODO: Fix this, or get rid of it.
+  type
+    TRequestMethod = enum reqGet, reqPost
+
+  proc executeCgi(client: Socket, path, query: string, meth: TRequestMethod) =
+    var env = newStringTable(modeCaseInsensitive)
+    var contentLength = -1
+    case meth
+    of reqGet:
+      discardHeaders(client)
+
+      env["REQUEST_METHOD"] = "GET"
+      env["QUERY_STRING"] = query
+    of reqPost:
+      var buf = TaintedString""
+      var dataAvail = false
+      while dataAvail:
+        dataAvail = recvLine(client, buf) # TODO: This is incorrect.
+        var L = toLower(buf.string)
+        if L.startsWith("content-length:"):
+          var i = len("content-length:")
+          while L[i] in Whitespace: inc(i)
+          contentLength = parseInt(substr(L, i))
+
+      if contentLength < 0:
+        badRequest(client)
+        return
+
+      env["REQUEST_METHOD"] = "POST"
+      env["CONTENT_LENGTH"] = $contentLength
+
+    send(client, "HTTP/1.0 200 OK" & wwwNL)
+
+    var process = startProcess(command=path, env=env)
+    if meth == reqPost:
+      # get from client and post to CGI program:
+      var buf = alloc(contentLength)
+      if recv(client, buf, contentLength) != contentLength: 
+        dealloc(buf)
+        raiseOSError()
+      var inp = process.inputStream
+      inp.writeData(buf, contentLength)
+      dealloc(buf)
+
+    var outp = process.outputStream
+    var line = newStringOfCap(120).TaintedString
+    while true:
+      if outp.readLine(line):
+        send(client, line.string)
+        send(client, wwwNL)
+      elif not running(process): break
+
+  # --------------- Server Setup -----------------------------------------------
+
+  proc acceptRequest(client: Socket) =
+    var cgi = false
+    var query = ""
+    var buf = TaintedString""
+    discard recvLine(client, buf)
+    var path = ""
+    var data = buf.string.split()
+    var meth = reqGet
+
+    var q = find(data[1], '?')
+
+    # extract path
+    if q >= 0:
+      # strip "?..." from path, this may be found in both POST and GET
+      path = "." & data[1].substr(0, q-1)
+    else:
+      path = "." & data[1]
+    # path starts with "/", by adding "." in front of it we serve files from cwd
+    
+    if cmpIgnoreCase(data[0], "GET") == 0:
+      if q >= 0:
+        cgi = true
+        query = data[1].substr(q+1)
+    elif cmpIgnoreCase(data[0], "POST") == 0:
+      cgi = true
+      meth = reqPost
+    else:
+      unimplemented(client)
+
+    if path[path.len-1] == '/' or existsDir(path):
+      path = path / "index.html"
+
+    if not existsFile(path):
+      discardHeaders(client)
+      notFound(client)
+    else:
+      when defined(Windows):
+        var ext = splitFile(path).ext.toLower
+        if ext == ".exe" or ext == ".cgi":
+          # XXX: extract interpreter information here?
+          cgi = true
+      else:
+        if {fpUserExec, fpGroupExec, fpOthersExec} * path.getFilePermissions != {}:
+          cgi = true
+      if not cgi:
+        serveFile(client, path)
+      else:
+        executeCgi(client, path, query, meth)
+
+type
+  TServer* = object of RootObj  ## contains the current server state
+    socket: Socket
+    port: Port
+    client*: Socket          ## the socket to write the file data to
+    reqMethod*: string       ## Request method. GET or POST.
+    path*, query*: string    ## path and query the client requested
+    headers*: StringTableRef ## headers with which the client made the request
+    body*: string            ## only set with POST requests
+    ip*: string              ## ip address of the requesting client
+  
+  PAsyncHTTPServer* = ref TAsyncHTTPServer
+  TAsyncHTTPServer = object of TServer
+    asyncSocket: AsyncSocket
+  
+proc open*(s: var TServer, port = Port(80), reuseAddr = false) =
+  ## creates a new server at port `port`. If ``port == 0`` a free port is
+  ## acquired that can be accessed later by the ``port`` proc.
+  s.socket = socket(AF_INET)
+  if s.socket == invalidSocket: raiseOSError(osLastError())
+  if reuseAddr:
+    s.socket.setSockOpt(OptReuseAddr, true)
+  bindAddr(s.socket, port)
+  listen(s.socket)
+
+  if port == Port(0):
+    s.port = getSockName(s.socket)
+  else:
+    s.port = port
+  s.client = invalidSocket
+  s.reqMethod = ""
+  s.body = ""
+  s.path = ""
+  s.query = ""
+  s.headers = {:}.newStringTable()
+
+proc port*(s: var TServer): Port =
+  ## get the port number the server has acquired.
+  result = s.port
+
+proc next*(s: var TServer) =
+  ## proceed to the first/next request.
+  var client: Socket
+  new(client)
+  var ip: string
+  acceptAddr(s.socket, client, ip)
+  s.client = client
+  s.ip = ip
+  s.headers = newStringTable(modeCaseInsensitive)
+  #headers(s.client, "")
+  var data = ""
+  s.client.readLine(data)
+  if data == "":
+    # Socket disconnected 
+    s.client.close()
+    next(s)
+    return
+  var header = ""
+  while true:
+    s.client.readLine(header)
+    if header == "\c\L": break
+    if header != "":
+      var i = 0
+      var key = ""
+      var value = ""
+      i = header.parseUntil(key, ':')
+      inc(i) # skip :
+      i += header.skipWhiteSpace(i)
+      i += header.parseUntil(value, {'\c', '\L'}, i)
+      s.headers[key] = value
+    else:
+      s.client.close()
+      next(s)
+      return
+  
+  var i = skipWhitespace(data)
+  if skipIgnoreCase(data, "GET") > 0: 
+    s.reqMethod = "GET"
+    inc(i, 3)
+  elif skipIgnoreCase(data, "POST") > 0:
+    s.reqMethod = "POST"
+    inc(i, 4)
+  else:
+    unimplemented(s.client)
+    s.client.close()
+    next(s)
+    return
+  
+  if s.reqMethod == "POST":
+    # Check for Expect header
+    if s.headers.hasKey("Expect"):
+      if s.headers["Expect"].toLower == "100-continue":
+        s.client.sendStatus("100 Continue")
+      else:
+        s.client.sendStatus("417 Expectation Failed")
+  
+    # Read the body
+    # - Check for Content-length header
+    if s.headers.hasKey("Content-Length"):
+      var contentLength = 0
+      if parseInt(s.headers["Content-Length"], contentLength) == 0:
+        badRequest(s.client)
+        s.client.close()
+        next(s)
+        return
+      else:
+        var totalRead = 0
+        var totalBody = ""
+        while totalRead < contentLength:
+          var chunkSize = 8000
+          if (contentLength - totalRead) < 8000:
+            chunkSize = (contentLength - totalRead)
+          var bodyData = newString(chunkSize)
+          var octetsRead = s.client.recv(cstring(bodyData), chunkSize)
+          if octetsRead <= 0:
+            s.client.close()
+            next(s)
+            return
+          totalRead += octetsRead
+          totalBody.add(bodyData)
+        if totalBody.len != contentLength:
+          s.client.close()
+          next(s)
+          return
+
+        s.body = totalBody
+    else:
+      badRequest(s.client)
+      s.client.close()
+      next(s)
+      return
+  
+  var L = skipWhitespace(data, i)
+  inc(i, L)
+  # XXX we ignore "HTTP/1.1" etc. for now here
+  var query = 0
+  var last = i
+  while last < data.len and data[last] notin Whitespace: 
+    if data[last] == '?' and query == 0: query = last
+    inc(last)
+  if query > 0:
+    s.query = data.substr(query+1, last-1)
+    s.path = data.substr(i, query-1)
+  else:
+    s.query = ""
+    s.path = data.substr(i, last-1)
+
+proc close*(s: TServer) =
+  ## closes the server (and the socket the server uses).
+  close(s.socket)
+
+proc run*(handleRequest: proc (client: Socket, 
+                               path, query: string): bool {.closure.},
+          port = Port(80)) =
+  ## encapsulates the server object and main loop
+  var s: TServer
+  open(s, port, reuseAddr = true)
+  #echo("httpserver running on port ", s.port)
+  while true:
+    next(s)
+    if handleRequest(s.client, s.path, s.query): break
+    close(s.client)
+  close(s)
+
+# -- AsyncIO begin
+
+proc nextAsync(s: PAsyncHTTPServer) =
+  ## proceed to the first/next request.
+  var client: Socket
+  new(client)
+  var ip: string
+  acceptAddr(getSocket(s.asyncSocket), client, ip)
+  s.client = client
+  s.ip = ip
+  s.headers = newStringTable(modeCaseInsensitive)
+  #headers(s.client, "")
+  var data = ""
+  s.client.readLine(data)
+  if data == "":
+    # Socket disconnected 
+    s.client.close()
+    return
+  var header = ""
+  while true:
+    s.client.readLine(header) # TODO: Very inefficient here. Prone to DOS.
+    if header == "\c\L": break
+    if header != "":
+      var i = 0
+      var key = ""
+      var value = ""
+      i = header.parseUntil(key, ':')
+      inc(i) # skip :
+      if i < header.len:
+        i += header.skipWhiteSpace(i)
+        i += header.parseUntil(value, {'\c', '\L'}, i)
+      s.headers[key] = value
+    else:
+      s.client.close()
+      return
+  
+  var i = skipWhitespace(data)
+  if skipIgnoreCase(data, "GET") > 0: 
+    s.reqMethod = "GET"
+    inc(i, 3)
+  elif skipIgnoreCase(data, "POST") > 0:
+    s.reqMethod = "POST"
+    inc(i, 4)
+  else:
+    unimplemented(s.client)
+    s.client.close()
+    return
+  
+  if s.reqMethod == "POST":
+    # Check for Expect header
+    if s.headers.hasKey("Expect"):
+      if s.headers["Expect"].toLower == "100-continue":
+        s.client.sendStatus("100 Continue")
+      else:
+        s.client.sendStatus("417 Expectation Failed")
+  
+    # Read the body
+    # - Check for Content-length header
+    if s.headers.hasKey("Content-Length"):
+      var contentLength = 0
+      if parseInt(s.headers["Content-Length"], contentLength) == 0:
+        badRequest(s.client)
+        s.client.close()
+        return
+      else:
+        var totalRead = 0
+        var totalBody = ""
+        while totalRead < contentLength:
+          var chunkSize = 8000
+          if (contentLength - totalRead) < 8000:
+            chunkSize = (contentLength - totalRead)
+          var bodyData = newString(chunkSize)
+          var octetsRead = s.client.recv(cstring(bodyData), chunkSize)
+          if octetsRead <= 0:
+            s.client.close()
+            return
+          totalRead += octetsRead
+          totalBody.add(bodyData)
+        if totalBody.len != contentLength:
+          s.client.close()
+          return
+
+        s.body = totalBody
+    else:
+      badRequest(s.client)
+      s.client.close()
+      return
+  
+  var L = skipWhitespace(data, i)
+  inc(i, L)
+  # XXX we ignore "HTTP/1.1" etc. for now here
+  var query = 0
+  var last = i
+  while last < data.len and data[last] notin Whitespace: 
+    if data[last] == '?' and query == 0: query = last
+    inc(last)
+  if query > 0:
+    s.query = data.substr(query+1, last-1)
+    s.path = data.substr(i, query-1)
+  else:
+    s.query = ""
+    s.path = data.substr(i, last-1)
+
+proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: Socket, 
+                        path, query: string): bool {.closure, gcsafe.},
+                     port = Port(80), address = "",
+                     reuseAddr = false): PAsyncHTTPServer =
+  ## Creates an Asynchronous HTTP server at ``port``.
+  var capturedRet: PAsyncHTTPServer
+  new(capturedRet)
+  capturedRet.asyncSocket = asyncSocket()
+  capturedRet.asyncSocket.handleAccept =
+    proc (s: AsyncSocket) =
+      nextAsync(capturedRet)
+      let quit = handleRequest(capturedRet, capturedRet.client, capturedRet.path,
+                               capturedRet.query)
+      if quit: capturedRet.asyncSocket.close()
+  if reuseAddr:
+    capturedRet.asyncSocket.setSockOpt(OptReuseAddr, true)
+  
+  capturedRet.asyncSocket.bindAddr(port, address)
+  capturedRet.asyncSocket.listen()
+  if port == Port(0):
+    capturedRet.port = getSockName(capturedRet.asyncSocket)
+  else:
+    capturedRet.port = port
+  
+  capturedRet.client = invalidSocket
+  capturedRet.reqMethod = ""
+  capturedRet.body = ""
+  capturedRet.path = ""
+  capturedRet.query = ""
+  capturedRet.headers = {:}.newStringTable()
+  result = capturedRet
+
+proc register*(d: Dispatcher, s: PAsyncHTTPServer) =
+  ## Registers a ``PAsyncHTTPServer`` with a ``Dispatcher``.
+  d.register(s.asyncSocket)
+
+proc close*(h: PAsyncHTTPServer) =
+  ## Closes the ``PAsyncHTTPServer``.
+  h.asyncSocket.close()
+
+when not defined(testing) and isMainModule:
+  var counter = 0
+
+  var s: TServer
+  open(s, Port(0))
+  echo("httpserver running on port ", s.port)
+  while true:
+    next(s)
+    
+    inc(counter)
+    s.client.send("Hello, Andreas, for the $#th time. $# ? $#" % [
+      $counter, s.path, s.query] & wwwNL)
+    
+    close(s.client)
+  close(s)
+
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
new file mode 100644
index 000000000..0959bb221
--- /dev/null
+++ b/lib/pure/json.nim
@@ -0,0 +1,1262 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple high performance `JSON`:idx:
+## parser. JSON (JavaScript Object Notation) is a lightweight
+## data-interchange format that is easy for humans to read and write
+## (unlike XML). It is easy for machines to parse and generate.
+## JSON is based on a subset of the JavaScript Programming Language,
+## Standard ECMA-262 3rd Edition - December 1999.
+##
+## Usage example:
+##
+## .. code-block:: nim
+##  let
+##    small_json = """{"test": 1.3, "key2": true}"""
+##    jobj = parseJson(small_json)
+##  assert (jobj.kind == JObject)
+##  echo($jobj["test"].fnum)
+##  echo($jobj["key2"].bval)
+##
+## Results in:
+##
+## .. code-block:: nim
+##
+##   1.3000000000000000e+00
+##   true
+##
+## This module can also be used to comfortably create JSON using the `%*`
+## operator:
+##
+## .. code-block:: nim
+##
+##   var hisName = "John"
+##   let herAge = 31
+##   var j = %*
+##     [
+##       {
+##         "name": hisName,
+##         "age": 30
+##       },
+##       {
+##         "name": "Susan",
+##         "age": herAge
+##       }
+##     ]
+
+import
+  hashes, strutils, lexbase, streams, unicode, macros
+
+type
+  JsonEventKind* = enum  ## enumeration of all events that may occur when parsing
+    jsonError,           ## an error occurred during parsing
+    jsonEof,             ## end of file reached
+    jsonString,          ## a string literal
+    jsonInt,             ## an integer literal
+    jsonFloat,           ## a float literal
+    jsonTrue,            ## the value ``true``
+    jsonFalse,           ## the value ``false``
+    jsonNull,            ## the value ``null``
+    jsonObjectStart,     ## start of an object: the ``{`` token
+    jsonObjectEnd,       ## end of an object: the ``}`` token
+    jsonArrayStart,      ## start of an array: the ``[`` token
+    jsonArrayEnd         ## start of an array: the ``]`` token
+
+  TTokKind = enum        # must be synchronized with TJsonEventKind!
+    tkError,
+    tkEof,
+    tkString,
+    tkInt,
+    tkFloat,
+    tkTrue,
+    tkFalse,
+    tkNull,
+    tkCurlyLe,
+    tkCurlyRi,
+    tkBracketLe,
+    tkBracketRi,
+    tkColon,
+    tkComma
+
+  JsonError* = enum        ## enumeration that lists all errors that can occur
+    errNone,               ## no error
+    errInvalidToken,       ## invalid token
+    errStringExpected,     ## string expected
+    errColonExpected,      ## ``:`` expected
+    errCommaExpected,      ## ``,`` expected
+    errBracketRiExpected,  ## ``]`` expected
+    errCurlyRiExpected,    ## ``}`` expected
+    errQuoteExpected,      ## ``"`` or ``'`` expected
+    errEOC_Expected,       ## ``*/`` expected
+    errEofExpected,        ## EOF expected
+    errExprExpected        ## expr expected
+
+  ParserState = enum
+    stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
+    stateExpectObjectComma, stateExpectColon, stateExpectValue
+
+  JsonParser* = object of BaseLexer ## the parser object.
+    a: string
+    tok: TTokKind
+    kind: JsonEventKind
+    err: JsonError
+    state: seq[ParserState]
+    filename: string
+
+{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
+  TJsonParser: JsonParser].}
+
+const
+  errorMessages: array [JsonError, string] = [
+    "no error",
+    "invalid token",
+    "string expected",
+    "':' expected",
+    "',' expected",
+    "']' expected",
+    "'}' expected",
+    "'\"' or \"'\" expected",
+    "'*/' expected",
+    "EOF expected",
+    "expression expected"
+  ]
+  tokToStr: array [TTokKind, string] = [
+    "invalid token",
+    "EOF",
+    "string literal",
+    "int literal",
+    "float literal",
+    "true",
+    "false",
+    "null",
+    "{", "}", "[", "]", ":", ","
+  ]
+
+proc open*(my: var JsonParser, input: Stream, filename: string) =
+  ## initializes the parser with an input stream. `Filename` is only used
+  ## for nice error messages.
+  lexbase.open(my, input)
+  my.filename = filename
+  my.state = @[stateStart]
+  my.kind = jsonError
+  my.a = ""
+
+proc close*(my: var JsonParser) {.inline.} =
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+proc str*(my: JsonParser): string {.inline.} =
+  ## returns the character data for the events: ``jsonInt``, ``jsonFloat``,
+  ## ``jsonString``
+  assert(my.kind in {jsonInt, jsonFloat, jsonString})
+  return my.a
+
+proc getInt*(my: JsonParser): BiggestInt {.inline.} =
+  ## returns the number for the event: ``jsonInt``
+  assert(my.kind == jsonInt)
+  return parseBiggestInt(my.a)
+
+proc getFloat*(my: JsonParser): float {.inline.} =
+  ## returns the number for the event: ``jsonFloat``
+  assert(my.kind == jsonFloat)
+  return parseFloat(my.a)
+
+proc kind*(my: JsonParser): JsonEventKind {.inline.} =
+  ## returns the current event type for the JSON parser
+  return my.kind
+
+proc getColumn*(my: JsonParser): int {.inline.} =
+  ## get the current column the parser has arrived at.
+  result = getColNumber(my, my.bufpos)
+
+proc getLine*(my: JsonParser): int {.inline.} =
+  ## get the current line the parser has arrived at.
+  result = my.lineNumber
+
+proc getFilename*(my: JsonParser): string {.inline.} =
+  ## get the filename of the file that the parser processes.
+  result = my.filename
+
+proc errorMsg*(my: JsonParser): string =
+  ## returns a helpful error message for the event ``jsonError``
+  assert(my.kind == jsonError)
+  result = "$1($2, $3) Error: $4" % [
+    my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]]
+
+proc errorMsgExpected*(my: JsonParser, e: string): string =
+  ## returns an error message "`e` expected" in the same format as the
+  ## other error messages
+  result = "$1($2, $3) Error: $4" % [
+    my.filename, $getLine(my), $getColumn(my), e & " expected"]
+
+proc handleHexChar(c: char, x: var int): bool =
+  result = true # Success
+  case c
+  of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
+  of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
+  else: result = false # error
+
+proc parseString(my: var JsonParser): TTokKind =
+  result = tkString
+  var pos = my.bufpos + 1
+  var buf = my.buf
+  while true:
+    case buf[pos]
+    of '\0':
+      my.err = errQuoteExpected
+      result = tkError
+      break
+    of '"':
+      inc(pos)
+      break
+    of '\\':
+      case buf[pos+1]
+      of '\\', '"', '\'', '/':
+        add(my.a, buf[pos+1])
+        inc(pos, 2)
+      of 'b':
+        add(my.a, '\b')
+        inc(pos, 2)
+      of 'f':
+        add(my.a, '\f')
+        inc(pos, 2)
+      of 'n':
+        add(my.a, '\L')
+        inc(pos, 2)
+      of 'r':
+        add(my.a, '\C')
+        inc(pos, 2)
+      of 't':
+        add(my.a, '\t')
+        inc(pos, 2)
+      of 'u':
+        inc(pos, 2)
+        var r: int
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        add(my.a, toUTF8(Rune(r)))
+      else:
+        # don't bother with the error
+        add(my.a, buf[pos])
+        inc(pos)
+    of '\c':
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\c')
+    of '\L':
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos # store back
+
+proc skip(my: var JsonParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  while true:
+    case buf[pos]
+    of '/':
+      if buf[pos+1] == '/':
+        # skip line comment:
+        inc(pos, 2)
+        while true:
+          case buf[pos]
+          of '\0':
+            break
+          of '\c':
+            pos = lexbase.handleCR(my, pos)
+            buf = my.buf
+            break
+          of '\L':
+            pos = lexbase.handleLF(my, pos)
+            buf = my.buf
+            break
+          else:
+            inc(pos)
+      elif buf[pos+1] == '*':
+        # skip long comment:
+        inc(pos, 2)
+        while true:
+          case buf[pos]
+          of '\0':
+            my.err = errEOC_Expected
+            break
+          of '\c':
+            pos = lexbase.handleCR(my, pos)
+            buf = my.buf
+          of '\L':
+            pos = lexbase.handleLF(my, pos)
+            buf = my.buf
+          of '*':
+            inc(pos)
+            if buf[pos] == '/':
+              inc(pos)
+              break
+          else:
+            inc(pos)
+      else:
+        break
+    of ' ', '\t':
+      inc(pos)
+    of '\c':
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+    of '\L':
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+    else:
+      break
+  my.bufpos = pos
+
+proc parseNumber(my: var JsonParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] == '-':
+    add(my.a, '-')
+    inc(pos)
+  if buf[pos] == '.':
+    add(my.a, "0.")
+    inc(pos)
+  else:
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+    if buf[pos] == '.':
+      add(my.a, '.')
+      inc(pos)
+  # digits after the dot:
+  while buf[pos] in Digits:
+    add(my.a, buf[pos])
+    inc(pos)
+  if buf[pos] in {'E', 'e'}:
+    add(my.a, buf[pos])
+    inc(pos)
+    if buf[pos] in {'+', '-'}:
+      add(my.a, buf[pos])
+      inc(pos)
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc parseName(my: var JsonParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] in IdentStartChars:
+    while buf[pos] in IdentChars:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc getTok(my: var JsonParser): TTokKind =
+  setLen(my.a, 0)
+  skip(my) # skip whitespace, comments
+  case my.buf[my.bufpos]
+  of '-', '.', '0'..'9':
+    parseNumber(my)
+    if {'.', 'e', 'E'} in my.a:
+      result = tkFloat
+    else:
+      result = tkInt
+  of '"':
+    result = parseString(my)
+  of '[':
+    inc(my.bufpos)
+    result = tkBracketLe
+  of '{':
+    inc(my.bufpos)
+    result = tkCurlyLe
+  of ']':
+    inc(my.bufpos)
+    result = tkBracketRi
+  of '}':
+    inc(my.bufpos)
+    result = tkCurlyRi
+  of ',':
+    inc(my.bufpos)
+    result = tkComma
+  of ':':
+    inc(my.bufpos)
+    result = tkColon
+  of '\0':
+    result = tkEof
+  of 'a'..'z', 'A'..'Z', '_':
+    parseName(my)
+    case my.a
+    of "null": result = tkNull
+    of "true": result = tkTrue
+    of "false": result = tkFalse
+    else: result = tkError
+  else:
+    inc(my.bufpos)
+    result = tkError
+  my.tok = result
+
+proc next*(my: var JsonParser) =
+  ## retrieves the first/next event. This controls the parser.
+  var tk = getTok(my)
+  var i = my.state.len-1
+  # the following code is a state machine. If we had proper coroutines,
+  # the code could be much simpler.
+  case my.state[i]
+  of stateEof:
+    if tk == tkEof:
+      my.kind = jsonEof
+    else:
+      my.kind = jsonError
+      my.err = errEofExpected
+  of stateStart:
+    # tokens allowed?
+    case tk
+    of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
+      my.state[i] = stateEof # expect EOF next!
+      my.kind = JsonEventKind(ord(tk))
+    of tkBracketLe:
+      my.state.add(stateArray) # we expect any
+      my.kind = jsonArrayStart
+    of tkCurlyLe:
+      my.state.add(stateObject)
+      my.kind = jsonObjectStart
+    of tkEof:
+      my.kind = jsonEof
+    else:
+      my.kind = jsonError
+      my.err = errEofExpected
+  of stateObject:
+    case tk
+    of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
+      my.state.add(stateExpectColon)
+      my.kind = JsonEventKind(ord(tk))
+    of tkBracketLe:
+      my.state.add(stateExpectColon)
+      my.state.add(stateArray)
+      my.kind = jsonArrayStart
+    of tkCurlyLe:
+      my.state.add(stateExpectColon)
+      my.state.add(stateObject)
+      my.kind = jsonObjectStart
+    of tkCurlyRi:
+      my.kind = jsonObjectEnd
+      discard my.state.pop()
+    else:
+      my.kind = jsonError
+      my.err = errCurlyRiExpected
+  of stateArray:
+    case tk
+    of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
+      my.state.add(stateExpectArrayComma) # expect value next!
+      my.kind = JsonEventKind(ord(tk))
+    of tkBracketLe:
+      my.state.add(stateExpectArrayComma)
+      my.state.add(stateArray)
+      my.kind = jsonArrayStart
+    of tkCurlyLe:
+      my.state.add(stateExpectArrayComma)
+      my.state.add(stateObject)
+      my.kind = jsonObjectStart
+    of tkBracketRi:
+      my.kind = jsonArrayEnd
+      discard my.state.pop()
+    else:
+      my.kind = jsonError
+      my.err = errBracketRiExpected
+  of stateExpectArrayComma:
+    case tk
+    of tkComma:
+      discard my.state.pop()
+      next(my)
+    of tkBracketRi:
+      my.kind = jsonArrayEnd
+      discard my.state.pop() # pop stateExpectArrayComma
+      discard my.state.pop() # pop stateArray
+    else:
+      my.kind = jsonError
+      my.err = errBracketRiExpected
+  of stateExpectObjectComma:
+    case tk
+    of tkComma:
+      discard my.state.pop()
+      next(my)
+    of tkCurlyRi:
+      my.kind = jsonObjectEnd
+      discard my.state.pop() # pop stateExpectObjectComma
+      discard my.state.pop() # pop stateObject
+    else:
+      my.kind = jsonError
+      my.err = errCurlyRiExpected
+  of stateExpectColon:
+    case tk
+    of tkColon:
+      my.state[i] = stateExpectValue
+      next(my)
+    else:
+      my.kind = jsonError
+      my.err = errColonExpected
+  of stateExpectValue:
+    case tk
+    of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
+      my.state[i] = stateExpectObjectComma
+      my.kind = JsonEventKind(ord(tk))
+    of tkBracketLe:
+      my.state[i] = stateExpectObjectComma
+      my.state.add(stateArray)
+      my.kind = jsonArrayStart
+    of tkCurlyLe:
+      my.state[i] = stateExpectObjectComma
+      my.state.add(stateObject)
+      my.kind = jsonObjectStart
+    else:
+      my.kind = jsonError
+      my.err = errExprExpected
+
+
+# ------------- higher level interface ---------------------------------------
+
+type
+  JsonNodeKind* = enum ## possible JSON node types
+    JNull,
+    JBool,
+    JInt,
+    JFloat,
+    JString,
+    JObject,
+    JArray
+
+  JsonNode* = ref JsonNodeObj ## JSON node
+  JsonNodeObj* {.acyclic.} = object
+    case kind*: JsonNodeKind
+    of JString:
+      str*: string
+    of JInt:
+      num*: BiggestInt
+    of JFloat:
+      fnum*: float
+    of JBool:
+      bval*: bool
+    of JNull:
+      nil
+    of JObject:
+      fields*: seq[tuple[key: string, val: JsonNode]]
+    of JArray:
+      elems*: seq[JsonNode]
+
+  JsonParsingError* = object of ValueError ## is raised for a JSON error
+
+{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj,
+    PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].}
+
+proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} =
+  ## raises an `EJsonParsingError` exception.
+  raise newException(JsonParsingError, errorMsgExpected(p, msg))
+
+proc newJString*(s: string): JsonNode =
+  ## Creates a new `JString JsonNode`.
+  new(result)
+  result.kind = JString
+  result.str = s
+
+proc newJStringMove(s: string): JsonNode =
+  new(result)
+  result.kind = JString
+  shallowCopy(result.str, s)
+
+proc newJInt*(n: BiggestInt): JsonNode =
+  ## Creates a new `JInt JsonNode`.
+  new(result)
+  result.kind = JInt
+  result.num  = n
+
+proc newJFloat*(n: float): JsonNode =
+  ## Creates a new `JFloat JsonNode`.
+  new(result)
+  result.kind = JFloat
+  result.fnum  = n
+
+proc newJBool*(b: bool): JsonNode =
+  ## Creates a new `JBool JsonNode`.
+  new(result)
+  result.kind = JBool
+  result.bval = b
+
+proc newJNull*(): JsonNode =
+  ## Creates a new `JNull JsonNode`.
+  new(result)
+
+proc newJObject*(): JsonNode =
+  ## Creates a new `JObject JsonNode`
+  new(result)
+  result.kind = JObject
+  result.fields = @[]
+
+proc newJArray*(): JsonNode =
+  ## Creates a new `JArray JsonNode`
+  new(result)
+  result.kind = JArray
+  result.elems = @[]
+
+proc getStr*(n: JsonNode, default: string = ""): string =
+  ## Retrieves the string value of a `JString JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JString``.
+  if n.kind != JString: return default
+  else: return n.str
+
+proc getNum*(n: JsonNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `JInt JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JInt``.
+  if n.kind != JInt: return default
+  else: return n.num
+
+proc getFNum*(n: JsonNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `JFloat JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JFloat``.
+  if n.kind != JFloat: return default
+  else: return n.fnum
+
+proc getBVal*(n: JsonNode, default: bool = false): bool =
+  ## Retrieves the bool value of a `JBool JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JBool``.
+  if n.kind != JBool: return default
+  else: return n.bval
+
+proc getFields*(n: JsonNode,
+    default: seq[tuple[key: string, val: JsonNode]] = @[]):
+        seq[tuple[key: string, val: JsonNode]] =
+  ## Retrieves the key, value pairs of a `JObject JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JObject``.
+  if n.kind != JObject: return default
+  else: return n.fields
+
+proc getElems*(n: JsonNode, default: seq[JsonNode] = @[]): seq[JsonNode] =
+  ## Retrieves the int value of a `JArray JsonNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``JArray``.
+  if n.kind != JArray: return default
+  else: return n.elems
+
+proc `%`*(s: string): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JString JsonNode`.
+  new(result)
+  result.kind = JString
+  result.str = s
+
+proc `%`*(n: BiggestInt): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
+  new(result)
+  result.kind = JInt
+  result.num  = n
+
+proc `%`*(n: float): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JFloat JsonNode`.
+  new(result)
+  result.kind = JFloat
+  result.fnum  = n
+
+proc `%`*(b: bool): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JBool JsonNode`.
+  new(result)
+  result.kind = JBool
+  result.bval = b
+
+proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JObject JsonNode`
+  new(result)
+  result.kind = JObject
+  newSeq(result.fields, keyVals.len)
+  for i, p in pairs(keyVals): result.fields[i] = p
+
+proc `%`*(elements: openArray[JsonNode]): JsonNode =
+  ## Generic constructor for JSON data. Creates a new `JArray JsonNode`
+  new(result)
+  result.kind = JArray
+  newSeq(result.elems, elements.len)
+  for i, p in pairs(elements): result.elems[i] = p
+
+proc toJson(x: NimNode): NimNode {.compiletime.} =
+  case x.kind
+  of nnkBracket:
+    result = newNimNode(nnkBracket)
+    for i in 0 .. <x.len:
+      result.add(toJson(x[i]))
+
+  of nnkTableConstr:
+    result = newNimNode(nnkTableConstr)
+    for i in 0 .. <x.len:
+      assert x[i].kind == nnkExprColonExpr
+      result.add(newNimNode(nnkExprColonExpr).add(x[i][0]).add(toJson(x[i][1])))
+
+  else:
+    result = x
+
+  result = prefix(result, "%")
+
+macro `%*`*(x: expr): expr =
+  ## Convert an expression to a JsonNode directly, without having to specify
+  ## `%` for every element.
+  result = toJson(x)
+
+proc `==`* (a,b: JsonNode): bool =
+  ## Check two nodes for equality
+  if a.isNil:
+    if b.isNil: return true
+    return false
+  elif b.isNil or a.kind != b.kind:
+    return false
+  else:
+    return case a.kind
+    of JString:
+      a.str == b.str
+    of JInt:
+      a.num == b.num
+    of JFloat:
+      a.fnum == b.fnum
+    of JBool:
+      a.bval == b.bval
+    of JNull:
+      true
+    of JArray:
+      a.elems == b.elems
+    of JObject:
+      a.fields == b.fields
+
+proc hash* (n:JsonNode): THash =
+  ## Compute the hash for a JSON node
+  case n.kind
+  of JArray:
+    result = hash(n.elems)
+  of JObject:
+    result = hash(n.fields)
+  of JInt:
+    result = hash(n.num)
+  of JFloat:
+    result = hash(n.fnum)
+  of JBool:
+    result = hash(n.bval.int)
+  of JString:
+    result = hash(n.str)
+  of JNull:
+    result = hash(0)
+
+proc len*(n: JsonNode): int =
+  ## If `n` is a `JArray`, it returns the number of elements.
+  ## If `n` is a `JObject`, it returns the number of pairs.
+  ## Else it returns 0.
+  case n.kind
+  of JArray: result = n.elems.len
+  of JObject: result = n.fields.len
+  else: discard
+
+proc `[]`*(node: JsonNode, name: string): JsonNode {.inline.} =
+  ## Gets a field from a `JObject`, which must not be nil.
+  ## If the value at `name` does not exist, returns nil
+  assert(not isNil(node))
+  assert(node.kind == JObject)
+  for key, item in items(node.fields):
+    if key == name:
+      return item
+  return nil
+
+proc `[]`*(node: JsonNode, index: int): JsonNode {.inline.} =
+  ## Gets the node at `index` in an Array. Result is undefined if `index`
+  ## is out of bounds
+  assert(not isNil(node))
+  assert(node.kind == JArray)
+  return node.elems[index]
+
+proc hasKey*(node: JsonNode, key: string): bool =
+  ## Checks if `key` exists in `node`.
+  assert(node.kind == JObject)
+  for k, item in items(node.fields):
+    if k == key: return true
+
+proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
+  ## Deprecated for `hasKey`
+
+proc add*(father, child: JsonNode) =
+  ## Adds `child` to a JArray node `father`.
+  assert father.kind == JArray
+  father.elems.add(child)
+
+proc add*(obj: JsonNode, key: string, val: JsonNode) =
+  ## Adds ``(key, val)`` pair to the JObject node `obj`. For speed
+  ## reasons no check for duplicate keys is performed!
+  ## But ``[]=`` performs the check.
+  assert obj.kind == JObject
+  obj.fields.add((key, val))
+
+proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) {.inline.} =
+  ## Sets a field from a `JObject`. Performs a check for duplicate keys.
+  assert(obj.kind == JObject)
+  for i in 0..obj.fields.len-1:
+    if obj.fields[i].key == key:
+      obj.fields[i].val = val
+      return
+  obj.fields.add((key, val))
+
+proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
+  ## Traverses the node and gets the given value. If any of the
+  ## keys do not exist, returns nil. Also returns nil if one of the
+  ## intermediate data structures is not an object
+  result = node
+  for key in keys:
+    if isNil(result) or result.kind!=JObject:
+      return nil
+    result=result[key]
+
+proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
+  ## Traverses the node and tries to set the value at the given location
+  ## to `value` If any of the keys are missing, they are added
+  var node = node
+  for i in 0..(keys.len-2):
+    if isNil(node[keys[i]]):
+      node[keys[i]] = newJObject()
+    node = node[keys[i]]
+  node[keys[keys.len-1]] = value
+
+proc delete*(obj: JsonNode, key: string) =
+  ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
+  assert(obj.kind == JObject)
+  for i in 0..obj.fields.len-1:
+    if obj.fields[i].key == key:
+      obj.fields.delete(i)
+      return
+  raise newException(IndexError, "key not in object")
+
+proc copy*(p: JsonNode): JsonNode =
+  ## Performs a deep copy of `a`.
+  case p.kind
+  of JString:
+    result = newJString(p.str)
+  of JInt:
+    result = newJInt(p.num)
+  of JFloat:
+    result = newJFloat(p.fnum)
+  of JBool:
+    result = newJBool(p.bval)
+  of JNull:
+    result = newJNull()
+  of JObject:
+    result = newJObject()
+    for key, field in items(p.fields):
+      result.fields.add((key, copy(field)))
+  of JArray:
+    result = newJArray()
+    for i in items(p.elems):
+      result.elems.add(copy(i))
+
+# ------------- pretty printing ----------------------------------------------
+
+proc indent(s: var string, i: int) =
+  s.add(spaces(i))
+
+proc newIndent(curr, indent: int, ml: bool): int =
+  if ml: return curr + indent
+  else: return indent
+
+proc nl(s: var string, ml: bool) =
+  if ml: s.add("\n")
+
+proc escapeJson*(s: string): string =
+  ## Converts a string `s` to its JSON representation.
+  result = newStringOfCap(s.len + s.len shr 3)
+  result.add("\"")
+  for x in runes(s):
+    var r = int(x)
+    if r >= 32 and r <= 127:
+      var c = chr(r)
+      case c
+      of '"': result.add("\\\"")
+      of '\\': result.add("\\\\")
+      else: result.add(c)
+    else:
+      result.add("\\u")
+      result.add(toHex(r, 4))
+  result.add("\"")
+
+proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
+              lstArr = false, currIndent = 0) =
+  case node.kind
+  of JObject:
+    if currIndent != 0 and not lstArr: result.nl(ml)
+    result.indent(currIndent) # Indentation
+    if node.fields.len > 0:
+      result.add("{")
+      result.nl(ml) # New line
+      for i in 0..len(node.fields)-1:
+        if i > 0:
+          result.add(", ")
+          result.nl(ml) # New Line
+        # Need to indent more than {
+        result.indent(newIndent(currIndent, indent, ml))
+        result.add(escapeJson(node.fields[i].key))
+        result.add(": ")
+        toPretty(result, node.fields[i].val, indent, ml, false,
+                 newIndent(currIndent, indent, ml))
+      result.nl(ml)
+      result.indent(currIndent) # indent the same as {
+      result.add("}")
+    else:
+      result.add("{}")
+  of JString:
+    if lstArr: result.indent(currIndent)
+    result.add(escapeJson(node.str))
+  of JInt:
+    if lstArr: result.indent(currIndent)
+    result.add($node.num)
+  of JFloat:
+    if lstArr: result.indent(currIndent)
+    result.add($node.fnum)
+  of JBool:
+    if lstArr: result.indent(currIndent)
+    result.add($node.bval)
+  of JArray:
+    if lstArr: result.indent(currIndent)
+    if len(node.elems) != 0:
+      result.add("[")
+      result.nl(ml)
+      for i in 0..len(node.elems)-1:
+        if i > 0:
+          result.add(", ")
+          result.nl(ml) # New Line
+        toPretty(result, node.elems[i], indent, ml,
+            true, newIndent(currIndent, indent, ml))
+      result.nl(ml)
+      result.indent(currIndent)
+      result.add("]")
+    else: result.add("[]")
+  of JNull:
+    if lstArr: result.indent(currIndent)
+    result.add("null")
+
+proc pretty*(node: JsonNode, indent = 2): string =
+  ## Converts `node` to its JSON Representation, with indentation and
+  ## on multiple lines.
+  result = ""
+  toPretty(result, node, indent)
+
+proc toUgly*(result: var string, node: JsonNode) =
+  ## Converts `node` to its JSON Representation, without
+  ## regard for human readability. Meant to improve ``$`` string
+  ## conversion performance.
+  ##
+  ## This provides higher efficiency than the ``toPretty`` procedure as it
+  ## does **not** attempt to format the resulting JSON to make it human readable.
+  var comma = false
+  case node.kind:
+  of JArray:
+    result.add "["
+    for child in node.elems:
+      if comma: result.add ","
+      else:     comma = true
+      result.toUgly child
+    result.add "]"
+  of JObject:
+    result.add "{"
+    for key, value in items(node.fields):
+      if comma: result.add ","
+      else:     comma = true
+      result.add key.escapeJson()
+      result.add ":"
+      result.toUgly value
+    result.add "}"
+  of JString:
+    result.add node.str.escapeJson()
+  of JInt:
+    result.add($node.num)
+  of JFloat:
+    result.add($node.fnum)
+  of JBool:
+    result.add(if node.bval: "true" else: "false")
+  of JNull:
+    result.add "null"
+
+proc `$`*(node: JsonNode): string =
+  ## Converts `node` to its JSON Representation on one line.
+  result = newStringOfCap(node.len shl 1)
+  toUgly(result, node)
+
+iterator items*(node: JsonNode): JsonNode =
+  ## Iterator for the items of `node`. `node` has to be a JArray.
+  assert node.kind == JArray
+  for i in items(node.elems):
+    yield i
+
+iterator mitems*(node: var JsonNode): var JsonNode =
+  ## Iterator for the items of `node`. `node` has to be a JArray. Items can be
+  ## modified.
+  assert node.kind == JArray
+  for i in mitems(node.elems):
+    yield i
+
+iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] =
+  ## Iterator for the child elements of `node`. `node` has to be a JObject.
+  assert node.kind == JObject
+  for key, val in items(node.fields):
+    yield (key, val)
+
+iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
+  ## Iterator for the child elements of `node`. `node` has to be a JObject.
+  ## Items can be modified
+  assert node.kind == JObject
+  for keyVal in mitems(node.fields):
+    yield keyVal
+
+proc eat(p: var JsonParser, tok: TTokKind) =
+  if p.tok == tok: discard getTok(p)
+  else: raiseParseErr(p, tokToStr[tok])
+
+proc parseJson(p: var JsonParser): JsonNode =
+  ## Parses JSON from a JSON Parser `p`.
+  case p.tok
+  of tkString:
+    # we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
+    result = newJStringMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkInt:
+    result = newJInt(parseBiggestInt(p.a))
+    discard getTok(p)
+  of tkFloat:
+    result = newJFloat(parseFloat(p.a))
+    discard getTok(p)
+  of tkTrue:
+    result = newJBool(true)
+    discard getTok(p)
+  of tkFalse:
+    result = newJBool(false)
+    discard getTok(p)
+  of tkNull:
+    result = newJNull()
+    discard getTok(p)
+  of tkCurlyLe:
+    result = newJObject()
+    discard getTok(p)
+    while p.tok != tkCurlyRi:
+      if p.tok != tkString:
+        raiseParseErr(p, "string literal as key expected")
+      var key = p.a
+      discard getTok(p)
+      eat(p, tkColon)
+      var val = parseJson(p)
+      result[key] = val
+      if p.tok != tkComma: break
+      discard getTok(p)
+    eat(p, tkCurlyRi)
+  of tkBracketLe:
+    result = newJArray()
+    discard getTok(p)
+    while p.tok != tkBracketRi:
+      result.add(parseJson(p))
+      if p.tok != tkComma: break
+      discard getTok(p)
+    eat(p, tkBracketRi)
+  of tkError, tkCurlyRi, tkBracketRi, tkColon, tkComma, tkEof:
+    raiseParseErr(p, "{")
+
+when not defined(js):
+  proc parseJson*(s: Stream, filename: string): JsonNode =
+    ## Parses from a stream `s` into a `JsonNode`. `filename` is only needed
+    ## for nice error messages.
+    var p: JsonParser
+    p.open(s, filename)
+    discard getTok(p) # read first token
+    result = p.parseJson()
+    p.close()
+
+  proc parseJson*(buffer: string): JsonNode =
+    ## Parses JSON from `buffer`.
+    result = parseJson(newStringStream(buffer), "input")
+
+  proc parseFile*(filename: string): JsonNode =
+    ## Parses `file` into a `JsonNode`.
+    var stream = newFileStream(filename, fmRead)
+    if stream == nil:
+      raise newException(IOError, "cannot read from file: " & filename)
+    result = parseJson(stream, filename)
+else:
+  from math import `mod`
+  type
+    TJSObject = object
+  proc parseNativeJson(x: cstring): TJSObject {.importc: "JSON.parse".}
+
+  proc getVarType(x): JsonNodeKind =
+    result = JNull
+    proc getProtoName(y): cstring
+      {.importc: "Object.prototype.toString.call".}
+    case $getProtoName(x) # TODO: Implicit returns fail here.
+    of "[object Array]": return JArray
+    of "[object Object]": return JObject
+    of "[object Number]":
+      if cast[float](x) mod 1.0 == 0:
+        return JInt
+      else:
+        return JFloat
+    of "[object Boolean]": return JBool
+    of "[object Null]": return JNull
+    of "[object String]": return JString
+    else: assert false
+
+  proc len(x: TJSObject): int =
+    assert x.getVarType == JArray
+    asm """
+      return `x`.length;
+    """
+
+  proc `[]`(x: TJSObject, y: string): TJSObject =
+    assert x.getVarType == JObject
+    asm """
+      return `x`[`y`];
+    """
+
+  proc `[]`(x: TJSObject, y: int): TJSObject =
+    assert x.getVarType == JArray
+    asm """
+      return `x`[`y`];
+    """
+
+  proc convertObject(x: TJSObject): JsonNode =
+    case getVarType(x)
+    of JArray:
+      result = newJArray()
+      for i in 0 .. <x.len:
+        result.add(x[i].convertObject())
+    of JObject:
+      result = newJObject()
+      asm """for (property in `x`) {
+        if (`x`.hasOwnProperty(property)) {
+      """
+      var nimProperty: cstring
+      var nimValue: TJSObject
+      asm "`nimProperty` = property; `nimValue` = `x`[property];"
+      result[$nimProperty] = nimValue.convertObject()
+      asm "}}"
+    of JInt:
+      result = newJInt(cast[int](x))
+    of JFloat:
+      result = newJFloat(cast[float](x))
+    of JString:
+      result = newJString($cast[cstring](x))
+    of JBool:
+      result = newJBool(cast[bool](x))
+    of JNull:
+      result = newJNull()
+
+  proc parseJson*(buffer: string): JsonNode =
+    return parseNativeJson(buffer).convertObject()
+
+when false:
+  import os
+  var s = newFileStream(paramStr(1), fmRead)
+  if s == nil: quit("cannot open the file" & paramStr(1))
+  var x: JsonParser
+  open(x, s, paramStr(1))
+  while true:
+    next(x)
+    case x.kind
+    of jsonError:
+      Echo(x.errorMsg())
+      break
+    of jsonEof: break
+    of jsonString, jsonInt, jsonFloat: echo(x.str)
+    of jsonTrue: echo("!TRUE")
+    of jsonFalse: echo("!FALSE")
+    of jsonNull: echo("!NULL")
+    of jsonObjectStart: echo("{")
+    of jsonObjectEnd: echo("}")
+    of jsonArrayStart: echo("[")
+    of jsonArrayEnd: echo("]")
+
+  close(x)
+
+# { "json": 5 }
+# To get that we shall use, obj["json"]
+
+when isMainModule:
+  var parsed = parseFile("tests/testdata/jsontest.json")
+  var parsed2 = parseFile("tests/testdata/jsontest2.json")
+
+  try:
+    discard parsed["key2"][12123]
+    assert(false)
+  except IndexError: assert(true)
+
+  let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
+  # nil passthrough
+  assert(testJson{"doesnt_exist"}{"anything"}.isNil)
+  testJson{["c", "d"]} = %true
+  assert(testJson["c"]["d"].bval)
+
+  # test `$`
+  let stringified = $testJson
+  let parsedAgain = parseJson(stringified)
+  assert(parsedAgain["b"].str == "asd")
+
+  # Bounds checking
+  try:
+    let a = testJson["a"][9]
+    assert(false, "EInvalidIndex not thrown")
+  except IndexError:
+    discard
+  try:
+    let a = testJson["a"][-1]
+    assert(false, "EInvalidIndex not thrown")
+  except IndexError:
+    discard
+  try:
+    assert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
+  except:
+    assert(false, "EInvalidIndex thrown for valid index")
+
+  assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
+  assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
+  assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+  assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+  assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+
+  # Generator:
+  var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
+  assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+  var j2 = %*
+    [
+      {
+        "name": "John",
+        "age": 30
+      },
+      {
+        "name": "Susan",
+        "age": 31
+      }
+    ]
+  assert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+  var name = "John"
+  let herAge = 30
+  const hisAge = 31
+
+  var j3 = %*
+    [ { "name": "John"
+      , "age": herAge
+      }
+    , { "name": "Susan"
+      , "age": hisAge
+      }
+    ]
+  assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim
new file mode 100644
index 000000000..23a87d9f8
--- /dev/null
+++ b/lib/pure/lexbase.nim
@@ -0,0 +1,169 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2009 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. Only at line endings checks are necessary if the buffer
+## needs refilling.
+
+import
+  strutils, streams
+
+const
+  EndOfFile* = '\0'           ## end of file marker
+  NewLines* = {'\c', '\L'}
+
+# Buffer handling:
+#  buf:
+#  "Example Text\n ha!"   bufLen = 17
+#   ^pos = 0     ^ sentinel = 12
+#
+
+type
+  BaseLexer* = object of RootObj ## 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
+    input: Stream            ## the input stream
+    lineNumber*: int          ## the current line number
+    sentinel: int
+    lineStart: int            # index of last line start in buffer
+    fileOpened: bool
+
+{.deprecated: [TBaseLexer: BaseLexer].}
+
+proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192)
+  ## inits the TBaseLexer with a stream to read from
+
+proc close*(L: var BaseLexer)
+  ## closes the base lexer. This closes `L`'s associated stream too.
+
+proc getCurrentLine*(L: BaseLexer, marker: bool = true): string
+  ## retrieves the current line.
+
+proc getColNumber*(L: BaseLexer, pos: int): int
+  ## retrieves the current column.
+
+proc handleCR*(L: var BaseLexer, 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 BaseLexer, 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 close(L: var BaseLexer) =
+  dealloc(L.buf)
+  close(L.input)
+
+proc fillBuffer(L: var BaseLexer) =
+  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 = readData(L.input, 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 = readData(L.input, 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 BaseLexer, 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 BaseLexer, 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 BaseLexer, pos: int): int =
+  assert(L.buf[pos] == '\L')
+  inc(L.lineNumber)
+  result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
+
+proc skipUtf8Bom(L: var BaseLexer) =
+  if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
+    inc(L.bufpos, 3)
+    inc(L.lineStart, 3)
+
+proc open(L: var BaseLexer, input: Stream, bufLen: int = 8192) =
+  assert(bufLen > 0)
+  assert(input != nil)
+  L.input = input
+  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
+  fillBuffer(L)
+  skipUtf8Bom(L)
+
+proc getColNumber(L: BaseLexer, pos: int): int =
+  result = abs(pos - L.lineStart)
+
+proc getCurrentLine(L: BaseLexer, 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, spaces(getColNumber(L, L.bufpos)) & "^\n")
+
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
new file mode 100644
index 000000000..cc5340211
--- /dev/null
+++ b/lib/pure/logging.nim
@@ -0,0 +1,291 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple logger. It has been designed to be as simple
+## as possible to avoid bloat, if this library does not fulfill your needs,
+## write your own.
+##
+## Format strings support the following variables which must be prefixed with
+## the dollar operator (``$``):
+##
+## ============  =======================
+##   Operator     Output
+## ============  =======================
+## $date         Current date
+## $time         Current time
+## $app          ``os.getAppFilename()``
+## ============  =======================
+##
+##
+## The following example demonstrates logging to three different handlers
+## simultaneously:
+##
+## .. code-block:: nim
+##
+##    var L = newConsoleLogger()
+##    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
+##    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+##    addHandler(L)
+##    addHandler(fL)
+##    addHandler(rL)
+##    info("920410:52 accepted")
+##    warn("4 8 15 16 23 4-- Error")
+##    error("922044:16 SYSTEM FAILURE")
+##    fatal("SYSTEM FAILURE SYSTEM FAILURE")
+##
+## **Warning:** The global list of handlers is a thread var, this means that
+## the handlers must be re-added in each thread.
+
+import strutils, os, times
+
+type
+  Level* = enum  ## logging level
+    lvlAll,       ## all levels active
+    lvlDebug,     ## debug level (and any above) active
+    lvlInfo,      ## info level (and any above) active
+    lvlWarn,      ## warn level (and any above) active
+    lvlError,     ## error level (and any above) active
+    lvlFatal,     ## fatal level (and any above) active
+    lvlNone       ## no levels active
+
+const
+  LevelNames*: array [Level, string] = [
+    "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
+  ]
+
+  defaultFmtStr* = "" ## default string between log level and message per logger
+  verboseFmtStr* = "$date $time "
+
+type
+  Logger* = ref object of RootObj ## abstract logger; the base type of all loggers
+    levelThreshold*: Level    ## only messages of level >= levelThreshold
+                              ## should be processed
+    fmtStr*: string ## = defaultFmtStr by default, see substituteLog for $date etc.
+
+  ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
+                                        ## console
+
+  FileLogger* = ref object of Logger ## logger that writes the messages to a file
+    f: File
+
+  RollingFileLogger* = ref object of FileLogger ## logger that writes the
+                                                ## messages to a file and
+                                                ## performs log rotation
+    maxLines: int # maximum number of lines
+    curLine : int
+    baseName: string # initial filename
+    baseMode: FileMode # initial file mode
+    logFiles: int # how many log files already created, e.g. basename.1, basename.2...
+
+{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
+    PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
+
+proc substituteLog(frmt: string): string =
+  ## converts $date to the current date
+  ## converts $time to the current time
+  ## converts $app to getAppFilename()
+  ## converts
+  result = newStringOfCap(frmt.len + 20)
+  var i = 0
+  while i < frmt.len:
+    if frmt[i] != '$':
+      result.add(frmt[i])
+      inc(i)
+    else:
+      inc(i)
+      var v = ""
+      var app = getAppFilename()
+      while frmt[i] in IdentChars:
+        v.add(toLower(frmt[i]))
+        inc(i)
+      case v
+      of "date": result.add(getDateStr())
+      of "time": result.add(getClockStr())
+      of "app":  result.add(app)
+      of "appdir": result.add(app.splitFile.dir)
+      of "appname": result.add(app.splitFile.name)
+      else: discard
+
+method log*(logger: Logger, level: Level,
+            frmt: string, args: varargs[string, `$`]) {.
+            raises: [Exception],
+            tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} =
+  ## Override this method in custom loggers. Default implementation does
+  ## nothing.
+  discard
+
+method log*(logger: ConsoleLogger, level: Level,
+            frmt: string, args: varargs[string, `$`]) =
+  ## Logs to the console using ``logger`` only.
+  if level >= logger.levelThreshold:
+    writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
+            frmt % args)
+
+method log*(logger: FileLogger, level: Level,
+            frmt: string, args: varargs[string, `$`]) =
+  ## Logs to a file using ``logger`` only.
+  if level >= logger.levelThreshold:
+    writeln(logger.f, LevelNames[level], " ",
+            substituteLog(logger.fmtStr), frmt % args)
+
+proc defaultFilename*(): string =
+  ## Returns the default filename for a logger.
+  var (path, name, ext) = splitFile(getAppFilename())
+  result = changeFileExt(path / name, "log")
+
+proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
+  ## Creates a new console logger. This logger logs to the console.
+  new result
+  result.fmtStr = fmtStr
+  result.levelThreshold = levelThreshold
+
+proc newFileLogger*(filename = defaultFilename(),
+                    mode: FileMode = fmAppend,
+                    levelThreshold = lvlAll,
+                    fmtStr = defaultFmtStr): FileLogger =
+  ## Creates a new file logger. This logger logs to a file.
+  new(result)
+  result.levelThreshold = levelThreshold
+  result.f = open(filename, mode)
+  result.fmtStr = fmtStr
+
+# ------
+
+proc countLogLines(logger: RollingFileLogger): int =
+  result = 0
+  for line in logger.f.lines():
+    result.inc()
+
+proc countFiles(filename: string): int =
+  # Example: file.log.1
+  result = 0
+  let (dir, name, ext) = splitFile(filename)
+  for kind, path in walkDir(dir):
+    if kind == pcFile:
+      let llfn = name & ext & ExtSep
+      if path.extractFilename.startsWith(llfn):
+        let numS = path.extractFilename[llfn.len .. ^1]
+        try:
+          let num = parseInt(numS)
+          if num > result:
+            result = num
+        except ValueError: discard
+
+proc newRollingFileLogger*(filename = defaultFilename(),
+                           mode: FileMode = fmReadWrite,
+                           levelThreshold = lvlAll,
+                           fmtStr = defaultFmtStr,
+                           maxLines = 1000): RollingFileLogger =
+  ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
+  ## a new log file will be started and the old will be renamed.
+  new(result)
+  result.levelThreshold = levelThreshold
+  result.fmtStr = fmtStr
+  result.maxLines = maxLines
+  result.f = open(filename, mode)
+  result.curLine = 0
+  result.baseName = filename
+  result.baseMode = mode
+
+  result.logFiles = countFiles(filename)
+
+  if mode == fmAppend:
+    # We need to get a line count because we will be appending to the file.
+    result.curLine = countLogLines(result)
+
+proc rotate(logger: RollingFileLogger) =
+  let (dir, name, ext) = splitFile(logger.baseName)
+  for i in countdown(logger.logFiles, 0):
+    let srcSuff = if i != 0: ExtSep & $i else: ""
+    moveFile(dir / (name & ext & srcSuff),
+             dir / (name & ext & ExtSep & $(i+1)))
+
+method log*(logger: RollingFileLogger, level: Level,
+            frmt: string, args: varargs[string, `$`]) =
+  ## Logs to a file using rolling ``logger`` only.
+  if level >= logger.levelThreshold:
+    if logger.curLine >= logger.maxLines:
+      logger.f.close()
+      rotate(logger)
+      logger.logFiles.inc
+      logger.curLine = 0
+      logger.f = open(logger.baseName, logger.baseMode)
+
+    writeln(logger.f, LevelNames[level], " ",substituteLog(logger.fmtStr), frmt % args)
+    logger.curLine.inc
+
+# --------
+
+var level {.threadvar.}: Level   ## global log filter
+var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
+
+proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) =
+  for logger in items(handlers):
+    if level >= logger.levelThreshold:
+      log(logger, level, frmt, args)
+
+template log*(level: Level, frmt: string, args: varargs[string, `$`]) =
+  ## Logs a message to all registered handlers at the given level.
+  bind logLoop
+  bind `%`
+  bind logging.level
+
+  if level >= logging.level:
+    logLoop(level, frmt, args)
+
+template debug*(frmt: string, args: varargs[string, `$`]) =
+  ## Logs a debug message to all registered handlers.
+  log(lvlDebug, frmt, args)
+
+template info*(frmt: string, args: varargs[string, `$`]) =
+  ## Logs an info message to all registered handlers.
+  log(lvlInfo, frmt, args)
+
+template warn*(frmt: string, args: varargs[string, `$`]) =
+  ## Logs a warning message to all registered handlers.
+  log(lvlWarn, frmt, args)
+
+template error*(frmt: string, args: varargs[string, `$`]) =
+  ## Logs an error message to all registered handlers.
+  log(lvlError, frmt, args)
+
+template fatal*(frmt: string, args: varargs[string, `$`]) =
+  ## Logs a fatal error message to all registered handlers.
+  log(lvlFatal, frmt, args)
+
+proc addHandler*(handler: Logger) =
+  ## Adds ``handler`` to the list of handlers.
+  if handlers.isNil: handlers = @[]
+  handlers.add(handler)
+
+proc getHandlers*(): seq[Logger] =
+  ## Returns a list of all the registered handlers.
+  return handlers
+
+proc setLogFilter*(lvl: Level) =
+  ## Sets the global log filter.
+  level = lvl
+
+proc getLogFilter*(): Level =
+  ## Gets the global log filter.
+  return level
+
+# --------------
+
+when not defined(testing) and isMainModule:
+  var L = newConsoleLogger()
+  var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
+  var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+  addHandler(L)
+  addHandler(fL)
+  addHandler(rL)
+  for i in 0 .. 25:
+    info("hello" & $i, [])
+
+
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
new file mode 100644
index 000000000..e0092f314
--- /dev/null
+++ b/lib/pure/marshal.nim
@@ -0,0 +1,330 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains procs for `serialization`:idx: and `deseralization`:idx:
+## of arbitrary Nim data structures. The serialization format uses `JSON`:idx:.
+##
+## **Restriction**: For objects their type is **not** serialized. This means
+## essentially that it does not work if the object has some other runtime
+## type than its compiletime type:
+##
+## .. code-block:: nim
+##
+##   type
+##     TA = object
+##     TB = object of TA
+##       f: int
+##
+##   var
+##     a: ref TA
+##     b: ref TB
+##
+##   new(b)
+##   a = b
+##   echo($$a[]) # produces "{}", not "{f: 0}"
+##
+## **Note**: The ``to`` and ``$$`` operations are available at compile-time!
+
+import streams, typeinfo, json, intsets, tables
+
+proc ptrToInt(x: pointer): int {.inline.} =
+  result = cast[int](x) # don't skip alignment
+
+proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
+  case a.kind
+  of akNone: assert false
+  of akBool: s.write($getBool(a))
+  of akChar:
+    let ch = getChar(a)
+    if ch < '\128':
+      s.write(escapeJson($ch))
+    else:
+      s.write($int(ch))
+  of akArray, akSequence:
+    if a.kind == akSequence and isNil(a): s.write("null")
+    else:
+      s.write("[")
+      for i in 0 .. a.len-1:
+        if i > 0: s.write(", ")
+        storeAny(s, a[i], stored)
+      s.write("]")
+  of akObject, akTuple:
+    s.write("{")
+    var i = 0
+    for key, val in fields(a):
+      if i > 0: s.write(", ")
+      s.write(escapeJson(key))
+      s.write(": ")
+      storeAny(s, val, stored)
+      inc(i)
+    s.write("}")
+  of akSet:
+    s.write("[")
+    var i = 0
+    for e in elements(a):
+      if i > 0: s.write(", ")
+      s.write($e)
+      inc(i)
+    s.write("]")
+  of akRange: storeAny(s, skipRange(a), stored)
+  of akEnum: s.write(getEnumField(a).escapeJson)
+  of akPtr, akRef:
+    var x = a.getPointer
+    if isNil(x): s.write("null")
+    elif stored.containsOrIncl(x.ptrToInt):
+      # already stored, so we simply write out the pointer as an int:
+      s.write($x.ptrToInt)
+    else:
+      # else as a [value, key] pair:
+      # (reversed order for convenient x[0] access!)
+      s.write("[")
+      s.write($x.ptrToInt)
+      s.write(", ")
+      storeAny(s, a[], stored)
+      s.write("]")
+  of akProc, akPointer, akCString: s.write($a.getPointer.ptrToInt)
+  of akString:
+    var x = getString(a)
+    if isNil(x): s.write("null")
+    else: s.write(escapeJson(x))
+  of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a))
+  of akFloat..akFloat128: s.write($getBiggestFloat(a))
+
+proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
+  case a.kind
+  of akNone: assert false
+  of akBool:
+    case p.kind
+    of jsonFalse: setBiggestInt(a, 0)
+    of jsonTrue: setBiggestInt(a, 1)
+    else: raiseParseErr(p, "'true' or 'false' expected for a bool")
+    next(p)
+  of akChar:
+    if p.kind == jsonString:
+      var x = p.str
+      if x.len == 1:
+        setBiggestInt(a, ord(x[0]))
+        next(p)
+        return
+    elif p.kind == jsonInt:
+      setBiggestInt(a, getInt(p))
+      next(p)
+      return
+    raiseParseErr(p, "string of length 1 expected for a char")
+  of akEnum:
+    if p.kind == jsonString:
+      setBiggestInt(a, getEnumOrdinal(a, p.str))
+      next(p)
+      return
+    raiseParseErr(p, "string expected for an enum")
+  of akArray:
+    if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array")
+    next(p)
+    var i = 0
+    while p.kind != jsonArrayEnd and p.kind != jsonEof:
+      loadAny(p, a[i], t)
+      inc(i)
+    if p.kind == jsonArrayEnd: next(p)
+    else: raiseParseErr(p, "']' end of array expected")
+  of akSequence:
+    case p.kind
+    of jsonNull:
+      setPointer(a, nil)
+      next(p)
+    of jsonArrayStart:
+      next(p)
+      invokeNewSeq(a, 0)
+      var i = 0
+      while p.kind != jsonArrayEnd and p.kind != jsonEof:
+        extendSeq(a)
+        loadAny(p, a[i], t)
+        inc(i)
+      if p.kind == jsonArrayEnd: next(p)
+      else: raiseParseErr(p, "")
+    else:
+      raiseParseErr(p, "'[' expected for a seq")
+  of akObject, akTuple:
+    if a.kind == akObject: setObjectRuntimeType(a)
+    if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
+    next(p)
+    while p.kind != jsonObjectEnd and p.kind != jsonEof:
+      if p.kind != jsonString:
+        raiseParseErr(p, "string expected for a field name")
+      var fieldName = p.str
+      next(p)
+      loadAny(p, a[fieldName], t)
+    if p.kind == jsonObjectEnd: next(p)
+    else: raiseParseErr(p, "'}' end of object expected")
+  of akSet:
+    if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set")
+    next(p)
+    while p.kind != jsonArrayEnd and p.kind != jsonEof:
+      if p.kind != jsonInt: raiseParseErr(p, "int expected for a set")
+      inclSetElement(a, p.getInt.int)
+      next(p)
+    if p.kind == jsonArrayEnd: next(p)
+    else: raiseParseErr(p, "']' end of array expected")
+  of akPtr, akRef:
+    case p.kind
+    of jsonNull:
+      setPointer(a, nil)
+      next(p)
+    of jsonInt:
+      setPointer(a, t[p.getInt])
+      next(p)
+    of jsonArrayStart:
+      next(p)
+      if a.kind == akRef: invokeNew(a)
+      else: setPointer(a, alloc0(a.baseTypeSize))
+      if p.kind == jsonInt:
+        t[p.getInt] = getPointer(a)
+        next(p)
+      else: raiseParseErr(p, "index for ref type expected")
+      loadAny(p, a[], t)
+      if p.kind == jsonArrayEnd: next(p)
+      else: raiseParseErr(p, "']' end of ref-address pair expected")
+    else: raiseParseErr(p, "int for pointer type expected")
+  of akProc, akPointer, akCString:
+    case p.kind
+    of jsonNull:
+      setPointer(a, nil)
+      next(p)
+    of jsonInt:
+      setPointer(a, cast[pointer](p.getInt.int))
+      next(p)
+    else: raiseParseErr(p, "int for pointer type expected")
+  of akString:
+    case p.kind
+    of jsonNull:
+      setPointer(a, nil)
+      next(p)
+    of jsonString:
+      setString(a, p.str)
+      next(p)
+    else: raiseParseErr(p, "string expected")
+  of akInt..akInt64, akUInt..akUInt64:
+    if p.kind == jsonInt:
+      setBiggestInt(a, getInt(p))
+      next(p)
+      return
+    raiseParseErr(p, "int expected")
+  of akFloat..akFloat128:
+    if p.kind == jsonFloat:
+      setBiggestFloat(a, getFloat(p))
+      next(p)
+      return
+    raiseParseErr(p, "float expected")
+  of akRange: loadAny(p, a.skipRange, t)
+
+proc loadAny(s: Stream, a: TAny, t: var Table[BiggestInt, pointer]) =
+  var p: JsonParser
+  open(p, s, "unknown file")
+  next(p)
+  loadAny(p, a, t)
+  close(p)
+
+proc load*[T](s: Stream, data: var T) =
+  ## loads `data` from the stream `s`. Raises `EIO` in case of an error.
+  var tab = initTable[BiggestInt, pointer]()
+  loadAny(s, toAny(data), tab)
+
+proc store*[T](s: Stream, data: T) =
+  ## stores `data` into the stream `s`. Raises `EIO` in case of an error.
+  var stored = initIntSet()
+  var d: T
+  shallowCopy(d, data)
+  storeAny(s, toAny(d), stored)
+
+proc `$$`*[T](x: T): string =
+  ## returns a string representation of `x`.
+  var stored = initIntSet()
+  var d: T
+  shallowCopy(d, x)
+  var s = newStringStream()
+  storeAny(s, toAny(d), stored)
+  result = s.data
+
+proc to*[T](data: string): T =
+  ## reads data and transforms it to a ``T``.
+  var tab = initTable[BiggestInt, pointer]()
+  loadAny(newStringStream(data), toAny(result), tab)
+
+when not defined(testing) and isMainModule:
+  template testit(x: expr) = echo($$to[type(x)]($$x))
+
+  var x: array[0..4, array[0..4, string]] = [
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"]]
+  testit(x)
+  var test2: tuple[name: string, s: uint] = ("tuple test", 56u)
+  testit(test2)
+
+  type
+    TE = enum
+      blah, blah2
+
+    TestObj = object
+      test, asd: int
+      case test2: TE
+      of blah:
+        help: string
+      else:
+        nil
+
+    PNode = ref TNode
+    TNode = object
+      next, prev: PNode
+      data: string
+
+  proc buildList(): PNode =
+    new(result)
+    new(result.next)
+    new(result.prev)
+    result.data = "middle"
+    result.next.data = "next"
+    result.prev.data = "prev"
+    result.next.next = result.prev
+    result.next.prev = result
+    result.prev.next = result
+    result.prev.prev = result.next
+
+  var test3: TestObj
+  test3.test = 42
+  test3.test2 = blah
+  testit(test3)
+
+  var test4: ref tuple[a, b: string]
+  new(test4)
+  test4.a = "ref string test: A"
+  test4.b = "ref string test: B"
+  testit(test4)
+
+  var test5 = @[(0,1),(2,3),(4,5)]
+  testit(test5)
+
+  var test6: set[char] = {'A'..'Z', '_'}
+  testit(test6)
+
+  var test7 = buildList()
+  echo($$test7)
+  testit(test7)
+
+  type
+    TA {.inheritable.} = object
+    TB = object of TA
+      f: int
+
+  var
+    a: ref TA
+    b: ref TB
+  new(b)
+  a = b
+  echo($$a[]) # produces "{}", not "{f: 0}"
+
diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim
new file mode 100644
index 000000000..d55963c15
--- /dev/null
+++ b/lib/pure/matchers.nim
@@ -0,0 +1,64 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains various string matchers for email addresses, etc.
+{.deadCodeElim: on.}
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+include "system/inclrtl"
+
+import parseutils, strutils
+
+proc validEmailAddress*(s: string): bool {.noSideEffect,
+  rtl, extern: "nsuValidEmailAddress".} = 
+  ## returns true if `s` seems to be a valid e-mail address. 
+  ## The checking also uses a domain list.
+  const
+    chars = Letters + Digits + {'!','#','$','%','&',
+      '\'','*','+','/','=','?','^','_','`','{','}','|','~','-','.'}
+  var i = 0
+  if s[i] notin chars or s[i] == '.': return false
+  while s[i] in chars: 
+    if s[i] == '.' and s[i+1] == '.': return false
+    inc(i)
+  if s[i] != '@': return false
+  var j = len(s)-1
+  if s[j] notin Letters: return false
+  while j >= i and s[j] in Letters: dec(j)
+  inc(i) # skip '@'
+  while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i) 
+  if s[i] != '\0': return false
+  
+  var x = substr(s, j+1)
+  if len(x) == 2 and x[0] in Letters and x[1] in Letters: return true
+  case toLower(x)
+  of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name",
+     "aero", "jobs", "museum": return true
+  else: return false
+
+proc parseInt*(s: string, value: var int, validRange: Slice[int]) {.
+  noSideEffect, rtl, extern: "nmatchParseInt".} =
+  ## parses `s` into an integer in the range `validRange`. If successful,
+  ## `value` is modified to contain the result. Otherwise no exception is
+  ## raised and `value` is not touched; this way a reasonable default value
+  ## won't be overwritten.
+  var x = value
+  try:
+    discard parseutils.parseInt(s, x, 0)
+  except OverflowError:
+    discard
+  if x in validRange: value = x
+
+when isMainModule:
+  doAssert "wuseldusel@codehome.com".validEmailAddress
+  
+{.pop.}
+
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
new file mode 100644
index 000000000..a9e9010f6
--- /dev/null
+++ b/lib/pure/math.nim
@@ -0,0 +1,389 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+##   Constructive mathematics is naturally typed. -- Simon Thompson
+## 
+## Basic math routines for Nim.
+## This module is available for the `JavaScript target
+## <backends.html#the-javascript-target>`_.
+
+include "system/inclrtl"
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+{.push checks:off, line_dir:off, stack_trace:off.}
+
+when defined(Posix) and not defined(haiku):
+  {.passl: "-lm".}
+when not defined(js):
+  import times
+
+const
+  PI* = 3.1415926535897932384626433 ## the circle constant PI (Ludolph's number)
+  E* = 2.71828182845904523536028747 ## Euler's number
+
+  MaxFloat64Precision* = 16 ## maximum number of meaningful digits
+                            ## after the decimal point for Nim's
+                            ## ``float64`` type.
+  MaxFloat32Precision* = 8  ## maximum number of meaningful digits
+                            ## after the decimal point for Nim's
+                            ## ``float32`` type.
+  MaxFloatPrecision* = MaxFloat64Precision ## maximum number of 
+                                           ## meaningful digits
+                                           ## after the decimal point 
+                                           ## for Nim's ``float`` type.
+
+type
+  FloatClass* = enum ## describes the class a floating point value belongs to.
+                     ## This is the type that is returned by `classify`.
+    fcNormal,    ## value is an ordinary nonzero floating point value
+    fcSubnormal, ## value is a subnormal (a very small) floating point value
+    fcZero,      ## value is zero
+    fcNegZero,   ## value is the negative zero
+    fcNan,       ## value is Not-A-Number (NAN)
+    fcInf,       ## value is positive infinity
+    fcNegInf     ## value is negative infinity
+
+proc classify*(x: float): FloatClass = 
+  ## classifies a floating point value. Returns `x`'s class as specified by
+  ## `FloatClass`.
+  
+  # JavaScript and most C compilers have no classify:
+  if x == 0.0:
+    if 1.0/x == Inf:
+      return fcZero
+    else:
+      return fcNegZero
+  if x*0.5 == x:
+    if x > 0.0: return fcInf
+    else: return fcNegInf
+  if x != x: return fcNan
+  return fcNormal
+  # XXX: fcSubnormal is not detected!
+
+
+proc binom*(n, k: int): int {.noSideEffect.} = 
+  ## computes the binomial coefficient
+  if k <= 0: return 1
+  if 2*k > n: return binom(n, n-k)
+  result = n
+  for i in countup(2, k):
+    result = (result * (n + 1 - i)) div i
+    
+proc fac*(n: int): int {.noSideEffect.} = 
+  ## computes the faculty/factorial function.
+  result = 1
+  for i in countup(2, n):
+    result = result * i
+
+proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
+  ## returns true, if `x` is a power of two, false otherwise.
+  ## Zero and negative numbers are not a power of two.
+  return (x > 0) and ((x and (x - 1)) == 0)
+
+proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
+  ## returns `x` rounded up to the nearest power of two.
+  ## Zero and negative numbers get rounded up to 1.
+  result = x - 1 
+  when defined(cpu64):
+    result = result or (result shr 32)
+  when sizeof(int) > 2:
+    result = result or (result shr 16)
+  when sizeof(int) > 1:
+    result = result or (result shr 8)
+  result = result or (result shr 4)
+  result = result or (result shr 2)
+  result = result or (result shr 1)
+  result += 1 + ord(x<=0)
+
+proc countBits32*(n: int32): int {.noSideEffect.} =
+  ## counts the set bits in `n`.
+  var v = n
+  v = v -% ((v shr 1'i32) and 0x55555555'i32)
+  v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32)
+  result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32
+
+proc sum*[T](x: openArray[T]): T {.noSideEffect.} = 
+  ## computes the sum of the elements in `x`. 
+  ## If `x` is empty, 0 is returned.
+  for i in items(x): result = result + i
+
+template toFloat(f: float): float = f
+
+proc mean*[T](x: openArray[T]): float {.noSideEffect.} =
+  ## computes the mean of the elements in `x`, which are first converted to floats.
+  ## If `x` is empty, NaN is returned.
+  ## ``toFloat(x: T): float`` must be defined.
+  for i in items(x): result = result + toFloat(i)
+  result = result / toFloat(len(x))
+
+proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
+  ## computes the variance of the elements in `x`. 
+  ## If `x` is empty, NaN is returned.
+  ## ``toFloat(x: T): float`` must be defined.
+  result = 0.0
+  var m = mean(x)
+  for i in items(x):
+    var diff = toFloat(i) - m
+    result = result + diff*diff
+  result = result / toFloat(len(x))
+
+proc random*(max: int): int {.benign.}
+  ## returns a random number in the range 0..max-1. The sequence of
+  ## random number is always the same, unless `randomize` is called
+  ## which initializes the random number generator with a "random"
+  ## number, i.e. a tickcount.
+
+proc random*(max: float): float {.benign.}
+  ## returns a random number in the range 0..<max. The sequence of
+  ## random number is always the same, unless `randomize` is called
+  ## which initializes the random number generator with a "random"
+  ## number, i.e. a tickcount. This has a 16-bit resolution on windows
+  ## and a 48-bit resolution on other platforms.
+
+proc randomize*() {.benign.}
+  ## initializes the random number generator with a "random"
+  ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target,
+  ## as JavaScript does not support this.
+  
+proc randomize*(seed: int) {.benign.}
+  ## initializes the random number generator with a specific seed.
+  ## Note: Does nothing for the JavaScript target,
+  ## as JavaScript does not support this.
+
+{.push noSideEffect.}
+when not defined(JS):
+  proc sqrt*(x: float): float {.importc: "sqrt", header: "<math.h>".}
+    ## computes the square root of `x`.
+  
+  proc ln*(x: float): float {.importc: "log", header: "<math.h>".}
+    ## computes ln(x).
+  proc log10*(x: float): float {.importc: "log10", header: "<math.h>".}
+  proc log2*(x: float): float = return ln(x) / ln(2.0)
+  proc exp*(x: float): float {.importc: "exp", header: "<math.h>".}
+    ## computes e**x.
+  
+  proc frexp*(x: float, exponent: var int): float {.
+    importc: "frexp", header: "<math.h>".}
+    ## Split a number into mantissa and exponent.
+    ## `frexp` calculates the mantissa m (a float greater than or equal to 0.5
+    ## and less than 1) and the integer value n such that `x` (the original
+    ## float value) equals m * 2**n. frexp stores n in `exponent` and returns
+    ## m.
+  
+  proc round*(x: float): int {.importc: "lrint", header: "<math.h>".}
+    ## converts a float to an int by rounding.  
+  
+  proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
+  proc arcsin*(x: float): float {.importc: "asin", header: "<math.h>".}
+  proc arctan*(x: float): float {.importc: "atan", header: "<math.h>".}
+  proc arctan2*(y, x: float): float {.importc: "atan2", header: "<math.h>".}
+    ## Calculate the arc tangent of `y` / `x`.
+    ## `atan2` returns the arc tangent of `y` / `x`; it produces correct
+    ## results even when the resulting angle is near pi/2 or -pi/2
+    ## (`x` near 0).
+  
+  proc cos*(x: float): float {.importc: "cos", header: "<math.h>".}
+  proc cosh*(x: float): float {.importc: "cosh", header: "<math.h>".}
+  proc hypot*(x, y: float): float {.importc: "hypot", header: "<math.h>".}
+    ## same as ``sqrt(x*x + y*y)``.
+  
+  proc sinh*(x: float): float {.importc: "sinh", header: "<math.h>".}
+  proc sin*(x: float): float {.importc: "sin", header: "<math.h>".}
+  proc tan*(x: float): float {.importc: "tan", header: "<math.h>".}
+  proc tanh*(x: float): float {.importc: "tanh", header: "<math.h>".}
+  proc pow*(x, y: float): float {.importc: "pow", header: "<math.h>".}
+    ## computes x to power raised of y.
+    
+  # C procs:
+  proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".}
+  proc rand(): cint {.importc: "rand", header: "<stdlib.h>".}
+  
+  when not defined(windows):
+    proc srand48(seed: clong) {.importc: "srand48", header: "<stdlib.h>".}
+    proc drand48(): float {.importc: "drand48", header: "<stdlib.h>".}
+    proc random(max: float): float =
+      result = drand48() * max
+  when defined(windows):
+    proc random(max: float): float =
+      # we are hardcodeing this because
+      # importcing macros is extremely problematic
+      # and because the value is publicly documented
+      # on MSDN and very unlikely to change
+      const rand_max = 32767
+      result = (float(rand()) / float(rand_max)) * max
+  proc randomize() =
+    randomize(cast[int](epochTime()))
+
+  proc randomize(seed: int) =
+    srand(cint(seed))
+    when declared(srand48): srand48(seed)
+  proc random(max: int): int =
+    result = int(rand()) mod max
+
+  proc trunc*(x: float): float {.importc: "trunc", header: "<math.h>".}
+  proc floor*(x: float): float {.importc: "floor", header: "<math.h>".}
+  proc ceil*(x: float): float {.importc: "ceil", header: "<math.h>".}
+
+  proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".}
+
+else:
+  proc mathrandom(): float {.importc: "Math.random", nodecl.}
+  proc floor*(x: float): float {.importc: "Math.floor", nodecl.}
+  proc ceil*(x: float): float {.importc: "Math.ceil", nodecl.}
+  proc random(max: int): int =
+    result = int(floor(mathrandom() * float(max)))
+  proc random(max: float): float =
+    result = float(mathrandom() * float(max))
+  proc randomize() = discard
+  proc randomize(seed: int) = discard
+  
+  proc sqrt*(x: float): float {.importc: "Math.sqrt", nodecl.}
+  proc ln*(x: float): float {.importc: "Math.log", nodecl.}
+  proc log10*(x: float): float = return ln(x) / ln(10.0)
+  proc log2*(x: float): float = return ln(x) / ln(2.0)
+
+  proc exp*(x: float): float {.importc: "Math.exp", nodecl.}
+  proc round*(x: float): int {.importc: "Math.round", nodecl.}
+  proc pow*(x, y: float): float {.importc: "Math.pow", nodecl.}
+  
+  proc frexp*(x: float, exponent: var int): float =
+    if x == 0.0:
+      exponent = 0
+      result = 0.0
+    elif x < 0.0:
+      result = -frexp(-x, exponent)
+    else:
+      var ex = floor(log2(x))
+      exponent = round(ex)
+      result = x / pow(2.0, ex)
+
+  proc arccos*(x: float): float {.importc: "Math.acos", nodecl.}
+  proc arcsin*(x: float): float {.importc: "Math.asin", nodecl.}
+  proc arctan*(x: float): float {.importc: "Math.atan", nodecl.}
+  proc arctan2*(y, x: float): float {.importc: "Math.atan2", nodecl.}
+  
+  proc cos*(x: float): float {.importc: "Math.cos", nodecl.}
+  proc cosh*(x: float): float = return (exp(x)+exp(-x))*0.5
+  proc hypot*(x, y: float): float = return sqrt(x*x + y*y)
+  proc sinh*(x: float): float = return (exp(x)-exp(-x))*0.5
+  proc sin*(x: float): float {.importc: "Math.sin", nodecl.}
+  proc tan*(x: float): float {.importc: "Math.tan", nodecl.}
+  proc tanh*(x: float): float =
+    var y = exp(2.0*x)
+    return (y-1.0)/(y+1.0)
+
+{.pop.}
+
+proc `mod`*(x, y: float): float =
+  result = if y == 0.0: x else: x - y * (x/y).floor
+
+proc random*[T](x: Slice[T]): T =
+  ## For a slice `a .. b` returns a value in the range `a .. b-1`.
+  result = random(x.b - x.a) + x.a
+
+proc random*[T](a: openArray[T]): T =
+  ## returns a random element from the openarray `a`.
+  result = a[random(a.low..a.len)]
+
+type
+  RunningStat* = object                 ## an accumulator for statistical data
+    n*: int                             ## number of pushed data
+    sum*, min*, max*, mean*: float      ## self-explaining
+    oldM, oldS, newS: float
+
+{.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].}
+
+proc push*(s: var RunningStat, x: float) = 
+  ## pushes a value `x` for processing
+  inc(s.n)
+  # See Knuth TAOCP vol 2, 3rd edition, page 232
+  if s.n == 1:
+    s.min = x
+    s.max = x
+    s.oldM = x
+    s.mean = x
+    s.oldS = 0.0
+  else:
+    if s.min > x: s.min = x
+    if s.max < x: s.max = x
+    s.mean = s.oldM + (x - s.oldM)/toFloat(s.n)
+    s.newS = s.oldS + (x - s.oldM)*(x - s.mean)
+
+    # set up for next iteration:
+    s.oldM = s.mean
+    s.oldS = s.newS
+  s.sum = s.sum + x
+  
+proc push*(s: var RunningStat, x: int) = 
+  ## pushes a value `x` for processing. `x` is simply converted to ``float``
+  ## and the other push operation is called.
+  push(s, toFloat(x))
+  
+proc variance*(s: RunningStat): float = 
+  ## computes the current variance of `s`
+  if s.n > 1: result = s.newS / (toFloat(s.n - 1))
+
+proc standardDeviation*(s: RunningStat): float = 
+  ## computes the current standard deviation of `s`
+  result = sqrt(variance(s))
+
+{.pop.}
+{.pop.}
+
+proc `^`*[T](x, y: T): T =
+  ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use
+  ## `pow <#pow,float,float>` for negative exponents.
+  assert y >= 0
+  var (x, y) = (x, y)
+  result = 1
+
+  while y != 0:
+    if (y and 1) != 0:
+      result *= x
+    y = y shr 1
+    x *= x
+
+proc gcd*[T](x, y: T): T =
+  ## Computes the greatest common divisor of ``x`` and ``y``.
+  ## Note that for floats, the result cannot always be interpreted as
+  ## "greatest decimal `z` such that ``z*N == x and z*M == y``
+  ## where N and M are positive integers."
+  var (x,y) = (x,y)
+  while y != 0:
+    x = x mod y
+    swap x, y
+  abs x
+
+proc lcm*[T](x, y: T): T =
+  ## Computes the least common multiple of ``x`` and ``y``.
+  x div gcd(x, y) * y
+
+when isMainModule and not defined(JS):
+  proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
+
+  # Verifies random seed initialization.
+  let seed = gettime(nil)
+  randomize(seed)
+  const SIZE = 10
+  var buf : array[0..SIZE, int]
+  # Fill the buffer with random values
+  for i in 0..SIZE-1:
+    buf[i] = random(high(int))
+  # Check that the second random calls are the same for each position.
+  randomize(seed)
+  for i in 0..SIZE-1:
+    assert buf[i] == random(high(int)), "non deterministic random seeding"
+
+  when not defined(testing):
+    echo "random values equal after reseeding"
+
+  # Check for no side effect annotation
+  proc mySqrt(num: float): float {.noSideEffect.} =
+    return sqrt(num)
diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim
new file mode 100644
index 000000000..5ee301b15
--- /dev/null
+++ b/lib/pure/md5.nim
@@ -0,0 +1,245 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Module for computing MD5 checksums.
+
+import unsigned
+
+type
+  MD5State = array[0..3, uint32]
+  MD5Block = array[0..15, uint32]
+  MD5CBits = array[0..7, uint8]
+  MD5Digest* = array[0..15, uint8]
+  MD5Buffer = array[0..63, uint8]
+  MD5Context* {.final.} = object
+    state: MD5State
+    count: array[0..1, uint32]
+    buffer: MD5Buffer
+
+const
+  padding: cstring = "\x80\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0\0\0\0\0" &
+                     "\0\0\0\0"
+
+proc F(x, y, z: uint32): uint32 {.inline.} =
+  result = (x and y) or ((not x) and z)
+
+proc G(x, y, z: uint32): uint32 {.inline.} =
+  result = (x and z) or (y and (not z))
+
+proc H(x, y, z: uint32): uint32 {.inline.} =
+  result = x xor y xor z
+
+proc I(x, y, z: uint32): uint32 {.inline.} =
+  result = y xor (x or (not z))
+
+proc rot(x: var uint32, n: uint8) {.inline.} =
+  x = (x shl n) or (x shr (32'u32 - n))
+
+proc FF(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + F(b, c, d) + x + ac
+  rot(a, s)
+  a = a + b
+
+proc GG(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + G(b, c, d) + x + ac
+  rot(a, s)
+  a = a + b
+
+proc HH(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + H(b, c, d) + x + ac
+  rot(a, s)
+  a = a + b
+
+proc II(a: var uint32, b, c, d, x: uint32, s: uint8, ac: uint32) =
+  a = a + I(b, c, d) + x + ac
+  rot(a, s)
+  a = a + b
+
+proc encode(dest: var MD5Block, src: cstring) =
+  var j = 0
+  for i in 0..high(dest):
+    dest[i] = uint32(ord(src[j])) or
+              uint32(ord(src[j+1])) shl 8 or
+              uint32(ord(src[j+2])) shl 16 or
+              uint32(ord(src[j+3])) shl 24
+    inc(j, 4)
+
+proc decode(dest: var openArray[uint8], src: openArray[uint32]) =
+  var i = 0
+  for j in 0..high(src):
+    dest[i] = src[j] and 0xff'u32
+    dest[i+1] = src[j] shr 8 and 0xff'u32
+    dest[i+2] = src[j] shr 16 and 0xff'u32
+    dest[i+3] = src[j] shr 24 and 0xff'u32
+    inc(i, 4)
+
+proc transform(buffer: pointer, state: var MD5State) =
+  var
+    myBlock: MD5Block
+  encode(myBlock, cast[cstring](buffer))
+  var a = state[0]
+  var b = state[1]
+  var c = state[2]
+  var d = state[3]
+  FF(a, b, c, d, myBlock[0], 7'u8, 0xD76AA478'u32)
+  FF(d, a, b, c, myBlock[1], 12'u8, 0xE8C7B756'u32)
+  FF(c, d, a, b, myBlock[2], 17'u8, 0x242070DB'u32)
+  FF(b, c, d, a, myBlock[3], 22'u8, 0xC1BDCEEE'u32)
+  FF(a, b, c, d, myBlock[4], 7'u8, 0xF57C0FAF'u32)
+  FF(d, a, b, c, myBlock[5], 12'u8, 0x4787C62A'u32)
+  FF(c, d, a, b, myBlock[6], 17'u8, 0xA8304613'u32)
+  FF(b, c, d, a, myBlock[7], 22'u8, 0xFD469501'u32)
+  FF(a, b, c, d, myBlock[8], 7'u8, 0x698098D8'u32)
+  FF(d, a, b, c, myBlock[9], 12'u8, 0x8B44F7AF'u32)
+  FF(c, d, a, b, myBlock[10], 17'u8, 0xFFFF5BB1'u32)
+  FF(b, c, d, a, myBlock[11], 22'u8, 0x895CD7BE'u32)
+  FF(a, b, c, d, myBlock[12], 7'u8, 0x6B901122'u32)
+  FF(d, a, b, c, myBlock[13], 12'u8, 0xFD987193'u32)
+  FF(c, d, a, b, myBlock[14], 17'u8, 0xA679438E'u32)
+  FF(b, c, d, a, myBlock[15], 22'u8, 0x49B40821'u32)
+  GG(a, b, c, d, myBlock[1], 5'u8, 0xF61E2562'u32)
+  GG(d, a, b, c, myBlock[6], 9'u8, 0xC040B340'u32)
+  GG(c, d, a, b, myBlock[11], 14'u8, 0x265E5A51'u32)
+  GG(b, c, d, a, myBlock[0], 20'u8, 0xE9B6C7AA'u32)
+  GG(a, b, c, d, myBlock[5], 5'u8, 0xD62F105D'u32)
+  GG(d, a, b, c, myBlock[10], 9'u8, 0x02441453'u32)
+  GG(c, d, a, b, myBlock[15], 14'u8, 0xD8A1E681'u32)
+  GG(b, c, d, a, myBlock[4], 20'u8, 0xE7D3FBC8'u32)
+  GG(a, b, c, d, myBlock[9], 5'u8, 0x21E1CDE6'u32)
+  GG(d, a, b, c, myBlock[14], 9'u8, 0xC33707D6'u32)
+  GG(c, d, a, b, myBlock[3], 14'u8, 0xF4D50D87'u32)
+  GG(b, c, d, a, myBlock[8], 20'u8, 0x455A14ED'u32)
+  GG(a, b, c, d, myBlock[13], 5'u8, 0xA9E3E905'u32)
+  GG(d, a, b, c, myBlock[2], 9'u8, 0xFCEFA3F8'u32)
+  GG(c, d, a, b, myBlock[7], 14'u8, 0x676F02D9'u32)
+  GG(b, c, d, a, myBlock[12], 20'u8, 0x8D2A4C8A'u32)
+  HH(a, b, c, d, myBlock[5], 4'u8, 0xFFFA3942'u32)
+  HH(d, a, b, c, myBlock[8], 11'u8, 0x8771F681'u32)
+  HH(c, d, a, b, myBlock[11], 16'u8, 0x6D9D6122'u32)
+  HH(b, c, d, a, myBlock[14], 23'u8, 0xFDE5380C'u32)
+  HH(a, b, c, d, myBlock[1], 4'u8, 0xA4BEEA44'u32)
+  HH(d, a, b, c, myBlock[4], 11'u8, 0x4BDECFA9'u32)
+  HH(c, d, a, b, myBlock[7], 16'u8, 0xF6BB4B60'u32)
+  HH(b, c, d, a, myBlock[10], 23'u8, 0xBEBFBC70'u32)
+  HH(a, b, c, d, myBlock[13], 4'u8, 0x289B7EC6'u32)
+  HH(d, a, b, c, myBlock[0], 11'u8, 0xEAA127FA'u32)
+  HH(c, d, a, b, myBlock[3], 16'u8, 0xD4EF3085'u32)
+  HH(b, c, d, a, myBlock[6], 23'u8, 0x04881D05'u32)
+  HH(a, b, c, d, myBlock[9], 4'u8, 0xD9D4D039'u32)
+  HH(d, a, b, c, myBlock[12], 11'u8, 0xE6DB99E5'u32)
+  HH(c, d, a, b, myBlock[15], 16'u8, 0x1FA27CF8'u32)
+  HH(b, c, d, a, myBlock[2], 23'u8, 0xC4AC5665'u32)
+  II(a, b, c, d, myBlock[0], 6'u8, 0xF4292244'u32)
+  II(d, a, b, c, myBlock[7], 10'u8, 0x432AFF97'u32)
+  II(c, d, a, b, myBlock[14], 15'u8, 0xAB9423A7'u32)
+  II(b, c, d, a, myBlock[5], 21'u8, 0xFC93A039'u32)
+  II(a, b, c, d, myBlock[12], 6'u8, 0x655B59C3'u32)
+  II(d, a, b, c, myBlock[3], 10'u8, 0x8F0CCC92'u32)
+  II(c, d, a, b, myBlock[10], 15'u8, 0xFFEFF47D'u32)
+  II(b, c, d, a, myBlock[1], 21'u8, 0x85845DD1'u32)
+  II(a, b, c, d, myBlock[8], 6'u8, 0x6FA87E4F'u32)
+  II(d, a, b, c, myBlock[15], 10'u8, 0xFE2CE6E0'u32)
+  II(c, d, a, b, myBlock[6], 15'u8, 0xA3014314'u32)
+  II(b, c, d, a, myBlock[13], 21'u8, 0x4E0811A1'u32)
+  II(a, b, c, d, myBlock[4], 6'u8, 0xF7537E82'u32)
+  II(d, a, b, c, myBlock[11], 10'u8, 0xBD3AF235'u32)
+  II(c, d, a, b, myBlock[2], 15'u8, 0x2AD7D2BB'u32)
+  II(b, c, d, a, myBlock[9], 21'u8, 0xEB86D391'u32)
+  state[0] = state[0] + a
+  state[1] = state[1] + b
+  state[2] = state[2] + c
+  state[3] = state[3] + d
+
+proc md5Init*(c: var MD5Context) =
+  ## initializes a MD5Context
+  c.state[0] = 0x67452301'u32
+  c.state[1] = 0xEFCDAB89'u32
+  c.state[2] = 0x98BADCFE'u32
+  c.state[3] = 0x10325476'u32
+  c.count[0] = 0'u32
+  c.count[1] = 0'u32
+  zeroMem(addr(c.buffer), sizeof(MD5buffer))
+
+proc md5Update*(c: var MD5Context, input: cstring, len: int) =
+  ## updates the MD5Context with the `input` data of length `len`
+  var input = input
+  var Index = int((c.count[0] shr 3) and 0x3F)
+  c.count[0] = c.count[0] + (uint32(len) shl 3)
+  if c.count[0] < (uint32(len) shl 3): c.count[1] = c.count[1] + 1'u32
+  c.count[1] = c.count[1] + (uint32(len) shr 29)
+  var PartLen = 64 - Index
+  if len >= PartLen:
+    copyMem(addr(c.buffer[Index]), input, PartLen)
+    transform(addr(c.buffer), c.state)
+    var i = PartLen
+    while i + 63 < len:
+      transform(addr(input[i]), c.state)
+      inc(i, 64)
+    copyMem(addr(c.buffer[0]), addr(input[i]), len-i)
+  else:
+    copyMem(addr(c.buffer[Index]), addr(input[0]), len)
+
+proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
+  ## finishes the MD5Context and stores the result in `digest`
+  var
+    Bits: MD5CBits
+    PadLen: int
+  decode(Bits, c.count)
+  var Index = int((c.count[0] shr 3) and 0x3F)
+  if Index < 56: PadLen = 56 - Index
+  else: PadLen = 120 - Index
+  md5Update(c, padding, PadLen)
+  md5Update(c, cast[cstring](addr(Bits)), 8)
+  decode(digest, c.state)
+  zeroMem(addr(c), sizeof(MD5Context))
+
+proc toMD5*(s: string): MD5Digest =
+  ## computes the MD5Digest value for a string `s`
+  var c: MD5Context
+  md5Init(c)
+  md5Update(c, cstring(s), len(s))
+  md5Final(c, result)
+
+proc `$`*(d: MD5Digest): string =
+  ## converts a MD5Digest value into its string representation
+  const digits = "0123456789abcdef"
+  result = ""
+  for i in 0..15:
+    add(result, digits[(d[i] shr 4) and 0xF])
+    add(result, digits[d[i] and 0xF])
+
+proc getMD5*(s: string): string =
+  ## computes an MD5 value of `s` and returns its string representation
+  var
+    c: MD5Context
+    d: MD5Digest
+  md5Init(c)
+  md5Update(c, cstring(s), len(s))
+  md5Final(c, d)
+  result = $d
+
+proc `==`*(D1, D2: MD5Digest): bool =
+  ## checks if two MD5Digest values are identical
+  for i in 0..15:
+    if D1[i] != D2[i]: return false
+  return true
+
+when isMainModule:
+  assert(getMD5("Franz jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
+    "a3cca2b2aa1e3b5b3b5aad99a8529074")
+  assert(getMD5("Frank jagt im komplett verwahrlosten Taxi quer durch Bayern") ==
+    "7e716d0e702df0505fc72e2b89467910")
+  assert($toMD5("") == "d41d8cd98f00b204e9800998ecf8427e")
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
new file mode 100644
index 000000000..d49dfae9f
--- /dev/null
+++ b/lib/pure/memfiles.nim
@@ -0,0 +1,247 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Nim Contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## :Authors: Zahary Karadjov, Andreas Rumpf
+##
+## This module provides support for `memory mapped files`:idx:
+## (Posix's `mmap`:idx:) on the different operating systems.
+
+when defined(windows):
+  import winlean
+elif defined(posix):
+  import posix
+else:
+  {.error: "the memfiles module is not supported on your operating system!".}
+
+import os
+
+type
+  MemFile* = object  ## represents a memory mapped file
+    mem*: pointer    ## a pointer to the memory mapped file. The pointer
+                     ## can be used directly to change the contents of the
+                     ## file, if it was opened with write access.
+    size*: int       ## size of the memory mapped file
+
+    when defined(windows):
+      fHandle: int
+      mapHandle: int 
+    else:
+      handle: cint
+
+{.deprecated: [TMemFile: MemFile].}
+
+proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
+             mappedSize = -1, offset = 0): pointer =
+  var readonly = mode == fmRead
+  when defined(windows):
+    result = mapViewOfFileEx(
+      m.mapHandle,
+      if readonly: FILE_MAP_READ else: FILE_MAP_WRITE,
+      int32(offset shr 32),
+      int32(offset and 0xffffffff),
+      if mappedSize == -1: 0 else: mappedSize,
+      nil)
+    if result == nil:
+      raiseOSError(osLastError())
+  else:
+    assert mappedSize > 0
+    result = mmap(
+      nil,
+      mappedSize,
+      if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
+      if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE),
+      m.handle, offset)
+    if result == cast[pointer](MAP_FAILED):
+      raiseOSError(osLastError())
+
+
+proc unmapMem*(f: var MemFile, p: pointer, size: int) =
+  ## unmaps the memory region ``(p, <p+size)`` of the mapped file `f`.
+  ## All changes are written back to the file system, if `f` was opened
+  ## with write access. ``size`` must be of exactly the size that was requested
+  ## via ``mapMem``.
+  when defined(windows):
+    if unmapViewOfFile(p) == 0: raiseOSError(osLastError())
+  else:
+    if munmap(p, size) != 0: raiseOSError(osLastError())
+
+
+proc open*(filename: string, mode: FileMode = fmRead,
+           mappedSize = -1, offset = 0, newFileSize = -1): MemFile =
+  ## opens a memory mapped file. If this fails, ``EOS`` is raised.
+  ## `newFileSize` can only be set if the file does not exist and is opened
+  ## with write access (e.g., with fmReadWrite). `mappedSize` and `offset`
+  ## can be used to map only a slice of the file. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var
+  ##     mm, mm_full, mm_half: MemFile
+  ##
+  ##   mm = memfiles.open("/tmp/test.mmap", mode = fmWrite, newFileSize = 1024)    # Create a new file
+  ##   mm.close()
+  ##
+  ##   # Read the whole file, would fail if newFileSize was set
+  ##   mm_full = memfiles.open("/tmp/test.mmap", mode = fmReadWrite, mappedSize = -1)
+  ##
+  ##   # Read the first 512 bytes
+  ##   mm_half = memfiles.open("/tmp/test.mmap", mode = fmReadWrite, mappedSize = 512)
+
+  # The file can be resized only when write mode is used:
+  assert newFileSize == -1 or mode != fmRead
+  var readonly = mode == fmRead
+
+  template rollback =
+    result.mem = nil
+    result.size = 0
+
+  when defined(windows):
+    template fail(errCode: OSErrorCode, msg: expr) =
+      rollback()
+      if result.fHandle != 0: discard closeHandle(result.fHandle)
+      if result.mapHandle != 0: discard closeHandle(result.mapHandle)
+      raiseOSError(errCode)
+      # return false
+      #raise newException(EIO, msg)
+
+    template callCreateFile(winApiProc, filename: expr): expr =
+      winApiProc(
+        filename,
+        if readonly: GENERIC_READ else: GENERIC_ALL,
+        FILE_SHARE_READ,
+        nil,
+        if newFileSize != -1: CREATE_ALWAYS else: OPEN_EXISTING,
+        if readonly: FILE_ATTRIBUTE_READONLY else: FILE_ATTRIBUTE_TEMPORARY,
+        0)
+
+    when useWinUnicode:
+      result.fHandle = callCreateFile(createFileW, newWideCString(filename))
+    else:
+      result.fHandle = callCreateFile(createFileA, filename)
+
+    if result.fHandle == INVALID_HANDLE_VALUE:
+      fail(osLastError(), "error opening file")
+
+    if newFileSize != -1:
+      var 
+        sizeHigh = int32(newFileSize shr 32)
+        sizeLow  = int32(newFileSize and 0xffffffff)
+
+      var status = setFilePointer(result.fHandle, sizeLow, addr(sizeHigh),
+                                  FILE_BEGIN)
+      let lastErr = osLastError()
+      if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or
+         (setEndOfFile(result.fHandle) == 0):
+        fail(lastErr, "error setting file size")
+
+    # since the strings are always 'nil', we simply always call
+    # CreateFileMappingW which should be slightly faster anyway:
+    result.mapHandle = createFileMappingW(
+      result.fHandle, nil,
+      if readonly: PAGE_READONLY else: PAGE_READWRITE,
+      0, 0, nil)
+
+    if result.mapHandle == 0:
+      fail(osLastError(), "error creating mapping")
+
+    result.mem = mapViewOfFileEx(
+      result.mapHandle,
+      if readonly: FILE_MAP_READ else: FILE_MAP_WRITE,
+      int32(offset shr 32),
+      int32(offset and 0xffffffff),
+      if mappedSize == -1: 0 else: mappedSize,
+      nil)
+
+    if result.mem == nil:
+      fail(osLastError(), "error mapping view")
+
+    var hi, low: int32
+    low = getFileSize(result.fHandle, addr(hi))
+    if low == INVALID_FILE_SIZE:
+      fail(osLastError(), "error getting file size")
+    else:
+      var fileSize = (int64(hi) shr 32) or low
+      if mappedSize != -1: result.size = min(fileSize, mappedSize).int
+      else: result.size = fileSize.int
+
+  else:
+    template fail(errCode: OSErrorCode, msg: expr) =
+      rollback()
+      if result.handle != 0: discard close(result.handle)
+      raiseOSError(errCode)
+  
+    var flags = if readonly: O_RDONLY else: O_RDWR
+
+    if newFileSize != -1:
+      flags = flags or O_CREAT or O_TRUNC
+      var permissions_mode = S_IRUSR or S_IWUSR
+      result.handle = open(filename, flags, permissions_mode)
+    else:
+      result.handle = open(filename, flags)
+
+    if result.handle == -1:
+      # XXX: errno is supposed to be set here
+      # Is there an exception that wraps it?
+      fail(osLastError(), "error opening file")
+
+    if newFileSize != -1:
+      if ftruncate(result.handle, newFileSize) == -1:
+        fail(osLastError(), "error setting file size")
+
+    if mappedSize != -1:
+      result.size = mappedSize
+    else:
+      var stat: TStat
+      if fstat(result.handle, stat) != -1:
+        # XXX: Hmm, this could be unsafe
+        # Why is mmap taking int anyway?
+        result.size = int(stat.st_size)
+      else:
+        fail(osLastError(), "error getting file size")
+
+    result.mem = mmap(
+      nil,
+      result.size,
+      if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
+      if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE),
+      result.handle,
+      offset)
+
+    if result.mem == cast[pointer](MAP_FAILED):
+      fail(osLastError(), "file mapping failed")
+
+proc close*(f: var MemFile) =
+  ## closes the memory mapped file `f`. All changes are written back to the
+  ## file system, if `f` was opened with write access.
+  
+  var error = false
+  var lastErr: OSErrorCode
+
+  when defined(windows):
+    if f.fHandle != INVALID_HANDLE_VALUE:
+      error = unmapViewOfFile(f.mem) == 0
+      lastErr = osLastError()
+      error = (closeHandle(f.mapHandle) == 0) or error
+      error = (closeHandle(f.fHandle) == 0) or error
+  else:
+    if f.handle != 0:
+      error = munmap(f.mem, f.size) != 0
+      lastErr = osLastError()
+      error = (close(f.handle) != 0) or error
+
+  f.size = 0
+  f.mem = nil
+
+  when defined(windows):
+    f.fHandle = 0
+    f.mapHandle = 0
+  else:
+    f.handle = 0
+  
+  if error: raiseOSError(lastErr)
+
diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim
new file mode 100644
index 000000000..74112e304
--- /dev/null
+++ b/lib/pure/mersenne.nim
@@ -0,0 +1,39 @@
+import unsigned
+
+type
+  MersenneTwister* = object
+    mt: array[0..623, uint32]
+    index: int
+
+{.deprecated: [TMersenneTwister: MersenneTwister].}
+
+proc newMersenneTwister*(seed: int): MersenneTwister =   
+  result.index = 0
+  result.mt[0]= uint32(seed)
+  for i in 1..623'u32:
+    result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
+
+proc generateNumbers(m: var MersenneTwister) =
+  for i in 0..623:
+    var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32)
+    m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
+    if (y mod 2'u32) != 0:
+     m.mt[i] = m.mt[i] xor 0x9908b0df'u32
+
+proc getNum*(m: var MersenneTwister): int =
+  if m.index == 0:
+    generateNumbers(m)
+  var y = m.mt[m.index]
+  y = y xor (y shr 11'u32)
+  y = y xor ((7'u32 shl y) and 0x9d2c5680'u32)
+  y = y xor ((15'u32 shl y) and 0xefc60000'u32)
+  y = y xor (y shr 18'u32)
+  m.index = (m.index+1) mod 624
+  return int(y)
+
+# Test
+when not defined(testing) and isMainModule:
+  var mt = newMersenneTwister(2525)
+
+  for i in 0..99:
+    echo mt.getNum
diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim
new file mode 100644
index 000000000..642419e64
--- /dev/null
+++ b/lib/pure/mimetypes.nim
@@ -0,0 +1,522 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a mimetypes database
+import strtabs
+type
+  MimeDB* = object
+    mimes: StringTableRef
+
+{.deprecated: [TMimeDB: MimeDB].}
+
+const mimes* = {
+    "ez": "application/andrew-inset",
+    "anx": "application/annodex",
+    "atom": "application/atom+xml",
+    "atomcat": "application/atomcat+xml",
+    "atomsrv": "application/atomserv+xml",
+    "lin": "application/bbolin",
+    "cap": "application/cap",
+    "pcap": "application/cap",
+    "cu": "application/cu-seeme",
+    "davmount": "application/davmount+xml",
+    "tsp": "application/dsptype",
+    "es": "application/ecmascript",
+    "spl": "application/futuresplash",
+    "hta": "application/hta",
+    "jar": "application/java-archive",
+    "ser": "application/java-serialized-object",
+    "class": "application/java-vm",
+    "js": "application/javascript",
+    "m3g": "application/m3g",
+    "hqx": "application/mac-binhex40",
+    "cpt": "application/mac-compactpro",
+    "nb": "application/mathematica",
+    "nbp": "application/mathematica",
+    "mdb": "application/msaccess",
+    "doc": "application/msword",
+    "dot": "application/msword",
+    "mxf": "application/mxf",
+    "bin": "application/octet-stream",
+    "oda": "application/oda",
+    "ogx": "application/ogg",
+    "pdf": "application/pdf",
+    "key": "application/pgp-keys",
+    "pgp": "application/pgp-signature",
+    "prf": "application/pics-rules",
+    "ps": "application/postscript",
+    "ai": "application/postscript",
+    "eps": "application/postscript",
+    "epsi": "application/postscript",
+    "epsf": "application/postscript",
+    "eps2": "application/postscript",
+    "eps3": "application/postscript",
+    "rar": "application/rar",
+    "rdf": "application/rdf+xml",
+    "rss": "application/rss+xml",
+    "rtf": "application/rtf",
+    "smi": "application/smil",
+    "smil": "application/smil",
+    "xhtml": "application/xhtml+xml",
+    "xht": "application/xhtml+xml",
+    "xml": "application/xml",
+    "xsl": "application/xml",
+    "xsd": "application/xml",
+    "xspf": "application/xspf+xml",
+    "zip": "application/zip",
+    "apk": "application/vnd.android.package-archive",
+    "cdy": "application/vnd.cinderella",
+    "kml": "application/vnd.google-earth.kml+xml",
+    "kmz": "application/vnd.google-earth.kmz",
+    "xul": "application/vnd.mozilla.xul+xml",
+    "xls": "application/vnd.ms-excel",
+    "xlb": "application/vnd.ms-excel",
+    "xlt": "application/vnd.ms-excel",
+    "cat": "application/vnd.ms-pki.seccat",
+    "stl": "application/vnd.ms-pki.stl",
+    "ppt": "application/vnd.ms-powerpoint",
+    "pps": "application/vnd.ms-powerpoint",
+    "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+    "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
+    "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
+    "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
+    "potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
+    "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+    "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
+    "cod": "application/vnd.rim.cod",
+    "mmf": "application/vnd.smaf",
+    "sis": "application/vnd.symbian.install",
+    "vsd": "application/vnd.visio",
+    "wbxml": "application/vnd.wap.wbxml",
+    "wmlc": "application/vnd.wap.wmlc",
+    "wmlsc": "application/vnd.wap.wmlscriptc",
+    "wpd": "application/vnd.wordperfect",
+    "wp5": "application/vnd.wordperfect5.1",
+    "wk": "application/x-123",
+    "7z": "application/x-7z-compressed",
+    "abw": "application/x-abiword",
+    "dmg": "application/x-apple-diskimage",
+    "bcpio": "application/x-bcpio",
+    "torrent": "application/x-bittorrent",
+    "cab": "application/x-cab",
+    "cbr": "application/x-cbr",
+    "cbz": "application/x-cbz",
+    "cdf": "application/x-cdf",
+    "cda": "application/x-cdf",
+    "vcd": "application/x-cdlink",
+    "pgn": "application/x-chess-pgn",
+    "cpio": "application/x-cpio",
+    "csh": "application/x-csh",
+    "deb": "application/x-debian-package",
+    "udeb": "application/x-debian-package",
+    "dcr": "application/x-director",
+    "dir": "application/x-director",
+    "dxr": "application/x-director",
+    "dms": "application/x-dms",
+    "wad": "application/x-doom",
+    "dvi": "application/x-dvi",
+    "rhtml": "application/x-httpd-eruby",
+    "pfa": "application/x-font",
+    "pfb": "application/x-font",
+    "gsf": "application/x-font",
+    "pcf": "application/x-font",
+    "pcf.Z": "application/x-font",
+    "mm": "application/x-freemind",
+    "spl": "application/x-futuresplash",
+    "gnumeric": "application/x-gnumeric",
+    "sgf": "application/x-go-sgf",
+    "gcf": "application/x-graphing-calculator",
+    "gtar": "application/x-gtar",
+    "tgz": "application/x-gtar",
+    "taz": "application/x-gtar",
+    "hdf": "application/x-hdf",
+    "phtml": "application/x-httpd-php",
+    "pht": "application/x-httpd-php",
+    "php": "application/x-httpd-php",
+    "phps": "application/x-httpd-php-source",
+    "php3": "application/x-httpd-php3",
+    "php3p": "application/x-httpd-php3-preprocessed",
+    "php4": "application/x-httpd-php4",
+    "php5": "application/x-httpd-php5",
+    "ica": "application/x-ica",
+    "info": "application/x-info",
+    "ins": "application/x-internet-signup",
+    "isp": "application/x-internet-signup",
+    "iii": "application/x-iphone",
+    "iso": "application/x-iso9660-image",
+    "jam": "application/x-jam",
+    "jnlp": "application/x-java-jnlp-file",
+    "jmz": "application/x-jmol",
+    "chrt": "application/x-kchart",
+    "kil": "application/x-killustrator",
+    "skp": "application/x-koan",
+    "skd": "application/x-koan",
+    "skt": "application/x-koan",
+    "skm": "application/x-koan",
+    "kpr": "application/x-kpresenter",
+    "kpt": "application/x-kpresenter",
+    "ksp": "application/x-kspread",
+    "kwd": "application/x-kword",
+    "kwt": "application/x-kword",
+    "latex": "application/x-latex",
+    "lha": "application/x-lha",
+    "lyx": "application/x-lyx",
+    "lzh": "application/x-lzh",
+    "lzx": "application/x-lzx",
+    "frm": "application/x-maker",
+    "maker": "application/x-maker",
+    "frame": "application/x-maker",
+    "fm": "application/x-maker",
+    "fb": "application/x-maker",
+    "book": "application/x-maker",
+    "fbdoc": "application/x-maker",
+    "mif": "application/x-mif",
+    "wmd": "application/x-ms-wmd",
+    "wmz": "application/x-ms-wmz",
+    "com": "application/x-msdos-program",
+    "exe": "application/x-msdos-program",
+    "bat": "application/x-msdos-program",
+    "dll": "application/x-msdos-program",
+    "msi": "application/x-msi",
+    "nc": "application/x-netcdf",
+    "pac": "application/x-ns-proxy-autoconfig",
+    "dat": "application/x-ns-proxy-autoconfig",
+    "nwc": "application/x-nwc",
+    "o": "application/x-object",
+    "oza": "application/x-oz-application",
+    "p7r": "application/x-pkcs7-certreqresp",
+    "crl": "application/x-pkcs7-crl",
+    "pyc": "application/x-python-code",
+    "pyo": "application/x-python-code",
+    "qgs": "application/x-qgis",
+    "shp": "application/x-qgis",
+    "shx": "application/x-qgis",
+    "qtl": "application/x-quicktimeplayer",
+    "rpm": "application/x-redhat-package-manager",
+    "rb": "application/x-ruby",
+    "sh": "application/x-sh",
+    "shar": "application/x-shar",
+    "swf": "application/x-shockwave-flash",
+    "swfl": "application/x-shockwave-flash",
+    "scr": "application/x-silverlight",
+    "sit": "application/x-stuffit",
+    "sitx": "application/x-stuffit",
+    "sv4cpio": "application/x-sv4cpio",
+    "sv4crc": "application/x-sv4crc",
+    "tar": "application/x-tar",
+    "tcl": "application/x-tcl",
+    "gf": "application/x-tex-gf",
+    "pk": "application/x-tex-pk",
+    "texinfo": "application/x-texinfo",
+    "texi": "application/x-texinfo",
+    "~": "application/x-trash",
+    "%": "application/x-trash",
+    "bak": "application/x-trash",
+    "old": "application/x-trash",
+    "sik": "application/x-trash",
+    "t": "application/x-troff",
+    "tr": "application/x-troff",
+    "roff": "application/x-troff",
+    "man": "application/x-troff-man",
+    "me": "application/x-troff-me",
+    "ms": "application/x-troff-ms",
+    "ustar": "application/x-ustar",
+    "src": "application/x-wais-source",
+    "wz": "application/x-wingz",
+    "crt": "application/x-x509-ca-cert",
+    "xcf": "application/x-xcf",
+    "fig": "application/x-xfig",
+    "xpi": "application/x-xpinstall",
+    "amr": "audio/amr",
+    "awb": "audio/amr-wb",
+    "amr": "audio/amr",
+    "awb": "audio/amr-wb",
+    "axa": "audio/annodex",
+    "au": "audio/basic",
+    "snd": "audio/basic",
+    "flac": "audio/flac",
+    "mid": "audio/midi",
+    "midi": "audio/midi",
+    "kar": "audio/midi",
+    "mpga": "audio/mpeg",
+    "mpega": "audio/mpeg",
+    "mp2": "audio/mpeg",
+    "mp3": "audio/mpeg",
+    "m4a": "audio/mpeg",
+    "m3u": "audio/mpegurl",
+    "oga": "audio/ogg",
+    "ogg": "audio/ogg",
+    "spx": "audio/ogg",
+    "sid": "audio/prs.sid",
+    "aif": "audio/x-aiff",
+    "aiff": "audio/x-aiff",
+    "aifc": "audio/x-aiff",
+    "gsm": "audio/x-gsm",
+    "m3u": "audio/x-mpegurl",
+    "wma": "audio/x-ms-wma",
+    "wax": "audio/x-ms-wax",
+    "ra": "audio/x-pn-realaudio",
+    "rm": "audio/x-pn-realaudio",
+    "ram": "audio/x-pn-realaudio",
+    "ra": "audio/x-realaudio",
+    "pls": "audio/x-scpls",
+    "sd2": "audio/x-sd2",
+    "wav": "audio/x-wav",
+    "alc": "chemical/x-alchemy",
+    "cac": "chemical/x-cache",
+    "cache": "chemical/x-cache",
+    "csf": "chemical/x-cache-csf",
+    "cbin": "chemical/x-cactvs-binary",
+    "cascii": "chemical/x-cactvs-binary",
+    "ctab": "chemical/x-cactvs-binary",
+    "cdx": "chemical/x-cdx",
+    "cer": "chemical/x-cerius",
+    "c3d": "chemical/x-chem3d",
+    "chm": "chemical/x-chemdraw",
+    "cif": "chemical/x-cif",
+    "cmdf": "chemical/x-cmdf",
+    "cml": "chemical/x-cml",
+    "cpa": "chemical/x-compass",
+    "bsd": "chemical/x-crossfire",
+    "csml": "chemical/x-csml",
+    "csm": "chemical/x-csml",
+    "ctx": "chemical/x-ctx",
+    "cxf": "chemical/x-cxf",
+    "cef": "chemical/x-cxf",
+    "smi": "#chemical/x-daylight-smiles",
+    "emb": "chemical/x-embl-dl-nucleotide",
+    "embl": "chemical/x-embl-dl-nucleotide",
+    "spc": "chemical/x-galactic-spc",
+    "inp": "chemical/x-gamess-input",
+    "gam": "chemical/x-gamess-input",
+    "gamin": "chemical/x-gamess-input",
+    "fch": "chemical/x-gaussian-checkpoint",
+    "fchk": "chemical/x-gaussian-checkpoint",
+    "cub": "chemical/x-gaussian-cube",
+    "gau": "chemical/x-gaussian-input",
+    "gjc": "chemical/x-gaussian-input",
+    "gjf": "chemical/x-gaussian-input",
+    "gal": "chemical/x-gaussian-log",
+    "gcg": "chemical/x-gcg8-sequence",
+    "gen": "chemical/x-genbank",
+    "hin": "chemical/x-hin",
+    "istr": "chemical/x-isostar",
+    "ist": "chemical/x-isostar",
+    "jdx": "chemical/x-jcamp-dx",
+    "dx": "chemical/x-jcamp-dx",
+    "kin": "chemical/x-kinemage",
+    "mcm": "chemical/x-macmolecule",
+    "mmd": "chemical/x-macromodel-input",
+    "mmod": "chemical/x-macromodel-input",
+    "mol": "chemical/x-mdl-molfile",
+    "rd": "chemical/x-mdl-rdfile",
+    "rxn": "chemical/x-mdl-rxnfile",
+    "sd": "chemical/x-mdl-sdfile",
+    "sdf": "chemical/x-mdl-sdfile",
+    "tgf": "chemical/x-mdl-tgf",
+    "mif": "#chemical/x-mif",
+    "mcif": "chemical/x-mmcif",
+    "mol2": "chemical/x-mol2",
+    "b": "chemical/x-molconn-Z",
+    "gpt": "chemical/x-mopac-graph",
+    "mop": "chemical/x-mopac-input",
+    "mopcrt": "chemical/x-mopac-input",
+    "mpc": "chemical/x-mopac-input",
+    "zmt": "chemical/x-mopac-input",
+    "moo": "chemical/x-mopac-out",
+    "mvb": "chemical/x-mopac-vib",
+    "asn": "chemical/x-ncbi-asn1",
+    "prt": "chemical/x-ncbi-asn1-ascii",
+    "ent": "chemical/x-ncbi-asn1-ascii",
+    "val": "chemical/x-ncbi-asn1-binary",
+    "aso": "chemical/x-ncbi-asn1-binary",
+    "asn": "chemical/x-ncbi-asn1-spec",
+    "pdb": "chemical/x-pdb",
+    "ent": "chemical/x-pdb",
+    "ros": "chemical/x-rosdal",
+    "sw": "chemical/x-swissprot",
+    "vms": "chemical/x-vamas-iso14976",
+    "vmd": "chemical/x-vmd",
+    "xtel": "chemical/x-xtel",
+    "xyz": "chemical/x-xyz",
+    "gif": "image/gif",
+    "ief": "image/ief",
+    "jpeg": "image/jpeg",
+    "jpg": "image/jpeg",
+    "jpe": "image/jpeg",
+    "pcx": "image/pcx",
+    "png": "image/png",
+    "svg": "image/svg+xml",
+    "svgz": "image/svg+xml",
+    "tiff": "image/tiff",
+    "tif": "image/tiff",
+    "djvu": "image/vnd.djvu",
+    "djv": "image/vnd.djvu",
+    "wbmp": "image/vnd.wap.wbmp",
+    "cr2": "image/x-canon-cr2",
+    "crw": "image/x-canon-crw",
+    "ras": "image/x-cmu-raster",
+    "cdr": "image/x-coreldraw",
+    "pat": "image/x-coreldrawpattern",
+    "cdt": "image/x-coreldrawtemplate",
+    "cpt": "image/x-corelphotopaint",
+    "erf": "image/x-epson-erf",
+    "ico": "image/x-icon",
+    "art": "image/x-jg",
+    "jng": "image/x-jng",
+    "bmp": "image/x-ms-bmp",
+    "nef": "image/x-nikon-nef",
+    "orf": "image/x-olympus-orf",
+    "psd": "image/x-photoshop",
+    "pnm": "image/x-portable-anymap",
+    "pbm": "image/x-portable-bitmap",
+    "pgm": "image/x-portable-graymap",
+    "ppm": "image/x-portable-pixmap",
+    "rgb": "image/x-rgb",
+    "xbm": "image/x-xbitmap",
+    "xpm": "image/x-xpixmap",
+    "xwd": "image/x-xwindowdump",
+    "eml": "message/rfc822",
+    "igs": "model/iges",
+    "iges": "model/iges",
+    "msh": "model/mesh",
+    "mesh": "model/mesh",
+    "silo": "model/mesh",
+    "wrl": "model/vrml",
+    "vrml": "model/vrml",
+    "x3dv": "model/x3d+vrml",
+    "x3d": "model/x3d+xml",
+    "x3db": "model/x3d+binary",
+    "manifest": "text/cache-manifest",
+    "ics": "text/calendar",
+    "icz": "text/calendar",
+    "css": "text/css",
+    "csv": "text/csv",
+    "323": "text/h323",
+    "html": "text/html",
+    "htm": "text/html",
+    "shtml": "text/html",
+    "uls": "text/iuls",
+    "mml": "text/mathml",
+    "asc": "text/plain",
+    "txt": "text/plain",
+    "text": "text/plain",
+    "pot": "text/plain",
+    "brf": "text/plain",
+    "rtx": "text/richtext",
+    "sct": "text/scriptlet",
+    "wsc": "text/scriptlet",
+    "tm": "text/texmacs",
+    "ts": "text/texmacs",
+    "tsv": "text/tab-separated-values",
+    "jad": "text/vnd.sun.j2me.app-descriptor",
+    "wml": "text/vnd.wap.wml",
+    "wmls": "text/vnd.wap.wmlscript",
+    "bib": "text/x-bibtex",
+    "boo": "text/x-boo",
+    "h++": "text/x-c++hdr",
+    "hpp": "text/x-c++hdr",
+    "hxx": "text/x-c++hdr",
+    "hh": "text/x-c++hdr",
+    "c++": "text/x-c++src",
+    "cpp": "text/x-c++src",
+    "cxx": "text/x-c++src",
+    "cc": "text/x-c++src",
+    "h": "text/x-chdr",
+    "htc": "text/x-component",
+    "csh": "text/x-csh",
+    "c": "text/x-csrc",
+    "d": "text/x-dsrc",
+    "diff": "text/x-diff",
+    "patch": "text/x-diff",
+    "hs": "text/x-haskell",
+    "java": "text/x-java",
+    "lhs": "text/x-literate-haskell",
+    "moc": "text/x-moc",
+    "p": "text/x-pascal",
+    "pas": "text/x-pascal",
+    "gcd": "text/x-pcs-gcd",
+    "pl": "text/x-perl",
+    "pm": "text/x-perl",
+    "py": "text/x-python",
+    "scala": "text/x-scala",
+    "etx": "text/x-setext",
+    "sh": "text/x-sh",
+    "tcl": "text/x-tcl",
+    "tk": "text/x-tcl",
+    "tex": "text/x-tex",
+    "ltx": "text/x-tex",
+    "sty": "text/x-tex",
+    "cls": "text/x-tex",
+    "vcs": "text/x-vcalendar",
+    "vcf": "text/x-vcard",
+    "3gp": "video/3gpp",
+    "axv": "video/annodex",
+    "dl": "video/dl",
+    "dif": "video/dv",
+    "dv": "video/dv",
+    "fli": "video/fli",
+    "gl": "video/gl",
+    "mpeg": "video/mpeg",
+    "mpg": "video/mpeg",
+    "mpe": "video/mpeg",
+    "mp4": "video/mp4",
+    "qt": "video/quicktime",
+    "mov": "video/quicktime",
+    "ogv": "video/ogg",
+    "mxu": "video/vnd.mpegurl",
+    "flv": "video/x-flv",
+    "lsf": "video/x-la-asf",
+    "lsx": "video/x-la-asf",
+    "mng": "video/x-mng",
+    "asf": "video/x-ms-asf",
+    "asx": "video/x-ms-asf",
+    "wm": "video/x-ms-wm",
+    "wmv": "video/x-ms-wmv",
+    "wmx": "video/x-ms-wmx",
+    "wvx": "video/x-ms-wvx",
+    "avi": "video/x-msvideo",
+    "movie": "video/x-sgi-movie",
+    "mpv": "video/x-matroska",
+    "mkv": "video/x-matroska",
+    "ice": "x-conference/x-cooltalk",
+    "sisx": "x-epoc/x-sisx-app",
+    "vrm": "x-world/x-vrml",
+    "vrml": "x-world/x-vrml",
+    "wrl": "x-world/x-vrml"}
+
+proc newMimetypes*(): MimeDB =
+  ## Creates a new Mimetypes database. The database will contain the most
+  ## common mimetypes.
+  result.mimes = mimes.newStringTable()
+
+proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string =
+  ## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext``
+  ## could not be found.
+  result = mimedb.mimes[ext]
+  if result == "":
+    return default
+
+proc getExt*(mimedb: MimeDB, mimetype: string, default = "txt"): string =
+  ## Gets extension which corresponds to ``mimetype``. Returns ``default`` if
+  ## ``mimetype`` could not be found. Extensions are returned without the
+  ## leading dot.
+  result = default
+  for e, m in mimedb.mimes:
+    if m == mimetype:
+      result = e
+
+proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
+  ## Adds ``mimetype`` to the ``mimedb``.
+  mimedb.mimes[ext] = mimetype
+
+when isMainModule:
+  var m = newMimetypes()
+  assert m.getMimetype("mp4") == "video/mp4"
+  assert m.getExt("text/html") == "html"
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
new file mode 100644
index 000000000..cf37c271e
--- /dev/null
+++ b/lib/pure/net.nim
@@ -0,0 +1,1271 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a high-level cross-platform sockets interface.
+
+{.deadCodeElim: on.}
+import rawsockets, os, strutils, unsigned, parseutils, times
+export Port, `$`, `==`
+
+const useWinVersion = defined(Windows) or defined(nimdoc)
+
+when defined(ssl):
+  import openssl
+
+# Note: The enumerations are mapped to Window's constants.
+
+when defined(ssl):
+  type
+    SslError* = object of Exception
+
+    SslCVerifyMode* = enum
+      CVerifyNone, CVerifyPeer
+    
+    SslProtVersion* = enum
+      protSSLv2, protSSLv3, protTLSv1, protSSLv23
+    
+    SslContext* = distinct SslCtx
+
+    SslAcceptResult* = enum
+      AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
+
+  {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
+    TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
+    TSSLAcceptResult: SSLAcceptResult].}
+
+const
+  BufferSize*: int = 4000 ## size of a buffered socket's buffer
+
+type
+  SocketImpl* = object ## socket type
+    fd: SocketHandle
+    case isBuffered: bool # determines whether this socket is buffered.
+    of true:
+      buffer: array[0..BufferSize, char]
+      currPos: int # current index in buffer
+      bufLen: int # current length of buffer
+    of false: nil
+    when defined(ssl):
+      case isSsl: bool
+      of true:
+        sslHandle: SSLPtr
+        sslContext: SSLContext
+        sslNoHandshake: bool # True if needs handshake.
+        sslHasPeekChar: bool
+        sslPeekChar: char
+      of false: nil
+    lastError: OSErrorCode ## stores the last error on this socket
+
+  Socket* = ref SocketImpl
+
+  SOBool* = enum ## Boolean socket options.
+    OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
+    OptOOBInline, OptReuseAddr
+
+  ReadLineResult* = enum ## result for readLineAsync
+    ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
+
+  TimeoutError* = object of Exception
+
+  SocketFlag* {.pure.} = enum
+    Peek,
+    SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown.
+
+{.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError,
+    TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket,
+    TSocketImpl: SocketImpl].}
+
+type
+  IpAddressFamily* {.pure.} = enum ## Describes the type of an IP address
+    IPv6, ## IPv6 address
+    IPv4  ## IPv4 address
+
+  TIpAddress* = object ## stores an arbitrary IP address    
+    case family*: IpAddressFamily ## the type of the IP address (IPv4 or IPv6)
+    of IpAddressFamily.IPv6:
+      address_v6*: array[0..15, uint8] ## Contains the IP address in bytes in
+                                       ## case of IPv6
+    of IpAddressFamily.IPv4:
+      address_v4*: array[0..3, uint8] ## Contains the IP address in bytes in
+                                      ## case of IPv4
+
+proc isIpAddress*(address_str: string): bool {.tags: [].}
+proc parseIpAddress*(address_str: string): TIpAddress
+
+proc isDisconnectionError*(flags: set[SocketFlag],
+    lastError: OSErrorCode): bool =
+  ## Determines whether ``lastError`` is a disconnection error. Only does this
+  ## if flags contains ``SafeDisconn``.
+  when useWinVersion:
+    SocketFlag.SafeDisconn in flags and
+      lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
+                          WSAEDISCON, ERROR_NETNAME_DELETED}
+  else:
+    SocketFlag.SafeDisconn in flags and
+      lastError.int32 in {ECONNRESET, EPIPE, ENETRESET} 
+
+proc toOSFlags*(socketFlags: set[SocketFlag]): cint =
+  ## Converts the flags into the underlying OS representation.
+  for f in socketFlags:
+    case f
+    of SocketFlag.Peek:
+      result = result or MSG_PEEK
+    of SocketFlag.SafeDisconn: continue
+
+proc newSocket(fd: SocketHandle, isBuff: bool): Socket =
+  ## Creates a new socket as specified by the params.
+  assert fd != osInvalidSocket
+  new(result)
+  result.fd = fd
+  result.isBuffered = isBuff
+  if isBuff:
+    result.currPos = 0
+
+proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket =
+  ## Creates a new socket.
+  ##
+  ## If an error occurs EOS will be raised.
+  let fd = newRawSocket(domain, typ, protocol)
+  if fd == osInvalidSocket:
+    raiseOSError(osLastError())
+  result = newSocket(fd, buffered)
+
+proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+                protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
+  ## Creates a new socket.
+  ##
+  ## If an error occurs EOS will be raised.
+  let fd = newRawSocket(domain, typ, protocol)
+  if fd == osInvalidSocket:
+    raiseOSError(osLastError())
+  result = newSocket(fd, buffered)
+
+when defined(ssl):
+  CRYPTO_malloc_init()
+  SslLibraryInit()
+  SslLoadErrorStrings()
+  ErrLoadBioStrings()
+  OpenSSL_add_all_algorithms()
+
+  proc raiseSSLError*(s = "") =
+    ## Raises a new SSL error.
+    if s != "":
+      raise newException(SSLError, s)
+    let err = ErrPeekLastError()
+    if err == 0:
+      raise newException(SSLError, "No error reported.")
+    if err == -1:
+      raiseOSError(osLastError())
+    var errStr = ErrErrorString(err, nil)
+    raise newException(SSLError, $errStr)
+
+  # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
+  proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
+    if certFile != "" and not existsFile(certFile):
+      raise newException(system.IOError, "Certificate file could not be found: " & certFile)
+    if keyFile != "" and not existsFile(keyFile):
+      raise newException(system.IOError, "Key file could not be found: " & keyFile)
+    
+    if certFile != "":
+      var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
+      if ret != 1:
+        raiseSSLError()
+    
+    # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
+    if keyFile != "":
+      if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
+                                     SSL_FILETYPE_PEM) != 1:
+        raiseSSLError()
+        
+      if SSL_CTX_check_private_key(ctx) != 1:
+        raiseSSLError("Verification of private key file failed.")
+
+  proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
+                   certFile = "", keyFile = ""): SSLContext =
+    ## Creates an SSL context.
+    ## 
+    ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 
+    ## are available with the addition of ``protSSLv23`` which allows for 
+    ## compatibility with all of them.
+    ##
+    ## There are currently only two options for verify mode;
+    ## one is ``CVerifyNone`` and with it certificates will not be verified
+    ## the other is ``CVerifyPeer`` and certificates will be verified for
+    ## it, ``CVerifyPeer`` is the safest choice.
+    ##
+    ## The last two parameters specify the certificate file path and the key file
+    ## path, a server socket will most likely not work without these.
+    ## Certificates can be generated using the following command:
+    ## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
+    var newCTX: SSL_CTX
+    case protVersion
+    of protSSLv23:
+      newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
+    of protSSLv2:
+      when not defined(linux):
+        newCTX = SSL_CTX_new(SSLv2_method())
+      else:
+        raiseSslError()
+    of protSSLv3:
+      newCTX = SSL_CTX_new(SSLv3_method())
+    of protTLSv1:
+      newCTX = SSL_CTX_new(TLSv1_method())
+    
+    if newCTX.SSLCTXSetCipherList("ALL") != 1:
+      raiseSSLError()
+    case verifyMode
+    of CVerifyPeer:
+      newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil)
+    of CVerifyNone:
+      newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
+    if newCTX == nil:
+      raiseSSLError()
+
+    discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
+    newCTX.loadCertificates(certFile, keyFile)
+    return SSLContext(newCTX)
+
+  proc wrapSocket*(ctx: SSLContext, socket: Socket) =
+    ## Wraps a socket in an SSL context. This function effectively turns
+    ## ``socket`` into an SSL socket.
+    ##
+    ## **Disclaimer**: This code is not well tested, may be very unsafe and
+    ## prone to security vulnerabilities.
+    
+    socket.isSSL = true
+    socket.sslContext = ctx
+    socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
+    socket.sslNoHandshake = false
+    socket.sslHasPeekChar = false
+    if socket.sslHandle == nil:
+      raiseSSLError()
+    
+    if SSLSetFd(socket.sslHandle, socket.fd) != 1:
+      raiseSSLError()
+
+proc getSocketError*(socket: Socket): OSErrorCode =
+  ## Checks ``osLastError`` for a valid error. If it has been reset it uses
+  ## the last error stored in the socket object.
+  result = osLastError()
+  if result == 0.OSErrorCode:
+    result = socket.lastError
+  if result == 0.OSErrorCode:
+    raise newException(OSError, "No valid socket error code available")
+
+proc socketError*(socket: Socket, err: int = -1, async = false,
+                  lastError = (-1).OSErrorCode) =
+  ## Raises an OSError based on the error code returned by ``SSLGetError``
+  ## (for SSL sockets) and ``osLastError`` otherwise.
+  ##
+  ## If ``async`` is ``true`` no error will be thrown in the case when the
+  ## error was caused by no data being available to be read.
+  ##
+  ## If ``err`` is not lower than 0 no exception will be raised.
+  when defined(ssl):
+    if socket.isSSL:
+      if err <= 0:
+        var ret = SSLGetError(socket.sslHandle, err.cint)
+        case ret
+        of SSL_ERROR_ZERO_RETURN:
+          raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+          if async:
+            return
+          else: raiseSSLError("Not enough data on socket.")
+        of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
+          if async:
+            return
+          else: raiseSSLError("Not enough data on socket.")
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          raiseSSLError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL:
+          var errStr = "IO error has occurred "
+          let sslErr = ErrPeekLastError()
+          if sslErr == 0 and err == 0:
+            errStr.add "because an EOF was observed that violates the protocol"
+          elif sslErr == 0 and err == -1:
+            errStr.add "in the BIO layer"
+          else:
+            let errStr = $ErrErrorString(sslErr, nil)
+            raiseSSLError(errStr & ": " & errStr)
+          let osMsg = osErrorMsg osLastError()
+          if osMsg != "":
+            errStr.add ". The OS reports: " & osMsg
+          raise newException(OSError, errStr)
+        of SSL_ERROR_SSL:
+          raiseSSLError()
+        else: raiseSSLError("Unknown Error")
+  
+  if err == -1 and not (when defined(ssl): socket.isSSL else: false):
+    var lastE = if lastError.int == -1: getSocketError(socket) else: lastError
+    if async:
+      when useWinVersion:
+        if lastE.int32 == WSAEWOULDBLOCK:
+          return
+        else: raiseOSError(lastE)
+      else:
+        if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK:
+          return
+        else: raiseOSError(lastE)
+    else: raiseOSError(lastE)
+
+proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
+  ## Marks ``socket`` as accepting connections. 
+  ## ``Backlog`` specifies the maximum length of the 
+  ## queue of pending connections.
+  ##
+  ## Raises an EOS error upon failure.
+  if rawsockets.listen(socket.fd, backlog) < 0'i32:
+    raiseOSError(osLastError())
+
+proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
+  tags: [ReadIOEffect].} =
+  ## Binds ``address``:``port`` to the socket.
+  ##
+  ## If ``address`` is "" then ADDR_ANY will be bound.
+
+  if address == "":
+    var name: Sockaddr_in
+    when useWinVersion:
+      name.sin_family = toInt(AF_INET).int16
+    else:
+      name.sin_family = toInt(AF_INET)
+    name.sin_port = htons(int16(port))
+    name.sin_addr.s_addr = htonl(INADDR_ANY)
+    if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)),
+                  sizeof(name).SockLen) < 0'i32:
+      raiseOSError(osLastError())
+  else:
+    var aiList = getAddrInfo(address, port, AF_INET)
+    if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
+      dealloc(aiList)
+      raiseOSError(osLastError())
+    dealloc(aiList)
+
+proc acceptAddr*(server: Socket, client: var Socket, address: var string,
+                 flags = {SocketFlag.SafeDisconn}) {.
+                 tags: [ReadIOEffect], gcsafe, locks: 0.} =
+  ## Blocks until a connection is being made from a client. When a connection
+  ## is made sets ``client`` to the client socket and ``address`` to the address
+  ## of the connecting client.
+  ## This function will raise EOS if an error occurs.
+  ##
+  ## The resulting client will inherit any properties of the server socket. For
+  ## example: whether the socket is buffered or not.
+  ##
+  ## **Note**: ``client`` must be initialised (with ``new``), this function 
+  ## makes no effort to initialise the ``client`` variable.
+  ##
+  ## The ``accept`` call may result in an error if the connecting socket
+  ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
+  ## flag is specified then this error will not be raised and instead
+  ## accept will be called again.
+  assert(client != nil)
+  var sockAddress: Sockaddr_in
+  var addrLen = sizeof(sockAddress).SockLen
+  var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
+                    addr(addrLen))
+  
+  if sock == osInvalidSocket:
+    let err = osLastError()
+    if flags.isDisconnectionError(err):
+      acceptAddr(server, client, address, flags)
+    raiseOSError(err)
+  else:
+    client.fd = sock
+    client.isBuffered = server.isBuffered
+
+    # Handle SSL.
+    when defined(ssl):
+      if server.isSSL:
+        # We must wrap the client sock in a ssl context.
+        
+        server.sslContext.wrapSocket(client)
+        let ret = SSLAccept(client.sslHandle)
+        socketError(client, ret, false)
+    
+    # Client socket is set above.
+    address = $inet_ntoa(sockAddress.sin_addr)
+
+when false: #defined(ssl):
+  proc acceptAddrSSL*(server: Socket, client: var Socket,
+                      address: var string): TSSLAcceptResult {.
+                      tags: [ReadIOEffect].} =
+    ## This procedure should only be used for non-blocking **SSL** sockets. 
+    ## It will immediately return with one of the following values:
+    ## 
+    ## ``AcceptSuccess`` will be returned when a client has been successfully
+    ## accepted and the handshake has been successfully performed between
+    ## ``server`` and the newly connected client.
+    ##
+    ## ``AcceptNoHandshake`` will be returned when a client has been accepted
+    ## but no handshake could be performed. This can happen when the client
+    ## connects but does not yet initiate a handshake. In this case
+    ## ``acceptAddrSSL`` should be called again with the same parameters.
+    ##
+    ## ``AcceptNoClient`` will be returned when no client is currently attempting
+    ## to connect.
+    template doHandshake(): stmt =
+      when defined(ssl):
+        if server.isSSL:
+          client.setBlocking(false)
+          # We must wrap the client sock in a ssl context.
+          
+          if not client.isSSL or client.sslHandle == nil:
+            server.sslContext.wrapSocket(client)
+          let ret = SSLAccept(client.sslHandle)
+          while ret <= 0:
+            let err = SSLGetError(client.sslHandle, ret)
+            if err != SSL_ERROR_WANT_ACCEPT:
+              case err
+              of SSL_ERROR_ZERO_RETURN:
+                raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+              of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
+                 SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+                client.sslNoHandshake = true
+                return AcceptNoHandshake
+              of SSL_ERROR_WANT_X509_LOOKUP:
+                raiseSSLError("Function for x509 lookup has been called.")
+              of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+                raiseSSLError()
+              else:
+                raiseSSLError("Unknown error")
+          client.sslNoHandshake = false
+
+    if client.isSSL and client.sslNoHandshake:
+      doHandshake()
+      return AcceptSuccess
+    else:
+      acceptAddrPlain(AcceptNoClient, AcceptSuccess):
+        doHandshake()
+
+proc accept*(server: Socket, client: var Socket,
+             flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} =
+  ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
+  ## socket.
+  ## 
+  ## **Note**: ``client`` must be initialised (with ``new``), this function
+  ## makes no effort to initialise the ``client`` variable.
+  ##
+  ## The ``accept`` call may result in an error if the connecting socket
+  ## disconnects during the duration of the ``accept``. If the ``SafeDisconn``
+  ## flag is specified then this error will not be raised and instead
+  ## accept will be called again.
+  var addrDummy = ""
+  acceptAddr(server, client, addrDummy, flags)
+
+proc close*(socket: Socket) =
+  ## Closes a socket.
+  try:
+    when defined(ssl):
+      if socket.isSSL:
+        ErrClearError()
+        # As we are closing the underlying socket immediately afterwards,
+        # it is valid, under the TLS standard, to perform a unidirectional
+        # shutdown i.e not wait for the peers "close notify" alert with a second
+        # call to SSLShutdown
+        let res = SSLShutdown(socket.sslHandle)
+        SSLFree(socket.sslHandle)
+        socket.sslHandle = nil
+        if res == 0:
+          discard
+        elif res != 1:
+          socketError(socket, res)
+  finally:
+    socket.fd.close()
+
+proc toCInt*(opt: SOBool): cint =
+  ## Converts a ``SOBool`` into its Socket Option cint representation.
+  case opt
+  of OptAcceptConn: SO_ACCEPTCONN
+  of OptBroadcast: SO_BROADCAST
+  of OptDebug: SO_DEBUG
+  of OptDontRoute: SO_DONTROUTE
+  of OptKeepAlive: SO_KEEPALIVE
+  of OptOOBInline: SO_OOBINLINE
+  of OptReuseAddr: SO_REUSEADDR
+
+proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
+  tags: [ReadIOEffect].} =
+  ## Retrieves option ``opt`` as a boolean value.
+  var res = getSockOptInt(socket.fd, cint(level), toCInt(opt))
+  result = res != 0
+
+proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.
+  tags: [WriteIOEffect].} =
+  ## Sets option ``opt`` to a boolean value specified by ``value``.
+  var valuei = cint(if value: 1 else: 0)
+  setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei)
+
+proc connect*(socket: Socket, address: string, port = Port(0), 
+              af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
+  ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
+  ## host name. If ``address`` is a host name, this function will try each IP
+  ## of that host name. ``htons`` is already performed on ``port`` so you must
+  ## not do it.
+  ##
+  ## If ``socket`` is an SSL socket a handshake will be automatically performed.
+  var aiList = getAddrInfo(address, port, af)
+  # try all possibilities:
+  var success = false
+  var lastError: OSErrorCode
+  var it = aiList
+  while it != nil:
+    if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
+      success = true
+      break
+    else: lastError = osLastError()
+    it = it.ai_next
+
+  dealloc(aiList)
+  if not success: raiseOSError(lastError)
+  
+  when defined(ssl):
+    if socket.isSSL:
+      # RFC3546 for SNI specifies that IP addresses are not allowed.
+      if not isIpAddress(address):
+        # Discard result in case OpenSSL version doesn't support SNI, or we're
+        # not using TLSv1+
+        discard SSL_set_tlsext_host_name(socket.sslHandle, address)
+
+      let ret = SSLConnect(socket.sslHandle)
+      socketError(socket, ret)
+
+when defined(ssl):
+  proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+    ## This proc needs to be called on a socket after it connects. This is
+    ## only applicable when using ``connectAsync``.
+    ## This proc performs the SSL handshake.
+    ##
+    ## Returns ``False`` whenever the socket is not yet ready for a handshake,
+    ## ``True`` whenever handshake completed successfully.
+    ##
+    ## A ESSL error is raised on any other errors.
+    result = true
+    if socket.isSSL:
+      var ret = SSLConnect(socket.sslHandle)
+      if ret <= 0:
+        var errret = SSLGetError(socket.sslHandle, ret)
+        case errret
+        of SSL_ERROR_ZERO_RETURN:
+          raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
+          SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE:
+          return false
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          raiseSSLError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+          raiseSSLError()
+        else:
+          raiseSSLError("Unknown Error")
+      socket.sslNoHandshake = false
+    else:
+      raiseSSLError("Socket is not an SSL socket.")
+
+  proc gotHandshake*(socket: Socket): bool =
+    ## Determines whether a handshake has occurred between a client (``socket``)
+    ## and the server that ``socket`` is connected to.
+    ##
+    ## Throws ESSL if ``socket`` is not an SSL socket.
+    if socket.isSSL:
+      return not socket.sslNoHandshake
+    else:
+      raiseSSLError("Socket is not an SSL socket.")
+
+proc hasDataBuffered*(s: Socket): bool =
+  ## Determines whether a socket has data buffered.
+  result = false
+  if s.isBuffered:
+    result = s.bufLen > 0 and s.currPos != s.bufLen
+
+  when defined(ssl):
+    if s.isSSL and not result:
+      result = s.sslHasPeekChar
+
+proc select(readfd: Socket, timeout = 500): int =
+  ## Used for socket operation timeouts.
+  if readfd.hasDataBuffered:
+    return 1
+
+  var fds = @[readfd.fd]
+  result = select(fds, timeout)
+
+proc readIntoBuf(socket: Socket, flags: int32): int =
+  result = 0
+  when defined(ssl):
+    if socket.isSSL:
+      result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
+    else:
+      result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  else:
+    result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  if result < 0:
+    # Save it in case it gets reset (the Nim codegen occassionally may call
+    # Win API functions which reset it).
+    socket.lastError = osLastError()
+  if result <= 0:
+    socket.bufLen = 0
+    socket.currPos = 0
+    return result
+  socket.bufLen = result
+  socket.currPos = 0
+
+template retRead(flags, readBytes: int) {.dirty.} =
+  let res = socket.readIntoBuf(flags.int32)
+  if res <= 0:
+    if readBytes > 0:
+      return readBytes
+    else:
+      return res
+
+proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} =
+  ## Receives data from a socket.
+  ##
+  ## **Note**: This is a low-level function, you may be interested in the higher
+  ## level versions of this function which are also named ``recv``.
+  if size == 0: return
+  if socket.isBuffered:
+    if socket.bufLen == 0:
+      retRead(0'i32, 0)
+    
+    var read = 0
+    while read < size:
+      if socket.currPos >= socket.bufLen:
+        retRead(0'i32, read)
+    
+      let chunk = min(socket.bufLen-socket.currPos, size-read)
+      var d = cast[cstring](data)
+      assert size-read >= chunk
+      copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
+      read.inc(chunk)
+      socket.currPos.inc(chunk)
+
+    result = read
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        if socket.sslHasPeekChar:
+          copyMem(data, addr(socket.sslPeekChar), 1)
+          socket.sslHasPeekChar = false
+          if size-1 > 0:
+            var d = cast[cstring](data)
+            result = SSLRead(socket.sslHandle, addr(d[1]), size-1) + 1
+          else:
+            result = 1
+        else:
+          result = SSLRead(socket.sslHandle, data, size)
+      else:
+        result = recv(socket.fd, data, size.cint, 0'i32)
+    else:
+      result = recv(socket.fd, data, size.cint, 0'i32)
+    if result < 0:
+      # Save the error in case it gets reset.
+      socket.lastError = osLastError()
+
+proc waitFor(socket: Socket, waited: var float, timeout, size: int,
+             funcName: string): int {.tags: [TimeEffect].} =
+  ## determines the amount of characters that can be read. Result will never
+  ## be larger than ``size``. For unbuffered sockets this will be ``1``.
+  ## For buffered sockets it can be as big as ``BufferSize``.
+  ##
+  ## If this function does not determine that there is data on the socket
+  ## within ``timeout`` ms, an ETimeout error will be raised.
+  result = 1
+  if size <= 0: assert false
+  if timeout == -1: return size
+  if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
+    result = socket.bufLen - socket.currPos
+    result = min(result, size)
+  else:
+    if timeout - int(waited * 1000.0) < 1:
+      raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
+    
+    when defined(ssl):
+      if socket.isSSL:
+        if socket.hasDataBuffered:
+          # sslPeekChar is present.
+          return 1
+        let sslPending = SSLPending(socket.sslHandle)
+        if sslPending != 0:
+          return sslPending
+    
+    var startTime = epochTime()
+    let selRet = select(socket, timeout - int(waited * 1000.0))
+    if selRet < 0: raiseOSError(osLastError())
+    if selRet != 1:
+      raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
+    waited += (epochTime() - startTime)
+
+proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
+  tags: [ReadIOEffect, TimeEffect].} =
+  ## overload with a ``timeout`` parameter in milliseconds.
+  var waited = 0.0 # number of seconds already waited  
+  
+  var read = 0
+  while read < size:
+    let avail = waitFor(socket, waited, timeout, size-read, "recv")
+    var d = cast[cstring](data)
+    assert avail <= size-read
+    result = recv(socket, addr(d[read]), avail)
+    if result == 0: break
+    if result < 0:
+      return result
+    inc(read, result)
+  
+  result = read
+
+proc recv*(socket: Socket, data: var string, size: int, timeout = -1,
+           flags = {SocketFlag.SafeDisconn}): int =
+  ## Higher-level version of ``recv``.
+  ##
+  ## When 0 is returned the socket's connection has been closed.
+  ##
+  ## This function will throw an EOS exception when an error occurs. A value
+  ## lower than 0 is never returned.
+  ##
+  ## A timeout may be specified in milliseconds, if enough data is not received
+  ## within the time specified an ETimeout exception will be raised.
+  ##
+  ## **Note**: ``data`` must be initialised.
+  ##
+  ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
+  data.setLen(size)
+  result = recv(socket, cstring(data), size, timeout)
+  if result < 0:
+    data.setLen(0)
+    let lastError = getSocketError(socket)
+    if flags.isDisconnectionError(lastError): return
+    socket.socketError(result, lastError = lastError)
+  data.setLen(result)
+
+proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
+  if socket.isBuffered:
+    result = 1
+    if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
+      var res = socket.readIntoBuf(0'i32)
+      if res <= 0:
+        result = res
+    
+    c = socket.buffer[socket.currPos]
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        if not socket.sslHasPeekChar:
+          result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
+          socket.sslHasPeekChar = true
+        
+        c = socket.sslPeekChar
+        return
+    result = recv(socket.fd, addr(c), 1, MSG_PEEK)
+
+proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
+               flags = {SocketFlag.SafeDisconn}) {.
+  tags: [ReadIOEffect, TimeEffect].} =
+  ## Reads a line of data from ``socket``.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## An EOS exception will be raised in the case of a socket error.
+  ##
+  ## A timeout can be specified in milliseconds, if data is not received within
+  ## the specified time an ETimeout exception will be raised.
+  ##
+  ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
+  
+  template addNLIfEmpty(): stmt =
+    if line.len == 0:
+      line.add("\c\L")
+
+  template raiseSockError(): stmt {.dirty, immediate.} =
+    let lastError = getSocketError(socket)
+    if flags.isDisconnectionError(lastError): setLen(line.string, 0); return
+    socket.socketError(n, lastError = lastError)
+
+  var waited = 0.0
+
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    discard waitFor(socket, waited, timeout, 1, "readLine")
+    var n = recv(socket, addr(c), 1)
+    if n < 0: raiseSockError()
+    elif n == 0: setLen(line.string, 0); return
+    if c == '\r':
+      discard waitFor(socket, waited, timeout, 1, "readLine")
+      n = peekChar(socket, c)
+      if n > 0 and c == '\L':
+        discard recv(socket, addr(c), 1)
+      elif n <= 0: raiseSockError()
+      addNLIfEmpty()
+      return
+    elif c == '\L': 
+      addNLIfEmpty()
+      return
+    add(line.string, c)
+
+proc recvFrom*(socket: Socket, data: var string, length: int,
+               address: var string, port: var Port, flags = 0'i32): int {.
+               tags: [ReadIOEffect].} =
+  ## Receives data from ``socket``. This function should normally be used with
+  ## connection-less sockets (UDP sockets).
+  ##
+  ## If an error occurs an EOS exception will be raised. Otherwise the return
+  ## value will be the length of data received.
+  ##
+  ## **Warning:** This function does not yet have a buffered implementation,
+  ## so when ``socket`` is buffered the non-buffered implementation will be
+  ## used. Therefore if ``socket`` contains something in its buffer this
+  ## function will make no effort to return it.
+  
+  # TODO: Buffered sockets
+  data.setLen(length)
+  var sockAddress: Sockaddr_in
+  var addrLen = sizeof(sockAddress).SockLen
+  result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
+                    cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
+
+  if result != -1:
+    data.setLen(result)
+    address = $inet_ntoa(sockAddress.sin_addr)
+    port = ntohs(sockAddress.sin_port).Port
+  else:
+    raiseOSError(osLastError())
+
+proc skip*(socket: Socket, size: int, timeout = -1) =
+  ## Skips ``size`` amount of bytes.
+  ##
+  ## An optional timeout can be specified in milliseconds, if skipping the
+  ## bytes takes longer than specified an ETimeout exception will be raised.
+  ##
+  ## Returns the number of skipped bytes.
+  var waited = 0.0
+  var dummy = alloc(size)
+  var bytesSkipped = 0
+  while bytesSkipped != size:
+    let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
+    bytesSkipped += recv(socket, dummy, avail)
+  dealloc(dummy)
+
+proc send*(socket: Socket, data: pointer, size: int): int {.
+  tags: [WriteIOEffect].} =
+  ## Sends data to a socket.
+  ##
+  ## **Note**: This is a low-level version of ``send``. You likely should use 
+  ## the version below.
+  when defined(ssl):
+    if socket.isSSL:
+      return SSLWrite(socket.sslHandle, cast[cstring](data), size)
+  
+  when useWinVersion or defined(macosx):
+    result = send(socket.fd, data, size.cint, 0'i32)
+  else:
+    when defined(solaris): 
+      const MSG_NOSIGNAL = 0
+    result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
+
+proc send*(socket: Socket, data: string,
+           flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} =
+  ## sends data to a socket.
+  let sent = send(socket, cstring(data), data.len)
+  if sent < 0:
+    let lastError = osLastError()
+    if flags.isDisconnectionError(lastError): return
+    socketError(socket, lastError = lastError)
+
+  if sent != data.len:
+    raise newException(OSError, "Could not send all data.")
+
+proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
+  ## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
+  ## and instead returns ``false`` on failure.
+  result = send(socket, cstring(data), data.len) == data.len
+
+proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
+             size: int, af: Domain = AF_INET, flags = 0'i32): int {.
+             tags: [WriteIOEffect].} =
+  ## This proc sends ``data`` to the specified ``address``,
+  ## which may be an IP address or a hostname, if a hostname is specified 
+  ## this function will try each IP of that hostname.
+  ##
+  ##
+  ## **Note:** You may wish to use the high-level version of this function
+  ## which is defined below.
+  ##
+  ## **Note:** This proc is not available for SSL sockets.
+  var aiList = getAddrInfo(address, port, af)
+  
+  # try all possibilities:
+  var success = false
+  var it = aiList
+  while it != nil:
+    result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
+                    it.ai_addrlen.SockLen)
+    if result != -1'i32:
+      success = true
+      break
+    it = it.ai_next
+
+  dealloc(aiList)
+
+proc sendTo*(socket: Socket, address: string, port: Port, 
+             data: string): int {.tags: [WriteIOEffect].} =
+  ## This proc sends ``data`` to the specified ``address``,
+  ## which may be an IP address or a hostname, if a hostname is specified 
+  ## this function will try each IP of that hostname.
+  ##
+  ## This is the high-level version of the above ``sendTo`` function.
+  result = socket.sendTo(address, port, cstring(data), data.len)
+
+proc connectAsync(socket: Socket, name: string, port = Port(0),
+                  af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
+  ## A variant of ``connect`` for non-blocking sockets.
+  ##
+  ## This procedure will immediately return, it will not block until a connection
+  ## is made. It is up to the caller to make sure the connection has been established
+  ## by checking (using ``select``) whether the socket is writeable.
+  ##
+  ## **Note**: For SSL sockets, the ``handshake`` procedure must be called
+  ## whenever the socket successfully connects to a server.
+  var aiList = getAddrInfo(name, port, af)
+  # try all possibilities:
+  var success = false
+  var lastError: OSErrorCode
+  var it = aiList
+  while it != nil:
+    var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
+    if ret == 0'i32:
+      success = true
+      break
+    else:
+      lastError = osLastError()
+      when useWinVersion:
+        # Windows EINTR doesn't behave same as POSIX.
+        if lastError.int32 == WSAEWOULDBLOCK:
+          success = true
+          break
+      else:
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+          success = true
+          break
+        
+    it = it.ai_next
+
+  dealloc(aiList)
+  if not success: raiseOSError(lastError)
+
+proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
+             af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Connects to server as specified by ``address`` on port specified by ``port``.
+  ##
+  ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
+  ## the connection to the server to be made.
+  socket.fd.setBlocking(false)
+  
+  socket.connectAsync(address, port, af)
+  var s = @[socket.fd]
+  if selectWrite(s, timeout) != 1:
+    raise newException(TimeoutError, "Call to 'connect' timed out.")
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        socket.fd.setBlocking(true)
+        doAssert socket.handshake()
+  socket.fd.setBlocking(true)
+
+proc isSsl*(socket: Socket): bool = 
+  ## Determines whether ``socket`` is a SSL socket.
+  when defined(ssl):
+    result = socket.isSSL
+  else:
+    result = false
+
+proc getFd*(socket: Socket): SocketHandle = return socket.fd
+  ## Returns the socket's file descriptor
+
+proc IPv4_any*(): TIpAddress =
+  ## Returns the IPv4 any address, which can be used to listen on all available
+  ## network adapters
+  result = TIpAddress(
+    family: IpAddressFamily.IPv4,
+    address_v4: [0'u8, 0, 0, 0])
+
+proc IPv4_loopback*(): TIpAddress =
+  ## Returns the IPv4 loopback address (127.0.0.1)
+  result = TIpAddress(
+    family: IpAddressFamily.IPv4,
+    address_v4: [127'u8, 0, 0, 1])
+
+proc IPv4_broadcast*(): TIpAddress =
+  ## Returns the IPv4 broadcast address (255.255.255.255)
+  result = TIpAddress(
+    family: IpAddressFamily.IPv4,
+    address_v4: [255'u8, 255, 255, 255])
+
+proc IPv6_any*(): TIpAddress =
+  ## Returns the IPv6 any address (::0), which can be used
+  ## to listen on all available network adapters 
+  result = TIpAddress(
+    family: IpAddressFamily.IPv6,
+    address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
+
+proc IPv6_loopback*(): TIpAddress =
+  ## Returns the IPv6 loopback address (::1)
+  result = TIpAddress(
+    family: IpAddressFamily.IPv6,
+    address_v6: [0'u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
+
+proc `==`*(lhs, rhs: TIpAddress): bool =
+  ## Compares two IpAddresses for Equality. Returns two if the addresses are equal
+  if lhs.family != rhs.family: return false
+  if lhs.family == IpAddressFamily.IPv4:
+    for i in low(lhs.address_v4) .. high(lhs.address_v4):
+      if lhs.address_v4[i] != rhs.address_v4[i]: return false
+  else: # IPv6
+    for i in low(lhs.address_v6) .. high(lhs.address_v6):
+      if lhs.address_v6[i] != rhs.address_v6[i]: return false
+  return true
+
+proc `$`*(address: TIpAddress): string =
+  ## Converts an TIpAddress into the textual representation
+  result = ""
+  case address.family
+  of IpAddressFamily.IPv4:
+    for i in 0 .. 3:
+      if i != 0:
+        result.add('.')
+      result.add($address.address_v4[i])
+  of IpAddressFamily.IPv6:
+    var
+      currentZeroStart = -1
+      currentZeroCount = 0
+      biggestZeroStart = -1
+      biggestZeroCount = 0
+    # Look for the largest block of zeros
+    for i in 0..7:
+      var isZero = address.address_v6[i*2] == 0 and address.address_v6[i*2+1] == 0
+      if isZero:
+        if currentZeroStart == -1:
+          currentZeroStart = i
+          currentZeroCount = 1
+        else:
+          currentZeroCount.inc()
+        if currentZeroCount > biggestZeroCount:
+          biggestZeroCount = currentZeroCount
+          biggestZeroStart = currentZeroStart
+      else:
+        currentZeroStart = -1
+
+    if biggestZeroCount == 8: # Special case ::0
+      result.add("::")
+    else: # Print address
+      var printedLastGroup = false
+      for i in 0..7:
+        var word:uint16 = (cast[uint16](address.address_v6[i*2])) shl 8
+        word = word or cast[uint16](address.address_v6[i*2+1])
+
+        if biggestZeroCount != 0 and # Check if group is in skip group
+          (i >= biggestZeroStart and i < (biggestZeroStart + biggestZeroCount)):
+          if i == biggestZeroStart: # skip start
+            result.add("::")
+          printedLastGroup = false
+        else:
+          if printedLastGroup:
+            result.add(':')
+          var
+            afterLeadingZeros = false
+            mask = 0xF000'u16
+          for j in 0'u16..3'u16:
+            var val = (mask and word) shr (4'u16*(3'u16-j))
+            if val != 0 or afterLeadingZeros:
+              if val < 0xA:
+                result.add(chr(uint16(ord('0'))+val))
+              else: # val >= 0xA
+                result.add(chr(uint16(ord('a'))+val-0xA))
+              afterLeadingZeros = true
+            mask = mask shr 4
+          printedLastGroup = true
+
+proc parseIPv4Address(address_str: string): TIpAddress =
+  ## Parses IPv4 adresses
+  ## Raises EInvalidValue on errors
+  var
+    byteCount = 0
+    currentByte:uint16 = 0
+    seperatorValid = false
+
+  result.family = IpAddressFamily.IPv4
+
+  for i in 0 .. high(address_str):
+    if address_str[i] in strutils.Digits: # Character is a number
+      currentByte = currentByte * 10 +
+        cast[uint16](ord(address_str[i]) - ord('0'))
+      if currentByte > 255'u16:
+        raise newException(ValueError,
+          "Invalid IP Address. Value is out of range")
+      seperatorValid = true
+    elif address_str[i] == '.': # IPv4 address separator
+      if not seperatorValid or byteCount >= 3:
+        raise newException(ValueError,
+          "Invalid IP Address. The address consists of too many groups")
+      result.address_v4[byteCount] = cast[uint8](currentByte)
+      currentByte = 0
+      byteCount.inc
+      seperatorValid = false
+    else:
+      raise newException(ValueError,
+        "Invalid IP Address. Address contains an invalid character")
+
+  if byteCount != 3 or not seperatorValid:
+    raise newException(ValueError, "Invalid IP Address")
+  result.address_v4[byteCount] = cast[uint8](currentByte)
+
+proc parseIPv6Address(address_str: string): TIpAddress =
+  ## Parses IPv6 adresses
+  ## Raises EInvalidValue on errors
+  result.family = IpAddressFamily.IPv6
+  if address_str.len < 2:
+    raise newException(ValueError, "Invalid IP Address")
+
+  var
+    groupCount = 0
+    currentGroupStart = 0
+    currentShort:uint32 = 0
+    seperatorValid = true
+    dualColonGroup = -1
+    lastWasColon = false
+    v4StartPos = -1
+    byteCount = 0
+
+  for i,c in address_str:
+    if c == ':':
+      if not seperatorValid:
+        raise newException(ValueError,
+          "Invalid IP Address. Address contains an invalid seperator")
+      if lastWasColon:        
+        if dualColonGroup != -1:
+          raise newException(ValueError,
+            "Invalid IP Address. Address contains more than one \"::\" seperator")
+        dualColonGroup = groupCount
+        seperatorValid = false
+      elif i != 0 and i != high(address_str):
+        if groupCount >= 8:
+          raise newException(ValueError,
+            "Invalid IP Address. The address consists of too many groups")
+        result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
+        result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
+        currentShort = 0
+        groupCount.inc()        
+        if dualColonGroup != -1: seperatorValid = false
+      elif i == 0: # only valid if address starts with ::
+        if address_str[1] != ':':
+          raise newException(ValueError,
+            "Invalid IP Address. Address may not start with \":\"")
+      else: # i == high(address_str) - only valid if address ends with ::
+        if address_str[high(address_str)-1] != ':': 
+          raise newException(ValueError,
+            "Invalid IP Address. Address may not end with \":\"")
+      lastWasColon = true
+      currentGroupStart = i + 1
+    elif c == '.': # Switch to parse IPv4 mode
+      if i < 3 or not seperatorValid or groupCount >= 7:
+        raise newException(ValueError, "Invalid IP Address")
+      v4StartPos = currentGroupStart
+      currentShort = 0
+      seperatorValid = false
+      break
+    elif c in strutils.HexDigits:
+      if c in strutils.Digits: # Normal digit
+        currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('0'))
+      elif c >= 'a' and c <= 'f': # Lower case hex
+        currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('a')) + 10
+      else: # Upper case hex
+        currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10
+      if currentShort > 65535'u32:
+        raise newException(ValueError,
+          "Invalid IP Address. Value is out of range")
+      lastWasColon = false
+      seperatorValid = true
+    else:
+      raise newException(ValueError,
+        "Invalid IP Address. Address contains an invalid character")
+
+
+  if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff
+    if seperatorValid: # Copy remaining data
+      if groupCount >= 8:
+        raise newException(ValueError,
+          "Invalid IP Address. The address consists of too many groups")
+      result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8)
+      result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF)
+      groupCount.inc()
+  else: # Must parse IPv4 address
+    for i,c in address_str[v4StartPos..high(address_str)]:
+      if c in strutils.Digits: # Character is a number
+        currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0'))
+        if currentShort > 255'u32:
+          raise newException(ValueError,
+            "Invalid IP Address. Value is out of range")
+        seperatorValid = true
+      elif c == '.': # IPv4 address separator
+        if not seperatorValid or byteCount >= 3:
+          raise newException(ValueError, "Invalid IP Address")
+        result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
+        currentShort = 0
+        byteCount.inc()
+        seperatorValid = false
+      else: # Invalid character
+        raise newException(ValueError,
+          "Invalid IP Address. Address contains an invalid character")
+
+    if byteCount != 3 or not seperatorValid:
+      raise newException(ValueError, "Invalid IP Address")
+    result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort)
+    groupCount += 2
+
+  # Shift and fill zeros in case of ::
+  if groupCount > 8:
+    raise newException(ValueError,
+      "Invalid IP Address. The address consists of too many groups")
+  elif groupCount < 8: # must fill
+    if dualColonGroup == -1:
+      raise newException(ValueError,
+        "Invalid IP Address. The address consists of too few groups")
+    var toFill = 8 - groupCount # The number of groups to fill
+    var toShift = groupCount - dualColonGroup # Nr of known groups after ::
+    for i in 0..2*toShift-1: # shift
+      result.address_v6[15-i] = result.address_v6[groupCount*2-i-1]
+    for i in 0..2*toFill-1: # fill with 0s
+      result.address_v6[dualColonGroup*2+i] = 0
+  elif dualColonGroup != -1:
+    raise newException(ValueError,
+      "Invalid IP Address. The address consists of too many groups")
+
+proc parseIpAddress(address_str: string): TIpAddress =
+  ## Parses an IP address
+  ## Raises EInvalidValue on error
+  if address_str == nil:
+    raise newException(ValueError, "IP Address string is nil")
+  if address_str.contains(':'):
+    return parseIPv6Address(address_str)
+  else:
+    return parseIPv4Address(address_str)
+
+
+proc isIpAddress(address_str: string): bool =
+  ## Checks if a string is an IP address
+  ## Returns true if it is, false otherwise
+  try:
+    discard parseIpAddress(address_str)
+  except ValueError:
+    return false
+  return true
diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim
new file mode 100644
index 000000000..cce2a20ae
--- /dev/null
+++ b/lib/pure/nimprof.nim
@@ -0,0 +1,205 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Profiling support for Nim. This is an embedded profiler that requires
+## ``--profiler:on``. You only need to import this module to get a profiling
+## report at program exit.
+
+when not defined(profiler) and not defined(memProfiler):
+  {.warning: "Profiling support is turned off!".}
+
+# We don't want to profile the profiling code ...
+{.push profiler: off.}
+
+import hashes, algorithm, strutils, tables, sets
+
+when not defined(memProfiler):
+  include "system/timers"
+
+const
+  withThreads = compileOption("threads")
+  tickCountCorrection = 50_000
+
+when not declared(system.TStackTrace):
+  type TStackTrace = array [0..20, cstring]
+
+# We use a simple hash table of bounded size to keep track of the stack traces:
+type
+  TProfileEntry = object
+    total: int
+    st: TStackTrace
+  TProfileData = array [0..64*1024-1, ptr TProfileEntry]
+
+proc `==`(a, b: TStackTrace): bool =
+  for i in 0 .. high(a):
+    if a[i] != b[i]: return false
+  result = true
+
+# XXX extract this data structure; it is generally useful ;-)
+# However a chain length of over 3000 is suspicious...
+var
+  profileData: TProfileData
+  emptySlots = profileData.len * 3 div 2
+  maxChainLen = 0
+  totalCalls = 0
+
+when not defined(memProfiler):
+  var interval: TNanos = 5_000_000 - tickCountCorrection # 5ms
+
+  proc setSamplingFrequency*(intervalInUs: int) =
+    ## set this to change the sampling frequency. Default value is 5ms.
+    ## Set it to 0 to disable time based profiling; it uses an imprecise
+    ## instruction count measure instead then.
+    if intervalInUs <= 0: interval = 0
+    else: interval = intervalInUs * 1000 - tickCountCorrection
+
+when withThreads:
+  import locks
+  var
+    profilingLock: TLock
+
+  initLock profilingLock
+
+proc hookAux(st: TStackTrace, costs: int) =
+  # this is quite performance sensitive!
+  when withThreads: acquire profilingLock
+  inc totalCalls
+  var last = high(st)
+  while last > 0 and isNil(st[last]): dec last
+  var h = hash(pointer(st[last])) and high(profileData)
+
+  # we use probing for maxChainLen entries and replace the encountered entry
+  # with the minimal 'total' value:
+  if emptySlots == 0:
+    var minIdx = h
+    var probes = maxChainLen
+    while probes >= 0:
+      if profileData[h].st == st:
+        # wow, same entry found:
+        inc profileData[h].total, costs
+        return
+      if profileData[minIdx].total < profileData[h].total:
+        minIdx = h
+      h = ((5 * h) + 1) and high(profileData)
+      dec probes
+    profileData[minIdx].total = costs
+    profileData[minIdx].st = st
+  else:
+    var chain = 0
+    while true:
+      if profileData[h] == nil:
+        profileData[h] = cast[ptr TProfileEntry](
+                             allocShared0(sizeof(TProfileEntry)))
+        profileData[h].total = costs
+        profileData[h].st = st
+        dec emptySlots
+        break
+      if profileData[h].st == st:
+        # wow, same entry found:
+        inc profileData[h].total, costs
+        break
+      h = ((5 * h) + 1) and high(profileData)
+      inc chain
+    maxChainLen = max(maxChainLen, chain)
+  when withThreads: release profilingLock
+
+when defined(memProfiler):
+  const
+    SamplingInterval = 50_000
+  var
+    gTicker {.threadvar.}: int
+
+  proc hook(st: TStackTrace, size: int) {.nimcall.} =
+    if gTicker == 0:
+      gTicker = -1
+      when defined(ignoreAllocationSize):
+        hookAux(st, 1)
+      else:
+        hookAux(st, size)
+      gTicker = SamplingInterval
+    dec gTicker
+
+else:
+  var
+    t0 {.threadvar.}: TTicks
+
+  proc hook(st: TStackTrace) {.nimcall.} =
+    if interval == 0:
+      hookAux(st, 1)
+    elif int64(t0) == 0 or getTicks() - t0 > interval:
+      hookAux(st, 1)
+      t0 = getTicks()
+
+proc getTotal(x: ptr TProfileEntry): int =
+  result = if isNil(x): 0 else: x.total
+
+proc cmpEntries(a, b: ptr TProfileEntry): int =
+  result = b.getTotal - a.getTotal
+
+proc `//`(a, b: int): string =
+  result = format("$1/$2 = $3%", a, b, formatFloat(a / b * 100.0, ffDefault, 2))
+
+proc writeProfile() {.noconv.} =
+  when declared(system.TStackTrace):
+    system.profilerHook = nil
+  const filename = "profile_results.txt"
+  echo "writing " & filename & "..."
+  var f: File
+  if open(f, filename, fmWrite):
+    sort(profileData, cmpEntries)
+    writeln(f, "total executions of each stack trace:")
+    var entries = 0
+    for i in 0..high(profileData):
+      if profileData[i] != nil: inc entries
+
+    var perProc = initCountTable[string]()
+    for i in 0..entries-1:
+      var dups = initSet[string]()
+      for ii in 0..high(TStackTrace):
+        let procname = profileData[i].st[ii]
+        if isNil(procname): break
+        let p = $procname
+        if not containsOrIncl(dups, p):
+          perProc.inc(p, profileData[i].total)
+
+    var sum = 0
+    # only write the first 100 entries:
+    for i in 0..min(100, entries-1):
+      if profileData[i].total > 1:
+        inc sum, profileData[i].total
+        writeln(f, "Entry: ", i+1, "/", entries, " Calls: ",
+          profileData[i].total // totalCalls, " [sum: ", sum, "; ",
+          sum // totalCalls, "]")
+        for ii in 0..high(TStackTrace):
+          let procname = profileData[i].st[ii]
+          if isNil(procname): break
+          writeln(f, "  ", procname, " ", perProc[$procname] // totalCalls)
+    close(f)
+    echo "... done"
+  else:
+    echo "... failed"
+
+var
+  disabled: int
+
+proc disableProfiling*() =
+  when declared(system.TStackTrace):
+    atomicDec disabled
+    system.profilerHook = nil
+
+proc enableProfiling*() =
+  when declared(system.TStackTrace):
+    if atomicInc(disabled) >= 0:
+      system.profilerHook = hook
+
+when declared(system.TStackTrace):
+  system.profilerHook = hook
+  addQuitProc(writeProfile)
+
+{.pop.}
diff --git a/lib/pure/nimprof.nim.cfg b/lib/pure/nimprof.nim.cfg
new file mode 100644
index 000000000..1589e7394
--- /dev/null
+++ b/lib/pure/nimprof.nim.cfg
@@ -0,0 +1 @@
+--profiler:on
diff --git a/lib/pure/numeric.nim b/lib/pure/numeric.nim
new file mode 100644
index 000000000..9b298c0a0
--- /dev/null
+++ b/lib/pure/numeric.nim
@@ -0,0 +1,84 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Robert Persson
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+type OneVarFunction* = proc (x: float): float
+
+{.deprecated: [TOneVarFunction: OneVarFunction].}
+
+proc brent*(xmin,xmax:float, function:OneVarFunction, tol:float,maxiter=1000): 
+  tuple[rootx, rooty: float, success: bool]=
+  ## Searches `function` for a root between `xmin` and `xmax` 
+  ## using brents method. If the function value at `xmin`and `xmax` has the
+  ## same sign, `rootx`/`rooty` is set too the extrema value closest to x-axis
+  ## and succes is set to false.
+  ## Otherwise there exists at least one root and success is set to true.
+  ## This root is searched for at most `maxiter` iterations.
+  ## If `tol` tolerance is reached within `maxiter` iterations 
+  ## the root refinement stops and success=true.
+
+  # see http://en.wikipedia.org/wiki/Brent%27s_method
+  var 
+    a=xmin
+    b=xmax
+    c=a
+    d=1.0e308 
+    fa=function(a)
+    fb=function(b)
+    fc=fa
+    s=0.0
+    fs=0.0
+    mflag:bool
+    i=0
+    tmp2:float
+
+  if fa*fb>=0:
+    if abs(fa)<abs(fb):
+      return (a,fa,false)
+    else:
+      return (b,fb,false)
+  
+  if abs(fa)<abs(fb):
+    swap(fa,fb)
+    swap(a,b)
+  
+  while fb!=0.0 and abs(a-b)>tol:
+    if fa!=fc and fb!=fc: # inverse quadratic interpolation
+      s = a * fb * fc / (fa - fb) / (fa - fc) + b * fa * fc / (fb - fa) / (fb - fc) + c * fa * fb / (fc - fa) / (fc - fb)
+    else: #secant rule
+      s = b - fb * (b - a) / (fb - fa)
+    tmp2 = (3.0 * a + b) / 4.0
+    if not((s > tmp2 and s < b) or (s < tmp2 and s > b)) or 
+      (mflag and abs(s - b) >= (abs(b - c) / 2.0)) or 
+      (not mflag and abs(s - b) >= abs(c - d) / 2.0):
+      s=(a+b)/2.0
+      mflag=true
+    else:
+      if (mflag and (abs(b - c) < tol)) or (not mflag and (abs(c - d) < tol)):
+        s=(a+b)/2.0
+        mflag=true
+      else:
+        mflag=false
+    fs = function(s)
+    d = c
+    c = b
+    fc = fb
+    if fa * fs<0.0:
+      b=s
+      fb=fs
+    else:
+      a=s
+      fa=fs
+    if abs(fa)<abs(fb):
+      swap(a,b)
+      swap(fa,fb)
+    inc i
+    if i>maxiter:
+      break
+  
+  return (b,fb,true)
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
new file mode 100644
index 000000000..ac90dd16b
--- /dev/null
+++ b/lib/pure/oids.nim
@@ -0,0 +1,93 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nim OID support. An OID is a global ID that consists of a timestamp,
+## a unique counter and a random value. This combination should suffice to 
+## produce a globally distributed unique ID. This implementation was extracted
+## from the Mongodb interface and it thus binary compatible with a Mongo OID.
+##
+## This implementation calls ``math.randomize()`` for the first call of
+## ``genOid``.
+
+import times, endians
+
+type
+  Oid* = object ## an OID
+    time: int32  ## 
+    fuzz: int32  ## 
+    count: int32 ## 
+
+{.deprecated: [Toid: Oid].}
+
+proc hexbyte*(hex: char): int = 
+  case hex
+  of '0'..'9': result = (ord(hex) - ord('0'))
+  of 'a'..'f': result = (ord(hex) - ord('a') + 10)
+  of 'A'..'F': result = (ord(hex) - ord('A') + 10)
+  else: discard
+
+proc parseOid*(str: cstring): Oid =
+  ## parses an OID.
+  var bytes = cast[cstring](addr(result.time))
+  var i = 0
+  while i < 12:
+    bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1]))
+    inc(i)
+
+proc oidToString*(oid: Oid, str: cstring) = 
+  const hex = "0123456789abcdef"
+  # work around a compiler bug:
+  var str = str
+  var o = oid
+  var bytes = cast[cstring](addr(o))
+  var i = 0
+  while i < 12:
+    let b = bytes[i].ord
+    str[2 * i] = hex[(b and 0xF0) shr 4]
+    str[2 * i + 1] = hex[b and 0xF]
+    inc(i)
+  str[24] = '\0'
+
+proc `$`*(oid: Oid): string =
+  result = newString(24)
+  oidToString(oid, result)
+
+var
+  incr: int 
+  fuzz: int32
+
+proc genOid*(): Oid =
+  ## generates a new OID.
+  proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.}
+  proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
+  proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>", nodecl.}
+
+  var t = gettime(nil)
+  
+  var i = int32(incr)
+  atomicInc(incr)
+  
+  if fuzz == 0:
+    # racy, but fine semantically:
+    srand(t)
+    fuzz = rand()
+  bigEndian32(addr result.time, addr(t))
+  result.fuzz = fuzz
+  bigEndian32(addr result.count, addr(i))
+
+proc generatedTime*(oid: Oid): Time =
+  ## returns the generated timestamp of the OID.
+  var tmp: int32
+  var dummy = oid.time
+  bigEndian32(addr(tmp), addr(dummy))
+  result = Time(tmp)
+
+when not defined(testing) and isMainModule:
+  let xo = genOid()
+  echo xo.generatedTime
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
new file mode 100644
index 000000000..ef01e1260
--- /dev/null
+++ b/lib/pure/options.nim
@@ -0,0 +1,160 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Nim Contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Abstract
+## ========
+##
+## This module implements types which encapsulate an optional value.
+##
+## A value of type ``Option[T]`` either contains a value `x` (represented as
+## ``some(x)``) or is empty (``none(T)``).
+##
+## This can be useful when you have a value that can be present or not.  The
+## absence of a value is often represented by ``nil``, but it is not always
+## available, nor is it always a good solution.
+##
+##
+## Tutorial
+## ========
+##
+## Let's start with an example: a procedure that finds the index of a character
+## in a string.
+##
+## .. code-block:: nim
+##
+##   import optionals
+##
+##   proc find(haystack: string, needle: char): Option[int] =
+##     for i, c in haystack:
+##       if c == needle:
+##         return some(i)
+##     return none(int)  # This line is actually optional,
+##                       # because the default is empty
+##
+## .. code-block:: nim
+##
+##   try:
+##     assert("abc".find('c').get() == 2)  # Immediately extract the value
+##   except UnpackError:  # If there is no value
+##     assert false  # This will not be reached, because the value is present
+##
+## The ``get`` operation demonstrated above returns the underlying value, or
+## raises ``UnpackError`` if there is no value. There is another option for
+## obtaining the value: ``unsafeGet``, but you must only use it when you are
+## absolutely sure the value is present (e.g. after checking ``isSome``). If
+## you do not care about the tiny overhead that ``get`` causes, you should
+## simply never use ``unsafeGet``.
+##
+## How to deal with an absence of a value:
+##
+## .. code-block:: nim
+##
+##   let result = "team".find('i')
+##
+##   # Nothing was found, so the result is `none`.
+##   assert(result == none(int))
+##   # It has no value:
+##   assert(result.isNone)
+##
+##   try:
+##     echo result.get()
+##     assert(false)  # This will not be reached
+##   except UnpackError:  # Because an exception is raised
+##     discard
+
+import typetraits
+
+
+type
+  Option*[T] = object
+    ## An optional type that stores its value and state separately in a boolean.
+    val: T
+    has: bool
+  UnpackError* = ref object of ValueError
+
+
+proc some*[T](val: T): Option[T] =
+  ## Returns a ``Option`` that has this value.
+  result.has = true
+  result.val = val
+
+proc none*(T: typedesc): Option[T] =
+  ## Returns a ``Option`` for this type that has no value.
+  result.has = false
+
+
+proc isSome*[T](self: Option[T]): bool =
+  self.has
+
+proc isNone*[T](self: Option[T]): bool =
+  not self.has
+
+
+proc unsafeGet*[T](self: Option[T]): T =
+  ## Returns the value of a ``some``. Behavior is undefined for ``none``.
+  assert self.isSome
+  self.val
+
+proc get*[T](self: Option[T]): T =
+  ## Returns contents of the Option. If it is none, then an exception is
+  ## thrown.
+  if self.isNone:
+    raise UnpackError(msg : "Can't obtain a value from a `none`")
+  self.val
+
+
+proc `==`*(a, b: Option): bool =
+  ## Returns ``true`` if both ``Option``s are ``none``,
+  ## or if they have equal values
+  (a.has and b.has and a.val == b.val) or (not a.has and not b.has)
+
+
+when isMainModule:
+  import unittest
+
+  suite "optionals":
+    # work around a bug in unittest
+    let intNone = none(int)
+    let stringNone = none(string)
+
+    test "example":
+      proc find(haystack: string, needle: char): Option[int] =
+        for i, c in haystack:
+          if c == needle:
+            return some i
+
+      check("abc".find('c').get() == 2)
+
+      let result = "team".find('i')
+
+      check result == intNone
+      check result.isNone
+
+    test "some":
+      check some(6).get() == 6
+      check some("a").unsafeGet() == "a"
+      check some(6).isSome
+      check some("a").isSome
+
+    test "none":
+      expect UnpackError:
+        discard none(int).get()
+      check(none(int).isNone)
+      check(not none(string).isSome)
+
+    test "equality":
+      check some("a") == some("a")
+      check some(7) != some(6)
+      check some("a") != stringNone
+      check intNone == intNone
+
+      when compiles(some("a") == some(5)):
+        check false
+      when compiles(none(string) == none(int)):
+        check false
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
new file mode 100644
index 000000000..3a5bcbfa1
--- /dev/null
+++ b/lib/pure/os.nim
@@ -0,0 +1,2068 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains basic operating system facilities like
+## retrieving environment variables, reading command line arguments,
+## working with directories, running shell commands, etc.
+{.deadCodeElim: on.}
+
+{.push debugger: off.}
+
+include "system/inclrtl"
+
+import
+  strutils, times
+
+when defined(windows):
+  import winlean
+elif defined(posix):
+  import posix
+else:
+  {.error: "OS module not ported to your operating system!".}
+
+include "system/ansi_c"
+
+type
+  ReadEnvEffect* = object of ReadIOEffect   ## effect that denotes a read
+                                            ## from an environment variable
+  WriteEnvEffect* = object of WriteIOEffect ## effect that denotes a write
+                                            ## to an environment variable
+
+  ReadDirEffect* = object of ReadIOEffect   ## effect that denotes a write
+                                            ## operation to the directory structure
+  WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to
+                                            ## the directory structure
+
+  OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
+
+{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect, 
+    FReadDir: ReadDirEffect,
+    FWriteDir: WriteDirEffect,
+    TOSErrorCode: OSErrorCode
+].}
+const
+  doslike = defined(windows) or defined(OS2) or defined(DOS)
+    # DOS-like filesystem
+
+when defined(Nimdoc): # only for proper documentation:
+  const
+    CurDir* = '.'
+      ## The constant string used by the operating system to refer to the
+      ## current directory.
+      ##
+      ## For example: '.' for POSIX or ':' for the classic Macintosh.
+
+    ParDir* = ".."
+      ## The constant string used by the operating system to refer to the
+      ## parent directory.
+      ##
+      ## For example: ".." for POSIX or "::" for the classic Macintosh.
+
+    DirSep* = '/'
+      ## The character used by the operating system to separate pathname
+      ## components, for example, '/' for POSIX or ':' for the classic
+      ## Macintosh.
+
+    AltSep* = '/'
+      ## An alternative character used by the operating system to separate
+      ## pathname components, or the same as `DirSep` if only one separator
+      ## character exists. This is set to '/' on Windows systems where `DirSep`
+      ## is a backslash.
+
+    PathSep* = ':'
+      ## The character conventionally used by the operating system to separate
+      ## search patch components (as in PATH), such as ':' for POSIX or ';' for
+      ## Windows.
+
+    FileSystemCaseSensitive* = true
+      ## True if the file system is case sensitive, false otherwise. Used by
+      ## `cmpPaths` to compare filenames properly.
+
+    ExeExt* = ""
+      ## The file extension of native executables. For example:
+      ## "" for POSIX, "exe" on Windows.
+
+    ScriptExt* = ""
+      ## The file extension of a script file. For example: "" for POSIX,
+      ## "bat" on Windows.
+
+    DynlibFormat* = "lib$1.so"
+      ## The format string to turn a filename into a `DLL`:idx: file (also
+      ## called `shared object`:idx: on some operating systems).
+
+elif defined(macos):
+  const
+    CurDir* = ':'
+    ParDir* = "::"
+    DirSep* = ':'
+    AltSep* = Dirsep
+    PathSep* = ','
+    FileSystemCaseSensitive* = false
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = "$1.dylib"
+
+  #  MacOS paths
+  #  ===========
+  #  MacOS directory separator is a colon ":" which is the only character not
+  #  allowed in filenames.
+  #
+  #  A path containing no colon or which begins with a colon is a partial path.
+  #  E.g. ":kalle:petter" ":kalle" "kalle"
+  #
+  #  All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
+  #  When generating paths, one is safe if one ensures that all partial paths
+  #  begin with a colon, and all full paths end with a colon.
+  #  In full paths the first name (e g HD above) is the name of a mounted
+  #  volume.
+  #  These names are not unique, because, for instance, two diskettes with the
+  #  same names could be inserted. This means that paths on MacOS are not
+  #  waterproof. In case of equal names the first volume found will do.
+  #  Two colons "::" are the relative path to the parent. Three is to the
+  #  grandparent etc.
+elif doslike:
+  const
+    CurDir* = '.'
+    ParDir* = ".."
+    DirSep* = '\\' # seperator within paths
+    AltSep* = '/'
+    PathSep* = ';' # seperator between paths
+    FileSystemCaseSensitive* = false
+    ExeExt* = "exe"
+    ScriptExt* = "bat"
+    DynlibFormat* = "$1.dll"
+elif defined(PalmOS) or defined(MorphOS):
+  const
+    DirSep* = '/'
+    AltSep* = Dirsep
+    PathSep* = ';'
+    ParDir* = ".."
+    FileSystemCaseSensitive* = false
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = "$1.prc"
+elif defined(RISCOS):
+  const
+    DirSep* = '.'
+    AltSep* = '.'
+    ParDir* = ".." # is this correct?
+    PathSep* = ','
+    FileSystemCaseSensitive* = true
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = "lib$1.so"
+else: # UNIX-like operating system
+  const
+    CurDir* = '.'
+    ParDir* = ".."
+    DirSep* = '/'
+    AltSep* = DirSep
+    PathSep* = ':'
+    FileSystemCaseSensitive* = true
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
+
+when defined(posix):
+  when NoFakeVars:
+    const pathMax = 5000 # doesn't matter really. The concept of PATH_MAX
+                         # doesn't work anymore on modern OSes.
+  else:
+    var
+      pathMax {.importc: "PATH_MAX", header: "<stdlib.h>".}: cint
+
+const
+  ExtSep* = '.'
+    ## The character which separates the base filename from the extension;
+    ## for example, the '.' in ``os.nim``.
+
+proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
+  ## Retrieves the operating system's error flag, ``errno``.
+  ## On Windows ``GetLastError`` is checked before ``errno``.
+  ## Returns "" if no error occurred.
+  ##
+  ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc.
+
+  result = ""
+  when defined(Windows):
+    var err = getLastError()
+    if err != 0'i32:
+      when useWinUnicode:
+        var msgbuf: WideCString
+        if formatMessageW(0x00000100 or 0x00001000 or 0x00000200,
+                          nil, err, 0, addr(msgbuf), 0, nil) != 0'i32:
+          result = $msgbuf
+          if msgbuf != nil: localFree(cast[pointer](msgbuf))
+      else:
+        var msgbuf: cstring
+        if formatMessageA(0x00000100 or 0x00001000 or 0x00000200,
+                          nil, err, 0, addr(msgbuf), 0, nil) != 0'i32:
+          result = $msgbuf
+          if msgbuf != nil: localFree(msgbuf)
+  if errno != 0'i32:
+    result = $os.strerror(errno)
+
+{.push warning[deprecated]: off.}
+proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1",
+                                       deprecated.} =
+  ## raises an OSError exception with the given message ``msg``.
+  ## If ``msg == ""``, the operating system's error flag
+  ## (``errno``) is converted to a readable error message. On Windows
+  ## ``GetLastError`` is checked before ``errno``.
+  ## If no error flag is set, the message ``unknown OS error`` is used.
+  ##
+  ## **Deprecated since version 0.9.4**: use the other ``raiseOSError`` proc.
+  if len(msg) == 0:
+    var m = osErrorMsg()
+    raise newException(OSError, if m.len > 0: m else: "unknown OS error")
+  else:
+    raise newException(OSError, msg)
+{.pop.}
+
+when not defined(nimfix):
+  {.deprecated: [osError: raiseOSError].}
+
+proc `==`*(err1, err2: OSErrorCode): bool {.borrow.}
+proc `$`*(err: OSErrorCode): string {.borrow.}
+
+proc osErrorMsg*(errorCode: OSErrorCode): string =
+  ## Converts an OS error code into a human readable string.
+  ##
+  ## The error code can be retrieved using the ``osLastError`` proc.
+  ##
+  ## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be
+  ## returned.
+  ##
+  ## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to
+  ## make this procedure use the non-unicode Win API calls to retrieve the
+  ## message.
+  result = ""
+  when defined(Windows):
+    if errorCode != OSErrorCode(0'i32):
+      when useWinUnicode:
+        var msgbuf: WideCString
+        if formatMessageW(0x00000100 or 0x00001000 or 0x00000200,
+                        nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
+          result = $msgbuf
+          if msgbuf != nil: localFree(cast[pointer](msgbuf))
+      else:
+        var msgbuf: cstring
+        if formatMessageA(0x00000100 or 0x00001000 or 0x00000200,
+                        nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
+          result = $msgbuf
+          if msgbuf != nil: localFree(msgbuf)
+  else:
+    if errorCode != OSErrorCode(0'i32):
+      result = $os.strerror(errorCode.int32)
+
+proc raiseOSError*(errorCode: OSErrorCode) =
+  ## Raises an ``OSError`` exception. The ``errorCode`` will determine the
+  ## message, ``osErrorMsg`` will be used to get this message.
+  ##
+  ## The error code can be retrieved using the ``osLastError`` proc.
+  ##
+  ## If the error code is ``0`` or an error message could not be retrieved,
+  ## the message ``unknown OS error`` will be used.
+  var e: ref OSError; new(e)
+  e.errorCode = errorCode.int32
+  e.msg = osErrorMsg(errorCode)
+  if e.msg == "":
+    e.msg = "unknown OS error"
+  raise e
+
+{.push stackTrace:off.}
+proc osLastError*(): OSErrorCode =
+  ## Retrieves the last operating system error code.
+  ##
+  ## This procedure is useful in the event when an OS call fails. In that case
+  ## this procedure will return the error code describing the reason why the
+  ## OS call failed. The ``OSErrorMsg`` procedure can then be used to convert
+  ## this code into a string.
+  ##
+  ## **Warning**:
+  ## The behaviour of this procedure varies between Windows and POSIX systems.
+  ## On Windows some OS calls can reset the error code to ``0`` causing this
+  ## procedure to return ``0``. It is therefore advised to call this procedure
+  ## immediately after an OS call fails. On POSIX systems this is not a problem.
+
+  when defined(windows):
+    result = OSErrorCode(getLastError())
+  else:
+    result = OSErrorCode(errno)
+{.pop.}
+
+proc unixToNativePath*(path: string, drive=""): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Converts an UNIX-like path to a native one.
+  ##
+  ## On an UNIX system this does nothing. Else it converts
+  ## '/', '.', '..' to the appropriate things.
+  ##
+  ## On systems with a concept of "drives", `drive` is used to determine
+  ## which drive label to use during absolute path conversion.
+  ## `drive` defaults to the drive of the current working directory, and is
+  ## ignored on systems that do not have a concept of "drives".
+
+  when defined(unix):
+    result = path
+  else:
+    var start: int
+    if path[0] == '/':
+      # an absolute path
+      when doslike:
+        if drive != "":
+          result = drive & ":" & DirSep
+        else:
+          result = $DirSep
+      elif defined(macos):
+        result = "" # must not start with ':'
+      else:
+        result = $DirSep
+      start = 1
+    elif path[0] == '.' and path[1] == '/':
+      # current directory
+      result = $CurDir
+      start = 2
+    else:
+      result = ""
+      start = 0
+
+    var i = start
+    while i < len(path): # ../../../ --> ::::
+      if path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
+        # parent directory
+        when defined(macos):
+          if result[high(result)] == ':':
+            add result, ':'
+          else:
+            add result, ParDir
+        else:
+          add result, ParDir & DirSep
+        inc(i, 3)
+      elif path[i] == '/':
+        add result, DirSep
+        inc(i)
+      else:
+        add result, path[i]
+        inc(i)
+
+when defined(windows):
+  when useWinUnicode:
+    template wrapUnary(varname, winApiProc, arg: expr) {.immediate.} =
+      var varname = winApiProc(newWideCString(arg))
+
+    template wrapBinary(varname, winApiProc, arg, arg2: expr) {.immediate.} =
+      var varname = winApiProc(newWideCString(arg), arg2)
+    proc findFirstFile(a: string, b: var TWIN32_FIND_DATA): THandle =
+      result = findFirstFileW(newWideCString(a), b)
+    template findNextFile(a, b: expr): expr = findNextFileW(a, b)
+    template getCommandLine(): expr = getCommandLineW()
+
+    template getFilename(f: expr): expr =
+      $cast[WideCString](addr(f.cFilename[0]))
+  else:
+    template findFirstFile(a, b: expr): expr = findFirstFileA(a, b)
+    template findNextFile(a, b: expr): expr = findNextFileA(a, b)
+    template getCommandLine(): expr = getCommandLineA()
+
+    template getFilename(f: expr): expr = $f.cFilename
+
+  proc skipFindData(f: TWIN32_FIND_DATA): bool {.inline.} =
+    # Note - takes advantage of null delimiter in the cstring
+    const dot = ord('.')
+    result = f.cFileName[0].int == dot and (f.cFileName[1].int == 0 or
+             f.cFileName[1].int == dot and f.cFileName[2].int == 0)
+
+proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
+                                          tags: [ReadDirEffect].} =
+  ## Returns true if the file exists, false otherwise.
+  when defined(windows):
+    when useWinUnicode:
+      wrapUnary(a, getFileAttributesW, filename)
+    else:
+      var a = getFileAttributesA(filename)
+    if a != -1'i32:
+      result = (a and FILE_ATTRIBUTE_DIRECTORY) == 0'i32
+  else:
+    var res: TStat
+    return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
+
+proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect].} =
+  ## Returns true iff the directory `dir` exists. If `dir` is a file, false
+  ## is returned.
+  when defined(windows):
+    when useWinUnicode:
+      wrapUnary(a, getFileAttributesW, dir)
+    else:
+      var a = getFileAttributesA(dir)
+    if a != -1'i32:
+      result = (a and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
+  else:
+    var res: TStat
+    return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
+
+proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
+                                          tags: [ReadDirEffect].} =
+  ## Returns true iff the symlink `link` exists. Will return true
+  ## regardless of whether the link points to a directory or file.
+  when defined(windows):
+    when useWinUnicode:
+      wrapUnary(a, getFileAttributesW, link)
+    else:
+      var a = getFileAttributesA(link)
+    if a != -1'i32:
+      result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
+  else:
+    var res: TStat
+    return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
+
+proc fileExists*(filename: string): bool {.inline.} =
+  ## Synonym for existsFile
+  existsFile(filename)
+
+proc dirExists*(dir: string): bool {.inline.} =
+  ## Synonym for existsDir
+  existsDir(dir)
+
+proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} =
+  ## Returns the `file`'s last modification time.
+  when defined(posix):
+    var res: TStat
+    if stat(file, res) < 0'i32: raiseOSError(osLastError())
+    return res.st_mtime
+  else:
+    var f: TWIN32_FIND_DATA
+    var h = findFirstFile(file, f)
+    if h == -1'i32: raiseOSError(osLastError())
+    result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
+    findClose(h)
+
+proc getLastAccessTime*(file: string): Time {.rtl, extern: "nos$1".} =
+  ## Returns the `file`'s last read or write access time.
+  when defined(posix):
+    var res: TStat
+    if stat(file, res) < 0'i32: raiseOSError(osLastError())
+    return res.st_atime
+  else:
+    var f: TWIN32_FIND_DATA
+    var h = findFirstFile(file, f)
+    if h == -1'i32: raiseOSError(osLastError())
+    result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
+    findClose(h)
+
+proc getCreationTime*(file: string): Time {.rtl, extern: "nos$1".} =
+  ## Returns the `file`'s creation time.
+  ## Note that under posix OS's, the returned time may actually be the time at
+  ## which the file's attribute's were last modified.
+  when defined(posix):
+    var res: TStat
+    if stat(file, res) < 0'i32: raiseOSError(osLastError())
+    return res.st_ctime
+  else:
+    var f: TWIN32_FIND_DATA
+    var h = findFirstFile(file, f)
+    if h == -1'i32: raiseOSError(osLastError())
+    result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
+    findClose(h)
+
+proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
+  ## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s
+  ## modification time is later than `b`'s.
+  when defined(posix):
+    result = getLastModificationTime(a) - getLastModificationTime(b) >= 0
+    # Posix's resolution sucks so, we use '>=' for posix.
+  else:
+    result = getLastModificationTime(a) - getLastModificationTime(b) > 0
+
+proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
+  ## Returns the `current working directory`:idx:.
+  const bufsize = 512 # should be enough
+  when defined(windows):
+    when useWinUnicode:
+      var res = newWideCString("", bufsize)
+      var L = getCurrentDirectoryW(bufsize, res)
+      if L == 0'i32: raiseOSError(osLastError())
+      result = res$L
+    else:
+      result = newString(bufsize)
+      var L = getCurrentDirectoryA(bufsize, result)
+      if L == 0'i32: raiseOSError(osLastError())
+      setLen(result, L)
+  else:
+    result = newString(bufsize)
+    if getcwd(result, bufsize) != nil:
+      setLen(result, c_strlen(result))
+    else:
+      raiseOSError(osLastError())
+
+proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
+  ## Sets the `current working directory`:idx:; `OSError` is raised if
+  ## `newDir` cannot been set.
+  when defined(Windows):
+    when useWinUnicode:
+      if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32:
+        raiseOSError(osLastError())
+    else:
+      if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError())
+  else:
+    if chdir(newDir) != 0'i32: raiseOSError(osLastError())
+
+proc joinPath*(head, tail: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Joins two directory names to one.
+  ##
+  ## For example on Unix:
+  ##
+  ## .. code-block:: nim
+  ##   joinPath("usr", "lib")
+  ##
+  ## results in:
+  ##
+  ## .. code-block:: nim
+  ##   "usr/lib"
+  ##
+  ## If head is the empty string, tail is returned. If tail is the empty
+  ## string, head is returned with a trailing path separator. If tail starts
+  ## with a path separator it will be removed when concatenated to head. Other
+  ## path separators not located on boundaries won't be modified. More
+  ## examples on Unix:
+  ##
+  ## .. code-block:: nim
+  ##   assert joinPath("usr", "") == "usr/"
+  ##   assert joinPath("", "lib") == "lib"
+  ##   assert joinPath("", "/lib") == "/lib"
+  ##   assert joinPath("usr/", "/lib") == "usr/lib"
+  if len(head) == 0:
+    result = tail
+  elif head[len(head)-1] in {DirSep, AltSep}:
+    if tail[0] in {DirSep, AltSep}:
+      result = head & substr(tail, 1)
+    else:
+      result = head & tail
+  else:
+    if tail[0] in {DirSep, AltSep}:
+      result = head & tail
+    else:
+      result = head & DirSep & tail
+
+proc joinPath*(parts: varargs[string]): string {.noSideEffect,
+  rtl, extern: "nos$1OpenArray".} =
+  ## The same as `joinPath(head, tail)`, but works with any number of directory
+  ## parts. You need to pass at least one element or the proc will assert in
+  ## debug builds and crash on release builds.
+  result = parts[0]
+  for i in 1..high(parts):
+    result = joinPath(result, parts[i])
+
+proc `/` * (head, tail: string): string {.noSideEffect.} =
+  ## The same as ``joinPath(head, tail)``
+  ##
+  ## Here are some examples for Unix:
+  ##
+  ## .. code-block:: nim
+  ##   assert "usr" / "" == "usr/"
+  ##   assert "" / "lib" == "lib"
+  ##   assert "" / "/lib" == "/lib"
+  ##   assert "usr/" / "/lib" == "usr/lib"
+  return joinPath(head, tail)
+
+proc splitPath*(path: string): tuple[head, tail: string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Splits a directory into (head, tail), so that
+  ## ``head / tail == path`` (except for edge cases like "/usr").
+  ##
+  ## Examples:
+  ##
+  ## .. code-block:: nim
+  ##   splitPath("usr/local/bin") -> ("usr/local", "bin")
+  ##   splitPath("usr/local/bin/") -> ("usr/local/bin", "")
+  ##   splitPath("bin") -> ("", "bin")
+  ##   splitPath("/bin") -> ("", "bin")
+  ##   splitPath("") -> ("", "")
+  var sepPos = -1
+  for i in countdown(len(path)-1, 0):
+    if path[i] in {DirSep, AltSep}:
+      sepPos = i
+      break
+  if sepPos >= 0:
+    result.head = substr(path, 0, sepPos-1)
+    result.tail = substr(path, sepPos+1)
+  else:
+    result.head = ""
+    result.tail = path
+
+proc parentDirPos(path: string): int =
+  var q = 1
+  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
+  for i in countdown(len(path)-q, 0):
+    if path[i] in {DirSep, AltSep}: return i
+  result = -1
+
+proc parentDir*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Returns the parent directory of `path`.
+  ##
+  ## This is often the same as the ``head`` result of ``splitPath``.
+  ## If there is no parent, "" is returned.
+  ## | Example: ``parentDir("/usr/local/bin") == "/usr/local"``.
+  ## | Example: ``parentDir("/usr/local/bin/") == "/usr/local"``.
+  let sepPos = parentDirPos(path)
+  if sepPos >= 0:
+    result = substr(path, 0, sepPos-1)
+  else:
+    result = ""
+
+proc isRootDir*(path: string): bool {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Checks whether a given `path` is a root directory
+  result = parentDirPos(path) < 0
+
+iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string =
+  ## Walks over all parent directories of a given `path`
+  ##
+  ## If `fromRoot` is set, the traversal will start from the file system root
+  ## diretory. If `inclusive` is set, the original argument will be included
+  ## in the traversal.
+  ##
+  ## Relative paths won't be expanded by this proc. Instead, it will traverse
+  ## only the directories appearing in the relative path.
+  if not fromRoot:
+    var current = path
+    if inclusive: yield path
+    while true:
+      if current.isRootDir: break
+      current = current.parentDir
+      yield current
+  else:
+    for i in countup(0, path.len - 2): # ignore the last /
+      # deal with non-normalized paths such as /foo//bar//baz
+      if path[i] in {DirSep, AltSep} and
+          (i == 0 or path[i-1] notin {DirSep, AltSep}):
+        yield path.substr(0, i)
+
+    if inclusive: yield path
+
+proc `/../` * (head, tail: string): string {.noSideEffect.} =
+  ## The same as ``parentDir(head) / tail`` unless there is no parent directory.
+  ## Then ``head / tail`` is performed instead.
+  let sepPos = parentDirPos(head)
+  if sepPos >= 0:
+    result = substr(head, 0, sepPos-1) / tail
+  else:
+    result = head / tail
+
+proc normExt(ext: string): string =
+  if ext == "" or ext[0] == ExtSep: result = ext # no copy needed here
+  else: result = ExtSep & ext
+
+proc searchExtPos(s: string): int =
+  # BUGFIX: do not search until 0! .DS_Store is no file extension!
+  result = -1
+  for i in countdown(len(s)-1, 1):
+    if s[i] == ExtSep:
+      result = i
+      break
+    elif s[i] in {DirSep, AltSep}:
+      break # do not skip over path
+
+proc splitFile*(path: string): tuple[dir, name, ext: string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Splits a filename into (dir, filename, extension).
+  ## `dir` does not end in `DirSep`.
+  ## `extension` includes the leading dot.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var (dir, name, ext) = splitFile("usr/local/nimc.html")
+  ##   assert dir == "usr/local"
+  ##   assert name == "nimc"
+  ##   assert ext == ".html"
+  ##
+  ## If `path` has no extension, `ext` is the empty string.
+  ## If `path` has no directory component, `dir` is the empty string.
+  ## If `path` has no filename component, `name` and `ext` are empty strings.
+  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
+    result = (path, "", "")
+  else:
+    var sepPos = -1
+    var dotPos = path.len
+    for i in countdown(len(path)-1, 0):
+      if path[i] == ExtSep:
+        if dotPos == path.len and i > 0 and
+            path[i-1] notin {DirSep, AltSep}: dotPos = i
+      elif path[i] in {DirSep, AltSep}:
+        sepPos = i
+        break
+    result.dir = substr(path, 0, sepPos-1)
+    result.name = substr(path, sepPos+1, dotPos-1)
+    result.ext = substr(path, dotPos)
+
+proc extractFilename*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Extracts the filename of a given `path`. This is the same as
+  ## ``name & ext`` from ``splitFile(path)``.
+  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
+    result = ""
+  else:
+    result = splitPath(path).tail
+
+proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
+  tags: [ReadDirEffect].} =
+  ## Returns the full path of `filename`, raises OSError in case of an error.
+  when defined(windows):
+    const bufsize = 3072'i32
+    when useWinUnicode:
+      var unused: WideCString
+      var res = newWideCString("", bufsize div 2)
+      var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused)
+      if L <= 0'i32 or L >= bufsize:
+        raiseOSError(osLastError())
+      result = res$L
+    else:
+      var unused: cstring
+      result = newString(bufsize)
+      var L = getFullPathNameA(filename, bufsize, result, unused)
+      if L <= 0'i32 or L >= bufsize: raiseOSError(osLastError())
+      setLen(result, L)
+  else:
+    # careful, realpath needs to take an allocated buffer according to Posix:
+    result = newString(pathMax)
+    var r = realpath(filename, result)
+    if r.isNil: raiseOSError(osLastError())
+    setLen(result, c_strlen(result))
+
+proc changeFileExt*(filename, ext: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Changes the file extension to `ext`.
+  ##
+  ## If the `filename` has no extension, `ext` will be added.
+  ## If `ext` == "" then any extension is removed.
+  ## `Ext` should be given without the leading '.', because some
+  ## filesystems may use a different character. (Although I know
+  ## of none such beast.)
+  var extPos = searchExtPos(filename)
+  if extPos < 0: result = filename & normExt(ext)
+  else: result = substr(filename, 0, extPos-1) & normExt(ext)
+
+proc addFileExt*(filename, ext: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Adds the file extension `ext` to `filename`, unless
+  ## `filename` already has an extension.
+  ##
+  ## `Ext` should be given without the leading '.', because some
+  ## filesystems may use a different character.
+  ## (Although I know of none such beast.)
+  var extPos = searchExtPos(filename)
+  if extPos < 0: result = filename & normExt(ext)
+  else: result = filename
+
+proc cmpPaths*(pathA, pathB: string): int {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Compares two paths.
+  ##
+  ## On a case-sensitive filesystem this is done
+  ## case-sensitively otherwise case-insensitively. Returns:
+  ##
+  ## | 0 iff pathA == pathB
+  ## | < 0 iff pathA < pathB
+  ## | > 0 iff pathA > pathB
+  if FileSystemCaseSensitive:
+    result = cmp(pathA, pathB)
+  else:
+    result = cmpIgnoreCase(pathA, pathB)
+
+proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
+  ## Checks whether a given `path` is absolute.
+  ##
+  ## On Windows, network paths are considered absolute too.
+  when doslike:
+    var len = len(path)
+    result = (len > 1 and path[0] in {'/', '\\'}) or
+             (len > 2 and path[0] in Letters and path[1] == ':')
+  elif defined(macos):
+    result = path.len > 0 and path[0] != ':'
+  elif defined(RISCOS):
+    result = path[0] == '$'
+  elif defined(posix):
+    result = path[0] == '/'
+
+when defined(Windows):
+  proc openHandle(path: string, followSymlink=true): THandle =
+    var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
+    if not followSymlink:
+      flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
+
+    when useWinUnicode:
+      result = createFileW(
+        newWideCString(path), 0'i32, 
+        FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
+        nil, OPEN_EXISTING, flags, 0
+        )
+    else:
+      result = createFileA(
+        path, 0'i32, 
+        FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
+        nil, OPEN_EXISTING, flags, 0
+        )
+
+proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
+  tags: [ReadDirEffect].} =
+  ## Returns True if both pathname arguments refer to the same physical
+  ## file or directory. Raises an exception if any of the files does not
+  ## exist or information about it can not be obtained.
+  ##
+  ## This proc will return true if given two alternative hard-linked or
+  ## sym-linked paths to the same file or directory.
+  when defined(Windows):
+    var success = true
+    var f1 = openHandle(path1)
+    var f2 = openHandle(path2)
+
+    var lastErr: OSErrorCode
+    if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
+      var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
+
+      if getFileInformationByHandle(f1, addr(fi1)) != 0 and
+         getFileInformationByHandle(f2, addr(fi2)) != 0:
+        result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
+                 fi1.nFileIndexHigh == fi2.nFileIndexHigh and
+                 fi1.nFileIndexLow == fi2.nFileIndexLow
+      else:
+        lastErr = osLastError()
+        success = false
+    else:
+      lastErr = osLastError()
+      success = false
+
+    discard closeHandle(f1)
+    discard closeHandle(f2)
+
+    if not success: raiseOSError(lastErr)
+  else:
+    var a, b: TStat
+    if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
+      raiseOSError(osLastError())
+    else:
+      result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
+
+proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1",
+  tags: [ReadIOEffect].} =
+  ## Returns True if both pathname arguments refer to files with identical
+  ## binary content.
+  const
+    bufSize = 8192 # 8K buffer
+  var
+    a, b: File
+  if not open(a, path1): return false
+  if not open(b, path2):
+    close(a)
+    return false
+  var bufA = alloc(bufSize)
+  var bufB = alloc(bufSize)
+  while true:
+    var readA = readBuffer(a, bufA, bufSize)
+    var readB = readBuffer(b, bufB, bufSize)
+    if readA != readB:
+      result = false
+      break
+    if readA == 0:
+      result = true
+      break
+    result = equalMem(bufA, bufB, readA)
+    if not result: break
+    if readA != bufSize: break # end of file
+  dealloc(bufA)
+  dealloc(bufB)
+  close(a)
+  close(b)
+
+type
+  FilePermission* = enum   ## file access permission; modelled after UNIX
+    fpUserExec,            ## execute access for the file owner
+    fpUserWrite,           ## write access for the file owner
+    fpUserRead,            ## read access for the file owner
+    fpGroupExec,           ## execute access for the group
+    fpGroupWrite,          ## write access for the group
+    fpGroupRead,           ## read access for the group
+    fpOthersExec,          ## execute access for others
+    fpOthersWrite,         ## write access for others
+    fpOthersRead           ## read access for others
+
+{.deprecated: [TFilePermission: FilePermission].}
+
+proc getFilePermissions*(filename: string): set[FilePermission] {.
+  rtl, extern: "nos$1", tags: [ReadDirEffect].} =
+  ## retrieves file permissions for `filename`. `OSError` is raised in case of
+  ## an error. On Windows, only the ``readonly`` flag is checked, every other
+  ## permission is available in any case.
+  when defined(posix):
+    var a: TStat
+    if stat(filename, a) < 0'i32: raiseOSError(osLastError())
+    result = {}
+    if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
+    if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
+    if (a.st_mode and S_IXUSR) != 0'i32: result.incl(fpUserExec)
+
+    if (a.st_mode and S_IRGRP) != 0'i32: result.incl(fpGroupRead)
+    if (a.st_mode and S_IWGRP) != 0'i32: result.incl(fpGroupWrite)
+    if (a.st_mode and S_IXGRP) != 0'i32: result.incl(fpGroupExec)
+
+    if (a.st_mode and S_IROTH) != 0'i32: result.incl(fpOthersRead)
+    if (a.st_mode and S_IWOTH) != 0'i32: result.incl(fpOthersWrite)
+    if (a.st_mode and S_IXOTH) != 0'i32: result.incl(fpOthersExec)
+  else:
+    when useWinUnicode:
+      wrapUnary(res, getFileAttributesW, filename)
+    else:
+      var res = getFileAttributesA(filename)
+    if res == -1'i32: raiseOSError(osLastError())
+    if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
+      result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, 
+                fpOthersExec, fpOthersRead}
+    else:
+      result = {fpUserExec..fpOthersRead}
+  
+proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
+  rtl, extern: "nos$1", tags: [WriteDirEffect].} =
+  ## sets the file permissions for `filename`. `OSError` is raised in case of
+  ## an error. On Windows, only the ``readonly`` flag is changed, depending on
+  ## ``fpUserWrite``.
+  when defined(posix):
+    var p = 0'i32
+    if fpUserRead in permissions: p = p or S_IRUSR
+    if fpUserWrite in permissions: p = p or S_IWUSR
+    if fpUserExec in permissions: p = p or S_IXUSR
+    
+    if fpGroupRead in permissions: p = p or S_IRGRP
+    if fpGroupWrite in permissions: p = p or S_IWGRP
+    if fpGroupExec in permissions: p = p or S_IXGRP
+    
+    if fpOthersRead in permissions: p = p or S_IROTH
+    if fpOthersWrite in permissions: p = p or S_IWOTH
+    if fpOthersExec in permissions: p = p or S_IXOTH
+    
+    if chmod(filename, p) != 0: raiseOSError(osLastError())
+  else:
+    when useWinUnicode:
+      wrapUnary(res, getFileAttributesW, filename)
+    else:
+      var res = getFileAttributesA(filename)
+    if res == -1'i32: raiseOSError(osLastError())
+    if fpUserWrite in permissions: 
+      res = res and not FILE_ATTRIBUTE_READONLY
+    else:
+      res = res or FILE_ATTRIBUTE_READONLY
+    when useWinUnicode:
+      wrapBinary(res2, setFileAttributesW, filename, res)
+    else:
+      var res2 = setFileAttributesA(filename, res)
+    if res2 == - 1'i32: raiseOSError(osLastError())
+
+proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
+  tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Copies a file from `source` to `dest`.
+  ##
+  ## If this fails, `OSError` is raised. On the Windows platform this proc will
+  ## copy the source file's attributes into dest. On other platforms you need
+  ## to use `getFilePermissions() <#getFilePermissions>`_ and
+  ## `setFilePermissions() <#setFilePermissions>`_ to copy them by hand (or use
+  ## the convenience `copyFileWithPermissions() <#copyFileWithPermissions>`_
+  ## proc), otherwise `dest` will inherit the default permissions of a newly
+  ## created file for the user. If `dest` already exists, the file attributes
+  ## will be preserved and the content overwritten.
+  when defined(Windows):
+    when useWinUnicode:
+      let s = newWideCString(source)
+      let d = newWideCString(dest)
+      if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError())
+    else:
+      if copyFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError())
+  else:
+    # generic version of copyFile which works for any platform:
+    const bufSize = 8000 # better for memory manager
+    var d, s: File
+    if not open(s, source): raiseOSError(osLastError())
+    if not open(d, dest, fmWrite):
+      close(s)
+      raiseOSError(osLastError())
+    var buf = alloc(bufSize)
+    while true:
+      var bytesread = readBuffer(s, buf, bufSize)
+      if bytesread > 0:
+        var byteswritten = writeBuffer(d, buf, bytesread)
+        if bytesread != byteswritten:
+          dealloc(buf)
+          close(s)
+          close(d)
+          raiseOSError(osLastError())
+      if bytesread != bufSize: break
+    dealloc(buf)
+    close(s)
+    close(d)
+
+proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
+  tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
+  when defined(Windows):
+    when useWinUnicode:
+      let s = newWideCString(source)
+      let d = newWideCString(dest)
+      if moveFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError())
+    else:
+      if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError())
+  else:
+    if c_rename(source, dest) != 0'i32:
+      raise newException(OSError, $strerror(errno))
+
+when not declared(ENOENT) and not defined(Windows):
+  when NoFakeVars:
+    const ENOENT = cint(2) # 2 on most systems including Solaris
+  else:
+    var ENOENT {.importc, header: "<errno.h>".}: cint
+
+when defined(Windows):
+  when useWinUnicode:
+    template deleteFile(file: expr): expr {.immediate.} = deleteFileW(file)
+    template setFileAttributes(file, attrs: expr): expr {.immediate.} = 
+      setFileAttributesW(file, attrs)
+  else:
+    template deleteFile(file: expr): expr {.immediate.} = deleteFileA(file)
+    template setFileAttributes(file, attrs: expr): expr {.immediate.} = 
+      setFileAttributesA(file, attrs)
+
+proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
+  ## Removes the `file`. If this fails, `OSError` is raised. This does not fail
+  ## if the file never existed in the first place.
+  ## On Windows, ignores the read-only attribute.
+  when defined(Windows):
+    when useWinUnicode:
+      let f = newWideCString(file)
+    else:
+      let f = file
+    if deleteFile(f) == 0:
+      if getLastError() == ERROR_ACCESS_DENIED: 
+        if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0:
+          raiseOSError(osLastError())
+        if deleteFile(f) == 0:
+          raiseOSError(osLastError())
+  else:
+    if c_remove(file) != 0'i32 and errno != ENOENT:
+      raise newException(OSError, $strerror(errno))
+
+proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
+  tags: [ExecIOEffect].} =
+  ## Executes a `shell command`:idx:.
+  ##
+  ## Command has the form 'program args' where args are the command
+  ## line arguments given to program. The proc returns the error code
+  ## of the shell when it has finished. The proc does not return until
+  ## the process has finished. To execute a program without having a
+  ## shell involved, use the `execProcess` proc of the `osproc`
+  ## module.
+  when defined(linux):
+    result = c_system(command) shr 8
+  else:
+    result = c_system(command)
+
+# Environment handling cannot be put into RTL, because the ``envPairs``
+# iterator depends on ``environment``.
+
+var
+  envComputed {.threadvar.}: bool
+  environment {.threadvar.}: seq[string]
+
+when defined(windows):
+  # because we support Windows GUI applications, things get really
+  # messy here...
+  when useWinUnicode:
+    when defined(cpp):
+      proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
+        importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".}
+    else:
+      proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
+        importc: "wcschr", header: "<string.h>".}
+  else:
+    proc strEnd(cstr: cstring, c = 0'i32): cstring {.
+      importc: "strchr", header: "<string.h>".}
+
+  proc getEnvVarsC() =
+    if not envComputed:
+      environment = @[]
+      when useWinUnicode:
+        var
+          env = getEnvironmentStringsW()
+          e = env
+        if e == nil: return # an error occurred
+        while true:
+          var eend = strEnd(e)
+          add(environment, $e)
+          e = cast[WideCString](cast[ByteAddress](eend)+2)
+          if eend[1].int == 0: break
+        discard freeEnvironmentStringsW(env)
+      else:
+        var
+          env = getEnvironmentStringsA()
+          e = env
+        if e == nil: return # an error occurred
+        while true:
+          var eend = strEnd(e)
+          add(environment, $e)
+          e = cast[cstring](cast[ByteAddress](eend)+1)
+          if eend[1] == '\0': break
+        discard freeEnvironmentStringsA(env)
+      envComputed = true
+
+else:
+  const
+    useNSGetEnviron = defined(macosx)
+
+  when useNSGetEnviron:
+    # From the manual:
+    # Shared libraries and bundles don't have direct access to environ,
+    # which is only available to the loader ld(1) when a complete program
+    # is being linked.
+    # The environment routines can still be used, but if direct access to
+    # environ is needed, the _NSGetEnviron() routine, defined in
+    # <crt_externs.h>, can be used to retrieve the address of environ
+    # at runtime.
+    proc NSGetEnviron(): ptr cstringArray {.
+      importc: "_NSGetEnviron", header: "<crt_externs.h>".}
+  else:
+    var gEnv {.importc: "environ".}: cstringArray
+
+  proc getEnvVarsC() =
+    # retrieves the variables of char** env of C's main proc
+    if not envComputed:
+      environment = @[]
+      when useNSGetEnviron:
+        var gEnv = NSGetEnviron()[]
+      var i = 0
+      while true:
+        if gEnv[i] == nil: break
+        add environment, $gEnv[i]
+        inc(i)
+      envComputed = true
+
+proc findEnvVar(key: string): int =
+  getEnvVarsC()
+  var temp = key & '='
+  for i in 0..high(environment):
+    if startsWith(environment[i], temp): return i
+  return -1
+
+proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} =
+  ## Returns the value of the `environment variable`:idx: named `key`.
+  ##
+  ## If the variable does not exist, "" is returned. To distinguish
+  ## whether a variable exists or it's value is just "", call
+  ## `existsEnv(key)`.
+  var i = findEnvVar(key)
+  if i >= 0:
+    return TaintedString(substr(environment[i], find(environment[i], '=')+1))
+  else:
+    var env = c_getenv(key)
+    if env == nil: return TaintedString("")
+    result = TaintedString($env)
+
+proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
+  ## Checks whether the environment variable named `key` exists.
+  ## Returns true if it exists, false otherwise.
+  if c_getenv(key) != nil: return true
+  else: return findEnvVar(key) >= 0
+
+proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
+  ## Sets the value of the `environment variable`:idx: named `key` to `val`.
+  ## If an error occurs, `EInvalidEnvVar` is raised.
+
+  # Note: by storing the string in the environment sequence,
+  # we guarantee that we don't free the memory before the program
+  # ends (this is needed for POSIX compliance). It is also needed so that
+  # the process itself may access its modified environment variables!
+  var indx = findEnvVar(key)
+  if indx >= 0:
+    environment[indx] = key & '=' & val
+  else:
+    add environment, (key & '=' & val)
+    indx = high(environment)
+  when defined(unix):
+    if c_putenv(environment[indx]) != 0'i32:
+      raiseOSError(osLastError())
+  else:
+    when useWinUnicode:
+      var k = newWideCString(key)
+      var v = newWideCString(val)
+      if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError())
+    else:
+      if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError())
+
+iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} =
+  ## Iterate over all `environments variables`:idx:. In the first component
+  ## of the tuple is the name of the current variable stored, in the second
+  ## its value.
+  getEnvVarsC()
+  for i in 0..high(environment):
+    var p = find(environment[i], '=')
+    yield (TaintedString(substr(environment[i], 0, p-1)),
+           TaintedString(substr(environment[i], p+1)))
+
+iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
+  ## Iterate over all the files that match the `pattern`. On POSIX this uses
+  ## the `glob`:idx: call.
+  ##
+  ## `pattern` is OS dependent, but at least the "\*.ext"
+  ## notation is supported.
+  when defined(windows):
+    var
+      f: TWIN32_FIND_DATA
+      res: int
+    res = findFirstFile(pattern, f)
+    if res != -1:
+      while true:
+        if not skipFindData(f) and
+            (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) == 0'i32:
+          yield splitFile(pattern).dir / extractFilename(getFilename(f))
+        if findNextFile(res, f) == 0'i32: break
+      findClose(res)
+  else: # here we use glob
+    var
+      f: TGlob
+      res: int
+    f.gl_offs = 0
+    f.gl_pathc = 0
+    f.gl_pathv = nil
+    res = glob(pattern, 0, nil, addr(f))
+    if res == 0:
+      for i in 0.. f.gl_pathc - 1:
+        assert(f.gl_pathv[i] != nil)
+        yield $f.gl_pathv[i]
+    globfree(addr(f))
+
+type
+  PathComponent* = enum   ## Enumeration specifying a path component.
+    pcFile,               ## path refers to a file
+    pcLinkToFile,         ## path refers to a symbolic link to a file
+    pcDir,                ## path refers to a directory
+    pcLinkToDir           ## path refers to a symbolic link to a directory
+
+{.deprecated: [TPathComponent: PathComponent].}
+
+iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {.
+  tags: [ReadDirEffect].} =
+  ## walks over the directory `dir` and yields for each directory or file in
+  ## `dir`. The component type and full path for each item is returned.
+  ## Walking is not recursive.
+  ## Example: This directory structure::
+  ##   dirA / dirB / fileB1.txt
+  ##        / dirC
+  ##        / fileA1.txt
+  ##        / fileA2.txt
+  ##
+  ## and this code:
+  ##
+  ## .. code-block:: Nim
+  ##     for kind, path in walkDir("dirA"):
+  ##       echo(path)
+  ##
+  ## produces this output (but not necessarily in this order!)::
+  ##   dirA/dirB
+  ##   dirA/dirC
+  ##   dirA/fileA1.txt
+  ##   dirA/fileA2.txt
+  when defined(windows):
+    var f: TWIN32_FIND_DATA
+    var h = findFirstFile(dir / "*", f)
+    if h != -1:
+      while true:
+        var k = pcFile
+        if not skipFindData(f):
+          if (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
+            k = pcDir
+          if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
+            k = succ(k)
+          yield (k, dir / extractFilename(getFilename(f)))
+        if findNextFile(h, f) == 0'i32: break
+      findClose(h)
+  else:
+    var d = opendir(dir)
+    if d != nil:
+      while true:
+        var x = readdir(d)
+        if x == nil: break
+        var y = $x.d_name
+        if y != "." and y != "..":
+          var s: TStat
+          y = dir / y
+          var k = pcFile
+
+          when defined(linux) or defined(macosx) or defined(bsd):
+            if x.d_type != DT_UNKNOWN:
+              if x.d_type == DT_DIR: k = pcDir
+              if x.d_type == DT_LNK: k = succ(k)
+              yield (k, y)
+              continue
+
+          if lstat(y, s) < 0'i32: break
+          if S_ISDIR(s.st_mode): k = pcDir
+          if S_ISLNK(s.st_mode): k = succ(k)
+          yield (k, y)
+      discard closedir(d)
+
+iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
+  tags: [ReadDirEffect].} =
+  ## walks over the directory `dir` and yields for each file in `dir`. The
+  ## full path for each file is returned.
+  ## **Warning**:
+  ## Modifying the directory structure while the iterator 
+  ## is traversing may result in undefined behavior! 
+  ## 
+  ## Walking is recursive. `filter` controls the behaviour of the iterator:
+  ##
+  ## ---------------------   ---------------------------------------------
+  ## filter                  meaning
+  ## ---------------------   ---------------------------------------------
+  ## ``pcFile``              yield real files
+  ## ``pcLinkToFile``        yield symbolic links to files
+  ## ``pcDir``               follow real directories
+  ## ``pcLinkToDir``         follow symbolic links to directories
+  ## ---------------------   ---------------------------------------------
+  ##
+  var stack = @[dir]
+  while stack.len > 0:
+    for k,p in walkDir(stack.pop()):
+      if k in filter:
+        case k
+        of pcFile, pcLinkToFile: yield p
+        of pcDir, pcLinkToDir: stack.add(p)
+
+proc rawRemoveDir(dir: string) =
+  when defined(windows):
+    when useWinUnicode:
+      wrapUnary(res, removeDirectoryW, dir)
+    else:
+      var res = removeDirectoryA(dir)
+    let lastError = osLastError()
+    if res == 0'i32 and lastError.int32 != 3'i32 and
+        lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
+      raiseOSError(lastError)
+  else:
+    if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
+
+proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
+  WriteDirEffect, ReadDirEffect], benign.} =
+  ## Removes the directory `dir` including all subdirectories and files
+  ## in `dir` (recursively).
+  ##
+  ## If this fails, `OSError` is raised. This does not fail if the directory never
+  ## existed in the first place.
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile, pcLinkToFile, pcLinkToDir: removeFile(path)
+    of pcDir: removeDir(path)
+  rawRemoveDir(dir)
+
+proc rawCreateDir(dir: string) =
+  when defined(solaris):
+    if mkdir(dir, 0o777) != 0'i32 and errno != EEXIST and errno != ENOSYS:
+      raiseOSError(osLastError())
+  elif defined(unix):
+    if mkdir(dir, 0o777) != 0'i32 and errno != EEXIST:
+      raiseOSError(osLastError())
+  else:
+    when useWinUnicode:
+      wrapUnary(res, createDirectoryW, dir)
+    else:
+      var res = createDirectoryA(dir)
+    if res == 0'i32 and getLastError() != 183'i32:
+      raiseOSError(osLastError())
+
+proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
+  ## Creates the `directory`:idx: `dir`.
+  ##
+  ## The directory may contain several subdirectories that do not exist yet.
+  ## The full path is created. If this fails, `OSError` is raised. It does **not**
+  ## fail if the path already exists because for most usages this does not
+  ## indicate an error.
+  var omitNext = false
+  when doslike:
+    omitNext = isAbsolute(dir)
+  for i in 1.. dir.len-1:
+    if dir[i] in {DirSep, AltSep}:
+      if omitNext:
+        omitNext = false
+      else:
+        rawCreateDir(substr(dir, 0, i-1))
+  rawCreateDir(dir)
+
+proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
+  tags: [WriteIOEffect, ReadIOEffect], benign.} =
+  ## Copies a directory from `source` to `dest`.
+  ##
+  ## If this fails, `OSError` is raised. On the Windows platform this proc will
+  ## copy the attributes from `source` into `dest`. On other platforms created
+  ## files and directories will inherit the default permissions of a newly
+  ## created file/directory for the user. To preserve attributes recursively on
+  ## these platforms use `copyDirWithPermissions() <#copyDirWithPermissions>`_.
+  createDir(dest)
+  for kind, path in walkDir(source):
+    var noSource = path.substr(source.len()+1)
+    case kind
+    of pcFile:
+      copyFile(path, dest / noSource)
+    of pcDir:
+      copyDir(path, dest / noSource)
+    else: discard
+
+proc createSymlink*(src, dest: string) =
+  ## Create a symbolic link at `dest` which points to the item specified
+  ## by `src`. On most operating systems, will fail if a lonk
+  ##
+  ## **Warning**:
+  ## Some OS's (such as Microsoft Windows) restrict the creation 
+  ## of symlinks to root users (administrators).
+  when defined(Windows):
+    let flag = dirExists(src).int32
+    when useWinUnicode:
+      var wSrc = newWideCString(src)
+      var wDst = newWideCString(dest)
+      if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0:
+        raiseOSError(osLastError())
+    else:
+      if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0:
+        raiseOSError(osLastError())
+  else:
+    if symlink(src, dest) != 0:
+      raiseOSError(osLastError())
+
+proc createHardlink*(src, dest: string) =
+  ## Create a hard link at `dest` which points to the item specified
+  ## by `src`.
+  ##
+  ## **Warning**: Most OS's restrict the creation of hard links to 
+  ## root users (administrators) .
+  when defined(Windows):
+    when useWinUnicode:
+      var wSrc = newWideCString(src)
+      var wDst = newWideCString(dest)
+      if createHardLinkW(wDst, wSrc, nil) == 0:
+        raiseOSError(osLastError())
+    else:
+      if createHardLinkA(dest, src, nil) == 0:
+        raiseOSError(osLastError())
+  else:
+    if link(src, dest) != 0:
+      raiseOSError(osLastError())
+
+proc parseCmdLine*(c: string): seq[string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Splits a command line into several components;
+  ## This proc is only occasionally useful, better use the `parseopt` module.
+  ##
+  ## On Windows, it uses the following parsing rules
+  ## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx ):
+  ##
+  ## * Arguments are delimited by white space, which is either a space or a tab.
+  ## * The caret character (^) is not recognized as an escape character or
+  ##   delimiter. The character is handled completely by the command-line parser
+  ##   in the operating system before being passed to the argv array in the
+  ##   program.
+  ## * A string surrounded by double quotation marks ("string") is interpreted
+  ##   as a single argument, regardless of white space contained within. A
+  ##   quoted string can be embedded in an argument.
+  ## * A double quotation mark preceded by a backslash (\") is interpreted as a
+  ##   literal double quotation mark character (").
+  ## * Backslashes are interpreted literally, unless they immediately precede
+  ##   a double quotation mark.
+  ## * If an even number of backslashes is followed by a double quotation mark,
+  ##   one backslash is placed in the argv array for every pair of backslashes,
+  ##   and the double quotation mark is interpreted as a string delimiter.
+  ## * If an odd number of backslashes is followed by a double quotation mark,
+  ##   one backslash is placed in the argv array for every pair of backslashes,
+  ##   and the double quotation mark is "escaped" by the remaining backslash,
+  ##   causing a literal double quotation mark (") to be placed in argv.
+  ##
+  ## On Posix systems, it uses the following parsing rules:
+  ## Components are separated by whitespace unless the whitespace
+  ## occurs within ``"`` or ``'`` quotes.
+  result = @[]
+  var i = 0
+  var a = ""
+  while true:
+    setLen(a, 0)
+    # eat all delimiting whitespace
+    while c[i] == ' ' or c[i] == '\t' or c [i] == '\l' or c [i] == '\r' : inc(i)
+    when defined(windows):
+      # parse a single argument according to the above rules:
+      if c[i] == '\0': break
+      var inQuote = false
+      while true:
+        case c[i]
+        of '\0': break
+        of '\\':
+          var j = i
+          while c[j] == '\\': inc(j)
+          if c[j] == '"':
+            for k in 1..(j-i) div 2: a.add('\\')
+            if (j-i) mod 2 == 0:
+              i = j
+            else:
+              a.add('"')
+              i = j+1
+          else:
+            a.add(c[i])
+            inc(i)
+        of '"':
+          inc(i)
+          if not inQuote: inQuote = true
+          elif c[i] == '"':
+            a.add(c[i])
+            inc(i)
+          else:
+            inQuote = false
+            break
+        of ' ', '\t':
+          if not inQuote: break
+          a.add(c[i])
+          inc(i)
+        else:
+          a.add(c[i])
+          inc(i)
+    else:
+      case c[i]
+      of '\'', '\"':
+        var delim = c[i]
+        inc(i) # skip ' or "
+        while c[i] != '\0' and c[i] != delim:
+          add a, c[i]
+          inc(i)
+        if c[i] != '\0': inc(i)
+      of '\0': break
+      else:
+        while c[i] > ' ':
+          add(a, c[i])
+          inc(i)
+    add(result, a)
+  
+proc copyFileWithPermissions*(source, dest: string,
+                              ignorePermissionErrors = true) =
+  ## Copies a file from `source` to `dest` preserving file permissions.
+  ##
+  ## This is a wrapper proc around `copyFile() <#copyFile>`_,
+  ## `getFilePermissions() <#getFilePermissions>`_ and `setFilePermissions()
+  ## <#setFilePermissions>`_ on non Windows platform. On Windows this proc is
+  ## just a wrapper for `copyFile() <#copyFile>`_ since that proc already
+  ## copies attributes.
+  ##
+  ## On non Windows systems permissions are copied after the file itself has
+  ## been copied, which won't happen atomically and could lead to a race
+  ## condition. If `ignorePermissionErrors` is true, errors while
+  ## reading/setting file attributes will be ignored, otherwise will raise
+  ## `OSError`.
+  copyFile(source, dest)
+  when not defined(Windows):
+    try:
+      setFilePermissions(dest, getFilePermissions(source))
+    except:
+      if not ignorePermissionErrors:
+        raise
+
+proc copyDirWithPermissions*(source, dest: string,
+    ignorePermissionErrors = true) {.rtl, extern: "nos$1",
+    tags: [WriteIOEffect, ReadIOEffect], benign.} =
+  ## Copies a directory from `source` to `dest` preserving file permissions.
+  ##
+  ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()
+  ## <#copyDir>`_ and `copyFileWithPermissions() <#copyFileWithPermissions>`_
+  ## on non Windows platforms. On Windows this proc is just a wrapper for
+  ## `copyDir() <#copyDir>`_ since that proc already copies attributes.
+  ##
+  ## On non Windows systems permissions are copied after the file or directory
+  ## itself has been copied, which won't happen atomically and could lead to a
+  ## race condition. If `ignorePermissionErrors` is true, errors while
+  ## reading/setting file attributes will be ignored, otherwise will raise
+  ## `OSError`.
+  createDir(dest)
+  when not defined(Windows):
+    try:
+      setFilePermissions(dest, getFilePermissions(source))
+    except:
+      if not ignorePermissionErrors:
+        raise
+  for kind, path in walkDir(source):
+    var noSource = path.substr(source.len()+1)
+    case kind
+    of pcFile:
+      copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors)
+    of pcDir:
+      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors)
+    else: discard
+
+proc inclFilePermissions*(filename: string,
+                          permissions: set[FilePermission]) {.
+  rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
+  ## a convenience procedure for:
+  ##
+  ## .. code-block:: nim
+  ##   setFilePermissions(filename, getFilePermissions(filename)+permissions)
+  setFilePermissions(filename, getFilePermissions(filename)+permissions)
+
+proc exclFilePermissions*(filename: string,
+                          permissions: set[FilePermission]) {.
+  rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
+  ## a convenience procedure for:
+  ##
+  ## .. code-block:: nim
+  ##   setFilePermissions(filename, getFilePermissions(filename)-permissions)
+  setFilePermissions(filename, getFilePermissions(filename)-permissions)
+
+proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  ## Returns the home directory of the current user.
+  ##
+  ## This proc is wrapped by the expandTilde proc for the convenience of
+  ## processing paths coming from user configuration files.
+  when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
+  else: return string(getEnv("HOME")) & "/"
+
+proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  ## Returns the config directory of the current user for applications.
+  when defined(windows): return string(getEnv("APPDATA")) & "\\"
+  else: return string(getEnv("HOME")) & "/.config/"
+
+proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} =
+  ## Returns the temporary directory of the current user for applications to
+  ## save temporary files in.
+  when defined(windows): return string(getEnv("TEMP")) & "\\"
+  else: return "/tmp/"
+
+when defined(nimdoc):
+  # Common forward declaration docstring block for parameter retrieval procs.
+  proc paramCount*(): int {.tags: [ReadIOEffect].} =
+    ## Returns the number of `command line arguments`:idx: given to the
+    ## application.
+    ##
+    ## If your binary was called without parameters this will return zero.  You
+    ## can later query each individual paramater with `paramStr() <#paramStr>`_
+    ## or retrieve all of them in one go with `commandLineParams()
+    ## <#commandLineParams>`_.
+    ##
+    ## **Availability**: On Posix there is no portable way to get the command
+    ## line from a DLL and thus the proc isn't defined in this environment. You
+    ## can test for its availability with `declared() <system.html#declared>`_.
+    ## Example:
+    ##
+    ## .. code-block:: nim
+    ##   when declared(paramCount):
+    ##     # Use paramCount() here
+    ##   else:
+    ##     # Do something else!
+
+  proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
+    ## Returns the `i`-th `command line argument`:idx: given to the application.
+    ##
+    ## `i` should be in the range `1..paramCount()`, the `EInvalidIndex`
+    ## exception will be raised for invalid values.  Instead of iterating over
+    ## `paramCount() <#paramCount>`_ with this proc you can call the
+    ## convenience `commandLineParams() <#commandLineParams>`_.
+    ##
+    ## It is possible to call ``paramStr(0)`` but this will return OS specific
+    ## contents (usually the name of the invoked executable). You should avoid
+    ## this and call `getAppFilename() <#getAppFilename>`_ instead.
+    ##
+    ## **Availability**: On Posix there is no portable way to get the command
+    ## line from a DLL and thus the proc isn't defined in this environment. You
+    ## can test for its availability with `declared() <system.html#declared>`_.
+    ## Example:
+    ##
+    ## .. code-block:: nim
+    ##   when declared(paramStr):
+    ##     # Use paramStr() here
+    ##   else:
+    ##     # Do something else!
+
+elif defined(windows):
+  # Since we support GUI applications with Nim, we sometimes generate
+  # a WinMain entry proc. But a WinMain proc has no access to the parsed
+  # command line arguments. The way to get them differs. Thus we parse them
+  # ourselves. This has the additional benefit that the program's behaviour
+  # is always the same -- independent of the used C compiler.
+  var
+    ownArgv {.threadvar.}: seq[string]
+
+  proc paramCount*(): int {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
+    # Docstring in nimdoc block.
+    if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
+    result = ownArgv.len-1
+
+  proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1",
+    tags: [ReadIOEffect].} =
+    # Docstring in nimdoc block.
+    if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine())
+    return TaintedString(ownArgv[i])
+
+elif not defined(createNimRtl):
+  # On Posix, there is no portable way to get the command line from a DLL.
+  var
+    cmdCount {.importc: "cmdCount".}: cint
+    cmdLine {.importc: "cmdLine".}: cstringArray
+
+  proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
+    # Docstring in nimdoc block.
+    if i < cmdCount and i >= 0: return TaintedString($cmdLine[i])
+    raise newException(IndexError, "invalid index")
+
+  proc paramCount*(): int {.tags: [ReadIOEffect].} =
+    # Docstring in nimdoc block.
+    result = cmdCount-1
+
+when declared(paramCount) or defined(nimdoc):
+  proc commandLineParams*(): seq[TaintedString] =
+    ## Convenience proc which returns the command line parameters.
+    ##
+    ## This returns **only** the parameters. If you want to get the application
+    ## executable filename, call `getAppFilename() <#getAppFilename>`_.
+    ##
+    ## **Availability**: On Posix there is no portable way to get the command
+    ## line from a DLL and thus the proc isn't defined in this environment. You
+    ## can test for its availability with `declared() <system.html#declared>`_.
+    ## Example:
+    ##
+    ## .. code-block:: nim
+    ##   when declared(commandLineParams):
+    ##     # Use commandLineParams() here
+    ##   else:
+    ##     # Do something else!
+    result = @[]
+    for i in 1..paramCount():
+      result.add(paramStr(i))
+
+when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
+  proc getApplAux(procPath: string): string =
+    result = newString(256)
+    var len = readlink(procPath, result, 256)
+    if len > 256:
+      result = newString(len+1)
+      len = readlink(procPath, result, len)
+    setLen(result, len)
+
+when not (defined(windows) or defined(macosx)):
+  proc getApplHeuristic(): string =
+    when declared(paramStr):
+      result = string(paramStr(0))
+      # POSIX guaranties that this contains the executable
+      # as it has been executed by the calling process
+      if len(result) > 0 and result[0] != DirSep: # not an absolute path?
+        # iterate over any path in the $PATH environment variable
+        for p in split(string(getEnv("PATH")), {PathSep}):
+          var x = joinPath(p, result)
+          if existsFile(x): return x
+    else:
+      result = ""
+
+when defined(macosx):
+  type
+    cuint32* {.importc: "unsigned int", nodecl.} = int
+    ## This is the same as the type ``uint32_t`` in *C*.
+
+  # a really hacky solution: since we like to include 2 headers we have to
+  # define two procs which in reality are the same
+  proc getExecPath1(c: cstring, size: var cuint32) {.
+    importc: "_NSGetExecutablePath", header: "<sys/param.h>".}
+  proc getExecPath2(c: cstring, size: var cuint32): bool {.
+    importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".}
+
+proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
+  ## Returns the filename of the application's executable.
+  ##
+  ## This procedure will resolve symlinks.
+  ##
+  ## **Note**: This does not work reliably on BSD.
+
+  # Linux: /proc/<pid>/exe
+  # Solaris:
+  # /proc/<pid>/object/a.out (filename only)
+  # /proc/<pid>/path/a.out (complete pathname)
+  # *BSD (and maybe Darwin too):
+  # /proc/<pid>/file
+  when defined(windows):
+    when useWinUnicode:
+      var buf = cast[WideCString](alloc(256*2))
+      var len = getModuleFileNameW(0, buf, 256)
+      result = buf$len
+    else:
+      result = newString(256)
+      var len = getModuleFileNameA(0, result, 256)
+      setlen(result, int(len))
+  elif defined(linux) or defined(aix):
+    result = getApplAux("/proc/self/exe")
+    if result.len == 0: result = getApplHeuristic()
+  elif defined(solaris):
+    result = getApplAux("/proc/" & $getpid() & "/path/a.out")
+    if result.len == 0: result = getApplHeuristic()
+  elif defined(freebsd):
+    result = getApplAux("/proc/" & $getpid() & "/file")
+    if result.len == 0: result = getApplHeuristic()
+  elif defined(macosx):
+    var size: cuint32
+    getExecPath1(nil, size)
+    result = newString(int(size))
+    if getExecPath2(result, size):
+      result = "" # error!
+    if result.len > 0:
+      result = result.expandFilename
+  else:
+    # little heuristic that may work on other POSIX-like systems:
+    result = string(getEnv("_"))
+    if result.len == 0: result = getApplHeuristic()
+
+proc getApplicationFilename*(): string {.rtl, extern: "nos$1", deprecated.} =
+  ## Returns the filename of the application's executable.
+  ## **Deprecated since version 0.8.12**: use ``getAppFilename``
+  ## instead.
+  result = getAppFilename()
+
+proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} =
+  ## Returns the directory of the application's executable.
+  ## **Deprecated since version 0.8.12**: use ``getAppDir``
+  ## instead.
+  result = splitFile(getAppFilename()).dir
+
+proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
+  ## Returns the directory of the application's executable.
+  ## **Note**: This does not work reliably on BSD.
+  result = splitFile(getAppFilename()).dir
+
+proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
+  ## sleeps `milsecs` milliseconds.
+  when defined(windows):
+    winlean.sleep(int32(milsecs))
+  else:
+    var a, b: Ttimespec
+    a.tv_sec = Time(milsecs div 1000)
+    a.tv_nsec = (milsecs mod 1000) * 1000 * 1000
+    discard posix.nanosleep(a, b)
+
+proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
+  tags: [ReadIOEffect].} =
+  ## returns the file size of `file`. Can raise ``OSError``.
+  when defined(windows):
+    var a: TWIN32_FIND_DATA
+    var resA = findFirstFile(file, a)
+    if resA == -1: raiseOSError(osLastError())
+    result = rdFileSize(a)
+    findClose(resA)
+  else:
+    var f: File
+    if open(f, file):
+      result = getFileSize(f)
+      close(f)
+    else: raiseOSError(osLastError())
+
+proc expandTilde*(path: string): string {.tags: [ReadEnvEffect].}
+
+proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} =
+  ## Searches for `exe` in the current working directory and then
+  ## in directories listed in the ``PATH`` environment variable.
+  ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe`
+  ## is added the `ExeExt <#ExeExt>`_ file extension if it has none.
+  result = addFileExt(exe, os.ExeExt)
+  if existsFile(result): return
+  var path = string(os.getEnv("PATH"))
+  for candidate in split(path, PathSep):
+    when defined(windows):
+      var x = candidate / result
+    else:
+      var x = expandTilde(candidate) / result
+    if existsFile(x): return x
+  result = ""
+
+proc expandTilde*(path: string): string =
+  ## Expands a path starting with ``~/`` to a full path.
+  ##
+  ## If `path` starts with the tilde character and is followed by `/` or `\\`
+  ## this proc will return the reminder of the path appended to the result of
+  ## the getHomeDir() proc, otherwise the input path will be returned without
+  ## modification.
+  ##
+  ## The behaviour of this proc is the same on the Windows platform despite not
+  ## having this convention. Example:
+  ##
+  ## .. code-block:: nim
+  ##   let configFile = expandTilde("~" / "appname.cfg")
+  ##   echo configFile
+  ##   # --> C:\Users\amber\appname.cfg
+  if len(path) > 1 and path[0] == '~' and (path[1] == '/' or path[1] == '\\'):
+    result = getHomeDir() / path[2..len(path)-1]
+  else:
+    result = path
+
+when defined(Windows):
+  type
+    DeviceId* = int32
+    FileId* = int64
+else:
+  type
+    DeviceId* = TDev
+    FileId* = Tino
+
+type
+  FileInfo* = object
+    ## Contains information associated with a file object.
+    id*: tuple[device: DeviceId, file: FileId] # Device and file id.
+    kind*: PathComponent # Kind of file object - directory, symlink, etc.
+    size*: BiggestInt # Size of file.
+    permissions*: set[FilePermission] # File permissions
+    linkCount*: BiggestInt # Number of hard links the file object has.
+    lastAccessTime*: Time # Time file was last accessed.
+    lastWriteTime*: Time # Time file was last modified/written to.
+    creationTime*: Time # Time file was created. Not supported on all systems!
+
+template rawToFormalFileInfo(rawInfo, formalInfo): expr =
+  ## Transforms the native file info structure into the one nim uses.
+  ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
+  ## or a 'TStat' structure on posix
+  when defined(Windows):
+    template toTime(e): expr = winTimeToUnixTime(rdFileTime(e))
+    template merge(a, b): expr = a or (b shl 32)
+    formalInfo.id.device = rawInfo.dwVolumeSerialNumber
+    formalInfo.id.file = merge(rawInfo.nFileIndexLow, rawInfo.nFileIndexHigh)
+    formalInfo.size = merge(rawInfo.nFileSizeLow, rawInfo.nFileSizeHigh)
+    formalInfo.linkCount = rawInfo.nNumberOfLinks
+    formalInfo.lastAccessTime = toTime(rawInfo.ftLastAccessTime)
+    formalInfo.lastWriteTime = toTime(rawInfo.ftLastWriteTime)
+    formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
+    
+    # Retrieve basic permissions
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
+      formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec, 
+                                fpGroupRead, fpOthersExec, fpOthersRead}
+    else:
+      result.permissions = {fpUserExec..fpOthersRead}
+
+    # Retrieve basic file kind
+    result.kind = pcFile
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
+      formalInfo.kind = pcDir
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
+      formalInfo.kind = succ(result.kind)
+
+
+  else:
+    template checkAndIncludeMode(rawMode, formalMode: expr) = 
+      if (rawInfo.st_mode and rawMode) != 0'i32:
+        formalInfo.permissions.incl(formalMode)
+    formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
+    formalInfo.size = rawInfo.st_size
+    formalInfo.linkCount = rawInfo.st_Nlink
+    formalInfo.lastAccessTime = rawInfo.st_atime
+    formalInfo.lastWriteTime = rawInfo.st_mtime
+    formalInfo.creationTime = rawInfo.st_ctime
+
+    result.permissions = {}
+    checkAndIncludeMode(S_IRUSR, fpUserRead)
+    checkAndIncludeMode(S_IWUSR, fpUserWrite)
+    checkAndIncludeMode(S_IXUSR, fpUserExec)
+
+    checkAndIncludeMode(S_IRGRP, fpGroupRead)
+    checkAndIncludeMode(S_IWGRP, fpGroupWrite)
+    checkAndIncludeMode(S_IXGRP, fpGroupExec)
+
+    checkAndIncludeMode(S_IROTH, fpOthersRead)
+    checkAndIncludeMode(S_IWOTH, fpOthersWrite)
+    checkAndIncludeMode(S_IXOTH, fpOthersExec)
+
+    formalInfo.kind = pcFile
+    if S_ISDIR(rawInfo.st_mode): formalInfo.kind = pcDir
+    if S_ISLNK(rawInfo.st_mode): formalInfo.kind.inc()
+
+proc getFileInfo*(handle: FileHandle): FileInfo =
+  ## Retrieves file information for the file object represented by the given
+  ## handle.
+  ##
+  ## If the information cannot be retrieved, such as when the file handle
+  ## is invalid, an error will be thrown.
+  # Done: ID, Kind, Size, Permissions, Link Count
+  when defined(Windows):
+    var rawInfo: TBY_HANDLE_FILE_INFORMATION
+    # We have to use the super special '_get_osfhandle' call (wrapped above)
+    # To transform the C file descripter to a native file handle.
+    var realHandle = get_osfhandle(handle)
+    if getFileInformationByHandle(realHandle, addr rawInfo) == 0:
+      raiseOSError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+  else:
+    var rawInfo: TStat
+    if fstat(handle, rawInfo) < 0'i32:
+      raiseOSError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+
+proc getFileInfo*(file: File): FileInfo =
+  if file.isNil:
+    raise newException(IOError, "File is nil")
+  result = getFileInfo(file.getFileHandle())
+
+proc getFileInfo*(path: string, followSymlink = true): FileInfo =
+  ## Retrieves file information for the file object pointed to by `path`.
+  ## 
+  ## Due to intrinsic differences between operating systems, the information
+  ## contained by the returned `FileInfo` structure will be slightly different
+  ## across platforms, and in some cases, incomplete or inaccurate.
+  ## 
+  ## When `followSymlink` is true, symlinks are followed and the information
+  ## retrieved is information related to the symlink's target. Otherwise,
+  ## information on the symlink itself is retrieved.
+  ## 
+  ## If the information cannot be retrieved, such as when the path doesn't
+  ## exist, or when permission restrictions prevent the program from retrieving
+  ## file information, an error will be thrown.
+  when defined(Windows):
+    var 
+      handle = openHandle(path, followSymlink)
+      rawInfo: TBY_HANDLE_FILE_INFORMATION
+    if handle == INVALID_HANDLE_VALUE:
+      raiseOSError(osLastError())
+    if getFileInformationByHandle(handle, addr rawInfo) == 0:
+      raiseOSError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+    discard closeHandle(handle)
+  else:
+    var rawInfo: TStat
+    if followSymlink:
+      if stat(path, rawInfo) < 0'i32:
+        raiseOSError(osLastError())
+    else:
+      if lstat(path, rawInfo) < 0'i32:
+        raiseOSError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
+
+proc isHidden*(path: string): bool =
+  ## Determines whether a given path is hidden or not. Returns false if the
+  ## file doesn't exist. The given path must be accessible from the current
+  ## working directory of the program.
+  ## 
+  ## On Windows, a file is hidden if the file's 'hidden' attribute is set.
+  ## On Unix-like systems, a file is hidden if it starts with a '.' (period)
+  ## and is not *just* '.' or '..' ' ."
+  when defined(Windows):
+    when useWinUnicode:
+      wrapUnary(attributes, getFileAttributesW, path)
+    else:
+      var attributes = getFileAttributesA(path)
+    if attributes != -1'i32:
+      result = (attributes and FILE_ATTRIBUTE_HIDDEN) != 0'i32
+  else:
+    if fileExists(path):
+      let
+        fileName = extractFilename(path)
+        nameLen = len(fileName)
+      if nameLen == 2:
+        result = (fileName[0] == '.') and (fileName[1] != '.')
+      elif nameLen > 2:
+        result = (fileName[0] == '.') and (fileName[3] != '.')
+
+{.pop.}
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
new file mode 100644
index 000000000..dc6f21174
--- /dev/null
+++ b/lib/pure/osproc.nim
@@ -0,0 +1,983 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements an advanced facility for executing OS processes
+## and process communication.
+
+include "system/inclrtl"
+
+import
+  strutils, os, strtabs, streams, cpuinfo
+
+when defined(windows):
+  import winlean
+else:
+  import posix
+
+when defined(linux):
+  import linux
+
+type
+  ProcessObj = object of RootObj
+    when defined(windows):
+      fProcessHandle: THandle
+      inHandle, outHandle, errHandle: FileHandle
+      id: THandle
+    else:
+      inHandle, outHandle, errHandle: FileHandle
+      inStream, outStream, errStream: Stream
+      id: TPid
+    exitCode: cint
+
+  Process* = ref ProcessObj ## represents an operating system process
+
+  ProcessOption* = enum ## options that can be passed `startProcess`
+    poEchoCmd,           ## echo the command before execution
+    poUsePath,           ## Asks system to search for executable using PATH environment
+                         ## variable.
+                         ## On Windows, this is the default.
+    poEvalCommand,       ## Pass `command` directly to the shell, without quoting.
+                         ## Use it only if `command` comes from trused source.
+    poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
+    poParentStreams      ## use the parent's streams
+
+{.deprecated: [TProcess: ProcessObj, PProcess: Process,
+  TProcessOption: ProcessOption].}
+
+const poUseShell* {.deprecated.} = poUsePath
+  ## Deprecated alias for poUsePath.
+
+proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to Windows API.
+  ## Based on Python's subprocess.list2cmdline
+  ## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  let needQuote = {' ', '\t'} in s or s.len == 0
+
+  result = ""
+  var backslashBuff = ""
+  if needQuote:
+    result.add("\"")
+
+  for c in s:
+    if c == '\\':
+      backslashBuff.add(c)
+    elif c == '\"':
+      result.add(backslashBuff)
+      result.add(backslashBuff)
+      backslashBuff.setLen(0)
+      result.add("\\\"")
+    else:
+      if backslashBuff.len != 0:
+        result.add(backslashBuff)
+        backslashBuff.setLen(0)
+      result.add(c)
+
+  if needQuote:
+    result.add("\"")
+
+proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to POSIX shell.
+  ## Based on Python's pipes.quote
+  const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
+                         '0'..'9', 'A'..'Z', 'a'..'z'}
+  if s.len == 0:
+    return "''"
+
+  let safe = s.allCharsInSet(safeUnixChars)
+
+  if safe:
+    return s
+  else:
+    return "'" & s.replace("'", "'\"'\"'") & "'"
+
+proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to shell.
+  when defined(Windows):
+    return quoteShellWindows(s)
+  elif defined(posix):
+    return quoteShellPosix(s)
+  else:
+    {.error:"quoteShell is not supported on your system".}
+
+proc execProcess*(command: string,
+                  args: openArray[string] = [],
+                  env: StringTableRef = nil,
+                  options: set[ProcessOption] = {poStdErrToStdOut,
+                                                  poUsePath,
+                                                  poEvalCommand}): TaintedString {.
+                                                  rtl, extern: "nosp$1",
+                                                  tags: [ExecIOEffect, ReadIOEffect].}
+  ## A convenience procedure that executes ``command`` with ``startProcess``
+  ## and returns its output as a string.
+  ## WARNING: this function uses poEvalCommand by default for backward compatibility.
+  ## Make sure to pass options explicitly.
+
+proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [ExecIOEffect].}
+  ## Executes ``command`` and returns its error code. Standard input, output,
+  ## error streams are inherited from the calling process. This operation
+  ## is also often called `system`:idx:.
+
+proc startProcess*(command: string,
+                   workingDir: string = "",
+                   args: openArray[string] = [],
+                   env: StringTableRef = nil,
+                   options: set[ProcessOption] = {poStdErrToStdOut}):
+              Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect].}
+  ## Starts a process. `Command` is the executable file, `workingDir` is the
+  ## process's working directory. If ``workingDir == ""`` the current directory
+  ## is used. `args` are the command line arguments that are passed to the
+  ## process. On many operating systems, the first command line argument is the
+  ## name of the executable. `args` should not contain this argument!
+  ## `env` is the environment that will be passed to the process.
+  ## If ``env == nil`` the environment is inherited of
+  ## the parent process. `options` are additional flags that may be passed
+  ## to `startProcess`. See the documentation of ``ProcessOption`` for the
+  ## meaning of these flags. You need to `close` the process when done.
+  ##
+  ## Note that you can't pass any `args` if you use the option
+  ## ``poEvalCommand``, which invokes the system shell to run the specified
+  ## `command`. In this situation you have to concatenate manually the contents
+  ## of `args` to `command` carefully escaping/quoting any special characters,
+  ## since it will be passed *as is* to the system shell. Each system/shell may
+  ## feature different escaping rules, so try to avoid this kind of shell
+  ## invocation if possible as it leads to non portable software.
+  ##
+  ## Return value: The newly created process object. Nil is never returned,
+  ## but ``EOS`` is raised in case of an error.
+
+proc startCmd*(command: string, options: set[ProcessOption] = {
+               poStdErrToStdOut, poUsePath}): Process {.
+               tags: [ExecIOEffect, ReadEnvEffect], deprecated.} =
+  ## Deprecated - use `startProcess` directly.
+  result = startProcess(command=command, options=options + {poEvalCommand})
+
+proc close*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
+  ## When the process has finished executing, cleanup related handles
+
+proc suspend*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
+  ## Suspends the process `p`.
+
+proc resume*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
+  ## Resumes the process `p`.
+
+proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
+  ## Stop the process `p`. On Posix OSes the procedure sends ``SIGTERM``
+  ## to the process. On Windows the Win32 API function ``TerminateProcess()``
+  ## is called to stop the process.
+
+proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
+  ## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to
+  ## the process. On Windows ``kill()`` is simply an alias for ``terminate()``.
+
+proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
+  ## Returns true iff the process `p` is still running. Returns immediately.
+
+proc processID*(p: Process): int {.rtl, extern: "nosp$1".} =
+  ## returns `p`'s process ID.
+  return p.id
+
+proc waitForExit*(p: Process, timeout: int = -1): int {.rtl,
+  extern: "nosp$1", tags: [].}
+  ## waits for the process to finish and returns `p`'s error code.
+  ##
+  ## **Warning**: Be careful when using waitForExit for processes created without
+  ## poParentStreams because they may fill output buffers, causing deadlock.
+
+proc peekExitCode*(p: Process): int {.tags: [].}
+  ## return -1 if the process is still running. Otherwise the process' exit code
+
+proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
+  ## returns ``p``'s input stream for writing to.
+  ##
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
+
+proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
+  ## returns ``p``'s output stream for reading from.
+  ##
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
+
+proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].}
+  ## returns ``p``'s error stream for reading from.
+  ##
+  ## **Warning**: The returned `Stream` should not be closed manually as it
+  ## is closed when closing the Process ``p``.
+
+proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
+  tags: [].} =
+  ## returns ``p``'s input file handle for writing to.
+  ##
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
+  result = p.inHandle
+
+proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
+  tags: [].} =
+  ## returns ``p``'s output file handle for reading from.
+  ##
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
+  result = p.outHandle
+
+proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1",
+  tags: [].} =
+  ## returns ``p``'s error file handle for reading from.
+  ##
+  ## **Warning**: The returned `FileHandle` should not be closed manually as
+  ## it is closed when closing the Process ``p``.
+  result = p.errHandle
+
+proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
+  ## returns the numer of the processors/cores the machine has.
+  ## Returns 0 if it cannot be detected.
+  result = cpuinfo.countProcessors()
+
+proc execProcesses*(cmds: openArray[string],
+                    options = {poStdErrToStdOut, poParentStreams},
+                    n = countProcessors(),
+                    beforeRunEvent: proc(idx: int) = nil): int
+                    {.rtl, extern: "nosp$1",
+                    tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect]} =
+  ## executes the commands `cmds` in parallel. Creates `n` processes
+  ## that execute in parallel. The highest return value of all processes
+  ## is returned. Runs `beforeRunEvent` before running each command.
+  when defined(posix):
+    # poParentStreams causes problems on Posix, so we simply disable it:
+    var options = options - {poParentStreams}
+
+  assert n > 0
+  if n > 1:
+    var q: seq[Process]
+    newSeq(q, n)
+    var m = min(n, cmds.len)
+    for i in 0..m-1:
+      if beforeRunEvent != nil:
+        beforeRunEvent(i)
+      q[i] = startProcess(cmds[i], options=options + {poEvalCommand})
+    when defined(noBusyWaiting):
+      var r = 0
+      for i in m..high(cmds):
+        when defined(debugExecProcesses):
+          var err = ""
+          var outp = outputStream(q[r])
+          while running(q[r]) or not atEnd(outp):
+            err.add(outp.readLine())
+            err.add("\n")
+          echo(err)
+        result = max(waitForExit(q[r]), result)
+        if q[r] != nil: close(q[r])
+        if beforeRunEvent != nil:
+          beforeRunEvent(i)
+        q[r] = startProcess(cmds[i], options=options + {poEvalCommand})
+        r = (r + 1) mod n
+    else:
+      var i = m
+      while i <= high(cmds):
+        sleep(50)
+        for r in 0..n-1:
+          if not running(q[r]):
+            #echo(outputStream(q[r]).readLine())
+            result = max(waitForExit(q[r]), result)
+            if q[r] != nil: close(q[r])
+            if beforeRunEvent != nil:
+              beforeRunEvent(i)
+            q[r] = startProcess(cmds[i], options=options + {poEvalCommand})
+            inc(i)
+            if i > high(cmds): break
+    for j in 0..m-1:
+      result = max(waitForExit(q[j]), result)
+      if q[j] != nil: close(q[j])
+  else:
+    for i in 0..high(cmds):
+      if beforeRunEvent != nil:
+        beforeRunEvent(i)
+      var p = startProcess(cmds[i], options=options + {poEvalCommand})
+      result = max(waitForExit(p), result)
+      close(p)
+
+proc select*(readfds: var seq[Process], timeout = 500): int
+  ## `select` with a sensible Nim interface. `timeout` is in milliseconds.
+  ## Specify -1 for no timeout. Returns the number of processes that are
+  ## ready to read from. The processes that are ready to be read from are
+  ## removed from `readfds`.
+  ##
+  ## **Warning**: This function may give unexpected or completely wrong
+  ## results on Windows.
+
+when not defined(useNimRtl):
+  proc execProcess(command: string,
+                   args: openArray[string] = [],
+                   env: StringTableRef = nil,
+                   options: set[ProcessOption] = {poStdErrToStdOut,
+                                                   poUsePath,
+                                                   poEvalCommand}): TaintedString =
+    var p = startProcess(command, args=args, env=env, options=options)
+    var outp = outputStream(p)
+    result = TaintedString""
+    var line = newStringOfCap(120).TaintedString
+    while true:
+      # FIXME: converts CR-LF to LF.
+      if outp.readLine(line):
+        result.string.add(line.string)
+        result.string.add("\n")
+      elif not running(p): break
+    close(p)
+
+
+when defined(Windows) and not defined(useNimRtl):
+  # We need to implement a handle stream for Windows:
+  type
+    PFileHandleStream = ref TFileHandleStream
+    TFileHandleStream = object of StreamObj
+      handle: THandle
+      atTheEnd: bool
+
+  proc hsClose(s: Stream) = discard # nothing to do here
+  proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd
+
+  proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int =
+    var s = PFileHandleStream(s)
+    if s.atTheEnd: return 0
+    var br: int32
+    var a = winlean.readFile(s.handle, buffer, bufLen.cint, addr br, nil)
+    # TRUE and zero bytes returned (EOF).
+    # TRUE and n (>0) bytes returned (good data).
+    # FALSE and bytes returned undefined (system error).
+    if a == 0 and br != 0: raiseOSError(osLastError())
+    s.atTheEnd = br < bufLen
+    result = br
+
+  proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) =
+    var s = PFileHandleStream(s)
+    var bytesWritten: int32
+    var a = winlean.writeFile(s.handle, buffer, bufLen.cint,
+                              addr bytesWritten, nil)
+    if a == 0: raiseOSError(osLastError())
+
+  proc newFileHandleStream(handle: THandle): PFileHandleStream =
+    new(result)
+    result.handle = handle
+    result.closeImpl = hsClose
+    result.atEndImpl = hsAtEnd
+    result.readDataImpl = hsReadData
+    result.writeDataImpl = hsWriteData
+
+  proc buildCommandLine(a: string, args: openArray[string]): cstring =
+    var res = quoteShell(a)
+    for i in 0..high(args):
+      res.add(' ')
+      res.add(quoteShell(args[i]))
+    result = cast[cstring](alloc0(res.len+1))
+    copyMem(result, cstring(res), res.len)
+
+  proc buildEnv(env: StringTableRef): cstring =
+    var L = 0
+    for key, val in pairs(env): inc(L, key.len + val.len + 2)
+    result = cast[cstring](alloc0(L+2))
+    L = 0
+    for key, val in pairs(env):
+      var x = key & "=" & val
+      copyMem(addr(result[L]), cstring(x), x.len+1) # copy \0
+      inc(L, x.len+1)
+
+  #proc open_osfhandle(osh: THandle, mode: int): int {.
+  #  importc: "_open_osfhandle", header: "<fcntl.h>".}
+
+  #var
+  #  O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
+  #  O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
+
+  proc createPipeHandles(rdHandle, wrHandle: var THandle) =
+    var piInheritablePipe: TSECURITY_ATTRIBUTES
+    piInheritablePipe.nLength = sizeof(TSECURITY_ATTRIBUTES).cint
+    piInheritablePipe.lpSecurityDescriptor = nil
+    piInheritablePipe.bInheritHandle = 1
+    if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
+      raiseOSError(osLastError())
+
+  proc fileClose(h: THandle) {.inline.} =
+    if h > 4: discard closeHandle(h)
+
+  proc startProcess(command: string,
+                 workingDir: string = "",
+                 args: openArray[string] = [],
+                 env: StringTableRef = nil,
+                 options: set[ProcessOption] = {poStdErrToStdOut}): Process =
+    var
+      si: TSTARTUPINFO
+      procInfo: TPROCESS_INFORMATION
+      success: int
+      hi, ho, he: THandle
+    new(result)
+    si.cb = sizeof(si).cint
+    if poParentStreams notin options:
+      si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
+      createPipeHandles(si.hStdInput, hi)
+      createPipeHandles(ho, si.hStdOutput)
+      if poStdErrToStdOut in options:
+        si.hStdError = si.hStdOutput
+        he = ho
+      else:
+        createPipeHandles(he, si.hStdError)
+      result.inHandle = FileHandle(hi)
+      result.outHandle = FileHandle(ho)
+      result.errHandle = FileHandle(he)
+    else:
+      si.hStdError = getStdHandle(STD_ERROR_HANDLE)
+      si.hStdInput = getStdHandle(STD_INPUT_HANDLE)
+      si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE)
+      result.inHandle = FileHandle(si.hStdInput)
+      result.outHandle = FileHandle(si.hStdOutput)
+      result.errHandle = FileHandle(si.hStdError)
+
+    var cmdl: cstring
+    if poEvalCommand in options:
+      cmdl = command
+      assert args.len == 0
+    else:
+      cmdl = buildCommandLine(command, args)
+    var wd: cstring = nil
+    var e: cstring = nil
+    if len(workingDir) > 0: wd = workingDir
+    if env != nil: e = buildEnv(env)
+    if poEchoCmd in options: echo($cmdl)
+    when useWinUnicode:
+      var tmp = newWideCString(cmdl)
+      var ee = newWideCString(e)
+      var wwd = newWideCString(wd)
+      success = winlean.createProcessW(nil,
+        tmp, nil, nil, 1, NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
+        ee, wwd, si, procInfo)
+    else:
+      success = winlean.createProcessA(nil,
+        cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo)
+    let lastError = osLastError()
+
+    if poParentStreams notin options:
+      fileClose(si.hStdInput)
+      fileClose(si.hStdOutput)
+      if poStdErrToStdOut notin options:
+        fileClose(si.hStdError)
+
+    if e != nil: dealloc(e)
+    if success == 0: raiseOSError(lastError)
+    # Close the handle now so anyone waiting is woken:
+    discard closeHandle(procInfo.hThread)
+    result.fProcessHandle = procInfo.hProcess
+    result.id = procInfo.dwProcessId
+
+  proc close(p: Process) =
+    when false:
+      # somehow this does not work on Windows:
+      discard closeHandle(p.inHandle)
+      discard closeHandle(p.outHandle)
+      discard closeHandle(p.errHandle)
+      discard closeHandle(p.FProcessHandle)
+
+  proc suspend(p: Process) =
+    discard suspendThread(p.fProcessHandle)
+
+  proc resume(p: Process) =
+    discard resumeThread(p.fProcessHandle)
+
+  proc running(p: Process): bool =
+    var x = waitForSingleObject(p.fProcessHandle, 50)
+    return x == WAIT_TIMEOUT
+
+  proc terminate(p: Process) =
+    if running(p):
+      discard terminateProcess(p.fProcessHandle, 0)
+
+  proc kill(p: Process) =
+    terminate(p)
+
+  proc waitForExit(p: Process, timeout: int = -1): int =
+    discard waitForSingleObject(p.fProcessHandle, timeout.int32)
+
+    var res: int32
+    discard getExitCodeProcess(p.fProcessHandle, res)
+    result = res
+    discard closeHandle(p.fProcessHandle)
+
+  proc peekExitCode(p: Process): int =
+    var b = waitForSingleObject(p.fProcessHandle, 50) == WAIT_TIMEOUT
+    if b: result = -1
+    else:
+      var res: int32
+      discard getExitCodeProcess(p.fProcessHandle, res)
+      return res
+
+  proc inputStream(p: Process): Stream =
+    result = newFileHandleStream(p.inHandle)
+
+  proc outputStream(p: Process): Stream =
+    result = newFileHandleStream(p.outHandle)
+
+  proc errorStream(p: Process): Stream =
+    result = newFileHandleStream(p.errHandle)
+
+  proc execCmd(command: string): int =
+    var
+      si: TSTARTUPINFO
+      procInfo: TPROCESS_INFORMATION
+      process: THandle
+      L: int32
+    si.cb = sizeof(si).cint
+    si.hStdError = getStdHandle(STD_ERROR_HANDLE)
+    si.hStdInput = getStdHandle(STD_INPUT_HANDLE)
+    si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE)
+    when useWinUnicode:
+      var c = newWideCString(command)
+      var res = winlean.createProcessW(nil, c, nil, nil, 0,
+        NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
+    else:
+      var res = winlean.createProcessA(nil, command, nil, nil, 0,
+        NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
+    if res == 0:
+      raiseOSError(osLastError())
+    else:
+      process = procInfo.hProcess
+      discard closeHandle(procInfo.hThread)
+      if waitForSingleObject(process, INFINITE) != -1:
+        discard getExitCodeProcess(process, L)
+        result = int(L)
+      else:
+        result = -1
+      discard closeHandle(process)
+
+  proc select(readfds: var seq[Process], timeout = 500): int =
+    assert readfds.len <= MAXIMUM_WAIT_OBJECTS
+    var rfds: TWOHandleArray
+    for i in 0..readfds.len()-1:
+      rfds[i] = readfds[i].fProcessHandle
+
+    var ret = waitForMultipleObjects(readfds.len.int32,
+                                     addr(rfds), 0'i32, timeout.int32)
+    case ret
+    of WAIT_TIMEOUT:
+      return 0
+    of WAIT_FAILED:
+      raiseOSError(osLastError())
+    else:
+      var i = ret - WAIT_OBJECT_0
+      readfds.del(i)
+      return 1
+
+elif not defined(useNimRtl):
+  const
+    readIdx = 0
+    writeIdx = 1
+
+  proc envToCStringArray(t: StringTableRef): cstringArray =
+    result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring)))
+    var i = 0
+    for key, val in pairs(t):
+      var x = key & "=" & val
+      result[i] = cast[cstring](alloc(x.len+1))
+      copyMem(result[i], addr(x[0]), x.len+1)
+      inc(i)
+
+  proc envToCStringArray(): cstringArray =
+    var counter = 0
+    for key, val in envPairs(): inc counter
+    result = cast[cstringArray](alloc0((counter + 1) * sizeof(cstring)))
+    var i = 0
+    for key, val in envPairs():
+      var x = key.string & "=" & val.string
+      result[i] = cast[cstring](alloc(x.len+1))
+      copyMem(result[i], addr(x[0]), x.len+1)
+      inc(i)
+
+  type TStartProcessData = object
+    sysCommand: cstring
+    sysArgs: cstringArray
+    sysEnv: cstringArray
+    workingDir: cstring
+    pStdin, pStdout, pStderr, pErrorPipe: array[0..1, cint]
+    optionPoUsePath: bool
+    optionPoParentStreams: bool
+    optionPoStdErrToStdOut: bool
+
+  when not defined(useFork):
+    proc startProcessAuxSpawn(data: TStartProcessData): TPid {.
+      tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
+  proc startProcessAuxFork(data: TStartProcessData): TPid {.
+    tags: [ExecIOEffect, ReadEnvEffect], gcsafe.}
+  {.push stacktrace: off, profiler: off.}
+  proc startProcessAfterFork(data: ptr TStartProcessData) {.
+    tags: [ExecIOEffect, ReadEnvEffect], cdecl, gcsafe.}
+  {.pop.}
+
+  proc startProcess(command: string,
+                 workingDir: string = "",
+                 args: openArray[string] = [],
+                 env: StringTableRef = nil,
+                 options: set[ProcessOption] = {poStdErrToStdOut}): Process =
+    var
+      pStdin, pStdout, pStderr: array [0..1, cint]
+    new(result)
+    result.exitCode = -3 # for ``waitForExit``
+    if poParentStreams notin options:
+      if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
+         pipe(pStderr) != 0'i32:
+        raiseOSError(osLastError())
+
+    var sysCommand: string
+    var sysArgsRaw: seq[string]
+    if poEvalCommand in options:
+      sysCommand = "/bin/sh"
+      sysArgsRaw = @[sysCommand, "-c", command]
+      assert args.len == 0, "`args` has to be empty when using poEvalCommand."
+    else:
+      sysCommand = command
+      sysArgsRaw = @[command]
+      for arg in args.items:
+        sysArgsRaw.add arg
+
+    var pid: TPid
+
+    var sysArgs = allocCStringArray(sysArgsRaw)
+    defer: deallocCStringArray(sysArgs)
+
+    var sysEnv = if env == nil:
+        envToCStringArray()
+      else:
+        envToCStringArray(env)
+
+    defer: deallocCStringArray(sysEnv)
+
+    var data: TStartProcessData
+    data.sysCommand = sysCommand
+    data.sysArgs = sysArgs
+    data.sysEnv = sysEnv
+    data.pStdin = pStdin
+    data.pStdout = pStdout
+    data.pStderr = pStderr
+    data.optionPoParentStreams = poParentStreams in options
+    data.optionPoUsePath = poUsePath in options
+    data.optionPoStdErrToStdOut = poStdErrToStdOut in options
+    data.workingDir = workingDir
+
+
+    when declared(posix_spawn) and not defined(useFork) and
+        not defined(useClone) and not defined(linux):
+      pid = startProcessAuxSpawn(data)
+    else:
+      pid = startProcessAuxFork(data)
+
+    # Parent process. Copy process information.
+    if poEchoCmd in options:
+      echo(command, " ", join(args, " "))
+    result.id = pid
+
+    if poParentStreams in options:
+      # does not make much sense, but better than nothing:
+      result.inHandle = 0
+      result.outHandle = 1
+      if poStdErrToStdOut in options:
+        result.errHandle = result.outHandle
+      else:
+        result.errHandle = 2
+    else:
+      result.inHandle = pStdin[writeIdx]
+      result.outHandle = pStdout[readIdx]
+      if poStdErrToStdOut in options:
+        result.errHandle = result.outHandle
+        discard close(pStderr[readIdx])
+      else:
+        result.errHandle = pStderr[readIdx]
+      discard close(pStderr[writeIdx])
+      discard close(pStdin[readIdx])
+      discard close(pStdout[writeIdx])
+
+  when not defined(useFork):
+    proc startProcessAuxSpawn(data: TStartProcessData): TPid =
+      var attr: Tposix_spawnattr
+      var fops: Tposix_spawn_file_actions
+
+      template chck(e: expr) =
+        if e != 0'i32: raiseOSError(osLastError())
+
+      chck posix_spawn_file_actions_init(fops)
+      chck posix_spawnattr_init(attr)
+
+      var mask: Tsigset
+      chck sigemptyset(mask)
+      chck posix_spawnattr_setsigmask(attr, mask)
+      chck posix_spawnattr_setpgroup(attr, 0'i32)
+
+      chck posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK or
+                                          POSIX_SPAWN_SETSIGMASK or
+                                          POSIX_SPAWN_SETPGROUP)
+
+      if not data.optionPoParentStreams:
+        chck posix_spawn_file_actions_addclose(fops, data.pStdin[writeIdx])
+        chck posix_spawn_file_actions_adddup2(fops, data.pStdin[readIdx], readIdx)
+        chck posix_spawn_file_actions_addclose(fops, data.pStdout[readIdx])
+        chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], writeIdx)
+        chck posix_spawn_file_actions_addclose(fops, data.pStderr[readIdx])
+        if data.optionPoStdErrToStdOut:
+          chck posix_spawn_file_actions_adddup2(fops, data.pStdout[writeIdx], 2)
+        else:
+          chck posix_spawn_file_actions_adddup2(fops, data.pStderr[writeIdx], 2)
+
+      var res: cint
+      # FIXME: chdir is global to process
+      if data.workingDir.len > 0:
+        setCurrentDir($data.workingDir)
+      var pid: TPid
+
+      if data.optionPoUsePath:
+        res = posix_spawnp(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
+      else:
+        res = posix_spawn(pid, data.sysCommand, fops, attr, data.sysArgs, data.sysEnv)
+
+      discard posix_spawn_file_actions_destroy(fops)
+      discard posix_spawnattr_destroy(attr)
+      chck res
+      return pid
+
+  proc startProcessAuxFork(data: TStartProcessData): TPid =
+    if pipe(data.pErrorPipe) != 0:
+      raiseOSError(osLastError())
+
+    defer:
+      discard close(data.pErrorPipe[readIdx])
+
+    var pid: TPid
+    var dataCopy = data
+
+    when defined(useClone):
+      const stackSize = 65536
+      let stackEnd = cast[clong](alloc(stackSize))
+      let stack = cast[pointer](stackEnd + stackSize)
+      let fn: pointer = startProcessAfterFork
+      pid = clone(fn, stack,
+                  cint(CLONE_VM or CLONE_VFORK or SIGCHLD),
+                  pointer(addr dataCopy), nil, nil, nil)
+      discard close(data.pErrorPipe[writeIdx])
+      dealloc(stack)
+    else:
+      pid = fork()
+      if pid == 0:
+        startProcessAfterFork(addr(dataCopy))
+        exitnow(1)
+
+    discard close(data.pErrorPipe[writeIdx])
+    if pid < 0: raiseOSError(osLastError())
+
+    var error: cint
+    let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error))
+    if sizeRead == sizeof(error):
+      raiseOSError($strerror(error))
+
+    return pid
+
+  {.push stacktrace: off, profiler: off.}
+  proc startProcessFail(data: ptr TStartProcessData) =
+    var error: cint = errno
+    discard write(data.pErrorPipe[writeIdx], addr error, sizeof(error))
+    exitnow(1)
+
+  when defined(macosx) or defined(freebsd):
+    var environ {.importc.}: cstringArray
+
+  proc startProcessAfterFork(data: ptr TStartProcessData) =
+    # Warning: no GC here!
+    # Or anything that touches global structures - all called nim procs
+    # must be marked with stackTrace:off. Inspect C code after making changes.
+    if not data.optionPoParentStreams:
+      discard close(data.pStdin[writeIdx])
+      if dup2(data.pStdin[readIdx], readIdx) < 0:
+        startProcessFail(data)
+      discard close(data.pStdout[readIdx])
+      if dup2(data.pStdout[writeIdx], writeIdx) < 0:
+        startProcessFail(data)
+      discard close(data.pStderr[readIdx])
+      if data.optionPoStdErrToStdOut:
+        if dup2(data.pStdout[writeIdx], 2) < 0:
+          startProcessFail(data)
+      else:
+        if dup2(data.pStderr[writeIdx], 2) < 0:
+          startProcessFail(data)
+
+    if data.workingDir.len > 0:
+      if chdir(data.workingDir) < 0:
+        startProcessFail(data)
+
+    discard close(data.pErrorPipe[readIdx])
+    discard fcntl(data.pErrorPipe[writeIdx], F_SETFD, FD_CLOEXEC)
+
+    if data.optionPoUsePath:
+      when defined(macosx) or defined(freebsd):
+        # MacOSX doesn't have execvpe, so we need workaround.
+        # On MacOSX we can arrive here only from fork, so this is safe:
+        environ = data.sysEnv
+        discard execvp(data.sysCommand, data.sysArgs)
+      else:
+        when defined(uClibc):
+          # uClibc environment (OpenWrt included) doesn't have the full execvpe
+          discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
+        else:
+          discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
+    else:
+      discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
+
+    startProcessFail(data)
+  {.pop}
+
+  proc close(p: Process) =
+    if p.inStream != nil: close(p.inStream)
+    if p.outStream != nil: close(p.outStream)
+    if p.errStream != nil: close(p.errStream)
+    discard close(p.inHandle)
+    discard close(p.outHandle)
+    discard close(p.errHandle)
+
+  proc suspend(p: Process) =
+    if kill(p.id, SIGSTOP) != 0'i32: raiseOsError(osLastError())
+
+  proc resume(p: Process) =
+    if kill(p.id, SIGCONT) != 0'i32: raiseOsError(osLastError())
+
+  proc running(p: Process): bool =
+    var ret : int
+    when not defined(freebsd):
+      ret = waitpid(p.id, p.exitCode, WNOHANG)
+    else:
+      var status : cint = 1
+      ret = waitpid(p.id, status, WNOHANG)
+      if WIFEXITED(status):
+        p.exitCode = status
+    if ret == 0: return true # Can't establish status. Assume running.
+    result = ret == int(p.id)
+
+  proc terminate(p: Process) =
+    if kill(p.id, SIGTERM) != 0'i32:
+      raiseOsError(osLastError())
+
+  proc kill(p: Process) =
+    if kill(p.id, SIGKILL) != 0'i32:
+      raiseOsError(osLastError())
+
+  proc waitForExit(p: Process, timeout: int = -1): int =
+    #if waitPid(p.id, p.exitCode, 0) == int(p.id):
+    # ``waitPid`` fails if the process is not running anymore. But then
+    # ``running`` probably set ``p.exitCode`` for us. Since ``p.exitCode`` is
+    # initialized with -3, wrong success exit codes are prevented.
+    if p.exitCode != -3: return p.exitCode
+    if waitpid(p.id, p.exitCode, 0) < 0:
+      p.exitCode = -3
+      raiseOSError(osLastError())
+    result = int(p.exitCode) shr 8
+
+  proc peekExitCode(p: Process): int =
+    if p.exitCode != -3: return p.exitCode
+    var ret = waitpid(p.id, p.exitCode, WNOHANG)
+    var b = ret == int(p.id)
+    if b: result = -1
+    if not WIFEXITED(p.exitCode): result = -1
+    else: result = p.exitCode.int shr 8
+
+  proc createStream(stream: var Stream, handle: var FileHandle,
+                    fileMode: FileMode) =
+    var f: File
+    if not open(f, handle, fileMode): raiseOSError(osLastError())
+    stream = newFileStream(f)
+
+  proc inputStream(p: Process): Stream =
+    if p.inStream == nil:
+      createStream(p.inStream, p.inHandle, fmWrite)
+    return p.inStream
+
+  proc outputStream(p: Process): Stream =
+    if p.outStream == nil:
+      createStream(p.outStream, p.outHandle, fmRead)
+    return p.outStream
+
+  proc errorStream(p: Process): Stream =
+    if p.errStream == nil:
+      createStream(p.errStream, p.errHandle, fmRead)
+    return p.errStream
+
+  proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
+                                     header: "<stdlib.h>".}
+
+  proc execCmd(command: string): int =
+    when defined(linux):
+      result = csystem(command) shr 8
+    else:
+      result = csystem(command)
+
+  proc createFdSet(fd: var TFdSet, s: seq[Process], m: var int) =
+    FD_ZERO(fd)
+    for i in items(s):
+      m = max(m, int(i.outHandle))
+      FD_SET(cint(i.outHandle), fd)
+
+  proc pruneProcessSet(s: var seq[Process], fd: var TFdSet) =
+    var i = 0
+    var L = s.len
+    while i < L:
+      if FD_ISSET(cint(s[i].outHandle), fd) == 0'i32:
+        s[i] = s[L-1]
+        dec(L)
+      else:
+        inc(i)
+    setLen(s, L)
+
+  proc select(readfds: var seq[Process], timeout = 500): int =
+    var tv: Timeval
+    tv.tv_sec = 0
+    tv.tv_usec = timeout * 1000
+
+    var rd: TFdSet
+    var m = 0
+    createFdSet((rd), readfds, m)
+
+    if timeout != -1:
+      result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
+    else:
+      result = int(select(cint(m+1), addr(rd), nil, nil, nil))
+
+    pruneProcessSet(readfds, (rd))
+
+
+proc execCmdEx*(command: string, options: set[ProcessOption] = {
+                poStdErrToStdOut, poUsePath}): tuple[
+                output: TaintedString,
+                exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} =
+  ## a convenience proc that runs the `command`, grabs all its output and
+  ## exit code and returns both.
+  var p = startProcess(command, options=options + {poEvalCommand})
+  var outp = outputStream(p)
+  result = (TaintedString"", -1)
+  var line = newStringOfCap(120).TaintedString
+  while true:
+    if outp.readLine(line):
+      result[0].string.add(line.string)
+      result[0].string.add("\n")
+    else:
+      result[1] = peekExitCode(p)
+      if result[1] != -1: break
+  close(p)
+
+when isMainModule:
+  assert quoteShellWindows("aaa") == "aaa"
+  assert quoteShellWindows("aaa\"") == "aaa\\\""
+  assert quoteShellWindows("") == "\"\""
+
+  assert quoteShellPosix("aaa") == "aaa"
+  assert quoteShellPosix("aaa a") == "'aaa a'"
+  assert quoteShellPosix("") == "''"
+  assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
+
+  when defined(posix):
+    assert quoteShell("") == "''"
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
new file mode 100644
index 000000000..bb64c8134
--- /dev/null
+++ b/lib/pure/parsecfg.nim
@@ -0,0 +1,361 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 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 quoted string literals are supported 
+## as in the Nim programming language.
+
+## This is an example of how a configuration file may look like:
+##
+## .. include:: doc/mytest.cfg
+##     :literal:
+## The file ``examples/parsecfgex.nim`` demonstrates how to use the 
+## configuration file parser:
+##
+## .. code-block:: nim
+##     :file: examples/parsecfgex.nim
+
+
+import
+  hashes, strutils, lexbase, streams
+
+include "system/inclrtl"
+
+type
+  CfgEventKind* = enum ## enumeration 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 occurred during parsing
+    
+  CfgEvent* = object of RootObj ## describes a parsing event
+    case kind*: CfgEventKind    ## the kind of the event
+    of cfgEof: nil
+    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.
+  
+  TokKind = enum 
+    tkInvalid, tkEof,        
+    tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash
+  Token = object             # a token
+    kind: TokKind            # the type of the token
+    literal: string          # the parsed (string) literal
+  
+  CfgParser* = object of BaseLexer ## the parser object.
+    tok: Token
+    filename: string
+
+{.deprecated: [TCfgEventKind: CfgEventKind, TCfgEvent: CfgEvent,
+    TTokKind: TokKind, TToken: Token, TCfgParser: CfgParser].}
+
+# implementation
+
+const 
+  SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', '/', '\\'} 
+  
+proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.}
+
+proc open*(c: var CfgParser, input: Stream, filename: string, 
+           lineOffset = 0) {.rtl, extern: "npc$1".} =
+  ## initializes the parser with an input stream. `Filename` is only used
+  ## for nice error messages. `lineOffset` can be used to influence the line
+  ## number information in the generated error messages.
+  lexbase.open(c, input)
+  c.filename = filename
+  c.tok.kind = tkInvalid
+  c.tok.literal = ""
+  inc(c.lineNumber, lineOffset)
+  rawGetTok(c, c.tok)
+  
+proc close*(c: var CfgParser) {.rtl, extern: "npc$1".} =
+  ## closes the parser `c` and its associated input stream.
+  lexbase.close(c)
+
+proc getColumn*(c: CfgParser): int {.rtl, extern: "npc$1".} =
+  ## get the current column the parser has arrived at.
+  result = getColNumber(c, c.bufpos)
+
+proc getLine*(c: CfgParser): int {.rtl, extern: "npc$1".} =
+  ## get the current line the parser has arrived at.
+  result = c.lineNumber
+
+proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} =
+  ## get the filename of the file that the parser processes.
+  result = c.filename
+
+proc handleHexChar(c: var CfgParser, 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: 
+    discard
+
+proc handleDecChars(c: var CfgParser, 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 CfgParser, tok: var Token) = 
+  inc(c.bufpos)               # skip '\'
+  case c.buf[c.bufpos]
+  of 'n', 'N': 
+    add(tok.literal, "\n")
+    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)
+    var xi = 0
+    handleHexChar(c, xi)
+    handleHexChar(c, xi)
+    add(tok.literal, chr(xi))
+  of '0'..'9': 
+    var 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 CfgParser, 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 CfgParser, tok: var Token, rawMode: bool) = 
+  var pos = c.bufpos + 1          # skip "
+  var 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)
+    buf = c.buf
+    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)
+        buf = c.buf
+        add(tok.literal, "\n")
+      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: 
+      var 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 CfgParser, tok: var Token) = 
+  var pos = c.bufpos
+  var 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 CfgParser) = 
+  var pos = c.bufpos
+  var 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)
+      buf = c.buf
+    else: 
+      break                   # EndOfFile also leaves the loop
+  c.bufpos = pos
+
+proc rawGetTok(c: var CfgParser, tok: var Token) = 
+  tok.kind = tkInvalid
+  setLen(tok.literal, 0)
+  skip(c)
+  case c.buf[c.bufpos]
+  of '=': 
+    tok.kind = tkEquals
+    inc(c.bufpos)
+    tok.literal = "="
+  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
+    tok.literal = "[EOF]"
+  else: getSymbol(c, tok)
+  
+proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
+  ## returns a properly formated error message containing current line and
+  ## column information.
+  result = `%`("$1($2, $3) Error: $4", 
+               [c.filename, $getLine(c), $getColumn(c), msg])
+  
+proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} =
+  ## returns a properly formated warning message containing current line and
+  ## column information.
+  result = `%`("$1($2, $3) Warning: $4", 
+               [c.filename, $getLine(c), $getColumn(c), msg])
+
+proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} =
+  ## returns a properly formated warning message containing that
+  ## an entry is ignored.
+  case e.kind 
+  of cfgSectionStart: result = c.warningStr("section ignored: " & e.section)
+  of cfgKeyValuePair: result = c.warningStr("key ignored: " & e.key)
+  of cfgOption: 
+    result = c.warningStr("command ignored: " & e.key & ": " & e.value)
+  of cfgError: result = e.msg
+  of cfgEof: result = ""
+
+proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent = 
+  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: 
+        reset result
+        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 CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
+  ## retrieves the first/next event. This controls the parser.
+  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:
+      reset(result)
+      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/pure/parsecsv.nim b/lib/pure/parsecsv.nim
new file mode 100644
index 000000000..117d75cfa
--- /dev/null
+++ b/lib/pure/parsecsv.nim
@@ -0,0 +1,180 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple high performance `CSV`:idx:
+## (`comma separated value`:idx:) parser. 
+##
+## Example: How to use the parser
+## ==============================
+##
+## .. code-block:: nim
+##   import os, parsecsv, streams
+##   var s = newFileStream(paramStr(1), fmRead)
+##   if s == nil: quit("cannot open the file" & paramStr(1))
+##   var x: CsvParser
+##   open(x, s, paramStr(1))
+##   while readRow(x):
+##     echo "new row: "
+##     for val in items(x.row):
+##       echo "##", val, "##"
+##   close(x)
+##
+
+import
+  lexbase, streams
+
+type
+  CsvRow* = seq[string] ## a row in a CSV file
+  CsvParser* = object of BaseLexer ## the parser object.
+    row*: CsvRow                    ## the current row
+    filename: string
+    sep, quote, esc: char
+    skipWhite: bool
+    currRow: int
+
+  CsvError* = object of IOError ## exception that is raised if
+                                ## a parsing error occurs
+
+{.deprecated: [TCsvRow: CsvRow, TCsvParser: CsvParser, EInvalidCsv: CsvError].}
+
+proc raiseEInvalidCsv(filename: string, line, col: int, 
+                      msg: string) {.noreturn.} =
+  var e: ref CsvError
+  new(e)
+  e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
+  raise e
+
+proc error(my: CsvParser, pos: int, msg: string) =
+  raiseEInvalidCsv(my.filename, my.lineNumber, getColNumber(my, pos), msg)
+
+proc open*(my: var CsvParser, input: Stream, filename: string,
+           separator = ',', quote = '"', escape = '\0',
+           skipInitialSpace = false) =
+  ## initializes the parser with an input stream. `Filename` is only used
+  ## for nice error messages. The parser's behaviour can be controlled by
+  ## the diverse optional parameters:
+  ## - `separator`: character used to separate fields
+  ## - `quote`: Used to quote fields containing special characters like 
+  ##   `separator`, `quote` or new-line characters. '\0' disables the parsing
+  ##   of quotes.
+  ## - `escape`: removes any special meaning from the following character; 
+  ##   '\0' disables escaping; if escaping is disabled and `quote` is not '\0',
+  ##   two `quote` characters are parsed one literal `quote` character.
+  ## - `skipInitialSpace`: If true, whitespace immediately following the 
+  ##   `separator` is ignored.
+  lexbase.open(my, input)
+  my.filename = filename
+  my.sep = separator
+  my.quote = quote
+  my.esc = escape
+  my.skipWhite = skipInitialSpace
+  my.row = @[]
+  my.currRow = 0
+
+proc parseField(my: var CsvParser, a: var string) = 
+  var pos = my.bufpos
+  var buf = my.buf
+  if my.skipWhite:
+    while buf[pos] in {' ', '\t'}: inc(pos)
+  setLen(a, 0) # reuse memory
+  if buf[pos] == my.quote and my.quote != '\0': 
+    inc(pos)
+    while true:
+      var c = buf[pos]
+      if c == '\0':
+        my.bufpos = pos # can continue after exception?
+        error(my, pos, my.quote & " expected")
+        break
+      elif c == my.quote: 
+        if my.esc == '\0' and buf[pos+1] == my.quote:
+          add(a, my.quote)
+          inc(pos, 2)
+        else:
+          inc(pos)
+          break
+      elif c == my.esc:
+        add(a, buf[pos+1])
+        inc(pos, 2)
+      else:
+        case c
+        of '\c': 
+          pos = handleCR(my, pos)
+          buf = my.buf
+          add(a, "\n")
+        of '\l': 
+          pos = handleLF(my, pos)
+          buf = my.buf
+          add(a, "\n")
+        else:
+          add(a, c)
+          inc(pos)
+  else:
+    while true:
+      var c = buf[pos]
+      if c == my.sep: break
+      if c in {'\c', '\l', '\0'}: break
+      add(a, c)
+      inc(pos)
+  my.bufpos = pos
+
+proc processedRows*(my: var CsvParser): int = 
+  ## returns number of the processed rows
+  return my.currRow
+
+proc readRow*(my: var CsvParser, columns = 0): bool = 
+  ## reads the next row; if `columns` > 0, it expects the row to have
+  ## exactly this many columns. Returns false if the end of the file
+  ## has been encountered else true.
+  var col = 0 # current column
+  var oldpos = my.bufpos
+  while my.buf[my.bufpos] != '\0':
+    var oldlen = my.row.len
+    if oldlen < col+1:
+      setLen(my.row, col+1)
+      my.row[col] = ""
+    parseField(my, my.row[col])
+    inc(col)
+    if my.buf[my.bufpos] == my.sep: 
+      inc(my.bufpos)
+    else:
+      case my.buf[my.bufpos]
+      of '\c', '\l': 
+        # skip empty lines:
+        while true: 
+          case my.buf[my.bufpos]
+          of '\c': my.bufpos = handleCR(my, my.bufpos)
+          of '\l': my.bufpos = handleLF(my, my.bufpos)
+          else: break
+      of '\0': discard
+      else: error(my, my.bufpos, my.sep & " expected")
+      break
+  
+  setLen(my.row, col)
+  result = col > 0
+  if result and col != columns and columns > 0: 
+    error(my, oldpos+1, $columns & " columns expected, but found " & 
+          $col & " columns")
+  inc(my.currRow)
+  
+proc close*(my: var CsvParser) {.inline.} = 
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+when not defined(testing) and isMainModule:
+  import os
+  var s = newFileStream(paramStr(1), fmRead)
+  if s == nil: quit("cannot open the file" & paramStr(1))
+  var x: CsvParser
+  open(x, s, paramStr(1))
+  while readRow(x):
+    echo "new row: "
+    for val in items(x.row):
+      echo "##", val, "##"
+  close(x)
+
diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim
new file mode 100644
index 000000000..4c92a7cdf
--- /dev/null
+++ b/lib/pure/parseopt.nim
@@ -0,0 +1,159 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides the standard Nim command line parser.
+## It supports one convenience iterator over all command line options and some
+## lower-level features.
+##
+## Supported syntax:
+##
+## 1. short options - ``-abcd``, where a, b, c, d are names
+## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo``
+## 3. argument - everything else
+
+{.push debugger: off.}
+
+include "system/inclrtl"
+
+import 
+  os, strutils
+
+type 
+  CmdLineKind* = 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
+  OptParser* = 
+      object of RootObj ## this object implements the command line parser  
+    cmd: string
+    pos: int
+    inShortState: bool
+    kind*: CmdLineKind        ## the dected command line token
+    key*, val*: TaintedString ## key and value pair; ``key`` is the option
+                              ## or the argument, ``value`` is not "" if
+                              ## the option was given a value
+
+{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
+
+when declared(os.paramCount):
+  # we cannot provide this for NimRtl creation on Posix, because we can't 
+  # access the command line arguments then!
+
+  proc initOptParser*(cmdline = ""): OptParser =
+    ## inits the option parser. If ``cmdline == ""``, the real command line
+    ## (as provided by the ``OS`` module) is taken.
+    result.pos = 0
+    result.inShortState = false
+    if cmdline != "": 
+      result.cmd = cmdline
+    else: 
+      result.cmd = ""
+      for i in countup(1, paramCount()): 
+        result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i).string) & ' '
+    result.kind = cmdEnd
+    result.key = TaintedString""
+    result.val = TaintedString""
+
+proc parseWord(s: string, i: int, w: var string, 
+               delim: set[char] = {'\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 OptParser) = 
+  var i = p.pos
+  p.kind = cmdShortOption
+  add(p.key.string, 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.string)
+  if p.cmd[i] == '\0': p.inShortState = false
+  p.pos = i
+
+proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = 
+  ## parses the first or next option; ``p.kind`` describes what token has been
+  ## parsed. ``p.key`` and ``p.val`` are set accordingly.
+  var i = p.pos
+  while p.cmd[i] in {'\x09', ' '}: inc(i)
+  p.pos = i
+  setLen(p.key.string, 0)
+  setLen(p.val.string, 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.string, {'\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.string)
+      else: 
+        p.pos = i
+    else: 
+      p.pos = i
+      handleShortOption(p)
+  else:
+    p.kind = cmdArgument
+    p.pos = parseWord(p.cmd, i, p.key.string)
+
+proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = 
+  ## retrieves the rest of the command line that has not been parsed yet.
+  result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString
+
+when declared(initOptParser):
+  iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] =
+    ## This is an convenience iterator for iterating over the command line.
+    ## This uses the TOptParser object. Example:
+    ##
+    ## .. code-block:: nim
+    ##   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 = initOptParser()
+    while true:
+      next(p)
+      if p.kind == cmdEnd: break
+      yield (p.kind, p.key, p.val)
+
+{.pop.}
diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim
new file mode 100644
index 000000000..73b498fe0
--- /dev/null
+++ b/lib/pure/parseopt2.nim
@@ -0,0 +1,152 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides the standard Nim command line parser.
+## It supports one convenience iterator over all command line options and some
+## lower-level features.
+##
+## Supported syntax:
+##
+## 1. short options - ``-abcd``, where a, b, c, d are names
+## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo``
+## 3. argument - everything else
+
+{.push debugger: off.}
+
+include "system/inclrtl"
+
+import
+  os, strutils
+
+type
+  CmdLineKind* = 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
+  OptParser* =
+      object of RootObj ## this object implements the command line parser
+    cmd: seq[string]
+    pos: int
+    remainingShortOptions: string
+    kind*: CmdLineKind        ## the dected command line token
+    key*, val*: TaintedString ## key and value pair; ``key`` is the option
+                              ## or the argument, ``value`` is not "" if
+                              ## the option was given a value
+
+{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].}
+
+proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} =
+  ## Initalizes option parses with cmdline. cmdline should not contain
+  ## argument 0 - program name.
+  ## If cmdline == nil default to current command line arguments.
+  result.remainingShortOptions = ""
+  when not defined(createNimRtl):
+    if cmdline == nil:
+      result.cmd = commandLineParams()
+      return
+  else:
+    assert cmdline != nil, "Cannot determine command line arguments."
+
+  result.cmd = @cmdline
+
+proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} =
+  ## Initalizes option parses with cmdline. Splits cmdline in on spaces
+  ## and calls initOptParser(openarray[string])
+  ## Do not use.
+  if cmdline == "": # backward compatibility
+    return initOptParser(seq[string](nil))
+  else:
+    return initOptParser(cmdline.split)
+
+when not defined(createNimRtl):
+  proc initOptParser*(): OptParser =
+    ## Initializes option parser from current command line arguments.
+    return initOptParser(commandLineParams())
+
+proc next*(p: var OptParser) {.rtl, extern: "npo$1".}
+
+proc nextOption(p: var OptParser, token: string, allowEmpty: bool) =
+  for splitchar in [':', '=']:
+    if splitchar in token:
+      let pos = token.find(splitchar)
+      p.key = token[0..pos-1]
+      p.val = token[pos+1..token.len-1]
+      return
+
+  p.key = token
+  if allowEmpty:
+    p.val = ""
+  else:
+    p.remainingShortOptions = token[0..token.len-1]
+    p.next()
+
+proc next(p: var OptParser) =
+  if p.remainingShortOptions.len != 0:
+    p.kind = cmdShortOption
+    p.key = TaintedString(p.remainingShortOptions[0..0])
+    p.val = ""
+    p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1]
+    return
+
+  if p.pos >= p.cmd.len:
+    p.kind = cmdEnd
+    return
+
+  let token = p.cmd[p.pos]
+  p.pos += 1
+
+  if token.startsWith("--"):
+    p.kind = cmdLongOption
+    nextOption(p, token[2..token.len-1], allowEmpty=true)
+  elif token.startsWith("-"):
+    p.kind = cmdShortOption
+    nextOption(p, token[1..token.len-1], allowEmpty=true)
+  else:
+    p.kind = cmdArgument
+    p.key = token
+    p.val = ""
+
+proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1", deprecated.} =
+  ## Returns part of command line string that has not been parsed yet.
+  ## Do not use - does not correctly handle whitespace.
+  return p.cmd[p.pos..p.cmd.len-1].join(" ")
+
+type
+  GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString]
+
+{.deprecated: [TGetoptResult: GetoptResult].}
+
+when declared(paramCount):
+  iterator getopt*(): GetoptResult =
+    ## This is an convenience iterator for iterating over the command line.
+    ## This uses the OptParser object. Example:
+    ##
+    ## .. code-block:: nim
+    ##   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 = initOptParser()
+    while true:
+      next(p)
+      if p.kind == cmdEnd: break
+      yield (p.kind, p.key, p.val)
+
+{.pop.}
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
new file mode 100644
index 000000000..91917b1c5
--- /dev/null
+++ b/lib/pure/parsesql.nim
@@ -0,0 +1,1350 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The ``parsesql`` module implements a high performance SQL file 
+## parser. It parses PostgreSQL syntax and the SQL ANSI standard.
+
+import
+  hashes, strutils, lexbase, streams
+
+# ------------------- scanner -------------------------------------------------
+
+type
+  TokKind = enum       ## enumeration of all SQL tokens
+    tkInvalid,          ## invalid token
+    tkEof,              ## end of file reached
+    tkIdentifier,       ## abc
+    tkQuotedIdentifier, ## "abc"
+    tkStringConstant,   ## 'abc'
+    tkEscapeConstant,       ## e'abc'
+    tkDollarQuotedConstant, ## $tag$abc$tag$
+    tkBitStringConstant,    ## B'00011'
+    tkHexStringConstant,    ## x'00011'
+    tkInteger,
+    tkNumeric,
+    tkOperator,             ## + - * / < > = ~ ! @ # % ^ & | ` ?
+    tkSemicolon,            ## ';'
+    tkColon,                ## ':'
+    tkComma,                ## ','
+    tkParLe,                ## '('
+    tkParRi,                ## ')'
+    tkBracketLe,            ## '['
+    tkBracketRi,            ## ']'
+    tkDot                   ## '.'
+  
+  Token = object  # a token
+    kind: TokKind           # the type of the token
+    literal: string          # the parsed (string) literal
+  
+  SqlLexer* = object of BaseLexer ## the parser object.
+    filename: string
+
+{.deprecated: [TToken: Token, TSqlLexer: SqlLexer].}
+
+const
+  tokKindToStr: array[TokKind, string] = [
+    "invalid", "[EOF]", "identifier", "quoted identifier", "string constant",
+    "escape string constant", "dollar quoted constant", "bit string constant",
+    "hex string constant", "integer constant", "numeric constant", "operator",
+    ";", ":", ",", "(", ")", "[", "]", "."
+  ]
+
+proc open(L: var SqlLexer, input: Stream, filename: string) = 
+  lexbase.open(L, input)
+  L.filename = filename
+  
+proc close(L: var SqlLexer) = 
+  lexbase.close(L)
+
+proc getColumn(L: SqlLexer): int = 
+  ## get the current column the parser has arrived at.
+  result = getColNumber(L, L.bufpos)
+
+proc getLine(L: SqlLexer): int = 
+  result = L.lineNumber
+
+proc handleHexChar(c: var SqlLexer, 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: 
+    discard
+
+proc handleOctChar(c: var SqlLexer, xi: var int) = 
+  if c.buf[c.bufpos] in {'0'..'7'}:
+    xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0'))
+    inc(c.bufpos)
+
+proc getEscapedChar(c: var SqlLexer, tok: var Token) = 
+  inc(c.bufpos)
+  case c.buf[c.bufpos]
+  of 'n', 'N': 
+    add(tok.literal, '\L')
+    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)
+    var xi = 0
+    handleHexChar(c, xi)
+    handleHexChar(c, xi)
+    add(tok.literal, chr(xi))
+  of '0'..'7': 
+    var xi = 0
+    handleOctChar(c, xi)
+    handleOctChar(c, xi)
+    handleOctChar(c, xi)
+    if (xi <= 255): add(tok.literal, chr(xi))
+    else: tok.kind = tkInvalid
+  else: tok.kind = tkInvalid
+  
+proc handleCRLF(c: var SqlLexer, 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 skip(c: var SqlLexer) = 
+  var pos = c.bufpos
+  var buf = c.buf
+  var nested = 0
+  while true: 
+    case buf[pos]
+    of ' ', '\t': 
+      inc(pos)
+    of '-':
+      if buf[pos+1] == '-':
+        while not (buf[pos] in {'\c', '\L', lexbase.EndOfFile}): inc(pos)
+      else:
+        break
+    of '/':
+      if buf[pos+1] == '*':
+        inc(pos,2)
+        while true:
+          case buf[pos]
+          of '\0': break
+          of '\c', '\L': 
+            pos = handleCRLF(c, pos)
+            buf = c.buf
+          of '*':
+            if buf[pos+1] == '/':
+              inc(pos, 2)
+              if nested <= 0: break
+              dec(nested)
+            else:
+              inc(pos)
+          of '/':
+            if buf[pos+1] == '*':
+              inc(pos, 2)
+              inc(nested)
+            else:
+              inc(pos)
+          else: inc(pos)
+      else: break
+    of '\c', '\L': 
+      pos = handleCRLF(c, pos)
+      buf = c.buf
+    else: 
+      break                   # EndOfFile also leaves the loop
+  c.bufpos = pos
+  
+proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) = 
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  tok.kind = kind
+  block parseLoop:
+    while true:
+      while true: 
+        var ch = buf[pos]
+        if ch == '\'':
+          if buf[pos+1] == '\'':
+            inc(pos, 2)
+            add(tok.literal, '\'')
+          else:
+            inc(pos)
+            break 
+        elif ch in {'\c', '\L', lexbase.EndOfFile}: 
+          tok.kind = tkInvalid
+          break parseLoop
+        elif (ch == '\\') and kind == tkEscapeConstant: 
+          c.bufpos = pos
+          getEscapedChar(c, tok)
+          pos = c.bufpos
+        else: 
+          add(tok.literal, ch)
+          inc(pos)
+      c.bufpos = pos
+      var line = c.lineNumber
+      skip(c)
+      if c.lineNumber > line:
+        # a new line whitespace has been parsed, so we check if the string
+        # continues after the whitespace:
+        buf = c.buf # may have been reallocated
+        pos = c.bufpos
+        if buf[pos] == '\'': inc(pos)
+        else: break parseLoop
+      else: break parseLoop
+  c.bufpos = pos
+
+proc getDollarString(c: var SqlLexer, tok: var Token) = 
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  tok.kind = tkDollarQuotedConstant
+  var tag = "$"
+  while buf[pos] in IdentChars:
+    add(tag, buf[pos])
+    inc(pos)
+  if buf[pos] == '$': inc(pos)
+  else:
+    tok.kind = tkInvalid
+    return
+  while true:
+    case buf[pos]
+    of '\c', '\L': 
+      pos = handleCRLF(c, pos)
+      buf = c.buf
+      add(tok.literal, "\L")
+    of '\0':
+      tok.kind = tkInvalid
+      break
+    of '$':
+      inc(pos)
+      var tag2 = "$"
+      while buf[pos] in IdentChars:
+        add(tag2, buf[pos])
+        inc(pos)
+      if buf[pos] == '$': inc(pos)
+      if tag2 == tag: break
+      add(tok.literal, tag2)
+      add(tok.literal, '$')
+    else:
+      add(tok.literal, buf[pos])
+      inc(pos)
+  c.bufpos = pos
+
+proc getSymbol(c: var SqlLexer, tok: var Token) = 
+  var pos = c.bufpos
+  var buf = c.buf
+  while true: 
+    add(tok.literal, buf[pos])
+    inc(pos)
+    if buf[pos] notin {'a'..'z','A'..'Z','0'..'9','_','$', '\128'..'\255'}:
+      break
+  c.bufpos = pos
+  tok.kind = tkIdentifier
+
+proc getQuotedIdentifier(c: var SqlLexer, tok: var Token) = 
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  tok.kind = tkQuotedIdentifier
+  while true:
+    var ch = buf[pos]
+    if ch == '\"':
+      if buf[pos+1] == '\"':
+        inc(pos, 2)
+        add(tok.literal, '\"')
+      else:
+        inc(pos)
+        break
+    elif ch in {'\c', '\L', lexbase.EndOfFile}: 
+      tok.kind = tkInvalid
+      break
+    else:
+      add(tok.literal, ch)
+      inc(pos)
+  c.bufpos = pos
+
+proc getBitHexString(c: var SqlLexer, tok: var Token, validChars: set[char]) =
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  block parseLoop:
+    while true:
+      while true: 
+        var ch = buf[pos]
+        if ch in validChars:
+          add(tok.literal, ch)
+          inc(pos)          
+        elif ch == '\'':
+          inc(pos)
+          break
+        else: 
+          tok.kind = tkInvalid
+          break parseLoop
+      c.bufpos = pos
+      var line = c.lineNumber
+      skip(c)
+      if c.lineNumber > line:
+        # a new line whitespace has been parsed, so we check if the string
+        # continues after the whitespace:
+        buf = c.buf # may have been reallocated
+        pos = c.bufpos
+        if buf[pos] == '\'': inc(pos)
+        else: break parseLoop
+      else: break parseLoop
+  c.bufpos = pos
+
+proc getNumeric(c: var SqlLexer, tok: var Token) =
+  tok.kind = tkInteger
+  var pos = c.bufpos
+  var buf = c.buf
+  while buf[pos] in Digits:
+    add(tok.literal, buf[pos])
+    inc(pos)
+  if buf[pos] == '.':
+    tok.kind = tkNumeric
+    add(tok.literal, buf[pos])
+    inc(pos)
+    while buf[pos] in Digits:
+      add(tok.literal, buf[pos])
+      inc(pos)
+  if buf[pos] in {'E', 'e'}:
+    tok.kind = tkNumeric
+    add(tok.literal, buf[pos])
+    inc(pos)
+    if buf[pos] == '+':
+      inc(pos)
+    elif buf[pos] == '-':
+      add(tok.literal, buf[pos])
+      inc(pos)
+    if buf[pos] in Digits:
+      while buf[pos] in Digits:
+        add(tok.literal, buf[pos])
+        inc(pos)
+    else:
+      tok.kind = tkInvalid
+  c.bufpos = pos  
+
+proc getOperator(c: var SqlLexer, tok: var Token) =
+  const operators = {'+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%',
+                     '^', '&', '|', '`', '?'}
+  tok.kind = tkOperator
+  var pos = c.bufpos
+  var buf = c.buf
+  var trailingPlusMinus = false
+  while true:
+    case buf[pos]
+    of '-':
+      if buf[pos] == '-': break
+      if not trailingPlusMinus and buf[pos+1] notin operators and
+           tok.literal.len > 0: break
+    of '/':
+      if buf[pos] == '*': break
+    of '~', '!', '@', '#', '%', '^', '&', '|', '`', '?':
+      trailingPlusMinus = true
+    of '+':
+      if not trailingPlusMinus and buf[pos+1] notin operators and
+           tok.literal.len > 0: break
+    of '*', '<', '>', '=': discard
+    else: break
+    add(tok.literal, buf[pos])
+    inc(pos)
+  c.bufpos = pos
+
+proc getTok(c: var SqlLexer, tok: var Token) = 
+  tok.kind = tkInvalid
+  setLen(tok.literal, 0)
+  skip(c)
+  case c.buf[c.bufpos]
+  of ';': 
+    tok.kind = tkSemicolon
+    inc(c.bufpos)
+    add(tok.literal, ';')
+  of ',':
+    tok.kind = tkComma
+    inc(c.bufpos)
+    add(tok.literal, ',')
+  of ':': 
+    tok.kind = tkColon
+    inc(c.bufpos)
+    add(tok.literal, ':')
+  of 'e', 'E': 
+    if c.buf[c.bufpos + 1] == '\'': 
+      inc(c.bufpos)
+      getString(c, tok, tkEscapeConstant)
+    else: 
+      getSymbol(c, tok)
+  of 'b', 'B':
+    if c.buf[c.bufpos + 1] == '\'':
+      tok.kind = tkBitStringConstant
+      getBitHexString(c, tok, {'0'..'1'})
+    else:
+      getSymbol(c, tok)
+  of 'x', 'X':
+    if c.buf[c.bufpos + 1] == '\'':
+      tok.kind = tkHexStringConstant
+      getBitHexString(c, tok, {'a'..'f','A'..'F','0'..'9'})
+    else:
+      getSymbol(c, tok)
+  of '$': getDollarString(c, tok)
+  of '[': 
+    tok.kind = tkBracketLe
+    inc(c.bufpos)
+    add(tok.literal, '[')
+  of ']': 
+    tok.kind = tkBracketRi
+    inc(c.bufpos)
+    add(tok.literal, ']')
+  of '(':
+    tok.kind = tkParLe
+    inc(c.bufpos)
+    add(tok.literal, '(')
+  of ')':
+    tok.kind = tkParRi
+    inc(c.bufpos)
+    add(tok.literal, ')')
+  of '.': 
+    if c.buf[c.bufpos + 1] in Digits:
+      getNumeric(c, tok)
+    else:
+      tok.kind = tkDot
+      inc(c.bufpos)
+    add(tok.literal, '.')
+  of '0'..'9': getNumeric(c, tok)
+  of '\'': getString(c, tok, tkStringConstant)
+  of '"': getQuotedIdentifier(c, tok)
+  of lexbase.EndOfFile: 
+    tok.kind = tkEof
+    tok.literal = "[EOF]"
+  of 'a', 'c', 'd', 'f'..'w', 'y', 'z', 'A', 'C', 'D', 'F'..'W', 'Y', 'Z', '_',
+     '\128'..'\255':
+    getSymbol(c, tok)
+  of '+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%',
+     '^', '&', '|', '`', '?':
+    getOperator(c, tok)
+  else:
+    add(tok.literal, c.buf[c.bufpos])
+    inc(c.bufpos)
+  
+proc errorStr(L: SqlLexer, msg: string): string = 
+  result = "$1($2, $3) Error: $4" % [L.filename, $getLine(L), $getColumn(L), msg]
+
+
+# ----------------------------- parser ----------------------------------------
+
+# Operator/Element	Associativity	Description
+# .	                left    	table/column name separator
+# ::            	left	        PostgreSQL-style typecast
+# [ ]	                left    	array element selection
+# -	                right	        unary minus
+# ^                     left	        exponentiation
+# * / %	                left	        multiplication, division, modulo
+# + -	                left	        addition, subtraction
+# IS	 	IS TRUE, IS FALSE, IS UNKNOWN, IS NULL
+# ISNULL	 	test for null
+# NOTNULL	 	test for not null
+# (any other)	        left    	all other native and user-defined oprs
+# IN	          	set membership
+# BETWEEN	 	range containment
+# OVERLAPS	 	time interval overlap
+# LIKE ILIKE SIMILAR	 	string pattern matching
+# < >	 	less than, greater than
+# =	                right	        equality, assignment
+# NOT	                right	        logical negation
+# AND	                left	        logical conjunction
+# OR              	left	        logical disjunction
+
+type
+  SqlNodeKind* = enum ## kind of SQL abstract syntax tree
+    nkNone,
+    nkIdent,
+    nkStringLit,
+    nkBitStringLit,
+    nkHexStringLit,
+    nkIntegerLit,
+    nkNumericLit,
+    nkPrimaryKey,
+    nkForeignKey,
+    nkNotNull,
+    
+    nkStmtList,
+    nkDot,
+    nkDotDot,
+    nkPrefix,
+    nkInfix,
+    nkCall,
+    nkColumnReference,
+    nkReferences,
+    nkDefault,
+    nkCheck,
+    nkConstraint,
+    nkUnique,
+    nkIdentity,
+    nkColumnDef,        ## name, datatype, constraints
+    nkInsert,
+    nkUpdate,
+    nkDelete,
+    nkSelect,
+    nkSelectDistinct,
+    nkSelectColumns,
+    nkAsgn,
+    nkFrom,
+    nkGroup,
+    nkHaving,
+    nkOrder,
+    nkDesc,
+    nkUnion,
+    nkIntersect,
+    nkExcept,
+    nkColumnList,
+    nkValueList,
+    nkWhere,
+    nkCreateTable,
+    nkCreateTableIfNotExists, 
+    nkCreateType,
+    nkCreateTypeIfNotExists,
+    nkCreateIndex,
+    nkCreateIndexIfNotExists,
+    nkEnumDef
+    
+type
+  SqlParseError* = object of ValueError ## Invalid SQL encountered
+  SqlNode* = ref SqlNodeObj        ## an SQL abstract syntax tree node
+  SqlNodeObj* = object              ## an SQL abstract syntax tree node
+    case kind*: SqlNodeKind      ## kind of syntax tree
+    of nkIdent, nkStringLit, nkBitStringLit, nkHexStringLit,
+                nkIntegerLit, nkNumericLit:
+      strVal*: string             ## AST leaf: the identifier, numeric literal
+                                  ## string literal, etc.
+    else:
+      sons*: seq[SqlNode]        ## the node's children
+
+  SqlParser* = object of SqlLexer ## SQL parser object
+    tok: Token
+
+{.deprecated: [EInvalidSql: SqlParseError, PSqlNode: SqlNode,
+    TSqlNode: SqlNodeObj, TSqlParser: SqlParser, TSqlNodeKind: SqlNodeKind].}
+
+proc newNode(k: SqlNodeKind): SqlNode =
+  new(result)
+  result.kind = k
+
+proc newNode(k: SqlNodeKind, s: string): SqlNode =
+  new(result)
+  result.kind = k
+  result.strVal = s
+  
+proc len*(n: SqlNode): int =
+  if isNil(n.sons): result = 0
+  else: result = n.sons.len
+  
+proc add*(father, n: SqlNode) =
+  if isNil(father.sons): father.sons = @[]
+  add(father.sons, n)
+
+proc getTok(p: var SqlParser) =
+  getTok(p, p.tok)
+
+proc sqlError(p: SqlParser, msg: string) =
+  var e: ref SqlParseError
+  new(e)
+  e.msg = errorStr(p, msg)
+  raise e
+
+proc isKeyw(p: SqlParser, keyw: string): bool =
+  result = p.tok.kind == tkIdentifier and
+           cmpIgnoreCase(p.tok.literal, keyw) == 0
+
+proc isOpr(p: SqlParser, opr: string): bool =
+  result = p.tok.kind == tkOperator and
+           cmpIgnoreCase(p.tok.literal, opr) == 0
+
+proc optKeyw(p: var SqlParser, keyw: string) =
+  if p.tok.kind == tkIdentifier and cmpIgnoreCase(p.tok.literal, keyw) == 0:
+    getTok(p)
+
+proc expectIdent(p: SqlParser) =
+  if p.tok.kind != tkIdentifier and p.tok.kind != tkQuotedIdentifier:
+    sqlError(p, "identifier expected")
+
+proc expect(p: SqlParser, kind: TokKind) =
+  if p.tok.kind != kind:
+    sqlError(p, tokKindToStr[kind] & " expected")
+
+proc eat(p: var SqlParser, kind: TokKind) =
+  if p.tok.kind == kind:
+    getTok(p)
+  else:
+    sqlError(p, tokKindToStr[kind] & " expected")
+
+proc eat(p: var SqlParser, keyw: string) =
+  if isKeyw(p, keyw):
+    getTok(p)
+  else:
+    sqlError(p, keyw.toUpper() & " expected")
+
+proc parseDataType(p: var SqlParser): SqlNode =
+  if isKeyw(p, "enum"):
+    result = newNode(nkEnumDef)
+    getTok(p)
+    if p.tok.kind == tkParLe:
+      getTok(p)
+      result.add(newNode(nkStringLit, p.tok.literal))
+      getTok(p)
+      while p.tok.kind == tkComma:
+        getTok(p)
+        result.add(newNode(nkStringLit, p.tok.literal))
+        getTok(p)
+      eat(p, tkParRi)
+  else:
+    expectIdent(p)
+    result = newNode(nkIdent, p.tok.literal)
+    getTok(p)
+    # ignore (12, 13) part:
+    if p.tok.kind == tkParLe:
+      getTok(p)
+      expect(p, tkInteger)
+      getTok(p)
+      while p.tok.kind == tkComma:
+        getTok(p)
+        expect(p, tkInteger)
+        getTok(p)
+      eat(p, tkParRi)
+
+proc getPrecedence(p: SqlParser): int = 
+  if isOpr(p, "*") or isOpr(p, "/") or isOpr(p, "%"):
+    result = 6
+  elif isOpr(p, "+") or isOpr(p, "-"):
+    result = 5  
+  elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or
+       isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or
+       isKeyw(p, "like"):
+    result = 3
+  elif isKeyw(p, "and"):
+    result = 2
+  elif isKeyw(p, "or"):
+    result = 1
+  elif p.tok.kind == tkOperator:
+    # user-defined operator:
+    result = 0
+  else:
+    result = - 1
+
+proc parseExpr(p: var SqlParser): SqlNode
+
+proc identOrLiteral(p: var SqlParser): SqlNode =
+  case p.tok.kind
+  of tkIdentifier, tkQuotedIdentifier: 
+    result = newNode(nkIdent, p.tok.literal)
+    getTok(p)
+  of tkStringConstant, tkEscapeConstant, tkDollarQuotedConstant:
+    result = newNode(nkStringLit, p.tok.literal)
+    getTok(p)
+  of tkBitStringConstant:
+    result = newNode(nkBitStringLit, p.tok.literal)
+    getTok(p)
+  of tkHexStringConstant:
+    result = newNode(nkHexStringLit, p.tok.literal)
+    getTok(p)
+  of tkInteger:
+    result = newNode(nkIntegerLit, p.tok.literal)
+    getTok(p)
+  of tkNumeric:
+    result = newNode(nkNumericLit, p.tok.literal)
+    getTok(p)
+  of tkParLe:
+    getTok(p)
+    result = parseExpr(p)
+    eat(p, tkParRi)
+  else: 
+    sqlError(p, "expression expected")
+    getTok(p) # we must consume a token here to prevend endless loops!
+
+proc primary(p: var SqlParser): SqlNode = 
+  if p.tok.kind == tkOperator or isKeyw(p, "not"): 
+    result = newNode(nkPrefix)
+    result.add(newNode(nkIdent, p.tok.literal))
+    getTok(p)
+    result.add(primary(p))
+    return
+  result = identOrLiteral(p)
+  while true: 
+    case p.tok.kind
+    of tkParLe: 
+      var a = result
+      result = newNode(nkCall)
+      result.add(a)
+      getTok(p)
+      while true:
+        result.add(parseExpr(p))
+        if p.tok.kind == tkComma: getTok(p)
+        else: break
+      eat(p, tkParRi)
+    of tkDot: 
+      getTok(p)
+      var a = result
+      if p.tok.kind == tkDot:
+        getTok(p)
+        result = newNode(nkDotDot)
+      else:
+        result = newNode(nkDot)
+      result.add(a)
+      if isOpr(p, "*"):
+        result.add(newNode(nkIdent, "*"))
+      elif p.tok.kind in {tkIdentifier, tkQuotedIdentifier}:
+        result.add(newNode(nkIdent, p.tok.literal))
+      else:
+        sqlError(p, "identifier expected")
+      getTok(p)
+    else: break
+  
+proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int = 
+  var
+    v2, node, opNode: SqlNode
+  v = primary(p) # expand while operators have priorities higher than 'limit'
+  var opPred = getPrecedence(p)
+  result = opPred
+  while opPred > limit: 
+    node = newNode(nkInfix)
+    opNode = newNode(nkIdent, p.tok.literal)
+    getTok(p)
+    result = lowestExprAux(p, v2, opPred)
+    node.add(opNode)
+    node.add(v)
+    node.add(v2)
+    v = node
+    opPred = getPrecedence(p)
+  
+proc parseExpr(p: var SqlParser): SqlNode = 
+  discard lowestExprAux(p, result, - 1)
+
+proc parseTableName(p: var SqlParser): SqlNode =
+  expectIdent(p)
+  result = primary(p)
+
+proc parseColumnReference(p: var SqlParser): SqlNode =
+  result = parseTableName(p)
+  if p.tok.kind == tkParLe:
+    getTok(p)
+    var a = result
+    result = newNode(nkColumnReference)
+    result.add(a)
+    result.add(parseTableName(p))
+    while p.tok.kind == tkComma:
+      getTok(p)
+      result.add(parseTableName(p))
+    eat(p, tkParRi)
+
+proc parseCheck(p: var SqlParser): SqlNode = 
+  getTok(p)
+  result = newNode(nkCheck)
+  result.add(parseExpr(p))
+
+proc parseConstraint(p: var SqlParser): SqlNode =
+  getTok(p)
+  result = newNode(nkConstraint)
+  expectIdent(p)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  eat(p, "check")
+  result.add(parseExpr(p))
+
+proc parseColumnConstraints(p: var SqlParser, result: SqlNode) =
+  while true:
+    if isKeyw(p, "default"):
+      getTok(p)
+      var n = newNode(nkDefault)
+      n.add(parseExpr(p))
+      result.add(n)
+    elif isKeyw(p, "references"):
+      getTok(p)
+      var n = newNode(nkReferences)
+      n.add(parseColumnReference(p))
+      result.add(n)
+    elif isKeyw(p, "not"):
+      getTok(p)
+      eat(p, "null")
+      result.add(newNode(nkNotNull))
+    elif isKeyw(p, "identity"):
+      getTok(p)
+      result.add(newNode(nkIdentity))
+    elif isKeyw(p, "primary"):
+      getTok(p)
+      eat(p, "key")
+      result.add(newNode(nkPrimaryKey))
+    elif isKeyw(p, "check"):
+      result.add(parseCheck(p))
+    elif isKeyw(p, "constraint"):
+      result.add(parseConstraint(p))
+    elif isKeyw(p, "unique"):
+      result.add(newNode(nkUnique))
+    else:
+      break
+
+proc parseColumnDef(p: var SqlParser): SqlNode =
+  expectIdent(p)
+  result = newNode(nkColumnDef)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  result.add(parseDataType(p))
+  parseColumnConstraints(p, result)  
+
+proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode = 
+  getTok(p)
+  if isKeyw(p, "if"):
+    getTok(p)
+    eat(p, "not")
+    eat(p, "exists")
+    result = newNode(succ(k))
+  else:
+    result = newNode(k)
+
+proc parseParIdentList(p: var SqlParser, father: SqlNode) =
+  eat(p, tkParLe)
+  while true:
+    expectIdent(p)
+    father.add(newNode(nkIdent, p.tok.literal))
+    getTok(p)
+    if p.tok.kind != tkComma: break
+    getTok(p)
+  eat(p, tkParRi)
+
+proc parseTableConstraint(p: var SqlParser): SqlNode =
+  if isKeyw(p, "primary"):
+    getTok(p)
+    eat(p, "key")
+    result = newNode(nkPrimaryKey)
+    parseParIdentList(p, result)
+  elif isKeyw(p, "foreign"):
+    getTok(p)
+    eat(p, "key")
+    result = newNode(nkForeignKey)
+    parseParIdentList(p, result)
+    eat(p, "references")
+    var m = newNode(nkReferences)
+    m.add(parseColumnReference(p))
+    result.add(m)
+  elif isKeyw(p, "unique"):
+    getTok(p)
+    eat(p, "key")
+    result = newNode(nkUnique)
+    parseParIdentList(p, result)
+  elif isKeyw(p, "check"):
+    result = parseCheck(p)
+  elif isKeyw(p, "constraint"):
+    result = parseConstraint(p)
+  else:
+    sqlError(p, "column definition expected")
+
+proc parseTableDef(p: var SqlParser): SqlNode =
+  result = parseIfNotExists(p, nkCreateTable)
+  expectIdent(p)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  if p.tok.kind == tkParLe:
+    while true:
+      getTok(p)
+      if p.tok.kind == tkIdentifier or p.tok.kind == tkQuotedIdentifier:
+        result.add(parseColumnDef(p))
+      else:
+        result.add(parseTableConstraint(p))
+      if p.tok.kind != tkComma: break
+    eat(p, tkParRi)
+  
+proc parseTypeDef(p: var SqlParser): SqlNode =
+  result = parseIfNotExists(p, nkCreateType)
+  expectIdent(p)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  eat(p, "as")
+  result.add(parseDataType(p))
+
+proc parseWhere(p: var SqlParser): SqlNode =
+  getTok(p)
+  result = newNode(nkWhere)
+  result.add(parseExpr(p))
+
+proc parseIndexDef(p: var SqlParser): SqlNode =
+  result = parseIfNotExists(p, nkCreateIndex)
+  if isKeyw(p, "primary"):
+    getTok(p)
+    eat(p, "key")
+    result.add(newNode(nkPrimaryKey))
+  else:
+    expectIdent(p)
+    result.add(newNode(nkIdent, p.tok.literal))
+    getTok(p)
+  eat(p, "on")
+  expectIdent(p)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  eat(p, tkParLe)
+  expectIdent(p)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  while p.tok.kind == tkComma:
+    getTok(p)
+    expectIdent(p)
+    result.add(newNode(nkIdent, p.tok.literal))
+    getTok(p)
+  eat(p, tkParRi)
+
+proc parseInsert(p: var SqlParser): SqlNode =
+  getTok(p)
+  eat(p, "into")
+  expectIdent(p)
+  result = newNode(nkInsert)
+  result.add(newNode(nkIdent, p.tok.literal))
+  getTok(p)
+  if p.tok.kind == tkParLe:
+    var n = newNode(nkColumnList)
+    parseParIdentList(p, n)
+  else:
+    result.add(nil)
+  if isKeyw(p, "default"):
+    getTok(p)
+    eat(p, "values")
+    result.add(newNode(nkDefault))
+  else:
+    eat(p, "values")
+    eat(p, tkParLe)
+    var n = newNode(nkValueList)
+    while true:
+      n.add(parseExpr(p))
+      if p.tok.kind != tkComma: break
+      getTok(p)
+    result.add(n)
+    eat(p, tkParRi)
+
+proc parseUpdate(p: var SqlParser): SqlNode =
+  getTok(p)
+  result = newNode(nkUpdate)
+  result.add(primary(p))
+  eat(p, "set")
+  while true:
+    var a = newNode(nkAsgn)
+    expectIdent(p)
+    a.add(newNode(nkIdent, p.tok.literal))
+    getTok(p)
+    if isOpr(p, "="): getTok(p)
+    else: sqlError(p, "= expected")
+    a.add(parseExpr(p))
+    result.add(a)
+    if p.tok.kind != tkComma: break
+    getTok(p)
+  if isKeyw(p, "where"):
+    result.add(parseWhere(p))
+  else:
+    result.add(nil)
+    
+proc parseDelete(p: var SqlParser): SqlNode =
+  getTok(p)
+  result = newNode(nkDelete)
+  eat(p, "from")
+  result.add(primary(p))
+  if isKeyw(p, "where"):
+    result.add(parseWhere(p))
+  else:
+    result.add(nil)
+
+proc parseSelect(p: var SqlParser): SqlNode =
+  getTok(p)
+  if isKeyw(p, "distinct"):
+    getTok(p)
+    result = newNode(nkSelectDistinct)
+  elif isKeyw(p, "all"):
+    getTok(p)
+  result = newNode(nkSelect)
+  var a = newNode(nkSelectColumns)
+  while true:
+    if isOpr(p, "*"):
+      a.add(newNode(nkIdent, "*"))
+      getTok(p)
+    else:
+      a.add(parseExpr(p))
+    if p.tok.kind != tkComma: break
+    getTok(p)
+  result.add(a)
+  if isKeyw(p, "from"):
+    var f = newNode(nkFrom)
+    while true:
+      getTok(p)
+      f.add(parseExpr(p))
+      if p.tok.kind != tkComma: break
+    result.add(f)
+  if isKeyw(p, "where"):
+    result.add(parseWhere(p))
+  if isKeyw(p, "group"):
+    getTok(p)
+    eat(p, "by")
+    var g = newNode(nkGroup)
+    while true:
+      g.add(parseExpr(p))
+      if p.tok.kind != tkComma: break
+      getTok(p)
+    result.add(g)
+  if isKeyw(p, "having"):
+    var h = newNode(nkHaving)
+    while true:
+      getTok(p)
+      h.add(parseExpr(p))
+      if p.tok.kind != tkComma: break    
+    result.add(h)
+  if isKeyw(p, "union"):
+    result.add(newNode(nkUnion))
+    getTok(p)
+  elif isKeyw(p, "intersect"):
+    result.add(newNode(nkIntersect))
+    getTok(p)  
+  elif isKeyw(p, "except"):
+    result.add(newNode(nkExcept))
+    getTok(p)
+  if isKeyw(p, "order"):
+    getTok(p)
+    eat(p, "by")
+    var n = newNode(nkOrder)
+    while true:
+      var e = parseExpr(p)
+      if isKeyw(p, "asc"): getTok(p) # is default
+      elif isKeyw(p, "desc"):
+        getTok(p)
+        var x = newNode(nkDesc)
+        x.add(e)
+        e = x
+      n.add(e)
+      if p.tok.kind != tkComma: break
+      getTok(p)
+    result.add(n)
+
+proc parseStmt(p: var SqlParser): SqlNode =
+  if isKeyw(p, "create"):
+    getTok(p)
+    optKeyw(p, "cached")
+    optKeyw(p, "memory")
+    optKeyw(p, "temp")
+    optKeyw(p, "global")
+    optKeyw(p, "local")
+    optKeyw(p, "temporary")
+    optKeyw(p, "unique")
+    optKeyw(p, "hash")
+    if isKeyw(p, "table"):
+      result = parseTableDef(p)
+    elif isKeyw(p, "type"):
+      result = parseTypeDef(p)
+    elif isKeyw(p, "index"):
+      result = parseIndexDef(p)
+    else:
+      sqlError(p, "TABLE expected")
+  elif isKeyw(p, "insert"):
+    result = parseInsert(p)
+  elif isKeyw(p, "update"):
+    result = parseUpdate(p)
+  elif isKeyw(p, "delete"):
+    result = parseDelete(p)
+  elif isKeyw(p, "select"):
+    result = parseSelect(p)
+  else:
+    sqlError(p, "CREATE expected")
+
+proc open(p: var SqlParser, input: Stream, filename: string) =
+  ## opens the parser `p` and assigns the input stream `input` to it.
+  ## `filename` is only used for error messages.
+  open(SqlLexer(p), input, filename)
+  p.tok.kind = tkInvalid
+  p.tok.literal = ""
+  getTok(p)
+  
+proc parse(p: var SqlParser): SqlNode =
+  ## parses the content of `p`'s input stream and returns the SQL AST.
+  ## Syntax errors raise an `EInvalidSql` exception.
+  result = newNode(nkStmtList)
+  while p.tok.kind != tkEof:
+    var s = parseStmt(p)
+    eat(p, tkSemicolon)
+    result.add(s)
+  if result.len == 1:
+    result = result.sons[0]
+  
+proc close(p: var SqlParser) =
+  ## closes the parser `p`. The associated input stream is closed too.
+  close(SqlLexer(p))
+
+proc parseSQL*(input: Stream, filename: string): SqlNode =
+  ## parses the SQL from `input` into an AST and returns the AST. 
+  ## `filename` is only used for error messages.
+  ## Syntax errors raise an `EInvalidSql` exception.
+  var p: SqlParser
+  open(p, input, filename)
+  try:
+    result = parse(p)
+  finally:
+    close(p)
+
+proc ra(n: SqlNode, s: var string, indent: int)
+
+proc rs(n: SqlNode, s: var string, indent: int,
+        prefix = "(", suffix = ")",
+        sep = ", ") = 
+  if n.len > 0:
+    s.add(prefix)
+    for i in 0 .. n.len-1:
+      if i > 0: s.add(sep)
+      ra(n.sons[i], s, indent)
+    s.add(suffix)
+
+proc ra(n: SqlNode, s: var string, indent: int) =
+  if n == nil: return
+  case n.kind
+  of nkNone: discard
+  of nkIdent:
+    if allCharsInSet(n.strVal, {'\33'..'\127'}):
+      s.add(n.strVal)
+    else:
+      s.add("\"" & replace(n.strVal, "\"", "\"\"") & "\"")
+  of nkStringLit:
+    s.add(escape(n.strVal, "e'", "'"))
+  of nkBitStringLit:
+    s.add("b'" & n.strVal & "'")
+  of nkHexStringLit:
+    s.add("x'" & n.strVal & "'")
+  of nkIntegerLit, nkNumericLit:
+    s.add(n.strVal)
+  of nkPrimaryKey:
+    s.add(" primary key")
+    rs(n, s, indent)
+  of nkForeignKey:
+    s.add(" foreign key")
+    rs(n, s, indent)
+  of nkNotNull:
+    s.add(" not null")
+  of nkDot:
+    ra(n.sons[0], s, indent)
+    s.add(".")
+    ra(n.sons[1], s, indent)
+  of nkDotDot:
+    ra(n.sons[0], s, indent)
+    s.add(". .")
+    ra(n.sons[1], s, indent)
+  of nkPrefix:
+    s.add('(')
+    ra(n.sons[0], s, indent)
+    s.add(' ')
+    ra(n.sons[1], s, indent)
+    s.add(')')
+  of nkInfix:
+    s.add('(')    
+    ra(n.sons[1], s, indent)
+    s.add(' ')
+    ra(n.sons[0], s, indent)
+    s.add(' ')
+    ra(n.sons[2], s, indent)
+    s.add(')')
+  of nkCall, nkColumnReference:
+    ra(n.sons[0], s, indent)
+    s.add('(')
+    for i in 1..n.len-1:
+      if i > 1: s.add(", ")
+      ra(n.sons[i], s, indent)
+    s.add(')')
+  of nkReferences:
+    s.add(" references ")
+    ra(n.sons[0], s, indent)
+  of nkDefault:
+    s.add(" default ")
+    ra(n.sons[0], s, indent)
+  of nkCheck:
+    s.add(" check ")
+    ra(n.sons[0], s, indent)
+  of nkConstraint:
+    s.add(" constraint ")
+    ra(n.sons[0], s, indent)
+    s.add(" check ")
+    ra(n.sons[1], s, indent)
+  of nkUnique:
+    s.add(" unique")
+    rs(n, s, indent)
+  of nkIdentity:
+    s.add(" identity")
+  of nkColumnDef:
+    s.add("\n  ")
+    rs(n, s, indent, "", "", " ")
+  of nkStmtList:
+    for i in 0..n.len-1:
+      ra(n.sons[i], s, indent)
+      s.add("\n")
+  of nkInsert:
+    assert n.len == 3
+    s.add("insert into ")
+    ra(n.sons[0], s, indent)
+    ra(n.sons[1], s, indent)
+    if n.sons[2].kind == nkDefault: 
+      s.add("default values")
+    else:
+      s.add("\nvalues ")
+      ra(n.sons[2], s, indent)
+    s.add(';')
+  of nkUpdate: 
+    s.add("update ")
+    ra(n.sons[0], s, indent)
+    s.add(" set ")
+    var L = n.len
+    for i in 1 .. L-2:
+      if i > 1: s.add(", ")
+      var it = n.sons[i]
+      assert it.kind == nkAsgn
+      ra(it, s, indent)
+    ra(n.sons[L-1], s, indent)
+    s.add(';')
+  of nkDelete: 
+    s.add("delete from ")
+    ra(n.sons[0], s, indent)
+    ra(n.sons[1], s, indent)
+    s.add(';')
+  of nkSelect, nkSelectDistinct:
+    s.add("select ")
+    if n.kind == nkSelectDistinct:
+      s.add("distinct ")
+    rs(n.sons[0], s, indent, "", "", ", ")
+    for i in 1 .. n.len-1: ra(n.sons[i], s, indent)
+    s.add(';')
+  of nkSelectColumns: 
+    assert(false)
+  of nkAsgn:
+    ra(n.sons[0], s, indent)
+    s.add(" = ")
+    ra(n.sons[1], s, indent)  
+  of nkFrom:
+    s.add("\nfrom ")
+    rs(n, s, indent, "", "", ", ")
+  of nkGroup:
+    s.add("\ngroup by")
+    rs(n, s, indent, "", "", ", ")
+  of nkHaving:
+    s.add("\nhaving")
+    rs(n, s, indent, "", "", ", ")
+  of nkOrder:
+    s.add("\norder by ")
+    rs(n, s, indent, "", "", ", ")
+  of nkDesc:
+    ra(n.sons[0], s, indent)
+    s.add(" desc")
+  of nkUnion:
+    s.add(" union")
+  of nkIntersect:
+    s.add(" intersect")
+  of nkExcept:
+    s.add(" except")
+  of nkColumnList:
+    rs(n, s, indent)
+  of nkValueList:
+    s.add("values ")
+    rs(n, s, indent)
+  of nkWhere:
+    s.add("\nwhere ")
+    ra(n.sons[0], s, indent)
+  of nkCreateTable, nkCreateTableIfNotExists:
+    s.add("create table ")
+    if n.kind == nkCreateTableIfNotExists:
+      s.add("if not exists ")
+    ra(n.sons[0], s, indent)
+    s.add('(')
+    for i in 1..n.len-1:
+      if i > 1: s.add(", ")
+      ra(n.sons[i], s, indent)
+    s.add(");")
+  of nkCreateType, nkCreateTypeIfNotExists:
+    s.add("create type ")
+    if n.kind == nkCreateTypeIfNotExists:
+      s.add("if not exists ")
+    ra(n.sons[0], s, indent)
+    s.add(" as ")
+    ra(n.sons[1], s, indent)
+    s.add(';')
+  of nkCreateIndex, nkCreateIndexIfNotExists:
+    s.add("create index ")
+    if n.kind == nkCreateIndexIfNotExists:
+      s.add("if not exists ")
+    ra(n.sons[0], s, indent)
+    s.add(" on ")
+    ra(n.sons[1], s, indent)
+    s.add('(')
+    for i in 2..n.len-1:
+      if i > 2: s.add(", ")
+      ra(n.sons[i], s, indent)
+    s.add(");")
+  of nkEnumDef:
+    s.add("enum ")
+    rs(n, s, indent)
+
+# What I want: 
+#
+#select(columns = [T1.all, T2.name], 
+#       fromm = [T1, T2],
+#       where = T1.name ==. T2.name,
+#       orderby = [name]):
+#  
+#for row in dbQuery(db, """select x, y, z 
+#                          from a, b 
+#                          where a.name = b.name"""):
+#  
+
+#select x, y, z:
+#  fromm: Table1, Table2
+#  where: x.name == y.name
+#db.select(fromm = [t1, t2], where = t1.name == t2.name):
+#for x, y, z in db.select(fromm = a, b where = a.name == b.name): 
+#  writeln x, y, z
+
+proc renderSQL*(n: SqlNode): string =
+  ## Converts an SQL abstract syntax tree to its string representation.
+  result = ""
+  ra(n, result, 0)
+
+when not defined(testing) and isMainModule:
+  echo(renderSQL(parseSQL(newStringStream("""
+      CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
+      CREATE TABLE holidays (
+         num_weeks int,
+         happiness happiness
+      );
+      CREATE INDEX table1_attr1 ON table1(attr1);
+      
+      SELECT * FROM myTab WHERE col1 = 'happy';
+  """), "stdin")))
+
+# CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
+# CREATE TABLE holidays (
+#    num_weeks int,
+#    happiness happiness
+# );
+# CREATE INDEX table1_attr1 ON table1(attr1)
diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim
new file mode 100644
index 000000000..56bf10768
--- /dev/null
+++ b/lib/pure/parseurl.nim
@@ -0,0 +1,114 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## **Warnings:** This module is deprecated since version 0.10.2.
+## Use the `uri <uri.html>`_ module instead.
+##
+## Parses & constructs URLs.
+
+{.deprecated.}
+
+import strutils
+
+type
+  Url* = tuple[      ## represents a *Uniform Resource Locator* (URL)
+                     ## any optional component is "" if it does not exist
+    scheme, username, password, 
+    hostname, port, path, query, anchor: string]
+
+{.deprecated: [TUrl: Url].}
+
+proc parseUrl*(url: string): Url {.deprecated.} =
+  var i = 0
+
+  var scheme, username, password: string = ""
+  var hostname, port, path, query, anchor: string = ""
+
+  var temp = ""
+  
+  if url[i] != '/': # url isn't a relative path
+    while true:
+      # Scheme
+      if url[i] == ':':
+        if url[i+1] == '/' and url[i+2] == '/':
+          scheme = temp
+          temp.setLen(0)
+          inc(i, 3) # Skip the //
+      # Authority(username, password)
+      if url[i] == '@':
+        username = temp
+        let colon = username.find(':')
+        if colon >= 0:
+          password = username.substr(colon+1)
+          username = username.substr(0, colon-1)
+        temp.setLen(0)
+        inc(i) #Skip the @ 
+      # hostname(subdomain, domain, port)
+      if url[i] == '/' or url[i] == '\0':
+        hostname = temp
+        let colon = hostname.find(':')
+        if colon >= 0:
+          port = hostname.substr(colon+1)
+          hostname = hostname.substr(0, colon-1)
+        
+        temp.setLen(0)
+        break
+      
+      temp.add(url[i])
+      inc(i)
+
+  if url[i] == '/': inc(i) # Skip the '/'
+  # Path
+  while true:
+    if url[i] == '?':
+      path = temp
+      temp.setLen(0)
+    if url[i] == '#':
+      if temp[0] == '?':
+        query = temp
+      else:
+        path = temp
+      temp.setLen(0)
+      
+    if url[i] == '\0':
+      if temp[0] == '?':
+        query = temp
+      elif temp[0] == '#':
+        anchor = temp
+      else:
+        path = temp
+      break
+      
+    temp.add(url[i])
+    inc(i)
+    
+  return (scheme, username, password, hostname, port, path, query, anchor)
+
+proc `$`*(u: Url): string {.deprecated.} =
+  ## turns the URL `u` into its string representation.
+  result = ""
+  if u.scheme.len > 0:
+    result.add(u.scheme)
+    result.add("://")
+  if u.username.len > 0:
+    result.add(u.username)
+    if u.password.len > 0:
+      result.add(":")
+      result.add(u.password)
+    result.add("@")
+  result.add(u.hostname)
+  if u.port.len > 0: 
+    result.add(":")
+    result.add(u.port)
+  if u.path.len > 0: 
+    result.add("/")
+    result.add(u.path)
+  result.add(u.query)
+  result.add(u.anchor)
+  
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
new file mode 100644
index 000000000..c07b713de
--- /dev/null
+++ b/lib/pure/parseutils.nim
@@ -0,0 +1,342 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains helpers for parsing tokens, numbers, identifiers, etc.
+
+{.deadCodeElim: on.}
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+include "system/inclrtl"
+
+const
+  Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
+  IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
+  IdentStartChars = {'a'..'z', 'A'..'Z', '_'}
+    ## copied from strutils
+
+proc toLower(c: char): char {.inline.} =
+  result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
+
+proc parseHex*(s: string, number: var int, start = 0): int {.
+  rtl, extern: "npuParseHex", noSideEffect.}  = 
+  ## Parses a hexadecimal number and stores its value in ``number``.
+  ##
+  ## Returns the number of the parsed characters or 0 in case of an error. This
+  ## proc is sensitive to the already existing value of ``number`` and will
+  ## likely not do what you want unless you make sure ``number`` is zero. You
+  ## can use this feature to *chain* calls, though the result int will quickly
+  ## overflow. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var value = 0
+  ##   discard parseHex("0x38", value)
+  ##   assert value == 56
+  ##   discard parseHex("0x34", value)
+  ##   assert value == 56 * 256 + 52
+  ##   value = -1
+  ##   discard parseHex("0x38", value)
+  ##   assert value == -200
+  ##
+  var i = start
+  var foundDigit = false
+  if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
+  elif s[i] == '#': inc(i)
+  while true: 
+    case s[i]
+    of '_': discard
+    of '0'..'9':
+      number = number shl 4 or (ord(s[i]) - ord('0'))
+      foundDigit = true
+    of 'a'..'f':
+      number = number shl 4 or (ord(s[i]) - ord('a') + 10)
+      foundDigit = true
+    of 'A'..'F':
+      number = number shl 4 or (ord(s[i]) - ord('A') + 10)
+      foundDigit = true
+    else: break
+    inc(i)
+  if foundDigit: result = i-start
+
+proc parseOct*(s: string, number: var int, start = 0): int  {.
+  rtl, extern: "npuParseOct", noSideEffect.} = 
+  ## parses an octal number and stores its value in ``number``. Returns
+  ## the number of the parsed characters or 0 in case of an error.
+  var i = start
+  var foundDigit = false
+  if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
+  while true: 
+    case s[i]
+    of '_': discard
+    of '0'..'7':
+      number = number shl 3 or (ord(s[i]) - ord('0'))
+      foundDigit = true
+    else: break
+    inc(i)
+  if foundDigit: result = i-start
+
+proc parseIdent*(s: string, ident: var string, start = 0): int =
+  ## parses an identifier and stores it in ``ident``. Returns
+  ## the number of the parsed characters or 0 in case of an error.
+  var i = start
+  if s[i] in IdentStartChars:
+    inc(i)
+    while s[i] in IdentChars: inc(i)
+    ident = substr(s, start, i-1)
+    result = i-start
+
+proc parseIdent*(s: string, start = 0): string =
+  ## parses an identifier and stores it in ``ident``. 
+  ## Returns the parsed identifier or an empty string in case of an error.
+  result = ""
+  var i = start
+
+  if s[i] in IdentStartChars:
+    inc(i)
+    while s[i] in IdentChars: inc(i)
+    
+    result = substr(s, start, i-1)
+
+proc parseToken*(s: string, token: var string, validChars: set[char],
+                 start = 0): int {.inline, deprecated.} =
+  ## parses a token and stores it in ``token``. Returns
+  ## the number of the parsed characters or 0 in case of an error. A token
+  ## consists of the characters in `validChars`. 
+  ##
+  ## **Deprecated since version 0.8.12**: Use ``parseWhile`` instead.
+  var i = start
+  while s[i] in validChars: inc(i)
+  result = i-start
+  token = substr(s, start, i-1)
+
+proc skipWhitespace*(s: string, start = 0): int {.inline.} =
+  ## skips the whitespace starting at ``s[start]``. Returns the number of
+  ## skipped characters.
+  while s[start+result] in Whitespace: inc(result)
+
+proc skip*(s, token: string, start = 0): int {.inline.} =
+  ## skips the `token` starting at ``s[start]``. Returns the length of `token`
+  ## or 0 if there was no `token` at ``s[start]``.
+  while result < token.len and s[result+start] == token[result]: inc(result)
+  if result != token.len: result = 0
+  
+proc skipIgnoreCase*(s, token: string, start = 0): int =
+  ## same as `skip` but case is ignored for token matching.
+  while result < token.len and
+      toLower(s[result+start]) == toLower(token[result]): inc(result)
+  if result != token.len: result = 0
+  
+proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
+  ## Skips all characters until one char from the set `until` is found
+  ## or the end is reached.
+  ## Returns number of characters skipped.
+  while s[result+start] notin until and s[result+start] != '\0': inc(result)
+
+proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
+  ## Skips all characters until the char `until` is found
+  ## or the end is reached.
+  ## Returns number of characters skipped.
+  while s[result+start] != until and s[result+start] != '\0': inc(result)
+
+proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
+  ## Skips all characters while one char from the set `token` is found.
+  ## Returns number of characters skipped.
+  while s[result+start] in toSkip and s[result+start] != '\0': inc(result)
+
+proc parseUntil*(s: string, token: var string, until: set[char],
+                 start = 0): int {.inline.} =
+  ## parses a token and stores it in ``token``. Returns
+  ## the number of the parsed characters or 0 in case of an error. A token
+  ## consists of the characters notin `until`. 
+  var i = start
+  while i < s.len and s[i] notin until: inc(i)
+  result = i-start
+  token = substr(s, start, i-1)
+
+proc parseUntil*(s: string, token: var string, until: char,
+                 start = 0): int {.inline.} =
+  ## parses a token and stores it in ``token``. Returns
+  ## the number of the parsed characters or 0 in case of an error. A token
+  ## consists of any character that is not the `until` character.
+  var i = start
+  while i < s.len and s[i] != until: inc(i)
+  result = i-start
+  token = substr(s, start, i-1)
+
+proc parseWhile*(s: string, token: var string, validChars: set[char],
+                 start = 0): int {.inline.} =
+  ## parses a token and stores it in ``token``. Returns
+  ## the number of the parsed characters or 0 in case of an error. A token
+  ## consists of the characters in `validChars`. 
+  var i = start
+  while s[i] in validChars: inc(i)
+  result = i-start
+  token = substr(s, start, i-1)
+
+proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
+  ## Finds the first occurrence of ``first``, then returns everything from there
+  ## up to ``second``(if ``second`` is '\0', then ``first`` is used).
+  var i = skipUntil(s, first, start)+1+start
+  result = ""
+  discard s.parseUntil(result, if second == '\0': first else: second, i)
+
+{.push overflowChecks: on.}
+# this must be compiled with overflow checking turned on:
+proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
+  var
+    sign: BiggestInt = -1
+    i = start
+  if s[i] == '+': inc(i)
+  elif s[i] == '-':
+    inc(i)
+    sign = 1
+  if s[i] in {'0'..'9'}:
+    b = 0
+    while s[i] in {'0'..'9'}:
+      b = b * 10 - (ord(s[i]) - ord('0'))
+      inc(i)
+      while s[i] == '_': inc(i) # underscores are allowed and ignored
+    b = b * sign
+    result = i - start
+{.pop.} # overflowChecks
+
+proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
+  rtl, extern: "npuParseBiggestInt", noSideEffect.} =
+  ## parses an integer starting at `start` and stores the value into `number`.
+  ## Result is the number of processed chars or 0 if there is no integer.
+  ## `EOverflow` is raised if an overflow occurs.
+  var res: BiggestInt
+  # use 'res' for exception safety (don't write to 'number' in case of an
+  # overflow exception:
+  result = rawParseInt(s, res, start)
+  number = res
+
+proc parseInt*(s: string, number: var int, start = 0): int {.
+  rtl, extern: "npuParseInt", noSideEffect.} =
+  ## parses an integer starting at `start` and stores the value into `number`.
+  ## Result is the number of processed chars or 0 if there is no integer.
+  ## `EOverflow` is raised if an overflow occurs.
+  var res: BiggestInt
+  result = parseBiggestInt(s, res, start)
+  if (sizeof(int) <= 4) and
+      ((res < low(int)) or (res > high(int))):
+    raise newException(OverflowError, "overflow")
+  elif result != 0:
+    number = int(res)
+
+proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
+  magic: "ParseBiggestFloat", importc: "nimParseBiggestFloat", noSideEffect.}
+  ## parses a float starting at `start` and stores the value into `number`.
+  ## Result is the number of processed chars or 0 if a parsing error
+  ## occurred.
+
+proc parseFloat*(s: string, number: var float, start = 0): int {.
+  rtl, extern: "npuParseFloat", noSideEffect.} =
+  ## parses a float starting at `start` and stores the value into `number`.
+  ## Result is the number of processed chars or 0 if there occurred a parsing
+  ## error.
+  var bf: BiggestFloat
+  result = parseBiggestFloat(s, bf, start)
+  if result != 0:
+    number = bf
+  
+type
+  InterpolatedKind* = enum   ## describes for `interpolatedFragments`
+                             ## which part of the interpolated string is
+                             ## yielded; for example in "str$$$var${expr}"
+    ikStr,                   ## ``str`` part of the interpolated string
+    ikDollar,                ## escaped ``$`` part of the interpolated string
+    ikVar,                   ## ``var`` part of the interpolated string
+    ikExpr                   ## ``expr`` part of the interpolated string
+
+{.deprecated: [TInterpolatedKind: InterpolatedKind].}
+
+iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
+  value: string] =
+  ## Tokenizes the string `s` into substrings for interpolation purposes.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   for k, v in interpolatedFragments("  $this is ${an  example}  $$"):
+  ##     echo "(", k, ", \"", v, "\")"
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   (ikString, "  ")
+  ##   (ikExpr, "this")
+  ##   (ikString, " is ")
+  ##   (ikExpr, "an  example")
+  ##   (ikString, "  ")
+  ##   (ikDollar, "$")
+  var i = 0
+  var kind: InterpolatedKind
+  while true:
+    var j = i
+    if s[j] == '$':
+      if s[j+1] == '{':
+        inc j, 2
+        var nesting = 0
+        while true:
+          case s[j]
+          of '{': inc nesting
+          of '}':
+            if nesting == 0: 
+              inc j
+              break
+            dec nesting
+          of '\0':
+            raise newException(ValueError, 
+              "Expected closing '}': " & substr(s, i, s.high))
+          else: discard
+          inc j
+        inc i, 2 # skip ${
+        kind = ikExpr
+      elif s[j+1] in IdentStartChars:
+        inc j, 2
+        while s[j] in IdentChars: inc(j)
+        inc i # skip $
+        kind = ikVar
+      elif s[j+1] == '$':
+        inc j, 2
+        inc i # skip $
+        kind = ikDollar
+      else:
+        raise newException(ValueError, 
+          "Unable to parse a varible name at " & substr(s, i, s.high))
+    else:
+      while j < s.len and s[j] != '$': inc j
+      kind = ikStr
+    if j > i:
+      # do not copy the trailing } for ikExpr:
+      yield (kind, substr(s, i, j-1-ord(kind == ikExpr)))
+    else:
+      break
+    i = j
+
+when isMainModule:
+  import sequtils
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                   (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  assert toSeq(interpolatedFragments(input)) == expected
+
+  var value = 0
+  discard parseHex("0x38", value)
+  assert value == 56
+  discard parseHex("0x34", value)
+  assert value == 56 * 256 + 52
+  value = -1
+  discard parseHex("0x38", value)
+  assert value == -200
+
+
+{.pop.}
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
new file mode 100644
index 000000000..eb792f086
--- /dev/null
+++ b/lib/pure/parsexml.nim
@@ -0,0 +1,662 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple high performance `XML`:idx: / `HTML`:idx:
+## parser. 
+## The only encoding that is supported is UTF-8. The parser has been designed
+## to be somewhat error correcting, so that even most "wild HTML" found on the 
+## web can be parsed with it. **Note:** This parser does not check that each
+## ``<tag>`` has a corresponding ``</tag>``! These checks have do be 
+## implemented by the client code for various reasons: 
+##
+## * Old HTML contains tags that have no end tag: ``<br>`` for example.
+## * HTML tags are case insensitive, XML tags are case sensitive. Since this
+##   library can parse both, only the client knows which comparison is to be
+##   used.
+## * Thus the checks would have been very difficult to implement properly with
+##   little benefit, especially since they are simple to implement in the 
+##   client. The client should use the `errorMsgExpected` proc to generate
+##   a nice error message that fits the other error messages this library
+##   creates.
+##
+##
+## Example 1: Retrieve HTML title
+## ==============================
+##
+## The file ``examples/htmltitle.nim`` demonstrates how to use the 
+## XML parser to accomplish a simple task: To determine the title of an HTML
+## document.
+##
+## .. code-block:: nim
+##     :file: examples/htmltitle.nim
+##
+##
+## Example 2: Retrieve all HTML links
+## ==================================
+##
+## The file ``examples/htmlrefs.nim`` demonstrates how to use the 
+## XML parser to accomplish another simple task: To determine all the links 
+## an HTML document contains.
+##
+## .. code-block:: nim
+##     :file: examples/htmlrefs.nim
+##
+
+import 
+  hashes, strutils, lexbase, streams, unicode
+
+# the parser treats ``<br />`` as ``<br></br>``
+
+#  xmlElementCloseEnd, ## ``/>`` 
+
+type 
+  XmlEventKind* = enum ## enumation of all events that may occur when parsing
+    xmlError,           ## an error occurred during parsing
+    xmlEof,             ## end of file reached
+    xmlCharData,        ## character data
+    xmlWhitespace,      ## whitespace has been parsed
+    xmlComment,         ## a comment has been parsed
+    xmlPI,              ## processing instruction (``<?name something ?>``)
+    xmlElementStart,    ## ``<elem>``
+    xmlElementEnd,      ## ``</elem>``
+    xmlElementOpen,     ## ``<elem 
+    xmlAttribute,       ## ``key = "value"`` pair
+    xmlElementClose,    ## ``>`` 
+    xmlCData,           ## ``<![CDATA[`` ... data ... ``]]>``
+    xmlEntity,          ## &entity;
+    xmlSpecial          ## ``<! ... data ... >``
+    
+  XmlErrorKind* = enum       ## enumeration that lists all errors that can occur
+    errNone,                 ## no error
+    errEndOfCDataExpected,   ## ``]]>`` expected
+    errNameExpected,         ## name expected
+    errSemicolonExpected,    ## ``;`` expected
+    errQmGtExpected,         ## ``?>`` expected
+    errGtExpected,           ## ``>`` expected
+    errEqExpected,           ## ``=`` expected
+    errQuoteExpected,        ## ``"`` or ``'`` expected
+    errEndOfCommentExpected  ## ``-->`` expected
+    
+  ParserState = enum 
+    stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError
+
+  XmlParseOption* = enum  ## options for the XML parser
+    reportWhitespace,      ## report whitespace
+    reportComments         ## report comments
+
+  XmlParser* = object of BaseLexer ## the parser object.
+    a, b, c: string
+    kind: XmlEventKind
+    err: XmlErrorKind
+    state: ParserState
+    filename: string
+    options: set[XmlParseOption]
+
+{.deprecated: [TXmlParser: XmlParser, TXmlParseOptions: XmlParseOption,
+    TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].}
+
+const
+  errorMessages: array[XmlErrorKind, string] = [
+    "no error",
+    "']]>' expected",
+    "name expected",
+    "';' expected",
+    "'?>' expected",
+    "'>' expected",
+    "'=' expected",
+    "'\"' or \"'\" expected",
+    "'-->' expected"
+  ]
+
+proc open*(my: var XmlParser, input: Stream, filename: string,
+           options: set[XmlParseOption] = {}) =
+  ## initializes the parser with an input stream. `Filename` is only used
+  ## for nice error messages. The parser's behaviour can be controlled by
+  ## the `options` parameter: If `options` contains ``reportWhitespace``
+  ## a whitespace token is reported as an ``xmlWhitespace`` event.
+  ## If `options` contains ``reportComments`` a comment token is reported as an
+  ## ``xmlComment`` event. 
+  lexbase.open(my, input)
+  my.filename = filename
+  my.state = stateStart
+  my.kind = xmlError
+  my.a = ""
+  my.b = ""
+  my.c = nil
+  my.options = options
+  
+proc close*(my: var XmlParser) {.inline.} = 
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+proc kind*(my: XmlParser): XmlEventKind {.inline.} = 
+  ## returns the current event type for the XML parser
+  return my.kind
+
+template charData*(my: XmlParser): string =
+  ## returns the character data for the events: ``xmlCharData``, 
+  ## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial``
+  assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData, 
+                     xmlSpecial})
+  my.a
+
+template elementName*(my: XmlParser): string =
+  ## returns the element name for the events: ``xmlElementStart``, 
+  ## ``xmlElementEnd``, ``xmlElementOpen``
+  assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen})
+  my.a
+
+template entityName*(my: XmlParser): string =
+  ## returns the entity name for the event: ``xmlEntity``
+  assert(my.kind == xmlEntity)
+  my.a
+  
+template attrKey*(my: XmlParser): string =
+  ## returns the attribute key for the event ``xmlAttribute``
+  assert(my.kind == xmlAttribute)
+  my.a
+  
+template attrValue*(my: XmlParser): string =
+  ## returns the attribute value for the event ``xmlAttribute``
+  assert(my.kind == xmlAttribute)
+  my.b
+
+template piName*(my: XmlParser): string =
+  ## returns the processing instruction name for the event ``xmlPI``
+  assert(my.kind == xmlPI)
+  my.a
+
+template piRest*(my: XmlParser): string =
+  ## returns the rest of the processing instruction for the event ``xmlPI``
+  assert(my.kind == xmlPI)
+  my.b
+
+proc rawData*(my: XmlParser): string {.inline.} =
+  ## returns the underlying 'data' string by reference.
+  ## This is only used for speed hacks.
+  shallowCopy(result, my.a)
+
+proc rawData2*(my: XmlParser): string {.inline.} =
+  ## returns the underlying second 'data' string by reference.
+  ## This is only used for speed hacks.
+  shallowCopy(result, my.b)
+
+proc getColumn*(my: XmlParser): int {.inline.} = 
+  ## get the current column the parser has arrived at.
+  result = getColNumber(my, my.bufpos)
+
+proc getLine*(my: XmlParser): int {.inline.} = 
+  ## get the current line the parser has arrived at.
+  result = my.lineNumber
+
+proc getFilename*(my: XmlParser): string {.inline.} = 
+  ## get the filename of the file that the parser processes.
+  result = my.filename
+  
+proc errorMsg*(my: XmlParser): string = 
+  ## returns a helpful error message for the event ``xmlError``
+  assert(my.kind == xmlError)
+  result = "$1($2, $3) Error: $4" % [
+    my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]]
+
+proc errorMsgExpected*(my: XmlParser, tag: string): string = 
+  ## returns an error message "<tag> expected" in the same format as the
+  ## other error messages 
+  result = "$1($2, $3) Error: $4" % [
+    my.filename, $getLine(my), $getColumn(my), "<$1> expected" % tag]
+
+proc errorMsg*(my: XmlParser, msg: string): string = 
+  ## returns an error message with text `msg` in the same format as the
+  ## other error messages 
+  result = "$1($2, $3) Error: $4" % [
+    my.filename, $getLine(my), $getColumn(my), msg]
+    
+proc markError(my: var XmlParser, kind: XmlErrorKind) {.inline.} = 
+  my.err = kind
+  my.state = stateError
+
+proc parseCDATA(my: var XmlParser) = 
+  var pos = my.bufpos + len("<![CDATA[")
+  var buf = my.buf
+  while true:
+    case buf[pos] 
+    of ']':
+      if buf[pos+1] == ']' and buf[pos+2] == '>':
+        inc(pos, 3)
+        break
+      add(my.a, ']')
+      inc(pos)
+    of '\0': 
+      markError(my, errEndOfCDataExpected)
+      break
+    of '\c': 
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    of '\L': 
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)    
+  my.bufpos = pos # store back
+  my.kind = xmlCData
+
+proc parseComment(my: var XmlParser) = 
+  var pos = my.bufpos + len("<!--")
+  var buf = my.buf
+  while true:
+    case buf[pos] 
+    of '-':
+      if buf[pos+1] == '-' and buf[pos+2] == '>':
+        inc(pos, 3)
+        break
+      if my.options.contains(reportComments): add(my.a, '-')
+      inc(pos)
+    of '\0': 
+      markError(my, errEndOfCommentExpected)
+      break
+    of '\c': 
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      if my.options.contains(reportComments): add(my.a, '\L')
+    of '\L': 
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      if my.options.contains(reportComments): add(my.a, '\L')
+    else:
+      if my.options.contains(reportComments): add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+  my.kind = xmlComment
+
+proc parseWhitespace(my: var XmlParser, skip=false) = 
+  var pos = my.bufpos
+  var buf = my.buf
+  while true: 
+    case buf[pos]
+    of ' ', '\t': 
+      if not skip: add(my.a, buf[pos])
+      inc(pos)
+    of '\c':  
+      # the specification says that CR-LF, CR are to be transformed to LF
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      if not skip: add(my.a, '\L')
+    of '\L': 
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      if not skip: add(my.a, '\L')
+    else:
+      break
+  my.bufpos = pos
+
+const
+  NameStartChar = {'A'..'Z', 'a'..'z', '_', ':', '\128'..'\255'}
+  NameChar = {'A'..'Z', 'a'..'z', '0'..'9', '.', '-', '_', ':', '\128'..'\255'}
+
+proc parseName(my: var XmlParser, dest: var string) = 
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] in NameStartChar: 
+    while true:
+      add(dest, buf[pos])
+      inc(pos)
+      if buf[pos] notin NameChar: break
+    my.bufpos = pos
+  else:
+    markError(my, errNameExpected)
+
+proc parseEntity(my: var XmlParser, dest: var string) = 
+  var pos = my.bufpos+1
+  var buf = my.buf
+  my.kind = xmlCharData
+  if buf[pos] == '#':
+    var r: int
+    inc(pos)
+    if buf[pos] == 'x': 
+      inc(pos)
+      while true:
+        case buf[pos]
+        of '0'..'9': r = (r shl 4) or (ord(buf[pos]) - ord('0'))
+        of 'a'..'f': r = (r shl 4) or (ord(buf[pos]) - ord('a') + 10)
+        of 'A'..'F': r = (r shl 4) or (ord(buf[pos]) - ord('A') + 10)
+        else: break
+        inc(pos)
+    else:
+      while buf[pos] in {'0'..'9'}: 
+        r = r * 10 + (ord(buf[pos]) - ord('0'))
+        inc(pos)
+    add(dest, toUTF8(Rune(r)))
+  elif buf[pos] == 'l' and buf[pos+1] == 't' and buf[pos+2] == ';':
+    add(dest, '<')
+    inc(pos, 2)
+  elif buf[pos] == 'g' and buf[pos+1] == 't' and buf[pos+2] == ';':
+    add(dest, '>')
+    inc(pos, 2)
+  elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p' and
+      buf[pos+3] == ';':
+    add(dest, '&')
+    inc(pos, 3)
+  elif buf[pos] == 'a' and buf[pos+1] == 'p' and buf[pos+2] == 'o' and 
+      buf[pos+3] == 's' and buf[pos+4] == ';':
+    add(dest, '\'')
+    inc(pos, 4)
+  elif buf[pos] == 'q' and buf[pos+1] == 'u' and buf[pos+2] == 'o' and 
+      buf[pos+3] == 't' and buf[pos+4] == ';':
+    add(dest, '"')
+    inc(pos, 4)
+  else:
+    my.bufpos = pos
+    parseName(my, dest)
+    pos = my.bufpos
+    if my.err != errNameExpected: 
+      my.kind = xmlEntity
+    else:
+      add(dest, '&')
+  if buf[pos] == ';': 
+    inc(pos)
+  else:
+    markError(my, errSemicolonExpected)
+  my.bufpos = pos
+
+proc parsePI(my: var XmlParser) = 
+  inc(my.bufpos, "<?".len)
+  parseName(my, my.a)
+  var pos = my.bufpos
+  var buf = my.buf
+  setLen(my.b, 0)
+  while true: 
+    case buf[pos]
+    of '\0':
+      markError(my, errQmGtExpected)
+      break
+    of '?':
+      if buf[pos+1] == '>':
+        inc(pos, 2)
+        break
+      add(my.b, '?')
+      inc(pos)
+    of '\c':
+      # the specification says that CR-LF, CR are to be transformed to LF
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf      
+      add(my.b, '\L')
+    of '\L': 
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.b, '\L')
+    else:
+      add(my.b, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+  my.kind = xmlPI
+
+proc parseSpecial(my: var XmlParser) = 
+  # things that start with <!
+  var pos = my.bufpos + 2
+  var buf = my.buf
+  var opentags = 0
+  while true: 
+    case buf[pos]
+    of '\0':
+      markError(my, errGtExpected)
+      break
+    of '<': 
+      inc(opentags)
+      inc(pos)
+      add(my.a, '<')
+    of '>':
+      if opentags <= 0:
+        inc(pos)
+        break
+      dec(opentags)
+      inc(pos)
+      add(my.a, '>')
+    of '\c':  
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    of '\L': 
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+  my.kind = xmlSpecial
+
+proc parseTag(my: var XmlParser) = 
+  inc(my.bufpos)
+  parseName(my, my.a)
+  # if we have no name, do not interpret the '<':
+  if my.a.len == 0: 
+    my.kind = xmlCharData
+    add(my.a, '<')
+    return
+  parseWhitespace(my, skip=true)
+  if my.buf[my.bufpos] in NameStartChar: 
+    # an attribute follows:
+    my.kind = xmlElementOpen
+    my.state = stateAttr
+    my.c = my.a # save for later
+  else:
+    my.kind = xmlElementStart
+    if my.buf[my.bufpos] == '/' and my.buf[my.bufpos+1] == '>':
+      inc(my.bufpos, 2)
+      my.state = stateEmptyElementTag
+      my.c = nil
+    elif my.buf[my.bufpos] == '>':
+      inc(my.bufpos)  
+    else:
+      markError(my, errGtExpected)
+  
+proc parseEndTag(my: var XmlParser) = 
+  inc(my.bufpos, 2)
+  parseName(my, my.a)
+  parseWhitespace(my, skip=true)
+  if my.buf[my.bufpos] == '>':
+    inc(my.bufpos)
+  else:
+    markError(my, errGtExpected)
+  my.kind = xmlElementEnd
+
+proc parseAttribute(my: var XmlParser) = 
+  my.kind = xmlAttribute
+  setLen(my.a, 0)
+  setLen(my.b, 0)
+  parseName(my, my.a)
+  # if we have no name, we have '<tag attr= key %&$$%':
+  if my.a.len == 0: 
+    markError(my, errGtExpected)
+    return
+  parseWhitespace(my, skip=true)
+  if my.buf[my.bufpos] != '=':
+    markError(my, errEqExpected)
+    return
+  inc(my.bufpos)
+  parseWhitespace(my, skip=true)
+
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] in {'\'', '"'}:
+    var quote = buf[pos]
+    var pendingSpace = false
+    inc(pos)
+    while true: 
+      case buf[pos]
+      of '\0':
+        markError(my, errQuoteExpected)
+        break
+      of '&': 
+        if pendingSpace: 
+          add(my.b, ' ')
+          pendingSpace = false
+        my.bufpos = pos
+        parseEntity(my, my.b)
+        my.kind = xmlAttribute # parseEntity overwrites my.kind!
+        pos = my.bufpos
+      of ' ', '\t': 
+        pendingSpace = true
+        inc(pos)
+      of '\c':  
+        pos = lexbase.handleCR(my, pos)
+        buf = my.buf
+        pendingSpace = true
+      of '\L': 
+        pos = lexbase.handleLF(my, pos)
+        buf = my.buf
+        pendingSpace = true
+      else:
+        if buf[pos] == quote:
+          inc(pos)
+          break
+        else:
+          if pendingSpace: 
+            add(my.b, ' ')
+            pendingSpace = false
+          add(my.b, buf[pos])
+          inc(pos)
+  else:
+    markError(my, errQuoteExpected)  
+  my.bufpos = pos
+  parseWhitespace(my, skip=true)
+  
+proc parseCharData(my: var XmlParser) = 
+  var pos = my.bufpos
+  var buf = my.buf
+  while true: 
+    case buf[pos]
+    of '\0', '<', '&': break
+    of '\c':  
+      # the specification says that CR-LF, CR are to be transformed to LF
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    of '\L': 
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+  my.kind = xmlCharData
+
+proc rawGetTok(my: var XmlParser) = 
+  my.kind = xmlError
+  setLen(my.a, 0)
+  var pos = my.bufpos
+  var buf = my.buf
+  case buf[pos]
+  of '<': 
+    case buf[pos+1]
+    of '/':
+      parseEndTag(my)
+    of '!':
+      if buf[pos+2] == '[' and buf[pos+3] == 'C' and buf[pos+4] == 'D' and
+          buf[pos+5] == 'A' and buf[pos+6] == 'T' and buf[pos+7] == 'A' and
+          buf[pos+8] == '[':
+        parseCDATA(my)
+      elif buf[pos+2] == '-' and buf[pos+3] == '-': 
+        parseComment(my)
+      else: 
+        parseSpecial(my)
+    of '?':
+      parsePI(my)
+    else: 
+      parseTag(my)
+  of ' ', '\t', '\c', '\l': 
+    parseWhitespace(my)
+    my.kind = xmlWhitespace
+  of '\0': 
+    my.kind = xmlEof
+  of '&':
+    parseEntity(my, my.a)
+  else: 
+    parseCharData(my)
+  assert my.kind != xmlError
+    
+proc getTok(my: var XmlParser) = 
+  while true:
+    rawGetTok(my)
+    case my.kind
+    of xmlComment: 
+      if my.options.contains(reportComments): break
+    of xmlWhitespace: 
+      if my.options.contains(reportWhitespace): break
+    else: break
+    
+proc next*(my: var XmlParser) = 
+  ## retrieves the first/next event. This controls the parser.
+  case my.state
+  of stateNormal:
+    getTok(my)  
+  of stateStart:
+    my.state = stateNormal
+    getTok(my)
+    if my.kind == xmlPI and my.a == "xml": 
+      # just skip the first ``<?xml >`` processing instruction
+      getTok(my)
+  of stateAttr:
+    # parse an attribute key-value pair:
+    if my.buf[my.bufpos] == '>':
+      my.kind = xmlElementClose
+      inc(my.bufpos)
+      my.state = stateNormal
+    elif my.buf[my.bufpos] == '/' and my.buf[my.bufpos+1] == '>': 
+      my.kind = xmlElementClose
+      inc(my.bufpos, 2)
+      my.state = stateEmptyElementTag
+    else:
+      parseAttribute(my)
+      # state remains the same
+  of stateEmptyElementTag:
+    my.state = stateNormal
+    my.kind = xmlElementEnd
+    if not my.c.isNil:
+      my.a = my.c
+  of stateError: 
+    my.kind = xmlError
+    my.state = stateNormal
+  
+when not defined(testing) and isMainModule:
+  import os
+  var s = newFileStream(paramStr(1), fmRead)
+  if s == nil: quit("cannot open the file" & paramStr(1))
+  var x: XmlParser
+  open(x, s, paramStr(1))
+  while true:
+    next(x)
+    case x.kind
+    of xmlError: echo(x.errorMsg())
+    of xmlEof: break
+    of xmlCharData: echo(x.charData)
+    of xmlWhitespace: echo("|$1|" % x.charData)
+    of xmlComment: echo("<!-- $1 -->" % x.charData)
+    of xmlPI: echo("<? $1 ## $2 ?>" % [x.piName, x.piRest])
+    of xmlElementStart: echo("<$1>" % x.elementName)
+    of xmlElementEnd: echo("</$1>" % x.elementName)
+    
+    of xmlElementOpen: echo("<$1" % x.elementName) 
+    of xmlAttribute:   
+      echo("Key: " & x.attrKey)
+      echo("Value: " & x.attrValue)
+    
+    of xmlElementClose: echo(">") 
+    of xmlCData:
+      echo("<![CDATA[$1]]>" % x.charData)
+    of xmlEntity:
+      echo("&$1;" % x.entityName)
+    of xmlSpecial:
+      echo("SPECIAL: " & x.charData)
+  close(x)
+
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
new file mode 100644
index 000000000..39f0bfa95
--- /dev/null
+++ b/lib/pure/pegs.nim
@@ -0,0 +1,1791 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Simple PEG (Parsing expression grammar) matching. Uses no memorization, but
+## uses superoperators and symbol inlining to improve performance. Note:
+## Matching performance is hopefully competitive with optimized regular
+## expression engines.
+##
+## .. include:: ../doc/pegdocs.txt
+##
+
+include "system/inclrtl"
+
+const
+  useUnicode = true ## change this to deactivate proper UTF-8 support
+
+import
+  strutils
+
+when useUnicode:
+  import unicode
+
+const
+  InlineThreshold = 5  ## number of leaves; -1 to disable inlining
+  MaxSubpatterns* = 20 ## defines the maximum number of subpatterns that
+                       ## can be captured. More subpatterns cannot be captured!
+
+type
+  PegKind = enum
+    pkEmpty,
+    pkAny,              ## any character (.)
+    pkAnyRune,          ## any Unicode character (_)
+    pkNewLine,          ## CR-LF, LF, CR
+    pkLetter,           ## Unicode letter
+    pkLower,            ## Unicode lower case letter
+    pkUpper,            ## Unicode upper case letter
+    pkTitle,            ## Unicode title character
+    pkWhitespace,       ## Unicode whitespace character
+    pkTerminal,
+    pkTerminalIgnoreCase,
+    pkTerminalIgnoreStyle,
+    pkChar,             ## single character to match
+    pkCharChoice,
+    pkNonTerminal,
+    pkSequence,         ## a b c ... --> Internal DSL: peg(a, b, c)
+    pkOrderedChoice,    ## a / b / ... --> Internal DSL: a / b or /[a, b, c]
+    pkGreedyRep,        ## a*     --> Internal DSL: *a
+                        ## a+     --> (a a*)
+    pkGreedyRepChar,    ## x* where x is a single character (superop)
+    pkGreedyRepSet,     ## [set]* (superop)
+    pkGreedyAny,        ## .* or _* (superop)
+    pkOption,           ## a?     --> Internal DSL: ?a
+    pkAndPredicate,     ## &a     --> Internal DSL: &a
+    pkNotPredicate,     ## !a     --> Internal DSL: !a
+    pkCapture,          ## {a}    --> Internal DSL: capture(a)
+    pkBackRef,          ## $i     --> Internal DSL: backref(i)
+    pkBackRefIgnoreCase,
+    pkBackRefIgnoreStyle,
+    pkSearch,           ## @a     --> Internal DSL: !*a
+    pkCapturedSearch,   ## {@} a  --> Internal DSL: !*\a
+    pkRule,             ## a <- b
+    pkList,             ## a, b
+    pkStartAnchor       ## ^      --> Internal DSL: startAnchor()
+  NonTerminalFlag = enum
+    ntDeclared, ntUsed
+  NonTerminalObj = object         ## represents a non terminal symbol
+    name: string                  ## the name of the symbol
+    line: int                     ## line the symbol has been declared/used in
+    col: int                      ## column the symbol has been declared/used in
+    flags: set[NonTerminalFlag]   ## the nonterminal's flags
+    rule: TNode                   ## the rule that the symbol refers to
+  TNode {.shallow.} = object
+    case kind: PegKind
+    of pkEmpty..pkWhitespace: nil
+    of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
+    of pkChar, pkGreedyRepChar: ch: char
+    of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
+    of pkNonTerminal: nt: NonTerminal
+    of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
+    else: sons: seq[TNode]
+  NonTerminal* = ref NonTerminalObj
+
+  Peg* = TNode ## type that represents a PEG
+
+{.deprecated: [TPeg: Peg].}
+
+proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
+  ## constructs a PEG from a terminal string
+  if t.len != 1:
+    result.kind = pkTerminal
+    result.term = t
+  else:
+    result.kind = pkChar
+    result.ch = t[0]
+
+proc termIgnoreCase*(t: string): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a PEG from a terminal string; ignore case for matching
+  result.kind = pkTerminalIgnoreCase
+  result.term = t
+
+proc termIgnoreStyle*(t: string): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a PEG from a terminal string; ignore style for matching
+  result.kind = pkTerminalIgnoreStyle
+  result.term = t
+
+proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} =
+  ## constructs a PEG from a terminal char
+  assert t != '\0'
+  result.kind = pkChar
+  result.ch = t
+
+proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a PEG from a character set `s`
+  assert '\0' notin s
+  result.kind = pkCharChoice
+  new(result.charChoice)
+  result.charChoice[] = s
+
+proc len(a: Peg): int {.inline.} = return a.sons.len
+proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
+
+proc addChoice(dest: var Peg, elem: Peg) =
+  var L = dest.len-1
+  if L >= 0 and dest.sons[L].kind == pkCharChoice:
+    # caution! Do not introduce false aliasing here!
+    case elem.kind
+    of pkCharChoice:
+      dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
+    of pkChar:
+      dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
+    else: add(dest, elem)
+  else: add(dest, elem)
+
+template multipleOp(k: PegKind, localOpt: expr) =
+  result.kind = k
+  result.sons = @[]
+  for x in items(a):
+    if x.kind == k:
+      for y in items(x.sons):
+        localOpt(result, y)
+    else:
+      localOpt(result, x)
+  if result.len == 1:
+    result = result.sons[0]
+
+proc `/`*(a: varargs[Peg]): Peg {.
+  nosideEffect, rtl, extern: "npegsOrderedChoice".} =
+  ## constructs an ordered choice with the PEGs in `a`
+  multipleOp(pkOrderedChoice, addChoice)
+
+proc addSequence(dest: var Peg, elem: Peg) =
+  var L = dest.len-1
+  if L >= 0 and dest.sons[L].kind == pkTerminal:
+    # caution! Do not introduce false aliasing here!
+    case elem.kind
+    of pkTerminal:
+      dest.sons[L] = term(dest.sons[L].term & elem.term)
+    of pkChar:
+      dest.sons[L] = term(dest.sons[L].term & elem.ch)
+    else: add(dest, elem)
+  else: add(dest, elem)
+
+proc sequence*(a: varargs[Peg]): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a sequence with all the PEGs from `a`
+  multipleOp(pkSequence, addSequence)
+
+proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} =
+  ## constructs an optional for the PEG `a`
+  if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
+                pkGreedyRepSet}:
+    # a* ?  --> a*
+    # a? ?  --> a?
+    result = a
+  else:
+    result.kind = pkOption
+    result.sons = @[a]
+
+proc `*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyRep".} =
+  ## constructs a "greedy repetition" for the PEG `a`
+  case a.kind
+  of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption:
+    assert false
+    # produces endless loop!
+  of pkChar:
+    result.kind = pkGreedyRepChar
+    result.ch = a.ch
+  of pkCharChoice:
+    result.kind = pkGreedyRepSet
+    result.charChoice = a.charChoice # copying a reference suffices!
+  of pkAny, pkAnyRune:
+    result.kind = pkGreedyAny
+  else:
+    result.kind = pkGreedyRep
+    result.sons = @[a]
+
+proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} =
+  ## constructs a "search" for the PEG `a`
+  result.kind = pkSearch
+  result.sons = @[a]
+
+proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl,
+                             extern: "npgegsCapturedSearch".} =
+  ## constructs a "captured search" for the PEG `a`
+  result.kind = pkCapturedSearch
+  result.sons = @[a]
+
+proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} =
+  ## constructs a "greedy positive repetition" with the PEG `a`
+  return sequence(a, *a)
+
+proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} =
+  ## constructs an "and predicate" with the PEG `a`
+  result.kind = pkAndPredicate
+  result.sons = @[a]
+
+proc `!`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsNotPredicate".} =
+  ## constructs a "not predicate" with the PEG `a`
+  result.kind = pkNotPredicate
+  result.sons = @[a]
+
+proc any*: Peg {.inline.} =
+  ## constructs the PEG `any character`:idx: (``.``)
+  result.kind = pkAny
+
+proc anyRune*: Peg {.inline.} =
+  ## constructs the PEG `any rune`:idx: (``_``)
+  result.kind = pkAnyRune
+
+proc newLine*: Peg {.inline.} =
+  ## constructs the PEG `newline`:idx: (``\n``)
+  result.kind = pkNewLine
+
+proc unicodeLetter*: Peg {.inline.} =
+  ## constructs the PEG ``\letter`` which matches any Unicode letter.
+  result.kind = pkLetter
+
+proc unicodeLower*: Peg {.inline.} =
+  ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
+  result.kind = pkLower
+
+proc unicodeUpper*: Peg {.inline.} =
+  ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
+  result.kind = pkUpper
+
+proc unicodeTitle*: Peg {.inline.} =
+  ## constructs the PEG ``\title`` which matches any Unicode title letter.
+  result.kind = pkTitle
+
+proc unicodeWhitespace*: Peg {.inline.} =
+  ## constructs the PEG ``\white`` which matches any Unicode
+  ## whitespace character.
+  result.kind = pkWhitespace
+
+proc startAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``^`` which matches the start of the input.
+  result.kind = pkStartAnchor
+
+proc endAnchor*: Peg {.inline.} =
+  ## constructs the PEG ``$`` which matches the end of the input.
+  result = !any()
+
+proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} =
+  ## constructs a capture with the PEG `a`
+  result.kind = pkCapture
+  result.sons = @[a]
+
+proc backref*(index: range[1..MaxSubpatterns]): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a back reference of the given `index`. `index` starts counting
+  ## from 1.
+  result.kind = pkBackRef
+  result.index = index-1
+
+proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a back reference of the given `index`. `index` starts counting
+  ## from 1. Ignores case for matching.
+  result.kind = pkBackRefIgnoreCase
+  result.index = index-1
+
+proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".}=
+  ## constructs a back reference of the given `index`. `index` starts counting
+  ## from 1. Ignores style for matching.
+  result.kind = pkBackRefIgnoreStyle
+  result.index = index-1
+
+proc spaceCost(n: Peg): int =
+  case n.kind
+  of pkEmpty: discard
+  of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
+     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
+     pkAny..pkWhitespace, pkGreedyAny:
+    result = 1
+  of pkNonTerminal:
+    # we cannot inline a rule with a non-terminal
+    result = InlineThreshold+1
+  else:
+    for i in 0..n.len-1:
+      inc(result, spaceCost(n.sons[i]))
+      if result >= InlineThreshold: break
+
+proc nonterminal*(n: NonTerminal): Peg {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a PEG that consists of the nonterminal symbol
+  assert n != nil
+  if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
+    when false: echo "inlining symbol: ", n.name
+    result = n.rule # inlining of rule enables better optimizations
+  else:
+    result.kind = pkNonTerminal
+    result.nt = n
+
+proc newNonTerminal*(name: string, line, column: int): NonTerminal {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## constructs a nonterminal symbol
+  new(result)
+  result.name = name
+  result.line = line
+  result.col = column
+
+template letters*: expr =
+  ## expands to ``charset({'A'..'Z', 'a'..'z'})``
+  charSet({'A'..'Z', 'a'..'z'})
+
+template digits*: expr =
+  ## expands to ``charset({'0'..'9'})``
+  charSet({'0'..'9'})
+
+template whitespace*: expr =
+  ## expands to ``charset({' ', '\9'..'\13'})``
+  charSet({' ', '\9'..'\13'})
+
+template identChars*: expr =
+  ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
+  charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
+
+template identStartChars*: expr =
+  ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
+  charSet({'a'..'z', 'A'..'Z', '_'})
+
+template ident*: expr =
+  ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
+  sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
+           *charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
+
+template natural*: expr =
+  ## same as ``\d+``
+  +digits
+
+# ------------------------- debugging -----------------------------------------
+
+proc esc(c: char, reserved = {'\0'..'\255'}): string =
+  case c
+  of '\b': result = "\\b"
+  of '\t': result = "\\t"
+  of '\c': result = "\\c"
+  of '\L': result = "\\l"
+  of '\v': result = "\\v"
+  of '\f': result = "\\f"
+  of '\e': result = "\\e"
+  of '\a': result = "\\a"
+  of '\\': result = "\\\\"
+  of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
+  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
+  elif c in reserved: result = '\\' & c
+  else: result = $c
+
+proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
+
+proc singleQuoteEsc(str: string): string =
+  result = "'"
+  for c in items(str): add result, esc(c, {'\''})
+  add result, '\''
+
+proc charSetEscAux(cc: set[char]): string =
+  const reserved = {'^', '-', ']'}
+  result = ""
+  var c1 = 0
+  while c1 <= 0xff:
+    if chr(c1) in cc:
+      var c2 = c1
+      while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
+      if c1 == c2:
+        add result, esc(chr(c1), reserved)
+      elif c2 == succ(c1):
+        add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
+      else:
+        add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
+      c1 = c2
+    inc(c1)
+
+proc charSetEsc(cc: set[char]): string =
+  if card(cc) >= 128+64:
+    result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
+  else:
+    result = '[' & charSetEscAux(cc) & ']'
+
+proc toStrAux(r: Peg, res: var string) =
+  case r.kind
+  of pkEmpty: add(res, "()")
+  of pkAny: add(res, '.')
+  of pkAnyRune: add(res, '_')
+  of pkLetter: add(res, "\\letter")
+  of pkLower: add(res, "\\lower")
+  of pkUpper: add(res, "\\upper")
+  of pkTitle: add(res, "\\title")
+  of pkWhitespace: add(res, "\\white")
+
+  of pkNewLine: add(res, "\\n")
+  of pkTerminal: add(res, singleQuoteEsc(r.term))
+  of pkTerminalIgnoreCase:
+    add(res, 'i')
+    add(res, singleQuoteEsc(r.term))
+  of pkTerminalIgnoreStyle:
+    add(res, 'y')
+    add(res, singleQuoteEsc(r.term))
+  of pkChar: add(res, singleQuoteEsc(r.ch))
+  of pkCharChoice: add(res, charSetEsc(r.charChoice[]))
+  of pkNonTerminal: add(res, r.nt.name)
+  of pkSequence:
+    add(res, '(')
+    toStrAux(r.sons[0], res)
+    for i in 1 .. high(r.sons):
+      add(res, ' ')
+      toStrAux(r.sons[i], res)
+    add(res, ')')
+  of pkOrderedChoice:
+    add(res, '(')
+    toStrAux(r.sons[0], res)
+    for i in 1 .. high(r.sons):
+      add(res, " / ")
+      toStrAux(r.sons[i], res)
+    add(res, ')')
+  of pkGreedyRep:
+    toStrAux(r.sons[0], res)
+    add(res, '*')
+  of pkGreedyRepChar:
+    add(res, singleQuoteEsc(r.ch))
+    add(res, '*')
+  of pkGreedyRepSet:
+    add(res, charSetEsc(r.charChoice[]))
+    add(res, '*')
+  of pkGreedyAny:
+    add(res, ".*")
+  of pkOption:
+    toStrAux(r.sons[0], res)
+    add(res, '?')
+  of pkAndPredicate:
+    add(res, '&')
+    toStrAux(r.sons[0], res)
+  of pkNotPredicate:
+    add(res, '!')
+    toStrAux(r.sons[0], res)
+  of pkSearch:
+    add(res, '@')
+    toStrAux(r.sons[0], res)
+  of pkCapturedSearch:
+    add(res, "{@}")
+    toStrAux(r.sons[0], res)
+  of pkCapture:
+    add(res, '{')
+    toStrAux(r.sons[0], res)
+    add(res, '}')
+  of pkBackRef:
+    add(res, '$')
+    add(res, $r.index)
+  of pkBackRefIgnoreCase:
+    add(res, "i$")
+    add(res, $r.index)
+  of pkBackRefIgnoreStyle:
+    add(res, "y$")
+    add(res, $r.index)
+  of pkRule:
+    toStrAux(r.sons[0], res)
+    add(res, " <- ")
+    toStrAux(r.sons[1], res)
+  of pkList:
+    for i in 0 .. high(r.sons):
+      toStrAux(r.sons[i], res)
+      add(res, "\n")
+  of pkStartAnchor:
+    add(res, '^')
+
+proc `$` *(r: Peg): string {.nosideEffect, rtl, extern: "npegsToString".} =
+  ## converts a PEG to its string representation
+  result = ""
+  toStrAux(r, result)
+
+# --------------------- core engine -------------------------------------------
+
+type
+  Captures* = object ## contains the captured substrings.
+    matches: array[0..MaxSubpatterns-1, tuple[first, last: int]]
+    ml: int
+    origStart: int
+
+{.deprecated: [TCaptures: Captures].}
+
+proc bounds*(c: Captures,
+             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
+  ## returns the bounds ``[first..last]`` of the `i`'th capture.
+  result = c.matches[i]
+
+when not useUnicode:
+  type
+    Rune = char
+  template fastRuneAt(s, i, ch: expr) =
+    ch = s[i]
+    inc(i)
+  template runeLenAt(s, i: expr): expr = 1
+
+  proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'}
+  proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'}
+  proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'}
+  proc isTitle(a: char): bool {.inline.} = return false
+  proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
+
+proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {.
+               nosideEffect, rtl, extern: "npegs$1".} =
+  ## low-level matching proc that implements the PEG interpreter. Use this
+  ## for maximum efficiency (every other PEG operation ends up calling this
+  ## proc).
+  ## Returns -1 if it does not match, else the length of the match
+  case p.kind
+  of pkEmpty: result = 0 # match of length 0
+  of pkAny:
+    if s[start] != '\0': result = 1
+    else: result = -1
+  of pkAnyRune:
+    if s[start] != '\0':
+      result = runeLenAt(s, start)
+    else:
+      result = -1
+  of pkLetter:
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isAlpha(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkLower:
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isLower(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkUpper:
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isUpper(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkTitle:
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isTitle(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkWhitespace:
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isWhiteSpace(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkGreedyAny:
+    result = len(s) - start
+  of pkNewLine:
+    if s[start] == '\L': result = 1
+    elif s[start] == '\C':
+      if s[start+1] == '\L': result = 2
+      else: result = 1
+    else: result = -1
+  of pkTerminal:
+    result = len(p.term)
+    for i in 0..result-1:
+      if p.term[i] != s[start+i]:
+        result = -1
+        break
+  of pkTerminalIgnoreCase:
+    var
+      i = 0
+      a, b: Rune
+    result = start
+    while i < len(p.term):
+      fastRuneAt(p.term, i, a)
+      fastRuneAt(s, result, b)
+      if toLower(a) != toLower(b):
+        result = -1
+        break
+    dec(result, start)
+  of pkTerminalIgnoreStyle:
+    var
+      i = 0
+      a, b: Rune
+    result = start
+    while i < len(p.term):
+      while true:
+        fastRuneAt(p.term, i, a)
+        if a != Rune('_'): break
+      while true:
+        fastRuneAt(s, result, b)
+        if b != Rune('_'): break
+      if toLower(a) != toLower(b):
+        result = -1
+        break
+    dec(result, start)
+  of pkChar:
+    if p.ch == s[start]: result = 1
+    else: result = -1
+  of pkCharChoice:
+    if contains(p.charChoice[], s[start]): result = 1
+    else: result = -1
+  of pkNonTerminal:
+    var oldMl = c.ml
+    when false: echo "enter: ", p.nt.name
+    result = rawMatch(s, p.nt.rule, start, c)
+    when false: echo "leave: ", p.nt.name
+    if result < 0: c.ml = oldMl
+  of pkSequence:
+    var oldMl = c.ml
+    result = 0
+    for i in 0..high(p.sons):
+      var x = rawMatch(s, p.sons[i], start+result, c)
+      if x < 0:
+        c.ml = oldMl
+        result = -1
+        break
+      else: inc(result, x)
+  of pkOrderedChoice:
+    var oldMl = c.ml
+    for i in 0..high(p.sons):
+      result = rawMatch(s, p.sons[i], start, c)
+      if result >= 0: break
+      c.ml = oldMl
+  of pkSearch:
+    var oldMl = c.ml
+    result = 0
+    while start+result < s.len:
+      var x = rawMatch(s, p.sons[0], start+result, c)
+      if x >= 0:
+        inc(result, x)
+        return
+      inc(result)
+    result = -1
+    c.ml = oldMl
+  of pkCapturedSearch:
+    var idx = c.ml # reserve a slot for the subpattern
+    inc(c.ml)
+    result = 0
+    while start+result < s.len:
+      var x = rawMatch(s, p.sons[0], start+result, c)
+      if x >= 0:
+        if idx < MaxSubpatterns:
+          c.matches[idx] = (start, start+result-1)
+        #else: silently ignore the capture
+        inc(result, x)
+        return
+      inc(result)
+    result = -1
+    c.ml = idx
+  of pkGreedyRep:
+    result = 0
+    while true:
+      var x = rawMatch(s, p.sons[0], start+result, c)
+      # if x == 0, we have an endless loop; so the correct behaviour would be
+      # not to break. But endless loops can be easily introduced:
+      # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the
+      # expected thing in this case.
+      if x <= 0: break
+      inc(result, x)
+  of pkGreedyRepChar:
+    result = 0
+    var ch = p.ch
+    while ch == s[start+result]: inc(result)
+  of pkGreedyRepSet:
+    result = 0
+    while contains(p.charChoice[], s[start+result]): inc(result)
+  of pkOption:
+    result = max(0, rawMatch(s, p.sons[0], start, c))
+  of pkAndPredicate:
+    var oldMl = c.ml
+    result = rawMatch(s, p.sons[0], start, c)
+    if result >= 0: result = 0 # do not consume anything
+    else: c.ml = oldMl
+  of pkNotPredicate:
+    var oldMl = c.ml
+    result = rawMatch(s, p.sons[0], start, c)
+    if result < 0: result = 0
+    else:
+      c.ml = oldMl
+      result = -1
+  of pkCapture:
+    var idx = c.ml # reserve a slot for the subpattern
+    inc(c.ml)
+    result = rawMatch(s, p.sons[0], start, c)
+    if result >= 0:
+      if idx < MaxSubpatterns:
+        c.matches[idx] = (start, start+result-1)
+      #else: silently ignore the capture
+    else:
+      c.ml = idx
+  of pkBackRef..pkBackRefIgnoreStyle:
+    if p.index >= c.ml: return -1
+    var (a, b) = c.matches[p.index]
+    var n: Peg
+    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef))
+    n.term = s.substr(a, b)
+    result = rawMatch(s, n, start, c)
+  of pkStartAnchor:
+    if c.origStart == start: result = 0
+    else: result = -1
+  of pkRule, pkList: assert false
+
+template fillMatches(s, caps, c: expr) =
+  for k in 0..c.ml-1:
+    let startIdx = c.matches[k][0]
+    let endIdx = c.matches[k][1]
+    if startIdx != -1:
+      caps[k] = substr(s, startIdx, endIdx)
+    else:
+      caps[k] = nil
+
+proc matchLen*(s: string, pattern: Peg, matches: var openArray[string],
+               start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## the same as ``match``, but it returns the length of the match,
+  ## if there is no match, -1 is returned. Note that a match length
+  ## of zero can happen. It's possible that a suffix of `s` remains
+  ## that does not belong to the match.
+  var c: Captures
+  c.origStart = start
+  result = rawMatch(s, pattern, start, c)
+  if result >= 0: fillMatches(s, matches, c)
+
+proc matchLen*(s: string, pattern: Peg,
+               start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
+  ## the same as ``match``, but it returns the length of the match,
+  ## if there is no match, -1 is returned. Note that a match length
+  ## of zero can happen. It's possible that a suffix of `s` remains
+  ## that does not belong to the match.
+  var c: Captures
+  c.origStart = start
+  result = rawMatch(s, pattern, start, c)
+
+proc match*(s: string, pattern: Peg, matches: var openArray[string],
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
+  ## the captured substrings in the array ``matches``. If it does not
+  ## match, nothing is written into ``matches`` and ``false`` is
+  ## returned.
+  result = matchLen(s, pattern, matches, start) != -1
+
+proc match*(s: string, pattern: Peg,
+            start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
+  result = matchLen(s, pattern, start) != -1
+
+
+proc find*(s: string, pattern: Peg, matches: var openArray[string],
+           start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## returns the starting position of ``pattern`` in ``s`` and the captured
+  ## substrings in the array ``matches``. If it does not match, nothing
+  ## is written into ``matches`` and -1 is returned.
+  var c: Captures
+  c.origStart = start
+  for i in start .. s.len-1:
+    c.ml = 0
+    if rawMatch(s, pattern, i, c) >= 0:
+      fillMatches(s, matches, c)
+      return i
+  return -1
+  # could also use the pattern here: (!P .)* P
+
+proc findBounds*(s: string, pattern: Peg, matches: var openArray[string],
+                 start = 0): tuple[first, last: int] {.
+                 nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## returns the starting position and end position of ``pattern`` in ``s``
+  ## and the captured
+  ## substrings in the array ``matches``. If it does not match, nothing
+  ## is written into ``matches`` and (-1,0) is returned.
+  var c: Captures
+  c.origStart = start
+  for i in start .. s.len-1:
+    c.ml = 0
+    var L = rawMatch(s, pattern, i, c)
+    if L >= 0:
+      fillMatches(s, matches, c)
+      return (i, i+L-1)
+  return (-1, 0)
+
+proc find*(s: string, pattern: Peg,
+           start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns the starting position of ``pattern`` in ``s``. If it does not
+  ## match, -1 is returned.
+  var c: Captures
+  c.origStart = start
+  for i in start .. s.len-1:
+    if rawMatch(s, pattern, i, c) >= 0: return i
+  return -1
+
+iterator findAll*(s: string, pattern: Peg, start = 0): string =
+  ## yields all matching *substrings* of `s` that match `pattern`.
+  var c: Captures
+  c.origStart = start
+  var i = start
+  while i < s.len:
+    c.ml = 0
+    var L = rawMatch(s, pattern, i, c)
+    if L < 0:
+      inc(i, 1)
+    else:
+      yield substr(s, i, i+L-1)
+      inc(i, L)
+
+proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns all matching *substrings* of `s` that match `pattern`.
+  ## If it does not match, @[] is returned.
+  accumulateResult(findAll(s, pattern, start))
+
+when not defined(nimhygiene):
+  {.pragma: inject.}
+
+template `=~`*(s: string, pattern: Peg): bool =
+  ## This calls ``match`` with an implicit declared ``matches`` array that
+  ## can be used in the scope of the ``=~`` call:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
+  ##     # matches a key=value pair:
+  ##     echo("Key: ", matches[0])
+  ##     echo("Value: ", matches[1])
+  ##   elif line =~ peg"\s*{'#'.*}":
+  ##     # matches a comment
+  ##     # note that the implicit ``matches`` array is different from the
+  ##     # ``matches`` array of the first branch
+  ##     echo("comment: ", matches[0])
+  ##   else:
+  ##     echo("syntax error")
+  ##
+  bind MaxSubpatterns
+  when not declaredInScope(matches):
+    var matches {.inject.}: array[0..MaxSubpatterns-1, string]
+  match(s, pattern, matches)
+
+# ------------------------- more string handling ------------------------------
+
+proc contains*(s: string, pattern: Peg, start = 0): bool {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## same as ``find(s, pattern, start) >= 0``
+  return find(s, pattern, start) >= 0
+
+proc contains*(s: string, pattern: Peg, matches: var openArray[string],
+              start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
+  ## same as ``find(s, pattern, matches, start) >= 0``
+  return find(s, pattern, matches, start) >= 0
+
+proc startsWith*(s: string, prefix: Peg, start = 0): bool {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns true if `s` starts with the pattern `prefix`
+  result = matchLen(s, prefix, start) >= 0
+
+proc endsWith*(s: string, suffix: Peg, start = 0): bool {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## returns true if `s` ends with the pattern `prefix`
+  var c: Captures
+  c.origStart = start
+  for i in start .. s.len-1:
+    if rawMatch(s, suffix, i, c) == s.len - i: return true
+
+proc replacef*(s: string, sub: Peg, by: string): string {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
+  ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
+  ##
+  ## .. code-block:: nim
+  ##   "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   "var1<-keykey; val2<-key2key2"
+  result = ""
+  var i = 0
+  var caps: array[0..MaxSubpatterns-1, string]
+  var c: Captures
+  while i < s.len:
+    c.ml = 0
+    var x = rawMatch(s, sub, i, c)
+    if x <= 0:
+      add(result, s[i])
+      inc(i)
+    else:
+      fillMatches(s, caps, c)
+      addf(result, by, caps)
+      inc(i, x)
+  add(result, substr(s, i))
+
+proc replace*(s: string, sub: Peg, by = ""): string {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed
+  ## in `by`.
+  result = ""
+  var i = 0
+  var c: Captures
+  while i < s.len:
+    var x = rawMatch(s, sub, i, c)
+    if x <= 0:
+      add(result, s[i])
+      inc(i)
+    else:
+      add(result, by)
+      inc(i, x)
+  add(result, substr(s, i))
+
+proc parallelReplace*(s: string, subs: varargs[
+                      tuple[pattern: Peg, repl: string]]): string {.
+                      nosideEffect, rtl, extern: "npegs$1".} =
+  ## Returns a modified copy of `s` with the substitutions in `subs`
+  ## applied in parallel.
+  result = ""
+  var i = 0
+  var c: Captures
+  var caps: array[0..MaxSubpatterns-1, string]
+  while i < s.len:
+    block searchSubs:
+      for j in 0..high(subs):
+        c.ml = 0
+        var x = rawMatch(s, subs[j][0], i, c)
+        if x > 0:
+          fillMatches(s, caps, c)
+          addf(result, subs[j][1], caps)
+          inc(i, x)
+          break searchSubs
+      add(result, s[i])
+      inc(i)
+  # copy the rest:
+  add(result, substr(s, i))
+
+proc transformFile*(infile, outfile: string,
+                    subs: varargs[tuple[pattern: Peg, repl: string]]) {.
+                    rtl, extern: "npegs$1".} =
+  ## reads in the file `infile`, performs a parallel replacement (calls
+  ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
+  ## error occurs. This is supposed to be used for quick scripting.
+  var x = readFile(infile).string
+  writeFile(outfile, x.parallelReplace(subs))
+
+iterator split*(s: string, sep: Peg): string =
+  ## Splits the string `s` into substrings.
+  ##
+  ## Substrings are separated by the PEG `sep`.
+  ## Examples:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split("00232this02939is39an22example111", peg"\d+"):
+  ##     writeln(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   "example"
+  ##
+  var c: Captures
+  var
+    first = 0
+    last = 0
+  while last < len(s):
+    c.ml = 0
+    var x = rawMatch(s, sep, last, c)
+    if x > 0: inc(last, x)
+    first = last
+    while last < len(s):
+      inc(last)
+      c.ml = 0
+      x = rawMatch(s, sep, last, c)
+      if x > 0: break
+    if first < last:
+      yield substr(s, first, last-1)
+
+proc split*(s: string, sep: Peg): seq[string] {.
+  nosideEffect, rtl, extern: "npegs$1".} =
+  ## Splits the string `s` into substrings.
+  accumulateResult(split(s, sep))
+
+# ------------------- scanner -------------------------------------------------
+
+type
+  TModifier = enum
+    modNone,
+    modVerbatim,
+    modIgnoreCase,
+    modIgnoreStyle
+  TTokKind = enum       ## enumeration of all tokens
+    tkInvalid,          ## invalid token
+    tkEof,              ## end of file reached
+    tkAny,              ## .
+    tkAnyRune,          ## _
+    tkIdentifier,       ## abc
+    tkStringLit,        ## "abc" or 'abc'
+    tkCharSet,          ## [^A-Z]
+    tkParLe,            ## '('
+    tkParRi,            ## ')'
+    tkCurlyLe,          ## '{'
+    tkCurlyRi,          ## '}'
+    tkCurlyAt,          ## '{@}'
+    tkArrow,            ## '<-'
+    tkBar,              ## '/'
+    tkStar,             ## '*'
+    tkPlus,             ## '+'
+    tkAmp,              ## '&'
+    tkNot,              ## '!'
+    tkOption,           ## '?'
+    tkAt,               ## '@'
+    tkBuiltin,          ## \identifier
+    tkEscaped,          ## \\
+    tkBackref,          ## '$'
+    tkDollar,           ## '$'
+    tkHat               ## '^'
+
+  TToken {.final.} = object  ## a token
+    kind: TTokKind           ## the type of the token
+    modifier: TModifier
+    literal: string          ## the parsed (string) literal
+    charset: set[char]       ## if kind == tkCharSet
+    index: int               ## if kind == tkBackref
+
+  PegLexer {.inheritable.} = object          ## the lexer object.
+    bufpos: int               ## the current position within the buffer
+    buf: cstring              ## the buffer itself
+    lineNumber: int           ## the current line number
+    lineStart: int            ## index of last line start in buffer
+    colOffset: int            ## column to add
+    filename: string
+
+const
+  tokKindToStr: array[TTokKind, string] = [
+    "invalid", "[EOF]", ".", "_", "identifier", "string literal",
+    "character set", "(", ")", "{", "}", "{@}",
+    "<-", "/", "*", "+", "&", "!", "?",
+    "@", "built-in", "escaped", "$", "$", "^"
+  ]
+
+proc handleCR(L: var PegLexer, pos: int): int =
+  assert(L.buf[pos] == '\c')
+  inc(L.lineNumber)
+  result = pos+1
+  if L.buf[result] == '\L': inc(result)
+  L.lineStart = result
+
+proc handleLF(L: var PegLexer, pos: int): int =
+  assert(L.buf[pos] == '\L')
+  inc(L.lineNumber)
+  result = pos+1
+  L.lineStart = result
+
+proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) =
+  L.buf = input
+  L.bufpos = 0
+  L.lineNumber = line
+  L.colOffset = col
+  L.lineStart = 0
+  L.filename = filename
+
+proc getColumn(L: PegLexer): int {.inline.} =
+  result = abs(L.bufpos - L.lineStart) + L.colOffset
+
+proc getLine(L: PegLexer): int {.inline.} =
+  result = L.lineNumber
+
+proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string =
+  var line = if line < 0: getLine(L) else: line
+  var col = if col < 0: getColumn(L) else: col
+  result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
+
+proc handleHexChar(c: var PegLexer, 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: discard
+
+proc getEscapedChar(c: var PegLexer, tok: var TToken) =
+  inc(c.bufpos)
+  case c.buf[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 'x', 'X':
+    inc(c.bufpos)
+    var xi = 0
+    handleHexChar(c, xi)
+    handleHexChar(c, xi)
+    if xi == 0: tok.kind = tkInvalid
+    else: add(tok.literal, chr(xi))
+  of '0'..'9':
+    var val = ord(c.buf[c.bufpos]) - ord('0')
+    inc(c.bufpos)
+    var i = 1
+    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
+      val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
+      inc(c.bufpos)
+      inc(i)
+    if val > 0 and val <= 255: add(tok.literal, chr(val))
+    else: tok.kind = tkInvalid
+  of '\0'..'\31':
+    tok.kind = tkInvalid
+  elif c.buf[c.bufpos] in strutils.Letters:
+    tok.kind = tkInvalid
+  else:
+    add(tok.literal, c.buf[c.bufpos])
+    inc(c.bufpos)
+
+proc skip(c: var PegLexer) =
+  var pos = c.bufpos
+  var buf = c.buf
+  while true:
+    case buf[pos]
+    of ' ', '\t':
+      inc(pos)
+    of '#':
+      while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
+    of '\c':
+      pos = handleCR(c, pos)
+      buf = c.buf
+    of '\L':
+      pos = handleLF(c, pos)
+      buf = c.buf
+    else:
+      break                   # EndOfFile also leaves the loop
+  c.bufpos = pos
+
+proc getString(c: var PegLexer, tok: var TToken) =
+  tok.kind = tkStringLit
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  var quote = buf[pos-1]
+  while true:
+    case buf[pos]
+    of '\\':
+      c.bufpos = pos
+      getEscapedChar(c, tok)
+      pos = c.bufpos
+    of '\c', '\L', '\0':
+      tok.kind = tkInvalid
+      break
+    elif buf[pos] == quote:
+      inc(pos)
+      break
+    else:
+      add(tok.literal, buf[pos])
+      inc(pos)
+  c.bufpos = pos
+
+proc getDollar(c: var PegLexer, tok: var TToken) =
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  if buf[pos] in {'0'..'9'}:
+    tok.kind = tkBackref
+    tok.index = 0
+    while buf[pos] in {'0'..'9'}:
+      tok.index = tok.index * 10 + ord(buf[pos]) - ord('0')
+      inc(pos)
+  else:
+    tok.kind = tkDollar
+  c.bufpos = pos
+
+proc getCharSet(c: var PegLexer, tok: var TToken) =
+  tok.kind = tkCharSet
+  tok.charset = {}
+  var pos = c.bufpos + 1
+  var buf = c.buf
+  var caret = false
+  if buf[pos] == '^':
+    inc(pos)
+    caret = true
+  while true:
+    var ch: char
+    case buf[pos]
+    of ']':
+      inc(pos)
+      break
+    of '\\':
+      c.bufpos = pos
+      getEscapedChar(c, tok)
+      pos = c.bufpos
+      ch = tok.literal[tok.literal.len-1]
+    of '\C', '\L', '\0':
+      tok.kind = tkInvalid
+      break
+    else:
+      ch = buf[pos]
+      inc(pos)
+    incl(tok.charset, ch)
+    if buf[pos] == '-':
+      if buf[pos+1] == ']':
+        incl(tok.charset, '-')
+        inc(pos)
+      else:
+        inc(pos)
+        var ch2: char
+        case buf[pos]
+        of '\\':
+          c.bufpos = pos
+          getEscapedChar(c, tok)
+          pos = c.bufpos
+          ch2 = tok.literal[tok.literal.len-1]
+        of '\C', '\L', '\0':
+          tok.kind = tkInvalid
+          break
+        else:
+          ch2 = buf[pos]
+          inc(pos)
+        for i in ord(ch)+1 .. ord(ch2):
+          incl(tok.charset, chr(i))
+  c.bufpos = pos
+  if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
+
+proc getSymbol(c: var PegLexer, tok: var TToken) =
+  var pos = c.bufpos
+  var buf = c.buf
+  while true:
+    add(tok.literal, buf[pos])
+    inc(pos)
+    if buf[pos] notin strutils.IdentChars: break
+  c.bufpos = pos
+  tok.kind = tkIdentifier
+
+proc getBuiltin(c: var PegLexer, tok: var TToken) =
+  if c.buf[c.bufpos+1] in strutils.Letters:
+    inc(c.bufpos)
+    getSymbol(c, tok)
+    tok.kind = tkBuiltin
+  else:
+    tok.kind = tkEscaped
+    getEscapedChar(c, tok) # may set tok.kind to tkInvalid
+
+proc getTok(c: var PegLexer, tok: var TToken) =
+  tok.kind = tkInvalid
+  tok.modifier = modNone
+  setLen(tok.literal, 0)
+  skip(c)
+  case c.buf[c.bufpos]
+  of '{':
+    inc(c.bufpos)
+    if c.buf[c.bufpos] == '@' and c.buf[c.bufpos+1] == '}':
+      tok.kind = tkCurlyAt
+      inc(c.bufpos, 2)
+      add(tok.literal, "{@}")
+    else:
+      tok.kind = tkCurlyLe
+      add(tok.literal, '{')
+  of '}':
+    tok.kind = tkCurlyRi
+    inc(c.bufpos)
+    add(tok.literal, '}')
+  of '[':
+    getCharSet(c, tok)
+  of '(':
+    tok.kind = tkParLe
+    inc(c.bufpos)
+    add(tok.literal, '(')
+  of ')':
+    tok.kind = tkParRi
+    inc(c.bufpos)
+    add(tok.literal, ')')
+  of '.':
+    tok.kind = tkAny
+    inc(c.bufpos)
+    add(tok.literal, '.')
+  of '_':
+    tok.kind = tkAnyRune
+    inc(c.bufpos)
+    add(tok.literal, '_')
+  of '\\':
+    getBuiltin(c, tok)
+  of '\'', '"': getString(c, tok)
+  of '$': getDollar(c, tok)
+  of '\0':
+    tok.kind = tkEof
+    tok.literal = "[EOF]"
+  of 'a'..'z', 'A'..'Z', '\128'..'\255':
+    getSymbol(c, tok)
+    if c.buf[c.bufpos] in {'\'', '"'} or
+        c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
+      case tok.literal
+      of "i": tok.modifier = modIgnoreCase
+      of "y": tok.modifier = modIgnoreStyle
+      of "v": tok.modifier = modVerbatim
+      else: discard
+      setLen(tok.literal, 0)
+      if c.buf[c.bufpos] == '$':
+        getDollar(c, tok)
+      else:
+        getString(c, tok)
+      if tok.modifier == modNone: tok.kind = tkInvalid
+  of '+':
+    tok.kind = tkPlus
+    inc(c.bufpos)
+    add(tok.literal, '+')
+  of '*':
+    tok.kind = tkStar
+    inc(c.bufpos)
+    add(tok.literal, '+')
+  of '<':
+    if c.buf[c.bufpos+1] == '-':
+      inc(c.bufpos, 2)
+      tok.kind = tkArrow
+      add(tok.literal, "<-")
+    else:
+      add(tok.literal, '<')
+  of '/':
+    tok.kind = tkBar
+    inc(c.bufpos)
+    add(tok.literal, '/')
+  of '?':
+    tok.kind = tkOption
+    inc(c.bufpos)
+    add(tok.literal, '?')
+  of '!':
+    tok.kind = tkNot
+    inc(c.bufpos)
+    add(tok.literal, '!')
+  of '&':
+    tok.kind = tkAmp
+    inc(c.bufpos)
+    add(tok.literal, '!')
+  of '@':
+    tok.kind = tkAt
+    inc(c.bufpos)
+    add(tok.literal, '@')
+    if c.buf[c.bufpos] == '@':
+      tok.kind = tkCurlyAt
+      inc(c.bufpos)
+      add(tok.literal, '@')
+  of '^':
+    tok.kind = tkHat
+    inc(c.bufpos)
+    add(tok.literal, '^')
+  else:
+    add(tok.literal, c.buf[c.bufpos])
+    inc(c.bufpos)
+
+proc arrowIsNextTok(c: PegLexer): bool =
+  # the only look ahead we need
+  var pos = c.bufpos
+  while c.buf[pos] in {'\t', ' '}: inc(pos)
+  result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
+
+# ----------------------------- parser ----------------------------------------
+
+type
+  EInvalidPeg* = object of ValueError ## raised if an invalid
+                                         ## PEG has been detected
+  PegParser = object of PegLexer ## the PEG parser object
+    tok: TToken
+    nonterms: seq[NonTerminal]
+    modifier: TModifier
+    captures: int
+    identIsVerbatim: bool
+    skip: Peg
+
+proc pegError(p: PegParser, msg: string, line = -1, col = -1) =
+  var e: ref EInvalidPeg
+  new(e)
+  e.msg = errorStr(p, msg, line, col)
+  raise e
+
+proc getTok(p: var PegParser) =
+  getTok(p, p.tok)
+  if p.tok.kind == tkInvalid: pegError(p, "invalid token")
+
+proc eat(p: var PegParser, kind: TTokKind) =
+  if p.tok.kind == kind: getTok(p)
+  else: pegError(p, tokKindToStr[kind] & " expected")
+
+proc parseExpr(p: var PegParser): Peg {.gcsafe.}
+
+proc getNonTerminal(p: var PegParser, name: string): NonTerminal =
+  for i in 0..high(p.nonterms):
+    result = p.nonterms[i]
+    if cmpIgnoreStyle(result.name, name) == 0: return
+  # forward reference:
+  result = newNonTerminal(name, getLine(p), getColumn(p))
+  add(p.nonterms, result)
+
+proc modifiedTerm(s: string, m: TModifier): Peg =
+  case m
+  of modNone, modVerbatim: result = term(s)
+  of modIgnoreCase: result = termIgnoreCase(s)
+  of modIgnoreStyle: result = termIgnoreStyle(s)
+
+proc modifiedBackref(s: int, m: TModifier): Peg =
+  case m
+  of modNone, modVerbatim: result = backref(s)
+  of modIgnoreCase: result = backrefIgnoreCase(s)
+  of modIgnoreStyle: result = backrefIgnoreStyle(s)
+
+proc builtin(p: var PegParser): Peg =
+  # do not use "y", "skip" or "i" as these would be ambiguous
+  case p.tok.literal
+  of "n": result = newLine()
+  of "d": result = charSet({'0'..'9'})
+  of "D": result = charSet({'\1'..'\xff'} - {'0'..'9'})
+  of "s": result = charSet({' ', '\9'..'\13'})
+  of "S": result = charSet({'\1'..'\xff'} - {' ', '\9'..'\13'})
+  of "w": result = charSet({'a'..'z', 'A'..'Z', '_', '0'..'9'})
+  of "W": result = charSet({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
+  of "a": result = charSet({'a'..'z', 'A'..'Z'})
+  of "A": result = charSet({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
+  of "ident": result = pegs.ident
+  of "letter": result = unicodeLetter()
+  of "upper": result = unicodeUpper()
+  of "lower": result = unicodeLower()
+  of "title": result = unicodeTitle()
+  of "white": result = unicodeWhitespace()
+  else: pegError(p, "unknown built-in: " & p.tok.literal)
+
+proc token(terminal: Peg, p: PegParser): Peg =
+  if p.skip.kind == pkEmpty: result = terminal
+  else: result = sequence(p.skip, terminal)
+
+proc primary(p: var PegParser): Peg =
+  case p.tok.kind
+  of tkAmp:
+    getTok(p)
+    return &primary(p)
+  of tkNot:
+    getTok(p)
+    return !primary(p)
+  of tkAt:
+    getTok(p)
+    return !*primary(p)
+  of tkCurlyAt:
+    getTok(p)
+    return !*\primary(p).token(p)
+  else: discard
+  case p.tok.kind
+  of tkIdentifier:
+    if p.identIsVerbatim:
+      var m = p.tok.modifier
+      if m == modNone: m = p.modifier
+      result = modifiedTerm(p.tok.literal, m).token(p)
+      getTok(p)
+    elif not arrowIsNextTok(p):
+      var nt = getNonTerminal(p, p.tok.literal)
+      incl(nt.flags, ntUsed)
+      result = nonterminal(nt).token(p)
+      getTok(p)
+    else:
+      pegError(p, "expression expected, but found: " & p.tok.literal)
+  of tkStringLit:
+    var m = p.tok.modifier
+    if m == modNone: m = p.modifier
+    result = modifiedTerm(p.tok.literal, m).token(p)
+    getTok(p)
+  of tkCharSet:
+    if '\0' in p.tok.charset:
+      pegError(p, "binary zero ('\\0') not allowed in character class")
+    result = charSet(p.tok.charset).token(p)
+    getTok(p)
+  of tkParLe:
+    getTok(p)
+    result = parseExpr(p)
+    eat(p, tkParRi)
+  of tkCurlyLe:
+    getTok(p)
+    result = capture(parseExpr(p)).token(p)
+    eat(p, tkCurlyRi)
+    inc(p.captures)
+  of tkAny:
+    result = any().token(p)
+    getTok(p)
+  of tkAnyRune:
+    result = anyRune().token(p)
+    getTok(p)
+  of tkBuiltin:
+    result = builtin(p).token(p)
+    getTok(p)
+  of tkEscaped:
+    result = term(p.tok.literal[0]).token(p)
+    getTok(p)
+  of tkDollar:
+    result = endAnchor()
+    getTok(p)
+  of tkHat:
+    result = startAnchor()
+    getTok(p)
+  of tkBackref:
+    var m = p.tok.modifier
+    if m == modNone: m = p.modifier
+    result = modifiedBackref(p.tok.index, m).token(p)
+    if p.tok.index < 0 or p.tok.index > p.captures:
+      pegError(p, "invalid back reference index: " & $p.tok.index)
+    getTok(p)
+  else:
+    pegError(p, "expression expected, but found: " & p.tok.literal)
+    getTok(p) # we must consume a token here to prevent endless loops!
+  while true:
+    case p.tok.kind
+    of tkOption:
+      result = ?result
+      getTok(p)
+    of tkStar:
+      result = *result
+      getTok(p)
+    of tkPlus:
+      result = +result
+      getTok(p)
+    else: break
+
+proc seqExpr(p: var PegParser): Peg =
+  result = primary(p)
+  while true:
+    case p.tok.kind
+    of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe,
+       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref,
+       tkHat, tkCurlyAt:
+      result = sequence(result, primary(p))
+    of tkIdentifier:
+      if not arrowIsNextTok(p):
+        result = sequence(result, primary(p))
+      else: break
+    else: break
+
+proc parseExpr(p: var PegParser): Peg =
+  result = seqExpr(p)
+  while p.tok.kind == tkBar:
+    getTok(p)
+    result = result / seqExpr(p)
+
+proc parseRule(p: var PegParser): NonTerminal =
+  if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
+    result = getNonTerminal(p, p.tok.literal)
+    if ntDeclared in result.flags:
+      pegError(p, "attempt to redefine: " & result.name)
+    result.line = getLine(p)
+    result.col = getColumn(p)
+    getTok(p)
+    eat(p, tkArrow)
+    result.rule = parseExpr(p)
+    incl(result.flags, ntDeclared) # NOW inlining may be attempted
+  else:
+    pegError(p, "rule expected, but found: " & p.tok.literal)
+
+proc rawParse(p: var PegParser): Peg =
+  ## parses a rule or a PEG expression
+  while p.tok.kind == tkBuiltin:
+    case p.tok.literal
+    of "i":
+      p.modifier = modIgnoreCase
+      getTok(p)
+    of "y":
+      p.modifier = modIgnoreStyle
+      getTok(p)
+    of "skip":
+      getTok(p)
+      p.skip = ?primary(p)
+    else: break
+  if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
+    result = parseRule(p).rule
+    while p.tok.kind != tkEof:
+      discard parseRule(p)
+  else:
+    p.identIsVerbatim = true
+    result = parseExpr(p)
+  if p.tok.kind != tkEof:
+    pegError(p, "EOF expected, but found: " & p.tok.literal)
+  for i in 0..high(p.nonterms):
+    var nt = p.nonterms[i]
+    if ntDeclared notin nt.flags:
+      pegError(p, "undeclared identifier: " & nt.name, nt.line, nt.col)
+    elif ntUsed notin nt.flags and i > 0:
+      pegError(p, "unused rule: " & nt.name, nt.line, nt.col)
+
+proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg =
+  ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are
+  ## used for error messages, but they only provide start offsets. `parsePeg`
+  ## keeps track of line and column numbers within `pattern`.
+  var p: PegParser
+  init(PegLexer(p), pattern, filename, line, col)
+  p.tok.kind = tkInvalid
+  p.tok.modifier = modNone
+  p.tok.literal = ""
+  p.tok.charset = {}
+  p.nonterms = @[]
+  p.identIsVerbatim = false
+  getTok(p)
+  result = rawParse(p)
+
+proc peg*(pattern: string): Peg =
+  ## constructs a Peg object from the `pattern`. The short name has been
+  ## chosen to encourage its use as a raw string modifier::
+  ##
+  ##   peg"{\ident} \s* '=' \s* {.*}"
+  result = parsePeg(pattern, "pattern")
+
+proc escapePeg*(s: string): string =
+  ## escapes `s` so that it is matched verbatim when used as a peg.
+  result = ""
+  var inQuote = false
+  for c in items(s):
+    case c
+    of '\0'..'\31', '\'', '"', '\\':
+      if inQuote:
+        result.add('\'')
+        inQuote = false
+      result.add("\\x")
+      result.add(toHex(ord(c), 2))
+    else:
+      if not inQuote:
+        result.add('\'')
+        inQuote = true
+      result.add(c)
+  if inQuote: result.add('\'')
+
+when isMainModule:
+  assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
+  assert match("(a b c)", peg"'(' @ ')'")
+  assert match("W_HI_Le", peg"\y 'while'")
+  assert(not match("W_HI_L", peg"\y 'while'"))
+  assert(not match("W_HI_Le", peg"\y v'while'"))
+  assert match("W_HI_Le", peg"y'while'")
+
+  assert($ +digits == $peg"\d+")
+  assert "0158787".match(peg"\d+")
+  assert "ABC 0232".match(peg"\w+\s+\d+")
+  assert "ABC".match(peg"\d+ / \w+")
+
+  var accum: seq[string] = @[]
+  for word in split("00232this02939is39an22example111", peg"\d+"):
+    accum.add(word)
+  assert(accum == @["this", "is", "an", "example"])
+
+  assert matchLen("key", ident) == 3
+
+  var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
+  assert matchLen("key1=  cal9", pattern) == 11
+
+  var ws = newNonTerminal("ws", 1, 1)
+  ws.rule = *whitespace
+
+  var expr = newNonTerminal("expr", 1, 1)
+  expr.rule = sequence(capture(ident), *sequence(
+                nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
+
+  var c: Captures
+  var s = "a+b +  c +d+e+f"
+  assert rawMatch(s, expr.rule, 0, c) == len(s)
+  var a = ""
+  for i in 0..c.ml-1:
+    a.add(substr(s, c.matches[i][0], c.matches[i][1]))
+  assert a == "abcdef"
+  #echo expr.rule
+
+  #const filename = "lib/devel/peg/grammar.txt"
+  #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
+  #echo "a <- [abc]*?".match(grammar)
+  assert find("_____abc_______", term("abc"), 2) == 5
+  assert match("_______ana", peg"A <- 'ana' / . A")
+  assert match("abcs%%%", peg"A <- ..A / .A / '%'")
+
+  var matches: array[0..MaxSubpatterns-1, string]
+  if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
+    assert matches[0] == "abc"
+  else:
+    assert false
+
+  var g2 = peg"""S <- A B / C D
+                 A <- 'a'+
+                 B <- 'b'+
+                 C <- 'c'+
+                 D <- 'd'+
+              """
+  assert($g2 == "((A B) / (C D))")
+  assert match("cccccdddddd", g2)
+  assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+         "var1<-keykey; var2<-key2key2")
+  assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+         "$1<-$2$2; $1<-$2$2")
+  assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
+
+  if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
+    assert matches[0] == "a"
+  else:
+    assert false
+
+  if match("abcdefg", peg"c {d} ef {g}", matches, 2):
+    assert matches[0] == "d"
+    assert matches[1] == "g"
+  else:
+    assert false
+
+  accum = @[]
+  for x in findAll("abcdef", peg".", 3):
+    accum.add(x)
+  assert(accum == @["d", "e", "f"])
+
+  for x in findAll("abcdef", peg"^{.}", 3):
+    assert x == "d"
+
+  if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
+    assert matches[0] == "f"
+    assert matches[1] == "a, b"
+  else:
+    assert false
+
+  assert match("eine übersicht und außerdem", peg"(\letter \white*)+")
+  # ß is not a lower cased letter?!
+  assert match("eine übersicht und auerdem", peg"(\lower \white*)+")
+  assert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
+  assert(not match("456678", peg"(\letter)+"))
+
+  assert("var1 = key; var2 = key2".replacef(
+    peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
+         "var1<-keykey;var2<-key2key2")
+
+  assert match("prefix/start", peg"^start$", 7)
+
+  if "foo" =~ peg"{'a'}?.*":
+    assert matches[0] == nil
+  else: assert false
+
+  if "foo" =~ peg"{''}.*":
+    assert matches[0] == ""
+  else: assert false
+
+  if "foo" =~ peg"{'foo'}":
+    assert matches[0] == "foo"
+  else: assert false
+
+  let empty_test = peg"^\d*"
+  let str = "XYZ"
+
+  assert(str.find(empty_test) == 0)
+  assert(str.match(empty_test))
diff --git a/lib/pure/poly.nim b/lib/pure/poly.nim
new file mode 100644
index 000000000..58dcdc1ad
--- /dev/null
+++ b/lib/pure/poly.nim
@@ -0,0 +1,368 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Robert Persson
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import math
+import strutils
+import numeric
+
+type 
+  Poly* = object
+      cofs:seq[float]
+
+{.deprecated: [TPoly: Poly].}
+
+proc degree*(p:Poly):int=
+  ## Returns the degree of the polynomial,
+  ## that is the number of coefficients-1
+  return p.cofs.len-1
+
+
+proc eval*(p:Poly,x:float):float=
+  ## Evaluates a polynomial function value for `x`
+  ## quickly using Horners method
+  var n=p.degree
+  result=p.cofs[n]
+  dec n
+  while n>=0:
+    result = result*x+p.cofs[n]
+    dec n
+
+proc `[]` *(p:Poly;idx:int):float=
+  ## Gets a coefficient of the polynomial.
+  ## p[2] will returns the quadric term, p[3] the cubic etc.
+  ## Out of bounds index will return 0.0.
+  if idx<0 or idx>p.degree:
+      return 0.0
+  return p.cofs[idx]
+    
+proc `[]=` *(p:var Poly;idx:int,v:float)=
+  ## Sets an coefficient of the polynomial by index.
+  ## p[2] set the quadric term, p[3] the cubic etc.
+  ## If index is out of range for the coefficients,
+  ## the polynomial grows to the smallest needed degree.
+  assert(idx>=0)
+
+  if idx>p.degree:  #polynomial must grow
+    var oldlen=p.cofs.len
+    p.cofs.setLen(idx+1)
+    for q in oldlen.. <high(p.cofs):
+      p.cofs[q]=0.0 #new-grown coefficients set to zero
+
+  p.cofs[idx]=v
+    
+      
+iterator items*(p:Poly):float=
+  ## Iterates through the coefficients of the polynomial.
+  var i=p.degree
+  while i>=0:
+    yield p[i]
+    dec i    
+    
+proc clean*(p:var Poly;zerotol=0.0)=
+  ## Removes leading zero coefficients of the polynomial.
+  ## An optional tolerance can be given for what's considered zero.
+  var n=p.degree
+  var relen=false
+
+  while n>0 and abs(p[n])<=zerotol:    # >0 => keep at least one coefficient
+    dec n
+    relen=true
+
+  if relen: p.cofs.setLen(n+1)
+
+
+proc `$` *(p:Poly):string = 
+  ## Gets a somewhat reasonable string representation of the polynomial
+  ## The format should be compatible with most online function plotters,
+  ## for example directly in google search
+  result=""
+  var first=true #might skip + sign if first coefficient
+  
+  for idx in countdown(p.degree,0):
+    let a=p[idx]
+    
+    if a==0.0:
+      continue
+    
+    if a>= 0.0 and not first:
+      result.add('+')
+    first=false
+
+    if a!=1.0 or idx==0:
+      result.add(formatFloat(a,ffDefault,0))
+    if idx>=2:
+      result.add("x^" & $idx)
+    elif idx==1:
+      result.add("x")
+
+  if result=="":
+      result="0"
+          
+
+proc derivative*(p: Poly): Poly=
+  ## Returns a new polynomial, which is the derivative of `p`
+  newSeq[float](result.cofs,p.degree)
+  for idx in 0..high(result.cofs):
+    result.cofs[idx]=p.cofs[idx+1]*float(idx+1)
+    
+proc diff*(p:Poly,x:float):float=
+  ## Evaluates the differentiation of a polynomial with
+  ## respect to `x` quickly using a modifed Horners method
+  var n=p.degree
+  result=p[n]*float(n)
+  dec n
+  while n>=1:
+    result = result*x+p[n]*float(n)
+    dec n
+
+proc integral*(p:Poly):Poly=
+  ## Returns a new polynomial which is the indefinite
+  ## integral of `p`. The constant term is set to 0.0
+  newSeq(result.cofs,p.cofs.len+1)
+  result.cofs[0]=0.0  #constant arbitrary term, use 0.0
+  for i in 1..high(result.cofs):
+    result.cofs[i]=p.cofs[i-1]/float(i)
+        
+
+proc integrate*(p:Poly;xmin,xmax:float):float=
+  ## Computes the definite integral of `p` between `xmin` and `xmax`
+  ## quickly using a modified version of Horners method
+  var
+    n=p.degree
+    s1=p[n]/float(n+1)
+    s2=s1
+    fac:float
+
+  dec n
+  while n>=0:
+    fac=p[n]/float(n+1)
+    s1 = s1*xmin+fac
+    s2 = s2*xmax+fac
+    dec n
+ 
+  result=s2*xmax-s1*xmin
+  
+proc initPoly*(cofs:varargs[float]):Poly=
+  ## Initializes a polynomial with given coefficients.
+  ## The most significant coefficient is first, so to create x^2-2x+3:
+  ## intiPoly(1.0,-2.0,3.0)
+  if len(cofs)<=0:
+      result.cofs= @[0.0]  #need at least one coefficient
+  else:
+    # reverse order of coefficients so indexing matches degree of
+    # coefficient...
+    result.cofs= @[]
+    for idx in countdown(cofs.len-1,0):  
+      result.cofs.add(cofs[idx])
+
+  result.clean #remove leading zero terms
+
+
+proc divMod*(p,d:Poly;q,r:var Poly)=
+  ## Divides `p` with `d`, and stores the quotinent in `q` and
+  ## the remainder in `d`
+  var 
+    pdeg=p.degree
+    ddeg=d.degree
+    power=p.degree-d.degree
+    ratio:float
+  
+  r.cofs = p.cofs #initial remainder=numerator
+  if power<0: #denominator is larger than numerator
+    q.cofs= @ [0.0] #quotinent is 0.0
+    return # keep remainder as numerator
+      
+  q.cofs=newSeq[float](power+1)
+  
+  for i in countdown(pdeg,ddeg):
+    ratio=r.cofs[i]/d.cofs[ddeg]
+    
+    q.cofs[i-ddeg]=ratio
+    r.cofs[i]=0.0
+    
+    for j in countup(0,<ddeg):
+        var idx=i-ddeg+j
+        r.cofs[idx] = r.cofs[idx] - d.cofs[j]*ratio
+     
+  r.clean # drop zero coefficients in remainder
+
+proc `+` *(p1:Poly,p2:Poly):Poly=
+  ## Adds two polynomials
+  var n=max(p1.cofs.len,p2.cofs.len)
+  newSeq(result.cofs,n)
+  
+  for idx in countup(0,n-1):
+      result[idx]=p1[idx]+p2[idx]
+      
+  result.clean # drop zero coefficients in remainder
+    
+proc `*` *(p1:Poly,p2:Poly):Poly=
+  ## Multiplies the polynomial `p1` with `p2`
+  var 
+    d1=p1.degree
+    d2=p2.degree
+    n=d1+d2
+    idx:int
+      
+  newSeq(result.cofs,n)
+
+  for i1 in countup(0,d1):
+    for i2 in countup(0,d2):
+      idx=i1+i2
+      result[idx]=result[idx]+p1[i1]*p2[i2]
+
+  result.clean
+
+proc `*` *(p:Poly,f:float):Poly=
+  ## Multiplies the polynomial `p` with a real number
+  newSeq(result.cofs,p.cofs.len)
+  for i in 0..high(p.cofs):
+    result[i]=p.cofs[i]*f
+  result.clean
+  
+proc `*` *(f:float,p:Poly):Poly=
+  ## Multiplies a real number with a polynomial
+  return p*f
+    
+proc `-`*(p:Poly):Poly=
+  ## Negates a polynomial
+  result=p
+  for i in countup(0,<result.cofs.len):
+    result.cofs[i]= -result.cofs[i]
+    
+proc `-` *(p1:Poly,p2:Poly):Poly=
+  ## Subtract `p1` with `p2`
+  var n=max(p1.cofs.len,p2.cofs.len)
+  newSeq(result.cofs,n)
+  
+  for idx in countup(0,n-1):
+      result[idx]=p1[idx]-p2[idx]
+      
+  result.clean # drop zero coefficients in remainder
+    
+proc `/`*(p:Poly,f:float):Poly=
+  ## Divides polynomial `p` with a real number `f`
+  newSeq(result.cofs,p.cofs.len)
+  for i in 0..high(p.cofs):
+    result[i]=p.cofs[i]/f
+  result.clean
+  
+proc `/` *(p,q:Poly):Poly=
+  ## Divides polynomial `p` with polynomial `q`
+  var dummy:Poly
+  p.divMod(q,result,dummy)  
+
+proc `mod` *(p,q:Poly):Poly=
+  ## Computes the polynomial modulo operation,
+  ## that is the remainder of `p`/`q`
+  var dummy:Poly
+  p.divMod(q,dummy,result)
+
+
+proc normalize*(p:var Poly)=
+  ## Multiplies the polynomial inplace by a term so that
+  ## the leading term is 1.0.
+  ## This might lead to an unstable polynomial
+  ## if the leading term is zero.
+  p=p/p[p.degree]
+
+
+proc solveQuadric*(a,b,c:float;zerotol=0.0):seq[float]=
+  ## Solves the quadric equation `ax^2+bx+c`, with a possible
+  ## tolerance `zerotol` to find roots of curves just 'touching'
+  ## the x axis. Returns sequence with 0,1 or 2 solutions.
+  
+  var p,q,d:float
+  
+  p=b/(2.0*a)
+  
+  if p==Inf or p==NegInf: #linear equation..
+    var linrt= -c/b
+    if linrt==Inf or linrt==NegInf: #constant only
+      return @[]
+    return @[linrt]
+  
+  q=c/a
+  d=p*p-q
+  
+  if d<0.0:
+    #check for inside zerotol range for neg. roots
+    var err=a*p*p-b*p+c #evaluate error at parabola center axis
+    if(err<=zerotol): return @[-p]
+    return @[]
+  else:
+    var sr=sqrt(d)
+    result= @[-sr-p,sr-p]
+
+proc getRangeForRoots(p:Poly):tuple[xmin,xmax:float]=
+  ## helper function for `roots` function
+  ## quickly computes a range, guaranteed to contain
+  ## all the real roots of the polynomial
+  # see http://www.mathsisfun.com/algebra/polynomials-bounds-zeros.html
+
+  var deg=p.degree
+  var d=p[deg]
+  var bound1,bound2:float
+  
+  for i in countup(0,deg):
+    var c=abs(p.cofs[i]/d)
+    bound1=max(bound1,c+1.0)
+    bound2=bound2+c
+    
+  bound2=max(1.0,bound2)
+  result.xmax=min(bound1,bound2)
+  result.xmin= -result.xmax
+
+
+proc addRoot(p:Poly,res:var seq[float],xp0,xp1,tol,zerotol,mergetol:float,maxiter:int)=
+  ## helper function for `roots` function
+  ## try to do a numeric search for a single root in range xp0-xp1,
+  ## adding it to `res` (allocating `res` if nil)
+  var br=brent(xp0,xp1, proc(x:float):float=p.eval(x),tol)
+  if br.success:
+    if res.len==0 or br.rootx>=res[high(res)]+mergetol: #dont add equal roots.
+      res.add(br.rootx) 
+  else:
+    #this might be a 'touching' case, check function value against
+    #zero tolerance
+    if abs(br.rooty)<=zerotol:
+      if res.len==0 or br.rootx>=res[high(res)]+mergetol: #dont add equal roots.
+        res.add(br.rootx) 
+
+
+proc roots*(p:Poly,tol=1.0e-9,zerotol=1.0e-6,mergetol=1.0e-12,maxiter=1000):seq[float]=
+  ## Computes the real roots of the polynomial `p`
+  ## `tol` is the tolerance used to break searching for each root when reached.
+  ## `zerotol` is the tolerance, which is 'close enough' to zero to be considered a root
+  ## and is used to find roots for curves that only 'touch' the x-axis.
+  ## `mergetol` is the tolerance, of which two x-values are considered beeing the same root.
+  ## `maxiter` can be used to limit the number of iterations for each root.
+  ## Returns a (possibly empty) sorted sequence with the solutions.
+  var deg=p.degree
+  if deg<=0: #constant only => no roots
+    return @[]
+  elif p.degree==1: #linear
+    var linrt= -p.cofs[0]/p.cofs[1]
+    if linrt==Inf or linrt==NegInf:
+      return @[] #constant only => no roots
+    return @[linrt]
+  elif p.degree==2:
+    return solveQuadric(p.cofs[2],p.cofs[1],p.cofs[0],zerotol)
+  else:
+    # degree >=3 , find min/max points of polynomial with recursive
+    # derivative and do a numerical search for root between each min/max
+    var range=p.getRangeForRoots()
+    var minmax=p.derivative.roots(tol,zerotol,mergetol)
+    result= @[]
+    if minmax!=nil: #ie. we have minimas/maximas in this function
+      for x in minmax.items:
+        addRoot(p,result,range.xmin,x,tol,zerotol,mergetol,maxiter)
+        range.xmin=x
+    addRoot(p,result,range.xmin,range.xmax,tol,zerotol,mergetol,maxiter)
+
diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim
new file mode 100644
index 000000000..3b68a2381
--- /dev/null
+++ b/lib/pure/rationals.nim
@@ -0,0 +1,289 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dennis Felsing
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## This module implements rational numbers, consisting of a numerator `num` and
+## a denominator `den`, both of type int. The denominator can not be 0.
+
+import math
+import hashes
+
+type Rational*[T] = object
+  ## a rational number, consisting of a numerator and denominator
+  num*, den*: T
+
+proc initRational*[T](num, den: T): Rational[T] =
+  ## Create a new rational number.
+  result.num = num
+  result.den = den
+
+proc `//`*[T](num, den: T): Rational[T] = initRational[T](num, den)
+  ## A friendlier version of `initRational`. Example usage:
+  ##
+  ## .. code-block:: nim
+  ##   var x = 1//3 + 1//5
+
+proc `$`*[T](x: Rational[T]): string =
+  ## Turn a rational number into a string.
+  result = $x.num & "/" & $x.den
+
+proc toRational*[T](x: T): Rational[T] =
+  ## Convert some integer `x` to a rational number.
+  result.num = x
+  result.den = 1
+
+proc toFloat*[T](x: Rational[T]): float =
+  ## Convert a rational number `x` to a float.
+  x.num / x.den
+
+proc toInt*[T](x: Rational[T]): int =
+  ## Convert a rational number `x` to an int. Conversion rounds towards 0 if
+  ## `x` does not contain an integer value.
+  x.num div x.den
+
+proc reduce*[T](x: var Rational[T]) =
+  ## Reduce rational `x`.
+  let common = gcd(x.num, x.den)
+  if x.den > 0:
+    x.num = x.num div common
+    x.den = x.den div common
+  elif x.den < 0:
+    x.num = -x.num div common
+    x.den = -x.den div common
+  else:
+    raise newException(DivByZeroError, "division by zero")
+
+proc `+` *[T](x, y: Rational[T]): Rational[T] =
+  ## Add two rational numbers.
+  let common = lcm(x.den, y.den)
+  result.num = common div x.den * x.num + common div y.den * y.num
+  result.den = common
+  reduce(result)
+
+proc `+` *[T](x: Rational[T], y: T): Rational[T] =
+  ## Add rational `x` to int `y`.
+  result.num = x.num + y * x.den
+  result.den = x.den
+
+proc `+` *[T](x: T, y: Rational[T]): Rational[T] =
+  ## Add int `x` to rational `y`.
+  result.num = x * y.den + y.num
+  result.den = y.den
+
+proc `+=` *[T](x: var Rational[T], y: Rational[T]) =
+  ## Add rational `y` to rational `x`.
+  let common = lcm(x.den, y.den)
+  x.num = common div x.den * x.num + common div y.den * y.num
+  x.den = common
+  reduce(x)
+
+proc `+=` *[T](x: var Rational[T], y: T) =
+  ## Add int `y` to rational `x`.
+  x.num += y * x.den
+
+proc `-` *[T](x: Rational[T]): Rational[T] =
+  ## Unary minus for rational numbers.
+  result.num = -x.num
+  result.den = x.den
+
+proc `-` *[T](x, y: Rational[T]): Rational[T] =
+  ## Subtract two rational numbers.
+  let common = lcm(x.den, y.den)
+  result.num = common div x.den * x.num - common div y.den * y.num
+  result.den = common
+  reduce(result)
+
+proc `-` *[T](x: Rational[T], y: T): Rational[T] =
+  ## Subtract int `y` from rational `x`.
+  result.num = x.num - y * x.den
+  result.den = x.den
+
+proc `-` *[T](x: T, y: Rational[T]): Rational[T] =
+  ## Subtract rational `y` from int `x`.
+  result.num = - x * y.den + y.num
+  result.den = y.den
+
+proc `-=` *[T](x: var Rational[T], y: Rational[T]) =
+  ## Subtract rational `y` from rational `x`.
+  let common = lcm(x.den, y.den)
+  x.num = common div x.den * x.num - common div y.den * y.num
+  x.den = common
+  reduce(x)
+
+proc `-=` *[T](x: var Rational[T], y: T) =
+  ## Subtract int `y` from rational `x`.
+  x.num -= y * x.den
+
+proc `*` *[T](x, y: Rational[T]): Rational[T] =
+  ## Multiply two rational numbers.
+  result.num = x.num * y.num
+  result.den = x.den * y.den
+  reduce(result)
+
+proc `*` *[T](x: Rational[T], y: T): Rational[T] =
+  ## Multiply rational `x` with int `y`.
+  result.num = x.num * y
+  result.den = x.den
+  reduce(result)
+
+proc `*` *[T](x: T, y: Rational[T]): Rational[T] =
+  ## Multiply int `x` with rational `y`.
+  result.num = x * y.num
+  result.den = y.den
+  reduce(result)
+
+proc `*=` *[T](x: var Rational[T], y: Rational[T]) =
+  ## Multiply rationals `y` to `x`.
+  x.num *= y.num
+  x.den *= y.den
+  reduce(x)
+
+proc `*=` *[T](x: var Rational[T], y: T) =
+  ## Multiply int `y` to rational `x`.
+  x.num *= y
+  reduce(x)
+
+proc reciprocal*[T](x: Rational[T]): Rational[T] =
+  ## Calculate the reciprocal of `x`. (1/x)
+  if x.num > 0:
+    result.num = x.den
+    result.den = x.num
+  elif x.num < 0:
+    result.num = -x.den
+    result.den = -x.num
+  else:
+    raise newException(DivByZeroError, "division by zero")
+
+proc `/`*[T](x, y: Rational[T]): Rational[T] =
+  ## Divide rationals `x` by `y`.
+  result.num = x.num * y.den
+  result.den = x.den * y.num
+  reduce(result)
+
+proc `/`*[T](x: Rational[T], y: T): Rational[T] =
+  ## Divide rational `x` by int `y`.
+  result.num = x.num
+  result.den = x.den * y
+  reduce(result)
+
+proc `/`*[T](x: T, y: Rational[T]): Rational[T] =
+  ## Divide int `x` by Rational `y`.
+  result.num = x * y.den
+  result.den = y.num
+  reduce(result)
+
+proc `/=`*[T](x: var Rational[T], y: Rational[T]) =
+  ## Divide rationals `x` by `y` in place.
+  x.num *= y.den
+  x.den *= y.num
+  reduce(x)
+
+proc `/=`*[T](x: var Rational[T], y: T) =
+  ## Divide rational `x` by int `y` in place.
+  x.den *= y
+  reduce(x)
+
+proc cmp*(x, y: Rational): int {.procvar.} =
+  ## Compares two rationals.
+  (x - y).num
+
+proc `<` *(x, y: Rational): bool =
+  (x - y).num < 0
+
+proc `<=` *(x, y: Rational): bool =
+  (x - y).num <= 0
+
+proc `==` *(x, y: Rational): bool =
+  (x - y).num == 0
+
+proc abs*[T](x: Rational[T]): Rational[T] =
+  result.num = abs x.num
+  result.den = abs x.den
+
+proc hash*[T](x: Rational[T]): THash =
+  ## Computes hash for rational `x`
+  # reduce first so that hash(x) == hash(y) for x == y
+  var copy = x
+  reduce(copy)
+
+  var h: THash = 0
+  h = h !& hash(copy.num)
+  h = h !& hash(copy.den)
+  result = !$h
+  
+when isMainModule:
+  var
+    z = Rational[int](num: 0, den: 1)
+    o = initRational(num=1, den=1)
+    a = initRational(1, 2)
+    b = -1 // -2
+    m1 = -1 // 1
+    tt = 10 // 2
+
+  assert( a     == a )
+  assert( (a-a) == z )
+  assert( (a+b) == o )
+  assert( (a/b) == o )
+  assert( (a*b) == 1 // 4 )
+  assert( (3/a) == 6 // 1 )
+  assert( (a/3) == 1 // 6 )
+  assert( a*b   == 1 // 4 )
+  assert( tt*z  == z )
+  assert( 10*a  == tt )
+  assert( a*10  == tt )
+  assert( tt/10 == a  )
+  assert( a-m1  == 3 // 2 )
+  assert( a+m1  == -1 // 2 )
+  assert( m1+tt == 16 // 4 )
+  assert( m1-tt == 6 // -1 )
+
+  assert( z < o )
+  assert( z <= o )
+  assert( z == z )
+  assert( cmp(z, o) < 0 )
+  assert( cmp(o, z) > 0 )
+
+  assert( o == o )
+  assert( o >= o )
+  assert( not(o > o) )
+  assert( cmp(o, o) == 0 )
+  assert( cmp(z, z) == 0 )
+  assert( hash(o) == hash(o) )
+
+  assert( a == b )
+  assert( a >= b )
+  assert( not(b > a) )
+  assert( cmp(a, b) == 0 )
+  assert( hash(a) == hash(b) )
+
+  var x = 1//3
+
+  x *= 5//1
+  assert( x == 5//3 )
+  x += 2 // 9
+  assert( x == 17//9 )
+  x -= 9//18
+  assert( x == 25//18 )
+  x /= 1//2
+  assert( x == 50//18 )
+
+  var y = 1//3
+
+  y *= 4
+  assert( y == 4//3 )
+  y += 5
+  assert( y == 19//3 )
+  y -= 2
+  assert( y == 13//3 )
+  y /= 9
+  assert( y == 13//27 )
+
+  assert toRational(5) == 5//1
+  assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
+  assert toInt(z) == 0
diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim
new file mode 100644
index 000000000..d08c5b769
--- /dev/null
+++ b/lib/pure/rawsockets.nim
@@ -0,0 +1,436 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a low-level cross-platform sockets interface. Look
+## at the ``net`` module for the higher-level version.
+
+# TODO: Clean up the exports a bit and everything else in general.
+
+import unsigned, os
+
+when hostOS == "solaris":
+  {.passl: "-lsocket -lnsl".}
+
+const useWinVersion = defined(Windows) or defined(nimdoc)
+
+when useWinVersion:
+  import winlean
+  export WSAEWOULDBLOCK, WSAECONNRESET, WSAECONNABORTED, WSAENETRESET,
+         WSAEDISCON, ERROR_NETNAME_DELETED
+else:
+  import posix
+  export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL,
+    EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET
+
+export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen,
+  inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto
+
+export
+  SO_ERROR,
+  SOL_SOCKET,
+  SOMAXCONN,
+  SO_ACCEPTCONN, SO_BROADCAST, SO_DEBUG, SO_DONTROUTE,
+  SO_KEEPALIVE, SO_OOBINLINE, SO_REUSEADDR,
+  MSG_PEEK
+
+when defined(macosx):
+    export SO_NOSIGPIPE
+
+type
+  Port* = distinct uint16  ## port type
+  
+  Domain* = enum    ## domain, which specifies the protocol family of the
+                    ## created socket. Other domains than those that are listed
+                    ## here are unsupported.
+    AF_UNIX,        ## for local socket (using a file). Unsupported on Windows.
+    AF_INET = 2,    ## for network protocol IPv4 or
+    AF_INET6 = 23   ## for network protocol IPv6.
+
+  SockType* = enum     ## second argument to `socket` proc
+    SOCK_STREAM = 1,   ## reliable stream-oriented service or Stream Sockets
+    SOCK_DGRAM = 2,    ## datagram service or Datagram Sockets
+    SOCK_RAW = 3,      ## raw protocols atop the network layer.
+    SOCK_SEQPACKET = 5 ## reliable sequenced packet service
+
+  Protocol* = enum      ## third argument to `socket` proc
+    IPPROTO_TCP = 6,    ## Transmission control protocol. 
+    IPPROTO_UDP = 17,   ## User datagram protocol.
+    IPPROTO_IP,         ## Internet protocol. Unsupported on Windows.
+    IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
+    IPPROTO_RAW,        ## Raw IP Packets Protocol. Unsupported on Windows.
+    IPPROTO_ICMP        ## Control message protocol. Unsupported on Windows.
+
+  Servent* = object ## information about a service
+    name*: string
+    aliases*: seq[string]
+    port*: Port
+    proto*: string
+
+  Hostent* = object ## information about a given host
+    name*: string
+    aliases*: seq[string]
+    addrtype*: Domain
+    length*: int
+    addrList*: seq[string]
+
+{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType,
+    TProtocol: Protocol, TServent: Servent, THostent: Hostent].}
+
+when useWinVersion:
+  let
+    osInvalidSocket* = winlean.INVALID_SOCKET
+
+  const
+    IOCPARM_MASK* = 127
+    IOC_IN* = int(-2147483648)
+    FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or 
+                             (102 shl 8) or 126
+
+  proc ioctlsocket*(s: SocketHandle, cmd: clong, 
+                   argptr: ptr clong): cint {.
+                   stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".}
+else:
+  let
+    osInvalidSocket* = posix.INVALID_SOCKET
+
+proc `==`*(a, b: Port): bool {.borrow.}
+  ## ``==`` for ports.
+
+proc `$`*(p: Port): string {.borrow.}
+  ## returns the port number as a string
+
+proc toInt*(domain: Domain): cint
+  ## Converts the TDomain enum to a platform-dependent ``cint``.
+
+proc toInt*(typ: SockType): cint
+  ## Converts the TType enum to a platform-dependent ``cint``.
+
+proc toInt*(p: Protocol): cint
+  ## Converts the TProtocol enum to a platform-dependent ``cint``.
+
+when not useWinVersion:
+  proc toInt(domain: Domain): cint =
+    case domain
+    of AF_UNIX:        result = posix.AF_UNIX
+    of AF_INET:        result = posix.AF_INET
+    of AF_INET6:       result = posix.AF_INET6
+    else: discard
+
+  proc toInt(typ: SockType): cint =
+    case typ
+    of SOCK_STREAM:    result = posix.SOCK_STREAM
+    of SOCK_DGRAM:     result = posix.SOCK_DGRAM
+    of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
+    of SOCK_RAW:       result = posix.SOCK_RAW
+    else: discard
+
+  proc toInt(p: Protocol): cint =
+    case p
+    of IPPROTO_TCP:    result = posix.IPPROTO_TCP
+    of IPPROTO_UDP:    result = posix.IPPROTO_UDP
+    of IPPROTO_IP:     result = posix.IPPROTO_IP
+    of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
+    of IPPROTO_RAW:    result = posix.IPPROTO_RAW
+    of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
+    else: discard
+
+else:
+  proc toInt(domain: Domain): cint = 
+    result = toU16(ord(domain))
+
+  proc toInt(typ: SockType): cint =
+    result = cint(ord(typ))
+  
+  proc toInt(p: Protocol): cint =
+    result = cint(ord(p))
+
+
+proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+             protocol: Protocol = IPPROTO_TCP): SocketHandle =
+  ## Creates a new socket; returns `InvalidSocket` if an error occurs.
+  socket(toInt(domain), toInt(typ), toInt(protocol))
+
+proc newRawSocket*(domain: cint, typ: cint, protocol: cint): SocketHandle =
+  ## Creates a new socket; returns `InvalidSocket` if an error occurs.
+  ##
+  ## Use this overload if one of the enums specified above does
+  ## not contain what you need.
+  socket(domain, typ, protocol)
+
+proc close*(socket: SocketHandle) =
+  ## closes a socket.
+  when useWinVersion:
+    discard winlean.closesocket(socket)
+  else:
+    discard posix.close(socket)
+  # TODO: These values should not be discarded. An EOS should be raised.
+  # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
+
+proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint =
+  result = bindSocket(socket, name, namelen)
+
+proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEffect].} =
+  ## Marks ``socket`` as accepting connections. 
+  ## ``Backlog`` specifies the maximum length of the 
+  ## queue of pending connections.
+  when useWinVersion:
+    result = winlean.listen(socket, cint(backlog))
+  else:
+    result = posix.listen(socket, cint(backlog))
+
+proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+                 prot: Protocol = IPPROTO_TCP): ptr AddrInfo =
+  ##
+  ##
+  ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``!
+  var hints: AddrInfo
+  result = nil
+  hints.ai_family = toInt(af)
+  hints.ai_socktype = toInt(typ)
+  hints.ai_protocol = toInt(prot)
+  var gaiResult = getaddrinfo(address, $port, addr(hints), result)
+  if gaiResult != 0'i32:
+    when useWinVersion:
+      raiseOSError(osLastError())
+    else:
+      raise newException(OSError, $gai_strerror(gaiResult))
+
+proc dealloc*(ai: ptr AddrInfo) =
+  freeaddrinfo(ai)
+
+proc ntohl*(x: int32): int32 = 
+  ## Converts 32-bit integers from network to host byte order.
+  ## On machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 24'i32) or
+                 (x shr 8'i32 and 0xff00'i32) or
+                 (x shl 8'i32 and 0xff0000'i32) or
+                 (x shl 24'i32)
+
+proc ntohs*(x: int16): int16 =
+  ## Converts 16-bit integers from network to host byte order. On machines
+  ## where the host byte order is the same as network byte order, this is
+  ## a no-op; otherwise, it performs a 2-byte swap operation.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 8'i16) or (x shl 8'i16)
+
+proc htonl*(x: int32): int32 =
+  ## Converts 32-bit integers from host to network byte order. On machines
+  ## where the host byte order is the same as network byte order, this is
+  ## a no-op; otherwise, it performs a 4-byte swap operation.
+  result = rawsockets.ntohl(x)
+
+proc htons*(x: int16): int16 =
+  ## Converts 16-bit positive integers from host to network byte order.
+  ## On machines where the host byte order is the same as network byte
+  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
+  result = rawsockets.ntohs(x)
+
+proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
+  ## Searches the database from the beginning and finds the first entry for 
+  ## which the service name specified by ``name`` matches the s_name member
+  ## and the protocol name specified by ``proto`` matches the s_proto member.
+  ##
+  ## On posix this will search through the ``/etc/services`` file.
+  when useWinVersion:
+    var s = winlean.getservbyname(name, proto)
+  else:
+    var s = posix.getservbyname(name, proto)
+  if s == nil: raise newException(OSError, "Service not found.")
+  result.name = $s.s_name
+  result.aliases = cstringArrayToSeq(s.s_aliases)
+  result.port = Port(s.s_port)
+  result.proto = $s.s_proto
+  
+proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = 
+  ## Searches the database from the beginning and finds the first entry for 
+  ## which the port specified by ``port`` matches the s_port member and the 
+  ## protocol name specified by ``proto`` matches the s_proto member.
+  ##
+  ## On posix this will search through the ``/etc/services`` file.
+  when useWinVersion:
+    var s = winlean.getservbyport(ze(int16(port)).cint, proto)
+  else:
+    var s = posix.getservbyport(ze(int16(port)).cint, proto)
+  if s == nil: raise newException(OSError, "Service not found.")
+  result.name = $s.s_name
+  result.aliases = cstringArrayToSeq(s.s_aliases)
+  result.port = Port(s.s_port)
+  result.proto = $s.s_proto
+
+proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
+  ## This function will lookup the hostname of an IP Address.
+  var myaddr: InAddr
+  myaddr.s_addr = inet_addr(ip)
+  
+  when useWinVersion:
+    var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
+                                  cint(rawsockets.AF_INET))
+    if s == nil: raiseOSError(osLastError())
+  else:
+    var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, 
+                                cint(posix.AF_INET))
+    if s == nil:
+      raise newException(OSError, $hstrerror(h_errno))
+  
+  result.name = $s.h_name
+  result.aliases = cstringArrayToSeq(s.h_aliases)
+  when useWinVersion:
+    result.addrtype = Domain(s.h_addrtype)
+  else:
+    if s.h_addrtype == posix.AF_INET:
+      result.addrtype = AF_INET
+    elif s.h_addrtype == posix.AF_INET6:
+      result.addrtype = AF_INET6
+    else:
+      raise newException(OSError, "unknown h_addrtype")
+  result.addrList = cstringArrayToSeq(s.h_addr_list)
+  result.length = int(s.h_length)
+
+proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = 
+  ## This function will lookup the IP address of a hostname.
+  when useWinVersion:
+    var s = winlean.gethostbyname(name)
+  else:
+    var s = posix.gethostbyname(name)
+  if s == nil: raiseOSError(osLastError())
+  result.name = $s.h_name
+  result.aliases = cstringArrayToSeq(s.h_aliases)
+  when useWinVersion:
+    result.addrtype = Domain(s.h_addrtype)
+  else:
+    if s.h_addrtype == posix.AF_INET:
+      result.addrtype = AF_INET
+    elif s.h_addrtype == posix.AF_INET6:
+      result.addrtype = AF_INET6
+    else:
+      raise newException(OSError, "unknown h_addrtype")
+  result.addrList = cstringArrayToSeq(s.h_addr_list)
+  result.length = int(s.h_length)
+
+proc getSockName*(socket: SocketHandle): Port = 
+  ## returns the socket's associated port number.
+  var name: Sockaddr_in
+  when useWinVersion:
+    name.sin_family = int16(ord(AF_INET))
+  else:
+    name.sin_family = posix.AF_INET
+  #name.sin_port = htons(cint16(port))
+  #name.sin_addr.s_addr = htonl(INADDR_ANY)
+  var namelen = sizeof(name).SockLen
+  if getsockname(socket, cast[ptr SockAddr](addr(name)),
+                 addr(namelen)) == -1'i32:
+    raiseOSError(osLastError())
+  result = Port(rawsockets.ntohs(name.sin_port))
+
+proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {.
+  tags: [ReadIOEffect].} = 
+  ## getsockopt for integer options.
+  var res: cint
+  var size = sizeof(res).SockLen
+  if getsockopt(socket, cint(level), cint(optname), 
+                addr(res), addr(size)) < 0'i32:
+    raiseOSError(osLastError())
+  result = int(res)
+
+proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {.
+  tags: [WriteIOEffect].} =
+  ## setsockopt for integer options.
+  var value = cint(optval)
+  if setsockopt(socket, cint(level), cint(optname), addr(value),  
+                sizeof(value).SockLen) < 0'i32:
+    raiseOSError(osLastError())
+
+proc setBlocking*(s: SocketHandle, blocking: bool) =
+  ## Sets blocking mode on socket.
+  ##
+  ## Raises EOS on error.
+  when useWinVersion:
+    var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
+    if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
+      raiseOSError(osLastError())
+  else: # BSD sockets
+    var x: int = fcntl(s, F_GETFL, 0)
+    if x == -1:
+      raiseOSError(osLastError())
+    else:
+      var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
+      if fcntl(s, F_SETFL, mode) == -1:
+        raiseOSError(osLastError())
+
+proc timeValFromMilliseconds(timeout = 500): Timeval =
+  if timeout != -1:
+    var seconds = timeout div 1000
+    result.tv_sec = seconds.int32
+    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) = 
+  FD_ZERO(fd)
+  for i in items(s): 
+    m = max(m, int(i))
+    FD_SET(i, fd)
+   
+proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = 
+  var i = 0
+  var L = s.len
+  while i < L:
+    if FD_ISSET(s[i], fd) == 0'i32:
+      s[i] = s[L-1]
+      dec(L)
+    else:
+      inc(i)
+  setLen(s, L)
+
+proc select*(readfds: var seq[SocketHandle], timeout = 500): int =
+  ## Traditional select function. This function will return the number of
+  ## sockets that are ready to be read from, written to, or which have errors.
+  ## If there are none; 0 is returned. 
+  ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
+  ## 
+  ## A socket is removed from the specific ``seq`` when it has data waiting to
+  ## be read/written to or has errors (``exceptfds``).
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+  
+  var rd: TFdSet
+  var m = 0
+  createFdSet((rd), readfds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), addr(rd), nil, nil, nil))
+  
+  pruneSocketSet(readfds, (rd))
+
+proc selectWrite*(writefds: var seq[SocketHandle],
+                  timeout = 500): int {.tags: [ReadIOEffect].} =
+  ## When a socket in ``writefds`` is ready to be written to then a non-zero
+  ## value will be returned specifying the count of the sockets which can be
+  ## written to. The sockets which can be written to will also be removed
+  ## from ``writefds``.
+  ##
+  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
+  ## an unlimited time.
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+  
+  var wr: TFdSet
+  var m = 0
+  createFdSet((wr), writefds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), nil, addr(wr), nil, nil))
+  
+  pruneSocketSet(writefds, (wr))
+
+when defined(Windows):
+  var wsa: WSAData
+  if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim
new file mode 100644
index 000000000..aa2e0f9bd
--- /dev/null
+++ b/lib/pure/redis.nim
@@ -0,0 +1,1096 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a redis client. It allows you to connect to a
+## redis-server instance, send commands and receive replies.
+##
+## **Beware**: Most (if not all) functions that return a ``TRedisString`` may
+## return ``redisNil``, and functions which return a ``TRedisList`` 
+## may return ``nil``.
+
+import sockets, os, strutils, parseutils
+
+const
+  redisNil* = "\0\0"
+
+type 
+  Pipeline = ref object
+    enabled: bool
+    buffer: string
+    expected: int ## number of replies expected if pipelined
+
+type
+  SendMode = enum
+    normal, pipelined, multiple
+
+type
+  Redis* = object
+    socket: Socket
+    connected: bool
+    pipeline: Pipeline
+  
+  RedisStatus* = string
+  RedisInteger* = BiggestInt
+  RedisString* = string ## Bulk reply
+  RedisList* = seq[RedisString] ## Multi-bulk reply
+
+  ReplyError* = object of IOError ## Invalid reply from redis
+  RedisError* = object of IOError        ## Error in redis
+
+{.deprecated: [TSendMode: SendMode, TRedis: Redis, TRedisStatus: RedisStatus,
+     TRedisInteger: RedisInteger, TRedisString: RedisString,
+     TRedisList: RedisList, EInvalidReply: ReplyError, ERedis: RedisError].}
+
+proc newPipeline(): Pipeline =
+  new(result)
+  result.buffer = ""
+  result.enabled = false
+  result.expected = 0
+
+proc open*(host = "localhost", port = 6379.Port): Redis =
+  ## Opens a connection to the redis server.
+  result.socket = socket(buffered = false)
+  if result.socket == invalidSocket:
+    raiseOSError(osLastError())
+  result.socket.connect(host, port)
+  result.pipeline = newPipeline()  
+
+proc raiseInvalidReply(expected, got: char) =
+  raise newException(ReplyError, 
+          "Expected '$1' at the beginning of a status reply got '$2'" %
+          [$expected, $got])
+
+proc raiseNoOK(status: string, pipelineEnabled: bool) =
+  if pipelineEnabled and not (status == "QUEUED" or status == "PIPELINED"):
+    raise newException(ReplyError, "Expected \"QUEUED\" or \"PIPELINED\" got \"$1\"" % status)
+  elif not pipelineEnabled and status != "OK":
+    raise newException(ReplyError, "Expected \"OK\" got \"$1\"" % status)
+
+template readSocket(r: Redis, dummyVal:expr): stmt =
+  var line {.inject.}: TaintedString = ""
+  if r.pipeline.enabled:
+    return dummyVal
+  else:
+    readLine(r.socket, line)
+
+proc parseStatus(r: Redis, line: string = ""): RedisStatus =
+  if r.pipeline.enabled:
+    return "PIPELINED"
+
+  if line == "":
+    raise newException(RedisError, "Server closed connection prematurely")
+
+  if line[0] == '-':
+    raise newException(RedisError, strip(line))
+  if line[0] != '+':
+    raiseInvalidReply('+', line[0])
+  
+  return line.substr(1) # Strip '+'
+
+proc readStatus(r:Redis): RedisStatus =
+  r.readSocket("PIPELINED")
+  return r.parseStatus(line)
+ 
+proc parseInteger(r: Redis, line: string = ""): RedisInteger =
+  if r.pipeline.enabled: return -1
+  
+  #if line == "+QUEUED":  # inside of multi
+  #  return -1
+
+  if line == "":
+    raise newException(RedisError, "Server closed connection prematurely")
+
+  if line[0] == '-':
+    raise newException(RedisError, strip(line))
+  if line[0] != ':':
+    raiseInvalidReply(':', line[0])
+  
+  # Strip ':'
+  if parseBiggestInt(line, result, 1) == 0:
+    raise newException(ReplyError, "Unable to parse integer.") 
+
+proc readInteger(r: Redis): RedisInteger =
+  r.readSocket(-1)
+  return r.parseInteger(line)
+
+proc recv(sock: Socket, size: int): TaintedString =
+  result = newString(size).TaintedString
+  if sock.recv(cstring(result), size) != size:
+    raise newException(ReplyError, "recv failed")
+
+proc parseSingleString(r: Redis, line:string, allowMBNil = false): RedisString =
+  if r.pipeline.enabled: return ""
+  
+  # Error.
+  if line[0] == '-':
+    raise newException(RedisError, strip(line))
+  
+  # Some commands return a /bulk/ value or a /multi-bulk/ nil. Odd.
+  if allowMBNil:
+    if line == "*-1":
+       return redisNil
+  
+  if line[0] != '$':
+    raiseInvalidReply('$', line[0])
+  
+  var numBytes = parseInt(line.substr(1))
+  if numBytes == -1:
+    return redisNil
+
+  var s = r.socket.recv(numBytes+2)
+  result = strip(s.string)
+
+proc readSingleString(r: Redis): RedisString =
+  r.readSocket("")
+  return r.parseSingleString(line)
+
+proc readNext(r: Redis): RedisList
+
+proc parseArrayLines(r: Redis, countLine:string): RedisList =
+  if countLine.string[0] != '*':
+    raiseInvalidReply('*', countLine.string[0])
+
+  var numElems = parseInt(countLine.string.substr(1))
+  if numElems == -1: return nil
+  result = @[]
+
+  for i in 1..numElems:
+    var parsed = r.readNext()
+    if not isNil(parsed):
+      for item in parsed:
+        result.add(item)
+
+proc readArrayLines(r: Redis): RedisList =
+  r.readSocket(nil)
+  return r.parseArrayLines(line)  
+
+proc parseBulkString(r: Redis, allowMBNil = false, line:string = ""): RedisString =
+  if r.pipeline.enabled: return ""
+
+  return r.parseSingleString(line, allowMBNil)
+
+proc readBulkString(r: Redis, allowMBNil = false): RedisString =
+  r.readSocket("")
+  return r.parseBulkString(allowMBNil, line)
+
+proc readArray(r: Redis): RedisList =
+  r.readSocket(@[])
+  return r.parseArrayLines(line)
+
+proc readNext(r: Redis): RedisList =
+  r.readSocket(@[])
+
+  var res = case line[0]
+    of '+', '-': @[r.parseStatus(line)]
+    of ':': @[$(r.parseInteger(line))]
+    of '$': @[r.parseBulkString(true,line)]
+    of '*': r.parseArrayLines(line)
+    else: 
+      raise newException(ReplyError, "readNext failed on line: " & line)
+      nil
+  r.pipeline.expected -= 1
+  return res
+
+proc flushPipeline*(r: Redis, wasMulti = false): RedisList =
+  ## Send buffered commands, clear buffer, return results
+  if r.pipeline.buffer.len > 0:
+    r.socket.send(r.pipeline.buffer)
+  r.pipeline.buffer = ""
+  
+  r.pipeline.enabled = false
+  result = @[]
+  
+  var tot = r.pipeline.expected
+
+  for i in 0..tot-1:
+    var ret = r.readNext()
+    for item in ret:
+     if not (item.contains("OK") or item.contains("QUEUED")):
+       result.add(item)
+
+  r.pipeline.expected = 0
+
+proc startPipelining*(r: Redis) =
+  ## Enable command pipelining (reduces network roundtrips).
+  ## Note that when enabled, you must call flushPipeline to actually send commands, except
+  ## for multi/exec() which enable and flush the pipeline automatically.
+  ## Commands return immediately with dummy values; actual results returned from
+  ## flushPipeline() or exec()
+  r.pipeline.expected = 0
+  r.pipeline.enabled = true
+
+proc sendCommand(r: Redis, cmd: string, args: varargs[string]) =
+  var request = "*" & $(1 + args.len()) & "\c\L"
+  request.add("$" & $cmd.len() & "\c\L")
+  request.add(cmd & "\c\L")
+  for i in items(args):
+    request.add("$" & $i.len() & "\c\L")
+    request.add(i & "\c\L")
+  
+  if r.pipeline.enabled:
+    r.pipeline.buffer.add(request)
+    r.pipeline.expected += 1
+  else:
+    r.socket.send(request)
+
+proc sendCommand(r: Redis, cmd: string, arg1: string,
+                 args: varargs[string]) =
+  var request = "*" & $(2 + args.len()) & "\c\L"
+  request.add("$" & $cmd.len() & "\c\L")
+  request.add(cmd & "\c\L")
+  request.add("$" & $arg1.len() & "\c\L")
+  request.add(arg1 & "\c\L")
+  for i in items(args):
+    request.add("$" & $i.len() & "\c\L")
+    request.add(i & "\c\L")
+    
+  if r.pipeline.enabled:
+    r.pipeline.expected += 1
+    r.pipeline.buffer.add(request)
+  else:
+    r.socket.send(request)
+
+# Keys
+
+proc del*(r: Redis, keys: varargs[string]): RedisInteger =
+  ## Delete a key or multiple keys
+  r.sendCommand("DEL", keys)
+  return r.readInteger()
+
+proc exists*(r: Redis, key: string): bool =
+  ## Determine if a key exists
+  r.sendCommand("EXISTS", key)
+  return r.readInteger() == 1
+
+proc expire*(r: Redis, key: string, seconds: int): bool =
+  ## Set a key's time to live in seconds. Returns `false` if the key could
+  ## not be found or the timeout could not be set.
+  r.sendCommand("EXPIRE", key, $seconds)
+  return r.readInteger() == 1
+
+proc expireAt*(r: Redis, key: string, timestamp: int): bool =
+  ## Set the expiration for a key as a UNIX timestamp. Returns `false` 
+  ## if the key could not be found or the timeout could not be set.
+  r.sendCommand("EXPIREAT", key, $timestamp)
+  return r.readInteger() == 1
+
+proc keys*(r: Redis, pattern: string): RedisList =
+  ## Find all keys matching the given pattern
+  r.sendCommand("KEYS", pattern)
+  return r.readArray()
+
+proc scan*(r: Redis, cursor: var BiggestInt): RedisList =
+  ## Find all keys matching the given pattern and yield it to client in portions
+  ## using default Redis values for MATCH and COUNT parameters
+  r.sendCommand("SCAN", $cursor)
+  let reply = r.readArray()
+  cursor = strutils.parseBiggestInt(reply[0])
+  return reply[1..high(reply)]
+
+proc scan*(r: Redis, cursor: var BiggestInt, pattern: string): RedisList =
+  ## Find all keys matching the given pattern and yield it to client in portions
+  ## using cursor as a client query identifier. Using default Redis value for COUNT argument
+  r.sendCommand("SCAN", $cursor, ["MATCH", pattern])
+  let reply = r.readArray()
+  cursor = strutils.parseBiggestInt(reply[0])
+  return reply[1..high(reply)]
+
+proc scan*(r: Redis, cursor: var BiggestInt, pattern: string, count: int): RedisList = 
+  ## Find all keys matching the given pattern and yield it to client in portions
+  ## using cursor as a client query identifier.
+  r.sendCommand("SCAN", $cursor, ["MATCH", pattern, "COUNT", $count])
+  let reply = r.readArray()
+  cursor = strutils.parseBiggestInt(reply[0])
+  return reply[1..high(reply)]
+
+proc move*(r: Redis, key: string, db: int): bool =
+  ## Move a key to another database. Returns `true` on a successful move.
+  r.sendCommand("MOVE", key, $db)
+  return r.readInteger() == 1
+
+proc persist*(r: Redis, key: string): bool =
+  ## Remove the expiration from a key. 
+  ## Returns `true` when the timeout was removed.
+  r.sendCommand("PERSIST", key)
+  return r.readInteger() == 1
+  
+proc randomKey*(r: Redis): RedisString =
+  ## Return a random key from the keyspace
+  r.sendCommand("RANDOMKEY")
+  return r.readBulkString()
+
+proc rename*(r: Redis, key, newkey: string): RedisStatus =
+  ## Rename a key.
+  ## 
+  ## **WARNING:** Overwrites `newkey` if it exists!
+  r.sendCommand("RENAME", key, newkey)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+  
+proc renameNX*(r: Redis, key, newkey: string): bool =
+  ## Same as ``rename`` but doesn't continue if `newkey` exists.
+  ## Returns `true` if key was renamed.
+  r.sendCommand("RENAMENX", key, newkey)
+  return r.readInteger() == 1
+
+proc ttl*(r: Redis, key: string): RedisInteger =
+  ## Get the time to live for a key
+  r.sendCommand("TTL", key)
+  return r.readInteger()
+  
+proc keyType*(r: Redis, key: string): RedisStatus =
+  ## Determine the type stored at key
+  r.sendCommand("TYPE", key)
+  return r.readStatus()
+  
+
+# Strings
+
+proc append*(r: Redis, key, value: string): RedisInteger =
+  ## Append a value to a key
+  r.sendCommand("APPEND", key, value)
+  return r.readInteger()
+
+proc decr*(r: Redis, key: string): RedisInteger =
+  ## Decrement the integer value of a key by one
+  r.sendCommand("DECR", key)
+  return r.readInteger()
+  
+proc decrBy*(r: Redis, key: string, decrement: int): RedisInteger =
+  ## Decrement the integer value of a key by the given number
+  r.sendCommand("DECRBY", key, $decrement)
+  return r.readInteger()
+  
+proc get*(r: Redis, key: string): RedisString =
+  ## Get the value of a key. Returns `redisNil` when `key` doesn't exist.
+  r.sendCommand("GET", key)
+  return r.readBulkString()
+
+proc getBit*(r: Redis, key: string, offset: int): RedisInteger =
+  ## Returns the bit value at offset in the string value stored at key
+  r.sendCommand("GETBIT", key, $offset)
+  return r.readInteger()
+
+proc getRange*(r: Redis, key: string, start, stop: int): RedisString =
+  ## Get a substring of the string stored at a key
+  r.sendCommand("GETRANGE", key, $start, $stop)
+  return r.readBulkString()
+
+proc getSet*(r: Redis, key: string, value: string): RedisString =
+  ## Set the string value of a key and return its old value. Returns `redisNil`
+  ## when key doesn't exist.
+  r.sendCommand("GETSET", key, value)
+  return r.readBulkString()
+
+proc incr*(r: Redis, key: string): RedisInteger =
+  ## Increment the integer value of a key by one.
+  r.sendCommand("INCR", key)
+  return r.readInteger()
+
+proc incrBy*(r: Redis, key: string, increment: int): RedisInteger =
+  ## Increment the integer value of a key by the given number
+  r.sendCommand("INCRBY", key, $increment)
+  return r.readInteger()
+
+proc setk*(r: Redis, key, value: string) = 
+  ## Set the string value of a key.
+  ##
+  ## NOTE: This function had to be renamed due to a clash with the `set` type.
+  r.sendCommand("SET", key, value)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc setNX*(r: Redis, key, value: string): bool =
+  ## Set the value of a key, only if the key does not exist. Returns `true`
+  ## if the key was set.
+  r.sendCommand("SETNX", key, value)
+  return r.readInteger() == 1
+
+proc setBit*(r: Redis, key: string, offset: int, 
+             value: string): RedisInteger =
+  ## Sets or clears the bit at offset in the string value stored at key
+  r.sendCommand("SETBIT", key, $offset, value)
+  return r.readInteger()
+  
+proc setEx*(r: Redis, key: string, seconds: int, value: string): RedisStatus =
+  ## Set the value and expiration of a key
+  r.sendCommand("SETEX", key, $seconds, value)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc setRange*(r: Redis, key: string, offset: int, 
+               value: string): RedisInteger =
+  ## Overwrite part of a string at key starting at the specified offset
+  r.sendCommand("SETRANGE", key, $offset, value)
+  return r.readInteger()
+
+proc strlen*(r: Redis, key: string): RedisInteger =
+  ## Get the length of the value stored in a key. Returns 0 when key doesn't
+  ## exist.
+  r.sendCommand("STRLEN", key)
+  return r.readInteger()
+
+# Hashes
+proc hDel*(r: Redis, key, field: string): bool =
+  ## Delete a hash field at `key`. Returns `true` if the field was removed.
+  r.sendCommand("HDEL", key, field)
+  return r.readInteger() == 1
+
+proc hExists*(r: Redis, key, field: string): bool =
+  ## Determine if a hash field exists.
+  r.sendCommand("HEXISTS", key, field)
+  return r.readInteger() == 1
+
+proc hGet*(r: Redis, key, field: string): RedisString =
+  ## Get the value of a hash field
+  r.sendCommand("HGET", key, field)
+  return r.readBulkString()
+
+proc hGetAll*(r: Redis, key: string): RedisList =
+  ## Get all the fields and values in a hash
+  r.sendCommand("HGETALL", key)
+  return r.readArray()
+
+proc hIncrBy*(r: Redis, key, field: string, incr: int): RedisInteger =
+  ## Increment the integer value of a hash field by the given number
+  r.sendCommand("HINCRBY", key, field, $incr)
+  return r.readInteger()
+
+proc hKeys*(r: Redis, key: string): RedisList =
+  ## Get all the fields in a hash
+  r.sendCommand("HKEYS", key)
+  return r.readArray()
+
+proc hLen*(r: Redis, key: string): RedisInteger =
+  ## Get the number of fields in a hash
+  r.sendCommand("HLEN", key)
+  return r.readInteger()
+
+proc hMGet*(r: Redis, key: string, fields: varargs[string]): RedisList =
+  ## Get the values of all the given hash fields
+  r.sendCommand("HMGET", key, fields)
+  return r.readArray()
+
+proc hMSet*(r: Redis, key: string, 
+            fieldValues: openArray[tuple[field, value: string]]) =
+  ## Set multiple hash fields to multiple values
+  var args = @[key]
+  for field, value in items(fieldValues):
+    args.add(field)
+    args.add(value)
+  r.sendCommand("HMSET", args)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc hSet*(r: Redis, key, field, value: string): RedisInteger =
+  ## Set the string value of a hash field
+  r.sendCommand("HSET", key, field, value)
+  return r.readInteger()
+  
+proc hSetNX*(r: Redis, key, field, value: string): RedisInteger =
+  ## Set the value of a hash field, only if the field does **not** exist
+  r.sendCommand("HSETNX", key, field, value)
+  return r.readInteger()
+
+proc hVals*(r: Redis, key: string): RedisList =
+  ## Get all the values in a hash
+  r.sendCommand("HVALS", key)
+  return r.readArray()
+  
+# Lists
+
+proc bLPop*(r: Redis, keys: varargs[string], timeout: int): RedisList =
+  ## Remove and get the *first* element in a list, or block until 
+  ## one is available
+  var args: seq[string] = @[]
+  for i in items(keys): args.add(i)
+  args.add($timeout)
+  r.sendCommand("BLPOP", args)
+  return r.readArray()
+
+proc bRPop*(r: Redis, keys: varargs[string], timeout: int): RedisList =
+  ## Remove and get the *last* element in a list, or block until one 
+  ## is available.
+  var args: seq[string] = @[]
+  for i in items(keys): args.add(i)
+  args.add($timeout)
+  r.sendCommand("BRPOP", args)
+  return r.readArray()
+
+proc bRPopLPush*(r: Redis, source, destination: string,
+                 timeout: int): RedisString =
+  ## Pop a value from a list, push it to another list and return it; or
+  ## block until one is available.
+  ##
+  ## http://redis.io/commands/brpoplpush
+  r.sendCommand("BRPOPLPUSH", source, destination, $timeout)
+  return r.readBulkString(true) # Multi-Bulk nil allowed.
+
+proc lIndex*(r: Redis, key: string, index: int): RedisString =
+  ## Get an element from a list by its index
+  r.sendCommand("LINDEX", key, $index)
+  return r.readBulkString()
+
+proc lInsert*(r: Redis, key: string, before: bool, pivot, value: string):
+              RedisInteger =
+  ## Insert an element before or after another element in a list
+  var pos = if before: "BEFORE" else: "AFTER"
+  r.sendCommand("LINSERT", key, pos, pivot, value)
+  return r.readInteger()
+  
+proc lLen*(r: Redis, key: string): RedisInteger =
+  ## Get the length of a list
+  r.sendCommand("LLEN", key)
+  return r.readInteger()
+
+proc lPop*(r: Redis, key: string): RedisString =
+  ## Remove and get the first element in a list
+  r.sendCommand("LPOP", key)
+  return r.readBulkString()
+
+proc lPush*(r: Redis, key, value: string, create: bool = true): RedisInteger =
+  ## Prepend a value to a list. Returns the length of the list after the push.
+  ## The ``create`` param specifies whether a list should be created if it
+  ## doesn't exist at ``key``. More specifically if ``create`` is true, `LPUSH` 
+  ## will be used, otherwise `LPUSHX`.
+  if create:
+    r.sendCommand("LPUSH", key, value)
+  else:
+    r.sendCommand("LPUSHX", key, value)
+  return r.readInteger()
+
+proc lRange*(r: Redis, key: string, start, stop: int): RedisList =
+  ## Get a range of elements from a list. Returns `nil` when `key` 
+  ## doesn't exist.
+  r.sendCommand("LRANGE", key, $start, $stop)
+  return r.readArray()
+
+proc lRem*(r: Redis, key: string, value: string, count: int = 0): RedisInteger =
+  ## Remove elements from a list. Returns the number of elements that have been
+  ## removed.
+  r.sendCommand("LREM", key, $count, value)
+  return r.readInteger()
+
+proc lSet*(r: Redis, key: string, index: int, value: string) =
+  ## Set the value of an element in a list by its index
+  r.sendCommand("LSET", key, $index, value)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc lTrim*(r: Redis, key: string, start, stop: int)  =
+  ## Trim a list to the specified range
+  r.sendCommand("LTRIM", key, $start, $stop)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc rPop*(r: Redis, key: string): RedisString =
+  ## Remove and get the last element in a list
+  r.sendCommand("RPOP", key)
+  return r.readBulkString()
+  
+proc rPopLPush*(r: Redis, source, destination: string): RedisString =
+  ## Remove the last element in a list, append it to another list and return it
+  r.sendCommand("RPOPLPUSH", source, destination)
+  return r.readBulkString()
+  
+proc rPush*(r: Redis, key, value: string, create: bool = true): RedisInteger =
+  ## Append a value to a list. Returns the length of the list after the push.
+  ## The ``create`` param specifies whether a list should be created if it
+  ## doesn't exist at ``key``. More specifically if ``create`` is true, `RPUSH` 
+  ## will be used, otherwise `RPUSHX`.
+  if create:
+    r.sendCommand("RPUSH", key, value)
+  else:
+    r.sendCommand("RPUSHX", key, value)
+  return r.readInteger()
+
+# Sets
+
+proc sadd*(r: Redis, key: string, member: string): RedisInteger =
+  ## Add a member to a set
+  r.sendCommand("SADD", key, member)
+  return r.readInteger()
+
+proc scard*(r: Redis, key: string): RedisInteger =
+  ## Get the number of members in a set
+  r.sendCommand("SCARD", key)
+  return r.readInteger()
+
+proc sdiff*(r: Redis, keys: varargs[string]): RedisList =
+  ## Subtract multiple sets
+  r.sendCommand("SDIFF", keys)
+  return r.readArray()
+
+proc sdiffstore*(r: Redis, destination: string,
+                keys: varargs[string]): RedisInteger =
+  ## Subtract multiple sets and store the resulting set in a key
+  r.sendCommand("SDIFFSTORE", destination, keys)
+  return r.readInteger()
+
+proc sinter*(r: Redis, keys: varargs[string]): RedisList =
+  ## Intersect multiple sets
+  r.sendCommand("SINTER", keys)
+  return r.readArray()
+
+proc sinterstore*(r: Redis, destination: string,
+                 keys: varargs[string]): RedisInteger =
+  ## Intersect multiple sets and store the resulting set in a key
+  r.sendCommand("SINTERSTORE", destination, keys)
+  return r.readInteger()
+
+proc sismember*(r: Redis, key: string, member: string): RedisInteger =
+  ## Determine if a given value is a member of a set
+  r.sendCommand("SISMEMBER", key, member)
+  return r.readInteger()
+
+proc smembers*(r: Redis, key: string): RedisList =
+  ## Get all the members in a set
+  r.sendCommand("SMEMBERS", key)
+  return r.readArray()
+
+proc smove*(r: Redis, source: string, destination: string,
+           member: string): RedisInteger =
+  ## Move a member from one set to another
+  r.sendCommand("SMOVE", source, destination, member)
+  return r.readInteger()
+
+proc spop*(r: Redis, key: string): RedisString =
+  ## Remove and return a random member from a set
+  r.sendCommand("SPOP", key)
+  return r.readBulkString()
+
+proc srandmember*(r: Redis, key: string): RedisString =
+  ## Get a random member from a set
+  r.sendCommand("SRANDMEMBER", key)
+  return r.readBulkString()
+
+proc srem*(r: Redis, key: string, member: string): RedisInteger =
+  ## Remove a member from a set
+  r.sendCommand("SREM", key, member)
+  return r.readInteger()
+
+proc sunion*(r: Redis, keys: varargs[string]): RedisList =
+  ## Add multiple sets
+  r.sendCommand("SUNION", keys)
+  return r.readArray()
+
+proc sunionstore*(r: Redis, destination: string,
+                 key: varargs[string]): RedisInteger =
+  ## Add multiple sets and store the resulting set in a key 
+  r.sendCommand("SUNIONSTORE", destination, key)
+  return r.readInteger()
+
+# Sorted sets
+
+proc zadd*(r: Redis, key: string, score: int, member: string): RedisInteger =
+  ## Add a member to a sorted set, or update its score if it already exists
+  r.sendCommand("ZADD", key, $score, member)
+  return r.readInteger()
+
+proc zcard*(r: Redis, key: string): RedisInteger =
+  ## Get the number of members in a sorted set
+  r.sendCommand("ZCARD", key)
+  return r.readInteger()
+
+proc zcount*(r: Redis, key: string, min: string, max: string): RedisInteger =
+  ## Count the members in a sorted set with scores within the given values
+  r.sendCommand("ZCOUNT", key, min, max)
+  return r.readInteger()
+
+proc zincrby*(r: Redis, key: string, increment: string,
+             member: string): RedisString =
+  ## Increment the score of a member in a sorted set
+  r.sendCommand("ZINCRBY", key, increment, member)
+  return r.readBulkString()
+
+proc zinterstore*(r: Redis, destination: string, numkeys: string,
+                 keys: openArray[string], weights: openArray[string] = [],
+                 aggregate: string = ""): RedisInteger =
+  ## Intersect multiple sorted sets and store the resulting sorted set in
+  ## a new key
+  var args = @[destination, numkeys]
+  for i in items(keys): args.add(i)
+  
+  if weights.len != 0:
+    args.add("WITHSCORE")
+    for i in items(weights): args.add(i)
+  if aggregate.len != 0:
+    args.add("AGGREGATE")
+    args.add(aggregate)
+    
+  r.sendCommand("ZINTERSTORE", args)
+  
+  return r.readInteger()
+
+proc zrange*(r: Redis, key: string, start: string, stop: string,
+            withScores: bool): RedisList =
+  ## Return a range of members in a sorted set, by index
+  if not withScores:
+    r.sendCommand("ZRANGE", key, start, stop)
+  else:
+    r.sendCommand("ZRANGE", "WITHSCORES", key, start, stop)
+  return r.readArray()
+
+proc zrangebyscore*(r: Redis, key: string, min: string, max: string, 
+                   withScore: bool = false, limit: bool = false,
+                   limitOffset: int = 0, limitCount: int = 0): RedisList =
+  ## Return a range of members in a sorted set, by score
+  var args = @[key, min, max]
+  
+  if withScore: args.add("WITHSCORE")
+  if limit: 
+    args.add("LIMIT")
+    args.add($limitOffset)
+    args.add($limitCount)
+    
+  r.sendCommand("ZRANGEBYSCORE", args)
+  return r.readArray()
+
+proc zrank*(r: Redis, key: string, member: string): RedisString =
+  ## Determine the index of a member in a sorted set
+  r.sendCommand("ZRANK", key, member)
+  return r.readBulkString()
+
+proc zrem*(r: Redis, key: string, member: string): RedisInteger =
+  ## Remove a member from a sorted set
+  r.sendCommand("ZREM", key, member)
+  return r.readInteger()
+
+proc zremrangebyrank*(r: Redis, key: string, start: string,
+                     stop: string): RedisInteger =
+  ## Remove all members in a sorted set within the given indexes
+  r.sendCommand("ZREMRANGEBYRANK", key, start, stop)
+  return r.readInteger()
+
+proc zremrangebyscore*(r: Redis, key: string, min: string,
+                      max: string): RedisInteger =
+  ## Remove all members in a sorted set within the given scores
+  r.sendCommand("ZREMRANGEBYSCORE", key, min, max)
+  return r.readInteger()
+
+proc zrevrange*(r: Redis, key: string, start: string, stop: string,
+               withScore: bool): RedisList =
+  ## Return a range of members in a sorted set, by index, 
+  ## with scores ordered from high to low
+  if withScore:
+    r.sendCommand("ZREVRANGE", "WITHSCORE", key, start, stop)
+  else: r.sendCommand("ZREVRANGE", key, start, stop)
+  return r.readArray()
+
+proc zrevrangebyscore*(r: Redis, key: string, min: string, max: string, 
+                   withScore: bool = false, limit: bool = false,
+                   limitOffset: int = 0, limitCount: int = 0): RedisList =
+  ## Return a range of members in a sorted set, by score, with
+  ## scores ordered from high to low
+  var args = @[key, min, max]
+  
+  if withScore: args.add("WITHSCORE")
+  if limit: 
+    args.add("LIMIT")
+    args.add($limitOffset)
+    args.add($limitCount)
+  
+  r.sendCommand("ZREVRANGEBYSCORE", args)
+  return r.readArray()
+
+proc zrevrank*(r: Redis, key: string, member: string): RedisString =
+  ## Determine the index of a member in a sorted set, with
+  ## scores ordered from high to low
+  r.sendCommand("ZREVRANK", key, member)
+  return r.readBulkString()
+
+proc zscore*(r: Redis, key: string, member: string): RedisString =
+  ## Get the score associated with the given member in a sorted set
+  r.sendCommand("ZSCORE", key, member)
+  return r.readBulkString()
+
+proc zunionstore*(r: Redis, destination: string, numkeys: string,
+                 keys: openArray[string], weights: openArray[string] = [],
+                 aggregate: string = ""): RedisInteger =
+  ## Add multiple sorted sets and store the resulting sorted set in a new key 
+  var args = @[destination, numkeys]
+  for i in items(keys): args.add(i)
+  
+  if weights.len != 0:
+    args.add("WEIGHTS")
+    for i in items(weights): args.add(i)
+  if aggregate.len != 0:
+    args.add("AGGREGATE")
+    args.add(aggregate)
+    
+  r.sendCommand("ZUNIONSTORE", args)
+  
+  return r.readInteger()
+
+# HyperLogLog
+
+proc pfadd*(r: Redis, key: string, elements: varargs[string]): RedisInteger = 
+  ## Add variable number of elements into special 'HyperLogLog' set type
+  r.sendCommand("PFADD", key, elements)
+  return r.readInteger()
+
+proc pfcount*(r: Redis, key: string): RedisInteger =
+  ## Count approximate number of elements in 'HyperLogLog'
+  r.sendCommand("PFCOUNT", key)
+  return r.readInteger()
+
+proc pfmerge*(r: Redis, destination: string, sources: varargs[string]) =
+  ## Merge several source HyperLogLog's into one specified by destKey
+  r.sendCommand("PFMERGE", destination, sources)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+# Pub/Sub
+
+# TODO: pub/sub -- I don't think this will work synchronously.
+discard """
+proc psubscribe*(r: TRedis, pattern: openarray[string]): ???? =
+  ## Listen for messages published to channels matching the given patterns
+  r.socket.send("PSUBSCRIBE $#\c\L" % pattern)
+  return ???
+
+proc publish*(r: TRedis, channel: string, message: string): TRedisInteger =
+  ## Post a message to a channel
+  r.socket.send("PUBLISH $# $#\c\L" % [channel, message])
+  return r.readInteger()
+
+proc punsubscribe*(r: TRedis, [pattern: openarray[string], : string): ???? =
+  ## Stop listening for messages posted to channels matching the given patterns
+  r.socket.send("PUNSUBSCRIBE $# $#\c\L" % [[pattern.join(), ])
+  return ???
+
+proc subscribe*(r: TRedis, channel: openarray[string]): ???? =
+  ## Listen for messages published to the given channels
+  r.socket.send("SUBSCRIBE $#\c\L" % channel.join)
+  return ???
+
+proc unsubscribe*(r: TRedis, [channel: openarray[string], : string): ???? =
+  ## Stop listening for messages posted to the given channels 
+  r.socket.send("UNSUBSCRIBE $# $#\c\L" % [[channel.join(), ])
+  return ???
+
+"""
+
+# Transactions
+
+proc discardMulti*(r: Redis) =
+  ## Discard all commands issued after MULTI
+  r.sendCommand("DISCARD")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc exec*(r: Redis): RedisList =
+  ## Execute all commands issued after MULTI
+  r.sendCommand("EXEC")  
+  r.pipeline.enabled = false
+  # Will reply with +OK for MULTI/EXEC and +QUEUED for every command
+  # between, then with the results
+  return r.flushPipeline(true)
+  
+
+proc multi*(r: Redis) =
+  ## Mark the start of a transaction block
+  r.startPipelining()
+  r.sendCommand("MULTI")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc unwatch*(r: Redis) =
+  ## Forget about all watched keys
+  r.sendCommand("UNWATCH")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc watch*(r: Redis, key: varargs[string]) =
+  ## Watch the given keys to determine execution of the MULTI/EXEC block 
+  r.sendCommand("WATCH", key)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+# Connection
+
+proc auth*(r: Redis, password: string) =
+  ## Authenticate to the server
+  r.sendCommand("AUTH", password)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc echoServ*(r: Redis, message: string): RedisString =
+  ## Echo the given string
+  r.sendCommand("ECHO", message)
+  return r.readBulkString()
+
+proc ping*(r: Redis): RedisStatus =
+  ## Ping the server
+  r.sendCommand("PING")
+  return r.readStatus()
+
+proc quit*(r: Redis) =
+  ## Close the connection
+  r.sendCommand("QUIT")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc select*(r: Redis, index: int): RedisStatus =
+  ## Change the selected database for the current connection 
+  r.sendCommand("SELECT", $index)
+  return r.readStatus()
+
+# Server
+
+proc bgrewriteaof*(r: Redis) =
+  ## Asynchronously rewrite the append-only file
+  r.sendCommand("BGREWRITEAOF")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc bgsave*(r: Redis) =
+  ## Asynchronously save the dataset to disk
+  r.sendCommand("BGSAVE")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc configGet*(r: Redis, parameter: string): RedisList =
+  ## Get the value of a configuration parameter
+  r.sendCommand("CONFIG", "GET", parameter)
+  return r.readArray()
+
+proc configSet*(r: Redis, parameter: string, value: string) =
+  ## Set a configuration parameter to the given value
+  r.sendCommand("CONFIG", "SET", parameter, value)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc configResetStat*(r: Redis) =
+  ## Reset the stats returned by INFO
+  r.sendCommand("CONFIG", "RESETSTAT")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc dbsize*(r: Redis): RedisInteger =
+  ## Return the number of keys in the selected database
+  r.sendCommand("DBSIZE")
+  return r.readInteger()
+
+proc debugObject*(r: Redis, key: string): RedisStatus =
+  ## Get debugging information about a key
+  r.sendCommand("DEBUG", "OBJECT", key)
+  return r.readStatus()
+
+proc debugSegfault*(r: Redis) =
+  ## Make the server crash
+  r.sendCommand("DEBUG", "SEGFAULT")
+
+proc flushall*(r: Redis): RedisStatus =
+  ## Remove all keys from all databases
+  r.sendCommand("FLUSHALL")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc flushdb*(r: Redis): RedisStatus =
+  ## Remove all keys from the current database
+  r.sendCommand("FLUSHDB")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc info*(r: Redis): RedisString =
+  ## Get information and statistics about the server
+  r.sendCommand("INFO")
+  return r.readBulkString()
+
+proc lastsave*(r: Redis): RedisInteger =
+  ## Get the UNIX time stamp of the last successful save to disk
+  r.sendCommand("LASTSAVE")
+  return r.readInteger()
+
+discard """
+proc monitor*(r: TRedis) =
+  ## Listen for all requests received by the server in real time
+  r.socket.send("MONITOR\c\L")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+"""
+
+proc save*(r: Redis) =
+  ## Synchronously save the dataset to disk
+  r.sendCommand("SAVE")
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+proc shutdown*(r: Redis) =
+  ## Synchronously save the dataset to disk and then shut down the server
+  r.sendCommand("SHUTDOWN")
+  var s = "".TaintedString
+  r.socket.readLine(s)
+  if s.string.len != 0: raise newException(RedisError, s.string)
+
+proc slaveof*(r: Redis, host: string, port: string) =
+  ## Make the server a slave of another instance, or promote it as master
+  r.sendCommand("SLAVEOF", host, port)
+  raiseNoOK(r.readStatus(), r.pipeline.enabled)
+
+iterator hPairs*(r: Redis, key: string): tuple[key, value: string] =
+  ## Iterator for keys and values in a hash.
+  var 
+    contents = r.hGetAll(key)
+    k = ""
+  for i in items(contents):
+    if k == "":
+      k = i
+    else:
+      yield (k, i)
+      k = ""
+
+proc someTests(r: Redis, how: SendMode):seq[string] =
+  var list:seq[string] = @[]
+
+  if how == pipelined:
+    r.startPipelining()
+  elif how ==  multiple: 
+    r.multi()
+    
+  r.setk("nim:test", "Testing something.")
+  r.setk("nim:utf8", "ã“ã‚“ã«ã¡ã¯")
+  r.setk("nim:esc", "\\ths Ä…gt\\")
+  r.setk("nim:int", "1")
+  list.add(r.get("nim:esc"))
+  list.add($(r.incr("nim:int")))
+  list.add(r.get("nim:int"))
+  list.add(r.get("nim:utf8"))
+  list.add($(r.hSet("test1", "name", "A Test")))
+  var res = r.hGetAll("test1")
+  for r in res:
+    list.add(r)
+  list.add(r.get("invalid_key"))
+  list.add($(r.lPush("mylist","itema")))
+  list.add($(r.lPush("mylist","itemb")))
+  r.lTrim("mylist",0,1)
+  var p = r.lRange("mylist", 0, -1)
+
+  for i in items(p):
+    if not isNil(i):
+      list.add(i) 
+
+  list.add(r.debugObject("mylist"))
+
+  r.configSet("timeout", "299")
+  var g = r.configGet("timeout")
+  for i in items(g):
+    list.add(i)
+
+  list.add(r.echoServ("BLAH"))
+
+  case how
+  of normal:
+    return list
+  of pipelined:
+    return r.flushPipeline()
+  of multiple:
+    return r.exec()
+
+proc assertListsIdentical(listA, listB: seq[string]) =
+  assert(listA.len == listB.len)
+  var i = 0
+  for item in listA:
+    assert(item == listB[i])
+    i = i + 1
+  
+when not defined(testing) and isMainModule:
+  when false:
+    var r = open()
+
+    # Test with no pipelining
+    var listNormal = r.someTests(normal)
+
+    # Test with pipelining enabled
+    var listPipelined = r.someTests(pipelined)
+    assertListsIdentical(listNormal, listPipelined)
+
+    # Test with multi/exec() (automatic pipelining)
+    var listMulti = r.someTests(multiple)
+    assertListsIdentical(listNormal, listMulti)
diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim
new file mode 100644
index 000000000..0c182843a
--- /dev/null
+++ b/lib/pure/romans.nim
@@ -0,0 +1,56 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2011 Philippe Lhoste
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Module for converting an integer to a Roman numeral.
+## See http://en.wikipedia.org/wiki/Roman_numerals for reference.
+
+const
+  RomanNumeralDigits* = {'I', 'i', 'V', 'v', 'X', 'x', 'L', 'l', 'C', 'c', 
+    'D', 'd', 'M', 'm'} ## set of all characters a Roman numeral may consist of
+
+proc romanToDecimal*(romanVal: string): int =
+  ## Converts a Roman numeral to its int representation.
+  result = 0
+  var prevVal = 0
+  for i in countdown(romanVal.len - 1, 0):
+    var val = 0
+    case romanVal[i]
+    of 'I', 'i': val = 1
+    of 'V', 'v': val = 5
+    of 'X', 'x': val = 10
+    of 'L', 'l': val = 50
+    of 'C', 'c': val = 100
+    of 'D', 'd': val = 500
+    of 'M', 'm': val = 1000
+    else: 
+      raise newException(EInvalidValue, "invalid roman numeral: " & $romanVal)
+    if val >= prevVal:
+      inc(result, val)
+    else:
+      dec(result, val)
+    prevVal = val
+
+proc decimalToRoman*(number: range[1..3_999]): string =
+  ## Converts a number to a Roman numeral.
+  const romanComposites = [
+    ("M", 1000), ("CM", 900),
+    ("D", 500), ("CD", 400), ("C", 100),
+    ("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
+    ("V", 5), ("IV", 4), ("I", 1)]
+  result = ""
+  var decVal: int = number
+  for key, val in items(romanComposites):
+    while decVal >= val:
+      dec(decVal, val)
+      result.add(key)
+
+when isMainModule:
+  for i in 1 .. 3_999:
+    assert i == i.decimalToRoman.romanToDecimal
+
diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim
new file mode 100644
index 000000000..5c7fedfe3
--- /dev/null
+++ b/lib/pure/ropes.nim
@@ -0,0 +1,386 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains support for a `rope`:idx: data type.
+## Ropes can represent very long strings efficiently; especially concatenation
+## is done in O(1) instead of O(n). They are essentially concatenation
+## trees that are only flattened when converting to a native Nim
+## string. The empty string is represented by ``nil``. Ropes are immutable and
+## subtrees can be shared without copying.
+## Leaves can be cached for better memory efficiency at the cost of
+## runtime efficiency.
+
+include "system/inclrtl"
+
+{.deadCodeElim: on.}
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+const
+  countCacheMisses = false
+
+var
+  cacheEnabled = false
+
+type 
+  Rope* = ref RopeObj ## empty rope is represented by nil
+  RopeObj {.acyclic.} = object
+    left, right: Rope
+    length: int
+    data: string # != nil if a leaf
+
+{.deprecated: [PRope: Rope].}
+
+proc isConc(r: Rope): bool {.inline.} = return isNil(r.data)
+
+# Note that the left and right pointers are not needed for leafs.
+# Leaves have relatively high memory overhead (~30 bytes on a 32
+# bit machine) and we produce many of them. This is why we cache and
+# share leafs across different rope trees.
+# To cache them they are inserted in another tree, a splay tree for best
+# performance. But for the caching tree we use the leaf's left and right
+# pointers.
+
+proc len*(a: Rope): int {.rtl, extern: "nro$1".} =
+  ## the rope's length
+  if a == nil: result = 0
+  else: result = a.length
+
+proc newRope(): Rope = new(result)
+proc newRope(data: string): Rope =
+  new(result)
+  result.length = len(data)
+  result.data = data
+
+var 
+  cache {.threadvar.}: Rope     # the root of the cache tree
+  N {.threadvar.}: Rope         # dummy rope needed for splay algorithm
+
+when countCacheMisses:
+  var misses, hits: int
+
+proc splay(s: string, tree: Rope, cmpres: var int): Rope =
+  var c: int
+  var t = tree
+  N.left = nil
+  N.right = nil               # reset to nil
+  var le = N
+  var r = N
+  while true:
+    c = cmp(s, t.data)
+    if c < 0:
+      if (t.left != nil) and (s < t.left.data):
+        var y = t.left
+        t.left = y.right
+        y.right = t
+        t = y
+      if t.left == nil: break 
+      r.left = t
+      r = t
+      t = t.left
+    elif c > 0:
+      if (t.right != nil) and (s > t.right.data):
+        var y = t.right
+        t.right = y.left
+        y.left = t
+        t = y
+      if t.right == nil: break 
+      le.right = t
+      le = t
+      t = t.right
+    else:
+      break
+  cmpres = c
+  le.right = t.left
+  r.left = t.right
+  t.left = N.right
+  t.right = N.left
+  result = t
+
+proc insertInCache(s: string, tree: Rope): Rope =
+  var t = tree
+  if t == nil:
+    result = newRope(s)
+    when countCacheMisses: inc(misses)
+    return 
+  var cmp: int
+  t = splay(s, t, cmp)
+  if cmp == 0:
+    # We get here if it's already in the Tree
+    # Don't add it again
+    result = t
+    when countCacheMisses: inc(hits)
+  else:
+    when countCacheMisses: inc(misses)
+    result = newRope(s)
+    if cmp < 0:
+      result.left = t.left
+      result.right = t
+      t.left = nil
+    else:
+      # i > t.item:
+      result.right = t.right
+      result.left = t
+      t.right = nil
+
+proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} =
+  ## Converts a string to a rope.
+  if s.len == 0:
+    result = nil
+  elif cacheEnabled:
+    result = insertInCache(s, cache)
+    cache = result
+  else:
+    result = newRope(s)
+
+proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} =
+  ## Converts an int to a rope.
+  result = rope($i)
+
+proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} =
+  ## Converts a float to a rope.
+  result = rope($f)
+
+proc enableCache*() {.rtl, extern: "nro$1".} =
+  ## Enables the caching of leaves. This reduces the memory footprint at
+  ## the cost of runtime efficiency.
+  cacheEnabled = true
+
+proc disableCache*() {.rtl, extern: "nro$1".} =
+  ## the cache is discarded and disabled. The GC will reuse its used memory.
+  cache = nil
+  cacheEnabled = false
+
+proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} =
+  ## the concatenation operator for ropes.
+  if a == nil:
+    result = b
+  elif b == nil:
+    result = a
+  else:
+    result = newRope()
+    result.length = a.length + b.length
+    when false:
+      # XXX rebalancing would be nice, but is too expensive.
+      result.left = a.left
+      var x = newRope()
+      x.left = a.right
+      x.right = b
+      result.right = x
+    else:
+      result.left = a
+      result.right = b
+
+proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} =
+  ## the concatenation operator for ropes.
+  result = a & rope(b)
+
+proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} =
+  ## the concatenation operator for ropes.
+  result = rope(a) & b
+
+proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} =
+  ## the concatenation operator for an openarray of ropes.
+  for i in countup(0, high(a)): result = result & a[i]
+
+proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} =
+  ## adds `b` to the rope `a`.
+  a = a & b
+
+proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} =
+  ## adds `b` to the rope `a`.
+  a = a & b
+  
+proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} =
+  ## returns the character at position `i` in the rope `r`. This is quite
+  ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned.
+  var x = r
+  var j = i
+  if x == nil: return
+  while true:
+    if not isConc(x):
+      if x.data.len <% j: return x.data[j]
+      return '\0'
+    else:
+      if x.left.len >% j:
+        x = x.left
+      else:
+        x = x.right
+        dec(j, x.len)
+
+iterator leaves*(r: Rope): string =
+  ## iterates over any leaf string in the rope `r`.
+  if r != nil:
+    var stack = @[r]
+    while stack.len > 0:
+      var it = stack.pop
+      while isConc(it):
+        stack.add(it.right)
+        it = it.left
+        assert(it != nil)
+      assert(it.data != nil)
+      yield it.data
+
+iterator items*(r: Rope): char =
+  ## iterates over any character in the rope `r`.
+  for s in leaves(r):
+    for c in items(s): yield c
+
+proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} =
+  ## writes a rope to a file.
+  for s in leaves(r): write(f, s)
+
+proc `$`*(r: Rope): string  {.rtl, extern: "nroToString".}=
+  ## converts a rope back to a string.
+  result = newString(r.len)
+  setLen(result, 0)
+  for s in leaves(r): add(result, s)
+
+when false:
+  # Format string caching seems reasonable: All leaves can be shared and format
+  # string parsing has to be done only once. A compiled format string is stored
+  # as a rope. A negative length is used for the index into the args array.
+  proc compiledArg(idx: int): Rope =
+    new(result)
+    result.length = -idx
+  
+  proc compileFrmt(frmt: string): Rope =
+    var i = 0
+    var length = len(frmt)
+    result = nil
+    var num = 0
+    while i < length:
+      if frmt[i] == '$':
+        inc(i)
+        case frmt[i]
+        of '$':
+          add(result, "$")
+          inc(i)
+        of '#':
+          inc(i)
+          add(result, compiledArg(num+1))
+          inc(num)
+        of '0'..'9':
+          var j = 0
+          while true:
+            j = j * 10 + ord(frmt[i]) - ord('0')
+            inc(i)
+            if frmt[i] notin {'0'..'9'}: break 
+          add(s, compiledArg(j))
+        of '{':
+          inc(i)
+          var j = 0
+          while frmt[i] in {'0'..'9'}:
+            j = j * 10 + ord(frmt[i]) - ord('0')
+            inc(i)
+          if frmt[i] == '}': inc(i)
+          else: raise newException(EInvalidValue, "invalid format string")
+          add(s, compiledArg(j))
+        else: raise newException(EInvalidValue, "invalid format string")
+      var start = i
+      while i < length:
+        if frmt[i] != '$': inc(i)
+        else: break
+      if i - 1 >= start:
+        add(result, substr(frmt, start, i-1))
+
+proc `%`*(frmt: string, args: openArray[Rope]): Rope {.
+  rtl, extern: "nroFormat".} =
+  ## `%` substitution operator for ropes. Does not support the ``$identifier``
+  ## nor ``${identifier}`` notations.
+  var i = 0
+  var length = len(frmt)
+  result = nil
+  var num = 0
+  while i < length:
+    if frmt[i] == '$':
+      inc(i)
+      case frmt[i]
+      of '$':
+        add(result, "$")
+        inc(i)
+      of '#':
+        inc(i)
+        add(result, args[num])
+        inc(num)
+      of '0'..'9':
+        var j = 0
+        while true:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+          if frmt[i] notin {'0'..'9'}: break
+        add(result, args[j-1])
+      of '{':
+        inc(i)
+        var j = 0
+        while frmt[i] in {'0'..'9'}:
+          j = j * 10 + ord(frmt[i]) - ord('0')
+          inc(i)
+        if frmt[i] == '}': inc(i)
+        else: raise newException(ValueError, "invalid format string")
+
+        add(result, args[j-1])
+      else: raise newException(ValueError, "invalid format string")
+    var start = i
+    while i < length:
+      if frmt[i] != '$': inc(i)
+      else: break
+    if i - 1 >= start:
+      add(result, substr(frmt, start, i - 1))
+
+proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {.
+  rtl, extern: "nro$1".} =
+  ## shortcut for ``add(c, frmt % args)``.
+  add(c, frmt % args)
+
+const
+  bufSize = 1024              # 1 KB is reasonable
+
+proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} =
+  ## returns true if the contents of the file `f` equal `r`.
+  var 
+    buf: array[bufSize, char]
+    bpos = buf.len
+    blen = buf.len
+
+  for s in leaves(r):
+    var spos = 0
+    let slen = s.len
+    while spos < slen:
+      if bpos == blen:
+        # Read more data
+        bpos = 0
+        blen = readBuffer(f, addr(buf[0]), buf.len)
+        if blen == 0:  # no more data in file
+          result = false
+          return
+      let n = min(blen - bpos, slen - spos)
+      # TODO There's gotta be a better way of comparing here...
+      if not equalMem(addr(buf[bpos]), 
+                      cast[pointer](cast[int](cstring(s))+spos), n):
+        result = false
+        return
+      spos += n
+      bpos += n
+
+  result = readBuffer(f, addr(buf[0]), 1) == 0  # check that we've read all
+
+proc equalsFile*(r: Rope, filename: string): bool {.rtl, extern: "nro$1Str".} =
+  ## returns true if the contents of the file `f` equal `r`. If `f` does not
+  ## exist, false is returned.
+  var f: File
+  result = open(f, filename)
+  if result:
+    result = equalsFile(r, f)
+    close(f)
+
+new(N) # init dummy node for splay algorithm
+
+{.pop.}
diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim
new file mode 100644
index 000000000..3de422c87
--- /dev/null
+++ b/lib/pure/scgi.nim
@@ -0,0 +1,297 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements helper procs for SCGI applications. Example:
+## 
+## .. code-block:: Nim
+##
+##    import strtabs, sockets, scgi
+##
+##    var counter = 0
+##    proc handleRequest(client: Socket, input: string, 
+##                       headers: StringTableRef): bool {.procvar.} =
+##      inc(counter)
+##      client.writeStatusOkTextContent()
+##      client.send("Hello for the $#th time." % $counter & "\c\L")
+##      return false # do not stop processing
+##
+##    run(handleRequest)
+##
+## **Warning:** The API of this module is unstable, and therefore is subject
+## to change.
+##
+## **Warning:** This module only supports the old asynchronous interface.
+## You may wish to use the `asynchttpserver <asynchttpserver.html>`_
+## instead for web applications.
+
+include "system/inclrtl"
+
+import sockets, strutils, os, strtabs, asyncio
+
+type
+  ScgiError* = object of IOError ## the exception that is raised, if a SCGI error occurs
+
+proc raiseScgiError*(msg: string) {.noreturn.} = 
+  ## raises an ScgiError exception with message `msg`.
+  var e: ref ScgiError
+  new(e)
+  e.msg = msg
+  raise e
+
+proc parseWord(inp: string, outp: var string, start: int): int = 
+  result = start
+  while inp[result] != '\0': inc(result)
+  outp = substr(inp, start, result-1)
+
+proc parseHeaders(s: string, L: int): StringTableRef = 
+  result = newStringTable()
+  var i = 0
+  while i < L:
+    var key, val: string
+    i = parseWord(s, key, i)+1
+    i = parseWord(s, val, i)+1
+    result[key] = val
+  if s[i] == ',': inc(i)
+  else: raiseScgiError("',' after netstring expected")
+  
+proc recvChar(s: Socket): char = 
+  var c: char
+  if recv(s, addr(c), sizeof(c)) == sizeof(c): 
+    result = c
+  
+type
+  ScgiState* = object of RootObj ## SCGI state object
+    server: Socket
+    bufLen: int
+    client*: Socket ## the client socket to send data to
+    headers*: StringTableRef ## the parsed headers
+    input*: string  ## the input buffer
+  
+  
+  # Async
+  
+  ClientMode = enum
+    ClientReadChar, ClientReadHeaders, ClientReadContent
+  
+  AsyncClient = ref object
+    c: AsyncSocket
+    mode: ClientMode
+    dataLen: int
+    headers: StringTableRef ## the parsed headers
+    input: string  ## the input buffer
+  
+  AsyncScgiStateObj = object
+    handleRequest: proc (client: AsyncSocket, 
+                         input: string,
+                         headers: StringTableRef) {.closure, gcsafe.}
+    asyncServer: AsyncSocket
+    disp: Dispatcher
+  AsyncScgiState* = ref AsyncScgiStateObj
+
+{.deprecated: [EScgi: ScgiError, TScgiState: ScgiState,
+   PAsyncScgiState: AsyncScgiState, scgiError: raiseScgiError].}
+
+proc recvBuffer(s: var ScgiState, L: int) =
+  if L > s.bufLen: 
+    s.bufLen = L
+    s.input = newString(L)
+  if L > 0 and recv(s.client, cstring(s.input), L) != L: 
+    raiseScgiError("could not read all data")
+  setLen(s.input, L)
+  
+proc open*(s: var ScgiState, port = Port(4000), address = "127.0.0.1",
+           reuseAddr = false) = 
+  ## opens a connection.
+  s.bufLen = 4000
+  s.input = newString(s.bufLen) # will be reused
+  
+  s.server = socket()
+  if s.server == invalidSocket: raiseOSError(osLastError())
+  new(s.client) # Initialise s.client for `next`
+  if s.server == invalidSocket: raiseScgiError("could not open socket")
+  #s.server.connect(connectionName, port)
+  if reuseAddr:
+    s.server.setSockOpt(OptReuseAddr, true)
+  bindAddr(s.server, port, address)
+  listen(s.server)
+  
+proc close*(s: var ScgiState) = 
+  ## closes the connection.
+  s.server.close()
+
+proc next*(s: var ScgiState, timeout: int = -1): bool = 
+  ## proceed to the first/next request. Waits ``timeout`` milliseconds for a
+  ## request, if ``timeout`` is `-1` then this function will never time out.
+  ## Returns `true` if a new request has been processed.
+  var rsocks = @[s.server]
+  if select(rsocks, timeout) == 1 and rsocks.len == 1:
+    new(s.client)
+    accept(s.server, s.client)
+    var L = 0
+    while true:
+      var d = s.client.recvChar()
+      if d == '\0':
+        s.client.close()
+        return false
+      if d notin strutils.Digits: 
+        if d != ':': raiseScgiError("':' after length expected")
+        break
+      L = L * 10 + ord(d) - ord('0')  
+    recvBuffer(s, L+1)
+    s.headers = parseHeaders(s.input, L)
+    if s.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
+    L = parseInt(s.headers["CONTENT_LENGTH"])
+    recvBuffer(s, L)
+    return true
+  
+proc writeStatusOkTextContent*(c: Socket, contentType = "text/html") = 
+  ## sends the following string to the socket `c`::
+  ##
+  ##   Status: 200 OK\r\LContent-Type: text/html\r\L\r\L
+  ##
+  ## You should send this before sending your HTML page, for example.
+  c.send("Status: 200 OK\r\L" &
+         "Content-Type: $1\r\L\r\L" % contentType)
+
+proc run*(handleRequest: proc (client: Socket, input: string, 
+                               headers: StringTableRef): bool {.nimcall,gcsafe.},
+          port = Port(4000)) = 
+  ## encapsulates the SCGI object and main loop.
+  var s: ScgiState
+  s.open(port)
+  var stop = false
+  while not stop:
+    if next(s):
+      stop = handleRequest(s.client, s.input, s.headers)
+      s.client.close()
+  s.close()
+
+# -- AsyncIO start
+
+proc recvBufferAsync(client: AsyncClient, L: int): ReadLineResult =
+  result = ReadPartialLine
+  var data = ""
+  if L < 1:
+    raiseScgiError("Cannot read negative or zero length: " & $L)
+  let ret = recvAsync(client.c, data, L)
+  if ret == 0 and data == "":
+    client.c.close()
+    return ReadDisconnected
+  if ret == -1:
+    return ReadNone # No more data available
+  client.input.add(data)
+  if ret == L:
+    return ReadFullLine
+
+proc checkCloseSocket(client: AsyncClient) =
+  if not client.c.isClosed:
+    if client.c.isSendDataBuffered:
+      client.c.setHandleWrite do (s: AsyncSocket):
+        if not s.isClosed and not s.isSendDataBuffered:
+          s.close()
+          s.delHandleWrite()
+    else: client.c.close()
+    
+proc handleClientRead(client: AsyncClient, s: AsyncScgiState) =
+  case client.mode
+  of ClientReadChar:
+    while true:
+      var d = ""
+      let ret = client.c.recvAsync(d, 1)
+      if d == "" and ret == 0:
+        # Disconnected
+        client.c.close()
+        return
+      if ret == -1:
+        return # No more data available
+      if d[0] notin strutils.Digits:
+        if d[0] != ':': raiseScgiError("':' after length expected")
+        break
+      client.dataLen = client.dataLen * 10 + ord(d[0]) - ord('0')
+    client.mode = ClientReadHeaders
+    handleClientRead(client, s) # Allow progression
+  of ClientReadHeaders:
+    let ret = recvBufferAsync(client, (client.dataLen+1)-client.input.len)
+    case ret
+    of ReadFullLine:
+      client.headers = parseHeaders(client.input, client.input.len-1)
+      if client.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected")
+      client.input = "" # For next part
+      
+      let contentLen = parseInt(client.headers["CONTENT_LENGTH"])
+      if contentLen > 0:
+        client.mode = ClientReadContent
+      else:
+        s.handleRequest(client.c, client.input, client.headers)
+        checkCloseSocket(client)
+    of ReadPartialLine, ReadDisconnected, ReadNone: return
+  of ClientReadContent:
+    let L = parseInt(client.headers["CONTENT_LENGTH"])-client.input.len
+    if L > 0:
+      let ret = recvBufferAsync(client, L)
+      case ret
+      of ReadFullLine:
+        s.handleRequest(client.c, client.input, client.headers)
+        checkCloseSocket(client)
+      of ReadPartialLine, ReadDisconnected, ReadNone: return
+    else:
+      s.handleRequest(client.c, client.input, client.headers)
+      checkCloseSocket(client)
+
+proc handleAccept(sock: AsyncSocket, s: AsyncScgiState) =
+  var client: AsyncSocket
+  new(client)
+  accept(s.asyncServer, client)
+  var asyncClient = AsyncClient(c: client, mode: ClientReadChar, dataLen: 0,
+                                 headers: newStringTable(), input: "")
+  client.handleRead = 
+    proc (sock: AsyncSocket) =
+      handleClientRead(asyncClient, s)
+  s.disp.register(client)
+
+proc open*(handleRequest: proc (client: AsyncSocket, 
+                                input: string, headers: StringTableRef) {.
+                                closure, gcsafe.},
+           port = Port(4000), address = "127.0.0.1",
+           reuseAddr = false): AsyncScgiState =
+  ## Creates an ``AsyncScgiState`` object which serves as a SCGI server.
+  ##
+  ## After the execution of ``handleRequest`` the client socket will be closed
+  ## automatically unless it has already been closed.
+  var cres: AsyncScgiState
+  new(cres)
+  cres.asyncServer = asyncSocket()
+  cres.asyncServer.handleAccept = proc (s: AsyncSocket) = handleAccept(s, cres)
+  if reuseAddr:
+    cres.asyncServer.setSockOpt(OptReuseAddr, true)
+  bindAddr(cres.asyncServer, port, address)
+  listen(cres.asyncServer)
+  cres.handleRequest = handleRequest
+  result = cres
+
+proc register*(d: Dispatcher, s: AsyncScgiState): Delegate {.discardable.} =
+  ## Registers ``s`` with dispatcher ``d``.
+  result = d.register(s.asyncServer)
+  s.disp = d
+
+proc close*(s: AsyncScgiState) =
+  ## Closes the ``AsyncScgiState``.
+  s.asyncServer.close()
+
+when false:
+  var counter = 0
+  proc handleRequest(client: Socket, input: string, 
+                     headers: StringTableRef): bool {.procvar.} =
+    inc(counter)
+    client.writeStatusOkTextContent()
+    client.send("Hello for the $#th time." % $counter & "\c\L")
+    return false # do not stop processing
+
+  run(handleRequest)
+
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
new file mode 100644
index 000000000..6901ecf58
--- /dev/null
+++ b/lib/pure/selectors.nim
@@ -0,0 +1,323 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# TODO: Docs.
+
+import tables, os, unsigned, hashes
+
+when defined(linux): 
+  import posix, epoll
+elif defined(windows): 
+  import winlean
+else: 
+  import posix
+
+proc hash*(x: SocketHandle): THash {.borrow.}
+proc `$`*(x: SocketHandle): string {.borrow.}
+
+type
+  Event* = enum
+    EvRead, EvWrite, EvError
+
+  SelectorKey* = ref object
+    fd*: SocketHandle
+    events*: set[Event] ## The events which ``fd`` listens for.
+    data*: RootRef ## User object.
+
+  ReadyInfo* = tuple[key: SelectorKey, events: set[Event]]
+
+when defined(nimdoc):
+  type
+    Selector* = ref object
+      ## An object which holds file descriptors to be checked for read/write
+      ## status.
+      fds: Table[SocketHandle, SelectorKey]
+
+  proc register*(s: Selector, fd: SocketHandle, events: set[Event],
+                 data: RootRef): SelectorKey {.discardable.} =
+    ## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent
+    ## ``events``.
+
+  proc update*(s: Selector, fd: SocketHandle,
+               events: set[Event]): SelectorKey {.discardable.} =
+    ## Updates the events which ``fd`` wants notifications for.
+
+  proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
+    ## Unregisters file descriptor ``fd`` from selector ``s``.
+
+  proc close*(s: Selector) =
+    ## Closes the selector
+
+  proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
+    ## The ``events`` field of the returned ``key`` contains the original events
+    ## for which the ``fd`` was bound. This is contrary to the ``events`` field
+    ## of the ``TReadyInfo`` tuple which determines which events are ready
+    ## on the ``fd``.
+
+  proc newSelector*(): Selector =
+    ## Creates a new selector
+
+  proc contains*(s: Selector, fd: SocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+
+  proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
+    ## Retrieves the selector key for ``fd``.
+
+
+elif defined(linux):
+  type
+    Selector* = ref object
+      epollFD: cint
+      events: array[64, epoll_event]
+      fds: Table[SocketHandle, SelectorKey]
+  
+  proc createEventStruct(events: set[Event], fd: SocketHandle): epoll_event =
+    if EvRead in events:
+      result.events = EPOLLIN
+    if EvWrite in events:
+      result.events = result.events or EPOLLOUT
+    result.events = result.events or EPOLLRDHUP
+    result.data.fd = fd.cint
+  
+  proc register*(s: Selector, fd: SocketHandle, events: set[Event],
+      data: RootRef): SelectorKey {.discardable.} =
+    var event = createEventStruct(events, fd)
+    if events != {}:
+      if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
+        raiseOSError(osLastError())
+
+    var key = SelectorKey(fd: fd, events: events, data: data)
+  
+    s.fds[fd] = key
+    result = key
+  
+  proc update*(s: Selector, fd: SocketHandle,
+      events: set[Event]): SelectorKey {.discardable.} =
+    if s.fds[fd].events != events:
+      if events == {}:
+        # This fd is idle -- it should not be registered to epoll.
+        # But it should remain a part of this selector instance.
+        # This is to prevent epoll_wait from returning immediately
+        # because its got fds which are waiting for no events and
+        # are therefore constantly ready. (leading to 100% CPU usage).
+        if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
+          raiseOSError(osLastError())
+        s.fds[fd].events = events
+      else:
+        var event = createEventStruct(events, fd)
+        if s.fds[fd].events == {}:
+          # This fd is idle. It's not a member of this epoll instance and must
+          # be re-registered.
+          if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0:
+            raiseOSError(osLastError())
+        else:
+          if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
+            raiseOSError(osLastError())
+        s.fds[fd].events = events
+      
+      result = s.fds[fd]
+  
+  proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
+    if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0:
+      let err = osLastError()
+      if err.cint notin {ENOENT, EBADF}: # TODO: Why do we sometimes get an EBADF? Is this normal?
+        raiseOSError(err)
+    result = s.fds[fd]
+    s.fds.del(fd)
+
+  proc close*(s: Selector) =
+    if s.epollFD.close() != 0: raiseOSError(osLastError())
+    dealloc(addr s.events) # TODO: Test this
+  
+  proc epollHasFd(s: Selector, fd: SocketHandle): bool =
+    result = true
+    var event = createEventStruct(s.fds[fd].events, fd)
+    if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0:
+      let err = osLastError()
+      if err.cint in {ENOENT, EBADF}:
+        return false
+      raiseOSError(osLastError())
+  
+  proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
+    ##
+    ## The ``events`` field of the returned ``key`` contains the original events
+    ## for which the ``fd`` was bound. This is contrary to the ``events`` field
+    ## of the ``TReadyInfo`` tuple which determines which events are ready
+    ## on the ``fd``.
+    result = @[]
+    let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint)
+    if evNum < 0:
+      let err = osLastError()
+      if err.cint == EINTR:
+        return @[]
+      raiseOSError(osLastError())
+    if evNum == 0: return @[]
+    for i in 0 .. <evNum:
+      let fd = s.events[i].data.fd.SocketHandle
+    
+      var evSet: set[Event] = {}
+      if (s.events[i].events and EPOLLERR) != 0 or (s.events[i].events and EPOLLHUP) != 0: evSet = evSet + {EvError}
+      if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead}
+      if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite}
+      let selectorKey = s.fds[fd]
+      assert selectorKey != nil
+      result.add((selectorKey, evSet))
+
+      #echo("Epoll: ", result[i].key.fd, " ", result[i].events, " ", result[i].key.events)
+  
+  proc newSelector*(): Selector =
+    new result
+    result.epollFD = epoll_create(64)
+    #result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64))
+    result.fds = initTable[SocketHandle, SelectorKey]()
+    if result.epollFD < 0:
+      raiseOSError(osLastError())
+
+  proc contains*(s: Selector, fd: SocketHandle): bool =
+    ## Determines whether selector contains a file descriptor.
+    if s.fds.hasKey(fd):
+      # Ensure the underlying epoll instance still contains this fd.
+      if s.fds[fd].events != {}:
+        result = epollHasFd(s, fd)
+      else:
+        result = true
+    else:
+      return false
+
+  proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
+    ## Retrieves the selector key for ``fd``.
+    return s.fds[fd]
+
+elif not defined(nimdoc):
+  # TODO: kqueue for bsd/mac os x.
+  type
+    Selector* = ref object
+      fds: Table[SocketHandle, SelectorKey]
+
+  proc register*(s: Selector, fd: SocketHandle, events: set[Event],
+      data: RootRef): SelectorKey {.discardable.} =
+    if s.fds.hasKey(fd):
+      raise newException(ValueError, "File descriptor already exists.")
+    var sk = SelectorKey(fd: fd, events: events, data: data)
+    s.fds[fd] = sk
+    result = sk
+
+  proc update*(s: Selector, fd: SocketHandle,
+      events: set[Event]): SelectorKey {.discardable.} =
+    if not s.fds.hasKey(fd):
+      raise newException(ValueError, "File descriptor not found.")
+
+    s.fds[fd].events = events
+    result = s.fds[fd]
+
+  proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} =
+    result = s.fds[fd]
+    s.fds.del(fd)
+
+  proc close*(s: Selector) = discard
+
+  proc timeValFromMilliseconds(timeout: int): TimeVal =
+    if timeout != -1:
+      var seconds = timeout div 1000
+      result.tv_sec = seconds.int32
+      result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+  proc createFdSet(rd, wr: var TFdSet, fds: Table[SocketHandle, SelectorKey],
+      m: var int) =
+    FD_ZERO(rd); FD_ZERO(wr)
+    for k, v in pairs(fds):
+      if EvRead in v.events: 
+        m = max(m, int(k))
+        FD_SET(k, rd)
+      if EvWrite in v.events:
+        m = max(m, int(k))
+        FD_SET(k, wr)
+     
+  proc getReadyFDs(rd, wr: var TFdSet, fds: Table[SocketHandle, SelectorKey]):
+      seq[ReadyInfo] =
+    result = @[]
+    for k, v in pairs(fds):
+      var events: set[Event] = {}
+      if FD_ISSET(k, rd) != 0'i32:
+        events = events + {EvRead}
+      if FD_ISSET(k, wr) != 0'i32:
+        events = events + {EvWrite}
+      result.add((v, events))
+
+  proc select(fds: Table[SocketHandle, SelectorKey], timeout = 500):
+    seq[ReadyInfo] =
+    var tv {.noInit.}: TimeVal = timeValFromMilliseconds(timeout)
+    
+    var rd, wr: TFdSet
+    var m = 0
+    createFdSet(rd, wr, fds, m)
+    
+    var retCode = 0
+    if timeout != -1:
+      retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
+    else:
+      retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
+    
+    if retCode < 0:
+      raiseOSError(osLastError())
+    elif retCode == 0:
+      return @[]
+    else:
+      return getReadyFDs(rd, wr, fds)
+
+  proc select*(s: Selector, timeout: int): seq[ReadyInfo] =
+    result = select(s.fds, timeout)
+
+  proc newSelector*(): Selector =
+    new result
+    result.fds = initTable[SocketHandle, SelectorKey]()
+
+  proc contains*(s: Selector, fd: SocketHandle): bool =
+    return s.fds.hasKey(fd)
+
+  proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey =
+    return s.fds[fd]
+
+proc contains*(s: Selector, key: SelectorKey): bool =
+  ## Determines whether selector contains this selector key. More accurate
+  ## than checking if the file descriptor is in the selector because it
+  ## ensures that the keys are equal. File descriptors may not always be
+  ## unique especially when an fd is closed and then a new one is opened,
+  ## the new one may have the same value.
+  return key.fd in s and s.fds[key.fd] == key
+
+{.deprecated: [TEvent: Event, PSelectorKey: SelectorKey,
+   TReadyInfo: ReadyInfo, PSelector: Selector].}
+
+
+when not defined(testing) and isMainModule and not defined(nimdoc):
+  # Select()
+  import sockets
+  type
+    SockWrapper = ref object of RootObj
+      sock: Socket
+  
+  var sock = socket()
+  if sock == sockets.invalidSocket: raiseOSError(osLastError())
+  #sock.setBlocking(false)
+  sock.connect("irc.freenode.net", Port(6667))
+  
+  var selector = newSelector()
+  var data = SockWrapper(sock: sock)
+  let key = selector.register(sock.getFD, {EvWrite}, data)
+  var i = 0
+  while true:
+    let ready = selector.select(1000)
+    echo ready.len
+    if ready.len > 0: echo ready[0].events
+    i.inc
+    if i == 6:
+      assert selector.unregister(sock.getFD).fd == sock.getFD
+      selector.close()
+      break
diff --git a/lib/pure/sexp.nim b/lib/pure/sexp.nim
new file mode 100644
index 000000000..3c9fbc150
--- /dev/null
+++ b/lib/pure/sexp.nim
@@ -0,0 +1,697 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  hashes, strutils, lexbase, streams, unicode, macros
+
+type
+  SexpEventKind* = enum  ## enumeration of all events that may occur when parsing
+    sexpError,           ## an error occurred during parsing
+    sexpEof,             ## end of file reached
+    sexpString,          ## a string literal
+    sexpSymbol,          ## a symbol
+    sexpInt,             ## an integer literal
+    sexpFloat,           ## a float literal
+    sexpNil,             ## the value ``nil``
+    sexpDot,             ## the dot to separate car/cdr
+    sexpListStart,       ## start of a list: the ``(`` token
+    sexpListEnd,         ## end of a list: the ``)`` token
+
+  TTokKind = enum        # must be synchronized with SexpEventKind!
+    tkError,
+    tkEof,
+    tkString,
+    tkSymbol,
+    tkInt,
+    tkFloat,
+    tkNil,
+    tkDot,
+    tkParensLe,
+    tkParensRi
+    tkSpace
+
+  SexpError* = enum        ## enumeration that lists all errors that can occur
+    errNone,               ## no error
+    errInvalidToken,       ## invalid token
+    errParensRiExpected,    ## ``)`` expected
+    errQuoteExpected,      ## ``"`` expected
+    errEofExpected,        ## EOF expected
+
+  SexpParser* = object of BaseLexer ## the parser object.
+    a: string
+    tok: TTokKind
+    kind: SexpEventKind
+    err: SexpError
+
+const
+  errorMessages: array [SexpError, string] = [
+    "no error",
+    "invalid token",
+    "')' expected",
+    "'\"' or \"'\" expected",
+    "EOF expected",
+  ]
+  tokToStr: array [TTokKind, string] = [
+    "invalid token",
+    "EOF",
+    "string literal",
+    "symbol",
+    "int literal",
+    "float literal",
+    "nil",
+    ".",
+    "(", ")", "space"
+  ]
+
+proc close*(my: var SexpParser) {.inline.} =
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+proc str*(my: SexpParser): string {.inline.} =
+  ## returns the character data for the events: ``sexpInt``, ``sexpFloat``,
+  ## ``sexpString``
+  assert(my.kind in {sexpInt, sexpFloat, sexpString})
+  result = my.a
+
+proc getInt*(my: SexpParser): BiggestInt {.inline.} =
+  ## returns the number for the event: ``sexpInt``
+  assert(my.kind == sexpInt)
+  result = parseBiggestInt(my.a)
+
+proc getFloat*(my: SexpParser): float {.inline.} =
+  ## returns the number for the event: ``sexpFloat``
+  assert(my.kind == sexpFloat)
+  result = parseFloat(my.a)
+
+proc kind*(my: SexpParser): SexpEventKind {.inline.} =
+  ## returns the current event type for the SEXP parser
+  result = my.kind
+
+proc getColumn*(my: SexpParser): int {.inline.} =
+  ## get the current column the parser has arrived at.
+  result = getColNumber(my, my.bufpos)
+
+proc getLine*(my: SexpParser): int {.inline.} =
+  ## get the current line the parser has arrived at.
+  result = my.lineNumber
+
+proc errorMsg*(my: SexpParser): string =
+  ## returns a helpful error message for the event ``sexpError``
+  assert(my.kind == sexpError)
+  result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), errorMessages[my.err]]
+
+proc errorMsgExpected*(my: SexpParser, e: string): string =
+  ## returns an error message "`e` expected" in the same format as the
+  ## other error messages
+  result = "($1, $2) Error: $3" % [$getLine(my), $getColumn(my), e & " expected"]
+
+proc handleHexChar(c: char, x: var int): bool =
+  result = true # Success
+  case c
+  of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
+  of 'a'..'f': x = (x shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
+  else: result = false # error
+
+proc parseString(my: var SexpParser): TTokKind =
+  result = tkString
+  var pos = my.bufpos + 1
+  var buf = my.buf
+  while true:
+    case buf[pos]
+    of '\0':
+      my.err = errQuoteExpected
+      result = tkError
+      break
+    of '"':
+      inc(pos)
+      break
+    of '\\':
+      case buf[pos+1]
+      of '\\', '"', '\'', '/':
+        add(my.a, buf[pos+1])
+        inc(pos, 2)
+      of 'b':
+        add(my.a, '\b')
+        inc(pos, 2)
+      of 'f':
+        add(my.a, '\f')
+        inc(pos, 2)
+      of 'n':
+        add(my.a, '\L')
+        inc(pos, 2)
+      of 'r':
+        add(my.a, '\C')
+        inc(pos, 2)
+      of 't':
+        add(my.a, '\t')
+        inc(pos, 2)
+      of 'u':
+        inc(pos, 2)
+        var r: int
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        if handleHexChar(buf[pos], r): inc(pos)
+        add(my.a, toUTF8(Rune(r)))
+      else:
+        # don't bother with the error
+        add(my.a, buf[pos])
+        inc(pos)
+    of '\c':
+      pos = lexbase.handleCR(my, pos)
+      buf = my.buf
+      add(my.a, '\c')
+    of '\L':
+      pos = lexbase.handleLF(my, pos)
+      buf = my.buf
+      add(my.a, '\L')
+    else:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos # store back
+
+proc parseNumber(my: var SexpParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] == '-':
+    add(my.a, '-')
+    inc(pos)
+  if buf[pos] == '.':
+    add(my.a, "0.")
+    inc(pos)
+  else:
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+    if buf[pos] == '.':
+      add(my.a, '.')
+      inc(pos)
+  # digits after the dot:
+  while buf[pos] in Digits:
+    add(my.a, buf[pos])
+    inc(pos)
+  if buf[pos] in {'E', 'e'}:
+    add(my.a, buf[pos])
+    inc(pos)
+    if buf[pos] in {'+', '-'}:
+      add(my.a, buf[pos])
+      inc(pos)
+    while buf[pos] in Digits:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc parseSymbol(my: var SexpParser) =
+  var pos = my.bufpos
+  var buf = my.buf
+  if buf[pos] in IdentStartChars:
+    while buf[pos] in IdentChars:
+      add(my.a, buf[pos])
+      inc(pos)
+  my.bufpos = pos
+
+proc getTok(my: var SexpParser): TTokKind =
+  setLen(my.a, 0)
+  case my.buf[my.bufpos]
+  of '-', '0'..'9': # numbers that start with a . are not parsed
+                    # correctly.
+    parseNumber(my)
+    if {'.', 'e', 'E'} in my.a:
+      result = tkFloat
+    else:
+      result = tkInt
+  of '"': #" # gotta fix nim-mode
+    result = parseString(my)
+  of '(':
+    inc(my.bufpos)
+    result = tkParensLe
+  of ')':
+    inc(my.bufpos)
+    result = tkParensRi
+  of '\0':
+    result = tkEof
+  of 'a'..'z', 'A'..'Z', '_':
+    parseSymbol(my)
+    if my.a == "nil":
+      result = tkNil
+    else:
+      result = tkSymbol
+  of ' ':
+    result = tkSpace
+    inc(my.bufpos)
+  of '.':
+    result = tkDot
+    inc(my.bufpos)
+  else:
+    inc(my.bufpos)
+    result = tkError
+  my.tok = result
+
+# ------------- higher level interface ---------------------------------------
+
+type
+  SexpNodeKind* = enum ## possible SEXP node types
+    SNil,
+    SInt,
+    SFloat,
+    SString,
+    SSymbol,
+    SList,
+    SCons
+
+  SexpNode* = ref SexpNodeObj ## SEXP node
+  SexpNodeObj* {.acyclic.} = object
+    case kind*: SexpNodeKind
+    of SString:
+      str*: string
+    of SSymbol:
+      symbol*: string
+    of SInt:
+      num*: BiggestInt
+    of SFloat:
+      fnum*: float
+    of SList:
+      elems*: seq[SexpNode]
+    of SCons:
+      car: SexpNode
+      cdr: SexpNode
+    of SNil:
+      discard
+
+  Cons = tuple[car: SexpNode, cdr: SexpNode]
+
+  SexpParsingError* = object of ValueError ## is raised for a SEXP error
+
+proc raiseParseErr*(p: SexpParser, msg: string) {.noinline, noreturn.} =
+  ## raises an `ESexpParsingError` exception.
+  raise newException(SexpParsingError, errorMsgExpected(p, msg))
+
+proc newSString*(s: string): SexpNode {.procvar.}=
+  ## Creates a new `SString SexpNode`.
+  new(result)
+  result.kind = SString
+  result.str = s
+
+proc newSStringMove(s: string): SexpNode =
+  new(result)
+  result.kind = SString
+  shallowCopy(result.str, s)
+
+proc newSInt*(n: BiggestInt): SexpNode {.procvar.} =
+  ## Creates a new `SInt SexpNode`.
+  new(result)
+  result.kind = SInt
+  result.num  = n
+
+proc newSFloat*(n: float): SexpNode {.procvar.} =
+  ## Creates a new `SFloat SexpNode`.
+  new(result)
+  result.kind = SFloat
+  result.fnum  = n
+
+proc newSNil*(): SexpNode {.procvar.} =
+  ## Creates a new `SNil SexpNode`.
+  new(result)
+
+proc newSCons*(car, cdr: SexpNode): SexpNode {.procvar.} =
+  ## Creates a new `SCons SexpNode`
+  new(result)
+  result.kind = SCons
+  result.car = car
+  result.cdr = cdr
+
+proc newSList*(): SexpNode {.procvar.} =
+  ## Creates a new `SList SexpNode`
+  new(result)
+  result.kind = SList
+  result.elems = @[]
+
+proc newSSymbol*(s: string): SexpNode {.procvar.} =
+  new(result)
+  result.kind = SSymbol
+  result.symbol = s
+
+proc newSSymbolMove(s: string): SexpNode =
+  new(result)
+  result.kind = SSymbol
+  shallowCopy(result.symbol, s)
+
+proc getStr*(n: SexpNode, default: string = ""): string =
+  ## Retrieves the string value of a `SString SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SString``.
+  if n.kind != SString: return default
+  else: return n.str
+
+proc getNum*(n: SexpNode, default: BiggestInt = 0): BiggestInt =
+  ## Retrieves the int value of a `SInt SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SInt``.
+  if n.kind != SInt: return default
+  else: return n.num
+
+proc getFNum*(n: SexpNode, default: float = 0.0): float =
+  ## Retrieves the float value of a `SFloat SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SFloat``.
+  if n.kind != SFloat: return default
+  else: return n.fnum
+
+proc getSymbol*(n: SexpNode, default: string = ""): string =
+  ## Retrieves the int value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind != SSymbol: return default
+  else: return n.symbol
+
+proc getElems*(n: SexpNode, default: seq[SexpNode] = @[]): seq[SexpNode] =
+  ## Retrieves the int value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind == SNil: return @[]
+  elif n.kind != SList: return default
+  else: return n.elems
+
+proc getCons*(n: SexpNode, defaults: Cons = (newSNil(), newSNil())): Cons =
+  ## Retrieves the cons value of a `SList SexpNode`.
+  ##
+  ## Returns ``default`` if ``n`` is not a ``SList``.
+  if n.kind == SCons: return (n.car, n.cdr)
+  elif n.kind == SList: return (n.elems[0], n.elems[1])
+  else: return defaults
+
+proc sexp*(s: string): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SString SexpNode`.
+  new(result)
+  result.kind = SString
+  result.str = s
+
+proc sexp*(n: BiggestInt): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SInt SexpNode`.
+  new(result)
+  result.kind = SInt
+  result.num  = n
+
+proc sexp*(n: float): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SFloat SexpNode`.
+  new(result)
+  result.kind = SFloat
+  result.fnum  = n
+
+proc sexp*(b: bool): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SSymbol
+  ## SexpNode` with value t or `SNil SexpNode`.
+  new(result)
+  if b:
+    result.kind = SSymbol
+    result.symbol = "t"
+  else:
+    result.kind = SNil
+
+proc sexp*(elements: openArray[SexpNode]): SexpNode =
+  ## Generic constructor for SEXP data. Creates a new `SList SexpNode`
+  new(result)
+  result.kind = SList
+  newSeq(result.elems, elements.len)
+  for i, p in pairs(elements): result.elems[i] = p
+
+proc sexp*(s: SexpNode): SexpNode =
+  result = s
+
+proc toSexp(x: NimNode): NimNode {.compiletime.} =
+  case x.kind
+  of nnkBracket:
+    result = newNimNode(nnkBracket)
+    for i in 0 .. <x.len:
+      result.add(toSexp(x[i]))
+
+  else:
+    result = x
+
+  result = prefix(result, "sexp")
+
+macro convertSexp*(x: expr): expr =
+  ## Convert an expression to a SexpNode directly, without having to specify
+  ## `%` for every element.
+  result = toSexp(x)
+
+proc `==`* (a,b: SexpNode): bool =
+  ## Check two nodes for equality
+  if a.isNil:
+    if b.isNil: return true
+    return false
+  elif b.isNil or a.kind != b.kind:
+    return false
+  else:
+    return case a.kind
+    of SString:
+      a.str == b.str
+    of SInt:
+      a.num == b.num
+    of SFloat:
+      a.fnum == b.fnum
+    of SNil:
+      true
+    of SList:
+      a.elems == b.elems
+    of SSymbol:
+      a.symbol == b.symbol
+    of SCons:
+      a.car == b.car and a.cdr == b.cdr
+
+proc hash* (n:SexpNode): THash =
+  ## Compute the hash for a SEXP node
+  case n.kind
+  of SList:
+    result = hash(n.elems)
+  of SInt:
+    result = hash(n.num)
+  of SFloat:
+    result = hash(n.fnum)
+  of SString:
+    result = hash(n.str)
+  of SNil:
+    result = hash(0)
+  of SSymbol:
+    result = hash(n.symbol)
+  of SCons:
+    result = hash(n.car) !& hash(n.cdr)
+
+proc len*(n: SexpNode): int =
+  ## If `n` is a `SList`, it returns the number of elements.
+  ## If `n` is a `JObject`, it returns the number of pairs.
+  ## Else it returns 0.
+  case n.kind
+  of SList: result = n.elems.len
+  else: discard
+
+proc `[]`*(node: SexpNode, index: int): SexpNode =
+  ## Gets the node at `index` in a List. Result is undefined if `index`
+  ## is out of bounds
+  assert(not isNil(node))
+  assert(node.kind == SList)
+  return node.elems[index]
+
+proc add*(father, child: SexpNode) =
+  ## Adds `child` to a SList node `father`.
+  assert father.kind == SList
+  father.elems.add(child)
+
+# ------------- pretty printing ----------------------------------------------
+
+proc indent(s: var string, i: int) =
+  s.add(spaces(i))
+
+proc newIndent(curr, indent: int, ml: bool): int =
+  if ml: return curr + indent
+  else: return indent
+
+proc nl(s: var string, ml: bool) =
+  if ml: s.add("\n")
+
+proc escapeJson*(s: string): string =
+  ## Converts a string `s` to its JSON representation.
+  result = newStringOfCap(s.len + s.len shr 3)
+  result.add("\"")
+  for x in runes(s):
+    var r = int(x)
+    if r >= 32 and r <= 127:
+      var c = chr(r)
+      case c
+      of '"': result.add("\\\"") #" # gotta fix nim-mode
+      of '\\': result.add("\\\\")
+      else: result.add(c)
+    else:
+      result.add("\\u")
+      result.add(toHex(r, 4))
+  result.add("\"")
+
+proc copy*(p: SexpNode): SexpNode =
+  ## Performs a deep copy of `a`.
+  case p.kind
+  of SString:
+    result = newSString(p.str)
+  of SInt:
+    result = newSInt(p.num)
+  of SFloat:
+    result = newSFloat(p.fnum)
+  of SNil:
+    result = newSNil()
+  of SSymbol:
+    result = newSSymbol(p.symbol)
+  of SList:
+    result = newSList()
+    for i in items(p.elems):
+      result.elems.add(copy(i))
+  of SCons:
+    result = newSCons(copy(p.car), copy(p.cdr))
+
+proc toPretty(result: var string, node: SexpNode, indent = 2, ml = true,
+              lstArr = false, currIndent = 0) =
+  case node.kind
+  of SString:
+    if lstArr: result.indent(currIndent)
+    result.add(escapeJson(node.str))
+  of SInt:
+    if lstArr: result.indent(currIndent)
+    result.add($node.num)
+  of SFloat:
+    if lstArr: result.indent(currIndent)
+    result.add($node.fnum)
+  of SNil:
+    if lstArr: result.indent(currIndent)
+    result.add("nil")
+  of SSymbol:
+    if lstArr: result.indent(currIndent)
+    result.add($node.symbol)
+  of SList:
+    if lstArr: result.indent(currIndent)
+    if len(node.elems) != 0:
+      result.add("(")
+      result.nl(ml)
+      for i in 0..len(node.elems)-1:
+        if i > 0:
+          result.add(" ")
+          result.nl(ml) # New Line
+        toPretty(result, node.elems[i], indent, ml,
+            true, newIndent(currIndent, indent, ml))
+      result.nl(ml)
+      result.indent(currIndent)
+      result.add(")")
+    else: result.add("nil")
+  of SCons:
+    if lstArr: result.indent(currIndent)
+    result.add("(")
+    toPretty(result, node.car, indent, ml,
+        true, newIndent(currIndent, indent, ml))
+    result.add(" . ")
+    toPretty(result, node.cdr, indent, ml,
+        true, newIndent(currIndent, indent, ml))
+    result.add(")")
+
+proc pretty*(node: SexpNode, indent = 2): string =
+  ## Converts `node` to its Sexp Representation, with indentation and
+  ## on multiple lines.
+  result = ""
+  toPretty(result, node, indent)
+
+proc `$`*(node: SexpNode): string =
+  ## Converts `node` to its SEXP Representation on one line.
+  result = ""
+  toPretty(result, node, 0, false)
+
+iterator items*(node: SexpNode): SexpNode =
+  ## Iterator for the items of `node`. `node` has to be a SList.
+  assert node.kind == SList
+  for i in items(node.elems):
+    yield i
+
+iterator mitems*(node: var SexpNode): var SexpNode =
+  ## Iterator for the items of `node`. `node` has to be a SList. Items can be
+  ## modified.
+  assert node.kind == SList
+  for i in mitems(node.elems):
+    yield i
+
+proc eat(p: var SexpParser, tok: TTokKind) =
+  if p.tok == tok: discard getTok(p)
+  else: raiseParseErr(p, tokToStr[tok])
+
+proc parseSexp(p: var SexpParser): SexpNode =
+  ## Parses SEXP from a SEXP Parser `p`.
+  case p.tok
+  of tkString:
+    # we capture 'p.a' here, so we need to give it a fresh buffer afterwards:
+    result = newSStringMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkInt:
+    result = newSInt(parseBiggestInt(p.a))
+    discard getTok(p)
+  of tkFloat:
+    result = newSFloat(parseFloat(p.a))
+    discard getTok(p)
+  of tkNil:
+    result = newSNil()
+    discard getTok(p)
+  of tkSymbol:
+    result = newSSymbolMove(p.a)
+    p.a = ""
+    discard getTok(p)
+  of tkParensLe:
+    result = newSList()
+    discard getTok(p)
+    while p.tok notin {tkParensRi, tkDot}:
+      result.add(parseSexp(p))
+      if p.tok != tkSpace: break
+      discard getTok(p)
+    if p.tok == tkDot:
+      eat(p, tkDot)
+      eat(p, tkSpace)
+      result.add(parseSexp(p))
+      result = newSCons(result[0], result[1])
+    eat(p, tkParensRi)
+  of tkSpace, tkDot, tkError, tkParensRi, tkEof:
+    raiseParseErr(p, "(")
+
+proc open*(my: var SexpParser, input: Stream) =
+  ## initializes the parser with an input stream.
+  lexbase.open(my, input)
+  my.kind = sexpError
+  my.a = ""
+
+proc parseSexp*(s: Stream): SexpNode =
+  ## Parses from a buffer `s` into a `SexpNode`.
+  var p: SexpParser
+  p.open(s)
+  discard getTok(p) # read first token
+  result = p.parseSexp()
+  p.close()
+
+proc parseSexp*(buffer: string): SexpNode =
+  ## Parses Sexp from `buffer`.
+  result = parseSexp(newStringStream(buffer))
+
+when isMainModule:
+  let testSexp = parseSexp("""(1 (98 2) nil (2) foobar "foo" 9.234)""")
+  assert(testSexp[0].getNum == 1)
+  assert(testSexp[1][0].getNum == 98)
+  assert(testSexp[2].getElems == @[])
+  assert(testSexp[4].getSymbol == "foobar")
+  assert(testSexp[5].getStr == "foo")
+
+  let alist = parseSexp("""((1 . 2) (2 . "foo"))""")
+  assert(alist[0].getCons.car.getNum == 1)
+  assert(alist[0].getCons.cdr.getNum == 2)
+  assert(alist[1].getCons.cdr.getStr == "foo")
+
+  # Generator:
+  var j = convertSexp([true, false, "foobar", [1, 2, "baz"]])
+  assert($j == """(t nil "foobar" (1 2 "baz"))""")
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
new file mode 100644
index 000000000..c1bc259a5
--- /dev/null
+++ b/lib/pure/smtp.nim
@@ -0,0 +1,277 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements the SMTP client protocol as specified by RFC 5321, 
+## this can be used to send mail to any SMTP Server.
+## 
+## This module also implements the protocol used to format messages, 
+## as specified by RFC 2822.
+## 
+## Example gmail use:
+## 
+## 
+## .. code-block:: Nim
+##   var msg = createMessage("Hello from Nim's SMTP", 
+##                           "Hello!.\n Is this awesome or what?", 
+##                           @["foo@gmail.com"])
+##   var smtp = connect("smtp.gmail.com", 465, true, true)
+##   smtp.auth("username", "password")
+##   smtp.sendmail("username@gmail.com", @["foo@gmail.com"], $msg)
+##   
+## 
+## For SSL support this module relies on OpenSSL. If you want to 
+## enable SSL, compile with ``-d:ssl``.
+
+import net, strutils, strtabs, base64, os
+import asyncnet, asyncdispatch
+
+type
+  Smtp* = object
+    sock: Socket
+    debug: bool
+  
+  Message* = object
+    msgTo: seq[string]
+    msgCc: seq[string]
+    msgSubject: string
+    msgOtherHeaders: StringTableRef
+    msgBody: string
+  
+  ReplyError* = object of IOError
+
+  AsyncSmtp* = ref object
+    sock: AsyncSocket
+    address: string
+    port: Port
+    useSsl: bool
+    debug: bool
+
+{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].}
+
+proc debugSend(smtp: Smtp, cmd: string) =
+  if smtp.debug:
+    echo("C:" & cmd)
+  smtp.sock.send(cmd)
+
+proc debugRecv(smtp: var Smtp): TaintedString =
+  var line = TaintedString""
+  smtp.sock.readLine(line)
+
+  if smtp.debug:
+    echo("S:" & line.string)
+  return line
+
+proc quitExcpt(smtp: Smtp, msg: string) =
+  smtp.debugSend("QUIT")
+  raise newException(ReplyError, msg)
+
+proc checkReply(smtp: var Smtp, reply: string) =
+  var line = smtp.debugRecv()
+  if not line.string.startswith(reply):
+    quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
+
+const compiledWithSsl = defined(ssl)
+
+when not defined(ssl):
+  type PSSLContext = ref object
+  let defaultSSLContext: PSSLContext = nil
+else:
+  let defaultSSLContext = newContext(verifyMode = CVerifyNone)
+
+proc connect*(address: string, port = Port(25), 
+              ssl = false, debug = false,
+              sslContext = defaultSSLContext): Smtp =
+  ## Establishes a connection with a SMTP server.
+  ## May fail with ReplyError or with a socket error.
+  result.sock = newSocket()
+  if ssl:
+    when compiledWithSsl:
+      sslContext.wrapSocket(result.sock)
+    else:
+      raise newException(ESystem, 
+                         "SMTP module compiled without SSL support")
+  result.sock.connect(address, port)
+  result.debug = debug
+  
+  result.checkReply("220")
+  result.debugSend("HELO " & address & "\c\L")
+  result.checkReply("250")
+
+proc auth*(smtp: var Smtp, username, password: string) =
+  ## Sends an AUTH command to the server to login as the `username` 
+  ## using `password`.
+  ## May fail with ReplyError.
+
+  smtp.debugSend("AUTH LOGIN\c\L")
+  smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:"
+                         # i.e "334 VXNlcm5hbWU6"
+  smtp.debugSend(encode(username) & "\c\L")
+  smtp.checkReply("334") # TODO: Same as above, only "Password:" (I think?)
+  
+  smtp.debugSend(encode(password) & "\c\L")
+  smtp.checkReply("235") # Check whether the authentification was successful.
+
+proc sendmail*(smtp: var Smtp, fromaddr: string,
+               toaddrs: seq[string], msg: string) =
+  ## Sends `msg` from `fromaddr` to `toaddr`. 
+  ## Messages may be formed using ``createMessage`` by converting the
+  ## Message into a string.
+
+  smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L")
+  smtp.checkReply("250")
+  for address in items(toaddrs):
+    smtp.debugSend("RCPT TO:<" & address & ">\c\L")
+    smtp.checkReply("250")
+  
+  # Send the message
+  smtp.debugSend("DATA " & "\c\L")
+  smtp.checkReply("354")
+  smtp.debugSend(msg & "\c\L")
+  smtp.debugSend(".\c\L")
+  smtp.checkReply("250")
+
+proc close*(smtp: Smtp) =
+  ## Disconnects from the SMTP server and closes the socket.
+  smtp.debugSend("QUIT\c\L")
+  smtp.sock.close()
+
+proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
+                otherHeaders: openarray[tuple[name, value: string]]): Message =
+  ## Creates a new MIME compliant message.
+  result.msgTo = mTo
+  result.msgCc = mCc
+  result.msgSubject = mSubject
+  result.msgBody = mBody
+  result.msgOtherHeaders = newStringTable()
+  for n, v in items(otherHeaders):
+    result.msgOtherHeaders[n] = v
+
+proc createMessage*(mSubject, mBody: string, mTo,
+                    mCc: seq[string] = @[]): Message =
+  ## Alternate version of the above.
+  result.msgTo = mTo
+  result.msgCc = mCc
+  result.msgSubject = mSubject
+  result.msgBody = mBody
+  result.msgOtherHeaders = newStringTable()
+
+proc `$`*(msg: Message): string =
+  ## stringify for ``Message``.
+  result = ""
+  if msg.msgTo.len() > 0:
+    result = "TO: " & msg.msgTo.join(", ") & "\c\L"
+  if msg.msgCc.len() > 0:
+    result.add("CC: " & msg.msgCc.join(", ") & "\c\L")
+  # TODO: Folding? i.e when a line is too long, shorten it...
+  result.add("Subject: " & msg.msgSubject & "\c\L")
+  for key, value in pairs(msg.msgOtherHeaders):
+    result.add(key & ": " & value & "\c\L")
+
+  result.add("\c\L")
+  result.add(msg.msgBody)
+  
+proc newAsyncSmtp*(address: string, port: Port, useSsl = false,
+                   sslContext = defaultSslContext): AsyncSmtp =
+  ## Creates a new ``AsyncSmtp`` instance.
+  new result
+  result.address = address
+  result.port = port
+  result.useSsl = useSsl
+
+  result.sock = newAsyncSocket()
+  if useSsl:
+    when compiledWithSsl:
+      sslContext.wrapSocket(result.sock)
+    else:
+      raise newException(ESystem, 
+                         "SMTP module compiled without SSL support")
+
+proc quitExcpt(smtp: AsyncSmtp, msg: string): Future[void] =
+  var retFuture = newFuture[void]()
+  var sendFut = smtp.sock.send("QUIT")
+  sendFut.callback =
+    proc () =
+      # TODO: Fix this in async procs.
+      raise newException(ReplyError, msg)
+  return retFuture
+
+proc checkReply(smtp: AsyncSmtp, reply: string) {.async.} =
+  var line = await smtp.sock.recvLine()
+  if not line.string.startswith(reply):
+    await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
+
+proc connect*(smtp: AsyncSmtp) {.async.} =
+  ## Establishes a connection with a SMTP server.
+  ## May fail with ReplyError or with a socket error.
+  await smtp.sock.connect(smtp.address, smtp.port)
+
+  await smtp.checkReply("220")
+  await smtp.sock.send("HELO " & smtp.address & "\c\L")
+  await smtp.checkReply("250")
+
+proc auth*(smtp: AsyncSmtp, username, password: string) {.async.} =
+  ## Sends an AUTH command to the server to login as the `username` 
+  ## using `password`.
+  ## May fail with ReplyError.
+
+  await smtp.sock.send("AUTH LOGIN\c\L")
+  await smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:"
+                               # i.e "334 VXNlcm5hbWU6"
+  await smtp.sock.send(encode(username) & "\c\L")
+  await smtp.checkReply("334") # TODO: Same as above, only "Password:" (I think?)
+  
+  await smtp.sock.send(encode(password) & "\c\L")
+  await smtp.checkReply("235") # Check whether the authentification was successful.
+
+proc sendMail*(smtp: AsyncSmtp, fromAddr: string,
+               toAddrs: seq[string], msg: string) {.async.} =
+  ## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``.
+  ## Messages may be formed using ``createMessage`` by converting the
+  ## Message into a string.
+
+  await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L")
+  await smtp.checkReply("250")
+  for address in items(toAddrs):
+    await smtp.sock.send("RCPT TO:<" & address & ">\c\L")
+    await smtp.checkReply("250")
+  
+  # Send the message
+  await smtp.sock.send("DATA " & "\c\L")
+  await smtp.checkReply("354")
+  await smtp.sock.send(msg & "\c\L")
+  await smtp.sock.send(".\c\L")
+  await smtp.checkReply("250")
+
+proc close*(smtp: AsyncSmtp) {.async.} =
+  ## Disconnects from the SMTP server and closes the socket.
+  await smtp.sock.send("QUIT\c\L")
+  smtp.sock.close()
+
+when not defined(testing) and isMainModule:
+  #var msg = createMessage("Test subject!", 
+  #     "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
+  #echo(msg)
+
+  #var smtp = connect("localhost", 25, False, True)
+  #smtp.sendmail("root@localhost", @["dominik@localhost"], $msg)
+  
+  #echo(decode("a17sm3701420wbe.12"))
+  proc main() {.async.} =
+    var client = newAsyncSmtp("smtp.gmail.com", Port(465), true)
+    await client.connect()
+    await client.auth("johndoe", "foo")
+    var msg = createMessage("Hello from Nim's SMTP!", 
+                            "Hello!!!!.\n Is this awesome or what?", 
+                            @["blah@gmail.com"])
+    echo(msg)
+    await client.sendMail("blah@gmail.com", @["blah@gmail.com"], $msg)
+
+    await client.close()
+  
+  waitFor main()
diff --git a/lib/pure/smtp.nim.cfg b/lib/pure/smtp.nim.cfg
new file mode 100644
index 000000000..521e21de4
--- /dev/null
+++ b/lib/pure/smtp.nim.cfg
@@ -0,0 +1 @@
+-d:ssl
diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim
new file mode 100644
index 000000000..64e2cdcd3
--- /dev/null
+++ b/lib/pure/sockets.nim
@@ -0,0 +1,1740 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf, Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## **Warning:** Since version 0.10.2 this module is deprecated.
+## Use the `net <net.html>`_ or the
+## `rawsockets <rawsockets.html>`_ module instead.
+##
+## This module implements portable sockets, it supports a mix of different types
+## of sockets. Sockets are buffered by default meaning that data will be
+## received in ``BufferSize`` (4000) sized chunks, buffering
+## behaviour can be disabled by setting the ``buffered`` parameter when calling
+## the ``socket`` function to `false`. Be aware that some functions may not yet
+## support buffered sockets (mainly the recvFrom function).
+##
+## Most procedures raise OSError on error, but some may return ``-1`` or a
+## boolean ``false``.
+##
+## SSL is supported through the OpenSSL library. This support can be activated
+## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
+## raise ESSL exceptions when SSL errors occur.
+##
+## Asynchronous sockets are supported, however a better alternative is to use
+## the `asyncio <asyncio.html>`_ module.
+
+{.deprecated.}
+
+include "system/inclrtl"
+
+{.deadCodeElim: on.}
+
+when hostOS == "solaris":
+  {.passl: "-lsocket -lnsl".}
+
+import os, parseutils
+from times import epochTime
+import unsigned
+
+when defined(ssl):
+  import openssl
+
+when defined(Windows):
+  import winlean
+else:
+  import posix
+
+# Note: The enumerations are mapped to Window's constants.
+
+when defined(ssl):  
+
+  type
+    SSLError* = object of Exception
+
+    SSLCVerifyMode* = enum
+      CVerifyNone, CVerifyPeer
+    
+    SSLProtVersion* = enum
+      protSSLv2, protSSLv3, protTLSv1, protSSLv23
+    
+    SSLContext* = distinct SSLCTX
+
+    SSLAcceptResult* = enum
+      AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
+
+  {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
+     TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
+     TSSLAcceptResult: SSLAcceptResult].}
+
+const
+  BufferSize*: int = 4000 ## size of a buffered socket's buffer
+
+type
+  TSocketImpl = object ## socket type
+    fd: SocketHandle
+    case isBuffered: bool # determines whether this socket is buffered.
+    of true:
+      buffer: array[0..BufferSize, char]
+      currPos: int # current index in buffer
+      bufLen: int # current length of buffer
+    of false: nil
+    when defined(ssl):
+      case isSsl: bool
+      of true:
+        sslHandle: SSLPtr
+        sslContext: SSLContext
+        sslNoHandshake: bool # True if needs handshake.
+        sslHasPeekChar: bool
+        sslPeekChar: char
+      of false: nil
+    nonblocking: bool
+  
+  Socket* = ref TSocketImpl
+  
+  Port* = distinct uint16  ## port type
+  
+  Domain* = enum    ## domain, which specifies the protocol family of the
+                    ## created socket. Other domains than those that are listed
+                    ## here are unsupported.
+    AF_UNIX,        ## for local socket (using a file). Unsupported on Windows.
+    AF_INET = 2,    ## for network protocol IPv4 or
+    AF_INET6 = 23   ## for network protocol IPv6.
+
+  SockType* = enum     ## second argument to `socket` proc
+    SOCK_STREAM = 1,   ## reliable stream-oriented service or Stream Sockets
+    SOCK_DGRAM = 2,    ## datagram service or Datagram Sockets
+    SOCK_RAW = 3,      ## raw protocols atop the network layer.
+    SOCK_SEQPACKET = 5 ## reliable sequenced packet service
+
+  Protocol* = enum      ## third argument to `socket` proc
+    IPPROTO_TCP = 6,    ## Transmission control protocol. 
+    IPPROTO_UDP = 17,   ## User datagram protocol.
+    IPPROTO_IP,         ## Internet protocol. Unsupported on Windows.
+    IPPROTO_IPV6,       ## Internet Protocol Version 6. Unsupported on Windows.
+    IPPROTO_RAW,        ## Raw IP Packets Protocol. Unsupported on Windows.
+    IPPROTO_ICMP        ## Control message protocol. Unsupported on Windows.
+
+  Servent* = object ## information about a service
+    name*: string
+    aliases*: seq[string]
+    port*: Port
+    proto*: string
+
+  Hostent* = object ## information about a given host
+    name*: string
+    aliases*: seq[string]
+    addrtype*: Domain
+    length*: int
+    addrList*: seq[string]
+
+  SOBool* = enum ## Boolean socket options.
+    OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive,
+    OptOOBInline, OptReuseAddr
+
+  RecvLineResult* = enum ## result for recvLineAsync
+    RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail
+
+  ReadLineResult* = enum ## result for readLineAsync
+    ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone
+
+  TimeoutError* = object of Exception
+
+{.deprecated: [TSocket: Socket, TType: SockType, TPort: Port, TDomain: Domain,
+    TProtocol: Protocol, TServent: Servent, THostent: Hostent,
+    TSOBool: SOBool, TRecvLineResult: RecvLineResult, 
+    TReadLineResult: ReadLineResult, ETimeout: TimeoutError].}
+
+when defined(booting):
+  let invalidSocket*: Socket = nil ## invalid socket
+else:
+  const invalidSocket*: Socket = nil ## invalid socket
+
+when defined(windows):
+  let
+    osInvalidSocket = winlean.INVALID_SOCKET
+else:
+  let
+    osInvalidSocket = posix.INVALID_SOCKET
+
+proc newTSocket(fd: SocketHandle, isBuff: bool): Socket =
+  if fd == osInvalidSocket:
+    return nil
+  new(result)
+  result.fd = fd
+  result.isBuffered = isBuff
+  if isBuff:
+    result.currPos = 0
+  result.nonblocking = false
+
+proc `==`*(a, b: Port): bool {.borrow.}
+  ## ``==`` for ports.
+
+proc `$`*(p: Port): string {.borrow.}
+  ## returns the port number as a string
+
+proc ntohl*(x: int32): int32 = 
+  ## Converts 32-bit integers from network to host byte order.
+  ## On machines where the host byte order is the same as network byte order,
+  ## this is a no-op; otherwise, it performs a 4-byte swap operation.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 24'i32) or
+                 (x shr 8'i32 and 0xff00'i32) or
+                 (x shl 8'i32 and 0xff0000'i32) or
+                 (x shl 24'i32)
+
+proc ntohs*(x: int16): int16 =
+  ## Converts 16-bit integers from network to host byte order. On machines
+  ## where the host byte order is the same as network byte order, this is
+  ## a no-op; otherwise, it performs a 2-byte swap operation.
+  when cpuEndian == bigEndian: result = x
+  else: result = (x shr 8'i16) or (x shl 8'i16)
+
+proc htonl*(x: int32): int32 =
+  ## Converts 32-bit integers from host to network byte order. On machines
+  ## where the host byte order is the same as network byte order, this is
+  ## a no-op; otherwise, it performs a 4-byte swap operation.
+  result = sockets.ntohl(x)
+
+proc htons*(x: int16): int16 =
+  ## Converts 16-bit positive integers from host to network byte order.
+  ## On machines where the host byte order is the same as network byte
+  ## order, this is a no-op; otherwise, it performs a 2-byte swap operation.
+  result = sockets.ntohs(x)
+  
+when defined(Posix):
+  proc toInt(domain: Domain): cint =
+    case domain
+    of AF_UNIX:        result = posix.AF_UNIX
+    of AF_INET:        result = posix.AF_INET
+    of AF_INET6:       result = posix.AF_INET6
+    else: discard
+
+  proc toInt(typ: SockType): cint =
+    case typ
+    of SOCK_STREAM:    result = posix.SOCK_STREAM
+    of SOCK_DGRAM:     result = posix.SOCK_DGRAM
+    of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
+    of SOCK_RAW:       result = posix.SOCK_RAW
+    else: discard
+
+  proc toInt(p: Protocol): cint =
+    case p
+    of IPPROTO_TCP:    result = posix.IPPROTO_TCP
+    of IPPROTO_UDP:    result = posix.IPPROTO_UDP
+    of IPPROTO_IP:     result = posix.IPPROTO_IP
+    of IPPROTO_IPV6:   result = posix.IPPROTO_IPV6
+    of IPPROTO_RAW:    result = posix.IPPROTO_RAW
+    of IPPROTO_ICMP:   result = posix.IPPROTO_ICMP
+    else: discard
+
+else:
+  proc toInt(domain: Domain): cint = 
+    result = toU16(ord(domain))
+
+  proc toInt(typ: SockType): cint =
+    result = cint(ord(typ))
+  
+  proc toInt(p: Protocol): cint =
+    result = cint(ord(p))
+
+proc socket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
+             protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
+  ## Creates a new socket; returns `InvalidSocket` if an error occurs.
+  
+  # TODO: Perhaps this should just raise EOS when an error occurs.
+  when defined(Windows):
+    result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
+  else:
+    result = newTSocket(posix.socket(toInt(domain), toInt(typ), toInt(protocol)), buffered)
+
+when defined(ssl):
+  CRYPTO_malloc_init()
+  SslLibraryInit()
+  SslLoadErrorStrings()
+  ErrLoadBioStrings()
+  OpenSSL_add_all_algorithms()
+
+  proc raiseSSLError(s = "") =
+    if s != "":
+      raise newException(SSLError, s)
+    let err = ErrPeekLastError()
+    if err == 0:
+      raise newException(SSLError, "No error reported.")
+    if err == -1:
+      raiseOSError(osLastError())
+    var errStr = ErrErrorString(err, nil)
+    raise newException(SSLError, $errStr)
+
+  # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html
+  proc loadCertificates(ctx: SSL_CTX, certFile, keyFile: string) =
+    if certFile != "" and not existsFile(certFile):
+      raise newException(system.IOError, "Certificate file could not be found: " & certFile)
+    if keyFile != "" and not existsFile(keyFile):
+      raise newException(system.IOError, "Key file could not be found: " & keyFile)
+    
+    if certFile != "":
+      var ret = SSLCTXUseCertificateChainFile(ctx, certFile)
+      if ret != 1:
+        raiseSslError()
+    
+    # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf
+    if keyFile != "":
+      if SSL_CTX_use_PrivateKey_file(ctx, keyFile,
+                                     SSL_FILETYPE_PEM) != 1:
+        raiseSslError()
+        
+      if SSL_CTX_check_private_key(ctx) != 1:
+        raiseSslError("Verification of private key file failed.")
+
+  proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer,
+                   certFile = "", keyFile = ""): SSLContext =
+    ## Creates an SSL context.
+    ## 
+    ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are 
+    ## are available with the addition of ``ProtSSLv23`` which allows for 
+    ## compatibility with all of them.
+    ##
+    ## There are currently only two options for verify mode;
+    ## one is ``CVerifyNone`` and with it certificates will not be verified
+    ## the other is ``CVerifyPeer`` and certificates will be verified for
+    ## it, ``CVerifyPeer`` is the safest choice.
+    ##
+    ## The last two parameters specify the certificate file path and the key file
+    ## path, a server socket will most likely not work without these.
+    ## Certificates can be generated using the following command:
+    ## ``openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem``.
+    var newCTX: SSL_CTX
+    case protVersion
+    of protSSLv23:
+      newCTX = SSL_CTX_new(SSLv23_method()) # SSlv2,3 and TLS1 support.
+    of protSSLv2:
+      when not defined(linux) and not defined(OpenBSD):
+        newCTX = SSL_CTX_new(SSLv2_method())
+      else:
+        raiseSslError()
+    of protSSLv3:
+      newCTX = SSL_CTX_new(SSLv3_method())
+    of protTLSv1:
+      newCTX = SSL_CTX_new(TLSv1_method())
+    
+    if newCTX.SSLCTXSetCipherList("ALL") != 1:
+      raiseSslError()
+    case verifyMode
+    of CVerifyPeer:
+      newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil)
+    of CVerifyNone:
+      newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
+    if newCTX == nil:
+      raiseSslError()
+
+    discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
+    newCTX.loadCertificates(certFile, keyFile)
+    return SSLContext(newCTX)
+
+  proc wrapSocket*(ctx: SSLContext, socket: Socket) =
+    ## Wraps a socket in an SSL context. This function effectively turns
+    ## ``socket`` into an SSL socket.
+    ##
+    ## **Disclaimer**: This code is not well tested, may be very unsafe and
+    ## prone to security vulnerabilities.
+    
+    socket.isSSL = true
+    socket.sslContext = ctx
+    socket.sslHandle = SSLNew(SSLCTX(socket.sslContext))
+    socket.sslNoHandshake = false
+    socket.sslHasPeekChar = false
+    if socket.sslHandle == nil:
+      raiseSslError()
+    
+    if SSLSetFd(socket.sslHandle, socket.fd) != 1:
+      raiseSslError()
+
+proc raiseSocketError*(socket: Socket, err: int = -1, async = false) =
+  ## Raises proper errors based on return values of ``recv`` functions.
+  ##
+  ## If ``async`` is ``True`` no error will be thrown in the case when the
+  ## error was caused by no data being available to be read.
+  ##
+  ## If ``err`` is not lower than 0 no exception will be raised.
+  when defined(ssl):
+    if socket.isSSL:
+      if err <= 0:
+        var ret = SSLGetError(socket.sslHandle, err.cint)
+        case ret
+        of SSL_ERROR_ZERO_RETURN:
+          raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+          if async:
+            return
+          else: raiseSslError("Not enough data on socket.")
+        of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
+          if async:
+            return
+          else: raiseSslError("Not enough data on socket.")
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          raiseSslError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+          raiseSslError()
+        else: raiseSslError("Unknown Error")
+  
+  if err == -1 and not (when defined(ssl): socket.isSSL else: false):
+    let lastError = osLastError()
+    if async:
+      when defined(windows):
+        if lastError.int32 == WSAEWOULDBLOCK:
+          return
+        else: raiseOSError(lastError)
+      else:
+        if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
+          return
+        else: raiseOSError(lastError)
+    else: raiseOSError(lastError)
+
+proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
+  ## Marks ``socket`` as accepting connections. 
+  ## ``Backlog`` specifies the maximum length of the 
+  ## queue of pending connections.
+  if listen(socket.fd, cint(backlog)) < 0'i32: raiseOSError(osLastError())
+
+proc invalidIp4(s: string) {.noreturn, noinline.} =
+  raise newException(ValueError, "invalid ip4 address: " & s)
+
+proc parseIp4*(s: string): BiggestInt = 
+  ## parses an IP version 4 in dotted decimal form like "a.b.c.d".
+  ##
+  ## This is equivalent to `inet_ntoa`:idx:.
+  ##
+  ## Raises EInvalidValue in case of an error.
+  var a, b, c, d: int
+  var i = 0
+  var j = parseInt(s, a, i)
+  if j <= 0: invalidIp4(s)
+  inc(i, j)
+  if s[i] == '.': inc(i)
+  else: invalidIp4(s)
+  j = parseInt(s, b, i)
+  if j <= 0: invalidIp4(s)
+  inc(i, j)
+  if s[i] == '.': inc(i)
+  else: invalidIp4(s)
+  j = parseInt(s, c, i)
+  if j <= 0: invalidIp4(s)
+  inc(i, j)
+  if s[i] == '.': inc(i)
+  else: invalidIp4(s)
+  j = parseInt(s, d, i)
+  if j <= 0: invalidIp4(s)
+  inc(i, j)
+  if s[i] != '\0': invalidIp4(s)
+  result = BiggestInt(a shl 24 or b shl 16 or c shl 8 or d)
+
+template gaiNim(a, p, h, list: expr): stmt =
+  block:
+    var gaiResult = getaddrinfo(a, $p, addr(h), list)
+    if gaiResult != 0'i32:
+      when defined(windows):
+        raiseOSError(osLastError())
+      else:
+        raise newException(OSError, $gai_strerror(gaiResult))
+
+proc bindAddr*(socket: Socket, port = Port(0), address = "") {.
+  tags: [ReadIOEffect].} =
+  ## binds an address/port number to a socket.
+  ## Use address string in dotted decimal form like "a.b.c.d"
+  ## or leave "" for any address.
+
+  if address == "":
+    var name: Sockaddr_in
+    when defined(Windows):
+      name.sin_family = int16(ord(AF_INET))
+    else:
+      name.sin_family = posix.AF_INET
+    name.sin_port = sockets.htons(int16(port))
+    name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
+    if bindSocket(socket.fd, cast[ptr SockAddr](addr(name)),
+                  sizeof(name).SockLen) < 0'i32:
+      raiseOSError(osLastError())
+  else:
+    var hints: AddrInfo
+    var aiList: ptr AddrInfo = nil
+    hints.ai_family = toInt(AF_INET)
+    hints.ai_socktype = toInt(SOCK_STREAM)
+    hints.ai_protocol = toInt(IPPROTO_TCP)
+    gaiNim(address, port, hints, aiList)
+    if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
+      raiseOSError(osLastError())
+  
+proc getSockName*(socket: Socket): Port = 
+  ## returns the socket's associated port number.
+  var name: Sockaddr_in
+  when defined(Windows):
+    name.sin_family = int16(ord(AF_INET))
+  else:
+    name.sin_family = posix.AF_INET
+  #name.sin_port = htons(cint16(port))
+  #name.sin_addr.s_addr = htonl(INADDR_ANY)
+  var namelen = sizeof(name).SockLen
+  if getsockname(socket.fd, cast[ptr SockAddr](addr(name)),
+                 addr(namelen)) == -1'i32:
+    raiseOSError(osLastError())
+  result = Port(sockets.ntohs(name.sin_port))
+
+template acceptAddrPlain(noClientRet, successRet: expr, 
+                         sslImplementation: stmt): stmt {.immediate.} =
+  assert(client != nil)
+  var sockAddress: Sockaddr_in
+  var addrLen = sizeof(sockAddress).SockLen
+  var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)),
+                    addr(addrLen))
+  
+  if sock == osInvalidSocket:
+    let err = osLastError()
+    when defined(windows):
+      if err.int32 == WSAEINPROGRESS:
+        client = invalidSocket
+        address = ""
+        when noClientRet.int == -1:
+          return
+        else:
+          return noClientRet
+      else: raiseOSError(err)
+    else:
+      if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
+        client = invalidSocket
+        address = ""
+        when noClientRet.int == -1:
+          return
+        else:
+          return noClientRet
+      else: raiseOSError(err)
+  else:
+    client.fd = sock
+    client.isBuffered = server.isBuffered
+    sslImplementation
+    # Client socket is set above.
+    address = $inet_ntoa(sockAddress.sin_addr)
+    when successRet.int == -1:
+      return
+    else:
+      return successRet
+
+proc acceptAddr*(server: Socket, client: var Socket, address: var string) {.
+  tags: [ReadIOEffect].} =
+  ## Blocks until a connection is being made from a client. When a connection
+  ## is made sets ``client`` to the client socket and ``address`` to the address
+  ## of the connecting client.
+  ## If ``server`` is non-blocking then this function returns immediately, and
+  ## if there are no connections queued the returned socket will be
+  ## ``InvalidSocket``.
+  ## This function will raise EOS if an error occurs.
+  ##
+  ## The resulting client will inherit any properties of the server socket. For
+  ## example: whether the socket is buffered or not.
+  ##
+  ## **Note**: ``client`` must be initialised (with ``new``), this function 
+  ## makes no effort to initialise the ``client`` variable.
+  ##
+  ## **Warning:** When using SSL with non-blocking sockets, it is best to use
+  ## the acceptAddrSSL procedure as this procedure will most likely block.
+  acceptAddrPlain(-1, -1):
+    when defined(ssl):
+      if server.isSSL:
+        # We must wrap the client sock in a ssl context.
+        
+        server.sslContext.wrapSocket(client)
+        let ret = SSLAccept(client.sslHandle)
+        while ret <= 0:
+          let err = SSLGetError(client.sslHandle, ret)
+          if err != SSL_ERROR_WANT_ACCEPT:
+            case err
+            of SSL_ERROR_ZERO_RETURN:
+              raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+            of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
+               SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+              raiseSslError("acceptAddrSSL should be used for non-blocking SSL sockets.")
+            of SSL_ERROR_WANT_X509_LOOKUP:
+              raiseSslError("Function for x509 lookup has been called.")
+            of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+              raiseSslError()
+            else:
+              raiseSslError("Unknown error")
+
+proc setBlocking*(s: Socket, blocking: bool) {.tags: [], gcsafe.}
+  ## Sets blocking mode on socket
+
+when defined(ssl):
+  proc acceptAddrSSL*(server: Socket, client: var Socket,
+                      address: var string): SSLAcceptResult {.
+                      tags: [ReadIOEffect].} =
+    ## This procedure should only be used for non-blocking **SSL** sockets. 
+    ## It will immediately return with one of the following values:
+    ## 
+    ## ``AcceptSuccess`` will be returned when a client has been successfully
+    ## accepted and the handshake has been successfully performed between
+    ## ``server`` and the newly connected client.
+    ##
+    ## ``AcceptNoHandshake`` will be returned when a client has been accepted
+    ## but no handshake could be performed. This can happen when the client
+    ## connects but does not yet initiate a handshake. In this case
+    ## ``acceptAddrSSL`` should be called again with the same parameters.
+    ##
+    ## ``AcceptNoClient`` will be returned when no client is currently attempting
+    ## to connect.
+    template doHandshake(): stmt =
+      when defined(ssl):
+        if server.isSSL:
+          client.setBlocking(false)
+          # We must wrap the client sock in a ssl context.
+          
+          if not client.isSSL or client.sslHandle == nil:
+            server.sslContext.wrapSocket(client)
+          let ret = SSLAccept(client.sslHandle)
+          while ret <= 0:
+            let err = SSLGetError(client.sslHandle, ret)
+            if err != SSL_ERROR_WANT_ACCEPT:
+              case err
+              of SSL_ERROR_ZERO_RETURN:
+                raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+              of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE,
+                 SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+                client.sslNoHandshake = true
+                return AcceptNoHandshake
+              of SSL_ERROR_WANT_X509_LOOKUP:
+                raiseSslError("Function for x509 lookup has been called.")
+              of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+                raiseSslError()
+              else:
+                raiseSslError("Unknown error")
+          client.sslNoHandshake = false
+
+    if client.isSSL and client.sslNoHandshake:
+      doHandshake()
+      return AcceptSuccess
+    else:
+      acceptAddrPlain(AcceptNoClient, AcceptSuccess):
+        doHandshake()
+
+proc accept*(server: Socket, client: var Socket) {.tags: [ReadIOEffect].} =
+  ## Equivalent to ``acceptAddr`` but doesn't return the address, only the
+  ## socket.
+  ## 
+  ## **Note**: ``client`` must be initialised (with ``new``), this function
+  ## makes no effort to initialise the ``client`` variable.
+  
+  var addrDummy = ""
+  acceptAddr(server, client, addrDummy)
+
+proc acceptAddr*(server: Socket): tuple[client: Socket, address: string] {.
+  deprecated, tags: [ReadIOEffect].} =
+  ## Slightly different version of ``acceptAddr``.
+  ##
+  ## **Deprecated since version 0.9.0:** Please use the function above.
+  var client: Socket
+  new(client)
+  var address = ""
+  acceptAddr(server, client, address)
+  return (client, address)
+
+proc accept*(server: Socket): Socket {.deprecated, tags: [ReadIOEffect].} =
+  ## **Deprecated since version 0.9.0:** Please use the function above.
+  new(result)
+  var address = ""
+  acceptAddr(server, result, address)
+
+proc close*(socket: Socket) =
+  ## closes a socket.
+  when defined(windows):
+    discard winlean.closesocket(socket.fd)
+  else:
+    discard posix.close(socket.fd)
+  # TODO: These values should not be discarded. An EOS should be raised.
+  # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
+  when defined(ssl):
+    if socket.isSSL:
+      discard SSLShutdown(socket.sslHandle)
+      SSLFree(socket.sslHandle)
+      socket.sslHandle = nil
+
+proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} =
+  ## Searches the database from the beginning and finds the first entry for 
+  ## which the service name specified by ``name`` matches the s_name member
+  ## and the protocol name specified by ``proto`` matches the s_proto member.
+  ##
+  ## On posix this will search through the ``/etc/services`` file.
+  when defined(Windows):
+    var s = winlean.getservbyname(name, proto)
+  else:
+    var s = posix.getservbyname(name, proto)
+  if s == nil: raise newException(OSError, "Service not found.")
+  result.name = $s.s_name
+  result.aliases = cstringArrayToSeq(s.s_aliases)
+  result.port = Port(s.s_port)
+  result.proto = $s.s_proto
+  
+proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = 
+  ## Searches the database from the beginning and finds the first entry for 
+  ## which the port specified by ``port`` matches the s_port member and the 
+  ## protocol name specified by ``proto`` matches the s_proto member.
+  ##
+  ## On posix this will search through the ``/etc/services`` file.
+  when defined(Windows):
+    var s = winlean.getservbyport(ze(int16(port)).cint, proto)
+  else:
+    var s = posix.getservbyport(ze(int16(port)).cint, proto)
+  if s == nil: raise newException(OSError, "Service not found.")
+  result.name = $s.s_name
+  result.aliases = cstringArrayToSeq(s.s_aliases)
+  result.port = Port(s.s_port)
+  result.proto = $s.s_proto
+
+proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
+  ## This function will lookup the hostname of an IP Address.
+  var myaddr: InAddr
+  myaddr.s_addr = inet_addr(ip)
+  
+  when defined(windows):
+    var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
+                                  cint(sockets.AF_INET))
+    if s == nil: raiseOSError(osLastError())
+  else:
+    var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, 
+                                cint(posix.AF_INET))
+    if s == nil:
+      raise newException(OSError, $hstrerror(h_errno))
+  
+  result.name = $s.h_name
+  result.aliases = cstringArrayToSeq(s.h_aliases)
+  when defined(windows): 
+    result.addrtype = Domain(s.h_addrtype)
+  else:
+    if s.h_addrtype == posix.AF_INET:
+      result.addrtype = AF_INET
+    elif s.h_addrtype == posix.AF_INET6:
+      result.addrtype = AF_INET6
+    else:
+      raise newException(OSError, "unknown h_addrtype")
+  result.addrList = cstringArrayToSeq(s.h_addr_list)
+  result.length = int(s.h_length)
+
+proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = 
+  ## This function will lookup the IP address of a hostname.
+  when defined(Windows):
+    var s = winlean.gethostbyname(name)
+  else:
+    var s = posix.gethostbyname(name)
+  if s == nil: raiseOSError(osLastError())
+  result.name = $s.h_name
+  result.aliases = cstringArrayToSeq(s.h_aliases)
+  when defined(windows): 
+    result.addrtype = Domain(s.h_addrtype)
+  else:
+    if s.h_addrtype == posix.AF_INET:
+      result.addrtype = AF_INET
+    elif s.h_addrtype == posix.AF_INET6:
+      result.addrtype = AF_INET6
+    else:
+      raise newException(OSError, "unknown h_addrtype")
+  result.addrList = cstringArrayToSeq(s.h_addr_list)
+  result.length = int(s.h_length)
+
+proc getSockOptInt*(socket: Socket, level, optname: int): int {.
+  tags: [ReadIOEffect].} = 
+  ## getsockopt for integer options.
+  var res: cint
+  var size = sizeof(res).SockLen
+  if getsockopt(socket.fd, cint(level), cint(optname), 
+                addr(res), addr(size)) < 0'i32:
+    raiseOSError(osLastError())
+  result = int(res)
+
+proc setSockOptInt*(socket: Socket, level, optname, optval: int) {.
+  tags: [WriteIOEffect].} =
+  ## setsockopt for integer options.
+  var value = cint(optval)
+  if setsockopt(socket.fd, cint(level), cint(optname), addr(value),  
+                sizeof(value).SockLen) < 0'i32:
+    raiseOSError(osLastError())
+
+proc toCInt(opt: SOBool): cint =
+  case opt
+  of OptAcceptConn: SO_ACCEPTCONN
+  of OptBroadcast: SO_BROADCAST
+  of OptDebug: SO_DEBUG
+  of OptDontRoute: SO_DONTROUTE
+  of OptKeepAlive: SO_KEEPALIVE
+  of OptOOBInline: SO_OOBINLINE
+  of OptReuseAddr: SO_REUSEADDR
+
+proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {.
+  tags: [ReadIOEffect].} =
+  ## Retrieves option ``opt`` as a boolean value.
+  var res: cint
+  var size = sizeof(res).SockLen
+  if getsockopt(socket.fd, cint(level), toCInt(opt), 
+                addr(res), addr(size)) < 0'i32:
+    raiseOSError(osLastError())
+  result = res != 0
+
+proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {.
+  tags: [WriteIOEffect].} =
+  ## Sets option ``opt`` to a boolean value specified by ``value``.
+  var valuei = cint(if value: 1 else: 0)
+  if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),  
+                sizeof(valuei).SockLen) < 0'i32:
+    raiseOSError(osLastError())
+
+proc connect*(socket: Socket, address: string, port = Port(0), 
+              af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
+  ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a
+  ## host name. If ``address`` is a host name, this function will try each IP
+  ## of that host name. ``htons`` is already performed on ``port`` so you must
+  ## not do it.
+  ##
+  ## If ``socket`` is an SSL socket a handshake will be automatically performed.
+  var hints: AddrInfo
+  var aiList: ptr AddrInfo = nil
+  hints.ai_family = toInt(af)
+  hints.ai_socktype = toInt(SOCK_STREAM)
+  hints.ai_protocol = toInt(IPPROTO_TCP)
+  gaiNim(address, port, hints, aiList)
+  # try all possibilities:
+  var success = false
+  var lastError: OSErrorCode
+  var it = aiList
+  while it != nil:
+    if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32:
+      success = true
+      break
+    else: lastError = osLastError()
+    it = it.ai_next
+
+  freeaddrinfo(aiList)
+  if not success: raiseOSError(lastError)
+  
+  when defined(ssl):
+    if socket.isSSL:
+      let ret = SSLConnect(socket.sslHandle)
+      if ret <= 0:
+        let err = SSLGetError(socket.sslHandle, ret)
+        case err
+        of SSL_ERROR_ZERO_RETURN:
+          raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, 
+           SSL_ERROR_WANT_ACCEPT:
+          raiseSslError("The operation did not complete. Perhaps you should use connectAsync?")
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          raiseSslError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+          raiseSslError()
+        else:
+          raiseSslError("Unknown error")
+        
+  when false:
+    var s: TSockAddrIn
+    s.sin_addr.s_addr = inet_addr(address)
+    s.sin_port = sockets.htons(int16(port))
+    when defined(windows):
+      s.sin_family = toU16(ord(af))
+    else:
+      case af 
+      of AF_UNIX: s.sin_family = posix.AF_UNIX
+      of AF_INET: s.sin_family = posix.AF_INET
+      of AF_INET6: s.sin_family = posix.AF_INET6
+      else: nil
+    if connect(socket.fd, cast[ptr TSockAddr](addr(s)), sizeof(s).cint) < 0'i32:
+      OSError()
+
+proc connectAsync*(socket: Socket, name: string, port = Port(0),
+                     af: Domain = AF_INET) {.tags: [ReadIOEffect].} =
+  ## A variant of ``connect`` for non-blocking sockets.
+  ##
+  ## This procedure will immediately return, it will not block until a connection
+  ## is made. It is up to the caller to make sure the connection has been established
+  ## by checking (using ``select``) whether the socket is writeable.
+  ##
+  ## **Note**: For SSL sockets, the ``handshake`` procedure must be called
+  ## whenever the socket successfully connects to a server.
+  var hints: AddrInfo
+  var aiList: ptr AddrInfo = nil
+  hints.ai_family = toInt(af)
+  hints.ai_socktype = toInt(SOCK_STREAM)
+  hints.ai_protocol = toInt(IPPROTO_TCP)
+  gaiNim(name, port, hints, aiList)
+  # try all possibilities:
+  var success = false
+  var lastError: OSErrorCode
+  var it = aiList
+  while it != nil:
+    var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen)
+    if ret == 0'i32:
+      success = true
+      break
+    else:
+      lastError = osLastError()
+      when defined(windows):
+        # Windows EINTR doesn't behave same as POSIX.
+        if lastError.int32 == WSAEWOULDBLOCK:
+          success = true
+          break
+      else:
+        if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+          success = true
+          break
+        
+    it = it.ai_next
+
+  freeaddrinfo(aiList)
+  if not success: raiseOSError(lastError)
+  when defined(ssl):
+    if socket.isSSL:
+      socket.sslNoHandshake = true
+
+when defined(ssl):
+  proc handshake*(socket: Socket): bool {.tags: [ReadIOEffect, WriteIOEffect].} =
+    ## This proc needs to be called on a socket after it connects. This is
+    ## only applicable when using ``connectAsync``.
+    ## This proc performs the SSL handshake.
+    ##
+    ## Returns ``False`` whenever the socket is not yet ready for a handshake,
+    ## ``True`` whenever handshake completed successfully.
+    ##
+    ## A ESSL error is raised on any other errors.
+    result = true
+    if socket.isSSL:
+      var ret = SSLConnect(socket.sslHandle)
+      if ret <= 0:
+        var errret = SSLGetError(socket.sslHandle, ret)
+        case errret
+        of SSL_ERROR_ZERO_RETURN:
+          raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+        of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT,
+          SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE:
+          return false
+        of SSL_ERROR_WANT_X509_LOOKUP:
+          raiseSslError("Function for x509 lookup has been called.")
+        of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+          raiseSslError()
+        else:
+          raiseSslError("Unknown Error")
+      socket.sslNoHandshake = false
+    else:
+      raiseSslError("Socket is not an SSL socket.")
+
+  proc gotHandshake*(socket: Socket): bool =
+    ## Determines whether a handshake has occurred between a client (``socket``)
+    ## and the server that ``socket`` is connected to.
+    ##
+    ## Throws ESSL if ``socket`` is not an SSL socket.
+    if socket.isSSL:
+      return not socket.sslNoHandshake
+    else:
+      raiseSslError("Socket is not an SSL socket.")
+
+proc timeValFromMilliseconds(timeout = 500): Timeval =
+  if timeout != -1:
+    var seconds = timeout div 1000
+    result.tv_sec = seconds.int32
+    result.tv_usec = ((timeout - seconds * 1000) * 1000).int32
+
+proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) = 
+  FD_ZERO(fd)
+  for i in items(s): 
+    m = max(m, int(i.fd))
+    FD_SET(i.fd, fd)
+   
+proc pruneSocketSet(s: var seq[Socket], fd: var TFdSet) =
+  var i = 0
+  var L = s.len
+  while i < L:
+    if FD_ISSET(s[i].fd, fd) == 0'i32:
+      # not set.
+      s[i] = s[L-1]
+      dec(L)
+    else:
+      inc(i)
+  setLen(s, L)
+
+proc hasDataBuffered*(s: Socket): bool =
+  ## Determines whether a socket has data buffered.
+  result = false
+  if s.isBuffered:
+    result = s.bufLen > 0 and s.currPos != s.bufLen
+
+  when defined(ssl):
+    if s.isSSL and not result:
+      result = s.sslHasPeekChar
+
+proc checkBuffer(readfds: var seq[Socket]): int =
+  ## Checks the buffer of each socket in ``readfds`` to see whether there is data.
+  ## Removes the sockets from ``readfds`` and returns the count of removed sockets.
+  var res: seq[Socket] = @[]
+  result = 0
+  for s in readfds:
+    if hasDataBuffered(s):
+      inc(result)
+      res.add(s)
+  if result > 0:
+    readfds = res
+
+proc select*(readfds, writefds, exceptfds: var seq[Socket], 
+             timeout = 500): int {.tags: [ReadIOEffect].} = 
+  ## Traditional select function. This function will return the number of
+  ## sockets that are ready to be read from, written to, or which have errors.
+  ## If there are none; 0 is returned. 
+  ## ``Timeout`` is in milliseconds and -1 can be specified for no timeout.
+  ## 
+  ## Sockets which are **not** ready for reading, writing or which don't have
+  ## errors waiting on them are removed from the ``readfds``, ``writefds``,
+  ## ``exceptfds`` sequences respectively.
+  let buffersFilled = checkBuffer(readfds)
+  if buffersFilled > 0:
+    return buffersFilled
+
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+  
+  var rd, wr, ex: TFdSet
+  var m = 0
+  createFdSet((rd), readfds, m)
+  createFdSet((wr), writefds, m)
+  createFdSet((ex), exceptfds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), addr(tv)))
+  else:
+    result = int(select(cint(m+1), addr(rd), addr(wr), addr(ex), nil))
+  
+  pruneSocketSet(readfds, (rd))
+  pruneSocketSet(writefds, (wr))
+  pruneSocketSet(exceptfds, (ex))
+
+proc select*(readfds, writefds: var seq[Socket], 
+             timeout = 500): int {.tags: [ReadIOEffect].} =
+  ## Variant of select with only a read and write list.
+  let buffersFilled = checkBuffer(readfds)
+  if buffersFilled > 0:
+    return buffersFilled
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+  
+  var rd, wr: TFdSet
+  var m = 0
+  createFdSet((rd), readfds, m)
+  createFdSet((wr), writefds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), addr(rd), addr(wr), nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), addr(rd), addr(wr), nil, nil))
+  
+  pruneSocketSet(readfds, (rd))
+  pruneSocketSet(writefds, (wr))
+
+proc selectWrite*(writefds: var seq[Socket], 
+                  timeout = 500): int {.tags: [ReadIOEffect].} =
+  ## When a socket in ``writefds`` is ready to be written to then a non-zero
+  ## value will be returned specifying the count of the sockets which can be
+  ## written to. The sockets which **cannot** be written to will also be removed
+  ## from ``writefds``.
+  ##
+  ## ``timeout`` is specified in milliseconds and ``-1`` can be specified for
+  ## an unlimited time.
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+  
+  var wr: TFdSet
+  var m = 0
+  createFdSet((wr), writefds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), nil, addr(wr), nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), nil, addr(wr), nil, nil))
+  
+  pruneSocketSet(writefds, (wr))
+
+proc select*(readfds: var seq[Socket], timeout = 500): int =
+  ## variant of select with a read list only
+  let buffersFilled = checkBuffer(readfds)
+  if buffersFilled > 0:
+    return buffersFilled
+  var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout)
+  
+  var rd: TFdSet
+  var m = 0
+  createFdSet((rd), readfds, m)
+  
+  if timeout != -1:
+    result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
+  else:
+    result = int(select(cint(m+1), addr(rd), nil, nil, nil))
+  
+  pruneSocketSet(readfds, (rd))
+
+proc readIntoBuf(socket: Socket, flags: int32): int =
+  result = 0
+  when defined(ssl):
+    if socket.isSSL:
+      result = SSLRead(socket.sslHandle, addr(socket.buffer), int(socket.buffer.high))
+    else:
+      result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  else:
+    result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
+  if result <= 0:
+    socket.bufLen = 0
+    socket.currPos = 0
+    return result
+  socket.bufLen = result
+  socket.currPos = 0
+
+template retRead(flags, readBytes: int) {.dirty.} =
+  let res = socket.readIntoBuf(flags.int32)
+  if res <= 0:
+    if readBytes > 0:
+      return readBytes
+    else:
+      return res
+
+proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} =
+  ## Receives data from a socket.
+  ##
+  ## **Note**: This is a low-level function, you may be interested in the higher
+  ## level versions of this function which are also named ``recv``.
+  if size == 0: return
+  if socket.isBuffered:
+    if socket.bufLen == 0:
+      retRead(0'i32, 0)
+    
+    var read = 0
+    while read < size:
+      if socket.currPos >= socket.bufLen:
+        retRead(0'i32, read)
+    
+      let chunk = min(socket.bufLen-socket.currPos, size-read)
+      var d = cast[cstring](data)
+      copyMem(addr(d[read]), addr(socket.buffer[socket.currPos]), chunk)
+      read.inc(chunk)
+      socket.currPos.inc(chunk)
+
+    result = read
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        if socket.sslHasPeekChar:
+          copyMem(data, addr(socket.sslPeekChar), 1)
+          socket.sslHasPeekChar = false
+          if size-1 > 0:
+            var d = cast[cstring](data)
+            result = SSLRead(socket.sslHandle, addr(d[1]), size-1) + 1
+          else:
+            result = 1
+        else:
+          result = SSLRead(socket.sslHandle, data, size)
+      else:
+        result = recv(socket.fd, data, size.cint, 0'i32)
+    else:
+      result = recv(socket.fd, data, size.cint, 0'i32)
+
+proc waitFor(socket: Socket, waited: var float, timeout, size: int,
+             funcName: string): int {.tags: [TimeEffect].} =
+  ## determines the amount of characters that can be read. Result will never
+  ## be larger than ``size``. For unbuffered sockets this will be ``1``.
+  ## For buffered sockets it can be as big as ``BufferSize``.
+  ##
+  ## If this function does not determine that there is data on the socket
+  ## within ``timeout`` ms, an ETimeout error will be raised.
+  result = 1
+  if size <= 0: assert false
+  if timeout == -1: return size
+  if socket.isBuffered and socket.bufLen != 0 and socket.bufLen != socket.currPos:
+    result = socket.bufLen - socket.currPos
+    result = min(result, size)
+  else:
+    if timeout - int(waited * 1000.0) < 1:
+      raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
+    
+    when defined(ssl):
+      if socket.isSSL:
+        if socket.hasDataBuffered:
+          # sslPeekChar is present.
+          return 1
+        let sslPending = SSLPending(socket.sslHandle)
+        if sslPending != 0:
+          return sslPending
+    
+    var s = @[socket]
+    var startTime = epochTime()
+    let selRet = select(s, timeout - int(waited * 1000.0))
+    if selRet < 0: raiseOSError(osLastError())
+    if selRet != 1:
+      raise newException(TimeoutError, "Call to '" & funcName & "' timed out.")
+    waited += (epochTime() - startTime)
+
+proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {.
+  tags: [ReadIOEffect, TimeEffect].} =
+  ## overload with a ``timeout`` parameter in milliseconds.
+  var waited = 0.0 # number of seconds already waited  
+  
+  var read = 0
+  while read < size:
+    let avail = waitFor(socket, waited, timeout, size-read, "recv")
+    var d = cast[cstring](data)
+    result = recv(socket, addr(d[read]), avail)
+    if result == 0: break
+    if result < 0:
+      return result
+    inc(read, result)
+  
+  result = read
+
+proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int =
+  ## Higher-level version of ``recv``.
+  ##
+  ## When 0 is returned the socket's connection has been closed.
+  ##
+  ## This function will throw an EOS exception when an error occurs. A value
+  ## lower than 0 is never returned.
+  ##
+  ## A timeout may be specified in milliseconds, if enough data is not received
+  ## within the time specified an ETimeout exception will be raised.
+  ##
+  ## **Note**: ``data`` must be initialised.
+  data.setLen(size)
+  result = recv(socket, cstring(data), size, timeout)
+  if result < 0:
+    data.setLen(0)
+    socket.raiseSocketError(result)
+  data.setLen(result)
+
+proc recvAsync*(socket: Socket, data: var string, size: int): int =
+  ## Async version of ``recv``.
+  ##
+  ## When socket is non-blocking and no data is available on the socket,
+  ## ``-1`` will be returned and ``data`` will be ``""``.
+  ##
+  ## **Note**: ``data`` must be initialised.
+  data.setLen(size)
+  result = recv(socket, cstring(data), size)
+  if result < 0:
+    data.setLen(0)
+    socket.raiseSocketError(async = true)
+    result = -1
+  data.setLen(result)
+
+proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
+  if socket.isBuffered:
+    result = 1
+    if socket.bufLen == 0 or socket.currPos > socket.bufLen-1:
+      var res = socket.readIntoBuf(0'i32)
+      if res <= 0:
+        result = res
+    
+    c = socket.buffer[socket.currPos]
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        if not socket.sslHasPeekChar:
+          result = SSLRead(socket.sslHandle, addr(socket.sslPeekChar), 1)
+          socket.sslHasPeekChar = true
+        
+        c = socket.sslPeekChar
+        return
+    result = recv(socket.fd, addr(c), 1, MSG_PEEK)
+
+proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
+  tags: [ReadIOEffect, TimeEffect], deprecated.} =
+  ## Receive a line of data from ``socket``.
+  ##
+  ## If a full line is received ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is received then ``line``
+  ## will be set to it.
+  ## 
+  ## ``True`` is returned if data is available. ``False`` suggests an
+  ## error, EOS exceptions are not raised and ``False`` is simply returned
+  ## instead.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
+  ## will be returned.
+  ##
+  ## A timeout can be specified in milliseconds, if data is not received within
+  ## the specified time an ETimeout exception will be raised.
+  ##
+  ## **Deprecated since version 0.9.2**: This function has been deprecated in
+  ## favour of readLine.
+  
+  template addNLIfEmpty(): stmt =
+    if line.len == 0:
+      line.add("\c\L")
+
+  var waited = 0.0
+
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    discard waitFor(socket, waited, timeout, 1, "recvLine")
+    var n = recv(socket, addr(c), 1)
+    if n < 0: return
+    elif n == 0: return true
+    if c == '\r':
+      discard waitFor(socket, waited, timeout, 1, "recvLine")
+      n = peekChar(socket, c)
+      if n > 0 and c == '\L':
+        discard recv(socket, addr(c), 1)
+      elif n <= 0: return false
+      addNLIfEmpty()
+      return true
+    elif c == '\L': 
+      addNLIfEmpty()
+      return true
+    add(line.string, c)
+
+proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
+  tags: [ReadIOEffect, TimeEffect].} =
+  ## Reads a line of data from ``socket``.
+  ##
+  ## If a full line is read ``\r\L`` is not
+  ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+  ## will be set to it.
+  ## 
+  ## If the socket is disconnected, ``line`` will be set to ``""``.
+  ##
+  ## An EOS exception will be raised in the case of a socket error.
+  ##
+  ## A timeout can be specified in milliseconds, if data is not received within
+  ## the specified time an ETimeout exception will be raised.
+  
+  template addNLIfEmpty(): stmt =
+    if line.len == 0:
+      line.add("\c\L")
+
+  var waited = 0.0
+
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    discard waitFor(socket, waited, timeout, 1, "readLine")
+    var n = recv(socket, addr(c), 1)
+    if n < 0: socket.raiseSocketError()
+    elif n == 0: return
+    if c == '\r':
+      discard waitFor(socket, waited, timeout, 1, "readLine")
+      n = peekChar(socket, c)
+      if n > 0 and c == '\L':
+        discard recv(socket, addr(c), 1)
+      elif n <= 0: socket.raiseSocketError()
+      addNLIfEmpty()
+      return
+    elif c == '\L': 
+      addNLIfEmpty()
+      return
+    add(line.string, c)
+
+proc recvLineAsync*(socket: Socket, 
+  line: var TaintedString): RecvLineResult {.tags: [ReadIOEffect], deprecated.} =
+  ## Similar to ``recvLine`` but designed for non-blocking sockets.
+  ##
+  ## The values of the returned enum should be pretty self explanatory:
+  ##
+  ##   * If a full line has been retrieved; ``RecvFullLine`` is returned.
+  ##   * If some data has been retrieved; ``RecvPartialLine`` is returned.
+  ##   * If the socket has been disconnected; ``RecvDisconnected`` is returned.
+  ##   * If call to ``recv`` failed; ``RecvFail`` is returned.
+  ##
+  ## **Deprecated since version 0.9.2**: This function has been deprecated in
+  ## favour of readLineAsync.
+
+  setLen(line.string, 0)
+  while true:
+    var c: char
+    var n = recv(socket, addr(c), 1)
+    if n < 0: 
+      return (if line.len == 0: RecvFail else: RecvPartialLine)
+    elif n == 0: 
+      return (if line.len == 0: RecvDisconnected else: RecvPartialLine)
+    if c == '\r':
+      n = peekChar(socket, c)
+      if n > 0 and c == '\L':
+        discard recv(socket, addr(c), 1)
+      elif n <= 0: 
+        return (if line.len == 0: RecvFail else: RecvPartialLine)
+      return RecvFullLine
+    elif c == '\L': return RecvFullLine
+    add(line.string, c)
+
+proc readLineAsync*(socket: Socket, 
+  line: var TaintedString): ReadLineResult {.tags: [ReadIOEffect].} =
+  ## Similar to ``recvLine`` but designed for non-blocking sockets.
+  ##
+  ## The values of the returned enum should be pretty self explanatory:
+  ##
+  ##   * If a full line has been retrieved; ``ReadFullLine`` is returned.
+  ##   * If some data has been retrieved; ``ReadPartialLine`` is returned.
+  ##   * If the socket has been disconnected; ``ReadDisconnected`` is returned.
+  ##   * If no data could be retrieved; ``ReadNone`` is returned.
+  ##   * If call to ``recv`` failed; **an EOS exception is raised.**
+  setLen(line.string, 0)
+  
+  template errorOrNone =
+    socket.raiseSocketError(async = true)
+    return ReadNone
+  
+  while true:
+    var c: char
+    var n = recv(socket, addr(c), 1)
+    #echo(n)
+    if n < 0:
+      if line.len == 0: errorOrNone else: return ReadPartialLine
+    elif n == 0: 
+      return (if line.len == 0: ReadDisconnected else: ReadPartialLine)
+    if c == '\r':
+      n = peekChar(socket, c)
+      if n > 0 and c == '\L':
+        discard recv(socket, addr(c), 1)
+      elif n <= 0: 
+        if line.len == 0: errorOrNone else: return ReadPartialLine
+      return ReadFullLine
+    elif c == '\L': return ReadFullLine
+    add(line.string, c)
+
+proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} =
+  ## receives all the available data from the socket.
+  ## Socket errors will result in an ``EOS`` error.
+  ## If socket is not a connectionless socket and socket is not connected
+  ## ``""`` will be returned.
+  ##
+  ## **Deprecated since version 0.9.2**: This function is not safe for use.
+  const bufSize = 4000
+  result = newStringOfCap(bufSize).TaintedString
+  var pos = 0
+  while true:
+    var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
+    if bytesRead == -1: raiseOSError(osLastError())
+    setLen(result.string, pos + bytesRead)
+    if bytesRead != bufSize-1: break
+    # increase capacity:
+    setLen(result.string, result.string.len + bufSize)
+    inc(pos, bytesRead)
+  when false:
+    var buf = newString(bufSize)
+    result = TaintedString""
+    while true:
+      var bytesRead = recv(socket, cstring(buf), bufSize-1)
+      # Error
+      if bytesRead == -1: OSError(osLastError())
+      
+      buf[bytesRead] = '\0' # might not be necessary
+      setLen(buf, bytesRead)
+      add(result.string, buf)
+      if bytesRead != bufSize-1: break
+
+{.push warning[deprecated]: off.}
+proc recvTimeout*(socket: Socket, timeout: int): TaintedString {.
+  tags: [ReadIOEffect], deprecated.} =
+  ## overloaded variant to support a ``timeout`` parameter, the ``timeout``
+  ## parameter specifies the amount of milliseconds to wait for data on the
+  ## socket.
+  ##
+  ## **Deprecated since version 0.9.2**: This function is not safe for use.
+  if socket.bufLen == 0:
+    var s = @[socket]
+    if s.select(timeout) != 1:
+      raise newException(TimeoutError, "Call to recv() timed out.")
+  
+  return socket.recv
+{.pop.}
+
+proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
+  tags: [ReadIOEffect], deprecated.} =
+  ## receives all the data from a non-blocking socket. If socket is non-blocking 
+  ## and there are no messages available, `False` will be returned.
+  ## Other socket errors will result in an ``EOS`` error.
+  ## If socket is not a connectionless socket and socket is not connected
+  ## ``s`` will be set to ``""``.
+  ##
+  ## **Deprecated since version 0.9.2**: This function is not safe for use.
+  const bufSize = 1000
+  # ensure bufSize capacity:
+  setLen(s.string, bufSize)
+  setLen(s.string, 0)
+  var pos = 0
+  while true:
+    var bytesRead = recv(socket, addr(string(s)[pos]), bufSize-1)
+    when defined(ssl):
+      if socket.isSSL:
+        if bytesRead <= 0:
+          var ret = SSLGetError(socket.sslHandle, bytesRead.cint)
+          case ret
+          of SSL_ERROR_ZERO_RETURN:
+            raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+          of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+            raiseSslError("Unexpected error occurred.") # This should just not happen.
+          of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
+            return false
+          of SSL_ERROR_WANT_X509_LOOKUP:
+            raiseSslError("Function for x509 lookup has been called.")
+          of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+            raiseSslError()
+          else: raiseSslError("Unknown Error")
+          
+    if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
+      let err = osLastError()
+      when defined(windows):
+        if err.int32 == WSAEWOULDBLOCK:
+          return false
+        else: raiseOSError(err)
+      else:
+        if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
+          return false
+        else: raiseOSError(err)
+
+    setLen(s.string, pos + bytesRead)
+    if bytesRead != bufSize-1: break
+    # increase capacity:
+    setLen(s.string, s.string.len + bufSize)
+    inc(pos, bytesRead)
+  result = true
+
+proc recvFrom*(socket: Socket, data: var string, length: int,
+               address: var string, port: var Port, flags = 0'i32): int {.
+               tags: [ReadIOEffect].} =
+  ## Receives data from ``socket``. This function should normally be used with
+  ## connection-less sockets (UDP sockets).
+  ##
+  ## If an error occurs the return value will be ``-1``. Otherwise the return
+  ## value will be the length of data received.
+  ##
+  ## **Warning:** This function does not yet have a buffered implementation,
+  ## so when ``socket`` is buffered the non-buffered implementation will be
+  ## used. Therefore if ``socket`` contains something in its buffer this
+  ## function will make no effort to return it.
+  
+  # TODO: Buffered sockets
+  data.setLen(length)
+  var sockAddress: Sockaddr_in
+  var addrLen = sizeof(sockAddress).SockLen
+  result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
+                    cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
+
+  if result != -1:
+    data.setLen(result)
+    address = $inet_ntoa(sockAddress.sin_addr)
+    port = ntohs(sockAddress.sin_port).Port
+
+proc recvFromAsync*(socket: Socket, data: var string, length: int,
+                    address: var string, port: var Port, 
+                    flags = 0'i32): bool {.tags: [ReadIOEffect].} =
+  ## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``,
+  ## this function will raise an EOS error whenever a socket error occurs.
+  ##
+  ## If there is no data to be read from the socket ``False`` will be returned.
+  result = true
+  var callRes = recvFrom(socket, data, length, address, port, flags)
+  if callRes < 0:
+    let err = osLastError()
+    when defined(windows):
+      if err.int32 == WSAEWOULDBLOCK:
+        return false
+      else: raiseOSError(err)
+    else:
+      if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
+        return false
+      else: raiseOSError(err)
+
+proc skip*(socket: Socket) {.tags: [ReadIOEffect], deprecated.} =
+  ## skips all the data that is pending for the socket
+  ##
+  ## **Deprecated since version 0.9.2**: This function is not safe for use.
+  const bufSize = 1000
+  var buf = alloc(bufSize)
+  while recv(socket, buf, bufSize) == bufSize: discard
+  dealloc(buf)
+
+proc skip*(socket: Socket, size: int, timeout = -1) =
+  ## Skips ``size`` amount of bytes.
+  ##
+  ## An optional timeout can be specified in milliseconds, if skipping the
+  ## bytes takes longer than specified an ETimeout exception will be raised.
+  ##
+  ## Returns the number of skipped bytes.
+  var waited = 0.0
+  var dummy = alloc(size)
+  var bytesSkipped = 0
+  while bytesSkipped != size:
+    let avail = waitFor(socket, waited, timeout, size-bytesSkipped, "skip")
+    bytesSkipped += recv(socket, dummy, avail)
+  dealloc(dummy)
+
+proc send*(socket: Socket, data: pointer, size: int): int {.
+  tags: [WriteIOEffect].} =
+  ## sends data to a socket.
+  when defined(ssl):
+    if socket.isSSL:
+      return SSLWrite(socket.sslHandle, cast[cstring](data), size)
+  
+  when defined(windows) or defined(macosx):
+    result = send(socket.fd, data, size.cint, 0'i32)
+  else:
+    when defined(solaris): 
+      const MSG_NOSIGNAL = 0
+    result = send(socket.fd, data, size, int32(MSG_NOSIGNAL))
+
+proc send*(socket: Socket, data: string) {.tags: [WriteIOEffect].} =
+  ## sends data to a socket.
+  if socket.nonblocking:
+    raise newException(ValueError, "This function cannot be used on non-blocking sockets.")
+  let sent = send(socket, cstring(data), data.len)
+  if sent < 0:
+    when defined(ssl):
+      if socket.isSSL:
+        raiseSslError()
+    
+    raiseOSError(osLastError())
+
+  if sent != data.len:
+    raise newException(OSError, "Could not send all data.")
+
+proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
+  ## sends data to a non-blocking socket.
+  ## Returns ``0`` if no data could be sent, if data has been sent
+  ## returns the amount of bytes of ``data`` that was successfully sent. This
+  ## number may not always be the length of ``data`` but typically is.
+  ##
+  ## An EOS (or ESSL if socket is an SSL socket) exception is raised if an error
+  ## occurs.
+  result = send(socket, cstring(data), data.len)
+  when defined(ssl):
+    if socket.isSSL:
+      if result <= 0:
+          let ret = SSLGetError(socket.sslHandle, result.cint)
+          case ret
+          of SSL_ERROR_ZERO_RETURN:
+            raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.")
+          of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT:
+            raiseSslError("Unexpected error occurred.") # This should just not happen.
+          of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ:
+            return 0
+          of SSL_ERROR_WANT_X509_LOOKUP:
+            raiseSslError("Function for x509 lookup has been called.")
+          of SSL_ERROR_SYSCALL, SSL_ERROR_SSL:
+            raiseSslError()
+          else: raiseSslError("Unknown Error")
+      else:
+        return
+  if result == -1:
+    let err = osLastError()
+    when defined(windows):
+      if err.int32 == WSAEINPROGRESS:
+        return 0
+      else: raiseOSError(err)
+    else:
+      if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
+        return 0
+      else: raiseOSError(err)
+  
+
+proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
+  ## safe alternative to ``send``. Does not raise an EOS when an error occurs,
+  ## and instead returns ``false`` on failure.
+  result = send(socket, cstring(data), data.len) == data.len
+
+proc sendTo*(socket: Socket, address: string, port: Port, data: pointer,
+             size: int, af: Domain = AF_INET, flags = 0'i32): int {.
+             tags: [WriteIOEffect].} =
+  ## low-level sendTo proc. This proc sends ``data`` to the specified ``address``,
+  ## which may be an IP address or a hostname, if a hostname is specified 
+  ## this function will try each IP of that hostname.
+  ##
+  ## **Note:** This proc is not available for SSL sockets.
+  var hints: AddrInfo
+  var aiList: ptr AddrInfo = nil
+  hints.ai_family = toInt(af)
+  hints.ai_socktype = toInt(SOCK_STREAM)
+  hints.ai_protocol = toInt(IPPROTO_TCP)
+  gaiNim(address, port, hints, aiList)
+  
+  # try all possibilities:
+  var success = false
+  var it = aiList
+  while it != nil:
+    result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
+                    it.ai_addrlen.SockLen)
+    if result != -1'i32:
+      success = true
+      break
+    it = it.ai_next
+
+  freeaddrinfo(aiList)
+
+proc sendTo*(socket: Socket, address: string, port: Port, 
+             data: string): int {.tags: [WriteIOEffect].} =
+  ## Friendlier version of the low-level ``sendTo``.
+  result = socket.sendTo(address, port, cstring(data), data.len)
+
+when defined(Windows):
+  const
+    IOCPARM_MASK = 127
+    IOC_IN = int(-2147483648)
+    FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or 
+                             (102 shl 8) or 126
+
+  proc ioctlsocket(s: SocketHandle, cmd: clong, 
+                   argptr: ptr clong): cint {.
+                   stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".}
+
+proc setBlocking(s: Socket, blocking: bool) =
+  when defined(Windows):
+    var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
+    if ioctlsocket(s.fd, FIONBIO, addr(mode)) == -1:
+      raiseOSError(osLastError())
+  else: # BSD sockets
+    var x: int = fcntl(s.fd, F_GETFL, 0)
+    if x == -1:
+      raiseOSError(osLastError())
+    else:
+      var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
+      if fcntl(s.fd, F_SETFL, mode) == -1:
+        raiseOSError(osLastError())
+  s.nonblocking = not blocking
+
+discard """ proc setReuseAddr*(s: Socket) =
+  var blah: int = 1
+  var mode = SO_REUSEADDR
+  if setsockopt(s.fd, SOL_SOCKET, mode, addr blah, TSOcklen(sizeof(int))) == -1:
+    raiseOSError(osLastError()) """
+
+proc connect*(socket: Socket, address: string, port = Port(0), timeout: int,
+             af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} =
+  ## Connects to server as specified by ``address`` on port specified by ``port``.
+  ##
+  ## The ``timeout`` paremeter specifies the time in milliseconds to allow for
+  ## the connection to the server to be made.
+  let originalStatus = not socket.nonblocking
+  socket.setBlocking(false)
+  
+  socket.connectAsync(address, port, af)
+  var s: seq[Socket] = @[socket]
+  if selectWrite(s, timeout) != 1:
+    raise newException(TimeoutError, "Call to 'connect' timed out.")
+  else:
+    when defined(ssl):
+      if socket.isSSL:
+        socket.setBlocking(true)
+        doAssert socket.handshake()
+  socket.setBlocking(originalStatus)
+
+proc isSSL*(socket: Socket): bool = return socket.isSSL
+  ## Determines whether ``socket`` is a SSL socket.
+
+proc getFD*(socket: Socket): SocketHandle = return socket.fd
+  ## Returns the socket's file descriptor
+
+proc isBlocking*(socket: Socket): bool = not socket.nonblocking
+  ## Determines whether ``socket`` is blocking.
+
+when defined(Windows):
+  var wsa: WSAData
+  if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError())
+
+
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
new file mode 100644
index 000000000..c85a09bad
--- /dev/null
+++ b/lib/pure/streams.nim
@@ -0,0 +1,464 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides a stream interface and two implementations thereof:
+## the `FileStream` and the `StringStream` which implement the stream
+## interface for Nim file objects (`File`) and strings. Other modules
+## may provide other implementations for this standard stream interface.
+
+include "system/inclrtl"
+
+proc newEIO(msg: string): ref IOError =
+  new(result)
+  result.msg = msg
+
+type
+  Stream* = ref StreamObj
+  StreamObj* = object of RootObj ## Stream interface that supports
+                                 ## writing or reading. Note that these fields
+                                 ## here shouldn't be used directly. They are
+                                 ## accessible so that a stream implementation
+                                 ## can override them.
+    closeImpl*: proc (s: Stream) {.nimcall, tags: [], gcsafe.}
+    atEndImpl*: proc (s: Stream): bool {.nimcall, tags: [], gcsafe.}
+    setPositionImpl*: proc (s: Stream, pos: int) {.nimcall, tags: [], gcsafe.}
+    getPositionImpl*: proc (s: Stream): int {.nimcall, tags: [], gcsafe.}
+    readDataImpl*: proc (s: Stream, buffer: pointer,
+                         bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.}
+    peekDataImpl*: proc (s: Stream, buffer: pointer,
+                         bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.}
+    writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) {.nimcall,
+      tags: [WriteIOEffect], gcsafe.}
+    flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.}
+
+{.deprecated: [PStream: Stream, TStream: StreamObj].}
+
+proc flush*(s: Stream) =
+  ## flushes the buffers that the stream `s` might use.
+  if not isNil(s.flushImpl): s.flushImpl(s)
+
+proc close*(s: Stream) =
+  ## closes the stream `s`.
+  if not isNil(s.closeImpl): s.closeImpl(s)
+
+proc close*(s, unused: Stream) {.deprecated.} =
+  ## closes the stream `s`.
+  s.closeImpl(s)
+
+proc atEnd*(s: Stream): bool =
+  ## checks if more data can be read from `f`. Returns true if all data has
+  ## been read.
+  result = s.atEndImpl(s)
+
+proc atEnd*(s, unused: Stream): bool {.deprecated.} =
+  ## checks if more data can be read from `f`. Returns true if all data has
+  ## been read.
+  result = s.atEndImpl(s)
+
+proc setPosition*(s: Stream, pos: int) =
+  ## sets the position `pos` of the stream `s`.
+  s.setPositionImpl(s, pos)
+
+proc setPosition*(s, unused: Stream, pos: int) {.deprecated.} =
+  ## sets the position `pos` of the stream `s`.
+  s.setPositionImpl(s, pos)
+
+proc getPosition*(s: Stream): int =
+  ## retrieves the current position in the stream `s`.
+  result = s.getPositionImpl(s)
+
+proc getPosition*(s, unused: Stream): int {.deprecated.} =
+  ## retrieves the current position in the stream `s`.
+  result = s.getPositionImpl(s)
+
+proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
+  ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
+  result = s.readDataImpl(s, buffer, bufLen)
+
+proc readData*(s, unused: Stream, buffer: pointer,
+               bufLen: int): int {.deprecated.} =
+  ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
+  result = s.readDataImpl(s, buffer, bufLen)
+
+proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
+  ## low level proc that reads data into an untyped `buffer` of `bufLen` size
+  ## without moving stream position
+  result = s.peekDataImpl(s, buffer, bufLen)
+
+proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
+  ## low level proc that writes an untyped `buffer` of `bufLen` size
+  ## to the stream `s`.
+  s.writeDataImpl(s, buffer, bufLen)
+
+proc writeData*(s, unused: Stream, buffer: pointer,
+                bufLen: int) {.deprecated.} =
+  ## low level proc that writes an untyped `buffer` of `bufLen` size
+  ## to the stream `s`.
+  s.writeDataImpl(s, buffer, bufLen)
+
+proc write*[T](s: Stream, x: T) =
+  ## generic write procedure. Writes `x` to the stream `s`. Implementation:
+  ##
+  ## .. code-block:: Nim
+  ##
+  ##     s.writeData(s, addr(x), sizeof(x))
+  var y: T
+  shallowCopy(y, x)
+  writeData(s, addr(y), sizeof(y))
+
+proc write*(s: Stream, x: string) =
+  ## writes the string `x` to the the stream `s`. No length field or
+  ## terminating zero is written.
+  writeData(s, cstring(x), x.len)
+
+proc writeln*(s: Stream, args: varargs[string, `$`]) =
+  ## writes one or more strings to the the stream `s` followed
+  ## by a new line. No length field or terminating zero is written.
+  for str in args: write(s, str)
+  write(s, "\n")
+
+proc read[T](s: Stream, result: var T) =
+  ## generic read procedure. Reads `result` from the stream `s`.
+  if readData(s, addr(result), sizeof(T)) != sizeof(T):
+    raise newEIO("cannot read from stream")
+
+proc peek[T](s: Stream, result: var T) =
+  ## generic peek procedure. Peeks `result` from the stream `s`.
+  if peekData(s, addr(result), sizeof(T)) != sizeof(T):
+    raise newEIO("cannot read from stream")
+
+proc readChar*(s: Stream): char =
+  ## reads a char from the stream `s`. Raises `EIO` if an error occurred.
+  ## Returns '\0' as an EOF marker.
+  if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
+
+proc peekChar*(s: Stream): char =
+  ## peeks a char from the stream `s`. Raises `EIO` if an error occurred.
+  ## Returns '\0' as an EOF marker.
+  if peekData(s, addr(result), sizeof(result)) != 1: result = '\0'
+
+proc readBool*(s: Stream): bool =
+  ## reads a bool from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekBool*(s: Stream): bool =
+  ## peeks a bool from the stream `s`. Raises `EIO` if an error occured.
+  peek(s, result)
+
+proc readInt8*(s: Stream): int8 =
+  ## reads an int8 from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekInt8*(s: Stream): int8 =
+  ## peeks an int8 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
+proc readInt16*(s: Stream): int16 =
+  ## reads an int16 from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekInt16*(s: Stream): int16 =
+  ## peeks an int16 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
+proc readInt32*(s: Stream): int32 =
+  ## reads an int32 from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekInt32*(s: Stream): int32 =
+  ## peeks an int32 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
+proc readInt64*(s: Stream): int64 =
+  ## reads an int64 from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekInt64*(s: Stream): int64 =
+  ## peeks an int64 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
+proc readFloat32*(s: Stream): float32 =
+  ## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekFloat32*(s: Stream): float32 =
+  ## peeks a float32 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
+proc readFloat64*(s: Stream): float64 =
+  ## reads a float64 from the stream `s`. Raises `EIO` if an error occurred.
+  read(s, result)
+
+proc peekFloat64*(s: Stream): float64 =
+  ## peeks a float64 from the stream `s`. Raises `EIO` if an error occurred.
+  peek(s, result)
+
+proc readStr*(s: Stream, length: int): TaintedString =
+  ## reads a string of length `length` from the stream `s`. Raises `EIO` if
+  ## an error occurred.
+  result = newString(length).TaintedString
+  var L = readData(s, addr(string(result)[0]), length)
+  if L != length: setLen(result.string, L)
+
+proc peekStr*(s: Stream, length: int): TaintedString =
+  ## peeks a string of length `length` from the stream `s`. Raises `EIO` if
+  ## an error occurred.
+  result = newString(length).TaintedString
+  var L = peekData(s, addr(string(result)[0]), length)
+  if L != length: setLen(result.string, L)
+
+proc readLine*(s: Stream, line: var TaintedString): bool =
+  ## reads a line of text from the stream `s` into `line`. `line` must not be
+  ## ``nil``! May throw an IO exception.
+  ## A line of text may be delimited by ``CR``, ``LF`` or
+  ## ``CRLF``. The newline character(s) are not part of the returned string.
+  ## Returns ``false`` if the end of the file has been reached, ``true``
+  ## otherwise. If ``false`` is returned `line` contains no new data.
+  line.string.setLen(0)
+  while true:
+    var c = readChar(s)
+    if c == '\c':
+      c = readChar(s)
+      break
+    elif c == '\L': break
+    elif c == '\0':
+      if line.len > 0: break
+      else: return false
+    line.string.add(c)
+  result = true
+
+proc peekLine*(s: Stream, line: var TaintedString): bool =
+  ## peeks a line of text from the stream `s` into `line`. `line` must not be
+  ## ``nil``! May throw an IO exception.
+  ## A line of text may be delimited by ``CR``, ``LF`` or
+  ## ``CRLF``. The newline character(s) are not part of the returned string.
+  ## Returns ``false`` if the end of the file has been reached, ``true``
+  ## otherwise. If ``false`` is returned `line` contains no new data.
+  let pos = getPosition(s)
+  defer: setPosition(s, pos)
+  result = readLine(s, line)
+
+proc readLine*(s: Stream): TaintedString =
+  ## Reads a line from a stream `s`. Note: This is not very efficient. Raises
+  ## `EIO` if an error occurred.
+  result = TaintedString""
+  while true:
+    var c = readChar(s)
+    if c == '\c':
+      c = readChar(s)
+      break
+    if c == '\L' or c == '\0':
+      break
+    else:
+      result.string.add(c)
+
+proc peekLine*(s: Stream): TaintedString =
+  ## Peeks a line from a stream `s`. Note: This is not very efficient. Raises
+  ## `EIO` if an error occurred.
+  let pos = getPosition(s)
+  defer: setPosition(s, pos)
+  result = readLine(s)
+
+type
+  StringStream* = ref StringStreamObj ## a stream that encapsulates a string
+  StringStreamObj* = object of StreamObj
+    data*: string
+    pos: int
+
+{.deprecated: [PStringStream: StringStream, TStringStream: StringStreamObj].}
+
+proc ssAtEnd(s: Stream): bool =
+  var s = StringStream(s)
+  return s.pos >= s.data.len
+
+proc ssSetPosition(s: Stream, pos: int) =
+  var s = StringStream(s)
+  s.pos = clamp(pos, 0, s.data.high)
+
+proc ssGetPosition(s: Stream): int =
+  var s = StringStream(s)
+  return s.pos
+
+proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int =
+  var s = StringStream(s)
+  result = min(bufLen, s.data.len - s.pos)
+  if result > 0:
+    copyMem(buffer, addr(s.data[s.pos]), result)
+    inc(s.pos, result)
+
+proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int =
+  var s = StringStream(s)
+  result = min(bufLen, s.data.len - s.pos)
+  if result > 0:
+    copyMem(buffer, addr(s.data[s.pos]), result)
+
+proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) =
+  var s = StringStream(s)
+  if bufLen <= 0:
+    return
+  if s.pos + bufLen > s.data.len:
+    setLen(s.data, s.pos + bufLen)
+  copyMem(addr(s.data[s.pos]), buffer, bufLen)
+  inc(s.pos, bufLen)
+
+proc ssClose(s: Stream) =
+  var s = StringStream(s)
+  s.data = nil
+
+proc newStringStream*(s: string = ""): StringStream =
+  ## creates a new stream from the string `s`.
+  new(result)
+  result.data = s
+  result.pos = 0
+  result.closeImpl = ssClose
+  result.atEndImpl = ssAtEnd
+  result.setPositionImpl = ssSetPosition
+  result.getPositionImpl = ssGetPosition
+  result.readDataImpl = ssReadData
+  result.peekDataImpl = ssPeekData
+  result.writeDataImpl = ssWriteData
+
+when not defined(js):
+
+  type
+    FileStream* = ref FileStreamObj ## a stream that encapsulates a `TFile`
+    FileStreamObj* = object of Stream
+      f: File
+  {.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].}
+
+  proc fsClose(s: Stream) =
+    if FileStream(s).f != nil:
+      close(FileStream(s).f)
+      FileStream(s).f = nil
+  proc fsFlush(s: Stream) = flushFile(FileStream(s).f)
+  proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f)
+  proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos)
+  proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f))
+
+  proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
+    result = readBuffer(FileStream(s).f, buffer, bufLen)
+
+  proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int =
+    let pos = fsGetPosition(s)
+    defer: fsSetPosition(s, pos)
+    result = readBuffer(FileStream(s).f, buffer, bufLen)
+
+  proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) =
+    if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
+      raise newEIO("cannot write to stream")
+
+  proc newFileStream*(f: File): FileStream =
+    ## creates a new stream from the file `f`.
+    new(result)
+    result.f = f
+    result.closeImpl = fsClose
+    result.atEndImpl = fsAtEnd
+    result.setPositionImpl = fsSetPosition
+    result.getPositionImpl = fsGetPosition
+    result.readDataImpl = fsReadData
+    result.peekDataImpl = fsPeekData
+    result.writeDataImpl = fsWriteData
+    result.flushImpl = fsFlush
+
+  proc newFileStream*(filename: string, mode: FileMode): FileStream =
+    ## creates a new stream from the file named `filename` with the mode `mode`.
+    ## If the file cannot be opened, nil is returned. See the `system
+    ## <system.html>`_ module for a list of available FileMode enums.
+    var f: File
+    if open(f, filename, mode): result = newFileStream(f)
+
+
+when true:
+  discard
+else:
+  type
+    FileHandleStream* = ref FileHandleStreamObj
+    FileHandleStreamObj* = object of Stream
+      handle*: FileHandle
+      pos: int
+
+  {.deprecated: [PFileHandleStream: FileHandleStream,
+     TFileHandleStream: FileHandleStreamObj].}
+
+  proc newEOS(msg: string): ref OSError =
+    new(result)
+    result.msg = msg
+
+  proc hsGetPosition(s: FileHandleStream): int =
+    return s.pos
+
+  when defined(windows):
+    # do not import windows as this increases compile times:
+    discard
+  else:
+    import posix
+
+    proc hsSetPosition(s: FileHandleStream, pos: int) =
+      discard lseek(s.handle, pos, SEEK_SET)
+
+    proc hsClose(s: FileHandleStream) = discard close(s.handle)
+    proc hsAtEnd(s: FileHandleStream): bool =
+      var pos = hsGetPosition(s)
+      var theEnd = lseek(s.handle, 0, SEEK_END)
+      result = pos >= theEnd
+      hsSetPosition(s, pos) # set position back
+
+    proc hsReadData(s: FileHandleStream, buffer: pointer, bufLen: int): int =
+      result = posix.read(s.handle, buffer, bufLen)
+      inc(s.pos, result)
+
+    proc hsPeekData(s: FileHandleStream, buffer: pointer, bufLen: int): int =
+      result = posix.read(s.handle, buffer, bufLen)
+
+    proc hsWriteData(s: FileHandleStream, buffer: pointer, bufLen: int) =
+      if posix.write(s.handle, buffer, bufLen) != bufLen:
+        raise newEIO("cannot write to stream")
+      inc(s.pos, bufLen)
+
+  proc newFileHandleStream*(handle: FileHandle): FileHandleStream =
+    new(result)
+    result.handle = handle
+    result.pos = 0
+    result.close = hsClose
+    result.atEnd = hsAtEnd
+    result.setPosition = hsSetPosition
+    result.getPosition = hsGetPosition
+    result.readData = hsReadData
+    result.peekData = hsPeekData
+    result.writeData = hsWriteData
+
+  proc newFileHandleStream*(filename: string,
+                            mode: FileMode): FileHandleStream =
+    when defined(windows):
+      discard
+    else:
+      var flags: cint
+      case mode
+      of fmRead:              flags = posix.O_RDONLY
+      of fmWrite:             flags = O_WRONLY or int(O_CREAT)
+      of fmReadWrite:         flags = O_RDWR or int(O_CREAT)
+      of fmReadWriteExisting: flags = O_RDWR
+      of fmAppend:            flags = O_WRONLY or int(O_CREAT) or O_APPEND
+      var handle = open(filename, flags)
+      if handle < 0: raise newEOS("posix.open() call failed")
+    result = newFileHandleStream(handle)
+
+when isMainModule and defined(testing):
+  var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran")
+  assert(ss.getPosition == 0)
+  assert(ss.peekStr(5) == "The q")
+  assert(ss.getPosition == 0) # haven't moved
+  assert(ss.readStr(5) == "The q")
+  assert(ss.getPosition == 5) # did move
+  assert(ss.peekLine() == "uick brown fox jumped over the lazy dog.")
+  assert(ss.getPosition == 5) # haven't moved
+  var str = newString(100)
+  assert(ss.peekLine(str))
+  assert(str == "uick brown fox jumped over the lazy dog.")
+  assert(ss.getPosition == 5) # haven't moved
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
new file mode 100644
index 000000000..7fdd994f2
--- /dev/null
+++ b/lib/pure/strtabs.nim
@@ -0,0 +1,250 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 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
+
+include "system/inclrtl"
+
+type
+  StringTableMode* = enum     ## describes the tables operation mode
+    modeCaseSensitive,        ## the table is case sensitive
+    modeCaseInsensitive,      ## the table is case insensitive
+    modeStyleInsensitive      ## the table is style insensitive
+  KeyValuePair = tuple[key, val: string]
+  KeyValuePairSeq = seq[KeyValuePair]
+  StringTableObj* = object of RootObj
+    counter: int
+    data: KeyValuePairSeq
+    mode: StringTableMode
+
+  StringTableRef* = ref StringTableObj ## use this type to declare string tables
+
+{.deprecated: [TStringTableMode: StringTableMode,
+  TStringTable: StringTableObj, PStringTable: StringTableRef].}
+
+proc len*(t: StringTableRef): int {.rtl, extern: "nst$1".} =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*(t: StringTableRef): tuple[key, value: string] =
+  ## iterates over every (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)
+
+iterator keys*(t: StringTableRef): string =
+  ## iterates over every key in the table `t`.
+  for h in 0..high(t.data):
+    if not isNil(t.data[h].key):
+      yield t.data[h].key
+
+iterator values*(t: StringTableRef): string =
+  ## iterates over every value in the table `t`.
+  for h in 0..high(t.data):
+    if not isNil(t.data[h].key):
+      yield t.data[h].val
+
+type
+  FormatFlag* = 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)
+
+{.deprecated: [TFormatFlag: FormatFlag].}
+
+# implementation
+
+const
+  growthFactor = 2
+  startSize = 64
+
+proc myhash(t: StringTableRef, 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: StringTableRef, 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)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+proc rawGet(t: StringTableRef, key: string): int =
+  var h: THash = 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: StringTableRef, key: string): string {.rtl, extern: "nstGet".} =
+  ## 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.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: result = ""
+
+proc mget*(t: StringTableRef, key: string): var string {.
+             rtl, extern: "nstTake".} =
+  ## retrieves the location at ``t[key]``. If `key` is not in `t`, the
+  ## ``KeyError`` exception is raised.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: raise newException(KeyError, "key does not exist: " & key)
+
+proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) =
+  var h: THash = 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: StringTableRef) =
+  var n: KeyValuePairSeq
+  newSeq(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: StringTableRef, key, val: string) {.rtl, extern: "nstPut".} =
+  ## puts a (key, value)-pair into `t`.
+  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 ValueError
+  new(e)
+  e.msg = "format string: key not found: " & s
+  raise e
+
+proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string =
+  if hasKey(t, key): return t[key]
+  # hm difficult: assume safety in taint mode here. XXX This is dangerous!
+  if useEnvironment in flags: result = os.getEnv(key).string
+  else: result = ""
+  if result.len == 0:
+    if useKey in flags: result = '$' & key
+    elif useEmpty notin flags: raiseFormatException(key)
+
+proc newStringTable*(mode: StringTableMode): StringTableRef {.
+  rtl, extern: "nst$1".} =
+  ## creates a new string table that is empty.
+  new(result)
+  result.mode = mode
+  result.counter = 0
+  newSeq(result.data, startSize)
+
+proc clear*(s: StringTableRef, mode: StringTableMode) =
+  ## resets a string table to be empty again.
+  s.mode = mode
+  s.counter = 0
+  s.data.setLen(startSize)
+
+proc newStringTable*(keyValuePairs: varargs[string],
+                     mode: StringTableMode): StringTableRef {.
+  rtl, extern: "nst$1WithPairs".} =
+  ## creates a new string table with given key value pairs.
+  ## Example::
+  ##   var mytab = newStringTable("key1", "val1", "key2", "val2",
+  ##                              modeCaseInsensitive)
+  result = newStringTable(mode)
+  var i = 0
+  while i < high(keyValuePairs):
+    result[keyValuePairs[i]] = keyValuePairs[i + 1]
+    inc(i, 2)
+
+proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]],
+                     mode: StringTableMode = modeCaseSensitive): StringTableRef {.
+  rtl, extern: "nst$1WithTableConstr".} =
+  ## creates a new string table with given key value pairs.
+  ## Example::
+  ##   var mytab = newStringTable({"key1": "val1", "key2": "val2"},
+  ##                              modeCaseInsensitive)
+  result = newStringTable(mode)
+  for key, val in items(keyValuePairs): result[key] = val
+
+proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {.
+  rtl, extern: "nstFormat".} =
+  ## The `%` operator for string tables.
+  const
+    PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF'}
+  result = ""
+  var i = 0
+  while i < len(f):
+    if f[i] == '$':
+      case f[i+1]
+      of '$':
+        add(result, '$')
+        inc(i, 2)
+      of '{':
+        var j = i + 1
+        while j < f.len and f[j] != '}': inc(j)
+        add(result, getValue(t, flags, substr(f, i+2, j-1)))
+        i = j + 1
+      of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_':
+        var j = i + 1
+        while j < f.len and f[j] in PatternChars: inc(j)
+        add(result, getValue(t, flags, substr(f, i+1, j-1)))
+        i = j
+      else:
+        add(result, f[i])
+        inc(i)
+    else:
+      add(result, f[i])
+      inc(i)
+
+proc `$`*(t: StringTableRef): string {.rtl, extern: "nstDollar".} =
+  ## The `$` operator for string tables.
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.add(key)
+      result.add(": ")
+      result.add(val)
+    result.add("}")
+
+when isMainModule:
+  var x = {"k": "v", "11": "22", "565": "67"}.newStringTable
+  assert x["k"] == "v"
+  assert x["11"] == "22"
+  assert x["565"] == "67"
+  x.mget("11") = "23"
+  assert x["11"] == "23"
+
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
new file mode 100644
index 000000000..eb4be719a
--- /dev/null
+++ b/lib/pure/strutils.nim
@@ -0,0 +1,1441 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains various string utility routines.
+## See the module `re <re.html>`_ for regular expression support.
+## See the module `pegs <pegs.html>`_ for PEG support.
+## This module is available for the `JavaScript target
+## <backends.html#the-javascript-target>`_.
+
+import parseutils
+
+{.deadCodeElim: on.}
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+include "system/inclrtl"
+
+type
+  TCharSet* {.deprecated.} = set[char] # for compatibility with Nim
+
+const
+  Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'}
+    ## All the characters that count as whitespace.
+
+  Letters* = {'A'..'Z', 'a'..'z'}
+    ## the set of letters
+
+  Digits* = {'0'..'9'}
+    ## the set of digits
+
+  HexDigits* = {'0'..'9', 'A'..'F', 'a'..'f'}
+    ## the set of hexadecimal digits
+
+  IdentChars* = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
+    ## the set of characters an identifier can consist of
+
+  IdentStartChars* = {'a'..'z', 'A'..'Z', '_'}
+    ## the set of characters an identifier can start with
+
+  NewLines* = {'\13', '\10'}
+    ## the set of characters a newline terminator can start with
+
+  AllChars* = {'\x00'..'\xFF'}
+    ## A set with all the possible characters.
+    ##
+    ## Not very useful by its own, you can use it to create *inverted* sets to
+    ## make the `find() proc <#find,string,set[char],int>`_ find **invalid**
+    ## characters in strings.  Example:
+    ##
+    ## .. code-block:: nim
+    ##   let invalid = AllChars - Digits
+    ##   doAssert "01234".find(invalid) == -1
+    ##   doAssert "01A34".find(invalid) == 2
+
+proc toLower*(c: char): char {.noSideEffect, procvar,
+  rtl, extern: "nsuToLowerChar".} =
+  ## Converts `c` into lower case.
+  ##
+  ## This works only for the letters ``A-Z``. See `unicode.toLower
+  ## <unicode.html#toLower>`_ for a version that works for any Unicode
+  ## character.
+  if c in {'A'..'Z'}:
+    result = chr(ord(c) + (ord('a') - ord('A')))
+  else:
+    result = c
+
+proc toLower*(s: string): string {.noSideEffect, procvar,
+  rtl, extern: "nsuToLowerStr".} =
+  ## Converts `s` into lower case.
+  ##
+  ## This works only for the letters ``A-Z``. See `unicode.toLower
+  ## <unicode.html#toLower>`_ for a version that works for any Unicode
+  ## character.
+  result = newString(len(s))
+  for i in 0..len(s) - 1:
+    result[i] = toLower(s[i])
+
+proc toUpper*(c: char): char {.noSideEffect, procvar,
+  rtl, extern: "nsuToUpperChar".} =
+  ## Converts `c` into upper case.
+  ##
+  ## This works only for the letters ``A-Z``.  See `unicode.toUpper
+  ## <unicode.html#toUpper>`_ for a version that works for any Unicode
+  ## character.
+  if c in {'a'..'z'}:
+    result = chr(ord(c) - (ord('a') - ord('A')))
+  else:
+    result = c
+
+proc toUpper*(s: string): string {.noSideEffect, procvar,
+  rtl, extern: "nsuToUpperStr".} =
+  ## Converts `s` into upper case.
+  ##
+  ## This works only for the letters ``A-Z``.  See `unicode.toUpper
+  ## <unicode.html#toUpper>`_ for a version that works for any Unicode
+  ## character.
+  result = newString(len(s))
+  for i in 0..len(s) - 1:
+    result[i] = toUpper(s[i])
+
+proc capitalize*(s: string): string {.noSideEffect, procvar,
+  rtl, extern: "nsuCapitalize".} =
+  ## Converts the first character of `s` into upper case.
+  ##
+  ## This works only for the letters ``A-Z``.
+  result = toUpper(s[0]) & substr(s, 1)
+
+proc normalize*(s: string): string {.noSideEffect, procvar,
+  rtl, extern: "nsuNormalize".} =
+  ## Normalizes the string `s`.
+  ##
+  ## That means to convert it to lower case and remove any '_'. This is needed
+  ## for Nim identifiers for example.
+  result = newString(s.len)
+  var j = 0
+  for i in 0..len(s) - 1:
+    if s[i] in {'A'..'Z'}:
+      result[j] = chr(ord(s[i]) + (ord('a') - ord('A')))
+      inc j
+    elif s[i] != '_':
+      result[j] = s[i]
+      inc j
+  if j != s.len: setLen(result, j)
+
+proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
+  rtl, extern: "nsuCmpIgnoreCase", procvar.} =
+  ## Compares two strings in a case insensitive manner. Returns:
+  ##
+  ## | 0 iff a == b
+  ## | < 0 iff a < b
+  ## | > 0 iff a > b
+  var i = 0
+  var m = min(a.len, b.len)
+  while i < m:
+    result = ord(toLower(a[i])) - ord(toLower(b[i]))
+    if result != 0: return
+    inc(i)
+  result = a.len - b.len
+
+{.push checks: off, line_trace: off .} # this is a hot-spot in the compiler!
+                                       # thus we compile without checks here
+
+proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
+  rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
+  ## Compares two strings normalized (i.e. case and
+  ## underscores do not matter). Returns:
+  ##
+  ## | 0 iff a == b
+  ## | < 0 iff a < b
+  ## | > 0 iff a > b
+  var i = 0
+  var j = 0
+  while true:
+    while a[i] == '_': inc(i)
+    while b[j] == '_': inc(j) # BUGFIX: typo
+    var aa = toLower(a[i])
+    var bb = toLower(b[j])
+    result = ord(aa) - ord(bb)
+    if result != 0 or aa == '\0': break
+    inc(i)
+    inc(j)
+
+{.pop.}
+
+proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string 
+  {.noSideEffect, rtl, extern: "nsuStrip".} =
+  ## Strips `chars` from `s` and returns the resulting string.
+  ##
+  ## If `leading` is true, leading `chars` are stripped.
+  ## If `trailing` is true, trailing `chars` are stripped.
+  var
+    first = 0
+    last = len(s)-1
+  if leading:
+    while s[first] in chars: inc(first)
+  if trailing:
+    while last >= 0 and s[last] in chars: dec(last)
+  result = substr(s, first, last)
+
+proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
+  ## Converts a character `c` to its octal representation.
+  ##
+  ## The resulting string may not have a leading zero. Its length is always
+  ## exactly 3.
+  result = newString(3)
+  var val = ord(c)
+  for i in countdown(2, 0):
+    result[i] = chr(val mod 8 + ord('0'))
+    val = val div 8
+
+iterator split*(s: string, seps: set[char] = Whitespace): string =
+  ## Splits the string `s` into substrings using a group of separators.
+  ##
+  ## Substrings are separated by a substring containing only `seps`. Note
+  ## that whole sequences of characters found in ``seps`` will be counted as
+  ## a single split point and leading/trailing separators will be ignored.
+  ## The following example:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split("  this is an  example  "):
+  ##     writeln(stdout, word)
+  ##
+  ## ...generates this output:
+  ##
+  ## .. code-block::
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   "example"
+  ##
+  ## And the following code:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split(";;this;is;an;;example;;;", {';'}):
+  ##     writeln(stdout, word)
+  ##
+  ## ...produces the same output as the first example. The code:
+  ##
+  ## .. code-block:: nim
+  ##   let date = "2012-11-20T22:08:08.398990"
+  ##   let separators = {' ', '-', ':', 'T'}
+  ##   for number in split(date, separators):
+  ##     writeln(stdout, number)
+  ##
+  ## ...results in:
+  ##
+  ## .. code-block::
+  ##   "2012"
+  ##   "11"
+  ##   "20"
+  ##   "22"
+  ##   "08"
+  ##   "08.398990"
+  ##
+  var last = 0
+  assert(not ('\0' in seps))
+  while last < len(s):
+    while s[last] in seps: inc(last)
+    var first = last
+    while last < len(s) and s[last] notin seps: inc(last) # BUGFIX!
+    if first <= last-1:
+      yield substr(s, first, last-1)
+
+iterator split*(s: string, sep: char): string =
+  ## Splits the string `s` into substrings using a single separator.
+  ##
+  ## Substrings are separated by the character `sep`.
+  ## Unlike the version of the iterator which accepts a set of separator
+  ## characters, this proc will not coalesce groups of the
+  ## separator, returning a string for each found character. The code:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split(";;this;is;an;;example;;;", ';'):
+  ##     writeln(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block::
+  ##   ""
+  ##   ""
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   ""
+  ##   "example"
+  ##   ""
+  ##   ""
+  ##   ""
+  ##
+  var last = 0
+  assert('\0' != sep)
+  if len(s) > 0:
+    # `<=` is correct here for the edge cases!
+    while last <= len(s):
+      var first = last
+      while last < len(s) and s[last] != sep: inc(last)
+      yield substr(s, first, last-1)
+      inc(last)
+
+iterator split*(s: string, sep: string): string =
+  ## Splits the string `s` into substrings using a string separator.
+  ##
+  ## Substrings are separated by the string `sep`.
+  var last = 0
+  if len(s) > 0:
+    while last <= len(s):
+      var first = last
+      while last < len(s) and s.substr(last, last + <sep.len) != sep:
+        inc(last)
+      yield substr(s, first, last-1)
+      inc(last, sep.len)
+
+iterator splitLines*(s: string): string =
+  ## Splits the string `s` into its containing lines.
+  ##
+  ## Every `character literal <manual.html#character-literals>`_ newline
+  ## combination (CR, LF, CR-LF) is supported. The result strings contain no
+  ## trailing ``\n``.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   for line in splitLines("\nthis\nis\nan\n\nexample\n"):
+  ##     writeln(stdout, line)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   ""
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   ""
+  ##   "example"
+  ##   ""
+  var first = 0
+  var last = 0
+  while true:
+    while s[last] notin {'\0', '\c', '\l'}: inc(last)
+    yield substr(s, first, last-1)
+    # skip newlines:
+    if s[last] == '\l': inc(last)
+    elif s[last] == '\c':
+      inc(last)
+      if s[last] == '\l': inc(last)
+    else: break # was '\0'
+    first = last
+
+proc splitLines*(s: string): seq[string] {.noSideEffect,
+  rtl, extern: "nsuSplitLines".} =
+  ## The same as the `splitLines <#splitLines.i,string>`_ iterator, but is a
+  ## proc that returns a sequence of substrings.
+  accumulateResult(splitLines(s))
+
+proc countLines*(s: string): int {.noSideEffect,
+  rtl, extern: "nsuCountLines".} =
+  ## Returns the number of new line separators in the string `s`.
+  ##
+  ## This is the same as ``len(splitLines(s))``, but much more efficient
+  ## because it doesn't modify the string creating temporal objects. Every
+  ## `character literal <manual.html#character-literals>`_ newline combination
+  ## (CR, LF, CR-LF) is supported.
+  ##
+  ## Despite its name this proc might not actually return the *number of lines*
+  ## in `s` because the concept of what a line is can vary. For example, a
+  ## string like ``Hello world`` is a line of text, but the proc will return a
+  ## value of zero because there are no newline separators.  Also, text editors
+  ## usually don't count trailing newline characters in a text file as a new
+  ## empty line, but this proc will.
+  var i = 0
+  while i < s.len:
+    case s[i]
+    of '\c':
+      if s[i+1] == '\l': inc i
+      inc result
+    of '\l': inc result
+    else: discard
+    inc i
+
+proc split*(s: string, seps: set[char] = Whitespace): seq[string] {.
+  noSideEffect, rtl, extern: "nsuSplitCharSet".} =
+  ## The same as the `split iterator <#split.i,string,set[char]>`_, but is a
+  ## proc that returns a sequence of substrings.
+  accumulateResult(split(s, seps))
+
+proc split*(s: string, sep: char): seq[string] {.noSideEffect,
+  rtl, extern: "nsuSplitChar".} =
+  ## The same as the `split iterator <#split.i,string,char>`_, but is a proc
+  ## that returns a sequence of substrings.
+  accumulateResult(split(s, sep))
+
+proc split*(s: string, sep: string): seq[string] {.noSideEffect,
+  rtl, extern: "nsuSplitString".} =
+  ## Splits the string `s` into substrings using a string separator.
+  ##
+  ## Substrings are separated by the string `sep`. This is a wrapper around the
+  ## `split iterator <#split.i,string,string>`_.
+  accumulateResult(split(s, sep))
+
+proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
+  rtl, extern: "nsuToHex".} =
+  ## Converts `x` to its hexadecimal representation.
+  ##
+  ## The resulting string will be exactly `len` characters long. No prefix like
+  ## ``0x`` is generated. `x` is treated as an unsigned value.
+  const
+    HexChars = "0123456789ABCDEF"
+  var
+    n = x
+  result = newString(len)
+  for j in countdown(len-1, 0):
+    result[j] = HexChars[n and 0xF]
+    n = n shr 4
+    # handle negative overflow
+    if n == 0 and x < 0: n = -1
+
+proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
+  rtl, extern: "nsuIntToStr".} =
+  ## Converts `x` to its decimal representation.
+  ##
+  ## The resulting string will be minimally `minchars` characters long. This is
+  ## achieved by adding leading zeros.
+  result = $abs(x)
+  for i in 1 .. minchars - len(result):
+    result = '0' & result
+  if x < 0:
+    result = '-' & result
+
+proc parseInt*(s: string): int {.noSideEffect, procvar,
+  rtl, extern: "nsuParseInt".} =
+  ## Parses a decimal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `ValueError` is raised.
+  var L = parseutils.parseInt(s, result, 0)
+  if L != s.len or L == 0:
+    raise newException(ValueError, "invalid integer: " & s)
+
+proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar,
+  rtl, extern: "nsuParseBiggestInt".} =
+  ## Parses a decimal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `ValueError` is raised.
+  var L = parseutils.parseBiggestInt(s, result, 0)
+  if L != s.len or L == 0:
+    raise newException(ValueError, "invalid integer: " & s)
+
+proc parseFloat*(s: string): float {.noSideEffect, procvar,
+  rtl, extern: "nsuParseFloat".} =
+  ## Parses a decimal floating point value contained in `s`. If `s` is not
+  ## a valid floating point number, `ValueError` is raised. ``NAN``,
+  ## ``INF``, ``-INF`` are also supported (case insensitive comparison).
+  var L = parseutils.parseFloat(s, result, 0)
+  if L != s.len or L == 0:
+    raise newException(ValueError, "invalid float: " & s)
+
+proc parseHexInt*(s: string): int {.noSideEffect, procvar,
+  rtl, extern: "nsuParseHexInt".} =
+  ## Parses a hexadecimal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `ValueError` is raised. `s` can have one
+  ## of the following optional prefixes: ``0x``, ``0X``, ``#``.  Underscores
+  ## within `s` are ignored.
+  var i = 0
+  if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
+  elif s[i] == '#': inc(i)
+  while true:
+    case s[i]
+    of '_': inc(i)
+    of '0'..'9':
+      result = result shl 4 or (ord(s[i]) - ord('0'))
+      inc(i)
+    of 'a'..'f':
+      result = result shl 4 or (ord(s[i]) - ord('a') + 10)
+      inc(i)
+    of 'A'..'F':
+      result = result shl 4 or (ord(s[i]) - ord('A') + 10)
+      inc(i)
+    of '\0': break
+    else: raise newException(ValueError, "invalid integer: " & s)
+
+proc parseBool*(s: string): bool =
+  ## Parses a value into a `bool`.
+  ##
+  ## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then
+  ## returns `true`. If ``s`` is one of the following values: ``n, no, false,
+  ## 0, off``, then returns `false`.  If ``s`` is something else a
+  ## ``ValueError`` exception is raised.
+  case normalize(s)
+  of "y", "yes", "true", "1", "on": result = true
+  of "n", "no", "false", "0", "off": result = false
+  else: raise newException(ValueError, "cannot interpret as a bool: " & s)
+
+proc parseEnum*[T: enum](s: string): T =
+  ## Parses an enum ``T``.
+  ##
+  ## Raises ``ValueError`` for an invalid value in `s`. The comparison is
+  ## done in a style insensitive way.
+  for e in low(T)..high(T):
+    if cmpIgnoreStyle(s, $e) == 0:
+      return e
+  raise newException(ValueError, "invalid enum value: " & s)
+
+proc parseEnum*[T: enum](s: string, default: T): T =
+  ## Parses an enum ``T``.
+  ##
+  ## Uses `default` for an invalid value in `s`. The comparison is done in a
+  ## style insensitive way.
+  for e in low(T)..high(T):
+    if cmpIgnoreStyle(s, $e) == 0:
+      return e
+  result = default
+
+proc repeat*(c: char, count: Natural): string {.noSideEffect,
+  rtl, extern: "nsuRepeatChar".} =
+  ## Returns a string of length `count` consisting only of
+  ## the character `c`. You can use this proc to left align strings. Example:
+  ##
+  ## .. code-block:: nim
+  ##   proc tabexpand(indent: int, text: string, tabsize: int = 4) =
+  ##     echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize), text
+  ##
+  ##   tabexpand(4, "At four")
+  ##   tabexpand(5, "At five")
+  ##   tabexpand(6, "At six")
+  result = newString(count)
+  for i in 0..count-1: result[i] = c
+
+proc repeat*(s: string, n: Natural): string {.noSideEffect,
+  rtl, extern: "nsuRepeatStr".} =
+  ## Returns String `s` concatenated `n` times.  Example:
+  ##
+  ## .. code-block:: nim
+  ##   echo "+++ STOP ".repeat(4), "+++"
+  result = newStringOfCap(n * s.len)
+  for i in 1..n: result.add(s)
+
+template spaces*(n: Natural): string =  repeat(' ',n)
+  ## Returns a String with `n` space characters. You can use this proc
+  ## to left align strings. Example:
+  ##
+  ## .. code-block:: nim
+  ##   let
+  ##     width = 15
+  ##     text1 = "Hello user!"
+  ##     text2 = "This is a very long string"
+  ##   echo text1 & spaces(max(0, width - text1.len)) & "|"
+  ##   echo text2 & spaces(max(0, width - text2.len)) & "|"
+
+proc repeatChar*(count: Natural, c: char = ' '): string {.deprecated.} = repeat(c, count)
+  ## deprecated: use repeat() or spaces()
+
+proc repeatStr*(count: Natural, s: string): string {.deprecated.} = repeat(s, count)
+  ## deprecated: use repeat(string, count) or string.repeat(count)
+
+proc align*(s: string, count: Natural, padding = ' '): string {.
+  noSideEffect, rtl, extern: "nsuAlignString".} =
+  ## Aligns a string `s` with `padding`, so that it is of length `count`.
+  ##
+  ## `padding` characters (by default spaces) are added before `s` resulting in
+  ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
+  ## returned unchanged. If you need to left align a string use the `repeatChar
+  ## proc <#repeatChar>`_. Example:
+  ##
+  ## .. code-block:: nim
+  ##   assert align("abc", 4) == " abc"
+  ##   assert align("a", 0) == "a"
+  ##   assert align("1232", 6) == "  1232"
+  ##   assert align("1232", 6, '#') == "##1232"
+  if s.len < count:
+    result = newString(count)
+    let spaces = count - s.len
+    for i in 0..spaces-1: result[i] = padding
+    for i in spaces..count-1: result[i] = s[i-spaces]
+  else:
+    result = s
+
+iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] =
+  ## Tokenizes the string `s` into substrings.
+  ##
+  ## Substrings are separated by a substring containing only `seps`.
+  ## Examples:
+  ##
+  ## .. code-block:: nim
+  ##   for word in tokenize("  this is an  example  "):
+  ##     writeln(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   ("  ", true)
+  ##   ("this", false)
+  ##   (" ", true)
+  ##   ("is", false)
+  ##   (" ", true)
+  ##   ("an", false)
+  ##   ("  ", true)
+  ##   ("example", false)
+  ##   ("  ", true)
+  var i = 0
+  while true:
+    var j = i
+    var isSep = s[j] in seps
+    while j < s.len and (s[j] in seps) == isSep: inc(j)
+    if j > i:
+      yield (substr(s, i, j-1), isSep)
+    else:
+      break
+    i = j
+
+proc wordWrap*(s: string, maxLineWidth = 80,
+               splitLongWords = true,
+               seps: set[char] = Whitespace,
+               newLine = "\n"): string {.
+               noSideEffect, rtl, extern: "nsuWordWrap".} =
+  ## Word wraps `s`.
+  result = newStringOfCap(s.len + s.len shr 6)
+  var spaceLeft = maxLineWidth
+  var lastSep = ""
+  for word, isSep in tokenize(s, seps):
+    if isSep:
+      lastSep = word
+      spaceLeft = spaceLeft - len(word)
+      continue
+    if len(word) > spaceLeft:
+      if splitLongWords and len(word) > maxLineWidth:
+        result.add(substr(word, 0, spaceLeft-1))
+        var w = spaceLeft+1
+        var wordLeft = len(word) - spaceLeft
+        while wordLeft > 0:
+          result.add(newLine)
+          var L = min(maxLineWidth, wordLeft)
+          spaceLeft = maxLineWidth - L
+          result.add(substr(word, w, w+L-1))
+          inc(w, L)
+          dec(wordLeft, L)
+      else:
+        spaceLeft = maxLineWidth - len(word)
+        result.add(newLine)
+        result.add(word)
+    else:
+      spaceLeft = spaceLeft - len(word)
+      result.add(lastSep & word)
+      lastSep.setLen(0)
+
+proc unindent*(s: string, eatAllIndent = false): string {.
+               noSideEffect, rtl, extern: "nsuUnindent".} =
+  ## Unindents `s`.
+  result = newStringOfCap(s.len)
+  var i = 0
+  var pattern = true
+  var indent = 0
+  while s[i] == ' ': inc i
+  var level = if i == 0: -1 else: i
+  while i < s.len:
+    if s[i] == ' ':
+      if i > 0 and s[i-1] in {'\l', '\c'}:
+        pattern = true
+        indent = 0
+      if pattern:
+        inc(indent)
+        if indent > level and not eatAllIndent:
+          result.add(s[i])
+        if level < 0: level = indent
+      else:
+        # a space somewhere: do not delete
+        result.add(s[i])
+    else:
+      pattern = false
+      result.add(s[i])
+    inc i
+
+proc startsWith*(s, prefix: string): bool {.noSideEffect,
+  rtl, extern: "nsuStartsWith".} =
+  ## Returns true iff ``s`` starts with ``prefix``.
+  ##
+  ## If ``prefix == ""`` true is returned.
+  var i = 0
+  while true:
+    if prefix[i] == '\0': return true
+    if s[i] != prefix[i]: return false
+    inc(i)
+
+proc endsWith*(s, suffix: string): bool {.noSideEffect,
+  rtl, extern: "nsuEndsWith".} =
+  ## Returns true iff ``s`` ends with ``suffix``.
+  ##
+  ## If ``suffix == ""`` true is returned.
+  var i = 0
+  var j = len(s) - len(suffix)
+  while i+j <% s.len:
+    if s[i+j] != suffix[i]: return false
+    inc(i)
+  if suffix[i] == '\0': return true
+
+proc continuesWith*(s, substr: string, start: Natural): bool {.noSideEffect,
+  rtl, extern: "nsuContinuesWith".} =
+  ## Returns true iff ``s`` continues with ``substr`` at position ``start``.
+  ##
+  ## If ``substr == ""`` true is returned.
+  var i = 0
+  while true:
+    if substr[i] == '\0': return true
+    if s[i+start] != substr[i]: return false
+    inc(i)
+
+proc addSep*(dest: var string, sep = ", ", startLen: Natural = 0)
+  {.noSideEffect, inline.} =
+  ## Adds a separator to `dest` only if its length is bigger than `startLen`.
+  ##
+  ## A shorthand for:
+  ##
+  ## .. code-block:: nim
+  ##   if dest.len > startLen: add(dest, sep)
+  ##
+  ## This is often useful for generating some code where the items need to
+  ## be *separated* by `sep`. `sep` is only added if `dest` is longer than
+  ## `startLen`. The following example creates a string describing
+  ## an array of integers:
+  ##
+  ## .. code-block:: nim
+  ##   var arr = "["
+  ##   for x in items([2, 3, 5, 7, 11]):
+  ##     addSep(arr, startLen=len("["))
+  ##     add(arr, $x)
+  ##   add(arr, "]")
+  if dest.len > startLen: add(dest, sep)
+
+proc allCharsInSet*(s: string, theSet: set[char]): bool =
+  ## Returns true iff each character of `s` is in the set `theSet`.
+  for c in items(s):
+    if c notin theSet: return false
+  return true
+
+proc abbrev*(s: string, possibilities: openArray[string]): int =
+  ## Returns the index of the first item in `possibilities` if not ambiguous.
+  ##
+  ## Returns -1 if no item has been found and -2 if multiple items match.
+  result = -1 # none found
+  for i in 0..possibilities.len-1:
+    if possibilities[i].startsWith(s):
+      if possibilities[i] == s:
+        # special case: exact match shouldn't be ambiguous
+        return i
+      if result >= 0: return -2 # ambiguous
+      result = i
+
+# ---------------------------------------------------------------------------
+
+proc join*(a: openArray[string], sep: string): string {.
+  noSideEffect, rtl, extern: "nsuJoinSep".} =
+  ## Concatenates all strings in `a` separating them with `sep`.
+  if len(a) > 0:
+    var L = sep.len * (a.len-1)
+    for i in 0..high(a): inc(L, a[i].len)
+    result = newStringOfCap(L)
+    add(result, a[0])
+    for i in 1..high(a):
+      add(result, sep)
+      add(result, a[i])
+  else:
+    result = ""
+
+proc join*(a: openArray[string]): string {.
+  noSideEffect, rtl, extern: "nsuJoin".} =
+  ## Concatenates all strings in `a`.
+  if len(a) > 0:
+    var L = 0
+    for i in 0..high(a): inc(L, a[i].len)
+    result = newStringOfCap(L)
+    for i in 0..high(a): add(result, a[i])
+  else:
+    result = ""
+
+type
+  SkipTable = array[char, int]
+
+proc preprocessSub(sub: string, a: var SkipTable) =
+  var m = len(sub)
+  for i in 0..0xff: a[chr(i)] = m+1
+  for i in 0..m-1: a[sub[i]] = m-i
+
+proc findAux(s, sub: string, start: int, a: SkipTable): int =
+  # Fast "quick search" algorithm:
+  var
+    m = len(sub)
+    n = len(s)
+  # search:
+  var j = start
+  while j <= n - m:
+    block match:
+      for k in 0..m-1:
+        if sub[k] != s[k+j]: break match
+      return j
+    inc(j, a[s[j+m]])
+  return -1
+
+proc find*(s, sub: string, start: Natural = 0): int {.noSideEffect,
+  rtl, extern: "nsuFindStr".} =
+  ## Searches for `sub` in `s` starting at position `start`.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  var a {.noinit.}: SkipTable
+  preprocessSub(sub, a)
+  result = findAux(s, sub, start, a)
+
+proc find*(s: string, sub: char, start: Natural = 0): int {.noSideEffect,
+  rtl, extern: "nsuFindChar".} =
+  ## Searches for `sub` in `s` starting at position `start`.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  for i in start..len(s)-1:
+    if sub == s[i]: return i
+  return -1
+
+proc find*(s: string, chars: set[char], start: Natural = 0): int {.noSideEffect,
+  rtl, extern: "nsuFindCharSet".} =
+  ## Searches for `chars` in `s` starting at position `start`.
+  ##
+  ## If `s` contains none of the characters in `chars`, -1 is returned.
+  for i in start..s.len-1:
+    if s[i] in chars: return i
+  return -1
+
+proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
+  ## Searches for `sub` in `s` in reverse, starting at `start` and going
+  ## backwards to 0.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  let realStart = if start == -1: s.len else: start
+  for i in countdown(realStart-sub.len, 0):
+    for j in 0..sub.len-1:
+      result = i
+      if sub[j] != s[i+j]:
+        result = -1
+        break
+    if result != -1: return
+  return -1
+
+proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect,
+  rtl.} =
+  ## Searches for `sub` in `s` in reverse starting at position `start`.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  let realStart = if start == -1: s.len-1 else: start
+  for i in countdown(realStart, 0):
+    if sub == s[i]: return i
+  return -1
+
+proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect,
+  rtl, extern: "nsuCountString".} =
+  ## Count the occurrences of a substring `sub` in the string `s`.
+  ## Overlapping occurrences of `sub` only count when `overlapping`
+  ## is set to true.
+  var i = 0
+  while true:
+    i = s.find(sub, i)
+    if i < 0:
+      break
+    if overlapping:
+      inc i
+    else:
+      i += sub.len
+    inc result
+
+proc count*(s: string, sub: char): int {.noSideEffect,
+  rtl, extern: "nsuCountChar".} =
+  ## Count the occurrences of the character `sub` in the string `s`.
+  for c in s:
+    if c == sub:
+      inc result
+
+proc count*(s: string, subs: set[char]): int {.noSideEffect,
+  rtl, extern: "nsuCountCharSet".} =
+  ## Count the occurrences of the group of character `subs` in the string `s`.
+  for c in s:
+    if c in subs:
+      inc result
+
+proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
+  ## Returns ``'"' & s & '"'`` if `s` contains a space and does not
+  ## start with a quote, else returns `s`.
+  ##
+  ## **DEPRECATED** as it was confused for shell quoting function.  For this
+  ## application use `osproc.quoteShell <osproc.html#quoteShell>`_.
+  if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
+    result = '"' & s & '"'
+  else:
+    result = s
+
+proc contains*(s: string, c: char): bool {.noSideEffect.} =
+  ## Same as ``find(s, c) >= 0``.
+  return find(s, c) >= 0
+
+proc contains*(s, sub: string): bool {.noSideEffect.} =
+  ## Same as ``find(s, sub) >= 0``.
+  return find(s, sub) >= 0
+
+proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
+  ## Same as ``find(s, chars) >= 0``.
+  return find(s, chars) >= 0
+
+proc replace*(s, sub: string, by = ""): string {.noSideEffect,
+  rtl, extern: "nsuReplaceStr".} =
+  ## Replaces `sub` in `s` by the string `by`.
+  var a {.noinit.}: SkipTable
+  result = ""
+  preprocessSub(sub, a)
+  var i = 0
+  while true:
+    var j = findAux(s, sub, i, a)
+    if j < 0: break
+    add result, substr(s, i, j - 1)
+    add result, by
+    i = j + len(sub)
+  # copy the rest:
+  add result, substr(s, i)
+
+proc replace*(s: string, sub, by: char): string {.noSideEffect,
+  rtl, extern: "nsuReplaceChar".} =
+  ## Replaces `sub` in `s` by the character `by`.
+  ##
+  ## Optimized version of `replace <#replace,string,string>`_ for characters.
+  result = newString(s.len)
+  var i = 0
+  while i < s.len:
+    if s[i] == sub: result[i] = by
+    else: result[i] = s[i]
+    inc(i)
+
+proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
+  rtl, extern: "nsuReplaceWord".} =
+  ## Replaces `sub` in `s` by the string `by`.
+  ##
+  ## Each occurrence of `sub` has to be surrounded by word boundaries
+  ## (comparable to ``\\w`` in regular expressions), otherwise it is not
+  ## replaced.
+  const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
+  var a {.noinit.}: SkipTable
+  result = ""
+  preprocessSub(sub, a)
+  var i = 0
+  while true:
+    var j = findAux(s, sub, i, a)
+    if j < 0: break
+    # word boundary?
+    if (j == 0 or s[j-1] notin wordChars) and
+        (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
+      add result, substr(s, i, j - 1)
+      add result, by
+      i = j + len(sub)
+    else:
+      add result, substr(s, i, j)
+      i = j + 1
+  # copy the rest:
+  add result, substr(s, i)
+
+proc delete*(s: var string, first, last: int) {.noSideEffect,
+  rtl, extern: "nsuDelete".} =
+  ## Deletes in `s` the characters at position `first` .. `last`.
+  ##
+  ## This modifies `s` itself, it does not return a copy.
+  var i = first
+  var j = last+1
+  var newLen = len(s)-j+i
+  while i < newLen:
+    s[i] = s[j]
+    inc(i)
+    inc(j)
+  setLen(s, newLen)
+
+proc parseOctInt*(s: string): int {.noSideEffect,
+  rtl, extern: "nsuParseOctInt".} =
+  ## Parses an octal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `ValueError` is raised. `s` can have one
+  ## of the following optional prefixes: ``0o``, ``0O``.  Underscores within
+  ## `s` are ignored.
+  var i = 0
+  if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
+  while true:
+    case s[i]
+    of '_': inc(i)
+    of '0'..'7':
+      result = result shl 3 or (ord(s[i]) - ord('0'))
+      inc(i)
+    of '\0': break
+    else: raise newException(ValueError, "invalid integer: " & s)
+
+proc toOct*(x: BiggestInt, len: Positive): string {.noSideEffect,
+  rtl, extern: "nsuToOct".} =
+  ## Converts `x` into its octal representation.
+  ##
+  ## The resulting string is always `len` characters long. No leading ``0o``
+  ## prefix is generated.
+  var
+    mask: BiggestInt = 7
+    shift: BiggestInt = 0
+  assert(len > 0)
+  result = newString(len)
+  for j in countdown(len-1, 0):
+    result[j] = chr(int((x and mask) shr shift) + ord('0'))
+    shift = shift + 3
+    mask = mask shl 3
+
+proc toBin*(x: BiggestInt, len: Positive): string {.noSideEffect,
+  rtl, extern: "nsuToBin".} =
+  ## Converts `x` into its binary representation.
+  ##
+  ## The resulting string is always `len` characters long. No leading ``0b``
+  ## prefix is generated.
+  var
+    mask: BiggestInt = 1
+    shift: BiggestInt = 0
+  assert(len > 0)
+  result = newString(len)
+  for j in countdown(len-1, 0):
+    result[j] = chr(int((x and mask) shr shift) + ord('0'))
+    shift = shift + 1
+    mask = mask shl 1
+
+proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,
+  rtl, extern: "nsuInsertSep".} =
+  ## Inserts the separator `sep` after `digits` digits from right to left.
+  ##
+  ## Even though the algorithm works with any string `s`, it is only useful
+  ## if `s` contains a number.
+  ## Example: ``insertSep("1000000") == "1_000_000"``
+  var L = (s.len-1) div digits + s.len
+  result = newString(L)
+  var j = 0
+  dec(L)
+  for i in countdown(len(s)-1, 0):
+    if j == digits:
+      result[L] = sep
+      dec(L)
+      j = 0
+    result[L] = s[i]
+    inc(j)
+    dec(L)
+
+proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
+  rtl, extern: "nsuEscape".} =
+  ## Escapes a string `s`.
+  ##
+  ## This does these operations (at the same time):
+  ## * replaces any ``\`` by ``\\``
+  ## * replaces any ``'`` by ``\'``
+  ## * replaces any ``"`` by ``\"``
+  ## * replaces any other character in the set ``{'\0'..'\31', '\128'..'\255'}``
+  ##   by ``\xHH`` where ``HH`` is its hexadecimal value.
+  ## The procedure has been designed so that its output is usable for many
+  ## different common syntaxes. The resulting string is prefixed with
+  ## `prefix` and suffixed with `suffix`. Both may be empty strings.
+  result = newStringOfCap(s.len + s.len shr 2)
+  result.add(prefix)
+  for c in items(s):
+    case c
+    of '\0'..'\31', '\128'..'\255':
+      add(result, "\\x")
+      add(result, toHex(ord(c), 2))
+    of '\\': add(result, "\\\\")
+    of '\'': add(result, "\\'")
+    of '\"': add(result, "\\\"")
+    else: add(result, c)
+  add(result, suffix)
+
+proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
+  rtl, extern: "nsuUnescape".} =
+  ## Unescapes a string `s`.
+  ##
+  ## This complements `escape <#escape>`_ as it performs the opposite
+  ## operations.
+  ##
+  ## If `s` does not begin with ``prefix`` and end with ``suffix`` a
+  ## ValueError exception will be raised.
+  result = newStringOfCap(s.len)
+  var i = 0
+  if not s.startsWith(prefix):
+    raise newException(ValueError,
+                       "String does not start with a prefix of: " & prefix)
+  inc(i)
+  while true:
+    if i == s.len-suffix.len: break
+    case s[i]
+    of '\\':
+      case s[i+1]:
+      of 'x':
+        inc i
+        var c: int
+        i += parseutils.parseHex(s, c, i)
+        result.add(chr(c))
+        inc(i, 2)
+      of '\\':
+        result.add('\\')
+      of '\'':
+        result.add('\'')
+      of '\"':
+        result.add('\"')
+      else: result.add("\\" & s[i+1])
+      inc(i)
+    of '\0': break
+    else:
+      result.add(s[i])
+    inc(i)
+  if not s.endsWith(suffix):
+    raise newException(ValueError,
+                       "String does not end with a suffix of: " & suffix)
+
+proc validIdentifier*(s: string): bool {.noSideEffect,
+  rtl, extern: "nsuValidIdentifier".} =
+  ## Returns true if `s` is a valid identifier.
+  ##
+  ## A valid identifier starts with a character of the set `IdentStartChars`
+  ## and is followed by any number of characters of the set `IdentChars`.
+  if s[0] in IdentStartChars:
+    for i in 1..s.len-1:
+      if s[i] notin IdentChars: return false
+    return true
+
+proc editDistance*(a, b: string): int {.noSideEffect,
+  rtl, extern: "nsuEditDistance".} =
+  ## Returns the edit distance between `a` and `b`.
+  ##
+  ## This uses the `Levenshtein`:idx: distance algorithm with only a linear
+  ## memory overhead.  This implementation is highly optimized!
+  var len1 = a.len
+  var len2 = b.len
+  if len1 > len2:
+    # make `b` the longer string
+    return editDistance(b, a)
+
+  # strip common prefix:
+  var s = 0
+  while a[s] == b[s] and a[s] != '\0':
+    inc(s)
+    dec(len1)
+    dec(len2)
+  # strip common suffix:
+  while len1 > 0 and len2 > 0 and a[s+len1-1] == b[s+len2-1]:
+    dec(len1)
+    dec(len2)
+  # trivial cases:
+  if len1 == 0: return len2
+  if len2 == 0: return len1
+
+  # another special case:
+  if len1 == 1:
+    for j in s..len2-1:
+      if a[s] == b[j]: return len2 - 1
+    return len2
+
+  inc(len1)
+  inc(len2)
+  var half = len1 shr 1
+  # initalize first row:
+  #var row = cast[ptr array[0..high(int) div 8, int]](alloc(len2*sizeof(int)))
+  var row: seq[int]
+  newSeq(row, len2)
+  var e = s + len2 - 1 # end marker
+  for i in 1..len2 - half - 1: row[i] = i
+  row[0] = len1 - half - 1
+  for i in 1 .. len1 - 1:
+    var char1 = a[i + s - 1]
+    var char2p: int
+    var D, x: int
+    var p: int
+    if i >= len1 - half:
+      # skip the upper triangle:
+      var offset = i - len1 + half
+      char2p = offset
+      p = offset
+      var c3 = row[p] + ord(char1 != b[s + char2p])
+      inc(p)
+      inc(char2p)
+      x = row[p] + 1
+      D = x
+      if x > c3: x = c3
+      row[p] = x
+      inc(p)
+    else:
+      p = 1
+      char2p = 0
+      D = i
+      x = i
+    if i <= half + 1:
+      # skip the lower triangle:
+      e = len2 + i - half - 2
+    # main:
+    while p <= e:
+      dec(D)
+      var c3 = D + ord(char1 != b[char2p + s])
+      inc(char2p)
+      inc(x)
+      if x > c3: x = c3
+      D = row[p] + 1
+      if x > D: x = D
+      row[p] = x
+      inc(p)
+    # lower triangle sentinel:
+    if i <= half:
+      dec(D)
+      var c3 = D + ord(char1 != b[char2p + s])
+      inc(x)
+      if x > c3: x = c3
+      row[p] = x
+  result = row[e]
+  #dealloc(row)
+
+
+# floating point formating:
+
+proc c_sprintf(buf, frmt: cstring) {.header: "<stdio.h>", importc: "sprintf",
+                                     varargs, noSideEffect.}
+
+type
+  FloatFormatMode* = enum ## the different modes of floating point formating
+    ffDefault,         ## use the shorter floating point notation
+    ffDecimal,         ## use decimal floating point notation
+    ffScientific       ## use scientific notation (using ``e`` character)
+
+{.deprecated: [TFloatFormat: FloatFormatMode].}
+
+proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
+                         precision: range[0..32] = 16): string {.
+                         noSideEffect, rtl, extern: "nsu$1".} =
+  ## Converts a floating point value `f` to a string.
+  ##
+  ## If ``format == ffDecimal`` then precision is the number of digits to
+  ## be printed after the decimal point.
+  ## If ``format == ffScientific`` then precision is the maximum number
+  ## of significant digits to be printed.
+  ## `precision`'s default value is the maximum number of meaningful digits
+  ## after the decimal point for Nim's ``biggestFloat`` type.
+  ##
+  ## If ``precision == 0``, it tries to format it nicely.
+  const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
+  var
+    frmtstr {.noinit.}: array[0..5, char]
+    buf {.noinit.}: array[0..2500, char]
+  frmtstr[0] = '%'
+  if precision > 0:
+    frmtstr[1] = '#'
+    frmtstr[2] = '.'
+    frmtstr[3] = '*'
+    frmtstr[4] = floatFormatToChar[format]
+    frmtstr[5] = '\0'
+    c_sprintf(buf, frmtstr, precision, f)
+  else:
+    frmtstr[1] = floatFormatToChar[format]
+    frmtstr[2] = '\0'
+    c_sprintf(buf, frmtstr, f)
+  result = $buf
+
+proc formatFloat*(f: float, format: FloatFormatMode = ffDefault,
+                  precision: range[0..32] = 16): string {.
+                  noSideEffect, rtl, extern: "nsu$1".} =
+  ## Converts a floating point value `f` to a string.
+  ##
+  ## If ``format == ffDecimal`` then precision is the number of digits to
+  ## be printed after the decimal point.
+  ## If ``format == ffScientific`` then precision is the maximum number
+  ## of significant digits to be printed.
+  ## `precision`'s default value is the maximum number of meaningful digits
+  ## after the decimal point for Nim's ``float`` type.
+  result = formatBiggestFloat(f, format, precision)
+
+proc formatSize*(bytes: BiggestInt, decimalSep = '.'): string =
+  ## Rounds and formats `bytes`. Examples:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##    formatSize(1'i64 shl 31 + 300'i64) == "2.204GB"
+  ##    formatSize(4096) == "4KB"
+  ##
+  template frmt(a, b, c: expr): expr =
+    let bs = $b
+    insertSep($a) & decimalSep & bs.substr(0, 2) & c
+  let gigabytes = bytes shr 30
+  let megabytes = bytes shr 20
+  let kilobytes = bytes shr 10
+  if gigabytes != 0:
+    result = frmt(gigabytes, megabytes, "GB")
+  elif megabytes != 0:
+    result = frmt(megabytes, kilobytes, "MB")
+  elif kilobytes != 0:
+    result = frmt(kilobytes, bytes, "KB")
+  else:
+    result = insertSep($bytes) & "B"
+
+proc findNormalized(x: string, inArray: openArray[string]): int =
+  var i = 0
+  while i < high(inArray):
+    if cmpIgnoreStyle(x, inArray[i]) == 0: return i
+    inc(i, 2) # incrementing by 1 would probably lead to a
+              # security hole...
+  return -1
+
+proc invalidFormatString() {.noinline.} =
+  raise newException(ValueError, "invalid format string")
+
+proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
+  noSideEffect, rtl, extern: "nsuAddf".} =
+  ## The same as ``add(s, formatstr % a)``, but more efficient.
+  const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
+  var i = 0
+  var num = 0
+  while i < len(formatstr):
+    if formatstr[i] == '$':
+      case formatstr[i+1] # again we use the fact that strings
+                          # are zero-terminated here
+      of '#':
+        if num >% a.high: invalidFormatString()
+        add s, a[num]
+        inc i, 2
+        inc num
+      of '$':
+        add s, '$'
+        inc(i, 2)
+      of '1'..'9', '-':
+        var j = 0
+        inc(i) # skip $
+        var negative = formatstr[i] == '-'
+        if negative: inc i
+        while formatstr[i] in Digits:
+          j = j * 10 + ord(formatstr[i]) - ord('0')
+          inc(i)
+        let idx = if not negative: j-1 else: a.len-j
+        if idx >% a.high: invalidFormatString()
+        add s, a[idx]
+      of '{':
+        var j = i+1
+        while formatstr[j] notin {'\0', '}'}: inc(j)
+        var x = findNormalized(substr(formatstr, i+2, j-1), a)
+        if x >= 0 and x < high(a): add s, a[x+1]
+        else: invalidFormatString()
+        i = j+1
+      of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
+        var j = i+1
+        while formatstr[j] in PatternChars: inc(j)
+        var x = findNormalized(substr(formatstr, i+1, j-1), a)
+        if x >= 0 and x < high(a): add s, a[x+1]
+        else: invalidFormatString()
+        i = j
+      else:
+        invalidFormatString()
+    else:
+      add s, formatstr[i]
+      inc(i)
+
+proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect,
+  rtl, extern: "nsuFormatOpenArray".} =
+  ## Interpolates a format string with the values from `a`.
+  ##
+  ## The `substitution`:idx: operator performs string substitutions in
+  ## `formatstr` and returns a modified `formatstr`. This is often called
+  ## `string interpolation`:idx:.
+  ##
+  ## This is best explained by an example:
+  ##
+  ## .. code-block:: nim
+  ##   "$1 eats $2." % ["The cat", "fish"]
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   "The cat eats fish."
+  ##
+  ## The substitution variables (the thing after the ``$``) are enumerated
+  ## from 1 to ``a.len``.
+  ## To produce a verbatim ``$``, use ``$$``.
+  ## The notation ``$#`` can be used to refer to the next substitution
+  ## variable:
+  ##
+  ## .. code-block:: nim
+  ##   "$# eats $#." % ["The cat", "fish"]
+  ##
+  ## Substitution variables can also be words (that is
+  ## ``[A-Za-z_]+[A-Za-z0-9_]*``) in which case the arguments in `a` with even
+  ## indices are keys and with odd indices are the corresponding values.
+  ## An example:
+  ##
+  ## .. code-block:: nim
+  ##   "$animal eats $food." % ["animal", "The cat", "food", "fish"]
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   "The cat eats fish."
+  ##
+  ## The variables are compared with `cmpIgnoreStyle`. `ValueError` is
+  ## raised if an ill-formed format string has been passed to the `%` operator.
+  result = newStringOfCap(formatstr.len + a.len shl 4)
+  addf(result, formatstr, a)
+
+proc `%` *(formatstr, a: string): string {.noSideEffect,
+  rtl, extern: "nsuFormatSingleElem".} =
+  ## This is the same as ``formatstr % [a]``.
+  result = newStringOfCap(formatstr.len + a.len)
+  addf(result, formatstr, [a])
+
+proc format*(formatstr: string, a: varargs[string, `$`]): string {.noSideEffect,
+  rtl, extern: "nsuFormatVarargs".} =
+  ## This is the same as ``formatstr % a`` except that it supports
+  ## auto stringification.
+  result = newStringOfCap(formatstr.len + a.len)
+  addf(result, formatstr, a)
+
+{.pop.}
+
+when isMainModule:
+  doAssert align("abc", 4) == " abc"
+  doAssert align("a", 0) == "a"
+  doAssert align("1232", 6) == "  1232"
+  doAssert align("1232", 6, '#') == "##1232"
+
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+               it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  doAssert wordWrap(inp, 10, false) == outp
+
+  doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
+  doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) in
+                                                   ["1.0e-11", "1.0e-011"]
+
+  doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
+  when not defined(testing):
+    echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
+    echo formatSize(1'i64 shl 31)
+
+  doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
+           "The cat eats fish."
+
+  doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
+  doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
+
+  type MyEnum = enum enA, enB, enC, enuD, enE
+  doAssert parseEnum[MyEnum]("enu_D") == enuD
+
+  doAssert parseEnum("invalid enum value", enC) == enC
+
+  doAssert count("foofoofoo", "foofoo") == 1
+  doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
+  doAssert count("foofoofoo", 'f') == 3
+  doAssert count("foofoofoobar", {'f','b'}) == 4
+
+  doAssert strip("  foofoofoo  ") == "foofoofoo"
+  doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+  doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+  doAssert strip("stripme but don't strip this stripme",
+                 chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this "
+  doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+  doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
new file mode 100644
index 000000000..d213c99e6
--- /dev/null
+++ b/lib/pure/subexes.nim
@@ -0,0 +1,411 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nim support for `substitution expressions`:idx: (`subex`:idx:).
+##
+## .. include:: ../doc/subexes.txt
+##
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+from strutils import parseInt, cmpIgnoreStyle, Digits
+include "system/inclrtl"
+
+
+proc findNormalized(x: string, inArray: openarray[string]): int =
+  var i = 0
+  while i < high(inArray):
+    if cmpIgnoreStyle(x, inArray[i]) == 0: return i
+    inc(i, 2) # incrementing by 1 would probably lead to a
+              # security hole...
+  return -1
+
+type
+  SubexError* = object of ValueError ## exception that is raised for
+                                     ## an invalid subex
+
+{.deprecated: [EInvalidSubex: SubexError].}
+
+proc raiseInvalidFormat(msg: string) {.noinline.} =
+  raise newException(SubexError, "invalid format string: " & msg)
+
+type
+  TFormatParser = object {.pure, final.}
+    when defined(js):
+      f: string # we rely on the '\0' terminator
+                # which JS's native string doesn't have
+    else:
+      f: cstring
+    num, i, lineLen: int
+
+template call(x: stmt) {.immediate.} =
+  p.i = i
+  x
+  i = p.i
+
+template callNoLineLenTracking(x: stmt) {.immediate.} =
+  let oldLineLen = p.lineLen
+  p.i = i
+  x
+  i = p.i
+  p.lineLen = oldLineLen
+
+proc getFormatArg(p: var TFormatParser, a: openArray[string]): int =
+  const PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\128'..'\255', '_'}
+  var i = p.i
+  var f = p.f
+  case f[i]
+  of '#':
+    result = p.num
+    inc i
+    inc p.num
+  of '1'..'9', '-':
+    var j = 0
+    var negative = f[i] == '-'
+    if negative: inc i
+    while f[i] in Digits:
+      j = j * 10 + ord(f[i]) - ord('0')
+      inc i
+    result = if not negative: j-1 else: a.len-j
+  of 'a'..'z', 'A'..'Z', '\128'..'\255', '_':
+    var name = ""
+    while f[i] in PatternChars: 
+      name.add(f[i])
+      inc(i)
+    result = findNormalized(name, a)+1
+  of '$':
+    inc(i)
+    call:
+      result = getFormatArg(p, a)
+    result = parseInt(a[result])-1
+  else:
+    raiseInvalidFormat("'#', '$', number or identifier expected")
+  if result >=% a.len: raiseInvalidFormat("index out of bounds: " & $result)
+  p.i = i
+
+proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) {.
+  noSideEffect.}
+
+proc emitChar(p: var TFormatParser, x: var string, ch: char) {.inline.} =
+  x.add(ch)
+  if ch == '\L': p.lineLen = 0
+  else: inc p.lineLen
+
+proc emitStrLinear(p: var TFormatParser, x: var string, y: string) {.inline.} =
+  for ch in items(y): emitChar(p, x, ch)
+
+proc emitStr(p: var TFormatParser, x: var string, y: string) {.inline.} =
+  x.add(y)
+  inc p.lineLen, y.len
+
+proc scanQuote(p: var TFormatParser, x: var string, toAdd: bool) =
+  var i = p.i+1
+  var f = p.f
+  while true:
+    if f[i] == '\'':
+      inc i
+      if f[i] != '\'': break
+      inc i
+      if toAdd: emitChar(p, x, '\'')
+    elif f[i] == '\0': raiseInvalidFormat("closing \"'\" expected")
+    else:
+      if toAdd: emitChar(p, x, f[i])
+      inc i
+  p.i = i
+
+proc scanBranch(p: var TFormatParser, a: openArray[string],
+                x: var string, choice: int) =
+  var i = p.i
+  var f = p.f
+  var c = 0
+  var elsePart = i
+  var toAdd = choice == 0
+  while true:
+    case f[i]
+    of ']': break
+    of '|': 
+      inc i
+      elsePart = i
+      inc c
+      if toAdd: break
+      toAdd = choice == c
+    of '\'':
+      call: scanQuote(p, x, toAdd)
+    of '\0': raiseInvalidFormat("closing ']' expected")
+    else:
+      if toAdd:
+        if f[i] == '$':
+          inc i
+          call: scanDollar(p, a, x)
+        else:
+          emitChar(p, x, f[i])
+          inc i
+      else:
+        inc i
+  if not toAdd and choice >= 0:
+    # evaluate 'else' part:
+    var last = i
+    i = elsePart
+    while true:
+      case f[i]
+      of '|', ']': break
+      of '\'':
+        call: scanQuote(p, x, true)
+      of '$':
+        inc i
+        call: scanDollar(p, a, x)
+      else:
+        emitChar(p, x, f[i])
+        inc i
+    i = last
+  p.i = i+1
+
+proc scanSlice(p: var TFormatParser, a: openarray[string]): tuple[x, y: int] =
+  var slice = false
+  var i = p.i
+  var f = p.f
+  
+  if f[i] == '{': inc i
+  else: raiseInvalidFormat("'{' expected")
+  if f[i] == '.' and f[i+1] == '.':
+    inc i, 2
+    slice = true
+  else:
+    call: result.x = getFormatArg(p, a)
+    if f[i] == '.' and f[i+1] == '.':
+      inc i, 2
+      slice = true
+  if slice:
+    if f[i] != '}':
+      call: result.y = getFormatArg(p, a)
+    else:
+      result.y = high(a)
+  else:
+    result.y = result.x
+  if f[i] != '}': raiseInvalidFormat("'}' expected")
+  inc i
+  p.i = i
+  
+proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) =
+  var i = p.i
+  var f = p.f
+  case f[i]
+  of '$': 
+    emitChar p, s, '$'
+    inc i
+  of '*':
+    for j in 0..a.high: emitStr p, s, a[j]
+    inc i
+  of '{':
+    call:
+      let (x, y) = scanSlice(p, a)
+    for j in x..y: emitStr p, s, a[j]
+  of '[':
+    inc i
+    var start = i
+    call: scanBranch(p, a, s, -1)
+    var x: int
+    if f[i] == '{':
+      inc i
+      call: x = getFormatArg(p, a)
+      if f[i] != '}': raiseInvalidFormat("'}' expected")
+      inc i
+    else:
+      call: x = getFormatArg(p, a)
+    var last = i
+    let choice = parseInt(a[x])
+    i = start
+    call: scanBranch(p, a, s, choice)
+    i = last
+  of '\'':
+    var sep = ""
+    callNoLineLenTracking: scanQuote(p, sep, true)
+    if f[i] == '~':
+      # $' '~{1..3}
+      # insert space followed by 1..3 if not empty
+      inc i
+      call: 
+        let (x, y) = scanSlice(p, a)
+      var L = 0
+      for j in x..y: inc L, a[j].len
+      if L > 0:
+        emitStrLinear p, s, sep
+        for j in x..y: emitStr p, s, a[j]
+    else:
+      block StringJoin:
+        block OptionalLineLengthSpecifier:
+          var maxLen = 0
+          case f[i]
+          of '0'..'9':
+            while f[i] in Digits:
+              maxLen = maxLen * 10 + ord(f[i]) - ord('0')
+              inc i
+          of '$':
+            # do not skip the '$' here for `getFormatArg`!
+            call:
+              maxLen = getFormatArg(p, a)
+          else: break OptionalLineLengthSpecifier
+          var indent = ""
+          case f[i]
+          of 'i':
+            inc i
+            callNoLineLenTracking: scanQuote(p, indent, true)
+            
+            call:
+              let (x, y) = scanSlice(p, a)
+            if maxLen < 1: emitStrLinear(p, s, indent)
+            var items = 1
+            emitStr p, s, a[x]
+            for j in x+1..y:
+              emitStr p, s, sep
+              if items >= maxLen: 
+                emitStrLinear p, s, indent
+                items = 0
+              emitStr p, s, a[j]
+              inc items
+          of 'c':
+            inc i
+            callNoLineLenTracking: scanQuote(p, indent, true)
+            
+            call:
+              let (x, y) = scanSlice(p, a)
+            if p.lineLen + a[x].len > maxLen: emitStrLinear(p, s, indent)
+            emitStr p, s, a[x]
+            for j in x+1..y:
+              emitStr p, s, sep
+              if p.lineLen + a[j].len > maxLen: emitStrLinear(p, s, indent)
+              emitStr p, s, a[j]
+            
+          else: raiseInvalidFormat("unit 'c' (chars) or 'i' (items) expected")
+          break StringJoin
+
+        call:
+          let (x, y) = scanSlice(p, a)
+        emitStr p, s, a[x]
+        for j in x+1..y:
+          emitStr p, s, sep
+          emitStr p, s, a[j]
+  else:
+    call: 
+      var x = getFormatArg(p, a)
+    emitStr p, s, a[x]
+  p.i = i
+
+
+type
+  Subex* = distinct string ## string that contains a substitution expression
+
+{.deprecated: [TSubex: Subex].}
+
+proc subex*(s: string): Subex =
+  ## constructs a *substitution expression* from `s`. Currently this performs
+  ## no syntax checking but this may change in later versions.
+  result = Subex(s)
+
+proc addf*(s: var string, formatstr: Subex, a: varargs[string, `$`]) {.
+           noSideEffect, rtl, extern: "nfrmtAddf".} =
+  ## The same as ``add(s, formatstr % a)``, but more efficient.
+  var p: TFormatParser
+  p.f = formatstr.string
+  var i = 0
+  while i < len(formatstr.string):
+    if p.f[i] == '$':
+      inc i
+      call: scanDollar(p, a, s)
+    else:
+      emitChar(p, s, p.f[i])
+      inc(i)
+
+proc `%` *(formatstr: Subex, a: openarray[string]): string {.noSideEffect,
+  rtl, extern: "nfrmtFormatOpenArray".} =
+  ## The `substitution`:idx: operator performs string substitutions in
+  ## `formatstr` and returns a modified `formatstr`. This is often called
+  ## `string interpolation`:idx:.
+  ##
+  result = newStringOfCap(formatstr.string.len + a.len shl 4)
+  addf(result, formatstr, a)
+
+proc `%` *(formatstr: Subex, a: string): string {.noSideEffect,
+  rtl, extern: "nfrmtFormatSingleElem".} =
+  ## This is the same as ``formatstr % [a]``.
+  result = newStringOfCap(formatstr.string.len + a.len)
+  addf(result, formatstr, [a])
+
+proc format*(formatstr: Subex, a: varargs[string, `$`]): string {.noSideEffect,
+  rtl, extern: "nfrmtFormatVarargs".} =
+  ## The `substitution`:idx: operator performs string substitutions in
+  ## `formatstr` and returns a modified `formatstr`. This is often called
+  ## `string interpolation`:idx:.
+  ##
+  result = newStringOfCap(formatstr.string.len + a.len shl 4)
+  addf(result, formatstr, a)
+
+{.pop.}
+
+when isMainModule:
+
+  proc `%`(formatstr: string, a: openarray[string]): string =
+    result = newStringOfCap(formatstr.len + a.len shl 4)
+    addf(result, formatstr.Subex, a)
+
+  proc `%`(formatstr: string, a: string): string =
+    result = newStringOfCap(formatstr.len + a.len)
+    addf(result, formatstr.Subex, [a])
+
+
+  doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
+  doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
+           "The cat eats fish."
+
+
+  doAssert "$[abc|def]# $3 $# $#" % ["17", "b", "c"] == "def c b c"
+  doAssert "$[abc|def]# $3 $# $#" % ["1", "b", "c"] == "def c b c"
+  doAssert "$[abc|def]# $3 $# $#" % ["0", "b", "c"] == "abc c b c"
+  doAssert "$[abc|def|]# $3 $# $#" % ["17", "b", "c"] == " c b c"
+
+  doAssert "$[abc|def|]# $3 $# $#" % ["-9", "b", "c"] == " c b c"
+  doAssert "$1($', '{2..})" % ["f", "a", "b"] == "f(a, b)"
+
+  doAssert "$[$1($', '{2..})|''''|fg'$3']1" % ["7", "a", "b"] == "fg$3"
+  
+  doAssert "$[$#($', '{#..})|''''|$3]1" % ["0", "a", "b"] == "0(a, b)"
+  doAssert "$' '~{..}" % "" == ""
+  doAssert "$' '~{..}" % "P0" == " P0"
+  doAssert "${$1}" % "1" == "1"
+  doAssert "${$$-1} $$1" % "1" == "1 $1"
+           
+  doAssert "$#($', '10c'\n    '{#..})" % ["doAssert", "longishA", "longish"] ==
+           """doAssert(
+    longishA, 
+    longish)"""
+  
+  assert "type TMyEnum* = enum\n  $', '2i'\n  '{..}" % ["fieldA",
+    "fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
+    strutils.unindent """
+      type TMyEnum* = enum
+        fieldA, fieldB, 
+        FiledClkad, fieldD, 
+        fieldE, longishFieldName"""
+  
+  doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
+  
+  doAssert subex"$1 $[files|file|files]{1} copied" % ["1"] == "1 file copied"
+  
+  doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
+  
+  assert subex("type\n  TEnum = enum\n    $', '40c'\n    '{..}") % [
+    "fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
+    strutils.unindent """
+      type
+        TEnum = enum
+          fieldNameA, fieldNameB, fieldNameC, 
+          fieldNameD"""
+  
+  
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
new file mode 100644
index 000000000..29f700db5
--- /dev/null
+++ b/lib/pure/terminal.nim
@@ -0,0 +1,390 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains a few procedures to control the *terminal*
+## (also called *console*). On UNIX, the implementation simply uses ANSI escape
+## sequences and does not depend on any other module, on Windows it uses the
+## Windows API.
+## Changing the style is permanent even after program termination! Use the
+## code ``system.addQuitProc(resetAttributes)`` to restore the defaults.
+
+import macros
+
+when defined(windows):
+  import windows, os
+
+  var
+    conHandle: THandle
+  # = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
+
+  block:
+    var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
+    if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
+                       addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
+      raiseOSError(osLastError())
+
+  proc getCursorPos(): tuple [x,y: int] =
+    var c: TCONSOLESCREENBUFFERINFO
+    if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0:
+      raiseOSError(osLastError())
+    return (int(c.dwCursorPosition.X), int(c.dwCursorPosition.Y))
+
+  proc getAttributes(): int16 =
+    var c: TCONSOLESCREENBUFFERINFO
+    # workaround Windows bugs: try several times
+    if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
+      return c.wAttributes
+    return 0x70'i16 # ERROR: return white background, black text
+
+  var
+    oldAttr = getAttributes()
+
+else:
+  import termios, unsigned
+
+  proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
+    var mode: Termios
+    discard fd.tcgetattr(addr mode)
+    mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
+      ISTRIP or IXON)
+    mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
+    mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
+    mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
+    mode.c_cc[VMIN] = 1.cuchar
+    mode.c_cc[VTIME] = 0.cuchar
+    discard fd.tcsetattr(time, addr mode)
+
+proc setCursorPos*(x, y: int) =
+  ## sets the terminal's cursor to the (x,y) position. (0,0) is the
+  ## upper left of the screen.
+  when defined(windows):
+    var c: TCOORD
+    c.X = int16(x)
+    c.Y = int16(y)
+    if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError())
+  else:
+    stdout.write("\e[" & $y & ';' & $x & 'f')
+
+proc setCursorXPos*(x: int) =
+  ## sets the terminal's cursor to the x position. The y position is
+  ## not changed.
+  when defined(windows):
+    var scrbuf: TCONSOLESCREENBUFFERINFO
+    var hStdout = conHandle
+    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+      raiseOSError(osLastError())
+    var origin = scrbuf.dwCursorPosition
+    origin.X = int16(x)
+    if SetConsoleCursorPosition(conHandle, origin) == 0:
+      raiseOSError(osLastError())
+  else:
+    stdout.write("\e[" & $x & 'G')
+
+when defined(windows):
+  proc setCursorYPos*(y: int) =
+    ## sets the terminal's cursor to the y position. The x position is
+    ## not changed. **Warning**: This is not supported on UNIX!
+    when defined(windows):
+      var scrbuf: TCONSOLESCREENBUFFERINFO
+      var hStdout = conHandle
+      if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+        raiseOSError(osLastError())
+      var origin = scrbuf.dwCursorPosition
+      origin.Y = int16(y)
+      if SetConsoleCursorPosition(conHandle, origin) == 0:
+        raiseOSError(osLastError())
+    else:
+      discard
+
+proc cursorUp*(count=1) =
+  ## Moves the cursor up by `count` rows.
+  when defined(windows):
+    var p = getCursorPos()
+    dec(p.y, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'A')
+
+proc cursorDown*(count=1) =
+  ## Moves the cursor down by `count` rows.
+  when defined(windows):
+    var p = getCursorPos()
+    inc(p.y, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'B')
+
+proc cursorForward*(count=1) =
+  ## Moves the cursor forward by `count` columns.
+  when defined(windows):
+    var p = getCursorPos()
+    inc(p.x, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'C')
+
+proc cursorBackward*(count=1) =
+  ## Moves the cursor backward by `count` columns.
+  when defined(windows):
+    var p = getCursorPos()
+    dec(p.x, count)
+    setCursorPos(p.x, p.y)
+  else:
+    stdout.write("\e[" & $count & 'D')
+
+when true:
+  discard
+else:
+  proc eraseLineEnd* =
+    ## Erases from the current cursor position to the end of the current line.
+    when defined(windows):
+      discard
+    else:
+      stdout.write("\e[K")
+
+  proc eraseLineStart* =
+    ## Erases from the current cursor position to the start of the current line.
+    when defined(windows):
+      discard
+    else:
+      stdout.write("\e[1K")
+
+  proc eraseDown* =
+    ## Erases the screen from the current line down to the bottom of the screen.
+    when defined(windows):
+      discard
+    else:
+      stdout.write("\e[J")
+
+  proc eraseUp* =
+    ## Erases the screen from the current line up to the top of the screen.
+    when defined(windows):
+      discard
+    else:
+      stdout.write("\e[1J")
+
+proc eraseLine* =
+  ## Erases the entire current line.
+  when defined(windows):
+    var scrbuf: TCONSOLESCREENBUFFERINFO
+    var numwrote: DWORD
+    var hStdout = conHandle
+    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+      raiseOSError(osLastError())
+    var origin = scrbuf.dwCursorPosition
+    origin.X = 0'i16
+    if SetConsoleCursorPosition(conHandle, origin) == 0:
+      raiseOSError(osLastError())
+    var ht = scrbuf.dwSize.Y - origin.Y
+    var wt = scrbuf.dwSize.X - origin.X
+    if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
+                                  origin, addr(numwrote)) == 0:
+      raiseOSError(osLastError())
+    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
+                                  scrbuf.dwCursorPosition, addr(numwrote)) == 0:
+      raiseOSError(osLastError())
+  else:
+    stdout.write("\e[2K")
+    setCursorXPos(0)
+
+proc eraseScreen* =
+  ## Erases the screen with the background colour and moves the cursor to home.
+  when defined(windows):
+    var scrbuf: TCONSOLESCREENBUFFERINFO
+    var numwrote: DWORD
+    var origin: TCOORD # is inititalized to 0, 0
+    var hStdout = conHandle
+
+    if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+      raiseOSError(osLastError())
+    let numChars = int32(scrbuf.dwSize.X)*int32(scrbuf.dwSize.Y)
+
+    if FillConsoleOutputCharacter(hStdout, ' ', numChars,
+                                  origin, addr(numwrote)) == 0:
+      raiseOSError(osLastError())
+    if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, numChars,
+                                  origin, addr(numwrote)) == 0:
+      raiseOSError(osLastError())
+    setCursorXPos(0)
+  else:
+    stdout.write("\e[2J")
+
+proc resetAttributes* {.noconv.} =
+  ## resets all attributes; it is advisable to register this as a quit proc
+  ## with ``system.addQuitProc(resetAttributes)``.
+  when defined(windows):
+    discard SetConsoleTextAttribute(conHandle, oldAttr)
+  else:
+    stdout.write("\e[0m")
+
+type
+  Style* = enum         ## different styles for text output
+    styleBright = 1,     ## bright text
+    styleDim,            ## dim text
+    styleUnknown,        ## unknown
+    styleUnderscore = 4, ## underscored text
+    styleBlink,          ## blinking/bold text
+    styleReverse = 7,    ## unknown
+    styleHidden          ## hidden text
+
+{.deprecated: [TStyle: Style].}
+
+when not defined(windows):
+  var
+    # XXX: These better be thread-local
+    gFG = 0
+    gBG = 0
+
+proc setStyle*(style: set[Style]) =
+  ## sets the terminal style
+  when defined(windows):
+    var a = 0'i16
+    if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)
+    if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)
+    if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO
+    if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE
+    discard SetConsoleTextAttribute(conHandle, a)
+  else:
+    for s in items(style):
+      stdout.write("\e[" & $ord(s) & 'm')
+
+proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
+  ## writes the text `txt` in a given `style`.
+  when defined(windows):
+    var old = getAttributes()
+    setStyle(style)
+    stdout.write(txt)
+    discard SetConsoleTextAttribute(conHandle, old)
+  else:
+    setStyle(style)
+    stdout.write(txt)
+    resetAttributes()
+    if gFG != 0:
+      stdout.write("\e[" & $ord(gFG) & 'm')
+    if gBG != 0:
+      stdout.write("\e[" & $ord(gBG) & 'm')
+
+type
+  ForegroundColor* = enum  ## terminal's foreground colors
+    fgBlack = 30,          ## black
+    fgRed,                 ## red
+    fgGreen,               ## green
+    fgYellow,              ## yellow
+    fgBlue,                ## blue
+    fgMagenta,             ## magenta
+    fgCyan,                ## cyan
+    fgWhite                ## white
+
+  BackgroundColor* = enum  ## terminal's background colors
+    bgBlack = 40,          ## black
+    bgRed,                 ## red
+    bgGreen,               ## green
+    bgYellow,              ## yellow
+    bgBlue,                ## blue
+    bgMagenta,             ## magenta
+    bgCyan,                ## cyan
+    bgWhite                ## white
+
+{.deprecated: [TForegroundColor: ForegroundColor,
+               TBackgroundColor: BackgroundColor].}
+
+proc setForegroundColor*(fg: ForegroundColor, bright=false) =
+  ## sets the terminal's foreground color
+  when defined(windows):
+    var old = getAttributes() and not 0x0007
+    if bright:
+      old = old or FOREGROUND_INTENSITY
+    const lookup: array [ForegroundColor, int] = [
+      0,
+      (FOREGROUND_RED),
+      (FOREGROUND_GREEN),
+      (FOREGROUND_RED or FOREGROUND_GREEN),
+      (FOREGROUND_BLUE),
+      (FOREGROUND_RED or FOREGROUND_BLUE),
+      (FOREGROUND_BLUE or FOREGROUND_GREEN),
+      (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)]
+    discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[fg]))
+  else:
+    gFG = ord(fg)
+    if bright: inc(gFG, 60)
+    stdout.write("\e[" & $gFG & 'm')
+
+proc setBackgroundColor*(bg: BackgroundColor, bright=false) =
+  ## sets the terminal's background color
+  when defined(windows):
+    var old = getAttributes() and not 0x0070
+    if bright:
+      old = old or BACKGROUND_INTENSITY
+    const lookup: array [BackgroundColor, int] = [
+      0,
+      (BACKGROUND_RED),
+      (BACKGROUND_GREEN),
+      (BACKGROUND_RED or BACKGROUND_GREEN),
+      (BACKGROUND_BLUE),
+      (BACKGROUND_RED or BACKGROUND_BLUE),
+      (BACKGROUND_BLUE or BACKGROUND_GREEN),
+      (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)]
+    discard SetConsoleTextAttribute(conHandle, toU16(old or lookup[bg]))
+  else:
+    gBG = ord(bg)
+    if bright: inc(gBG, 60)
+    stdout.write("\e[" & $gBG & 'm')
+
+proc isatty*(f: File): bool =
+  ## returns true if `f` is associated with a terminal device.
+  when defined(posix):
+    proc isatty(fildes: FileHandle): cint {.
+      importc: "isatty", header: "<unistd.h>".}
+  else:
+    proc isatty(fildes: FileHandle): cint {.
+      importc: "_isatty", header: "<io.h>".}
+
+  result = isatty(getFileHandle(f)) != 0'i32
+
+proc styledEchoProcessArg(s: string) = write stdout, s
+proc styledEchoProcessArg(style: Style) = setStyle({style})
+proc styledEchoProcessArg(style: set[Style]) = setStyle style
+proc styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color
+proc styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color
+
+macro styledEcho*(m: varargs[expr]): stmt =
+  ## to be documented.
+  let m = callsite()
+  result = newNimNode(nnkStmtList)
+
+  for i in countup(1, m.len - 1):
+    result.add(newCall(bindSym"styledEchoProcessArg", m[i]))
+
+  result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
+  result.add(newCall(bindSym"resetAttributes"))
+
+when not defined(windows):
+  proc getch*(): char =
+    ## Read a single character from the terminal, blocking until it is entered.
+    ## The character is not printed to the terminal. This is not available for
+    ## Windows.
+    let fd = getFileHandle(stdin)
+    var oldMode: Termios
+    discard fd.tcgetattr(addr oldMode)
+    fd.setRaw()
+    result = stdin.readChar()
+    discard fd.tcsetattr(TCSADRAIN, addr oldMode)
+
+when not defined(testing) and isMainModule:
+  system.addQuitProc(resetAttributes)
+  write(stdout, "never mind")
+  eraseLine()
+  #setCursorPos(2, 2)
+  writeStyled("styled text ", {styleBright, styleBlink, styleUnderscore})
+  setBackGroundColor(bgCyan, true)
+  setForeGroundColor(fgBlue)
+  writeln(stdout, "ordinary text")
+
+  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
+
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
new file mode 100644
index 000000000..b8836c15b
--- /dev/null
+++ b/lib/pure/times.nim
@@ -0,0 +1,1120 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## This module contains routines and types for dealing with time.
+## This module is available for the `JavaScript target
+## <backends.html#the-javascript-target>`_.
+
+{.push debugger:off.} # the user does not want to trace a part
+                      # of the standard library!
+
+import
+  strutils, parseutils
+
+include "system/inclrtl"
+
+type
+  Month* = enum ## represents a month
+    mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec
+  WeekDay* = enum ## represents a weekday
+    dMon, dTue, dWed, dThu, dFri, dSat, dSun
+
+when not defined(JS):
+  var
+    timezone {.importc, header: "<time.h>".}: int
+    tzname {.importc, header: "<time.h>" .}: array[0..1, cstring]
+
+when defined(posix) and not defined(JS):
+  type
+    TimeImpl {.importc: "time_t", header: "<time.h>".} = int
+    Time* = distinct TimeImpl ## distinct type that represents a time
+                              ## measured as number of seconds since the epoch
+
+    Timeval {.importc: "struct timeval",
+              header: "<sys/select.h>".} = object ## struct timeval
+      tv_sec: int  ## Seconds.
+      tv_usec: int ## Microseconds.
+
+  # we cannot import posix.nim here, because posix.nim depends on times.nim.
+  # Ok, we could, but I don't want circular dependencies.
+  # And gettimeofday() is not defined in the posix module anyway. Sigh.
+
+  proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
+    importc: "gettimeofday", header: "<sys/time.h>".}
+
+  # we also need tzset() to make sure that tzname is initialized
+  proc tzset() {.importc, header: "<time.h>".}
+  # calling tzset() implicitly to initialize tzname data.
+  tzset()
+
+elif defined(windows):
+  import winlean
+
+  when defined(vcc):
+    # newest version of Visual C++ defines time_t to be of 64 bits
+    type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64
+  else:
+    type TimeImpl {.importc: "time_t", header: "<time.h>".} = int32
+
+  type
+    Time* = distinct TimeImpl
+
+elif defined(JS):
+  type
+    Time* {.importc.} = object
+      getDay: proc (): int {.tags: [], raises: [], benign.}
+      getFullYear: proc (): int {.tags: [], raises: [], benign.}
+      getHours: proc (): int {.tags: [], raises: [], benign.}
+      getMilliseconds: proc (): int {.tags: [], raises: [], benign.}
+      getMinutes: proc (): int {.tags: [], raises: [], benign.}
+      getMonth: proc (): int {.tags: [], raises: [], benign.}
+      getSeconds: proc (): int {.tags: [], raises: [], benign.}
+      getTime: proc (): int {.tags: [], raises: [], benign.}
+      getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.}
+      getDate: proc (): int {.tags: [], raises: [], benign.}
+      getUTCDate: proc (): int {.tags: [], raises: [], benign.}
+      getUTCFullYear: proc (): int {.tags: [], raises: [], benign.}
+      getUTCHours: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMinutes: proc (): int {.tags: [], raises: [], benign.}
+      getUTCMonth: proc (): int {.tags: [], raises: [], benign.}
+      getUTCSeconds: proc (): int {.tags: [], raises: [], benign.}
+      getUTCDay: proc (): int {.tags: [], raises: [], benign.}
+      getYear: proc (): int {.tags: [], raises: [], benign.}
+      parse: proc (s: cstring): Time {.tags: [], raises: [], benign.}
+      setDate: proc (x: int) {.tags: [], raises: [], benign.}
+      setFullYear: proc (x: int) {.tags: [], raises: [], benign.}
+      setHours: proc (x: int) {.tags: [], raises: [], benign.}
+      setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setMinutes: proc (x: int) {.tags: [], raises: [], benign.}
+      setMonth: proc (x: int) {.tags: [], raises: [], benign.}
+      setSeconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setTime: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCDate: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCHours: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.}
+      setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.}
+      setYear: proc (x: int) {.tags: [], raises: [], benign.}
+      toGMTString: proc (): cstring {.tags: [], raises: [], benign.}
+      toLocaleString: proc (): cstring {.tags: [], raises: [], benign.}
+
+type
+  TimeInfo* = object of RootObj ## represents a time in different parts
+    second*: range[0..61]     ## The number of seconds after the minute,
+                              ## normally in the range 0 to 59, but can
+                              ## be up to 61 to allow for leap seconds.
+    minute*: range[0..59]     ## The number of minutes after the hour,
+                              ## in the range 0 to 59.
+    hour*: range[0..23]       ## The number of hours past midnight,
+                              ## in the range 0 to 23.
+    monthday*: range[1..31]   ## The day of the month, in the range 1 to 31.
+    month*: Month             ## The current month.
+    year*: int                ## The current year.
+    weekday*: WeekDay         ## The current day of the week.
+    yearday*: range[0..365]   ## The number of days since January 1,
+                              ## in the range 0 to 365.
+                              ## Always 0 if the target is JS.
+    isDST*: bool              ## Determines whether DST is in effect. Always
+                              ## ``False`` if time is UTC.
+    tzname*: string           ## The timezone this time is in. E.g. GMT
+    timezone*: int            ## The offset of the (non-DST) timezone in seconds
+                              ## west of UTC.
+
+  ## I make some assumptions about the data in here. Either
+  ## everything should be positive or everything negative. Zero is
+  ## fine too. Mixed signs will lead to unexpected results.
+  TimeInterval* = object ## a time interval
+    milliseconds*: int ## The number of milliseconds
+    seconds*: int     ## The number of seconds
+    minutes*: int     ## The number of minutes
+    hours*: int       ## The number of hours
+    days*: int        ## The number of days
+    months*: int      ## The number of months
+    years*: int       ## The number of years
+
+{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
+    TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].}
+
+proc miliseconds*(t: TimeInterval): int {.deprecated.} = t.milliseconds
+
+proc `miliseconds=`*(t:var TimeInterval, milliseconds: int) {.deprecated.} =
+  t.milliseconds = milliseconds
+
+proc getTime*(): Time {.tags: [TimeEffect], benign.}
+  ## gets the current calendar time as a UNIX epoch value (number of seconds
+  ## elapsed since 1970) with integer precission. Use epochTime for higher
+  ## resolution.
+proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
+  ## converts the calendar time `t` to broken-time representation,
+  ## expressed relative to the user's specified time zone.
+proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.}
+  ## converts the calendar time `t` to broken-down time representation,
+  ## expressed in Coordinated Universal Time (UTC).
+
+proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.}
+  ## converts a broken-down time structure to
+  ## calendar time representation. The function ignores the specified
+  ## contents of the structure members `weekday` and `yearday` and recomputes
+  ## them from the other information in the broken-down time structure.
+
+proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.}
+  ## Takes a float which contains the number of seconds since the unix epoch and
+  ## returns a time object.
+
+proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} =
+  ## Takes an int which contains the number of seconds since the unix epoch and
+  ## returns a time object.
+  fromSeconds(float(since1970))
+
+proc toSeconds*(time: Time): float {.tags: [], raises: [], benign.}
+  ## Returns the time in seconds since the unix epoch.
+
+proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], benign.}
+  ## converts a `TimeInfo` object to a string representation.
+proc `$` *(time: Time): string {.tags: [], raises: [], benign.}
+  ## converts a calendar time to a string representation.
+
+proc `-`*(a, b: Time): int64 {.
+  rtl, extern: "ntDiffTime", tags: [], raises: [], benign.}
+  ## computes the difference of two calendar times. Result is in seconds.
+
+proc `<`*(a, b: Time): bool {.
+  rtl, extern: "ntLtTime", tags: [], raises: [].} =
+  ## returns true iff ``a < b``, that is iff a happened before b.
+  result = a - b < 0
+
+proc `<=` * (a, b: Time): bool {.
+  rtl, extern: "ntLeTime", tags: [], raises: [].}=
+  ## returns true iff ``a <= b``.
+  result = a - b <= 0
+
+proc `==`*(a, b: Time): bool {.
+  rtl, extern: "ntEqTime", tags: [], raises: [].} =
+  ## returns true if ``a == b``, that is if both times represent the same value
+  result = a - b == 0
+
+when not defined(JS):
+  proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [],
+    benign.}
+    ## returns the local timezone; ``nonDST`` is the name of the local non-DST
+    ## timezone, ``DST`` is the name of the local DST timezone.
+
+proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.}
+  ## returns the offset of the local (non-DST) timezone in seconds west of UTC.
+
+proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.}
+  ## get the milliseconds from the start of the program. **Deprecated since
+  ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead.
+
+proc initInterval*(milliseconds, seconds, minutes, hours, days, months,
+                   years: int = 0): TimeInterval =
+  ## creates a new ``TimeInterval``.
+  result.milliseconds = milliseconds
+  result.seconds = seconds
+  result.minutes = minutes
+  result.hours = hours
+  result.days = days
+  result.months = months
+  result.years = years
+
+proc isLeapYear*(year: int): bool =
+  ## returns true if ``year`` is a leap year
+
+  if year mod 400 == 0:
+    return true
+  elif year mod 100 == 0:
+    return false
+  elif year mod 4 == 0:
+    return true
+  else:
+    return false
+
+proc getDaysInMonth*(month: Month, year: int): int =
+  ## gets the amount of days in a ``month`` of a ``year``
+
+  # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
+  case month
+  of mFeb: result = if isLeapYear(year): 29 else: 28
+  of mApr, mJun, mSep, mNov: result = 30
+  else: result = 31
+
+proc toSeconds(a: TimeInfo, interval: TimeInterval): float =
+  ## Calculates how many seconds the interval is worth by adding up
+  ## all the fields
+
+  var anew = a
+  var newinterv = interval
+  result = 0
+
+  newinterv.months += interval.years * 12
+  var curMonth = anew.month
+  for mth in 1 .. newinterv.months:
+    result += float(getDaysInMonth(curMonth, anew.year) * 24 * 60 * 60)
+    if curMonth == mDec:
+      curMonth = mJan
+      anew.year.inc()
+    else:
+      curMonth.inc()
+  result += float(newinterv.days * 24 * 60 * 60)
+  result += float(newinterv.hours * 60 * 60)
+  result += float(newinterv.minutes * 60)
+  result += float(newinterv.seconds)
+  result += newinterv.milliseconds / 1000
+
+proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
+  ## adds ``interval`` time.
+  ##
+  ## **Note:** This has been only briefly tested and it may not be
+  ## very accurate.
+  let t = toSeconds(timeInfoToTime(a))
+  let secs = toSeconds(a, interval)
+  if a.tzname == "UTC":
+    result = getGMTime(fromSeconds(t + secs))
+  else:
+    result = getLocalTime(fromSeconds(t + secs))
+
+proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo =
+  ## subtracts ``interval`` time.
+  ##
+  ## **Note:** This has been only briefly tested, it is inaccurate especially
+  ## when you subtract so much that you reach the Julian calendar.
+  let t = toSeconds(timeInfoToTime(a))
+  let secs = toSeconds(a, interval)
+  if a.tzname == "UTC":
+    result = getGMTime(fromSeconds(t - secs))
+  else:
+    result = getLocalTime(fromSeconds(t - secs))
+
+when not defined(JS):
+  proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
+    ## gets time after the UNIX epoch (1970) in seconds. It is a float
+    ## because sub-second resolution is likely to be supported (depending
+    ## on the hardware/OS).
+
+  proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].}
+    ## gets time spent that the CPU spent to run the current process in
+    ## seconds. This may be more useful for benchmarking than ``epochTime``.
+    ## However, it may measure the real time instead (depending on the OS).
+    ## The value of the result has no meaning.
+    ## To generate useful timing values, take the difference between
+    ## the results of two ``cpuTime`` calls:
+    ##
+    ## .. code-block:: nim
+    ##   var t0 = cpuTime()
+    ##   doWork()
+    ##   echo "CPU time [s] ", cpuTime() - t0
+
+when not defined(JS):
+  # C wrapper:
+  type
+    StructTM {.importc: "struct tm", final.} = object
+      second {.importc: "tm_sec".},
+        minute {.importc: "tm_min".},
+        hour {.importc: "tm_hour".},
+        monthday {.importc: "tm_mday".},
+        month {.importc: "tm_mon".},
+        year {.importc: "tm_year".},
+        weekday {.importc: "tm_wday".},
+        yearday {.importc: "tm_yday".},
+        isdst {.importc: "tm_isdst".}: cint
+
+    TimeInfoPtr = ptr StructTM
+    Clock {.importc: "clock_t".} = distinct int
+
+  proc localtime(timer: ptr Time): TimeInfoPtr {.
+    importc: "localtime", header: "<time.h>", tags: [].}
+  proc gmtime(timer: ptr Time): TimeInfoPtr {.
+    importc: "gmtime", header: "<time.h>", tags: [].}
+  proc timec(timer: ptr Time): Time {.
+    importc: "time", header: "<time.h>", tags: [].}
+  proc mktime(t: StructTM): Time {.
+    importc: "mktime", header: "<time.h>", tags: [].}
+  proc asctime(tblock: StructTM): cstring {.
+    importc: "asctime", header: "<time.h>", tags: [].}
+  proc ctime(time: ptr Time): cstring {.
+    importc: "ctime", header: "<time.h>", tags: [].}
+  #  strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
+  #    importc: "strftime", header: "<time.h>".}
+  proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].}
+  proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>",
+    tags: [].}
+
+  var
+    clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
+
+  # our own procs on top of that:
+  proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo =
+    const
+      weekDays: array [0..6, WeekDay] = [
+        dSun, dMon, dTue, dWed, dThu, dFri, dSat]
+    TimeInfo(second: int(tm.second),
+      minute: int(tm.minute),
+      hour: int(tm.hour),
+      monthday: int(tm.monthday),
+      month: Month(tm.month),
+      year: tm.year + 1900'i32,
+      weekday: weekDays[int(tm.weekday)],
+      yearday: int(tm.yearday),
+      isDST: tm.isdst > 0,
+      tzname: if local:
+          if tm.isdst > 0:
+            getTzname().DST
+          else:
+            getTzname().nonDST
+        else:
+          "UTC",
+      timezone: if local: getTimezone() else: 0
+    )
+
+  proc timeInfoToTM(t: TimeInfo): StructTM =
+    const
+      weekDays: array [WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
+    result.second = t.second
+    result.minute = t.minute
+    result.hour = t.hour
+    result.monthday = t.monthday
+    result.month = ord(t.month)
+    result.year = cint(t.year - 1900)
+    result.weekday = weekDays[t.weekday]
+    result.yearday = t.yearday
+    result.isdst = if t.isDST: 1 else: 0
+
+  when not defined(useNimRtl):
+    proc `-` (a, b: Time): int64 =
+      return toBiggestInt(difftime(a, b))
+
+  proc getStartMilsecs(): int =
+    #echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock())
+    #return getClock() div (clocksPerSec div 1000)
+    when defined(macosx):
+      result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0))
+    else:
+      result = int(getClock()) div (clocksPerSec div 1000)
+    when false:
+      var a: Timeval
+      posix_gettimeofday(a)
+      result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64
+      #echo "result: ", result
+
+  proc getTime(): Time = return timec(nil)
+  proc getLocalTime(t: Time): TimeInfo =
+    var a = t
+    result = tmToTimeInfo(localtime(addr(a))[], true)
+    # copying is needed anyway to provide reentrancity; thus
+    # the conversion is not expensive
+
+  proc getGMTime(t: Time): TimeInfo =
+    var a = t
+    result = tmToTimeInfo(gmtime(addr(a))[], false)
+    # copying is needed anyway to provide reentrancity; thus
+    # the conversion is not expensive
+
+  proc timeInfoToTime(timeInfo: TimeInfo): Time =
+    var cTimeInfo = timeInfo # for C++ we have to make a copy,
+    # because the header of mktime is broken in my version of libc
+    return mktime(timeInfoToTM(cTimeInfo))
+
+  proc toStringTillNL(p: cstring): string =
+    result = ""
+    var i = 0
+    while p[i] != '\0' and p[i] != '\10' and p[i] != '\13':
+      add(result, p[i])
+      inc(i)
+
+  proc `$`(timeInfo: TimeInfo): string =
+    # BUGFIX: asctime returns a newline at the end!
+    var p = asctime(timeInfoToTM(timeInfo))
+    result = toStringTillNL(p)
+
+  proc `$`(time: Time): string =
+    # BUGFIX: ctime returns a newline at the end!
+    var a = time
+    return toStringTillNL(ctime(addr(a)))
+
+  const
+    epochDiff = 116444736000000000'i64
+    rateDiff = 10000000'i64 # 100 nsecs
+
+  proc unixTimeToWinTime*(t: Time): int64 =
+    ## converts a UNIX `Time` (``time_t``) to a Windows file time
+    result = int64(t) * rateDiff + epochDiff
+
+  proc winTimeToUnixTime*(t: int64): Time =
+    ## converts a Windows time to a UNIX `Time` (``time_t``)
+    result = Time((t - epochDiff) div rateDiff)
+
+  proc getTzname(): tuple[nonDST, DST: string] =
+    return ($tzname[0], $tzname[1])
+
+  proc getTimezone(): int =
+    return timezone
+
+  proc fromSeconds(since1970: float): Time = Time(since1970)
+
+  proc toSeconds(time: Time): float = float(time)
+
+  when not defined(useNimRtl):
+    proc epochTime(): float =
+      when defined(posix):
+        var a: Timeval
+        posix_gettimeofday(a)
+        result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
+      elif defined(windows):
+        var f: winlean.TFILETIME
+        getSystemTimeAsFileTime(f)
+        var i64 = rdFileTime(f) - epochDiff
+        var secs = i64 div rateDiff
+        var subsecs = i64 mod rateDiff
+        result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
+      else:
+        {.error: "unknown OS".}
+
+    proc cpuTime(): float =
+      result = toFloat(int(getClock())) / toFloat(clocksPerSec)
+
+elif defined(JS):
+  proc newDate(): Time {.importc: "new Date".}
+  proc internGetTime(): Time {.importc: "new Date", tags: [].}
+
+  proc newDate(value: float): Time {.importc: "new Date".}
+  proc newDate(value: string): Time {.importc: "new Date".}
+  proc getTime(): Time =
+    # Warning: This is something different in JS.
+    return newDate()
+
+  const
+    weekDays: array [0..6, WeekDay] = [
+      dSun, dMon, dTue, dWed, dThu, dFri, dSat]
+
+  proc getLocalTime(t: Time): TimeInfo =
+    result.second = t.getSeconds()
+    result.minute = t.getMinutes()
+    result.hour = t.getHours()
+    result.monthday = t.getDate()
+    result.month = Month(t.getMonth())
+    result.year = t.getFullYear()
+    result.weekday = weekDays[t.getDay()]
+    result.yearday = 0
+
+  proc getGMTime(t: Time): TimeInfo =
+    result.second = t.getUTCSeconds()
+    result.minute = t.getUTCMinutes()
+    result.hour = t.getUTCHours()
+    result.monthday = t.getUTCDate()
+    result.month = Month(t.getUTCMonth())
+    result.year = t.getUTCFullYear()
+    result.weekday = weekDays[t.getUTCDay()]
+    result.yearday = 0
+
+  proc timeInfoToTime*(timeInfo: TimeInfo): Time =
+    result = internGetTime()
+    result.setSeconds(timeInfo.second)
+    result.setMinutes(timeInfo.minute)
+    result.setHours(timeInfo.hour)
+    result.setMonth(ord(timeInfo.month))
+    result.setFullYear(timeInfo.year)
+    result.setDate(timeInfo.monthday)
+
+  proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo))
+  proc `$`(time: Time): string = return $time.toLocaleString()
+
+  proc `-` (a, b: Time): int64 =
+    return a.getTime() - b.getTime()
+
+  var
+    startMilsecs = getTime()
+
+  proc getStartMilsecs(): int =
+    ## get the milliseconds from the start of the program
+    return int(getTime() - startMilsecs)
+
+  proc valueOf(time: Time): float {.importcpp: "getTime", tags:[]}
+
+  proc fromSeconds(since1970: float): Time = result = newDate(since1970)
+
+  proc toSeconds(time: Time): float = result = time.valueOf() / 1000
+
+  proc getTimezone(): int = result = newDate().getTimezoneOffset()
+
+  proc epochTime*(): float {.tags: [TimeEffect].} = newDate().toSeconds()
+
+proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
+  ## gets the current date as a string of the format ``YYYY-MM-DD``.
+  var ti = getLocalTime(getTime())
+  result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
+    '-' & intToStr(ti.monthday, 2)
+
+proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
+  ## gets the current clock time as a string of the format ``HH:MM:SS``.
+  var ti = getLocalTime(getTime())
+  result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
+    ':' & intToStr(ti.second, 2)
+
+proc `$`*(day: WeekDay): string =
+  ## stingify operator for ``WeekDay``.
+  const lookup: array[WeekDay, string] = ["Monday", "Tuesday", "Wednesday",
+     "Thursday", "Friday", "Saturday", "Sunday"]
+  return lookup[day]
+
+proc `$`*(m: Month): string =
+  ## stingify operator for ``Month``.
+  const lookup: array[Month, string] = ["January", "February", "March",
+      "April", "May", "June", "July", "August", "September", "October",
+      "November", "December"]
+  return lookup[m]
+
+proc formatToken(info: TimeInfo, token: string, buf: var string) =
+  ## Helper of the format proc to parse individual tokens.
+  ##
+  ## Pass the found token in the user input string, and the buffer where the
+  ## final string is being built. This has to be a var value because certain
+  ## formatting tokens require modifying the previous characters.
+  case token
+  of "d":
+    buf.add($info.monthday)
+  of "dd":
+    if info.monthday < 10:
+      buf.add("0")
+    buf.add($info.monthday)
+  of "ddd":
+    buf.add(($info.weekday)[0 .. 2])
+  of "dddd":
+    buf.add($info.weekday)
+  of "h":
+    buf.add($(if info.hour > 12: info.hour - 12 else: info.hour))
+  of "hh":
+    let amerHour = if info.hour > 12: info.hour - 12 else: info.hour
+    if amerHour < 10:
+      buf.add('0')
+    buf.add($amerHour)
+  of "H":
+    buf.add($info.hour)
+  of "HH":
+    if info.hour < 10:
+      buf.add('0')
+    buf.add($info.hour)
+  of "m":
+    buf.add($info.minute)
+  of "mm":
+    if info.minute < 10:
+      buf.add('0')
+    buf.add($info.minute)
+  of "M":
+    buf.add($(int(info.month)+1))
+  of "MM":
+    if info.month < mOct:
+      buf.add('0')
+    buf.add($(int(info.month)+1))
+  of "MMM":
+    buf.add(($info.month)[0..2])
+  of "MMMM":
+    buf.add($info.month)
+  of "s":
+    buf.add($info.second)
+  of "ss":
+    if info.second < 10:
+      buf.add('0')
+    buf.add($info.second)
+  of "t":
+    if info.hour >= 12:
+      buf.add('P')
+    else: buf.add('A')
+  of "tt":
+    if info.hour >= 12:
+      buf.add("PM")
+    else: buf.add("AM")
+  of "y":
+    var fr = ($info.year).len()-1
+    if fr < 0: fr = 0
+    buf.add(($info.year)[fr .. ($info.year).len()-1])
+  of "yy":
+    var fr = ($info.year).len()-2
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 2: fyear = repeat('0', 2-fyear.len()) & fyear
+    buf.add(fyear)
+  of "yyy":
+    var fr = ($info.year).len()-3
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 3: fyear = repeat('0', 3-fyear.len()) & fyear
+    buf.add(fyear)
+  of "yyyy":
+    var fr = ($info.year).len()-4
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 4: fyear = repeat('0', 4-fyear.len()) & fyear
+    buf.add(fyear)
+  of "yyyyy":
+    var fr = ($info.year).len()-5
+    if fr < 0: fr = 0
+    var fyear = ($info.year)[fr .. ($info.year).len()-1]
+    if fyear.len != 5: fyear = repeat('0', 5-fyear.len()) & fyear
+    buf.add(fyear)
+  of "z":
+    let hrs = (info.timezone div 60) div 60
+    buf.add($hrs)
+  of "zz":
+    let hrs = (info.timezone div 60) div 60
+
+    buf.add($hrs)
+    if hrs.abs < 10:
+      var atIndex = buf.len-(($hrs).len-(if hrs < 0: 1 else: 0))
+      buf.insert("0", atIndex)
+  of "zzz":
+    let hrs = (info.timezone div 60) div 60
+
+    buf.add($hrs & ":00")
+    if hrs.abs < 10:
+      var atIndex = buf.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
+      buf.insert("0", atIndex)
+  of "ZZZ":
+    buf.add(info.tzname)
+  of "":
+    discard
+  else:
+    raise newException(ValueError, "Invalid format string: " & token)
+
+
+proc format*(info: TimeInfo, f: string): string =
+  ## This function formats `info` as specified by `f`. The following format
+  ## specifiers are available:
+  ##
+  ## ==========  =================================================================================  ================================================
+  ## Specifier   Description                                                                        Example
+  ## ==========  =================================================================================  ================================================
+  ##    d        Numeric value of the day of the month, it will be one or two digits long.          ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
+  ##    dd       Same as above, but always two digits.                                              ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
+  ##    ddd      Three letter string which indicates the day of the week.                           ``Saturday -> Sat``, ``Monday -> Mon``
+  ##    dddd     Full string for the day of the week.                                               ``Saturday -> Saturday``, ``Monday -> Monday``
+  ##    h        The hours in one digit if possible. Ranging from 0-12.                             ``5pm -> 5``, ``2am -> 2``
+  ##    hh       The hours in two digits always. If the hour is one digit 0 is prepended.           ``5pm -> 05``, ``11am -> 11``
+  ##    H        The hours in one digit if possible, randing from 0-24.                             ``5pm -> 17``, ``2am -> 2``
+  ##    HH       The hours in two digits always. 0 is prepended if the hour is one digit.           ``5pm -> 17``, ``2am -> 02``
+  ##    m        The minutes in 1 digit if possible.                                                ``5:30 -> 30``, ``2:01 -> 1``
+  ##    mm       Same as above but always 2 digits, 0 is prepended if the minute is one digit.      ``5:30 -> 30``, ``2:01 -> 01``
+  ##    M        The month in one digit if possible.                                                ``September -> 9``, ``December -> 12``
+  ##    MM       The month in two digits always. 0 is prepended.                                    ``September -> 09``, ``December -> 12``
+  ##    MMM      Abbreviated three-letter form of the month.                                        ``September -> Sep``, ``December -> Dec``
+  ##    MMMM     Full month string, properly capitalized.                                           ``September -> September``
+  ##    s        Seconds as one digit if possible.                                                  ``00:00:06 -> 6``
+  ##    ss       Same as above but always two digits. 0 is prepended.                               ``00:00:06 -> 06``
+  ##    t        ``A`` when time is in the AM. ``P`` when time is in the PM.
+  ##    tt       Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
+  ##    y(yyyy)  This displays the year to different digits. You most likely only want 2 or 4 'y's
+  ##    yy       Displays the year to two digits.                                                   ``2012 -> 12``
+  ##    yyyy     Displays the year to four digits.                                                  ``2012 -> 2012``
+  ##    z        Displays the timezone offset from UTC.                                             ``GMT+7 -> +7``, ``GMT-5 -> -5``
+  ##    zz       Same as above but with leading 0.                                                  ``GMT+7 -> +07``, ``GMT-5 -> -05``
+  ##    zzz      Same as above but with ``:00``.                                                    ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
+  ##    ZZZ      Displays the name of the timezone.                                                 ``GMT -> GMT``, ``EST -> EST``
+  ## ==========  =================================================================================  ================================================
+  ##
+  ## Other strings can be inserted by putting them in ``''``. For example
+  ## ``hh'->'mm`` will give ``01->56``.  The following characters can be
+  ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
+  ## ``,``. However you don't need to necessarily separate format specifiers, a
+  ## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
+
+  result = ""
+  var i = 0
+  var currentF = ""
+  while true:
+    case f[i]
+    of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
+      formatToken(info, currentF, result)
+
+      currentF = ""
+      if f[i] == '\0': break
+
+      if f[i] == '\'':
+        inc(i) # Skip '
+        while f[i] != '\'' and f.len-1 > i:
+          result.add(f[i])
+          inc(i)
+      else: result.add(f[i])
+
+    else:
+      # Check if the letter being added matches previous accumulated buffer.
+      if currentF.len < 1 or currentF[high(currentF)] == f[i]:
+        currentF.add(f[i])
+      else:
+        formatToken(info, currentF, result)
+        dec(i) # Move position back to re-process the character separately.
+        currentF = ""
+
+    inc(i)
+
+{.pop.}
+
+proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
+  ## Helper of the parse proc to parse individual tokens.
+  var sv: int
+  case token
+  of "d":
+    var pd = parseInt(value[j..j+1], sv)
+    info.monthday = sv
+    j += pd
+  of "dd":
+    info.monthday = value[j..j+1].parseInt()
+    j += 2
+  of "ddd":
+    case value[j..j+2].toLower()
+    of "sun":
+      info.weekday = dSun
+    of "mon":
+      info.weekday = dMon
+    of "tue":
+      info.weekday = dTue
+    of "wed":
+      info.weekday = dWed
+    of "thu":
+      info.weekday = dThu
+    of "fri":
+      info.weekday = dFri
+    of "sat":
+      info.weekday = dSat
+    else:
+      raise newException(ValueError, "invalid day of week ")
+    j += 3
+  of "dddd":
+    if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
+      info.weekday = dSun
+      j += 6
+    elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("monday") == 0:
+      info.weekday = dMon
+      j += 6
+    elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("tuesday") == 0:
+      info.weekday = dTue
+      j += 7
+    elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("wednesday") == 0:
+      info.weekday = dWed
+      j += 9
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("thursday") == 0:
+      info.weekday = dThu
+      j += 8
+    elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("friday") == 0:
+      info.weekday = dFri
+      j += 6
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("saturday") == 0:
+      info.weekday = dSat
+      j += 8
+    else:
+      raise newException(ValueError, "invalid day of week ")
+  of "h", "H":
+    var pd = parseInt(value[j..j+1], sv)
+    info.hour = sv
+    j += pd
+  of "hh", "HH":
+    info.hour = value[j..j+1].parseInt()
+    j += 2
+  of "m":
+    var pd = parseInt(value[j..j+1], sv)
+    info.minute = sv
+    j += pd
+  of "mm":
+    info.minute = value[j..j+1].parseInt()
+    j += 2
+  of "M":
+    var pd = parseInt(value[j..j+1], sv)
+    info.month = Month(sv-1)
+    info.monthday = sv
+    j += pd
+  of "MM":
+    var month = value[j..j+1].parseInt()
+    j += 2
+    info.month = Month(month-1)
+  of "MMM":
+    case value[j..j+2].toLower():
+    of "jan":
+      info.month =  mJan
+    of "feb":
+      info.month =  mFeb
+    of "mar":
+      info.month =  mMar
+    of "apr":
+      info.month =  mApr
+    of "may":
+      info.month =  mMay
+    of "jun":
+      info.month =  mJun
+    of "jul":
+      info.month =  mJul
+    of "aug":
+      info.month =  mAug
+    of "sep":
+      info.month =  mSep
+    of "oct":
+      info.month =  mOct
+    of "nov":
+      info.month =  mNov
+    of "dec":
+      info.month =  mDec
+    else:
+      raise newException(ValueError, "invalid month")
+    j += 3
+  of "MMMM":
+    if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
+      info.month =  mJan
+      j += 7
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0:
+      info.month =  mFeb
+      j += 8
+    elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0:
+      info.month =  mMar
+      j += 5
+    elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0:
+      info.month =  mApr
+      j += 5
+    elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0:
+      info.month =  mMay
+      j += 3
+    elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0:
+      info.month =  mJun
+      j += 4
+    elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0:
+      info.month =  mJul
+      j += 4
+    elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0:
+      info.month =  mAug
+      j += 6
+    elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0:
+      info.month =  mSep
+      j += 9
+    elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0:
+      info.month =  mOct
+      j += 7
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0:
+      info.month =  mNov
+      j += 8
+    elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0:
+      info.month =  mDec
+      j += 8
+    else:
+      raise newException(ValueError, "invalid month")
+  of "s":
+    var pd = parseInt(value[j..j+1], sv)
+    info.second = sv
+    j += pd
+  of "ss":
+    info.second = value[j..j+1].parseInt()
+    j += 2
+  of "t":
+    if value[j] == 'P' and info.hour > 0 and info.hour < 12:
+      info.hour += 12
+    j += 1
+  of "tt":
+    if value[j..j+1] == "PM" and info.hour > 0 and info.hour < 12:
+      info.hour += 12
+    j += 2
+  of "yy":
+    # Assumes current century
+    var year = value[j..j+1].parseInt()
+    var thisCen = getLocalTime(getTime()).year div 100
+    info.year = thisCen*100 + year
+    j += 2
+  of "yyyy":
+    info.year = value[j..j+3].parseInt()
+    j += 4
+  of "z":
+    if value[j] == '+':
+      info.timezone = parseInt($value[j+1])
+    elif value[j] == '-':
+      info.timezone = 0-parseInt($value[j+1])
+    else:
+      raise newException(ValueError, "Sign for timezone " & value[j])
+    j += 2
+  of "zz":
+    if value[j] == '+':
+      info.timezone = value[j+1..j+2].parseInt()
+    elif value[j] == '-':
+      info.timezone = 0-value[j+1..j+2].parseInt()
+    else:
+      raise newException(ValueError, "Sign for timezone " & value[j])
+    j += 3
+  of "zzz":
+    if value[j] == '+':
+      info.timezone = value[j+1..j+2].parseInt()
+    elif value[j] == '-':
+      info.timezone = 0-value[j+1..j+2].parseInt()
+    else:
+      raise newException(ValueError, "Sign for timezone " & value[j])
+    j += 6
+  of "ZZZ":
+    info.tzname = value[j..j+2].toUpper()
+    j += 3
+  else:
+    # Ignore the token and move forward in the value string by the same length
+    j += token.len
+
+proc parse*(value, layout: string): TimeInfo =
+  ## This function parses a date/time string using the standard format identifiers (below)
+  ## The function defaults information not provided in the format string from the running program (timezone, month, year, etc)
+  ##
+  ## ==========  =================================================================================  ================================================
+  ## Specifier   Description                                                                        Example
+  ## ==========  =================================================================================  ================================================
+  ##    d        Numeric value of the day of the month, it will be one or two digits long.          ``1/04/2012 -> 1``, ``21/04/2012 -> 21``
+  ##    dd       Same as above, but always two digits.                                              ``1/04/2012 -> 01``, ``21/04/2012 -> 21``
+  ##    ddd      Three letter string which indicates the day of the week.                           ``Saturday -> Sat``, ``Monday -> Mon``
+  ##    dddd     Full string for the day of the week.                                               ``Saturday -> Saturday``, ``Monday -> Monday``
+  ##    h        The hours in one digit if possible. Ranging from 0-12.                             ``5pm -> 5``, ``2am -> 2``
+  ##    hh       The hours in two digits always. If the hour is one digit 0 is prepended.           ``5pm -> 05``, ``11am -> 11``
+  ##    H        The hours in one digit if possible, randing from 0-24.                             ``5pm -> 17``, ``2am -> 2``
+  ##    HH       The hours in two digits always. 0 is prepended if the hour is one digit.           ``5pm -> 17``, ``2am -> 02``
+  ##    m        The minutes in 1 digit if possible.                                                ``5:30 -> 30``, ``2:01 -> 1``
+  ##    mm       Same as above but always 2 digits, 0 is prepended if the minute is one digit.      ``5:30 -> 30``, ``2:01 -> 01``
+  ##    M        The month in one digit if possible.                                                ``September -> 9``, ``December -> 12``
+  ##    MM       The month in two digits always. 0 is prepended.                                    ``September -> 09``, ``December -> 12``
+  ##    MMM      Abbreviated three-letter form of the month.                                        ``September -> Sep``, ``December -> Dec``
+  ##    MMMM     Full month string, properly capitalized.                                           ``September -> September``
+  ##    s        Seconds as one digit if possible.                                                  ``00:00:06 -> 6``
+  ##    ss       Same as above but always two digits. 0 is prepended.                               ``00:00:06 -> 06``
+  ##    t        ``A`` when time is in the AM. ``P`` when time is in the PM.
+  ##    tt       Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively.
+  ##    yy       Displays the year to two digits.                                                   ``2012 -> 12``
+  ##    yyyy     Displays the year to four digits.                                                  ``2012 -> 2012``
+  ##    z        Displays the timezone offset from UTC.                                             ``GMT+7 -> +7``, ``GMT-5 -> -5``
+  ##    zz       Same as above but with leading 0.                                                  ``GMT+7 -> +07``, ``GMT-5 -> -05``
+  ##    zzz      Same as above but with ``:00``.                                                    ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00``
+  ##    ZZZ      Displays the name of the timezone.                                                 ``GMT -> GMT``, ``EST -> EST``
+  ## ==========  =================================================================================  ================================================
+  ##
+  ## Other strings can be inserted by putting them in ``''``. For example
+  ## ``hh'->'mm`` will give ``01->56``.  The following characters can be
+  ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
+  ## ``,``. However you don't need to necessarily separate format specifiers, a
+  ## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
+  var i = 0 # pointer for format string
+  var j = 0 # pointer for value string
+  var token = ""
+  # Assumes current day of month, month and year, but time is reset to 00:00:00. Weekday will be reset after parsing.
+  var info = getLocalTime(getTime())
+  info.hour = 0
+  info.minute = 0
+  info.second = 0
+  while true:
+    case layout[i]
+    of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
+      if token.len > 0:
+        parseToken(info, token, value, j)
+      # Reset token
+      token = ""
+      # Break if at end of line
+      if layout[i] == '\0': break
+      # Skip separator and everything between single quotes
+      # These are literals in both the layout and the value string
+      if layout[i] == '\'':
+        inc(i)
+        inc(j)
+        while layout[i] != '\'' and layout.len-1 > i:
+          inc(i)
+          inc(j)
+      else:
+        inc(i)
+        inc(j)
+    else:
+      # Check if the letter being added matches previous accumulated buffer.
+      if token.len < 1 or token[high(token)] == layout[i]:
+        token.add(layout[i])
+        inc(i)
+      else:
+        parseToken(info, token, value, j)
+        token = ""
+  # Reset weekday as it might not have been provided and the default may be wrong
+  info.weekday = getLocalTime(timeInfoToTime(info)).weekday
+  return info
+
+
+when isMainModule:
+  # $ date --date='@2147483647'
+  # Tue 19 Jan 03:14:07 GMT 2038
+
+  var t = getGMTime(fromSeconds(2147483647))
+  assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
+  assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
+
+  assert t.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
+    " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
+    "19 19 Tue Tuesday 3 03 3 03 14 14 1 01 Jan January 7 07 A AM 8 38 038 2038 02038 0 00 00:00 UTC"
+
+  assert t.format("yyyyMMddhhmmss") == "20380119031407"
+
+  var t2 = getGMTime(fromSeconds(160070789)) # Mon 27 Jan 16:06:29 GMT 1975
+  assert t2.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
+    " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
+    "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC"
+
+  when not defined(JS) and sizeof(Time) == 8:
+    var t3 = getGMTime(fromSeconds(889067643645)) # Fri  7 Jun 19:20:45 BST 30143
+    assert t3.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
+      " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
+      "7 07 Fri Friday 6 06 18 18 20 20 6 06 Jun June 45 45 P PM 3 43 143 0143 30143 0 00 00:00 UTC"
+    assert t3.format(":,[]()-/") == ":,[]()-/"
+
+  var t4 = getGMTime(fromSeconds(876124714)) # Mon  6 Oct 08:58:34 BST 1997
+  assert t4.format("M MM MMM MMMM") == "10 10 Oct October"
+
+  # Interval tests
+  assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
+  assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
+
+  var s = "Tuesday at 09:04am on Dec 15, 2015"
+  var f = "dddd at hh:mmtt on MMM d, yyyy"
+  assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
+  # ANSIC       = "Mon Jan _2 15:04:05 2006"
+  s = "Thu Jan 12 15:04:05 2006"
+  f = "ddd MMM dd HH:mm:ss yyyy"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
+  s = "Thu Jan 12 15:04:05 MST 2006"
+  f = "ddd MMM dd HH:mm:ss ZZZ yyyy"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
+  s = "Thu Jan 12 15:04:05 -07:00 2006"
+  f = "ddd MMM dd HH:mm:ss zzz yyyy"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # RFC822      = "02 Jan 06 15:04 MST"
+  s = "12 Jan 16 15:04 MST"
+  f = "dd MMM yy HH:mm ZZZ"
+  assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
+  # RFC822Z     = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
+  s = "12 Jan 16 15:04 -07:00"
+  f = "dd MMM yy HH:mm zzz"
+  assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
+  # RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
+  s = "Monday, 12-Jan-06 15:04:05 MST"
+  f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
+  s = "Thu, 12 Jan 2006 15:04:05 MST"
+  f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
+  s = "Thu, 12 Jan 2006 15:04:05 -07:00"
+  f = "ddd, dd MMM yyyy HH:mm:ss zzz"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # RFC3339     = "2006-01-02T15:04:05Z07:00"
+  s = "2006-01-12T15:04:05Z-07:00"
+  f = "yyyy-MM-ddTHH:mm:ssZzzz"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
+  s = "2006-01-12T15:04:05.999999999Z-07:00"
+  f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
+  assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
+  # Kitchen     = "3:04PM"
+  s = "3:04PM"
+  f = "h:mmtt"
+  assert "15:04:00" in $s.parse(f)
+  when not defined(testing):
+    echo "Kitchen: " & $s.parse(f)
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
new file mode 100644
index 000000000..2c3d872df
--- /dev/null
+++ b/lib/pure/typetraits.nim
@@ -0,0 +1,36 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Nim Contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module defines compile-time reflection procs for
+## working with types
+
+proc name*(t: typedesc): string {.magic: "TypeTrait".}
+  ## Returns the name of the given type.
+  ##
+  ## Example:
+  ##
+  ## .. code-block::
+  ##
+  ##   import typetraits
+  ##
+  ##   proc `$`*[T](some:typedesc[T]): string = name(T)
+  ##
+  ##   template test(x): stmt =
+  ##     echo "type: ", type(x), ", value: ", x
+  ##
+  ##   test 42
+  ##   # --> type: int, value: 42
+  ##   test "Foo"
+  ##   # --> type: string, value: Foo
+  ##   test(@['A','B'])
+  ##   # --> type: seq[char], value: @[A, B]
+
+
+proc arity*(t: typedesc): int {.magic: "TypeTrait".}
+  ## Returns the arity of the given type
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
new file mode 100644
index 000000000..5fd3c2418
--- /dev/null
+++ b/lib/pure/unicode.nim
@@ -0,0 +1,1318 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module provides support to handle the Unicode UTF-8 encoding.
+
+{.deadCodeElim: on.}
+
+include "system/inclrtl"
+
+type
+  RuneImpl = int # underlying type of Rune
+  Rune* = distinct RuneImpl   ## type that can hold any Unicode character
+  Rune16* = distinct int16 ## 16 bit Unicode character
+
+{.deprecated: [TRune: Rune, TRune16: Rune16].}
+
+proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
+proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
+proc `==`*(a, b: Rune): bool = return int(a) == int(b)
+
+template ones(n: expr): expr = ((1 shl n)-1)
+
+proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
+  ## returns the number of Unicode characters of the string `s`.
+  var i = 0
+  while i < len(s):
+    if ord(s[i]) <=% 127: inc(i)
+    elif ord(s[i]) shr 5 == 0b110: inc(i, 2)
+    elif ord(s[i]) shr 4 == 0b1110: inc(i, 3)
+    elif ord(s[i]) shr 3 == 0b11110: inc(i, 4)
+    elif ord(s[i]) shr 2 == 0b111110: inc(i, 5)
+    elif ord(s[i]) shr 1 == 0b1111110: inc(i, 6)
+    else: inc i
+    inc(result)
+
+proc runeLenAt*(s: string, i: Natural): int =
+  ## returns the number of bytes the rune starting at ``s[i]`` takes.
+  if ord(s[i]) <=% 127: result = 1
+  elif ord(s[i]) shr 5 == 0b110: result = 2
+  elif ord(s[i]) shr 4 == 0b1110: result = 3
+  elif ord(s[i]) shr 3 == 0b11110: result = 4
+  elif ord(s[i]) shr 2 == 0b111110: result = 5
+  elif ord(s[i]) shr 1 == 0b1111110: result = 6
+  else: result = 1
+
+template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
+  ## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
+  ## `i` is incremented by the number of bytes that have been processed.
+  bind ones
+  if ord(s[i]) <=% 127:
+    result = Rune(ord(s[i]))
+    when doInc: inc(i)
+  elif ord(s[i]) shr 5 == 0b110:
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    result = Rune((ord(s[i]) and (ones(5))) shl 6 or
+                  (ord(s[i+1]) and ones(6)))
+    when doInc: inc(i, 2)
+  elif ord(s[i]) shr 4 == 0b1110:
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    result = Rune((ord(s[i]) and ones(4)) shl 12 or
+             (ord(s[i+1]) and ones(6)) shl 6 or
+             (ord(s[i+2]) and ones(6)))
+    when doInc: inc(i, 3)
+  elif ord(s[i]) shr 3 == 0b11110:
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+3]) shr 6 == 0b10)
+    result = Rune((ord(s[i]) and ones(3)) shl 18 or
+             (ord(s[i+1]) and ones(6)) shl 12 or
+             (ord(s[i+2]) and ones(6)) shl 6 or
+             (ord(s[i+3]) and ones(6)))
+    when doInc: inc(i, 4)
+  elif ord(s[i]) shr 2 == 0b111110:
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+3]) shr 6 == 0b10)
+    # assert(ord(s[i+4]) shr 6 == 0b10)
+    result = Rune((ord(s[i]) and ones(2)) shl 24 or
+             (ord(s[i+1]) and ones(6)) shl 18 or
+             (ord(s[i+2]) and ones(6)) shl 12 or
+             (ord(s[i+3]) and ones(6)) shl 6 or
+             (ord(s[i+4]) and ones(6)))
+    when doInc: inc(i, 5)
+  elif ord(s[i]) shr 1 == 0b1111110:
+    # assert(ord(s[i+1]) shr 6 == 0b10)
+    # assert(ord(s[i+2]) shr 6 == 0b10)
+    # assert(ord(s[i+3]) shr 6 == 0b10)
+    # assert(ord(s[i+4]) shr 6 == 0b10)
+    # assert(ord(s[i+5]) shr 6 == 0b10)
+    result = Rune((ord(s[i]) and ones(1)) shl 30 or
+             (ord(s[i+1]) and ones(6)) shl 24 or
+             (ord(s[i+2]) and ones(6)) shl 18 or
+             (ord(s[i+3]) and ones(6)) shl 12 or
+             (ord(s[i+4]) and ones(6)) shl 6 or
+             (ord(s[i+5]) and ones(6)))
+    when doInc: inc(i, 6)
+  else:
+    result = Rune(ord(s[i]))
+    when doInc: inc(i)
+
+proc validateUtf8*(s: string): int =
+  ## returns the position of the invalid byte in ``s`` if the string ``s`` does
+  ## not hold valid UTF-8 data. Otherwise -1 is returned.
+  var i = 0
+  let L = s.len
+  while i < L:
+    if ord(s[i]) <=% 127:
+      inc(i)
+    elif ord(s[i]) shr 5 == 0b110:
+      if i+1 < L and ord(s[i+1]) shr 6 == 0b10: inc(i, 2)
+      else: return i
+    elif ord(s[i]) shr 4 == 0b1110:
+      if i+2 < L and ord(s[i+1]) shr 6 == 0b10 and ord(s[i+2]) shr 6 == 0b10:
+        inc i, 3
+      else: return i
+    elif ord(s[i]) shr 3 == 0b11110:
+      if i+3 < L and ord(s[i+1]) shr 6 == 0b10 and
+                     ord(s[i+2]) shr 6 == 0b10 and
+                     ord(s[i+3]) shr 6 == 0b10:
+        inc i, 4
+      else: return i
+    else:
+      return i
+  return -1
+
+proc runeAt*(s: string, i: Natural): Rune =
+  ## returns the unicode character in `s` at byte index `i`
+  fastRuneAt(s, i, result, false)
+
+proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
+  ## converts a rune into its UTF8 representation
+  var i = RuneImpl(c)
+  if i <=% 127:
+    result = newString(1)
+    result[0] = chr(i)
+  elif i <=% 0x07FF:
+    result = newString(2)
+    result[0] = chr((i shr 6) or 0b110_00000)
+    result[1] = chr((i and ones(6)) or 0b10_0000_00)
+  elif i <=% 0xFFFF:
+    result = newString(3)
+    result[0] = chr(i shr 12 or 0b1110_0000)
+    result[1] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x001FFFFF:
+    result = newString(4)
+    result[0] = chr(i shr 18 or 0b1111_0000)
+    result[1] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x03FFFFFF:
+    result = newString(5)
+    result[0] = chr(i shr 24 or 0b111110_00)
+    result[1] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i and ones(6) or 0b10_0000_00)
+  elif i <=% 0x7FFFFFFF:
+    result = newString(6)
+    result[0] = chr(i shr 30 or 0b1111110_0)
+    result[1] = chr(i shr 24 and ones(6) or 0b10_0000_00)
+    result[2] = chr(i shr 18 and ones(6) or 0b10_0000_00)
+    result[3] = chr(i shr 12 and ones(6) or 0b10_0000_00)
+    result[4] = chr(i shr 6 and ones(6) or 0b10_0000_00)
+    result[5] = chr(i and ones(6) or 0b10_0000_00)
+  else:
+    discard # error, exception?
+
+proc `$`*(rune: Rune): string =
+  ## converts a rune to a string
+  rune.toUTF8
+
+proc `$`*(runes: seq[Rune]): string =
+  ## converts a sequence of runes to a string
+  result = ""
+  for rune in runes: result.add(rune.toUTF8)
+
+const
+  alphaRanges = [
+    0x00d8,  0x00f6,  #  -
+    0x00f8,  0x01f5,  #  -
+    0x0250,  0x02a8,  #  -
+    0x038e,  0x03a1,  #  -
+    0x03a3,  0x03ce,  #  -
+    0x03d0,  0x03d6,  #  -
+    0x03e2,  0x03f3,  #  -
+    0x0490,  0x04c4,  #  -
+    0x0561,  0x0587,  #  -
+    0x05d0,  0x05ea,  #  -
+    0x05f0,  0x05f2,  #  -
+    0x0621,  0x063a,  #  -
+    0x0640,  0x064a,  #  -
+    0x0671,  0x06b7,  #  -
+    0x06ba,  0x06be,  #  -
+    0x06c0,  0x06ce,  #  -
+    0x06d0,  0x06d3,  #  -
+    0x0905,  0x0939,  #  -
+    0x0958,  0x0961,  #  -
+    0x0985,  0x098c,  #  -
+    0x098f,  0x0990,  #  -
+    0x0993,  0x09a8,  #  -
+    0x09aa,  0x09b0,  #  -
+    0x09b6,  0x09b9,  #  -
+    0x09dc,  0x09dd,  #  -
+    0x09df,  0x09e1,  #  -
+    0x09f0,  0x09f1,  #  -
+    0x0a05,  0x0a0a,  #  -
+    0x0a0f,  0x0a10,  #  -
+    0x0a13,  0x0a28,  #  -
+    0x0a2a,  0x0a30,  #  -
+    0x0a32,  0x0a33,  #  -
+    0x0a35,  0x0a36,  #  -
+    0x0a38,  0x0a39,  #  -
+    0x0a59,  0x0a5c,  #  -
+    0x0a85,  0x0a8b,  #  -
+    0x0a8f,  0x0a91,  #  -
+    0x0a93,  0x0aa8,  #  -
+    0x0aaa,  0x0ab0,  #  -
+    0x0ab2,  0x0ab3,  #  -
+    0x0ab5,  0x0ab9,  #  -
+    0x0b05,  0x0b0c,  #  -
+    0x0b0f,  0x0b10,  #  -
+    0x0b13,  0x0b28,  #  -
+    0x0b2a,  0x0b30,  #  -
+    0x0b32,  0x0b33,  #  -
+    0x0b36,  0x0b39,  #  -
+    0x0b5c,  0x0b5d,  #  -
+    0x0b5f,  0x0b61,  #  -
+    0x0b85,  0x0b8a,  #  -
+    0x0b8e,  0x0b90,  #  -
+    0x0b92,  0x0b95,  #  -
+    0x0b99,  0x0b9a,  #  -
+    0x0b9e,  0x0b9f,  #  -
+    0x0ba3,  0x0ba4,  #  -
+    0x0ba8,  0x0baa,  #  -
+    0x0bae,  0x0bb5,  #  -
+    0x0bb7,  0x0bb9,  #  -
+    0x0c05,  0x0c0c,  #  -
+    0x0c0e,  0x0c10,  #  -
+    0x0c12,  0x0c28,  #  -
+    0x0c2a,  0x0c33,  #  -
+    0x0c35,  0x0c39,  #  -
+    0x0c60,  0x0c61,  #  -
+    0x0c85,  0x0c8c,  #  -
+    0x0c8e,  0x0c90,  #  -
+    0x0c92,  0x0ca8,  #  -
+    0x0caa,  0x0cb3,  #  -
+    0x0cb5,  0x0cb9,  #  -
+    0x0ce0,  0x0ce1,  #  -
+    0x0d05,  0x0d0c,  #  -
+    0x0d0e,  0x0d10,  #  -
+    0x0d12,  0x0d28,  #  -
+    0x0d2a,  0x0d39,  #  -
+    0x0d60,  0x0d61,  #  -
+    0x0e01,  0x0e30,  #  -
+    0x0e32,  0x0e33,  #  -
+    0x0e40,  0x0e46,  #  -
+    0x0e5a,  0x0e5b,  #  -
+    0x0e81,  0x0e82,  #  -
+    0x0e87,  0x0e88,  #  -
+    0x0e94,  0x0e97,  #  -
+    0x0e99,  0x0e9f,  #  -
+    0x0ea1,  0x0ea3,  #  -
+    0x0eaa,  0x0eab,  #  -
+    0x0ead,  0x0eae,  #  -
+    0x0eb2,  0x0eb3,  #  -
+    0x0ec0,  0x0ec4,  #  -
+    0x0edc,  0x0edd,  #  -
+    0x0f18,  0x0f19,  #  -
+    0x0f40,  0x0f47,  #  -
+    0x0f49,  0x0f69,  #  -
+    0x10d0,  0x10f6,  #  -
+    0x1100,  0x1159,  #  -
+    0x115f,  0x11a2,  #  -
+    0x11a8,  0x11f9,  #  -
+    0x1e00,  0x1e9b,  #  -
+    0x1f50,  0x1f57,  #  -
+    0x1f80,  0x1fb4,  #  -
+    0x1fb6,  0x1fbc,  #  -
+    0x1fc2,  0x1fc4,  #  -
+    0x1fc6,  0x1fcc,  #  -
+    0x1fd0,  0x1fd3,  #  -
+    0x1fd6,  0x1fdb,  #  -
+    0x1fe0,  0x1fec,  #  -
+    0x1ff2,  0x1ff4,  #  -
+    0x1ff6,  0x1ffc,  #  -
+    0x210a,  0x2113,  #  -
+    0x2115,  0x211d,  #  -
+    0x2120,  0x2122,  #  -
+    0x212a,  0x2131,  #  -
+    0x2133,  0x2138,  #  -
+    0x3041,  0x3094,  #  -
+    0x30a1,  0x30fa,  #  -
+    0x3105,  0x312c,  #  -
+    0x3131,  0x318e,  #  -
+    0x3192,  0x319f,  #  -
+    0x3260,  0x327b,  #  -
+    0x328a,  0x32b0,  #  -
+    0x32d0,  0x32fe,  #  -
+    0x3300,  0x3357,  #  -
+    0x3371,  0x3376,  #  -
+    0x337b,  0x3394,  #  -
+    0x3399,  0x339e,  #  -
+    0x33a9,  0x33ad,  #  -
+    0x33b0,  0x33c1,  #  -
+    0x33c3,  0x33c5,  #  -
+    0x33c7,  0x33d7,  #  -
+    0x33d9,  0x33dd,  #  -
+    0x4e00,  0x9fff,  #  -
+    0xac00,  0xd7a3,  #  -
+    0xf900,  0xfb06,  #  -
+    0xfb13,  0xfb17,  #  -
+    0xfb1f,  0xfb28,  #  -
+    0xfb2a,  0xfb36,  #  -
+    0xfb38,  0xfb3c,  #  -
+    0xfb40,  0xfb41,  #  -
+    0xfb43,  0xfb44,  #  -
+    0xfb46,  0xfbb1,  #  -
+    0xfbd3,  0xfd3d,  #  -
+    0xfd50,  0xfd8f,  #  -
+    0xfd92,  0xfdc7,  #  -
+    0xfdf0,  0xfdf9,  #  -
+    0xfe70,  0xfe72,  #  -
+    0xfe76,  0xfefc,  #  -
+    0xff66,  0xff6f,  #  -
+    0xff71,  0xff9d,  #  -
+    0xffa0,  0xffbe,  #  -
+    0xffc2,  0xffc7,  #  -
+    0xffca,  0xffcf,  #  -
+    0xffd2,  0xffd7,  #  -
+    0xffda,  0xffdc]  #  -
+
+  alphaSinglets = [
+    0x00aa,  #
+    0x00b5,  #
+    0x00ba,  #
+    0x03da,  #
+    0x03dc,  #
+    0x03de,  #
+    0x03e0,  #
+    0x06d5,  #
+    0x09b2,  #
+    0x0a5e,  #
+    0x0a8d,  #
+    0x0ae0,  #
+    0x0b9c,  #
+    0x0cde,  #
+    0x0e4f,  #
+    0x0e84,  #
+    0x0e8a,  #
+    0x0e8d,  #
+    0x0ea5,  #
+    0x0ea7,  #
+    0x0eb0,  #
+    0x0ebd,  #
+    0x1fbe,  #
+    0x207f,  #
+    0x20a8,  #
+    0x2102,  #
+    0x2107,  #
+    0x2124,  #
+    0x2126,  #
+    0x2128,  #
+    0xfb3e,  #
+    0xfe74]  #
+
+  spaceRanges = [
+    0x0009,  0x000a,  # tab and newline
+    0x0020,  0x0020,  # space
+    0x00a0,  0x00a0,  #
+    0x2000,  0x200b,  #  -
+    0x2028,  0x2029,  #  -     0x3000,  0x3000,  #
+    0xfeff,  0xfeff]  #
+
+  toupperRanges = [
+    0x0061,  0x007a, 468,  # a-z A-Z
+    0x00e0,  0x00f6, 468,  # - -
+    0x00f8,  0x00fe, 468,  # - -
+    0x0256,  0x0257, 295,  # - -
+    0x0258,  0x0259, 298,  # - -
+    0x028a,  0x028b, 283,  # - -
+    0x03ad,  0x03af, 463,  # - -
+    0x03b1,  0x03c1, 468,  # - -
+    0x03c3,  0x03cb, 468,  # - -
+    0x03cd,  0x03ce, 437,  # - -
+    0x0430,  0x044f, 468,  # - -
+    0x0451,  0x045c, 420,  # - -
+    0x045e,  0x045f, 420,  # - -
+    0x0561,  0x0586, 452,  # - -
+    0x1f00,  0x1f07, 508,  # - -
+    0x1f10,  0x1f15, 508,  # - -
+    0x1f20,  0x1f27, 508,  # - -
+    0x1f30,  0x1f37, 508,  # - -
+    0x1f40,  0x1f45, 508,  # - -
+    0x1f60,  0x1f67, 508,  # - -
+    0x1f70,  0x1f71, 574,  # - -
+    0x1f72,  0x1f75, 586,  # - -
+    0x1f76,  0x1f77, 600,  # - -
+    0x1f78,  0x1f79, 628,  # - -
+    0x1f7a,  0x1f7b, 612,  # - -
+    0x1f7c,  0x1f7d, 626,  # - -
+    0x1f80,  0x1f87, 508,  # - -
+    0x1f90,  0x1f97, 508,  # - -
+    0x1fa0,  0x1fa7, 508,  # - -
+    0x1fb0,  0x1fb1, 508,  # - -
+    0x1fd0,  0x1fd1, 508,  # - -
+    0x1fe0,  0x1fe1, 508,  # - -
+    0x2170,  0x217f, 484,  # - -
+    0x24d0,  0x24e9, 474,  # - -
+    0xff41,  0xff5a, 468]  # - -
+
+  toupperSinglets = [
+    0x00ff, 621,  #
+    0x0101, 499,  #
+    0x0103, 499,  #
+    0x0105, 499,  #
+    0x0107, 499,  #
+    0x0109, 499,  #
+    0x010b, 499,  #
+    0x010d, 499,  #
+    0x010f, 499,  #
+    0x0111, 499,  #
+    0x0113, 499,  #
+    0x0115, 499,  #
+    0x0117, 499,  #
+    0x0119, 499,  #
+    0x011b, 499,  #
+    0x011d, 499,  #
+    0x011f, 499,  #
+    0x0121, 499,  #
+    0x0123, 499,  #
+    0x0125, 499,  #
+    0x0127, 499,  #
+    0x0129, 499,  #
+    0x012b, 499,  #
+    0x012d, 499,  #
+    0x012f, 499,  #
+    0x0131, 268,  #  I
+    0x0133, 499,  #
+    0x0135, 499,  #
+    0x0137, 499,  #
+    0x013a, 499,  #
+    0x013c, 499,  #
+    0x013e, 499,  #
+    0x0140, 499,  #
+    0x0142, 499,  #
+    0x0144, 499,  #
+    0x0146, 499,  #
+    0x0148, 499,  #
+    0x014b, 499,  #
+    0x014d, 499,  #
+    0x014f, 499,  #
+    0x0151, 499,  #
+    0x0153, 499,  #
+    0x0155, 499,  #
+    0x0157, 499,  #
+    0x0159, 499,  #
+    0x015b, 499,  #
+    0x015d, 499,  #
+    0x015f, 499,  #
+    0x0161, 499,  #
+    0x0163, 499,  #
+    0x0165, 499,  #
+    0x0167, 499,  #
+    0x0169, 499,  #
+    0x016b, 499,  #
+    0x016d, 499,  #
+    0x016f, 499,  #
+    0x0171, 499,  #
+    0x0173, 499,  #
+    0x0175, 499,  #
+    0x0177, 499,  #
+    0x017a, 499,  #
+    0x017c, 499,  #
+    0x017e, 499,  #
+    0x017f, 200,  #  S
+    0x0183, 499,  #
+    0x0185, 499,  #
+    0x0188, 499,  #
+    0x018c, 499,  #
+    0x0192, 499,  #
+    0x0199, 499,  #
+    0x01a1, 499,  #
+    0x01a3, 499,  #
+    0x01a5, 499,  #
+    0x01a8, 499,  #
+    0x01ad, 499,  #
+    0x01b0, 499,  #
+    0x01b4, 499,  #
+    0x01b6, 499,  #
+    0x01b9, 499,  #
+    0x01bd, 499,  #
+    0x01c5, 499,  #
+    0x01c6, 498,  #
+    0x01c8, 499,  #
+    0x01c9, 498,  #
+    0x01cb, 499,  #
+    0x01cc, 498,  #
+    0x01ce, 499,  #
+    0x01d0, 499,  #
+    0x01d2, 499,  #
+    0x01d4, 499,  #
+    0x01d6, 499,  #
+    0x01d8, 499,  #
+    0x01da, 499,  #
+    0x01dc, 499,  #
+    0x01df, 499,  #
+    0x01e1, 499,  #
+    0x01e3, 499,  #
+    0x01e5, 499,  #
+    0x01e7, 499,  #
+    0x01e9, 499,  #
+    0x01eb, 499,  #
+    0x01ed, 499,  #
+    0x01ef, 499,  #
+    0x01f2, 499,  #
+    0x01f3, 498,  #
+    0x01f5, 499,  #
+    0x01fb, 499,  #
+    0x01fd, 499,  #
+    0x01ff, 499,  #
+    0x0201, 499,  #
+    0x0203, 499,  #
+    0x0205, 499,  #
+    0x0207, 499,  #
+    0x0209, 499,  #
+    0x020b, 499,  #
+    0x020d, 499,  #
+    0x020f, 499,  #
+    0x0211, 499,  #
+    0x0213, 499,  #
+    0x0215, 499,  #
+    0x0217, 499,  #
+    0x0253, 290,  #
+    0x0254, 294,  #
+    0x025b, 297,  #
+    0x0260, 295,  #
+    0x0263, 293,  #
+    0x0268, 291,  #
+    0x0269, 289,  #
+    0x026f, 289,  #
+    0x0272, 287,  #
+    0x0283, 282,  #
+    0x0288, 282,  #
+    0x0292, 281,  #
+    0x03ac, 462,  #
+    0x03cc, 436,  #
+    0x03d0, 438,  #
+    0x03d1, 443,  #
+    0x03d5, 453,  #
+    0x03d6, 446,  #
+    0x03e3, 499,  #
+    0x03e5, 499,  #
+    0x03e7, 499,  #
+    0x03e9, 499,  #
+    0x03eb, 499,  #
+    0x03ed, 499,  #
+    0x03ef, 499,  #
+    0x03f0, 414,  #
+    0x03f1, 420,  #
+    0x0461, 499,  #
+    0x0463, 499,  #
+    0x0465, 499,  #
+    0x0467, 499,  #
+    0x0469, 499,  #
+    0x046b, 499,  #
+    0x046d, 499,  #
+    0x046f, 499,  #
+    0x0471, 499,  #
+    0x0473, 499,  #
+    0x0475, 499,  #
+    0x0477, 499,  #
+    0x0479, 499,  #
+    0x047b, 499,  #
+    0x047d, 499,  #
+    0x047f, 499,  #
+    0x0481, 499,  #
+    0x0491, 499,  #
+    0x0493, 499,  #
+    0x0495, 499,  #
+    0x0497, 499,  #
+    0x0499, 499,  #
+    0x049b, 499,  #
+    0x049d, 499,  #
+    0x049f, 499,  #
+    0x04a1, 499,  #
+    0x04a3, 499,  #
+    0x04a5, 499,  #
+    0x04a7, 499,  #
+    0x04a9, 499,  #
+    0x04ab, 499,  #
+    0x04ad, 499,  #
+    0x04af, 499,  #
+    0x04b1, 499,  #
+    0x04b3, 499,  #
+    0x04b5, 499,  #
+    0x04b7, 499,  #
+    0x04b9, 499,  #
+    0x04bb, 499,  #
+    0x04bd, 499,  #
+    0x04bf, 499,  #
+    0x04c2, 499,  #
+    0x04c4, 499,  #
+    0x04c8, 499,  #
+    0x04cc, 499,  #
+    0x04d1, 499,  #
+    0x04d3, 499,  #
+    0x04d5, 499,  #
+    0x04d7, 499,  #
+    0x04d9, 499,  #
+    0x04db, 499,  #
+    0x04dd, 499,  #
+    0x04df, 499,  #
+    0x04e1, 499,  #
+    0x04e3, 499,  #
+    0x04e5, 499,  #
+    0x04e7, 499,  #
+    0x04e9, 499,  #
+    0x04eb, 499,  #
+    0x04ef, 499,  #
+    0x04f1, 499,  #
+    0x04f3, 499,  #
+    0x04f5, 499,  #
+    0x04f9, 499,  #
+    0x1e01, 499,  #
+    0x1e03, 499,  #
+    0x1e05, 499,  #
+    0x1e07, 499,  #
+    0x1e09, 499,  #
+    0x1e0b, 499,  #
+    0x1e0d, 499,  #
+    0x1e0f, 499,  #
+    0x1e11, 499,  #
+    0x1e13, 499,  #
+    0x1e15, 499,  #
+    0x1e17, 499,  #
+    0x1e19, 499,  #
+    0x1e1b, 499,  #
+    0x1e1d, 499,  #
+    0x1e1f, 499,  #
+    0x1e21, 499,  #
+    0x1e23, 499,  #
+    0x1e25, 499,  #
+    0x1e27, 499,  #
+    0x1e29, 499,  #
+    0x1e2b, 499,  #
+    0x1e2d, 499,  #
+    0x1e2f, 499,  #
+    0x1e31, 499,  #
+    0x1e33, 499,  #
+    0x1e35, 499,  #
+    0x1e37, 499,  #
+    0x1e39, 499,  #
+    0x1e3b, 499,  #
+    0x1e3d, 499,  #
+    0x1e3f, 499,  #
+    0x1e41, 499,  #
+    0x1e43, 499,  #
+    0x1e45, 499,  #
+    0x1e47, 499,  #
+    0x1e49, 499,  #
+    0x1e4b, 499,  #
+    0x1e4d, 499,  #
+    0x1e4f, 499,  #
+    0x1e51, 499,  #
+    0x1e53, 499,  #
+    0x1e55, 499,  #
+    0x1e57, 499,  #
+    0x1e59, 499,  #
+    0x1e5b, 499,  #
+    0x1e5d, 499,  #
+    0x1e5f, 499,  #
+    0x1e61, 499,  #
+    0x1e63, 499,  #
+    0x1e65, 499,  #
+    0x1e67, 499,  #
+    0x1e69, 499,  #
+    0x1e6b, 499,  #
+    0x1e6d, 499,  #
+    0x1e6f, 499,  #
+    0x1e71, 499,  #
+    0x1e73, 499,  #
+    0x1e75, 499,  #
+    0x1e77, 499,  #
+    0x1e79, 499,  #
+    0x1e7b, 499,  #
+    0x1e7d, 499,  #
+    0x1e7f, 499,  #
+    0x1e81, 499,  #
+    0x1e83, 499,  #
+    0x1e85, 499,  #
+    0x1e87, 499,  #
+    0x1e89, 499,  #
+    0x1e8b, 499,  #
+    0x1e8d, 499,  #
+    0x1e8f, 499,  #
+    0x1e91, 499,  #
+    0x1e93, 499,  #
+    0x1e95, 499,  #
+    0x1ea1, 499,  #
+    0x1ea3, 499,  #
+    0x1ea5, 499,  #
+    0x1ea7, 499,  #
+    0x1ea9, 499,  #
+    0x1eab, 499,  #
+    0x1ead, 499,  #
+    0x1eaf, 499,  #
+    0x1eb1, 499,  #
+    0x1eb3, 499,  #
+    0x1eb5, 499,  #
+    0x1eb7, 499,  #
+    0x1eb9, 499,  #
+    0x1ebb, 499,  #
+    0x1ebd, 499,  #
+    0x1ebf, 499,  #
+    0x1ec1, 499,  #
+    0x1ec3, 499,  #
+    0x1ec5, 499,  #
+    0x1ec7, 499,  #
+    0x1ec9, 499,  #
+    0x1ecb, 499,  #
+    0x1ecd, 499,  #
+    0x1ecf, 499,  #
+    0x1ed1, 499,  #
+    0x1ed3, 499,  #
+    0x1ed5, 499,  #
+    0x1ed7, 499,  #
+    0x1ed9, 499,  #
+    0x1edb, 499,  #
+    0x1edd, 499,  #
+    0x1edf, 499,  #
+    0x1ee1, 499,  #
+    0x1ee3, 499,  #
+    0x1ee5, 499,  #
+    0x1ee7, 499,  #
+    0x1ee9, 499,  #
+    0x1eeb, 499,  #
+    0x1eed, 499,  #
+    0x1eef, 499,  #
+    0x1ef1, 499,  #
+    0x1ef3, 499,  #
+    0x1ef5, 499,  #
+    0x1ef7, 499,  #
+    0x1ef9, 499,  #
+    0x1f51, 508,  #
+    0x1f53, 508,  #
+    0x1f55, 508,  #
+    0x1f57, 508,  #
+    0x1fb3, 509,  #
+    0x1fc3, 509,  #
+    0x1fe5, 507,  #
+    0x1ff3, 509]  #
+
+  tolowerRanges = [
+    0x0041,  0x005a, 532,  # A-Z a-z
+    0x00c0,  0x00d6, 532,  # - -
+    0x00d8,  0x00de, 532,  # - -
+    0x0189,  0x018a, 705,  # - -
+    0x018e,  0x018f, 702,  # - -
+    0x01b1,  0x01b2, 717,  # - -
+    0x0388,  0x038a, 537,  # - -
+    0x038e,  0x038f, 563,  # - -
+    0x0391,  0x03a1, 532,  # - -
+    0x03a3,  0x03ab, 532,  # - -
+    0x0401,  0x040c, 580,  # - -
+    0x040e,  0x040f, 580,  # - -
+    0x0410,  0x042f, 532,  # - -
+    0x0531,  0x0556, 548,  # - -
+    0x10a0,  0x10c5, 548,  # - -
+    0x1f08,  0x1f0f, 492,  # - -
+    0x1f18,  0x1f1d, 492,  # - -
+    0x1f28,  0x1f2f, 492,  # - -
+    0x1f38,  0x1f3f, 492,  # - -
+    0x1f48,  0x1f4d, 492,  # - -
+    0x1f68,  0x1f6f, 492,  # - -
+    0x1f88,  0x1f8f, 492,  # - -
+    0x1f98,  0x1f9f, 492,  # - -
+    0x1fa8,  0x1faf, 492,  # - -
+    0x1fb8,  0x1fb9, 492,  # - -
+    0x1fba,  0x1fbb, 426,  # - -
+    0x1fc8,  0x1fcb, 414,  # - -
+    0x1fd8,  0x1fd9, 492,  # - -
+    0x1fda,  0x1fdb, 400,  # - -
+    0x1fe8,  0x1fe9, 492,  # - -
+    0x1fea,  0x1feb, 388,  # - -
+    0x1ff8,  0x1ff9, 372,  # - -
+    0x1ffa,  0x1ffb, 374,  # - -
+    0x2160,  0x216f, 516,  # - -
+    0x24b6,  0x24cf, 526,  # - -
+    0xff21,  0xff3a, 532]  # - -
+
+  tolowerSinglets = [
+    0x0100, 501,  #
+    0x0102, 501,  #
+    0x0104, 501,  #
+    0x0106, 501,  #
+    0x0108, 501,  #
+    0x010a, 501,  #
+    0x010c, 501,  #
+    0x010e, 501,  #
+    0x0110, 501,  #
+    0x0112, 501,  #
+    0x0114, 501,  #
+    0x0116, 501,  #
+    0x0118, 501,  #
+    0x011a, 501,  #
+    0x011c, 501,  #
+    0x011e, 501,  #
+    0x0120, 501,  #
+    0x0122, 501,  #
+    0x0124, 501,  #
+    0x0126, 501,  #
+    0x0128, 501,  #
+    0x012a, 501,  #
+    0x012c, 501,  #
+    0x012e, 501,  #
+    0x0130, 301,  #  i
+    0x0132, 501,  #
+    0x0134, 501,  #
+    0x0136, 501,  #
+    0x0139, 501,  #
+    0x013b, 501,  #
+    0x013d, 501,  #
+    0x013f, 501,  #
+    0x0141, 501,  #
+    0x0143, 501,  #
+    0x0145, 501,  #
+    0x0147, 501,  #
+    0x014a, 501,  #
+    0x014c, 501,  #
+    0x014e, 501,  #
+    0x0150, 501,  #
+    0x0152, 501,  #
+    0x0154, 501,  #
+    0x0156, 501,  #
+    0x0158, 501,  #
+    0x015a, 501,  #
+    0x015c, 501,  #
+    0x015e, 501,  #
+    0x0160, 501,  #
+    0x0162, 501,  #
+    0x0164, 501,  #
+    0x0166, 501,  #
+    0x0168, 501,  #
+    0x016a, 501,  #
+    0x016c, 501,  #
+    0x016e, 501,  #
+    0x0170, 501,  #
+    0x0172, 501,  #
+    0x0174, 501,  #
+    0x0176, 501,  #
+    0x0178, 379,  #
+    0x0179, 501,  #
+    0x017b, 501,  #
+    0x017d, 501,  #
+    0x0181, 710,  #
+    0x0182, 501,  #
+    0x0184, 501,  #
+    0x0186, 706,  #
+    0x0187, 501,  #
+    0x018b, 501,  #
+    0x0190, 703,  #
+    0x0191, 501,  #
+    0x0193, 705,  #
+    0x0194, 707,  #
+    0x0196, 711,  #
+    0x0197, 709,  #
+    0x0198, 501,  #
+    0x019c, 711,  #
+    0x019d, 713,  #
+    0x01a0, 501,  #
+    0x01a2, 501,  #
+    0x01a4, 501,  #
+    0x01a7, 501,  #
+    0x01a9, 718,  #
+    0x01ac, 501,  #
+    0x01ae, 718,  #
+    0x01af, 501,  #
+    0x01b3, 501,  #
+    0x01b5, 501,  #
+    0x01b7, 719,  #
+    0x01b8, 501,  #
+    0x01bc, 501,  #
+    0x01c4, 502,  #
+    0x01c5, 501,  #
+    0x01c7, 502,  #
+    0x01c8, 501,  #
+    0x01ca, 502,  #
+    0x01cb, 501,  #
+    0x01cd, 501,  #
+    0x01cf, 501,  #
+    0x01d1, 501,  #
+    0x01d3, 501,  #
+    0x01d5, 501,  #
+    0x01d7, 501,  #
+    0x01d9, 501,  #
+    0x01db, 501,  #
+    0x01de, 501,  #
+    0x01e0, 501,  #
+    0x01e2, 501,  #
+    0x01e4, 501,  #
+    0x01e6, 501,  #
+    0x01e8, 501,  #
+    0x01ea, 501,  #
+    0x01ec, 501,  #
+    0x01ee, 501,  #
+    0x01f1, 502,  #
+    0x01f2, 501,  #
+    0x01f4, 501,  #
+    0x01fa, 501,  #
+    0x01fc, 501,  #
+    0x01fe, 501,  #
+    0x0200, 501,  #
+    0x0202, 501,  #
+    0x0204, 501,  #
+    0x0206, 501,  #
+    0x0208, 501,  #
+    0x020a, 501,  #
+    0x020c, 501,  #
+    0x020e, 501,  #
+    0x0210, 501,  #
+    0x0212, 501,  #
+    0x0214, 501,  #
+    0x0216, 501,  #
+    0x0386, 538,  #
+    0x038c, 564,  #
+    0x03e2, 501,  #
+    0x03e4, 501,  #
+    0x03e6, 501,  #
+    0x03e8, 501,  #
+    0x03ea, 501,  #
+    0x03ec, 501,  #
+    0x03ee, 501,  #
+    0x0460, 501,  #
+    0x0462, 501,  #
+    0x0464, 501,  #
+    0x0466, 501,  #
+    0x0468, 501,  #
+    0x046a, 501,  #
+    0x046c, 501,  #
+    0x046e, 501,  #
+    0x0470, 501,  #
+    0x0472, 501,  #
+    0x0474, 501,  #
+    0x0476, 501,  #
+    0x0478, 501,  #
+    0x047a, 501,  #
+    0x047c, 501,  #
+    0x047e, 501,  #
+    0x0480, 501,  #
+    0x0490, 501,  #
+    0x0492, 501,  #
+    0x0494, 501,  #
+    0x0496, 501,  #
+    0x0498, 501,  #
+    0x049a, 501,  #
+    0x049c, 501,  #
+    0x049e, 501,  #
+    0x04a0, 501,  #
+    0x04a2, 501,  #
+    0x04a4, 501,  #
+    0x04a6, 501,  #
+    0x04a8, 501,  #
+    0x04aa, 501,  #
+    0x04ac, 501,  #
+    0x04ae, 501,  #
+    0x04b0, 501,  #
+    0x04b2, 501,  #
+    0x04b4, 501,  #
+    0x04b6, 501,  #
+    0x04b8, 501,  #
+    0x04ba, 501,  #
+    0x04bc, 501,  #
+    0x04be, 501,  #
+    0x04c1, 501,  #
+    0x04c3, 501,  #
+    0x04c7, 501,  #
+    0x04cb, 501,  #
+    0x04d0, 501,  #
+    0x04d2, 501,  #
+    0x04d4, 501,  #
+    0x04d6, 501,  #
+    0x04d8, 501,  #
+    0x04da, 501,  #
+    0x04dc, 501,  #
+    0x04de, 501,  #
+    0x04e0, 501,  #
+    0x04e2, 501,  #
+    0x04e4, 501,  #
+    0x04e6, 501,  #
+    0x04e8, 501,  #
+    0x04ea, 501,  #
+    0x04ee, 501,  #
+    0x04f0, 501,  #
+    0x04f2, 501,  #
+    0x04f4, 501,  #
+    0x04f8, 501,  #
+    0x1e00, 501,  #
+    0x1e02, 501,  #
+    0x1e04, 501,  #
+    0x1e06, 501,  #
+    0x1e08, 501,  #
+    0x1e0a, 501,  #
+    0x1e0c, 501,  #
+    0x1e0e, 501,  #
+    0x1e10, 501,  #
+    0x1e12, 501,  #
+    0x1e14, 501,  #
+    0x1e16, 501,  #
+    0x1e18, 501,  #
+    0x1e1a, 501,  #
+    0x1e1c, 501,  #
+    0x1e1e, 501,  #
+    0x1e20, 501,  #
+    0x1e22, 501,  #
+    0x1e24, 501,  #
+    0x1e26, 501,  #
+    0x1e28, 501,  #
+    0x1e2a, 501,  #
+    0x1e2c, 501,  #
+    0x1e2e, 501,  #
+    0x1e30, 501,  #
+    0x1e32, 501,  #
+    0x1e34, 501,  #
+    0x1e36, 501,  #
+    0x1e38, 501,  #
+    0x1e3a, 501,  #
+    0x1e3c, 501,  #
+    0x1e3e, 501,  #
+    0x1e40, 501,  #
+    0x1e42, 501,  #
+    0x1e44, 501,  #
+    0x1e46, 501,  #
+    0x1e48, 501,  #
+    0x1e4a, 501,  #
+    0x1e4c, 501,  #
+    0x1e4e, 501,  #
+    0x1e50, 501,  #
+    0x1e52, 501,  #
+    0x1e54, 501,  #
+    0x1e56, 501,  #
+    0x1e58, 501,  #
+    0x1e5a, 501,  #
+    0x1e5c, 501,  #
+    0x1e5e, 501,  #
+    0x1e60, 501,  #
+    0x1e62, 501,  #
+    0x1e64, 501,  #
+    0x1e66, 501,  #
+    0x1e68, 501,  #
+    0x1e6a, 501,  #
+    0x1e6c, 501,  #
+    0x1e6e, 501,  #
+    0x1e70, 501,  #
+    0x1e72, 501,  #
+    0x1e74, 501,  #
+    0x1e76, 501,  #
+    0x1e78, 501,  #
+    0x1e7a, 501,  #
+    0x1e7c, 501,  #
+    0x1e7e, 501,  #
+    0x1e80, 501,  #
+    0x1e82, 501,  #
+    0x1e84, 501,  #
+    0x1e86, 501,  #
+    0x1e88, 501,  #
+    0x1e8a, 501,  #
+    0x1e8c, 501,  #
+    0x1e8e, 501,  #
+    0x1e90, 501,  #
+    0x1e92, 501,  #
+    0x1e94, 501,  #
+    0x1ea0, 501,  #
+    0x1ea2, 501,  #
+    0x1ea4, 501,  #
+    0x1ea6, 501,  #
+    0x1ea8, 501,  #
+    0x1eaa, 501,  #
+    0x1eac, 501,  #
+    0x1eae, 501,  #
+    0x1eb0, 501,  #
+    0x1eb2, 501,  #
+    0x1eb4, 501,  #
+    0x1eb6, 501,  #
+    0x1eb8, 501,  #
+    0x1eba, 501,  #
+    0x1ebc, 501,  #
+    0x1ebe, 501,  #
+    0x1ec0, 501,  #
+    0x1ec2, 501,  #
+    0x1ec4, 501,  #
+    0x1ec6, 501,  #
+    0x1ec8, 501,  #
+    0x1eca, 501,  #
+    0x1ecc, 501,  #
+    0x1ece, 501,  #
+    0x1ed0, 501,  #
+    0x1ed2, 501,  #
+    0x1ed4, 501,  #
+    0x1ed6, 501,  #
+    0x1ed8, 501,  #
+    0x1eda, 501,  #
+    0x1edc, 501,  #
+    0x1ede, 501,  #
+    0x1ee0, 501,  #
+    0x1ee2, 501,  #
+    0x1ee4, 501,  #
+    0x1ee6, 501,  #
+    0x1ee8, 501,  #
+    0x1eea, 501,  #
+    0x1eec, 501,  #
+    0x1eee, 501,  #
+    0x1ef0, 501,  #
+    0x1ef2, 501,  #
+    0x1ef4, 501,  #
+    0x1ef6, 501,  #
+    0x1ef8, 501,  #
+    0x1f59, 492,  #
+    0x1f5b, 492,  #
+    0x1f5d, 492,  #
+    0x1f5f, 492,  #
+    0x1fbc, 491,  #
+    0x1fcc, 491,  #
+    0x1fec, 493,  #
+    0x1ffc, 491]  #
+
+  toTitleSinglets = [
+    0x01c4, 501,  #
+    0x01c6, 499,  #
+    0x01c7, 501,  #
+    0x01c9, 499,  #
+    0x01ca, 501,  #
+    0x01cc, 499,  #
+    0x01f1, 501,  #
+    0x01f3, 499]  #
+
+proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int =
+  var n = len
+  var t = 0
+  while n > 1:
+    var m = n div 2
+    var p = t + m*stride
+    if c >= tab[p]:
+      t = p
+      n = n-m
+    else:
+      n = m
+  if n != 0 and c >= tab[t]:
+    return t
+  return -1
+
+proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+  ## Converts `c` into lower case. This works for any Unicode character.
+  ## If possible, prefer `toLower` over `toUpper`.
+  var c = RuneImpl(c)
+  var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
+  if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
+    return Rune(c + tolowerRanges[p+2] - 500)
+  p = binarySearch(c, tolowerSinglets, len(tolowerSinglets) div 2, 2)
+  if p >= 0 and c == tolowerSinglets[p]:
+    return Rune(c + tolowerSinglets[p+1] - 500)
+  return Rune(c)
+
+proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+  ## Converts `c` into upper case. This works for any Unicode character.
+  ## If possible, prefer `toLower` over `toUpper`.
+  var c = RuneImpl(c)
+  var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
+  if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
+    return Rune(c + toupperRanges[p+2] - 500)
+  p = binarySearch(c, toupperSinglets, len(toupperSinglets) div 2, 2)
+  if p >= 0 and c == toupperSinglets[p]:
+    return Rune(c + toupperSinglets[p+1] - 500)
+  return Rune(c)
+
+proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} =
+  var c = RuneImpl(c)
+  var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
+  if p >= 0 and c == toTitleSinglets[p]:
+    return Rune(c + toTitleSinglets[p+1] - 500)
+  return Rune(c)
+
+proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## returns true iff `c` is a lower case Unicode character
+  ## If possible, prefer `isLower` over `isUpper`.
+  var c = RuneImpl(c)
+  # Note: toUpperRanges is correct here!
+  var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
+  if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
+    return true
+  p = binarySearch(c, toupperSinglets, len(toupperSinglets) div 2, 2)
+  if p >= 0 and c == toupperSinglets[p]:
+    return true
+
+proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## returns true iff `c` is a upper case Unicode character
+  ## If possible, prefer `isLower` over `isUpper`.
+  var c = RuneImpl(c)
+  # Note: toLowerRanges is correct here!
+  var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
+  if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
+    return true
+  p = binarySearch(c, tolowerSinglets, len(tolowerSinglets) div 2, 2)
+  if p >= 0 and c == tolowerSinglets[p]:
+    return true
+
+proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
+  if isUpper(c) or isLower(c):
+    return true
+  var c = RuneImpl(c)
+  var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
+  if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]:
+    return true
+  p = binarySearch(c, alphaSinglets, len(alphaSinglets), 1)
+  if p >= 0 and c == alphaSinglets[p]:
+    return true
+
+proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  return isUpper(c) and isLower(c)
+
+proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## returns true iff `c` is a Unicode whitespace character
+  var c = RuneImpl(c)
+  var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
+  if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
+    return true
+
+proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} =
+  ## returns true iff `c` is a Unicode combining character
+  var c = RuneImpl(c)
+
+  # Optimized to return false immediately for ASCII
+  return c >= 0x0300 and (c <= 0x036f or
+    (c >= 0x1ab0 and c <= 0x1aff) or
+    (c >= 0x1dc0 and c <= 0x1dff) or
+    (c >= 0x20d0 and c <= 0x20ff) or
+    (c >= 0xfe20 and c <= 0xfe2f))
+
+iterator runes*(s: string): Rune =
+  ## iterates over any unicode character of the string `s`.
+  var
+    i = 0
+    result: Rune
+  while i < len(s):
+    fastRuneAt(s, i, result, true)
+    yield result
+
+proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
+  ## compares two UTF8 strings and ignores the case. Returns:
+  ##
+  ## | 0 iff a == b
+  ## | < 0 iff a < b
+  ## | > 0 iff a > b
+  var i = 0
+  var j = 0
+  var ar, br: Rune
+  while i < a.len and j < b.len:
+    # slow path:
+    fastRuneAt(a, i, ar)
+    fastRuneAt(b, j, br)
+    result = RuneImpl(toLower(ar)) - RuneImpl(toLower(br))
+    if result != 0: return
+  result = a.len - b.len
+
+proc reversed*(s: string): string =
+  ## returns the reverse of `s`, interpreting it as unicode characters. Unicode
+  ## combining characters are correctly interpreted as well:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   assert reversed("Reverse this!") == "!siht esreveR"
+  ##   assert reversed("先秦兩漢") == "漢兩秦先"
+  ##   assert reversed("asâƒdfÌ…") == "fÌ…dsâƒa"
+  ##   assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+  var
+    i = 0
+    lastI = 0
+    newPos = len(s) - 1
+    blockPos = 0
+    r: Rune
+
+  template reverseUntil(pos): stmt =
+    var j = pos - 1
+    while j > blockPos:
+      result[newPos] = s[j]
+      dec j
+      dec newPos
+    blockPos = pos - 1
+
+  result = newString(len(s))
+
+  while i < len(s):
+    lastI = i
+    fastRuneAt(s, i, r, true)
+    if not isCombining(r):
+      reverseUntil(lastI)
+
+  reverseUntil(len(s))
+
+when isMainModule:
+  let
+    someString = "öÑ"
+    someRunes = @[runeAt(someString, 0), runeAt(someString, 2)]
+    compared = (someString == $someRunes)
+  assert compared == true
+
+  assert reversed("Reverse this!") == "!siht esreveR"
+  assert reversed("先秦兩漢") == "漢兩秦先"
+  assert reversed("asâƒdfÌ…") == "fÌ…dsâƒa"
+  assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
diff --git a/lib/pure/unidecode/gen.py b/lib/pure/unidecode/gen.py
new file mode 100644
index 000000000..8da0136ff
--- /dev/null
+++ b/lib/pure/unidecode/gen.py
@@ -0,0 +1,26 @@
+#! usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Generates the unidecode.dat module
+# (c) 2010 Andreas Rumpf
+
+from unidecode import unidecode
+
+def main2(): 
+  data = []
+  for x in xrange(128, 0xffff + 1):
+    u = eval("u'\u%04x'" % x)
+    
+    val = unidecode(u)
+    data.append(val)
+    
+    
+  f = open("unidecode.dat", "wb+") 
+  for d in data:
+    f.write("%s\n" % d)
+  f.close()
+
+
+main2()
+
+
diff --git a/lib/pure/unidecode/unidecode.dat b/lib/pure/unidecode/unidecode.dat
new file mode 100644
index 000000000..9dff0a4a9
--- /dev/null
+++ b/lib/pure/unidecode/unidecode.dat
@@ -0,0 +1,65411 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 
+!
+C/
+PS
+$?
+Y=
+|
+SS
+"
+(c)
+a
+<<
+!
+
+(r)
+-
+deg
++-
+2
+3
+'
+u
+P
+*
+,
+1
+o
+>>
+1/4
+1/2
+3/4
+?
+A
+A
+A
+A
+A
+A
+AE
+C
+E
+E
+E
+E
+I
+I
+I
+I
+D
+N
+O
+O
+O
+O
+O
+x
+O
+U
+U
+U
+U
+U
+Th
+ss
+a
+a
+a
+a
+a
+a
+ae
+c
+e
+e
+e
+e
+i
+i
+i
+i
+d
+n
+o
+o
+o
+o
+o
+/
+o
+u
+u
+u
+u
+y
+th
+y
+A
+a
+A
+a
+A
+a
+C
+c
+C
+c
+C
+c
+C
+c
+D
+d
+D
+d
+E
+e
+E
+e
+E
+e
+E
+e
+E
+e
+G
+g
+G
+g
+G
+g
+G
+g
+H
+h
+H
+h
+I
+i
+I
+i
+I
+i
+I
+i
+I
+i
+IJ
+
+J
+j
+K
+k
+k
+L
+l
+L
+l
+L
+l
+L
+l
+L
+l
+N
+n
+N
+n
+N
+n
+'n
+ng
+NG
+O
+o
+O
+o
+O
+o
+OE
+oe
+R
+r
+R
+r
+R
+r
+S
+s
+S
+s
+S
+s
+S
+s
+T
+t
+T
+t
+T
+t
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+W
+w
+Y
+y
+Y
+Z
+z
+Z
+z
+Z
+z
+s
+b
+B
+B
+b
+6
+6
+O
+C
+c
+D
+D
+D
+d
+d
+3
+@
+E
+F
+f
+G
+G
+hv
+I
+I
+K
+k
+l
+l
+W
+N
+n
+O
+O
+o
+OI
+oi
+P
+p
+YR
+2
+2
+SH
+sh
+t
+T
+t
+T
+U
+u
+Y
+V
+Y
+y
+Z
+z
+ZH
+ZH
+zh
+zh
+2
+5
+5
+ts
+w
+|
+||
+|=
+!
+DZ
+Dz
+dz
+LJ
+Lj
+lj
+NJ
+Nj
+nj
+A
+a
+I
+i
+O
+o
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+@
+A
+a
+A
+a
+AE
+ae
+G
+g
+G
+g
+K
+k
+O
+o
+O
+o
+ZH
+zh
+j
+DZ
+D
+dz
+G
+g
+HV
+W
+N
+n
+A
+a
+AE
+ae
+O
+o
+A
+a
+A
+a
+E
+e
+E
+e
+I
+i
+I
+i
+O
+o
+O
+o
+R
+r
+R
+r
+U
+u
+U
+u
+S
+s
+T
+t
+Y
+y
+H
+h
+[?]
+[?]
+OU
+ou
+Z
+z
+A
+a
+E
+e
+O
+o
+O
+o
+O
+o
+O
+o
+Y
+y
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+a
+a
+a
+b
+o
+c
+d
+d
+e
+@
+@
+e
+e
+e
+e
+j
+g
+g
+g
+g
+u
+Y
+h
+h
+i
+i
+I
+l
+l
+l
+lZ
+W
+W
+m
+n
+n
+n
+o
+OE
+O
+F
+R
+R
+R
+R
+r
+r
+R
+R
+R
+s
+S
+j
+S
+S
+t
+t
+U
+U
+v
+^
+W
+Y
+Y
+z
+z
+Z
+Z
+?
+?
+?
+C
+@
+B
+E
+G
+H
+j
+k
+L
+q
+?
+?
+dz
+dZ
+dz
+ts
+tS
+tC
+fN
+ls
+lz
+WW
+]]
+[?]
+[?]
+k
+h
+j
+r
+r
+r
+r
+w
+y
+'
+"
+`
+'
+`
+`
+'
+?
+?
+<
+>
+^
+V
+^
+V
+'
+-
+/
+\
+,
+_
+\
+/
+:
+.
+`
+'
+^
+V
++
+-
+V
+.
+@
+,
+~
+"
+R
+X
+G
+l
+s
+x
+?
+
+
+
+
+
+
+
+V
+=
+"
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+'
+,
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+?
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+A
+;
+E
+E
+I
+[?]
+O
+[?]
+U
+O
+I
+A
+B
+G
+D
+E
+Z
+E
+Th
+I
+K
+L
+M
+N
+Ks
+O
+P
+R
+[?]
+S
+T
+U
+Ph
+Kh
+Ps
+O
+I
+U
+a
+e
+e
+i
+u
+a
+b
+g
+d
+e
+z
+e
+th
+i
+k
+l
+m
+n
+x
+o
+p
+r
+s
+s
+t
+u
+ph
+kh
+ps
+o
+i
+u
+o
+u
+o
+[?]
+b
+th
+U
+U
+U
+ph
+p
+&
+[?]
+[?]
+St
+st
+W
+w
+Q
+q
+Sp
+sp
+Sh
+sh
+F
+f
+Kh
+kh
+H
+h
+G
+g
+CH
+ch
+Ti
+ti
+k
+r
+c
+j
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+Ie
+Io
+Dj
+Gj
+Ie
+Dz
+I
+Yi
+J
+Lj
+Nj
+Tsh
+Kj
+I
+U
+Dzh
+A
+B
+V
+G
+D
+E
+Zh
+Z
+I
+I
+K
+L
+M
+N
+O
+P
+R
+S
+T
+U
+F
+Kh
+Ts
+Ch
+Sh
+Shch
+'
+Y
+'
+E
+Iu
+Ia
+a
+b
+v
+g
+d
+e
+zh
+z
+i
+i
+k
+l
+m
+n
+o
+p
+r
+s
+t
+u
+f
+kh
+ts
+ch
+sh
+shch
+'
+y
+'
+e
+iu
+ia
+ie
+io
+dj
+gj
+ie
+dz
+i
+yi
+j
+lj
+nj
+tsh
+kj
+i
+u
+dzh
+O
+o
+E
+e
+Ie
+ie
+E
+e
+Ie
+ie
+O
+o
+Io
+io
+Ks
+ks
+Ps
+ps
+F
+f
+Y
+y
+Y
+y
+u
+u
+O
+o
+O
+o
+Ot
+ot
+Q
+q
+*1000*
+
+
+
+
+[?]
+*100.000*
+*1.000.000*
+[?]
+[?]
+"
+"
+R'
+r'
+G'
+g'
+G'
+g'
+G'
+g'
+Zh'
+zh'
+Z'
+z'
+K'
+k'
+K'
+k'
+K'
+k'
+K'
+k'
+N'
+n'
+Ng
+ng
+P'
+p'
+Kh
+kh
+S'
+s'
+T'
+t'
+U
+u
+U'
+u'
+Kh'
+kh'
+Tts
+tts
+Ch'
+ch'
+Ch'
+ch'
+H
+h
+Ch
+ch
+Ch'
+ch'
+`
+Zh
+zh
+K'
+k'
+[?]
+[?]
+N'
+n'
+[?]
+[?]
+Ch
+ch
+[?]
+[?]
+[?]
+a
+a
+A
+a
+Ae
+ae
+Ie
+ie
+@
+@
+@
+@
+Zh
+zh
+Z
+z
+Dz
+dz
+I
+i
+I
+i
+O
+o
+O
+o
+O
+o
+E
+e
+U
+u
+U
+u
+U
+u
+Ch
+ch
+[?]
+[?]
+Y
+y
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+A
+B
+G
+D
+E
+Z
+E
+E
+T`
+Zh
+I
+L
+Kh
+Ts
+K
+H
+Dz
+Gh
+Ch
+M
+Y
+N
+Sh
+O
+Ch`
+P
+J
+Rh
+S
+V
+T
+R
+Ts`
+W
+P`
+K`
+O
+F
+[?]
+[?]
+<
+'
+/
+!
+,
+?
+.
+[?]
+a
+b
+g
+d
+e
+z
+e
+e
+t`
+zh
+i
+l
+kh
+ts
+k
+h
+dz
+gh
+ch
+m
+y
+n
+sh
+o
+ch`
+p
+j
+rh
+s
+v
+t
+r
+ts`
+w
+p`
+k`
+o
+f
+ew
+[?]
+.
+-
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+@
+e
+a
+o
+i
+e
+e
+a
+a
+o
+[?]
+u
+'
+
+
+
+
+
+
+:
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+b
+g
+d
+h
+v
+z
+kh
+t
+y
+k
+k
+l
+m
+m
+n
+n
+s
+`
+p
+p
+ts
+ts
+q
+r
+sh
+t
+[?]
+[?]
+[?]
+[?]
+[?]
+V
+oy
+i
+'
+"
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+,
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+;
+[?]
+[?]
+[?]
+?
+[?]
+
+a
+'
+w'
+
+y'
+
+b
+@
+t
+th
+j
+H
+kh
+d
+dh
+r
+z
+s
+sh
+S
+D
+T
+Z
+`
+G
+[?]
+[?]
+[?]
+[?]
+[?]
+
+f
+q
+k
+l
+m
+n
+h
+w
+~
+y
+an
+un
+in
+a
+u
+i
+W
+
+
+'
+'
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+%
+.
+,
+*
+[?]
+[?]
+
+'
+'
+'
+
+'
+'w
+'u
+'y
+tt
+tth
+b
+t
+T
+p
+th
+bh
+'h
+H
+ny
+dy
+H
+ch
+cch
+dd
+D
+D
+Dt
+dh
+ddh
+d
+D
+D
+rr
+R
+R
+R
+R
+R
+R
+j
+R
+S
+S
+S
+S
+S
+T
+GH
+F
+F
+F
+v
+f
+ph
+Q
+Q
+kh
+k
+K
+K
+ng
+K
+g
+G
+N
+G
+G
+G
+L
+L
+L
+L
+N
+N
+N
+N
+N
+h
+Ch
+hy
+h
+H
+@
+W
+oe
+oe
+u
+yu
+yu
+W
+v
+y
+Y
+Y
+W
+
+
+y
+y'
+.
+ae
+
+
+
+
+
+
+
+@
+#
+
+
+
+
+
+
+
+
+
+
+^
+
+
+
+
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+Sh
+D
+Gh
+&
++m
+
+//
+/
+,
+!
+!
+-
+,
+,
+;
+?
+~
+{
+}
+*
+[?]
+
+'
+
+b
+g
+g
+d
+d
+h
+w
+z
+H
+t
+t
+y
+yh
+k
+l
+m
+n
+s
+s
+`
+p
+p
+S
+q
+r
+sh
+t
+[?]
+[?]
+[?]
+a
+a
+a
+A
+A
+A
+e
+e
+e
+E
+i
+i
+u
+u
+u
+o
+
+`
+'
+
+
+X
+Q
+@
+@
+|
++
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+h
+sh
+n
+r
+b
+L
+k
+'
+v
+m
+f
+dh
+th
+l
+g
+ny
+s
+d
+z
+t
+y
+p
+j
+ch
+tt
+hh
+kh
+th
+z
+sh
+s
+d
+t
+z
+`
+gh
+q
+w
+a
+aa
+i
+ee
+u
+oo
+e
+ey
+o
+oa
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+N
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+L
+eN
+e
+e
+ai
+oN
+o
+o
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+nnn
+p
+ph
+b
+bh
+m
+y
+r
+rr
+l
+l
+lll
+v
+sh
+ss
+s
+h
+[?]
+[?]
+'
+'
+aa
+i
+ii
+u
+uu
+R
+RR
+eN
+e
+e
+ai
+oN
+o
+o
+au
+
+[?]
+[?]
+AUM
+'
+'
+`
+'
+[?]
+[?]
+[?]
+q
+khh
+ghh
+z
+dddh
+rh
+f
+yy
+RR
+LL
+L
+LL
+ / 
+ // 
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+.
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+N
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+RR
+[?]
+[?]
+e
+ai
+[?]
+[?]
+o
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bh
+m
+y
+r
+[?]
+l
+[?]
+[?]
+[?]
+sh
+ss
+s
+h
+[?]
+[?]
+'
+[?]
+aa
+i
+ii
+u
+uu
+R
+RR
+[?]
+[?]
+e
+ai
+[?]
+[?]
+o
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
++
+[?]
+[?]
+[?]
+[?]
+rr
+rh
+[?]
+yy
+RR
+LL
+L
+LL
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+r'
+r`
+Rs
+Rs
+1/
+2/
+3/
+4/
+ 1 - 1/
+/16
+
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+N
+[?]
+[?]
+a
+aa
+i
+ii
+u
+uu
+[?]
+[?]
+[?]
+[?]
+ee
+ai
+[?]
+[?]
+oo
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bb
+m
+y
+r
+[?]
+l
+ll
+[?]
+v
+sh
+[?]
+s
+h
+[?]
+[?]
+'
+[?]
+aa
+i
+ii
+u
+uu
+[?]
+[?]
+[?]
+[?]
+ee
+ai
+[?]
+[?]
+oo
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+khh
+ghh
+z
+rr
+[?]
+f
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+N
+H
+
+
+G.E.O.
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+N
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+[?]
+eN
+[?]
+e
+ai
+oN
+[?]
+o
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bh
+m
+ya
+r
+[?]
+l
+ll
+[?]
+v
+sh
+ss
+s
+h
+[?]
+[?]
+'
+'
+aa
+i
+ii
+u
+uu
+R
+RR
+eN
+[?]
+e
+ai
+oN
+[?]
+o
+au
+
+[?]
+[?]
+AUM
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+RR
+[?]
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+N
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+L
+[?]
+[?]
+e
+ai
+[?]
+[?]
+o
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bh
+m
+y
+r
+[?]
+l
+ll
+[?]
+
+sh
+ss
+s
+h
+[?]
+[?]
+'
+'
+aa
+i
+ii
+u
+uu
+R
+[?]
+[?]
+[?]
+e
+ai
+[?]
+[?]
+o
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
++
++
+[?]
+[?]
+[?]
+[?]
+rr
+rh
+[?]
+yy
+RR
+LL
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+[?]
+[?]
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+k
+[?]
+[?]
+[?]
+ng
+c
+[?]
+j
+[?]
+ny
+tt
+[?]
+[?]
+[?]
+nn
+t
+[?]
+[?]
+[?]
+n
+nnn
+p
+[?]
+[?]
+[?]
+m
+y
+r
+rr
+l
+ll
+lll
+v
+[?]
+ss
+s
+h
+[?]
+[?]
+[?]
+[?]
+aa
+i
+ii
+u
+uu
+[?]
+[?]
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
++
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
++10+
++100+
++1000+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+N
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+L
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bh
+m
+y
+r
+rr
+l
+ll
+[?]
+v
+sh
+ss
+s
+h
+[?]
+[?]
+[?]
+[?]
+aa
+i
+ii
+u
+uu
+R
+RR
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
++
++
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+RR
+LL
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+L
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bh
+m
+y
+r
+rr
+l
+ll
+[?]
+v
+sh
+ss
+s
+h
+[?]
+[?]
+[?]
+[?]
+aa
+i
+ii
+u
+uu
+R
+RR
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
++
++
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+lll
+[?]
+RR
+LL
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+N
+H
+[?]
+a
+aa
+i
+ii
+u
+uu
+R
+L
+[?]
+e
+ee
+ai
+[?]
+o
+oo
+au
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+[?]
+p
+ph
+b
+bh
+m
+y
+r
+rr
+l
+ll
+lll
+v
+sh
+ss
+s
+h
+[?]
+[?]
+[?]
+[?]
+aa
+i
+ii
+u
+uu
+R
+[?]
+[?]
+e
+ee
+ai
+
+o
+oo
+au
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
++
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+RR
+LL
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+N
+H
+[?]
+a
+aa
+ae
+aae
+i
+ii
+u
+uu
+R
+RR
+L
+LL
+e
+ee
+ai
+o
+oo
+au
+[?]
+[?]
+[?]
+k
+kh
+g
+gh
+ng
+nng
+c
+ch
+j
+jh
+ny
+jny
+nyj
+tt
+tth
+dd
+ddh
+nn
+nndd
+t
+th
+d
+dh
+n
+[?]
+nd
+p
+ph
+b
+bh
+m
+mb
+y
+r
+[?]
+l
+[?]
+[?]
+v
+sh
+ss
+s
+h
+ll
+f
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+aa
+ae
+aae
+i
+ii
+u
+[?]
+uu
+[?]
+R
+e
+ee
+ai
+o
+oo
+au
+L
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+RR
+LL
+ . 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+k
+kh
+kh
+kh
+kh
+kh
+ng
+cch
+ch
+ch
+ch
+ch
+y
+d
+t
+th
+th
+th
+n
+d
+t
+th
+th
+th
+n
+b
+p
+ph
+f
+ph
+f
+ph
+m
+y
+r
+R
+l
+L
+w
+s
+s
+s
+h
+l
+`
+h
+~
+a
+a
+aa
+am
+i
+ii
+ue
+uue
+u
+uu
+'
+[?]
+[?]
+[?]
+[?]
+Bh.
+e
+ae
+o
+ai
+ai
+ao
++
+
+
+
+
+
+
+M
+
+ * 
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+ // 
+ /// 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+k
+kh
+[?]
+kh
+[?]
+[?]
+ng
+ch
+[?]
+s
+[?]
+[?]
+ny
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+d
+h
+th
+th
+[?]
+n
+b
+p
+ph
+f
+ph
+f
+[?]
+m
+y
+r
+[?]
+l
+[?]
+w
+[?]
+[?]
+s
+h
+[?]
+`
+
+~
+a
+
+aa
+am
+i
+ii
+y
+yy
+u
+uu
+[?]
+o
+l
+ny
+[?]
+[?]
+e
+ei
+o
+ay
+ai
+[?]
++
+[?]
+
+
+
+
+
+M
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+hn
+hm
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+AUM
+
+
+
+
+
+
+
+ // 
+ * 
+
+-
+ / 
+ / 
+ // 
+ -/ 
+ +/ 
+ X/ 
+ /XX/ 
+ /X/ 
+, 
+
+
+
+
+
+
+
+
+
+
+
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+.5
+1.5
+2.5
+3.5
+4.5
+5.5
+6.5
+7.5
+8.5
+-.5
++
+*
+^
+_
+
+~
+[?]
+]
+[[
+]]
+
+
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+[?]
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+p
+ph
+b
+bh
+m
+ts
+tsh
+dz
+dzh
+w
+zh
+z
+'
+y
+r
+l
+sh
+ssh
+s
+h
+a
+kss
+r
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+aa
+i
+ii
+u
+uu
+R
+RR
+L
+LL
+e
+ee
+o
+oo
+M
+H
+i
+ii
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+[?]
+ny
+tt
+tth
+dd
+ddh
+nn
+t
+th
+d
+dh
+n
+p
+ph
+b
+bh
+m
+ts
+tsh
+dz
+dzh
+w
+zh
+z
+'
+y
+r
+l
+sh
+ss
+s
+h
+a
+kss
+w
+y
+r
+[?]
+X
+ :X: 
+ /O/ 
+ /o/ 
+ \o\ 
+ (O) 
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+nny
+tt
+tth
+dd
+ddh
+nn
+tt
+th
+d
+dh
+n
+p
+ph
+b
+bh
+m
+y
+r
+l
+w
+s
+h
+ll
+a
+[?]
+i
+ii
+u
+uu
+e
+[?]
+o
+au
+[?]
+aa
+i
+ii
+u
+uu
+e
+ai
+[?]
+[?]
+[?]
+N
+'
+:
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+ / 
+ // 
+n*
+r*
+l*
+e*
+sh
+ss
+R
+RR
+L
+LL
+R
+RR
+L
+LL
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+A
+B
+G
+D
+E
+V
+Z
+T`
+I
+K
+L
+M
+N
+O
+P
+Zh
+R
+S
+T
+U
+P`
+K`
+G'
+Q
+Sh
+Ch`
+C`
+Z'
+C
+Ch
+X
+J
+H
+E
+Y
+W
+Xh
+OE
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+a
+b
+g
+d
+e
+v
+z
+t`
+i
+k
+l
+m
+n
+o
+p
+zh
+r
+s
+t
+u
+p`
+k`
+g'
+q
+sh
+ch`
+c`
+z'
+c
+ch
+x
+j
+h
+e
+y
+w
+xh
+oe
+f
+[?]
+[?]
+[?]
+[?]
+ // 
+[?]
+[?]
+[?]
+
+g
+gg
+n
+d
+dd
+r
+m
+b
+bb
+s
+ss
+
+j
+jj
+c
+k
+t
+p
+h
+ng
+nn
+nd
+nb
+dg
+rn
+rr
+rh
+rN
+mb
+mN
+bg
+bn
+
+bs
+bsg
+bst
+bsb
+bss
+bsj
+bj
+bc
+bt
+bp
+bN
+bbN
+sg
+sn
+sd
+sr
+sm
+sb
+sbg
+sss
+s
+sj
+sc
+sk
+st
+sp
+sh
+
+
+
+
+Z
+g
+d
+m
+b
+s
+Z
+
+j
+c
+t
+p
+N
+j
+
+
+
+
+ck
+ch
+
+
+pb
+pN
+hh
+Q
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+a
+ae
+ya
+yae
+eo
+e
+yeo
+ye
+o
+wa
+wae
+oe
+yo
+u
+weo
+we
+wi
+yu
+eu
+yi
+i
+a-o
+a-u
+ya-o
+ya-yo
+eo-o
+eo-u
+eo-eu
+yeo-o
+yeo-u
+o-eo
+o-e
+o-ye
+o-o
+o-u
+yo-ya
+yo-yae
+yo-yeo
+yo-o
+yo-i
+u-a
+u-ae
+u-eo-eu
+u-ye
+u-u
+yu-a
+yu-eo
+yu-e
+yu-yeo
+yu-ye
+yu-u
+yu-i
+eu-u
+eu-eu
+yi-u
+i-a
+i-ya
+i-o
+i-u
+i-eu
+i-U
+U
+U-eo
+U-u
+U-i
+UU
+[?]
+[?]
+[?]
+[?]
+[?]
+g
+gg
+gs
+n
+nj
+nh
+d
+l
+lg
+lm
+lb
+ls
+lt
+lp
+lh
+m
+b
+bs
+s
+ss
+ng
+j
+c
+k
+t
+p
+h
+gl
+gsg
+ng
+nd
+ns
+nZ
+nt
+dg
+tl
+lgs
+ln
+ld
+lth
+ll
+lmg
+lms
+lbs
+lbh
+rNp
+lss
+lZ
+lk
+lQ
+mg
+ml
+mb
+ms
+mss
+mZ
+mc
+mh
+mN
+bl
+bp
+ph
+pN
+sg
+sd
+sl
+sb
+Z
+g
+ss
+
+kh
+N
+Ns
+NZ
+pb
+pN
+hn
+hl
+hm
+hb
+Q
+[?]
+[?]
+[?]
+[?]
+[?]
+
+ha
+hu
+hi
+haa
+hee
+he
+ho
+[?]
+la
+lu
+li
+laa
+lee
+le
+lo
+lwa
+hha
+hhu
+hhi
+hhaa
+hhee
+hhe
+hho
+hhwa
+ma
+mu
+mi
+maa
+mee
+me
+mo
+mwa
+sza
+szu
+szi
+szaa
+szee
+sze
+szo
+szwa
+ra
+ru
+ri
+raa
+ree
+re
+ro
+rwa
+sa
+su
+si
+saa
+see
+se
+so
+swa
+sha
+shu
+shi
+shaa
+shee
+she
+sho
+shwa
+qa
+qu
+qi
+qaa
+qee
+qe
+qo
+[?]
+qwa
+[?]
+qwi
+qwaa
+qwee
+qwe
+[?]
+[?]
+qha
+qhu
+qhi
+qhaa
+qhee
+qhe
+qho
+[?]
+qhwa
+[?]
+qhwi
+qhwaa
+qhwee
+qhwe
+[?]
+[?]
+ba
+bu
+bi
+baa
+bee
+be
+bo
+bwa
+va
+vu
+vi
+vaa
+vee
+ve
+vo
+vwa
+ta
+tu
+ti
+taa
+tee
+te
+to
+twa
+ca
+cu
+ci
+caa
+cee
+ce
+co
+cwa
+xa
+xu
+xi
+xaa
+xee
+xe
+xo
+[?]
+xwa
+[?]
+xwi
+xwaa
+xwee
+xwe
+[?]
+[?]
+na
+nu
+ni
+naa
+nee
+ne
+no
+nwa
+nya
+nyu
+nyi
+nyaa
+nyee
+nye
+nyo
+nywa
+'a
+'u
+[?]
+'aa
+'ee
+'e
+'o
+'wa
+ka
+ku
+ki
+kaa
+kee
+ke
+ko
+[?]
+kwa
+[?]
+kwi
+kwaa
+kwee
+kwe
+[?]
+[?]
+kxa
+kxu
+kxi
+kxaa
+kxee
+kxe
+kxo
+[?]
+kxwa
+[?]
+kxwi
+kxwaa
+kxwee
+kxwe
+[?]
+[?]
+wa
+wu
+wi
+waa
+wee
+we
+wo
+[?]
+`a
+`u
+`i
+`aa
+`ee
+`e
+`o
+[?]
+za
+zu
+zi
+zaa
+zee
+ze
+zo
+zwa
+zha
+zhu
+zhi
+zhaa
+zhee
+zhe
+zho
+zhwa
+ya
+yu
+yi
+yaa
+yee
+ye
+yo
+[?]
+da
+du
+di
+daa
+dee
+de
+do
+dwa
+dda
+ddu
+ddi
+ddaa
+ddee
+dde
+ddo
+ddwa
+ja
+ju
+ji
+jaa
+jee
+je
+jo
+jwa
+ga
+gu
+gi
+gaa
+gee
+ge
+go
+[?]
+gwa
+[?]
+gwi
+gwaa
+gwee
+gwe
+[?]
+[?]
+gga
+ggu
+ggi
+ggaa
+ggee
+gge
+ggo
+[?]
+tha
+thu
+thi
+thaa
+thee
+the
+tho
+thwa
+cha
+chu
+chi
+chaa
+chee
+che
+cho
+chwa
+pha
+phu
+phi
+phaa
+phee
+phe
+pho
+phwa
+tsa
+tsu
+tsi
+tsaa
+tsee
+tse
+tso
+tswa
+tza
+tzu
+tzi
+tzaa
+tzee
+tze
+tzo
+[?]
+fa
+fu
+fi
+faa
+fee
+fe
+fo
+fwa
+pa
+pu
+pi
+paa
+pee
+pe
+po
+pwa
+rya
+mya
+fya
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+ 
+.
+,
+;
+:
+:: 
+?
+//
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10+
+20+
+30+
+40+
+50+
+60+
+70+
+80+
+90+
+100+
+10,000+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+a
+e
+i
+o
+u
+v
+ga
+ka
+ge
+gi
+go
+gu
+gv
+ha
+he
+hi
+ho
+hu
+hv
+la
+le
+li
+lo
+lu
+lv
+ma
+me
+mi
+mo
+mu
+na
+hna
+nah
+ne
+ni
+no
+nu
+nv
+qua
+que
+qui
+quo
+quu
+quv
+sa
+s
+se
+si
+so
+su
+sv
+da
+ta
+de
+te
+di
+ti
+do
+du
+dv
+dla
+tla
+tle
+tli
+tlo
+tlu
+tlv
+tsa
+tse
+tsi
+tso
+tsu
+tsv
+wa
+we
+wi
+wo
+wu
+wv
+ya
+ye
+yi
+yo
+yu
+yv
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+e
+aai
+i
+ii
+o
+oo
+oo
+ee
+i
+a
+aa
+we
+we
+wi
+wi
+wii
+wii
+wo
+wo
+woo
+woo
+woo
+wa
+wa
+waa
+waa
+waa
+ai
+w
+'
+t
+k
+sh
+s
+n
+w
+n
+[?]
+w
+c
+?
+l
+en
+in
+on
+an
+pe
+paai
+pi
+pii
+po
+poo
+poo
+hee
+hi
+pa
+paa
+pwe
+pwe
+pwi
+pwi
+pwii
+pwii
+pwo
+pwo
+pwoo
+pwoo
+pwa
+pwa
+pwaa
+pwaa
+pwaa
+p
+p
+h
+te
+taai
+ti
+tii
+to
+too
+too
+dee
+di
+ta
+taa
+twe
+twe
+twi
+twi
+twii
+twii
+two
+two
+twoo
+twoo
+twa
+twa
+twaa
+twaa
+twaa
+t
+tte
+tti
+tto
+tta
+ke
+kaai
+ki
+kii
+ko
+koo
+koo
+ka
+kaa
+kwe
+kwe
+kwi
+kwi
+kwii
+kwii
+kwo
+kwo
+kwoo
+kwoo
+kwa
+kwa
+kwaa
+kwaa
+kwaa
+k
+kw
+keh
+kih
+koh
+kah
+ce
+caai
+ci
+cii
+co
+coo
+coo
+ca
+caa
+cwe
+cwe
+cwi
+cwi
+cwii
+cwii
+cwo
+cwo
+cwoo
+cwoo
+cwa
+cwa
+cwaa
+cwaa
+cwaa
+c
+th
+me
+maai
+mi
+mii
+mo
+moo
+moo
+ma
+maa
+mwe
+mwe
+mwi
+mwi
+mwii
+mwii
+mwo
+mwo
+mwoo
+mwoo
+mwa
+mwa
+mwaa
+mwaa
+mwaa
+m
+m
+mh
+m
+m
+ne
+naai
+ni
+nii
+no
+noo
+noo
+na
+naa
+nwe
+nwe
+nwa
+nwa
+nwaa
+nwaa
+nwaa
+n
+ng
+nh
+le
+laai
+li
+lii
+lo
+loo
+loo
+la
+laa
+lwe
+lwe
+lwi
+lwi
+lwii
+lwii
+lwo
+lwo
+lwoo
+lwoo
+lwa
+lwa
+lwaa
+lwaa
+l
+l
+l
+se
+saai
+si
+sii
+so
+soo
+soo
+sa
+saa
+swe
+swe
+swi
+swi
+swii
+swii
+swo
+swo
+swoo
+swoo
+swa
+swa
+swaa
+swaa
+swaa
+s
+s
+sw
+s
+sk
+skw
+sW
+spwa
+stwa
+skwa
+scwa
+she
+shi
+shii
+sho
+shoo
+sha
+shaa
+shwe
+shwe
+shwi
+shwi
+shwii
+shwii
+shwo
+shwo
+shwoo
+shwoo
+shwa
+shwa
+shwaa
+shwaa
+sh
+ye
+yaai
+yi
+yii
+yo
+yoo
+yoo
+ya
+yaa
+ywe
+ywe
+ywi
+ywi
+ywii
+ywii
+ywo
+ywo
+ywoo
+ywoo
+ywa
+ywa
+ywaa
+ywaa
+ywaa
+y
+y
+y
+yi
+re
+re
+le
+raai
+ri
+rii
+ro
+roo
+lo
+ra
+raa
+la
+rwaa
+rwaa
+r
+r
+r
+fe
+faai
+fi
+fii
+fo
+foo
+fa
+faa
+fwaa
+fwaa
+f
+the
+the
+thi
+thi
+thii
+thii
+tho
+thoo
+tha
+thaa
+thwaa
+thwaa
+th
+tthe
+tthi
+ttho
+ttha
+tth
+tye
+tyi
+tyo
+tya
+he
+hi
+hii
+ho
+hoo
+ha
+haa
+h
+h
+hk
+qaai
+qi
+qii
+qo
+qoo
+qa
+qaa
+q
+tlhe
+tlhi
+tlho
+tlha
+re
+ri
+ro
+ra
+ngaai
+ngi
+ngii
+ngo
+ngoo
+nga
+ngaa
+ng
+nng
+she
+shi
+sho
+sha
+the
+thi
+tho
+tha
+th
+lhi
+lhii
+lho
+lhoo
+lha
+lhaa
+lh
+the
+thi
+thii
+tho
+thoo
+tha
+thaa
+th
+b
+e
+i
+o
+a
+we
+wi
+wo
+wa
+ne
+ni
+no
+na
+ke
+ki
+ko
+ka
+he
+hi
+ho
+ha
+ghu
+gho
+ghe
+ghee
+ghi
+gha
+ru
+ro
+re
+ree
+ri
+ra
+wu
+wo
+we
+wee
+wi
+wa
+hwu
+hwo
+hwe
+hwee
+hwi
+hwa
+thu
+tho
+the
+thee
+thi
+tha
+ttu
+tto
+tte
+ttee
+tti
+tta
+pu
+po
+pe
+pee
+pi
+pa
+p
+gu
+go
+ge
+gee
+gi
+ga
+khu
+kho
+khe
+khee
+khi
+kha
+kku
+kko
+kke
+kkee
+kki
+kka
+kk
+nu
+no
+ne
+nee
+ni
+na
+mu
+mo
+me
+mee
+mi
+ma
+yu
+yo
+ye
+yee
+yi
+ya
+ju
+ju
+jo
+je
+jee
+ji
+ji
+ja
+jju
+jjo
+jje
+jjee
+jji
+jja
+lu
+lo
+le
+lee
+li
+la
+dlu
+dlo
+dle
+dlee
+dli
+dla
+lhu
+lho
+lhe
+lhee
+lhi
+lha
+tlhu
+tlho
+tlhe
+tlhee
+tlhi
+tlha
+tlu
+tlo
+tle
+tlee
+tli
+tla
+zu
+zo
+ze
+zee
+zi
+za
+z
+z
+dzu
+dzo
+dze
+dzee
+dzi
+dza
+su
+so
+se
+see
+si
+sa
+shu
+sho
+she
+shee
+shi
+sha
+sh
+tsu
+tso
+tse
+tsee
+tsi
+tsa
+chu
+cho
+che
+chee
+chi
+cha
+ttsu
+ttso
+ttse
+ttsee
+ttsi
+ttsa
+X
+.
+qai
+ngai
+nngi
+nngii
+nngo
+nngoo
+nnga
+nngaa
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+ 
+b
+l
+f
+s
+n
+h
+d
+t
+c
+q
+m
+g
+ng
+z
+r
+a
+o
+u
+e
+i
+ch
+th
+ph
+p
+x
+p
+<
+>
+[?]
+[?]
+[?]
+f
+v
+u
+yr
+y
+w
+th
+th
+a
+o
+ac
+ae
+o
+o
+o
+oe
+on
+r
+k
+c
+k
+g
+ng
+g
+g
+w
+h
+h
+h
+h
+n
+n
+n
+i
+e
+j
+g
+ae
+a
+eo
+p
+z
+s
+s
+s
+c
+z
+t
+t
+d
+b
+b
+p
+p
+e
+m
+m
+m
+l
+l
+ng
+ng
+d
+o
+ear
+ior
+qu
+qu
+qu
+s
+yr
+yr
+yr
+q
+x
+.
+:
++
+17
+18
+19
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+k
+kh
+g
+gh
+ng
+c
+ch
+j
+jh
+ny
+t
+tth
+d
+ddh
+nn
+t
+th
+d
+dh
+n
+p
+ph
+b
+bh
+m
+y
+r
+l
+v
+sh
+ss
+s
+h
+l
+q
+a
+aa
+i
+ii
+u
+uk
+uu
+uuv
+ry
+ryy
+ly
+lyy
+e
+ai
+oo
+oo
+au
+a
+aa
+aa
+i
+ii
+y
+yy
+u
+uu
+ua
+oe
+ya
+ie
+e
+ae
+ai
+oo
+au
+M
+H
+a`
+
+
+
+r
+
+!
+
+
+
+
+
+.
+ // 
+:
++
+++
+ * 
+ /// 
+KR
+'
+[?]
+[?]
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+ @ 
+ ... 
+, 
+. 
+: 
+ // 
+
+-
+, 
+. 
+
+
+
+
+
+[?]
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+a
+e
+i
+o
+u
+O
+U
+ee
+n
+ng
+b
+p
+q
+g
+m
+l
+s
+sh
+t
+d
+ch
+j
+y
+r
+w
+f
+k
+kha
+ts
+z
+h
+zr
+lh
+zh
+ch
+-
+e
+i
+o
+u
+O
+U
+ng
+b
+p
+q
+g
+m
+t
+d
+ch
+j
+ts
+y
+w
+k
+g
+h
+jy
+ny
+dz
+e
+i
+iy
+U
+u
+ng
+k
+g
+h
+p
+sh
+t
+d
+j
+f
+g
+h
+ts
+z
+r
+ch
+zh
+i
+k
+r
+f
+zh
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+H
+X
+W
+M
+ 3 
+ 333 
+a
+i
+k
+ng
+c
+tt
+tth
+dd
+nn
+t
+d
+p
+ph
+ss
+zh
+z
+a
+t
+zh
+gh
+ng
+c
+jh
+tta
+ddh
+t
+dh
+ss
+cy
+zh
+z
+u
+y
+bh
+'
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+A
+a
+B
+b
+B
+b
+B
+b
+C
+c
+D
+d
+D
+d
+D
+d
+D
+d
+D
+d
+E
+e
+E
+e
+E
+e
+E
+e
+E
+e
+F
+f
+G
+g
+H
+h
+H
+h
+H
+h
+H
+h
+H
+h
+I
+i
+I
+i
+K
+k
+K
+k
+K
+k
+L
+l
+L
+l
+L
+l
+L
+l
+M
+m
+M
+m
+M
+m
+N
+n
+N
+n
+N
+n
+N
+n
+O
+o
+O
+o
+O
+o
+O
+o
+P
+p
+P
+p
+R
+r
+R
+r
+R
+r
+R
+r
+S
+s
+S
+s
+S
+s
+S
+s
+S
+s
+T
+t
+T
+t
+T
+t
+T
+t
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+V
+v
+V
+v
+W
+w
+W
+w
+W
+w
+W
+w
+W
+w
+X
+x
+X
+x
+Y
+y
+Z
+z
+Z
+z
+Z
+z
+h
+t
+w
+y
+a
+S
+[?]
+[?]
+[?]
+[?]
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+A
+a
+E
+e
+E
+e
+E
+e
+E
+e
+E
+e
+E
+e
+E
+e
+E
+e
+I
+i
+I
+i
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+O
+o
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+U
+u
+Y
+y
+Y
+y
+Y
+y
+Y
+y
+[?]
+[?]
+[?]
+[?]
+[?]
+
+a
+a
+a
+a
+a
+a
+a
+a
+A
+A
+A
+A
+A
+A
+A
+A
+e
+e
+e
+e
+e
+e
+[?]
+[?]
+E
+E
+E
+E
+E
+E
+[?]
+[?]
+e
+e
+e
+e
+e
+e
+e
+e
+E
+E
+E
+E
+E
+E
+E
+E
+i
+i
+i
+i
+i
+i
+i
+i
+I
+I
+I
+I
+I
+I
+I
+I
+o
+o
+o
+o
+o
+o
+[?]
+[?]
+O
+O
+O
+O
+O
+O
+[?]
+[?]
+u
+u
+u
+u
+u
+u
+u
+u
+[?]
+U
+[?]
+U
+[?]
+U
+[?]
+U
+o
+o
+o
+o
+o
+o
+o
+o
+O
+O
+O
+O
+O
+O
+O
+O
+a
+a
+e
+e
+e
+e
+i
+i
+o
+o
+u
+u
+o
+o
+[?]
+[?]
+a
+a
+a
+a
+a
+a
+a
+a
+A
+A
+A
+A
+A
+A
+A
+A
+e
+e
+e
+e
+e
+e
+e
+e
+E
+E
+E
+E
+E
+E
+E
+E
+o
+o
+o
+o
+o
+o
+o
+o
+O
+O
+O
+O
+O
+O
+O
+O
+a
+a
+a
+a
+a
+[?]
+a
+a
+A
+A
+A
+A
+A
+'
+i
+'
+~
+"~
+e
+e
+e
+[?]
+e
+e
+E
+E
+E
+E
+E
+'`
+''
+'~
+i
+i
+i
+i
+[?]
+[?]
+i
+i
+I
+I
+I
+I
+[?]
+`'
+`'
+`~
+u
+u
+u
+u
+R
+R
+u
+u
+U
+U
+U
+U
+R
+"`
+"'
+`
+[?]
+[?]
+o
+o
+o
+[?]
+o
+o
+O
+O
+O
+O
+O
+'
+`
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+
+
+
+
+-
+-
+-
+-
+--
+--
+||
+_
+'
+'
+,
+'
+"
+"
+,,
+"
++
+++
+*
+*>
+.
+..
+...
+.
+
+
+
+
+
+
+
+
+
+
+ 
+%0
+%00
+'
+''
+'''
+`
+``
+```
+^
+<
+>
+*
+!!
+!?
+-
+_
+-
+^
+***
+--
+/
+-[
+]-
+[?]
+?!
+!?
+7
+PP
+(]
+[)
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+0
+
+
+
+4
+5
+6
+7
+8
+9
++
+-
+=
+(
+)
+n
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
++
+-
+=
+(
+)
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+ECU
+CL
+Cr
+FF
+L
+mil
+N
+Pts
+Rs
+W
+NS
+D
+EU
+K
+T
+Dr
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+ 1/3 
+ 2/3 
+ 1/5 
+ 2/5 
+ 3/5 
+ 4/5 
+ 1/6 
+ 5/6 
+ 1/8 
+ 3/8 
+ 5/8 
+ 7/8 
+ 1/
+I
+II
+III
+IV
+V
+VI
+VII
+VIII
+IX
+X
+XI
+XII
+L
+C
+D
+M
+i
+ii
+iii
+iv
+v
+vi
+vii
+viii
+ix
+x
+xi
+xii
+l
+c
+d
+m
+(D
+D)
+((|))
+)
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+-
+|
+-
+|
+-
+|
+\
+/
+\
+/
+-
+-
+~
+~
+-
+|
+-
+|
+-
+-
+-
+|
+-
+|
+|
+-
+-
+-
+-
+-
+-
+|
+|
+|
+|
+|
+|
+|
+^
+V
+\
+=
+V
+^
+-
+-
+|
+|
+-
+-
+|
+|
+=
+|
+=
+=
+|
+=
+|
+=
+=
+=
+=
+=
+=
+|
+=
+|
+=
+|
+\
+/
+\
+/
+=
+=
+~
+~
+|
+|
+-
+|
+-
+|
+-
+-
+-
+|
+-
+|
+|
+|
+|
+|
+|
+|
+-
+\
+\
+|
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+-
+-
+|
+|
+-
+-
+|
+|
+-
+-
+|
+|
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+-
+-
+|
+|
+-
+|
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+/
+\
+X
+-
+|
+-
+|
+-
+|
+-
+|
+-
+|
+-
+|
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+-
+|
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+#
+^
+^
+^
+^
+>
+>
+>
+>
+>
+>
+V
+V
+V
+V
+<
+<
+<
+<
+<
+<
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+*
+#
+#
+#
+#
+#
+^
+^
+^
+O
+#
+#
+#
+#
+#
+#
+#
+#
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+ 
+a
+1
+b
+'
+k
+2
+l
+@
+c
+i
+f
+/
+m
+s
+p
+"
+e
+3
+h
+9
+o
+6
+r
+^
+d
+j
+g
+>
+n
+t
+q
+,
+*
+5
+<
+-
+u
+8
+v
+.
+%
+[
+$
++
+x
+!
+&
+;
+:
+4
+\
+0
+z
+7
+(
+_
+?
+w
+]
+#
+y
+)
+=
+[d7]
+[d17]
+[d27]
+[d127]
+[d37]
+[d137]
+[d237]
+[d1237]
+[d47]
+[d147]
+[d247]
+[d1247]
+[d347]
+[d1347]
+[d2347]
+[d12347]
+[d57]
+[d157]
+[d257]
+[d1257]
+[d357]
+[d1357]
+[d2357]
+[d12357]
+[d457]
+[d1457]
+[d2457]
+[d12457]
+[d3457]
+[d13457]
+[d23457]
+[d123457]
+[d67]
+[d167]
+[d267]
+[d1267]
+[d367]
+[d1367]
+[d2367]
+[d12367]
+[d467]
+[d1467]
+[d2467]
+[d12467]
+[d3467]
+[d13467]
+[d23467]
+[d123467]
+[d567]
+[d1567]
+[d2567]
+[d12567]
+[d3567]
+[d13567]
+[d23567]
+[d123567]
+[d4567]
+[d14567]
+[d24567]
+[d124567]
+[d34567]
+[d134567]
+[d234567]
+[d1234567]
+[d8]
+[d18]
+[d28]
+[d128]
+[d38]
+[d138]
+[d238]
+[d1238]
+[d48]
+[d148]
+[d248]
+[d1248]
+[d348]
+[d1348]
+[d2348]
+[d12348]
+[d58]
+[d158]
+[d258]
+[d1258]
+[d358]
+[d1358]
+[d2358]
+[d12358]
+[d458]
+[d1458]
+[d2458]
+[d12458]
+[d3458]
+[d13458]
+[d23458]
+[d123458]
+[d68]
+[d168]
+[d268]
+[d1268]
+[d368]
+[d1368]
+[d2368]
+[d12368]
+[d468]
+[d1468]
+[d2468]
+[d12468]
+[d3468]
+[d13468]
+[d23468]
+[d123468]
+[d568]
+[d1568]
+[d2568]
+[d12568]
+[d3568]
+[d13568]
+[d23568]
+[d123568]
+[d4568]
+[d14568]
+[d24568]
+[d124568]
+[d34568]
+[d134568]
+[d234568]
+[d1234568]
+[d78]
+[d178]
+[d278]
+[d1278]
+[d378]
+[d1378]
+[d2378]
+[d12378]
+[d478]
+[d1478]
+[d2478]
+[d12478]
+[d3478]
+[d13478]
+[d23478]
+[d123478]
+[d578]
+[d1578]
+[d2578]
+[d12578]
+[d3578]
+[d13578]
+[d23578]
+[d123578]
+[d4578]
+[d14578]
+[d24578]
+[d124578]
+[d34578]
+[d134578]
+[d234578]
+[d1234578]
+[d678]
+[d1678]
+[d2678]
+[d12678]
+[d3678]
+[d13678]
+[d23678]
+[d123678]
+[d4678]
+[d14678]
+[d24678]
+[d124678]
+[d34678]
+[d134678]
+[d234678]
+[d1234678]
+[d5678]
+[d15678]
+[d25678]
+[d125678]
+[d35678]
+[d135678]
+[d235678]
+[d1235678]
+[d45678]
+[d145678]
+[d245678]
+[d1245678]
+[d345678]
+[d1345678]
+[d2345678]
+[d12345678]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?]
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?]
+[?]
+[?]
+
+ 
+, 
+. 
+"
+[JIS]
+"
+/
+0
+<
+> 
+<<
+>> 
+[
+] 
+{
+} 
+[(
+)] 
+@
+X 
+[
+] 
+[[
+]] 
+((
+)) 
+[[
+]] 
+~ 
+``
+''
+,,
+@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+
+
+
+
+
+
+~
++
++
++
++
+
+@
+ // 
++10+
++20+
++30+
+[?]
+[?]
+[?]
+
+
+[?]
+a
+a
+i
+i
+u
+u
+e
+e
+o
+o
+ka
+ga
+ki
+gi
+ku
+gu
+ke
+ge
+ko
+go
+sa
+za
+shi
+zi
+su
+zu
+se
+ze
+so
+zo
+ta
+da
+chi
+di
+tsu
+tsu
+du
+te
+de
+to
+do
+na
+ni
+nu
+ne
+no
+ha
+ba
+pa
+hi
+bi
+pi
+hu
+bu
+pu
+he
+be
+pe
+ho
+bo
+po
+ma
+mi
+mu
+me
+mo
+ya
+ya
+yu
+yu
+yo
+yo
+ra
+ri
+ru
+re
+ro
+wa
+wa
+wi
+we
+wo
+n
+vu
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+"
+"
+[?]
+[?]
+a
+a
+i
+i
+u
+u
+e
+e
+o
+o
+ka
+ga
+ki
+gi
+ku
+gu
+ke
+ge
+ko
+go
+sa
+za
+shi
+zi
+su
+zu
+se
+ze
+so
+zo
+ta
+da
+chi
+di
+tsu
+tsu
+du
+te
+de
+to
+do
+na
+ni
+nu
+ne
+no
+ha
+ba
+pa
+hi
+bi
+pi
+hu
+bu
+pu
+he
+be
+pe
+ho
+bo
+po
+ma
+mi
+mu
+me
+mo
+ya
+ya
+yu
+yu
+yo
+yo
+ra
+ri
+ru
+re
+ro
+wa
+wa
+wi
+we
+wo
+n
+vu
+ka
+ke
+va
+vi
+ve
+vo
+
+
+"
+"
+
+[?]
+[?]
+[?]
+[?]
+[?]
+B
+P
+M
+F
+D
+T
+N
+L
+G
+K
+H
+J
+Q
+X
+ZH
+CH
+SH
+R
+Z
+C
+S
+A
+O
+E
+EH
+AI
+EI
+AU
+OU
+AN
+EN
+ANG
+ENG
+ER
+I
+U
+IU
+V
+NG
+GN
+[?]
+[?]
+[?]
+[?]
+g
+gg
+gs
+n
+nj
+nh
+d
+dd
+r
+lg
+lm
+lb
+ls
+lt
+lp
+rh
+m
+b
+bb
+bs
+s
+ss
+
+j
+jj
+c
+k
+t
+p
+h
+a
+ae
+ya
+yae
+eo
+e
+yeo
+ye
+o
+wa
+wae
+oe
+yo
+u
+weo
+we
+wi
+yu
+eu
+yi
+i
+
+nn
+nd
+ns
+nZ
+lgs
+ld
+lbs
+lZ
+lQ
+mb
+ms
+mZ
+mN
+bg
+
+bsg
+bst
+bj
+bt
+bN
+bbN
+sg
+sn
+sd
+sb
+sj
+Z
+
+N
+Ns
+NZ
+pN
+hh
+Q
+yo-ya
+yo-yae
+yo-i
+yu-yeo
+yu-ye
+yu-i
+U
+U-i
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+BU
+ZI
+JI
+GU
+EE
+ENN
+OO
+ONN
+IR
+ANN
+INN
+UNN
+IM
+NGG
+AINN
+AUNN
+AM
+OM
+ONG
+INNN
+P
+T
+K
+H
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+(g)
+(n)
+(d)
+(r)
+(m)
+(b)
+(s)
+()
+(j)
+(c)
+(k)
+(t)
+(p)
+(h)
+(ga)
+(na)
+(da)
+(ra)
+(ma)
+(ba)
+(sa)
+(a)
+(ja)
+(ca)
+(ka)
+(ta)
+(pa)
+(ha)
+(ju)
+[?]
+[?]
+[?]
+(1) 
+(2) 
+(3) 
+(4) 
+(5) 
+(6) 
+(7) 
+(8) 
+(9) 
+(10) 
+(Yue) 
+(Huo) 
+(Shui) 
+(Mu) 
+(Jin) 
+(Tu) 
+(Ri) 
+(Zhu) 
+(You) 
+(She) 
+(Ming) 
+(Te) 
+(Cai) 
+(Zhu) 
+(Lao) 
+(Dai) 
+(Hu) 
+(Xue) 
+(Jian) 
+(Qi) 
+(Zi) 
+(Xie) 
+(Ji) 
+(Xiu) 
+<<
+>>
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+(g)
+(n)
+(d)
+(r)
+(m)
+(b)
+(s)
+()
+(j)
+(c)
+(k)
+(t)
+(p)
+(h)
+(ga)
+(na)
+(da)
+(ra)
+(ma)
+(ba)
+(sa)
+(a)
+(ja)
+(ca)
+(ka)
+(ta)
+(pa)
+(ha)
+[?]
+[?]
+[?]
+KIS 
+(1) 
+(2) 
+(3) 
+(4) 
+(5) 
+(6) 
+(7) 
+(8) 
+(9) 
+(10) 
+(Yue) 
+(Huo) 
+(Shui) 
+(Mu) 
+(Jin) 
+(Tu) 
+(Ri) 
+(Zhu) 
+(You) 
+(She) 
+(Ming) 
+(Te) 
+(Cai) 
+(Zhu) 
+(Lao) 
+(Mi) 
+(Nan) 
+(Nu) 
+(Shi) 
+(You) 
+(Yin) 
+(Zhu) 
+(Xiang) 
+(Xiu) 
+(Xie) 
+(Zheng) 
+(Shang) 
+(Zhong) 
+(Xia) 
+(Zuo) 
+(You) 
+(Yi) 
+(Zong) 
+(Xue) 
+(Jian) 
+(Qi) 
+(Zi) 
+(Xie) 
+(Ye) 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+1M
+2M
+3M
+4M
+5M
+6M
+7M
+8M
+9M
+10M
+11M
+12M
+[?]
+[?]
+[?]
+[?]
+a
+i
+u
+u
+o
+ka
+ki
+ku
+ke
+ko
+sa
+si
+su
+se
+so
+ta
+ti
+tu
+te
+to
+na
+ni
+nu
+ne
+no
+ha
+hi
+hu
+he
+ho
+ma
+mi
+mu
+me
+mo
+ya
+yu
+yo
+ra
+ri
+ru
+re
+ro
+wa
+wi
+we
+wo
+
+apartment
+alpha
+ampere
+are
+inning
+inch
+won
+escudo
+acre
+ounce
+ohm
+kai-ri
+carat
+calorie
+gallon
+gamma
+giga
+guinea
+curie
+guilder
+kilo
+kilogram
+kilometer
+kilowatt
+gram
+gram ton
+cruzeiro
+krone
+case
+koruna
+co-op
+cycle
+centime
+shilling
+centi
+cent
+dozen
+desi
+dollar
+ton
+nano
+knot
+heights
+percent
+parts
+barrel
+piaster
+picul
+pico
+building
+farad
+feet
+bushel
+franc
+hectare
+peso
+pfennig
+hertz
+pence
+page
+beta
+point
+volt
+hon
+pound
+hall
+horn
+micro
+mile
+mach
+mark
+mansion
+micron
+milli
+millibar
+mega
+megaton
+meter
+yard
+yard
+yuan
+liter
+lira
+rupee
+ruble
+rem
+roentgen
+watt
+0h
+1h
+2h
+3h
+4h
+5h
+6h
+7h
+8h
+9h
+10h
+11h
+12h
+13h
+14h
+15h
+16h
+17h
+18h
+19h
+20h
+21h
+22h
+23h
+24h
+HPA
+da
+AU
+bar
+oV
+pc
+[?]
+[?]
+[?]
+[?]
+Heisei
+Syouwa
+Taisyou
+Meiji
+Inc.
+pA
+nA
+microamp
+mA
+kA
+kB
+MB
+GB
+cal
+kcal
+pF
+nF
+microFarad
+microgram
+mg
+kg
+Hz
+kHz
+MHz
+GHz
+THz
+microliter
+ml
+dl
+kl
+fm
+nm
+micrometer
+mm
+cm
+km
+mm^2
+cm^2
+m^2
+km^2
+mm^4
+cm^3
+m^3
+km^3
+m/s
+m/s^2
+Pa
+kPa
+MPa
+GPa
+rad
+rad/s
+rad/s^2
+ps
+ns
+microsecond
+ms
+pV
+nV
+microvolt
+mV
+kV
+MV
+pW
+nW
+microwatt
+mW
+kW
+MW
+kOhm
+MOhm
+a.m.
+Bq
+cc
+cd
+C/kg
+Co.
+dB
+Gy
+ha
+HP
+in
+K.K.
+KM
+kt
+lm
+ln
+log
+lx
+mb
+mil
+mol
+pH
+p.m.
+PPM
+PR
+sr
+Sv
+Wb
+[?]
+[?]
+1d
+2d
+3d
+4d
+5d
+6d
+7d
+8d
+9d
+10d
+11d
+12d
+13d
+14d
+15d
+16d
+17d
+18d
+19d
+20d
+21d
+22d
+23d
+24d
+25d
+26d
+27d
+28d
+29d
+30d
+31d
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?] 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+[?] 
+Ding 
+Kao 
+Qi 
+Shang 
+Xia 
+[?] 
+Mo 
+Zhang 
+San 
+Shang 
+Xia 
+Ji 
+Bu 
+Yu 
+Mian 
+Gai 
+Chou 
+Chou 
+Zhuan 
+Qie 
+Pi 
+Shi 
+Shi 
+Qiu 
+Bing 
+Ye 
+Cong 
+Dong 
+Si 
+Cheng 
+Diu 
+Qiu 
+Liang 
+Diu 
+You 
+Liang 
+Yan 
+Bing 
+Sang 
+Gun 
+Jiu 
+Ge 
+Ya 
+Qiang 
+Zhong 
+Ji 
+Jie 
+Feng 
+Guan 
+Chuan 
+Chan 
+Lin 
+Zhuo 
+Zhu 
+Ha 
+Wan 
+Dan 
+Wei 
+Zhu 
+Jing 
+Li 
+Ju 
+Pie 
+Fu 
+Yi 
+Yi 
+Nai 
+Shime 
+Jiu 
+Jiu 
+Zhe 
+Yao 
+Yi 
+[?] 
+Zhi 
+Wu 
+Zha 
+Hu 
+Fa 
+Le 
+Zhong 
+Ping 
+Pang 
+Qiao 
+Hu 
+Guai 
+Cheng 
+Cheng 
+Yi 
+Yin 
+[?] 
+Mie 
+Jiu 
+Qi 
+Ye 
+Xi 
+Xiang 
+Gai 
+Diu 
+Hal 
+[?] 
+Shu 
+Twul 
+Shi 
+Ji 
+Nang 
+Jia 
+Kel 
+Shi 
+[?] 
+Ol 
+Mai 
+Luan 
+Cal 
+Ru 
+Xue 
+Yan 
+Fu 
+Sha 
+Na 
+Gan 
+Sol 
+El 
+Cwul 
+[?] 
+Gan 
+Chi 
+Gui 
+Gan 
+Luan 
+Lin 
+Yi 
+Jue 
+Liao 
+Ma 
+Yu 
+Zheng 
+Shi 
+Shi 
+Er 
+Chu 
+Yu 
+Yu 
+Yu 
+Yun 
+Hu 
+Qi 
+Wu 
+Jing 
+Si 
+Sui 
+Gen 
+Gen 
+Ya 
+Xie 
+Ya 
+Qi 
+Ya 
+Ji 
+Tou 
+Wang 
+Kang 
+Ta 
+Jiao 
+Hai 
+Yi 
+Chan 
+Heng 
+Mu 
+[?] 
+Xiang 
+Jing 
+Ting 
+Liang 
+Xiang 
+Jing 
+Ye 
+Qin 
+Bo 
+You 
+Xie 
+Dan 
+Lian 
+Duo 
+Wei 
+Ren 
+Ren 
+Ji 
+La 
+Wang 
+Yi 
+Shi 
+Ren 
+Le 
+Ding 
+Ze 
+Jin 
+Pu 
+Chou 
+Ba 
+Zhang 
+Jin 
+Jie 
+Bing 
+Reng 
+Cong 
+Fo 
+San 
+Lun 
+Sya 
+Cang 
+Zi 
+Shi 
+Ta 
+Zhang 
+Fu 
+Xian 
+Xian 
+Tuo 
+Hong 
+Tong 
+Ren 
+Qian 
+Gan 
+Yi 
+Di 
+Dai 
+Ling 
+Yi 
+Chao 
+Chang 
+Sa 
+[?] 
+Yi 
+Mu 
+Men 
+Ren 
+Jia 
+Chao 
+Yang 
+Qian 
+Zhong 
+Pi 
+Wan 
+Wu 
+Jian 
+Jie 
+Yao 
+Feng 
+Cang 
+Ren 
+Wang 
+Fen 
+Di 
+Fang 
+Zhong 
+Qi 
+Pei 
+Yu 
+Diao 
+Dun 
+Wen 
+Yi 
+Xin 
+Kang 
+Yi 
+Ji 
+Ai 
+Wu 
+Ji 
+Fu 
+Fa 
+Xiu 
+Jin 
+Bei 
+Dan 
+Fu 
+Tang 
+Zhong 
+You 
+Huo 
+Hui 
+Yu 
+Cui 
+Chuan 
+San 
+Wei 
+Chuan 
+Che 
+Ya 
+Xian 
+Shang 
+Chang 
+Lun 
+Cang 
+Xun 
+Xin 
+Wei 
+Zhu 
+[?] 
+Xuan 
+Nu 
+Bo 
+Gu 
+Ni 
+Ni 
+Xie 
+Ban 
+Xu 
+Ling 
+Zhou 
+Shen 
+Qu 
+Si 
+Beng 
+Si 
+Jia 
+Pi 
+Yi 
+Si 
+Ai 
+Zheng 
+Dian 
+Han 
+Mai 
+Dan 
+Zhu 
+Bu 
+Qu 
+Bi 
+Shao 
+Ci 
+Wei 
+Di 
+Zhu 
+Zuo 
+You 
+Yang 
+Ti 
+Zhan 
+He 
+Bi 
+Tuo 
+She 
+Yu 
+Yi 
+Fo 
+Zuo 
+Kou 
+Ning 
+Tong 
+Ni 
+Xuan 
+Qu 
+Yong 
+Wa 
+Qian 
+[?] 
+Ka 
+[?] 
+Pei 
+Huai 
+He 
+Lao 
+Xiang 
+Ge 
+Yang 
+Bai 
+Fa 
+Ming 
+Jia 
+Er 
+Bing 
+Ji 
+Hen 
+Huo 
+Gui 
+Quan 
+Tiao 
+Jiao 
+Ci 
+Yi 
+Shi 
+Xing 
+Shen 
+Tuo 
+Kan 
+Zhi 
+Gai 
+Lai 
+Yi 
+Chi 
+Kua 
+Guang 
+Li 
+Yin 
+Shi 
+Mi 
+Zhu 
+Xu 
+You 
+An 
+Lu 
+Mou 
+Er 
+Lun 
+Tong 
+Cha 
+Chi 
+Xun 
+Gong 
+Zhou 
+Yi 
+Ru 
+Jian 
+Xia 
+Jia 
+Zai 
+Lu 
+Ko 
+Jiao 
+Zhen 
+Ce 
+Qiao 
+Kuai 
+Chai 
+Ning 
+Nong 
+Jin 
+Wu 
+Hou 
+Jiong 
+Cheng 
+Zhen 
+Zuo 
+Chou 
+Qin 
+Lu 
+Ju 
+Shu 
+Ting 
+Shen 
+Tuo 
+Bo 
+Nan 
+Hao 
+Bian 
+Tui 
+Yu 
+Xi 
+Cu 
+E 
+Qiu 
+Xu 
+Kuang 
+Ku 
+Wu 
+Jun 
+Yi 
+Fu 
+Lang 
+Zu 
+Qiao 
+Li 
+Yong 
+Hun 
+Jing 
+Xian 
+San 
+Pai 
+Su 
+Fu 
+Xi 
+Li 
+Fu 
+Ping 
+Bao 
+Yu 
+Si 
+Xia 
+Xin 
+Xiu 
+Yu 
+Ti 
+Che 
+Chou 
+[?] 
+Yan 
+Lia 
+Li 
+Lai 
+[?] 
+Jian 
+Xiu 
+Fu 
+He 
+Ju 
+Xiao 
+Pai 
+Jian 
+Biao 
+Chu 
+Fei 
+Feng 
+Ya 
+An 
+Bei 
+Yu 
+Xin 
+Bi 
+Jian 
+Chang 
+Chi 
+Bing 
+Zan 
+Yao 
+Cui 
+Lia 
+Wan 
+Lai 
+Cang 
+Zong 
+Ge 
+Guan 
+Bei 
+Tian 
+Shu 
+Shu 
+Men 
+Dao 
+Tan 
+Jue 
+Chui 
+Xing 
+Peng 
+Tang 
+Hou 
+Yi 
+Qi 
+Ti 
+Gan 
+Jing 
+Jie 
+Sui 
+Chang 
+Jie 
+Fang 
+Zhi 
+Kong 
+Juan 
+Zong 
+Ju 
+Qian 
+Ni 
+Lun 
+Zhuo 
+Wei 
+Luo 
+Song 
+Leng 
+Hun 
+Dong 
+Zi 
+Ben 
+Wu 
+Ju 
+Nai 
+Cai 
+Jian 
+Zhai 
+Ye 
+Zhi 
+Sha 
+Qing 
+[?] 
+Ying 
+Cheng 
+Jian 
+Yan 
+Nuan 
+Zhong 
+Chun 
+Jia 
+Jie 
+Wei 
+Yu 
+Bing 
+Ruo 
+Ti 
+Wei 
+Pian 
+Yan 
+Feng 
+Tang 
+Wo 
+E 
+Xie 
+Che 
+Sheng 
+Kan 
+Di 
+Zuo 
+Cha 
+Ting 
+Bei 
+Ye 
+Huang 
+Yao 
+Zhan 
+Chou 
+Yan 
+You 
+Jian 
+Xu 
+Zha 
+Ci 
+Fu 
+Bi 
+Zhi 
+Zong 
+Mian 
+Ji 
+Yi 
+Xie 
+Xun 
+Si 
+Duan 
+Ce 
+Zhen 
+Ou 
+Tou 
+Tou 
+Bei 
+Za 
+Lu 
+Jie 
+Wei 
+Fen 
+Chang 
+Gui 
+Sou 
+Zhi 
+Su 
+Xia 
+Fu 
+Yuan 
+Rong 
+Li 
+Ru 
+Yun 
+Gou 
+Ma 
+Bang 
+Dian 
+Tang 
+Hao 
+Jie 
+Xi 
+Shan 
+Qian 
+Jue 
+Cang 
+Chu 
+San 
+Bei 
+Xiao 
+Yong 
+Yao 
+Tan 
+Suo 
+Yang 
+Fa 
+Bing 
+Jia 
+Dai 
+Zai 
+Tang 
+[?] 
+Bin 
+Chu 
+Nuo 
+Can 
+Lei 
+Cui 
+Yong 
+Zao 
+Zong 
+Peng 
+Song 
+Ao 
+Chuan 
+Yu 
+Zhai 
+Cou 
+Shang 
+Qiang 
+Jing 
+Chi 
+Sha 
+Han 
+Zhang 
+Qing 
+Yan 
+Di 
+Xi 
+Lu 
+Bei 
+Piao 
+Jin 
+Lian 
+Lu 
+Man 
+Qian 
+Xian 
+Tan 
+Ying 
+Dong 
+Zhuan 
+Xiang 
+Shan 
+Qiao 
+Jiong 
+Tui 
+Zun 
+Pu 
+Xi 
+Lao 
+Chang 
+Guang 
+Liao 
+Qi 
+Deng 
+Chan 
+Wei 
+Ji 
+Fan 
+Hui 
+Chuan 
+Jian 
+Dan 
+Jiao 
+Jiu 
+Seng 
+Fen 
+Xian 
+Jue 
+E 
+Jiao 
+Jian 
+Tong 
+Lin 
+Bo 
+Gu 
+[?] 
+Su 
+Xian 
+Jiang 
+Min 
+Ye 
+Jin 
+Jia 
+Qiao 
+Pi 
+Feng 
+Zhou 
+Ai 
+Sai 
+Yi 
+Jun 
+Nong 
+Chan 
+Yi 
+Dang 
+Jing 
+Xuan 
+Kuai 
+Jian 
+Chu 
+Dan 
+Jiao 
+Sha 
+Zai 
+[?] 
+Bin 
+An 
+Ru 
+Tai 
+Chou 
+Chai 
+Lan 
+Ni 
+Jin 
+Qian 
+Meng 
+Wu 
+Ning 
+Qiong 
+Ni 
+Chang 
+Lie 
+Lei 
+Lu 
+Kuang 
+Bao 
+Du 
+Biao 
+Zan 
+Zhi 
+Si 
+You 
+Hao 
+Chen 
+Chen 
+Li 
+Teng 
+Wei 
+Long 
+Chu 
+Chan 
+Rang 
+Shu 
+Hui 
+Li 
+Luo 
+Zan 
+Nuo 
+Tang 
+Yan 
+Lei 
+Nang 
+Er 
+Wu 
+Yun 
+Zan 
+Yuan 
+Xiong 
+Chong 
+Zhao 
+Xiong 
+Xian 
+Guang 
+Dui 
+Ke 
+Dui 
+Mian 
+Tu 
+Chang 
+Er 
+Dui 
+Er 
+Xin 
+Tu 
+Si 
+Yan 
+Yan 
+Shi 
+Shi 
+Dang 
+Qian 
+Dou 
+Fen 
+Mao 
+Shen 
+Dou 
+Bai 
+Jing 
+Li 
+Huang 
+Ru 
+Wang 
+Nei 
+Quan 
+Liang 
+Yu 
+Ba 
+Gong 
+Liu 
+Xi 
+[?] 
+Lan 
+Gong 
+Tian 
+Guan 
+Xing 
+Bing 
+Qi 
+Ju 
+Dian 
+Zi 
+Ppwun 
+Yang 
+Jian 
+Shou 
+Ji 
+Yi 
+Ji 
+Chan 
+Jiong 
+Mao 
+Ran 
+Nei 
+Yuan 
+Mao 
+Gang 
+Ran 
+Ce 
+Jiong 
+Ce 
+Zai 
+Gua 
+Jiong 
+Mao 
+Zhou 
+Mou 
+Gou 
+Xu 
+Mian 
+Mi 
+Rong 
+Yin 
+Xie 
+Kan 
+Jun 
+Nong 
+Yi 
+Mi 
+Shi 
+Guan 
+Meng 
+Zhong 
+Ju 
+Yuan 
+Ming 
+Kou 
+Lam 
+Fu 
+Xie 
+Mi 
+Bing 
+Dong 
+Tai 
+Gang 
+Feng 
+Bing 
+Hu 
+Chong 
+Jue 
+Hu 
+Kuang 
+Ye 
+Leng 
+Pan 
+Fu 
+Min 
+Dong 
+Xian 
+Lie 
+Xia 
+Jian 
+Jing 
+Shu 
+Mei 
+Tu 
+Qi 
+Gu 
+Zhun 
+Song 
+Jing 
+Liang 
+Qing 
+Diao 
+Ling 
+Dong 
+Gan 
+Jian 
+Yin 
+Cou 
+Yi 
+Li 
+Cang 
+Ming 
+Zhuen 
+Cui 
+Si 
+Duo 
+Jin 
+Lin 
+Lin 
+Ning 
+Xi 
+Du 
+Ji 
+Fan 
+Fan 
+Fan 
+Feng 
+Ju 
+Chu 
+Tako 
+Feng 
+Mok 
+Ci 
+Fu 
+Feng 
+Ping 
+Feng 
+Kai 
+Huang 
+Kai 
+Gan 
+Deng 
+Ping 
+Qu 
+Xiong 
+Kuai 
+Tu 
+Ao 
+Chu 
+Ji 
+Dang 
+Han 
+Han 
+Zao 
+Dao 
+Diao 
+Dao 
+Ren 
+Ren 
+Chuang 
+Fen 
+Qie 
+Yi 
+Ji 
+Kan 
+Qian 
+Cun 
+Chu 
+Wen 
+Ji 
+Dan 
+Xing 
+Hua 
+Wan 
+Jue 
+Li 
+Yue 
+Lie 
+Liu 
+Ze 
+Gang 
+Chuang 
+Fu 
+Chu 
+Qu 
+Ju 
+Shan 
+Min 
+Ling 
+Zhong 
+Pan 
+Bie 
+Jie 
+Jie 
+Bao 
+Li 
+Shan 
+Bie 
+Chan 
+Jing 
+Gua 
+Gen 
+Dao 
+Chuang 
+Kui 
+Ku 
+Duo 
+Er 
+Zhi 
+Shua 
+Quan 
+Cha 
+Ci 
+Ke 
+Jie 
+Gui 
+Ci 
+Gui 
+Kai 
+Duo 
+Ji 
+Ti 
+Jing 
+Lou 
+Gen 
+Ze 
+Yuan 
+Cuo 
+Xue 
+Ke 
+La 
+Qian 
+Cha 
+Chuang 
+Gua 
+Jian 
+Cuo 
+Li 
+Ti 
+Fei 
+Pou 
+Chan 
+Qi 
+Chuang 
+Zi 
+Gang 
+Wan 
+Bo 
+Ji 
+Duo 
+Qing 
+Yan 
+Zhuo 
+Jian 
+Ji 
+Bo 
+Yan 
+Ju 
+Huo 
+Sheng 
+Jian 
+Duo 
+Duan 
+Wu 
+Gua 
+Fu 
+Sheng 
+Jian 
+Ge 
+Zha 
+Kai 
+Chuang 
+Juan 
+Chan 
+Tuan 
+Lu 
+Li 
+Fou 
+Shan 
+Piao 
+Kou 
+Jiao 
+Gua 
+Qiao 
+Jue 
+Hua 
+Zha 
+Zhuo 
+Lian 
+Ju 
+Pi 
+Liu 
+Gui 
+Jiao 
+Gui 
+Jian 
+Jian 
+Tang 
+Huo 
+Ji 
+Jian 
+Yi 
+Jian 
+Zhi 
+Chan 
+Cuan 
+Mo 
+Li 
+Zhu 
+Li 
+Ya 
+Quan 
+Ban 
+Gong 
+Jia 
+Wu 
+Mai 
+Lie 
+Jin 
+Keng 
+Xie 
+Zhi 
+Dong 
+Zhu 
+Nu 
+Jie 
+Qu 
+Shao 
+Yi 
+Zhu 
+Miao 
+Li 
+Jing 
+Lao 
+Lao 
+Juan 
+Kou 
+Yang 
+Wa 
+Xiao 
+Mou 
+Kuang 
+Jie 
+Lie 
+He 
+Shi 
+Ke 
+Jing 
+Hao 
+Bo 
+Min 
+Chi 
+Lang 
+Yong 
+Yong 
+Mian 
+Ke 
+Xun 
+Juan 
+Qing 
+Lu 
+Pou 
+Meng 
+Lai 
+Le 
+Kai 
+Mian 
+Dong 
+Xu 
+Xu 
+Kan 
+Wu 
+Yi 
+Xun 
+Weng 
+Sheng 
+Lao 
+Mu 
+Lu 
+Piao 
+Shi 
+Ji 
+Qin 
+Qiang 
+Jiao 
+Quan 
+Yang 
+Yi 
+Jue 
+Fan 
+Juan 
+Tong 
+Ju 
+Dan 
+Xie 
+Mai 
+Xun 
+Xun 
+Lu 
+Li 
+Che 
+Rang 
+Quan 
+Bao 
+Shao 
+Yun 
+Jiu 
+Bao 
+Gou 
+Wu 
+Yun 
+Mwun 
+Nay 
+Gai 
+Gai 
+Bao 
+Cong 
+[?] 
+Xiong 
+Peng 
+Ju 
+Tao 
+Ge 
+Pu 
+An 
+Pao 
+Fu 
+Gong 
+Da 
+Jiu 
+Qiong 
+Bi 
+Hua 
+Bei 
+Nao 
+Chi 
+Fang 
+Jiu 
+Yi 
+Za 
+Jiang 
+Kang 
+Jiang 
+Kuang 
+Hu 
+Xia 
+Qu 
+Bian 
+Gui 
+Qie 
+Zang 
+Kuang 
+Fei 
+Hu 
+Tou 
+Gui 
+Gui 
+Hui 
+Dan 
+Gui 
+Lian 
+Lian 
+Suan 
+Du 
+Jiu 
+Qu 
+Xi 
+Pi 
+Qu 
+Yi 
+Qia 
+Yan 
+Bian 
+Ni 
+Qu 
+Shi 
+Xin 
+Qian 
+Nian 
+Sa 
+Zu 
+Sheng 
+Wu 
+Hui 
+Ban 
+Shi 
+Xi 
+Wan 
+Hua 
+Xie 
+Wan 
+Bei 
+Zu 
+Zhuo 
+Xie 
+Dan 
+Mai 
+Nan 
+Dan 
+Ji 
+Bo 
+Shuai 
+Bu 
+Kuang 
+Bian 
+Bu 
+Zhan 
+Qia 
+Lu 
+You 
+Lu 
+Xi 
+Gua 
+Wo 
+Xie 
+Jie 
+Jie 
+Wei 
+Ang 
+Qiong 
+Zhi 
+Mao 
+Yin 
+Wei 
+Shao 
+Ji 
+Que 
+Luan 
+Shi 
+Juan 
+Xie 
+Xu 
+Jin 
+Que 
+Wu 
+Ji 
+E 
+Qing 
+Xi 
+[?] 
+Han 
+Zhan 
+E 
+Ting 
+Li 
+Zhe 
+Han 
+Li 
+Ya 
+Ya 
+Yan 
+She 
+Zhi 
+Zha 
+Pang 
+[?] 
+He 
+Ya 
+Zhi 
+Ce 
+Pang 
+Ti 
+Li 
+She 
+Hou 
+Ting 
+Zui 
+Cuo 
+Fei 
+Yuan 
+Ce 
+Yuan 
+Xiang 
+Yan 
+Li 
+Jue 
+Sha 
+Dian 
+Chu 
+Jiu 
+Qin 
+Ao 
+Gui 
+Yan 
+Si 
+Li 
+Chang 
+Lan 
+Li 
+Yan 
+Yan 
+Yuan 
+Si 
+Gong 
+Lin 
+Qiu 
+Qu 
+Qu 
+Uk 
+Lei 
+Du 
+Xian 
+Zhuan 
+San 
+Can 
+Can 
+Can 
+Can 
+Ai 
+Dai 
+You 
+Cha 
+Ji 
+You 
+Shuang 
+Fan 
+Shou 
+Guai 
+Ba 
+Fa 
+Ruo 
+Shi 
+Shu 
+Zhuo 
+Qu 
+Shou 
+Bian 
+Xu 
+Jia 
+Pan 
+Sou 
+Gao 
+Wei 
+Sou 
+Die 
+Rui 
+Cong 
+Kou 
+Gu 
+Ju 
+Ling 
+Gua 
+Tao 
+Kou 
+Zhi 
+Jiao 
+Zhao 
+Ba 
+Ding 
+Ke 
+Tai 
+Chi 
+Shi 
+You 
+Qiu 
+Po 
+Xie 
+Hao 
+Si 
+Tan 
+Chi 
+Le 
+Diao 
+Ji 
+[?] 
+Hong 
+Mie 
+Xu 
+Mang 
+Chi 
+Ge 
+Xuan 
+Yao 
+Zi 
+He 
+Ji 
+Diao 
+Cun 
+Tong 
+Ming 
+Hou 
+Li 
+Tu 
+Xiang 
+Zha 
+Xia 
+Ye 
+Lu 
+A 
+Ma 
+Ou 
+Xue 
+Yi 
+Jun 
+Chou 
+Lin 
+Tun 
+Yin 
+Fei 
+Bi 
+Qin 
+Qin 
+Jie 
+Bu 
+Fou 
+Ba 
+Dun 
+Fen 
+E 
+Han 
+Ting 
+Hang 
+Shun 
+Qi 
+Hong 
+Zhi 
+Shen 
+Wu 
+Wu 
+Chao 
+Ne 
+Xue 
+Xi 
+Chui 
+Dou 
+Wen 
+Hou 
+Ou 
+Wu 
+Gao 
+Ya 
+Jun 
+Lu 
+E 
+Ge 
+Mei 
+Ai 
+Qi 
+Cheng 
+Wu 
+Gao 
+Fu 
+Jiao 
+Hong 
+Chi 
+Sheng 
+Ne 
+Tun 
+Fu 
+Yi 
+Dai 
+Ou 
+Li 
+Bai 
+Yuan 
+Kuai 
+[?] 
+Qiang 
+Wu 
+E 
+Shi 
+Quan 
+Pen 
+Wen 
+Ni 
+M 
+Ling 
+Ran 
+You 
+Di 
+Zhou 
+Shi 
+Zhou 
+Tie 
+Xi 
+Yi 
+Qi 
+Ping 
+Zi 
+Gu 
+Zi 
+Wei 
+Xu 
+He 
+Nao 
+Xia 
+Pei 
+Yi 
+Xiao 
+Shen 
+Hu 
+Ming 
+Da 
+Qu 
+Ju 
+Gem 
+Za 
+Tuo 
+Duo 
+Pou 
+Pao 
+Bi 
+Fu 
+Yang 
+He 
+Zha 
+He 
+Hai 
+Jiu 
+Yong 
+Fu 
+Que 
+Zhou 
+Wa 
+Ka 
+Gu 
+Ka 
+Zuo 
+Bu 
+Long 
+Dong 
+Ning 
+Tha 
+Si 
+Xian 
+Huo 
+Qi 
+Er 
+E 
+Guang 
+Zha 
+Xi 
+Yi 
+Lie 
+Zi 
+Mie 
+Mi 
+Zhi 
+Yao 
+Ji 
+Zhou 
+Ge 
+Shuai 
+Zan 
+Xiao 
+Ke 
+Hui 
+Kua 
+Huai 
+Tao 
+Xian 
+E 
+Xuan 
+Xiu 
+Wai 
+Yan 
+Lao 
+Yi 
+Ai 
+Pin 
+Shen 
+Tong 
+Hong 
+Xiong 
+Chi 
+Wa 
+Ha 
+Zai 
+Yu 
+Di 
+Pai 
+Xiang 
+Ai 
+Hen 
+Kuang 
+Ya 
+Da 
+Xiao 
+Bi 
+Yue 
+[?] 
+Hua 
+Sasou 
+Kuai 
+Duo 
+[?] 
+Ji 
+Nong 
+Mou 
+Yo 
+Hao 
+Yuan 
+Long 
+Pou 
+Mang 
+Ge 
+E 
+Chi 
+Shao 
+Li 
+Na 
+Zu 
+He 
+Ku 
+Xiao 
+Xian 
+Lao 
+Bo 
+Zhe 
+Zha 
+Liang 
+Ba 
+Mie 
+Le 
+Sui 
+Fou 
+Bu 
+Han 
+Heng 
+Geng 
+Shuo 
+Ge 
+You 
+Yan 
+Gu 
+Gu 
+Bai 
+Han 
+Suo 
+Chun 
+Yi 
+Ai 
+Jia 
+Tu 
+Xian 
+Huan 
+Li 
+Xi 
+Tang 
+Zuo 
+Qiu 
+Che 
+Wu 
+Zao 
+Ya 
+Dou 
+Qi 
+Di 
+Qin 
+Ma 
+Mal 
+Hong 
+Dou 
+Kes 
+Lao 
+Liang 
+Suo 
+Zao 
+Huan 
+Lang 
+Sha 
+Ji 
+Zuo 
+Wo 
+Feng 
+Yin 
+Hu 
+Qi 
+Shou 
+Wei 
+Shua 
+Chang 
+Er 
+Li 
+Qiang 
+An 
+Jie 
+Yo 
+Nian 
+Yu 
+Tian 
+Lai 
+Sha 
+Xi 
+Tuo 
+Hu 
+Ai 
+Zhou 
+Nou 
+Ken 
+Zhuo 
+Zhuo 
+Shang 
+Di 
+Heng 
+Lan 
+A 
+Xiao 
+Xiang 
+Tun 
+Wu 
+Wen 
+Cui 
+Sha 
+Hu 
+Qi 
+Qi 
+Tao 
+Dan 
+Dan 
+Ye 
+Zi 
+Bi 
+Cui 
+Chuo 
+He 
+Ya 
+Qi 
+Zhe 
+Pei 
+Liang 
+Xian 
+Pi 
+Sha 
+La 
+Ze 
+Qing 
+Gua 
+Pa 
+Zhe 
+Se 
+Zhuan 
+Nie 
+Guo 
+Luo 
+Yan 
+Di 
+Quan 
+Tan 
+Bo 
+Ding 
+Lang 
+Xiao 
+[?] 
+Tang 
+Chi 
+Ti 
+An 
+Jiu 
+Dan 
+Ke 
+Yong 
+Wei 
+Nan 
+Shan 
+Yu 
+Zhe 
+La 
+Jie 
+Hou 
+Han 
+Die 
+Zhou 
+Chai 
+Wai 
+Re 
+Yu 
+Yin 
+Zan 
+Yao 
+Wo 
+Mian 
+Hu 
+Yun 
+Chuan 
+Hui 
+Huan 
+Huan 
+Xi 
+He 
+Ji 
+Kui 
+Zhong 
+Wei 
+Sha 
+Xu 
+Huang 
+Du 
+Nie 
+Xuan 
+Liang 
+Yu 
+Sang 
+Chi 
+Qiao 
+Yan 
+Dan 
+Pen 
+Can 
+Li 
+Yo 
+Zha 
+Wei 
+Miao 
+Ying 
+Pen 
+Phos 
+Kui 
+Xi 
+Yu 
+Jie 
+Lou 
+Ku 
+Sao 
+Huo 
+Ti 
+Yao 
+He 
+A 
+Xiu 
+Qiang 
+Se 
+Yong 
+Su 
+Hong 
+Xie 
+Yi 
+Suo 
+Ma 
+Cha 
+Hai 
+Ke 
+Ta 
+Sang 
+Tian 
+Ru 
+Sou 
+Wa 
+Ji 
+Pang 
+Wu 
+Xian 
+Shi 
+Ge 
+Zi 
+Jie 
+Luo 
+Weng 
+Wa 
+Si 
+Chi 
+Hao 
+Suo 
+Jia 
+Hai 
+Suo 
+Qin 
+Nie 
+He 
+Cis 
+Sai 
+Ng 
+Ge 
+Na 
+Dia 
+Ai 
+[?] 
+Tong 
+Bi 
+Ao 
+Ao 
+Lian 
+Cui 
+Zhe 
+Mo 
+Sou 
+Sou 
+Tan 
+Di 
+Qi 
+Jiao 
+Chong 
+Jiao 
+Kai 
+Tan 
+San 
+Cao 
+Jia 
+Ai 
+Xiao 
+Piao 
+Lou 
+Ga 
+Gu 
+Xiao 
+Hu 
+Hui 
+Guo 
+Ou 
+Xian 
+Ze 
+Chang 
+Xu 
+Po 
+De 
+Ma 
+Ma 
+Hu 
+Lei 
+Du 
+Ga 
+Tang 
+Ye 
+Beng 
+Ying 
+Saai 
+Jiao 
+Mi 
+Xiao 
+Hua 
+Mai 
+Ran 
+Zuo 
+Peng 
+Lao 
+Xiao 
+Ji 
+Zhu 
+Chao 
+Kui 
+Zui 
+Xiao 
+Si 
+Hao 
+Fu 
+Liao 
+Qiao 
+Xi 
+Xiu 
+Tan 
+Tan 
+Mo 
+Xun 
+E 
+Zun 
+Fan 
+Chi 
+Hui 
+Zan 
+Chuang 
+Cu 
+Dan 
+Yu 
+Tun 
+Cheng 
+Jiao 
+Ye 
+Xi 
+Qi 
+Hao 
+Lian 
+Xu 
+Deng 
+Hui 
+Yin 
+Pu 
+Jue 
+Qin 
+Xun 
+Nie 
+Lu 
+Si 
+Yan 
+Ying 
+Da 
+Dan 
+Yu 
+Zhou 
+Jin 
+Nong 
+Yue 
+Hui 
+Qi 
+E 
+Zao 
+Yi 
+Shi 
+Jiao 
+Yuan 
+Ai 
+Yong 
+Jue 
+Kuai 
+Yu 
+Pen 
+Dao 
+Ge 
+Xin 
+Dun 
+Dang 
+Sin 
+Sai 
+Pi 
+Pi 
+Yin 
+Zui 
+Ning 
+Di 
+Lan 
+Ta 
+Huo 
+Ru 
+Hao 
+Xia 
+Ya 
+Duo 
+Xi 
+Chou 
+Ji 
+Jin 
+Hao 
+Ti 
+Chang 
+[?] 
+[?] 
+Ca 
+Ti 
+Lu 
+Hui 
+Bo 
+You 
+Nie 
+Yin 
+Hu 
+Mo 
+Huang 
+Zhe 
+Li 
+Liu 
+Haai 
+Nang 
+Xiao 
+Mo 
+Yan 
+Li 
+Lu 
+Long 
+Fu 
+Dan 
+Chen 
+Pin 
+Pi 
+Xiang 
+Huo 
+Mo 
+Xi 
+Duo 
+Ku 
+Yan 
+Chan 
+Ying 
+Rang 
+Dian 
+La 
+Ta 
+Xiao 
+Jiao 
+Chuo 
+Huan 
+Huo 
+Zhuan 
+Nie 
+Xiao 
+Ca 
+Li 
+Chan 
+Chai 
+Li 
+Yi 
+Luo 
+Nang 
+Zan 
+Su 
+Xi 
+So 
+Jian 
+Za 
+Zhu 
+Lan 
+Nie 
+Nang 
+[?] 
+[?] 
+Wei 
+Hui 
+Yin 
+Qiu 
+Si 
+Nin 
+Jian 
+Hui 
+Xin 
+Yin 
+Nan 
+Tuan 
+Tuan 
+Dun 
+Kang 
+Yuan 
+Jiong 
+Pian 
+Yun 
+Cong 
+Hu 
+Hui 
+Yuan 
+You 
+Guo 
+Kun 
+Cong 
+Wei 
+Tu 
+Wei 
+Lun 
+Guo 
+Qun 
+Ri 
+Ling 
+Gu 
+Guo 
+Tai 
+Guo 
+Tu 
+You 
+Guo 
+Yin 
+Hun 
+Pu 
+Yu 
+Han 
+Yuan 
+Lun 
+Quan 
+Yu 
+Qing 
+Guo 
+Chuan 
+Wei 
+Yuan 
+Quan 
+Ku 
+Fu 
+Yuan 
+Yuan 
+E 
+Tu 
+Tu 
+Tu 
+Tuan 
+Lue 
+Hui 
+Yi 
+Yuan 
+Luan 
+Luan 
+Tu 
+Ya 
+Tu 
+Ting 
+Sheng 
+Pu 
+Lu 
+Iri 
+Ya 
+Zai 
+Wei 
+Ge 
+Yu 
+Wu 
+Gui 
+Pi 
+Yi 
+Di 
+Qian 
+Qian 
+Zhen 
+Zhuo 
+Dang 
+Qia 
+Akutsu 
+Yama 
+Kuang 
+Chang 
+Qi 
+Nie 
+Mo 
+Ji 
+Jia 
+Zhi 
+Zhi 
+Ban 
+Xun 
+Tou 
+Qin 
+Fen 
+Jun 
+Keng 
+Tun 
+Fang 
+Fen 
+Ben 
+Tan 
+Kan 
+Pi 
+Zuo 
+Keng 
+Bi 
+Xing 
+Di 
+Jing 
+Ji 
+Kuai 
+Di 
+Jing 
+Jian 
+Tan 
+Li 
+Ba 
+Wu 
+Fen 
+Zhui 
+Po 
+Pan 
+Tang 
+Kun 
+Qu 
+Tan 
+Zhi 
+Tuo 
+Gan 
+Ping 
+Dian 
+Gua 
+Ni 
+Tai 
+Pi 
+Jiong 
+Yang 
+Fo 
+Ao 
+Liu 
+Qiu 
+Mu 
+Ke 
+Gou 
+Xue 
+Ba 
+Chi 
+Che 
+Ling 
+Zhu 
+Fu 
+Hu 
+Zhi 
+Chui 
+La 
+Long 
+Long 
+Lu 
+Ao 
+Tay 
+Pao 
+[?] 
+Xing 
+Dong 
+Ji 
+Ke 
+Lu 
+Ci 
+Chi 
+Lei 
+Gai 
+Yin 
+Hou 
+Dui 
+Zhao 
+Fu 
+Guang 
+Yao 
+Duo 
+Duo 
+Gui 
+Cha 
+Yang 
+Yin 
+Fa 
+Gou 
+Yuan 
+Die 
+Xie 
+Ken 
+Jiong 
+Shou 
+E 
+Ha 
+Dian 
+Hong 
+Wu 
+Kua 
+[?] 
+Tao 
+Dang 
+Kai 
+Gake 
+Nao 
+An 
+Xing 
+Xian 
+Huan 
+Bang 
+Pei 
+Ba 
+Yi 
+Yin 
+Han 
+Xu 
+Chui 
+Cen 
+Geng 
+Ai 
+Peng 
+Fang 
+Que 
+Yong 
+Xun 
+Jia 
+Di 
+Mai 
+Lang 
+Xuan 
+Cheng 
+Yan 
+Jin 
+Zhe 
+Lei 
+Lie 
+Bu 
+Cheng 
+Gomi 
+Bu 
+Shi 
+Xun 
+Guo 
+Jiong 
+Ye 
+Nian 
+Di 
+Yu 
+Bu 
+Ya 
+Juan 
+Sui 
+Pi 
+Cheng 
+Wan 
+Ju 
+Lun 
+Zheng 
+Kong 
+Chong 
+Dong 
+Dai 
+Tan 
+An 
+Cai 
+Shu 
+Beng 
+Kan 
+Zhi 
+Duo 
+Yi 
+Zhi 
+Yi 
+Pei 
+Ji 
+Zhun 
+Qi 
+Sao 
+Ju 
+Ni 
+Ku 
+Ke 
+Tang 
+Kun 
+Ni 
+Jian 
+Dui 
+Jin 
+Gang 
+Yu 
+E 
+Peng 
+Gu 
+Tu 
+Leng 
+[?] 
+Ya 
+Qian 
+[?] 
+An 
+[?] 
+Duo 
+Nao 
+Tu 
+Cheng 
+Yin 
+Hun 
+Bi 
+Lian 
+Guo 
+Die 
+Zhuan 
+Hou 
+Bao 
+Bao 
+Yu 
+Di 
+Mao 
+Jie 
+Ruan 
+E 
+Geng 
+Kan 
+Zong 
+Yu 
+Huang 
+E 
+Yao 
+Yan 
+Bao 
+Ji 
+Mei 
+Chang 
+Du 
+Tuo 
+Yin 
+Feng 
+Zhong 
+Jie 
+Zhen 
+Feng 
+Gang 
+Chuan 
+Jian 
+Pyeng 
+Toride 
+Xiang 
+Huang 
+Leng 
+Duan 
+[?] 
+Xuan 
+Ji 
+Ji 
+Kuai 
+Ying 
+Ta 
+Cheng 
+Yong 
+Kai 
+Su 
+Su 
+Shi 
+Mi 
+Ta 
+Weng 
+Cheng 
+Tu 
+Tang 
+Que 
+Zhong 
+Li 
+Peng 
+Bang 
+Sai 
+Zang 
+Dui 
+Tian 
+Wu 
+Cheng 
+Xun 
+Ge 
+Zhen 
+Ai 
+Gong 
+Yan 
+Kan 
+Tian 
+Yuan 
+Wen 
+Xie 
+Liu 
+Ama 
+Lang 
+Chang 
+Peng 
+Beng 
+Chen 
+Cu 
+Lu 
+Ou 
+Qian 
+Mei 
+Mo 
+Zhuan 
+Shuang 
+Shu 
+Lou 
+Chi 
+Man 
+Biao 
+Jing 
+Qi 
+Shu 
+Di 
+Zhang 
+Kan 
+Yong 
+Dian 
+Chen 
+Zhi 
+Xi 
+Guo 
+Qiang 
+Jin 
+Di 
+Shang 
+Mu 
+Cui 
+Yan 
+Ta 
+Zeng 
+Qi 
+Qiang 
+Liang 
+[?] 
+Zhui 
+Qiao 
+Zeng 
+Xu 
+Shan 
+Shan 
+Ba 
+Pu 
+Kuai 
+Dong 
+Fan 
+Que 
+Mo 
+Dun 
+Dun 
+Dun 
+Di 
+Sheng 
+Duo 
+Duo 
+Tan 
+Deng 
+Wu 
+Fen 
+Huang 
+Tan 
+Da 
+Ye 
+Sho 
+Mama 
+Yu 
+Qiang 
+Ji 
+Qiao 
+Ken 
+Yi 
+Pi 
+Bi 
+Dian 
+Jiang 
+Ye 
+Yong 
+Bo 
+Tan 
+Lan 
+Ju 
+Huai 
+Dang 
+Rang 
+Qian 
+Xun 
+Lan 
+Xi 
+He 
+Ai 
+Ya 
+Dao 
+Hao 
+Ruan 
+Mama 
+Lei 
+Kuang 
+Lu 
+Yan 
+Tan 
+Wei 
+Huai 
+Long 
+Long 
+Rui 
+Li 
+Lin 
+Rang 
+Ten 
+Xun 
+Yan 
+Lei 
+Ba 
+[?] 
+Shi 
+Ren 
+[?] 
+Zhuang 
+Zhuang 
+Sheng 
+Yi 
+Mai 
+Ke 
+Zhu 
+Zhuang 
+Hu 
+Hu 
+Kun 
+Yi 
+Hu 
+Xu 
+Kun 
+Shou 
+Mang 
+Zun 
+Shou 
+Yi 
+Zhi 
+Gu 
+Chu 
+Jiang 
+Feng 
+Bei 
+Cay 
+Bian 
+Sui 
+Qun 
+Ling 
+Fu 
+Zuo 
+Xia 
+Xiong 
+[?] 
+Nao 
+Xia 
+Kui 
+Xi 
+Wai 
+Yuan 
+Mao 
+Su 
+Duo 
+Duo 
+Ye 
+Qing 
+Uys 
+Gou 
+Gou 
+Qi 
+Meng 
+Meng 
+Yin 
+Huo 
+Chen 
+Da 
+Ze 
+Tian 
+Tai 
+Fu 
+Guai 
+Yao 
+Yang 
+Hang 
+Gao 
+Shi 
+Ben 
+Tai 
+Tou 
+Yan 
+Bi 
+Yi 
+Kua 
+Jia 
+Duo 
+Kwu 
+Kuang 
+Yun 
+Jia 
+Pa 
+En 
+Lian 
+Huan 
+Di 
+Yan 
+Pao 
+Quan 
+Qi 
+Nai 
+Feng 
+Xie 
+Fen 
+Dian 
+[?] 
+Kui 
+Zou 
+Huan 
+Qi 
+Kai 
+Zha 
+Ben 
+Yi 
+Jiang 
+Tao 
+Zang 
+Ben 
+Xi 
+Xiang 
+Fei 
+Diao 
+Xun 
+Keng 
+Dian 
+Ao 
+She 
+Weng 
+Pan 
+Ao 
+Wu 
+Ao 
+Jiang 
+Lian 
+Duo 
+Yun 
+Jiang 
+Shi 
+Fen 
+Huo 
+Bi 
+Lian 
+Duo 
+Nu 
+Nu 
+Ding 
+Nai 
+Qian 
+Jian 
+Ta 
+Jiu 
+Nan 
+Cha 
+Hao 
+Xian 
+Fan 
+Ji 
+Shuo 
+Ru 
+Fei 
+Wang 
+Hong 
+Zhuang 
+Fu 
+Ma 
+Dan 
+Ren 
+Fu 
+Jing 
+Yan 
+Xie 
+Wen 
+Zhong 
+Pa 
+Du 
+Ji 
+Keng 
+Zhong 
+Yao 
+Jin 
+Yun 
+Miao 
+Pei 
+Shi 
+Yue 
+Zhuang 
+Niu 
+Yan 
+Na 
+Xin 
+Fen 
+Bi 
+Yu 
+Tuo 
+Feng 
+Yuan 
+Fang 
+Wu 
+Yu 
+Gui 
+Du 
+Ba 
+Ni 
+Zhou 
+Zhuo 
+Zhao 
+Da 
+Nai 
+Yuan 
+Tou 
+Xuan 
+Zhi 
+E 
+Mei 
+Mo 
+Qi 
+Bi 
+Shen 
+Qie 
+E 
+He 
+Xu 
+Fa 
+Zheng 
+Min 
+Ban 
+Mu 
+Fu 
+Ling 
+Zi 
+Zi 
+Shi 
+Ran 
+Shan 
+Yang 
+Man 
+Jie 
+Gu 
+Si 
+Xing 
+Wei 
+Zi 
+Ju 
+Shan 
+Pin 
+Ren 
+Yao 
+Tong 
+Jiang 
+Shu 
+Ji 
+Gai 
+Shang 
+Kuo 
+Juan 
+Jiao 
+Gou 
+Mu 
+Jian 
+Jian 
+Yi 
+Nian 
+Zhi 
+Ji 
+Ji 
+Xian 
+Heng 
+Guang 
+Jun 
+Kua 
+Yan 
+Ming 
+Lie 
+Pei 
+Yan 
+You 
+Yan 
+Cha 
+Shen 
+Yin 
+Chi 
+Gui 
+Quan 
+Zi 
+Song 
+Wei 
+Hong 
+Wa 
+Lou 
+Ya 
+Rao 
+Jiao 
+Luan 
+Ping 
+Xian 
+Shao 
+Li 
+Cheng 
+Xiao 
+Mang 
+Fu 
+Suo 
+Wu 
+Wei 
+Ke 
+Lai 
+Chuo 
+Ding 
+Niang 
+Xing 
+Nan 
+Yu 
+Nuo 
+Pei 
+Nei 
+Juan 
+Shen 
+Zhi 
+Han 
+Di 
+Zhuang 
+E 
+Pin 
+Tui 
+Han 
+Mian 
+Wu 
+Yan 
+Wu 
+Xi 
+Yan 
+Yu 
+Si 
+Yu 
+Wa 
+[?] 
+Xian 
+Ju 
+Qu 
+Shui 
+Qi 
+Xian 
+Zhui 
+Dong 
+Chang 
+Lu 
+Ai 
+E 
+E 
+Lou 
+Mian 
+Cong 
+Pou 
+Ju 
+Po 
+Cai 
+Ding 
+Wan 
+Biao 
+Xiao 
+Shu 
+Qi 
+Hui 
+Fu 
+E 
+Wo 
+Tan 
+Fei 
+Wei 
+Jie 
+Tian 
+Ni 
+Quan 
+Jing 
+Hun 
+Jing 
+Qian 
+Dian 
+Xing 
+Hu 
+Wa 
+Lai 
+Bi 
+Yin 
+Chou 
+Chuo 
+Fu 
+Jing 
+Lun 
+Yan 
+Lan 
+Kun 
+Yin 
+Ya 
+Ju 
+Li 
+Dian 
+Xian 
+Hwa 
+Hua 
+Ying 
+Chan 
+Shen 
+Ting 
+Dang 
+Yao 
+Wu 
+Nan 
+Ruo 
+Jia 
+Tou 
+Xu 
+Yu 
+Wei 
+Ti 
+Rou 
+Mei 
+Dan 
+Ruan 
+Qin 
+Hui 
+Wu 
+Qian 
+Chun 
+Mao 
+Fu 
+Jie 
+Duan 
+Xi 
+Zhong 
+Mei 
+Huang 
+Mian 
+An 
+Ying 
+Xuan 
+Jie 
+Wei 
+Mei 
+Yuan 
+Zhen 
+Qiu 
+Ti 
+Xie 
+Tuo 
+Lian 
+Mao 
+Ran 
+Si 
+Pian 
+Wei 
+Wa 
+Jiu 
+Hu 
+Ao 
+[?] 
+Bou 
+Xu 
+Tou 
+Gui 
+Zou 
+Yao 
+Pi 
+Xi 
+Yuan 
+Ying 
+Rong 
+Ru 
+Chi 
+Liu 
+Mei 
+Pan 
+Ao 
+Ma 
+Gou 
+Kui 
+Qin 
+Jia 
+Sao 
+Zhen 
+Yuan 
+Cha 
+Yong 
+Ming 
+Ying 
+Ji 
+Su 
+Niao 
+Xian 
+Tao 
+Pang 
+Lang 
+Nao 
+Bao 
+Ai 
+Pi 
+Pin 
+Yi 
+Piao 
+Yu 
+Lei 
+Xuan 
+Man 
+Yi 
+Zhang 
+Kang 
+Yong 
+Ni 
+Li 
+Di 
+Gui 
+Yan 
+Jin 
+Zhuan 
+Chang 
+Ce 
+Han 
+Nen 
+Lao 
+Mo 
+Zhe 
+Hu 
+Hu 
+Ao 
+Nen 
+Qiang 
+Ma 
+Pie 
+Gu 
+Wu 
+Jiao 
+Tuo 
+Zhan 
+Mao 
+Xian 
+Xian 
+Mo 
+Liao 
+Lian 
+Hua 
+Gui 
+Deng 
+Zhi 
+Xu 
+Yi 
+Hua 
+Xi 
+Hui 
+Rao 
+Xi 
+Yan 
+Chan 
+Jiao 
+Mei 
+Fan 
+Fan 
+Xian 
+Yi 
+Wei 
+Jiao 
+Fu 
+Shi 
+Bi 
+Shan 
+Sui 
+Qiang 
+Lian 
+Huan 
+Xin 
+Niao 
+Dong 
+Yi 
+Can 
+Ai 
+Niang 
+Neng 
+Ma 
+Tiao 
+Chou 
+Jin 
+Ci 
+Yu 
+Pin 
+Yong 
+Xu 
+Nai 
+Yan 
+Tai 
+Ying 
+Can 
+Niao 
+Wo 
+Ying 
+Mian 
+Kaka 
+Ma 
+Shen 
+Xing 
+Ni 
+Du 
+Liu 
+Yuan 
+Lan 
+Yan 
+Shuang 
+Ling 
+Jiao 
+Niang 
+Lan 
+Xian 
+Ying 
+Shuang 
+Shuai 
+Quan 
+Mi 
+Li 
+Luan 
+Yan 
+Zhu 
+Lan 
+Zi 
+Jie 
+Jue 
+Jue 
+Kong 
+Yun 
+Zi 
+Zi 
+Cun 
+Sun 
+Fu 
+Bei 
+Zi 
+Xiao 
+Xin 
+Meng 
+Si 
+Tai 
+Bao 
+Ji 
+Gu 
+Nu 
+Xue 
+[?] 
+Zhuan 
+Hai 
+Luan 
+Sun 
+Huai 
+Mie 
+Cong 
+Qian 
+Shu 
+Chan 
+Ya 
+Zi 
+Ni 
+Fu 
+Zi 
+Li 
+Xue 
+Bo 
+Ru 
+Lai 
+Nie 
+Nie 
+Ying 
+Luan 
+Mian 
+Zhu 
+Rong 
+Ta 
+Gui 
+Zhai 
+Qiong 
+Yu 
+Shou 
+An 
+Tu 
+Song 
+Wan 
+Rou 
+Yao 
+Hong 
+Yi 
+Jing 
+Zhun 
+Mi 
+Zhu 
+Dang 
+Hong 
+Zong 
+Guan 
+Zhou 
+Ding 
+Wan 
+Yi 
+Bao 
+Shi 
+Shi 
+Chong 
+Shen 
+Ke 
+Xuan 
+Shi 
+You 
+Huan 
+Yi 
+Tiao 
+Shi 
+Xian 
+Gong 
+Cheng 
+Qun 
+Gong 
+Xiao 
+Zai 
+Zha 
+Bao 
+Hai 
+Yan 
+Xiao 
+Jia 
+Shen 
+Chen 
+Rong 
+Huang 
+Mi 
+Kou 
+Kuan 
+Bin 
+Su 
+Cai 
+Zan 
+Ji 
+Yuan 
+Ji 
+Yin 
+Mi 
+Kou 
+Qing 
+Que 
+Zhen 
+Jian 
+Fu 
+Ning 
+Bing 
+Huan 
+Mei 
+Qin 
+Han 
+Yu 
+Shi 
+Ning 
+Qin 
+Ning 
+Zhi 
+Yu 
+Bao 
+Kuan 
+Ning 
+Qin 
+Mo 
+Cha 
+Ju 
+Gua 
+Qin 
+Hu 
+Wu 
+Liao 
+Shi 
+Zhu 
+Zhai 
+Shen 
+Wei 
+Xie 
+Kuan 
+Hui 
+Liao 
+Jun 
+Huan 
+Yi 
+Yi 
+Bao 
+Qin 
+Chong 
+Bao 
+Feng 
+Cun 
+Dui 
+Si 
+Xun 
+Dao 
+Lu 
+Dui 
+Shou 
+Po 
+Feng 
+Zhuan 
+Fu 
+She 
+Ke 
+Jiang 
+Jiang 
+Zhuan 
+Wei 
+Zun 
+Xun 
+Shu 
+Dui 
+Dao 
+Xiao 
+Ji 
+Shao 
+Er 
+Er 
+Er 
+Ga 
+Jian 
+Shu 
+Chen 
+Shang 
+Shang 
+Mo 
+Ga 
+Chang 
+Liao 
+Xian 
+Xian 
+[?] 
+Wang 
+Wang 
+You 
+Liao 
+Liao 
+Yao 
+Mang 
+Wang 
+Wang 
+Wang 
+Ga 
+Yao 
+Duo 
+Kui 
+Zhong 
+Jiu 
+Gan 
+Gu 
+Gan 
+Tui 
+Gan 
+Gan 
+Shi 
+Yin 
+Chi 
+Kao 
+Ni 
+Jin 
+Wei 
+Niao 
+Ju 
+Pi 
+Ceng 
+Xi 
+Bi 
+Ju 
+Jie 
+Tian 
+Qu 
+Ti 
+Jie 
+Wu 
+Diao 
+Shi 
+Shi 
+Ping 
+Ji 
+Xie 
+Chen 
+Xi 
+Ni 
+Zhan 
+Xi 
+[?] 
+Man 
+E 
+Lou 
+Ping 
+Ti 
+Fei 
+Shu 
+Xie 
+Tu 
+Lu 
+Lu 
+Xi 
+Ceng 
+Lu 
+Ju 
+Xie 
+Ju 
+Jue 
+Liao 
+Jue 
+Shu 
+Xi 
+Che 
+Tun 
+Ni 
+Shan 
+[?] 
+Xian 
+Li 
+Xue 
+Nata 
+[?] 
+Long 
+Yi 
+Qi 
+Ren 
+Wu 
+Han 
+Shen 
+Yu 
+Chu 
+Sui 
+Qi 
+[?] 
+Yue 
+Ban 
+Yao 
+Ang 
+Ya 
+Wu 
+Jie 
+E 
+Ji 
+Qian 
+Fen 
+Yuan 
+Qi 
+Cen 
+Qian 
+Qi 
+Cha 
+Jie 
+Qu 
+Gang 
+Xian 
+Ao 
+Lan 
+Dao 
+Ba 
+Zuo 
+Zuo 
+Yang 
+Ju 
+Gang 
+Ke 
+Gou 
+Xue 
+Bei 
+Li 
+Tiao 
+Ju 
+Yan 
+Fu 
+Xiu 
+Jia 
+Ling 
+Tuo 
+Pei 
+You 
+Dai 
+Kuang 
+Yue 
+Qu 
+Hu 
+Po 
+Min 
+An 
+Tiao 
+Ling 
+Chi 
+Yuri 
+Dong 
+Cem 
+Kui 
+Xiu 
+Mao 
+Tong 
+Xue 
+Yi 
+Kura 
+He 
+Ke 
+Luo 
+E 
+Fu 
+Xun 
+Die 
+Lu 
+An 
+Er 
+Gai 
+Quan 
+Tong 
+Yi 
+Mu 
+Shi 
+An 
+Wei 
+Hu 
+Zhi 
+Mi 
+Li 
+Ji 
+Tong 
+Wei 
+You 
+Sang 
+Xia 
+Li 
+Yao 
+Jiao 
+Zheng 
+Luan 
+Jiao 
+E 
+E 
+Yu 
+Ye 
+Bu 
+Qiao 
+Qun 
+Feng 
+Feng 
+Nao 
+Li 
+You 
+Xian 
+Hong 
+Dao 
+Shen 
+Cheng 
+Tu 
+Geng 
+Jun 
+Hao 
+Xia 
+Yin 
+Yu 
+Lang 
+Kan 
+Lao 
+Lai 
+Xian 
+Que 
+Kong 
+Chong 
+Chong 
+Ta 
+Lin 
+Hua 
+Ju 
+Lai 
+Qi 
+Min 
+Kun 
+Kun 
+Zu 
+Gu 
+Cui 
+Ya 
+Ya 
+Gang 
+Lun 
+Lun 
+Leng 
+Jue 
+Duo 
+Zheng 
+Guo 
+Yin 
+Dong 
+Han 
+Zheng 
+Wei 
+Yao 
+Pi 
+Yan 
+Song 
+Jie 
+Beng 
+Zu 
+Jue 
+Dong 
+Zhan 
+Gu 
+Yin 
+[?] 
+Ze 
+Huang 
+Yu 
+Wei 
+Yang 
+Feng 
+Qiu 
+Dun 
+Ti 
+Yi 
+Zhi 
+Shi 
+Zai 
+Yao 
+E 
+Zhu 
+Kan 
+Lu 
+Yan 
+Mei 
+Gan 
+Ji 
+Ji 
+Huan 
+Ting 
+Sheng 
+Mei 
+Qian 
+Wu 
+Yu 
+Zong 
+Lan 
+Jue 
+Yan 
+Yan 
+Wei 
+Zong 
+Cha 
+Sui 
+Rong 
+Yamashina 
+Qin 
+Yu 
+Kewashii 
+Lou 
+Tu 
+Dui 
+Xi 
+Weng 
+Cang 
+Dang 
+Hong 
+Jie 
+Ai 
+Liu 
+Wu 
+Song 
+Qiao 
+Zi 
+Wei 
+Beng 
+Dian 
+Cuo 
+Qian 
+Yong 
+Nie 
+Cuo 
+Ji 
+[?] 
+Tao 
+Song 
+Zong 
+Jiang 
+Liao 
+Kang 
+Chan 
+Die 
+Cen 
+Ding 
+Tu 
+Lou 
+Zhang 
+Zhan 
+Zhan 
+Ao 
+Cao 
+Qu 
+Qiang 
+Zui 
+Zui 
+Dao 
+Dao 
+Xi 
+Yu 
+Bo 
+Long 
+Xiang 
+Ceng 
+Bo 
+Qin 
+Jiao 
+Yan 
+Lao 
+Zhan 
+Lin 
+Liao 
+Liao 
+Jin 
+Deng 
+Duo 
+Zun 
+Jiao 
+Gui 
+Yao 
+Qiao 
+Yao 
+Jue 
+Zhan 
+Yi 
+Xue 
+Nao 
+Ye 
+Ye 
+Yi 
+E 
+Xian 
+Ji 
+Xie 
+Ke 
+Xi 
+Di 
+Ao 
+Zui 
+[?] 
+Ni 
+Rong 
+Dao 
+Ling 
+Za 
+Yu 
+Yue 
+Yin 
+[?] 
+Jie 
+Li 
+Sui 
+Long 
+Long 
+Dian 
+Ying 
+Xi 
+Ju 
+Chan 
+Ying 
+Kui 
+Yan 
+Wei 
+Nao 
+Quan 
+Chao 
+Cuan 
+Luan 
+Dian 
+Dian 
+[?] 
+Yan 
+Yan 
+Yan 
+Nao 
+Yan 
+Chuan 
+Gui 
+Chuan 
+Zhou 
+Huang 
+Jing 
+Xun 
+Chao 
+Chao 
+Lie 
+Gong 
+Zuo 
+Qiao 
+Ju 
+Gong 
+Kek 
+Wu 
+Pwu 
+Pwu 
+Chai 
+Qiu 
+Qiu 
+Ji 
+Yi 
+Si 
+Ba 
+Zhi 
+Zhao 
+Xiang 
+Yi 
+Jin 
+Xun 
+Juan 
+Phas 
+Xun 
+Jin 
+Fu 
+Za 
+Bi 
+Shi 
+Bu 
+Ding 
+Shuai 
+Fan 
+Nie 
+Shi 
+Fen 
+Pa 
+Zhi 
+Xi 
+Hu 
+Dan 
+Wei 
+Zhang 
+Tang 
+Dai 
+Ma 
+Pei 
+Pa 
+Tie 
+Fu 
+Lian 
+Zhi 
+Zhou 
+Bo 
+Zhi 
+Di 
+Mo 
+Yi 
+Yi 
+Ping 
+Qia 
+Juan 
+Ru 
+Shuai 
+Dai 
+Zheng 
+Shui 
+Qiao 
+Zhen 
+Shi 
+Qun 
+Xi 
+Bang 
+Dai 
+Gui 
+Chou 
+Ping 
+Zhang 
+Sha 
+Wan 
+Dai 
+Wei 
+Chang 
+Sha 
+Qi 
+Ze 
+Guo 
+Mao 
+Du 
+Hou 
+Zheng 
+Xu 
+Mi 
+Wei 
+Wo 
+Fu 
+Yi 
+Bang 
+Ping 
+Tazuna 
+Gong 
+Pan 
+Huang 
+Dao 
+Mi 
+Jia 
+Teng 
+Hui 
+Zhong 
+Shan 
+Man 
+Mu 
+Biao 
+Guo 
+Ze 
+Mu 
+Bang 
+Zhang 
+Jiong 
+Chan 
+Fu 
+Zhi 
+Hu 
+Fan 
+Chuang 
+Bi 
+Hei 
+[?] 
+Mi 
+Qiao 
+Chan 
+Fen 
+Meng 
+Bang 
+Chou 
+Mie 
+Chu 
+Jie 
+Xian 
+Lan 
+Gan 
+Ping 
+Nian 
+Qian 
+Bing 
+Bing 
+Xing 
+Gan 
+Yao 
+Huan 
+You 
+You 
+Ji 
+Yan 
+Pi 
+Ting 
+Ze 
+Guang 
+Zhuang 
+Mo 
+Qing 
+Bi 
+Qin 
+Dun 
+Chuang 
+Gui 
+Ya 
+Bai 
+Jie 
+Xu 
+Lu 
+Wu 
+[?] 
+Ku 
+Ying 
+Di 
+Pao 
+Dian 
+Ya 
+Miao 
+Geng 
+Ci 
+Fu 
+Tong 
+Pang 
+Fei 
+Xiang 
+Yi 
+Zhi 
+Tiao 
+Zhi 
+Xiu 
+Du 
+Zuo 
+Xiao 
+Tu 
+Gui 
+Ku 
+Pang 
+Ting 
+You 
+Bu 
+Ding 
+Cheng 
+Lai 
+Bei 
+Ji 
+An 
+Shu 
+Kang 
+Yong 
+Tuo 
+Song 
+Shu 
+Qing 
+Yu 
+Yu 
+Miao 
+Sou 
+Ce 
+Xiang 
+Fei 
+Jiu 
+He 
+Hui 
+Liu 
+Sha 
+Lian 
+Lang 
+Sou 
+Jian 
+Pou 
+Qing 
+Jiu 
+Jiu 
+Qin 
+Ao 
+Kuo 
+Lou 
+Yin 
+Liao 
+Dai 
+Lu 
+Yi 
+Chu 
+Chan 
+Tu 
+Si 
+Xin 
+Miao 
+Chang 
+Wu 
+Fei 
+Guang 
+Koc 
+Kuai 
+Bi 
+Qiang 
+Xie 
+Lin 
+Lin 
+Liao 
+Lu 
+[?] 
+Ying 
+Xian 
+Ting 
+Yong 
+Li 
+Ting 
+Yin 
+Xun 
+Yan 
+Ting 
+Di 
+Po 
+Jian 
+Hui 
+Nai 
+Hui 
+Gong 
+Nian 
+Kai 
+Bian 
+Yi 
+Qi 
+Nong 
+Fen 
+Ju 
+Yan 
+Yi 
+Zang 
+Bi 
+Yi 
+Yi 
+Er 
+San 
+Shi 
+Er 
+Shi 
+Shi 
+Gong 
+Diao 
+Yin 
+Hu 
+Fu 
+Hong 
+Wu 
+Tui 
+Chi 
+Jiang 
+Ba 
+Shen 
+Di 
+Zhang 
+Jue 
+Tao 
+Fu 
+Di 
+Mi 
+Xian 
+Hu 
+Chao 
+Nu 
+Jing 
+Zhen 
+Yi 
+Mi 
+Quan 
+Wan 
+Shao 
+Ruo 
+Xuan 
+Jing 
+Dun 
+Zhang 
+Jiang 
+Qiang 
+Peng 
+Dan 
+Qiang 
+Bi 
+Bi 
+She 
+Dan 
+Jian 
+Gou 
+Sei 
+Fa 
+Bi 
+Kou 
+Nagi 
+Bie 
+Xiao 
+Dan 
+Kuo 
+Qiang 
+Hong 
+Mi 
+Kuo 
+Wan 
+Jue 
+Ji 
+Ji 
+Gui 
+Dang 
+Lu 
+Lu 
+Tuan 
+Hui 
+Zhi 
+Hui 
+Hui 
+Yi 
+Yi 
+Yi 
+Yi 
+Huo 
+Huo 
+Shan 
+Xing 
+Wen 
+Tong 
+Yan 
+Yan 
+Yu 
+Chi 
+Cai 
+Biao 
+Diao 
+Bin 
+Peng 
+Yong 
+Piao 
+Zhang 
+Ying 
+Chi 
+Chi 
+Zhuo 
+Tuo 
+Ji 
+Pang 
+Zhong 
+Yi 
+Wang 
+Che 
+Bi 
+Chi 
+Ling 
+Fu 
+Wang 
+Zheng 
+Cu 
+Wang 
+Jing 
+Dai 
+Xi 
+Xun 
+Hen 
+Yang 
+Huai 
+Lu 
+Hou 
+Wa 
+Cheng 
+Zhi 
+Xu 
+Jing 
+Tu 
+Cong 
+[?] 
+Lai 
+Cong 
+De 
+Pai 
+Xi 
+[?] 
+Qi 
+Chang 
+Zhi 
+Cong 
+Zhou 
+Lai 
+Yu 
+Xie 
+Jie 
+Jian 
+Chi 
+Jia 
+Bian 
+Huang 
+Fu 
+Xun 
+Wei 
+Pang 
+Yao 
+Wei 
+Xi 
+Zheng 
+Piao 
+Chi 
+De 
+Zheng 
+Zheng 
+Bie 
+De 
+Chong 
+Che 
+Jiao 
+Wei 
+Jiao 
+Hui 
+Mei 
+Long 
+Xiang 
+Bao 
+Qu 
+Xin 
+Shu 
+Bi 
+Yi 
+Le 
+Ren 
+Dao 
+Ding 
+Gai 
+Ji 
+Ren 
+Ren 
+Chan 
+Tan 
+Te 
+Te 
+Gan 
+Qi 
+Shi 
+Cun 
+Zhi 
+Wang 
+Mang 
+Xi 
+Fan 
+Ying 
+Tian 
+Min 
+Min 
+Zhong 
+Chong 
+Wu 
+Ji 
+Wu 
+Xi 
+Ye 
+You 
+Wan 
+Cong 
+Zhong 
+Kuai 
+Yu 
+Bian 
+Zhi 
+Qi 
+Cui 
+Chen 
+Tai 
+Tun 
+Qian 
+Nian 
+Hun 
+Xiong 
+Niu 
+Wang 
+Xian 
+Xin 
+Kang 
+Hu 
+Kai 
+Fen 
+Huai 
+Tai 
+Song 
+Wu 
+Ou 
+Chang 
+Chuang 
+Ju 
+Yi 
+Bao 
+Chao 
+Min 
+Pei 
+Zuo 
+Zen 
+Yang 
+Kou 
+Ban 
+Nu 
+Nao 
+Zheng 
+Pa 
+Bu 
+Tie 
+Gu 
+Hu 
+Ju 
+Da 
+Lian 
+Si 
+Chou 
+Di 
+Dai 
+Yi 
+Tu 
+You 
+Fu 
+Ji 
+Peng 
+Xing 
+Yuan 
+Ni 
+Guai 
+Fu 
+Xi 
+Bi 
+You 
+Qie 
+Xuan 
+Cong 
+Bing 
+Huang 
+Xu 
+Chu 
+Pi 
+Xi 
+Xi 
+Tan 
+Koraeru 
+Zong 
+Dui 
+[?] 
+Ki 
+Yi 
+Chi 
+Ren 
+Xun 
+Shi 
+Xi 
+Lao 
+Heng 
+Kuang 
+Mu 
+Zhi 
+Xie 
+Lian 
+Tiao 
+Huang 
+Die 
+Hao 
+Kong 
+Gui 
+Heng 
+Xi 
+Xiao 
+Shu 
+S 
+Kua 
+Qiu 
+Yang 
+Hui 
+Hui 
+Chi 
+Jia 
+Yi 
+Xiong 
+Guai 
+Lin 
+Hui 
+Zi 
+Xu 
+Chi 
+Xiang 
+Nu 
+Hen 
+En 
+Ke 
+Tong 
+Tian 
+Gong 
+Quan 
+Xi 
+Qia 
+Yue 
+Peng 
+Ken 
+De 
+Hui 
+E 
+Kyuu 
+Tong 
+Yan 
+Kai 
+Ce 
+Nao 
+Yun 
+Mang 
+Yong 
+Yong 
+Yuan 
+Pi 
+Kun 
+Qiao 
+Yue 
+Yu 
+Yu 
+Jie 
+Xi 
+Zhe 
+Lin 
+Ti 
+Han 
+Hao 
+Qie 
+Ti 
+Bu 
+Yi 
+Qian 
+Hui 
+Xi 
+Bei 
+Man 
+Yi 
+Heng 
+Song 
+Quan 
+Cheng 
+Hui 
+Wu 
+Wu 
+You 
+Li 
+Liang 
+Huan 
+Cong 
+Yi 
+Yue 
+Li 
+Nin 
+Nao 
+E 
+Que 
+Xuan 
+Qian 
+Wu 
+Min 
+Cong 
+Fei 
+Bei 
+Duo 
+Cui 
+Chang 
+Men 
+Li 
+Ji 
+Guan 
+Guan 
+Xing 
+Dao 
+Qi 
+Kong 
+Tian 
+Lun 
+Xi 
+Kan 
+Kun 
+Ni 
+Qing 
+Chou 
+Dun 
+Guo 
+Chan 
+Liang 
+Wan 
+Yuan 
+Jin 
+Ji 
+Lin 
+Yu 
+Huo 
+He 
+Quan 
+Tan 
+Ti 
+Ti 
+Nie 
+Wang 
+Chuo 
+Bu 
+Hun 
+Xi 
+Tang 
+Xin 
+Wei 
+Hui 
+E 
+Rui 
+Zong 
+Jian 
+Yong 
+Dian 
+Ju 
+Can 
+Cheng 
+De 
+Bei 
+Qie 
+Can 
+Dan 
+Guan 
+Duo 
+Nao 
+Yun 
+Xiang 
+Zhui 
+Die 
+Huang 
+Chun 
+Qiong 
+Re 
+Xing 
+Ce 
+Bian 
+Hun 
+Zong 
+Ti 
+Qiao 
+Chou 
+Bei 
+Xuan 
+Wei 
+Ge 
+Qian 
+Wei 
+Yu 
+Yu 
+Bi 
+Xuan 
+Huan 
+Min 
+Bi 
+Yi 
+Mian 
+Yong 
+Kai 
+Dang 
+Yin 
+E 
+Chen 
+Mou 
+Ke 
+Ke 
+Yu 
+Ai 
+Qie 
+Yan 
+Nuo 
+Gan 
+Yun 
+Zong 
+Sai 
+Leng 
+Fen 
+[?] 
+Kui 
+Kui 
+Que 
+Gong 
+Yun 
+Su 
+Su 
+Qi 
+Yao 
+Song 
+Huang 
+Ji 
+Gu 
+Ju 
+Chuang 
+Ni 
+Xie 
+Kai 
+Zheng 
+Yong 
+Cao 
+Sun 
+Shen 
+Bo 
+Kai 
+Yuan 
+Xie 
+Hun 
+Yong 
+Yang 
+Li 
+Sao 
+Tao 
+Yin 
+Ci 
+Xu 
+Qian 
+Tai 
+Huang 
+Yun 
+Shen 
+Ming 
+[?] 
+She 
+Cong 
+Piao 
+Mo 
+Mu 
+Guo 
+Chi 
+Can 
+Can 
+Can 
+Cui 
+Min 
+Te 
+Zhang 
+Tong 
+Ao 
+Shuang 
+Man 
+Guan 
+Que 
+Zao 
+Jiu 
+Hui 
+Kai 
+Lian 
+Ou 
+Song 
+Jin 
+Yin 
+Lu 
+Shang 
+Wei 
+Tuan 
+Man 
+Qian 
+She 
+Yong 
+Qing 
+Kang 
+Di 
+Zhi 
+Lou 
+Juan 
+Qi 
+Qi 
+Yu 
+Ping 
+Liao 
+Cong 
+You 
+Chong 
+Zhi 
+Tong 
+Cheng 
+Qi 
+Qu 
+Peng 
+Bei 
+Bie 
+Chun 
+Jiao 
+Zeng 
+Chi 
+Lian 
+Ping 
+Kui 
+Hui 
+Qiao 
+Cheng 
+Yin 
+Yin 
+Xi 
+Xi 
+Dan 
+Tan 
+Duo 
+Dui 
+Dui 
+Su 
+Jue 
+Ce 
+Xiao 
+Fan 
+Fen 
+Lao 
+Lao 
+Chong 
+Han 
+Qi 
+Xian 
+Min 
+Jing 
+Liao 
+Wu 
+Can 
+Jue 
+Cu 
+Xian 
+Tan 
+Sheng 
+Pi 
+Yi 
+Chu 
+Xian 
+Nao 
+Dan 
+Tan 
+Jing 
+Song 
+Han 
+Jiao 
+Wai 
+Huan 
+Dong 
+Qin 
+Qin 
+Qu 
+Cao 
+Ken 
+Xie 
+Ying 
+Ao 
+Mao 
+Yi 
+Lin 
+Se 
+Jun 
+Huai 
+Men 
+Lan 
+Ai 
+Lin 
+Yan 
+Gua 
+Xia 
+Chi 
+Yu 
+Yin 
+Dai 
+Meng 
+Ai 
+Meng 
+Dui 
+Qi 
+Mo 
+Lan 
+Men 
+Chou 
+Zhi 
+Nuo 
+Nuo 
+Yan 
+Yang 
+Bo 
+Zhi 
+Kuang 
+Kuang 
+You 
+Fu 
+Liu 
+Mie 
+Cheng 
+[?] 
+Chan 
+Meng 
+Lan 
+Huai 
+Xuan 
+Rang 
+Chan 
+Ji 
+Ju 
+Huan 
+She 
+Yi 
+Lian 
+Nan 
+Mi 
+Tang 
+Jue 
+Gang 
+Gang 
+Gang 
+Ge 
+Yue 
+Wu 
+Jian 
+Xu 
+Shu 
+Rong 
+Xi 
+Cheng 
+Wo 
+Jie 
+Ge 
+Jian 
+Qiang 
+Huo 
+Qiang 
+Zhan 
+Dong 
+Qi 
+Jia 
+Die 
+Zei 
+Jia 
+Ji 
+Shi 
+Kan 
+Ji 
+Kui 
+Gai 
+Deng 
+Zhan 
+Chuang 
+Ge 
+Jian 
+Jie 
+Yu 
+Jian 
+Yan 
+Lu 
+Xi 
+Zhan 
+Xi 
+Xi 
+Chuo 
+Dai 
+Qu 
+Hu 
+Hu 
+Hu 
+E 
+Shi 
+Li 
+Mao 
+Hu 
+Li 
+Fang 
+Suo 
+Bian 
+Dian 
+Jiong 
+Shang 
+Yi 
+Yi 
+Shan 
+Hu 
+Fei 
+Yan 
+Shou 
+T 
+Cai 
+Zha 
+Qiu 
+Le 
+Bu 
+Ba 
+Da 
+Reng 
+Fu 
+Hameru 
+Zai 
+Tuo 
+Zhang 
+Diao 
+Kang 
+Yu 
+Ku 
+Han 
+Shen 
+Cha 
+Yi 
+Gu 
+Kou 
+Wu 
+Tuo 
+Qian 
+Zhi 
+Ren 
+Kuo 
+Men 
+Sao 
+Yang 
+Niu 
+Ban 
+Che 
+Rao 
+Xi 
+Qian 
+Ban 
+Jia 
+Yu 
+Fu 
+Ao 
+Xi 
+Pi 
+Zhi 
+Zi 
+E 
+Dun 
+Zhao 
+Cheng 
+Ji 
+Yan 
+Kuang 
+Bian 
+Chao 
+Ju 
+Wen 
+Hu 
+Yue 
+Jue 
+Ba 
+Qin 
+Zhen 
+Zheng 
+Yun 
+Wan 
+Nu 
+Yi 
+Shu 
+Zhua 
+Pou 
+Tou 
+Dou 
+Kang 
+Zhe 
+Pou 
+Fu 
+Pao 
+Ba 
+Ao 
+Ze 
+Tuan 
+Kou 
+Lun 
+Qiang 
+[?] 
+Hu 
+Bao 
+Bing 
+Zhi 
+Peng 
+Tan 
+Pu 
+Pi 
+Tai 
+Yao 
+Zhen 
+Zha 
+Yang 
+Bao 
+He 
+Ni 
+Yi 
+Di 
+Chi 
+Pi 
+Za 
+Mo 
+Mo 
+Shen 
+Ya 
+Chou 
+Qu 
+Min 
+Chu 
+Jia 
+Fu 
+Zhan 
+Zhu 
+Dan 
+Chai 
+Mu 
+Nian 
+La 
+Fu 
+Pao 
+Ban 
+Pai 
+Ling 
+Na 
+Guai 
+Qian 
+Ju 
+Tuo 
+Ba 
+Tuo 
+Tuo 
+Ao 
+Ju 
+Zhuo 
+Pan 
+Zhao 
+Bai 
+Bai 
+Di 
+Ni 
+Ju 
+Kuo 
+Long 
+Jian 
+[?] 
+Yong 
+Lan 
+Ning 
+Bo 
+Ze 
+Qian 
+Hen 
+Gua 
+Shi 
+Jie 
+Zheng 
+Nin 
+Gong 
+Gong 
+Quan 
+Shuan 
+Cun 
+Zan 
+Kao 
+Chi 
+Xie 
+Ce 
+Hui 
+Pin 
+Zhuai 
+Shi 
+Na 
+Bo 
+Chi 
+Gua 
+Zhi 
+Kuo 
+Duo 
+Duo 
+Zhi 
+Qie 
+An 
+Nong 
+Zhen 
+Ge 
+Jiao 
+Ku 
+Dong 
+Ru 
+Tiao 
+Lie 
+Zha 
+Lu 
+Die 
+Wa 
+Jue 
+Mushiru 
+Ju 
+Zhi 
+Luan 
+Ya 
+Zhua 
+Ta 
+Xie 
+Nao 
+Dang 
+Jiao 
+Zheng 
+Ji 
+Hui 
+Xun 
+Ku 
+Ai 
+Tuo 
+Nuo 
+Cuo 
+Bo 
+Geng 
+Ti 
+Zhen 
+Cheng 
+Suo 
+Suo 
+Keng 
+Mei 
+Long 
+Ju 
+Peng 
+Jian 
+Yi 
+Ting 
+Shan 
+Nuo 
+Wan 
+Xie 
+Cha 
+Feng 
+Jiao 
+Wu 
+Jun 
+Jiu 
+Tong 
+Kun 
+Huo 
+Tu 
+Zhuo 
+Pou 
+Le 
+Ba 
+Han 
+Shao 
+Nie 
+Juan 
+Ze 
+Song 
+Ye 
+Jue 
+Bu 
+Huan 
+Bu 
+Zun 
+Yi 
+Zhai 
+Lu 
+Sou 
+Tuo 
+Lao 
+Sun 
+Bang 
+Jian 
+Huan 
+Dao 
+[?] 
+Wan 
+Qin 
+Peng 
+She 
+Lie 
+Min 
+Men 
+Fu 
+Bai 
+Ju 
+Dao 
+Wo 
+Ai 
+Juan 
+Yue 
+Zong 
+Chen 
+Chui 
+Jie 
+Tu 
+Ben 
+Na 
+Nian 
+Nuo 
+Zu 
+Wo 
+Xi 
+Xian 
+Cheng 
+Dian 
+Sao 
+Lun 
+Qing 
+Gang 
+Duo 
+Shou 
+Diao 
+Pou 
+Di 
+Zhang 
+Gun 
+Ji 
+Tao 
+Qia 
+Qi 
+Pai 
+Shu 
+Qian 
+Ling 
+Yi 
+Ya 
+Jue 
+Zheng 
+Liang 
+Gua 
+Yi 
+Huo 
+Shan 
+Zheng 
+Lue 
+Cai 
+Tan 
+Che 
+Bing 
+Jie 
+Ti 
+Kong 
+Tui 
+Yan 
+Cuo 
+Zou 
+Ju 
+Tian 
+Qian 
+Ken 
+Bai 
+Shou 
+Jie 
+Lu 
+Guo 
+Haba 
+[?] 
+Zhi 
+Dan 
+Mang 
+Xian 
+Sao 
+Guan 
+Peng 
+Yuan 
+Nuo 
+Jian 
+Zhen 
+Jiu 
+Jian 
+Yu 
+Yan 
+Kui 
+Nan 
+Hong 
+Rou 
+Pi 
+Wei 
+Sai 
+Zou 
+Xuan 
+Miao 
+Ti 
+Nie 
+Cha 
+Shi 
+Zong 
+Zhen 
+Yi 
+Shun 
+Heng 
+Bian 
+Yang 
+Huan 
+Yan 
+Zuan 
+An 
+Xu 
+Ya 
+Wo 
+Ke 
+Chuai 
+Ji 
+Ti 
+La 
+La 
+Cheng 
+Kai 
+Jiu 
+Jiu 
+Tu 
+Jie 
+Hui 
+Geng 
+Chong 
+Shuo 
+She 
+Xie 
+Yuan 
+Qian 
+Ye 
+Cha 
+Zha 
+Bei 
+Yao 
+[?] 
+[?] 
+Lan 
+Wen 
+Qin 
+Chan 
+Ge 
+Lou 
+Zong 
+Geng 
+Jiao 
+Gou 
+Qin 
+Yong 
+Que 
+Chou 
+Chi 
+Zhan 
+Sun 
+Sun 
+Bo 
+Chu 
+Rong 
+Beng 
+Cuo 
+Sao 
+Ke 
+Yao 
+Dao 
+Zhi 
+Nu 
+Xie 
+Jian 
+Sou 
+Qiu 
+Gao 
+Xian 
+Shuo 
+Sang 
+Jin 
+Mie 
+E 
+Chui 
+Nuo 
+Shan 
+Ta 
+Jie 
+Tang 
+Pan 
+Ban 
+Da 
+Li 
+Tao 
+Hu 
+Zhi 
+Wa 
+Xia 
+Qian 
+Wen 
+Qiang 
+Tian 
+Zhen 
+E 
+Xi 
+Nuo 
+Quan 
+Cha 
+Zha 
+Ge 
+Wu 
+En 
+She 
+Kang 
+She 
+Shu 
+Bai 
+Yao 
+Bin 
+Sou 
+Tan 
+Sa 
+Chan 
+Suo 
+Liao 
+Chong 
+Chuang 
+Guo 
+Bing 
+Feng 
+Shuai 
+Di 
+Qi 
+Sou 
+Zhai 
+Lian 
+Tang 
+Chi 
+Guan 
+Lu 
+Luo 
+Lou 
+Zong 
+Gai 
+Hu 
+Zha 
+Chuang 
+Tang 
+Hua 
+Cui 
+Nai 
+Mo 
+Jiang 
+Gui 
+Ying 
+Zhi 
+Ao 
+Zhi 
+Nie 
+Man 
+Shan 
+Kou 
+Shu 
+Suo 
+Tuan 
+Jiao 
+Mo 
+Mo 
+Zhe 
+Xian 
+Keng 
+Piao 
+Jiang 
+Yin 
+Gou 
+Qian 
+Lue 
+Ji 
+Ying 
+Jue 
+Pie 
+Pie 
+Lao 
+Dun 
+Xian 
+Ruan 
+Kui 
+Zan 
+Yi 
+Xun 
+Cheng 
+Cheng 
+Sa 
+Nao 
+Heng 
+Si 
+Qian 
+Huang 
+Da 
+Zun 
+Nian 
+Lin 
+Zheng 
+Hui 
+Zhuang 
+Jiao 
+Ji 
+Cao 
+Dan 
+Dan 
+Che 
+Bo 
+Che 
+Jue 
+Xiao 
+Liao 
+Ben 
+Fu 
+Qiao 
+Bo 
+Cuo 
+Zhuo 
+Zhuan 
+Tuo 
+Pu 
+Qin 
+Dun 
+Nian 
+[?] 
+Xie 
+Lu 
+Jiao 
+Cuan 
+Ta 
+Han 
+Qiao 
+Zhua 
+Jian 
+Gan 
+Yong 
+Lei 
+Kuo 
+Lu 
+Shan 
+Zhuo 
+Ze 
+Pu 
+Chuo 
+Ji 
+Dang 
+Suo 
+Cao 
+Qing 
+Jing 
+Huan 
+Jie 
+Qin 
+Kuai 
+Dan 
+Xi 
+Ge 
+Pi 
+Bo 
+Ao 
+Ju 
+Ye 
+[?] 
+Mang 
+Sou 
+Mi 
+Ji 
+Tai 
+Zhuo 
+Dao 
+Xing 
+Lan 
+Ca 
+Ju 
+Ye 
+Ru 
+Ye 
+Ye 
+Ni 
+Hu 
+Ji 
+Bin 
+Ning 
+Ge 
+Zhi 
+Jie 
+Kuo 
+Mo 
+Jian 
+Xie 
+Lie 
+Tan 
+Bai 
+Sou 
+Lu 
+Lue 
+Rao 
+Zhi 
+Pan 
+Yang 
+Lei 
+Sa 
+Shu 
+Zan 
+Nian 
+Xian 
+Jun 
+Huo 
+Li 
+La 
+Han 
+Ying 
+Lu 
+Long 
+Qian 
+Qian 
+Zan 
+Qian 
+Lan 
+San 
+Ying 
+Mei 
+Rang 
+Chan 
+[?] 
+Cuan 
+Xi 
+She 
+Luo 
+Jun 
+Mi 
+Li 
+Zan 
+Luan 
+Tan 
+Zuan 
+Li 
+Dian 
+Wa 
+Dang 
+Jiao 
+Jue 
+Lan 
+Li 
+Nang 
+Zhi 
+Gui 
+Gui 
+Qi 
+Xin 
+Pu 
+Sui 
+Shou 
+Kao 
+You 
+Gai 
+Yi 
+Gong 
+Gan 
+Ban 
+Fang 
+Zheng 
+Bo 
+Dian 
+Kou 
+Min 
+Wu 
+Gu 
+He 
+Ce 
+Xiao 
+Mi 
+Chu 
+Ge 
+Di 
+Xu 
+Jiao 
+Min 
+Chen 
+Jiu 
+Zhen 
+Duo 
+Yu 
+Chi 
+Ao 
+Bai 
+Xu 
+Jiao 
+Duo 
+Lian 
+Nie 
+Bi 
+Chang 
+Dian 
+Duo 
+Yi 
+Gan 
+San 
+Ke 
+Yan 
+Dun 
+Qi 
+Dou 
+Xiao 
+Duo 
+Jiao 
+Jing 
+Yang 
+Xia 
+Min 
+Shu 
+Ai 
+Qiao 
+Ai 
+Zheng 
+Di 
+Zhen 
+Fu 
+Shu 
+Liao 
+Qu 
+Xiong 
+Xi 
+Jiao 
+Sen 
+Jiao 
+Zhuo 
+Yi 
+Lian 
+Bi 
+Li 
+Xiao 
+Xiao 
+Wen 
+Xue 
+Qi 
+Qi 
+Zhai 
+Bin 
+Jue 
+Zhai 
+[?] 
+Fei 
+Ban 
+Ban 
+Lan 
+Yu 
+Lan 
+Wei 
+Dou 
+Sheng 
+Liao 
+Jia 
+Hu 
+Xie 
+Jia 
+Yu 
+Zhen 
+Jiao 
+Wo 
+Tou 
+Chu 
+Jin 
+Chi 
+Yin 
+Fu 
+Qiang 
+Zhan 
+Qu 
+Zhuo 
+Zhan 
+Duan 
+Zhuo 
+Si 
+Xin 
+Zhuo 
+Zhuo 
+Qin 
+Lin 
+Zhuo 
+Chu 
+Duan 
+Zhu 
+Fang 
+Xie 
+Hang 
+Yu 
+Shi 
+Pei 
+You 
+Mye 
+Pang 
+Qi 
+Zhan 
+Mao 
+Lu 
+Pei 
+Pi 
+Liu 
+Fu 
+Fang 
+Xuan 
+Jing 
+Jing 
+Ni 
+Zu 
+Zhao 
+Yi 
+Liu 
+Shao 
+Jian 
+Es 
+Yi 
+Qi 
+Zhi 
+Fan 
+Piao 
+Fan 
+Zhan 
+Guai 
+Sui 
+Yu 
+Wu 
+Ji 
+Ji 
+Ji 
+Huo 
+Ri 
+Dan 
+Jiu 
+Zhi 
+Zao 
+Xie 
+Tiao 
+Xun 
+Xu 
+Xu 
+Xu 
+Gan 
+Han 
+Tai 
+Di 
+Xu 
+Chan 
+Shi 
+Kuang 
+Yang 
+Shi 
+Wang 
+Min 
+Min 
+Tun 
+Chun 
+Wu 
+Yun 
+Bei 
+Ang 
+Ze 
+Ban 
+Jie 
+Kun 
+Sheng 
+Hu 
+Fang 
+Hao 
+Gui 
+Chang 
+Xuan 
+Ming 
+Hun 
+Fen 
+Qin 
+Hu 
+Yi 
+Xi 
+Xin 
+Yan 
+Ze 
+Fang 
+Tan 
+Shen 
+Ju 
+Yang 
+Zan 
+Bing 
+Xing 
+Ying 
+Xuan 
+Pei 
+Zhen 
+Ling 
+Chun 
+Hao 
+Mei 
+Zuo 
+Mo 
+Bian 
+Xu 
+Hun 
+Zhao 
+Zong 
+Shi 
+Shi 
+Yu 
+Fei 
+Die 
+Mao 
+Ni 
+Chang 
+Wen 
+Dong 
+Ai 
+Bing 
+Ang 
+Zhou 
+Long 
+Xian 
+Kuang 
+Tiao 
+Chao 
+Shi 
+Huang 
+Huang 
+Xuan 
+Kui 
+Xu 
+Jiao 
+Jin 
+Zhi 
+Jin 
+Shang 
+Tong 
+Hong 
+Yan 
+Gai 
+Xiang 
+Shai 
+Xiao 
+Ye 
+Yun 
+Hui 
+Han 
+Han 
+Jun 
+Wan 
+Xian 
+Kun 
+Zhou 
+Xi 
+Cheng 
+Sheng 
+Bu 
+Zhe 
+Zhe 
+Wu 
+Han 
+Hui 
+Hao 
+Chen 
+Wan 
+Tian 
+Zhuo 
+Zui 
+Zhou 
+Pu 
+Jing 
+Xi 
+Shan 
+Yi 
+Xi 
+Qing 
+Qi 
+Jing 
+Gui 
+Zhen 
+Yi 
+Zhi 
+An 
+Wan 
+Lin 
+Liang 
+Chang 
+Wang 
+Xiao 
+Zan 
+Hi 
+Xuan 
+Xuan 
+Yi 
+Xia 
+Yun 
+Hui 
+Fu 
+Min 
+Kui 
+He 
+Ying 
+Du 
+Wei 
+Shu 
+Qing 
+Mao 
+Nan 
+Jian 
+Nuan 
+An 
+Yang 
+Chun 
+Yao 
+Suo 
+Jin 
+Ming 
+Jiao 
+Kai 
+Gao 
+Weng 
+Chang 
+Qi 
+Hao 
+Yan 
+Li 
+Ai 
+Ji 
+Gui 
+Men 
+Zan 
+Xie 
+Hao 
+Mu 
+Mo 
+Cong 
+Ni 
+Zhang 
+Hui 
+Bao 
+Han 
+Xuan 
+Chuan 
+Liao 
+Xian 
+Dan 
+Jing 
+Pie 
+Lin 
+Tun 
+Xi 
+Yi 
+Ji 
+Huang 
+Tai 
+Ye 
+Ye 
+Li 
+Tan 
+Tong 
+Xiao 
+Fei 
+Qin 
+Zhao 
+Hao 
+Yi 
+Xiang 
+Xing 
+Sen 
+Jiao 
+Bao 
+Jing 
+Yian 
+Ai 
+Ye 
+Ru 
+Shu 
+Meng 
+Xun 
+Yao 
+Pu 
+Li 
+Chen 
+Kuang 
+Die 
+[?] 
+Yan 
+Huo 
+Lu 
+Xi 
+Rong 
+Long 
+Nang 
+Luo 
+Luan 
+Shai 
+Tang 
+Yan 
+Chu 
+Yue 
+Yue 
+Qu 
+Yi 
+Geng 
+Ye 
+Hu 
+He 
+Shu 
+Cao 
+Cao 
+Noboru 
+Man 
+Ceng 
+Ceng 
+Ti 
+Zui 
+Can 
+Xu 
+Hui 
+Yin 
+Qie 
+Fen 
+Pi 
+Yue 
+You 
+Ruan 
+Peng 
+Ban 
+Fu 
+Ling 
+Fei 
+Qu 
+[?] 
+Nu 
+Tiao 
+Shuo 
+Zhen 
+Lang 
+Lang 
+Juan 
+Ming 
+Huang 
+Wang 
+Tun 
+Zhao 
+Ji 
+Qi 
+Ying 
+Zong 
+Wang 
+Tong 
+Lang 
+[?] 
+Meng 
+Long 
+Mu 
+Deng 
+Wei 
+Mo 
+Ben 
+Zha 
+Zhu 
+Zhu 
+[?] 
+Zhu 
+Ren 
+Ba 
+Po 
+Duo 
+Duo 
+Dao 
+Li 
+Qiu 
+Ji 
+Jiu 
+Bi 
+Xiu 
+Ting 
+Ci 
+Sha 
+Eburi 
+Za 
+Quan 
+Qian 
+Yu 
+Gan 
+Wu 
+Cha 
+Shan 
+Xun 
+Fan 
+Wu 
+Zi 
+Li 
+Xing 
+Cai 
+Cun 
+Ren 
+Shao 
+Tuo 
+Di 
+Zhang 
+Mang 
+Chi 
+Yi 
+Gu 
+Gong 
+Du 
+Yi 
+Qi 
+Shu 
+Gang 
+Tiao 
+Moku 
+Soma 
+Tochi 
+Lai 
+Sugi 
+Mang 
+Yang 
+Ma 
+Miao 
+Si 
+Yuan 
+Hang 
+Fei 
+Bei 
+Jie 
+Dong 
+Gao 
+Yao 
+Xian 
+Chu 
+Qun 
+Pa 
+Shu 
+Hua 
+Xin 
+Chou 
+Zhu 
+Chou 
+Song 
+Ban 
+Song 
+Ji 
+Yue 
+Jin 
+Gou 
+Ji 
+Mao 
+Pi 
+Bi 
+Wang 
+Ang 
+Fang 
+Fen 
+Yi 
+Fu 
+Nan 
+Xi 
+Hu 
+Ya 
+Dou 
+Xun 
+Zhen 
+Yao 
+Lin 
+Rui 
+E 
+Mei 
+Zhao 
+Guo 
+Zhi 
+Cong 
+Yun 
+Waku 
+Dou 
+Shu 
+Zao 
+[?] 
+Li 
+Haze 
+Jian 
+Cheng 
+Matsu 
+Qiang 
+Feng 
+Nan 
+Xiao 
+Xian 
+Ku 
+Ping 
+Yi 
+Xi 
+Zhi 
+Guai 
+Xiao 
+Jia 
+Jia 
+Gou 
+Fu 
+Mo 
+Yi 
+Ye 
+Ye 
+Shi 
+Nie 
+Bi 
+Duo 
+Yi 
+Ling 
+Bing 
+Ni 
+La 
+He 
+Pan 
+Fan 
+Zhong 
+Dai 
+Ci 
+Yang 
+Fu 
+Bo 
+Mou 
+Gan 
+Qi 
+Ran 
+Rou 
+Mao 
+Zhao 
+Song 
+Zhe 
+Xia 
+You 
+Shen 
+Ju 
+Tuo 
+Zuo 
+Nan 
+Ning 
+Yong 
+Di 
+Zhi 
+Zha 
+Cha 
+Dan 
+Gu 
+Pu 
+Jiu 
+Ao 
+Fu 
+Jian 
+Bo 
+Duo 
+Ke 
+Nai 
+Zhu 
+Bi 
+Liu 
+Chai 
+Zha 
+Si 
+Zhu 
+Pei 
+Shi 
+Guai 
+Cha 
+Yao 
+Jue 
+Jiu 
+Shi 
+Zhi 
+Liu 
+Mei 
+Hoy 
+Rong 
+Zha 
+[?] 
+Biao 
+Zhan 
+Jie 
+Long 
+Dong 
+Lu 
+Sayng 
+Li 
+Lan 
+Yong 
+Shu 
+Xun 
+Shuan 
+Qi 
+Zhen 
+Qi 
+Li 
+Yi 
+Xiang 
+Zhen 
+Li 
+Su 
+Gua 
+Kan 
+Bing 
+Ren 
+Xiao 
+Bo 
+Ren 
+Bing 
+Zi 
+Chou 
+Yi 
+Jie 
+Xu 
+Zhu 
+Jian 
+Zui 
+Er 
+Er 
+You 
+Fa 
+Gong 
+Kao 
+Lao 
+Zhan 
+Li 
+Yin 
+Yang 
+He 
+Gen 
+Zhi 
+Chi 
+Ge 
+Zai 
+Luan 
+Fu 
+Jie 
+Hang 
+Gui 
+Tao 
+Guang 
+Wei 
+Kuang 
+Ru 
+An 
+An 
+Juan 
+Yi 
+Zhuo 
+Ku 
+Zhi 
+Qiong 
+Tong 
+Sang 
+Sang 
+Huan 
+Jie 
+Jiu 
+Xue 
+Duo 
+Zhui 
+Yu 
+Zan 
+Kasei 
+Ying 
+Masu 
+[?] 
+Zhan 
+Ya 
+Nao 
+Zhen 
+Dang 
+Qi 
+Qiao 
+Hua 
+Kuai 
+Jiang 
+Zhuang 
+Xun 
+Suo 
+Sha 
+Zhen 
+Bei 
+Ting 
+Gua 
+Jing 
+Bo 
+Ben 
+Fu 
+Rui 
+Tong 
+Jue 
+Xi 
+Lang 
+Liu 
+Feng 
+Qi 
+Wen 
+Jun 
+Gan 
+Cu 
+Liang 
+Qiu 
+Ting 
+You 
+Mei 
+Bang 
+Long 
+Peng 
+Zhuang 
+Di 
+Xuan 
+Tu 
+Zao 
+Ao 
+Gu 
+Bi 
+Di 
+Han 
+Zi 
+Zhi 
+Ren 
+Bei 
+Geng 
+Jian 
+Huan 
+Wan 
+Nuo 
+Jia 
+Tiao 
+Ji 
+Xiao 
+Lu 
+Huan 
+Shao 
+Cen 
+Fen 
+Song 
+Meng 
+Wu 
+Li 
+Li 
+Dou 
+Cen 
+Ying 
+Suo 
+Ju 
+Ti 
+Jie 
+Kun 
+Zhuo 
+Shu 
+Chan 
+Fan 
+Wei 
+Jing 
+Li 
+Bing 
+Fumoto 
+Shikimi 
+Tao 
+Zhi 
+Lai 
+Lian 
+Jian 
+Zhuo 
+Ling 
+Li 
+Qi 
+Bing 
+Zhun 
+Cong 
+Qian 
+Mian 
+Qi 
+Qi 
+Cai 
+Gun 
+Chan 
+Te 
+Fei 
+Pai 
+Bang 
+Pou 
+Hun 
+Zong 
+Cheng 
+Zao 
+Ji 
+Li 
+Peng 
+Yu 
+Yu 
+Gu 
+Hun 
+Dong 
+Tang 
+Gang 
+Wang 
+Di 
+Xi 
+Fan 
+Cheng 
+Zhan 
+Qi 
+Yuan 
+Yan 
+Yu 
+Quan 
+Yi 
+Sen 
+Ren 
+Chui 
+Leng 
+Qi 
+Zhuo 
+Fu 
+Ke 
+Lai 
+Zou 
+Zou 
+Zhuo 
+Guan 
+Fen 
+Fen 
+Chen 
+Qiong 
+Nie 
+Wan 
+Guo 
+Lu 
+Hao 
+Jie 
+Yi 
+Chou 
+Ju 
+Ju 
+Cheng 
+Zuo 
+Liang 
+Qiang 
+Zhi 
+Zhui 
+Ya 
+Ju 
+Bei 
+Jiao 
+Zhuo 
+Zi 
+Bin 
+Peng 
+Ding 
+Chu 
+Chang 
+Kunugi 
+Momiji 
+Jian 
+Gui 
+Xi 
+Du 
+Qian 
+Kunugi 
+Soko 
+Shide 
+Luo 
+Zhi 
+Ken 
+Myeng 
+Tafu 
+[?] 
+Peng 
+Zhan 
+[?] 
+Tuo 
+Sen 
+Duo 
+Ye 
+Fou 
+Wei 
+Wei 
+Duan 
+Jia 
+Zong 
+Jian 
+Yi 
+Shen 
+Xi 
+Yan 
+Yan 
+Chuan 
+Zhan 
+Chun 
+Yu 
+He 
+Zha 
+Wo 
+Pian 
+Bi 
+Yao 
+Huo 
+Xu 
+Ruo 
+Yang 
+La 
+Yan 
+Ben 
+Hun 
+Kui 
+Jie 
+Kui 
+Si 
+Feng 
+Xie 
+Tuo 
+Zhi 
+Jian 
+Mu 
+Mao 
+Chu 
+Hu 
+Hu 
+Lian 
+Leng 
+Ting 
+Nan 
+Yu 
+You 
+Mei 
+Song 
+Xuan 
+Xuan 
+Ying 
+Zhen 
+Pian 
+Ye 
+Ji 
+Jie 
+Ye 
+Chu 
+Shun 
+Yu 
+Cou 
+Wei 
+Mei 
+Di 
+Ji 
+Jie 
+Kai 
+Qiu 
+Ying 
+Rou 
+Heng 
+Lou 
+Le 
+Hazou 
+Katsura 
+Pin 
+Muro 
+Gai 
+Tan 
+Lan 
+Yun 
+Yu 
+Chen 
+Lu 
+Ju 
+Sakaki 
+[?] 
+Pi 
+Xie 
+Jia 
+Yi 
+Zhan 
+Fu 
+Nai 
+Mi 
+Lang 
+Rong 
+Gu 
+Jian 
+Ju 
+Ta 
+Yao 
+Zhen 
+Bang 
+Sha 
+Yuan 
+Zi 
+Ming 
+Su 
+Jia 
+Yao 
+Jie 
+Huang 
+Gan 
+Fei 
+Zha 
+Qian 
+Ma 
+Sun 
+Yuan 
+Xie 
+Rong 
+Shi 
+Zhi 
+Cui 
+Yun 
+Ting 
+Liu 
+Rong 
+Tang 
+Que 
+Zhai 
+Si 
+Sheng 
+Ta 
+Ke 
+Xi 
+Gu 
+Qi 
+Kao 
+Gao 
+Sun 
+Pan 
+Tao 
+Ge 
+Xun 
+Dian 
+Nou 
+Ji 
+Shuo 
+Gou 
+Chui 
+Qiang 
+Cha 
+Qian 
+Huai 
+Mei 
+Xu 
+Gang 
+Gao 
+Zhuo 
+Tuo 
+Hashi 
+Yang 
+Dian 
+Jia 
+Jian 
+Zui 
+Kashi 
+Ori 
+Bin 
+Zhu 
+[?] 
+Xi 
+Qi 
+Lian 
+Hui 
+Yong 
+Qian 
+Guo 
+Gai 
+Gai 
+Tuan 
+Hua 
+Cu 
+Sen 
+Cui 
+Beng 
+You 
+Hu 
+Jiang 
+Hu 
+Huan 
+Kui 
+Yi 
+Nie 
+Gao 
+Kang 
+Gui 
+Gui 
+Cao 
+Man 
+Jin 
+Di 
+Zhuang 
+Le 
+Lang 
+Chen 
+Cong 
+Li 
+Xiu 
+Qing 
+Shuang 
+Fan 
+Tong 
+Guan 
+Ji 
+Suo 
+Lei 
+Lu 
+Liang 
+Mi 
+Lou 
+Chao 
+Su 
+Ke 
+Shu 
+Tang 
+Biao 
+Lu 
+Jiu 
+Shu 
+Zha 
+Shu 
+Zhang 
+Men 
+Mo 
+Niao 
+Yang 
+Tiao 
+Peng 
+Zhu 
+Sha 
+Xi 
+Quan 
+Heng 
+Jian 
+Cong 
+[?] 
+Hokuso 
+Qiang 
+Tara 
+Ying 
+Er 
+Xin 
+Zhi 
+Qiao 
+Zui 
+Cong 
+Pu 
+Shu 
+Hua 
+Kui 
+Zhen 
+Zun 
+Yue 
+Zhan 
+Xi 
+Xun 
+Dian 
+Fa 
+Gan 
+Mo 
+Wu 
+Qiao 
+Nao 
+Lin 
+Liu 
+Qiao 
+Xian 
+Run 
+Fan 
+Zhan 
+Tuo 
+Lao 
+Yun 
+Shun 
+Tui 
+Cheng 
+Tang 
+Meng 
+Ju 
+Cheng 
+Su 
+Jue 
+Jue 
+Tan 
+Hui 
+Ji 
+Nuo 
+Xiang 
+Tuo 
+Ning 
+Rui 
+Zhu 
+Chuang 
+Zeng 
+Fen 
+Qiong 
+Ran 
+Heng 
+Cen 
+Gu 
+Liu 
+Lao 
+Gao 
+Chu 
+Zusa 
+Nude 
+Ca 
+San 
+Ji 
+Dou 
+Shou 
+Lu 
+[?] 
+[?] 
+Yuan 
+Ta 
+Shu 
+Jiang 
+Tan 
+Lin 
+Nong 
+Yin 
+Xi 
+Sui 
+Shan 
+Zui 
+Xuan 
+Cheng 
+Gan 
+Ju 
+Zui 
+Yi 
+Qin 
+Pu 
+Yan 
+Lei 
+Feng 
+Hui 
+Dang 
+Ji 
+Sui 
+Bo 
+Bi 
+Ding 
+Chu 
+Zhua 
+Kuai 
+Ji 
+Jie 
+Jia 
+Qing 
+Zhe 
+Jian 
+Qiang 
+Dao 
+Yi 
+Biao 
+Song 
+She 
+Lin 
+Kunugi 
+Cha 
+Meng 
+Yin 
+Tao 
+Tai 
+Mian 
+Qi 
+Toan 
+Bin 
+Huo 
+Ji 
+Qian 
+Mi 
+Ning 
+Yi 
+Gao 
+Jian 
+Yin 
+Er 
+Qing 
+Yan 
+Qi 
+Mi 
+Zhao 
+Gui 
+Chun 
+Ji 
+Kui 
+Po 
+Deng 
+Chu 
+[?] 
+Mian 
+You 
+Zhi 
+Guang 
+Qian 
+Lei 
+Lei 
+Sa 
+Lu 
+Li 
+Cuan 
+Lu 
+Mie 
+Hui 
+Ou 
+Lu 
+Jie 
+Gao 
+Du 
+Yuan 
+Li 
+Fei 
+Zhuo 
+Sou 
+Lian 
+Tamo 
+Chu 
+[?] 
+Zhu 
+Lu 
+Yan 
+Li 
+Zhu 
+Chen 
+Jie 
+E 
+Su 
+Huai 
+Nie 
+Yu 
+Long 
+Lai 
+[?] 
+Xian 
+Kwi 
+Ju 
+Xiao 
+Ling 
+Ying 
+Jian 
+Yin 
+You 
+Ying 
+Xiang 
+Nong 
+Bo 
+Chan 
+Lan 
+Ju 
+Shuang 
+She 
+Wei 
+Cong 
+Quan 
+Qu 
+Cang 
+[?] 
+Yu 
+Luo 
+Li 
+Zan 
+Luan 
+Dang 
+Jue 
+Em 
+Lan 
+Lan 
+Zhu 
+Lei 
+Li 
+Ba 
+Nang 
+Yu 
+Ling 
+Tsuki 
+Qian 
+Ci 
+Huan 
+Xin 
+Yu 
+Yu 
+Qian 
+Ou 
+Xu 
+Chao 
+Chu 
+Chi 
+Kai 
+Yi 
+Jue 
+Xi 
+Xu 
+Xia 
+Yu 
+Kuai 
+Lang 
+Kuan 
+Shuo 
+Xi 
+Ai 
+Yi 
+Qi 
+Hu 
+Chi 
+Qin 
+Kuan 
+Kan 
+Kuan 
+Kan 
+Chuan 
+Sha 
+Gua 
+Yin 
+Xin 
+Xie 
+Yu 
+Qian 
+Xiao 
+Yi 
+Ge 
+Wu 
+Tan 
+Jin 
+Ou 
+Hu 
+Ti 
+Huan 
+Xu 
+Pen 
+Xi 
+Xiao 
+Xu 
+Xi 
+Sen 
+Lian 
+Chu 
+Yi 
+Kan 
+Yu 
+Chuo 
+Huan 
+Zhi 
+Zheng 
+Ci 
+Bu 
+Wu 
+Qi 
+Bu 
+Bu 
+Wai 
+Ju 
+Qian 
+Chi 
+Se 
+Chi 
+Se 
+Zhong 
+Sui 
+Sui 
+Li 
+Cuo 
+Yu 
+Li 
+Gui 
+Dai 
+Dai 
+Si 
+Jian 
+Zhe 
+Mo 
+Mo 
+Yao 
+Mo 
+Cu 
+Yang 
+Tian 
+Sheng 
+Dai 
+Shang 
+Xu 
+Xun 
+Shu 
+Can 
+Jue 
+Piao 
+Qia 
+Qiu 
+Su 
+Qing 
+Yun 
+Lian 
+Yi 
+Fou 
+Zhi 
+Ye 
+Can 
+Hun 
+Dan 
+Ji 
+Ye 
+Zhen 
+Yun 
+Wen 
+Chou 
+Bin 
+Ti 
+Jin 
+Shang 
+Yin 
+Diao 
+Cu 
+Hui 
+Cuan 
+Yi 
+Dan 
+Du 
+Jiang 
+Lian 
+Bin 
+Du 
+Tsukusu 
+Jian 
+Shu 
+Ou 
+Duan 
+Zhu 
+Yin 
+Qing 
+Yi 
+Sha 
+Que 
+Ke 
+Yao 
+Jun 
+Dian 
+Hui 
+Hui 
+Gu 
+Que 
+Ji 
+Yi 
+Ou 
+Hui 
+Duan 
+Yi 
+Xiao 
+Wu 
+Guan 
+Mu 
+Mei 
+Mei 
+Ai 
+Zuo 
+Du 
+Yu 
+Bi 
+Bi 
+Bi 
+Pi 
+Pi 
+Bi 
+Chan 
+Mao 
+[?] 
+[?] 
+Pu 
+Mushiru 
+Jia 
+Zhan 
+Sai 
+Mu 
+Tuo 
+Xun 
+Er 
+Rong 
+Xian 
+Ju 
+Mu 
+Hao 
+Qiu 
+Dou 
+Mushiru 
+Tan 
+Pei 
+Ju 
+Duo 
+Cui 
+Bi 
+San 
+[?] 
+Mao 
+Sui 
+Yu 
+Yu 
+Tuo 
+He 
+Jian 
+Ta 
+San 
+Lu 
+Mu 
+Li 
+Tong 
+Rong 
+Chang 
+Pu 
+Luo 
+Zhan 
+Sao 
+Zhan 
+Meng 
+Luo 
+Qu 
+Die 
+Shi 
+Di 
+Min 
+Jue 
+Mang 
+Qi 
+Pie 
+Nai 
+Qi 
+Dao 
+Xian 
+Chuan 
+Fen 
+Ri 
+Nei 
+[?] 
+Fu 
+Shen 
+Dong 
+Qing 
+Qi 
+Yin 
+Xi 
+Hai 
+Yang 
+An 
+Ya 
+Ke 
+Qing 
+Ya 
+Dong 
+Dan 
+Lu 
+Qing 
+Yang 
+Yun 
+Yun 
+Shui 
+San 
+Zheng 
+Bing 
+Yong 
+Dang 
+Shitamizu 
+Le 
+Ni 
+Tun 
+Fan 
+Gui 
+Ting 
+Zhi 
+Qiu 
+Bin 
+Ze 
+Mian 
+Cuan 
+Hui 
+Diao 
+Yi 
+Cha 
+Zhuo 
+Chuan 
+Wan 
+Fan 
+Dai 
+Xi 
+Tuo 
+Mang 
+Qiu 
+Qi 
+Shan 
+Pai 
+Han 
+Qian 
+Wu 
+Wu 
+Xun 
+Si 
+Ru 
+Gong 
+Jiang 
+Chi 
+Wu 
+Tsuchi 
+[?] 
+Tang 
+Zhi 
+Chi 
+Qian 
+Mi 
+Yu 
+Wang 
+Qing 
+Jing 
+Rui 
+Jun 
+Hong 
+Tai 
+Quan 
+Ji 
+Bian 
+Bian 
+Gan 
+Wen 
+Zhong 
+Fang 
+Xiong 
+Jue 
+Hang 
+Niou 
+Qi 
+Fen 
+Xu 
+Xu 
+Qin 
+Yi 
+Wo 
+Yun 
+Yuan 
+Hang 
+Yan 
+Chen 
+Chen 
+Dan 
+You 
+Dun 
+Hu 
+Huo 
+Qie 
+Mu 
+Rou 
+Mei 
+Ta 
+Mian 
+Wu 
+Chong 
+Tian 
+Bi 
+Sha 
+Zhi 
+Pei 
+Pan 
+Zhui 
+Za 
+Gou 
+Liu 
+Mei 
+Ze 
+Feng 
+Ou 
+Li 
+Lun 
+Cang 
+Feng 
+Wei 
+Hu 
+Mo 
+Mei 
+Shu 
+Ju 
+Zan 
+Tuo 
+Tuo 
+Tuo 
+He 
+Li 
+Mi 
+Yi 
+Fa 
+Fei 
+You 
+Tian 
+Zhi 
+Zhao 
+Gu 
+Zhan 
+Yan 
+Si 
+Kuang 
+Jiong 
+Ju 
+Xie 
+Qiu 
+Yi 
+Jia 
+Zhong 
+Quan 
+Bo 
+Hui 
+Mi 
+Ben 
+Zhuo 
+Chu 
+Le 
+You 
+Gu 
+Hong 
+Gan 
+Fa 
+Mao 
+Si 
+Hu 
+Ping 
+Ci 
+Fan 
+Chi 
+Su 
+Ning 
+Cheng 
+Ling 
+Pao 
+Bo 
+Qi 
+Si 
+Ni 
+Ju 
+Yue 
+Zhu 
+Sheng 
+Lei 
+Xuan 
+Xue 
+Fu 
+Pan 
+Min 
+Tai 
+Yang 
+Ji 
+Yong 
+Guan 
+Beng 
+Xue 
+Long 
+Lu 
+[?] 
+Bo 
+Xie 
+Po 
+Ze 
+Jing 
+Yin 
+Zhou 
+Ji 
+Yi 
+Hui 
+Hui 
+Zui 
+Cheng 
+Yin 
+Wei 
+Hou 
+Jian 
+Yang 
+Lie 
+Si 
+Ji 
+Er 
+Xing 
+Fu 
+Sa 
+Suo 
+Zhi 
+Yin 
+Wu 
+Xi 
+Kao 
+Zhu 
+Jiang 
+Luo 
+[?] 
+An 
+Dong 
+Yi 
+Mou 
+Lei 
+Yi 
+Mi 
+Quan 
+Jin 
+Mo 
+Wei 
+Xiao 
+Xie 
+Hong 
+Xu 
+Shuo 
+Kuang 
+Tao 
+Qie 
+Ju 
+Er 
+Zhou 
+Ru 
+Ping 
+Xun 
+Xiong 
+Zhi 
+Guang 
+Huan 
+Ming 
+Huo 
+Wa 
+Qia 
+Pai 
+Wu 
+Qu 
+Liu 
+Yi 
+Jia 
+Jing 
+Qian 
+Jiang 
+Jiao 
+Cheng 
+Shi 
+Zhuo 
+Ce 
+Pal 
+Kuai 
+Ji 
+Liu 
+Chan 
+Hun 
+Hu 
+Nong 
+Xun 
+Jin 
+Lie 
+Qiu 
+Wei 
+Zhe 
+Jun 
+Han 
+Bang 
+Mang 
+Zhuo 
+You 
+Xi 
+Bo 
+Dou 
+Wan 
+Hong 
+Yi 
+Pu 
+Ying 
+Lan 
+Hao 
+Lang 
+Han 
+Li 
+Geng 
+Fu 
+Wu 
+Lian 
+Chun 
+Feng 
+Yi 
+Yu 
+Tong 
+Lao 
+Hai 
+Jin 
+Jia 
+Chong 
+Weng 
+Mei 
+Sui 
+Cheng 
+Pei 
+Xian 
+Shen 
+Tu 
+Kun 
+Pin 
+Nie 
+Han 
+Jing 
+Xiao 
+She 
+Nian 
+Tu 
+Yong 
+Xiao 
+Xian 
+Ting 
+E 
+Su 
+Tun 
+Juan 
+Cen 
+Ti 
+Li 
+Shui 
+Si 
+Lei 
+Shui 
+Tao 
+Du 
+Lao 
+Lai 
+Lian 
+Wei 
+Wo 
+Yun 
+Huan 
+Di 
+[?] 
+Run 
+Jian 
+Zhang 
+Se 
+Fu 
+Guan 
+Xing 
+Shou 
+Shuan 
+Ya 
+Chuo 
+Zhang 
+Ye 
+Kong 
+Wo 
+Han 
+Tuo 
+Dong 
+He 
+Wo 
+Ju 
+Gan 
+Liang 
+Hun 
+Ta 
+Zhuo 
+Dian 
+Qie 
+De 
+Juan 
+Zi 
+Xi 
+Yao 
+Qi 
+Gu 
+Guo 
+Han 
+Lin 
+Tang 
+Zhou 
+Peng 
+Hao 
+Chang 
+Shu 
+Qi 
+Fang 
+Chi 
+Lu 
+Nao 
+Ju 
+Tao 
+Cong 
+Lei 
+Zhi 
+Peng 
+Fei 
+Song 
+Tian 
+Pi 
+Dan 
+Yu 
+Ni 
+Yu 
+Lu 
+Gan 
+Mi 
+Jing 
+Ling 
+Lun 
+Yin 
+Cui 
+Qu 
+Huai 
+Yu 
+Nian 
+Shen 
+Piao 
+Chun 
+Wa 
+Yuan 
+Lai 
+Hun 
+Qing 
+Yan 
+Qian 
+Tian 
+Miao 
+Zhi 
+Yin 
+Mi 
+Ben 
+Yuan 
+Wen 
+Re 
+Fei 
+Qing 
+Yuan 
+Ke 
+Ji 
+She 
+Yuan 
+Shibui 
+Lu 
+Zi 
+Du 
+[?] 
+Jian 
+Min 
+Pi 
+Tani 
+Yu 
+Yuan 
+Shen 
+Shen 
+Rou 
+Huan 
+Zhu 
+Jian 
+Nuan 
+Yu 
+Qiu 
+Ting 
+Qu 
+Du 
+Feng 
+Zha 
+Bo 
+Wo 
+Wo 
+Di 
+Wei 
+Wen 
+Ru 
+Xie 
+Ce 
+Wei 
+Ge 
+Gang 
+Yan 
+Hong 
+Xuan 
+Mi 
+Ke 
+Mao 
+Ying 
+Yan 
+You 
+Hong 
+Miao 
+Xing 
+Mei 
+Zai 
+Hun 
+Nai 
+Kui 
+Shi 
+E 
+Pai 
+Mei 
+Lian 
+Qi 
+Qi 
+Mei 
+Tian 
+Cou 
+Wei 
+Can 
+Tuan 
+Mian 
+Hui 
+Mo 
+Xu 
+Ji 
+Pen 
+Jian 
+Jian 
+Hu 
+Feng 
+Xiang 
+Yi 
+Yin 
+Zhan 
+Shi 
+Jie 
+Cheng 
+Huang 
+Tan 
+Yu 
+Bi 
+Min 
+Shi 
+Tu 
+Sheng 
+Yong 
+Qu 
+Zhong 
+Suei 
+Jiu 
+Jiao 
+Qiou 
+Yin 
+Tang 
+Long 
+Huo 
+Yuan 
+Nan 
+Ban 
+You 
+Quan 
+Chui 
+Liang 
+Chan 
+Yan 
+Chun 
+Nie 
+Zi 
+Wan 
+Shi 
+Man 
+Ying 
+Ratsu 
+Kui 
+[?] 
+Jian 
+Xu 
+Lu 
+Gui 
+Gai 
+[?] 
+[?] 
+Po 
+Jin 
+Gui 
+Tang 
+Yuan 
+Suo 
+Yuan 
+Lian 
+Yao 
+Meng 
+Zhun 
+Sheng 
+Ke 
+Tai 
+Da 
+Wa 
+Liu 
+Gou 
+Sao 
+Ming 
+Zha 
+Shi 
+Yi 
+Lun 
+Ma 
+Pu 
+Wei 
+Li 
+Cai 
+Wu 
+Xi 
+Wen 
+Qiang 
+Ze 
+Shi 
+Su 
+Yi 
+Zhen 
+Sou 
+Yun 
+Xiu 
+Yin 
+Rong 
+Hun 
+Su 
+Su 
+Ni 
+Ta 
+Shi 
+Ru 
+Wei 
+Pan 
+Chu 
+Chu 
+Pang 
+Weng 
+Cang 
+Mie 
+He 
+Dian 
+Hao 
+Huang 
+Xi 
+Zi 
+Di 
+Zhi 
+Ying 
+Fu 
+Jie 
+Hua 
+Ge 
+Zi 
+Tao 
+Teng 
+Sui 
+Bi 
+Jiao 
+Hui 
+Gun 
+Yin 
+Gao 
+Long 
+Zhi 
+Yan 
+She 
+Man 
+Ying 
+Chun 
+Lu 
+Lan 
+Luan 
+[?] 
+Bin 
+Tan 
+Yu 
+Sou 
+Hu 
+Bi 
+Biao 
+Zhi 
+Jiang 
+Kou 
+Shen 
+Shang 
+Di 
+Mi 
+Ao 
+Lu 
+Hu 
+Hu 
+You 
+Chan 
+Fan 
+Yong 
+Gun 
+Man 
+Qing 
+Yu 
+Piao 
+Ji 
+Ya 
+Jiao 
+Qi 
+Xi 
+Ji 
+Lu 
+Lu 
+Long 
+Jin 
+Guo 
+Cong 
+Lou 
+Zhi 
+Gai 
+Qiang 
+Li 
+Yan 
+Cao 
+Jiao 
+Cong 
+Qun 
+Tuan 
+Ou 
+Teng 
+Ye 
+Xi 
+Mi 
+Tang 
+Mo 
+Shang 
+Han 
+Lian 
+Lan 
+Wa 
+Li 
+Qian 
+Feng 
+Xuan 
+Yi 
+Man 
+Zi 
+Mang 
+Kang 
+Lei 
+Peng 
+Shu 
+Zhang 
+Zhang 
+Chong 
+Xu 
+Huan 
+Kuo 
+Jian 
+Yan 
+Chuang 
+Liao 
+Cui 
+Ti 
+Yang 
+Jiang 
+Cong 
+Ying 
+Hong 
+Xun 
+Shu 
+Guan 
+Ying 
+Xiao 
+[?] 
+[?] 
+Xu 
+Lian 
+Zhi 
+Wei 
+Pi 
+Jue 
+Jiao 
+Po 
+Dang 
+Hui 
+Jie 
+Wu 
+Pa 
+Ji 
+Pan 
+Gui 
+Xiao 
+Qian 
+Qian 
+Xi 
+Lu 
+Xi 
+Xuan 
+Dun 
+Huang 
+Min 
+Run 
+Su 
+Liao 
+Zhen 
+Zhong 
+Yi 
+Di 
+Wan 
+Dan 
+Tan 
+Chao 
+Xun 
+Kui 
+Yie 
+Shao 
+Tu 
+Zhu 
+San 
+Hei 
+Bi 
+Shan 
+Chan 
+Chan 
+Shu 
+Tong 
+Pu 
+Lin 
+Wei 
+Se 
+Se 
+Cheng 
+Jiong 
+Cheng 
+Hua 
+Jiao 
+Lao 
+Che 
+Gan 
+Cun 
+Heng 
+Si 
+Shu 
+Peng 
+Han 
+Yun 
+Liu 
+Hong 
+Fu 
+Hao 
+He 
+Xian 
+Jian 
+Shan 
+Xi 
+Oki 
+[?] 
+Lan 
+[?] 
+Yu 
+Lin 
+Min 
+Zao 
+Dang 
+Wan 
+Ze 
+Xie 
+Yu 
+Li 
+Shi 
+Xue 
+Ling 
+Man 
+Zi 
+Yong 
+Kuai 
+Can 
+Lian 
+Dian 
+Ye 
+Ao 
+Huan 
+Zhen 
+Chan 
+Man 
+Dan 
+Dan 
+Yi 
+Sui 
+Pi 
+Ju 
+Ta 
+Qin 
+Ji 
+Zhuo 
+Lian 
+Nong 
+Guo 
+Jin 
+Fen 
+Se 
+Ji 
+Sui 
+Hui 
+Chu 
+Ta 
+Song 
+Ding 
+[?] 
+Zhu 
+Lai 
+Bin 
+Lian 
+Mi 
+Shi 
+Shu 
+Mi 
+Ning 
+Ying 
+Ying 
+Meng 
+Jin 
+Qi 
+Pi 
+Ji 
+Hao 
+Ru 
+Zui 
+Wo 
+Tao 
+Yin 
+Yin 
+Dui 
+Ci 
+Huo 
+Jing 
+Lan 
+Jun 
+Ai 
+Pu 
+Zhuo 
+Wei 
+Bin 
+Gu 
+Qian 
+Xing 
+Hama 
+Kuo 
+Fei 
+[?] 
+Boku 
+Jian 
+Wei 
+Luo 
+Zan 
+Lu 
+Li 
+You 
+Yang 
+Lu 
+Si 
+Jie 
+Ying 
+Du 
+Wang 
+Hui 
+Xie 
+Pan 
+Shen 
+Biao 
+Chan 
+Mo 
+Liu 
+Jian 
+Pu 
+Se 
+Cheng 
+Gu 
+Bin 
+Huo 
+Xian 
+Lu 
+Qin 
+Han 
+Ying 
+Yong 
+Li 
+Jing 
+Xiao 
+Ying 
+Sui 
+Wei 
+Xie 
+Huai 
+Hao 
+Zhu 
+Long 
+Lai 
+Dui 
+Fan 
+Hu 
+Lai 
+[?] 
+[?] 
+Ying 
+Mi 
+Ji 
+Lian 
+Jian 
+Ying 
+Fen 
+Lin 
+Yi 
+Jian 
+Yue 
+Chan 
+Dai 
+Rang 
+Jian 
+Lan 
+Fan 
+Shuang 
+Yuan 
+Zhuo 
+Feng 
+She 
+Lei 
+Lan 
+Cong 
+Qu 
+Yong 
+Qian 
+Fa 
+Guan 
+Que 
+Yan 
+Hao 
+Hyeng 
+Sa 
+Zan 
+Luan 
+Yan 
+Li 
+Mi 
+Shan 
+Tan 
+Dang 
+Jiao 
+Chan 
+[?] 
+Hao 
+Ba 
+Zhu 
+Lan 
+Lan 
+Nang 
+Wan 
+Luan 
+Xun 
+Xian 
+Yan 
+Gan 
+Yan 
+Yu 
+Huo 
+Si 
+Mie 
+Guang 
+Deng 
+Hui 
+Xiao 
+Xiao 
+Hu 
+Hong 
+Ling 
+Zao 
+Zhuan 
+Jiu 
+Zha 
+Xie 
+Chi 
+Zhuo 
+Zai 
+Zai 
+Can 
+Yang 
+Qi 
+Zhong 
+Fen 
+Niu 
+Jiong 
+Wen 
+Po 
+Yi 
+Lu 
+Chui 
+Pi 
+Kai 
+Pan 
+Yan 
+Kai 
+Pang 
+Mu 
+Chao 
+Liao 
+Gui 
+Kang 
+Tun 
+Guang 
+Xin 
+Zhi 
+Guang 
+Guang 
+Wei 
+Qiang 
+[?] 
+Da 
+Xia 
+Zheng 
+Zhu 
+Ke 
+Zhao 
+Fu 
+Ba 
+Duo 
+Duo 
+Ling 
+Zhuo 
+Xuan 
+Ju 
+Tan 
+Pao 
+Jiong 
+Pao 
+Tai 
+Tai 
+Bing 
+Yang 
+Tong 
+Han 
+Zhu 
+Zha 
+Dian 
+Wei 
+Shi 
+Lian 
+Chi 
+Huang 
+[?] 
+Hu 
+Shuo 
+Lan 
+Jing 
+Jiao 
+Xu 
+Xing 
+Quan 
+Lie 
+Huan 
+Yang 
+Xiao 
+Xiu 
+Xian 
+Yin 
+Wu 
+Zhou 
+Yao 
+Shi 
+Wei 
+Tong 
+Xue 
+Zai 
+Kai 
+Hong 
+Luo 
+Xia 
+Zhu 
+Xuan 
+Zheng 
+Po 
+Yan 
+Hui 
+Guang 
+Zhe 
+Hui 
+Kao 
+[?] 
+Fan 
+Shao 
+Ye 
+Hui 
+[?] 
+Tang 
+Jin 
+Re 
+[?] 
+Xi 
+Fu 
+Jiong 
+Che 
+Pu 
+Jing 
+Zhuo 
+Ting 
+Wan 
+Hai 
+Peng 
+Lang 
+Shan 
+Hu 
+Feng 
+Chi 
+Rong 
+Hu 
+Xi 
+Shu 
+He 
+Xun 
+Ku 
+Jue 
+Xiao 
+Xi 
+Yan 
+Han 
+Zhuang 
+Jun 
+Di 
+Xie 
+Ji 
+Wu 
+[?] 
+[?] 
+Han 
+Yan 
+Huan 
+Men 
+Ju 
+Chou 
+Bei 
+Fen 
+Lin 
+Kun 
+Hun 
+Tun 
+Xi 
+Cui 
+Wu 
+Hong 
+Ju 
+Fu 
+Wo 
+Jiao 
+Cong 
+Feng 
+Ping 
+Qiong 
+Ruo 
+Xi 
+Qiong 
+Xin 
+Zhuo 
+Yan 
+Yan 
+Yi 
+Jue 
+Yu 
+Gang 
+Ran 
+Pi 
+Gu 
+[?] 
+Sheng 
+Chang 
+Shao 
+[?] 
+[?] 
+[?] 
+[?] 
+Chen 
+He 
+Kui 
+Zhong 
+Duan 
+Xia 
+Hui 
+Feng 
+Lian 
+Xuan 
+Xing 
+Huang 
+Jiao 
+Jian 
+Bi 
+Ying 
+Zhu 
+Wei 
+Tuan 
+Tian 
+Xi 
+Nuan 
+Nuan 
+Chan 
+Yan 
+Jiong 
+Jiong 
+Yu 
+Mei 
+Sha 
+Wei 
+Ye 
+Xin 
+Qiong 
+Rou 
+Mei 
+Huan 
+Xu 
+Zhao 
+Wei 
+Fan 
+Qiu 
+Sui 
+Yang 
+Lie 
+Zhu 
+Jie 
+Gao 
+Gua 
+Bao 
+Hu 
+Yun 
+Xia 
+[?] 
+[?] 
+Bian 
+Gou 
+Tui 
+Tang 
+Chao 
+Shan 
+N 
+Bo 
+Huang 
+Xie 
+Xi 
+Wu 
+Xi 
+Yun 
+He 
+He 
+Xi 
+Yun 
+Xiong 
+Nai 
+Shan 
+Qiong 
+Yao 
+Xun 
+Mi 
+Lian 
+Ying 
+Wen 
+Rong 
+Oozutsu 
+[?] 
+Qiang 
+Liu 
+Xi 
+Bi 
+Biao 
+Zong 
+Lu 
+Jian 
+Shou 
+Yi 
+Lou 
+Feng 
+Sui 
+Yi 
+Tong 
+Jue 
+Zong 
+Yun 
+Hu 
+Yi 
+Zhi 
+Ao 
+Wei 
+Liao 
+Han 
+Ou 
+Re 
+Jiong 
+Man 
+[?] 
+Shang 
+Cuan 
+Zeng 
+Jian 
+Xi 
+Xi 
+Xi 
+Yi 
+Xiao 
+Chi 
+Huang 
+Chan 
+Ye 
+Qian 
+Ran 
+Yan 
+Xian 
+Qiao 
+Zun 
+Deng 
+Dun 
+Shen 
+Jiao 
+Fen 
+Si 
+Liao 
+Yu 
+Lin 
+Tong 
+Shao 
+Fen 
+Fan 
+Yan 
+Xun 
+Lan 
+Mei 
+Tang 
+Yi 
+Jing 
+Men 
+[?] 
+[?] 
+Ying 
+Yu 
+Yi 
+Xue 
+Lan 
+Tai 
+Zao 
+Can 
+Sui 
+Xi 
+Que 
+Cong 
+Lian 
+Hui 
+Zhu 
+Xie 
+Ling 
+Wei 
+Yi 
+Xie 
+Zhao 
+Hui 
+Tatsu 
+Nung 
+Lan 
+Ru 
+Xian 
+Kao 
+Xun 
+Jin 
+Chou 
+Chou 
+Yao 
+He 
+Lan 
+Biao 
+Rong 
+Li 
+Mo 
+Bao 
+Ruo 
+Lu 
+La 
+Ao 
+Xun 
+Kuang 
+Shuo 
+[?] 
+Li 
+Lu 
+Jue 
+Liao 
+Yan 
+Xi 
+Xie 
+Long 
+Ye 
+[?] 
+Rang 
+Yue 
+Lan 
+Cong 
+Jue 
+Tong 
+Guan 
+[?] 
+Che 
+Mi 
+Tang 
+Lan 
+Zhu 
+[?] 
+Ling 
+Cuan 
+Yu 
+Zhua 
+Tsumekanmuri 
+Pa 
+Zheng 
+Pao 
+Cheng 
+Yuan 
+Ai 
+Wei 
+[?] 
+Jue 
+Jue 
+Fu 
+Ye 
+Ba 
+Die 
+Ye 
+Yao 
+Zu 
+Shuang 
+Er 
+Qiang 
+Chuang 
+Ge 
+Zang 
+Die 
+Qiang 
+Yong 
+Qiang 
+Pian 
+Ban 
+Pan 
+Shao 
+Jian 
+Pai 
+Du 
+Chuang 
+Tou 
+Zha 
+Bian 
+Die 
+Bang 
+Bo 
+Chuang 
+You 
+[?] 
+Du 
+Ya 
+Cheng 
+Niu 
+Ushihen 
+Pin 
+Jiu 
+Mou 
+Tuo 
+Mu 
+Lao 
+Ren 
+Mang 
+Fang 
+Mao 
+Mu 
+Gang 
+Wu 
+Yan 
+Ge 
+Bei 
+Si 
+Jian 
+Gu 
+You 
+Ge 
+Sheng 
+Mu 
+Di 
+Qian 
+Quan 
+Quan 
+Zi 
+Te 
+Xi 
+Mang 
+Keng 
+Qian 
+Wu 
+Gu 
+Xi 
+Li 
+Li 
+Pou 
+Ji 
+Gang 
+Zhi 
+Ben 
+Quan 
+Run 
+Du 
+Ju 
+Jia 
+Jian 
+Feng 
+Pian 
+Ke 
+Ju 
+Kao 
+Chu 
+Xi 
+Bei 
+Luo 
+Jie 
+Ma 
+San 
+Wei 
+Li 
+Dun 
+Tong 
+[?] 
+Jiang 
+Ikenie 
+Li 
+Du 
+Lie 
+Pi 
+Piao 
+Bao 
+Xi 
+Chou 
+Wei 
+Kui 
+Chou 
+Quan 
+Fan 
+Ba 
+Fan 
+Qiu 
+Ji 
+Cai 
+Chuo 
+An 
+Jie 
+Zhuang 
+Guang 
+Ma 
+You 
+Kang 
+Bo 
+Hou 
+Ya 
+Yin 
+Huan 
+Zhuang 
+Yun 
+Kuang 
+Niu 
+Di 
+Qing 
+Zhong 
+Mu 
+Bei 
+Pi 
+Ju 
+Ni 
+Sheng 
+Pao 
+Xia 
+Tuo 
+Hu 
+Ling 
+Fei 
+Pi 
+Ni 
+Ao 
+You 
+Gou 
+Yue 
+Ju 
+Dan 
+Po 
+Gu 
+Xian 
+Ning 
+Huan 
+Hen 
+Jiao 
+He 
+Zhao 
+Ji 
+Xun 
+Shan 
+Ta 
+Rong 
+Shou 
+Tong 
+Lao 
+Du 
+Xia 
+Shi 
+Hua 
+Zheng 
+Yu 
+Sun 
+Yu 
+Bi 
+Mang 
+Xi 
+Juan 
+Li 
+Xia 
+Yin 
+Suan 
+Lang 
+Bei 
+Zhi 
+Yan 
+Sha 
+Li 
+Han 
+Xian 
+Jing 
+Pai 
+Fei 
+Yao 
+Ba 
+Qi 
+Ni 
+Biao 
+Yin 
+Lai 
+Xi 
+Jian 
+Qiang 
+Kun 
+Yan 
+Guo 
+Zong 
+Mi 
+Chang 
+Yi 
+Zhi 
+Zheng 
+Ya 
+Meng 
+Cai 
+Cu 
+She 
+Kari 
+Cen 
+Luo 
+Hu 
+Zong 
+Ji 
+Wei 
+Feng 
+Wo 
+Yuan 
+Xing 
+Zhu 
+Mao 
+Wei 
+Yuan 
+Xian 
+Tuan 
+Ya 
+Nao 
+Xie 
+Jia 
+Hou 
+Bian 
+You 
+You 
+Mei 
+Zha 
+Yao 
+Sun 
+Bo 
+Ming 
+Hua 
+Yuan 
+Sou 
+Ma 
+Yuan 
+Dai 
+Yu 
+Shi 
+Hao 
+[?] 
+Yi 
+Zhen 
+Chuang 
+Hao 
+Man 
+Jing 
+Jiang 
+Mu 
+Zhang 
+Chan 
+Ao 
+Ao 
+Hao 
+Cui 
+Fen 
+Jue 
+Bi 
+Bi 
+Huang 
+Pu 
+Lin 
+Yu 
+Tong 
+Yao 
+Liao 
+Shuo 
+Xiao 
+Swu 
+Ton 
+Xi 
+Ge 
+Juan 
+Du 
+Hui 
+Kuai 
+Xian 
+Xie 
+Ta 
+Xian 
+Xun 
+Ning 
+Pin 
+Huo 
+Nou 
+Meng 
+Lie 
+Nao 
+Guang 
+Shou 
+Lu 
+Ta 
+Xian 
+Mi 
+Rang 
+Huan 
+Nao 
+Luo 
+Xian 
+Qi 
+Jue 
+Xuan 
+Miao 
+Zi 
+Lu 
+Lu 
+Yu 
+Su 
+Wang 
+Qiu 
+Ga 
+Ding 
+Le 
+Ba 
+Ji 
+Hong 
+Di 
+Quan 
+Gan 
+Jiu 
+Yu 
+Ji 
+Yu 
+Yang 
+Ma 
+Gong 
+Wu 
+Fu 
+Wen 
+Jie 
+Ya 
+Fen 
+Bian 
+Beng 
+Yue 
+Jue 
+Yun 
+Jue 
+Wan 
+Jian 
+Mei 
+Dan 
+Pi 
+Wei 
+Huan 
+Xian 
+Qiang 
+Ling 
+Dai 
+Yi 
+An 
+Ping 
+Dian 
+Fu 
+Xuan 
+Xi 
+Bo 
+Ci 
+Gou 
+Jia 
+Shao 
+Po 
+Ci 
+Ke 
+Ran 
+Sheng 
+Shen 
+Yi 
+Zu 
+Jia 
+Min 
+Shan 
+Liu 
+Bi 
+Zhen 
+Zhen 
+Jue 
+Fa 
+Long 
+Jin 
+Jiao 
+Jian 
+Li 
+Guang 
+Xian 
+Zhou 
+Gong 
+Yan 
+Xiu 
+Yang 
+Xu 
+Luo 
+Su 
+Zhu 
+Qin 
+Ken 
+Xun 
+Bao 
+Er 
+Xiang 
+Yao 
+Xia 
+Heng 
+Gui 
+Chong 
+Xu 
+Ban 
+Pei 
+[?] 
+Dang 
+Ei 
+Hun 
+Wen 
+E 
+Cheng 
+Ti 
+Wu 
+Wu 
+Cheng 
+Jun 
+Mei 
+Bei 
+Ting 
+Xian 
+Chuo 
+Han 
+Xuan 
+Yan 
+Qiu 
+Quan 
+Lang 
+Li 
+Xiu 
+Fu 
+Liu 
+Ye 
+Xi 
+Ling 
+Li 
+Jin 
+Lian 
+Suo 
+Chiisai 
+[?] 
+Wan 
+Dian 
+Pin 
+Zhan 
+Cui 
+Min 
+Yu 
+Ju 
+Chen 
+Lai 
+Wen 
+Sheng 
+Wei 
+Dian 
+Chu 
+Zhuo 
+Pei 
+Cheng 
+Hu 
+Qi 
+E 
+Kun 
+Chang 
+Qi 
+Beng 
+Wan 
+Lu 
+Cong 
+Guan 
+Yan 
+Diao 
+Bei 
+Lin 
+Qin 
+Pi 
+Pa 
+Que 
+Zhuo 
+Qin 
+Fa 
+[?] 
+Qiong 
+Du 
+Jie 
+Hun 
+Yu 
+Mao 
+Mei 
+Chun 
+Xuan 
+Ti 
+Xing 
+Dai 
+Rou 
+Min 
+Zhen 
+Wei 
+Ruan 
+Huan 
+Jie 
+Chuan 
+Jian 
+Zhuan 
+Yang 
+Lian 
+Quan 
+Xia 
+Duan 
+Yuan 
+Ye 
+Nao 
+Hu 
+Ying 
+Yu 
+Huang 
+Rui 
+Se 
+Liu 
+Shi 
+Rong 
+Suo 
+Yao 
+Wen 
+Wu 
+Jin 
+Jin 
+Ying 
+Ma 
+Tao 
+Liu 
+Tang 
+Li 
+Lang 
+Gui 
+Zhen 
+Qiang 
+Cuo 
+Jue 
+Zhao 
+Yao 
+Ai 
+Bin 
+Tu 
+Chang 
+Kun 
+Zhuan 
+Cong 
+Jin 
+Yi 
+Cui 
+Cong 
+Qi 
+Li 
+Ying 
+Suo 
+Qiu 
+Xuan 
+Ao 
+Lian 
+Man 
+Zhang 
+Yin 
+[?] 
+Ying 
+Zhi 
+Lu 
+Wu 
+Deng 
+Xiou 
+Zeng 
+Xun 
+Qu 
+Dang 
+Lin 
+Liao 
+Qiong 
+Su 
+Huang 
+Gui 
+Pu 
+Jing 
+Fan 
+Jin 
+Liu 
+Ji 
+[?] 
+Jing 
+Ai 
+Bi 
+Can 
+Qu 
+Zao 
+Dang 
+Jiao 
+Gun 
+Tan 
+Hui 
+Huan 
+Se 
+Sui 
+Tian 
+[?] 
+Yu 
+Jin 
+Lu 
+Bin 
+Shou 
+Wen 
+Zui 
+Lan 
+Xi 
+Ji 
+Xuan 
+Ruan 
+Huo 
+Gai 
+Lei 
+Du 
+Li 
+Zhi 
+Rou 
+Li 
+Zan 
+Qiong 
+Zhe 
+Gui 
+Sui 
+La 
+Long 
+Lu 
+Li 
+Zan 
+Lan 
+Ying 
+Mi 
+Xiang 
+Xi 
+Guan 
+Dao 
+Zan 
+Huan 
+Gua 
+Bo 
+Die 
+Bao 
+Hu 
+Zhi 
+Piao 
+Ban 
+Rang 
+Li 
+Wa 
+Dekaguramu 
+Jiang 
+Qian 
+Fan 
+Pen 
+Fang 
+Dan 
+Weng 
+Ou 
+Deshiguramu 
+Miriguramu 
+Thon 
+Hu 
+Ling 
+Yi 
+Ping 
+Ci 
+Hekutogura 
+Juan 
+Chang 
+Chi 
+Sarake 
+Dang 
+Meng 
+Pou 
+Zhui 
+Ping 
+Bian 
+Zhou 
+Zhen 
+Senchigura 
+Ci 
+Ying 
+Qi 
+Xian 
+Lou 
+Di 
+Ou 
+Meng 
+Zhuan 
+Peng 
+Lin 
+Zeng 
+Wu 
+Pi 
+Dan 
+Weng 
+Ying 
+Yan 
+Gan 
+Dai 
+Shen 
+Tian 
+Tian 
+Han 
+Chang 
+Sheng 
+Qing 
+Sheng 
+Chan 
+Chan 
+Rui 
+Sheng 
+Su 
+Sen 
+Yong 
+Shuai 
+Lu 
+Fu 
+Yong 
+Beng 
+Feng 
+Ning 
+Tian 
+You 
+Jia 
+Shen 
+Zha 
+Dian 
+Fu 
+Nan 
+Dian 
+Ping 
+Ting 
+Hua 
+Ting 
+Quan 
+Zi 
+Meng 
+Bi 
+Qi 
+Liu 
+Xun 
+Liu 
+Chang 
+Mu 
+Yun 
+Fan 
+Fu 
+Geng 
+Tian 
+Jie 
+Jie 
+Quan 
+Wei 
+Fu 
+Tian 
+Mu 
+Tap 
+Pan 
+Jiang 
+Wa 
+Da 
+Nan 
+Liu 
+Ben 
+Zhen 
+Chu 
+Mu 
+Mu 
+Ce 
+Cen 
+Gai 
+Bi 
+Da 
+Zhi 
+Lue 
+Qi 
+Lue 
+Pan 
+Kesa 
+Fan 
+Hua 
+Yu 
+Yu 
+Mu 
+Jun 
+Yi 
+Liu 
+Yu 
+Die 
+Chou 
+Hua 
+Dang 
+Chuo 
+Ji 
+Wan 
+Jiang 
+Sheng 
+Chang 
+Tuan 
+Lei 
+Ji 
+Cha 
+Liu 
+Tatamu 
+Tuan 
+Lin 
+Jiang 
+Jiang 
+Chou 
+Bo 
+Die 
+Die 
+Pi 
+Nie 
+Dan 
+Shu 
+Shu 
+Zhi 
+Yi 
+Chuang 
+Nai 
+Ding 
+Bi 
+Jie 
+Liao 
+Gong 
+Ge 
+Jiu 
+Zhou 
+Xia 
+Shan 
+Xu 
+Nue 
+Li 
+Yang 
+Chen 
+You 
+Ba 
+Jie 
+Jue 
+Zhi 
+Xia 
+Cui 
+Bi 
+Yi 
+Li 
+Zong 
+Chuang 
+Feng 
+Zhu 
+Pao 
+Pi 
+Gan 
+Ke 
+Ci 
+Xie 
+Qi 
+Dan 
+Zhen 
+Fa 
+Zhi 
+Teng 
+Ju 
+Ji 
+Fei 
+Qu 
+Dian 
+Jia 
+Xian 
+Cha 
+Bing 
+Ni 
+Zheng 
+Yong 
+Jing 
+Quan 
+Chong 
+Tong 
+Yi 
+Kai 
+Wei 
+Hui 
+Duo 
+Yang 
+Chi 
+Zhi 
+Hen 
+Ya 
+Mei 
+Dou 
+Jing 
+Xiao 
+Tong 
+Tu 
+Mang 
+Pi 
+Xiao 
+Suan 
+Pu 
+Li 
+Zhi 
+Cuo 
+Duo 
+Wu 
+Sha 
+Lao 
+Shou 
+Huan 
+Xian 
+Yi 
+Peng 
+Zhang 
+Guan 
+Tan 
+Fei 
+Ma 
+Lin 
+Chi 
+Ji 
+Dian 
+An 
+Chi 
+Bi 
+Bei 
+Min 
+Gu 
+Dui 
+E 
+Wei 
+Yu 
+Cui 
+Ya 
+Zhu 
+Cu 
+Dan 
+Shen 
+Zhung 
+Ji 
+Yu 
+Hou 
+Feng 
+La 
+Yang 
+Shen 
+Tu 
+Yu 
+Gua 
+Wen 
+Huan 
+Ku 
+Jia 
+Yin 
+Yi 
+Lu 
+Sao 
+Jue 
+Chi 
+Xi 
+Guan 
+Yi 
+Wen 
+Ji 
+Chuang 
+Ban 
+Lei 
+Liu 
+Chai 
+Shou 
+Nue 
+Dian 
+Da 
+Pie 
+Tan 
+Zhang 
+Biao 
+Shen 
+Cu 
+Luo 
+Yi 
+Zong 
+Chou 
+Zhang 
+Zhai 
+Sou 
+Suo 
+Que 
+Diao 
+Lou 
+Lu 
+Mo 
+Jin 
+Yin 
+Ying 
+Huang 
+Fu 
+Liao 
+Long 
+Qiao 
+Liu 
+Lao 
+Xian 
+Fei 
+Dan 
+Yin 
+He 
+Yan 
+Ban 
+Xian 
+Guan 
+Guai 
+Nong 
+Yu 
+Wei 
+Yi 
+Yong 
+Pi 
+Lei 
+Li 
+Shu 
+Dan 
+Lin 
+Dian 
+Lin 
+Lai 
+Pie 
+Ji 
+Chi 
+Yang 
+Xian 
+Jie 
+Zheng 
+[?] 
+Li 
+Huo 
+Lai 
+Shaku 
+Dian 
+Xian 
+Ying 
+Yin 
+Qu 
+Yong 
+Tan 
+Dian 
+Luo 
+Luan 
+Luan 
+Bo 
+[?] 
+Gui 
+Po 
+Fa 
+Deng 
+Fa 
+Bai 
+Bai 
+Qie 
+Bi 
+Zao 
+Zao 
+Mao 
+De 
+Pa 
+Jie 
+Huang 
+Gui 
+Ci 
+Ling 
+Gao 
+Mo 
+Ji 
+Jiao 
+Peng 
+Gao 
+Ai 
+E 
+Hao 
+Han 
+Bi 
+Wan 
+Chou 
+Qian 
+Xi 
+Ai 
+Jiong 
+Hao 
+Huang 
+Hao 
+Ze 
+Cui 
+Hao 
+Xiao 
+Ye 
+Po 
+Hao 
+Jiao 
+Ai 
+Xing 
+Huang 
+Li 
+Piao 
+He 
+Jiao 
+Pi 
+Gan 
+Pao 
+Zhou 
+Jun 
+Qiu 
+Cun 
+Que 
+Zha 
+Gu 
+Jun 
+Jun 
+Zhou 
+Zha 
+Gu 
+Zhan 
+Du 
+Min 
+Qi 
+Ying 
+Yu 
+Bei 
+Zhao 
+Zhong 
+Pen 
+He 
+Ying 
+He 
+Yi 
+Bo 
+Wan 
+He 
+Ang 
+Zhan 
+Yan 
+Jian 
+He 
+Yu 
+Kui 
+Fan 
+Gai 
+Dao 
+Pan 
+Fu 
+Qiu 
+Sheng 
+Dao 
+Lu 
+Zhan 
+Meng 
+Li 
+Jin 
+Xu 
+Jian 
+Pan 
+Guan 
+An 
+Lu 
+Shu 
+Zhou 
+Dang 
+An 
+Gu 
+Li 
+Mu 
+Cheng 
+Gan 
+Xu 
+Mang 
+Mang 
+Zhi 
+Qi 
+Ruan 
+Tian 
+Xiang 
+Dun 
+Xin 
+Xi 
+Pan 
+Feng 
+Dun 
+Min 
+Ming 
+Sheng 
+Shi 
+Yun 
+Mian 
+Pan 
+Fang 
+Miao 
+Dan 
+Mei 
+Mao 
+Kan 
+Xian 
+Ou 
+Shi 
+Yang 
+Zheng 
+Yao 
+Shen 
+Huo 
+Da 
+Zhen 
+Kuang 
+Ju 
+Shen 
+Chi 
+Sheng 
+Mei 
+Mo 
+Zhu 
+Zhen 
+Zhen 
+Mian 
+Di 
+Yuan 
+Die 
+Yi 
+Zi 
+Zi 
+Chao 
+Zha 
+Xuan 
+Bing 
+Mi 
+Long 
+Sui 
+Dong 
+Mi 
+Die 
+Yi 
+Er 
+Ming 
+Xuan 
+Chi 
+Kuang 
+Juan 
+Mou 
+Zhen 
+Tiao 
+Yang 
+Yan 
+Mo 
+Zhong 
+Mai 
+Zhao 
+Zheng 
+Mei 
+Jun 
+Shao 
+Han 
+Huan 
+Di 
+Cheng 
+Cuo 
+Juan 
+E 
+Wan 
+Xian 
+Xi 
+Kun 
+Lai 
+Jian 
+Shan 
+Tian 
+Hun 
+Wan 
+Ling 
+Shi 
+Qiong 
+Lie 
+Yai 
+Jing 
+Zheng 
+Li 
+Lai 
+Sui 
+Juan 
+Shui 
+Sui 
+Du 
+Bi 
+Bi 
+Mu 
+Hun 
+Ni 
+Lu 
+Yi 
+Jie 
+Cai 
+Zhou 
+Yu 
+Hun 
+Ma 
+Xia 
+Xing 
+Xi 
+Gun 
+Cai 
+Chun 
+Jian 
+Mei 
+Du 
+Hou 
+Xuan 
+Ti 
+Kui 
+Gao 
+Rui 
+Mou 
+Xu 
+Fa 
+Wen 
+Miao 
+Chou 
+Kui 
+Mi 
+Weng 
+Kou 
+Dang 
+Chen 
+Ke 
+Sou 
+Xia 
+Qiong 
+Mao 
+Ming 
+Man 
+Shui 
+Ze 
+Zhang 
+Yi 
+Diao 
+Ou 
+Mo 
+Shun 
+Cong 
+Lou 
+Chi 
+Man 
+Piao 
+Cheng 
+Ji 
+Meng 
+[?] 
+Run 
+Pie 
+Xi 
+Qiao 
+Pu 
+Zhu 
+Deng 
+Shen 
+Shun 
+Liao 
+Che 
+Xian 
+Kan 
+Ye 
+Xu 
+Tong 
+Mou 
+Lin 
+Kui 
+Xian 
+Ye 
+Ai 
+Hui 
+Zhan 
+Jian 
+Gu 
+Zhao 
+Qu 
+Wei 
+Chou 
+Sao 
+Ning 
+Xun 
+Yao 
+Huo 
+Meng 
+Mian 
+Bin 
+Mian 
+Li 
+Kuang 
+Jue 
+Xuan 
+Mian 
+Huo 
+Lu 
+Meng 
+Long 
+Guan 
+Man 
+Xi 
+Chu 
+Tang 
+Kan 
+Zhu 
+Mao 
+Jin 
+Lin 
+Yu 
+Shuo 
+Ce 
+Jue 
+Shi 
+Yi 
+Shen 
+Zhi 
+Hou 
+Shen 
+Ying 
+Ju 
+Zhou 
+Jiao 
+Cuo 
+Duan 
+Ai 
+Jiao 
+Zeng 
+Huo 
+Bai 
+Shi 
+Ding 
+Qi 
+Ji 
+Zi 
+Gan 
+Wu 
+Tuo 
+Ku 
+Qiang 
+Xi 
+Fan 
+Kuang 
+Dang 
+Ma 
+Sha 
+Dan 
+Jue 
+Li 
+Fu 
+Min 
+Nuo 
+Huo 
+Kang 
+Zhi 
+Qi 
+Kan 
+Jie 
+Fen 
+E 
+Ya 
+Pi 
+Zhe 
+Yan 
+Sui 
+Zhuan 
+Che 
+Dun 
+Pan 
+Yan 
+[?] 
+Feng 
+Fa 
+Mo 
+Zha 
+Qu 
+Yu 
+Luo 
+Tuo 
+Tuo 
+Di 
+Zhai 
+Zhen 
+Ai 
+Fei 
+Mu 
+Zhu 
+Li 
+Bian 
+Nu 
+Ping 
+Peng 
+Ling 
+Pao 
+Le 
+Po 
+Bo 
+Po 
+Shen 
+Za 
+Nuo 
+Li 
+Long 
+Tong 
+[?] 
+Li 
+Aragane 
+Chu 
+Keng 
+Quan 
+Zhu 
+Kuang 
+Huo 
+E 
+Nao 
+Jia 
+Lu 
+Wei 
+Ai 
+Luo 
+Ken 
+Xing 
+Yan 
+Tong 
+Peng 
+Xi 
+[?] 
+Hong 
+Shuo 
+Xia 
+Qiao 
+[?] 
+Wei 
+Qiao 
+[?] 
+Keng 
+Xiao 
+Que 
+Chan 
+Lang 
+Hong 
+Yu 
+Xiao 
+Xia 
+Mang 
+Long 
+Iong 
+Che 
+Che 
+E 
+Liu 
+Ying 
+Mang 
+Que 
+Yan 
+Sha 
+Kun 
+Yu 
+[?] 
+Kaki 
+Lu 
+Chen 
+Jian 
+Nue 
+Song 
+Zhuo 
+Keng 
+Peng 
+Yan 
+Zhui 
+Kong 
+Ceng 
+Qi 
+Zong 
+Qing 
+Lin 
+Jun 
+Bo 
+Ding 
+Min 
+Diao 
+Jian 
+He 
+Lu 
+Ai 
+Sui 
+Que 
+Ling 
+Bei 
+Yin 
+Dui 
+Wu 
+Qi 
+Lun 
+Wan 
+Dian 
+Gang 
+Pei 
+Qi 
+Chen 
+Ruan 
+Yan 
+Die 
+Ding 
+Du 
+Tuo 
+Jie 
+Ying 
+Bian 
+Ke 
+Bi 
+Wei 
+Shuo 
+Zhen 
+Duan 
+Xia 
+Dang 
+Ti 
+Nao 
+Peng 
+Jian 
+Di 
+Tan 
+Cha 
+Seki 
+Qi 
+[?] 
+Feng 
+Xuan 
+Que 
+Que 
+Ma 
+Gong 
+Nian 
+Su 
+E 
+Ci 
+Liu 
+Si 
+Tang 
+Bang 
+Hua 
+Pi 
+Wei 
+Sang 
+Lei 
+Cuo 
+Zhen 
+Xia 
+Qi 
+Lian 
+Pan 
+Wei 
+Yun 
+Dui 
+Zhe 
+Ke 
+La 
+[?] 
+Qing 
+Gun 
+Zhuan 
+Chan 
+Qi 
+Ao 
+Peng 
+Lu 
+Lu 
+Kan 
+Qiang 
+Chen 
+Yin 
+Lei 
+Biao 
+Qi 
+Mo 
+Qi 
+Cui 
+Zong 
+Qing 
+Chuo 
+[?] 
+Ji 
+Shan 
+Lao 
+Qu 
+Zeng 
+Deng 
+Jian 
+Xi 
+Lin 
+Ding 
+Dian 
+Huang 
+Pan 
+Za 
+Qiao 
+Di 
+Li 
+Tani 
+Jiao 
+[?] 
+Zhang 
+Qiao 
+Dun 
+Xian 
+Yu 
+Zhui 
+He 
+Huo 
+Zhai 
+Lei 
+Ke 
+Chu 
+Ji 
+Que 
+Dang 
+Yi 
+Jiang 
+Pi 
+Pi 
+Yu 
+Pin 
+Qi 
+Ai 
+Kai 
+Jian 
+Yu 
+Ruan 
+Meng 
+Pao 
+Ci 
+[?] 
+[?] 
+Mie 
+Ca 
+Xian 
+Kuang 
+Lei 
+Lei 
+Zhi 
+Li 
+Li 
+Fan 
+Que 
+Pao 
+Ying 
+Li 
+Long 
+Long 
+Mo 
+Bo 
+Shuang 
+Guan 
+Lan 
+Zan 
+Yan 
+Shi 
+Shi 
+Li 
+Reng 
+She 
+Yue 
+Si 
+Qi 
+Ta 
+Ma 
+Xie 
+Xian 
+Xian 
+Zhi 
+Qi 
+Zhi 
+Beng 
+Dui 
+Zhong 
+[?] 
+Yi 
+Shi 
+You 
+Zhi 
+Tiao 
+Fu 
+Fu 
+Mi 
+Zu 
+Zhi 
+Suan 
+Mei 
+Zuo 
+Qu 
+Hu 
+Zhu 
+Shen 
+Sui 
+Ci 
+Chai 
+Mi 
+Lu 
+Yu 
+Xiang 
+Wu 
+Tiao 
+Piao 
+Zhu 
+Gui 
+Xia 
+Zhi 
+Ji 
+Gao 
+Zhen 
+Gao 
+Shui 
+Jin 
+Chen 
+Gai 
+Kun 
+Di 
+Dao 
+Huo 
+Tao 
+Qi 
+Gu 
+Guan 
+Zui 
+Ling 
+Lu 
+Bing 
+Jin 
+Dao 
+Zhi 
+Lu 
+Shan 
+Bei 
+Zhe 
+Hui 
+You 
+Xi 
+Yin 
+Zi 
+Huo 
+Zhen 
+Fu 
+Yuan 
+Wu 
+Xian 
+Yang 
+Ti 
+Yi 
+Mei 
+Si 
+Di 
+[?] 
+Zhuo 
+Zhen 
+Yong 
+Ji 
+Gao 
+Tang 
+Si 
+Ma 
+Ta 
+[?] 
+Xuan 
+Qi 
+Yu 
+Xi 
+Ji 
+Si 
+Chan 
+Tan 
+Kuai 
+Sui 
+Li 
+Nong 
+Ni 
+Dao 
+Li 
+Rang 
+Yue 
+Ti 
+Zan 
+Lei 
+Rou 
+Yu 
+Yu 
+Chi 
+Xie 
+Qin 
+He 
+Tu 
+Xiu 
+Si 
+Ren 
+Tu 
+Zi 
+Cha 
+Gan 
+Yi 
+Xian 
+Bing 
+Nian 
+Qiu 
+Qiu 
+Chong 
+Fen 
+Hao 
+Yun 
+Ke 
+Miao 
+Zhi 
+Geng 
+Bi 
+Zhi 
+Yu 
+Mi 
+Ku 
+Ban 
+Pi 
+Ni 
+Li 
+You 
+Zu 
+Pi 
+Ba 
+Ling 
+Mo 
+Cheng 
+Nian 
+Qin 
+Yang 
+Zuo 
+Zhi 
+Zhi 
+Shu 
+Ju 
+Zi 
+Huo 
+Ji 
+Cheng 
+Tong 
+Zhi 
+Huo 
+He 
+Yin 
+Zi 
+Zhi 
+Jie 
+Ren 
+Du 
+Yi 
+Zhu 
+Hui 
+Nong 
+Fu 
+Xi 
+Kao 
+Lang 
+Fu 
+Ze 
+Shui 
+Lu 
+Kun 
+Gan 
+Geng 
+Ti 
+Cheng 
+Tu 
+Shao 
+Shui 
+Ya 
+Lun 
+Lu 
+Gu 
+Zuo 
+Ren 
+Zhun 
+Bang 
+Bai 
+Ji 
+Zhi 
+Zhi 
+Kun 
+Leng 
+Peng 
+Ke 
+Bing 
+Chou 
+Zu 
+Yu 
+Su 
+Lue 
+[?] 
+Yi 
+Xi 
+Bian 
+Ji 
+Fu 
+Bi 
+Nuo 
+Jie 
+Zhong 
+Zong 
+Xu 
+Cheng 
+Dao 
+Wen 
+Lian 
+Zi 
+Yu 
+Ji 
+Xu 
+Zhen 
+Zhi 
+Dao 
+Jia 
+Ji 
+Gao 
+Gao 
+Gu 
+Rong 
+Sui 
+You 
+Ji 
+Kang 
+Mu 
+Shan 
+Men 
+Zhi 
+Ji 
+Lu 
+Su 
+Ji 
+Ying 
+Wen 
+Qiu 
+Se 
+[?] 
+Yi 
+Huang 
+Qie 
+Ji 
+Sui 
+Xiao 
+Pu 
+Jiao 
+Zhuo 
+Tong 
+Sai 
+Lu 
+Sui 
+Nong 
+Se 
+Hui 
+Rang 
+Nuo 
+Yu 
+Bin 
+Ji 
+Tui 
+Wen 
+Cheng 
+Huo 
+Gong 
+Lu 
+Biao 
+[?] 
+Rang 
+Zhuo 
+Li 
+Zan 
+Xue 
+Wa 
+Jiu 
+Qiong 
+Xi 
+Qiong 
+Kong 
+Yu 
+Sen 
+Jing 
+Yao 
+Chuan 
+Zhun 
+Tu 
+Lao 
+Qie 
+Zhai 
+Yao 
+Bian 
+Bao 
+Yao 
+Bing 
+Wa 
+Zhu 
+Jiao 
+Qiao 
+Diao 
+Wu 
+Gui 
+Yao 
+Zhi 
+Chuang 
+Yao 
+Tiao 
+Jiao 
+Chuang 
+Jiong 
+Xiao 
+Cheng 
+Kou 
+Cuan 
+Wo 
+Dan 
+Ku 
+Ke 
+Zhui 
+Xu 
+Su 
+Guan 
+Kui 
+Dou 
+[?] 
+Yin 
+Wo 
+Wa 
+Ya 
+Yu 
+Ju 
+Qiong 
+Yao 
+Yao 
+Tiao 
+Chao 
+Yu 
+Tian 
+Diao 
+Ju 
+Liao 
+Xi 
+Wu 
+Kui 
+Chuang 
+Zhao 
+[?] 
+Kuan 
+Long 
+Cheng 
+Cui 
+Piao 
+Zao 
+Cuan 
+Qiao 
+Qiong 
+Dou 
+Zao 
+Long 
+Qie 
+Li 
+Chu 
+Shi 
+Fou 
+Qian 
+Chu 
+Hong 
+Qi 
+Qian 
+Gong 
+Shi 
+Shu 
+Miao 
+Ju 
+Zhan 
+Zhu 
+Ling 
+Long 
+Bing 
+Jing 
+Jing 
+Zhang 
+Yi 
+Si 
+Jun 
+Hong 
+Tong 
+Song 
+Jing 
+Diao 
+Yi 
+Shu 
+Jing 
+Qu 
+Jie 
+Ping 
+Duan 
+Shao 
+Zhuan 
+Ceng 
+Deng 
+Cui 
+Huai 
+Jing 
+Kan 
+Jing 
+Zhu 
+Zhu 
+Le 
+Peng 
+Yu 
+Chi 
+Gan 
+Mang 
+Zhu 
+Utsubo 
+Du 
+Ji 
+Xiao 
+Ba 
+Suan 
+Ji 
+Zhen 
+Zhao 
+Sun 
+Ya 
+Zhui 
+Yuan 
+Hu 
+Gang 
+Xiao 
+Cen 
+Pi 
+Bi 
+Jian 
+Yi 
+Dong 
+Shan 
+Sheng 
+Xia 
+Di 
+Zhu 
+Na 
+Chi 
+Gu 
+Li 
+Qie 
+Min 
+Bao 
+Tiao 
+Si 
+Fu 
+Ce 
+Ben 
+Pei 
+Da 
+Zi 
+Di 
+Ling 
+Ze 
+Nu 
+Fu 
+Gou 
+Fan 
+Jia 
+Ge 
+Fan 
+Shi 
+Mao 
+Po 
+Sey 
+Jian 
+Qiong 
+Long 
+Souke 
+Bian 
+Luo 
+Gui 
+Qu 
+Chi 
+Yin 
+Yao 
+Xian 
+Bi 
+Qiong 
+Gua 
+Deng 
+Jiao 
+Jin 
+Quan 
+Sun 
+Ru 
+Fa 
+Kuang 
+Zhu 
+Tong 
+Ji 
+Da 
+Xing 
+Ce 
+Zhong 
+Kou 
+Lai 
+Bi 
+Shai 
+Dang 
+Zheng 
+Ce 
+Fu 
+Yun 
+Tu 
+Pa 
+Li 
+Lang 
+Ju 
+Guan 
+Jian 
+Han 
+Tong 
+Xia 
+Zhi 
+Cheng 
+Suan 
+Shi 
+Zhu 
+Zuo 
+Xiao 
+Shao 
+Ting 
+Ce 
+Yan 
+Gao 
+Kuai 
+Gan 
+Chou 
+Kago 
+Gang 
+Yun 
+O 
+Qian 
+Xiao 
+Jian 
+Pu 
+Lai 
+Zou 
+Bi 
+Bi 
+Bi 
+Ge 
+Chi 
+Guai 
+Yu 
+Jian 
+Zhao 
+Gu 
+Chi 
+Zheng 
+Jing 
+Sha 
+Zhou 
+Lu 
+Bo 
+Ji 
+Lin 
+Suan 
+Jun 
+Fu 
+Zha 
+Gu 
+Kong 
+Qian 
+Quan 
+Jun 
+Chui 
+Guan 
+Yuan 
+Ce 
+Ju 
+Bo 
+Ze 
+Qie 
+Tuo 
+Luo 
+Dan 
+Xiao 
+Ruo 
+Jian 
+Xuan 
+Bian 
+Sun 
+Xiang 
+Xian 
+Ping 
+Zhen 
+Sheng 
+Hu 
+Shi 
+Zhu 
+Yue 
+Chun 
+Lu 
+Wu 
+Dong 
+Xiao 
+Ji 
+Jie 
+Huang 
+Xing 
+Mei 
+Fan 
+Chui 
+Zhuan 
+Pian 
+Feng 
+Zhu 
+Hong 
+Qie 
+Hou 
+Qiu 
+Miao 
+Qian 
+[?] 
+Kui 
+Sik 
+Lou 
+Yun 
+He 
+Tang 
+Yue 
+Chou 
+Gao 
+Fei 
+Ruo 
+Zheng 
+Gou 
+Nie 
+Qian 
+Xiao 
+Cuan 
+Gong 
+Pang 
+Du 
+Li 
+Bi 
+Zhuo 
+Chu 
+Shai 
+Chi 
+Zhu 
+Qiang 
+Long 
+Lan 
+Jian 
+Bu 
+Li 
+Hui 
+Bi 
+Di 
+Cong 
+Yan 
+Peng 
+Sen 
+Zhuan 
+Pai 
+Piao 
+Dou 
+Yu 
+Mie 
+Zhuan 
+Ze 
+Xi 
+Guo 
+Yi 
+Hu 
+Chan 
+Kou 
+Cu 
+Ping 
+Chou 
+Ji 
+Gui 
+Su 
+Lou 
+Zha 
+Lu 
+Nian 
+Suo 
+Cuan 
+Sasara 
+Suo 
+Le 
+Duan 
+Yana 
+Xiao 
+Bo 
+Mi 
+Si 
+Dang 
+Liao 
+Dan 
+Dian 
+Fu 
+Jian 
+Min 
+Kui 
+Dai 
+Qiao 
+Deng 
+Huang 
+Sun 
+Lao 
+Zan 
+Xiao 
+Du 
+Shi 
+Zan 
+[?] 
+Pai 
+Hata 
+Pai 
+Gan 
+Ju 
+Du 
+Lu 
+Yan 
+Bo 
+Dang 
+Sai 
+Ke 
+Long 
+Qian 
+Lian 
+Bo 
+Zhou 
+Lai 
+[?] 
+Lan 
+Kui 
+Yu 
+Yue 
+Hao 
+Zhen 
+Tai 
+Ti 
+Mi 
+Chou 
+Ji 
+[?] 
+Hata 
+Teng 
+Zhuan 
+Zhou 
+Fan 
+Sou 
+Zhou 
+Kuji 
+Zhuo 
+Teng 
+Lu 
+Lu 
+Jian 
+Tuo 
+Ying 
+Yu 
+Lai 
+Long 
+Shinshi 
+Lian 
+Lan 
+Qian 
+Yue 
+Zhong 
+Qu 
+Lian 
+Bian 
+Duan 
+Zuan 
+Li 
+Si 
+Luo 
+Ying 
+Yue 
+Zhuo 
+Xu 
+Mi 
+Di 
+Fan 
+Shen 
+Zhe 
+Shen 
+Nu 
+Xie 
+Lei 
+Xian 
+Zi 
+Ni 
+Cun 
+[?] 
+Qian 
+Kume 
+Bi 
+Ban 
+Wu 
+Sha 
+Kang 
+Rou 
+Fen 
+Bi 
+Cui 
+[?] 
+Li 
+Chi 
+Nukamiso 
+Ro 
+Ba 
+Li 
+Gan 
+Ju 
+Po 
+Mo 
+Cu 
+Nian 
+Zhou 
+Li 
+Su 
+Tiao 
+Li 
+Qi 
+Su 
+Hong 
+Tong 
+Zi 
+Ce 
+Yue 
+Zhou 
+Lin 
+Zhuang 
+Bai 
+[?] 
+Fen 
+Ji 
+[?] 
+Sukumo 
+Liang 
+Xian 
+Fu 
+Liang 
+Can 
+Geng 
+Li 
+Yue 
+Lu 
+Ju 
+Qi 
+Cui 
+Bai 
+Zhang 
+Lin 
+Zong 
+Jing 
+Guo 
+Kouji 
+San 
+San 
+Tang 
+Bian 
+Rou 
+Mian 
+Hou 
+Xu 
+Zong 
+Hu 
+Jian 
+Zan 
+Ci 
+Li 
+Xie 
+Fu 
+Ni 
+Bei 
+Gu 
+Xiu 
+Gao 
+Tang 
+Qiu 
+Sukumo 
+Cao 
+Zhuang 
+Tang 
+Mi 
+San 
+Fen 
+Zao 
+Kang 
+Jiang 
+Mo 
+San 
+San 
+Nuo 
+Xi 
+Liang 
+Jiang 
+Kuai 
+Bo 
+Huan 
+[?] 
+Zong 
+Xian 
+Nuo 
+Tuan 
+Nie 
+Li 
+Zuo 
+Di 
+Nie 
+Tiao 
+Lan 
+Mi 
+Jiao 
+Jiu 
+Xi 
+Gong 
+Zheng 
+Jiu 
+You 
+Ji 
+Cha 
+Zhou 
+Xun 
+Yue 
+Hong 
+Yu 
+He 
+Wan 
+Ren 
+Wen 
+Wen 
+Qiu 
+Na 
+Zi 
+Tou 
+Niu 
+Fou 
+Jie 
+Shu 
+Chun 
+Pi 
+Yin 
+Sha 
+Hong 
+Zhi 
+Ji 
+Fen 
+Yun 
+Ren 
+Dan 
+Jin 
+Su 
+Fang 
+Suo 
+Cui 
+Jiu 
+Zha 
+Kinu 
+Jin 
+Fu 
+Zhi 
+Ci 
+Zi 
+Chou 
+Hong 
+Zha 
+Lei 
+Xi 
+Fu 
+Xie 
+Shen 
+Bei 
+Zhu 
+Qu 
+Ling 
+Zhu 
+Shao 
+Gan 
+Yang 
+Fu 
+Tuo 
+Zhen 
+Dai 
+Zhuo 
+Shi 
+Zhong 
+Xian 
+Zu 
+Jiong 
+Ban 
+Ju 
+Mo 
+Shu 
+Zui 
+Wata 
+Jing 
+Ren 
+Heng 
+Xie 
+Jie 
+Zhu 
+Chou 
+Gua 
+Bai 
+Jue 
+Kuang 
+Hu 
+Ci 
+Geng 
+Geng 
+Tao 
+Xie 
+Ku 
+Jiao 
+Quan 
+Gai 
+Luo 
+Xuan 
+Bing 
+Xian 
+Fu 
+Gei 
+Tong 
+Rong 
+Tiao 
+Yin 
+Lei 
+Xie 
+Quan 
+Xu 
+Lun 
+Die 
+Tong 
+Si 
+Jiang 
+Xiang 
+Hui 
+Jue 
+Zhi 
+Jian 
+Juan 
+Chi 
+Mian 
+Zhen 
+Lu 
+Cheng 
+Qiu 
+Shu 
+Bang 
+Tong 
+Xiao 
+Wan 
+Qin 
+Geng 
+Xiu 
+Ti 
+Xiu 
+Xie 
+Hong 
+Xi 
+Fu 
+Ting 
+Sui 
+Dui 
+Kun 
+Fu 
+Jing 
+Hu 
+Zhi 
+Yan 
+Jiong 
+Feng 
+Ji 
+Sok 
+Kase 
+Zong 
+Lin 
+Duo 
+Li 
+Lu 
+Liang 
+Chou 
+Quan 
+Shao 
+Qi 
+Qi 
+Zhun 
+Qi 
+Wan 
+Qian 
+Xian 
+Shou 
+Wei 
+Qi 
+Tao 
+Wan 
+Gang 
+Wang 
+Beng 
+Zhui 
+Cai 
+Guo 
+Cui 
+Lun 
+Liu 
+Qi 
+Zhan 
+Bei 
+Chuo 
+Ling 
+Mian 
+Qi 
+Qie 
+Tan 
+Zong 
+Gun 
+Zou 
+Yi 
+Zi 
+Xing 
+Liang 
+Jin 
+Fei 
+Rui 
+Min 
+Yu 
+Zong 
+Fan 
+Lu 
+Xu 
+Yingl 
+Zhang 
+Kasuri 
+Xu 
+Xiang 
+Jian 
+Ke 
+Xian 
+Ruan 
+Mian 
+Qi 
+Duan 
+Zhong 
+Di 
+Min 
+Miao 
+Yuan 
+Xie 
+Bao 
+Si 
+Qiu 
+Bian 
+Huan 
+Geng 
+Cong 
+Mian 
+Wei 
+Fu 
+Wei 
+Yu 
+Gou 
+Miao 
+Xie 
+Lian 
+Zong 
+Bian 
+Yun 
+Yin 
+Ti 
+Gua 
+Zhi 
+Yun 
+Cheng 
+Chan 
+Dai 
+Xia 
+Yuan 
+Zong 
+Xu 
+Nawa 
+Odoshi 
+Geng 
+Sen 
+Ying 
+Jin 
+Yi 
+Zhui 
+Ni 
+Bang 
+Gu 
+Pan 
+Zhou 
+Jian 
+Cuo 
+Quan 
+Shuang 
+Yun 
+Xia 
+Shuai 
+Xi 
+Rong 
+Tao 
+Fu 
+Yun 
+Zhen 
+Gao 
+Ru 
+Hu 
+Zai 
+Teng 
+Xian 
+Su 
+Zhen 
+Zong 
+Tao 
+Horo 
+Cai 
+Bi 
+Feng 
+Cu 
+Li 
+Suo 
+Yin 
+Xi 
+Zong 
+Lei 
+Zhuan 
+Qian 
+Man 
+Zhi 
+Lu 
+Mo 
+Piao 
+Lian 
+Mi 
+Xuan 
+Zong 
+Ji 
+Shan 
+Sui 
+Fan 
+Shuai 
+Beng 
+Yi 
+Sao 
+Mou 
+Zhou 
+Qiang 
+Hun 
+Sem 
+Xi 
+Jung 
+Xiu 
+Ran 
+Xuan 
+Hui 
+Qiao 
+Zeng 
+Zuo 
+Zhi 
+Shan 
+San 
+Lin 
+Yu 
+Fan 
+Liao 
+Chuo 
+Zun 
+Jian 
+Rao 
+Chan 
+Rui 
+Xiu 
+Hui 
+Hua 
+Zuan 
+Xi 
+Qiang 
+Un 
+Da 
+Sheng 
+Hui 
+Xi 
+Se 
+Jian 
+Jiang 
+Huan 
+Zao 
+Cong 
+Jie 
+Jiao 
+Bo 
+Chan 
+Yi 
+Nao 
+Sui 
+Yi 
+Shai 
+Xu 
+Ji 
+Bin 
+Qian 
+Lan 
+Pu 
+Xun 
+Zuan 
+Qi 
+Peng 
+Li 
+Mo 
+Lei 
+Xie 
+Zuan 
+Kuang 
+You 
+Xu 
+Lei 
+Xian 
+Chan 
+Kou 
+Lu 
+Chan 
+Ying 
+Cai 
+Xiang 
+Xian 
+Zui 
+Zuan 
+Luo 
+Xi 
+Dao 
+Lan 
+Lei 
+Lian 
+Si 
+Jiu 
+Yu 
+Hong 
+Zhou 
+Xian 
+He 
+Yue 
+Ji 
+Wan 
+Kuang 
+Ji 
+Ren 
+Wei 
+Yun 
+Hong 
+Chun 
+Pi 
+Sha 
+Gang 
+Na 
+Ren 
+Zong 
+Lun 
+Fen 
+Zhi 
+Wen 
+Fang 
+Zhu 
+Yin 
+Niu 
+Shu 
+Xian 
+Gan 
+Xie 
+Fu 
+Lian 
+Zu 
+Shen 
+Xi 
+Zhi 
+Zhong 
+Zhou 
+Ban 
+Fu 
+Zhuo 
+Shao 
+Yi 
+Jing 
+Dai 
+Bang 
+Rong 
+Jie 
+Ku 
+Rao 
+Die 
+Heng 
+Hui 
+Gei 
+Xuan 
+Jiang 
+Luo 
+Jue 
+Jiao 
+Tong 
+Geng 
+Xiao 
+Juan 
+Xiu 
+Xi 
+Sui 
+Tao 
+Ji 
+Ti 
+Ji 
+Xu 
+Ling 
+[?] 
+Xu 
+Qi 
+Fei 
+Chuo 
+Zhang 
+Gun 
+Sheng 
+Wei 
+Mian 
+Shou 
+Beng 
+Chou 
+Tao 
+Liu 
+Quan 
+Zong 
+Zhan 
+Wan 
+Lu 
+Zhui 
+Zi 
+Ke 
+Xiang 
+Jian 
+Mian 
+Lan 
+Ti 
+Miao 
+Qi 
+Yun 
+Hui 
+Si 
+Duo 
+Duan 
+Bian 
+Xian 
+Gou 
+Zhui 
+Huan 
+Di 
+Lu 
+Bian 
+Min 
+Yuan 
+Jin 
+Fu 
+Ru 
+Zhen 
+Feng 
+Shuai 
+Gao 
+Chan 
+Li 
+Yi 
+Jian 
+Bin 
+Piao 
+Man 
+Lei 
+Ying 
+Suo 
+Mou 
+Sao 
+Xie 
+Liao 
+Shan 
+Zeng 
+Jiang 
+Qian 
+Zao 
+Huan 
+Jiao 
+Zuan 
+Fou 
+Xie 
+Gang 
+Fou 
+Que 
+Fou 
+Kaakeru 
+Bo 
+Ping 
+Hou 
+[?] 
+Gang 
+Ying 
+Ying 
+Qing 
+Xia 
+Guan 
+Zun 
+Tan 
+Chang 
+Qi 
+Weng 
+Ying 
+Lei 
+Tan 
+Lu 
+Guan 
+Wang 
+Wang 
+Gang 
+Wang 
+Han 
+[?] 
+Luo 
+Fu 
+Mi 
+Fa 
+Gu 
+Zhu 
+Ju 
+Mao 
+Gu 
+Min 
+Gang 
+Ba 
+Gua 
+Ti 
+Juan 
+Fu 
+Lin 
+Yan 
+Zhao 
+Zui 
+Gua 
+Zhuo 
+Yu 
+Zhi 
+An 
+Fa 
+Nan 
+Shu 
+Si 
+Pi 
+Ma 
+Liu 
+Ba 
+Fa 
+Li 
+Chao 
+Wei 
+Bi 
+Ji 
+Zeng 
+Tong 
+Liu 
+Ji 
+Juan 
+Mi 
+Zhao 
+Luo 
+Pi 
+Ji 
+Ji 
+Luan 
+Yang 
+Mie 
+Qiang 
+Ta 
+Mei 
+Yang 
+You 
+You 
+Fen 
+Ba 
+Gao 
+Yang 
+Gu 
+Qiang 
+Zang 
+Gao 
+Ling 
+Yi 
+Zhu 
+Di 
+Xiu 
+Qian 
+Yi 
+Xian 
+Rong 
+Qun 
+Qun 
+Qian 
+Huan 
+Zui 
+Xian 
+Yi 
+Yashinau 
+Qiang 
+Xian 
+Yu 
+Geng 
+Jie 
+Tang 
+Yuan 
+Xi 
+Fan 
+Shan 
+Fen 
+Shan 
+Lian 
+Lei 
+Geng 
+Nou 
+Qiang 
+Chan 
+Yu 
+Gong 
+Yi 
+Chong 
+Weng 
+Fen 
+Hong 
+Chi 
+Chi 
+Cui 
+Fu 
+Xia 
+Pen 
+Yi 
+La 
+Yi 
+Pi 
+Ling 
+Liu 
+Zhi 
+Qu 
+Xi 
+Xie 
+Xiang 
+Xi 
+Xi 
+Qi 
+Qiao 
+Hui 
+Hui 
+Xiao 
+Se 
+Hong 
+Jiang 
+Di 
+Cui 
+Fei 
+Tao 
+Sha 
+Chi 
+Zhu 
+Jian 
+Xuan 
+Shi 
+Pian 
+Zong 
+Wan 
+Hui 
+Hou 
+He 
+He 
+Han 
+Ao 
+Piao 
+Yi 
+Lian 
+Qu 
+[?] 
+Lin 
+Pen 
+Qiao 
+Ao 
+Fan 
+Yi 
+Hui 
+Xuan 
+Dao 
+Yao 
+Lao 
+[?] 
+Kao 
+Mao 
+Zhe 
+Qi 
+Gou 
+Gou 
+Gou 
+Die 
+Die 
+Er 
+Shua 
+Ruan 
+Er 
+Nai 
+Zhuan 
+Lei 
+Ting 
+Zi 
+Geng 
+Chao 
+Hao 
+Yun 
+Pa 
+Pi 
+Chi 
+Si 
+Chu 
+Jia 
+Ju 
+He 
+Chu 
+Lao 
+Lun 
+Ji 
+Tang 
+Ou 
+Lou 
+Nou 
+Gou 
+Pang 
+Ze 
+Lou 
+Ji 
+Lao 
+Huo 
+You 
+Mo 
+Huai 
+Er 
+Zhe 
+Ting 
+Ye 
+Da 
+Song 
+Qin 
+Yun 
+Chi 
+Dan 
+Dan 
+Hong 
+Geng 
+Zhi 
+[?] 
+Nie 
+Dan 
+Zhen 
+Che 
+Ling 
+Zheng 
+You 
+Wa 
+Liao 
+Long 
+Zhi 
+Ning 
+Tiao 
+Er 
+Ya 
+Die 
+Gua 
+[?] 
+Lian 
+Hao 
+Sheng 
+Lie 
+Pin 
+Jing 
+Ju 
+Bi 
+Di 
+Guo 
+Wen 
+Xu 
+Ping 
+Cong 
+Shikato 
+[?] 
+Ting 
+Yu 
+Cong 
+Kui 
+Tsuraneru 
+Kui 
+Cong 
+Lian 
+Weng 
+Kui 
+Lian 
+Lian 
+Cong 
+Ao 
+Sheng 
+Song 
+Ting 
+Kui 
+Nie 
+Zhi 
+Dan 
+Ning 
+Qie 
+Ji 
+Ting 
+Ting 
+Long 
+Yu 
+Yu 
+Zhao 
+Si 
+Su 
+Yi 
+Su 
+Si 
+Zhao 
+Zhao 
+Rou 
+Yi 
+Le 
+Ji 
+Qiu 
+Ken 
+Cao 
+Ge 
+Di 
+Huan 
+Huang 
+Yi 
+Ren 
+Xiao 
+Ru 
+Zhou 
+Yuan 
+Du 
+Gang 
+Rong 
+Gan 
+Cha 
+Wo 
+Chang 
+Gu 
+Zhi 
+Han 
+Fu 
+Fei 
+Fen 
+Pei 
+Pang 
+Jian 
+Fang 
+Zhun 
+You 
+Na 
+Hang 
+Ken 
+Ran 
+Gong 
+Yu 
+Wen 
+Yao 
+Jin 
+Pi 
+Qian 
+Xi 
+Xi 
+Fei 
+Ken 
+Jing 
+Tai 
+Shen 
+Zhong 
+Zhang 
+Xie 
+Shen 
+Wei 
+Zhou 
+Die 
+Dan 
+Fei 
+Ba 
+Bo 
+Qu 
+Tian 
+Bei 
+Gua 
+Tai 
+Zi 
+Ku 
+Zhi 
+Ni 
+Ping 
+Zi 
+Fu 
+Pang 
+Zhen 
+Xian 
+Zuo 
+Pei 
+Jia 
+Sheng 
+Zhi 
+Bao 
+Mu 
+Qu 
+Hu 
+Ke 
+Yi 
+Yin 
+Xu 
+Yang 
+Long 
+Dong 
+Ka 
+Lu 
+Jing 
+Nu 
+Yan 
+Pang 
+Kua 
+Yi 
+Guang 
+Gai 
+Ge 
+Dong 
+Zhi 
+Xiao 
+Xiong 
+Xiong 
+Er 
+E 
+Xing 
+Pian 
+Neng 
+Zi 
+Gui 
+Cheng 
+Tiao 
+Zhi 
+Cui 
+Mei 
+Xie 
+Cui 
+Xie 
+Mo 
+Mai 
+Ji 
+Obiyaakasu 
+[?] 
+Kuai 
+Sa 
+Zang 
+Qi 
+Nao 
+Mi 
+Nong 
+Luan 
+Wan 
+Bo 
+Wen 
+Guan 
+Qiu 
+Jiao 
+Jing 
+Rou 
+Heng 
+Cuo 
+Lie 
+Shan 
+Ting 
+Mei 
+Chun 
+Shen 
+Xie 
+De 
+Zui 
+Cu 
+Xiu 
+Xin 
+Tuo 
+Pao 
+Cheng 
+Nei 
+Fu 
+Dou 
+Tuo 
+Niao 
+Noy 
+Pi 
+Gu 
+Gua 
+Li 
+Lian 
+Zhang 
+Cui 
+Jie 
+Liang 
+Zhou 
+Pi 
+Biao 
+Lun 
+Pian 
+Guo 
+Kui 
+Chui 
+Dan 
+Tian 
+Nei 
+Jing 
+Jie 
+La 
+Yi 
+An 
+Ren 
+Shen 
+Chuo 
+Fu 
+Fu 
+Ju 
+Fei 
+Qiang 
+Wan 
+Dong 
+Pi 
+Guo 
+Zong 
+Ding 
+Wu 
+Mei 
+Ruan 
+Zhuan 
+Zhi 
+Cou 
+Gua 
+Ou 
+Di 
+An 
+Xing 
+Nao 
+Yu 
+Chuan 
+Nan 
+Yun 
+Zhong 
+Rou 
+E 
+Sai 
+Tu 
+Yao 
+Jian 
+Wei 
+Jiao 
+Yu 
+Jia 
+Duan 
+Bi 
+Chang 
+Fu 
+Xian 
+Ni 
+Mian 
+Wa 
+Teng 
+Tui 
+Bang 
+Qian 
+Lu 
+Wa 
+Sou 
+Tang 
+Su 
+Zhui 
+Ge 
+Yi 
+Bo 
+Liao 
+Ji 
+Pi 
+Xie 
+Gao 
+Lu 
+Bin 
+Ou 
+Chang 
+Lu 
+Guo 
+Pang 
+Chuai 
+Piao 
+Jiang 
+Fu 
+Tang 
+Mo 
+Xi 
+Zhuan 
+Lu 
+Jiao 
+Ying 
+Lu 
+Zhi 
+Tara 
+Chun 
+Lian 
+Tong 
+Peng 
+Ni 
+Zha 
+Liao 
+Cui 
+Gui 
+Xiao 
+Teng 
+Fan 
+Zhi 
+Jiao 
+Shan 
+Wu 
+Cui 
+Run 
+Xiang 
+Sui 
+Fen 
+Ying 
+Tan 
+Zhua 
+Dan 
+Kuai 
+Nong 
+Tun 
+Lian 
+Bi 
+Yong 
+Jue 
+Chu 
+Yi 
+Juan 
+La 
+Lian 
+Sao 
+Tun 
+Gu 
+Qi 
+Cui 
+Bin 
+Xun 
+Ru 
+Huo 
+Zang 
+Xian 
+Biao 
+Xing 
+Kuan 
+La 
+Yan 
+Lu 
+Huo 
+Zang 
+Luo 
+Qu 
+Zang 
+Luan 
+Ni 
+Zang 
+Chen 
+Qian 
+Wo 
+Guang 
+Zang 
+Lin 
+Guang 
+Zi 
+Jiao 
+Nie 
+Chou 
+Ji 
+Gao 
+Chou 
+Mian 
+Nie 
+Zhi 
+Zhi 
+Ge 
+Jian 
+Die 
+Zhi 
+Xiu 
+Tai 
+Zhen 
+Jiu 
+Xian 
+Yu 
+Cha 
+Yao 
+Yu 
+Chong 
+Xi 
+Xi 
+Jiu 
+Yu 
+Yu 
+Xing 
+Ju 
+Jiu 
+Xin 
+She 
+She 
+Yadoru 
+Jiu 
+Shi 
+Tan 
+Shu 
+Shi 
+Tian 
+Dan 
+Pu 
+Pu 
+Guan 
+Hua 
+Tan 
+Chuan 
+Shun 
+Xia 
+Wu 
+Zhou 
+Dao 
+Gang 
+Shan 
+Yi 
+[?] 
+Pa 
+Tai 
+Fan 
+Ban 
+Chuan 
+Hang 
+Fang 
+Ban 
+Que 
+Hesaki 
+Zhong 
+Jian 
+Cang 
+Ling 
+Zhu 
+Ze 
+Duo 
+Bo 
+Xian 
+Ge 
+Chuan 
+Jia 
+Lu 
+Hong 
+Pang 
+Xi 
+[?] 
+Fu 
+Zao 
+Feng 
+Li 
+Shao 
+Yu 
+Lang 
+Ting 
+[?] 
+Wei 
+Bo 
+Meng 
+Nian 
+Ju 
+Huang 
+Shou 
+Zong 
+Bian 
+Mao 
+Die 
+[?] 
+Bang 
+Cha 
+Yi 
+Sao 
+Cang 
+Cao 
+Lou 
+Dai 
+Sori 
+Yao 
+Tong 
+Yofune 
+Dang 
+Tan 
+Lu 
+Yi 
+Jie 
+Jian 
+Huo 
+Meng 
+Qi 
+Lu 
+Lu 
+Chan 
+Shuang 
+Gen 
+Liang 
+Jian 
+Jian 
+Se 
+Yan 
+Fu 
+Ping 
+Yan 
+Yan 
+Cao 
+Cao 
+Yi 
+Le 
+Ting 
+Qiu 
+Ai 
+Nai 
+Tiao 
+Jiao 
+Jie 
+Peng 
+Wan 
+Yi 
+Chai 
+Mian 
+Mie 
+Gan 
+Qian 
+Yu 
+Yu 
+Shuo 
+Qiong 
+Tu 
+Xia 
+Qi 
+Mang 
+Zi 
+Hui 
+Sui 
+Zhi 
+Xiang 
+Bi 
+Fu 
+Tun 
+Wei 
+Wu 
+Zhi 
+Qi 
+Shan 
+Wen 
+Qian 
+Ren 
+Fou 
+Kou 
+Jie 
+Lu 
+Xu 
+Ji 
+Qin 
+Qi 
+Yuan 
+Fen 
+Ba 
+Rui 
+Xin 
+Ji 
+Hua 
+Hua 
+Fang 
+Wu 
+Jue 
+Gou 
+Zhi 
+Yun 
+Qin 
+Ao 
+Chu 
+Mao 
+Ya 
+Fei 
+Reng 
+Hang 
+Cong 
+Yin 
+You 
+Bian 
+Yi 
+Susa 
+Wei 
+Li 
+Pi 
+E 
+Xian 
+Chang 
+Cang 
+Meng 
+Su 
+Yi 
+Yuan 
+Ran 
+Ling 
+Tai 
+Tiao 
+Di 
+Miao 
+Qiong 
+Li 
+Yong 
+Ke 
+Mu 
+Pei 
+Bao 
+Gou 
+Min 
+Yi 
+Yi 
+Ju 
+Pi 
+Ruo 
+Ku 
+Zhu 
+Ni 
+Bo 
+Bing 
+Shan 
+Qiu 
+Yao 
+Xian 
+Ben 
+Hong 
+Ying 
+Zha 
+Dong 
+Ju 
+Die 
+Nie 
+Gan 
+Hu 
+Ping 
+Mei 
+Fu 
+Sheng 
+Gu 
+Bi 
+Wei 
+Fu 
+Zhuo 
+Mao 
+Fan 
+Qie 
+Mao 
+Mao 
+Ba 
+Zi 
+Mo 
+Zi 
+Di 
+Chi 
+Ji 
+Jing 
+Long 
+[?] 
+Niao 
+[?] 
+Xue 
+Ying 
+Qiong 
+Ge 
+Ming 
+Li 
+Rong 
+Yin 
+Gen 
+Qian 
+Chai 
+Chen 
+Yu 
+Xiu 
+Zi 
+Lie 
+Wu 
+Ji 
+Kui 
+Ce 
+Chong 
+Ci 
+Gou 
+Guang 
+Mang 
+Chi 
+Jiao 
+Jiao 
+Fu 
+Yu 
+Zhu 
+Zi 
+Jiang 
+Hui 
+Yin 
+Cha 
+Fa 
+Rong 
+Ru 
+Chong 
+Mang 
+Tong 
+Zhong 
+[?] 
+Zhu 
+Xun 
+Huan 
+Kua 
+Quan 
+Gai 
+Da 
+Jing 
+Xing 
+Quan 
+Cao 
+Jing 
+Er 
+An 
+Shou 
+Chi 
+Ren 
+Jian 
+Ti 
+Huang 
+Ping 
+Li 
+Jin 
+Lao 
+Shu 
+Zhuang 
+Da 
+Jia 
+Rao 
+Bi 
+Ze 
+Qiao 
+Hui 
+Qi 
+Dang 
+[?] 
+Rong 
+Hun 
+Ying 
+Luo 
+Ying 
+Xun 
+Jin 
+Sun 
+Yin 
+Mai 
+Hong 
+Zhou 
+Yao 
+Du 
+Wei 
+Chu 
+Dou 
+Fu 
+Ren 
+Yin 
+He 
+Bi 
+Bu 
+Yun 
+Di 
+Tu 
+Sui 
+Sui 
+Cheng 
+Chen 
+Wu 
+Bie 
+Xi 
+Geng 
+Li 
+Fu 
+Zhu 
+Mo 
+Li 
+Zhuang 
+Ji 
+Duo 
+Qiu 
+Sha 
+Suo 
+Chen 
+Feng 
+Ju 
+Mei 
+Meng 
+Xing 
+Jing 
+Che 
+Xin 
+Jun 
+Yan 
+Ting 
+Diao 
+Cuo 
+Wan 
+Han 
+You 
+Cuo 
+Jia 
+Wang 
+You 
+Niu 
+Shao 
+Xian 
+Lang 
+Fu 
+E 
+Mo 
+Wen 
+Jie 
+Nan 
+Mu 
+Kan 
+Lai 
+Lian 
+Shi 
+Wo 
+Usagi 
+Lian 
+Huo 
+You 
+Ying 
+Ying 
+Nuc 
+Chun 
+Mang 
+Mang 
+Ci 
+Wan 
+Jing 
+Di 
+Qu 
+Dong 
+Jian 
+Zou 
+Gu 
+La 
+Lu 
+Ju 
+Wei 
+Jun 
+Nie 
+Kun 
+He 
+Pu 
+Zi 
+Gao 
+Guo 
+Fu 
+Lun 
+Chang 
+Chou 
+Song 
+Chui 
+Zhan 
+Men 
+Cai 
+Ba 
+Li 
+Tu 
+Bo 
+Han 
+Bao 
+Qin 
+Juan 
+Xi 
+Qin 
+Di 
+Jie 
+Pu 
+Dang 
+Jin 
+Zhao 
+Tai 
+Geng 
+Hua 
+Gu 
+Ling 
+Fei 
+Jin 
+An 
+Wang 
+Beng 
+Zhou 
+Yan 
+Ju 
+Jian 
+Lin 
+Tan 
+Shu 
+Tian 
+Dao 
+Hu 
+Qi 
+He 
+Cui 
+Tao 
+Chun 
+Bei 
+Chang 
+Huan 
+Fei 
+Lai 
+Qi 
+Meng 
+Ping 
+Wei 
+Dan 
+Sha 
+Huan 
+Yan 
+Yi 
+Tiao 
+Qi 
+Wan 
+Ce 
+Nai 
+Kutabireru 
+Tuo 
+Jiu 
+Tie 
+Luo 
+[?] 
+[?] 
+Meng 
+[?] 
+Yaji 
+[?] 
+Ying 
+Ying 
+Ying 
+Xiao 
+Sa 
+Qiu 
+Ke 
+Xiang 
+Wan 
+Yu 
+Yu 
+Fu 
+Lian 
+Xuan 
+Yuan 
+Nan 
+Ze 
+Wo 
+Chun 
+Xiao 
+Yu 
+Pian 
+Mao 
+An 
+E 
+Luo 
+Ying 
+Huo 
+Gua 
+Jiang 
+Mian 
+Zuo 
+Zuo 
+Ju 
+Bao 
+Rou 
+Xi 
+Xie 
+An 
+Qu 
+Jian 
+Fu 
+Lu 
+Jing 
+Pen 
+Feng 
+Hong 
+Hong 
+Hou 
+Yan 
+Tu 
+Zhu 
+Zi 
+Xiang 
+Shen 
+Ge 
+Jie 
+Jing 
+Mi 
+Huang 
+Shen 
+Pu 
+Gai 
+Dong 
+Zhou 
+Qian 
+Wei 
+Bo 
+Wei 
+Pa 
+Ji 
+Hu 
+Zang 
+Jia 
+Duan 
+Yao 
+Jun 
+Cong 
+Quan 
+Wei 
+Xian 
+Kui 
+Ting 
+Hun 
+Xi 
+Shi 
+Qi 
+Lan 
+Zong 
+Yao 
+Yuan 
+Mei 
+Yun 
+Shu 
+Di 
+Zhuan 
+Guan 
+Sukumo 
+Xue 
+Chan 
+Kai 
+Kui 
+[?] 
+Jiang 
+Lou 
+Wei 
+Pai 
+[?] 
+Sou 
+Yin 
+Shi 
+Chun 
+Shi 
+Yun 
+Zhen 
+Lang 
+Nu 
+Meng 
+He 
+Que 
+Suan 
+Yuan 
+Li 
+Ju 
+Xi 
+Pang 
+Chu 
+Xu 
+Tu 
+Liu 
+Wo 
+Zhen 
+Qian 
+Zu 
+Po 
+Cuo 
+Yuan 
+Chu 
+Yu 
+Kuai 
+Pan 
+Pu 
+Pu 
+Na 
+Shuo 
+Xi 
+Fen 
+Yun 
+Zheng 
+Jian 
+Ji 
+Ruo 
+Cang 
+En 
+Mi 
+Hao 
+Sun 
+Zhen 
+Ming 
+Sou 
+Xu 
+Liu 
+Xi 
+Gu 
+Lang 
+Rong 
+Weng 
+Gai 
+Cuo 
+Shi 
+Tang 
+Luo 
+Ru 
+Suo 
+Xian 
+Bei 
+Yao 
+Gui 
+Bi 
+Zong 
+Gun 
+Za 
+Xiu 
+Ce 
+Hai 
+Lan 
+[?] 
+Ji 
+Li 
+Can 
+Lang 
+Yu 
+[?] 
+Ying 
+Mo 
+Diao 
+Tiao 
+Mao 
+Tong 
+Zhu 
+Peng 
+An 
+Lian 
+Cong 
+Xi 
+Ping 
+Qiu 
+Jin 
+Chun 
+Jie 
+Wei 
+Tui 
+Cao 
+Yu 
+Yi 
+Ji 
+Liao 
+Bi 
+Lu 
+Su 
+Bu 
+Zhang 
+Luo 
+Jiang 
+Man 
+Yan 
+Ling 
+Ji 
+Piao 
+Gun 
+Han 
+Di 
+Su 
+Lu 
+She 
+Shang 
+Di 
+Mie 
+Xun 
+Man 
+Bo 
+Di 
+Cuo 
+Zhe 
+Sen 
+Xuan 
+Wei 
+Hu 
+Ao 
+Mi 
+Lou 
+Cu 
+Zhong 
+Cai 
+Po 
+Jiang 
+Mi 
+Cong 
+Niao 
+Hui 
+Jun 
+Yin 
+Jian 
+Yan 
+Shu 
+Yin 
+Kui 
+Chen 
+Hu 
+Sha 
+Kou 
+Qian 
+Ma 
+Zang 
+Sonoko 
+Qiang 
+Dou 
+Lian 
+Lin 
+Kou 
+Ai 
+Bi 
+Li 
+Wei 
+Ji 
+Xun 
+Sheng 
+Fan 
+Meng 
+Ou 
+Chan 
+Dian 
+Xun 
+Jiao 
+Rui 
+Rui 
+Lei 
+Yu 
+Qiao 
+Chu 
+Hua 
+Jian 
+Mai 
+Yun 
+Bao 
+You 
+Qu 
+Lu 
+Rao 
+Hui 
+E 
+Teng 
+Fei 
+Jue 
+Zui 
+Fa 
+Ru 
+Fen 
+Kui 
+Shun 
+Rui 
+Ya 
+Xu 
+Fu 
+Jue 
+Dang 
+Wu 
+Tong 
+Si 
+Xiao 
+Xi 
+Long 
+Yun 
+[?] 
+Qi 
+Jian 
+Yun 
+Sun 
+Ling 
+Yu 
+Xia 
+Yong 
+Ji 
+Hong 
+Si 
+Nong 
+Lei 
+Xuan 
+Yun 
+Yu 
+Xi 
+Hao 
+Bo 
+Hao 
+Ai 
+Wei 
+Hui 
+Wei 
+Ji 
+Ci 
+Xiang 
+Luan 
+Mie 
+Yi 
+Leng 
+Jiang 
+Can 
+Shen 
+Qiang 
+Lian 
+Ke 
+Yuan 
+Da 
+Ti 
+Tang 
+Xie 
+Bi 
+Zhan 
+Sun 
+Lian 
+Fan 
+Ding 
+Jie 
+Gu 
+Xie 
+Shu 
+Jian 
+Kao 
+Hong 
+Sa 
+Xin 
+Xun 
+Yao 
+Hie 
+Sou 
+Shu 
+Xun 
+Dui 
+Pin 
+Wei 
+Neng 
+Chou 
+Mai 
+Ru 
+Piao 
+Tai 
+Qi 
+Zao 
+Chen 
+Zhen 
+Er 
+Ni 
+Ying 
+Gao 
+Cong 
+Xiao 
+Qi 
+Fa 
+Jian 
+Xu 
+Kui 
+Jie 
+Bian 
+Diao 
+Mi 
+Lan 
+Jin 
+Cang 
+Miao 
+Qiong 
+Qie 
+Xian 
+[?] 
+Ou 
+Xian 
+Su 
+Lu 
+Yi 
+Xu 
+Xie 
+Li 
+Yi 
+La 
+Lei 
+Xiao 
+Di 
+Zhi 
+Bei 
+Teng 
+Yao 
+Mo 
+Huan 
+Piao 
+Fan 
+Sou 
+Tan 
+Tui 
+Qiong 
+Qiao 
+Wei 
+Liu 
+Hui 
+[?] 
+Gao 
+Yun 
+[?] 
+Li 
+Shu 
+Chu 
+Ai 
+Lin 
+Zao 
+Xuan 
+Chen 
+Lai 
+Huo 
+Tuo 
+Wu 
+Rui 
+Rui 
+Qi 
+Heng 
+Lu 
+Su 
+Tui 
+Mang 
+Yun 
+Pin 
+Yu 
+Xun 
+Ji 
+Jiong 
+Xian 
+Mo 
+Hagi 
+Su 
+Jiong 
+[?] 
+Nie 
+Bo 
+Rang 
+Yi 
+Xian 
+Yu 
+Ju 
+Lian 
+Lian 
+Yin 
+Qiang 
+Ying 
+Long 
+Tong 
+Wei 
+Yue 
+Ling 
+Qu 
+Yao 
+Fan 
+Mi 
+Lan 
+Kui 
+Lan 
+Ji 
+Dang 
+Katsura 
+Lei 
+Lei 
+Hua 
+Feng 
+Zhi 
+Wei 
+Kui 
+Zhan 
+Huai 
+Li 
+Ji 
+Mi 
+Lei 
+Huai 
+Luo 
+Ji 
+Kui 
+Lu 
+Jian 
+San 
+[?] 
+Lei 
+Quan 
+Xiao 
+Yi 
+Luan 
+Men 
+Bie 
+Hu 
+Hu 
+Lu 
+Nue 
+Lu 
+Si 
+Xiao 
+Qian 
+Chu 
+Hu 
+Xu 
+Cuo 
+Fu 
+Xu 
+Xu 
+Lu 
+Hu 
+Yu 
+Hao 
+Jiao 
+Ju 
+Guo 
+Bao 
+Yan 
+Zhan 
+Zhan 
+Kui 
+Ban 
+Xi 
+Shu 
+Chong 
+Qiu 
+Diao 
+Ji 
+Qiu 
+Cheng 
+Shi 
+[?] 
+Di 
+Zhe 
+She 
+Yu 
+Gan 
+Zi 
+Hong 
+Hui 
+Meng 
+Ge 
+Sui 
+Xia 
+Chai 
+Shi 
+Yi 
+Ma 
+Xiang 
+Fang 
+E 
+Pa 
+Chi 
+Qian 
+Wen 
+Wen 
+Rui 
+Bang 
+Bi 
+Yue 
+Yue 
+Jun 
+Qi 
+Ran 
+Yin 
+Qi 
+Tian 
+Yuan 
+Jue 
+Hui 
+Qin 
+Qi 
+Zhong 
+Ya 
+Ci 
+Mu 
+Wang 
+Fen 
+Fen 
+Hang 
+Gong 
+Zao 
+Fu 
+Ran 
+Jie 
+Fu 
+Chi 
+Dou 
+Piao 
+Xian 
+Ni 
+Te 
+Qiu 
+You 
+Zha 
+Ping 
+Chi 
+You 
+He 
+Han 
+Ju 
+Li 
+Fu 
+Ran 
+Zha 
+Gou 
+Pi 
+Bo 
+Xian 
+Zhu 
+Diao 
+Bie 
+Bing 
+Gu 
+Ran 
+Qu 
+She 
+Tie 
+Ling 
+Gu 
+Dan 
+Gu 
+Ying 
+Li 
+Cheng 
+Qu 
+Mou 
+Ge 
+Ci 
+Hui 
+Hui 
+Mang 
+Fu 
+Yang 
+Wa 
+Lie 
+Zhu 
+Yi 
+Xian 
+Kuo 
+Jiao 
+Li 
+Yi 
+Ping 
+Ji 
+Ha 
+She 
+Yi 
+Wang 
+Mo 
+Qiong 
+Qie 
+Gui 
+Gong 
+Zhi 
+Man 
+Ebi 
+Zhi 
+Jia 
+Rao 
+Si 
+Qi 
+Xing 
+Lie 
+Qiu 
+Shao 
+Yong 
+Jia 
+Shui 
+Che 
+Bai 
+E 
+Han 
+Shu 
+Xuan 
+Feng 
+Shen 
+Zhen 
+Fu 
+Xian 
+Zhe 
+Wu 
+Fu 
+Li 
+Lang 
+Bi 
+Chu 
+Yuan 
+You 
+Jie 
+Dan 
+Yan 
+Ting 
+Dian 
+Shui 
+Hui 
+Gua 
+Zhi 
+Song 
+Fei 
+Ju 
+Mi 
+Qi 
+Qi 
+Yu 
+Jun 
+Zha 
+Meng 
+Qiang 
+Si 
+Xi 
+Lun 
+Li 
+Die 
+Tiao 
+Tao 
+Kun 
+Gan 
+Han 
+Yu 
+Bang 
+Fei 
+Pi 
+Wei 
+Dun 
+Yi 
+Yuan 
+Su 
+Quan 
+Qian 
+Rui 
+Ni 
+Qing 
+Wei 
+Liang 
+Guo 
+Wan 
+Dong 
+E 
+Ban 
+Di 
+Wang 
+Can 
+Yang 
+Ying 
+Guo 
+Chan 
+[?] 
+La 
+Ke 
+Ji 
+He 
+Ting 
+Mai 
+Xu 
+Mian 
+Yu 
+Jie 
+Shi 
+Xuan 
+Huang 
+Yan 
+Bian 
+Rou 
+Wei 
+Fu 
+Yuan 
+Mei 
+Wei 
+Fu 
+Ruan 
+Xie 
+You 
+Qiu 
+Mao 
+Xia 
+Ying 
+Shi 
+Chong 
+Tang 
+Zhu 
+Zong 
+Ti 
+Fu 
+Yuan 
+Hui 
+Meng 
+La 
+Du 
+Hu 
+Qiu 
+Die 
+Li 
+Gua 
+Yun 
+Ju 
+Nan 
+Lou 
+Qun 
+Rong 
+Ying 
+Jiang 
+[?] 
+Lang 
+Pang 
+Si 
+Xi 
+Ci 
+Xi 
+Yuan 
+Weng 
+Lian 
+Sou 
+Ban 
+Rong 
+Rong 
+Ji 
+Wu 
+Qiu 
+Han 
+Qin 
+Yi 
+Bi 
+Hua 
+Tang 
+Yi 
+Du 
+Nai 
+He 
+Hu 
+Hui 
+Ma 
+Ming 
+Yi 
+Wen 
+Ying 
+Teng 
+Yu 
+Cang 
+So 
+Ebi 
+Man 
+[?] 
+Shang 
+Zhe 
+Cao 
+Chi 
+Di 
+Ao 
+Lu 
+Wei 
+Zhi 
+Tang 
+Chen 
+Piao 
+Qu 
+Pi 
+Yu 
+Jian 
+Luo 
+Lou 
+Qin 
+Zhong 
+Yin 
+Jiang 
+Shuai 
+Wen 
+Jiao 
+Wan 
+Zhi 
+Zhe 
+Ma 
+Ma 
+Guo 
+Liu 
+Mao 
+Xi 
+Cong 
+Li 
+Man 
+Xiao 
+Kamakiri 
+Zhang 
+Mang 
+Xiang 
+Mo 
+Zui 
+Si 
+Qiu 
+Te 
+Zhi 
+Peng 
+Peng 
+Jiao 
+Qu 
+Bie 
+Liao 
+Pan 
+Gui 
+Xi 
+Ji 
+Zhuan 
+Huang 
+Fei 
+Lao 
+Jue 
+Jue 
+Hui 
+Yin 
+Chan 
+Jiao 
+Shan 
+Rao 
+Xiao 
+Mou 
+Chong 
+Xun 
+Si 
+[?] 
+Cheng 
+Dang 
+Li 
+Xie 
+Shan 
+Yi 
+Jing 
+Da 
+Chan 
+Qi 
+Ci 
+Xiang 
+She 
+Luo 
+Qin 
+Ying 
+Chai 
+Li 
+Ze 
+Xuan 
+Lian 
+Zhu 
+Ze 
+Xie 
+Mang 
+Xie 
+Qi 
+Rong 
+Jian 
+Meng 
+Hao 
+Ruan 
+Huo 
+Zhuo 
+Jie 
+Bin 
+He 
+Mie 
+Fan 
+Lei 
+Jie 
+La 
+Mi 
+Li 
+Chun 
+Li 
+Qiu 
+Nie 
+Lu 
+Du 
+Xiao 
+Zhu 
+Long 
+Li 
+Long 
+Feng 
+Ye 
+Beng 
+Shang 
+Gu 
+Juan 
+Ying 
+[?] 
+Xi 
+Can 
+Qu 
+Quan 
+Du 
+Can 
+Man 
+Jue 
+Jie 
+Zhu 
+Zha 
+Xie 
+Huang 
+Niu 
+Pei 
+Nu 
+Xin 
+Zhong 
+Mo 
+Er 
+Ke 
+Mie 
+Xi 
+Xing 
+Yan 
+Kan 
+Yuan 
+[?] 
+Ling 
+Xuan 
+Shu 
+Xian 
+Tong 
+Long 
+Jie 
+Xian 
+Ya 
+Hu 
+Wei 
+Dao 
+Chong 
+Wei 
+Dao 
+Zhun 
+Heng 
+Qu 
+Yi 
+Yi 
+Bu 
+Gan 
+Yu 
+Biao 
+Cha 
+Yi 
+Shan 
+Chen 
+Fu 
+Gun 
+Fen 
+Shuai 
+Jie 
+Na 
+Zhong 
+Dan 
+Ri 
+Zhong 
+Zhong 
+Xie 
+Qi 
+Xie 
+Ran 
+Zhi 
+Ren 
+Qin 
+Jin 
+Jun 
+Yuan 
+Mei 
+Chai 
+Ao 
+Niao 
+Hui 
+Ran 
+Jia 
+Tuo 
+Ling 
+Dai 
+Bao 
+Pao 
+Yao 
+Zuo 
+Bi 
+Shao 
+Tan 
+Ju 
+He 
+Shu 
+Xiu 
+Zhen 
+Yi 
+Pa 
+Bo 
+Di 
+Wa 
+Fu 
+Gun 
+Zhi 
+Zhi 
+Ran 
+Pan 
+Yi 
+Mao 
+Tuo 
+Na 
+Kou 
+Xian 
+Chan 
+Qu 
+Bei 
+Gun 
+Xi 
+Ne 
+Bo 
+Horo 
+Fu 
+Yi 
+Chi 
+Ku 
+Ren 
+Jiang 
+Jia 
+Cun 
+Mo 
+Jie 
+Er 
+Luo 
+Ru 
+Zhu 
+Gui 
+Yin 
+Cai 
+Lie 
+Kamishimo 
+Yuki 
+Zhuang 
+Dang 
+[?] 
+Kun 
+Ken 
+Niao 
+Shu 
+Jia 
+Kun 
+Cheng 
+Li 
+Juan 
+Shen 
+Pou 
+Ge 
+Yi 
+Yu 
+Zhen 
+Liu 
+Qiu 
+Qun 
+Ji 
+Yi 
+Bu 
+Zhuang 
+Shui 
+Sha 
+Qun 
+Li 
+Lian 
+Lian 
+Ku 
+Jian 
+Fou 
+Chan 
+Bi 
+Gun 
+Tao 
+Yuan 
+Ling 
+Chi 
+Chang 
+Chou 
+Duo 
+Biao 
+Liang 
+Chang 
+Pei 
+Pei 
+Fei 
+Yuan 
+Luo 
+Guo 
+Yan 
+Du 
+Xi 
+Zhi 
+Ju 
+Qi 
+Ji 
+Zhi 
+Gua 
+Ken 
+Che 
+Ti 
+Ti 
+Fu 
+Chong 
+Xie 
+Bian 
+Die 
+Kun 
+Duan 
+Xiu 
+Xiu 
+He 
+Yuan 
+Bao 
+Bao 
+Fu 
+Yu 
+Tuan 
+Yan 
+Hui 
+Bei 
+Chu 
+Lu 
+Ena 
+Hitoe 
+Yun 
+Da 
+Gou 
+Da 
+Huai 
+Rong 
+Yuan 
+Ru 
+Nai 
+Jiong 
+Suo 
+Ban 
+Tun 
+Chi 
+Sang 
+Niao 
+Ying 
+Jie 
+Qian 
+Huai 
+Ku 
+Lian 
+Bao 
+Li 
+Zhe 
+Shi 
+Lu 
+Yi 
+Die 
+Xie 
+Xian 
+Wei 
+Biao 
+Cao 
+Ji 
+Jiang 
+Sen 
+Bao 
+Xiang 
+Chihaya 
+Pu 
+Jian 
+Zhuan 
+Jian 
+Zui 
+Ji 
+Dan 
+Za 
+Fan 
+Bo 
+Xiang 
+Xin 
+Bie 
+Rao 
+Man 
+Lan 
+Ao 
+Duo 
+Gui 
+Cao 
+Sui 
+Nong 
+Chan 
+Lian 
+Bi 
+Jin 
+Dang 
+Shu 
+Tan 
+Bi 
+Lan 
+Pu 
+Ru 
+Zhi 
+[?] 
+Shu 
+Wa 
+Shi 
+Bai 
+Xie 
+Bo 
+Chen 
+Lai 
+Long 
+Xi 
+Xian 
+Lan 
+Zhe 
+Dai 
+Tasuki 
+Zan 
+Shi 
+Jian 
+Pan 
+Yi 
+Ran 
+Ya 
+Xi 
+Xi 
+Yao 
+Feng 
+Tan 
+[?] 
+Biao 
+Fu 
+Ba 
+He 
+Ji 
+Ji 
+Jian 
+Guan 
+Bian 
+Yan 
+Gui 
+Jue 
+Pian 
+Mao 
+Mi 
+Mi 
+Mie 
+Shi 
+Si 
+Zhan 
+Luo 
+Jue 
+Mi 
+Tiao 
+Lian 
+Yao 
+Zhi 
+Jun 
+Xi 
+Shan 
+Wei 
+Xi 
+Tian 
+Yu 
+Lan 
+E 
+Du 
+Qin 
+Pang 
+Ji 
+Ming 
+Ying 
+Gou 
+Qu 
+Zhan 
+Jin 
+Guan 
+Deng 
+Jian 
+Luo 
+Qu 
+Jian 
+Wei 
+Jue 
+Qu 
+Luo 
+Lan 
+Shen 
+Di 
+Guan 
+Jian 
+Guan 
+Yan 
+Gui 
+Mi 
+Shi 
+Zhan 
+Lan 
+Jue 
+Ji 
+Xi 
+Di 
+Tian 
+Yu 
+Gou 
+Jin 
+Qu 
+Jiao 
+Jiu 
+Jin 
+Cu 
+Jue 
+Zhi 
+Chao 
+Ji 
+Gu 
+Dan 
+Zui 
+Di 
+Shang 
+Hua 
+Quan 
+Ge 
+Chi 
+Jie 
+Gui 
+Gong 
+Hong 
+Jie 
+Hun 
+Qiu 
+Xing 
+Su 
+Ni 
+Ji 
+Lu 
+Zhi 
+Zha 
+Bi 
+Xing 
+Hu 
+Shang 
+Gong 
+Zhi 
+Xue 
+Chu 
+Xi 
+Yi 
+Lu 
+Jue 
+Xi 
+Yan 
+Xi 
+Yan 
+Yan 
+Ding 
+Fu 
+Qiu 
+Qiu 
+Jiao 
+Hong 
+Ji 
+Fan 
+Xun 
+Diao 
+Hong 
+Cha 
+Tao 
+Xu 
+Jie 
+Yi 
+Ren 
+Xun 
+Yin 
+Shan 
+Qi 
+Tuo 
+Ji 
+Xun 
+Yin 
+E 
+Fen 
+Ya 
+Yao 
+Song 
+Shen 
+Yin 
+Xin 
+Jue 
+Xiao 
+Ne 
+Chen 
+You 
+Zhi 
+Xiong 
+Fang 
+Xin 
+Chao 
+She 
+Xian 
+Sha 
+Tun 
+Xu 
+Yi 
+Yi 
+Su 
+Chi 
+He 
+Shen 
+He 
+Xu 
+Zhen 
+Zhu 
+Zheng 
+Gou 
+Zi 
+Zi 
+Zhan 
+Gu 
+Fu 
+Quan 
+Die 
+Ling 
+Di 
+Yang 
+Li 
+Nao 
+Pan 
+Zhou 
+Gan 
+Yi 
+Ju 
+Ao 
+Zha 
+Tuo 
+Yi 
+Qu 
+Zhao 
+Ping 
+Bi 
+Xiong 
+Qu 
+Ba 
+Da 
+Zu 
+Tao 
+Zhu 
+Ci 
+Zhe 
+Yong 
+Xu 
+Xun 
+Yi 
+Huang 
+He 
+Shi 
+Cha 
+Jiao 
+Shi 
+Hen 
+Cha 
+Gou 
+Gui 
+Quan 
+Hui 
+Jie 
+Hua 
+Gai 
+Xiang 
+Wei 
+Shen 
+Chou 
+Tong 
+Mi 
+Zhan 
+Ming 
+E 
+Hui 
+Yan 
+Xiong 
+Gua 
+Er 
+Beng 
+Tiao 
+Chi 
+Lei 
+Zhu 
+Kuang 
+Kua 
+Wu 
+Yu 
+Teng 
+Ji 
+Zhi 
+Ren 
+Su 
+Lang 
+E 
+Kuang 
+E 
+Shi 
+Ting 
+Dan 
+Bo 
+Chan 
+You 
+Heng 
+Qiao 
+Qin 
+Shua 
+An 
+Yu 
+Xiao 
+Cheng 
+Jie 
+Xian 
+Wu 
+Wu 
+Gao 
+Song 
+Pu 
+Hui 
+Jing 
+Shuo 
+Zhen 
+Shuo 
+Du 
+Yasashi 
+Chang 
+Shui 
+Jie 
+Ke 
+Qu 
+Cong 
+Xiao 
+Sui 
+Wang 
+Xuan 
+Fei 
+Chi 
+Ta 
+Yi 
+Na 
+Yin 
+Diao 
+Pi 
+Chuo 
+Chan 
+Chen 
+Zhun 
+Ji 
+Qi 
+Tan 
+Zhui 
+Wei 
+Ju 
+Qing 
+Jian 
+Zheng 
+Ze 
+Zou 
+Qian 
+Zhuo 
+Liang 
+Jian 
+Zhu 
+Hao 
+Lun 
+Shen 
+Biao 
+Huai 
+Pian 
+Yu 
+Die 
+Xu 
+Pian 
+Shi 
+Xuan 
+Shi 
+Hun 
+Hua 
+E 
+Zhong 
+Di 
+Xie 
+Fu 
+Pu 
+Ting 
+Jian 
+Qi 
+Yu 
+Zi 
+Chuan 
+Xi 
+Hui 
+Yin 
+An 
+Xian 
+Nan 
+Chen 
+Feng 
+Zhu 
+Yang 
+Yan 
+Heng 
+Xuan 
+Ge 
+Nuo 
+Qi 
+Mou 
+Ye 
+Wei 
+[?] 
+Teng 
+Zou 
+Shan 
+Jian 
+Bo 
+Ku 
+Huang 
+Huo 
+Ge 
+Ying 
+Mi 
+Xiao 
+Mi 
+Xi 
+Qiang 
+Chen 
+Nue 
+Ti 
+Su 
+Bang 
+Chi 
+Qian 
+Shi 
+Jiang 
+Yuan 
+Xie 
+Xue 
+Tao 
+Yao 
+Yao 
+[?] 
+Yu 
+Biao 
+Cong 
+Qing 
+Li 
+Mo 
+Mo 
+Shang 
+Zhe 
+Miu 
+Jian 
+Ze 
+Jie 
+Lian 
+Lou 
+Can 
+Ou 
+Guan 
+Xi 
+Zhuo 
+Ao 
+Ao 
+Jin 
+Zhe 
+Yi 
+Hu 
+Jiang 
+Man 
+Chao 
+Han 
+Hua 
+Chan 
+Xu 
+Zeng 
+Se 
+Xi 
+She 
+Dui 
+Zheng 
+Nao 
+Lan 
+E 
+Ying 
+Jue 
+Ji 
+Zun 
+Jiao 
+Bo 
+Hui 
+Zhuan 
+Mu 
+Zen 
+Zha 
+Shi 
+Qiao 
+Tan 
+Zen 
+Pu 
+Sheng 
+Xuan 
+Zao 
+Tan 
+Dang 
+Sui 
+Qian 
+Ji 
+Jiao 
+Jing 
+Lian 
+Nou 
+Yi 
+Ai 
+Zhan 
+Pi 
+Hui 
+Hua 
+Yi 
+Yi 
+Shan 
+Rang 
+Nou 
+Qian 
+Zhui 
+Ta 
+Hu 
+Zhou 
+Hao 
+Ye 
+Ying 
+Jian 
+Yu 
+Jian 
+Hui 
+Du 
+Zhe 
+Xuan 
+Zan 
+Lei 
+Shen 
+Wei 
+Chan 
+Li 
+Yi 
+Bian 
+Zhe 
+Yan 
+E 
+Chou 
+Wei 
+Chou 
+Yao 
+Chan 
+Rang 
+Yin 
+Lan 
+Chen 
+Huo 
+Zhe 
+Huan 
+Zan 
+Yi 
+Dang 
+Zhan 
+Yan 
+Du 
+Yan 
+Ji 
+Ding 
+Fu 
+Ren 
+Ji 
+Jie 
+Hong 
+Tao 
+Rang 
+Shan 
+Qi 
+Tuo 
+Xun 
+Yi 
+Xun 
+Ji 
+Ren 
+Jiang 
+Hui 
+Ou 
+Ju 
+Ya 
+Ne 
+Xu 
+E 
+Lun 
+Xiong 
+Song 
+Feng 
+She 
+Fang 
+Jue 
+Zheng 
+Gu 
+He 
+Ping 
+Zu 
+Shi 
+Xiong 
+Zha 
+Su 
+Zhen 
+Di 
+Zou 
+Ci 
+Qu 
+Zhao 
+Bi 
+Yi 
+Yi 
+Kuang 
+Lei 
+Shi 
+Gua 
+Shi 
+Jie 
+Hui 
+Cheng 
+Zhu 
+Shen 
+Hua 
+Dan 
+Gou 
+Quan 
+Gui 
+Xun 
+Yi 
+Zheng 
+Gai 
+Xiang 
+Cha 
+Hun 
+Xu 
+Zhou 
+Jie 
+Wu 
+Yu 
+Qiao 
+Wu 
+Gao 
+You 
+Hui 
+Kuang 
+Shuo 
+Song 
+Ai 
+Qing 
+Zhu 
+Zou 
+Nuo 
+Du 
+Zhuo 
+Fei 
+Ke 
+Wei 
+Yu 
+Shui 
+Shen 
+Diao 
+Chan 
+Liang 
+Zhun 
+Sui 
+Tan 
+Shen 
+Yi 
+Mou 
+Chen 
+Die 
+Huang 
+Jian 
+Xie 
+Nue 
+Ye 
+Wei 
+E 
+Yu 
+Xuan 
+Chan 
+Zi 
+An 
+Yan 
+Di 
+Mi 
+Pian 
+Xu 
+Mo 
+Dang 
+Su 
+Xie 
+Yao 
+Bang 
+Shi 
+Qian 
+Mi 
+Jin 
+Man 
+Zhe 
+Jian 
+Miu 
+Tan 
+Zen 
+Qiao 
+Lan 
+Pu 
+Jue 
+Yan 
+Qian 
+Zhan 
+Chen 
+Gu 
+Qian 
+Hong 
+Xia 
+Jue 
+Hong 
+Han 
+Hong 
+Xi 
+Xi 
+Huo 
+Liao 
+Han 
+Du 
+Long 
+Dou 
+Jiang 
+Qi 
+Shi 
+Li 
+Deng 
+Wan 
+Bi 
+Shu 
+Xian 
+Feng 
+Zhi 
+Zhi 
+Yan 
+Yan 
+Shi 
+Chu 
+Hui 
+Tun 
+Yi 
+Tun 
+Yi 
+Jian 
+Ba 
+Hou 
+E 
+Cu 
+Xiang 
+Huan 
+Jian 
+Ken 
+Gai 
+Qu 
+Fu 
+Xi 
+Bin 
+Hao 
+Yu 
+Zhu 
+Jia 
+[?] 
+Xi 
+Bo 
+Wen 
+Huan 
+Bin 
+Di 
+Zong 
+Fen 
+Yi 
+Zhi 
+Bao 
+Chai 
+Han 
+Pi 
+Na 
+Pi 
+Gou 
+Na 
+You 
+Diao 
+Mo 
+Si 
+Xiu 
+Huan 
+Kun 
+He 
+He 
+Mo 
+Han 
+Mao 
+Li 
+Ni 
+Bi 
+Yu 
+Jia 
+Tuan 
+Mao 
+Pi 
+Xi 
+E 
+Ju 
+Mo 
+Chu 
+Tan 
+Huan 
+Jue 
+Bei 
+Zhen 
+Yuan 
+Fu 
+Cai 
+Gong 
+Te 
+Yi 
+Hang 
+Wan 
+Pin 
+Huo 
+Fan 
+Tan 
+Guan 
+Ze 
+Zhi 
+Er 
+Zhu 
+Shi 
+Bi 
+Zi 
+Er 
+Gui 
+Pian 
+Bian 
+Mai 
+Dai 
+Sheng 
+Kuang 
+Fei 
+Tie 
+Yi 
+Chi 
+Mao 
+He 
+Bi 
+Lu 
+Ren 
+Hui 
+Gai 
+Pian 
+Zi 
+Jia 
+Xu 
+Zei 
+Jiao 
+Gai 
+Zang 
+Jian 
+Ying 
+Xun 
+Zhen 
+She 
+Bin 
+Bin 
+Qiu 
+She 
+Chuan 
+Zang 
+Zhou 
+Lai 
+Zan 
+Si 
+Chen 
+Shang 
+Tian 
+Pei 
+Geng 
+Xian 
+Mai 
+Jian 
+Sui 
+Fu 
+Tan 
+Cong 
+Cong 
+Zhi 
+Ji 
+Zhang 
+Du 
+Jin 
+Xiong 
+Shun 
+Yun 
+Bao 
+Zai 
+Lai 
+Feng 
+Cang 
+Ji 
+Sheng 
+Ai 
+Zhuan 
+Fu 
+Gou 
+Sai 
+Ze 
+Liao 
+Wei 
+Bai 
+Chen 
+Zhuan 
+Zhi 
+Zhui 
+Biao 
+Yun 
+Zeng 
+Tan 
+Zan 
+Yan 
+[?] 
+Shan 
+Wan 
+Ying 
+Jin 
+Gan 
+Xian 
+Zang 
+Bi 
+Du 
+Shu 
+Yan 
+[?] 
+Xuan 
+Long 
+Gan 
+Zang 
+Bei 
+Zhen 
+Fu 
+Yuan 
+Gong 
+Cai 
+Ze 
+Xian 
+Bai 
+Zhang 
+Huo 
+Zhi 
+Fan 
+Tan 
+Pin 
+Bian 
+Gou 
+Zhu 
+Guan 
+Er 
+Jian 
+Bi 
+Shi 
+Tie 
+Gui 
+Kuang 
+Dai 
+Mao 
+Fei 
+He 
+Yi 
+Zei 
+Zhi 
+Jia 
+Hui 
+Zi 
+Ren 
+Lu 
+Zang 
+Zi 
+Gai 
+Jin 
+Qiu 
+Zhen 
+Lai 
+She 
+Fu 
+Du 
+Ji 
+Shu 
+Shang 
+Si 
+Bi 
+Zhou 
+Geng 
+Pei 
+Tan 
+Lai 
+Feng 
+Zhui 
+Fu 
+Zhuan 
+Sai 
+Ze 
+Yan 
+Zan 
+Yun 
+Zeng 
+Shan 
+Ying 
+Gan 
+Chi 
+Xi 
+She 
+Nan 
+Xiong 
+Xi 
+Cheng 
+He 
+Cheng 
+Zhe 
+Xia 
+Tang 
+Zou 
+Zou 
+Li 
+Jiu 
+Fu 
+Zhao 
+Gan 
+Qi 
+Shan 
+Qiong 
+Qin 
+Xian 
+Ci 
+Jue 
+Qin 
+Chi 
+Ci 
+Chen 
+Chen 
+Die 
+Ju 
+Chao 
+Di 
+Se 
+Zhan 
+Zhu 
+Yue 
+Qu 
+Jie 
+Chi 
+Chu 
+Gua 
+Xue 
+Ci 
+Tiao 
+Duo 
+Lie 
+Gan 
+Suo 
+Cu 
+Xi 
+Zhao 
+Su 
+Yin 
+Ju 
+Jian 
+Que 
+Tang 
+Chuo 
+Cui 
+Lu 
+Qu 
+Dang 
+Qiu 
+Zi 
+Ti 
+Qu 
+Chi 
+Huang 
+Qiao 
+Qiao 
+Yao 
+Zao 
+Ti 
+[?] 
+Zan 
+Zan 
+Zu 
+Pa 
+Bao 
+Ku 
+Ke 
+Dun 
+Jue 
+Fu 
+Chen 
+Jian 
+Fang 
+Zhi 
+Sa 
+Yue 
+Pa 
+Qi 
+Yue 
+Qiang 
+Tuo 
+Tai 
+Yi 
+Nian 
+Ling 
+Mei 
+Ba 
+Die 
+Ku 
+Tuo 
+Jia 
+Ci 
+Pao 
+Qia 
+Zhu 
+Ju 
+Die 
+Zhi 
+Fu 
+Pan 
+Ju 
+Shan 
+Bo 
+Ni 
+Ju 
+Li 
+Gen 
+Yi 
+Ji 
+Dai 
+Xian 
+Jiao 
+Duo 
+Zhu 
+Zhuan 
+Kua 
+Zhuai 
+Gui 
+Qiong 
+Kui 
+Xiang 
+Chi 
+Lu 
+Beng 
+Zhi 
+Jia 
+Tiao 
+Cai 
+Jian 
+Ta 
+Qiao 
+Bi 
+Xian 
+Duo 
+Ji 
+Ju 
+Ji 
+Shu 
+Tu 
+Chu 
+Jing 
+Nie 
+Xiao 
+Bo 
+Chi 
+Qun 
+Mou 
+Shu 
+Lang 
+Yong 
+Jiao 
+Chou 
+Qiao 
+[?] 
+Ta 
+Jian 
+Qi 
+Wo 
+Wei 
+Zhuo 
+Jie 
+Ji 
+Nie 
+Ju 
+Ju 
+Lun 
+Lu 
+Leng 
+Huai 
+Ju 
+Chi 
+Wan 
+Quan 
+Ti 
+Bo 
+Zu 
+Qie 
+Ji 
+Cu 
+Zong 
+Cai 
+Zong 
+Peng 
+Zhi 
+Zheng 
+Dian 
+Zhi 
+Yu 
+Duo 
+Dun 
+Chun 
+Yong 
+Zhong 
+Di 
+Zhe 
+Chen 
+Chuai 
+Jian 
+Gua 
+Tang 
+Ju 
+Fu 
+Zu 
+Die 
+Pian 
+Rou 
+Nuo 
+Ti 
+Cha 
+Tui 
+Jian 
+Dao 
+Cuo 
+Xi 
+Ta 
+Qiang 
+Zhan 
+Dian 
+Ti 
+Ji 
+Nie 
+Man 
+Liu 
+Zhan 
+Bi 
+Chong 
+Lu 
+Liao 
+Cu 
+Tang 
+Dai 
+Suo 
+Xi 
+Kui 
+Ji 
+Zhi 
+Qiang 
+Di 
+Man 
+Zong 
+Lian 
+Beng 
+Zao 
+Nian 
+Bie 
+Tui 
+Ju 
+Deng 
+Ceng 
+Xian 
+Fan 
+Chu 
+Zhong 
+Dun 
+Bo 
+Cu 
+Zu 
+Jue 
+Jue 
+Lin 
+Ta 
+Qiao 
+Qiao 
+Pu 
+Liao 
+Dun 
+Cuan 
+Kuang 
+Zao 
+Ta 
+Bi 
+Bi 
+Zhu 
+Ju 
+Chu 
+Qiao 
+Dun 
+Chou 
+Ji 
+Wu 
+Yue 
+Nian 
+Lin 
+Lie 
+Zhi 
+Li 
+Zhi 
+Chan 
+Chu 
+Duan 
+Wei 
+Long 
+Lin 
+Xian 
+Wei 
+Zuan 
+Lan 
+Xie 
+Rang 
+Xie 
+Nie 
+Ta 
+Qu 
+Jie 
+Cuan 
+Zuan 
+Xi 
+Kui 
+Jue 
+Lin 
+Shen 
+Gong 
+Dan 
+Segare 
+Qu 
+Ti 
+Duo 
+Duo 
+Gong 
+Lang 
+Nerau 
+Luo 
+Ai 
+Ji 
+Ju 
+Tang 
+Utsuke 
+[?] 
+Yan 
+Shitsuke 
+Kang 
+Qu 
+Lou 
+Lao 
+Tuo 
+Zhi 
+Yagate 
+Ti 
+Dao 
+Yagate 
+Yu 
+Che 
+Ya 
+Gui 
+Jun 
+Wei 
+Yue 
+Xin 
+Di 
+Xuan 
+Fan 
+Ren 
+Shan 
+Qiang 
+Shu 
+Tun 
+Chen 
+Dai 
+E 
+Na 
+Qi 
+Mao 
+Ruan 
+Ren 
+Fan 
+Zhuan 
+Hong 
+Hu 
+Qu 
+Huang 
+Di 
+Ling 
+Dai 
+Ao 
+Zhen 
+Fan 
+Kuang 
+Ang 
+Peng 
+Bei 
+Gu 
+Ku 
+Pao 
+Zhu 
+Rong 
+E 
+Ba 
+Zhou 
+Zhi 
+Yao 
+Ke 
+Yi 
+Qing 
+Shi 
+Ping 
+Er 
+Qiong 
+Ju 
+Jiao 
+Guang 
+Lu 
+Kai 
+Quan 
+Zhou 
+Zai 
+Zhi 
+She 
+Liang 
+Yu 
+Shao 
+You 
+Huan 
+Yun 
+Zhe 
+Wan 
+Fu 
+Qing 
+Zhou 
+Ni 
+Ling 
+Zhe 
+Zhan 
+Liang 
+Zi 
+Hui 
+Wang 
+Chuo 
+Guo 
+Kan 
+Yi 
+Peng 
+Qian 
+Gun 
+Nian 
+Pian 
+Guan 
+Bei 
+Lun 
+Pai 
+Liang 
+Ruan 
+Rou 
+Ji 
+Yang 
+Xian 
+Chuan 
+Cou 
+Qun 
+Ge 
+You 
+Hong 
+Shu 
+Fu 
+Zi 
+Fu 
+Wen 
+Ben 
+Zhan 
+Yu 
+Wen 
+Tao 
+Gu 
+Zhen 
+Xia 
+Yuan 
+Lu 
+Jiu 
+Chao 
+Zhuan 
+Wei 
+Hun 
+Sori 
+Che 
+Jiao 
+Zhan 
+Pu 
+Lao 
+Fen 
+Fan 
+Lin 
+Ge 
+Se 
+Kan 
+Huan 
+Yi 
+Ji 
+Dui 
+Er 
+Yu 
+Xian 
+Hong 
+Lei 
+Pei 
+Li 
+Li 
+Lu 
+Lin 
+Che 
+Ya 
+Gui 
+Xuan 
+Di 
+Ren 
+Zhuan 
+E 
+Lun 
+Ruan 
+Hong 
+Ku 
+Ke 
+Lu 
+Zhou 
+Zhi 
+Yi 
+Hu 
+Zhen 
+Li 
+Yao 
+Qing 
+Shi 
+Zai 
+Zhi 
+Jiao 
+Zhou 
+Quan 
+Lu 
+Jiao 
+Zhe 
+Fu 
+Liang 
+Nian 
+Bei 
+Hui 
+Gun 
+Wang 
+Liang 
+Chuo 
+Zi 
+Cou 
+Fu 
+Ji 
+Wen 
+Shu 
+Pei 
+Yuan 
+Xia 
+Zhan 
+Lu 
+Che 
+Lin 
+Xin 
+Gu 
+Ci 
+Ci 
+Pi 
+Zui 
+Bian 
+La 
+La 
+Ci 
+Xue 
+Ban 
+Bian 
+Bian 
+Bian 
+[?] 
+Bian 
+Ban 
+Ci 
+Bian 
+Bian 
+Chen 
+Ru 
+Nong 
+Nong 
+Zhen 
+Chuo 
+Chuo 
+Suberu 
+Reng 
+Bian 
+Bian 
+Sip 
+Ip 
+Liao 
+Da 
+Chan 
+Gan 
+Qian 
+Yu 
+Yu 
+Qi 
+Xun 
+Yi 
+Guo 
+Mai 
+Qi 
+Za 
+Wang 
+Jia 
+Zhun 
+Ying 
+Ti 
+Yun 
+Jin 
+Hang 
+Ya 
+Fan 
+Wu 
+Da 
+E 
+Huan 
+Zhe 
+Totemo 
+Jin 
+Yuan 
+Wei 
+Lian 
+Chi 
+Che 
+Ni 
+Tiao 
+Zhi 
+Yi 
+Jiong 
+Jia 
+Chen 
+Dai 
+Er 
+Di 
+Po 
+Wang 
+Die 
+Ze 
+Tao 
+Shu 
+Tuo 
+Kep 
+Jing 
+Hui 
+Tong 
+You 
+Mi 
+Beng 
+Ji 
+Nai 
+Yi 
+Jie 
+Zhui 
+Lie 
+Xun 
+Tui 
+Song 
+Gua 
+Tao 
+Pang 
+Hou 
+Ni 
+Dun 
+Jiong 
+Xuan 
+Xun 
+Bu 
+You 
+Xiao 
+Qiu 
+Tou 
+Zhu 
+Qiu 
+Di 
+Di 
+Tu 
+Jing 
+Ti 
+Dou 
+Yi 
+Zhe 
+Tong 
+Guang 
+Wu 
+Shi 
+Cheng 
+Su 
+Zao 
+Qun 
+Feng 
+Lian 
+Suo 
+Hui 
+Li 
+Sako 
+Lai 
+Ben 
+Cuo 
+Jue 
+Beng 
+Huan 
+Dai 
+Lu 
+You 
+Zhou 
+Jin 
+Yu 
+Chuo 
+Kui 
+Wei 
+Ti 
+Yi 
+Da 
+Yuan 
+Luo 
+Bi 
+Nuo 
+Yu 
+Dang 
+Sui 
+Dun 
+Sui 
+Yan 
+Chuan 
+Chi 
+Ti 
+Yu 
+Shi 
+Zhen 
+You 
+Yun 
+E 
+Bian 
+Guo 
+E 
+Xia 
+Huang 
+Qiu 
+Dao 
+Da 
+Wei 
+Appare 
+Yi 
+Gou 
+Yao 
+Chu 
+Liu 
+Xun 
+Ta 
+Di 
+Chi 
+Yuan 
+Su 
+Ta 
+Qian 
+[?] 
+Yao 
+Guan 
+Zhang 
+Ao 
+Shi 
+Ce 
+Chi 
+Su 
+Zao 
+Zhe 
+Dun 
+Di 
+Lou 
+Chi 
+Cuo 
+Lin 
+Zun 
+Rao 
+Qian 
+Xuan 
+Yu 
+Yi 
+Wu 
+Liao 
+Ju 
+Shi 
+Bi 
+Yao 
+Mai 
+Xie 
+Sui 
+Huan 
+Zhan 
+Teng 
+Er 
+Miao 
+Bian 
+Bian 
+La 
+Li 
+Yuan 
+Yao 
+Luo 
+Li 
+Yi 
+Ting 
+Deng 
+Qi 
+Yong 
+Shan 
+Han 
+Yu 
+Mang 
+Ru 
+Qiong 
+[?] 
+Kuang 
+Fu 
+Kang 
+Bin 
+Fang 
+Xing 
+Na 
+Xin 
+Shen 
+Bang 
+Yuan 
+Cun 
+Huo 
+Xie 
+Bang 
+Wu 
+Ju 
+You 
+Han 
+Tai 
+Qiu 
+Bi 
+Pei 
+Bing 
+Shao 
+Bei 
+Wa 
+Di 
+Zou 
+Ye 
+Lin 
+Kuang 
+Gui 
+Zhu 
+Shi 
+Ku 
+Yu 
+Gai 
+Ge 
+Xi 
+Zhi 
+Ji 
+Xun 
+Hou 
+Xing 
+Jiao 
+Xi 
+Gui 
+Nuo 
+Lang 
+Jia 
+Kuai 
+Zheng 
+Otoko 
+Yun 
+Yan 
+Cheng 
+Dou 
+Chi 
+Lu 
+Fu 
+Wu 
+Fu 
+Gao 
+Hao 
+Lang 
+Jia 
+Geng 
+Jun 
+Ying 
+Bo 
+Xi 
+Bei 
+Li 
+Yun 
+Bu 
+Xiao 
+Qi 
+Pi 
+Qing 
+Guo 
+Zhou 
+Tan 
+Zou 
+Ping 
+Lai 
+Ni 
+Chen 
+You 
+Bu 
+Xiang 
+Dan 
+Ju 
+Yong 
+Qiao 
+Yi 
+Du 
+Yan 
+Mei 
+Ruo 
+Bei 
+E 
+Yu 
+Juan 
+Yu 
+Yun 
+Hou 
+Kui 
+Xiang 
+Xiang 
+Sou 
+Tang 
+Ming 
+Xi 
+Ru 
+Chu 
+Zi 
+Zou 
+Ju 
+Wu 
+Xiang 
+Yun 
+Hao 
+Yong 
+Bi 
+Mo 
+Chao 
+Fu 
+Liao 
+Yin 
+Zhuan 
+Hu 
+Qiao 
+Yan 
+Zhang 
+Fan 
+Qiao 
+Xu 
+Deng 
+Bi 
+Xin 
+Bi 
+Ceng 
+Wei 
+Zheng 
+Mao 
+Shan 
+Lin 
+Po 
+Dan 
+Meng 
+Ye 
+Cao 
+Kuai 
+Feng 
+Meng 
+Zou 
+Kuang 
+Lian 
+Zan 
+Chan 
+You 
+Qi 
+Yan 
+Chan 
+Zan 
+Ling 
+Huan 
+Xi 
+Feng 
+Zan 
+Li 
+You 
+Ding 
+Qiu 
+Zhuo 
+Pei 
+Zhou 
+Yi 
+Hang 
+Yu 
+Jiu 
+Yan 
+Zui 
+Mao 
+Dan 
+Xu 
+Tou 
+Zhen 
+Fen 
+Sakenomoto 
+[?] 
+Yun 
+Tai 
+Tian 
+Qia 
+Tuo 
+Zuo 
+Han 
+Gu 
+Su 
+Po 
+Chou 
+Zai 
+Ming 
+Luo 
+Chuo 
+Chou 
+You 
+Tong 
+Zhi 
+Xian 
+Jiang 
+Cheng 
+Yin 
+Tu 
+Xiao 
+Mei 
+Ku 
+Suan 
+Lei 
+Pu 
+Zui 
+Hai 
+Yan 
+Xi 
+Niang 
+Wei 
+Lu 
+Lan 
+Yan 
+Tao 
+Pei 
+Zhan 
+Chun 
+Tan 
+Zui 
+Chuo 
+Cu 
+Kun 
+Ti 
+Mian 
+Du 
+Hu 
+Xu 
+Xing 
+Tan 
+Jiu 
+Chun 
+Yun 
+Po 
+Ke 
+Sou 
+Mi 
+Quan 
+Chou 
+Cuo 
+Yun 
+Yong 
+Ang 
+Zha 
+Hai 
+Tang 
+Jiang 
+Piao 
+Shan 
+Yu 
+Li 
+Zao 
+Lao 
+Yi 
+Jiang 
+Pu 
+Jiao 
+Xi 
+Tan 
+Po 
+Nong 
+Yi 
+Li 
+Ju 
+Jiao 
+Yi 
+Niang 
+Ru 
+Xun 
+Chou 
+Yan 
+Ling 
+Mi 
+Mi 
+Niang 
+Xin 
+Jiao 
+Xi 
+Mi 
+Yan 
+Bian 
+Cai 
+Shi 
+You 
+Shi 
+Shi 
+Li 
+Zhong 
+Ye 
+Liang 
+Li 
+Jin 
+Jin 
+Qiu 
+Yi 
+Diao 
+Dao 
+Zhao 
+Ding 
+Po 
+Qiu 
+He 
+Fu 
+Zhen 
+Zhi 
+Ba 
+Luan 
+Fu 
+Nai 
+Diao 
+Shan 
+Qiao 
+Kou 
+Chuan 
+Zi 
+Fan 
+Yu 
+Hua 
+Han 
+Gong 
+Qi 
+Mang 
+Ri 
+Di 
+Si 
+Xi 
+Yi 
+Chai 
+Shi 
+Tu 
+Xi 
+Nu 
+Qian 
+Ishiyumi 
+Jian 
+Pi 
+Ye 
+Yin 
+Ba 
+Fang 
+Chen 
+Xing 
+Tou 
+Yue 
+Yan 
+Fu 
+Pi 
+Na 
+Xin 
+E 
+Jue 
+Dun 
+Gou 
+Yin 
+Qian 
+Ban 
+Ji 
+Ren 
+Chao 
+Niu 
+Fen 
+Yun 
+Ji 
+Qin 
+Pi 
+Guo 
+Hong 
+Yin 
+Jun 
+Shi 
+Yi 
+Zhong 
+Nie 
+Gai 
+Ri 
+Huo 
+Tai 
+Kang 
+Habaki 
+Irori 
+Ngaak 
+[?] 
+Duo 
+Zi 
+Ni 
+Tu 
+Shi 
+Min 
+Gu 
+E 
+Ling 
+Bing 
+Yi 
+Gu 
+Ba 
+Pi 
+Yu 
+Si 
+Zuo 
+Bu 
+You 
+Dian 
+Jia 
+Zhen 
+Shi 
+Shi 
+Tie 
+Ju 
+Zhan 
+Shi 
+She 
+Xuan 
+Zhao 
+Bao 
+He 
+Bi 
+Sheng 
+Chu 
+Shi 
+Bo 
+Zhu 
+Chi 
+Za 
+Po 
+Tong 
+Qian 
+Fu 
+Zhai 
+Liu 
+Qian 
+Fu 
+Li 
+Yue 
+Pi 
+Yang 
+Ban 
+Bo 
+Jie 
+Gou 
+Shu 
+Zheng 
+Mu 
+Ni 
+Nie 
+Di 
+Jia 
+Mu 
+Dan 
+Shen 
+Yi 
+Si 
+Kuang 
+Ka 
+Bei 
+Jian 
+Tong 
+Xing 
+Hong 
+Jiao 
+Chi 
+Er 
+Ge 
+Bing 
+Shi 
+Mou 
+Jia 
+Yin 
+Jun 
+Zhou 
+Chong 
+Shang 
+Tong 
+Mo 
+Lei 
+Ji 
+Yu 
+Xu 
+Ren 
+Zun 
+Zhi 
+Qiong 
+Shan 
+Chi 
+Xian 
+Xing 
+Quan 
+Pi 
+Tie 
+Zhu 
+Hou 
+Ming 
+Kua 
+Yao 
+Xian 
+Xian 
+Xiu 
+Jun 
+Cha 
+Lao 
+Ji 
+Pi 
+Ru 
+Mi 
+Yi 
+Yin 
+Guang 
+An 
+Diou 
+You 
+Se 
+Kao 
+Qian 
+Luan 
+Kasugai 
+Ai 
+Diao 
+Han 
+Rui 
+Shi 
+Keng 
+Qiu 
+Xiao 
+Zhe 
+Xiu 
+Zang 
+Ti 
+Cuo 
+Gua 
+Gong 
+Zhong 
+Dou 
+Lu 
+Mei 
+Lang 
+Wan 
+Xin 
+Yun 
+Bei 
+Wu 
+Su 
+Yu 
+Chan 
+Ting 
+Bo 
+Han 
+Jia 
+Hong 
+Cuan 
+Feng 
+Chan 
+Wan 
+Zhi 
+Si 
+Xuan 
+Wu 
+Wu 
+Tiao 
+Gong 
+Zhuo 
+Lue 
+Xing 
+Qian 
+Shen 
+Han 
+Lue 
+Xie 
+Chu 
+Zheng 
+Ju 
+Xian 
+Tie 
+Mang 
+Pu 
+Li 
+Pan 
+Rui 
+Cheng 
+Gao 
+Li 
+Te 
+Pyeng 
+Zhu 
+[?] 
+Tu 
+Liu 
+Zui 
+Ju 
+Chang 
+Yuan 
+Jian 
+Gang 
+Diao 
+Tao 
+Chang 
+Lun 
+Kua 
+Ling 
+Bei 
+Lu 
+Li 
+Qiang 
+Pou 
+Juan 
+Min 
+Zui 
+Peng 
+An 
+Pi 
+Xian 
+Ya 
+Zhui 
+Lei 
+A 
+Kong 
+Ta 
+Kun 
+Du 
+Wei 
+Chui 
+Zi 
+Zheng 
+Ben 
+Nie 
+Cong 
+Qun 
+Tan 
+Ding 
+Qi 
+Qian 
+Zhuo 
+Qi 
+Yu 
+Jin 
+Guan 
+Mao 
+Chang 
+Tian 
+Xi 
+Lian 
+Tao 
+Gu 
+Cuo 
+Shu 
+Zhen 
+Lu 
+Meng 
+Lu 
+Hua 
+Biao 
+Ga 
+Lai 
+Ken 
+Kazari 
+Bu 
+Nai 
+Wan 
+Zan 
+[?] 
+De 
+Xian 
+[?] 
+Huo 
+Liang 
+[?] 
+Men 
+Kai 
+Ying 
+Di 
+Lian 
+Guo 
+Xian 
+Du 
+Tu 
+Wei 
+Cong 
+Fu 
+Rou 
+Ji 
+E 
+Rou 
+Chen 
+Ti 
+Zha 
+Hong 
+Yang 
+Duan 
+Xia 
+Yu 
+Keng 
+Xing 
+Huang 
+Wei 
+Fu 
+Zhao 
+Cha 
+Qie 
+She 
+Hong 
+Kui 
+Tian 
+Mou 
+Qiao 
+Qiao 
+Hou 
+Tou 
+Cong 
+Huan 
+Ye 
+Min 
+Jian 
+Duan 
+Jian 
+Song 
+Kui 
+Hu 
+Xuan 
+Duo 
+Jie 
+Zhen 
+Bian 
+Zhong 
+Zi 
+Xiu 
+Ye 
+Mei 
+Pai 
+Ai 
+Jie 
+[?] 
+Mei 
+Chuo 
+Ta 
+Bang 
+Xia 
+Lian 
+Suo 
+Xi 
+Liu 
+Zu 
+Ye 
+Nou 
+Weng 
+Rong 
+Tang 
+Suo 
+Qiang 
+Ge 
+Shuo 
+Chui 
+Bo 
+Pan 
+Sa 
+Bi 
+Sang 
+Gang 
+Zi 
+Wu 
+Ying 
+Huang 
+Tiao 
+Liu 
+Kai 
+Sun 
+Sha 
+Sou 
+Wan 
+Hao 
+Zhen 
+Zhen 
+Luo 
+Yi 
+Yuan 
+Tang 
+Nie 
+Xi 
+Jia 
+Ge 
+Ma 
+Juan 
+Kasugai 
+Habaki 
+Suo 
+[?] 
+[?] 
+[?] 
+Na 
+Lu 
+Suo 
+Ou 
+Zu 
+Tuan 
+Xiu 
+Guan 
+Xuan 
+Lian 
+Shou 
+Ao 
+Man 
+Mo 
+Luo 
+Bi 
+Wei 
+Liu 
+Di 
+Qiao 
+Cong 
+Yi 
+Lu 
+Ao 
+Keng 
+Qiang 
+Cui 
+Qi 
+Chang 
+Tang 
+Man 
+Yong 
+Chan 
+Feng 
+Jing 
+Biao 
+Shu 
+Lou 
+Xiu 
+Cong 
+Long 
+Zan 
+Jian 
+Cao 
+Li 
+Xia 
+Xi 
+Kang 
+[?] 
+Beng 
+[?] 
+[?] 
+Zheng 
+Lu 
+Hua 
+Ji 
+Pu 
+Hui 
+Qiang 
+Po 
+Lin 
+Suo 
+Xiu 
+San 
+Cheng 
+Kui 
+Si 
+Liu 
+Nao 
+Heng 
+Pie 
+Sui 
+Fan 
+Qiao 
+Quan 
+Yang 
+Tang 
+Xiang 
+Jue 
+Jiao 
+Zun 
+Liao 
+Jie 
+Lao 
+Dui 
+Tan 
+Zan 
+Ji 
+Jian 
+Zhong 
+Deng 
+Ya 
+Ying 
+Dui 
+Jue 
+Nou 
+Ti 
+Pu 
+Tie 
+[?] 
+[?] 
+Ding 
+Shan 
+Kai 
+Jian 
+Fei 
+Sui 
+Lu 
+Juan 
+Hui 
+Yu 
+Lian 
+Zhuo 
+Qiao 
+Qian 
+Zhuo 
+Lei 
+Bi 
+Tie 
+Huan 
+Ye 
+Duo 
+Guo 
+Dang 
+Ju 
+Fen 
+Da 
+Bei 
+Yi 
+Ai 
+Zong 
+Xun 
+Diao 
+Zhu 
+Heng 
+Zhui 
+Ji 
+Nie 
+Ta 
+Huo 
+Qing 
+Bin 
+Ying 
+Kui 
+Ning 
+Xu 
+Jian 
+Jian 
+Yari 
+Cha 
+Zhi 
+Mie 
+Li 
+Lei 
+Ji 
+Zuan 
+Kuang 
+Shang 
+Peng 
+La 
+Du 
+Shuo 
+Chuo 
+Lu 
+Biao 
+Bao 
+Lu 
+[?] 
+[?] 
+Long 
+E 
+Lu 
+Xin 
+Jian 
+Lan 
+Bo 
+Jian 
+Yao 
+Chan 
+Xiang 
+Jian 
+Xi 
+Guan 
+Cang 
+Nie 
+Lei 
+Cuan 
+Qu 
+Pan 
+Luo 
+Zuan 
+Luan 
+Zao 
+Nie 
+Jue 
+Tang 
+Shu 
+Lan 
+Jin 
+Qiu 
+Yi 
+Zhen 
+Ding 
+Zhao 
+Po 
+Diao 
+Tu 
+Qian 
+Chuan 
+Shan 
+Ji 
+Fan 
+Diao 
+Men 
+Nu 
+Xi 
+Chai 
+Xing 
+Gai 
+Bu 
+Tai 
+Ju 
+Dun 
+Chao 
+Zhong 
+Na 
+Bei 
+Gang 
+Ban 
+Qian 
+Yao 
+Qin 
+Jun 
+Wu 
+Gou 
+Kang 
+Fang 
+Huo 
+Tou 
+Niu 
+Ba 
+Yu 
+Qian 
+Zheng 
+Qian 
+Gu 
+Bo 
+E 
+Po 
+Bu 
+Ba 
+Yue 
+Zuan 
+Mu 
+Dan 
+Jia 
+Dian 
+You 
+Tie 
+Bo 
+Ling 
+Shuo 
+Qian 
+Liu 
+Bao 
+Shi 
+Xuan 
+She 
+Bi 
+Ni 
+Pi 
+Duo 
+Xing 
+Kao 
+Lao 
+Er 
+Mang 
+Ya 
+You 
+Cheng 
+Jia 
+Ye 
+Nao 
+Zhi 
+Dang 
+Tong 
+Lu 
+Diao 
+Yin 
+Kai 
+Zha 
+Zhu 
+Xian 
+Ting 
+Diu 
+Xian 
+Hua 
+Quan 
+Sha 
+Jia 
+Yao 
+Ge 
+Ming 
+Zheng 
+Se 
+Jiao 
+Yi 
+Chan 
+Chong 
+Tang 
+An 
+Yin 
+Ru 
+Zhu 
+Lao 
+Pu 
+Wu 
+Lai 
+Te 
+Lian 
+Keng 
+Xiao 
+Suo 
+Li 
+Zheng 
+Chu 
+Guo 
+Gao 
+Tie 
+Xiu 
+Cuo 
+Lue 
+Feng 
+Xin 
+Liu 
+Kai 
+Jian 
+Rui 
+Ti 
+Lang 
+Qian 
+Ju 
+A 
+Qiang 
+Duo 
+Tian 
+Cuo 
+Mao 
+Ben 
+Qi 
+De 
+Kua 
+Kun 
+Chang 
+Xi 
+Gu 
+Luo 
+Chui 
+Zhui 
+Jin 
+Zhi 
+Xian 
+Juan 
+Huo 
+Pou 
+Tan 
+Ding 
+Jian 
+Ju 
+Meng 
+Zi 
+Qie 
+Ying 
+Kai 
+Qiang 
+Song 
+E 
+Cha 
+Qiao 
+Zhong 
+Duan 
+Sou 
+Huang 
+Huan 
+Ai 
+Du 
+Mei 
+Lou 
+Zi 
+Fei 
+Mei 
+Mo 
+Zhen 
+Bo 
+Ge 
+Nie 
+Tang 
+Juan 
+Nie 
+Na 
+Liu 
+Hao 
+Bang 
+Yi 
+Jia 
+Bin 
+Rong 
+Biao 
+Tang 
+Man 
+Luo 
+Beng 
+Yong 
+Jing 
+Di 
+Zu 
+Xuan 
+Liu 
+Tan 
+Jue 
+Liao 
+Pu 
+Lu 
+Dui 
+Lan 
+Pu 
+Cuan 
+Qiang 
+Deng 
+Huo 
+Lei 
+Huan 
+Zhuo 
+Lian 
+Yi 
+Cha 
+Biao 
+La 
+Chan 
+Xiang 
+Chang 
+Chang 
+Jiu 
+Ao 
+Die 
+Qu 
+Liao 
+Mi 
+Chang 
+Men 
+Ma 
+Shuan 
+Shan 
+Huo 
+Men 
+Yan 
+Bi 
+Han 
+Bi 
+San 
+Kai 
+Kang 
+Beng 
+Hong 
+Run 
+San 
+Xian 
+Xian 
+Jian 
+Min 
+Xia 
+Yuru 
+Dou 
+Zha 
+Nao 
+Jian 
+Peng 
+Xia 
+Ling 
+Bian 
+Bi 
+Run 
+He 
+Guan 
+Ge 
+Ge 
+Fa 
+Chu 
+Hong 
+Gui 
+Min 
+Se 
+Kun 
+Lang 
+Lu 
+Ting 
+Sha 
+Ju 
+Yue 
+Yue 
+Chan 
+Qu 
+Lin 
+Chang 
+Shai 
+Kun 
+Yan 
+Min 
+Yan 
+E 
+Hun 
+Yu 
+Wen 
+Xiang 
+Bao 
+Xiang 
+Qu 
+Yao 
+Wen 
+Ban 
+An 
+Wei 
+Yin 
+Kuo 
+Que 
+Lan 
+Du 
+[?] 
+Phwung 
+Tian 
+Nie 
+Ta 
+Kai 
+He 
+Que 
+Chuang 
+Guan 
+Dou 
+Qi 
+Kui 
+Tang 
+Guan 
+Piao 
+Kan 
+Xi 
+Hui 
+Chan 
+Pi 
+Dang 
+Huan 
+Ta 
+Wen 
+[?] 
+Men 
+Shuan 
+Shan 
+Yan 
+Han 
+Bi 
+Wen 
+Chuang 
+Run 
+Wei 
+Xian 
+Hong 
+Jian 
+Min 
+Kang 
+Men 
+Zha 
+Nao 
+Gui 
+Wen 
+Ta 
+Min 
+Lu 
+Kai 
+Fa 
+Ge 
+He 
+Kun 
+Jiu 
+Yue 
+Lang 
+Du 
+Yu 
+Yan 
+Chang 
+Xi 
+Wen 
+Hun 
+Yan 
+E 
+Chan 
+Lan 
+Qu 
+Hui 
+Kuo 
+Que 
+Ge 
+Tian 
+Ta 
+Que 
+Kan 
+Huan 
+Fu 
+Fu 
+Le 
+Dui 
+Xin 
+Qian 
+Wu 
+Yi 
+Tuo 
+Yin 
+Yang 
+Dou 
+E 
+Sheng 
+Ban 
+Pei 
+Keng 
+Yun 
+Ruan 
+Zhi 
+Pi 
+Jing 
+Fang 
+Yang 
+Yin 
+Zhen 
+Jie 
+Cheng 
+E 
+Qu 
+Di 
+Zu 
+Zuo 
+Dian 
+Ling 
+A 
+Tuo 
+Tuo 
+Po 
+Bing 
+Fu 
+Ji 
+Lu 
+Long 
+Chen 
+Xing 
+Duo 
+Lou 
+Mo 
+Jiang 
+Shu 
+Duo 
+Xian 
+Er 
+Gui 
+Yu 
+Gai 
+Shan 
+Xun 
+Qiao 
+Xing 
+Chun 
+Fu 
+Bi 
+Xia 
+Shan 
+Sheng 
+Zhi 
+Pu 
+Dou 
+Yuan 
+Zhen 
+Chu 
+Xian 
+Tou 
+Nie 
+Yun 
+Xian 
+Pei 
+Pei 
+Zou 
+Yi 
+Dui 
+Lun 
+Yin 
+Ju 
+Chui 
+Chen 
+Pi 
+Ling 
+Tao 
+Xian 
+Lu 
+Sheng 
+Xian 
+Yin 
+Zhu 
+Yang 
+Reng 
+Shan 
+Chong 
+Yan 
+Yin 
+Yu 
+Ti 
+Yu 
+Long 
+Wei 
+Wei 
+Nie 
+Dui 
+Sui 
+An 
+Huang 
+Jie 
+Sui 
+Yin 
+Gai 
+Yan 
+Hui 
+Ge 
+Yun 
+Wu 
+Wei 
+Ai 
+Xi 
+Tang 
+Ji 
+Zhang 
+Dao 
+Ao 
+Xi 
+Yin 
+[?] 
+Rao 
+Lin 
+Tui 
+Deng 
+Pi 
+Sui 
+Sui 
+Yu 
+Xian 
+Fen 
+Ni 
+Er 
+Ji 
+Dao 
+Xi 
+Yin 
+E 
+Hui 
+Long 
+Xi 
+Li 
+Li 
+Li 
+Zhui 
+He 
+Zhi 
+Zhun 
+Jun 
+Nan 
+Yi 
+Que 
+Yan 
+Qian 
+Ya 
+Xiong 
+Ya 
+Ji 
+Gu 
+Huan 
+Zhi 
+Gou 
+Jun 
+Ci 
+Yong 
+Ju 
+Chu 
+Hu 
+Za 
+Luo 
+Yu 
+Chou 
+Diao 
+Sui 
+Han 
+Huo 
+Shuang 
+Guan 
+Chu 
+Za 
+Yong 
+Ji 
+Xi 
+Chou 
+Liu 
+Li 
+Nan 
+Xue 
+Za 
+Ji 
+Ji 
+Yu 
+Yu 
+Xue 
+Na 
+Fou 
+Se 
+Mu 
+Wen 
+Fen 
+Pang 
+Yun 
+Li 
+Li 
+Ang 
+Ling 
+Lei 
+An 
+Bao 
+Meng 
+Dian 
+Dang 
+Xing 
+Wu 
+Zhao 
+Xu 
+Ji 
+Mu 
+Chen 
+Xiao 
+Zha 
+Ting 
+Zhen 
+Pei 
+Mei 
+Ling 
+Qi 
+Chou 
+Huo 
+Sha 
+Fei 
+Weng 
+Zhan 
+Yin 
+Ni 
+Chou 
+Tun 
+Lin 
+[?] 
+Dong 
+Ying 
+Wu 
+Ling 
+Shuang 
+Ling 
+Xia 
+Hong 
+Yin 
+Mo 
+Mai 
+Yun 
+Liu 
+Meng 
+Bin 
+Wu 
+Wei 
+Huo 
+Yin 
+Xi 
+Yi 
+Ai 
+Dan 
+Deng 
+Xian 
+Yu 
+Lu 
+Long 
+Dai 
+Ji 
+Pang 
+Yang 
+Ba 
+Pi 
+Wei 
+[?] 
+Xi 
+Ji 
+Mai 
+Meng 
+Meng 
+Lei 
+Li 
+Huo 
+Ai 
+Fei 
+Dai 
+Long 
+Ling 
+Ai 
+Feng 
+Li 
+Bao 
+[?] 
+He 
+He 
+Bing 
+Qing 
+Qing 
+Jing 
+Tian 
+Zhen 
+Jing 
+Cheng 
+Qing 
+Jing 
+Jing 
+Dian 
+Jing 
+Tian 
+Fei 
+Fei 
+Kao 
+Mi 
+Mian 
+Mian 
+Pao 
+Ye 
+Tian 
+Hui 
+Ye 
+Ge 
+Ding 
+Cha 
+Jian 
+Ren 
+Di 
+Du 
+Wu 
+Ren 
+Qin 
+Jin 
+Xue 
+Niu 
+Ba 
+Yin 
+Sa 
+Na 
+Mo 
+Zu 
+Da 
+Ban 
+Yi 
+Yao 
+Tao 
+Tuo 
+Jia 
+Hong 
+Pao 
+Yang 
+Tomo 
+Yin 
+Jia 
+Tao 
+Ji 
+Xie 
+An 
+An 
+Hen 
+Gong 
+Kohaze 
+Da 
+Qiao 
+Ting 
+Wan 
+Ying 
+Sui 
+Tiao 
+Qiao 
+Xuan 
+Kong 
+Beng 
+Ta 
+Zhang 
+Bing 
+Kuo 
+Ju 
+La 
+Xie 
+Rou 
+Bang 
+Yi 
+Qiu 
+Qiu 
+He 
+Xiao 
+Mu 
+Ju 
+Jian 
+Bian 
+Di 
+Jian 
+On 
+Tao 
+Gou 
+Ta 
+Bei 
+Xie 
+Pan 
+Ge 
+Bi 
+Kuo 
+Tang 
+Lou 
+Gui 
+Qiao 
+Xue 
+Ji 
+Jian 
+Jiang 
+Chan 
+Da 
+Huo 
+Xian 
+Qian 
+Du 
+Wa 
+Jian 
+Lan 
+Wei 
+Ren 
+Fu 
+Mei 
+Juan 
+Ge 
+Wei 
+Qiao 
+Han 
+Chang 
+[?] 
+Rou 
+Xun 
+She 
+Wei 
+Ge 
+Bei 
+Tao 
+Gou 
+Yun 
+[?] 
+Bi 
+Wei 
+Hui 
+Du 
+Wa 
+Du 
+Wei 
+Ren 
+Fu 
+Han 
+Wei 
+Yun 
+Tao 
+Jiu 
+Jiu 
+Xian 
+Xie 
+Xian 
+Ji 
+Yin 
+Za 
+Yun 
+Shao 
+Le 
+Peng 
+Heng 
+Ying 
+Yun 
+Peng 
+Yin 
+Yin 
+Xiang 
+Hu 
+Ye 
+Ding 
+Qing 
+Pan 
+Xiang 
+Shun 
+Han 
+Xu 
+Yi 
+Xu 
+Gu 
+Song 
+Kui 
+Qi 
+Hang 
+Yu 
+Wan 
+Ban 
+Dun 
+Di 
+Dan 
+Pan 
+Po 
+Ling 
+Ce 
+Jing 
+Lei 
+He 
+Qiao 
+E 
+E 
+Wei 
+Jie 
+Gua 
+Shen 
+Yi 
+Shen 
+Hai 
+Dui 
+Pian 
+Ping 
+Lei 
+Fu 
+Jia 
+Tou 
+Hui 
+Kui 
+Jia 
+Le 
+Tian 
+Cheng 
+Ying 
+Jun 
+Hu 
+Han 
+Jing 
+Tui 
+Tui 
+Pin 
+Lai 
+Tui 
+Zi 
+Zi 
+Chui 
+Ding 
+Lai 
+Yan 
+Han 
+Jian 
+Ke 
+Cui 
+Jiong 
+Qin 
+Yi 
+Sai 
+Ti 
+E 
+E 
+Yan 
+Hun 
+Kan 
+Yong 
+Zhuan 
+Yan 
+Xian 
+Xin 
+Yi 
+Yuan 
+Sang 
+Dian 
+Dian 
+Jiang 
+Ku 
+Lei 
+Liao 
+Piao 
+Yi 
+Man 
+Qi 
+Rao 
+Hao 
+Qiao 
+Gu 
+Xun 
+Qian 
+Hui 
+Zhan 
+Ru 
+Hong 
+Bin 
+Xian 
+Pin 
+Lu 
+Lan 
+Nie 
+Quan 
+Ye 
+Ding 
+Qing 
+Han 
+Xiang 
+Shun 
+Xu 
+Xu 
+Wan 
+Gu 
+Dun 
+Qi 
+Ban 
+Song 
+Hang 
+Yu 
+Lu 
+Ling 
+Po 
+Jing 
+Jie 
+Jia 
+Tian 
+Han 
+Ying 
+Jiong 
+Hai 
+Yi 
+Pin 
+Hui 
+Tui 
+Han 
+Ying 
+Ying 
+Ke 
+Ti 
+Yong 
+E 
+Zhuan 
+Yan 
+E 
+Nie 
+Man 
+Dian 
+Sang 
+Hao 
+Lei 
+Zhan 
+Ru 
+Pin 
+Quan 
+Feng 
+Biao 
+Oroshi 
+Fu 
+Xia 
+Zhan 
+Biao 
+Sa 
+Ba 
+Tai 
+Lie 
+Gua 
+Xuan 
+Shao 
+Ju 
+Bi 
+Si 
+Wei 
+Yang 
+Yao 
+Sou 
+Kai 
+Sao 
+Fan 
+Liu 
+Xi 
+Liao 
+Piao 
+Piao 
+Liu 
+Biao 
+Biao 
+Biao 
+Liao 
+[?] 
+Se 
+Feng 
+Biao 
+Feng 
+Yang 
+Zhan 
+Biao 
+Sa 
+Ju 
+Si 
+Sou 
+Yao 
+Liu 
+Piao 
+Biao 
+Biao 
+Fei 
+Fan 
+Fei 
+Fei 
+Shi 
+Shi 
+Can 
+Ji 
+Ding 
+Si 
+Tuo 
+Zhan 
+Sun 
+Xiang 
+Tun 
+Ren 
+Yu 
+Juan 
+Chi 
+Yin 
+Fan 
+Fan 
+Sun 
+Yin 
+Zhu 
+Yi 
+Zhai 
+Bi 
+Jie 
+Tao 
+Liu 
+Ci 
+Tie 
+Si 
+Bao 
+Shi 
+Duo 
+Hai 
+Ren 
+Tian 
+Jiao 
+Jia 
+Bing 
+Yao 
+Tong 
+Ci 
+Xiang 
+Yang 
+Yang 
+Er 
+Yan 
+Le 
+Yi 
+Can 
+Bo 
+Nei 
+E 
+Bu 
+Jun 
+Dou 
+Su 
+Yu 
+Shi 
+Yao 
+Hun 
+Guo 
+Shi 
+Jian 
+Zhui 
+Bing 
+Xian 
+Bu 
+Ye 
+Tan 
+Fei 
+Zhang 
+Wei 
+Guan 
+E 
+Nuan 
+Hun 
+Hu 
+Huang 
+Tie 
+Hui 
+Jian 
+Hou 
+He 
+Xing 
+Fen 
+Wei 
+Gu 
+Cha 
+Song 
+Tang 
+Bo 
+Gao 
+Xi 
+Kui 
+Liu 
+Sou 
+Tao 
+Ye 
+Yun 
+Mo 
+Tang 
+Man 
+Bi 
+Yu 
+Xiu 
+Jin 
+San 
+Kui 
+Zhuan 
+Shan 
+Chi 
+Dan 
+Yi 
+Ji 
+Rao 
+Cheng 
+Yong 
+Tao 
+Hui 
+Xiang 
+Zhan 
+Fen 
+Hai 
+Meng 
+Yan 
+Mo 
+Chan 
+Xiang 
+Luo 
+Zuan 
+Nang 
+Shi 
+Ding 
+Ji 
+Tuo 
+Xing 
+Tun 
+Xi 
+Ren 
+Yu 
+Chi 
+Fan 
+Yin 
+Jian 
+Shi 
+Bao 
+Si 
+Duo 
+Yi 
+Er 
+Rao 
+Xiang 
+Jia 
+Le 
+Jiao 
+Yi 
+Bing 
+Bo 
+Dou 
+E 
+Yu 
+Nei 
+Jun 
+Guo 
+Hun 
+Xian 
+Guan 
+Cha 
+Kui 
+Gu 
+Sou 
+Chan 
+Ye 
+Mo 
+Bo 
+Liu 
+Xiu 
+Jin 
+Man 
+San 
+Zhuan 
+Nang 
+Shou 
+Kui 
+Guo 
+Xiang 
+Fen 
+Ba 
+Ni 
+Bi 
+Bo 
+Tu 
+Han 
+Fei 
+Jian 
+An 
+Ai 
+Fu 
+Xian 
+Wen 
+Xin 
+Fen 
+Bin 
+Xing 
+Ma 
+Yu 
+Feng 
+Han 
+Di 
+Tuo 
+Tuo 
+Chi 
+Xun 
+Zhu 
+Zhi 
+Pei 
+Xin 
+Ri 
+Sa 
+Yin 
+Wen 
+Zhi 
+Dan 
+Lu 
+You 
+Bo 
+Bao 
+Kuai 
+Tuo 
+Yi 
+Qu 
+[?] 
+Qu 
+Jiong 
+Bo 
+Zhao 
+Yuan 
+Peng 
+Zhou 
+Ju 
+Zhu 
+Nu 
+Ju 
+Pi 
+Zang 
+Jia 
+Ling 
+Zhen 
+Tai 
+Fu 
+Yang 
+Shi 
+Bi 
+Tuo 
+Tuo 
+Si 
+Liu 
+Ma 
+Pian 
+Tao 
+Zhi 
+Rong 
+Teng 
+Dong 
+Xun 
+Quan 
+Shen 
+Jiong 
+Er 
+Hai 
+Bo 
+Zhu 
+Yin 
+Luo 
+Shuu 
+Dan 
+Xie 
+Liu 
+Ju 
+Song 
+Qin 
+Mang 
+Liang 
+Han 
+Tu 
+Xuan 
+Tui 
+Jun 
+E 
+Cheng 
+Xin 
+Ai 
+Lu 
+Zhui 
+Zhou 
+She 
+Pian 
+Kun 
+Tao 
+Lai 
+Zong 
+Ke 
+Qi 
+Qi 
+Yan 
+Fei 
+Sao 
+Yan 
+Jie 
+Yao 
+Wu 
+Pian 
+Cong 
+Pian 
+Qian 
+Fei 
+Huang 
+Jian 
+Huo 
+Yu 
+Ti 
+Quan 
+Xia 
+Zong 
+Kui 
+Rou 
+Si 
+Gua 
+Tuo 
+Kui 
+Sou 
+Qian 
+Cheng 
+Zhi 
+Liu 
+Pang 
+Teng 
+Xi 
+Cao 
+Du 
+Yan 
+Yuan 
+Zou 
+Sao 
+Shan 
+Li 
+Zhi 
+Shuang 
+Lu 
+Xi 
+Luo 
+Zhang 
+Mo 
+Ao 
+Can 
+Piao 
+Cong 
+Qu 
+Bi 
+Zhi 
+Yu 
+Xu 
+Hua 
+Bo 
+Su 
+Xiao 
+Lin 
+Chan 
+Dun 
+Liu 
+Tuo 
+Zeng 
+Tan 
+Jiao 
+Tie 
+Yan 
+Luo 
+Zhan 
+Jing 
+Yi 
+Ye 
+Tuo 
+Bin 
+Zou 
+Yan 
+Peng 
+Lu 
+Teng 
+Xiang 
+Ji 
+Shuang 
+Ju 
+Xi 
+Huan 
+Li 
+Biao 
+Ma 
+Yu 
+Tuo 
+Xun 
+Chi 
+Qu 
+Ri 
+Bo 
+Lu 
+Zang 
+Shi 
+Si 
+Fu 
+Ju 
+Zou 
+Zhu 
+Tuo 
+Nu 
+Jia 
+Yi 
+Tai 
+Xiao 
+Ma 
+Yin 
+Jiao 
+Hua 
+Luo 
+Hai 
+Pian 
+Biao 
+Li 
+Cheng 
+Yan 
+Xin 
+Qin 
+Jun 
+Qi 
+Qi 
+Ke 
+Zhui 
+Zong 
+Su 
+Can 
+Pian 
+Zhi 
+Kui 
+Sao 
+Wu 
+Ao 
+Liu 
+Qian 
+Shan 
+Piao 
+Luo 
+Cong 
+Chan 
+Zou 
+Ji 
+Shuang 
+Xiang 
+Gu 
+Wei 
+Wei 
+Wei 
+Yu 
+Gan 
+Yi 
+Ang 
+Tou 
+Xie 
+Bao 
+Bi 
+Chi 
+Ti 
+Di 
+Ku 
+Hai 
+Qiao 
+Gou 
+Kua 
+Ge 
+Tui 
+Geng 
+Pian 
+Bi 
+Ke 
+Ka 
+Yu 
+Sui 
+Lou 
+Bo 
+Xiao 
+Pang 
+Bo 
+Ci 
+Kuan 
+Bin 
+Mo 
+Liao 
+Lou 
+Nao 
+Du 
+Zang 
+Sui 
+Ti 
+Bin 
+Kuan 
+Lu 
+Gao 
+Gao 
+Qiao 
+Kao 
+Qiao 
+Lao 
+Zao 
+Biao 
+Kun 
+Kun 
+Ti 
+Fang 
+Xiu 
+Ran 
+Mao 
+Dan 
+Kun 
+Bin 
+Fa 
+Tiao 
+Peng 
+Zi 
+Fa 
+Ran 
+Ti 
+Pao 
+Pi 
+Mao 
+Fu 
+Er 
+Rong 
+Qu 
+Gong 
+Xiu 
+Gua 
+Ji 
+Peng 
+Zhua 
+Shao 
+Sha 
+Ti 
+Li 
+Bin 
+Zong 
+Ti 
+Peng 
+Song 
+Zheng 
+Quan 
+Zong 
+Shun 
+Jian 
+Duo 
+Hu 
+La 
+Jiu 
+Qi 
+Lian 
+Zhen 
+Bin 
+Peng 
+Mo 
+San 
+Man 
+Man 
+Seng 
+Xu 
+Lie 
+Qian 
+Qian 
+Nong 
+Huan 
+Kuai 
+Ning 
+Bin 
+Lie 
+Rang 
+Dou 
+Dou 
+Nao 
+Hong 
+Xi 
+Dou 
+Han 
+Dou 
+Dou 
+Jiu 
+Chang 
+Yu 
+Yu 
+Li 
+Juan 
+Fu 
+Qian 
+Gui 
+Zong 
+Liu 
+Gui 
+Shang 
+Yu 
+Gui 
+Mei 
+Ji 
+Qi 
+Jie 
+Kui 
+Hun 
+Ba 
+Po 
+Mei 
+Xu 
+Yan 
+Xiao 
+Liang 
+Yu 
+Tui 
+Qi 
+Wang 
+Liang 
+Wei 
+Jian 
+Chi 
+Piao 
+Bi 
+Mo 
+Ji 
+Xu 
+Chou 
+Yan 
+Zhan 
+Yu 
+Dao 
+Ren 
+Ji 
+Eri 
+Gong 
+Tuo 
+Diao 
+Ji 
+Xu 
+E 
+E 
+Sha 
+Hang 
+Tun 
+Mo 
+Jie 
+Shen 
+Fan 
+Yuan 
+Bi 
+Lu 
+Wen 
+Hu 
+Lu 
+Za 
+Fang 
+Fen 
+Na 
+You 
+Namazu 
+Todo 
+He 
+Xia 
+Qu 
+Han 
+Pi 
+Ling 
+Tuo 
+Bo 
+Qiu 
+Ping 
+Fu 
+Bi 
+Ji 
+Wei 
+Ju 
+Diao 
+Bo 
+You 
+Gun 
+Pi 
+Nian 
+Xing 
+Tai 
+Bao 
+Fu 
+Zha 
+Ju 
+Gu 
+Kajika 
+Tong 
+[?] 
+Ta 
+Jie 
+Shu 
+Hou 
+Xiang 
+Er 
+An 
+Wei 
+Tiao 
+Zhu 
+Yin 
+Lie 
+Luo 
+Tong 
+Yi 
+Qi 
+Bing 
+Wei 
+Jiao 
+Bu 
+Gui 
+Xian 
+Ge 
+Hui 
+Bora 
+Mate 
+Kao 
+Gori 
+Duo 
+Jun 
+Ti 
+Man 
+Xiao 
+Za 
+Sha 
+Qin 
+Yu 
+Nei 
+Zhe 
+Gun 
+Geng 
+Su 
+Wu 
+Qiu 
+Ting 
+Fu 
+Wan 
+You 
+Li 
+Sha 
+Sha 
+Gao 
+Meng 
+Ugui 
+Asari 
+Subashiri 
+Kazunoko 
+Yong 
+Ni 
+Zi 
+Qi 
+Qing 
+Xiang 
+Nei 
+Chun 
+Ji 
+Diao 
+Qie 
+Gu 
+Zhou 
+Dong 
+Lai 
+Fei 
+Ni 
+Yi 
+Kun 
+Lu 
+Jiu 
+Chang 
+Jing 
+Lun 
+Ling 
+Zou 
+Li 
+Meng 
+Zong 
+Zhi 
+Nian 
+Shachi 
+Dojou 
+Sukesou 
+Shi 
+Shen 
+Hun 
+Shi 
+Hou 
+Xing 
+Zhu 
+La 
+Zong 
+Ji 
+Bian 
+Bian 
+Huan 
+Quan 
+Ze 
+Wei 
+Wei 
+Yu 
+Qun 
+Rou 
+Die 
+Huang 
+Lian 
+Yan 
+Qiu 
+Qiu 
+Jian 
+Bi 
+E 
+Yang 
+Fu 
+Sai 
+Jian 
+Xia 
+Tuo 
+Hu 
+Muroaji 
+Ruo 
+Haraka 
+Wen 
+Jian 
+Hao 
+Wu 
+Fang 
+Sao 
+Liu 
+Ma 
+Shi 
+Shi 
+Yin 
+Z 
+Teng 
+Ta 
+Yao 
+Ge 
+Rong 
+Qian 
+Qi 
+Wen 
+Ruo 
+Hatahata 
+Lian 
+Ao 
+Le 
+Hui 
+Min 
+Ji 
+Tiao 
+Qu 
+Jian 
+Sao 
+Man 
+Xi 
+Qiu 
+Biao 
+Ji 
+Ji 
+Zhu 
+Jiang 
+Qiu 
+Zhuan 
+Yong 
+Zhang 
+Kang 
+Xue 
+Bie 
+Jue 
+Qu 
+Xiang 
+Bo 
+Jiao 
+Xun 
+Su 
+Huang 
+Zun 
+Shan 
+Shan 
+Fan 
+Jue 
+Lin 
+Xun 
+Miao 
+Xi 
+Eso 
+Kyou 
+Fen 
+Guan 
+Hou 
+Kuai 
+Zei 
+Sao 
+Zhan 
+Gan 
+Gui 
+Sheng 
+Li 
+Chang 
+Hatahata 
+Shiira 
+Mutsu 
+Ru 
+Ji 
+Xu 
+Huo 
+Shiira 
+Li 
+Lie 
+Li 
+Mie 
+Zhen 
+Xiang 
+E 
+Lu 
+Guan 
+Li 
+Xian 
+Yu 
+Dao 
+Ji 
+You 
+Tun 
+Lu 
+Fang 
+Ba 
+He 
+Bo 
+Ping 
+Nian 
+Lu 
+You 
+Zha 
+Fu 
+Bo 
+Bao 
+Hou 
+Pi 
+Tai 
+Gui 
+Jie 
+Kao 
+Wei 
+Er 
+Tong 
+Ze 
+Hou 
+Kuai 
+Ji 
+Jiao 
+Xian 
+Za 
+Xiang 
+Xun 
+Geng 
+Li 
+Lian 
+Jian 
+Li 
+Shi 
+Tiao 
+Gun 
+Sha 
+Wan 
+Jun 
+Ji 
+Yong 
+Qing 
+Ling 
+Qi 
+Zou 
+Fei 
+Kun 
+Chang 
+Gu 
+Ni 
+Nian 
+Diao 
+Jing 
+Shen 
+Shi 
+Zi 
+Fen 
+Die 
+Bi 
+Chang 
+Shi 
+Wen 
+Wei 
+Sai 
+E 
+Qiu 
+Fu 
+Huang 
+Quan 
+Jiang 
+Bian 
+Sao 
+Ao 
+Qi 
+Ta 
+Yin 
+Yao 
+Fang 
+Jian 
+Le 
+Biao 
+Xue 
+Bie 
+Man 
+Min 
+Yong 
+Wei 
+Xi 
+Jue 
+Shan 
+Lin 
+Zun 
+Huo 
+Gan 
+Li 
+Zhan 
+Guan 
+Niao 
+Yi 
+Fu 
+Li 
+Jiu 
+Bu 
+Yan 
+Fu 
+Diao 
+Ji 
+Feng 
+Nio 
+Gan 
+Shi 
+Feng 
+Ming 
+Bao 
+Yuan 
+Zhi 
+Hu 
+Qin 
+Fu 
+Fen 
+Wen 
+Jian 
+Shi 
+Yu 
+Fou 
+Yiao 
+Jue 
+Jue 
+Pi 
+Huan 
+Zhen 
+Bao 
+Yan 
+Ya 
+Zheng 
+Fang 
+Feng 
+Wen 
+Ou 
+Te 
+Jia 
+Nu 
+Ling 
+Mie 
+Fu 
+Tuo 
+Wen 
+Li 
+Bian 
+Zhi 
+Ge 
+Yuan 
+Zi 
+Qu 
+Xiao 
+Zhi 
+Dan 
+Ju 
+You 
+Gu 
+Zhong 
+Yu 
+Yang 
+Rong 
+Ya 
+Tie 
+Yu 
+Shigi 
+Ying 
+Zhui 
+Wu 
+Er 
+Gua 
+Ai 
+Zhi 
+Yan 
+Heng 
+Jiao 
+Ji 
+Lie 
+Zhu 
+Ren 
+Yi 
+Hong 
+Luo 
+Ru 
+Mou 
+Ge 
+Ren 
+Jiao 
+Xiu 
+Zhou 
+Zhi 
+Luo 
+Chidori 
+Toki 
+Ten 
+Luan 
+Jia 
+Ji 
+Yu 
+Huan 
+Tuo 
+Bu 
+Wu 
+Juan 
+Yu 
+Bo 
+Xun 
+Xun 
+Bi 
+Xi 
+Jun 
+Ju 
+Tu 
+Jing 
+Ti 
+E 
+E 
+Kuang 
+Hu 
+Wu 
+Shen 
+Lai 
+Ikaruga 
+Kakesu 
+Lu 
+Ping 
+Shu 
+Fu 
+An 
+Zhao 
+Peng 
+Qin 
+Qian 
+Bei 
+Diao 
+Lu 
+Que 
+Jian 
+Ju 
+Tu 
+Ya 
+Yuan 
+Qi 
+Li 
+Ye 
+Zhui 
+Kong 
+Zhui 
+Kun 
+Sheng 
+Qi 
+Jing 
+Yi 
+Yi 
+Jing 
+Zi 
+Lai 
+Dong 
+Qi 
+Chun 
+Geng 
+Ju 
+Qu 
+Isuka 
+Kikuitadaki 
+Ji 
+Shu 
+[?] 
+Chi 
+Miao 
+Rou 
+An 
+Qiu 
+Ti 
+Hu 
+Ti 
+E 
+Jie 
+Mao 
+Fu 
+Chun 
+Tu 
+Yan 
+He 
+Yuan 
+Pian 
+Yun 
+Mei 
+Hu 
+Ying 
+Dun 
+Mu 
+Ju 
+Tsugumi 
+Cang 
+Fang 
+Gu 
+Ying 
+Yuan 
+Xuan 
+Weng 
+Shi 
+He 
+Chu 
+Tang 
+Xia 
+Ruo 
+Liu 
+Ji 
+Gu 
+Jian 
+Zhun 
+Han 
+Zi 
+Zi 
+Ni 
+Yao 
+Yan 
+Ji 
+Li 
+Tian 
+Kou 
+Ti 
+Ti 
+Ni 
+Tu 
+Ma 
+Jiao 
+Gao 
+Tian 
+Chen 
+Li 
+Zhuan 
+Zhe 
+Ao 
+Yao 
+Yi 
+Ou 
+Chi 
+Zhi 
+Liao 
+Rong 
+Lou 
+Bi 
+Shuang 
+Zhuo 
+Yu 
+Wu 
+Jue 
+Yin 
+Quan 
+Si 
+Jiao 
+Yi 
+Hua 
+Bi 
+Ying 
+Su 
+Huang 
+Fan 
+Jiao 
+Liao 
+Yan 
+Kao 
+Jiu 
+Xian 
+Xian 
+Tu 
+Mai 
+Zun 
+Yu 
+Ying 
+Lu 
+Tuan 
+Xian 
+Xue 
+Yi 
+Pi 
+Shu 
+Luo 
+Qi 
+Yi 
+Ji 
+Zhe 
+Yu 
+Zhan 
+Ye 
+Yang 
+Pi 
+Ning 
+Huo 
+Mi 
+Ying 
+Meng 
+Di 
+Yue 
+Yu 
+Lei 
+Bao 
+Lu 
+He 
+Long 
+Shuang 
+Yue 
+Ying 
+Guan 
+Qu 
+Li 
+Luan 
+Niao 
+Jiu 
+Ji 
+Yuan 
+Ming 
+Shi 
+Ou 
+Ya 
+Cang 
+Bao 
+Zhen 
+Gu 
+Dong 
+Lu 
+Ya 
+Xiao 
+Yang 
+Ling 
+Zhi 
+Qu 
+Yuan 
+Xue 
+Tuo 
+Si 
+Zhi 
+Er 
+Gua 
+Xiu 
+Heng 
+Zhou 
+Ge 
+Luan 
+Hong 
+Wu 
+Bo 
+Li 
+Juan 
+Hu 
+E 
+Yu 
+Xian 
+Ti 
+Wu 
+Que 
+Miao 
+An 
+Kun 
+Bei 
+Peng 
+Qian 
+Chun 
+Geng 
+Yuan 
+Su 
+Hu 
+He 
+E 
+Gu 
+Qiu 
+Zi 
+Mei 
+Mu 
+Ni 
+Yao 
+Weng 
+Liu 
+Ji 
+Ni 
+Jian 
+He 
+Yi 
+Ying 
+Zhe 
+Liao 
+Liao 
+Jiao 
+Jiu 
+Yu 
+Lu 
+Xuan 
+Zhan 
+Ying 
+Huo 
+Meng 
+Guan 
+Shuang 
+Lu 
+Jin 
+Ling 
+Jian 
+Xian 
+Cuo 
+Jian 
+Jian 
+Yan 
+Cuo 
+Lu 
+You 
+Cu 
+Ji 
+Biao 
+Cu 
+Biao 
+Zhu 
+Jun 
+Zhu 
+Jian 
+Mi 
+Mi 
+Wu 
+Liu 
+Chen 
+Jun 
+Lin 
+Ni 
+Qi 
+Lu 
+Jiu 
+Jun 
+Jing 
+Li 
+Xiang 
+Yan 
+Jia 
+Mi 
+Li 
+She 
+Zhang 
+Lin 
+Jing 
+Ji 
+Ling 
+Yan 
+Cu 
+Mai 
+Mai 
+Ge 
+Chao 
+Fu 
+Mian 
+Mian 
+Fu 
+Pao 
+Qu 
+Qu 
+Mou 
+Fu 
+Xian 
+Lai 
+Qu 
+Mian 
+[?] 
+Feng 
+Fu 
+Qu 
+Mian 
+Ma 
+Mo 
+Mo 
+Hui 
+Ma 
+Zou 
+Nen 
+Fen 
+Huang 
+Huang 
+Jin 
+Guang 
+Tian 
+Tou 
+Heng 
+Xi 
+Kuang 
+Heng 
+Shu 
+Li 
+Nian 
+Chi 
+Hei 
+Hei 
+Yi 
+Qian 
+Dan 
+Xi 
+Tuan 
+Mo 
+Mo 
+Qian 
+Dai 
+Chu 
+You 
+Dian 
+Yi 
+Xia 
+Yan 
+Qu 
+Mei 
+Yan 
+Jing 
+Yu 
+Li 
+Dang 
+Du 
+Can 
+Yin 
+An 
+Yan 
+Tan 
+An 
+Zhen 
+Dai 
+Can 
+Yi 
+Mei 
+Dan 
+Yan 
+Du 
+Lu 
+Zhi 
+Fen 
+Fu 
+Fu 
+Min 
+Min 
+Yuan 
+Cu 
+Qu 
+Chao 
+Wa 
+Zhu 
+Zhi 
+Mang 
+Ao 
+Bie 
+Tuo 
+Bi 
+Yuan 
+Chao 
+Tuo 
+Ding 
+Mi 
+Nai 
+Ding 
+Zi 
+Gu 
+Gu 
+Dong 
+Fen 
+Tao 
+Yuan 
+Pi 
+Chang 
+Gao 
+Qi 
+Yuan 
+Tang 
+Teng 
+Shu 
+Shu 
+Fen 
+Fei 
+Wen 
+Ba 
+Diao 
+Tuo 
+Tong 
+Qu 
+Sheng 
+Shi 
+You 
+Shi 
+Ting 
+Wu 
+Nian 
+Jing 
+Hun 
+Ju 
+Yan 
+Tu 
+Ti 
+Xi 
+Xian 
+Yan 
+Lei 
+Bi 
+Yao 
+Qiu 
+Han 
+Wu 
+Wu 
+Hou 
+Xi 
+Ge 
+Zha 
+Xiu 
+Weng 
+Zha 
+Nong 
+Nang 
+Qi 
+Zhai 
+Ji 
+Zi 
+Ji 
+Ji 
+Qi 
+Ji 
+Chi 
+Chen 
+Chen 
+He 
+Ya 
+Ken 
+Xie 
+Pao 
+Cuo 
+Shi 
+Zi 
+Chi 
+Nian 
+Ju 
+Tiao 
+Ling 
+Ling 
+Chu 
+Quan 
+Xie 
+Ken 
+Nie 
+Jiu 
+Yao 
+Chuo 
+Kun 
+Yu 
+Chu 
+Yi 
+Ni 
+Cuo 
+Zou 
+Qu 
+Nen 
+Xian 
+Ou 
+E 
+Wo 
+Yi 
+Chuo 
+Zou 
+Dian 
+Chu 
+Jin 
+Ya 
+Chi 
+Chen 
+He 
+Ken 
+Ju 
+Ling 
+Pao 
+Tiao 
+Zi 
+Ken 
+Yu 
+Chuo 
+Qu 
+Wo 
+Long 
+Pang 
+Gong 
+Pang 
+Yan 
+Long 
+Long 
+Gong 
+Kan 
+Ta 
+Ling 
+Ta 
+Long 
+Gong 
+Kan 
+Gui 
+Qiu 
+Bie 
+Gui 
+Yue 
+Chui 
+He 
+Jue 
+Xie 
+Yu 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+it
+ix
+i
+ip
+iet
+iex
+ie
+iep
+at
+ax
+a
+ap
+uox
+uo
+uop
+ot
+ox
+o
+op
+ex
+e
+wu
+bit
+bix
+bi
+bip
+biet
+biex
+bie
+biep
+bat
+bax
+ba
+bap
+buox
+buo
+buop
+bot
+box
+bo
+bop
+bex
+be
+bep
+but
+bux
+bu
+bup
+burx
+bur
+byt
+byx
+by
+byp
+byrx
+byr
+pit
+pix
+pi
+pip
+piex
+pie
+piep
+pat
+pax
+pa
+pap
+puox
+puo
+puop
+pot
+pox
+po
+pop
+put
+pux
+pu
+pup
+purx
+pur
+pyt
+pyx
+py
+pyp
+pyrx
+pyr
+bbit
+bbix
+bbi
+bbip
+bbiet
+bbiex
+bbie
+bbiep
+bbat
+bbax
+bba
+bbap
+bbuox
+bbuo
+bbuop
+bbot
+bbox
+bbo
+bbop
+bbex
+bbe
+bbep
+bbut
+bbux
+bbu
+bbup
+bburx
+bbur
+bbyt
+bbyx
+bby
+bbyp
+nbit
+nbix
+nbi
+nbip
+nbiex
+nbie
+nbiep
+nbat
+nbax
+nba
+nbap
+nbot
+nbox
+nbo
+nbop
+nbut
+nbux
+nbu
+nbup
+nburx
+nbur
+nbyt
+nbyx
+nby
+nbyp
+nbyrx
+nbyr
+hmit
+hmix
+hmi
+hmip
+hmiex
+hmie
+hmiep
+hmat
+hmax
+hma
+hmap
+hmuox
+hmuo
+hmuop
+hmot
+hmox
+hmo
+hmop
+hmut
+hmux
+hmu
+hmup
+hmurx
+hmur
+hmyx
+hmy
+hmyp
+hmyrx
+hmyr
+mit
+mix
+mi
+mip
+miex
+mie
+miep
+mat
+max
+ma
+map
+muot
+muox
+muo
+muop
+mot
+mox
+mo
+mop
+mex
+me
+mut
+mux
+mu
+mup
+murx
+mur
+myt
+myx
+my
+myp
+fit
+fix
+fi
+fip
+fat
+fax
+fa
+fap
+fox
+fo
+fop
+fut
+fux
+fu
+fup
+furx
+fur
+fyt
+fyx
+fy
+fyp
+vit
+vix
+vi
+vip
+viet
+viex
+vie
+viep
+vat
+vax
+va
+vap
+vot
+vox
+vo
+vop
+vex
+vep
+vut
+vux
+vu
+vup
+vurx
+vur
+vyt
+vyx
+vy
+vyp
+vyrx
+vyr
+dit
+dix
+di
+dip
+diex
+die
+diep
+dat
+dax
+da
+dap
+duox
+duo
+dot
+dox
+do
+dop
+dex
+de
+dep
+dut
+dux
+du
+dup
+durx
+dur
+tit
+tix
+ti
+tip
+tiex
+tie
+tiep
+tat
+tax
+ta
+tap
+tuot
+tuox
+tuo
+tuop
+tot
+tox
+to
+top
+tex
+te
+tep
+tut
+tux
+tu
+tup
+turx
+tur
+ddit
+ddix
+ddi
+ddip
+ddiex
+ddie
+ddiep
+ddat
+ddax
+dda
+ddap
+dduox
+dduo
+dduop
+ddot
+ddox
+ddo
+ddop
+ddex
+dde
+ddep
+ddut
+ddux
+ddu
+ddup
+ddurx
+ddur
+ndit
+ndix
+ndi
+ndip
+ndiex
+ndie
+ndat
+ndax
+nda
+ndap
+ndot
+ndox
+ndo
+ndop
+ndex
+nde
+ndep
+ndut
+ndux
+ndu
+ndup
+ndurx
+ndur
+hnit
+hnix
+hni
+hnip
+hniet
+hniex
+hnie
+hniep
+hnat
+hnax
+hna
+hnap
+hnuox
+hnuo
+hnot
+hnox
+hnop
+hnex
+hne
+hnep
+hnut
+nit
+nix
+ni
+nip
+niex
+nie
+niep
+nax
+na
+nap
+nuox
+nuo
+nuop
+not
+nox
+no
+nop
+nex
+ne
+nep
+nut
+nux
+nu
+nup
+nurx
+nur
+hlit
+hlix
+hli
+hlip
+hliex
+hlie
+hliep
+hlat
+hlax
+hla
+hlap
+hluox
+hluo
+hluop
+hlox
+hlo
+hlop
+hlex
+hle
+hlep
+hlut
+hlux
+hlu
+hlup
+hlurx
+hlur
+hlyt
+hlyx
+hly
+hlyp
+hlyrx
+hlyr
+lit
+lix
+li
+lip
+liet
+liex
+lie
+liep
+lat
+lax
+la
+lap
+luot
+luox
+luo
+luop
+lot
+lox
+lo
+lop
+lex
+le
+lep
+lut
+lux
+lu
+lup
+lurx
+lur
+lyt
+lyx
+ly
+lyp
+lyrx
+lyr
+git
+gix
+gi
+gip
+giet
+giex
+gie
+giep
+gat
+gax
+ga
+gap
+guot
+guox
+guo
+guop
+got
+gox
+go
+gop
+get
+gex
+ge
+gep
+gut
+gux
+gu
+gup
+gurx
+gur
+kit
+kix
+ki
+kip
+kiex
+kie
+kiep
+kat
+kax
+ka
+kap
+kuox
+kuo
+kuop
+kot
+kox
+ko
+kop
+ket
+kex
+ke
+kep
+kut
+kux
+ku
+kup
+kurx
+kur
+ggit
+ggix
+ggi
+ggiex
+ggie
+ggiep
+ggat
+ggax
+gga
+ggap
+gguot
+gguox
+gguo
+gguop
+ggot
+ggox
+ggo
+ggop
+gget
+ggex
+gge
+ggep
+ggut
+ggux
+ggu
+ggup
+ggurx
+ggur
+mgiex
+mgie
+mgat
+mgax
+mga
+mgap
+mguox
+mguo
+mguop
+mgot
+mgox
+mgo
+mgop
+mgex
+mge
+mgep
+mgut
+mgux
+mgu
+mgup
+mgurx
+mgur
+hxit
+hxix
+hxi
+hxip
+hxiet
+hxiex
+hxie
+hxiep
+hxat
+hxax
+hxa
+hxap
+hxuot
+hxuox
+hxuo
+hxuop
+hxot
+hxox
+hxo
+hxop
+hxex
+hxe
+hxep
+ngiex
+ngie
+ngiep
+ngat
+ngax
+nga
+ngap
+nguot
+nguox
+nguo
+ngot
+ngox
+ngo
+ngop
+ngex
+nge
+ngep
+hit
+hiex
+hie
+hat
+hax
+ha
+hap
+huot
+huox
+huo
+huop
+hot
+hox
+ho
+hop
+hex
+he
+hep
+wat
+wax
+wa
+wap
+wuox
+wuo
+wuop
+wox
+wo
+wop
+wex
+we
+wep
+zit
+zix
+zi
+zip
+ziex
+zie
+ziep
+zat
+zax
+za
+zap
+zuox
+zuo
+zuop
+zot
+zox
+zo
+zop
+zex
+ze
+zep
+zut
+zux
+zu
+zup
+zurx
+zur
+zyt
+zyx
+zy
+zyp
+zyrx
+zyr
+cit
+cix
+ci
+cip
+ciet
+ciex
+cie
+ciep
+cat
+cax
+ca
+cap
+cuox
+cuo
+cuop
+cot
+cox
+co
+cop
+cex
+ce
+cep
+cut
+cux
+cu
+cup
+curx
+cur
+cyt
+cyx
+cy
+cyp
+cyrx
+cyr
+zzit
+zzix
+zzi
+zzip
+zziet
+zziex
+zzie
+zziep
+zzat
+zzax
+zza
+zzap
+zzox
+zzo
+zzop
+zzex
+zze
+zzep
+zzux
+zzu
+zzup
+zzurx
+zzur
+zzyt
+zzyx
+zzy
+zzyp
+zzyrx
+zzyr
+nzit
+nzix
+nzi
+nzip
+nziex
+nzie
+nziep
+nzat
+nzax
+nza
+nzap
+nzuox
+nzuo
+nzox
+nzop
+nzex
+nze
+nzux
+nzu
+nzup
+nzurx
+nzur
+nzyt
+nzyx
+nzy
+nzyp
+nzyrx
+nzyr
+sit
+six
+si
+sip
+siex
+sie
+siep
+sat
+sax
+sa
+sap
+suox
+suo
+suop
+sot
+sox
+so
+sop
+sex
+se
+sep
+sut
+sux
+su
+sup
+surx
+sur
+syt
+syx
+sy
+syp
+syrx
+syr
+ssit
+ssix
+ssi
+ssip
+ssiex
+ssie
+ssiep
+ssat
+ssax
+ssa
+ssap
+ssot
+ssox
+sso
+ssop
+ssex
+sse
+ssep
+ssut
+ssux
+ssu
+ssup
+ssyt
+ssyx
+ssy
+ssyp
+ssyrx
+ssyr
+zhat
+zhax
+zha
+zhap
+zhuox
+zhuo
+zhuop
+zhot
+zhox
+zho
+zhop
+zhet
+zhex
+zhe
+zhep
+zhut
+zhux
+zhu
+zhup
+zhurx
+zhur
+zhyt
+zhyx
+zhy
+zhyp
+zhyrx
+zhyr
+chat
+chax
+cha
+chap
+chuot
+chuox
+chuo
+chuop
+chot
+chox
+cho
+chop
+chet
+chex
+che
+chep
+chux
+chu
+chup
+churx
+chur
+chyt
+chyx
+chy
+chyp
+chyrx
+chyr
+rrax
+rra
+rruox
+rruo
+rrot
+rrox
+rro
+rrop
+rret
+rrex
+rre
+rrep
+rrut
+rrux
+rru
+rrup
+rrurx
+rrur
+rryt
+rryx
+rry
+rryp
+rryrx
+rryr
+nrat
+nrax
+nra
+nrap
+nrox
+nro
+nrop
+nret
+nrex
+nre
+nrep
+nrut
+nrux
+nru
+nrup
+nrurx
+nrur
+nryt
+nryx
+nry
+nryp
+nryrx
+nryr
+shat
+shax
+sha
+shap
+shuox
+shuo
+shuop
+shot
+shox
+sho
+shop
+shet
+shex
+she
+shep
+shut
+shux
+shu
+shup
+shurx
+shur
+shyt
+shyx
+shy
+shyp
+shyrx
+shyr
+rat
+rax
+ra
+rap
+ruox
+ruo
+ruop
+rot
+rox
+ro
+rop
+rex
+re
+rep
+rut
+rux
+ru
+rup
+rurx
+rur
+ryt
+ryx
+ry
+ryp
+ryrx
+ryr
+jit
+jix
+ji
+jip
+jiet
+jiex
+jie
+jiep
+juot
+juox
+juo
+juop
+jot
+jox
+jo
+jop
+jut
+jux
+ju
+jup
+jurx
+jur
+jyt
+jyx
+jy
+jyp
+jyrx
+jyr
+qit
+qix
+qi
+qip
+qiet
+qiex
+qie
+qiep
+quot
+quox
+quo
+quop
+qot
+qox
+qo
+qop
+qut
+qux
+qu
+qup
+qurx
+qur
+qyt
+qyx
+qy
+qyp
+qyrx
+qyr
+jjit
+jjix
+jji
+jjip
+jjiet
+jjiex
+jjie
+jjiep
+jjuox
+jjuo
+jjuop
+jjot
+jjox
+jjo
+jjop
+jjut
+jjux
+jju
+jjup
+jjurx
+jjur
+jjyt
+jjyx
+jjy
+jjyp
+njit
+njix
+nji
+njip
+njiet
+njiex
+njie
+njiep
+njuox
+njuo
+njot
+njox
+njo
+njop
+njux
+nju
+njup
+njurx
+njur
+njyt
+njyx
+njy
+njyp
+njyrx
+njyr
+nyit
+nyix
+nyi
+nyip
+nyiet
+nyiex
+nyie
+nyiep
+nyuox
+nyuo
+nyuop
+nyot
+nyox
+nyo
+nyop
+nyut
+nyux
+nyu
+nyup
+xit
+xix
+xi
+xip
+xiet
+xiex
+xie
+xiep
+xuox
+xuo
+xot
+xox
+xo
+xop
+xyt
+xyx
+xy
+xyp
+xyrx
+xyr
+yit
+yix
+yi
+yip
+yiet
+yiex
+yie
+yiep
+yuot
+yuox
+yuo
+yuop
+yot
+yox
+yo
+yop
+yut
+yux
+yu
+yup
+yurx
+yur
+yyt
+yyx
+yy
+yyp
+yyrx
+yyr
+[?]
+[?]
+[?]
+Qot
+Li
+Kit
+Nyip
+Cyp
+Ssi
+Ggop
+Gep
+Mi
+Hxit
+Lyr
+Bbut
+Mop
+Yo
+Put
+Hxuo
+Tat
+Ga
+[?]
+[?]
+Ddur
+Bur
+Gguo
+Nyop
+Tu
+Op
+Jjut
+Zot
+Pyt
+Hmo
+Yit
+Vur
+Shy
+Vep
+Za
+Jo
+[?]
+Jjy
+Got
+Jjie
+Wo
+Du
+Shur
+Lie
+Cy
+Cuop
+Cip
+Hxop
+Shat
+[?]
+Shop
+Che
+Zziet
+[?]
+Ke
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ga
+gag
+gagg
+gags
+gan
+ganj
+ganh
+gad
+gal
+galg
+galm
+galb
+gals
+galt
+galp
+galh
+gam
+gab
+gabs
+gas
+gass
+gang
+gaj
+gac
+gak
+gat
+gap
+gah
+gae
+gaeg
+gaegg
+gaegs
+gaen
+gaenj
+gaenh
+gaed
+gael
+gaelg
+gaelm
+gaelb
+gaels
+gaelt
+gaelp
+gaelh
+gaem
+gaeb
+gaebs
+gaes
+gaess
+gaeng
+gaej
+gaec
+gaek
+gaet
+gaep
+gaeh
+gya
+gyag
+gyagg
+gyags
+gyan
+gyanj
+gyanh
+gyad
+gyal
+gyalg
+gyalm
+gyalb
+gyals
+gyalt
+gyalp
+gyalh
+gyam
+gyab
+gyabs
+gyas
+gyass
+gyang
+gyaj
+gyac
+gyak
+gyat
+gyap
+gyah
+gyae
+gyaeg
+gyaegg
+gyaegs
+gyaen
+gyaenj
+gyaenh
+gyaed
+gyael
+gyaelg
+gyaelm
+gyaelb
+gyaels
+gyaelt
+gyaelp
+gyaelh
+gyaem
+gyaeb
+gyaebs
+gyaes
+gyaess
+gyaeng
+gyaej
+gyaec
+gyaek
+gyaet
+gyaep
+gyaeh
+geo
+geog
+geogg
+geogs
+geon
+geonj
+geonh
+geod
+geol
+geolg
+geolm
+geolb
+geols
+geolt
+geolp
+geolh
+geom
+geob
+geobs
+geos
+geoss
+geong
+geoj
+geoc
+geok
+geot
+geop
+geoh
+ge
+geg
+gegg
+gegs
+gen
+genj
+genh
+ged
+gel
+gelg
+gelm
+gelb
+gels
+gelt
+gelp
+gelh
+gem
+geb
+gebs
+ges
+gess
+geng
+gej
+gec
+gek
+get
+gep
+geh
+gyeo
+gyeog
+gyeogg
+gyeogs
+gyeon
+gyeonj
+gyeonh
+gyeod
+gyeol
+gyeolg
+gyeolm
+gyeolb
+gyeols
+gyeolt
+gyeolp
+gyeolh
+gyeom
+gyeob
+gyeobs
+gyeos
+gyeoss
+gyeong
+gyeoj
+gyeoc
+gyeok
+gyeot
+gyeop
+gyeoh
+gye
+gyeg
+gyegg
+gyegs
+gyen
+gyenj
+gyenh
+gyed
+gyel
+gyelg
+gyelm
+gyelb
+gyels
+gyelt
+gyelp
+gyelh
+gyem
+gyeb
+gyebs
+gyes
+gyess
+gyeng
+gyej
+gyec
+gyek
+gyet
+gyep
+gyeh
+go
+gog
+gogg
+gogs
+gon
+gonj
+gonh
+god
+gol
+golg
+golm
+golb
+gols
+golt
+golp
+golh
+gom
+gob
+gobs
+gos
+goss
+gong
+goj
+goc
+gok
+got
+gop
+goh
+gwa
+gwag
+gwagg
+gwags
+gwan
+gwanj
+gwanh
+gwad
+gwal
+gwalg
+gwalm
+gwalb
+gwals
+gwalt
+gwalp
+gwalh
+gwam
+gwab
+gwabs
+gwas
+gwass
+gwang
+gwaj
+gwac
+gwak
+gwat
+gwap
+gwah
+gwae
+gwaeg
+gwaegg
+gwaegs
+gwaen
+gwaenj
+gwaenh
+gwaed
+gwael
+gwaelg
+gwaelm
+gwaelb
+gwaels
+gwaelt
+gwaelp
+gwaelh
+gwaem
+gwaeb
+gwaebs
+gwaes
+gwaess
+gwaeng
+gwaej
+gwaec
+gwaek
+gwaet
+gwaep
+gwaeh
+goe
+goeg
+goegg
+goegs
+goen
+goenj
+goenh
+goed
+goel
+goelg
+goelm
+goelb
+goels
+goelt
+goelp
+goelh
+goem
+goeb
+goebs
+goes
+goess
+goeng
+goej
+goec
+goek
+goet
+goep
+goeh
+gyo
+gyog
+gyogg
+gyogs
+gyon
+gyonj
+gyonh
+gyod
+gyol
+gyolg
+gyolm
+gyolb
+gyols
+gyolt
+gyolp
+gyolh
+gyom
+gyob
+gyobs
+gyos
+gyoss
+gyong
+gyoj
+gyoc
+gyok
+gyot
+gyop
+gyoh
+gu
+gug
+gugg
+gugs
+gun
+gunj
+gunh
+gud
+gul
+gulg
+gulm
+gulb
+guls
+gult
+gulp
+gulh
+gum
+gub
+gubs
+gus
+guss
+gung
+guj
+guc
+guk
+gut
+gup
+guh
+gweo
+gweog
+gweogg
+gweogs
+gweon
+gweonj
+gweonh
+gweod
+gweol
+gweolg
+gweolm
+gweolb
+gweols
+gweolt
+gweolp
+gweolh
+gweom
+gweob
+gweobs
+gweos
+gweoss
+gweong
+gweoj
+gweoc
+gweok
+gweot
+gweop
+gweoh
+gwe
+gweg
+gwegg
+gwegs
+gwen
+gwenj
+gwenh
+gwed
+gwel
+gwelg
+gwelm
+gwelb
+gwels
+gwelt
+gwelp
+gwelh
+gwem
+gweb
+gwebs
+gwes
+gwess
+gweng
+gwej
+gwec
+gwek
+gwet
+gwep
+gweh
+gwi
+gwig
+gwigg
+gwigs
+gwin
+gwinj
+gwinh
+gwid
+gwil
+gwilg
+gwilm
+gwilb
+gwils
+gwilt
+gwilp
+gwilh
+gwim
+gwib
+gwibs
+gwis
+gwiss
+gwing
+gwij
+gwic
+gwik
+gwit
+gwip
+gwih
+gyu
+gyug
+gyugg
+gyugs
+gyun
+gyunj
+gyunh
+gyud
+gyul
+gyulg
+gyulm
+gyulb
+gyuls
+gyult
+gyulp
+gyulh
+gyum
+gyub
+gyubs
+gyus
+gyuss
+gyung
+gyuj
+gyuc
+gyuk
+gyut
+gyup
+gyuh
+geu
+geug
+geugg
+geugs
+geun
+geunj
+geunh
+geud
+geul
+geulg
+geulm
+geulb
+geuls
+geult
+geulp
+geulh
+geum
+geub
+geubs
+geus
+geuss
+geung
+geuj
+geuc
+geuk
+geut
+geup
+geuh
+gyi
+gyig
+gyigg
+gyigs
+gyin
+gyinj
+gyinh
+gyid
+gyil
+gyilg
+gyilm
+gyilb
+gyils
+gyilt
+gyilp
+gyilh
+gyim
+gyib
+gyibs
+gyis
+gyiss
+gying
+gyij
+gyic
+gyik
+gyit
+gyip
+gyih
+gi
+gig
+gigg
+gigs
+gin
+ginj
+ginh
+gid
+gil
+gilg
+gilm
+gilb
+gils
+gilt
+gilp
+gilh
+gim
+gib
+gibs
+gis
+giss
+ging
+gij
+gic
+gik
+git
+gip
+gih
+gga
+ggag
+ggagg
+ggags
+ggan
+gganj
+gganh
+ggad
+ggal
+ggalg
+ggalm
+ggalb
+ggals
+ggalt
+ggalp
+ggalh
+ggam
+ggab
+ggabs
+ggas
+ggass
+ggang
+ggaj
+ggac
+ggak
+ggat
+ggap
+ggah
+ggae
+ggaeg
+ggaegg
+ggaegs
+ggaen
+ggaenj
+ggaenh
+ggaed
+ggael
+ggaelg
+ggaelm
+ggaelb
+ggaels
+ggaelt
+ggaelp
+ggaelh
+ggaem
+ggaeb
+ggaebs
+ggaes
+ggaess
+ggaeng
+ggaej
+ggaec
+ggaek
+ggaet
+ggaep
+ggaeh
+ggya
+ggyag
+ggyagg
+ggyags
+ggyan
+ggyanj
+ggyanh
+ggyad
+ggyal
+ggyalg
+ggyalm
+ggyalb
+ggyals
+ggyalt
+ggyalp
+ggyalh
+ggyam
+ggyab
+ggyabs
+ggyas
+ggyass
+ggyang
+ggyaj
+ggyac
+ggyak
+ggyat
+ggyap
+ggyah
+ggyae
+ggyaeg
+ggyaegg
+ggyaegs
+ggyaen
+ggyaenj
+ggyaenh
+ggyaed
+ggyael
+ggyaelg
+ggyaelm
+ggyaelb
+ggyaels
+ggyaelt
+ggyaelp
+ggyaelh
+ggyaem
+ggyaeb
+ggyaebs
+ggyaes
+ggyaess
+ggyaeng
+ggyaej
+ggyaec
+ggyaek
+ggyaet
+ggyaep
+ggyaeh
+ggeo
+ggeog
+ggeogg
+ggeogs
+ggeon
+ggeonj
+ggeonh
+ggeod
+ggeol
+ggeolg
+ggeolm
+ggeolb
+ggeols
+ggeolt
+ggeolp
+ggeolh
+ggeom
+ggeob
+ggeobs
+ggeos
+ggeoss
+ggeong
+ggeoj
+ggeoc
+ggeok
+ggeot
+ggeop
+ggeoh
+gge
+ggeg
+ggegg
+ggegs
+ggen
+ggenj
+ggenh
+gged
+ggel
+ggelg
+ggelm
+ggelb
+ggels
+ggelt
+ggelp
+ggelh
+ggem
+ggeb
+ggebs
+gges
+ggess
+ggeng
+ggej
+ggec
+ggek
+gget
+ggep
+ggeh
+ggyeo
+ggyeog
+ggyeogg
+ggyeogs
+ggyeon
+ggyeonj
+ggyeonh
+ggyeod
+ggyeol
+ggyeolg
+ggyeolm
+ggyeolb
+ggyeols
+ggyeolt
+ggyeolp
+ggyeolh
+ggyeom
+ggyeob
+ggyeobs
+ggyeos
+ggyeoss
+ggyeong
+ggyeoj
+ggyeoc
+ggyeok
+ggyeot
+ggyeop
+ggyeoh
+ggye
+ggyeg
+ggyegg
+ggyegs
+ggyen
+ggyenj
+ggyenh
+ggyed
+ggyel
+ggyelg
+ggyelm
+ggyelb
+ggyels
+ggyelt
+ggyelp
+ggyelh
+ggyem
+ggyeb
+ggyebs
+ggyes
+ggyess
+ggyeng
+ggyej
+ggyec
+ggyek
+ggyet
+ggyep
+ggyeh
+ggo
+ggog
+ggogg
+ggogs
+ggon
+ggonj
+ggonh
+ggod
+ggol
+ggolg
+ggolm
+ggolb
+ggols
+ggolt
+ggolp
+ggolh
+ggom
+ggob
+ggobs
+ggos
+ggoss
+ggong
+ggoj
+ggoc
+ggok
+ggot
+ggop
+ggoh
+ggwa
+ggwag
+ggwagg
+ggwags
+ggwan
+ggwanj
+ggwanh
+ggwad
+ggwal
+ggwalg
+ggwalm
+ggwalb
+ggwals
+ggwalt
+ggwalp
+ggwalh
+ggwam
+ggwab
+ggwabs
+ggwas
+ggwass
+ggwang
+ggwaj
+ggwac
+ggwak
+ggwat
+ggwap
+ggwah
+ggwae
+ggwaeg
+ggwaegg
+ggwaegs
+ggwaen
+ggwaenj
+ggwaenh
+ggwaed
+ggwael
+ggwaelg
+ggwaelm
+ggwaelb
+ggwaels
+ggwaelt
+ggwaelp
+ggwaelh
+ggwaem
+ggwaeb
+ggwaebs
+ggwaes
+ggwaess
+ggwaeng
+ggwaej
+ggwaec
+ggwaek
+ggwaet
+ggwaep
+ggwaeh
+ggoe
+ggoeg
+ggoegg
+ggoegs
+ggoen
+ggoenj
+ggoenh
+ggoed
+ggoel
+ggoelg
+ggoelm
+ggoelb
+ggoels
+ggoelt
+ggoelp
+ggoelh
+ggoem
+ggoeb
+ggoebs
+ggoes
+ggoess
+ggoeng
+ggoej
+ggoec
+ggoek
+ggoet
+ggoep
+ggoeh
+ggyo
+ggyog
+ggyogg
+ggyogs
+ggyon
+ggyonj
+ggyonh
+ggyod
+ggyol
+ggyolg
+ggyolm
+ggyolb
+ggyols
+ggyolt
+ggyolp
+ggyolh
+ggyom
+ggyob
+ggyobs
+ggyos
+ggyoss
+ggyong
+ggyoj
+ggyoc
+ggyok
+ggyot
+ggyop
+ggyoh
+ggu
+ggug
+ggugg
+ggugs
+ggun
+ggunj
+ggunh
+ggud
+ggul
+ggulg
+ggulm
+ggulb
+gguls
+ggult
+ggulp
+ggulh
+ggum
+ggub
+ggubs
+ggus
+gguss
+ggung
+gguj
+gguc
+gguk
+ggut
+ggup
+gguh
+ggweo
+ggweog
+ggweogg
+ggweogs
+ggweon
+ggweonj
+ggweonh
+ggweod
+ggweol
+ggweolg
+ggweolm
+ggweolb
+ggweols
+ggweolt
+ggweolp
+ggweolh
+ggweom
+ggweob
+ggweobs
+ggweos
+ggweoss
+ggweong
+ggweoj
+ggweoc
+ggweok
+ggweot
+ggweop
+ggweoh
+ggwe
+ggweg
+ggwegg
+ggwegs
+ggwen
+ggwenj
+ggwenh
+ggwed
+ggwel
+ggwelg
+ggwelm
+ggwelb
+ggwels
+ggwelt
+ggwelp
+ggwelh
+ggwem
+ggweb
+ggwebs
+ggwes
+ggwess
+ggweng
+ggwej
+ggwec
+ggwek
+ggwet
+ggwep
+ggweh
+ggwi
+ggwig
+ggwigg
+ggwigs
+ggwin
+ggwinj
+ggwinh
+ggwid
+ggwil
+ggwilg
+ggwilm
+ggwilb
+ggwils
+ggwilt
+ggwilp
+ggwilh
+ggwim
+ggwib
+ggwibs
+ggwis
+ggwiss
+ggwing
+ggwij
+ggwic
+ggwik
+ggwit
+ggwip
+ggwih
+ggyu
+ggyug
+ggyugg
+ggyugs
+ggyun
+ggyunj
+ggyunh
+ggyud
+ggyul
+ggyulg
+ggyulm
+ggyulb
+ggyuls
+ggyult
+ggyulp
+ggyulh
+ggyum
+ggyub
+ggyubs
+ggyus
+ggyuss
+ggyung
+ggyuj
+ggyuc
+ggyuk
+ggyut
+ggyup
+ggyuh
+ggeu
+ggeug
+ggeugg
+ggeugs
+ggeun
+ggeunj
+ggeunh
+ggeud
+ggeul
+ggeulg
+ggeulm
+ggeulb
+ggeuls
+ggeult
+ggeulp
+ggeulh
+ggeum
+ggeub
+ggeubs
+ggeus
+ggeuss
+ggeung
+ggeuj
+ggeuc
+ggeuk
+ggeut
+ggeup
+ggeuh
+ggyi
+ggyig
+ggyigg
+ggyigs
+ggyin
+ggyinj
+ggyinh
+ggyid
+ggyil
+ggyilg
+ggyilm
+ggyilb
+ggyils
+ggyilt
+ggyilp
+ggyilh
+ggyim
+ggyib
+ggyibs
+ggyis
+ggyiss
+ggying
+ggyij
+ggyic
+ggyik
+ggyit
+ggyip
+ggyih
+ggi
+ggig
+ggigg
+ggigs
+ggin
+gginj
+gginh
+ggid
+ggil
+ggilg
+ggilm
+ggilb
+ggils
+ggilt
+ggilp
+ggilh
+ggim
+ggib
+ggibs
+ggis
+ggiss
+gging
+ggij
+ggic
+ggik
+ggit
+ggip
+ggih
+na
+nag
+nagg
+nags
+nan
+nanj
+nanh
+nad
+nal
+nalg
+nalm
+nalb
+nals
+nalt
+nalp
+nalh
+nam
+nab
+nabs
+nas
+nass
+nang
+naj
+nac
+nak
+nat
+nap
+nah
+nae
+naeg
+naegg
+naegs
+naen
+naenj
+naenh
+naed
+nael
+naelg
+naelm
+naelb
+naels
+naelt
+naelp
+naelh
+naem
+naeb
+naebs
+naes
+naess
+naeng
+naej
+naec
+naek
+naet
+naep
+naeh
+nya
+nyag
+nyagg
+nyags
+nyan
+nyanj
+nyanh
+nyad
+nyal
+nyalg
+nyalm
+nyalb
+nyals
+nyalt
+nyalp
+nyalh
+nyam
+nyab
+nyabs
+nyas
+nyass
+nyang
+nyaj
+nyac
+nyak
+nyat
+nyap
+nyah
+nyae
+nyaeg
+nyaegg
+nyaegs
+nyaen
+nyaenj
+nyaenh
+nyaed
+nyael
+nyaelg
+nyaelm
+nyaelb
+nyaels
+nyaelt
+nyaelp
+nyaelh
+nyaem
+nyaeb
+nyaebs
+nyaes
+nyaess
+nyaeng
+nyaej
+nyaec
+nyaek
+nyaet
+nyaep
+nyaeh
+neo
+neog
+neogg
+neogs
+neon
+neonj
+neonh
+neod
+neol
+neolg
+neolm
+neolb
+neols
+neolt
+neolp
+neolh
+neom
+neob
+neobs
+neos
+neoss
+neong
+neoj
+neoc
+neok
+neot
+neop
+neoh
+ne
+neg
+negg
+negs
+nen
+nenj
+nenh
+ned
+nel
+nelg
+nelm
+nelb
+nels
+nelt
+nelp
+nelh
+nem
+neb
+nebs
+nes
+ness
+neng
+nej
+nec
+nek
+net
+nep
+neh
+nyeo
+nyeog
+nyeogg
+nyeogs
+nyeon
+nyeonj
+nyeonh
+nyeod
+nyeol
+nyeolg
+nyeolm
+nyeolb
+nyeols
+nyeolt
+nyeolp
+nyeolh
+nyeom
+nyeob
+nyeobs
+nyeos
+nyeoss
+nyeong
+nyeoj
+nyeoc
+nyeok
+nyeot
+nyeop
+nyeoh
+nye
+nyeg
+nyegg
+nyegs
+nyen
+nyenj
+nyenh
+nyed
+nyel
+nyelg
+nyelm
+nyelb
+nyels
+nyelt
+nyelp
+nyelh
+nyem
+nyeb
+nyebs
+nyes
+nyess
+nyeng
+nyej
+nyec
+nyek
+nyet
+nyep
+nyeh
+no
+nog
+nogg
+nogs
+non
+nonj
+nonh
+nod
+nol
+nolg
+nolm
+nolb
+nols
+nolt
+nolp
+nolh
+nom
+nob
+nobs
+nos
+noss
+nong
+noj
+noc
+nok
+not
+nop
+noh
+nwa
+nwag
+nwagg
+nwags
+nwan
+nwanj
+nwanh
+nwad
+nwal
+nwalg
+nwalm
+nwalb
+nwals
+nwalt
+nwalp
+nwalh
+nwam
+nwab
+nwabs
+nwas
+nwass
+nwang
+nwaj
+nwac
+nwak
+nwat
+nwap
+nwah
+nwae
+nwaeg
+nwaegg
+nwaegs
+nwaen
+nwaenj
+nwaenh
+nwaed
+nwael
+nwaelg
+nwaelm
+nwaelb
+nwaels
+nwaelt
+nwaelp
+nwaelh
+nwaem
+nwaeb
+nwaebs
+nwaes
+nwaess
+nwaeng
+nwaej
+nwaec
+nwaek
+nwaet
+nwaep
+nwaeh
+noe
+noeg
+noegg
+noegs
+noen
+noenj
+noenh
+noed
+noel
+noelg
+noelm
+noelb
+noels
+noelt
+noelp
+noelh
+noem
+noeb
+noebs
+noes
+noess
+noeng
+noej
+noec
+noek
+noet
+noep
+noeh
+nyo
+nyog
+nyogg
+nyogs
+nyon
+nyonj
+nyonh
+nyod
+nyol
+nyolg
+nyolm
+nyolb
+nyols
+nyolt
+nyolp
+nyolh
+nyom
+nyob
+nyobs
+nyos
+nyoss
+nyong
+nyoj
+nyoc
+nyok
+nyot
+nyop
+nyoh
+nu
+nug
+nugg
+nugs
+nun
+nunj
+nunh
+nud
+nul
+nulg
+nulm
+nulb
+nuls
+nult
+nulp
+nulh
+num
+nub
+nubs
+nus
+nuss
+nung
+nuj
+nuc
+nuk
+nut
+nup
+nuh
+nweo
+nweog
+nweogg
+nweogs
+nweon
+nweonj
+nweonh
+nweod
+nweol
+nweolg
+nweolm
+nweolb
+nweols
+nweolt
+nweolp
+nweolh
+nweom
+nweob
+nweobs
+nweos
+nweoss
+nweong
+nweoj
+nweoc
+nweok
+nweot
+nweop
+nweoh
+nwe
+nweg
+nwegg
+nwegs
+nwen
+nwenj
+nwenh
+nwed
+nwel
+nwelg
+nwelm
+nwelb
+nwels
+nwelt
+nwelp
+nwelh
+nwem
+nweb
+nwebs
+nwes
+nwess
+nweng
+nwej
+nwec
+nwek
+nwet
+nwep
+nweh
+nwi
+nwig
+nwigg
+nwigs
+nwin
+nwinj
+nwinh
+nwid
+nwil
+nwilg
+nwilm
+nwilb
+nwils
+nwilt
+nwilp
+nwilh
+nwim
+nwib
+nwibs
+nwis
+nwiss
+nwing
+nwij
+nwic
+nwik
+nwit
+nwip
+nwih
+nyu
+nyug
+nyugg
+nyugs
+nyun
+nyunj
+nyunh
+nyud
+nyul
+nyulg
+nyulm
+nyulb
+nyuls
+nyult
+nyulp
+nyulh
+nyum
+nyub
+nyubs
+nyus
+nyuss
+nyung
+nyuj
+nyuc
+nyuk
+nyut
+nyup
+nyuh
+neu
+neug
+neugg
+neugs
+neun
+neunj
+neunh
+neud
+neul
+neulg
+neulm
+neulb
+neuls
+neult
+neulp
+neulh
+neum
+neub
+neubs
+neus
+neuss
+neung
+neuj
+neuc
+neuk
+neut
+neup
+neuh
+nyi
+nyig
+nyigg
+nyigs
+nyin
+nyinj
+nyinh
+nyid
+nyil
+nyilg
+nyilm
+nyilb
+nyils
+nyilt
+nyilp
+nyilh
+nyim
+nyib
+nyibs
+nyis
+nyiss
+nying
+nyij
+nyic
+nyik
+nyit
+nyip
+nyih
+ni
+nig
+nigg
+nigs
+nin
+ninj
+ninh
+nid
+nil
+nilg
+nilm
+nilb
+nils
+nilt
+nilp
+nilh
+nim
+nib
+nibs
+nis
+niss
+ning
+nij
+nic
+nik
+nit
+nip
+nih
+da
+dag
+dagg
+dags
+dan
+danj
+danh
+dad
+dal
+dalg
+dalm
+dalb
+dals
+dalt
+dalp
+dalh
+dam
+dab
+dabs
+das
+dass
+dang
+daj
+dac
+dak
+dat
+dap
+dah
+dae
+daeg
+daegg
+daegs
+daen
+daenj
+daenh
+daed
+dael
+daelg
+daelm
+daelb
+daels
+daelt
+daelp
+daelh
+daem
+daeb
+daebs
+daes
+daess
+daeng
+daej
+daec
+daek
+daet
+daep
+daeh
+dya
+dyag
+dyagg
+dyags
+dyan
+dyanj
+dyanh
+dyad
+dyal
+dyalg
+dyalm
+dyalb
+dyals
+dyalt
+dyalp
+dyalh
+dyam
+dyab
+dyabs
+dyas
+dyass
+dyang
+dyaj
+dyac
+dyak
+dyat
+dyap
+dyah
+dyae
+dyaeg
+dyaegg
+dyaegs
+dyaen
+dyaenj
+dyaenh
+dyaed
+dyael
+dyaelg
+dyaelm
+dyaelb
+dyaels
+dyaelt
+dyaelp
+dyaelh
+dyaem
+dyaeb
+dyaebs
+dyaes
+dyaess
+dyaeng
+dyaej
+dyaec
+dyaek
+dyaet
+dyaep
+dyaeh
+deo
+deog
+deogg
+deogs
+deon
+deonj
+deonh
+deod
+deol
+deolg
+deolm
+deolb
+deols
+deolt
+deolp
+deolh
+deom
+deob
+deobs
+deos
+deoss
+deong
+deoj
+deoc
+deok
+deot
+deop
+deoh
+de
+deg
+degg
+degs
+den
+denj
+denh
+ded
+del
+delg
+delm
+delb
+dels
+delt
+delp
+delh
+dem
+deb
+debs
+des
+dess
+deng
+dej
+dec
+dek
+det
+dep
+deh
+dyeo
+dyeog
+dyeogg
+dyeogs
+dyeon
+dyeonj
+dyeonh
+dyeod
+dyeol
+dyeolg
+dyeolm
+dyeolb
+dyeols
+dyeolt
+dyeolp
+dyeolh
+dyeom
+dyeob
+dyeobs
+dyeos
+dyeoss
+dyeong
+dyeoj
+dyeoc
+dyeok
+dyeot
+dyeop
+dyeoh
+dye
+dyeg
+dyegg
+dyegs
+dyen
+dyenj
+dyenh
+dyed
+dyel
+dyelg
+dyelm
+dyelb
+dyels
+dyelt
+dyelp
+dyelh
+dyem
+dyeb
+dyebs
+dyes
+dyess
+dyeng
+dyej
+dyec
+dyek
+dyet
+dyep
+dyeh
+do
+dog
+dogg
+dogs
+don
+donj
+donh
+dod
+dol
+dolg
+dolm
+dolb
+dols
+dolt
+dolp
+dolh
+dom
+dob
+dobs
+dos
+doss
+dong
+doj
+doc
+dok
+dot
+dop
+doh
+dwa
+dwag
+dwagg
+dwags
+dwan
+dwanj
+dwanh
+dwad
+dwal
+dwalg
+dwalm
+dwalb
+dwals
+dwalt
+dwalp
+dwalh
+dwam
+dwab
+dwabs
+dwas
+dwass
+dwang
+dwaj
+dwac
+dwak
+dwat
+dwap
+dwah
+dwae
+dwaeg
+dwaegg
+dwaegs
+dwaen
+dwaenj
+dwaenh
+dwaed
+dwael
+dwaelg
+dwaelm
+dwaelb
+dwaels
+dwaelt
+dwaelp
+dwaelh
+dwaem
+dwaeb
+dwaebs
+dwaes
+dwaess
+dwaeng
+dwaej
+dwaec
+dwaek
+dwaet
+dwaep
+dwaeh
+doe
+doeg
+doegg
+doegs
+doen
+doenj
+doenh
+doed
+doel
+doelg
+doelm
+doelb
+doels
+doelt
+doelp
+doelh
+doem
+doeb
+doebs
+does
+doess
+doeng
+doej
+doec
+doek
+doet
+doep
+doeh
+dyo
+dyog
+dyogg
+dyogs
+dyon
+dyonj
+dyonh
+dyod
+dyol
+dyolg
+dyolm
+dyolb
+dyols
+dyolt
+dyolp
+dyolh
+dyom
+dyob
+dyobs
+dyos
+dyoss
+dyong
+dyoj
+dyoc
+dyok
+dyot
+dyop
+dyoh
+du
+dug
+dugg
+dugs
+dun
+dunj
+dunh
+dud
+dul
+dulg
+dulm
+dulb
+duls
+dult
+dulp
+dulh
+dum
+dub
+dubs
+dus
+duss
+dung
+duj
+duc
+duk
+dut
+dup
+duh
+dweo
+dweog
+dweogg
+dweogs
+dweon
+dweonj
+dweonh
+dweod
+dweol
+dweolg
+dweolm
+dweolb
+dweols
+dweolt
+dweolp
+dweolh
+dweom
+dweob
+dweobs
+dweos
+dweoss
+dweong
+dweoj
+dweoc
+dweok
+dweot
+dweop
+dweoh
+dwe
+dweg
+dwegg
+dwegs
+dwen
+dwenj
+dwenh
+dwed
+dwel
+dwelg
+dwelm
+dwelb
+dwels
+dwelt
+dwelp
+dwelh
+dwem
+dweb
+dwebs
+dwes
+dwess
+dweng
+dwej
+dwec
+dwek
+dwet
+dwep
+dweh
+dwi
+dwig
+dwigg
+dwigs
+dwin
+dwinj
+dwinh
+dwid
+dwil
+dwilg
+dwilm
+dwilb
+dwils
+dwilt
+dwilp
+dwilh
+dwim
+dwib
+dwibs
+dwis
+dwiss
+dwing
+dwij
+dwic
+dwik
+dwit
+dwip
+dwih
+dyu
+dyug
+dyugg
+dyugs
+dyun
+dyunj
+dyunh
+dyud
+dyul
+dyulg
+dyulm
+dyulb
+dyuls
+dyult
+dyulp
+dyulh
+dyum
+dyub
+dyubs
+dyus
+dyuss
+dyung
+dyuj
+dyuc
+dyuk
+dyut
+dyup
+dyuh
+deu
+deug
+deugg
+deugs
+deun
+deunj
+deunh
+deud
+deul
+deulg
+deulm
+deulb
+deuls
+deult
+deulp
+deulh
+deum
+deub
+deubs
+deus
+deuss
+deung
+deuj
+deuc
+deuk
+deut
+deup
+deuh
+dyi
+dyig
+dyigg
+dyigs
+dyin
+dyinj
+dyinh
+dyid
+dyil
+dyilg
+dyilm
+dyilb
+dyils
+dyilt
+dyilp
+dyilh
+dyim
+dyib
+dyibs
+dyis
+dyiss
+dying
+dyij
+dyic
+dyik
+dyit
+dyip
+dyih
+di
+dig
+digg
+digs
+din
+dinj
+dinh
+did
+dil
+dilg
+dilm
+dilb
+dils
+dilt
+dilp
+dilh
+dim
+dib
+dibs
+dis
+diss
+ding
+dij
+dic
+dik
+dit
+dip
+dih
+dda
+ddag
+ddagg
+ddags
+ddan
+ddanj
+ddanh
+ddad
+ddal
+ddalg
+ddalm
+ddalb
+ddals
+ddalt
+ddalp
+ddalh
+ddam
+ddab
+ddabs
+ddas
+ddass
+ddang
+ddaj
+ddac
+ddak
+ddat
+ddap
+ddah
+ddae
+ddaeg
+ddaegg
+ddaegs
+ddaen
+ddaenj
+ddaenh
+ddaed
+ddael
+ddaelg
+ddaelm
+ddaelb
+ddaels
+ddaelt
+ddaelp
+ddaelh
+ddaem
+ddaeb
+ddaebs
+ddaes
+ddaess
+ddaeng
+ddaej
+ddaec
+ddaek
+ddaet
+ddaep
+ddaeh
+ddya
+ddyag
+ddyagg
+ddyags
+ddyan
+ddyanj
+ddyanh
+ddyad
+ddyal
+ddyalg
+ddyalm
+ddyalb
+ddyals
+ddyalt
+ddyalp
+ddyalh
+ddyam
+ddyab
+ddyabs
+ddyas
+ddyass
+ddyang
+ddyaj
+ddyac
+ddyak
+ddyat
+ddyap
+ddyah
+ddyae
+ddyaeg
+ddyaegg
+ddyaegs
+ddyaen
+ddyaenj
+ddyaenh
+ddyaed
+ddyael
+ddyaelg
+ddyaelm
+ddyaelb
+ddyaels
+ddyaelt
+ddyaelp
+ddyaelh
+ddyaem
+ddyaeb
+ddyaebs
+ddyaes
+ddyaess
+ddyaeng
+ddyaej
+ddyaec
+ddyaek
+ddyaet
+ddyaep
+ddyaeh
+ddeo
+ddeog
+ddeogg
+ddeogs
+ddeon
+ddeonj
+ddeonh
+ddeod
+ddeol
+ddeolg
+ddeolm
+ddeolb
+ddeols
+ddeolt
+ddeolp
+ddeolh
+ddeom
+ddeob
+ddeobs
+ddeos
+ddeoss
+ddeong
+ddeoj
+ddeoc
+ddeok
+ddeot
+ddeop
+ddeoh
+dde
+ddeg
+ddegg
+ddegs
+dden
+ddenj
+ddenh
+dded
+ddel
+ddelg
+ddelm
+ddelb
+ddels
+ddelt
+ddelp
+ddelh
+ddem
+ddeb
+ddebs
+ddes
+ddess
+ddeng
+ddej
+ddec
+ddek
+ddet
+ddep
+ddeh
+ddyeo
+ddyeog
+ddyeogg
+ddyeogs
+ddyeon
+ddyeonj
+ddyeonh
+ddyeod
+ddyeol
+ddyeolg
+ddyeolm
+ddyeolb
+ddyeols
+ddyeolt
+ddyeolp
+ddyeolh
+ddyeom
+ddyeob
+ddyeobs
+ddyeos
+ddyeoss
+ddyeong
+ddyeoj
+ddyeoc
+ddyeok
+ddyeot
+ddyeop
+ddyeoh
+ddye
+ddyeg
+ddyegg
+ddyegs
+ddyen
+ddyenj
+ddyenh
+ddyed
+ddyel
+ddyelg
+ddyelm
+ddyelb
+ddyels
+ddyelt
+ddyelp
+ddyelh
+ddyem
+ddyeb
+ddyebs
+ddyes
+ddyess
+ddyeng
+ddyej
+ddyec
+ddyek
+ddyet
+ddyep
+ddyeh
+ddo
+ddog
+ddogg
+ddogs
+ddon
+ddonj
+ddonh
+ddod
+ddol
+ddolg
+ddolm
+ddolb
+ddols
+ddolt
+ddolp
+ddolh
+ddom
+ddob
+ddobs
+ddos
+ddoss
+ddong
+ddoj
+ddoc
+ddok
+ddot
+ddop
+ddoh
+ddwa
+ddwag
+ddwagg
+ddwags
+ddwan
+ddwanj
+ddwanh
+ddwad
+ddwal
+ddwalg
+ddwalm
+ddwalb
+ddwals
+ddwalt
+ddwalp
+ddwalh
+ddwam
+ddwab
+ddwabs
+ddwas
+ddwass
+ddwang
+ddwaj
+ddwac
+ddwak
+ddwat
+ddwap
+ddwah
+ddwae
+ddwaeg
+ddwaegg
+ddwaegs
+ddwaen
+ddwaenj
+ddwaenh
+ddwaed
+ddwael
+ddwaelg
+ddwaelm
+ddwaelb
+ddwaels
+ddwaelt
+ddwaelp
+ddwaelh
+ddwaem
+ddwaeb
+ddwaebs
+ddwaes
+ddwaess
+ddwaeng
+ddwaej
+ddwaec
+ddwaek
+ddwaet
+ddwaep
+ddwaeh
+ddoe
+ddoeg
+ddoegg
+ddoegs
+ddoen
+ddoenj
+ddoenh
+ddoed
+ddoel
+ddoelg
+ddoelm
+ddoelb
+ddoels
+ddoelt
+ddoelp
+ddoelh
+ddoem
+ddoeb
+ddoebs
+ddoes
+ddoess
+ddoeng
+ddoej
+ddoec
+ddoek
+ddoet
+ddoep
+ddoeh
+ddyo
+ddyog
+ddyogg
+ddyogs
+ddyon
+ddyonj
+ddyonh
+ddyod
+ddyol
+ddyolg
+ddyolm
+ddyolb
+ddyols
+ddyolt
+ddyolp
+ddyolh
+ddyom
+ddyob
+ddyobs
+ddyos
+ddyoss
+ddyong
+ddyoj
+ddyoc
+ddyok
+ddyot
+ddyop
+ddyoh
+ddu
+ddug
+ddugg
+ddugs
+ddun
+ddunj
+ddunh
+ddud
+ddul
+ddulg
+ddulm
+ddulb
+dduls
+ddult
+ddulp
+ddulh
+ddum
+ddub
+ddubs
+ddus
+dduss
+ddung
+dduj
+dduc
+dduk
+ddut
+ddup
+dduh
+ddweo
+ddweog
+ddweogg
+ddweogs
+ddweon
+ddweonj
+ddweonh
+ddweod
+ddweol
+ddweolg
+ddweolm
+ddweolb
+ddweols
+ddweolt
+ddweolp
+ddweolh
+ddweom
+ddweob
+ddweobs
+ddweos
+ddweoss
+ddweong
+ddweoj
+ddweoc
+ddweok
+ddweot
+ddweop
+ddweoh
+ddwe
+ddweg
+ddwegg
+ddwegs
+ddwen
+ddwenj
+ddwenh
+ddwed
+ddwel
+ddwelg
+ddwelm
+ddwelb
+ddwels
+ddwelt
+ddwelp
+ddwelh
+ddwem
+ddweb
+ddwebs
+ddwes
+ddwess
+ddweng
+ddwej
+ddwec
+ddwek
+ddwet
+ddwep
+ddweh
+ddwi
+ddwig
+ddwigg
+ddwigs
+ddwin
+ddwinj
+ddwinh
+ddwid
+ddwil
+ddwilg
+ddwilm
+ddwilb
+ddwils
+ddwilt
+ddwilp
+ddwilh
+ddwim
+ddwib
+ddwibs
+ddwis
+ddwiss
+ddwing
+ddwij
+ddwic
+ddwik
+ddwit
+ddwip
+ddwih
+ddyu
+ddyug
+ddyugg
+ddyugs
+ddyun
+ddyunj
+ddyunh
+ddyud
+ddyul
+ddyulg
+ddyulm
+ddyulb
+ddyuls
+ddyult
+ddyulp
+ddyulh
+ddyum
+ddyub
+ddyubs
+ddyus
+ddyuss
+ddyung
+ddyuj
+ddyuc
+ddyuk
+ddyut
+ddyup
+ddyuh
+ddeu
+ddeug
+ddeugg
+ddeugs
+ddeun
+ddeunj
+ddeunh
+ddeud
+ddeul
+ddeulg
+ddeulm
+ddeulb
+ddeuls
+ddeult
+ddeulp
+ddeulh
+ddeum
+ddeub
+ddeubs
+ddeus
+ddeuss
+ddeung
+ddeuj
+ddeuc
+ddeuk
+ddeut
+ddeup
+ddeuh
+ddyi
+ddyig
+ddyigg
+ddyigs
+ddyin
+ddyinj
+ddyinh
+ddyid
+ddyil
+ddyilg
+ddyilm
+ddyilb
+ddyils
+ddyilt
+ddyilp
+ddyilh
+ddyim
+ddyib
+ddyibs
+ddyis
+ddyiss
+ddying
+ddyij
+ddyic
+ddyik
+ddyit
+ddyip
+ddyih
+ddi
+ddig
+ddigg
+ddigs
+ddin
+ddinj
+ddinh
+ddid
+ddil
+ddilg
+ddilm
+ddilb
+ddils
+ddilt
+ddilp
+ddilh
+ddim
+ddib
+ddibs
+ddis
+ddiss
+dding
+ddij
+ddic
+ddik
+ddit
+ddip
+ddih
+ra
+rag
+ragg
+rags
+ran
+ranj
+ranh
+rad
+ral
+ralg
+ralm
+ralb
+rals
+ralt
+ralp
+ralh
+ram
+rab
+rabs
+ras
+rass
+rang
+raj
+rac
+rak
+rat
+rap
+rah
+rae
+raeg
+raegg
+raegs
+raen
+raenj
+raenh
+raed
+rael
+raelg
+raelm
+raelb
+raels
+raelt
+raelp
+raelh
+raem
+raeb
+raebs
+raes
+raess
+raeng
+raej
+raec
+raek
+raet
+raep
+raeh
+rya
+ryag
+ryagg
+ryags
+ryan
+ryanj
+ryanh
+ryad
+ryal
+ryalg
+ryalm
+ryalb
+ryals
+ryalt
+ryalp
+ryalh
+ryam
+ryab
+ryabs
+ryas
+ryass
+ryang
+ryaj
+ryac
+ryak
+ryat
+ryap
+ryah
+ryae
+ryaeg
+ryaegg
+ryaegs
+ryaen
+ryaenj
+ryaenh
+ryaed
+ryael
+ryaelg
+ryaelm
+ryaelb
+ryaels
+ryaelt
+ryaelp
+ryaelh
+ryaem
+ryaeb
+ryaebs
+ryaes
+ryaess
+ryaeng
+ryaej
+ryaec
+ryaek
+ryaet
+ryaep
+ryaeh
+reo
+reog
+reogg
+reogs
+reon
+reonj
+reonh
+reod
+reol
+reolg
+reolm
+reolb
+reols
+reolt
+reolp
+reolh
+reom
+reob
+reobs
+reos
+reoss
+reong
+reoj
+reoc
+reok
+reot
+reop
+reoh
+re
+reg
+regg
+regs
+ren
+renj
+renh
+red
+rel
+relg
+relm
+relb
+rels
+relt
+relp
+relh
+rem
+reb
+rebs
+res
+ress
+reng
+rej
+rec
+rek
+ret
+rep
+reh
+ryeo
+ryeog
+ryeogg
+ryeogs
+ryeon
+ryeonj
+ryeonh
+ryeod
+ryeol
+ryeolg
+ryeolm
+ryeolb
+ryeols
+ryeolt
+ryeolp
+ryeolh
+ryeom
+ryeob
+ryeobs
+ryeos
+ryeoss
+ryeong
+ryeoj
+ryeoc
+ryeok
+ryeot
+ryeop
+ryeoh
+rye
+ryeg
+ryegg
+ryegs
+ryen
+ryenj
+ryenh
+ryed
+ryel
+ryelg
+ryelm
+ryelb
+ryels
+ryelt
+ryelp
+ryelh
+ryem
+ryeb
+ryebs
+ryes
+ryess
+ryeng
+ryej
+ryec
+ryek
+ryet
+ryep
+ryeh
+ro
+rog
+rogg
+rogs
+ron
+ronj
+ronh
+rod
+rol
+rolg
+rolm
+rolb
+rols
+rolt
+rolp
+rolh
+rom
+rob
+robs
+ros
+ross
+rong
+roj
+roc
+rok
+rot
+rop
+roh
+rwa
+rwag
+rwagg
+rwags
+rwan
+rwanj
+rwanh
+rwad
+rwal
+rwalg
+rwalm
+rwalb
+rwals
+rwalt
+rwalp
+rwalh
+rwam
+rwab
+rwabs
+rwas
+rwass
+rwang
+rwaj
+rwac
+rwak
+rwat
+rwap
+rwah
+rwae
+rwaeg
+rwaegg
+rwaegs
+rwaen
+rwaenj
+rwaenh
+rwaed
+rwael
+rwaelg
+rwaelm
+rwaelb
+rwaels
+rwaelt
+rwaelp
+rwaelh
+rwaem
+rwaeb
+rwaebs
+rwaes
+rwaess
+rwaeng
+rwaej
+rwaec
+rwaek
+rwaet
+rwaep
+rwaeh
+roe
+roeg
+roegg
+roegs
+roen
+roenj
+roenh
+roed
+roel
+roelg
+roelm
+roelb
+roels
+roelt
+roelp
+roelh
+roem
+roeb
+roebs
+roes
+roess
+roeng
+roej
+roec
+roek
+roet
+roep
+roeh
+ryo
+ryog
+ryogg
+ryogs
+ryon
+ryonj
+ryonh
+ryod
+ryol
+ryolg
+ryolm
+ryolb
+ryols
+ryolt
+ryolp
+ryolh
+ryom
+ryob
+ryobs
+ryos
+ryoss
+ryong
+ryoj
+ryoc
+ryok
+ryot
+ryop
+ryoh
+ru
+rug
+rugg
+rugs
+run
+runj
+runh
+rud
+rul
+rulg
+rulm
+rulb
+ruls
+rult
+rulp
+rulh
+rum
+rub
+rubs
+rus
+russ
+rung
+ruj
+ruc
+ruk
+rut
+rup
+ruh
+rweo
+rweog
+rweogg
+rweogs
+rweon
+rweonj
+rweonh
+rweod
+rweol
+rweolg
+rweolm
+rweolb
+rweols
+rweolt
+rweolp
+rweolh
+rweom
+rweob
+rweobs
+rweos
+rweoss
+rweong
+rweoj
+rweoc
+rweok
+rweot
+rweop
+rweoh
+rwe
+rweg
+rwegg
+rwegs
+rwen
+rwenj
+rwenh
+rwed
+rwel
+rwelg
+rwelm
+rwelb
+rwels
+rwelt
+rwelp
+rwelh
+rwem
+rweb
+rwebs
+rwes
+rwess
+rweng
+rwej
+rwec
+rwek
+rwet
+rwep
+rweh
+rwi
+rwig
+rwigg
+rwigs
+rwin
+rwinj
+rwinh
+rwid
+rwil
+rwilg
+rwilm
+rwilb
+rwils
+rwilt
+rwilp
+rwilh
+rwim
+rwib
+rwibs
+rwis
+rwiss
+rwing
+rwij
+rwic
+rwik
+rwit
+rwip
+rwih
+ryu
+ryug
+ryugg
+ryugs
+ryun
+ryunj
+ryunh
+ryud
+ryul
+ryulg
+ryulm
+ryulb
+ryuls
+ryult
+ryulp
+ryulh
+ryum
+ryub
+ryubs
+ryus
+ryuss
+ryung
+ryuj
+ryuc
+ryuk
+ryut
+ryup
+ryuh
+reu
+reug
+reugg
+reugs
+reun
+reunj
+reunh
+reud
+reul
+reulg
+reulm
+reulb
+reuls
+reult
+reulp
+reulh
+reum
+reub
+reubs
+reus
+reuss
+reung
+reuj
+reuc
+reuk
+reut
+reup
+reuh
+ryi
+ryig
+ryigg
+ryigs
+ryin
+ryinj
+ryinh
+ryid
+ryil
+ryilg
+ryilm
+ryilb
+ryils
+ryilt
+ryilp
+ryilh
+ryim
+ryib
+ryibs
+ryis
+ryiss
+rying
+ryij
+ryic
+ryik
+ryit
+ryip
+ryih
+ri
+rig
+rigg
+rigs
+rin
+rinj
+rinh
+rid
+ril
+rilg
+rilm
+rilb
+rils
+rilt
+rilp
+rilh
+rim
+rib
+ribs
+ris
+riss
+ring
+rij
+ric
+rik
+rit
+rip
+rih
+ma
+mag
+magg
+mags
+man
+manj
+manh
+mad
+mal
+malg
+malm
+malb
+mals
+malt
+malp
+malh
+mam
+mab
+mabs
+mas
+mass
+mang
+maj
+mac
+mak
+mat
+map
+mah
+mae
+maeg
+maegg
+maegs
+maen
+maenj
+maenh
+maed
+mael
+maelg
+maelm
+maelb
+maels
+maelt
+maelp
+maelh
+maem
+maeb
+maebs
+maes
+maess
+maeng
+maej
+maec
+maek
+maet
+maep
+maeh
+mya
+myag
+myagg
+myags
+myan
+myanj
+myanh
+myad
+myal
+myalg
+myalm
+myalb
+myals
+myalt
+myalp
+myalh
+myam
+myab
+myabs
+myas
+myass
+myang
+myaj
+myac
+myak
+myat
+myap
+myah
+myae
+myaeg
+myaegg
+myaegs
+myaen
+myaenj
+myaenh
+myaed
+myael
+myaelg
+myaelm
+myaelb
+myaels
+myaelt
+myaelp
+myaelh
+myaem
+myaeb
+myaebs
+myaes
+myaess
+myaeng
+myaej
+myaec
+myaek
+myaet
+myaep
+myaeh
+meo
+meog
+meogg
+meogs
+meon
+meonj
+meonh
+meod
+meol
+meolg
+meolm
+meolb
+meols
+meolt
+meolp
+meolh
+meom
+meob
+meobs
+meos
+meoss
+meong
+meoj
+meoc
+meok
+meot
+meop
+meoh
+me
+meg
+megg
+megs
+men
+menj
+menh
+med
+mel
+melg
+melm
+melb
+mels
+melt
+melp
+melh
+mem
+meb
+mebs
+mes
+mess
+meng
+mej
+mec
+mek
+met
+mep
+meh
+myeo
+myeog
+myeogg
+myeogs
+myeon
+myeonj
+myeonh
+myeod
+myeol
+myeolg
+myeolm
+myeolb
+myeols
+myeolt
+myeolp
+myeolh
+myeom
+myeob
+myeobs
+myeos
+myeoss
+myeong
+myeoj
+myeoc
+myeok
+myeot
+myeop
+myeoh
+mye
+myeg
+myegg
+myegs
+myen
+myenj
+myenh
+myed
+myel
+myelg
+myelm
+myelb
+myels
+myelt
+myelp
+myelh
+myem
+myeb
+myebs
+myes
+myess
+myeng
+myej
+myec
+myek
+myet
+myep
+myeh
+mo
+mog
+mogg
+mogs
+mon
+monj
+monh
+mod
+mol
+molg
+molm
+molb
+mols
+molt
+molp
+molh
+mom
+mob
+mobs
+mos
+moss
+mong
+moj
+moc
+mok
+mot
+mop
+moh
+mwa
+mwag
+mwagg
+mwags
+mwan
+mwanj
+mwanh
+mwad
+mwal
+mwalg
+mwalm
+mwalb
+mwals
+mwalt
+mwalp
+mwalh
+mwam
+mwab
+mwabs
+mwas
+mwass
+mwang
+mwaj
+mwac
+mwak
+mwat
+mwap
+mwah
+mwae
+mwaeg
+mwaegg
+mwaegs
+mwaen
+mwaenj
+mwaenh
+mwaed
+mwael
+mwaelg
+mwaelm
+mwaelb
+mwaels
+mwaelt
+mwaelp
+mwaelh
+mwaem
+mwaeb
+mwaebs
+mwaes
+mwaess
+mwaeng
+mwaej
+mwaec
+mwaek
+mwaet
+mwaep
+mwaeh
+moe
+moeg
+moegg
+moegs
+moen
+moenj
+moenh
+moed
+moel
+moelg
+moelm
+moelb
+moels
+moelt
+moelp
+moelh
+moem
+moeb
+moebs
+moes
+moess
+moeng
+moej
+moec
+moek
+moet
+moep
+moeh
+myo
+myog
+myogg
+myogs
+myon
+myonj
+myonh
+myod
+myol
+myolg
+myolm
+myolb
+myols
+myolt
+myolp
+myolh
+myom
+myob
+myobs
+myos
+myoss
+myong
+myoj
+myoc
+myok
+myot
+myop
+myoh
+mu
+mug
+mugg
+mugs
+mun
+munj
+munh
+mud
+mul
+mulg
+mulm
+mulb
+muls
+mult
+mulp
+mulh
+mum
+mub
+mubs
+mus
+muss
+mung
+muj
+muc
+muk
+mut
+mup
+muh
+mweo
+mweog
+mweogg
+mweogs
+mweon
+mweonj
+mweonh
+mweod
+mweol
+mweolg
+mweolm
+mweolb
+mweols
+mweolt
+mweolp
+mweolh
+mweom
+mweob
+mweobs
+mweos
+mweoss
+mweong
+mweoj
+mweoc
+mweok
+mweot
+mweop
+mweoh
+mwe
+mweg
+mwegg
+mwegs
+mwen
+mwenj
+mwenh
+mwed
+mwel
+mwelg
+mwelm
+mwelb
+mwels
+mwelt
+mwelp
+mwelh
+mwem
+mweb
+mwebs
+mwes
+mwess
+mweng
+mwej
+mwec
+mwek
+mwet
+mwep
+mweh
+mwi
+mwig
+mwigg
+mwigs
+mwin
+mwinj
+mwinh
+mwid
+mwil
+mwilg
+mwilm
+mwilb
+mwils
+mwilt
+mwilp
+mwilh
+mwim
+mwib
+mwibs
+mwis
+mwiss
+mwing
+mwij
+mwic
+mwik
+mwit
+mwip
+mwih
+myu
+myug
+myugg
+myugs
+myun
+myunj
+myunh
+myud
+myul
+myulg
+myulm
+myulb
+myuls
+myult
+myulp
+myulh
+myum
+myub
+myubs
+myus
+myuss
+myung
+myuj
+myuc
+myuk
+myut
+myup
+myuh
+meu
+meug
+meugg
+meugs
+meun
+meunj
+meunh
+meud
+meul
+meulg
+meulm
+meulb
+meuls
+meult
+meulp
+meulh
+meum
+meub
+meubs
+meus
+meuss
+meung
+meuj
+meuc
+meuk
+meut
+meup
+meuh
+myi
+myig
+myigg
+myigs
+myin
+myinj
+myinh
+myid
+myil
+myilg
+myilm
+myilb
+myils
+myilt
+myilp
+myilh
+myim
+myib
+myibs
+myis
+myiss
+mying
+myij
+myic
+myik
+myit
+myip
+myih
+mi
+mig
+migg
+migs
+min
+minj
+minh
+mid
+mil
+milg
+milm
+milb
+mils
+milt
+milp
+milh
+mim
+mib
+mibs
+mis
+miss
+ming
+mij
+mic
+mik
+mit
+mip
+mih
+ba
+bag
+bagg
+bags
+ban
+banj
+banh
+bad
+bal
+balg
+balm
+balb
+bals
+balt
+balp
+balh
+bam
+bab
+babs
+bas
+bass
+bang
+baj
+bac
+bak
+bat
+bap
+bah
+bae
+baeg
+baegg
+baegs
+baen
+baenj
+baenh
+baed
+bael
+baelg
+baelm
+baelb
+baels
+baelt
+baelp
+baelh
+baem
+baeb
+baebs
+baes
+baess
+baeng
+baej
+baec
+baek
+baet
+baep
+baeh
+bya
+byag
+byagg
+byags
+byan
+byanj
+byanh
+byad
+byal
+byalg
+byalm
+byalb
+byals
+byalt
+byalp
+byalh
+byam
+byab
+byabs
+byas
+byass
+byang
+byaj
+byac
+byak
+byat
+byap
+byah
+byae
+byaeg
+byaegg
+byaegs
+byaen
+byaenj
+byaenh
+byaed
+byael
+byaelg
+byaelm
+byaelb
+byaels
+byaelt
+byaelp
+byaelh
+byaem
+byaeb
+byaebs
+byaes
+byaess
+byaeng
+byaej
+byaec
+byaek
+byaet
+byaep
+byaeh
+beo
+beog
+beogg
+beogs
+beon
+beonj
+beonh
+beod
+beol
+beolg
+beolm
+beolb
+beols
+beolt
+beolp
+beolh
+beom
+beob
+beobs
+beos
+beoss
+beong
+beoj
+beoc
+beok
+beot
+beop
+beoh
+be
+beg
+begg
+begs
+ben
+benj
+benh
+bed
+bel
+belg
+belm
+belb
+bels
+belt
+belp
+belh
+bem
+beb
+bebs
+bes
+bess
+beng
+bej
+bec
+bek
+bet
+bep
+beh
+byeo
+byeog
+byeogg
+byeogs
+byeon
+byeonj
+byeonh
+byeod
+byeol
+byeolg
+byeolm
+byeolb
+byeols
+byeolt
+byeolp
+byeolh
+byeom
+byeob
+byeobs
+byeos
+byeoss
+byeong
+byeoj
+byeoc
+byeok
+byeot
+byeop
+byeoh
+bye
+byeg
+byegg
+byegs
+byen
+byenj
+byenh
+byed
+byel
+byelg
+byelm
+byelb
+byels
+byelt
+byelp
+byelh
+byem
+byeb
+byebs
+byes
+byess
+byeng
+byej
+byec
+byek
+byet
+byep
+byeh
+bo
+bog
+bogg
+bogs
+bon
+bonj
+bonh
+bod
+bol
+bolg
+bolm
+bolb
+bols
+bolt
+bolp
+bolh
+bom
+bob
+bobs
+bos
+boss
+bong
+boj
+boc
+bok
+bot
+bop
+boh
+bwa
+bwag
+bwagg
+bwags
+bwan
+bwanj
+bwanh
+bwad
+bwal
+bwalg
+bwalm
+bwalb
+bwals
+bwalt
+bwalp
+bwalh
+bwam
+bwab
+bwabs
+bwas
+bwass
+bwang
+bwaj
+bwac
+bwak
+bwat
+bwap
+bwah
+bwae
+bwaeg
+bwaegg
+bwaegs
+bwaen
+bwaenj
+bwaenh
+bwaed
+bwael
+bwaelg
+bwaelm
+bwaelb
+bwaels
+bwaelt
+bwaelp
+bwaelh
+bwaem
+bwaeb
+bwaebs
+bwaes
+bwaess
+bwaeng
+bwaej
+bwaec
+bwaek
+bwaet
+bwaep
+bwaeh
+boe
+boeg
+boegg
+boegs
+boen
+boenj
+boenh
+boed
+boel
+boelg
+boelm
+boelb
+boels
+boelt
+boelp
+boelh
+boem
+boeb
+boebs
+boes
+boess
+boeng
+boej
+boec
+boek
+boet
+boep
+boeh
+byo
+byog
+byogg
+byogs
+byon
+byonj
+byonh
+byod
+byol
+byolg
+byolm
+byolb
+byols
+byolt
+byolp
+byolh
+byom
+byob
+byobs
+byos
+byoss
+byong
+byoj
+byoc
+byok
+byot
+byop
+byoh
+bu
+bug
+bugg
+bugs
+bun
+bunj
+bunh
+bud
+bul
+bulg
+bulm
+bulb
+buls
+bult
+bulp
+bulh
+bum
+bub
+bubs
+bus
+buss
+bung
+buj
+buc
+buk
+but
+bup
+buh
+bweo
+bweog
+bweogg
+bweogs
+bweon
+bweonj
+bweonh
+bweod
+bweol
+bweolg
+bweolm
+bweolb
+bweols
+bweolt
+bweolp
+bweolh
+bweom
+bweob
+bweobs
+bweos
+bweoss
+bweong
+bweoj
+bweoc
+bweok
+bweot
+bweop
+bweoh
+bwe
+bweg
+bwegg
+bwegs
+bwen
+bwenj
+bwenh
+bwed
+bwel
+bwelg
+bwelm
+bwelb
+bwels
+bwelt
+bwelp
+bwelh
+bwem
+bweb
+bwebs
+bwes
+bwess
+bweng
+bwej
+bwec
+bwek
+bwet
+bwep
+bweh
+bwi
+bwig
+bwigg
+bwigs
+bwin
+bwinj
+bwinh
+bwid
+bwil
+bwilg
+bwilm
+bwilb
+bwils
+bwilt
+bwilp
+bwilh
+bwim
+bwib
+bwibs
+bwis
+bwiss
+bwing
+bwij
+bwic
+bwik
+bwit
+bwip
+bwih
+byu
+byug
+byugg
+byugs
+byun
+byunj
+byunh
+byud
+byul
+byulg
+byulm
+byulb
+byuls
+byult
+byulp
+byulh
+byum
+byub
+byubs
+byus
+byuss
+byung
+byuj
+byuc
+byuk
+byut
+byup
+byuh
+beu
+beug
+beugg
+beugs
+beun
+beunj
+beunh
+beud
+beul
+beulg
+beulm
+beulb
+beuls
+beult
+beulp
+beulh
+beum
+beub
+beubs
+beus
+beuss
+beung
+beuj
+beuc
+beuk
+beut
+beup
+beuh
+byi
+byig
+byigg
+byigs
+byin
+byinj
+byinh
+byid
+byil
+byilg
+byilm
+byilb
+byils
+byilt
+byilp
+byilh
+byim
+byib
+byibs
+byis
+byiss
+bying
+byij
+byic
+byik
+byit
+byip
+byih
+bi
+big
+bigg
+bigs
+bin
+binj
+binh
+bid
+bil
+bilg
+bilm
+bilb
+bils
+bilt
+bilp
+bilh
+bim
+bib
+bibs
+bis
+biss
+bing
+bij
+bic
+bik
+bit
+bip
+bih
+bba
+bbag
+bbagg
+bbags
+bban
+bbanj
+bbanh
+bbad
+bbal
+bbalg
+bbalm
+bbalb
+bbals
+bbalt
+bbalp
+bbalh
+bbam
+bbab
+bbabs
+bbas
+bbass
+bbang
+bbaj
+bbac
+bbak
+bbat
+bbap
+bbah
+bbae
+bbaeg
+bbaegg
+bbaegs
+bbaen
+bbaenj
+bbaenh
+bbaed
+bbael
+bbaelg
+bbaelm
+bbaelb
+bbaels
+bbaelt
+bbaelp
+bbaelh
+bbaem
+bbaeb
+bbaebs
+bbaes
+bbaess
+bbaeng
+bbaej
+bbaec
+bbaek
+bbaet
+bbaep
+bbaeh
+bbya
+bbyag
+bbyagg
+bbyags
+bbyan
+bbyanj
+bbyanh
+bbyad
+bbyal
+bbyalg
+bbyalm
+bbyalb
+bbyals
+bbyalt
+bbyalp
+bbyalh
+bbyam
+bbyab
+bbyabs
+bbyas
+bbyass
+bbyang
+bbyaj
+bbyac
+bbyak
+bbyat
+bbyap
+bbyah
+bbyae
+bbyaeg
+bbyaegg
+bbyaegs
+bbyaen
+bbyaenj
+bbyaenh
+bbyaed
+bbyael
+bbyaelg
+bbyaelm
+bbyaelb
+bbyaels
+bbyaelt
+bbyaelp
+bbyaelh
+bbyaem
+bbyaeb
+bbyaebs
+bbyaes
+bbyaess
+bbyaeng
+bbyaej
+bbyaec
+bbyaek
+bbyaet
+bbyaep
+bbyaeh
+bbeo
+bbeog
+bbeogg
+bbeogs
+bbeon
+bbeonj
+bbeonh
+bbeod
+bbeol
+bbeolg
+bbeolm
+bbeolb
+bbeols
+bbeolt
+bbeolp
+bbeolh
+bbeom
+bbeob
+bbeobs
+bbeos
+bbeoss
+bbeong
+bbeoj
+bbeoc
+bbeok
+bbeot
+bbeop
+bbeoh
+bbe
+bbeg
+bbegg
+bbegs
+bben
+bbenj
+bbenh
+bbed
+bbel
+bbelg
+bbelm
+bbelb
+bbels
+bbelt
+bbelp
+bbelh
+bbem
+bbeb
+bbebs
+bbes
+bbess
+bbeng
+bbej
+bbec
+bbek
+bbet
+bbep
+bbeh
+bbyeo
+bbyeog
+bbyeogg
+bbyeogs
+bbyeon
+bbyeonj
+bbyeonh
+bbyeod
+bbyeol
+bbyeolg
+bbyeolm
+bbyeolb
+bbyeols
+bbyeolt
+bbyeolp
+bbyeolh
+bbyeom
+bbyeob
+bbyeobs
+bbyeos
+bbyeoss
+bbyeong
+bbyeoj
+bbyeoc
+bbyeok
+bbyeot
+bbyeop
+bbyeoh
+bbye
+bbyeg
+bbyegg
+bbyegs
+bbyen
+bbyenj
+bbyenh
+bbyed
+bbyel
+bbyelg
+bbyelm
+bbyelb
+bbyels
+bbyelt
+bbyelp
+bbyelh
+bbyem
+bbyeb
+bbyebs
+bbyes
+bbyess
+bbyeng
+bbyej
+bbyec
+bbyek
+bbyet
+bbyep
+bbyeh
+bbo
+bbog
+bbogg
+bbogs
+bbon
+bbonj
+bbonh
+bbod
+bbol
+bbolg
+bbolm
+bbolb
+bbols
+bbolt
+bbolp
+bbolh
+bbom
+bbob
+bbobs
+bbos
+bboss
+bbong
+bboj
+bboc
+bbok
+bbot
+bbop
+bboh
+bbwa
+bbwag
+bbwagg
+bbwags
+bbwan
+bbwanj
+bbwanh
+bbwad
+bbwal
+bbwalg
+bbwalm
+bbwalb
+bbwals
+bbwalt
+bbwalp
+bbwalh
+bbwam
+bbwab
+bbwabs
+bbwas
+bbwass
+bbwang
+bbwaj
+bbwac
+bbwak
+bbwat
+bbwap
+bbwah
+bbwae
+bbwaeg
+bbwaegg
+bbwaegs
+bbwaen
+bbwaenj
+bbwaenh
+bbwaed
+bbwael
+bbwaelg
+bbwaelm
+bbwaelb
+bbwaels
+bbwaelt
+bbwaelp
+bbwaelh
+bbwaem
+bbwaeb
+bbwaebs
+bbwaes
+bbwaess
+bbwaeng
+bbwaej
+bbwaec
+bbwaek
+bbwaet
+bbwaep
+bbwaeh
+bboe
+bboeg
+bboegg
+bboegs
+bboen
+bboenj
+bboenh
+bboed
+bboel
+bboelg
+bboelm
+bboelb
+bboels
+bboelt
+bboelp
+bboelh
+bboem
+bboeb
+bboebs
+bboes
+bboess
+bboeng
+bboej
+bboec
+bboek
+bboet
+bboep
+bboeh
+bbyo
+bbyog
+bbyogg
+bbyogs
+bbyon
+bbyonj
+bbyonh
+bbyod
+bbyol
+bbyolg
+bbyolm
+bbyolb
+bbyols
+bbyolt
+bbyolp
+bbyolh
+bbyom
+bbyob
+bbyobs
+bbyos
+bbyoss
+bbyong
+bbyoj
+bbyoc
+bbyok
+bbyot
+bbyop
+bbyoh
+bbu
+bbug
+bbugg
+bbugs
+bbun
+bbunj
+bbunh
+bbud
+bbul
+bbulg
+bbulm
+bbulb
+bbuls
+bbult
+bbulp
+bbulh
+bbum
+bbub
+bbubs
+bbus
+bbuss
+bbung
+bbuj
+bbuc
+bbuk
+bbut
+bbup
+bbuh
+bbweo
+bbweog
+bbweogg
+bbweogs
+bbweon
+bbweonj
+bbweonh
+bbweod
+bbweol
+bbweolg
+bbweolm
+bbweolb
+bbweols
+bbweolt
+bbweolp
+bbweolh
+bbweom
+bbweob
+bbweobs
+bbweos
+bbweoss
+bbweong
+bbweoj
+bbweoc
+bbweok
+bbweot
+bbweop
+bbweoh
+bbwe
+bbweg
+bbwegg
+bbwegs
+bbwen
+bbwenj
+bbwenh
+bbwed
+bbwel
+bbwelg
+bbwelm
+bbwelb
+bbwels
+bbwelt
+bbwelp
+bbwelh
+bbwem
+bbweb
+bbwebs
+bbwes
+bbwess
+bbweng
+bbwej
+bbwec
+bbwek
+bbwet
+bbwep
+bbweh
+bbwi
+bbwig
+bbwigg
+bbwigs
+bbwin
+bbwinj
+bbwinh
+bbwid
+bbwil
+bbwilg
+bbwilm
+bbwilb
+bbwils
+bbwilt
+bbwilp
+bbwilh
+bbwim
+bbwib
+bbwibs
+bbwis
+bbwiss
+bbwing
+bbwij
+bbwic
+bbwik
+bbwit
+bbwip
+bbwih
+bbyu
+bbyug
+bbyugg
+bbyugs
+bbyun
+bbyunj
+bbyunh
+bbyud
+bbyul
+bbyulg
+bbyulm
+bbyulb
+bbyuls
+bbyult
+bbyulp
+bbyulh
+bbyum
+bbyub
+bbyubs
+bbyus
+bbyuss
+bbyung
+bbyuj
+bbyuc
+bbyuk
+bbyut
+bbyup
+bbyuh
+bbeu
+bbeug
+bbeugg
+bbeugs
+bbeun
+bbeunj
+bbeunh
+bbeud
+bbeul
+bbeulg
+bbeulm
+bbeulb
+bbeuls
+bbeult
+bbeulp
+bbeulh
+bbeum
+bbeub
+bbeubs
+bbeus
+bbeuss
+bbeung
+bbeuj
+bbeuc
+bbeuk
+bbeut
+bbeup
+bbeuh
+bbyi
+bbyig
+bbyigg
+bbyigs
+bbyin
+bbyinj
+bbyinh
+bbyid
+bbyil
+bbyilg
+bbyilm
+bbyilb
+bbyils
+bbyilt
+bbyilp
+bbyilh
+bbyim
+bbyib
+bbyibs
+bbyis
+bbyiss
+bbying
+bbyij
+bbyic
+bbyik
+bbyit
+bbyip
+bbyih
+bbi
+bbig
+bbigg
+bbigs
+bbin
+bbinj
+bbinh
+bbid
+bbil
+bbilg
+bbilm
+bbilb
+bbils
+bbilt
+bbilp
+bbilh
+bbim
+bbib
+bbibs
+bbis
+bbiss
+bbing
+bbij
+bbic
+bbik
+bbit
+bbip
+bbih
+sa
+sag
+sagg
+sags
+san
+sanj
+sanh
+sad
+sal
+salg
+salm
+salb
+sals
+salt
+salp
+salh
+sam
+sab
+sabs
+sas
+sass
+sang
+saj
+sac
+sak
+sat
+sap
+sah
+sae
+saeg
+saegg
+saegs
+saen
+saenj
+saenh
+saed
+sael
+saelg
+saelm
+saelb
+saels
+saelt
+saelp
+saelh
+saem
+saeb
+saebs
+saes
+saess
+saeng
+saej
+saec
+saek
+saet
+saep
+saeh
+sya
+syag
+syagg
+syags
+syan
+syanj
+syanh
+syad
+syal
+syalg
+syalm
+syalb
+syals
+syalt
+syalp
+syalh
+syam
+syab
+syabs
+syas
+syass
+syang
+syaj
+syac
+syak
+syat
+syap
+syah
+syae
+syaeg
+syaegg
+syaegs
+syaen
+syaenj
+syaenh
+syaed
+syael
+syaelg
+syaelm
+syaelb
+syaels
+syaelt
+syaelp
+syaelh
+syaem
+syaeb
+syaebs
+syaes
+syaess
+syaeng
+syaej
+syaec
+syaek
+syaet
+syaep
+syaeh
+seo
+seog
+seogg
+seogs
+seon
+seonj
+seonh
+seod
+seol
+seolg
+seolm
+seolb
+seols
+seolt
+seolp
+seolh
+seom
+seob
+seobs
+seos
+seoss
+seong
+seoj
+seoc
+seok
+seot
+seop
+seoh
+se
+seg
+segg
+segs
+sen
+senj
+senh
+sed
+sel
+selg
+selm
+selb
+sels
+selt
+selp
+selh
+sem
+seb
+sebs
+ses
+sess
+seng
+sej
+sec
+sek
+set
+sep
+seh
+syeo
+syeog
+syeogg
+syeogs
+syeon
+syeonj
+syeonh
+syeod
+syeol
+syeolg
+syeolm
+syeolb
+syeols
+syeolt
+syeolp
+syeolh
+syeom
+syeob
+syeobs
+syeos
+syeoss
+syeong
+syeoj
+syeoc
+syeok
+syeot
+syeop
+syeoh
+sye
+syeg
+syegg
+syegs
+syen
+syenj
+syenh
+syed
+syel
+syelg
+syelm
+syelb
+syels
+syelt
+syelp
+syelh
+syem
+syeb
+syebs
+syes
+syess
+syeng
+syej
+syec
+syek
+syet
+syep
+syeh
+so
+sog
+sogg
+sogs
+son
+sonj
+sonh
+sod
+sol
+solg
+solm
+solb
+sols
+solt
+solp
+solh
+som
+sob
+sobs
+sos
+soss
+song
+soj
+soc
+sok
+sot
+sop
+soh
+swa
+swag
+swagg
+swags
+swan
+swanj
+swanh
+swad
+swal
+swalg
+swalm
+swalb
+swals
+swalt
+swalp
+swalh
+swam
+swab
+swabs
+swas
+swass
+swang
+swaj
+swac
+swak
+swat
+swap
+swah
+swae
+swaeg
+swaegg
+swaegs
+swaen
+swaenj
+swaenh
+swaed
+swael
+swaelg
+swaelm
+swaelb
+swaels
+swaelt
+swaelp
+swaelh
+swaem
+swaeb
+swaebs
+swaes
+swaess
+swaeng
+swaej
+swaec
+swaek
+swaet
+swaep
+swaeh
+soe
+soeg
+soegg
+soegs
+soen
+soenj
+soenh
+soed
+soel
+soelg
+soelm
+soelb
+soels
+soelt
+soelp
+soelh
+soem
+soeb
+soebs
+soes
+soess
+soeng
+soej
+soec
+soek
+soet
+soep
+soeh
+syo
+syog
+syogg
+syogs
+syon
+syonj
+syonh
+syod
+syol
+syolg
+syolm
+syolb
+syols
+syolt
+syolp
+syolh
+syom
+syob
+syobs
+syos
+syoss
+syong
+syoj
+syoc
+syok
+syot
+syop
+syoh
+su
+sug
+sugg
+sugs
+sun
+sunj
+sunh
+sud
+sul
+sulg
+sulm
+sulb
+suls
+sult
+sulp
+sulh
+sum
+sub
+subs
+sus
+suss
+sung
+suj
+suc
+suk
+sut
+sup
+suh
+sweo
+sweog
+sweogg
+sweogs
+sweon
+sweonj
+sweonh
+sweod
+sweol
+sweolg
+sweolm
+sweolb
+sweols
+sweolt
+sweolp
+sweolh
+sweom
+sweob
+sweobs
+sweos
+sweoss
+sweong
+sweoj
+sweoc
+sweok
+sweot
+sweop
+sweoh
+swe
+sweg
+swegg
+swegs
+swen
+swenj
+swenh
+swed
+swel
+swelg
+swelm
+swelb
+swels
+swelt
+swelp
+swelh
+swem
+sweb
+swebs
+swes
+swess
+sweng
+swej
+swec
+swek
+swet
+swep
+sweh
+swi
+swig
+swigg
+swigs
+swin
+swinj
+swinh
+swid
+swil
+swilg
+swilm
+swilb
+swils
+swilt
+swilp
+swilh
+swim
+swib
+swibs
+swis
+swiss
+swing
+swij
+swic
+swik
+swit
+swip
+swih
+syu
+syug
+syugg
+syugs
+syun
+syunj
+syunh
+syud
+syul
+syulg
+syulm
+syulb
+syuls
+syult
+syulp
+syulh
+syum
+syub
+syubs
+syus
+syuss
+syung
+syuj
+syuc
+syuk
+syut
+syup
+syuh
+seu
+seug
+seugg
+seugs
+seun
+seunj
+seunh
+seud
+seul
+seulg
+seulm
+seulb
+seuls
+seult
+seulp
+seulh
+seum
+seub
+seubs
+seus
+seuss
+seung
+seuj
+seuc
+seuk
+seut
+seup
+seuh
+syi
+syig
+syigg
+syigs
+syin
+syinj
+syinh
+syid
+syil
+syilg
+syilm
+syilb
+syils
+syilt
+syilp
+syilh
+syim
+syib
+syibs
+syis
+syiss
+sying
+syij
+syic
+syik
+syit
+syip
+syih
+si
+sig
+sigg
+sigs
+sin
+sinj
+sinh
+sid
+sil
+silg
+silm
+silb
+sils
+silt
+silp
+silh
+sim
+sib
+sibs
+sis
+siss
+sing
+sij
+sic
+sik
+sit
+sip
+sih
+ssa
+ssag
+ssagg
+ssags
+ssan
+ssanj
+ssanh
+ssad
+ssal
+ssalg
+ssalm
+ssalb
+ssals
+ssalt
+ssalp
+ssalh
+ssam
+ssab
+ssabs
+ssas
+ssass
+ssang
+ssaj
+ssac
+ssak
+ssat
+ssap
+ssah
+ssae
+ssaeg
+ssaegg
+ssaegs
+ssaen
+ssaenj
+ssaenh
+ssaed
+ssael
+ssaelg
+ssaelm
+ssaelb
+ssaels
+ssaelt
+ssaelp
+ssaelh
+ssaem
+ssaeb
+ssaebs
+ssaes
+ssaess
+ssaeng
+ssaej
+ssaec
+ssaek
+ssaet
+ssaep
+ssaeh
+ssya
+ssyag
+ssyagg
+ssyags
+ssyan
+ssyanj
+ssyanh
+ssyad
+ssyal
+ssyalg
+ssyalm
+ssyalb
+ssyals
+ssyalt
+ssyalp
+ssyalh
+ssyam
+ssyab
+ssyabs
+ssyas
+ssyass
+ssyang
+ssyaj
+ssyac
+ssyak
+ssyat
+ssyap
+ssyah
+ssyae
+ssyaeg
+ssyaegg
+ssyaegs
+ssyaen
+ssyaenj
+ssyaenh
+ssyaed
+ssyael
+ssyaelg
+ssyaelm
+ssyaelb
+ssyaels
+ssyaelt
+ssyaelp
+ssyaelh
+ssyaem
+ssyaeb
+ssyaebs
+ssyaes
+ssyaess
+ssyaeng
+ssyaej
+ssyaec
+ssyaek
+ssyaet
+ssyaep
+ssyaeh
+sseo
+sseog
+sseogg
+sseogs
+sseon
+sseonj
+sseonh
+sseod
+sseol
+sseolg
+sseolm
+sseolb
+sseols
+sseolt
+sseolp
+sseolh
+sseom
+sseob
+sseobs
+sseos
+sseoss
+sseong
+sseoj
+sseoc
+sseok
+sseot
+sseop
+sseoh
+sse
+sseg
+ssegg
+ssegs
+ssen
+ssenj
+ssenh
+ssed
+ssel
+sselg
+sselm
+sselb
+ssels
+sselt
+sselp
+sselh
+ssem
+sseb
+ssebs
+sses
+ssess
+sseng
+ssej
+ssec
+ssek
+sset
+ssep
+sseh
+ssyeo
+ssyeog
+ssyeogg
+ssyeogs
+ssyeon
+ssyeonj
+ssyeonh
+ssyeod
+ssyeol
+ssyeolg
+ssyeolm
+ssyeolb
+ssyeols
+ssyeolt
+ssyeolp
+ssyeolh
+ssyeom
+ssyeob
+ssyeobs
+ssyeos
+ssyeoss
+ssyeong
+ssyeoj
+ssyeoc
+ssyeok
+ssyeot
+ssyeop
+ssyeoh
+ssye
+ssyeg
+ssyegg
+ssyegs
+ssyen
+ssyenj
+ssyenh
+ssyed
+ssyel
+ssyelg
+ssyelm
+ssyelb
+ssyels
+ssyelt
+ssyelp
+ssyelh
+ssyem
+ssyeb
+ssyebs
+ssyes
+ssyess
+ssyeng
+ssyej
+ssyec
+ssyek
+ssyet
+ssyep
+ssyeh
+sso
+ssog
+ssogg
+ssogs
+sson
+ssonj
+ssonh
+ssod
+ssol
+ssolg
+ssolm
+ssolb
+ssols
+ssolt
+ssolp
+ssolh
+ssom
+ssob
+ssobs
+ssos
+ssoss
+ssong
+ssoj
+ssoc
+ssok
+ssot
+ssop
+ssoh
+sswa
+sswag
+sswagg
+sswags
+sswan
+sswanj
+sswanh
+sswad
+sswal
+sswalg
+sswalm
+sswalb
+sswals
+sswalt
+sswalp
+sswalh
+sswam
+sswab
+sswabs
+sswas
+sswass
+sswang
+sswaj
+sswac
+sswak
+sswat
+sswap
+sswah
+sswae
+sswaeg
+sswaegg
+sswaegs
+sswaen
+sswaenj
+sswaenh
+sswaed
+sswael
+sswaelg
+sswaelm
+sswaelb
+sswaels
+sswaelt
+sswaelp
+sswaelh
+sswaem
+sswaeb
+sswaebs
+sswaes
+sswaess
+sswaeng
+sswaej
+sswaec
+sswaek
+sswaet
+sswaep
+sswaeh
+ssoe
+ssoeg
+ssoegg
+ssoegs
+ssoen
+ssoenj
+ssoenh
+ssoed
+ssoel
+ssoelg
+ssoelm
+ssoelb
+ssoels
+ssoelt
+ssoelp
+ssoelh
+ssoem
+ssoeb
+ssoebs
+ssoes
+ssoess
+ssoeng
+ssoej
+ssoec
+ssoek
+ssoet
+ssoep
+ssoeh
+ssyo
+ssyog
+ssyogg
+ssyogs
+ssyon
+ssyonj
+ssyonh
+ssyod
+ssyol
+ssyolg
+ssyolm
+ssyolb
+ssyols
+ssyolt
+ssyolp
+ssyolh
+ssyom
+ssyob
+ssyobs
+ssyos
+ssyoss
+ssyong
+ssyoj
+ssyoc
+ssyok
+ssyot
+ssyop
+ssyoh
+ssu
+ssug
+ssugg
+ssugs
+ssun
+ssunj
+ssunh
+ssud
+ssul
+ssulg
+ssulm
+ssulb
+ssuls
+ssult
+ssulp
+ssulh
+ssum
+ssub
+ssubs
+ssus
+ssuss
+ssung
+ssuj
+ssuc
+ssuk
+ssut
+ssup
+ssuh
+ssweo
+ssweog
+ssweogg
+ssweogs
+ssweon
+ssweonj
+ssweonh
+ssweod
+ssweol
+ssweolg
+ssweolm
+ssweolb
+ssweols
+ssweolt
+ssweolp
+ssweolh
+ssweom
+ssweob
+ssweobs
+ssweos
+ssweoss
+ssweong
+ssweoj
+ssweoc
+ssweok
+ssweot
+ssweop
+ssweoh
+sswe
+ssweg
+sswegg
+sswegs
+sswen
+sswenj
+sswenh
+sswed
+sswel
+sswelg
+sswelm
+sswelb
+sswels
+sswelt
+sswelp
+sswelh
+sswem
+ssweb
+sswebs
+sswes
+sswess
+ssweng
+sswej
+sswec
+sswek
+sswet
+sswep
+ssweh
+sswi
+sswig
+sswigg
+sswigs
+sswin
+sswinj
+sswinh
+sswid
+sswil
+sswilg
+sswilm
+sswilb
+sswils
+sswilt
+sswilp
+sswilh
+sswim
+sswib
+sswibs
+sswis
+sswiss
+sswing
+sswij
+sswic
+sswik
+sswit
+sswip
+sswih
+ssyu
+ssyug
+ssyugg
+ssyugs
+ssyun
+ssyunj
+ssyunh
+ssyud
+ssyul
+ssyulg
+ssyulm
+ssyulb
+ssyuls
+ssyult
+ssyulp
+ssyulh
+ssyum
+ssyub
+ssyubs
+ssyus
+ssyuss
+ssyung
+ssyuj
+ssyuc
+ssyuk
+ssyut
+ssyup
+ssyuh
+sseu
+sseug
+sseugg
+sseugs
+sseun
+sseunj
+sseunh
+sseud
+sseul
+sseulg
+sseulm
+sseulb
+sseuls
+sseult
+sseulp
+sseulh
+sseum
+sseub
+sseubs
+sseus
+sseuss
+sseung
+sseuj
+sseuc
+sseuk
+sseut
+sseup
+sseuh
+ssyi
+ssyig
+ssyigg
+ssyigs
+ssyin
+ssyinj
+ssyinh
+ssyid
+ssyil
+ssyilg
+ssyilm
+ssyilb
+ssyils
+ssyilt
+ssyilp
+ssyilh
+ssyim
+ssyib
+ssyibs
+ssyis
+ssyiss
+ssying
+ssyij
+ssyic
+ssyik
+ssyit
+ssyip
+ssyih
+ssi
+ssig
+ssigg
+ssigs
+ssin
+ssinj
+ssinh
+ssid
+ssil
+ssilg
+ssilm
+ssilb
+ssils
+ssilt
+ssilp
+ssilh
+ssim
+ssib
+ssibs
+ssis
+ssiss
+ssing
+ssij
+ssic
+ssik
+ssit
+ssip
+ssih
+a
+ag
+agg
+ags
+an
+anj
+anh
+ad
+al
+alg
+alm
+alb
+als
+alt
+alp
+alh
+am
+ab
+abs
+as
+ass
+ang
+aj
+ac
+ak
+at
+ap
+ah
+ae
+aeg
+aegg
+aegs
+aen
+aenj
+aenh
+aed
+ael
+aelg
+aelm
+aelb
+aels
+aelt
+aelp
+aelh
+aem
+aeb
+aebs
+aes
+aess
+aeng
+aej
+aec
+aek
+aet
+aep
+aeh
+ya
+yag
+yagg
+yags
+yan
+yanj
+yanh
+yad
+yal
+yalg
+yalm
+yalb
+yals
+yalt
+yalp
+yalh
+yam
+yab
+yabs
+yas
+yass
+yang
+yaj
+yac
+yak
+yat
+yap
+yah
+yae
+yaeg
+yaegg
+yaegs
+yaen
+yaenj
+yaenh
+yaed
+yael
+yaelg
+yaelm
+yaelb
+yaels
+yaelt
+yaelp
+yaelh
+yaem
+yaeb
+yaebs
+yaes
+yaess
+yaeng
+yaej
+yaec
+yaek
+yaet
+yaep
+yaeh
+eo
+eog
+eogg
+eogs
+eon
+eonj
+eonh
+eod
+eol
+eolg
+eolm
+eolb
+eols
+eolt
+eolp
+eolh
+eom
+eob
+eobs
+eos
+eoss
+eong
+eoj
+eoc
+eok
+eot
+eop
+eoh
+e
+eg
+egg
+egs
+en
+enj
+enh
+ed
+el
+elg
+elm
+elb
+els
+elt
+elp
+elh
+em
+eb
+ebs
+es
+ess
+eng
+ej
+ec
+ek
+et
+ep
+eh
+yeo
+yeog
+yeogg
+yeogs
+yeon
+yeonj
+yeonh
+yeod
+yeol
+yeolg
+yeolm
+yeolb
+yeols
+yeolt
+yeolp
+yeolh
+yeom
+yeob
+yeobs
+yeos
+yeoss
+yeong
+yeoj
+yeoc
+yeok
+yeot
+yeop
+yeoh
+ye
+yeg
+yegg
+yegs
+yen
+yenj
+yenh
+yed
+yel
+yelg
+yelm
+yelb
+yels
+yelt
+yelp
+yelh
+yem
+yeb
+yebs
+yes
+yess
+yeng
+yej
+yec
+yek
+yet
+yep
+yeh
+o
+og
+ogg
+ogs
+on
+onj
+onh
+od
+ol
+olg
+olm
+olb
+ols
+olt
+olp
+olh
+om
+ob
+obs
+os
+oss
+ong
+oj
+oc
+ok
+ot
+op
+oh
+wa
+wag
+wagg
+wags
+wan
+wanj
+wanh
+wad
+wal
+walg
+walm
+walb
+wals
+walt
+walp
+walh
+wam
+wab
+wabs
+was
+wass
+wang
+waj
+wac
+wak
+wat
+wap
+wah
+wae
+waeg
+waegg
+waegs
+waen
+waenj
+waenh
+waed
+wael
+waelg
+waelm
+waelb
+waels
+waelt
+waelp
+waelh
+waem
+waeb
+waebs
+waes
+waess
+waeng
+waej
+waec
+waek
+waet
+waep
+waeh
+oe
+oeg
+oegg
+oegs
+oen
+oenj
+oenh
+oed
+oel
+oelg
+oelm
+oelb
+oels
+oelt
+oelp
+oelh
+oem
+oeb
+oebs
+oes
+oess
+oeng
+oej
+oec
+oek
+oet
+oep
+oeh
+yo
+yog
+yogg
+yogs
+yon
+yonj
+yonh
+yod
+yol
+yolg
+yolm
+yolb
+yols
+yolt
+yolp
+yolh
+yom
+yob
+yobs
+yos
+yoss
+yong
+yoj
+yoc
+yok
+yot
+yop
+yoh
+u
+ug
+ugg
+ugs
+un
+unj
+unh
+ud
+ul
+ulg
+ulm
+ulb
+uls
+ult
+ulp
+ulh
+um
+ub
+ubs
+us
+uss
+ung
+uj
+uc
+uk
+ut
+up
+uh
+weo
+weog
+weogg
+weogs
+weon
+weonj
+weonh
+weod
+weol
+weolg
+weolm
+weolb
+weols
+weolt
+weolp
+weolh
+weom
+weob
+weobs
+weos
+weoss
+weong
+weoj
+weoc
+weok
+weot
+weop
+weoh
+we
+weg
+wegg
+wegs
+wen
+wenj
+wenh
+wed
+wel
+welg
+welm
+welb
+wels
+welt
+welp
+welh
+wem
+web
+webs
+wes
+wess
+weng
+wej
+wec
+wek
+wet
+wep
+weh
+wi
+wig
+wigg
+wigs
+win
+winj
+winh
+wid
+wil
+wilg
+wilm
+wilb
+wils
+wilt
+wilp
+wilh
+wim
+wib
+wibs
+wis
+wiss
+wing
+wij
+wic
+wik
+wit
+wip
+wih
+yu
+yug
+yugg
+yugs
+yun
+yunj
+yunh
+yud
+yul
+yulg
+yulm
+yulb
+yuls
+yult
+yulp
+yulh
+yum
+yub
+yubs
+yus
+yuss
+yung
+yuj
+yuc
+yuk
+yut
+yup
+yuh
+eu
+eug
+eugg
+eugs
+eun
+eunj
+eunh
+eud
+eul
+eulg
+eulm
+eulb
+euls
+eult
+eulp
+eulh
+eum
+eub
+eubs
+eus
+euss
+eung
+euj
+euc
+euk
+eut
+eup
+euh
+yi
+yig
+yigg
+yigs
+yin
+yinj
+yinh
+yid
+yil
+yilg
+yilm
+yilb
+yils
+yilt
+yilp
+yilh
+yim
+yib
+yibs
+yis
+yiss
+ying
+yij
+yic
+yik
+yit
+yip
+yih
+i
+ig
+igg
+igs
+in
+inj
+inh
+id
+il
+ilg
+ilm
+ilb
+ils
+ilt
+ilp
+ilh
+im
+ib
+ibs
+is
+iss
+ing
+ij
+ic
+ik
+it
+ip
+ih
+ja
+jag
+jagg
+jags
+jan
+janj
+janh
+jad
+jal
+jalg
+jalm
+jalb
+jals
+jalt
+jalp
+jalh
+jam
+jab
+jabs
+jas
+jass
+jang
+jaj
+jac
+jak
+jat
+jap
+jah
+jae
+jaeg
+jaegg
+jaegs
+jaen
+jaenj
+jaenh
+jaed
+jael
+jaelg
+jaelm
+jaelb
+jaels
+jaelt
+jaelp
+jaelh
+jaem
+jaeb
+jaebs
+jaes
+jaess
+jaeng
+jaej
+jaec
+jaek
+jaet
+jaep
+jaeh
+jya
+jyag
+jyagg
+jyags
+jyan
+jyanj
+jyanh
+jyad
+jyal
+jyalg
+jyalm
+jyalb
+jyals
+jyalt
+jyalp
+jyalh
+jyam
+jyab
+jyabs
+jyas
+jyass
+jyang
+jyaj
+jyac
+jyak
+jyat
+jyap
+jyah
+jyae
+jyaeg
+jyaegg
+jyaegs
+jyaen
+jyaenj
+jyaenh
+jyaed
+jyael
+jyaelg
+jyaelm
+jyaelb
+jyaels
+jyaelt
+jyaelp
+jyaelh
+jyaem
+jyaeb
+jyaebs
+jyaes
+jyaess
+jyaeng
+jyaej
+jyaec
+jyaek
+jyaet
+jyaep
+jyaeh
+jeo
+jeog
+jeogg
+jeogs
+jeon
+jeonj
+jeonh
+jeod
+jeol
+jeolg
+jeolm
+jeolb
+jeols
+jeolt
+jeolp
+jeolh
+jeom
+jeob
+jeobs
+jeos
+jeoss
+jeong
+jeoj
+jeoc
+jeok
+jeot
+jeop
+jeoh
+je
+jeg
+jegg
+jegs
+jen
+jenj
+jenh
+jed
+jel
+jelg
+jelm
+jelb
+jels
+jelt
+jelp
+jelh
+jem
+jeb
+jebs
+jes
+jess
+jeng
+jej
+jec
+jek
+jet
+jep
+jeh
+jyeo
+jyeog
+jyeogg
+jyeogs
+jyeon
+jyeonj
+jyeonh
+jyeod
+jyeol
+jyeolg
+jyeolm
+jyeolb
+jyeols
+jyeolt
+jyeolp
+jyeolh
+jyeom
+jyeob
+jyeobs
+jyeos
+jyeoss
+jyeong
+jyeoj
+jyeoc
+jyeok
+jyeot
+jyeop
+jyeoh
+jye
+jyeg
+jyegg
+jyegs
+jyen
+jyenj
+jyenh
+jyed
+jyel
+jyelg
+jyelm
+jyelb
+jyels
+jyelt
+jyelp
+jyelh
+jyem
+jyeb
+jyebs
+jyes
+jyess
+jyeng
+jyej
+jyec
+jyek
+jyet
+jyep
+jyeh
+jo
+jog
+jogg
+jogs
+jon
+jonj
+jonh
+jod
+jol
+jolg
+jolm
+jolb
+jols
+jolt
+jolp
+jolh
+jom
+job
+jobs
+jos
+joss
+jong
+joj
+joc
+jok
+jot
+jop
+joh
+jwa
+jwag
+jwagg
+jwags
+jwan
+jwanj
+jwanh
+jwad
+jwal
+jwalg
+jwalm
+jwalb
+jwals
+jwalt
+jwalp
+jwalh
+jwam
+jwab
+jwabs
+jwas
+jwass
+jwang
+jwaj
+jwac
+jwak
+jwat
+jwap
+jwah
+jwae
+jwaeg
+jwaegg
+jwaegs
+jwaen
+jwaenj
+jwaenh
+jwaed
+jwael
+jwaelg
+jwaelm
+jwaelb
+jwaels
+jwaelt
+jwaelp
+jwaelh
+jwaem
+jwaeb
+jwaebs
+jwaes
+jwaess
+jwaeng
+jwaej
+jwaec
+jwaek
+jwaet
+jwaep
+jwaeh
+joe
+joeg
+joegg
+joegs
+joen
+joenj
+joenh
+joed
+joel
+joelg
+joelm
+joelb
+joels
+joelt
+joelp
+joelh
+joem
+joeb
+joebs
+joes
+joess
+joeng
+joej
+joec
+joek
+joet
+joep
+joeh
+jyo
+jyog
+jyogg
+jyogs
+jyon
+jyonj
+jyonh
+jyod
+jyol
+jyolg
+jyolm
+jyolb
+jyols
+jyolt
+jyolp
+jyolh
+jyom
+jyob
+jyobs
+jyos
+jyoss
+jyong
+jyoj
+jyoc
+jyok
+jyot
+jyop
+jyoh
+ju
+jug
+jugg
+jugs
+jun
+junj
+junh
+jud
+jul
+julg
+julm
+julb
+juls
+jult
+julp
+julh
+jum
+jub
+jubs
+jus
+juss
+jung
+juj
+juc
+juk
+jut
+jup
+juh
+jweo
+jweog
+jweogg
+jweogs
+jweon
+jweonj
+jweonh
+jweod
+jweol
+jweolg
+jweolm
+jweolb
+jweols
+jweolt
+jweolp
+jweolh
+jweom
+jweob
+jweobs
+jweos
+jweoss
+jweong
+jweoj
+jweoc
+jweok
+jweot
+jweop
+jweoh
+jwe
+jweg
+jwegg
+jwegs
+jwen
+jwenj
+jwenh
+jwed
+jwel
+jwelg
+jwelm
+jwelb
+jwels
+jwelt
+jwelp
+jwelh
+jwem
+jweb
+jwebs
+jwes
+jwess
+jweng
+jwej
+jwec
+jwek
+jwet
+jwep
+jweh
+jwi
+jwig
+jwigg
+jwigs
+jwin
+jwinj
+jwinh
+jwid
+jwil
+jwilg
+jwilm
+jwilb
+jwils
+jwilt
+jwilp
+jwilh
+jwim
+jwib
+jwibs
+jwis
+jwiss
+jwing
+jwij
+jwic
+jwik
+jwit
+jwip
+jwih
+jyu
+jyug
+jyugg
+jyugs
+jyun
+jyunj
+jyunh
+jyud
+jyul
+jyulg
+jyulm
+jyulb
+jyuls
+jyult
+jyulp
+jyulh
+jyum
+jyub
+jyubs
+jyus
+jyuss
+jyung
+jyuj
+jyuc
+jyuk
+jyut
+jyup
+jyuh
+jeu
+jeug
+jeugg
+jeugs
+jeun
+jeunj
+jeunh
+jeud
+jeul
+jeulg
+jeulm
+jeulb
+jeuls
+jeult
+jeulp
+jeulh
+jeum
+jeub
+jeubs
+jeus
+jeuss
+jeung
+jeuj
+jeuc
+jeuk
+jeut
+jeup
+jeuh
+jyi
+jyig
+jyigg
+jyigs
+jyin
+jyinj
+jyinh
+jyid
+jyil
+jyilg
+jyilm
+jyilb
+jyils
+jyilt
+jyilp
+jyilh
+jyim
+jyib
+jyibs
+jyis
+jyiss
+jying
+jyij
+jyic
+jyik
+jyit
+jyip
+jyih
+ji
+jig
+jigg
+jigs
+jin
+jinj
+jinh
+jid
+jil
+jilg
+jilm
+jilb
+jils
+jilt
+jilp
+jilh
+jim
+jib
+jibs
+jis
+jiss
+jing
+jij
+jic
+jik
+jit
+jip
+jih
+jja
+jjag
+jjagg
+jjags
+jjan
+jjanj
+jjanh
+jjad
+jjal
+jjalg
+jjalm
+jjalb
+jjals
+jjalt
+jjalp
+jjalh
+jjam
+jjab
+jjabs
+jjas
+jjass
+jjang
+jjaj
+jjac
+jjak
+jjat
+jjap
+jjah
+jjae
+jjaeg
+jjaegg
+jjaegs
+jjaen
+jjaenj
+jjaenh
+jjaed
+jjael
+jjaelg
+jjaelm
+jjaelb
+jjaels
+jjaelt
+jjaelp
+jjaelh
+jjaem
+jjaeb
+jjaebs
+jjaes
+jjaess
+jjaeng
+jjaej
+jjaec
+jjaek
+jjaet
+jjaep
+jjaeh
+jjya
+jjyag
+jjyagg
+jjyags
+jjyan
+jjyanj
+jjyanh
+jjyad
+jjyal
+jjyalg
+jjyalm
+jjyalb
+jjyals
+jjyalt
+jjyalp
+jjyalh
+jjyam
+jjyab
+jjyabs
+jjyas
+jjyass
+jjyang
+jjyaj
+jjyac
+jjyak
+jjyat
+jjyap
+jjyah
+jjyae
+jjyaeg
+jjyaegg
+jjyaegs
+jjyaen
+jjyaenj
+jjyaenh
+jjyaed
+jjyael
+jjyaelg
+jjyaelm
+jjyaelb
+jjyaels
+jjyaelt
+jjyaelp
+jjyaelh
+jjyaem
+jjyaeb
+jjyaebs
+jjyaes
+jjyaess
+jjyaeng
+jjyaej
+jjyaec
+jjyaek
+jjyaet
+jjyaep
+jjyaeh
+jjeo
+jjeog
+jjeogg
+jjeogs
+jjeon
+jjeonj
+jjeonh
+jjeod
+jjeol
+jjeolg
+jjeolm
+jjeolb
+jjeols
+jjeolt
+jjeolp
+jjeolh
+jjeom
+jjeob
+jjeobs
+jjeos
+jjeoss
+jjeong
+jjeoj
+jjeoc
+jjeok
+jjeot
+jjeop
+jjeoh
+jje
+jjeg
+jjegg
+jjegs
+jjen
+jjenj
+jjenh
+jjed
+jjel
+jjelg
+jjelm
+jjelb
+jjels
+jjelt
+jjelp
+jjelh
+jjem
+jjeb
+jjebs
+jjes
+jjess
+jjeng
+jjej
+jjec
+jjek
+jjet
+jjep
+jjeh
+jjyeo
+jjyeog
+jjyeogg
+jjyeogs
+jjyeon
+jjyeonj
+jjyeonh
+jjyeod
+jjyeol
+jjyeolg
+jjyeolm
+jjyeolb
+jjyeols
+jjyeolt
+jjyeolp
+jjyeolh
+jjyeom
+jjyeob
+jjyeobs
+jjyeos
+jjyeoss
+jjyeong
+jjyeoj
+jjyeoc
+jjyeok
+jjyeot
+jjyeop
+jjyeoh
+jjye
+jjyeg
+jjyegg
+jjyegs
+jjyen
+jjyenj
+jjyenh
+jjyed
+jjyel
+jjyelg
+jjyelm
+jjyelb
+jjyels
+jjyelt
+jjyelp
+jjyelh
+jjyem
+jjyeb
+jjyebs
+jjyes
+jjyess
+jjyeng
+jjyej
+jjyec
+jjyek
+jjyet
+jjyep
+jjyeh
+jjo
+jjog
+jjogg
+jjogs
+jjon
+jjonj
+jjonh
+jjod
+jjol
+jjolg
+jjolm
+jjolb
+jjols
+jjolt
+jjolp
+jjolh
+jjom
+jjob
+jjobs
+jjos
+jjoss
+jjong
+jjoj
+jjoc
+jjok
+jjot
+jjop
+jjoh
+jjwa
+jjwag
+jjwagg
+jjwags
+jjwan
+jjwanj
+jjwanh
+jjwad
+jjwal
+jjwalg
+jjwalm
+jjwalb
+jjwals
+jjwalt
+jjwalp
+jjwalh
+jjwam
+jjwab
+jjwabs
+jjwas
+jjwass
+jjwang
+jjwaj
+jjwac
+jjwak
+jjwat
+jjwap
+jjwah
+jjwae
+jjwaeg
+jjwaegg
+jjwaegs
+jjwaen
+jjwaenj
+jjwaenh
+jjwaed
+jjwael
+jjwaelg
+jjwaelm
+jjwaelb
+jjwaels
+jjwaelt
+jjwaelp
+jjwaelh
+jjwaem
+jjwaeb
+jjwaebs
+jjwaes
+jjwaess
+jjwaeng
+jjwaej
+jjwaec
+jjwaek
+jjwaet
+jjwaep
+jjwaeh
+jjoe
+jjoeg
+jjoegg
+jjoegs
+jjoen
+jjoenj
+jjoenh
+jjoed
+jjoel
+jjoelg
+jjoelm
+jjoelb
+jjoels
+jjoelt
+jjoelp
+jjoelh
+jjoem
+jjoeb
+jjoebs
+jjoes
+jjoess
+jjoeng
+jjoej
+jjoec
+jjoek
+jjoet
+jjoep
+jjoeh
+jjyo
+jjyog
+jjyogg
+jjyogs
+jjyon
+jjyonj
+jjyonh
+jjyod
+jjyol
+jjyolg
+jjyolm
+jjyolb
+jjyols
+jjyolt
+jjyolp
+jjyolh
+jjyom
+jjyob
+jjyobs
+jjyos
+jjyoss
+jjyong
+jjyoj
+jjyoc
+jjyok
+jjyot
+jjyop
+jjyoh
+jju
+jjug
+jjugg
+jjugs
+jjun
+jjunj
+jjunh
+jjud
+jjul
+jjulg
+jjulm
+jjulb
+jjuls
+jjult
+jjulp
+jjulh
+jjum
+jjub
+jjubs
+jjus
+jjuss
+jjung
+jjuj
+jjuc
+jjuk
+jjut
+jjup
+jjuh
+jjweo
+jjweog
+jjweogg
+jjweogs
+jjweon
+jjweonj
+jjweonh
+jjweod
+jjweol
+jjweolg
+jjweolm
+jjweolb
+jjweols
+jjweolt
+jjweolp
+jjweolh
+jjweom
+jjweob
+jjweobs
+jjweos
+jjweoss
+jjweong
+jjweoj
+jjweoc
+jjweok
+jjweot
+jjweop
+jjweoh
+jjwe
+jjweg
+jjwegg
+jjwegs
+jjwen
+jjwenj
+jjwenh
+jjwed
+jjwel
+jjwelg
+jjwelm
+jjwelb
+jjwels
+jjwelt
+jjwelp
+jjwelh
+jjwem
+jjweb
+jjwebs
+jjwes
+jjwess
+jjweng
+jjwej
+jjwec
+jjwek
+jjwet
+jjwep
+jjweh
+jjwi
+jjwig
+jjwigg
+jjwigs
+jjwin
+jjwinj
+jjwinh
+jjwid
+jjwil
+jjwilg
+jjwilm
+jjwilb
+jjwils
+jjwilt
+jjwilp
+jjwilh
+jjwim
+jjwib
+jjwibs
+jjwis
+jjwiss
+jjwing
+jjwij
+jjwic
+jjwik
+jjwit
+jjwip
+jjwih
+jjyu
+jjyug
+jjyugg
+jjyugs
+jjyun
+jjyunj
+jjyunh
+jjyud
+jjyul
+jjyulg
+jjyulm
+jjyulb
+jjyuls
+jjyult
+jjyulp
+jjyulh
+jjyum
+jjyub
+jjyubs
+jjyus
+jjyuss
+jjyung
+jjyuj
+jjyuc
+jjyuk
+jjyut
+jjyup
+jjyuh
+jjeu
+jjeug
+jjeugg
+jjeugs
+jjeun
+jjeunj
+jjeunh
+jjeud
+jjeul
+jjeulg
+jjeulm
+jjeulb
+jjeuls
+jjeult
+jjeulp
+jjeulh
+jjeum
+jjeub
+jjeubs
+jjeus
+jjeuss
+jjeung
+jjeuj
+jjeuc
+jjeuk
+jjeut
+jjeup
+jjeuh
+jjyi
+jjyig
+jjyigg
+jjyigs
+jjyin
+jjyinj
+jjyinh
+jjyid
+jjyil
+jjyilg
+jjyilm
+jjyilb
+jjyils
+jjyilt
+jjyilp
+jjyilh
+jjyim
+jjyib
+jjyibs
+jjyis
+jjyiss
+jjying
+jjyij
+jjyic
+jjyik
+jjyit
+jjyip
+jjyih
+jji
+jjig
+jjigg
+jjigs
+jjin
+jjinj
+jjinh
+jjid
+jjil
+jjilg
+jjilm
+jjilb
+jjils
+jjilt
+jjilp
+jjilh
+jjim
+jjib
+jjibs
+jjis
+jjiss
+jjing
+jjij
+jjic
+jjik
+jjit
+jjip
+jjih
+ca
+cag
+cagg
+cags
+can
+canj
+canh
+cad
+cal
+calg
+calm
+calb
+cals
+calt
+calp
+calh
+cam
+cab
+cabs
+cas
+cass
+cang
+caj
+cac
+cak
+cat
+cap
+cah
+cae
+caeg
+caegg
+caegs
+caen
+caenj
+caenh
+caed
+cael
+caelg
+caelm
+caelb
+caels
+caelt
+caelp
+caelh
+caem
+caeb
+caebs
+caes
+caess
+caeng
+caej
+caec
+caek
+caet
+caep
+caeh
+cya
+cyag
+cyagg
+cyags
+cyan
+cyanj
+cyanh
+cyad
+cyal
+cyalg
+cyalm
+cyalb
+cyals
+cyalt
+cyalp
+cyalh
+cyam
+cyab
+cyabs
+cyas
+cyass
+cyang
+cyaj
+cyac
+cyak
+cyat
+cyap
+cyah
+cyae
+cyaeg
+cyaegg
+cyaegs
+cyaen
+cyaenj
+cyaenh
+cyaed
+cyael
+cyaelg
+cyaelm
+cyaelb
+cyaels
+cyaelt
+cyaelp
+cyaelh
+cyaem
+cyaeb
+cyaebs
+cyaes
+cyaess
+cyaeng
+cyaej
+cyaec
+cyaek
+cyaet
+cyaep
+cyaeh
+ceo
+ceog
+ceogg
+ceogs
+ceon
+ceonj
+ceonh
+ceod
+ceol
+ceolg
+ceolm
+ceolb
+ceols
+ceolt
+ceolp
+ceolh
+ceom
+ceob
+ceobs
+ceos
+ceoss
+ceong
+ceoj
+ceoc
+ceok
+ceot
+ceop
+ceoh
+ce
+ceg
+cegg
+cegs
+cen
+cenj
+cenh
+ced
+cel
+celg
+celm
+celb
+cels
+celt
+celp
+celh
+cem
+ceb
+cebs
+ces
+cess
+ceng
+cej
+cec
+cek
+cet
+cep
+ceh
+cyeo
+cyeog
+cyeogg
+cyeogs
+cyeon
+cyeonj
+cyeonh
+cyeod
+cyeol
+cyeolg
+cyeolm
+cyeolb
+cyeols
+cyeolt
+cyeolp
+cyeolh
+cyeom
+cyeob
+cyeobs
+cyeos
+cyeoss
+cyeong
+cyeoj
+cyeoc
+cyeok
+cyeot
+cyeop
+cyeoh
+cye
+cyeg
+cyegg
+cyegs
+cyen
+cyenj
+cyenh
+cyed
+cyel
+cyelg
+cyelm
+cyelb
+cyels
+cyelt
+cyelp
+cyelh
+cyem
+cyeb
+cyebs
+cyes
+cyess
+cyeng
+cyej
+cyec
+cyek
+cyet
+cyep
+cyeh
+co
+cog
+cogg
+cogs
+con
+conj
+conh
+cod
+col
+colg
+colm
+colb
+cols
+colt
+colp
+colh
+com
+cob
+cobs
+cos
+coss
+cong
+coj
+coc
+cok
+cot
+cop
+coh
+cwa
+cwag
+cwagg
+cwags
+cwan
+cwanj
+cwanh
+cwad
+cwal
+cwalg
+cwalm
+cwalb
+cwals
+cwalt
+cwalp
+cwalh
+cwam
+cwab
+cwabs
+cwas
+cwass
+cwang
+cwaj
+cwac
+cwak
+cwat
+cwap
+cwah
+cwae
+cwaeg
+cwaegg
+cwaegs
+cwaen
+cwaenj
+cwaenh
+cwaed
+cwael
+cwaelg
+cwaelm
+cwaelb
+cwaels
+cwaelt
+cwaelp
+cwaelh
+cwaem
+cwaeb
+cwaebs
+cwaes
+cwaess
+cwaeng
+cwaej
+cwaec
+cwaek
+cwaet
+cwaep
+cwaeh
+coe
+coeg
+coegg
+coegs
+coen
+coenj
+coenh
+coed
+coel
+coelg
+coelm
+coelb
+coels
+coelt
+coelp
+coelh
+coem
+coeb
+coebs
+coes
+coess
+coeng
+coej
+coec
+coek
+coet
+coep
+coeh
+cyo
+cyog
+cyogg
+cyogs
+cyon
+cyonj
+cyonh
+cyod
+cyol
+cyolg
+cyolm
+cyolb
+cyols
+cyolt
+cyolp
+cyolh
+cyom
+cyob
+cyobs
+cyos
+cyoss
+cyong
+cyoj
+cyoc
+cyok
+cyot
+cyop
+cyoh
+cu
+cug
+cugg
+cugs
+cun
+cunj
+cunh
+cud
+cul
+culg
+culm
+culb
+culs
+cult
+culp
+culh
+cum
+cub
+cubs
+cus
+cuss
+cung
+cuj
+cuc
+cuk
+cut
+cup
+cuh
+cweo
+cweog
+cweogg
+cweogs
+cweon
+cweonj
+cweonh
+cweod
+cweol
+cweolg
+cweolm
+cweolb
+cweols
+cweolt
+cweolp
+cweolh
+cweom
+cweob
+cweobs
+cweos
+cweoss
+cweong
+cweoj
+cweoc
+cweok
+cweot
+cweop
+cweoh
+cwe
+cweg
+cwegg
+cwegs
+cwen
+cwenj
+cwenh
+cwed
+cwel
+cwelg
+cwelm
+cwelb
+cwels
+cwelt
+cwelp
+cwelh
+cwem
+cweb
+cwebs
+cwes
+cwess
+cweng
+cwej
+cwec
+cwek
+cwet
+cwep
+cweh
+cwi
+cwig
+cwigg
+cwigs
+cwin
+cwinj
+cwinh
+cwid
+cwil
+cwilg
+cwilm
+cwilb
+cwils
+cwilt
+cwilp
+cwilh
+cwim
+cwib
+cwibs
+cwis
+cwiss
+cwing
+cwij
+cwic
+cwik
+cwit
+cwip
+cwih
+cyu
+cyug
+cyugg
+cyugs
+cyun
+cyunj
+cyunh
+cyud
+cyul
+cyulg
+cyulm
+cyulb
+cyuls
+cyult
+cyulp
+cyulh
+cyum
+cyub
+cyubs
+cyus
+cyuss
+cyung
+cyuj
+cyuc
+cyuk
+cyut
+cyup
+cyuh
+ceu
+ceug
+ceugg
+ceugs
+ceun
+ceunj
+ceunh
+ceud
+ceul
+ceulg
+ceulm
+ceulb
+ceuls
+ceult
+ceulp
+ceulh
+ceum
+ceub
+ceubs
+ceus
+ceuss
+ceung
+ceuj
+ceuc
+ceuk
+ceut
+ceup
+ceuh
+cyi
+cyig
+cyigg
+cyigs
+cyin
+cyinj
+cyinh
+cyid
+cyil
+cyilg
+cyilm
+cyilb
+cyils
+cyilt
+cyilp
+cyilh
+cyim
+cyib
+cyibs
+cyis
+cyiss
+cying
+cyij
+cyic
+cyik
+cyit
+cyip
+cyih
+ci
+cig
+cigg
+cigs
+cin
+cinj
+cinh
+cid
+cil
+cilg
+cilm
+cilb
+cils
+cilt
+cilp
+cilh
+cim
+cib
+cibs
+cis
+ciss
+cing
+cij
+cic
+cik
+cit
+cip
+cih
+ka
+kag
+kagg
+kags
+kan
+kanj
+kanh
+kad
+kal
+kalg
+kalm
+kalb
+kals
+kalt
+kalp
+kalh
+kam
+kab
+kabs
+kas
+kass
+kang
+kaj
+kac
+kak
+kat
+kap
+kah
+kae
+kaeg
+kaegg
+kaegs
+kaen
+kaenj
+kaenh
+kaed
+kael
+kaelg
+kaelm
+kaelb
+kaels
+kaelt
+kaelp
+kaelh
+kaem
+kaeb
+kaebs
+kaes
+kaess
+kaeng
+kaej
+kaec
+kaek
+kaet
+kaep
+kaeh
+kya
+kyag
+kyagg
+kyags
+kyan
+kyanj
+kyanh
+kyad
+kyal
+kyalg
+kyalm
+kyalb
+kyals
+kyalt
+kyalp
+kyalh
+kyam
+kyab
+kyabs
+kyas
+kyass
+kyang
+kyaj
+kyac
+kyak
+kyat
+kyap
+kyah
+kyae
+kyaeg
+kyaegg
+kyaegs
+kyaen
+kyaenj
+kyaenh
+kyaed
+kyael
+kyaelg
+kyaelm
+kyaelb
+kyaels
+kyaelt
+kyaelp
+kyaelh
+kyaem
+kyaeb
+kyaebs
+kyaes
+kyaess
+kyaeng
+kyaej
+kyaec
+kyaek
+kyaet
+kyaep
+kyaeh
+keo
+keog
+keogg
+keogs
+keon
+keonj
+keonh
+keod
+keol
+keolg
+keolm
+keolb
+keols
+keolt
+keolp
+keolh
+keom
+keob
+keobs
+keos
+keoss
+keong
+keoj
+keoc
+keok
+keot
+keop
+keoh
+ke
+keg
+kegg
+kegs
+ken
+kenj
+kenh
+ked
+kel
+kelg
+kelm
+kelb
+kels
+kelt
+kelp
+kelh
+kem
+keb
+kebs
+kes
+kess
+keng
+kej
+kec
+kek
+ket
+kep
+keh
+kyeo
+kyeog
+kyeogg
+kyeogs
+kyeon
+kyeonj
+kyeonh
+kyeod
+kyeol
+kyeolg
+kyeolm
+kyeolb
+kyeols
+kyeolt
+kyeolp
+kyeolh
+kyeom
+kyeob
+kyeobs
+kyeos
+kyeoss
+kyeong
+kyeoj
+kyeoc
+kyeok
+kyeot
+kyeop
+kyeoh
+kye
+kyeg
+kyegg
+kyegs
+kyen
+kyenj
+kyenh
+kyed
+kyel
+kyelg
+kyelm
+kyelb
+kyels
+kyelt
+kyelp
+kyelh
+kyem
+kyeb
+kyebs
+kyes
+kyess
+kyeng
+kyej
+kyec
+kyek
+kyet
+kyep
+kyeh
+ko
+kog
+kogg
+kogs
+kon
+konj
+konh
+kod
+kol
+kolg
+kolm
+kolb
+kols
+kolt
+kolp
+kolh
+kom
+kob
+kobs
+kos
+koss
+kong
+koj
+koc
+kok
+kot
+kop
+koh
+kwa
+kwag
+kwagg
+kwags
+kwan
+kwanj
+kwanh
+kwad
+kwal
+kwalg
+kwalm
+kwalb
+kwals
+kwalt
+kwalp
+kwalh
+kwam
+kwab
+kwabs
+kwas
+kwass
+kwang
+kwaj
+kwac
+kwak
+kwat
+kwap
+kwah
+kwae
+kwaeg
+kwaegg
+kwaegs
+kwaen
+kwaenj
+kwaenh
+kwaed
+kwael
+kwaelg
+kwaelm
+kwaelb
+kwaels
+kwaelt
+kwaelp
+kwaelh
+kwaem
+kwaeb
+kwaebs
+kwaes
+kwaess
+kwaeng
+kwaej
+kwaec
+kwaek
+kwaet
+kwaep
+kwaeh
+koe
+koeg
+koegg
+koegs
+koen
+koenj
+koenh
+koed
+koel
+koelg
+koelm
+koelb
+koels
+koelt
+koelp
+koelh
+koem
+koeb
+koebs
+koes
+koess
+koeng
+koej
+koec
+koek
+koet
+koep
+koeh
+kyo
+kyog
+kyogg
+kyogs
+kyon
+kyonj
+kyonh
+kyod
+kyol
+kyolg
+kyolm
+kyolb
+kyols
+kyolt
+kyolp
+kyolh
+kyom
+kyob
+kyobs
+kyos
+kyoss
+kyong
+kyoj
+kyoc
+kyok
+kyot
+kyop
+kyoh
+ku
+kug
+kugg
+kugs
+kun
+kunj
+kunh
+kud
+kul
+kulg
+kulm
+kulb
+kuls
+kult
+kulp
+kulh
+kum
+kub
+kubs
+kus
+kuss
+kung
+kuj
+kuc
+kuk
+kut
+kup
+kuh
+kweo
+kweog
+kweogg
+kweogs
+kweon
+kweonj
+kweonh
+kweod
+kweol
+kweolg
+kweolm
+kweolb
+kweols
+kweolt
+kweolp
+kweolh
+kweom
+kweob
+kweobs
+kweos
+kweoss
+kweong
+kweoj
+kweoc
+kweok
+kweot
+kweop
+kweoh
+kwe
+kweg
+kwegg
+kwegs
+kwen
+kwenj
+kwenh
+kwed
+kwel
+kwelg
+kwelm
+kwelb
+kwels
+kwelt
+kwelp
+kwelh
+kwem
+kweb
+kwebs
+kwes
+kwess
+kweng
+kwej
+kwec
+kwek
+kwet
+kwep
+kweh
+kwi
+kwig
+kwigg
+kwigs
+kwin
+kwinj
+kwinh
+kwid
+kwil
+kwilg
+kwilm
+kwilb
+kwils
+kwilt
+kwilp
+kwilh
+kwim
+kwib
+kwibs
+kwis
+kwiss
+kwing
+kwij
+kwic
+kwik
+kwit
+kwip
+kwih
+kyu
+kyug
+kyugg
+kyugs
+kyun
+kyunj
+kyunh
+kyud
+kyul
+kyulg
+kyulm
+kyulb
+kyuls
+kyult
+kyulp
+kyulh
+kyum
+kyub
+kyubs
+kyus
+kyuss
+kyung
+kyuj
+kyuc
+kyuk
+kyut
+kyup
+kyuh
+keu
+keug
+keugg
+keugs
+keun
+keunj
+keunh
+keud
+keul
+keulg
+keulm
+keulb
+keuls
+keult
+keulp
+keulh
+keum
+keub
+keubs
+keus
+keuss
+keung
+keuj
+keuc
+keuk
+keut
+keup
+keuh
+kyi
+kyig
+kyigg
+kyigs
+kyin
+kyinj
+kyinh
+kyid
+kyil
+kyilg
+kyilm
+kyilb
+kyils
+kyilt
+kyilp
+kyilh
+kyim
+kyib
+kyibs
+kyis
+kyiss
+kying
+kyij
+kyic
+kyik
+kyit
+kyip
+kyih
+ki
+kig
+kigg
+kigs
+kin
+kinj
+kinh
+kid
+kil
+kilg
+kilm
+kilb
+kils
+kilt
+kilp
+kilh
+kim
+kib
+kibs
+kis
+kiss
+king
+kij
+kic
+kik
+kit
+kip
+kih
+ta
+tag
+tagg
+tags
+tan
+tanj
+tanh
+tad
+tal
+talg
+talm
+talb
+tals
+talt
+talp
+talh
+tam
+tab
+tabs
+tas
+tass
+tang
+taj
+tac
+tak
+tat
+tap
+tah
+tae
+taeg
+taegg
+taegs
+taen
+taenj
+taenh
+taed
+tael
+taelg
+taelm
+taelb
+taels
+taelt
+taelp
+taelh
+taem
+taeb
+taebs
+taes
+taess
+taeng
+taej
+taec
+taek
+taet
+taep
+taeh
+tya
+tyag
+tyagg
+tyags
+tyan
+tyanj
+tyanh
+tyad
+tyal
+tyalg
+tyalm
+tyalb
+tyals
+tyalt
+tyalp
+tyalh
+tyam
+tyab
+tyabs
+tyas
+tyass
+tyang
+tyaj
+tyac
+tyak
+tyat
+tyap
+tyah
+tyae
+tyaeg
+tyaegg
+tyaegs
+tyaen
+tyaenj
+tyaenh
+tyaed
+tyael
+tyaelg
+tyaelm
+tyaelb
+tyaels
+tyaelt
+tyaelp
+tyaelh
+tyaem
+tyaeb
+tyaebs
+tyaes
+tyaess
+tyaeng
+tyaej
+tyaec
+tyaek
+tyaet
+tyaep
+tyaeh
+teo
+teog
+teogg
+teogs
+teon
+teonj
+teonh
+teod
+teol
+teolg
+teolm
+teolb
+teols
+teolt
+teolp
+teolh
+teom
+teob
+teobs
+teos
+teoss
+teong
+teoj
+teoc
+teok
+teot
+teop
+teoh
+te
+teg
+tegg
+tegs
+ten
+tenj
+tenh
+ted
+tel
+telg
+telm
+telb
+tels
+telt
+telp
+telh
+tem
+teb
+tebs
+tes
+tess
+teng
+tej
+tec
+tek
+tet
+tep
+teh
+tyeo
+tyeog
+tyeogg
+tyeogs
+tyeon
+tyeonj
+tyeonh
+tyeod
+tyeol
+tyeolg
+tyeolm
+tyeolb
+tyeols
+tyeolt
+tyeolp
+tyeolh
+tyeom
+tyeob
+tyeobs
+tyeos
+tyeoss
+tyeong
+tyeoj
+tyeoc
+tyeok
+tyeot
+tyeop
+tyeoh
+tye
+tyeg
+tyegg
+tyegs
+tyen
+tyenj
+tyenh
+tyed
+tyel
+tyelg
+tyelm
+tyelb
+tyels
+tyelt
+tyelp
+tyelh
+tyem
+tyeb
+tyebs
+tyes
+tyess
+tyeng
+tyej
+tyec
+tyek
+tyet
+tyep
+tyeh
+to
+tog
+togg
+togs
+ton
+tonj
+tonh
+tod
+tol
+tolg
+tolm
+tolb
+tols
+tolt
+tolp
+tolh
+tom
+tob
+tobs
+tos
+toss
+tong
+toj
+toc
+tok
+tot
+top
+toh
+twa
+twag
+twagg
+twags
+twan
+twanj
+twanh
+twad
+twal
+twalg
+twalm
+twalb
+twals
+twalt
+twalp
+twalh
+twam
+twab
+twabs
+twas
+twass
+twang
+twaj
+twac
+twak
+twat
+twap
+twah
+twae
+twaeg
+twaegg
+twaegs
+twaen
+twaenj
+twaenh
+twaed
+twael
+twaelg
+twaelm
+twaelb
+twaels
+twaelt
+twaelp
+twaelh
+twaem
+twaeb
+twaebs
+twaes
+twaess
+twaeng
+twaej
+twaec
+twaek
+twaet
+twaep
+twaeh
+toe
+toeg
+toegg
+toegs
+toen
+toenj
+toenh
+toed
+toel
+toelg
+toelm
+toelb
+toels
+toelt
+toelp
+toelh
+toem
+toeb
+toebs
+toes
+toess
+toeng
+toej
+toec
+toek
+toet
+toep
+toeh
+tyo
+tyog
+tyogg
+tyogs
+tyon
+tyonj
+tyonh
+tyod
+tyol
+tyolg
+tyolm
+tyolb
+tyols
+tyolt
+tyolp
+tyolh
+tyom
+tyob
+tyobs
+tyos
+tyoss
+tyong
+tyoj
+tyoc
+tyok
+tyot
+tyop
+tyoh
+tu
+tug
+tugg
+tugs
+tun
+tunj
+tunh
+tud
+tul
+tulg
+tulm
+tulb
+tuls
+tult
+tulp
+tulh
+tum
+tub
+tubs
+tus
+tuss
+tung
+tuj
+tuc
+tuk
+tut
+tup
+tuh
+tweo
+tweog
+tweogg
+tweogs
+tweon
+tweonj
+tweonh
+tweod
+tweol
+tweolg
+tweolm
+tweolb
+tweols
+tweolt
+tweolp
+tweolh
+tweom
+tweob
+tweobs
+tweos
+tweoss
+tweong
+tweoj
+tweoc
+tweok
+tweot
+tweop
+tweoh
+twe
+tweg
+twegg
+twegs
+twen
+twenj
+twenh
+twed
+twel
+twelg
+twelm
+twelb
+twels
+twelt
+twelp
+twelh
+twem
+tweb
+twebs
+twes
+twess
+tweng
+twej
+twec
+twek
+twet
+twep
+tweh
+twi
+twig
+twigg
+twigs
+twin
+twinj
+twinh
+twid
+twil
+twilg
+twilm
+twilb
+twils
+twilt
+twilp
+twilh
+twim
+twib
+twibs
+twis
+twiss
+twing
+twij
+twic
+twik
+twit
+twip
+twih
+tyu
+tyug
+tyugg
+tyugs
+tyun
+tyunj
+tyunh
+tyud
+tyul
+tyulg
+tyulm
+tyulb
+tyuls
+tyult
+tyulp
+tyulh
+tyum
+tyub
+tyubs
+tyus
+tyuss
+tyung
+tyuj
+tyuc
+tyuk
+tyut
+tyup
+tyuh
+teu
+teug
+teugg
+teugs
+teun
+teunj
+teunh
+teud
+teul
+teulg
+teulm
+teulb
+teuls
+teult
+teulp
+teulh
+teum
+teub
+teubs
+teus
+teuss
+teung
+teuj
+teuc
+teuk
+teut
+teup
+teuh
+tyi
+tyig
+tyigg
+tyigs
+tyin
+tyinj
+tyinh
+tyid
+tyil
+tyilg
+tyilm
+tyilb
+tyils
+tyilt
+tyilp
+tyilh
+tyim
+tyib
+tyibs
+tyis
+tyiss
+tying
+tyij
+tyic
+tyik
+tyit
+tyip
+tyih
+ti
+tig
+tigg
+tigs
+tin
+tinj
+tinh
+tid
+til
+tilg
+tilm
+tilb
+tils
+tilt
+tilp
+tilh
+tim
+tib
+tibs
+tis
+tiss
+ting
+tij
+tic
+tik
+tit
+tip
+tih
+pa
+pag
+pagg
+pags
+pan
+panj
+panh
+pad
+pal
+palg
+palm
+palb
+pals
+palt
+palp
+palh
+pam
+pab
+pabs
+pas
+pass
+pang
+paj
+pac
+pak
+pat
+pap
+pah
+pae
+paeg
+paegg
+paegs
+paen
+paenj
+paenh
+paed
+pael
+paelg
+paelm
+paelb
+paels
+paelt
+paelp
+paelh
+paem
+paeb
+paebs
+paes
+paess
+paeng
+paej
+paec
+paek
+paet
+paep
+paeh
+pya
+pyag
+pyagg
+pyags
+pyan
+pyanj
+pyanh
+pyad
+pyal
+pyalg
+pyalm
+pyalb
+pyals
+pyalt
+pyalp
+pyalh
+pyam
+pyab
+pyabs
+pyas
+pyass
+pyang
+pyaj
+pyac
+pyak
+pyat
+pyap
+pyah
+pyae
+pyaeg
+pyaegg
+pyaegs
+pyaen
+pyaenj
+pyaenh
+pyaed
+pyael
+pyaelg
+pyaelm
+pyaelb
+pyaels
+pyaelt
+pyaelp
+pyaelh
+pyaem
+pyaeb
+pyaebs
+pyaes
+pyaess
+pyaeng
+pyaej
+pyaec
+pyaek
+pyaet
+pyaep
+pyaeh
+peo
+peog
+peogg
+peogs
+peon
+peonj
+peonh
+peod
+peol
+peolg
+peolm
+peolb
+peols
+peolt
+peolp
+peolh
+peom
+peob
+peobs
+peos
+peoss
+peong
+peoj
+peoc
+peok
+peot
+peop
+peoh
+pe
+peg
+pegg
+pegs
+pen
+penj
+penh
+ped
+pel
+pelg
+pelm
+pelb
+pels
+pelt
+pelp
+pelh
+pem
+peb
+pebs
+pes
+pess
+peng
+pej
+pec
+pek
+pet
+pep
+peh
+pyeo
+pyeog
+pyeogg
+pyeogs
+pyeon
+pyeonj
+pyeonh
+pyeod
+pyeol
+pyeolg
+pyeolm
+pyeolb
+pyeols
+pyeolt
+pyeolp
+pyeolh
+pyeom
+pyeob
+pyeobs
+pyeos
+pyeoss
+pyeong
+pyeoj
+pyeoc
+pyeok
+pyeot
+pyeop
+pyeoh
+pye
+pyeg
+pyegg
+pyegs
+pyen
+pyenj
+pyenh
+pyed
+pyel
+pyelg
+pyelm
+pyelb
+pyels
+pyelt
+pyelp
+pyelh
+pyem
+pyeb
+pyebs
+pyes
+pyess
+pyeng
+pyej
+pyec
+pyek
+pyet
+pyep
+pyeh
+po
+pog
+pogg
+pogs
+pon
+ponj
+ponh
+pod
+pol
+polg
+polm
+polb
+pols
+polt
+polp
+polh
+pom
+pob
+pobs
+pos
+poss
+pong
+poj
+poc
+pok
+pot
+pop
+poh
+pwa
+pwag
+pwagg
+pwags
+pwan
+pwanj
+pwanh
+pwad
+pwal
+pwalg
+pwalm
+pwalb
+pwals
+pwalt
+pwalp
+pwalh
+pwam
+pwab
+pwabs
+pwas
+pwass
+pwang
+pwaj
+pwac
+pwak
+pwat
+pwap
+pwah
+pwae
+pwaeg
+pwaegg
+pwaegs
+pwaen
+pwaenj
+pwaenh
+pwaed
+pwael
+pwaelg
+pwaelm
+pwaelb
+pwaels
+pwaelt
+pwaelp
+pwaelh
+pwaem
+pwaeb
+pwaebs
+pwaes
+pwaess
+pwaeng
+pwaej
+pwaec
+pwaek
+pwaet
+pwaep
+pwaeh
+poe
+poeg
+poegg
+poegs
+poen
+poenj
+poenh
+poed
+poel
+poelg
+poelm
+poelb
+poels
+poelt
+poelp
+poelh
+poem
+poeb
+poebs
+poes
+poess
+poeng
+poej
+poec
+poek
+poet
+poep
+poeh
+pyo
+pyog
+pyogg
+pyogs
+pyon
+pyonj
+pyonh
+pyod
+pyol
+pyolg
+pyolm
+pyolb
+pyols
+pyolt
+pyolp
+pyolh
+pyom
+pyob
+pyobs
+pyos
+pyoss
+pyong
+pyoj
+pyoc
+pyok
+pyot
+pyop
+pyoh
+pu
+pug
+pugg
+pugs
+pun
+punj
+punh
+pud
+pul
+pulg
+pulm
+pulb
+puls
+pult
+pulp
+pulh
+pum
+pub
+pubs
+pus
+puss
+pung
+puj
+puc
+puk
+put
+pup
+puh
+pweo
+pweog
+pweogg
+pweogs
+pweon
+pweonj
+pweonh
+pweod
+pweol
+pweolg
+pweolm
+pweolb
+pweols
+pweolt
+pweolp
+pweolh
+pweom
+pweob
+pweobs
+pweos
+pweoss
+pweong
+pweoj
+pweoc
+pweok
+pweot
+pweop
+pweoh
+pwe
+pweg
+pwegg
+pwegs
+pwen
+pwenj
+pwenh
+pwed
+pwel
+pwelg
+pwelm
+pwelb
+pwels
+pwelt
+pwelp
+pwelh
+pwem
+pweb
+pwebs
+pwes
+pwess
+pweng
+pwej
+pwec
+pwek
+pwet
+pwep
+pweh
+pwi
+pwig
+pwigg
+pwigs
+pwin
+pwinj
+pwinh
+pwid
+pwil
+pwilg
+pwilm
+pwilb
+pwils
+pwilt
+pwilp
+pwilh
+pwim
+pwib
+pwibs
+pwis
+pwiss
+pwing
+pwij
+pwic
+pwik
+pwit
+pwip
+pwih
+pyu
+pyug
+pyugg
+pyugs
+pyun
+pyunj
+pyunh
+pyud
+pyul
+pyulg
+pyulm
+pyulb
+pyuls
+pyult
+pyulp
+pyulh
+pyum
+pyub
+pyubs
+pyus
+pyuss
+pyung
+pyuj
+pyuc
+pyuk
+pyut
+pyup
+pyuh
+peu
+peug
+peugg
+peugs
+peun
+peunj
+peunh
+peud
+peul
+peulg
+peulm
+peulb
+peuls
+peult
+peulp
+peulh
+peum
+peub
+peubs
+peus
+peuss
+peung
+peuj
+peuc
+peuk
+peut
+peup
+peuh
+pyi
+pyig
+pyigg
+pyigs
+pyin
+pyinj
+pyinh
+pyid
+pyil
+pyilg
+pyilm
+pyilb
+pyils
+pyilt
+pyilp
+pyilh
+pyim
+pyib
+pyibs
+pyis
+pyiss
+pying
+pyij
+pyic
+pyik
+pyit
+pyip
+pyih
+pi
+pig
+pigg
+pigs
+pin
+pinj
+pinh
+pid
+pil
+pilg
+pilm
+pilb
+pils
+pilt
+pilp
+pilh
+pim
+pib
+pibs
+pis
+piss
+ping
+pij
+pic
+pik
+pit
+pip
+pih
+ha
+hag
+hagg
+hags
+han
+hanj
+hanh
+had
+hal
+halg
+halm
+halb
+hals
+halt
+halp
+halh
+ham
+hab
+habs
+has
+hass
+hang
+haj
+hac
+hak
+hat
+hap
+hah
+hae
+haeg
+haegg
+haegs
+haen
+haenj
+haenh
+haed
+hael
+haelg
+haelm
+haelb
+haels
+haelt
+haelp
+haelh
+haem
+haeb
+haebs
+haes
+haess
+haeng
+haej
+haec
+haek
+haet
+haep
+haeh
+hya
+hyag
+hyagg
+hyags
+hyan
+hyanj
+hyanh
+hyad
+hyal
+hyalg
+hyalm
+hyalb
+hyals
+hyalt
+hyalp
+hyalh
+hyam
+hyab
+hyabs
+hyas
+hyass
+hyang
+hyaj
+hyac
+hyak
+hyat
+hyap
+hyah
+hyae
+hyaeg
+hyaegg
+hyaegs
+hyaen
+hyaenj
+hyaenh
+hyaed
+hyael
+hyaelg
+hyaelm
+hyaelb
+hyaels
+hyaelt
+hyaelp
+hyaelh
+hyaem
+hyaeb
+hyaebs
+hyaes
+hyaess
+hyaeng
+hyaej
+hyaec
+hyaek
+hyaet
+hyaep
+hyaeh
+heo
+heog
+heogg
+heogs
+heon
+heonj
+heonh
+heod
+heol
+heolg
+heolm
+heolb
+heols
+heolt
+heolp
+heolh
+heom
+heob
+heobs
+heos
+heoss
+heong
+heoj
+heoc
+heok
+heot
+heop
+heoh
+he
+heg
+hegg
+hegs
+hen
+henj
+henh
+hed
+hel
+helg
+helm
+helb
+hels
+helt
+help
+helh
+hem
+heb
+hebs
+hes
+hess
+heng
+hej
+hec
+hek
+het
+hep
+heh
+hyeo
+hyeog
+hyeogg
+hyeogs
+hyeon
+hyeonj
+hyeonh
+hyeod
+hyeol
+hyeolg
+hyeolm
+hyeolb
+hyeols
+hyeolt
+hyeolp
+hyeolh
+hyeom
+hyeob
+hyeobs
+hyeos
+hyeoss
+hyeong
+hyeoj
+hyeoc
+hyeok
+hyeot
+hyeop
+hyeoh
+hye
+hyeg
+hyegg
+hyegs
+hyen
+hyenj
+hyenh
+hyed
+hyel
+hyelg
+hyelm
+hyelb
+hyels
+hyelt
+hyelp
+hyelh
+hyem
+hyeb
+hyebs
+hyes
+hyess
+hyeng
+hyej
+hyec
+hyek
+hyet
+hyep
+hyeh
+ho
+hog
+hogg
+hogs
+hon
+honj
+honh
+hod
+hol
+holg
+holm
+holb
+hols
+holt
+holp
+holh
+hom
+hob
+hobs
+hos
+hoss
+hong
+hoj
+hoc
+hok
+hot
+hop
+hoh
+hwa
+hwag
+hwagg
+hwags
+hwan
+hwanj
+hwanh
+hwad
+hwal
+hwalg
+hwalm
+hwalb
+hwals
+hwalt
+hwalp
+hwalh
+hwam
+hwab
+hwabs
+hwas
+hwass
+hwang
+hwaj
+hwac
+hwak
+hwat
+hwap
+hwah
+hwae
+hwaeg
+hwaegg
+hwaegs
+hwaen
+hwaenj
+hwaenh
+hwaed
+hwael
+hwaelg
+hwaelm
+hwaelb
+hwaels
+hwaelt
+hwaelp
+hwaelh
+hwaem
+hwaeb
+hwaebs
+hwaes
+hwaess
+hwaeng
+hwaej
+hwaec
+hwaek
+hwaet
+hwaep
+hwaeh
+hoe
+hoeg
+hoegg
+hoegs
+hoen
+hoenj
+hoenh
+hoed
+hoel
+hoelg
+hoelm
+hoelb
+hoels
+hoelt
+hoelp
+hoelh
+hoem
+hoeb
+hoebs
+hoes
+hoess
+hoeng
+hoej
+hoec
+hoek
+hoet
+hoep
+hoeh
+hyo
+hyog
+hyogg
+hyogs
+hyon
+hyonj
+hyonh
+hyod
+hyol
+hyolg
+hyolm
+hyolb
+hyols
+hyolt
+hyolp
+hyolh
+hyom
+hyob
+hyobs
+hyos
+hyoss
+hyong
+hyoj
+hyoc
+hyok
+hyot
+hyop
+hyoh
+hu
+hug
+hugg
+hugs
+hun
+hunj
+hunh
+hud
+hul
+hulg
+hulm
+hulb
+huls
+hult
+hulp
+hulh
+hum
+hub
+hubs
+hus
+huss
+hung
+huj
+huc
+huk
+hut
+hup
+huh
+hweo
+hweog
+hweogg
+hweogs
+hweon
+hweonj
+hweonh
+hweod
+hweol
+hweolg
+hweolm
+hweolb
+hweols
+hweolt
+hweolp
+hweolh
+hweom
+hweob
+hweobs
+hweos
+hweoss
+hweong
+hweoj
+hweoc
+hweok
+hweot
+hweop
+hweoh
+hwe
+hweg
+hwegg
+hwegs
+hwen
+hwenj
+hwenh
+hwed
+hwel
+hwelg
+hwelm
+hwelb
+hwels
+hwelt
+hwelp
+hwelh
+hwem
+hweb
+hwebs
+hwes
+hwess
+hweng
+hwej
+hwec
+hwek
+hwet
+hwep
+hweh
+hwi
+hwig
+hwigg
+hwigs
+hwin
+hwinj
+hwinh
+hwid
+hwil
+hwilg
+hwilm
+hwilb
+hwils
+hwilt
+hwilp
+hwilh
+hwim
+hwib
+hwibs
+hwis
+hwiss
+hwing
+hwij
+hwic
+hwik
+hwit
+hwip
+hwih
+hyu
+hyug
+hyugg
+hyugs
+hyun
+hyunj
+hyunh
+hyud
+hyul
+hyulg
+hyulm
+hyulb
+hyuls
+hyult
+hyulp
+hyulh
+hyum
+hyub
+hyubs
+hyus
+hyuss
+hyung
+hyuj
+hyuc
+hyuk
+hyut
+hyup
+hyuh
+heu
+heug
+heugg
+heugs
+heun
+heunj
+heunh
+heud
+heul
+heulg
+heulm
+heulb
+heuls
+heult
+heulp
+heulh
+heum
+heub
+heubs
+heus
+heuss
+heung
+heuj
+heuc
+heuk
+heut
+heup
+heuh
+hyi
+hyig
+hyigg
+hyigs
+hyin
+hyinj
+hyinh
+hyid
+hyil
+hyilg
+hyilm
+hyilb
+hyils
+hyilt
+hyilp
+hyilh
+hyim
+hyib
+hyibs
+hyis
+hyiss
+hying
+hyij
+hyic
+hyik
+hyit
+hyip
+hyih
+hi
+hig
+higg
+higs
+hin
+hinj
+hinh
+hid
+hil
+hilg
+hilm
+hilb
+hils
+hilt
+hilp
+hilh
+him
+hib
+hibs
+his
+hiss
+hing
+hij
+hic
+hik
+hit
+hip
+hih
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Kay 
+Kayng 
+Ke 
+Ko 
+Kol 
+Koc 
+Kwi 
+Kwi 
+Kyun 
+Kul 
+Kum 
+Na 
+Na 
+Na 
+La 
+Na 
+Na 
+Na 
+Na 
+Na 
+Nak 
+Nak 
+Nak 
+Nak 
+Nak 
+Nak 
+Nak 
+Nan 
+Nan 
+Nan 
+Nan 
+Nan 
+Nan 
+Nam 
+Nam 
+Nam 
+Nam 
+Nap 
+Nap 
+Nap 
+Nang 
+Nang 
+Nang 
+Nang 
+Nang 
+Nay 
+Nayng 
+No 
+No 
+No 
+No 
+No 
+No 
+No 
+No 
+No 
+No 
+No 
+No 
+Nok 
+Nok 
+Nok 
+Nok 
+Nok 
+Nok 
+Non 
+Nong 
+Nong 
+Nong 
+Nong 
+Noy 
+Noy 
+Noy 
+Noy 
+Nwu 
+Nwu 
+Nwu 
+Nwu 
+Nwu 
+Nwu 
+Nwu 
+Nwu 
+Nuk 
+Nuk 
+Num 
+Nung 
+Nung 
+Nung 
+Nung 
+Nung 
+Twu 
+La 
+Lak 
+Lak 
+Lan 
+Lyeng 
+Lo 
+Lyul 
+Li 
+Pey 
+Pen 
+Pyen 
+Pwu 
+Pwul 
+Pi 
+Sak 
+Sak 
+Sam 
+Sayk 
+Sayng 
+Sep 
+Sey 
+Sway 
+Sin 
+Sim 
+Sip 
+Ya 
+Yak 
+Yak 
+Yang 
+Yang 
+Yang 
+Yang 
+Yang 
+Yang 
+Yang 
+Yang 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Ye 
+Yek 
+Yek 
+Yek 
+Yek 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yen 
+Yel 
+Yel 
+Yel 
+Yel 
+Yel 
+Yel 
+Yem 
+Yem 
+Yem 
+Yem 
+Yem 
+Yep 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yeng 
+Yey 
+Yey 
+Yey 
+Yey 
+O 
+Yo 
+Yo 
+Yo 
+Yo 
+Yo 
+Yo 
+Yo 
+Yo 
+Yo 
+Yo 
+Yong 
+Wun 
+Wen 
+Yu 
+Yu 
+Yu 
+Yu 
+Yu 
+Yu 
+Yu 
+Yu 
+Yu 
+Yu 
+Yuk 
+Yuk 
+Yuk 
+Yun 
+Yun 
+Yun 
+Yun 
+Yul 
+Yul 
+Yul 
+Yul 
+Yung 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+I 
+Ik 
+Ik 
+In 
+In 
+In 
+In 
+In 
+In 
+In 
+Im 
+Im 
+Im 
+Ip 
+Ip 
+Ip 
+Cang 
+Cek 
+Ci 
+Cip 
+Cha 
+Chek 
+Chey 
+Thak 
+Thak 
+Thang 
+Thayk 
+Thong 
+Pho 
+Phok 
+Hang 
+Hang 
+Hyen 
+Hwak 
+Wu 
+Huo 
+[?] 
+[?] 
+Zhong 
+[?] 
+Qing 
+[?] 
+[?] 
+Xi 
+Zhu 
+Yi 
+Li 
+Shen 
+Xiang 
+Fu 
+Jing 
+Jing 
+Yu 
+[?] 
+Hagi 
+[?] 
+Zhu 
+[?] 
+[?] 
+Yi 
+Du 
+[?] 
+[?] 
+[?] 
+Fan 
+Si 
+Guan 
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+ff
+fi
+fl
+ffi
+ffl
+st
+st
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+mn
+me
+mi
+vn
+mkh
+[?]
+[?]
+[?]
+[?]
+[?]
+yi
+
+ay
+`
+
+d
+h
+k
+l
+m
+m
+t
++
+sh
+s
+sh
+s
+a
+a
+
+b
+g
+d
+h
+v
+z
+[?]
+t
+y
+k
+k
+l
+[?]
+l
+[?]
+n
+n
+[?]
+p
+p
+[?]
+ts
+ts
+r
+sh
+t
+vo
+b
+k
+p
+l
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+[?]
+
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+
+
+
+~
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+..
+--
+-
+_
+_
+(
+) 
+{
+} 
+[
+] 
+[(
+)] 
+<<
+>> 
+<
+> 
+[
+] 
+{
+}
+[?]
+[?]
+[?]
+[?]
+
+
+
+
+
+
+
+,
+,
+.
+
+;
+:
+?
+!
+-
+(
+)
+{
+}
+{
+}
+#
+&
+*
++
+-
+<
+>
+=
+
+\
+$
+%
+@
+[?]
+[?]
+[?]
+[?]
+
+
+
+[?]
+
+[?]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[?]
+[?]
+
+[?]
+!
+"
+#
+$
+%
+&
+'
+(
+)
+*
++
+,
+-
+.
+/
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+:
+;
+<
+=
+>
+?
+@
+A
+B
+C
+D
+E
+F
+G
+H
+I
+J
+K
+L
+M
+N
+O
+P
+Q
+R
+S
+T
+U
+V
+W
+X
+Y
+Z
+[
+\
+]
+^
+_
+`
+a
+b
+c
+d
+e
+f
+g
+h
+i
+j
+k
+l
+m
+n
+o
+p
+q
+r
+s
+t
+u
+v
+w
+x
+y
+z
+{
+|
+}
+~
+[?]
+[?]
+.
+[
+]
+,
+*
+wo
+a
+i
+u
+e
+o
+ya
+yu
+yo
+tu
++
+a
+i
+u
+e
+o
+ka
+ki
+ku
+ke
+ko
+sa
+si
+su
+se
+so
+ta
+ti
+tu
+te
+to
+na
+ni
+nu
+ne
+no
+ha
+hi
+hu
+he
+ho
+ma
+mi
+mu
+me
+mo
+ya
+yu
+yo
+ra
+ri
+ru
+re
+ro
+wa
+n
+:
+;
+
+g
+gg
+gs
+n
+nj
+nh
+d
+dd
+r
+lg
+lm
+lb
+ls
+lt
+lp
+rh
+m
+b
+bb
+bs
+s
+ss
+
+j
+jj
+c
+k
+t
+p
+h
+[?]
+[?]
+[?]
+a
+ae
+ya
+yae
+eo
+e
+[?]
+[?]
+yeo
+ye
+o
+wa
+wae
+oe
+[?]
+[?]
+yo
+u
+weo
+we
+wi
+yu
+[?]
+[?]
+eu
+yi
+i
+[?]
+[?]
+[?]
+/C
+PS
+!
+-
+|
+Y=
+W=
+[?]
+|
+-
+|
+-
+|
+#
+O
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+[?]
+{
+|
+}
+
+
+
+
diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim
new file mode 100644
index 000000000..a83b9be0f
--- /dev/null
+++ b/lib/pure/unidecode/unidecode.nim
@@ -0,0 +1,74 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module is based on Python's Unidecode module by Tomaz Solc, 
+## which in turn is based on the ``Text::Unidecode`` Perl module by 
+## Sean M. Burke 
+## (http://search.cpan.org/~sburke/Text-Unidecode-0.04/lib/Text/Unidecode.pm ).
+##
+## It provides a single proc that does Unicode to ASCII transliterations:
+## It finds the sequence of ASCII characters that is the closest approximation
+## to the Unicode string.
+##
+## For example, the closest to string "Äußerst" in ASCII is "Ausserst". Some 
+## information is lost in this transformation, of course, since several Unicode 
+## strings can be transformed in the same ASCII representation. So this is a
+## strictly one-way transformation. However a human reader will probably 
+## still be able to guess what original string was meant from the context.
+##
+## This module needs the data file "unidecode.dat" to work: You can either
+## ship this file with your application and initialize this module with the
+## `loadUnidecodeTable` proc or you can define the ``embedUnidecodeTable``
+## symbol to embed the file as a resource into your application.
+
+import unicode
+
+when defined(embedUnidecodeTable):
+  import strutils
+  
+  const translationTable = splitLines(slurp"unidecode/unidecode.dat")
+else:
+  # shared is fine for threading:
+  var translationTable: seq[string]
+
+proc loadUnidecodeTable*(datafile = "unidecode.dat") =
+  ## loads the datafile that `unidecode` to work. Unless this module is
+  ## compiled with the ``embedUnidecodeTable`` symbol defined, this needs
+  ## to be called by the main thread before any thread can make a call
+  ## to `unidecode`.
+  when not defined(embedUnidecodeTable):
+    newSeq(translationTable, 0xffff)
+    var i = 0
+    for line in lines(datafile):
+      translationTable[i] = line.string
+      inc(i)
+
+proc unidecode*(s: string): string = 
+  ## Finds the sequence of ASCII characters that is the closest approximation
+  ## to the UTF-8 string `s`.
+  ##
+  ## Example: 
+  ## 
+  ## ..code-block:: nim
+  ##
+  ##   unidecode("\x53\x17\x4E\xB0")
+  ##
+  ## Results in: "Bei Jing"
+  ##
+  assert(not isNil(translationTable))
+  result = ""
+  for r in runes(s): 
+    var c = int(r)
+    if c <=% 127: add(result, chr(c))
+    elif c <% translationTable.len: add(result, translationTable[c-128])
+
+when isMainModule:
+  loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
+  assert unidecode("Äußerst") == "Ausserst"
+
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
new file mode 100644
index 000000000..3bf4724b9
--- /dev/null
+++ b/lib/pure/unittest.nim
@@ -0,0 +1,237 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Nim Contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## :Author: Zahary Karadjov
+##
+## This module implements boilerplate to make testing easy.
+##
+## Example:
+##
+## .. code:: nim
+##
+##   suite "description for this stuff":
+##     test "essential truths":
+##       # give up and stop if this fails
+##       require(true)
+##
+##     test "slightly less obvious stuff":
+##       # print a nasty message and move on, skipping
+##       # the remainder of this block
+##       check(1 != 1)
+##       check("asd"[2] == 'd')
+##
+##     test "out of bounds error is thrown on bad access":
+##       let v = @[1, 2, 3]  # you can do initialization here
+##       expect(IndexError):
+##         discard v[4]
+
+import
+  macros
+
+when declared(stdout):
+  import os
+
+when not defined(ECMAScript):
+  import terminal
+  system.addQuitProc(resetAttributes)
+
+type
+  TestStatus* = enum OK, FAILED
+  OutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE
+
+{.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]}
+
+var
+  abortOnError* {.threadvar.}: bool
+  outputLevel* {.threadvar.}: OutputLevel
+  colorOutput* {.threadvar.}: bool
+
+  checkpoints {.threadvar.}: seq[string]
+
+checkpoints = @[]
+
+template testSetupIMPL*: stmt {.immediate, dirty.} = discard
+template testTeardownIMPL*: stmt {.immediate, dirty.} = discard
+
+proc shouldRun(testName: string): bool =
+  result = true
+
+template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
+  block:
+    template setup*(setupBody: stmt): stmt {.immediate, dirty.} =
+      template testSetupIMPL: stmt {.immediate, dirty.} = setupBody
+
+    template teardown*(teardownBody: stmt): stmt {.immediate, dirty.} =
+      template testTeardownIMPL: stmt {.immediate, dirty.} = teardownBody
+
+    body
+
+proc testDone(name: string, s: TestStatus) =
+  if s == FAILED:
+    programResult += 1
+
+  if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED):
+    template rawPrint() = echo("[", $s, "] ", name)
+    when not defined(ECMAScript):
+      if colorOutput and not defined(ECMAScript):
+        var color = (if s == OK: fgGreen else: fgRed)
+        styledEcho styleBright, color, "[", $s, "] ", fgWhite, name
+      else:
+        rawPrint()
+    else:
+      rawPrint()
+
+template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
+  bind shouldRun, checkpoints, testDone
+
+  if shouldRun(name):
+    checkpoints = @[]
+    var testStatusIMPL {.inject.} = OK
+
+    try:
+      testSetupIMPL()
+      body
+
+    except:
+      checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
+      echo getCurrentException().getStackTrace()
+      fail()
+
+    finally:
+      testTeardownIMPL()
+      testDone name, testStatusIMPL
+
+proc checkpoint*(msg: string) =
+  checkpoints.add(msg)
+  # TODO: add support for something like SCOPED_TRACE from Google Test
+
+template fail* =
+  bind checkpoints
+  for msg in items(checkpoints):
+    # this used to be 'echo' which now breaks due to a bug. XXX will revisit
+    # this issue later.
+    stdout.writeln msg
+
+  when not defined(ECMAScript):
+    if abortOnError: quit(1)
+
+  when declared(testStatusIMPL):
+    testStatusIMPL = FAILED
+  else:
+    programResult += 1
+
+  checkpoints = @[]
+
+macro check*(conditions: stmt): stmt {.immediate.} =
+  let checked = callsite()[1]
+
+  var
+    argsAsgns = newNimNode(nnkStmtList)
+    argsPrintOuts = newNimNode(nnkStmtList)
+    counter = 0
+
+  template asgn(a, value: expr): stmt =
+    var a = value # XXX: we need "var: var" here in order to
+                  # preserve the semantics of var params
+
+  template print(name, value: expr): stmt =
+    when compiles(string($value)):
+      checkpoint(name & " was " & $value)
+
+  proc inspectArgs(exp: NimNode) =
+    for i in 1 .. <exp.len:
+      if exp[i].kind notin nnkLiterals:
+        inc counter
+        var arg = newIdentNode(":p" & $counter)
+        var argStr = exp[i].toStrLit
+        var paramAst = exp[i]
+        if exp[i].kind in nnkCallKinds: inspectArgs(exp[i])
+        if exp[i].kind == nnkExprEqExpr:
+          # ExprEqExpr
+          #   Ident !"v"
+          #   IntLit 2
+          paramAst = exp[i][1]
+        argsAsgns.add getAst(asgn(arg, paramAst))
+        argsPrintOuts.add getAst(print(argStr, arg))
+        if exp[i].kind != nnkExprEqExpr:
+          exp[i] = arg
+        else:
+          exp[i][1] = arg
+
+  case checked.kind
+  of nnkCallKinds:
+    template rewrite(call, lineInfoLit: expr, callLit: string,
+                     argAssgs, argPrintOuts: stmt): stmt =
+      block:
+        argAssgs
+        if not call:
+          checkpoint(lineInfoLit & ": Check failed: " & callLit)
+          argPrintOuts
+          fail()
+
+    var checkedStr = checked.toStrLit
+    inspectArgs(checked)
+    result = getAst(rewrite(checked, checked.lineinfo, checkedStr,
+                            argsAsgns, argsPrintOuts))
+
+  of nnkStmtList:
+    result = newNimNode(nnkStmtList)
+    for i in countup(0, checked.len - 1):
+      if checked[i].kind != nnkCommentStmt:
+        result.add(newCall(!"check", checked[i]))
+
+  else:
+    template rewrite(Exp, lineInfoLit: expr, expLit: string): stmt =
+      if not Exp:
+        checkpoint(lineInfoLit & ": Check failed: " & expLit)
+        fail()
+
+    result = getAst(rewrite(checked, checked.lineinfo, checked.toStrLit))
+
+template require*(conditions: stmt): stmt {.immediate, dirty.} =
+  block:
+    const AbortOnError {.inject.} = true
+    check conditions
+
+macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
+  let exp = callsite()
+  template expectBody(errorTypes, lineInfoLit: expr,
+                      body: stmt): NimNode {.dirty.} =
+    try:
+      body
+      checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")
+      fail()
+    except errorTypes:
+      discard
+
+  var body = exp[exp.len - 1]
+
+  var errorTypes = newNimNode(nnkBracket)
+  for i in countup(1, exp.len - 2):
+    errorTypes.add(exp[i])
+
+  result = getAst(expectBody(errorTypes, exp.lineinfo, body))
+
+
+when declared(stdout):
+  ## Reading settings
+  var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string
+
+  abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
+  colorOutput  = not existsEnv("NIMTEST_NO_COLOR")
+
+else:
+  var envOutLvl = "" # TODO
+  colorOutput  = false
+
+if envOutLvl.len > 0:
+  for opt in countup(low(OutputLevel), high(OutputLevel)):
+    if $opt == envOutLvl:
+      outputLevel = opt
+      break
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
new file mode 100644
index 000000000..1890a9bf4
--- /dev/null
+++ b/lib/pure/uri.nim
@@ -0,0 +1,421 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements URI parsing as specified by RFC 3986.
+
+import strutils, parseutils
+type
+  Url* = distinct string
+
+  Uri* = object
+    scheme*, username*, password*: string 
+    hostname*, port*, path*, query*, anchor*: string
+    opaque*: bool
+
+{.deprecated: [TUrl: Url, TUri: Uri].}
+
+{.push warning[deprecated]: off.}
+proc `$`*(url: Url): string {.deprecated.} =
+  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
+  return string(url)
+
+proc `/`*(a, b: Url): Url {.deprecated.} =
+  ## Joins two URLs together, separating them with / if needed.
+  ##
+  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
+  var urlS = $a
+  var bS = $b
+  if urlS == "": return b
+  if urlS[urlS.len-1] != '/':
+    urlS.add('/')
+  if bS[0] == '/':
+    urlS.add(bS.substr(1))
+  else:
+    urlS.add(bs)
+  result = Url(urlS)
+
+proc add*(url: var Url, a: Url) {.deprecated.} =
+  ## Appends url to url.
+  ##
+  ## **Deprecated since 0.9.6**: Use ``Uri`` instead.
+  url = url / a
+{.pop.}
+
+proc parseAuthority(authority: string, result: var Uri) =
+  var i = 0
+  var inPort = false
+  while true:
+    case authority[i]
+    of '@':
+      swap result.password, result.port
+      result.port.setLen(0)
+      swap result.username, result.hostname
+      result.hostname.setLen(0)
+      inPort = false
+    of ':':
+      inPort = true
+    of '\0': break
+    else:
+      if inPort:
+        result.port.add(authority[i])
+      else:
+        result.hostname.add(authority[i])
+    i.inc
+
+proc parsePath(uri: string, i: var int, result: var Uri) =
+  
+  i.inc parseUntil(uri, result.path, {'?', '#'}, i)
+
+  # The 'mailto' scheme's PATH actually contains the hostname/username
+  if result.scheme.toLower == "mailto":
+    parseAuthority(result.path, result)
+    result.path.setLen(0)
+
+  if uri[i] == '?':
+    i.inc # Skip '?'
+    i.inc parseUntil(uri, result.query, {'#'}, i)
+
+  if uri[i] == '#':
+    i.inc # Skip '#'
+    i.inc parseUntil(uri, result.anchor, {}, i)
+
+proc initUri*(): Uri =
+  ## Initializes a URI.
+  result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
+                path: "", query: "", anchor: "")
+
+proc resetUri(uri: var Uri) =
+  for f in uri.fields:
+    when f is string:
+      f.setLen(0)
+    else:
+      f = false
+
+proc parseUri*(uri: string, result: var Uri) =
+  ## Parses a URI. The `result` variable will be cleared before.
+  resetUri(result)
+
+  var i = 0
+
+  # Check if this is a reference URI (relative URI)
+  if uri[i] == '/':
+    parsePath(uri, i, result)
+    return
+
+  # Scheme
+  i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
+  if uri[i] != ':':
+    # Assume this is a reference URI (relative URI)
+    i = 0
+    result.scheme.setLen(0)
+    parsePath(uri, i, result)
+    return
+  i.inc # Skip ':'
+
+  # Authority
+  if uri[i] == '/' and uri[i+1] == '/':
+    i.inc(2) # Skip //
+    var authority = ""
+    i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
+    if authority == "":
+      raise newException(ValueError, "Expected authority got nothing.")
+    parseAuthority(authority, result)
+  else:
+    result.opaque = true
+
+  # Path
+  parsePath(uri, i, result)
+
+proc parseUri*(uri: string): Uri =
+  ## Parses a URI and returns it.
+  result = initUri()
+  parseUri(uri, result)
+
+proc removeDotSegments(path: string): string =
+  var collection: seq[string] = @[]
+  let endsWithSlash = path[path.len-1] == '/'
+  var i = 0
+  var currentSegment = ""
+  while true:
+    case path[i]
+    of '/':
+      collection.add(currentSegment)
+      currentSegment = ""
+    of '.':
+      if path[i+1] == '.' and path[i+2] == '/':
+        if collection.len > 0:
+          discard collection.pop()
+          i.inc 3
+          continue
+      elif path[i+1] == '/':
+        i.inc 2
+        continue
+      currentSegment.add path[i]
+    of '\0':
+      if currentSegment != "":
+        collection.add currentSegment
+      break
+    else:
+      currentSegment.add path[i]
+    i.inc
+
+  result = collection.join("/")
+  if endsWithSlash: result.add '/'
+
+proc merge(base, reference: Uri): string =
+  # http://tools.ietf.org/html/rfc3986#section-5.2.3
+  if base.hostname != "" and base.path == "":
+    '/' & reference.path
+  else:
+    let lastSegment = rfind(base.path, "/")
+    if lastSegment == -1:
+      reference.path
+    else:
+      base.path[0 .. lastSegment] & reference.path
+
+proc combine*(base: Uri, reference: Uri): Uri =
+  ## Combines a base URI with a reference URI.
+  ##
+  ## This uses the algorithm specified in
+  ## `section 5.2.2 of RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2.2>`_.
+  ##
+  ## This means that the slashes inside the base URI's path as well as reference
+  ## URI's path affect the resulting URI.
+  ##
+  ## For building URIs you may wish to use \`/\` instead.
+  ##
+  ## Examples:
+  ##
+  ## .. code-block::
+  ##   let foo = combine(parseUri("http://example.com/foo/bar"), parseUri("/baz"))
+  ##   assert foo.path == "/baz"
+  ##
+  ##   let bar = combine(parseUri("http://example.com/foo/bar"), parseUri("baz"))
+  ##   assert bar.path == "/foo/baz"
+  ##
+  ##   let bar = combine(parseUri("http://example.com/foo/bar/"), parseUri("baz"))
+  ##   assert bar.path == "/foo/bar/baz"
+  
+  template setAuthority(dest, src: expr): stmt =
+    dest.hostname = src.hostname
+    dest.username = src.username
+    dest.port = src.port
+    dest.password = src.password
+
+  result = initUri()
+  if reference.scheme != base.scheme and reference.scheme != "":
+    result = reference
+    result.path = removeDotSegments(result.path)
+  else:
+    if reference.hostname != "":
+      setAuthority(result, reference)
+      result.path = removeDotSegments(reference.path)
+      result.query = reference.query
+    else:
+      if reference.path == "":
+        result.path = base.path
+        if reference.query != "":
+          result.query = reference.query
+        else:
+          result.query = base.query
+      else:
+        if reference.path.startsWith("/"):
+          result.path = removeDotSegments(reference.path)
+        else:
+          result.path = removeDotSegments(merge(base, reference))
+        result.query = reference.query
+      setAuthority(result, base)
+    result.scheme = base.scheme
+  result.anchor = reference.anchor
+
+proc combine*(uris: varargs[Uri]): Uri =
+  ## Combines multiple URIs together.
+  result = uris[0]
+  for i in 1 .. <uris.len:
+    result = combine(result, uris[i])
+
+proc `/`*(x: Uri, path: string): Uri =
+  ## Concatenates the path specified to the specified URI's path.
+  ##
+  ## Contrary to the ``combine`` procedure you do not have to worry about
+  ## the slashes at the beginning and end of the path and URI's path
+  ## respectively.
+  ##
+  ## Examples:
+  ##
+  ## .. code-block::
+  ##   let foo = parseUri("http://example.com/foo/bar") / parseUri("/baz")
+  ##   assert foo.path == "/foo/bar/baz"
+  ##
+  ##   let bar = parseUri("http://example.com/foo/bar") / parseUri("baz")
+  ##   assert bar.path == "/foo/bar/baz"
+  ##
+  ##   let bar = parseUri("http://example.com/foo/bar/") / parseUri("baz")
+  ##   assert bar.path == "/foo/bar/baz"
+  result = x
+  if result.path[result.path.len-1] == '/':
+    if path[0] == '/':
+      result.path.add(path[1 .. path.len-1])
+    else:
+      result.path.add(path)
+  else:
+    if path[0] != '/':
+      result.path.add '/'
+    result.path.add(path)
+
+proc `$`*(u: Uri): string =
+  ## Returns the string representation of the specified URI object.
+  result = ""
+  if u.scheme.len > 0:
+    result.add(u.scheme)
+    if u.opaque:
+      result.add(":")
+    else:
+      result.add("://")
+  if u.username.len > 0:
+    result.add(u.username)
+    if u.password.len > 0:
+      result.add(":")
+      result.add(u.password)
+    result.add("@")
+  result.add(u.hostname)
+  if u.port.len > 0:
+    result.add(":")
+    result.add(u.port)
+  if u.path.len > 0:
+    result.add(u.path)
+  if u.query.len > 0:
+    result.add("?")
+    result.add(u.query)
+  if u.anchor.len > 0:
+    result.add("#")
+    result.add(u.anchor)
+
+when isMainModule:
+  block:
+    let str = "http://localhost"
+    let test = parseUri(str)
+    doAssert test.path == ""
+
+  block:
+    let str = "http://localhost/"
+    let test = parseUri(str)
+    doAssert test.path == "/"
+
+  block:
+    let str = "http://localhost:8080/test"
+    let test = parseUri(str)
+    doAssert test.scheme == "http"
+    doAssert test.port == "8080"
+    doAssert test.path == "/test"
+    doAssert test.hostname == "localhost"
+    doAssert($test == str)
+
+  block:
+    let str = "foo://username:password@example.com:8042/over/there" &
+              "/index.dtb?type=animal&name=narwhal#nose"
+    let test = parseUri(str)
+    doAssert test.scheme == "foo"
+    doAssert test.username == "username"
+    doAssert test.password == "password"
+    doAssert test.hostname == "example.com"
+    doAssert test.port == "8042"
+    doAssert test.path == "/over/there/index.dtb"
+    doAssert test.query == "type=animal&name=narwhal"
+    doAssert test.anchor == "nose"
+    doAssert($test == str)
+
+  block:
+    let str = "urn:example:animal:ferret:nose"
+    let test = parseUri(str)
+    doAssert test.scheme == "urn"
+    doAssert test.path == "example:animal:ferret:nose"
+    doAssert($test == str)
+
+  block:
+    let str = "mailto:username@example.com?subject=Topic"
+    let test = parseUri(str)
+    doAssert test.scheme == "mailto"
+    doAssert test.username == "username"
+    doAssert test.hostname == "example.com"
+    doAssert test.query == "subject=Topic"
+    doAssert($test == str)
+
+  block:
+    let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+    let test = parseUri(str)
+    doAssert test.scheme == "magnet"
+    doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+    doAssert($test == str)
+
+  block:
+    let str = "/test/foo/bar?q=2#asdf"
+    let test = parseUri(str)
+    doAssert test.scheme == ""
+    doAssert test.path == "/test/foo/bar"
+    doAssert test.query == "q=2"
+    doAssert test.anchor == "asdf"
+    doAssert($test == str)
+
+  block:
+    let str = "test/no/slash"
+    let test = parseUri(str)
+    doAssert test.path == "test/no/slash"
+    doAssert($test == str)
+
+  # Remove dot segments tests
+  block:
+    doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz"
+
+  # Combine tests
+  block:
+    let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz"))
+    doAssert concat.path == "/foo/bar/baz"
+    doAssert concat.hostname == "google.com"
+    doAssert concat.scheme == "http"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz"))
+    doAssert concat.path == "/baz"
+    doAssert concat.hostname == "google.com"
+    doAssert concat.scheme == "http"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+    doAssert concat.path == "/foo/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar"))
+    doAssert concat.path == "/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+    doAssert concat.path == "/foo/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar"))
+    doAssert concat.path == "/foo/test/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"))
+    doAssert concat.path == "/foo/test/bar/"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"),
+                         parseUri("baz"))
+    doAssert concat.path == "/foo/test/bar/baz"
+
+  # `/` tests
+  block:
+    let test = parseUri("http://example.com/foo") / "bar/asd"
+    doAssert test.path == "/foo/bar/asd"
+
+  block:
+    let test = parseUri("http://example.com/foo/") / "/bar/asd"
+    doAssert test.path == "/foo/bar/asd"
diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim
new file mode 100644
index 000000000..6cf837f25
--- /dev/null
+++ b/lib/pure/xmldom.nim
@@ -0,0 +1,1120 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+import strutils
+## This module implements XML DOM Level 2 Core
+## specification (http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html)
+
+
+#http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+
+#Exceptions
+type
+  EDOMException* = object of ValueError ## Base exception object for all DOM Exceptions
+  EDOMStringSizeErr* = object of EDOMException ## If the specified range of text does not fit into a DOMString
+                                               ## Currently not used(Since DOMString is just string)
+  EHierarchyRequestErr* = object of EDOMException ## If any node is inserted somewhere it doesn't belong
+  EIndexSizeErr* = object of EDOMException ## If index or size is negative, or greater than the allowed value
+  EInuseAttributeErr* = object of EDOMException ## If an attempt is made to add an attribute that is already in use elsewhere
+  EInvalidAccessErr* = object of EDOMException ## If a parameter or an operation is not supported by the underlying object.
+  EInvalidCharacterErr* = object of EDOMException ## This exception is raised when a string parameter contains an illegal character
+  EInvalidModificationErr* = object of EDOMException ## If an attempt is made to modify the type of the underlying object.
+  EInvalidStateErr* = object of EDOMException ## If an attempt is made to use an object that is not, or is no longer, usable.
+  ENamespaceErr* = object of EDOMException ## If an attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
+  ENotFoundErr* = object of EDOMException ## If an attempt is made to reference a node in a context where it does not exist
+  ENotSupportedErr* = object of EDOMException ## If the implementation does not support the requested type of object or operation.
+  ENoDataAllowedErr* = object of EDOMException ## If data is specified for a node which does not support data
+  ENoModificationAllowedErr* = object of EDOMException ## If an attempt is made to modify an object where modifications are not allowed
+  ESyntaxErr* = object of EDOMException ## If an invalid or illegal string is specified.
+  EWrongDocumentErr* = object of EDOMException ## If a node is used in a different document than the one that created it (that doesn't support it)
+
+const
+  ElementNode* = 1
+  AttributeNode* = 2
+  TextNode* = 3
+  CDataSectionNode* = 4
+  ProcessingInstructionNode* = 7
+  CommentNode* = 8
+  DocumentNode* = 9
+  DocumentFragmentNode* = 11
+
+  # Nodes which are childless - Not sure about AttributeNode
+  childlessObjects = {DocumentNode, AttributeNode, TextNode,
+    CDataSectionNode, ProcessingInstructionNode, CommentNode}
+  # Illegal characters
+  illegalChars = {'>', '<', '&', '"'}
+
+
+type
+  Feature = tuple[name: string, version: string]
+  PDOMImplementation* = ref DOMImplementation
+  DOMImplementation = object
+    features: seq[Feature] # Read-Only
+
+  PNode* = ref Node
+  Node = object of RootObj
+    attributes*: seq[PAttr]
+    childNodes*: seq[PNode]
+    fLocalName: string # Read-only
+    fNamespaceURI: string # Read-only
+    fNodeName: string # Read-only
+    nodeValue*: string
+    fNodeType: int # Read-only
+    fOwnerDocument: PDocument # Read-Only
+    fParentNode: PNode # Read-Only
+    prefix*: string # Setting this should change some values... TODO!
+
+  PElement* = ref Element
+  Element = object of Node
+    fTagName: string # Read-only
+
+  PCharacterData* = ref CharacterData
+  CharacterData = object of Node
+    data*: string
+
+  PDocument* = ref Document
+  Document = object of Node
+    fImplementation: PDOMImplementation # Read-only
+    fDocumentElement: PElement # Read-only
+
+  PAttr* = ref Attr
+  Attr = object of Node
+    fName: string # Read-only
+    fSpecified: bool # Read-only
+    value*: string
+    fOwnerElement: PElement # Read-only
+
+  PDocumentFragment* = ref DocumentFragment
+  DocumentFragment = object of Node
+
+  PText* = ref Text
+  Text = object of CharacterData
+
+  PComment* = ref Comment
+  Comment = object of CharacterData
+
+  PCDataSection* = ref CDataSection
+  CDataSection = object of Text
+
+  PProcessingInstruction* = ref ProcessingInstruction
+  ProcessingInstruction = object of Node
+    data*: string
+    fTarget: string # Read-only
+
+# DOMImplementation
+proc getDOM*(): PDOMImplementation =
+  ## Returns a DOMImplementation
+  new(result)
+  result.features = @[(name: "core", version: "2.0"),
+                      (name: "core", version: "1.0"),
+                      (name: "XML", version: "2.0")]
+
+proc createDocument*(dom: PDOMImplementation, namespaceURI: string, qualifiedName: string): PDocument =
+  ## Creates an XML Document object of the specified type with its document element.
+  var doc: PDocument
+  new(doc)
+  doc.fNamespaceURI = namespaceURI
+  doc.fImplementation = dom
+
+  var elTag: PElement
+  new(elTag)
+  elTag.fTagName = qualifiedName
+  elTag.fNodeName = qualifiedName
+  doc.fDocumentElement = elTag
+  doc.fNodeType = DocumentNode
+
+  return doc
+
+proc createDocument*(dom: PDOMImplementation, n: PElement): PDocument =
+  ## Creates an XML Document object of the specified type with its document element.
+
+  # This procedure is not in the specification, it's provided for the parser.
+  var doc: PDocument
+  new(doc)
+  doc.fDocumentElement = n
+  doc.fImplementation = dom
+  doc.fNodeType = DocumentNode
+
+  return doc
+
+proc hasFeature*(dom: PDOMImplementation, feature: string, version: string = ""): bool =
+  ## Returns ``true`` if this ``version`` of the DomImplementation implements ``feature``, otherwise ``false``
+  for iName, iVersion in items(dom.features):
+    if iName == feature:
+      if version == "":
+        return true
+      else:
+        if iVersion == version:
+          return true
+  return false
+
+
+# Document
+# Attributes
+
+proc implementation*(doc: PDocument): PDOMImplementation =
+  return doc.fImplementation
+
+proc documentElement*(doc: PDocument): PElement =
+  return doc.fDocumentElement
+
+# Internal procedures
+proc findNodes(nl: PNode, name: string): seq[PNode] =
+  # Made for getElementsByTagName
+  var r: seq[PNode] = @[]
+  if isNil(nl.childNodes): return @[]
+  if nl.childNodes.len() == 0: return @[]
+
+  for i in items(nl.childNodes):
+    if i.fNodeType == ElementNode:
+      if i.fNodeName == name or name == "*":
+        r.add(i)
+
+      if not isNil(i.childNodes):
+        if i.childNodes.len() != 0:
+          r.add(findNodes(i, name))
+
+  return r
+
+proc findNodesNS(nl: PNode, namespaceURI: string, localName: string): seq[PNode] =
+  # Made for getElementsByTagNameNS
+  var r: seq[PNode] = @[]
+  if isNil(nl.childNodes): return @[]
+  if nl.childNodes.len() == 0: return @[]
+
+  for i in items(nl.childNodes):
+    if i.fNodeType == ElementNode:
+      if (i.fNamespaceURI == namespaceURI or namespaceURI == "*") and (i.fLocalName == localName or localName == "*"):
+        r.add(i)
+
+      if not isNil(i.childNodes):
+        if i.childNodes.len() != 0:
+          r.add(findNodesNS(i, namespaceURI, localName))
+
+  return r
+
+
+#Procedures
+proc createAttribute*(doc: PDocument, name: string): PAttr =
+  ## Creates an Attr of the given name. Note that the Attr instance can then be set on an Element using the setAttributeNode method.
+  ## To create an attribute with a qualified name and namespace URI, use the createAttributeNS method.
+
+  # Check if name contains illegal characters
+  if illegalChars in name:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  var attrNode: PAttr
+  new(attrNode)
+  attrNode.fName = name
+  attrNode.fNodeName = name
+  attrNode.fLocalName = nil
+  attrNode.prefix = nil
+  attrNode.fNamespaceURI = nil
+  attrNode.value = ""
+  attrNode.fSpecified = false
+  return attrNode
+
+proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PAttr =
+  ## Creates an attribute of the given qualified name and namespace URI
+
+  # Check if name contains illegal characters
+  if illegalChars in namespaceURI or illegalChars in qualifiedName:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+  # Exceptions
+  if qualifiedName.contains(':'):
+    if isNil(namespaceURI):
+      raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
+    elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace":
+      raise newException(ENamespaceErr,
+        "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
+    elif qualifiedName.split(':')[1].toLower() == "xmlns" and namespaceURI != "http://www.w3.org/2000/xmlns/":
+      raise newException(ENamespaceErr,
+        "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
+
+  var attrNode: PAttr
+  new(attrNode)
+  attrNode.fName = qualifiedName
+  attrNode.fNodeName = qualifiedName
+  attrNode.fSpecified = false
+  attrNode.fNamespaceURI = namespaceURI
+  if qualifiedName.contains(':'):
+    attrNode.prefix = qualifiedName.split(':')[0]
+    attrNode.fLocalName = qualifiedName.split(':')[1]
+  else:
+    attrNode.prefix = nil
+    attrNode.fLocalName = qualifiedName
+  attrNode.value = ""
+
+  attrNode.fNodeType = AttributeNode
+  return attrNode
+
+proc createCDATASection*(doc: PDocument, data: string): PCDataSection =
+  ## Creates a CDATASection node whose value is the specified string.
+  var cData: PCDataSection
+  new(cData)
+  cData.data = data
+  cData.nodeValue = data
+  cData.fNodeName = "#text" # Not sure about this, but this is technically a TextNode
+  cData.fNodeType = CDataSectionNode
+  return cData
+
+proc createComment*(doc: PDocument, data: string): PComment =
+  ## Creates a Comment node given the specified string.
+  var comm: PComment
+  new(comm)
+  comm.data = data
+  comm.nodeValue = data
+
+  comm.fNodeType = CommentNode
+  return comm
+
+proc createDocumentFragment*(doc: PDocument): PDocumentFragment =
+  ## Creates an empty DocumentFragment object.
+  var df: PDocumentFragment
+  new(df)
+  return df
+
+proc createElement*(doc: PDocument, tagName: string): PElement =
+  ## Creates an element of the type specified.
+
+  # Check if name contains illegal characters
+  if illegalChars in tagName:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  var elNode: PElement
+  new(elNode)
+  elNode.fTagName = tagName
+  elNode.fNodeName = tagName
+  elNode.fLocalName = nil
+  elNode.prefix = nil
+  elNode.fNamespaceURI = nil
+  elNode.childNodes = @[]
+  elNode.attributes = @[]
+
+  elNode.fNodeType = ElementNode
+
+  return elNode
+
+proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement =
+  ## Creates an element of the given qualified name and namespace URI.
+  if qualifiedName.contains(':'):
+    if isNil(namespaceURI):
+      raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
+    elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace":
+      raise newException(ENamespaceErr,
+        "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
+
+  # Check if name contains illegal characters
+  if illegalChars in namespaceURI or illegalChars in qualifiedName:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  var elNode: PElement
+  new(elNode)
+  elNode.fTagName = qualifiedName
+  elNode.fNodeName = qualifiedName
+  if qualifiedName.contains(':'):
+    elNode.prefix = qualifiedName.split(':')[0]
+    elNode.fLocalName = qualifiedName.split(':')[1]
+  else:
+    elNode.prefix = nil
+    elNode.fLocalName = qualifiedName
+  elNode.fNamespaceURI = namespaceURI
+  elNode.childNodes = @[]
+  elNode.attributes = @[]
+
+  elNode.fNodeType = ElementNode
+
+  return elNode
+
+proc createProcessingInstruction*(doc: PDocument, target: string, data: string): PProcessingInstruction =
+  ## Creates a ProcessingInstruction node given the specified name and data strings.
+
+  #Check if name contains illegal characters
+  if illegalChars in target:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  var pi: PProcessingInstruction
+  new(pi)
+  pi.fTarget = target
+  pi.data = data
+  pi.fNodeType = ProcessingInstructionNode
+  return pi
+
+proc createTextNode*(doc: PDocument, data: string): PText = #Propably TextNode
+  ## Creates a Text node given the specified string.
+  var txtNode: PText
+  new(txtNode)
+  txtNode.data = data
+  txtNode.nodeValue = data
+  txtNode.fNodeName = "#text"
+
+  txtNode.fNodeType = TextNode
+  return txtNode
+
+discard """proc getElementById*(doc: PDocument, elementId: string): PElement =
+  ##Returns the ``Element`` whose ID is given by ``elementId``. If no such element exists, returns ``nil``
+  #TODO"""
+
+proc getElementsByTagName*(doc: PDocument, tagName: string): seq[PNode] =
+  ## Returns a NodeList of all the Elements with a given tag name in
+  ## the order in which they are encountered in a preorder traversal of the Document tree.
+  result = @[]
+  if doc.fDocumentElement.fNodeName == tagName or tagName == "*":
+    result.add(doc.fDocumentElement)
+
+  result.add(doc.fDocumentElement.findNodes(tagName))
+
+proc getElementsByTagNameNS*(doc: PDocument, namespaceURI: string, localName: string): seq[PNode] =
+  ## Returns a NodeList of all the Elements with a given localName and namespaceURI
+  ## in the order in which they are encountered in a preorder traversal of the Document tree.
+  result = @[]
+  if doc.fDocumentElement.fLocalName == localName or localName == "*":
+    if doc.fDocumentElement.fNamespaceURI == namespaceURI or namespaceURI == "*":
+      result.add(doc.fDocumentElement)
+
+  result.add(doc.fDocumentElement.findNodesNS(namespaceURI, localName))
+
+proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode =
+  ## Imports a node from another document to this document
+  case importedNode.fNodeType
+  of AttributeNode:
+    var nAttr: PAttr = PAttr(importedNode)
+    nAttr.fOwnerDocument = doc
+    nAttr.fParentNode = nil
+    nAttr.fOwnerElement = nil
+    nAttr.fSpecified = true
+    return nAttr
+  of DocumentFragmentNode:
+    var n: PNode
+    new(n)
+    n = importedNode
+    n.fOwnerDocument = doc
+    n.fParentNode = nil
+
+    n.fOwnerDocument = doc
+    n.fParentNode = nil
+    var tmp: seq[PNode] = n.childNodes
+    n.childNodes = @[]
+    if deep:
+      for i in low(tmp.len())..high(tmp.len()):
+        n.childNodes.add(importNode(doc, tmp[i], deep))
+
+    return n
+  of ElementNode:
+    var n: PNode
+    new(n)
+    n = importedNode
+    n.fOwnerDocument = doc
+    n.fParentNode = nil
+
+    var tmpA: seq[PAttr] = n.attributes
+    n.attributes = @[]
+    # Import the Element node's attributes
+    for i in low(tmpA.len())..high(tmpA.len()):
+      n.attributes.add(PAttr(importNode(doc, tmpA[i], deep)))
+    # Import the childNodes
+    var tmp: seq[PNode] = n.childNodes
+    n.childNodes = @[]
+    if deep:
+      for i in low(tmp.len())..high(tmp.len()):
+        n.childNodes.add(importNode(doc, tmp[i], deep))
+
+    return n
+  of ProcessingInstructionNode, TextNode, CDataSectionNode, CommentNode:
+    var n: PNode
+    new(n)
+    n = importedNode
+    n.fOwnerDocument = doc
+    n.fParentNode = nil
+    return n
+  else:
+    raise newException(ENotSupportedErr, "The type of node being imported is not supported")
+
+
+# Node
+# Attributes
+
+proc firstChild*(n: PNode): PNode =
+  ## Returns this node's first child
+
+  if not isNil(n.childNodes) and n.childNodes.len() > 0:
+    return n.childNodes[0]
+  else:
+    return nil
+
+proc lastChild*(n: PNode): PNode =
+  ## Returns this node's last child
+
+  if not isNil(n.childNodes) and n.childNodes.len() > 0:
+    return n.childNodes[n.childNodes.len() - 1]
+  else:
+    return nil
+
+proc localName*(n: PNode): string =
+  ## Returns this nodes local name
+
+  return n.fLocalName
+
+proc namespaceURI*(n: PNode): string =
+  ## Returns this nodes namespace URI
+
+  return n.fNamespaceURI
+
+proc `namespaceURI=`*(n: PNode, value: string) =
+  n.fNamespaceURI = value
+
+proc nextSibling*(n: PNode): PNode =
+  ## Returns the next sibling of this node
+
+  if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes):
+    return nil
+  var nLow: int = low(n.fParentNode.childNodes)
+  var nHigh: int = high(n.fParentNode.childNodes)
+  for i in nLow..nHigh:
+    if n.fParentNode.childNodes[i] == n:
+      return n.fParentNode.childNodes[i + 1]
+  return nil
+
+proc nodeName*(n: PNode): string =
+  ## Returns the name of this node
+
+  return n.fNodeName
+
+proc nodeType*(n: PNode): int =
+  ## Returns the type of this node
+
+  return n.fNodeType
+
+proc ownerDocument*(n: PNode): PDocument =
+  ## Returns the owner document of this node
+
+  return n.fOwnerDocument
+
+proc parentNode*(n: PNode): PNode =
+  ## Returns the parent node of this node
+
+  return n.fParentNode
+
+proc previousSibling*(n: PNode): PNode =
+  ## Returns the previous sibling of this node
+
+  if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes):
+    return nil
+  var nLow: int = low(n.fParentNode.childNodes)
+  var nHigh: int = high(n.fParentNode.childNodes)
+  for i in nLow..nHigh:
+    if n.fParentNode.childNodes[i] == n:
+      return n.fParentNode.childNodes[i - 1]
+  return nil
+
+proc `prefix=`*(n: PNode, value: string) =
+  ## Modifies the prefix of this node
+
+  # Setter
+  # Check if name contains illegal characters
+  if illegalChars in value:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  if isNil(n.fNamespaceURI):
+    raise newException(ENamespaceErr, "namespaceURI cannot be nil")
+  elif value.toLower() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace":
+    raise newException(ENamespaceErr,
+      "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
+  elif value.toLower() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/":
+    raise newException(ENamespaceErr,
+      "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
+  elif value.toLower() == "xmlns" and n.fNodeType == AttributeNode:
+    raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"")
+
+  n.fNodeName = value & ":" & n.fLocalName
+  if n.nodeType == ElementNode:
+    var el: PElement = PElement(n)
+    el.fTagName = value & ":" & n.fLocalName
+
+  elif n.nodeType == AttributeNode:
+    var attr: PAttr = PAttr(n)
+    attr.fName = value & ":" & n.fLocalName
+
+# Procedures
+proc appendChild*(n: PNode, newChild: PNode) =
+  ## Adds the node newChild to the end of the list of children of this node.
+  ## If the newChild is already in the tree, it is first removed.
+
+  # Check if n contains newChild
+  if not isNil(n.childNodes):
+    for i in low(n.childNodes)..high(n.childNodes):
+      if n.childNodes[i] == newChild:
+        raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.")
+
+  # Check if newChild is from this nodes document
+  if n.fOwnerDocument != newChild.fOwnerDocument:
+    raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+
+  if n == newChild:
+    raise newException(EHierarchyRequestErr, "You can't add a node into itself")
+
+  if n.nodeType in childlessObjects:
+    raise newException(ENoModificationAllowedErr, "Cannot append children to a childless node")
+
+  if isNil(n.childNodes): n.childNodes = @[]
+
+  newChild.fParentNode = n
+  for i in low(n.childNodes)..high(n.childNodes):
+    if n.childNodes[i] == newChild:
+      n.childNodes[i] = newChild
+
+  n.childNodes.add(newChild)
+
+proc cloneNode*(n: PNode, deep: bool): PNode =
+  ## Returns a duplicate of this node, if ``deep`` is `true`, Element node's children are copied
+  case n.fNodeType
+  of AttributeNode:
+    var newNode: PAttr
+    new(newNode)
+    newNode = PAttr(n)
+    newNode.fSpecified = true
+    newNode.fOwnerElement = nil
+    return newNode
+  of ElementNode:
+    var newNode: PElement
+    new(newNode)
+    newNode = PElement(n)
+    # Import the childNodes
+    var tmp: seq[PNode] = n.childNodes
+    n.childNodes = @[]
+    if deep and not isNil(tmp):
+      for i in low(tmp.len())..high(tmp.len()):
+        n.childNodes.add(cloneNode(tmp[i], deep))
+    return newNode
+  else:
+    var newNode: PNode
+    new(newNode)
+    newNode = n
+    return newNode
+
+proc hasAttributes*(n: PNode): bool =
+  ## Returns whether this node (if it is an element) has any attributes.
+  return not isNil(n.attributes) and n.attributes.len() > 0
+
+proc hasChildNodes*(n: PNode): bool =
+  ## Returns whether this node has any children.
+  return not isNil(n.childNodes) and n.childNodes.len() > 0
+
+proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode =
+  ## Inserts the node ``newChild`` before the existing child node ``refChild``.
+  ## If ``refChild`` is nil, insert ``newChild`` at the end of the list of children.
+
+  # Check if newChild is from this nodes document
+  if n.fOwnerDocument != newChild.fOwnerDocument:
+    raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+
+  if isNil(n.childNodes):
+    n.childNodes = @[]
+
+  for i in low(n.childNodes)..high(n.childNodes):
+    if n.childNodes[i] == refChild:
+      n.childNodes.insert(newChild, i - 1)
+      return
+
+  n.childNodes.add(newChild)
+
+proc isSupported*(n: PNode, feature: string, version: string): bool =
+  ## Tests whether the DOM implementation implements a specific
+  ## feature and that feature is supported by this node.
+  return n.fOwnerDocument.fImplementation.hasFeature(feature, version)
+
+proc isEmpty(s: string): bool =
+
+  if isNil(s) or s == "":
+    return true
+  for i in items(s):
+    if i != ' ':
+      return false
+  return true
+
+proc normalize*(n: PNode) =
+  ## Merges all separated TextNodes together, and removes any empty TextNodes
+  var curTextNode: PNode = nil
+  var i: int = 0
+
+  var newChildNodes: seq[PNode] = @[]
+  while true:
+    if isNil(n.childNodes) or i >= n.childNodes.len:
+      break
+    if n.childNodes[i].nodeType == TextNode:
+
+      #If the TextNode is empty, remove it
+      if PText(n.childNodes[i]).data.isEmpty():
+        inc(i)
+
+      if isNil(curTextNode):
+        curTextNode = n.childNodes[i]
+      else:
+        PText(curTextNode).data.add(PText(n.childNodes[i]).data)
+        curTextNode.nodeValue.add(PText(n.childNodes[i]).data)
+        inc(i)
+    else:
+      newChildNodes.add(curTextNode)
+      newChildNodes.add(n.childNodes[i])
+      curTextNode = nil
+
+    inc(i)
+  n.childNodes = newChildNodes
+
+proc removeChild*(n: PNode, oldChild: PNode): PNode =
+  ## Removes the child node indicated by ``oldChild`` from the list of children, and returns it.
+  if not isNil(n.childNodes):
+    for i in low(n.childNodes)..high(n.childNodes):
+      if n.childNodes[i] == oldChild:
+        result = n.childNodes[i]
+        n.childNodes.delete(i)
+        return
+
+  raise newException(ENotFoundErr, "Node not found")
+
+proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode =
+  ## Replaces the child node ``oldChild`` with ``newChild`` in the list of children, and returns the ``oldChild`` node.
+
+  # Check if newChild is from this nodes document
+  if n.fOwnerDocument != newChild.fOwnerDocument:
+    raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+
+  if not isNil(n.childNodes):
+    for i in low(n.childNodes)..high(n.childNodes):
+      if n.childNodes[i] == oldChild:
+        result = n.childNodes[i]
+        n.childNodes[i] = newChild
+        return
+
+  raise newException(ENotFoundErr, "Node not found")
+
+# NamedNodeMap
+
+proc getNamedItem*(nList: seq[PNode], name: string): PNode =
+  ## Retrieves a node specified by ``name``. If this node cannot be found returns ``nil``
+  for i in items(nList):
+    if i.nodeName() == name:
+      return i
+  return nil
+
+proc getNamedItem*(nList: seq[PAttr], name: string): PAttr =
+  ## Retrieves a node specified by ``name``. If this node cannot be found returns ``nil``
+  for i in items(nList):
+    if i.nodeName() == name:
+      return i
+  return nil
+
+proc getNamedItemNS*(nList: seq[PNode], namespaceURI: string, localName: string): PNode =
+  ## Retrieves a node specified by ``localName`` and ``namespaceURI``. If this node cannot be found returns ``nil``
+  for i in items(nList):
+    if i.namespaceURI() == namespaceURI and i.localName() == localName:
+      return i
+  return nil
+
+proc getNamedItemNS*(nList: seq[PAttr], namespaceURI: string, localName: string): PAttr =
+  ## Retrieves a node specified by ``localName`` and ``namespaceURI``. If this node cannot be found returns ``nil``
+  for i in items(nList):
+    if i.namespaceURI() == namespaceURI and i.localName() == localName:
+      return i
+  return nil
+
+proc item*(nList: seq[PNode], index: int): PNode =
+  ## Returns the ``index`` th item in the map.
+  ## If ``index`` is greater than or equal to the number of nodes in this map, this returns ``nil``.
+  if index >= nList.len(): return nil
+  else: return nList[index]
+
+proc removeNamedItem*(nList: var seq[PNode], name: string): PNode =
+  ## Removes a node specified by ``name``
+  ## Raises the ``ENotFoundErr`` exception, if the node was not found
+  for i in low(nList)..high(nList):
+    if nList[i].fNodeName == name:
+      result = nList[i]
+      nList.delete(i)
+      return
+
+  raise newException(ENotFoundErr, "Node not found")
+
+proc removeNamedItemNS*(nList: var seq[PNode], namespaceURI: string, localName: string): PNode =
+  ## Removes a node specified by local name and namespace URI
+  for i in low(nList)..high(nList):
+    if nList[i].fLocalName == localName and nList[i].fNamespaceURI == namespaceURI:
+      result = nList[i]
+      nList.delete(i)
+      return
+
+  raise newException(ENotFoundErr, "Node not found")
+
+proc setNamedItem*(nList: var seq[PNode], arg: PNode): PNode =
+  ## Adds ``arg`` as a ``Node`` to the ``NList``
+  ## If a node with the same name is already present in this map, it is replaced by the new one.
+  if not isNil(nList):
+    if nList.len() > 0:
+      #Check if newChild is from this nodes document
+      if nList[0].fOwnerDocument != arg.fOwnerDocument:
+        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+  #Exceptions End
+
+  var item: PNode = nList.getNamedItem(arg.nodeName())
+  if isNil(item):
+    nList.add(arg)
+    return nil
+  else:
+    # Node with the same name exists
+    var index: int = 0
+    for i in low(nList)..high(nList):
+      if nList[i] == item:
+        index = i
+        break
+    nList[index] = arg
+    return item # Return the replaced node
+
+proc setNamedItem*(nList: var seq[PAttr], arg: PAttr): PAttr =
+  ## Adds ``arg`` as a ``Node`` to the ``NList``
+  ## If a node with the same name is already present in this map, it is replaced by the new one.
+  if not isNil(nList):
+    if nList.len() > 0:
+      # Check if newChild is from this nodes document
+      if nList[0].fOwnerDocument != arg.fOwnerDocument:
+        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+
+  if not isNil(arg.fOwnerElement):
+    raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode")
+
+  # Exceptions end
+  var item: PAttr = nList.getNamedItem(arg.nodeName())
+  if isNil(item):
+    nList.add(arg)
+    return nil
+  else:
+    # Node with the same name exists
+    var index: int = 0
+    for i in low(nList)..high(nList):
+      if nList[i] == item:
+        index = i
+        break
+    nList[index] = arg
+    return item # Return the replaced node
+
+proc setNamedItemNS*(nList: var seq[PNode], arg: PNode): PNode =
+  ## Adds a node using its ``namespaceURI`` and ``localName``
+  if not isNil(nList):
+    if nList.len() > 0:
+      # Check if newChild is from this nodes document
+      if nList[0].fOwnerDocument != arg.fOwnerDocument:
+        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+  #Exceptions end
+
+  var item: PNode = nList.getNamedItemNS(arg.namespaceURI(), arg.localName())
+  if isNil(item):
+    nList.add(arg)
+    return nil
+  else:
+    # Node with the same name exists
+    var index: int = 0
+    for i in low(nList)..high(nList):
+      if nList[i] == item:
+        index = i
+        break
+    nList[index] = arg
+    return item # Return the replaced node
+
+proc setNamedItemNS*(nList: var seq[PAttr], arg: PAttr): PAttr =
+  ## Adds a node using its ``namespaceURI`` and ``localName``
+  if not isNil(nList):
+    if nList.len() > 0:
+      # Check if newChild is from this nodes document
+      if nList[0].fOwnerDocument != arg.fOwnerDocument:
+        raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.")
+
+  if not isNil(arg.fOwnerElement):
+    raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode")
+
+  # Exceptions end
+  var item: PAttr = nList.getNamedItemNS(arg.namespaceURI(), arg.localName())
+  if isNil(item):
+    nList.add(arg)
+    return nil
+  else:
+    # Node with the same name exists
+    var index: int = 0
+    for i in low(nList)..high(nList):
+      if nList[i] == item:
+        index = i
+        break
+    nList[index] = arg
+    return item # Return the replaced node
+
+# CharacterData - Decided to implement this,
+# Didn't add the procedures, because you can just edit .data
+
+# Attr
+# Attributes
+proc name*(a: PAttr): string =
+  ## Returns the name of the Attribute
+
+  return a.fName
+
+proc specified*(a: PAttr): bool =
+  ## Specifies whether this attribute was specified in the original document
+
+  return a.fSpecified
+
+proc ownerElement*(a: PAttr): PElement =
+  ## Returns this Attributes owner element
+
+  return a.fOwnerElement
+
+# Element
+# Attributes
+
+proc tagName*(el: PElement): string =
+  ## Returns the Element Tag Name
+
+  return el.fTagName
+
+# Procedures
+proc getAttribute*(el: PElement, name: string): string =
+  ## Retrieves an attribute value by ``name``
+  if isNil(el.attributes):
+    return nil
+  var attribute = el.attributes.getNamedItem(name)
+  if not isNil(attribute):
+    return attribute.value
+  else:
+    return nil
+
+proc getAttributeNS*(el: PElement, namespaceURI: string, localName: string): string =
+  ## Retrieves an attribute value by ``localName`` and ``namespaceURI``
+  if isNil(el.attributes):
+    return nil
+  var attribute = el.attributes.getNamedItemNS(namespaceURI, localName)
+  if not isNil(attribute):
+    return attribute.value
+  else:
+    return nil
+
+proc getAttributeNode*(el: PElement, name: string): PAttr =
+  ## Retrieves an attribute node by ``name``
+  ## To retrieve an attribute node by qualified name and namespace URI, use the `getAttributeNodeNS` method
+  if isNil(el.attributes):
+    return nil
+  return el.attributes.getNamedItem(name)
+
+proc getAttributeNodeNS*(el: PElement, namespaceURI: string, localName: string): PAttr =
+  ## Retrieves an `Attr` node by ``localName`` and ``namespaceURI``
+  if isNil(el.attributes):
+    return nil
+  return el.attributes.getNamedItemNS(namespaceURI, localName)
+
+proc getElementsByTagName*(el: PElement, name: string): seq[PNode] =
+  ## Returns a `NodeList` of all descendant `Elements` of ``el`` with a given tag ``name``,
+  ## in the order in which they are encountered in a preorder traversal of this `Element` tree
+  ## If ``name`` is `*`, returns all descendant of ``el``
+  result = el.findNodes(name)
+
+proc getElementsByTagNameNS*(el: PElement, namespaceURI: string, localName: string): seq[PNode] =
+  ## Returns a `NodeList` of all the descendant Elements with a given
+  ## ``localName`` and ``namespaceURI`` in the order in which they are
+  ## encountered in a preorder traversal of this Element tree
+  result = el.findNodesNS(namespaceURI, localName)
+
+proc hasAttribute*(el: PElement, name: string): bool =
+  ## Returns ``true`` when an attribute with a given ``name`` is specified
+  ## on this element , ``false`` otherwise.
+  if isNil(el.attributes):
+    return false
+  return not isNil(el.attributes.getNamedItem(name))
+
+proc hasAttributeNS*(el: PElement, namespaceURI: string, localName: string): bool =
+  ## Returns ``true`` when an attribute with a given ``localName`` and
+  ## ``namespaceURI`` is specified on this element , ``false`` otherwise
+  if isNil(el.attributes):
+    return false
+  return not isNil(el.attributes.getNamedItemNS(namespaceURI, localName))
+
+proc removeAttribute*(el: PElement, name: string) =
+  ## Removes an attribute by ``name``
+  if not isNil(el.attributes):
+    for i in low(el.attributes)..high(el.attributes):
+      if el.attributes[i].fName == name:
+        el.attributes.delete(i)
+
+proc removeAttributeNS*(el: PElement, namespaceURI: string, localName: string) =
+  ## Removes an attribute by ``localName`` and ``namespaceURI``
+  if not isNil(el.attributes):
+    for i in low(el.attributes)..high(el.attributes):
+      if el.attributes[i].fNamespaceURI == namespaceURI and
+          el.attributes[i].fLocalName == localName:
+        el.attributes.delete(i)
+
+proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr =
+  ## Removes the specified attribute node
+  ## If the attribute node cannot be found raises ``ENotFoundErr``
+  if not isNil(el.attributes):
+    for i in low(el.attributes)..high(el.attributes):
+      if el.attributes[i] == oldAttr:
+        result = el.attributes[i]
+        el.attributes.delete(i)
+        return
+
+  raise newException(ENotFoundErr, "oldAttr is not a member of el's Attributes")
+
+proc setAttributeNode*(el: PElement, newAttr: PAttr): PAttr =
+  ## Adds a new attribute node, if an attribute with the same `nodeName` is
+  ## present, it is replaced by the new one and the replaced attribute is
+  ## returned, otherwise ``nil`` is returned.
+
+  # Check if newAttr is from this nodes document
+  if el.fOwnerDocument != newAttr.fOwnerDocument:
+    raise newException(EWrongDocumentErr,
+      "This node belongs to a different document, use importNode.")
+
+  if not isNil(newAttr.fOwnerElement):
+    raise newException(EInuseAttributeErr,
+      "This attribute is in use by another element, use cloneNode")
+  # Exceptions end
+
+  if isNil(el.attributes): el.attributes = @[]
+  return el.attributes.setNamedItem(newAttr)
+
+proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr =
+  ## Adds a new attribute node, if an attribute with the localName and
+  ## namespaceURI of ``newAttr`` is present, it is replaced by the new one
+  ## and the replaced attribute is returned, otherwise ``nil`` is returned.
+
+  # Check if newAttr is from this nodes document
+  if el.fOwnerDocument != newAttr.fOwnerDocument:
+    raise newException(EWrongDocumentErr,
+      "This node belongs to a different document, use importNode.")
+
+  if not isNil(newAttr.fOwnerElement):
+    raise newException(EInuseAttributeErr,
+      "This attribute is in use by another element, use cloneNode")
+  # Exceptions end
+
+  if isNil(el.attributes): el.attributes = @[]
+  return el.attributes.setNamedItemNS(newAttr)
+
+proc setAttribute*(el: PElement, name: string, value: string) =
+  ## Adds a new attribute, as specified by ``name`` and ``value``
+  ## If an attribute with that name is already present in the element, its
+  ## value is changed to be that of the value parameter
+  ## Raises the EInvalidCharacterErr if the specified ``name`` contains
+  ## illegal characters
+  var attrNode = el.fOwnerDocument.createAttribute(name)
+  # Check if name contains illegal characters
+  if illegalChars in name:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  discard el.setAttributeNode(attrNode)
+  # Set the info later, the setAttributeNode checks
+  # if FOwnerElement is nil, and if it isn't it raises an exception
+  attrNode.fOwnerElement = el
+  attrNode.fSpecified = true
+  attrNode.value = value
+
+proc setAttributeNS*(el: PElement, namespaceURI, localName, value: string) =
+  ## Adds a new attribute, as specified by ``namespaceURI``, ``localName``
+  ## and ``value``.
+
+  # Check if name contains illegal characters
+  if illegalChars in namespaceURI or illegalChars in localName:
+    raise newException(EInvalidCharacterErr, "Invalid character")
+
+  var attrNode = el.fOwnerDocument.createAttributeNS(namespaceURI, localName)
+
+  discard el.setAttributeNodeNS(attrNode)
+  # Set the info later, the setAttributeNode checks
+  # if FOwnerElement is nil, and if it isn't it raises an exception
+  attrNode.fOwnerElement = el
+  attrNode.fSpecified = true
+  attrNode.value = value
+
+# Text
+proc splitData*(textNode: PText, offset: int): PText =
+  ## Breaks this node into two nodes at the specified offset,
+  ## keeping both in the tree as siblings.
+
+  if offset > textNode.data.len():
+    raise newException(EIndexSizeErr, "Index out of bounds")
+
+  var left: string = textNode.data.substr(0, offset)
+  textNode.data = left
+  var right: string = textNode.data.substr(offset, textNode.data.len())
+
+  if not isNil(textNode.fParentNode) and not isNil(textNode.fParentNode.childNodes):
+    for i in low(textNode.fParentNode.childNodes)..high(textNode.fParentNode.childNodes):
+      if textNode.fParentNode.childNodes[i] == textNode:
+        var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
+        textNode.fParentNode.childNodes.insert(newNode, i)
+        return newNode
+  else:
+    var newNode: PText = textNode.fOwnerDocument.createTextNode(right)
+    return newNode
+
+
+# ProcessingInstruction
+proc target*(pi: PProcessingInstruction): string =
+  ## Returns the Processing Instructions target
+
+  return pi.fTarget
+
+
+# --Other stuff--
+# Writer
+proc addEscaped(s: string): string =
+  result = ""
+  for c in items(s):
+    case c
+    of '<': result.add("&lt;")
+    of '>': result.add("&gt;")
+    of '&': result.add("&amp;")
+    of '"': result.add("&quot;")
+    else: result.add(c)
+
+proc nodeToXml(n: PNode, indent: int = 0): string =
+  result = spaces(indent) & "<" & n.nodeName
+  if not isNil(n.attributes):
+    for i in items(n.attributes):
+      result.add(" " & i.name & "=\"" & addEscaped(i.value) & "\"")
+
+  if isNil(n.childNodes) or n.childNodes.len() == 0:
+    result.add("/>") # No idea why this doesn't need a \n :O
+  else:
+    # End the beginning of this tag
+    result.add(">\n")
+    for i in items(n.childNodes):
+      case i.nodeType
+      of ElementNode:
+        result.add(nodeToXml(i, indent + 2))
+      of TextNode:
+        result.add(spaces(indent * 2))
+        result.add(addEscaped(i.nodeValue))
+      of CDataSectionNode:
+        result.add(spaces(indent * 2))
+        result.add("<![CDATA[" & i.nodeValue & "]]>")
+      of ProcessingInstructionNode:
+        result.add(spaces(indent * 2))
+        result.add("<?" & PProcessingInstruction(i).target & " " &
+                          PProcessingInstruction(i).data & " ?>")
+      of CommentNode:
+        result.add(spaces(indent * 2))
+        result.add("<!-- " & i.nodeValue & " -->")
+      else:
+        continue
+      result.add("\n")
+    # Add the ending tag - </tag>
+    result.add(spaces(indent) & "</" & n.nodeName & ">")
+
+proc `$`*(doc: PDocument): string =
+  ## Converts a PDocument object into a string representation of it's XML
+  result = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+  result.add(nodeToXml(doc.documentElement))
diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim
new file mode 100644
index 000000000..050362435
--- /dev/null
+++ b/lib/pure/xmldomparser.nim
@@ -0,0 +1,168 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import xmldom, os, streams, parsexml, strutils
+
+## This module parses a XML Document into a XML DOM Document representation.
+
+#XMLDom's Parser - Turns XML into a Document
+
+type
+  # Parsing errors
+  EMismatchedTag* = object of ValueError ## Raised when a tag is not properly closed
+  EParserError* = object of ValueError ## Raised when an unexpected XML Parser event occurs
+
+  # For namespaces
+  XmlnsAttr = tuple[name, value: string, ownerElement: PElement]
+
+var nsList: seq[XmlnsAttr] = @[] # Used for storing namespaces
+
+proc getNS(prefix: string): string =
+  var defaultNS: seq[string] = @[]
+
+  for key, value, tag in items(nsList):
+    if ":" in key:
+      if key.split(':')[1] == prefix:
+        return value
+        
+    if key == "xmlns":
+      defaultNS.add(value)
+      
+  # Don't return the default namespaces
+  # in the loop, because then they would have a precedence
+  # over normal namespaces
+  if defaultNS.len() > 0:
+    return defaultNS[0] # Return the first found default namespace
+                        # if none are specified for this prefix
+    
+  return ""
+    
+proc parseText(x: var XmlParser, doc: var PDocument): PText =
+  result = doc.createTextNode(x.charData())
+
+proc parseElement(x: var XmlParser, doc: var PDocument): PElement =
+  var n = doc.createElement("")
+
+  while true:
+    case x.kind()
+    of xmlEof:
+      break
+    of xmlElementStart, xmlElementOpen:
+      if n.tagName() != "":
+        n.appendChild(parseElement(x, doc))
+      else:
+        n = doc.createElementNS("", x.elementName)
+        
+    of xmlElementEnd:
+      if x.elementName == n.nodeName:
+        # n.normalize() # Remove any whitespace etc.
+        
+        var ns: string
+        if x.elementName.contains(':'):
+          ns = getNS(x.elementName.split(':')[0])
+        else:
+          ns = getNS("")
+        
+        n.namespaceURI = ns
+        
+        # Remove any namespaces this element declared
+        var count = 0 # Variable which keeps the index
+                      # We need to edit it..
+        for i in low(nsList)..len(nsList)-1:
+          if nsList[count][2] == n:
+            nsList.delete(count)
+            dec(count)
+          inc(count)
+
+        return n
+      else: #The wrong element is ended
+        raise newException(EMismatchedTag, "Mismatched tag at line " & 
+          $x.getLine() & " column " & $x.getColumn)
+      
+    of xmlCharData:
+      n.appendChild(parseText(x, doc))
+    of xmlAttribute:
+      if x.attrKey == "xmlns" or x.attrKey.startsWith("xmlns:"):
+        nsList.add((x.attrKey, x.attrValue, n))
+        
+      if x.attrKey.contains(':'):
+        var ns = getNS(x.attrKey)
+        n.setAttributeNS(ns, x.attrKey, x.attrValue)
+      else:
+        n.setAttribute(x.attrKey, x.attrValue)
+
+    of xmlCData:
+      n.appendChild(doc.createCDATASection(x.charData()))
+    of xmlComment:
+      n.appendChild(doc.createComment(x.charData()))
+    of xmlPI:
+      n.appendChild(doc.createProcessingInstruction(x.piName(), x.piRest()))
+      
+    of xmlWhitespace, xmlElementClose, xmlEntity, xmlSpecial:
+      discard " Unused \'events\'"
+
+    else:
+      raise newException(EParserError, "Unexpected XML Parser event")
+    x.next()
+
+  raise newException(EMismatchedTag, 
+    "Mismatched tag at line " & $x.getLine() & " column " & $x.getColumn)
+
+proc loadXMLStream*(stream: Stream): PDocument =
+  ## Loads and parses XML from a stream specified by ``stream``, and returns 
+  ## a ``PDocument``
+
+  var x: XmlParser
+  open(x, stream, nil, {reportComments})
+  
+  var xmlDoc: PDocument
+  var dom: PDOMImplementation = getDOM()
+  
+  while true:
+    x.next()
+    case x.kind()
+    of xmlEof:
+      break
+    of xmlElementStart, xmlElementOpen:
+      var el: PElement = parseElement(x, xmlDoc)
+      xmlDoc = dom.createDocument(el)
+    of xmlWhitespace, xmlElementClose, xmlEntity, xmlSpecial:
+      discard " Unused \'events\'"
+    else:
+      raise newException(EParserError, "Unexpected XML Parser event")
+
+  return xmlDoc
+
+proc loadXML*(xml: string): PDocument =
+  ## Loads and parses XML from a string specified by ``xml``, and returns 
+  ## a ``PDocument``
+  var s = newStringStream(xml)
+  return loadXMLStream(s)
+  
+    
+proc loadXMLFile*(path: string): PDocument =
+  ## Loads and parses XML from a file specified by ``path``, and returns 
+  ## a ``PDocument``
+  
+  var s = newFileStream(path, fmRead)
+  if s == nil: raise newException(IOError, "Unable to read file " & path)
+  return loadXMLStream(s)
+
+
+when not defined(testing) and isMainModule:
+  var xml = loadXMLFile("nim/xmldom/test.xml")
+  #echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
+  #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
+  #echo(xml.getElementsByTagName("test")[0].namespaceURI)
+  for i in items(xml.getElementsByTagName("*")):
+    if i.namespaceURI != nil:
+      echo(i.nodeName, "=", i.namespaceURI)
+
+    
+  echo($xml)
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
new file mode 100644
index 000000000..840cae734
--- /dev/null
+++ b/lib/pure/xmlparser.nim
@@ -0,0 +1,159 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module parses an XML document and creates its XML tree representation.
+
+import streams, parsexml, strtabs, xmltree
+
+type
+  XmlError* = object of ValueError ## exception that is raised
+                                   ## for invalid XML
+    errors*: seq[string]           ## all detected parsing errors
+
+{.deprecated: [EInvalidXml: XmlError].}
+
+proc raiseInvalidXml(errors: seq[string]) = 
+  var e: ref XmlError
+  new(e)
+  e.msg = errors[0]
+  e.errors = errors
+  raise e
+
+proc addNode(father, son: XmlNode) = 
+  if son != nil: add(father, son)
+
+proc parse(x: var XmlParser, errors: var seq[string]): XmlNode
+
+proc untilElementEnd(x: var XmlParser, result: XmlNode, 
+                     errors: var seq[string]) =
+  while true:
+    case x.kind
+    of xmlElementEnd: 
+      if x.elementName == result.tag: 
+        next(x)
+      else:
+        errors.add(errorMsg(x, "</" & result.tag & "> expected"))
+        # do not skip it here!
+      break
+    of xmlEof:
+      errors.add(errorMsg(x, "</" & result.tag & "> expected"))
+      break
+    else:
+      result.addNode(parse(x, errors))
+
+proc parse(x: var XmlParser, errors: var seq[string]): XmlNode =
+  case x.kind
+  of xmlComment: 
+    result = newComment(x.charData)
+    next(x)
+  of xmlCharData, xmlWhitespace:
+    result = newText(x.charData)
+    next(x)
+  of xmlPI, xmlSpecial:
+    # we just ignore processing instructions for now
+    next(x)
+  of xmlError:
+    errors.add(errorMsg(x))
+    next(x)
+  of xmlElementStart:    ## ``<elem>``
+    result = newElement(x.elementName)
+    next(x)
+    untilElementEnd(x, result, errors)
+  of xmlElementEnd:
+    errors.add(errorMsg(x, "unexpected ending tag: " & x.elementName))
+  of xmlElementOpen: 
+    result = newElement(x.elementName)
+    next(x)
+    result.attrs = newStringTable()
+    while true: 
+      case x.kind
+      of xmlAttribute:
+        result.attrs[x.attrKey] = x.attrValue
+        next(x)
+      of xmlElementClose:
+        next(x)
+        break
+      of xmlError:
+        errors.add(errorMsg(x))
+        next(x)
+        break
+      else:
+        errors.add(errorMsg(x, "'>' expected"))
+        next(x)
+        break
+    untilElementEnd(x, result, errors)
+  of xmlAttribute, xmlElementClose:
+    errors.add(errorMsg(x, "<some_tag> expected"))
+    next(x)
+  of xmlCData: 
+    result = newCData(x.charData)
+    next(x)
+  of xmlEntity:
+    ## &entity;
+    errors.add(errorMsg(x, "unknown entity: " & x.entityName))
+    next(x)
+  of xmlEof: discard
+
+proc parseXml*(s: Stream, filename: string, 
+               errors: var seq[string]): XmlNode = 
+  ## parses the XML from stream `s` and returns a ``PXmlNode``. Every
+  ## occurred parsing error is added to the `errors` sequence.
+  var x: XmlParser
+  open(x, s, filename, {reportComments})
+  while true:
+    x.next()
+    case x.kind
+    of xmlElementOpen, xmlElementStart: 
+      result = parse(x, errors)
+      break
+    of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: discard # just skip it
+    of xmlError:
+      errors.add(errorMsg(x))
+    else:
+      errors.add(errorMsg(x, "<some_tag> expected"))
+      break
+  close(x)
+
+proc parseXml*(s: Stream): XmlNode = 
+  ## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing
+  ## errors are turned into an ``EInvalidXML`` exception.
+  var errors: seq[string] = @[]
+  result = parseXml(s, "unknown_html_doc", errors)
+  if errors.len > 0: raiseInvalidXml(errors)
+
+proc loadXml*(path: string, errors: var seq[string]): XmlNode =
+  ## Loads and parses XML from file specified by ``path``, and returns 
+  ## a ``PXmlNode``. Every occurred parsing error is added to the `errors`
+  ## sequence.
+  var s = newFileStream(path, fmRead)
+  if s == nil: raise newException(IOError, "Unable to read file: " & path)
+  result = parseXml(s, path, errors)
+
+proc loadXml*(path: string): XmlNode =
+  ## Loads and parses XML from file specified by ``path``, and returns 
+  ## a ``PXmlNode``.  All parsing errors are turned into an ``EInvalidXML``
+  ## exception.  
+  var errors: seq[string] = @[]
+  result = loadXml(path, errors)
+  if errors.len > 0: raiseInvalidXml(errors)
+
+when not defined(testing) and isMainModule:
+  import os
+
+  var errors: seq[string] = @[]  
+  var x = loadXml(paramStr(1), errors)
+  for e in items(errors): echo e
+  
+  var f: File
+  if open(f, "xmltest.txt", fmWrite):
+    f.write($x)
+    f.close()
+  else:
+    quit("cannot write test.txt")
+    
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
new file mode 100644
index 000000000..bbe3c05b7
--- /dev/null
+++ b/lib/pure/xmltree.nim
@@ -0,0 +1,357 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## A simple XML tree. More efficient and simpler than the DOM.
+
+import macros, strtabs
+
+type
+  XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s.
+
+  XmlNodeKind* = enum  ## different kinds of ``PXmlNode``'s
+    xnText,             ## a text element
+    xnElement,          ## an element with 0 or more children
+    xnCData,            ## a CDATA node
+    xnEntity,           ## an entity (like ``&thing;``)
+    xnComment           ## an XML comment
+
+  XmlAttributes* = StringTableRef ## an alias for a string to string mapping
+
+  XmlNodeObj {.acyclic.} = object
+    case k: XmlNodeKind # private, use the kind() proc to read this field.
+    of xnText, xnComment, xnCData, xnEntity:
+      fText: string
+    of xnElement:
+      fTag: string
+      s: seq[XmlNode]
+      fAttr: XmlAttributes
+    fClientData: int              ## for other clients
+
+{.deprecated: [PXmlNode: XmlNode, TXmlNodeKind: XmlNodeKind, PXmlAttributes:
+    XmlAttributes, TXmlNode: XmlNodeObj].}
+
+proc newXmlNode(kind: XmlNodeKind): XmlNode =
+  ## creates a new ``XmlNode``.
+  new(result)
+  result.k = kind
+
+proc newElement*(tag: string): XmlNode =
+  ## creates a new ``PXmlNode`` of kind ``xnText`` with the given `tag`.
+  result = newXmlNode(xnElement)
+  result.fTag = tag
+  result.s = @[]
+  # init attributes lazily to safe memory
+
+proc newText*(text: string): XmlNode =
+  ## creates a new ``PXmlNode`` of kind ``xnText`` with the text `text`.
+  result = newXmlNode(xnText)
+  result.fText = text
+
+proc newComment*(comment: string): XmlNode =
+  ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `comment`.
+  result = newXmlNode(xnComment)
+  result.fText = comment
+
+proc newCData*(cdata: string): XmlNode =
+  ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `cdata`.
+  result = newXmlNode(xnCData)
+  result.fText = cdata
+
+proc newEntity*(entity: string): XmlNode =
+  ## creates a new ``PXmlNode`` of kind ``xnEntity`` with the text `entity`.
+  result = newXmlNode(xnCData)
+  result.fText = entity
+
+proc text*(n: XmlNode): string {.inline.} =
+  ## gets the associated text with the node `n`. `n` can be a CDATA, Text,
+  ## comment, or entity node.
+  assert n.k in {xnText, xnComment, xnCData, xnEntity}
+  result = n.fText
+
+proc rawText*(n: XmlNode): string {.inline.} =
+  ## returns the underlying 'text' string by reference.
+  ## This is only used for speed hacks.
+  shallowCopy(result, n.fText)
+
+proc rawTag*(n: XmlNode): string {.inline.} =
+  ## returns the underlying 'tag' string by reference.
+  ## This is only used for speed hacks.
+  shallowCopy(result, n.fTag)
+
+proc innerText*(n: XmlNode): string =
+  ## gets the inner text of `n`. `n` has to be an ``xnElement`` node. Only
+  ## ``xnText`` and ``xnEntity`` nodes are considered part of `n`'s inner text,
+  ## other child nodes are silently ignored.
+  result = ""
+  assert n.k == xnElement
+  for i in 0 .. n.s.len-1:
+    if n.s[i].k in {xnText, xnEntity}: result.add(n.s[i].fText)
+
+proc tag*(n: XmlNode): string {.inline.} =
+  ## gets the tag name of `n`. `n` has to be an ``xnElement`` node.
+  assert n.k == xnElement
+  result = n.fTag
+
+proc add*(father, son: XmlNode) {.inline.} =
+  ## adds the child `son` to `father`.
+  add(father.s, son)
+
+proc len*(n: XmlNode): int {.inline.} =
+  ## returns the number `n`'s children.
+  if n.k == xnElement: result = len(n.s)
+
+proc kind*(n: XmlNode): XmlNodeKind {.inline.} =
+  ## returns `n`'s kind.
+  result = n.k
+
+proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} =
+  ## returns the `i`'th child of `n`.
+  assert n.k == xnElement
+  result = n.s[i]
+
+proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} =
+  ## returns the `i`'th child of `n` so that it can be modified
+  assert n.k == xnElement
+  result = n.s[i]
+
+iterator items*(n: XmlNode): XmlNode {.inline.} =
+  ## iterates over any child of `n`.
+  assert n.k == xnElement
+  for i in 0 .. n.len-1: yield n[i]
+
+iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
+  ## iterates over any child of `n`.
+  assert n.k == xnElement
+  for i in 0 .. n.len-1: yield mget(n, i)
+
+proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
+  ## gets the attributes belonging to `n`.
+  ## Returns `nil` if attributes have not been initialised for this node.
+  assert n.k == xnElement
+  result = n.fAttr
+
+proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} =
+  ## sets the attributes belonging to `n`.
+  assert n.k == xnElement
+  n.fAttr = attr
+
+proc attrsLen*(n: XmlNode): int {.inline.} =
+  ## returns the number of `n`'s attributes.
+  assert n.k == xnElement
+  if not isNil(n.fAttr): result = len(n.fAttr)
+
+proc clientData*(n: XmlNode): int {.inline.} =
+  ## gets the client data of `n`. The client data field is used by the HTML
+  ## parser and generator.
+  result = n.fClientData
+
+proc `clientData=`*(n: XmlNode, data: int) {.inline.} =
+  ## sets the client data of `n`. The client data field is used by the HTML
+  ## parser and generator.
+  n.fClientData = data
+
+proc addEscaped*(result: var string, s: string) =
+  ## same as ``result.add(escape(s))``, but more efficient.
+  for c in items(s):
+    case c
+    of '<': result.add("&lt;")
+    of '>': result.add("&gt;")
+    of '&': result.add("&amp;")
+    of '"': result.add("&quot;")
+    of '\'': result.add("&#x27;")
+    of '/': result.add("&#x2F;")
+    else: result.add(c)
+
+proc escape*(s: string): string =
+  ## escapes `s` for inclusion into an XML document.
+  ## Escapes these characters:
+  ##
+  ## ------------    -------------------
+  ## char            is converted to
+  ## ------------    -------------------
+  ##  ``<``          ``&lt;``
+  ##  ``>``          ``&gt;``
+  ##  ``&``          ``&amp;``
+  ##  ``"``          ``&quot;``
+  ##  ``'``          ``&#x27;``
+  ##  ``/``          ``&#x2F;``
+  ## ------------    -------------------
+  result = newStringOfCap(s.len)
+  addEscaped(result, s)
+
+proc addIndent(result: var string, indent: int) =
+  result.add("\n")
+  for i in 1..indent: result.add(' ')
+
+proc noWhitespace(n: XmlNode): bool =
+  #for i in 1..n.len-1:
+  #  if n[i].kind != n[0].kind: return true
+  for i in 0..n.len-1:
+    if n[i].kind in {xnText, xnEntity}: return true
+
+proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
+  ## adds the textual representation of `n` to `result`.
+  if n == nil: return
+  case n.k
+  of xnElement:
+    result.add('<')
+    result.add(n.fTag)
+    if not isNil(n.fAttr):
+      for key, val in pairs(n.fAttr):
+        result.add(' ')
+        result.add(key)
+        result.add("=\"")
+        result.addEscaped(val)
+        result.add('"')
+    if n.len > 0:
+      result.add('>')
+      if n.len > 1:
+        if noWhitespace(n):
+          # for mixed leaves, we cannot output whitespace for readability,
+          # because this would be wrong. For example: ``a<b>b</b>`` is
+          # different from ``a <b>b</b>``.
+          for i in 0..n.len-1: result.add(n[i], indent+indWidth, indWidth)
+        else:
+          for i in 0..n.len-1:
+            result.addIndent(indent+indWidth)
+            result.add(n[i], indent+indWidth, indWidth)
+          result.addIndent(indent)
+      else:
+        result.add(n[0], indent+indWidth, indWidth)
+      result.add("</")
+      result.add(n.fTag)
+      result.add(">")
+    else:
+      result.add(" />")
+  of xnText:
+    result.addEscaped(n.fText)
+  of xnComment:
+    result.add("<!-- ")
+    result.addEscaped(n.fText)
+    result.add(" -->")
+  of xnCData:
+    result.add("<![CDATA[")
+    result.add(n.fText)
+    result.add("]]>")
+  of xnEntity:
+    result.add('&')
+    result.add(n.fText)
+    result.add(';')
+
+const
+  xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+    ## header to use for complete XML output
+
+proc `$`*(n: XmlNode): string =
+  ## converts `n` into its string representation. No ``<$xml ...$>`` declaration
+  ## is produced, so that the produced XML fragments are composable.
+  result = ""
+  result.add(n)
+
+proc newXmlTree*(tag: string, children: openArray[XmlNode],
+                 attributes: XmlAttributes = nil): XmlNode =
+  ## creates a new XML tree with `tag`, `children` and `attributes`
+  result = newXmlNode(xnElement)
+  result.fTag = tag
+  newSeq(result.s, children.len)
+  for i in 0..children.len-1: result.s[i] = children[i]
+  result.fAttr = attributes
+
+proc xmlConstructor(e: NimNode): NimNode {.compileTime.} =
+  expectLen(e, 2)
+  var a = e[1]
+  if a.kind == nnkCall:
+    result = newCall("newXmlTree", toStrLit(a[0]))
+    var attrs = newNimNode(nnkBracket, a)
+    var newStringTabCall = newCall("newStringTable", attrs,
+                                   newIdentNode("modeCaseSensitive"))
+    var elements = newNimNode(nnkBracket, a)
+    for i in 1..a.len-1:
+      if a[i].kind == nnkExprEqExpr:
+        attrs.add(toStrLit(a[i][0]))
+        attrs.add(a[i][1])
+        #echo repr(attrs)
+      else:
+        elements.add(a[i])
+    result.add(elements)
+    if attrs.len > 1:
+      #echo repr(newStringTabCall)
+      result.add(newStringTabCall)
+  else:
+    result = newCall("newXmlTree", toStrLit(a))
+
+macro `<>`*(x: expr): expr {.immediate.} =
+  ## Constructor macro for XML. Example usage:
+  ##
+  ## .. code-block:: nim
+  ##   <>a(href="http://nim-lang.org", newText("Nim rules."))
+  ##
+  ## Produces an XML tree for::
+  ##
+  ##  <a href="http://nim-lang.org">Nim rules.</a>
+  ##
+  let x = callsite()
+  result = xmlConstructor(x)
+
+proc child*(n: XmlNode, name: string): XmlNode =
+  ## Finds the first child element of `n` with a name of `name`.
+  ## Returns `nil` on failure.
+  assert n.kind == xnElement
+  for i in items(n):
+    if i.kind == xnElement:
+      if i.tag == name:
+        return i
+
+proc attr*(n: XmlNode, name: string): string =
+  ## Finds the first attribute of `n` with a name of `name`.
+  ## Returns "" on failure.
+  assert n.kind == xnElement
+  if n.attrs == nil: return ""
+  return n.attrs[name]
+
+proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) =
+  ## Iterates over all the children of `n` returning those matching `tag`.
+  ##
+  ## Found nodes satisfying the condition will be appended to the `result`
+  ## sequence, which can't be nil or the proc will crash. Usage example:
+  ##
+  ## .. code-block::
+  ##   var
+  ##     html: XmlNode
+  ##     tags: seq[XmlNode] = @[]
+  ##
+  ##   html = buildHtml()
+  ##   findAll(html, "img", tags)
+  ##   for imgTag in tags:
+  ##     process(imgTag)
+  assert isNil(result) == false
+  assert n.k == xnElement
+  for child in n.items():
+    if child.k != xnElement:
+      continue
+    if child.tag == tag:
+      result.add(child)
+    child.findAll(tag, result)
+
+proc findAll*(n: XmlNode, tag: string): seq[XmlNode] =
+  ## Shortcut version to assign in let blocks. Example:
+  ##
+  ## .. code-block::
+  ##   var html: XmlNode
+  ##
+  ##   html = buildHtml(html)
+  ##   for imgTag in html.findAll("img"):
+  ##     process(imgTag)
+  newSeq(result, 0)
+  findAll(n, tag, result)
+
+when isMainModule:
+  let link = "http://nim-lang.org"
+  assert """<a href="""" & escape(link) & """">Nim rules.</a>""" ==
+    $(<>a(href="http://nim-lang.org", newText("Nim rules.")))
diff --git a/lib/stdlib.nimble b/lib/stdlib.nimble
new file mode 100644
index 000000000..0805ead54
--- /dev/null
+++ b/lib/stdlib.nimble
@@ -0,0 +1,6 @@
+[Package]
+name          = "stdlib"
+version       = "0.9.0"
+author        = "Dominik Picheta"
+description   = "Nim's standard library."
+license       = "MIT"
diff --git a/lib/system.nim b/lib/system.nim
new file mode 100644
index 000000000..a4b053ca7
--- /dev/null
+++ b/lib/system.nim
@@ -0,0 +1,3276 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## The compiler depends on the System module to work properly and the System
+## module depends on the compiler. Most of the routines listed here use
+## special compiler magic.
+## Each module implicitly imports the System module; it must not be listed
+## explicitly. Because of this there cannot be a user-defined module named
+## ``system``.
+##
+## Exception hierarchy
+## ===================
+##
+## For visual convenience here is the exception inheritance hierarchy
+## represented as a tree:
+##
+## .. include:: ../doc/exception_hierarchy_fragment.txt
+##
+## Module system
+## =============
+##
+
+# That lonesome header above is to prevent :idx: entries from being mentioned
+# in the global index as part of the previous header (Exception hierarchy).
+
+type
+  int* {.magic: Int.} ## default integer type; bitwidth depends on
+                      ## architecture, but is always the same as a pointer
+  int8* {.magic: Int8.} ## signed 8 bit integer type
+  int16* {.magic: Int16.} ## signed 16 bit integer type
+  int32* {.magic: Int32.} ## signed 32 bit integer type
+  int64* {.magic: Int64.} ## signed 64 bit integer type
+  uint* {.magic: UInt.} ## unsigned default integer type
+  uint8* {.magic: UInt8.} ## unsigned 8 bit integer type
+  uint16* {.magic: UInt16.} ## unsigned 16 bit integer type
+  uint32* {.magic: UInt32.} ## unsigned 32 bit integer type
+  uint64* {.magic: UInt64.} ## unsigned 64 bit integer type
+  float* {.magic: Float.} ## default floating point type
+  float32* {.magic: Float32.} ## 32 bit floating point type
+  float64* {.magic: Float.} ## 64 bit floating point type
+
+# 'float64' is now an alias to 'float'; this solves many problems
+
+type # we need to start a new type section here, so that ``0`` can have a type
+  bool* {.magic: Bool.} = enum ## built-in boolean type
+    false = 0, true = 1
+
+type
+  char* {.magic: Char.} ## built-in 8 bit character type (unsigned)
+  string* {.magic: String.} ## built-in string type
+  cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type
+  pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr``
+                              ## operator to get a pointer to a variable
+const
+  on* = true    ## alias for ``true``
+  off* = false  ## alias for ``false``
+
+{.push warning[GcMem]: off, warning[Uninit]: off.}
+{.push hints: off.}
+
+type
+  Ordinal* {.magic: Ordinal.}[T]
+  `ptr`* {.magic: Pointer.}[T] ## built-in generic untraced pointer type
+  `ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type
+
+  `nil` {.magic: "Nil".}
+  expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
+  stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
+  typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
+  void* {.magic: "VoidType".}   ## meta type to denote the absence of any type
+  auto* = expr
+  any* = distinct auto
+  untyped* {.magic: Expr.} ## meta type to denote an expression that
+                           ## is not resolved (for templates)
+  typed* {.magic: Stmt.}   ## meta type to denote an expression that
+                           ## is resolved (for templates)
+
+  SomeSignedInt* = int|int8|int16|int32|int64
+    ## type class matching all signed integer types
+
+  SomeUnsignedInt* = uint|uint8|uint16|uint32|uint64
+    ## type class matching all unsigned integer types
+
+  SomeInteger* = SomeSignedInt|SomeUnsignedInt
+    ## type class matching all integer types
+
+  SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
+    ## type class matching all ordinal types; however this includes enums with
+    ## holes.
+
+  SomeReal* = float|float32|float64
+    ## type class matching all floating point number types
+
+  SomeNumber* = SomeInteger|SomeReal
+    ## type class matching all number types
+
+proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
+  ## Special compile-time procedure that checks whether `x` is
+  ## defined.
+  ## `x` is an external symbol introduced through the compiler's
+  ## `-d:x switch <nimc.html#compile-time-symbols>`_ to enable build time
+  ## conditionals:
+  ##
+  ## .. code-block:: Nim
+  ##   when not defined(release):
+  ##     # Do here programmer friendly expensive sanity checks.
+  ##   # Put here the normal code
+
+when defined(nimalias):
+  {.deprecated: [
+    TSignedInt: SomeSignedInt,
+    TUnsignedInt: SomeUnsignedInt,
+    TInteger: SomeInteger,
+    TReal: SomeReal,
+    TNumber: SomeNumber,
+    TOrdinal: SomeOrdinal].}
+
+proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.}
+  ## Special compile-time procedure that checks whether `x` is
+  ## declared. `x` has to be an identifier or a qualified identifier.
+  ## This can be used to check whether a library provides a certain
+  ## feature or not:
+  ##
+  ## .. code-block:: Nim
+  ##   when not declared(strutils.toUpper):
+  ##     # provide our own toUpper proc here, because strutils is
+  ##     # missing it.
+
+when defined(useNimRtl):
+  {.deadCodeElim: on.}
+
+proc definedInScope*(x: expr): bool {.
+  magic: "DefinedInScope", noSideEffect, deprecated.}
+  ## **Deprecated since version 0.9.6**: Use ``declaredInScope`` instead.
+
+proc declaredInScope*(x: expr): bool {.
+  magic: "DefinedInScope", noSideEffect.}
+  ## Special compile-time procedure that checks whether `x` is
+  ## declared in the current scope. `x` has to be an identifier.
+
+proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
+  ## Builtin 'addr' operator for taking the address of a memory location.
+  ## Cannot be overloaded.
+  discard
+
+proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} =
+  ## Builtin 'type' operator for accessing the type of an expression.
+  ## Cannot be overloaded.
+  discard
+
+proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.}
+  ## Boolean not; returns true iff ``x == false``.
+
+proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.}
+  ## Boolean ``and``; returns true iff ``x == y == true``.
+  ## Evaluation is lazy: if ``x`` is false,
+  ## ``y`` will not even be evaluated.
+proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
+  ## Boolean ``or``; returns true iff ``not (not x and not y)``.
+  ## Evaluation is lazy: if ``x`` is true,
+  ## ``y`` will not even be evaluated.
+proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
+  ## Boolean `exclusive or`; returns true iff ``x != y``.
+
+proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``.
+
+proc new*(T: typedesc): ref T =
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it as result value
+  new(result)
+
+proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
+  ## leaked implementation detail. Do not use.
+
+proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {.
+  magic: "NewFinalize", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``. When the garbage collector frees the object,
+  ## `finalizer` is called. The `finalizer` may not keep a reference to the
+  ## object pointed to by `x`. The `finalizer` cannot prevent the GC from
+  ## freeing the object. Note: The `finalizer` refers to the type `T`, not to
+  ## the object! This means that for each object of type `T` the finalizer
+  ## will be called!
+
+proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
+  ## resets an object `obj` to its initial (binary zero) value. This needs to
+  ## be called before any possible `object branch transition`:idx:.
+
+# for low and high the return type T may not be correct, but
+# we handle that with compiler magic in semLowHigh()
+proc high*[T](x: T): T {.magic: "High", noSideEffect.}
+  ## returns the highest possible index of an array, a sequence, a string or
+  ## the highest possible value of an ordinal value `x`. As a special
+  ## semantic rule, `x` may also be a type identifier.
+  ## ``high(int)`` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:.
+
+proc low*[T](x: T): T {.magic: "Low", noSideEffect.}
+  ## returns the lowest possible index of an array, a sequence, a string or
+  ## the lowest possible value of an ordinal value `x`. As a special
+  ## semantic rule, `x` may also be a type identifier.
+
+type
+  range*{.magic: "Range".}[T] ## Generic type to construct range types.
+  array*{.magic: "Array".}[I, T]  ## Generic type to construct
+                                  ## fixed-length arrays.
+  openArray*{.magic: "OpenArray".}[T]  ## Generic type to construct open arrays.
+                                       ## Open arrays are implemented as a
+                                       ## pointer to the array data and a
+                                       ## length field.
+  varargs*{.magic: "Varargs".}[T] ## Generic type to construct a varargs type.
+  seq*{.magic: "Seq".}[T]  ## Generic type to construct sequences.
+  set*{.magic: "Set".}[T]  ## Generic type to construct bit sets.
+
+type
+  Slice*[T] = object ## builtin slice type
+    a*, b*: T        ## the bounds
+
+when defined(nimalias):
+  {.deprecated: [TSlice: Slice].}
+
+proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
+  ## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a`
+  ## and `b` are inclusive. Slices can also be used in the set constructor
+  ## and in ordinal case statements, but then they are special-cased by the
+  ## compiler.
+  result.a = a
+  result.b = b
+
+proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} =
+  ## `slice`:idx: operator that constructs an interval ``[default(T), b]``
+  result.b = b
+
+when not defined(niminheritable):
+  {.pragma: inheritable.}
+when not defined(nimunion):
+  {.pragma: unchecked.}
+
+when defined(nimNewShared):
+  type
+    `shared`* {.magic: "Shared".}
+    guarded* {.magic: "Guarded".}
+
+# comparison operators:
+proc `==` *[TEnum: enum](x, y: TEnum): bool {.magic: "EqEnum", noSideEffect.}
+proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.}
+proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.}
+proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.}
+proc `==` *(x, y: char): bool {.magic: "EqCh", noSideEffect.}
+proc `==` *(x, y: bool): bool {.magic: "EqB", noSideEffect.}
+proc `==` *[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.}
+proc `==` *[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.}
+proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.}
+proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.}
+
+proc `<=` *[TEnum: enum](x, y: TEnum): bool {.magic: "LeEnum", noSideEffect.}
+proc `<=` *(x, y: string): bool {.magic: "LeStr", noSideEffect.}
+proc `<=` *(x, y: char): bool {.magic: "LeCh", noSideEffect.}
+proc `<=` *[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.}
+proc `<=` *(x, y: bool): bool {.magic: "LeB", noSideEffect.}
+proc `<=` *[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.}
+proc `<=` *(x, y: pointer): bool {.magic: "LePtr", noSideEffect.}
+
+proc `<` *[TEnum: enum](x, y: TEnum): bool {.magic: "LtEnum", noSideEffect.}
+proc `<` *(x, y: string): bool {.magic: "LtStr", noSideEffect.}
+proc `<` *(x, y: char): bool {.magic: "LtCh", noSideEffect.}
+proc `<` *[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.}
+proc `<` *(x, y: bool): bool {.magic: "LtB", noSideEffect.}
+proc `<` *[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.}
+proc `<` *[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.}
+proc `<` *(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.}
+
+template `!=` * (x, y: expr): expr {.immediate.} =
+  ## unequals operator. This is a shorthand for ``not (x == y)``.
+  not (x == y)
+
+template `>=` * (x, y: expr): expr {.immediate.} =
+  ## "is greater or equals" operator. This is the same as ``y <= x``.
+  y <= x
+
+template `>` * (x, y: expr): expr {.immediate.} =
+  ## "is greater" operator. This is the same as ``y < x``.
+  y < x
+
+const
+  appType* {.magic: "AppType"}: string = ""
+    ## a string that describes the application type. Possible values:
+    ## "console", "gui", "lib".
+
+include "system/inclrtl"
+
+const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
+  ## "fake variables" like 'var EBADF {.importc.}: cint'.
+
+const ArrayDummySize = when defined(cpu16): 10_000 else: 100_000_000
+
+when not defined(JS):
+  type
+    TGenericSeq {.compilerproc, pure, inheritable.} = object
+      len, reserved: int
+    PGenericSeq {.exportc.} = ptr TGenericSeq
+    UncheckedCharArray {.unchecked.} = array[0..ArrayDummySize, char]
+    # len and space without counting the terminating zero:
+    NimStringDesc {.compilerproc, final.} = object of TGenericSeq
+      data: UncheckedCharArray
+    NimString = ptr NimStringDesc
+
+when not defined(JS) and not defined(NimrodVM):
+  template space(s: PGenericSeq): int {.dirty.} =
+    s.reserved and not seqShallowFlag
+
+  include "system/hti"
+
+type
+  byte* = uint8 ## this is an alias for ``uint8``, that is an unsigned
+                ## int 8 bits wide.
+
+  Natural* = range[0..high(int)]
+    ## is an int type ranging from zero to the maximum value
+    ## of an int. This type is often useful for documentation and debugging.
+
+  Positive* = range[1..high(int)]
+    ## is an int type ranging from one to the maximum value
+    ## of an int. This type is often useful for documentation and debugging.
+
+  RootObj* {.exportc: "TNimObject", inheritable.} =
+    object ## the root of Nim's object hierarchy. Objects should
+           ## inherit from TObject or one of its descendants. However,
+           ## objects that have no ancestor are allowed.
+  RootRef* = ref RootObj ## reference to RootObj
+
+  RootEffect* {.compilerproc.} = object of RootObj ## \
+    ## base effect class; each effect should
+    ## inherit from `TEffect` unless you know what
+    ## you doing.
+  TimeEffect* = object of RootEffect   ## Time effect.
+  IOEffect* = object of RootEffect     ## IO effect.
+  ReadIOEffect* = object of IOEffect   ## Effect describing a read IO operation.
+  WriteIOEffect* = object of IOEffect  ## Effect describing a write IO operation.
+  ExecIOEffect* = object of IOEffect   ## Effect describing an executing IO operation.
+
+  Exception* {.compilerproc.} = object of RootObj ## \
+    ## Base exception class.
+    ##
+    ## Each exception has to inherit from `Exception`. See the full `exception
+    ## hierarchy`_.
+    parent*: ref Exception ## parent exception (can be used as a stack)
+    name: cstring ## The exception's name is its Nim identifier.
+                  ## This field is filled automatically in the
+                  ## ``raise`` statement.
+    msg* {.exportc: "message".}: string ## the exception's message. Not
+                                        ## providing an exception message
+                                        ## is bad style.
+    trace: string
+
+  SystemError* = object of Exception ## \
+    ## Abstract class for exceptions that the runtime system raises.
+    ##
+    ## See the full `exception hierarchy`_.
+  IOError* = object of SystemError ## \
+    ## Raised if an IO error occurred.
+    ##
+    ## See the full `exception hierarchy`_.
+  OSError* = object of SystemError ## \
+    ## Raised if an operating system service failed.
+    ##
+    ## See the full `exception hierarchy`_.
+    errorCode*: int32 ## OS-defined error code describing this error.
+  LibraryError* = object of OSError ## \
+    ## Raised if a dynamic library could not be loaded.
+    ##
+    ## See the full `exception hierarchy`_.
+  ResourceExhaustedError* = object of SystemError ## \
+    ## Raised if a resource request could not be fulfilled.
+    ##
+    ## See the full `exception hierarchy`_.
+  ArithmeticError* = object of Exception ## \
+    ## Raised if any kind of arithmetic error occurred.
+    ##
+    ## See the full `exception hierarchy`_.
+  DivByZeroError* = object of ArithmeticError ## \
+    ## Raised for runtime integer divide-by-zero errors.
+    ##
+    ## See the full `exception hierarchy`_.
+
+  OverflowError* = object of ArithmeticError ## \
+    ## Raised for runtime integer overflows.
+    ##
+    ## This happens for calculations whose results are too large to fit in the
+    ## provided bits.  See the full `exception hierarchy`_.
+  AccessViolationError* = object of Exception ## \
+    ## Raised for invalid memory access errors
+    ##
+    ## See the full `exception hierarchy`_.
+  AssertionError* = object of Exception ## \
+    ## Raised when assertion is proved wrong.
+    ##
+    ## Usually the result of using the `assert() template <#assert>`_.  See the
+    ## full `exception hierarchy`_.
+  ValueError* = object of Exception ## \
+    ## Raised for string and object conversion errors.
+  KeyError* = object of ValueError ## \
+    ## Raised if a key cannot be found in a table.
+    ##
+    ## Mostly used by the `tables <tables.html>`_ module, it can also be raised
+    ## by other collection modules like `sets <sets.html>`_ or `strtabs
+    ## <strtabs.html>`_. See the full `exception hierarchy`_.
+  OutOfMemError* = object of SystemError ## \
+    ## Raised for unsuccessful attempts to allocate memory.
+    ##
+    ## See the full `exception hierarchy`_.
+  IndexError* = object of Exception ## \
+    ## Raised if an array index is out of bounds.
+    ##
+    ## See the full `exception hierarchy`_.
+
+  FieldError* = object of Exception ## \
+    ## Raised if a record field is not accessible because its dicriminant's
+    ## value does not fit.
+    ##
+    ## See the full `exception hierarchy`_.
+  RangeError* = object of Exception ## \
+    ## Raised if a range check error occurred.
+    ##
+    ## See the full `exception hierarchy`_.
+  StackOverflowError* = object of SystemError ## \
+    ## Raised if the hardware stack used for subroutine calls overflowed.
+    ##
+    ## See the full `exception hierarchy`_.
+  ReraiseError* = object of Exception ## \
+    ## Raised if there is no exception to reraise.
+    ##
+    ## See the full `exception hierarchy`_.
+  ObjectAssignmentError* = object of Exception ## \
+    ## Raised if an object gets assigned to its parent's object.
+    ##
+    ## See the full `exception hierarchy`_.
+  ObjectConversionError* = object of Exception ## \
+    ## Raised if an object is converted to an incompatible object type.
+    ##
+    ## See the full `exception hierarchy`_.
+  FloatingPointError* = object of Exception ## \
+    ## Base class for floating point exceptions.
+    ##
+    ## See the full `exception hierarchy`_.
+  FloatInvalidOpError* = object of FloatingPointError ## \
+    ## Raised by invalid operations according to IEEE.
+    ##
+    ## Raised by ``0.0/0.0``, for example.  See the full `exception
+    ## hierarchy`_.
+  FloatDivByZeroError* = object of FloatingPointError ## \
+    ## Raised by division by zero.
+    ##
+    ## Divisor is zero and dividend is a finite nonzero number.  See the full
+    ## `exception hierarchy`_.
+  FloatOverflowError* = object of FloatingPointError ## \
+    ## Raised for overflows.
+    ##
+    ## The operation produced a result that exceeds the range of the exponent.
+    ## See the full `exception hierarchy`_.
+  FloatUnderflowError* = object of FloatingPointError ## \
+    ## Raised for underflows.
+    ##
+    ## The operation produced a result that is too small to be represented as a
+    ## normal number. See the full `exception hierarchy`_.
+  FloatInexactError* = object of FloatingPointError ## \
+    ## Raised for inexact results.
+    ##
+    ## The operation produced a result that cannot be represented with infinite
+    ## precision -- for example: ``2.0 / 3.0, log(1.1)``
+    ##
+    ## **NOTE**: Nim currently does not detect these!  See the full
+    ## `exception hierarchy`_.
+  DeadThreadError* = object of Exception ## \
+    ## Raised if it is attempted to send a message to a dead thread.
+    ##
+    ## See the full `exception hierarchy`_.
+
+  TResult* {.deprecated.} = enum Failure, Success
+
+{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect,
+  FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect,
+  FWriteIO: WriteIOEffect, FExecIO: ExecIOEffect,
+
+  E_Base: Exception, ESystem: SystemError, EIO: IOError,
+  EOS: OSError, EInvalidLibrary: LibraryError,
+  EResourceExhausted: ResourceExhaustedError,
+  EArithmetic: ArithmeticError, EDivByZero: DivByZeroError,
+  EOverflow: OverflowError, EAccessViolation: AccessViolationError,
+  EAssertionFailed: AssertionError, EInvalidValue: ValueError,
+  EInvalidKey: KeyError, EOutOfMemory: OutOfMemError,
+  EInvalidIndex: IndexError, EInvalidField: FieldError,
+  EOutOfRange: RangeError, EStackOverflow: StackOverflowError,
+  ENoExceptionToReraise: ReraiseError,
+  EInvalidObjectAssignment: ObjectAssignmentError,
+  EInvalidObjectConversion: ObjectConversionError,
+  EDeadThread: DeadThreadError,
+  EFloatInexact: FloatInexactError,
+  EFloatUnderflow: FloatUnderflowError,
+  EFloatingPoint: FloatingPointError,
+  EFloatInvalidOp: FloatInvalidOpError,
+  EFloatDivByZero: FloatDivByZeroError,
+  EFloatOverflow: FloatOverflowError,
+  ESynch: Exception
+].}
+
+proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``. This is **unsafe** as it allocates an object
+  ## of the passed ``size``. This should only be used for optimization
+  ## purposes when you know what you're doing!
+
+proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.}
+  ## returns the size of ``x`` in bytes. Since this is a low-level proc,
+  ## its usage is discouraged - using ``new`` for the most cases suffices
+  ## that one never needs to know ``x``'s size. As a special semantic rule,
+  ## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
+
+proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
+  ## unary ``<`` that can be used for nice looking excluding ranges:
+  ##
+  ## .. code-block:: nim
+  ##   for i in 0 .. <10: echo i
+  ##
+  ## Semantically this is the same as ``pred``.
+
+proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
+  ## returns the ``y``-th successor of the value ``x``. ``T`` has to be
+  ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
+  ## or a compile time error occurs.
+
+proc pred*[T](x: Ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.}
+  ## returns the ``y``-th predecessor of the value ``x``. ``T`` has to be
+  ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
+  ## or a compile time error occurs.
+
+proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.}
+  ## increments the ordinal ``x`` by ``y``. If such a value does not
+  ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
+  ## short notation for: ``x = succ(x, y)``.
+
+proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.}
+  ## decrements the ordinal ``x`` by ``y``. If such a value does not
+  ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
+  ## short notation for: ``x = pred(x, y)``.
+
+proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.}
+  ## creates a new sequence of type ``seq[T]`` with length ``len``.
+  ## This is equivalent to ``s = @[]; setlen(s, len)``, but more
+  ## efficient since no reallocation is needed.
+  ##
+  ## Note that the sequence will be filled with zeroed entries, which can be a
+  ## problem for sequences containing strings since their value will be
+  ## ``nil``. After the creation of the sequence you should assign entries to
+  ## the sequence instead of adding them. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var inputStrings : seq[string]
+  ##   newSeq(inputStrings, 3)
+  ##   inputStrings[0] = "The fourth"
+  ##   inputStrings[1] = "assignment"
+  ##   inputStrings[2] = "would crash"
+  ##   #inputStrings[3] = "out of bounds"
+
+proc newSeq*[T](len = 0.Natural): seq[T] =
+  ## creates a new sequence of type ``seq[T]`` with length ``len``.
+  ##
+  ## Note that the sequence will be filled with zeroed entries, which can be a
+  ## problem for sequences containing strings since their value will be
+  ## ``nil``. After the creation of the sequence you should assign entries to
+  ## the sequence instead of adding them. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var inputStrings = newSeq[string](3)
+  ##   inputStrings[0] = "The fourth"
+  ##   inputStrings[1] = "assignment"
+  ##   inputStrings[2] = "would crash"
+  ##   #inputStrings[3] = "out of bounds"
+  newSeq(result, len)
+
+proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.
+  magic: "LengthOpenArray", noSideEffect.}
+proc len*(x: string): int {.magic: "LengthStr", noSideEffect.}
+proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.}
+proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.}
+proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
+  ## returns the length of an array, an openarray, a sequence or a string.
+  ## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is
+  ## always an int.
+
+# set routines:
+proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.}
+  ## includes element ``y`` to the set ``x``. This is the same as
+  ## ``x = x + {y}``, but it might be more efficient.
+
+template incl*[T](s: var set[T], flags: set[T]) =
+  ## includes the set of flags to the set ``x``.
+  s = s + flags
+
+proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.}
+  ## excludes element ``y`` to the set ``x``. This is the same as
+  ## ``x = x - {y}``, but it might be more efficient.
+
+template excl*[T](s: var set[T], flags: set[T]) =
+  ## excludes the set of flags to ``x``.
+  s = s - flags
+
+proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.}
+  ## returns the cardinality of the set ``x``, i.e. the number of elements
+  ## in the set.
+
+proc ord*[T](x: T): int {.magic: "Ord", noSideEffect.}
+  ## returns the internal int value of an ordinal value ``x``.
+
+proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.}
+  ## converts an int in the range 0..255 to a character.
+
+# --------------------------------------------------------------------------
+# built-in operators
+
+when not defined(JS):
+  proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
+    ## zero extends a smaller integer type to ``int``. This treats `x` as
+    ## unsigned.
+  proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
+    ## zero extends a smaller integer type to ``int``. This treats `x` as
+    ## unsigned.
+
+  proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned.
+  proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned.
+
+  proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned.
+  proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
+    ## zero extends a smaller integer type to ``int64``. This treats `x` as
+    ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
+    ## (This is the case on 64 bit processors.)
+
+  proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
+    ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
+    ## from `x`.
+  proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
+    ## treats `x` as unsigned and converts it to an ``int16`` by taking the last
+    ## 16 bits from `x`.
+  proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
+    ## treats `x` as unsigned and converts it to an ``int32`` by taking the
+    ## last 32 bits from `x`.
+
+# integer calculations:
+proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
+proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.}
+proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.}
+proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.}
+proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.}
+  ## Unary `+` operator for an integer. Has no effect.
+
+proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.}
+proc `-` *(x: int8): int8 {.magic: "UnaryMinusI", noSideEffect.}
+proc `-` *(x: int16): int16 {.magic: "UnaryMinusI", noSideEffect.}
+proc `-` *(x: int32): int32 {.magic: "UnaryMinusI", noSideEffect.}
+proc `-` *(x: int64): int64 {.magic: "UnaryMinusI64", noSideEffect.}
+  ## Unary `-` operator for an integer. Negates `x`.
+
+proc `not` *(x: int): int {.magic: "BitnotI", noSideEffect.}
+proc `not` *(x: int8): int8 {.magic: "BitnotI", noSideEffect.}
+proc `not` *(x: int16): int16 {.magic: "BitnotI", noSideEffect.}
+proc `not` *(x: int32): int32 {.magic: "BitnotI", noSideEffect.}
+proc `not` *(x: int64): int64 {.magic: "BitnotI64", noSideEffect.}
+  ## computes the `bitwise complement` of the integer `x`.
+
+proc `+` *(x, y: int): int {.magic: "AddI", noSideEffect.}
+proc `+` *(x, y: int8): int8 {.magic: "AddI", noSideEffect.}
+proc `+` *(x, y: int16): int16 {.magic: "AddI", noSideEffect.}
+proc `+` *(x, y: int32): int32 {.magic: "AddI", noSideEffect.}
+proc `+` *(x, y: int64): int64 {.magic: "AddI64", noSideEffect.}
+  ## Binary `+` operator for an integer.
+
+proc `-` *(x, y: int): int {.magic: "SubI", noSideEffect.}
+proc `-` *(x, y: int8): int8 {.magic: "SubI", noSideEffect.}
+proc `-` *(x, y: int16): int16 {.magic: "SubI", noSideEffect.}
+proc `-` *(x, y: int32): int32 {.magic: "SubI", noSideEffect.}
+proc `-` *(x, y: int64): int64 {.magic: "SubI64", noSideEffect.}
+  ## Binary `-` operator for an integer.
+
+proc `*` *(x, y: int): int {.magic: "MulI", noSideEffect.}
+proc `*` *(x, y: int8): int8 {.magic: "MulI", noSideEffect.}
+proc `*` *(x, y: int16): int16 {.magic: "MulI", noSideEffect.}
+proc `*` *(x, y: int32): int32 {.magic: "MulI", noSideEffect.}
+proc `*` *(x, y: int64): int64 {.magic: "MulI64", noSideEffect.}
+  ## Binary `*` operator for an integer.
+
+proc `div` *(x, y: int): int {.magic: "DivI", noSideEffect.}
+proc `div` *(x, y: int8): int8 {.magic: "DivI", noSideEffect.}
+proc `div` *(x, y: int16): int16 {.magic: "DivI", noSideEffect.}
+proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
+proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.}
+  ## computes the integer division. This is roughly the same as
+  ## ``floor(x/y)``.
+  ##
+  ## .. code-block:: Nim
+  ##   1 div 2 == 0
+  ##   2 div 2 == 1
+  ##   3 div 2 == 1
+
+proc `mod` *(x, y: int): int {.magic: "ModI", noSideEffect.}
+proc `mod` *(x, y: int8): int8 {.magic: "ModI", noSideEffect.}
+proc `mod` *(x, y: int16): int16 {.magic: "ModI", noSideEffect.}
+proc `mod` *(x, y: int32): int32 {.magic: "ModI", noSideEffect.}
+proc `mod` *(x, y: int64): int64 {.magic: "ModI64", noSideEffect.}
+  ## computes the integer modulo operation. This is the same as
+  ## ``x - (x div y) * y``.
+
+proc `shr` *(x, y: int): int {.magic: "ShrI", noSideEffect.}
+proc `shr` *(x, y: int8): int8 {.magic: "ShrI", noSideEffect.}
+proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.}
+proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.}
+proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.}
+  ## computes the `shift right` operation of `x` and `y`.
+  ##
+  ## .. code-block:: Nim
+  ##   0b0001_0000'i8 shr 2 == 0b0100_0000'i8
+  ##   0b1000_0000'i8 shr 2 == 0b0000_0000'i8
+  ##   0b0000_0001'i8 shr 9 == 0b0000_0000'i8
+
+proc `shl` *(x, y: int): int {.magic: "ShlI", noSideEffect.}
+proc `shl` *(x, y: int8): int8 {.magic: "ShlI", noSideEffect.}
+proc `shl` *(x, y: int16): int16 {.magic: "ShlI", noSideEffect.}
+proc `shl` *(x, y: int32): int32 {.magic: "ShlI", noSideEffect.}
+proc `shl` *(x, y: int64): int64 {.magic: "ShlI64", noSideEffect.}
+  ## computes the `shift left` operation of `x` and `y`.
+
+proc `and` *(x, y: int): int {.magic: "BitandI", noSideEffect.}
+proc `and` *(x, y: int8): int8 {.magic: "BitandI", noSideEffect.}
+proc `and` *(x, y: int16): int16 {.magic: "BitandI", noSideEffect.}
+proc `and` *(x, y: int32): int32 {.magic: "BitandI", noSideEffect.}
+proc `and` *(x, y: int64): int64 {.magic: "BitandI64", noSideEffect.}
+  ## computes the `bitwise and` of numbers `x` and `y`.
+
+proc `or` *(x, y: int): int {.magic: "BitorI", noSideEffect.}
+proc `or` *(x, y: int8): int8 {.magic: "BitorI", noSideEffect.}
+proc `or` *(x, y: int16): int16 {.magic: "BitorI", noSideEffect.}
+proc `or` *(x, y: int32): int32 {.magic: "BitorI", noSideEffect.}
+proc `or` *(x, y: int64): int64 {.magic: "BitorI64", noSideEffect.}
+  ## computes the `bitwise or` of numbers `x` and `y`.
+
+proc `xor` *(x, y: int): int {.magic: "BitxorI", noSideEffect.}
+proc `xor` *(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.}
+proc `xor` *(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.}
+proc `xor` *(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.}
+proc `xor` *(x, y: int64): int64 {.magic: "BitxorI64", noSideEffect.}
+  ## computes the `bitwise xor` of numbers `x` and `y`.
+
+proc `==` *(x, y: int): bool {.magic: "EqI", noSideEffect.}
+proc `==` *(x, y: int8): bool {.magic: "EqI", noSideEffect.}
+proc `==` *(x, y: int16): bool {.magic: "EqI", noSideEffect.}
+proc `==` *(x, y: int32): bool {.magic: "EqI", noSideEffect.}
+proc `==` *(x, y: int64): bool {.magic: "EqI64", noSideEffect.}
+  ## Compares two integers for equality.
+
+proc `<=` *(x, y: int): bool {.magic: "LeI", noSideEffect.}
+proc `<=` *(x, y: int8): bool {.magic: "LeI", noSideEffect.}
+proc `<=` *(x, y: int16): bool {.magic: "LeI", noSideEffect.}
+proc `<=` *(x, y: int32): bool {.magic: "LeI", noSideEffect.}
+proc `<=` *(x, y: int64): bool {.magic: "LeI64", noSideEffect.}
+  ## Returns true iff `x` is less than or equal to `y`.
+
+proc `<` *(x, y: int): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int8): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int16): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int32): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int64): bool {.magic: "LtI64", noSideEffect.}
+  ## Returns true iff `x` is less than `y`.
+
+type
+  IntMax32 = int|int8|int16|int32
+
+proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
+proc `+%` *(x, y: int64): int64 {.magic: "AddU", noSideEffect.}
+  ## treats `x` and `y` as unsigned and adds them. The result is truncated to
+  ## fit into the result. This implements modulo arithmetic. No overflow
+  ## errors are possible.
+
+proc `-%` *(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.}
+proc `-%` *(x, y: int64): int64 {.magic: "SubU", noSideEffect.}
+  ## treats `x` and `y` as unsigned and subtracts them. The result is
+  ## truncated to fit into the result. This implements modulo arithmetic.
+  ## No overflow errors are possible.
+
+proc `*%` *(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.}
+proc `*%` *(x, y: int64): int64 {.magic: "MulU", noSideEffect.}
+  ## treats `x` and `y` as unsigned and multiplies them. The result is
+  ## truncated to fit into the result. This implements modulo arithmetic.
+  ## No overflow errors are possible.
+
+proc `/%` *(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.}
+proc `/%` *(x, y: int64): int64 {.magic: "DivU", noSideEffect.}
+  ## treats `x` and `y` as unsigned and divides them. The result is
+  ## truncated to fit into the result. This implements modulo arithmetic.
+  ## No overflow errors are possible.
+
+proc `%%` *(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.}
+proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
+  ## treats `x` and `y` as unsigned and compute the modulo of `x` and `y`.
+  ## The result is truncated to fit into the result.
+  ## This implements modulo arithmetic.
+  ## No overflow errors are possible.
+
+proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
+proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
+  ## treats `x` and `y` as unsigned and compares them.
+  ## Returns true iff ``unsigned(x) <= unsigned(y)``.
+
+proc `<%` *(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.}
+proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.}
+  ## treats `x` and `y` as unsigned and compares them.
+  ## Returns true iff ``unsigned(x) < unsigned(y)``.
+
+
+# floating point operations:
+
+proc `+` *(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.}
+proc `-` *(x: float32): float32 {.magic: "UnaryMinusF64", noSideEffect.}
+proc `+` *(x, y: float32): float32 {.magic: "AddF64", noSideEffect.}
+proc `-` *(x, y: float32): float32 {.magic: "SubF64", noSideEffect.}
+proc `*` *(x, y: float32): float32 {.magic: "MulF64", noSideEffect.}
+proc `/` *(x, y: float32): float32 {.magic: "DivF64", noSideEffect.}
+
+proc `+` *(x: float): float {.magic: "UnaryPlusF64", noSideEffect.}
+proc `-` *(x: float): float {.magic: "UnaryMinusF64", noSideEffect.}
+proc `+` *(x, y: float): float {.magic: "AddF64", noSideEffect.}
+proc `-` *(x, y: float): float {.magic: "SubF64", noSideEffect.}
+proc `*` *(x, y: float): float {.magic: "MulF64", noSideEffect.}
+proc `/` *(x, y: float): float {.magic: "DivF64", noSideEffect.}
+  ## computes the floating point division
+
+proc `==` *(x, y: float32): bool {.magic: "EqF64", noSideEffect.}
+proc `<=` *(x, y: float32): bool {.magic: "LeF64", noSideEffect.}
+proc `<`  *(x, y: float32): bool {.magic: "LtF64", noSideEffect.}
+
+proc `==` *(x, y: float): bool {.magic: "EqF64", noSideEffect.}
+proc `<=` *(x, y: float): bool {.magic: "LeF64", noSideEffect.}
+proc `<`  *(x, y: float): bool {.magic: "LtF64", noSideEffect.}
+
+# set operators
+proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.}
+  ## This operator computes the intersection of two sets.
+proc `+` *[T](x, y: set[T]): set[T] {.magic: "PlusSet", noSideEffect.}
+  ## This operator computes the union of two sets.
+proc `-` *[T](x, y: set[T]): set[T] {.magic: "MinusSet", noSideEffect.}
+  ## This operator computes the difference of two sets.
+
+proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.}
+  ## One should overload this proc if one wants to overload the ``in`` operator.
+  ## The parameters are in reverse order! ``a in b`` is a template for
+  ## ``contains(b, a)``.
+  ## This is because the unification algorithm that Nim uses for overload
+  ## resolution works from left to right.
+  ## But for the ``in`` operator that would be the wrong direction for this
+  ## piece of code:
+  ##
+  ## .. code-block:: Nim
+  ##   var s: set[range['a'..'z']] = {'a'..'c'}
+  ##   writeln(stdout, 'b' in s)
+  ##
+  ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would
+  ## have been bound to ``char``. But ``s`` is not compatible to type
+  ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This
+  ## is achieved by reversing the parameters for ``contains``; ``in`` then
+  ## passes its arguments in reverse order.
+
+proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} =
+  ## Checks if `value` is within the range of `s`; returns true iff
+  ## `value >= s.a and value <= s.b`
+  ##
+  ## .. code-block:: Nim
+  ##   assert((1..3).contains(1) == true)
+  ##   assert((1..3).contains(2) == true)
+  ##   assert((1..3).contains(4) == false)
+  result = s.a <= value and value <= s.b
+
+template `in` * (x, y: expr): expr {.immediate, dirty.} = contains(y, x)
+  ## Sugar for contains
+  ##
+  ## .. code-block:: Nim
+  ##   assert(1 in (1..3) == true)
+  ##   assert(5 in (1..3) == false)
+template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x)
+  ## Sugar for not containing
+  ##
+  ## .. code-block:: Nim
+  ##   assert(1 notin (1..3) == false)
+  ##   assert(5 notin (1..3) == true)
+
+proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
+  ## Checks if T is of the same type as S
+  ##
+  ## .. code-block:: Nim
+  ##   proc test[T](a: T): int =
+  ##     when (T is int):
+  ##       return a
+  ##     else:
+  ##       return 0
+  ##
+  ##   assert(test[int](3) == 3)
+  ##   assert(test[string]("xyz") == 0)
+template `isnot` *(x, y: expr): expr {.immediate.} = not (x is y)
+  ## Negated version of `is`. Equivalent to ``not(x is y)``.
+
+proc `of` *[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.}
+  ## Checks if `x` has a type of `y`
+  ##
+  ## .. code-block:: Nim
+  ##   assert(FloatingPointError of Exception)
+  ##   assert(DivByZeroError of Exception)
+
+proc cmp*[T](x, y: T): int {.procvar.} =
+  ## Generic compare proc. Returns a value < 0 iff x < y, a value > 0 iff x > y
+  ## and 0 iff x == y. This is useful for writing generic algorithms without
+  ## performance loss. This generic implementation uses the `==` and `<`
+  ## operators.
+  if x == y: return 0
+  if x < y: return -1
+  return 1
+
+proc cmp*(x, y: string): int {.noSideEffect, procvar.}
+  ## Compare proc for strings. More efficient than the generic version.
+
+proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {.
+  magic: "ArrToSeq", nosideeffect.}
+  ## turns an array into a sequence. This most often useful for constructing
+  ## sequences with the array constructor: ``@[1, 2, 3]`` has the type
+  ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``.
+
+proc setLen*[T](s: var seq[T], newlen: Natural) {.
+  magic: "SetLengthSeq", noSideEffect.}
+  ## sets the length of `s` to `newlen`.
+  ## ``T`` may be any sequence type.
+  ## If the current length is greater than the new length,
+  ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with
+  ## a size, use ``newSeq`` instead.
+
+proc setLen*(s: var string, newlen: Natural) {.
+  magic: "SetLengthStr", noSideEffect.}
+  ## sets the length of `s` to `newlen`.
+  ## If the current length is greater than the new length,
+  ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
+  ## a size, use ``newString`` instead.
+
+proc newString*(len: Natural): string {.
+  magic: "NewString", importc: "mnewString", noSideEffect.}
+  ## returns a new string of length ``len`` but with uninitialized
+  ## content. One needs to fill the string character after character
+  ## with the index operator ``s[i]``. This procedure exists only for
+  ## optimization purposes; the same effect can be achieved with the
+  ## ``&`` operator or with ``add``.
+
+proc newStringOfCap*(cap: Natural): string {.
+  magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.}
+  ## returns a new string of length ``0`` but with capacity `cap`.This
+  ## procedure exists only for optimization purposes; the same effect can
+  ## be achieved with the ``&`` operator or with ``add``.
+
+proc `&` * (x: string, y: char): string {.
+  magic: "ConStrStr", noSideEffect, merge.}
+  ## Concatenates `x` with `y`
+  ##
+  ## .. code-block:: Nim
+  ##   assert("ab" & 'c' == "abc")
+proc `&` * (x: char, y: char): string {.
+  magic: "ConStrStr", noSideEffect, merge.}
+  ## Concatenates `x` and `y` into a string
+  ##
+  ## .. code-block:: Nim
+  ##   assert('a' & 'b' == "ab")
+proc `&` * (x, y: string): string {.
+  magic: "ConStrStr", noSideEffect, merge.}
+  ## Concatenates `x` and `y`
+  ##
+  ## .. code-block:: Nim
+  ##   assert("ab" & "cd" == "abcd")
+proc `&` * (x: char, y: string): string {.
+  magic: "ConStrStr", noSideEffect, merge.}
+  ## Concatenates `x` with `y`
+  ##
+  ## .. code-block:: Nim
+  ##   assert('a' & "bc" == "abc")
+
+# implementation note: These must all have the same magic value "ConStrStr" so
+# that the merge optimization works properly.
+
+proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
+  ## Appends `y` to `x` in place
+  ##
+  ## .. code-block:: Nim
+  ##   var tmp = ""
+  ##   tmp.add('a')
+  ##   tmp.add('b')
+  ##   assert(tmp == "ab")
+proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
+  ## Concatenates `x` and `y` in place
+  ##
+  ## .. code-block:: Nim
+  ##   var tmp = ""
+  ##   tmp.add("ab")
+  ##   tmp.add("cd")
+  ##   assert(tmp == "abcd")
+
+type
+  Endianness* = enum ## is a type describing the endianness of a processor.
+    littleEndian, bigEndian
+
+const
+  isMainModule* {.magic: "IsMainModule".}: bool = false
+    ## is true only when accessed in the main module. This works thanks to
+    ## compiler magic. It is useful to embed testing code in a module.
+
+  CompileDate* {.magic: "CompileDate"}: string = "0000-00-00"
+    ## is the date of compilation as a string of the form
+    ## ``YYYY-MM-DD``. This works thanks to compiler magic.
+
+  CompileTime* {.magic: "CompileTime"}: string = "00:00:00"
+    ## is the time of compilation as a string of the form
+    ## ``HH:MM:SS``. This works thanks to compiler magic.
+
+  cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian
+    ## is the endianness of the target CPU. This is a valuable piece of
+    ## information for low-level code only. This works thanks to compiler
+    ## magic.
+
+  hostOS* {.magic: "HostOS".}: string = ""
+    ## a string that describes the host operating system. Possible values:
+    ## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris",
+    ## "aix", "standalone".
+
+  hostCPU* {.magic: "HostCPU".}: string = ""
+    ## a string that describes the host CPU. Possible values:
+    ## "i386", "alpha", "powerpc", "powerpc64", "sparc", "amd64", "mips", "arm".
+
+  seqShallowFlag = low(int)
+
+proc compileOption*(option: string): bool {.
+  magic: "CompileOption", noSideEffect.}
+  ## can be used to determine an on|off compile-time option. Example:
+  ##
+  ## .. code-block:: nim
+  ##   when compileOption("floatchecks"):
+  ##     echo "compiled with floating point NaN and Inf checks"
+
+proc compileOption*(option, arg: string): bool {.
+  magic: "CompileOptionArg", noSideEffect.}
+  ## can be used to determine an enum compile-time option. Example:
+  ##
+  ## .. code-block:: nim
+  ##   when compileOption("opt", "size") and compileOption("gc", "boehm"):
+  ##     echo "compiled with optimization for size and uses Boehm's GC"
+
+const
+  hasThreadSupport = compileOption("threads")
+  hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own
+  taintMode = compileOption("taintmode")
+
+when taintMode:
+  type TaintedString* = distinct string ## a distinct string type that
+                                        ## is `tainted`:idx:. It is an alias for
+                                        ## ``string`` if the taint mode is not
+                                        ## turned on. Use the ``-d:taintMode``
+                                        ## command line switch to turn the taint
+                                        ## mode on.
+
+  proc len*(s: TaintedString): int {.borrow.}
+else:
+  type TaintedString* = string          ## a distinct string type that
+                                        ## is `tainted`:idx:. It is an alias for
+                                        ## ``string`` if the taint mode is not
+                                        ## turned on. Use the ``-d:taintMode``
+                                        ## command line switch to turn the taint
+                                        ## mode on.
+
+when defined(profiler):
+  proc nimProfile() {.compilerProc, noinline.}
+when hasThreadSupport:
+  {.pragma: rtlThreadVar, threadvar.}
+else:
+  {.pragma: rtlThreadVar.}
+
+const
+  QuitSuccess* = 0
+    ## is the value that should be passed to `quit <#quit>`_ to indicate
+    ## success.
+
+  QuitFailure* = 1
+    ## is the value that should be passed to `quit <#quit>`_ to indicate
+    ## failure.
+
+var programResult* {.exportc: "nim_program_result".}: int
+  ## modify this variable to specify the exit code of the program
+  ## under normal circumstances. When the program is terminated
+  ## prematurely using ``quit``, this value is ignored.
+
+proc quit*(errorcode: int = QuitSuccess) {.
+  magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.}
+  ## Stops the program immediately with an exit code.
+  ##
+  ## Before stopping the program the "quit procedures" are called in the
+  ## opposite order they were added with `addQuitProc <#addQuitProc>`_.
+  ## ``quit`` never returns and ignores any exception that may have been raised
+  ## by the quit procedures.  It does *not* call the garbage collector to free
+  ## all the memory, unless a quit procedure calls `GC_fullCollect
+  ## <#GC_fullCollect>`_.
+  ##
+  ## The proc ``quit(QuitSuccess)`` is called implicitly when your nim
+  ## program finishes without incident. A raised unhandled exception is
+  ## equivalent to calling ``quit(QuitFailure)``.
+  ##
+  ## Note that this is a *runtime* call and using ``quit`` inside a macro won't
+  ## have any compile time effect. If you need to stop the compiler inside a
+  ## macro, use the `error <manual.html#error-pragma>`_ or `fatal
+  ## <manual.html#fatal-pragma>`_ pragmas.
+
+template sysAssert(cond: bool, msg: string) =
+  when defined(useSysAssert):
+    if not cond:
+      echo "[SYSASSERT] ", msg
+      quit 1
+
+when not defined(JS) and not defined(nimrodVm) and hostOS != "standalone":
+  include "system/cgprocs"
+
+proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
+proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
+  ## Generic proc for adding a data item `y` to a container `x`.
+  ## For containers that have an order, `add` means *append*. New generic
+  ## containers should also call their adding proc `add` for consistency.
+  ## Generic code becomes much easier to write if the Nim naming scheme is
+  ## respected.
+  let xl = x.len
+  setLen(x, xl + y.len)
+  for i in 0..high(y): x[xl+i] = y[i]
+
+proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
+  ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy
+  ## only changes the semantics for sequences and strings (and types which
+  ## contain those). Be careful with the changed semantics though! There
+  ## is a reason why the default assignment does a deep copy of sequences
+  ## and strings.
+
+proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
+  ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
+  ## This is an O(1) operation.
+  let xl = x.len
+  shallowCopy(x[i], x[xl-1])
+  setLen(x, xl-1)
+
+proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} =
+  ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
+  ## This is an O(n) operation.
+  let xl = x.len
+  for j in i..xl-2: shallowCopy(x[j], x[j+1])
+  setLen(x, xl-1)
+
+proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
+  ## inserts `item` into `x` at position `i`.
+  let xl = x.len
+  setLen(x, xl+1)
+  var j = xl-1
+  while j >= i:
+    shallowCopy(x[j+1], x[j])
+    dec(j)
+  x[i] = item
+
+proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
+  ## takes any Nim variable and returns its string representation. It
+  ## works even for complex data graphs with cycles. This is a great
+  ## debugging tool.
+
+type
+  ByteAddress* = int
+    ## is the signed integer type that should be used for converting
+    ## pointers to integer addresses for readability.
+
+  BiggestInt* = int64
+    ## is an alias for the biggest signed integer type the Nim compiler
+    ## supports. Currently this is ``int64``, but it is platform-dependant
+    ## in general.
+
+  BiggestFloat* = float64
+    ## is an alias for the biggest floating point type the Nim
+    ## compiler supports. Currently this is ``float64``, but it is
+    ## platform-dependant in general.
+
+{.deprecated: [TAddress: ByteAddress].}
+
+when defined(windows):
+  type
+    clong* {.importc: "long", nodecl.} = int32
+      ## This is the same as the type ``long`` in *C*.
+    culong* {.importc: "unsigned long", nodecl.} = uint32
+      ## This is the same as the type ``unsigned long`` in *C*.
+else:
+  type
+    clong* {.importc: "long", nodecl.} = int
+      ## This is the same as the type ``long`` in *C*.
+    culong* {.importc: "unsigned long", nodecl.} = uint
+      ## This is the same as the type ``unsigned long`` in *C*.
+
+type # these work for most platforms:
+  cchar* {.importc: "char", nodecl.} = char
+    ## This is the same as the type ``char`` in *C*.
+  cschar* {.importc: "signed char", nodecl.} = int8
+    ## This is the same as the type ``signed char`` in *C*.
+  cshort* {.importc: "short", nodecl.} = int16
+    ## This is the same as the type ``short`` in *C*.
+  cint* {.importc: "int", nodecl.} = int32
+    ## This is the same as the type ``int`` in *C*.
+  csize* {.importc: "size_t", nodecl.} = int
+    ## This is the same as the type ``size_t`` in *C*.
+  clonglong* {.importc: "long long", nodecl.} = int64
+    ## This is the same as the type ``long long`` in *C*.
+  cfloat* {.importc: "float", nodecl.} = float32
+    ## This is the same as the type ``float`` in *C*.
+  cdouble* {.importc: "double", nodecl.} = float64
+    ## This is the same as the type ``double`` in *C*.
+  clongdouble* {.importc: "long double", nodecl.} = BiggestFloat
+    ## This is the same as the type ``long double`` in *C*.
+    ## This C type is not supported by Nim's code generator
+
+  cuchar* {.importc: "unsigned char", nodecl.} = char
+    ## This is the same as the type ``unsigned char`` in *C*.
+  cushort* {.importc: "unsigned short", nodecl.} = uint16
+    ## This is the same as the type ``unsigned short`` in *C*.
+  cuint* {.importc: "unsigned int", nodecl.} = uint32
+    ## This is the same as the type ``unsigned int`` in *C*.
+  culonglong* {.importc: "unsigned long long", nodecl.} = uint64
+    ## This is the same as the type ``unsigned long long`` in *C*.
+
+  cstringArray* {.importc: "char**", nodecl.} = ptr array [0..ArrayDummySize, cstring]
+    ## This is binary compatible to the type ``char**`` in *C*. The array's
+    ## high value is large enough to disable bounds checking in practice.
+    ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
+
+  PFloat32* = ptr float32 ## an alias for ``ptr float32``
+  PFloat64* = ptr float64 ## an alias for ``ptr float64``
+  PInt64* = ptr int64 ## an alias for ``ptr int64``
+  PInt32* = ptr int32 ## an alias for ``ptr int32``
+
+proc toFloat*(i: int): float {.
+  magic: "ToFloat", noSideEffect, importc: "toFloat".}
+  ## converts an integer `i` into a ``float``. If the conversion
+  ## fails, `EInvalidValue` is raised. However, on most platforms the
+  ## conversion cannot fail.
+
+proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.
+  magic: "ToBiggestFloat", noSideEffect, importc: "toBiggestFloat".}
+  ## converts an biggestint `i` into a ``biggestfloat``. If the conversion
+  ## fails, `EInvalidValue` is raised. However, on most platforms the
+  ## conversion cannot fail.
+
+proc toInt*(f: float): int {.
+  magic: "ToInt", noSideEffect, importc: "toInt".}
+  ## converts a floating point number `f` into an ``int``. Conversion
+  ## rounds `f` if it does not contain an integer value. If the conversion
+  ## fails (because `f` is infinite for example), `EInvalidValue` is raised.
+
+proc toBiggestInt*(f: BiggestFloat): BiggestInt {.
+  magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".}
+  ## converts a biggestfloat `f` into a ``biggestint``. Conversion
+  ## rounds `f` if it does not contain an integer value. If the conversion
+  ## fails (because `f` is infinite for example), `EInvalidValue` is raised.
+
+proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
+  importc: "atexit", header: "<stdlib.h>".}
+  ## Adds/registers a quit procedure.
+  ##
+  ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30
+  ## procedures can be registered. They are executed on a last-in, first-out
+  ## basis (that is, the last function registered is the first to be executed).
+  ## ``addQuitProc`` raises an EOutOfIndex exception if ``QuitProc`` cannot be
+  ## registered.
+
+# Support for addQuitProc() is done by Ansi C's facilities here.
+# In case of an unhandled exeption the exit handlers should
+# not be called explicitly! The user may decide to do this manually though.
+
+proc copy*(s: string, first = 0): string {.
+  magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.}
+proc copy*(s: string, first, last: int): string {.
+  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect,
+  deprecated.}
+  ## copies a slice of `s` into a new string and returns this new
+  ## string. The bounds `first` and `last` denote the indices of
+  ## the first and last characters that shall be copied. If ``last``
+  ## is omitted, it is treated as ``high(s)``.
+  ## **Deprecated since version 0.8.12**: Use ``substr`` instead.
+
+proc substr*(s: string, first = 0): string {.
+  magic: "CopyStr", importc: "copyStr", noSideEffect.}
+proc substr*(s: string, first, last: int): string {.
+  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.}
+  ## copies a slice of `s` into a new string and returns this new
+  ## string. The bounds `first` and `last` denote the indices of
+  ## the first and last characters that shall be copied. If ``last``
+  ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len``
+  ## is used instead: This means ``substr`` can also be used to `cut`:idx:
+  ## or `limit`:idx: a string's length.
+
+when not defined(nimrodVM):
+  proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
+    ## overwrites the contents of the memory at ``p`` with the value 0.
+    ## Exactly ``size`` bytes will be overwritten. Like any procedure
+    ## dealing with raw memory this is *unsafe*.
+
+  proc copyMem*(dest, source: pointer, size: Natural) {.
+    importc: "memcpy", header: "<string.h>", benign.}
+    ## copies the contents from the memory at ``source`` to the memory
+    ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
+    ## regions may not overlap. Like any procedure dealing with raw
+    ## memory this is *unsafe*.
+
+  proc moveMem*(dest, source: pointer, size: Natural) {.
+    importc: "memmove", header: "<string.h>", benign.}
+    ## copies the contents from the memory at ``source`` to the memory
+    ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
+    ## regions may overlap, ``moveMem`` handles this case appropriately
+    ## and is thus somewhat more safe than ``copyMem``. Like any procedure
+    ## dealing with raw memory this is still *unsafe*, though.
+
+  proc equalMem*(a, b: pointer, size: Natural): bool {.
+    importc: "equalMem", noDecl, noSideEffect.}
+    ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
+    ## be compared. If the blocks are equal, true is returned, false
+    ## otherwise. Like any procedure dealing with raw memory this is
+    ## *unsafe*.
+
+  when hostOS != "standalone":
+    proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
+      ## allocates a new memory block with at least ``size`` bytes. The
+      ## block has to be freed with ``realloc(block, 0)`` or
+      ## ``dealloc(block)``. The block is not initialized, so reading
+      ## from it before writing to it is undefined behaviour!
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `allocShared` to allocate from a shared heap.
+    proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign.} =
+      ## allocates a new memory block with at least ``T.sizeof * size``
+      ## bytes. The block has to be freed with ``resize(block, 0)`` or
+      ## ``free(block)``. The block is not initialized, so reading
+      ## from it before writing to it is undefined behaviour!
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `createSharedU` to allocate from a shared heap.
+      cast[ptr T](alloc(T.sizeof * size))
+    proc alloc0*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
+      ## allocates a new memory block with at least ``size`` bytes. The
+      ## block has to be freed with ``realloc(block, 0)`` or
+      ## ``dealloc(block)``. The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``alloc``.
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `allocShared0` to allocate from a shared heap.
+    proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign.} =
+      ## allocates a new memory block with at least ``T.sizeof * size``
+      ## bytes. The block has to be freed with ``resize(block, 0)`` or
+      ## ``free(block)``. The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``createU``.
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `createShared` to allocate from a shared heap.
+      cast[ptr T](alloc0(T.sizeof * size))
+    proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [],
+                                                           benign.}
+      ## grows or shrinks a given memory block. If p is **nil** then a new
+      ## memory block is returned. In either way the block has at least
+      ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
+      ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
+      ## be freed with ``dealloc``.
+      ## The allocated memory belongs to its allocating thread!
+      ## Use `reallocShared` to reallocate from a shared heap.
+    proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign.} =
+      ## grows or shrinks a given memory block. If p is **nil** then a new
+      ## memory block is returned. In either way the block has at least
+      ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not
+      ## **nil** ``resize`` calls ``free(p)``. In other cases the block
+      ## has to be freed with ``free``. The allocated memory belongs to
+      ## its allocating thread!
+      ## Use `resizeShared` to reallocate from a shared heap.
+      cast[ptr T](realloc(p, T.sizeof * newSize))
+    proc dealloc*(p: pointer) {.noconv, rtl, tags: [], benign.}
+      ## frees the memory allocated with ``alloc``, ``alloc0`` or
+      ## ``realloc``. This procedure is dangerous! If one forgets to
+      ## free the memory a leak occurs; if one tries to access freed
+      ## memory (or just freeing it twice!) a core dump may happen
+      ## or other memory may be corrupted.
+      ## The freed memory must belong to its allocating thread!
+      ## Use `deallocShared` to deallocate from a shared heap.
+    proc free*[T](p: ptr T) {.inline, benign.} =
+      dealloc(p)
+    proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.}
+      ## allocates a new memory block on the shared heap with at
+      ## least ``size`` bytes. The block has to be freed with
+      ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block
+      ## is not initialized, so reading from it before writing to it is
+      ## undefined behaviour!
+    proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline,
+                                                                 benign.} =
+      ## allocates a new memory block on the shared heap with at
+      ## least ``T.sizeof * size`` bytes. The block has to be freed with
+      ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block
+      ## is not initialized, so reading from it before writing to it is
+      ## undefined behaviour!
+      cast[ptr T](allocShared(T.sizeof * size))
+    proc allocShared0*(size: Natural): pointer {.noconv, rtl, benign.}
+      ## allocates a new memory block on the shared heap with at
+      ## least ``size`` bytes. The block has to be freed with
+      ## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
+      ## The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``allocShared``.
+    proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} =
+      ## allocates a new memory block on the shared heap with at
+      ## least ``T.sizeof * size`` bytes. The block has to be freed with
+      ## ``resizeShared(block, 0)`` or ``freeShared(block)``.
+      ## The block is initialized with all bytes
+      ## containing zero, so it is somewhat safer than ``createSharedU``.
+      cast[ptr T](allocShared0(T.sizeof * size))
+    proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl,
+                                                                 benign.}
+      ## grows or shrinks a given memory block on the heap. If p is **nil**
+      ## then a new memory block is returned. In either way the block has at
+      ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil**
+      ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
+      ## block has to be freed with ``deallocShared``.
+    proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline.} =
+      ## grows or shrinks a given memory block on the heap. If p is **nil**
+      ## then a new memory block is returned. In either way the block has at
+      ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is
+      ## not **nil** ``resizeShared`` calls ``freeShared(p)``. In other
+      ## cases the block has to be freed with ``freeShared``.
+      cast[ptr T](reallocShared(p, T.sizeof * newSize))
+    proc deallocShared*(p: pointer) {.noconv, rtl, benign.}
+      ## frees the memory allocated with ``allocShared``, ``allocShared0`` or
+      ## ``reallocShared``. This procedure is dangerous! If one forgets to
+      ## free the memory a leak occurs; if one tries to access freed
+      ## memory (or just freeing it twice!) a core dump may happen
+      ## or other memory may be corrupted.
+    proc freeShared*[T](p: ptr T) {.inline, benign.} =
+      ## frees the memory allocated with ``createShared``, ``createSharedU`` or
+      ## ``resizeShared``. This procedure is dangerous! If one forgets to
+      ## free the memory a leak occurs; if one tries to access freed
+      ## memory (or just freeing it twice!) a core dump may happen
+      ## or other memory may be corrupted.
+      deallocShared(p)
+
+proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.}
+  ## swaps the values `a` and `b`. This is often more efficient than
+  ## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms.
+
+template `>=%` *(x, y: expr): expr {.immediate.} = y <=% x
+  ## treats `x` and `y` as unsigned and compares them.
+  ## Returns true iff ``unsigned(x) >= unsigned(y)``.
+
+template `>%` *(x, y: expr): expr {.immediate.} = y <% x
+  ## treats `x` and `y` as unsigned and compares them.
+  ## Returns true iff ``unsigned(x) > unsigned(y)``.
+
+proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.}
+  ## The stringify operator for an integer argument. Returns `x`
+  ## converted to a decimal string. ``$`` is Nim's general way of
+  ## spelling `toString`:idx:.
+
+proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
+  ## The stringify operator for an integer argument. Returns `x`
+  ## converted to a decimal string.
+
+when not defined(NimrodVM):
+  when not defined(JS) and hostOS != "standalone":
+    proc `$` *(x: uint64): string {.noSideEffect.}
+      ## The stringify operator for an unsigned integer argument. Returns `x`
+      ## converted to a decimal string.
+
+proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.}
+  ## The stringify operator for a float argument. Returns `x`
+  ## converted to a decimal string.
+
+proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.}
+  ## The stringify operator for a boolean argument. Returns `x`
+  ## converted to the string "false" or "true".
+
+proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
+  ## The stringify operator for a character argument. Returns `x`
+  ## converted to a string.
+
+proc `$` *(x: cstring): string {.magic: "CStrToStr", noSideEffect.}
+  ## The stringify operator for a CString argument. Returns `x`
+  ## converted to a string.
+
+proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.}
+  ## The stringify operator for a string argument. Returns `x`
+  ## as it is. This operator is useful for generic code, so
+  ## that ``$expr`` also works if ``expr`` is already a string.
+
+proc `$` *[TEnum: enum](x: TEnum): string {.magic: "EnumToStr", noSideEffect.}
+  ## The stringify operator for an enumeration argument. This works for
+  ## any enumeration type thanks to compiler magic. If
+  ## a ``$`` operator for a concrete enumeration is provided, this is
+  ## used instead. (In other words: *Overwriting* is possible.)
+
+# undocumented:
+proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.}
+proc getRefcount*(x: string): int {.importc: "getRefcount", noSideEffect.}
+proc getRefcount*[T](x: seq[T]): int {.importc: "getRefcount", noSideEffect.}
+  ## retrieves the reference count of an heap-allocated object. The
+  ## value is implementation-dependent.
+
+
+const
+  Inf* {.magic: "Inf".} = 1.0 / 0.0
+    ## contains the IEEE floating point value of positive infinity.
+  NegInf* {.magic: "NegInf".} = -Inf
+    ## contains the IEEE floating point value of negative infinity.
+  NaN* {.magic: "NaN".} = 0.0 / 0.0
+    ## contains an IEEE floating point value of *Not A Number*. Note
+    ## that you cannot compare a floating point value to this value
+    ## and expect a reasonable result - use the `classify` procedure
+    ## in the module ``math`` for checking for NaN.
+  NimMajor*: int = 0
+    ## is the major number of Nim's version.
+
+  NimMinor*: int = 11
+    ## is the minor number of Nim's version.
+
+  NimPatch*: int = 2
+    ## is the patch number of Nim's version.
+
+  NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
+    ## is the version of Nim as a string.
+
+{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion,
+    NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].}
+
+# GC interface:
+
+when not defined(nimrodVM) and hostOS != "standalone":
+  proc getOccupiedMem*(): int {.rtl.}
+    ## returns the number of bytes that are owned by the process and hold data.
+
+  proc getFreeMem*(): int {.rtl.}
+    ## returns the number of bytes that are owned by the process, but do not
+    ## hold any meaningful data.
+
+  proc getTotalMem*(): int {.rtl.}
+    ## returns the number of bytes that are owned by the process.
+
+  when hasThreadSupport:
+    proc getOccupiedSharedMem*(): int {.rtl.}
+      ## returns the number of bytes that are owned by the process
+      ## on the shared heap and hold data. This is only available when
+      ## threads are enabled.
+
+    proc getFreeSharedMem*(): int {.rtl.}
+      ## returns the number of bytes that are owned by the
+      ## process on the shared heap, but do not hold any meaningful data.
+      ## This is only available when threads are enabled.
+
+    proc getTotalSharedMem*(): int {.rtl.}
+      ## returns the number of bytes on the shared heap that are owned by the
+      ## process. This is only available when threads are enabled.
+
+when sizeof(int) <= 2:
+  type IntLikeForCount = int|int8|int16|char|bool|uint8|enum
+else:
+  type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum
+
+iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
+  ## Counts from ordinal value `a` down to `b` with the given
+  ## step count. `T` may be any ordinal type, `step` may only
+  ## be positive. **Note**: This fails to count to ``low(int)`` if T = int for
+  ## efficiency reasons.
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res >= int(b):
+      yield T(res)
+      dec(res, step)
+  else:
+    var res = a
+    while res >= b:
+      yield res
+      dec(res, step)
+
+template countupImpl(incr: stmt) {.immediate, dirty.} =
+  when T is IntLikeForCount:
+    var res = int(a)
+    while res <= int(b):
+      yield T(res)
+      incr
+  else:
+    var res: T = T(a)
+    while res <= b:
+      yield res
+      incr
+
+iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} =
+  ## Counts from ordinal value `a` up to `b` with the given
+  ## step count. `S`, `T` may be any ordinal type, `step` may only
+  ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for
+  ## efficiency reasons.
+  countupImpl:
+    inc(res, step)
+
+iterator `..`*[S, T](a: S, b: T): T {.inline.} =
+  ## An alias for `countup`.
+  countupImpl:
+    inc(res)
+
+iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
+  inline, magic: "OmpParFor", sideEffect.} =
+  ## parallel loop iterator. Same as `..` but the loop may run in parallel.
+  ## `annotation` is an additional annotation for the code generator to use.
+  ## Note that the compiler maps that to
+  ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as
+  ## such isn't aware of the parallelism in your code! Be careful! Later
+  ## versions of ``||`` will get proper support by Nim's code generator
+  ## and GC.
+  discard
+
+{.push stackTrace:off.}
+proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} =
+  if x <= y: x else: y
+proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.} =
+  if x <= y: x else: y
+proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} =
+  if x <= y: x else: y
+proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} =
+  if x <= y: x else: y
+proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} =
+  ## The minimum value of two integers.
+  if x <= y: x else: y
+
+proc min*[T](x: varargs[T]): T =
+  ## The minimum value of `x`. ``T`` needs to have a ``<`` operator.
+  result = x[0]
+  for i in 1..high(x):
+    if x[i] < result: result = x[i]
+
+proc max*(x, y: int): int {.magic: "MaxI", noSideEffect.} =
+  if y <= x: x else: y
+proc max*(x, y: int8): int8 {.magic: "MaxI", noSideEffect.} =
+  if y <= x: x else: y
+proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} =
+  if y <= x: x else: y
+proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} =
+  if y <= x: x else: y
+proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} =
+  ## The maximum value of two integers.
+  if y <= x: x else: y
+
+proc max*[T](x: varargs[T]): T =
+  ## The maximum value of `x`. ``T`` needs to have a ``<`` operator.
+  result = x[0]
+  for i in 1..high(x):
+    if result < x[i]: result = x[i]
+
+proc abs*(x: float): float {.magic: "AbsF64", noSideEffect.} =
+  if x < 0.0: -x else: x
+proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} =
+  if x <= y: x else: y
+proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} =
+  if y <= x: x else: y
+{.pop.}
+
+proc clamp*[T](x, a, b: T): T =
+  ## limits the value ``x`` within the interval [a, b]
+  ##
+  ## .. code-block:: Nim
+  ##   assert((1.4).clamp(0.0, 1.0) == 1.0)
+  ##   assert((0.5).clamp(0.0, 1.0) == 0.5)
+  if x < a: return a
+  if x > b: return b
+  return x
+
+iterator items*[T](a: openArray[T]): T {.inline.} =
+  ## iterates over each item of `a`.
+  var i = 0
+  while i < len(a):
+    yield a[i]
+    inc(i)
+
+iterator mitems*[T](a: var openArray[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  while i < len(a):
+    yield a[i]
+    inc(i)
+
+iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
+  ## iterates over each item of `a`.
+  var i = low(IX)
+  if i <= high(IX):
+    while true:
+      yield a[i]
+      if i >= high(IX): break
+      inc(i)
+
+iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = low(IX)
+  if i <= high(IX):
+    while true:
+      yield a[i]
+      if i >= high(IX): break
+      inc(i)
+
+iterator items*[T](a: set[T]): T {.inline.} =
+  ## iterates over each element of `a`. `items` iterates only over the
+  ## elements that are really in the set (and not over the ones the set is
+  ## able to hold).
+  var i = low(T).int
+  while i <= high(T).int:
+    if T(i) in a: yield T(i)
+    inc(i)
+
+iterator items*(a: cstring): char {.inline.} =
+  ## iterates over each item of `a`.
+  var i = 0
+  while a[i] != '\0':
+    yield a[i]
+    inc(i)
+
+iterator mitems*(a: var cstring): var char {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  while a[i] != '\0':
+    yield a[i]
+    inc(i)
+
+iterator items*(E: typedesc[enum]): E =
+  ## iterates over the values of the enum ``E``.
+  for v in low(E)..high(E):
+    yield v
+
+iterator items*[T](s: Slice[T]): T =
+  ## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
+  ## (inclusively).
+  for x in s.a..s.b:
+    yield x
+
+iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  var i = low(IX)
+  if i <= high(IX):
+    while true:
+      yield (i, a[i])
+      if i >= high(IX): break
+      inc(i)
+
+iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = low(IX)
+  if i <= high(IX):
+    while true:
+      yield (i, a[i])
+      if i >= high(IX): break
+      inc(i)
+
+iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while i < len(a):
+    yield (i, a[i])
+    inc(i)
+
+iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  var i = 0
+  while a[i] != '\0':
+    yield (i, a[i])
+    inc(i)
+
+iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
+  ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
+  ## ``a[index]`` can be modified.
+  var i = 0
+  while a[i] != '\0':
+    yield (i, a[i])
+    inc(i)
+
+
+proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".}
+proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".}
+  ## Fast check whether `x` is nil. This is sometimes more efficient than
+  ## ``== nil``.
+
+proc `==` *[I, T](x, y: array[I, T]): bool =
+  for f in low(x)..high(x):
+    if x[f] != y[f]:
+      return
+  result = true
+
+proc `@`*[T](a: openArray[T]): seq[T] =
+  ## turns an openarray into a sequence. This is not as efficient as turning
+  ## a fixed length array into a sequence as it always copies every element
+  ## of `a`.
+  newSeq(result, a.len)
+  for i in 0..a.len-1: result[i] = a[i]
+
+proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} =
+  ## Concatenates two sequences.
+  ## Requires copying of the sequences.
+  ##
+  ## .. code-block:: Nim
+  ##   assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6])
+  newSeq(result, x.len + y.len)
+  for i in 0..x.len-1:
+    result[i] = x[i]
+  for i in 0..y.len-1:
+    result[i+x.len] = y[i]
+
+proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} =
+  ## Appends element y to the end of the sequence.
+  ## Requires copying of the sequence
+  ##
+  ## .. code-block:: Nim
+  ##   assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4])
+  newSeq(result, x.len + 1)
+  for i in 0..x.len-1:
+    result[i] = x[i]
+  result[x.len] = y
+
+proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} =
+  ## Prepends the element x to the beginning of the sequence.
+  ## Requires copying of the sequence
+  ##
+  ## .. code-block:: Nim
+  ##   assert(1 & @[2, 3, 4] == @[1, 2, 3, 4])
+  newSeq(result, y.len + 1)
+  result[0] = x
+  for i in 0..y.len-1:
+    result[i+1] = y[i]
+
+when not defined(NimrodVM):
+  when not defined(JS):
+    proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
+      result = cast[pointer](x)
+  else:
+    proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
+      asm """return `x`"""
+
+  proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
+    ## Generic equals operator for sequences: relies on a equals operator for
+    ## the element type `T`.
+    if seqToPtr(x) == seqToPtr(y):
+      result = true
+    elif seqToPtr(x) == nil or seqToPtr(y) == nil:
+      result = false
+    elif x.len == y.len:
+      for i in 0..x.len-1:
+        if x[i] != y[i]: return false
+      result = true
+
+proc find*[T, S](a: T, item: S): int {.inline.}=
+  ## Returns the first index of `item` in `a` or -1 if not found. This requires
+  ## appropriate `items` and `==` operations to work.
+  for i in items(a):
+    if i == item: return
+    inc(result)
+  result = -1
+
+proc contains*[T](a: openArray[T], item: T): bool {.inline.}=
+  ## Returns true if `item` is in `a` or false if not found. This is a shortcut
+  ## for ``find(a, item) >= 0``.
+  return find(a, item) >= 0
+
+proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
+  ## returns the last item of `s` and decreases ``s.len`` by one. This treats
+  ## `s` as a stack and implements the common *pop* operation.
+  var L = s.len-1
+  result = s[L]
+  setLen(s, L)
+
+proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {.
+  deprecated.} =
+  ## The well-known ``map`` operation from functional programming. Applies
+  ## `op` to every item in `data` and returns the result as a sequence.
+  ##
+  ## **Deprecated since version 0.9:** Use the ``map`` proc instead.
+  newSeq(result, data.len)
+  for i in 0..data.len-1: result[i] = op(data[i])
+
+proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {.
+  deprecated.} =
+  ## The well-known ``map`` operation from functional programming. Applies
+  ## `op` to every item in `data` modifying it directly.
+  ##
+  ## **Deprecated since version 0.9:** Use the ``map`` proc instead.
+  for i in 0..data.len-1: op(data[i])
+
+proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] =
+  ## Returns a new sequence with the results of `op` applied to every item in
+  ## `data`.
+  ##
+  ## Since the input is not modified you can use this version of ``map`` to
+  ## transform the type of the elements in the input sequence. Example:
+  ##
+  ## .. code-block:: nim
+  ##   let
+  ##     a = @[1, 2, 3, 4]
+  ##     b = map(a, proc(x: int): string = $x)
+  ##   assert b == @["1", "2", "3", "4"]
+  newSeq(result, data.len)
+  for i in 0..data.len-1: result[i] = op(data[i])
+
+proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) =
+  ## Applies `op` to every item in `data` modifying it directly.
+  ##
+  ## Note that this version of ``map`` requires your input and output types to
+  ## be the same, since they are modified in-place. Example:
+  ##
+  ## .. code-block:: nim
+  ##   var a = @["1", "2", "3", "4"]
+  ##   echo repr(a)
+  ##   # --> ["1", "2", "3", "4"]
+  ##   map(a, proc(x: var string) = x &= "42")
+  ##   echo repr(a)
+  ##   # --> ["142", "242", "342", "442"]
+  for i in 0..data.len-1: op(data[i])
+
+iterator fields*[T: tuple|object](x: T): RootObj {.
+  magic: "Fields", noSideEffect.}
+  ## iterates over every field of `x`. Warning: This really transforms
+  ## the 'for' and unrolls the loop. The current implementation also has a bug
+  ## that affects symbol binding in the loop body.
+iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {.
+  magic: "Fields", noSideEffect.}
+  ## iterates over every field of `x` and `y`.
+  ## Warning: This is really transforms the 'for' and unrolls the loop.
+  ## The current implementation also has a bug that affects symbol binding
+  ## in the loop body.
+iterator fieldPairs*[T: tuple|object](x: T): RootObj {.
+  magic: "FieldPairs", noSideEffect.}
+  ## Iterates over every field of `x` returning their name and value.
+  ##
+  ## When you iterate over objects with different field types you have to use
+  ## the compile time ``when`` instead of a runtime ``if`` to select the code
+  ## you want to run for each type. To perform the comparison use the `is
+  ## operator <manual.html#is-operator>`_. Example:
+  ##
+  ## .. code-block:: Nim
+  ##
+  ##   type
+  ##     Custom = object
+  ##       foo: string
+  ##       bar: bool
+  ##
+  ##   proc `$`(x: Custom): string =
+  ##     result = "Custom:"
+  ##     for name, value in x.fieldPairs:
+  ##       when value is bool:
+  ##         result.add("\n\t" & name & " is " & $value)
+  ##       else:
+  ##         if value.isNil:
+  ##           result.add("\n\t" & name & " (nil)")
+  ##         else:
+  ##           result.add("\n\t" & name & " '" & value & "'")
+  ##
+  ## Another way to do the same without ``when`` is to leave the task of
+  ## picking the appropriate code to a secondary proc which you overload for
+  ## each field type and pass the `value` to.
+  ##
+  ## Warning: This really transforms the 'for' and unrolls the loop. The
+  ## current implementation also has a bug that affects symbol binding in the
+  ## loop body.
+iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[
+  a, b: expr] {.
+  magic: "FieldPairs", noSideEffect.}
+  ## iterates over every field of `x` and `y`.
+  ## Warning: This really transforms the 'for' and unrolls the loop.
+  ## The current implementation also has a bug that affects symbol binding
+  ## in the loop body.
+
+proc `==`*[T: tuple|object](x, y: T): bool =
+  ## generic ``==`` operator for tuples that is lifted from the components
+  ## of `x` and `y`.
+  for a, b in fields(x, y):
+    if a != b: return false
+  return true
+
+proc `<=`*[T: tuple](x, y: T): bool =
+  ## generic ``<=`` operator for tuples that is lifted from the components
+  ## of `x` and `y`. This implementation uses `cmp`.
+  for a, b in fields(x, y):
+    var c = cmp(a, b)
+    if c < 0: return true
+    if c > 0: return false
+  return true
+
+proc `<`*[T: tuple](x, y: T): bool =
+  ## generic ``<`` operator for tuples that is lifted from the components
+  ## of `x` and `y`. This implementation uses `cmp`.
+  for a, b in fields(x, y):
+    var c = cmp(a, b)
+    if c < 0: return true
+    if c > 0: return false
+  return false
+
+proc `$`*[T: tuple|object](x: T): string =
+  ## generic ``$`` operator for tuples that is lifted from the components
+  ## of `x`. Example:
+  ##
+  ## .. code-block:: nim
+  ##   $(23, 45) == "(23, 45)"
+  ##   $() == "()"
+  result = "("
+  var firstElement = true
+  for name, value in fieldPairs(x):
+    if not firstElement: result.add(", ")
+    result.add(name)
+    result.add(": ")
+    result.add($value)
+    firstElement = false
+  result.add(")")
+
+proc collectionToString[T](x: T, b, e: string): string =
+  result = b
+  var firstElement = true
+  for value in items(x):
+    if not firstElement: result.add(", ")
+    result.add($value)
+    firstElement = false
+  result.add(e)
+
+proc `$`*[T](x: set[T]): string =
+  ## generic ``$`` operator for sets that is lifted from the components
+  ## of `x`. Example:
+  ##
+  ## .. code-block:: nim
+  ##   ${23, 45} == "{23, 45}"
+  collectionToString(x, "{", "}")
+
+proc `$`*[T](x: seq[T]): string =
+  ## generic ``$`` operator for seqs that is lifted from the components
+  ## of `x`. Example:
+  ##
+  ## .. code-block:: nim
+  ##   $(@[23, 45]) == "@[23, 45]"
+  collectionToString(x, "@[", "]")
+
+when false:
+  # causes bootstrapping to fail as we use array of chars and cstring should
+  # match better ...
+  proc `$`*[T, IDX](x: array[IDX, T]): string =
+    collectionToString(x, "[", "]")
+
+# ----------------- GC interface ---------------------------------------------
+
+when not defined(nimrodVM) and hostOS != "standalone":
+  proc GC_disable*() {.rtl, inl, benign.}
+    ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
+    ## reactivate the GC. Note that in most circumstances one should only disable
+    ## the mark and sweep phase with `GC_disableMarkAndSweep`.
+
+  proc GC_enable*() {.rtl, inl, benign.}
+    ## enables the GC again.
+
+  proc GC_fullCollect*() {.rtl, benign.}
+    ## forces a full garbage collection pass.
+    ## Ordinary code does not need to call this (and should not).
+
+  type
+    GC_Strategy* = enum ## the strategy the GC should use for the application
+      gcThroughput,      ## optimize for throughput
+      gcResponsiveness,  ## optimize for responsiveness (default)
+      gcOptimizeTime,    ## optimize for speed
+      gcOptimizeSpace    ## optimize for memory footprint
+
+  {.deprecated: [TGC_Strategy: GC_Strategy].}
+
+  proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
+    ## tells the GC the desired strategy for the application.
+    ## **Deprecated** since version 0.8.14. This has always been a nop.
+
+  proc GC_enableMarkAndSweep*() {.rtl, benign.}
+  proc GC_disableMarkAndSweep*() {.rtl, benign.}
+    ## the current implementation uses a reference counting garbage collector
+    ## with a seldomly run mark and sweep phase to free cycles. The mark and
+    ## sweep phase may take a long time and is not needed if the application
+    ## does not create cycles. Thus the mark and sweep phase can be deactivated
+    ## and activated separately from the rest of the GC.
+
+  proc GC_getStatistics*(): string {.rtl, benign.}
+    ## returns an informative string about the GC's activity. This may be useful
+    ## for tweaking.
+
+  proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
+  proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
+  proc GC_ref*(x: string) {.magic: "GCref", benign.}
+    ## marks the object `x` as referenced, so that it will not be freed until
+    ## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
+    ## n calls to `GC_unref` are needed to unmark `x`.
+
+  proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
+  proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
+  proc GC_unref*(x: string) {.magic: "GCunref", benign.}
+    ## see the documentation of `GC_ref`.
+
+template accumulateResult*(iter: expr) =
+  ## helps to convert an iterator to a proc.
+  result = @[]
+  for x in iter: add(result, x)
+
+# we have to compute this here before turning it off in except.nim anyway ...
+const NimStackTrace = compileOption("stacktrace")
+
+{.push checks: off.}
+# obviously we cannot generate checking operations here :-)
+# because it would yield into an endless recursion
+# however, stack-traces are available for most parts
+# of the code
+
+var
+  globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.}
+    ## with this hook you can influence exception handling on a global level.
+    ## If not nil, every 'raise' statement ends up calling this hook. Ordinary
+    ## application code should never set this hook! You better know what you
+    ## do when setting this. If ``globalRaiseHook`` returns false, the
+    ## exception is caught and does not propagate further through the call
+    ## stack.
+
+  localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.}
+    ## with this hook you can influence exception handling on a
+    ## thread local level.
+    ## If not nil, every 'raise' statement ends up calling this hook. Ordinary
+    ## application code should never set this hook! You better know what you
+    ## do when setting this. If ``localRaiseHook`` returns false, the exception
+    ## is caught and does not propagate further through the call stack.
+
+  outOfMemHook*: proc () {.nimcall, tags: [], benign.}
+    ## set this variable to provide a procedure that should be called
+    ## in case of an `out of memory`:idx: event. The standard handler
+    ## writes an error message and terminates the program. `outOfMemHook` can
+    ## be used to raise an exception in case of OOM like so:
+    ##
+    ## .. code-block:: nim
+    ##
+    ##   var gOutOfMem: ref EOutOfMemory
+    ##   new(gOutOfMem) # need to be allocated *before* OOM really happened!
+    ##   gOutOfMem.msg = "out of memory"
+    ##
+    ##   proc handleOOM() =
+    ##     raise gOutOfMem
+    ##
+    ##   system.outOfMemHook = handleOOM
+    ##
+    ## If the handler does not raise an exception, ordinary control flow
+    ## continues and the program is terminated.
+
+type
+  PFrame* = ptr TFrame  ## represents a runtime frame of the call stack;
+                        ## part of the debugger API.
+  TFrame* {.importc, nodecl, final.} = object ## the frame itself
+    prev*: PFrame       ## previous frame; used for chaining the call stack
+    procname*: cstring  ## name of the proc that is currently executing
+    line*: int          ## line number of the proc that is currently executing
+    filename*: cstring  ## filename of the proc that is currently executing
+    len*: int16         ## length of the inspectable slots
+    calldepth*: int16   ## used for max call depth checking
+
+when defined(JS):
+  proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
+    asm """
+      var len = `x`[0].length-1;
+      for (var i = 0; i < `y`.length; ++i) {
+        `x`[0][len] = `y`.charCodeAt(i);
+        ++len;
+      }
+      `x`[0][len] = 0
+    """
+  proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
+
+elif hostOS != "standalone":
+  {.push stack_trace:off, profiler:off.}
+  proc add*(x: var string, y: cstring) =
+    var i = 0
+    while y[i] != '\0':
+      add(x, y[i])
+      inc(i)
+  {.pop.}
+
+proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect],
+  benign, sideEffect.}
+  ## Writes and flushes the parameters to the standard output.
+  ##
+  ## Special built-in that takes a variable number of arguments. Each argument
+  ## is converted to a string via ``$``, so it works for user-defined
+  ## types that have an overloaded ``$`` operator.
+  ## It is roughly equivalent to ``writeln(stdout, x); flushFile(stdout)``, but
+  ## available for the JavaScript target too.
+  ##
+  ## Unlike other IO operations this is guaranteed to be thread-safe as
+  ## ``echo`` is very often used for debugging convenience. If you want to use
+  ## ``echo`` inside a `proc without side effects
+  ## <manual.html#pragmas-nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
+  ## instead.
+
+proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect,
+                                           tags: [], raises: [].}
+  ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
+  ## pretends to be free of side effects, so that it can be used for debugging
+  ## routines marked as `noSideEffect <manual.html#pragmas-nosideeffect-pragma>`_.
+
+template newException*(exceptn: typedesc, message: string): expr =
+  ## creates an exception object of type ``exceptn`` and sets its ``msg`` field
+  ## to `message`. Returns the new exception object.
+  var
+    e: ref exceptn
+  new(e)
+  e.msg = message
+  e
+
+when hostOS == "standalone":
+  include panicoverride
+
+when not declared(sysFatal):
+  when hostOS == "standalone":
+    proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
+      panic(message)
+
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} =
+      rawoutput(message)
+      panic(arg)
+  else:
+    proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} =
+      var e: ref exceptn
+      new(e)
+      e.msg = message
+      raise e
+
+    proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
+      var e: ref exceptn
+      new(e)
+      e.msg = message & arg
+      raise e
+
+proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.}
+  ## get type information for `x`. Ordinary code should not use this, but
+  ## the `typeinfo` module instead.
+
+{.push stackTrace: off.}
+proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} =
+  if x < 0: -x else: x
+proc abs*(x: int8): int8 {.magic: "AbsI", noSideEffect.} =
+  if x < 0: -x else: x
+proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} =
+  if x < 0: -x else: x
+proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} =
+  if x < 0: -x else: x
+proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
+  ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
+  ## is -MININT for its type), an overflow exception is thrown (if overflow
+  ## checking is turned on).
+  if x < 0: -x else: x
+{.pop.}
+
+when not defined(JS): #and not defined(NimrodVM):
+  {.push stack_trace: off, profiler:off.}
+
+  when not defined(NimrodVM) and hostOS != "standalone":
+    proc initGC()
+    when not defined(boehmgc) and not defined(useMalloc):
+      proc initAllocator() {.inline.}
+
+    proc initStackBottom() {.inline, compilerproc.} =
+      # WARNING: This is very fragile! An array size of 8 does not work on my
+      # Linux 64bit system. -- That's because the stack direction is the other
+      # way round.
+      when declared(setStackBottom):
+        var locals {.volatile.}: pointer
+        locals = addr(locals)
+        setStackBottom(locals)
+
+    proc initStackBottomWith(locals: pointer) {.inline, compilerproc.} =
+      # We need to keep initStackBottom around for now to avoid
+      # bootstrapping problems.
+      when declared(setStackBottom):
+        setStackBottom(locals)
+
+    var
+      strDesc: TNimType
+
+    strDesc.size = sizeof(string)
+    strDesc.kind = tyString
+    strDesc.flags = {ntfAcyclic}
+
+  include "system/ansi_c"
+
+  proc cmp(x, y: string): int =
+    result = int(c_strcmp(x, y))
+
+  const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
+  when not defined(NimrodVM):
+    when defined(windows):
+      # work-around C's sucking abstraction:
+      # BUGFIX: stdin and stdout should be binary files!
+      proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
+                                        header: "<io.h>".}
+      proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
+                                            header: "<fcntl.h>".}
+      var
+        O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
+
+      # we use binary mode in Windows:
+      setmode(fileno(c_stdin), O_BINARY)
+      setmode(fileno(c_stdout), O_BINARY)
+
+    when defined(endb):
+      proc endbStep()
+
+  # ----------------- IO Part ------------------------------------------------
+  when hostOS != "standalone":
+    type
+      CFile {.importc: "FILE", header: "<stdio.h>",
+              final, incompletestruct.} = object
+      File* = ptr CFile ## The type representing a file handle.
+
+      FileMode* = enum           ## The file mode when opening a file.
+        fmRead,                   ## Open the file for read access only.
+        fmWrite,                  ## Open the file for write access only.
+        fmReadWrite,              ## Open the file for read and write access.
+                                  ## If the file does not exist, it will be
+                                  ## created.
+        fmReadWriteExisting,      ## Open the file for read and write access.
+                                  ## If the file does not exist, it will not be
+                                  ## created.
+        fmAppend                  ## Open the file for writing only; append data
+                                  ## at the end.
+
+      FileHandle* = cint ## type that represents an OS file handle; this is
+                         ## useful for low-level file access
+
+    {.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].}
+
+    # text file handling:
+    var
+      stdin* {.importc: "stdin", header: "<stdio.h>".}: File
+        ## The standard input stream.
+      stdout* {.importc: "stdout", header: "<stdio.h>".}: File
+        ## The standard output stream.
+      stderr* {.importc: "stderr", header: "<stdio.h>".}: File
+        ## The standard error stream.
+
+    when defined(useStdoutAsStdmsg):
+      template stdmsg*: File = stdout
+    else:
+      template stdmsg*: File = stderr
+        ## Template which expands to either stdout or stderr depending on
+        ## `useStdoutAsStdmsg` compile-time switch.
+
+    proc open*(f: var File, filename: string,
+               mode: FileMode = fmRead, bufSize: int = -1): bool {.tags: [],
+               benign.}
+      ## Opens a file named `filename` with given `mode`.
+      ##
+      ## Default mode is readonly. Returns true iff the file could be opened.
+      ## This throws no exception if the file could not be opened.
+
+    proc open*(f: var File, filehandle: FileHandle,
+               mode: FileMode = fmRead): bool {.tags: [], benign.}
+      ## Creates a ``TFile`` from a `filehandle` with given `mode`.
+      ##
+      ## Default mode is readonly. Returns true iff the file could be opened.
+
+    proc open*(filename: string,
+               mode: FileMode = fmRead, bufSize: int = -1): File =
+      ## Opens a file named `filename` with given `mode`.
+      ##
+      ## Default mode is readonly. Raises an ``IO`` exception if the file
+      ## could not be opened.
+      if not open(result, filename, mode, bufSize):
+        sysFatal(IOError, "cannot open: ", filename)
+
+    proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {.
+      tags: [], benign.}
+      ## reopens the file `f` with given `filename` and `mode`. This
+      ## is often used to redirect the `stdin`, `stdout` or `stderr`
+      ## file variables.
+      ##
+      ## Default mode is readonly. Returns true iff the file could be reopened.
+
+    proc close*(f: File) {.importc: "fclose", header: "<stdio.h>", tags: [].}
+      ## Closes the file.
+
+    proc endOfFile*(f: File): bool {.tags: [], benign.}
+      ## Returns true iff `f` is at the end.
+
+    proc readChar*(f: File): char {.
+      importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
+      ## Reads a single character from the stream `f`.
+    proc flushFile*(f: File) {.
+      importc: "fflush", header: "<stdio.h>", tags: [WriteIOEffect].}
+      ## Flushes `f`'s buffer.
+
+    proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.}
+      ## Reads all data from the stream `file`.
+      ##
+      ## Raises an IO exception in case of an error. It is an error if the
+      ## current file position is not at the beginning of the file.
+
+    proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
+      ## Opens a file named `filename` for reading.
+      ##
+      ## Then calls `readAll <#readAll>`_ and closes the file afterwards.
+      ## Returns the string.  Raises an IO exception in case of an error. If
+      ## you need to call this inside a compile time macro you can use
+      ## `staticRead <#staticRead>`_.
+
+    proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.}
+      ## Opens a file named `filename` for writing. Then writes the
+      ## `content` completely to the file and closes the file afterwards.
+      ## Raises an IO exception in case of an error.
+
+    proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, i: BiggestInt) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, c: char) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.}
+    proc write*(f: File, a: varargs[string, `$`]) {.tags: [WriteIOEffect], benign.}
+      ## Writes a value to the file `f`. May throw an IO exception.
+
+    proc readLine*(f: File): TaintedString  {.tags: [ReadIOEffect], benign.}
+      ## reads a line of text from the file `f`. May throw an IO exception.
+      ## A line of text may be delimited by ``CR``, ``LF`` or
+      ## ``CRLF``. The newline character(s) are not part of the returned string.
+
+    proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
+                  benign.}
+      ## reads a line of text from the file `f` into `line`. `line` must not be
+      ## ``nil``! May throw an IO exception.
+      ## A line of text may be delimited by ``CR``, ``LF`` or
+      ## ``CRLF``. The newline character(s) are not part of the returned string.
+      ## Returns ``false`` if the end of the file has been reached, ``true``
+      ## otherwise. If ``false`` is returned `line` contains no new data.
+
+    proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
+                             tags: [WriteIOEffect], benign.}
+      ## writes the values `x` to `f` and then writes "\n".
+      ## May throw an IO exception.
+
+    proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.}
+      ## retrieves the file size (in bytes) of `f`.
+
+    proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {.
+      tags: [ReadIOEffect], benign.}
+      ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+      ## the actual number of bytes that have been read which may be less than
+      ## `len` (if not as many bytes are remaining), but not greater.
+
+    proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {.
+      tags: [ReadIOEffect], benign.}
+      ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
+      ## the actual number of bytes that have been read which may be less than
+      ## `len` (if not as many bytes are remaining), but not greater.
+
+    proc readBuffer*(f: File, buffer: pointer, len: Natural): int {.
+      tags: [ReadIOEffect], benign.}
+      ## reads `len` bytes into the buffer pointed to by `buffer`. Returns
+      ## the actual number of bytes that have been read which may be less than
+      ## `len` (if not as many bytes are remaining), but not greater.
+
+    proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {.
+      tags: [WriteIOEffect], benign.}
+      ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+      ## the number of actual written bytes, which may be less than `len` in case
+      ## of an error.
+
+    proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {.
+      tags: [WriteIOEffect], benign.}
+      ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
+      ## the number of actual written bytes, which may be less than `len` in case
+      ## of an error.
+
+    proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {.
+      tags: [WriteIOEffect], benign.}
+      ## writes the bytes of buffer pointed to by the parameter `buffer` to the
+      ## file `f`. Returns the number of actual written bytes, which may be less
+      ## than `len` in case of an error.
+
+    proc setFilePos*(f: File, pos: int64) {.benign.}
+      ## sets the position of the file pointer that is used for read/write
+      ## operations. The file's first byte has the index zero.
+
+    proc getFilePos*(f: File): int64 {.benign.}
+      ## retrieves the current position of the file pointer that is used to
+      ## read from the file `f`. The file's first byte has the index zero.
+
+    proc getFileHandle*(f: File): FileHandle {.importc: "fileno",
+                                               header: "<stdio.h>"}
+      ## returns the OS file handle of the file ``f``. This is only useful for
+      ## platform specific programming.
+
+    when not defined(nimfix):
+      {.deprecated: [fileHandle: getFileHandle].}
+
+    proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
+      ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
+      ## of length ``len``.
+      newSeq(result, len)
+      for i in 0..len-1: result[i] = $a[i]
+
+    proc cstringArrayToSeq*(a: cstringArray): seq[string] =
+      ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
+      ## terminated by ``nil``.
+      var L = 0
+      while a[L] != nil: inc(L)
+      result = cstringArrayToSeq(a, L)
+
+  # -------------------------------------------------------------------------
+
+  when not defined(NimrodVM) and hostOS != "standalone":
+    proc allocCStringArray*(a: openArray[string]): cstringArray =
+      ## creates a NULL terminated cstringArray from `a`. The result has to
+      ## be freed with `deallocCStringArray` after it's not needed anymore.
+      result = cast[cstringArray](alloc0((a.len+1) * sizeof(cstring)))
+      let x = cast[ptr array[0..20_000, string]](a)
+      for i in 0 .. a.high:
+        result[i] = cast[cstring](alloc0(x[i].len+1))
+        copyMem(result[i], addr(x[i][0]), x[i].len)
+
+    proc deallocCStringArray*(a: cstringArray) =
+      ## frees a NULL terminated cstringArray.
+      var i = 0
+      while a[i] != nil:
+        dealloc(a[i])
+        inc(i)
+      dealloc(a)
+
+  when not defined(NimrodVM):
+    proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
+      discardable, benign.}
+      ## atomic increment of `memLoc`. Returns the value after the operation.
+
+    proc atomicDec*(memLoc: var int, x: int = 1): int {.inline,
+      discardable, benign.}
+      ## atomic decrement of `memLoc`. Returns the value after the operation.
+
+    include "system/atomics"
+
+  type
+    PSafePoint = ptr TSafePoint
+    TSafePoint {.compilerproc, final.} = object
+      prev: PSafePoint # points to next safe point ON THE STACK
+      status: int
+      context: C_JmpBuf
+      hasRaiseAction: bool
+      raiseAction: proc (e: ref Exception): bool {.closure.}
+
+  when declared(initAllocator):
+    initAllocator()
+  when hasThreadSupport:
+    include "system/syslocks"
+    when hostOS != "standalone": include "system/threads"
+  elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone":
+    when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
+    initGC()
+
+  when not defined(NimrodVM):
+    proc setControlCHook*(hook: proc () {.noconv.} not nil)
+      ## allows you to override the behaviour of your application when CTRL+C
+      ## is pressed. Only one such hook is supported.
+
+    proc writeStackTrace*() {.tags: [WriteIOEffect].}
+      ## writes the current stack trace to ``stderr``. This is only works
+      ## for debug builds.
+    when hostOS != "standalone":
+      proc getStackTrace*(): string
+        ## gets the current stack trace. This only works for debug builds.
+
+      proc getStackTrace*(e: ref Exception): string
+        ## gets the stack trace associated with `e`, which is the stack that
+        ## lead to the ``raise`` statement. This only works for debug builds.
+
+    {.push stack_trace: off, profiler:off.}
+    when hostOS == "standalone":
+      include "system/embedded"
+    else:
+      include "system/excpt"
+    include "system/chcks"
+
+    # we cannot compile this with stack tracing on
+    # as it would recurse endlessly!
+    include "system/arithm"
+    {.pop.} # stack trace
+  {.pop.} # stack trace
+
+  when hostOS != "standalone" and not defined(NimrodVM):
+    include "system/dyncalls"
+  when not defined(NimrodVM):
+    include "system/sets"
+
+    const
+      GenericSeqSize = (2 * sizeof(int))
+
+    proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
+      sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
+      var d: int
+      var a = cast[ByteAddress](aa)
+      case n.typ.size
+      of 1: d = ze(cast[ptr int8](a +% n.offset)[])
+      of 2: d = ze(cast[ptr int16](a +% n.offset)[])
+      of 4: d = int(cast[ptr int32](a +% n.offset)[])
+      else: sysAssert(false, "getDiscriminant: invalid n.typ.size")
+      return d
+
+    proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
+      var discr = getDiscriminant(aa, n)
+      if discr <% n.len:
+        result = n.sons[discr]
+        if result == nil: result = n.sons[n.len]
+        # n.sons[n.len] contains the ``else`` part (but may be nil)
+      else:
+        result = n.sons[n.len]
+
+    when hostOS != "standalone": include "system/mmdisp"
+    {.push stack_trace: off, profiler:off.}
+    when hostOS != "standalone": include "system/sysstr"
+    {.pop.}
+
+    when hostOS != "standalone": include "system/sysio"
+    when hasThreadSupport:
+      when hostOS != "standalone": include "system/channels"
+  else:
+    include "system/sysio"
+
+  when hostOS != "standalone":
+    iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} =
+      ## Iterates over any line in the file named `filename`.
+      ##
+      ## If the file does not exist `EIO` is raised. The trailing newline
+      ## character(s) are removed from the iterated lines. Example:
+      ##
+      ## .. code-block:: nim
+      ##   import strutils
+      ##
+      ##   proc transformLetters(filename: string) =
+      ##     var buffer = ""
+      ##     for line in filename.lines:
+      ##       buffer.add(line.replace("a", "0") & '\x0A')
+      ##     writeFile(filename, buffer)
+      var f = open(filename, bufSize=8000)
+      var res = TaintedString(newStringOfCap(80))
+      while f.readLine(res): yield res
+      close(f)
+
+    iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} =
+      ## Iterate over any line in the file `f`.
+      ##
+      ## The trailing newline character(s) are removed from the iterated lines.
+      ## Example:
+      ##
+      ## .. code-block:: nim
+      ##   proc countZeros(filename: File): tuple[lines, zeros: int] =
+      ##     for line in filename.lines:
+      ##       for letter in line:
+      ##         if letter == '0':
+      ##           result.zeros += 1
+      ##       result.lines += 1
+      var res = TaintedString(newStringOfCap(80))
+      while f.readLine(res): yield res
+
+  when hostOS != "standalone" and not defined(NimrodVM):
+    include "system/assign"
+    include "system/repr"
+
+    proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} =
+      ## retrieves the current exception; if there is none, nil is returned.
+      result = currException
+
+    proc getCurrentExceptionMsg*(): string {.inline, benign.} =
+      ## retrieves the error message that was attached to the current
+      ## exception; if there is none, "" is returned.
+      var e = getCurrentException()
+      return if e == nil: "" else: e.msg
+
+    proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) =
+      ## can be used in a ``try`` statement to setup a Lisp-like
+      ## `condition system`:idx:\: This prevents the 'raise' statement to
+      ## raise an exception but instead calls ``action``.
+      ## If ``action`` returns false, the exception has been handled and
+      ## does not propagate further through the call stack.
+      if not isNil(excHandler):
+        excHandler.hasRaiseAction = true
+        excHandler.raiseAction = action
+
+    proc setCurrentException*(exc: ref Exception) {.inline, benign.} =
+      ## sets the current exception.
+      ##
+      ## **Warning**: Only use this if you know what you are doing.
+      currException = exc
+
+  {.push stack_trace: off, profiler:off.}
+  when defined(endb) and not defined(NimrodVM):
+    include "system/debugger"
+
+  when defined(profiler) or defined(memProfiler):
+    include "system/profiler"
+  {.pop.} # stacktrace
+
+  when not defined(NimrodVM):
+    proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
+      ## Hints the optimizer that `val` is likely going to be true.
+      ##
+      ## You can use this proc to decorate a branch condition. On certain
+      ## platforms this can help the processor predict better which branch is
+      ## going to be run. Example:
+      ##
+      ## .. code-block:: nim
+      ##   for value in inputValues:
+      ##     if likely(value <= 100):
+      ##       process(value)
+      ##     else:
+      ##       echo "Value too big!"
+
+    proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
+      ## Hints the optimizer that `val` is likely going to be false.
+      ##
+      ## You can use this proc to decorate a branch condition. On certain
+      ## platforms this can help the processor predict better which branch is
+      ## going to be run. Example:
+      ##
+      ## .. code-block:: nim
+      ##   for value in inputValues:
+      ##     if unlikely(value > 100):
+      ##       echo "Value too big!"
+      ##     else:
+      ##       process(value)
+
+    proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
+      ## retrieves the raw proc pointer of the closure `x`. This is
+      ## useful for interfacing closures with C.
+      {.emit: """
+      `result` = `x`.ClPrc;
+      """.}
+
+    proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} =
+      ## retrieves the raw environment pointer of the closure `x`. This is
+      ## useful for interfacing closures with C.
+      {.emit: """
+      `result` = `x`.ClEnv;
+      """.}
+
+    proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} =
+      ## can be used to determine if a first class iterator has finished.
+      {.emit: """
+      `result` = *((NI*) `x`.ClEnv) < 0;
+      """.}
+
+elif defined(JS):
+  # Stubs:
+  proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
+
+  proc GC_disable() = discard
+  proc GC_enable() = discard
+  proc GC_fullCollect() = discard
+  proc GC_setStrategy(strategy: GC_Strategy) = discard
+  proc GC_enableMarkAndSweep() = discard
+  proc GC_disableMarkAndSweep() = discard
+  proc GC_getStatistics(): string = return ""
+
+  proc getOccupiedMem(): int = return -1
+  proc getFreeMem(): int = return -1
+  proc getTotalMem(): int = return -1
+
+  proc dealloc(p: pointer) = discard
+  proc alloc(size: Natural): pointer = discard
+  proc alloc0(size: Natural): pointer = discard
+  proc realloc(p: pointer, newsize: Natural): pointer = discard
+
+  proc allocShared(size: Natural): pointer = discard
+  proc allocShared0(size: Natural): pointer = discard
+  proc deallocShared(p: pointer) = discard
+  proc reallocShared(p: pointer, newsize: Natural): pointer = discard
+
+  when defined(JS):
+    include "system/jssys"
+    include "system/reprjs"
+  elif defined(NimrodVM):
+    proc cmp(x, y: string): int =
+      if x == y: return 0
+      if x < y: return -1
+      return 1
+
+  when defined(nimffi):
+    include "system/sysio"
+
+
+proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
+  ## a shorthand for ``echo(errormsg); quit(errorcode)``.
+  echo(errormsg)
+  quit(errorcode)
+
+{.pop.} # checks
+{.pop.} # hints
+
+proc `/`*(x, y: int): float {.inline, noSideEffect.} =
+  ## integer division that results in a float.
+  result = toFloat(x) / toFloat(y)
+
+template `-|`*(b, s: expr): expr =
+  (if b >= 0: b else: s.len + b)
+
+template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
+  # make room for additional elements or cut:
+  var slen = s.len
+  var shift = b.len - L
+  var newLen = slen + shift
+  if shift > 0:
+    # enlarge:
+    setLen(s, newLen)
+    for i in countdown(newLen-1, a+shift+1): shallowCopy(s[i], s[i-shift])
+  else:
+    for i in countup(a+b.len, s.len-1+shift): shallowCopy(s[i], s[i-shift])
+    # cut down:
+    setLen(s, newLen)
+  # fill the hole:
+  for i in 0 .. <b.len: s[i+a] = b[i]
+
+when hostOS != "standalone":
+  proc `[]`*(s: string, x: Slice[int]): string {.inline.} =
+    ## slice operation for strings.
+    result = s.substr(x.a, x.b)
+
+  proc `[]=`*(s: var string, x: Slice[int], b: string) =
+    ## slice assignment for strings. If
+    ## ``b.len`` is not exactly the number of elements that are referred to
+    ## by `x`, a `splice`:idx: is performed:
+    ##
+    ## .. code-block:: nim
+    ##   var s = "abcdef"
+    ##   s[1 .. ^2] = "xyz"
+    ##   assert s == "axyzf"
+    var a = x.a
+    var L = x.b - a + 1
+    if L == b.len:
+      for i in 0 .. <L: s[i+a] = b[i]
+    else:
+      spliceImpl(s, a, L, b)
+
+proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
+  ## slice operation for arrays.
+  when low(a) < 0:
+    {.error: "Slicing for arrays with negative indices is unsupported.".}
+  var L = x.b - x.a + 1
+  newSeq(result, L)
+  for i in 0.. <L: result[i] = a[i + x.a]
+
+proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
+  ## slice assignment for arrays.
+  when low(a) < 0:
+    {.error: "Slicing for arrays with negative indices is unsupported.".}
+  var L = x.b - x.a + 1
+  if L == b.len:
+    for i in 0 .. <L: a[i+x.a] = b[i]
+  else:
+    sysFatal(RangeError, "different lengths for slice assignment")
+
+proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
+  ## slice operation for arrays.
+  var L = ord(x.b) - ord(x.a) + 1
+  newSeq(result, L)
+  for i in 0.. <L:
+    result[i] = a[Idx(ord(x.a) + i)]
+
+proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
+  ## slice assignment for arrays.
+  var L = ord(x.b) - ord(x.a) + 1
+  if L == b.len:
+    for i in 0 .. <L:
+      a[Idx(ord(x.a) + i)] = b[i]
+  else:
+    sysFatal(RangeError, "different lengths for slice assignment")
+
+proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] =
+  ## slice operation for sequences.
+  var a = x.a
+  var L = x.b - a + 1
+  newSeq(result, L)
+  for i in 0.. <L: result[i] = s[i + a]
+
+proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) =
+  ## slice assignment for sequences. If
+  ## ``b.len`` is not exactly the number of elements that are referred to
+  ## by `x`, a `splice`:idx: is performed.
+  var a = x.a
+  var L = x.b - a + 1
+  if L == b.len:
+    for i in 0 .. <L: s[i+a] = b[i]
+  else:
+    spliceImpl(s, a, L, b)
+
+proc slurp*(filename: string): string {.magic: "Slurp".}
+  ## This is an alias for `staticRead <#staticRead>`_.
+
+proc staticRead*(filename: string): string {.magic: "Slurp".}
+  ## Compile-time `readFile <#readFile>`_ proc for easy `resource`:idx:
+  ## embedding:
+  ##
+  ## .. code-block:: nim
+  ##     const myResource = staticRead"mydatafile.bin"
+  ##
+  ## `slurp <#slurp>`_ is an alias for ``staticRead``.
+
+proc gorge*(command: string, input = ""): string {.
+  magic: "StaticExec".} = discard
+  ## This is an alias for `staticExec <#staticExec>`_.
+
+proc staticExec*(command: string, input = ""): string {.
+  magic: "StaticExec".} = discard
+  ## Executes an external process at compile-time.
+  ## if `input` is not an empty string, it will be passed as a standard input
+  ## to the executed program.
+  ##
+  ## .. code-block:: nim
+  ##     const buildInfo = "Revision " & staticExec("git rev-parse HEAD") &
+  ##                       "\nCompiled on " & staticExec("uname -v")
+  ##
+  ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use
+  ## this proc inside a pragma like `passC <nimc.html#passc-pragma>`_ or `passL
+  ## <nimc.html#passl-pragma>`_.
+
+proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.}
+  ## Increments an ordinal
+
+proc `-=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Dec", noSideEffect.}
+  ## Decrements an ordinal
+
+proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.inline, noSideEffect.} =
+  ## Binary `*=` operator for ordinals
+  x = x * y
+
+proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
+  ## Increments in placee a floating point number
+  x = x + y
+
+proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
+  ## Decrements in place a floating point number
+  x = x - y
+
+proc `*=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} =
+  ## Multiplies in place a floating point number
+  x = x * y
+
+proc `/=`*(x: var float64, y: float64) {.inline, noSideEffect.} =
+  ## Divides in place a floating point number
+  x = x / y
+
+proc `/=`*[T: float|float32](x: var T, y: T) {.inline, noSideEffect.} =
+  ## Divides in place a floating point number
+  x = x / y
+
+proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
+
+proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.}
+  ## converts the AST of `x` into a string representation. This is very useful
+  ## for debugging.
+
+proc instantiationInfo*(index = -1, fullPaths = false): tuple[
+  filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.}
+  ## provides access to the compiler's instantiation stack line information.
+  ##
+  ## This proc is mostly useful for meta programming (eg. ``assert`` template)
+  ## to retrieve information about the current filename and line number.
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   import strutils
+  ##
+  ##   template testException(exception, code: expr): stmt =
+  ##     try:
+  ##       let pos = instantiationInfo()
+  ##       discard(code)
+  ##       echo "Test failure at $1:$2 with '$3'" % [pos.filename,
+  ##         $pos.line, astToStr(code)]
+  ##       assert false, "A test expecting failure succeeded?"
+  ##     except exception:
+  ##       discard
+  ##
+  ##   proc tester(pos: int): int =
+  ##     let
+  ##       a = @[1, 2, 3]
+  ##     result = a[pos]
+  ##
+  ##   when isMainModule:
+  ##     testException(IndexError, tester(30))
+  ##     testException(IndexError, tester(1))
+  ##     # --> Test failure at example.nim:20 with 'tester(1)'
+
+template currentSourcePath*: string = instantiationInfo(-1, true).filename
+  ## returns the full file-system path of the current source
+
+proc raiseAssert*(msg: string) {.noinline.} =
+  sysFatal(AssertionError, msg)
+
+proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
+  # trick the compiler to not list ``AssertionError`` when called
+  # by ``assert``.
+  type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
+                                    tags: [].}
+  THide(raiseAssert)(msg)
+
+template assert*(cond: bool, msg = "") =
+  ## Raises ``AssertionError`` with `msg` if `cond` is false. Note
+  ## that ``AssertionError`` is hidden from the effect system, so it doesn't
+  ## produce ``{.raises: [AssertionError].}``. This exception is only supposed
+  ## to be caught by unit testing frameworks.
+  ## The compiler may not generate any code at all for ``assert`` if it is
+  ## advised to do so through the ``-d:release`` or ``--assertions:off``
+  ## `command line switches <nimc.html#command-line-switches>`_.
+  bind instantiationInfo
+  mixin failedAssertImpl
+  when compileOption("assertions"):
+    {.line.}:
+      if not cond: failedAssertImpl(astToStr(cond) & ' ' & msg)
+
+template doAssert*(cond: bool, msg = "") =
+  ## same as `assert` but is always turned on and not affected by the
+  ## ``--assertions`` command line switch.
+  bind instantiationInfo
+  {.line: instantiationInfo().}:
+    if not cond:
+      raiseAssert(astToStr(cond) & ' ' & msg)
+
+iterator items*[T](a: seq[T]): T {.inline.} =
+  ## iterates over each item of `a`.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
+iterator mitems*[T](a: var seq[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
+iterator items*(a: string): char {.inline.} =
+  ## iterates over each item of `a`.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "string modified while iterating over it")
+
+iterator mitems*(a: var string): var char {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "string modified while iterating over it")
+
+when not defined(nimhygiene):
+  {.pragma: inject.}
+
+template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
+  ## Sets an assertion failure handler that will intercept any assert
+  ## statements following `onFailedAssert` in the current module scope.
+  ##
+  ## .. code-block:: nim
+  ##  # module-wide policy to change the failed assert
+  ##  # exception type in order to include a lineinfo
+  ##  onFailedAssert(msg):
+  ##    var e = new(TMyError)
+  ##    e.msg = msg
+  ##    e.lineinfo = instantiationInfo(-2)
+  ##    raise e
+  ##
+  template failedAssertImpl(msgIMPL: string): stmt {.dirty.} =
+    let msg = msgIMPL
+    code
+
+proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
+  ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
+  ## perform deep copies of `s`. This is only useful for optimization
+  ## purposes.
+  when not defined(JS) and not defined(NimrodVM):
+    var s = cast[PGenericSeq](s)
+    s.reserved = s.reserved or seqShallowFlag
+
+proc shallow*(s: var string) {.noSideEffect, inline.} =
+  ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
+  ## perform deep copies of `s`. This is only useful for optimization
+  ## purposes.
+  when not defined(JS) and not defined(NimrodVM):
+    var s = cast[PGenericSeq](s)
+    s.reserved = s.reserved or seqShallowFlag
+
+type
+  NimNodeObj = object
+
+  NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
+    ## represents a Nim AST node. Macros operate on this type.
+{.deprecated: [PNimrodNode: NimNode].}
+
+when false:
+  template eval*(blk: stmt): stmt =
+    ## executes a block of code at compile time just as if it was a macro
+    ## optionally, the block can return an AST tree that will replace the
+    ## eval expression
+    macro payload: stmt {.gensym.} = blk
+    payload()
+
+when hostOS != "standalone":
+  proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} =
+    ## inserts `item` into `x` at position `i`.
+    var xl = x.len
+    setLen(x, xl+item.len)
+    var j = xl-1
+    while j >= i:
+      shallowCopy(x[j+item.len], x[j])
+      dec(j)
+    j = 0
+    while j < item.len:
+      x[j+i] = item[j]
+      inc(j)
+
+proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
+  ## Special compile-time procedure that checks whether `x` can be compiled
+  ## without any semantic error.
+  ## This can be used to check whether a type supports some operation:
+  ##
+  ## .. code-block:: Nim
+  ##   when not compiles(3 + 4):
+  ##     echo "'+' for integers is available"
+  discard
+
+when declared(initDebugger):
+  initDebugger()
+
+when hostOS != "standalone":
+  # XXX: make these the default (or implement the NilObject optimization)
+  proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} =
+    if x == nil: x = @[y]
+    else: x.add(y)
+
+  proc safeAdd*(x: var string, y: char) =
+    if x == nil: x = ""
+    x.add(y)
+
+  proc safeAdd*(x: var string, y: string) =
+    if x == nil: x = y
+    else: x.add(y)
+
+proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
+  ## generates a tuple constructor expression listing all the local variables
+  ## in the current scope. This is quite fast as it does not rely
+  ## on any debug or runtime information. Note that in constrast to what
+  ## the official signature says, the return type is not ``RootObj`` but a
+  ## tuple of a structure that depends on the current scope. Example:
+  ##
+  ## .. code-block:: nim
+  ##   proc testLocals() =
+  ##     var
+  ##       a = "something"
+  ##       b = 4
+  ##       c = locals()
+  ##       d = "super!"
+  ##
+  ##     b = 1
+  ##     for name, value in fieldPairs(c):
+  ##       echo "name ", name, " with value ", value
+  ##     echo "B is ", b
+  ##   # -> name a with value something
+  ##   # -> name b with value 4
+  ##   # -> B is 1
+  discard
+
+when hostOS != "standalone" and not defined(NimrodVM) and not defined(JS):
+  proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} =
+    ## performs a deep copy of `x`. This is also used by the code generator
+    ## for the implementation of ``spawn``.
+    discard
+
+  include "system/deepcopy"
+
+proc procCall*(x: expr) {.magic: "ProcCall".} =
+  ## special magic to prohibit dynamic binding for `method`:idx: calls.
+  ## This is similar to `super`:idx: in ordinary OO languages.
+  ##
+  ## .. code-block:: nim
+  ##   # 'someMethod' will be resolved fully statically:
+  ##   procCall someMethod(a, b)
+  discard
+
+proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
+  ## builtin `roof`:idx: operator that can be used for convenient array access.
+  ## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a``
+  ## expression must not have side effects for this to compile. Note that since
+  ## this is a builtin, it automatically works for all kinds of
+  ## overloaded ``[]`` or ``[]=`` accessors.
+  discard
+
+template `..^`*(a, b: expr): expr =
+  ## a shortcut for '.. ^' to avoid the common gotcha that a space between
+  ## '..' and '^' is required.
+  a .. ^b
+
+template `..<`*(a, b: expr): expr =
+  ## a shortcut for '.. <' to avoid the common gotcha that a space between
+  ## '..' and '<' is required.
+  a .. <b
+
+proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
+proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
+  ## returns the length of a sequence or a string without testing for 'nil'.
+  ## This is an optimization that rarely makes sense.
+  discard
+
+{.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.}
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
new file mode 100644
index 000000000..ad3419808
--- /dev/null
+++ b/lib/system/alloc.nim
@@ -0,0 +1,854 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Low level allocator for Nim. Has been designed to support the GC.
+# TODO:
+# - eliminate "used" field
+# - make searching for block O(1)
+{.push profiler:off.}
+
+# ------------ platform specific chunk allocation code -----------------------
+
+# some platforms have really weird unmap behaviour: unmap(blockStart, PageSize)
+# really frees the whole block. Happens for Linux/PowerPC for example. Amd64
+# and x86 are safe though; Windows is special because MEM_RELEASE can only be
+# used with a size of 0:
+const weirdUnmap = not (defined(amd64) or defined(i386)) or defined(windows)
+
+when defined(posix):
+  const
+    PROT_READ  = 1             # page can be read
+    PROT_WRITE = 2             # page can be written
+    MAP_PRIVATE = 2'i32        # Changes are private
+
+  when defined(macosx) or defined(bsd):
+    const MAP_ANONYMOUS = 0x1000
+  elif defined(solaris):
+    const MAP_ANONYMOUS = 0x100
+  else:
+    var
+      MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
+
+  proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
+            off: int): pointer {.header: "<sys/mman.h>".}
+
+  proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
+
+  proc osAllocPages(size: int): pointer {.inline.} =
+    result = mmap(nil, size, PROT_READ or PROT_WRITE,
+                             MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
+    if result == nil or result == cast[pointer](-1):
+      raiseOutOfMem()
+
+  proc osDeallocPages(p: pointer, size: int) {.inline} =
+    when reallyOsDealloc: munmap(p, size)
+
+elif defined(windows):
+  const
+    MEM_RESERVE = 0x2000
+    MEM_COMMIT = 0x1000
+    MEM_TOP_DOWN = 0x100000
+    PAGE_READWRITE = 0x04
+
+    MEM_DECOMMIT = 0x4000
+    MEM_RELEASE = 0x8000
+
+  proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
+                    flProtect: int32): pointer {.
+                    header: "<windows.h>", stdcall, importc: "VirtualAlloc".}
+
+  proc virtualFree(lpAddress: pointer, dwSize: int,
+                   dwFreeType: int32) {.header: "<windows.h>", stdcall,
+                   importc: "VirtualFree".}
+
+  proc osAllocPages(size: int): pointer {.inline.} =
+    result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
+                          PAGE_READWRITE)
+    if result == nil: raiseOutOfMem()
+
+  proc osDeallocPages(p: pointer, size: int) {.inline.} =
+    # according to Microsoft, 0 is the only correct value for MEM_RELEASE:
+    # This means that the OS has some different view over how big the block is
+    # that we want to free! So, we cannot reliably release the memory back to
+    # Windows :-(. We have to live with MEM_DECOMMIT instead.
+    # Well that used to be the case but MEM_DECOMMIT fragments the address
+    # space heavily, so we now treat Windows as a strange unmap target.
+    when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE)
+    #VirtualFree(p, size, MEM_DECOMMIT)
+
+else:
+  {.error: "Port memory manager to your platform".}
+
+# --------------------- end of non-portable code -----------------------------
+
+# We manage *chunks* of memory. Each chunk is a multiple of the page size.
+# Each chunk starts at an address that is divisible by the page size. Chunks
+# that are bigger than ``ChunkOsReturn`` are returned back to the operating
+# system immediately.
+
+const
+  ChunkOsReturn = 256 * PageSize # 1 MB
+  InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
+  SmallChunkSize = PageSize
+
+type
+  PTrunk = ptr TTrunk
+  TTrunk {.final.} = object
+    next: PTrunk         # all nodes are connected with this pointer
+    key: int             # start address at bit 0
+    bits: array[0..IntsPerTrunk-1, int] # a bit vector
+
+  TTrunkBuckets = array[0..255, PTrunk]
+  TIntSet {.final.} = object
+    data: TTrunkBuckets
+
+type
+  TAlignType = BiggestFloat
+  TFreeCell {.final, pure.} = object
+    next: ptr TFreeCell  # next free cell in chunk (overlaid with refcount)
+    zeroField: int       # 0 means cell is not used (overlaid with typ field)
+                         # 1 means cell is manually managed pointer
+                         # otherwise a PNimType is stored in there
+
+  PChunk = ptr TBaseChunk
+  PBigChunk = ptr TBigChunk
+  PSmallChunk = ptr TSmallChunk
+  TBaseChunk {.pure, inheritable.} = object
+    prevSize: int        # size of previous chunk; for coalescing
+    size: int            # if < PageSize it is a small chunk
+    used: bool           # later will be optimized into prevSize...
+
+  TSmallChunk = object of TBaseChunk
+    next, prev: PSmallChunk  # chunks of the same size
+    freeList: ptr TFreeCell
+    free: int            # how many bytes remain
+    acc: int             # accumulator for small object allocation
+    data: TAlignType     # start of usable memory
+
+  TBigChunk = object of TBaseChunk # not necessarily > PageSize!
+    next, prev: PBigChunk    # chunks of the same (or bigger) size
+    align: int
+    data: TAlignType     # start of usable memory
+
+template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
+template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
+
+proc roundup(x, v: int): int {.inline.} =
+  result = (x + (v-1)) and not (v-1)
+  sysAssert(result >= x, "roundup: result < x")
+  #return ((-x) and (v-1)) +% x
+
+sysAssert(roundup(14, PageSize) == PageSize, "invalid PageSize")
+sysAssert(roundup(15, 8) == 16, "roundup broken")
+sysAssert(roundup(65, 8) == 72, "roundup broken 2")
+
+# ------------- chunk table ---------------------------------------------------
+# We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk
+# endings of big chunks. This is needed by the merging operation. The only
+# remaining operation is best-fit for big chunks. Since there is a size-limit
+# for big chunks (because greater than the limit means they are returned back
+# to the OS), a fixed size array can be used.
+
+type
+  PLLChunk = ptr TLLChunk
+  TLLChunk {.pure.} = object ## *low-level* chunk
+    size: int                # remaining size
+    acc: int                 # accumulator
+    next: PLLChunk           # next low-level chunk; only needed for dealloc
+
+  PAvlNode = ptr TAvlNode
+  TAvlNode {.pure, final.} = object
+    link: array[0..1, PAvlNode] # Left (0) and right (1) links
+    key, upperBound: int
+    level: int
+
+  TMemRegion {.final, pure.} = object
+    minLargeObj, maxLargeObj: int
+    freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
+    llmem: PLLChunk
+    currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
+    lastSize: int # needed for the case that OS gives us pages linearly
+    freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
+    chunkStarts: TIntSet
+    root, deleted, last, freeAvlNodes: PAvlNode
+
+# shared:
+var
+  bottomData: TAvlNode
+  bottom: PAvlNode
+
+{.push stack_trace: off.}
+proc initAllocator() =
+  when not defined(useNimRtl):
+    bottom = addr(bottomData)
+    bottom.link[0] = bottom
+    bottom.link[1] = bottom
+{.pop.}
+
+proc incCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
+  inc(a.currMem, bytes)
+
+proc decCurrMem(a: var TMemRegion, bytes: int) {.inline.} =
+  a.maxMem = max(a.maxMem, a.currMem)
+  dec(a.currMem, bytes)
+
+proc getMaxMem(a: var TMemRegion): int =
+  # Since we update maxPagesCount only when freeing pages,
+  # maxPagesCount may not be up to date. Thus we use the
+  # maximum of these both values here:
+  result = max(a.currMem, a.maxMem)
+
+proc llAlloc(a: var TMemRegion, size: int): pointer =
+  # *low-level* alloc for the memory managers data structures. Deallocation
+  # is done at he end of the allocator's life time.
+  if a.llmem == nil or size > a.llmem.size:
+    # the requested size is ``roundup(size+sizeof(TLLChunk), PageSize)``, but
+    # since we know ``size`` is a (small) constant, we know the requested size
+    # is one page:
+    sysAssert roundup(size+sizeof(TLLChunk), PageSize) == PageSize, "roundup 6"
+    var old = a.llmem # can be nil and is correct with nil
+    a.llmem = cast[PLLChunk](osAllocPages(PageSize))
+    incCurrMem(a, PageSize)
+    a.llmem.size = PageSize - sizeof(TLLChunk)
+    a.llmem.acc = sizeof(TLLChunk)
+    a.llmem.next = old
+  result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc)
+  dec(a.llmem.size, size)
+  inc(a.llmem.acc, size)
+  zeroMem(result, size)
+
+proc allocAvlNode(a: var TMemRegion, key, upperBound: int): PAvlNode =
+  if a.freeAvlNodes != nil:
+    result = a.freeAvlNodes
+    a.freeAvlNodes = a.freeAvlNodes.link[0]
+  else:
+    result = cast[PAvlNode](llAlloc(a, sizeof(TAvlNode)))
+  result.key = key
+  result.upperBound = upperBound
+  result.link[0] = bottom
+  result.link[1] = bottom
+  result.level = 1
+  sysAssert(bottom == addr(bottomData), "bottom data")
+  sysAssert(bottom.link[0] == bottom, "bottom link[0]")
+  sysAssert(bottom.link[1] == bottom, "bottom link[1]")
+
+proc deallocAvlNode(a: var TMemRegion, n: PAvlNode) {.inline.} =
+  n.link[0] = a.freeAvlNodes
+  a.freeAvlNodes = n
+
+include "system/avltree"
+
+proc llDeallocAll(a: var TMemRegion) =
+  var it = a.llmem
+  while it != nil:
+    # we know each block in the list has the size of 1 page:
+    var next = it.next
+    osDeallocPages(it, PageSize)
+    it = next
+
+proc intSetGet(t: TIntSet, key: int): PTrunk =
+  var it = t.data[key and high(t.data)]
+  while it != nil:
+    if it.key == key: return it
+    it = it.next
+  result = nil
+
+proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
+  result = intSetGet(t, key)
+  if result == nil:
+    result = cast[PTrunk](llAlloc(a, sizeof(result[])))
+    result.next = t.data[key and high(t.data)]
+    t.data[key and high(t.data)] = result
+    result.key = key
+
+proc contains(s: TIntSet, key: int): bool =
+  var t = intSetGet(s, key shr TrunkShift)
+  if t != nil:
+    var u = key and TrunkMask
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+  else:
+    result = false
+
+proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
+  var t = intSetPut(a, s, key shr TrunkShift)
+  var u = key and TrunkMask
+  t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
+
+proc excl(s: var TIntSet, key: int) =
+  var t = intSetGet(s, key shr TrunkShift)
+  if t != nil:
+    var u = key and TrunkMask
+    t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
+        (1 shl (u and IntMask))
+
+iterator elements(t: TIntSet): int {.inline.} =
+  # while traversing it is forbidden to change the set!
+  for h in 0..high(t.data):
+    var r = t.data[h]
+    while r != nil:
+      var i = 0
+      while i <= high(r.bits):
+        var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
+        # modifying operations are not allowed during traversation
+        var j = 0
+        while w != 0:         # test all remaining bits for zero
+          if (w and 1) != 0:  # the bit is set!
+            yield (r.key shl TrunkShift) or (i shl IntShift +% j)
+          inc(j)
+          w = w shr 1
+        inc(i)
+      r = r.next
+
+proc isSmallChunk(c: PChunk): bool {.inline.} =
+  return c.size <= SmallChunkSize-smallChunkOverhead()
+
+proc chunkUnused(c: PChunk): bool {.inline.} =
+  result = not c.used
+
+iterator allObjects(m: TMemRegion): pointer {.inline.} =
+  for s in elements(m.chunkStarts):
+    # we need to check here again as it could have been modified:
+    if s in m.chunkStarts:
+      let c = cast[PChunk](s shl PageShift)
+      if not chunkUnused(c):
+        if isSmallChunk(c):
+          var c = cast[PSmallChunk](c)
+
+          let size = c.size
+          var a = cast[ByteAddress](addr(c.data))
+          let limit = a + c.acc
+          while a <% limit:
+            yield cast[pointer](a)
+            a = a +% size
+        else:
+          let c = cast[PBigChunk](c)
+          yield addr(c.data)
+
+proc isCell(p: pointer): bool {.inline.} =
+  result = cast[ptr TFreeCell](p).zeroField >% 1
+
+# ------------- chunk management ----------------------------------------------
+proc pageIndex(c: PChunk): int {.inline.} =
+  result = cast[ByteAddress](c) shr PageShift
+
+proc pageIndex(p: pointer): int {.inline.} =
+  result = cast[ByteAddress](p) shr PageShift
+
+proc pageAddr(p: pointer): PChunk {.inline.} =
+  result = cast[PChunk](cast[ByteAddress](p) and not PageMask)
+  #sysAssert(Contains(allocator.chunkStarts, pageIndex(result)))
+
+proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk =
+  incCurrMem(a, size)
+  inc(a.freeMem, size)
+  result = cast[PBigChunk](osAllocPages(size))
+  sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1")
+  #zeroMem(result, size)
+  result.next = nil
+  result.prev = nil
+  result.used = false
+  result.size = size
+  # update next.prevSize:
+  var nxt = cast[ByteAddress](result) +% size
+  sysAssert((nxt and PageMask) == 0, "requestOsChunks 2")
+  var next = cast[PChunk](nxt)
+  if pageIndex(next) in a.chunkStarts:
+    #echo("Next already allocated!")
+    next.prevSize = size
+  # set result.prevSize:
+  var lastSize = if a.lastSize != 0: a.lastSize else: PageSize
+  var prv = cast[ByteAddress](result) -% lastSize
+  sysAssert((nxt and PageMask) == 0, "requestOsChunks 3")
+  var prev = cast[PChunk](prv)
+  if pageIndex(prev) in a.chunkStarts and prev.size == lastSize:
+    #echo("Prev already allocated!")
+    result.prevSize = lastSize
+  else:
+    result.prevSize = 0 # unknown
+  a.lastSize = size # for next request
+
+proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
+  # update next.prevSize:
+  var c = cast[PChunk](p)
+  var nxt = cast[ByteAddress](p) +% c.size
+  sysAssert((nxt and PageMask) == 0, "freeOsChunks")
+  var next = cast[PChunk](nxt)
+  if pageIndex(next) in a.chunkStarts:
+    next.prevSize = 0 # XXX used
+  excl(a.chunkStarts, pageIndex(p))
+  osDeallocPages(p, size)
+  decCurrMem(a, size)
+  dec(a.freeMem, size)
+  #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
+
+proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
+  result = contains(a.chunkStarts, pageIndex(p))
+
+proc contains[T](list, x: T): bool =
+  var it = list
+  while it != nil:
+    if it == x: return true
+    it = it.next
+
+proc writeFreeList(a: TMemRegion) =
+  var it = a.freeChunksList
+  c_fprintf(c_stdout, "freeChunksList: %p\n", it)
+  while it != nil:
+    c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n",
+              it, it.next, it.prev)
+    it = it.next
+
+proc listAdd[T](head: var T, c: T) {.inline.} =
+  sysAssert(c notin head, "listAdd 1")
+  sysAssert c.prev == nil, "listAdd 2"
+  sysAssert c.next == nil, "listAdd 3"
+  c.next = head
+  if head != nil:
+    sysAssert head.prev == nil, "listAdd 4"
+    head.prev = c
+  head = c
+
+proc listRemove[T](head: var T, c: T) {.inline.} =
+  sysAssert(c in head, "listRemove")
+  if c == head:
+    head = c.next
+    sysAssert c.prev == nil, "listRemove 2"
+    if head != nil: head.prev = nil
+  else:
+    sysAssert c.prev != nil, "listRemove 3"
+    c.prev.next = c.next
+    if c.next != nil: c.next.prev = c.prev
+  c.next = nil
+  c.prev = nil
+
+proc updatePrevSize(a: var TMemRegion, c: PBigChunk,
+                    prevSize: int) {.inline.} =
+  var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
+  sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize")
+  if isAccessible(a, ri):
+    ri.prevSize = prevSize
+
+proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
+  var c = c
+  sysAssert(c.size >= PageSize, "freeBigChunk")
+  inc(a.freeMem, c.size)
+  when coalescRight:
+    var ri = cast[PChunk](cast[ByteAddress](c) +% c.size)
+    sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "freeBigChunk 2")
+    if isAccessible(a, ri) and chunkUnused(ri):
+      sysAssert(not isSmallChunk(ri), "freeBigChunk 3")
+      if not isSmallChunk(ri):
+        listRemove(a.freeChunksList, cast[PBigChunk](ri))
+        inc(c.size, ri.size)
+        excl(a.chunkStarts, pageIndex(ri))
+  when coalescLeft:
+    if c.prevSize != 0:
+      var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize)
+      sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4")
+      if isAccessible(a, le) and chunkUnused(le):
+        sysAssert(not isSmallChunk(le), "freeBigChunk 5")
+        if not isSmallChunk(le):
+          listRemove(a.freeChunksList, cast[PBigChunk](le))
+          inc(le.size, c.size)
+          excl(a.chunkStarts, pageIndex(c))
+          c = cast[PBigChunk](le)
+
+  if c.size < ChunkOsReturn or weirdUnmap:
+    incl(a, a.chunkStarts, pageIndex(c))
+    updatePrevSize(a, c, c.size)
+    listAdd(a.freeChunksList, c)
+    c.used = false
+  else:
+    freeOsChunks(a, c, c.size)
+
+proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
+  var rest = cast[PBigChunk](cast[ByteAddress](c) +% size)
+  sysAssert(rest notin a.freeChunksList, "splitChunk")
+  rest.size = c.size - size
+  rest.used = false
+  rest.next = nil
+  rest.prev = nil
+  rest.prevSize = size
+  updatePrevSize(a, c, rest.size)
+  c.size = size
+  incl(a, a.chunkStarts, pageIndex(rest))
+  listAdd(a.freeChunksList, rest)
+
+proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
+  # use first fit for now:
+  sysAssert((size and PageMask) == 0, "getBigChunk 1")
+  sysAssert(size > 0, "getBigChunk 2")
+  result = a.freeChunksList
+  block search:
+    while result != nil:
+      sysAssert chunkUnused(result), "getBigChunk 3"
+      if result.size == size:
+        listRemove(a.freeChunksList, result)
+        break search
+      elif result.size > size:
+        listRemove(a.freeChunksList, result)
+        splitChunk(a, result, size)
+        break search
+      result = result.next
+      sysAssert result != a.freeChunksList, "getBigChunk 4"
+    if size < InitialMemoryRequest:
+      result = requestOsChunks(a, InitialMemoryRequest)
+      splitChunk(a, result, size)
+    else:
+      result = requestOsChunks(a, size)
+  result.prevSize = 0 # XXX why is this needed?
+  result.used = true
+  incl(a, a.chunkStarts, pageIndex(result))
+  dec(a.freeMem, size)
+
+proc getSmallChunk(a: var TMemRegion): PSmallChunk =
+  var res = getBigChunk(a, PageSize)
+  sysAssert res.prev == nil, "getSmallChunk 1"
+  sysAssert res.next == nil, "getSmallChunk 2"
+  result = cast[PSmallChunk](res)
+
+# -----------------------------------------------------------------------------
+proc isAllocatedPtr(a: TMemRegion, p: pointer): bool {.benign.}
+
+proc allocInv(a: TMemRegion): bool =
+  ## checks some (not all yet) invariants of the allocator's data structures.
+  for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
+    var c = a.freeSmallChunks[s]
+    while c != nil:
+      if c.next == c:
+        echo "[SYSASSERT] c.next == c"
+        return false
+      if c.size != s * MemAlign:
+        echo "[SYSASSERT] c.size != s * MemAlign"
+        return false
+      var it = c.freeList
+      while it != nil:
+        if it.zeroField != 0:
+          echo "[SYSASSERT] it.zeroField != 0"
+          c_printf("%ld %p\n", it.zeroField, it)
+          return false
+        it = it.next
+      c = c.next
+  result = true
+
+proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
+  sysAssert(allocInv(a), "rawAlloc: begin")
+  sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
+  sysAssert(requestedSize >= sizeof(TFreeCell), "rawAlloc: requested size too small")
+  var size = roundup(requestedSize, MemAlign)
+  sysAssert(size >= requestedSize, "insufficient allocated size!")
+  #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
+  if size <= SmallChunkSize-smallChunkOverhead():
+    # allocate a small block: for small chunks, we use only its next pointer
+    var s = size div MemAlign
+    var c = a.freeSmallChunks[s]
+    if c == nil:
+      c = getSmallChunk(a)
+      c.freeList = nil
+      sysAssert c.size == PageSize, "rawAlloc 3"
+      c.size = size
+      c.acc = size
+      c.free = SmallChunkSize - smallChunkOverhead() - size
+      c.next = nil
+      c.prev = nil
+      listAdd(a.freeSmallChunks[s], c)
+      result = addr(c.data)
+      sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4")
+    else:
+      sysAssert(allocInv(a), "rawAlloc: begin c != nil")
+      sysAssert c.next != c, "rawAlloc 5"
+      #if c.size != size:
+      #  c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
+      sysAssert c.size == size, "rawAlloc 6"
+      if c.freeList == nil:
+        sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
+                  "rawAlloc 7")
+        result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc)
+        inc(c.acc, size)
+      else:
+        result = c.freeList
+        sysAssert(c.freeList.zeroField == 0, "rawAlloc 8")
+        c.freeList = c.freeList.next
+      dec(c.free, size)
+      sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9")
+      sysAssert(allocInv(a), "rawAlloc: end c != nil")
+    sysAssert(allocInv(a), "rawAlloc: before c.free < size")
+    if c.free < size:
+      sysAssert(allocInv(a), "rawAlloc: before listRemove test")
+      listRemove(a.freeSmallChunks[s], c)
+      sysAssert(allocInv(a), "rawAlloc: end listRemove test")
+    sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %%
+               size == 0, "rawAlloc 21")
+    sysAssert(allocInv(a), "rawAlloc: end small size")
+  else:
+    size = roundup(requestedSize+bigChunkOverhead(), PageSize)
+    # allocate a large block
+    var c = getBigChunk(a, size)
+    sysAssert c.prev == nil, "rawAlloc 10"
+    sysAssert c.next == nil, "rawAlloc 11"
+    sysAssert c.size == size, "rawAlloc 12"
+    result = addr(c.data)
+    sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 13")
+    if a.root == nil: a.root = bottom
+    add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size)
+  sysAssert(isAccessible(a, result), "rawAlloc 14")
+  sysAssert(allocInv(a), "rawAlloc: end")
+  when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
+
+proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
+  result = rawAlloc(a, requestedSize)
+  zeroMem(result, requestedSize)
+
+proc rawDealloc(a: var TMemRegion, p: pointer) =
+  #sysAssert(isAllocatedPtr(a, p), "rawDealloc: no allocated pointer")
+  sysAssert(allocInv(a), "rawDealloc: begin")
+  var c = pageAddr(p)
+  if isSmallChunk(c):
+    # `p` is within a small chunk:
+    var c = cast[PSmallChunk](c)
+    var s = c.size
+    sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
+               s == 0, "rawDealloc 3")
+    var f = cast[ptr TFreeCell](p)
+    #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField)))
+    sysAssert(f.zeroField != 0, "rawDealloc 1")
+    f.zeroField = 0
+    f.next = c.freeList
+    c.freeList = f
+    when overwriteFree:
+      # set to 0xff to check for usage after free bugs:
+      c_memset(cast[pointer](cast[int](p) +% sizeof(TFreeCell)), -1'i32,
+               s -% sizeof(TFreeCell))
+    # check if it is not in the freeSmallChunks[s] list:
+    if c.free < s:
+      # add it to the freeSmallChunks[s] array:
+      listAdd(a.freeSmallChunks[s div MemAlign], c)
+      inc(c.free, s)
+    else:
+      inc(c.free, s)
+      if c.free == SmallChunkSize-smallChunkOverhead():
+        listRemove(a.freeSmallChunks[s div MemAlign], c)
+        c.size = SmallChunkSize
+        freeBigChunk(a, cast[PBigChunk](c))
+    sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %%
+               s == 0, "rawDealloc 2")
+  else:
+    # set to 0xff to check for usage after free bugs:
+    when overwriteFree: c_memset(p, -1'i32, c.size -% bigChunkOverhead())
+    # free big chunk
+    var c = cast[PBigChunk](c)
+    a.deleted = bottom
+    del(a, a.root, cast[int](addr(c.data)))
+    freeBigChunk(a, c)
+  sysAssert(allocInv(a), "rawDealloc: end")
+  when logAlloc: cprintf("rawDealloc: %p\n", p)
+
+proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
+  if isAccessible(a, p):
+    var c = pageAddr(p)
+    if not chunkUnused(c):
+      if isSmallChunk(c):
+        var c = cast[PSmallChunk](c)
+        var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
+                     smallChunkOverhead()
+        result = (c.acc >% offset) and (offset %% c.size == 0) and
+          (cast[ptr TFreeCell](p).zeroField >% 1)
+      else:
+        var c = cast[PBigChunk](c)
+        result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
+
+proc prepareForInteriorPointerChecking(a: var TMemRegion) {.inline.} =
+  a.minLargeObj = lowGauge(a.root)
+  a.maxLargeObj = highGauge(a.root)
+
+proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer =
+  if isAccessible(a, p):
+    var c = pageAddr(p)
+    if not chunkUnused(c):
+      if isSmallChunk(c):
+        var c = cast[PSmallChunk](c)
+        var offset = (cast[ByteAddress](p) and (PageSize-1)) -%
+                     smallChunkOverhead()
+        if c.acc >% offset:
+          sysAssert(cast[ByteAddress](addr(c.data)) +% offset ==
+                    cast[ByteAddress](p), "offset is not what you think it is")
+          var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +%
+                    offset -% (offset %% c.size))
+          if d.zeroField >% 1:
+            result = d
+            sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
+      else:
+        var c = cast[PBigChunk](c)
+        var d = addr(c.data)
+        if p >= d and cast[ptr TFreeCell](d).zeroField >% 1:
+          result = d
+          sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
+  else:
+    var q = cast[int](p)
+    if q >=% a.minLargeObj and q <=% a.maxLargeObj:
+      # this check is highly effective! Test fails for 99,96% of all checks on
+      # an x86-64.
+      var avlNode = inRange(a.root, q)
+      if avlNode != nil:
+        var k = cast[pointer](avlNode.key)
+        var c = cast[PBigChunk](pageAddr(k))
+        sysAssert(addr(c.data) == k, " k is not the same as addr(c.data)!")
+        if cast[ptr TFreeCell](k).zeroField >% 1:
+          result = k
+          sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
+
+proc ptrSize(p: pointer): int =
+  var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell))
+  var c = pageAddr(p)
+  sysAssert(not chunkUnused(c), "ptrSize")
+  result = c.size -% sizeof(TFreeCell)
+  if not isSmallChunk(c):
+    dec result, bigChunkOverhead()
+
+proc alloc(allocator: var TMemRegion, size: Natural): pointer =
+  result = rawAlloc(allocator, size+sizeof(TFreeCell))
+  cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
+  sysAssert(not isAllocatedPtr(allocator, result), "alloc")
+  result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell))
+
+proc alloc0(allocator: var TMemRegion, size: Natural): pointer =
+  result = alloc(allocator, size)
+  zeroMem(result, size)
+
+proc dealloc(allocator: var TMemRegion, p: pointer) =
+  sysAssert(p != nil, "dealloc 0")
+  var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell))
+  sysAssert(x != nil, "dealloc 1")
+  sysAssert(isAccessible(allocator, x), "is not accessible")
+  sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 2")
+  rawDealloc(allocator, x)
+  sysAssert(not isAllocatedPtr(allocator, x), "dealloc 3")
+
+proc realloc(allocator: var TMemRegion, p: pointer, newsize: Natural): pointer =
+  if newsize > 0:
+    result = alloc0(allocator, newsize)
+    if p != nil:
+      copyMem(result, p, ptrSize(p))
+      dealloc(allocator, p)
+  elif p != nil:
+    dealloc(allocator, p)
+
+proc deallocOsPages(a: var TMemRegion) =
+  # we free every 'ordinarily' allocated page by iterating over the page bits:
+  for p in elements(a.chunkStarts):
+    var page = cast[PChunk](p shl PageShift)
+    when not weirdUnmap:
+      var size = if page.size < PageSize: PageSize else: page.size
+      osDeallocPages(page, size)
+    else:
+      # Linux on PowerPC for example frees MORE than asked if 'munmap'
+      # receives the start of an originally mmap'ed memory block. This is not
+      # too bad, but we must not access 'page.size' then as that could trigger
+      # a segfault. But we don't need to access 'page.size' here anyway,
+      # because calling munmap with PageSize suffices:
+      osDeallocPages(page, PageSize)
+  # And then we free the pages that are in use for the page bits:
+  llDeallocAll(a)
+
+proc getFreeMem(a: TMemRegion): int {.inline.} = result = a.freeMem
+proc getTotalMem(a: TMemRegion): int {.inline.} = result = a.currMem
+proc getOccupiedMem(a: TMemRegion): int {.inline.} =
+  result = a.currMem - a.freeMem
+
+# ---------------------- thread memory region -------------------------------
+
+template instantiateForRegion(allocator: expr) =
+  when defined(fulldebug):
+    proc interiorAllocatedPtr*(p: pointer): pointer =
+      result = interiorAllocatedPtr(allocator, p)
+
+    proc isAllocatedPtr*(p: pointer): bool =
+      let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(TCell)))
+      result = isAllocatedPtr(allocator, p)
+
+  proc deallocOsPages = deallocOsPages(allocator)
+
+  proc alloc(size: Natural): pointer =
+    result = alloc(allocator, size)
+
+  proc alloc0(size: Natural): pointer =
+    result = alloc0(allocator, size)
+
+  proc dealloc(p: pointer) =
+    dealloc(allocator, p)
+
+  proc realloc(p: pointer, newsize: Natural): pointer =
+    result = realloc(allocator, p, newSize)
+
+  when false:
+    proc countFreeMem(): int =
+      # only used for assertions
+      var it = allocator.freeChunksList
+      while it != nil:
+        inc(result, it.size)
+        it = it.next
+
+  proc getFreeMem(): int =
+    result = allocator.freeMem
+    #sysAssert(result == countFreeMem())
+
+  proc getTotalMem(): int = return allocator.currMem
+  proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
+
+  # -------------------- shared heap region ----------------------------------
+  when hasThreadSupport:
+    var sharedHeap: TMemRegion
+    var heapLock: TSysLock
+    initSysLock(heapLock)
+
+  proc allocShared(size: Natural): pointer =
+    when hasThreadSupport:
+      acquireSys(heapLock)
+      result = alloc(sharedHeap, size)
+      releaseSys(heapLock)
+    else:
+      result = alloc(size)
+
+  proc allocShared0(size: Natural): pointer =
+    result = allocShared(size)
+    zeroMem(result, size)
+
+  proc deallocShared(p: pointer) =
+    when hasThreadSupport:
+      acquireSys(heapLock)
+      dealloc(sharedHeap, p)
+      releaseSys(heapLock)
+    else:
+      dealloc(p)
+
+  proc reallocShared(p: pointer, newsize: Natural): pointer =
+    when hasThreadSupport:
+      acquireSys(heapLock)
+      result = realloc(sharedHeap, p, newsize)
+      releaseSys(heapLock)
+    else:
+      result = realloc(p, newSize)
+
+  when hasThreadSupport:
+
+    template sharedMemStatsShared(v: int) {.immediate.} =
+      acquireSys(heapLock)
+      result = v
+      releaseSys(heapLock)
+
+    proc getFreeSharedMem(): int =
+      sharedMemStatsShared(sharedHeap.freeMem)
+
+    proc getTotalSharedMem(): int =
+      sharedMemStatsShared(sharedHeap.currMem)
+
+    proc getOccupiedSharedMem(): int =
+      sharedMemStatsShared(sharedHeap.currMem - sharedHeap.freeMem)
+
+{.pop.}
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
new file mode 100644
index 000000000..9406f26c9
--- /dev/null
+++ b/lib/system/ansi_c.nim
@@ -0,0 +1,168 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This include file contains headers of Ansi C procs
+# and definitions of Ansi C types in Nim syntax
+# All symbols are prefixed with 'c_' to avoid ambiguities
+
+{.push hints:off}
+
+proc c_strcmp(a, b: cstring): cint {.header: "<string.h>", 
+  noSideEffect, importc: "strcmp".}
+proc c_memcmp(a, b: cstring, size: int): cint {.header: "<string.h>", 
+  noSideEffect, importc: "memcmp".}
+proc c_memcpy(a, b: cstring, size: int) {.header: "<string.h>", importc: "memcpy".}
+proc c_strlen(a: cstring): int {.header: "<string.h>", 
+  noSideEffect, importc: "strlen".}
+proc c_memset(p: pointer, value: cint, size: int) {.
+  header: "<string.h>", importc: "memset".}
+
+type
+  C_TextFile {.importc: "FILE", header: "<stdio.h>", 
+               final, incompleteStruct.} = object
+  C_BinaryFile {.importc: "FILE", header: "<stdio.h>", 
+                 final, incompleteStruct.} = object
+  C_TextFileStar = ptr C_TextFile
+  C_BinaryFileStar = ptr C_BinaryFile
+
+  C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
+
+when not defined(vm):
+  var
+    c_stdin {.importc: "stdin", nodecl.}: C_TextFileStar
+    c_stdout {.importc: "stdout", nodecl.}: C_TextFileStar
+    c_stderr {.importc: "stderr", nodecl.}: C_TextFileStar
+
+# constants faked as variables:
+when not declared(SIGINT):
+  when NoFakeVars:
+    when defined(windows):
+      const
+        SIGABRT = cint(22)
+        SIGFPE = cint(8)
+        SIGILL = cint(4)
+        SIGINT = cint(2)
+        SIGSEGV = cint(11)
+        SIGTERM = cint(15)
+    elif defined(macosx) or defined(linux):
+      const
+        SIGABRT = cint(6)
+        SIGFPE = cint(8)
+        SIGILL = cint(4)
+        SIGINT = cint(2)
+        SIGSEGV = cint(11)
+        SIGTERM = cint(15)
+        SIGPIPE = cint(13)
+    else:
+      {.error: "SIGABRT not ported to your platform".}
+  else:
+    var
+      SIGINT {.importc: "SIGINT", nodecl.}: cint
+      SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint
+      SIGABRT {.importc: "SIGABRT", nodecl.}: cint
+      SIGFPE {.importc: "SIGFPE", nodecl.}: cint
+      SIGILL {.importc: "SIGILL", nodecl.}: cint
+    when defined(macosx) or defined(linux):
+      var SIGPIPE {.importc: "SIGPIPE", nodecl.}: cint
+
+when defined(macosx):
+  when NoFakeVars:
+    const SIGBUS = cint(10)
+  else:
+    var SIGBUS {.importc: "SIGBUS", nodecl.}: cint
+else:
+  template SIGBUS: expr = SIGSEGV
+
+when defined(nimSigSetjmp) and not defined(nimStdSetjmp):
+  proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
+    header: "<setjmp.h>", importc: "siglongjmp".}
+  template c_setjmp(jmpb: C_JmpBuf): cint =
+    proc c_sigsetjmp(jmpb: C_JmpBuf, savemask: cint): cint {.
+      header: "<setjmp.h>", importc: "sigsetjmp".}
+    c_sigsetjmp(jmpb, 0)
+elif defined(nimRawSetjmp) and not defined(nimStdSetjmp):
+  proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
+    header: "<setjmp.h>", importc: "_longjmp".}
+  proc c_setjmp(jmpb: C_JmpBuf): cint {.
+    header: "<setjmp.h>", importc: "_setjmp".}
+else:
+  proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
+    header: "<setjmp.h>", importc: "longjmp".}
+  proc c_setjmp(jmpb: C_JmpBuf): cint {.
+    header: "<setjmp.h>", importc: "setjmp".}
+
+proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
+  importc: "signal", header: "<signal.h>".}
+proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".}
+
+proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", 
+  header: "<stdio.h>".}
+proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring  {.
+  importc: "fgets", header: "<stdio.h>".}
+proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc", 
+  header: "<stdio.h>".}
+proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc", 
+  header: "<stdio.h>".}
+proc c_putc(c: char, stream: C_TextFileStar) {.importc: "putc", 
+  header: "<stdio.h>".}
+proc c_fprintf(f: C_TextFileStar, frmt: cstring) {.
+  importc: "fprintf", header: "<stdio.h>", varargs.}
+proc c_printf(frmt: cstring) {.
+  importc: "printf", header: "<stdio.h>", varargs.}
+
+proc c_fopen(filename, mode: cstring): C_TextFileStar {.
+  importc: "fopen", header: "<stdio.h>".}
+proc c_fclose(f: C_TextFileStar) {.importc: "fclose", header: "<stdio.h>".}
+
+proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>", 
+  importc: "sprintf", varargs, noSideEffect.}
+  # we use it only in a way that cannot lead to security issues
+
+proc c_fread(buf: pointer, size, n: int, f: C_BinaryFileStar): int {.
+  importc: "fread", header: "<stdio.h>".}
+proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
+  importc: "fseek", header: "<stdio.h>".}
+
+proc c_fwrite(buf: pointer, size, n: int, f: C_BinaryFileStar): int {.
+  importc: "fwrite", header: "<stdio.h>".}
+
+proc c_exit(errorcode: cint) {.importc: "exit", header: "<stdlib.h>".}
+proc c_ferror(stream: C_TextFileStar): bool {.
+  importc: "ferror", header: "<stdio.h>".}
+proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", header: "<stdio.h>".}
+proc c_abort() {.importc: "abort", header: "<stdlib.h>".}
+proc c_feof(stream: C_TextFileStar): bool {.
+  importc: "feof", header: "<stdio.h>".}
+
+proc c_malloc(size: int): pointer {.importc: "malloc", header: "<stdlib.h>".}
+proc c_free(p: pointer) {.importc: "free", header: "<stdlib.h>".}
+proc c_realloc(p: pointer, newsize: int): pointer {.
+  importc: "realloc", header: "<stdlib.h>".}
+
+when hostOS != "standalone":
+  when not declared(errno):
+    when defined(NimrodVM):
+      var vmErrnoWrapper {.importc.}: ptr cint
+      template errno: expr = 
+        bind vmErrnoWrapper
+        vmErrnoWrapper[]
+    else:
+      var errno {.importc, header: "<errno.h>".}: cint ## error variable
+proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
+
+proc c_remove(filename: cstring): cint {.
+  importc: "remove", header: "<stdio.h>".}
+proc c_rename(oldname, newname: cstring): cint {.
+  importc: "rename", header: "<stdio.h>".}
+
+proc c_system(cmd: cstring): cint {.importc: "system", header: "<stdlib.h>".}
+proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
+proc c_putenv(env: cstring): cint {.importc: "putenv", header: "<stdlib.h>".}
+
+{.pop}
diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim
new file mode 100644
index 000000000..ef153417c
--- /dev/null
+++ b/lib/system/arithm.nim
@@ -0,0 +1,343 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# simple integer arithmetic with overflow checking
+
+proc raiseOverflow {.compilerproc, noinline.} =
+  # a single proc to reduce code size to a minimum
+  sysFatal(OverflowError, "over- or underflow")
+
+proc raiseDivByZero {.compilerproc, noinline.} =
+  sysFatal(DivByZeroError, "division by zero")
+
+proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  result = a +% b
+  if (result xor a) >= int64(0) or (result xor b) >= int64(0):
+    return result
+  raiseOverflow()
+
+proc subInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  result = a -% b
+  if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
+    return result
+  raiseOverflow()
+
+proc negInt64(a: int64): int64 {.compilerProc, inline.} =
+  if a != low(int64): return -a
+  raiseOverflow()
+
+proc absInt64(a: int64): int64 {.compilerProc, inline.} =
+  if a != low(int64):
+    if a >= 0: return a
+    else: return -a
+  raiseOverflow()
+
+proc divInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  if b == int64(0):
+    raiseDivByZero()
+  if a == low(int64) and b == int64(-1):
+    raiseOverflow()
+  return a div b
+
+proc modInt64(a, b: int64): int64 {.compilerProc, inline.} =
+  if b == int64(0):
+    raiseDivByZero()
+  return a mod b
+
+#
+# This code has been inspired by Python's source code.
+# The native int product x*y is either exactly right or *way* off, being
+# just the last n bits of the true product, where n is the number of bits
+# in an int (the delivered product is the true product plus i*2**n for
+# some integer i).
+#
+# The native float64 product x*y is subject to three
+# rounding errors: on a sizeof(int)==8 box, each cast to double can lose
+# info, and even on a sizeof(int)==4 box, the multiplication can lose info.
+# But, unlike the native int product, it's not in *range* trouble:  even
+# if sizeof(int)==32 (256-bit ints), the product easily fits in the
+# dynamic range of a float64. So the leading 50 (or so) bits of the float64
+# product are correct.
+#
+# We check these two ways against each other, and declare victory if they're
+# approximately the same. Else, because the native int product is the only
+# one that can lose catastrophic amounts of information, it's the native int
+# product that must have overflowed.
+#
+proc mulInt64(a, b: int64): int64 {.compilerproc.} =
+  var
+    resAsFloat, floatProd: float64
+  result = a *% b
+  floatProd = toBiggestFloat(a) # conversion
+  floatProd = floatProd * toBiggestFloat(b)
+  resAsFloat = toBiggestFloat(result)
+
+  # Fast path for normal case: small multiplicands, and no info
+  # is lost in either method.
+  if resAsFloat == floatProd: return result
+
+  # Somebody somewhere lost info. Close enough, or way off? Note
+  # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
+  # The difference either is or isn't significant compared to the
+  # true value (of which floatProd is a good approximation).
+
+  # abs(diff)/abs(prod) <= 1/32 iff
+  #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
+  if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+    return result
+  raiseOverflow()
+
+
+proc absInt(a: int): int {.compilerProc, inline.} =
+  if a != low(int):
+    if a >= 0: return a
+    else: return -a
+  raiseOverflow()
+
+const
+  asmVersion = defined(I386) and (defined(vcc) or defined(wcc) or
+               defined(dmc) or defined(gcc) or defined(llvm_gcc))
+    # my Version of Borland C++Builder does not have
+    # tasm32, which is needed for assembler blocks
+    # this is why Borland is not included in the 'when'
+
+when asmVersion and not defined(gcc) and not defined(llvm_gcc):
+  # assembler optimized versions for compilers that
+  # have an intel syntax assembler:
+  proc addInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
+    # a in eax, and b in edx
+    asm """
+        mov eax, ecx
+        add eax, edx
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+        ret
+    """
+
+  proc subInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
+    asm """
+        mov eax, ecx
+        sub eax, edx
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+        ret
+    """
+
+  proc negInt(a: int): int {.compilerProc, asmNoStackFrame.} =
+    asm """
+        mov eax, ecx
+        neg eax
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+        ret
+    """
+
+  proc divInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
+    asm """
+        mov eax, ecx
+        mov ecx, edx
+        xor edx, edx
+        idiv ecx
+        jno  theEnd
+        call `raiseOverflow`
+      theEnd:
+        ret
+    """
+
+  proc modInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
+    asm """
+        mov eax, ecx
+        mov ecx, edx
+        xor edx, edx
+        idiv ecx
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+        mov eax, edx
+        ret
+    """
+
+  proc mulInt(a, b: int): int {.compilerProc, asmNoStackFrame.} =
+    asm """
+        mov eax, ecx
+        mov ecx, edx
+        xor edx, edx
+        imul ecx
+        jno theEnd
+        call `raiseOverflow`
+      theEnd:
+        ret
+    """
+
+elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
+  proc addInt(a, b: int): int {.compilerProc, inline.} =
+    # don't use a pure proc here!
+    asm """
+      "addl %%ecx, %%eax\n"
+      "jno 1\n"
+      "call _raiseOverflow\n"
+      "1: \n"
+      :"=a"(`result`)
+      :"a"(`a`), "c"(`b`)
+    """
+    #".intel_syntax noprefix"
+    #/* Intel syntax here */
+    #".att_syntax"
+
+  proc subInt(a, b: int): int {.compilerProc, inline.} =
+    asm """ "subl %%ecx,%%eax\n"
+            "jno 1\n"
+            "call _raiseOverflow\n"
+            "1: \n"
+           :"=a"(`result`)
+           :"a"(`a`), "c"(`b`)
+    """
+
+  proc mulInt(a, b: int): int {.compilerProc, inline.} =
+    asm """  "xorl %%edx, %%edx\n"
+             "imull %%ecx\n"
+             "jno 1\n"
+             "call _raiseOverflow\n"
+             "1: \n"
+            :"=a"(`result`)
+            :"a"(`a`), "c"(`b`)
+            :"%edx"
+    """
+
+  proc negInt(a: int): int {.compilerProc, inline.} =
+    asm """ "negl %%eax\n"
+            "jno 1\n"
+            "call _raiseOverflow\n"
+            "1: \n"
+           :"=a"(`result`)
+           :"a"(`a`)
+    """
+
+  proc divInt(a, b: int): int {.compilerProc, inline.} =
+    asm """  "xorl %%edx, %%edx\n"
+             "idivl %%ecx\n"
+             "jno 1\n"
+             "call _raiseOverflow\n"
+             "1: \n"
+            :"=a"(`result`)
+            :"a"(`a`), "c"(`b`)
+            :"%edx"
+    """
+
+  proc modInt(a, b: int): int {.compilerProc, inline.} =
+    asm """  "xorl %%edx, %%edx\n"
+             "idivl %%ecx\n"
+             "jno 1\n"
+             "call _raiseOverflow\n"
+             "1: \n"
+             "movl %%edx, %%eax"
+            :"=a"(`result`)
+            :"a"(`a`), "c"(`b`)
+            :"%edx"
+    """
+
+# Platform independent versions of the above (slower!)
+when not declared(addInt):
+  proc addInt(a, b: int): int {.compilerProc, inline.} =
+    result = a +% b
+    if (result xor a) >= 0 or (result xor b) >= 0:
+      return result
+    raiseOverflow()
+
+when not declared(subInt):
+  proc subInt(a, b: int): int {.compilerProc, inline.} =
+    result = a -% b
+    if (result xor a) >= 0 or (result xor not b) >= 0:
+      return result
+    raiseOverflow()
+
+when not declared(negInt):
+  proc negInt(a: int): int {.compilerProc, inline.} =
+    if a != low(int): return -a
+    raiseOverflow()
+
+when not declared(divInt):
+  proc divInt(a, b: int): int {.compilerProc, inline.} =
+    if b == 0:
+      raiseDivByZero()
+    if a == low(int) and b == -1:
+      raiseOverflow()
+    return a div b
+
+when not declared(modInt):
+  proc modInt(a, b: int): int {.compilerProc, inline.} =
+    if b == 0:
+      raiseDivByZero()
+    return a mod b
+
+when not declared(mulInt):
+  #
+  # This code has been inspired by Python's source code.
+  # The native int product x*y is either exactly right or *way* off, being
+  # just the last n bits of the true product, where n is the number of bits
+  # in an int (the delivered product is the true product plus i*2**n for
+  # some integer i).
+  #
+  # The native float64 product x*y is subject to three
+  # rounding errors: on a sizeof(int)==8 box, each cast to double can lose
+  # info, and even on a sizeof(int)==4 box, the multiplication can lose info.
+  # But, unlike the native int product, it's not in *range* trouble:  even
+  # if sizeof(int)==32 (256-bit ints), the product easily fits in the
+  # dynamic range of a float64. So the leading 50 (or so) bits of the float64
+  # product are correct.
+  #
+  # We check these two ways against each other, and declare victory if
+  # they're approximately the same. Else, because the native int product is
+  # the only one that can lose catastrophic amounts of information, it's the
+  # native int product that must have overflowed.
+  #
+  proc mulInt(a, b: int): int {.compilerProc.} =
+    var
+      resAsFloat, floatProd: float
+
+    result = a *% b
+    floatProd = toFloat(a) * toFloat(b)
+    resAsFloat = toFloat(result)
+
+    # Fast path for normal case: small multiplicands, and no info
+    # is lost in either method.
+    if resAsFloat == floatProd: return result
+
+    # Somebody somewhere lost info. Close enough, or way off? Note
+    # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
+    # The difference either is or isn't significant compared to the
+    # true value (of which floatProd is a good approximation).
+
+    # abs(diff)/abs(prod) <= 1/32 iff
+    #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
+    if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+      return result
+    raiseOverflow()
+
+# We avoid setting the FPU control word here for compatibility with libraries
+# written in other languages.
+
+proc raiseFloatInvalidOp {.noinline.} =
+  sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result")
+
+proc nanCheck(x: float64) {.compilerProc, inline.} =
+  if x != x: raiseFloatInvalidOp()
+
+proc raiseFloatOverflow(x: float64) {.noinline.} =
+  if x > 0.0:
+    sysFatal(FloatOverflowError, "FPU operation caused an overflow")
+  else:
+    sysFatal(FloatUnderflowError, "FPU operations caused an underflow")
+
+proc infCheck(x: float64) {.compilerProc, inline.} =
+  if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x)
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
new file mode 100644
index 000000000..78995954f
--- /dev/null
+++ b/lib/system/assign.nim
@@ -0,0 +1,234 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+proc genericResetAux(dest: pointer, n: ptr TNimNode) {.benign.}
+
+proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign.}
+proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
+                      shallow: bool) {.benign.} =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  case n.kind
+  of nkSlot:
+    genericAssignAux(cast[pointer](d +% n.offset), 
+                     cast[pointer](s +% n.offset), n.typ, shallow)
+  of nkList:
+    for i in 0..n.len-1:
+      genericAssignAux(dest, src, n.sons[i], shallow)
+  of nkCase:
+    var dd = selectBranch(dest, n)
+    var m = selectBranch(src, n)
+    # reset if different branches are in use; note different branches also
+    # imply that's not self-assignment (``x = x``)!
+    if m != dd and dd != nil:
+      genericResetAux(dest, dd)
+    copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
+            n.typ.size)
+    if m != nil:
+      genericAssignAux(dest, src, m, shallow)
+  of nkNone: sysAssert(false, "genericAssignAux")
+  #else:
+  #  echo "ugh memory corruption! ", n.kind
+  #  quit 1
+
+proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  sysAssert(mt != nil, "genericAssignAux 2")
+  case mt.kind
+  of tyString:
+    var x = cast[PPointer](dest)
+    var s2 = cast[PPointer](s)[]
+    if s2 == nil or shallow or (
+        cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
+      unsureAsgnRef(x, s2)
+    else:
+      unsureAsgnRef(x, copyString(cast[NimString](s2)))
+  of tySequence:
+    var s2 = cast[PPointer](src)[]
+    var seq = cast[PGenericSeq](s2)      
+    var x = cast[PPointer](dest)
+    if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
+      # this can happen! nil sequences are allowed
+      unsureAsgnRef(x, s2)
+      return
+    sysAssert(dest != nil, "genericAssignAux 3")
+    unsureAsgnRef(x, newSeq(mt, seq.len))
+    var dst = cast[ByteAddress](cast[PPointer](dest)[])
+    for i in 0..seq.len-1:
+      genericAssignAux(
+        cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+        cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
+                     GenericSeqSize),
+        mt.base, shallow)
+  of tyObject:
+    if mt.base != nil:
+      genericAssignAux(dest, src, mt.base, shallow)
+    genericAssignAux(dest, src, mt.node, shallow)
+    # we need to copy m_type field for tyObject, as it could be empty for
+    # sequence reallocations:
+    var pint = cast[ptr PNimType](dest)
+    # We need to copy the *static* type not the dynamic type:
+    #   if p of TB:
+    #     var tbObj = TB(p)
+    #     tbObj of TC # needs to be false!
+    pint[] = mt # cast[ptr PNimType](src)[]
+  of tyTuple:
+    genericAssignAux(dest, src, mt.node, shallow)
+  of tyArray, tyArrayConstr:
+    for i in 0..(mt.size div mt.base.size)-1:
+      genericAssignAux(cast[pointer](d +% i*% mt.base.size),
+                       cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
+  of tyRef:
+    unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
+  else:
+    copyMem(dest, src, mt.size) # copy raw bits
+
+proc genericAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
+  genericAssignAux(dest, src, mt, false)
+
+proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
+  genericAssignAux(dest, src, mt, true)
+
+when false:
+  proc debugNimType(t: PNimType) =
+    if t.isNil: 
+      cprintf("nil!")
+      return
+    var k: cstring
+    case t.kind
+    of tyBool: k = "bool"
+    of tyChar: k = "char"
+    of tyEnum: k = "enum"
+    of tyArray: k = "array"
+    of tyObject: k = "object"
+    of tyTuple: k = "tuple"
+    of tyRange: k = "range"
+    of tyPtr: k = "ptr"
+    of tyRef: k = "ref"
+    of tyVar: k = "var"
+    of tySequence: k = "seq"
+    of tyProc: k = "proc"
+    of tyPointer: k = "range"
+    of tyOpenArray: k = "openarray"
+    of tyString: k = "string"
+    of tyCString: k = "cstring"
+    of tyInt: k = "int"
+    of tyInt32: k = "int32"
+    else: k = "other"
+    cprintf("%s %ld\n", k, t.size)
+    debugNimType(t.base)
+
+proc genericSeqAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
+  var src = src # ugly, but I like to stress the parser sometimes :-)
+  genericAssign(dest, addr(src), mt)
+
+proc genericAssignOpenArray(dest, src: pointer, len: int,
+                            mt: PNimType) {.compilerproc.} =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  for i in 0..len-1:
+    genericAssign(cast[pointer](d +% i*% mt.base.size),
+                  cast[pointer](s +% i*% mt.base.size), mt.base)
+
+proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, benign.}
+proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} =
+  var d = cast[ByteAddress](dest)
+  case n.kind
+  of nkNone: sysAssert(false, "objectInitAux")
+  of nkSlot: objectInit(cast[pointer](d +% n.offset), n.typ)
+  of nkList:
+    for i in 0..n.len-1:
+      objectInitAux(dest, n.sons[i])
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: objectInitAux(dest, m)
+
+proc objectInit(dest: pointer, typ: PNimType) =
+  # the generic init proc that takes care of initialization of complex
+  # objects on the stack or heap
+  var d = cast[ByteAddress](dest)
+  case typ.kind
+  of tyObject:
+    # iterate over any structural type
+    # here we have to init the type field:
+    var pint = cast[ptr PNimType](dest)
+    pint[] = typ
+    objectInitAux(dest, typ.node)
+  of tyTuple:
+    objectInitAux(dest, typ.node)
+  of tyArray, tyArrayConstr:
+    for i in 0..(typ.size div typ.base.size)-1:
+      objectInit(cast[pointer](d +% i * typ.base.size), typ.base)
+  else: discard # nothing to do
+  
+# ---------------------- assign zero -----------------------------------------
+
+when not defined(nimmixin):
+  proc destroy(x: int) = discard
+  proc nimDestroyRange*[T](r: T) =
+    # internal proc used for destroying sequences and arrays
+    for i in countup(0, r.len - 1): destroy(r[i])
+else:
+  # XXX Why is this exported and no compilerproc? -> compilerprocs cannot be
+  # generic for now
+  proc nimDestroyRange*[T](r: T) =
+    # internal proc used for destroying sequences and arrays
+    mixin destroy
+    for i in countup(0, r.len - 1): destroy(r[i])
+
+proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, benign.}
+proc genericResetAux(dest: pointer, n: ptr TNimNode) =
+  var d = cast[ByteAddress](dest)
+  case n.kind
+  of nkNone: sysAssert(false, "genericResetAux")
+  of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ)
+  of nkList:
+    for i in 0..n.len-1: genericResetAux(dest, n.sons[i])
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: genericResetAux(dest, m)
+    zeroMem(cast[pointer](d +% n.offset), n.typ.size)
+  
+proc genericReset(dest: pointer, mt: PNimType) =
+  var d = cast[ByteAddress](dest)
+  sysAssert(mt != nil, "genericReset 2")
+  case mt.kind
+  of tyString, tyRef, tySequence:
+    unsureAsgnRef(cast[PPointer](dest), nil)
+  of tyTuple:
+    genericResetAux(dest, mt.node)
+  of tyObject:
+    genericResetAux(dest, mt.node)
+    # also reset the type field for tyObject, for correct branch switching!
+    var pint = cast[ptr PNimType](dest)
+    pint[] = nil
+  of tyArray, tyArrayConstr:
+    for i in 0..(mt.size div mt.base.size)-1:
+      genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)
+  else:
+    zeroMem(dest, mt.size) # set raw bits to zero
+
+proc selectBranch(discVal, L: int, 
+                  a: ptr array [0..0x7fff, ptr TNimNode]): ptr TNimNode =
+  result = a[L] # a[L] contains the ``else`` part (but may be nil)
+  if discVal <% L:
+    var x = a[discVal]
+    if x != nil: result = x
+  
+proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int, 
+                            a: ptr array [0..0x7fff, ptr TNimNode], 
+                            L: int) {.compilerProc.} =
+  var oldBranch = selectBranch(oldDiscVal, L, a)
+  var newBranch = selectBranch(newDiscVal, L, a)
+  if newBranch != oldBranch and oldDiscVal != 0:
+    sysFatal(FieldError, "assignment to discriminant changes object branch")
diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim
new file mode 100644
index 000000000..c97d2fc7f
--- /dev/null
+++ b/lib/system/atomics.nim
@@ -0,0 +1,227 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Atomic operations for Nim.
+{.push stackTrace:off.}
+
+const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang)
+
+when someGcc and hasThreadSupport:
+  type AtomMemModel* = distinct cint
+  var ATOMIC_RELAXED* {.importc: "__ATOMIC_RELAXED", nodecl.}: AtomMemModel
+    ## No barriers or synchronization.
+  var ATOMIC_CONSUME* {.importc: "__ATOMIC_CONSUME", nodecl.}: AtomMemModel
+    ## Data dependency only for both barrier and
+    ## synchronization with another thread.
+  var ATOMIC_ACQUIRE* {.importc: "__ATOMIC_ACQUIRE", nodecl.}: AtomMemModel
+    ## Barrier to hoisting of code and synchronizes with
+    ## release (or stronger)
+    ## semantic stores from another thread.
+  var ATOMIC_RELEASE* {.importc: "__ATOMIC_RELEASE", nodecl.}: AtomMemModel
+    ## Barrier to sinking of code and synchronizes with
+    ## acquire (or stronger)
+    ## semantic loads from another thread.
+  var ATOMIC_ACQ_REL* {.importc: "__ATOMIC_ACQ_REL", nodecl.}: AtomMemModel
+    ## Full barrier in both directions and synchronizes
+    ## with acquire loads
+    ## and release stores in another thread.
+  var ATOMIC_SEQ_CST* {.importc: "__ATOMIC_SEQ_CST", nodecl.}: AtomMemModel
+    ## Full barrier in both directions and synchronizes
+    ## with acquire loads
+    ## and release stores in all threads.
+
+  type
+    TAtomType* = SomeNumber|pointer|ptr|char|bool
+      ## Type Class representing valid types for use with atomic procs
+
+  proc atomicLoadN*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {.
+    importc: "__atomic_load_n", nodecl.}
+    ## This proc implements an atomic load operation. It returns the contents at p.
+    ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
+
+  proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {.
+    importc: "__atomic_load", nodecl.}
+    ## This is the generic version of an atomic load. It returns the contents at p in ret.
+
+  proc atomicStoreN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
+    importc: "__atomic_store_n", nodecl.}
+    ## This proc implements an atomic store operation. It writes val at p.
+    ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
+
+  proc atomicStore*[T: TAtomType](p, val: ptr T, mem: AtomMemModel) {.
+    importc: "__atomic_store", nodecl.}
+    ## This is the generic version of an atomic store. It stores the value of val at p
+
+  proc atomicExchangeN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_exchange_n", nodecl.}
+    ## This proc implements an atomic exchange operation. It writes val at p,
+    ## and returns the previous contents at p.
+    ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
+
+  proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
+    importc: "__atomic_exchange", nodecl.}
+    ## This is the generic version of an atomic exchange. It stores the contents at val at p.
+    ## The original value at p is copied into ret.
+
+  proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T,
+    weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
+    importc: "__atomic_compare_exchange_n ", nodecl.}
+    ## This proc implements an atomic compare and exchange operation. This compares the
+    ## contents at p with the contents at expected and if equal, writes desired at p.
+    ## If they are not equal, the current contents at p is written into expected.
+    ## Weak is true for weak compare_exchange, and false for the strong variation.
+    ## Many targets only offer the strong variation and ignore the parameter.
+    ## When in doubt, use the strong variation.
+    ## True is returned if desired is written at p and the execution is considered
+    ## to conform to the memory model specified by success_memmodel. There are no
+    ## restrictions on what memory model can be used here. False is returned otherwise,
+    ## and the execution is considered to conform to failure_memmodel. This memory model
+    ## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
+    ## than that specified by success_memmodel.
+
+  proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
+    weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
+    importc: "__atomic_compare_exchange", nodecl.}
+    ## This proc implements the generic version of atomic_compare_exchange.
+    ## The proc is virtually identical to atomic_compare_exchange_n, except the desired
+    ## value is also a pointer.
+
+  ## Perform the operation return the new value, all memory models are valid
+  proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_add_fetch", nodecl.}
+  proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_sub_fetch", nodecl.}
+  proc atomicOrFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_or_fetch ", nodecl.}
+  proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_and_fetch", nodecl.}
+  proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_xor_fetch", nodecl.}
+  proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_nand_fetch ", nodecl.}
+
+  ## Perform the operation return the old value, all memory models are valid
+  proc atomicFetchAdd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_add", nodecl.}
+  proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_sub", nodecl.}
+  proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_or", nodecl.}
+  proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_and", nodecl.}
+  proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_xor", nodecl.}
+  proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
+    importc: "__atomic_fetch_nand", nodecl.}
+
+  proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.
+    importc: "__atomic_test_and_set", nodecl.}
+    ## This built-in function performs an atomic test-and-set operation on the byte at p.
+    ## The byte is set to some implementation defined nonzero “set†value and the return
+    ## value is true if and only if the previous contents were “setâ€.
+    ## All memory models are valid.
+
+  proc atomicClear*(p: pointer, mem: AtomMemModel) {.
+    importc: "__atomic_clear", nodecl.}
+    ## This built-in function performs an atomic clear operation at p.
+    ## After the operation, at p contains 0.
+    ## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_RELEASE
+
+  proc atomicThreadFence*(mem: AtomMemModel) {.
+    importc: "__atomic_thread_fence", nodecl.}
+    ## This built-in function acts as a synchronization fence between threads based
+    ## on the specified memory model. All memory orders are valid.
+
+  proc atomicSignalFence*(mem: AtomMemModel) {.
+    importc: "__atomic_signal_fence", nodecl.}
+    ## This built-in function acts as a synchronization fence between a thread and
+    ## signal handlers based in the same thread. All memory orders are valid.
+
+  proc atomicAlwaysLockFree*(size: int, p: pointer): bool {.
+    importc: "__atomic_always_lock_free", nodecl.}
+    ## This built-in function returns true if objects of size bytes always generate
+    ## lock free atomic instructions for the target architecture. size must resolve
+    ## to a compile-time constant and the result also resolves to a compile-time constant.
+    ## ptr is an optional pointer to the object that may be used to determine alignment.
+    ## A value of 0 indicates typical alignment should be used. The compiler may also
+    ## ignore this parameter.
+
+  proc atomicIsLockFree*(size: int, p: pointer): bool {.
+    importc: "__atomic_is_lock_free", nodecl.}
+    ## This built-in function returns true if objects of size bytes always generate
+    ## lock free atomic instructions for the target architecture. If it is not known
+    ## to be lock free a call is made to a runtime routine named __atomic_is_lock_free.
+    ## ptr is an optional pointer to the object that may be used to determine alignment.
+    ## A value of 0 indicates typical alignment should be used. The compiler may also
+    ## ignore this parameter.
+
+  template fence*() = atomicThreadFence(ATOMIC_SEQ_CST)
+elif defined(vcc) and hasThreadSupport:
+  proc addAndFetch*(p: ptr int, val: int): int {.
+    importc: "NimXadd", nodecl.}
+  proc fence*() {.importc: "_ReadWriteBarrier", header: "<intrin.h>".}
+
+else:
+  proc addAndFetch*(p: ptr int, val: int): int {.inline.} =
+    inc(p[], val)
+    result = p[]
+
+proc atomicInc*(memLoc: var int, x: int = 1): int =
+  when someGcc and hasThreadSupport:
+    result = atomic_add_fetch(memLoc.addr, x, ATOMIC_RELAXED)
+  else:
+    inc(memLoc, x)
+    result = memLoc
+
+proc atomicDec*(memLoc: var int, x: int = 1): int =
+  when someGcc and hasThreadSupport:
+    when declared(atomic_sub_fetch):
+      result = atomic_sub_fetch(memLoc.addr, x, ATOMIC_RELAXED)
+    else:
+      result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
+  else:
+    dec(memLoc, x)
+    result = memLoc
+
+when defined(windows) and not someGcc:
+  proc interlockedCompareExchange(p: pointer; exchange, comparand: int32): int32
+    {.importc: "InterlockedCompareExchange", header: "<windows.h>", cdecl.}
+
+  proc cas*[T: bool|int|ptr](p: ptr T; oldValue, newValue: T): bool =
+    interlockedCompareExchange(p, newValue.int32, oldValue.int32) != 0
+  # XXX fix for 64 bit build
+else:
+  # this is valid for GCC and Intel C++
+  proc cas*[T: bool|int|ptr](p: ptr T; oldValue, newValue: T): bool
+    {.importc: "__sync_bool_compare_and_swap", nodecl.}
+  # XXX is this valid for 'int'?
+
+
+when (defined(x86) or defined(amd64)) and someGcc:
+  proc cpuRelax* {.inline.} =
+    {.emit: """asm volatile("pause" ::: "memory");""".}
+elif someGcc:
+  proc cpuRelax* {.inline.} =
+    {.emit: """asm volatile("" ::: "memory");""".}
+elif (defined(x86) or defined(amd64)) and defined(vcc):
+  proc cpuRelax* {.importc: "YieldProcessor", header: "<windows.h>".}
+elif defined(icl):
+  proc cpuRelax* {.importc: "_mm_pause", header: "xmmintrin.h".}
+elif false:
+  from os import sleep
+
+  proc cpuRelax* {.inline.} = os.sleep(1)
+
+when not declared(fence) and hasThreadSupport:
+  # XXX fixme
+  proc fence*() {.inline.} =
+    var dummy: bool
+    discard cas(addr dummy, false, true)
+
+{.pop.}
diff --git a/lib/system/avltree.nim b/lib/system/avltree.nim
new file mode 100644
index 000000000..292097062
--- /dev/null
+++ b/lib/system/avltree.nim
@@ -0,0 +1,91 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# not really an AVL tree anymore, but still balanced ...
+
+template isBottom(n: PAvlNode): bool = n == bottom
+
+proc lowGauge(n: PAvlNode): int =
+  var it = n
+  while not isBottom(it):
+    result = it.key
+    it = it.link[0]
+  
+proc highGauge(n: PAvlNode): int =
+  result = -1
+  var it = n
+  while not isBottom(it):
+    result = it.upperBound
+    it = it.link[1]
+
+proc find(root: PAvlNode, key: int): PAvlNode = 
+  var it = root
+  while not isBottom(it):
+    if it.key == key: return it
+    it = it.link[ord(it.key <% key)]
+
+proc inRange(root: PAvlNode, key: int): PAvlNode =
+  var it = root
+  while not isBottom(it):
+    if it.key <=% key and key <% it.upperBound: return it
+    it = it.link[ord(it.key <% key)]
+
+proc skew(t: var PAvlNode) =
+  if t.link[0].level == t.level:
+    var temp = t
+    t = t.link[0]
+    temp.link[0] = t.link[1]
+    t.link[1] = temp
+
+proc split(t: var PAvlNode) =
+  if t.link[1].link[1].level == t.level:
+    var temp = t
+    t = t.link[1]
+    temp.link[1] = t.link[0]
+    t.link[0] = temp
+    inc t.level
+
+proc add(a: var TMemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
+  if t == bottom:
+    t = allocAvlNode(a, key, upperBound)
+  else:
+    if key <% t.key:
+      add(a, t.link[0], key, upperBound)
+    elif key >% t.key:
+      add(a, t.link[1], key, upperBound)
+    else:
+      sysAssert false, "key already exists"
+    skew(t)
+    split(t)
+
+proc del(a: var TMemRegion, t: var PAvlNode, x: int) {.benign.} =
+  if t == bottom: return
+  a.last = t
+  if x <% t.key:
+    del(a, t.link[0], x)
+  else:
+    a.deleted = t
+    del(a, t.link[1], x)
+  if t == a.last and a.deleted != bottom and x == a.deleted.key:
+    a.deleted.key = t.key
+    a.deleted.upperBound = t.upperBound
+    a.deleted = bottom
+    t = t.link[1]
+    deallocAvlNode(a, a.last)
+  elif t.link[0].level < t.level-1 or
+       t.link[1].level < t.level-1:
+    dec t.level
+    if t.link[1].level > t.level:
+      t.link[1].level = t.level
+    skew(t)
+    skew(t.link[1])
+    skew(t.link[1].link[1])
+    split(t)
+    split(t.link[1])
+
diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim
new file mode 100644
index 000000000..0e3a01eba
--- /dev/null
+++ b/lib/system/cellsets.nim
@@ -0,0 +1,220 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Efficient set of pointers for the GC (and repr)
+
+type
+  TRefCount = int
+
+  TCell {.pure.} = object
+    refcount: TRefCount  # the refcount and some flags
+    typ: PNimType
+    when trackAllocationSource:
+      filename: cstring
+      line: int
+    when useCellIds:
+      id: int
+
+  PCell = ptr TCell
+
+  PPageDesc = ptr TPageDesc
+  TBitIndex = range[0..UnitsPerPage-1]
+  TPageDesc {.final, pure.} = object
+    next: PPageDesc # all nodes are connected with this pointer
+    key: ByteAddress   # start address at bit 0
+    bits: array[TBitIndex, int] # a bit vector
+
+  PPageDescArray = ptr array[0..1000_000, PPageDesc]
+  TCellSet {.final, pure.} = object
+    counter, max: int
+    head: PPageDesc
+    data: PPageDescArray
+
+  PCellArray = ptr array[0..100_000_000, PCell]
+  TCellSeq {.final, pure.} = object
+    len, cap: int
+    d: PCellArray
+
+# ------------------- cell seq handling ---------------------------------------
+
+proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
+  for i in 0 .. s.len-1:
+    if s.d[i] == c: return true
+  return false
+
+proc add(s: var TCellSeq, c: PCell) {.inline.} =
+  if s.len >= s.cap:
+    s.cap = s.cap * 3 div 2
+    var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
+    copyMem(d, s.d, s.len * sizeof(PCell))
+    dealloc(s.d)
+    s.d = d
+    # XXX: realloc?
+  s.d[s.len] = c
+  inc(s.len)
+
+proc init(s: var TCellSeq, cap: int = 1024) =
+  s.len = 0
+  s.cap = cap
+  s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
+
+proc deinit(s: var TCellSeq) = 
+  dealloc(s.d)
+  s.d = nil
+  s.len = 0
+  s.cap = 0
+
+# ------------------- cell set handling ---------------------------------------
+
+const
+  InitCellSetSize = 1024 # must be a power of two!
+
+proc init(s: var TCellSet) =
+  s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
+  s.max = InitCellSetSize-1
+  s.counter = 0
+  s.head = nil
+
+proc deinit(s: var TCellSet) =
+  var it = s.head
+  while it != nil:
+    var n = it.next
+    dealloc(it)
+    it = n
+  s.head = nil # play it safe here
+  dealloc(s.data)
+  s.data = nil
+  s.counter = 0
+
+proc nextTry(h, maxHash: int): int {.inline.} =
+  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 cellSetGet(t: TCellSet, key: ByteAddress): PPageDesc =
+  var h = cast[int](key) and t.max
+  while t.data[h] != nil:
+    if t.data[h].key == key: return t.data[h]
+    h = nextTry(h, t.max)
+  return nil
+
+proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
+  var h = cast[int](desc.key) and t.max
+  while data[h] != nil:
+    sysAssert(data[h] != desc, "CellSetRawInsert 1")
+    h = nextTry(h, t.max)
+  sysAssert(data[h] == nil, "CellSetRawInsert 2")
+  data[h] = desc
+
+proc cellSetEnlarge(t: var TCellSet) =
+  var oldMax = t.max
+  t.max = ((t.max+1)*2)-1
+  var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
+  for i in 0 .. oldMax:
+    if t.data[i] != nil:
+      cellSetRawInsert(t, n, t.data[i])
+  dealloc(t.data)
+  t.data = n
+
+proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc =
+  var h = cast[int](key) and t.max
+  while true:
+    var x = t.data[h]
+    if x == nil: break
+    if x.key == key: return x
+    h = nextTry(h, t.max)
+
+  if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
+    cellSetEnlarge(t)
+  inc(t.counter)
+  h = cast[int](key) and t.max
+  while t.data[h] != nil: h = nextTry(h, t.max)
+  sysAssert(t.data[h] == nil, "CellSetPut")
+  # the new page descriptor goes into result
+  result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
+  result.next = t.head
+  result.key = key
+  t.head = result
+  t.data[h] = result
+
+# ---------- slightly higher level procs --------------------------------------
+
+proc contains(s: TCellSet, cell: PCell): bool =
+  var u = cast[ByteAddress](cell)
+  var t = cellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+  else:
+    result = false
+
+proc incl(s: var TCellSet, cell: PCell) {.noinline.} =
+  var u = cast[ByteAddress](cell)
+  var t = cellSetPut(s, u shr PageShift)
+  u = (u %% PageSize) /% MemAlign
+  t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
+
+proc excl(s: var TCellSet, cell: PCell) =
+  var u = cast[ByteAddress](cell)
+  var t = cellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
+                              not (1 shl (u and IntMask)))
+
+proc containsOrIncl(s: var TCellSet, cell: PCell): bool = 
+  var u = cast[ByteAddress](cell)
+  var t = cellSetGet(s, u shr PageShift)
+  if t != nil:
+    u = (u %% PageSize) /% MemAlign
+    result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
+    if not result: 
+      t.bits[u shr IntShift] = t.bits[u shr IntShift] or
+          (1 shl (u and IntMask))
+  else: 
+    incl(s, cell)
+    result = false
+
+iterator elements(t: TCellSet): PCell {.inline.} =
+  # while traversing it is forbidden to add pointers to the tree!
+  var r = t.head
+  while r != nil:
+    var i = 0
+    while i <= high(r.bits):
+      var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
+      # modifying operations are not allowed during traversation
+      var j = 0
+      while w != 0:         # test all remaining bits for zero
+        if (w and 1) != 0:  # the bit is set!
+          yield cast[PCell]((r.key shl PageShift) or
+                              (i shl IntShift +% j) *% MemAlign)
+        inc(j)
+        w = w shr 1
+      inc(i)
+    r = r.next
+
+iterator elementsExcept(t, s: TCellSet): PCell {.inline.} =
+  var r = t.head
+  while r != nil:
+    let ss = cellSetGet(s, r.key)
+    var i = 0
+    while i <= high(r.bits):
+      var w = r.bits[i]
+      if ss != nil:
+        w = w and not ss.bits[i]
+      var j = 0
+      while w != 0:
+        if (w and 1) != 0:
+          yield cast[PCell]((r.key shl PageShift) or
+                              (i shl IntShift +% j) *% MemAlign)
+        inc(j)
+        w = w shr 1
+      inc(i)
+    r = r.next
diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim
new file mode 100644
index 000000000..f3acc81f2
--- /dev/null
+++ b/lib/system/cgprocs.nim
@@ -0,0 +1,25 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Headers for procs that the code generator depends on ("compilerprocs")
+
+proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
+
+type
+  TLibHandle = pointer       # private type
+  TProcAddr = pointer        # library loading and loading of procs:
+
+proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.}
+proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
+proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
+
+proc nimLoadLibraryError(path: string) {.compilerproc, noinline.}
+
+proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline, benign.}
+
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
new file mode 100644
index 000000000..ebd30c353
--- /dev/null
+++ b/lib/system/channels.nim
@@ -0,0 +1,265 @@
+#

+#

+#            Nim's Runtime Library

+#        (c) Copyright 2015 Andreas Rumpf
+#

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

+#    distribution, for details about the copyright.

+#

+

+## Channel support for threads. **Note**: This is part of the system module.

+## Do not import it directly. To activate thread support you need to compile

+## with the ``--threads:on`` command line switch.

+##

+## **Note:** The current implementation of message passing is slow and does

+## not work with cyclic data structures.

+  

+when not declared(NimString):

+  {.error: "You must not import this module explicitly".}

+

+type

+  pbytes = ptr array[0.. 0xffff, byte]

+  TRawChannel {.pure, final.} = object ## msg queue for a thread

+    rd, wr, count, mask: int

+    data: pbytes

+    lock: TSysLock

+    cond: TSysCond

+    elemType: PNimType

+    ready: bool

+    region: TMemRegion

+  PRawChannel = ptr TRawChannel

+  TLoadStoreMode = enum mStore, mLoad

+  TChannel* {.gcsafe.}[TMsg] = TRawChannel ## a channel for thread communication

+

+const ChannelDeadMask = -2

+

+proc initRawChannel(p: pointer) =

+  var c = cast[PRawChannel](p)

+  initSysLock(c.lock)

+  initSysCond(c.cond)

+  c.mask = -1

+

+proc deinitRawChannel(p: pointer) =

+  var c = cast[PRawChannel](p)

+  # we need to grab the lock to be safe against sending threads!

+  acquireSys(c.lock)

+  c.mask = ChannelDeadMask

+  deallocOsPages(c.region)

+  deinitSys(c.lock)

+  deinitSysCond(c.cond)

+

+proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, 

+              mode: TLoadStoreMode) {.benign.}

+proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,

+              mode: TLoadStoreMode) {.benign.} =

+  var

+    d = cast[ByteAddress](dest)

+    s = cast[ByteAddress](src)

+  case n.kind

+  of nkSlot: storeAux(cast[pointer](d +% n.offset), 

+                      cast[pointer](s +% n.offset), n.typ, t, mode)

+  of nkList:

+    for i in 0..n.len-1: storeAux(dest, src, n.sons[i], t, mode)

+  of nkCase:

+    copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),

+            n.typ.size)

+    var m = selectBranch(src, n)

+    if m != nil: storeAux(dest, src, m, t, mode)

+  of nkNone: sysAssert(false, "storeAux")

+

+proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, 

+              mode: TLoadStoreMode) =

+  var

+    d = cast[ByteAddress](dest)

+    s = cast[ByteAddress](src)

+  sysAssert(mt != nil, "mt == nil")

+  case mt.kind

+  of tyString:

+    if mode == mStore:

+      var x = cast[PPointer](dest)

+      var s2 = cast[PPointer](s)[]

+      if s2 == nil: 

+        x[] = nil

+      else:

+        var ss = cast[NimString](s2)

+        var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize))

+        copyMem(ns, ss, ss.len+1 + GenericSeqSize)

+        x[] = ns

+    else:

+      var x = cast[PPointer](dest)

+      var s2 = cast[PPointer](s)[]

+      if s2 == nil:

+        unsureAsgnRef(x, s2)

+      else:

+        unsureAsgnRef(x, copyString(cast[NimString](s2)))

+        dealloc(t.region, s2)

+  of tySequence:

+    var s2 = cast[PPointer](src)[]

+    var seq = cast[PGenericSeq](s2)

+    var x = cast[PPointer](dest)

+    if s2 == nil:

+      if mode == mStore:

+        x[] = nil

+      else:

+        unsureAsgnRef(x, nil)

+    else:

+      sysAssert(dest != nil, "dest == nil")

+      if mode == mStore:

+        x[] = alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)

+      else:

+        unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))

+      var dst = cast[ByteAddress](cast[PPointer](dest)[])

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

+        storeAux(

+          cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),

+          cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%

+                        GenericSeqSize),

+          mt.base, t, mode)

+      var dstseq = cast[PGenericSeq](dst)

+      dstseq.len = seq.len

+      dstseq.reserved = seq.len

+      if mode != mStore: dealloc(t.region, s2)

+  of tyObject:

+    # copy type field:

+    var pint = cast[ptr PNimType](dest)

+    # XXX use dynamic type here!

+    pint[] = mt

+    if mt.base != nil:

+      storeAux(dest, src, mt.base, t, mode)

+    storeAux(dest, src, mt.node, t, mode)

+  of tyTuple:

+    storeAux(dest, src, mt.node, t, mode)

+  of tyArray, tyArrayConstr:

+    for i in 0..(mt.size div mt.base.size)-1:

+      storeAux(cast[pointer](d +% i*% mt.base.size),

+               cast[pointer](s +% i*% mt.base.size), mt.base, t, mode)

+  of tyRef:

+    var s = cast[PPointer](src)[]

+    var x = cast[PPointer](dest)

+    if s == nil:

+      if mode == mStore:

+        x[] = nil

+      else:

+        unsureAsgnRef(x, nil)

+    else:

+      if mode == mStore:

+        x[] = alloc(t.region, mt.base.size)

+      else:

+        # XXX we should use the dynamic type here too, but that is not stored

+        # in the inbox at all --> use source[]'s object type? but how? we need

+        # a tyRef to the object!

+        var obj = newObj(mt, mt.base.size)

+        unsureAsgnRef(x, obj)

+      storeAux(x[], s, mt.base, t, mode)

+      if mode != mStore: dealloc(t.region, s)

+  else:

+    copyMem(dest, src, mt.size) # copy raw bits

+

+proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =

+  ## adds an `item` to the end of the queue `q`.

+  var cap = q.mask+1

+  if q.count >= cap:

+    # start with capacity for 2 entries in the queue:

+    if cap == 0: cap = 1

+    var n = cast[pbytes](alloc0(q.region, cap*2*typ.size))

+    var z = 0

+    var i = q.rd

+    var c = q.count

+    while c > 0:

+      dec c

+      copyMem(addr(n[z*typ.size]), addr(q.data[i*typ.size]), typ.size)

+      i = (i + 1) and q.mask

+      inc z

+    if q.data != nil: dealloc(q.region, q.data)

+    q.data = n

+    q.mask = cap*2 - 1

+    q.wr = q.count

+    q.rd = 0

+  storeAux(addr(q.data[q.wr * typ.size]), data, typ, q, mStore)

+  inc q.count

+  q.wr = (q.wr + 1) and q.mask

+

+proc rawRecv(q: PRawChannel, data: pointer, typ: PNimType) =

+  sysAssert q.count > 0, "rawRecv"

+  dec q.count

+  storeAux(data, addr(q.data[q.rd * typ.size]), typ, q, mLoad)

+  q.rd = (q.rd + 1) and q.mask

+

+template lockChannel(q: expr, action: stmt) {.immediate.} =

+  acquireSys(q.lock)

+  action

+  releaseSys(q.lock)

+

+template sendImpl(q: expr) {.immediate.} =  

+  if q.mask == ChannelDeadMask:

+    sysFatal(DeadThreadError, "cannot send message; thread died")

+  acquireSys(q.lock)

+  var m: TMsg

+  shallowCopy(m, msg)

+  var typ = cast[PNimType](getTypeInfo(msg))

+  rawSend(q, addr(m), typ)

+  q.elemType = typ

+  releaseSys(q.lock)

+  signalSysCond(q.cond)

+

+proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) =

+  ## sends a message to a thread. `msg` is deeply copied.

+  var q = cast[PRawChannel](addr(c))

+  sendImpl(q)

+

+proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =

+  # to save space, the generic is as small as possible

+  q.ready = true

+  while q.count <= 0:

+    waitSysCond(q.cond, q.lock)

+  q.ready = false

+  if typ != q.elemType:

+    releaseSys(q.lock)

+    sysFatal(ValueError, "cannot receive message of wrong type")

+  rawRecv(q, res, typ)

+

+proc recv*[TMsg](c: var TChannel[TMsg]): TMsg =

+  ## receives a message from the channel `c`. This blocks until

+  ## a message has arrived! You may use ``peek`` to avoid the blocking.

+  var q = cast[PRawChannel](addr(c))

+  acquireSys(q.lock)

+  llRecv(q, addr(result), cast[PNimType](getTypeInfo(result)))

+  releaseSys(q.lock)

+

+proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,

+                                                  msg: TMsg] =

+  ## try to receives a message from the channel `c` if available. Otherwise

+  ## it returns ``(false, default(msg))``.

+  var q = cast[PRawChannel](addr(c))

+  if q.mask != ChannelDeadMask:

+    if tryAcquireSys(q.lock):
+      if q.count > 0:

+        llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))

+        result.dataAvailable = true

+      releaseSys(q.lock)

+

+proc peek*[TMsg](c: var TChannel[TMsg]): int =

+  ## returns the current number of messages in the channel `c`. Returns -1

+  ## if the channel has been closed. **Note**: This is dangerous to use

+  ## as it encourages races. It's much better to use ``tryRecv`` instead.

+  var q = cast[PRawChannel](addr(c))

+  if q.mask != ChannelDeadMask:

+    lockChannel(q):

+      result = q.count

+  else:

+    result = -1

+

+proc open*[TMsg](c: var TChannel[TMsg]) =

+  ## opens a channel `c` for inter thread communication.

+  initRawChannel(addr(c))

+

+proc close*[TMsg](c: var TChannel[TMsg]) =

+  ## closes a channel `c` and frees its associated resources.

+  deinitRawChannel(addr(c))

+

+proc ready*[TMsg](c: var TChannel[TMsg]): bool =

+  ## returns true iff some thread is waiting on the channel `c` for

+  ## new messages.

+  var q = cast[PRawChannel](addr(c))

+  result = q.ready

+

diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim
new file mode 100644
index 000000000..6caf99d27
--- /dev/null
+++ b/lib/system/chcks.nim
@@ -0,0 +1,99 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Implementation of some runtime checks.
+
+proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
+  when hostOS == "standalone":
+    sysFatal(RangeError, "value out of range")
+  else:
+    sysFatal(RangeError, "value out of range: ", $val)
+
+proc raiseIndexError() {.compilerproc, noinline.} =
+  sysFatal(IndexError, "index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noinline.} =
+  sysFatal(FieldError, f, " is not accessible")
+
+proc chckIndx(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseIndexError()
+
+proc chckRange(i, a, b: int): int =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
+  if i >= a and i <= b:
+    return i
+  else:
+    raiseRangeError(i)
+
+proc chckRangeF(x, a, b: float): float =
+  if x >= a and x <= b:
+    return x
+  else:
+    when hostOS == "standalone":
+      sysFatal(RangeError, "value out of range")
+    else:
+      sysFatal(RangeError, "value out of range: ", $x)
+
+proc chckNil(p: pointer) =
+  if p == nil:
+    sysFatal(ValueError, "attempt to write to a nil address")
+    #c_raise(SIGSEGV)
+
+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:
+      sysFatal(ObjectConversionError, "invalid object conversion")
+      break
+    x = x.base
+
+proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
+  if a != b:
+    sysFatal(ObjectAssignmentError, "invalid object assignment")
+
+type ObjCheckCache = array[0..1, PNimType]
+
+proc isObjSlowPath(obj, subclass: PNimType;
+                   cache: var ObjCheckCache): bool {.noinline.} =
+  # checks if obj is of type subclass:
+  var x = obj.base
+  while x != subclass:
+    if x == nil:
+      cache[0] = obj
+      return false
+    x = x.base
+  cache[1] = obj
+  return true
+
+proc isObjWithCache(obj, subclass: PNimType;
+                    cache: var ObjCheckCache): bool {.compilerProc, inline.} =
+  if obj == subclass: return true
+  if obj.base == subclass: return true
+  if cache[0] == obj: return false
+  if cache[1] == obj: return true
+  return isObjSlowPath(obj, subclass, cache)
+
+proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return true # optimized fast path
+  while x != subclass:
+    if x == nil: return false
+    x = x.base
+  return true
diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim
new file mode 100644
index 000000000..7b5169344
--- /dev/null
+++ b/lib/system/debugger.nim
@@ -0,0 +1,303 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This file implements basic features for any debugger.
+
+type
+  TVarSlot* {.compilerproc, final.} = object ## a slot in a frame
+    address*: pointer ## the variable's address
+    typ*: PNimType    ## the variable's type
+    name*: cstring    ## the variable's name; for globals this is "module.name"
+
+  PExtendedFrame = ptr TExtendedFrame
+  TExtendedFrame = object  # If the debugger is enabled the compiler
+                           # provides an extended frame. Of course
+                           # only slots that are
+                           # needed are allocated and not 10_000,
+                           # except for the global data description.
+    f: TFrame
+    slots: array[0..10_000, TVarSlot]
+
+var
+  dbgGlobalData: TExtendedFrame # this reserves much space, but
+                                # for now it is the most practical way
+
+proc dbgRegisterGlobal(name: cstring, address: pointer,
+                       typ: PNimType) {.compilerproc.} =
+  let i = dbgGlobalData.f.len
+  if i >= high(dbgGlobalData.slots):
+    #debugOut("[Warning] cannot register global ")
+    return
+  dbgGlobalData.slots[i].name = name
+  dbgGlobalData.slots[i].typ = typ
+  dbgGlobalData.slots[i].address = address
+  inc(dbgGlobalData.f.len)
+
+proc getLocal*(frame: PFrame; slot: int): TVarSlot {.inline.} =
+  ## retrieves the meta data for the local variable at `slot`. CAUTION: An
+  ## invalid `slot` value causes a corruption!
+  result = cast[PExtendedFrame](frame).slots[slot]
+
+proc getGlobalLen*(): int {.inline.} =
+  ## gets the number of registered globals.
+  result = dbgGlobalData.f.len
+
+proc getGlobal*(slot: int): TVarSlot {.inline.} =
+  ## retrieves the meta data for the global variable at `slot`. CAUTION: An
+  ## invalid `slot` value causes a corruption!
+  result = dbgGlobalData.slots[slot]
+
+# ------------------- breakpoint support ------------------------------------
+
+type
+  TBreakpoint* = object  ## represents a break point
+    low*, high*: int     ## range from low to high; if disabled
+                         ## both low and high are set to their negative values
+    filename*: cstring   ## the filename of the breakpoint
+
+var
+  dbgBP: array[0..127, TBreakpoint] # breakpoints
+  dbgBPlen: int
+  dbgBPbloom: int64  # we use a bloom filter to speed up breakpoint checking
+  
+  dbgFilenames*: array[0..300, cstring] ## registered filenames;
+                                        ## 'nil' terminated
+  dbgFilenameLen: int
+
+proc dbgRegisterFilename(filename: cstring) {.compilerproc.} =
+  # XXX we could check for duplicates here for DLL support
+  dbgFilenames[dbgFilenameLen] = filename
+  inc dbgFilenameLen
+
+proc dbgRegisterBreakpoint(line: int,
+                           filename, name: cstring) {.compilerproc.} =
+  let x = dbgBPlen
+  if x >= high(dbgBP):
+    #debugOut("[Warning] cannot register breakpoint")
+    return
+  inc(dbgBPlen)
+  dbgBP[x].filename = filename
+  dbgBP[x].low = line
+  dbgBP[x].high = line
+  dbgBPbloom = dbgBPbloom or line
+
+proc addBreakpoint*(filename: cstring, lo, hi: int): bool =
+  let x = dbgBPlen
+  if x >= high(dbgBP): return false
+  inc(dbgBPlen)
+  result = true
+  dbgBP[x].filename = filename
+  dbgBP[x].low = lo
+  dbgBP[x].high = hi
+  for line in lo..hi: dbgBPbloom = dbgBPbloom or line
+
+const
+  FileSystemCaseInsensitive = defined(windows) or defined(dos) or defined(os2)
+
+proc fileMatches(c, bp: cstring): bool =
+  # bp = breakpoint filename
+  # c = current filename
+  # we consider it a match if bp is a suffix of c
+  # and the character for the suffix does not exist or
+  # is one of: \  /  :
+  # depending on the OS case does not matter!
+  var blen: int = c_strlen(bp)
+  var clen: int = c_strlen(c)
+  if blen > clen: return false
+  # check for \ /  :
+  if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}:
+    return false
+  var i = 0
+  while i < blen:
+    var x = bp[i]
+    var y = c[i+clen-blen]
+    when FileSystemCaseInsensitive:
+      if x >= 'A' and x <= 'Z': x = chr(ord(x) - ord('A') + ord('a'))
+      if y >= 'A' and y <= 'Z': y = chr(ord(y) - ord('A') + ord('a'))
+    if x != y: return false
+    inc(i)
+  return true
+
+proc canonFilename*(filename: cstring): cstring =
+  ## returns 'nil' if the filename cannot be found.
+  for i in 0 .. <dbgFilenameLen:
+    result = dbgFilenames[i]
+    if fileMatches(result, filename): return result
+  result = nil
+
+iterator listBreakpoints*(): ptr TBreakpoint =
+  ## lists all breakpoints.
+  for i in 0..dbgBPlen-1: yield addr(dbgBP[i])
+
+proc isActive*(b: ptr TBreakpoint): bool = b.low > 0
+proc flip*(b: ptr TBreakpoint) =
+  ## enables or disables 'b' depending on its current state.
+  b.low = -b.low; b.high = -b.high
+
+proc checkBreakpoints*(filename: cstring, line: int): ptr TBreakpoint =
+  ## in which breakpoint (if any) we are.
+  if (dbgBPbloom and line) != line: return nil
+  for b in listBreakpoints():
+    if line >= b.low and line <= b.high and filename == b.filename: return b
+
+# ------------------- watchpoint support ------------------------------------
+
+type
+  THash = int
+  TWatchpoint {.pure, final.} = object
+    name: cstring
+    address: pointer
+    typ: PNimType
+    oldValue: THash
+
+var
+  watchpoints: array [0..99, TWatchpoint]
+  watchpointsLen: int
+
+proc `!&`(h: THash, val: int): THash {.inline.} =
+  result = h +% val
+  result = result +% result shl 10
+  result = result xor (result shr 6)
+
+proc `!$`(h: THash): THash {.inline.} =
+  result = h +% h shl 3
+  result = result xor (result shr 11)
+  result = result +% result shl 15
+
+proc hash(data: pointer, size: int): THash =
+  var h: THash = 0
+  var p = cast[cstring](data)
+  var i = 0
+  var s = size
+  while s > 0:
+    h = h !& ord(p[i])
+    inc(i)
+    dec(s)
+  result = !$h
+
+proc hashGcHeader(data: pointer): THash =
+  const headerSize = sizeof(int)*2
+  result = hash(cast[pointer](cast[int](data) -% headerSize), headerSize)
+
+proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool,
+                    h: THash): THash
+proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool,
+                    h: THash): THash =
+  var d = cast[ByteAddress](dest)
+  case n.kind
+  of nkSlot:
+    result = genericHashAux(cast[pointer](d +% n.offset), n.typ, shallow, h)
+  of nkList:
+    result = h
+    for i in 0..n.len-1: 
+      result = result !& genericHashAux(dest, n.sons[i], shallow, result)
+  of nkCase:
+    result = h !& hash(cast[pointer](d +% n.offset), n.typ.size)
+    var m = selectBranch(dest, n)
+    if m != nil: result = genericHashAux(dest, m, shallow, result)
+  of nkNone: sysAssert(false, "genericHashAux")
+
+proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, 
+                    h: THash): THash =
+  sysAssert(mt != nil, "genericHashAux 2")
+  case mt.kind
+  of tyString:
+    var x = cast[PPointer](dest)[]
+    result = h
+    if x != nil:
+      let s = cast[NimString](x)
+      when defined(trackGcHeaders):
+        result = result !& hashGcHeader(x)
+      else:
+        result = result !& hash(x, s.len)
+  of tySequence:
+    var x = cast[PPointer](dest)
+    var dst = cast[ByteAddress](cast[PPointer](dest)[])
+    result = h
+    if dst != 0:
+      when defined(trackGcHeaders):
+        result = result !& hashGcHeader(cast[PPointer](dest)[])
+      else:
+        for i in 0..cast[PGenericSeq](dst).len-1:
+          result = result !& genericHashAux(
+            cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+            mt.base, shallow, result)
+  of tyObject, tyTuple:
+    # we don't need to copy m_type field for tyObject, as they are equal anyway
+    result = genericHashAux(dest, mt.node, shallow, h)
+  of tyArray, tyArrayConstr:
+    let d = cast[ByteAddress](dest)
+    result = h
+    for i in 0..(mt.size div mt.base.size)-1:
+      result = result !& genericHashAux(cast[pointer](d +% i*% mt.base.size),
+                                        mt.base, shallow, result)
+  of tyRef:
+    when defined(trackGcHeaders):
+      var s = cast[PPointer](dest)[]
+      if s != nil:
+        result = result !& hashGcHeader(s)
+    else:
+      if shallow:
+        result = h !& hash(dest, mt.size)
+      else:
+        result = h
+        var s = cast[PPointer](dest)[]
+        if s != nil:
+          result = result !& genericHashAux(s, mt.base, shallow, result)
+  else:
+    result = h !& hash(dest, mt.size) # hash raw bits
+
+proc genericHash(dest: pointer, mt: PNimType): int =
+  result = genericHashAux(dest, mt, false, 0)
+  
+proc dbgRegisterWatchpoint(address: pointer, name: cstring,
+                           typ: PNimType) {.compilerproc.} =
+  let L = watchPointsLen
+  for i in 0.. <L:
+    if watchPoints[i].name == name:
+      # address may have changed:
+      watchPoints[i].address = address
+      return
+  if L >= watchPoints.high:
+    #debugOut("[Warning] cannot register watchpoint")
+    return
+  watchPoints[L].name = name
+  watchPoints[L].address = address
+  watchPoints[L].typ = typ
+  watchPoints[L].oldValue = genericHash(address, typ)
+  inc watchPointsLen
+
+proc dbgUnregisterWatchpoints*() =
+  watchPointsLen = 0
+
+var
+  dbgLineHook*: proc () {.nimcall.}
+    ## set this variable to provide a procedure that should be called before
+    ## each executed instruction. This should only be used by debuggers!
+    ## Only code compiled with the ``debugger:on`` switch calls this hook.
+
+  dbgWatchpointHook*: proc (watchpointName: cstring) {.nimcall.}
+  
+proc checkWatchpoints =
+  let L = watchPointsLen
+  for i in 0.. <L:
+    let newHash = genericHash(watchPoints[i].address, watchPoints[i].typ)
+    if newHash != watchPoints[i].oldValue:
+      dbgWatchpointHook(watchPoints[i].name)
+      watchPoints[i].oldValue = newHash
+
+proc endb(line: int, file: cstring) {.compilerproc, noinline.} =
+  # This proc is called before every Nim code line!
+  if framePtr == nil: return
+  if dbgWatchpointHook != nil: checkWatchpoints()
+  framePtr.line = line # this is done here for smaller code size!
+  framePtr.filename = file
+  if dbgLineHook != nil: dbgLineHook()
+
+include "system/endb"
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
new file mode 100644
index 000000000..093c0f3a7
--- /dev/null
+++ b/lib/system/deepcopy.nim
@@ -0,0 +1,141 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) {.benign.}
+proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  case n.kind
+  of nkSlot:
+    genericDeepCopyAux(cast[pointer](d +% n.offset), 
+                       cast[pointer](s +% n.offset), n.typ)
+  of nkList:
+    for i in 0..n.len-1:
+      genericDeepCopyAux(dest, src, n.sons[i])
+  of nkCase:
+    var dd = selectBranch(dest, n)
+    var m = selectBranch(src, n)
+    # reset if different branches are in use; note different branches also
+    # imply that's not self-assignment (``x = x``)!
+    if m != dd and dd != nil: 
+      genericResetAux(dest, dd)
+    copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
+            n.typ.size)
+    if m != nil:
+      genericDeepCopyAux(dest, src, m)
+  of nkNone: sysAssert(false, "genericDeepCopyAux")
+
+proc copyDeepString(src: NimString): NimString {.inline.} =
+  if src != nil:
+    result = rawNewStringNoInit(src.len)
+    result.len = src.len
+    c_memcpy(result.data, src.data, src.len + 1)
+
+proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  sysAssert(mt != nil, "genericDeepCopyAux 2")
+  case mt.kind
+  of tyString:
+    var x = cast[PPointer](dest)
+    var s2 = cast[PPointer](s)[]
+    if s2 == nil:
+      unsureAsgnRef(x, s2)
+    else:
+      unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
+  of tySequence:
+    var s2 = cast[PPointer](src)[]
+    var seq = cast[PGenericSeq](s2)
+    var x = cast[PPointer](dest)
+    if s2 == nil:
+      unsureAsgnRef(x, s2)
+      return
+    sysAssert(dest != nil, "genericDeepCopyAux 3")
+    unsureAsgnRef(x, newSeq(mt, seq.len))
+    var dst = cast[ByteAddress](cast[PPointer](dest)[])
+    for i in 0..seq.len-1:
+      genericDeepCopyAux(
+        cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
+        cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
+                     GenericSeqSize),
+        mt.base)
+  of tyObject:
+    # we need to copy m_type field for tyObject, as it could be empty for
+    # sequence reallocations:
+    var pint = cast[ptr PNimType](dest)
+    pint[] = cast[ptr PNimType](src)[]
+    if mt.base != nil:
+      genericDeepCopyAux(dest, src, mt.base)
+    genericDeepCopyAux(dest, src, mt.node)
+  of tyTuple:
+    genericDeepCopyAux(dest, src, mt.node)
+  of tyArray, tyArrayConstr:
+    for i in 0..(mt.size div mt.base.size)-1:
+      genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
+                         cast[pointer](s +% i*% mt.base.size), mt.base)
+  of tyRef:
+    let s2 = cast[PPointer](src)[]
+    if s2 == nil:
+      unsureAsgnRef(cast[PPointer](dest), s2)
+    elif mt.base.deepcopy != nil:
+      let z = mt.base.deepcopy(s2)
+      unsureAsgnRef(cast[PPointer](dest), z)
+    else:
+      # we modify the header of the cell temporarily; instead of the type
+      # field we store a forwarding pointer. XXX This is bad when the cloning
+      # fails due to OOM etc.
+      when declared(usrToCell):
+        # unfortunately we only have cycle detection for our native GCs.
+        let x = usrToCell(s2)
+        let forw = cast[int](x.typ)
+        if (forw and 1) == 1:
+          # we stored a forwarding pointer, so let's use that:
+          let z = cast[pointer](forw and not 1)
+          unsureAsgnRef(cast[PPointer](dest), z)
+        else:
+          let realType = x.typ
+          let z = newObj(realType, realType.base.size)
+          
+          unsureAsgnRef(cast[PPointer](dest), z)
+          x.typ = cast[PNimType](cast[int](z) or 1)
+          genericDeepCopyAux(z, s2, realType.base)
+          x.typ = realType
+      else:
+        let realType = mt
+        let z = newObj(realType, realType.base.size)        
+        unsureAsgnRef(cast[PPointer](dest), z)
+        genericDeepCopyAux(z, s2, realType.base)        
+  of tyPtr:
+    # no cycle check here, but also not really required
+    let s2 = cast[PPointer](src)[]
+    if s2 != nil and mt.base.deepcopy != nil:
+      cast[PPointer](dest)[] = mt.base.deepcopy(s2)
+    else:
+      cast[PPointer](dest)[] = s2
+  else:
+    copyMem(dest, src, mt.size)
+
+proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
+  genericDeepCopyAux(dest, src, mt)
+
+proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
+  # also invoked for 'string'
+  var src = src
+  genericDeepCopy(dest, addr(src), mt)
+
+proc genericDeepCopyOpenArray(dest, src: pointer, len: int,
+                            mt: PNimType) {.compilerproc.} =
+  var
+    d = cast[ByteAddress](dest)
+    s = cast[ByteAddress](src)
+  for i in 0..len-1:
+    genericDeepCopy(cast[pointer](d +% i*% mt.base.size),
+                    cast[pointer](s +% i*% mt.base.size), mt.base)
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
new file mode 100644
index 000000000..44f7b67c3
--- /dev/null
+++ b/lib/system/dyncalls.nim
@@ -0,0 +1,150 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This file implements the ability to call native procs from libraries.
+# It is not possible to do this in a platform independent way, unfortunately.
+# However, the interface has been designed to take platform differences into
+# account and been ported to all major platforms.
+
+{.push stack_trace: off.}
+
+const
+  NilLibHandle: TLibHandle = nil
+
+proc rawWrite(f: File, s: string) = 
+  # we cannot throw an exception here!
+  discard writeBuffer(f, cstring(s), s.len)
+
+proc nimLoadLibraryError(path: string) =
+  # carefully written to avoid memory allocation:
+  stdout.rawWrite("could not load: ")
+  stdout.rawWrite(path)
+  stdout.rawWrite("\n")
+  quit(1)
+
+proc procAddrError(name: cstring) {.noinline.} =
+  # carefully written to avoid memory allocation:
+  stdout.rawWrite("could not import: ")
+  stdout.write(name)
+  stdout.rawWrite("\n")
+  quit(1)
+
+# this code was inspired from Lua's source code:
+# Lua - An Extensible Extension Language
+# Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
+# http://www.lua.org
+# mailto:info@lua.org
+
+when defined(posix):
+  #
+  # =========================================================================
+  # This is an implementation based on the dlfcn interface.
+  # The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
+  # NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
+  # as an emulation layer on top of native functions.
+  # =========================================================================
+  #
+
+  # c stuff:
+  var
+    RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
+
+  proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
+  proc dlopen(path: cstring, mode: int): TLibHandle {.
+      importc, header: "<dlfcn.h>".}
+  proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
+      importc, header: "<dlfcn.h>".}
+
+  proc dlerror(): cstring {.importc, header: "<dlfcn.h>".}
+
+  proc nimUnloadLibrary(lib: TLibHandle) =
+    dlclose(lib)
+
+  proc nimLoadLibrary(path: string): TLibHandle =
+    result = dlopen(path, RTLD_NOW)
+    #c_fprintf(c_stdout, "%s\n", dlerror())
+
+  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
+    result = dlsym(lib, name)
+    if result == nil: procAddrError(name)
+
+elif defined(windows) or defined(dos):
+  #
+  # =======================================================================
+  # Native Windows Implementation
+  # =======================================================================
+  #
+  when defined(cpp):
+    type
+      THINSTANCE {.importc: "HINSTANCE".} = object
+        x: pointer
+    proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
+        importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.}
+  else:
+    type
+      THINSTANCE {.importc: "HINSTANCE".} = pointer
+    proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
+        importc: "GetProcAddress", header: "<windows.h>", stdcall.}
+
+  proc freeLibrary(lib: THINSTANCE) {.
+      importc: "FreeLibrary", header: "<windows.h>", stdcall.}
+  proc winLoadLibrary(path: cstring): THINSTANCE {.
+      importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
+
+  proc nimUnloadLibrary(lib: TLibHandle) =
+    freeLibrary(cast[THINSTANCE](lib))
+
+  proc nimLoadLibrary(path: string): TLibHandle =
+    result = cast[TLibHandle](winLoadLibrary(path))
+
+  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
+    result = getProcAddress(cast[THINSTANCE](lib), name)
+    if result == nil: procAddrError(name)
+
+elif defined(mac):
+  #
+  # =======================================================================
+  # Native Mac OS X / Darwin Implementation
+  # =======================================================================
+  #
+  {.error: "no implementation for dyncalls yet".}
+
+  proc nimUnloadLibrary(lib: TLibHandle) =
+    NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
+
+  var
+    dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
+
+  proc nimLoadLibrary(path: string): TLibHandle =
+    var
+      img: NSObjectFileImage
+      ret: NSObjectFileImageReturnCode
+      modul: NSModule
+    # this would be a rare case, but prevents crashing if it happens
+    result = nil
+    if dyld_present != 0:
+      ret = NSCreateObjectFileImageFromFile(path, addr(img))
+      if ret == NSObjectFileImageSuccess:
+        modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
+                                        NSLINKMODULE_OPTION_RETURN_ON_ERROR)
+        NSDestroyObjectFileImage(img)
+        result = TLibHandle(modul)
+
+  proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
+    var
+      nss: NSSymbol
+    nss = NSLookupSymbolInModule(NSModule(lib), name)
+    result = TProcAddr(NSAddressOfSymbol(nss))
+    if result == nil: ProcAddrError(name)
+
+else:
+  {.error: "no implementation for dyncalls".}
+  
+{.pop.}
+
diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim
new file mode 100644
index 000000000..a14f43e7e
--- /dev/null
+++ b/lib/system/embedded.nim
@@ -0,0 +1,43 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# Bare-bones implementation of some things for embedded targets.
+
+proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
+proc chckRange(i, a, b: int): int {.inline, compilerproc.}
+proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
+proc chckNil(p: pointer) {.inline, compilerproc.}
+
+proc nimFrame(s: PFrame) {.compilerRtl, inl, exportc: "nimFrame".} = discard
+proc popFrame {.compilerRtl, inl.} = discard
+
+proc setFrame(s: PFrame) {.compilerRtl, inl.} = discard
+proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = discard
+proc popSafePoint {.compilerRtl, inl.} = discard
+proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} = discard
+proc popCurrentException {.compilerRtl, inl.} = discard
+
+# some platforms have native support for stack traces:
+const
+  nativeStackTraceSupported = false
+  hasSomeStackTrace = false
+
+proc quitOrDebug() {.inline.} =
+  quit(1)
+
+proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
+  sysFatal(ReraiseError, "exception handling is not available")
+
+proc reraiseException() {.compilerRtl.} =
+  sysFatal(ReraiseError, "no exception to reraise")
+
+proc writeStackTrace() = discard
+
+proc setControlCHook(hook: proc () {.noconv.} not nil) = discard
diff --git a/lib/system/endb.nim b/lib/system/endb.nim
new file mode 100644
index 000000000..003698421
--- /dev/null
+++ b/lib/system/endb.nim
@@ -0,0 +1,538 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This file implements the embedded debugger that can be linked
+# with the application. Mostly we do not use dynamic memory here as that
+# would interfere with the GC and trigger ON/OFF errors if the
+# user program corrupts memory. Unfortunately, for dispaying
+# variables we use the ``system.repr()`` proc which uses Nim
+# strings and thus allocates memory from the heap. Pity, but
+# I do not want to implement ``repr()`` twice.
+
+const
+  EndbBeg = "*** endb"
+  EndbEnd = "***\n"
+
+type
+  TStaticStr = object
+    len: int
+    data: array[0..100, char]
+
+  TBreakpointFilename = object
+    b: ptr TBreakpoint
+    filename: TStaticStr
+
+  TDbgState = enum
+    dbOff,        # debugger is turned off
+    dbStepInto,   # debugger is in tracing mode
+    dbStepOver,
+    dbSkipCurrent,
+    dbQuiting,    # debugger wants to quit
+    dbBreakpoints # debugger is only interested in breakpoints
+
+var
+  dbgUser: TStaticStr   # buffer for user input; first command is ``step_into``
+                        # needs to be global cause we store the last command
+                        # in it
+  dbgState: TDbgState   # state of debugger
+  dbgSkipToFrame: PFrame # frame to be skipped to
+
+  maxDisplayRecDepth: int = 5 # do not display too much data!
+
+  brkPoints: array[0..127, TBreakpointFilename]
+
+proc setLen(s: var TStaticStr, newLen=0) =
+  s.len = newLen
+  s.data[newLen] = '\0'
+
+proc add(s: var TStaticStr, c: char) =
+  if s.len < high(s.data)-1:
+    s.data[s.len] = c
+    s.data[s.len+1] = '\0'
+    inc s.len
+
+proc add(s: var TStaticStr, c: cstring) =
+  var i = 0
+  while c[i] != '\0':
+    add s, c[i]
+    inc i
+
+proc assign(s: var TStaticStr, c: cstring) =
+  setLen(s)
+  add s, c
+
+proc `==`(a, b: TStaticStr): bool =
+  if a.len == b.len:
+    for i in 0 .. a.len-1:
+      if a.data[i] != b.data[i]: return false
+    return true
+
+proc `==`(a: TStaticStr, b: cstring): bool =
+  result = c_strcmp(a.data, b) == 0
+
+proc write(f: TFile, s: TStaticStr) =
+  write(f, cstring(s.data))
+
+proc listBreakPoints() =
+  write(stdout, EndbBeg)
+  write(stdout, "| Breakpoints:\n")
+  for b in listBreakpoints():
+    write(stdout, abs(b.low))
+    if b.high != b.low:
+      write(stdout, "..")
+      write(stdout, abs(b.high))
+    write(stdout, " ")
+    write(stdout, b.filename)
+    if b.isActive:
+      write(stdout, " [disabled]\n")
+    else:
+      write(stdout, "\n")
+  write(stdout, EndbEnd)
+
+proc openAppend(filename: cstring): TFile =
+  var p: pointer = fopen(filename, "ab")
+  if p != nil:
+    result = cast[TFile](p)
+    write(result, "----------------------------------------\n")
+
+proc dbgRepr(p: pointer, typ: PNimType): string =
+  var cl: TReprClosure
+  initReprClosure(cl)
+  cl.recDepth = maxDisplayRecDepth
+  # locks for the GC turned out to be a bad idea...
+  # inc(recGcLock)
+  result = ""
+  reprAux(result, p, typ, cl)
+  # dec(recGcLock)
+  deinitReprClosure(cl)
+
+proc writeVariable(stream: TFile, slot: TVarSlot) =
+  write(stream, slot.name)
+  write(stream, " = ")
+  writeln(stream, dbgRepr(slot.address, slot.typ))
+
+proc listFrame(stream: TFile, f: PFrame) =
+  write(stream, EndbBeg)
+  write(stream, "| Frame (")
+  write(stream, f.len)
+  write(stream, " slots):\n")
+  for i in 0 .. f.len-1:
+    writeln(stream, getLocal(f, i).name)
+  write(stream, EndbEnd)
+
+proc listLocals(stream: TFile, f: PFrame) =
+  write(stream, EndbBeg)
+  write(stream, "| Frame (")
+  write(stream, f.len)
+  write(stream, " slots):\n")
+  for i in 0 .. f.len-1:
+    writeVariable(stream, getLocal(f, i))
+  write(stream, EndbEnd)
+
+proc listGlobals(stream: TFile) =
+  write(stream, EndbBeg)
+  write(stream, "| Globals:\n")
+  for i in 0 .. getGlobalLen()-1:
+    writeln(stream, getGlobal(i).name)
+  write(stream, EndbEnd)
+
+proc debugOut(msg: cstring) =
+  # the *** *** markers are for easy recognition of debugger
+  # output for external frontends.
+  write(stdout, EndbBeg)
+  write(stdout, "| ")
+  write(stdout, msg)
+  write(stdout, EndbEnd)
+
+proc dbgFatal(msg: cstring) =
+  debugOut(msg)
+  dbgAborting = true # the debugger wants to abort
+  quit(1)
+
+proc dbgShowCurrentProc(dbgFramePointer: PFrame) =
+  if dbgFramePointer != nil:
+    write(stdout, "*** endb| now in proc: ")
+    write(stdout, dbgFramePointer.procname)
+    write(stdout, " ***\n")
+  else:
+    write(stdout, "*** endb| (proc name not available) ***\n")
+
+proc dbgShowExecutionPoint() =
+  write(stdout, "*** endb| ")
+  write(stdout, framePtr.filename)
+  write(stdout, "(")
+  write(stdout, framePtr.line)
+  write(stdout, ") ")
+  write(stdout, framePtr.procname)
+  write(stdout, " ***\n")
+
+proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int =
+  result = start
+  # skip whitespace:
+  while src[result] in {'\t', ' '}: inc(result)
+  while true:
+    case src[result]
+    of 'a'..'z', '0'..'9': add(a, src[result])
+    of '_': discard # just skip it
+    of 'A'..'Z': add(a, chr(ord(src[result]) - ord('A') + ord('a')))
+    else: break
+    inc(result)
+
+proc scanWord(src: cstring, a: var TStaticStr, start: int): int =
+  setlen(a)
+  result = scanAndAppendWord(src, a, start)
+
+proc scanFilename(src: cstring, a: var TStaticStr, start: int): int =
+  result = start
+  setLen a
+  while src[result] in {'\t', ' '}: inc(result)
+  while src[result] notin {'\t', ' ', '\0'}:
+    add(a, src[result])
+    inc(result)
+
+proc scanNumber(src: cstring, a: var int, start: int): int =
+  result = start
+  a = 0
+  while src[result] in {'\t', ' '}: inc(result)
+  while true:
+    case src[result]
+    of '0'..'9': a = a * 10 + ord(src[result]) - ord('0')
+    of '_': discard # skip underscores (nice for long line numbers)
+    else: break
+    inc(result)
+
+proc dbgHelp() =
+  debugOut("""
+list of commands (see the manual for further help):
+              GENERAL
+h, help                 display this help message
+q, quit                 quit the debugger and the program
+<ENTER>                 repeat the previous debugger command
+              EXECUTING
+s, step                 single step, stepping into routine calls
+n, next                 single step, without stepping into routine calls
+f, skipcurrent          continue execution until the current routine finishes
+c, continue, r, run     continue execution until the next breakpoint
+i, ignore               continue execution, ignore all breakpoints
+              BREAKPOINTS
+b, break [fromline [toline]] [file]
+                        set a new breakpoint for line and file
+                        if line or file are omitted the current one is used
+breakpoints             display the entire breakpoint list
+toggle fromline [file]  enable or disable a breakpoint
+filenames               list all valid filenames
+              DATA DISPLAY
+e, eval <expr>          evaluate the expression <expr>
+o, out <file> <expr>    evaluate <expr> and write it to <file>
+w, where                display the current execution point
+stackframe [file]       display current stack frame [and write it to file]
+u, up                   go up in the call stack
+d, down                 go down in the call stack
+bt, backtrace           display the entire call stack
+l, locals               display available local variables
+g, globals              display available global variables
+maxdisplay <integer>    set the display's recursion maximum
+""")
+
+proc invalidCommand() =
+  debugOut("[Warning] invalid command ignored (type 'h' for help) ")
+
+proc hasExt(s: cstring): bool =
+  # returns true if s has a filename extension
+  var i = 0
+  while s[i] != '\0':
+    if s[i] == '.': return true
+    inc i
+
+proc parseBreakpoint(s: cstring, start: int): TBreakpoint =
+  var dbgTemp: TStaticStr
+  var i = scanNumber(s, result.low, start)
+  if result.low == 0: result.low = framePtr.line
+  i = scanNumber(s, result.high, i)
+  if result.high == 0: result.high = result.low
+  i = scanFilename(s, dbgTemp, i)
+  if dbgTemp.len != 0:
+    if not hasExt(dbgTemp.data): add(dbgTemp, ".nim")
+    result.filename = canonFilename(dbgTemp.data.cstring)
+    if result.filename.isNil:
+      debugOut("[Warning] no breakpoint could be set; unknown filename ")
+      return
+  else:
+    result.filename = framePtr.filename
+
+proc createBreakPoint(s: cstring, start: int) =
+  let br = parseBreakpoint(s, start)
+  if not br.filename.isNil:
+    if not addBreakpoint(br.filename, br.low, br.high):
+      debugOut("[Warning] no breakpoint could be set; out of breakpoint space ")
+
+proc breakpointToggle(s: cstring, start: int) =
+  var a = parseBreakpoint(s, start)
+  if not a.filename.isNil:
+    var b = checkBreakpoints(a.filename, a.low)
+    if not b.isNil: b.flip
+    else: debugOut("[Warning] unknown breakpoint ")
+
+proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) =
+  var dbgTemp: TStaticStr
+  var i = scanWord(s, dbgTemp, start)
+  while s[i] in {' ', '\t'}: inc(i)
+  var v: TVarSlot
+  if s[i] == '.':
+    inc(i)
+    add(dbgTemp, '.')
+    i = scanAndAppendWord(s, dbgTemp, i)
+    for i in 0 .. getGlobalLen()-1:
+      let v = getGlobal(i)
+      if c_strcmp(v.name, dbgTemp.data) == 0:
+        writeVariable(stream, v)
+  else:
+    for i in 0 .. f.len-1:
+      let v = getLocal(f, i)
+      if c_strcmp(v.name, dbgTemp.data) == 0:
+        writeVariable(stream, v)  
+
+proc dbgOut(s: cstring, start: int, currFrame: PFrame) =
+  var dbgTemp: TStaticStr
+  var i = scanFilename(s, dbgTemp, start)
+  if dbgTemp.len == 0:
+    invalidCommand()
+    return
+  var stream = openAppend(dbgTemp.data)
+  if stream == nil:
+    debugOut("[Warning] could not open or create file ")
+    return
+  dbgEvaluate(stream, s, i, currFrame)
+  close(stream)
+
+proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
+  var dbgTemp: TStaticStr
+  var i = scanFilename(s, dbgTemp, start)
+  if dbgTemp.len == 0:
+    # just write it to stdout:
+    listFrame(stdout, currFrame)
+  else:
+    var stream = openAppend(dbgTemp.data)
+    if stream == nil:
+      debugOut("[Warning] could not open or create file ")
+      return
+    listFrame(stream, currFrame)
+    close(stream)
+
+proc readLine(f: TFile, line: var TStaticStr): bool =
+  while true:
+    var c = fgetc(f)
+    if c < 0'i32:
+      if line.len > 0: break
+      else: return false
+    if c == 10'i32: break # LF
+    if c == 13'i32:  # CR
+      c = fgetc(f) # is the next char LF?
+      if c != 10'i32: ungetc(c, f) # no, put the character back
+      break
+    add line, chr(int(c))
+  result = true
+
+proc listFilenames() =
+  write(stdout, EndbBeg)
+  write(stdout, "| Files:\n")
+  var i = 0
+  while true:
+    let x = dbgFilenames[i]
+    if x.isNil: break
+    write(stdout, x)
+    write(stdout, "\n")
+    inc i
+  write(stdout, EndbEnd)
+
+proc dbgWriteStackTrace(f: PFrame)
+proc commandPrompt() =
+  # if we return from this routine, user code executes again
+  var
+    again = true
+    dbgFramePtr = framePtr # for going down and up the stack
+    dbgDown = 0 # how often we did go down
+    dbgTemp: TStaticStr
+
+  while again:
+    write(stdout, "*** endb| >>")
+    let oldLen = dbgUser.len
+    dbgUser.len = 0
+    if not readLine(stdin, dbgUser): break
+    if dbgUser.len == 0: dbgUser.len = oldLen
+    # now look what we have to do:
+    var i = scanWord(dbgUser.data, dbgTemp, 0)
+    template `?`(x: expr): expr = dbgTemp == cstring(x)
+    if ?"s" or ?"step":
+      dbgState = dbStepInto
+      again = false
+    elif ?"n" or ?"next":
+      dbgState = dbStepOver
+      dbgSkipToFrame = framePtr
+      again = false
+    elif ?"f" or ?"skipcurrent":
+      dbgState = dbSkipCurrent
+      dbgSkipToFrame = framePtr.prev
+      again = false
+    elif ?"c" or ?"continue" or ?"r" or ?"run":
+      dbgState = dbBreakpoints
+      again = false
+    elif ?"i" or ?"ignore":
+      dbgState = dbOff
+      again = false
+    elif ?"h" or ?"help":
+      dbgHelp()
+    elif ?"q" or ?"quit":
+      dbgState = dbQuiting
+      dbgAborting = true
+      again = false
+      quit(1) # BUGFIX: quit with error code > 0
+    elif ?"e" or ?"eval":
+      dbgEvaluate(stdout, dbgUser.data, i, dbgFramePtr)
+    elif ?"o" or ?"out":
+      dbgOut(dbgUser.data, i, dbgFramePtr)
+    elif ?"stackframe":
+      dbgStackFrame(dbgUser.data, i, dbgFramePtr)
+    elif ?"w" or ?"where":
+      dbgShowExecutionPoint()
+    elif ?"l" or ?"locals":
+      listLocals(stdout, dbgFramePtr)
+    elif ?"g" or ?"globals":
+      listGlobals(stdout)
+    elif ?"u" or ?"up":
+      if dbgDown <= 0:
+        debugOut("[Warning] cannot go up any further ")
+      else:
+        dbgFramePtr = framePtr
+        for j in 0 .. dbgDown-2: # BUGFIX
+          dbgFramePtr = dbgFramePtr.prev
+        dec(dbgDown)
+      dbgShowCurrentProc(dbgFramePtr)
+    elif ?"d" or ?"down":
+      if dbgFramePtr != nil:
+        inc(dbgDown)
+        dbgFramePtr = dbgFramePtr.prev
+        dbgShowCurrentProc(dbgFramePtr)
+      else:
+        debugOut("[Warning] cannot go down any further ")
+    elif ?"bt" or ?"backtrace":
+      dbgWriteStackTrace(framePtr)
+    elif ?"b" or ?"break":
+      createBreakPoint(dbgUser.data, i)
+    elif ?"breakpoints":
+      listBreakPoints()
+    elif ?"toggle":
+      breakpointToggle(dbgUser.data, i)
+    elif ?"filenames":
+      listFilenames()
+    elif ?"maxdisplay":
+      var parsed: int
+      i = scanNumber(dbgUser.data, parsed, i)
+      if dbgUser.data[i-1] in {'0'..'9'}:
+        if parsed == 0: maxDisplayRecDepth = -1
+        else: maxDisplayRecDepth = parsed
+      else:
+        invalidCommand()
+    else: invalidCommand()
+
+proc endbStep() =
+  # we get into here if an unhandled exception has been raised
+  # XXX: do not allow the user to run the program any further?
+  # XXX: BUG: the frame is lost here!
+  dbgShowExecutionPoint()
+  commandPrompt()
+
+proc dbgWriteStackTrace(f: PFrame) =
+  const
+    firstCalls = 32
+  var
+    it = f
+    i = 0
+    total = 0
+    tempFrames: array [0..127, PFrame]
+  # setup long head:
+  while it != nil and i <= high(tempFrames)-firstCalls:
+    tempFrames[i] = it
+    inc(i)
+    inc(total)
+    it = it.prev
+  # go up the stack to count 'total':
+  var b = it
+  while it != nil:
+    inc(total)
+    it = it.prev
+  var skipped = 0
+  if total > len(tempFrames):
+    # skip N
+    skipped = total-i-firstCalls+1
+    for j in 1..skipped:
+      if b != nil: b = b.prev
+    # create '...' entry:
+    tempFrames[i] = nil
+    inc(i)
+  # setup short tail:
+  while b != nil and i <= high(tempFrames):
+    tempFrames[i] = b
+    inc(i)
+    b = b.prev
+  for j in countdown(i-1, 0):
+    if tempFrames[j] == nil: 
+      write(stdout, "(")
+      write(stdout, skipped)
+      write(stdout, " calls omitted) ...")
+    else:
+      write(stdout, tempFrames[j].filename)
+      if tempFrames[j].line > 0:
+        write(stdout, '(')
+        write(stdout, tempFrames[j].line)
+        write(stdout, ')')
+      write(stdout, ' ')
+      write(stdout, tempFrames[j].procname)
+    write(stdout, "\n")
+
+proc checkForBreakpoint =
+  let b = checkBreakpoints(framePtr.filename, framePtr.line)
+  if b != nil:
+    write(stdout, "*** endb| reached ")
+    write(stdout, framePtr.filename)
+    write(stdout, "(")
+    write(stdout, framePtr.line)
+    write(stdout, ") ")
+    write(stdout, framePtr.procname)
+    write(stdout, " ***\n")
+    commandPrompt()
+
+proc lineHookImpl() {.nimcall.} =
+  case dbgState
+  of dbStepInto:
+    # we really want the command prompt here:
+    dbgShowExecutionPoint()
+    commandPrompt()
+  of dbSkipCurrent, dbStepOver: # skip current routine
+    if framePtr == dbgSkipToFrame:
+      dbgShowExecutionPoint()
+      commandPrompt()
+    else:
+      # breakpoints are wanted though (I guess)
+      checkForBreakpoint()
+  of dbBreakpoints:
+    # debugger is only interested in breakpoints
+    checkForBreakpoint()
+  else: discard
+
+proc watchpointHookImpl(name: cstring) {.nimcall.} =
+  dbgWriteStackTrace(framePtr)
+  debugOut(name)
+
+proc initDebugger {.inline.} =
+  dbgState = dbStepInto
+  dbgUser.len = 1
+  dbgUser.data[0] = 's'
+  dbgWatchpointHook = watchpointHookImpl
+  dbgLineHook = lineHookImpl
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
new file mode 100644
index 000000000..189d52f57
--- /dev/null
+++ b/lib/system/excpt.nim
@@ -0,0 +1,369 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Exception handling code. Carefully coded so that tiny programs which do not
+# use the heap (and nor exceptions) do not include the GC or memory allocator.
+
+var
+  errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], benign.})
+    ## Function that will be called
+    ## instead of stdmsg.write when printing stacktrace.
+    ## Unstable API.
+
+when not defined(windows) or not defined(guiapp):
+  proc writeToStdErr(msg: cstring) = write(stdmsg, msg)
+
+else:
+  proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
+    header: "<windows.h>", nodecl.}
+
+  proc writeToStdErr(msg: cstring) =
+    discard MessageBoxA(0, msg, nil, 0)
+
+proc showErrorMessage(data: cstring) =
+  if errorMessageWriter != nil:
+    errorMessageWriter($data)
+  else:
+    writeToStdErr(data)
+
+proc chckIndx(i, a, b: int): int {.inline, compilerproc, benign.}
+proc chckRange(i, a, b: int): int {.inline, compilerproc, benign.}
+proc chckRangeF(x, a, b: float): float {.inline, compilerproc, benign.}
+proc chckNil(p: pointer) {.noinline, compilerproc, benign.}
+
+var
+  framePtr {.threadvar.}: PFrame
+  excHandler {.threadvar.}: PSafePoint
+    # list of exception handlers
+    # a global variable for the root of all try blocks
+  currException {.threadvar.}: ref Exception
+
+proc popFrame {.compilerRtl, inl.} =
+  framePtr = framePtr.prev
+
+proc setFrame(s: PFrame) {.compilerRtl, inl.} =
+  framePtr = s
+
+proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
+  s.hasRaiseAction = false
+  s.prev = excHandler
+  excHandler = s
+
+proc popSafePoint {.compilerRtl, inl.} =
+  excHandler = excHandler.prev
+
+proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
+  e.parent = currException
+  currException = e
+
+proc popCurrentException {.compilerRtl, inl.} =
+  currException = currException.parent
+
+# some platforms have native support for stack traces:
+const
+  nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and
+                              not NimStackTrace
+  hasSomeStackTrace = NimStackTrace or
+    defined(nativeStackTrace) and nativeStackTraceSupported
+
+when defined(nativeStacktrace) and nativeStackTraceSupported:
+  type
+    TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
+               final, pure.} = object
+      dli_fname: cstring
+      dli_fbase: pointer
+      dli_sname: cstring
+      dli_saddr: pointer
+
+  proc backtrace(symbols: ptr pointer, size: int): int {.
+    importc: "backtrace", header: "<execinfo.h>".}
+  proc dladdr(addr1: pointer, info: ptr TDl_info): int {.
+    importc: "dladdr", header: "<dlfcn.h>".}
+
+  when not hasThreadSupport:
+    var
+      tempAddresses: array [0..127, pointer] # should not be alloc'd on stack
+      tempDlInfo: TDl_info
+
+  proc auxWriteStackTraceWithBacktrace(s: var string) =
+    when hasThreadSupport:
+      var
+        tempAddresses: array [0..127, pointer] # but better than a threadvar
+        tempDlInfo: TDl_info
+    # This is allowed to be expensive since it only happens during crashes
+    # (but this way you don't need manual stack tracing)
+    var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
+                         len(tempAddresses))
+    var enabled = false
+    for i in 0..size-1:
+      var dlresult = dladdr(tempAddresses[i], addr(tempDlInfo))
+      if enabled:
+        if dlresult != 0:
+          var oldLen = s.len
+          add(s, tempDlInfo.dli_fname)
+          if tempDlInfo.dli_sname != nil:
+            for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
+            add(s, tempDlInfo.dli_sname)
+        else:
+          add(s, '?')
+        add(s, "\n")
+      else:
+        if dlresult != 0 and tempDlInfo.dli_sname != nil and
+            c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
+          # Once we're past signalHandler, we're at what the user is
+          # interested in
+          enabled = true
+
+when not hasThreadSupport:
+  var
+    tempFrames: array [0..127, PFrame] # should not be alloc'd on stack
+
+proc auxWriteStackTrace(f: PFrame, s: var string) =
+  when hasThreadSupport:
+    var
+      tempFrames: array [0..127, PFrame] # but better than a threadvar
+  const
+    firstCalls = 32
+  var
+    it = f
+    i = 0
+    total = 0
+  # setup long head:
+  while it != nil and i <= high(tempFrames)-firstCalls:
+    tempFrames[i] = it
+    inc(i)
+    inc(total)
+    it = it.prev
+  # go up the stack to count 'total':
+  var b = it
+  while it != nil:
+    inc(total)
+    it = it.prev
+  var skipped = 0
+  if total > len(tempFrames):
+    # skip N
+    skipped = total-i-firstCalls+1
+    for j in 1..skipped:
+      if b != nil: b = b.prev
+    # create '...' entry:
+    tempFrames[i] = nil
+    inc(i)
+  # setup short tail:
+  while b != nil and i <= high(tempFrames):
+    tempFrames[i] = b
+    inc(i)
+    b = b.prev
+  for j in countdown(i-1, 0):
+    if tempFrames[j] == nil:
+      add(s, "(")
+      add(s, $skipped)
+      add(s, " calls omitted) ...")
+    else:
+      var oldLen = s.len
+      add(s, tempFrames[j].filename)
+      if tempFrames[j].line > 0:
+        add(s, '(')
+        add(s, $tempFrames[j].line)
+        add(s, ')')
+      for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
+      add(s, tempFrames[j].procname)
+    add(s, "\n")
+
+proc stackTraceAvailable*(): bool
+
+when hasSomeStackTrace:
+  proc rawWriteStackTrace(s: var string) =
+    when NimStackTrace:
+      if framePtr == nil:
+        add(s, "No stack traceback available\n")
+      else:
+        add(s, "Traceback (most recent call last)\n")
+        auxWriteStackTrace(framePtr, s)
+    elif defined(nativeStackTrace) and nativeStackTraceSupported:
+      add(s, "Traceback from system (most recent call last)\n")
+      auxWriteStackTraceWithBacktrace(s)
+    else:
+      add(s, "No stack traceback available\n")
+  proc stackTraceAvailable(): bool =
+    when NimStackTrace:
+      if framePtr == nil:
+        result = false
+      else:
+        result = true
+    elif defined(nativeStackTrace) and nativeStackTraceSupported:
+      result = true
+    else:
+      result = false
+else:
+  proc stackTraceAvailable*(): bool = result = false
+
+proc quitOrDebug() {.inline.} =
+  when not defined(endb):
+    quit(1)
+  else:
+    endbStep() # call the debugger
+
+proc raiseExceptionAux(e: ref Exception) =
+  if localRaiseHook != nil:
+    if not localRaiseHook(e): return
+  if globalRaiseHook != nil:
+    if not globalRaiseHook(e): return
+  when defined(cpp):
+    if e[] of OutOfMemError:
+      showErrorMessage(e.name)
+      quitOrDebug()
+    else:
+      pushCurrentException(e)
+      {.emit: "throw NimException(`e`, `e`->name);".}
+  else:
+    if excHandler != nil:
+      if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
+        pushCurrentException(e)
+        c_longjmp(excHandler.context, 1)
+    elif e[] of OutOfMemError:
+      showErrorMessage(e.name)
+      quitOrDebug()
+    else:
+      when hasSomeStackTrace:
+        var buf = newStringOfCap(2000)
+        if isNil(e.trace): rawWriteStackTrace(buf)
+        else: add(buf, e.trace)
+        add(buf, "Error: unhandled exception: ")
+        if not isNil(e.msg): add(buf, e.msg)
+        add(buf, " [")
+        add(buf, $e.name)
+        add(buf, "]\n")
+        showErrorMessage(buf)
+      else:
+        # ugly, but avoids heap allocations :-)
+        template xadd(buf, s, slen: expr) =
+          if L + slen < high(buf):
+            copyMem(addr(buf[L]), cstring(s), slen)
+            inc L, slen
+        template add(buf, s: expr) =
+          xadd(buf, s, s.len)
+        var buf: array [0..2000, char]
+        var L = 0
+        add(buf, "Error: unhandled exception: ")
+        if not isNil(e.msg): add(buf, e.msg)
+        add(buf, " [")
+        xadd(buf, e.name, c_strlen(e.name))
+        add(buf, "]\n")
+        showErrorMessage(buf)
+      quitOrDebug()
+
+proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
+  e.name = ename
+  when hasSomeStackTrace:
+    e.trace = ""
+    rawWriteStackTrace(e.trace)
+  raiseExceptionAux(e)
+
+proc reraiseException() {.compilerRtl.} =
+  if currException == nil:
+    sysFatal(ReraiseError, "no exception to reraise")
+  else:
+    raiseExceptionAux(currException)
+
+proc writeStackTrace() =
+  when hasSomeStackTrace:
+    var s = ""
+    rawWriteStackTrace(s)
+    showErrorMessage(s)
+  else:
+    showErrorMessage("No stack traceback available\n")
+
+proc getStackTrace(): string =
+  when hasSomeStackTrace:
+    result = ""
+    rawWriteStackTrace(result)
+  else:
+    result = "No stack traceback available\n"
+
+proc getStackTrace(e: ref Exception): string =
+  if not isNil(e) and not isNil(e.trace):
+    result = e.trace
+  else:
+    result = ""
+
+when defined(nimRequiresNimFrame):
+  proc stackOverflow() {.noinline.} =
+    writeStackTrace()
+    showErrorMessage("Stack overflow\n")
+    quitOrDebug()
+
+  proc nimFrame(s: PFrame) {.compilerRtl, inl, exportc: "nimFrame".} =
+    s.calldepth = if framePtr == nil: 0 else: framePtr.calldepth+1
+    s.prev = framePtr
+    framePtr = s
+    if s.calldepth == 2000: stackOverflow()
+else:
+  proc pushFrame(s: PFrame) {.compilerRtl, inl, exportc: "nimFrame".} =
+    # XXX only for backwards compatibility
+    s.prev = framePtr
+    framePtr = s
+
+when defined(endb):
+  var
+    dbgAborting: bool # whether the debugger wants to abort
+
+when not defined(noSignalHandler):
+  proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
+    template processSignal(s, action: expr) {.immediate,  dirty.} =
+      if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
+      elif s == SIGSEGV:
+        action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
+      elif s == SIGABRT:
+        when defined(endb):
+          if dbgAborting: return # the debugger wants to abort
+        action("SIGABRT: Abnormal termination.\n")
+      elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n")
+      elif s == SIGILL: action("SIGILL: Illegal operation.\n")
+      elif s == SIGBUS:
+        action("SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
+      else:
+        block platformSpecificSignal:
+          when declared(SIGPIPE):
+            if s == SIGPIPE:
+              action("SIGPIPE: Pipe closed.\n")
+              break platformSpecificSignal
+          action("unknown signal\n")
+
+    # print stack trace and quit
+    when hasSomeStackTrace:
+      GC_disable()
+      var buf = newStringOfCap(2000)
+      rawWriteStackTrace(buf)
+      processSignal(sig, buf.add) # nice hu? currying a la Nim :-)
+      showErrorMessage(buf)
+      GC_enable()
+    else:
+      var msg: cstring
+      template asgn(y: expr) = msg = y
+      processSignal(sig, asgn)
+      showErrorMessage(msg)
+    when defined(endb): dbgAborting = true
+    quit(1) # always quit when SIGABRT
+
+  proc registerSignalHandler() =
+    c_signal(SIGINT, signalHandler)
+    c_signal(SIGSEGV, signalHandler)
+    c_signal(SIGABRT, signalHandler)
+    c_signal(SIGFPE, signalHandler)
+    c_signal(SIGILL, signalHandler)
+    c_signal(SIGBUS, signalHandler)
+    when declared(SIGPIPE):
+      c_signal(SIGPIPE, signalHandler)
+
+  registerSignalHandler() # call it in initialization section
+
+proc setControlCHook(hook: proc () {.noconv.} not nil) =
+  # ugly cast, but should work on all architectures:
+  type TSignalHandler = proc (sig: cint) {.noconv, benign.}
+  c_signal(SIGINT, cast[TSignalHandler](hook))
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
new file mode 100644
index 000000000..e0d1006d9
--- /dev/null
+++ b/lib/system/gc.nim
@@ -0,0 +1,1142 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#            Garbage Collector
+#
+# The basic algorithm is *Deferred Reference Counting* with cycle detection.
+# This is achieved by combining a Deutsch-Bobrow garbage collector
+# together with Christoper's partial mark-sweep garbage collector.
+#
+# Special care has been taken to avoid recursion as far as possible to avoid
+# stack overflows when traversing deep datastructures. It is well-suited
+# for soft real time applications (like games).
+{.push profiler:off.}
+
+const
+  CycleIncrease = 2 # is a multiplicative increase
+  InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
+  ZctThreshold = 500  # we collect garbage if the ZCT's size
+                      # reaches this threshold
+                      # this seems to be a good value
+  withRealTime = defined(useRealtimeGC)
+  useMarkForDebug = defined(gcGenerational)
+  useBackupGc = false                     # use a simple M&S GC to collect
+                                          # cycles instead of the complex
+                                          # algorithm
+
+when withRealTime and not declared(getTicks):
+  include "system/timers"
+when defined(memProfiler):
+  proc nimProfile(requestedSize: int) {.benign.}
+
+const
+  rcIncrement = 0b1000 # so that lowest 3 bits are not touched
+  rcBlack = 0b000  # cell is colored black; in use or free
+  rcGray = 0b001   # possible member of a cycle
+  rcWhite = 0b010  # member of a garbage cycle
+  rcPurple = 0b011 # possible root of a cycle
+  ZctFlag = 0b100  # in ZCT
+  rcShift = 3      # shift by rcShift to get the reference counter
+  colorMask = 0b011
+type
+  TWalkOp = enum
+    waMarkGlobal,    # part of the backup/debug mark&sweep
+    waMarkPrecise,   # part of the backup/debug mark&sweep
+    waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack,
+    waCollectWhite #, waDebug
+
+  TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
+    # A ref type can have a finalizer that is called before the object's
+    # storage is freed.
+
+  TGcStat {.final, pure.} = object
+    stackScans: int          # number of performed stack scans (for statistics)
+    cycleCollections: int    # number of performed full collections
+    maxThreshold: int        # max threshold that has been set
+    maxStackSize: int        # max stack size
+    maxStackCells: int       # max stack cells in ``decStack``
+    cycleTableSize: int      # max entries in cycle table
+    maxPause: int64          # max measured GC pause in nanoseconds
+
+  TGcHeap {.final, pure.} = object # this contains the zero count and
+                                   # non-zero count table
+    stackBottom: pointer
+    cycleThreshold: int
+    when useCellIds:
+      idGenerator: int
+    zct: TCellSeq            # the zero count table
+    decStack: TCellSeq       # cells in the stack that are to decref again
+    cycleRoots: TCellSet
+    tempStack: TCellSeq      # temporary stack for recursion elimination
+    recGcLock: int           # prevent recursion via finalizers; no thread lock
+    when withRealTime:
+      maxPause: TNanos       # max allowed pause in nanoseconds; active if > 0
+    region: TMemRegion       # garbage collected region
+    stat: TGcStat
+    when useMarkForDebug or useBackupGc:
+      marked: TCellSet
+
+var
+  gch {.rtlThreadVar.}: TGcHeap
+
+when not defined(useNimRtl):
+  instantiateForRegion(gch.region)
+
+template acquire(gch: TGcHeap) =
+  when hasThreadSupport and hasSharedHeap:
+    acquireSys(HeapLock)
+
+template release(gch: TGcHeap) =
+  when hasThreadSupport and hasSharedHeap:
+    releaseSys(HeapLock)
+
+template gcAssert(cond: bool, msg: string) =
+  when defined(useGcAssert):
+    if not cond:
+      echo "[GCASSERT] ", msg
+      GC_disable()
+      writeStackTrace()
+      quit 1
+
+proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
+  if (c.refcount and ZctFlag) == 0:
+    c.refcount = c.refcount or ZctFlag
+    add(s, c)
+
+proc cellToUsr(cell: PCell): pointer {.inline.} =
+  # convert object (=pointer to refcount) to pointer to userdata
+  result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
+
+proc usrToCell(usr: pointer): PCell {.inline.} =
+  # convert pointer to userdata to object (=pointer to refcount)
+  result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
+
+proc canBeCycleRoot(c: PCell): bool {.inline.} =
+  result = ntfAcyclic notin c.typ.flags
+
+proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
+  # used for code generation concerning debugging
+  result = usrToCell(c).typ
+
+proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
+  result = int(usrToCell(p).refcount) shr rcShift
+
+# this that has to equals zero, otherwise we have to round up UnitsPerPage:
+when BitsPerPage mod (sizeof(int)*8) != 0:
+  {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
+
+template color(c): expr = c.refCount and colorMask
+template setColor(c, col) =
+  when col == rcBlack:
+    c.refcount = c.refcount and not colorMask
+  else:
+    c.refcount = c.refcount and not colorMask or col
+
+proc writeCell(msg: cstring, c: PCell) =
+  var kind = -1
+  if c.typ != nil: kind = ord(c.typ.kind)
+  when leakDetector:
+    c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld from %s(%ld)\n",
+              msg, c, kind, c.refcount shr rcShift, c.filename, c.line)
+  else:
+    c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld; color=%ld\n",
+              msg, c, kind, c.refcount shr rcShift, c.color)
+
+template gcTrace(cell, state: expr): stmt {.immediate.} =
+  when traceGC: traceCell(cell, state)
+
+# forward declarations:
+proc collectCT(gch: var TGcHeap) {.benign.}
+proc isOnStack*(p: pointer): bool {.noinline, benign.}
+proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
+proc doOperation(p: pointer, op: TWalkOp) {.benign.}
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
+# we need the prototype here for debugging purposes
+
+when hasThreadSupport and hasSharedHeap:
+  template `--`(x: expr): expr = atomicDec(x, rcIncrement) <% rcIncrement
+  template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
+else:
+  template `--`(x: expr): expr =
+    dec(x, rcIncrement)
+    x <% rcIncrement
+  template `++`(x: expr): stmt = inc(x, rcIncrement)
+
+proc prepareDealloc(cell: PCell) =
+  when useMarkForDebug:
+    gcAssert(cell notin gch.marked, "Cell still alive!")
+  if cell.typ.finalizer != nil:
+    # the finalizer could invoke something that
+    # allocates memory; this could trigger a garbage
+    # collection. Since we are already collecting we
+    # prevend recursive entering here by a lock.
+    # XXX: we should set the cell's children to nil!
+    inc(gch.recGcLock)
+    (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
+    dec(gch.recGcLock)
+
+proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
+  # we MUST access gch as a global here, because this crosses DLL boundaries!
+  when hasThreadSupport and hasSharedHeap:
+    acquireSys(HeapLock)
+  when cycleGC:
+    if c.color != rcPurple:
+      c.setColor(rcPurple)
+      incl(gch.cycleRoots, c)
+  when hasThreadSupport and hasSharedHeap:
+    releaseSys(HeapLock)
+
+proc rtlAddZCT(c: PCell) {.rtl, inl.} =
+  # we MUST access gch as a global here, because this crosses DLL boundaries!
+  when hasThreadSupport and hasSharedHeap:
+    acquireSys(HeapLock)
+  addZCT(gch.zct, c)
+  when hasThreadSupport and hasSharedHeap:
+    releaseSys(HeapLock)
+
+proc decRef(c: PCell) {.inline.} =
+  gcAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr")
+  gcAssert(c.refcount >=% rcIncrement, "decRef")
+  if --c.refcount:
+    rtlAddZCT(c)
+  elif canbeCycleRoot(c):
+    # unfortunately this is necessary here too, because a cycle might just
+    # have been broken up and we could recycle it.
+    rtlAddCycleRoot(c)
+    #writeCell("decRef", c)
+
+proc incRef(c: PCell) {.inline.} =
+  gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
+  c.refcount = c.refcount +% rcIncrement
+  # and not colorMask
+  #writeCell("incRef", c)
+  if canbeCycleRoot(c):
+    rtlAddCycleRoot(c)
+
+proc nimGCref(p: pointer) {.compilerProc, inline.} = incRef(usrToCell(p))
+proc nimGCunref(p: pointer) {.compilerProc, inline.} = decRef(usrToCell(p))
+
+proc GC_addCycleRoot*[T](p: ref T) {.inline.} =
+  ## adds 'p' to the cycle candidate set for the cycle collector. It is
+  ## necessary if you used the 'acyclic' pragma for optimization
+  ## purposes and need to break cycles manually.
+  rtlAddCycleRoot(usrToCell(cast[pointer](p)))
+
+proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
+  sysAssert(allocInv(gch.region), "begin nimGCunrefNoCycle")
+  var c = usrToCell(p)
+  gcAssert(isAllocatedPtr(gch.region, c), "nimGCunrefNoCycle: isAllocatedPtr")
+  if --c.refcount:
+    rtlAddZCT(c)
+    sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
+  sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
+
+proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+  # the code generator calls this proc!
+  gcAssert(not isOnStack(dest), "asgnRef")
+  # BUGFIX: first incRef then decRef!
+  if src != nil: incRef(usrToCell(src))
+  if dest[] != nil: decRef(usrToCell(dest[]))
+  dest[] = src
+
+proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+  # the code generator calls this proc if it is known at compile time that no
+  # cycle is possible.
+  if src != nil:
+    var c = usrToCell(src)
+    ++c.refcount
+  if dest[] != nil:
+    var c = usrToCell(dest[])
+    if --c.refcount:
+      rtlAddZCT(c)
+  dest[] = src
+
+proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
+  # unsureAsgnRef updates the reference counters only if dest is not on the
+  # stack. It is used by the code generator if it cannot decide wether a
+  # reference is in the stack or not (this can happen for var parameters).
+  if not isOnStack(dest):
+    if src != nil: incRef(usrToCell(src))
+    # XXX finally use assembler for the stack checking instead!
+    # the test for '!= nil' is correct, but I got tired of the segfaults
+    # resulting from the crappy stack checking:
+    if cast[int](dest[]) >=% PageSize: decRef(usrToCell(dest[]))
+  else:
+    # can't be an interior pointer if it's a stack location!
+    gcAssert(interiorAllocatedPtr(gch.region, dest) == nil,
+             "stack loc AND interior pointer")
+  dest[] = src
+
+proc initGC() =
+  when not defined(useNimRtl):
+    when traceGC:
+      for i in low(TCellState)..high(TCellState): init(states[i])
+    gch.cycleThreshold = InitialCycleThreshold
+    gch.stat.stackScans = 0
+    gch.stat.cycleCollections = 0
+    gch.stat.maxThreshold = 0
+    gch.stat.maxStackSize = 0
+    gch.stat.maxStackCells = 0
+    gch.stat.cycleTableSize = 0
+    # init the rt
+    init(gch.zct)
+    init(gch.tempStack)
+    init(gch.cycleRoots)
+    init(gch.decStack)
+    when useMarkForDebug or useBackupGc:
+      init(gch.marked)
+
+var
+  localGcInitialized {.rtlThreadVar.}: bool
+
+proc setupForeignThreadGc*() =
+  ## call this if you registered a callback that will be run from a thread not
+  ## under your control. This has a cheap thread-local guard, so the GC for
+  ## this thread will only be initialized once per thread, no matter how often
+  ## it is called.
+  if not localGcInitialized:
+    localGcInitialized = true
+    var stackTop {.volatile.}: pointer
+    setStackBottom(addr(stackTop))
+    initGC()
+
+when useMarkForDebug or useBackupGc:
+  type
+    TGlobalMarkerProc = proc () {.nimcall, benign.}
+  var
+    globalMarkersLen: int
+    globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
+
+  proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
+    if globalMarkersLen <= high(globalMarkers):
+      globalMarkers[globalMarkersLen] = markerProc
+      inc globalMarkersLen
+    else:
+      echo "[GC] cannot register global variable; too many global variables"
+      quit 1
+
+proc cellsetReset(s: var TCellSet) =
+  deinit(s)
+  init(s)
+
+proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
+  var d = cast[ByteAddress](dest)
+  case n.kind
+  of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
+  of nkList:
+    for i in 0..n.len-1:
+      # inlined for speed
+      if n.sons[i].kind == nkSlot:
+        if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
+          doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
+        else:
+          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
+                            n.sons[i].typ, op)
+      else:
+        forAllSlotsAux(dest, n.sons[i], op)
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: forAllSlotsAux(dest, m, op)
+  of nkNone: sysAssert(false, "forAllSlotsAux")
+
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
+  var d = cast[ByteAddress](dest)
+  if dest == nil: return # nothing to do
+  if ntfNoRefs notin mt.flags:
+    case mt.kind
+    of tyRef, tyString, tySequence: # leaf:
+      doOperation(cast[PPointer](d)[], op)
+    of tyObject, tyTuple:
+      forAllSlotsAux(dest, mt.node, op)
+    of tyArray, tyArrayConstr, tyOpenArray:
+      for i in 0..(mt.size div mt.base.size)-1:
+        forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
+    else: discard
+
+proc forAllChildren(cell: PCell, op: TWalkOp) =
+  gcAssert(cell != nil, "forAllChildren: 1")
+  gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
+  gcAssert(cell.typ != nil, "forAllChildren: 3")
+  gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
+  let marker = cell.typ.marker
+  if marker != nil:
+    marker(cellToUsr(cell), op.int)
+  else:
+    case cell.typ.kind
+    of tyRef: # common case
+      forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
+    of tySequence:
+      var d = cast[ByteAddress](cellToUsr(cell))
+      var s = cast[PGenericSeq](d)
+      if s != nil:
+        for i in 0..s.len-1:
+          forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
+            GenericSeqSize), cell.typ.base, op)
+    else: discard
+
+proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
+  # we check the last 8 entries (cache line) for a slot that could be reused.
+  # In 63% of all cases we succeed here! But we have to optimize the heck
+  # out of this small linear search so that ``newObj`` is not slowed down.
+  #
+  # Slots to try          cache hit
+  # 1                     32%
+  # 4                     59%
+  # 8                     63%
+  # 16                    66%
+  # all slots             68%
+  var L = gch.zct.len
+  var d = gch.zct.d
+  when true:
+    # loop unrolled for performance:
+    template replaceZctEntry(i: expr) =
+      c = d[i]
+      if c.refcount >=% rcIncrement:
+        c.refcount = c.refcount and not ZctFlag
+        d[i] = res
+        return
+    if L > 8:
+      var c: PCell
+      replaceZctEntry(L-1)
+      replaceZctEntry(L-2)
+      replaceZctEntry(L-3)
+      replaceZctEntry(L-4)
+      replaceZctEntry(L-5)
+      replaceZctEntry(L-6)
+      replaceZctEntry(L-7)
+      replaceZctEntry(L-8)
+      add(gch.zct, res)
+    else:
+      d[L] = res
+      inc(gch.zct.len)
+  else:
+    for i in countdown(L-1, max(0, L-8)):
+      var c = d[i]
+      if c.refcount >=% rcIncrement:
+        c.refcount = c.refcount and not ZctFlag
+        d[i] = res
+        return
+    add(gch.zct, res)
+
+{.push stackTrace: off, profiler:off.}
+proc gcInvariant*() =
+  sysAssert(allocInv(gch.region), "injected")
+  when declared(markForDebug):
+    markForDebug(gch)
+{.pop.}
+
+proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
+  # generates a new object and sets its reference counter to 0
+  sysAssert(allocInv(gch.region), "rawNewObj begin")
+  acquire(gch)
+  gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
+  collectCT(gch)
+  var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
+  gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
+  # now it is buffered in the ZCT
+  res.typ = typ
+  when leakDetector and not hasThreadSupport:
+    if framePtr != nil and framePtr.prev != nil:
+      res.filename = framePtr.prev.filename
+      res.line = framePtr.prev.line
+  # refcount is zero, color is black, but mark it to be in the ZCT
+  res.refcount = ZctFlag
+  sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
+  # its refcount is zero, so add it to the ZCT:
+  addNewObjToZCT(res, gch)
+  when logGC: writeCell("new cell", res)
+  gcTrace(res, csAllocated)
+  release(gch)
+  when useCellIds:
+    inc gch.idGenerator
+    res.id = gch.idGenerator
+  result = cellToUsr(res)
+  sysAssert(allocInv(gch.region), "rawNewObj end")
+
+{.pop.}
+
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  when defined(memProfiler): nimProfile(size)
+
+proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  # `newObj` already uses locks, so no need for them here.
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObj(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  # generates a new object and sets its reference counter to 1
+  sysAssert(allocInv(gch.region), "newObjRC1 begin")
+  acquire(gch)
+  gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
+  collectCT(gch)
+  sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
+
+  var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
+  sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc")
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
+  # now it is buffered in the ZCT
+  res.typ = typ
+  when leakDetector and not hasThreadSupport:
+    if framePtr != nil and framePtr.prev != nil:
+      res.filename = framePtr.prev.filename
+      res.line = framePtr.prev.line
+  res.refcount = rcIncrement # refcount is 1
+  sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
+  when logGC: writeCell("new cell", res)
+  gcTrace(res, csAllocated)
+  release(gch)
+  when useCellIds:
+    inc gch.idGenerator
+    res.id = gch.idGenerator
+  result = cellToUsr(res)
+  zeroMem(result, size)
+  sysAssert(allocInv(gch.region), "newObjRC1 end")
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObjRC1(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+  when defined(memProfiler): nimProfile(size)
+
+proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
+  acquire(gch)
+  collectCT(gch)
+  var ol = usrToCell(old)
+  sysAssert(ol.typ != nil, "growObj: 1")
+  gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
+  sysAssert(allocInv(gch.region), "growObj begin")
+
+  var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
+  var elemSize = 1
+  if ol.typ.kind != tyString: elemSize = ol.typ.base.size
+
+  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+  copyMem(res, ol, oldsize + sizeof(TCell))
+  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
+          newsize-oldsize)
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
+  # This can be wrong for intermediate temps that are nevertheless on the
+  # heap because of lambda lifting:
+  #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
+  when logGC:
+    writeCell("growObj old cell", ol)
+    writeCell("growObj new cell", res)
+  gcTrace(ol, csZctFreed)
+  gcTrace(res, csAllocated)
+  when reallyDealloc:
+    sysAssert(allocInv(gch.region), "growObj before dealloc")
+    if ol.refcount shr rcShift <=% 1:
+      # free immediately to save space:
+      if (ol.refcount and ZctFlag) != 0:
+        var j = gch.zct.len-1
+        var d = gch.zct.d
+        while j >= 0:
+          if d[j] == ol:
+            d[j] = res
+            break
+          dec(j)
+      if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
+      rawDealloc(gch.region, ol)
+    else:
+      # we split the old refcount in 2 parts. XXX This is still not entirely
+      # correct if the pointer that receives growObj's result is on the stack.
+      # A better fix would be to emit the location specific write barrier for
+      # 'growObj', but this is lost of more work and who knows what new problems
+      # this would create.
+      res.refcount = rcIncrement
+      decRef(ol)
+  else:
+    sysAssert(ol.typ != nil, "growObj: 5")
+    zeroMem(ol, sizeof(TCell))
+  release(gch)
+  when useCellIds:
+    inc gch.idGenerator
+    res.id = gch.idGenerator
+  result = cellToUsr(res)
+  sysAssert(allocInv(gch.region), "growObj end")
+  when defined(memProfiler): nimProfile(newsize-oldsize)
+
+proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
+  result = growObj(old, newsize, gch)
+
+{.push profiler:off.}
+
+# ---------------- cycle collector -------------------------------------------
+
+proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
+  prepareDealloc(c)
+  gcTrace(c, csCycFreed)
+  when logGC: writeCell("cycle collector dealloc cell", c)
+  when reallyDealloc:
+    sysAssert(allocInv(gch.region), "free cyclic cell")
+    rawDealloc(gch.region, c)
+  else:
+    gcAssert(c.typ != nil, "freeCyclicCell")
+    zeroMem(c, sizeof(TCell))
+
+proc markGray(s: PCell) =
+  if s.color != rcGray:
+    setColor(s, rcGray)
+    forAllChildren(s, waMarkGray)
+
+proc scanBlack(s: PCell) =
+  s.setColor(rcBlack)
+  forAllChildren(s, waScanBlack)
+
+proc scan(s: PCell) =
+  if s.color == rcGray:
+    if s.refcount >=% rcIncrement:
+      scanBlack(s)
+    else:
+      s.setColor(rcWhite)
+      forAllChildren(s, waScan)
+
+proc collectWhite(s: PCell) =
+  # This is a hacky way to deal with the following problem (bug #1796)
+  # Consider this content in cycleRoots:
+  #   x -> a; y -> a  where 'a' is an acyclic object so not included in
+  # cycleRoots itself. Then 'collectWhite' used to free 'a' twice. The
+  # 'isAllocatedPtr' check prevents this. This also means we do not need
+  # to query 's notin gch.cycleRoots' at all.
+  if isAllocatedPtr(gch.region, s) and s.color == rcWhite:
+    s.setColor(rcBlack)
+    forAllChildren(s, waCollectWhite)
+    freeCyclicCell(gch, s)
+
+proc markRoots(gch: var TGcHeap) =
+  var tabSize = 0
+  for s in elements(gch.cycleRoots):
+    #writeCell("markRoot", s)
+    inc tabSize
+    if s.color == rcPurple and s.refcount >=% rcIncrement:
+      markGray(s)
+    else:
+      excl(gch.cycleRoots, s)
+      # (s.color == rcBlack and rc == 0) as 1 condition:
+      if s.refcount == 0:
+        freeCyclicCell(gch, s)
+  gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
+
+when useBackupGc:
+  proc sweep(gch: var TGcHeap) =
+    for x in allObjects(gch.region):
+      if isCell(x):
+        # cast to PCell is correct here:
+        var c = cast[PCell](x)
+        if c notin gch.marked: freeCyclicCell(gch, c)
+
+when useMarkForDebug or useBackupGc:
+  proc markS(gch: var TGcHeap, c: PCell) =
+    incl(gch.marked, c)
+    gcAssert gch.tempStack.len == 0, "stack not empty!"
+    forAllChildren(c, waMarkPrecise)
+    while gch.tempStack.len > 0:
+      dec gch.tempStack.len
+      var d = gch.tempStack.d[gch.tempStack.len]
+      if not containsOrIncl(gch.marked, d):
+        forAllChildren(d, waMarkPrecise)
+
+  proc markGlobals(gch: var TGcHeap) =
+    for i in 0 .. < globalMarkersLen: globalMarkers[i]()
+
+  proc stackMarkS(gch: var TGcHeap, p: pointer) {.inline.} =
+    # the addresses are not as cells on the stack, so turn them to cells:
+    var cell = usrToCell(p)
+    var c = cast[TAddress](cell)
+    if c >% PageSize:
+      # fast check: does it look like a cell?
+      var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
+      if objStart != nil:
+        markS(gch, objStart)
+
+when logGC:
+  var
+    cycleCheckA: array[100, PCell]
+    cycleCheckALen = 0
+
+  proc alreadySeen(c: PCell): bool =
+    for i in 0 .. <cycleCheckALen:
+      if cycleCheckA[i] == c: return true
+    if cycleCheckALen == len(cycleCheckA):
+      gcAssert(false, "cycle detection overflow")
+      quit 1
+    cycleCheckA[cycleCheckALen] = c
+    inc cycleCheckALen
+
+  proc debugGraph(s: PCell) =
+    if alreadySeen(s):
+      writeCell("child cell (already seen) ", s)
+    else:
+      writeCell("cell {", s)
+      forAllChildren(s, waDebug)
+      c_fprintf(c_stdout, "}\n")
+
+proc doOperation(p: pointer, op: TWalkOp) =
+  if p == nil: return
+  var c: PCell = usrToCell(p)
+  gcAssert(c != nil, "doOperation: 1")
+  # the 'case' should be faster than function pointers because of easy
+  # prediction:
+  case op
+  of waZctDecRef:
+    #if not isAllocatedPtr(gch.region, c):
+    #  c_fprintf(c_stdout, "[GC] decref bug: %p", c)
+    gcAssert(isAllocatedPtr(gch.region, c), "decRef: waZctDecRef")
+    gcAssert(c.refcount >=% rcIncrement, "doOperation 2")
+    #c.refcount = c.refcount -% rcIncrement
+    when logGC: writeCell("decref (from doOperation)", c)
+    decRef(c)
+    #if c.refcount <% rcIncrement: addZCT(gch.zct, c)
+  of waPush:
+    add(gch.tempStack, c)
+  of waCycleDecRef:
+    gcAssert(c.refcount >=% rcIncrement, "doOperation 3")
+    c.refcount = c.refcount -% rcIncrement
+  of waMarkGray:
+    gcAssert(c.refcount >=% rcIncrement, "waMarkGray")
+    c.refcount = c.refcount -% rcIncrement
+    markGray(c)
+  of waScan: scan(c)
+  of waScanBlack:
+    c.refcount = c.refcount +% rcIncrement
+    if c.color != rcBlack:
+      scanBlack(c)
+  of waCollectWhite: collectWhite(c)
+  of waMarkGlobal:
+    when useMarkForDebug or useBackupGc:
+      when hasThreadSupport:
+        # could point to a cell which we don't own and don't want to touch/trace
+        if isAllocatedPtr(gch.region, c):
+          markS(gch, c)
+      else:
+        markS(gch, c)
+  of waMarkPrecise:
+    when useMarkForDebug or useBackupGc:
+      add(gch.tempStack, c)
+  #of waDebug: debugGraph(c)
+
+proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
+  doOperation(d, TWalkOp(op))
+
+proc collectZCT(gch: var TGcHeap): bool {.benign.}
+
+when useMarkForDebug or useBackupGc:
+  proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl,
+                                                         benign.}
+
+proc collectRoots(gch: var TGcHeap) =
+  for s in elements(gch.cycleRoots):
+    collectWhite(s)
+
+proc collectCycles(gch: var TGcHeap) =
+  # ensure the ZCT 'color' is not used:
+  while gch.zct.len > 0: discard collectZCT(gch)
+  when useBackupGc:
+    cellsetReset(gch.marked)
+    markStackAndRegistersForSweep(gch)
+    markGlobals(gch)
+    sweep(gch)
+  else:
+    markRoots(gch)
+    # scanRoots:
+    for s in elements(gch.cycleRoots): scan(s)
+    collectRoots(gch)
+
+    cellsetReset(gch.cycleRoots)
+  # alive cycles need to be kept in 'cycleRoots' if they are referenced
+  # from the stack; otherwise the write barrier will add the cycle root again
+  # anyway:
+  when false:
+    var d = gch.decStack.d
+    var cycleRootsLen = 0
+    for i in 0..gch.decStack.len-1:
+      var c = d[i]
+      gcAssert isAllocatedPtr(gch.region, c), "addBackStackRoots"
+      gcAssert c.refcount >=% rcIncrement, "addBackStackRoots: dead cell"
+      if canBeCycleRoot(c):
+        #if c notin gch.cycleRoots:
+        inc cycleRootsLen
+        incl(gch.cycleRoots, c)
+      gcAssert c.typ != nil, "addBackStackRoots 2"
+    if cycleRootsLen != 0:
+      cfprintf(cstdout, "cycle roots: %ld\n", cycleRootsLen)
+
+proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
+  # the addresses are not as cells on the stack, so turn them to cells:
+  sysAssert(allocInv(gch.region), "gcMark begin")
+  var cell = usrToCell(p)
+  var c = cast[ByteAddress](cell)
+  if c >% PageSize:
+    # fast check: does it look like a cell?
+    var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
+    if objStart != nil:
+      # mark the cell:
+      objStart.refcount = objStart.refcount +% rcIncrement
+      add(gch.decStack, objStart)
+    when false:
+      if isAllocatedPtr(gch.region, cell):
+        sysAssert false, "allocated pointer but not interior?"
+        # mark the cell:
+        cell.refcount = cell.refcount +% rcIncrement
+        add(gch.decStack, cell)
+  sysAssert(allocInv(gch.region), "gcMark end")
+
+proc markThreadStacks(gch: var TGcHeap) =
+  when hasThreadSupport and hasSharedHeap:
+    {.error: "not fully implemented".}
+    var it = threadList
+    while it != nil:
+      # mark registers:
+      for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
+      var sp = cast[TAddress](it.stackBottom)
+      var max = cast[TAddress](it.stackTop)
+      # XXX stack direction?
+      # XXX unroll this loop:
+      while sp <=% max:
+        gcMark(gch, cast[ppointer](sp)[])
+        sp = sp +% sizeof(pointer)
+      it = it.next
+
+# ----------------- stack management --------------------------------------
+#  inspired from Smart Eiffel
+
+when defined(sparc):
+  const stackIncreases = false
+elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
+     defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
+  const stackIncreases = true
+else:
+  const stackIncreases = false
+
+when not defined(useNimRtl):
+  {.push stack_trace: off.}
+  proc setStackBottom(theStackBottom: pointer) =
+    #c_fprintf(c_stdout, "stack bottom: %p;\n", theStackBottom)
+    # the first init must be the one that defines the stack bottom:
+    if gch.stackBottom == nil: gch.stackBottom = theStackBottom
+    else:
+      var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
+      var b = cast[ByteAddress](gch.stackBottom)
+      #c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
+      when stackIncreases:
+        gch.stackBottom = cast[pointer](min(a, b))
+      else:
+        gch.stackBottom = cast[pointer](max(a, b))
+  {.pop.}
+
+proc stackSize(): int {.noinline.} =
+  var stackTop {.volatile.}: pointer
+  result = abs(cast[int](addr(stackTop)) - cast[int](gch.stackBottom))
+
+when defined(sparc): # For SPARC architecture.
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var b = cast[TAddress](gch.stackBottom)
+    var a = cast[TAddress](stackTop)
+    var x = cast[TAddress](p)
+    result = a <=% x and x <=% b
+
+  template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
+    when defined(sparcv9):
+      asm  """"flushw \n" """
+    else:
+      asm  """"ta      0x3   ! ST_FLUSH_WINDOWS\n" """
+
+    var
+      max = gch.stackBottom
+      sp: PPointer
+      stackTop: array[0..1, pointer]
+    sp = addr(stackTop[0])
+    # Addresses decrease as the stack grows.
+    while sp <= max:
+      gcMark(gch, sp[])
+      sp = cast[PPointer](cast[TAddress](sp) +% sizeof(pointer))
+
+elif defined(ELATE):
+  {.error: "stack marking code is to be written for this architecture".}
+
+elif stackIncreases:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses increase as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var a = cast[TAddress](gch.stackBottom)
+    var b = cast[TAddress](stackTop)
+    var x = cast[TAddress](p)
+    result = a <=% x and x <=% b
+
+  var
+    jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
+      # a little hack to get the size of a TJmpBuf in the generated C code
+      # in a platform independent way
+
+  template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
+    var registers: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[TAddress](gch.stackBottom)
+      var sp = cast[TAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
+      # sp will traverse the JMP_BUF as well (jmp_buf size is added,
+      # otherwise sp would be below the registers structure).
+      while sp >=% max:
+        gcMark(gch, cast[ppointer](sp)[])
+        sp = sp -% sizeof(pointer)
+
+else:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses decrease as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+
+  template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} =
+    # We use a jmp_buf buffer that is in the C stack.
+    # Used to traverse the stack and registers assuming
+    # that 'setjmp' will save registers in the C stack.
+    type PStackSlice = ptr array [0..7, pointer]
+    var registers {.noinit.}: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[ByteAddress](gch.stackBottom)
+      var sp = cast[ByteAddress](addr(registers))
+      when defined(amd64):
+        # words within the jmp_buf structure may not be properly aligned.
+        let regEnd = sp +% sizeof(registers)
+        while sp <% regEnd:
+          gcMark(gch, cast[PPointer](sp)[])
+          gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[])
+          sp = sp +% sizeof(pointer)
+      # Make sure sp is word-aligned
+      sp = sp and not (sizeof(pointer) - 1)
+      # loop unrolled:
+      while sp <% max - 8*sizeof(pointer):
+        gcMark(gch, cast[PStackSlice](sp)[0])
+        gcMark(gch, cast[PStackSlice](sp)[1])
+        gcMark(gch, cast[PStackSlice](sp)[2])
+        gcMark(gch, cast[PStackSlice](sp)[3])
+        gcMark(gch, cast[PStackSlice](sp)[4])
+        gcMark(gch, cast[PStackSlice](sp)[5])
+        gcMark(gch, cast[PStackSlice](sp)[6])
+        gcMark(gch, cast[PStackSlice](sp)[7])
+        sp = sp +% sizeof(pointer)*8
+      # last few entries:
+      while sp <=% max:
+        gcMark(gch, cast[PPointer](sp)[])
+        sp = sp +% sizeof(pointer)
+
+proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+  forEachStackSlot(gch, gcMark)
+
+when useMarkForDebug or useBackupGc:
+  proc markStackAndRegistersForSweep(gch: var TGcHeap) =
+    forEachStackSlot(gch, stackMarkS)
+
+# ----------------------------------------------------------------------------
+# end of non-portable code
+# ----------------------------------------------------------------------------
+
+proc collectZCT(gch: var TGcHeap): bool =
+  # Note: Freeing may add child objects to the ZCT! So essentially we do
+  # deep freeing, which is bad for incremental operation. In order to
+  # avoid a deep stack, we move objects to keep the ZCT small.
+  # This is performance critical!
+  const workPackage = 100
+  var L = addr(gch.zct.len)
+
+  when withRealTime:
+    var steps = workPackage
+    var t0: TTicks
+    if gch.maxPause > 0: t0 = getticks()
+  while L[] > 0:
+    var c = gch.zct.d[0]
+    sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr")
+    # remove from ZCT:
+    gcAssert((c.refcount and ZctFlag) == ZctFlag, "collectZCT")
+
+    c.refcount = c.refcount and not ZctFlag
+    gch.zct.d[0] = gch.zct.d[L[] - 1]
+    dec(L[])
+    when withRealTime: dec steps
+    if c.refcount <% rcIncrement:
+      # It may have a RC > 0, if it is in the hardware stack or
+      # it has not been removed yet from the ZCT. This is because
+      # ``incref`` does not bother to remove the cell from the ZCT
+      # as this might be too slow.
+      # In any case, it should be removed from the ZCT. But not
+      # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
+      when cycleGC:
+        if canbeCycleRoot(c): excl(gch.cycleRoots, c)
+      when logGC: writeCell("zct dealloc cell", c)
+      gcTrace(c, csZctFreed)
+      # We are about to free the object, call the finalizer BEFORE its
+      # children are deleted as well, because otherwise the finalizer may
+      # access invalid memory. This is done by prepareDealloc():
+      prepareDealloc(c)
+      forAllChildren(c, waZctDecRef)
+      when reallyDealloc:
+        sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
+        rawDealloc(gch.region, c)
+      else:
+        sysAssert(c.typ != nil, "collectZCT 2")
+        zeroMem(c, sizeof(TCell))
+    when withRealTime:
+      if steps == 0:
+        steps = workPackage
+        if gch.maxPause > 0:
+          let duration = getticks() - t0
+          # the GC's measuring is not accurate and needs some cleanup actions
+          # (stack unmarking), so subtract some short amount of time in
+          # order to miss deadlines less often:
+          if duration >= gch.maxPause - 50_000:
+            return false
+  result = true
+
+proc unmarkStackAndRegisters(gch: var TGcHeap) =
+  var d = gch.decStack.d
+  for i in 0..gch.decStack.len-1:
+    sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
+    decRef(d[i])
+    #var c = d[i]
+    # XXX no need for an atomic dec here:
+    #if --c.refcount:
+    #  addZCT(gch.zct, c)
+    #sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
+  gch.decStack.len = 0
+
+proc collectCTBody(gch: var TGcHeap) =
+  when withRealTime:
+    let t0 = getticks()
+  sysAssert(allocInv(gch.region), "collectCT: begin")
+
+  gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
+  sysAssert(gch.decStack.len == 0, "collectCT")
+  prepareForInteriorPointerChecking(gch.region)
+  markStackAndRegisters(gch)
+  markThreadStacks(gch)
+  gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
+  inc(gch.stat.stackScans)
+  if collectZCT(gch):
+    when cycleGC:
+      if getOccupiedMem(gch.region) >= gch.cycleThreshold or alwaysCycleGC:
+        collectCycles(gch)
+        #discard collectZCT(gch)
+        inc(gch.stat.cycleCollections)
+        gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
+                                 CycleIncrease)
+        gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
+  unmarkStackAndRegisters(gch)
+  sysAssert(allocInv(gch.region), "collectCT: end")
+
+  when withRealTime:
+    let duration = getticks() - t0
+    gch.stat.maxPause = max(gch.stat.maxPause, duration)
+    when defined(reportMissedDeadlines):
+      if gch.maxPause > 0 and duration > gch.maxPause:
+        c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
+
+when useMarkForDebug or useBackupGc:
+  proc markForDebug(gch: var TGcHeap) =
+    markStackAndRegistersForSweep(gch)
+    markGlobals(gch)
+
+proc collectCT(gch: var TGcHeap) =
+  # stackMarkCosts prevents some pathological behaviour: Stack marking
+  # becomes more expensive with large stacks and large stacks mean that
+  # cells with RC=0 are more likely to be kept alive by the stack.
+  let stackMarkCosts = max(stackSize() div (16*sizeof(int)), ZctThreshold)
+  if (gch.zct.len >= stackMarkCosts or (cycleGC and
+      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
+      gch.recGcLock == 0:
+    when useMarkForDebug:
+      prepareForInteriorPointerChecking(gch.region)
+      cellsetReset(gch.marked)
+      markForDebug(gch)
+    collectCTBody(gch)
+
+when withRealTime:
+  proc toNano(x: int): TNanos {.inline.} =
+    result = x * 1000
+
+  proc GC_setMaxPause*(MaxPauseInUs: int) =
+    gch.maxPause = MaxPauseInUs.toNano
+
+  proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
+    acquire(gch)
+    gch.maxPause = us.toNano
+    if (gch.zct.len >= ZctThreshold or (cycleGC and
+        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
+        strongAdvice:
+      collectCTBody(gch)
+    release(gch)
+
+  proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
+
+when not defined(useNimRtl):
+  proc GC_disable() =
+    when hasThreadSupport and hasSharedHeap:
+      discard atomicInc(gch.recGcLock, 1)
+    else:
+      inc(gch.recGcLock)
+  proc GC_enable() =
+    if gch.recGcLock > 0:
+      when hasThreadSupport and hasSharedHeap:
+        discard atomicDec(gch.recGcLock, 1)
+      else:
+        dec(gch.recGcLock)
+
+  proc GC_setStrategy(strategy: GC_Strategy) =
+    discard
+
+  proc GC_enableMarkAndSweep() =
+    gch.cycleThreshold = InitialCycleThreshold
+
+  proc GC_disableMarkAndSweep() =
+    gch.cycleThreshold = high(gch.cycleThreshold)-1
+    # set to the max value to suppress the cycle detector
+
+  proc GC_fullCollect() =
+    acquire(gch)
+    var oldThreshold = gch.cycleThreshold
+    gch.cycleThreshold = 0 # forces cycle collection
+    collectCT(gch)
+    gch.cycleThreshold = oldThreshold
+    release(gch)
+
+  proc GC_getStatistics(): string =
+    GC_disable()
+    result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
+             "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
+             "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
+             "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
+             "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
+             "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
+             "[GC] zct capacity: " & $gch.zct.cap & "\n" &
+             "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
+             "[GC] max stack size: " & $gch.stat.maxStackSize & "\n" &
+             "[GC] max pause time [ms]: " & $(gch.stat.maxPause div 1000_000)
+    GC_enable()
+
+{.pop.}
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
new file mode 100644
index 000000000..4e3dee51c
--- /dev/null
+++ b/lib/system/gc2.nim
@@ -0,0 +1,1393 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#            Garbage Collector
+#
+# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
+# This is achieved by combining a Deutsch-Bobrow garbage collector
+# together with Christoper's partial mark-sweep garbage collector.
+#
+# Special care has been taken to avoid recursion as far as possible to avoid
+# stack overflows when traversing deep datastructures. It is well-suited
+# for soft real time applications (like games).
+{.push profiler:off.}
+
+const
+  CycleIncrease = 2 # is a multiplicative increase
+  InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
+  ZctThreshold = 500  # we collect garbage if the ZCT's size
+                      # reaches this threshold
+                      # this seems to be a good value
+  withRealTime = defined(useRealtimeGC)
+
+when withRealTime and not declared(getTicks):
+  include "system/timers"
+when defined(memProfiler):
+  proc nimProfile(requestedSize: int)
+
+const
+  rcShift = 6 # the reference count is shifted so we can use
+              # the least significat bits for additinal flags:
+
+  rcAlive = 0b00000           # object is reachable.
+                              # color *black* in the original paper
+                              
+  rcCycleCandidate = 0b00001  # possible root of a cycle. *purple*
+
+  rcDecRefApplied = 0b00010   # the first dec-ref phase of the
+                              # collector was already applied to this
+                              # object. *gray*
+                              
+  rcMaybeDead = 0b00011       # this object is a candidate for deletion
+                              # during the collect cycles algorithm.
+                              # *white*.
+                              
+  rcReallyDead = 0b00100      # this is proved to be garbage
+  
+  rcRetiredBuffer = 0b00101   # this is a seq or string buffer that
+                              # was replaced by a resize operation.
+                              # see growObj for details
+
+  rcColorMask = TRefCount(0b00111)
+
+  rcZct = 0b01000             # already added to ZCT
+  rcInCycleRoots = 0b10000    # already buffered as cycle candidate
+  rcHasStackRef = 0b100000    # the object had a stack ref in the last
+                              # cycle collection
+
+  rcMarkBit = rcHasStackRef   # this is currently used for leak detection
+                              # when traceGC is on
+
+  rcBufferedAnywhere = rcZct or rcInCycleRoots
+
+  rcIncrement = 1 shl rcShift # don't touch the color bits
+
+const
+  NewObjectsAreCycleRoots = true
+    # the alternative is to use the old strategy of adding cycle roots
+    # in incRef (in the compiler itself, this doesn't change much)
+
+  IncRefRemovesCandidates = false
+    # this is safe only if we can reliably track the fact that the object
+    # has stack references. This could be easily done by adding another bit
+    # to the refcount field and setting it up in unmarkStackAndRegisters.
+    # The bit must also be set for new objects that are not rc1 and it must be
+    # examined in the decref loop in collectCycles.
+    # XXX: not implemented yet as tests didn't show any improvement from this
+   
+  MarkingSkipsAcyclicObjects = true
+    # Acyclic objects can be safely ignored in the mark and scan phases, 
+    # because they cannot contribute to the internal count.
+    # XXX: if we generate specialized `markCyclic` and `markAcyclic`
+    # procs we can further optimize this as there won't be need for any
+    # checks in the code
+  
+  MinimumStackMarking = false
+    # Try to scan only the user stack and ignore the part of the stack
+    # belonging to the GC itself. see setStackTop for further info.
+    # XXX: still has problems in release mode in the compiler itself.
+    # investigate how it affects growObj
+
+  CollectCyclesStats = false
+
+type
+  TWalkOp = enum
+    waPush
+
+  TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall.}
+    # A ref type can have a finalizer that is called before the object's
+    # storage is freed.
+
+  TGcStat {.final, pure.} = object
+    stackScans: int          # number of performed stack scans (for statistics)
+    cycleCollections: int    # number of performed full collections
+    maxThreshold: int        # max threshold that has been set
+    maxStackSize: int        # max stack size
+    maxStackCells: int       # max stack cells in ``decStack``
+    cycleTableSize: int      # max entries in cycle table  
+    maxPause: int64          # max measured GC pause in nanoseconds
+  
+  TGcHeap {.final, pure.} = object # this contains the zero count and
+                                   # non-zero count table
+    stackBottom: pointer
+    stackTop: pointer
+    cycleThreshold: int
+    zct: TCellSeq            # the zero count table
+    decStack: TCellSeq       # cells in the stack that are to decref again
+    cycleRoots: TCellSeq
+    tempStack: TCellSeq      # temporary stack for recursion elimination
+    freeStack: TCellSeq      # objects ready to be freed
+    recGcLock: int           # prevent recursion via finalizers; no thread lock
+    cycleRootsTrimIdx: int   # Trimming is a light-weight collection of the 
+                             # cycle roots table that uses a cheap linear scan
+                             # to find only possitively dead objects.
+                             # One strategy is to perform it only for new objects
+                             # allocated between the invocations of collectZCT.
+                             # This index indicates the start of the range of
+                             # such new objects within the table.
+    when withRealTime:
+      maxPause: TNanos       # max allowed pause in nanoseconds; active if > 0
+    region: TMemRegion       # garbage collected region
+    stat: TGcStat
+
+var
+  gch* {.rtlThreadVar.}: TGcHeap
+
+when not defined(useNimRtl):
+  instantiateForRegion(gch.region)
+
+template acquire(gch: TGcHeap) = 
+  when hasThreadSupport and hasSharedHeap:
+    AcquireSys(HeapLock)
+
+template release(gch: TGcHeap) = 
+  when hasThreadSupport and hasSharedHeap:
+    releaseSys(HeapLock)
+
+template setColor(c: PCell, color) =
+  c.refcount = (c.refcount and not rcColorMask) or color
+
+template color(c: PCell): expr =
+  c.refcount and rcColorMask
+
+template isBitDown(c: PCell, bit): expr =
+  (c.refcount and bit) == 0
+
+template isBitUp(c: PCell, bit): expr =
+  (c.refcount and bit) != 0
+
+template setBit(c: PCell, bit): expr =
+  c.refcount = c.refcount or bit
+
+template isDead(c: Pcell): expr =
+  c.isBitUp(rcReallyDead) # also covers rcRetiredBuffer
+
+template clearBit(c: PCell, bit): expr =
+  c.refcount = c.refcount and (not TRefCount(bit))
+
+when debugGC:
+  var gcCollectionIdx = 0
+
+  proc colorStr(c: PCell): cstring =
+    let color = c.color
+    case color
+    of rcAlive: return "alive"
+    of rcMaybeDead: return "maybedead"
+    of rcCycleCandidate: return "candidate"
+    of rcDecRefApplied: return "marked"
+    of rcRetiredBuffer: return "retired"
+    of rcReallyDead: return "dead"
+    else: return "unknown?"
+  
+  proc inCycleRootsStr(c: PCell): cstring =
+    if c.isBitUp(rcInCycleRoots): result = "cycleroot"
+    else: result = ""
+
+  proc inZctStr(c: PCell): cstring =
+    if c.isBitUp(rcZct): result = "zct"
+    else: result = ""
+
+  proc writeCell*(msg: CString, c: PCell, force = false) =
+    var kind = -1
+    if c.typ != nil: kind = ord(c.typ.kind)
+    when trackAllocationSource:
+      c_fprintf(c_stdout, "[GC %d] %s: %p %d rc=%ld %s %s %s from %s(%ld)\n",
+                gcCollectionIdx,
+                msg, c, kind, c.refcount shr rcShift,
+                c.colorStr, c.inCycleRootsStr, c.inZctStr,
+                c.filename, c.line)
+    else:
+      c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld\n",
+                msg, c, kind, c.refcount shr rcShift)
+
+proc addZCT(zct: var TCellSeq, c: PCell) {.noinline.} =
+  if c.isBitDown(rcZct):
+    c.setBit rcZct
+    zct.add c
+
+template setStackTop(gch) =
+  # This must be called immediately after we enter the GC code
+  # to minimize the size of the scanned stack. The stack consumed
+  # by the GC procs may amount to 200-400 bytes depending on the
+  # build settings and this contributes to false-positives
+  # in the conservative stack marking
+  when MinimumStackMarking:
+    var stackTop {.volatile.}: pointer
+    gch.stackTop = addr(stackTop)
+
+template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) =
+  if c.color != rcCycleCandidate:
+    c.setColor rcCycleCandidate
+    
+    # the object may be buffered already. for example, consider:
+    # decref; incref; decref
+    if c.isBitDown(rcInCycleRoots):
+      c.setBit rcInCycleRoots
+      cycleRoots.add c
+
+proc cellToUsr(cell: PCell): pointer {.inline.} =
+  # convert object (=pointer to refcount) to pointer to userdata
+  result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
+
+proc usrToCell*(usr: pointer): PCell {.inline.} =
+  # convert pointer to userdata to object (=pointer to refcount)
+  result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
+
+proc canbeCycleRoot(c: PCell): bool {.inline.} =
+  result = ntfAcyclic notin c.typ.flags
+
+proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
+  # used for code generation concerning debugging
+  result = usrToCell(c).typ
+
+proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
+  result = int(usrToCell(p).refcount) shr rcShift
+
+# this that has to equals zero, otherwise we have to round up UnitsPerPage:
+when BitsPerPage mod (sizeof(int)*8) != 0:
+  {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
+
+# forward declarations:
+proc collectCT(gch: var TGcHeap)
+proc isOnStack*(p: pointer): bool {.noinline.}
+proc forAllChildren(cell: PCell, op: TWalkOp)
+proc doOperation(p: pointer, op: TWalkOp)
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
+# we need the prototype here for debugging purposes
+
+proc prepareDealloc(cell: PCell) =
+  if cell.typ.finalizer != nil:
+    # the finalizer could invoke something that
+    # allocates memory; this could trigger a garbage
+    # collection. Since we are already collecting we
+    # prevend recursive entering here by a lock.
+    # XXX: we should set the cell's children to nil!
+    inc(gch.recGcLock)
+    (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
+    dec(gch.recGcLock)
+
+when traceGC:
+  # traceGC is a special switch to enable extensive debugging
+  type
+    TCellState = enum
+      csAllocated, csFreed
+  var
+    states: array[TCellState, TCellSet]
+
+  proc traceCell(c: PCell, state: TCellState) =
+    case state
+    of csAllocated:
+      if c in states[csAllocated]:
+        writeCell("attempt to alloc an already allocated cell", c)
+        sysAssert(false, "traceCell 1")
+      excl(states[csFreed], c)
+      # writecell("allocated", c)
+    of csFreed:
+      if c in states[csFreed]:
+        writeCell("attempt to free a cell twice", c)
+        sysAssert(false, "traceCell 2")
+      if c notin states[csAllocated]:
+        writeCell("attempt to free not an allocated cell", c)
+        sysAssert(false, "traceCell 3")
+      excl(states[csAllocated], c)
+      # writecell("freed", c)
+    incl(states[state], c)
+
+  proc computeCellWeight(c: PCell): int =
+    var x: TCellSet
+    x.init
+
+    let startLen = gch.tempStack.len
+    c.forAllChildren waPush
+    
+    while startLen != gch.tempStack.len:
+      dec gch.tempStack.len
+      var c = gch.tempStack.d[gch.tempStack.len]
+      if c in states[csFreed]: continue
+      inc result
+      if c notin x:
+        x.incl c
+        c.forAllChildren waPush
+
+  template markChildrenRec(cell) =
+    let startLen = gch.tempStack.len
+    cell.forAllChildren waPush
+    let isMarked = cell.isBitUp(rcMarkBit)
+    while startLen != gch.tempStack.len:
+      dec gch.tempStack.len
+      var c = gch.tempStack.d[gch.tempStack.len]
+      if c in states[csFreed]: continue
+      if c.isBitDown(rcMarkBit):
+        c.setBit rcMarkBit
+        c.forAllChildren waPush
+    if c.isBitUp(rcMarkBit) and not isMarked:
+      writecell("cyclic cell", cell)
+      cprintf "Weight %d\n", cell.computeCellWeight
+      
+  proc writeLeakage(onlyRoots: bool) =
+    if onlyRoots:
+      for c in elements(states[csAllocated]):
+        if c notin states[csFreed]:
+          markChildrenRec(c)
+    var f = 0
+    var a = 0
+    for c in elements(states[csAllocated]):
+      inc a
+      if c in states[csFreed]: inc f
+      elif c.isBitDown(rcMarkBit):
+        writeCell("leak", c)
+        cprintf "Weight %d\n", c.computeCellWeight
+    cfprintf(cstdout, "Allocations: %ld; freed: %ld\n", a, f)
+
+template gcTrace(cell, state: expr): stmt {.immediate.} =
+  when logGC: writeCell($state, cell)
+  when traceGC: traceCell(cell, state)
+
+template WithHeapLock(blk: stmt): stmt =
+  when hasThreadSupport and hasSharedHeap: AcquireSys(HeapLock)
+  blk
+  when hasThreadSupport and hasSharedHeap: ReleaseSys(HeapLock)
+
+proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} = 
+  # we MUST access gch as a global here, because this crosses DLL boundaries!
+  WithHeapLock: addCycleRoot(gch.cycleRoots, c)
+
+proc rtlAddZCT(c: PCell) {.rtl, inl.} =
+  # we MUST access gch as a global here, because this crosses DLL boundaries!
+  WithHeapLock: addZCT(gch.zct, c)
+
+type
+  TCyclicMode = enum
+    Cyclic,
+    Acyclic,
+    MaybeCyclic
+
+  TReleaseType = enum
+    AddToZTC
+    FreeImmediately
+
+  THeapType = enum
+    LocalHeap
+    SharedHeap
+
+template `++` (rc: TRefCount, heapType: THeapType): stmt =
+  when heapType == SharedHeap:
+    discard atomicInc(rc, rcIncrement)
+  else:
+    inc rc, rcIncrement
+
+template `--`(rc: TRefCount): expr =
+  dec rc, rcIncrement
+  rc <% rcIncrement
+
+template `--` (rc: TRefCount, heapType: THeapType): expr =
+  (when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
+
+template doDecRef(cc: PCell,
+                  heapType = LocalHeap,
+                  cycleFlag = MaybeCyclic): stmt =
+  var c = cc
+  sysAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr")
+  # XXX: move this elesewhere
+
+  sysAssert(c.refcount >=% rcIncrement, "decRef")
+  if c.refcount--(heapType):
+    # this is the last reference from the heap
+    # add to a zero-count-table that will be matched against stack pointers
+    rtlAddZCT(c)
+  else:
+    when cycleFlag != Acyclic:
+      if cycleFlag == Cyclic or canBeCycleRoot(c):
+        # a cycle may have been broken
+        rtlAddCycleRoot(c)
+
+template doIncRef(cc: PCell,
+                 heapType = LocalHeap,
+                 cycleFlag = MaybeCyclic): stmt =
+  var c = cc
+  c.refcount++(heapType)
+  when cycleFlag != Acyclic:
+    when NewObjectsAreCycleRoots:
+      if canbeCycleRoot(c):
+        addCycleRoot(gch.cycleRoots, c)
+    elif IncRefRemovesCandidates:
+      c.setColor rcAlive
+  # XXX: this is not really atomic enough!
+  
+proc nimGCref(p: pointer) {.compilerProc, inline.} = doIncRef(usrToCell(p))
+proc nimGCunref(p: pointer) {.compilerProc, inline.} = doDecRef(usrToCell(p))
+
+proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
+  sysAssert(allocInv(gch.region), "begin nimGCunrefNoCycle")
+  var c = usrToCell(p)
+  sysAssert(isAllocatedPtr(gch.region, c), "nimGCunrefNoCycle: isAllocatedPtr")
+  if c.refcount--(LocalHeap):
+    rtlAddZCT(c)
+    sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
+  sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
+
+template doAsgnRef(dest: PPointer, src: pointer,
+                  heapType = LocalHeap, cycleFlag = MaybeCyclic): stmt =
+  sysAssert(not isOnStack(dest), "asgnRef")
+  # BUGFIX: first incRef then decRef!
+  if src != nil: doIncRef(usrToCell(src), heapType, cycleFlag)
+  if dest[] != nil: doDecRef(usrToCell(dest[]), heapType, cycleFlag)
+  dest[] = src
+
+proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+  # the code generator calls this proc!
+  doAsgnRef(dest, src, LocalHeap, MaybeCyclic)
+
+proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+  # the code generator calls this proc if it is known at compile time that no 
+  # cycle is possible.
+  doAsgnRef(dest, src, LocalHeap, Acyclic)
+
+proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
+  # unsureAsgnRef updates the reference counters only if dest is not on the
+  # stack. It is used by the code generator if it cannot decide wether a
+  # reference is in the stack or not (this can happen for var parameters).
+  if not isOnStack(dest):
+    if src != nil: doIncRef(usrToCell(src))
+    # XXX we must detect a shared heap here
+    # better idea may be to just eliminate the need for unsureAsgnRef
+    #
+    # XXX finally use assembler for the stack checking instead!
+    # the test for '!= nil' is correct, but I got tired of the segfaults
+    # resulting from the crappy stack checking:
+    if cast[int](dest[]) >=% PageSize: doDecRef(usrToCell(dest[]))
+  else:
+    # can't be an interior pointer if it's a stack location!
+    sysAssert(interiorAllocatedPtr(gch.region, dest)==nil,
+              "stack loc AND interior pointer")
+  dest[] = src
+
+when hasThreadSupport and hasSharedHeap:
+  # shared heap version of the above procs
+  proc asgnRefSh(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+    doAsgnRef(dest, src, SharedHeap, MaybeCyclic)
+
+  proc asgnRefNoCycleSh(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+    doAsgnRef(dest, src, SharedHeap, Acyclic)
+
+proc initGC() =
+  when not defined(useNimRtl):
+    when traceGC:
+      for i in low(TCellState)..high(TCellState): init(states[i])
+    gch.cycleThreshold = InitialCycleThreshold
+    gch.stat.stackScans = 0
+    gch.stat.cycleCollections = 0
+    gch.stat.maxThreshold = 0
+    gch.stat.maxStackSize = 0
+    gch.stat.maxStackCells = 0
+    gch.stat.cycleTableSize = 0
+    # init the rt
+    init(gch.zct)
+    init(gch.tempStack)
+    init(gch.freeStack)
+    init(gch.cycleRoots)
+    init(gch.decStack)
+
+proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
+  var d = cast[ByteAddress](dest)
+  case n.kind
+  of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
+  of nkList:
+    for i in 0..n.len-1:
+      # inlined for speed
+      if n.sons[i].kind == nkSlot:
+        if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
+          doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
+        else:
+          forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), 
+                            n.sons[i].typ, op)
+      else:
+        forAllSlotsAux(dest, n.sons[i], op)
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: forAllSlotsAux(dest, m, op)
+  of nkNone: sysAssert(false, "forAllSlotsAux")
+
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
+  var d = cast[ByteAddress](dest)
+  if dest == nil: return # nothing to do
+  if ntfNoRefs notin mt.flags:
+    case mt.kind
+    of tyRef, tyString, tySequence: # leaf:
+      doOperation(cast[PPointer](d)[], op)
+    of tyObject, tyTuple:
+      forAllSlotsAux(dest, mt.node, op)
+    of tyArray, tyArrayConstr, tyOpenArray:
+      for i in 0..(mt.size div mt.base.size)-1:
+        forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
+    else: discard
+
+proc forAllChildren(cell: PCell, op: TWalkOp) =
+  sysAssert(cell != nil, "forAllChildren: 1")
+  sysAssert(cell.typ != nil, "forAllChildren: 2")
+  sysAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
+  let marker = cell.typ.marker
+  if marker != nil:
+    marker(cellToUsr(cell), op.int)
+  else:
+    case cell.typ.kind
+    of tyRef: # common case
+      forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
+    of tySequence:
+      var d = cast[ByteAddress](cellToUsr(cell))
+      var s = cast[PGenericSeq](d)
+      if s != nil:
+        let baseAddr = d +% GenericSeqSize
+        for i in 0..s.len-1:
+          forAllChildrenAux(cast[pointer](baseAddr +% i *% cell.typ.base.size),
+                            cell.typ.base, op)
+    else: discard
+
+proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
+  # we check the last 8 entries (cache line) for a slot that could be reused.
+  # In 63% of all cases we succeed here! But we have to optimize the heck
+  # out of this small linear search so that ``newObj`` is not slowed down.
+  # 
+  # Slots to try          cache hit
+  # 1                     32%
+  # 4                     59%
+  # 8                     63%
+  # 16                    66%
+  # all slots             68%
+  var L = gch.zct.len
+  var d = gch.zct.d
+  when true:
+    # loop unrolled for performance:
+    template replaceZctEntry(i: expr) =
+      c = d[i]
+      if c.refcount >=% rcIncrement:
+        c.clearBit(rcZct)
+        d[i] = res
+        return
+    if L > 8:
+      var c: PCell
+      replaceZctEntry(L-1)
+      replaceZctEntry(L-2)
+      replaceZctEntry(L-3)
+      replaceZctEntry(L-4)
+      replaceZctEntry(L-5)
+      replaceZctEntry(L-6)
+      replaceZctEntry(L-7)
+      replaceZctEntry(L-8)
+      add(gch.zct, res)
+    else:
+      d[L] = res
+      inc(gch.zct.len)
+  else:
+    for i in countdown(L-1, max(0, L-8)):
+      var c = d[i]
+      if c.refcount >=% rcIncrement:
+        c.clearBit(rcZct)
+        d[i] = res
+        return
+    add(gch.zct, res)
+
+proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1 = false): pointer =
+  # generates a new object and sets its reference counter to 0
+  acquire(gch)
+  sysAssert(allocInv(gch.region), "rawNewObj begin")
+  sysAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
+  
+  collectCT(gch)
+  sysAssert(allocInv(gch.region), "rawNewObj after collect")
+
+  var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
+  sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc")
+
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
+  
+  res.typ = typ
+  
+  when trackAllocationSource and not hasThreadSupport:
+    if framePtr != nil and framePtr.prev != nil and framePtr.prev.prev != nil:
+      res.filename = framePtr.prev.prev.filename
+      res.line = framePtr.prev.prev.line
+    else:
+      res.filename = "nofile"
+  
+  if rc1:
+    res.refcount = rcIncrement # refcount is 1
+  else:
+    # its refcount is zero, so add it to the ZCT:
+    res.refcount = rcZct
+    addNewObjToZCT(res, gch)
+
+    if NewObjectsAreCycleRoots and canBeCycleRoot(res):
+      res.setBit(rcInCycleRoots)
+      res.setColor rcCycleCandidate
+      gch.cycleRoots.add res
+    
+  sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
+  
+  when logGC: writeCell("new cell", res)
+  gcTrace(res, csAllocated)
+  release(gch)
+  result = cellToUsr(res)
+  sysAssert(allocInv(gch.region), "rawNewObj end")
+
+{.pop.}
+
+proc freeCell(gch: var TGcHeap, c: PCell) =
+  # prepareDealloc(c)
+  gcTrace(c, csFreed)
+
+  when reallyDealloc: rawDealloc(gch.region, c)
+  else:
+    sysAssert(c.typ != nil, "collectCycles")
+    zeroMem(c, sizeof(TCell))
+
+template eraseAt(cells: var TCellSeq, at: int): stmt =
+  cells.d[at] = cells.d[cells.len - 1]
+  dec cells.len
+
+template trimAt(roots: var TCellSeq, at: int): stmt =
+  # This will remove a cycle root candidate during trimming.
+  # a candidate is removed either because it received a refup and
+  # it's no longer a candidate or because it received further refdowns
+  # and now it's dead for sure.
+  let c = roots.d[at]
+  c.clearBit(rcInCycleRoots)
+  roots.eraseAt(at)
+  if c.isBitUp(rcReallyDead) and c.refcount <% rcIncrement:
+    # This case covers both dead objects and retired buffers
+    # That's why we must also check the refcount (it may be
+    # kept possitive by stack references).
+    freeCell(gch, c)
+
+proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  result = rawNewObj(typ, size, gch, false)
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  result = rawNewObj(typ, size, gch, false)
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  # `newObj` already uses locks, so no need for them here.
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObj(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+
+proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  result = rawNewObj(typ, size, gch, true)
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  setStackTop(gch)
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObjRC1(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+
+proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
+  acquire(gch)
+  collectCT(gch)
+  var ol = usrToCell(old)
+  sysAssert(ol.typ != nil, "growObj: 1")
+  sysAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
+  sysAssert(allocInv(gch.region), "growObj begin")
+
+  var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
+  var elemSize = if ol.typ.kind != tyString: ol.typ.base.size
+                 else: 1
+  
+  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+  
+  # XXX: This should happen outside
+  # call user-defined move code
+  # call user-defined default constructor
+  copyMem(res, ol, oldsize + sizeof(TCell))
+  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
+          newsize-oldsize)
+
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
+  sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4")
+  
+  when false:
+    if ol.isBitUp(rcZct):
+      var j = gch.zct.len-1
+      var d = gch.zct.d
+      while j >= 0: 
+        if d[j] == ol:
+          d[j] = res
+          break
+        dec(j)
+    
+    if ol.isBitUp(rcInCycleRoots):
+      for i in 0 .. <gch.cycleRoots.len:
+        if gch.cycleRoots.d[i] == ol:
+          eraseAt(gch.cycleRoots, i)
+
+    freeCell(gch, ol)
+  
+  else:
+    # the new buffer inherits the GC state of the old one
+    if res.isBitUp(rcZct): gch.zct.add res
+    if res.isBitUp(rcInCycleRoots): gch.cycleRoots.add res
+
+    # Pay attention to what's going on here! We're not releasing the old memory.
+    # This is because at this point there may be an interior pointer pointing
+    # into this buffer somewhere on the stack (due to `var` parameters now and
+    # and `let` and `var:var` stack locations in the future).
+    # We'll release the memory in the next GC cycle. If we release it here,
+    # we cannot guarantee that no memory will be corrupted when only safe
+    # language features are used. Accessing the memory after the seq/string
+    # has been invalidated may still result in logic errors in the user code.
+    # We may improve on that by protecting the page in debug builds or
+    # by providing a warning when we detect a stack pointer into it.
+    let bufferFlags = ol.refcount and rcBufferedAnywhere
+    if bufferFlags == 0:
+      # we need this in order to collect it safely later
+      ol.refcount = rcRetiredBuffer or rcZct
+      gch.zct.add ol
+    else:
+      ol.refcount = rcRetiredBuffer or bufferFlags
+
+    when logGC:
+      writeCell("growObj old cell", ol)
+      writeCell("growObj new cell", res)
+
+  gcTrace(res, csAllocated)
+  release(gch)
+  result = cellToUsr(res)
+  sysAssert(allocInv(gch.region), "growObj end")
+  when defined(memProfiler): nimProfile(newsize-oldsize)
+
+proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
+  setStackTop(gch)
+  result = growObj(old, newsize, gch)
+
+{.push profiler:off.}
+
+# ---------------- cycle collector -------------------------------------------
+
+proc doOperation(p: pointer, op: TWalkOp) =
+  if p == nil: return
+  var c: PCell = usrToCell(p)
+  sysAssert(c != nil, "doOperation: 1")
+  gch.tempStack.add c
+  
+proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
+  doOperation(d, TWalkOp(op))
+
+type
+  TRecursionType = enum 
+    FromChildren,
+    FromRoot
+
+proc collectZCT(gch: var TGcHeap): bool
+
+template pseudoRecursion(typ: TRecursionType, body: stmt): stmt =
+  discard
+
+proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) =
+  var i = startIdx
+  while i < gch.cycleRoots.len:
+    if gch.cycleRoots.d[i].color != rcCycleCandidate:
+      gch.cycleRoots.trimAt i
+    else:
+      inc i
+
+  gch.cycleRootsTrimIdx = gch.cycleRoots.len
+
+# we now use a much simpler and non-recursive algorithm for cycle removal
+proc collectCycles(gch: var TGcHeap) =
+  if gch.cycleRoots.len == 0: return
+  gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, gch.cycleRoots.len)
+
+  when CollectCyclesStats:
+    let l0 = gch.cycleRoots.len
+    let tStart = getTicks()
+
+  var
+    decrefs = 0
+    increfs = 0
+    collected = 0
+    maybedeads = 0
+
+  template ignoreObject(c: PCell): expr =
+    # This controls which objects will be ignored in the mark and scan stages
+    (when MarkingSkipsAcyclicObjects: not canbeCycleRoot(c) else: false)
+    # not canbeCycleRoot(c)
+    # false
+    # c.isBitUp(rcHasStackRef)
+
+  template earlyMarkAliveRec(cell) =
+    let startLen = gch.tempStack.len
+    cell.setColor rcAlive
+    cell.forAllChildren waPush
+    
+    while startLen != gch.tempStack.len:
+      dec gch.tempStack.len
+      var c = gch.tempStack.d[gch.tempStack.len]
+      if c.color != rcAlive:
+        c.setColor rcAlive
+        c.forAllChildren waPush
+  
+  template earlyMarkAlive(stackRoots) =
+    # This marks all objects reachable from the stack as alive before any
+    # of the other stages is executed. Such objects cannot be garbage and
+    # they don't need to participate in the recursive decref/incref.
+    for i in 0 .. <stackRoots.len:
+      var c = stackRoots.d[i]
+      # c.setBit rcHasStackRef
+      earlyMarkAliveRec(c)
+
+  earlyMarkAlive(gch.decStack)
+  
+  when CollectCyclesStats:
+    let tAfterEarlyMarkAlive = getTicks()
+
+  template recursiveDecRef(cell) =
+    let startLen = gch.tempStack.len
+    cell.setColor rcDecRefApplied
+    cell.forAllChildren waPush
+    
+    while startLen != gch.tempStack.len:
+      dec gch.tempStack.len
+      var c = gch.tempStack.d[gch.tempStack.len]
+      if ignoreObject(c): continue
+
+      sysAssert(c.refcount >=% rcIncrement, "recursive dec ref")
+      dec c.refcount, rcIncrement
+      inc decrefs
+      if c.color != rcDecRefApplied:
+        c.setColor rcDecRefApplied
+        c.forAllChildren waPush
+ 
+  template markRoots(roots) =
+    var i = 0
+    while i < roots.len:
+      if roots.d[i].color == rcCycleCandidate:
+        recursiveDecRef(roots.d[i])
+        inc i
+      else:
+        roots.trimAt i
+  
+  markRoots(gch.cycleRoots)
+  
+  when CollectCyclesStats:
+    let tAfterMark = getTicks()
+    c_printf "COLLECT CYCLES %d: %d/%d\n", gcCollectionIdx, gch.cycleRoots.len, l0
+  
+  template recursiveMarkAlive(cell) =
+    let startLen = gch.tempStack.len
+    cell.setColor rcAlive
+    cell.forAllChildren waPush
+    
+    while startLen != gch.tempStack.len:
+      dec gch.tempStack.len
+      var c = gch.tempStack.d[gch.tempStack.len]
+      if ignoreObject(c): continue
+      inc c.refcount, rcIncrement
+      inc increfs
+      
+      if c.color != rcAlive:
+        c.setColor rcAlive
+        c.forAllChildren waPush
+ 
+  template scanRoots(roots) =
+    for i in 0 .. <roots.len:
+      let startLen = gch.tempStack.len
+      gch.tempStack.add roots.d[i]
+      
+      while startLen != gch.tempStack.len:
+        dec gch.tempStack.len
+        var c = gch.tempStack.d[gch.tempStack.len]
+        if ignoreObject(c): continue
+        if c.color == rcDecRefApplied:
+          if c.refcount >=% rcIncrement:
+            recursiveMarkAlive(c)
+          else:
+            # note that this is not necessarily the ultimate
+            # destiny of the object. we may still mark it alive
+            # later if we encounter another node from where it's
+            # reachable.
+            c.setColor rcMaybeDead
+            inc maybedeads
+            c.forAllChildren waPush
+  
+  scanRoots(gch.cycleRoots)
+  
+  when CollectCyclesStats:
+    let tAfterScan = getTicks()
+
+  template collectDead(roots) =
+    for i in 0 .. <roots.len:
+      var c = roots.d[i]
+      c.clearBit(rcInCycleRoots)
+
+      let startLen = gch.tempStack.len
+      gch.tempStack.add c
+      
+      while startLen != gch.tempStack.len:
+        dec gch.tempStack.len
+        var c = gch.tempStack.d[gch.tempStack.len]
+        when MarkingSkipsAcyclicObjects:
+          if not canbeCycleRoot(c):
+            # This is an acyclic object reachable from a dead cyclic object
+            # We must do a normal decref here that may add the acyclic object
+            # to the ZCT
+            doDecRef(c, LocalHeap, Cyclic)
+            continue
+        if c.color == rcMaybeDead and not c.isBitUp(rcInCycleRoots):
+          c.setColor(rcReallyDead)
+          inc collected
+          c.forAllChildren waPush
+          # we need to postpone the actual deallocation in order to allow
+          # the finalizers to run while the data structures are still intact
+          gch.freeStack.add c
+          prepareDealloc(c)
+
+    for i in 0 .. <gch.freeStack.len:
+      freeCell(gch, gch.freeStack.d[i])
+
+  collectDead(gch.cycleRoots)
+  
+  when CollectCyclesStats:
+    let tFinal = getTicks()
+    cprintf "times:\n  early mark alive: %d ms\n  mark: %d ms\n  scan: %d ms\n  collect: %d ms\n  decrefs: %d\n  increfs: %d\n  marked dead: %d\n  collected: %d\n",
+      (tAfterEarlyMarkAlive - tStart)  div 1_000_000,
+      (tAfterMark - tAfterEarlyMarkAlive) div 1_000_000,
+      (tAfterScan - tAfterMark) div 1_000_000,
+      (tFinal - tAfterScan) div 1_000_000,
+      decrefs,
+      increfs,
+      maybedeads,
+      collected
+
+  deinit(gch.cycleRoots)
+  init(gch.cycleRoots)
+
+  deinit(gch.freeStack)
+  init(gch.freeStack)
+
+  when MarkingSkipsAcyclicObjects:
+    # Collect the acyclic objects that became unreachable due to collected
+    # cyclic objects. 
+    discard collectZCT(gch)
+    # collectZCT may add new cycle candidates and we may decide to loop here
+    # if gch.cycleRoots.len > 0: repeat
+
+var gcDebugging* = false
+
+var seqdbg* : proc (s: PGenericSeq) {.cdecl.}
+
+proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
+  # the addresses are not as cells on the stack, so turn them to cells:
+  sysAssert(allocInv(gch.region), "gcMark begin")
+  var cell = usrToCell(p)
+  var c = cast[ByteAddress](cell)
+  if c >% PageSize:
+    # fast check: does it look like a cell?
+    var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
+    if objStart != nil:
+      # mark the cell:
+      if objStart.color != rcReallyDead:
+        if gcDebugging:
+          # writeCell("marking ", objStart)
+          discard
+        else:
+          inc objStart.refcount, rcIncrement
+          gch.decStack.add objStart
+      else:
+        # With incremental clean-up, objects spend some time
+        # in various lists before being deallocated.
+        # We just found a reference on the stack to an object,
+        # which we have previously labeled as unreachable.
+        # This is either a bug in the GC or a pure accidental
+        # coincidence due to the conservative stack marking.
+        when debugGC:
+          # writeCell("marking dead object", objStart)
+          discard
+    when false:
+      if isAllocatedPtr(gch.region, cell):
+        sysAssert false, "allocated pointer but not interior?"
+        # mark the cell:
+        inc cell.refcount, rcIncrement
+        add(gch.decStack, cell)
+  sysAssert(allocInv(gch.region), "gcMark end")
+
+proc markThreadStacks(gch: var TGcHeap) = 
+  when hasThreadSupport and hasSharedHeap:
+    {.error: "not fully implemented".}
+    var it = threadList
+    while it != nil:
+      # mark registers: 
+      for i in 0 .. high(it.registers): gcMark(gch, it.registers[i])
+      var sp = cast[ByteAddress](it.stackBottom)
+      var max = cast[ByteAddress](it.stackTop)
+      # XXX stack direction?
+      # XXX unroll this loop:
+      while sp <=% max:
+        gcMark(gch, cast[PPointer](sp)[])
+        sp = sp +% sizeof(pointer)
+      it = it.next
+
+# ----------------- stack management --------------------------------------
+#  inspired from Smart Eiffel
+
+when defined(sparc):
+  const stackIncreases = false
+elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
+     defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
+  const stackIncreases = true
+else:
+  const stackIncreases = false
+
+when not defined(useNimRtl):
+  {.push stack_trace: off.}
+  proc setStackBottom(theStackBottom: pointer) =
+    #c_fprintf(c_stdout, "stack bottom: %p;\n", theStackBottom)
+    # the first init must be the one that defines the stack bottom:
+    if gch.stackBottom == nil: gch.stackBottom = theStackBottom
+    else:
+      var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
+      var b = cast[ByteAddress](gch.stackBottom)
+      #c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
+      when stackIncreases:
+        gch.stackBottom = cast[pointer](min(a, b))
+      else:
+        gch.stackBottom = cast[pointer](max(a, b))
+  {.pop.}
+
+proc stackSize(): int {.noinline.} =
+  var stackTop {.volatile.}: pointer
+  result = abs(cast[int](addr(stackTop)) - cast[int](gch.stackBottom))
+
+var
+  jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
+    # a little hack to get the size of a TJmpBuf in the generated C code
+    # in a platform independent way
+
+when defined(sparc): # For SPARC architecture.
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    when defined(sparcv9):
+      asm  """"flushw \n" """
+    else:
+      asm  """"ta      0x3   ! ST_FLUSH_WINDOWS\n" """
+
+    var
+      max = gch.stackBottom
+      sp: PPointer
+      stackTop: array[0..1, pointer]
+    sp = addr(stackTop[0])
+    # Addresses decrease as the stack grows.
+    while sp <= max:
+      gcMark(gch, sp[])
+      sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer))
+
+elif defined(ELATE):
+  {.error: "stack marking code is to be written for this architecture".}
+
+elif stackIncreases:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses increase as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var a = cast[ByteAddress](gch.stackBottom)
+    var b = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+  
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    var registers: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[ByteAddress](gch.stackBottom)
+      var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
+      # sp will traverse the JMP_BUF as well (jmp_buf size is added,
+      # otherwise sp would be below the registers structure).
+      while sp >=% max:
+        gcMark(gch, cast[PPointer](sp)[])
+        sp = sp -% sizeof(pointer)
+
+else:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses decrease as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    # We use a jmp_buf buffer that is in the C stack.
+    # Used to traverse the stack and registers assuming
+    # that 'setjmp' will save registers in the C stack.
+    type PStackSlice = ptr array [0..7, pointer]
+    var registers: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      when MinimumStackMarking:
+        # mark the registers
+        var jmpbufPtr = cast[ByteAddress](addr(registers))
+        var jmpbufEnd = jmpbufPtr +% jmpbufSize
+      
+        while jmpbufPtr <=% jmpbufEnd:
+          gcMark(gch, cast[PPointer](jmpbufPtr)[])
+          jmpbufPtr = jmpbufPtr +% sizeof(pointer)
+
+        var sp = cast[ByteAddress](gch.stackTop)
+      else:
+        var sp = cast[ByteAddress](addr(registers))
+      # mark the user stack
+      var max = cast[ByteAddress](gch.stackBottom)
+      # loop unrolled:
+      while sp <% max - 8*sizeof(pointer):
+        gcMark(gch, cast[PStackSlice](sp)[0])
+        gcMark(gch, cast[PStackSlice](sp)[1])
+        gcMark(gch, cast[PStackSlice](sp)[2])
+        gcMark(gch, cast[PStackSlice](sp)[3])
+        gcMark(gch, cast[PStackSlice](sp)[4])
+        gcMark(gch, cast[PStackSlice](sp)[5])
+        gcMark(gch, cast[PStackSlice](sp)[6])
+        gcMark(gch, cast[PStackSlice](sp)[7])
+        sp = sp +% sizeof(pointer)*8
+      # last few entries:
+      while sp <=% max:
+        gcMark(gch, cast[PPointer](sp)[])
+        sp = sp +% sizeof(pointer)
+
+# ----------------------------------------------------------------------------
+# end of non-portable code
+# ----------------------------------------------------------------------------
+
+proc releaseCell(gch: var TGcHeap, cell: PCell) =
+  if cell.color != rcReallyDead:
+    prepareDealloc(cell)
+    cell.setColor rcReallyDead
+
+    let l1 = gch.tempStack.len
+    cell.forAllChildren waPush
+    let l2 = gch.tempStack.len
+    for i in l1 .. <l2:
+      var cc = gch.tempStack.d[i]
+      if cc.refcount--(LocalHeap):
+        releaseCell(gch, cc)
+      else:
+        if canbeCycleRoot(cc):
+          addCycleRoot(gch.cycleRoots, cc)
+
+    gch.tempStack.len = l1
+
+  if cell.isBitDown(rcBufferedAnywhere):
+    freeCell(gch, cell)
+  # else:
+  # This object is either buffered in the cycleRoots list and we'll leave
+  # it there to be collected in the next collectCycles or it's pending in
+  # the ZCT:
+  # (e.g. we are now cleaning the 15th object, but this one is 18th in the
+  #  list. Note that this can happen only if we reached this point by the
+  #  recursion).
+  # We can ignore it now as the ZCT cleaner will reach it soon.
+
+proc collectZCT(gch: var TGcHeap): bool =
+  const workPackage = 100
+  var L = addr(gch.zct.len)
+  
+  when withRealtime:
+    var steps = workPackage
+    var t0: TTicks
+    if gch.maxPause > 0: t0 = getticks()
+  
+  while L[] > 0:
+    var c = gch.zct.d[0]
+    sysAssert c.isBitUp(rcZct), "collectZCT: rcZct missing!"
+    sysAssert(isAllocatedPtr(gch.region, c), "collectZCT: isAllocatedPtr")
+    
+    # remove from ZCT:    
+    c.clearBit(rcZct)
+    gch.zct.d[0] = gch.zct.d[L[] - 1]
+    dec(L[])
+    when withRealtime: dec steps
+    if c.refcount <% rcIncrement:
+      # It may have a RC > 0, if it is in the hardware stack or
+      # it has not been removed yet from the ZCT. This is because
+      # ``incref`` does not bother to remove the cell from the ZCT 
+      # as this might be too slow.
+      # In any case, it should be removed from the ZCT. But not
+      # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
+      if c.color == rcRetiredBuffer:
+        if c.isBitDown(rcInCycleRoots):
+          freeCell(gch, c)
+      else:
+        # if c.color == rcReallyDead: writeCell("ReallyDead in ZCT?", c)
+        releaseCell(gch, c)
+    when withRealtime:
+      if steps == 0:
+        steps = workPackage
+        if gch.maxPause > 0:
+          let duration = getticks() - t0
+          # the GC's measuring is not accurate and needs some cleanup actions 
+          # (stack unmarking), so subtract some short amount of time in to
+          # order to miss deadlines less often:
+          if duration >= gch.maxPause - 50_000:
+            return false
+  result = true
+  gch.trimCycleRoots
+  #deInit(gch.zct)
+  #init(gch.zct)
+
+proc unmarkStackAndRegisters(gch: var TGcHeap) =
+  var d = gch.decStack.d
+  for i in 0 .. <gch.decStack.len:
+    sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
+    # XXX: just call doDecRef?
+    var c = d[i]
+    sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
+    
+    if c.color == rcRetiredBuffer:
+      continue
+
+    # XXX no need for an atomic dec here:
+    if c.refcount--(LocalHeap):
+      # the object survived only because of a stack reference
+      # it still doesn't have heap references
+      addZCT(gch.zct, c)
+    
+    if canbeCycleRoot(c):
+      # any cyclic object reachable from the stack can be turned into
+      # a leak if it's orphaned through the stack reference
+      # that's because the write-barrier won't be executed for stack
+      # locations
+      addCycleRoot(gch.cycleRoots, c)
+
+  gch.decStack.len = 0
+
+proc collectCTBody(gch: var TGcHeap) =
+  when withRealtime:
+    let t0 = getticks()
+  when debugGC: inc gcCollectionIdx
+  sysAssert(allocInv(gch.region), "collectCT: begin")
+  
+  gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
+  sysAssert(gch.decStack.len == 0, "collectCT")
+  prepareForInteriorPointerChecking(gch.region)
+  markStackAndRegisters(gch)
+  markThreadStacks(gch)
+  gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
+  inc(gch.stat.stackScans)
+  if collectZCT(gch):
+    when cycleGC:
+      if getOccupiedMem(gch.region) >= gch.cycleThreshold or alwaysCycleGC:
+        collectCycles(gch)
+        sysAssert gch.zct.len == 0, "zct is not null after collect cycles"
+        inc(gch.stat.cycleCollections)
+        gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
+                                 CycleIncrease)
+        gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
+  unmarkStackAndRegisters(gch)
+  sysAssert(allocInv(gch.region), "collectCT: end")
+  
+  when withRealtime:
+    let duration = getticks() - t0
+    gch.stat.maxPause = max(gch.stat.maxPause, duration)
+    when defined(reportMissedDeadlines):
+      if gch.maxPause > 0 and duration > gch.maxPause:
+        c_fprintf(c_stdout, "[GC] missed deadline: %ld\n", duration)
+
+proc collectCT(gch: var TGcHeap) =
+  if (gch.zct.len >= ZctThreshold or (cycleGC and
+      getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and 
+      gch.recGcLock == 0:
+    collectCTBody(gch)
+
+when withRealtime:
+  proc toNano(x: int): TNanos {.inline.} =
+    result = x * 1000
+
+  proc GC_setMaxPause*(MaxPauseInUs: int) =
+    gch.maxPause = MaxPauseInUs.toNano
+
+  proc GC_step(gch: var TGcHeap, us: int, strongAdvice: bool) =
+    acquire(gch)
+    gch.maxPause = us.toNano
+    if (gch.zct.len >= ZctThreshold or (cycleGC and
+        getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or 
+        strongAdvice:
+      collectCTBody(gch)
+    release(gch)
+
+  proc GC_step*(us: int, strongAdvice = false) = GC_step(gch, us, strongAdvice)
+
+when not defined(useNimRtl):
+  proc GC_disable() = 
+    when hasThreadSupport and hasSharedHeap:
+      discard atomicInc(gch.recGcLock, 1)
+    else:
+      inc(gch.recGcLock)
+  proc GC_enable() =
+    if gch.recGcLock > 0: 
+      when hasThreadSupport and hasSharedHeap:
+        discard atomicDec(gch.recGcLock, 1)
+      else:
+        dec(gch.recGcLock)
+
+  proc GC_setStrategy(strategy: GC_Strategy) =
+    case strategy
+    of gcThroughput: discard
+    of gcResponsiveness: discard
+    of gcOptimizeSpace: discard
+    of gcOptimizeTime: discard
+
+  proc GC_enableMarkAndSweep() =
+    gch.cycleThreshold = InitialCycleThreshold
+
+  proc GC_disableMarkAndSweep() =
+    gch.cycleThreshold = high(gch.cycleThreshold)-1
+    # set to the max value to suppress the cycle detector
+
+  proc GC_fullCollect() =
+    setStackTop(gch)
+    acquire(gch)
+    var oldThreshold = gch.cycleThreshold
+    gch.cycleThreshold = 0 # forces cycle collection
+    collectCT(gch)
+    gch.cycleThreshold = oldThreshold
+    release(gch)
+
+  proc GC_getStatistics(): string =
+    GC_disable()
+    result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
+             "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
+             "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
+             "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
+             "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
+             "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
+             "[GC] zct capacity: " & $gch.zct.cap & "\n" &
+             "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
+             "[GC] max stack size: " & $gch.stat.maxStackSize & "\n" &
+             "[GC] max pause time [ms]: " & $(gch.stat.maxPause div 1000_000)
+    when traceGC: writeLeakage(true)
+    GC_enable()
+
+{.pop.}
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
new file mode 100644
index 000000000..a0699f46a
--- /dev/null
+++ b/lib/system/gc_ms.nim
@@ -0,0 +1,605 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# A simple mark&sweep garbage collector for Nim. Define the
+# symbol ``gcUseBitvectors`` to generate a variant of this GC.
+{.push profiler:off.}
+
+const
+  InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow
+  withBitvectors = defined(gcUseBitvectors)
+  # bitvectors are significantly faster for GC-bench, but slower for
+  # bootstrapping and use more memory
+  rcWhite = 0
+  rcGrey = 1   # unused
+  rcBlack = 2
+
+template mulThreshold(x): expr {.immediate.} = x * 2
+
+when defined(memProfiler):
+  proc nimProfile(requestedSize: int)
+
+type
+  TWalkOp = enum
+    waMarkGlobal,  # we need to mark conservatively for global marker procs
+                   # as these may refer to a global var and not to a thread
+                   # local
+    waMarkPrecise  # fast precise marking
+
+  TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
+    # A ref type can have a finalizer that is called before the object's
+    # storage is freed.
+
+  TGlobalMarkerProc = proc () {.nimcall, benign.}
+
+  TGcStat = object
+    collections: int         # number of performed full collections
+    maxThreshold: int        # max threshold that has been set
+    maxStackSize: int        # max stack size
+    freedObjects: int        # max entries in cycle table
+
+  TGcHeap = object           # this contains the zero count and
+                             # non-zero count table
+    stackBottom: pointer
+    cycleThreshold: int
+    when useCellIds:
+      idGenerator: int
+    when withBitvectors:
+      allocated, marked: TCellSet
+    tempStack: TCellSeq      # temporary stack for recursion elimination
+    recGcLock: int           # prevent recursion via finalizers; no thread lock
+    region: TMemRegion       # garbage collected region
+    stat: TGcStat
+    additionalRoots: TCellSeq # dummy roots for GC_ref/unref
+
+var
+  gch {.rtlThreadVar.}: TGcHeap
+
+when not defined(useNimRtl):
+  instantiateForRegion(gch.region)
+
+template acquire(gch: TGcHeap) =
+  when hasThreadSupport and hasSharedHeap:
+    acquireSys(HeapLock)
+
+template release(gch: TGcHeap) =
+  when hasThreadSupport and hasSharedHeap:
+    releaseSys(HeapLock)
+
+template gcAssert(cond: bool, msg: string) =
+  when defined(useGcAssert):
+    if not cond:
+      echo "[GCASSERT] ", msg
+      quit 1
+
+proc cellToUsr(cell: PCell): pointer {.inline.} =
+  # convert object (=pointer to refcount) to pointer to userdata
+  result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell)))
+
+proc usrToCell(usr: pointer): PCell {.inline.} =
+  # convert pointer to userdata to object (=pointer to refcount)
+  result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell)))
+
+proc canbeCycleRoot(c: PCell): bool {.inline.} =
+  result = ntfAcyclic notin c.typ.flags
+
+proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
+  # used for code generation concerning debugging
+  result = usrToCell(c).typ
+
+proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline.} =
+  dest[] = src
+
+proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
+  result = 0
+
+var
+  globalMarkersLen: int
+  globalMarkers: array[0.. 7_000, TGlobalMarkerProc]
+
+proc nimRegisterGlobalMarker(markerProc: TGlobalMarkerProc) {.compilerProc.} =
+  if globalMarkersLen <= high(globalMarkers):
+    globalMarkers[globalMarkersLen] = markerProc
+    inc globalMarkersLen
+  else:
+    echo "[GC] cannot register global variable; too many global variables"
+    quit 1
+
+# this that has to equals zero, otherwise we have to round up UnitsPerPage:
+when BitsPerPage mod (sizeof(int)*8) != 0:
+  {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
+
+# forward declarations:
+proc collectCT(gch: var TGcHeap) {.benign.}
+proc isOnStack*(p: pointer): bool {.noinline, benign.}
+proc forAllChildren(cell: PCell, op: TWalkOp) {.benign.}
+proc doOperation(p: pointer, op: TWalkOp) {.benign.}
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) {.benign.}
+# we need the prototype here for debugging purposes
+
+proc prepareDealloc(cell: PCell) =
+  if cell.typ.finalizer != nil:
+    # the finalizer could invoke something that
+    # allocates memory; this could trigger a garbage
+    # collection. Since we are already collecting we
+    # prevend recursive entering here by a lock.
+    # XXX: we should set the cell's children to nil!
+    inc(gch.recGcLock)
+    (cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
+    dec(gch.recGcLock)
+
+proc nimGCref(p: pointer) {.compilerProc.} =
+  # we keep it from being collected by pretending it's not even allocated:
+  when false:
+    when withBitvectors: excl(gch.allocated, usrToCell(p))
+    else: usrToCell(p).refcount = rcBlack
+  add(gch.additionalRoots, usrToCell(p))
+
+proc nimGCunref(p: pointer) {.compilerProc.} =
+  let cell = usrToCell(p)
+  var L = gch.additionalRoots.len-1
+  var i = L
+  let d = gch.additionalRoots.d
+  while i >= 0:
+    if d[i] == cell:
+      d[i] = d[L]
+      dec gch.additionalRoots.len
+      break
+    dec(i)
+  when false:
+    when withBitvectors: incl(gch.allocated, usrToCell(p))
+    else: usrToCell(p).refcount = rcWhite
+
+proc initGC() =
+  when not defined(useNimRtl):
+    gch.cycleThreshold = InitialThreshold
+    gch.stat.collections = 0
+    gch.stat.maxThreshold = 0
+    gch.stat.maxStackSize = 0
+    init(gch.tempStack)
+    init(gch.additionalRoots)
+    when withBitvectors:
+      init(gch.allocated)
+      init(gch.marked)
+
+var
+  localGcInitialized {.rtlThreadVar.}: bool
+
+proc setupForeignThreadGc*() =
+  ## call this if you registered a callback that will be run from a thread not
+  ## under your control. This has a cheap thread-local guard, so the GC for
+  ## this thread will only be initialized once per thread, no matter how often
+  ## it is called.
+  if not localGcInitialized:
+    localGcInitialized = true
+    var stackTop {.volatile.}: pointer
+    setStackBottom(addr(stackTop))
+    initGC()
+
+proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.benign.} =
+  var d = cast[ByteAddress](dest)
+  case n.kind
+  of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op)
+  of nkList:
+    for i in 0..n.len-1:
+      forAllSlotsAux(dest, n.sons[i], op)
+  of nkCase:
+    var m = selectBranch(dest, n)
+    if m != nil: forAllSlotsAux(dest, m, op)
+  of nkNone: sysAssert(false, "forAllSlotsAux")
+
+proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
+  var d = cast[ByteAddress](dest)
+  if dest == nil: return # nothing to do
+  if ntfNoRefs notin mt.flags:
+    case mt.kind
+    of tyRef, tyString, tySequence: # leaf:
+      doOperation(cast[PPointer](d)[], op)
+    of tyObject, tyTuple:
+      forAllSlotsAux(dest, mt.node, op)
+    of tyArray, tyArrayConstr, tyOpenArray:
+      for i in 0..(mt.size div mt.base.size)-1:
+        forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
+    else: discard
+
+proc forAllChildren(cell: PCell, op: TWalkOp) =
+  gcAssert(cell != nil, "forAllChildren: 1")
+  gcAssert(cell.typ != nil, "forAllChildren: 2")
+  gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
+  let marker = cell.typ.marker
+  if marker != nil:
+    marker(cellToUsr(cell), op.int)
+  else:
+    case cell.typ.kind
+    of tyRef: # common case
+      forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
+    of tySequence:
+      var d = cast[ByteAddress](cellToUsr(cell))
+      var s = cast[PGenericSeq](d)
+      if s != nil:
+        for i in 0..s.len-1:
+          forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
+            GenericSeqSize), cell.typ.base, op)
+    else: discard
+
+proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
+  # generates a new object and sets its reference counter to 0
+  acquire(gch)
+  gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
+  collectCT(gch)
+  var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
+  gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
+  # now it is buffered in the ZCT
+  res.typ = typ
+  when leakDetector and not hasThreadSupport:
+    if framePtr != nil and framePtr.prev != nil:
+      res.filename = framePtr.prev.filename
+      res.line = framePtr.prev.line
+  res.refcount = 0
+  release(gch)
+  when withBitvectors: incl(gch.allocated, res)
+  when useCellIds:
+    inc gch.idGenerator
+    res.id = gch.idGenerator
+  result = cellToUsr(res)
+
+when useCellIds:
+  proc getCellId*[T](x: ref T): int =
+    let p = usrToCell(cast[pointer](x))
+    result = p.id
+
+{.pop.}
+
+proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  # `newObj` already uses locks, so no need for them here.
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObj(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+  when defined(memProfiler): nimProfile(size)
+
+proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
+  result = rawNewObj(typ, size, gch)
+  zeroMem(result, size)
+  when defined(memProfiler): nimProfile(size)
+
+proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
+  let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
+  result = newObj(typ, size)
+  cast[PGenericSeq](result).len = len
+  cast[PGenericSeq](result).reserved = len
+  when defined(memProfiler): nimProfile(size)
+
+proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
+  acquire(gch)
+  collectCT(gch)
+  var ol = usrToCell(old)
+  sysAssert(ol.typ != nil, "growObj: 1")
+  gcAssert(ol.typ.kind in {tyString, tySequence}, "growObj: 2")
+
+  var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(TCell)))
+  var elemSize = 1
+  if ol.typ.kind != tyString: elemSize = ol.typ.base.size
+
+  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+  copyMem(res, ol, oldsize + sizeof(TCell))
+  zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)),
+          newsize-oldsize)
+  sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3")
+  when false:
+    # this is wrong since seqs can be shared via 'shallow':
+    when withBitvectors: excl(gch.allocated, ol)
+    when reallyDealloc: rawDealloc(gch.region, ol)
+    else:
+      zeroMem(ol, sizeof(TCell))
+  when withBitvectors: incl(gch.allocated, res)
+  when useCellIds:
+    inc gch.idGenerator
+    res.id = gch.idGenerator
+  release(gch)
+  result = cellToUsr(res)
+  when defined(memProfiler): nimProfile(newsize-oldsize)
+
+proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
+  result = growObj(old, newsize, gch)
+
+{.push profiler:off.}
+
+# ----------------- collector -----------------------------------------------
+
+proc mark(gch: var TGcHeap, c: PCell) =
+  when withBitvectors:
+    incl(gch.marked, c)
+    gcAssert gch.tempStack.len == 0, "stack not empty!"
+    forAllChildren(c, waMarkPrecise)
+    while gch.tempStack.len > 0:
+      dec gch.tempStack.len
+      var d = gch.tempStack.d[gch.tempStack.len]
+      if not containsOrIncl(gch.marked, d):
+        forAllChildren(d, waMarkPrecise)
+  else:
+    # XXX no 'if c.refCount != rcBlack' here?
+    c.refCount = rcBlack
+    gcAssert gch.tempStack.len == 0, "stack not empty!"
+    forAllChildren(c, waMarkPrecise)
+    while gch.tempStack.len > 0:
+      dec gch.tempStack.len
+      var d = gch.tempStack.d[gch.tempStack.len]
+      if d.refcount == rcWhite:
+        d.refCount = rcBlack
+        forAllChildren(d, waMarkPrecise)
+
+proc doOperation(p: pointer, op: TWalkOp) =
+  if p == nil: return
+  var c: PCell = usrToCell(p)
+  gcAssert(c != nil, "doOperation: 1")
+  case op
+  of waMarkGlobal:
+    when hasThreadSupport:
+      # could point to a cell which we don't own and don't want to touch/trace
+      if isAllocatedPtr(gch.region, c):
+        mark(gch, c)
+    else:
+      mark(gch, c)
+  of waMarkPrecise: add(gch.tempStack, c)
+
+proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
+  doOperation(d, TWalkOp(op))
+
+proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
+  inc gch.stat.freedObjects
+  prepareDealloc(c)
+  when reallyDealloc: rawDealloc(gch.region, c)
+  else:
+    gcAssert(c.typ != nil, "freeCyclicCell")
+    zeroMem(c, sizeof(TCell))
+
+proc sweep(gch: var TGcHeap) =
+  when withBitvectors:
+    for c in gch.allocated.elementsExcept(gch.marked):
+      gch.allocated.excl(c)
+      freeCyclicCell(gch, c)
+  else:
+    for x in allObjects(gch.region):
+      if isCell(x):
+        # cast to PCell is correct here:
+        var c = cast[PCell](x)
+        if c.refcount == rcBlack: c.refcount = rcWhite
+        else: freeCyclicCell(gch, c)
+
+when false:
+  proc newGcInvariant*() =
+    for x in allObjects(gch.region):
+      if isCell(x):
+        var c = cast[PCell](x)
+        if c.typ == nil:
+          writeStackTrace()
+          quit 1
+
+proc markGlobals(gch: var TGcHeap) =
+  for i in 0 .. < globalMarkersLen: globalMarkers[i]()
+  let d = gch.additionalRoots.d
+  for i in 0 .. < gch.additionalRoots.len: mark(gch, d[i])
+
+proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} =
+  # the addresses are not as cells on the stack, so turn them to cells:
+  var cell = usrToCell(p)
+  var c = cast[ByteAddress](cell)
+  if c >% PageSize:
+    # fast check: does it look like a cell?
+    var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
+    if objStart != nil:
+      mark(gch, objStart)
+
+# ----------------- stack management --------------------------------------
+#  inspired from Smart Eiffel
+
+when defined(sparc):
+  const stackIncreases = false
+elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
+     defined(hp9000s700) or defined(hp9000s800) or defined(hp9000s820):
+  const stackIncreases = true
+else:
+  const stackIncreases = false
+
+when not defined(useNimRtl):
+  {.push stack_trace: off.}
+  proc setStackBottom(theStackBottom: pointer) =
+    #c_fprintf(c_stdout, "stack bottom: %p;\n", theStackBottom)
+    # the first init must be the one that defines the stack bottom:
+    if gch.stackBottom == nil: gch.stackBottom = theStackBottom
+    else:
+      var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2
+      var b = cast[ByteAddress](gch.stackBottom)
+      #c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom)
+      when stackIncreases:
+        gch.stackBottom = cast[pointer](min(a, b))
+      else:
+        gch.stackBottom = cast[pointer](max(a, b))
+  {.pop.}
+
+proc stackSize(): int {.noinline.} =
+  var stackTop {.volatile.}: pointer
+  result = abs(cast[int](addr(stackTop)) - cast[int](gch.stackBottom))
+
+when defined(sparc): # For SPARC architecture.
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    when defined(sparcv9):
+      asm  """"flushw \n" """
+    else:
+      asm  """"ta      0x3   ! ST_FLUSH_WINDOWS\n" """
+
+    var
+      max = gch.stackBottom
+      sp: PPointer
+      stackTop: array[0..1, pointer]
+    sp = addr(stackTop[0])
+    # Addresses decrease as the stack grows.
+    while sp <= max:
+      gcMark(gch, sp[])
+      sp = cast[ppointer](cast[ByteAddress](sp) +% sizeof(pointer))
+
+elif defined(ELATE):
+  {.error: "stack marking code is to be written for this architecture".}
+
+elif stackIncreases:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses increase as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var a = cast[ByteAddress](gch.stackBottom)
+    var b = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+
+  var
+    jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
+      # a little hack to get the size of a TJmpBuf in the generated C code
+      # in a platform independent way
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    var registers: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[ByteAddress](gch.stackBottom)
+      var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer)
+      # sp will traverse the JMP_BUF as well (jmp_buf size is added,
+      # otherwise sp would be below the registers structure).
+      while sp >=% max:
+        gcMark(gch, cast[ppointer](sp)[])
+        sp = sp -% sizeof(pointer)
+
+else:
+  # ---------------------------------------------------------------------------
+  # Generic code for architectures where addresses decrease as the stack grows.
+  # ---------------------------------------------------------------------------
+  proc isOnStack(p: pointer): bool =
+    var stackTop {.volatile.}: pointer
+    stackTop = addr(stackTop)
+    var b = cast[ByteAddress](gch.stackBottom)
+    var a = cast[ByteAddress](stackTop)
+    var x = cast[ByteAddress](p)
+    result = a <=% x and x <=% b
+
+  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
+    # We use a jmp_buf buffer that is in the C stack.
+    # Used to traverse the stack and registers assuming
+    # that 'setjmp' will save registers in the C stack.
+    type PStackSlice = ptr array [0..7, pointer]
+    var registers {.noinit.}: C_JmpBuf
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      var max = cast[ByteAddress](gch.stackBottom)
+      var sp = cast[ByteAddress](addr(registers))
+      when defined(amd64):
+        # words within the jmp_buf structure may not be properly aligned.
+        let regEnd = sp +% sizeof(registers)
+        while sp <% regEnd:
+          gcMark(gch, cast[PPointer](sp)[])
+          gcMark(gch, cast[PPointer](sp +% sizeof(pointer) div 2)[])
+          sp = sp +% sizeof(pointer)
+      # Make sure sp is word-aligned
+      sp = sp and not (sizeof(pointer) - 1)
+      # loop unrolled:
+      while sp <% max - 8*sizeof(pointer):
+        gcMark(gch, cast[PStackSlice](sp)[0])
+        gcMark(gch, cast[PStackSlice](sp)[1])
+        gcMark(gch, cast[PStackSlice](sp)[2])
+        gcMark(gch, cast[PStackSlice](sp)[3])
+        gcMark(gch, cast[PStackSlice](sp)[4])
+        gcMark(gch, cast[PStackSlice](sp)[5])
+        gcMark(gch, cast[PStackSlice](sp)[6])
+        gcMark(gch, cast[PStackSlice](sp)[7])
+        sp = sp +% sizeof(pointer)*8
+      # last few entries:
+      while sp <=% max:
+        gcMark(gch, cast[PPointer](sp)[])
+        sp = sp +% sizeof(pointer)
+
+# ----------------------------------------------------------------------------
+# end of non-portable code
+# ----------------------------------------------------------------------------
+
+proc collectCTBody(gch: var TGcHeap) =
+  gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
+  prepareForInteriorPointerChecking(gch.region)
+  markStackAndRegisters(gch)
+  markGlobals(gch)
+  sweep(gch)
+
+  inc(gch.stat.collections)
+  when withBitvectors:
+    deinit(gch.marked)
+    init(gch.marked)
+  gch.cycleThreshold = max(InitialThreshold, getOccupiedMem().mulThreshold)
+  gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
+  sysAssert(allocInv(gch.region), "collectCT: end")
+
+proc collectCT(gch: var TGcHeap) =
+  if getOccupiedMem(gch.region) >= gch.cycleThreshold and gch.recGcLock == 0:
+    collectCTBody(gch)
+
+when not defined(useNimRtl):
+  proc GC_disable() =
+    when hasThreadSupport and hasSharedHeap:
+      atomicInc(gch.recGcLock, 1)
+    else:
+      inc(gch.recGcLock)
+  proc GC_enable() =
+    if gch.recGcLock > 0:
+      when hasThreadSupport and hasSharedHeap:
+        atomicDec(gch.recGcLock, 1)
+      else:
+        dec(gch.recGcLock)
+
+  proc GC_setStrategy(strategy: GC_Strategy) = discard
+
+  proc GC_enableMarkAndSweep() =
+    gch.cycleThreshold = InitialThreshold
+
+  proc GC_disableMarkAndSweep() =
+    gch.cycleThreshold = high(gch.cycleThreshold)-1
+    # set to the max value to suppress the cycle detector
+
+  proc GC_fullCollect() =
+    acquire(gch)
+    var oldThreshold = gch.cycleThreshold
+    gch.cycleThreshold = 0 # forces cycle collection
+    collectCT(gch)
+    gch.cycleThreshold = oldThreshold
+    release(gch)
+
+  proc GC_getStatistics(): string =
+    GC_disable()
+    result = "[GC] total memory: " & $getTotalMem() & "\n" &
+             "[GC] occupied memory: " & $getOccupiedMem() & "\n" &
+             "[GC] collections: " & $gch.stat.collections & "\n" &
+             "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
+             "[GC] freed objects: " & $gch.stat.freedObjects & "\n" &
+             "[GC] max stack size: " & $gch.stat.maxStackSize & "\n"
+    GC_enable()
+
+{.pop.}
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
new file mode 100644
index 000000000..aff0c0e6f
--- /dev/null
+++ b/lib/system/hti.nim
@@ -0,0 +1,92 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+when declared(NimString): 
+  # we are in system module:
+  {.pragma: codegenType, compilerproc.}
+else:
+  {.pragma: codegenType, importc.}
+
+type 
+  # This should be he same as ast.TTypeKind
+  # many enum fields are not used at runtime
+  TNimKind = enum
+    tyNone,
+    tyBool,
+    tyChar,
+    tyEmpty,
+    tyArrayConstr,
+    tyNil,
+    tyExpr,
+    tyStmt,
+    tyTypeDesc,
+    tyGenericInvocation, # ``T[a, b]`` for types to invoke
+    tyGenericBody,       # ``T[a, b, body]`` last parameter is the body
+    tyGenericInst,       # ``T[a, b, realInstance]`` instantiated generic type
+    tyGenericParam,      # ``a`` in the example
+    tyDistinct,          # distinct type
+    tyEnum,
+    tyOrdinal,
+    tyArray,
+    tyObject,
+    tyTuple,             # WARNING: The compiler uses tyTuple for pure objects!
+    tySet,
+    tyRange,
+    tyPtr,
+    tyRef,
+    tyVar,
+    tySequence,
+    tyProc,
+    tyPointer,
+    tyOpenArray,
+    tyString,
+    tyCString,
+    tyForward,
+    tyInt,
+    tyInt8,
+    tyInt16,
+    tyInt32,
+    tyInt64,
+    tyFloat,
+    tyFloat32,
+    tyFloat64,
+    tyFloat128,
+    tyUInt,
+    tyUInt8,
+    tyUInt16,
+    tyUInt32,
+    tyUInt64,
+    tyBigNum,
+
+  TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
+  TNimNode {.codegenType.} = object
+    kind: TNimNodeKind
+    offset: int
+    typ: ptr TNimType
+    name: cstring
+    len: int
+    sons: ptr array [0..0x7fff, ptr TNimNode]
+
+  TNimTypeFlag = enum 
+    ntfNoRefs = 0,     # type contains no tyRef, tySequence, tyString
+    ntfAcyclic = 1,    # type cannot form a cycle
+    ntfEnumHole = 2    # enum has holes and thus `$` for them needs the slow
+                       # version
+  TNimType {.codegenType.} = object
+    size: int
+    kind: TNimKind
+    flags: set[TNimTypeFlag]
+    base: ptr TNimType
+    node: ptr TNimNode # valid for tyRecord, tyObject, tyTuple, tyEnum
+    finalizer: pointer # the finalizer for the type
+    marker: proc (p: pointer, op: int) {.nimcall, benign.} # marker proc for GC
+    deepcopy: proc (p: pointer): pointer {.nimcall, benign.}
+  PNimType = ptr TNimType
+  
+# node.len may be the ``first`` element of a set
diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim
new file mode 100644
index 000000000..dbc961402
--- /dev/null
+++ b/lib/system/inclrtl.nim
@@ -0,0 +1,53 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Pragmas for RTL generation. Has to be an include, because user-defined
+# pragmas cannot be exported.
+
+# There are 3 different usages:
+# 1) Ordinary imported code.
+# 2) Imported from nimrtl.
+#    -> defined(useNimRtl) or appType == "lib" and not defined(createNimRtl)
+# 3) Exported into nimrtl.
+#    -> appType == "lib" and defined(createNimRtl)
+when not defined(nimNewShared):
+  {.pragma: gcsafe.}
+
+when defined(createNimRtl):
+  when defined(useNimRtl): 
+    {.error: "Cannot create and use nimrtl at the same time!".}
+  elif appType != "lib":
+    {.error: "nimrtl must be built as a library!".}
+
+when defined(createNimRtl): 
+  {.pragma: rtl, exportc: "nimrtl_$1", dynlib, gcsafe.}
+  {.pragma: inl.}
+  {.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
+elif defined(useNimRtl):
+  when defined(windows): 
+    const nimrtl* = "nimrtl.dll"
+  elif defined(macosx):
+    const nimrtl* = "nimrtl.dylib"
+  else: 
+    const nimrtl* = "libnimrtl.so"
+  {.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl, gcsafe.}
+  {.pragma: inl.}
+  {.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.}
+else:
+  {.pragma: rtl, gcsafe.}
+  {.pragma: inl, inline.}
+  {.pragma: compilerRtl, compilerproc.}
+
+when not defined(nimsuperops):
+  {.pragma: operator.}
+
+when defined(nimlocks):
+  {.pragma: benign, gcsafe, locks: 0.}
+else:
+  {.pragma: benign, gcsafe.}
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
new file mode 100644
index 000000000..3b55f62ca
--- /dev/null
+++ b/lib/system/jssys.nim
@@ -0,0 +1,730 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+when defined(nodejs):
+  proc alert*(s: cstring) {.importc: "console.log", nodecl.}
+else:
+  proc alert*(s: cstring) {.importc, nodecl.}
+
+proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
+
+type
+  PSafePoint = ptr TSafePoint
+  TSafePoint {.compilerproc, final.} = object
+    prev: PSafePoint # points to next safe point
+    exc: ref Exception
+
+  PCallFrame = ptr TCallFrame
+  TCallFrame {.importc, nodecl, final.} = object
+    prev: PCallFrame
+    procname: cstring
+    line: int # current line number
+    filename: cstring
+
+  PJSError = ref object
+    columnNumber {.importc.}: int
+    fileName {.importc.}: cstring
+    lineNumber {.importc.}: int
+    message {.importc.}: cstring
+    stack {.importc.}: 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
+  lastJSError {.importc, nodecl, volatile.}: PJSError = nil
+
+{.push stacktrace: off, profiler: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 and excHandler.exc != nil:
+    return $excHandler.exc.msg
+  elif lastJSError != nil:
+    return $lastJSError.message
+  else:
+    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 = "Traceback (most recent call last)\n" & auxWriteStackTrace(framePtr)
+    framePtr = nil
+  elif lastJSError != nil:
+    result = $lastJSError.stack
+  else:
+    result = "No stack traceback available\n"
+
+proc raiseException(e: ref Exception, ename: cstring) {.
+    compilerproc, asmNoStackFrame.} =
+  e.name = ename
+  if excHandler != nil:
+    excHandler.exc = e
+  else:
+    when NimStackTrace:
+      var buf = rawWriteStackTrace()
+    else:
+      var buf = ""
+    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() {.compilerproc, asmNoStackFrame.} =
+  if excHandler == nil:
+    raise newException(ReraiseError, "no exception to reraise")
+  else:
+    asm """throw excHandler.exc;"""
+
+proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} =
+  raise newException(OverflowError, "over- or underflow")
+
+proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} =
+  raise newException(DivByZeroError, "division by zero")
+
+proc raiseRangeError() {.compilerproc, noreturn.} =
+  raise newException(RangeError, "value out of range")
+
+proc raiseIndexError() {.compilerproc, noreturn.} =
+  raise newException(IndexError, "index out of bounds")
+
+proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
+  raise newException(FieldError, f & " is not accessible")
+
+proc SetConstr() {.varargs, asmNoStackFrame, 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 {.asmNoStackFrame, 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 toJSStr(s: string): cstring {.asmNoStackFrame, 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 {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = new Array(`len`+1);
+    result[0] = 0;
+    result[`len`] = 0;
+    return result;
+  """
+
+proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
+  # argument type is a fake
+  asm """
+    var result = 0;
+    for (var elem in `a`) { ++result; }
+    return result;
+  """
+
+proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
+  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, asmNoStackFrame.} =
+  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, asmNoStackFrame.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
+
+proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
+  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, asmNoStackFrame.} =
+  asm """
+    var result = {};
+    for (var elem in `a`) {
+      if (!`b`[elem]) { result[elem] = true; }
+    }
+    return result;
+  """
+
+proc cmpStrings(a, b: string): int {.asmNoStackFrame, 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 {.asmNoStackFrame, 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 RootObj
+    write: proc (text: cstring) {.nimcall.}
+    writeln: proc (text: cstring) {.nimcall.}
+    createAttribute: proc (identifier: cstring): ref TNode {.nimcall.}
+    createElement: proc (identifier: cstring): ref TNode {.nimcall.}
+    createTextNode: proc (identifier: cstring): ref TNode {.nimcall.}
+    getElementById: proc (id: cstring): ref TNode {.nimcall.}
+    getElementsByName: proc (name: cstring): seq[ref TNode] {.nimcall.}
+    getElementsByTagName: proc (name: cstring): seq[ref TNode] {.nimcall.}
+
+  TNodeType* = enum
+    ElementNode = 1,
+    AttributeNode,
+    TextNode,
+    CDATANode,
+    EntityRefNode,
+    EntityNode,
+    ProcessingInstructionNode,
+    CommentNode,
+    DocumentNode,
+    DocumentTypeNode,
+    DocumentFragmentNode,
+    NotationNode
+  TNode* {.importc.} = object of RootObj
+    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) {.nimcall.}
+    appendData*: proc (data: cstring) {.nimcall.}
+    cloneNode*: proc (copyContent: bool) {.nimcall.}
+    deleteData*: proc (start, len: int) {.nimcall.}
+    getAttribute*: proc (attr: cstring): cstring {.nimcall.}
+    getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.}
+    getElementsByTagName*: proc (): seq[ref TNode] {.nimcall.}
+    hasChildNodes*: proc (): bool {.nimcall.}
+    insertBefore*: proc (newNode, before: ref TNode) {.nimcall.}
+    insertData*: proc (position: int, data: cstring) {.nimcall.}
+    removeAttribute*: proc (attr: cstring) {.nimcall.}
+    removeAttributeNode*: proc (attr: ref TNode) {.nimcall.}
+    removeChild*: proc (child: ref TNode) {.nimcall.}
+    replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.}
+    replaceData*: proc (start, len: int, text: cstring) {.nimcall.}
+    setAttribute*: proc (name, value: cstring) {.nimcall.}
+    setAttributeNode*: proc (attr: ref TNode) {.nimcall.}
+
+when defined(kwin):
+  proc rawEcho {.compilerproc, asmNoStackFrame.} =
+    asm """
+      var buf = "";
+      for (var i = 0; i < arguments.length; ++i) {
+        buf += `toJSStr`(arguments[i]);
+      }
+      print(buf);
+    """
+
+elif defined(nodejs):
+  proc ewriteln(x: cstring) = log(x)
+
+  proc rawEcho {.compilerproc, asmNoStackFrame.} =
+    asm """
+      var buf = "";
+      for (var i = 0; i < arguments.length; ++i) {
+        buf += `toJSStr`(arguments[i]);
+      }
+      console.log(buf);
+    """
+
+else:
+  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(ValueError, "<body> element does not exist yet!")
+
+  proc rawEcho {.compilerproc.} =
+    var node = document.getElementsByTagName("body")[0]
+    if node == nil:
+      raise newException(IOError, "<body> element does not exist yet!")
+    asm """
+      for (var i = 0; i < arguments.length; ++i) {
+        var x = `toJSStr`(arguments[i]);
+        `node`.appendChild(document.createTextNode(x))
+      }
+    """
+    node.appendChild(document.createElement("br"))
+
+# Arithmetic:
+proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = `a` + `b`;
+    if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
+    return result;
+  """
+
+proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = `a` - `b`;
+    if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
+    return result;
+  """
+
+proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = `a` * `b`;
+    if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
+    return result;
+  """
+
+proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
+    return Math.floor(`a` / `b`);
+  """
+
+proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
+    return Math.floor(`a` % `b`);
+  """
+
+proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = `a` + `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) `raiseOverflow`();
+    return result;
+  """
+
+proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = `a` - `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) `raiseOverflow`();
+    return result;
+  """
+
+proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    var result = `a` * `b`;
+    if (result > 9223372036854775807
+    || result < -9223372036854775808) `raiseOverflow`();
+    return result;
+  """
+
+proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
+    return Math.floor(`a` / `b`);
+  """
+
+proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
+  asm """
+    if (`b` == 0) `raiseDivByZero`();
+    if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
+    return Math.floor(`a` % `b`);
+  """
+
+proc negInt(a: int): int {.compilerproc.} =
+  result = a*(-1)
+
+proc negInt64(a: int64): int64 {.compilerproc.} =
+  result = a*(-1)
+
+proc absInt(a: int): int {.compilerproc.} =
+  result = if a < 0: a*(-1) else: a
+
+proc absInt64(a: int64): int64 {.compilerproc.} =
+  result = if a < 0: a*(-1) else: a
+
+proc leU(a, b: int): bool {.compilerproc.} =
+  result = abs(a) <= abs(b)
+
+proc ltU(a, b: int): bool {.compilerproc.} =
+  result = abs(a) < abs(b)
+
+proc leU64(a, b: int64): bool {.compilerproc.} =
+  result = abs(a) <= abs(b)
+proc ltU64(a, b: int64): bool {.compilerproc.} =
+  result = abs(a) < abs(b)
+
+proc addU(a, b: int): int {.compilerproc.} =
+  result = abs(a) + abs(b)
+proc addU64(a, b: int64): int64 {.compilerproc.} =
+  result = abs(a) + abs(b)
+
+proc subU(a, b: int): int {.compilerproc.} =
+  result = abs(a) - abs(b)
+proc subU64(a, b: int64): int64 {.compilerproc.} =
+  result = abs(a) - abs(b)
+
+proc mulU(a, b: int): int {.compilerproc.} =
+  result = abs(a) * abs(b)
+proc mulU64(a, b: int64): int64 {.compilerproc.} =
+  result = abs(a) * abs(b)
+
+proc divU(a, b: int): int {.compilerproc.} =
+  result = abs(a) div abs(b)
+proc divU64(a, b: int64): int64 {.compilerproc.} =
+  result = abs(a) div abs(b)
+
+proc modU(a, b: int): int {.compilerproc.} =
+  result = abs(a) mod abs(b)
+proc modU64(a, b: int64): int64 {.compilerproc.} =
+  result = abs(a) mod abs(b)
+
+proc ze*(a: int): int {.compilerproc.} =
+  result = a
+
+proc ze64*(a: int64): int64 {.compilerproc.} =
+  result = a
+
+proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} =
+  asm """
+    return `a`;
+  """
+
+proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} =
+  asm """
+    return `a`;
+  """
+
+proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} =
+  asm """
+    return `a`;
+  """
+
+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
+
+type NimString = string # hack for hti.nim
+include "system/hti"
+
+proc isFatPointer(ti: PNimType): bool =
+  # This has to be consistent with the code generator!
+  return ti.base.kind notin {tyObject,
+    tyArray, tyArrayConstr, tyTuple,
+    tyOpenArray, tySet, tyVar, tyRef, tyPtr}
+
+proc nimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
+
+proc nimCopyAux(dest, src: pointer, n: ptr TNimNode) {.compilerproc.} =
+  case n.kind
+  of nkNone: sysAssert(false, "nimCopyAux")
+  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 tySet:
+    asm """
+      `result` = {};
+      for (var key in `x`) { `result`[key] = `x`[key]; }
+    """
+  of 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 """
+      if (`x` !== null) {
+        `result` = `x`.slice(0);
+      }
+    """
+  else:
+    result = x
+
+proc genericReset(x: pointer, ti: PNimType): pointer {.compilerproc.} =
+  case ti.kind
+  of tyPtr, tyRef, tyVar, tyNil:
+    if not isFatPointer(ti):
+      result = nil
+    else:
+      asm """
+        `result` = [null, 0];
+      """
+  of tySet:
+    asm """
+      `result` = {};
+    """
+  of tyTuple, tyObject:
+    if ti.kind == tyObject:
+      asm "`result` = {m_type: `ti`};"
+    else:
+      asm "`result` = {};"
+  of tySequence, tyOpenArray:
+    asm """
+      `result` = [];
+    """
+  of tyArrayConstr, tyArray:
+    asm """
+      `result` = new Array(`x`.length);
+      for (var i = 0; i < `x`.length; ++i) {
+        `result`[i] = genericReset(`x`[i], `ti`.base);
+      }
+    """
+  else:
+    result = nil
+
+proc arrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
+                 asmNoStackFrame, 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(ObjectConversionError, "invalid object conversion")
+    x = x.base
+
+proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
+  # checks if obj is of type subclass:
+  var x = obj
+  if x == subclass: return true # optimized fast path
+  while x != subclass:
+    if x == nil: return false
+    x = x.base
+  return true
+
+proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
+  asm """
+    `x`[`x`.length-1] = `c`; `x`.push(0);
+  """
+
+{.pop.}
+
+proc tenToThePowerOf(b: int): BiggestFloat =
+  var b = b
+  var a = 10.0
+  result = 1.0
+  while true:
+    if (b and 1) == 1:
+      result = result * a
+    b = b shr 1
+    if b == 0: break
+    a = a * a
+
+const
+  IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
+
+# XXX use JS's native way here
+proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {.
+                          compilerProc.} =
+  var
+    esign = 1.0
+    sign = 1.0
+    i = start
+    exponent: int
+    flags: int
+  number = 0.0
+  if s[i] == '+': inc(i)
+  elif s[i] == '-':
+    sign = -1.0
+    inc(i)
+  if s[i] == 'N' or s[i] == 'n':
+    if s[i+1] == 'A' or s[i+1] == 'a':
+      if s[i+2] == 'N' or s[i+2] == 'n':
+        if s[i+3] notin IdentChars:
+          number = NaN
+          return i+3 - start
+    return 0
+  if s[i] == 'I' or s[i] == 'i':
+    if s[i+1] == 'N' or s[i+1] == 'n':
+      if s[i+2] == 'F' or s[i+2] == 'f':
+        if s[i+3] notin IdentChars:
+          number = Inf*sign
+          return i+3 - start
+    return 0
+  while s[i] in {'0'..'9'}:
+    # Read integer part
+    flags = flags or 1
+    number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
+    inc(i)
+    while s[i] == '_': inc(i)
+  # Decimal?
+  if s[i] == '.':
+    var hd = 1.0
+    inc(i)
+    while s[i] in {'0'..'9'}:
+      # Read fractional part
+      flags = flags or 2
+      number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
+      hd = hd * 10.0
+      inc(i)
+      while s[i] == '_': inc(i)
+    number = number / hd # this complicated way preserves precision
+  # Again, read integer and fractional part
+  if flags == 0: return 0
+  # Exponent?
+  if s[i] in {'e', 'E'}:
+    inc(i)
+    if s[i] == '+':
+      inc(i)
+    elif s[i] == '-':
+      esign = -1.0
+      inc(i)
+    if s[i] notin {'0'..'9'}:
+      return 0
+    while s[i] in {'0'..'9'}:
+      exponent = exponent * 10 + ord(s[i]) - ord('0')
+      inc(i)
+      while s[i] == '_': inc(i)
+  # Calculate Exponent
+  let hd = tenToThePowerOf(exponent)
+  if esign > 0.0: number = number * hd
+  else:           number = number / hd
+  # evaluate sign
+  number = number * sign
+  result = i - start
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
new file mode 100644
index 000000000..bdbb3a95a
--- /dev/null
+++ b/lib/system/mmdisp.nim
@@ -0,0 +1,337 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Nim high-level memory manager: It supports Boehm's GC, no GC and the
+# native Nim GC. The native Nim GC is the default.
+
+#{.push checks:on, assertions:on.}
+{.push checks:off.}
+
+const
+  debugGC = false # we wish to debug the GC...
+  logGC = false
+  traceGC = false # extensive debugging
+  alwaysCycleGC = false
+  alwaysGC = defined(fulldebug) # collect after every memory
+                                # allocation (for debugging)
+  leakDetector = false
+  overwriteFree = false
+  trackAllocationSource = leakDetector
+
+  cycleGC = true # (de)activate the cycle GC
+  reallyDealloc = true # for debugging purposes this can be set to false
+  reallyOsDealloc = true
+  coalescRight = true
+  coalescLeft = true
+  logAlloc = false
+  useCellIds = defined(corruption)
+
+type
+  PPointer = ptr pointer
+  TByteArray = array[0..1000_0000, byte]
+  PByte = ptr TByteArray
+  PString = ptr string
+
+# Page size of the system; in most cases 4096 bytes. For exotic OS or
+# CPU this needs to be changed:
+const
+  PageShift = 12
+  PageSize = 1 shl PageShift
+  PageMask = PageSize-1
+
+  MemAlign = 8 # also minimal allocatable memory block
+
+  BitsPerPage = PageSize div MemAlign
+  UnitsPerPage = BitsPerPage div (sizeof(int)*8)
+    # how many ints do we need to describe a page:
+    # on 32 bit systems this is only 16 (!)
+
+  TrunkShift = 9
+  BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64
+  TrunkMask = BitsPerTrunk - 1
+  IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8)
+  IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
+  IntMask = 1 shl IntShift - 1
+
+proc raiseOutOfMem() {.noinline.} =
+  if outOfMemHook != nil: outOfMemHook()
+  echo("out of memory")
+  quit(1)
+
+when defined(boehmgc):
+  when defined(windows):
+    const boehmLib = "boehmgc.dll"
+  elif defined(macosx):
+    const boehmLib = "libgc.dylib"
+  else:
+    const boehmLib = "libgc.so.1"
+
+  proc boehmGCinit {.importc: "GC_init", dynlib: boehmLib.}
+  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.}
+  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.}
+  proc boehmGCincremental {.
+    importc: "GC_enable_incremental", dynlib: boehmLib.}
+  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}
+  proc boehmAlloc(size: int): pointer {.
+    importc: "GC_malloc", dynlib: boehmLib.}
+  proc boehmAllocAtomic(size: int): pointer {.
+    importc: "GC_malloc_atomic", dynlib: boehmLib.}
+  proc boehmRealloc(p: pointer, size: int): pointer {.
+    importc: "GC_realloc", dynlib: boehmLib.}
+  proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
+
+  proc boehmGetHeapSize: int {.importc: "GC_get_heap_size", dynlib: boehmLib.}
+    ## Return the number of bytes in the heap.  Excludes collector private
+    ## data structures. Includes empty blocks and fragmentation loss.
+    ## Includes some pages that were allocated but never written.
+
+  proc boehmGetFreeBytes: int {.importc: "GC_get_free_bytes", dynlib: boehmLib.}
+    ## Return a lower bound on the number of free bytes in the heap.
+
+  proc boehmGetBytesSinceGC: int {.importc: "GC_get_bytes_since_gc",
+    dynlib: boehmLib.}
+    ## Return the number of bytes allocated since the last collection.
+
+  proc boehmGetTotalBytes: int {.importc: "GC_get_total_bytes",
+    dynlib: boehmLib.}
+    ## Return the total number of bytes allocated in this process.
+    ## Never decreases.
+
+  proc allocAtomic(size: int): pointer =
+    result = boehmAllocAtomic(size)
+    zeroMem(result, size)
+
+  when not defined(useNimRtl):
+
+    proc alloc(size: Natural): pointer =
+      result = boehmAlloc(size)
+      if result == nil: raiseOutOfMem()
+    proc alloc0(size: Natural): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc realloc(p: pointer, newsize: Natural): pointer =
+      result = boehmRealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc dealloc(p: pointer) = boehmDealloc(p)
+
+    proc allocShared(size: Natural): pointer =
+      result = boehmAlloc(size)
+      if result == nil: raiseOutOfMem()
+    proc allocShared0(size: Natural): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc reallocShared(p: pointer, newsize: Natural): pointer =
+      result = boehmRealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc deallocShared(p: pointer) = boehmDealloc(p)
+
+    when hasThreadSupport:
+      proc getFreeSharedMem(): int =
+        boehmGetFreeBytes()
+      proc getTotalSharedMem(): int =
+        boehmGetHeapSize()
+      proc getOccupiedSharedMem(): int =
+        getTotalSharedMem() - getFreeSharedMem()
+
+    #boehmGCincremental()
+
+    proc GC_disable() = boehmGC_disable()
+    proc GC_enable() = boehmGC_enable()
+    proc GC_fullCollect() = boehmGCfullCollect()
+    proc GC_setStrategy(strategy: GC_Strategy) = discard
+    proc GC_enableMarkAndSweep() = discard
+    proc GC_disableMarkAndSweep() = discard
+    proc GC_getStatistics(): string = return ""
+
+    proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
+    proc getFreeMem(): int = return boehmGetFreeBytes()
+    proc getTotalMem(): int = return boehmGetHeapSize()
+
+    proc setStackBottom(theStackBottom: pointer) = discard
+
+  proc initGC() =
+    when defined(macosx): boehmGCinit()
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    if ntfNoRefs in typ.flags: result = allocAtomic(size)
+    else: result = alloc(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
+
+  proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
+  type
+    TMemRegion = object {.final, pure.}
+
+  proc alloc(r: var TMemRegion, size: int): pointer =
+    result = boehmAlloc(size)
+    if result == nil: raiseOutOfMem()
+  proc alloc0(r: var TMemRegion, size: int): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+  proc dealloc(r: var TMemRegion, p: pointer) = boehmDealloc(p)
+  proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
+  proc deallocOsPages() {.inline.} = discard
+
+  include "system/cellsets"
+elif defined(nogc) and defined(useMalloc):
+
+  when not defined(useNimRtl):
+    proc alloc(size: Natural): pointer =
+      result = cmalloc(size)
+      if result == nil: raiseOutOfMem()
+    proc alloc0(size: Natural): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc realloc(p: pointer, newsize: Natural): pointer =
+      result = crealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc dealloc(p: pointer) = cfree(p)
+
+    proc allocShared(size: Natural): pointer =
+      result = cmalloc(size)
+      if result == nil: raiseOutOfMem()
+    proc allocShared0(size: Natural): pointer =
+      result = alloc(size)
+      zeroMem(result, size)
+    proc reallocShared(p: pointer, newsize: Natural): pointer =
+      result = crealloc(p, newsize)
+      if result == nil: raiseOutOfMem()
+    proc deallocShared(p: pointer) = cfree(p)
+
+    proc GC_disable() = discard
+    proc GC_enable() = discard
+    proc GC_fullCollect() = discard
+    proc GC_setStrategy(strategy: GC_Strategy) = discard
+    proc GC_enableMarkAndSweep() = discard
+    proc GC_disableMarkAndSweep() = discard
+    proc GC_getStatistics(): string = return ""
+
+    proc getOccupiedMem(): int = discard
+    proc getFreeMem(): int = discard
+    proc getTotalMem(): int = discard
+
+    proc setStackBottom(theStackBottom: pointer) = discard
+
+  proc initGC() = discard
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = alloc(size)
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
+
+  proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
+  type
+    TMemRegion = object {.final, pure.}
+
+  proc alloc(r: var TMemRegion, size: int): pointer =
+    result = alloc(size)
+  proc alloc0(r: var TMemRegion, size: int): pointer =
+    result = alloc0(size)
+  proc dealloc(r: var TMemRegion, p: pointer) = dealloc(p)
+  proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
+  proc deallocOsPages() {.inline.} = discard
+
+elif defined(nogc):
+  # Even though we don't want the GC, we cannot simply use C's memory manager
+  # because Nim's runtime wants ``realloc`` to zero out the additional
+  # space which C's ``realloc`` does not. And we cannot get the old size of an
+  # object, because C does not support this operation... Even though every
+  # possible implementation has to have a way to determine the object's size.
+  # C just sucks.
+  when appType == "lib":
+    {.warning: "nogc in a library context may not work".}
+
+  include "system/alloc"
+
+  proc initGC() = discard
+  proc GC_disable() = discard
+  proc GC_enable() = discard
+  proc GC_fullCollect() = discard
+  proc GC_setStrategy(strategy: GC_Strategy) = discard
+  proc GC_enableMarkAndSweep() = discard
+  proc GC_disableMarkAndSweep() = discard
+  proc GC_getStatistics(): string = return ""
+
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc0(size)
+
+  proc newObjNoInit(typ: PNimType, size: int): pointer =
+    result = alloc(size)
+
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).reserved = len
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc setStackBottom(theStackBottom: pointer) = discard
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
+
+  proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
+    dest[] = src
+
+  var allocator {.rtlThreadVar.}: TMemRegion
+  instantiateForRegion(allocator)
+
+  include "system/cellsets"
+
+else:
+  include "system/alloc"
+
+  include "system/cellsets"
+  when not leakDetector:
+    sysAssert(sizeof(TCell) == sizeof(TFreeCell), "sizeof TFreeCell")
+  when compileOption("gc", "v2"):
+    include "system/gc2"
+  elif defined(gcMarkAndSweep):
+    # XXX use 'compileOption' here
+    include "system/gc_ms"
+  elif defined(gcGenerational):
+    include "system/gc"
+  else:
+    include "system/gc"
+
+{.pop.}
diff --git a/lib/system/platforms.nim b/lib/system/platforms.nim
new file mode 100644
index 000000000..47a01d5fe
--- /dev/null
+++ b/lib/system/platforms.nim
@@ -0,0 +1,74 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Platform detection for Nim. This module is included by the system module!
+## Do not import it directly!
+
+type
+  CpuPlatform* {.pure.} = enum ## the CPU this program will run on.
+    none,                      ## unknown CPU
+    i386,                      ## 32 bit x86 compatible CPU
+    m68k,                      ## M68k based processor
+    alpha,                     ## Alpha processor
+    powerpc,                   ## 32 bit PowerPC
+    powerpc64,                 ## 64 bit PowerPC
+    sparc,                     ## Sparc based processor
+    ia64,                      ## Intel Itanium
+    amd64,                     ## x86_64 (AMD64); 64 bit x86 compatible CPU
+    mips,                      ## Mips based processor
+    arm,                       ## ARM based processor
+    vm,                        ## Some Virtual machine: Nim's VM or JavaScript
+    avr                        ## AVR based processor
+
+  OsPlatform* {.pure.} = enum ## the OS this program will run on.
+    none, dos, windows, os2, linux, morphos, skyos, solaris,
+    irix, netbsd, freebsd, openbsd, aix, palmos, qnx, amiga,
+    atari, netware, macos, macosx, haiku, js, nimVM, standalone
+
+const
+  targetOS* = when defined(windows): OsPlatform.windows
+              elif defined(dos): OsPlatform.dos
+              elif defined(os2): OsPlatform.os2
+              elif defined(linux): OsPlatform.linux
+              elif defined(morphos): OsPlatform.morphos
+              elif defined(skyos): OsPlatform.skyos
+              elif defined(solaris): OsPlatform.solaris
+              elif defined(irix): OsPlatform.irix
+              elif defined(netbsd): OsPlatform.netbsd
+              elif defined(freebsd): OsPlatform.freebsd
+              elif defined(openbsd): OsPlatform.openbsd
+              elif defined(aix): OsPlatform.aix
+              elif defined(palmos): OsPlatform.palmos
+              elif defined(qnx): OsPlatform.qnx
+              elif defined(amiga): OsPlatform.amiga
+              elif defined(atari): OsPlatform.atari
+              elif defined(netware): OsPlatform.netware
+              elif defined(macosx): OsPlatform.macosx
+              elif defined(macos): OsPlatform.macos
+              elif defined(haiku): OsPlatform.haiku
+              elif defined(js): OsPlatform.js
+              elif defined(nimrodVM): OsPlatform.nimVM
+              elif defined(standalone): OsPlatform.standalone
+              else: OsPlatform.none
+    ## the OS this program will run on.
+
+  targetCPU* = when defined(i386): CpuPlatform.i386
+               elif defined(m68k): CpuPlatform.m68k
+               elif defined(alpha): CpuPlatform.alpha
+               elif defined(powerpc): CpuPlatform.powerpc
+               elif defined(powerpc64): CpuPlatform.powerpc64
+               elif defined(sparc): CpuPlatform.sparc
+               elif defined(ia64): CpuPlatform.ia64
+               elif defined(amd64): CpuPlatform.amd64
+               elif defined(mips): CpuPlatform.mips
+               elif defined(arm): CpuPlatform.arm
+               elif defined(vm): CpuPlatform.vm
+               elif defined(avr): CpuPlatform.avr
+               else: CpuPlatform.none
+    ## the CPU this program will run on.
diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim
new file mode 100644
index 000000000..6d6863caa
--- /dev/null
+++ b/lib/system/profiler.nim
@@ -0,0 +1,99 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# This file implements the Nim profiler. The profiler needs support by the
+# code generator. The idea is to inject the instruction stream
+# with 'nimProfile()' calls. These calls are injected at every loop end
+# (except perhaps loops that have no side-effects). At every Nth call a
+# stack trace is taken. A stack tace is a list of cstrings.
+
+{.push profiler: off.}
+
+const
+  MaxTraceLen = 20 # tracking the last 20 calls is enough
+
+type
+  TStackTrace* = array [0..MaxTraceLen-1, cstring]
+  TProfilerHook* = proc (st: TStackTrace) {.nimcall.}
+
+proc captureStackTrace(f: PFrame, st: var TStackTrace) =
+  const
+    firstCalls = 5
+  var
+    it = f
+    i = 0
+    total = 0
+  while it != nil and i <= high(st)-(firstCalls-1):
+    # the (-1) is for the "..." entry
+    st[i] = it.procname
+    inc(i)
+    inc(total)
+    it = it.prev
+  var b = it
+  while it != nil:
+    inc(total)
+    it = it.prev
+  for j in 1..total-i-(firstCalls-1): 
+    if b != nil: b = b.prev
+  if total != i:
+    st[i] = "..."
+    inc(i)
+  while b != nil and i <= high(st):
+    st[i] = b.procname
+    inc(i)
+    b = b.prev
+
+when defined(memProfiler):
+  type
+    TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall, benign.}
+  var
+    profilerHook*: TMemProfilerHook
+      ## set this variable to provide a procedure that implements a profiler in
+      ## user space. See the `nimprof` module for a reference implementation.
+
+  proc callProfilerHook(hook: TMemProfilerHook, requestedSize: int) =
+    var st: TStackTrace
+    captureStackTrace(framePtr, st)
+    hook(st, requestedSize)
+
+  proc nimProfile(requestedSize: int) =
+    if not isNil(profilerHook):
+      callProfilerHook(profilerHook, requestedSize)
+else:
+  const
+    SamplingInterval = 50_000
+      # set this to change the default sampling interval
+  var
+    profilerHook*: TProfilerHook
+      ## set this variable to provide a procedure that implements a profiler in
+      ## user space. See the `nimprof` module for a reference implementation.
+    gTicker {.threadvar.}: int
+
+  proc callProfilerHook(hook: TProfilerHook) {.noinline.} =
+    # 'noinline' so that 'nimProfile' does not perform the stack allocation
+    # in the common case.
+    var st: TStackTrace
+    captureStackTrace(framePtr, st)
+    hook(st)
+
+  proc nimProfile() =
+    ## This is invoked by the compiler in every loop and on every proc entry!
+    if gTicker == 0:
+      gTicker = -1
+      if not isNil(profilerHook):
+        # disable recursive calls: XXX should use try..finally,
+        # but that's too expensive!
+        let oldHook = profilerHook
+        profilerHook = nil
+        callProfilerHook(oldHook)
+        profilerHook = oldHook
+      gTicker = SamplingInterval
+    dec gTicker
+
+{.pop.}
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
new file mode 100644
index 000000000..f1029ff6a
--- /dev/null
+++ b/lib/system/repr.nim
@@ -0,0 +1,287 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# The generic ``repr`` procedure. It is an invaluable debugging tool.
+
+when not defined(useNimRtl):
+  proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl, gcsafe.}
+
+proc reprInt(x: int64): string {.compilerproc.} = return $x
+proc reprFloat(x: float): string {.compilerproc.} = return $x
+
+proc reprPointer(x: pointer): string {.compilerproc.} =
+  var buf: array [0..59, char]
+  discard c_sprintf(buf, "%p", x)
+  return $buf
+
+proc `$`(x: uint64): string =
+  var buf: array [0..59, char]
+  discard c_sprintf(buf, "%llu", x)
+  return $buf
+
+proc reprStrAux(result: var string, s: string) =
+  if cast[pointer](s) == nil:
+    add result, "nil"
+    return
+  add result, reprPointer(cast[pointer](s)) & "\""
+  for i in 0.. <s.len:
+    let c = s[i]
+    case c
+    of '"': add result, "\\\""
+    of '\\': add result, "\\\\" # BUGFIX: forgotten
+    of '\10': add result, "\\10\"\n\"" # " \n " # better readability
+    of '\128' .. '\255', '\0'..'\9', '\11'..'\31':
+      add result, "\\" & reprInt(ord(c))
+    else:
+      result.add(c)
+  add result, "\""
+
+proc reprStr(s: string): string {.compilerRtl.} =
+  result = ""
+  reprStrAux(result, s)
+
+proc reprBool(x: bool): string {.compilerRtl.} =
+  if x: result = "true"
+  else: result = "false"
+
+proc reprChar(x: char): string {.compilerRtl.} =
+  result = "\'"
+  case x
+  of '"': add result, "\\\""
+  of '\\': add result, "\\\\"
+  of '\128' .. '\255', '\0'..'\31': add result, "\\" & reprInt(ord(x))
+  else: add result, x
+  add result, "\'"
+
+proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
+  # we read an 'int' but this may have been too large, so mask the other bits:
+  let e = if typ.size == 1: e and 0xff
+          elif typ.size == 2: e and 0xffff
+          else: e
+  # XXX we need a proper narrowing based on signedness here
+  #e and ((1 shl (typ.size*8)) - 1)
+  if ntfEnumHole notin typ.flags:
+    if e <% typ.node.len:
+      return $typ.node.sons[e].name
+  else:
+    # ugh we need a slow linear search:
+    var n = typ.node
+    var s = n.sons
+    for i in 0 .. n.len-1:
+      if s[i].offset == e: return $s[i].name
+  result = $e & " (invalid data!)"
+
+type
+  PByteArray = ptr array[0.. 0xffff, int8]
+
+proc addSetElem(result: var string, elem: int, typ: PNimType) {.benign.} =
+  case typ.kind
+  of tyEnum: add result, reprEnum(elem, typ)
+  of tyBool: add result, reprBool(bool(elem))
+  of tyChar: add result, reprChar(chr(elem))
+  of tyRange: addSetElem(result, elem, typ.base)
+  of tyInt..tyInt64, tyUInt8, tyUInt16: add result, reprInt(elem)
+  else: # data corrupt --> inform the user
+    add result, " (invalid data!)"
+
+proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
+  # "typ.slots.len" field is for sets the "first" field
+  var elemCounter = 0  # we need this flag for adding the comma at
+                       # the right places
+  add result, "{"
+  var u: int64
+  case typ.size
+  of 1: u = ze64(cast[ptr int8](p)[])
+  of 2: u = ze64(cast[ptr int16](p)[])
+  of 4: u = ze64(cast[ptr int32](p)[])
+  of 8: u = cast[ptr int64](p)[]
+  else:
+    var a = cast[PByteArray](p)
+    for i in 0 .. typ.size*8-1:
+      if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
+        if elemCounter > 0: add result, ", "
+        addSetElem(result, i+typ.node.len, typ.base)
+        inc(elemCounter)
+  if typ.size <= 8:
+    for i in 0..sizeof(int64)*8-1:
+      if (u and (1'i64 shl int64(i))) != 0'i64:
+        if elemCounter > 0: add result, ", "
+        addSetElem(result, i+typ.node.len, typ.base)
+        inc(elemCounter)
+  add result, "}"
+
+proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
+  result = ""
+  reprSetAux(result, p, typ)
+
+type
+  TReprClosure {.final.} = object # we cannot use a global variable here
+                                  # as this wouldn't be thread-safe
+    when declared(TCellSet):
+      marked: TCellSet
+    recdepth: int       # do not recurse endlessly
+    indent: int         # indentation
+
+when not defined(useNimRtl):
+  proc initReprClosure(cl: var TReprClosure) =
+    # Important: cellsets does not lock the heap when doing allocations! We
+    # have to do it here ...
+    when hasThreadSupport and hasSharedHeap and declared(heapLock):
+      AcquireSys(HeapLock)
+    when declared(TCellSet):
+      init(cl.marked)
+    cl.recdepth = -1      # default is to display everything!
+    cl.indent = 0
+
+  proc deinitReprClosure(cl: var TReprClosure) =
+    when declared(TCellSet): deinit(cl.marked)
+    when hasThreadSupport and hasSharedHeap and declared(heapLock): 
+      ReleaseSys(HeapLock)
+
+  proc reprBreak(result: var string, cl: TReprClosure) =
+    add result, "\n"
+    for i in 0..cl.indent-1: add result, ' '
+
+  proc reprAux(result: var string, p: pointer, typ: PNimType,
+               cl: var TReprClosure) {.benign.}
+
+  proc reprArray(result: var string, p: pointer, typ: PNimType,
+                 cl: var TReprClosure) =
+    add result, "["
+    var bs = typ.base.size
+    for i in 0..typ.size div bs - 1:
+      if i > 0: add result, ", "
+      reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), typ.base, cl)
+    add result, "]"
+
+  proc reprSequence(result: var string, p: pointer, typ: PNimType,
+                    cl: var TReprClosure) =
+    if p == nil:
+      add result, "nil"
+      return
+    result.add(reprPointer(p) & "[")
+    var bs = typ.base.size
+    for i in 0..cast[PGenericSeq](p).len-1:
+      if i > 0: add result, ", "
+      reprAux(result, cast[pointer](cast[ByteAddress](p) + GenericSeqSize + i*bs),
+              typ.base, cl)
+    add result, "]"
+
+  proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
+                     cl: var TReprClosure) {.benign.} =
+    case n.kind
+    of nkNone: sysAssert(false, "reprRecordAux")
+    of nkSlot:
+      add result, $n.name
+      add result, " = "
+      reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl)
+    of nkList:
+      for i in 0..n.len-1:
+        if i > 0: add result, ",\n"
+        reprRecordAux(result, p, n.sons[i], cl)
+    of nkCase:
+      var m = selectBranch(p, n)
+      reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl)
+      if m != nil: reprRecordAux(result, p, m, cl)
+
+  proc reprRecord(result: var string, p: pointer, typ: PNimType,
+                  cl: var TReprClosure) =
+    add result, "["
+    let oldLen = result.len
+    reprRecordAux(result, p, typ.node, cl)
+    if typ.base != nil: 
+      if oldLen != result.len: add result, ",\n"
+      reprRecordAux(result, p, typ.base.node, cl)
+    add result, "]"
+
+  proc reprRef(result: var string, p: pointer, typ: PNimType,
+               cl: var TReprClosure) =
+    # we know that p is not nil here:
+    when declared(TCellSet):
+      when defined(boehmGC) or defined(nogc):
+        var cell = cast[PCell](p)
+      else:
+        var cell = usrToCell(p)
+      add result, "ref " & reprPointer(p)
+      if cell notin cl.marked:
+        # only the address is shown:
+        incl(cl.marked, cell)
+        add result, " --> "
+        reprAux(result, p, typ.base, cl)
+
+  proc reprAux(result: var string, p: pointer, typ: PNimType,
+               cl: var TReprClosure) =
+    if cl.recdepth == 0:
+      add result, "..."
+      return
+    dec(cl.recdepth)
+    case typ.kind
+    of tySet: reprSetAux(result, p, typ)
+    of tyArray, tyArrayConstr: reprArray(result, p, typ, cl)
+    of tyTuple: reprRecord(result, p, typ, cl)
+    of tyObject: 
+      var t = cast[ptr PNimType](p)[]
+      reprRecord(result, p, t, cl)
+    of tyRef, tyPtr:
+      sysAssert(p != nil, "reprAux")
+      if cast[PPointer](p)[] == nil: add result, "nil"
+      else: reprRef(result, cast[PPointer](p)[], typ, cl)
+    of tySequence:
+      reprSequence(result, cast[PPointer](p)[], typ, cl)
+    of tyInt: add result, $(cast[ptr int](p)[])
+    of tyInt8: add result, $int(cast[ptr int8](p)[])
+    of tyInt16: add result, $int(cast[ptr int16](p)[])
+    of tyInt32: add result, $int(cast[ptr int32](p)[])
+    of tyInt64: add result, $(cast[ptr int64](p)[])
+    of tyUInt8: add result, $ze(cast[ptr int8](p)[])
+    of tyUInt16: add result, $ze(cast[ptr int16](p)[])
+    
+    of tyFloat: add result, $(cast[ptr float](p)[])
+    of tyFloat32: add result, $(cast[ptr float32](p)[])
+    of tyFloat64: add result, $(cast[ptr float64](p)[])
+    of tyEnum: add result, reprEnum(cast[ptr int](p)[], typ)
+    of tyBool: add result, reprBool(cast[ptr bool](p)[])
+    of tyChar: add result, reprChar(cast[ptr char](p)[])
+    of tyString: reprStrAux(result, cast[ptr string](p)[])
+    of tyCString: reprStrAux(result, $(cast[ptr cstring](p)[]))
+    of tyRange: reprAux(result, p, typ.base, cl)
+    of tyProc, tyPointer:
+      if cast[PPointer](p)[] == nil: add result, "nil"
+      else: add result, reprPointer(cast[PPointer](p)[])
+    else:
+      add result, "(invalid data!)"
+    inc(cl.recdepth)
+
+proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
+                   compilerRtl.} =
+  var
+    cl: TReprClosure
+  initReprClosure(cl)
+  result = "["
+  var bs = elemtyp.size
+  for i in 0..length - 1:
+    if i > 0: add result, ", "
+    reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), elemtyp, cl)
+  add result, "]"
+  deinitReprClosure(cl)
+
+when not defined(useNimRtl):
+  proc reprAny(p: pointer, typ: PNimType): string =
+    var
+      cl: TReprClosure
+    initReprClosure(cl)
+    result = ""
+    if typ.kind in {tyObject, tyTuple, tyArray, tyArrayConstr, tySet}:
+      reprAux(result, p, typ, cl)
+    else:
+      var p = p
+      reprAux(result, addr(p), typ, cl)
+    add result, "\n"
+    deinitReprClosure(cl)
+
diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim
new file mode 100644
index 000000000..57237cfff
--- /dev/null
+++ b/lib/system/reprjs.nim
@@ -0,0 +1,23 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+proc reprInt(x: int64): string {.compilerproc.} = return $x
+
+proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
+  if ntfEnumHole notin typ.flags:
+    if e <% typ.node.len:
+      return $typ.node.sons[e].name
+  else:
+    # ugh we need a slow linear search:
+    var n = typ.node
+    var s = n.sons
+    for i in 0 .. n.len-1:
+      if s[i].offset == e: return $s[i].name
+  result = $e & " (invalid data!)"
+
diff --git a/lib/system/sets.nim b/lib/system/sets.nim
new file mode 100644
index 000000000..626d43c33
--- /dev/null
+++ b/lib/system/sets.nim
@@ -0,0 +1,28 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# set handling
+
+type
+  TNimSet = array [0..4*2048-1, uint8]
+
+proc countBits32(n: int32): int {.compilerproc.} =
+  var v = n
+  v = v -% ((v shr 1'i32) and 0x55555555'i32)
+  v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32)
+  result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32
+
+proc countBits64(n: int64): int {.compilerproc.} = 
+  result = countBits32(toU32(n and 0xffff'i64)) +
+           countBits32(toU32(n shr 16'i64))
+
+proc cardSet(s: TNimSet, len: int): int {.compilerproc.} =
+  result = 0
+  for i in countup(0, len-1):
+    inc(result, countBits32(int32(s[i])))
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
new file mode 100644
index 000000000..3f860655e
--- /dev/null
+++ b/lib/system/sysio.nim
@@ -0,0 +1,321 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+# Nim's standard IO library. It contains high-performance
+# routines for reading and writing data to (buffered) files or
+# TTYs.
+
+{.push debugger:off .} # the user does not want to trace a part
+                       # of the standard library!
+
+
+proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>",
+  tags: [WriteIOEffect].}
+proc fgets(c: cstring, n: int, f: File): cstring {.
+  importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
+proc fgetc(stream: File): cint {.importc: "fgetc", header: "<stdio.h>",
+  tags: [ReadIOEffect].}
+proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "<stdio.h>",
+  tags: [].}
+proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>",
+  tags: [WriteIOEffect].}
+proc fprintf(f: File, frmt: cstring) {.importc: "fprintf",
+  header: "<stdio.h>", varargs, tags: [WriteIOEffect].}
+proc strlen(c: cstring): int {.
+  importc: "strlen", header: "<string.h>", tags: [].}
+
+when defined(posix):
+  proc getc_unlocked(stream: File): cint {.importc: "getc_unlocked",
+    header: "<stdio.h>", tags: [ReadIOEffect].}
+
+  proc flockfile(stream: File) {.importc: "flockfile", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+
+  proc funlockfile(stream: File) {.importc: "funlockfile", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+elif false:
+  # doesn't work on Windows yet:
+  proc getc_unlocked(stream: File): cint {.importc: "_fgetc_nolock",
+    header: "<stdio.h>", tags: [ReadIOEffect].}
+
+  proc flockfile(stream: File) {.importc: "_lock_file", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+
+  proc funlockfile(stream: File) {.importc: "_unlock_file", header: "<stdio.h>",
+    tags: [ReadIOEffect].}
+
+# C routine that is used here:
+proc fread(buf: pointer, size, n: int, f: File): int {.
+  importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
+proc fseek(f: File, offset: clong, whence: int): int {.
+  importc: "fseek", header: "<stdio.h>", tags: [].}
+proc ftell(f: File): int {.importc: "ftell", header: "<stdio.h>", tags: [].}
+proc setvbuf(stream: File, buf: pointer, typ, size: cint): cint {.
+  importc, header: "<stdio.h>", tags: [].}
+
+{.push stackTrace:off, profiler:off.}
+proc write(f: File, c: cstring) = fputs(c, f)
+{.pop.}
+
+when NoFakeVars:
+  when defined(windows):
+    const
+      IOFBF = cint(0)
+      IONBF = cint(4)
+  elif defined(macosx) or defined(linux):
+    const
+      IOFBF = cint(0)
+      IONBF = cint(2)
+  else:
+    {.error: "IOFBF not ported to your platform".}
+else:
+  var
+    IOFBF {.importc: "_IOFBF", nodecl.}: cint
+    IONBF {.importc: "_IONBF", nodecl.}: cint
+
+const
+  BufSize = 4000
+
+proc raiseEIO(msg: string) {.noinline, noreturn.} =
+  sysFatal(IOError, msg)
+
+when declared(getc_unlocked):
+  proc readLine(f: File, line: var TaintedString): bool =
+    setLen(line.string, 0) # reuse the buffer!
+    flockfile(f)
+    while true:
+      var c = getc_unlocked(f)
+      if c < 0'i32:
+        if line.len > 0: break
+        else: return false
+      if c == 10'i32: break # LF
+      if c == 13'i32:  # CR
+        c = getc_unlocked(f) # is the next char LF?
+        if c != 10'i32: ungetc(c, f) # no, put the character back
+        break
+      add line.string, chr(int(c))
+    result = true
+    funlockfile(f)
+else:
+  proc readLine(f: File, line: var TaintedString): bool =
+    # of course this could be optimized a bit; but IO is slow anyway...
+    # and it was difficult to get this CORRECT with Ansi C's methods
+    setLen(line.string, 0) # reuse the buffer!
+    while true:
+      var c = fgetc(f)
+      if c < 0'i32:
+        if line.len > 0: break
+        else: return false
+      if c == 10'i32: break # LF
+      if c == 13'i32:  # CR
+        c = fgetc(f) # is the next char LF?
+        if c != 10'i32: ungetc(c, f) # no, put the character back
+        break
+      add line.string, chr(int(c))
+    result = true
+
+proc readLine(f: File): TaintedString =
+  result = TaintedString(newStringOfCap(80))
+  if not readLine(f, result): raiseEIO("EOF reached")
+
+proc write(f: File, i: int) =
+  when sizeof(int) == 8:
+    fprintf(f, "%lld", i)
+  else:
+    fprintf(f, "%ld", i)
+
+proc write(f: File, i: BiggestInt) =
+  when sizeof(BiggestInt) == 8:
+    fprintf(f, "%lld", i)
+  else:
+    fprintf(f, "%ld", i)
+
+proc write(f: File, b: bool) =
+  if b: write(f, "true")
+  else: write(f, "false")
+proc write(f: File, r: float32) = fprintf(f, "%g", r)
+proc write(f: File, r: BiggestFloat) = fprintf(f, "%g", r)
+
+proc write(f: File, c: char) = putc(c, f)
+proc write(f: File, a: varargs[string, `$`]) =
+  for x in items(a): write(f, x)
+
+proc readAllBuffer(file: File): string =
+  # This proc is for File we want to read but don't know how many
+  # bytes we need to read before the buffer is empty.
+  result = ""
+  var buffer = newString(BufSize)
+  while true:
+    var bytesRead = readBuffer(file, addr(buffer[0]), BufSize)
+    if bytesRead == BufSize:
+      result.add(buffer)
+    else:
+      buffer.setLen(bytesRead)
+      result.add(buffer)
+      break
+
+proc rawFileSize(file: File): int =
+  # this does not raise an error opposed to `getFileSize`
+  var oldPos = ftell(file)
+  discard fseek(file, 0, 2) # seek the end of the file
+  result = ftell(file)
+  discard fseek(file, clong(oldPos), 0)
+
+proc readAllFile(file: File, len: int): string =
+  # We acquire the filesize beforehand and hope it doesn't change.
+  # Speeds things up.
+  result = newString(int(len))
+  if readBuffer(file, addr(result[0]), int(len)) != len:
+    raiseEIO("error while reading from file")
+
+proc readAllFile(file: File): string =
+  var len = rawFileSize(file)
+  result = readAllFile(file, len)
+
+proc readAll(file: File): TaintedString =
+  # Separate handling needed because we need to buffer when we
+  # don't know the overall length of the File.
+  let len = if file != stdin: rawFileSize(file) else: -1
+  if len > 0:
+    result = readAllFile(file, len).TaintedString
+  else:
+    result = readAllBuffer(file).TaintedString
+
+proc readFile(filename: string): TaintedString =
+  var f = open(filename)
+  try:
+    result = readAll(f).TaintedString
+  finally:
+    close(f)
+
+proc writeFile(filename, content: string) =
+  var f = open(filename, fmWrite)
+  try:
+    f.write(content)
+  finally:
+    close(f)
+
+proc endOfFile(f: File): bool =
+  # do not blame me; blame the ANSI C standard this is so brain-damaged
+  var c = fgetc(f)
+  ungetc(c, f)
+  return c < 0'i32
+
+proc writeln[Ty](f: File, x: varargs[Ty, `$`]) =
+  for i in items(x): write(f, i)
+  write(f, "\n")
+
+proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x)
+proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
+
+# interface to the C procs:
+
+when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc):
+  include "system/widestrs"
+
+when defined(windows) and not defined(useWinAnsi):
+  when defined(cpp):
+    proc wfopen(filename, mode: WideCString): pointer {.
+      importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.}
+    proc wfreopen(filename, mode: WideCString, stream: File): File {.
+      importcpp: "_wfreopen((const wchar_t*)#, (const wchar_t*)#, #)", nodecl.}
+  else:
+    proc wfopen(filename, mode: WideCString): pointer {.
+      importc: "_wfopen", nodecl.}
+    proc wfreopen(filename, mode: WideCString, stream: File): File {.
+      importc: "_wfreopen", nodecl.}
+
+  proc fopen(filename, mode: cstring): pointer =
+    var f = newWideCString(filename)
+    var m = newWideCString(mode)
+    result = wfopen(f, m)
+
+  proc freopen(filename, mode: cstring, stream: File): File =
+    var f = newWideCString(filename)
+    var m = newWideCString(mode)
+    result = wfreopen(f, m, stream)
+
+else:
+  proc fopen(filename, mode: cstring): pointer {.importc: "fopen", noDecl.}
+  proc freopen(filename, mode: cstring, stream: File): File {.
+    importc: "freopen", nodecl.}
+
+const
+  FormatOpen: array [FileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"]
+    #"rt", "wt", "w+t", "r+t", "at"
+    # we always use binary here as for Nim the OS line ending
+    # should not be translated.
+
+
+proc open(f: var File, filename: string,
+          mode: FileMode = fmRead,
+          bufSize: int = -1): bool =
+  var p: pointer = fopen(filename, FormatOpen[mode])
+  if p != nil:
+    result = true
+    f = cast[File](p)
+    if bufSize > 0 and bufSize <= high(cint).int:
+      discard setvbuf(f, nil, IOFBF, bufSize.cint)
+    elif bufSize == 0:
+      discard setvbuf(f, nil, IONBF, 0)
+
+proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
+  var p: pointer = freopen(filename, FormatOpen[mode], f)
+  result = p != nil
+
+proc fdopen(filehandle: FileHandle, mode: cstring): File {.
+  importc: pccHack & "fdopen", header: "<stdio.h>".}
+
+proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
+  f = fdopen(filehandle, FormatOpen[mode])
+  result = f != nil
+
+proc fwrite(buf: pointer, size, n: int, f: File): int {.
+  importc: "fwrite", noDecl.}
+
+proc readBuffer(f: File, buffer: pointer, len: Natural): int =
+  result = fread(buffer, 1, len, f)
+
+proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
+  result = readBuffer(f, addr(a[start]), len)
+
+proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
+  result = readBuffer(f, addr(a[start]), len)
+
+{.push stackTrace:off, profiler:off.}
+proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
+  var x = cast[ptr array[0..1000_000_000, int8]](a)
+  result = writeBuffer(f, addr(x[start]), len)
+proc writeChars(f: File, a: openArray[char], start, len: Natural): int =
+  var x = cast[ptr array[0..1000_000_000, int8]](a)
+  result = writeBuffer(f, addr(x[start]), len)
+proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
+  result = fwrite(buffer, 1, len, f)
+
+proc write(f: File, s: string) =
+  if writeBuffer(f, cstring(s), s.len) != s.len:
+    raiseEIO("cannot write string to file")
+{.pop.}
+
+proc setFilePos(f: File, pos: int64) =
+  if fseek(f, clong(pos), 0) != 0:
+    raiseEIO("cannot set file position")
+
+proc getFilePos(f: File): int64 =
+  result = ftell(f)
+  if result < 0: raiseEIO("cannot retrieve file position")
+
+proc getFileSize(f: File): int64 =
+  var oldPos = getFilePos(f)
+  discard fseek(f, 0, 2) # seek the end of the file
+  result = getFilePos(f)
+  setFilePos(f, oldPos)
+
+{.pop.}
diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim
new file mode 100644
index 000000000..8b38f34f3
--- /dev/null
+++ b/lib/system/syslocks.nim
@@ -0,0 +1,104 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Low level system locks and condition vars.
+
+when defined(Windows):
+  type
+    THandle = int
+    TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
+      DebugInfo: pointer
+      LockCount: int32
+      RecursionCount: int32
+      OwningThread: int
+      LockSemaphore: int
+      Reserved: int32
+
+    TSysCond = THandle
+          
+  proc initSysLock(L: var TSysLock) {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "InitializeCriticalSection".}
+    ## Initializes the lock `L`.
+
+  proc tryAcquireSysAux(L: var TSysLock): int32 {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "TryEnterCriticalSection".}
+    ## Tries to acquire the lock `L`.
+    
+  proc tryAcquireSys(L: var TSysLock): bool {.inline.} = 
+    result = tryAcquireSysAux(L) != 0'i32
+
+  proc acquireSys(L: var TSysLock) {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "EnterCriticalSection".}
+    ## Acquires the lock `L`.
+    
+  proc releaseSys(L: var TSysLock) {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "LeaveCriticalSection".}
+    ## Releases the lock `L`.
+
+  proc deinitSys(L: var TSysLock) {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "DeleteCriticalSection".}
+
+  proc createEvent(lpEventAttributes: pointer, 
+                   bManualReset, bInitialState: int32,
+                   lpName: cstring): TSysCond {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "CreateEventA".}
+  
+  proc closeHandle(hObject: THandle) {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "CloseHandle".}
+  proc waitForSingleObject(hHandle: THandle, dwMilliseconds: int32): int32 {.
+    stdcall, dynlib: "kernel32", importc: "WaitForSingleObject", noSideEffect.}
+
+  proc signalSysCond(hEvent: TSysCond) {.stdcall, noSideEffect,
+    dynlib: "kernel32", importc: "SetEvent".}
+  
+  proc initSysCond(cond: var TSysCond) {.inline.} =
+    cond = createEvent(nil, 0'i32, 0'i32, nil)
+  proc deinitSysCond(cond: var TSysCond) {.inline.} =
+    closeHandle(cond)
+  proc waitSysCond(cond: var TSysCond, lock: var TSysLock) =
+    releaseSys(lock)
+    discard waitForSingleObject(cond, -1'i32)
+    acquireSys(lock)
+
+  proc waitSysCondWindows(cond: var TSysCond) =
+    discard waitForSingleObject(cond, -1'i32)
+
+else:
+  type
+    TSysLock {.importc: "pthread_mutex_t", pure, final,
+               header: "<sys/types.h>".} = object
+    TSysCond {.importc: "pthread_cond_t", pure, final,
+               header: "<sys/types.h>".} = object
+
+  proc initSysLock(L: var TSysLock, attr: pointer = nil) {.
+    importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
+
+  proc acquireSys(L: var TSysLock) {.noSideEffect,
+    importc: "pthread_mutex_lock", header: "<pthread.h>".}
+  proc tryAcquireSysAux(L: var TSysLock): cint {.noSideEffect,
+    importc: "pthread_mutex_trylock", header: "<pthread.h>".}
+
+  proc tryAcquireSys(L: var TSysLock): bool {.inline.} = 
+    result = tryAcquireSysAux(L) == 0'i32
+
+  proc releaseSys(L: var TSysLock) {.noSideEffect,
+    importc: "pthread_mutex_unlock", header: "<pthread.h>".}
+  proc deinitSys(L: var TSysLock) {.noSideEffect,
+    importc: "pthread_mutex_destroy", header: "<pthread.h>".}
+
+  proc initSysCond(cond: var TSysCond, cond_attr: pointer = nil) {.
+    importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
+  proc waitSysCond(cond: var TSysCond, lock: var TSysLock) {.
+    importc: "pthread_cond_wait", header: "<pthread.h>", noSideEffect.}
+  proc signalSysCond(cond: var TSysCond) {.
+    importc: "pthread_cond_signal", header: "<pthread.h>", noSideEffect.}
+  
+  proc deinitSysCond(cond: var TSysCond) {.noSideEffect,
+    importc: "pthread_cond_destroy", header: "<pthread.h>".}
+  
diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim
new file mode 100644
index 000000000..6f45f1509
--- /dev/null
+++ b/lib/system/sysspawn.nim
@@ -0,0 +1,194 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Implements Nim's 'spawn'.
+
+when not declared(NimString): 
+  {.error: "You must not import this module explicitly".}
+
+{.push stackTrace:off.}
+
+# We declare our own condition variables here to get rid of the dummy lock
+# on Windows:
+
+type
+  CondVar = object
+    c: TSysCond
+    when defined(posix):
+      stupidLock: TSysLock
+      counter: int
+
+proc createCondVar(): CondVar =
+  initSysCond(result.c)
+  when defined(posix):
+    initSysLock(result.stupidLock)
+    #acquireSys(result.stupidLock)
+
+proc destroyCondVar(c: var CondVar) {.inline.} =
+  deinitSysCond(c.c)
+
+proc await(cv: var CondVar) =
+  when defined(posix):
+    acquireSys(cv.stupidLock)
+    while cv.counter <= 0:
+      waitSysCond(cv.c, cv.stupidLock)
+    dec cv.counter
+    releaseSys(cv.stupidLock)
+  else:
+    waitSysCondWindows(cv.c)
+
+proc signal(cv: var CondVar) =
+  when defined(posix):
+    acquireSys(cv.stupidLock)
+    inc cv.counter
+    releaseSys(cv.stupidLock)
+  signalSysCond(cv.c)
+
+type
+  FastCondVar = object
+    event, slowPath: bool
+    slow: CondVar
+
+proc createFastCondVar(): FastCondVar =
+  initSysCond(result.slow.c)
+  when defined(posix):
+    initSysLock(result.slow.stupidLock)
+    #acquireSys(result.slow.stupidLock)
+  result.event = false
+  result.slowPath = false
+
+proc await(cv: var FastCondVar) =
+  #for i in 0 .. 50:
+  #  if cas(addr cv.event, true, false):
+  #    # this is a HIT: Triggers > 95% in my tests.
+  #    return
+  #  cpuRelax()
+  #cv.slowPath = true
+  # XXX For some reason this crashes some test programs
+  await(cv.slow)
+  cv.event = false
+
+proc signal(cv: var FastCondVar) =
+  cv.event = true
+  #if cas(addr cv.slowPath, true, false):
+  signal(cv.slow)
+
+type
+  Barrier* {.compilerProc.} = object
+    counter: int
+    cv: CondVar
+
+proc barrierEnter*(b: ptr Barrier) {.compilerProc.} =
+  atomicInc b.counter
+
+proc barrierLeave*(b: ptr Barrier) {.compilerProc.} =
+  atomicDec b.counter
+  if b.counter <= 0: signal(b.cv)
+
+proc openBarrier*(b: ptr Barrier) {.compilerProc.} =
+  b.counter = 0
+  b.cv = createCondVar()
+
+proc closeBarrier*(b: ptr Barrier) {.compilerProc.} =
+  await(b.cv)
+  destroyCondVar(b.cv)
+
+{.pop.}
+
+# ----------------------------------------------------------------------------
+
+type
+  WorkerProc = proc (thread, args: pointer) {.nimcall, gcsafe.}
+  Worker = object
+    taskArrived: CondVar
+    taskStarted: FastCondVar #\
+    # task data:
+    f: WorkerProc
+    data: pointer
+    ready: bool # put it here for correct alignment!
+
+proc nimArgsPassingDone(p: pointer) {.compilerProc.} =
+  let w = cast[ptr Worker](p)
+  signal(w.taskStarted)
+
+var gSomeReady = createFastCondVar()
+
+proc slave(w: ptr Worker) {.thread.} =
+  while true:
+    w.ready = true # If we instead signal "workerReady" we need the scheduler
+                   # to notice this. The scheduler could then optimize the
+                   # layout of the worker threads (e.g. keep the list sorted)
+                   # so that no search for a "ready" thread is necessary.
+                   # This might be implemented later, but is more tricky than
+                   # it looks because 'spawn' itself can run concurrently.
+    signal(gSomeReady)
+    await(w.taskArrived)
+    assert(not w.ready)
+    # shield against spurious wakeups:
+    if w.data != nil:
+      w.f(w, w.data)
+      w.data = nil
+
+const NumThreads = 4
+
+var
+  workers: array[NumThreads, TThread[ptr Worker]]
+  workersData: array[NumThreads, Worker]
+
+proc setup() =
+  for i in 0.. <NumThreads:
+    workersData[i].taskArrived = createCondVar()
+    workersData[i].taskStarted = createFastCondVar()
+    createThread(workers[i], slave, addr(workersData[i]))
+
+proc preferSpawn*(): bool =
+  ## Use this proc to determine quickly if a 'spawn' or a direct call is
+  ## preferable. If it returns 'true' a 'spawn' may make sense. In general
+  ## it is not necessary to call this directly; use 'spawnX' instead.
+  result = gSomeReady.event
+
+proc spawn*(call: stmt) {.magic: "Spawn".}
+  ## always spawns a new task, so that the 'call' is never executed on
+  ## the calling thread. 'call' has to be proc call 'p(...)' where 'p'
+  ## is gcsafe and has 'void' as the return type.
+
+template spawnX*(call: stmt) =
+  ## spawns a new task if a CPU core is ready, otherwise executes the
+  ## call in the calling thread. Usually it is advised to
+  ## use 'spawn' in order to not block the producer for an unknown
+  ## amount of time. 'call' has to be proc call 'p(...)' where 'p'
+  ## is gcsafe and has 'void' as the return type.
+  if preferSpawn(): spawn call
+  else: call
+
+proc nimSpawn(fn: WorkerProc; data: pointer) {.compilerProc.} =
+  # implementation of 'spawn' that is used by the code generator.
+  while true:
+    for i in 0.. high(workers):
+      let w = addr(workersData[i])
+      if cas(addr w.ready, true, false):
+        w.data = data
+        w.f = fn
+        signal(w.taskArrived)
+        await(w.taskStarted)
+        return
+    await(gSomeReady)
+
+proc sync*() =
+  ## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate
+  ## waiting, you have to use an explicit barrier.
+  while true:
+    var allReady = true
+    for i in 0 .. high(workers):
+      if not allReady: break
+      allReady = allReady and workersData[i].ready
+    if allReady: break
+    await(gSomeReady)
+
+setup()
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
new file mode 100644
index 000000000..5b4020c8c
--- /dev/null
+++ b/lib/system/sysstr.nim
@@ -0,0 +1,423 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# string & sequence handling procedures needed by the code generator
+
+# strings are dynamically resized, have a length field
+# and are zero-terminated, so they can be casted to C
+# strings easily
+# we don't use refcounts because that's a behaviour
+# the programmer may not want
+
+proc resize(old: int): int {.inline.} =
+  if old <= 0: result = 4
+  elif old < 65536: result = old * 2
+  else: result = old * 3 div 2 # for large arrays * 3/2 is better
+
+proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} =
+  if a == b: return 0
+  if a == nil: return -1
+  if b == nil: return 1
+  return c_strcmp(a.data, b.data)
+
+proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
+  if a == b: return true
+  if a == nil or b == nil: return false
+  return a.len == b.len and
+    c_memcmp(a.data, b.data, a.len) == 0'i32
+
+when declared(allocAtomic):
+  template allocStr(size: expr): expr =
+    cast[NimString](allocAtomic(size))
+
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](boehmAllocAtomic(size))
+else:
+  template allocStr(size: expr): expr =
+    cast[NimString](newObj(addr(strDesc), size))
+
+  template allocStrNoInit(size: expr): expr =
+    cast[NimString](newObjNoInit(addr(strDesc), size))
+
+proc rawNewStringNoInit(space: int): NimString {.compilerProc.} =
+  var s = space
+  if s < 7: s = 7
+  result = allocStrNoInit(sizeof(TGenericSeq) + s + 1)
+  result.reserved = s
+
+proc rawNewString(space: int): NimString {.compilerProc.} =
+  var s = space
+  if s < 7: s = 7
+  result = allocStr(sizeof(TGenericSeq) + s + 1)
+  result.reserved = s
+
+proc mnewString(len: int): NimString {.compilerProc.} =
+  result = rawNewString(len)
+  result.len = len
+
+proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
+  var start = max(start, 0)
+  var len = min(last, s.len-1) - start + 1
+  if len > 0:
+    result = rawNewStringNoInit(len)
+    result.len = len
+    c_memcpy(result.data, addr(s.data[start]), len)
+    result.data[len] = '\0'
+  else:
+    result = rawNewString(len)
+
+proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
+  result = copyStrLast(s, start, s.len-1)
+
+proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
+  result = rawNewStringNoInit(len)
+  result.len = len
+  c_memcpy(result.data, str, len + 1)
+
+proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
+  result = toNimStr(str, c_strlen(str))
+
+proc copyString(src: NimString): NimString {.compilerRtl.} =
+  if src != nil:
+    if (src.reserved and seqShallowFlag) != 0:
+      result = src
+    else:
+      result = rawNewStringNoInit(src.len)
+      result.len = src.len
+      c_memcpy(result.data, src.data, src.len + 1)
+
+proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
+  if src != nil:
+    when declared(newObjRC1):
+      var s = src.len
+      if s < 7: s = 7
+      result = cast[NimString](newObjRC1(addr(strDesc), sizeof(TGenericSeq) +
+                               s+1))
+      result.reserved = s
+    else:
+      result = rawNewStringNoInit(src.len)
+    result.len = src.len
+    c_memcpy(result.data, src.data, src.len + 1)
+
+
+proc hashString(s: string): int {.compilerproc.} =
+  # the compiler needs exactly the same hash function!
+  # this used to be used for efficient generation of string case statements
+  var h = 0
+  for i in 0..len(s)-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 addChar(s: NimString, c: char): NimString =
+  # is compilerproc!
+  result = s
+  if result.len >= result.space:
+    result.reserved = resize(result.space)
+    result = cast[NimString](growObj(result,
+      sizeof(TGenericSeq) + result.reserved + 1))
+  result.data[result.len] = c
+  result.data[result.len+1] = '\0'
+  inc(result.len)
+
+# These routines should be used like following:
+#   <Nim code>
+#   s &= "Hello " & name & ", how do you feel?"
+#
+#   <generated C code>
+#   {
+#     s = resizeString(s, 6 + name->len + 17);
+#     appendString(s, strLit1);
+#     appendString(s, strLit2);
+#     appendString(s, strLit3);
+#   }
+#
+#   <Nim code>
+#   s = "Hello " & name & ", how do you feel?"
+#
+#   <generated C code>
+#   {
+#     string tmp0;
+#     tmp0 = rawNewString(6 + name->len + 17);
+#     appendString(s, strLit1);
+#     appendString(s, strLit2);
+#     appendString(s, strLit3);
+#     s = tmp0;
+#   }
+#
+#   <Nim code>
+#   s = ""
+#
+#   <generated C code>
+#   s = rawNewString(0);
+
+proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
+  if dest.len + addlen <= dest.space:
+    result = dest
+  else: # slow path:
+    var sp = max(resize(dest.space), dest.len + addlen)
+    result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
+    result.reserved = sp
+    #result = rawNewString(sp)
+    #copyMem(result, dest, dest.len + sizeof(TGenericSeq))
+    # DO NOT UPDATE LEN YET: dest.len = newLen
+
+proc appendString(dest, src: NimString) {.compilerproc, inline.} =
+  c_memcpy(addr(dest.data[dest.len]), src.data, src.len + 1)
+  inc(dest.len, src.len)
+
+proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} =
+  dest.data[dest.len] = c
+  dest.data[dest.len+1] = '\0'
+  inc(dest.len)
+
+proc setLengthStr(s: NimString, newLen: int): NimString {.compilerRtl.} =
+  var n = max(newLen, 0)
+  if n <= s.space:
+    result = s
+  else:
+    result = resizeString(s, n)
+  result.len = n
+  result.data[n] = '\0'
+
+# ----------------- sequences ----------------------------------------------
+
+proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
+  # increments the length by one:
+  # this is needed for supporting ``add``;
+  #
+  #  add(seq, x)  generates:
+  #  seq = incrSeq(seq, sizeof(x));
+  #  seq[seq->len-1] = x;
+  result = seq
+  if result.len >= result.space:
+    result.reserved = resize(result.space)
+    result = cast[PGenericSeq](growObj(result, elemSize * result.reserved +
+                               GenericSeqSize))
+  inc(result.len)
+
+proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
+    compilerRtl.} =
+  result = seq
+  if result.space < newLen:
+    result.reserved = max(resize(result.space), newLen)
+    result = cast[PGenericSeq](growObj(result, elemSize * result.reserved +
+                               GenericSeqSize))
+  elif newLen < result.len:
+    # we need to decref here, otherwise the GC leaks!
+    when not defined(boehmGC) and not defined(nogc) and
+         not defined(gcMarkAndSweep):
+      when compileOption("gc", "v2"):
+        for i in newLen..result.len-1:
+          let len0 = gch.tempStack.len
+          forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
+                            GenericSeqSize +% (i*%elemSize)),
+                            extGetCellType(result).base, waPush)
+          let len1 = gch.tempStack.len
+          for i in len0 .. <len1:
+            doDecRef(gch.tempStack.d[i], LocalHeap, MaybeCyclic)
+          gch.tempStack.len = len0
+      else:
+        for i in newLen..result.len-1:
+          forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +%
+                            GenericSeqSize +% (i*%elemSize)),
+                            extGetCellType(result).base, waZctDecRef)
+
+    # XXX: zeroing out the memory can still result in crashes if a wiped-out
+    # cell is aliased by another pointer (ie proc parameter or a let variable).
+    # This is a tought problem, because even if we don't zeroMem here, in the
+    # presence of user defined destructors, the user will expect the cell to be
+    # "destroyed" thus creating the same problem. We can destoy the cell in the
+    # finalizer of the sequence, but this makes destruction non-deterministic.
+    zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +%
+           (newLen*%elemSize)), (result.len-%newLen) *% elemSize)
+  result.len = newLen
+
+# --------------- other string routines ----------------------------------
+proc nimIntToStr(x: int): string {.compilerRtl.} =
+  result = newString(sizeof(x)*4)
+  var i = 0
+  var y = x
+  while true:
+    var d = y div 10
+    result[i] = chr(abs(int(y - d*10)) + ord('0'))
+    inc(i)
+    y = d
+    if y == 0: break
+  if x < 0:
+    result[i] = '-'
+    inc(i)
+  setLen(result, i)
+  # mirror the string:
+  for j in 0..i div 2 - 1:
+    swap(result[j], result[i-j-1])
+
+proc nimFloatToStr(f: float): string {.compilerproc.} =
+  var buf: array[0..64, char]
+  var n: int = c_sprintf(buf, "%.16g", f)
+  var hasDot = false
+  for i in 0..n-1:
+    if buf[i] == ',':
+      buf[i] = '.'
+      hasDot = true
+    elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
+      hasDot = true
+  if not hasDot:
+    buf[n] = '.'
+    buf[n+1] = '0'
+    buf[n+2] = '\0'
+  # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced.
+  # We want to get rid of these here:
+  if buf[n-1] == 'N':
+    result = "nan"
+  elif buf[n-1] == 'F':
+    if buf[0] == '-':
+      result = "-inf"
+    else:
+      result = "inf"
+  else:
+    result = $buf
+
+proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc,
+  header: "<stdlib.h>", noSideEffect.}
+
+var decimalPoint: char
+
+proc getDecimalPoint(): char =
+  result = decimalPoint
+  if result == '\0':
+    if strtod("0,5", nil) == 0.5: result = ','
+    else: result = '.'
+    # yes this is threadsafe in practice, spare me:
+    decimalPoint = result
+
+const
+  IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
+
+proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
+                          start = 0): int {.compilerProc.} =
+  # This routine leverages `strtod()` for the non-trivial task of
+  # parsing floating point numbers correctly. Because `strtod()` is
+  # locale-dependent with respect to the radix character, we create
+  # a copy where the decimal point is replaced with the locale's
+  # radix character.
+  var
+    i = start
+    sign = 1.0
+    t: array[500, char] # flaviu says: 325 is the longest reasonable literal
+    ti = 0
+    hasdigits = false
+
+  template addToBuf(c) =
+    if ti < t.high:
+      t[ti] = c; inc(ti)
+
+  # Sign?
+  if s[i] == '+' or s[i] == '-':
+    if s[i] == '-':
+      sign = -1.0
+    t[ti] = s[i]
+    inc(i); inc(ti)
+
+  # NaN?
+  if s[i] == 'N' or s[i] == 'n':
+    if s[i+1] == 'A' or s[i+1] == 'a':
+      if s[i+2] == 'N' or s[i+2] == 'n':
+        if s[i+3] notin IdentChars:
+          number = NaN
+          return i+3 - start
+    return 0
+
+  # Inf?
+  if s[i] == 'I' or s[i] == 'i':
+    if s[i+1] == 'N' or s[i+1] == 'n':
+      if s[i+2] == 'F' or s[i+2] == 'f':
+        if s[i+3] notin IdentChars:
+          number = Inf*sign
+          return i+3 - start
+    return 0
+
+  # Integer part?
+  while s[i] in {'0'..'9'}:
+    hasdigits = true
+    addToBuf(s[i])
+    inc(i);
+    while s[i] == '_': inc(i)
+
+  # Fractional part?
+  if s[i] == '.':
+    addToBuf(getDecimalPoint())
+    inc(i)
+    while s[i] in {'0'..'9'}:
+      hasdigits = true
+      addToBuf(s[i])
+      inc(i)
+      while s[i] == '_': inc(i)
+  if not hasdigits:
+    return 0
+
+  # Exponent?
+  if s[i] in {'e', 'E'}:
+    addToBuf(s[i])
+    inc(i)
+    if s[i] in {'+', '-'}:
+      addToBuf(s[i])
+      inc(i)
+    if s[i] notin {'0'..'9'}:
+      return 0
+    while s[i] in {'0'..'9'}:
+      addToBuf(s[i])
+      inc(i)
+      while s[i] == '_': inc(i)
+  number = strtod(t, nil)
+  result = i - start
+
+proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
+  result = newString(sizeof(x)*4)
+  var i = 0
+  var y = x
+  while true:
+    var d = y div 10
+    result[i] = chr(abs(int(y - d*10)) + ord('0'))
+    inc(i)
+    y = d
+    if y == 0: break
+  if x < 0:
+    result[i] = '-'
+    inc(i)
+  setLen(result, i)
+  # mirror the string:
+  for j in 0..i div 2 - 1:
+    swap(result[j], result[i-j-1])
+
+proc nimBoolToStr(x: bool): string {.compilerRtl.} =
+  return if x: "true" else: "false"
+
+proc nimCharToStr(x: char): string {.compilerRtl.} =
+  result = newString(1)
+  result[0] = x
+
+proc binaryStrSearch(x: openArray[string], y: string): int {.compilerproc.} =
+  var
+    a = 0
+    b = len(x)
+  while a < b:
+    var mid = (a + b) div 2
+    if x[mid] < y:
+      a = mid + 1
+    else:
+      b = mid
+  if a < len(x) and x[a] == y:
+    result = a
+  else:
+    result = -1
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
new file mode 100644
index 000000000..d8e011ecb
--- /dev/null
+++ b/lib/system/threads.nim
@@ -0,0 +1,410 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Thread support for Nim. **Note**: This is part of the system module.
+## Do not import it directly. To activate thread support you need to compile
+## with the ``--threads:on`` command line switch.
+##
+## Nim's memory model for threads is quite different from other common 
+## programming languages (C, Pascal): Each thread has its own
+## (garbage collected) heap and sharing of memory is restricted. This helps
+## to prevent race conditions and improves efficiency. See `the manual for
+## details of this memory model <manual.html#threads>`_.
+##
+## Example:
+##
+## .. code-block:: Nim
+##
+##  import locks
+##
+##  var
+##    thr: array [0..4, TThread[tuple[a,b: int]]]
+##    L: TLock
+##  
+##  proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
+##    for i in interval.a..interval.b:
+##      acquire(L) # lock stdout
+##      echo i
+##      release(L)
+##
+##  initLock(L)
+##
+##  for i in 0..high(thr):
+##    createThread(thr[i], threadFunc, (i*10, i*10+5))
+##  joinThreads(thr)
+  
+when not declared(NimString): 
+  {.error: "You must not import this module explicitly".}
+
+const
+  maxRegisters = 256 # don't think there is an arch with more registers
+  useStackMaskHack = false ## use the stack mask hack for better performance
+  StackGuardSize = 4096
+  ThreadStackMask = 1024*256*sizeof(int)-1
+  ThreadStackSize = ThreadStackMask+1 - StackGuardSize
+
+when defined(windows):
+  type
+    TSysThread = THandle
+    TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
+
+  proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
+                     lpStartAddress: TWinThreadProc, 
+                     lpParameter: pointer,
+                     dwCreationFlags: int32, 
+                     lpThreadId: var int32): TSysThread {.
+    stdcall, dynlib: "kernel32", importc: "CreateThread".}
+
+  proc winSuspendThread(hThread: TSysThread): int32 {.
+    stdcall, dynlib: "kernel32", importc: "SuspendThread".}
+      
+  proc winResumeThread(hThread: TSysThread): int32 {.
+    stdcall, dynlib: "kernel32", importc: "ResumeThread".}
+
+  proc waitForMultipleObjects(nCount: int32,
+                              lpHandles: ptr TSysThread,
+                              bWaitAll: int32,
+                              dwMilliseconds: int32): int32 {.
+    stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
+
+  proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
+    stdcall, dynlib: "kernel32", importc: "TerminateThread".}
+    
+  type
+    TThreadVarSlot = distinct int32
+
+  when true:
+    proc threadVarAlloc(): TThreadVarSlot {.
+      importc: "TlsAlloc", stdcall, header: "<windows.h>".}
+    proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
+      importc: "TlsSetValue", stdcall, header: "<windows.h>".}
+    proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
+      importc: "TlsGetValue", stdcall, header: "<windows.h>".}
+
+    proc getLastError(): uint32 {.
+      importc: "GetLastError", stdcall, header: "<windows.h>".}
+    proc setLastError(x: uint32) {.
+      importc: "SetLastError", stdcall, header: "<windows.h>".}
+
+    proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer =
+      let realLastError = getLastError()
+      result = tlsGetValue(dwTlsIndex)
+      setLastError(realLastError)
+  else:
+    proc threadVarAlloc(): TThreadVarSlot {.
+      importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
+    proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
+      importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
+    proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
+      importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
+  
+else:
+  when not defined(macosx):
+    {.passL: "-pthread".}
+
+  {.passC: "-pthread".}
+
+  type
+    TSysThread {.importc: "pthread_t", header: "<sys/types.h>",
+                 final, pure.} = object
+    Tpthread_attr {.importc: "pthread_attr_t",
+                     header: "<sys/types.h>", final, pure.} = object
+                 
+    Ttimespec {.importc: "struct timespec",
+                header: "<time.h>", final, pure.} = object
+      tv_sec: int
+      tv_nsec: int
+
+  proc pthread_attr_init(a1: var TPthread_attr) {.
+    importc, header: "<pthread.h>".}
+  proc pthread_attr_setstacksize(a1: var TPthread_attr, a2: int) {.
+    importc, header: "<pthread.h>".}
+
+  proc pthread_create(a1: var TSysThread, a2: var TPthread_attr,
+            a3: proc (x: pointer): pointer {.noconv.}, 
+            a4: pointer): cint {.importc: "pthread_create", 
+            header: "<pthread.h>".}
+  proc pthread_join(a1: TSysThread, a2: ptr pointer): cint {.
+    importc, header: "<pthread.h>".}
+
+  proc pthread_cancel(a1: TSysThread): cint {.
+    importc: "pthread_cancel", header: "<pthread.h>".}
+
+  type
+    TThreadVarSlot {.importc: "pthread_key_t", pure, final,
+                   header: "<sys/types.h>".} = object
+
+  proc pthread_getspecific(a1: TThreadVarSlot): pointer {.
+    importc: "pthread_getspecific", header: "<pthread.h>".}
+  proc pthread_key_create(a1: ptr TThreadVarSlot, 
+                          destruct: proc (x: pointer) {.noconv.}): int32 {.
+    importc: "pthread_key_create", header: "<pthread.h>".}
+  proc pthread_key_delete(a1: TThreadVarSlot): int32 {.
+    importc: "pthread_key_delete", header: "<pthread.h>".}
+
+  proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
+    importc: "pthread_setspecific", header: "<pthread.h>".}
+  
+  proc threadVarAlloc(): TThreadVarSlot {.inline.} =
+    discard pthread_key_create(addr(result), nil)
+  proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
+    discard pthread_setspecific(s, value)
+  proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
+    result = pthread_getspecific(s)
+
+  when useStackMaskHack:
+    proc pthread_attr_setstack(attr: var TPthread_attr, stackaddr: pointer,
+                               size: int): cint {.
+      importc: "pthread_attr_setstack", header: "<pthread.h>".}
+
+const
+  emulatedThreadVars = compileOption("tlsEmulation")
+
+when emulatedThreadVars:
+  # the compiler generates this proc for us, so that we can get the size of
+  # the thread local var block; we use this only for sanity checking though
+  proc nimThreadVarsSize(): int {.noconv, importc: "NimThreadVarsSize".}
+
+# we preallocate a fixed size for thread local storage, so that no heap
+# allocations are needed. Currently less than 7K are used on a 64bit machine.
+# We use ``float`` for proper alignment:
+type
+  TThreadLocalStorage = array [0..1_000, float]
+
+  PGcThread = ptr TGcThread
+  TGcThread {.pure, inheritable.} = object
+    sys: TSysThread
+    when emulatedThreadVars and not useStackMaskHack:
+      tls: TThreadLocalStorage
+    else:
+      nil
+    when hasSharedHeap:
+      next, prev: PGcThread
+      stackBottom, stackTop: pointer
+      stackSize: int
+    else:
+      nil
+
+# XXX it'd be more efficient to not use a global variable for the 
+# thread storage slot, but to rely on the implementation to assign slot X
+# for us... ;-)
+var globalsSlot: TThreadVarSlot
+
+when not defined(useNimRtl):
+  when not useStackMaskHack:
+    var mainThread: TGcThread
+
+proc initThreadVarsEmulation() {.compilerProc, inline.} =
+  when not defined(useNimRtl):
+    globalsSlot = threadVarAlloc()
+    when declared(mainThread):
+      threadVarSetValue(globalsSlot, addr(mainThread))
+
+#const globalsSlot = TThreadVarSlot(0)
+#sysAssert checkSlot.int == globalsSlot.int
+
+when emulatedThreadVars:
+  proc GetThreadLocalVars(): pointer {.compilerRtl, inl.} =
+    result = addr(cast[PGcThread](threadVarGetValue(globalsSlot)).tls)
+
+when useStackMaskHack:
+  proc maskStackPointer(offset: int): pointer {.compilerRtl, inl.} =
+    var x {.volatile.}: pointer
+    x = addr(x)
+    result = cast[pointer]((cast[int](x) and not ThreadStackMask) +% 
+      (0) +% offset)
+
+# create for the main thread. Note: do not insert this data into the list
+# of all threads; it's not to be stopped etc.
+when not defined(useNimRtl):
+  when not useStackMaskHack:
+    #when not defined(createNimRtl): initStackBottom()
+    initGC()
+    
+  when emulatedThreadVars:
+    if nimThreadVarsSize() > sizeof(TThreadLocalStorage):
+      echo "too large thread local storage size requested"
+      quit 1
+  
+  when hasSharedHeap and not defined(boehmgc) and not defined(nogc):
+    var
+      threadList: PGcThread
+      
+    proc registerThread(t: PGcThread) = 
+      # we need to use the GC global lock here!
+      acquireSys(HeapLock)
+      t.prev = nil
+      t.next = threadList
+      if threadList != nil: 
+        sysAssert(threadList.prev == nil, "threadList.prev == nil")
+        threadList.prev = t
+      threadList = t
+      releaseSys(HeapLock)
+    
+    proc unregisterThread(t: PGcThread) =
+      # we need to use the GC global lock here!
+      acquireSys(HeapLock)
+      if t == threadList: threadList = t.next
+      if t.next != nil: t.next.prev = t.prev
+      if t.prev != nil: t.prev.next = t.next
+      # so that a thread can be unregistered twice which might happen if the
+      # code executes `destroyThread`:
+      t.next = nil
+      t.prev = nil
+      releaseSys(HeapLock)
+      
+    # on UNIX, the GC uses ``SIGFREEZE`` to tell every thread to stop so that
+    # the GC can examine the stacks?
+    proc stopTheWord() = discard
+    
+# We jump through some hops here to ensure that Nim thread procs can have
+# the Nim calling convention. This is needed because thread procs are 
+# ``stdcall`` on Windows and ``noconv`` on UNIX. Alternative would be to just
+# use ``stdcall`` since it is mapped to ``noconv`` on UNIX anyway.
+
+type
+  TThread* {.pure, final.}[TArg] =
+      object of TGcThread ## Nim thread. A thread is a heavy object (~14K)
+                          ## that **must not** be part of a message! Use
+                          ## a ``TThreadId`` for that.
+    when TArg is void:
+      dataFn: proc () {.nimcall, gcsafe.}
+    else:
+      dataFn: proc (m: TArg) {.nimcall, gcsafe.}
+      data: TArg
+  TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
+                                       ## a pointer as a thread ID.
+
+when not defined(boehmgc) and not hasSharedHeap:
+  proc deallocOsPages()
+
+template threadProcWrapperBody(closure: expr) {.immediate.} =
+  when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
+  var t = cast[ptr TThread[TArg]](closure)
+  when useStackMaskHack:
+    var tls: TThreadLocalStorage
+  when not defined(boehmgc) and not defined(nogc) and not hasSharedHeap:
+    # init the GC for this thread:
+    setStackBottom(addr(t))
+    initGC()
+  when declared(registerThread):
+    t.stackBottom = addr(t)
+    registerThread(t)
+  when TArg is void: t.dataFn()
+  else: t.dataFn(t.data)
+  when declared(registerThread): unregisterThread(t)
+  when declared(deallocOsPages): deallocOsPages()
+  # Since an unhandled exception terminates the whole process (!), there is
+  # no need for a ``try finally`` here, nor would it be correct: The current
+  # exception is tried to be re-raised by the code-gen after the ``finally``!
+  # However this is doomed to fail, because we already unmapped every heap
+  # page!
+  
+  # mark as not running anymore:
+  t.dataFn = nil
+  
+{.push stack_trace:off.}
+when defined(windows):
+  proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} = 
+    threadProcWrapperBody(closure)
+    # implicitly return 0
+else:
+  proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} = 
+    threadProcWrapperBody(closure)
+{.pop.}
+
+proc running*[TArg](t: TThread[TArg]): bool {.inline.} = 
+  ## returns true if `t` is running.
+  result = t.dataFn != nil
+
+when hostOS == "windows":
+  proc joinThread*[TArg](t: TThread[TArg]) {.inline.} = 
+    ## waits for the thread `t` to finish.
+    discard waitForSingleObject(t.sys, -1'i32)
+
+  proc joinThreads*[TArg](t: varargs[TThread[TArg]]) = 
+    ## waits for every thread in `t` to finish.
+    var a: array[0..255, TSysThread]
+    sysAssert a.len >= t.len, "a.len >= t.len"
+    for i in 0..t.high: a[i] = t[i].sys
+    discard waitForMultipleObjects(t.len.int32,
+                                   cast[ptr TSysThread](addr(a)), 1, -1)
+
+else:
+  proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
+    ## waits for the thread `t` to finish.
+    discard pthread_join(t.sys, nil)
+
+  proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
+    ## waits for every thread in `t` to finish.
+    for i in 0..t.high: joinThread(t[i])
+
+when false:
+  # XXX a thread should really release its heap here somehow:
+  proc destroyThread*[TArg](t: var TThread[TArg]) =
+    ## forces the thread `t` to terminate. This is potentially dangerous if
+    ## you don't have full control over `t` and its acquired resources.
+    when hostOS == "windows":
+      discard TerminateThread(t.sys, 1'i32)
+    else:
+      discard pthread_cancel(t.sys)
+    when declared(registerThread): unregisterThread(addr(t))
+    t.dataFn = nil
+
+when hostOS == "windows":
+  proc createThread*[TArg](t: var TThread[TArg],
+                           tp: proc (arg: TArg) {.thread.}, 
+                           param: TArg) =
+    ## creates a new thread `t` and starts its execution. Entry point is the
+    ## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
+    ## don't need to pass any data to the thread.
+    when TArg isnot void: t.data = param
+    t.dataFn = tp
+    when hasSharedHeap: t.stackSize = ThreadStackSize
+    var dummyThreadId: int32
+    t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
+                         addr(t), 0'i32, dummyThreadId)
+    if t.sys <= 0:
+      raise newException(ResourceExhaustedError, "cannot create thread")
+else:
+  proc createThread*[TArg](t: var TThread[TArg], 
+                           tp: proc (arg: TArg) {.thread.}, 
+                           param: TArg) =
+    ## creates a new thread `t` and starts its execution. Entry point is the
+    ## proc `tp`. `param` is passed to `tp`. `TArg` can be ``void`` if you
+    ## don't need to pass any data to the thread.
+    when TArg isnot void: t.data = param
+    t.dataFn = tp
+    when hasSharedHeap: t.stackSize = ThreadStackSize
+    var a {.noinit.}: Tpthread_attr
+    pthread_attr_init(a)
+    pthread_attr_setstacksize(a, ThreadStackSize)
+    if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0:
+      raise newException(ResourceExhaustedError, "cannot create thread")
+
+proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} =
+  ## returns the thread ID of `t`.
+  result = addr(t)
+
+proc myThreadId*[TArg](): TThreadId[TArg] =
+  ## returns the thread ID of the thread that calls this proc. This is unsafe
+  ## because the type ``TArg`` is not checked for consistency!
+  result = cast[TThreadId[TArg]](threadVarGetValue(globalsSlot))
+
+when false:
+  proc mainThreadId*[TArg](): TThreadId[TArg] =
+    ## returns the thread ID of the main thread.
+    result = cast[TThreadId[TArg]](addr(mainThread))
+
+when useStackMaskHack:
+  proc runMain(tp: proc () {.thread.}) {.compilerproc.} =
+    var mainThread: TThread[pointer]
+    createThread(mainThread, tp)
+    joinThread(mainThread)
+
diff --git a/lib/system/timers.nim b/lib/system/timers.nim
new file mode 100644
index 000000000..e5de791ac
--- /dev/null
+++ b/lib/system/timers.nim
@@ -0,0 +1,93 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Timer support for the realtime GC. Based on
+## `<https://github.com/jckarter/clay/blob/master/compiler/src/hirestimer.cpp>`_
+
+type
+  TTicks = distinct int64
+  TNanos = int64
+
+when defined(windows):
+
+  proc QueryPerformanceCounter(res: var TTicks) {.
+    importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
+  proc QueryPerformanceFrequency(res: var int64) {.
+    importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}
+
+  proc getTicks(): TTicks {.inline.} =
+    QueryPerformanceCounter(result)
+
+  proc `-`(a, b: TTicks): TNanos =
+    var frequency: int64
+    QueryPerformanceFrequency(frequency)
+    var performanceCounterRate = 1e+9'f64 / float64(frequency)
+
+    result = TNanos(float64(a.int64 - b.int64) * performanceCounterRate)
+
+elif defined(macosx):
+  type
+    TMachTimebaseInfoData {.pure, final, 
+        importc: "mach_timebase_info_data_t", 
+        header: "<mach/mach_time.h>".} = object
+      numer, denom: int32
+
+  proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
+  proc mach_timebase_info(info: var TMachTimebaseInfoData) {.importc,
+    header: "<mach/mach_time.h>".}
+
+  proc getTicks(): TTicks {.inline.} =
+    result = TTicks(mach_absolute_time())
+  
+  var timeBaseInfo: TMachTimebaseInfoData
+  mach_timebase_info(timeBaseInfo)
+    
+  proc `-`(a, b: TTicks): TNanos =
+    result = (a.int64 - b.int64)  * timeBaseInfo.numer div timeBaseInfo.denom
+
+elif defined(posixRealtime):
+  type
+    TClockid {.importc: "clockid_t", header: "<time.h>", final.} = object
+
+    TTimeSpec {.importc: "struct timespec", header: "<time.h>", 
+               final, pure.} = object ## struct timespec
+      tv_sec: int  ## Seconds. 
+      tv_nsec: int ## Nanoseconds. 
+
+  var
+    CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: TClockid
+
+  proc clock_gettime(clkId: TClockid, tp: var TTimespec) {.
+    importc: "clock_gettime", header: "<time.h>".}
+
+  proc getTicks(): TTicks =
+    var t: TTimespec
+    clock_gettime(CLOCK_REALTIME, t)
+    result = TTicks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))
+
+  proc `-`(a, b: TTicks): TNanos {.borrow.}
+
+else:
+  # fallback Posix implementation:  
+  type
+    Ttimeval {.importc: "struct timeval", header: "<sys/select.h>", 
+               final, pure.} = object ## struct timeval
+      tv_sec: int  ## Seconds. 
+      tv_usec: int ## Microseconds. 
+        
+  proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {.
+    importc: "gettimeofday", header: "<sys/time.h>".}
+
+  proc getTicks(): TTicks =
+    var t: Ttimeval
+    posix_gettimeofday(t)
+    result = TTicks(int64(t.tv_sec) * 1000_000_000'i64 + 
+                    int64(t.tv_usec) * 1000'i64)
+
+  proc `-`(a, b: TTicks): TNanos {.borrow.}
diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim
new file mode 100644
index 000000000..1e8bc6791
--- /dev/null
+++ b/lib/system/widestrs.nim
@@ -0,0 +1,153 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Nim support for C/C++'s `wide strings`:idx:. This is part of the system
+# module! Do not import it directly!
+
+when not declared(NimString):
+  {.error: "You must not import this module explicitly".}
+
+type
+  TUtf16Char* = distinct int16
+  WideCString* = ref array[0.. 1_000_000, TUtf16Char]
+
+proc len*(w: WideCString): int =
+  ## returns the length of a widestring. This traverses the whole string to
+  ## find the binary zero end marker!
+  while int16(w[result]) != 0'i16: inc result
+
+const
+  UNI_REPLACEMENT_CHAR = TUtf16Char(0xFFFD'i16)
+  UNI_MAX_BMP = 0x0000FFFF
+  UNI_MAX_UTF16 = 0x0010FFFF
+  UNI_MAX_UTF32 = 0x7FFFFFFF
+  UNI_MAX_LEGAL_UTF32 = 0x0010FFFF
+
+  halfShift = 10
+  halfBase = 0x0010000
+  halfMask = 0x3FF
+
+  UNI_SUR_HIGH_START = 0xD800
+  UNI_SUR_HIGH_END = 0xDBFF
+  UNI_SUR_LOW_START = 0xDC00
+  UNI_SUR_LOW_END = 0xDFFF
+
+template ones(n: expr): expr = ((1 shl n)-1)
+
+template fastRuneAt(s: cstring, i: int, result: expr, doInc = true) =
+  ## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
+  ## `i` is incremented by the number of bytes that have been processed.
+  bind ones
+
+  if ord(s[i]) <=% 127:
+    result = ord(s[i])
+    when doInc: inc(i)
+  elif ord(s[i]) shr 5 == 0b110:
+    #assert(ord(s[i+1]) shr 6 == 0b10)
+    result = (ord(s[i]) and (ones(5))) shl 6 or (ord(s[i+1]) and ones(6))
+    when doInc: inc(i, 2)
+  elif ord(s[i]) shr 4 == 0b1110:
+    #assert(ord(s[i+1]) shr 6 == 0b10)
+    #assert(ord(s[i+2]) shr 6 == 0b10)
+    result = (ord(s[i]) and ones(4)) shl 12 or
+             (ord(s[i+1]) and ones(6)) shl 6 or
+             (ord(s[i+2]) and ones(6))
+    when doInc: inc(i, 3)
+  elif ord(s[i]) shr 3 == 0b11110:
+    #assert(ord(s[i+1]) shr 6 == 0b10)
+    #assert(ord(s[i+2]) shr 6 == 0b10)
+    #assert(ord(s[i+3]) shr 6 == 0b10)
+    result = (ord(s[i]) and ones(3)) shl 18 or
+             (ord(s[i+1]) and ones(6)) shl 12 or
+             (ord(s[i+2]) and ones(6)) shl 6 or
+             (ord(s[i+3]) and ones(6))
+    when doInc: inc(i, 4)
+  else:
+    result = 0xFFFD
+    when doInc: inc(i)
+
+iterator runes(s: cstring): int =
+  var
+    i = 0
+    result: int
+  while s[i] != '\0':
+    fastRuneAt(s, i, result, true)
+    yield result
+
+proc newWideCString*(source: cstring, L: int): WideCString =
+  unsafeNew(result, L * 4 + 2)
+  #result = cast[wideCString](alloc(L * 4 + 2))
+  var d = 0
+  for ch in runes(source):
+    if ch <=% UNI_MAX_BMP:
+      if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
+        result[d] = UNI_REPLACEMENT_CHAR
+      else:
+        result[d] = TUtf16Char(toU16(ch))
+    elif ch >% UNI_MAX_UTF16:
+      result[d] = UNI_REPLACEMENT_CHAR
+    else:
+      let ch = ch -% halfBase
+      result[d] = TUtf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
+      inc d
+      result[d] = TUtf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
+    inc d
+  result[d] = TUtf16Char(0'i16)
+
+proc newWideCString*(s: cstring): WideCString =
+  if s.isNil: return nil
+
+  when not declared(c_strlen):
+    proc c_strlen(a: cstring): int {.
+      header: "<string.h>", noSideEffect, importc: "strlen".}
+
+  let L = c_strlen(s)
+  result = newWideCString(s, L)
+
+proc newWideCString*(s: string): WideCString =
+  result = newWideCString(s, s.len)
+
+proc `$`*(w: WideCString, estimate: int): string =
+  result = newStringOfCap(estimate + estimate shr 2)
+
+  var i = 0
+  while w[i].int16 != 0'i16:
+    var ch = w[i].int
+    inc i
+    if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_HIGH_END:
+      # If the 16 bits following the high surrogate are in the source buffer...
+      let ch2 = w[i].int
+      # If it's a low surrogate, convert to UTF32:
+      if ch2 >=% UNI_SUR_LOW_START and ch2 <=% UNI_SUR_LOW_END:
+        ch = ((ch -% UNI_SUR_HIGH_START) shr halfShift) +%
+              (ch2 -% UNI_SUR_LOW_START) +% halfBase
+        inc i
+        
+    if ch <=% 127:
+      result.add chr(ch)
+    elif ch <=% 0x07FF:
+      result.add chr((ch shr 6) or 0b110_00000)
+      result.add chr((ch and ones(6)) or 0b10_000000)
+    elif ch <=% 0xFFFF:
+      result.add chr(ch shr 12 or 0b1110_0000)
+      result.add chr(ch shr 6 and ones(6) or 0b10_0000_00)
+      result.add chr(ch and ones(6) or 0b10_0000_00)
+    elif ch <=% 0x0010FFFF:
+      result.add chr(ch shr 18 or 0b1111_0000)
+      result.add chr(ch shr 12 and ones(6) or 0b10_0000_00)
+      result.add chr(ch shr 6 and ones(6) or 0b10_0000_00)
+      result.add chr(ch and ones(6) or 0b10_0000_00)
+    else:
+      # replacement char:
+      result.add chr(0xFFFD shr 12 or 0b1110_0000)
+      result.add chr(0xFFFD shr 6 and ones(6) or 0b10_0000_00)
+      result.add chr(0xFFFD and ones(6) or 0b10_0000_00)
+
+proc `$`*(s: WideCString): string =
+  result = s $ 80
diff --git a/lib/windows/mmsystem.nim b/lib/windows/mmsystem.nim
new file mode 100644
index 000000000..45613d8e2
--- /dev/null
+++ b/lib/windows/mmsystem.nim
@@ -0,0 +1,2652 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#*********************************
+#*******************************
+# Generated by c2pas32  v0.9b
+#     Fixed by P.V.Ozerski
+# (c) 2001 Oleg Bulychov
+#     Original C header file
+# Gladiators Software
+#     (created at Dec-03-1998)
+# http://www.astonshell.com/
+#   from LCC-win32 is used
+#*********************************
+#   LCC-win32 (c) Jacob Navia
+#*******************************
+
+{.deadCodeElim: on.}
+
+import
+  windows
+
+type
+  MMRESULT* = uint32
+  MMVERSION* = uint32
+  HWAVEOUT* = THandle
+  LPHWAVEOUT* = ptr HWAVEOUT
+  HWAVEIN* = THandle
+  LPHWAVEIN* = ptr HWAVEOUT
+  HWAVE* = THandle
+  LPHWAVE* = ptr THandle
+  LPUINT* = ptr uint32
+
+const
+  MAXPNAMELEN* = 32
+  MAXERRORLENGTH* = 256
+  MAX_JOYSTICKOEMVXDNAME* = 260
+  MM_MIDI_MAPPER* = 1
+  MM_WAVE_MAPPER* = 2
+  MM_SNDBLST_MIDIOUT* = 3
+  MM_SNDBLST_MIDIIN* = 4
+  MM_SNDBLST_SYNTH* = 5
+  MM_SNDBLST_WAVEOUT* = 6
+  MM_SNDBLST_WAVEIN* = 7
+  MM_ADLIB* = 9
+  MM_MPU401_MIDIOUT* = 10
+  MM_MPU401_MIDIIN* = 11
+  MM_PC_JOYSTICK* = 12
+  TIME_MS* = 1
+  TIME_SAMPLES* = 2
+  TIME_BYTES* = 4
+  TIME_SMPTE* = 8
+  TIME_MIDI* = 16
+  TIME_TICKS* = 32
+  MM_MCINOTIFY* = 0x000003B9
+  MM_WOM_OPEN* = 0x000003BB
+  MM_WOM_CLOSE* = 0x000003BC
+  MM_WOM_DONE* = 0x000003BD
+  MM_WIM_OPEN* = 0x000003BE
+  MM_WIM_CLOSE* = 0x000003BF
+  MM_WIM_DATA* = 0x000003C0
+  MM_MIM_OPEN* = 0x000003C1
+  MM_MIM_CLOSE* = 0x000003C2
+  MM_MIM_DATA* = 0x000003C3
+  MM_MIM_LONGDATA* = 0x000003C4
+  MM_MIM_ERROR* = 0x000003C5
+  MM_MIM_LONGERROR* = 0x000003C6
+  MM_MOM_OPEN* = 0x000003C7
+  MM_MOM_CLOSE* = 0x000003C8
+  MM_MOM_DONE* = 0x000003C9
+  MM_DRVM_OPEN* = 0x000003D0
+  MM_DRVM_CLOSE* = 0x000003D1
+  MM_DRVM_DATA* = 0x000003D2
+  MM_DRVM_ERROR* = 0x000003D3
+  MM_STREAM_OPEN* = 0x000003D4
+  MM_STREAM_CLOSE* = 0x000003D5
+  MM_STREAM_DONE* = 0x000003D6
+  MM_STREAM_ERROR* = 0x000003D7
+  MM_MOM_POSITIONCB* = 0x000003CA
+  MM_MCISIGNAL* = 0x000003CB
+  WAVE_INVALIDFORMAT* = 0
+  WAVE_FORMAT_1M08* = 1
+  WAVE_FORMAT_1S08* = 2
+  WAVE_FORMAT_1M16* = 4
+  WAVE_FORMAT_1S16* = 8
+  WAVE_FORMAT_2M08* = 16
+  WAVE_FORMAT_2S08* = 32
+  WAVE_FORMAT_2M16* = 64
+  WAVE_FORMAT_2S16* = 128
+  WAVE_FORMAT_4M08* = 256
+  WAVE_FORMAT_4S08* = 512
+  WAVE_FORMAT_4M16* = 0x00000400
+  WAVE_FORMAT_4S16* = 0x00000800
+  MM_MIM_MOREDATA* = 0x000003CC
+  MM_MIXM_LINE_CHANGE* = 0x000003D0
+  MM_MIXM_CONTROL_CHANGE* = 0x000003D1
+  MMSYSERR_BASE* = 0
+  WAVERR_BASE* = 32
+  MIDIERR_BASE* = 64
+  TIMERR_BASE* = 96
+  JOYERR_BASE* = 160
+  MCIERR_BASE* = 256
+  MIXERR_BASE* = 1024
+  MCI_STRING_OFFSET* = 512
+  MCI_VD_OFFSET* = 1024
+  MCI_CD_OFFSET* = 1088
+  MCI_WAVE_OFFSET* = 1152
+  MCI_SEQ_OFFSET* = 1216
+  MMSYSERR_NOERROR* = 0
+  MMSYSERR_ERROR* = (MMSYSERR_BASE + 1)
+  MMSYSERR_BADDEVICEID* = (MMSYSERR_BASE + 2)
+  MMSYSERR_NOTENABLED* = (MMSYSERR_BASE + 3)
+  MMSYSERR_ALLOCATED* = (MMSYSERR_BASE + 4)
+  MMSYSERR_INVALHANDLE* = (MMSYSERR_BASE + 5)
+  MMSYSERR_NODRIVER* = (MMSYSERR_BASE + 6)
+  MMSYSERR_NOMEM* = (MMSYSERR_BASE + 7)
+  MMSYSERR_NOTSUPPORTED* = (MMSYSERR_BASE + 8)
+  MMSYSERR_BADERRNUM* = (MMSYSERR_BASE + 9)
+  MMSYSERR_INVALFLAG* = (MMSYSERR_BASE + 10)
+  MMSYSERR_INVALPARAM* = (MMSYSERR_BASE + 11)
+  MMSYSERR_HANDLEBUSY* = (MMSYSERR_BASE + 12)
+  MMSYSERR_INVALIDALIAS* = (MMSYSERR_BASE + 13)
+  MMSYSERR_BADDB* = (MMSYSERR_BASE + 14)
+  MMSYSERR_KEYNOTFOUND* = (MMSYSERR_BASE + 15)
+  MMSYSERR_READERROR* = (MMSYSERR_BASE + 16)
+  MMSYSERR_WRITEERROR* = (MMSYSERR_BASE + 17)
+  MMSYSERR_DELETEERROR* = (MMSYSERR_BASE + 18)
+  MMSYSERR_VALNOTFOUND* = (MMSYSERR_BASE + 19)
+  MMSYSERR_NODRIVERCB* = (MMSYSERR_BASE + 20)
+  MMSYSERR_LASTERROR* = (MMSYSERR_BASE + 20)
+  MM_JOY1MOVE* = 0x000003A0
+  MM_JOY2MOVE* = 0x000003A1
+  MM_JOY1ZMOVE* = 0x000003A2
+  MM_JOY2ZMOVE* = 0x000003A3
+  MM_JOY1BUTTONDOWN* = 0x000003B5
+  MM_JOY2BUTTONDOWN* = 0x000003B6
+  MM_JOY1BUTTONUP* = 0x000003B7
+  MM_JOY2BUTTONUP* = 0x000003B8
+  CALLBACK_TYPEMASK* = 0x00070000
+  CALLBACK_NULL* = 0
+  CALLBACK_EVENT* = 0x00050000
+  CALLBACK_WINDOW* = 0x00010000
+  CALLBACK_TASK* = 0x00020000
+  CALLBACK_THREAD* = CALLBACK_TASK
+  CALLBACK_FUNCTION* = 0x00030000
+
+type
+  HDRVR* = THandle
+
+const
+  DRV_LOAD* = 1
+  DRV_ENABLE* = 2
+  DRV_OPEN* = 0x00000003
+  DRV_CLOSE* = 4
+  DRV_DISABLE* = 0x00000005
+  DRV_FREE* = 0x00000006
+  DRV_CONFIGURE* = 0x00000007
+  DRV_QUERYCONFIGURE* = 8
+  DRV_INSTALL* = 0x00000009
+  DRV_REMOVE* = 0x0000000A
+  DRV_EXITSESSION* = 0x0000000B
+  DRV_POWER* = 0x0000000F
+  DRV_RESERVED* = 0x00000800
+  DRV_USER* = 0x00004000
+  DRVCNF_CANCEL* = 0
+  DRVCNF_OK* = 1
+  DRVCNF_RESTART* = 2
+  DRV_CANCEL* = DRVCNF_CANCEL
+  DRV_OK* = DRVCNF_OK
+  DRV_RESTART* = DRVCNF_RESTART
+  DRV_MCI_FIRST* = DRV_RESERVED
+  DRV_MCI_LAST* = (DRV_RESERVED + 0x00000FFF)
+
+type
+  PDRVCALLBACK* = proc (hdrvr: THandle, uMsg: uint32, dwUser, dw1, dw2: DWORD){.
+      stdcall.}
+
+proc sndPlaySoundA*(Name: LPCSTR, flags: uint32): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "sndPlaySoundA".}
+proc sndPlaySoundW*(Name: LPCWSTR, flags: uint32): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "sndPlaySoundW".}
+when defined(winUNICODE):
+  proc sndPlaySound*(Name: cstring, flags: uint32): bool{.stdcall,
+      dynlib: "winmm.dll", importc: "sndPlaySoundW".}
+else:
+  proc sndPlaySound*(Name: cstring, flags: uint32): bool{.stdcall,
+      dynlib: "winmm.dll", importc: "sndPlaySoundA".}
+const
+  SND_NODEFAULT* = 2
+  SND_MEMORY* = 4
+  SND_LOOP* = 8
+  SND_NOSTOP* = 16
+  SND_SYNC* = 0
+  SND_ASYNC* = 1
+  SND_PURGE* = 64
+  SND_APPLICATION* = 128
+  SND_ALIAS_START* = 0
+  SND_ALIAS_SYSTEMHAND* = 18515
+  SND_ALIAS_SYSTEMEXCLAMATION* = 8531
+  SND_ALIAS_SYSTEMASTERISK* = 10835
+  SND_ALIAS_SYSTEMQUESTION* = 16211
+  SND_ALIAS_SYSTEMDEFAULT* = 17491
+  SND_ALIAS_SYSTEMEXIT* = 17747
+  SND_ALIAS_SYSTEMSTART* = 21331
+  SND_ALIAS_SYSTEMWELCOME* = 22355
+  SND_NOWAIT* = 0x00002000
+  SND_ALIAS* = 0x00010000
+  SND_ALIAS_ID* = 0x00110000
+  SND_FILENAME* = 0x00020000
+  SND_RESOURCE* = 0x00040004
+  WAVERR_BADFORMAT* = (WAVERR_BASE + 0)
+  WAVERR_STILLPLAYING* = (WAVERR_BASE + 1)
+  WAVERR_UNPREPARED* = (WAVERR_BASE + 2)
+  WAVERR_SYNC* = (WAVERR_BASE + 3)
+  WAVERR_LASTERROR* = (WAVERR_BASE + 3)
+  WOM_OPEN* = MM_WOM_OPEN
+  WOM_CLOSE* = MM_WOM_CLOSE
+  WOM_DONE* = MM_WOM_DONE
+  WIM_OPEN* = MM_WIM_OPEN
+  WIM_CLOSE* = MM_WIM_CLOSE
+  WIM_DATA* = MM_WIM_DATA
+  WAVE_MAPPER* = uint32(- 1)
+  WAVE_FORMAT_QUERY* = 1
+  WAVE_ALLOWSYNC* = 2
+  WAVE_MAPPED* = 4
+  WAVE_FORMAT_DIRECT* = 8
+  WAVE_FORMAT_DIRECT_QUERY* = (WAVE_FORMAT_QUERY or WAVE_FORMAT_DIRECT)
+  MIM_OPEN* = MM_MIM_OPEN
+  MIM_CLOSE* = MM_MIM_CLOSE
+  MIM_DATA* = MM_MIM_DATA
+  MIM_LONGDATA* = MM_MIM_LONGDATA
+  MIM_ERROR* = MM_MIM_ERROR
+  MIM_LONGERROR* = MM_MIM_LONGERROR
+  MOM_OPEN* = MM_MOM_OPEN
+  MOM_CLOSE* = MM_MOM_CLOSE
+  MOM_DONE* = MM_MOM_DONE
+  MIM_MOREDATA* = MM_MIM_MOREDATA
+  MOM_POSITIONCB* = MM_MOM_POSITIONCB
+  MIDIMAPPER* = uint32(- 1)
+  MIDI_IO_STATUS* = 32
+  MIDI_CACHE_ALL* = 1
+  MIDI_CACHE_BESTFIT* = 2
+  MIDI_CACHE_QUERY* = 3
+  MIDI_UNCACHE* = 4
+  WHDR_DONE* = 1
+  WHDR_PREPARED* = 2
+  WHDR_BEGINLOOP* = 0x00000004
+  WHDR_ENDLOOP* = 0x00000008
+  WHDR_INQUEUE* = 0x00000010
+  MOD_MIDIPORT* = 1
+  MOD_SYNTH* = 2
+  MOD_SQSYNTH* = 3
+  MOD_FMSYNTH* = 4
+  MOD_MAPPER* = 5
+  MIDICAPS_VOLUME* = 1
+  MIDICAPS_LRVOLUME* = 2
+  MIDICAPS_CACHE* = 4
+  MIDICAPS_STREAM* = 8
+  MHDR_DONE* = 1
+  MHDR_PREPARED* = 2
+  MHDR_INQUEUE* = 0x00000004
+  MHDR_ISSTRM* = 0x00000008
+  MEVT_F_SHORT* = 0
+  MEVT_F_LONG* = 0x80000000
+  MEVT_F_CALLBACK* = 0x40000000
+
+proc MEVT_EVENTTYPE*(x: int8): int8
+proc MEVT_EVENTPARM*(x: DWORD): DWORD
+const
+  MEVT_SHORTMSG* = 0
+  MEVT_TEMPO* = 0x00000001
+  MEVT_NOP* = 0x00000002
+  MEVT_LONGMSG* = 0x00000080
+  MEVT_COMMENT* = 0x00000082
+  MEVT_VERSION* = 0x00000084
+  MIDISTRM_ERROR* = - 2
+  MIDIPROP_SET* = 0x80000000
+  MIDIPROP_GET* = 0x40000000
+  MIDIPROP_TIMEDIV* = 1
+  MIDIPROP_TEMPO* = 2
+  MIXERLINE_LINEF_ACTIVE* = 1
+  MIXERLINE_LINEF_DISCONNECTED* = 0x00008000
+  MIXERLINE_LINEF_SOURCE* = 0x80000000
+  MIXERLINE_COMPONENTTYPE_DST_FIRST* = 0
+  MIXERLINE_COMPONENTTYPE_DST_UNDEFINED* = (MIXERLINE_COMPONENTTYPE_DST_FIRST)
+  MIXERLINE_COMPONENTTYPE_DST_DIGITAL* = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 1)
+  MIXERLINE_COMPONENTTYPE_DST_LINE* = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 2)
+  MIXERLINE_COMPONENTTYPE_DST_MONITOR* = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 3)
+  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS* = (MIXERLINE_COMPONENTTYPE_DST_FIRST +
+      4)
+  MIXERLINE_COMPONENTTYPE_DST_HEADPHONES* = (
+    MIXERLINE_COMPONENTTYPE_DST_FIRST + 5)
+  MIXERLINE_COMPONENTTYPE_DST_TELEPHONE* = (
+    MIXERLINE_COMPONENTTYPE_DST_FIRST + 6)
+  MIXERLINE_COMPONENTTYPE_DST_WAVEIN* = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 7)
+  MIXERLINE_COMPONENTTYPE_DST_VOICEIN* = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 8)
+  MIXERLINE_COMPONENTTYPE_DST_LAST* = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 8)
+  MIXERLINE_COMPONENTTYPE_SRC_FIRST* = 0x00001000
+  MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 0)
+  MIXERLINE_COMPONENTTYPE_SRC_DIGITAL* = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 1)
+  MIXERLINE_COMPONENTTYPE_SRC_LINE* = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 2)
+  MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 3)
+  MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 4)
+  MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 5)
+  MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 6)
+  MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 7)
+  MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT* = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 8)
+  MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY* = (
+    MIXERLINE_COMPONENTTYPE_SRC_FIRST + 9)
+  MIXERLINE_COMPONENTTYPE_SRC_ANALOG* = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10)
+  MIXERLINE_COMPONENTTYPE_SRC_LAST* = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10)
+  MIXERLINE_TARGETTYPE_UNDEFINED* = 0
+  MIXERLINE_TARGETTYPE_WAVEOUT* = 1
+  MIXERLINE_TARGETTYPE_WAVEIN* = 2
+  MIXERLINE_TARGETTYPE_MIDIOUT* = 3
+  MIXERLINE_TARGETTYPE_MIDIIN* = 4
+  MIXERLINE_TARGETTYPE_AUX* = 5
+  MIDIERR_UNPREPARED* = (MIDIERR_BASE + 0)
+  MIDIERR_STILLPLAYING* = (MIDIERR_BASE + 1)
+  MIDIERR_NOMAP* = (MIDIERR_BASE + 2)
+  MIDIERR_NOTREADY* = (MIDIERR_BASE + 3)
+  MIDIERR_NODEVICE* = (MIDIERR_BASE + 4)
+  MIDIERR_INVALIDSETUP* = (MIDIERR_BASE + 5)
+  MIDIERR_BADOPENMODE* = (MIDIERR_BASE + 6)
+  MIDIERR_DONT_CONTINUE* = (MIDIERR_BASE + 7)
+  MIDIERR_LASTERROR* = (MIDIERR_BASE + 7)
+  MIXERCONTROL_CONTROLF_UNIFORM* = 1
+  MIXERCONTROL_CONTROLF_MULTIPLE* = 2
+  MIXERCONTROL_CONTROLF_DISABLED* = 0x80000000
+  MIXERCONTROL_CT_CLASS_MASK* = 0xF0000000
+  MIXERCONTROL_CT_CLASS_CUSTOM* = 0
+  MIXERCONTROL_CT_CLASS_METER* = 0x10000000
+  MIXERCONTROL_CT_CLASS_SWITCH* = 0x20000000
+  MIXERCONTROL_CT_CLASS_NUMBER* = 0x30000000
+  MIXERCONTROL_CT_CLASS_SLIDER* = 0x40000000
+  MIXERCONTROL_CT_CLASS_FADER* = 0x50000000
+  MIXERCONTROL_CT_CLASS_TIME* = 0x60000000
+  MIXERCONTROL_CT_CLASS_LIST* = 0x70000000
+  MIXERCONTROL_CT_SUBCLASS_MASK* = 0x0F000000
+  MIXERCONTROL_CT_SC_SWITCH_BOOLEAN* = 0
+  MIXERCONTROL_CT_SC_SWITCH_BUTTON* = 0x01000000
+  MIXERCONTROL_CT_SC_METER_POLLED* = 0
+  MIXERCONTROL_CT_SC_TIME_MICROSECS* = 0
+  MIXERCONTROL_CT_SC_TIME_MILLISECS* = 0x01000000
+  MIXERCONTROL_CT_SC_LIST_SINGLE* = 0
+  MIXERCONTROL_CT_SC_LIST_MULTIPLE* = 0x01000000
+  MIXERCONTROL_CT_UNITS_MASK* = 0x00FF0000
+  MIXERCONTROL_CT_UNITS_CUSTOM* = 0
+  MIXERCONTROL_CT_UNITS_BOOLEAN* = 0x00010000
+  MIXERCONTROL_CT_UNITS_SIGNED* = 0x00020000
+  MIXERCONTROL_CT_UNITS_UNSIGNED* = 0x00030000
+  MIXERCONTROL_CT_UNITS_DECIBELS* = 0x00040000
+  MIXERCONTROL_CT_UNITS_PERCENT* = 0x00050000
+  MIXERCONTROL_CONTROLTYPE_CUSTOM* = (
+    MIXERCONTROL_CT_CLASS_CUSTOM or MIXERCONTROL_CT_UNITS_CUSTOM)
+  MIXERCONTROL_CONTROLTYPE_BOOLEANMETER* = (MIXERCONTROL_CT_CLASS_METER or
+      MIXERCONTROL_CT_SC_METER_POLLED or MIXERCONTROL_CT_UNITS_BOOLEAN)
+  MIXERCONTROL_CONTROLTYPE_SIGNEDMETER* = (MIXERCONTROL_CT_CLASS_METER or
+      MIXERCONTROL_CT_SC_METER_POLLED or MIXERCONTROL_CT_UNITS_SIGNED)
+  MIXERCONTROL_CONTROLTYPE_PEAKMETER* = (
+    MIXERCONTROL_CONTROLTYPE_SIGNEDMETER + 1)
+  MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER* = (MIXERCONTROL_CT_CLASS_METER or
+      MIXERCONTROL_CT_SC_METER_POLLED or MIXERCONTROL_CT_UNITS_UNSIGNED)
+  MIXERCONTROL_CONTROLTYPE_BOOLEAN* = (MIXERCONTROL_CT_CLASS_SWITCH or
+      MIXERCONTROL_CT_SC_SWITCH_BOOLEAN or MIXERCONTROL_CT_UNITS_BOOLEAN)
+  MIXERCONTROL_CONTROLTYPE_ONOFF* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1)
+  MIXERCONTROL_CONTROLTYPE_MUTE* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2)
+  MIXERCONTROL_CONTROLTYPE_MONO* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3)
+  MIXERCONTROL_CONTROLTYPE_LOUDNESS* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4)
+  MIXERCONTROL_CONTROLTYPE_STEREOENH* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5)
+  MIXERCONTROL_CONTROLTYPE_BUTTON* = (MIXERCONTROL_CT_CLASS_SWITCH or
+      MIXERCONTROL_CT_SC_SWITCH_BUTTON or MIXERCONTROL_CT_UNITS_BOOLEAN)
+  MIXERCONTROL_CONTROLTYPE_DECIBELS* = (
+    MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_DECIBELS)
+  MIXERCONTROL_CONTROLTYPE_SIGNED* = (
+    MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_SIGNED)
+  MIXERCONTROL_CONTROLTYPE_UNSIGNED* = (
+    MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_UNSIGNED)
+  MIXERCONTROL_CONTROLTYPE_PERCENT* = (
+    MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_PERCENT)
+  MIXERCONTROL_CONTROLTYPE_SLIDER* = (
+    MIXERCONTROL_CT_CLASS_SLIDER or MIXERCONTROL_CT_UNITS_SIGNED)
+  MIXERCONTROL_CONTROLTYPE_PAN* = (MIXERCONTROL_CONTROLTYPE_SLIDER + 1)
+  MIXERCONTROL_CONTROLTYPE_QSOUNDPAN* = (MIXERCONTROL_CONTROLTYPE_SLIDER + 2)
+  MIXERCONTROL_CONTROLTYPE_FADER* = (
+    MIXERCONTROL_CT_CLASS_FADER or MIXERCONTROL_CT_UNITS_UNSIGNED)
+  MIXERCONTROL_CONTROLTYPE_VOLUME* = (MIXERCONTROL_CONTROLTYPE_FADER + 1)
+  MIXERCONTROL_CONTROLTYPE_BASS* = (MIXERCONTROL_CONTROLTYPE_FADER + 2)
+  MIXERCONTROL_CONTROLTYPE_TREBLE* = (MIXERCONTROL_CONTROLTYPE_FADER + 3)
+  MIXERCONTROL_CONTROLTYPE_EQUALIZER* = (MIXERCONTROL_CONTROLTYPE_FADER + 4)
+  MIXERCONTROL_CONTROLTYPE_SINGLESELECT* = (MIXERCONTROL_CT_CLASS_LIST or
+      MIXERCONTROL_CT_SC_LIST_SINGLE or MIXERCONTROL_CT_UNITS_BOOLEAN)
+  MIXERCONTROL_CONTROLTYPE_MUX* = (MIXERCONTROL_CONTROLTYPE_SINGLESELECT + 1)
+  MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT* = (MIXERCONTROL_CT_CLASS_LIST or
+      MIXERCONTROL_CT_SC_LIST_MULTIPLE or MIXERCONTROL_CT_UNITS_BOOLEAN)
+  MIXERCONTROL_CONTROLTYPE_MIXER* = (MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT +
+      1)
+  MIXERCONTROL_CONTROLTYPE_MICROTIME* = (MIXERCONTROL_CT_CLASS_TIME or
+      MIXERCONTROL_CT_SC_TIME_MICROSECS or MIXERCONTROL_CT_UNITS_UNSIGNED)
+  MIXERCONTROL_CONTROLTYPE_MILLITIME* = (MIXERCONTROL_CT_CLASS_TIME or
+      MIXERCONTROL_CT_SC_TIME_MILLISECS or MIXERCONTROL_CT_UNITS_UNSIGNED)
+  MIXER_SHORT_NAME_CHARS* = 16
+  MIXER_LONG_NAME_CHARS* = 64
+  MIXERR_INVALLINE* = (MIXERR_BASE + 0)
+  MIXERR_INVALCONTROL* = (MIXERR_BASE + 1)
+  MIXERR_INVALVALUE* = (MIXERR_BASE + 2)
+  MIXERR_LASTERROR* = (MIXERR_BASE + 2)
+  MIXER_OBJECTF_HANDLE* = 0x80000000
+  MIXER_OBJECTF_MIXER* = 0
+  MIXER_OBJECTF_HMIXER* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_MIXER)
+  MIXER_OBJECTF_WAVEOUT* = 0x10000000
+  MIXER_OBJECTF_HWAVEOUT* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_WAVEOUT)
+  MIXER_OBJECTF_WAVEIN* = 0x20000000
+  MIXER_OBJECTF_HWAVEIN* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_WAVEIN)
+  MIXER_OBJECTF_MIDIOUT* = 0x30000000
+  MIXER_OBJECTF_HMIDIOUT* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_MIDIOUT)
+  MIXER_OBJECTF_MIDIIN* = 0x40000000
+  MIXER_OBJECTF_HMIDIIN* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_MIDIIN)
+  MIXER_OBJECTF_AUX* = 0x50000000
+  MIXER_GETCONTROLDETAILSF_VALUE* = 0
+  MIXER_GETCONTROLDETAILSF_LISTTEXT* = 1
+  MIXER_GETCONTROLDETAILSF_QUERYMASK* = 0x0000000F
+  MIXER_SETCONTROLDETAILSF_VALUE* = 0
+  MIXER_SETCONTROLDETAILSF_CUSTOM* = 1
+  MIXER_SETCONTROLDETAILSF_QUERYMASK* = 0x0000000F
+  JOYERR_NOERROR* = (0)
+  JOYERR_PARMS* = (JOYERR_BASE + 5)
+  JOYERR_NOCANDO* = (JOYERR_BASE + 6)
+  JOYERR_UNPLUGGED* = (JOYERR_BASE + 7)
+  JOY_BUTTON1* = 1
+  JOY_BUTTON2* = 2
+  JOY_BUTTON3* = 4
+  JOY_BUTTON4* = 8
+  JOY_BUTTON1CHG* = 256
+  JOY_BUTTON2CHG* = 512
+  JOY_BUTTON3CHG* = 0x00000400
+  JOY_BUTTON4CHG* = 0x00000800
+  JOY_BUTTON5* = 16
+  JOY_BUTTON6* = 32
+  JOY_BUTTON7* = 64
+  JOY_BUTTON8* = 128
+  JOY_BUTTON9* = 256
+  JOY_BUTTON10* = 512
+  JOY_BUTTON11* = 0x00000400
+  JOY_BUTTON12* = 0x00000800
+  JOY_BUTTON13* = 0x00001000
+  JOY_BUTTON14* = 0x00002000
+  JOY_BUTTON15* = 0x00004000
+  JOY_BUTTON16* = 0x00008000
+  JOY_BUTTON17* = 0x00010000
+  JOY_BUTTON18* = 0x00020000
+  JOY_BUTTON19* = 0x00040000
+  JOY_BUTTON20* = 0x00080000
+  JOY_BUTTON21* = 0x00100000
+  JOY_BUTTON22* = 0x00200000
+  JOY_BUTTON23* = 0x00400000
+  JOY_BUTTON24* = 0x00800000
+  JOY_BUTTON25* = 0x01000000
+  JOY_BUTTON26* = 0x02000000
+  JOY_BUTTON27* = 0x04000000
+  JOY_BUTTON28* = 0x08000000
+  JOY_BUTTON29* = 0x10000000
+  JOY_BUTTON30* = 0x20000000
+  JOY_BUTTON31* = 0x40000000
+  JOY_BUTTON32* = 0x80000000
+  JOY_POVCENTERED* = - 1
+  JOY_POVFORWARD* = 0
+  JOY_POVRIGHT* = 9000
+  JOY_POVBACKWARD* = 18000
+  JOY_POVLEFT* = 27000
+  JOY_RETURNX* = 1
+  JOY_RETURNY* = 2
+  JOY_RETURNZ* = 4
+  JOY_RETURNR* = 8
+  JOY_RETURNU* = 16
+  JOY_RETURNV* = 32
+  JOY_RETURNPOV* = 64
+  JOY_RETURNBUTTONS* = 128
+  JOY_RETURNRAWDATA* = 256
+  JOY_RETURNPOVCTS* = 512
+  JOY_RETURNCENTERED* = 0x00000400
+  JOY_USEDEADZONE* = 0x00000800
+  JOY_RETURNALL* = (JOY_RETURNX or JOY_RETURNY or JOY_RETURNZ or JOY_RETURNR or
+      JOY_RETURNU or JOY_RETURNV or JOY_RETURNPOV or JOY_RETURNBUTTONS)
+  JOY_CAL_READALWAYS* = 0x00010000
+  JOY_CAL_READXYONLY* = 0x00020000
+  JOY_CAL_READ3* = 0x00040000
+  JOY_CAL_READ4* = 0x00080000
+  JOY_CAL_READXONLY* = 0x00100000
+  JOY_CAL_READYONLY* = 0x00200000
+  JOY_CAL_READ5* = 0x00400000
+  JOY_CAL_READ6* = 0x00800000
+  JOY_CAL_READZONLY* = 0x01000000
+  JOY_CAL_READRONLY* = 0x02000000
+  JOY_CAL_READUONLY* = 0x04000000
+  JOY_CAL_READVONLY* = 0x08000000
+  JOYSTICKID1* = 0
+  JOYSTICKID2* = 1
+  JOYCAPS_HASZ* = 1
+  JOYCAPS_HASR* = 2
+  JOYCAPS_HASU* = 4
+  JOYCAPS_HASV* = 8
+  JOYCAPS_HASPOV* = 16
+  JOYCAPS_POV4DIR* = 32
+  JOYCAPS_POVCTS* = 64
+  MMIOERR_BASE* = 256
+  MMIOERR_FILENOTFOUND* = (MMIOERR_BASE + 1)
+  MMIOERR_OUTOFMEMORY* = (MMIOERR_BASE + 2)
+  MMIOERR_CANNOTOPEN* = (MMIOERR_BASE + 3)
+  MMIOERR_CANNOTCLOSE* = (MMIOERR_BASE + 4)
+  MMIOERR_CANNOTREAD* = (MMIOERR_BASE + 5)
+  MMIOERR_CANNOTWRITE* = (MMIOERR_BASE + 6)
+  MMIOERR_CANNOTSEEK* = (MMIOERR_BASE + 7)
+  MMIOERR_CANNOTEXPAND* = (MMIOERR_BASE + 8)
+  MMIOERR_CHUNKNOTFOUND* = (MMIOERR_BASE + 9)
+  MMIOERR_UNBUFFERED* = (MMIOERR_BASE + 10)
+  MMIOERR_PATHNOTFOUND* = (MMIOERR_BASE + 11)
+  MMIOERR_ACCESSDENIED* = (MMIOERR_BASE + 12)
+  MMIOERR_SHARINGVIOLATION* = (MMIOERR_BASE + 13)
+  MMIOERR_NETWORKERROR* = (MMIOERR_BASE + 14)
+  MMIOERR_TOOMANYOPENFILES* = (MMIOERR_BASE + 15)
+  MMIOERR_INVALIDFILE* = (MMIOERR_BASE + 16)
+  CFSEPCHAR* = '+'
+  WAVECAPS_PITCH* = 1
+  WAVECAPS_PLAYBACKRATE* = 2
+  WAVECAPS_VOLUME* = 4
+  WAVECAPS_LRVOLUME* = 8
+  WAVECAPS_SYNC* = 16
+  WAVECAPS_SAMPLEACCURATE* = 32
+  WAVECAPS_DIRECTSOUND* = 64
+  MIXER_GETLINEINFOF_DESTINATION* = 0
+  MIXER_GETLINEINFOF_SOURCE* = 1
+  MIXER_GETLINEINFOF_LINEID* = 2
+  MIXER_GETLINEINFOF_COMPONENTTYPE* = 3
+  MIXER_GETLINEINFOF_TARGETTYPE* = 4
+  MIXER_GETLINEINFOF_QUERYMASK* = 0x0000000F
+  MMIO_RWMODE* = 3
+  MMIO_SHAREMODE* = 0x00000070
+  MMIO_CREATE* = 0x00001000
+  MMIO_PARSE* = 256
+  MMIO_DELETE* = 512
+  MMIO_EXIST* = 0x00004000
+  MMIO_ALLOCBUF* = 0x00010000
+  MMIO_GETTEMP* = 0x00020000
+  MMIO_DIRTY* = 0x10000000
+  cMMIO_READ* = 0
+  cMMIO_WRITE* = 1
+  MMIO_READWRITE* = 2
+  MMIO_COMPAT* = 0
+  MMIO_EXCLUSIVE* = 16
+  MMIO_DENYWRITE* = 32
+  MMIO_DENYREAD* = 0x00000030
+  MMIO_DENYNONE* = 64
+  MMIO_FHOPEN* = 16
+  MMIO_EMPTYBUF* = 16
+  MMIO_TOUPPER* = 16
+  MMIO_INSTALLPROC* = 0x00010000
+  MMIO_GLOBALPROC* = 0x10000000
+  MMIO_REMOVEPROC* = 0x00020000
+  MMIO_UNICODEPROC* = 0x01000000
+  MMIO_FINDPROC* = 0x00040000
+  MMIO_FINDCHUNK* = 16
+  MMIO_FINDRIFF* = 32
+  MMIO_FINDLIST* = 64
+  MMIO_CREATERIFF* = 32
+  MMIO_CREATELIST* = 64
+  MMIOM_READ* = cMMIO_READ
+  MMIOM_WRITE* = cMMIO_WRITE
+  MMIOM_SEEK* = 2
+  MMIOM_OPEN* = 3
+  MMIOM_CLOSE* = 4
+  MMIOM_WRITEFLUSH* = 5
+  MMIOM_RENAME* = 6
+  MMIOM_USER* = 0x00008000
+  FOURCC_RIFF* = 0x46464952   #'R','I','F','F'
+  FOURCC_LIST* = 0x5453494C   #'L','I','S','T'
+  FOURCC_DOS* = 0x20532F44    #'D','O','S',' '
+  FOURCC_MEM* = 0x204D454D    #'M','E','M',' '
+  SEEK_SET* = 0
+  SEEK_CUR* = 1
+  SEEK_END* = 2
+  MMIO_DEFAULTBUFFER* = 8192
+  MCIERR_INVALID_DEVICE_ID* = (MCIERR_BASE + 1)
+  MCIERR_UNRECOGNIZED_KEYWORD* = (MCIERR_BASE + 3)
+  MCIERR_UNRECOGNIZED_COMMAND* = (MCIERR_BASE + 5)
+  MCIERR_HARDWARE* = (MCIERR_BASE + 6)
+  MCIERR_INVALID_DEVICE_NAME* = (MCIERR_BASE + 7)
+  MCIERR_OUT_OF_MEMORY* = (MCIERR_BASE + 8)
+  MCIERR_DEVICE_OPEN* = (MCIERR_BASE + 9)
+  MCIERR_CANNOT_LOAD_DRIVER* = (MCIERR_BASE + 10)
+  MCIERR_MISSING_COMMAND_STRING* = (MCIERR_BASE + 11)
+  MCIERR_PARAM_OVERFLOW* = (MCIERR_BASE + 12)
+  MCIERR_MISSING_STRING_ARGUMENT* = (MCIERR_BASE + 13)
+  MCIERR_BAD_INTEGER* = (MCIERR_BASE + 14)
+  MCIERR_PARSER_INTERNAL* = (MCIERR_BASE + 15)
+  MCIERR_DRIVER_INTERNAL* = (MCIERR_BASE + 16)
+  MCIERR_MISSING_PARAMETER* = (MCIERR_BASE + 17)
+  MCIERR_UNSUPPORTED_FUNCTION* = (MCIERR_BASE + 18)
+  MCIERR_FILE_NOT_FOUND* = (MCIERR_BASE + 19)
+  MCIERR_DEVICE_NOT_READY* = (MCIERR_BASE + 20)
+  MCIERR_INTERNAL* = (MCIERR_BASE + 21)
+  MCIERR_DRIVER* = (MCIERR_BASE + 22)
+  MCIERR_CANNOT_USE_ALL* = (MCIERR_BASE + 23)
+  MCIERR_MULTIPLE* = (MCIERR_BASE + 24)
+  MCIERR_EXTENSION_NOT_FOUND* = (MCIERR_BASE + 25)
+  MCIERR_OUTOFRANGE* = (MCIERR_BASE + 26)
+  MCIERR_FLAGS_NOT_COMPATIBLE* = (MCIERR_BASE + 28)
+  MCIERR_FILE_NOT_SAVED* = (MCIERR_BASE + 30)
+  MCIERR_DEVICE_TYPE_REQUIRED* = (MCIERR_BASE + 31)
+  MCIERR_DEVICE_LOCKED* = (MCIERR_BASE + 32)
+  MCIERR_DUPLICATE_ALIAS* = (MCIERR_BASE + 33)
+  MCIERR_BAD_CONSTANT* = (MCIERR_BASE + 34)
+  MCIERR_MUST_USE_SHAREABLE* = (MCIERR_BASE + 35)
+  MCIERR_MISSING_DEVICE_NAME* = (MCIERR_BASE + 36)
+  MCIERR_BAD_TIME_FORMAT* = (MCIERR_BASE + 37)
+  MCIERR_NO_CLOSING_QUOTE* = (MCIERR_BASE + 38)
+  MCIERR_DUPLICATE_FLAGS* = (MCIERR_BASE + 39)
+  MCIERR_INVALID_FILE* = (MCIERR_BASE + 40)
+  MCIERR_NULL_PARAMETER_BLOCK* = (MCIERR_BASE + 41)
+  MCIERR_UNNAMED_RESOURCE* = (MCIERR_BASE + 42)
+  MCIERR_NEW_REQUIRES_ALIAS* = (MCIERR_BASE + 43)
+  MCIERR_NOTIFY_ON_AUTO_OPEN* = (MCIERR_BASE + 44)
+  MCIERR_NO_ELEMENT_ALLOWED* = (MCIERR_BASE + 45)
+  MCIERR_NONAPPLICABLE_FUNCTION* = (MCIERR_BASE + 46)
+  MCIERR_ILLEGAL_FOR_AUTO_OPEN* = (MCIERR_BASE + 47)
+  MCIERR_FILENAME_REQUIRED* = (MCIERR_BASE + 48)
+  MCIERR_EXTRA_CHARACTERS* = (MCIERR_BASE + 49)
+  MCIERR_DEVICE_NOT_INSTALLED* = (MCIERR_BASE + 50)
+  MCIERR_GET_CD* = (MCIERR_BASE + 51)
+  MCIERR_SET_CD* = (MCIERR_BASE + 52)
+  MCIERR_SET_DRIVE* = (MCIERR_BASE + 53)
+  MCIERR_DEVICE_LENGTH* = (MCIERR_BASE + 54)
+  MCIERR_DEVICE_ORD_LENGTH* = (MCIERR_BASE + 55)
+  MCIERR_NO_INTEGER* = (MCIERR_BASE + 56)
+  MCIERR_WAVE_OUTPUTSINUSE* = (MCIERR_BASE + 64)
+  MCIERR_WAVE_SETOUTPUTINUSE* = (MCIERR_BASE + 65)
+  MCIERR_WAVE_INPUTSINUSE* = (MCIERR_BASE + 66)
+  MCIERR_WAVE_SETINPUTINUSE* = (MCIERR_BASE + 67)
+  MCIERR_WAVE_OUTPUTUNSPECIFIED* = (MCIERR_BASE + 68)
+  MCIERR_WAVE_INPUTUNSPECIFIED* = (MCIERR_BASE + 69)
+  MCIERR_WAVE_OUTPUTSUNSUITABLE* = (MCIERR_BASE + 70)
+  MCIERR_WAVE_SETOUTPUTUNSUITABLE* = (MCIERR_BASE + 71)
+  MCIERR_WAVE_INPUTSUNSUITABLE* = (MCIERR_BASE + 72)
+  MCIERR_WAVE_SETINPUTUNSUITABLE* = (MCIERR_BASE + 73)
+  MCIERR_SEQ_DIV_INCOMPATIBLE* = (MCIERR_BASE + 80)
+  MCIERR_SEQ_PORT_INUSE* = (MCIERR_BASE + 81)
+  MCIERR_SEQ_PORT_NONEXISTENT* = (MCIERR_BASE + 82)
+  MCIERR_SEQ_PORT_MAPNODEVICE* = (MCIERR_BASE + 83)
+  MCIERR_SEQ_PORT_MISCERROR* = (MCIERR_BASE + 84)
+  MCIERR_SEQ_TIMER* = (MCIERR_BASE + 85)
+  MCIERR_SEQ_PORTUNSPECIFIED* = (MCIERR_BASE + 86)
+  MCIERR_SEQ_NOMIDIPRESENT* = (MCIERR_BASE + 87)
+  MCIERR_NO_WINDOW* = (MCIERR_BASE + 90)
+  MCIERR_CREATEWINDOW* = (MCIERR_BASE + 91)
+  MCIERR_FILE_READ* = (MCIERR_BASE + 92)
+  MCIERR_FILE_WRITE* = (MCIERR_BASE + 93)
+  MCIERR_NO_IDENTITY* = (MCIERR_BASE + 94)
+  MCIERR_CUSTOM_DRIVER_BASE* = (MCIERR_BASE + 256)
+  MCI_FIRST* = DRV_MCI_FIRST
+  MCI_ESCAPE* = 0x00000805
+  MCI_PLAY* = 0x00000806
+  MCI_SEEK* = 0x00000807
+  MCI_STOP* = 0x00000808
+  MCI_PAUSE* = 0x00000809
+  MCI_INFO* = 0x0000080A
+  MCI_GETDEVCAPS* = 0x0000080B
+  MCI_BREAK* = 0x00000811
+  MCI_WHERE* = 0x00000843
+  MCI_FREEZE* = 0x00000844
+  MCI_UNFREEZE* = 0x00000845
+  MCI_LOAD* = 0x00000850
+  MCI_CUT* = 0x00000851
+  MCI_COPY* = 0x00000852
+  MCI_PASTE* = 0x00000853
+  MCI_UPDATE* = 0x00000854
+  MCI_RESUME* = 0x00000855
+  MCI_DELETE* = 0x00000856
+  MCI_SET* = 0x0000080D
+  MCI_STEP* = 0x0000080E
+  MCI_SAVE* = 0x00000813
+  MCI_SPIN* = 0x0000080C
+  MCI_STATUS* = 0x00000814
+  MCI_CUE* = 0x00000830
+  MCI_REALIZE* = 0x00000840
+  MCI_WINDOW* = 0x00000841
+  MCI_PUT* = 0x00000842
+  MCI_RECORD* = 0x0000080F
+  MCI_SYSINFO* = 0x00000810
+  MCI_OPEN* = 0x00000803
+  MCI_CLOSE* = 0x00000804
+  MCI_USER_MESSAGES* = (DRV_MCI_FIRST + 0x00000400)
+  MCI_LAST* = 0x00000FFF
+  MCI_ALL_DEVICE_ID* = - 1
+  MCI_DEVTYPE_VCR* = 513
+  MCI_DEVTYPE_VIDEODISC* = 514
+  MCI_DEVTYPE_OVERLAY* = 515
+  MCI_DEVTYPE_CD_AUDIO* = 516
+  MCI_DEVTYPE_DAT* = 517
+  MCI_DEVTYPE_SCANNER* = 518
+  MCI_DEVTYPE_ANIMATION* = 519
+  MCI_DEVTYPE_DIGITAL_VIDEO* = 520
+  MCI_DEVTYPE_OTHER* = 521
+  MCI_DEVTYPE_WAVEFORM_AUDIO* = 522
+  MCI_DEVTYPE_SEQUENCER* = 523
+  MCI_DEVTYPE_FIRST* = MCI_DEVTYPE_VCR
+  MCI_DEVTYPE_LAST* = MCI_DEVTYPE_SEQUENCER
+  MCI_DEVTYPE_FIRST_USER* = 0x00001000
+  MCI_MODE_NOT_READY* = (MCI_STRING_OFFSET + 12)
+  MCI_MODE_STOP* = (MCI_STRING_OFFSET + 13)
+  MCI_MODE_PLAY* = (MCI_STRING_OFFSET + 14)
+  MCI_MODE_RECORD* = (MCI_STRING_OFFSET + 15)
+  MCI_MODE_SEEK* = (MCI_STRING_OFFSET + 16)
+  MCI_MODE_PAUSE* = (MCI_STRING_OFFSET + 17)
+  MCI_MODE_OPEN* = (MCI_STRING_OFFSET + 18)
+  MCI_FORMAT_MILLISECONDS* = 0
+  MCI_FORMAT_HMS* = 1
+  MCI_FORMAT_MSF* = 2
+  MCI_FORMAT_FRAMES* = 3
+  MCI_FORMAT_SMPTE_24* = 4
+  MCI_FORMAT_SMPTE_25* = 5
+  MCI_FORMAT_SMPTE_30* = 6
+  MCI_FORMAT_SMPTE_30DROP* = 7
+  MCI_FORMAT_BYTES* = 8
+  MCI_FORMAT_SAMPLES* = 9
+  MCI_FORMAT_TMSF* = 10
+
+proc MCI_MSF_MINUTE*(msf: int32): int8
+proc MCI_MSF_SECOND*(msf: int32): int8
+proc MCI_MSF_FRAME*(msf: int32): int8
+proc MCI_MAKE_MSF*(m, s, f: int8): int32
+const
+  MCI_SET_DOOR_OPEN* = 256
+  MCI_SET_DOOR_CLOSED* = 512
+  MCI_SET_TIME_FORMAT* = 0x00000400
+  MCI_SET_AUDIO* = 0x00000800
+  MCI_SET_VIDEO* = 0x00001000
+  MCI_SET_ON* = 0x00002000
+  MCI_SET_OFF* = 0x00004000
+  MCI_SET_AUDIO_ALL* = 0
+  MCI_SET_AUDIO_LEFT* = 1
+  MCI_SET_AUDIO_RIGHT* = 2
+
+proc MCI_TMSF_TRACK*(tmsf: int32): int8
+proc MCI_TMSF_MINUTE*(tmsf: int32): int8
+proc MCI_TMSF_SECOND*(tmsf: int32): int8
+proc MCI_TMSF_FRAME*(tmsf: int32): int8
+proc MCI_HMS_HOUR*(h: int32): int8
+proc MCI_HMS_MINUTE*(h: int32): int8
+proc MCI_HMS_SECOND*(h: int32): int8
+proc MCI_MAKE_HMS*(h, m, s: int8): int32
+const
+  MCI_INFO_PRODUCT* = 256
+  MCI_INFO_FILE* = 512
+  MCI_INFO_MEDIA_UPC* = 0x00000400
+  MCI_INFO_MEDIA_IDENTITY* = 0x00000800
+  MCI_INFO_NAME* = 0x00001000
+  MCI_INFO_COPYRIGHT* = 0x00002000
+
+proc MCI_MAKE_TMSF*(t, m, s, f: int8): int32
+const
+  MCI_WAIT* = 2
+  MCI_FROM* = 4
+  MCI_TO* = 8
+  MCI_TRACK* = 16
+  MCI_SEEK_TO_START* = 256
+  MCI_SEEK_TO_END* = 512
+  MCI_STATUS_ITEM* = 256
+  MCI_STATUS_START* = 512
+  MCI_STATUS_LENGTH* = 1
+  MCI_STATUS_POSITION* = 2
+  MCI_STATUS_NUMBER_OF_TRACKS* = 3
+  MCI_STATUS_MODE* = 4
+  MCI_STATUS_MEDIA_PRESENT* = 5
+  MCI_STATUS_TIME_FORMAT* = 6
+  MCI_STATUS_READY* = 7
+  MCI_STATUS_CURRENT_TRACK* = 8
+  MCI_OPEN_SHAREABLE* = 256
+  MCI_OPEN_ELEMENT* = 512
+  MCI_OPEN_ALIAS* = 0x00000400
+  MCI_OPEN_ELEMENT_ID* = 0x00000800
+  MCI_OPEN_TYPE_ID* = 0x00001000
+  MCI_OPEN_TYPE* = 0x00002000
+  MCI_GETDEVCAPS_ITEM* = 256
+  MCI_GETDEVCAPS_CAN_RECORD* = 1
+  MCI_GETDEVCAPS_HAS_AUDIO* = 2
+  MCI_GETDEVCAPS_HAS_VIDEO* = 3
+  MCI_GETDEVCAPS_DEVICE_TYPE* = 4
+  MCI_GETDEVCAPS_USES_FILES* = 5
+  MCI_GETDEVCAPS_COMPOUND_DEVICE* = 6
+  MCI_GETDEVCAPS_CAN_EJECT* = 7
+  MCI_GETDEVCAPS_CAN_PLAY* = 8
+  MCI_GETDEVCAPS_CAN_SAVE* = 9
+  MCI_SYSINFO_QUANTITY* = 256
+  MCI_SYSINFO_OPEN* = 512
+  MCI_SYSINFO_NAME* = 0x00000400
+  MCI_SYSINFO_INSTALLNAME* = 0x00000800
+  MCI_NOTIFY_SUCCESSFUL* = 1
+  MCI_NOTIFY_SUPERSEDED* = 2
+  MCI_NOTIFY_ABORTED* = 4
+  MCI_NOTIFY_FAILURE* = 8
+  MCI_NOTIFY* = 1
+  MCI_BREAK_KEY* = 256
+  MCI_BREAK_HWND* = 512
+  MCI_BREAK_OFF* = 0x00000400
+  MCI_RECORD_INSERT* = 256
+  MCI_RECORD_OVERWRITE* = 512
+  MCI_SAVE_FILE* = 256
+  MCI_LOAD_FILE* = 256
+  MCI_VD_GETDEVCAPS_FAST_RATE* = 0x00004003
+  MCI_VD_GETDEVCAPS_SLOW_RATE* = 0x00004004
+  MCI_VD_GETDEVCAPS_NORMAL_RATE* = 0x00004005
+  MCI_VD_STEP_FRAMES* = 0x00010000
+  MCI_VD_STEP_REVERSE* = 0x00020000
+  MCI_VD_ESCAPE_STRING* = 256
+  MCI_VD_FORMAT_TRACK* = 0x00004001
+  MCI_VD_PLAY_REVERSE* = 0x00010000
+  MCI_VD_PLAY_FAST* = 0x00020000
+  MCI_VD_MODE_PARK* = (MCI_VD_OFFSET + 1)
+  MCI_VD_GETDEVCAPS_CAV* = 0x00020000
+  MCI_VD_SPIN_UP* = 0x00010000
+  MCI_VD_SPIN_DOWN* = 0x00020000
+  MCI_VD_SEEK_REVERSE* = 0x00010000
+  MCI_VD_STATUS_SPEED* = 0x00004002
+  MCI_VD_STATUS_FORWARD* = 0x00004003
+  MCI_VD_STATUS_MEDIA_TYPE* = 0x00004004
+  MCI_VD_STATUS_SIDE* = 0x00004005
+  MCI_VD_GETDEVCAPS_CAN_REVERSE* = 0x00004002
+  MCI_VD_MEDIA_CLV* = (MCI_VD_OFFSET + 2)
+  MCI_VD_MEDIA_CAV* = (MCI_VD_OFFSET + 3)
+  MCI_VD_MEDIA_OTHER* = (MCI_VD_OFFSET + 4)
+  MCI_VD_STATUS_DISC_SIZE* = 0x00004006
+  MCI_VD_GETDEVCAPS_CLV* = 0x00010000
+  MCI_VD_PLAY_SPEED* = 0x00040000
+  MCI_VD_PLAY_SCAN* = 0x00080000
+  MCI_VD_PLAY_SLOW* = 0x00100000
+  MCI_WAVE_STATUS_CHANNELS* = 0x00004002
+  MCI_WAVE_STATUS_SAMPLESPERSEC* = 0x00004003
+  MCI_WAVE_PCM* = MCI_WAVE_OFFSET
+  MCI_WAVE_MAPPER* = (MCI_WAVE_OFFSET + 1)
+  MCI_WAVE_OPEN_BUFFER* = 0x00010000
+  MCI_WAVE_STATUS_BITSPERSAMPLE* = 0x00004006
+  MCI_WAVE_STATUS_LEVEL* = 0x00004007
+  MCI_WAVE_SET_FORMATTAG* = 0x00010000
+  MCI_WAVE_SET_CHANNELS* = 0x00020000
+  MCI_WAVE_SET_SAMPLESPERSEC* = 0x00040000
+  MCI_WAVE_SET_AVGBYTESPERSEC* = 0x00080000
+  MCI_WAVE_SET_BLOCKALIGN* = 0x00100000
+  MCI_WAVE_SET_BITSPERSAMPLE* = 0x00200000
+  MCI_WAVE_INPUT* = 0x00400000
+  MCI_WAVE_OUTPUT* = 0x00800000
+  MCI_WAVE_STATUS_FORMATTAG* = 0x00004001
+  MCI_WAVE_SET_ANYINPUT* = 0x04000000
+  MCI_WAVE_SET_ANYOUTPUT* = 0x08000000
+  MCI_WAVE_GETDEVCAPS_INPUTS* = 0x00004001
+  MCI_WAVE_GETDEVCAPS_OUTPUTS* = 0x00004002
+  MCI_WAVE_STATUS_AVGBYTESPERSEC* = 0x00004004
+  MCI_WAVE_STATUS_BLOCKALIGN* = 0x00004005
+  MCI_CDA_STATUS_TYPE_TRACK* = 0x00004001
+  MCI_CDA_TRACK_AUDIO* = (MCI_CD_OFFSET)
+  MCI_CDA_TRACK_OTHER* = (MCI_CD_OFFSET + 1)
+  MCI_SEQ_DIV_PPQN* = (MCI_SEQ_OFFSET)
+  MCI_SEQ_DIV_SMPTE_24* = (MCI_SEQ_OFFSET + 1)
+  MCI_SEQ_DIV_SMPTE_25* = (MCI_SEQ_OFFSET + 2)
+  MCI_SEQ_DIV_SMPTE_30DROP* = (MCI_SEQ_OFFSET + 3)
+  MCI_SEQ_DIV_SMPTE_30* = (MCI_SEQ_OFFSET + 4)
+  MCI_SEQ_FORMAT_SONGPTR* = 0x00004001
+  MCI_SEQ_FILE* = 0x00004002
+  MCI_SEQ_MIDI* = 0x00004003
+  MCI_SEQ_SMPTE* = 0x00004004
+  MCI_SEQ_NONE* = 65533
+  MCI_SEQ_MAPPER* = 65535
+  MCI_SEQ_STATUS_TEMPO* = 0x00004002
+  MCI_SEQ_STATUS_PORT* = 0x00004003
+  MCI_SEQ_STATUS_SLAVE* = 0x00004007
+  MCI_SEQ_STATUS_MASTER* = 0x00004008
+  MCI_SEQ_STATUS_OFFSET* = 0x00004009
+  MCI_SEQ_STATUS_DIVTYPE* = 0x0000400A
+  MCI_SEQ_STATUS_NAME* = 0x0000400B
+  MCI_SEQ_STATUS_COPYRIGHT* = 0x0000400C
+  MCI_SEQ_SET_TEMPO* = 0x00010000
+  MCI_SEQ_SET_PORT* = 0x00020000
+  MCI_SEQ_SET_SLAVE* = 0x00040000
+  MCI_SEQ_SET_MASTER* = 0x00080000
+  MCI_SEQ_SET_OFFSET* = 0x01000000
+  MCI_ANIM_PLAY_SLOW* = 0x00080000
+  MCI_ANIM_PLAY_SCAN* = 0x00100000
+  MCI_ANIM_GETDEVCAPS_SLOW_RATE* = 0x00004003
+  MCI_ANIM_GETDEVCAPS_NORMAL_RATE* = 0x00004004
+  MCI_ANIM_STEP_REVERSE* = 0x00010000
+  MCI_ANIM_STEP_FRAMES* = 0x00020000
+  MCI_ANIM_STATUS_SPEED* = 0x00004001
+  MCI_ANIM_GETDEVCAPS_PALETTES* = 0x00004006
+  MCI_ANIM_OPEN_WS* = 0x00010000
+  MCI_ANIM_OPEN_PARENT* = 0x00020000
+  MCI_ANIM_OPEN_NOSTATIC* = 0x00040000
+  MCI_ANIM_GETDEVCAPS_FAST_RATE* = 0x00004002
+  MCI_ANIM_PLAY_SPEED* = 0x00010000
+  MCI_ANIM_PLAY_REVERSE* = 0x00020000
+  MCI_ANIM_PLAY_FAST* = 0x00040000
+  MCI_ANIM_STATUS_FORWARD* = 0x00004002
+  MCI_ANIM_STATUS_HWND* = 0x00004003
+  MCI_ANIM_STATUS_HPAL* = 0x00004004
+  MCI_ANIM_STATUS_STRETCH* = 0x00004005
+  MCI_ANIM_INFO_TEXT* = 0x00010000
+  MCI_ANIM_GETDEVCAPS_CAN_REVERSE* = 0x00004001
+  MCI_ANIM_WINDOW_TEXT* = 0x00080000
+  MCI_ANIM_WINDOW_ENABLE_STRETCH* = 0x00100000
+  MCI_ANIM_WINDOW_DISABLE_STRETCH* = 0x00200000
+  MCI_ANIM_WINDOW_DEFAULT* = 0
+  MCI_ANIM_RECT* = 0x00010000
+  MCI_ANIM_PUT_SOURCE* = 0x00020000
+  MCI_ANIM_PUT_DESTINATION* = 0x00040000
+  MCI_ANIM_WHERE_SOURCE* = 0x00020000
+  MCI_ANIM_WHERE_DESTINATION* = 0x00040000
+  MCI_ANIM_UPDATE_HDC* = 0x00020000
+  MCI_ANIM_GETDEVCAPS_CAN_STRETCH* = 0x00004007
+  MCI_ANIM_GETDEVCAPS_MAX_WINDOWS* = 0x00004008
+  MCI_ANIM_REALIZE_NORM* = 0x00010000
+  MCI_ANIM_REALIZE_BKGD* = 0x00020000
+  MCI_ANIM_WINDOW_HWND* = 0x00010000
+  MCI_ANIM_WINDOW_STATE* = 0x00040000
+  TIMERR_NOERROR* = 0
+  TIMERR_NOCANDO* = (TIMERR_BASE + 1)
+  TIMERR_STRUCT* = (TIMERR_BASE + 33)
+  TIME_ONESHOT* = 0
+  TIME_PERIODIC* = 1
+  TIME_CALLBACK_FUNCTION* = 0
+  TIME_CALLBACK_EVENT_SET* = 16
+  TIME_CALLBACK_EVENT_PULSE* = 32
+  MCI_OVLY_OPEN_WS* = 0x00010000
+  MCI_OVLY_OPEN_PARENT* = 0x00020000
+  MCI_OVLY_STATUS_HWND* = 0x00004001
+  MCI_OVLY_STATUS_STRETCH* = 0x00004002
+  MCI_OVLY_INFO_TEXT* = 0x00010000
+  MCI_OVLY_GETDEVCAPS_CAN_STRETCH* = 0x00004001
+  MCI_OVLY_GETDEVCAPS_CAN_FREEZE* = 0x00004002
+  MCI_OVLY_GETDEVCAPS_MAX_WINDOWS* = 0x00004003
+  MCI_OVLY_WINDOW_HWND* = 0x00010000
+  MCI_OVLY_WINDOW_STATE* = 0x00040000
+  MCI_OVLY_WINDOW_TEXT* = 0x00080000
+  MCI_OVLY_WINDOW_ENABLE_STRETCH* = 0x00100000
+  MCI_OVLY_WINDOW_DISABLE_STRETCH* = 0x00200000
+  MCI_OVLY_WINDOW_DEFAULT* = 0
+  MCI_OVLY_RECT* = 0x00010000
+  MCI_OVLY_PUT_SOURCE* = 0x00020000
+  MCI_OVLY_PUT_DESTINATION* = 0x00040000
+  MCI_OVLY_PUT_FRAME* = 0x00080000
+  MCI_OVLY_PUT_VIDEO* = 0x00100000
+  MCI_OVLY_WHERE_SOURCE* = 0x00020000
+  MCI_OVLY_WHERE_DESTINATION* = 0x00040000
+  MCI_OVLY_WHERE_FRAME* = 0x00080000
+  MCI_OVLY_WHERE_VIDEO* = 0x00100000
+  AUX_MAPPER* = - 1
+  MIXER_GETLINECONTROLSF_ONEBYID* = 1
+  MIXER_GETLINECONTROLSF_ONEBYTYPE* = 2
+  MIXER_GETLINECONTROLSF_ALL* = 0
+  MIXER_GETLINECONTROLSF_QUERYMASK* = 0x0000000F
+  NEWTRANSPARENT* = 3
+  QUERYROPSUPPORT* = 40
+  SELECTDIB* = 41
+
+proc DIBINDEX*(n: int32): int32
+const
+  SC_SCREENSAVE* = 0x0000F140
+  AUXCAPS_CDAUDIO* = 1
+  AUXCAPS_AUXIN* = 2
+  AUXCAPS_VOLUME* = 1
+  AUXCAPS_LRVOLUME* = 2 #/////////////////////////////////////////////////////////
+                        # Structures and typedefs
+                        #/////////////////////////////////////////////////////////
+
+type
+  MMTIME* {.final.} = object
+    wType*: uint32
+    hour*, min*, sec*, frame*, fps*, dummy*: int8
+    pad*: array[0..1, int8]
+
+  PMMTIME* = ptr MMTIME
+  NPMMTIME* = ptr MMTIME
+  LPMMTIME* = ptr MMTIME
+  PWAVEHDR* = ptr WAVEHDR
+  TMMTime* = MMTIME
+  WAVEHDR* {.final.} = object
+    lpData*: cstring
+    dwBufferLength*: DWORD
+    dwBytesRecorded*: DWORD
+    dwUser*: DWORD
+    dwFlags*: DWORD
+    dwLoops*: DWORD
+    lpNext*: PWAVEHDR
+    reserved*: DWORD
+
+  TWAVEHDR* = WAVEHDR
+  NPWAVEHDR* = ptr WAVEHDR
+  LPWAVEHDR* = ptr WAVEHDR
+  WAVEOUTCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    dwFormats*: DWORD
+    wChannels*: int16
+    wReserved1*: int16
+    dwSupport*: DWORD
+
+  TWAVEOUTCAPSA* = WAVEOUTCAPSA
+  PWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
+  NPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
+  LPWAVEOUTCAPSA* = ptr WAVEOUTCAPSA
+  WAVEOUTCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), WCHAR]
+    dwFormats*: DWORD
+    wChannels*: int16
+    wReserved1*: int16
+    dwSupport*: DWORD
+
+  PWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
+  NPWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
+  LPWAVEOUTCAPSW* = ptr WAVEOUTCAPSW
+  TWAVEOUTCAPSW* = WAVEOUTCAPSW
+
+when defined(UNICODE):
+  type
+    WAVEOUTCAPS* = WAVEOUTCAPSW
+    PWAVEOUTCAPS* = PWAVEOUTCAPSW
+    NPWAVEOUTCAPS* = NPWAVEOUTCAPSW
+    LPWAVEOUTCAPS* = LPWAVEOUTCAPSW
+else:
+  type
+    WAVEOUTCAPS* = WAVEOUTCAPSA
+    PWAVEOUTCAPS* = PWAVEOUTCAPSA
+    NPWAVEOUTCAPS* = NPWAVEOUTCAPSA
+    LPWAVEOUTCAPS* = LPWAVEOUTCAPSA
+type
+  TWAVEOUTCAPS* = WAVEOUTCAPS
+  WAVEINCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    dwFormats*: DWORD
+    wChannels*: int16
+    wReserved1*: int16
+
+  PWAVEINCAPSA* = ptr WAVEINCAPSA
+  NPWAVEINCAPSA* = ptr WAVEINCAPSA
+  LPWAVEINCAPSA* = ptr WAVEINCAPSA
+  TWAVEINCAPSA* = WAVEINCAPSA
+  WAVEINCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), WCHAR]
+    dwFormats*: DWORD
+    wChannels*: int16
+    wReserved1*: int16
+
+  PWAVEINCAPSW* = ptr WAVEINCAPSW
+  NPWAVEINCAPSW* = ptr WAVEINCAPSW
+  LPWAVEINCAPSW* = ptr WAVEINCAPSW
+  TWAVEINCAPSW* = WAVEINCAPSW
+
+when defined(UNICODE):
+  type
+    WAVEINCAPS* = WAVEINCAPSW
+    PWAVEINCAPS* = PWAVEINCAPSW
+    NPWAVEINCAPS* = NPWAVEINCAPSW
+    LPWAVEINCAPS* = LPWAVEINCAPSW
+else:
+  type
+    WAVEINCAPS* = WAVEINCAPSA
+    PWAVEINCAPS* = PWAVEINCAPSA
+    NPWAVEINCAPS* = NPWAVEINCAPSA
+    LPWAVEINCAPS* = LPWAVEINCAPSA
+type
+  TWAVEINCAPS* = WAVEINCAPS
+  WAVEFORMAT* {.final.} = object
+    wFormatTag*: int16
+    nChannels*: int16
+    nSamplesPerSec*: DWORD
+    nAvgBytesPerSec*: DWORD
+    nBlockAlign*: int16
+
+  PWAVEFORMAT* = ptr WAVEFORMAT
+  NPWAVEFORMAT* = ptr WAVEFORMAT
+  LPWAVEFORMAT* = ptr WAVEFORMAT
+  TWAVEFORMAT* = WAVEFORMAT
+
+const
+  WAVE_FORMAT_PCM* = 1
+
+type
+  PCMWAVEFORMAT* {.final.} = object
+    wf*: WAVEFORMAT
+    wBitsPerSample*: int16
+
+  PPCMWAVEFORMAT* = ptr PCMWAVEFORMAT
+  NPPCMWAVEFORMAT* = ptr PCMWAVEFORMAT
+  LPPCMWAVEFORMAT* = ptr PCMWAVEFORMAT
+  TPCMWAVEFORMAT* = PCMWAVEFORMAT
+  WAVEFORMATEX* {.final.} = object
+    wFormatTag*: int16
+    nChannels*: int16
+    nSamplesPerSec*: DWORD
+    nAvgBytesPerSec*: DWORD
+    nBlockAlign*: int16
+    wBitsPerSample*: int16
+    cbSize*: int16
+
+  PWAVEFORMATEX* = ptr WAVEFORMATEX
+  NPWAVEFORMATEX* = ptr WAVEFORMATEX
+  LPWAVEFORMATEX* = ptr WAVEFORMATEX
+  LPCWAVEFORMATEX* = ptr WAVEFORMATEX
+  TWAVEFORMATEX* = WAVEFORMATEX
+  HMIDI* = THandle
+  HMIDIIN* = THandle
+  HMIDIOUT* = THandle
+  HMIDISTRM* = THandle
+  LPHMIDI* = ptr HMIDI
+  LPHMIDIIN* = ptr HMIDIIN
+  LPHMIDIOUT* = ptr HMIDIOUT
+  LPHMIDISTRM* = ptr HMIDISTRM
+  LPMIDICALLBACK* = PDRVCALLBACK
+
+const
+  MIDIPATCHSIZE* = 128
+
+type
+  PATCHARRAY* = array[0..pred(MIDIPATCHSIZE), int16]
+  LPPATCHARRAY* = ptr int16
+  KEYARRAY* = array[0..pred(MIDIPATCHSIZE), int16]
+  LPKEYARRAY* = ptr int16
+  MIDIOUTCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    wTechnology*: int16
+    wVoices*: int16
+    wNotes*: int16
+    wChannelMask*: int16
+    dwSupport*: DWORD
+
+  PMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
+  NPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
+  LPMIDIOUTCAPSA* = ptr MIDIOUTCAPSA
+  TMIDIOUTCAPSA* = MIDIOUTCAPSA
+  MIDIOUTCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), Wchar]
+    wTechnology*: int16
+    wVoices*: int16
+    wNotes*: int16
+    wChannelMask*: int16
+    dwSupport*: DWORD
+
+  PMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
+  NPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
+  LPMIDIOUTCAPSW* = ptr MIDIOUTCAPSW
+  TMIDIOUTCAPSW* = MIDIOUTCAPSW
+  MIDIINCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    dwSupport*: DWORD
+
+  PMIDIINCAPSA* = ptr MIDIINCAPSA
+  NPMIDIINCAPSA* = ptr MIDIINCAPSA
+  LPMIDIINCAPSA* = ptr MIDIINCAPSA
+  TMIDIINCAPSA* = MIDIINCAPSA
+  MIDIINCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), Wchar]
+    dwSupport*: DWORD
+
+  PMIDIINCAPSW* = ptr MIDIINCAPSW
+  NPMIDIINCAPSW* = ptr MIDIINCAPSW
+  LPMIDIINCAPSW* = ptr MIDIINCAPSW
+  TMIDIINCAPSW* = MIDIINCAPSW
+
+when defined(UNICODE):
+  type
+    MIDIINCAPS* = MIDIINCAPSW
+    PMIDIINCAPS* = PMIDIINCAPSW
+    NPMIDIINCAPS* = NPMIDIINCAPSW
+    LPMIDIINCAPS* = LPMIDIINCAPSW
+    MIDIOUTCAPS* = MIDIOUTCAPSW
+    PMIDIOUTCAPS* = PMIDIOUTCAPSW
+    NPMIDIOUTCAPS* = NPMIDIOUTCAPSW
+    LPMIDIOUTCAPS* = LPMIDIOUTCAPSW
+else:
+  type
+    MIDIOUTCAPS* = MIDIOUTCAPSA
+    PMIDIOUTCAPS* = PMIDIOUTCAPSA
+    NPMIDIOUTCAPS* = NPMIDIOUTCAPSA
+    LPMIDIOUTCAPS* = LPMIDIOUTCAPSA
+    MIDIINCAPS* = MIDIINCAPSA
+    PMIDIINCAPS* = PMIDIINCAPSA
+    NPMIDIINCAPS* = NPMIDIINCAPSA
+    LPMIDIINCAPS* = LPMIDIINCAPSA
+type
+  TMIDIINCAPS* = MIDIINCAPS
+  PMIDIHDR* = ptr MIDIHDR
+  MIDIHDR* {.final.} = object
+    lpData*: cstring
+    dwBufferLength*: DWORD
+    dwBytesRecorded*: DWORD
+    dwUser*: DWORD
+    dwFlags*: DWORD
+    lpNext*: PMIDIHDR
+    reserved*: DWORD
+    dwOffset*: DWORD
+    dwReserved*: array[0..pred(8), DWORD]
+
+  NPMIDIHDR* = ptr MIDIHDR
+  LPMIDIHDR* = ptr MIDIHDR
+  TMIDIHDR* = MIDIHDR
+  MIDIEVENT* {.final.} = object
+    dwDeltaTime*: DWORD
+    dwStreamID*: DWORD
+    dwEvent*: DWORD
+    dwParms*: array[0..pred(1), DWORD]
+
+  TMIDIEVENT* = MIDIEVENT
+  MIDISTRMBUFFVER* {.final.} = object
+    dwVersion*: DWORD
+    dwMid*: DWORD
+    dwOEMVersion*: DWORD
+
+  TMIDISTRMBUFFVER* = MIDISTRMBUFFVER
+  Tmidiproptimediv* {.final.} = object
+    cbStruct*: DWORD
+    dwTimeDiv*: DWORD
+
+  LPMIDIPROPTIMEDIV* = ptr Tmidiproptimediv
+  Tmidiproptempo* {.final.} = object
+    cbStruct*: DWORD
+    dwTempo*: DWORD
+
+  LPMIDIPROPTEMPO* = ptr Tmidiproptempo
+  AUXCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    wTechnology*: int16
+    wReserved1*: int16
+    dwSupport*: DWORD
+
+  PAUXCAPSA* = ptr AUXCAPSA
+  NPAUXCAPSA* = ptr AUXCAPSA
+  LPAUXCAPSA* = ptr AUXCAPSA
+  TAUXCAPSA* = AUXCAPSA
+  AUXCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), Wchar]
+    wTechnology*: int16
+    wReserved1*: int16
+    dwSupport*: DWORD
+
+  PAUXCAPSW* = ptr AUXCAPSW
+  NPAUXCAPSW* = ptr AUXCAPSW
+  LPAUXCAPSW* = ptr AUXCAPSW
+  TAUXCAPSW* = AUXCAPSW
+
+when defined(UNICODE):
+  type
+    AUXCAPS* = AUXCAPSW
+    PAUXCAPS* = PAUXCAPSW
+    NPAUXCAPS* = NPAUXCAPSW
+    LPAUXCAPS* = LPAUXCAPSW
+else:
+  type
+    AUXCAPS* = AUXCAPSA
+    PAUXCAPS* = PAUXCAPSA
+    NPAUXCAPS* = NPAUXCAPSA
+    LPAUXCAPS* = LPAUXCAPSA
+type
+  TAUXCAPS* = AUXCAPS
+  HMIXEROBJ* = THandle
+  LPHMIXEROBJ* = ptr HMIXEROBJ
+  HMIXER* = THandle
+  LPHMIXER* = ptr HMIXER
+
+proc mixerGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                               importc: "mixerGetNumDevs".}
+type
+  MIXERCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    fdwSupport*: DWORD
+    cDestinations*: DWORD
+
+  PMIXERCAPSA* = ptr MIXERCAPSA
+  LPMIXERCAPSA* = ptr MIXERCAPSA
+  TMIXERCAPSA* = MIXERCAPSA
+  MIXERCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), Wchar]
+    fdwSupport*: DWORD
+    cDestinations*: DWORD
+
+  PMIXERCAPSW* = ptr MIXERCAPSW
+  LPMIXERCAPSW* = ptr MIXERCAPSW
+  TMIXERCAPSW* = MIXERCAPSW
+
+when defined(UNICODE):
+  type
+    MIXERCAPS* = MIXERCAPSW
+    PMIXERCAPS* = PMIXERCAPSW
+    LPMIXERCAPS* = LPMIXERCAPSW
+else:
+  type
+    MIXERCAPS* = MIXERCAPSA
+    PMIXERCAPS* = PMIXERCAPSA
+    LPMIXERCAPS* = LPMIXERCAPSA
+type
+  TMIXERCAPS* = MIXERCAPS
+  MIXERLINEA* {.final.} = object
+    cbStruct*: DWORD
+    dwDestination*: DWORD
+    dwSource*: DWORD
+    dwLineID*: DWORD
+    fdwLine*: DWORD
+    dwUser*: DWORD
+    dwComponentType*: DWORD
+    cChannels*: DWORD
+    cConnections*: DWORD
+    cControls*: DWORD
+    szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), char]
+    szName*: array[0..pred(MIXER_LONG_NAME_CHARS), char]
+    dwType*, dwDeviceID*: DWORD
+    wMid*, wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+
+  PMIXERLINEA* = ptr MIXERLINEA
+  LPMIXERLINEA* = ptr MIXERLINEA
+  TMIXERLINEA* = MIXERLINEA
+  MIXERLINEW* {.final.} = object
+    cbStruct*: DWORD
+    dwDestination*: DWORD
+    dwSource*: DWORD
+    dwLineID*: DWORD
+    fdwLine*: DWORD
+    dwUser*: DWORD
+    dwComponentType*: DWORD
+    cChannels*: DWORD
+    cConnections*: DWORD
+    cControls*: DWORD
+    szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), WCHAR]
+    szName*: array[0..pred(MIXER_LONG_NAME_CHARS), WCHAR]
+    dwType*, dwDeviceID*: DWORD
+    wMid*, wPid*: int16
+    vDriverVersion*: MMVERSION
+    szPname*: array[0..pred(MAXPNAMELEN), WChar]
+
+  TMIXERLINEW* = MIXERLINEW
+  PMIXERLINEW* = ptr MIXERLINEW
+  LPMIXERLINEW* = ptr MIXERLINEW
+
+when defined(UNICODE):
+  type
+    MIXERLINE* = MIXERLINEW
+    PMIXERLINE* = PMIXERLINEW
+    LPMIXERLINE* = LPMIXERLINEW
+else:
+  type
+    MIXERLINE* = MIXERLINEA
+    PMIXERLINE* = PMIXERLINEA
+    LPMIXERLINE* = LPMIXERLINEA
+type
+  TMIXERLINE* = MIXERLINE
+  MIXERCONTROLA* {.final.} = object
+    cbStruct*: DWORD
+    dwControlID*: DWORD
+    dwControlType*: DWORD
+    fdwControl*: DWORD
+    cMultipleItems*: DWORD
+    szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), char]
+    szName*: array[0..pred(MIXER_LONG_NAME_CHARS), char]
+    dwMinimum*, dwMaximum*: DWORD
+    dwReserved*: array[0..3, DWORD]
+    cSteps*: DWORD
+    dwReserved2*: array[0..4, DWORD]
+
+  PMIXERCONTROLA* = ptr MIXERCONTROLA
+  LPMIXERCONTROLA* = ptr MIXERCONTROLA
+  TMIXERCONTROLA* = MIXERCONTROLA
+  MIXERCONTROLW* {.final.} = object
+    cbStruct*: DWORD
+    dwControlID*: DWORD
+    dwControlType*: DWORD
+    fdwControl*: DWORD
+    cMultipleItems*: DWORD
+    szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), WCHAR]
+    szName*: array[0..pred(MIXER_LONG_NAME_CHARS), WCHAR]
+    dwMinimum*, dwMaximum*: DWORD
+    dwReserved*: array[0..3, DWORD]
+    cSteps*: DWORD
+    dwReserved2*: array[0..4, DWORD]
+
+  PMIXERCONTROLW* = ptr MIXERCONTROLW
+  LPMIXERCONTROLW* = ptr MIXERCONTROLW
+  TMIXERCONTROLW* = MIXERCONTROLW
+
+when defined(UNICODE):
+  type
+    MIXERCONTROL* = MIXERCONTROLW
+    PMIXERCONTROL* = PMIXERCONTROLW
+    LPMIXERCONTROL* = LPMIXERCONTROLW
+else:
+  type
+    MIXERCONTROL* = MIXERCONTROLA
+    PMIXERCONTROL* = PMIXERCONTROLA
+    LPMIXERCONTROL* = LPMIXERCONTROLA
+type
+  TMIXERCONTROL* = MIXERCONTROL
+  MIXERLINECONTROLSA* {.final.} = object
+    cbStruct*: DWORD
+    dwLineID*: DWORD
+    dwControlType*, cControls*, cbmxctrl*: DWORD
+    pamxctrl*: PMIXERCONTROLA
+
+  PMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA
+  LPMIXERLINECONTROLSA* = ptr MIXERLINECONTROLSA
+  TMIXERLINECONTROLSA* = MIXERLINECONTROLSA
+  MIXERLINECONTROLSW* {.final.} = object
+    cbStruct*: DWORD
+    dwLineID*: DWORD
+    dwControlType*, cControls*, cbmxctrl*: DWORD
+    pamxctrl*: PMIXERCONTROLW
+
+  PMIXERLINECONTROLSW* = ptr MIXERLINECONTROLSW
+  LPMIXERLINECONTROLSW* = ptr MIXERLINECONTROLSW
+  TMIXERLINECONTROLSW* = MIXERLINECONTROLSW
+
+when defined(UNICODE):
+  type
+    MIXERLINECONTROLS* = MIXERLINECONTROLSW
+    PMIXERLINECONTROLS* = PMIXERLINECONTROLSW
+    LPMIXERLINECONTROLS* = LPMIXERLINECONTROLSW
+else:
+  type
+    MIXERLINECONTROLS* = MIXERLINECONTROLSA
+    PMIXERLINECONTROLS* = PMIXERLINECONTROLSA
+    LPMIXERLINECONTROLS* = LPMIXERLINECONTROLSA
+type
+  TMIXERLINECONTROLS* = MIXERLINECONTROLS
+  TMIXERCONTROLDETAILS* {.final.} = object
+    cbStruct*: DWORD
+    dwControlID*: DWORD
+    cChannels*: DWORD
+    cMultipleItems*, cbDetails*: DWORD
+    paDetails*: pointer
+
+  MIXERCONTROLDETAILS* = TMIXERCONTROLDETAILS
+  PMIXERCONTROLDETAILS* = ptr TMIXERCONTROLDETAILS
+  LPMIXERCONTROLDETAILS* = ptr TMIXERCONTROLDETAILS
+  MIXERCONTROLDETAILS_LISTTEXTA* {.final.} = object
+    dwParam1*: DWORD
+    dwParam2*: DWORD
+    szName*: array[0..pred(MIXER_LONG_NAME_CHARS), char]
+
+  PMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA
+  LPMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA
+  TMIXERCONTROLDETAILS_LISTTEXTA* = MIXERCONTROLDETAILS_LISTTEXTA
+  MIXERCONTROLDETAILS_LISTTEXTW* {.final.} = object
+    dwParam1*: DWORD
+    dwParam2*: DWORD
+    szName*: array[0..pred(MIXER_LONG_NAME_CHARS), WCHAR]
+
+  PMIXERCONTROLDETAILS_LISTTEXTW* = ptr MIXERCONTROLDETAILS_LISTTEXTW
+  LPMIXERCONTROLDETAILS_LISTTEXTW* = ptr MIXERCONTROLDETAILS_LISTTEXTW
+  TMIXERCONTROLDETAILS_LISTTEXTW* = MIXERCONTROLDETAILS_LISTTEXTW
+
+when defined(UNICODE):
+  type
+    MIXERCONTROLDETAILS_LISTTEXT* = MIXERCONTROLDETAILS_LISTTEXTW
+    PMIXERCONTROLDETAILS_LISTTEXT* = PMIXERCONTROLDETAILS_LISTTEXTW
+    LPMIXERCONTROLDETAILS_LISTTEXT* = LPMIXERCONTROLDETAILS_LISTTEXTW
+else:
+  type
+    MIXERCONTROLDETAILS_LISTTEXT* = MIXERCONTROLDETAILS_LISTTEXTA
+    PMIXERCONTROLDETAILS_LISTTEXT* = PMIXERCONTROLDETAILS_LISTTEXTA
+    LPMIXERCONTROLDETAILS_LISTTEXT* = LPMIXERCONTROLDETAILS_LISTTEXTA
+type
+  TMIXERCONTROLDETAILS_LISTTEXT* = MIXERCONTROLDETAILS_LISTTEXT
+  MIXERCONTROLDETAILS_BOOLEAN* {.final.} = object
+    fValue*: int32
+
+  PMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN
+  LPMIXERCONTROLDETAILS_BOOLEAN* = ptr MIXERCONTROLDETAILS_BOOLEAN
+  TMIXERCONTROLDETAILS_BOOLEAN* = MIXERCONTROLDETAILS_BOOLEAN
+  MIXERCONTROLDETAILS_SIGNED* {.final.} = object
+    lValue*: int32
+
+  PMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED
+  LPMIXERCONTROLDETAILS_SIGNED* = ptr MIXERCONTROLDETAILS_SIGNED
+  TMIXERCONTROLDETAILS_SIGNED* = MIXERCONTROLDETAILS_SIGNED
+  MIXERCONTROLDETAILS_UNSIGNED* {.final.} = object
+    dwValue*: DWORD
+
+  PMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED
+  LPMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED
+  TMIXERCONTROLDETAILS_UNSIGNED* = MIXERCONTROLDETAILS_UNSIGNED
+  LPTIMECALLBACK* = proc (uTimerID, uMsg: uint32, dwUser, dw1, dw2: DWORD){.
+      stdcall.}
+  TTIMECALLBACK* = LPTIMECALLBACK
+  TIMECAPS* {.final.} = object
+    wPeriodMin*: uint32
+    wPeriodMax*: uint32
+
+  PTIMECAPS* = ptr TIMECAPS
+  NPTIMECAPS* = ptr TIMECAPS
+  LPTIMECAPS* = ptr TIMECAPS
+  TTIMECAS* = TIMECAPS
+  JOYCAPSA* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    szPname*: array[0..pred(MAXPNAMELEN), char]
+    wXmin*: uint32
+    wXmax*: uint32
+    wYmin*: uint32
+    wYmax*: uint32
+    wZmin*: uint32
+    wZmax*: uint32
+    wNumButtons*: uint32
+    wPeriodMin*: uint32
+    wPeriodMax*: uint32
+    wRmin*: uint32
+    wRmax*: uint32
+    wUmin*: uint32
+    wUmax*: uint32
+    wVmin*: uint32
+    wVmax*: uint32
+    wCaps*: uint32
+    wMaxAxes*: uint32
+    wNumAxes*: uint32
+    wMaxButtons*: uint32
+    szRegKey*: array[0..pred(MAXPNAMELEN), char]
+    szOEMVxD*: array[0..pred(MAX_JOYSTICKOEMVXDNAME), char]
+
+  PJOYCAPSA* = ptr JOYCAPSA
+  NPJOYCAPSA* = ptr JOYCAPSA
+  LPJOYCAPSA* = ptr JOYCAPSA
+  TJOYCAPSA* = JOYCAPSA
+  JOYCAPSW* {.final.} = object
+    wMid*: int16
+    wPid*: int16
+    szPname*: array[0..pred(MAXPNAMELEN), WCHAR]
+    wXmin*: uint32
+    wXmax*: uint32
+    wYmin*: uint32
+    wYmax*: uint32
+    wZmin*: uint32
+    wZmax*: uint32
+    wNumButtons*: uint32
+    wPeriodMin*: uint32
+    wPeriodMax*: uint32
+    wRmin*: uint32
+    wRmax*: uint32
+    wUmin*: uint32
+    wUmax*: uint32
+    wVmin*: uint32
+    wVmax*: uint32
+    wCaps*: uint32
+    wMaxAxes*: uint32
+    wNumAxes*: uint32
+    wMaxButtons*: uint32
+    szRegKey*: array[0..pred(MAXPNAMELEN), WCHAR]
+    szOEMVxD*: array[0..pred(MAX_JOYSTICKOEMVXDNAME), WCHAR]
+
+  PJOYCAPSW* = ptr JOYCAPSW
+  NPJOYCAPSW* = ptr JOYCAPSW
+  LPJOYCAPSW* = ptr JOYCAPSW
+  TJOYCAPSW* = JOYCAPSW
+
+when defined(UNICODE):
+  type
+    JOYCAPS* = JOYCAPSW
+    PJOYCAPS* = PJOYCAPSW
+    NPJOYCAPS* = NPJOYCAPSW
+    LPJOYCAPS* = LPJOYCAPSW
+else:
+  type
+    JOYCAPS* = JOYCAPSA
+    PJOYCAPS* = PJOYCAPSA
+    NPJOYCAPS* = NPJOYCAPSA
+    LPJOYCAPS* = LPJOYCAPSA
+type
+  TJOYCAPS* = JOYCAPS
+  JOYINFO* {.final.} = object
+    wXpos*: uint32
+    wYpos*: uint32
+    wZpos*: uint32
+    wButtons*: uint32
+
+  PJOYINFO* = ptr JOYINFO
+  NPJOYINFO* = ptr JOYINFO
+  LPJOYINFO* = ptr JOYINFO
+  TJOYINFO* = JOYINFO
+  JOYINFOEX* {.final.} = object
+    dwSize*: DWORD
+    dwFlags*: DWORD
+    wXpos*: uint32
+    wYpos*: uint32
+    wZpos*: uint32
+    dwRpos*: DWORD
+    dwUpos*: DWORD
+    dwVpos*: DWORD
+    wButtons*: uint32
+    dwButtonNumber*: DWORD
+    dwPOV*: DWORD
+    dwReserved1*: DWORD
+    dwReserved2*: DWORD
+
+  PJOYINFOEX* = ptr JOYINFOEX
+  NPJOYINFOEX* = ptr JOYINFOEX
+  LPJOYINFOEX* = ptr JOYINFOEX
+  TJOYINFOEX* = JOYINFOEX
+  FOURCC* = DWORD
+  HPSTR* = cstring
+  HMMIO* = THandle
+  LPMMIOPROC* = proc (x1: LPSTR, x2: uint32, x3, x4: LPARAM): LRESULT{.stdcall.}
+  TMMIOPROC* = LPMMIOPROC
+  MMIOINFO* {.final.} = object
+    dwFlags*: DWORD
+    fccIOProc*: FOURCC
+    pIOProc*: LPMMIOPROC
+    wErrorRet*: uint32
+    htask*: HTASK
+    cchBuffer*: int32
+    pchBuffer*: HPSTR
+    pchNext*: HPSTR
+    pchEndRead*: HPSTR
+    pchEndWrite*: HPSTR
+    lBufOffset*: int32
+    lDiskOffset*: int32
+    adwInfo*: array[0..pred(3), DWORD]
+    dwReserved1*: DWORD
+    dwReserved2*: DWORD
+    hmmio*: HMMIO
+
+  PMMIOINFO* = ptr MMIOINFO
+  NPMMIOINFO* = ptr MMIOINFO
+  LPMMIOINFO* = ptr MMIOINFO
+  LPCMMIOINFO* = ptr MMIOINFO
+  TMMIOINFO* = MMIOINFO
+  MMCKINFO* {.final.} = object
+    ckid*: FOURCC
+    cksize*: DWORD
+    fccType*: FOURCC
+    dwDataOffset*: DWORD
+    dwFlags*: DWORD
+
+  PMMCKINFO* = ptr MMCKINFO
+  NPMMCKINFO* = ptr MMCKINFO
+  LPMMCKINFO* = ptr MMCKINFO
+  LPCMMCKINFO* = ptr MMCKINFO
+  TMMCKINFO* = MMCKINFO
+  MCIERROR* = DWORD
+  MCIDEVICEID* = uint32
+  YIELDPROC* = proc (mciId: MCIDEVICEID, dwYieldData: DWORD): uint32{.stdcall.}
+  TYIELDPROC* = YIELDPROC
+  MCI_GENERIC_PARMS* {.final.} = object
+    dwCallback*: DWORD
+
+  PMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS
+  LPMCI_GENERIC_PARMS* = ptr MCI_GENERIC_PARMS
+  TMCI_GENERIC_PARMS* = MCI_GENERIC_PARMS
+  MCI_OPEN_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCSTR
+    lpstrElementName*: LPCSTR
+    lpstrAlias*: LPCSTR
+
+  PMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA
+  LPMCI_OPEN_PARMSA* = ptr MCI_OPEN_PARMSA
+  TMCI_OPEN_PARMSA* = MCI_OPEN_PARMSA
+  MCI_OPEN_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCWSTR
+    lpstrElementName*: LPCWSTR
+    lpstrAlias*: LPCWSTR
+
+  PMCI_OPEN_PARMSW* = ptr MCI_OPEN_PARMSW
+  LPMCI_OPEN_PARMSW* = ptr MCI_OPEN_PARMSW
+  TMCI_OPEN_PARMSW* = MCI_OPEN_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_OPEN_PARMS* = MCI_OPEN_PARMSW
+    PMCI_OPEN_PARMS* = PMCI_OPEN_PARMSW
+    LPMCI_OPEN_PARMS* = LPMCI_OPEN_PARMSW
+else:
+  type
+    MCI_OPEN_PARMS* = MCI_OPEN_PARMSA
+    PMCI_OPEN_PARMS* = PMCI_OPEN_PARMSA
+    LPMCI_OPEN_PARMS* = LPMCI_OPEN_PARMSA
+type
+  TMCI_OPEN_PARMS* = MCI_OPEN_PARMS
+  MCI_PLAY_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrom*: DWORD
+    dwTo*: DWORD
+
+  PMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS
+  LPMCI_PLAY_PARMS* = ptr MCI_PLAY_PARMS
+  TMCI_PLAY_PARMS* = MCI_PLAY_PARMS
+  MCI_SEEK_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwTo*: DWORD
+
+  PMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS
+  LPMCI_SEEK_PARMS* = ptr MCI_SEEK_PARMS
+  TMCI_SEEK_PARMS* = MCI_SEEK_PARMS
+  MCI_STATUS_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwReturn*: DWORD
+    dwItem*: DWORD
+    dwTrack*: DWORD
+
+  PMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS
+  LPMCI_STATUS_PARMS* = ptr MCI_STATUS_PARMS
+  TMCI_STATUS_PARMS* = MCI_STATUS_PARMS
+  MCI_INFO_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpstrReturn*: cstring
+    dwRetSize*: DWORD
+
+  LPMCI_INFO_PARMSA* = ptr MCI_INFO_PARMSA
+  TMCI_INFO_PARMSA* = MCI_INFO_PARMSA
+  MCI_INFO_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpstrReturn*: LPWSTR
+    dwRetSize*: DWORD
+
+  LPMCI_INFO_PARMSW* = ptr MCI_INFO_PARMSW
+  TMCI_INFO_PARMSW* = MCI_INFO_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_INFO_PARMS* = MCI_INFO_PARMSW
+    LPMCI_INFO_PARMS* = LPMCI_INFO_PARMSW
+else:
+  type
+    MCI_INFO_PARMS* = MCI_INFO_PARMSA
+    LPMCI_INFO_PARMS* = LPMCI_INFO_PARMSA
+type
+  TMCI_INFO_PARMS* = MCI_INFO_PARMS
+  MCI_GETDEVCAPS_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwReturn*: DWORD
+    dwItem*: DWORD
+
+  PMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS
+  LPMCI_GETDEVCAPS_PARMS* = ptr MCI_GETDEVCAPS_PARMS
+  TMCI_GETDEVCAPS_PARMS* = MCI_GETDEVCAPS_PARMS
+  MCI_SYSINFO_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpstrReturn*: cstring
+    dwRetSize*: DWORD
+    dwNumber*: DWORD
+    wDeviceType*: uint32
+
+  PMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA
+  LPMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA
+  TMCI_SYSINFO_PARMSA* = MCI_SYSINFO_PARMSA
+  MCI_SYSINFO_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpstrReturn*: LPWSTR
+    dwRetSize*: DWORD
+    dwNumber*: DWORD
+    wDeviceType*: uint32
+
+  PMCI_SYSINFO_PARMSW* = ptr MCI_SYSINFO_PARMSW
+  LPMCI_SYSINFO_PARMSW* = ptr MCI_SYSINFO_PARMSW
+  TMCI_SYSINFO_PARMSW* = MCI_SYSINFO_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_SYSINFO_PARMS* = MCI_SYSINFO_PARMSW
+    PMCI_SYSINFO_PARMS* = PMCI_SYSINFO_PARMSW
+    LPMCI_SYSINFO_PARMS* = LPMCI_SYSINFO_PARMSW
+else:
+  type
+    MCI_SYSINFO_PARMS* = MCI_SYSINFO_PARMSA
+    PMCI_SYSINFO_PARMS* = PMCI_SYSINFO_PARMSA
+    LPMCI_SYSINFO_PARMS* = LPMCI_SYSINFO_PARMSA
+type
+  TMCI_SYSINFO_PARMS* = MCI_SYSINFO_PARMS
+  MCI_SET_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwTimeFormat*: DWORD
+    dwAudio*: DWORD
+
+  PMCI_SET_PARMS* = ptr MCI_SET_PARMS
+  LPMCI_SET_PARMS* = ptr MCI_SET_PARMS
+  TMCI_SET_PARMS* = MCI_SET_PARMS
+  MCI_BREAK_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    nVirtKey*: int32
+    hwndBreak*: HWND
+
+  PMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS
+  LPMCI_BREAK_PARMS* = ptr MCI_BREAK_PARMS
+  TMCI_BREAK_PARMS* = MCI_BREAK_PARMS
+  MCI_SAVE_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCSTR
+
+  PMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA
+  LPMCI_SAVE_PARMSA* = ptr MCI_SAVE_PARMSA
+  TMCI_SAVE_PARMSA* = MCI_SAVE_PARMSA
+  MCI_SAVE_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCWSTR
+
+  PMCI_SAVE_PARMSW* = ptr MCI_SAVE_PARMSW
+  LPMCI_SAVE_PARMSW* = ptr MCI_SAVE_PARMSW
+  TMCI_SAVE_PARMSW* = MCI_SAVE_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_SAVE_PARMS* = MCI_SAVE_PARMSW
+    PMCI_SAVE_PARMS* = PMCI_SAVE_PARMSW
+    LPMCI_SAVE_PARMS* = LPMCI_SAVE_PARMSW
+else:
+  type
+    MCI_SAVE_PARMS* = MCI_SAVE_PARMSA
+    PMCI_SAVE_PARMS* = PMCI_SAVE_PARMSA
+    LPMCI_SAVE_PARMS* = LPMCI_SAVE_PARMSA
+type
+  TMCI_SAVE_PARMS* = MCI_SAVE_PARMS
+  MCI_LOAD_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCSTR
+
+  PMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA
+  LPMCI_LOAD_PARMSA* = ptr MCI_LOAD_PARMSA
+  TMCI_LOAD_PARMSA* = MCI_LOAD_PARMSA
+  MCI_LOAD_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCWSTR
+
+  PMCI_LOAD_PARMSW* = ptr MCI_LOAD_PARMSW
+  LPMCI_LOAD_PARMSW* = ptr MCI_LOAD_PARMSW
+  TMCI_LOAD_PARMSW* = MCI_LOAD_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_LOAD_PARMS* = MCI_LOAD_PARMSW
+    PMCI_LOAD_PARMS* = PMCI_LOAD_PARMSW
+    LPMCI_LOAD_PARMS* = LPMCI_LOAD_PARMSW
+else:
+  type
+    MCI_LOAD_PARMS* = MCI_LOAD_PARMSA
+    PMCI_LOAD_PARMS* = PMCI_LOAD_PARMSA
+    LPMCI_LOAD_PARMS* = LPMCI_LOAD_PARMSA
+type
+  TMCI_LOAD_PARMS* = MCI_LOAD_PARMS
+  MCI_RECORD_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrom*: DWORD
+    dwTo*: DWORD
+
+  LPMCI_RECORD_PARMS* = ptr MCI_RECORD_PARMS
+  TMCI_RECORD_PARMS* = MCI_RECORD_PARMS
+  MCI_VD_PLAY_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrom*: DWORD
+    dwTo*: DWORD
+    dwSpeed*: DWORD
+
+  PMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS
+  LPMCI_VD_PLAY_PARMS* = ptr MCI_VD_PLAY_PARMS
+  TMCI_VD_PLAY_PARMS* = MCI_VD_PLAY_PARMS
+  MCI_VD_STEP_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrames*: DWORD
+
+  PMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS
+  LPMCI_VD_STEP_PARMS* = ptr MCI_VD_STEP_PARMS
+  MCI_VD_ESCAPE_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpstrCommand*: LPCSTR
+
+  PMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA
+  LPMCI_VD_ESCAPE_PARMSA* = ptr MCI_VD_ESCAPE_PARMSA
+  TMCI_VD_ESCAPE_PARMSA* = MCI_VD_ESCAPE_PARMSA
+  MCI_VD_ESCAPE_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpstrCommand*: LPCWSTR
+
+  PMCI_VD_ESCAPE_PARMSW* = ptr MCI_VD_ESCAPE_PARMSW
+  LPMCI_VD_ESCAPE_PARMSW* = ptr MCI_VD_ESCAPE_PARMSW
+  TMCI_VD_ESCAPE_PARMSW* = MCI_VD_ESCAPE_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_VD_ESCAPE_PARMS* = MCI_VD_ESCAPE_PARMSW
+    PMCI_VD_ESCAPE_PARMS* = PMCI_VD_ESCAPE_PARMSW
+    LPMCI_VD_ESCAPE_PARMS* = LPMCI_VD_ESCAPE_PARMSW
+else:
+  type
+    MCI_VD_ESCAPE_PARMS* = MCI_VD_ESCAPE_PARMSA
+    PMCI_VD_ESCAPE_PARMS* = PMCI_VD_ESCAPE_PARMSA
+    LPMCI_VD_ESCAPE_PARMS* = LPMCI_VD_ESCAPE_PARMSA
+type
+  TMCI_VD_ESCAPE_PARMS* = MCI_VD_ESCAPE_PARMS
+  MCI_WAVE_OPEN_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCSTR
+    lpstrElementName*: LPCSTR
+    lpstrAlias*: LPCSTR
+    dwBufferSeconds*: DWORD
+
+  PMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA
+  LPMCI_WAVE_OPEN_PARMSA* = ptr MCI_WAVE_OPEN_PARMSA
+  TMCI_WAVE_OPEN_PARMSA* = MCI_WAVE_OPEN_PARMSA
+  MCI_WAVE_OPEN_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCWSTR
+    lpstrElementName*: LPCWSTR
+    lpstrAlias*: LPCWSTR
+    dwBufferSeconds*: DWORD
+
+  PMCI_WAVE_OPEN_PARMSW* = ptr MCI_WAVE_OPEN_PARMSW
+  LPMCI_WAVE_OPEN_PARMSW* = ptr MCI_WAVE_OPEN_PARMSW
+  TMCI_WAVE_OPEN_PARMSW* = MCI_WAVE_OPEN_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_WAVE_OPEN_PARMS* = MCI_WAVE_OPEN_PARMSW
+    PMCI_WAVE_OPEN_PARMS* = PMCI_WAVE_OPEN_PARMSW
+    LPMCI_WAVE_OPEN_PARMS* = LPMCI_WAVE_OPEN_PARMSW
+else:
+  type
+    MCI_WAVE_OPEN_PARMS* = MCI_WAVE_OPEN_PARMSA
+    PMCI_WAVE_OPEN_PARMS* = PMCI_WAVE_OPEN_PARMSA
+    LPMCI_WAVE_OPEN_PARMS* = LPMCI_WAVE_OPEN_PARMSA
+type
+  TMCI_WAVE_OPEN_PARMS* = MCI_WAVE_OPEN_PARMS
+  MCI_WAVE_DELETE_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrom*: DWORD
+    dwTo*: DWORD
+
+  PMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS
+  LPMCI_WAVE_DELETE_PARMS* = ptr MCI_WAVE_DELETE_PARMS
+  TMCI_WAVE_DELETE_PARMS* = MCI_WAVE_DELETE_PARMS
+  MCI_WAVE_SET_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwTimeFormat*: DWORD
+    dwAudio*: DWORD
+    wInput*: uint32
+    wOutput*: uint32
+    wFormatTag*: int16
+    wReserved2*: int16
+    nChannels*: int16
+    wReserved3*: int16
+    nSamplesPerSec*: DWORD
+    nAvgBytesPerSec*: DWORD
+    nBlockAlign*: int16
+    wReserved4*: int16
+    wBitsPerSample*: int16
+    wReserved5*: int16
+
+  PMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS
+  LPMCI_WAVE_SET_PARMS* = ptr MCI_WAVE_SET_PARMS
+  TMCI_WAVE_SET_PARMS* = MCI_WAVE_SET_PARMS
+  MCI_SEQ_SET_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwTimeFormat*: DWORD
+    dwAudio*: DWORD
+    dwTempo*: DWORD
+    dwPort*: DWORD
+    dwSlave*: DWORD
+    dwMaster*: DWORD
+    dwOffset*: DWORD
+
+  PMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS
+  LPMCI_SEQ_SET_PARMS* = ptr MCI_SEQ_SET_PARMS
+  TMCI_SEQ_SET_PARMS* = MCI_SEQ_SET_PARMS
+  MCI_ANIM_OPEN_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCSTR
+    lpstrElementName*: LPCSTR
+    lpstrAlias*: LPCSTR
+    dwStyle*: DWORD
+    hWndParent*: HWND
+
+  PMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA
+  LPMCI_ANIM_OPEN_PARMSA* = ptr MCI_ANIM_OPEN_PARMSA
+  TMCI_ANIM_OPEN_PARMSA* = MCI_ANIM_OPEN_PARMSA
+  MCI_ANIM_OPEN_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCWSTR
+    lpstrElementName*: LPCWSTR
+    lpstrAlias*: LPCWSTR
+    dwStyle*: DWORD
+    hWndParent*: HWND
+
+  PMCI_ANIM_OPEN_PARMSW* = ptr MCI_ANIM_OPEN_PARMSW
+  LPMCI_ANIM_OPEN_PARMSW* = ptr MCI_ANIM_OPEN_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_ANIM_OPEN_PARMS* = MCI_ANIM_OPEN_PARMSW
+    PMCI_ANIM_OPEN_PARMS* = PMCI_ANIM_OPEN_PARMSW
+    LPMCI_ANIM_OPEN_PARMS* = LPMCI_ANIM_OPEN_PARMSW
+else:
+  type
+    MCI_ANIM_OPEN_PARMS* = MCI_ANIM_OPEN_PARMSA
+    PMCI_ANIM_OPEN_PARMS* = PMCI_ANIM_OPEN_PARMSA
+    LPMCI_ANIM_OPEN_PARMS* = LPMCI_ANIM_OPEN_PARMSA
+type
+  TMCI_ANIM_OPEN_PARMS* = MCI_ANIM_OPEN_PARMS
+  MCI_ANIM_WINDOW_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    hWnd*: HWND
+    nCmdShow*: uint32
+    lpstrText*: LPCWSTR
+
+  PMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW
+  LPMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW
+  TMCI_ANIM_WINDOW_PARMSW* = MCI_ANIM_WINDOW_PARMSW
+  MCI_ANIM_STEP_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrames*: DWORD
+
+  PMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS
+  LPMCI_ANIM_STEP_PARMS* = ptr MCI_ANIM_STEP_PARMS
+  TMCI_ANIM_STEP_PARMS* = MCI_ANIM_STEP_PARMS
+  MCI_ANIM_WINDOW_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    hWnd*: HWND
+    nCmdShow*: uint32
+    lpstrText*: LPCSTR
+
+  PMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA
+  LPMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA
+  TMCI_ANIM_WINDOW_PARMSA* = MCI_ANIM_WINDOW_PARMSA
+  MCI_ANIM_PLAY_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    dwFrom*: DWORD
+    dwTo*: DWORD
+    dwSpeed*: DWORD
+
+  PMCI_ANIM_PLAY_PARMS* = ptr MCI_ANIM_PLAY_PARMS
+  LPMCI_ANIM_PLAY_PARMS* = ptr MCI_ANIM_PLAY_PARMS
+
+when defined(UNICODE):
+  type
+    MCI_ANIM_WINDOW_PARMS* = MCI_ANIM_WINDOW_PARMSW
+    PMCI_ANIM_WINDOW_PARMS* = PMCI_ANIM_WINDOW_PARMSW
+    LPMCI_ANIM_WINDOW_PARMS* = LPMCI_ANIM_WINDOW_PARMSW
+else:
+  type
+    MCI_ANIM_WINDOW_PARMS* = MCI_ANIM_WINDOW_PARMSA
+    PMCI_ANIM_WINDOW_PARMS* = PMCI_ANIM_WINDOW_PARMSA
+    LPMCI_ANIM_WINDOW_PARMS* = LPMCI_ANIM_WINDOW_PARMSA
+type
+  MCI_ANIM_RECT_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    rc*: TRECT
+
+  PMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
+  LPMCI_ANIM_RECT_PARMS* = ptr MCI_ANIM_RECT_PARMS
+  TMCI_ANIM_RECT_PARMS* = MCI_ANIM_RECT_PARMS
+  MCI_ANIM_UPDATE_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    rc*: TRECT
+    hDC*: HDC
+
+  PMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
+  LPMCI_ANIM_UPDATE_PARMS* = ptr MCI_ANIM_UPDATE_PARMS
+  TMCI_ANIM_UPDATE_PARMS* = MCI_ANIM_UPDATE_PARMS
+  MCI_OVLY_OPEN_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCSTR
+    lpstrElementName*: LPCSTR
+    lpstrAlias*: LPCSTR
+    dwStyle*: DWORD
+    hWndParent*: HWND
+
+  PMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA
+  LPMCI_OVLY_OPEN_PARMSA* = ptr MCI_OVLY_OPEN_PARMSA
+  TMCI_OVLY_OPEN_PARMSA* = MCI_OVLY_OPEN_PARMSA
+  MCI_OVLY_OPEN_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    wDeviceID*: MCIDEVICEID
+    lpstrDeviceType*: LPCWSTR
+    lpstrElementName*: LPCWSTR
+    lpstrAlias*: LPCWSTR
+    dwStyle*: DWORD
+    hWndParent*: HWND
+
+  PMCI_OVLY_OPEN_PARMSW* = ptr MCI_OVLY_OPEN_PARMSW
+  LPMCI_OVLY_OPEN_PARMSW* = ptr MCI_OVLY_OPEN_PARMSW
+  TMCI_OVLY_OPEN_PARMSW* = MCI_OVLY_OPEN_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_OVLY_OPEN_PARMS* = MCI_OVLY_OPEN_PARMSW
+    PMCI_OVLY_OPEN_PARMS* = PMCI_OVLY_OPEN_PARMSW
+    LPMCI_OVLY_OPEN_PARMS* = LPMCI_OVLY_OPEN_PARMSW
+else:
+  type
+    MCI_OVLY_OPEN_PARMS* = MCI_OVLY_OPEN_PARMSA
+    PMCI_OVLY_OPEN_PARMS* = PMCI_OVLY_OPEN_PARMSA
+    LPMCI_OVLY_OPEN_PARMS* = LPMCI_OVLY_OPEN_PARMSA
+type
+  TMCI_OVLY_OPEN_PARMS* = MCI_OVLY_OPEN_PARMS
+  MCI_OVLY_WINDOW_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    hWnd*: HWND
+    nCmdShow*: uint32
+    lpstrText*: LPCSTR
+
+  PMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA
+  LPMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA
+  TMCI_OVLY_WINDOW_PARMSA* = MCI_OVLY_WINDOW_PARMSA
+  MCI_OVLY_WINDOW_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    hWnd*: HWND
+    nCmdShow*: uint32
+    lpstrText*: LPCWSTR
+
+  PMCI_OVLY_WINDOW_PARMSW* = ptr MCI_OVLY_WINDOW_PARMSW
+  LPMCI_OVLY_WINDOW_PARMSW* = ptr MCI_OVLY_WINDOW_PARMSW
+  TMCI_OVLY_WINDOW_PARMSW* = MCI_OVLY_WINDOW_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW
+    PMCI_OVLY_WINDOW_PARMS* = PMCI_OVLY_WINDOW_PARMSW
+    LPMCI_OVLY_WINDOW_PARMS* = LPMCI_OVLY_WINDOW_PARMSW
+else:
+  type
+    MCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSA
+    PMCI_OVLY_WINDOW_PARMS* = PMCI_OVLY_WINDOW_PARMSA
+    LPMCI_OVLY_WINDOW_PARMS* = LPMCI_OVLY_WINDOW_PARMSA
+type
+  TMCI_OVLY_WINDOW_PARMS* = MCI_OVLY_WINDOW_PARMSW
+  MCI_OVLY_RECT_PARMS* {.final.} = object
+    dwCallback*: DWORD
+    rc*: TRECT
+
+  PMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
+  LPMCI_OVLY_RECT_PARMS* = ptr MCI_OVLY_RECT_PARMS
+  TMCI_OVLY_RECT_PARMS* = MCI_OVLY_RECT_PARMS
+  MCI_OVLY_SAVE_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCSTR
+    rc*: TRECT
+
+  PMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
+  LPMCI_OVLY_SAVE_PARMSA* = ptr MCI_OVLY_SAVE_PARMSA
+  TMCI_OVLY_SAVE_PARMSA* = MCI_OVLY_SAVE_PARMSA
+  MCI_OVLY_SAVE_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCWSTR
+    rc*: TRECT
+
+  PMCI_OVLY_SAVE_PARMSW* = ptr MCI_OVLY_SAVE_PARMSW
+  LPMCI_OVLY_SAVE_PARMSW* = ptr MCI_OVLY_SAVE_PARMSW
+  TMCI_OVLY_SAVE_PARMSW* = MCI_OVLY_SAVE_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_OVLY_SAVE_PARMS* = MCI_OVLY_SAVE_PARMSW
+    PMCI_OVLY_SAVE_PARMS* = PMCI_OVLY_SAVE_PARMSW
+    LPMCI_OVLY_SAVE_PARMS* = LPMCI_OVLY_SAVE_PARMSW
+else:
+  type
+    MCI_OVLY_SAVE_PARMS* = MCI_OVLY_SAVE_PARMSA
+    PMCI_OVLY_SAVE_PARMS* = PMCI_OVLY_SAVE_PARMSA
+    LPMCI_OVLY_SAVE_PARMS* = LPMCI_OVLY_SAVE_PARMSA
+type
+  TMCI_OVLY_SAVE_PARMS* = MCI_OVLY_SAVE_PARMS
+  MCI_OVLY_LOAD_PARMSA* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCSTR
+    rc*: TRECT
+
+  PMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
+  LPMCI_OVLY_LOAD_PARMSA* = ptr MCI_OVLY_LOAD_PARMSA
+  TMCI_OVLY_LOAD_PARMSA* = MCI_OVLY_LOAD_PARMSA
+  MCI_OVLY_LOAD_PARMSW* {.final.} = object
+    dwCallback*: DWORD
+    lpfilename*: LPCWSTR
+    rc*: TRECT
+
+  PMCI_OVLY_LOAD_PARMSW* = ptr MCI_OVLY_LOAD_PARMSW
+  LPMCI_OVLY_LOAD_PARMSW* = ptr MCI_OVLY_LOAD_PARMSW
+  TMCI_OVLY_LOAD_PARMSW* = MCI_OVLY_LOAD_PARMSW
+
+when defined(UNICODE):
+  type
+    MCI_OVLY_LOAD_PARMS* = MCI_OVLY_LOAD_PARMSW
+    PMCI_OVLY_LOAD_PARMS* = PMCI_OVLY_LOAD_PARMSW
+    LPMCI_OVLY_LOAD_PARMS* = LPMCI_OVLY_LOAD_PARMSW
+else:
+  type
+    MCI_OVLY_LOAD_PARMS* = MCI_OVLY_LOAD_PARMSA
+    PMCI_OVLY_LOAD_PARMS* = PMCI_OVLY_LOAD_PARMSA
+    LPMCI_OVLY_LOAD_PARMS* = LPMCI_OVLY_LOAD_PARMSA
+type
+  TMCI_OVLY_LOAD_PARMS* = MCI_OVLY_LOAD_PARMS
+
+proc mmioStringToFOURCCA*(x1: LPCSTR, x2: uint32): FOURCC{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioStringToFOURCCA".}
+proc mmioStringToFOURCCW*(x1: LPCWSTR, x2: uint32): FOURCC{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioStringToFOURCCW".}
+proc mmioStringToFOURCC*(x1: cstring, x2: uint32): FOURCC{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioStringToFOURCCA".}
+proc mmioInstallIOProcA*(x1: FOURCC, x2: LPMMIOPROC, x3: DWORD): LPMMIOPROC{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioInstallIOProcA".}
+proc mmioInstallIOProcW*(x1: FOURCC, x2: LPMMIOPROC, x3: DWORD): LPMMIOPROC{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioInstallIOProcW".}
+proc mmioInstallIOProc*(x1: FOURCC, x2: LPMMIOPROC, x3: DWORD): LPMMIOPROC{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioInstallIOProcA".}
+proc mmioOpenA*(x1: LPSTR, x2: LPMMIOINFO, x3: DWORD): HMMIO{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioOpenA".}
+proc mmioOpenW*(x1: LPWSTR, x2: LPMMIOINFO, x3: DWORD): HMMIO{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioOpenW".}
+proc mmioOpen*(x1: cstring, x2: LPMMIOINFO, x3: DWORD): HMMIO{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioOpenA".}
+proc mmioRenameA*(x1: LPCSTR, x2: LPCSTR, x3: LPCMMIOINFO, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioRenameA".}
+proc mmioRenameW*(x1: LPCWSTR, x2: LPCWSTR, x3: LPCMMIOINFO, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioRenameW".}
+proc mmioRename*(x1: cstring, x2: cstring, x3: LPCMMIOINFO, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioRenameA".}
+proc mmioClose*(x1: HMMIO, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "mmioClose".}
+proc mmioRead*(x1: HMMIO, x2: HPSTR, x3: LONG): LONG{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioRead".}
+proc mmioWrite*(x1: HMMIO, x2: cstring, x3: LONG): LONG{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioWrite".}
+proc mmioSeek*(x1: HMMIO, x2: LONG, x3: WINT): LONG{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioSeek".}
+proc mmioGetInfo*(x1: HMMIO, x2: LPMMIOINFO, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioGetInfo".}
+proc mmioSetInfo*(x1: HMMIO, x2: LPCMMIOINFO, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioSetInfo".}
+proc mmioSetBuffer*(x1: HMMIO, x2: LPSTR, x3: LONG, x4: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioSetBuffer".}
+proc mmioFlush*(x1: HMMIO, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "mmioFlush".}
+proc mmioAdvance*(x1: HMMIO, x2: LPMMIOINFO, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioAdvance".}
+proc mmioSendMessage*(x1: HMMIO, x2: uint32, x3: LPARAM, x4: LPARAM): LRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioSendMessage".}
+proc mmioDescend*(x1: HMMIO, x2: LPMMCKINFO, x3: PMMCKINFO, x4: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mmioDescend".}
+proc mmioAscend*(x1: HMMIO, x2: LPMMCKINFO, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioAscend".}
+proc mmioCreateChunk*(x1: HMMIO, x2: LPMMCKINFO, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mmioCreateChunk".}
+proc mciSendCommandA*(x1: MCIDEVICEID, x2: uint32, x3: DWORD, x4: DWORD): MCIERROR{.
+    stdcall, dynlib: "winmm.dll", importc: "mciSendCommandA".}
+proc mciSendCommandW*(x1: MCIDEVICEID, x2: uint32, x3: DWORD, x4: DWORD): MCIERROR{.
+    stdcall, dynlib: "winmm.dll", importc: "mciSendCommandW".}
+proc mciSendCommand*(x1: MCIDEVICEID, x2: uint32, x3: DWORD, x4: DWORD): MCIERROR{.
+    stdcall, dynlib: "winmm.dll", importc: "mciSendCommandA".}
+proc mciSendStringA*(x1: LPCSTR, x2: LPSTR, x3: uint32, x4: HWND): MCIERROR{.
+    stdcall, dynlib: "winmm.dll", importc: "mciSendStringA".}
+proc mciSendStringW*(x1: LPCWSTR, x2: LPWSTR, x3: uint32, x4: HWND): MCIERROR{.
+    stdcall, dynlib: "winmm.dll", importc: "mciSendStringW".}
+proc mciSendString*(x1: cstring, x2: cstring, x3: uint32, x4: HWND): MCIERROR{.
+    stdcall, dynlib: "winmm.dll", importc: "mciSendStringA".}
+proc mciGetDeviceIDA*(x1: LPCSTR): MCIDEVICEID{.stdcall, dynlib: "winmm.dll",
+    importc: "mciGetDeviceIDA".}
+proc mciGetDeviceIDW*(x1: LPCWSTR): MCIDEVICEID{.stdcall, dynlib: "winmm.dll",
+    importc: "mciGetDeviceIDW".}
+proc mciGetDeviceID*(x1: cstring): MCIDEVICEID{.stdcall, dynlib: "winmm.dll",
+    importc: "mciGetDeviceIDA".}
+proc mciGetDeviceIDFromElementIDA*(x1: DWORD, x2: LPCSTR): MCIDEVICEID{.stdcall,
+    dynlib: "winmm.dll", importc: "mciGetDeviceIDFromElementIDA".}
+proc mciGetDeviceIDFromElementIDW*(x1: DWORD, x2: LPCWSTR): MCIDEVICEID{.
+    stdcall, dynlib: "winmm.dll", importc: "mciGetDeviceIDFromElementIDW".}
+proc mciGetDeviceIDFromElementID*(x1: DWORD, x2: cstring): MCIDEVICEID{.stdcall,
+    dynlib: "winmm.dll", importc: "mciGetDeviceIDFromElementIDA".}
+proc mciGetErrorStringA*(x1: MCIERROR, x2: LPSTR, x3: uint32): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "mciGetErrorStringA".}
+proc mciGetErrorStringW*(x1: MCIERROR, x2: LPWSTR, x3: uint32): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "mciGetErrorStringW".}
+proc mciGetErrorString*(x1: MCIERROR, x2: cstring, x3: uint32): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "mciGetErrorStringA".}
+proc mciSetYieldProc*(x1: MCIDEVICEID, x2: YIELDPROC, x3: DWORD): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "mciSetYieldProc".}
+proc mciGetCreatorTask*(x1: MCIDEVICEID): HTASK{.stdcall, dynlib: "winmm.dll",
+    importc: "mciGetCreatorTask".}
+proc mciGetYieldProc*(x1: MCIDEVICEID, x2: LPDWORD): YIELDPROC{.stdcall,
+    dynlib: "winmm.dll", importc: "mciGetYieldProc".}
+proc mciExecute*(x1: LPCSTR): bool{.stdcall, dynlib: "winmm.dll",
+                                    importc: "mciExecute".}
+proc joyGetPos*(x1: uint32, x2: LPJOYINFO): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joyGetPos".}
+proc joyGetPosEx*(x1: uint32, x2: LPJOYINFOEX): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joyGetPosEx".}
+proc joyGetThreshold*(x1: uint32, x2: LPUINT): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joyGetThreshold".}
+proc joyReleaseCapture*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "joyReleaseCapture".}
+proc joySetCapture*(x1: HWND, x2: uint32, x3: uint32, x4: bool): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joySetCapture".}
+proc joySetThreshold*(x1: uint32, x2: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joySetThreshold".}
+proc waveOutGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                                 importc: "waveOutGetNumDevs".}
+proc waveOutGetDevCapsA*(x1: uint32, x2: LPWAVEOUTCAPSA, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetDevCapsA".}
+proc waveOutGetDevCapsW*(x1: uint32, x2: LPWAVEOUTCAPSW, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetDevCapsW".}
+proc waveOutGetDevCaps*(x1: uint32, x2: LPWAVEOUTCAPS, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetDevCapsA".}
+proc waveOutGetVolume*(x1: HWAVEOUT, x2: LPDWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutGetVolume".}
+proc waveOutSetVolume*(x1: HWAVEOUT, x2: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutSetVolume".}
+proc waveOutGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetErrorTextA".}
+proc waveOutGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetErrorTextW".}
+proc waveOutGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetErrorTextA".}
+proc waveOutOpen*(x1: LPHWAVEOUT, x2: uint32, x3: LPCWAVEFORMATEX, x4: DWORD,
+                  x5: DWORD, x6: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveOutOpen".}
+proc waveOutClose*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveOutClose".}
+proc waveOutPrepareHeader*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutPrepareHeader".}
+proc waveOutUnprepareHeader*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutUnprepareHeader".}
+proc waveOutWrite*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutWrite".}
+proc waveOutPause*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveOutPause".}
+proc waveOutRestart*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveOutRestart".}
+proc waveOutReset*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveOutReset".}
+proc waveOutBreakLoop*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveOutBreakLoop".}
+proc waveOutGetPosition*(x1: HWAVEOUT, x2: LPMMTIME, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutGetPosition".}
+proc waveOutGetPitch*(x1: HWAVEOUT, x2: LPDWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutGetPitch".}
+proc waveOutSetPitch*(x1: HWAVEOUT, x2: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutSetPitch".}
+proc waveOutGetPlaybackRate*(x1: HWAVEOUT, x2: LPDWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutGetPlaybackRate".}
+proc waveOutSetPlaybackRate*(x1: HWAVEOUT, x2: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutSetPlaybackRate".}
+proc waveOutGetID*(x1: HWAVEOUT, x2: LPUINT): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveOutGetID".}
+proc waveOutMessage*(x1: HWAVEOUT, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveOutMessage".}
+proc waveInGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                                importc: "waveInGetNumDevs".}
+proc waveInGetDevCapsA*(x1: uint32, x2: LPWAVEINCAPSA, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInGetDevCapsA".}
+proc waveInGetDevCapsW*(x1: uint32, x2: LPWAVEINCAPSW, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInGetDevCapsW".}
+proc waveInGetDevCaps*(x1: uint32, x2: LPWAVEINCAPS, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveInGetDevCapsA".}
+proc waveInGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveInGetErrorTextA".}
+proc waveInGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInGetErrorTextW".}
+proc waveInGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInGetErrorTextA".}
+proc waveInOpen*(x1: LPHWAVEIN, x2: uint32, x3: LPCWAVEFORMATEX, x4: DWORD,
+                 x5: DWORD, x6: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveInOpen".}
+proc waveInClose*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveInClose".}
+proc waveInPrepareHeader*(x1: HWAVEIN, x2: LPWAVEHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInPrepareHeader".}
+proc waveInUnprepareHeader*(x1: HWAVEIN, x2: LPWAVEHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInUnprepareHeader".}
+proc waveInAddBuffer*(x1: HWAVEIN, x2: LPWAVEHDR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveInAddBuffer".}
+proc waveInStart*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveInStart".}
+proc waveInStop*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveInStop".}
+proc waveInReset*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "waveInReset".}
+proc waveInGetPosition*(x1: HWAVEIN, x2: LPMMTIME, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveInGetPosition".}
+proc waveInGetID*(x1: HWAVEIN, x2: LPUINT): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "waveInGetID".}
+proc waveInMessage*(x1: HWAVEIN, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "waveInMessage".}
+proc mixerGetLineControlsA*(x1: HMIXEROBJ, x2: LPMIXERLINECONTROLSA, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetLineControlsA".}
+proc mixerGetLineControlsW*(x1: HMIXEROBJ, x2: LPMIXERLINECONTROLSW, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetLineControlsW".}
+proc mixerGetLineControls*(x1: HMIXEROBJ, x2: LPMIXERLINECONTROLS, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetLineControlsA".}
+proc joyGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                             importc: "joyGetNumDevs".}
+proc joyGetDevCapsA*(x1: uint32, x2: LPJOYCAPSA, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joyGetDevCapsA".}
+proc joyGetDevCapsW*(x1: uint32, x2: LPJOYCAPSW, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joyGetDevCapsW".}
+proc joyGetDevCaps*(x1: uint32, x2: LPJOYCAPS, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "joyGetDevCapsA".}
+proc mixerGetControlDetailsA*(x1: HMIXEROBJ, x2: LPMIXERCONTROLDETAILS,
+                              x3: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerGetControlDetailsA".}
+proc mixerGetControlDetailsW*(x1: HMIXEROBJ, x2: LPMIXERCONTROLDETAILS,
+                              x3: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerGetControlDetailsW".}
+proc mixerGetControlDetails*(x1: HMIXEROBJ, x2: LPMIXERCONTROLDETAILS, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetControlDetailsA".}
+proc timeGetSystemTime*(x1: LPMMTIME, x2: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "timeGetSystemTime".}
+proc timeGetTime*(): DWORD{.stdcall, dynlib: "winmm.dll", importc: "timeGetTime".}
+proc timeSetEvent*(x1: uint32, x2: uint32, x3: LPTIMECALLBACK, x4: DWORD, x5: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "timeSetEvent".}
+proc timeKillEvent*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "timeKillEvent".}
+proc timeGetDevCaps*(x1: LPTIMECAPS, x2: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "timeGetDevCaps".}
+proc timeBeginPeriod*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "timeBeginPeriod".}
+proc timeEndPeriod*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "timeEndPeriod".}
+proc mixerGetDevCapsA*(x1: uint32, x2: LPMIXERCAPSA, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerGetDevCapsA".}
+proc mixerGetDevCapsW*(x1: uint32, x2: LPMIXERCAPSW, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerGetDevCapsW".}
+proc mixerGetDevCaps*(x1: uint32, x2: LPMIXERCAPS, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerGetDevCapsA".}
+proc mixerOpen*(x1: LPHMIXER, x2: uint32, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerOpen".}
+proc mixerClose*(x1: HMIXER): MMRESULT{.stdcall, dynlib: "winmm.dll",
+                                        importc: "mixerClose".}
+proc mixerMessage*(x1: HMIXER, x2: uint32, x3: DWORD, x4: DWORD): DWORD{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerMessage".}
+proc auxGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                             importc: "auxGetNumDevs".}
+proc auxGetDevCapsA*(x1: uint32, x2: LPAUXCAPSA, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "auxGetDevCapsA".}
+proc auxGetDevCapsW*(x1: uint32, x2: LPAUXCAPSW, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "auxGetDevCapsW".}
+proc auxGetDevCaps*(x1: uint32, x2: LPAUXCAPS, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "auxGetDevCapsA".}
+proc auxSetVolume*(x1: uint32, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "auxSetVolume".}
+proc auxGetVolume*(x1: uint32, x2: LPDWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "auxGetVolume".}
+proc auxOutMessage*(x1: uint32, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "auxOutMessage".}
+proc midiOutGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                                 importc: "midiOutGetNumDevs".}
+proc midiStreamOpen*(x1: LPHMIDISTRM, x2: LPUINT, x3: DWORD, x4: DWORD,
+                     x5: DWORD, x6: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiStreamOpen".}
+proc midiStreamClose*(x1: HMIDISTRM): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiStreamClose".}
+proc midiStreamProperty*(x1: HMIDISTRM, x2: LPBYTE, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiStreamProperty".}
+proc midiStreamPosition*(x1: HMIDISTRM, x2: LPMMTIME, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiStreamPosition".}
+proc midiStreamOut*(x1: HMIDISTRM, x2: LPMIDIHDR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiStreamOut".}
+proc midiStreamPause*(x1: HMIDISTRM): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiStreamPause".}
+proc midiStreamRestart*(x1: HMIDISTRM): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiStreamRestart".}
+proc midiStreamStop*(x1: HMIDISTRM): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiStreamStop".}
+proc midiConnect*(x1: HMIDI, x2: HMIDIOUT, x3: pointer): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiConnect".}
+proc midiDisconnect*(x1: HMIDI, x2: HMIDIOUT, x3: pointer): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiDisconnect".}
+proc midiOutGetDevCapsA*(x1: uint32, x2: LPMIDIOUTCAPSA, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutGetDevCapsA".}
+proc midiOutGetDevCapsW*(x1: uint32, x2: LPMIDIOUTCAPSW, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutGetDevCapsW".}
+proc midiOutGetDevCaps*(x1: uint32, x2: LPMIDIOUTCAPS, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutGetDevCapsA".}
+proc midiOutGetVolume*(x1: HMIDIOUT, x2: LPDWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiOutGetVolume".}
+proc midiOutSetVolume*(x1: HMIDIOUT, x2: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiOutSetVolume".}
+proc midiOutGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutGetErrorTextA".}
+proc midiOutGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutGetErrorTextW".}
+proc midiOutGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutGetErrorTextA".}
+proc midiOutOpen*(x1: LPHMIDIOUT, x2: uint32, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutOpen".}
+proc midiOutClose*(x1: HMIDIOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiOutClose".}
+proc midiOutPrepareHeader*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutPrepareHeader".}
+proc midiOutUnprepareHeader*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutUnprepareHeader".}
+proc midiOutShortMsg*(x1: HMIDIOUT, x2: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiOutShortMsg".}
+proc midiOutLongMsg*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiOutLongMsg".}
+proc midiOutReset*(x1: HMIDIOUT): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiOutReset".}
+proc midiOutCachePatches*(x1: HMIDIOUT, x2: uint32, x3: LPWORD, x4: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutCachePatches".}
+proc midiOutCacheDrumPatches*(x1: HMIDIOUT, x2: uint32, x3: LPWORD, x4: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutCacheDrumPatches".}
+proc midiOutGetID*(x1: HMIDIOUT, x2: LPUINT): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiOutGetID".}
+proc midiOutMessage*(x1: HMIDIOUT, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiOutMessage".}
+proc midiInGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll",
+                                importc: "midiInGetNumDevs".}
+proc midiInGetDevCapsA*(x1: uint32, x2: LPMIDIINCAPSA, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInGetDevCapsA".}
+proc midiInGetDevCapsW*(x1: uint32, x2: LPMIDIINCAPSW, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInGetDevCapsW".}
+proc midiInGetDevCaps*(x1: uint32, x2: LPMIDIINCAPS, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiInGetDevCapsA".}
+proc midiInGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiInGetErrorTextA".}
+proc midiInGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInGetErrorTextW".}
+proc midiInGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInGetErrorTextA".}
+proc midiInOpen*(x1: LPHMIDIIN, x2: uint32, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInOpen".}
+proc midiInClose*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiInClose".}
+proc midiInPrepareHeader*(x1: HMIDIIN, x2: LPMIDIHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInPrepareHeader".}
+proc midiInUnprepareHeader*(x1: HMIDIIN, x2: LPMIDIHDR, x3: uint32): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInUnprepareHeader".}
+proc midiInAddBuffer*(x1: HMIDIIN, x2: LPMIDIHDR, x3: uint32): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiInAddBuffer".}
+proc midiInStart*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiInStart".}
+proc midiInStop*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiInStop".}
+proc midiInReset*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll",
+    importc: "midiInReset".}
+proc midiInGetID*(x1: HMIDIIN, x2: LPUINT): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "midiInGetID".}
+proc midiInMessage*(x1: HMIDIIN, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "midiInMessage".}
+proc mixerGetLineInfoA*(x1: HMIXEROBJ, x2: LPMIXERLINEA, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetLineInfoA".}
+proc mixerGetLineInfoW*(x1: HMIXEROBJ, x2: LPMIXERLINEW, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetLineInfoW".}
+proc mixerGetLineInfo*(x1: HMIXEROBJ, x2: LPMIXERLINE, x3: DWORD): MMRESULT{.
+    stdcall, dynlib: "winmm.dll", importc: "mixerGetLineInfoA".}
+proc mixerGetID*(x1: HMIXEROBJ, x2: var uint32, x3: DWORD): MMRESULT{.stdcall,
+    dynlib: "winmm.dll", importc: "mixerGetID".}
+proc PlaySoundA*(x1: LPCSTR, x2: HMODULE, x3: DWORD): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "PlaySoundA".}
+proc PlaySoundW*(x1: LPCWSTR, x2: HMODULE, x3: DWORD): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "PlaySoundW".}
+proc PlaySound*(x1: cstring, x2: HMODULE, x3: DWORD): bool{.stdcall,
+    dynlib: "winmm.dll", importc: "PlaySoundA".}
+# implementation
+
+proc MEVT_EVENTTYPE(x: int8): int8 =
+  result = toU8(x shr 24)
+
+proc MEVT_EVENTPARM(x: DWORD): DWORD =
+  result = x and 0x00FFFFFF
+
+proc MCI_MSF_MINUTE(msf: int32): int8 =
+  result = toU8(msf and 0xff)
+
+proc MCI_TMSF_TRACK(tmsf: int32): int8 =
+  result = toU8(tmsf and 0xff)
+
+proc MCI_HMS_HOUR(h: int32): int8 =
+  result = toU8(h and 0xff)
+
+proc MCI_MSF_SECOND(msf: int32): int8 =
+  result = toU8(msf shr 8)
+
+proc MCI_TMSF_MINUTE(tmsf: int32): int8 =
+  result = toU8(tmsf shr 8)
+
+proc MCI_HMS_MINUTE(h: int32): int8 =
+  result = toU8(h shr 8)
+
+proc MCI_MSF_FRAME(msf: int32): int8 =
+  result = toU8(msf shr 16)
+
+proc MCI_TMSF_SECOND(tmsf: int32): int8 =
+  result = toU8(tmsf shr 16)
+
+proc MCI_HMS_SECOND(h: int32): int8 =
+  result = toU8(h shr 16)
+
+proc MCI_MAKE_MSF(m, s, f: int8): int32 =
+  result = toU32(ze(m) or ze(s) shl 8 or ze(f) shl 16)
+
+proc MCI_MAKE_HMS(h, m, s: int8): int32 =
+  result = toU32(ze(h) or ze(m) shl 8 or ze(s) shl 16)
+
+proc MCI_TMSF_FRAME(tmsf: int32): int8 =
+  result = toU8(tmsf shr 24)
+
+proc MCI_MAKE_TMSF(t, m, s, f: int8): int32 =
+  result = (ze(t) or ze(m) shl 8 or ze(s) shl 16 or ze(f) shl 24).int32
+
+proc DIBINDEX(n: int32): int32 =
+  result = n or 0x000010FF'i32 shl 16'i32
diff --git a/lib/windows/nb30.nim b/lib/windows/nb30.nim
new file mode 100644
index 000000000..2e0c679ae
--- /dev/null
+++ b/lib/windows/nb30.nim
@@ -0,0 +1,232 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+#       NetBIOS 3.0 interface unit 
+
+# This module contains the definitions for portable NetBIOS 3.0 support. 
+
+{.deadCodeElim: on.}
+
+import                        # Data structure templates 
+  windows
+
+const 
+  NCBNAMSZ* = 16              # absolute length of a net name
+  MAX_LANA* = 254             # lana's in range 0 to MAX_LANA inclusive
+
+type                          # Network Control Block
+  PNCB* = ptr TNCB
+  TNCBPostProc* = proc (P: PNCB) {.stdcall.}
+  TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed
+                           # by an array of NAME_BUFFER structures.
+    ncb_command*: char        # command code
+    ncb_retcode*: char        # return code
+    ncb_lsn*: char            # local session number
+    ncb_num*: char            # number of our network name
+    ncb_buffer*: cstring      # address of message buffer
+    ncb_length*: int16        # size of message buffer
+    ncb_callname*: array[0..NCBNAMSZ - 1, char] # blank-padded name of remote
+    ncb_name*: array[0..NCBNAMSZ - 1, char] # our blank-padded netname
+    ncb_rto*: char            # rcv timeout/retry count
+    ncb_sto*: char            # send timeout/sys timeout
+    ncb_post*: TNCBPostProc   # POST routine address
+    ncb_lana_num*: char       # lana (adapter) number
+    ncb_cmd_cplt*: char       # 0xff => commmand pending
+    ncb_reserve*: array[0..9, char] # reserved, used by BIOS
+    ncb_event*: THandle       # HANDLE to Win32 event which
+                              # will be set to the signalled
+                              # state when an ASYNCH command
+                              # completes
+  
+  PAdapterStatus* = ptr TAdapterStatus
+  TAdapterStatus* {.final.} = object 
+    adapter_address*: array[0..5, char]
+    rev_major*: char
+    reserved0*: char
+    adapter_type*: char
+    rev_minor*: char
+    duration*: int16
+    frmr_recv*: int16
+    frmr_xmit*: int16
+    iframe_recv_err*: int16
+    xmit_aborts*: int16
+    xmit_success*: DWORD
+    recv_success*: DWORD
+    iframe_xmit_err*: int16
+    recv_buff_unavail*: int16
+    t1_timeouts*: int16
+    ti_timeouts*: int16
+    reserved1*: DWORD
+    free_ncbs*: int16
+    max_cfg_ncbs*: int16
+    max_ncbs*: int16
+    xmit_buf_unavail*: int16
+    max_dgram_size*: int16
+    pending_sess*: int16
+    max_cfg_sess*: int16
+    max_sess*: int16
+    max_sess_pkt_size*: int16
+    name_count*: int16
+
+  PNameBuffer* = ptr TNameBuffer
+  TNameBuffer* {.final.} = object 
+    name*: array[0..NCBNAMSZ - 1, char]
+    name_num*: char
+    name_flags*: char
+
+
+const                         # values for name_flags bits.
+  NAME_FLAGS_MASK* = 0x00000087
+  GROUP_NAME* = 0x00000080
+  UNIQUE_NAME* = 0x00000000
+  REGISTERING* = 0x00000000
+  REGISTERED* = 0x00000004
+  DEREGISTERED* = 0x00000005
+  DUPLICATE* = 0x00000006
+  DUPLICATE_DEREG* = 0x00000007
+
+type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed
+     # by an array of SESSION_BUFFER structures. If the NCB_NAME starts with an
+     # asterisk then an array of these structures is returned containing the
+     # status for all names.
+  PSessionHeader* = ptr TSessionHeader
+  TSessionHeader* {.final.} = object 
+    sess_name*: char
+    num_sess*: char
+    rcv_dg_outstanding*: char
+    rcv_any_outstanding*: char
+
+  PSessionBuffer* = ptr TSessionBuffer
+  TSessionBuffer* {.final.} = object 
+    lsn*: char
+    state*: char
+    local_name*: array[0..NCBNAMSZ - 1, char]
+    remote_name*: array[0..NCBNAMSZ - 1, char]
+    rcvs_outstanding*: char
+    sends_outstanding*: char
+
+
+const                         # Values for state
+  LISTEN_OUTSTANDING* = 0x00000001
+  CALL_PENDING* = 0x00000002
+  SESSION_ESTABLISHED* = 0x00000003
+  HANGUP_PENDING* = 0x00000004
+  HANGUP_COMPLETE* = 0x00000005
+  SESSION_ABORTED* = 0x00000006
+
+type # Structure returned to the NCB command NCBENUM.
+     # On a system containing lana's 0, 2 and 3, a structure with
+     # length =3, lana[0]=0, lana[1]=2 and lana[2]=3 will be returned.
+  PLanaEnum* = ptr TLanaEnum
+  TLanaEnum* {.final.} = object # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed
+                                # by an array of FIND_NAME_BUFFER structures.
+    len*: char                #  Number of valid entries in lana[]
+    lana*: array[0..MAX_LANA, char]
+
+  PFindNameHeader* = ptr TFindNameHeader
+  TFindNameHeader* {.final.} = object 
+    node_count*: int16
+    reserved*: char
+    unique_group*: char
+
+  PFindNameBuffer* = ptr TFindNameBuffer
+  TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide
+                                      # transport specific extensions to netbios.
+    len*: char
+    access_control*: char
+    frame_control*: char
+    destination_addr*: array[0..5, char]
+    source_addr*: array[0..5, char]
+    routing_info*: array[0..17, char]
+
+  PActionHeader* = ptr TActionHeader
+  TActionHeader* {.final.} = object 
+    transport_id*: int32
+    action_code*: int16
+    reserved*: int16
+
+
+const                         # Values for transport_id
+  ALL_TRANSPORTS* = "M\0\0\0"
+  MS_NBF* = "MNBF"            # Special values and constants 
+
+const                         # NCB Command codes
+  NCBCALL* = 0x00000010       # NCB CALL
+  NCBLISTEN* = 0x00000011     # NCB LISTEN
+  NCBHANGUP* = 0x00000012     # NCB HANG UP
+  NCBSEND* = 0x00000014       # NCB SEND
+  NCBRECV* = 0x00000015       # NCB RECEIVE
+  NCBRECVANY* = 0x00000016    # NCB RECEIVE ANY
+  NCBCHAINSEND* = 0x00000017  # NCB CHAIN SEND
+  NCBDGSEND* = 0x00000020     # NCB SEND DATAGRAM
+  NCBDGRECV* = 0x00000021     # NCB RECEIVE DATAGRAM
+  NCBDGSENDBC* = 0x00000022   # NCB SEND BROADCAST DATAGRAM
+  NCBDGRECVBC* = 0x00000023   # NCB RECEIVE BROADCAST DATAGRAM
+  NCBADDNAME* = 0x00000030    # NCB ADD NAME
+  NCBDELNAME* = 0x00000031    # NCB DELETE NAME
+  NCBRESET* = 0x00000032      # NCB RESET
+  NCBASTAT* = 0x00000033      # NCB ADAPTER STATUS
+  NCBSSTAT* = 0x00000034      # NCB SESSION STATUS
+  NCBCANCEL* = 0x00000035     # NCB CANCEL
+  NCBADDGRNAME* = 0x00000036  # NCB ADD GROUP NAME
+  NCBENUM* = 0x00000037       # NCB ENUMERATE LANA NUMBERS
+  NCBUNLINK* = 0x00000070     # NCB UNLINK
+  NCBSENDNA* = 0x00000071     # NCB SEND NO ACK
+  NCBCHAINSENDNA* = 0x00000072 # NCB CHAIN SEND NO ACK
+  NCBLANSTALERT* = 0x00000073 # NCB LAN STATUS ALERT
+  NCBACTION* = 0x00000077     # NCB ACTION
+  NCBFINDNAME* = 0x00000078   # NCB FIND NAME
+  NCBTRACE* = 0x00000079      # NCB TRACE
+  ASYNCH* = 0x00000080        # high bit set = asynchronous
+                              # NCB Return codes
+  NRC_GOODRET* = 0x00000000   # good return
+                              # also returned when ASYNCH request accepted
+  NRC_BUFLEN* = 0x00000001    # illegal buffer length
+  NRC_ILLCMD* = 0x00000003    # illegal command
+  NRC_CMDTMO* = 0x00000005    # command timed out
+  NRC_INCOMP* = 0x00000006    # message incomplete, issue another command
+  NRC_BADDR* = 0x00000007     # illegal buffer address
+  NRC_SNUMOUT* = 0x00000008   # session number out of range
+  NRC_NORES* = 0x00000009     # no resource available
+  NRC_SCLOSED* = 0x0000000A   # session closed
+  NRC_CMDCAN* = 0x0000000B    # command cancelled
+  NRC_DUPNAME* = 0x0000000D   # duplicate name
+  NRC_NAMTFUL* = 0x0000000E   # name table full
+  NRC_ACTSES* = 0x0000000F    # no deletions, name has active sessions
+  NRC_LOCTFUL* = 0x00000011   # local session table full
+  NRC_REMTFUL* = 0x00000012   # remote session table full
+  NRC_ILLNN* = 0x00000013     # illegal name number
+  NRC_NOCALL* = 0x00000014    # no callname
+  NRC_NOWILD* = 0x00000015    # cannot put * in NCB_NAME
+  NRC_INUSE* = 0x00000016     # name in use on remote adapter
+  NRC_NAMERR* = 0x00000017    # name deleted
+  NRC_SABORT* = 0x00000018    # session ended abnormally
+  NRC_NAMCONF* = 0x00000019   # name conflict detected
+  NRC_IFBUSY* = 0x00000021    # interface busy, IRET before retrying
+  NRC_TOOMANY* = 0x00000022   # too many commands outstanding, retry later
+  NRC_BRIDGE* = 0x00000023    # NCB_lana_num field invalid
+  NRC_CANOCCR* = 0x00000024   # command completed while cancel occurring
+  NRC_CANCEL* = 0x00000026    # command not valid to cancel
+  NRC_DUPENV* = 0x00000030    # name defined by anther local process
+  NRC_ENVNOTDEF* = 0x00000034 # environment undefined. RESET required
+  NRC_OSRESNOTAV* = 0x00000035 # required OS resources exhausted
+  NRC_MAXAPPS* = 0x00000036   # max number of applications exceeded
+  NRC_NOSAPS* = 0x00000037    # no saps available for netbios
+  NRC_NORESOURCES* = 0x00000038 # requested resources are not available
+  NRC_INVADDRESS* = 0x00000039 # invalid ncb address or length > segment
+  NRC_INVDDID* = 0x0000003B   # invalid NCB DDID
+  NRC_LOCKFAIL* = 0x0000003C  # lock of user area failed
+  NRC_OPENERR* = 0x0000003F   # NETBIOS not loaded
+  NRC_SYSTEM* = 0x00000040    # system error
+  NRC_PENDING* = 0x000000FF   # asynchronous command is not yet finished
+                              # main user entry point for NetBIOS 3.0
+                              #   Usage: Result = Netbios( pncb ); 
+
+proc Netbios*(P: PNCB): char{.stdcall, dynlib: "netapi32.dll", 
+                              importc: "Netbios".}
+# implementation
diff --git a/lib/windows/psapi.nim b/lib/windows/psapi.nim
new file mode 100644
index 000000000..fd1dcada8
--- /dev/null
+++ b/lib/windows/psapi.nim
@@ -0,0 +1,202 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+#       PSAPI interface unit
+
+# Contains the definitions for the APIs provided by PSAPI.DLL
+
+import                        # Data structure templates
+  Windows
+
+const
+  psapiDll = "psapi.dll"
+
+proc EnumProcesses*(lpidProcess: ptr DWORD, cb: DWORD, 
+                    cbNeeded: ptr DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "EnumProcesses".}
+proc EnumProcessModules*(hProcess: HANDLE, lphModule: ptr HMODULE, cb: DWORD, lpcbNeeded: LPDWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "EnumProcessModules".}
+
+proc GetModuleBaseNameA*(hProcess: HANDLE, hModule: HMODULE, lpBaseName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetModuleBaseNameA".}
+proc GetModuleBaseNameW*(hProcess: HANDLE, hModule: HMODULE, lpBaseName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetModuleBaseNameW".}
+when defined(winUnicode):
+  proc GetModuleBaseName*(hProcess: HANDLE, hModule: HMODULE, lpBaseName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetModuleBaseNameW".}
+else:
+  proc GetModuleBaseName*(hProcess: HANDLE, hModule: HMODULE, lpBaseName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetModuleBaseNameA".}
+
+proc GetModuleFileNameExA*(hProcess: HANDLE, hModule: HMODULE, lpFileNameEx: LPSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetModuleFileNameExA".}
+proc GetModuleFileNameExW*(hProcess: HANDLE, hModule: HMODULE, lpFileNameEx: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetModuleFileNameExW".}
+when defined(winUnicode):
+  proc GetModuleFileNameEx*(hProcess: HANDLE, hModule: HMODULE, lpFileNameEx: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetModuleFileNameExW".}
+else:
+  proc GetModuleFileNameEx*(hProcess: HANDLE, hModule: HMODULE, lpFileNameEx: LPSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetModuleFileNameExA".}
+
+type
+  MODULEINFO* {.final.} = object
+    lpBaseOfDll*: LPVOID
+    SizeOfImage*: DWORD
+    EntryPoint*: LPVOID
+  LPMODULEINFO* = ptr MODULEINFO
+
+proc GetModuleInformation*(hProcess: HANDLE, hModule: HMODULE, lpmodinfo: LPMODULEINFO, cb: DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "GetModuleInformation".}
+proc EmptyWorkingSet*(hProcess: HANDLE): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "EmptyWorkingSet".}
+proc QueryWorkingSet*(hProcess: HANDLE, pv: PVOID, cb: DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "QueryWorkingSet".}
+proc QueryWorkingSetEx*(hProcess: HANDLE, pv: PVOID, cb: DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "QueryWorkingSetEx".}
+proc InitializeProcessForWsWatch*(hProcess: HANDLE): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "InitializeProcessForWsWatch".}
+
+type
+  PSAPI_WS_WATCH_INFORMATION* {.final.} = object
+    FaultingPc*: LPVOID
+    FaultingVa*: LPVOID
+  PPSAPI_WS_WATCH_INFORMATION* = ptr PSAPI_WS_WATCH_INFORMATION
+
+proc GetWsChanges*(hProcess: HANDLE, lpWatchInfo: PPSAPI_WS_WATCH_INFORMATION, cb: DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "GetWsChanges".}
+
+proc GetMappedFileNameA*(hProcess: HANDLE, lpv: LPVOID, lpFilename: LPSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetMappedFileNameA".}
+proc GetMappedFileNameW*(hProcess: HANDLE, lpv: LPVOID, lpFilename: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetMappedFileNameW".}
+when defined(winUnicode):
+  proc GetMappedFileName*(hProcess: HANDLE, lpv: LPVOID, lpFilename: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetMappedFileNameW".}
+else:
+  proc GetMappedFileName*(hProcess: HANDLE, lpv: LPVOID, lpFilename: LPSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetMappedFileNameA".}
+
+proc EnumDeviceDrivers*(lpImageBase: LPVOID, cb: DWORD, lpcbNeeded: LPDWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "EnumDeviceDrivers".}
+
+proc GetDeviceDriverBaseNameA*(ImageBase: LPVOID, lpBaseName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetDeviceDriverBaseNameA".}
+proc GetDeviceDriverBaseNameW*(ImageBase: LPVOID, lpBaseName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetDeviceDriverBaseNameW".}
+when defined(winUnicode):
+  proc GetDeviceDriverBaseName*(ImageBase: LPVOID, lpBaseName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetDeviceDriverBaseNameW".}
+else:
+  proc GetDeviceDriverBaseName*(ImageBase: LPVOID, lpBaseName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetDeviceDriverBaseNameA".}
+
+proc GetDeviceDriverFileNameA*(ImageBase: LPVOID, lpFileName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetDeviceDriverFileNameA".}
+proc GetDeviceDriverFileNameW*(ImageBase: LPVOID, lpFileName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetDeviceDriverFileNameW".}
+when defined(winUnicode):
+  proc GetDeviceDriverFileName*(ImageBase: LPVOID, lpFileName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetDeviceDriverFileNameW".}
+else:
+  proc GetDeviceDriverFileName*(ImageBase: LPVOID, lpFileName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetDeviceDriverFileNameA".}
+
+type
+  PROCESS_MEMORY_COUNTERS* {.final.} = object
+    cb*: DWORD
+    PageFaultCount*: DWORD
+    PeakWorkingSetSize: SIZE_T
+    WorkingSetSize: SIZE_T
+    QuotaPeakPagedPoolUsage: SIZE_T
+    QuotaPagedPoolUsage: SIZE_T
+    QuotaPeakNonPagedPoolUsage: SIZE_T
+    QuotaNonPagedPoolUsage: SIZE_T
+    PagefileUsage: SIZE_T
+    PeakPagefileUsage: SIZE_T
+  PPROCESS_MEMORY_COUNTERS* = ptr PROCESS_MEMORY_COUNTERS
+
+type
+  PROCESS_MEMORY_COUNTERS_EX* {.final.} = object
+    cb*: DWORD
+    PageFaultCount*: DWORD
+    PeakWorkingSetSize: SIZE_T
+    WorkingSetSize: SIZE_T
+    QuotaPeakPagedPoolUsage: SIZE_T
+    QuotaPagedPoolUsage: SIZE_T
+    QuotaPeakNonPagedPoolUsage: SIZE_T
+    QuotaNonPagedPoolUsage: SIZE_T
+    PagefileUsage: SIZE_T
+    PeakPagefileUsage: SIZE_T
+    PrivateUsage: SIZE_T
+  PPROCESS_MEMORY_COUNTERS_EX* = ptr PROCESS_MEMORY_COUNTERS_EX
+
+proc GetProcessMemoryInfo*(hProcess: HANDLE, ppsmemCounters: PPROCESS_MEMORY_COUNTERS, cb: DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "GetProcessMemoryInfo".}
+
+type
+  PERFORMANCE_INFORMATION* {.final.} = object
+    cb*: DWORD
+    CommitTotal: SIZE_T
+    CommitLimit: SIZE_T
+    CommitPeak: SIZE_T
+    PhysicalTotal: SIZE_T
+    PhysicalAvailable: SIZE_T
+    SystemCache: SIZE_T
+    KernelTotal: SIZE_T
+    KernelPaged: SIZE_T
+    KernelNonpaged: SIZE_T
+    PageSize: SIZE_T
+    HandleCount*: DWORD
+    ProcessCount*: DWORD
+    ThreadCount*: DWORD
+  PPERFORMANCE_INFORMATION* = ptr PERFORMANCE_INFORMATION
+  # Skip definition of PERFORMACE_INFORMATION...
+
+proc GetPerformanceInfo*(pPerformanceInformation: PPERFORMANCE_INFORMATION, cb: DWORD): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "GetPerformanceInfo".}
+
+type
+  ENUM_PAGE_FILE_INFORMATION* {.final.} = object
+    cb*: DWORD
+    Reserved*: DWORD
+    TotalSize: SIZE_T
+    TotalInUse: SIZE_T
+    PeakUsage: SIZE_T
+  PENUM_PAGE_FILE_INFORMATION* = ptr ENUM_PAGE_FILE_INFORMATION
+
+# Callback procedure
+type
+  PENUM_PAGE_FILE_CALLBACKW* = proc (pContext: LPVOID, pPageFileInfo: PENUM_PAGE_FILE_INFORMATION, lpFilename: LPCWSTR): WINBOOL{.stdcall.}
+  PENUM_PAGE_FILE_CALLBACKA* = proc (pContext: LPVOID, pPageFileInfo: PENUM_PAGE_FILE_INFORMATION, lpFilename: LPCSTR): WINBOOL{.stdcall.}
+
+#TODO
+proc EnumPageFilesA*(pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKA, pContext: LPVOID): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "EnumPageFilesA".}
+proc EnumPageFilesW*(pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKW, pContext: LPVOID): WINBOOL {.stdcall,
+    dynlib: psapiDll, importc: "EnumPageFilesW".}
+when defined(winUnicode):
+  proc EnumPageFiles*(pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKW, pContext: LPVOID): WINBOOL {.stdcall,
+      dynlib: psapiDll, importc: "EnumPageFilesW".}
+  type PENUM_PAGE_FILE_CALLBACK* = proc (pContext: LPVOID, pPageFileInfo: PENUM_PAGE_FILE_INFORMATION, lpFilename: LPCWSTR): WINBOOL{.stdcall.}
+else:
+  proc EnumPageFiles*(pCallBackRoutine: PENUM_PAGE_FILE_CALLBACKA, pContext: LPVOID): WINBOOL {.stdcall,
+      dynlib: psapiDll, importc: "EnumPageFilesA".}
+  type PENUM_PAGE_FILE_CALLBACK* = proc (pContext: LPVOID, pPageFileInfo: PENUM_PAGE_FILE_INFORMATION, lpFilename: LPCSTR): WINBOOL{.stdcall.}
+
+proc GetProcessImageFileNameA*(hProcess: HANDLE, lpImageFileName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetProcessImageFileNameA".}
+proc GetProcessImageFileNameW*(hProcess: HANDLE, lpImageFileName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+    dynlib: psapiDll, importc: "GetProcessImageFileNameW".}
+when defined(winUnicode):
+  proc GetProcessImageFileName*(hProcess: HANDLE, lpImageFileName: LPWSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetProcessImageFileNameW".}
+else:
+  proc GetProcessImageFileName*(hProcess: HANDLE, lpImageFileName: LPSTR, nSize: DWORD): DWORD {.stdcall,
+      dynlib: psapiDll, importc: "GetProcessImageFileNameA".}
diff --git a/lib/windows/shellapi.nim b/lib/windows/shellapi.nim
new file mode 100644
index 000000000..079257680
--- /dev/null
+++ b/lib/windows/shellapi.nim
@@ -0,0 +1,863 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim: on.}
+
+# leave out unused functions so the unit can be used on win2000 as well
+
+#+-------------------------------------------------------------------------
+#
+#  Microsoft Windows
+#  Copyright (c) Microsoft Corporation. All rights reserved.
+#
+#  File: shellapi.h
+#
+#  Header translation by Marco van de Voort for Free Pascal Platform
+#  SDK dl'ed January 2002
+#
+#--------------------------------------------------------------------------
+
+#
+#    shellapi.h -  SHELL.DLL functions, types, and definitions
+#    Copyright (c) Microsoft Corporation. All rights reserved.
+
+import
+  windows
+
+type
+  HDROP* = THandle
+  UINT_PTR* = ptr uint32
+  DWORD_PTR* = ptr DWORD
+  PHICON* = ptr HICON
+  PBool* = ptr bool
+  STARTUPINFOW* {.final.} = object # a guess. Omission should get fixed in Windows.
+    cb*: DWORD
+    lpReserved*: LPTSTR
+    lpDesktop*: LPTSTR
+    lpTitle*: LPTSTR
+    dwX*: DWORD
+    dwY*: DWORD
+    dwXSize*: DWORD
+    dwYSize*: DWORD
+    dwXCountChars*: DWORD
+    dwYCountChars*: DWORD
+    dwFillAttribute*: DWORD
+    dwFlags*: DWORD
+    wShowWindow*: int16
+    cbReserved2*: int16
+    lpReserved2*: LPBYTE
+    hStdInput*: HANDLE
+    hStdOutput*: HANDLE
+    hStdError*: HANDLE
+
+  LPSTARTUPINFOW* = ptr STARTUPINFOW
+  TSTARTUPINFOW* = STARTUPINFOW
+  PSTARTUPINFOW* = ptr STARTUPINFOW #unicode
+
+proc DragQueryFileA*(arg1: HDROP, arg2: uint32, arg3: LPSTR, arg4: uint32): uint32{.
+    stdcall, dynlib: "shell32.dll", importc: "DragQueryFileA".}
+proc DragQueryFileW*(arg1: HDROP, arg2: uint32, arg3: LPWSTR, arg4: uint32): uint32{.
+    stdcall, dynlib: "shell32.dll", importc: "DragQueryFileW".}
+proc DragQueryFile*(arg1: HDROP, arg2: uint32, arg3: LPSTR, arg4: uint32): uint32{.
+    stdcall, dynlib: "shell32.dll", importc: "DragQueryFileA".}
+proc DragQueryFile*(arg1: HDROP, arg2: uint32, arg3: LPWSTR, arg4: uint32): uint32{.
+    stdcall, dynlib: "shell32.dll", importc: "DragQueryFileW".}
+proc DragQueryPoint*(arg1: HDROP, arg2: LPPOINT): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "DragQueryPoint".}
+proc DragFinish*(arg1: HDROP){.stdcall, dynlib: "shell32.dll",
+                               importc: "DragFinish".}
+proc DragAcceptFiles*(hwnd: HWND, arg2: bool){.stdcall, dynlib: "shell32.dll",
+    importc: "DragAcceptFiles".}
+proc ShellExecuteA*(hwnd: HWND, lpOperation: LPCSTR, lpFile: LPCSTR,
+                    lpParameters: LPCSTR, lpDirectory: LPCSTR, nShowCmd: int32): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
+proc ShellExecuteW*(hwnd: HWND, lpOperation: LPCWSTR, lpFile: LPCWSTR,
+                    lpParameters: LPCWSTR, lpDirectory: LPCWSTR, nShowCmd: int32): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".}
+proc ShellExecute*(hwnd: HWND, lpOperation: LPCSTR, lpFile: LPCSTR,
+                   lpParameters: LPCSTR, lpDirectory: LPCSTR, nShowCmd: int32): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
+proc ShellExecute*(hwnd: HWND, lpOperation: LPCWSTR, lpFile: LPCWSTR,
+                   lpParameters: LPCWSTR, lpDirectory: LPCWSTR, nShowCmd: int32): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".}
+proc FindExecutableA*(lpFile: LPCSTR, lpDirectory: LPCSTR, lpResult: LPSTR): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "FindExecutableA".}
+proc FindExecutableW*(lpFile: LPCWSTR, lpDirectory: LPCWSTR, lpResult: LPWSTR): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "FindExecutableW".}
+proc FindExecutable*(lpFile: LPCSTR, lpDirectory: LPCSTR, lpResult: LPSTR): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "FindExecutableA".}
+proc FindExecutable*(lpFile: LPCWSTR, lpDirectory: LPCWSTR, lpResult: LPWSTR): HInst{.
+    stdcall, dynlib: "shell32.dll", importc: "FindExecutableW".}
+proc CommandLineToArgvW*(lpCmdLine: LPCWSTR, pNumArgs: ptr int32): PLPWSTR{.
+    stdcall, dynlib: "shell32.dll", importc: "CommandLineToArgvW".}
+proc ShellAboutA*(hwnd: HWND, szApp: LPCSTR, szOtherStuff: LPCSTR, hIcon: HICON): int32{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellAboutA".}
+proc ShellAboutW*(hwnd: HWND, szApp: LPCWSTR, szOtherStuff: LPCWSTR,
+                  hIcon: HICON): int32{.stdcall, dynlib: "shell32.dll",
+                                        importc: "ShellAboutW".}
+proc ShellAbout*(hwnd: HWND, szApp: LPCSTR, szOtherStuff: LPCSTR, hIcon: HICON): int32{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellAboutA".}
+proc ShellAbout*(hwnd: HWND, szApp: LPCWSTR, szOtherStuff: LPCWSTR, hIcon: HICON): int32{.
+    stdcall, dynlib: "shell32.dll", importc: "ShellAboutW".}
+proc DuplicateIcon*(inst: HINST, icon: HICON): HIcon{.stdcall,
+    dynlib: "shell32.dll", importc: "DuplicateIcon".}
+proc ExtractAssociatedIconA*(hInst: HINST, lpIconPath: LPSTR, lpiIcon: LPWORD): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractAssociatedIconA".}
+proc ExtractAssociatedIconW*(hInst: HINST, lpIconPath: LPWSTR, lpiIcon: LPWORD): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractAssociatedIconW".}
+proc ExtractAssociatedIcon*(hInst: HINST, lpIconPath: LPSTR, lpiIcon: LPWORD): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractAssociatedIconA".}
+proc ExtractAssociatedIcon*(hInst: HINST, lpIconPath: LPWSTR, lpiIcon: LPWORD): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractAssociatedIconW".}
+proc ExtractIconA*(hInst: HINST, lpszExeFileName: LPCSTR, nIconIndex: uint32): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractIconA".}
+proc ExtractIconW*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: uint32): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".}
+proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCSTR, nIconIndex: uint32): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractIconA".}
+proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: uint32): HICON{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".}
+  # if(WINVER >= 0x0400)
+type                          # init with sizeof(DRAGINFO)
+  DRAGINFOA* {.final.} = object
+    uSize*: uint32
+    pt*: POINT
+    fNC*: bool
+    lpFileList*: LPSTR
+    grfKeyState*: DWORD
+
+  TDRAGINFOA* = DRAGINFOA
+  LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO)
+  DRAGINFOW* {.final.} = object
+    uSize*: uint32
+    pt*: POINT
+    fNC*: bool
+    lpFileList*: LPWSTR
+    grfKeyState*: DWORD
+
+  TDRAGINFOW* = DRAGINFOW
+  LPDRAGINFOW* = ptr DRAGINFOW
+
+when defined(UNICODE):
+  type
+    DRAGINFO* = DRAGINFOW
+    TDRAGINFO* = DRAGINFOW
+    LPDRAGINFO* = LPDRAGINFOW
+else:
+  type
+    DRAGINFO* = DRAGINFOA
+    TDRAGINFO* = DRAGINFOW
+    LPDRAGINFO* = LPDRAGINFOA
+const
+  ABM_NEW* = 0x00000000
+  ABM_REMOVE* = 0x00000001
+  ABM_QUERYPOS* = 0x00000002
+  ABM_SETPOS* = 0x00000003
+  ABM_GETSTATE* = 0x00000004
+  ABM_GETTASKBARPOS* = 0x00000005
+  ABM_ACTIVATE* = 0x00000006  # lParam == TRUE/FALSE means activate/deactivate
+  ABM_GETAUTOHIDEBAR* = 0x00000007
+  ABM_SETAUTOHIDEBAR* = 0x00000008 # this can fail at any time.  MUST check the result
+                                   # lParam = TRUE/FALSE  Set/Unset
+                                   # uEdge = what edge
+  ABM_WINDOWPOSCHANGED* = 0x00000009
+  ABM_SETSTATE* = 0x0000000A
+  ABN_STATECHANGE* = 0x00000000 # these are put in the wparam of callback messages
+  ABN_POSCHANGED* = 0x00000001
+  ABN_FULLSCREENAPP* = 0x00000002
+  ABN_WINDOWARRANGE* = 0x00000003 # lParam == TRUE means hide
+                                  # flags for get state
+  ABS_AUTOHIDE* = 0x00000001
+  ABS_ALWAYSONTOP* = 0x00000002
+  ABE_LEFT* = 0
+  ABE_TOP* = 1
+  ABE_RIGHT* = 2
+  ABE_BOTTOM* = 3
+
+type
+  AppBarData* {.final.} = object
+    cbSize*: DWORD
+    hWnd*: HWND
+    uCallbackMessage*: uint32
+    uEdge*: uint32
+    rc*: RECT
+    lParam*: LPARAM           # message specific
+
+  TAPPBARDATA* = AppBarData
+  PAPPBARDATA* = ptr AppBarData
+
+proc SHAppBarMessage*(dwMessage: DWORD, pData: APPBARDATA): UINT_PTR{.stdcall,
+    dynlib: "shell32.dll", importc: "SHAppBarMessage".}
+  #
+  #  EndAppBar
+  #
+proc DoEnvironmentSubstA*(szString: LPSTR, cchString: uint32): DWORD{.stdcall,
+    dynlib: "shell32.dll", importc: "DoEnvironmentSubstA".}
+proc DoEnvironmentSubstW*(szString: LPWSTR, cchString: uint32): DWORD{.stdcall,
+    dynlib: "shell32.dll", importc: "DoEnvironmentSubstW".}
+proc DoEnvironmentSubst*(szString: LPSTR, cchString: uint32): DWORD{.stdcall,
+    dynlib: "shell32.dll", importc: "DoEnvironmentSubstA".}
+proc DoEnvironmentSubst*(szString: LPWSTR, cchString: uint32): DWORD{.stdcall,
+    dynlib: "shell32.dll", importc: "DoEnvironmentSubstW".}
+  #Macro
+proc EIRESID*(x: int32): int32
+proc ExtractIconExA*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: PHICON,
+                     phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall,
+    dynlib: "shell32.dll", importc: "ExtractIconExA".}
+proc ExtractIconExW*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: PHICON,
+                     phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall,
+    dynlib: "shell32.dll", importc: "ExtractIconExW".}
+proc ExtractIconExA*(lpszFile: LPCSTR, nIconIndex: int32,
+                     phiconLarge: var HICON, phiconSmall: var HIcon,
+                     nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll",
+    importc: "ExtractIconExA".}
+proc ExtractIconExW*(lpszFile: LPCWSTR, nIconIndex: int32,
+                     phiconLarge: var HICON, phiconSmall: var HIcon,
+                     nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll",
+    importc: "ExtractIconExW".}
+proc ExtractIconEx*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: PHICON,
+                    phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall,
+    dynlib: "shell32.dll", importc: "ExtractIconExA".}
+proc ExtractIconEx*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: PHICON,
+                    phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall,
+    dynlib: "shell32.dll", importc: "ExtractIconExW".}
+proc ExtractIconEx*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: var HICON,
+                    phiconSmall: var HIcon, nIcons: uint32): uint32{.stdcall,
+    dynlib: "shell32.dll", importc: "ExtractIconExA".}
+proc ExtractIconEx*(lpszFile: LPCWSTR, nIconIndex: int32,
+                    phiconLarge: var HICON, phiconSmall: var HIcon, nIcons: uint32): uint32{.
+    stdcall, dynlib: "shell32.dll", importc: "ExtractIconExW".}
+  #
+  # Shell File Operations
+  #
+  #ifndef FO_MOVE  //these need to be kept in sync with the ones in shlobj.h}
+const
+  FO_MOVE* = 0x00000001
+  FO_COPY* = 0x00000002
+  FO_DELETE* = 0x00000003
+  FO_RENAME* = 0x00000004
+  FOF_MULTIDESTFILES* = 0x00000001
+  FOF_CONFIRMMOUSE* = 0x00000002
+  FOF_SILENT* = 0x00000004    # don't create progress/report
+  FOF_RENAMEONCOLLISION* = 0x00000008
+  FOF_NOCONFIRMATION* = 0x00000010 # Don't prompt the user.
+  FOF_WANTMAPPINGHANDLE* = 0x00000020 # Fill in SHFILEOPSTRUCT.hNameMappings
+  FOF_ALLOWUNDO* = 0x00000040 # Must be freed using SHFreeNameMappings
+  FOF_FILESONLY* = 0x00000080 # on *.*, do only files
+  FOF_SIMPLEPROGRESS* = 0x00000100 # means don't show names of files
+  FOF_NOCONFIRMMKDIR* = 0x00000200 # don't confirm making any needed dirs
+  FOF_NOERRORUI* = 0x00000400 # don't put up error UI
+  FOF_NOCOPYSECURITYATTRIBS* = 0x00000800 # dont copy NT file Security Attributes
+  FOF_NORECURSION* = 0x00001000 # don't recurse into directories.
+                                #if (_WIN32_IE >= 0x0500)
+  FOF_NO_CONNECTED_ELEMENTS* = 0x00002000 # don't operate on connected elements.
+  FOF_WANTNUKEWARNING* = 0x00004000 # during delete operation, warn if nuking instead of recycling (partially overrides FOF_NOCONFIRMATION)
+                                    #endif
+                                    #if (_WIN32_WINNT >= 0x0501)
+  FOF_NORECURSEREPARSE* = 0x00008000 # treat reparse points as objects, not containers
+                                     #endif
+
+type
+  FILEOP_FLAGS* = int16
+
+const
+  PO_DELETE* = 0x00000013     # printer is being deleted
+  PO_RENAME* = 0x00000014     # printer is being renamed
+  PO_PORTCHANGE* = 0x00000020 # port this printer connected to is being changed
+                              # if this id is set, the strings received by
+                              # the copyhook are a doubly-null terminated
+                              # list of strings.  The first is the printer
+                              # name and the second is the printer port.
+  PO_REN_PORT* = 0x00000034   # PO_RENAME and PO_PORTCHANGE at same time.
+                              # no POF_ flags currently defined
+
+type
+  PRINTEROP_FLAGS* = int16 #endif}
+                           # FO_MOVE
+                           # implicit parameters are:
+                           #      if pFrom or pTo are unqualified names the current directories are
+                           #      taken from the global current drive/directory settings managed
+                           #      by Get/SetCurrentDrive/Directory
+                           #
+                           #      the global confirmation settings
+                           # only used if FOF_SIMPLEPROGRESS
+
+type
+  SHFILEOPSTRUCTA* {.final.} = object
+    hwnd*: HWND
+    wFunc*: uint32
+    pFrom*: LPCSTR
+    pTo*: LPCSTR
+    fFlags*: FILEOP_FLAGS
+    fAnyOperationsAborted*: bool
+    hNameMappings*: LPVOID
+    lpszProgressTitle*: LPCSTR # only used if FOF_SIMPLEPROGRESS
+
+  TSHFILEOPSTRUCTA* = SHFILEOPSTRUCTA
+  LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA
+  SHFILEOPSTRUCTW* {.final.} = object
+    hwnd*: HWND
+    wFunc*: uint32
+    pFrom*: LPCWSTR
+    pTo*: LPCWSTR
+    fFlags*: FILEOP_FLAGS
+    fAnyOperationsAborted*: bool
+    hNameMappings*: LPVOID
+    lpszProgressTitle*: LPCWSTR
+
+  TSHFILEOPSTRUCTW* = SHFILEOPSTRUCTW
+  LPSHFILEOPSTRUCTW* = ptr SHFILEOPSTRUCTW
+
+when defined(UNICODE):
+  type
+    SHFILEOPSTRUCT* = SHFILEOPSTRUCTW
+    TSHFILEOPSTRUCT* = SHFILEOPSTRUCTW
+    LPSHFILEOPSTRUCT* = LPSHFILEOPSTRUCTW
+else:
+  type
+    SHFILEOPSTRUCT* = SHFILEOPSTRUCTA
+    TSHFILEOPSTRUCT* = SHFILEOPSTRUCTA
+    LPSHFILEOPSTRUCT* = LPSHFILEOPSTRUCTA
+proc SHFileOperationA*(lpFileOp: LPSHFILEOPSTRUCTA): int32{.stdcall,
+    dynlib: "shell32.dll", importc: "SHFileOperationA".}
+proc SHFileOperationW*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
+    dynlib: "shell32.dll", importc: "SHFileOperationW".}
+proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTA): int32{.stdcall,
+    dynlib: "shell32.dll", importc: "SHFileOperationA".}
+proc SHFileOperation*(lpFileOp: LPSHFILEOPSTRUCTW): int32{.stdcall,
+    dynlib: "shell32.dll", importc: "SHFileOperationW".}
+proc SHFreeNameMappings*(hNameMappings: THandle){.stdcall,
+    dynlib: "shell32.dll", importc: "SHFreeNameMappings".}
+type
+  SHNAMEMAPPINGA* {.final.} = object
+    pszOldPath*: LPSTR
+    pszNewPath*: LPSTR
+    cchOldPath*: int32
+    cchNewPath*: int32
+
+  TSHNAMEMAPPINGA* = SHNAMEMAPPINGA
+  LPSHNAMEMAPPINGA* = ptr SHNAMEMAPPINGA
+  SHNAMEMAPPINGW* {.final.} = object
+    pszOldPath*: LPWSTR
+    pszNewPath*: LPWSTR
+    cchOldPath*: int32
+    cchNewPath*: int32
+
+  TSHNAMEMAPPINGW* = SHNAMEMAPPINGW
+  LPSHNAMEMAPPINGW* = ptr SHNAMEMAPPINGW
+
+when not(defined(UNICODE)):
+  type
+    SHNAMEMAPPING* = SHNAMEMAPPINGW
+    TSHNAMEMAPPING* = SHNAMEMAPPINGW
+    LPSHNAMEMAPPING* = LPSHNAMEMAPPINGW
+else:
+  type
+    SHNAMEMAPPING* = SHNAMEMAPPINGA
+    TSHNAMEMAPPING* = SHNAMEMAPPINGA
+    LPSHNAMEMAPPING* = LPSHNAMEMAPPINGA
+#
+# End Shell File Operations
+#
+#
+#  Begin ShellExecuteEx and family
+#
+# ShellExecute() and ShellExecuteEx() error codes
+# regular WinExec() codes
+
+const
+  SE_ERR_FNF* = 2             # file not found
+  SE_ERR_PNF* = 3             # path not found
+  SE_ERR_ACCESSDENIED* = 5    # access denied
+  SE_ERR_OOM* = 8             # out of memory
+  SE_ERR_DLLNOTFOUND* = 32    # endif   WINVER >= 0x0400
+                              # error values for ShellExecute() beyond the regular WinExec() codes
+  SE_ERR_SHARE* = 26
+  SE_ERR_ASSOCINCOMPLETE* = 27
+  SE_ERR_DDETIMEOUT* = 28
+  SE_ERR_DDEFAIL* = 29
+  SE_ERR_DDEBUSY* = 30
+  SE_ERR_NOASSOC* = 31        #if(WINVER >= 0x0400)}
+                              # Note CLASSKEY overrides CLASSNAME
+  SEE_MASK_CLASSNAME* = 0x00000001
+  SEE_MASK_CLASSKEY* = 0x00000003 # Note INVOKEIDLIST overrides IDLIST
+  SEE_MASK_IDLIST* = 0x00000004
+  SEE_MASK_INVOKEIDLIST* = 0x0000000C
+  SEE_MASK_ICON* = 0x00000010
+  SEE_MASK_HOTKEY* = 0x00000020
+  SEE_MASK_NOCLOSEPROCESS* = 0x00000040
+  SEE_MASK_CONNECTNETDRV* = 0x00000080
+  SEE_MASK_FLAG_DDEWAIT* = 0x00000100
+  SEE_MASK_DOENVSUBST* = 0x00000200
+  SEE_MASK_FLAG_NO_UI* = 0x00000400
+  SEE_MASK_UNICODE* = 0x00004000
+  SEE_MASK_NO_CONSOLE* = 0x00008000
+  SEE_MASK_ASYNCOK* = 0x00100000
+  SEE_MASK_HMONITOR* = 0x00200000 #if (_WIN32_IE >= 0x0500)
+  SEE_MASK_NOQUERYCLASSSTORE* = 0x01000000
+  SEE_MASK_WAITFORINPUTIDLE* = 0x02000000 #endif  (_WIN32_IE >= 0x500)
+                                          #if (_WIN32_IE >= 0x0560)
+  SEE_MASK_FLAG_LOG_USAGE* = 0x04000000 #endif
+                                        # (_WIN32_IE >= 0x560)
+
+type
+  SHELLEXECUTEINFOA* {.final.} = object
+    cbSize*: DWORD
+    fMask*: ULONG
+    hwnd*: HWND
+    lpVerb*: LPCSTR
+    lpFile*: LPCSTR
+    lpParameters*: LPCSTR
+    lpDirectory*: LPCSTR
+    nShow*: int32
+    hInstApp*: HINST
+    lpIDList*: LPVOID
+    lpClass*: LPCSTR
+    hkeyClass*: HKEY
+    dwHotKey*: DWORD
+    hMonitor*: HANDLE         # also: hIcon
+    hProcess*: HANDLE
+
+  TSHELLEXECUTEINFOA* = SHELLEXECUTEINFOA
+  LPSHELLEXECUTEINFOA* = ptr SHELLEXECUTEINFOA
+  SHELLEXECUTEINFOW* {.final.} = object
+    cbSize*: DWORD
+    fMask*: ULONG
+    hwnd*: HWND
+    lpVerb*: LPCWSTR
+    lpFile*: LPCWSTR
+    lpParameters*: LPCWSTR
+    lpDirectory*: LPCWSTR
+    nShow*: int32
+    hInstApp*: HINST
+    lpIDList*: LPVOID
+    lpClass*: LPCWSTR
+    hkeyClass*: HKEY
+    dwHotKey*: DWORD
+    hMonitor*: HANDLE         # also: hIcon
+    hProcess*: HANDLE
+
+  TSHELLEXECUTEINFOW* = SHELLEXECUTEINFOW
+  LPSHELLEXECUTEINFOW* = ptr SHELLEXECUTEINFOW
+
+when defined(UNICODE):
+  type
+    SHELLEXECUTEINFO* = SHELLEXECUTEINFOW
+    TSHELLEXECUTEINFO* = SHELLEXECUTEINFOW
+    LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOW
+else:
+  type
+    SHELLEXECUTEINFO* = SHELLEXECUTEINFOA
+    TSHELLEXECUTEINFO* = SHELLEXECUTEINFOA
+    LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOA
+proc ShellExecuteExA*(lpExecInfo: LPSHELLEXECUTEINFOA): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "ShellExecuteExA".}
+proc ShellExecuteExW*(lpExecInfo: LPSHELLEXECUTEINFOW): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "ShellExecuteExW".}
+proc ShellExecuteEx*(lpExecInfo: LPSHELLEXECUTEINFOA): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "ShellExecuteExA".}
+proc ShellExecuteEx*(lpExecInfo: LPSHELLEXECUTEINFOW): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "ShellExecuteExW".}
+proc WinExecErrorA*(hwnd: HWND, error: int32, lpstrFileName: LPCSTR,
+                    lpstrTitle: LPCSTR){.stdcall, dynlib: "shell32.dll",
+    importc: "WinExecErrorA".}
+proc WinExecErrorW*(hwnd: HWND, error: int32, lpstrFileName: LPCWSTR,
+                    lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll",
+    importc: "WinExecErrorW".}
+proc WinExecError*(hwnd: HWND, error: int32, lpstrFileName: LPCSTR,
+                   lpstrTitle: LPCSTR){.stdcall, dynlib: "shell32.dll",
+                                        importc: "WinExecErrorA".}
+proc WinExecError*(hwnd: HWND, error: int32, lpstrFileName: LPCWSTR,
+                   lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll",
+    importc: "WinExecErrorW".}
+type
+  SHCREATEPROCESSINFOW* {.final.} = object
+    cbSize*: DWORD
+    fMask*: ULONG
+    hwnd*: HWND
+    pszFile*: LPCWSTR
+    pszParameters*: LPCWSTR
+    pszCurrentDirectory*: LPCWSTR
+    hUserToken*: HANDLE
+    lpProcessAttributes*: LPSECURITY_ATTRIBUTES
+    lpThreadAttributes*: LPSECURITY_ATTRIBUTES
+    bInheritHandles*: bool
+    dwCreationFlags*: DWORD
+    lpStartupInfo*: LPSTARTUPINFOW
+    lpProcessInformation*: LPPROCESS_INFORMATION
+
+  TSHCREATEPROCESSINFOW* = SHCREATEPROCESSINFOW
+  PSHCREATEPROCESSINFOW* = ptr SHCREATEPROCESSINFOW
+
+proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHCreateProcessAsUserW".}
+  #
+  #  End ShellExecuteEx and family }
+  #
+  #
+  # RecycleBin
+  #
+  # struct for query recycle bin info
+type
+  SHQUERYRBINFO* {.final.} = object
+    cbSize*: DWORD
+    i64Size*: int64
+    i64NumItems*: int64
+
+  TSHQUERYRBINFO* = SHQUERYRBINFO
+  LPSHQUERYRBINFO* = ptr SHQUERYRBINFO # flags for SHEmptyRecycleBin
+
+const
+  SHERB_NOCONFIRMATION* = 0x00000001
+  SHERB_NOPROGRESSUI* = 0x00000002
+  SHERB_NOSOUND* = 0x00000004
+
+proc SHQueryRecycleBinA*(pszRootPath: LPCSTR, pSHQueryRBInfo: LPSHQUERYRBINFO): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHQueryRecycleBinA".}
+proc SHQueryRecycleBinW*(pszRootPath: LPCWSTR, pSHQueryRBInfo: LPSHQUERYRBINFO): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHQueryRecycleBinW".}
+proc SHQueryRecycleBin*(pszRootPath: LPCSTR, pSHQueryRBInfo: LPSHQUERYRBINFO): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHQueryRecycleBinA".}
+proc SHQueryRecycleBin*(pszRootPath: LPCWSTR, pSHQueryRBInfo: LPSHQUERYRBINFO): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHQueryRecycleBinW".}
+proc SHEmptyRecycleBinA*(hwnd: HWND, pszRootPath: LPCSTR, dwFlags: DWORD): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHEmptyRecycleBinA".}
+proc SHEmptyRecycleBinW*(hwnd: HWND, pszRootPath: LPCWSTR, dwFlags: DWORD): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHEmptyRecycleBinW".}
+proc SHEmptyRecycleBin*(hwnd: HWND, pszRootPath: LPCSTR, dwFlags: DWORD): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHEmptyRecycleBinA".}
+proc SHEmptyRecycleBin*(hwnd: HWND, pszRootPath: LPCWSTR, dwFlags: DWORD): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHEmptyRecycleBinW".}
+  #
+  # end of RecycleBin
+  #
+  #
+  # Tray notification definitions
+  #
+type
+  NOTIFYICONDATAA* {.final.} = object
+    cbSize*: DWORD
+    hWnd*: HWND
+    uID*: uint32
+    uFlags*: uint32
+    uCallbackMessage*: uint32
+    hIcon*: HICON
+    szTip*: array[0..127, char]
+    dwState*: DWORD
+    dwStateMask*: DWORD
+    szInfo*: array[0..255, char]
+    uTimeout*: uint32           # also: uVersion
+    szInfoTitle*: array[0..63, char]
+    dwInfoFlags*: DWORD
+    guidItem*: TGUID
+
+  TNOTIFYICONDATAA* = NOTIFYICONDATAA
+  PNOTIFYICONDATAA* = ptr NOTIFYICONDATAA
+  NOTIFYICONDATAW* {.final.} = object
+    cbSize*: DWORD
+    hWnd*: HWND
+    uID*: uint32
+    uFlags*: uint32
+    uCallbackMessage*: uint32
+    hIcon*: HICON
+    szTip*: array[0..127, Wchar]
+    dwState*: DWORD
+    dwStateMask*: DWORD
+    szInfo*: array[0..255, Wchar]
+    uTimeout*: uint32           # also uVersion : UINT
+    szInfoTitle*: array[0..63, char]
+    dwInfoFlags*: DWORD
+    guidItem*: TGUID
+
+  TNOTIFYICONDATAW* = NOTIFYICONDATAW
+  PNOTIFYICONDATAW* = ptr NOTIFYICONDATAW
+
+when defined(UNICODE):
+  type
+    NOTIFYICONDATA* = NOTIFYICONDATAW
+    TNOTIFYICONDATA* = NOTIFYICONDATAW
+    PNOTIFYICONDATA* = PNOTIFYICONDATAW
+else:
+  type
+    NOTIFYICONDATA* = NOTIFYICONDATAA
+    TNOTIFYICONDATA* = NOTIFYICONDATAA
+    PNOTIFYICONDATA* = PNOTIFYICONDATAA
+const
+  NIN_SELECT* = WM_USER + 0
+  NINF_KEY* = 0x00000001
+  NIN_KEYSELECT* = NIN_SELECT or NINF_KEY
+  NIN_BALLOONSHOW* = WM_USER + 2
+  NIN_BALLOONHIDE* = WM_USER + 3
+  NIN_BALLOONTIMEOUT* = WM_USER + 4
+  NIN_BALLOONUSERCLICK* = WM_USER + 5
+  NIM_ADD* = 0x00000000
+  NIM_MODIFY* = 0x00000001
+  NIM_DELETE* = 0x00000002
+  NIM_SETFOCUS* = 0x00000003
+  NIM_SETVERSION* = 0x00000004
+  NOTIFYICON_VERSION* = 3
+  NIF_MESSAGE* = 0x00000001
+  NIF_ICON* = 0x00000002
+  NIF_TIP* = 0x00000004
+  NIF_STATE* = 0x00000008
+  NIF_INFO* = 0x00000010
+  NIF_GUID* = 0x00000020
+  NIS_HIDDEN* = 0x00000001
+  NIS_SHAREDICON* = 0x00000002 # says this is the source of a shared icon
+                               # Notify Icon Infotip flags
+  NIIF_NONE* = 0x00000000     # icon flags are mutually exclusive
+                              # and take only the lowest 2 bits
+  NIIF_INFO* = 0x00000001
+  NIIF_WARNING* = 0x00000002
+  NIIF_ERROR* = 0x00000003
+  NIIF_ICON_MASK* = 0x0000000F
+  NIIF_NOSOUND* = 0x00000010
+
+proc Shell_NotifyIconA*(dwMessage: Dword, lpData: PNOTIFYICONDATAA): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconA".}
+proc Shell_NotifyIconW*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconW".}
+proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAA): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconA".}
+proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconW".}
+  #
+  #       The SHGetFileInfo API provides an easy way to get attributes
+  #       for a file given a pathname.
+  #
+  #         PARAMETERS
+  #
+  #           pszPath              file name to get info about
+  #           dwFileAttributes     file attribs, only used with SHGFI_USEFILEATTRIBUTES
+  #           psfi                 place to return file info
+  #           cbFileInfo           size of structure
+  #           uFlags               flags
+  #
+  #         RETURN
+  #           TRUE if things worked
+  #
+  # out: icon
+  # out: icon index
+  # out: SFGAO_ flags
+  # out: display name (or path)
+  # out: type name
+type
+  SHFILEINFOA* {.final.} = object
+    hIcon*: HICON             # out: icon
+    iIcon*: int32             # out: icon index
+    dwAttributes*: DWORD      # out: SFGAO_ flags
+    szDisplayName*: array[0..(MAX_PATH) - 1, char] # out: display name (or path)
+    szTypeName*: array[0..79, char] # out: type name
+
+  TSHFILEINFOA* = SHFILEINFOA
+  PSHFILEINFOA* = ptr SHFILEINFOA
+  SHFILEINFOW* {.final.} = object
+    hIcon*: HICON             # out: icon
+    iIcon*: int32             # out: icon index
+    dwAttributes*: DWORD      # out: SFGAO_ flags
+    szDisplayName*: array[0..(MAX_PATH) - 1, Wchar] # out: display name (or path)
+    szTypeName*: array[0..79, Wchar] # out: type name
+
+  TSHFILEINFOW* = SHFILEINFOW
+  PSHFILEINFOW* = ptr SHFILEINFOW
+
+when defined(UNICODE):
+  type
+    SHFILEINFO* = SHFILEINFOW
+    TSHFILEINFO* = SHFILEINFOW
+    pFILEINFO* = SHFILEINFOW
+else:
+  type
+    SHFILEINFO* = SHFILEINFOA
+    TSHFILEINFO* = SHFILEINFOA
+    pFILEINFO* = SHFILEINFOA
+# NOTE: This is also in shlwapi.h.  Please keep in synch.
+
+const
+  SHGFI_ICON* = 0x00000100    # get Icon
+  SHGFI_DISPLAYNAME* = 0x00000200 # get display name
+  SHGFI_TYPENAME* = 0x00000400 # get type name
+  SHGFI_ATTRIBUTES* = 0x00000800 # get attributes
+  SHGFI_ICONLOCATION* = 0x00001000 # get icon location
+  SHGFI_EXETYPE* = 0x00002000 # return exe type
+  SHGFI_SYSICONINDEX* = 0x00004000 # get system icon index
+  SHGFI_LINKOVERLAY* = 0x00008000 # put a link overlay on icon
+  SHGFI_SELECTED* = 0x00010000 # show icon in selected state
+  SHGFI_ATTR_SPECIFIED* = 0x00020000 # get only specified attributes
+  SHGFI_LARGEICON* = 0x00000000 # get large icon
+  SHGFI_SMALLICON* = 0x00000001 # get small icon
+  SHGFI_OPENICON* = 0x00000002 # get open icon
+  SHGFI_SHELLICONSIZE* = 0x00000004 # get shell size icon
+  SHGFI_PIDL* = 0x00000008    # pszPath is a pidl
+  SHGFI_USEFILEATTRIBUTES* = 0x00000010 # use passed dwFileAttribute
+  SHGFI_ADDOVERLAYS* = 0x00000020 # apply the appropriate overlays
+  SHGFI_OVERLAYINDEX* = 0x00000040 # Get the index of the overlay
+                                   # in the upper 8 bits of the iIcon
+
+proc SHGetFileInfoA*(pszPath: LPCSTR, dwFileAttributes: DWORD,
+                     psfi: PSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
+proc SHGetFileInfoW*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
+                     psfi: PSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
+proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD,
+                    psfi: PSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
+proc SHGetFileInfoA*(pszPath: LPCSTR, dwFileAttributes: DWORD,
+                     psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
+proc SHGetFileInfoW*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
+                     psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
+proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD,
+                    psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".}
+proc SHGetFileInfo*(pszPath: LPCWSTR, dwFileAttributes: DWORD,
+                    psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".}
+proc SHGetDiskFreeSpaceExA*(pszDirectoryName: LPCSTR,
+                            pulFreeBytesAvailableToCaller: PULARGE_INTEGER,
+                            pulTotalNumberOfBytes: PULARGE_INTEGER,
+                            pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExA".}
+proc SHGetDiskFreeSpaceExW*(pszDirectoryName: LPCWSTR,
+                            pulFreeBytesAvailableToCaller: PULARGE_INTEGER,
+                            pulTotalNumberOfBytes: PULARGE_INTEGER,
+                            pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExW".}
+proc SHGetDiskFreeSpaceEx*(pszDirectoryName: LPCSTR,
+                           pulFreeBytesAvailableToCaller: PULARGE_INTEGER,
+                           pulTotalNumberOfBytes: PULARGE_INTEGER,
+                           pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExA".}
+proc SHGetDiskFreeSpace*(pszDirectoryName: LPCSTR,
+                         pulFreeBytesAvailableToCaller: PULARGE_INTEGER,
+                         pulTotalNumberOfBytes: PULARGE_INTEGER,
+                         pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExA".}
+proc SHGetDiskFreeSpaceEx*(pszDirectoryName: LPCWSTR,
+                           pulFreeBytesAvailableToCaller: PULARGE_INTEGER,
+                           pulTotalNumberOfBytes: PULARGE_INTEGER,
+                           pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExW".}
+proc SHGetDiskFreeSpace*(pszDirectoryName: LPCWSTR,
+                         pulFreeBytesAvailableToCaller: PULARGE_INTEGER,
+                         pulTotalNumberOfBytes: PULARGE_INTEGER,
+                         pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExW".}
+proc SHGetNewLinkInfoA*(pszLinkTo: LPCSTR, pszDir: LPCSTR, pszName: LPSTR,
+                        pfMustCopy: PBool, uFlags: uint32): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetNewLinkInfoA".}
+proc SHGetNewLinkInfoW*(pszLinkTo: LPCWSTR, pszDir: LPCWSTR, pszName: LPWSTR,
+                        pfMustCopy: PBool, uFlags: uint32): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetNewLinkInfoW".}
+proc SHGetNewLinkInfo*(pszLinkTo: LPCSTR, pszDir: LPCSTR, pszName: LPSTR,
+                       pfMustCopy: PBool, uFlags: uint32): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetNewLinkInfoA".}
+proc SHGetNewLinkInfo*(pszLinkTo: LPCWSTR, pszDir: LPCWSTR, pszName: LPWSTR,
+                       pfMustCopy: PBool, uFlags: uint32): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetNewLinkInfoW".}
+const
+  SHGNLI_PIDL* = 0x00000001   # pszLinkTo is a pidl
+  SHGNLI_PREFIXNAME* = 0x00000002 # Make name "Shortcut to xxx"
+  SHGNLI_NOUNIQUE* = 0x00000004 # don't do the unique name generation
+  SHGNLI_NOLNK* = 0x00000008  # don't add ".lnk" extension
+  PRINTACTION_OPEN* = 0
+  PRINTACTION_PROPERTIES* = 1
+  PRINTACTION_NETINSTALL* = 2
+  PRINTACTION_NETINSTALLLINK* = 3
+  PRINTACTION_TESTPAGE* = 4
+  PRINTACTION_OPENNETPRN* = 5
+  PRINTACTION_DOCUMENTDEFAULTS* = 6
+  PRINTACTION_SERVERPROPERTIES* = 7
+
+proc SHInvokePrinterCommandA*(hwnd: HWND, uAction: uint32, lpBuf1: LPCSTR,
+                              lpBuf2: LPCSTR, fModal: bool): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHInvokePrinterCommandA".}
+proc SHInvokePrinterCommandW*(hwnd: HWND, uAction: uint32, lpBuf1: LPCWSTR,
+                              lpBuf2: LPCWSTR, fModal: bool): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHInvokePrinterCommandW".}
+proc SHInvokePrinterCommand*(hwnd: HWND, uAction: uint32, lpBuf1: LPCSTR,
+                             lpBuf2: LPCSTR, fModal: bool): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHInvokePrinterCommandA".}
+proc SHInvokePrinterCommand*(hwnd: HWND, uAction: uint32, lpBuf1: LPCWSTR,
+                             lpBuf2: LPCWSTR, fModal: bool): bool{.stdcall,
+    dynlib: "shell32.dll", importc: "SHInvokePrinterCommandW".}
+proc SHLoadNonloadedIconOverlayIdentifiers*(): HResult{.stdcall,
+    dynlib: "shell32.dll", importc: "SHInvokePrinterCommandW".}
+proc SHIsFileAvailableOffline*(pwszPath: LPCWSTR, pdwStatus: LPDWORD): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHIsFileAvailableOffline".}
+const
+  OFFLINE_STATUS_LOCAL* = 0x00000001 # If open, it's open locally
+  OFFLINE_STATUS_REMOTE* = 0x00000002 # If open, it's open remotely
+  OFFLINE_STATUS_INCOMPLETE* = 0x00000004 # The local copy is currently incomplete.
+                                          # The file will not be available offline
+                                          # until it has been synchronized.
+                                          #  sets the specified path to use the string resource
+                                          #  as the UI instead of the file system name
+
+proc SHSetLocalizedName*(pszPath: LPWSTR, pszResModule: LPCWSTR, idsRes: int32): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHSetLocalizedName".}
+proc SHEnumerateUnreadMailAccountsA*(hKeyUser: HKEY, dwIndex: DWORD,
+                                     pszMailAddress: LPSTR,
+                                     cchMailAddress: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHEnumerateUnreadMailAccountsA".}
+proc SHEnumerateUnreadMailAccountsW*(hKeyUser: HKEY, dwIndex: DWORD,
+                                     pszMailAddress: LPWSTR,
+                                     cchMailAddress: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHEnumerateUnreadMailAccountsW".}
+proc SHEnumerateUnreadMailAccounts*(hKeyUser: HKEY, dwIndex: DWORD,
+                                    pszMailAddress: LPWSTR,
+                                    cchMailAddress: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHEnumerateUnreadMailAccountsW".}
+proc SHGetUnreadMailCountA*(hKeyUser: HKEY, pszMailAddress: LPCSTR,
+                            pdwCount: PDWORD, pFileTime: PFILETIME,
+                            pszShellExecuteCommand: LPSTR,
+                            cchShellExecuteCommand: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetUnreadMailCountA".}
+proc SHGetUnreadMailCountW*(hKeyUser: HKEY, pszMailAddress: LPCWSTR,
+                            pdwCount: PDWORD, pFileTime: PFILETIME,
+                            pszShellExecuteCommand: LPWSTR,
+                            cchShellExecuteCommand: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetUnreadMailCountW".}
+proc SHGetUnreadMailCount*(hKeyUser: HKEY, pszMailAddress: LPCSTR,
+                           pdwCount: PDWORD, pFileTime: PFILETIME,
+                           pszShellExecuteCommand: LPSTR,
+                           cchShellExecuteCommand: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetUnreadMailCountA".}
+proc SHGetUnreadMailCount*(hKeyUser: HKEY, pszMailAddress: LPCWSTR,
+                           pdwCount: PDWORD, pFileTime: PFILETIME,
+                           pszShellExecuteCommand: LPWSTR,
+                           cchShellExecuteCommand: int32): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHGetUnreadMailCountW".}
+proc SHSetUnreadMailCountA*(pszMailAddress: LPCSTR, dwCount: DWORD,
+                            pszShellExecuteCommand: LPCSTR): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHSetUnreadMailCountA".}
+proc SHSetUnreadMailCountW*(pszMailAddress: LPCWSTR, dwCount: DWORD,
+                            pszShellExecuteCommand: LPCWSTR): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHSetUnreadMailCountW".}
+proc SHSetUnreadMailCount*(pszMailAddress: LPCSTR, dwCount: DWORD,
+                           pszShellExecuteCommand: LPCSTR): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHSetUnreadMailCountA".}
+proc SHSetUnreadMailCount*(pszMailAddress: LPCWSTR, dwCount: DWORD,
+                           pszShellExecuteCommand: LPCWSTR): HRESULT{.stdcall,
+    dynlib: "shell32.dll", importc: "SHSetUnreadMailCountW".}
+proc SHGetImageList*(iImageList: int32, riid: TIID, ppvObj: ptr pointer): HRESULT{.
+    stdcall, dynlib: "shell32.dll", importc: "SHGetImageList".}
+const
+  SHIL_LARGE* = 0             # normally 32x32
+  SHIL_SMALL* = 1             # normally 16x16
+  SHIL_EXTRALARGE* = 2
+  SHIL_SYSSMALL* = 3          # like SHIL_SMALL, but tracks system small icon metric correctly
+  SHIL_LAST* = SHIL_SYSSMALL
+
+# implementation
+
+proc EIRESID(x: int32): int32 =
+  result = -x
diff --git a/lib/windows/shfolder.nim b/lib/windows/shfolder.nim
new file mode 100644
index 000000000..886d757eb
--- /dev/null
+++ b/lib/windows/shfolder.nim
@@ -0,0 +1,93 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2006 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# ---------------------------------------------------------------------
+#  shfolder.dll is distributed standard with IE5.5, so it should ship
+#  with 2000/XP or higher but is likely to be installed on NT/95/98 or
+#  ME as well.  It works on all these systems.
+#
+#  The info found here is also in the registry:
+#  HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\
+#  HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\
+#
+#  Note that not all CSIDL_* constants are supported by shlfolder.dll,
+#  they should be supported by the shell32.dll, though again not on all
+#  systems.
+#  ---------------------------------------------------------------------
+
+{.deadCodeElim: on.}
+
+import 
+  windows
+
+const 
+  LibName* = "SHFolder.dll"
+
+const 
+  CSIDL_PROGRAMS* = 0x00000002 # %SYSTEMDRIVE%\Program Files                                      
+  CSIDL_PERSONAL* = 0x00000005 # %USERPROFILE%\My Documents                                       
+  CSIDL_FAVORITES* = 0x00000006 # %USERPROFILE%\Favorites                                          
+  CSIDL_STARTUP* = 0x00000007 # %USERPROFILE%\Start menu\Programs\Startup                        
+  CSIDL_RECENT* = 0x00000008  # %USERPROFILE%\Recent                                             
+  CSIDL_SENDTO* = 0x00000009  # %USERPROFILE%\Sendto                                             
+  CSIDL_STARTMENU* = 0x0000000B # %USERPROFILE%\Start menu                                         
+  CSIDL_MYMUSIC* = 0x0000000D # %USERPROFILE%\Documents\My Music                                 
+  CSIDL_MYVIDEO* = 0x0000000E # %USERPROFILE%\Documents\My Videos                                
+  CSIDL_DESKTOPDIRECTORY* = 0x00000010 # %USERPROFILE%\Desktop                                            
+  CSIDL_NETHOOD* = 0x00000013 # %USERPROFILE%\NetHood                                            
+  CSIDL_TEMPLATES* = 0x00000015 # %USERPROFILE%\Templates                                          
+  CSIDL_COMMON_STARTMENU* = 0x00000016 # %PROFILEPATH%\All users\Start menu                               
+  CSIDL_COMMON_PROGRAMS* = 0x00000017 # %PROFILEPATH%\All users\Start menu\Programs                      
+  CSIDL_COMMON_STARTUP* = 0x00000018 # %PROFILEPATH%\All users\Start menu\Programs\Startup              
+  CSIDL_COMMON_DESKTOPDIRECTORY* = 0x00000019 # %PROFILEPATH%\All users\Desktop                                  
+  CSIDL_APPDATA* = 0x0000001A # %USERPROFILE%\Application Data (roaming)                         
+  CSIDL_PRINTHOOD* = 0x0000001B # %USERPROFILE%\Printhood                                          
+  CSIDL_LOCAL_APPDATA* = 0x0000001C # %USERPROFILE%\Local Settings\Application Data (non roaming)      
+  CSIDL_COMMON_FAVORITES* = 0x0000001F # %PROFILEPATH%\All users\Favorites                                
+  CSIDL_INTERNET_CACHE* = 0x00000020 # %USERPROFILE%\Local Settings\Temporary Internet Files            
+  CSIDL_COOKIES* = 0x00000021 # %USERPROFILE%\Cookies                                            
+  CSIDL_HISTORY* = 0x00000022 # %USERPROFILE%\Local settings\History                             
+  CSIDL_COMMON_APPDATA* = 0x00000023 # %PROFILESPATH%\All Users\Application Data                        
+  CSIDL_WINDOWS* = 0x00000024 # %SYSTEMROOT%                                                     
+  CSIDL_SYSTEM* = 0x00000025  # %SYSTEMROOT%\SYSTEM32 (may be system on 95/98/ME)                
+  CSIDL_PROGRAM_FILES* = 0x00000026 # %SYSTEMDRIVE%\Program Files                                      
+  CSIDL_MYPICTURES* = 0x00000027 # %USERPROFILE%\My Documents\My Pictures                           
+  CSIDL_PROFILE* = 0x00000028 # %USERPROFILE%                                                    
+  CSIDL_PROGRAM_FILES_COMMON* = 0x0000002B # %SYSTEMDRIVE%\Program Files\Common                               
+  CSIDL_COMMON_TEMPLATES* = 0x0000002D # %PROFILEPATH%\All Users\Templates                                
+  CSIDL_COMMON_DOCUMENTS* = 0x0000002E # %PROFILEPATH%\All Users\Documents                                
+  CSIDL_COMMON_ADMINTOOLS* = 0x0000002F # %PROFILEPATH%\All Users\Start Menu\Programs\Administrative Tools 
+  CSIDL_ADMINTOOLS* = 0x00000030 # %USERPROFILE%\Start Menu\Programs\Administrative Tools           
+  CSIDL_COMMON_MUSIC* = 0x00000035 # %PROFILEPATH%\All Users\Documents\my music                       
+  CSIDL_COMMON_PICTURES* = 0x00000036 # %PROFILEPATH%\All Users\Documents\my pictures                    
+  CSIDL_COMMON_VIDEO* = 0x00000037 # %PROFILEPATH%\All Users\Documents\my videos                      
+  CSIDL_CDBURN_AREA* = 0x0000003B # %USERPROFILE%\Local Settings\Application Data\Microsoft\CD Burning 
+  CSIDL_PROFILES* = 0x0000003E # %PROFILEPATH%                                                    
+  CSIDL_FLAG_CREATE* = 0x00008000 # (force creation of requested folder if it doesn't exist yet)     
+                                  # Original entry points 
+
+proc SHGetFolderPathA*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord, 
+                       Path: cstring): HRESULT{.stdcall, dynlib: LibName, 
+    importc: "SHGetFolderPathA".}
+proc SHGetFolderPathW*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord, 
+                       Path: cstring): HRESULT{.stdcall, dynlib: LibName, 
+    importc: "SHGetFolderPathW".}
+proc SHGetFolderPath*(Ahwnd: HWND, Csidl: int, Token: THandle, Flags: DWord, 
+                      Path: cstring): HRESULT{.stdcall, dynlib: LibName, 
+    importc: "SHGetFolderPathA".}
+type 
+  PFNSHGetFolderPathA* = proc (Ahwnd: HWND, Csidl: int, Token: THandle, 
+                               Flags: DWord, Path: cstring): HRESULT{.stdcall.}
+  PFNSHGetFolderPathW* = proc (Ahwnd: HWND, Csidl: int, Token: THandle, 
+                               Flags: DWord, Path: cstring): HRESULT{.stdcall.}
+  PFNSHGetFolderPath* = PFNSHGetFolderPathA
+  TSHGetFolderPathA* = PFNSHGetFolderPathA
+  TSHGetFolderPathW* = PFNSHGetFolderPathW
+  TSHGetFolderPath* = TSHGetFolderPathA
+
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
new file mode 100644
index 000000000..02c87132a
--- /dev/null
+++ b/lib/windows/windows.nim
@@ -0,0 +1,23973 @@
+#

+#

+#            Nim's Runtime Library

+#        (c) Copyright 2010 Andreas Rumpf

+#

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

+#    distribution, for details about the copyright.

+#

+

+## Define ``winUnicode`` before importing this module for the

+## Unicode version.

+

+{.deadCodeElim: on.}

+{.push gcsafe.}

+type

+  WideChar* = uint16

+  PWideChar* = ptr uint16

+

+type  # WinNT.h -- Defines the 32-Bit Windows types and constants

+  SHORT* = int16

+  LONG* = int32

+  # UNICODE (Wide Character) types

+  PWCHAR* = PWideChar

+  LPWCH* = PWideChar

+  PWCH* = PWideChar

+  LPCWCH* = PWideChar

+  PCWCH* = PWideChar

+  NWPSTR* = PWideChar

+  LPWSTR* = PWideChar

+  LPCWSTR* = PWideChar

+  PCWSTR* = PWideChar

+  # ANSI (Multi-byte Character) types

+  LPCH* = cstring

+  PCH* = cstring

+  LPCCH* = cstring

+  PCCH* = cstring

+  LPSTR* = cstring

+  PSTR* = cstring

+  LPCSTR* = cstring

+  PCSTR* = cstring

+

+type  # BaseTsd.h -- Type definitions for the basic sized types

+      # Give here only the bare minimum, to be expanded as needs arise

+  LONG32* = int32

+  ULONG32* = int32

+  DWORD32* = int32

+  LONG64* = int64

+  ULONG64* = int64

+  DWORD64* = int64

+  PDWORD64* = ptr DWORD64

+  # int32 on Win32, int64 on Win64

+  INT_PTR* = ByteAddress

+  UINT_PTR* = ByteAddress

+  LONG_PTR* = ByteAddress

+  ULONG_PTR* = ByteAddress

+  SIZE_T* = ByteAddress

+  SSIZE_T* = ByteAddress

+  DWORD_PTR* = ByteAddress

+  # Thread affinity

+  KAFFINITY* = ByteAddress

+  PKAFFINITY* = ptr KAFFINITY

+

+type  # WinDef.h -- Basic Windows Type Definitions

+  # BaseTypes

+  WINUINT* = int32

+  ULONG* = int

+  PULONG* = ptr int

+  USHORT* = int16

+  PUSHORT* = ptr int16

+  UCHAR* = int8

+  PUCHAR* = ptr int8

+  PSZ* = cstring

+

+  DWORD* = int32

+  WINBOOL* = int32

+  WORD* = int16

+  #FLOAT* = float

+  PFLOAT* = ptr float32

+  PWINBOOL* = ptr WINBOOL

+  LPWINBOOL* = ptr WINBOOL

+  PBYTE* = ptr int8

+  LPBYTE* = ptr int8

+  PINT* = ptr int32

+  LPINT* = ptr int32

+  PWORD* = ptr int16

+  LPWORD* = ptr int16

+  LPLONG* = ptr int32

+  PDWORD* = ptr DWORD

+  LPDWORD* = ptr DWORD

+  LPVOID* = pointer

+  LPCVOID* = pointer

+

+  # INT* = int  # Cannot work and not necessary anyway

+  PUINT* = ptr int

+

+  WPARAM* = LONG_PTR

+  LPARAM* = LONG_PTR

+  LRESULT* = LONG_PTR

+

+  ATOM* = int16

+  TAtom* = ATOM

+  HANDLE* = int

+  THandle* = HANDLE

+  PHANDLE* = ptr HANDLE

+  LPHANDLE* = ptr HANDLE

+  HWND* = HANDLE

+  HHOOK* = HANDLE

+  HEVENT* = HANDLE

+  HGLOBAL* = HANDLE

+  HLOCAL* = HANDLE

+  HGDIOBJ* = HANDLE

+  HKEY* = HANDLE

+  PHKEY* = ptr HKEY

+  HACCEL* = HANDLE

+  HBITMAP* = HANDLE

+  HBRUSH* = HANDLE

+  HCOLORSPACE* = HANDLE

+  HDC* = HANDLE

+  HGLRC* = HANDLE

+  HDESK* = HANDLE

+  HENHMETAFILE* = HANDLE

+  HFONT* = HANDLE

+  HICON* = HANDLE

+  HMETAFILE* = HANDLE

+  HINST* = HANDLE  # Not HINSTANCE, else it has problems with the var HInstance

+  HMODULE* = HANDLE

+  HPALETTE* = HANDLE

+  HPEN* = HANDLE

+  HRGN* = HANDLE

+  HRSRC* = HANDLE

+  HTASK* = HANDLE

+  HWINSTA* = HANDLE

+  HKL* = HANDLE

+  HMONITOR* = HANDLE

+  HWINEVENTHOOK* = HANDLE

+  HUMPD* = HANDLE

+

+  HFILE* = HANDLE

+  HCURSOR* = HANDLE # = HICON

+  COLORREF* = DWORD

+  LPCOLORREF* = ptr COLORREF

+

+  POINT* {.final, pure.} = object

+    x*: LONG

+    y*: LONG

+  PPOINT* = ptr POINT

+  LPPOINT* = ptr POINT

+  POINTL* {.final, pure.} = object

+    x*: LONG

+    y*: LONG

+  PPOINTL* = ptr POINTL

+

+  TPOINT* = POINT

+  TPOINTL* = POINTL

+

+  RECT* {.final, pure.} = object

+    TopLeft*, BottomRight*: TPoint

+  PRECT* = ptr RECT

+  LPRECT* = ptr RECT

+

+  RECTL* {.final, pure.} = object

+    left*: LONG

+    top*: LONG

+    right*: LONG

+    bottom*: LONG

+  PRECTL* = ptr RECTL

+

+  SIZE* {.final, pure.} = object

+    cx*: LONG

+    cy*: LONG

+  PSIZE* = ptr SIZE

+  LPSIZE* = ptr SIZE

+  SIZEL* = SIZE

+  PSIZEL* = ptr SIZE

+  LPSIZEL* = ptr SIZE

+

+  POINTS* {.final, pure.} = object

+    x*: SHORT

+    y*: SHORT

+  PPOINTS* = ptr POINTS

+

+  TRECT* = RECT

+  TRECTL* = RECTL

+  TSIZE* = SIZE

+  TSIZEL* = SIZE

+  TPOINTS* = POINTS

+

+  FILETIME* {.final, pure.} = object

+    dwLowDateTime*: DWORD

+    dwHighDateTime*: DWORD

+  PFILETIME* = ptr FILETIME

+  LPFILETIME* = ptr FILETIME

+

+  TFILETIME* = FILETIME

+

+const

+  MAX_PATH* = 260

+  HFILE_ERROR* = HFILE(-1)

+

+  # mode selections for the device mode function

+  # DocumentProperties

+  DM_UPDATE* = 1

+  DM_COPY* = 2

+  DM_PROMPT* = 4

+  DM_MODIFY* = 8

+

+  DM_IN_BUFFER* = DM_MODIFY

+  DM_IN_PROMPT* = DM_PROMPT

+  DM_OUT_BUFFER* = DM_COPY

+  DM_OUT_DEFAULT* = DM_UPDATE

+

+  # device capabilities indices

+  DC_FIELDS* = 1

+  DC_PAPERS* = 2

+  DC_PAPERSIZE* = 3

+  DC_MINEXTENT* = 4

+  DC_MAXEXTENT* = 5

+  DC_BINS* = 6

+  DC_DUPLEX* = 7

+  DC_SIZE* = 8

+  DC_EXTRA* = 9

+  DC_VERSION* = 10

+  DC_DRIVER* = 11

+  DC_BINNAMES* = 12

+  DC_ENUMRESOLUTIONS* = 13

+  DC_FILEDEPENDENCIES* = 14

+  DC_TRUETYPE* = 15

+  DC_PAPERNAMES* = 16

+  DC_ORIENTATION* = 17

+  DC_COPIES* = 18

+

+  DC_BINADJUST* = 19

+  DC_EMF_COMPLIANT* = 20

+  DC_DATATYPE_PRODUCED* = 21

+

+type

+  WORDBOOL* = int16  # XXX: not a bool

+  CALTYPE* = int

+  CALID* = int

+  CCHAR* = char

+  TCOLORREF* = COLORREF

+  WINT* = int32

+  PINTEGER* = ptr int32

+  PBOOL* = ptr WINBOOL

+  LONGLONG* = int64

+  PLONGLONG* = ptr LONGLONG

+  LPLONGLONG* = ptr LONGLONG

+  ULONGLONG* = int64          # used in AMD64 CONTEXT

+  PULONGLONG* = ptr ULONGLONG #

+  DWORDLONG* = int64          # was unsigned long

+  PDWORDLONG* = ptr DWORDLONG

+  HRESULT* = int

+  PHRESULT* = ptr HRESULT

+  HCONV* = HANDLE

+  HCONVLIST* = HANDLE

+  HDBC* = HANDLE

+  HDDEDATA* = HANDLE

+  HDROP* = HANDLE

+  HDWP* = HANDLE

+  HENV* = HANDLE

+  HIMAGELIST* = HANDLE

+  HMENU* = HANDLE

+  HRASCONN* = HANDLE

+  HSTMT* = HANDLE

+  HSTR* = HANDLE

+  HSZ* = HANDLE

+  LANGID* = int16

+  LCID* = DWORD

+  LCTYPE* = DWORD

+  LP* = ptr int16

+  LPBOOL* = ptr WINBOOL

+

+when defined(winUnicode):

+  type

+    LPCTSTR* = PWideChar

+else:

+  type

+    LPCTSTR* = cstring

+type

+  LPPCSTR* = ptr LPCSTR

+  LPPCTSTR* = ptr LPCTSTR

+  LPPCWSTR* = ptr LPCWSTR

+

+when defined(winUnicode):

+  type

+    LPTCH* = PWideChar

+    LPTSTR* = PWideChar

+else:

+  type

+    LPTCH* = cstring

+    LPTSTR* = cstring

+type

+  PBOOLEAN* = ptr int8

+  PLONG* = ptr int32

+  PSHORT* = ptr SHORT

+

+when defined(winUnicode):

+  type

+    PTBYTE* = ptr uint16

+    PTCH* = PWideChar

+    PTCHAR* = PWideChar

+    PTSTR* = PWideChar

+else:

+  type

+    PTBYTE* = ptr byte

+    PTCH* = cstring

+    PTCHAR* = cstring

+    PTSTR* = cstring

+type

+  PVOID* = pointer

+  RETCODE* = SHORT

+  SC_HANDLE* = HANDLE

+  SC_LOCK* = LPVOID

+  LPSC_HANDLE* = ptr SC_HANDLE

+  SERVICE_STATUS_HANDLE* = DWORD

+

+when defined(winUnicode):

+  type

+    TBYTE* = uint16

+    TCHAR* = widechar

+    BCHAR* = int16

+else:

+  type

+    TBYTE* = uint8

+    TCHAR* = char

+    BCHAR* = int8

+type

+  WCHAR* = WideChar

+  PLPSTR* = ptr LPSTR

+  PLPWStr* = ptr LPWStr

+  ACL_INFORMATION_CLASS* = enum

+    AclRevisionInformation = 1, AclSizeInformation

+  MEDIA_TYPE* = enum

+    Unknown, F5_1Pt2_512, F3_1Pt44_512, F3_2Pt88_512, F3_20Pt8_512, F3_720_512,

+    F5_360_512, F5_320_512, F5_320_1024, F5_180_512, F5_160_512, RemovableMedia,

+    FixedMedia

+

+const

+  RASCS_DONE* = 0x00002000

+  RASCS_PAUSED* = 0x00001000

+

+type

+  RASCONNSTATE* = enum

+    RASCS_OpenPort = 0, RASCS_PortOpened, RASCS_ConnectDevice,

+    RASCS_DeviceConnected, RASCS_AllDevicesConnected, RASCS_Authenticate,

+    RASCS_AuthNotify, RASCS_AuthRetry, RASCS_AuthCallback,

+    RASCS_AuthChangePassword, RASCS_AuthProject, RASCS_AuthLinkSpeed,

+    RASCS_AuthAck, RASCS_ReAuthenticate, RASCS_Authenticated,

+    RASCS_PrepareForCallback, RASCS_WaitForModemReset, RASCS_WaitForCallback,

+    RASCS_Projected, RASCS_StartAuthentication, RASCS_CallbackComplete,

+    RASCS_LogonNetwork, RASCS_Interactive = RASCS_PAUSED,

+    RASCS_RetryAuthentication, RASCS_CallbackSetByCaller, RASCS_PasswordExpired,

+    RASCS_Connected = RASCS_DONE, RASCS_Disconnected

+  RASPROJECTION* = enum

+    RASP_PppIp = 0x00008021, RASP_PppIpx = 0x0000802B, RASP_PppNbf = 0x0000803F,

+    RASP_Amb = 0x00010000

+  SECURITY_IMPERSONATION_LEVEL* = enum

+

+

+    SecurityAnonymous, SecurityIdentification, SecurityImpersonation,

+    SecurityDelegation

+  SID_NAME_USE* = enum

+    SidTypeUser = 1, SidTypeGroup, SidTypeDomain, SidTypeAlias,

+    SidTypeWellKnownGroup, SidTypeDeletedAccount, SidTypeInvalid, SidTypeUnknown

+  PSID_NAME_USE* = ptr SID_NAME_USE

+  TOKEN_INFORMATION_CLASS* = enum

+    TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup,

+    TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel,

+    TokenStatistics

+  TTOKEN_TYPE* = enum

+    TokenPrimary = 1, TokenImpersonation

+  MakeIntResourceA* = cstring

+  MakeIntResourceW* = PWideChar

+  MakeIntResource* = MakeIntResourceA

+

+#

+#    Definitions for callback procedures

+#

+type

+  BFFCALLBACK* = proc (para1: HWND, para2: WINUINT, para3: LPARAM, para4: LPARAM): int32{.

+      stdcall.}

+  LPCCHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): WINUINT{.

+      stdcall.}

+  LPCFHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): WINUINT{.

+      stdcall.}

+  PTHREAD_START_ROUTINE* = pointer

+  LPTHREAD_START_ROUTINE* = PTHREAD_START_ROUTINE

+  EDITSTREAMCALLBACK* = proc (para1: DWORD, para2: LPBYTE, para3: LONG,

+                              para4: LONG): DWORD{.stdcall.}

+  LPFRHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): WINUINT{.

+      stdcall.}

+  LPOFNHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): WINUINT{.

+      stdcall.}

+  LPPRINTHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM,

+                           para4: LPARAM): WINUINT{.stdcall.}

+  LPSETUPHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM,

+                           para4: LPARAM): WINUINT{.stdcall.}

+  DLGPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): LRESULT{.

+      stdcall.}

+  PFNPROPSHEETCALLBACK* = proc (para1: HWND, para2: WINUINT, para3: LPARAM): int32{.

+      stdcall.}

+  LPSERVICE_MAIN_FUNCTION* = proc (para1: DWORD, para2: LPTSTR){.stdcall.}

+  PFNTVCOMPARE* = proc (para1: LPARAM, para2: LPARAM, para3: LPARAM): int32{.

+      stdcall.}

+  WNDPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): LRESULT{.

+      stdcall.}

+  FARPROC* = pointer

+  TFarProc* = FARPROC

+  TProc* = pointer

+  ENUMRESTYPEPROC* = proc (para1: HANDLE, para2: LPTSTR, para3: LONG): WINBOOL{.

+      stdcall.}

+  ENUMRESNAMEPROC* = proc (para1: HANDLE, para2: LPCTSTR, para3: LPTSTR,

+                           para4: LONG): WINBOOL{.stdcall.}

+  ENUMRESLANGPROC* = proc (para1: HANDLE, para2: LPCTSTR, para3: LPCTSTR,

+                           para4: int16, para5: LONG): WINBOOL{.stdcall.}

+  DESKTOPENUMPROC* = FARPROC

+  ENUMWINDOWSPROC* = proc (para1: HWND, para2: LPARAM): WINBOOL{.stdcall.}

+  ENUMWINDOWSTATIONPROC* = proc (para1: LPTSTR, para2: LPARAM): WINBOOL{.stdcall.}

+  SENDASYNCPROC* = proc (para1: HWND, para2: WINUINT, para3: DWORD, para4: LRESULT){.

+      stdcall.}

+  TIMERPROC* = proc (para1: HWND, para2: WINUINT, para3: WINUINT, para4: DWORD){.

+      stdcall.}

+  GRAYSTRINGPROC* = FARPROC

+  DRAWSTATEPROC* = proc (para1: HDC, para2: LPARAM, para3: WPARAM, para4: int32,

+                         para5: int32): WINBOOL{.stdcall.}

+  PROPENUMPROCEX* = proc (para1: HWND, para2: LPCTSTR, para3: HANDLE,

+                          para4: DWORD): WINBOOL{.stdcall.}

+  PROPENUMPROC* = proc (para1: HWND, para2: LPCTSTR, para3: HANDLE): WINBOOL{.

+      stdcall.}

+  HOOKPROC* = proc (para1: int32, para2: WPARAM, para3: LPARAM): LRESULT{.

+      stdcall.}

+  ENUMOBJECTSPROC* = proc (para1: LPVOID, para2: LPARAM){.stdcall.}

+  LINEDDAPROC* = proc (para1: int32, para2: int32, para3: LPARAM){.stdcall.}

+  TABORTPROC* = proc (para1: HDC, para2: int32): WINBOOL{.stdcall.}

+  LPPAGEPAINTHOOK* = proc (para1: HWND, para2: WINUINT, para3: WPARAM,

+                           para4: LPARAM): WINUINT{.stdcall.}

+  LPPAGESETUPHOOK* = proc (para1: HWND, para2: WINUINT, para3: WPARAM,

+                           para4: LPARAM): WINUINT{.stdcall.}

+  ICMENUMPROC* = proc (para1: LPTSTR, para2: LPARAM): int32{.stdcall.}

+  EDITWORDBREAKPROCEX* = proc (para1: cstring, para2: LONG, para3: int8,

+                               para4: WINT): LONG{.stdcall.}

+  PFNLVCOMPARE* = proc (para1: LPARAM, para2: LPARAM, para3: LPARAM): int32{.

+      stdcall.}

+  LOCALE_ENUMPROC* = proc (para1: LPTSTR): WINBOOL{.stdcall.}

+  CODEPAGE_ENUMPROC* = proc (para1: LPTSTR): WINBOOL{.stdcall.}

+  DATEFMT_ENUMPROC* = proc (para1: LPTSTR): WINBOOL{.stdcall.}

+  TIMEFMT_ENUMPROC* = proc (para1: LPTSTR): WINBOOL{.stdcall.}

+  CALINFO_ENUMPROC* = proc (para1: LPTSTR): WINBOOL{.stdcall.}

+  PHANDLER_ROUTINE* = proc (para1: DWORD): WINBOOL{.stdcall.}

+  LPHANDLER_FUNCTION* = proc (para1: DWORD): WINBOOL{.stdcall.}

+  PFNGETPROFILEPATH* = proc (para1: LPCTSTR, para2: LPSTR, para3: WINUINT): WINUINT{.

+      stdcall.}

+  PFNRECONCILEPROFILE* = proc (para1: LPCTSTR, para2: LPCTSTR, para3: DWORD): WINUINT{.

+      stdcall.}

+  PFNPROCESSPOLICIES* = proc (para1: HWND, para2: LPCTSTR, para3: LPCTSTR,

+                              para4: LPCTSTR, para5: DWORD): WINBOOL{.stdcall.}

+

+const

+  SE_CREATE_TOKEN_NAME* = "SeCreateTokenPrivilege"

+  SE_ASSIGNPRIMARYTOKEN_NAME* = "SeAssignPrimaryTokenPrivilege"

+  SE_LOCK_MEMORY_NAME* = "SeLockMemoryPrivilege"

+  SE_INCREASE_QUOTA_NAME* = "SeIncreaseQuotaPrivilege"

+  SE_UNSOLICITED_INPUT_NAME* = "SeUnsolicitedInputPrivilege"

+  SE_MACHINE_ACCOUNT_NAME* = "SeMachineAccountPrivilege"

+  SE_TCB_NAME* = "SeTcbPrivilege"

+  SE_SECURITY_NAME* = "SeSecurityPrivilege"

+  SE_TAKE_OWNERSHIP_NAME* = "SeTakeOwnershipPrivilege"

+  SE_LOAD_DRIVER_NAME* = "SeLoadDriverPrivilege"

+  SE_SYSTEM_PROFILE_NAME* = "SeSystemProfilePrivilege"

+  SE_SYSTEMTIME_NAME* = "SeSystemtimePrivilege"

+  SE_PROF_SINGLE_PROCESS_NAME* = "SeProfileSingleProcessPrivilege"

+  SE_INC_BASE_PRIORITY_NAME* = "SeIncreaseBasePriorityPrivilege"

+  SE_CREATE_PAGEFILE_NAME* = "SeCreatePagefilePrivilege"

+  SE_CREATE_PERMANENT_NAME* = "SeCreatePermanentPrivilege"

+  SE_BACKUP_NAME* = "SeBackupPrivilege"

+  SE_RESTORE_NAME* = "SeRestorePrivilege"

+  SE_SHUTDOWN_NAME* = "SeShutdownPrivilege"

+  SE_DEBUG_NAME* = "SeDebugPrivilege"

+  SE_AUDIT_NAME* = "SeAuditPrivilege"

+  SE_SYSTEM_ENVIRONMENT_NAME* = "SeSystemEnvironmentPrivilege"

+  SE_CHANGE_NOTIFY_NAME* = "SeChangeNotifyPrivilege"

+  SE_REMOTE_SHUTDOWN_NAME* = "SeRemoteShutdownPrivilege"

+  SERVICES_ACTIVE_DATABASEW* = "ServicesActive"

+  SERVICES_FAILED_DATABASEW* = "ServicesFailed"

+  SERVICES_ACTIVE_DATABASEA* = "ServicesActive"

+  SERVICES_FAILED_DATABASEA* = "ServicesFailed"

+  SC_GROUP_IDENTIFIERW* = "+"

+  SC_GROUP_IDENTIFIERA* = "+"

+

+when defined(winUnicode):

+  const

+    SERVICES_ACTIVE_DATABASE* = SERVICES_ACTIVE_DATABASEW

+    SERVICES_FAILED_DATABASE* = SERVICES_FAILED_DATABASEW

+    SC_GROUP_IDENTIFIER* = SC_GROUP_IDENTIFIERW

+else:

+  const

+    SERVICES_ACTIVE_DATABASE* = SERVICES_ACTIVE_DATABASEA

+    SERVICES_FAILED_DATABASE* = SERVICES_FAILED_DATABASEA

+    SC_GROUP_IDENTIFIER* = SC_GROUP_IDENTIFIERA

+type

+  PFNCALLBACK* = proc (para1, para2: WINUINT, para3: HCONV, para4, para5: HSZ,

+                       para6: HDDEDATA, para7, para8: DWORD): HDDEData{.stdcall.}

+  CALLB* = PFNCALLBACK

+  SECURITY_CONTEXT_TRACKING_MODE* = WINBOOL

+  # End of stuff from ddeml.h in old Cygnus headers

+

+  WNDENUMPROC* = FARPROC

+  ENHMFENUMPROC* = FARPROC

+  CCSTYLE* = DWORD

+  PCCSTYLE* = ptr CCSTYLE

+  LPCCSTYLE* = ptr CCSTYLE

+  CCSTYLEFLAGA* = DWORD

+  PCCSTYLEFLAGA* = ptr CCSTYLEFLAGA

+  LPCCSTYLEFLAGA* = ptr CCSTYLEFLAGA

+

+const

+  LZERROR_UNKNOWNALG* = -8

+  LZERROR_BADVALUE* = -7

+  LZERROR_GLOBLOCK* = -6

+  LZERROR_GLOBALLOC* = -5

+  LZERROR_WRITE* = -4

+  LZERROR_READ* = -3

+  LZERROR_BADOUTHANDLE* = -2

+  LZERROR_BADINHANDLE* = -1

+  NO_ERROR* = 0

+  ERROR_SUCCESS* = 0

+  ERROR_INVALID_FUNCTION* = 1

+  ERROR_FILE_NOT_FOUND* = 2

+  ERROR_PATH_NOT_FOUND* = 3

+  ERROR_TOO_MANY_OPEN_FILES* = 4

+  ERROR_ACCESS_DENIED* = 5

+  ERROR_INVALID_HANDLE* = 6

+  ERROR_ARENA_TRASHED* = 7

+  ERROR_NOT_ENOUGH_MEMORY* = 8

+  ERROR_INVALID_BLOCK* = 9

+  ERROR_BAD_ENVIRONMENT* = 10

+  ERROR_BAD_FORMAT* = 11

+  ERROR_INVALID_ACCESS* = 12

+  ERROR_INVALID_DATA* = 13

+  ERROR_OUTOFMEMORY* = 14

+  ERROR_INVALID_DRIVE* = 15

+  ERROR_CURRENT_DIRECTORY* = 16

+  ERROR_NOT_SAME_DEVICE* = 17

+  ERROR_NO_MORE_FILES* = 18

+  ERROR_WRITE_PROTECT* = 19

+  ERROR_BAD_UNIT* = 20

+  ERROR_NOT_READY* = 21

+  ERROR_BAD_COMMAND* = 22

+  ERROR_CRC* = 23

+  ERROR_BAD_LENGTH* = 24

+  ERROR_SEEK* = 25

+  ERROR_NOT_DOS_DISK* = 26

+  ERROR_SECTOR_NOT_FOUND* = 27

+  ERROR_OUT_OF_PAPER* = 28

+  ERROR_WRITE_FAULT* = 29

+  ERROR_READ_FAULT* = 30

+  ERROR_GEN_FAILURE* = 31

+  ERROR_SHARING_VIOLATION* = 32

+  ERROR_LOCK_VIOLATION* = 33

+  ERROR_WRONG_DISK* = 34

+  ERROR_SHARING_BUFFER_EXCEEDED* = 36

+  ERROR_HANDLE_EOF* = 38

+  ERROR_HANDLE_DISK_FULL* = 39

+  ERROR_NOT_SUPPORTED* = 50

+  ERROR_REM_NOT_LIST* = 51

+  ERROR_DUP_NAME* = 52

+  ERROR_BAD_NETPATH* = 53

+  ERROR_NETWORK_BUSY* = 54

+  ERROR_DEV_NOT_EXIST* = 55

+  ERROR_TOO_MANY_CMDS* = 56

+  ERROR_ADAP_HDW_ERR* = 57

+  ERROR_BAD_NET_RESP* = 58

+  ERROR_UNEXP_NET_ERR* = 59

+  ERROR_BAD_REM_ADAP* = 60

+  ERROR_PRINTQ_FULL* = 61

+  ERROR_NO_SPOOL_SPACE* = 62

+  ERROR_PRINT_CANCELLED* = 63

+  ERROR_NETNAME_DELETED* = 64

+  ERROR_NETWORK_ACCESS_DENIED* = 65

+  ERROR_BAD_DEV_TYPE* = 66

+  ERROR_BAD_NET_NAME* = 67

+  ERROR_TOO_MANY_NAMES* = 68

+  ERROR_TOO_MANY_SESS* = 69

+  ERROR_SHARING_PAUSED* = 70

+  ERROR_REQ_NOT_ACCEP* = 71

+  ERROR_REDIR_PAUSED* = 72

+  ERROR_FILE_EXISTS* = 80

+  ERROR_CANNOT_MAKE* = 82

+  ERROR_FAIL_I24* = 83

+  ERROR_OUT_OF_STRUCTURES* = 84

+  ERROR_ALREADY_ASSIGNED* = 85

+  ERROR_INVALID_PASSWORD* = 86

+  ERROR_INVALID_PARAMETER* = 87

+  ERROR_NET_WRITE_FAULT* = 88

+  ERROR_NO_PROC_SLOTS* = 89

+  ERROR_TOO_MANY_SEMAPHORES* = 100

+  ERROR_EXCL_SEM_ALREADY_OWNED* = 101

+  ERROR_SEM_IS_SET* = 102

+  ERROR_TOO_MANY_SEM_REQUESTS* = 103

+  ERROR_INVALID_AT_INTERRUPT_TIME* = 104

+  ERROR_SEM_OWNER_DIED* = 105

+  ERROR_SEM_USER_LIMIT* = 106

+  ERROR_DISK_CHANGE* = 107

+  ERROR_DRIVE_LOCKED* = 108

+  ERROR_BROKEN_PIPE* = 109

+  ERROR_OPEN_FAILED* = 110

+  ERROR_BUFFER_OVERFLOW* = 111

+  ERROR_DISK_FULL* = 112

+  ERROR_NO_MORE_SEARCH_HANDLES* = 113

+  ERROR_INVALID_TARGET_HANDLE* = 114

+  ERROR_INVALID_CATEGORY* = 117

+  ERROR_INVALID_VERIFY_SWITCH* = 118

+  ERROR_BAD_DRIVER_LEVEL* = 119

+  ERROR_CALL_NOT_IMPLEMENTED* = 120

+  ERROR_SEM_TIMEOUT* = 121

+  ERROR_INSUFFICIENT_BUFFER* = 122

+  ERROR_INVALID_NAME* = 123

+  ERROR_INVALID_LEVEL* = 124

+  ERROR_NO_VOLUME_LABEL* = 125

+  ERROR_MOD_NOT_FOUND* = 126

+  ERROR_PROC_NOT_FOUND* = 127

+  ERROR_WAIT_NO_CHILDREN* = 128

+  ERROR_CHILD_NOT_COMPLETE* = 129

+  ERROR_DIRECT_ACCESS_HANDLE* = 130

+  ERROR_NEGATIVE_SEEK* = 131

+  ERROR_SEEK_ON_DEVICE* = 132

+  ERROR_IS_JOIN_TARGET* = 133

+  ERROR_IS_JOINED* = 134

+  ERROR_IS_SUBSTED* = 135

+  ERROR_NOT_JOINED* = 136

+  ERROR_NOT_SUBSTED* = 137

+  ERROR_JOIN_TO_JOIN* = 138

+  ERROR_SUBST_TO_SUBST* = 139

+  ERROR_JOIN_TO_SUBST* = 140

+  ERROR_SUBST_TO_JOIN* = 141

+  ERROR_BUSY_DRIVE* = 142

+  ERROR_SAME_DRIVE* = 143

+  ERROR_DIR_NOT_ROOT* = 144

+  ERROR_DIR_NOT_EMPTY* = 145

+  ERROR_IS_SUBST_PATH* = 146

+  ERROR_IS_JOIN_PATH* = 147

+  ERROR_PATH_BUSY* = 148

+  ERROR_IS_SUBST_TARGET* = 149

+  ERROR_SYSTEM_TRACE* = 150

+  ERROR_INVALID_EVENT_COUNT* = 151

+  ERROR_TOO_MANY_MUXWAITERS* = 152

+  ERROR_INVALID_LIST_FORMAT* = 153

+  ERROR_LABEL_TOO_LONG* = 154

+  ERROR_TOO_MANY_TCBS* = 155

+  ERROR_SIGNAL_REFUSED* = 156

+  ERROR_DISCARDED* = 157

+  ERROR_NOT_LOCKED* = 158

+  ERROR_BAD_THREADID_ADDR* = 159

+  ERROR_BAD_ARGUMENTS* = 160

+  ERROR_BAD_PATHNAME* = 161

+  ERROR_SIGNAL_PENDING* = 162

+  ERROR_MAX_THRDS_REACHED* = 164

+  ERROR_LOCK_FAILED* = 167

+  ERROR_BUSY* = 170

+  ERROR_CANCEL_VIOLATION* = 173

+  ERROR_ATOMIC_LOCKS_NOT_SUPPORTED* = 174

+  ERROR_INVALID_SEGMENT_NUMBER* = 180

+  ERROR_INVALID_ORDINAL* = 182

+  ERROR_ALREADY_EXISTS* = 183

+  ERROR_INVALID_FLAG_NUMBER* = 186

+  ERROR_SEM_NOT_FOUND* = 187

+  ERROR_INVALID_STARTING_CODESEG* = 188

+  ERROR_INVALID_STACKSEG* = 189

+  ERROR_INVALID_MODULETYPE* = 190

+  ERROR_INVALID_EXE_SIGNATURE* = 191

+  ERROR_EXE_MARKED_INVALID* = 192

+  ERROR_BAD_EXE_FORMAT* = 193

+  ERROR_ITERATED_DATA_EXCEEDS_64k* = 194

+  ERROR_INVALID_MINALLOCSIZE* = 195

+  ERROR_DYNLINK_FROM_INVALID_RING* = 196

+  ERROR_IOPL_NOT_ENABLED* = 197

+  ERROR_INVALID_SEGDPL* = 198

+  ERROR_AUTODATASEG_EXCEEDS_64k* = 199

+  ERROR_RING2SEG_MUST_BE_MOVABLE* = 200

+  ERROR_RELOC_CHAIN_XEEDS_SEGLIM* = 201

+  ERROR_INFLOOP_IN_RELOC_CHAIN* = 202

+  ERROR_ENVVAR_NOT_FOUND* = 203

+  ERROR_NO_SIGNAL_SENT* = 205

+  ERROR_FILENAME_EXCED_RANGE* = 206

+  ERROR_RING2_STACK_IN_USE* = 207

+  ERROR_META_EXPANSION_TOO_LONG* = 208

+  ERROR_INVALID_SIGNAL_NUMBER* = 209

+  ERROR_THREAD_1_INACTIVE* = 210

+  ERROR_LOCKED* = 212

+  ERROR_TOO_MANY_MODULES* = 214

+  ERROR_NESTING_NOT_ALLOWED* = 215

+  ERROR_BAD_PIPE* = 230

+  ERROR_PIPE_BUSY* = 231

+  ERROR_NO_DATA* = 232

+  ERROR_PIPE_NOT_CONNECTED* = 233

+  ERROR_MORE_DATA* = 234

+  ERROR_VC_DISCONNECTED* = 240

+  ERROR_INVALID_EA_NAME* = 254

+  ERROR_EA_LIST_INCONSISTENT* = 255

+  ERROR_NO_MORE_ITEMS* = 259

+  ERROR_CANNOT_COPY* = 266

+  ERROR_DIRECTORY* = 267

+  ERROR_EAS_DIDNT_FIT* = 275

+  ERROR_EA_FILE_CORRUPT* = 276

+  ERROR_EA_TABLE_FULL* = 277

+  ERROR_INVALID_EA_HANDLE* = 278

+  ERROR_EAS_NOT_SUPPORTED* = 282

+  ERROR_NOT_OWNER* = 288

+  ERROR_TOO_MANY_POSTS* = 298

+  ERROR_PARTIAL_COPY* = 299

+  ERROR_MR_MID_NOT_FOUND* = 317

+  ERROR_INVALID_ADDRESS* = 487

+  ERROR_ARITHMETIC_OVERFLOW* = 534

+  ERROR_PIPE_CONNECTED* = 535

+  ERROR_PIPE_LISTENING* = 536

+  ERROR_EA_ACCESS_DENIED* = 994

+  ERROR_OPERATION_ABORTED* = 995

+  ERROR_IO_INCOMPLETE* = 996

+  ERROR_IO_PENDING* = 997

+  ERROR_NOACCESS* = 998

+  ERROR_SWAPERROR* = 999

+  ERROR_STACK_OVERFLOW* = 1001

+  ERROR_INVALID_MESSAGE* = 1002

+  ERROR_CAN_NOT_COMPLETE* = 1003

+  ERROR_INVALID_FLAGS* = 1004

+  ERROR_UNRECOGNIZED_VOLUME* = 1005

+  ERROR_FILE_INVALID* = 1006

+  ERROR_FULLSCREEN_MODE* = 1007

+  ERROR_NO_TOKEN* = 1008

+  ERROR_BADDB* = 1009

+  ERROR_BADKEY* = 1010

+  ERROR_CANTOPEN* = 1011

+  ERROR_CANTREAD* = 1012

+  ERROR_CANTWRITE* = 1013

+  ERROR_REGISTRY_RECOVERED* = 1014

+  ERROR_REGISTRY_CORRUPT* = 1015

+  ERROR_REGISTRY_IO_FAILED* = 1016

+  ERROR_NOT_REGISTRY_FILE* = 1017

+  ERROR_KEY_DELETED* = 1018

+  ERROR_NO_LOG_SPACE* = 1019

+  ERROR_KEY_HAS_CHILDREN* = 1020

+  ERROR_CHILD_MUST_BE_VOLATILE* = 1021

+  ERROR_NOTIFY_ENUM_DIR* = 1022

+  ERROR_DEPENDENT_SERVICES_RUNNING* = 1051

+  ERROR_INVALID_SERVICE_CONTROL* = 1052

+  ERROR_SERVICE_REQUEST_TIMEOUT* = 1053

+  ERROR_SERVICE_NO_THREAD* = 1054

+  ERROR_SERVICE_DATABASE_LOCKED* = 1055

+  ERROR_SERVICE_ALREADY_RUNNING* = 1056

+  ERROR_INVALID_SERVICE_ACCOUNT* = 1057

+  ERROR_SERVICE_DISABLED* = 1058

+  ERROR_CIRCULAR_DEPENDENCY* = 1059

+  ERROR_SERVICE_DOES_NOT_EXIST* = 1060

+  ERROR_SERVICE_CANNOT_ACCEPT_CTRL* = 1061

+  ERROR_SERVICE_NOT_ACTIVE* = 1062

+  ERROR_FAILED_SERVICE_CONTROLLER_CONNECT* = 1063

+  ERROR_EXCEPTION_IN_SERVICE* = 1064

+  ERROR_DATABASE_DOES_NOT_EXIST* = 1065

+  ERROR_SERVICE_SPECIFIC_ERROR* = 1066

+  ERROR_PROCESS_ABORTED* = 1067

+  ERROR_SERVICE_DEPENDENCY_FAIL* = 1068

+  ERROR_SERVICE_LOGON_FAILED* = 1069

+  ERROR_SERVICE_START_HANG* = 1070

+  ERROR_INVALID_SERVICE_LOCK* = 1071

+  ERROR_SERVICE_MARKED_FOR_DELETE* = 1072

+  ERROR_SERVICE_EXISTS* = 1073

+  ERROR_ALREADY_RUNNING_LKG* = 1074

+  ERROR_SERVICE_DEPENDENCY_DELETED* = 1075

+  ERROR_BOOT_ALREADY_ACCEPTED* = 1076

+  ERROR_SERVICE_NEVER_STARTED* = 1077

+  ERROR_DUPLICATE_SERVICE_NAME* = 1078

+  ERROR_END_OF_MEDIA* = 1100

+  ERROR_FILEMARK_DETECTED* = 1101

+  ERROR_BEGINNING_OF_MEDIA* = 1102

+  ERROR_SETMARK_DETECTED* = 1103

+  ERROR_NO_DATA_DETECTED* = 1104

+  ERROR_PARTITION_FAILURE* = 1105

+  ERROR_INVALID_BLOCK_LENGTH* = 1106

+  ERROR_DEVICE_NOT_PARTITIONED* = 1107

+  ERROR_UNABLE_TO_LOCK_MEDIA* = 1108

+  ERROR_UNABLE_TO_UNLOAD_MEDIA* = 1109

+  ERROR_MEDIA_CHANGED* = 1110

+  ERROR_BUS_RESET* = 1111

+  ERROR_NO_MEDIA_IN_DRIVE* = 1112

+  ERROR_NO_UNICODE_TRANSLATION* = 1113

+  ERROR_DLL_INIT_FAILED* = 1114

+  ERROR_SHUTDOWN_IN_PROGRESS* = 1115

+  ERROR_NO_SHUTDOWN_IN_PROGRESS* = 1116

+  ERROR_IO_DEVICE* = 1117

+  ERROR_SERIAL_NO_DEVICE* = 1118

+  ERROR_IRQ_BUSY* = 1119

+  ERROR_MORE_WRITES* = 1120

+  ERROR_COUNTER_TIMEOUT* = 1121

+  ERROR_FLOPPY_ID_MARK_NOT_FOUND* = 1122

+  ERROR_FLOPPY_WRONG_CYLINDER* = 1123

+  ERROR_FLOPPY_UNKNOWN_ERROR* = 1124

+  ERROR_FLOPPY_BAD_REGISTERS* = 1125

+  ERROR_DISK_RECALIBRATE_FAILED* = 1126

+  ERROR_DISK_OPERATION_FAILED* = 1127

+  ERROR_DISK_RESET_FAILED* = 1128

+  ERROR_EOM_OVERFLOW* = 1129

+  ERROR_NOT_ENOUGH_SERVER_MEMORY* = 1130

+  ERROR_POSSIBLE_DEADLOCK* = 1131

+  ERROR_MAPPED_ALIGNMENT* = 1132

+  ERROR_SET_POWER_STATE_VETOED* = 1140

+  ERROR_SET_POWER_STATE_FAILED* = 1141

+  ERROR_OLD_WIN_VERSION* = 1150

+  ERROR_APP_WRONG_OS* = 1151

+  ERROR_SINGLE_INSTANCE_APP* = 1152

+  ERROR_RMODE_APP* = 1153

+  ERROR_INVALID_DLL* = 1154

+  ERROR_NO_ASSOCIATION* = 1155

+  ERROR_DDE_FAIL* = 1156

+  ERROR_DLL_NOT_FOUND* = 1157

+  ERROR_BAD_USERNAME* = 2202

+  ERROR_NOT_CONNECTED* = 2250

+  ERROR_OPEN_FILES* = 2401

+  ERROR_ACTIVE_CONNECTIONS* = 2402

+  ERROR_DEVICE_IN_USE* = 2404

+  ERROR_BAD_DEVICE* = 1200

+  ERROR_CONNECTION_UNAVAIL* = 1201

+  ERROR_DEVICE_ALREADY_REMEMBERED* = 1202

+  ERROR_NO_NET_OR_BAD_PATH* = 1203

+  ERROR_BAD_PROVIDER* = 1204

+  ERROR_CANNOT_OPEN_PROFILE* = 1205

+  ERROR_BAD_PROFILE* = 1206

+  ERROR_NOT_CONTAINER* = 1207

+  ERROR_EXTENDED_ERROR* = 1208

+  ERROR_INVALID_GROUPNAME* = 1209

+  ERROR_INVALID_COMPUTERNAME* = 1210

+  ERROR_INVALID_EVENTNAME* = 1211

+  ERROR_INVALID_DOMAINNAME* = 1212

+  ERROR_INVALID_SERVICENAME* = 1213

+  ERROR_INVALID_NETNAME* = 1214

+  ERROR_INVALID_SHARENAME* = 1215

+  ERROR_INVALID_PASSWORDNAME* = 1216

+  ERROR_INVALID_MESSAGENAME* = 1217

+  ERROR_INVALID_MESSAGEDEST* = 1218

+  ERROR_SESSION_CREDENTIAL_CONFLICT* = 1219

+  ERROR_REMOTE_SESSION_LIMIT_EXCEEDED* = 1220

+  ERROR_DUP_DOMAINNAME* = 1221

+  ERROR_NO_NETWORK* = 1222

+  ERROR_CANCELLED* = 1223

+  ERROR_USER_MAPPED_FILE* = 1224

+  ERROR_CONNECTION_REFUSED* = 1225

+  ERROR_GRACEFUL_DISCONNECT* = 1226

+  ERROR_ADDRESS_ALREADY_ASSOCIATED* = 1227

+  ERROR_ADDRESS_NOT_ASSOCIATED* = 1228

+  ERROR_CONNECTION_INVALID* = 1229

+  ERROR_CONNECTION_ACTIVE* = 1230

+  ERROR_NETWORK_UNREACHABLE* = 1231

+  ERROR_HOST_UNREACHABLE* = 1232

+  ERROR_PROTOCOL_UNREACHABLE* = 1233

+  ERROR_PORT_UNREACHABLE* = 1234

+  ERROR_REQUEST_ABORTED* = 1235

+  ERROR_CONNECTION_ABORTED* = 1236

+  ERROR_RETRY* = 1237

+  ERROR_CONNECTION_COUNT_LIMIT* = 1238

+  ERROR_LOGIN_TIME_RESTRICTION* = 1239

+  ERROR_LOGIN_WKSTA_RESTRICTION* = 1240

+  ERROR_INCORRECT_ADDRESS* = 1241

+  ERROR_ALREADY_REGISTERED* = 1242

+  ERROR_SERVICE_NOT_FOUND* = 1243

+  ERROR_NOT_AUTHENTICATED* = 1244

+  ERROR_NOT_LOGGED_ON* = 1245

+  ERROR_CONTINUE* = 1246

+  ERROR_ALREADY_INITIALIZED* = 1247

+  ERROR_NO_MORE_DEVICES* = 1248

+  ERROR_NOT_ALL_ASSIGNED* = 1300

+  ERROR_SOME_NOT_MAPPED* = 1301

+  ERROR_NO_QUOTAS_FOR_ACCOUNT* = 1302

+  ERROR_LOCAL_USER_SESSION_KEY* = 1303

+  ERROR_NULL_LM_PASSWORD* = 1304

+  ERROR_UNKNOWN_REVISION* = 1305

+  ERROR_REVISION_MISMATCH* = 1306

+  ERROR_INVALID_OWNER* = 1307

+  ERROR_INVALID_PRIMARY_GROUP* = 1308

+  ERROR_NO_IMPERSONATION_TOKEN* = 1309

+  ERROR_CANT_DISABLE_MANDATORY* = 1310

+  ERROR_NO_LOGON_SERVERS* = 1311

+  ERROR_NO_SUCH_LOGON_SESSION* = 1312

+  ERROR_NO_SUCH_PRIVILEGE* = 1313

+  ERROR_PRIVILEGE_NOT_HELD* = 1314

+  ERROR_INVALID_ACCOUNT_NAME* = 1315

+  ERROR_USER_EXISTS* = 1316

+  ERROR_NO_SUCH_USER* = 1317

+  ERROR_GROUP_EXISTS* = 1318

+  ERROR_NO_SUCH_GROUP* = 1319

+  ERROR_MEMBER_IN_GROUP* = 1320

+  ERROR_MEMBER_NOT_IN_GROUP* = 1321

+  ERROR_LAST_ADMIN* = 1322

+  ERROR_WRONG_PASSWORD* = 1323

+  ERROR_ILL_FORMED_PASSWORD* = 1324

+  ERROR_PASSWORD_RESTRICTION* = 1325

+  ERROR_LOGON_FAILURE* = 1326

+  ERROR_ACCOUNT_RESTRICTION* = 1327

+  ERROR_INVALID_LOGON_HOURS* = 1328

+  ERROR_INVALID_WORKSTATION* = 1329

+  ERROR_PASSWORD_EXPIRED* = 1330

+  ERROR_ACCOUNT_DISABLED* = 1331

+  ERROR_NONE_MAPPED* = 1332

+  ERROR_TOO_MANY_LUIDS_REQUESTED* = 1333

+  ERROR_LUIDS_EXHAUSTED* = 1334

+  ERROR_INVALID_SUB_AUTHORITY* = 1335

+  ERROR_INVALID_ACL* = 1336

+  ERROR_INVALID_SID* = 1337

+  ERROR_INVALID_SECURITY_DESCR* = 1338

+  ERROR_BAD_INHERITANCE_ACL* = 1340

+  ERROR_SERVER_DISABLED* = 1341

+  ERROR_SERVER_NOT_DISABLED* = 1342

+  ERROR_INVALID_ID_AUTHORITY* = 1343

+  ERROR_ALLOTTED_SPACE_EXCEEDED* = 1344

+  ERROR_INVALID_GROUP_ATTRIBUTES* = 1345

+  ERROR_BAD_IMPERSONATION_LEVEL* = 1346

+  ERROR_CANT_OPEN_ANONYMOUS* = 1347

+  ERROR_BAD_VALIDATION_CLASS* = 1348

+  ERROR_BAD_TOKEN_TYPE* = 1349

+  ERROR_NO_SECURITY_ON_OBJECT* = 1350

+  ERROR_CANT_ACCESS_DOMAIN_INFO* = 1351

+  ERROR_INVALID_SERVER_STATE* = 1352

+  ERROR_INVALID_DOMAIN_STATE* = 1353

+  ERROR_INVALID_DOMAIN_ROLE* = 1354

+  ERROR_NO_SUCH_DOMAIN* = 1355

+  ERROR_DOMAIN_EXISTS* = 1356

+  ERROR_DOMAIN_LIMIT_EXCEEDED* = 1357

+  ERROR_INTERNAL_DB_CORRUPTION* = 1358

+  ERROR_INTERNAL_ERROR* = 1359

+  ERROR_GENERIC_NOT_MAPPED* = 1360

+  ERROR_BAD_DESCRIPTOR_FORMAT* = 1361

+  ERROR_NOT_LOGON_PROCESS* = 1362

+  ERROR_LOGON_SESSION_EXISTS* = 1363

+  ERROR_NO_SUCH_PACKAGE* = 1364

+  ERROR_BAD_LOGON_SESSION_STATE* = 1365

+  ERROR_LOGON_SESSION_COLLISION* = 1366

+  ERROR_INVALID_LOGON_TYPE* = 1367

+  ERROR_CANNOT_IMPERSONATE* = 1368

+  ERROR_RXACT_INVALID_STATE* = 1369

+  ERROR_RXACT_COMMIT_FAILURE* = 1370

+  ERROR_SPECIAL_ACCOUNT* = 1371

+  ERROR_SPECIAL_GROUP* = 1372

+  ERROR_SPECIAL_USER* = 1373

+  ERROR_MEMBERS_PRIMARY_GROUP* = 1374

+  ERROR_TOKEN_ALREADY_IN_USE* = 1375

+  ERROR_NO_SUCH_ALIAS* = 1376

+  ERROR_MEMBER_NOT_IN_ALIAS* = 1377

+  ERROR_MEMBER_IN_ALIAS* = 1378

+  ERROR_ALIAS_EXISTS* = 1379

+  ERROR_LOGON_NOT_GRANTED* = 1380

+  ERROR_TOO_MANY_SECRETS* = 1381

+  ERROR_SECRET_TOO_LONG* = 1382

+  ERROR_INTERNAL_DB_ERROR* = 1383

+  ERROR_TOO_MANY_CONTEXT_IDS* = 1384

+  ERROR_LOGON_TYPE_NOT_GRANTED* = 1385

+  ERROR_NT_CROSS_ENCRYPTION_REQUIRED* = 1386

+  ERROR_NO_SUCH_MEMBER* = 1387

+  ERROR_INVALID_MEMBER* = 1388

+  ERROR_TOO_MANY_SIDS* = 1389

+  ERROR_LM_CROSS_ENCRYPTION_REQUIRED* = 1390

+  ERROR_NO_INHERITANCE* = 1391

+  ERROR_FILE_CORRUPT* = 1392

+  ERROR_DISK_CORRUPT* = 1393

+  ERROR_NO_USER_SESSION_KEY* = 1394

+  ERROR_LICENSE_QUOTA_EXCEEDED* = 1395

+  ERROR_INVALID_WINDOW_HANDLE* = 1400

+  ERROR_INVALID_MENU_HANDLE* = 1401

+  ERROR_INVALID_CURSOR_HANDLE* = 1402

+  ERROR_INVALID_ACCEL_HANDLE* = 1403

+  ERROR_INVALID_HOOK_HANDLE* = 1404

+  ERROR_INVALID_DWP_HANDLE* = 1405

+  ERROR_TLW_WITH_WSCHILD* = 1406

+  ERROR_CANNOT_FIND_WND_CLASS* = 1407

+  ERROR_WINDOW_OF_OTHER_THREAD* = 1408

+  ERROR_HOTKEY_ALREADY_REGISTERED* = 1409

+  ERROR_CLASS_ALREADY_EXISTS* = 1410

+  ERROR_CLASS_DOES_NOT_EXIST* = 1411

+  ERROR_CLASS_HAS_WINDOWS* = 1412

+  ERROR_INVALID_INDEX* = 1413

+  ERROR_INVALID_ICON_HANDLE* = 1414

+  ERROR_PRIVATE_DIALOG_INDEX* = 1415

+  ERROR_LISTBOX_ID_NOT_FOUND* = 1416

+  ERROR_NO_WILDCARD_CHARACTERS* = 1417

+  ERROR_CLIPBOARD_NOT_OPEN* = 1418

+  ERROR_HOTKEY_NOT_REGISTERED* = 1419

+  ERROR_WINDOW_NOT_DIALOG* = 1420

+  ERROR_CONTROL_ID_NOT_FOUND* = 1421

+  ERROR_INVALID_COMBOBOX_MESSAGE* = 1422

+  ERROR_WINDOW_NOT_COMBOBOX* = 1423

+  ERROR_INVALID_EDIT_HEIGHT* = 1424

+  ERROR_DC_NOT_FOUND* = 1425

+  ERROR_INVALID_HOOK_FILTER* = 1426

+  ERROR_INVALID_FILTER_PROC* = 1427

+  ERROR_HOOK_NEEDS_HMOD* = 1428

+  ERROR_GLOBAL_ONLY_HOOK* = 1429

+  ERROR_JOURNAL_HOOK_SET* = 1430

+  ERROR_HOOK_NOT_INSTALLED* = 1431

+  ERROR_INVALID_LB_MESSAGE* = 1432

+  ERROR_SETCOUNT_ON_BAD_LB* = 1433

+  ERROR_LB_WITHOUT_TABSTOPS* = 1434

+  ERROR_DESTROY_OBJECT_OF_OTHER_THREAD* = 1435

+  ERROR_CHILD_WINDOW_MENU* = 1436

+  ERROR_NO_SYSTEM_MENU* = 1437

+  ERROR_INVALID_MSGBOX_STYLE* = 1438

+  ERROR_INVALID_SPI_VALUE* = 1439

+  ERROR_SCREEN_ALREADY_LOCKED* = 1440

+  ERROR_HWNDS_HAVE_DIFF_PARENT* = 1441

+  ERROR_NOT_CHILD_WINDOW* = 1442

+  ERROR_INVALID_GW_COMMAND* = 1443

+  ERROR_INVALID_THREAD_ID* = 1444

+  ERROR_NON_MDICHILD_WINDOW* = 1445

+  ERROR_POPUP_ALREADY_ACTIVE* = 1446

+  ERROR_NO_SCROLLBARS* = 1447

+  ERROR_INVALID_SCROLLBAR_RANGE* = 1448

+  ERROR_INVALID_SHOWWIN_COMMAND* = 1449

+  ERROR_NO_SYSTEM_RESOURCES* = 1450

+  ERROR_NONPAGED_SYSTEM_RESOURCES* = 1451

+  ERROR_PAGED_SYSTEM_RESOURCES* = 1452

+  ERROR_WORKING_SET_QUOTA* = 1453

+  ERROR_PAGEFILE_QUOTA* = 1454

+  ERROR_COMMITMENT_LIMIT* = 1455

+  ERROR_MENU_ITEM_NOT_FOUND* = 1456

+  ERROR_INVALID_KEYBOARD_HANDLE* = 1457

+  ERROR_HOOK_TYPE_NOT_ALLOWED* = 1458

+  ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION* = 1459

+  ERROR_TIMEOUT* = 1460

+  ERROR_EVENTLOG_FILE_CORRUPT* = 1500

+  ERROR_EVENTLOG_CANT_START* = 1501

+  ERROR_LOG_FILE_FULL* = 1502

+  ERROR_EVENTLOG_FILE_CHANGED* = 1503

+  RPC_S_INVALID_STRING_BINDING* = 1700

+  RPC_S_WRONG_KIND_OF_BINDING* = 1701

+  RPC_S_INVALID_BINDING* = 1702

+  RPC_S_PROTSEQ_NOT_SUPPORTED* = 1703

+  RPC_S_INVALID_RPC_PROTSEQ* = 1704

+  RPC_S_INVALID_STRING_UUID* = 1705

+  RPC_S_INVALID_ENDPOINT_FORMAT* = 1706

+  RPC_S_INVALID_NET_ADDR* = 1707

+  RPC_S_NO_ENDPOINT_FOUND* = 1708

+  RPC_S_INVALID_TIMEOUT* = 1709

+  RPC_S_OBJECT_NOT_FOUND* = 1710

+  RPC_S_ALREADY_REGISTERED* = 1711

+  RPC_S_TYPE_ALREADY_REGISTERED* = 1712

+  RPC_S_ALREADY_LISTENING* = 1713

+  RPC_S_NO_PROTSEQS_REGISTERED* = 1714

+  RPC_S_NOT_LISTENING* = 1715

+  RPC_S_UNKNOWN_MGR_TYPE* = 1716

+  RPC_S_UNKNOWN_IF* = 1717

+  RPC_S_NO_BINDINGS* = 1718

+  RPC_S_NO_PROTSEQS* = 1719

+  RPC_S_CANT_CREATE_ENDPOINT* = 1720

+  RPC_S_OUT_OF_RESOURCES* = 1721

+  RPC_S_SERVER_UNAVAILABLE* = 1722

+  RPC_S_SERVER_TOO_BUSY* = 1723

+  RPC_S_INVALID_NETWORK_OPTIONS* = 1724

+  RPC_S_NO_CALL_ACTIVE* = 1725

+  RPC_S_CALL_FAILED* = 1726

+  RPC_S_CALL_FAILED_DNE* = 1727

+  RPC_S_PROTOCOL_ERROR* = 1728

+  RPC_S_UNSUPPORTED_TRANS_SYN* = 1730

+  RPC_S_UNSUPPORTED_TYPE* = 1732

+  RPC_S_INVALID_TAG* = 1733

+  RPC_S_INVALID_BOUND* = 1734

+  RPC_S_NO_ENTRY_NAME* = 1735

+  RPC_S_INVALID_NAME_SYNTAX* = 1736

+  RPC_S_UNSUPPORTED_NAME_SYNTAX* = 1737

+  RPC_S_UUID_NO_ADDRESS* = 1739

+  RPC_S_DUPLICATE_ENDPOINT* = 1740

+  RPC_S_UNKNOWN_AUTHN_TYPE* = 1741

+  RPC_S_MAX_CALLS_TOO_SMALL* = 1742

+  RPC_S_STRING_TOO_LONG* = 1743

+  RPC_S_PROTSEQ_NOT_FOUND* = 1744

+  RPC_S_PROCNUM_OUT_OF_RANGE* = 1745

+  RPC_S_BINDING_HAS_NO_AUTH* = 1746

+  RPC_S_UNKNOWN_AUTHN_SERVICE* = 1747

+  RPC_S_UNKNOWN_AUTHN_LEVEL* = 1748

+  RPC_S_INVALID_AUTH_IDENTITY* = 1749

+  RPC_S_UNKNOWN_AUTHZ_SERVICE* = 1750

+  EPT_S_INVALID_ENTRY* = 1751

+  EPT_S_CANT_PERFORM_OP* = 1752

+  EPT_S_NOT_REGISTERED* = 1753

+  RPC_S_NOTHING_TO_EXPORT* = 1754

+  RPC_S_INCOMPLETE_NAME* = 1755

+  RPC_S_INVALID_VERS_OPTION* = 1756

+  RPC_S_NO_MORE_MEMBERS* = 1757

+  RPC_S_NOT_ALL_OBJS_UNEXPORTED* = 1758

+  RPC_S_INTERFACE_NOT_FOUND* = 1759

+  RPC_S_ENTRY_ALREADY_EXISTS* = 1760

+  RPC_S_ENTRY_NOT_FOUND* = 1761

+  RPC_S_NAME_SERVICE_UNAVAILABLE* = 1762

+  RPC_S_INVALID_NAF_ID* = 1763

+  RPC_S_CANNOT_SUPPORT* = 1764

+  RPC_S_NO_CONTEXT_AVAILABLE* = 1765

+  RPC_S_INTERNAL_ERROR* = 1766

+  RPC_S_ZERO_DIVIDE* = 1767

+  RPC_S_ADDRESS_ERROR* = 1768

+  RPC_S_FP_DIV_ZERO* = 1769

+  RPC_S_FP_UNDERFLOW* = 1770

+  RPC_S_FP_OVERFLOW* = 1771

+  RPC_X_NO_MORE_ENTRIES* = 1772

+  RPC_X_SS_CHAR_TRANS_OPEN_FAIL* = 1773

+  RPC_X_SS_CHAR_TRANS_SHORT_FILE* = 1774

+  RPC_X_SS_IN_NULL_CONTEXT* = 1775

+  RPC_X_SS_CONTEXT_DAMAGED* = 1777

+  RPC_X_SS_HANDLES_MISMATCH* = 1778

+  RPC_X_SS_CANNOT_GET_CALL_HANDLE* = 1779

+  RPC_X_NULL_REF_POINTER* = 1780

+  RPC_X_ENUM_VALUE_OUT_OF_RANGE* = 1781

+  RPC_X_BYTE_COUNT_TOO_SMALL* = 1782

+  RPC_X_BAD_STUB_DATA* = 1783

+  ERROR_INVALID_USER_BUFFER* = 1784

+  ERROR_UNRECOGNIZED_MEDIA* = 1785

+  ERROR_NO_TRUST_LSA_SECRET* = 1786

+  ERROR_NO_TRUST_SAM_ACCOUNT* = 1787

+  ERROR_TRUSTED_DOMAIN_FAILURE* = 1788

+  ERROR_TRUSTED_RELATIONSHIP_FAILURE* = 1789

+  ERROR_TRUST_FAILURE* = 1790

+  RPC_S_CALL_IN_PROGRESS* = 1791

+  ERROR_NETLOGON_NOT_STARTED* = 1792

+  ERROR_ACCOUNT_EXPIRED* = 1793

+  ERROR_REDIRECTOR_HAS_OPEN_HANDLES* = 1794

+  ERROR_PRINTER_DRIVER_ALREADY_INSTALLED* = 1795

+  ERROR_UNKNOWN_PORT* = 1796

+  ERROR_UNKNOWN_PRINTER_DRIVER* = 1797

+  ERROR_UNKNOWN_PRINTPROCESSOR* = 1798

+  ERROR_INVALID_SEPARATOR_FILE* = 1799

+  ERROR_INVALID_PRIORITY* = 1800

+  ERROR_INVALID_PRINTER_NAME* = 1801

+  ERROR_PRINTER_ALREADY_EXISTS* = 1802

+  ERROR_INVALID_PRINTER_COMMAND* = 1803

+  ERROR_INVALID_DATATYPE* = 1804

+  ERROR_INVALID_ENVIRONMENT* = 1805

+  RPC_S_NO_MORE_BINDINGS* = 1806

+  ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT* = 1807

+  ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT* = 1808

+  ERROR_NOLOGON_SERVER_TRUST_ACCOUNT* = 1809

+  ERROR_DOMAIN_TRUST_INCONSISTENT* = 1810

+  ERROR_SERVER_HAS_OPEN_HANDLES* = 1811

+  ERROR_RESOURCE_DATA_NOT_FOUND* = 1812

+  ERROR_RESOURCE_TYPE_NOT_FOUND* = 1813

+  ERROR_RESOURCE_NAME_NOT_FOUND* = 1814

+  ERROR_RESOURCE_LANG_NOT_FOUND* = 1815

+  ERROR_NOT_ENOUGH_QUOTA* = 1816

+  RPC_S_NO_INTERFACES* = 1817

+  RPC_S_CALL_CANCELLED* = 1818

+  RPC_S_BINDING_INCOMPLETE* = 1819

+  RPC_S_COMM_FAILURE* = 1820

+  RPC_S_UNSUPPORTED_AUTHN_LEVEL* = 1821

+  RPC_S_NO_PRINC_NAME* = 1822

+  RPC_S_NOT_RPC_ERROR* = 1823

+  RPC_S_UUID_LOCAL_ONLY* = 1824

+  RPC_S_SEC_PKG_ERROR* = 1825

+  RPC_S_NOT_CANCELLED* = 1826

+  RPC_X_INVALID_ES_ACTION* = 1827

+  RPC_X_WRONG_ES_VERSION* = 1828

+  RPC_X_WRONG_STUB_VERSION* = 1829

+  RPC_X_INVALID_PIPE_OBJECT* = 1830

+  RPC_X_INVALID_PIPE_OPERATION* = 1831

+  RPC_S_GROUP_MEMBER_NOT_FOUND* = 1898

+  EPT_S_CANT_CREATE* = 1899

+  RPC_S_INVALID_OBJECT* = 1900

+  ERROR_INVALID_TIME* = 1901

+  ERROR_INVALID_FORM_NAME* = 1902

+  ERROR_INVALID_FORM_SIZE* = 1903

+  ERROR_ALREADY_WAITING* = 1904

+  ERROR_PRINTER_DELETED* = 1905

+  ERROR_INVALID_PRINTER_STATE* = 1906

+  ERROR_PASSWORD_MUST_CHANGE* = 1907

+  ERROR_DOMAIN_CONTROLLER_NOT_FOUND* = 1908

+  ERROR_ACCOUNT_LOCKED_OUT* = 1909

+  OR_INVALID_OXID* = 1910

+  OR_INVALID_OID* = 1911

+  OR_INVALID_SET* = 1912

+  RPC_S_SEND_INCOMPLETE* = 1913

+  ERROR_NO_BROWSER_SERVERS_FOUND* = 6118

+  ERROR_INVALID_PIXEL_FORMAT* = 2000

+  ERROR_BAD_DRIVER* = 2001

+  ERROR_INVALID_WINDOW_STYLE* = 2002

+  ERROR_METAFILE_NOT_SUPPORTED* = 2003

+  ERROR_TRANSFORM_NOT_SUPPORTED* = 2004

+  ERROR_CLIPPING_NOT_SUPPORTED* = 2005

+  ERROR_UNKNOWN_PRINT_MONITOR* = 3000

+  ERROR_PRINTER_DRIVER_IN_USE* = 3001

+  ERROR_SPOOL_FILE_NOT_FOUND* = 3002

+  ERROR_SPL_NO_STARTDOC* = 3003

+  ERROR_SPL_NO_ADDJOB* = 3004

+  ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED* = 3005

+  ERROR_PRINT_MONITOR_ALREADY_INSTALLED* = 3006

+  ERROR_INVALID_PRINT_MONITOR* = 3007

+  ERROR_PRINT_MONITOR_IN_USE* = 3008

+  ERROR_PRINTER_HAS_JOBS_QUEUED* = 3009

+  ERROR_SUCCESS_REBOOT_REQUIRED* = 3010

+  ERROR_SUCCESS_RESTART_REQUIRED* = 3011

+  ERROR_WINS_INTERNAL* = 4000

+  ERROR_CAN_NOT_DEL_LOCAL_WINS* = 4001

+  ERROR_STATIC_INIT* = 4002

+  ERROR_INC_BACKUP* = 4003

+  ERROR_FULL_BACKUP* = 4004

+  ERROR_REC_NON_EXISTENT* = 4005

+  ERROR_RPL_NOT_ALLOWED* = 4006

+  E_UNEXPECTED* = HRESULT(0x8000FFFF)

+  E_NOTIMPL* = HRESULT(0x80004001)

+  E_OUTOFMEMORY* = HRESULT(0x8007000E)

+  E_INVALIDARG* = HRESULT(0x80070057)

+  E_NOINTERFACE* = HRESULT(0x80004002)

+  E_POINTER* = HRESULT(0x80004003)

+  E_HANDLE* = HRESULT(0x80070006)

+  E_ABORT* = HRESULT(0x80004004)

+  E_FAIL* = HRESULT(0x80004005)

+  E_ACCESSDENIED* = HRESULT(0x80070005)

+  E_PENDING* = HRESULT(0x8000000A)

+  CO_E_INIT_TLS* = HRESULT(0x80004006)

+  CO_E_INIT_SHARED_ALLOCATOR* = HRESULT(0x80004007)

+  CO_E_INIT_MEMORY_ALLOCATOR* = HRESULT(0x80004008)

+  CO_E_INIT_CLASS_CACHE* = HRESULT(0x80004009)

+  CO_E_INIT_RPC_CHANNEL* = HRESULT(0x8000400A)

+  CO_E_INIT_TLS_SET_CHANNEL_CONTROL* = HRESULT(0x8000400B)

+  CO_E_INIT_TLS_CHANNEL_CONTROL* = HRESULT(0x8000400C)

+  CO_E_INIT_UNACCEPTED_USER_ALLOCATOR* = HRESULT(0x8000400D)

+  CO_E_INIT_SCM_MUTEX_EXISTS* = HRESULT(0x8000400E)

+  CO_E_INIT_SCM_FILE_MAPPING_EXISTS* = HRESULT(0x8000400F)

+  CO_E_INIT_SCM_MAP_VIEW_OF_FILE* = HRESULT(0x80004010)

+  CO_E_INIT_SCM_EXEC_FAILURE* = HRESULT(0x80004011)

+  CO_E_INIT_ONLY_SINGLE_THREADED* = HRESULT(0x80004012)

+  CO_E_CANT_REMOTE* = HRESULT(0x80004013)

+  CO_E_BAD_SERVER_NAME* = HRESULT(0x80004014)

+  CO_E_WRONG_SERVER_IDENTITY* = HRESULT(0x80004015)

+  CO_E_OLE1DDE_DISABLED* = HRESULT(0x80004016)

+  CO_E_RUNAS_SYNTAX* = HRESULT(0x80004017)

+  CO_E_CREATEPROCESS_FAILURE* = HRESULT(0x80004018)

+  CO_E_RUNAS_CREATEPROCESS_FAILURE* = HRESULT(0x80004019)

+  CO_E_RUNAS_LOGON_FAILURE* = HRESULT(0x8000401A)

+  CO_E_LAUNCH_PERMSSION_DENIED* = HRESULT(0x8000401B)

+  CO_E_START_SERVICE_FAILURE* = HRESULT(0x8000401C)

+  CO_E_REMOTE_COMMUNICATION_FAILURE* = HRESULT(0x8000401D)

+  CO_E_SERVER_START_TIMEOUT* = HRESULT(0x8000401E)

+  CO_E_CLSREG_INCONSISTENT* = HRESULT(0x8000401F)

+  CO_E_IIDREG_INCONSISTENT* = HRESULT(0x80004020)

+  CO_E_NOT_SUPPORTED* = HRESULT(0x80004021)

+  CO_E_FIRST* = DWORD(0x800401F0)

+  CO_E_LAST* = DWORD(0x800401FF)

+  CO_S_FIRST* = DWORD(0x000401F0)

+  CO_S_LAST* = DWORD(0x000401FF)

+  S_OK* = HRESULT(0x00000000)

+  S_FALSE* = HRESULT(0x00000001)

+  CO_E_NOTINITIALIZED* = HRESULT(0x800401F0)

+  CO_E_ALREADYINITIALIZED* = HRESULT(0x800401F1)

+  CO_E_CANTDETERMINECLASS* = HRESULT(0x800401F2)

+  CO_E_CLASSSTRING* = HRESULT(0x800401F3)

+  CO_E_IIDSTRING* = HRESULT(0x800401F4)

+  CO_E_APPNOTFOUND* = HRESULT(0x800401F5)

+  CO_E_APPSINGLEUSE* = HRESULT(0x800401F6)

+  CO_E_ERRORINAPP* = HRESULT(0x800401F7)

+  CO_E_DLLNOTFOUND* = HRESULT(0x800401F8)

+  CO_E_ERRORINDLL* = HRESULT(0x800401F9)

+  CO_E_WRONGOSFORAPP* = HRESULT(0x800401FA)

+  CO_E_OBJNOTREG* = HRESULT(0x800401FB)

+  CO_E_OBJISREG* = HRESULT(0x800401FC)

+  CO_E_OBJNOTCONNECTED* = HRESULT(0x800401FD)

+  CO_E_APPDIDNTREG* = HRESULT(0x800401FE)

+  CO_E_RELEASED* = HRESULT(0x800401FF)

+  OLE_E_FIRST* = HRESULT(0x80040000)

+  OLE_E_LAST* = HRESULT(0x800400FF)

+  OLE_S_FIRST* = HRESULT(0x00040000)

+  OLE_S_LAST* = HRESULT(0x000400FF)

+  OLE_E_OLEVERB* = HRESULT(0x80040000)

+  OLE_E_ADVF* = HRESULT(0x80040001)

+  OLE_E_ENUM_NOMORE* = HRESULT(0x80040002)

+  OLE_E_ADVISENOTSUPPORTED* = HRESULT(0x80040003)

+  OLE_E_NOCONNECTION* = HRESULT(0x80040004)

+  OLE_E_NOTRUNNING* = HRESULT(0x80040005)

+  OLE_E_NOCACHE* = HRESULT(0x80040006)

+  OLE_E_BLANK* = HRESULT(0x80040007)

+  OLE_E_CLASSDIFF* = HRESULT(0x80040008)

+  OLE_E_CANT_GETMONIKER* = HRESULT(0x80040009)

+  OLE_E_CANT_BINDTOSOURCE* = HRESULT(0x8004000A)

+  OLE_E_STATIC* = HRESULT(0x8004000B)

+  OLE_E_PROMPTSAVECANCELLED* = HRESULT(0x8004000C)

+  OLE_E_INVALIDRECT* = HRESULT(0x8004000D)

+  OLE_E_WRONGCOMPOBJ* = HRESULT(0x8004000E)

+  OLE_E_INVALIDHWND* = HRESULT(0x8004000F)

+  OLE_E_NOT_INPLACEACTIVE* = HRESULT(0x80040010)

+  OLE_E_CANTCONVERT* = HRESULT(0x80040011)

+  OLE_E_NOSTORAGE* = HRESULT(0x80040012)

+  DV_E_FORMATETC* = HRESULT(0x80040064)

+  DV_E_DVTARGETDEVICE* = HRESULT(0x80040065)

+  DV_E_STGMEDIUM* = HRESULT(0x80040066)

+  DV_E_STATDATA* = HRESULT(0x80040067)

+  DV_E_LINDEX* = HRESULT(0x80040068)

+  DV_E_TYMED* = HRESULT(0x80040069)

+  DV_E_CLIPFORMAT* = HRESULT(0x8004006A)

+  DV_E_DVASPECT* = HRESULT(0x8004006B)

+  DV_E_DVTARGETDEVICE_SIZE* = HRESULT(0x8004006C)

+  DV_E_NOIVIEWOBJECT* = HRESULT(0x8004006D)

+  DRAGDROP_E_FIRST* = DWORD(0x80040100)

+  DRAGDROP_E_LAST* = DWORD(0x8004010F)

+  DRAGDROP_S_FIRST* = DWORD(0x00040100)

+  DRAGDROP_S_LAST* = DWORD(0x0004010F)

+  DRAGDROP_E_NOTREGISTERED* = HRESULT(0x80040100)

+  DRAGDROP_E_ALREADYREGISTERED* = HRESULT(0x80040101)

+  DRAGDROP_E_INVALIDHWND* = HRESULT(0x80040102)

+  CLASSFACTORY_E_FIRST* = DWORD(0x80040110)

+  CLASSFACTORY_E_LAST* = DWORD(0x8004011F)

+  CLASSFACTORY_S_FIRST* = DWORD(0x00040110)

+  CLASSFACTORY_S_LAST* = DWORD(0x0004011F)

+  CLASS_E_NOAGGREGATION* = HRESULT(0x80040110)

+  CLASS_E_CLASSNOTAVAILABLE* = HRESULT(0x80040111)

+  MARSHAL_E_FIRST* = DWORD(0x80040120)

+  MARSHAL_E_LAST* = DWORD(0x8004012F)

+  MARSHAL_S_FIRST* = DWORD(0x00040120)

+  MARSHAL_S_LAST* = DWORD(0x0004012F)

+  DATA_E_FIRST* = DWORD(0x80040130)

+  DATA_E_LAST* = DWORD(0x8004013F)

+  DATA_S_FIRST* = DWORD(0x00040130)

+  DATA_S_LAST* = DWORD(0x0004013F)

+  VIEW_E_FIRST* = DWORD(0x80040140)

+  VIEW_E_LAST* = DWORD(0x8004014F)

+  VIEW_S_FIRST* = DWORD(0x00040140)

+  VIEW_S_LAST* = DWORD(0x0004014F)

+  VIEW_E_DRAW* = HRESULT(0x80040140)

+  REGDB_E_FIRST* = DWORD(0x80040150)

+  REGDB_E_LAST* = DWORD(0x8004015F)

+  REGDB_S_FIRST* = DWORD(0x00040150)

+  REGDB_S_LAST* = DWORD(0x0004015F)

+  REGDB_E_READREGDB* = HRESULT(0x80040150)

+  REGDB_E_WRITEREGDB* = HRESULT(0x80040151)

+  REGDB_E_KEYMISSING* = HRESULT(0x80040152)

+  REGDB_E_INVALIDVALUE* = HRESULT(0x80040153)

+  REGDB_E_CLASSNOTREG* = HRESULT(0x80040154)

+  REGDB_E_IIDNOTREG* = HRESULT(0x80040155)

+  CACHE_E_FIRST* = DWORD(0x80040170)

+  CACHE_E_LAST* = DWORD(0x8004017F)

+  CACHE_S_FIRST* = DWORD(0x00040170)

+  CACHE_S_LAST* = DWORD(0x0004017F)

+  CACHE_E_NOCACHE_UPDATED* = HRESULT(0x80040170)

+  OLEOBJ_E_FIRST* = DWORD(0x80040180)

+  OLEOBJ_E_LAST* = DWORD(0x8004018F)

+  OLEOBJ_S_FIRST* = DWORD(0x00040180)

+  OLEOBJ_S_LAST* = DWORD(0x0004018F)

+  OLEOBJ_E_NOVERBS* = HRESULT(0x80040180)

+  OLEOBJ_E_INVALIDVERB* = HRESULT(0x80040181)

+  CLIENTSITE_E_FIRST* = DWORD(0x80040190)

+  CLIENTSITE_E_LAST* = DWORD(0x8004019F)

+  CLIENTSITE_S_FIRST* = DWORD(0x00040190)

+  CLIENTSITE_S_LAST* = DWORD(0x0004019F)

+  INPLACE_E_NOTUNDOABLE* = HRESULT(0x800401A0)

+  INPLACE_E_NOTOOLSPACE* = HRESULT(0x800401A1)

+  INPLACE_E_FIRST* = DWORD(0x800401A0)

+  INPLACE_E_LAST* = DWORD(0x800401AF)

+  INPLACE_S_FIRST* = DWORD(0x000401A0)

+  INPLACE_S_LAST* = DWORD(0x000401AF)

+  ENUM_E_FIRST* = DWORD(0x800401B0)

+  ENUM_E_LAST* = DWORD(0x800401BF)

+  ENUM_S_FIRST* = DWORD(0x000401B0)

+  ENUM_S_LAST* = DWORD(0x000401BF)

+  CONVERT10_E_FIRST* = DWORD(0x800401C0)

+  CONVERT10_E_LAST* = DWORD(0x800401CF)

+  CONVERT10_S_FIRST* = DWORD(0x000401C0)

+  CONVERT10_S_LAST* = DWORD(0x000401CF)

+  CONVERT10_E_OLESTREAM_GET* = HRESULT(0x800401C0)

+  CONVERT10_E_OLESTREAM_PUT* = HRESULT(0x800401C1)

+  CONVERT10_E_OLESTREAM_FMT* = HRESULT(0x800401C2)

+  CONVERT10_E_OLESTREAM_BITMAP_TO_DIB* = HRESULT(0x800401C3)

+  CONVERT10_E_STG_FMT* = HRESULT(0x800401C4)

+  CONVERT10_E_STG_NO_STD_STREAM* = HRESULT(0x800401C5)

+  CONVERT10_E_STG_DIB_TO_BITMAP* = HRESULT(0x800401C6)

+  CLIPBRD_E_FIRST* = DWORD(0x800401D0)

+  CLIPBRD_E_LAST* = DWORD(0x800401DF)

+  CLIPBRD_S_FIRST* = DWORD(0x000401D0)

+  CLIPBRD_S_LAST* = DWORD(0x000401DF)

+  CLIPBRD_E_CANT_OPEN* = HRESULT(0x800401D0)

+  CLIPBRD_E_CANT_EMPTY* = HRESULT(0x800401D1)

+  CLIPBRD_E_CANT_SET* = HRESULT(0x800401D2)

+  CLIPBRD_E_BAD_DATA* = HRESULT(0x800401D3)

+  CLIPBRD_E_CANT_CLOSE* = HRESULT(0x800401D4)

+  MK_E_FIRST* = DWORD(0x800401E0)

+  MK_E_LAST* = DWORD(0x800401EF)

+  MK_S_FIRST* = DWORD(0x000401E0)

+  MK_S_LAST* = DWORD(0x000401EF)

+  MK_E_CONNECTMANUALLY* = HRESULT(0x800401E0)

+  MK_E_EXCEEDEDDEADLINE* = HRESULT(0x800401E1)

+  MK_E_NEEDGENERIC* = HRESULT(0x800401E2)

+  MK_E_UNAVAILABLE* = HRESULT(0x800401E3)

+  MK_E_SYNTAX* = HRESULT(0x800401E4)

+  MK_E_NOOBJECT* = HRESULT(0x800401E5)

+  MK_E_INVALIDEXTENSION* = HRESULT(0x800401E6)

+  MK_E_INTERMEDIATEINTERFACENOTSUPPORTED* = HRESULT(0x800401E7)

+  MK_E_NOTBINDABLE* = HRESULT(0x800401E8)

+  MK_E_NOTBOUND* = HRESULT(0x800401E9)

+  MK_E_CANTOPENFILE* = HRESULT(0x800401EA)

+  MK_E_MUSTBOTHERUSER* = HRESULT(0x800401EB)

+  MK_E_NOINVERSE* = HRESULT(0x800401EC)

+  MK_E_NOSTORAGE* = HRESULT(0x800401ED)

+  MK_E_NOPREFIX* = HRESULT(0x800401EE)

+  MK_E_ENUMERATION_FAILED* = HRESULT(0x800401EF)

+  OLE_S_USEREG* = HRESULT(0x00040000)

+  OLE_S_STATIC* = HRESULT(0x00040001)

+  OLE_S_MAC_CLIPFORMAT* = HRESULT(0x00040002)

+  DRAGDROP_S_DROP* = HRESULT(0x00040100)

+  DRAGDROP_S_CANCEL* = HRESULT(0x00040101)

+  DRAGDROP_S_USEDEFAULTCURSORS* = HRESULT(0x00040102)

+  DATA_S_SAMEFORMATETC* = HRESULT(0x00040130)

+  VIEW_S_ALREADY_FROZEN* = HRESULT(0x00040140)

+  CACHE_S_FORMATETC_NOTSUPPORTED* = HRESULT(0x00040170)

+  CACHE_S_SAMECACHE* = HRESULT(0x00040171)

+  CACHE_S_SOMECACHES_NOTUPDATED* = HRESULT(0x00040172)

+  OLEOBJ_S_INVALIDVERB* = HRESULT(0x00040180)

+  OLEOBJ_S_CANNOT_DOVERB_NOW* = HRESULT(0x00040181)

+  OLEOBJ_S_INVALIDHWND* = HRESULT(0x00040182)

+  INPLACE_S_TRUNCATED* = HRESULT(0x000401A0)

+  CONVERT10_S_NO_PRESENTATION* = HRESULT(0x000401C0)

+  MK_S_REDUCED_TO_SELF* = HRESULT(0x000401E2)

+  MK_S_ME* = HRESULT(0x000401E4)

+  MK_S_HIM* = HRESULT(0x000401E5)

+  MK_S_US* = HRESULT(0x000401E6)

+  MK_S_MONIKERALREADYREGISTERED* = HRESULT(0x000401E7)

+  CO_E_CLASS_CREATE_FAILED* = HRESULT(0x80080001)

+  CO_E_SCM_ERROR* = HRESULT(0x80080002)

+  CO_E_SCM_RPC_FAILURE* = HRESULT(0x80080003)

+  CO_E_BAD_PATH* = HRESULT(0x80080004)

+  CO_E_SERVER_EXEC_FAILURE* = HRESULT(0x80080005)

+  CO_E_OBJSRV_RPC_FAILURE* = HRESULT(0x80080006)

+  MK_E_NO_NORMALIZED* = HRESULT(0x80080007)

+  CO_E_SERVER_STOPPING* = HRESULT(0x80080008)

+  MEM_E_INVALID_ROOT* = HRESULT(0x80080009)

+  MEM_E_INVALID_LINK* = HRESULT(0x80080010)

+  MEM_E_INVALID_SIZE* = HRESULT(0x80080011)

+  CO_S_NOTALLINTERFACES* = HRESULT(0x00080012)

+  DISP_E_UNKNOWNINTERFACE* = HRESULT(0x80020001)

+  DISP_E_MEMBERNOTFOUND* = HRESULT(0x80020003)

+  DISP_E_PARAMNOTFOUND* = HRESULT(0x80020004)

+  DISP_E_TYPEMISMATCH* = HRESULT(0x80020005)

+  DISP_E_UNKNOWNNAME* = HRESULT(0x80020006)

+  DISP_E_NONAMEDARGS* = HRESULT(0x80020007)

+  DISP_E_BADVARTYPE* = HRESULT(0x80020008)

+  DISP_E_EXCEPTION* = HRESULT(0x80020009)

+  DISP_E_OVERFLOW* = HRESULT(0x8002000A)

+  DISP_E_BADINDEX* = HRESULT(0x8002000B)

+  DISP_E_UNKNOWNLCID* = HRESULT(0x8002000C)

+  DISP_E_ARRAYISLOCKED* = HRESULT(0x8002000D)

+  DISP_E_BADPARAMCOUNT* = HRESULT(0x8002000E)

+  DISP_E_PARAMNOTOPTIONAL* = HRESULT(0x8002000F)

+  DISP_E_BADCALLEE* = HRESULT(0x80020010)

+  DISP_E_NOTACOLLECTION* = HRESULT(0x80020011)

+  TYPE_E_BUFFERTOOSMALL* = HRESULT(0x80028016)

+  TYPE_E_INVDATAREAD* = HRESULT(0x80028018)

+  TYPE_E_UNSUPFORMAT* = HRESULT(0x80028019)

+  TYPE_E_REGISTRYACCESS* = HRESULT(0x8002801C)

+  TYPE_E_LIBNOTREGISTERED* = HRESULT(0x8002801D)

+  TYPE_E_UNDEFINEDTYPE* = HRESULT(0x80028027)

+  TYPE_E_QUALIFIEDNAMEDISALLOWED* = HRESULT(0x80028028)

+  TYPE_E_INVALIDSTATE* = HRESULT(0x80028029)

+  TYPE_E_WRONGTYPEKIND* = HRESULT(0x8002802A)

+  TYPE_E_ELEMENTNOTFOUND* = HRESULT(0x8002802B)

+  TYPE_E_AMBIGUOUSNAME* = HRESULT(0x8002802C)

+  TYPE_E_NAMECONFLICT* = HRESULT(0x8002802D)

+  TYPE_E_UNKNOWNLCID* = HRESULT(0x8002802E)

+  TYPE_E_DLLFUNCTIONNOTFOUND* = HRESULT(0x8002802F)

+  TYPE_E_BADMODULEKIND* = HRESULT(0x800288BD)

+  TYPE_E_SIZETOOBIG* = HRESULT(0x800288C5)

+  TYPE_E_DUPLICATEID* = HRESULT(0x800288C6)

+  TYPE_E_INVALIDID* = HRESULT(0x800288CF)

+  TYPE_E_TYPEMISMATCH* = HRESULT(0x80028CA0)

+  TYPE_E_OUTOFBOUNDS* = HRESULT(0x80028CA1)

+  TYPE_E_IOERROR* = HRESULT(0x80028CA2)

+  TYPE_E_CANTCREATETMPFILE* = HRESULT(0x80028CA3)

+  TYPE_E_CANTLOADLIBRARY* = HRESULT(0x80029C4A)

+  TYPE_E_INCONSISTENTPROPFUNCS* = HRESULT(0x80029C83)

+  TYPE_E_CIRCULARTYPE* = HRESULT(0x80029C84)

+  STG_E_INVALIDFUNCTION* = HRESULT(0x80030001)

+  STG_E_FILENOTFOUND* = HRESULT(0x80030002)

+  STG_E_PATHNOTFOUND* = HRESULT(0x80030003)

+  STG_E_TOOMANYOPENFILES* = HRESULT(0x80030004)

+  STG_E_ACCESSDENIED* = HRESULT(0x80030005)

+  STG_E_INVALIDHANDLE* = HRESULT(0x80030006)

+  STG_E_INSUFFICIENTMEMORY* = HRESULT(0x80030008)

+  STG_E_INVALIDPOINTER* = HRESULT(0x80030009)

+  STG_E_NOMOREFILES* = HRESULT(0x80030012)

+  STG_E_DISKISWRITEPROTECTED* = HRESULT(0x80030013)

+  STG_E_SEEKERROR* = HRESULT(0x80030019)

+  STG_E_WRITEFAULT* = HRESULT(0x8003001D)

+  STG_E_READFAULT* = HRESULT(0x8003001E)

+  STG_E_SHAREVIOLATION* = HRESULT(0x80030020)

+  STG_E_LOCKVIOLATION* = HRESULT(0x80030021)

+  STG_E_FILEALREADYEXISTS* = HRESULT(0x80030050)

+  STG_E_INVALIDPARAMETER* = HRESULT(0x80030057)

+  STG_E_MEDIUMFULL* = HRESULT(0x80030070)

+  STG_E_PROPSETMISMATCHED* = HRESULT(0x800300F0)

+  STG_E_ABNORMALAPIEXIT* = HRESULT(0x800300FA)

+  STG_E_INVALIDHEADER* = HRESULT(0x800300FB)

+  STG_E_INVALIDNAME* = HRESULT(0x800300FC)

+  STG_E_UNKNOWN* = HRESULT(0x800300FD)

+  STG_E_UNIMPLEMENTEDFUNCTION* = HRESULT(0x800300FE)

+  STG_E_INVALIDFLAG* = HRESULT(0x800300FF)

+  STG_E_INUSE* = HRESULT(0x80030100)

+  STG_E_NOTCURRENT* = HRESULT(0x80030101)

+  STG_E_REVERTED* = HRESULT(0x80030102)

+  STG_E_CANTSAVE* = HRESULT(0x80030103)

+  STG_E_OLDFORMAT* = HRESULT(0x80030104)

+  STG_E_OLDDLL* = HRESULT(0x80030105)

+  STG_E_SHAREREQUIRED* = HRESULT(0x80030106)

+  STG_E_NOTFILEBASEDSTORAGE* = HRESULT(0x80030107)

+  STG_E_EXTANTMARSHALLINGS* = HRESULT(0x80030108)

+  STG_E_DOCFILECORRUPT* = HRESULT(0x80030109)

+  STG_E_BADBASEADDRESS* = HRESULT(0x80030110)

+  STG_E_INCOMPLETE* = HRESULT(0x80030201)

+  STG_E_TERMINATED* = HRESULT(0x80030202)

+  STG_S_CONVERTED* = HRESULT(0x00030200)

+  STG_S_BLOCK* = HRESULT(0x00030201)

+  STG_S_RETRYNOW* = HRESULT(0x00030202)

+  STG_S_MONITORING* = HRESULT(0x00030203)

+  RPC_E_CALL_REJECTED* = HRESULT(0x80010001)

+  RPC_E_CALL_CANCELED* = HRESULT(0x80010002)

+  RPC_E_CANTPOST_INSENDCALL* = HRESULT(0x80010003)

+  RPC_E_CANTCALLOUT_INASYNCCALL* = HRESULT(0x80010004)

+  RPC_E_CANTCALLOUT_INEXTERNALCALL* = HRESULT(0x80010005)

+  RPC_E_CONNECTION_TERMINATED* = HRESULT(0x80010006)

+  RPC_E_SERVER_DIED* = HRESULT(0x80010007)

+  RPC_E_CLIENT_DIED* = HRESULT(0x80010008)

+  RPC_E_INVALID_DATAPACKET* = HRESULT(0x80010009)

+  RPC_E_CANTTRANSMIT_CALL* = HRESULT(0x8001000A)

+  RPC_E_CLIENT_CANTMARSHAL_DATA* = HRESULT(0x8001000B)

+  RPC_E_CLIENT_CANTUNMARSHAL_DATA* = HRESULT(0x8001000C)

+  RPC_E_SERVER_CANTMARSHAL_DATA* = HRESULT(0x8001000D)

+  RPC_E_SERVER_CANTUNMARSHAL_DATA* = HRESULT(0x8001000E)

+  RPC_E_INVALID_DATA* = HRESULT(0x8001000F)

+  RPC_E_INVALID_PARAMETER* = HRESULT(0x80010010)

+  RPC_E_CANTCALLOUT_AGAIN* = HRESULT(0x80010011)

+  RPC_E_SERVER_DIED_DNE* = HRESULT(0x80010012)

+  RPC_E_SYS_CALL_FAILED* = HRESULT(0x80010100)

+  RPC_E_OUT_OF_RESOURCES* = HRESULT(0x80010101)

+  RPC_E_ATTEMPTED_MULTITHREAD* = HRESULT(0x80010102)

+  RPC_E_NOT_REGISTERED* = HRESULT(0x80010103)

+  RPC_E_FAULT* = HRESULT(0x80010104)

+  RPC_E_SERVERFAULT* = HRESULT(0x80010105)

+  RPC_E_CHANGED_MODE* = HRESULT(0x80010106)

+  RPC_E_INVALIDMETHOD* = HRESULT(0x80010107)

+  RPC_E_DISCONNECTED* = HRESULT(0x80010108)

+  RPC_E_RETRY* = HRESULT(0x80010109)

+  RPC_E_SERVERCALL_RETRYLATER* = HRESULT(0x8001010A)

+  RPC_E_SERVERCALL_REJECTED* = HRESULT(0x8001010B)

+  RPC_E_INVALID_CALLDATA* = HRESULT(0x8001010C)

+  RPC_E_CANTCALLOUT_ININPUTSYNCCALL* = HRESULT(0x8001010D)

+  RPC_E_WRONG_THREAD* = HRESULT(0x8001010E)

+  RPC_E_THREAD_NOT_INIT* = HRESULT(0x8001010F)

+  RPC_E_VERSION_MISMATCH* = HRESULT(0x80010110)

+  RPC_E_INVALID_HEADER* = HRESULT(0x80010111)

+  RPC_E_INVALID_EXTENSION* = HRESULT(0x80010112)

+  RPC_E_INVALID_IPID* = HRESULT(0x80010113)

+  RPC_E_INVALID_OBJECT* = HRESULT(0x80010114)

+  RPC_S_CALLPENDING* = HRESULT(0x80010115)

+  RPC_S_WAITONTIMER* = HRESULT(0x80010116)

+  RPC_E_CALL_COMPLETE* = HRESULT(0x80010117)

+  RPC_E_UNSECURE_CALL* = HRESULT(0x80010118)

+  RPC_E_TOO_LATE* = HRESULT(0x80010119)

+  RPC_E_NO_GOOD_SECURITY_PACKAGES* = HRESULT(0x8001011A)

+  RPC_E_ACCESS_DENIED* = HRESULT(0x8001011B)

+  RPC_E_REMOTE_DISABLED* = HRESULT(0x8001011C)

+  RPC_E_INVALID_OBJREF* = HRESULT(0x8001011D)

+  RPC_E_UNEXPECTED* = HRESULT(0x8001FFFF)

+  NTE_BAD_UID* = HRESULT(0x80090001)

+  NTE_BAD_HASH* = HRESULT(0x80090002)

+  NTE_BAD_KEY* = HRESULT(0x80090003)

+  NTE_BAD_LEN* = HRESULT(0x80090004)

+  NTE_BAD_DATA* = HRESULT(0x80090005)

+  NTE_BAD_SIGNATURE* = HRESULT(0x80090006)

+  NTE_BAD_VER* = HRESULT(0x80090007)

+  NTE_BAD_ALGID* = HRESULT(0x80090008)

+  NTE_BAD_FLAGS* = HRESULT(0x80090009)

+  NTE_BAD_TYPE* = HRESULT(0x8009000A)

+  NTE_BAD_KEY_STATE* = HRESULT(0x8009000B)

+  NTE_BAD_HASH_STATE* = HRESULT(0x8009000C)

+  NTE_NO_KEY* = HRESULT(0x8009000D)

+  NTE_NO_MEMORY* = HRESULT(0x8009000E)

+  NTE_EXISTS* = HRESULT(0x8009000F)

+  NTE_PERM* = HRESULT(0x80090010)

+  NTE_NOT_FOUND* = HRESULT(0x80090011)

+  NTE_DOUBLE_ENCRYPT* = HRESULT(0x80090012)

+  NTE_BAD_PROVIDER* = HRESULT(0x80090013)

+  NTE_BAD_PROV_TYPE* = HRESULT(0x80090014)

+  NTE_BAD_PUBLIC_KEY* = HRESULT(0x80090015)

+  NTE_BAD_KEYSET* = HRESULT(0x80090016)

+  NTE_PROV_TYPE_NOT_DEF* = HRESULT(0x80090017)

+  NTE_PROV_TYPE_ENTRY_BAD* = HRESULT(0x80090018)

+  NTE_KEYSET_NOT_DEF* = HRESULT(0x80090019)

+  NTE_KEYSET_ENTRY_BAD* = HRESULT(0x8009001A)

+  NTE_PROV_TYPE_NO_MATCH* = HRESULT(0x8009001B)

+  NTE_SIGNATURE_FILE_BAD* = HRESULT(0x8009001C)

+  NTE_PROVIDER_DLL_FAIL* = HRESULT(0x8009001D)

+  NTE_PROV_DLL_NOT_FOUND* = HRESULT(0x8009001E)

+  NTE_BAD_KEYSET_PARAM* = HRESULT(0x8009001F)

+  NTE_FAIL* = HRESULT(0x80090020)

+  NTE_SYS_ERR* = HRESULT(0x80090021)

+  NTE_OP_OK* = HRESULT(0)

+  TRUST_E_PROVIDER_UNKNOWN* = HRESULT(0x800B0001)

+  TRUST_E_ACTION_UNKNOWN* = HRESULT(0x800B0002)

+  TRUST_E_SUBJECT_FORM_UNKNOWN* = HRESULT(0x800B0003)

+  TRUST_E_SUBJECT_NOT_TRUSTED* = HRESULT(0x800B0004)

+  DIGSIG_E_ENCODE* = HRESULT(0x800B0005)

+  DIGSIG_E_DECODE* = HRESULT(0x800B0006)

+  DIGSIG_E_EXTENSIBILITY* = HRESULT(0x800B0007)

+  DIGSIG_E_CRYPTO* = HRESULT(0x800B0008)

+  PERSIST_E_SIZEDEFINITE* = HRESULT(0x800B0009)

+  PERSIST_E_SIZEINDEFINITE* = HRESULT(0x800B000A)

+  PERSIST_E_NOTSELFSIZING* = HRESULT(0x800B000B)

+  TRUST_E_NOSIGNATURE* = HRESULT(0x800B0100)

+  CERT_E_EXPIRED* = HRESULT(0x800B0101)

+  CERT_E_VALIDIYPERIODNESTING* = HRESULT(0x800B0102)

+  CERT_E_ROLE* = HRESULT(0x800B0103)

+  CERT_E_PATHLENCONST* = HRESULT(0x800B0104)

+  CERT_E_CRITICAL* = HRESULT(0x800B0105)

+  CERT_E_PURPOSE* = HRESULT(0x800B0106)

+  CERT_E_ISSUERCHAINING* = HRESULT(0x800B0107)

+  CERT_E_MALFORMED* = HRESULT(0x800B0108)

+  CERT_E_UNTRUSTEDROOT* = HRESULT(0x800B0109)

+  CERT_E_CHAINING* = HRESULT(0x800B010A)

+

+proc UNICODE_NULL*(): WCHAR

+const

+  LF_FACESIZE* = 32

+  LF_FULLFACESIZE* = 64

+  ELF_VENDOR_SIZE* = 4

+  SECURITY_STATIC_TRACKING* = 0

+  SECURITY_DYNAMIC_TRACKING* = 1

+  MAX_DEFAULTCHAR* = 2

+  MAX_LEADBYTES* = 12

+  EXCEPTION_MAXIMUM_PARAMETERS* = 15

+  CCHDEVICENAME* = 32

+  CCHFORMNAME* = 32

+  MENU_TEXT_LEN* = 40

+  MAX_LANA* = 254

+  NCBNAMSZ* = 16

+  NETBIOS_NAME_LEN* = 16

+  OFS_MAXPATHNAME* = 128

+  MAX_TAB_STOPS* = 32

+  ANYSIZE_ARRAY* = 1

+  RAS_MaxCallbackNumber* = 128

+  RAS_MaxDeviceName* = 128

+  RAS_MaxDeviceType* = 16

+  RAS_MaxEntryName* = 256

+  RAS_MaxIpAddress* = 15

+  RAS_MaxIpxAddress* = 21

+  RAS_MaxPhoneNumber* = 128

+  UNLEN* = 256

+  PWLEN* = 256

+  CNLEN* = 15

+  DNLEN* = 15

+  # Unsigned types max

+  MAXDWORD* = 0xFFFFFFFF

+  MAXWORD* = 0x0000FFFF

+  MAXBYTE* = 0x000000FF

+  # Signed types max/min

+  MINCHAR* = 0x00000080

+  MAXCHAR* = 0x0000007F

+  MINSHORT* = 0x00008000

+  MAXSHORT* = 0x00007FFF

+  MINLONG* = 0x80000000

+  MAXLONG* = 0x7FFFFFFF

+  # _llseek

+  FILE_BEGIN* = 0

+  FILE_CURRENT* = 1

+  FILE_END* = 2

+  # _lopen, LZOpenFile, OpenFile

+  OF_READ* = 0

+  OF_READWRITE* = 2

+  OF_WRITE* = 1

+  OF_SHARE_COMPAT* = 0

+  OF_SHARE_DENY_NONE* = 64

+  OF_SHARE_DENY_READ* = 48

+  OF_SHARE_DENY_WRITE* = 32

+  OF_SHARE_EXCLUSIVE* = 16

+  OF_CANCEL* = 2048

+  OF_CREATE* = 4096

+  OF_DELETE* = 512

+  OF_EXIST* = 16384

+  OF_PARSE* = 256

+  OF_PROMPT* = 8192

+  OF_REOPEN* = 32768

+  OF_VERIFY* = 1024

+  # ActivateKeyboardLayout, LoadKeyboardLayout

+  HKL_NEXT* = 1

+  HKL_PREV* = 0

+  KLF_REORDER* = 8

+  KLF_UNLOADPREVIOUS* = 4

+  KLF_ACTIVATE* = 1

+  KLF_NOTELLSHELL* = 128

+  KLF_REPLACELANG* = 16

+  KLF_SUBSTITUTE_OK* = 2

+  # AppendMenu

+  MF_BITMAP* = 0x00000004

+  MF_DISABLED* = 0x00000002

+  MF_ENABLED* = 0

+  MF_GRAYED* = 0x00000001

+  MF_HELP* = 0x00004000

+  MF_MENUBARBREAK* = 0x00000020

+  MF_MENUBREAK* = 0x00000040

+  MF_MOUSESELECT* = 0x00008000

+  MF_OWNERDRAW* = 0x00000100

+  MF_POPUP* = 0x00000010

+  MF_SEPARATOR* = 0x00000800

+  MF_STRING* = 0

+  MF_SYSMENU* = 0x00002000

+  MF_USECHECKBITMAPS* = 0x00000200

+  # Ternary Raster Operations - BitBlt

+  BLACKNESS* = 0x00000042

+  NOTSRCERASE* = 0x001100A6

+  NOTSRCCOPY* = 0x00330008

+  SRCERASE* = 0x00440328

+  DSTINVERT* = 0x00550009

+  PATINVERT* = 0x005A0049

+  SRCINVERT* = 0x00660046

+  SRCAND* = 0x008800C6

+  MERGEPAINT* = 0x00BB0226

+  MERGECOPY* = 0x00C000CA

+  SRCCOPY* = 0x00CC0020

+  SRCPAINT* = 0x00EE0086

+  PATCOPY* = 0x00F00021

+  PATPAINT* = 0x00FB0A09

+  WHITENESS* = 0x00FF0062

+  # Binary Raster Operations

+  R2_BLACK* = 1

+  R2_COPYPEN* = 13

+  R2_MASKNOTPEN* = 3

+  R2_MASKPEN* = 9

+  R2_MASKPENNOT* = 5

+  R2_MERGENOTPEN* = 12

+  R2_MERGEPEN* = 15

+  R2_MERGEPENNOT* = 14

+  R2_NOP* = 11

+  R2_NOT* = 6

+  R2_NOTCOPYPEN* = 4

+  R2_NOTMASKPEN* = 8

+  R2_NOTMERGEPEN* = 2

+  R2_NOTXORPEN* = 10

+  R2_WHITE* = 16

+  R2_XORPEN* = 7

+  # BroadcastSystemMessage

+  BSF_FLUSHDISK* = 4

+  BSF_FORCEIFHUNG* = 32

+  BSF_IGNORECURRENTTASK* = 2

+  BSF_NOHANG* = 8

+  BSF_POSTMESSAGE* = 16

+  BSF_QUERY* = 1

+  BSM_ALLCOMPONENTS* = 0

+  BSM_APPLICATIONS* = 8

+  BSM_INSTALLABLEDRIVERS* = 4

+  BSM_NETDRIVER* = 2

+  BSM_VXDS* = 1

+  BROADCAST_QUERY_DENY* = 1112363332

+                                     # CallNamedPipe

+  NMPWAIT_NOWAIT* = 1

+  NMPWAIT_WAIT_FOREVER* = -1

+  NMPWAIT_USE_DEFAULT_WAIT* = 0

+  # CascadeWindows, TileWindows

+  MDITILE_SKIPDISABLED* = 2

+  MDITILE_HORIZONTAL* = 1

+  MDITILE_VERTICAL* = 0

+  # CBTProc

+  HCBT_ACTIVATE* = 5

+  HCBT_CLICKSKIPPED* = 6

+  HCBT_CREATEWND* = 3

+  HCBT_DESTROYWND* = 4

+  HCBT_KEYSKIPPED* = 7

+  HCBT_MINMAX* = 1

+  HCBT_MOVESIZE* = 0

+  HCBT_QS* = 2

+  HCBT_SETFOCUS* = 9

+  HCBT_SYSCOMMAND* = 8

+

+  CDS_UPDATEREGISTRY* = 1

+  CDS_TEST* = 2

+  CDS_FULLSCREEN* = 4

+  CDS_GLOBAL* = 8

+  CDS_SET_PRIMARY* = 0x00000010

+  CDS_RESET* = 0x40000000

+  CDS_SETRECT* = 0x20000000

+  CDS_NORESET* = 0x10000000

+  DISP_CHANGE_SUCCESSFUL* = 0

+  DISP_CHANGE_RESTART* = 1

+  DISP_CHANGE_BADFLAGS* = -4

+  DISP_CHANGE_FAILED* = -1

+  DISP_CHANGE_BADMODE* = -2

+  DISP_CHANGE_NOTUPDATED* = -3

+  # ChangeServiceConfig

+  SERVICE_NO_CHANGE* = -1

+  SERVICE_WIN32_OWN_PROCESS* = 16

+  SERVICE_WIN32_SHARE_PROCESS* = 32

+  SERVICE_KERNEL_DRIVER* = 1

+  SERVICE_FILE_SYSTEM_DRIVER* = 2

+  SERVICE_INTERACTIVE_PROCESS* = 256

+  SERVICE_BOOT_START* = 0

+  SERVICE_SYSTEM_START* = 1

+  SERVICE_AUTO_START* = 2

+  SERVICE_DEMAND_START* = 3

+  SERVICE_DISABLED* = 4

+  SERVICE_STOPPED* = 1

+  SERVICE_START_PENDING* = 2

+  SERVICE_STOP_PENDING* = 3

+  SERVICE_RUNNING* = 4

+  SERVICE_CONTINUE_PENDING* = 5

+  SERVICE_PAUSE_PENDING* = 6

+  SERVICE_PAUSED* = 7

+  SERVICE_ACCEPT_STOP* = 1

+  SERVICE_ACCEPT_PAUSE_CONTINUE* = 2

+  SERVICE_ACCEPT_SHUTDOWN* = 4

+  # CheckDlgButton

+  BST_CHECKED* = 1

+  BST_INDETERMINATE* = 2

+  BST_UNCHECKED* = 0

+  BST_FOCUS* = 8

+  BST_PUSHED* = 4

+  # CheckMenuItem, HiliteMenuItem

+  MF_BYCOMMAND* = 0

+  MF_BYPOSITION* = 0x00000400

+  MF_CHECKED* = 0x00000008

+  MF_UNCHECKED* = 0

+  MF_HILITE* = 0x00000080

+  MF_UNHILITE* = 0

+  # ChildWindowFromPointEx

+  CWP_ALL* = 0

+  CWP_SKIPINVISIBLE* = 1

+  CWP_SKIPDISABLED* = 2

+  CWP_SKIPTRANSPARENT* = 4

+  # ClearCommError

+  CE_BREAK* = 16

+  CE_DNS* = 2048

+  CE_FRAME* = 8

+  CE_IOE* = 1024

+  CE_MODE* = 32768

+  CE_OOP* = 4096

+  CE_OVERRUN* = 2

+  CE_PTO* = 512

+  CE_RXOVER* = 1

+  CE_RXPARITY* = 4

+  CE_TXFULL* = 256

+                              # CombineRgn

+  RGN_AND* = 1

+  RGN_COPY* = 5

+  RGN_DIFF* = 4

+  RGN_OR* = 2

+  RGN_XOR* = 3

+  NULLREGION* = 1

+  SIMPLEREGION* = 2

+  COMPLEXREGION* = 3

+  ERROR* = 0

+  # CommonDlgExtendedError

+  CDERR_DIALOGFAILURE* = 0x0000FFFF

+  CDERR_FINDRESFAILURE* = 6

+  CDERR_INITIALIZATION* = 2

+  CDERR_LOADRESFAILURE* = 7

+  CDERR_LOADSTRFAILURE* = 5

+  CDERR_LOCKRESFAILURE* = 8

+  CDERR_MEMALLOCFAILURE* = 9

+  CDERR_MEMLOCKFAILURE* = 10

+  CDERR_NOHINSTANCE* = 4

+  CDERR_NOHOOK* = 11

+  CDERR_NOTEMPLATE* = 3

+  CDERR_REGISTERMSGFAIL* = 12

+  CDERR_STRUCTSIZE* = 1

+  PDERR_CREATEICFAILURE* = 0x00001000 + 10

+  PDERR_DEFAULTDIFFERENT* = 0x00001000 + 12

+  PDERR_DNDMMISMATCH* = 0x00001000 + 9

+  PDERR_GETDEVMODEFAIL* = 0x00001000 + 5

+  PDERR_INITFAILURE* = 0x00001000 + 6

+  PDERR_LOADDRVFAILURE* = 0x00001000 + 4

+  PDERR_NODEFAULTPRN* = 0x00001000 + 8

+  PDERR_NODEVICES* = 0x00001000 + 7

+  PDERR_PARSEFAILURE* = 0x00001000 + 2

+  PDERR_PRINTERNOTFOUND* = 0x00001000 + 11

+  PDERR_RETDEFFAILURE* = 0x00001000 + 3

+  PDERR_SETUPFAILURE* = 0x00001000 + 1

+  CFERR_MAXLESSTHANMIN* = 0x00002000 + 2

+  CFERR_NOFONTS* = 0x00002000 + 1

+  FNERR_BUFFERTOOSMALL* = 0x00003000 + 3

+  FNERR_INVALIDFILENAME* = 0x00003000 + 2

+  FNERR_SUBCLASSFAILURE* = 0x00003000 + 1

+  FRERR_BUFFERLENGTHZERO* = 0x00004000 + 1

+  # CompareString, LCMapString

+  LOCALE_SYSTEM_DEFAULT* = 0x00000800

+  LOCALE_USER_DEFAULT* = 0x00000400

+  NORM_IGNORECASE* = 1

+  NORM_IGNOREKANATYPE* = 65536

+  NORM_IGNORENONSPACE* = 2

+  NORM_IGNORESYMBOLS* = 4

+  NORM_IGNOREWIDTH* = 131072

+  SORT_STRINGSORT* = 4096

+  LCMAP_BYTEREV* = 2048

+  LCMAP_FULLWIDTH* = 8388608

+  LCMAP_HALFWIDTH* = 4194304

+  LCMAP_HIRAGANA* = 1048576

+  LCMAP_KATAKANA* = 2097152

+  LCMAP_LOWERCASE* = 256

+  LCMAP_SORTKEY* = 1024

+  LCMAP_UPPERCASE* = 512

+  # ContinueDebugEvent

+  DBG_CONTINUE* = 0x00010002

+  DBG_CONTROL_BREAK* = 0x40010008

+  DBG_CONTROL_C* = 0x40010005

+  DBG_EXCEPTION_NOT_HANDLED* = 0x80010001

+  DBG_TERMINATE_THREAD* = 0x40010003

+  DBG_TERMINATE_PROCESS* = 0x40010004

+  # ControlService

+  SERVICE_CONTROL_STOP* = 1

+  SERVICE_CONTROL_PAUSE* = 2

+  SERVICE_CONTROL_CONTINUE* = 3

+  SERVICE_CONTROL_INTERROGATE* = 4

+  SERVICE_CONTROL_SHUTDOWN* = 5

+  # CopyImage, LoadImage

+  IMAGE_BITMAP* = 0

+  IMAGE_CURSOR* = 2

+  IMAGE_ENHMETAFILE* = 1

+  IMAGE_ICON* = 1

+  LR_MONOCHROME* = 1

+  LR_COLOR* = 2

+  LR_COPYRETURNORG* = 4

+  LR_COPYDELETEORG* = 8

+  LR_DEFAULTSIZE* = 64

+  LR_CREATEDIBSECTION* = 8192

+  LR_COPYFROMRESOURCE* = 0x00004000

+  LR_SHARED* = 0x00008000

+  # CreateDesktop

+  DF_ALLOWOTHERACCOUNTHOOK* = 0x00000001

+  DESKTOP_CREATEMENU* = 0x00000004

+  DESKTOP_CREATEWINDOW* = 0x00000002

+  DESKTOP_ENUMERATE* = 0x00000040

+  DESKTOP_HOOKCONTROL* = 0x00000008

+  DESKTOP_JOURNALPLAYBACK* = 0x00000020

+  DESKTOP_JOURNALRECORD* = 0x00000010

+  DESKTOP_READOBJECTS* = 0x00000001

+  DESKTOP_SWITCHDESKTOP* = 0x00000100

+  DESKTOP_WRITEOBJECTS* = 0x00000080

+  WSF_VISIBLE* = 0x00000001

+  # CreateDIBitmap

+  CBM_INIT* = 0x00000004

+  DIB_PAL_COLORS* = 1

+  DIB_RGB_COLORS* = 0

+  # CreateFile, GetFileAttributes, SetFileAttributes

+  GENERIC_READ* = 0x80000000

+  GENERIC_WRITE* = 0x40000000

+  FILE_READ_DATA* = 0x00000001 # file & pipe

+  FILE_LIST_DIRECTORY* = 0x00000001 # directory

+  FILE_WRITE_DATA* = 0x00000002 # file & pipe

+  FILE_ADD_FILE* = 0x00000002 # directory

+  FILE_APPEND_DATA* = 0x00000004 # file

+  FILE_ADD_SUBDIRECTORY* = 0x00000004 # directory

+  FILE_CREATE_PIPE_INSTANCE* = 0x00000004 # named pipe

+  FILE_READ_EA* = 0x00000008 # file & directory

+  FILE_READ_PROPERTIES* = FILE_READ_EA

+  FILE_WRITE_EA* = 0x00000010 # file & directory

+  FILE_WRITE_PROPERTIES* = FILE_WRITE_EA

+  FILE_EXECUTE* = 0x00000020 # file

+  FILE_TRAVERSE* = 0x00000020 # directory

+  FILE_DELETE_CHILD* = 0x00000040 # directory

+  FILE_READ_ATTRIBUTES* = 0x00000080 # all

+  FILE_WRITE_ATTRIBUTES* = 0x00000100 # all

+  FILE_SHARE_DELETE* = 4

+  FILE_SHARE_READ* = 1

+  FILE_SHARE_WRITE* = 2

+  CONSOLE_TEXTMODE_BUFFER* = 1

+  CREATE_NEW* = 1

+  CREATE_ALWAYS* = 2

+  OPEN_EXISTING* = 3

+  OPEN_ALWAYS* = 4

+  TRUNCATE_EXISTING* = 5

+  FILE_ATTRIBUTE_ARCHIVE* = 32

+  FILE_ATTRIBUTE_COMPRESSED* = 2048

+  FILE_ATTRIBUTE_NORMAL* = 128

+  FILE_ATTRIBUTE_DIRECTORY* = 16

+  FILE_ATTRIBUTE_HIDDEN* = 2

+  FILE_ATTRIBUTE_READONLY* = 1

+  FILE_ATTRIBUTE_SYSTEM* = 4

+  FILE_ATTRIBUTE_TEMPORARY* = 256

+  FILE_FLAG_WRITE_THROUGH* = 0x80000000

+  FILE_FLAG_OVERLAPPED* = 1073741824

+  FILE_FLAG_NO_BUFFERING* = 536870912

+  FILE_FLAG_RANDOM_ACCESS* = 268435456

+  FILE_FLAG_SEQUENTIAL_SCAN* = 134217728

+  FILE_FLAG_DELETE_ON_CLOSE* = 67108864

+  FILE_FLAG_BACKUP_SEMANTICS* = 33554432

+  FILE_FLAG_POSIX_SEMANTICS* = 16777216

+  cSECURITY_ANONYMOUS* = 0

+  cSECURITY_IDENTIFICATION* = 65536

+  cSECURITY_IMPERSONATION* = 131072

+  cSECURITY_DELEGATION* = 196608

+  cSECURITY_CONTEXT_TRACKING* = 262144

+  cSECURITY_EFFECTIVE_ONLY* = 524288

+  cSECURITY_SQOS_PRESENT* = 1048576

+  # CreateFileMapping, VirtualAlloc, VirtualFree, VirtualProtect

+  SEC_COMMIT* = 134217728

+  SEC_IMAGE* = 16777216

+  SEC_NOCACHE* = 268435456

+  SEC_RESERVE* = 67108864

+  PAGE_READONLY* = 2

+  PAGE_READWRITE* = 4

+  PAGE_WRITECOPY* = 8

+  PAGE_EXECUTE* = 16

+  PAGE_EXECUTE_READ* = 32

+  PAGE_EXECUTE_READWRITE* = 64

+  PAGE_EXECUTE_WRITECOPY* = 128

+  PAGE_GUARD* = 256

+  PAGE_NOACCESS* = 1

+  PAGE_NOCACHE* = 512

+  MEM_COMMIT* = 4096

+  MEM_FREE* = 65536

+  MEM_RESERVE* = 8192

+  MEM_IMAGE* = 16777216

+  MEM_MAPPED* = 262144

+  MEM_PRIVATE* = 131072

+  MEM_DECOMMIT* = 16384

+  MEM_RELEASE* = 32768

+  MEM_TOP_DOWN* = 1048576

+  EXCEPTION_GUARD_PAGE* = 0x80000001

+  SECTION_EXTEND_SIZE* = 0x00000010

+  SECTION_MAP_READ* = 0x00000004

+  SECTION_MAP_WRITE* = 0x00000002

+  SECTION_QUERY* = 0x00000001

+  SECTION_ALL_ACCESS* = 0x000F001F

+  # CreateFont

+  FW_DONTCARE* = 0

+  FW_THIN* = 100

+  FW_EXTRALIGHT* = 200

+  FW_LIGHT* = 300

+  FW_NORMAL* = 400

+  FW_REGULAR* = FW_NORMAL

+  FW_MEDIUM* = 500

+  FW_SEMIBOLD* = 600

+  FW_BOLD* = 700

+  FW_EXTRABOLD* = 800

+  FW_HEAVY* = 900

+  ANSI_CHARSET* = 0

+  DEFAULT_CHARSET* = 1

+  SYMBOL_CHARSET* = 2

+  SHIFTJIS_CHARSET* = 128

+  HANGEUL_CHARSET* = 129

+  GB2312_CHARSET* = 134

+  CHINESEBIG5_CHARSET* = 136

+  GREEK_CHARSET* = 161

+  TURKISH_CHARSET* = 162

+  HEBREW_CHARSET* = 177

+  ARABIC_CHARSET* = 178

+  BALTIC_CHARSET* = 186

+  RUSSIAN_CHARSET* = 204

+  THAI_CHARSET* = 222

+  EASTEUROPE_CHARSET* = 238

+  OEM_CHARSET* = 255

+  OUT_DEFAULT_PRECIS* = 0

+  OUT_STRING_PRECIS* = 1

+  OUT_CHARACTER_PRECIS* = 2

+  OUT_STROKE_PRECIS* = 3

+  OUT_TT_PRECIS* = 4

+  OUT_DEVICE_PRECIS* = 5

+  OUT_RASTER_PRECIS* = 6

+  OUT_TT_ONLY_PRECIS* = 7

+  OUT_OUTLINE_PRECIS* = 8

+  CLIP_DEFAULT_PRECIS* = 0

+  CLIP_CHARACTER_PRECIS* = 1

+  CLIP_STROKE_PRECIS* = 2

+  CLIP_MASK* = 15

+  CLIP_LH_ANGLES* = 16

+  CLIP_TT_ALWAYS* = 32

+  CLIP_EMBEDDED* = 128

+  DEFAULT_QUALITY* = 0

+  DRAFT_QUALITY* = 1

+  PROOF_QUALITY* = 2

+  NONANTIALIASED_QUALITY* = 3

+  ANTIALIASED_QUALITY* = 4

+  DEFAULT_PITCH* = 0

+  FIXED_PITCH* = 1

+  VARIABLE_PITCH* = 2

+  MONO_FONT* = 8

+  FF_DECORATIVE* = 80

+  FF_DONTCARE* = 0

+  FF_MODERN* = 48

+  FF_ROMAN* = 16

+  FF_SCRIPT* = 64

+  FF_SWISS* = 32

+  # CreateHatchBrush

+  HS_BDIAGONAL* = 3

+  HS_CROSS* = 4

+  HS_DIAGCROSS* = 5

+  HS_FDIAGONAL* = 2

+  HS_HORIZONTAL* = 0

+  HS_VERTICAL* = 1

+  # CreateIconFromResourceEx

+  LR_DEFAULTCOLOR* = 0

+  LR_LOADREALSIZE* = 128

+                              # CreateMailslot, GetMailslotInfo

+  MAILSLOT_WAIT_FOREVER* = 0xFFFFFFFF

+  MAILSLOT_NO_MESSAGE* = 0xFFFFFFFF

+  # CreateMappedBitmap

+  CMB_MASKED* = 2

+  # CreateNamedPipe

+  PIPE_ACCESS_DUPLEX* = 3

+  PIPE_ACCESS_INBOUND* = 1

+  PIPE_ACCESS_OUTBOUND* = 2

+  WRITE_DAC* = 0x00040000

+  WRITE_OWNER* = 0x00080000

+  ACCESS_SYSTEM_SECURITY* = 0x01000000

+  PIPE_TYPE_BYTE* = 0

+  PIPE_TYPE_MESSAGE* = 4

+  PIPE_READMODE_BYTE* = 0

+  PIPE_READMODE_MESSAGE* = 2

+  PIPE_WAIT* = 0

+  PIPE_NOWAIT* = 1

+  # CreatePen, ExtCreatePen

+  PS_GEOMETRIC* = 65536

+  PS_COSMETIC* = 0

+  PS_ALTERNATE* = 8

+  PS_SOLID* = 0

+  PS_DASH* = 1

+  PS_DOT* = 2

+  PS_DASHDOT* = 3

+  PS_DASHDOTDOT* = 4

+  PS_NULL* = 5

+  PS_USERSTYLE* = 7

+  PS_INSIDEFRAME* = 6

+  PS_ENDCAP_ROUND* = 0

+  PS_ENDCAP_SQUARE* = 256

+  PS_ENDCAP_FLAT* = 512

+  PS_JOIN_BEVEL* = 4096

+  PS_JOIN_MITER* = 8192

+  PS_JOIN_ROUND* = 0

+  PS_STYLE_MASK* = 15

+  PS_ENDCAP_MASK* = 3840

+  PS_TYPE_MASK* = 983040

+  # CreatePolygonRgn

+  ALTERNATE* = 1

+  WINDING* = 2

+  # CreateProcess

+  CREATE_DEFAULT_ERROR_MODE* = 67108864

+  CREATE_NEW_CONSOLE* = 16

+  CREATE_NEW_PROCESS_GROUP* = 512

+  CREATE_SEPARATE_WOW_VDM* = 2048

+  CREATE_SUSPENDED* = 4

+  CREATE_UNICODE_ENVIRONMENT* = 1024

+  DEBUG_PROCESS* = 1

+  DEBUG_ONLY_THIS_PROCESS* = 2

+  DETACHED_PROCESS* = 8

+  HIGH_PRIORITY_CLASS* = 128

+  IDLE_PRIORITY_CLASS* = 64

+  NORMAL_PRIORITY_CLASS* = 32

+  REALTIME_PRIORITY_CLASS* = 256

+  # CreateService

+  SERVICE_ALL_ACCESS* = 0x000F01FF

+  SERVICE_CHANGE_CONFIG* = 2

+  SERVICE_ENUMERATE_DEPENDENTS* = 8

+  SERVICE_INTERROGATE* = 128

+  SERVICE_PAUSE_CONTINUE* = 64

+  SERVICE_QUERY_CONFIG* = 1

+  SERVICE_QUERY_STATUS* = 4

+  SERVICE_START* = 16

+  SERVICE_STOP* = 32

+  SERVICE_USER_DEFINED_CONTROL* = 256

+  SERVICE_DELETE* = 0x00010000

+  SERVICE_READ_CONTROL* = 0x00020000

+  SERVICE_GENERIC_EXECUTE* = 0x20000000

+  SERVICE_ERROR_IGNORE* = 0

+  SERVICE_ERROR_NORMAL* = 1

+  SERVICE_ERROR_SEVERE* = 2

+  SERVICE_ERROR_CRITICAL* = 3

+  # CreateTapePartition, WriteTapemark

+  TAPE_FIXED_PARTITIONS* = 0

+  TAPE_INITIATOR_PARTITIONS* = 0x00000002

+  TAPE_SELECT_PARTITIONS* = 0x00000001

+  TAPE_FILEMARKS* = 0x00000001

+  TAPE_LONG_FILEMARKS* = 0x00000003

+  TAPE_SETMARKS* = 0

+  TAPE_SHORT_FILEMARKS* = 0x00000002

+  # CreateWindow

+  CW_USEDEFAULT* = int32(0x80000000)

+  WS_BORDER* = 0x00800000

+  WS_CAPTION* = 0x00C00000

+  WS_CHILD* = 0x40000000

+  WS_CHILDWINDOW* = 0x40000000

+  WS_CLIPCHILDREN* = 0x02000000

+  WS_CLIPSIBLINGS* = 0x04000000

+  WS_DISABLED* = 0x08000000

+  WS_DLGFRAME* = 0x00400000

+  WS_GROUP* = 0x00020000

+  WS_HSCROLL* = 0x00100000

+  WS_ICONIC* = 0x20000000

+  WS_MAXIMIZE* = 0x01000000

+  WS_MAXIMIZEBOX* = 0x00010000

+  WS_MINIMIZE* = 0x20000000

+  WS_MINIMIZEBOX* = 0x00020000

+  WS_OVERLAPPED* = 0

+  WS_OVERLAPPEDWINDOW* = 0x00CF0000

+  WS_POPUP* = LONG(0x80000000)

+  WS_POPUPWINDOW* = LONG(0x80880000)

+  WS_SIZEBOX* = 0x00040000

+  WS_SYSMENU* = 0x00080000

+  WS_TABSTOP* = 0x00010000

+  WS_THICKFRAME* = 0x00040000

+

+  WS_TILED* = 0

+  WS_TILEDWINDOW* = 0x00CF0000

+  WS_VISIBLE* = 0x10000000

+  WS_VSCROLL* = 0x00200000

+  MDIS_ALLCHILDSTYLES* = 0x00000001

+  BS_3STATE* = 0x00000005

+  BS_AUTO3STATE* = 0x00000006

+  BS_AUTOCHECKBOX* = 0x00000003

+  BS_AUTORADIOBUTTON* = 0x00000009

+  BS_BITMAP* = 0x00000080

+  BS_BOTTOM* = 0x00000800

+  BS_CENTER* = 0x00000300

+  BS_CHECKBOX* = 0x00000002

+  BS_DEFPUSHBUTTON* = 0x00000001

+  BS_GROUPBOX* = 0x00000007

+  BS_ICON* = 0x00000040

+  BS_LEFT* = 0x00000100

+  BS_LEFTTEXT* = 0x00000020

+  BS_MULTILINE* = 0x00002000

+  BS_NOTIFY* = 0x00004000

+  BS_OWNERDRAW* = 0x0000000B

+  BS_PUSHBUTTON* = 0

+  BS_PUSHLIKE* = 0x00001000

+  BS_RADIOBUTTON* = 0x00000004

+  BS_RIGHT* = 0x00000200

+  BS_RIGHTBUTTON* = 0x00000020

+  BS_TEXT* = 0

+  BS_TOP* = 0x00000400

+  BS_USERBUTTON* = 0x00000008

+  BS_VCENTER* = 0x00000C00

+  BS_FLAT* = 0x00008000

+  CBS_AUTOHSCROLL* = 0x00000040

+  CBS_DISABLENOSCROLL* = 0x00000800

+  CBS_DROPDOWN* = 0x00000002

+  CBS_DROPDOWNLIST* = 0x00000003

+  CBS_HASSTRINGS* = 0x00000200

+  CBS_LOWERCASE* = 0x00004000

+  CBS_NOINTEGRALHEIGHT* = 0x00000400

+  CBS_OEMCONVERT* = 0x00000080

+  CBS_OWNERDRAWFIXED* = 0x00000010

+  CBS_OWNERDRAWVARIABLE* = 0x00000020

+  CBS_SIMPLE* = 0x00000001

+  CBS_SORT* = 0x00000100

+  CBS_UPPERCASE* = 0x00002000

+  ES_AUTOHSCROLL* = 0x00000080

+  ES_AUTOVSCROLL* = 0x00000040

+  ES_CENTER* = 0x00000001

+  ES_LEFT* = 0

+  ES_LOWERCASE* = 0x00000010

+  ES_MULTILINE* = 0x00000004

+  ES_NOHIDESEL* = 0x00000100

+  ES_NUMBER* = 0x00002000

+  ES_OEMCONVERT* = 0x00000400

+  ES_PASSWORD* = 0x00000020

+  ES_READONLY* = 0x00000800

+  ES_RIGHT* = 0x00000002

+  ES_UPPERCASE* = 0x00000008

+  ES_WANTRETURN* = 0x00001000

+  LBS_DISABLENOSCROLL* = 0x00001000

+  LBS_EXTENDEDSEL* = 0x00000800

+  LBS_HASSTRINGS* = 0x00000040

+  LBS_MULTICOLUMN* = 0x00000200

+  LBS_MULTIPLESEL* = 0x00000008

+  LBS_NODATA* = 0x00002000

+  LBS_NOINTEGRALHEIGHT* = 0x00000100

+  LBS_NOREDRAW* = 0x00000004

+  LBS_NOSEL* = 0x00004000

+  LBS_NOTIFY* = 0x00000001

+  LBS_OWNERDRAWFIXED* = 0x00000010

+  LBS_OWNERDRAWVARIABLE* = 0x00000020

+  LBS_SORT* = 0x00000002

+  LBS_STANDARD* = 0x00A00003

+  LBS_USETABSTOPS* = 0x00000080

+  LBS_WANTKEYBOARDINPUT* = 0x00000400

+  SBS_BOTTOMALIGN* = 0x00000004

+  SBS_HORZ* = 0

+  SBS_LEFTALIGN* = 0x00000002

+  SBS_RIGHTALIGN* = 0x00000004

+  SBS_SIZEBOX* = 0x00000008

+  SBS_SIZEBOXBOTTOMRIGHTALIGN* = 0x00000004

+  SBS_SIZEBOXTOPLEFTALIGN* = 0x00000002

+  SBS_SIZEGRIP* = 0x00000010

+  SBS_TOPALIGN* = 0x00000002

+  SBS_VERT* = 0x00000001

+  SS_BITMAP* = 0x0000000E

+  SS_BLACKFRAME* = 0x00000007

+  SS_BLACKRECT* = 0x00000004

+  SS_CENTER* = 0x00000001

+  SS_CENTERIMAGE* = 0x00000200

+  SS_ENHMETAFILE* = 0x0000000F

+  SS_ETCHEDFRAME* = 0x00000012

+  SS_ETCHEDHORZ* = 0x00000010

+  SS_ETCHEDVERT* = 0x00000011

+  SS_GRAYFRAME* = 0x00000008

+  SS_GRAYRECT* = 0x00000005

+  SS_ICON* = 0x00000003

+  SS_LEFT* = 0

+  SS_LEFTNOWORDWRAP* = 0x0000000C

+  SS_NOPREFIX* = 0x00000080

+  SS_NOTIFY* = 0x00000100

+  SS_OWNERDRAW* = 0x0000000D

+  SS_REALSIZEIMAGE* = 0x00000800

+  SS_RIGHT* = 0x00000002

+  SS_RIGHTJUST* = 0x00000400

+  SS_SIMPLE* = 0x0000000B

+  SS_SUNKEN* = 0x00001000

+  SS_USERITEM* = 0x0000000A

+  SS_WHITEFRAME* = 0x00000009

+  SS_WHITERECT* = 0x00000006

+  DS_3DLOOK* = 0x00000004

+  DS_ABSALIGN* = 0x00000001

+  DS_CENTER* = 0x00000800

+  DS_CENTERMOUSE* = 0x00001000

+  DS_CONTEXTHELP* = 0x00002000

+  DS_CONTROL* = 0x00000400

+  DS_FIXEDSYS* = 0x00000008

+  DS_LOCALEDIT* = 0x00000020

+  DS_MODALFRAME* = 0x00000080

+  DS_NOFAILCREATE* = 0x00000010

+  DS_NOIDLEMSG* = 0x00000100

+  DS_SETFONT* = 0x00000040

+  DS_SETFOREGROUND* = 0x00000200

+  DS_SYSMODAL* = 0x00000002

+  # CreateWindowEx

+  WS_EX_ACCEPTFILES* = 0x00000010

+  WS_EX_APPWINDOW* = 0x00040000

+  WS_EX_CLIENTEDGE* = 0x00000200

+  WS_EX_CONTEXTHELP* = 0x00000400

+  WS_EX_CONTROLPARENT* = 0x00010000

+  WS_EX_DLGMODALFRAME* = 0x00000001

+  WS_EX_LEFT* = 0

+  WS_EX_LEFTSCROLLBAR* = 0x00004000

+  WS_EX_LTRREADING* = 0

+  WS_EX_MDICHILD* = 0x00000040

+  WS_EX_NOPARENTNOTIFY* = 0x00000004

+  WS_EX_OVERLAPPEDWINDOW* = 0x00000300

+  WS_EX_PALETTEWINDOW* = 0x00000188

+  WS_EX_RIGHT* = 0x00001000

+  WS_EX_RIGHTSCROLLBAR* = 0

+  WS_EX_RTLREADING* = 0x00002000

+  WS_EX_STATICEDGE* = 0x00020000

+  WS_EX_TOOLWINDOW* = 0x00000080

+  WS_EX_TOPMOST* = 0x00000008

+  WS_EX_TRANSPARENT* = 0x00000020

+  WS_EX_WINDOWEDGE* = 0x00000100

+  # CreateWindowStation

+  WINSTA_ACCESSCLIPBOARD* = 0x00000004

+  WINSTA_ACCESSGLOBALATOMS* = 0x00000020

+  WINSTA_CREATEDESKTOP* = 0x00000008

+  WINSTA_ENUMDESKTOPS* = 0x00000001

+  WINSTA_ENUMERATE* = 0x00000100

+  WINSTA_EXITWINDOWS* = 0x00000040

+  WINSTA_READATTRIBUTES* = 0x00000002

+  WINSTA_READSCREEN* = 0x00000200

+  WINSTA_WRITEATTRIBUTES* = 0x00000010

+  # DdeCallback

+  # DdeClientTransaction

+  # DdeEnableCallback

+  # DdeGetLastError

+  # DdeInitialize

+  # DdeNameService

+  # DebugProc

+  WH_CALLWNDPROC* = 4

+  WH_CALLWNDPROCRET* = 12

+  WH_CBT* = 5

+  WH_DEBUG* = 9

+  WH_GETMESSAGE* = 3

+  WH_JOURNALPLAYBACK* = 1

+  WH_JOURNALRECORD* = 0

+  WH_KEYBOARD* = 2

+  WH_MOUSE* = 7

+  WH_MSGFILTER* = -1

+  WH_SHELL* = 10

+  WH_SYSMSGFILTER* = 6

+  WH_FOREGROUNDIDLE* = 11

+  # DefineDosDevice

+  DDD_RAW_TARGET_PATH* = 1

+  DDD_REMOVE_DEFINITION* = 2

+  DDD_EXACT_MATCH_ON_REMOVE* = 4

+  # DeviceCapbilities

+  DCTT_BITMAP* = 0x00000001

+  DCTT_DOWNLOAD* = 0x00000002

+  DCTT_SUBDEV* = 0x00000004

+                              # DlgDirList

+  DDL_ARCHIVE* = 32

+  DDL_DIRECTORY* = 16

+  DDL_DRIVES* = 16384

+  DDL_EXCLUSIVE* = 32768

+  DDL_HIDDEN* = 2

+  DDL_READONLY* = 1

+  DDL_READWRITE* = 0

+  DDL_SYSTEM* = 4

+  DDL_POSTMSGS* = 8192

+  # DllEntryPoint

+  DLL_PROCESS_ATTACH* = 1

+  DLL_THREAD_ATTACH* = 2

+  DLL_PROCESS_DETACH* = 0

+  DLL_THREAD_DETACH* = 3

+  # DrawAnimatedRects

+  IDANI_OPEN* = 1

+  IDANI_CLOSE* = 2

+  # DrawCaption

+  DC_ACTIVE* = 1

+  DC_SMALLCAP* = 2

+  # DrawEdge

+  BDR_RAISEDINNER* = 4

+  BDR_SUNKENINNER* = 8

+  BDR_RAISEDOUTER* = 1

+  BDR_SUNKENOUTER* = 2

+  BDR_OUTER* = BDR_RAISEDOUTER or BDR_SUNKENOUTER

+  BDR_INNER* = BDR_RAISEDINNER or BDR_SUNKENINNER

+  BDR_RAISED* = BDR_RAISEDOUTER or BDR_RAISEDINNER

+  BDR_SUNKEN* = BDR_SUNKENOUTER or BDR_SUNKENINNER

+  EDGE_BUMP* = 9

+  EDGE_ETCHED* = 6

+  EDGE_RAISED* = 5

+  EDGE_SUNKEN* = 10

+  BF_ADJUST* = 8192

+  BF_BOTTOM* = 8

+  BF_BOTTOMLEFT* = 9

+  BF_BOTTOMRIGHT* = 12

+  BF_DIAGONAL* = 16

+  BF_DIAGONAL_ENDBOTTOMLEFT* = 25

+  BF_DIAGONAL_ENDBOTTOMRIGHT* = 28

+  BF_DIAGONAL_ENDTOPLEFT* = 19

+  BF_DIAGONAL_ENDTOPRIGHT* = 22

+  BF_FLAT* = 16384

+  BF_LEFT* = 1

+  BF_MIDDLE* = 2048

+  BF_MONO* = 32768

+  BF_RECT* = 15

+  BF_RIGHT* = 4

+  BF_SOFT* = 4096

+  BF_TOP* = 2

+  BF_TOPLEFT* = 3

+  BF_TOPRIGHT* = 6

+  # DrawFrameControl

+  DFC_BUTTON* = 4

+  DFC_CAPTION* = 1

+  DFC_MENU* = 2

+  DFC_SCROLL* = 3

+  DFCS_BUTTON3STATE* = 8

+  DFCS_BUTTONCHECK* = 0

+  DFCS_BUTTONPUSH* = 16

+  DFCS_BUTTONRADIO* = 4

+  DFCS_BUTTONRADIOIMAGE* = 1

+  DFCS_BUTTONRADIOMASK* = 2

+  DFCS_CAPTIONCLOSE* = 0

+  DFCS_CAPTIONHELP* = 4

+  DFCS_CAPTIONMAX* = 2

+  DFCS_CAPTIONMIN* = 1

+  DFCS_CAPTIONRESTORE* = 3

+  DFCS_MENUARROW* = 0

+  DFCS_MENUBULLET* = 2

+  DFCS_MENUCHECK* = 1

+  DFCS_SCROLLCOMBOBOX* = 5

+  DFCS_SCROLLDOWN* = 1

+  DFCS_SCROLLLEFT* = 2

+  DFCS_SCROLLRIGHT* = 3

+  DFCS_SCROLLSIZEGRIP* = 8

+  DFCS_SCROLLUP* = 0

+  DFCS_ADJUSTRECT* = 8192

+  DFCS_CHECKED* = 1024

+  DFCS_FLAT* = 16384

+  DFCS_INACTIVE* = 256

+  DFCS_MONO* = 32768

+  DFCS_PUSHED* = 512

+  # DrawIconEx

+  DI_COMPAT* = 4

+  DI_DEFAULTSIZE* = 8

+  DI_IMAGE* = 2

+  DI_MASK* = 1

+  DI_NORMAL* = 3

+  # DrawState

+  DST_BITMAP* = 4

+  DST_COMPLEX* = 0

+  DST_ICON* = 3

+  DST_PREFIXTEXT* = 2

+  DST_TEXT* = 1

+  DSS_NORMAL* = 0

+  DSS_UNION* = 16

+  DSS_DISABLED* = 32

+  DSS_MONO* = 128

+  # DrawStatusText

+  SBT_NOBORDERS* = 256

+  SBT_OWNERDRAW* = 4096

+  SBT_POPOUT* = 512

+  SBT_RTLREADING* = 1024

+  # DrawText, DrawTextEx

+  DT_BOTTOM* = 8

+  DT_CALCRECT* = 1024

+  DT_CENTER* = 1

+  DT_EDITCONTROL* = 8192

+  DT_END_ELLIPSIS* = 32768

+  DT_PATH_ELLIPSIS* = 16384

+  DT_EXPANDTABS* = 64

+  DT_EXTERNALLEADING* = 512

+  DT_LEFT* = 0

+  DT_MODIFYSTRING* = 65536

+  DT_NOCLIP* = 256

+  DT_NOPREFIX* = 2048

+  DT_RIGHT* = 2

+  DT_RTLREADING* = 131072

+  DT_SINGLELINE* = 32

+  DT_TABSTOP* = 128

+  DT_TOP* = 0

+  DT_VCENTER* = 4

+  DT_WORDBREAK* = 16

+  DT_INTERNAL* = 4096

+  DT_WORD_ELLIPSIS* = 0x00040000

+  DT_HIDEPREFIX* = 0x00100000

+  DT_PREFIXONLY* = 0x00200000

+  # DuplicateHandle, MapViewOfFile

+  DUPLICATE_CLOSE_SOURCE* = 1

+  DUPLICATE_SAME_ACCESS* = 2

+  FILE_MAP_ALL_ACCESS* = 0x000F001F

+  FILE_MAP_READ* = 4

+  FILE_MAP_WRITE* = 2

+  FILE_MAP_COPY* = 1

+  MUTEX_ALL_ACCESS* = 0x001F0001

+  MUTEX_MODIFY_STATE* = 1

+  SYNCHRONIZE* = 0x00100000

+  SEMAPHORE_ALL_ACCESS* = 0x001F0003

+  SEMAPHORE_MODIFY_STATE* = 2

+  EVENT_ALL_ACCESS* = 0x001F0003

+  EVENT_MODIFY_STATE* = 2

+  KEY_ALL_ACCESS* = 0x000F003F

+  KEY_CREATE_LINK* = 32

+  KEY_CREATE_SUB_KEY* = 4

+  KEY_ENUMERATE_SUB_KEYS* = 8

+  KEY_EXECUTE* = 0x00020019

+  KEY_NOTIFY* = 16

+  KEY_QUERY_VALUE* = 1

+  KEY_READ* = 0x00020019

+  KEY_SET_VALUE* = 2

+  KEY_WRITE* = 0x00020006

+  PROCESS_ALL_ACCESS* = 0x001F0FFF

+  PROCESS_CREATE_PROCESS* = 128

+  PROCESS_CREATE_THREAD* = 2

+  PROCESS_DUP_HANDLE* = 64

+  PROCESS_QUERY_INFORMATION* = 1024

+  PROCESS_SET_INFORMATION* = 512

+  PROCESS_TERMINATE* = 1

+  PROCESS_VM_OPERATION* = 8

+  PROCESS_VM_READ* = 16

+  PROCESS_VM_WRITE* = 32

+  THREAD_ALL_ACCESS* = 0x001F03FF

+  THREAD_DIRECT_IMPERSONATION* = 512

+  THREAD_GET_CONTEXT* = 8

+  THREAD_IMPERSONATE* = 256

+  THREAD_QUERY_INFORMATION* = 64

+  THREAD_SET_CONTEXT* = 16

+  THREAD_SET_INFORMATION* = 32

+  THREAD_SET_THREAD_TOKEN* = 128

+  THREAD_SUSPEND_RESUME* = 2

+  THREAD_TERMINATE* = 1

+  # EditWordBreakProc

+  WB_ISDELIMITER* = 2

+  WB_LEFT* = 0

+  WB_RIGHT* = 1

+  # EnableScrollBar

+  SB_BOTH* = 3

+  SB_CTL* = 2

+  SB_HORZ* = 0

+  SB_VERT* = 1

+  ESB_DISABLE_BOTH* = 3

+  ESB_DISABLE_DOWN* = 2

+  ESB_DISABLE_LEFT* = 1

+  ESB_DISABLE_LTUP* = 1

+  ESB_DISABLE_RIGHT* = 2

+  ESB_DISABLE_RTDN* = 2

+  ESB_DISABLE_UP* = 1

+  ESB_ENABLE_BOTH* = 0

+  # Scroll Bar notifications

+  SB_LINEUP* = 0

+  SB_LINEDOWN* = 1

+  SB_LINELEFT* = 0

+  SB_LINERIGHT* = 1

+  SB_PAGEUP* = 2

+  SB_PAGEDOWN* = 3

+  SB_PAGELEFT* = 2

+  SB_PAGERIGHT* = 3

+  SB_THUMBPOSITION* = 4

+  SB_THUMBTRACK* = 5

+  SB_ENDSCROLL* = 8

+  SB_LEFT* = 6

+  SB_RIGHT* = 7

+  SB_BOTTOM* = 7

+  SB_TOP* = 6

+  # EnumCalendarInfo

+  ENUM_ALL_CALENDARS* = -1

+  # EnumDateFormats

+  # GetDateFormat

+  DATE_SHORTDATE* = 1

+  DATE_LONGDATE* = 2

+  DATE_USE_ALT_CALENDAR* = 4

+  # EnumDependentServices

+  SERVICE_ACTIVE* = 1

+  SERVICE_INACTIVE* = 2

+  # EnumFontFamExProc

+  DEVICE_FONTTYPE* = 2

+  RASTER_FONTTYPE* = 1

+  TRUETYPE_FONTTYPE* = 4

+  # EnumObjects, GetCurrentObject, GetObjectType

+  OBJ_BRUSH* = 2

+  OBJ_PEN* = 1

+  OBJ_PAL* = 5

+  OBJ_FONT* = 6

+  OBJ_BITMAP* = 7

+  OBJ_EXTPEN* = 11

+  OBJ_REGION* = 8

+  OBJ_DC* = 3

+  OBJ_MEMDC* = 10

+  OBJ_METAFILE* = 9

+  OBJ_METADC* = 4

+  OBJ_ENHMETAFILE* = 13

+  OBJ_ENHMETADC* = 12

+

+                              #

+                              # Predefined Resource Types

+                              #

+const

+  RT_CURSOR* = cast[MAKEINTRESOURCE](1)

+  RT_BITMAP* = cast[MAKEINTRESOURCE](2)

+  RT_ICON* = cast[MAKEINTRESOURCE](3)

+  RT_MENU* = cast[MAKEINTRESOURCE](4)

+  RT_DIALOG* = cast[MAKEINTRESOURCE](5)

+  RT_STRING* = cast[MAKEINTRESOURCE](6)

+  RT_FONTDIR* = cast[MAKEINTRESOURCE](7)

+  RT_FONT* = cast[MAKEINTRESOURCE](8)

+  RT_ACCELERATOR* = cast[MAKEINTRESOURCE](9)

+  RT_RCDATA* = cast[MAKEINTRESOURCE](10)

+  RT_MESSAGETABLE* = cast[MAKEINTRESOURCE](11)

+  DIFFERENCE* = 11

+  RT_GROUP_CURSOR* = cast[MAKEINTRESOURCE](12)

+  RT_GROUP_ICON* = cast[MAKEINTRESOURCE](14)

+  RT_VERSION* = cast[MAKEINTRESOURCE](16)

+  RT_DLGINCLUDE* = cast[MAKEINTRESOURCE](17)

+  RT_PLUGPLAY* = cast[MAKEINTRESOURCE](19)

+  RT_VXD* = cast[MAKEINTRESOURCE](20)

+  RT_ANICURSOR* = cast[MAKEINTRESOURCE](21)

+  RT_ANIICON* = cast[MAKEINTRESOURCE](22)

+  RT_HTML* = cast[MAKEINTRESOURCE](23)

+  RT_MANIFEST* = cast[MAKEINTRESOURCE](24)

+

+const

+  # EnumServicesStatus

+  SERVICE_WIN32* = 48

+  SERVICE_DRIVER* = 11

+  # EnumSystemCodePages

+  CP_INSTALLED* = 1

+  CP_SUPPORTED* = 2

+  # EnumSystemLocales

+  LCID_INSTALLED* = 1

+  LCID_SUPPORTED* = 2

+  # EraseTape

+  TAPE_ERASE_LONG* = 0x00000001

+  TAPE_ERASE_SHORT* = 0

+  # Escape

+  SP_ERROR* = -1

+  SP_OUTOFDISK* = -4

+  SP_OUTOFMEMORY* = -5

+  SP_USERABORT* = -3

+  PHYSICALWIDTH* = 110

+  PHYSICALHEIGHT* = 111

+  PHYSICALOFFSETX* = 112

+  PHYSICALOFFSETY* = 113

+  SCALINGFACTORX* = 114

+  SCALINGFACTORY* = 115

+  QUERYESCSUPPORT* = 8

+  #ABORTDOC = 2; conflicts with AbortDoc function

+  cABORTDOC* = 2

+  #ENDDOC = 11; conflicts with AbortDoc function

+  cENDDOC* = 11

+  GETPHYSPAGESIZE* = 12

+  GETPRINTINGOFFSET* = 13

+  GETSCALINGFACTOR* = 14

+  NEWFRAME* = 1

+  NEXTBAND* = 3

+  PASSTHROUGH* = 19

+  #SETABORTPROC = 9; conflicts with AbortDoc function

+  cSETABORTPROC* = 9

+  #STARTDOC = 10; conflicts with AbortDoc function

+  cSTARTDOC* = 10

+  # EscapeCommFunction

+  CLRDTR* = 6

+  CLRRTS* = 4

+  SETDTR* = 5

+  SETRTS* = 3

+  SETXOFF* = 1

+  SETXON* = 2

+  SETBREAK* = 8

+  CLRBREAK* = 9

+  # ExitWindowsEx

+  EWX_FORCE* = 4

+  EWX_LOGOFF* = 0

+  EWX_POWEROFF* = 8

+  EWX_REBOOT* = 2

+  EWX_SHUTDOWN* = 1

+  # ExtFloodFill

+  FLOODFILLBORDER* = 0

+  FLOODFILLSURFACE* = 1

+  # ExtTextOut

+  ETO_CLIPPED* = 4

+  ETO_GLYPH_INDEX* = 16

+  ETO_OPAQUE* = 2

+  ETO_RTLREADING* = 128

+  # FillConsoleOutputAttribute

+  FOREGROUND_BLUE* = 1

+  FOREGROUND_GREEN* = 2

+  FOREGROUND_RED* = 4

+  FOREGROUND_INTENSITY* = 8

+  BACKGROUND_BLUE* = 16

+  BACKGROUND_GREEN* = 32

+  BACKGROUND_RED* = 64

+  BACKGROUND_INTENSITY* = 128

+  # FindFirstChangeNotification

+  FILE_NOTIFY_CHANGE_FILE_NAME* = 1

+  FILE_NOTIFY_CHANGE_DIR_NAME* = 2

+  FILE_NOTIFY_CHANGE_ATTRIBUTES* = 4

+  FILE_NOTIFY_CHANGE_SIZE* = 8

+  FILE_NOTIFY_CHANGE_LAST_WRITE* = 16

+  FILE_NOTIFY_CHANGE_SECURITY* = 256

+  # FindFirstPrinterChangeNotification

+  # FindNextPrinterNotification

+  # FMExtensionProc

+  # FoldString

+  MAP_FOLDCZONE* = 16

+  MAP_FOLDDIGITS* = 128

+  MAP_PRECOMPOSED* = 32

+  MAP_COMPOSITE* = 64

+  # ForegroundIdleProc

+  HC_ACTION* = 0

+  # FormatMessage

+  FORMAT_MESSAGE_ALLOCATE_BUFFER* = 256

+  FORMAT_MESSAGE_IGNORE_INSERTS* = 512

+  FORMAT_MESSAGE_FROM_STRING* = 1024

+  FORMAT_MESSAGE_FROM_HMODULE* = 2048

+  FORMAT_MESSAGE_FROM_SYSTEM* = 4096

+  FORMAT_MESSAGE_ARGUMENT_ARRAY* = 8192

+  FORMAT_MESSAGE_MAX_WIDTH_MASK* = 255

+  # GdiComment

+  GDICOMMENT_WINDOWS_METAFILE* = -2147483647

+  GDICOMMENT_BEGINGROUP* = 2

+  GDICOMMENT_ENDGROUP* = 3

+  GDICOMMENT_MULTIFORMATS* = 1073741828

+  GDICOMMENT_IDENTIFIER* = 1128875079

+  # GenerateConsoleCtrlEvent, HandlerRoutine

+  CTRL_C_EVENT* = 0

+  CTRL_BREAK_EVENT* = 1

+  CTRL_CLOSE_EVENT* = 2

+  CTRL_LOGOFF_EVENT* = 5

+  CTRL_SHUTDOWN_EVENT* = 6

+  # GetAddressByName

+  # GetArcDirection

+  AD_COUNTERCLOCKWISE* = 1

+  AD_CLOCKWISE* = 2

+  # GetBinaryTypes

+  SCS_32BIT_BINARY* = 0

+  SCS_DOS_BINARY* = 1

+  SCS_OS216_BINARY* = 5

+  SCS_PIF_BINARY* = 3

+  SCS_POSIX_BINARY* = 4

+  SCS_WOW_BINARY* = 2

+  # GetBoundsRect, SetBoundsRect

+  DCB_DISABLE* = 8

+  DCB_ENABLE* = 4

+  DCB_RESET* = 1

+  DCB_SET* = 3

+  DCB_ACCUMULATE* = 2

+  # GetCharacterPlacement, GetFontLanguageInfo

+  GCP_DBCS* = 1

+  GCP_ERROR* = 0x00008000

+  GCP_CLASSIN* = 0x00080000

+  GCP_DIACRITIC* = 256

+  GCP_DISPLAYZWG* = 0x00400000

+  GCP_GLYPHSHAPE* = 16

+  GCP_JUSTIFY* = 0x00010000

+  GCP_JUSTIFYIN* = 0x00200000

+  GCP_KASHIDA* = 1024

+  GCP_LIGATE* = 32

+  GCP_MAXEXTENT* = 0x00100000

+  GCP_NEUTRALOVERRIDE* = 0x02000000

+  GCP_NUMERICOVERRIDE* = 0x01000000

+  GCP_NUMERICSLATIN* = 0x04000000

+  GCP_NUMERICSLOCAL* = 0x08000000

+  GCP_REORDER* = 2

+  GCP_SYMSWAPOFF* = 0x00800000

+  GCP_USEKERNING* = 8

+  FLI_GLYPHS* = 0x00040000

+  FLI_MASK* = 0x0000103B

+  # GetClassLong, GetClassWord

+  GCW_ATOM* = -32

+  GCL_CBCLSEXTRA* = -20

+  GCL_CBWNDEXTRA* = -18

+  GCL_HBRBACKGROUND* = -10

+  GCL_HCURSOR* = -12

+  GCL_HICON* = -14

+  GCL_HICONSM* = -34

+  GCL_HMODULE* = -16

+  GCL_MENUNAME* = -8

+  GCL_STYLE* = -26

+  GCL_WNDPROC* = -24

+  # GetClipboardFormat, SetClipboardData

+  CF_BITMAP* = 2

+  CF_DIB* = 8

+  CF_PALETTE* = 9

+  CF_ENHMETAFILE* = 14

+  CF_METAFILEPICT* = 3

+  CF_OEMTEXT* = 7

+  CF_TEXT* = 1

+  CF_UNICODETEXT* = 13

+  CF_DIF* = 5

+  CF_DSPBITMAP* = 130

+  CF_DSPENHMETAFILE* = 142

+  CF_DSPMETAFILEPICT* = 131

+  CF_DSPTEXT* = 129

+  CF_GDIOBJFIRST* = 768

+  CF_GDIOBJLAST* = 1023

+  CF_HDROP* = 15

+  CF_LOCALE* = 16

+  CF_OWNERDISPLAY* = 128

+  CF_PENDATA* = 10

+  CF_PRIVATEFIRST* = 512

+  CF_PRIVATELAST* = 767

+  CF_RIFF* = 11

+  CF_SYLK* = 4

+  CF_WAVE* = 12

+  CF_TIFF* = 6

+  # GetCommMask

+  EV_BREAK* = 64

+  EV_CTS* = 8

+  EV_DSR* = 16

+  EV_ERR* = 128

+  EV_EVENT1* = 2048

+  EV_EVENT2* = 4096

+  EV_PERR* = 512

+  EV_RING* = 256

+  EV_RLSD* = 32

+  EV_RX80FULL* = 1024

+  EV_RXCHAR* = 1

+  EV_RXFLAG* = 2

+  EV_TXEMPTY* = 4

+  # GetCommModemStatus

+  MS_CTS_ON* = 0x00000010

+  MS_DSR_ON* = 0x00000020

+  MS_RING_ON* = 0x00000040

+  MS_RLSD_ON* = 0x00000080

+  # GetComputerName

+  MAX_COMPUTERNAME_LENGTH* = 15

+  # GetConsoleMode

+  ENABLE_LINE_INPUT* = 2

+  ENABLE_ECHO_INPUT* = 4

+  ENABLE_PROCESSED_INPUT* = 1

+  ENABLE_WINDOW_INPUT* = 8

+  ENABLE_MOUSE_INPUT* = 16

+  ENABLE_PROCESSED_OUTPUT* = 1

+  ENABLE_WRAP_AT_EOL_OUTPUT* = 2

+  # GetCPInfo

+  CP_ACP* = 0

+  CP_MACCP* = 2

+  CP_OEMCP* = 1

+  # GetDCEx

+  DCX_WINDOW* = 0x00000001

+  DCX_CACHE* = 0x00000002

+  DCX_PARENTCLIP* = 0x00000020

+  DCX_CLIPSIBLINGS* = 0x00000010

+  DCX_CLIPCHILDREN* = 0x00000008

+  DCX_NORESETATTRS* = 0x00000004

+  DCX_LOCKWINDOWUPDATE* = 0x00000400

+  DCX_EXCLUDERGN* = 0x00000040

+  DCX_INTERSECTRGN* = 0x00000080

+  DCX_VALIDATE* = 0x00200000

+  # GetDeviceCaps

+  DRIVERVERSION* = 0

+  TECHNOLOGY* = 2

+  DT_PLOTTER* = 0

+  DT_RASDISPLAY* = 1

+  DT_RASPRINTER* = 2

+  DT_RASCAMERA* = 3

+  DT_CHARSTREAM* = 4

+  DT_METAFILE* = 5

+  DT_DISPFILE* = 6

+  HORZSIZE* = 4

+  VERTSIZE* = 6

+  HORZRES* = 8

+  VERTRES* = 10

+  LOGPIXELSX* = 88

+  LOGPIXELSY* = 90

+  BITSPIXEL* = 12

+  PLANES* = 14

+  NUMBRUSHES* = 16

+  NUMPENS* = 18

+  NUMFONTS* = 22

+  NUMCOLORS* = 24

+  ASPECTX* = 40

+  ASPECTY* = 42

+  ASPECTXY* = 44

+  PDEVICESIZE* = 26

+  CLIPCAPS* = 36

+  SIZEPALETTE* = 104

+  NUMRESERVED* = 106

+  COLORRES* = 108

+  VREFRESH* = 116

+  DESKTOPHORZRES* = 118

+  DESKTOPVERTRES* = 117

+  BLTALIGNMENT* = 119

+  RASTERCAPS* = 38

+  RC_BANDING* = 2

+  RC_BITBLT* = 1

+  RC_BITMAP64* = 8

+  RC_DI_BITMAP* = 128

+  RC_DIBTODEV* = 512

+  RC_FLOODFILL* = 4096

+  RC_GDI20_OUTPUT* = 16

+  RC_PALETTE* = 256

+  RC_SCALING* = 4

+  RC_STRETCHBLT* = 2048

+  RC_STRETCHDIB* = 8192

+  CURVECAPS* = 28

+  CC_NONE* = 0

+  CC_CIRCLES* = 1

+  CC_PIE* = 2

+  CC_CHORD* = 4

+  CC_ELLIPSES* = 8

+  CC_WIDE* = 16

+  CC_STYLED* = 32

+  CC_WIDESTYLED* = 64

+  CC_INTERIORS* = 128

+  CC_ROUNDRECT* = 256

+  LINECAPS* = 30

+  LC_NONE* = 0

+  LC_POLYLINE* = 2

+  LC_MARKER* = 4

+  LC_POLYMARKER* = 8

+  LC_WIDE* = 16

+  LC_STYLED* = 32

+  LC_WIDESTYLED* = 64

+  LC_INTERIORS* = 128

+  POLYGONALCAPS* = 32

+  PC_NONE* = 0

+  PC_POLYGON* = 1

+  PC_RECTANGLE* = 2

+  PC_WINDPOLYGON* = 4

+  PC_SCANLINE* = 8

+  PC_WIDE* = 16

+  PC_STYLED* = 32

+  PC_WIDESTYLED* = 64

+  PC_INTERIORS* = 128

+  TEXTCAPS* = 34

+  TC_OP_CHARACTER* = 1

+  TC_OP_STROKE* = 2

+  TC_CP_STROKE* = 4

+  TC_CR_90* = 8

+  TC_CR_ANY* = 16

+  TC_SF_X_YINDEP* = 32

+  TC_SA_DOUBLE* = 64

+  TC_SA_INTEGER* = 128

+  TC_SA_CONTIN* = 256

+  TC_EA_DOUBLE* = 512

+  TC_IA_ABLE* = 1024

+  TC_UA_ABLE* = 2048

+  TC_SO_ABLE* = 4096

+  TC_RA_ABLE* = 8192

+  TC_VA_ABLE* = 16384

+  TC_RESERVED* = 32768

+  TC_SCROLLBLT* = 65536

+  PC_PATHS* = 512

+  # GetDriveType

+  DRIVE_REMOVABLE* = 2

+  DRIVE_FIXED* = 3

+  DRIVE_REMOTE* = 4

+  DRIVE_CDROM* = 5

+  DRIVE_RAMDISK* = 6

+  DRIVE_UNKNOWN* = 0

+  DRIVE_NO_ROOT_DIR* = 1

+  # GetExceptionCode

+  EXCEPTION_ACCESS_VIOLATION* = 0xC0000005

+  EXCEPTION_BREAKPOINT* = 0x80000003

+  EXCEPTION_DATATYPE_MISALIGNMENT* = 0x80000002

+  EXCEPTION_SINGLE_STEP* = 0x80000004

+  EXCEPTION_ARRAY_BOUNDS_EXCEEDED* = 0xC000008C

+  EXCEPTION_FLT_DENORMAL_OPERAND* = 0xC000008D

+  EXCEPTION_FLT_DIVIDE_BY_ZERO* = 0xC000008E

+  EXCEPTION_FLT_INEXACT_RESULT* = 0xC000008F

+  EXCEPTION_FLT_INVALID_OPERATION* = 0xC0000090

+  EXCEPTION_FLT_OVERFLOW* = 0xC0000091

+  EXCEPTION_FLT_STACK_CHECK* = 0xC0000092

+  EXCEPTION_FLT_UNDERFLOW* = 0xC0000093

+  EXCEPTION_INT_DIVIDE_BY_ZERO* = 0xC0000094

+  EXCEPTION_INT_OVERFLOW* = 0xC0000095

+  EXCEPTION_INVALID_HANDLE* = 0xC0000008

+  EXCEPTION_PRIV_INSTRUCTION* = 0xC0000096

+  EXCEPTION_NONCONTINUABLE_EXCEPTION* = 0xC0000025

+  EXCEPTION_NONCONTINUABLE* = 0x00000001

+  EXCEPTION_STACK_OVERFLOW* = 0xC00000FD

+  EXCEPTION_INVALID_DISPOSITION* = 0xC0000026

+  EXCEPTION_IN_PAGE_ERROR* = 0xC0000006

+  EXCEPTION_ILLEGAL_INSTRUCTION* = 0xC000001D

+  EXCEPTION_POSSIBLE_DEADLOCK* = 0xC0000194

+  # GetFileType

+  FILE_TYPE_UNKNOWN* = 0

+  FILE_TYPE_DISK* = 1

+  FILE_TYPE_CHAR* = 2

+  FILE_TYPE_PIPE* = 3

+  # GetGlyphOutline

+  GGO_BITMAP* = 1

+  GGO_NATIVE* = 2

+  GGO_METRICS* = 0

+  GGO_GRAY2_BITMAP* = 4

+  GGO_GRAY4_BITMAP* = 5

+  GGO_GRAY8_BITMAP* = 6

+  GDI_ERROR* = 0xFFFFFFFF

+  # GetGraphicsMode

+  GM_COMPATIBLE* = 1

+  GM_ADVANCED* = 2

+  # GetHandleInformation

+  HANDLE_FLAG_INHERIT* = 1

+  HANDLE_FLAG_PROTECT_FROM_CLOSE* = 2

+  # GetIconInfo

+  IDC_ARROW* =       cast[MAKEINTRESOURCE](32512)

+  IDC_IBEAM* =       cast[MAKEINTRESOURCE](32513)

+  IDC_WAIT* =        cast[MAKEINTRESOURCE](32514)

+  IDC_CROSS* =       cast[MAKEINTRESOURCE](32515)

+  IDC_UPARROW* =     cast[MAKEINTRESOURCE](32516)

+  IDC_SIZE* =        cast[MAKEINTRESOURCE](32640)  # OBSOLETE: use IDC_SIZEALL

+  IDC_ICON* =        cast[MAKEINTRESOURCE](32641)  # OBSOLETE: use IDC_ARROW

+  IDC_SIZENWSE* =    cast[MAKEINTRESOURCE](32642)

+  IDC_SIZENESW* =    cast[MAKEINTRESOURCE](32643)

+  IDC_SIZEWE* =      cast[MAKEINTRESOURCE](32644)

+  IDC_SIZENS* =      cast[MAKEINTRESOURCE](32645)

+  IDC_SIZEALL* =     cast[MAKEINTRESOURCE](32646)

+  IDC_NO* =          cast[MAKEINTRESOURCE](32648)

+  IDC_HAND* =        cast[MAKEINTRESOURCE](32649)

+  IDC_APPSTARTING* = cast[MAKEINTRESOURCE](32650)

+  IDC_HELP* =        cast[MAKEINTRESOURCE](32651)

+

+  IDI_APPLICATION* = cast[MAKEINTRESOURCE](32512)

+  IDI_HAND* =        cast[MAKEINTRESOURCE](32513)

+  IDI_QUESTION* =    cast[MAKEINTRESOURCE](32514)

+  IDI_EXCLAMATION* = cast[MAKEINTRESOURCE](32515)

+  IDI_ASTERISK* =    cast[MAKEINTRESOURCE](32516)

+  IDI_WINLOGO* =     cast[MAKEINTRESOURCE](32517)

+  IDI_WARNING* =     IDI_EXCLAMATION

+  IDI_ERROR* =       IDI_HAND

+  IDI_INFORMATION* = IDI_ASTERISK

+

+const

+  # GetMapMode

+  MM_ANISOTROPIC* = 8

+  MM_HIENGLISH* = 5

+  MM_HIMETRIC* = 3

+  MM_ISOTROPIC* = 7

+  MM_LOENGLISH* = 4

+  MM_LOMETRIC* = 2

+  MM_TEXT* = 1

+  MM_TWIPS* = 6

+  # GetMenuDefaultItem

+  GMDI_GOINTOPOPUPS* = 0x00000002

+  GMDI_USEDISABLED* = 0x00000001

+  # PeekMessage

+  PM_NOREMOVE* = 0

+  PM_REMOVE* = 1

+  PM_NOYIELD* = 2

+  # GetNamedPipeHandleState

+  #   PIPE_NOWAIT = 1; already above

+  #   PIPE_READMODE_MESSAGE = 2;already above

+  # GetNamedPipeInfo

+  PIPE_CLIENT_END* = 0

+  PIPE_SERVER_END* = 1

+  #   PIPE_TYPE_MESSAGE = 4;already above

+  # GetNextWindow, GetWindow

+  GW_HWNDNEXT* = 2

+  GW_HWNDPREV* = 3

+  GW_CHILD* = 5

+  GW_HWNDFIRST* = 0

+  GW_HWNDLAST* = 1

+  GW_OWNER* = 4

+  # GetPath

+  PT_MOVETO* = 6

+  PT_LINETO* = 2

+  PT_BEZIERTO* = 4

+  PT_CLOSEFIGURE* = 1

+  # GetProcessShutdownParameters

+  SHUTDOWN_NORETRY* = 1

+  # GetQueueStatus

+  QS_ALLEVENTS* = 191

+  QS_ALLINPUT* = 255

+  QS_HOTKEY* = 128

+  QS_INPUT* = 7

+  QS_KEY* = 1

+  QS_MOUSE* = 6

+  QS_MOUSEBUTTON* = 4

+  QS_MOUSEMOVE* = 2

+  QS_PAINT* = 32

+  QS_POSTMESSAGE* = 8

+  QS_SENDMESSAGE* = 64

+  QS_TIMER* = 16

+  # GetScrollInfo, SetScrollInfo

+  SIF_ALL* = 23

+  SIF_PAGE* = 2

+  SIF_POS* = 4

+  SIF_RANGE* = 1

+  SIF_DISABLENOSCROLL* = 8

+

+  # GetStdHandle

+  STD_INPUT_HANDLE* =  DWORD(-10)

+  STD_OUTPUT_HANDLE* = DWORD(-11)

+  STD_ERROR_HANDLE* =  DWORD(-12)

+

+  INVALID_HANDLE_VALUE* = HANDLE(-1)

+  INVALID_SET_FILE_POINTER* = ULONG(-1)

+  INVALID_FILE_SIZE* = ULONG(-1)

+  INVALID_FILE_ATTRIBUTES* = ULONG(-1)

+

+const

+  # GetStockObject

+  BLACK_BRUSH* = 4

+  DKGRAY_BRUSH* = 3

+  GRAY_BRUSH* = 2

+  HOLLOW_BRUSH* = 5

+  LTGRAY_BRUSH* = 1

+  NULL_BRUSH* = 5

+  WHITE_BRUSH* = 0

+  BLACK_PEN* = 7

+  NULL_PEN* = 8

+  WHITE_PEN* = 6

+  ANSI_FIXED_FONT* = 11

+  ANSI_VAR_FONT* = 12

+  DEVICE_DEFAULT_FONT* = 14

+  DEFAULT_GUI_FONT* = 17

+  OEM_FIXED_FONT* = 10

+  SYSTEM_FONT* = 13

+  SYSTEM_FIXED_FONT* = 16

+  DEFAULT_PALETTE* = 15

+  # GetStringTypeA

+  CT_CTYPE1* = 1

+  CT_CTYPE2* = 2

+  CT_CTYPE3* = 4

+  C1_UPPER* = 1

+  C1_LOWER* = 2

+  C1_DIGIT* = 4

+  C1_SPACE* = 8

+  C1_PUNCT* = 16

+  C1_CNTRL* = 32

+  C1_BLANK* = 64

+  C1_XDIGIT* = 128

+  C1_ALPHA* = 256

+  C2_LEFTTORIGHT* = 1

+  C2_RIGHTTOLEFT* = 2

+  C2_EUROPENUMBER* = 3

+  C2_EUROPESEPARATOR* = 4

+  C2_EUROPETERMINATOR* = 5

+  C2_ARABICNUMBER* = 6

+  C2_COMMONSEPARATOR* = 7

+  C2_BLOCKSEPARATOR* = 8

+  C2_SEGMENTSEPARATOR* = 9

+  C2_WHITESPACE* = 10

+  C2_OTHERNEUTRAL* = 11

+  C2_NOTAPPLICABLE* = 0

+  C3_NONSPACING* = 1

+  C3_DIACRITIC* = 2

+  C3_VOWELMARK* = 4

+  C3_SYMBOL* = 8

+  C3_KATAKANA* = 16

+  C3_HIRAGANA* = 32

+  C3_HALFWIDTH* = 64

+  C3_FULLWIDTH* = 128

+  C3_IDEOGRAPH* = 256

+  C3_KASHIDA* = 512

+  C3_ALPHA* = 32768

+  C3_NOTAPPLICABLE* = 0

+  # GetSysColor

+  COLOR_3DDKSHADOW* = 21

+  COLOR_3DFACE* = 15

+  COLOR_3DHILIGHT* = 20

+  COLOR_3DLIGHT* = 22

+  COLOR_BTNHILIGHT* = 20

+  COLOR_3DSHADOW* = 16

+  COLOR_ACTIVEBORDER* = 10

+  COLOR_ACTIVECAPTION* = 2

+  COLOR_APPWORKSPACE* = 12

+  COLOR_BACKGROUND* = 1

+  COLOR_DESKTOP* = 1

+  COLOR_BTNFACE* = 15

+  COLOR_BTNHIGHLIGHT* = 20

+  COLOR_BTNSHADOW* = 16

+  COLOR_BTNTEXT* = 18

+  COLOR_CAPTIONTEXT* = 9

+  COLOR_GRAYTEXT* = 17

+  COLOR_HIGHLIGHT* = 13

+  COLOR_HIGHLIGHTTEXT* = 14

+  COLOR_INACTIVEBORDER* = 11

+  COLOR_INACTIVECAPTION* = 3

+  COLOR_INACTIVECAPTIONTEXT* = 19

+  COLOR_INFOBK* = 24

+  COLOR_INFOTEXT* = 23

+  COLOR_MENU* = 4

+  COLOR_MENUTEXT* = 7

+  COLOR_SCROLLBAR* = 0

+  COLOR_WINDOW* = 5

+  COLOR_WINDOWFRAME* = 6

+  COLOR_WINDOWTEXT* = 8

+  # GetSystemMetrics

+  SM_CYMIN* = 29

+  SM_CXMIN* = 28

+  SM_ARRANGE* = 56

+  SM_CLEANBOOT* = 67

+  # The right value for SM_CEMETRICS for NT 3.5 is 75.  For Windows 95

+  #     and NT 4.0, it is 76.  The meaning is undocumented, anyhow.

+  SM_CMETRICS* = 76

+  SM_CMOUSEBUTTONS* = 43

+  SM_CXBORDER* = 5

+  SM_CYBORDER* = 6

+  SM_CXCURSOR* = 13

+  SM_CYCURSOR* = 14

+  SM_CXDLGFRAME* = 7

+  SM_CYDLGFRAME* = 8

+  SM_CXDOUBLECLK* = 36

+  SM_CYDOUBLECLK* = 37

+  SM_CXDRAG* = 68

+  SM_CYDRAG* = 69

+  SM_CXEDGE* = 45

+  SM_CYEDGE* = 46

+  SM_CXFIXEDFRAME* = 7

+  SM_CYFIXEDFRAME* = 8

+  SM_CXFRAME* = 32

+  SM_CYFRAME* = 33

+  SM_CXFULLSCREEN* = 16

+  SM_CYFULLSCREEN* = 17

+  SM_CXHSCROLL* = 21

+  SM_CYHSCROLL* = 3

+  SM_CXHTHUMB* = 10

+  SM_CXICON* = 11

+  SM_CYICON* = 12

+  SM_CXICONSPACING* = 38

+  SM_CYICONSPACING* = 39

+  SM_CXMAXIMIZED* = 61

+  SM_CYMAXIMIZED* = 62

+  SM_CXMAXTRACK* = 59

+  SM_CYMAXTRACK* = 60

+  SM_CXMENUCHECK* = 71

+  SM_CYMENUCHECK* = 72

+  SM_CXMENUSIZE* = 54

+  SM_CYMENUSIZE* = 55

+  SM_CXMINIMIZED* = 57

+  SM_CYMINIMIZED* = 58

+  SM_CXMINSPACING* = 47

+  SM_CYMINSPACING* = 48

+  SM_CXMINTRACK* = 34

+  SM_CYMINTRACK* = 35

+  SM_CXSCREEN* = 0

+  SM_CYSCREEN* = 1

+  SM_CXSIZE* = 30

+  SM_CYSIZE* = 31

+  SM_CXSIZEFRAME* = 32

+  SM_CYSIZEFRAME* = 33

+  SM_CXSMICON* = 49

+  SM_CYSMICON* = 50

+  SM_CXSMSIZE* = 52

+  SM_CYSMSIZE* = 53

+  SM_CXVSCROLL* = 2

+  #SM_CYHSCROLL = 3;already above

+  #SM_CXHSCROLL = 21;already above

+  SM_CYVSCROLL* = 20

+  SM_CYVTHUMB* = 9

+  SM_CYCAPTION* = 4

+  SM_CYKANJIWINDOW* = 18

+  SM_CYMENU* = 15

+  SM_CYSMCAPTION* = 51

+  SM_DBCSENABLED* = 42

+  SM_DEBUG* = 22

+  SM_MENUDROPALIGNMENT* = 40

+  SM_MIDEASTENABLED* = 74

+  SM_MOUSEPRESENT* = 19

+  SM_MOUSEWHEELPRESENT* = 75

+  SM_NETWORK* = 63

+  SM_PENWINDOWS* = 41

+  SM_SECURE* = 44

+  SM_SHOWSOUNDS* = 70

+  SM_SLOWMACHINE* = 73

+  SM_SWAPBUTTON* = 23

+  ARW_BOTTOMLEFT* = 0

+  ARW_BOTTOMRIGHT* = 0x00000001

+  ARW_HIDE* = 0x00000008

+  ARW_TOPLEFT* = 0x00000002

+  ARW_TOPRIGHT* = 0x00000003

+  ARW_DOWN* = 0x00000004

+  ARW_LEFT* = 0

+  ARW_RIGHT* = 0

+  ARW_UP* = 0x00000004

+  # GetSystemPaletteUse

+  SYSPAL_NOSTATIC* = 2

+  SYSPAL_STATIC* = 1

+  SYSPAL_ERROR* = 0

+  # GetTapeParameters, SetTapeParameters

+  GET_TAPE_MEDIA_INFORMATION* = 0

+  GET_TAPE_DRIVE_INFORMATION* = 1

+  SET_TAPE_MEDIA_INFORMATION* = 0

+  SET_TAPE_DRIVE_INFORMATION* = 1

+  # GetTapePosition

+  TAPE_ABSOLUTE_POSITION* = 0

+  TAPE_LOGICAL_POSITION* = 0x00000001

+  # GetTextAlign

+  TA_BASELINE* = 24

+  TA_BOTTOM* = 8

+  TA_TOP* = 0

+  TA_CENTER* = 6

+  TA_LEFT* = 0

+  TA_RIGHT* = 2

+  TA_RTLREADING* = 256

+  TA_NOUPDATECP* = 0

+  TA_UPDATECP* = 1

+  VTA_BASELINE* = 24

+  VTA_CENTER* = 6

+  # GetThreadPriority

+  THREAD_PRIORITY_ABOVE_NORMAL* = 1

+  THREAD_PRIORITY_BELOW_NORMAL* = -1

+  THREAD_PRIORITY_HIGHEST* = 2

+  THREAD_PRIORITY_IDLE* = -15

+  THREAD_PRIORITY_LOWEST* = -2

+  THREAD_PRIORITY_NORMAL* = 0

+  THREAD_PRIORITY_TIME_CRITICAL* = 15

+  THREAD_PRIORITY_ERROR_RETURN* = 2147483647

+  TLS_MINIMUM_AVAILABLE* = 64

+  # GetTimeFormat

+  TIME_NOMINUTESORSECONDS* = 1

+  TIME_NOSECONDS* = 2

+  TIME_NOTIMEMARKER* = 4

+  TIME_FORCE24HOURFORMAT* = 8

+

+const

+  # GetTimeZoneInformation

+  TIME_ZONE_ID_INVALID* = DWORD(- 1)

+  TIME_ZONE_ID_UNKNOWN* = 0

+  TIME_ZONE_ID_STANDARD* = 1

+  TIME_ZONE_ID_DAYLIGHT* = 2

+  # GetUserObjectInformation

+  UOI_FLAGS* = 1

+  UOI_NAME* = 2

+  UOI_TYPE* = 3

+  # GetVolumeInformation

+  FS_CASE_IS_PRESERVED* = 2

+  FS_CASE_SENSITIVE* = 1

+  FS_UNICODE_STORED_ON_DISK* = 4

+  FS_PERSISTENT_ACLS* = 8

+  FS_FILE_COMPRESSION* = 16

+  FS_VOL_IS_COMPRESSED* = 32768

+  # GetWindowLong

+  GWL_EXSTYLE* = -20

+  GWL_STYLE* = -16

+  GWL_WNDPROC* = -4

+  GWL_HINSTANCE* = -6

+  GWL_HWNDPARENT* = -8

+  GWL_ID* = -12

+  GWL_USERDATA* = -21

+  DWL_DLGPROC* = 4

+  DWL_MSGRESULT* = 0

+  DWL_USER* = 8

+  # GlobalAlloc, GlobalFlags

+  GMEM_FIXED* = 0

+  GMEM_MOVEABLE* = 2

+  GPTR* = 64

+  GHND* = 66

+  GMEM_DDESHARE* = 8192

+  GMEM_DISCARDABLE* = 256

+  GMEM_LOWER* = 4096

+  GMEM_NOCOMPACT* = 16

+  GMEM_NODISCARD* = 32

+  GMEM_NOT_BANKED* = 4096

+  GMEM_NOTIFY* = 16384

+  GMEM_SHARE* = 8192

+  GMEM_ZEROINIT* = 64

+  GMEM_DISCARDED* = 16384

+  GMEM_INVALID_HANDLE* = 32768

+  GMEM_LOCKCOUNT* = 255

+  # HeapAlloc, HeapReAlloc

+  HEAP_GENERATE_EXCEPTIONS* = 4

+  HEAP_NO_SERIALIZE* = 1

+  HEAP_ZERO_MEMORY* = 8

+  STATUS_NO_MEMORY* = 0xC0000017

+  STATUS_ACCESS_VIOLATION* = 0xC0000005

+  HEAP_REALLOC_IN_PLACE_ONLY* = 16

+  # ImageList_Create

+  ILC_COLOR* = 0

+  ILC_COLOR4* = 4

+  ILC_COLOR8* = 8

+  ILC_COLOR16* = 16

+  ILC_COLOR24* = 24

+  ILC_COLOR32* = 32

+  ILC_COLORDDB* = 254

+  ILC_MASK* = 1

+  ILC_PALETTE* = 2048

+  # ImageList_Draw, ImageList_DrawEx

+  ILD_BLEND25* = 2

+  ILD_BLEND50* = 4

+  ILD_SELECTED* = 4

+  ILD_BLEND* = 4

+  ILD_FOCUS* = 2

+  ILD_MASK* = 16

+  ILD_NORMAL* = 0

+  ILD_TRANSPARENT* = 1

+  CLR_NONE* = 0xFFFFFFFF

+  CLR_DEFAULT* = 0xFF000000

+  CLR_INVALID* = 0xFFFFFFFF

+  # ImageList_LoadImage

+  #LR_DEFAULTCOLOR = 0;already above

+  LR_LOADFROMFILE* = 16

+  LR_LOADMAP3DCOLORS* = 4096

+  LR_LOADTRANSPARENT* = 32

+  # ImmConfigureIME

+  IME_CONFIG_GENERAL* = 1

+  IME_CONFIG_REGISTERWORD* = 2

+  IME_CONFIG_SELECTDICTIONARY* = 3

+  # ImmGetConversionList

+  GCL_CONVERSION* = 1

+  GCL_REVERSECONVERSION* = 2

+  GCL_REVERSE_LENGTH* = 3

+  # ImmGetGuideLine

+  GGL_LEVEL* = 1

+  GGL_INDEX* = 2

+  GGL_STRING* = 3

+  GGL_PRIVATE* = 4

+  GL_LEVEL_ERROR* = 2

+  GL_LEVEL_FATAL* = 1

+  GL_LEVEL_INFORMATION* = 4

+  GL_LEVEL_NOGUIDELINE* = 0

+  GL_LEVEL_WARNING* = 3

+  GL_ID_CANNOTSAVE* = 17

+  GL_ID_NOCONVERT* = 32

+  GL_ID_NODICTIONARY* = 16

+  GL_ID_NOMODULE* = 1

+  GL_ID_READINGCONFLICT* = 35

+  GL_ID_TOOMANYSTROKE* = 34

+  GL_ID_TYPINGERROR* = 33

+  GL_ID_UNKNOWN* = 0

+  GL_ID_INPUTREADING* = 36

+  GL_ID_INPUTRADICAL* = 37

+  GL_ID_INPUTCODE* = 38

+  GL_ID_CHOOSECANDIDATE* = 40

+  GL_ID_REVERSECONVERSION* = 41

+  # ImmGetProperty

+  IGP_PROPERTY* = 4

+  IGP_CONVERSION* = 8

+  IGP_SENTENCE* = 12

+  IGP_UI* = 16

+  IGP_SETCOMPSTR* = 20

+  IGP_SELECT* = 24

+  IME_PROP_AT_CARET* = 65536

+  IME_PROP_SPECIAL_UI* = 131072

+  IME_PROP_CANDLIST_START_FROM_1* = 262144

+  IME_PROP_UNICODE* = 524288

+  UI_CAP_2700* = 1

+  UI_CAP_ROT90* = 2

+  UI_CAP_ROTANY* = 4

+  SCS_CAP_COMPSTR* = 1

+  SCS_CAP_MAKEREAD* = 2

+  SELECT_CAP_CONVERSION* = 1

+  SELECT_CAP_SENTENCE* = 2

+  # ImmNotifyIME

+  NI_CHANGECANDIDATELIST* = 19

+  NI_CLOSECANDIDATE* = 17

+  NI_COMPOSITIONSTR* = 21

+  NI_OPENCANDIDATE* = 16

+  NI_SELECTCANDIDATESTR* = 18

+  NI_SETCANDIDATE_PAGESIZE* = 23

+  NI_SETCANDIDATE_PAGESTART* = 22

+  CPS_CANCEL* = 4

+  CPS_COMPLETE* = 1

+  CPS_CONVERT* = 2

+  CPS_REVERT* = 3

+  # ImmSetCompositionString

+  SCS_SETSTR* = 9

+  SCS_CHANGEATTR* = 18

+  SCS_CHANGECLAUSE* = 36

+  # ImmUnregisterWord

+  IME_REGWORD_STYLE_EUDC* = 1

+  IME_REGWORD_STYLE_USER_FIRST* = 0x80000000

+  IME_REGWORD_STYLE_USER_LAST* = -1

+  # InitializeSecurityDescriptor

+  SECURITY_DESCRIPTOR_REVISION* = 1

+  # IsTextUnicode

+  IS_TEXT_UNICODE_ASCII16* = 1

+  IS_TEXT_UNICODE_REVERSE_ASCII16* = 16

+  IS_TEXT_UNICODE_STATISTICS* = 2

+  IS_TEXT_UNICODE_REVERSE_STATISTICS* = 32

+  IS_TEXT_UNICODE_CONTROLS* = 4

+  IS_TEXT_UNICODE_REVERSE_CONTROLS* = 64

+  IS_TEXT_UNICODE_SIGNATURE* = 8

+  IS_TEXT_UNICODE_REVERSE_SIGNATURE* = 128

+  IS_TEXT_UNICODE_ILLEGAL_CHARS* = 256

+  IS_TEXT_UNICODE_ODD_LENGTH* = 512

+  IS_TEXT_UNICODE_NULL_BYTES* = 4096

+  IS_TEXT_UNICODE_UNICODE_MASK* = 15

+  IS_TEXT_UNICODE_REVERSE_MASK* = 240

+  IS_TEXT_UNICODE_NOT_UNICODE_MASK* = 3840

+  IS_TEXT_UNICODE_NOT_ASCII_MASK* = 61440

+  # JournalPlaybackProc, KeyboardProc

+  HC_GETNEXT* = 1

+  HC_SKIP* = 2

+  HC_SYSMODALOFF* = 5

+  HC_SYSMODALON* = 4

+  HC_NOREMOVE* = 3

+  # keybd_event

+  KEYEVENTF_EXTENDEDKEY* = 1

+  KEYEVENTF_KEYUP* = 2

+  # LoadBitmap

+  OBM_BTNCORNERS* = 32758

+  OBM_BTSIZE* = 32761

+  OBM_CHECK* = 32760

+  OBM_CHECKBOXES* = 32759

+  OBM_CLOSE* = 32754

+  OBM_COMBO* = 32738

+  OBM_DNARROW* = 32752

+  OBM_DNARROWD* = 32742

+  OBM_DNARROWI* = 32736

+  OBM_LFARROW* = 32750

+  OBM_LFARROWI* = 32734

+  OBM_LFARROWD* = 32740

+  OBM_MNARROW* = 32739

+  OBM_OLD_CLOSE* = 32767

+  OBM_OLD_DNARROW* = 32764

+  OBM_OLD_LFARROW* = 32762

+  OBM_OLD_REDUCE* = 32757

+  OBM_OLD_RESTORE* = 32755

+  OBM_OLD_RGARROW* = 32763

+  OBM_OLD_UPARROW* = 32765

+  OBM_OLD_ZOOM* = 32756

+  OBM_REDUCE* = 32749

+  OBM_REDUCED* = 32746

+  OBM_RESTORE* = 32747

+  OBM_RESTORED* = 32744

+  OBM_RGARROW* = 32751

+  OBM_RGARROWD* = 32741

+  OBM_RGARROWI* = 32735

+  OBM_SIZE* = 32766

+  OBM_UPARROW* = 32753

+  OBM_UPARROWD* = 32743

+  OBM_UPARROWI* = 32737

+  OBM_ZOOM* = 32748

+  OBM_ZOOMD* = 32745

+  # LoadLibraryEx

+  DONT_RESOLVE_DLL_REFERENCES* = 1

+  LOAD_LIBRARY_AS_DATAFILE* = 2

+  LOAD_WITH_ALTERED_SEARCH_PATH* = 8

+  # LocalAlloc, LocalFlags

+  LPTR* = 64

+  LHND* = 66

+  NONZEROLHND* = 2

+  NONZEROLPTR* = 0

+  LMEM_NONZEROLHND* = 2

+  LMEM_NONZEROLPTR* = 0

+  LMEM_FIXED* = 0

+  LMEM_MOVEABLE* = 2

+  LMEM_NOCOMPACT* = 16

+  LMEM_NODISCARD* = 32

+  LMEM_ZEROINIT* = 64

+  LMEM_MODIFY* = 128

+  LMEM_LOCKCOUNT* = 255

+  LMEM_DISCARDABLE* = 3840

+  LMEM_DISCARDED* = 16384

+  LMEM_INVALID_HANDLE* = 32768

+  # LockFileEx

+  LOCKFILE_FAIL_IMMEDIATELY* = 1

+  LOCKFILE_EXCLUSIVE_LOCK* = 2

+  # LogonUser

+  # LZCopy, LZInit, LZRead

+  # MessageBeep, MessageBox

+  MB_USERICON* = 0x00000080

+  MB_ICONASTERISK* = 0x00000040

+  MB_ICONEXCLAMATION* = 0x00000030

+  MB_ICONWARNING* = 0x00000030

+  MB_ICONERROR* = 0x00000010

+  MB_ICONHAND* = 0x00000010

+  MB_ICONQUESTION* = 0x00000020

+  MB_OK* = 0

+  MB_ABORTRETRYIGNORE* = 0x00000002

+  MB_APPLMODAL* = 0

+  MB_DEFAULT_DESKTOP_ONLY* = 0x00020000

+  MB_HELP* = 0x00004000

+  MB_RIGHT* = 0x00080000

+  MB_RTLREADING* = 0x00100000

+  MB_TOPMOST* = 0x00040000

+  MB_DEFBUTTON1* = 0

+  MB_DEFBUTTON2* = 0x00000100

+  MB_DEFBUTTON3* = 0x00000200

+  MB_DEFBUTTON4* = 0x00000300

+  MB_ICONINFORMATION* = 0x00000040

+  MB_ICONSTOP* = 0x00000010

+  MB_OKCANCEL* = 0x00000001

+  MB_RETRYCANCEL* = 0x00000005

+  MB_SERVICE_NOTIFICATION* = 0x00040000

+  MB_SETFOREGROUND* = 0x00010000

+  MB_SYSTEMMODAL* = 0x00001000

+  MB_TASKMODAL* = 0x00002000

+  MB_YESNO* = 0x00000004

+  MB_YESNOCANCEL* = 0x00000003

+  IDABORT* = 3

+  IDCANCEL* = 2

+  IDCLOSE* = 8

+  IDHELP* = 9

+  IDIGNORE* = 5

+  IDNO* = 7

+  IDOK* = 1

+  IDRETRY* = 4

+  IDYES* = 6

+  # MessageProc

+  MSGF_DIALOGBOX* = 0

+  MSGF_MENU* = 2

+  MSGF_NEXTWINDOW* = 6

+  MSGF_SCROLLBAR* = 5

+  MSGF_MAINLOOP* = 8

+  MSGF_USER* = 4096

+  # ModifyWorldTransform

+  MWT_IDENTITY* = 1

+  MWT_LEFTMULTIPLY* = 2

+  MWT_RIGHTMULTIPLY* = 3

+  # mouse_event

+  MOUSEEVENTF_ABSOLUTE* = 32768

+  MOUSEEVENTF_MOVE* = 1

+  MOUSEEVENTF_LEFTDOWN* = 2

+  MOUSEEVENTF_LEFTUP* = 4

+  MOUSEEVENTF_RIGHTDOWN* = 8

+  MOUSEEVENTF_RIGHTUP* = 16

+  MOUSEEVENTF_MIDDLEDOWN* = 32

+  MOUSEEVENTF_MIDDLEUP* = 64

+  # MoveFileEx

+  MOVEFILE_REPLACE_EXISTING* = 1

+  MOVEFILE_COPY_ALLOWED* = 2

+  MOVEFILE_DELAY_UNTIL_REBOOT* = 4

+  # MsgWaitForMultipleObjects, WaitForMultipleObjectsEx

+  WAIT_OBJECT_0* = 0

+  WAIT_ABANDONED_0* = 0x00000080

+  WAIT_TIMEOUT* = 0x00000102

+  WAIT_IO_COMPLETION* = 0x000000C0

+  WAIT_ABANDONED* = 0x00000080

+  WAIT_FAILED* = 0xFFFFFFFF

+  MAXIMUM_WAIT_OBJECTS* = 0x00000040

+  MAXIMUM_SUSPEND_COUNT* = 0x0000007F

+  # MultiByteToWideChar

+  MB_PRECOMPOSED* = 1

+  MB_COMPOSITE* = 2

+  MB_ERR_INVALID_CHARS* = 8

+  MB_USEGLYPHCHARS* = 4

+  # NDdeSetTrustedShare

+  # NetAccessCheck

+  # NetServerEnum

+  # NetServiceControl

+  # NetUserEnum

+  # OpenProcessToken

+  TOKEN_ADJUST_DEFAULT* = 128

+  TOKEN_ADJUST_GROUPS* = 64

+  TOKEN_ADJUST_PRIVILEGES* = 32

+  TOKEN_ALL_ACCESS* = 0x000F00FF

+  TOKEN_ASSIGN_PRIMARY* = 1

+  TOKEN_DUPLICATE* = 2

+  TOKEN_EXECUTE* = 0x00020000

+  TOKEN_IMPERSONATE* = 4

+  TOKEN_QUERY* = 8

+  TOKEN_QUERY_SOURCE* = 16

+  TOKEN_READ* = 0x00020008

+  TOKEN_WRITE* = 0x000200E0

+  # OpenSCManager

+  SC_MANAGER_ALL_ACCESS* = 0x000F003F

+  SC_MANAGER_CONNECT* = 1

+  SC_MANAGER_CREATE_SERVICE* = 2

+  SC_MANAGER_ENUMERATE_SERVICE* = 4

+  SC_MANAGER_LOCK* = 8

+  SC_MANAGER_QUERY_LOCK_STATUS* = 16

+  SC_MANAGER_MODIFY_BOOT_CONFIG* = 32

+  # PostMessage

+  HWND_BROADCAST* = HWND(0xffff)

+

+const

+  # PrepareTape

+  TAPE_FORMAT* = 0x00000005

+  TAPE_LOAD* = 0

+  TAPE_LOCK* = 0x00000003

+  TAPE_TENSION* = 0x00000002

+  TAPE_UNLOAD* = 0x00000001

+  TAPE_UNLOCK* = 0x00000004

+  # PropertySheet

+  IS_PSREBOOTSYSTEM* = 3

+  IS_PSRESTARTWINDOWS* = 2

+  # PropSheetPageProc

+  PSPCB_CREATE* = 2

+  PSPCB_RELEASE* = 1

+  # PurgeComm

+  PURGE_TXABORT* = 1

+  PURGE_RXABORT* = 2

+  PURGE_TXCLEAR* = 4

+  PURGE_RXCLEAR* = 8

+  # QueryServiceObjectSecurity

+  OWNER_SECURITY_INFORMATION* = 0x00000001

+  GROUP_SECURITY_INFORMATION* = 0x00000002

+  DACL_SECURITY_INFORMATION* = 0x00000004

+  SACL_SECURITY_INFORMATION* = 0x00000008

+  # ReadEventLog, ReportEvent

+  EVENTLOG_FORWARDS_READ* = 4

+  EVENTLOG_BACKWARDS_READ* = 8

+  EVENTLOG_SEEK_READ* = 2

+  EVENTLOG_SEQUENTIAL_READ* = 1

+  EVENTLOG_ERROR_TYPE* = 1

+  EVENTLOG_WARNING_TYPE* = 2

+  EVENTLOG_INFORMATION_TYPE* = 4

+  EVENTLOG_AUDIT_SUCCESS* = 8

+

+  EVENTLOG_AUDIT_FAILURE* = 16

+  # RedrawWindow

+  RDW_ERASE* = 4

+  RDW_FRAME* = 1024

+  RDW_INTERNALPAINT* = 2

+  RDW_INVALIDATE* = 1

+  RDW_NOERASE* = 32

+  RDW_NOFRAME* = 2048

+  RDW_NOINTERNALPAINT* = 16

+  RDW_VALIDATE* = 8

+  RDW_ERASENOW* = 512

+  RDW_UPDATENOW* = 256

+  RDW_ALLCHILDREN* = 128

+  RDW_NOCHILDREN* = 64

+

+  # RegCreateKey

+  HKEY_CLASSES_ROOT* =     HKEY(0x80000000)

+  HKEY_CURRENT_USER* =     HKEY(0x80000001)

+  HKEY_LOCAL_MACHINE* =    HKEY(0x80000002)

+  HKEY_USERS* =            HKEY(0x80000003)

+  HKEY_PERFORMANCE_DATA* = HKEY(0x80000004)

+  HKEY_CURRENT_CONFIG* =   HKEY(0x80000005)

+  HKEY_DYN_DATA* =         HKEY(0x80000006)

+

+const

+  # RegCreateKeyEx

+  REG_OPTION_VOLATILE* = 0x00000001

+  REG_OPTION_NON_VOLATILE* = 0

+  REG_CREATED_NEW_KEY* = 0x00000001

+  REG_OPENED_EXISTING_KEY* = 0x00000002

+  # RegEnumValue

+  REG_BINARY* = 3

+  REG_DWORD* = 4

+  REG_DWORD_LITTLE_ENDIAN* = 4

+  REG_DWORD_BIG_ENDIAN* = 5

+  REG_EXPAND_SZ* = 2

+  REG_FULL_RESOURCE_DESCRIPTOR* = 9

+  REG_LINK* = 6

+  REG_MULTI_SZ* = 7

+  REG_NONE* = 0

+  REG_RESOURCE_LIST* = 8

+  REG_RESOURCE_REQUIREMENTS_LIST* = 10

+  REG_SZ* = 1

+  # RegisterHotKey

+  MOD_ALT* = 1

+  MOD_CONTROL* = 2

+  MOD_SHIFT* = 4

+  MOD_WIN* = 8

+  IDHOT_SNAPDESKTOP* = -2

+  IDHOT_SNAPWINDOW* = -1

+  # RegNotifyChangeKeyValue

+  REG_NOTIFY_CHANGE_NAME* = 0x00000001

+  REG_NOTIFY_CHANGE_ATTRIBUTES* = 0x00000002

+  REG_NOTIFY_CHANGE_LAST_SET* = 0x00000004

+  REG_NOTIFY_CHANGE_SECURITY* = 0x00000008

+  # ScrollWindowEx

+  SW_ERASE* = 4

+  SW_INVALIDATE* = 2

+  SW_SCROLLCHILDREN* = 1

+  # SendMessageTimeout

+  SMTO_ABORTIFHUNG* = 2

+  SMTO_BLOCK* = 1

+  SMTO_NORMAL* = 0

+  # SetBkMode

+  OPAQUE* = 2

+

+  TRANSPARENT* = 1

+  # SetDebugErrorLevel

+  SLE_ERROR* = 1

+  SLE_MINORERROR* = 2

+  SLE_WARNING* = 3

+  # SetErrorMode

+  SEM_FAILCRITICALERRORS* = 1

+  SEM_NOALIGNMENTFAULTEXCEPT* = 4

+  SEM_NOGPFAULTERRORBOX* = 2

+  SEM_NOOPENFILEERRORBOX* = 32768

+  # SetICMMode

+  ICM_ON* = 2

+  ICM_OFF* = 1

+  ICM_QUERY* = 3

+  # SetJob

+  # Locale Information

+  LOCALE_ILANGUAGE* = 1

+  LOCALE_SLANGUAGE* = 2

+  LOCALE_SENGLANGUAGE* = 4097

+  LOCALE_SABBREVLANGNAME* = 3

+  LOCALE_SNATIVELANGNAME* = 4

+  LOCALE_ICOUNTRY* = 5

+  LOCALE_SCOUNTRY* = 6

+  LOCALE_SENGCOUNTRY* = 4098

+  LOCALE_SABBREVCTRYNAME* = 7

+  LOCALE_SNATIVECTRYNAME* = 8

+  LOCALE_IDEFAULTLANGUAGE* = 9

+  LOCALE_IDEFAULTCOUNTRY* = 10

+  LOCALE_IDEFAULTANSICODEPAGE* = 4100

+  LOCALE_IDEFAULTCODEPAGE* = 11

+  LOCALE_SLIST* = 12

+  LOCALE_IMEASURE* = 13

+  LOCALE_SDECIMAL* = 14

+  LOCALE_STHOUSAND* = 15

+  LOCALE_SGROUPING* = 16

+  LOCALE_IDIGITS* = 17

+  LOCALE_ILZERO* = 18

+  LOCALE_INEGNUMBER* = 4112

+  LOCALE_SCURRENCY* = 20

+  LOCALE_SMONDECIMALSEP* = 22

+  LOCALE_SMONTHOUSANDSEP* = 23

+  LOCALE_SMONGROUPING* = 24

+  LOCALE_ICURRDIGITS* = 25

+  LOCALE_ICURRENCY* = 27

+  LOCALE_INEGCURR* = 28

+  LOCALE_SDATE* = 29

+  LOCALE_STIME* = 30

+  LOCALE_STIMEFORMAT* = 4099

+  LOCALE_SSHORTDATE* = 31

+  LOCALE_SLONGDATE* = 32

+  LOCALE_IDATE* = 33

+  LOCALE_ILDATE* = 34

+  LOCALE_ITIME* = 35

+  LOCALE_ITLZERO* = 37

+  LOCALE_IDAYLZERO* = 38

+  LOCALE_IMONLZERO* = 39

+  LOCALE_S1159* = 40

+  LOCALE_S2359* = 41

+  LOCALE_ICALENDARTYPE* = 4105

+  LOCALE_IOPTIONALCALENDAR* = 4107

+  LOCALE_IFIRSTDAYOFWEEK* = 4108

+  LOCALE_IFIRSTWEEKOFYEAR* = 4109

+  LOCALE_SDAYNAME1* = 42

+  LOCALE_SDAYNAME2* = 43

+  LOCALE_SDAYNAME3* = 44

+  LOCALE_SDAYNAME4* = 45

+  LOCALE_SDAYNAME5* = 46

+  LOCALE_SDAYNAME6* = 47

+  LOCALE_SDAYNAME7* = 48

+  LOCALE_SABBREVDAYNAME1* = 49

+  LOCALE_SABBREVDAYNAME2* = 50

+  LOCALE_SABBREVDAYNAME3* = 51

+  LOCALE_SABBREVDAYNAME4* = 52

+  LOCALE_SABBREVDAYNAME5* = 53

+  LOCALE_SABBREVDAYNAME6* = 54

+  LOCALE_SABBREVDAYNAME7* = 55

+  LOCALE_SMONTHNAME1* = 56

+  LOCALE_SMONTHNAME2* = 57

+  LOCALE_SMONTHNAME3* = 58

+  LOCALE_SMONTHNAME4* = 59

+  LOCALE_SMONTHNAME5* = 60

+  LOCALE_SMONTHNAME6* = 61

+  LOCALE_SMONTHNAME7* = 62

+  LOCALE_SMONTHNAME8* = 63

+  LOCALE_SMONTHNAME9* = 64

+  LOCALE_SMONTHNAME10* = 65

+  LOCALE_SMONTHNAME11* = 66

+  LOCALE_SMONTHNAME12* = 67

+  LOCALE_SMONTHNAME13* = 4110

+  LOCALE_SABBREVMONTHNAME1* = 68

+  LOCALE_SABBREVMONTHNAME2* = 69

+  LOCALE_SABBREVMONTHNAME3* = 70

+  LOCALE_SABBREVMONTHNAME4* = 71

+  LOCALE_SABBREVMONTHNAME5* = 72

+  LOCALE_SABBREVMONTHNAME6* = 73

+  LOCALE_SABBREVMONTHNAME7* = 74

+  LOCALE_SABBREVMONTHNAME8* = 75

+  LOCALE_SABBREVMONTHNAME9* = 76

+  LOCALE_SABBREVMONTHNAME10* = 77

+  LOCALE_SABBREVMONTHNAME11* = 78

+  LOCALE_SABBREVMONTHNAME12* = 79

+  LOCALE_SABBREVMONTHNAME13* = 4111

+  LOCALE_SPOSITIVESIGN* = 80

+  LOCALE_SNEGATIVESIGN* = 81

+  LOCALE_IPOSSIGNPOSN* = 82

+  LOCALE_INEGSIGNPOSN* = 83

+  LOCALE_IPOSSYMPRECEDES* = 84

+  LOCALE_IPOSSEPBYSPACE* = 85

+  LOCALE_INEGSYMPRECEDES* = 86

+  LOCALE_INEGSEPBYSPACE* = 87

+  LOCALE_NOUSEROVERRIDE* = 0x80000000

+  LOCALE_USE_CP_ACP* = 0x40000000 # use the system ACP

+  LOCALE_RETURN_NUMBER* = 0x20000000 # return number instead

+  LOCALE_SISO639LANGNAME* = 0x00000059

+  LOCALE_SISO3166CTRYNAME* = 0x0000005A

+  # Calendar Type Information

+  CAL_ICALINTVALUE* = 1

+  CAL_IYEAROFFSETRANGE* = 3

+  CAL_SABBREVDAYNAME1* = 14

+  CAL_SABBREVDAYNAME2* = 15

+  CAL_SABBREVDAYNAME3* = 16

+  CAL_SABBREVDAYNAME4* = 17

+  CAL_SABBREVDAYNAME5* = 18

+  CAL_SABBREVDAYNAME6* = 19

+  CAL_SABBREVDAYNAME7* = 20

+  CAL_SABBREVMONTHNAME1* = 34

+  CAL_SABBREVMONTHNAME2* = 35

+  CAL_SABBREVMONTHNAME3* = 36

+  CAL_SABBREVMONTHNAME4* = 37

+  CAL_SABBREVMONTHNAME5* = 38

+  CAL_SABBREVMONTHNAME6* = 39

+  CAL_SABBREVMONTHNAME7* = 40

+  CAL_SABBREVMONTHNAME8* = 41

+  CAL_SABBREVMONTHNAME9* = 42

+  CAL_SABBREVMONTHNAME10* = 43

+  CAL_SABBREVMONTHNAME11* = 44

+  CAL_SABBREVMONTHNAME12* = 45

+  CAL_SABBREVMONTHNAME13* = 46

+  CAL_SCALNAME* = 2

+  CAL_SDAYNAME1* = 7

+  CAL_SDAYNAME2* = 8

+  CAL_SDAYNAME3* = 9

+  CAL_SDAYNAME4* = 10

+  CAL_SDAYNAME5* = 11

+  CAL_SDAYNAME6* = 12

+  CAL_SDAYNAME7* = 13

+  CAL_SERASTRING* = 4

+  CAL_SLONGDATE* = 6

+  CAL_SMONTHNAME1* = 21

+  CAL_SMONTHNAME2* = 22

+  CAL_SMONTHNAME3* = 23

+  CAL_SMONTHNAME4* = 24

+  CAL_SMONTHNAME5* = 25

+  CAL_SMONTHNAME6* = 26

+  CAL_SMONTHNAME7* = 27

+  CAL_SMONTHNAME8* = 28

+  CAL_SMONTHNAME9* = 29

+  CAL_SMONTHNAME10* = 30

+  CAL_SMONTHNAME11* = 31

+  CAL_SMONTHNAME12* = 32

+  CAL_SMONTHNAME13* = 33

+  CAL_SSHORTDATE* = 5

+  # SetProcessWorkingSetSize

+  PROCESS_SET_QUOTA* = 256

+  # SetPrinter

+  # SetService

+  # SetStretchBltMode

+  BLACKONWHITE* = 1

+  COLORONCOLOR* = 3

+  HALFTONE* = 4

+  STRETCH_ANDSCANS* = 1

+  STRETCH_DELETESCANS* = 3

+  STRETCH_HALFTONE* = 4

+  STRETCH_ORSCANS* = 2

+  WHITEONBLACK* = 2

+  # SetSystemCursor

+  OCR_NORMAL* = 32512

+  OCR_IBEAM* = 32513

+  OCR_WAIT* = 32514

+  OCR_CROSS* = 32515

+  OCR_UP* = 32516

+  OCR_SIZE* = 32640

+  OCR_ICON* = 32641

+  OCR_SIZENWSE* = 32642

+  OCR_SIZENESW* = 32643

+  OCR_SIZEWE* = 32644

+  OCR_SIZENS* = 32645

+  OCR_SIZEALL* = 32646

+  OCR_NO* = 32648

+  OCR_APPSTARTING* = 32650

+  # SetTapePosition

+  TAPE_ABSOLUTE_BLOCK* = 0x00000001

+  TAPE_LOGICAL_BLOCK* = 0x00000002

+  TAPE_REWIND* = 0

+  TAPE_SPACE_END_OF_DATA* = 0x00000004

+  TAPE_SPACE_FILEMARKS* = 0x00000006

+  TAPE_SPACE_RELATIVE_BLOCKS* = 0x00000005

+  TAPE_SPACE_SEQUENTIAL_FMKS* = 0x00000007

+  TAPE_SPACE_SEQUENTIAL_SMKS* = 0x00000009

+  TAPE_SPACE_SETMARKS* = 0x00000008

+  # SetUnhandledExceptionFilter

+  EXCEPTION_EXECUTE_HANDLER* = 1

+  EXCEPTION_CONTINUE_EXECUTION* = -1

+  EXCEPTION_CONTINUE_SEARCH* = 0

+

+  # SetWindowPos, DeferWindowPos

+  HWND_BOTTOM* =    HWND(1)

+  HWND_NOTOPMOST* = HWND(-2)

+  HWND_TOP* =       HWND(0)

+  HWND_TOPMOST* =   HWND(-1)

+

+const

+  SWP_DRAWFRAME* = 32

+  SWP_FRAMECHANGED* = 32

+  SWP_HIDEWINDOW* = 128

+  SWP_NOACTIVATE* = 16

+  SWP_NOCOPYBITS* = 256

+  SWP_NOMOVE* = 2

+  SWP_NOSIZE* = 1

+  SWP_NOREDRAW* = 8

+  SWP_NOZORDER* = 4

+  SWP_SHOWWINDOW* = 64

+  SWP_NOOWNERZORDER* = 512

+  SWP_NOREPOSITION* = 512

+  SWP_NOSENDCHANGING* = 1024

+  # SHAddToRecentDocs

+  # SHAppBarMessage

+  # SHChangeNotify

+  # ShellProc

+  HSHELL_ACTIVATESHELLWINDOW* = 3

+  HSHELL_GETMINRECT* = 5

+  HSHELL_LANGUAGE* = 8

+  HSHELL_REDRAW* = 6

+  HSHELL_TASKMAN* = 7

+  HSHELL_WINDOWACTIVATED* = 4

+  HSHELL_WINDOWCREATED* = 1

+  HSHELL_WINDOWDESTROYED* = 2

+  # SHGetFileInfo

+  # SHGetSpecialFolderLocation

+  # ShowWindow

+  SW_HIDE* = 0

+  SW_MAXIMIZE* = 3

+  SW_MINIMIZE* = 6

+  SW_NORMAL* = 1

+  SW_RESTORE* = 9

+  SW_SHOW* = 5

+  SW_SHOWDEFAULT* = 10

+  SW_SHOWMAXIMIZED* = 3

+  SW_SHOWMINIMIZED* = 2

+  SW_SHOWMINNOACTIVE* = 7

+  SW_SHOWNA* = 8

+  SW_SHOWNOACTIVATE* = 4

+  SW_SHOWNORMAL* = 1

+  WPF_RESTORETOMAXIMIZED* = 2

+  WPF_SETMINPOSITION* = 1

+  # Sleep

+  INFINITE* = -1'i32

+  # SystemParametersInfo

+  SPI_GETBEEP* = 1

+  SPI_SETBEEP* = 2

+  SPI_GETMOUSE* = 3

+  SPI_SETMOUSE* = 4

+  SPI_GETBORDER* = 5

+  SPI_SETBORDER* = 6

+  SPI_GETKEYBOARDSPEED* = 10

+  SPI_SETKEYBOARDSPEED* = 11

+  SPI_LANGDRIVER* = 12

+  SPI_ICONHORIZONTALSPACING* = 13

+  SPI_GETSCREENSAVETIMEOUT* = 14

+  SPI_SETSCREENSAVETIMEOUT* = 15

+  SPI_GETSCREENSAVEACTIVE* = 16

+  SPI_SETSCREENSAVEACTIVE* = 17

+  SPI_GETGRIDGRANULARITY* = 18

+  SPI_SETGRIDGRANULARITY* = 19

+  SPI_SETDESKWALLPAPER* = 20

+  SPI_SETDESKPATTERN* = 21

+  SPI_GETKEYBOARDDELAY* = 22

+  SPI_SETKEYBOARDDELAY* = 23

+  SPI_ICONVERTICALSPACING* = 24

+  SPI_GETICONTITLEWRAP* = 25

+  SPI_SETICONTITLEWRAP* = 26

+  SPI_GETMENUDROPALIGNMENT* = 27

+  SPI_SETMENUDROPALIGNMENT* = 28

+  SPI_SETDOUBLECLKWIDTH* = 29

+  SPI_SETDOUBLECLKHEIGHT* = 30

+  SPI_GETICONTITLELOGFONT* = 31

+  SPI_SETDOUBLECLICKTIME* = 32

+  SPI_SETMOUSEBUTTONSWAP* = 33

+  SPI_SETICONTITLELOGFONT* = 34

+  SPI_GETFASTTASKSWITCH* = 35

+  SPI_SETFASTTASKSWITCH* = 36

+  SPI_SETDRAGFULLWINDOWS* = 37

+  SPI_GETDRAGFULLWINDOWS* = 38

+  SPI_GETNONCLIENTMETRICS* = 41

+  SPI_SETNONCLIENTMETRICS* = 42

+

+  SPI_GETMINIMIZEDMETRICS* = 43

+  SPI_SETMINIMIZEDMETRICS* = 44

+  SPI_GETICONMETRICS* = 45

+  SPI_SETICONMETRICS* = 46

+  SPI_SETWORKAREA* = 47

+  SPI_GETWORKAREA* = 48

+  SPI_SETPENWINDOWS* = 49

+  SPI_GETFILTERKEYS* = 50

+  SPI_SETFILTERKEYS* = 51

+  SPI_GETTOGGLEKEYS* = 52

+  SPI_SETTOGGLEKEYS* = 53

+  SPI_GETMOUSEKEYS* = 54

+  SPI_SETMOUSEKEYS* = 55

+  SPI_GETSHOWSOUNDS* = 56

+  SPI_SETSHOWSOUNDS* = 57

+  SPI_GETSTICKYKEYS* = 58

+  SPI_SETSTICKYKEYS* = 59

+  SPI_GETACCESSTIMEOUT* = 60

+  SPI_SETACCESSTIMEOUT* = 61

+  SPI_GETSERIALKEYS* = 62

+  SPI_SETSERIALKEYS* = 63

+  SPI_GETSOUNDSENTRY* = 64

+  SPI_SETSOUNDSENTRY* = 65

+  SPI_GETHIGHCONTRAST* = 66

+  SPI_SETHIGHCONTRAST* = 67

+  SPI_GETKEYBOARDPREF* = 68

+  SPI_SETKEYBOARDPREF* = 69

+  SPI_GETSCREENREADER* = 70

+  SPI_SETSCREENREADER* = 71

+  SPI_GETANIMATION* = 72

+  SPI_SETANIMATION* = 73

+  SPI_GETFONTSMOOTHING* = 74

+  SPI_SETFONTSMOOTHING* = 75

+  SPI_SETDRAGWIDTH* = 76

+  SPI_SETDRAGHEIGHT* = 77

+  SPI_SETHANDHELD* = 78

+  SPI_GETLOWPOWERTIMEOUT* = 79

+  SPI_GETPOWEROFFTIMEOUT* = 80

+  SPI_SETLOWPOWERTIMEOUT* = 81

+  SPI_SETPOWEROFFTIMEOUT* = 82

+  SPI_GETLOWPOWERACTIVE* = 83

+  SPI_GETPOWEROFFACTIVE* = 84

+  SPI_SETLOWPOWERACTIVE* = 85

+  SPI_SETPOWEROFFACTIVE* = 86

+  SPI_SETCURSORS* = 87

+  SPI_SETICONS* = 88

+  SPI_GETDEFAULTINPUTLANG* = 89

+  SPI_SETDEFAULTINPUTLANG* = 90

+  SPI_SETLANGTOGGLE* = 91

+  SPI_GETWINDOWSEXTENSION* = 92

+  SPI_SETMOUSETRAILS* = 93

+  SPI_GETMOUSETRAILS* = 94

+  SPI_GETSNAPTODEFBUTTON* = 95

+  SPI_SETSNAPTODEFBUTTON* = 96

+  SPI_SCREENSAVERRUNNING* = 97

+  SPI_SETSCREENSAVERRUNNING* = 97

+  SPI_GETMOUSEHOVERWIDTH* = 98

+  SPI_SETMOUSEHOVERWIDTH* = 99

+  SPI_GETMOUSEHOVERHEIGHT* = 100

+  SPI_SETMOUSEHOVERHEIGHT* = 101

+  SPI_GETMOUSEHOVERTIME* = 102

+  SPI_SETMOUSEHOVERTIME* = 103

+  SPI_GETWHEELSCROLLLINES* = 104

+  SPI_SETWHEELSCROLLLINES* = 105

+  SPI_GETMENUSHOWDELAY* = 106

+  SPI_SETMENUSHOWDELAY* = 107

+  SPI_GETSHOWIMEUI* = 110

+  SPI_SETSHOWIMEUI* = 111

+  # Windows Me/2000 and higher

+  SPI_GETMOUSESPEED* = 112

+  SPI_SETMOUSESPEED* = 113

+  SPI_GETSCREENSAVERRUNNING* = 114

+  SPI_GETDESKWALLPAPER* = 115

+  SPI_GETACTIVEWINDOWTRACKING* = 4096

+  SPI_SETACTIVEWINDOWTRACKING* = 4097

+  SPI_GETMENUANIMATION* = 4098

+  SPI_SETMENUANIMATION* = 4099

+  SPI_GETCOMBOBOXANIMATION* = 4100

+  SPI_SETCOMBOBOXANIMATION* = 4101

+  SPI_GETLISTBOXSMOOTHSCROLLING* = 4102

+  SPI_SETLISTBOXSMOOTHSCROLLING* = 4103

+  SPI_GETGRADIENTCAPTIONS* = 4104

+  SPI_SETGRADIENTCAPTIONS* = 4105

+  SPI_GETKEYBOARDCUES* = 4106

+  SPI_SETKEYBOARDCUES* = 4107

+  SPI_GETMENUUNDERLINES* = 4106

+  SPI_SETMENUUNDERLINES* = 4107

+  SPI_GETACTIVEWNDTRKZORDER* = 4108

+  SPI_SETACTIVEWNDTRKZORDER* = 4109

+  SPI_GETHOTTRACKING* = 4110

+  SPI_SETHOTTRACKING* = 4111

+  SPI_GETMENUFADE* = 4114

+  SPI_SETMENUFADE* = 4115

+  SPI_GETSELECTIONFADE* = 4116

+  SPI_SETSELECTIONFADE* = 4117

+  SPI_GETTOOLTIPANIMATION* = 4118

+  SPI_SETTOOLTIPANIMATION* = 4119

+  SPI_GETTOOLTIPFADE* = 4120

+  SPI_SETTOOLTIPFADE* = 4121

+  SPI_GETCURSORSHADOW* = 4122

+  SPI_SETCURSORSHADOW* = 4123

+  SPI_GETUIEFFECTS* = 4158

+  SPI_SETUIEFFECTS* = 4159

+  SPI_GETFOREGROUNDLOCKTIMEOUT* = 8192

+  SPI_SETFOREGROUNDLOCKTIMEOUT* = 8193

+  SPI_GETACTIVEWNDTRKTIMEOUT* = 8194

+  SPI_SETACTIVEWNDTRKTIMEOUT* = 8195

+  SPI_GETFOREGROUNDFLASHCOUNT* = 8196

+  SPI_SETFOREGROUNDFLASHCOUNT* = 8197

+  SPI_GETCARETWIDTH* = 8198

+  SPI_SETCARETWIDTH* = 8199

+  # Windows XP and higher

+  SPI_GETMOUSESONAR* = 4124

+  SPI_SETMOUSESONAR* = 4125

+  SPI_GETMOUSECLICKLOCK* = 4126

+  SPI_SETMOUSECLICKLOCK* = 4127

+  SPI_GETMOUSEVANISH* = 4128

+  SPI_SETMOUSEVANISH* = 4129

+  SPI_GETFLATMENU* = 4130

+  SPI_SETFLATMENU* = 4131

+  SPI_GETDROPSHADOW* = 4132

+  SPI_SETDROPSHADOW* = 4133

+  SPI_GETBLOCKSENDINPUTRESETS* = 4134

+  SPI_SETBLOCKSENDINPUTRESETS* = 4135

+  SPI_GETMOUSECLICKLOCKTIME* = 8200

+  SPI_SETMOUSECLICKLOCKTIME* = 8201

+  SPI_GETFONTSMOOTHINGTYPE* = 8202

+  SPI_SETFONTSMOOTHINGTYPE* = 8203

+  SPI_GETFONTSMOOTHINGCONTRAST* = 8204

+  SPI_SETFONTSMOOTHINGCONTRAST* = 8205

+  SPI_GETFOCUSBORDERWIDTH* = 8206

+  SPI_SETFOCUSBORDERWIDTH* = 8207

+  SPI_GETFOCUSBORDERHEIGHT* = 8208

+  SPI_SETFOCUSBORDERHEIGHT* = 8209

+  SPI_GETFONTSMOOTHINGORIENTATION* = 8210

+  SPI_SETFONTSMOOTHINGORIENTATION* = 8211

+  # constants for SPI_GETFONTSMOOTHINGTYPE and SPI_SETFONTSMOOTHINGTYPE:

+  FE_FONTSMOOTHINGSTANDARD* = 1

+  FE_FONTSMOOTHINGCLEARTYPE* = 2

+  FE_FONTSMOOTHINGDOCKING* = 32768

+  # constants for SPI_GETFONTSMOOTHINGORIENTATION and SPI_SETFONTSMOOTHINGORIENTATION:

+  FE_FONTSMOOTHINGORIENTATIONBGR* = 0

+  FE_FONTSMOOTHINGORIENTATIONRGB* = 1

+  # Flags

+  SPIF_UPDATEINIFILE* = 1

+  SPIF_SENDWININICHANGE* = 2

+  SPIF_SENDCHANGE* = 2

+  # TrackPopupMenu, TrackPopMenuEx

+  TPM_CENTERALIGN* = 0x00000004

+  TPM_LEFTALIGN* = 0

+  TPM_RIGHTALIGN* = 0x00000008

+  TPM_LEFTBUTTON* = 0

+  TPM_RIGHTBUTTON* = 0x00000002

+  TPM_HORIZONTAL* = 0

+  TPM_VERTICAL* = 0x00000040

+  # TranslateCharsetInfo

+  TCI_SRCCHARSET* = 1

+  TCI_SRCCODEPAGE* = 2

+  TCI_SRCFONTSIG* = 3

+  # VerFindFile

+  VFFF_ISSHAREDFILE* = 1

+  VFF_CURNEDEST* = 1

+  VFF_FILEINUSE* = 2

+  VFF_BUFFTOOSMALL* = 4

+  # VerInstallFile

+  VIFF_FORCEINSTALL* = 1

+  VIFF_DONTDELETEOLD* = 2

+  VIF_TEMPFILE* = 0x00000001

+  VIF_MISMATCH* = 0x00000002

+  VIF_SRCOLD* = 0x00000004

+  VIF_DIFFLANG* = 0x00000008

+  VIF_DIFFCODEPG* = 0x00000010

+  VIF_DIFFTYPE* = 0x00000020

+  VIF_WRITEPROT* = 0x00000040

+  VIF_FILEINUSE* = 0x00000080

+  VIF_OUTOFSPACE* = 0x00000100

+  VIF_ACCESSVIOLATION* = 0x00000200

+  VIF_SHARINGVIOLATION* = 0x00000400

+  VIF_CANNOTCREATE* = 0x00000800

+  VIF_CANNOTDELETE* = 0x00001000

+  VIF_CANNOTDELETECUR* = 0x00004000

+  VIF_CANNOTRENAME* = 0x00002000

+  VIF_OUTOFMEMORY* = 0x00008000

+  VIF_CANNOTREADSRC* = 0x00010000

+  VIF_CANNOTREADDST* = 0x00020000

+  VIF_BUFFTOOSMALL* = 0x00040000

+  # WideCharToMultiByte

+  WC_COMPOSITECHECK* = 512

+  WC_DISCARDNS* = 16

+  WC_SEPCHARS* = 32

+  WC_DEFAULTCHAR* = 64

+  # WinHelp

+  HELP_COMMAND* = 0x00000102

+  HELP_CONTENTS* = 0x00000003

+  HELP_CONTEXT* = 0x00000001

+  HELP_CONTEXTPOPUP* = 0x00000008

+  HELP_FORCEFILE* = 0x00000009

+  HELP_HELPONHELP* = 0x00000004

+  HELP_INDEX* = 0x00000003

+  HELP_KEY* = 0x00000101

+  HELP_MULTIKEY* = 0x00000201

+  HELP_PARTIALKEY* = 0x00000105

+  HELP_QUIT* = 0x00000002

+  HELP_SETCONTENTS* = 0x00000005

+  HELP_SETINDEX* = 0x00000005

+  HELP_CONTEXTMENU* = 0x0000000A

+  HELP_FINDER* = 0x0000000B

+  HELP_WM_HELP* = 0x0000000C

+  HELP_TCARD* = 0x00008000

+  HELP_TCARD_DATA* = 0x00000010

+  HELP_TCARD_OTHER_CALLER* = 0x00000011

+  # WNetAddConnectino2

+  CONNECT_UPDATE_PROFILE* = 1

+  # WNetConnectionDialog, WNetDisconnectDialog, WNetOpenEnum

+  RESOURCETYPE_DISK* = 1

+  RESOURCETYPE_PRINT* = 2

+  RESOURCETYPE_ANY* = 0

+  RESOURCE_CONNECTED* = 1

+  RESOURCE_GLOBALNET* = 2

+  RESOURCE_REMEMBERED* = 3

+  RESOURCEUSAGE_CONNECTABLE* = 1

+  RESOURCEUSAGE_CONTAINER* = 2

+  # WNetGetResourceInformation, WNetGetResourceParent

+  WN_BAD_NETNAME* = 0x00000043

+  WN_EXTENDED_ERROR* = 0x000004B8

+  WN_MORE_DATA* = 0x000000EA

+  WN_NO_NETWORK* = 0x000004C6

+  WN_SUCCESS* = 0

+  WN_ACCESS_DENIED* = 0x00000005

+  WN_BAD_PROVIDER* = 0x000004B4

+  WN_NOT_AUTHENTICATED* = 0x000004DC

+  # WNetGetUniversalName

+  UNIVERSAL_NAME_INFO_LEVEL* = 1

+  REMOTE_NAME_INFO_LEVEL* = 2

+  # GetExitCodeThread

+  STILL_ACTIVE* = 0x00000103

+  # COMMPROP structure

+  SP_SERIALCOMM* = 0x00000001

+  BAUD_075* = 0x00000001

+  BAUD_110* = 0x00000002

+  BAUD_134_5* = 0x00000004

+  BAUD_150* = 0x00000008

+  BAUD_300* = 0x00000010

+  BAUD_600* = 0x00000020

+  BAUD_1200* = 0x00000040

+  BAUD_1800* = 0x00000080

+  BAUD_2400* = 0x00000100

+  BAUD_4800* = 0x00000200

+  BAUD_7200* = 0x00000400

+  BAUD_9600* = 0x00000800

+  BAUD_14400* = 0x00001000

+  BAUD_19200* = 0x00002000

+  BAUD_38400* = 0x00004000

+  BAUD_56K* = 0x00008000

+  BAUD_57600* = 0x00040000

+  BAUD_115200* = 0x00020000

+  BAUD_128K* = 0x00010000

+  BAUD_USER* = 0x10000000

+  PST_FAX* = 0x00000021

+  PST_LAT* = 0x00000101

+  PST_MODEM* = 0x00000006

+  PST_NETWORK_BRIDGE* = 0x00000100

+  PST_PARALLELPORT* = 0x00000002

+  PST_RS232* = 0x00000001

+  PST_RS422* = 0x00000003

+  PST_RS423* = 0x00000004

+  PST_RS449* = 0x00000005

+  PST_SCANNER* = 0x00000022

+  PST_TCPIP_TELNET* = 0x00000102

+  PST_UNSPECIFIED* = 0

+  PST_X25* = 0x00000103

+  PCF_16BITMODE* = 0x00000200

+  PCF_DTRDSR* = 0x00000001

+  PCF_INTTIMEOUTS* = 0x00000080

+  PCF_PARITY_CHECK* = 0x00000008

+  PCF_RLSD* = 0x00000004

+  PCF_RTSCTS* = 0x00000002

+  PCF_SETXCHAR* = 0x00000020

+  PCF_SPECIALCHARS* = 0x00000100

+  PCF_TOTALTIMEOUTS* = 0x00000040

+  PCF_XONXOFF* = 0x00000010

+  SP_BAUD* = 0x00000002

+  SP_DATABITS* = 0x00000004

+  SP_HANDSHAKING* = 0x00000010

+  SP_PARITY* = 0x00000001

+  SP_PARITY_CHECK* = 0x00000020

+  SP_RLSD* = 0x00000040

+  SP_STOPBITS* = 0x00000008

+  DATABITS_5* = 1

+  DATABITS_6* = 2

+  DATABITS_7* = 4

+  DATABITS_8* = 8

+  DATABITS_16* = 16

+  DATABITS_16X* = 32

+  STOPBITS_10* = 1

+  STOPBITS_15* = 2

+  STOPBITS_20* = 4

+  PARITY_NONE* = 256

+  PARITY_ODD* = 512

+  PARITY_EVEN* = 1024

+  PARITY_MARK* = 2048

+  PARITY_SPACE* = 4096

+  COMMPROP_INITIALIZED* = 0xE73CF52E

+  # DCB structure

+  CBR_110* = 110

+  CBR_300* = 300

+  CBR_600* = 600

+  CBR_1200* = 1200

+  CBR_2400* = 2400

+  CBR_4800* = 4800

+  CBR_9600* = 9600

+  CBR_14400* = 14400

+  CBR_19200* = 19200

+  CBR_38400* = 38400

+  CBR_56000* = 56000

+  CBR_57600* = 57600

+  CBR_115200* = 115200

+  CBR_128000* = 128000

+  CBR_256000* = 256000

+  DTR_CONTROL_DISABLE* = 0

+  DTR_CONTROL_ENABLE* = 1

+  DTR_CONTROL_HANDSHAKE* = 2

+  RTS_CONTROL_DISABLE* = 0

+  RTS_CONTROL_ENABLE* = 1

+  RTS_CONTROL_HANDSHAKE* = 2

+  RTS_CONTROL_TOGGLE* = 3

+  EVENPARITY* = 2

+  MARKPARITY* = 3

+  NOPARITY* = 0

+  ODDPARITY* = 1

+  SPACEPARITY* = 4

+  ONESTOPBIT* = 0

+  ONE5STOPBITS* = 1

+  TWOSTOPBITS* = 2

+  # Debugging events

+  CREATE_PROCESS_DEBUG_EVENT* = 3

+  CREATE_THREAD_DEBUG_EVENT* = 2

+  EXCEPTION_DEBUG_EVENT* = 1

+  EXIT_PROCESS_DEBUG_EVENT* = 5

+  EXIT_THREAD_DEBUG_EVENT* = 4

+  LOAD_DLL_DEBUG_EVENT* = 6

+  OUTPUT_DEBUG_STRING_EVENT* = 8

+  UNLOAD_DLL_DEBUG_EVENT* = 7

+  RIP_EVENT* = 9

+  # PROCESS_HEAP_ENTRY structure

+  PROCESS_HEAP_REGION* = 1

+  PROCESS_HEAP_UNCOMMITTED_RANGE* = 2

+  PROCESS_HEAP_ENTRY_BUSY* = 4

+  PROCESS_HEAP_ENTRY_MOVEABLE* = 16

+  PROCESS_HEAP_ENTRY_DDESHARE* = 32

+  # Win32s

+  HINSTANCE_ERROR* = 32

+  # WIN32_STREAM_ID structure

+  BACKUP_DATA* = 1

+  BACKUP_EA_DATA* = 2

+  BACKUP_SECURITY_DATA* = 3

+  BACKUP_ALTERNATE_DATA* = 4

+  BACKUP_LINK* = 5

+  STREAM_MODIFIED_WHEN_READ* = 1

+  STREAM_CONTAINS_SECURITY* = 2

+  # STARTUPINFO structure

+  STARTF_USESHOWWINDOW* = 1

+  STARTF_USEPOSITION* = 4

+  STARTF_USESIZE* = 2

+  STARTF_USECOUNTCHARS* = 8

+  STARTF_USEFILLATTRIBUTE* = 16

+  STARTF_RUNFULLSCREEN* = 32

+  STARTF_FORCEONFEEDBACK* = 64

+  STARTF_FORCEOFFFEEDBACK* = 128

+  STARTF_USESTDHANDLES* = 256

+  STARTF_USEHOTKEY* = 512

+  # OSVERSIONINFO structure

+  VER_PLATFORM_WIN32s* = 0

+  VER_PLATFORM_WIN32_WINDOWS* = 1

+  VER_PLATFORM_WIN32_NT* = 2

+  # More versions

+  VER_SERVER_NT* = 0x80000000

+  VER_WORKSTATION_NT* = 0x40000000

+  VER_SUITE_SMALLBUSINESS* = 0x00000001

+  VER_SUITE_ENTERPRISE* = 0x00000002

+  VER_SUITE_BACKOFFICE* = 0x00000004

+  VER_SUITE_COMMUNICATIONS* = 0x00000008

+  VER_SUITE_TERMINAL* = 0x00000010

+  VER_SUITE_SMALLBUSINESS_RESTRICTED* = 0x00000020

+  VER_SUITE_EMBEDDEDNT* = 0x00000040

+  VER_SUITE_DATACENTER* = 0x00000080

+  VER_SUITE_SINGLEUSERTS* = 0x00000100

+  VER_SUITE_PERSONAL* = 0x00000200

+  VER_SUITE_BLADE* = 0x00000400

+  VER_SUITE_EMBEDDED_RESTRICTED* = 0x00000800

+  # PROPSHEETPAGE structure

+  MAXPROPPAGES* = 100

+  PSP_DEFAULT* = 0

+  PSP_DLGINDIRECT* = 1

+  PSP_HASHELP* = 32

+  PSP_USECALLBACK* = 128

+  PSP_USEHICON* = 2

+  PSP_USEICONID* = 4

+  PSP_USEREFPARENT* = 64

+  PSP_USETITLE* = 8

+  PSP_RTLREADING* = 16

+  # PROPSHEETHEADER structure

+  PSH_DEFAULT* = 0

+  PSH_HASHELP* = 512

+  PSH_MODELESS* = 1024

+  PSH_NOAPPLYNOW* = 128

+  PSH_PROPSHEETPAGE* = 8

+  PSH_PROPTITLE* = 1

+  PSH_USECALLBACK* = 256

+  PSH_USEHICON* = 2

+  PSH_USEICONID* = 4

+  PSH_USEPSTARTPAGE* = 64

+  PSH_WIZARD* = 32

+  PSH_RTLREADING* = 2048

+  PSCB_INITIALIZED* = 1

+  PSCB_PRECREATE* = 2

+  # PSN_APPLY message

+  PSNRET_NOERROR* = 0

+  PSNRET_INVALID_NOCHANGEPAGE* = 2

+  # Property Sheet

+  PSBTN_APPLYNOW* = 4

+  PSBTN_BACK* = 0

+  PSBTN_CANCEL* = 5

+  PSBTN_FINISH* = 2

+  PSBTN_HELP* = 6

+  PSBTN_NEXT* = 1

+  PSBTN_OK* = 3

+  PSWIZB_BACK* = 1

+  PSWIZB_NEXT* = 2

+  PSWIZB_FINISH* = 4

+  PSWIZB_DISABLEDFINISH* = 8

+  ID_PSREBOOTSYSTEM* = 3

+  ID_PSRESTARTWINDOWS* = 2

+  WIZ_BODYCX* = 184

+  WIZ_BODYX* = 92

+  WIZ_CXBMP* = 80

+  WIZ_CXDLG* = 276

+  WIZ_CYDLG* = 140

+

+  # VX_FIXEDFILEINFO structure

+  VS_FILE_INFO* = cast[MAKEINTRESOURCE](16)

+

+const

+  VS_VERSION_INFO* = 1

+  VS_FF_DEBUG* = 0x00000001

+  VS_FF_INFOINFERRED* = 0x00000010

+  VS_FF_PATCHED* = 0x00000004

+  VS_FF_PRERELEASE* = 0x00000002

+  VS_FF_PRIVATEBUILD* = 0x00000008

+  VS_FF_SPECIALBUILD* = 0x00000020

+  VOS_UNKNOWN* = 0

+  VOS_DOS* = 0x00010000

+  VOS_OS216* = 0x00020000

+  VOS_OS232* = 0x00030000

+  VOS_NT* = 0x00040000

+  VOS_DOS_WINDOWS16* = 0x00010001

+  VOS_DOS_WINDOWS32* = 0x00010004

+  VOS_OS216_PM16* = 0x00020002

+  VOS_OS232_PM32* = 0x00030003

+  VOS_NT_WINDOWS32* = 0x00040004

+  VFT_UNKNOWN* = 0

+  VFT_APP* = 0x00000001

+  VFT_DLL* = 0x00000002

+  VFT_DRV* = 0x00000003

+  VFT_FONT* = 0x00000004

+  VFT_VXD* = 0x00000005

+  VFT_STATIC_LIB* = 0x00000007

+  VFT2_UNKNOWN* = 0

+  VFT2_DRV_PRINTER* = 0x00000001

+  VFT2_DRV_KEYBOARD* = 0x00000002

+  VFT2_DRV_LANGUAGE* = 0x00000003

+  VFT2_DRV_DISPLAY* = 0x00000004

+  VFT2_DRV_MOUSE* = 0x00000005

+  VFT2_DRV_NETWORK* = 0x00000006

+  VFT2_DRV_SYSTEM* = 0x00000007

+  VFT2_DRV_INSTALLABLE* = 0x00000008

+  VFT2_DRV_SOUND* = 0x00000009

+  VFT2_FONT_RASTER* = 0x00000001

+  VFT2_FONT_VECTOR* = 0x00000002

+  VFT2_FONT_TRUETYPE* = 0x00000003

+  # PANOSE structure

+  PAN_ANY* = 0

+  PAN_NO_FIT* = 1

+  PAN_FAMILY_TEXT_DISPLAY* = 2

+  PAN_FAMILY_SCRIPT* = 3

+  PAN_FAMILY_DECORATIVE* = 4

+  PAN_FAMILY_PICTORIAL* = 5

+  PAN_SERIF_COVE* = 2

+  PAN_SERIF_OBTUSE_COVE* = 3

+  PAN_SERIF_SQUARE_COVE* = 4

+  PAN_SERIF_OBTUSE_SQUARE_COVE* = 5

+  PAN_SERIF_SQUARE* = 6

+  PAN_SERIF_THIN* = 7

+  PAN_SERIF_BONE* = 8

+  PAN_SERIF_EXAGGERATED* = 9

+  PAN_SERIF_TRIANGLE* = 10

+  PAN_SERIF_NORMAL_SANS* = 11

+  PAN_SERIF_OBTUSE_SANS* = 12

+  PAN_SERIF_PERP_SANS* = 13

+  PAN_SERIF_FLARED* = 14

+  PAN_SERIF_ROUNDED* = 15

+  PAN_WEIGHT_VERY_LIGHT* = 2

+  PAN_WEIGHT_LIGHT* = 3

+  PAN_WEIGHT_THIN* = 4

+  PAN_WEIGHT_BOOK* = 5

+  PAN_WEIGHT_MEDIUM* = 6

+  PAN_WEIGHT_DEMI* = 7

+  PAN_WEIGHT_BOLD* = 8

+  PAN_WEIGHT_HEAVY* = 9

+  PAN_WEIGHT_BLACK* = 10

+  PAN_WEIGHT_NORD* = 11

+  PAN_PROP_OLD_STYLE* = 2

+  PAN_PROP_MODERN* = 3

+  PAN_PROP_EVEN_WIDTH* = 4

+  PAN_PROP_EXPANDED* = 5

+  PAN_PROP_CONDENSED* = 6

+  PAN_PROP_VERY_EXPANDED* = 7

+  PAN_PROP_VERY_CONDENSED* = 8

+  PAN_PROP_MONOSPACED* = 9

+  PAN_CONTRAST_NONE* = 2

+  PAN_CONTRAST_VERY_LOW* = 3

+  PAN_CONTRAST_LOW* = 4

+  PAN_CONTRAST_MEDIUM_LOW* = 5

+  PAN_CONTRAST_MEDIUM* = 6

+  PAN_CONTRAST_MEDIUM_HIGH* = 7

+  PAN_CONTRAST_HIGH* = 8

+  PAN_CONTRAST_VERY_HIGH* = 9

+  PAN_STROKE_GRADUAL_DIAG* = 2

+  PAN_STROKE_GRADUAL_TRAN* = 3

+  PAN_STROKE_GRADUAL_VERT* = 4

+  PAN_STROKE_GRADUAL_HORZ* = 5

+  PAN_STROKE_RAPID_VERT* = 6

+  PAN_STROKE_RAPID_HORZ* = 7

+  PAN_STROKE_INSTANT_VERT* = 8

+  PAN_STRAIGHT_ARMS_HORZ* = 2

+  PAN_STRAIGHT_ARMS_WEDGE* = 3

+  PAN_STRAIGHT_ARMS_VERT* = 4

+  PAN_STRAIGHT_ARMS_SINGLE_SERIF* = 5

+  PAN_STRAIGHT_ARMS_DOUBLE_SERIF* = 6

+  PAN_BENT_ARMS_HORZ* = 7

+  PAN_BENT_ARMS_VERT* = 9

+  PAN_BENT_ARMS_WEDGE* = 8

+  PAN_BENT_ARMS_SINGLE_SERIF* = 10

+  PAN_BENT_ARMS_DOUBLE_SERIF* = 11

+  PAN_LETT_NORMAL_CONTACT* = 2

+  PAN_LETT_NORMAL_WEIGHTED* = 3

+  PAN_LETT_NORMAL_BOXED* = 4

+  PAN_LETT_NORMAL_FLATTENED* = 5

+  PAN_LETT_NORMAL_ROUNDED* = 6

+  PAN_LETT_NORMAL_OFF_CENTER* = 7

+  PAN_LETT_NORMAL_SQUARE* = 8

+  PAN_LETT_OBLIQUE_CONTACT* = 9

+  PAN_LETT_OBLIQUE_WEIGHTED* = 10

+  PAN_LETT_OBLIQUE_BOXED* = 11

+  PAN_LETT_OBLIQUE_FLATTENED* = 12

+  PAN_LETT_OBLIQUE_ROUNDED* = 13

+  PAN_LETT_OBLIQUE_OFF_CENTER* = 14

+  PAN_LETT_OBLIQUE_SQUARE* = 15

+  PAN_MIDLINE_STANDARD_TRIMMED* = 2

+  PAN_MIDLINE_STANDARD_POINTED* = 3

+  PAN_MIDLINE_STANDARD_SERIFED* = 4

+  PAN_MIDLINE_HIGH_TRIMMED* = 5

+  PAN_MIDLINE_HIGH_POINTED* = 6

+  PAN_MIDLINE_HIGH_SERIFED* = 7

+  PAN_MIDLINE_CONSTANT_TRIMMED* = 8

+  PAN_MIDLINE_CONSTANT_POINTED* = 9

+  PAN_MIDLINE_CONSTANT_SERIFED* = 10

+  PAN_MIDLINE_LOW_TRIMMED* = 11

+  PAN_MIDLINE_LOW_POINTED* = 12

+  PAN_MIDLINE_LOW_SERIFED* = 13

+  PAN_XHEIGHT_CONSTANT_SMALL* = 2

+  PAN_XHEIGHT_CONSTANT_STD* = 3

+  PAN_XHEIGHT_CONSTANT_LARGE* = 4

+  PAN_XHEIGHT_DUCKING_SMALL* = 5

+  PAN_XHEIGHT_DUCKING_STD* = 6

+  PAN_XHEIGHT_DUCKING_LARGE* = 7

+  # PALETTENTRY structure

+  PC_EXPLICIT* = 2

+  PC_NOCOLLAPSE* = 4

+  PC_RESERVED* = 1

+  # LOGBRUSH structure

+  BS_DIBPATTERN* = 5

+  BS_DIBPATTERN8X8* = 8

+  BS_DIBPATTERNPT* = 6

+  BS_HATCHED* = 2

+  BS_HOLLOW* = 1

+  BS_NULL* = 1

+  BS_PATTERN* = 3

+  BS_PATTERN8X8* = 7

+  BS_SOLID* = 0

+  # DEVMODE structure, field selection bits

+  DM_ORIENTATION* = 0x00000001

+  DM_PAPERSIZE* = 0x00000002

+  DM_PAPERLENGTH* = 0x00000004

+  DM_PAPERWIDTH* = 0x00000008

+  DM_SCALE* = 0x00000010

+  DM_POSITION* = 0x00000020

+  DM_NUP* = 0x00000040

+  DM_DISPLAYORIENTATION* = 0x00000080

+  DM_COPIES* = 0x00000100

+  DM_DEFAULTSOURCE* = 0x00000200

+  DM_PRINTQUALITY* = 0x00000400

+  DM_COLOR* = 0x00000800

+  DM_DUPLEX* = 0x00001000

+  DM_YRESOLUTION* = 0x00002000

+  DM_TTOPTION* = 0x00004000

+  DM_COLLATE* = 0x00008000

+  DM_FORMNAME* = 0x00010000

+  DM_LOGPIXELS* = 0x00020000

+  DM_BITSPERPEL* = 0x00040000

+  DM_PELSWIDTH* = 0x00080000

+  DM_PELSHEIGHT* = 0x00100000

+  DM_DISPLAYFLAGS* = 0x00200000

+  DM_DISPLAYFREQUENCY* = 0x00400000

+  DM_ICMMETHOD* = 0x00800000

+  DM_ICMINTENT* = 0x01000000

+  DM_MEDIATYPE* = 0x02000000

+  DM_DITHERTYPE* = 0x04000000

+  DM_PANNINGWIDTH* = 0x08000000

+  DM_PANNINGHEIGHT* = 0x10000000

+  DM_DISPLAYFIXEDOUTPUT* = 0x20000000

+  # orientation selections

+  DMORIENT_LANDSCAPE* = 2

+  DMORIENT_PORTRAIT* = 1

+  # paper selections

+  DMPAPER_LETTER* = 1

+  DMPAPER_LEGAL* = 5

+  DMPAPER_A4* = 9

+  DMPAPER_CSHEET* = 24

+  DMPAPER_DSHEET* = 25

+  DMPAPER_ESHEET* = 26

+  DMPAPER_LETTERSMALL* = 2

+  DMPAPER_TABLOID* = 3

+  DMPAPER_LEDGER* = 4

+  DMPAPER_STATEMENT* = 6

+  DMPAPER_EXECUTIVE* = 7

+  DMPAPER_A3* = 8

+  DMPAPER_A4SMALL* = 10

+  DMPAPER_A5* = 11

+  DMPAPER_B4* = 12

+  DMPAPER_B5* = 13

+  DMPAPER_FOLIO* = 14

+  DMPAPER_QUARTO* = 15

+  DMPAPER_10X14* = 16

+  DMPAPER_11X17* = 17

+  DMPAPER_NOTE* = 18

+  DMPAPER_ENV_9* = 19

+  DMPAPER_ENV_10* = 20

+  DMPAPER_ENV_11* = 21

+  DMPAPER_ENV_12* = 22

+  DMPAPER_ENV_14* = 23

+  DMPAPER_ENV_DL* = 27

+  DMPAPER_ENV_C5* = 28

+  DMPAPER_ENV_C3* = 29

+  DMPAPER_ENV_C4* = 30

+  DMPAPER_ENV_C6* = 31

+  DMPAPER_ENV_C65* = 32

+  DMPAPER_ENV_B4* = 33

+  DMPAPER_ENV_B5* = 34

+  DMPAPER_ENV_B6* = 35

+  DMPAPER_ENV_ITALY* = 36

+  DMPAPER_ENV_MONARCH* = 37

+  DMPAPER_ENV_PERSONAL* = 38

+  DMPAPER_FANFOLD_US* = 39

+  DMPAPER_FANFOLD_STD_GERMAN* = 40

+  DMPAPER_FANFOLD_LGL_GERMAN* = 41

+  DMPAPER_ISO_B4* = 42

+  DMPAPER_JAPANESE_POSTCARD* = 43

+  DMPAPER_9X11* = 44

+  DMPAPER_10X11* = 45

+  DMPAPER_15X11* = 46

+  DMPAPER_ENV_INVITE* = 47

+  DMPAPER_RESERVED_48* = 48

+  DMPAPER_RESERVED_49* = 49

+  DMPAPER_LETTER_EXTRA* = 50

+  DMPAPER_LEGAL_EXTRA* = 51

+  DMPAPER_TABLOID_EXTRA* = 52

+  DMPAPER_A4_EXTRA* = 53

+  DMPAPER_LETTER_TRANSVERSE* = 54

+  DMPAPER_A4_TRANSVERSE* = 55

+  DMPAPER_LETTER_EXTRA_TRANSVERSE* = 56

+  DMPAPER_A_PLUS* = 57

+  DMPAPER_B_PLUS* = 58

+  DMPAPER_LETTER_PLUS* = 59

+  DMPAPER_A4_PLUS* = 60

+  DMPAPER_A5_TRANSVERSE* = 61

+  DMPAPER_B5_TRANSVERSE* = 62

+  DMPAPER_A3_EXTRA* = 63

+  DMPAPER_A5_EXTRA* = 64

+  DMPAPER_B5_EXTRA* = 65

+  DMPAPER_A2* = 66

+  DMPAPER_A3_TRANSVERSE* = 67

+  DMPAPER_A3_EXTRA_TRANSVERSE* = 68

+  DMPAPER_DBL_JAPANESE_POSTCARD* = 69

+  DMPAPER_A6* = 70

+  DMPAPER_JENV_KAKU2* = 71

+  DMPAPER_JENV_KAKU3* = 72

+  DMPAPER_JENV_CHOU3* = 73

+  DMPAPER_JENV_CHOU4* = 74

+  DMPAPER_LETTER_ROTATED* = 75

+  DMPAPER_A3_ROTATED* = 76

+  DMPAPER_A4_ROTATED* = 77

+  DMPAPER_A5_ROTATED* = 78

+  DMPAPER_B4_JIS_ROTATED* = 79

+  DMPAPER_B5_JIS_ROTATED* = 80

+  DMPAPER_JAPANESE_POSTCARD_ROTATED* = 81

+  DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED* = 82

+  DMPAPER_A6_ROTATED* = 83

+  DMPAPER_JENV_KAKU2_ROTATED* = 84

+  DMPAPER_JENV_KAKU3_ROTATED* = 85

+  DMPAPER_JENV_CHOU3_ROTATED* = 86

+  DMPAPER_JENV_CHOU4_ROTATED* = 87

+  DMPAPER_B6_JIS* = 88

+  DMPAPER_B6_JIS_ROTATED* = 89

+  DMPAPER_12X11* = 90

+  DMPAPER_JENV_YOU4* = 91

+  DMPAPER_JENV_YOU4_ROTATED* = 92

+  DMPAPER_P16K* = 93

+  DMPAPER_P32K* = 94

+  DMPAPER_P32KBIG* = 95

+  DMPAPER_PENV_1* = 96

+  DMPAPER_PENV_2* = 97

+  DMPAPER_PENV_3* = 98

+  DMPAPER_PENV_4* = 99

+  DMPAPER_PENV_5* = 100

+  DMPAPER_PENV_6* = 101

+  DMPAPER_PENV_7* = 102

+  DMPAPER_PENV_8* = 103

+  DMPAPER_PENV_9* = 104

+  DMPAPER_PENV_10* = 105

+  DMPAPER_P16K_ROTATED* = 106

+  DMPAPER_P32K_ROTATED* = 107

+  DMPAPER_P32KBIG_ROTATED* = 108

+  DMPAPER_PENV_1_ROTATED* = 109

+  DMPAPER_PENV_2_ROTATED* = 110

+  DMPAPER_PENV_3_ROTATED* = 111

+  DMPAPER_PENV_4_ROTATED* = 112

+  DMPAPER_PENV_5_ROTATED* = 113

+  DMPAPER_PENV_6_ROTATED* = 114

+  DMPAPER_PENV_7_ROTATED* = 115

+  DMPAPER_PENV_8_ROTATED* = 116

+  DMPAPER_PENV_9_ROTATED* = 117

+  DMPAPER_PENV_10_ROTATED* = 118

+  DMPAPER_USER* = 256

+  # bin selections

+  DMBIN_UPPER* = 1

+  DMBIN_ONLYONE* = 1

+  DMBIN_LOWER* = 2

+  DMBIN_MIDDLE* = 3

+  DMBIN_MANUAL* = 4

+  DMBIN_ENVELOPE* = 5

+  DMBIN_ENVMANUAL* = 6

+  DMBIN_AUTO* = 7

+  DMBIN_TRACTOR* = 8

+  DMBIN_SMALLFMT* = 9

+  DMBIN_LARGEFMT* = 10

+  DMBIN_LARGECAPACITY* = 11

+  DMBIN_CASSETTE* = 14

+  DMBIN_FORMSOURCE* = 15

+  DMBIN_USER* = 256

+  # print qualities

+  DMRES_DRAFT* = -1

+  DMRES_LOW* = -2

+  DMRES_MEDIUM* = -3

+  DMRES_HIGH* = -4

+  # color enable/disable for color printers

+  DMCOLOR_MONOCHROME* = 1

+  DMCOLOR_COLOR* = 2

+  # duplex enable

+  DMDUP_SIMPLEX* = 1

+  DMDUP_VERTICAL* = 2

+  DMDUP_HORIZONTAL* = 3

+  # TrueType options

+  DMTT_BITMAP* = 1

+  DMTT_DOWNLOAD* = 2

+  DMTT_SUBDEV* = 3

+  # Collation selections

+  DMCOLLATE_TRUE* = 1

+  DMCOLLATE_FALSE* = 0

+  # DEVMODE dmDisplayOrientation specifiations

+  DMDO_DEFAULT* = 0

+  DMDO_90* = 1

+  DMDO_180* = 2

+  DMDO_270* = 3

+  # DEVMODE dmDisplayFixedOutput specifiations

+  DMDFO_DEFAULT* = 0

+  DMDFO_STRETCH* = 1

+  DMDFO_CENTER* = 2

+  # Deprecated

+  #DM_GRAYSCALE* = 1

+  #DM_INTERLACED* = 2

+  DMDISPLAYFLAGS_TEXTMODE* = 0x00000004

+  # dmNup , multiple logical page per physical page options

+  DMNUP_SYSTEM* = 1

+  DMNUP_ONEUP* = 2

+  # ICM methods

+  DMICMMETHOD_NONE* = 1

+  DMICMMETHOD_SYSTEM* = 2

+  DMICMMETHOD_DRIVER* = 3

+  DMICMMETHOD_DEVICE* = 4

+  DMICMMETHOD_USER* = 256

+  # ICM Intents

+  DMICM_SATURATE* = 1

+  DMICM_CONTRAST* = 2

+  DMICM_COLORMETRIC* = 3

+  DMICM_USER* = 256

+  # Media types

+  DMMEDIA_STANDARD* = 1

+  DMMEDIA_TRANSPARENCY* = 2

+  DMMEDIA_GLOSSY* = 3

+  DMMEDIA_USER* = 256

+  # Dither types

+  DMDITHER_NONE* = 1

+  DMDITHER_COARSE* = 2

+  DMDITHER_FINE* = 3

+  DMDITHER_LINEART* = 4

+  DMDITHER_GRAYSCALE* = 10

+  DMDITHER_USER* = 256

+  # RGNDATAHEADER structure

+  RDH_RECTANGLES* = 1

+  # TTPOLYGONHEADER structure

+  TT_POLYGON_TYPE* = 24

+  # TTPOLYCURVE structure

+  TT_PRIM_LINE* = 1

+  TT_PRIM_QSPLINE* = 2

+  # GCP_RESULTS structure

+  GCPCLASS_ARABIC* = 2

+  GCPCLASS_HEBREW* = 2

+  GCPCLASS_LATIN* = 1

+  GCPCLASS_LATINNUMBER* = 5

+  GCPCLASS_LOCALNUMBER* = 4

+  GCPCLASS_LATINNUMERICSEPARATOR* = 7

+  GCPCLASS_LATINNUMERICTERMINATOR* = 6

+  GCPCLASS_NEUTRAL* = 3

+  GCPCLASS_NUMERICSEPARATOR* = 8

+  GCPCLASS_PREBOUNDLTR* = 128

+  GCPCLASS_PREBOUNDRTL* = 64

+  GCPCLASS_POSTBOUNDLTR* = 32

+  GCPCLASS_POSTBOUNDRTL* = 16

+  GCPGLYPH_LINKBEFORE* = 32768

+  GCPGLYPH_LINKAFTER* = 16384

+  # RASTERIZER_STATUS structure

+  TT_AVAILABLE* = 1

+  TT_ENABLED* = 2

+  # COLORADJUSTMENT structure

+  CA_NEGATIVE* = 1

+  CA_LOG_FILTER* = 2

+  ILLUMINANT_DEVICE_DEFAULT* = 0

+  ILLUMINANT_A* = 1

+  ILLUMINANT_B* = 2

+  ILLUMINANT_C* = 3

+  ILLUMINANT_D50* = 4

+  ILLUMINANT_D55* = 5

+  ILLUMINANT_D65* = 6

+  ILLUMINANT_D75* = 7

+  ILLUMINANT_F2* = 8

+  ILLUMINANT_TUNGSTEN* = 1

+  ILLUMINANT_DAYLIGHT* = 3

+  ILLUMINANT_FLUORESCENT* = 8

+  ILLUMINANT_NTSC* = 3

+  # DOCINFO structure

+  DI_APPBANDING* = 1

+  # EMRMETAHEADER structure

+  EMR_HEADER* = 1

+  ENHMETA_SIGNATURE* = 1179469088

+  # RTF event masks

+  ENM_CHANGE* = 1

+  ENM_CORRECTTEXT* = 4194304

+  ENM_DROPFILES* = 1048576

+  ENM_KEYEVENTS* = 65536

+  ENM_MOUSEEVENTS* = 131072

+  ENM_PROTECTED* = 2097152

+  ENM_REQUESTRESIZE* = 262144

+  ENM_SCROLL* = 4

+  ENM_SELCHANGE* = 524288

+  ENM_UPDATE* = 2

+  ENM_NONE* = 0

+  # RTF styles

+  ES_DISABLENOSCROLL* = 8192

+  ES_EX_NOCALLOLEINIT* = 16777216

+  ES_NOIME* = 524288

+  ES_SAVESEL* = 32768

+  ES_SELFIME* = 262144

+  ES_SUNKEN* = 16384

+  ES_VERTICAL* = 4194304

+  ES_SELECTIONBAR* = 16777216

+  # EM_SETOPTIONS message

+  ECOOP_SET* = 1

+  ECOOP_OR* = 2

+  ECOOP_AND* = 3

+  ECOOP_XOR* = 4

+  ECO_AUTOWORDSELECTION* = 1

+  ECO_AUTOVSCROLL* = 64

+  ECO_AUTOHSCROLL* = 128

+  ECO_NOHIDESEL* = 256

+  ECO_READONLY* = 2048

+  ECO_WANTRETURN* = 4096

+  ECO_SAVESEL* = 32768

+  ECO_SELECTIONBAR* = 16777216

+  ECO_VERTICAL* = 4194304

+  # EM_SETCHARFORMAT message

+  SCF_WORD* = 2

+  SCF_SELECTION* = 1

+  # EM_STREAMOUT message

+  SF_TEXT* = 1

+  SF_RTF* = 2

+  SF_RTFNOOBJS* = 3

+  SF_TEXTIZED* = 4

+  SFF_SELECTION* = 32768

+  SFF_PLAINRTF* = 16384

+  # EM_FINDWORDBREAK message

+  WB_CLASSIFY* = 3

+  #WB_ISDELIMITER = 2;

+  #     WB_LEFT = 0; already above

+  WB_LEFTBREAK* = 6

+  WB_PREVBREAK* = 6

+  WB_MOVEWORDLEFT* = 4

+  WB_MOVEWORDPREV* = 4

+  WB_MOVEWORDRIGHT* = 5

+  WB_MOVEWORDNEXT* = 5

+  #WB_RIGHT = 1;already above

+  WB_RIGHTBREAK* = 7

+  WB_NEXTBREAK* = 7

+  # EM_GETPUNCTUATION message

+  PC_LEADING* = 2

+  PC_FOLLOWING* = 1

+  PC_DELIMITER* = 4

+  PC_OVERFLOW* = 3

+  # EM_SETWORDWRAPMODE message

+  WBF_WORDWRAP* = 16

+  WBF_WORDBREAK* = 32

+  WBF_OVERFLOW* = 64

+  WBF_LEVEL1* = 128

+  WBF_LEVEL2* = 256

+  WBF_CUSTOM* = 512

+  WBF_BREAKAFTER* = 64

+  WBF_BREAKLINE* = 32

+  WBF_ISWHITE* = 16

+  # CHARFORMAT structure

+  CFM_BOLD* = 1

+  CFM_COLOR* = 1073741824

+  CFM_FACE* = 536870912

+  CFM_ITALIC* = 2

+  CFM_OFFSET* = 268435456

+  CFM_PROTECTED* = 16

+  CFM_SIZE* = 0x80000000

+  CFM_STRIKEOUT* = 8

+  CFM_UNDERLINE* = 4

+  CFE_AUTOCOLOR* = 1073741824

+  CFE_BOLD* = 1

+  CFE_ITALIC* = 2

+  CFE_STRIKEOUT* = 8

+  CFE_UNDERLINE* = 4

+  CFE_PROTECTED* = 16

+  # PARAFORMAT structure

+  PFM_ALIGNMENT* = 8

+  PFM_NUMBERING* = 32

+  PFM_OFFSET* = 4

+  PFM_OFFSETINDENT* = 0x80000000

+  PFM_RIGHTINDENT* = 2

+  PFM_STARTINDENT* = 1

+  PFM_TABSTOPS* = 16

+  PFN_BULLET* = 1

+  PFA_LEFT* = 1

+  PFA_RIGHT* = 2

+  PFA_CENTER* = 3

+  # SELCHANGE structure

+  SEL_EMPTY* = 0

+  SEL_TEXT* = 1

+  SEL_OBJECT* = 2

+  SEL_MULTICHAR* = 4

+  SEL_MULTIOBJECT* = 8

+  # RTF clipboard formats

+  CF_RTF* = "Rich Text Format"

+  CF_RETEXTOBJ* = "RichEdit Text and Objects"

+  # DRAWITEMSTRUCT structure

+  ODT_BUTTON* = 4

+  ODT_COMBOBOX* = 3

+  ODT_LISTBOX* = 2

+  ODT_LISTVIEW* = 102

+  ODT_MENU* = 1

+  ODT_STATIC* = 5

+  ODT_TAB* = 101

+  ODT_HEADER* = 100

+  ODA_DRAWENTIRE* = 1

+  ODA_FOCUS* = 4

+  ODA_SELECT* = 2

+  ODS_SELECTED* = 1

+  ODS_GRAYED* = 2

+  ODS_DISABLED* = 4

+  ODS_CHECKED* = 8

+  ODS_FOCUS* = 16

+  ODS_DEFAULT* = 32

+  ODS_HOTLIGHT* = 0x00000040

+  ODS_INACTIVE* = 0x00000080

+  ODS_NOACCEL* = 0x00000100

+  ODS_NOFOCUSRECT* = 0x00000200

+  ODS_COMBOBOXEDIT* = 0x00001000

+  # Common control styles

+  CCS_ADJUSTABLE* = 0x00000020

+  CCS_BOTTOM* = 0x00000003

+  CCS_NODIVIDER* = 0x00000040

+  CCS_NOMOVEY* = 0x00000002

+  CCS_NOPARENTALIGN* = 0x00000008

+  CCS_NORESIZE* = 0x00000004

+  CCS_TOP* = 0x00000001

+

+  # Common control window classes

+  ANIMATE_CLASSW* = "SysAnimate32"

+  HOTKEY_CLASSW* = "msctls_hotkey32"

+  PROGRESS_CLASSW* = "msctls_progress32"

+  STATUSCLASSNAMEW* = "msctls_statusbar32"

+  TOOLBARCLASSNAMEW* = "ToolbarWindow32"

+  TOOLTIPS_CLASSW* = "tooltips_class32"

+  TRACKBAR_CLASSW* = "msctls_trackbar32"

+  UPDOWN_CLASSW* = "msctls_updown32"

+  WC_HEADERW* = "SysHeader32"

+  WC_LISTVIEWW* = "SysListView32"

+  WC_TABCONTROLW* = "SysTabControl32"

+  WC_TREEVIEWW* = "SysTreeView32"

+

+  ANIMATE_CLASSA* = "SysAnimate32"

+  HOTKEY_CLASSA* = "msctls_hotkey32"

+  PROGRESS_CLASSA* = "msctls_progress32"

+  STATUSCLASSNAMEA* = "msctls_statusbar32"

+  TOOLBARCLASSNAMEA* = "ToolbarWindow32"

+  TOOLTIPS_CLASSA* = "tooltips_class32"

+  TRACKBAR_CLASSA* = "msctls_trackbar32"

+  UPDOWN_CLASSA* = "msctls_updown32"

+  WC_HEADERA* = "SysHeader32"

+  WC_LISTVIEWA* = "SysListView32"

+  WC_TABCONTROLA* = "SysTabControl32"

+  WC_TREEVIEWA* = "SysTreeView32"

+

+when defined(winUnicode):

+  const

+    ANIMATE_CLASS* = ANIMATE_CLASSW

+    HOTKEY_CLASS* = HOTKEY_CLASSW

+    PROGRESS_CLASS* = PROGRESS_CLASSW

+    STATUSCLASSNAME* = STATUSCLASSNAMEW

+    TOOLBARCLASSNAME* = TOOLBARCLASSNAMEW

+    TOOLTIPS_CLASS* = TOOLTIPS_CLASSW

+    TRACKBAR_CLASS* = TRACKBAR_CLASSW

+    UPDOWN_CLASS* = UPDOWN_CLASSW

+    WC_HEADER* = WC_HEADERW

+    WC_LISTVIEW* = WC_LISTVIEWW

+    WC_TABCONTROL* = WC_TABCONTROLW

+    WC_TREEVIEW* = WC_TREEVIEWW

+else:

+  const

+    ANIMATE_CLASS* = ANIMATE_CLASSA

+    HOTKEY_CLASS* = HOTKEY_CLASSA

+    PROGRESS_CLASS* = PROGRESS_CLASSA

+    STATUSCLASSNAME* = STATUSCLASSNAMEA

+    TOOLBARCLASSNAME* = TOOLBARCLASSNAMEA

+    TOOLTIPS_CLASS* = TOOLTIPS_CLASSA

+    TRACKBAR_CLASS* = TRACKBAR_CLASSA

+    UPDOWN_CLASS* = UPDOWN_CLASSA

+    WC_HEADER* = WC_HEADERA

+    WC_LISTVIEW* = WC_LISTVIEWA

+    WC_TABCONTROL* = WC_TABCONTROLA

+    WC_TREEVIEW* = WC_TREEVIEWA

+# UNICODE

+

+const

+  # Header control styles

+  HDS_BUTTONS* = 2

+  HDS_HIDDEN* = 8

+  HDS_HORZ* = 0

+  # HD_ITEM structure

+  HDI_BITMAP* = 16

+  HDI_FORMAT* = 4

+  HDI_HEIGHT* = 1

+  HDI_LPARAM* = 8

+  HDI_TEXT* = 2

+  HDI_WIDTH* = 1

+  HDF_CENTER* = 2

+  HDF_LEFT* = 0

+  HDF_RIGHT* = 1

+  HDF_RTLREADING* = 4

+  HDF_BITMAP* = 8192

+  HDF_OWNERDRAW* = 32768

+  HDF_STRING* = 16384

+  HDF_JUSTIFYMASK* = 3

+  # HD_HITTESTINFO structure

+  HHT_NOWHERE* = 1

+  HHT_ONDIVIDER* = 4

+  HHT_ONDIVOPEN* = 8

+  HHT_ONHEADER* = 2

+  HHT_TOLEFT* = 2048

+  HHT_TORIGHT* = 1024

+  # TBADDBITMAP structure

+  HINST_COMMCTRL* = HINST(-1)

+

+const

+  IDB_STD_LARGE_COLOR* = 1

+  IDB_STD_SMALL_COLOR* = 0

+  IDB_VIEW_LARGE_COLOR* = 5

+  IDB_VIEW_SMALL_COLOR* = 4

+  STD_COPY* = 1

+  STD_CUT* = 0

+  STD_DELETE* = 5

+  STD_FILENEW* = 6

+  STD_FILEOPEN* = 7

+  STD_FILESAVE* = 8

+  STD_FIND* = 12

+  STD_HELP* = 11

+  STD_PASTE* = 2

+  STD_PRINT* = 14

+  STD_PRINTPRE* = 9

+  STD_PROPERTIES* = 10

+  STD_REDOW* = 4

+  STD_REPLACE* = 13

+  STD_UNDO* = 3

+  VIEW_LARGEICONS* = 0

+  VIEW_SMALLICONS* = 1

+  VIEW_LIST* = 2

+  VIEW_DETAILS* = 3

+  VIEW_SORTNAME* = 4

+  VIEW_SORTSIZE* = 5

+  VIEW_SORTDATE* = 6

+  VIEW_SORTTYPE* = 7

+  # Toolbar styles

+  TBSTYLE_ALTDRAG* = 1024

+  TBSTYLE_TOOLTIPS* = 256

+  TBSTYLE_WRAPABLE* = 512

+  TBSTYLE_BUTTON* = 0

+  TBSTYLE_CHECK* = 2

+  TBSTYLE_CHECKGROUP* = 6

+  TBSTYLE_GROUP* = 4

+  TBSTYLE_SEP* = 1

+  # Toolbar states

+  TBSTATE_CHECKED* = 1

+  TBSTATE_ENABLED* = 4

+  TBSTATE_HIDDEN* = 8

+  TBSTATE_INDETERMINATE* = 16

+  TBSTATE_PRESSED* = 2

+  TBSTATE_WRAP* = 32

+  # Tooltip styles

+  TTS_ALWAYSTIP* = 1

+  TTS_NOPREFIX* = 2

+  # TOOLINFO structure

+  TTF_IDISHWND* = 1

+  TTF_CENTERTIP* = 2

+  TTF_RTLREADING* = 4

+  TTF_SUBCLASS* = 16

+  # TTM_SETDELAYTIME message

+  TTDT_AUTOMATIC* = 0

+  TTDT_AUTOPOP* = 2

+  TTDT_INITIAL* = 3

+  TTDT_RESHOW* = 1

+  # Status window

+  SBARS_SIZEGRIP* = 256

+  #SBARS_SIZEGRIP = 256;already above

+  # DL_DRAGGING message

+  DL_MOVECURSOR* = 3

+  DL_COPYCURSOR* = 2

+  DL_STOPCURSOR* = 1

+  # Up-down control styles

+  UDS_ALIGNLEFT* = 8

+  UDS_ALIGNRIGHT* = 4

+  UDS_ARROWKEYS* = 32

+  UDS_AUTOBUDDY* = 16

+  UDS_HORZ* = 64

+  UDS_NOTHOUSANDS* = 128

+  UDS_SETBUDDYINT* = 2

+  UDS_WRAP* = 1

+  # UDM_SETRANGE message

+  UD_MAXVAL* = 32767

+  UD_MINVAL* = -32767

+  # HKM_GETHOTKEY message

+  HOTKEYF_ALT* = 4

+  HOTKEYF_CONTROL* = 2

+  HOTKEYF_EXT* = 8

+  HOTKEYF_SHIFT* = 1

+  # HKM_SETRULES message

+  HKCOMB_A* = 8

+  HKCOMB_C* = 4

+  HKCOMB_CA* = 64

+  HKCOMB_NONE* = 1

+  HKCOMB_S* = 2

+  HKCOMB_SA* = 32

+  HKCOMB_SC* = 16

+  HKCOMB_SCA* = 128

+  # Trackbar styles

+  TBS_HORZ* = 0

+  TBS_VERT* = 2

+  TBS_AUTOTICKS* = 1

+  TBS_NOTICKS* = 16

+  TBS_TOP* = 4

+  TBS_BOTTOM* = 0

+  TBS_LEFT* = 4

+  TBS_RIGHT* = 0

+  TBS_BOTH* = 8

+  TBS_ENABLESELRANGE* = 32

+  TBS_FIXEDLENGTH* = 64

+  TBS_NOTHUMB* = 128

+  TB_BOTTOM* = 7

+  TB_ENDTRACK* = 8

+  TB_LINEDOWN* = 1

+  TB_LINEUP* = 0

+  TB_PAGEDOWN* = 3

+  TB_PAGEUP* = 2

+  TB_THUMBPOSITION* = 4

+  TB_THUMBTRACK* = 5

+  TB_TOP* = 6

+  # List view styles

+  LVS_ALIGNLEFT* = 2048

+  LVS_ALIGNTOP* = 0

+  LVS_AUTOARRANGE* = 256

+  LVS_EDITLABELS* = 512

+  LVS_ICON* = 0

+  LVS_LIST* = 3

+  LVS_NOCOLUMNHEADER* = 16384

+  LVS_NOLABELWRAP* = 128

+  LVS_NOSCROLL* = 8192

+  LVS_NOSORTHEADER* = 32768

+  LVS_OWNERDRAWFIXED* = 1024

+  LVS_REPORT* = 1

+  LVS_SHAREIMAGELISTS* = 64

+  LVS_SHOWSELALWAYS* = 8

+  LVS_SINGLESEL* = 4

+  LVS_SMALLICON* = 2

+  LVS_SORTASCENDING* = 16

+  LVS_SORTDESCENDING* = 32

+  LVS_TYPESTYLEMASK* = 64512

+  LVSIL_NORMAL* = 0

+  LVSIL_SMALL* = 1

+  LVSIL_STATE* = 2

+  LVIS_CUT* = 4

+  LVIS_DROPHILITED* = 8

+  LVIS_FOCUSED* = 1

+  LVIS_SELECTED* = 2

+  LVIS_OVERLAYMASK* = 3840

+  LVIS_STATEIMAGEMASK* = 61440

+

+  LPSTR_TEXTCALLBACKW* = cast[LPWSTR](-1)

+  LPSTR_TEXTCALLBACKA* = cast[LPSTR](-1)

+when defined(winUnicode):

+  const LPSTR_TEXTCALLBACK*  = cast[LPWSTR](-1)

+else:

+  const LPSTR_TEXTCALLBACK*  = cast[LPSTR](-1)

+

+const

+  LVIF_TEXT* = 1

+  LVIF_IMAGE* = 2

+  LVIF_PARAM* = 4

+  LVIF_STATE* = 8

+  LVIF_DI_SETITEM* = 4096

+  # LVM_GETNEXTITEM structure

+  LVNI_ABOVE* = 256

+  LVNI_ALL* = 0

+  LVNI_BELOW* = 512

+  LVNI_TOLEFT* = 1024

+  LVNI_TORIGHT* = 2048

+  LVNI_CUT* = 4

+  LVNI_DROPHILITED* = 8

+  LVNI_FOCUSED* = 1

+  LVNI_SELECTED* = 2

+  # LV_FINDINFO structure

+  LVFI_PARAM* = 1

+  LVFI_PARTIAL* = 8

+  LVFI_STRING* = 2

+  LVFI_WRAP* = 32

+  LVFI_NEARESTXY* = 64

+  # LV_HITTESTINFO structure

+  LVHT_ABOVE* = 8

+  LVHT_BELOW* = 16

+  LVHT_NOWHERE* = 1

+  LVHT_ONITEMICON* = 2

+  LVHT_ONITEMLABEL* = 4

+  LVHT_ONITEMSTATEICON* = 8

+  LVHT_TOLEFT* = 64

+  LVHT_TORIGHT* = 32

+  # LV_COLUMN structure

+  LVCF_FMT* = 1

+  LVCF_SUBITEM* = 8

+  LVCF_TEXT* = 4

+  LVCF_WIDTH* = 2

+  LVCFMT_CENTER* = 2

+  LVCFMT_LEFT* = 0

+  LVCFMT_RIGHT* = 1

+  # ListView_GetItemRect

+  LVIR_BOUNDS* = 0

+  LVIR_ICON* = 1

+  LVIR_LABEL* = 2

+  LVIR_SELECTBOUNDS* = 3

+  # LVM_ARRANGE message

+  LVA_ALIGNLEFT* = 1

+  LVA_ALIGNTOP* = 2

+  LVA_DEFAULT* = 0

+  LVA_SNAPTOGRID* = 5

+  # LVM_SETCOLUMNWIDTH message

+  LVSCW_AUTOSIZE* = -1

+  LVSCW_AUTOSIZE_USEHEADER* = -2

+  # Tree View styles

+  TVS_DISABLEDRAGDROP* = 16

+  TVS_EDITLABELS* = 8

+  TVS_HASBUTTONS* = 1

+  TVS_HASLINES* = 2

+  TVS_LINESATROOT* = 4

+  TVS_SHOWSELALWAYS* = 32

+  # Tree View states

+  TVIS_BOLD* = 16

+  TVIS_CUT* = 4

+  TVIS_DROPHILITED* = 8

+  TVIS_EXPANDED* = 32

+  TVIS_EXPANDEDONCE* = 64

+  TVIS_FOCUSED* = 1

+  TVIS_OVERLAYMASK* = 3840

+  TVIS_SELECTED* = 2

+  TVIS_STATEIMAGEMASK* = 61440

+  TVIS_USERMASK* = 61440

+  # TV_ITEM structure

+  TVIF_CHILDREN* = 64

+  TVIF_HANDLE* = 16

+  TVIF_IMAGE* = 2

+  TVIF_PARAM* = 4

+  TVIF_SELECTEDIMAGE* = 32

+  TVIF_STATE* = 8

+  TVIF_TEXT* = 1

+  I_CHILDRENCALLBACK* = -1

+  I_IMAGECALLBACK* = -1

+  # TV_INSERTSTRUCT structure

+

+type

+  TTREEITEM* {.final, pure.} = object

+  HTREEITEM* = ptr TTREEITEM

+  PTREEITEM* = ptr TTREEITEM

+

+const

+  TVI_ROOT* =  cast[HTREEITEM](0xFFFF0000)

+  TVI_FIRST* = cast[HTREEITEM](0xFFFF0001)

+  TVI_LAST* =  cast[HTREEITEM](0xFFFF0002)

+  TVI_SORT* =  cast[HTREEITEM](0xFFFF0003)

+

+const

+  # TV_HITTESTINFO structure

+  TVHT_ABOVE* = 256

+  TVHT_BELOW* = 512

+  TVHT_NOWHERE* = 1

+  TVHT_ONITEM* = 70

+  TVHT_ONITEMBUTTON* = 16

+  TVHT_ONITEMICON* = 2

+  TVHT_ONITEMINDENT* = 8

+  TVHT_ONITEMLABEL* = 4

+  TVHT_ONITEMRIGHT* = 32

+  TVHT_ONITEMSTATEICON* = 64

+  TVHT_TOLEFT* = 2048

+  TVHT_TORIGHT* = 1024

+  # TVM_EXPAND message

+  TVE_COLLAPSE* = 1

+  TVE_COLLAPSERESET* = 32768

+  TVE_EXPAND* = 2

+  TVE_TOGGLE* = 3

+  # TVM_GETIMAGELIST message

+  TVSIL_NORMAL* = 0

+  TVSIL_STATE* = 2

+  # TVM_GETNEXTITEM message

+  TVGN_CARET* = 9

+  TVGN_CHILD* = 4

+  TVGN_DROPHILITE* = 8

+  TVGN_FIRSTVISIBLE* = 5

+  TVGN_NEXT* = 1

+  TVGN_NEXTVISIBLE* = 6

+  TVGN_PARENT* = 3

+  TVGN_PREVIOUS* = 2

+  TVGN_PREVIOUSVISIBLE* = 7

+  TVGN_ROOT* = 0

+  # TVN_SELCHANGED message

+  TVC_BYKEYBOARD* = 2

+  TVC_BYMOUSE* = 1

+  TVC_UNKNOWN* = 0

+  # Tab control styles

+  TCS_BUTTONS* = 256

+  TCS_FIXEDWIDTH* = 1024

+  TCS_FOCUSNEVER* = 32768

+  TCS_FOCUSONBUTTONDOWN* = 4096

+  TCS_FORCEICONLEFT* = 16

+  TCS_FORCELABELLEFT* = 32

+  TCS_MULTILINE* = 512

+  TCS_OWNERDRAWFIXED* = 8192

+  TCS_RAGGEDRIGHT* = 2048

+  TCS_RIGHTJUSTIFY* = 0

+  TCS_SINGLELINE* = 0

+  TCS_TABS* = 0

+  TCS_TOOLTIPS* = 16384

+  # TC_ITEM structure

+  TCIF_TEXT* = 1

+  TCIF_IMAGE* = 2

+  TCIF_PARAM* = 8

+  TCIF_RTLREADING* = 4

+  # TC_HITTESTINFO structure

+  TCHT_NOWHERE* = 1

+  TCHT_ONITEM* = 6

+  TCHT_ONITEMICON* = 2

+  TCHT_ONITEMLABEL* = 4

+  # Animation control styles

+  ACS_AUTOPLAY* = 4

+  ACS_CENTER* = 1

+  ACS_TRANSPARENT* = 2

+  # MODEMDEVCAPS structure

+  DIALOPTION_BILLING* = 64

+  DIALOPTION_QUIET* = 128

+  DIALOPTION_DIALTONE* = 256

+  MDMVOLFLAG_LOW* = 1

+  MDMVOLFLAG_MEDIUM* = 2

+  MDMVOLFLAG_HIGH* = 4

+  MDMVOL_LOW* = 0

+  MDMVOL_MEDIUM* = 1

+  MDMVOL_HIGH* = 2

+  MDMSPKRFLAG_OFF* = 1

+  MDMSPKRFLAG_DIAL* = 2

+  MDMSPKRFLAG_ON* = 4

+  MDMSPKRFLAG_CALLSETUP* = 8

+  MDMSPKR_OFF* = 0

+  MDMSPKR_DIAL* = 1

+  MDMSPKR_ON* = 2

+  MDMSPKR_CALLSETUP* = 3

+  MDM_BLIND_DIAL* = 512

+  MDM_CCITT_OVERRIDE* = 64

+  MDM_CELLULAR* = 8

+  MDM_COMPRESSION* = 1

+  MDM_ERROR_CONTROL* = 2

+  MDM_FLOWCONTROL_HARD* = 16

+  MDM_FLOWCONTROL_SOFT* = 32

+  MDM_FORCED_EC* = 4

+  MDM_SPEED_ADJUST* = 128

+  MDM_TONE_DIAL* = 256

+  MDM_V23_OVERRIDE* = 1024

+

+  # Languages

+  #

+  #  Language IDs.

+  #

+  #  The following two combinations of primary language ID and

+  #  sublanguage ID have special semantics:

+  #

+  #    Primary Language ID   Sublanguage ID      Result

+  #    -------------------   ---------------     ------------------------

+  #    LANG_NEUTRAL          SUBLANG_NEUTRAL     Language neutral

+  #    LANG_NEUTRAL          SUBLANG_DEFAULT     User default language

+  #    LANG_NEUTRAL          SUBLANG_SYS_DEFAULT System default language

+  #    LANG_INVARIANT        SUBLANG_NEUTRAL     Invariant locale

+  #

+  #

+  #  Primary language IDs.

+  #

+  LANG_NEUTRAL* = 0x00000000

+  LANG_INVARIANT* = 0x0000007F

+  LANG_AFRIKAANS* = 0x00000036

+  LANG_ALBANIAN* = 0x0000001C

+  LANG_ARABIC* = 0x00000001

+  LANG_ARMENIAN* = 0x0000002B

+  LANG_ASSAMESE* = 0x0000004D

+  LANG_AZERI* = 0x0000002C

+  LANG_BASQUE* = 0x0000002D

+  LANG_BELARUSIAN* = 0x00000023

+  LANG_BENGALI* = 0x00000045

+  LANG_BULGARIAN* = 0x00000002

+  LANG_CATALAN* = 0x00000003

+  LANG_CHINESE* = 0x00000004

+  LANG_CROATIAN* = 0x0000001A

+  LANG_CZECH* = 0x00000005

+  LANG_DANISH* = 0x00000006

+  LANG_DIVEHI* = 0x00000065

+  LANG_DUTCH* = 0x00000013

+  LANG_ENGLISH* = 0x00000009

+  LANG_ESTONIAN* = 0x00000025

+  LANG_FAEROESE* = 0x00000038

+  LANG_FARSI* = 0x00000029

+  LANG_FINNISH* = 0x0000000B

+  LANG_FRENCH* = 0x0000000C

+  LANG_GALICIAN* = 0x00000056

+  LANG_GEORGIAN* = 0x00000037

+  LANG_GERMAN* = 0x00000007

+  LANG_GREEK* = 0x00000008

+  LANG_GUJARATI* = 0x00000047

+  LANG_HEBREW* = 0x0000000D

+  LANG_HINDI* = 0x00000039

+  LANG_HUNGARIAN* = 0x0000000E

+  LANG_ICELANDIC* = 0x0000000F

+  LANG_INDONESIAN* = 0x00000021

+  LANG_ITALIAN* = 0x00000010

+  LANG_JAPANESE* = 0x00000011

+  LANG_KANNADA* = 0x0000004B

+  LANG_KASHMIRI* = 0x00000060

+  LANG_KAZAK* = 0x0000003F

+  LANG_KONKANI* = 0x00000057

+  LANG_KOREAN* = 0x00000012

+  LANG_KYRGYZ* = 0x00000040

+  LANG_LATVIAN* = 0x00000026

+  LANG_LITHUANIAN* = 0x00000027

+  LANG_MACEDONIAN* = 0x0000002F # the Former Yugoslav Republic of Macedonia

+  LANG_MALAY* = 0x0000003E

+  LANG_MALAYALAM* = 0x0000004C

+  LANG_MANIPURI* = 0x00000058

+  LANG_MARATHI* = 0x0000004E

+  LANG_MONGOLIAN* = 0x00000050

+  LANG_NEPALI* = 0x00000061

+  LANG_NORWEGIAN* = 0x00000014

+  LANG_ORIYA* = 0x00000048

+  LANG_POLISH* = 0x00000015

+  LANG_PORTUGUESE* = 0x00000016

+  LANG_PUNJABI* = 0x00000046

+  LANG_ROMANIAN* = 0x00000018

+  LANG_RUSSIAN* = 0x00000019

+  LANG_SANSKRIT* = 0x0000004F

+  LANG_SERBIAN* = 0x0000001A

+  LANG_SINDHI* = 0x00000059

+  LANG_SLOVAK* = 0x0000001B

+  LANG_SLOVENIAN* = 0x00000024

+  LANG_SPANISH* = 0x0000000A

+  LANG_SWAHILI* = 0x00000041

+  LANG_SWEDISH* = 0x0000001D

+  LANG_SYRIAC* = 0x0000005A

+  LANG_TAMIL* = 0x00000049

+  LANG_TATAR* = 0x00000044

+  LANG_TELUGU* = 0x0000004A

+  LANG_THAI* = 0x0000001E

+  LANG_TURKISH* = 0x0000001F

+  LANG_UKRAINIAN* = 0x00000022

+  LANG_URDU* = 0x00000020

+  LANG_UZBEK* = 0x00000043

+  LANG_VIETNAMESE* = 0x0000002A

+  #

+  #  Sublanguage IDs.

+  #

+  #  The name immediately following SUBLANG_ dictates which primary

+  #  language ID that sublanguage ID can be combined with to form a

+  #  valid language ID.

+  #

+  SUBLANG_NEUTRAL* = 0x00000000 # language neutral

+  SUBLANG_DEFAULT* = 0x00000001 # user default

+  SUBLANG_SYS_DEFAULT* = 0x00000002 # system default

+  SUBLANG_ARABIC_SAUDI_ARABIA* = 0x00000001 # Arabic (Saudi Arabia)

+  SUBLANG_ARABIC_IRAQ* = 0x00000002 # Arabic (Iraq)

+  SUBLANG_ARABIC_EGYPT* = 0x00000003 # Arabic (Egypt)

+  SUBLANG_ARABIC_LIBYA* = 0x00000004 # Arabic (Libya)

+  SUBLANG_ARABIC_ALGERIA* = 0x00000005 # Arabic (Algeria)

+  SUBLANG_ARABIC_MOROCCO* = 0x00000006 # Arabic (Morocco)

+  SUBLANG_ARABIC_TUNISIA* = 0x00000007 # Arabic (Tunisia)

+  SUBLANG_ARABIC_OMAN* = 0x00000008 # Arabic (Oman)

+  SUBLANG_ARABIC_YEMEN* = 0x00000009 # Arabic (Yemen)

+  SUBLANG_ARABIC_SYRIA* = 0x0000000A # Arabic (Syria)

+  SUBLANG_ARABIC_JORDAN* = 0x0000000B # Arabic (Jordan)

+  SUBLANG_ARABIC_LEBANON* = 0x0000000C # Arabic (Lebanon)

+  SUBLANG_ARABIC_KUWAIT* = 0x0000000D # Arabic (Kuwait)

+  SUBLANG_ARABIC_UAE* = 0x0000000E # Arabic (U.A.E)

+  SUBLANG_ARABIC_BAHRAIN* = 0x0000000F # Arabic (Bahrain)

+  SUBLANG_ARABIC_QATAR* = 0x00000010 # Arabic (Qatar)

+  SUBLANG_AZERI_LATIN* = 0x00000001 # Azeri (Latin)

+  SUBLANG_AZERI_CYRILLIC* = 0x00000002 # Azeri (Cyrillic)

+  SUBLANG_CHINESE_TRADITIONAL* = 0x00000001 # Chinese (Taiwan)

+  SUBLANG_CHINESE_SIMPLIFIED* = 0x00000002 # Chinese (PR China)

+  SUBLANG_CHINESE_HONGKONG* = 0x00000003 # Chinese (Hong Kong S.A.R., P.R.C.)

+  SUBLANG_CHINESE_SINGAPORE* = 0x00000004 # Chinese (Singapore)

+  SUBLANG_CHINESE_MACAU* = 0x00000005 # Chinese (Macau S.A.R.)

+  SUBLANG_DUTCH* = 0x00000001 # Dutch

+  SUBLANG_DUTCH_BELGIAN* = 0x00000002 # Dutch (Belgian)

+  SUBLANG_ENGLISH_US* = 0x00000001 # English (USA)

+  SUBLANG_ENGLISH_UK* = 0x00000002 # English (UK)

+  SUBLANG_ENGLISH_AUS* = 0x00000003 # English (Australian)

+  SUBLANG_ENGLISH_CAN* = 0x00000004 # English (Canadian)

+  SUBLANG_ENGLISH_NZ* = 0x00000005 # English (New Zealand)

+  SUBLANG_ENGLISH_EIRE* = 0x00000006 # English (Irish)

+  SUBLANG_ENGLISH_SOUTH_AFRICA* = 0x00000007 # English (South Africa)

+  SUBLANG_ENGLISH_JAMAICA* = 0x00000008 # English (Jamaica)

+  SUBLANG_ENGLISH_CARIBBEAN* = 0x00000009 # English (Caribbean)

+  SUBLANG_ENGLISH_BELIZE* = 0x0000000A # English (Belize)

+  SUBLANG_ENGLISH_TRINIDAD* = 0x0000000B # English (Trinidad)

+  SUBLANG_ENGLISH_ZIMBABWE* = 0x0000000C # English (Zimbabwe)

+  SUBLANG_ENGLISH_PHILIPPINES* = 0x0000000D # English (Philippines)

+  SUBLANG_FRENCH* = 0x00000001 # French

+  SUBLANG_FRENCH_BELGIAN* = 0x00000002 # French (Belgian)

+  SUBLANG_FRENCH_CANADIAN* = 0x00000003 # French (Canadian)

+  SUBLANG_FRENCH_SWISS* = 0x00000004 # French (Swiss)

+  SUBLANG_FRENCH_LUXEMBOURG* = 0x00000005 # French (Luxembourg)

+  SUBLANG_FRENCH_MONACO* = 0x00000006 # French (Monaco)

+  SUBLANG_GERMAN* = 0x00000001 # German

+  SUBLANG_GERMAN_SWISS* = 0x00000002 # German (Swiss)

+  SUBLANG_GERMAN_AUSTRIAN* = 0x00000003 # German (Austrian)

+  SUBLANG_GERMAN_LUXEMBOURG* = 0x00000004 # German (Luxembourg)

+  SUBLANG_GERMAN_LIECHTENSTEIN* = 0x00000005 # German (Liechtenstein)

+  SUBLANG_ITALIAN* = 0x00000001 # Italian

+  SUBLANG_ITALIAN_SWISS* = 0x00000002 # Italian (Swiss)

+  SUBLANG_KASHMIRI_SASIA* = 0x00000002 # Kashmiri (South Asia)

+  SUBLANG_KASHMIRI_INDIA* = 0x00000002 # For app compatibility only

+  SUBLANG_KOREAN* = 0x00000001 # Korean (Extended Wansung)

+  SUBLANG_LITHUANIAN* = 0x00000001 # Lithuanian

+  SUBLANG_MALAY_MALAYSIA* = 0x00000001 # Malay (Malaysia)

+  SUBLANG_MALAY_BRUNEI_DARUSSALAM* = 0x00000002 # Malay (Brunei Darussalam)

+  SUBLANG_NEPALI_INDIA* = 0x00000002 # Nepali (India)

+  SUBLANG_NORWEGIAN_BOKMAL* = 0x00000001 # Norwegian (Bokmal)

+  SUBLANG_NORWEGIAN_NYNORSK* = 0x00000002 # Norwegian (Nynorsk)

+  SUBLANG_PORTUGUESE* = 0x00000002 # Portuguese

+  SUBLANG_PORTUGUESE_BRAZILIAN* = 0x00000001 # Portuguese (Brazilian)

+  SUBLANG_SERBIAN_LATIN* = 0x00000002 # Serbian (Latin)

+  SUBLANG_SERBIAN_CYRILLIC* = 0x00000003 # Serbian (Cyrillic)

+  SUBLANG_SPANISH* = 0x00000001 # Spanish (Castilian)

+  SUBLANG_SPANISH_MEXICAN* = 0x00000002 # Spanish (Mexican)

+  SUBLANG_SPANISH_MODERN* = 0x00000003 # Spanish (Spain)

+  SUBLANG_SPANISH_GUATEMALA* = 0x00000004 # Spanish (Guatemala)

+  SUBLANG_SPANISH_COSTA_RICA* = 0x00000005 # Spanish (Costa Rica)

+  SUBLANG_SPANISH_PANAMA* = 0x00000006 # Spanish (Panama)

+  SUBLANG_SPANISH_DOMINICAN_REPUBLIC* = 0x00000007 # Spanish (Dominican Republic)

+  SUBLANG_SPANISH_VENEZUELA* = 0x00000008 # Spanish (Venezuela)

+  SUBLANG_SPANISH_COLOMBIA* = 0x00000009 # Spanish (Colombia)

+  SUBLANG_SPANISH_PERU* = 0x0000000A # Spanish (Peru)

+  SUBLANG_SPANISH_ARGENTINA* = 0x0000000B # Spanish (Argentina)

+  SUBLANG_SPANISH_ECUADOR* = 0x0000000C # Spanish (Ecuador)

+  SUBLANG_SPANISH_CHILE* = 0x0000000D # Spanish (Chile)

+  SUBLANG_SPANISH_URUGUAY* = 0x0000000E # Spanish (Uruguay)

+  SUBLANG_SPANISH_PARAGUAY* = 0x0000000F # Spanish (Paraguay)

+  SUBLANG_SPANISH_BOLIVIA* = 0x00000010 # Spanish (Bolivia)

+  SUBLANG_SPANISH_EL_SALVADOR* = 0x00000011 # Spanish (El Salvador)

+  SUBLANG_SPANISH_HONDURAS* = 0x00000012 # Spanish (Honduras)

+  SUBLANG_SPANISH_NICARAGUA* = 0x00000013 # Spanish (Nicaragua)

+  SUBLANG_SPANISH_PUERTO_RICO* = 0x00000014 # Spanish (Puerto Rico)

+  SUBLANG_SWEDISH* = 0x00000001 # Swedish

+  SUBLANG_SWEDISH_FINLAND* = 0x00000002 # Swedish (Finland)

+  SUBLANG_URDU_PAKISTAN* = 0x00000001 # Urdu (Pakistan)

+  SUBLANG_URDU_INDIA* = 0x00000002 # Urdu (India)

+  SUBLANG_UZBEK_LATIN* = 0x00000001 # Uzbek (Latin)

+  SUBLANG_UZBEK_CYRILLIC* = 0x00000002 # Uzbek (Cyrillic)

+                                       #

+                                       #  Sorting IDs.

+                                       #

+  SORT_DEFAULT* = 0x00000000  # sorting default

+  SORT_JAPANESE_XJIS* = 0x00000000 # Japanese XJIS order

+  SORT_JAPANESE_UNICODE* = 0x00000001 # Japanese Unicode order

+  SORT_CHINESE_BIG5* = 0x00000000 # Chinese BIG5 order

+  SORT_CHINESE_PRCP* = 0x00000000 # PRC Chinese Phonetic order

+  SORT_CHINESE_UNICODE* = 0x00000001 # Chinese Unicode order

+  SORT_CHINESE_PRC* = 0x00000002 # PRC Chinese Stroke Count order

+  SORT_CHINESE_BOPOMOFO* = 0x00000003 # Traditional Chinese Bopomofo order

+  SORT_KOREAN_KSC* = 0x00000000 # Korean KSC order

+  SORT_KOREAN_UNICODE* = 0x00000001 # Korean Unicode order

+  SORT_GERMAN_PHONE_BOOK* = 0x00000001 # German Phone Book order

+  SORT_HUNGARIAN_DEFAULT* = 0x00000000 # Hungarian Default order

+  SORT_HUNGARIAN_TECHNICAL* = 0x00000001 # Hungarian Technical order

+  SORT_GEORGIAN_TRADITIONAL* = 0x00000000 # Georgian Traditional order

+  SORT_GEORGIAN_MODERN* = 0x00000001 # Georgian Modern order

+                                     # SYSTEM_INFO structure

+  PROCESSOR_INTEL_386* = 386

+  PROCESSOR_INTEL_486* = 486

+  PROCESSOR_INTEL_PENTIUM* = 586

+  PROCESSOR_MIPS_R4000* = 4000

+  PROCESSOR_ALPHA_21064* = 21064

+  # FSCTL_SET_COMPRESSION

+  COMPRESSION_FORMAT_NONE* = 0

+  COMPRESSION_FORMAT_DEFAULT* = 1

+  COMPRESSION_FORMAT_LZNT1* = 2

+  # TAPE_GET_DRIVE_PARAMETERS structure

+  TAPE_DRIVE_COMPRESSION* = 131072

+  TAPE_DRIVE_ECC* = 65536

+  TAPE_DRIVE_ERASE_BOP_ONLY* = 64

+  TAPE_DRIVE_ERASE_LONG* = 32

+  TAPE_DRIVE_ERASE_IMMEDIATE* = 128

+  TAPE_DRIVE_ERASE_SHORT* = 16

+  TAPE_DRIVE_FIXED* = 1

+  TAPE_DRIVE_FIXED_BLOCK* = 1024

+  TAPE_DRIVE_INITIATOR* = 4

+  TAPE_DRIVE_PADDING* = 262144

+  TAPE_DRIVE_GET_ABSOLUTE_BLK* = 1048576

+  TAPE_DRIVE_GET_LOGICAL_BLK* = 2097152

+  TAPE_DRIVE_REPORT_SMKS* = 524288

+  TAPE_DRIVE_SELECT* = 2

+  TAPE_DRIVE_SET_EOT_WZ_SIZE* = 4194304

+  TAPE_DRIVE_TAPE_CAPACITY* = 256

+  TAPE_DRIVE_TAPE_REMAINING* = 512

+  TAPE_DRIVE_VARIABLE_BLOCK* = 2048

+  TAPE_DRIVE_WRITE_PROTECT* = 4096

+  TAPE_DRIVE_ABS_BLK_IMMED* = -2147475456

+  TAPE_DRIVE_ABSOLUTE_BLK* = -2147479552

+  TAPE_DRIVE_END_OF_DATA* = -2147418112

+  TAPE_DRIVE_FILEMARKS* = -2147221504

+  TAPE_DRIVE_LOAD_UNLOAD* = -2147483647

+  TAPE_DRIVE_LOAD_UNLD_IMMED* = -2147483616

+  TAPE_DRIVE_LOCK_UNLOCK* = -2147483644

+  TAPE_DRIVE_LOCK_UNLK_IMMED* = -2147483520

+  TAPE_DRIVE_LOG_BLK_IMMED* = -2147450880

+  TAPE_DRIVE_LOGICAL_BLK* = -2147467264

+  TAPE_DRIVE_RELATIVE_BLKS* = -2147352576

+  TAPE_DRIVE_REVERSE_POSITION* = -2143289344

+  TAPE_DRIVE_REWIND_IMMEDIATE* = -2147483640

+  TAPE_DRIVE_SEQUENTIAL_FMKS* = -2146959360

+  TAPE_DRIVE_SEQUENTIAL_SMKS* = -2145386496

+  TAPE_DRIVE_SET_BLOCK_SIZE* = -2147483632

+  TAPE_DRIVE_SET_COMPRESSION* = -2147483136

+  TAPE_DRIVE_SET_ECC* = -2147483392

+  TAPE_DRIVE_SET_PADDING* = -2147482624

+  TAPE_DRIVE_SET_REPORT_SMKS* = -2147481600

+  TAPE_DRIVE_SETMARKS* = -2146435072

+  TAPE_DRIVE_SPACE_IMMEDIATE* = -2139095040

+  TAPE_DRIVE_TENSION* = -2147483646

+  TAPE_DRIVE_TENSION_IMMED* = -2147483584

+  TAPE_DRIVE_WRITE_FILEMARKS* = -2113929216

+  TAPE_DRIVE_WRITE_LONG_FMKS* = -2013265920

+  TAPE_DRIVE_WRITE_MARK_IMMED* = -1879048192

+  TAPE_DRIVE_WRITE_SETMARKS* = -2130706432

+  TAPE_DRIVE_WRITE_SHORT_FMKS* = -2080374784

+  # Standard rights

+  STANDARD_RIGHTS_REQUIRED* = 0x000F0000

+  STANDARD_RIGHTS_WRITE* = 0x00020000

+  STANDARD_RIGHTS_READ* = 0x00020000

+  STANDARD_RIGHTS_EXECUTE* = 0x00020000

+  STANDARD_RIGHTS_ALL* = 0x001F0000

+  SPECIFIC_RIGHTS_ALL* = 0x0000FFFF

+

+  FILE_GENERIC_READ* = STANDARD_RIGHTS_READ or

+      FILE_READ_DATA or

+      FILE_READ_ATTRIBUTES or

+      FILE_READ_EA or

+      SYNCHRONIZE

+  FILE_GENERIC_WRITE* = STANDARD_RIGHTS_WRITE or

+      FILE_WRITE_DATA or

+      FILE_WRITE_ATTRIBUTES or

+      FILE_WRITE_EA or

+      FILE_APPEND_DATA or

+      SYNCHRONIZE

+  FILE_GENERIC_EXECUTE* = STANDARD_RIGHTS_EXECUTE or

+      FILE_READ_ATTRIBUTES or

+      FILE_EXECUTE or

+      SYNCHRONIZE

+  FILE_ALL_ACCESS* = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or 0x1FF

+

+  # ACCESS_MASK

+  MAXIMUM_ALLOWED* = 0x02000000

+  GENERIC_ALL* = 0x10000000

+  # SID

+  SECURITY_NULL_RID* = 0

+  SECURITY_WORLD_RID* = 0

+  SECURITY_LOCAL_RID* = 0

+  SECURITY_CREATOR_OWNER_RID* = 0

+  SECURITY_CREATOR_GROUP_RID* = 0x00000001

+  SECURITY_DIALUP_RID* = 0x00000001

+  SECURITY_NETWORK_RID* = 0x00000002

+  SECURITY_BATCH_RID* = 0x00000003

+  SECURITY_INTERACTIVE_RID* = 0x00000004

+  SECURITY_LOGON_IDS_RID* = 0x00000005

+  SECURITY_LOGON_IDS_RID_COUNT* = 0x00000003

+  SECURITY_SERVICE_RID* = 0x00000006

+  SECURITY_LOCAL_SYSTEM_RID* = 0x00000012

+  SECURITY_BUILTIN_DOMAIN_RID* = 0x00000020

+  DOMAIN_USER_RID_ADMIN* = 0x000001F4

+  DOMAIN_USER_RID_GUEST* = 0x000001F5

+  DOMAIN_GROUP_RID_ADMINS* = 0x00000200

+  DOMAIN_GROUP_RID_USERS* = 0x00000201

+  DOMAIN_ALIAS_RID_ADMINS* = 0x00000220

+  DOMAIN_ALIAS_RID_USERS* = 0x00000221

+  DOMAIN_ALIAS_RID_GUESTS* = 0x00000222

+  DOMAIN_ALIAS_RID_POWER_USERS* = 0x00000223

+  DOMAIN_ALIAS_RID_ACCOUNT_OPS* = 0x00000224

+  DOMAIN_ALIAS_RID_SYSTEM_OPS* = 0x00000225

+  DOMAIN_ALIAS_RID_PRINT_OPS* = 0x00000226

+  DOMAIN_ALIAS_RID_BACKUP_OPS* = 0x00000227

+  DOMAIN_ALIAS_RID_REPLICATOR* = 0x00000228

+  # TOKEN_GROUPS structure

+  SE_GROUP_MANDATORY* = 0x00000001

+  SE_GROUP_ENABLED_BY_DEFAULT* = 0x00000002

+  SE_GROUP_ENABLED* = 0x00000004

+  SE_GROUP_OWNER* = 0x00000008

+  SE_GROUP_LOGON_ID* = 0xC0000000

+  # ACL Defines

+  ACL_REVISION* = 2

+  # ACE_HEADER structure

+  ACCESS_ALLOWED_ACE_TYPE* = 0x00000000

+  ACCESS_DENIED_ACE_TYPE* = 0x00000001

+  SYSTEM_AUDIT_ACE_TYPE* = 0x00000002

+  SYSTEM_ALARM_ACE_TYPE* = 0x00000003

+  # ACE flags in the ACE_HEADER structure

+  OBJECT_INHERIT_ACE* = 0x00000001

+  CONTAINER_INHERIT_ACE* = 0x00000002

+  NO_PROPAGATE_INHERIT_ACE* = 0x00000004

+  INHERIT_ONLY_ACE* = 0x00000008

+  SUCCESSFUL_ACCESS_ACE_FLAG* = 0x00000040

+  FAILED_ACCESS_ACE_FLAG* = 0x00000080

+  # SECURITY_DESCRIPTOR_CONTROL

+  #SECURITY_DESCRIPTOR_REVISION = 1;already defined above

+  SECURITY_DESCRIPTOR_MIN_LENGTH* = 20

+  SE_OWNER_DEFAULTED* = 1

+  SE_GROUP_DEFAULTED* = 2

+  SE_DACL_PRESENT* = 4

+  SE_DACL_DEFAULTED* = 8

+  SE_SACL_PRESENT* = 16

+  SE_SACL_DEFAULTED* = 32

+  SE_SELF_RELATIVE* = 32768

+  # PRIVILEGE_SET

+  SE_PRIVILEGE_ENABLED_BY_DEFAULT* = 0x00000001

+  SE_PRIVILEGE_ENABLED* = 0x00000002

+  SE_PRIVILEGE_USED_FOR_ACCESS* = 0x80000000

+  PRIVILEGE_SET_ALL_NECESSARY* = 0x00000001

+  # OPENFILENAME structure

+  OFN_ALLOWMULTISELECT* = 0x00000200

+  OFN_CREATEPROMPT* = 0x00002000

+  OFN_ENABLEHOOK* = 0x00000020

+  OFN_ENABLETEMPLATE* = 0x00000040

+  OFN_ENABLETEMPLATEHANDLE* = 0x00000080

+  OFN_EXPLORER* = 0x00080000

+  OFN_EXTENSIONDIFFERENT* = 0x00000400

+  OFN_FILEMUSTEXIST* = 0x00001000

+  OFN_HIDEREADONLY* = 0x00000004

+  OFN_LONGNAMES* = 0x00200000

+  OFN_NOCHANGEDIR* = 0x00000008

+  OFN_NODEREFERENCELINKS* = 0x00100000

+  OFN_NOLONGNAMES* = 0x00040000

+  OFN_NONETWORKBUTTON* = 0x00020000

+  OFN_NOREADONLYRETURN* = 0x00008000

+  OFN_NOTESTFILECREATE* = 0x00010000

+  OFN_NOVALIDATE* = 0x00000100

+  OFN_OVERWRITEPROMPT* = 0x00000002

+  OFN_PATHMUSTEXIST* = 0x00000800

+  OFN_READONLY* = 0x00000001

+  OFN_SHAREAWARE* = 0x00004000

+  OFN_SHOWHELP* = 0x00000010

+  # SHAREVISTRING message

+  OFN_SHAREFALLTHROUGH* = 0x00000002

+  OFN_SHARENOWARN* = 0x00000001

+  OFN_SHAREWARN* = 0

+  # Open/Save notifications

+  CDN_INITDONE* = 0xFFFFFDA7

+  CDN_SELCHANGE* = 0xFFFFFDA6

+  CDN_FOLDERCHANGE* = 0xFFFFFDA5

+  CDN_SHAREVIOLATION* = 0xFFFFFDA4

+  CDN_HELP* = 0xFFFFFDA3

+  CDN_FILEOK* = 0xFFFFFDA2

+  CDN_TYPECHANGE* = 0xFFFFFDA1

+  # Open/Save messages

+  CDM_GETFILEPATH* = 0x00000465

+  CDM_GETFOLDERIDLIST* = 0x00000467

+  CDM_GETFOLDERPATH* = 0x00000466

+  CDM_GETSPEC* = 0x00000464

+  CDM_HIDECONTROL* = 0x00000469

+  CDM_SETCONTROLTEXT* = 0x00000468

+  CDM_SETDEFEXT* = 0x0000046A

+  # CHOOSECOLOR structure

+  CC_ENABLEHOOK* = 0x00000010

+  CC_ENABLETEMPLATE* = 0x00000020

+  CC_ENABLETEMPLATEHANDLE* = 0x00000040

+  CC_FULLOPEN* = 0x00000002

+  CC_PREVENTFULLOPEN* = 0x00000004

+  CC_RGBINIT* = 0x00000001

+  CC_SHOWHELP* = 0x00000008

+  CC_SOLIDCOLOR* = 0x00000080

+  # FINDREPLACE structure

+  FR_DIALOGTERM* = 0x00000040

+  FR_DOWN* = 0x00000001

+  FR_ENABLEHOOK* = 0x00000100

+  FR_ENABLETEMPLATE* = 0x00000200

+  FR_ENABLETEMPLATEHANDLE* = 0x00002000

+  FR_FINDNEXT* = 0x00000008

+  FR_HIDEUPDOWN* = 0x00004000

+  FR_HIDEMATCHCASE* = 0x00008000

+  FR_HIDEWHOLEWORD* = 0x00010000

+  FR_MATCHCASE* = 0x00000004

+  FR_NOMATCHCASE* = 0x00000800

+  FR_NOUPDOWN* = 0x00000400

+  FR_NOWHOLEWORD* = 0x00001000

+  FR_REPLACE* = 0x00000010

+  FR_REPLACEALL* = 0x00000020

+  FR_SHOWHELP* = 0x00000080

+  FR_WHOLEWORD* = 0x00000002

+  # CHOOSEFONT structure

+  CF_APPLY* = 0x00000200

+  CF_ANSIONLY* = 0x00000400

+  CF_BOTH* = 0x00000003

+  CF_TTONLY* = 0x00040000

+  CF_EFFECTS* = 0x00000100

+  CF_ENABLEHOOK* = 0x00000008

+  CF_ENABLETEMPLATE* = 0x00000010

+  CF_ENABLETEMPLATEHANDLE* = 0x00000020

+  CF_FIXEDPITCHONLY* = 0x00004000

+  CF_FORCEFONTEXIST* = 0x00010000

+  CF_INITTOLOGFONTSTRUCT* = 0x00000040

+  CF_LIMITSIZE* = 0x00002000

+  CF_NOOEMFONTS* = 0x00000800

+  CF_NOFACESEL* = 0x00080000

+  CF_NOSCRIPTSEL* = 0x00800000

+  CF_NOSTYLESEL* = 0x00100000

+  CF_NOSIZESEL* = 0x00200000

+  CF_NOSIMULATIONS* = 0x00001000

+  CF_NOVECTORFONTS* = 0x00000800

+  CF_NOVERTFONTS* = 0x01000000

+  CF_PRINTERFONTS* = 0x00000002

+  CF_SCALABLEONLY* = 0x00020000

+  CF_SCREENFONTS* = 0x00000001

+  CF_SCRIPTSONLY* = 0x00000400

+  CF_SELECTSCRIPT* = 0x00400000

+  CF_SHOWHELP* = 0x00000004

+  CF_USESTYLE* = 0x00000080

+  CF_WYSIWYG* = 0x00008000

+  BOLD_FONTTYPE* = 0x00000100

+  ITALIC_FONTTYPE* = 0x00000200

+  PRINTER_FONTTYPE* = 0x00004000

+  REGULAR_FONTTYPE* = 0x00000400

+  SCREEN_FONTTYPE* = 0x00002000

+  SIMULATED_FONTTYPE* = 0x00008000

+  # Common dialog messages

+  COLOROKSTRINGW* = "commdlg_ColorOK"

+  FILEOKSTRINGW* = "commdlg_FileNameOK"

+  FINDMSGSTRINGW* = "commdlg_FindReplace"

+  HELPMSGSTRINGW* = "commdlg_help"

+  LBSELCHSTRINGW* = "commdlg_LBSelChangedNotify"

+  SETRGBSTRINGW* = "commdlg_SetRGBColor"

+  SHAREVISTRINGW* = "commdlg_ShareViolation"

+  COLOROKSTRINGA* = "commdlg_ColorOK"

+  FILEOKSTRINGA* = "commdlg_FileNameOK"

+  FINDMSGSTRINGA* = "commdlg_FindReplace"

+  HELPMSGSTRINGA* = "commdlg_help"

+  LBSELCHSTRINGA* = "commdlg_LBSelChangedNotify"

+  SETRGBSTRINGA* = "commdlg_SetRGBColor"

+  SHAREVISTRINGA* = "commdlg_ShareViolation"

+

+when defined(winUnicode):

+  const

+    COLOROKSTRING* = COLOROKSTRINGW

+    FILEOKSTRING* = FILEOKSTRINGW

+    FINDMSGSTRING* = FINDMSGSTRINGW

+    HELPMSGSTRING* = HELPMSGSTRINGW

+    LBSELCHSTRING* = LBSELCHSTRINGW

+    SETRGBSTRING* = SETRGBSTRINGW

+    SHAREVISTRING* = SHAREVISTRINGW

+else:

+  const

+    COLOROKSTRING* = COLOROKSTRINGA

+    FILEOKSTRING* = FILEOKSTRINGA

+    FINDMSGSTRING* = FINDMSGSTRINGA

+    HELPMSGSTRING* = HELPMSGSTRINGA

+    LBSELCHSTRING* = LBSELCHSTRINGA

+    SETRGBSTRING* = SETRGBSTRINGA

+    SHAREVISTRING* = SHAREVISTRINGA

+

+const

+  # LBSELCHSTRING message

+  CD_LBSELCHANGE* = 0

+  CD_LBSELADD* = 2

+  CD_LBSELSUB* = 1

+  CD_LBSELNOITEMS* = -1

+  # DEVNAMES structure

+  DN_DEFAULTPRN* = 1

+  # PRINTDLG structure

+  PD_ALLPAGES* = 0

+  PD_COLLATE* = 16

+  PD_DISABLEPRINTTOFILE* = 524288

+  PD_ENABLEPRINTHOOK* = 4096

+  PD_ENABLEPRINTTEMPLATE* = 16384

+  PD_ENABLEPRINTTEMPLATEHANDLE* = 65536

+  PD_ENABLESETUPHOOK* = 8192

+  PD_ENABLESETUPTEMPLATE* = 32768

+  PD_ENABLESETUPTEMPLATEHANDLE* = 131072

+  PD_HIDEPRINTTOFILE* = 1048576

+  PD_NOPAGENUMS* = 8

+  PD_NOSELECTION* = 4

+  PD_NOWARNING* = 128

+  PD_PAGENUMS* = 2

+  PD_PRINTSETUP* = 64

+  PD_PRINTTOFILE* = 32

+  PD_RETURNDC* = 256

+  PD_RETURNDEFAULT* = 1024

+  PD_RETURNIC* = 512

+  PD_SELECTION* = 1

+  PD_SHOWHELP* = 2048

+  PD_USEDEVMODECOPIES* = 262144

+  PD_USEDEVMODECOPIESANDCOLLATE* = 262144

+  # PAGESETUPDLG structure

+  PSD_DEFAULTMINMARGINS* = 0

+  PSD_DISABLEMARGINS* = 16

+  PSD_DISABLEORIENTATION* = 256

+  PSD_DISABLEPAGEPAINTING* = 524288

+  PSD_DISABLEPAPER* = 512

+  PSD_DISABLEPRINTER* = 32

+  PSD_ENABLEPAGEPAINTHOOK* = 262144

+  PSD_ENABLEPAGESETUPHOOK* = 8192

+  PSD_ENABLEPAGESETUPTEMPLATE* = 32768

+  PSD_ENABLEPAGESETUPTEMPLATEHANDLE* = 131072

+  PSD_INHUNDREDTHSOFMILLIMETERS* = 8

+  PSD_INTHOUSANDTHSOFINCHES* = 4

+  PSD_INWININIINTLMEASURE* = 0

+  PSD_MARGINS* = 2

+  PSD_MINMARGINS* = 1

+  PSD_NOWARNING* = 128

+  PSD_RETURNDEFAULT* = 1024

+  PSD_SHOWHELP* = 2048

+  # WM_SHOWWINDOW message

+  SW_OTHERUNZOOM* = 4

+  SW_OTHERZOOM* = 2

+  SW_PARENTCLOSING* = 1

+  SW_PARENTOPENING* = 3

+  # Virtual Key codes

+  VK_LBUTTON* = 1

+  VK_RBUTTON* = 2

+  VK_CANCEL* = 3

+  VK_MBUTTON* = 4

+  VK_BACK* = 8

+  VK_TAB* = 9

+  VK_CLEAR* = 12

+  VK_RETURN* = 13

+  VK_SHIFT* = 16

+  VK_CONTROL* = 17

+  VK_MENU* = 18

+  VK_PAUSE* = 19

+  VK_CAPITAL* = 20

+  VK_ESCAPE* = 27

+  VK_SPACE* = 32

+  VK_PRIOR* = 33

+  VK_NEXT* = 34

+  VK_END* = 35

+  VK_HOME* = 36

+  VK_LEFT* = 37

+  VK_UP* = 38

+  VK_RIGHT* = 39

+  VK_DOWN* = 40

+  VK_SELECT* = 41

+  VK_PRINT* = 42

+  VK_EXECUTE* = 43

+  VK_SNAPSHOT* = 44

+  VK_INSERT* = 45

+  VK_DELETE* = 46

+  VK_HELP* = 47

+  VK_0* = 48

+  VK_1* = 49

+  VK_2* = 50

+  VK_3* = 51

+  VK_4* = 52

+  VK_5* = 53

+  VK_6* = 54

+  VK_7* = 55

+  VK_8* = 56

+  VK_9* = 57

+  VK_A* = 65

+  VK_B* = 66

+  VK_C* = 67

+  VK_D* = 68

+  VK_E* = 69

+  VK_F* = 70

+  VK_G* = 71

+  VK_H* = 72

+  VK_I* = 73

+  VK_J* = 74

+  VK_K* = 75

+  VK_L* = 76

+  VK_M* = 77

+  VK_N* = 78

+  VK_O* = 79

+  VK_P* = 80

+  VK_Q* = 81

+  VK_R* = 82

+  VK_S* = 83

+  VK_T* = 84

+  VK_U* = 85

+  VK_V* = 86

+  VK_W* = 87

+  VK_X* = 88

+  VK_Y* = 89

+  VK_Z* = 90

+  VK_LWIN* = 91

+  VK_RWIN* = 92

+  VK_APPS* = 93

+  VK_NUMPAD0* = 96

+  VK_NUMPAD1* = 97

+  VK_NUMPAD2* = 98

+  VK_NUMPAD3* = 99

+  VK_NUMPAD4* = 100

+  VK_NUMPAD5* = 101

+  VK_NUMPAD6* = 102

+  VK_NUMPAD7* = 103

+  VK_NUMPAD8* = 104

+  VK_NUMPAD9* = 105

+  VK_MULTIPLY* = 106

+  VK_ADD* = 107

+  VK_SEPARATOR* = 108

+  VK_SUBTRACT* = 109

+  VK_DECIMAL* = 110

+  VK_DIVIDE* = 111

+  VK_F1* = 112

+  VK_F2* = 113

+  VK_F3* = 114

+  VK_F4* = 115

+  VK_F5* = 116

+  VK_F6* = 117

+  VK_F7* = 118

+  VK_F8* = 119

+  VK_F9* = 120

+  VK_F10* = 121

+  VK_F11* = 122

+  VK_F12* = 123

+  VK_F13* = 124

+  VK_F14* = 125

+  VK_F15* = 126

+  VK_F16* = 127

+  VK_F17* = 128

+  VK_F18* = 129

+  VK_F19* = 130

+  VK_F20* = 131

+  VK_F21* = 132

+  VK_F22* = 133

+  VK_F23* = 134

+  VK_F24* = 135

+  # GetAsyncKeyState

+  VK_NUMLOCK* = 144

+  VK_SCROLL* = 145

+  VK_LSHIFT* = 160

+  VK_LCONTROL* = 162

+  VK_LMENU* = 164

+  VK_RSHIFT* = 161

+  VK_RCONTROL* = 163

+  VK_RMENU* = 165

+  # ImmGetVirtualKey

+  VK_PROCESSKEY* = 229

+  # Keystroke Message Flags

+  KF_ALTDOWN* = 8192

+  KF_DLGMODE* = 2048

+  KF_EXTENDED* = 256

+  KF_MENUMODE* = 4096

+  KF_REPEAT* = 16384

+  KF_UP* = 32768

+  # GetKeyboardLayoutName

+  KL_NAMELENGTH* = 9

+  # WM_ACTIVATE message

+  WA_ACTIVE* = 1

+  WA_CLICKACTIVE* = 2

+  WA_INACTIVE* = 0

+  # WM_ACTIVATE message

+  PWR_CRITICALRESUME* = 3

+  PWR_SUSPENDREQUEST* = 1

+  PWR_SUSPENDRESUME* = 2

+  PWR_FAIL* = -1

+  PWR_OK* = 1

+  # WM_NOTIFYFORMAT message

+  NF_QUERY* = 3

+  NF_REQUERY* = 4

+  NFR_ANSI* = 1

+  NFR_UNICODE* = 2

+  # WM_SIZING message

+  WMSZ_BOTTOM* = 6

+  WMSZ_BOTTOMLEFT* = 7

+  WMSZ_BOTTOMRIGHT* = 8

+  WMSZ_LEFT* = 1

+  WMSZ_RIGHT* = 2

+  WMSZ_TOP* = 3

+  WMSZ_TOPLEFT* = 4

+  WMSZ_TOPRIGHT* = 5

+  # WM_MOUSEACTIVATE message

+  MA_ACTIVATE* = 1

+  MA_ACTIVATEANDEAT* = 2

+  MA_NOACTIVATE* = 3

+  MA_NOACTIVATEANDEAT* = 4

+  # WM_SIZE message

+  SIZE_MAXHIDE* = 4

+  SIZE_MAXIMIZED* = 2

+  SIZE_MAXSHOW* = 3

+  SIZE_MINIMIZED* = 1

+  SIZE_RESTORED* = 0

+  # WM_NCCALCSIZE message

+  WVR_ALIGNTOP* = 16

+  WVR_ALIGNLEFT* = 32

+  WVR_ALIGNBOTTOM* = 64

+  WVR_ALIGNRIGHT* = 128

+  WVR_HREDRAW* = 256

+  WVR_VREDRAW* = 512

+  WVR_REDRAW* = 768

+  WVR_VALIDRECTS* = 1024

+  # WM_NCHITTEST message

+  HTBOTTOM* = 15

+  HTBOTTOMLEFT* = 16

+  HTBOTTOMRIGHT* = 17

+  HTCAPTION* = 2

+  HTCLIENT* = 1

+  HTERROR* = -2

+  HTGROWBOX* = 4

+  HTHSCROLL* = 6

+  HTLEFT* = 10

+  HTMENU* = 5

+  HTNOWHERE* = 0

+  HTREDUCE* = 8

+

+  HTRIGHT* = 11

+  HTSIZE* = 4

+  HTSYSMENU* = 3

+  HTTOP* = 12

+  HTTOPLEFT* = 13

+  HTTOPRIGHT* = 14

+  HTTRANSPARENT* = -1

+  HTVSCROLL* = 7

+  HTZOOM* = 9

+  # Mouse messages

+  MK_CONTROL* = 8

+  MK_LBUTTON* = 1

+  MK_MBUTTON* = 16

+  MK_RBUTTON* = 2

+  MK_SHIFT* = 4

+  # WNDCLASS structure

+  CS_BYTEALIGNCLIENT* = 4096

+  CS_BYTEALIGNWINDOW* = 8192

+  CS_CLASSDC* = 64

+  CS_DBLCLKS* = 8

+  CS_GLOBALCLASS* = 16384

+  CS_HREDRAW* = 2

+  CS_KEYCVTWINDOW* = 4

+  CS_NOCLOSE* = 512

+  CS_NOKEYCVT* = 256

+  CS_OWNDC* = 32

+  CS_PARENTDC* = 128

+  CS_SAVEBITS* = 2048

+  CS_VREDRAW* = 1

+  DLGWINDOWEXTRA* = 30

+  # ACCEL structure

+  FALT* = 16

+  FCONTROL* = 8

+  FNOINVERT* = 2

+  FSHIFT* = 4

+  FVIRTKEY* = 1

+  # WM_MENUCHAR return constants

+  MNC_IGNORE* = 0

+  MNC_CLOSE* = 1

+  MNC_EXECUTE* = 2

+  MNC_SELECT* = 3

+  # MENUINFO structure

+  MIM_MAXHEIGHT* = 1

+  MIM_BACKGROUND* = 2

+  MIM_HELPID* = 4

+  MIM_MENUDATA* = 8

+  MIM_STYLE* = 16

+  MIM_APPLYTOSUBMENUS* = 0x80000000

+  MNS_CHECKORBMP* = 0x04000000

+  MNS_NOTIFYBYPOS* = 0x08000000

+  MNS_AUTODISMISS* = 0x10000000

+  MNS_DRAGDROP* = 0x20000000

+  MNS_MODELESS* = 0x40000000

+  MNS_NOCHECK* = 0x80000000

+  # MENUITEMINFO structure

+  MIIM_CHECKMARKS* = 8

+  MIIM_DATA* = 32

+  MIIM_ID* = 2

+  MIIM_STATE* = 1

+  MIIM_SUBMENU* = 4

+  MIIM_TYPE* = 16

+  MIIM_STRING* = 64

+  MIIM_BITMAP* = 128

+  MIIM_FTYPE* = 256

+  MFT_BITMAP* = 0x00000004

+  MFT_MENUBARBREAK* = 0x00000020

+  MFT_MENUBREAK* = 0x00000040

+  MFT_OWNERDRAW* = 0x00000100

+  MFT_RADIOCHECK* = 0x00000200

+  MFT_RIGHTJUSTIFY* = 0x00004000

+  MFT_SEPARATOR* = 0x00000800

+  MFT_RIGHTORDER* = 0x00002000

+  MFT_STRING* = 0

+  MFS_CHECKED* = 0x00000008

+  MFS_DEFAULT* = 0x00001000

+  MFS_DISABLED* = 0x00000003

+  MFS_ENABLED* = 0

+  MFS_GRAYED* = 0x00000003

+  MFS_HILITE* = 0x00000080

+  MFS_UNCHECKED* = 0

+  MFS_UNHILITE* = 0

+  HBMMENU_CALLBACK* = - 1

+  HBMMENU_SYSTEM* = 1

+  HBMMENU_MBAR_RESTORE* = 2

+  HBMMENU_MBAR_MINIMIZE* = 3

+  HBMMENU_MBAR_CLOSE* = 5

+  HBMMENU_MBAR_CLOSE_D* = 6

+  HBMMENU_MBAR_MINIMIZE_D* = 7

+  HBMMENU_POPUP_CLOSE* = 8

+  HBMMENU_POPUP_RESTORE* = 9

+  HBMMENU_POPUP_MAXIMIZE* = 10

+  HBMMENU_POPUP_MINIMIZE* = 11

+  # SERIALKEYS structure

+  SERKF_AVAILABLE* = 2

+  SERKF_INDICATOR* = 4

+  SERKF_SERIALKEYSON* = 1

+  # FILTERKEYS structure

+  FKF_AVAILABLE* = 2

+  FKF_CLICKON* = 64

+  FKF_FILTERKEYSON* = 1

+  FKF_HOTKEYACTIVE* = 4

+  FKF_HOTKEYSOUND* = 16

+  FKF_CONFIRMHOTKEY* = 8

+  FKF_INDICATOR* = 32

+  # HELPINFO structure

+  HELPINFO_MENUITEM* = 2

+  HELPINFO_WINDOW* = 1

+  # WM_PRINT message

+  PRF_CHECKVISIBLE* = 0x00000001

+  PRF_CHILDREN* = 0x00000010

+  PRF_CLIENT* = 0x00000004

+  PRF_ERASEBKGND* = 0x00000008

+  PRF_NONCLIENT* = 0x00000002

+  PRF_OWNED* = 0x00000020

+

+  # MapWindowPoints

+  HWND_DESKTOP* = HWND(0)

+

+const

+  # WM_SYSCOMMAND message

+  SC_CLOSE* = 61536

+  SC_CONTEXTHELP* = 61824

+  SC_DEFAULT* = 61792

+  SC_HOTKEY* = 61776

+  SC_HSCROLL* = 61568

+  SC_KEYMENU* = 61696

+  SC_MAXIMIZE* = 61488

+  SC_ZOOM* = 61488

+  SC_MINIMIZE* = 61472

+  SC_ICON* = 61472

+  SC_MONITORPOWER* = 61808

+  SC_MOUSEMENU* = 61584

+  SC_MOVE* = 61456

+  SC_NEXTWINDOW* = 61504

+  SC_PREVWINDOW* = 61520

+  SC_RESTORE* = 61728

+  SC_SCREENSAVE* = 61760

+  SC_SIZE* = 61440

+  SC_TASKLIST* = 61744

+  SC_VSCROLL* = 61552

+  # DM_GETDEFID message

+  DC_HASDEFID* = 21323

+  # WM_GETDLGCODE message

+  DLGC_BUTTON* = 8192

+  DLGC_DEFPUSHBUTTON* = 16

+  DLGC_HASSETSEL* = 8

+  DLGC_RADIOBUTTON* = 64

+  DLGC_STATIC* = 256

+  DLGC_UNDEFPUSHBUTTON* = 32

+  DLGC_WANTALLKEYS* = 4

+  DLGC_WANTARROWS* = 1

+  DLGC_WANTCHARS* = 128

+  DLGC_WANTMESSAGE* = 4

+  DLGC_WANTTAB* = 2

+  # EM_SETMARGINS message

+  EC_LEFTMARGIN* = 1

+  EC_RIGHTMARGIN* = 2

+  EC_USEFONTINFO* = 65535

+  # LB_SETCOUNT message

+  LB_ERR* = -1

+  LB_ERRSPACE* = -2

+  LB_OKAY* = 0

+  # CB_DIR message

+  CB_ERR* = -1

+  CB_ERRSPACE* = -2

+  # WM_IME_CONTROL message

+  IMC_GETCANDIDATEPOS* = 7

+  IMC_GETCOMPOSITIONFONT* = 9

+  IMC_GETCOMPOSITIONWINDOW* = 11

+  IMC_GETSTATUSWINDOWPOS* = 15

+  IMC_CLOSESTATUSWINDOW* = 33

+  IMC_OPENSTATUSWINDOW* = 34

+  IMC_SETCANDIDATEPOS* = 8

+  IMC_SETCOMPOSITIONFONT* = 10

+  IMC_SETCOMPOSITIONWINDOW* = 12

+  IMC_SETSTATUSWINDOWPOS* = 16

+  # WM_IME_CONTROL message

+  IMN_CHANGECANDIDATE* = 3

+  IMN_CLOSECANDIDATE* = 4

+  IMN_CLOSESTATUSWINDOW* = 1

+  IMN_GUIDELINE* = 13

+  IMN_OPENCANDIDATE* = 5

+  IMN_OPENSTATUSWINDOW* = 2

+  IMN_SETCANDIDATEPOS* = 9

+  IMN_SETCOMPOSITIONFONT* = 10

+  IMN_SETCOMPOSITIONWINDOW* = 11

+  IMN_SETCONVERSIONMODE* = 6

+  IMN_SETOPENSTATUS* = 8

+  IMN_SETSENTENCEMODE* = 7

+  IMN_SETSTATUSWINDOWPOS* = 12

+  IMN_PRIVATE* = 14

+  # STICKYKEYS structure

+  SKF_AUDIBLEFEEDBACK* = 64

+  SKF_AVAILABLE* = 2

+  SKF_CONFIRMHOTKEY* = 8

+  SKF_HOTKEYACTIVE* = 4

+  SKF_HOTKEYSOUND* = 16

+  SKF_INDICATOR* = 32

+  SKF_STICKYKEYSON* = 1

+  SKF_TRISTATE* = 128

+  SKF_TWOKEYSOFF* = 256

+  # MOUSEKEYS structure

+  MKF_AVAILABLE* = 2

+  MKF_CONFIRMHOTKEY* = 8

+  MKF_HOTKEYACTIVE* = 4

+  MKF_HOTKEYSOUND* = 16

+  MKF_INDICATOR* = 32

+  MKF_MOUSEKEYSON* = 1

+  MKF_MODIFIERS* = 64

+  MKF_REPLACENUMBERS* = 128

+  # SOUNDSENTRY structure

+  SSF_AVAILABLE* = 2

+  SSF_SOUNDSENTRYON* = 1

+  SSTF_BORDER* = 2

+  SSTF_CHARS* = 1

+  SSTF_DISPLAY* = 3

+  SSTF_NONE* = 0

+  SSGF_DISPLAY* = 3

+  SSGF_NONE* = 0

+  SSWF_CUSTOM* = 4

+  SSWF_DISPLAY* = 3

+  SSWF_NONE* = 0

+  SSWF_TITLE* = 1

+  SSWF_WINDOW* = 2

+  # ACCESSTIMEOUT structure

+  ATF_ONOFFFEEDBACK* = 2

+  ATF_TIMEOUTON* = 1

+  # HIGHCONTRAST structure

+  HCF_AVAILABLE* = 2

+  HCF_CONFIRMHOTKEY* = 8

+  HCF_HIGHCONTRASTON* = 1

+  HCF_HOTKEYACTIVE* = 4

+  HCF_HOTKEYAVAILABLE* = 64

+  HCF_HOTKEYSOUND* = 16

+  HCF_INDICATOR* = 32

+  # TOGGLEKEYS structure

+  TKF_AVAILABLE* = 2

+  TKF_CONFIRMHOTKEY* = 8

+  TKF_HOTKEYACTIVE* = 4

+  TKF_HOTKEYSOUND* = 16

+  TKF_TOGGLEKEYSON* = 1

+  # Installable Policy

+  PP_DISPLAYERRORS* = 1

+  # SERVICE_INFO structure

+  RESOURCEDISPLAYTYPE_DOMAIN* = 1

+  RESOURCEDISPLAYTYPE_FILE* = 4

+  RESOURCEDISPLAYTYPE_GENERIC* = 0

+  RESOURCEDISPLAYTYPE_GROUP* = 5

+  RESOURCEDISPLAYTYPE_SERVER* = 2

+  RESOURCEDISPLAYTYPE_SHARE* = 3

+  # KEY_EVENT_RECORD structure

+  CAPSLOCK_ON* = 128

+  ENHANCED_KEY* = 256

+  LEFT_ALT_PRESSED* = 2

+  LEFT_CTRL_PRESSED* = 8

+  NUMLOCK_ON* = 32

+  RIGHT_ALT_PRESSED* = 1

+  RIGHT_CTRL_PRESSED* = 4

+  SCROLLLOCK_ON* = 64

+  SHIFT_PRESSED* = 16

+  # MOUSE_EVENT_RECORD structure

+  FROM_LEFT_1ST_BUTTON_PRESSED* = 1

+  RIGHTMOST_BUTTON_PRESSED* = 2

+  FROM_LEFT_2ND_BUTTON_PRESSED* = 4

+  FROM_LEFT_3RD_BUTTON_PRESSED* = 8

+  FROM_LEFT_4TH_BUTTON_PRESSED* = 16

+  DOUBLE_CLICK* = 2

+  MOUSE_MOVED* = 1

+  # INPUT_RECORD structure

+  KEY_EVENT* = 1

+  cMOUSE_EVENT* = 2

+  WINDOW_BUFFER_SIZE_EVENT* = 4

+  MENU_EVENT* = 8

+  FOCUS_EVENT* = 16

+  # BITMAPINFOHEADER structure

+  BI_RGB* = 0

+  BI_RLE8* = 1

+  BI_RLE4* = 2

+  BI_BITFIELDS* = 3

+  # Extensions to OpenGL

+  # ChoosePixelFormat

+  PFD_DOUBLEBUFFER* = 0x00000001

+  PFD_STEREO* = 0x00000002

+  PFD_DRAW_TO_WINDOW* = 0x00000004

+  PFD_DRAW_TO_BITMAP* = 0x00000008

+  PFD_SUPPORT_GDI* = 0x00000010

+  PFD_SUPPORT_OPENGL* = 0x00000020

+  PFD_DEPTH_DONTCARE* = 0x20000000

+  PFD_DOUBLEBUFFER_DONTCARE* = 0x40000000

+  PFD_STEREO_DONTCARE* = 0x80000000

+  PFD_TYPE_RGBA* = 0

+  PFD_TYPE_COLORINDEX* = 1

+  PFD_MAIN_PLANE* = 0

+  PFD_OVERLAY_PLANE* = 1

+  PFD_UNDERLAY_PLANE* = -1

+  # wglUseFontOutlines

+  WGL_FONT_LINES* = 0

+  WGL_FONT_POLYGONS* = 1

+  PFD_GENERIC_FORMAT* = 0x00000040

+  PFD_NEED_PALETTE* = 0x00000080

+  PFD_NEED_SYSTEM_PALETTE* = 0x00000100

+  PFD_SWAP_EXCHANGE* = 0x00000200

+  PFD_SWAP_COPY* = 0x00000400

+  PFD_SWAP_LAYER_BUFFERS* = 0x00000800

+  PFD_GENERIC_ACCELERATED* = 0x00001000

+  PFD_SUPPORT_DIRECTDRAW* = 0x00002000

+  TMPF_FIXED_PITCH* = 0x00000001

+  TMPF_VECTOR* = 0x00000002

+  TMPF_TRUETYPE* = 0x00000004

+  TMPF_DEVICE* = 0x00000008

+  WM_CTLCOLOR* = 25

+  LWA_COLORKEY* = 0x00000001

+  LWA_ALPHA* = 0x00000002

+  ULW_COLORKEY* = 0x00000001

+  ULW_ALPHA* = 0x00000002

+  ULW_OPAQUE* = 0x00000004

+  WS_EX_LAYERED* = 0x00080000

+  WS_EX_NOINHERITLAYOUT* = 0x00100000

+  WS_EX_LAYOUTRTL* = 0x00400000

+  WS_EX_COMPOSITED* = 0x02000000

+  WS_EX_NOACTIVATE* = 0x08000000

+  C3_LEXICAL* = 1024

+

+# --------------------- old stuff, need to organize! ---------------

+# BEGINNING of windowsx.h stuff from old headers:

+

+# was #define dname(params) def_expr

+proc GetFirstChild*(h: HWND): HWND

+  # was #define dname(params) def_expr

+proc GetNextSibling*(h: HWND): HWND

+  # was #define dname(params) def_expr

+proc GetWindowID*(h: HWND): int32

+  # was #define dname(params) def_expr

+proc SubclassWindow*(h: HWND, p: LONG): LONG

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_COMMAND_CMD*(w, L: int32): int32

+  # return type might be wrong

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_COMMAND_ID*(w, L: int32): int32

+  # return type might be wrong

+  # was #define dname(params) def_expr

+  # argument types are unknown

+proc GET_WM_CTLCOLOR_HDC*(w, L, msg: int32): HDC

+  # was #define dname(params) def_expr

+  # argument types are unknown

+proc GET_WM_CTLCOLOR_HWND*(w, L, msg: int32): HWND

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_HSCROLL_CODE*(w, L: int32): int32

+  # return type might be wrong

+  # was #define dname(params) def_expr

+  # argument types are unknown

+proc GET_WM_HSCROLL_HWND*(w, L: int32): HWND

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_HSCROLL_POS*(w, L: int32): int32

+  # return type might be wrong

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_MDIACTIVATE_FACTIVATE*(h, a, b: int32): int32

+  # return type might be wrong

+  # was #define dname(params) def_expr

+  # argument types are unknown

+proc GET_WM_MDIACTIVATE_HWNDACTIVATE*(a, b: int32): HWND

+  # was #define dname(params) def_expr

+  # argument types are unknown

+proc GET_WM_MDIACTIVATE_HWNDDEACT*(a, b: int32): HWND

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_VSCROLL_CODE*(w, L: int32): int32

+  # return type might be wrong

+  # was #define dname(params) def_expr

+  # argument types are unknown

+proc GET_WM_VSCROLL_HWND*(w, L: int32): HWND

+  # was #define dname(params) def_expr

+  # argument types are unknown

+  # return type might be wrong

+proc GET_WM_VSCROLL_POS*(w, L: int32): int32

+  # return type might be wrong

+  #  Not convertable by H2PAS

+  # END OF windowsx.h stuff from old headers

+  # ------------------------------------------------------------------

+

+const

+  # BEGINNING of shellapi.h stuff from old headers

+  SE_ERR_SHARE* = 26

+  SE_ERR_ASSOCINCOMPLETE* = 27

+  SE_ERR_DDETIMEOUT* = 28

+  SE_ERR_DDEFAIL* = 29

+  SE_ERR_DDEBUSY* = 30

+  SE_ERR_NOASSOC* = 31

+  # END OF shellapi.h stuff from old headers

+  #

+  # ------------------------------------------------------------------

+  # From ddeml.h in old Cygnus headers

+  XCLASS_BOOL* = 0x00001000

+  XCLASS_DATA* = 0x00002000

+  XCLASS_FLAGS* = 0x00004000

+  XCLASS_MASK* = 0x0000FC00

+  XCLASS_NOTIFICATION* = 0x00008000

+  XTYPF_NOBLOCK* = 0x00000002

+  XTYP_ADVDATA* = 0x00004010

+  XTYP_ADVREQ* = 0x00002022

+  XTYP_ADVSTART* = 0x00001030

+  XTYP_ADVSTOP* = 0x00008040

+  XTYP_CONNECT* = 0x00001062

+  XTYP_CONNECT_CONFIRM* = 0x00008072

+  XTYP_DISCONNECT* = 0x000080C2

+  XTYP_EXECUTE* = 0x00004050

+  XTYP_POKE* = 0x00004090

+  XTYP_REQUEST* = 0x000020B0

+  XTYP_WILDCONNECT* = 0x000020E2

+  XTYP_REGISTER* = 0x000080A2

+  XTYP_ERROR* = 0x00008002

+  XTYP_XACT_COMPLETE* = 0x00008080

+  XTYP_UNREGISTER* = 0x000080D2

+  DMLERR_DLL_USAGE* = 0x00004004

+  DMLERR_INVALIDPARAMETER* = 0x00004006

+  DMLERR_NOTPROCESSED* = 0x00004009

+  DMLERR_POSTMSG_FAILED* = 0x0000400C

+  DMLERR_SERVER_DIED* = 0x0000400E

+  DMLERR_SYS_ERROR* = 0x0000400F

+  DMLERR_BUSY* = 0x00004001

+  DMLERR_DATAACKTIMEOUT* = 0x00004002

+  DMLERR_ADVACKTIMEOUT* = 0x00004000

+  DMLERR_DLL_NOT_INITIALIZED* = 0x00004003

+  DMLERR_LOW_MEMORY* = 0x00004007

+  DMLERR_MEMORY_ERROR* = 0x00004008

+  DMLERR_POKEACKTIMEOUT* = 0x0000400B

+  DMLERR_NO_CONV_ESTABLISHED* = 0x0000400A

+  DMLERR_REENTRANCY* = 0x0000400D

+  DMLERR_UNFOUND_QUEUE_ID* = 0x00004011

+  DMLERR_UNADVACKTIMEOUT* = 0x00004010

+  DMLERR_EXECACKTIMEOUT* = 0x00004005

+  DDE_FACK* = 0x00008000

+  DDE_FNOTPROCESSED* = 0x00000000

+  DNS_REGISTER* = 0x00000001

+  DNS_UNREGISTER* = 0x00000002

+  CP_WINANSI* = 1004

+  CP_WINUNICODE* = 1200

+  #  Not convertable by H2PAS

+  #  #define EXPENTRY CALLBACK

+  APPCLASS_STANDARD* = 0x00000000

+  # End of stuff from ddeml.h in old Cygnus headers

+

+  BKMODE_LAST* = 2

+  CTLCOLOR_MSGBOX* = 0

+  CTLCOLOR_EDIT* = 1

+  CTLCOLOR_LISTBOX* = 2

+  CTLCOLOR_BTN* = 3

+  CTLCOLOR_DLG* = 4

+  CTLCOLOR_SCROLLBAR* = 5

+  CTLCOLOR_STATIC* = 6

+  CTLCOLOR_MAX* = 7

+  META_SETMAPMODE* = 0x00000103

+  META_SETWINDOWORG* = 0x0000020B

+  META_SETWINDOWEXT* = 0x0000020C

+  POLYFILL_LAST* = 2

+  STATUS_WAIT_0* = 0x00000000

+  STATUS_ABANDONED_WAIT_0* = 0x00000080

+  STATUS_USER_APC* = 0x000000C0

+  STATUS_TIMEOUT* = 0x00000102

+  STATUS_PENDING* = 0x00000103

+  STATUS_GUARD_PAGE_VIOLATION* = 0x80000001

+  STATUS_DATATYPE_MISALIGNMENT* = 0x80000002

+  STATUS_BREAKPOINT* = 0x80000003

+  STATUS_SINGLE_STEP* = 0x80000004

+  STATUS_IN_PAGE_ERROR* = 0xC0000006

+  STATUS_INVALID_HANDLE* = 0xC0000008

+  STATUS_ILLEGAL_INSTRUCTION* = 0xC000001D

+  STATUS_NONCONTINUABLE_EXCEPTION* = 0xC0000025

+  STATUS_INVALID_DISPOSITION* = 0xC0000026

+  STATUS_ARRAY_BOUNDS_EXCEEDED* = 0xC000008C

+  STATUS_FLOAT_DENORMAL_OPERAND* = 0xC000008D

+  STATUS_FLOAT_DIVIDE_BY_ZERO* = 0xC000008E

+  STATUS_FLOAT_INEXACT_RESULT* = 0xC000008F

+  STATUS_FLOAT_INVALID_OPERATION* = 0xC0000090

+  STATUS_FLOAT_OVERFLOW* = 0xC0000091

+  STATUS_FLOAT_STACK_CHECK* = 0xC0000092

+  STATUS_FLOAT_UNDERFLOW* = 0xC0000093

+  STATUS_INTEGER_DIVIDE_BY_ZERO* = 0xC0000094

+  STATUS_INTEGER_OVERFLOW* = 0xC0000095

+  STATUS_PRIVILEGED_INSTRUCTION* = 0xC0000096

+  STATUS_STACK_OVERFLOW* = 0xC00000FD

+  STATUS_CONTROL_C_EXIT* = 0xC000013A

+  PROCESSOR_ARCHITECTURE_INTEL* = 0

+  PROCESSOR_ARCHITECTURE_MIPS* = 1

+  PROCESSOR_ARCHITECTURE_ALPHA* = 2

+  PROCESSOR_ARCHITECTURE_PPC* = 3

+

+const

+  SIZEFULLSCREEN* = SIZE_MAXIMIZED

+  SIZENORMAL* = SIZE_RESTORED

+  SIZEICONIC* = SIZE_MINIMIZED

+

+const

+  EXCEPTION_READ_FAULT* = 0   # Access violation was caused by a read

+  EXCEPTION_WRITE_FAULT* = 1  # Access violation was caused by a write

+

+when hostCPU == "ia64":

+  const

+    EXCEPTION_EXECUTE_FAULT* = 2 # Access violation was caused by an instruction fetch

+else:

+  const

+    EXCEPTION_EXECUTE_FAULT* = 8

+when hostCPU == "powerpc":

+  # ppc

+  const

+    CONTEXT_CONTROL* = 1

+    CONTEXT_FLOATING_POINT* = 2

+    CONTEXT_INTEGER* = 4

+    CONTEXT_DEBUG_REGISTERS* = 8

+    CONTEXT_FULL* = CONTEXT_CONTROL or CONTEXT_FLOATING_POINT or CONTEXT_INTEGER

+    CONTEXT_DEBUGGER* = CONTEXT_FULL

+when hostCPU == "i386":

+  # x86

+  # The doc refered me to winnt.h, so I had to look...

+  const

+    SIZE_OF_80387_REGISTERS* = 80 # Values for contextflags

+    CONTEXT_i386* = 0x00010000 # this assumes that i386 and

+    CONTEXT_i486* = 0x00010000 # i486 have identical context records

+    CONTEXT_CONTROL* = CONTEXT_i386 or 1 # SS:SP, CS:IP, FLAGS, BP

+    CONTEXT_INTEGER* = CONTEXT_i386 or 2 # AX, BX, CX, DX, SI, DI

+    CONTEXT_SEGMENTS* = CONTEXT_i386 or 4 # DS, ES, FS, GS

+    CONTEXT_FLOATING_POINT* = CONTEXT_i386 or 8 # 387 state

+    CONTEXT_DEBUG_REGISTERS* = CONTEXT_i386 or 0x00000010 # DB 0-3,6,7

+    CONTEXT_EXTENDED_REGISTERS* = CONTEXT_i386 or 0x00000020 # cpu specific extensions

+    CONTEXT_FULL* = (CONTEXT_CONTROL or CONTEXT_INTEGER) or CONTEXT_SEGMENTS

+    CONTEXT_ALL* = CONTEXT_FULL or CONTEXT_FLOATING_POINT or

+        CONTEXT_DEBUG_REGISTERS or CONTEXT_EXTENDED_REGISTERS # our own invention

+    FLAG_TRACE_BIT* = 0x00000100

+    CONTEXT_DEBUGGER* = CONTEXT_FULL or CONTEXT_FLOATING_POINT

+when hostCPU == "amd64":

+  const

+    INITIAL_MXCSR* = 0x00001F80 # initial MXCSR value

+    INITIAL_FPCSR* = 0x0000027F # initial FPCSR value

+    CONTEXT_AMD64* = 0x00100000

+    CONTEXT_CONTROL* = (CONTEXT_AMD64 or 0x00000001)

+    CONTEXT_INTEGER* = (CONTEXT_AMD64 or 0x00000002)

+    CONTEXT_SEGMENTS* = (CONTEXT_AMD64 or 0x00000004)

+    CONTEXT_FLOATING_POINT* = (CONTEXT_AMD64 or 0x00000008)

+    CONTEXT_DEBUG_REGISTERS* = (CONTEXT_AMD64 or 0x00000010)

+    CONTEXT_FULL* = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_FLOATING_POINT

+    CONTEXT_ALL* = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS or

+        CONTEXT_FLOATING_POINT or CONTEXT_DEBUG_REGISTERS

+    CONTEXT_EXCEPTION_ACTIVE* = 0x08000000

+    CONTEXT_SERVICE_ACTIVE* = 0x10000000

+    CONTEXT_EXCEPTION_REQUEST* = 0x40000000

+    CONTEXT_EXCEPTION_REPORTING* = 0x80000000

+

+const

+  FILTER_TEMP_DUPLICATE_ACCOUNT* = 0x00000001

+  FILTER_NORMAL_ACCOUNT* = 0x00000002

+  FILTER_INTERDOMAIN_TRUST_ACCOUNT* = 0x00000008

+  FILTER_WORKSTATION_TRUST_ACCOUNT* = 0x00000010

+  FILTER_SERVER_TRUST_ACCOUNT* = 0x00000020

+  LOGON32_LOGON_INTERACTIVE* = 0x00000002

+  LOGON32_LOGON_BATCH* = 0x00000004

+  LOGON32_LOGON_SERVICE* = 0x00000005

+  LOGON32_PROVIDER_DEFAULT* = 0x00000000

+  LOGON32_PROVIDER_WINNT35* = 0x00000001

+  QID_SYNC* = 0xFFFFFFFF

+  # Magic numbers in PE executable header. # e_magic field

+  IMAGE_DOS_SIGNATURE* = 0x00005A4D

+  # nt_signature field

+  IMAGE_NT_SIGNATURE* = 0x00004550

+  # Severity values

+  SEVERITY_SUCCESS* = 0

+  SEVERITY_ERROR* = 1

+  # Variant type codes (wtypes.h).

+  #    Some, not all though

+  VT_EMPTY* = 0

+  VT_NULL* = 1

+  VT_I2* = 2

+  VT_I4* = 3

+  VT_R4* = 4

+  VT_R8* = 5

+  VT_BSTR* = 8

+  VT_ERROR* = 10

+  VT_BOOL* = 11

+  VT_UI1* = 17

+  VT_BYREF* = 0x00004000

+  VT_RESERVED* = 0x00008000

+

+const

+  # Define the facility codes

+  FACILITY_WINDOWS* = 8

+  FACILITY_STORAGE* = 3

+  FACILITY_RPC* = 1

+  FACILITY_SSPI* = 9

+  FACILITY_WIN32* = 7

+  FACILITY_CONTROL* = 10

+  FACILITY_NULL* = 0

+  FACILITY_INTERNET* = 12

+  FACILITY_ITF* = 4

+  FACILITY_DISPATCH* = 2

+  FACILITY_CERT* = 11         # Manually added, bug 2672

+  ICON_SMALL* = 0

+  ICON_BIG* = 1

+  # For the TrackMouseEvent

+  TME_HOVER* = 0x00000001

+  TME_LEAVE* = 0x00000002

+  TME_QUERY* = 0x40000000

+  TME_CANCEL* = DWORD(0x80000000)

+  HOVER_DEFAULT* = DWORD(0xFFFFFFFF) # Manually added, bug 3270

+  COLOR_HOTLIGHT* = 26

+  COLOR_GRADIENTACTIVECAPTION* = 27

+  COLOR_GRADIENTINACTIVECAPTION* = 28

+  COLOR_MENUHILIGHT* = 29

+  COLOR_MENUBAR* = 30

+  WM_APP* = 0x00008000

+  SYSRGN* = 4

+  UIS_SET* = 1

+  UIS_CLEAR* = 2

+  UIS_INITIALIZE* = 3

+  UISF_HIDEFOCUS* = 0x00000001

+  UISF_HIDEACCEL* = 0x00000002

+  UISF_ACTIVE* = 0x00000004

+

+type

+  # WARNING

+  #      the variable argument list

+  #      is not implemented for FPC

+  #      va_list is just a dummy record

+  #      MvdV: Nevertheless it should be a pointer type, not a record

+  va_list* = cstring

+  TABC* {.final, pure.} = object

+    abcA*: int32

+    abcB*: WINUINT

+    abcC*: int32

+

+  LPABC* = ptr TABC

+  PABC* = ptr TABC

+  TABCFLOAT* {.final, pure.} = object

+    abcfA*: float32

+    abcfB*: float32

+    abcfC*: float32

+  LPABCFLOAT* = ptr TABCFLOAT

+  PABCFLOAT* = ptr TABCFLOAT

+

+  TACCEL* {.final, pure.} = object

+    fVirt*: int8

+    key*: int16

+    cmd*: int16

+  LPACCEL* = ptr TACCEL

+  PACCEL* = ptr TACCEL

+  ACE_HEADER* {.final, pure.} = object

+    AceType*: int8

+    AceFlags*: int8

+    AceSize*: int16

+

+  TACE_HEADER* = ACE_HEADER

+  PACE_HEADER* = ptr ACE_HEADER

+  ACCESS_MASK* = DWORD

+  REGSAM* = ACCESS_MASK

+  ACCESS_ALLOWED_ACE* {.final, pure.} = object

+    Header*: ACE_HEADER

+    Mask*: ACCESS_MASK

+    SidStart*: DWORD

+

+  TACCESS_ALLOWED_ACE* = ACCESS_ALLOWED_ACE

+  PACCESS_ALLOWED_ACE* = ptr ACCESS_ALLOWED_ACE

+  ACCESS_DENIED_ACE* {.final, pure.} = object

+    Header*: ACE_HEADER

+    Mask*: ACCESS_MASK

+    SidStart*: DWORD

+

+  TACCESS_DENIED_ACE* = ACCESS_DENIED_ACE

+  ACCESSTIMEOUT* {.final, pure.} = object

+    cbSize*: WINUINT

+    dwFlags*: DWORD

+    iTimeOutMSec*: DWORD

+

+  TACCESSTIMEOUT* = ACCESSTIMEOUT

+  PACCESSTIMEOUT* = ptr ACCESSTIMEOUT

+  ACL* {.final, pure.} = object

+    AclRevision*: int8

+    Sbz1*: int8

+    AclSize*: int16

+    AceCount*: int16

+    Sbz2*: int16

+

+  PACL* = ptr ACL

+  TACL* = ACL

+  TACL_REVISION_INFORMATION* {.final, pure.} = object

+    AclRevision*: DWORD

+  PACLREVISIONINFORMATION* = ptr TACL_REVISION_INFORMATION

+

+  TACL_SIZE_INFORMATION* {.final, pure.} = object

+    AceCount*: DWORD

+    AclBytesInUse*: DWORD

+    AclBytesFree*: DWORD

+  PACLSIZEINFORMATION* = ptr TACL_SIZE_INFORMATION

+  ACTION_HEADER* {.final, pure.} = object

+    transport_id*: ULONG

+    action_code*: USHORT

+    reserved*: USHORT

+

+  TACTIONHEADER* = ACTION_HEADER

+  PACTIONHEADER* = ptr ACTION_HEADER

+  ADAPTER_STATUS* {.final, pure.} = object

+    adapter_address*: array[0..5, UCHAR]

+    rev_major*: UCHAR

+    reserved0*: UCHAR

+    adapter_type*: UCHAR

+    rev_minor*: UCHAR

+    duration*: int16

+    frmr_recv*: int16

+    frmr_xmit*: int16

+    iframe_recv_err*: int16

+    xmit_aborts*: int16

+    xmit_success*: DWORD

+    recv_success*: DWORD

+    iframe_xmit_err*: int16

+    recv_buff_unavail*: int16

+    t1_timeouts*: int16

+    ti_timeouts*: int16

+    reserved1*: DWORD

+    free_ncbs*: int16

+    max_cfg_ncbs*: int16

+    max_ncbs*: int16

+    xmit_buf_unavail*: int16

+    max_dgram_size*: int16

+    pending_sess*: int16

+    max_cfg_sess*: int16

+    max_sess*: int16

+    max_sess_pkt_size*: int16

+    name_count*: int16

+

+  TADAPTERSTATUS* = ADAPTER_STATUS

+  PADAPTERSTATUS* = ptr ADAPTER_STATUS

+  ADDJOB_INFO_1* {.final, pure.} = object

+    Path*: LPTSTR

+    JobId*: DWORD

+

+  TADDJOB_INFO_1* = ADDJOB_INFO_1

+  PADDJOB_INFO_1* = ptr ADDJOB_INFO_1

+  ANIMATIONINFO* {.final, pure.} = object

+    cbSize*: WINUINT

+    iMinAnimate*: int32

+

+  LPANIMATIONINFO* = ptr ANIMATIONINFO

+  TANIMATIONINFO* = ANIMATIONINFO

+  PANIMATIONINFO* = ptr ANIMATIONINFO

+

+  APPBARDATA* {.final, pure.} = object

+    cbSize*: DWORD

+    hWnd*: HWND

+    uCallbackMessage*: WINUINT

+    uEdge*: WINUINT

+    rc*: RECT

+    lParam*: LPARAM

+

+  TAppBarData* = APPBARDATA

+  PAppBarData* = ptr APPBARDATA

+  BITMAP* {.final, pure.} = object

+    bmType*: LONG

+    bmWidth*: LONG

+    bmHeight*: LONG

+    bmWidthBytes*: LONG

+    bmPlanes*: int16

+    bmBitsPixel*: int16

+    bmBits*: LPVOID

+

+  PBITMAP* = ptr BITMAP

+  NPBITMAP* = ptr BITMAP

+  LPBITMAP* = ptr BITMAP

+  TBITMAP* = BITMAP

+  BITMAPCOREHEADER* {.final, pure.} = object

+    bcSize*: DWORD

+    bcWidth*: int16

+    bcHeight*: int16

+    bcPlanes*: int16

+    bcBitCount*: int16

+

+  TBITMAPCOREHEADER* = BITMAPCOREHEADER

+  PBITMAPCOREHEADER* = ptr BITMAPCOREHEADER

+  RGBTRIPLE* {.final, pure.} = object

+    rgbtBlue*: int8

+    rgbtGreen*: int8

+    rgbtRed*: int8

+

+  TRGBTRIPLE* = RGBTRIPLE

+  PRGBTRIPLE* = ptr RGBTRIPLE

+  BITMAPCOREINFO* {.final, pure.} = object

+    bmciHeader*: BITMAPCOREHEADER

+    bmciColors*: array[0..0, RGBTRIPLE]

+

+  PBITMAPCOREINFO* = ptr BITMAPCOREINFO

+  LPBITMAPCOREINFO* = ptr BITMAPCOREINFO

+  TBITMAPCOREINFO* = BITMAPCOREINFO # error

+                                    #  WORD    bfReserved1;

+                                    #  WORD    bfReserved2;

+                                    # in declarator_list

+  BITMAPINFOHEADER* {.final, pure.} = object

+    biSize*: DWORD

+    biWidth*: LONG

+    biHeight*: LONG

+    biPlanes*: int16

+    biBitCount*: int16

+    biCompression*: DWORD

+    biSizeImage*: DWORD

+    biXPelsPerMeter*: LONG

+    biYPelsPerMeter*: LONG

+    biClrUsed*: DWORD

+    biClrImportant*: DWORD

+

+  LPBITMAPINFOHEADER* = ptr BITMAPINFOHEADER

+  TBITMAPINFOHEADER* = BITMAPINFOHEADER

+  PBITMAPINFOHEADER* = ptr BITMAPINFOHEADER

+  RGBQUAD* {.final, pure.} = object

+    rgbBlue*: int8

+    rgbGreen*: int8

+    rgbRed*: int8

+    rgbReserved*: int8

+

+  TRGBQUAD* = RGBQUAD

+  PRGBQUAD* = ptr RGBQUAD

+  BITMAPINFO* {.final, pure.} = object

+    bmiHeader*: BITMAPINFOHEADER

+    bmiColors*: array[0..0, RGBQUAD]

+

+  LPBITMAPINFO* = ptr BITMAPINFO

+  PBITMAPINFO* = ptr BITMAPINFO

+  TBITMAPINFO* = BITMAPINFO

+  FXPT2DOT30* = int32

+  LPFXPT2DOT30* = ptr FXPT2DOT30

+  TPFXPT2DOT30* = FXPT2DOT30

+  PPFXPT2DOT30* = ptr FXPT2DOT30

+  CIEXYZ* {.final, pure.} = object

+    ciexyzX*: FXPT2DOT30

+    ciexyzY*: FXPT2DOT30

+    ciexyzZ*: FXPT2DOT30

+

+  LPCIEXYZ* = ptr CIEXYZ

+  TPCIEXYZ* = CIEXYZ

+  PCIEXYZ* = ptr CIEXYZ

+  CIEXYZTRIPLE* {.final, pure.} = object

+    ciexyzRed*: CIEXYZ

+    ciexyzGreen*: CIEXYZ

+    ciexyzBlue*: CIEXYZ

+

+  LPCIEXYZTRIPLE* = ptr CIEXYZTRIPLE

+  TCIEXYZTRIPLE* = CIEXYZTRIPLE

+  PCIEXYZTRIPLE* = ptr CIEXYZTRIPLE

+  BITMAPV4HEADER* {.final, pure.} = object

+    bV4Size*: DWORD

+    bV4Width*: LONG

+    bV4Height*: LONG

+    bV4Planes*: int16

+    bV4BitCount*: int16

+    bV4V4Compression*: DWORD

+    bV4SizeImage*: DWORD

+    bV4XPelsPerMeter*: LONG

+    bV4YPelsPerMeter*: LONG

+    bV4ClrUsed*: DWORD

+    bV4ClrImportant*: DWORD

+    bV4RedMask*: DWORD

+    bV4GreenMask*: DWORD

+    bV4BlueMask*: DWORD

+    bV4AlphaMask*: DWORD

+    bV4CSType*: DWORD

+    bV4Endpoints*: CIEXYZTRIPLE

+    bV4GammaRed*: DWORD

+    bV4GammaGreen*: DWORD

+    bV4GammaBlue*: DWORD

+

+  LPBITMAPV4HEADER* = ptr BITMAPV4HEADER

+  TBITMAPV4HEADER* = BITMAPV4HEADER

+  PBITMAPV4HEADER* = ptr BITMAPV4HEADER

+  BITMAPFILEHEADER* {.final, pure.} = object

+    bfType*: int16

+    bfSize*: DWord

+    bfReserved1*: int16

+    bfReserved2*: int16

+    bfOffBits*: DWord

+

+  BLOB* {.final, pure.} = object

+    cbSize*: ULONG

+    pBlobData*: ptr int8

+

+  TBLOB* = BLOB

+  PBLOB* = ptr BLOB

+  SHITEMID* {.final, pure.} = object

+    cb*: USHORT

+    abID*: array[0..0, int8]

+

+  LPSHITEMID* = ptr SHITEMID

+  LPCSHITEMID* = ptr SHITEMID

+  TSHITEMID* = SHITEMID

+  PSHITEMID* = ptr SHITEMID

+  ITEMIDLIST* {.final, pure.} = object

+    mkid*: SHITEMID

+

+  LPITEMIDLIST* = ptr ITEMIDLIST

+  LPCITEMIDLIST* = ptr ITEMIDLIST

+  TITEMIDLIST* = ITEMIDLIST

+  PITEMIDLIST* = ptr ITEMIDLIST

+  BROWSEINFO* {.final, pure.} = object

+    hwndOwner*: HWND

+    pidlRoot*: LPCITEMIDLIST

+    pszDisplayName*: LPSTR

+    lpszTitle*: LPCSTR

+    ulFlags*: WINUINT

+    lpfn*: BFFCALLBACK

+    lParam*: LPARAM

+    iImage*: int32

+

+  LPBROWSEINFO* = ptr BROWSEINFO

+  Tbrowseinfo* = BROWSEINFO

+  PBROWSEINFO* = ptr BROWSEINFO

+

+  BY_HANDLE_FILE_INFORMATION* {.final, pure.} = object

+    dwFileAttributes*: DWORD

+    ftCreationTime*: FILETIME

+    ftLastAccessTime*: FILETIME

+    ftLastWriteTime*: FILETIME

+    dwVolumeSerialNumber*: DWORD

+    nFileSizeHigh*: DWORD

+    nFileSizeLow*: DWORD

+    nNumberOfLinks*: DWORD

+    nFileIndexHigh*: DWORD

+    nFileIndexLow*: DWORD

+

+  LPBY_HANDLE_FILE_INFORMATION* = ptr BY_HANDLE_FILE_INFORMATION

+  TBYHANDLEFILEINFORMATION* = BY_HANDLE_FILE_INFORMATION

+  PBYHANDLEFILEINFORMATION* = ptr BY_HANDLE_FILE_INFORMATION

+  FIXED* {.final, pure.} = object

+    fract*: int16

+    value*: SHORT

+

+  TFIXED* = FIXED

+  PFIXED* = ptr FIXED

+  POINTFX* {.final, pure.} = object

+    x*: FIXED

+    y*: FIXED

+

+  TPOINTFX* = POINTFX

+  PPOINTFX* = ptr POINTFX

+

+  TSmallPoint* {.final, pure.} = object

+    X*, Y*: SHORT

+

+  CANDIDATEFORM* {.final, pure.} = object

+    dwIndex*: DWORD

+    dwStyle*: DWORD

+    ptCurrentPos*: POINT

+    rcArea*: RECT

+

+  LPCANDIDATEFORM* = ptr CANDIDATEFORM

+  TCANDIDATEFORM* = CANDIDATEFORM

+  PCANDIDATEFORM* = ptr CANDIDATEFORM

+  CANDIDATELIST* {.final, pure.} = object

+    dwSize*: DWORD

+    dwStyle*: DWORD

+    dwCount*: DWORD

+    dwSelection*: DWORD

+    dwPageStart*: DWORD

+    dwPageSize*: DWORD

+    dwOffset*: array[0..0, DWORD]

+

+  LPCANDIDATELIST* = ptr CANDIDATELIST

+  TCANDIDATELIST* = CANDIDATELIST

+  PCANDIDATELIST* = ptr CANDIDATELIST

+  CREATESTRUCT* {.final, pure.} = object

+    lpCreateParams*: LPVOID

+    hInstance*: HINST

+    hMenu*: HMENU

+    hwndParent*: HWND

+    cy*: int32

+    cx*: int32

+    y*: int32

+    x*: int32

+    style*: LONG

+    lpszName*: LPCTSTR

+    lpszClass*: LPCTSTR

+    dwExStyle*: DWORD

+

+  LPCREATESTRUCT* = ptr CREATESTRUCT

+  TCREATESTRUCT* = CREATESTRUCT

+  PCREATESTRUCT* = ptr CREATESTRUCT

+  CBT_CREATEWND* {.final, pure.} = object

+    lpcs*: LPCREATESTRUCT

+    hwndInsertAfter*: HWND

+

+  TCBT_CREATEWND* = CBT_CREATEWND

+  PCBT_CREATEWND* = ptr CBT_CREATEWND

+  CBTACTIVATESTRUCT* {.final, pure.} = object

+    fMouse*: WINBOOL

+    hWndActive*: HWND

+

+  TCBTACTIVATESTRUCT* = CBTACTIVATESTRUCT

+  PCBTACTIVATESTRUCT* = ptr CBTACTIVATESTRUCT

+  CHAR_INFO* {.final, pure.} = object

+    UnicodeChar*: WCHAR

+    Attributes*: int16        # other union part: AsciiChar : CHAR

+

+  TCHAR_INFO* = CHAR_INFO

+  PCHAR_INFO* = ptr CHAR_INFO

+  CHARFORMAT* {.final, pure.} = object

+    cbSize*: WINUINT

+    dwMask*: DWORD

+    dwEffects*: DWORD

+    yHeight*: LONG

+    yOffset*: LONG

+    crTextColor*: COLORREF

+    bCharSet*: int8

+    bPitchAndFamily*: int8

+    szFaceName*: array[0..(LF_FACESIZE) - 1, TCHAR]

+

+  Tcharformat* = CHARFORMAT

+  Pcharformat* = ptr CHARFORMAT

+  CHARRANGE* {.final, pure.} = object

+    cpMin*: LONG

+    cpMax*: LONG

+

+  Tcharrange* = CHARRANGE

+  Pcharrange* = ptr CHARRANGE

+  CHARSET* {.final, pure.} = object

+    aflBlock*: array[0..2, DWORD]

+    flLang*: DWORD

+

+  TCHARSET* = CHARSET

+  PCHARSET* = ptr CHARSET

+  FONTSIGNATURE* {.final, pure.} = object

+    fsUsb*: array[0..3, DWORD]

+    fsCsb*: array[0..1, DWORD]

+

+  LPFONTSIGNATURE* = ptr FONTSIGNATURE

+  TFONTSIGNATURE* = FONTSIGNATURE

+  PFONTSIGNATURE* = ptr FONTSIGNATURE

+  CHARSETINFO* {.final, pure.} = object

+    ciCharset*: WINUINT

+    ciACP*: WINUINT

+    fs*: FONTSIGNATURE

+

+  LPCHARSETINFO* = ptr CHARSETINFO

+  TCHARSETINFO* = CHARSETINFO

+  PCHARSETINFO* = ptr CHARSETINFO

+  #CHOOSECOLOR = record confilcts with function ChooseColor

+  TCHOOSECOLOR* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hInstance*: HWND

+    rgbResult*: COLORREF

+    lpCustColors*: ptr COLORREF

+    Flags*: DWORD

+    lCustData*: LPARAM

+    lpfnHook*: LPCCHOOKPROC

+    lpTemplateName*: LPCTSTR

+

+  LPCHOOSECOLOR* = ptr TCHOOSECOLOR

+  PCHOOSECOLOR* = ptr TCHOOSECOLOR

+  LOGFONT* {.final, pure.} = object

+    lfHeight*: LONG

+    lfWidth*: LONG

+    lfEscapement*: LONG

+    lfOrientation*: LONG

+    lfWeight*: LONG

+    lfItalic*: int8

+    lfUnderline*: int8

+    lfStrikeOut*: int8

+    lfCharSet*: int8

+    lfOutPrecision*: int8

+    lfClipPrecision*: int8

+    lfQuality*: int8

+    lfPitchAndFamily*: int8

+    lfFaceName*: array[0..(LF_FACESIZE) - 1, TCHAR]

+

+  LPLOGFONT* = ptr LOGFONT

+  TLOGFONT* = LOGFONT

+  TLOGFONTA* = LOGFONT

+  PLOGFONT* = ptr LOGFONT

+  PLOGFONTA* = PLOGFONT

+  LOGFONTW* {.final, pure.} = object

+    lfHeight*: LONG

+    lfWidth*: LONG

+    lfEscapement*: LONG

+    lfOrientation*: LONG

+    lfWeight*: LONG

+    lfItalic*: int8

+    lfUnderline*: int8

+    lfStrikeOut*: int8

+    lfCharSet*: int8

+    lfOutPrecision*: int8

+    lfClipPrecision*: int8

+    lfQuality*: int8

+    lfPitchAndFamily*: int8

+    lfFaceName*: array[0..LF_FACESIZE - 1, WCHAR]

+

+  LPLOGFONTW* = ptr LOGFONTW

+  NPLOGFONTW* = ptr LOGFONTW

+  TLogFontW* = LOGFONTW

+  PLogFontW* = ptr TLogFontW

+  TCHOOSEFONT* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hDC*: HDC

+    lpLogFont*: LPLOGFONT

+    iPointSize*: WINT

+    Flags*: DWORD

+    rgbColors*: DWORD

+    lCustData*: LPARAM

+    lpfnHook*: LPCFHOOKPROC

+    lpTemplateName*: LPCTSTR

+    hInstance*: HINST

+    lpszStyle*: LPTSTR

+    nFontType*: int16

+    MISSING_ALIGNMENT*: int16

+    nSizeMin*: WINT

+    nSizeMax*: WINT

+

+  LPCHOOSEFONT* = ptr TCHOOSEFONT

+  PCHOOSEFONT* = ptr TCHOOSEFONT

+  CIDA* {.final, pure.} = object

+    cidl*: WINUINT

+    aoffset*: array[0..0, WINUINT]

+

+  LPIDA* = ptr CIDA

+  TIDA* = CIDA

+  PIDA* = ptr CIDA

+  CLIENTCREATESTRUCT* {.final, pure.} = object

+    hWindowMenu*: HANDLE

+    idFirstChild*: WINUINT

+

+  LPCLIENTCREATESTRUCT* = ptr CLIENTCREATESTRUCT

+  TCLIENTCREATESTRUCT* = CLIENTCREATESTRUCT

+  PCLIENTCREATESTRUCT* = ptr CLIENTCREATESTRUCT

+  CMINVOKECOMMANDINFO* {.final, pure.} = object

+    cbSize*: DWORD

+    fMask*: DWORD

+    hwnd*: HWND

+    lpVerb*: LPCSTR

+    lpParameters*: LPCSTR

+    lpDirectory*: LPCSTR

+    nShow*: int32

+    dwHotKey*: DWORD

+    hIcon*: HANDLE

+

+  LPCMINVOKECOMMANDINFO* = ptr CMINVOKECOMMANDINFO

+  TCMInvokeCommandInfo* = CMINVOKECOMMANDINFO

+  PCMInvokeCommandInfo* = ptr CMINVOKECOMMANDINFO

+  COLORADJUSTMENT* {.final, pure.} = object

+    caSize*: int16

+    caFlags*: int16

+    caIlluminantIndex*: int16

+    caRedGamma*: int16

+    caGreenGamma*: int16

+    caBlueGamma*: int16

+    caReferenceBlack*: int16

+    caReferenceWhite*: int16

+    caContrast*: SHORT

+    caBrightness*: SHORT

+    caColorfulness*: SHORT

+    caRedGreenTint*: SHORT

+

+  LPCOLORADJUSTMENT* = ptr COLORADJUSTMENT

+  TCOLORADJUSTMENT* = COLORADJUSTMENT

+  PCOLORADJUSTMENT* = ptr COLORADJUSTMENT

+  COLORMAP* {.final, pure.} = object

+    `from`*: COLORREF

+    `to`*: COLORREF          # XXX!

+

+  LPCOLORMAP* = ptr COLORMAP

+  TCOLORMAP* = COLORMAP

+  PCOLORMAP* = ptr COLORMAP

+  DCB* {.final, pure.} = object

+    DCBlength*: DWORD

+    BaudRate*: DWORD

+    flags*: DWORD

+    wReserved*: int16

+    XonLim*: int16

+    XoffLim*: int16

+    ByteSize*: int8

+    Parity*: int8

+    StopBits*: int8

+    XonChar*: char

+    XoffChar*: char

+    ErrorChar*: char

+    EofChar*: char

+    EvtChar*: char

+    wReserved1*: int16

+

+  LPDCB* = ptr DCB

+  TDCB* = DCB

+  PDCB* = ptr DCB

+

+const

+  bm_DCB_fBinary* = 1

+  bp_DCB_fBinary* = 0'i32

+  bm_DCB_fParity* = 0x00000002

+  bp_DCB_fParity* = 1'i32

+  bm_DCB_fOutxCtsFlow* = 0x00000004

+  bp_DCB_fOutxCtsFlow* = 2'i32

+  bm_DCB_fOutxDsrFlow* = 0x00000008

+  bp_DCB_fOutxDsrFlow* = 3'i32

+  bm_DCB_fDtrControl* = 0x00000030

+  bp_DCB_fDtrControl* = 4'i32

+  bm_DCB_fDsrSensitivity* = 0x00000040

+  bp_DCB_fDsrSensitivity* = 6'i32

+  bm_DCB_fTXContinueOnXoff* = 0x00000080

+  bp_DCB_fTXContinueOnXoff* = 7'i32

+  bm_DCB_fOutX* = 0x00000100

+  bp_DCB_fOutX* = 8'i32

+  bm_DCB_fInX* = 0x00000200

+  bp_DCB_fInX* = 9'i32

+  bm_DCB_fErrorChar* = 0x00000400

+  bp_DCB_fErrorChar* = 10'i32

+  bm_DCB_fNull* = 0x00000800

+  bp_DCB_fNull* = 11'i32

+  bm_DCB_fRtsControl* = 0x00003000

+  bp_DCB_fRtsControl* = 12'i32

+  bm_DCB_fAbortOnError* = 0x00004000

+  bp_DCB_fAbortOnError* = 14'i32

+  bm_DCB_fDummy2* = 0xFFFF8000'i32

+  bp_DCB_fDummy2* = 15'i32

+

+proc fBinary*(a: var DCB): DWORD

+proc set_fBinary*(a: var DCB, fBinary: DWORD)

+proc fParity*(a: var DCB): DWORD

+proc set_fParity*(a: var DCB, fParity: DWORD)

+proc fOutxCtsFlow*(a: var DCB): DWORD

+proc set_fOutxCtsFlow*(a: var DCB, fOutxCtsFlow: DWORD)

+proc fOutxDsrFlow*(a: var DCB): DWORD

+proc set_fOutxDsrFlow*(a: var DCB, fOutxDsrFlow: DWORD)

+proc fDtrControl*(a: var DCB): DWORD

+proc set_fDtrControl*(a: var DCB, fDtrControl: DWORD)

+proc fDsrSensitivity*(a: var DCB): DWORD

+proc set_fDsrSensitivity*(a: var DCB, fDsrSensitivity: DWORD)

+proc fTXContinueOnXoff*(a: var DCB): DWORD

+proc set_fTXContinueOnXoff*(a: var DCB, fTXContinueOnXoff: DWORD)

+proc fOutX*(a: var DCB): DWORD

+proc set_fOutX*(a: var DCB, fOutX: DWORD)

+proc fInX*(a: var DCB): DWORD

+proc set_fInX*(a: var DCB, fInX: DWORD)

+proc fErrorChar*(a: var DCB): DWORD

+proc set_fErrorChar*(a: var DCB, fErrorChar: DWORD)

+proc fNull*(a: var DCB): DWORD

+proc set_fNull*(a: var DCB, fNull: DWORD)

+proc fRtsControl*(a: var DCB): DWORD

+proc set_fRtsControl*(a: var DCB, fRtsControl: DWORD)

+proc fAbortOnError*(a: var DCB): DWORD

+proc set_fAbortOnError*(a: var DCB, fAbortOnError: DWORD)

+proc fDummy2*(a: var DCB): DWORD

+proc set_fDummy2*(a: var DCB, fDummy2: DWORD)

+type

+  COMMCONFIG* {.final, pure.} = object

+    dwSize*: DWORD

+    wVersion*: int16

+    wReserved*: int16

+    dcb*: DCB

+    dwProviderSubType*: DWORD

+    dwProviderOffset*: DWORD

+    dwProviderSize*: DWORD

+    wcProviderData*: array[0..0, WCHAR]

+

+  LPCOMMCONFIG* = ptr COMMCONFIG

+  TCOMMCONFIG* = COMMCONFIG

+  PCOMMCONFIG* = ptr COMMCONFIG

+  COMMPROP* {.final, pure.} = object

+    wPacketLength*: int16

+    wPacketVersion*: int16

+    dwServiceMask*: DWORD

+    dwReserved1*: DWORD

+    dwMaxTxQueue*: DWORD

+    dwMaxRxQueue*: DWORD

+    dwMaxBaud*: DWORD

+    dwProvSubType*: DWORD

+    dwProvCapabilities*: DWORD

+    dwSettableParams*: DWORD

+    dwSettableBaud*: DWORD

+    wSettableData*: int16

+    wSettableStopParity*: int16

+    dwCurrentTxQueue*: DWORD

+    dwCurrentRxQueue*: DWORD

+    dwProvSpec1*: DWORD

+    dwProvSpec2*: DWORD

+    wcProvChar*: array[0..0, WCHAR]

+

+  LPCOMMPROP* = ptr COMMPROP

+  TCOMMPROP* = COMMPROP

+  PCOMMPROP* = ptr COMMPROP

+  COMMTIMEOUTS* {.final, pure.} = object

+    ReadIntervalTimeout*: DWORD

+    ReadTotalTimeoutMultiplier*: DWORD

+    ReadTotalTimeoutConstant*: DWORD

+    WriteTotalTimeoutMultiplier*: DWORD

+    WriteTotalTimeoutConstant*: DWORD

+

+  LPCOMMTIMEOUTS* = ptr COMMTIMEOUTS

+  TCOMMTIMEOUTS* = COMMTIMEOUTS

+  PCOMMTIMEOUTS* = ptr COMMTIMEOUTS

+  COMPAREITEMSTRUCT* {.final, pure.} = object

+    CtlType*: WINUINT

+    CtlID*: WINUINT

+    hwndItem*: HWND

+    itemID1*: WINUINT

+    itemData1*: ULONG_PTR

+    itemID2*: WINUINT

+    itemData2*: ULONG_PTR

+

+  TCOMPAREITEMSTRUCT* = COMPAREITEMSTRUCT

+  PCOMPAREITEMSTRUCT* = ptr COMPAREITEMSTRUCT

+  COMPCOLOR* {.final, pure.} = object

+    crText*: COLORREF

+    crBackground*: COLORREF

+    dwEffects*: DWORD

+

+  TCOMPCOLOR* = COMPCOLOR

+  PCOMPCOLOR* = ptr COMPCOLOR

+  COMPOSITIONFORM* {.final, pure.} = object

+    dwStyle*: DWORD

+    ptCurrentPos*: POINT

+    rcArea*: RECT

+

+  LPCOMPOSITIONFORM* = ptr COMPOSITIONFORM

+  TCOMPOSITIONFORM* = COMPOSITIONFORM

+  PCOMPOSITIONFORM* = ptr COMPOSITIONFORM #     TComStatFlags = set of (fCtsHold, fDsrHold, fRlsdHold , fXoffHold ,

+                                          #                    fXoffSent , fEof ,  fTxim  , fReserved);

+  COMSTAT* {.final, pure.} = object

+    flag0*: DWORD             # can't use tcomstatflags, set packing issues

+                              # and conflicts with macro's

+    cbInQue*: DWORD

+    cbOutQue*: DWORD

+

+  LPCOMSTAT* = ptr COMSTAT

+  TCOMSTAT* = COMSTAT

+  PCOMSTAT* = ptr COMSTAT

+

+const

+  bm_COMSTAT_fCtsHold* = 0x00000001

+  bp_COMSTAT_fCtsHold* = 0'i32

+  bm_COMSTAT_fDsrHold* = 0x00000002

+  bp_COMSTAT_fDsrHold* = 1'i32

+  bm_COMSTAT_fRlsdHold* = 0x00000004

+  bp_COMSTAT_fRlsdHold* = 2'i32

+  bm_COMSTAT_fXoffHold* = 0x00000008

+  bp_COMSTAT_fXoffHold* = 3'i32

+  bm_COMSTAT_fXoffSent* = 0x00000010

+  bp_COMSTAT_fXoffSent* = 4'i32

+  bm_COMSTAT_fEof* = 0x00000020

+  bp_COMSTAT_fEof* = 5'i32

+  bm_COMSTAT_fTxim* = 0x00000040

+  bp_COMSTAT_fTxim* = 6'i32

+  bm_COMSTAT_fReserved* = 0xFFFFFF80'i32

+  bp_COMSTAT_fReserved* = 7'i32

+

+proc fCtsHold*(a: var COMSTAT): DWORD

+  # should be renamed to get_<x>?

+proc set_fCtsHold*(a: var COMSTAT, fCtsHold: DWORD)

+proc fDsrHold*(a: var COMSTAT): DWORD

+proc set_fDsrHold*(a: var COMSTAT, fDsrHold: DWORD)

+proc fRlsdHold*(a: var COMSTAT): DWORD

+proc set_fRlsdHold*(a: var COMSTAT, fRlsdHold: DWORD)

+proc fXoffHold*(a: var COMSTAT): DWORD

+proc set_fXoffHold*(a: var COMSTAT, fXoffHold: DWORD)

+proc fXoffSent*(a: var COMSTAT): DWORD

+proc set_fXoffSent*(a: var COMSTAT, fXoffSent: DWORD)

+proc fEof*(a: var COMSTAT): DWORD

+proc set_fEof*(a: var COMSTAT, fEof: DWORD)

+proc fTxim*(a: var COMSTAT): DWORD

+proc set_fTxim*(a: var COMSTAT, fTxim: DWORD)

+proc fReserved*(a: var COMSTAT): DWORD

+proc set_fReserved*(a: var COMSTAT, fReserved: DWORD)

+type

+  CONSOLE_CURSOR_INFO* {.final, pure.} = object

+    dwSize*: DWORD

+    bVisible*: WINBOOL

+

+  PCONSOLE_CURSOR_INFO* = ptr CONSOLE_CURSOR_INFO

+  TCONSOLECURSORINFO* = CONSOLE_CURSOR_INFO

+  TCURSORINFO* = CONSOLE_CURSOR_INFO

+  COORD* {.final, pure.} = object

+    X*: SHORT

+    Y*: SHORT

+

+  TCOORD* = COORD

+  PCOORD* = ptr COORD

+  SMALL_RECT* {.final, pure.} = object

+    Left*: SHORT

+    Top*: SHORT

+    Right*: SHORT

+    Bottom*: SHORT

+

+  TSMALL_RECT* = SMALL_RECT

+  PSMALL_RECT* = ptr SMALL_RECT

+  CONSOLE_SCREEN_BUFFER_INFO* {.final, pure.} = object

+    dwSize*: COORD

+    dwCursorPosition*: COORD

+    wAttributes*: int16

+    srWindow*: SMALL_RECT

+    dwMaximumWindowSize*: COORD

+

+  PCONSOLE_SCREEN_BUFFER_INFO* = ptr CONSOLE_SCREEN_BUFFER_INFO

+  TCONSOLESCREENBUFFERINFO* = CONSOLE_SCREEN_BUFFER_INFO

+

+when defined(i386):

+  type

+    FLOATING_SAVE_AREA* {.final, pure.} = object

+      ControlWord*: DWORD

+      StatusWord*: DWORD

+      TagWord*: DWORD

+      ErrorOffset*: DWORD

+      ErrorSelector*: DWORD

+      DataOffset*: DWORD

+      DataSelector*: DWORD

+      RegisterArea*: array[0..79, int8]

+      Cr0NpxState*: DWORD

+

+    TFLOATINGSAVEAREA* = FLOATING_SAVE_AREA

+    PFLOATINGSAVEAREA* = ptr FLOATING_SAVE_AREA

+    CONTEXT* {.final, pure.} = object

+      ContextFlags*: DWORD

+      Dr0*: DWORD

+      Dr1*: DWORD

+      Dr2*: DWORD

+      Dr3*: DWORD

+      Dr6*: DWORD

+      Dr7*: DWORD

+      FloatSave*: FLOATING_SAVE_AREA

+      SegGs*: DWORD

+      SegFs*: DWORD

+      SegEs*: DWORD

+      SegDs*: DWORD

+      Edi*: DWORD

+      Esi*: DWORD

+      Ebx*: DWORD

+      Edx*: DWORD

+      Ecx*: DWORD

+      Eax*: DWORD

+      Ebp*: DWORD

+      Eip*: DWORD

+      SegCs*: DWORD

+      EFlags*: DWORD

+      Esp*: DWORD

+      SegSs*: DWORD

+

+elif defined(x86_64):

+  #

+  # Define 128-bit 16-byte aligned xmm register type.

+  #

+  type

+    M128A* {.final, pure.} = object

+      Low*: ULONGLONG

+      High*: LONGLONG

+

+    TM128A* = M128A

+    PM128A* = TM128A #typedef struct _XMM_SAVE_AREA32 {

+    XMM_SAVE_AREA32* {.final, pure.} = object

+      ControlWord*: int16

+      StatusWord*: int16

+      TagWord*: int8

+      Reserved1*: int8

+      ErrorOpcode*: int16

+      ErrorOffset*: DWORD

+      ErrorSelector*: int16

+      Reserved2*: int16

+      DataOffset*: DWORD

+      DataSelector*: int16

+      Reserved3*: int16

+      MxCsr*: DWORD

+      MxCsr_Mask*: DWORD

+      FloatRegisters*: array[0..7, M128A]

+      XmmRegisters*: array[0..16, M128A]

+      Reserved4*: array[0..95, int8]

+

+    TXmmSaveArea* = XMM_SAVE_AREA32

+    PXmmSaveArea* = ptr TXmmSaveArea

+  type

+    CONTEXT* {.final, pure.} = object

+      P1Home*: DWORD64

+      P2Home*: DWORD64

+      P3Home*: DWORD64

+      P4Home*: DWORD64

+      P5Home*: DWORD64

+      P6Home*: DWORD64        #

+                              # Control flags.

+                              #

+      ContextFlags*: DWORD

+      MxCsr*: DWORD           #

+                              # Segment Registers and processor flags.

+                              #

+      SegCs*: int16

+      SegDs*: int16

+      SegEs*: int16

+      SegFs*: int16

+      SegGs*: int16

+      SegSs*: int16

+      EFlags*: DWORD          #

+                              # Debug registers

+                              #

+      Dr0*: DWORD64

+      Dr1*: DWORD64

+      Dr2*: DWORD64

+      Dr3*: DWORD64

+      Dr6*: DWORD64

+      Dr7*: DWORD64           #

+                              # Integer registers.

+                              #

+      Rax*: DWORD64

+      Rcx*: DWORD64

+      Rdx*: DWORD64

+      Rbx*: DWORD64

+      Rsp*: DWORD64

+      Rbp*: DWORD64

+      Rsi*: DWORD64

+      Rdi*: DWORD64

+      R8*: DWORD64

+      R9*: DWORD64

+      R10*: DWORD64

+      R11*: DWORD64

+      R12*: DWORD64

+      R13*: DWORD64

+      R14*: DWORD64

+      R15*: DWORD64           #

+                              # Program counter.

+                              #

+      Rip*: DWORD64           #

+                              # Floating point state.

+                              #

+      FltSave*: XMM_SAVE_AREA32 # MWE: only translated the FltSave part of the union

+                                #

+                                # Vector registers.

+                                #

+      VectorRegister*: array[0..25, M128A]

+      VectorControl*: DWORD64 #

+                              # Special debug control registers.

+                              #

+      DebugControl*: DWORD64

+      LastBranchToRip*: DWORD64

+      LastBranchFromRip*: DWORD64

+      LastExceptionToRip*: DWORD64

+      LastExceptionFromRip*: DWORD64

+

+elif hostCPU == "powerpc":

+  # ppc

+  # Floating point registers returned when CONTEXT_FLOATING_POINT is set

+  # Integer registers returned when CONTEXT_INTEGER is set.

+  # Condition register

+  # Fixed point exception register

+  # The following are set when CONTEXT_CONTROL is set.

+  # Machine status register

+  # Instruction address register

+  # Link register

+  # Control register

+  # Control which context values are returned

+  # Registers returned if CONTEXT_DEBUG_REGISTERS is set.

+  # Breakpoint Register 1

+  # Breakpoint Register 2

+  # Breakpoint Register 3

+  # Breakpoint Register 4

+  # Breakpoint Register 5

+  # Breakpoint Register 6

+  # Debug Status Register

+  # Debug Control Register

+  type

+    CONTEXT* {.final, pure.} = object

+      Fpr0*: float64

+      Fpr1*: float64

+      Fpr2*: float64

+      Fpr3*: float64

+      Fpr4*: float64

+      Fpr5*: float64

+      Fpr6*: float64

+      Fpr7*: float64

+      Fpr8*: float64

+      Fpr9*: float64

+      Fpr10*: float64

+      Fpr11*: float64

+      Fpr12*: float64

+      Fpr13*: float64

+      Fpr14*: float64

+      Fpr15*: float64

+      Fpr16*: float64

+      Fpr17*: float64

+      Fpr18*: float64

+      Fpr19*: float64

+      Fpr20*: float64

+      Fpr21*: float64

+      Fpr22*: float64

+      Fpr23*: float64

+      Fpr24*: float64

+      Fpr25*: float64

+      Fpr26*: float64

+      Fpr27*: float64

+      Fpr28*: float64

+      Fpr29*: float64

+      Fpr30*: float64

+      Fpr31*: float64

+      Fpscr*: float64

+      Gpr0*: DWORD

+      Gpr1*: DWORD

+      Gpr2*: DWORD

+      Gpr3*: DWORD

+      Gpr4*: DWORD

+      Gpr5*: DWORD

+      Gpr6*: DWORD

+      Gpr7*: DWORD

+      Gpr8*: DWORD

+      Gpr9*: DWORD

+      Gpr10*: DWORD

+      Gpr11*: DWORD

+      Gpr12*: DWORD

+      Gpr13*: DWORD

+      Gpr14*: DWORD

+      Gpr15*: DWORD

+      Gpr16*: DWORD

+      Gpr17*: DWORD

+      Gpr18*: DWORD

+      Gpr19*: DWORD

+      Gpr20*: DWORD

+      Gpr21*: DWORD

+      Gpr22*: DWORD

+      Gpr23*: DWORD

+      Gpr24*: DWORD

+      Gpr25*: DWORD

+      Gpr26*: DWORD

+      Gpr27*: DWORD

+      Gpr28*: DWORD

+      Gpr29*: DWORD

+      Gpr30*: DWORD

+      Gpr31*: DWORD

+      Cr*: DWORD

+      Xer*: DWORD

+      Msr*: DWORD

+      Iar*: DWORD

+      Lr*: DWORD

+      Ctr*: DWORD

+      ContextFlags*: DWORD

+      Fill*: array[0..2, DWORD]

+      Dr0*: DWORD

+      Dr1*: DWORD

+      Dr2*: DWORD

+      Dr3*: DWORD

+      Dr4*: DWORD

+      Dr5*: DWORD

+      Dr6*: DWORD

+      Dr7*: DWORD

+

+else:

+  # dummy CONTEXT so that it compiles:

+  type

+    CONTEXT* {.final, pure.} = object

+      data: array [0..255, float64]

+

+type

+  LPCONTEXT* = ptr CONTEXT

+  TCONTEXT* = CONTEXT

+  PCONTEXT* = ptr CONTEXT

+

+type

+  LIST_ENTRY* {.final, pure.} = object

+    Flink*: ptr LIST_ENTRY

+    Blink*: ptr LIST_ENTRY

+

+  TLISTENTRY* = LIST_ENTRY

+  PLISTENTRY* = ptr LIST_ENTRY

+  CRITICAL_SECTION_DEBUG* {.final, pure.} = object

+    `type`*: int16

+    CreatorBackTraceIndex*: int16

+    CriticalSection*: ptr TCRITICAL_SECTION

+    ProcessLocksList*: LIST_ENTRY

+    EntryCount*: DWORD

+    ContentionCount*: DWORD

+    Depth*: DWORD

+    OwnerBackTrace*: array[0..4, PVOID]

+

+  TRTL_CRITICAL_SECTION* {.final, pure.} = object

+    DebugInfo*: ptr CRITICAL_SECTION_DEBUG

+    LockCount*: int32

+    RecursionCount*: int32

+    OwningThread*: Handle

+    LockSemaphore*: Handle

+    Reserved*: DWORD

+

+  PRTLCriticalSection* = ptr TRTLCriticalSection

+

+  LPCRITICAL_SECTION_DEBUG* = ptr CRITICAL_SECTION_DEBUG

+  PCRITICAL_SECTION_DEBUG* = ptr CRITICAL_SECTION_DEBUG

+  TCRITICALSECTIONDEBUG* = CRITICAL_SECTION_DEBUG

+  TCRITICAL_SECTION* = TRTLCriticalSection

+  PCRITICAL_SECTION* = PRTLCriticalSection

+  LPCRITICAL_SECTION* = PRTLCriticalSection

+  SECURITY_QUALITY_OF_SERVICE* {.final, pure.} = object

+    len*: DWORD

+    ImpersonationLevel*: SECURITY_IMPERSONATION_LEVEL

+    ContextTrackingMode*: WINBOOL

+    EffectiveOnly*: bool

+

+  PSECURITY_QUALITY_OF_SERVICE* = ptr SECURITY_QUALITY_OF_SERVICE

+  TSECURITYQUALITYOFSERVICE* = SECURITY_QUALITY_OF_SERVICE

+  CONVCONTEXT* {.final, pure.} = object

+    cb*: WINUINT

+    wFlags*: WINUINT

+    wCountryID*: WINUINT

+    iCodePage*: int32

+    dwLangID*: DWORD

+    dwSecurity*: DWORD

+    qos*: SECURITY_QUALITY_OF_SERVICE

+

+  TCONVCONTEXT* = CONVCONTEXT

+  PCONVCONTEXT* = ptr CONVCONTEXT

+  CONVINFO* {.final, pure.} = object

+    cb*: DWORD

+    hUser*: DWORD

+    hConvPartner*: HCONV

+    hszSvcPartner*: HSZ

+    hszServiceReq*: HSZ

+    hszTopic*: HSZ

+    hszItem*: HSZ

+    wFmt*: WINUINT

+    wType*: WINUINT

+    wStatus*: WINUINT

+    wConvst*: WINUINT

+    wLastError*: WINUINT

+    hConvList*: HCONVLIST

+    ConvCtxt*: CONVCONTEXT

+    hwnd*: HWND

+    hwndPartner*: HWND

+

+  TCONVINFO* = CONVINFO

+  PCONVINFO* = ptr CONVINFO

+  COPYDATASTRUCT* {.final, pure.} = object

+    dwData*: DWORD

+    cbData*: DWORD

+    lpData*: PVOID

+

+  TCOPYDATASTRUCT* = COPYDATASTRUCT

+  PCOPYDATASTRUCT* = ptr COPYDATASTRUCT

+  CPINFO* {.final, pure.} = object

+    MaxCharSize*: WINUINT

+    DefaultChar*: array[0..(MAX_DEFAULTCHAR) - 1, int8]

+    LeadByte*: array[0..(MAX_LEADBYTES) - 1, int8]

+

+  LPCPINFO* = ptr CPINFO

+  Tcpinfo* = CPINFO

+  Pcpinfo* = ptr CPINFO

+  CPLINFO* {.final, pure.} = object

+    idIcon*: int32

+    idName*: int32

+    idInfo*: int32

+    lData*: LONG

+

+  TCPLINFO* = CPLINFO

+  PCPLINFO* = ptr CPLINFO

+  CREATE_PROCESS_DEBUG_INFO* {.final, pure.} = object

+    hFile*: HANDLE

+    hProcess*: HANDLE

+    hThread*: HANDLE

+    lpBaseOfImage*: LPVOID

+    dwDebugInfoFileOffset*: DWORD

+    nDebugInfoSize*: DWORD

+    lpThreadLocalBase*: LPVOID

+    lpStartAddress*: LPTHREAD_START_ROUTINE

+    lpImageName*: LPVOID

+    fUnicode*: int16

+

+  TCREATEPROCESSDEBUGINFO* = CREATE_PROCESS_DEBUG_INFO

+  PCREATEPROCESSDEBUGINFO* = ptr CREATE_PROCESS_DEBUG_INFO

+  CREATE_THREAD_DEBUG_INFO* {.final, pure.} = object

+    hThread*: HANDLE

+    lpThreadLocalBase*: LPVOID

+    lpStartAddress*: LPTHREAD_START_ROUTINE

+

+  TCREATETHREADDEBUGINFO* = CREATE_THREAD_DEBUG_INFO

+  PCREATETHREADDEBUGINFO* = ptr CREATE_THREAD_DEBUG_INFO

+

+  CURRENCYFMT* {.final, pure.} = object

+    NumDigits*: WINUINT

+    LeadingZero*: WINUINT

+    Grouping*: WINUINT

+    lpDecimalSep*: LPTSTR

+    lpThousandSep*: LPTSTR

+    NegativeOrder*: WINUINT

+    PositiveOrder*: WINUINT

+    lpCurrencySymbol*: LPTSTR

+

+  Tcurrencyfmt* = CURRENCYFMT

+  Pcurrencyfmt* = ptr CURRENCYFMT

+  CURSORSHAPE* {.final, pure.} = object

+    xHotSpot*: int32

+    yHotSpot*: int32

+    cx*: int32

+    cy*: int32

+    cbWidth*: int32

+    Planes*: int8

+    BitsPixel*: int8

+

+  LPCURSORSHAPE* = ptr CURSORSHAPE

+  TCURSORSHAPE* = CURSORSHAPE

+  PCURSORSHAPE* = ptr CURSORSHAPE

+  CWPRETSTRUCT* {.final, pure.} = object

+    lResult*: LRESULT

+    lParam*: LPARAM

+    wParam*: WPARAM

+    message*: DWORD

+    hwnd*: HWND

+

+  TCWPRETSTRUCT* = CWPRETSTRUCT

+  PCWPRETSTRUCT* = ptr CWPRETSTRUCT

+  CWPSTRUCT* {.final, pure.} = object

+    lParam*: LPARAM

+    wParam*: WPARAM

+    message*: WINUINT

+    hwnd*: HWND

+

+  TCWPSTRUCT* = CWPSTRUCT

+  PCWPSTRUCT* = ptr CWPSTRUCT

+  DATATYPES_INFO_1* {.final, pure.} = object

+    pName*: LPTSTR

+

+  TDATATYPESINFO1* = DATATYPES_INFO_1

+  PDATATYPESINFO1* = ptr DATATYPES_INFO_1

+  DDEACK* {.final, pure.} = object

+    flag0*: int16

+

+  TDDEACK* = DDEACK

+  PDDEACK* = ptr DDEACK

+

+const

+  bm_DDEACK_bAppReturnCode* = 0x000000FF'i16

+  bp_DDEACK_bAppReturnCode* = 0'i16

+  bm_DDEACK_reserved* = 0x00003F00'i16

+  bp_DDEACK_reserved* = 8'i16

+  bm_DDEACK_fBusy* = 0x00004000'i16

+  bp_DDEACK_fBusy* = 14'i16

+  bm_DDEACK_fAck* = 0x00008000'i16

+  bp_DDEACK_fAck* = 15'i16

+

+proc bAppReturnCode*(a: var DDEACK): int16

+proc set_bAppReturnCode*(a: var DDEACK, bAppReturnCode: int16)

+proc reserved*(a: var DDEACK): int16

+proc set_reserved*(a: var DDEACK, reserved: int16)

+proc fBusy*(a: var DDEACK): int16

+proc set_fBusy*(a: var DDEACK, fBusy: int16)

+proc fAck*(a: var DDEACK): int16

+proc set_fAck*(a: var DDEACK, fAck: int16)

+type

+  DDEADVISE* {.final, pure.} = object

+    flag0*: int16

+    cfFormat*: SHORT

+

+  TDDEADVISE* = DDEADVISE

+  PDDEADVISE* = ptr DDEADVISE

+

+const

+  bm_DDEADVISE_reserved* = 0x00003FFF'i16

+  bp_DDEADVISE_reserved* = 0'i16

+  bm_DDEADVISE_fDeferUpd* = 0x00004000'i16

+  bp_DDEADVISE_fDeferUpd* = 14'i16

+  bm_DDEADVISE_fAckReq* = 0x00008000'i16

+  bp_DDEADVISE_fAckReq* = 15'i16

+

+proc reserved*(a: var DDEADVISE): int16

+proc set_reserved*(a: var DDEADVISE, reserved: int16)

+proc fDeferUpd*(a: var DDEADVISE): int16

+proc set_fDeferUpd*(a: var DDEADVISE, fDeferUpd: int16)

+proc fAckReq*(a: var DDEADVISE): int16

+proc set_fAckReq*(a: var DDEADVISE, fAckReq: int16)

+type

+  DDEDATA* {.final, pure.} = object

+    flag0*: int16

+    cfFormat*: SHORT

+    Value*: array[0..0, int8]

+

+  PDDEDATA* = ptr DDEDATA

+

+const

+  bm_DDEDATA_unused* = 0x00000FFF'i16

+  bp_DDEDATA_unused* = 0'i16

+  bm_DDEDATA_fResponse* = 0x00001000'i16

+  bp_DDEDATA_fResponse* = 12'i16

+  bm_DDEDATA_fRelease* = 0x00002000'i16

+  bp_DDEDATA_fRelease* = 13'i16

+  bm_DDEDATA_reserved* = 0x00004000'i16

+  bp_DDEDATA_reserved* = 14'i16

+  bm_DDEDATA_fAckReq* = 0x00008000'i16

+  bp_DDEDATA_fAckReq* = 15'i16

+

+proc unused*(a: var DDEDATA): int16

+proc set_unused*(a: var DDEDATA, unused: int16)

+proc fResponse*(a: var DDEDATA): int16

+proc set_fResponse*(a: var DDEDATA, fResponse: int16)

+proc fRelease*(a: var DDEDATA): int16

+proc set_fRelease*(a: var DDEDATA, fRelease: int16)

+proc reserved*(a: var DDEDATA): int16

+proc set_reserved*(a: var DDEDATA, reserved: int16)

+proc fAckReq*(a: var DDEDATA): int16

+proc set_fAckReq*(a: var DDEDATA, fAckReq: int16)

+type

+  DDELN* {.final, pure.} = object

+    flag0*: int16

+    cfFormat*: SHORT

+

+  TDDELN* = DDELN

+  PDDELN* = ptr DDELN

+

+const

+  bm_DDELN_unused* = 0x00001FFF'i16

+  bp_DDELN_unused* = 0'i16

+  bm_DDELN_fRelease* = 0x00002000'i16

+  bp_DDELN_fRelease* = 13'i16

+  bm_DDELN_fDeferUpd* = 0x00004000'i16

+  bp_DDELN_fDeferUpd* = 14'i16

+  bm_DDELN_fAckReq* = 0x00008000'i16

+  bp_DDELN_fAckReq* = 15'i16

+

+proc unused*(a: var DDELN): int16

+proc set_unused*(a: var DDELN, unused: int16)

+proc fRelease*(a: var DDELN): int16

+proc set_fRelease*(a: var DDELN, fRelease: int16)

+proc fDeferUpd*(a: var DDELN): int16

+proc set_fDeferUpd*(a: var DDELN, fDeferUpd: int16)

+proc fAckReq*(a: var DDELN): int16

+proc set_fAckReq*(a: var DDELN, fAckReq: int16)

+type

+  DDEML_MSG_HOOK_DATA* {.final, pure.} = object

+    uiLo*: WINUINT

+    uiHi*: WINUINT

+    cbData*: DWORD

+    Data*: array[0..7, DWORD]

+

+  TDDEMLMSGHOOKDATA* = DDEML_MSG_HOOK_DATA

+  PDDEMLMSGHOOKDATA* = ptr DDEML_MSG_HOOK_DATA

+  DDEPOKE* {.final, pure.} = object

+    flag0*: int16

+    cfFormat*: SHORT

+    Value*: array[0..0, int8]

+

+  TDDEPOKE* = DDEPOKE

+  PDDEPOKE* = ptr DDEPOKE

+

+const

+  bm_DDEPOKE_unused* = 0x00001FFF'i16

+  bp_DDEPOKE_unused* = 0'i16

+  bm_DDEPOKE_fRelease* = 0x00002000'i16

+  bp_DDEPOKE_fRelease* = 13'i16

+  bm_DDEPOKE_fReserved* = 0x0000C000'i16

+  bp_DDEPOKE_fReserved* = 14'i16

+

+proc unused*(a: var DDEPOKE): int16

+proc set_unused*(a: var DDEPOKE, unused: int16)

+proc fRelease*(a: var DDEPOKE): int16

+proc set_fRelease*(a: var DDEPOKE, fRelease: int16)

+proc fReserved*(a: var DDEPOKE): int16

+proc set_fReserved*(a: var DDEPOKE, fReserved: int16)

+type

+  DDEUP* {.final, pure.} = object

+    flag0*: int16

+    cfFormat*: SHORT

+    rgb*: array[0..0, int8]

+

+  TDDEUP* = DDEUP

+  PDDEUP* = ptr DDEUP

+

+const

+  bm_DDEUP_unused* = 0x00000FFF'i16

+  bp_DDEUP_unused* = 0'i16

+  bm_DDEUP_fAck* = 0x00001000'i16

+  bp_DDEUP_fAck* = 12'i16

+  bm_DDEUP_fRelease* = 0x00002000'i16

+  bp_DDEUP_fRelease* = 13'i16

+  bm_DDEUP_fReserved* = 0x00004000'i16

+  bp_DDEUP_fReserved* = 14'i16

+  bm_DDEUP_fAckReq* = 0x00008000'i16

+  bp_DDEUP_fAckReq* = 15'i16

+

+proc unused*(a: var DDEUP): int16

+proc set_unused*(a: var DDEUP, unused: int16)

+proc fAck*(a: var DDEUP): int16

+proc set_fAck*(a: var DDEUP, fAck: int16)

+proc fRelease*(a: var DDEUP): int16

+proc set_fRelease*(a: var DDEUP, fRelease: int16)

+proc fReserved*(a: var DDEUP): int16

+proc set_fReserved*(a: var DDEUP, fReserved: int16)

+proc fAckReq*(a: var DDEUP): int16

+proc set_fAckReq*(a: var DDEUP, fAckReq: int16)

+type

+  EXCEPTION_RECORD* {.final, pure.} = object

+    ExceptionCode*: DWORD

+    ExceptionFlags*: DWORD

+    ExceptionRecord*: ptr EXCEPTION_RECORD

+    ExceptionAddress*: PVOID

+    NumberParameters*: DWORD

+    ExceptionInformation*: array[0..(EXCEPTION_MAXIMUM_PARAMETERS) - 1,

+                                 ULONG_PTR]

+

+  PEXCEPTION_RECORD* = ptr EXCEPTION_RECORD

+  TEXCEPTIONRECORD* = EXCEPTION_RECORD

+  EXCEPTION_DEBUG_INFO* {.final, pure.} = object

+    ExceptionRecord*: EXCEPTION_RECORD

+    dwFirstChance*: DWORD

+

+  PEXCEPTION_DEBUG_INFO* = ptr EXCEPTION_DEBUG_INFO

+  TEXCEPTIONDEBUGINFO* = EXCEPTION_DEBUG_INFO

+  EXCEPTION_RECORD32* {.final, pure.} = object

+    ExceptionCode*: DWORD

+    ExceptionFlags*: DWORD

+    ExceptionRecord*: DWORD

+    ExceptionAddress*: DWORD

+    NumberParameters*: DWORD

+    ExceptionInformation*: array[0..(EXCEPTION_MAXIMUM_PARAMETERS) - 1, DWORD]

+

+  PEXCEPTION_RECORD32* = ptr EXCEPTION_RECORD32

+  TExceptionRecord32* = EXCEPTION_RECORD32

+  EXCEPTION_DEBUG_INFO32* {.final, pure.} = object

+    ExceptionRecord*: EXCEPTION_RECORD32

+    dwFirstChance*: DWORD

+

+  PEXCEPTION_DEBUG_INFO32* = ptr EXCEPTION_DEBUG_INFO32

+  TExceptionDebugInfo32* = EXCEPTION_DEBUG_INFO32

+  EXCEPTION_RECORD64* {.final, pure.} = object

+    ExceptionCode*: DWORD

+    ExceptionFlags*: DWORD

+    ExceptionRecord*: DWORD64

+    ExceptionAddress*: DWORD64

+    NumberParameters*: DWORD

+    unusedAlignment*: DWORD

+    ExceptionInformation*: array[0..(EXCEPTION_MAXIMUM_PARAMETERS) - 1, DWORD64]

+

+  PEXCEPTION_RECORD64* = ptr EXCEPTION_RECORD64

+  TExceptionRecord64* = EXCEPTION_RECORD64

+  EXCEPTION_DEBUG_INFO64* {.final, pure.} = object

+    ExceptionRecord*: EXCEPTION_RECORD64

+    dwFirstChance*: DWORD

+

+  PEXCEPTION_DEBUG_INFO64* = ptr EXCEPTION_DEBUG_INFO64

+  TExceptionDebugInfo64* = EXCEPTION_DEBUG_INFO64

+  EXIT_PROCESS_DEBUG_INFO* {.final, pure.} = object

+    dwExitCode*: DWORD

+

+  TEXITPROCESSDEBUGINFO* = EXIT_PROCESS_DEBUG_INFO

+  PEXITPROCESSDEBUGINFO* = ptr EXIT_PROCESS_DEBUG_INFO

+  EXIT_THREAD_DEBUG_INFO* {.final, pure.} = object

+    dwExitCode*: DWORD

+

+  TEXITTHREADDEBUGINFO* = EXIT_THREAD_DEBUG_INFO

+  PEXITTHREADDEBUGINFO* = ptr EXIT_THREAD_DEBUG_INFO

+  LOAD_DLL_DEBUG_INFO* {.final, pure.} = object

+    hFile*: HANDLE

+    lpBaseOfDll*: LPVOID

+    dwDebugInfoFileOffset*: DWORD

+    nDebugInfoSize*: DWORD

+    lpImageName*: LPVOID

+    fUnicode*: int16

+

+  TLOADDLLDEBUGINFO* = LOAD_DLL_DEBUG_INFO

+  PLOADDLLDEBUGINFO* = ptr LOAD_DLL_DEBUG_INFO

+  UNLOAD_DLL_DEBUG_INFO* {.final, pure.} = object

+    lpBaseOfDll*: LPVOID

+

+  TUNLOADDLLDEBUGINFO* = UNLOAD_DLL_DEBUG_INFO

+  PUNLOADDLLDEBUGINFO* = ptr UNLOAD_DLL_DEBUG_INFO

+  OUTPUT_DEBUG_STRING_INFO* {.final, pure.} = object

+    lpDebugStringData*: LPSTR

+    fUnicode*: int16

+    nDebugStringLength*: int16

+

+  TOUTPUTDEBUGSTRINGINFO* = OUTPUT_DEBUG_STRING_INFO

+  POUTPUTDEBUGSTRINGINFO* = ptr OUTPUT_DEBUG_STRING_INFO

+  RIP_INFO* {.final, pure.} = object

+    dwError*: DWORD

+    dwType*: DWORD

+

+  TRIPINFO* = RIP_INFO

+  PRIPINFO* = ptr RIP_INFO

+  DEBUG_EVENT* {.final, pure.} = object

+    dwDebugEventCode*: DWORD

+    dwProcessId*: DWORD

+    dwThreadId*: DWORD

+    data*: array[0..15, DWORD]

+

+  LPDEBUG_EVENT* = ptr DEBUG_EVENT

+  TDEBUGEVENT* = DEBUG_EVENT

+  PDEBUGEVENT* = ptr DEBUG_EVENT

+  DEBUGHOOKINFO* {.final, pure.} = object

+    idThread*: DWORD

+    idThreadInstaller*: DWORD

+    lParam*: LPARAM

+    wParam*: WPARAM

+    code*: int32

+

+  TDEBUGHOOKINFO* = DEBUGHOOKINFO

+  PDEBUGHOOKINFO* = ptr DEBUGHOOKINFO

+  DELETEITEMSTRUCT* {.final, pure.} = object

+    CtlType*: WINUINT

+    CtlID*: WINUINT

+    itemID*: WINUINT

+    hwndItem*: HWND

+    itemData*: ULONG_PTR

+

+  TDELETEITEMSTRUCT* = DELETEITEMSTRUCT

+  PDELETEITEMSTRUCT* = ptr DELETEITEMSTRUCT

+  DEV_BROADCAST_HDR* {.final, pure.} = object

+    dbch_size*: ULONG

+    dbch_devicetype*: ULONG

+    dbch_reserved*: ULONG

+

+  PDEV_BROADCAST_HDR* = ptr DEV_BROADCAST_HDR

+  TDEVBROADCASTHDR* = DEV_BROADCAST_HDR

+  DEV_BROADCAST_OEM* {.final, pure.} = object

+    dbco_size*: ULONG

+    dbco_devicetype*: ULONG

+    dbco_reserved*: ULONG

+    dbco_identifier*: ULONG

+    dbco_suppfunc*: ULONG

+

+  PDEV_BROADCAST_OEM* = ptr DEV_BROADCAST_OEM

+  TDEVBROADCASTOEM* = DEV_BROADCAST_OEM

+  DEV_BROADCAST_PORT* {.final, pure.} = object

+    dbcp_size*: ULONG

+    dbcp_devicetype*: ULONG

+    dbcp_reserved*: ULONG

+    dbcp_name*: array[0..0, char]

+

+  PDEV_BROADCAST_PORT* = ptr DEV_BROADCAST_PORT

+  TDEVBROADCASTPORT* = DEV_BROADCAST_PORT

+  DEV_BROADCAST_USERDEFINED* {.final, pure.} = object

+    dbud_dbh*: DEV_BROADCAST_HDR

+    dbud_szName*: array[0..0, char]

+    dbud_rgbUserDefined*: array[0..0, int8]

+

+  TDEVBROADCASTUSERDEFINED* = DEV_BROADCAST_USERDEFINED

+  PDEVBROADCASTUSERDEFINED* = ptr DEV_BROADCAST_USERDEFINED

+  DEV_BROADCAST_VOLUME* {.final, pure.} = object

+    dbcv_size*: ULONG

+    dbcv_devicetype*: ULONG

+    dbcv_reserved*: ULONG

+    dbcv_unitmask*: ULONG

+    dbcv_flags*: USHORT

+

+  PDEV_BROADCAST_VOLUME* = ptr DEV_BROADCAST_VOLUME

+  TDEVBROADCASTVOLUME* = DEV_BROADCAST_VOLUME

+  DEVMODE* {.final, pure.} = object

+    dmDeviceName*: array[0..(CCHDEVICENAME) - 1, BCHAR]

+    dmSpecVersion*: int16

+    dmDriverVersion*: int16

+    dmSize*: int16

+    dmDriverExtra*: int16

+    dmFields*: DWORD

+    dmOrientation*: int16

+    dmPaperSize*: int16

+    dmPaperLength*: int16

+    dmPaperWidth*: int16

+    dmScale*: int16

+    dmCopies*: int16

+    dmDefaultSource*: int16

+    dmPrintQuality*: int16

+    dmColor*: int16

+    dmDuplex*: int16

+    dmYResolution*: int16

+    dmTTOption*: int16

+    dmCollate*: int16

+    dmFormName*: array[0..(CCHFORMNAME) - 1, BCHAR]

+    dmLogPixels*: int16

+    dmBitsPerPel*: DWORD

+    dmPelsWidth*: DWORD

+    dmPelsHeight*: DWORD

+    dmDisplayFlags*: DWORD

+    dmDisplayFrequency*: DWORD

+    dmICMMethod*: DWORD

+    dmICMIntent*: DWORD

+    dmMediaType*: DWORD

+    dmDitherType*: DWORD

+    dmICCManufacturer*: DWORD

+    dmICCModel*: DWORD        # other union part:

+                              # dmPosition: POINTL;

+                              # dmDisplayOrientation: DWORD;

+                              # dmDisplayFixedOutput: DWORD;

+

+  LPDEVMODE* = ptr DEVMODE

+  Devicemode* = DEVMODE

+  TDevicemode* = DEVMODE

+  TDevicemodeA* = DEVMODE

+  PDeviceModeA* = LPDEVMODE

+  PDeviceMode* = LPDEVMODE

+  TDEVMODE* = DEVMODE

+  PDEVMODE* = LPDEVMODE

+  DEVMODEW* {.final, pure.} = object

+    dmDeviceName*: array[0..CCHDEVICENAME - 1, WCHAR]

+    dmSpecVersion*: int16

+    dmDriverVersion*: int16

+    dmSize*: int16

+    dmDriverExtra*: int16

+    dmFields*: DWORD

+    dmOrientation*: SHORT

+    dmPaperSize*: SHORT

+    dmPaperLength*: SHORT

+    dmPaperWidth*: SHORT

+    dmScale*: SHORT

+    dmCopies*: SHORT

+    dmDefaultSource*: SHORT

+    dmPrintQuality*: SHORT

+    dmColor*: SHORT

+    dmDuplex*: SHORT

+    dmYResolution*: SHORT

+    dmTTOption*: SHORT

+    dmCollate*: SHORT

+    dmFormName*: array[0..CCHFORMNAME - 1, WCHAR]

+    dmLogPixels*: int16

+    dmBitsPerPel*: DWORD

+    dmPelsWidth*: DWORD

+    dmPelsHeight*: DWORD

+    dmDisplayFlags*: DWORD

+    dmDisplayFrequency*: DWORD

+    dmICMMethod*: DWORD

+    dmICMIntent*: DWORD

+    dmMediaType*: DWORD

+    dmDitherType*: DWORD

+    dmReserved1*: DWORD

+    dmReserved2*: DWORD

+    dmPanningWidth*: DWORD

+    dmPanningHeight*: DWORD

+

+  LPDEVMODEW* = ptr DEVMODEW

+  DevicemodeW* = DEVMODEW

+  TDeviceModeW* = DEVMODEW

+  PDeviceModeW* = LPDEVMODEW

+  TDEVMODEW* = DEVMODEW

+  PDEVMODEW* = LPDEVMODEW

+  DEVNAMES* {.final, pure.} = object

+    wDriverOffset*: int16

+    wDeviceOffset*: int16

+    wOutputOffset*: int16

+    wDefault*: int16

+

+  LPDEVNAMES* = ptr DEVNAMES

+  TDEVNAMES* = DEVNAMES

+  PDEVNAMES* = ptr DEVNAMES

+  DIBSECTION* {.final, pure.} = object

+    dsBm*: BITMAP

+    dsBmih*: BITMAPINFOHEADER

+    dsBitfields*: array[0..2, DWORD]

+    dshSection*: HANDLE

+    dsOffset*: DWORD

+

+  TDIBSECTION* = DIBSECTION

+  PDIBSECTION* = ptr DIBSECTION #

+                                #     LARGE_INTEGER = record

+                                #        case byte of

+                                #          0: (LowPart : DWORD;

+                                #              HighPart : LONG);

+                                #          1: (QuadPart : LONGLONG);

+                                #       end;     ULARGE_INTEGER = record

+                                #        case byte of

+                                #          0: (LowPart : DWORD;

+                                #              HighPart : DWORD);

+                                #          1: (QuadPart : LONGLONG);

+                                #       end;

+                                #

+  LARGE_INTEGER* = int64

+  ULARGE_INTEGER* = int64

+  PLARGE_INTEGER* = ptr LARGE_INTEGER

+  TLargeInteger* = int64

+  PULARGE_INTEGER* = ptr ULARGE_INTEGER

+  TULargeInteger* = int64

+  DISK_GEOMETRY* {.final, pure.} = object

+    Cylinders*: LARGE_INTEGER

+    MediaType*: MEDIA_TYPE

+    TracksPerCylinder*: DWORD

+    SectorsPerTrack*: DWORD

+    BytesPerSector*: DWORD

+

+  TDISKGEOMETRY* = DISK_GEOMETRY

+  PDISKGEOMETRY* = ptr DISK_GEOMETRY

+  DISK_PERFORMANCE* {.final, pure.} = object

+    BytesRead*: LARGE_INTEGER

+    BytesWritten*: LARGE_INTEGER

+    ReadTime*: LARGE_INTEGER

+    WriteTime*: LARGE_INTEGER

+    ReadCount*: DWORD

+    WriteCount*: DWORD

+    QueueDepth*: DWORD

+

+  TDISKPERFORMANCE* = DISK_PERFORMANCE

+  PDISKPERFORMANCE* = ptr DISK_PERFORMANCE

+  DLGITEMTEMPLATE* {.final, pure.} = object

+    style*: DWORD

+    dwExtendedStyle*: DWORD

+    x*: int16

+    y*: int16

+    cx*: int16

+    cy*: int16

+    id*: int16

+

+  LPDLGITEMTEMPLATE* = ptr DLGITEMTEMPLATE

+  TDLGITEMTEMPLATE* = DLGITEMTEMPLATE

+  PDLGITEMTEMPLATE* = ptr DLGITEMTEMPLATE

+  DLGTEMPLATE* {.final, pure.} = object

+    style*: DWORD

+    dwExtendedStyle*: DWORD

+    cdit*: int16

+    x*: int16

+    y*: int16

+    cx*: int16

+    cy*: int16

+

+  LPDLGTEMPLATE* = ptr DLGTEMPLATE

+  LPCDLGTEMPLATE* = ptr DLGTEMPLATE

+  TDLGTEMPLATE* = DLGTEMPLATE

+  PDLGTEMPLATE* = ptr DLGTEMPLATE

+  DOC_INFO_1* {.final, pure.} = object

+    pDocName*: LPTSTR

+    pOutputFile*: LPTSTR

+    pDatatype*: LPTSTR

+

+  TDOCINFO1* = DOC_INFO_1

+  PDOCINFO1* = ptr DOC_INFO_1

+  DOC_INFO_2* {.final, pure.} = object

+    pDocName*: LPTSTR

+    pOutputFile*: LPTSTR

+    pDatatype*: LPTSTR

+    dwMode*: DWORD

+    JobId*: DWORD

+

+  TDOCINFO2* = DOC_INFO_2

+  PDOCINFO2* = ptr DOC_INFO_2

+  DOCINFO* {.final, pure.} = object

+    cbSize*: int32

+    lpszDocName*: LPCTSTR

+    lpszOutput*: LPCTSTR

+    lpszDatatype*: LPCTSTR

+    fwType*: DWORD

+

+  TDOCINFO* = DOCINFO

+  TDOCINFOA* = DOCINFO

+  PDOCINFO* = ptr DOCINFO

+  DRAGLISTINFO* {.final, pure.} = object

+    uNotification*: WINUINT

+    hWnd*: HWND

+    ptCursor*: POINT

+

+  LPDRAGLISTINFO* = ptr DRAGLISTINFO

+  TDRAGLISTINFO* = DRAGLISTINFO

+  PDRAGLISTINFO* = ptr DRAGLISTINFO

+  DRAWITEMSTRUCT* {.final, pure.} = object

+    CtlType*: WINUINT

+    CtlID*: WINUINT

+    itemID*: WINUINT

+    itemAction*: WINUINT

+    itemState*: WINUINT

+    hwndItem*: HWND

+    hDC*: HDC

+    rcItem*: RECT

+    itemData*: ULONG_PTR

+

+  LPDRAWITEMSTRUCT* = ptr DRAWITEMSTRUCT

+  TDRAWITEMSTRUCT* = DRAWITEMSTRUCT

+  PDRAWITEMSTRUCT* = ptr DRAWITEMSTRUCT

+  DRAWTEXTPARAMS* {.final, pure.} = object

+    cbSize*: WINUINT

+    iTabLength*: int32

+    iLeftMargin*: int32

+    iRightMargin*: int32

+    uiLengthDrawn*: WINUINT

+

+  LPDRAWTEXTPARAMS* = ptr DRAWTEXTPARAMS

+  TDRAWTEXTPARAMS* = DRAWTEXTPARAMS

+  PDRAWTEXTPARAMS* = ptr DRAWTEXTPARAMS

+  PARTITION_INFORMATION* {.final, pure.} = object

+    PartitionType*: int8

+    BootIndicator*: bool

+    RecognizedPartition*: bool

+    RewritePartition*: bool

+    StartingOffset*: LARGE_INTEGER

+    PartitionLength*: LARGE_INTEGER

+    HiddenSectors*: LARGE_INTEGER

+

+  TPARTITIONINFORMATION* = PARTITION_INFORMATION

+  PPARTITIONINFORMATION* = ptr PARTITION_INFORMATION

+  DRIVE_LAYOUT_INFORMATION* {.final, pure.} = object

+    PartitionCount*: DWORD

+    Signature*: DWORD

+    PartitionEntry*: array[0..0, PARTITION_INFORMATION]

+

+  TDRIVELAYOUTINFORMATION* = DRIVE_LAYOUT_INFORMATION

+  PDRIVELAYOUTINFORMATION* = ptr DRIVE_LAYOUT_INFORMATION

+  DRIVER_INFO_1* {.final, pure.} = object

+    pName*: LPTSTR

+

+  TDRIVERINFO1* = DRIVER_INFO_1

+  PDRIVERINFO1* = ptr DRIVER_INFO_1

+  DRIVER_INFO_2* {.final, pure.} = object

+    cVersion*: DWORD

+    pName*: LPTSTR

+    pEnvironment*: LPTSTR

+    pDriverPath*: LPTSTR

+    pDataFile*: LPTSTR

+    pConfigFile*: LPTSTR

+

+  TDRIVERINFO2* = DRIVER_INFO_2

+  PDRIVERINFO2* = ptr DRIVER_INFO_2

+  DRIVER_INFO_3* {.final, pure.} = object

+    cVersion*: DWORD

+    pName*: LPTSTR

+    pEnvironment*: LPTSTR

+    pDriverPath*: LPTSTR

+    pDataFile*: LPTSTR

+    pConfigFile*: LPTSTR

+    pHelpFile*: LPTSTR

+    pDependentFiles*: LPTSTR

+    pMonitorName*: LPTSTR

+    pDefaultDataType*: LPTSTR

+

+  TDRIVERINFO3* = DRIVER_INFO_3

+  PDRIVERINFO3* = ptr DRIVER_INFO_3

+  EDITSTREAM* {.final, pure.} = object

+    dwCookie*: DWORD

+    dwError*: DWORD

+    pfnCallback*: EDITSTREAMCALLBACK

+

+  Teditstream* = EDITSTREAM

+  Peditstream* = ptr EDITSTREAM

+  EMR* {.final, pure.} = object

+    iType*: DWORD

+    nSize*: DWORD

+

+  TEMR* = EMR

+  PEMR* = ptr EMR

+  EMRANGLEARC* {.final, pure.} = object

+    emr*: EMR

+    ptlCenter*: POINTL

+    nRadius*: DWORD

+    eStartAngle*: float32

+    eSweepAngle*: float32

+

+  TEMRANGLEARC* = EMRANGLEARC

+  PEMRANGLEARC* = ptr EMRANGLEARC

+  EMRARC* {.final, pure.} = object

+    emr*: EMR

+    rclBox*: RECTL

+    ptlStart*: POINTL

+    ptlEnd*: POINTL

+

+  TEMRARC* = EMRARC

+  PEMRARC* = ptr EMRARC

+  EMRARCTO* = EMRARC

+  TEMRARCTO* = EMRARC

+  PEMRARCTO* = ptr EMRARC

+  EMRCHORD* = EMRARC

+  TEMRCHORD* = EMRARC

+  PEMRCHORD* = ptr EMRARC

+  EMRPIE* = EMRARC

+  TEMRPIE* = EMRARC

+  PEMRPIE* = ptr EMRARC

+  XFORM* {.final, pure.} = object

+    eM11*: float32

+    eM12*: float32

+    eM21*: float32

+    eM22*: float32

+    eDx*: float32

+    eDy*: float32

+

+  LPXFORM* = ptr XFORM

+  TXFORM* = XFORM

+  PXFORM* = ptr XFORM

+  EMRBITBLT* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    xDest*: LONG

+    yDest*: LONG

+    cxDest*: LONG

+    cyDest*: LONG

+    dwRop*: DWORD

+    xSrc*: LONG

+    ySrc*: LONG

+    xformSrc*: XFORM

+    crBkColorSrc*: COLORREF

+    iUsageSrc*: DWORD

+    offBmiSrc*: DWORD

+    offBitsSrc*: DWORD

+    cbBitsSrc*: DWORD

+

+  TEMRBITBLT* = EMRBITBLT

+  PEMRBITBLT* = ptr EMRBITBLT

+  LOGBRUSH* {.final, pure.} = object

+    lbStyle*: WINUINT

+    lbColor*: COLORREF

+    lbHatch*: LONG

+

+  TLOGBRUSH* = LOGBRUSH

+  PLOGBRUSH* = ptr LOGBRUSH

+  EMRCREATEBRUSHINDIRECT* {.final, pure.} = object

+    emr*: EMR

+    ihBrush*: DWORD

+    lb*: LOGBRUSH

+

+  TEMRCREATEBRUSHINDIRECT* = EMRCREATEBRUSHINDIRECT

+  PEMRCREATEBRUSHINDIRECT* = ptr EMRCREATEBRUSHINDIRECT

+  LCSCSTYPE* = LONG

+  LCSGAMUTMATCH* = LONG

+  LOGCOLORSPACE* {.final, pure.} = object

+    lcsSignature*: DWORD

+    lcsVersion*: DWORD

+    lcsSize*: DWORD

+    lcsCSType*: LCSCSTYPE

+    lcsIntent*: LCSGAMUTMATCH

+    lcsEndpoints*: CIEXYZTRIPLE

+    lcsGammaRed*: DWORD

+    lcsGammaGreen*: DWORD

+    lcsGammaBlue*: DWORD

+    lcsFilename*: array[0..(MAX_PATH) - 1, TCHAR]

+

+  LPLOGCOLORSPACE* = ptr LOGCOLORSPACE

+  TLOGCOLORSPACE* = LOGCOLORSPACE

+  TLOGCOLORSPACEA* = LOGCOLORSPACE

+  PLOGCOLORSPACE* = ptr LOGCOLORSPACE

+  EMRCREATECOLORSPACE* {.final, pure.} = object

+    emr*: EMR

+    ihCS*: DWORD

+    lcs*: LOGCOLORSPACE

+

+  TEMRCREATECOLORSPACE* = EMRCREATECOLORSPACE

+  PEMRCREATECOLORSPACE* = ptr EMRCREATECOLORSPACE

+  EMRCREATEDIBPATTERNBRUSHPT* {.final, pure.} = object

+    emr*: EMR

+    ihBrush*: DWORD

+    iUsage*: DWORD

+    offBmi*: DWORD

+    cbBmi*: DWORD

+    offBits*: DWORD

+    cbBits*: DWORD

+

+  TEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT

+  PEMRCREATEDIBPATTERNBRUSHPT* = EMRCREATEDIBPATTERNBRUSHPT

+  EMRCREATEMONOBRUSH* {.final, pure.} = object

+    emr*: EMR

+    ihBrush*: DWORD

+    iUsage*: DWORD

+    offBmi*: DWORD

+    cbBmi*: DWORD

+    offBits*: DWORD

+    cbBits*: DWORD

+

+  TEMRCREATEMONOBRUSH* = EMRCREATEMONOBRUSH

+  PEMRCREATEMONOBRUSH* = ptr EMRCREATEMONOBRUSH

+  PALETTEENTRY* {.final, pure.} = object

+    peRed*: int8

+    peGreen*: int8

+    peBlue*: int8

+    peFlags*: int8

+

+  LPPALETTEENTRY* = ptr PALETTEENTRY

+  TPALETTEENTRY* = PALETTEENTRY

+  PPALETTEENTRY* = ptr PALETTEENTRY

+  LOGPALETTE* {.final, pure.} = object

+    palVersion*: int16

+    palNumEntries*: int16

+    palPalEntry*: array[0..0, PALETTEENTRY]

+

+  LPLOGPALETTE* = ptr LOGPALETTE

+  NPLOGPALETTE* = ptr LOGPALETTE

+  TLOGPALETTE* = LOGPALETTE

+  PLOGPALETTE* = ptr LOGPALETTE

+  EMRCREATEPALETTE* {.final, pure.} = object

+    emr*: EMR

+    ihPal*: DWORD

+    lgpl*: LOGPALETTE

+

+  TEMRCREATEPALETTE* = EMRCREATEPALETTE

+  PEMRCREATEPALETTE* = ptr EMRCREATEPALETTE

+  LOGPEN* {.final, pure.} = object

+    lopnStyle*: WINUINT

+    lopnWidth*: POINT

+    lopnColor*: COLORREF

+

+  TLOGPEN* = LOGPEN

+  PLOGPEN* = ptr LOGPEN

+  EMRCREATEPEN* {.final, pure.} = object

+    emr*: EMR

+    ihPen*: DWORD

+    lopn*: LOGPEN

+

+  TEMRCREATEPEN* = EMRCREATEPEN

+  PEMRCREATEPEN* = ptr EMRCREATEPEN

+  EMRELLIPSE* {.final, pure.} = object

+    emr*: EMR

+    rclBox*: RECTL

+

+  TEMRELLIPSE* = EMRELLIPSE

+  PEMRELLIPSE* = ptr EMRELLIPSE

+  EMRRECTANGLE* = EMRELLIPSE

+  TEMRRECTANGLE* = EMRELLIPSE

+  PEMRRECTANGLE* = ptr EMRELLIPSE

+  EMREOF* {.final, pure.} = object

+    emr*: EMR

+    nPalEntries*: DWORD

+    offPalEntries*: DWORD

+    nSizeLast*: DWORD

+

+  TEMREOF* = EMREOF

+  PEMREOF* = ptr EMREOF

+  EMREXCLUDECLIPRECT* {.final, pure.} = object

+    emr*: EMR

+    rclClip*: RECTL

+

+  TEMREXCLUDECLIPRECT* = EMREXCLUDECLIPRECT

+  PEMREXCLUDECLIPRECT* = ptr EMREXCLUDECLIPRECT

+  EMRINTERSECTCLIPRECT* = EMREXCLUDECLIPRECT

+  TEMRINTERSECTCLIPRECT* = EMREXCLUDECLIPRECT

+  PEMRINTERSECTCLIPRECT* = ptr EMREXCLUDECLIPRECT

+  PANOSE* {.final, pure.} = object

+    bFamilyType*: int8

+    bSerifStyle*: int8

+    bWeight*: int8

+    bProportion*: int8

+    bContrast*: int8

+    bStrokeVariation*: int8

+    bArmStyle*: int8

+    bLetterform*: int8

+    bMidline*: int8

+    bXHeight*: int8

+

+  TPANOSE* = PANOSE

+  PPANOSE* = ptr PANOSE

+  EXTLOGFONT* {.final, pure.} = object

+    elfLogFont*: LOGFONT

+    elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR]

+    elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR]

+    elfVersion*: DWORD

+    elfStyleSize*: DWORD

+    elfMatch*: DWORD

+    elfReserved*: DWORD

+    elfVendorId*: array[0..(ELF_VENDOR_SIZE) - 1, int8]

+    elfCulture*: DWORD

+    elfPanose*: PANOSE

+

+  TEXTLOGFONT* = EXTLOGFONT

+  PEXTLOGFONT* = ptr EXTLOGFONT

+  EMREXTCREATEFONTINDIRECTW* {.final, pure.} = object

+    emr*: EMR

+    ihFont*: DWORD

+    elfw*: EXTLOGFONT

+

+  TEMREXTCREATEFONTINDIRECTW* = EMREXTCREATEFONTINDIRECTW

+  PEMREXTCREATEFONTINDIRECTW* = ptr EMREXTCREATEFONTINDIRECTW

+  EXTLOGPEN* {.final, pure.} = object

+    elpPenStyle*: WINUINT

+    elpWidth*: WINUINT

+    elpBrushStyle*: WINUINT

+    elpColor*: COLORREF

+    elpHatch*: LONG

+    elpNumEntries*: DWORD

+    elpStyleEntry*: array[0..0, DWORD]

+

+  TEXTLOGPEN* = EXTLOGPEN

+  PEXTLOGPEN* = ptr EXTLOGPEN

+  EMREXTCREATEPEN* {.final, pure.} = object

+    emr*: EMR

+    ihPen*: DWORD

+    offBmi*: DWORD

+    cbBmi*: DWORD

+    offBits*: DWORD

+    cbBits*: DWORD

+    elp*: EXTLOGPEN

+

+  TEMREXTCREATEPEN* = EMREXTCREATEPEN

+  PEMREXTCREATEPEN* = ptr EMREXTCREATEPEN

+  EMREXTFLOODFILL* {.final, pure.} = object

+    emr*: EMR

+    ptlStart*: POINTL

+    crColor*: COLORREF

+    iMode*: DWORD

+

+  TEMREXTFLOODFILL* = EMREXTFLOODFILL

+  PEMREXTFLOODFILL* = ptr EMREXTFLOODFILL

+  EMREXTSELECTCLIPRGN* {.final, pure.} = object

+    emr*: EMR

+    cbRgnData*: DWORD

+    iMode*: DWORD

+    RgnData*: array[0..0, int8]

+

+  TEMREXTSELECTCLIPRGN* = EMREXTSELECTCLIPRGN

+  PEMREXTSELECTCLIPRGN* = ptr EMREXTSELECTCLIPRGN

+  EMRTEXT* {.final, pure.} = object

+    ptlReference*: POINTL

+    nChars*: DWORD

+    offString*: DWORD

+    fOptions*: DWORD

+    rcl*: RECTL

+    offDx*: DWORD

+

+  TEMRTEXT* = EMRTEXT

+  PEMRTEXT* = ptr EMRTEXT

+  EMREXTTEXTOUTA* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    iGraphicsMode*: DWORD

+    exScale*: float32

+    eyScale*: float32

+    emrtext*: EMRTEXT

+

+  TEMREXTTEXTOUTA* = EMREXTTEXTOUTA

+  PEMREXTTEXTOUTA* = ptr EMREXTTEXTOUTA

+  EMREXTTEXTOUTW* = EMREXTTEXTOUTA

+  TEMREXTTEXTOUTW* = EMREXTTEXTOUTA

+  PEMREXTTEXTOUTW* = ptr EMREXTTEXTOUTA

+  EMRFILLPATH* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+

+  TEMRFILLPATH* = EMRFILLPATH

+  PEMRFILLPATH* = ptr EMRFILLPATH

+  EMRSTROKEANDFILLPATH* = EMRFILLPATH

+  TEMRSTROKEANDFILLPATH* = EMRFILLPATH

+  PEMRSTROKEANDFILLPATH* = ptr EMRFILLPATH

+  EMRSTROKEPATH* = EMRFILLPATH

+  TEMRSTROKEPATH* = EMRFILLPATH

+  PEMRSTROKEPATH* = ptr EMRFILLPATH

+  EMRFILLRGN* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cbRgnData*: DWORD

+    ihBrush*: DWORD

+    RgnData*: array[0..0, int8]

+

+  TEMRFILLRGN* = EMRFILLRGN

+  PEMRFILLRGN* = ptr EMRFILLRGN

+  EMRFORMAT* {.final, pure.} = object

+    dSignature*: DWORD

+    nVersion*: DWORD

+    cbData*: DWORD

+    offData*: DWORD

+

+  TEMRFORMAT* = EMRFORMAT

+  PEMRFORMAT* = ptr EMRFORMAT

+

+  EMRFRAMERGN* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cbRgnData*: DWORD

+    ihBrush*: DWORD

+    szlStroke*: SIZEL

+    RgnData*: array[0..0, int8]

+

+  TEMRFRAMERGN* = EMRFRAMERGN

+  PEMRFRAMERGN* = ptr EMRFRAMERGN

+  EMRGDICOMMENT* {.final, pure.} = object

+    emr*: EMR

+    cbData*: DWORD

+    Data*: array[0..0, int8]

+

+  TEMRGDICOMMENT* = EMRGDICOMMENT

+  PEMRGDICOMMENT* = ptr EMRGDICOMMENT

+  EMRINVERTRGN* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cbRgnData*: DWORD

+    RgnData*: array[0..0, int8]

+

+  TEMRINVERTRGN* = EMRINVERTRGN

+  PEMRINVERTRGN* = ptr EMRINVERTRGN

+  EMRPAINTRGN* = EMRINVERTRGN

+  TEMRPAINTRGN* = EMRINVERTRGN

+  PEMRPAINTRGN* = ptr EMRINVERTRGN

+  EMRLINETO* {.final, pure.} = object

+    emr*: EMR

+    ptl*: POINTL

+

+  TEMRLINETO* = EMRLINETO

+  PEMRLINETO* = ptr EMRLINETO

+  EMRMOVETOEX* = EMRLINETO

+  TEMRMOVETOEX* = EMRLINETO

+  PEMRMOVETOEX* = ptr EMRLINETO

+  EMRMASKBLT* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    xDest*: LONG

+    yDest*: LONG

+    cxDest*: LONG

+    cyDest*: LONG

+    dwRop*: DWORD

+    xSrc*: LONG

+    ySrc*: LONG

+    xformSrc*: XFORM

+    crBkColorSrc*: COLORREF

+    iUsageSrc*: DWORD

+    offBmiSrc*: DWORD

+    cbBmiSrc*: DWORD

+    offBitsSrc*: DWORD

+    cbBitsSrc*: DWORD

+    xMask*: LONG

+    yMask*: LONG

+    iUsageMask*: DWORD

+    offBmiMask*: DWORD

+    cbBmiMask*: DWORD

+    offBitsMask*: DWORD

+    cbBitsMask*: DWORD

+

+  TEMRMASKBLT* = EMRMASKBLT

+  PEMRMASKBLT* = ptr EMRMASKBLT

+  EMRMODIFYWORLDTRANSFORM* {.final, pure.} = object

+    emr*: EMR

+    xform*: XFORM

+    iMode*: DWORD

+

+  TEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM

+  PEMRMODIFYWORLDTRANSFORM* = EMRMODIFYWORLDTRANSFORM

+  EMROFFSETCLIPRGN* {.final, pure.} = object

+    emr*: EMR

+    ptlOffset*: POINTL

+

+  TEMROFFSETCLIPRGN* = EMROFFSETCLIPRGN

+  PEMROFFSETCLIPRGN* = ptr EMROFFSETCLIPRGN

+  EMRPLGBLT* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    aptlDest*: array[0..2, POINTL]

+    xSrc*: LONG

+    ySrc*: LONG

+    cxSrc*: LONG

+    cySrc*: LONG

+    xformSrc*: XFORM

+    crBkColorSrc*: COLORREF

+    iUsageSrc*: DWORD

+    offBmiSrc*: DWORD

+    cbBmiSrc*: DWORD

+    offBitsSrc*: DWORD

+    cbBitsSrc*: DWORD

+    xMask*: LONG

+    yMask*: LONG

+    iUsageMask*: DWORD

+    offBmiMask*: DWORD

+    cbBmiMask*: DWORD

+    offBitsMask*: DWORD

+    cbBitsMask*: DWORD

+

+  TEMRPLGBLT* = EMRPLGBLT

+  PEMRPLGBLT* = ptr EMRPLGBLT

+  EMRPOLYDRAW* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cptl*: DWORD

+    aptl*: array[0..0, POINTL]

+    abTypes*: array[0..0, int8]

+

+  TEMRPOLYDRAW* = EMRPOLYDRAW

+  PEMRPOLYDRAW* = ptr EMRPOLYDRAW

+  EMRPOLYDRAW16* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cpts*: DWORD

+    apts*: array[0..0, POINTS]

+    abTypes*: array[0..0, int8]

+

+  TEMRPOLYDRAW16* = EMRPOLYDRAW16

+  PEMRPOLYDRAW16* = ptr EMRPOLYDRAW16

+  EMRPOLYLINE* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cptl*: DWORD

+    aptl*: array[0..0, POINTL]

+

+  TEMRPOLYLINE* = EMRPOLYLINE

+  PEMRPOLYLINE* = ptr EMRPOLYLINE

+  EMRPOLYBEZIER* = EMRPOLYLINE

+  TEMRPOLYBEZIER* = EMRPOLYLINE

+  PEMRPOLYBEZIER* = ptr EMRPOLYLINE

+  EMRPOLYGON* = EMRPOLYLINE

+  TEMRPOLYGON* = EMRPOLYLINE

+  PEMRPOLYGON* = ptr EMRPOLYLINE

+  EMRPOLYBEZIERTO* = EMRPOLYLINE

+  TEMRPOLYBEZIERTO* = EMRPOLYLINE

+  PEMRPOLYBEZIERTO* = ptr EMRPOLYLINE

+  EMRPOLYLINETO* = EMRPOLYLINE

+  TEMRPOLYLINETO* = EMRPOLYLINE

+  PEMRPOLYLINETO* = ptr EMRPOLYLINE

+  EMRPOLYLINE16* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    cpts*: DWORD

+    apts*: array[0..0, POINTL]

+

+  TEMRPOLYLINE16* = EMRPOLYLINE16

+  PEMRPOLYLINE16* = ptr EMRPOLYLINE16

+  EMRPOLYBEZIER16* = EMRPOLYLINE16

+  TEMRPOLYBEZIER16* = EMRPOLYLINE16

+  PEMRPOLYBEZIER16* = ptr EMRPOLYLINE16

+  EMRPOLYGON16* = EMRPOLYLINE16

+  TEMRPOLYGON16* = EMRPOLYLINE16

+  PEMRPOLYGON16* = ptr EMRPOLYLINE16

+  EMRPOLYBEZIERTO16* = EMRPOLYLINE16

+  TEMRPOLYBEZIERTO16* = EMRPOLYLINE16

+  PEMRPOLYBEZIERTO16* = ptr EMRPOLYLINE16

+  EMRPOLYLINETO16* = EMRPOLYLINE16

+  TEMRPOLYLINETO16* = EMRPOLYLINE16

+  PEMRPOLYLINETO16* = ptr EMRPOLYLINE16

+  EMRPOLYPOLYLINE* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    nPolys*: DWORD

+    cptl*: DWORD

+    aPolyCounts*: array[0..0, DWORD]

+    aptl*: array[0..0, POINTL]

+

+  TEMRPOLYPOLYLINE* = EMRPOLYPOLYLINE

+  PEMRPOLYPOLYLINE* = ptr EMRPOLYPOLYLINE

+  EMRPOLYPOLYGON* = EMRPOLYPOLYLINE

+  TEMRPOLYPOLYGON* = EMRPOLYPOLYLINE

+  PEMRPOLYPOLYGON* = ptr EMRPOLYPOLYLINE

+  EMRPOLYPOLYLINE16* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    nPolys*: DWORD

+    cpts*: DWORD

+    aPolyCounts*: array[0..0, DWORD]

+    apts*: array[0..0, POINTS]

+

+  TEMRPOLYPOLYLINE16* = EMRPOLYPOLYLINE16

+  PEMRPOLYPOLYLINE16* = ptr EMRPOLYPOLYLINE16

+  EMRPOLYPOLYGON16* = EMRPOLYPOLYLINE16

+  TEMRPOLYPOLYGON16* = EMRPOLYPOLYLINE16

+  PEMRPOLYPOLYGON16* = ptr EMRPOLYPOLYLINE16

+  EMRPOLYTEXTOUTA* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    iGraphicsMode*: DWORD

+    exScale*: float32

+    eyScale*: float32

+    cStrings*: LONG

+    aemrtext*: array[0..0, EMRTEXT]

+

+  TEMRPOLYTEXTOUTA* = EMRPOLYTEXTOUTA

+  PEMRPOLYTEXTOUTA* = ptr EMRPOLYTEXTOUTA

+  EMRPOLYTEXTOUTW* = EMRPOLYTEXTOUTA

+  TEMRPOLYTEXTOUTW* = EMRPOLYTEXTOUTA

+  PEMRPOLYTEXTOUTW* = ptr EMRPOLYTEXTOUTA

+  EMRRESIZEPALETTE* {.final, pure.} = object

+    emr*: EMR

+    ihPal*: DWORD

+    cEntries*: DWORD

+

+  TEMRRESIZEPALETTE* = EMRRESIZEPALETTE

+  PEMRRESIZEPALETTE* = ptr EMRRESIZEPALETTE

+  EMRRESTOREDC* {.final, pure.} = object

+    emr*: EMR

+    iRelative*: LONG

+

+  TEMRRESTOREDC* = EMRRESTOREDC

+  PEMRRESTOREDC* = ptr EMRRESTOREDC

+  EMRROUNDRECT* {.final, pure.} = object

+    emr*: EMR

+    rclBox*: RECTL

+    szlCorner*: SIZEL

+

+  TEMRROUNDRECT* = EMRROUNDRECT

+  PEMRROUNDRECT* = ptr EMRROUNDRECT

+  EMRSCALEVIEWPORTEXTEX* {.final, pure.} = object

+    emr*: EMR

+    xNum*: LONG

+    xDenom*: LONG

+    yNum*: LONG

+    yDenom*: LONG

+

+  TEMRSCALEVIEWPORTEXTEX* = EMRSCALEVIEWPORTEXTEX

+  PEMRSCALEVIEWPORTEXTEX* = ptr EMRSCALEVIEWPORTEXTEX

+  EMRSCALEWINDOWEXTEX* = EMRSCALEVIEWPORTEXTEX

+  TEMRSCALEWINDOWEXTEX* = EMRSCALEVIEWPORTEXTEX

+  PEMRSCALEWINDOWEXTEX* = ptr EMRSCALEVIEWPORTEXTEX

+  EMRSELECTCOLORSPACE* {.final, pure.} = object

+    emr*: EMR

+

+    ihCS*: DWORD

+

+  TEMRSELECTCOLORSPACE* = EMRSELECTCOLORSPACE

+  PEMRSELECTCOLORSPACE* = ptr EMRSELECTCOLORSPACE

+  EMRDELETECOLORSPACE* = EMRSELECTCOLORSPACE

+  TEMRDELETECOLORSPACE* = EMRSELECTCOLORSPACE

+  PEMRDELETECOLORSPACE* = ptr EMRSELECTCOLORSPACE

+  EMRSELECTOBJECT* {.final, pure.} = object

+    emr*: EMR

+    ihObject*: DWORD

+

+  TEMRSELECTOBJECT* = EMRSELECTOBJECT

+  PEMRSELECTOBJECT* = ptr EMRSELECTOBJECT

+  EMRDELETEOBJECT* = EMRSELECTOBJECT

+  TEMRDELETEOBJECT* = EMRSELECTOBJECT

+  PEMRDELETEOBJECT* = ptr EMRSELECTOBJECT

+  EMRSELECTPALETTE* {.final, pure.} = object

+    emr*: EMR

+    ihPal*: DWORD

+

+  TEMRSELECTPALETTE* = EMRSELECTPALETTE

+  PEMRSELECTPALETTE* = ptr EMRSELECTPALETTE

+  EMRSETARCDIRECTION* {.final, pure.} = object

+    emr*: EMR

+    iArcDirection*: DWORD

+

+  TEMRSETARCDIRECTION* = EMRSETARCDIRECTION

+  PEMRSETARCDIRECTION* = ptr EMRSETARCDIRECTION

+  EMRSETBKCOLOR* {.final, pure.} = object

+    emr*: EMR

+    crColor*: COLORREF

+

+  TEMRSETBKCOLOR* = EMRSETBKCOLOR

+  PEMRSETBKCOLOR* = ptr EMRSETBKCOLOR

+  EMRSETTEXTCOLOR* = EMRSETBKCOLOR

+  TEMRSETTEXTCOLOR* = EMRSETBKCOLOR

+  PEMRSETTEXTCOLOR* = ptr EMRSETBKCOLOR

+  EMRSETCOLORADJUSTMENT* {.final, pure.} = object

+    emr*: EMR

+    ColorAdjustment*: COLORADJUSTMENT

+

+  TEMRSETCOLORADJUSTMENT* = EMRSETCOLORADJUSTMENT

+  PEMRSETCOLORADJUSTMENT* = ptr EMRSETCOLORADJUSTMENT

+  EMRSETDIBITSTODEVICE* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    xDest*: LONG

+    yDest*: LONG

+    xSrc*: LONG

+    ySrc*: LONG

+    cxSrc*: LONG

+    cySrc*: LONG

+    offBmiSrc*: DWORD

+    cbBmiSrc*: DWORD

+    offBitsSrc*: DWORD

+    cbBitsSrc*: DWORD

+    iUsageSrc*: DWORD

+    iStartScan*: DWORD

+    cScans*: DWORD

+

+  TEMRSETDIBITSTODEVICE* = EMRSETDIBITSTODEVICE

+  PEMRSETDIBITSTODEVICE* = ptr EMRSETDIBITSTODEVICE

+  EMRSETMAPPERFLAGS* {.final, pure.} = object

+    emr*: EMR

+    dwFlags*: DWORD

+

+  TEMRSETMAPPERFLAGS* = EMRSETMAPPERFLAGS

+  PEMRSETMAPPERFLAGS* = ptr EMRSETMAPPERFLAGS

+  EMRSETMITERLIMIT* {.final, pure.} = object

+    emr*: EMR

+    eMiterLimit*: float32

+

+  TEMRSETMITERLIMIT* = EMRSETMITERLIMIT

+  PEMRSETMITERLIMIT* = ptr EMRSETMITERLIMIT

+  EMRSETPALETTEENTRIES* {.final, pure.} = object

+    emr*: EMR

+    ihPal*: DWORD

+    iStart*: DWORD

+    cEntries*: DWORD

+    aPalEntries*: array[0..0, PALETTEENTRY]

+

+  TEMRSETPALETTEENTRIES* = EMRSETPALETTEENTRIES

+  PEMRSETPALETTEENTRIES* = ptr EMRSETPALETTEENTRIES

+  EMRSETPIXELV* {.final, pure.} = object

+    emr*: EMR

+    ptlPixel*: POINTL

+    crColor*: COLORREF

+

+  TEMRSETPIXELV* = EMRSETPIXELV

+  PEMRSETPIXELV* = ptr EMRSETPIXELV

+  EMRSETVIEWPORTEXTEX* {.final, pure.} = object

+    emr*: EMR

+    szlExtent*: SIZEL

+

+  TEMRSETVIEWPORTEXTEX* = EMRSETVIEWPORTEXTEX

+  PEMRSETVIEWPORTEXTEX* = ptr EMRSETVIEWPORTEXTEX

+  EMRSETWINDOWEXTEX* = EMRSETVIEWPORTEXTEX

+  TEMRSETWINDOWEXTEX* = EMRSETVIEWPORTEXTEX

+  PEMRSETWINDOWEXTEX* = ptr EMRSETVIEWPORTEXTEX

+  EMRSETVIEWPORTORGEX* {.final, pure.} = object

+    emr*: EMR

+    ptlOrigin*: POINTL

+

+  TEMRSETVIEWPORTORGEX* = EMRSETVIEWPORTORGEX

+  PEMRSETVIEWPORTORGEX* = ptr EMRSETVIEWPORTORGEX

+  EMRSETWINDOWORGEX* = EMRSETVIEWPORTORGEX

+  TEMRSETWINDOWORGEX* = EMRSETVIEWPORTORGEX

+  PEMRSETWINDOWORGEX* = ptr EMRSETVIEWPORTORGEX

+  EMRSETBRUSHORGEX* = EMRSETVIEWPORTORGEX

+  TEMRSETBRUSHORGEX* = EMRSETVIEWPORTORGEX

+  PEMRSETBRUSHORGEX* = ptr EMRSETVIEWPORTORGEX

+  EMRSETWORLDTRANSFORM* {.final, pure.} = object

+    emr*: EMR

+    xform*: XFORM

+

+  TEMRSETWORLDTRANSFORM* = EMRSETWORLDTRANSFORM

+  PEMRSETWORLDTRANSFORM* = ptr EMRSETWORLDTRANSFORM

+  EMRSTRETCHBLT* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    xDest*: LONG

+    yDest*: LONG

+    cxDest*: LONG

+    cyDest*: LONG

+    dwRop*: DWORD

+    xSrc*: LONG

+    ySrc*: LONG

+    xformSrc*: XFORM

+    crBkColorSrc*: COLORREF

+    iUsageSrc*: DWORD

+    offBmiSrc*: DWORD

+    cbBmiSrc*: DWORD

+    offBitsSrc*: DWORD

+    cbBitsSrc*: DWORD

+    cxSrc*: LONG

+    cySrc*: LONG

+

+  TEMRSTRETCHBLT* = EMRSTRETCHBLT

+  PEMRSTRETCHBLT* = ptr EMRSTRETCHBLT

+  EMRSTRETCHDIBITS* {.final, pure.} = object

+    emr*: EMR

+    rclBounds*: RECTL

+    xDest*: LONG

+    yDest*: LONG

+    xSrc*: LONG

+    ySrc*: LONG

+    cxSrc*: LONG

+    cySrc*: LONG

+    offBmiSrc*: DWORD

+    cbBmiSrc*: DWORD

+    offBitsSrc*: DWORD

+    cbBitsSrc*: DWORD

+    iUsageSrc*: DWORD

+    dwRop*: DWORD

+    cxDest*: LONG

+    cyDest*: LONG

+

+  TEMRSTRETCHDIBITS* = EMRSTRETCHDIBITS

+  PEMRSTRETCHDIBITS* = ptr EMRSTRETCHDIBITS

+  EMRABORTPATH* {.final, pure.} = object

+    emr*: EMR

+

+  TEMRABORTPATH* = EMRABORTPATH

+  PEMRABORTPATH* = ptr EMRABORTPATH

+  TABORTPATH* = EMRABORTPATH

+  EMRBEGINPATH* = EMRABORTPATH

+  TEMRBEGINPATH* = EMRABORTPATH

+  PEMRBEGINPATH* = ptr EMRABORTPATH

+  EMRENDPATH* = EMRABORTPATH

+  TEMRENDPATH* = EMRABORTPATH

+  PEMRENDPATH* = ptr EMRABORTPATH

+  EMRCLOSEFIGURE* = EMRABORTPATH

+  TEMRCLOSEFIGURE* = EMRABORTPATH

+  PEMRCLOSEFIGURE* = ptr EMRABORTPATH

+  EMRFLATTENPATH* = EMRABORTPATH

+  TEMRFLATTENPATH* = EMRABORTPATH

+  PEMRFLATTENPATH* = ptr EMRABORTPATH

+  EMRWIDENPATH* = EMRABORTPATH

+  TEMRWIDENPATH* = EMRABORTPATH

+  PEMRWIDENPATH* = ptr EMRABORTPATH

+  EMRSETMETARGN* = EMRABORTPATH

+  TEMRSETMETARGN* = EMRABORTPATH

+  PEMRSETMETARGN* = ptr EMRABORTPATH

+  EMRSAVEDC* = EMRABORTPATH

+  TEMRSAVEDC* = EMRABORTPATH

+  PEMRSAVEDC* = ptr EMRABORTPATH

+  EMRREALIZEPALETTE* = EMRABORTPATH

+  TEMRREALIZEPALETTE* = EMRABORTPATH

+  PEMRREALIZEPALETTE* = ptr EMRABORTPATH

+  EMRSELECTCLIPPATH* {.final, pure.} = object

+    emr*: EMR

+    iMode*: DWORD

+

+  TEMRSELECTCLIPPATH* = EMRSELECTCLIPPATH

+  PEMRSELECTCLIPPATH* = ptr EMRSELECTCLIPPATH

+  EMRSETBKMODE* = EMRSELECTCLIPPATH

+  TEMRSETBKMODE* = EMRSELECTCLIPPATH

+  PEMRSETBKMODE* = ptr EMRSELECTCLIPPATH

+  EMRSETMAPMODE* = EMRSELECTCLIPPATH

+  TEMRSETMAPMODE* = EMRSELECTCLIPPATH

+  PEMRSETMAPMODE* = ptr EMRSELECTCLIPPATH

+  EMRSETPOLYFILLMODE* = EMRSELECTCLIPPATH

+  TEMRSETPOLYFILLMODE* = EMRSELECTCLIPPATH

+  PEMRSETPOLYFILLMODE* = ptr EMRSELECTCLIPPATH

+  EMRSETROP2* = EMRSELECTCLIPPATH

+  TEMRSETROP2* = EMRSELECTCLIPPATH

+  PEMRSETROP2* = ptr EMRSELECTCLIPPATH

+  EMRSETSTRETCHBLTMODE* = EMRSELECTCLIPPATH

+  TEMRSETSTRETCHBLTMODE* = EMRSELECTCLIPPATH

+  PEMRSETSTRETCHBLTMODE* = ptr EMRSELECTCLIPPATH

+  EMRSETTEXTALIGN* = EMRSELECTCLIPPATH

+  TEMRSETTEXTALIGN* = EMRSELECTCLIPPATH

+  PEMRSETTEXTALIGN* = ptr EMRSELECTCLIPPATH

+  EMRENABLEICM* = EMRSELECTCLIPPATH

+  TEMRENABLEICM* = EMRSELECTCLIPPATH

+  PEMRENABLEICM* = ptr EMRSELECTCLIPPATH

+  NMHDR* {.final, pure.} = object

+    hwndFrom*: HWND

+    idFrom*: WINUINT

+    code*: WINUINT

+

+  TNMHDR* = NMHDR

+  PNMHDR* = ptr NMHDR

+  TENCORRECTTEXT* {.final, pure.} = object

+    nmhdr*: NMHDR

+    chrg*: CHARRANGE

+    seltyp*: int16

+

+  Pencorrecttext* = ptr TENCORRECTTEXT

+  TENDROPFILES* {.final, pure.} = object

+    nmhdr*: NMHDR

+    hDrop*: HANDLE

+    cp*: LONG

+    fProtected*: WINBOOL

+

+  Pendropfiles* = ptr TENDROPFILES

+  TENSAVECLIPBOARD* {.final, pure.} = object

+    nmhdr*: NMHDR

+    cObjectCount*: LONG

+    cch*: LONG

+

+  PENSAVECLIPBOARD* = ptr TENSAVECLIPBOARD

+  TENOLEOPFAILED* {.final, pure.} = object

+    nmhdr*: NMHDR

+    iob*: LONG

+    lOper*: LONG

+    hr*: HRESULT

+

+  PENOLEOPFAILED* = ptr TENOLEOPFAILED

+  TENHMETAHEADER* {.final, pure.} = object

+    iType*: DWORD

+    nSize*: DWORD

+    rclBounds*: RECTL

+    rclFrame*: RECTL

+    dSignature*: DWORD

+    nVersion*: DWORD

+    nBytes*: DWORD

+    nRecords*: DWORD

+    nHandles*: int16

+    sReserved*: int16

+    nDescription*: DWORD

+    offDescription*: DWORD

+    nPalEntries*: DWORD

+    szlDevice*: SIZEL

+    szlMillimeters*: SIZEL

+

+  LPENHMETAHEADER* = ptr TENHMETAHEADER

+  PENHMETAHEADER* = ptr TENHMETAHEADER

+  TENHMETARECORD* {.final, pure.} = object

+    iType*: DWORD

+    nSize*: DWORD

+    dParm*: array[0..0, DWORD]

+

+  LPENHMETARECORD* = ptr TENHMETARECORD

+  PENHMETARECORD* = ptr TENHMETARECORD

+  TENPROTECTED* {.final, pure.} = object

+    nmhdr*: NMHDR

+    msg*: WINUINT

+    wParam*: WPARAM

+    lParam*: LPARAM

+    chrg*: CHARRANGE

+

+  Penprotected* = ptr TENPROTECTED

+  SERVICE_STATUS* {.final, pure.} = object

+    dwServiceType*: DWORD

+    dwCurrentState*: DWORD

+    dwControlsAccepted*: DWORD

+    dwWin32ExitCode*: DWORD

+    dwServiceSpecificExitCode*: DWORD

+    dwCheckPoint*: DWORD

+    dwWaitHint*: DWORD

+

+  LPSERVICE_STATUS* = ptr SERVICE_STATUS

+  TSERVICESTATUS* = SERVICE_STATUS

+  PSERVICESTATUS* = ptr SERVICE_STATUS

+  ENUM_SERVICE_STATUS* {.final, pure.} = object

+    lpServiceName*: LPTSTR

+    lpDisplayName*: LPTSTR

+    ServiceStatus*: SERVICE_STATUS

+

+  LPENUM_SERVICE_STATUS* = ptr ENUM_SERVICE_STATUS

+  TENUMSERVICESTATUS* = ENUM_SERVICE_STATUS

+  PENUMSERVICESTATUS* = ptr ENUM_SERVICE_STATUS

+  ENUMLOGFONT* {.final, pure.} = object

+    elfLogFont*: LOGFONT

+    elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR]

+    elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR]

+

+  TENUMLOGFONT* = ENUMLOGFONT

+  PENUMLOGFONT* = ptr ENUMLOGFONT

+  ENUMLOGFONTEX* {.final, pure.} = object

+    elfLogFont*: LOGFONT

+    elfFullName*: array[0..(LF_FULLFACESIZE) - 1, BCHAR]

+    elfStyle*: array[0..(LF_FACESIZE) - 1, BCHAR]

+    elfScript*: array[0..(LF_FACESIZE) - 1, BCHAR]

+

+  TENUMLOGFONTEX* = ENUMLOGFONTEX

+  PENUMLOGFONTEX* = ptr ENUMLOGFONTEX

+

+  EVENTLOGRECORD* {.final, pure.} = object

+    Length*: DWORD

+    Reserved*: DWORD

+    RecordNumber*: DWORD

+    TimeGenerated*: DWORD

+    TimeWritten*: DWORD

+    EventID*: DWORD

+    EventType*: int16

+    NumStrings*: int16

+    EventCategory*: int16

+    ReservedFlags*: int16

+    ClosingRecordNumber*: DWORD

+    StringOffset*: DWORD

+    UserSidLength*: DWORD

+    UserSidOffset*: DWORD

+    DataLength*: DWORD

+    DataOffset*: DWORD

+

+  TEVENTLOGRECORD* = EVENTLOGRECORD

+  PEVENTLOGRECORD* = ptr EVENTLOGRECORD

+  EVENTMSG* {.final, pure.} = object

+    message*: WINUINT

+    paramL*: WINUINT

+    paramH*: WINUINT

+    time*: DWORD

+    hwnd*: HWND

+

+  TEVENTMSG* = EVENTMSG

+  PEVENTMSG* = ptr EVENTMSG

+  EXCEPTION_POINTERS* {.final, pure.} = object

+    ExceptionRecord*: PEXCEPTION_RECORD

+    ContextRecord*: PCONTEXT

+

+  LPEXCEPTION_POINTERS* = ptr EXCEPTION_POINTERS

+  PEXCEPTION_POINTERS* = ptr EXCEPTION_POINTERS

+  TEXCEPTIONPOINTERS* = EXCEPTION_POINTERS

+  EXT_BUTTON* {.final, pure.} = object

+    idCommand*: int16

+    idsHelp*: int16

+    fsStyle*: int16

+

+  LPEXT_BUTTON* = ptr EXT_BUTTON

+  TEXTBUTTON* = EXT_BUTTON

+  PEXTBUTTON* = ptr EXT_BUTTON

+  FILTERKEYS* {.final, pure.} = object

+    cbSize*: WINUINT

+    dwFlags*: DWORD

+    iWaitMSec*: DWORD

+    iDelayMSec*: DWORD

+    iRepeatMSec*: DWORD

+    iBounceMSec*: DWORD

+

+  TFILTERKEYS* = FILTERKEYS

+  PFILTERKEYS* = ptr FILTERKEYS

+  FIND_NAME_BUFFER* {.final, pure.} = object

+    len*: UCHAR

+    access_control*: UCHAR

+    frame_control*: UCHAR

+    destination_addr*: array[0..5, UCHAR]

+    source_addr*: array[0..5, UCHAR]

+    routing_info*: array[0..17, UCHAR]

+

+  TFINDNAMEBUFFER* = FIND_NAME_BUFFER

+  PFINDNAMEBUFFER* = ptr FIND_NAME_BUFFER

+  FIND_NAME_HEADER* {.final, pure.} = object

+    node_count*: int16

+    reserved*: UCHAR

+    unique_group*: UCHAR

+

+  TFINDNAMEHEADER* = FIND_NAME_HEADER

+  PFINDNAMEHEADER* = ptr FIND_NAME_HEADER

+  FINDREPLACE* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hInstance*: HINST

+    Flags*: DWORD

+    lpstrFindWhat*: LPTSTR

+    lpstrReplaceWith*: LPTSTR

+    wFindWhatLen*: int16

+    wReplaceWithLen*: int16

+    lCustData*: LPARAM

+    lpfnHook*: LPFRHOOKPROC

+    lpTemplateName*: LPCTSTR

+

+  LPFINDREPLACE* = ptr FINDREPLACE

+  TFINDREPLACE* = FINDREPLACE

+  PFINDREPLACE* = ptr FINDREPLACE

+  #FINDTEXT = record conflicts with FindText function

+  TFINDTEXT* {.final, pure.} = object

+    chrg*: CHARRANGE

+    lpstrText*: LPSTR

+

+  Pfindtext* = ptr TFINDTEXT

+  FINDTEXTEX* {.final, pure.} = object

+    chrg*: CHARRANGE

+    lpstrText*: LPSTR

+    chrgText*: CHARRANGE

+

+  Tfindtextex* = FINDTEXTEX

+  Pfindtextex* = ptr FINDTEXTEX

+  FMS_GETDRIVEINFO* {.final, pure.} = object

+    dwTotalSpace*: DWORD

+    dwFreeSpace*: DWORD

+    szPath*: array[0..259, TCHAR]

+    szVolume*: array[0..13, TCHAR]

+    szShare*: array[0..127, TCHAR]

+

+  TFMSGETDRIVEINFO* = FMS_GETDRIVEINFO

+  PFMSGETDRIVEINFO* = ptr FMS_GETDRIVEINFO

+  FMS_GETFILESEL* {.final, pure.} = object

+    ftTime*: FILETIME

+    dwSize*: DWORD

+    bAttr*: int8

+    szName*: array[0..259, TCHAR]

+

+  TFMSGETFILESEL* = FMS_GETFILESEL

+  PFMSGETFILESEL* = ptr FMS_GETFILESEL

+  FMS_LOAD* {.final, pure.} = object

+    dwSize*: DWORD

+    szMenuName*: array[0..(MENU_TEXT_LEN) - 1, TCHAR]

+    hMenu*: HMENU

+    wMenuDelta*: WINUINT

+

+  TFMSLOAD* = FMS_LOAD

+  PFMSLOAD* = ptr FMS_LOAD

+  FMS_TOOLBARLOAD* {.final, pure.} = object

+    dwSize*: DWORD

+    lpButtons*: LPEXT_BUTTON

+    cButtons*: int16

+    cBitmaps*: int16

+    idBitmap*: int16

+    hBitmap*: HBITMAP

+

+  TFMSTOOLBARLOAD* = FMS_TOOLBARLOAD

+  PFMSTOOLBARLOAD* = ptr FMS_TOOLBARLOAD

+  FOCUS_EVENT_RECORD* {.final, pure.} = object

+    bSetFocus*: WINBOOL

+

+  TFOCUSEVENTRECORD* = FOCUS_EVENT_RECORD

+  PFOCUSEVENTRECORD* = ptr FOCUS_EVENT_RECORD

+  FORM_INFO_1* {.final, pure.} = object

+    Flags*: DWORD

+    pName*: LPTSTR

+    Size*: SIZEL

+    ImageableArea*: RECTL

+

+  TFORMINFO1* = FORM_INFO_1

+  PFORMINFO1* = ptr FORM_INFO_1

+  FORMAT_PARAMETERS* {.final, pure.} = object

+    MediaType*: MEDIA_TYPE

+    StartCylinderNumber*: DWORD

+    EndCylinderNumber*: DWORD

+    StartHeadNumber*: DWORD

+    EndHeadNumber*: DWORD

+

+  TFORMATPARAMETERS* = FORMAT_PARAMETERS

+  PFORMATPARAMETERS* = ptr FORMAT_PARAMETERS

+  FORMATRANGE* {.final, pure.} = object

+    hdc*: HDC

+    hdcTarget*: HDC

+    rc*: RECT

+    rcPage*: RECT

+    chrg*: CHARRANGE

+

+  Tformatrange* = FORMATRANGE

+  Pformatrange* = ptr FORMATRANGE

+  GCP_RESULTS* {.final, pure.} = object

+    lStructSize*: DWORD

+    lpOutString*: LPTSTR

+    lpOrder*: ptr WINUINT

+    lpDx*: ptr WINT

+    lpCaretPos*: ptr WINT

+    lpClass*: LPTSTR

+    lpGlyphs*: ptr WINUINT

+    nGlyphs*: WINUINT

+    nMaxFit*: WINUINT

+

+  LPGCP_RESULTS* = ptr GCP_RESULTS

+  TGCPRESULTS* = GCP_RESULTS

+  PGCPRESULTS* = ptr GCP_RESULTS

+  GENERIC_MAPPING* {.final, pure.} = object

+    GenericRead*: ACCESS_MASK

+    GenericWrite*: ACCESS_MASK

+    GenericExecute*: ACCESS_MASK

+    GenericAll*: ACCESS_MASK

+

+  PGENERIC_MAPPING* = ptr GENERIC_MAPPING

+  TGENERICMAPPING* = GENERIC_MAPPING

+  GLYPHMETRICS* {.final, pure.} = object

+    gmBlackBoxX*: WINUINT

+    gmBlackBoxY*: WINUINT

+    gmptGlyphOrigin*: POINT

+    gmCellIncX*: SHORT

+    gmCellIncY*: SHORT

+

+  LPGLYPHMETRICS* = ptr GLYPHMETRICS

+  TGLYPHMETRICS* = GLYPHMETRICS

+  PGLYPHMETRICS* = ptr GLYPHMETRICS

+  HANDLETABLE* {.final, pure.} = object

+    objectHandle*: array[0..0, HGDIOBJ]

+

+  THANDLETABLE* = HANDLETABLE

+  LPHANDLETABLE* = ptr HANDLETABLE

+  HD_HITTESTINFO* {.final, pure.} = object

+    pt*: POINT

+    flags*: WINUINT

+    iItem*: int32

+

+  THDHITTESTINFO* = HD_HITTESTINFO

+  PHDHITTESTINFO* = ptr HD_HITTESTINFO

+  HD_ITEM* {.final, pure.} = object

+    mask*: WINUINT

+    cxy*: int32

+    pszText*: LPTSTR

+    hbm*: HBITMAP

+    cchTextMax*: int32

+    fmt*: int32

+    lParam*: LPARAM

+

+  THDITEM* = HD_ITEM

+  PHDITEM* = ptr HD_ITEM

+  WINDOWPOS* {.final, pure.} = object

+    hwnd*: HWND

+    hwndInsertAfter*: HWND

+    x*: int32

+    y*: int32

+    cx*: int32

+    cy*: int32

+    flags*: WINUINT

+

+  LPWINDOWPOS* = ptr WINDOWPOS

+  TWINDOWPOS* = WINDOWPOS

+  PWINDOWPOS* = ptr WINDOWPOS

+  HD_LAYOUT* {.final, pure.} = object

+    prc*: ptr RECT

+    pwpos*: ptr WINDOWPOS

+

+  THDLAYOUT* = HD_LAYOUT

+  PHDLAYOUT* = ptr HD_LAYOUT

+  HD_NOTIFY* {.final, pure.} = object

+    hdr*: NMHDR

+    iItem*: int32

+    iButton*: int32

+    pitem*: ptr HD_ITEM

+

+  THDNOTIFY* = HD_NOTIFY

+  PHDNOTIFY* = ptr HD_NOTIFY

+  HELPINFO* {.final, pure.} = object

+    cbSize*: WINUINT

+    iContextType*: int32

+    iCtrlId*: int32

+    hItemHandle*: HANDLE

+    dwContextId*: DWORD

+    MousePos*: POINT

+

+  LPHELPINFO* = ptr HELPINFO

+  THELPINFO* = HELPINFO

+  PHELPINFO* = ptr HELPINFO

+  HELPWININFO* {.final, pure.} = object

+    wStructSize*: int32

+    x*: int32

+    y*: int32

+    dx*: int32

+    dy*: int32

+    wMax*: int32

+    rgchMember*: array[0..1, TCHAR]

+

+  THELPWININFO* = HELPWININFO

+  PHELPWININFO* = ptr HELPWININFO

+  HIGHCONTRAST* {.final, pure.} = object

+    cbSize*: WINUINT

+    dwFlags*: DWORD

+    lpszDefaultScheme*: LPTSTR

+

+  LPHIGHCONTRAST* = ptr HIGHCONTRAST

+  THIGHCONTRAST* = HIGHCONTRAST

+  PHIGHCONTRAST* = ptr HIGHCONTRAST

+  HSZPAIR* {.final, pure.} = object

+    hszSvc*: HSZ

+    hszTopic*: HSZ

+

+  THSZPAIR* = HSZPAIR

+  PHSZPAIR* = ptr HSZPAIR

+  ICONINFO* {.final, pure.} = object

+    fIcon*: WINBOOL

+    xHotspot*: DWORD

+    yHotspot*: DWORD

+    hbmMask*: HBITMAP

+    hbmColor*: HBITMAP

+

+  TICONINFO* = ICONINFO

+  PICONINFO* = ptr ICONINFO

+  ICONMETRICS* {.final, pure.} = object

+    cbSize*: WINUINT

+    iHorzSpacing*: int32

+    iVertSpacing*: int32

+    iTitleWrap*: int32

+    lfFont*: LOGFONT

+

+  LPICONMETRICS* = ptr ICONMETRICS

+  TICONMETRICS* = ICONMETRICS

+  PICONMETRICS* = ptr ICONMETRICS

+  IMAGEINFO* {.final, pure.} = object

+    hbmImage*: HBITMAP

+    hbmMask*: HBITMAP

+    Unused1*: int32

+    Unused2*: int32

+    rcImage*: RECT

+

+  TIMAGEINFO* = IMAGEINFO

+  PIMAGEINFO* = ptr IMAGEINFO

+  KEY_EVENT_RECORD* {.final, pure.} = object

+    bKeyDown*: WINBOOL

+    wRepeatCount*: int16

+    wVirtualKeyCode*: int16

+    wVirtualScanCode*: int16

+    UnicodeChar*: WCHAR

+    dwControlKeyState*: DWORD # other union part: AsciiChar: CHAR

+

+  TKEYEVENTRECORD* = KEY_EVENT_RECORD

+  PKEYEVENTRECORD* = ptr KEY_EVENT_RECORD

+  MOUSE_EVENT_RECORD* {.final, pure.} = object

+    dwMousePosition*: COORD

+    dwButtonState*: DWORD

+    dwControlKeyState*: DWORD

+    dwEventFlags*: DWORD

+

+  TMOUSEEVENTRECORD* = MOUSE_EVENT_RECORD

+  PMOUSEEVENTRECORD* = ptr MOUSE_EVENT_RECORD

+  WINDOW_BUFFER_SIZE_RECORD* {.final, pure.} = object

+    dwSize*: COORD

+

+  TWINDOWBUFFERSIZERECORD* = WINDOW_BUFFER_SIZE_RECORD

+  PWINDOWBUFFERSIZERECORD* = ptr WINDOW_BUFFER_SIZE_RECORD

+  MENU_EVENT_RECORD* {.final, pure.} = object

+    dwCommandId*: WINUINT

+

+  PMENU_EVENT_RECORD* = ptr MENU_EVENT_RECORD

+  TMENUEVENTRECORD* = MENU_EVENT_RECORD

+  INPUT_RECORD* {.final, pure.} = object

+    EventType*: int16

+    Reserved*: int16

+    event*: array[0..5, DWORD]

+

+  PINPUT_RECORD* = ptr INPUT_RECORD

+  TINPUTRECORD* = INPUT_RECORD

+  SYSTEMTIME* {.final, pure.} = object

+    wYear*: int16

+    wMonth*: int16

+    wDayOfWeek*: int16

+    wDay*: int16

+    wHour*: int16

+    wMinute*: int16

+    wSecond*: int16

+    wMilliseconds*: int16

+

+  LPSYSTEMTIME* = ptr SYSTEMTIME

+  TSYSTEMTIME* = SYSTEMTIME

+  PSYSTEMTIME* = ptr SYSTEMTIME

+  JOB_INFO_1* {.final, pure.} = object

+    JobId*: DWORD

+    pPrinterName*: LPTSTR

+    pMachineName*: LPTSTR

+    pUserName*: LPTSTR

+    pDocument*: LPTSTR

+    pDatatype*: LPTSTR

+    pStatus*: LPTSTR

+    Status*: DWORD

+    Priority*: DWORD

+    Position*: DWORD

+    TotalPages*: DWORD

+    PagesPrinted*: DWORD

+    Submitted*: SYSTEMTIME

+

+  TJOBINFO1* = JOB_INFO_1

+  PJOBINFO1* = ptr JOB_INFO_1

+  SID_IDENTIFIER_AUTHORITY* {.final, pure.} = object

+    Value*: array[0..5, int8]

+

+  LPSID_IDENTIFIER_AUTHORITY* = ptr SID_IDENTIFIER_AUTHORITY

+  PSID_IDENTIFIER_AUTHORITY* = ptr SID_IDENTIFIER_AUTHORITY

+  TSIDIDENTIFIERAUTHORITY* = SID_IDENTIFIER_AUTHORITY

+  SID* {.final, pure.} = object

+    Revision*: int8

+    SubAuthorityCount*: int8

+    IdentifierAuthority*: SID_IDENTIFIER_AUTHORITY

+    SubAuthority*: array[0..(ANYSIZE_ARRAY) - 1, DWORD]

+

+  TSID* = SID

+  PSID* = ptr SID

+  SECURITY_DESCRIPTOR_CONTROL* = int16

+  PSECURITY_DESCRIPTOR_CONTROL* = ptr SECURITY_DESCRIPTOR_CONTROL

+  TSECURITYDESCRIPTORCONTROL* = SECURITY_DESCRIPTOR_CONTROL

+  SECURITY_DESCRIPTOR* {.final, pure.} = object

+    Revision*: int8

+    Sbz1*: int8

+    Control*: SECURITY_DESCRIPTOR_CONTROL

+    Owner*: PSID

+    Group*: PSID

+    Sacl*: PACL

+    Dacl*: PACL

+

+  PSECURITY_DESCRIPTOR* = ptr SECURITY_DESCRIPTOR

+  TSECURITYDESCRIPTOR* = SECURITY_DESCRIPTOR

+  JOB_INFO_2* {.final, pure.} = object

+    JobId*: DWORD

+    pPrinterName*: LPTSTR

+    pMachineName*: LPTSTR

+    pUserName*: LPTSTR

+    pDocument*: LPTSTR

+    pNotifyName*: LPTSTR

+    pDatatype*: LPTSTR

+    pPrintProcessor*: LPTSTR

+    pParameters*: LPTSTR

+    pDriverName*: LPTSTR

+    pDevMode*: LPDEVMODE

+    pStatus*: LPTSTR

+    pSecurityDescriptor*: PSECURITY_DESCRIPTOR

+    Status*: DWORD

+    Priority*: DWORD

+    Position*: DWORD

+    StartTime*: DWORD

+    UntilTime*: DWORD

+    TotalPages*: DWORD

+    Size*: DWORD

+    Submitted*: SYSTEMTIME

+    Time*: DWORD

+    PagesPrinted*: DWORD

+

+  TJOBINFO2* = JOB_INFO_2

+  PJOBINFO2* = ptr JOB_INFO_2

+  KERNINGPAIR* {.final, pure.} = object

+    wFirst*: int16

+    wSecond*: int16

+    iKernAmount*: int32

+

+  LPKERNINGPAIR* = ptr KERNINGPAIR

+  TKERNINGPAIR* = KERNINGPAIR

+  PKERNINGPAIR* = ptr KERNINGPAIR

+  LANA_ENUM* {.final, pure.} = object

+    len*: UCHAR

+    lana*: array[0..(MAX_LANA) - 1, UCHAR]

+

+  TLANAENUM* = LANA_ENUM

+  PLANAENUM* = ptr LANA_ENUM

+  LDT_ENTRY* {.final, pure.} = object

+    LimitLow*: int16

+    BaseLow*: int16

+    BaseMid*: int8

+    Flags1*: int8

+    Flags2*: int8

+    BaseHi*: int8

+

+  LPLDT_ENTRY* = ptr LDT_ENTRY

+  PLDT_ENTRY* = ptr LDT_ENTRY

+  TLDTENTRY* = LDT_ENTRY

+

+const

+  bm_LDT_ENTRY_BaseMid* = 0x000000FF

+  bp_LDT_ENTRY_BaseMid* = 0'i32

+  bm_LDT_ENTRY_Type* = 0x00001F00

+  bp_LDT_ENTRY_Type* = 8'i32

+  bm_LDT_ENTRY_Dpl* = 0x00006000

+  bp_LDT_ENTRY_Dpl* = 13'i32

+  bm_LDT_ENTRY_Pres* = 0x00008000

+  bp_LDT_ENTRY_Pres* = 15'i32

+  bm_LDT_ENTRY_LimitHi* = 0x000F0000

+  bp_LDT_ENTRY_LimitHi* = 16'i32

+  bm_LDT_ENTRY_Sys* = 0x00100000

+  bp_LDT_ENTRY_Sys* = 20'i32

+  bm_LDT_ENTRY_Reserved_0* = 0x00200000

+  bp_LDT_ENTRY_Reserved_0* = 21'i32

+  bm_LDT_ENTRY_Default_Big* = 0x00400000

+  bp_LDT_ENTRY_Default_Big* = 22'i32

+  bm_LDT_ENTRY_Granularity* = 0x00800000

+  bp_LDT_ENTRY_Granularity* = 23'i32

+  bm_LDT_ENTRY_BaseHi* = 0xFF000000

+  bp_LDT_ENTRY_BaseHi* = 24'i32

+

+type

+  LOCALESIGNATURE* {.final, pure.} = object

+    lsUsb*: array[0..3, DWORD]

+    lsCsbDefault*: array[0..1, DWORD]

+    lsCsbSupported*: array[0..1, DWORD]

+

+  TLOCALESIGNATURE* = LOCALESIGNATURE

+  PLOCALESIGNATURE* = ptr LOCALESIGNATURE

+  LOCALGROUP_MEMBERS_INFO_0* {.final, pure.} = object

+    lgrmi0_sid*: PSID

+

+  TLOCALGROUPMEMBERSINFO0* = LOCALGROUP_MEMBERS_INFO_0

+  PLOCALGROUPMEMBERSINFO0* = ptr LOCALGROUP_MEMBERS_INFO_0

+  LOCALGROUP_MEMBERS_INFO_3* {.final, pure.} = object

+    lgrmi3_domainandname*: LPWSTR

+

+  TLOCALGROUPMEMBERSINFO3* = LOCALGROUP_MEMBERS_INFO_3

+  PLOCALGROUPMEMBERSINFO3* = ptr LOCALGROUP_MEMBERS_INFO_3

+  FXPT16DOT16* = int32

+  LPFXPT16DOT16* = ptr FXPT16DOT16

+  TFXPT16DOT16* = FXPT16DOT16

+  PFXPT16DOT16* = ptr FXPT16DOT16

+  LUID* = TlargeInteger

+  TLUID* = LUID

+  PLUID* = ptr LUID

+  LUID_AND_ATTRIBUTES* {.final, pure.} = object

+    Luid*: LUID

+    Attributes*: DWORD

+

+  TLUIDANDATTRIBUTES* = LUID_AND_ATTRIBUTES

+  PLUIDANDATTRIBUTES* = ptr LUID_AND_ATTRIBUTES

+  LUID_AND_ATTRIBUTES_ARRAY* = array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES]

+  PLUID_AND_ATTRIBUTES_ARRAY* = ptr LUID_AND_ATTRIBUTES_ARRAY

+  TLUIDANDATTRIBUTESARRAY* = LUID_AND_ATTRIBUTES_ARRAY

+  LV_COLUMN* {.final, pure.} = object

+    mask*: WINUINT

+    fmt*: int32

+    cx*: int32

+    pszText*: LPTSTR

+    cchTextMax*: int32

+    iSubItem*: int32

+

+  TLVCOLUMN* = LV_COLUMN

+  PLVCOLUMN* = ptr LV_COLUMN

+  LV_ITEM* {.final, pure.} = object

+    mask*: WINUINT

+    iItem*: int32

+    iSubItem*: int32

+    state*: WINUINT

+    stateMask*: WINUINT

+    pszText*: LPTSTR

+    cchTextMax*: int32

+    iImage*: int32

+    lParam*: LPARAM

+

+  TLVITEM* = LV_ITEM

+  PLVITEM* = ptr LV_ITEM

+  LV_DISPINFO* {.final, pure.} = object

+    hdr*: NMHDR

+    item*: LV_ITEM

+

+  TLVDISPINFO* = LV_DISPINFO

+  PLVDISPINFO* = ptr LV_DISPINFO

+  LV_FINDINFO* {.final, pure.} = object

+    flags*: WINUINT

+    psz*: LPCTSTR

+    lParam*: LPARAM

+    pt*: POINT

+    vkDirection*: WINUINT

+

+  TLVFINDINFO* = LV_FINDINFO

+  PLVFINDINFO* = ptr LV_FINDINFO

+  LV_HITTESTINFO* {.final, pure.} = object

+    pt*: POINT

+    flags*: WINUINT

+    iItem*: int32

+

+  TLVHITTESTINFO* = LV_HITTESTINFO

+  PLVHITTESTINFO* = ptr LV_HITTESTINFO

+  LV_KEYDOWN* {.final, pure.} = object

+    hdr*: NMHDR

+    wVKey*: int16

+    flags*: WINUINT

+

+  TLVKEYDOWN* = LV_KEYDOWN

+  PLVKEYDOWN* = ptr LV_KEYDOWN

+  MAT2* {.final, pure.} = object

+    eM11*: FIXED

+    eM12*: FIXED

+    eM21*: FIXED

+    eM22*: FIXED

+

+  TMAT2* = MAT2

+  PMAT2* = ptr MAT2

+  MDICREATESTRUCT* {.final, pure.} = object

+    szClass*: LPCTSTR

+    szTitle*: LPCTSTR

+    hOwner*: HANDLE

+    x*: int32

+    y*: int32

+    cx*: int32

+    cy*: int32

+    style*: DWORD

+    lParam*: LPARAM

+

+  LPMDICREATESTRUCT* = ptr MDICREATESTRUCT

+  TMDICREATESTRUCT* = MDICREATESTRUCT

+  PMDICREATESTRUCT* = ptr MDICREATESTRUCT

+  MEASUREITEMSTRUCT* {.final, pure.} = object

+    CtlType*: WINUINT

+    CtlID*: WINUINT

+    itemID*: WINUINT

+    itemWidth*: WINUINT

+    itemHeight*: WINUINT

+    itemData*: ULONG_PTR

+

+  LPMEASUREITEMSTRUCT* = ptr MEASUREITEMSTRUCT

+  TMEASUREITEMSTRUCT* = MEASUREITEMSTRUCT

+  PMEASUREITEMSTRUCT* = ptr MEASUREITEMSTRUCT

+  MEMORY_BASIC_INFORMATION* {.final, pure.} = object

+    BaseAddress*: PVOID

+    AllocationBase*: PVOID

+    AllocationProtect*: DWORD

+    RegionSize*: DWORD

+    State*: DWORD

+    Protect*: DWORD

+    `type`*: DWORD

+

+  PMEMORY_BASIC_INFORMATION* = ptr MEMORY_BASIC_INFORMATION

+  TMEMORYBASICINFORMATION* = MEMORY_BASIC_INFORMATION

+  MEMORYSTATUS* {.final, pure.} = object

+    dwLength*: DWORD

+    dwMemoryLoad*: DWORD

+    dwTotalPhys*: int

+    dwAvailPhys*: int

+    dwTotalPageFile*: int

+    dwAvailPageFile*: int

+    dwTotalVirtual*: int

+    dwAvailVirtual*: int

+

+  TGUID* {.final, pure.} = object

+    D1*: int32

+    D2*: int16

+    D3*: int16

+    D4*: array [0..7, int8]

+

+  LPMEMORYSTATUS* = ptr MEMORYSTATUS

+  TMEMORYSTATUS* = MEMORYSTATUS

+  PMEMORYSTATUS* = ptr MEMORYSTATUS

+  MENUEX_TEMPLATE_HEADER* {.final, pure.} = object

+    wVersion*: int16

+    wOffset*: int16

+    dwHelpId*: DWORD

+

+  TMENUXTEMPLATEHEADER* = MENUEX_TEMPLATE_HEADER

+  PMENUXTEMPLATEHEADER* = ptr MENUEX_TEMPLATE_HEADER

+  MENUEX_TEMPLATE_ITEM* {.final, pure.} = object

+    dwType*: DWORD

+    dwState*: DWORD

+    uId*: WINUINT

+    bResInfo*: int8

+    szText*: array[0..0, WCHAR]

+    dwHelpId*: DWORD

+

+  TMENUEXTEMPLATEITEM* = MENUEX_TEMPLATE_ITEM

+  PMENUEXTEMPLATEITEM* = ptr MENUEX_TEMPLATE_ITEM

+  MENUINFO* {.final, pure.} = object

+    cbSize*: DWORD

+    fMask*: DWORD

+    dwStyle*: DWORD

+    cyMax*: WINUINT

+    hbrBack*: HBRUSH

+    dwContextHelpID*: DWORD

+    dwMenuData*: ULONG_PTR

+

+  LPMENUINFO* = ptr MENUINFO

+  LPCMENUINFO* = ptr MENUINFO

+  TMENUINFO* = MENUINFO

+  PMENUINFO* = ptr MENUINFO

+  MENUITEMINFO* {.final, pure.} = object

+    cbSize*: WINUINT

+    fMask*: WINUINT

+    fType*: WINUINT

+    fState*: WINUINT

+    wID*: WINUINT

+    hSubMenu*: HMENU

+    hbmpChecked*: HBITMAP

+    hbmpUnchecked*: HBITMAP

+    dwItemData*: ULONG_PTR

+    dwTypeData*: LPTSTR

+    cch*: WINUINT

+    hbmpItem*: HBITMAP

+

+  LPMENUITEMINFO* = ptr MENUITEMINFO

+  LPCMENUITEMINFO* = ptr MENUITEMINFO

+  TMENUITEMINFO* = MENUITEMINFO

+  TMENUITEMINFOA* = MENUITEMINFO

+  PMENUITEMINFO* = ptr MENUITEMINFO

+  MENUITEMTEMPLATE* {.final, pure.} = object

+    mtOption*: int16

+    mtID*: int16

+    mtString*: array[0..0, WCHAR]

+

+  TMENUITEMTEMPLATE* = MENUITEMTEMPLATE

+  PMENUITEMTEMPLATE* = ptr MENUITEMTEMPLATE

+  MENUITEMTEMPLATEHEADER* {.final, pure.} = object

+    versionNumber*: int16

+    offset*: int16

+

+  TMENUITEMTEMPLATEHEADER* = MENUITEMTEMPLATEHEADER

+  PMENUITEMTEMPLATEHEADER* = ptr MENUITEMTEMPLATEHEADER

+  MENUTEMPLATE* {.final, pure.} = object

+  LPMENUTEMPLATE* = ptr MENUTEMPLATE

+  TMENUTEMPLATE* = MENUTEMPLATE

+  PMENUTEMPLATE* = ptr MENUTEMPLATE

+  METAFILEPICT* {.final, pure.} = object

+    mm*: LONG

+    xExt*: LONG

+    yExt*: LONG

+    hMF*: HMETAFILE

+

+  LPMETAFILEPICT* = ptr METAFILEPICT

+  TMETAFILEPICT* = METAFILEPICT

+  PMETAFILEPICT* = ptr METAFILEPICT

+  METAHEADER* {.final, pure.} = object

+    mtType*: int16

+    mtHeaderSize*: int16

+    mtVersion*: int16

+    mtSize*: DWORD

+    mtNoObjects*: int16

+    mtMaxRecord*: DWORD

+    mtNoParameters*: int16

+

+  TMETAHEADER* = METAHEADER

+  PMETAHEADER* = ptr METAHEADER

+  METARECORD* {.final, pure.} = object

+    rdSize*: DWORD

+    rdFunction*: int16

+    rdParm*: array[0..0, int16]

+

+  LPMETARECORD* = ptr METARECORD

+  TMETARECORD* = METARECORD

+  PMETARECORD* = ptr METARECORD

+  MINIMIZEDMETRICS* {.final, pure.} = object

+    cbSize*: WINUINT

+    iWidth*: int32

+    iHorzGap*: int32

+    iVertGap*: int32

+    iArrange*: int32

+

+  LPMINIMIZEDMETRICS* = ptr MINIMIZEDMETRICS

+  TMINIMIZEDMETRICS* = MINIMIZEDMETRICS

+  PMINIMIZEDMETRICS* = ptr MINIMIZEDMETRICS

+  MINMAXINFO* {.final, pure.} = object

+    ptReserved*: POINT

+    ptMaxSize*: POINT

+    ptMaxPosition*: POINT

+    ptMinTrackSize*: POINT

+    ptMaxTrackSize*: POINT

+

+  TMINMAXINFO* = MINMAXINFO

+  PMINMAXINFO* = ptr MINMAXINFO

+  MODEMDEVCAPS* {.final, pure.} = object

+    dwActualSize*: DWORD

+    dwRequiredSize*: DWORD

+    dwDevSpecificOffset*: DWORD

+    dwDevSpecificSize*: DWORD

+    dwModemProviderVersion*: DWORD

+    dwModemManufacturerOffset*: DWORD

+    dwModemManufacturerSize*: DWORD

+    dwModemModelOffset*: DWORD

+    dwModemModelSize*: DWORD

+    dwModemVersionOffset*: DWORD

+    dwModemVersionSize*: DWORD

+    dwDialOptions*: DWORD

+    dwCallSetupFailTimer*: DWORD

+    dwInactivityTimeout*: DWORD

+    dwSpeakerVolume*: DWORD

+    dwSpeakerMode*: DWORD

+    dwModemOptions*: DWORD

+    dwMaxDTERate*: DWORD

+    dwMaxDCERate*: DWORD

+    abVariablePortion*: array[0..0, int8]

+

+  LPMODEMDEVCAPS* = ptr MODEMDEVCAPS

+  TMODEMDEVCAPS* = MODEMDEVCAPS

+  PMODEMDEVCAPS* = ptr MODEMDEVCAPS

+  MODEMSETTINGS* {.final, pure.} = object

+    dwActualSize*: DWORD

+    dwRequiredSize*: DWORD

+    dwDevSpecificOffset*: DWORD

+    dwDevSpecificSize*: DWORD

+    dwCallSetupFailTimer*: DWORD

+    dwInactivityTimeout*: DWORD

+    dwSpeakerVolume*: DWORD

+    dwSpeakerMode*: DWORD

+    dwPreferredModemOptions*: DWORD

+    dwNegotiatedModemOptions*: DWORD

+    dwNegotiatedDCERate*: DWORD

+    abVariablePortion*: array[0..0, int8]

+

+  LPMODEMSETTINGS* = ptr MODEMSETTINGS

+  TMODEMSETTINGS* = MODEMSETTINGS

+  PMODEMSETTINGS* = ptr MODEMSETTINGS

+  MONCBSTRUCT* {.final, pure.} = object

+    cb*: WINUINT

+    dwTime*: DWORD

+    hTask*: HANDLE

+    dwRet*: DWORD

+    wType*: WINUINT

+    wFmt*: WINUINT

+    hConv*: HCONV

+    hsz1*: HSZ

+    hsz2*: HSZ

+    hData*: HDDEDATA

+    dwData1*: DWORD

+    dwData2*: DWORD

+    cc*: CONVCONTEXT

+    cbData*: DWORD

+    Data*: array[0..7, DWORD]

+

+  TMONCBSTRUCT* = MONCBSTRUCT

+  PMONCBSTRUCT* = ptr MONCBSTRUCT

+  MONCONVSTRUCT* {.final, pure.} = object

+    cb*: WINUINT

+    fConnect*: WINBOOL

+    dwTime*: DWORD

+    hTask*: HANDLE

+    hszSvc*: HSZ

+    hszTopic*: HSZ

+    hConvClient*: HCONV

+    hConvServer*: HCONV

+

+  TMONCONVSTRUCT* = MONCONVSTRUCT

+  PMONCONVSTRUCT* = ptr MONCONVSTRUCT

+  MONERRSTRUCT* {.final, pure.} = object

+    cb*: WINUINT

+    wLastError*: WINUINT

+    dwTime*: DWORD

+    hTask*: HANDLE

+

+  TMONERRSTRUCT* = MONERRSTRUCT

+  PMONERRSTRUCT* = ptr MONERRSTRUCT

+  MONHSZSTRUCT* {.final, pure.} = object

+    cb*: WINUINT

+    fsAction*: WINBOOL

+    dwTime*: DWORD

+    hsz*: HSZ

+    hTask*: HANDLE

+    str*: array[0..0, TCHAR]

+

+  TMONHSZSTRUCT* = MONHSZSTRUCT

+  PMONHSZSTRUCT* = ptr MONHSZSTRUCT

+  MONITOR_INFO_1* {.final, pure.} = object

+    pName*: LPTSTR

+

+  TMONITORINFO1* = MONITOR_INFO_1

+  PMONITORINFO1* = ptr MONITOR_INFO_1

+  MONITOR_INFO_2* {.final, pure.} = object

+    pName*: LPTSTR

+    pEnvironment*: LPTSTR

+    pDLLName*: LPTSTR

+

+  TMONITORINFO2* = MONITOR_INFO_2

+  PMONITORINFO2* = ptr MONITOR_INFO_2

+  MONLINKSTRUCT* {.final, pure.} = object

+    cb*: WINUINT

+    dwTime*: DWORD

+    hTask*: HANDLE

+    fEstablished*: WINBOOL

+    fNoData*: WINBOOL

+    hszSvc*: HSZ

+    hszTopic*: HSZ

+    hszItem*: HSZ

+    wFmt*: WINUINT

+    fServer*: WINBOOL

+    hConvServer*: HCONV

+    hConvClient*: HCONV

+

+  TMONLINKSTRUCT* = MONLINKSTRUCT

+  PMONLINKSTRUCT* = ptr MONLINKSTRUCT

+  MONMSGSTRUCT* {.final, pure.} = object

+    cb*: WINUINT

+    hwndTo*: HWND

+    dwTime*: DWORD

+    hTask*: HANDLE

+    wMsg*: WINUINT

+    wParam*: WPARAM

+    lParam*: LPARAM

+    dmhd*: DDEML_MSG_HOOK_DATA

+

+  TMONMSGSTRUCT* = MONMSGSTRUCT

+  PMONMSGSTRUCT* = ptr MONMSGSTRUCT

+  MOUSEHOOKSTRUCT* {.final, pure.} = object

+    pt*: POINT

+    hwnd*: HWND

+    wHitTestCode*: WINUINT

+    dwExtraInfo*: DWORD

+

+  LPMOUSEHOOKSTRUCT* = ptr MOUSEHOOKSTRUCT

+  TMOUSEHOOKSTRUCT* = MOUSEHOOKSTRUCT

+  PMOUSEHOOKSTRUCT* = ptr MOUSEHOOKSTRUCT

+  MOUSEKEYS* {.final, pure.} = object

+    cbSize*: DWORD

+    dwFlags*: DWORD

+    iMaxSpeed*: DWORD

+    iTimeToMaxSpeed*: DWORD

+    iCtrlSpeed*: DWORD

+    dwReserved1*: DWORD

+    dwReserved2*: DWORD

+

+  TMOUSEKEYS* = MOUSEKEYS

+  PMOUSEKEYS* = ptr MOUSEKEYS

+  MSGBOXCALLBACK* = proc (lpHelpInfo: LPHELPINFO){.stdcall.}

+  TMSGBOXCALLBACK* = MSGBOXCALLBACK

+  MSGBOXPARAMS* {.final, pure.} = object

+    cbSize*: WINUINT

+    hwndOwner*: HWND

+    hInstance*: HINST

+    lpszText*: LPCSTR

+    lpszCaption*: LPCSTR

+    dwStyle*: DWORD

+    lpszIcon*: LPCSTR

+    dwContextHelpId*: DWORD

+    lpfnMsgBoxCallback*: MSGBOXCALLBACK

+    dwLanguageId*: DWORD

+

+  LPMSGBOXPARAMS* = ptr MSGBOXPARAMS

+  TMSGBOXPARAMS* = MSGBOXPARAMS

+  TMSGBOXPARAMSA* = MSGBOXPARAMS

+  PMSGBOXPARAMS* = ptr MSGBOXPARAMS

+  MSGFILTER* {.final, pure.} = object

+    nmhdr*: NMHDR

+    msg*: WINUINT

+    wParam*: WPARAM

+    lParam*: LPARAM

+

+  Tmsgfilter* = MSGFILTER

+  Pmsgfilter* = ptr MSGFILTER

+  MULTIKEYHELP* {.final, pure.} = object

+    mkSize*: DWORD

+    mkKeylist*: TCHAR

+    szKeyphrase*: array[0..0, TCHAR]

+

+  TMULTIKEYHELP* = MULTIKEYHELP

+  PMULTIKEYHELP* = ptr MULTIKEYHELP

+  NAME_BUFFER* {.final, pure.} = object

+    name*: array[0..(NCBNAMSZ) - 1, UCHAR]

+    name_num*: UCHAR

+    name_flags*: UCHAR

+

+  TNAMEBUFFER* = NAME_BUFFER

+  PNAMEBUFFER* = ptr NAME_BUFFER

+  p_NCB* = ptr NCB

+  NCB* {.final, pure.} = object

+    ncb_command*: UCHAR

+    ncb_retcode*: UCHAR

+    ncb_lsn*: UCHAR

+    ncb_num*: UCHAR

+    ncb_buffer*: PUCHAR

+    ncb_length*: int16

+    ncb_callname*: array[0..(NCBNAMSZ) - 1, UCHAR]

+    ncb_name*: array[0..(NCBNAMSZ) - 1, UCHAR]

+    ncb_rto*: UCHAR

+    ncb_sto*: UCHAR

+    ncb_post*: proc (para1: p_NCB){.cdecl.}

+    ncb_lana_num*: UCHAR

+    ncb_cmd_cplt*: UCHAR

+    ncb_reserve*: array[0..9, UCHAR]

+    ncb_event*: HANDLE

+

+  TNCB* = NCB

+  NCCALCSIZE_PARAMS* {.final, pure.} = object

+    rgrc*: array[0..2, RECT]

+    lppos*: PWINDOWPOS

+

+  TNCCALCSIZEPARAMS* = NCCALCSIZE_PARAMS

+  PNCCALCSIZEPARAMS* = ptr NCCALCSIZE_PARAMS

+  NDDESHAREINFO* {.final, pure.} = object

+    lRevision*: LONG

+    lpszShareName*: LPTSTR

+    lShareType*: LONG

+    lpszAppTopicList*: LPTSTR

+    fSharedFlag*: LONG

+    fService*: LONG

+    fStartAppFlag*: LONG

+    nCmdShow*: LONG

+    qModifyId*: array[0..1, LONG]

+    cNumItems*: LONG

+    lpszItemList*: LPTSTR

+

+  TNDDESHAREINFO* = NDDESHAREINFO

+  PNDDESHAREINFO* = ptr NDDESHAREINFO

+  NETRESOURCE* {.final, pure.} = object

+    dwScope*: DWORD

+    dwType*: DWORD

+    dwDisplayType*: DWORD

+    dwUsage*: DWORD

+    lpLocalName*: LPTSTR

+    lpRemoteName*: LPTSTR

+    lpComment*: LPTSTR

+    lpProvider*: LPTSTR

+

+  LPNETRESOURCE* = ptr NETRESOURCE

+  TNETRESOURCE* = NETRESOURCE

+  TNETRESOURCEA* = NETRESOURCE

+  PNETRESOURCE* = ptr NETRESOURCE

+  PNETRESOURCEA* = ptr NETRESOURCE

+  NEWCPLINFO* {.final, pure.} = object

+    dwSize*: DWORD

+    dwFlags*: DWORD

+    dwHelpContext*: DWORD

+    lData*: LONG

+    hIcon*: HICON

+    szName*: array[0..31, TCHAR]

+    szInfo*: array[0..63, TCHAR]

+    szHelpFile*: array[0..127, TCHAR]

+

+  TNEWCPLINFO* = NEWCPLINFO

+  PNEWCPLINFO* = ptr NEWCPLINFO

+  NEWTEXTMETRIC* {.final, pure.} = object

+    tmHeight*: LONG

+    tmAscent*: LONG

+    tmDescent*: LONG

+    tmInternalLeading*: LONG

+    tmExternalLeading*: LONG

+    tmAveCharWidth*: LONG

+    tmMaxCharWidth*: LONG

+    tmWeight*: LONG

+    tmOverhang*: LONG

+    tmDigitizedAspectX*: LONG

+    tmDigitizedAspectY*: LONG

+    tmFirstChar*: BCHAR

+    tmLastChar*: BCHAR

+    tmDefaultChar*: BCHAR

+    tmBreakChar*: BCHAR

+    tmItalic*: int8

+    tmUnderlined*: int8

+    tmStruckOut*: int8

+    tmPitchAndFamily*: int8

+    tmCharSet*: int8

+    ntmFlags*: DWORD

+    ntmSizeEM*: WINUINT

+    ntmCellHeight*: WINUINT

+    ntmAvgWidth*: WINUINT

+

+  TNEWTEXTMETRIC* = NEWTEXTMETRIC

+  PNEWTEXTMETRIC* = ptr NEWTEXTMETRIC

+  NEWTEXTMETRICEX* {.final, pure.} = object

+    ntmentm*: NEWTEXTMETRIC

+    ntmeFontSignature*: FONTSIGNATURE

+

+  TNEWTEXTMETRICEX* = NEWTEXTMETRICEX

+  PNEWTEXTMETRICEX* = ptr NEWTEXTMETRICEX

+  NM_LISTVIEW* {.final, pure.} = object

+    hdr*: NMHDR

+    iItem*: int32

+    iSubItem*: int32

+    uNewState*: WINUINT

+    uOldState*: WINUINT

+    uChanged*: WINUINT

+    ptAction*: POINT

+    lParam*: LPARAM

+

+  TNMLISTVIEW* = NM_LISTVIEW

+  PNMLISTVIEW* = ptr NM_LISTVIEW

+  TV_ITEM* {.final, pure.} = object

+    mask*: WINUINT

+    hItem*: HTREEITEM

+    state*: WINUINT

+    stateMask*: WINUINT

+    pszText*: LPTSTR

+    cchTextMax*: int32

+    iImage*: int32

+    iSelectedImage*: int32

+    cChildren*: int32

+    lParam*: LPARAM

+

+  LPTV_ITEM* = ptr TV_ITEM

+  TTVITEM* = TV_ITEM

+  PTVITEM* = ptr TV_ITEM

+  NM_TREEVIEW* {.final, pure.} = object

+    hdr*: NMHDR

+    action*: WINUINT

+    itemOld*: TV_ITEM

+    itemNew*: TV_ITEM

+    ptDrag*: POINT

+

+  LPNM_TREEVIEW* = ptr NM_TREEVIEW

+  TNMTREEVIEW* = NM_TREEVIEW

+  PNMTREEVIEW* = ptr NM_TREEVIEW

+  NM_UPDOWNW* {.final, pure.} = object

+    hdr*: NMHDR

+    iPos*: int32

+    iDelta*: int32

+

+  TNMUPDOWN* = NM_UPDOWNW

+  PNMUPDOWN* = ptr NM_UPDOWNW

+  NONCLIENTMETRICS* {.final, pure.} = object

+    cbSize*: WINUINT

+    iBorderWidth*: int32

+    iScrollWidth*: int32

+    iScrollHeight*: int32

+    iCaptionWidth*: int32

+    iCaptionHeight*: int32

+    lfCaptionFont*: LOGFONT

+    iSmCaptionWidth*: int32

+    iSmCaptionHeight*: int32

+    lfSmCaptionFont*: LOGFONT

+    iMenuWidth*: int32

+    iMenuHeight*: int32

+    lfMenuFont*: LOGFONT

+    lfStatusFont*: LOGFONT

+    lfMessageFont*: LOGFONT

+

+  LPNONCLIENTMETRICS* = ptr NONCLIENTMETRICS

+  TNONCLIENTMETRICS* = NONCLIENTMETRICS

+  PNONCLIENTMETRICS* = ptr NONCLIENTMETRICS

+  SERVICE_ADDRESS* {.final, pure.} = object

+    dwAddressType*: DWORD

+    dwAddressFlags*: DWORD

+    dwAddressLength*: DWORD

+    dwPrincipalLength*: DWORD

+    lpAddress*: ptr int8

+    lpPrincipal*: ptr int8

+

+  TSERVICEADDRESS* = SERVICE_ADDRESS

+  PSERVICEADDRESS* = ptr SERVICE_ADDRESS

+  SERVICE_ADDRESSES* {.final, pure.} = object

+    dwAddressCount*: DWORD

+    Addresses*: array[0..0, SERVICE_ADDRESS]

+

+  LPSERVICE_ADDRESSES* = ptr SERVICE_ADDRESSES

+  TSERVICEADDRESSES* = SERVICE_ADDRESSES

+  PSERVICEADDRESSES* = ptr SERVICE_ADDRESSES

+  LPGUID* = ptr TGUID

+  PGUID* = ptr TGUID

+  CLSID* = TGUID

+  LPCLSID* = ptr CLSID

+  TCLSID* = CLSID

+  PCLSID* = ptr CLSID

+  SERVICE_INFO* {.final, pure.} = object

+    lpServiceType*: LPGUID

+    lpServiceName*: LPTSTR

+    lpComment*: LPTSTR

+    lpLocale*: LPTSTR

+    dwDisplayHint*: DWORD

+    dwVersion*: DWORD

+    dwTime*: DWORD

+    lpMachineName*: LPTSTR

+    lpServiceAddress*: LPSERVICE_ADDRESSES

+    ServiceSpecificInfo*: BLOB

+

+  TSERVICEINFO* = SERVICE_INFO

+  PSERVICEINFO* = ptr SERVICE_INFO

+  NS_SERVICE_INFO* {.final, pure.} = object

+    dwNameSpace*: DWORD

+    ServiceInfo*: SERVICE_INFO

+

+  TNSSERVICEINFO* = NS_SERVICE_INFO

+  PNSSERVICEINFO* = ptr NS_SERVICE_INFO

+  NUMBERFMT* {.final, pure.} = object

+    NumDigits*: WINUINT

+    LeadingZero*: WINUINT

+    Grouping*: WINUINT

+    lpDecimalSep*: LPTSTR

+    lpThousandSep*: LPTSTR

+    NegativeOrder*: WINUINT

+

+  Tnumberfmt* = NUMBERFMT

+  Pnumberfmt* = ptr NUMBERFMT

+  OFSTRUCT* {.final, pure.} = object

+    cBytes*: int8

+    fFixedDisk*: int8

+    nErrCode*: int16

+    Reserved1*: int16

+    Reserved2*: int16

+    szPathName*: array[0..(OFS_MAXPATHNAME) - 1, char]

+

+  LPOFSTRUCT* = ptr OFSTRUCT

+  TOFSTRUCT* = OFSTRUCT

+  POFSTRUCT* = ptr OFSTRUCT

+  OPENFILENAME_NT4* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hInstance*: HINST

+    lpstrFilter*: LPCTSTR

+    lpstrCustomFilter*: LPTSTR

+    nMaxCustFilter*: DWORD

+    nFilterIndex*: DWORD

+    lpstrFile*: LPTSTR

+    nMaxFile*: DWORD

+    lpstrFileTitle*: LPTSTR

+    nMaxFileTitle*: DWORD

+    lpstrInitialDir*: LPCTSTR

+    lpstrTitle*: LPCTSTR

+    Flags*: DWORD

+    nFileOffset*: int16

+    nFileExtension*: int16

+    lpstrDefExt*: LPCTSTR

+    lCustData*: LPARAM

+    lpfnHook*: LPOFNHOOKPROC

+    lpTemplateName*: LPCTSTR

+

+  LPOPENFILENAME_NT4* = ptr OPENFILENAME_NT4

+  TOPENFILENAME_NT4* = OPENFILENAME_NT4

+  POPENFILENAME_NT4* = ptr OPENFILENAME_NT4

+  TOPENFILENAME* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hInstance*: HINST

+    lpstrFilter*: LPCTSTR

+    lpstrCustomFilter*: LPTSTR

+    nMaxCustFilter*: DWORD

+    nFilterIndex*: DWORD

+    lpstrFile*: LPTSTR

+    nMaxFile*: DWORD

+    lpstrFileTitle*: LPTSTR

+    nMaxFileTitle*: DWORD

+    lpstrInitialDir*: LPCTSTR

+    lpstrTitle*: LPCTSTR

+    flags*: DWORD

+    nFileOffset*: int16

+    nFileExtension*: int16

+    lpstrDefExt*: LPCTSTR

+    lCustData*: LPARAM

+    lpfnHook*: LPOFNHOOKPROC

+    lpTemplateName*: LPCTSTR

+    pvReserved*: pointer

+    dwreserved*: DWORD

+    FlagsEx*: DWORD

+

+  LPOPENFILENAME* = ptr TOPENFILENAME

+  POPENFILENAME* = ptr TOPENFILENAME

+  OFN* = TOPENFILENAME

+  POFN* = ptr TOPENFILENAME

+  OFNOTIFY* {.final, pure.} = object

+    hdr*: NMHDR

+    lpOFN*: LPOPENFILENAME

+    pszFile*: LPTSTR

+

+  LPOFNOTIFY* = ptr OFNOTIFY

+  TOFNOTIFY* = OFNOTIFY

+  POFNOTIFY* = ptr OFNOTIFY

+  OSVERSIONINFO* {.final, pure.} = object

+    dwOSVersionInfoSize*: DWORD

+    dwMajorVersion*: DWORD

+    dwMinorVersion*: DWORD

+    dwBuildNumber*: DWORD

+    dwPlatformId*: DWORD

+    szCSDVersion*: array[0..127, TCHAR]

+

+  LPOSVERSIONINFO* = ptr OSVERSIONINFO

+  TOSVERSIONINFO* = OSVERSIONINFO

+  POSVERSIONINFO* = ptr OSVERSIONINFO

+  OSVERSIONINFOW* {.final, pure.} = object

+    dwOSVersionInfoSize*: DWORD

+    dwMajorVersion*: DWORD

+    dwMinorVersion*: DWORD

+    dwBuildNumber*: DWORD

+    dwPlatformId*: DWORD

+    szCSDVersion*: array[0..127, WCHAR]

+

+  LPOSVERSIONINFOW* = ptr OSVERSIONINFOW

+  TOSVERSIONINFOW* = OSVERSIONINFOW

+  POSVERSIONINFOW* = ptr OSVERSIONINFOW

+  TEXTMETRIC* {.final, pure.} = object

+    tmHeight*: LONG

+    tmAscent*: LONG

+    tmDescent*: LONG

+    tmInternalLeading*: LONG

+    tmExternalLeading*: LONG

+    tmAveCharWidth*: LONG

+    tmMaxCharWidth*: LONG

+    tmWeight*: LONG

+    tmOverhang*: LONG

+    tmDigitizedAspectX*: LONG

+    tmDigitizedAspectY*: LONG

+    tmFirstChar*: BCHAR

+    tmLastChar*: BCHAR

+    tmDefaultChar*: BCHAR

+    tmBreakChar*: BCHAR

+    tmItalic*: int8

+    tmUnderlined*: int8

+    tmStruckOut*: int8

+    tmPitchAndFamily*: int8

+    tmCharSet*: int8

+

+  LPTEXTMETRIC* = ptr TEXTMETRIC

+  TTEXTMETRIC* = TEXTMETRIC

+  PTEXTMETRIC* = ptr TEXTMETRIC

+  TEXTMETRICW* {.final, pure.} = object

+    tmHeight*: LONG

+    tmAscent*: LONG

+    tmDescent*: LONG

+    tmInternalLeading*: LONG

+    tmExternalLeading*: LONG

+    tmAveCharWidth*: LONG

+    tmMaxCharWidth*: LONG

+    tmWeight*: LONG

+    tmOverhang*: LONG

+    tmDigitizedAspectX*: LONG

+    tmDigitizedAspectY*: LONG

+    tmFirstChar*: WCHAR

+    tmLastChar*: WCHAR

+    tmDefaultChar*: WCHAR

+    tmBreakChar*: WCHAR

+    tmItalic*: int8

+    tmUnderlined*: int8

+    tmStruckOut*: int8

+    tmPitchAndFamily*: int8

+    tmCharSet*: int8

+

+  LPTEXTMETRICW* = ptr TEXTMETRICW

+  TTEXTMETRICW* = TEXTMETRICW

+  PTEXTMETRICW* = ptr TEXTMETRICW

+  OUTLINETEXTMETRIC* {.final, pure.} = object

+    otmSize*: WINUINT

+    otmTextMetrics*: TEXTMETRIC

+    otmFiller*: int8

+    otmPanoseNumber*: PANOSE

+    otmfsSelection*: WINUINT

+    otmfsType*: WINUINT

+    otmsCharSlopeRise*: int32

+    otmsCharSlopeRun*: int32

+    otmItalicAngle*: int32

+    otmEMSquare*: WINUINT

+    otmAscent*: int32

+    otmDescent*: int32

+    otmLineGap*: WINUINT

+    otmsCapEmHeight*: WINUINT

+    otmsXHeight*: WINUINT

+    otmrcFontBox*: RECT

+    otmMacAscent*: int32

+    otmMacDescent*: int32

+    otmMacLineGap*: WINUINT

+    otmusMinimumPPEM*: WINUINT

+    otmptSubscriptSize*: POINT

+    otmptSubscriptOffset*: POINT

+    otmptSuperscriptSize*: POINT

+    otmptSuperscriptOffset*: POINT

+    otmsStrikeoutSize*: WINUINT

+    otmsStrikeoutPosition*: int32

+    otmsUnderscoreSize*: int32

+    otmsUnderscorePosition*: int32

+    otmpFamilyName*: PSTR

+    otmpFaceName*: PSTR

+    otmpStyleName*: PSTR

+    otmpFullName*: PSTR

+

+  LPOUTLINETEXTMETRIC* = ptr OUTLINETEXTMETRIC

+  TOUTLINETEXTMETRIC* = OUTLINETEXTMETRIC

+  POUTLINETEXTMETRIC* = ptr OUTLINETEXTMETRIC

+  OVERLAPPED* {.final, pure.} = object

+    Internal*: DWORD

+    InternalHigh*: DWORD

+    Offset*: DWORD

+    OffsetHigh*: DWORD

+    hEvent*: HANDLE

+

+  LPOVERLAPPED* = ptr OVERLAPPED

+  TOVERLAPPED* = OVERLAPPED

+  POVERLAPPED* = ptr OVERLAPPED

+  #PAGESETUPDLG = record conflicts with function PageSetupDlg

+  TPAGESETUPDLG* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hDevMode*: HGLOBAL

+    hDevNames*: HGLOBAL

+    Flags*: DWORD

+    ptPaperSize*: POINT

+    rtMinMargin*: RECT

+    rtMargin*: RECT

+    hInstance*: HINST

+    lCustData*: LPARAM

+    lpfnPageSetupHook*: LPPAGESETUPHOOK

+    lpfnPagePaintHook*: LPPAGEPAINTHOOK

+    lpPageSetupTemplateName*: LPCTSTR

+    hPageSetupTemplate*: HGLOBAL

+

+  LPPAGESETUPDLG* = ptr TPAGESETUPDLG

+  PPAGESETUPDLG* = ptr TPAGESETUPDLG

+  TPSD* = TPAGESETUPDLG

+  PPSD* = ptr TPAGESETUPDLG

+  PAINTSTRUCT* {.final, pure.} = object

+    hdc*: HDC

+    fErase*: WINBOOL

+    rcPaint*: RECT

+    fRestore*: WINBOOL

+    fIncUpdate*: WINBOOL

+    rgbReserved*: array[0..31, int8]

+

+  LPPAINTSTRUCT* = ptr PAINTSTRUCT

+  TPAINTSTRUCT* = PAINTSTRUCT

+  PPAINTSTRUCT* = ptr PAINTSTRUCT

+  PARAFORMAT* {.final, pure.} = object

+    cbSize*: WINUINT

+    dwMask*: DWORD

+    wNumbering*: int16

+    wReserved*: int16

+    dxStartIndent*: LONG

+    dxRightIndent*: LONG

+    dxOffset*: LONG

+    wAlignment*: int16

+    cTabCount*: SHORT

+    rgxTabs*: array[0..(MAX_TAB_STOPS) - 1, LONG]

+

+  Tparaformat* = PARAFORMAT

+  Pparaformat* = ptr PARAFORMAT

+  PERF_COUNTER_BLOCK* {.final, pure.} = object

+    ByteLength*: DWORD

+

+  TPERFCOUNTERBLOCK* = PERF_COUNTER_BLOCK

+  PPERFCOUNTERBLOCK* = ptr PERF_COUNTER_BLOCK

+  PERF_COUNTER_DEFINITION* {.final, pure.} = object

+    ByteLength*: DWORD

+    CounterNameTitleIndex*: DWORD

+    CounterNameTitle*: LPWSTR

+    CounterHelpTitleIndex*: DWORD

+    CounterHelpTitle*: LPWSTR

+    DefaultScale*: DWORD

+    DetailLevel*: DWORD

+    CounterType*: DWORD

+    CounterSize*: DWORD

+    CounterOffset*: DWORD

+

+  TPERFCOUNTERDEFINITION* = PERF_COUNTER_DEFINITION

+  PPERFCOUNTERDEFINITION* = ptr PERF_COUNTER_DEFINITION

+  PERF_DATA_BLOCK* {.final, pure.} = object

+    Signature*: array[0..3, WCHAR]

+    LittleEndian*: DWORD

+    Version*: DWORD

+    Revision*: DWORD

+    TotalByteLength*: DWORD

+    HeaderLength*: DWORD

+    NumObjectTypes*: DWORD

+    DefaultObject*: DWORD

+    SystemTime*: SYSTEMTIME

+    PerfTime*: LARGE_INTEGER

+    PerfFreq*: LARGE_INTEGER

+    PerfTime100nSec*: LARGE_INTEGER

+    SystemNameLength*: DWORD

+    SystemNameOffset*: DWORD

+

+  TPERFDATABLOCK* = PERF_DATA_BLOCK

+  PPERFDATABLOCK* = ptr PERF_DATA_BLOCK

+  PERF_INSTANCE_DEFINITION* {.final, pure.} = object

+    ByteLength*: DWORD

+    ParentObjectTitleIndex*: DWORD

+    ParentObjectInstance*: DWORD

+    UniqueID*: DWORD

+    NameOffset*: DWORD

+    NameLength*: DWORD

+

+  TPERFINSTANCEDEFINITION* = PERF_INSTANCE_DEFINITION

+  PPERFINSTANCEDEFINITION* = PERF_INSTANCE_DEFINITION

+  PERF_OBJECT_TYPE* {.final, pure.} = object

+    TotalByteLength*: DWORD

+    DefinitionLength*: DWORD

+    HeaderLength*: DWORD

+    ObjectNameTitleIndex*: DWORD

+    ObjectNameTitle*: LPWSTR

+    ObjectHelpTitleIndex*: DWORD

+    ObjectHelpTitle*: LPWSTR

+    DetailLevel*: DWORD

+    NumCounters*: DWORD

+    DefaultCounter*: DWORD

+    NumInstances*: DWORD

+    CodePage*: DWORD

+    PerfTime*: LARGE_INTEGER

+    PerfFreq*: LARGE_INTEGER

+

+  TPERFOBJECTTYPE* = PERF_OBJECT_TYPE

+  PPERFOBJECTTYPE* = ptr PERF_OBJECT_TYPE

+  POLYTEXT* {.final, pure.} = object

+    x*: int32

+    y*: int32

+    n*: WINUINT

+    lpstr*: LPCTSTR

+    uiFlags*: WINUINT

+    rcl*: RECT

+    pdx*: ptr int32

+

+  TPOLYTEXT* = POLYTEXT

+  PPOLYTEXT* = ptr POLYTEXT

+  PORT_INFO_1* {.final, pure.} = object

+    pName*: LPTSTR

+

+  TPORTINFO1* = PORT_INFO_1

+  PPORTINFO1* = ptr PORT_INFO_1

+  PORT_INFO_2* {.final, pure.} = object

+    pPortName*: LPSTR

+    pMonitorName*: LPSTR

+    pDescription*: LPSTR

+    fPortType*: DWORD

+    Reserved*: DWORD

+

+  TPORTINFO2* = PORT_INFO_2

+  PPORTINFO2* = ptr PORT_INFO_2

+  PREVENT_MEDIA_REMOVAL* {.final, pure.} = object

+    PreventMediaRemoval*: bool

+

+  TPREVENTMEDIAREMOVAL* = PREVENT_MEDIA_REMOVAL

+  PPREVENTMEDIAREMOVAL* = ptr PREVENT_MEDIA_REMOVAL

+  #PRINTDLG = record conflicts with PrintDlg function

+  TPRINTDLG* {.final, pure.} = object

+    lStructSize*: DWORD

+    hwndOwner*: HWND

+    hDevMode*: HANDLE

+    hDevNames*: HANDLE

+    hDC*: HDC

+    Flags*: DWORD

+    nFromPage*: int16

+    nToPage*: int16

+    nMinPage*: int16

+    nMaxPage*: int16

+    nCopies*: int16

+    hInstance*: HINST

+    lCustData*: DWORD

+    lpfnPrintHook*: LPPRINTHOOKPROC

+    lpfnSetupHook*: LPSETUPHOOKPROC

+    lpPrintTemplateName*: LPCTSTR

+    lpSetupTemplateName*: LPCTSTR

+    hPrintTemplate*: HANDLE

+    hSetupTemplate*: HANDLE

+

+  LPPRINTDLG* = ptr TPRINTDLG

+  PPRINTDLG* = ptr TPRINTDLG

+  TPD* = TPRINTDLG

+  PPD* = ptr TPRINTDLG

+  PRINTER_DEFAULTS* {.final, pure.} = object

+    pDatatype*: LPTSTR

+    pDevMode*: LPDEVMODE

+    DesiredAccess*: ACCESS_MASK

+

+  TPRINTERDEFAULTS* = PRINTER_DEFAULTS

+  PPRINTERDEFAULTS* = ptr PRINTER_DEFAULTS

+  PRINTER_INFO_1* {.final, pure.} = object

+    Flags*: DWORD

+    pDescription*: LPTSTR

+    pName*: LPTSTR

+    pComment*: LPTSTR

+

+  LPPRINTER_INFO_1* = ptr PRINTER_INFO_1

+  PPRINTER_INFO_1* = ptr PRINTER_INFO_1

+  TPRINTERINFO1* = PRINTER_INFO_1

+  PRINTER_INFO_2* {.final, pure.} = object

+    pServerName*: LPTSTR

+    pPrinterName*: LPTSTR

+    pShareName*: LPTSTR

+    pPortName*: LPTSTR

+    pDriverName*: LPTSTR

+    pComment*: LPTSTR

+    pLocation*: LPTSTR

+    pDevMode*: LPDEVMODE

+    pSepFile*: LPTSTR

+    pPrintProcessor*: LPTSTR

+    pDatatype*: LPTSTR

+    pParameters*: LPTSTR

+    pSecurityDescriptor*: PSECURITY_DESCRIPTOR

+    Attributes*: DWORD

+    Priority*: DWORD

+    DefaultPriority*: DWORD

+    StartTime*: DWORD

+    UntilTime*: DWORD

+    Status*: DWORD

+    cJobs*: DWORD

+    AveragePPM*: DWORD

+

+  TPRINTERINFO2* = PRINTER_INFO_2

+  PPRINTERINFO2* = ptr PRINTER_INFO_2

+  PRINTER_INFO_3* {.final, pure.} = object

+    pSecurityDescriptor*: PSECURITY_DESCRIPTOR

+

+  TPRINTERINFO3* = PRINTER_INFO_3

+  PPRINTERINFO3* = ptr PRINTER_INFO_3

+  PRINTER_INFO_4* {.final, pure.} = object

+    pPrinterName*: LPTSTR

+    pServerName*: LPTSTR

+    Attributes*: DWORD

+

+  TPRINTERINFO4* = PRINTER_INFO_4

+  PPRINTERINFO4* = ptr PRINTER_INFO_4

+  PRINTER_INFO_5* {.final, pure.} = object

+    pPrinterName*: LPTSTR

+    pPortName*: LPTSTR

+    Attributes*: DWORD

+    DeviceNotSelectedTimeout*: DWORD

+    TransmissionRetryTimeout*: DWORD

+

+  TPRINTERINFO5* = PRINTER_INFO_5

+  PPRINTERINFO5* = ptr PRINTER_INFO_5

+  PRINTER_NOTIFY_INFO_DATA* {.final, pure.} = object

+    `type`*: int16

+    Field*: int16

+    Reserved*: DWORD

+    Id*: DWORD

+    cbBuf*: DWORD

+    pBuf*: LPVOID

+

+  TPRINTERNOTIFYINFODATA* = PRINTER_NOTIFY_INFO_DATA

+  PPRINTERNOTIFYINFODATA* = ptr PRINTER_NOTIFY_INFO_DATA

+  PRINTER_NOTIFY_INFO* {.final, pure.} = object

+    Version*: DWORD

+    Flags*: DWORD

+    Count*: DWORD

+    aData*: array[0..0, PRINTER_NOTIFY_INFO_DATA]

+

+  TPRINTERNOTIFYINFO* = PRINTER_NOTIFY_INFO

+  PPRINTERNOTIFYINFO* = ptr PRINTER_NOTIFY_INFO

+  PRINTER_NOTIFY_OPTIONS_TYPE* {.final, pure.} = object

+    `type`*: int16

+    Reserved0*: int16

+    Reserved1*: DWORD

+    Reserved2*: DWORD

+    Count*: DWORD

+    pFields*: PWORD

+

+  PPRINTER_NOTIFY_OPTIONS_TYPE* = ptr PRINTER_NOTIFY_OPTIONS_TYPE

+  TPRINTERNOTIFYOPTIONSTYPE* = PRINTER_NOTIFY_OPTIONS_TYPE

+  PRINTER_NOTIFY_OPTIONS* {.final, pure.} = object

+    Version*: DWORD

+    Flags*: DWORD

+    Count*: DWORD

+    pTypes*: PPRINTER_NOTIFY_OPTIONS_TYPE

+

+  TPRINTERNOTIFYOPTIONS* = PRINTER_NOTIFY_OPTIONS

+  PPRINTERNOTIFYOPTIONS* = ptr PRINTER_NOTIFY_OPTIONS

+  PRINTPROCESSOR_INFO_1* {.final, pure.} = object

+    pName*: LPTSTR

+

+  TPRINTPROCESSORINFO1* = PRINTPROCESSOR_INFO_1

+  PPRINTPROCESSORINFO1* = ptr PRINTPROCESSOR_INFO_1

+  PRIVILEGE_SET* {.final, pure.} = object

+    PrivilegeCount*: DWORD

+    Control*: DWORD

+    Privilege*: array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES]

+

+  LPPRIVILEGE_SET* = ptr PRIVILEGE_SET

+  PPRIVILEGE_SET* = ptr PRIVILEGE_SET

+  TPRIVILEGESET* = PRIVILEGE_SET

+  PROCESS_HEAPENTRY* {.final, pure.} = object

+    lpData*: PVOID

+    cbData*: DWORD

+    cbOverhead*: int8

+    iRegionIndex*: int8

+    wFlags*: int16

+    dwCommittedSize*: DWORD

+    dwUnCommittedSize*: DWORD

+    lpFirstBlock*: LPVOID

+    lpLastBlock*: LPVOID

+    hMem*: HANDLE

+

+  LPPROCESS_HEAP_ENTRY* = ptr PROCESS_HEAPENTRY

+  TPROCESSHEAPENTRY* = PROCESS_HEAPENTRY

+  PPROCESSHEAPENTRY* = ptr PROCESS_HEAPENTRY

+  PROCESS_INFORMATION* {.final, pure.} = object

+    hProcess*: HANDLE

+    hThread*: HANDLE

+    dwProcessId*: DWORD

+    dwThreadId*: DWORD

+

+  LPPROCESS_INFORMATION* = ptr PROCESS_INFORMATION

+  TPROCESSINFORMATION* = PROCESS_INFORMATION

+  PPROCESSINFORMATION* = ptr PROCESS_INFORMATION

+  LPFNPSPCALLBACK* = proc (para1: HWND, para2: WINUINT, para3: LPVOID): WINUINT{.

+      stdcall.}

+  TFNPSPCALLBACK* = LPFNPSPCALLBACK

+  PROPSHEETPAGE* {.final, pure.} = object

+    dwSize*: DWORD

+    dwFlags*: DWORD

+    hInstance*: HINST

+    pszIcon*: LPCTSTR

+    pszTitle*: LPCTSTR

+    pfnDlgProc*: DLGPROC

+    lParam*: LPARAM

+    pfnCallback*: LPFNPSPCALLBACK

+    pcRefParent*: ptr WINUINT

+

+  LPPROPSHEETPAGE* = ptr PROPSHEETPAGE

+  LPCPROPSHEETPAGE* = ptr PROPSHEETPAGE

+  TPROPSHEETPAGE* = PROPSHEETPAGE

+  PPROPSHEETPAGE* = ptr PROPSHEETPAGE

+  emptyrecord* {.final, pure.} = object

+  lpemptyrecord* = ptr emptyrecord

+  HPROPSHEETPAGE* = ptr emptyrecord

+  PROPSHEETHEADER* {.final, pure.} = object

+    dwSize*: DWORD

+    dwFlags*: DWORD

+    hwndParent*: HWND

+    hInstance*: HINST

+    pszIcon*: LPCTSTR

+    pszCaption*: LPCTSTR

+    nPages*: WINUINT

+    pStartPage*: LPCTSTR

+    phpage*: ptr HPROPSHEETPAGE

+    pfnCallback*: PFNPROPSHEETCALLBACK

+    pszbmWatermark*: LPCTSTR

+    hplWatermark*: HPALETTE

+    pszbmHeader*: cstring

+

+  LPPROPSHEETHEADER* = ptr PROPSHEETHEADER

+  LPCPROPSHEETHEADER* = ptr PROPSHEETHEADER

+  TPROPSHEETHEADER* = PROPSHEETHEADER

+  PPROPSHEETHEADER* = ptr PROPSHEETHEADER

+  # PropertySheet callbacks

+  LPFNADDPROPSHEETPAGE* = proc (para1: HPROPSHEETPAGE, para2: LPARAM): WINBOOL{.

+      stdcall.}

+  TFNADDPROPSHEETPAGE* = LPFNADDPROPSHEETPAGE

+  LPFNADDPROPSHEETPAGES* = proc (para1: LPVOID, para2: LPFNADDPROPSHEETPAGE,

+                                 para3: LPARAM): WINBOOL{.stdcall.}

+  TFNADDPROPSHEETPAGES* = LPFNADDPROPSHEETPAGES

+  PROTOCOL_INFO* {.final, pure.} = object

+    dwServiceFlags*: DWORD

+    iAddressFamily*: WINT

+    iMaxSockAddr*: WINT

+    iMinSockAddr*: WINT

+    iSocketType*: WINT

+    iProtocol*: WINT

+    dwMessageSize*: DWORD

+    lpProtocol*: LPTSTR

+

+  TPROTOCOLINFO* = PROTOCOL_INFO

+  PPROTOCOLINFO* = ptr PROTOCOL_INFO

+  PROVIDOR_INFO_1* {.final, pure.} = object

+    pName*: LPTSTR

+    pEnvironment*: LPTSTR

+    pDLLName*: LPTSTR

+

+  TPROVIDORINFO1* = PROVIDOR_INFO_1

+  PPROVIDORINFO1* = ptr PROVIDOR_INFO_1

+  PSHNOTIFY* {.final, pure.} = object

+    hdr*: NMHDR

+    lParam*: LPARAM

+

+  LPPSHNOTIFY* = ptr PSHNOTIFY

+  TPSHNOTIFY* = PSHNOTIFY

+  PPSHNOTIFY* = ptr PSHNOTIFY

+  PUNCTUATION* {.final, pure.} = object

+    iSize*: WINUINT

+    szPunctuation*: LPSTR

+

+  Tpunctuation* = PUNCTUATION

+  Ppunctuation* = ptr PUNCTUATION

+  TQUERY_SERVICE_CONFIG* {.final, pure.} = object

+    dwServiceType*: DWORD

+    dwStartType*: DWORD

+    dwErrorControl*: DWORD

+    lpBinaryPathName*: LPTSTR

+    lpLoadOrderGroup*: LPTSTR

+    dwTagId*: DWORD

+    lpDependencies*: LPTSTR

+    lpServiceStartName*: LPTSTR

+    lpDisplayName*: LPTSTR

+

+  LPQUERY_SERVICE_CONFIG* = ptr TQUERY_SERVICE_CONFIG

+  PQUERYSERVICECONFIG* = ptr TQUERY_SERVICE_CONFIG

+  TQUERY_SERVICE_LOCK_STATUS* {.final, pure.} = object

+    fIsLocked*: DWORD

+    lpLockOwner*: LPTSTR

+    dwLockDuration*: DWORD

+

+  LPQUERY_SERVICE_LOCK_STATUS* = ptr TQUERY_SERVICE_LOCK_STATUS

+  PQUERYSERVICELOCKSTATUS* = ptr TQUERY_SERVICE_LOCK_STATUS

+  RASAMB* {.final, pure.} = object

+    dwSize*: DWORD

+    dwError*: DWORD

+    szNetBiosError*: array[0..(NETBIOS_NAME_LEN + 1) - 1, TCHAR]

+    bLana*: int8

+

+  TRASAMB* = RASAMB

+  PRASAMB* = ptr RASAMB

+  RASCONN* {.final, pure.} = object

+    dwSize*: DWORD

+    hrasconn*: HRASCONN

+    szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR]

+    szDeviceType*: array[0..(RAS_MaxDeviceType + 1) - 1, char]

+    szDeviceName*: array[0..(RAS_MaxDeviceName + 1) - 1, char]

+

+  TRASCONN* = RASCONN

+  PRASCONN* = ptr RASCONN

+  RASCONNSTATUS* {.final, pure.} = object

+    dwSize*: DWORD

+    rasconnstate*: RASCONNSTATE

+    dwError*: DWORD

+    szDeviceType*: array[0..(RAS_MaxDeviceType + 1) - 1, TCHAR]

+    szDeviceName*: array[0..(RAS_MaxDeviceName + 1) - 1, TCHAR]

+

+  TRASCONNSTATUS* = RASCONNSTATUS

+  PRASCONNSTATUS* = ptr RASCONNSTATUS

+  RASDIALEXTENSIONS* {.final, pure.} = object

+    dwSize*: DWORD

+    dwfOptions*: DWORD

+    hwndParent*: HWND

+    reserved*: DWORD

+

+  TRASDIALEXTENSIONS* = RASDIALEXTENSIONS

+  PRASDIALEXTENSIONS* = ptr RASDIALEXTENSIONS

+  RASDIALPARAMS* {.final, pure.} = object

+    dwSize*: DWORD

+    szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR]

+    szPhoneNumber*: array[0..(RAS_MaxPhoneNumber + 1) - 1, TCHAR]

+    szCallbackNumber*: array[0..(RAS_MaxCallbackNumber + 1) - 1, TCHAR]

+    szUserName*: array[0..(UNLEN + 1) - 1, TCHAR]

+    szPassword*: array[0..(PWLEN + 1) - 1, TCHAR]

+    szDomain*: array[0..(DNLEN + 1) - 1, TCHAR]

+

+  TRASDIALPARAMS* = RASDIALPARAMS

+  PRASDIALPARAMS* = ptr RASDIALPARAMS

+  RASENTRYNAME* {.final, pure.} = object

+    dwSize*: DWORD

+    szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR]

+

+  TRASENTRYNAME* = RASENTRYNAME

+  PRASENTRYNAME* = ptr RASENTRYNAME

+  RASPPPIP* {.final, pure.} = object

+    dwSize*: DWORD

+    dwError*: DWORD

+    szIpAddress*: array[0..(RAS_MaxIpAddress + 1) - 1, TCHAR]

+

+  TRASPPPIP* = RASPPPIP

+  PRASPPPIP* = ptr RASPPPIP

+  RASPPPIPX* {.final, pure.} = object

+    dwSize*: DWORD

+    dwError*: DWORD

+    szIpxAddress*: array[0..(RAS_MaxIpxAddress + 1) - 1, TCHAR]

+

+  TRASPPPIPX* = RASPPPIPX

+  PRASPPPIPX* = ptr RASPPPIPX

+  RASPPPNBF* {.final, pure.} = object

+    dwSize*: DWORD

+    dwError*: DWORD

+    dwNetBiosError*: DWORD

+    szNetBiosError*: array[0..(NETBIOS_NAME_LEN + 1) - 1, TCHAR]

+    szWorkstationName*: array[0..(NETBIOS_NAME_LEN + 1) - 1, TCHAR]

+    bLana*: int8

+

+  TRASPPPNBF* = RASPPPNBF

+  PRASPPPNBF* = ptr RASPPPNBF

+  RASTERIZER_STATUS* {.final, pure.} = object

+    nSize*: SHORT

+    wFlags*: SHORT

+    nLanguageID*: SHORT

+

+  LPRASTERIZER_STATUS* = ptr RASTERIZER_STATUS

+  TRASTERIZERSTATUS* = RASTERIZER_STATUS

+  PRASTERIZERSTATUS* = ptr RASTERIZER_STATUS

+  REASSIGN_BLOCKS* {.final, pure.} = object

+    Reserved*: int16

+    Count*: int16

+    BlockNumber*: array[0..0, DWORD]

+

+  TREASSIGNBLOCKS* = REASSIGN_BLOCKS

+  PREASSIGNBLOCKS* = ptr REASSIGN_BLOCKS

+  REMOTE_NAME_INFO* {.final, pure.} = object

+    lpUniversalName*: LPTSTR

+    lpConnectionName*: LPTSTR

+    lpRemainingPath*: LPTSTR

+

+  TREMOTENAMEINFO* = REMOTE_NAME_INFO

+  PREMOTENAMEINFO* = ptr REMOTE_NAME_INFO

+

+  REPASTESPECIAL* {.final, pure.} = object

+    dwAspect*: DWORD

+    dwParam*: DWORD

+

+  Trepastespecial* = REPASTESPECIAL

+  Prepastespecial* = ptr REPASTESPECIAL

+  REQRESIZE* {.final, pure.} = object

+    nmhdr*: NMHDR

+    rc*: RECT

+

+  Treqresize* = REQRESIZE

+  Preqresize* = ptr REQRESIZE

+  RGNDATAHEADER* {.final, pure.} = object

+    dwSize*: DWORD

+    iType*: DWORD

+    nCount*: DWORD

+    nRgnSize*: DWORD

+    rcBound*: RECT

+

+  TRGNDATAHEADER* = RGNDATAHEADER

+  PRGNDATAHEADER* = ptr RGNDATAHEADER

+  RGNDATA* {.final, pure.} = object

+    rdh*: RGNDATAHEADER

+    Buffer*: array[0..0, char]

+

+  LPRGNDATA* = ptr RGNDATA

+  TRGNDATA* = RGNDATA

+  PRGNDATA* = ptr RGNDATA

+  SCROLLINFO* {.final, pure.} = object

+    cbSize*: WINUINT

+    fMask*: WINUINT

+    nMin*: int32

+    nMax*: int32

+    nPage*: WINUINT

+    nPos*: int32

+    nTrackPos*: int32

+

+  LPSCROLLINFO* = ptr SCROLLINFO

+  LPCSCROLLINFO* = ptr SCROLLINFO

+  TSCROLLINFO* = SCROLLINFO

+  PSCROLLINFO* = ptr SCROLLINFO

+  SECURITY_ATTRIBUTES* {.final, pure.} = object

+    nLength*: DWORD

+    lpSecurityDescriptor*: LPVOID

+    bInheritHandle*: WINBOOL

+

+  LPSECURITY_ATTRIBUTES* = ptr SECURITY_ATTRIBUTES

+  TSECURITYATTRIBUTES* = SECURITY_ATTRIBUTES

+  PSECURITYATTRIBUTES* = ptr SECURITY_ATTRIBUTES

+  SECURITY_INFORMATION* = DWORD

+  PSECURITY_INFORMATION* = ptr SECURITY_INFORMATION

+  TSECURITYINFORMATION* = SECURITY_INFORMATION

+  SELCHANGE* {.final, pure.} = object

+    nmhdr*: NMHDR

+    chrg*: CHARRANGE

+    seltyp*: int16

+

+  Tselchange* = SELCHANGE

+  Pselchange* = ptr SELCHANGE

+  SERIALKEYS* {.final, pure.} = object

+    cbSize*: DWORD

+    dwFlags*: DWORD

+    lpszActivePort*: LPSTR

+    lpszPort*: LPSTR

+    iBaudRate*: DWORD

+    iPortState*: DWORD

+

+  LPSERIALKEYS* = ptr SERIALKEYS

+  TSERIALKEYS* = SERIALKEYS

+  PSERIALKEYS* = ptr SERIALKEYS

+  SERVICE_TABLE_ENTRY* {.final, pure.} = object

+    lpServiceName*: LPTSTR

+    lpServiceProc*: LPSERVICE_MAIN_FUNCTION

+

+  LPSERVICE_TABLE_ENTRY* = ptr SERVICE_TABLE_ENTRY

+  TSERVICETABLEENTRY* = SERVICE_TABLE_ENTRY

+  PSERVICETABLEENTRY* = ptr SERVICE_TABLE_ENTRY

+  SERVICE_TYPE_VALUE_ABS* {.final, pure.} = object

+    dwNameSpace*: DWORD

+    dwValueType*: DWORD

+    dwValueSize*: DWORD

+    lpValueName*: LPTSTR

+    lpValue*: PVOID

+

+  TSERVICETYPEVALUEABS* = SERVICE_TYPE_VALUE_ABS

+  PSERVICETYPEVALUEABS* = ptr SERVICE_TYPE_VALUE_ABS

+  SERVICE_TYPE_INFO_ABS* {.final, pure.} = object

+    lpTypeName*: LPTSTR

+    dwValueCount*: DWORD

+    Values*: array[0..0, SERVICE_TYPE_VALUE_ABS]

+

+  TSERVICETYPEINFOABS* = SERVICE_TYPE_INFO_ABS

+  PSERVICETYPEINFOABS* = ptr SERVICE_TYPE_INFO_ABS

+  SESSION_BUFFER* {.final, pure.} = object

+    lsn*: UCHAR

+    state*: UCHAR

+    local_name*: array[0..(NCBNAMSZ) - 1, UCHAR]

+    remote_name*: array[0..(NCBNAMSZ) - 1, UCHAR]

+    rcvs_outstanding*: UCHAR

+    sends_outstanding*: UCHAR

+

+  TSESSIONBUFFER* = SESSION_BUFFER

+  PSESSIONBUFFER* = ptr SESSION_BUFFER

+  SESSION_HEADER* {.final, pure.} = object

+    sess_name*: UCHAR

+    num_sess*: UCHAR

+    rcv_dg_outstanding*: UCHAR

+    rcv_any_outstanding*: UCHAR

+

+  TSESSIONHEADER* = SESSION_HEADER

+  PSESSIONHEADER* = ptr SESSION_HEADER

+  SET_PARTITION_INFORMATION* {.final, pure.} = object

+    PartitionType*: int8

+

+  TSETPARTITIONINFORMATION* = SET_PARTITION_INFORMATION

+  PSETPARTITIONINFORMATION* = ptr SET_PARTITION_INFORMATION

+  SHCONTF* = enum

+    SHCONTF_FOLDERS = 32, SHCONTF_NONFOLDERS = 64, SHCONTF_INCLUDEHIDDEN = 128

+  TSHCONTF* = SHCONTF

+  SHFILEINFO* {.final, pure.} = object

+    hIcon*: HICON

+    iIcon*: int32

+    dwAttributes*: DWORD

+    szDisplayName*: array[0..(MAX_PATH) - 1, char]

+    szTypeName*: array[0..79, char]

+

+  TSHFILEINFO* = SHFILEINFO

+  PSHFILEINFO* = ptr SHFILEINFO

+  FILEOP_FLAGS* = int16

+  TFILEOPFLAGS* = FILEOP_FLAGS

+  PFILEOPFLAGS* = ptr FILEOP_FLAGS

+  SHFILEOPSTRUCT* {.final, pure.} = object

+    hwnd*: HWND

+    wFunc*: WINUINT

+    pFrom*: LPCSTR

+    pTo*: LPCSTR

+    fFlags*: FILEOP_FLAGS

+    fAnyOperationsAborted*: WINBOOL

+    hNameMappings*: LPVOID

+    lpszProgressTitle*: LPCSTR

+

+  LPSHFILEOPSTRUCT* = ptr SHFILEOPSTRUCT

+  TSHFILEOPSTRUCT* = SHFILEOPSTRUCT

+  PSHFILEOPSTRUCT* = ptr SHFILEOPSTRUCT

+  SHGNO* = enum

+    SHGDN_NORMAL = 0, SHGDN_INFOLDER = 1, SHGDN_FORPARSING = 0x00008000

+  TSHGDN* = SHGNO

+  SHNAMEMAPPING* {.final, pure.} = object

+    pszOldPath*: LPSTR

+    pszNewPath*: LPSTR

+    cchOldPath*: int32

+    cchNewPath*: int32

+

+  LPSHNAMEMAPPING* = ptr SHNAMEMAPPING

+  TSHNAMEMAPPING* = SHNAMEMAPPING

+  PSHNAMEMAPPING* = ptr SHNAMEMAPPING

+  SID_AND_ATTRIBUTES* {.final, pure.} = object

+    Sid*: PSID

+    Attributes*: DWORD

+

+  TSIDANDATTRIBUTES* = SID_AND_ATTRIBUTES

+  PSIDANDATTRIBUTES* = ptr SID_AND_ATTRIBUTES

+  SID_AND_ATTRIBUTES_ARRAY* = array[0..(ANYSIZE_ARRAY) - 1, SID_AND_ATTRIBUTES]

+  PSID_AND_ATTRIBUTES_ARRAY* = ptr SID_AND_ATTRIBUTES_ARRAY

+  TSIDANDATTRIBUTESARRAY* = SID_AND_ATTRIBUTES_ARRAY

+  SINGLE_LIST_ENTRY* {.final, pure.} = object

+    Next*: ptr SINGLE_LIST_ENTRY

+

+  TSINGLELISTENTRY* = SINGLE_LIST_ENTRY

+  PSINGLELISTENTRY* = ptr SINGLE_LIST_ENTRY

+  SOUNDSENTRY* {.final, pure.} = object

+    cbSize*: WINUINT

+    dwFlags*: DWORD

+    iFSTextEffect*: DWORD

+    iFSTextEffectMSec*: DWORD

+    iFSTextEffectColorBits*: DWORD

+    iFSGrafEffect*: DWORD

+    iFSGrafEffectMSec*: DWORD

+    iFSGrafEffectColor*: DWORD

+    iWindowsEffect*: DWORD

+    iWindowsEffectMSec*: DWORD

+    lpszWindowsEffectDLL*: LPTSTR

+    iWindowsEffectOrdinal*: DWORD

+

+  LPSOUNDSENTRY* = ptr SOUNDSENTRY

+  TSOUNDSENTRY* = SOUNDSENTRY

+  PSOUNDSENTRY* = ptr SOUNDSENTRY

+  STARTUPINFO* {.final, pure.} = object

+    cb*: DWORD

+    lpReserved*: LPTSTR

+    lpDesktop*: LPTSTR

+    lpTitle*: LPTSTR

+    dwX*: DWORD

+    dwY*: DWORD

+    dwXSize*: DWORD

+    dwYSize*: DWORD

+    dwXCountChars*: DWORD

+    dwYCountChars*: DWORD

+    dwFillAttribute*: DWORD

+    dwFlags*: DWORD

+    wShowWindow*: int16

+    cbReserved2*: int16

+    lpReserved2*: LPBYTE

+    hStdInput*: HANDLE

+    hStdOutput*: HANDLE

+    hStdError*: HANDLE

+

+  LPSTARTUPINFO* = ptr STARTUPINFO

+  TSTARTUPINFO* = STARTUPINFO

+  PSTARTUPINFO* = ptr STARTUPINFO

+  STICKYKEYS* {.final, pure.} = object

+    cbSize*: DWORD

+    dwFlags*: DWORD

+

+  LPSTICKYKEYS* = ptr STICKYKEYS

+  TSTICKYKEYS* = STICKYKEYS

+  PSTICKYKEYS* = ptr STICKYKEYS

+  STRRET* {.final, pure.} = object

+    uType*: WINUINT

+    cStr*: array[0..(MAX_PATH) - 1, char]

+

+  LPSTRRET* = ptr STRRET

+  TSTRRET* = STRRET

+  PSTRRET* = ptr STRRET

+  STYLEBUF* {.final, pure.} = object

+    dwStyle*: DWORD

+    szDescription*: array[0..31, char]

+

+  LPSTYLEBUF* = ptr STYLEBUF

+  TSTYLEBUF* = STYLEBUF

+  PSTYLEBUF* = ptr STYLEBUF

+  STYLESTRUCT* {.final, pure.} = object

+    styleOld*: DWORD

+    styleNew*: DWORD

+

+  LPSTYLESTRUCT* = ptr STYLESTRUCT

+  TSTYLESTRUCT* = STYLESTRUCT

+  PSTYLESTRUCT* = ptr STYLESTRUCT

+  SYSTEM_AUDIT_ACE* {.final, pure.} = object

+    Header*: ACE_HEADER

+    Mask*: ACCESS_MASK

+    SidStart*: DWORD

+

+  TSYSTEMAUDITACE* = SYSTEM_AUDIT_ACE

+  PSYSTEMAUDITACE* = ptr SYSTEM_AUDIT_ACE

+  SYSTEM_INFO* {.final, pure.} = object

+    dwOemId*: DWORD

+    dwPageSize*: DWORD

+    lpMinimumApplicationAddress*: LPVOID

+    lpMaximumApplicationAddress*: LPVOID

+    dwActiveProcessorMask*: DWORD_PTR

+    dwNumberOfProcessors*: DWORD

+    dwProcessorType*: DWORD

+    dwAllocationGranularity*: DWORD

+    wProcessorLevel*: int16

+    wProcessorRevision*: int16

+

+  LPSYSTEM_INFO* = ptr SYSTEM_INFO

+  TSYSTEMINFO* = SYSTEM_INFO

+  PSYSTEMINFO* = ptr SYSTEM_INFO

+  SYSTEM_POWER_STATUS* {.final, pure.} = object

+    ACLineStatus*: int8

+    BatteryFlag*: int8

+    BatteryLifePercent*: int8

+    Reserved1*: int8

+    BatteryLifeTime*: DWORD

+    BatteryFullLifeTime*: DWORD

+

+  TSYSTEMPOWERSTATUS* = SYSTEM_POWER_STATUS

+  PSYSTEMPOWERSTATUS* = ptr SYSTEM_POWER_STATUS

+  LPSYSTEM_POWER_STATUS* = ptr emptyrecord

+  TAPE_ERASE* {.final, pure.} = object

+    `type`*: ULONG

+

+  TTAPEERASE* = TAPE_ERASE

+  PTAPEERASE* = ptr TAPE_ERASE

+  TAPE_GET_DRIVE_PARAMETERS* {.final, pure.} = object

+    ECC*: bool

+    Compression*: bool

+    DataPadding*: bool

+    ReportSetmarks*: bool

+    DefaultBlockSize*: ULONG

+    MaximumBlockSize*: ULONG

+    MinimumBlockSize*: ULONG

+    MaximumPartitionCount*: ULONG

+    FeaturesLow*: ULONG

+    FeaturesHigh*: ULONG

+    EOTWarningZoneSize*: ULONG

+

+  TTAPEGETDRIVEPARAMETERS* = TAPE_GET_DRIVE_PARAMETERS

+  PTAPEGETDRIVEPARAMETERS* = ptr TAPE_GET_DRIVE_PARAMETERS

+  TAPE_GET_MEDIA_PARAMETERS* {.final, pure.} = object

+    Capacity*: LARGE_INTEGER

+    Remaining*: LARGE_INTEGER

+    BlockSize*: DWORD

+    PartitionCount*: DWORD

+    WriteProtected*: bool

+

+  TTAPEGETMEDIAPARAMETERS* = TAPE_GET_MEDIA_PARAMETERS

+  PTAPEGETMEDIAPARAMETERS* = ptr TAPE_GET_MEDIA_PARAMETERS

+  TAPE_GET_POSITION* {.final, pure.} = object

+    `type`*: ULONG

+    Partition*: ULONG

+    OffsetLow*: ULONG

+    OffsetHigh*: ULONG

+

+  TTAPEGETPOSITION* = TAPE_GET_POSITION

+  PTAPEGETPOSITION* = ptr TAPE_GET_POSITION

+  TAPE_PREPARE* {.final, pure.} = object

+    Operation*: ULONG

+

+  TTAPEPREPARE* = TAPE_PREPARE

+  PTAPEPREPARE* = ptr TAPE_PREPARE

+  TAPE_SET_DRIVE_PARAMETERS* {.final, pure.} = object

+    ECC*: bool

+    Compression*: bool

+    DataPadding*: bool

+    ReportSetmarks*: bool

+    EOTWarningZoneSize*: ULONG

+

+  TTAPESETDRIVEPARAMETERS* = TAPE_SET_DRIVE_PARAMETERS

+  PTAPESETDRIVEPARAMETERS* = ptr TAPE_SET_DRIVE_PARAMETERS

+  TAPE_SET_MEDIA_PARAMETERS* {.final, pure.} = object

+    BlockSize*: ULONG

+

+  TTAPESETMEDIAPARAMETERS* = TAPE_SET_MEDIA_PARAMETERS

+  PTAPESETMEDIAPARAMETERS* = ptr TAPE_SET_MEDIA_PARAMETERS

+  TAPE_SET_POSITION* {.final, pure.} = object

+    `Method`*: ULONG

+    Partition*: ULONG

+    OffsetLow*: ULONG

+    OffsetHigh*: ULONG

+

+  TTAPESETPOSITION* = TAPE_SET_POSITION

+  PTAPESETPOSITION* = ptr TAPE_SET_POSITION

+  TAPE_WRITE_MARKS* {.final, pure.} = object

+    `type`*: ULONG

+    Count*: ULONG

+

+  TTAPEWRITEMARKS* = TAPE_WRITE_MARKS

+  PTAPEWRITEMARKS* = ptr TAPE_WRITE_MARKS

+  TTBADDBITMAP* {.final, pure.} = object

+    hInst*: HINST

+    nID*: WINUINT

+

+  LPTBADDBITMAP* = ptr TTBADDBITMAP

+  PTBADDBITMAP* = ptr TTBADDBITMAP

+  TBBUTTON* {.final, pure.} = object

+    iBitmap*: int32

+    idCommand*: int32

+    fsState*: int8

+    fsStyle*: int8

+    dwData*: DWORD

+    iString*: int32

+

+  LPTBBUTTON* = ptr TBBUTTON

+  LPCTBBUTTON* = ptr TBBUTTON

+  TTBBUTTON* = TBBUTTON

+  PTBBUTTON* = ptr TBBUTTON

+  TBNOTIFY* {.final, pure.} = object

+    hdr*: NMHDR

+    iItem*: int32

+    tbButton*: TBBUTTON

+    cchText*: int32

+    pszText*: LPTSTR

+

+  LPTBNOTIFY* = ptr TBNOTIFY

+  TTBNOTIFY* = TBNOTIFY

+  PTBNOTIFY* = ptr TBNOTIFY

+  TBSAVEPARAMS* {.final, pure.} = object

+    hkr*: HKEY

+    pszSubKey*: LPCTSTR

+    pszValueName*: LPCTSTR

+

+  TTBSAVEPARAMS* = TBSAVEPARAMS

+  PTBSAVEPARAMS* = ptr TBSAVEPARAMS

+  TC_HITTESTINFO* {.final, pure.} = object

+    pt*: POINT

+    flags*: WINUINT

+

+  TTCHITTESTINFO* = TC_HITTESTINFO

+  PTCHITTESTINFO* = ptr TC_HITTESTINFO

+  TC_ITEM* {.final, pure.} = object

+    mask*: WINUINT

+    lpReserved1*: WINUINT

+    lpReserved2*: WINUINT

+    pszText*: LPTSTR

+    cchTextMax*: int32

+    iImage*: int32

+    lParam*: LPARAM

+

+  TTCITEM* = TC_ITEM

+  PTCITEM* = ptr TC_ITEM

+  TC_ITEMHEADER* {.final, pure.} = object

+    mask*: WINUINT

+    lpReserved1*: WINUINT

+    lpReserved2*: WINUINT

+    pszText*: LPTSTR

+    cchTextMax*: int32

+    iImage*: int32

+

+  TTCITEMHEADER* = TC_ITEMHEADER

+  PTCITEMHEADER* = ptr TC_ITEMHEADER

+  TC_KEYDOWN* {.final, pure.} = object

+    hdr*: NMHDR

+    wVKey*: int16

+    flags*: WINUINT

+

+  TTCKEYDOWN* = TC_KEYDOWN

+  PTCKEYDOWN* = ptr TC_KEYDOWN

+  TEXTRANGE* {.final, pure.} = object

+    chrg*: CHARRANGE

+    lpstrText*: LPSTR

+

+  Ttextrange* = TEXTRANGE

+  Ptextrange* = ptr TEXTRANGE

+  TIME_ZONE_INFORMATION* {.final, pure.} = object

+    Bias*: LONG

+    StandardName*: array[0..31, WCHAR]

+    StandardDate*: SYSTEMTIME

+    StandardBias*: LONG

+    DaylightName*: array[0..31, WCHAR]

+    DaylightDate*: SYSTEMTIME

+    DaylightBias*: LONG

+

+  LPTIME_ZONE_INFORMATION* = ptr TIME_ZONE_INFORMATION

+  TTIMEZONEINFORMATION* = TIME_ZONE_INFORMATION

+  PTIMEZONEINFORMATION* = ptr TIME_ZONE_INFORMATION

+  TOGGLEKEYS* {.final, pure.} = object

+    cbSize*: DWORD

+    dwFlags*: DWORD

+

+  TTOGGLEKEYS* = TOGGLEKEYS

+  PTOGGLEKEYS* = ptr TOGGLEKEYS

+  TTOKEN_SOURCE* {.final, pure.} = object

+    SourceName*: array[0..7, char]

+    SourceIdentifier*: LUID

+

+  PTOKENSOURCE* = ptr TTOKEN_SOURCE

+  TOKEN_CONTROL* {.final, pure.} = object

+    TokenId*: LUID

+    AuthenticationId*: LUID

+    ModifiedId*: LUID

+    TokenSource*: TTOKEN_SOURCE

+

+  TTOKENCONTROL* = TOKEN_CONTROL

+  PTOKENCONTROL* = ptr TOKEN_CONTROL

+  TTOKEN_DEFAULT_DACL* {.final, pure.} = object

+    DefaultDacl*: PACL

+

+  PTOKENDEFAULTDACL* = ptr TTOKEN_DEFAULT_DACL

+  TTOKEN_GROUPS* {.final, pure.} = object

+    GroupCount*: DWORD

+    Groups*: array[0..(ANYSIZE_ARRAY) - 1, SID_AND_ATTRIBUTES]

+

+  LPTOKEN_GROUPS* = ptr TTOKEN_GROUPS

+  PTOKENGROUPS* = ptr TTOKEN_GROUPS

+  TTOKEN_OWNER* {.final, pure.} = object

+    Owner*: PSID

+

+  PTOKENOWNER* = ptr TTOKEN_OWNER

+  TTOKEN_PRIMARY_GROUP* {.final, pure.} = object

+    PrimaryGroup*: PSID

+

+  PTOKENPRIMARYGROUP* = ptr TTOKEN_PRIMARY_GROUP

+  TTOKEN_PRIVILEGES* {.final, pure.} = object

+    PrivilegeCount*: DWORD

+    Privileges*: array[0..(ANYSIZE_ARRAY) - 1, LUID_AND_ATTRIBUTES]

+

+  PTOKEN_PRIVILEGES* = ptr TTOKEN_PRIVILEGES

+  LPTOKEN_PRIVILEGES* = ptr TTOKEN_PRIVILEGES

+  TTOKEN_STATISTICS* {.final, pure.} = object

+    TokenId*: LUID

+    AuthenticationId*: LUID

+    ExpirationTime*: LARGE_INTEGER

+    TokenType*: TTOKEN_TYPE

+    ImpersonationLevel*: SECURITY_IMPERSONATION_LEVEL

+    DynamicCharged*: DWORD

+    DynamicAvailable*: DWORD

+    GroupCount*: DWORD

+    PrivilegeCount*: DWORD

+    ModifiedId*: LUID

+

+  PTOKENSTATISTICS* = ptr TTOKEN_STATISTICS

+  TTOKEN_USER* {.final, pure.} = object

+    User*: SID_AND_ATTRIBUTES

+

+  PTOKENUSER* = ptr TTOKEN_USER

+  TOOLINFO* {.final, pure.} = object

+    cbSize*: WINUINT

+    uFlags*: WINUINT

+    hwnd*: HWND

+    uId*: WINUINT

+    rect*: RECT

+    hinst*: HINST

+    lpszText*: LPTSTR

+

+  LPTOOLINFO* = ptr TOOLINFO

+  TTOOLINFO* = TOOLINFO

+  PTOOLINFO* = ptr TOOLINFO

+  TOOLTIPTEXT* {.final, pure.} = object

+    hdr*: NMHDR

+    lpszText*: LPTSTR

+    szText*: array[0..79, char]

+    hinst*: HINST

+    uFlags*: WINUINT

+

+  LPTOOLTIPTEXT* = ptr TOOLTIPTEXT

+  TTOOLTIPTEXT* = TOOLTIPTEXT

+  PTOOLTIPTEXT* = ptr TOOLTIPTEXT

+  TPMPARAMS* {.final, pure.} = object

+    cbSize*: WINUINT

+    rcExclude*: RECT

+

+  LPTPMPARAMS* = ptr TPMPARAMS

+  TTPMPARAMS* = TPMPARAMS

+  PTPMPARAMS* = ptr TPMPARAMS

+  TRANSMIT_FILE_BUFFERS* {.final, pure.} = object

+    Head*: PVOID

+    HeadLength*: DWORD

+    Tail*: PVOID

+    TailLength*: DWORD

+

+  TTRANSMITFILEBUFFERS* = TRANSMIT_FILE_BUFFERS

+  PTRANSMITFILEBUFFERS* = ptr TRANSMIT_FILE_BUFFERS

+  TTHITTESTINFO* {.final, pure.} = object

+    hwnd*: HWND

+    pt*: POINT

+    ti*: TOOLINFO

+

+  LPHITTESTINFO* = ptr TTHITTESTINFO

+  TTTHITTESTINFO* = TTHITTESTINFO

+  PTTHITTESTINFO* = ptr TTHITTESTINFO

+  TTPOLYCURVE* {.final, pure.} = object

+    wType*: int16

+    cpfx*: int16

+    apfx*: array[0..0, POINTFX]

+

+  LPTTPOLYCURVE* = ptr TTPOLYCURVE

+  TTTPOLYCURVE* = TTPOLYCURVE

+  PTTPOLYCURVE* = ptr TTPOLYCURVE

+  TTPOLYGONHEADER* {.final, pure.} = object

+    cb*: DWORD

+    dwType*: DWORD

+    pfxStart*: POINTFX

+

+  LPTTPOLYGONHEADER* = ptr TTPOLYGONHEADER

+  TTTPOLYGONHEADER* = TTPOLYGONHEADER

+  PTTPOLYGONHEADER* = ptr TTPOLYGONHEADER

+  TV_DISPINFO* {.final, pure.} = object

+    hdr*: NMHDR

+    item*: TV_ITEM

+

+  TTVDISPINFO* = TV_DISPINFO

+  PTVDISPINFO* = ptr TV_DISPINFO

+  TV_HITTESTINFO* {.final, pure.} = object

+    pt*: POINT

+    flags*: WINUINT

+    hItem*: HTREEITEM

+

+  LPTV_HITTESTINFO* = ptr TV_HITTESTINFO

+  TTVHITTESTINFO* = TV_HITTESTINFO

+  PTVHITTESTINFO* = ptr TV_HITTESTINFO

+  TV_INSERTSTRUCT* {.final, pure.} = object

+    hParent*: HTREEITEM

+    hInsertAfter*: HTREEITEM

+    item*: TV_ITEM

+

+  LPTV_INSERTSTRUCT* = ptr TV_INSERTSTRUCT

+  TTVINSERTSTRUCT* = TV_INSERTSTRUCT

+  PTVINSERTSTRUCT* = ptr TV_INSERTSTRUCT

+  TV_KEYDOWN* {.final, pure.} = object

+    hdr*: NMHDR

+    wVKey*: int16

+    flags*: WINUINT

+

+  TTVKEYDOWN* = TV_KEYDOWN

+  PTVKEYDOWN* = ptr TV_KEYDOWN

+  TV_SORTCB* {.final, pure.} = object

+    hParent*: HTREEITEM

+    lpfnCompare*: PFNTVCOMPARE

+    lParam*: LPARAM

+

+  LPTV_SORTCB* = ptr TV_SORTCB

+  TTVSORTCB* = TV_SORTCB

+  PTVSORTCB* = ptr TV_SORTCB

+  UDACCEL* {.final, pure.} = object

+    nSec*: WINUINT

+    nInc*: WINUINT

+

+  TUDACCEL* = UDACCEL

+  PUDACCEL* = ptr UDACCEL

+  UNIVERSAL_NAME_INFO* {.final, pure.} = object

+    lpUniversalName*: LPTSTR

+

+  TUNIVERSALNAMEINFO* = UNIVERSAL_NAME_INFO

+  PUNIVERSALNAMEINFO* = ptr UNIVERSAL_NAME_INFO

+  USEROBJECTFLAGS* {.final, pure.} = object

+    fInherit*: WINBOOL

+    fReserved*: WINBOOL

+    dwFlags*: DWORD

+

+  TUSEROBJECTFLAGS* = USEROBJECTFLAGS

+  PUSEROBJECTFLAGS* = ptr USEROBJECTFLAGS

+  VALENT* {.final, pure.} = object

+    ve_valuename*: LPTSTR

+    ve_valuelen*: DWORD

+    ve_valueptr*: DWORD

+    ve_type*: DWORD

+

+  TVALENT* = VALENT

+  PVALENT* = ptr VALENT

+  value_ent* = VALENT

+  Tvalue_ent* = VALENT

+  Pvalue_ent* = ptr VALENT

+  VERIFY_INFORMATION* {.final, pure.} = object

+    StartingOffset*: LARGE_INTEGER

+    len*: DWORD

+

+  TVERIFYINFORMATION* = VERIFY_INFORMATION

+  PVERIFYINFORMATION* = ptr VERIFY_INFORMATION

+  VS_FIXEDFILEINFO* {.final, pure.} = object

+    dwSignature*: DWORD

+    dwStrucVersion*: DWORD

+    dwFileVersionMS*: DWORD

+    dwFileVersionLS*: DWORD

+    dwProductVersionMS*: DWORD

+    dwProductVersionLS*: DWORD

+    dwFileFlagsMask*: DWORD

+    dwFileFlags*: DWORD

+    dwFileOS*: DWORD

+    dwFileType*: DWORD

+    dwFileSubtype*: DWORD

+    dwFileDateMS*: DWORD

+    dwFileDateLS*: DWORD

+

+  TVSFIXEDFILEINFO* = VS_FIXEDFILEINFO

+  PVSFIXEDFILEINFO* = ptr VS_FIXEDFILEINFO

+  WIN32_FIND_DATA* {.final, pure.} = object

+    dwFileAttributes*: DWORD

+    ftCreationTime*: FILETIME

+    ftLastAccessTime*: FILETIME

+    ftLastWriteTime*: FILETIME

+    nFileSizeHigh*: DWORD

+    nFileSizeLow*: DWORD

+    dwReserved0*: DWORD

+    dwReserved1*: DWORD

+    cFileName*: array[0..(MAX_PATH) - 1, TCHAR]

+    cAlternateFileName*: array[0..13, TCHAR]

+

+  LPWIN32_FIND_DATA* = ptr WIN32_FIND_DATA

+  PWIN32_FIND_DATA* = ptr WIN32_FIND_DATA

+  TWIN32FINDDATA* = WIN32_FIND_DATA

+  TWIN32FINDDATAA* = WIN32_FIND_DATA

+  WIN32_FIND_DATAW* {.final, pure.} = object

+    dwFileAttributes*: DWORD

+    ftCreationTime*: FILETIME

+    ftLastAccessTime*: FILETIME

+    ftLastWriteTime*: FILETIME

+    nFileSizeHigh*: DWORD

+    nFileSizeLow*: DWORD

+    dwReserved0*: DWORD

+    dwReserved1*: DWORD

+    cFileName*: array[0..(MAX_PATH) - 1, WCHAR]

+    cAlternateFileName*: array[0..13, WCHAR]

+

+  LPWIN32_FIND_DATAW* = ptr WIN32_FIND_DATAW

+  PWIN32_FIND_DATAW* = ptr WIN32_FIND_DATAW

+  TWIN32FINDDATAW* = WIN32_FIND_DATAW

+  WIN32_STREAM_ID* {.final, pure.} = object

+    dwStreamId*: DWORD

+    dwStreamAttributes*: DWORD

+    Size*: LARGE_INTEGER

+    dwStreamNameSize*: DWORD

+    cStreamName*: ptr WCHAR

+

+  TWIN32STREAMID* = WIN32_STREAM_ID

+  PWIN32STREAMID* = ptr WIN32_STREAM_ID

+  WINDOWPLACEMENT* {.final, pure.} = object

+    len*: WINUINT

+    flags*: WINUINT

+    showCmd*: WINUINT

+    ptMinPosition*: POINT

+    ptMaxPosition*: POINT

+    rcNormalPosition*: RECT

+

+  TWINDOWPLACEMENT* = WINDOWPLACEMENT

+  PWINDOWPLACEMENT* = ptr WINDOWPLACEMENT

+  WNDCLASS* {.final, pure.} = object

+    style*: WINUINT

+    lpfnWndProc*: WNDPROC

+    cbClsExtra*: int32

+    cbWndExtra*: int32

+    hInstance*: HANDLE

+    hIcon*: HICON

+    hCursor*: HCURSOR

+    hbrBackground*: HBRUSH

+    lpszMenuName*: LPCTSTR

+    lpszClassName*: LPCTSTR

+

+  LPWNDCLASS* = ptr WNDCLASS

+  TWNDCLASS* = WNDCLASS

+  TWNDCLASSA* = WNDCLASS

+  PWNDCLASS* = ptr WNDCLASS

+  WNDCLASSW* {.final, pure.} = object

+    style*: WINUINT

+    lpfnWndProc*: WNDPROC

+    cbClsExtra*: int32

+    cbWndExtra*: int32

+    hInstance*: HANDLE

+    hIcon*: HICON

+    hCursor*: HCURSOR

+    hbrBackground*: HBRUSH

+    lpszMenuName*: LPCWSTR

+    lpszClassName*: LPCWSTR

+

+  LPWNDCLASSW* = ptr WNDCLASSW

+  TWNDCLASSW* = WNDCLASSW

+  PWNDCLASSW* = ptr WNDCLASSW

+  WNDCLASSEX* {.final, pure.} = object

+    cbSize*: WINUINT

+    style*: WINUINT

+    lpfnWndProc*: WNDPROC

+    cbClsExtra*: int32

+    cbWndExtra*: int32

+    hInstance*: HANDLE

+    hIcon*: HICON

+    hCursor*: HCURSOR

+    hbrBackground*: HBRUSH

+    lpszMenuName*: LPCTSTR

+    lpszClassName*: LPCTSTR

+    hIconSm*: HANDLE

+

+  LPWNDCLASSEX* = ptr WNDCLASSEX

+  TWNDCLASSEX* = WNDCLASSEX

+  TWNDCLASSEXA* = WNDCLASSEX

+  PWNDCLASSEX* = ptr WNDCLASSEX

+  WNDCLASSEXW* {.final, pure.} = object

+    cbSize*: WINUINT

+    style*: WINUINT

+    lpfnWndProc*: WNDPROC

+    cbClsExtra*: int32

+    cbWndExtra*: int32

+    hInstance*: HANDLE

+    hIcon*: HICON

+    hCursor*: HCURSOR

+    hbrBackground*: HBRUSH

+    lpszMenuName*: LPCWSTR

+    lpszClassName*: LPCWSTR

+    hIconSm*: HANDLE

+

+  LPWNDCLASSEXW* = ptr WNDCLASSEXW

+  TWNDCLASSEXW* = WNDCLASSEXW

+  PWNDCLASSEXW* = ptr WNDCLASSEXW

+  CONNECTDLGSTRUCT* {.final, pure.} = object

+    cbStructure*: DWORD

+    hwndOwner*: HWND

+    lpConnRes*: LPNETRESOURCE

+    dwFlags*: DWORD

+    dwDevNum*: DWORD

+

+  LPCONNECTDLGSTRUCT* = ptr CONNECTDLGSTRUCT

+  TCONNECTDLGSTRUCT* = CONNECTDLGSTRUCT

+  PCONNECTDLGSTRUCT* = ptr CONNECTDLGSTRUCT

+  DISCDLGSTRUCT* {.final, pure.} = object

+    cbStructure*: DWORD

+    hwndOwner*: HWND

+    lpLocalName*: LPTSTR

+    lpRemoteName*: LPTSTR

+    dwFlags*: DWORD

+

+  LPDISCDLGSTRUCT* = ptr DISCDLGSTRUCT

+  TDISCDLGSTRUCT* = DISCDLGSTRUCT

+  TDISCDLGSTRUCTA* = DISCDLGSTRUCT

+  PDISCDLGSTRUCT* = ptr DISCDLGSTRUCT

+  NETINFOSTRUCT* {.final, pure.} = object

+    cbStructure*: DWORD

+    dwProviderVersion*: DWORD

+    dwStatus*: DWORD

+    dwCharacteristics*: DWORD

+    dwHandle*: DWORD

+    wNetType*: int16

+    dwPrinters*: DWORD

+    dwDrives*: DWORD

+

+  LPNETINFOSTRUCT* = ptr NETINFOSTRUCT

+  TNETINFOSTRUCT* = NETINFOSTRUCT

+  PNETINFOSTRUCT* = ptr NETINFOSTRUCT

+  NETCONNECTINFOSTRUCT* {.final, pure.} = object

+    cbStructure*: DWORD

+    dwFlags*: DWORD

+    dwSpeed*: DWORD

+    dwDelay*: DWORD

+    dwOptDataSize*: DWORD

+

+  LPNETCONNECTINFOSTRUCT* = ptr NETCONNECTINFOSTRUCT

+  TNETCONNECTINFOSTRUCT* = NETCONNECTINFOSTRUCT

+  PNETCONNECTINFOSTRUCT* = ptr NETCONNECTINFOSTRUCT

+  ENUMMETAFILEPROC* = proc (para1: HDC, para2: HANDLETABLE, para3: METARECORD,

+                            para4: int32, para5: LPARAM): int32{.stdcall.}

+  ENHMETAFILEPROC* = proc (para1: HDC, para2: HANDLETABLE, para3: TENHMETARECORD,

+                           para4: int32, para5: LPARAM): int32{.stdcall.}

+  ENUMFONTSPROC* = proc (para1: LPLOGFONT, para2: LPTEXTMETRIC, para3: DWORD,

+                         para4: LPARAM): int32{.stdcall.}

+  FONTENUMPROC* = proc (para1: var ENUMLOGFONT, para2: var NEWTEXTMETRIC,

+                        para3: int32, para4: LPARAM): int32{.stdcall.}

+  FONTENUMEXPROC* = proc (para1: var ENUMLOGFONTEX, para2: var NEWTEXTMETRICEX,

+                          para3: int32, para4: LPARAM): int32{.stdcall.}

+  LPOVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD,

+      para3: LPOVERLAPPED){.stdcall.}

+  # Structures for the extensions to OpenGL

+  POINTFLOAT* {.final, pure.} = object

+    x*: float32

+    y*: float32

+

+  TPOINTFLOAT* = POINTFLOAT

+  PPOINTFLOAT* = ptr POINTFLOAT

+  GLYPHMETRICSFLOAT* {.final, pure.} = object

+    gmfBlackBoxX*: float32

+    gmfBlackBoxY*: float32

+    gmfptGlyphOrigin*: POINTFLOAT

+    gmfCellIncX*: float32

+    gmfCellIncY*: float32

+

+  LPGLYPHMETRICSFLOAT* = ptr GLYPHMETRICSFLOAT

+  TGLYPHMETRICSFLOAT* = GLYPHMETRICSFLOAT

+  PGLYPHMETRICSFLOAT* = ptr GLYPHMETRICSFLOAT

+  LAYERPLANEDESCRIPTOR* {.final, pure.} = object

+    nSize*: int16

+    nVersion*: int16

+    dwFlags*: DWORD

+    iPixelType*: int8

+    cColorBits*: int8

+    cRedBits*: int8

+    cRedShift*: int8

+    cGreenBits*: int8

+    cGreenShift*: int8

+    cBlueBits*: int8

+    cBlueShift*: int8

+    cAlphaBits*: int8

+    cAlphaShift*: int8

+    cAccumBits*: int8

+    cAccumRedBits*: int8

+    cAccumGreenBits*: int8

+    cAccumBlueBits*: int8

+    cAccumAlphaBits*: int8

+    cDepthBits*: int8

+    cStencilBits*: int8

+    cAuxBuffers*: int8

+    iLayerPlane*: int8

+    bReserved*: int8

+    crTransparent*: COLORREF

+

+  LPLAYERPLANEDESCRIPTOR* = ptr LAYERPLANEDESCRIPTOR

+  TLAYERPLANEDESCRIPTOR* = LAYERPLANEDESCRIPTOR

+  PLAYERPLANEDESCRIPTOR* = ptr LAYERPLANEDESCRIPTOR

+  PIXELFORMATDESCRIPTOR* {.final, pure.} = object

+    nSize*: int16

+    nVersion*: int16

+    dwFlags*: DWORD

+    iPixelType*: int8

+    cColorBits*: int8

+    cRedBits*: int8

+    cRedShift*: int8

+    cGreenBits*: int8

+    cGreenShift*: int8

+    cBlueBits*: int8

+    cBlueShift*: int8

+    cAlphaBits*: int8

+    cAlphaShift*: int8

+    cAccumBits*: int8

+    cAccumRedBits*: int8

+    cAccumGreenBits*: int8

+    cAccumBlueBits*: int8

+    cAccumAlphaBits*: int8

+    cDepthBits*: int8

+    cStencilBits*: int8

+    cAuxBuffers*: int8

+    iLayerType*: int8

+    bReserved*: int8

+    dwLayerMask*: DWORD

+    dwVisibleMask*: DWORD

+    dwDamageMask*: DWORD

+

+  LPPIXELFORMATDESCRIPTOR* = ptr PIXELFORMATDESCRIPTOR

+  TPIXELFORMATDESCRIPTOR* = PIXELFORMATDESCRIPTOR

+  PPIXELFORMATDESCRIPTOR* = ptr PIXELFORMATDESCRIPTOR

+  USER_INFO_2* {.final, pure.} = object

+    usri2_name*: LPWSTR

+    usri2_password*: LPWSTR

+    usri2_password_age*: DWORD

+    usri2_priv*: DWORD

+    usri2_home_dir*: LPWSTR

+    usri2_comment*: LPWSTR

+    usri2_flags*: DWORD

+    usri2_script_path*: LPWSTR

+    usri2_auth_flags*: DWORD

+    usri2_full_name*: LPWSTR

+    usri2_usr_comment*: LPWSTR

+    usri2_parms*: LPWSTR

+    usri2_workstations*: LPWSTR

+    usri2_last_logon*: DWORD

+    usri2_last_logoff*: DWORD

+    usri2_acct_expires*: DWORD

+    usri2_max_storage*: DWORD

+    usri2_units_per_week*: DWORD

+    usri2_logon_hours*: PBYTE

+    usri2_bad_pw_count*: DWORD

+    usri2_num_logons*: DWORD

+    usri2_logon_server*: LPWSTR

+    usri2_country_code*: DWORD

+    usri2_code_page*: DWORD

+

+  PUSER_INFO_2* = ptr USER_INFO_2

+  LPUSER_INFO_2* = ptr USER_INFO_2

+  TUSERINFO2* = USER_INFO_2

+  USER_INFO_0* {.final, pure.} = object

+    usri0_name*: LPWSTR

+

+  PUSER_INFO_0* = ptr USER_INFO_0

+  LPUSER_INFO_0* = ptr USER_INFO_0

+  TUSERINFO0* = USER_INFO_0

+  USER_INFO_3* {.final, pure.} = object

+    usri3_name*: LPWSTR

+    usri3_password*: LPWSTR

+    usri3_password_age*: DWORD

+    usri3_priv*: DWORD

+    usri3_home_dir*: LPWSTR

+    usri3_comment*: LPWSTR

+    usri3_flags*: DWORD

+    usri3_script_path*: LPWSTR

+    usri3_auth_flags*: DWORD

+    usri3_full_name*: LPWSTR

+    usri3_usr_comment*: LPWSTR

+    usri3_parms*: LPWSTR

+    usri3_workstations*: LPWSTR

+    usri3_last_logon*: DWORD

+    usri3_last_logoff*: DWORD

+    usri3_acct_expires*: DWORD

+    usri3_max_storage*: DWORD

+    usri3_units_per_week*: DWORD

+    usri3_logon_hours*: PBYTE

+    usri3_bad_pw_count*: DWORD

+    usri3_num_logons*: DWORD

+    usri3_logon_server*: LPWSTR

+    usri3_country_code*: DWORD

+    usri3_code_page*: DWORD

+    usri3_user_id*: DWORD

+    usri3_primary_group_id*: DWORD

+    usri3_profile*: LPWSTR

+    usri3_home_dir_drive*: LPWSTR

+    usri3_password_expired*: DWORD

+

+  PUSER_INFO_3* = ptr USER_INFO_3

+  LPUSER_INFO_3* = ptr USER_INFO_3

+  TUSERINFO3* = USER_INFO_3

+  GROUP_INFO_2* {.final, pure.} = object

+    grpi2_name*: LPWSTR

+    grpi2_comment*: LPWSTR

+    grpi2_group_id*: DWORD

+    grpi2_attributes*: DWORD

+

+  PGROUP_INFO_2* = ptr GROUP_INFO_2

+  TGROUPINFO2* = GROUP_INFO_2

+  LOCALGROUP_INFO_0* {.final, pure.} = object

+    lgrpi0_name*: LPWSTR

+

+  PLOCALGROUP_INFO_0* = ptr LOCALGROUP_INFO_0

+  LPLOCALGROUP_INFO_0* = ptr LOCALGROUP_INFO_0

+  TLOCALGROUPINFO0* = LOCALGROUP_INFO_0

+  IMAGE_DOS_HEADER* {.final, pure.} = object

+    e_magic*: int16

+    e_cblp*: int16

+    e_cp*: int16

+    e_crlc*: int16

+    e_cparhdr*: int16

+    e_minalloc*: int16

+    e_maxalloc*: int16

+    e_ss*: int16

+    e_sp*: int16

+    e_csum*: int16

+    e_ip*: int16

+    e_cs*: int16

+    e_lfarlc*: int16

+    e_ovno*: int16

+    e_res*: array[0..3, int16]

+    e_oemid*: int16

+    e_oeminfo*: int16

+    e_res2*: array[0..9, int16]

+    e_lfanew*: LONG

+

+  PIMAGE_DOS_HEADER* = ptr IMAGE_DOS_HEADER

+  TIMAGEDOSHEADER* = IMAGE_DOS_HEADER

+  NOTIFYICONDATAA* {.final, pure.} = object

+    cbSize*: DWORD

+    Wnd*: HWND

+    uID*: WINUINT

+    uFlags*: WINUINT

+    uCallbackMessage*: WINUINT

+    hIcon*: HICON

+    szTip*: array[0..63, char]

+

+  NOTIFYICONDATA* = NOTIFYICONDATAA

+  NOTIFYICONDATAW* {.final, pure.} = object

+    cbSize*: DWORD

+    Wnd*: HWND

+    uID*: WINUINT

+    uFlags*: WINUINT

+    uCallbackMessage*: WINUINT

+    hIcon*: HICON

+    szTip*: array[0..63, int16]

+

+  TNotifyIconDataA* = NOTIFYICONDATAA

+  TNotifyIconDataW* = NOTIFYICONDATAW

+  TNotifyIconData* = TNotifyIconDataA

+  PNotifyIconDataA* = ptr TNotifyIconDataA

+  PNotifyIconDataW* = ptr TNotifyIconDataW

+  PNotifyIconData* = PNotifyIconDataA

+  TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, HANDLE]

+  PWOHandleArray* = ptr TWOHandleArray

+  MMRESULT* = int32

+

+type

+  PWaveFormatEx* = ptr TWaveFormatEx

+  TWaveFormatEx* {.final, pure.} = object

+    wFormatTag*: int16        # format type

+    nChannels*: int16         # number of channels (i.e. mono, stereo, etc.)

+    nSamplesPerSec*: DWORD    # sample rate

+    nAvgBytesPerSec*: DWORD   # for buffer estimation

+    nBlockAlign*: int16       # block size of data

+    wBitsPerSample*: int16    # number of bits per sample of mono data

+    cbSize*: int16            # the count in bytes of the size of

+

+  WIN32_FILE_ATTRIBUTE_DATA* {.final, pure.} = object

+    dwFileAttributes*: DWORD

+    ftCreationTime*: FILETIME

+    ftLastAccessTime*: FILETIME

+    ftLastWriteTime*: FILETIME

+    nFileSizeHigh*: DWORD

+    nFileSizeLow*: DWORD

+

+  LPWIN32_FILE_ATTRIBUTE_DATA* = ptr WIN32_FILE_ATTRIBUTE_DATA

+  TWIN32FILEATTRIBUTEDATA* = WIN32_FILE_ATTRIBUTE_DATA

+  PWIN32FILEATTRIBUTEDATA* = ptr WIN32_FILE_ATTRIBUTE_DATA

+  # TrackMouseEvent. NT or higher only.

+  TTrackMouseEvent* {.final, pure.} = object

+    cbSize*: DWORD

+    dwFlags*: DWORD

+    hwndTrack*: HWND

+    dwHoverTime*: DWORD

+

+  PTrackMouseEvent* = ptr TTrackMouseEvent

+

+const

+  ACM_OPENW* = 1127

+  ACM_OPENA* = 1124

+

+when defined(winUnicode):

+  const

+    ACM_OPEN* = ACM_OPENW

+else:

+  const

+    ACM_OPEN* = ACM_OPENA

+# UNICODE

+

+const

+  ACM_PLAY* = 1125

+  ACM_STOP* = 1126

+  ACN_START* = 1

+  ACN_STOP* = 2

+  # Buttons

+  BM_CLICK* = 245

+  BM_GETCHECK* = 240

+  BM_GETIMAGE* = 246

+  BM_GETSTATE* = 242

+  BM_SETCHECK* = 241

+  BM_SETIMAGE* = 247

+  BM_SETSTATE* = 243

+  BM_SETSTYLE* = 244

+  BN_CLICKED* = 0

+  BN_DBLCLK* = 5

+  BN_DISABLE* = 4

+  BN_DOUBLECLICKED* = 5

+  BN_HILITE* = 2

+  BN_KILLFOCUS* = 7

+  BN_PAINT* = 1

+  BN_PUSHED* = 2

+  BN_SETFOCUS* = 6

+  BN_UNHILITE* = 3

+  BN_UNPUSHED* = 3

+  # Combo Box

+  CB_ADDSTRING* = 323

+  CB_DELETESTRING* = 324

+  CB_DIR* = 325

+  CB_FINDSTRING* = 332

+  CB_FINDSTRINGEXACT* = 344

+  CB_GETCOUNT* = 326

+  CB_GETCURSEL* = 327

+  CB_GETDROPPEDCONTROLRECT* = 338

+  CB_GETDROPPEDSTATE* = 343

+  CB_GETDROPPEDWIDTH* = 351

+  CB_GETEDITSEL* = 320

+  CB_GETEXTENDEDUI* = 342

+  CB_GETHORIZONTALEXTENT* = 349

+  CB_GETITEMDATA* = 336

+  CB_GETITEMHEIGHT* = 340

+  CB_GETLBTEXT* = 328

+  CB_GETLBTEXTLEN* = 329

+  CB_GETLOCALE* = 346

+  CB_GETTOPINDEX* = 347

+  CB_INITSTORAGE* = 353

+  CB_INSERTSTRING* = 330

+  CB_LIMITTEXT* = 321

+  CB_RESETCONTENT* = 331

+  CB_SELECTSTRING* = 333

+  CB_SETCURSEL* = 334

+  CB_SETDROPPEDWIDTH* = 352

+  CB_SETEDITSEL* = 322

+  CB_SETEXTENDEDUI* = 341

+  CB_SETHORIZONTALEXTENT* = 350

+  CB_SETITEMDATA* = 337

+  CB_SETITEMHEIGHT* = 339

+  CB_SETLOCALE* = 345

+  CB_SETTOPINDEX* = 348

+  CB_SHOWDROPDOWN* = 335

+  # Combo Box notifications

+  CBN_CLOSEUP* = 8

+  CBN_DBLCLK* = 2

+  CBN_DROPDOWN* = 7

+  CBN_EDITCHANGE* = 5

+  CBN_EDITUPDATE* = 6

+  CBN_ERRSPACE* = -1

+  CBN_KILLFOCUS* = 4

+  CBN_SELCHANGE* = 1

+  CBN_SELENDCANCEL* = 10

+  CBN_SELENDOK* = 9

+  CBN_SETFOCUS* = 3

+  # Control Panel

+  # Device messages

+  # Drag list box

+  DL_BEGINDRAG* = 1157

+  DL_CANCELDRAG* = 1160

+  DL_DRAGGING* = 1158

+  DL_DROPPED* = 1159

+  # Default push button

+  DM_GETDEFID* = 1024

+  DM_REPOSITION* = 1026

+  DM_SETDEFID* = 1025

+  # RTF control

+  EM_CANPASTE* = 1074

+  EM_CANUNDO* = 198

+  EM_CHARFROMPOS* = 215

+  EM_DISPLAYBAND* = 1075

+  EM_EMPTYUNDOBUFFER* = 205

+  EM_EXGETSEL* = 1076

+  EM_EXLIMITTEXT* = 1077

+  EM_EXLINEFROMCHAR* = 1078

+  EM_EXSETSEL* = 1079

+  EM_FINDTEXT* = 1080

+  EM_FINDTEXTEX* = 1103

+  EM_FINDWORDBREAK* = 1100

+  EM_FMTLINES* = 200

+  EM_FORMATRANGE* = 1081

+  EM_GETCHARFORMAT* = 1082

+  EM_GETEVENTMASK* = 1083

+  EM_GETFIRSTVISIBLELINE* = 206

+  EM_GETHANDLE* = 189

+  EM_GETLIMITTEXT* = 213

+  EM_GETLINE* = 196

+  EM_GETLINECOUNT* = 186

+  EM_GETMARGINS* = 212

+  EM_GETMODIFY* = 184

+  EM_GETIMECOLOR* = 1129

+  EM_GETIMEOPTIONS* = 1131

+  EM_GETOPTIONS* = 1102

+  EM_GETOLEINTERFACE* = 1084

+  EM_GETPARAFORMAT* = 1085

+  EM_GETPASSWORDCHAR* = 210

+  EM_GETPUNCTUATION* = 1125

+  EM_GETRECT* = 178

+  EM_GETSEL* = 176

+  EM_GETSELTEXT* = 1086

+  EM_GETTEXTRANGE* = 1099

+  EM_GETTHUMB* = 190

+  EM_GETWORDBREAKPROC* = 209

+  EM_GETWORDBREAKPROCEX* = 1104

+  EM_GETWORDWRAPMODE* = 1127

+  EM_HIDESELECTION* = 1087

+  EM_LIMITTEXT* = 197

+  EM_LINEFROMCHAR* = 201

+  EM_LINEINDEX* = 187

+  EM_LINELENGTH* = 193

+  EM_LINESCROLL* = 182

+  EM_PASTESPECIAL* = 1088

+  EM_POSFROMCHAR* = 214

+  EM_REPLACESEL* = 194

+  EM_REQUESTRESIZE* = 1089

+  EM_SCROLL* = 181

+  EM_SCROLLCARET* = 183

+  EM_SELECTIONTYPE* = 1090

+  EM_SETBKGNDCOLOR* = 1091

+  EM_SETCHARFORMAT* = 1092

+  EM_SETEVENTMASK* = 1093

+  EM_SETHANDLE* = 188

+  EM_SETIMECOLOR* = 1128

+  EM_SETIMEOPTIONS* = 1130

+  EM_SETLIMITTEXT* = 197

+  EM_SETMARGINS* = 211

+  EM_SETMODIFY* = 185

+  EM_SETOLECALLBACK* = 1094

+  EM_SETOPTIONS* = 1101

+  EM_SETPARAFORMAT* = 1095

+  EM_SETPASSWORDCHAR* = 204

+  EM_SETPUNCTUATION* = 1124

+  EM_SETREADONLY* = 207

+  EM_SETRECT* = 179

+  EM_SETRECTNP* = 180

+  EM_SETSEL* = 177

+  EM_SETTABSTOPS* = 203

+  EM_SETTARGETDEVICE* = 1096

+  EM_SETWORDBREAKPROC* = 208

+  EM_SETWORDBREAKPROCEX* = 1105

+  EM_SETWORDWRAPMODE* = 1126

+  EM_STREAMIN* = 1097

+  EM_STREAMOUT* = 1098

+  EM_UNDO* = 199

+  # Edit control

+  EN_CHANGE* = 768

+  EN_CORRECTTEXT* = 1797

+  EN_DROPFILES* = 1795

+  EN_ERRSPACE* = 1280

+  EN_HSCROLL* = 1537

+  EN_IMECHANGE* = 1799

+  EN_KILLFOCUS* = 512

+  EN_MAXTEXT* = 1281

+  EN_MSGFILTER* = 1792

+  EN_OLEOPFAILED* = 1801

+  EN_PROTECTED* = 1796

+  EN_REQUESTRESIZE* = 1793

+  EN_SAVECLIPBOARD* = 1800

+  EN_SELCHANGE* = 1794

+  EN_SETFOCUS* = 256

+  EN_STOPNOUNDO* = 1798

+  EN_UPDATE* = 1024

+  EN_VSCROLL* = 1538

+  # File Manager extensions

+  # File Manager extensions DLL events

+  # Header control

+  HDM_DELETEITEM* = 4610

+  HDM_GETITEMW* = 4619

+  HDM_INSERTITEMW* = 4618

+  HDM_SETITEMW* = 4620

+  HDM_GETITEMA* = 4611

+  HDM_INSERTITEMA* = 4609

+  HDM_SETITEMA* = 4612

+

+when defined(winUnicode):

+  const

+    HDM_GETITEM* = HDM_GETITEMW

+    HDM_INSERTITEM* = HDM_INSERTITEMW

+    HDM_SETITEM* = HDM_SETITEMW

+else:

+  const

+    HDM_GETITEM* = HDM_GETITEMA

+    HDM_INSERTITEM* = HDM_INSERTITEMA

+    HDM_SETITEM* = HDM_SETITEMA

+# UNICODE

+

+const

+  HDM_GETITEMCOUNT* = 4608

+  HDM_HITTEST* = 4614

+  HDM_LAYOUT* = 4613

+  # Header control notifications

+  HDN_BEGINTRACKW* = -326

+  HDN_DIVIDERDBLCLICKW* = -325

+  HDN_ENDTRACKW* = -327

+  HDN_ITEMCHANGEDW* = -321

+  HDN_ITEMCHANGINGW* = -320

+  HDN_ITEMCLICKW* = -322

+  HDN_ITEMDBLCLICKW* = -323

+  HDN_TRACKW* = -328

+  HDN_BEGINTRACKA* = -306

+  HDN_DIVIDERDBLCLICKA* = -305

+  HDN_ENDTRACKA* = -307

+  HDN_ITEMCHANGEDA* = -301

+  HDN_ITEMCHANGINGA* = -300

+  HDN_ITEMCLICKA* = -302

+  HDN_ITEMDBLCLICKA* = -303

+  HDN_TRACKA* = -308

+

+when defined(winUnicode):

+  const

+    HDN_BEGINTRACK* = HDN_BEGINTRACKW

+    HDN_DIVIDERDBLCLICK* = HDN_DIVIDERDBLCLICKW

+    HDN_ENDTRACK* = HDN_ENDTRACKW

+    HDN_ITEMCHANGED* = HDN_ITEMCHANGEDW

+    HDN_ITEMCHANGING* = HDN_ITEMCHANGINGW

+    HDN_ITEMCLICK* = HDN_ITEMCLICKW

+    HDN_ITEMDBLCLICK* = HDN_ITEMDBLCLICKW

+    HDN_TRACK* = HDN_TRACKW

+else:

+  const

+    HDN_BEGINTRACK* = HDN_BEGINTRACKA

+    HDN_DIVIDERDBLCLICK* = HDN_DIVIDERDBLCLICKA

+    HDN_ENDTRACK* = HDN_ENDTRACKA

+    HDN_ITEMCHANGED* = HDN_ITEMCHANGEDA

+    HDN_ITEMCHANGING* = HDN_ITEMCHANGINGA

+    HDN_ITEMCLICK* = HDN_ITEMCLICKA

+    HDN_ITEMDBLCLICK* = HDN_ITEMDBLCLICKA

+    HDN_TRACK* = HDN_TRACKA

+# UNICODE

+

+const

+  # Hot key control

+  HKM_GETHOTKEY* = 1026

+  HKM_SETHOTKEY* = 1025

+  HKM_SETRULES* = 1027

+  # List box

+  LB_ADDFILE* = 406

+  LB_ADDSTRING* = 384

+  LB_DELETESTRING* = 386

+  LB_DIR* = 397

+  LB_FINDSTRING* = 399

+  LB_FINDSTRINGEXACT* = 418

+  LB_GETANCHORINDEX* = 413

+  LB_GETCARETINDEX* = 415

+  LB_GETCOUNT* = 395

+  LB_GETCURSEL* = 392

+  LB_GETHORIZONTALEXTENT* = 403

+  LB_GETITEMDATA* = 409

+  LB_GETITEMHEIGHT* = 417

+  LB_GETITEMRECT* = 408

+  LB_GETLOCALE* = 422

+  LB_GETSEL* = 391

+  LB_GETSELCOUNT* = 400

+  LB_GETSELITEMS* = 401

+  LB_GETTEXT* = 393

+  LB_GETTEXTLEN* = 394

+  LB_GETTOPINDEX* = 398

+  LB_INITSTORAGE* = 424

+  LB_INSERTSTRING* = 385

+  LB_ITEMFROMPOINT* = 425

+  LB_RESETCONTENT* = 388

+  LB_SELECTSTRING* = 396

+  LB_SELITEMRANGE* = 411

+  LB_SELITEMRANGEEX* = 387

+  LB_SETANCHORINDEX* = 412

+  LB_SETCARETINDEX* = 414

+  LB_SETCOLUMNWIDTH* = 405

+  LB_SETCOUNT* = 423

+  LB_SETCURSEL* = 390

+  LB_SETHORIZONTALEXTENT* = 404

+  LB_SETITEMDATA* = 410

+  LB_SETITEMHEIGHT* = 416

+  LB_SETLOCALE* = 421

+  LB_SETSEL* = 389

+  LB_SETTABSTOPS* = 402

+  LB_SETTOPINDEX* = 407

+  # List box notifications

+  LBN_DBLCLK* = 2

+  LBN_ERRSPACE* = -2

+  LBN_KILLFOCUS* = 5

+  LBN_SELCANCEL* = 3

+  LBN_SELCHANGE* = 1

+  LBN_SETFOCUS* = 4

+  # List view control

+  LVM_ARRANGE* = 4118

+  LVM_CREATEDRAGIMAGE* = 4129

+  LVM_DELETEALLITEMS* = 4105

+  LVM_DELETECOLUMN* = 4124

+  LVM_DELETEITEM* = 4104

+  LVM_ENSUREVISIBLE* = 4115

+  LVM_GETBKCOLOR* = 4096

+  LVM_GETCALLBACKMASK* = 4106

+  LVM_GETCOLUMNWIDTH* = 4125

+  LVM_GETCOUNTPERPAGE* = 4136

+  LVM_GETEDITCONTROL* = 4120

+  LVM_GETIMAGELIST* = 4098

+  LVM_EDITLABELW* = 4214

+  LVM_FINDITEMW* = 4179

+  LVM_GETCOLUMNW* = 4191

+  LVM_GETISEARCHSTRINGW* = 4213

+  LVM_GETITEMW* = 4171

+  LVM_GETITEMTEXTW* = 4211

+  LVM_GETSTRINGWIDTHW* = 4183

+  LVM_INSERTCOLUMNW* = 4193

+  LVM_INSERTITEMW* = 4173

+  LVM_SETCOLUMNW* = 4192

+  LVM_SETITEMW* = 4172

+  LVM_SETITEMTEXTW* = 4212

+  LVM_EDITLABELA* = 4119

+  LVM_FINDITEMA* = 4109

+  LVM_GETCOLUMNA* = 4121

+  LVM_GETISEARCHSTRINGA* = 4148

+  LVM_GETITEMA* = 4101

+  LVM_GETITEMTEXTA* = 4141

+  LVM_GETSTRINGWIDTHA* = 4113

+  LVM_INSERTCOLUMNA* = 4123

+  LVM_INSERTITEMA* = 4103

+  LVM_SETCOLUMNA* = 4122

+  LVM_SETITEMA* = 4102

+  LVM_SETITEMTEXTA* = 4142

+

+when defined(winUnicode):

+  const

+    LVM_EDITLABEL* = LVM_EDITLABELW

+    LVM_FINDITEM* = LVM_FINDITEMW

+    LVM_GETCOLUMN* = LVM_GETCOLUMNW

+    LVM_GETISEARCHSTRING* = LVM_GETISEARCHSTRINGW

+    LVM_GETITEM* = LVM_GETITEMW

+    LVM_GETITEMTEXT* = LVM_GETITEMTEXTW

+    LVM_GETSTRINGWIDTH* = LVM_GETSTRINGWIDTHW

+    LVM_INSERTCOLUMN* = LVM_INSERTCOLUMNW

+    LVM_INSERTITEM* = LVM_INSERTITEMW

+    LVM_SETCOLUMN* = LVM_SETCOLUMNW

+    LVM_SETITEM* = LVM_SETITEMW

+    LVM_SETITEMTEXT* = LVM_SETITEMTEXTW

+else:

+  const

+    LVM_EDITLABEL* = LVM_EDITLABELA

+    LVM_FINDITEM* = LVM_FINDITEMA

+    LVM_GETCOLUMN* = LVM_GETCOLUMNA

+    LVM_GETISEARCHSTRING* = LVM_GETISEARCHSTRINGA

+    LVM_GETITEM* = LVM_GETITEMA

+    LVM_GETITEMTEXT* = LVM_GETITEMTEXTA

+    LVM_GETSTRINGWIDTH* = LVM_GETSTRINGWIDTHA

+    LVM_INSERTCOLUMN* = LVM_INSERTCOLUMNA

+    LVM_INSERTITEM* = LVM_INSERTITEMA

+    LVM_SETCOLUMN* = LVM_SETCOLUMNA

+    LVM_SETITEM* = LVM_SETITEMA

+    LVM_SETITEMTEXT* = LVM_SETITEMTEXTA

+# UNICODE

+

+const

+  LVM_GETITEMCOUNT* = 4100

+  LVM_GETITEMPOSITION* = 4112

+  LVM_GETITEMRECT* = 4110

+  LVM_GETITEMSPACING* = 4147

+  LVM_GETITEMSTATE* = 4140

+  LVM_GETNEXTITEM* = 4108

+  LVM_GETORIGIN* = 4137

+  LVM_GETSELECTEDCOUNT* = 4146

+  LVM_GETTEXTBKCOLOR* = 4133

+  LVM_GETTEXTCOLOR* = 4131

+  LVM_GETTOPINDEX* = 4135

+  LVM_GETVIEWRECT* = 4130

+  LVM_HITTEST* = 4114

+  LVM_REDRAWITEMS* = 4117

+  LVM_SCROLL* = 4116

+  LVM_SETBKCOLOR* = 4097

+  LVM_SETCALLBACKMASK* = 4107

+  LVM_SETCOLUMNWIDTH* = 4126

+  LVM_SETIMAGELIST* = 4099

+  LVM_SETITEMCOUNT* = 4143

+  LVM_SETITEMPOSITION* = 4111

+  LVM_SETITEMPOSITION32* = 4145

+  LVM_SETITEMSTATE* = 4139

+  LVM_SETTEXTBKCOLOR* = 4134

+  LVM_SETTEXTCOLOR* = 4132

+  LVM_SORTITEMS* = 4144

+  LVM_UPDATE* = 4138

+  # List view control notifications

+  LVN_BEGINDRAG* = -109

+  LVN_BEGINRDRAG* = -111

+  LVN_COLUMNCLICK* = -108

+  LVN_DELETEALLITEMS* = -104

+  LVN_DELETEITEM* = -103

+  LVN_BEGINLABELEDITW* = -175

+  LVN_ENDLABELEDITW* = -176

+  LVN_GETDISPINFOW* = -177

+  LVN_SETDISPINFOW* = -178

+  LVN_BEGINLABELEDITA* = -105

+  LVN_ENDLABELEDITA* = -106

+  LVN_GETDISPINFOA* = -150

+  LVN_SETDISPINFOA* = -151

+

+when defined(winUnicode):

+  const

+    LVN_BEGINLABELEDIT* = LVN_BEGINLABELEDITW

+    LVN_ENDLABELEDIT* = LVN_ENDLABELEDITW

+    LVN_GETDISPINFO* = LVN_GETDISPINFOW

+    LVN_SETDISPINFO* = LVN_SETDISPINFOW

+else:

+  const

+    LVN_BEGINLABELEDIT* = LVN_BEGINLABELEDITA

+    LVN_ENDLABELEDIT* = LVN_ENDLABELEDITA

+    LVN_GETDISPINFO* = LVN_GETDISPINFOA

+    LVN_SETDISPINFO* = LVN_SETDISPINFOA

+# UNICODE

+

+const

+  LVN_INSERTITEM* = -102

+  LVN_ITEMCHANGED* = -101

+  LVN_ITEMCHANGING* = -100

+  LVN_KEYDOWN* = -155

+  # Control notification

+  NM_CLICK* = -2

+  NM_DBLCLK* = -3

+  NM_KILLFOCUS* = -8

+  NM_OUTOFMEMORY* = -1

+  NM_RCLICK* = -5

+  NM_RDBLCLK* = -6

+  NM_RETURN* = -4

+  NM_SETFOCUS* = -7

+  # Power status

+  # Progress bar control

+  PBM_DELTAPOS* = 1027

+  PBM_SETPOS* = 1026

+  PBM_SETRANGE* = 1025

+  PBM_SETRANGE32* = 1030

+  PBM_SETSTEP* = 1028

+  PBM_STEPIT* = 1029

+  # Property sheets

+  PSM_ADDPAGE* = 1127

+  PSM_APPLY* = 1134

+  PSM_CANCELTOCLOSE* = 1131

+  PSM_CHANGED* = 1128

+  PSM_GETTABCONTROL* = 1140

+  PSM_GETCURRENTPAGEHWND* = 1142

+  PSM_ISDIALOGMESSAGE* = 1141

+  PSM_PRESSBUTTON* = 1137

+  PSM_QUERYSIBLINGS* = 1132

+  PSM_REBOOTSYSTEM* = 1130

+  PSM_REMOVEPAGE* = 1126

+  PSM_RESTARTWINDOWS* = 1129

+  PSM_SETCURSEL* = 1125

+  PSM_SETCURSELID* = 1138

+  PSM_SETFINISHTEXTW* = 1145

+  PSM_SETTITLEW* = 1144

+  PSM_SETFINISHTEXTA* = 1139

+  PSM_SETTITLEA* = 1135

+

+when defined(winUnicode):

+  const

+    PSM_SETFINISHTEXT* = PSM_SETFINISHTEXTW

+    PSM_SETTITLE* = PSM_SETTITLEW

+else:

+  const

+    PSM_SETFINISHTEXT* = PSM_SETFINISHTEXTA

+    PSM_SETTITLE* = PSM_SETTITLEA

+# UNICODE

+

+const

+  PSM_SETWIZBUTTONS* = 1136

+  PSM_UNCHANGED* = 1133

+  # Property sheet notifications

+  PSN_APPLY* = -202

+  PSN_HELP* = -205

+  PSN_KILLACTIVE* = -201

+  PSN_QUERYCANCEL* = -209

+  PSN_RESET* = -203

+  PSN_SETACTIVE* = -200

+  PSN_WIZBACK* = -206

+  PSN_WIZFINISH* = -208

+  PSN_WIZNEXT* = -207

+  # Status window

+  SB_GETBORDERS* = 1031

+  SB_GETPARTS* = 1030

+  SB_GETRECT* = 1034

+  SB_GETTEXTW* = 1037

+  SB_GETTEXTLENGTHW* = 1036

+  SB_SETTEXTW* = 1035

+  SB_GETTEXTA* = 1026

+  SB_GETTEXTLENGTHA* = 1027

+  SB_SETTEXTA* = 1025

+

+when defined(winUnicode):

+  const

+    SB_GETTEXT* = SB_GETTEXTW

+    SB_GETTEXTLENGTH* = SB_GETTEXTLENGTHW

+    SB_SETTEXT* = SB_SETTEXTW

+else:

+  const

+    SB_GETTEXT* = SB_GETTEXTA

+    SB_GETTEXTLENGTH* = SB_GETTEXTLENGTHA

+    SB_SETTEXT* = SB_SETTEXTA

+# UNICODE

+

+const

+  SB_SETMINHEIGHT* = 1032

+  SB_SETPARTS* = 1028

+  SB_SIMPLE* = 1033

+  # Scroll bar control

+  SBM_ENABLE_ARROWS* = 228

+  SBM_GETPOS* = 225

+  SBM_GETRANGE* = 227

+  SBM_GETSCROLLINFO* = 234

+  SBM_SETPOS* = 224

+  SBM_SETRANGE* = 226

+  SBM_SETRANGEREDRAW* = 230

+  SBM_SETSCROLLINFO* = 233

+  # Static control

+  STM_GETICON* = 369

+  STM_GETIMAGE* = 371

+  STM_SETICON* = 368

+  STM_SETIMAGE* = 370

+  # Static control notifications

+  STN_CLICKED* = 0

+  STN_DBLCLK* = 1

+  STN_DISABLE* = 3

+  STN_ENABLE* = 2

+  # Toolbar control

+  TB_ADDBITMAP* = 1043

+  TB_ADDBUTTONS* = 1044

+  TB_AUTOSIZE* = 1057

+  TB_BUTTONCOUNT* = 1048

+  TB_BUTTONSTRUCTSIZE* = 1054

+  TB_CHANGEBITMAP* = 1067

+  TB_CHECKBUTTON* = 1026

+  TB_COMMANDTOINDEX* = 1049

+  TB_CUSTOMIZE* = 1051

+  TB_DELETEBUTTON* = 1046

+  TB_ENABLEBUTTON* = 1025

+  TB_GETBITMAP* = 1068

+  TB_GETBITMAPFLAGS* = 1065

+  TB_GETBUTTON* = 1047

+  TB_ADDSTRINGW* = 1101

+  TB_GETBUTTONTEXTW* = 1099

+  TB_SAVERESTOREW* = 1100

+  TB_ADDSTRINGA* = 1052

+  TB_GETBUTTONTEXTA* = 1069

+  TB_SAVERESTOREA* = 1050

+

+when defined(winUnicode):

+  const

+    TB_ADDSTRING* = TB_ADDSTRINGW

+    TB_GETBUTTONTEXT* = TB_GETBUTTONTEXTW

+    TB_SAVERESTORE* = TB_SAVERESTOREW

+else:

+  const

+    TB_ADDSTRING* = TB_ADDSTRINGA

+    TB_GETBUTTONTEXT* = TB_GETBUTTONTEXTA

+    TB_SAVERESTORE* = TB_SAVERESTOREA

+# UNICODE

+

+const

+  TB_GETITEMRECT* = 1053

+  TB_GETROWS* = 1064

+  TB_GETSTATE* = 1042

+  TB_GETTOOLTIPS* = 1059

+  TB_HIDEBUTTON* = 1028

+  TB_INDETERMINATE* = 1029

+  TB_INSERTBUTTON* = 1045

+  TB_ISBUTTONCHECKED* = 1034

+  TB_ISBUTTONENABLED* = 1033

+  TB_ISBUTTONHIDDEN* = 1036

+  TB_ISBUTTONINDETERMINATE* = 1037

+  TB_ISBUTTONPRESSED* = 1035

+  TB_PRESSBUTTON* = 1027

+  TB_SETBITMAPSIZE* = 1056

+  TB_SETBUTTONSIZE* = 1055

+  TB_SETCMDID* = 1066

+  TB_SETPARENT* = 1061

+  TB_SETROWS* = 1063

+  TB_SETSTATE* = 1041

+  TB_SETTOOLTIPS* = 1060

+  # Track bar control

+  TBM_CLEARSEL* = 1043

+  TBM_CLEARTICS* = 1033

+  TBM_GETCHANNELRECT* = 1050

+  TBM_GETLINESIZE* = 1048

+  TBM_GETNUMTICS* = 1040

+  TBM_GETPAGESIZE* = 1046

+  TBM_GETPOS* = 1024

+  TBM_GETPTICS* = 1038

+  TBM_GETRANGEMAX* = 1026

+  TBM_GETRANGEMIN* = 1025

+  TBM_GETSELEND* = 1042

+  TBM_GETSELSTART* = 1041

+  TBM_GETTHUMBLENGTH* = 1052

+  TBM_GETTHUMBRECT* = 1049

+  TBM_GETTIC* = 1027

+  TBM_GETTICPOS* = 1039

+  TBM_SETLINESIZE* = 1047

+  TBM_SETPAGESIZE* = 1045

+  TBM_SETPOS* = 1029

+  TBM_SETRANGE* = 1030

+  TBM_SETRANGEMAX* = 1032

+  TBM_SETRANGEMIN* = 1031

+  TBM_SETSEL* = 1034

+  TBM_SETSELEND* = 1036

+  TBM_SETSELSTART* = 1035

+  TBM_SETTHUMBLENGTH* = 1051

+  TBM_SETTIC* = 1028

+  TBM_SETTICFREQ* = 1044

+  # Tool bar control notifications

+  TBN_BEGINADJUST* = -703

+  TBN_BEGINDRAG* = -701

+  TBN_CUSTHELP* = -709

+  TBN_ENDADJUST* = -704

+  TBN_ENDDRAG* = -702

+  TBN_GETBUTTONINFOW* = -720

+  TBN_GETBUTTONINFOA* = -700

+

+when defined(winUnicode):

+  const

+    TBN_GETBUTTONINFO* = TBN_GETBUTTONINFOW

+else:

+  const

+    TBN_GETBUTTONINFO* = TBN_GETBUTTONINFOA

+# UNICODE

+

+const

+  TBN_QUERYDELETE* = -707

+  TBN_QUERYINSERT* = -706

+  TBN_RESET* = -705

+  TBN_TOOLBARCHANGE* = -708

+  # Tab control

+  TCM_ADJUSTRECT* = 4904

+  TCM_DELETEALLITEMS* = 4873

+  TCM_DELETEITEM* = 4872

+  TCM_GETCURFOCUS* = 4911

+  TCM_GETCURSEL* = 4875

+  TCM_GETIMAGELIST* = 4866

+  TCM_GETITEMW* = 4924

+  TCM_INSERTITEMW* = 4926

+  TCM_SETITEMW* = 4925

+  TCM_GETITEMA* = 4869

+  TCM_INSERTITEMA* = 4871

+  TCM_SETITEMA* = 4870

+

+when defined(winUnicode):

+  const

+    TCM_GETITEM* = TCM_GETITEM

+    TCM_INSERTITEM* = TCM_INSERTITEMW

+    TCM_SETITEM* = TCM_SETITEMW

+else:

+  const

+    TCM_GETITEM* = TCM_GETITEMA

+    TCM_INSERTITEM* = TCM_INSERTITEMA

+    TCM_SETITEM* = TCM_SETITEMA

+# UNICODE

+

+const

+  TCM_GETITEMCOUNT* = 4868

+  TCM_GETITEMRECT* = 4874

+  TCM_GETROWCOUNT* = 4908

+  TCM_GETTOOLTIPS* = 4909

+  TCM_HITTEST* = 4877

+  TCM_REMOVEIMAGE* = 4906

+  TCM_SETCURFOCUS* = 4912

+  TCM_SETCURSEL* = 4876

+  TCM_SETIMAGELIST* = 4867

+  TCM_SETITEMEXTRA* = 4878

+  TCM_SETITEMSIZE* = 4905

+  TCM_SETPADDING* = 4907

+  TCM_SETTOOLTIPS* = 4910

+  # Tab control notifications

+  TCN_KEYDOWN* = -550

+  TCN_SELCHANGE* = -551

+  TCN_SELCHANGING* = -552

+  # Tool tip control

+  TTM_ACTIVATE* = 1025

+  TTM_ADDTOOLW* = 1074

+  TTM_DELTOOLW* = 1075

+  TTM_ENUMTOOLSW* = 1082

+  TTM_GETCURRENTTOOLW* = 1083

+  TTM_GETTEXTW* = 1080

+  TTM_GETTOOLINFOW* = 1077

+  TTM_HITTESTW* = 1079

+  TTM_NEWTOOLRECTW* = 1076

+  TTM_SETTOOLINFOW* = 1078

+  TTM_UPDATETIPTEXTW* = 1081

+  TTM_ADDTOOLA* = 1028

+  TTM_DELTOOLA* = 1029

+  TTM_ENUMTOOLSA* = 1038

+  TTM_GETCURRENTTOOLA* = 1039

+  TTM_GETTEXTA* = 1035

+  TTM_GETTOOLINFOA* = 1032

+  TTM_HITTESTA* = 1034

+  TTM_NEWTOOLRECTA* = 1030

+  TTM_SETTOOLINFOA* = 1033

+  TTM_UPDATETIPTEXTA* = 1036

+

+when defined(winUnicode):

+  const

+    TTM_ADDTOOL* = TTM_ADDTOOLW

+    TTM_DELTOOL* = TTM_DELTOOLW

+    TTM_ENUMTOOLS* = TTM_ENUMTOOLSW

+    TTM_GETCURRENTTOOL* = TTM_GETCURRENTTOOLW

+    TTM_GETTEXT* = TTM_GETTEXTW

+    TTM_GETTOOLINFO* = TTM_GETTOOLINFOW

+    TTM_HITTEST* = TTM_HITTESTW

+    TTM_NEWTOOLRECT* = TTM_NEWTOOLRECTW

+    TTM_SETTOOLINFO* = TTM_SETTOOLINFOW

+    TTM_UPDATETIPTEXT* = TTM_UPDATETIPTEXTW

+else:

+  const

+    TTM_ADDTOOL* = TTM_ADDTOOLA

+    TTM_DELTOOL* = TTM_DELTOOLA

+    TTM_ENUMTOOLS* = TTM_ENUMTOOLSA

+    TTM_GETCURRENTTOOL* = TTM_GETCURRENTTOOLA

+    TTM_GETTEXT* = TTM_GETTEXTA

+    TTM_GETTOOLINFO* = TTM_GETTOOLINFOA

+    TTM_HITTEST* = TTM_HITTESTA

+    TTM_NEWTOOLRECT* = TTM_NEWTOOLRECTA

+    TTM_SETTOOLINFO* = TTM_SETTOOLINFOA

+    TTM_UPDATETIPTEXT* = TTM_UPDATETIPTEXTA

+# UNICODE

+

+const

+  TTM_GETTOOLCOUNT* = 1037

+  TTM_RELAYEVENT* = 1031

+  TTM_SETDELAYTIME* = 1027

+  TTM_WINDOWFROMPOINT* = 1040

+  # Tool tip control notification

+  TTN_NEEDTEXTW* = -530

+  TTN_NEEDTEXTA* = -520

+

+when defined(winUnicode):

+  const

+    TTN_NEEDTEXT* = TTN_NEEDTEXTW

+else:

+  const

+    TTN_NEEDTEXT* = TTN_NEEDTEXTA

+# UNICODE

+

+const

+  TTN_POP* = -522

+  TTN_SHOW* = -521

+  # Tree view control

+  TVM_CREATEDRAGIMAGE* = 4370

+  TVM_DELETEITEM* = 4353

+  TVM_ENDEDITLABELNOW* = 4374

+  TVM_ENSUREVISIBLE* = 4372

+  TVM_EXPAND* = 4354

+  TVM_GETCOUNT* = 4357

+  TVM_GETEDITCONTROL* = 4367

+  TVM_GETIMAGELIST* = 4360

+  TVM_GETINDENT* = 4358

+  TVM_GETITEMRECT* = 4356

+  TVM_GETNEXTITEM* = 4362

+  TVM_GETVISIBLECOUNT* = 4368

+  TVM_HITTEST* = 4369

+  TVM_EDITLABELW* = 4417

+  TVM_GETISEARCHSTRINGW* = 4416

+  TVM_GETITEMW* = 4414

+  TVM_INSERTITEMW* = 4402

+  TVM_SETITEMW* = 4415

+  TVM_EDITLABELA* = 4366

+  TVM_GETISEARCHSTRINGA* = 4375

+  TVM_GETITEMA* = 4364

+  TVM_INSERTITEMA* = 4352

+  TVM_SETITEMA* = 4365

+

+when defined(winUnicode):

+  const

+    TVM_EDITLABEL* = TVM_EDITLABELW

+    TVM_GETISEARCHSTRING* = TVM_GETISEARCHSTRINGW

+    TVM_GETITEM* = TVM_GETITEMW

+    TVM_INSERTITEM* = TVM_INSERTITEMW

+    TVM_SETITEM* = TVM_SETITEMW

+else:

+  const

+    TVM_EDITLABEL* = TVM_EDITLABELA

+    TVM_GETISEARCHSTRING* = TVM_GETISEARCHSTRINGA

+    TVM_GETITEM* = TVM_GETITEMA

+    TVM_INSERTITEM* = TVM_INSERTITEMA

+    TVM_SETITEM* = TVM_SETITEMA

+# UNICODE

+

+const

+  TVM_SELECTITEM* = 4363

+  TVM_SETIMAGELIST* = 4361

+  TVM_SETINDENT* = 4359

+  TVM_SORTCHILDREN* = 4371

+  TVM_SORTCHILDRENCB* = 4373

+  # Tree view control notification

+  TVN_KEYDOWN* = -412

+  TVN_BEGINDRAGW* = -456

+  TVN_BEGINLABELEDITW* = -459

+  TVN_BEGINRDRAGW* = -457

+  TVN_DELETEITEMW* = -458

+  TVN_ENDLABELEDITW* = -460

+  TVN_GETDISPINFOW* = -452

+  TVN_ITEMEXPANDEDW* = -455

+  TVN_ITEMEXPANDINGW* = -454

+  TVN_SELCHANGEDW* = -451

+  TVN_SELCHANGINGW* = -450

+  TVN_SETDISPINFOW* = -453

+  TVN_BEGINDRAGA* = -407

+  TVN_BEGINLABELEDITA* = -410

+  TVN_BEGINRDRAGA* = -408

+  TVN_DELETEITEMA* = -409

+  TVN_ENDLABELEDITA* = -411

+  TVN_GETDISPINFOA* = -403

+  TVN_ITEMEXPANDEDA* = -406

+  TVN_ITEMEXPANDINGA* = -405

+  TVN_SELCHANGEDA* = -402

+  TVN_SELCHANGINGA* = -401

+  TVN_SETDISPINFOA* = -404

+

+when defined(winUnicode):

+  const

+    TVN_BEGINDRAG* = TVN_BEGINDRAGW

+    TVN_BEGINLABELEDIT* = TVN_BEGINLABELEDITW

+    TVN_BEGINRDRAG* = TVN_BEGINRDRAGW

+    TVN_DELETEITEM* = TVN_DELETEITEMW

+    TVN_ENDLABELEDIT* = TVN_ENDLABELEDITW

+    TVN_GETDISPINFO* = TVN_GETDISPINFOW

+    TVN_ITEMEXPANDED* = TVN_ITEMEXPANDEDW

+    TVN_ITEMEXPANDING* = TVN_ITEMEXPANDINGW

+    TVN_SELCHANGED* = TVN_SELCHANGEDW

+    TVN_SELCHANGING* = TVN_SELCHANGINGW

+    TVN_SETDISPINFO* = TVN_SETDISPINFOW

+else:

+  const

+    TVN_BEGINDRAG* = TVN_BEGINDRAGA

+    TVN_BEGINLABELEDIT* = TVN_BEGINLABELEDITA

+    TVN_BEGINRDRAG* = TVN_BEGINRDRAGA

+    TVN_DELETEITEM* = TVN_DELETEITEMA

+    TVN_ENDLABELEDIT* = TVN_ENDLABELEDITA

+    TVN_GETDISPINFO* = TVN_GETDISPINFOA

+    TVN_ITEMEXPANDED* = TVN_ITEMEXPANDEDA

+    TVN_ITEMEXPANDING* = TVN_ITEMEXPANDINGA

+    TVN_SELCHANGED* = TVN_SELCHANGEDA

+    TVN_SELCHANGING* = TVN_SELCHANGINGA

+    TVN_SETDISPINFO* = TVN_SETDISPINFOA

+# UNICODE

+

+const

+  # Up/down control

+  UDM_GETACCEL* = 1132

+  UDM_GETBASE* = 1134

+  UDM_GETBUDDY* = 1130

+  UDM_GETPOS* = 1128

+  UDM_GETPOS32* = 1138

+  UDM_GETRANGE* = 1126

+  UDM_GETRANGE32* = 1136

+  UDM_SETACCEL* = 1131

+  UDM_SETBASE* = 1133

+  UDM_SETBUDDY* = 1129

+  UDM_SETPOS* = 1127

+  UDM_SETPOS32* = 1137

+  UDM_SETRANGE* = 1125

+  UDM_SETRANGE32* = 1135

+  # Up/down control notification

+  UDN_DELTAPOS* = -722

+  # Window messages

+  WM_ACTIVATE* = 6

+  WM_ACTIVATEAPP* = 28

+  WM_ASKCBFORMATNAME* = 780

+  WM_CANCELJOURNAL* = 75

+  WM_CANCELMODE* = 31

+  WM_CAPTURECHANGED* = 533

+  WM_CHANGECBCHAIN* = 781

+  WM_CHAR* = 258

+  WM_CHARTOITEM* = 47

+  WM_CHILDACTIVATE* = 34

+  WM_CHOOSEFONT_GETLOGFONT* = 1025

+  WM_CHOOSEFONT_SETLOGFONT* = 1125

+  WM_CHOOSEFONT_SETFLAGS* = 1126

+  WM_CLEAR* = 771

+  WM_CLOSE* = 16

+  WM_COMMAND* = 273

+  WM_COMPACTING* = 65

+  WM_COMPAREITEM* = 57

+  WM_CONTEXTMENU* = 123

+  WM_COPY* = 769

+  WM_COPYDATA* = 74

+  WM_CREATE* = 1

+  WM_CTLCOLORBTN* = 309

+  WM_CTLCOLORDLG* = 310

+  WM_CTLCOLOREDIT* = 307

+  WM_CTLCOLORLISTBOX* = 308

+  WM_CTLCOLORMSGBOX* = 306

+  WM_CTLCOLORSCROLLBAR* = 311

+  WM_CTLCOLORSTATIC* = 312

+  WM_CUT* = 768

+  WM_DEADCHAR* = 259

+  WM_DELETEITEM* = 45

+  WM_DESTROY* = 2

+  WM_DESTROYCLIPBOARD* = 775

+  WM_DEVICECHANGE* = 537

+  WM_DEVMODECHANGE* = 27

+  WM_DISPLAYCHANGE* = 126

+  WM_DRAWCLIPBOARD* = 776

+  WM_DRAWITEM* = 43

+  WM_DROPFILES* = 563

+  WM_ENABLE* = 10

+  WM_ENDSESSION* = 22

+  WM_ENTERIDLE* = 289

+  WM_ENTERMENULOOP* = 529

+  WM_ENTERSIZEMOVE* = 561

+  WM_ERASEBKGND* = 20

+  WM_EXITMENULOOP* = 530

+  WM_EXITSIZEMOVE* = 562

+  WM_FONTCHANGE* = 29

+  WM_GETDLGCODE* = 135

+  WM_GETFONT* = 49

+  WM_GETHOTKEY* = 51

+  WM_GETICON* = 127

+  WM_GETMINMAXINFO* = 36

+  WM_GETTEXT* = 13

+  WM_GETTEXTLENGTH* = 14

+  WM_HELP* = 83

+  WM_HOTKEY* = 786

+  WM_HSCROLL* = 276

+  WM_HSCROLLCLIPBOARD* = 782

+  WM_ICONERASEBKGND* = 39

+  WM_IME_CHAR* = 646

+  WM_IME_COMPOSITION* = 271

+  WM_IME_COMPOSITIONFULL* = 644

+  WM_IME_CONTROL* = 643

+  WM_IME_ENDCOMPOSITION* = 270

+  WM_IME_KEYDOWN* = 656

+  WM_IME_KEYUP* = 657

+  WM_IME_NOTIFY* = 642

+  WM_IME_SELECT* = 645

+  WM_IME_SETCONTEXT* = 641

+  WM_IME_STARTCOMPOSITION* = 269

+  WM_INITDIALOG* = 272

+  WM_INITMENU* = 278

+  WM_INITMENUPOPUP* = 279

+  WM_INPUTLANGCHANGE* = 81

+  WM_INPUTLANGCHANGEREQUEST* = 80

+  WM_KEYDOWN* = 256

+  WM_KEYUP* = 257

+  WM_KILLFOCUS* = 8

+  WM_LBUTTONDBLCLK* = 515

+  WM_LBUTTONDOWN* = 513

+  WM_LBUTTONUP* = 514

+  WM_MBUTTONDBLCLK* = 521

+  WM_MBUTTONDOWN* = 519

+  WM_MBUTTONUP* = 520

+  WM_MDIACTIVATE* = 546

+  WM_MDICASCADE* = 551

+  WM_MDICREATE* = 544

+  WM_MDIDESTROY* = 545

+  WM_MDIGETACTIVE* = 553

+  WM_MDIICONARRANGE* = 552

+  WM_MDIMAXIMIZE* = 549

+  WM_MDINEXT* = 548

+  WM_MDIREFRESHMENU* = 564

+  WM_MDIRESTORE* = 547

+  WM_MDISETMENU* = 560

+  WM_MDITILE* = 550

+  WM_MEASUREITEM* = 44

+  WM_MENUCHAR* = 288

+  WM_MENUSELECT* = 287

+  WM_MOUSEACTIVATE* = 33

+  WM_MOUSEMOVE* = 512

+  WM_MOUSEWHEEL* = 522

+  WM_MOUSEHOVER* = 673

+  WM_MOUSELEAVE* = 675

+  WM_MOVE* = 3

+  WM_MOVING* = 534

+  WM_NCACTIVATE* = 134

+  WM_NCCALCSIZE* = 131

+  WM_NCCREATE* = 129

+  WM_NCDESTROY* = 130

+  WM_NCHITTEST* = 132

+  WM_NCLBUTTONDBLCLK* = 163

+  WM_NCLBUTTONDOWN* = 161

+  WM_NCLBUTTONUP* = 162

+  WM_NCMBUTTONDBLCLK* = 169

+  WM_NCMBUTTONDOWN* = 167

+  WM_NCMBUTTONUP* = 168

+  WM_NCMOUSEMOVE* = 160

+  WM_NCPAINT* = 133

+  WM_NCRBUTTONDBLCLK* = 166

+  WM_NCRBUTTONDOWN* = 164

+  WM_NCRBUTTONUP* = 165

+  WM_NEXTDLGCTL* = 40

+  WM_NOTIFY* = 78

+  WM_NOTIFYFORMAT* = 85

+  WM_NULL* = 0

+  WM_PAINT* = 15

+  WM_PAINTCLIPBOARD* = 777

+  WM_PAINTICON* = 38

+  WM_PALETTECHANGED* = 785

+  WM_PALETTEISCHANGING* = 784

+  WM_PARENTNOTIFY* = 528

+  WM_PASTE* = 770

+  WM_PENWINFIRST* = 896

+  WM_PENWINLAST* = 911

+  WM_POWER* = 72

+  WM_POWERBROADCAST* = 536

+  WM_PRINT* = 791

+  WM_PRINTCLIENT* = 792

+  WM_PSD_ENVSTAMPRECT* = 1029

+  WM_PSD_FULLPAGERECT* = 1025

+  WM_PSD_GREEKTEXTRECT* = 1028

+  WM_PSD_MARGINRECT* = 1027

+  WM_PSD_MINMARGINRECT* = 1026

+  WM_PSD_PAGESETUPDLG* = 1024

+  WM_PSD_YAFULLPAGERECT* = 1030

+  WM_QUERYDRAGICON* = 55

+  WM_QUERYENDSESSION* = 17

+  WM_QUERYNEWPALETTE* = 783

+  WM_QUERYOPEN* = 19

+  WM_QUEUESYNC* = 35

+  WM_QUIT* = 18

+  WM_RBUTTONDBLCLK* = 518

+  WM_RBUTTONDOWN* = 516

+  WM_RBUTTONUP* = 517

+  WM_RENDERALLFORMATS* = 774

+  WM_RENDERFORMAT* = 773

+  WM_SETCURSOR* = 32

+  WM_SETFOCUS* = 7

+  WM_SETFONT* = 48

+  WM_SETHOTKEY* = 50

+  WM_SETICON* = 128

+  WM_SETREDRAW* = 11

+  WM_SETTEXT* = 12

+  WM_SETTINGCHANGE* = 26

+  WM_SHOWWINDOW* = 24

+  WM_SIZE* = 5

+  WM_SIZECLIPBOARD* = 779

+  WM_SIZING* = 532

+  WM_SPOOLERSTATUS* = 42

+  WM_STYLECHANGED* = 125

+  WM_STYLECHANGING* = 124

+  WM_SYSCHAR* = 262

+  WM_SYSCOLORCHANGE* = 21

+  WM_SYSCOMMAND* = 274

+  WM_SYSDEADCHAR* = 263

+  WM_SYSKEYDOWN* = 260

+  WM_SYSKEYUP* = 261

+  WM_TCARD* = 82

+  WM_TIMECHANGE* = 30

+  WM_TIMER* = 275

+  WM_UNDO* = 772

+  WM_USER* = 1024

+  WM_USERCHANGED* = 84

+  WM_VKEYTOITEM* = 46

+  WM_VSCROLL* = 277

+  WM_VSCROLLCLIPBOARD* = 778

+  WM_WINDOWPOSCHANGED* = 71

+  WM_WINDOWPOSCHANGING* = 70

+  WM_WININICHANGE* = 26

+  # Window message ranges

+  WM_KEYFIRST* = 256

+  WM_KEYLAST* = 264

+  WM_MOUSEFIRST* = 512

+  WM_MOUSELAST* = 525

+  WM_XBUTTONDOWN* = 523

+  WM_XBUTTONUP* = 524

+  WM_XBUTTONDBLCLK* = 525

+

+when defined(cpu64):

+  type

+    HALFLRESULT* = DWORD

+    HALFPARAM* = DWORD

+    HALFPARAMBOOL* = WINBOOL

+else:

+  type

+    HALFLRESULT* = int16

+    HALFPARAM* = int16

+    HALFPARAMBOOL* = WORDBOOL

+type

+  MSG* {.final, pure.} = object

+    hwnd*: HWND

+    message*: WINUINT

+    wParam*: WPARAM

+    lParam*: LPARAM

+    time*: DWORD

+    pt*: POINT

+

+  LPMSG* = ptr MSG

+  TMSG* = MSG

+  PMSG* = ptr MSG

+  PMessage* = ptr TMessage

+  TMessage* {.final, pure.} = object          #fields according to ICS

+    msg*: WINUINT

+    wParam*: WPARAM

+    lParam*: LPARAM

+    Result*: LRESULT

+

+  TWMSize* {.final, pure.} = object

+    Msg*: WINUINT

+    SizeType*: WPARAM

+    Width*: HALFPARAM

+    Height*: HALFPARAM

+    Result*: LRESULT

+

+  TWMNoParams* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: array[0..3, HALFPARAM]

+    Result*: LRESULT

+

+  TWMCancelMode* = TWMNoParams

+  TWMNCDestroy* = TWMNoParams

+  TWMDestroy* = TWMNoParams

+  TWMClose* = TWMNoParams

+  TWMQueryUIState* = TWMNoParams

+  TWMUIState* {.final, pure.} = object

+    Msg*: WINUINT

+    Action*: int16

+    Flags*: int16

+    Unused*: HRESULT

+

+  TWMChangeUIState* = TWMUIState

+  TWMUpdateUIState* = TWMUIState

+  TWMKey* {.final, pure.} = object

+    Msg*: WINUINT

+    CharCode*: int16

+    Unused*: int16

+    KeyData*: int32

+    Result*: LRESULT

+

+  TWMKeyDown* = TWMKey

+  TWMKeyUp* = TWMKey

+  TWMChar* = TWMKey

+  TWMSysChar* = TWMKey

+  TWMSysKeyDown* = TWMKey

+  TWMSysKeyUp* = TWMKey

+  TWMMenuChar* {.final, pure.} = object

+    Msg*: WINUINT

+    User*: char

+    MenuFlag*: int16

+    Menu*: HMENU

+    Result*: LRESULT

+

+  TWMGetDlgCode* = TWMNoParams

+  TWMFontChange* = TWMNoParams

+  TWMGetFont* = TWMNoParams

+  TWMSysColorChange* = TWMNoParams

+  TWMQueryDragIcon* = TWMNoParams

+  TWMScroll* {.final, pure.} = object

+    Msg*: WINUINT

+    ScrollCode*: HALFPARAM

+    Pos*: HALFPARAM

+    ScrollBar*: HWND

+    Result*: LRESULT

+

+  TWMHScroll* = TWMScroll

+  TWMVScroll* = TWMScroll

+  TWMGetText* {.final, pure.} = object

+    Msg*: WINUINT

+    TextMax*: LPARAM

+    Text*: cstring

+    Result*: LRESULT

+

+  TWMGetTextLength* = TWMNoParams

+  TWMKillFocus* {.final, pure.} = object

+    Msg*: WINUINT

+    FocusedWnd*: HWND

+    UnUsed*: WPARAM

+    Result*: LRESULT

+

+  TWMSetCursor* {.final, pure.} = object

+    Msg*: WINUINT

+    CursorWnd*: HWND

+    HitTest*: HALFPARAM

+    MouseMsg*: HALFPARAM

+    Result*: LRESULT

+

+  TWMSetFocus* {.final, pure.} = object

+    Msg*: WINUINT

+    FocusedWnd*: HWND

+    Unused*: WPARAM

+    Result*: LRESULT

+

+  TWMSetFont* {.final, pure.} = object

+    Msg*: WINUINT

+    Font*: HFONT

+    Redraw*: HALFPARAMBOOL

+    Unused*: HALFPARAM

+    Result*: LRESULT

+

+  TWMShowWindow* {.final, pure.} = object

+    Msg*: WINUINT

+    Show*: HALFPARAMBOOL

+    Unused*: HALFPARAM

+    Status*: WPARAM

+    Result*: LRESULT

+

+  TWMEraseBkgnd* {.final, pure.} = object

+    Msg*: WINUINT

+    DC*: HDC

+    Unused*: LPARAM

+    Result*: LRESULT

+

+  TWMNCHitTest* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int32

+    Pos*: TSmallPoint

+    Result*: LRESULT

+

+  TWMMouse* {.final, pure.} = object

+    Msg*: WINUINT

+    Keys*: int32

+    Pos*: TSmallPoint

+    Result*: LRESULT

+

+  TWMLButtonDblClk* = TWMMouse

+  TWMLButtonDown* = TWMMouse

+  TWMLButtonUp* = TWMMouse

+  TWMMButtonDblClk* = TWMMouse

+  TWMMButtonDown* = TWMMouse

+  TWMMButtonUp* = TWMMouse

+  TWMMouseWheel* {.final, pure.} = object

+    Msg*: WINUINT

+    Keys*: int16

+    WheelDelta*: int16

+    Pos*: TSmallPoint

+    Result*: LRESULT

+

+  TWMNCHitMessage* {.final, pure.} = object

+    Msg*: WINUINT

+    HitTest*: int32

+    XCursor*: int16

+    YCursor*: int16

+    Result*: LRESULT

+

+  TWMNCLButtonDblClk* = TWMNCHitMessage

+  TWMNCLButtonDown* = TWMNCHitMessage

+  TWMNCLButtonUp* = TWMNCHitMessage

+  TWMNCMButtonDblClk* = TWMNCHitMessage

+  TWMNCMButtonDown* = TWMNCHitMessage

+  TWMNCMButtonUp* = TWMNCHitMessage

+  TWMNCMouseMove* = TWMNCHitMessage

+  TWMRButtonDblClk* = TWMMouse

+  TWMRButtonDown* = TWMMouse

+  TWMRButtonUp* = TWMMouse

+  TWMMouseMove* = TWMMouse

+  TWMPaint* {.final, pure.} = object

+    Msg*: WINUINT

+    DC*: HDC

+    Unused*: int32

+    Result*: LRESULT

+

+  TWMCommand* {.final, pure.} = object

+    Msg*: WINUINT

+    ItemID*: int16

+    NotifyCode*: int16

+    Ctl*: HWND

+    Result*: LRESULT

+

+  TWMNotify* {.final, pure.} = object

+    Msg*: WINUINT

+    IDCtrl*: int32

+    NMHdr*: PNMHdr

+    Result*: LRESULT

+

+  TWMPrint* {.final, pure.} = object

+    Msg*: WINUINT

+    DC*: HDC

+    Flags*: int

+    Result*: LRESULT

+

+  TWMPrintClient* = TWMPrint

+  TWMWinIniChange* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    Section*: cstring

+    Result*: LRESULT

+

+  TWMContextMenu* {.final, pure.} = object

+    Msg*: WINUINT

+    hWnd*: HWND

+    Pos*: TSmallPoint

+    Result*: LRESULT

+

+  TWMNCCalcSize* {.final, pure.} = object

+    Msg*: WINUINT

+    CalcValidRects*: WINBOOL

+    CalcSize_Params*: PNCCalcSizeParams

+    Result*: LRESULT

+

+  TWMCharToItem* {.final, pure.} = object

+    Msg*: WINUINT

+    Key*: int16

+    CaretPos*: int16

+    ListBox*: HWND

+    Result*: LRESULT

+

+  TWMVKeyToItem* = TWMCharToItem

+  TMyEventRange = range[0'i16..16000'i16]

+  TWMParentNotify* {.final, pure.} = object

+    Msg*: WINUINT

+    case Event*: TMyEventRange

+    of TMyEventRange(WM_CREATE), TMyEventRange(WM_DESTROY):

+        ChildID*: int16

+        ChildWnd*: HWnd

+

+    of TMyEventRange(WM_LBUTTONDOWN),

+      TMyEventRange(WM_MBUTTONDOWN),

+      TMyEventRange(WM_RBUTTONDOWN):

+        Value*: int16

+        XPos*: int16

+        YPos*: int16

+

+    else:

+        Value1*: int16

+        Value2*: int32

+        Result*: LRESULT

+

+  TWMSysCommand* {.final, pure.} = object

+    Msg*: WINUINT

+    CmdType*: int32

+    XPos*: int16

+    YPos*: int16

+    Result*: LRESULT

+  #  case CmdType*: int32

+  #  of SC_HOTKEY:

+  #      ActivateWnd*: HWND

+  #  of SC_CLOSE, SC_HSCROLL, SC_MAXIMIZE, SC_MINIMIZE, SC_MOUSEMENU, SC_MOVE,

+  #     SC_NEXTWINDOW, SC_PREVWINDOW, SC_RESTORE, SC_SCREENSAVE, SC_SIZE,

+  #     SC_TASKLIST, SC_VSCROLL:

+  #      XPos*: int16

+  #      YPos*: int16

+  #      Result*: LRESULT

+  #  else: # of SC_KEYMENU:

+  #      Key*: int16

+

+  TWMMove* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    Pos*: TSmallPoint

+    Result*: LRESULT

+

+  TWMWindowPosMsg* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    WindowPos*: PWindowPos

+    Result*: LRESULT

+

+  TWMWindowPosChanged* = TWMWindowPosMsg

+  TWMWindowPosChanging* = TWMWindowPosMsg

+  TWMCompareItem* {.final, pure.} = object

+    Msg*: WINUINT

+    Ctl*: HWnd

+    CompareItemStruct*: PCompareItemStruct

+    Result*: LRESULT

+

+  TWMDeleteItem* {.final, pure.} = object

+    Msg*: WINUINT

+    Ctl*: HWND

+    DeleteItemStruct*: PDeleteItemStruct

+    Result*: LRESULT

+

+  TWMDrawItem* {.final, pure.} = object

+    Msg*: WINUINT

+    Ctl*: HWND

+    DrawItemStruct*: PDrawItemStruct

+    Result*: LRESULT

+

+  TWMMeasureItem* {.final, pure.} = object

+    Msg*: WINUINT

+    IDCtl*: HWnd

+    MeasureItemStruct*: PMeasureItemStruct

+    Result*: LRESULT

+

+  TWMNCCreate* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    CreateStruct*: PCreateStruct

+    Result*: LRESULT

+

+  TWMInitMenuPopup* {.final, pure.} = object

+    Msg*: WINUINT

+    MenuPopup*: HMENU

+    Pos*: int16

+    SystemMenu*: WordBool

+    Result*: LRESULT

+

+  TWMMenuSelect* {.final, pure.} = object

+    Msg*: WINUINT

+    IDItem*: int16

+    MenuFlag*: int16

+    Menu*: HMENU

+    Result*: LRESULT

+

+  TWMActivate* {.final, pure.} = object

+    Msg*: WINUINT

+    Active*: int16

+    Minimized*: WordBool

+    ActiveWindow*: HWND

+    Result*: LRESULT

+

+  TWMQueryEndSession* {.final, pure.} = object

+    Msg*: WINUINT

+    Source*: int32

+    Unused*: int32

+    Result*: LRESULT

+

+  TWMMDIActivate* {.final, pure.} = object

+    Msg*: WINUINT

+    DeactiveWnd*: HWND

+    ActiveWnd*: HWND

+    Result*: LRESULT

+

+  TWMNextDlgCtl* {.final, pure.} = object

+    Msg*: WINUINT

+    CtlFocus*: int32

+    Handle*: WordBool

+    Unused*: int16

+    Result*: LRESULT

+

+  TWMHelp* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    HelpInfo*: PHelpInfo

+    Result*: LRESULT

+

+  TWMGetMinMaxInfo* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    MinMaxInfo*: PMinMaxInfo

+    Result*: LRESULT

+

+  TWMSettingChange* {.final, pure.} = object

+    Msg*: WINUINT

+    Flag*: int

+    Section*: cstring

+    Result*: LRESULT

+

+  TWMCreate* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int

+    CreateStruct*: PCreateStruct

+    Result*: LRESULT

+

+  TWMCtlColor* {.final, pure.} = object

+    Msg*: WINUINT

+    ChildDC*: HDC

+    ChildWnd*: HWND

+    Result*: LRESULT

+

+  TWMCtlColorScrollbar* = TWMCtlColor

+  TWMCtlColorStatic* = TWMCtlColor

+  TWMCtlColorBtn* = TWMCtlColor

+  TWMCtlColorListbox* = TWMCtlColor

+  TWMCtlColorMsgbox* = TWMCtlColor

+  TWMCtlColorDlg* = TWMCtlColor

+  TWMCtlColorEdit* = TWMCtlColor

+  TWMInitDialog* {.final, pure.} = object

+    Msg*: WINUINT

+    Focus*: HWND

+    InitParam*: int32

+    Result*: LRESULT

+

+  TWMNCPaint* {.final, pure.} = object

+    Msg*: WINUINT

+    RGN*: HRGN

+    Unused*: int32

+    Result*: LRESULT

+

+  TWMSetText* {.final, pure.} = object

+    Msg*: WINUINT

+    Unused*: int32

+    Text*: cstring

+    Result*: LRESULT

+

+  TWMSizeClipboard* {.final, pure.} = object

+    Msg*: WINUINT

+    Viewer*: HWND

+    RC*: THandle

+    Result*: LRESULT

+

+  TWMSpoolerStatus* {.final, pure.} = object

+    Msg*: WINUINT

+    JobStatus*: LPARAM

+    JobsLeft*: WPARAM

+    Unused*: WPARAM

+    Result*: LRESULT

+

+  TWMStyleChange* {.final, pure.} = object

+    Msg*: WINUINT

+    StyleType*: LPARAM

+    StyleStruct*: PStyleStruct

+    Result*: LRESULT

+

+  TWMStyleChanged* = TWMStyleChange

+  TWMStyleChanging* = TWMStyleChange

+  TWMSysDeadChar* {.final, pure.} = object

+    Msg*: WINUINT

+    CharCode*: WPARAM

+    Unused*: WPARAM

+    KeyData*: LPARAM

+    Result*: LRESULT

+

+  TWMSystemError* {.final, pure.} = object

+    Msg*: WINUINT

+    ErrSpec*: WPARAM

+    Unused*: LPARAM

+    Result*: LRESULT

+

+  TWMTimeChange* = TWMNoParams

+  TWMTimer* {.final, pure.} = object

+    Msg*: WINUINT

+    TimerID*: LPARAM

+    TimerProc*: TFarProc

+    Result*: LRESULT

+

+  TWMUndo* = TWMNoParams

+  TWMVScrollClipboard* {.final, pure.} = object

+    Msg*: WINUINT

+    Viewer*: HWND

+    ScollCode*: WPARAM

+    ThumbPos*: WPARAM

+    Result*: LRESULT

+

+  TWMDisplayChange* {.final, pure.} = object

+    Msg*: WINUINT

+    BitsPerPixel*: int

+    Width*: WPARAM

+    Height*: WPARAM

+    Result*: LRESULT

+

+  TWMDropFiles* {.final, pure.} = object

+    Msg*: WINUINT

+    Drop*: THANDLE

+    Unused*: LPARAM

+    Result*: LRESULT

+

+  TWMEnable* {.final, pure.} = object

+    Msg*: int

+    Enabled*: WINBOOL

+    Unused*: int32

+    Result*: int32

+

+  TWMMouseActivate* {.final, pure.} = object

+    Msg*: int

+    TopLevel*: HWND

+    HitTestCode*: int16

+    MouseMsg*: int16

+    Result*: int32

+

+

+proc GetBinaryTypeA*(lpApplicationName: LPCSTR, lpBinaryType: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetBinaryTypeA".}

+

+proc GetShortPathNameA*(lpszLongPath: LPCSTR, lpszShortPath: LPSTR,

+                        cchBuffer: DWORD): DWORD{.stdcall,

+                        dynlib: "kernel32", importc.}

+proc GetEnvironmentStringsA*(): LPSTR{.stdcall, dynlib: "kernel32", importc.}

+proc FreeEnvironmentStringsA*(para1: LPSTR): WINBOOL{.stdcall, dynlib: "kernel32", importc.}

+proc FormatMessageA*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD,

+                     dwLanguageId: DWORD, lpBuffer: LPSTR, nSize: DWORD,

+                     Arguments: va_list): DWORD{.stdcall,dynlib: "kernel32", importc.}

+proc CreateMailslotA*(lpName: LPCSTR, nMaxMessageSize: DWORD,

+                      lReadTimeout: DWORD,

+                      lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+    stdcall, dynlib: "kernel32", importc.}

+proc lstrcmpA*(lpString1: LPCSTR, lpString2: LPCSTR): int32{.stdcall,

+  dynlib: "kernel32", importc.}

+proc lstrcmpiA*(lpString1: LPCSTR, lpString2: LPCSTR): int32{.stdcall, dynlib: "kernel32", importc.}

+proc lstrcpynA*(lpString1: LPSTR, lpString2: LPCSTR, iMaxLength: int32): LPSTR{.

+    stdcall, dynlib: "kernel32", importc.}

+proc CreateMutexA*(lpMutexAttributes: LPSECURITY_ATTRIBUTES,

+                   bInitialOwner: WINBOOL, lpName: LPCSTR): HANDLE{.stdcall,

+                   dynlib: "kernel32", importc.}

+proc OpenMutexA*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, lpName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc.}

+proc CreateEventA*(lpEventAttributes: LPSECURITY_ATTRIBUTES,

+                   bManualReset: WINBOOL, bInitialState: WINBOOL, lpName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc.}

+proc OpenEventA*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL, lpName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc.}

+proc CreateSemaphoreA*(lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES,

+                       lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc.}

+proc OpenSemaphoreA*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                     lpName: LPCSTR): HANDLE{.stdcall,

+                     dynlib: "kernel32", importc.}

+proc CreateFileMappingA*(hFile: HANDLE,

+                         lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,

+                         flProtect: DWORD, dwMaximumSizeHigh: DWORD,

+                         dwMaximumSizeLow: DWORD, lpName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc.}

+proc OpenFileMappingA*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                       lpName: LPCSTR): HANDLE{.stdcall,

+                       dynlib: "kernel32", importc.}

+proc GetLogicalDriveStringsA*(nBufferLength: DWORD, lpBuffer: LPSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc.}

+proc LoadLibraryA*(lpLibFileName: LPCSTR): HINST{.stdcall,

+  dynlib: "kernel32", importc.}

+proc LoadLibraryExA*(lpLibFileName: LPCSTR, hFile: HANDLE, dwFlags: DWORD): HINST{.

+    stdcall, dynlib: "kernel32", importc.}

+proc GetModuleFileNameA*(hModule: HINST, lpFilename: LPSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc.}

+proc GetModuleHandleA*(lpModuleName: LPCSTR): HMODULE{.stdcall,

+     dynlib: "kernel32", importc.}

+proc FatalAppExitA*(uAction: WINUINT, lpMessageText: LPCSTR){.stdcall,

+     dynlib: "kernel32", importc.}

+proc GetCommandLineA*(): LPSTR{.stdcall, dynlib: "kernel32", importc.}

+proc GetEnvironmentVariableA*(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc.}

+proc SetEnvironmentVariableA*(lpName: LPCSTR, lpValue: LPCSTR): WINBOOL{.stdcall,

+  dynlib: "kernel32", importc.}

+proc ExpandEnvironmentStringsA*(lpSrc: LPCSTR, lpDst: LPSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc.}

+proc OutputDebugStringA*(lpOutputString: LPCSTR){.stdcall,

+   dynlib: "kernel32", importc.}

+proc FindResourceA*(hModule: HINST, lpName: LPCSTR, lpType: LPCSTR): HRSRC{.

+    stdcall, dynlib: "kernel32", importc.}

+proc FindResourceExA*(hModule: HINST, lpType: LPCSTR, lpName: LPCSTR,

+                      wLanguage: int16): HRSRC{.stdcall,

+                      dynlib: "kernel32", importc.}

+proc EnumResourceTypesA*(hModule: HINST, lpEnumFunc: ENUMRESTYPEPROC,

+                         lParam: LONG): WINBOOL{.stdcall,

+                         dynlib: "kernel32", importc.}

+proc EnumResourceNamesA*(hModule: HINST, lpType: LPCSTR,

+                         lpEnumFunc: ENUMRESNAMEPROC, lParam: LONG): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc.}

+proc EnumResourceLanguagesA*(hModule: HINST, lpType: LPCSTR, lpName: LPCSTR,

+                             lpEnumFunc: ENUMRESLANGPROC, lParam: LONG): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumResourceLanguagesA".}

+

+proc BeginUpdateResourceA*(pFileName: LPCSTR, bDeleteExistingResources: WINBOOL): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "BeginUpdateResourceA".}

+

+proc UpdateResourceA*(hUpdate: HANDLE, lpType: LPCSTR, lpName: LPCSTR,

+                      wLanguage: int16, lpData: LPVOID, cbData: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "UpdateResourceA".}

+proc EndUpdateResourceA*(hUpdate: HANDLE, fDiscard: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "EndUpdateResourceA".}

+proc GlobalAddAtomA*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "GlobalAddAtomA".}

+proc GlobalFindAtomA*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "GlobalFindAtomA".}

+proc GlobalGetAtomNameA*(nAtom: ATOM, lpBuffer: LPSTR, nSize: int32): WINUINT{.

+    stdcall, dynlib: "kernel32", importc: "GlobalGetAtomNameA".}

+proc AddAtomA*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+                                        importc: "AddAtomA".}

+proc FindAtomA*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "FindAtomA".}

+proc GetAtomNameA*(nAtom: ATOM, lpBuffer: LPSTR, nSize: int32): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetAtomNameA".}

+proc GetProfileIntA*(lpAppName: LPCSTR, lpKeyName: LPCSTR, nDefault: WINT): WINUINT{.

+    stdcall, dynlib: "kernel32", importc: "GetProfileIntA".}

+proc GetProfileStringA*(lpAppName: LPCSTR, lpKeyName: LPCSTR, lpDefault: LPCSTR,

+                        lpReturnedString: LPSTR, nSize: DWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetProfileStringA".}

+proc WriteProfileStringA*(lpAppName: LPCSTR, lpKeyName: LPCSTR, lpString: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteProfileStringA".}

+proc GetProfileSectionA*(lpAppName: LPCSTR, lpReturnedString: LPSTR,

+                         nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetProfileSectionA".}

+proc WriteProfileSectionA*(lpAppName: LPCSTR, lpString: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteProfileSectionA".}

+proc GetPrivateProfileIntA*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                            nDefault: WINT, lpFileName: LPCSTR): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetPrivateProfileIntA".}

+proc GetPrivateProfileStringA*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                               lpDefault: LPCSTR, lpReturnedString: LPSTR,

+                               nSize: DWORD, lpFileName: LPCSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStringA".}

+

+proc WritePrivateProfileStringA*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                                 lpString: LPCSTR, lpFileName: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStringA".}

+proc GetPrivateProfileSectionA*(lpAppName: LPCSTR, lpReturnedString: LPSTR,

+                                nSize: DWORD, lpFileName: LPCSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileSectionA".}

+proc WritePrivateProfileSectionA*(lpAppName: LPCSTR, lpString: LPCSTR,

+                                  lpFileName: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WritePrivateProfileSectionA".}

+proc GetDriveTypeA*(lpRootPathName: LPCSTR): WINUINT{.stdcall, dynlib: "kernel32",

+    importc: "GetDriveTypeA".}

+proc GetSystemDirectoryA*(lpBuffer: LPSTR, uSize: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetSystemDirectoryA".}

+proc GetTempPathA*(nBufferLength: DWORD, lpBuffer: LPSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetTempPathA".}

+proc GetTempFileNameA*(lpPathName: LPCSTR, lpPrefixString: LPCSTR,

+                       uUnique: WINUINT, lpTempFileName: LPSTR): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetTempFileNameA".}

+proc GetWindowsDirectoryA*(lpBuffer: LPSTR, uSize: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetWindowsDirectoryA".}

+proc SetCurrentDirectoryA*(lpPathName: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetCurrentDirectoryA".}

+proc GetCurrentDirectoryA*(nBufferLength: DWORD, lpBuffer: LPSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetCurrentDirectoryA".}

+proc GetDiskFreeSpaceA*(lpRootPathName: LPCSTR, lpSectorsPerCluster: LPDWORD,

+                        lpBytesPerSector: LPDWORD,

+                        lpNumberOfFreeClusters: LPDWORD,

+                        lpTotalNumberOfClusters: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDiskFreeSpaceA".}

+proc CreateDirectoryA*(lpPathName: LPCSTR,

+

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateDirectoryA".}

+proc CreateDirectoryExA*(lpTemplateDirectory: LPCSTR, lpNewDirectory: LPCSTR,

+                         lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateDirectoryExA".}

+proc RemoveDirectoryA*(lpPathName: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "RemoveDirectoryA".}

+proc GetFullPathNameA*(lpFileName: LPCSTR, nBufferLength: DWORD,

+                       lpBuffer: LPSTR, lpFilePart: var LPSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetFullPathNameA".}

+proc DefineDosDeviceA*(dwFlags: DWORD, lpDeviceName: LPCSTR,

+                       lpTargetPath: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "DefineDosDeviceA".}

+proc QueryDosDeviceA*(lpDeviceName: LPCSTR, lpTargetPath: LPSTR, ucchMax: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "QueryDosDeviceA".}

+proc CreateFileA*(lpFileName: LPCSTR, dwDesiredAccess: DWORD,

+                  dwShareMode: DWORD,

+                  lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                  dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD,

+                  hTemplateFile: HANDLE): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "CreateFileA".}

+proc SetFileAttributesA*(lpFileName: LPCSTR, dwFileAttributes: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}

+proc GetFileAttributesA*(lpFileName: LPCSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetFileAttributesA".}

+proc GetCompressedFileSizeA*(lpFileName: LPCSTR, lpFileSizeHigh: LPDWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetCompressedFileSizeA".}

+proc DeleteFileA*(lpFileName: LPCSTR): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "DeleteFileA".}

+proc SearchPathA*(lpPath: LPCSTR, lpFileName: LPCSTR, lpExtension: LPCSTR,

+                  nBufferLength: DWORD, lpBuffer: LPSTR, lpFilePart: LPSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "SearchPathA".}

+proc CopyFileA*(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,

+                bFailIfExists: WINBOOL): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CopyFileA".}

+proc MoveFileA*(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "MoveFileA".}

+proc MoveFileExA*(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,

+                  dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "MoveFileExA".}

+proc CreateNamedPipeA*(lpName: LPCSTR, dwOpenMode: DWORD, dwPipeMode: DWORD,

+                       nMaxInstances: DWORD, nOutBufferSize: DWORD,

+                       nInBufferSize: DWORD, nDefaultTimeOut: DWORD,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "CreateNamedPipeA".}

+proc GetNamedPipeHandleStateA*(hNamedPipe: HANDLE, lpState: LPDWORD,

+                               lpCurInstances: LPDWORD,

+                               lpMaxCollectionCount: LPDWORD,

+                               lpCollectDataTimeout: LPDWORD, lpUserName: LPSTR,

+                               nMaxUserNameSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetNamedPipeHandleStateA".}

+proc CallNamedPipeA*(lpNamedPipeName: LPCSTR, lpInBuffer: LPVOID,

+                     nInBufferSize: DWORD, lpOutBuffer: LPVOID,

+                     nOutBufferSize: DWORD, lpBytesRead: LPDWORD,

+                     nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CallNamedPipeA".}

+proc WaitNamedPipeA*(lpNamedPipeName: LPCSTR, nTimeOut: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WaitNamedPipeA".}

+proc SetVolumeLabelA*(lpRootPathName: LPCSTR, lpVolumeName: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetVolumeLabelA".}

+proc GetVolumeInformationA*(lpRootPathName: LPCSTR, lpVolumeNameBuffer: LPSTR,

+                            nVolumeNameSize: DWORD,

+                            lpVolumeSerialNumber: LPDWORD,

+                            lpMaximumComponentLength: LPDWORD,

+                            lpFileSystemFlags: LPDWORD,

+                            lpFileSystemNameBuffer: LPSTR,

+                            nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVolumeInformationA".}

+proc ClearEventLogA*(hEventLog: HANDLE, lpBackupFileName: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ClearEventLogA".}

+proc BackupEventLogA*(hEventLog: HANDLE, lpBackupFileName: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "BackupEventLogA".}

+proc OpenEventLogA*(lpUNCServerName: LPCSTR, lpSourceName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "OpenEventLogA".}

+proc RegisterEventSourceA*(lpUNCServerName: LPCSTR, lpSourceName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "RegisterEventSourceA".}

+proc OpenBackupEventLogA*(lpUNCServerName: LPCSTR, lpFileName: LPCSTR): HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "OpenBackupEventLogA".}

+proc ReadEventLogA*(hEventLog: HANDLE, dwReadFlags: DWORD,

+                    dwRecordOffset: DWORD, lpBuffer: LPVOID,

+                    nNumberOfBytesToRead: DWORD, pnBytesRead: LPDWORD,

+                    pnMinNumberOfBytesNeeded: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ReadEventLogA".}

+proc ReportEventA*(hEventLog: HANDLE, wType: int16, wCategory: int16,

+                   dwEventID: DWORD, lpUserSid: PSID, wNumStrings: int16,

+                   dwDataSize: DWORD, lpStrings: LPPCSTR, lpRawData: LPVOID): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ReportEventA".}

+proc AccessCheckAndAuditAlarmA*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                                ObjectTypeName: LPSTR, ObjectName: LPSTR,

+                                SecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                DesiredAccess: DWORD,

+                                GenericMapping: PGENERIC_MAPPING,

+                                ObjectCreation: WINBOOL, GrantedAccess: LPDWORD,

+                                AccessStatus: LPBOOL, pfGenerateOnClose: LPBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AccessCheckAndAuditAlarmA".}

+proc ObjectOpenAuditAlarmA*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                            ObjectTypeName: LPSTR, ObjectName: LPSTR,

+                            pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                            ClientToken: HANDLE, DesiredAccess: DWORD,

+                            GrantedAccess: DWORD, Privileges: PPRIVILEGE_SET,

+                            ObjectCreation: WINBOOL, AccessGranted: WINBOOL,

+                            GenerateOnClose: LPBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectOpenAuditAlarmA".}

+proc ObjectPrivilegeAuditAlarmA*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                                 ClientToken: HANDLE, DesiredAccess: DWORD,

+                                 Privileges: PPRIVILEGE_SET,

+                                 AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmA".}

+proc ObjectCloseAuditAlarmA*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                             GenerateOnClose: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectCloseAuditAlarmA".}

+proc PrivilegedServiceAuditAlarmA*(SubsystemName: LPCSTR, ServiceName: LPCSTR,

+                                   ClientToken: HANDLE,

+                                   Privileges: PPRIVILEGE_SET,

+                                   AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmA".}

+proc SetFileSecurityA*(lpFileName: LPCSTR,

+                       SecurityInformation: SECURITY_INFORMATION,

+                       pSecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetFileSecurityA".}

+proc GetFileSecurityA*(lpFileName: LPCSTR,

+                       RequestedInformation: SECURITY_INFORMATION,

+                       pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                       nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetFileSecurityA".}

+proc FindFirstChangeNotificationA*(lpPathName: LPCSTR, bWatchSubtree: WINBOOL,

+                                   dwNotifyFilter: DWORD): HANDLE{.stdcall,

+    dynlib: "kernel32", importc: "FindFirstChangeNotificationA".}

+proc IsBadStringPtrA*(lpsz: LPCSTR, ucchMax: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsBadStringPtrA".}

+proc LookupAccountSidA*(lpSystemName: LPCSTR, Sid: PSID, Name: LPSTR,

+                        cbName: LPDWORD, ReferencedDomainName: LPSTR,

+                        cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupAccountSidA".}

+proc LookupAccountNameA*(lpSystemName: LPCSTR, lpAccountName: LPCSTR, Sid: PSID,

+                         cbSid: LPDWORD, ReferencedDomainName: LPSTR,

+                         cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupAccountNameA".}

+proc LookupPrivilegeValueA*(lpSystemName: LPCSTR, lpName: LPCSTR, lpLuid: PLUID): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupPrivilegeValueA".}

+proc LookupPrivilegeNameA*(lpSystemName: LPCSTR, lpLuid: PLUID, lpName: LPSTR,

+                           cbName: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeNameA".}

+proc LookupPrivilegeDisplayNameA*(lpSystemName: LPCSTR, lpName: LPCSTR,

+                                  lpDisplayName: LPSTR, cbDisplayName: LPDWORD,

+                                  lpLanguageId: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameA".}

+proc BuildCommDCBA*(lpDef: LPCSTR, lpDCB: LPDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "BuildCommDCBA".}

+proc BuildCommDCBAndTimeoutsA*(lpDef: LPCSTR, lpDCB: LPDCB,

+                               lpCommTimeouts: LPCOMMTIMEOUTS): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsA".}

+proc CommConfigDialogA*(lpszName: LPCSTR, wnd: HWND, lpCC: LPCOMMCONFIG): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CommConfigDialogA".}

+proc GetDefaultCommConfigA*(lpszName: LPCSTR, lpCC: LPCOMMCONFIG,

+                            lpdwSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDefaultCommConfigA".}

+proc SetDefaultCommConfigA*(lpszName: LPCSTR, lpCC: LPCOMMCONFIG, dwSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetDefaultCommConfigA".}

+proc GetComputerNameA*(lpBuffer: LPSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetComputerNameA".}

+proc SetComputerNameA*(lpComputerName: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetComputerNameA".}

+proc GetUserNameA*(lpBuffer: LPSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetUserNameA".}

+proc LoadKeyboardLayoutA*(pwszKLID: LPCSTR, Flags: WINUINT): HKL{.stdcall,

+    dynlib: "user32", importc: "LoadKeyboardLayoutA".}

+proc GetKeyboardLayoutNameA*(pwszKLID: LPSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetKeyboardLayoutNameA".}

+proc CreateDesktopA*(lpszDesktop: LPSTR, lpszDevice: LPSTR, pDevmode: LPDEVMODE,

+                     dwFlags: DWORD, dwDesiredAccess: DWORD,

+                     lpsa: LPSECURITY_ATTRIBUTES): HDESK{.stdcall,

+    dynlib: "user32", importc: "CreateDesktopA".}

+proc OpenDesktopA*(lpszDesktop: LPSTR, dwFlags: DWORD, fInherit: WINBOOL,

+                   dwDesiredAccess: DWORD): HDESK{.stdcall, dynlib: "user32",

+    importc: "OpenDesktopA".}

+proc EnumDesktopsA*(hwinsta: HWINSTA, lpEnumFunc: DESKTOPENUMPROC,

+                    lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "EnumDesktopsA".}

+proc CreateWindowStationA*(lpwinsta: LPSTR, dwReserved: DWORD,

+                           dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HWINSTA{.

+    stdcall, dynlib: "user32", importc: "CreateWindowStationA".}

+proc OpenWindowStationA*(lpszWinSta: LPSTR, fInherit: WINBOOL,

+                         dwDesiredAccess: DWORD): HWINSTA{.stdcall,

+    dynlib: "user32", importc: "OpenWindowStationA".}

+proc EnumWindowStationsA*(lpEnumFunc: ENUMWINDOWSTATIONPROC, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnumWindowStationsA".}

+proc GetUserObjectInformationA*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUserObjectInformationA".}

+proc SetUserObjectInformationA*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                nLength: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetUserObjectInformationA".}

+proc RegisterWindowMessageA*(lpString: LPCSTR): WINUINT{.stdcall, dynlib: "user32",

+    importc: "RegisterWindowMessageA".}

+proc GetMessageA*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                  wMsgFilterMax: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetMessageA".}

+proc DispatchMessageA*(lpMsg: LPMSG): LONG{.stdcall, dynlib: "user32",

+    importc: "DispatchMessageA".}

+proc PeekMessageA*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                   wMsgFilterMax: WINUINT, wRemoveMsg: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "PeekMessageA".}

+proc SendMessageA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageA".}

+proc SendMessageTimeoutA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM,

+                          fuFlags: WINUINT, uTimeout: WINUINT, lpdwResult: LPDWORD): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageTimeoutA".}

+proc SendNotifyMessageA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SendNotifyMessageA".}

+proc SendMessageCallbackA*(wnd: HWND, Msg: WINUINT, wp: WPARAM,

+                           lp: LPARAM, lpResultCallBack: SENDASYNCPROC,

+                           dwData: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SendMessageCallbackA".}

+proc PostMessageA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "PostMessageA".}

+proc PostThreadMessageA*(idThread: DWORD, Msg: WINUINT, wp: WPARAM,

+                         lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "PostThreadMessageA".}

+proc DefWindowProcA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "DefWindowProcA".}

+proc CallWindowProcA*(lpPrevWndFunc: WNDPROC, wnd: HWND, Msg: WINUINT,

+                      wp: WPARAM, lp: LPARAM): LRESULT{.stdcall,

+    dynlib: "user32", importc: "CallWindowProcA".}

+proc RegisterClassA*(lpWndClass: LPWNDCLASS): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassA".}

+proc UnregisterClassA*(lpClassName: LPCSTR, hInstance: HINST): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "UnregisterClassA".}

+proc GetClassInfoA*(hInstance: HINST, lpClassName: LPCSTR,

+                    lpWndClass: LPWNDCLASS): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetClassInfoA".}

+proc RegisterClassExA*(para1: LPWNDCLASSEX): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassExA".}

+proc GetClassInfoExA*(para1: HINST, para2: LPCSTR, para3: LPWNDCLASSEX): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetClassInfoExA".}

+proc CreateWindowExA*(dwExStyle: DWORD, lpClassName: LPCSTR,

+                      lpWindowName: LPCSTR, dwStyle: DWORD, X: int32, Y: int32,

+                      nWidth: int32, nHeight: int32, hWndParent: HWND,

+                      menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND{.

+    stdcall, dynlib: "user32", importc: "CreateWindowExA".}

+proc CreateDialogParamA*(hInstance: HINST, lpTemplateName: LPCSTR,

+                         hWndParent: HWND, lpDialogFunc: DLGPROC,

+                         dwInitParam: LPARAM): HWND{.stdcall, dynlib: "user32",

+    importc: "CreateDialogParamA".}

+proc CreateDialogIndirectParamA*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                                 hWndParent: HWND, lpDialogFunc: DLGPROC,

+                                 dwInitParam: LPARAM): HWND{.stdcall,

+    dynlib: "user32", importc: "CreateDialogIndirectParamA".}

+proc DialogBoxParamA*(hInstance: HINST, lpTemplateName: LPCSTR,

+                      hWndParent: HWND, lpDialogFunc: DLGPROC,

+                      dwInitParam: LPARAM): int32{.stdcall, dynlib: "user32",

+    importc: "DialogBoxParamA".}

+proc DialogBoxIndirectParamA*(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE,

+                              hWndParent: HWND, lpDialogFunc: DLGPROC,

+                              dwInitParam: LPARAM): int32{.stdcall,

+    dynlib: "user32", importc: "DialogBoxIndirectParamA".}

+proc SetDlgItemTextA*(hDlg: HWND, nIDDlgItem: int32, lpString: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetDlgItemTextA".}

+proc GetDlgItemTextA*(hDlg: HWND, nIDDlgItem: int32, lpString: LPSTR,

+                      nMaxCount: int32): WINUINT{.stdcall, dynlib: "user32",

+    importc: "GetDlgItemTextA".}

+proc SendDlgItemMessageA*(hDlg: HWND, nIDDlgItem: int32, Msg: WINUINT,

+                          wp: WPARAM, lp: LPARAM): LONG{.stdcall,

+    dynlib: "user32", importc: "SendDlgItemMessageA".}

+proc DefDlgProcA*(hDlg: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "DefDlgProcA".}

+proc CallMsgFilterA*(lpMsg: LPMSG, nCode: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CallMsgFilterA".}

+proc RegisterClipboardFormatA*(lpszFormat: LPCSTR): WINUINT{.stdcall,

+    dynlib: "user32", importc: "RegisterClipboardFormatA".}

+proc GetClipboardFormatNameA*(format: WINUINT, lpszFormatName: LPSTR,

+                              cchMaxCount: int32): int32{.stdcall,

+    dynlib: "user32", importc: "GetClipboardFormatNameA".}

+proc CharToOemA*(lpszSrc: LPCSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CharToOemA".}

+proc OemToCharA*(lpszSrc: LPCSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "OemToCharA".}

+proc CharToOemBuffA*(lpszSrc: LPCSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "CharToOemBuffA".}

+proc OemToCharBuffA*(lpszSrc: LPCSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "OemToCharBuffA".}

+proc CharUpperA*(lpsz: LPSTR): LPSTR{.stdcall, dynlib: "user32",

+                                      importc: "CharUpperA".}

+proc CharUpperBuffA*(lpsz: LPSTR, cchLength: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "CharUpperBuffA".}

+proc CharLowerA*(lpsz: LPSTR): LPSTR{.stdcall, dynlib: "user32",

+                                      importc: "CharLowerA".}

+proc CharLowerBuffA*(lpsz: LPSTR, cchLength: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "CharLowerBuffA".}

+proc CharNextA*(lpsz: LPCSTR): LPSTR{.stdcall, dynlib: "user32",

+                                      importc: "CharNextA".}

+proc CharPrevA*(lpszStart: LPCSTR, lpszCurrent: LPCSTR): LPSTR{.stdcall,

+    dynlib: "user32", importc: "CharPrevA".}

+proc IsCharAlphaA*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+                                       importc: "IsCharAlphaA".}

+proc IsCharAlphaNumericA*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsCharAlphaNumericA".}

+proc IsCharUpperA*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+                                       importc: "IsCharUpperA".}

+proc IsCharLowerA*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+                                       importc: "IsCharLowerA".}

+proc GetKeyNameTextA*(lParam: LONG, lpString: LPSTR, nSize: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetKeyNameTextA".}

+proc VkKeyScanA*(ch: char): SHORT{.stdcall, dynlib: "user32",

+                                   importc: "VkKeyScanA".}

+proc VkKeyScanExA*(ch: char, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32",

+    importc: "VkKeyScanExA".}

+proc MapVirtualKeyA*(uCode: WINUINT, uMapType: WINUINT): WINUINT{.stdcall,

+    dynlib: "user32", importc: "MapVirtualKeyA".}

+proc MapVirtualKeyExA*(uCode: WINUINT, uMapType: WINUINT, dwhkl: HKL): WINUINT{.stdcall,

+    dynlib: "user32", importc: "MapVirtualKeyExA".}

+proc LoadAcceleratorsA*(hInstance: HINST, lpTableName: LPCSTR): HACCEL{.stdcall,

+    dynlib: "user32", importc: "LoadAcceleratorsA".}

+proc CreateAcceleratorTableA*(para1: LPACCEL, para2: int32): HACCEL{.stdcall,

+    dynlib: "user32", importc: "CreateAcceleratorTableA".}

+proc CopyAcceleratorTableA*(hAccelSrc: HACCEL, lpAccelDst: LPACCEL,

+                            cAccelEntries: int32): int32{.stdcall,

+    dynlib: "user32", importc: "CopyAcceleratorTableA".}

+proc TranslateAcceleratorA*(wnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG): int32{.

+    stdcall, dynlib: "user32", importc: "TranslateAcceleratorA".}

+proc LoadMenuA*(hInstance: HINST, lpMenuName: LPCSTR): HMENU{.stdcall,

+    dynlib: "user32", importc: "LoadMenuA".}

+proc LoadMenuIndirectA*(lpMenuTemplate: LPMENUTEMPLATE): HMENU{.stdcall,

+    dynlib: "user32", importc: "LoadMenuIndirectA".}

+proc ChangeMenuA*(menu: HMENU, cmd: WINUINT, lpszNewItem: LPCSTR, cmdInsert: WINUINT,

+                  flags: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ChangeMenuA".}

+proc GetMenuStringA*(menu: HMENU, uIDItem: WINUINT, lpString: LPSTR,

+                     nMaxCount: int32, uFlag: WINUINT): int32{.stdcall,

+    dynlib: "user32", importc: "GetMenuStringA".}

+proc InsertMenuA*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT, uIDNewItem: WINUINT,

+                  lpNewItem: LPCSTR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "InsertMenuA".}

+proc AppendMenuA*(menu: HMENU, uFlags: WINUINT, uIDNewItem: WINUINT,

+                  lpNewItem: LPCSTR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "AppendMenuA".}

+proc ModifyMenuA*(hMnu: HMENU, uPosition: WINUINT, uFlags: WINUINT, uIDNewItem: WINUINT,

+                  lpNewItem: LPCSTR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ModifyMenuA".}

+proc InsertMenuItemA*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                      para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "InsertMenuItemA".}

+proc GetMenuItemInfoA*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                       para4: LPMENUITEMINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetMenuItemInfoA".}

+proc SetMenuItemInfoA*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                       para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetMenuItemInfoA".}

+proc DrawTextA*(hDC: HDC, lpString: LPCSTR, nCount: int32, lpRect: LPRECT,

+                uFormat: WINUINT): int32{.stdcall, dynlib: "user32",

+                                       importc: "DrawTextA".}

+proc DrawTextExA*(para1: HDC, para2: LPSTR, para3: int32, para4: LPRECT,

+                  para5: WINUINT, para6: LPDRAWTEXTPARAMS): int32{.stdcall,

+    dynlib: "user32", importc: "DrawTextExA".}

+proc GrayStringA*(hDC: HDC, hBrush: HBRUSH, lpOutputFunc: GRAYSTRINGPROC,

+                  lpData: LPARAM, nCount: int32, X: int32, Y: int32,

+                  nWidth: int32, nHeight: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GrayStringA".}

+proc DrawStateA*(para1: HDC, para2: HBRUSH, para3: DRAWSTATEPROC, para4: LPARAM,

+                 para5: WPARAM, para6: int32, para7: int32, para8: int32,

+                 para9: int32, para10: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DrawStateA".}

+proc TabbedTextOutA*(hDC: HDC, X: int32, Y: int32, lpString: LPCSTR,

+                     nCount: int32, nTabPositions: int32,

+                     lpnTabStopPositions: LPINT, nTabOrigin: int32): LONG{.

+    stdcall, dynlib: "user32", importc: "TabbedTextOutA".}

+proc GetTabbedTextExtentA*(hDC: HDC, lpString: LPCSTR, nCount: int32,

+                           nTabPositions: int32, lpnTabStopPositions: LPINT): DWORD{.

+    stdcall, dynlib: "user32", importc: "GetTabbedTextExtentA".}

+proc SetPropA*(wnd: HWND, lpString: LPCSTR, hData: HANDLE): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetPropA".}

+proc GetPropA*(wnd: HWND, lpString: LPCSTR): HANDLE{.stdcall, dynlib: "user32",

+    importc: "GetPropA".}

+proc RemovePropA*(wnd: HWND, lpString: LPCSTR): HANDLE{.stdcall,

+    dynlib: "user32", importc: "RemovePropA".}

+proc EnumPropsExA*(wnd: HWND, lpEnumFunc: PROPENUMPROCEX, lp: LPARAM): int32{.

+    stdcall, dynlib: "user32", importc: "EnumPropsExA".}

+proc EnumPropsA*(wnd: HWND, lpEnumFunc: PROPENUMPROC): int32{.stdcall,

+    dynlib: "user32", importc: "EnumPropsA".}

+proc SetWindowTextA*(wnd: HWND, lpString: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetWindowTextA".}

+proc GetWindowTextA*(wnd: HWND, lpString: LPSTR, nMaxCount: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetWindowTextA".}

+proc GetWindowTextLengthA*(wnd: HWND): int32{.stdcall, dynlib: "user32",

+    importc: "GetWindowTextLengthA".}

+proc MessageBoxA*(wnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: int): int32{.

+    stdcall, dynlib: "user32", importc: "MessageBoxA".}

+proc MessageBoxExA*(wnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: WINUINT,

+                    wLanguageId: int16): int32{.stdcall, dynlib: "user32",

+    importc: "MessageBoxExA".}

+proc MessageBoxIndirectA*(para1: LPMSGBOXPARAMS): int32{.stdcall,

+    dynlib: "user32", importc: "MessageBoxIndirectA".}

+proc GetWindowLongA*(wnd: HWND, nIndex: int32): LONG{.stdcall,

+    dynlib: "user32", importc: "GetWindowLongA".}

+proc SetWindowLongA*(wnd: HWND, nIndex: int32, dwNewLong: LONG): LONG{.stdcall,

+    dynlib: "user32", importc: "SetWindowLongA".}

+proc GetClassLongA*(wnd: HWND, nIndex: int32): DWORD{.stdcall,

+    dynlib: "user32", importc: "GetClassLongA".}

+proc SetClassLongA*(wnd: HWND, nIndex: int32, dwNewLong: LONG): DWORD{.stdcall,

+    dynlib: "user32", importc: "SetClassLongA".}

+when defined(cpu64):

+  proc GetWindowLongPtrA*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetWindowLongPtrA".}

+  proc SetWindowLongPtrA*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetWindowLongPtrA".}

+  proc GetClassLongPtrA*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetClassLongPtrA".}

+  proc SetClassLongPtrA*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetClassLongPtrA".}

+else:

+  proc GetWindowLongPtrA*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetWindowLongA".}

+  proc SetWindowLongPtrA*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetWindowLongA".}

+  proc GetClassLongPtrA*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetClassLongA".}

+  proc SetClassLongPtrA*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetClassLongA".}

+proc FindWindowA*(lpClassName: LPCSTR, lpWindowName: LPCSTR): HWND{.stdcall,

+    dynlib: "user32", importc: "FindWindowA".}

+proc FindWindowExA*(para1: HWND, para2: HWND, para3: LPCSTR, para4: LPCSTR): HWND{.

+    stdcall, dynlib: "user32", importc: "FindWindowExA".}

+proc GetClassNameA*(wnd: HWND, lpClassName: LPSTR, nMaxCount: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetClassNameA".}

+proc SetWindowsHookExA*(idHook: int32, lpfn: HOOKPROC, hmod: HINST,

+                        dwThreadId: DWORD): HHOOK{.stdcall, dynlib: "user32",

+    importc: "SetWindowsHookExA".}

+proc LoadBitmapA*(hInstance: HINST, lpBitmapName: LPCSTR): HBITMAP{.stdcall,

+    dynlib: "user32", importc: "LoadBitmapA".}

+proc LoadCursorA*(hInstance: HINST, lpCursorName: LPCSTR): HCURSOR{.stdcall,

+    dynlib: "user32", importc: "LoadCursorA".}

+proc LoadCursorFromFileA*(lpFileName: LPCSTR): HCURSOR{.stdcall,

+    dynlib: "user32", importc: "LoadCursorFromFileA".}

+proc LoadIconA*(hInstance: HINST, lpIconName: LPCSTR): HICON{.stdcall,

+    dynlib: "user32", importc: "LoadIconA".}

+proc LoadImageA*(para1: HINST, para2: LPCSTR, para3: WINUINT, para4: int32,

+                 para5: int32, para6: WINUINT): HANDLE{.stdcall, dynlib: "user32",

+    importc: "LoadImageA".}

+proc LoadStringA*(hInstance: HINST, uID: WINUINT, lpBuffer: LPSTR,

+                  nBufferMax: int32): int32{.stdcall, dynlib: "user32",

+    importc: "LoadStringA".}

+proc IsDialogMessageA*(hDlg: HWND, lpMsg: LPMSG): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "IsDialogMessageA".}

+proc DlgDirListA*(hDlg: HWND, lpPathSpec: LPSTR, nIDListBox: int32,

+                  nIDStaticPath: int32, uFileType: WINUINT): int32{.stdcall,

+    dynlib: "user32", importc: "DlgDirListA".}

+proc DlgDirSelectExA*(hDlg: HWND, lpString: LPSTR, nCount: int32,

+                      nIDListBox: int32): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DlgDirSelectExA".}

+proc DlgDirListComboBoxA*(hDlg: HWND, lpPathSpec: LPSTR, nIDComboBox: int32,

+                          nIDStaticPath: int32, uFiletype: WINUINT): int32{.

+    stdcall, dynlib: "user32", importc: "DlgDirListComboBoxA".}

+proc DlgDirSelectComboBoxExA*(hDlg: HWND, lpString: LPSTR, nCount: int32,

+                              nIDComboBox: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DlgDirSelectComboBoxExA".}

+proc DefFrameProcA*(wnd: HWND, hWndMDIClient: HWND, uMsg: WINUINT, wp: WPARAM,

+                    lp: LPARAM): LRESULT{.stdcall, dynlib: "user32",

+    importc: "DefFrameProcA".}

+proc DefMDIChildProcA*(wnd: HWND, uMsg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "DefMDIChildProcA".}

+proc CreateMDIWindowA*(lpClassName: LPSTR, lpWindowName: LPSTR, dwStyle: DWORD,

+                       X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                       hWndParent: HWND, hInstance: HINST, lp: LPARAM): HWND{.

+    stdcall, dynlib: "user32", importc: "CreateMDIWindowA".}

+proc WinHelpA*(hWndMain: HWND, lpszHelp: LPCSTR, uCommand: WINUINT, dwData: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "WinHelpA".}

+proc ChangeDisplaySettingsA*(lpDevMode: LPDEVMODE, dwFlags: DWORD): LONG{.

+    stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsA".}

+proc EnumDisplaySettingsA*(lpszDeviceName: LPCSTR, iModeNum: DWORD,

+                           lpDevMode: LPDEVMODE): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EnumDisplaySettingsA".}

+proc SystemParametersInfoA*(uiAction: WINUINT, uiParam: WINUINT, pvParam: PVOID,

+                            fWinIni: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SystemParametersInfoA".}

+proc AddFontResourceA*(para1: LPCSTR): int32{.stdcall, dynlib: "gdi32",

+    importc: "AddFontResourceA".}

+proc CopyMetaFileA*(para1: HMETAFILE, para2: LPCSTR): HMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "CopyMetaFileA".}

+proc CreateFontA*(para1: int32, para2: int32, para3: int32, para4: int32,

+                  para5: int32, para6: DWORD, para7: DWORD, para8: DWORD,

+                  para9: DWORD, para10: DWORD, para11: DWORD, para12: DWORD,

+                  para13: DWORD, para14: LPCSTR): HFONT{.stdcall,

+    dynlib: "gdi32", importc: "CreateFontA".}

+proc CreateFontIndirectA*(para1: LPLOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+    importc: "CreateFontIndirectA".}

+proc CreateFontIndirectA*(para1: var LOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+    importc: "CreateFontIndirectA".}

+proc CreateICA*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: LPDEVMODE): HDC{.

+    stdcall, dynlib: "gdi32", importc: "CreateICA".}

+proc CreateMetaFileA*(para1: LPCSTR): HDC{.stdcall, dynlib: "gdi32",

+    importc: "CreateMetaFileA".}

+proc CreateScalableFontResourceA*(para1: DWORD, para2: LPCSTR, para3: LPCSTR,

+                                  para4: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "CreateScalableFontResourceA".}

+proc EnumFontFamiliesExA*(para1: HDC, para2: LPLOGFONT, para3: FONTENUMEXPROC,

+                          para4: LPARAM, para5: DWORD): int32{.stdcall,

+    dynlib: "gdi32", importc: "EnumFontFamiliesExA".}

+proc EnumFontFamiliesA*(para1: HDC, para2: LPCSTR, para3: FONTENUMPROC,

+                        para4: LPARAM): int32{.stdcall, dynlib: "gdi32",

+    importc: "EnumFontFamiliesA".}

+proc EnumFontsA*(para1: HDC, para2: LPCSTR, para3: ENUMFONTSPROC, para4: LPARAM): int32{.

+    stdcall, dynlib: "gdi32", importc: "EnumFontsA".}

+proc EnumFontsA*(para1: HDC, para2: LPCSTR, para3: ENUMFONTSPROC, para4: pointer): int32{.

+    stdcall, dynlib: "gdi32", importc: "EnumFontsA".}

+proc GetCharWidthA*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthA".}

+proc GetCharWidth32A*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidth32A".}

+proc GetCharWidthFloatA*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: ptr float32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatA".}

+proc GetCharABCWidthsA*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPABC): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsA".}

+proc GetCharABCWidthsFloatA*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                             para4: LPABCFLOAT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharABCWidthsFloatA".}

+proc GetGlyphOutlineA*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                       para4: LPGLYPHMETRICS, para5: DWORD, para6: LPVOID,

+                       para7: PMAT2): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GetGlyphOutlineA".}

+proc GetMetaFileA*(para1: LPCSTR): HMETAFILE{.stdcall, dynlib: "gdi32",

+    importc: "GetMetaFileA".}

+proc GetOutlineTextMetricsA*(para1: HDC, para2: WINUINT, para3: LPOUTLINETEXTMETRIC): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetOutlineTextMetricsA".}

+proc GetTextExtentPointA*(para1: HDC, para2: LPCSTR, para3: int32, para4: LPSIZE): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPointA".}

+proc GetTextExtentPoint32A*(para1: HDC, para2: LPCSTR, para3: int32,

+                            para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentPoint32A".}

+proc GetTextExtentExPointA*(para1: HDC, para2: LPCSTR, para3: int32,

+                            para4: int32, para5: LPINT, para6: LPINT,

+                            para7: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentExPointA".}

+proc GetCharacterPlacementA*(para1: HDC, para2: LPCSTR, para3: int32,

+                             para4: int32, para5: LPGCP_RESULTS, para6: DWORD): DWORD{.

+    stdcall, dynlib: "gdi32", importc: "GetCharacterPlacementA".}

+proc ResetDCA*(para1: HDC, para2: LPDEVMODE): HDC{.stdcall, dynlib: "gdi32",

+    importc: "ResetDCA".}

+proc RemoveFontResourceA*(para1: LPCSTR): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "RemoveFontResourceA".}

+proc CopyEnhMetaFileA*(para1: HENHMETAFILE, para2: LPCSTR): HENHMETAFILE{.

+    stdcall, dynlib: "gdi32", importc: "CopyEnhMetaFileA".}

+proc CreateEnhMetaFileA*(para1: HDC, para2: LPCSTR, para3: LPRECT, para4: LPCSTR): HDC{.

+    stdcall, dynlib: "gdi32", importc: "CreateEnhMetaFileA".}

+proc GetEnhMetaFileA*(para1: LPCSTR): HENHMETAFILE{.stdcall, dynlib: "gdi32",

+    importc: "GetEnhMetaFileA".}

+proc GetEnhMetaFileDescriptionA*(para1: HENHMETAFILE, para2: WINUINT, para3: LPSTR): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetEnhMetaFileDescriptionA".}

+proc GetTextMetricsA*(para1: HDC, para2: LPTEXTMETRIC): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetTextMetricsA".}

+proc StartDocA*(para1: HDC, para2: PDOCINFO): int32{.stdcall, dynlib: "gdi32",

+    importc: "StartDocA".}

+proc GetObjectA*(para1: HGDIOBJ, para2: int32, para3: LPVOID): int32{.stdcall,

+    dynlib: "gdi32", importc: "GetObjectA".}

+proc TextOutA*(para1: HDC, para2: int32, para3: int32, para4: LPCSTR,

+               para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+                                       importc: "TextOutA".}

+proc ExtTextOutA*(para1: HDC, para2: int32, para3: int32, para4: WINUINT,

+                  para5: LPRECT, para6: LPCSTR, para7: WINUINT, para8: LPINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "ExtTextOutA".}

+proc PolyTextOutA*(para1: HDC, para2: PPOLYTEXT, para3: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyTextOutA".}

+proc GetTextFaceA*(para1: HDC, para2: int32, para3: LPSTR): int32{.stdcall,

+    dynlib: "gdi32", importc: "GetTextFaceA".}

+proc GetKerningPairsA*(para1: HDC, para2: DWORD, para3: LPKERNINGPAIR): DWORD{.

+    stdcall, dynlib: "gdi32", importc: "GetKerningPairsA".}

+proc CreateColorSpaceA*(para1: LPLOGCOLORSPACE): HCOLORSPACE{.stdcall,

+    dynlib: "gdi32", importc: "CreateColorSpaceA".}

+proc GetLogColorSpaceA*(para1: HCOLORSPACE, para2: LPLOGCOLORSPACE, para3: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetLogColorSpaceA".}

+proc GetICMProfileA*(para1: HDC, para2: DWORD, para3: LPSTR): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetICMProfileA".}

+proc SetICMProfileA*(para1: HDC, para2: LPSTR): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "SetICMProfileA".}

+proc UpdateICMRegKeyA*(para1: DWORD, para2: DWORD, para3: LPSTR, para4: WINUINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "UpdateICMRegKeyA".}

+proc EnumICMProfilesA*(para1: HDC, para2: ICMENUMPROC, para3: LPARAM): int32{.

+    stdcall, dynlib: "gdi32", importc: "EnumICMProfilesA".}

+proc PropertySheetA*(lppsph: LPCPROPSHEETHEADER): int32{.stdcall,

+    dynlib: "comctl32", importc: "PropertySheetA".}

+proc ImageList_LoadImageA*(hi: HINST, lpbmp: LPCSTR, cx: int32, cGrow: int32,

+                           crMask: COLORREF, uType: WINUINT, uFlags: WINUINT): HIMAGELIST{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_LoadImageA".}

+proc CreateStatusWindowA*(style: LONG, lpszText: LPCSTR, hwndParent: HWND,

+                          wID: WINUINT): HWND{.stdcall, dynlib: "comctl32",

+    importc: "CreateStatusWindowA".}

+proc DrawStatusTextA*(hDC: HDC, lprc: LPRECT, pszText: LPCSTR, uFlags: WINUINT){.

+    stdcall, dynlib: "comctl32", importc: "DrawStatusTextA".}

+proc GetOpenFileNameA*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+    dynlib: "comdlg32", importc: "GetOpenFileNameA".}

+proc GetSaveFileNameA*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+    dynlib: "comdlg32", importc: "GetSaveFileNameA".}

+proc GetFileTitleA*(para1: LPCSTR, para2: LPSTR, para3: int16): int{.stdcall,

+    dynlib: "comdlg32", importc: "GetFileTitleA".}

+proc ChooseColorA*(para1: LPCHOOSECOLOR): WINBOOL{.stdcall, dynlib: "comdlg32",

+    importc: "ChooseColorA".}

+proc FindTextA*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+    importc: "FindTextA".}

+proc ReplaceTextA*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+    importc: "ReplaceTextA".}

+proc ChooseFontA*(para1: LPCHOOSEFONT): WINBOOL{.stdcall, dynlib: "comdlg32",

+    importc: "ChooseFontA".}

+proc PrintDlgA*(para1: LPPRINTDLG): WINBOOL{.stdcall, dynlib: "comdlg32",

+    importc: "PrintDlgA".}

+proc PageSetupDlgA*(para1: LPPAGESETUPDLG): WINBOOL{.stdcall,

+    dynlib: "comdlg32", importc: "PageSetupDlgA".}

+proc CreateProcessA*(lpApplicationName: LPCSTR, lpCommandLine: LPSTR,

+                     lpProcessAttributes: LPSECURITY_ATTRIBUTES,

+                     lpThreadAttributes: LPSECURITY_ATTRIBUTES,

+                     bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                     lpEnvironment: LPVOID, lpCurrentDirectory: LPCSTR,

+                     lpStartupInfo: LPSTARTUPINFO,

+                     lpProcessInformation: LPPROCESS_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateProcessA".}

+proc GetStartupInfoA*(lpStartupInfo: LPSTARTUPINFO){.stdcall,

+    dynlib: "kernel32", importc: "GetStartupInfoA".}

+proc FindFirstFileA*(lpFileName: LPCSTR, lpFindFileData: LPWIN32_FIND_DATA): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}

+proc FindNextFileA*(hFindFile: HANDLE, lpFindFileData: LPWIN32_FIND_DATA): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FindNextFileA".}

+proc GetVersionExA*(VersionInformation: LPOSVERSIONINFO): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVersionExA".}

+proc CreateWindowA*(lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD,

+                    X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                    hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                    lpParam: LPVOID): HWND

+proc CreateDialogA*(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                    lpDialogFunc: DLGPROC): HWND

+proc CreateDialogIndirectA*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                            hWndParent: HWND, lpDialogFunc: DLGPROC): HWND

+proc DialogBoxA*(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                 lpDialogFunc: DLGPROC): int32

+proc DialogBoxIndirectA*(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE,

+                         hWndParent: HWND, lpDialogFunc: DLGPROC): int32

+proc CreateDCA*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: PDEVMODE): HDC{.

+    stdcall, dynlib: "gdi32", importc: "CreateDCA".}

+proc VerInstallFileA*(uFlags: DWORD, szSrcFileName: LPSTR,

+                      szDestFileName: LPSTR, szSrcDir: LPSTR, szDestDir: LPSTR,

+                      szCurDir: LPSTR, szTmpFile: LPSTR, lpuTmpFileLen: PUINT): DWORD{.

+    stdcall, dynlib: "version", importc: "VerInstallFileA".}

+proc GetFileVersionInfoSizeA*(lptstrFilename: LPSTR, lpdwHandle: LPDWORD): DWORD{.

+    stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeA".}

+proc GetFileVersionInfoA*(lptstrFilename: LPSTR, dwHandle: DWORD, dwLen: DWORD,

+                          lpData: LPVOID): WINBOOL{.stdcall, dynlib: "version",

+    importc: "GetFileVersionInfoA".}

+proc VerLanguageNameA*(wLang: DWORD, szLang: LPSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VerLanguageNameA".}

+proc VerQueryValueA*(pBlock: LPVOID, lpSubBlock: LPSTR, lplpBuffer: LPVOID,

+                     puLen: PUINT): WINBOOL{.stdcall, dynlib: "version",

+    importc: "VerQueryValueA".}

+proc VerFindFileA*(uFlags: DWORD, szFileName: LPSTR, szWinDir: LPSTR,

+                   szAppDir: LPSTR, szCurDir: LPSTR, lpuCurDirLen: PUINT,

+                   szDestDir: LPSTR, lpuDestDirLen: PUINT): DWORD{.stdcall,

+    dynlib: "version", importc: "VerFindFileA".}

+proc RegConnectRegistryA*(lpMachineName: LPSTR, key: HKEY, phkResult: PHKEY): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegConnectRegistryA".}

+proc RegCreateKeyA*(key: HKEY, lpSubKey: LPCSTR, phkResult: PHKEY): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyA".}

+proc RegCreateKeyExA*(key: HKEY, lpSubKey: LPCSTR, Reserved: DWORD,

+                      lpClass: LPSTR, dwOptions: DWORD, samDesired: REGSAM,

+                      lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                      phkResult: PHKEY, lpdwDisposition: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyExA".}

+proc RegDeleteKeyA*(key: HKEY, lpSubKey: LPCSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegDeleteKeyA".}

+proc RegDeleteValueA*(key: HKEY, lpValueName: LPCSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegDeleteValueA".}

+proc RegEnumKeyA*(key: HKEY, dwIndex: DWORD, lpName: LPSTR, cbName: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyA".}

+proc RegEnumKeyExA*(key: HKEY, dwIndex: DWORD, lpName: LPSTR,

+                    lpcbName: LPDWORD, lpReserved: LPDWORD, lpClass: LPSTR,

+                    lpcbClass: LPDWORD, lpftLastWriteTime: PFILETIME): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyExA".}

+proc RegEnumValueA*(key: HKEY, dwIndex: DWORD, lpValueName: LPSTR,

+                    lpcbValueName: LPDWORD, lpReserved: LPDWORD,

+                    lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumValueA".}

+proc RegLoadKeyA*(key: HKEY, lpSubKey: LPCSTR, lpFile: LPCSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegLoadKeyA".}

+proc RegOpenKeyA*(key: HKEY, lpSubKey: LPCSTR, phkResult: PHKEY): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegOpenKeyA".}

+proc RegOpenKeyExA*(key: HKEY, lpSubKey: LPCSTR, ulOptions: DWORD,

+                    samDesired: REGSAM, phkResult: PHKEY): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegOpenKeyExA".}

+proc RegQueryInfoKeyA*(key: HKEY, lpClass: LPSTR, lpcbClass: LPDWORD,

+                       lpReserved: LPDWORD, lpcSubKeys: LPDWORD,

+                       lpcbMaxSubKeyLen: LPDWORD, lpcbMaxClassLen: LPDWORD,

+                       lpcValues: LPDWORD, lpcbMaxValueNameLen: LPDWORD,

+                       lpcbMaxValueLen: LPDWORD,

+                       lpcbSecurityDescriptor: LPDWORD,

+                       lpftLastWriteTime: PFILETIME): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegQueryInfoKeyA".}

+proc RegQueryValueA*(key: HKEY, lpSubKey: LPCSTR, lpValue: LPSTR,

+                     lpcbValue: PLONG): LONG{.stdcall, dynlib: "advapi32",

+    importc: "RegQueryValueA".}

+proc RegQueryMultipleValuesA*(key: HKEY, val_list: PVALENT, num_vals: DWORD,

+                              lpValueBuf: LPSTR, ldwTotsize: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesA".}

+proc RegQueryValueExA*(key: HKEY, lpValueName: LPCSTR, lpReserved: LPDWORD,

+                       lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryValueExA".}

+proc RegReplaceKeyA*(key: HKEY, lpSubKey: LPCSTR, lpNewFile: LPCSTR,

+                     lpOldFile: LPCSTR): LONG{.stdcall, dynlib: "advapi32",

+    importc: "RegReplaceKeyA".}

+proc RegRestoreKeyA*(key: HKEY, lpFile: LPCSTR, dwFlags: DWORD): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegRestoreKeyA".}

+proc RegSaveKeyA*(key: HKEY, lpFile: LPCSTR,

+                  lpSecurityAttributes: LPSECURITY_ATTRIBUTES): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegSaveKeyA".}

+proc RegSetValueA*(key: HKEY, lpSubKey: LPCSTR, dwType: DWORD, lpData: LPCSTR,

+                   cbData: DWORD): LONG{.stdcall, dynlib: "advapi32",

+    importc: "RegSetValueA".}

+proc RegSetValueExA*(key: HKEY, lpValueName: LPCSTR, Reserved: DWORD,

+                     dwType: DWORD, lpData: LPBYTE, cbData: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegSetValueExA".}

+proc RegUnLoadKeyA*(key: HKEY, lpSubKey: LPCSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegUnLoadKeyA".}

+proc InitiateSystemShutdownA*(lpMachineName: LPSTR, lpMessage: LPSTR,

+                              dwTimeout: DWORD, bForceAppsClosed: WINBOOL,

+                              bRebootAfterShutdown: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "InitiateSystemShutdownA".}

+proc AbortSystemShutdownA*(lpMachineName: LPSTR): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AbortSystemShutdownA".}

+proc CompareStringA*(Locale: LCID, dwCmpFlags: DWORD, lpString1: LPCSTR,

+                     cchCount1: int32, lpString2: LPCSTR, cchCount2: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "CompareStringA".}

+proc LCMapStringA*(Locale: LCID, dwMapFlags: DWORD, lpSrcStr: LPCSTR,

+                   cchSrc: int32, lpDestStr: LPSTR, cchDest: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "LCMapStringA".}

+proc GetLocaleInfoA*(Locale: LCID, LCType: LCTYPE, lpLCData: LPSTR,

+                     cchData: int32): int32{.stdcall, dynlib: "kernel32",

+    importc: "GetLocaleInfoA".}

+proc SetLocaleInfoA*(Locale: LCID, LCType: LCTYPE, lpLCData: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetLocaleInfoA".}

+proc GetTimeFormatA*(Locale: LCID, dwFlags: DWORD, lpTime: LPSYSTEMTIME,

+                     lpFormat: LPCSTR, lpTimeStr: LPSTR, cchTime: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "GetTimeFormatA".}

+proc GetDateFormatA*(Locale: LCID, dwFlags: DWORD, lpDate: LPSYSTEMTIME,

+                     lpFormat: LPCSTR, lpDateStr: LPSTR, cchDate: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "GetDateFormatA".}

+proc GetNumberFormatA*(Locale: LCID, dwFlags: DWORD, lpValue: LPCSTR,

+                       lpFormat: PNUMBERFMT, lpNumberStr: LPSTR,

+                       cchNumber: int32): int32{.stdcall, dynlib: "kernel32",

+    importc: "GetNumberFormatA".}

+proc GetCurrencyFormatA*(Locale: LCID, dwFlags: DWORD, lpValue: LPCSTR,

+                         lpFormat: PCURRENCYFMT, lpCurrencyStr: LPSTR,

+                         cchCurrency: int32): int32{.stdcall,

+    dynlib: "kernel32", importc: "GetCurrencyFormatA".}

+proc EnumCalendarInfoA*(lpCalInfoEnumProc: CALINFO_ENUMPROC, Locale: LCID,

+                        Calendar: CALID, CalType: CALTYPE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "EnumCalendarInfoA".}

+proc EnumTimeFormatsA*(lpTimeFmtEnumProc: TIMEFMT_ENUMPROC, Locale: LCID,

+                       dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "EnumTimeFormatsA".}

+proc EnumDateFormatsA*(lpDateFmtEnumProc: DATEFMT_ENUMPROC, Locale: LCID,

+                       dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "EnumDateFormatsA".}

+proc GetStringTypeExA*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCSTR,

+                       cchSrc: int32, lpCharType: LPWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeExA".}

+proc GetStringTypeA*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCSTR,

+                     cchSrc: int32, lpCharType: LPWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeA".}

+proc FoldStringA*(dwMapFlags: DWORD, lpSrcStr: LPCSTR, cchSrc: int32,

+                  lpDestStr: LPSTR, cchDest: int32): int32{.stdcall,

+    dynlib: "kernel32", importc: "FoldStringA".}

+proc EnumSystemLocalesA*(lpLocaleEnumProc: LOCALE_ENUMPROC, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumSystemLocalesA".}

+proc EnumSystemCodePagesA*(lpCodePageEnumProc: CODEPAGE_ENUMPROC, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumSystemCodePagesA".}

+proc PeekConsoleInputA*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                        nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "PeekConsoleInputA".}

+proc ReadConsoleInputA*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                        nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleInputA".}

+proc WriteConsoleInputA*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                         nLength: DWORD, lpNumberOfEventsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleInputA".}

+proc ReadConsoleOutputA*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                         dwBufferSize: COORD, dwBufferCoord: COORD,

+                         lpReadRegion: PSMALL_RECT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadConsoleOutputA".}

+proc WriteConsoleOutputA*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                          dwBufferSize: COORD, dwBufferCoord: COORD,

+                          lpWriteRegion: PSMALL_RECT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteConsoleOutputA".}

+proc ReadConsoleOutputCharacterA*(hConsoleOutput: HANDLE, lpCharacter: LPSTR,

+                                  nLength: DWORD, dwReadCoord: COORD,

+                                  lpNumberOfCharsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterA".}

+proc WriteConsoleOutputCharacterA*(hConsoleOutput: HANDLE, lpCharacter: LPCSTR,

+                                   nLength: DWORD, dwWriteCoord: COORD,

+                                   lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterA".}

+proc FillConsoleOutputCharacterA*(hConsoleOutput: HANDLE, cCharacter: char,

+                                  nLength: DWORD, dwWriteCoord: COORD,

+                                  lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".}

+proc ScrollConsoleScreenBufferA*(hConsoleOutput: HANDLE,

+                                 lpScrollRectangle: PSMALL_RECT,

+                                 lpClipRectangle: PSMALL_RECT,

+                                 dwDestinationOrigin: COORD, lpFill: PCHAR_INFO): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ScrollConsoleScreenBufferA".}

+proc GetConsoleTitleA*(lpConsoleTitle: LPSTR, nSize: DWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetConsoleTitleA".}

+proc SetConsoleTitleA*(lpConsoleTitle: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetConsoleTitleA".}

+proc ReadConsoleA*(hConsoleInput: HANDLE, lpBuffer: LPVOID,

+                   nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: LPDWORD,

+                   lpReserved: LPVOID): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ReadConsoleA".}

+proc WriteConsoleA*(hConsoleOutput: HANDLE, lpBuffer: pointer,

+                    nNumberOfCharsToWrite: DWORD,

+                    lpNumberOfCharsWritten: LPDWORD, lpReserved: LPVOID): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleA".}

+proc WNetAddConnectionA*(lpRemoteName: LPCSTR, lpPassword: LPCSTR,

+                         lpLocalName: LPCSTR): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetAddConnectionA".}

+proc WNetAddConnection2A*(lpNetResource: LPNETRESOURCE, lpPassword: LPCSTR,

+                          lpUserName: LPCSTR, dwFlags: DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetAddConnection2A".}

+proc WNetAddConnection3A*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                          lpPassword: LPCSTR, lpUserName: LPCSTR, dwFlags: DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetAddConnection3A".}

+proc WNetCancelConnectionA*(lpName: LPCSTR, fForce: WINBOOL): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetCancelConnectionA".}

+proc WNetCancelConnection2A*(lpName: LPCSTR, dwFlags: DWORD, fForce: WINBOOL): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetCancelConnection2A".}

+proc WNetGetConnectionA*(lpLocalName: LPCSTR, lpRemoteName: LPSTR,

+                         lpnLength: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetConnectionA".}

+proc WNetUseConnectionA*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                         lpUserID: LPCSTR, lpPassword: LPCSTR, dwFlags: DWORD,

+                         lpAccessName: LPSTR, lpBufferSize: LPDWORD,

+                         lpResult: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetUseConnectionA".}

+proc WNetSetConnectionA*(lpName: LPCSTR, dwProperties: DWORD, pvValues: LPVOID): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetSetConnectionA".}

+proc WNetConnectionDialog1A*(lpConnDlgStruct: LPCONNECTDLGSTRUCT): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetConnectionDialog1A".}

+proc WNetDisconnectDialog1A*(lpConnDlgStruct: LPDISCDLGSTRUCT): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetDisconnectDialog1A".}

+proc WNetOpenEnumA*(dwScope: DWORD, dwType: DWORD, dwUsage: DWORD,

+                    lpNetResource: LPNETRESOURCE, lphEnum: LPHANDLE): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetOpenEnumA".}

+proc WNetEnumResourceA*(hEnum: HANDLE, lpcCount: LPDWORD, lpBuffer: LPVOID,

+                        lpBufferSize: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetEnumResourceA".}

+proc WNetGetUniversalNameA*(lpLocalPath: LPCSTR, dwInfoLevel: DWORD,

+                            lpBuffer: LPVOID, lpBufferSize: LPDWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameA".}

+proc WNetGetUserA*(lpName: LPCSTR, lpUserName: LPSTR, lpnLength: LPDWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUserA".}

+proc WNetGetProviderNameA*(dwNetType: DWORD, lpProviderName: LPSTR,

+                           lpBufferSize: LPDWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetGetProviderNameA".}

+proc WNetGetNetworkInformationA*(lpProvider: LPCSTR,

+                                 lpNetInfoStruct: LPNETINFOSTRUCT): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationA".}

+proc WNetGetLastErrorA*(lpError: LPDWORD, lpErrorBuf: LPSTR,

+                        nErrorBufSize: DWORD, lpNameBuf: LPSTR,

+                        nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetLastErrorA".}

+proc MultinetGetConnectionPerformanceA*(lpNetResource: LPNETRESOURCE,

+    lpNetConnectInfoStruct: LPNETCONNECTINFOSTRUCT): DWORD{.stdcall,

+    dynlib: "mpr", importc: "MultinetGetConnectionPerformanceA".}

+proc ChangeServiceConfigA*(hService: SC_HANDLE, dwServiceType: DWORD,

+                           dwStartType: DWORD, dwErrorControl: DWORD,

+                           lpBinaryPathName: LPCSTR, lpLoadOrderGroup: LPCSTR,

+                           lpdwTagId: LPDWORD, lpDependencies: LPCSTR,

+                           lpServiceStartName: LPCSTR, lpPassword: LPCSTR,

+                           lpDisplayName: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ChangeServiceConfigA".}

+proc CreateServiceA*(hSCManager: SC_HANDLE, lpServiceName: LPCSTR,

+                     lpDisplayName: LPCSTR, dwDesiredAccess: DWORD,

+                     dwServiceType: DWORD, dwStartType: DWORD,

+                     dwErrorControl: DWORD, lpBinaryPathName: LPCSTR,

+                     lpLoadOrderGroup: LPCSTR, lpdwTagId: LPDWORD,

+                     lpDependencies: LPCSTR, lpServiceStartName: LPCSTR,

+                     lpPassword: LPCSTR): SC_HANDLE{.stdcall,

+    dynlib: "advapi32", importc: "CreateServiceA".}

+proc EnumDependentServicesA*(hService: SC_HANDLE, dwServiceState: DWORD,

+                             lpServices: LPENUM_SERVICE_STATUS,

+                             cbBufSize: DWORD, pcbBytesNeeded: LPDWORD,

+                             lpServicesReturned: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "EnumDependentServicesA".}

+proc EnumServicesStatusA*(hSCManager: SC_HANDLE, dwServiceType: DWORD,

+                          dwServiceState: DWORD,

+                          lpServices: LPENUM_SERVICE_STATUS, cbBufSize: DWORD,

+                          pcbBytesNeeded: LPDWORD, lpServicesReturned: LPDWORD,

+                          lpResumeHandle: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "EnumServicesStatusA".}

+proc GetServiceKeyNameA*(hSCManager: SC_HANDLE, lpDisplayName: LPCSTR,

+                         lpServiceName: LPSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetServiceKeyNameA".}

+proc GetServiceDisplayNameA*(hSCManager: SC_HANDLE, lpServiceName: LPCSTR,

+                             lpDisplayName: LPSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetServiceDisplayNameA".}

+proc OpenSCManagerA*(lpMachineName: LPCSTR, lpDatabaseName: LPCSTR,

+                     dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+    dynlib: "advapi32", importc: "OpenSCManagerA".}

+proc OpenServiceA*(hSCManager: SC_HANDLE, lpServiceName: LPCSTR,

+                   dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+    dynlib: "advapi32", importc: "OpenServiceA".}

+proc QueryServiceConfigA*(hService: SC_HANDLE,

+                          lpServiceConfig: LPQUERY_SERVICE_CONFIG,

+                          cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "QueryServiceConfigA".}

+proc QueryServiceLockStatusA*(hSCManager: SC_HANDLE,

+                              lpLockStatus: LPQUERY_SERVICE_LOCK_STATUS,

+                              cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "QueryServiceLockStatusA".}

+proc RegisterServiceCtrlHandlerA*(lpServiceName: LPCSTR,

+                                  lpHandlerProc: LPHANDLER_FUNCTION): SERVICE_STATUS_HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "RegisterServiceCtrlHandlerA".}

+proc StartServiceCtrlDispatcherA*(lpServiceStartTable: LPSERVICE_TABLE_ENTRY): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "StartServiceCtrlDispatcherA".}

+proc StartServiceA*(hService: SC_HANDLE, dwNumServiceArgs: DWORD,

+                    lpServiceArgVectors: LPCSTR): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "StartServiceA".}

+proc DragQueryFileA*(para1: HDROP, para2: int, para3: cstring, para4: int): int{.

+    stdcall, dynlib: "shell32", importc: "DragQueryFileA".}

+proc ExtractAssociatedIconA*(para1: HINST, para2: cstring, para3: LPWORD): HICON{.

+    stdcall, dynlib: "shell32", importc: "ExtractAssociatedIconA".}

+proc ExtractIconA*(para1: HINST, para2: cstring, para3: int): HICON{.stdcall,

+    dynlib: "shell32", importc: "ExtractIconA".}

+proc FindExecutableA*(para1: cstring, para2: cstring, para3: cstring): HINST{.

+    stdcall, dynlib: "shell32", importc: "FindExecutableA".}

+proc ShellAboutA*(para1: HWND, para2: cstring, para3: cstring, para4: HICON): int32{.

+    stdcall, dynlib: "shell32", importc: "ShellAboutA".}

+proc ShellExecuteA*(para1: HWND, para2: cstring, para3: cstring, para4: cstring,

+                    para5: cstring, para6: int32): HINST{.stdcall,

+    dynlib: "shell32", importc: "ShellExecuteA".}

+proc Shell_NotifyIconA*(dwMessage: DWORD, lpData: PNotifyIconDataA): WINBOOL{.

+    stdcall, dynlib: "shell32", importc: "Shell_NotifyIconA".}

+proc DdeCreateStringHandleA*(para1: DWORD, para2: cstring, para3: int32): HSZ{.

+    stdcall, dynlib: "user32", importc: "DdeCreateStringHandleA".}

+proc DdeInitializeA*(para1: LPDWORD, para2: PFNCALLBACK, para3: DWORD,

+                     para4: DWORD): WINUINT{.stdcall, dynlib: "user32",

+    importc: "DdeInitializeA".}

+proc DdeQueryStringA*(para1: DWORD, para2: HSZ, para3: cstring, para4: DWORD,

+                      para5: int32): DWORD{.stdcall, dynlib: "user32",

+    importc: "DdeQueryStringA".}

+proc LogonUserA*(para1: LPSTR, para2: LPSTR, para3: LPSTR, para4: DWORD,

+                 para5: DWORD, para6: PHANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LogonUserA".}

+proc CreateProcessAsUserA*(para1: HANDLE, para2: LPCTSTR, para3: LPTSTR,

+                           para4: LPSECURITY_ATTRIBUTES,

+                           para5: LPSECURITY_ATTRIBUTES, para6: WINBOOL,

+                           para7: DWORD, para8: LPVOID, para9: LPCTSTR,

+                           para10: LPSTARTUPINFO, para11: LPPROCESS_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "CreateProcessAsUserA".}

+proc GetBinaryTypeW*(lpApplicationName: LPCWSTR, lpBinaryType: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetBinaryTypeW".}

+proc GetShortPathNameW*(lpszLongPath: LPCWSTR, lpszShortPath: LPWSTR,

+                        cchBuffer: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetShortPathNameW".}

+proc GetEnvironmentStringsW*(): LPWSTR{.stdcall, dynlib: "kernel32",

+                                        importc: "GetEnvironmentStringsW".}

+proc FreeEnvironmentStringsW*(para1: LPWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FreeEnvironmentStringsW".}

+proc FormatMessageW*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD,

+                     dwLanguageId: DWORD, lpBuffer: LPWSTR, nSize: DWORD,

+                     Arguments: va_list): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "FormatMessageW".}

+proc CreateMailslotW*(lpName: LPCWSTR, nMaxMessageSize: DWORD,

+                      lReadTimeout: DWORD,

+                      lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "CreateMailslotW".}

+proc lstrcmpW*(lpString1: LPCWSTR, lpString2: LPCWSTR): int32{.stdcall,

+    dynlib: "kernel32", importc: "lstrcmpW".}

+proc lstrcmpiW*(lpString1: LPCWSTR, lpString2: LPCWSTR): int32{.stdcall,

+    dynlib: "kernel32", importc: "lstrcmpiW".}

+proc lstrcpynW*(lpString1: LPWSTR, lpString2: LPCWSTR, iMaxLength: int32): LPWSTR{.

+    stdcall, dynlib: "kernel32", importc: "lstrcpynW".}

+proc lstrcpyW*(lpString1: LPWSTR, lpString2: LPCWSTR): LPWSTR{.stdcall,

+    dynlib: "kernel32", importc: "lstrcpyW".}

+proc lstrcatW*(lpString1: LPWSTR, lpString2: LPCWSTR): LPWSTR{.stdcall,

+    dynlib: "kernel32", importc: "lstrcatW".}

+proc lstrlenW*(lpString: LPCWSTR): int32{.stdcall, dynlib: "kernel32",

+    importc: "lstrlenW".}

+proc CreateMutexW*(lpMutexAttributes: LPSECURITY_ATTRIBUTES,

+                   bInitialOwner: WINBOOL, lpName: LPCWSTR): HANDLE{.stdcall,

+    dynlib: "kernel32", importc: "CreateMutexW".}

+proc OpenMutexW*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                 lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "OpenMutexW".}

+proc CreateEventW*(lpEventAttributes: LPSECURITY_ATTRIBUTES,

+                   bManualReset: WINBOOL, bInitialState: WINBOOL,

+                   lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "CreateEventW".}

+proc OpenEventW*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                 lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "OpenEventW".}

+proc CreateSemaphoreW*(lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES,

+                       lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "CreateSemaphoreW".}

+proc OpenSemaphoreW*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                     lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "OpenSemaphoreW".}

+proc CreateFileMappingW*(hFile: HANDLE,

+                         lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,

+                         flProtect: DWORD, dwMaximumSizeHigh: DWORD,

+                         dwMaximumSizeLow: DWORD, lpName: LPCWSTR): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}

+proc OpenFileMappingW*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                       lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "OpenFileMappingW".}

+proc GetLogicalDriveStringsW*(nBufferLength: DWORD, lpBuffer: LPWSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetLogicalDriveStringsW".}

+proc LoadLibraryW*(lpLibFileName: LPCWSTR): HINST{.stdcall, dynlib: "kernel32",

+    importc: "LoadLibraryW".}

+proc LoadLibraryExW*(lpLibFileName: LPCWSTR, hFile: HANDLE, dwFlags: DWORD): HINST{.

+    stdcall, dynlib: "kernel32", importc: "LoadLibraryExW".}

+proc GetModuleFileNameW*(hModule: HINST, lpFilename: LPWSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetModuleFileNameW".}

+proc GetModuleHandleW*(lpModuleName: LPCWSTR): HMODULE{.stdcall,

+    dynlib: "kernel32", importc: "GetModuleHandleW".}

+proc FatalAppExitW*(uAction: WINUINT, lpMessageText: LPCWSTR){.stdcall,

+    dynlib: "kernel32", importc: "FatalAppExitW".}

+proc GetCommandLineW*(): LPWSTR{.stdcall, dynlib: "kernel32",

+                                 importc: "GetCommandLineW".}

+proc GetEnvironmentVariableW*(lpName: LPCWSTR, lpBuffer: LPWSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetEnvironmentVariableW".}

+proc SetEnvironmentVariableW*(lpName: LPCWSTR, lpValue: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}

+proc ExpandEnvironmentStringsW*(lpSrc: LPCWSTR, lpDst: LPWSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "ExpandEnvironmentStringsW".}

+proc OutputDebugStringW*(lpOutputString: LPCWSTR){.stdcall, dynlib: "kernel32",

+    importc: "OutputDebugStringW".}

+proc FindResourceW*(hModule: HINST, lpName: LPCWSTR, lpType: LPCWSTR): HRSRC{.

+    stdcall, dynlib: "kernel32", importc: "FindResourceW".}

+proc FindResourceExW*(hModule: HINST, lpType: LPCWSTR, lpName: LPCWSTR,

+                      wLanguage: int16): HRSRC{.stdcall, dynlib: "kernel32",

+    importc: "FindResourceExW".}

+proc EnumResourceTypesW*(hModule: HINST, lpEnumFunc: ENUMRESTYPEPROC,

+                         lParam: LONG): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "EnumResourceTypesW".}

+proc EnumResourceNamesW*(hModule: HINST, lpType: LPCWSTR,

+                         lpEnumFunc: ENUMRESNAMEPROC, lParam: LONG): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumResourceNamesW".}

+proc EnumResourceLanguagesW*(hModule: HINST, lpType: LPCWSTR, lpName: LPCWSTR,

+                             lpEnumFunc: ENUMRESLANGPROC, lParam: LONG): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumResourceLanguagesW".}

+proc BeginUpdateResourceW*(pFileName: LPCWSTR, bDeleteExistingResources: WINBOOL): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "BeginUpdateResourceW".}

+proc UpdateResourceW*(hUpdate: HANDLE, lpType: LPCWSTR, lpName: LPCWSTR,

+                      wLanguage: int16, lpData: LPVOID, cbData: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "UpdateResourceW".}

+proc EndUpdateResourceW*(hUpdate: HANDLE, fDiscard: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "EndUpdateResourceW".}

+proc GlobalAddAtomW*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "GlobalAddAtomW".}

+proc GlobalFindAtomW*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "GlobalFindAtomW".}

+proc GlobalGetAtomNameW*(nAtom: ATOM, lpBuffer: LPWSTR, nSize: int32): WINUINT{.

+    stdcall, dynlib: "kernel32", importc: "GlobalGetAtomNameW".}

+proc AddAtomW*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "AddAtomW".}

+proc FindAtomW*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "FindAtomW".}

+proc GetAtomNameW*(nAtom: ATOM, lpBuffer: LPWSTR, nSize: int32): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetAtomNameW".}

+proc GetProfileIntW*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR, nDefault: WINT): WINUINT{.

+    stdcall, dynlib: "kernel32", importc: "GetProfileIntW".}

+proc GetProfileStringW*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                        lpDefault: LPCWSTR, lpReturnedString: LPWSTR,

+                        nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetProfileStringW".}

+proc WriteProfileStringW*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                          lpString: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteProfileStringW".}

+proc GetProfileSectionW*(lpAppName: LPCWSTR, lpReturnedString: LPWSTR,

+                         nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetProfileSectionW".}

+proc WriteProfileSectionW*(lpAppName: LPCWSTR, lpString: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteProfileSectionW".}

+proc GetPrivateProfileIntW*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                            nDefault: WINT, lpFileName: LPCWSTR): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetPrivateProfileIntW".}

+proc GetPrivateProfileStringW*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                               lpDefault: LPCWSTR, lpReturnedString: LPWSTR,

+                               nSize: DWORD, lpFileName: LPCWSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStringW".}

+proc WritePrivateProfileStringW*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                                 lpString: LPCWSTR, lpFileName: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStringW".}

+proc GetPrivateProfileSectionW*(lpAppName: LPCWSTR, lpReturnedString: LPWSTR,

+                                nSize: DWORD, lpFileName: LPCWSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileSectionW".}

+proc WritePrivateProfileSectionW*(lpAppName: LPCWSTR, lpString: LPCWSTR,

+                                  lpFileName: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WritePrivateProfileSectionW".}

+proc GetDriveTypeW*(lpRootPathName: LPCWSTR): WINUINT{.stdcall, dynlib: "kernel32",

+    importc: "GetDriveTypeW".}

+proc GetSystemDirectoryW*(lpBuffer: LPWSTR, uSize: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetSystemDirectoryW".}

+proc GetTempPathW*(nBufferLength: DWORD, lpBuffer: LPWSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetTempPathW".}

+proc GetTempFileNameW*(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR,

+                       uUnique: WINUINT, lpTempFileName: LPWSTR): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetTempFileNameW".}

+proc GetWindowsDirectoryW*(lpBuffer: LPWSTR, uSize: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "GetWindowsDirectoryW".}

+proc SetCurrentDirectoryW*(lpPathName: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetCurrentDirectoryW".}

+proc GetCurrentDirectoryW*(nBufferLength: DWORD, lpBuffer: LPWSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetCurrentDirectoryW".}

+proc GetDiskFreeSpaceW*(lpRootPathName: LPCWSTR, lpSectorsPerCluster: LPDWORD,

+                        lpBytesPerSector: LPDWORD,

+                        lpNumberOfFreeClusters: LPDWORD,

+                        lpTotalNumberOfClusters: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDiskFreeSpaceW".}

+proc CreateDirectoryW*(lpPathName: LPCWSTR,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateDirectoryW".}

+proc CreateDirectoryExW*(lpTemplateDirectory: LPCWSTR, lpNewDirectory: LPCWSTR,

+                         lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateDirectoryExW".}

+proc RemoveDirectoryW*(lpPathName: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "RemoveDirectoryW".}

+proc GetFullPathNameW*(lpFileName: LPCWSTR, nBufferLength: DWORD,

+                       lpBuffer: LPWSTR, lpFilePart: var LPWSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetFullPathNameW".}

+proc DefineDosDeviceW*(dwFlags: DWORD, lpDeviceName: LPCWSTR,

+                       lpTargetPath: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "DefineDosDeviceW".}

+proc QueryDosDeviceW*(lpDeviceName: LPCWSTR, lpTargetPath: LPWSTR,

+                      ucchMax: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "QueryDosDeviceW".}

+proc CreateFileW*(lpFileName: LPCWSTR, dwDesiredAccess: DWORD,

+                  dwShareMode: DWORD,

+                  lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                  dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD,

+                  hTemplateFile: HANDLE): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "CreateFileW".}

+proc SetFileAttributesW*(lpFileName: LPCWSTR, dwFileAttributes: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}

+proc GetFileAttributesW*(lpFileName: LPCWSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetFileAttributesW".}

+proc GetCompressedFileSizeW*(lpFileName: LPCWSTR, lpFileSizeHigh: LPDWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetCompressedFileSizeW".}

+proc DeleteFileW*(lpFileName: LPCWSTR): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "DeleteFileW".}

+proc SearchPathW*(lpPath: LPCWSTR, lpFileName: LPCWSTR, lpExtension: LPCWSTR,

+                  nBufferLength: DWORD, lpBuffer: LPWSTR, lpFilePart: LPWSTR): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "SearchPathW".}

+proc CopyFileW*(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR,

+                bFailIfExists: WINBOOL): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CopyFileW".}

+proc MoveFileW*(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "MoveFileW".}

+proc MoveFileExW*(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR,

+                  dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "MoveFileExW".}

+proc CreateNamedPipeW*(lpName: LPCWSTR, dwOpenMode: DWORD, dwPipeMode: DWORD,

+                       nMaxInstances: DWORD, nOutBufferSize: DWORD,

+                       nInBufferSize: DWORD, nDefaultTimeOut: DWORD,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "CreateNamedPipeW".}

+proc GetNamedPipeHandleStateW*(hNamedPipe: HANDLE, lpState: LPDWORD,

+                               lpCurInstances: LPDWORD,

+                               lpMaxCollectionCount: LPDWORD,

+                               lpCollectDataTimeout: LPDWORD,

+                               lpUserName: LPWSTR, nMaxUserNameSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetNamedPipeHandleStateW".}

+proc CallNamedPipeW*(lpNamedPipeName: LPCWSTR, lpInBuffer: LPVOID,

+                     nInBufferSize: DWORD, lpOutBuffer: LPVOID,

+                     nOutBufferSize: DWORD, lpBytesRead: LPDWORD,

+                     nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CallNamedPipeW".}

+proc WaitNamedPipeW*(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WaitNamedPipeW".}

+proc SetVolumeLabelW*(lpRootPathName: LPCWSTR, lpVolumeName: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetVolumeLabelW".}

+proc GetVolumeInformationW*(lpRootPathName: LPCWSTR, lpVolumeNameBuffer: LPWSTR,

+                            nVolumeNameSize: DWORD,

+                            lpVolumeSerialNumber: LPDWORD,

+                            lpMaximumComponentLength: LPDWORD,

+                            lpFileSystemFlags: LPDWORD,

+                            lpFileSystemNameBuffer: LPWSTR,

+                            nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVolumeInformationW".}

+proc ClearEventLogW*(hEventLog: HANDLE, lpBackupFileName: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ClearEventLogW".}

+proc BackupEventLogW*(hEventLog: HANDLE, lpBackupFileName: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "BackupEventLogW".}

+proc OpenEventLogW*(lpUNCServerName: LPCWSTR, lpSourceName: LPCWSTR): HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "OpenEventLogW".}

+proc RegisterEventSourceW*(lpUNCServerName: LPCWSTR, lpSourceName: LPCWSTR): HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "RegisterEventSourceW".}

+proc OpenBackupEventLogW*(lpUNCServerName: LPCWSTR, lpFileName: LPCWSTR): HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "OpenBackupEventLogW".}

+proc ReadEventLogW*(hEventLog: HANDLE, dwReadFlags: DWORD,

+                    dwRecordOffset: DWORD, lpBuffer: LPVOID,

+                    nNumberOfBytesToRead: DWORD, pnBytesRead: LPDWORD,

+                    pnMinNumberOfBytesNeeded: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ReadEventLogW".}

+proc ReportEventW*(hEventLog: HANDLE, wType: int16, wCategory: int16,

+                   dwEventID: DWORD, lpUserSid: PSID, wNumStrings: int16,

+                   dwDataSize: DWORD, lpStrings: LPPCWSTR, lpRawData: LPVOID): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ReportEventW".}

+proc AccessCheckAndAuditAlarmW*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                                ObjectTypeName: LPWSTR, ObjectName: LPWSTR,

+                                SecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                DesiredAccess: DWORD,

+                                GenericMapping: PGENERIC_MAPPING,

+                                ObjectCreation: WINBOOL, GrantedAccess: LPDWORD,

+                                AccessStatus: LPBOOL, pfGenerateOnClose: LPBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AccessCheckAndAuditAlarmW".}

+proc ObjectOpenAuditAlarmW*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                            ObjectTypeName: LPWSTR, ObjectName: LPWSTR,

+                            pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                            ClientToken: HANDLE, DesiredAccess: DWORD,

+                            GrantedAccess: DWORD, Privileges: PPRIVILEGE_SET,

+                            ObjectCreation: WINBOOL, AccessGranted: WINBOOL,

+                            GenerateOnClose: LPBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectOpenAuditAlarmW".}

+proc ObjectPrivilegeAuditAlarmW*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                                 ClientToken: HANDLE, DesiredAccess: DWORD,

+                                 Privileges: PPRIVILEGE_SET,

+                                 AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmW".}

+proc ObjectCloseAuditAlarmW*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                             GenerateOnClose: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectCloseAuditAlarmW".}

+proc PrivilegedServiceAuditAlarmW*(SubsystemName: LPCWSTR, ServiceName: LPCWSTR,

+                                   ClientToken: HANDLE,

+                                   Privileges: PPRIVILEGE_SET,

+                                   AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmW".}

+proc SetFileSecurityW*(lpFileName: LPCWSTR,

+                       SecurityInformation: SECURITY_INFORMATION,

+                       pSecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetFileSecurityW".}

+proc GetFileSecurityW*(lpFileName: LPCWSTR,

+                       RequestedInformation: SECURITY_INFORMATION,

+                       pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                       nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetFileSecurityW".}

+proc FindFirstChangeNotificationW*(lpPathName: LPCWSTR, bWatchSubtree: WINBOOL,

+                                   dwNotifyFilter: DWORD): HANDLE{.stdcall,

+    dynlib: "kernel32", importc: "FindFirstChangeNotificationW".}

+proc IsBadStringPtrW*(lpsz: LPCWSTR, ucchMax: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsBadStringPtrW".}

+proc LookupAccountSidW*(lpSystemName: LPCWSTR, Sid: PSID, Name: LPWSTR,

+                        cbName: LPDWORD, ReferencedDomainName: LPWSTR,

+                        cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupAccountSidW".}

+proc LookupAccountNameW*(lpSystemName: LPCWSTR, lpAccountName: LPCWSTR,

+                         Sid: PSID, cbSid: LPDWORD,

+                         ReferencedDomainName: LPWSTR,

+                         cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupAccountNameW".}

+proc LookupPrivilegeValueW*(lpSystemName: LPCWSTR, lpName: LPCWSTR,

+                            lpLuid: PLUID): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeValueW".}

+proc LookupPrivilegeNameW*(lpSystemName: LPCWSTR, lpLuid: PLUID, lpName: LPWSTR,

+                           cbName: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeNameW".}

+proc LookupPrivilegeDisplayNameW*(lpSystemName: LPCWSTR, lpName: LPCWSTR,

+                                  lpDisplayName: LPWSTR, cbDisplayName: LPDWORD,

+                                  lpLanguageId: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameW".}

+proc BuildCommDCBW*(lpDef: LPCWSTR, lpDCB: LPDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "BuildCommDCBW".}

+proc BuildCommDCBAndTimeoutsW*(lpDef: LPCWSTR, lpDCB: LPDCB,

+                               lpCommTimeouts: LPCOMMTIMEOUTS): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsW".}

+proc CommConfigDialogW*(lpszName: LPCWSTR, wnd: HWND, lpCC: LPCOMMCONFIG): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CommConfigDialogW".}

+proc GetDefaultCommConfigW*(lpszName: LPCWSTR, lpCC: LPCOMMCONFIG,

+                            lpdwSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDefaultCommConfigW".}

+proc SetDefaultCommConfigW*(lpszName: LPCWSTR, lpCC: LPCOMMCONFIG, dwSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetDefaultCommConfigW".}

+proc GetComputerNameW*(lpBuffer: LPWSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetComputerNameW".}

+proc SetComputerNameW*(lpComputerName: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetComputerNameW".}

+proc GetUserNameW*(lpBuffer: LPWSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetUserNameW".}

+proc LoadKeyboardLayoutW*(pwszKLID: LPCWSTR, Flags: WINUINT): HKL{.stdcall,

+    dynlib: "user32", importc: "LoadKeyboardLayoutW".}

+proc GetKeyboardLayoutNameW*(pwszKLID: LPWSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetKeyboardLayoutNameW".}

+proc CreateDesktopW*(lpszDesktop: LPWSTR, lpszDevice: LPWSTR,

+                     pDevmodew: LPDEVMODEw, dwFlags: DWORD,

+                     dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HDESK{.

+    stdcall, dynlib: "user32", importc: "CreateDesktopW".}

+proc OpenDesktopW*(lpszDesktop: LPWSTR, dwFlags: DWORD, fInherit: WINBOOL,

+                   dwDesiredAccess: DWORD): HDESK{.stdcall, dynlib: "user32",

+    importc: "OpenDesktopW".}

+proc EnumDesktopsW*(hwinsta: HWINSTA, lpEnumFunc: DESKTOPENUMPROC,

+                    lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "EnumDesktopsW".}

+proc CreateWindowStationW*(lpwinsta: LPWSTR, dwReserved: DWORD,

+                           dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HWINSTA{.

+    stdcall, dynlib: "user32", importc: "CreateWindowStationW".}

+proc OpenWindowStationW*(lpszWinSta: LPWSTR, fInherit: WINBOOL,

+                         dwDesiredAccess: DWORD): HWINSTA{.stdcall,

+    dynlib: "user32", importc: "OpenWindowStationW".}

+proc EnumWindowStationsW*(lpEnumFunc: ENUMWINDOWSTATIONPROC, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnumWindowStationsW".}

+proc GetUserObjectInformationW*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUserObjectInformationW".}

+proc SetUserObjectInformationW*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                nLength: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetUserObjectInformationW".}

+proc RegisterWindowMessageW*(lpString: LPCWSTR): WINUINT{.stdcall,

+    dynlib: "user32", importc: "RegisterWindowMessageW".}

+proc GetMessageW*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                  wMsgFilterMax: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetMessageW".}

+proc DispatchMessageW*(lpMsg: LPMSG): LONG{.stdcall, dynlib: "user32",

+    importc: "DispatchMessageW".}

+proc PeekMessageW*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                   wMsgFilterMax: WINUINT, wRemoveMsg: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "PeekMessageW".}

+proc SendMessageW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageW".}

+proc SendMessageTimeoutW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM,

+                          fuFlags: WINUINT, uTimeout: WINUINT, lpdwResult: LPDWORD): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageTimeoutW".}

+proc SendNotifyMessageW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SendNotifyMessageW".}

+proc SendMessageCallbackW*(wnd: HWND, Msg: WINUINT, wp: WPARAM,

+                           lp: LPARAM, lpResultCallBack: SENDASYNCPROC,

+                           dwData: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SendMessageCallbackW".}

+proc PostMessageW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "PostMessageW".}

+proc PostThreadMessageW*(idThread: DWORD, Msg: WINUINT, wp: WPARAM,

+                         lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "PostThreadMessageW".}

+proc DefWindowProcW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "DefWindowProcW".}

+proc CallWindowProcW*(lpPrevWndFunc: WNDPROC, wnd: HWND, Msg: WINUINT,

+                      wp: WPARAM, lp: LPARAM): LRESULT{.stdcall,

+    dynlib: "user32", importc: "CallWindowProcW".}

+proc RegisterClassW*(lpWndClass: LPWNDCLASSW): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassW".}

+proc UnregisterClassW*(lpClassName: LPCWSTR, hInstance: HINST): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "UnregisterClassW".}

+proc GetClassInfoW*(hInstance: HINST, lpClassName: LPCWSTR,

+                    lpWndClass: LPWNDCLASS): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetClassInfoW".}

+proc RegisterClassExW*(para1: LPWNDCLASSEXW): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassExW".}

+proc GetClassInfoExW*(para1: HINST, para2: LPCWSTR, para3: LPWNDCLASSEX): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetClassInfoExW".}

+proc CreateWindowExW*(dwExStyle: DWORD, lpClassName: LPCWSTR,

+                      lpWindowName: LPCWSTR, dwStyle: DWORD, X: int32, Y: int32,

+                      nWidth: int32, nHeight: int32, hWndParent: HWND,

+                      menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND{.

+    stdcall, dynlib: "user32", importc: "CreateWindowExW".}

+proc CreateDialogParamW*(hInstance: HINST, lpTemplateName: LPCWSTR,

+                         hWndParent: HWND, lpDialogFunc: DLGPROC,

+                         dwInitParam: LPARAM): HWND{.stdcall, dynlib: "user32",

+    importc: "CreateDialogParamW".}

+proc CreateDialogIndirectParamW*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                                 hWndParent: HWND, lpDialogFunc: DLGPROC,

+                                 dwInitParam: LPARAM): HWND{.stdcall,

+    dynlib: "user32", importc: "CreateDialogIndirectParamW".}

+proc DialogBoxParamW*(hInstance: HINST, lpTemplateName: LPCWSTR,

+                      hWndParent: HWND, lpDialogFunc: DLGPROC,

+                      dwInitParam: LPARAM): int32{.stdcall, dynlib: "user32",

+    importc: "DialogBoxParamW".}

+proc DialogBoxIndirectParamW*(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE,

+                              hWndParent: HWND, lpDialogFunc: DLGPROC,

+                              dwInitParam: LPARAM): int32{.stdcall,

+    dynlib: "user32", importc: "DialogBoxIndirectParamW".}

+proc SetDlgItemTextW*(hDlg: HWND, nIDDlgItem: int32, lpString: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetDlgItemTextW".}

+proc GetDlgItemTextW*(hDlg: HWND, nIDDlgItem: int32, lpString: LPWSTR,

+                      nMaxCount: int32): WINUINT{.stdcall, dynlib: "user32",

+    importc: "GetDlgItemTextW".}

+proc SendDlgItemMessageW*(hDlg: HWND, nIDDlgItem: int32, Msg: WINUINT,

+                          wp: WPARAM, lp: LPARAM): LONG{.stdcall,

+    dynlib: "user32", importc: "SendDlgItemMessageW".}

+proc DefDlgProcW*(hDlg: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "DefDlgProcW".}

+proc CallMsgFilterW*(lpMsg: LPMSG, nCode: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CallMsgFilterW".}

+proc RegisterClipboardFormatW*(lpszFormat: LPCWSTR): WINUINT{.stdcall,

+    dynlib: "user32", importc: "RegisterClipboardFormatW".}

+proc GetClipboardFormatNameW*(format: WINUINT, lpszFormatName: LPWSTR,

+                              cchMaxCount: int32): int32{.stdcall,

+    dynlib: "user32", importc: "GetClipboardFormatNameW".}

+proc CharToOemW*(lpszSrc: LPCWSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CharToOemW".}

+proc OemToCharW*(lpszSrc: LPCSTR, lpszDst: LPWSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "OemToCharW".}

+proc CharToOemBuffW*(lpszSrc: LPCWSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "CharToOemBuffW".}

+proc OemToCharBuffW*(lpszSrc: LPCSTR, lpszDst: LPWSTR, cchDstLength: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "OemToCharBuffW".}

+proc CharUpperW*(lpsz: LPWSTR): LPWSTR{.stdcall, dynlib: "user32",

+                                        importc: "CharUpperW".}

+proc CharUpperBuffW*(lpsz: LPWSTR, cchLength: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "CharUpperBuffW".}

+proc CharLowerW*(lpsz: LPWSTR): LPWSTR{.stdcall, dynlib: "user32",

+                                        importc: "CharLowerW".}

+proc CharLowerBuffW*(lpsz: LPWSTR, cchLength: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "CharLowerBuffW".}

+proc CharNextW*(lpsz: LPCWSTR): LPWSTR{.stdcall, dynlib: "user32",

+                                        importc: "CharNextW".}

+proc CharPrevW*(lpszStart: LPCWSTR, lpszCurrent: LPCWSTR): LPWSTR{.stdcall,

+    dynlib: "user32", importc: "CharPrevW".}

+proc IsCharAlphaW*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "IsCharAlphaW".}

+proc IsCharAlphaNumericW*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsCharAlphaNumericW".}

+proc IsCharUpperW*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "IsCharUpperW".}

+proc IsCharLowerW*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "IsCharLowerW".}

+proc GetKeyNameTextW*(lParam: LONG, lpString: LPWSTR, nSize: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetKeyNameTextW".}

+proc VkKeyScanW*(ch: WCHAR): SHORT{.stdcall, dynlib: "user32",

+                                    importc: "VkKeyScanW".}

+proc VkKeyScanExW*(ch: WCHAR, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32",

+    importc: "VkKeyScanExW".}

+proc MapVirtualKeyW*(uCode: WINUINT, uMapType: WINUINT): WINUINT{.stdcall,

+    dynlib: "user32", importc: "MapVirtualKeyW".}

+proc MapVirtualKeyExW*(uCode: WINUINT, uMapType: WINUINT, dwhkl: HKL): WINUINT{.stdcall,

+    dynlib: "user32", importc: "MapVirtualKeyExW".}

+proc LoadAcceleratorsW*(hInstance: HINST, lpTableName: LPCWSTR): HACCEL{.

+    stdcall, dynlib: "user32", importc: "LoadAcceleratorsW".}

+proc CreateAcceleratorTableW*(para1: LPACCEL, para2: int32): HACCEL{.stdcall,

+    dynlib: "user32", importc: "CreateAcceleratorTableW".}

+proc CopyAcceleratorTableW*(hAccelSrc: HACCEL, lpAccelDst: LPACCEL,

+                            cAccelEntries: int32): int32{.stdcall,

+    dynlib: "user32", importc: "CopyAcceleratorTableW".}

+proc TranslateAcceleratorW*(wnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG): int32{.

+    stdcall, dynlib: "user32", importc: "TranslateAcceleratorW".}

+proc LoadMenuW*(hInstance: HINST, lpMenuName: LPCWSTR): HMENU{.stdcall,

+    dynlib: "user32", importc: "LoadMenuW".}

+proc LoadMenuIndirectW*(lpMenuTemplate: LPMENUTEMPLATE): HMENU{.stdcall,

+    dynlib: "user32", importc: "LoadMenuIndirectW".}

+proc ChangeMenuW*(menu: HMENU, cmd: WINUINT, lpszNewItem: LPCWSTR,

+                  cmdInsert: WINUINT, flags: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ChangeMenuW".}

+proc GetMenuStringW*(menu: HMENU, uIDItem: WINUINT, lpString: LPWSTR,

+                     nMaxCount: int32, uFlag: WINUINT): int32{.stdcall,

+    dynlib: "user32", importc: "GetMenuStringW".}

+proc InsertMenuW*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT, uIDNewItem: WINUINT,

+                  lpNewItem: LPCWSTR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "InsertMenuW".}

+proc AppendMenuW*(menu: HMENU, uFlags: WINUINT, uIDNewItem: WINUINT,

+                  lpNewItem: LPCWSTR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "AppendMenuW".}

+proc ModifyMenuW*(hMnu: HMENU, uPosition: WINUINT, uFlags: WINUINT, uIDNewItem: WINUINT,

+                  lpNewItem: LPCWSTR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ModifyMenuW".}

+proc InsertMenuItemW*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                      para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "InsertMenuItemW".}

+proc GetMenuItemInfoW*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                       para4: LPMENUITEMINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetMenuItemInfoW".}

+proc SetMenuItemInfoW*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                       para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetMenuItemInfoW".}

+proc DrawTextW*(hDC: HDC, lpString: LPCWSTR, nCount: int32, lpRect: LPRECT,

+                uFormat: WINUINT): int32{.stdcall, dynlib: "user32",

+                                       importc: "DrawTextW".}

+proc DrawTextExW*(para1: HDC, para2: LPWSTR, para3: int32, para4: LPRECT,

+                  para5: WINUINT, para6: LPDRAWTEXTPARAMS): int32{.stdcall,

+    dynlib: "user32", importc: "DrawTextExW".}

+proc GrayStringW*(hDC: HDC, hBrush: HBRUSH, lpOutputFunc: GRAYSTRINGPROC,

+                  lpData: LPARAM, nCount: int32, X: int32, Y: int32,

+                  nWidth: int32, nHeight: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GrayStringW".}

+proc DrawStateW*(para1: HDC, para2: HBRUSH, para3: DRAWSTATEPROC, para4: LPARAM,

+                 para5: WPARAM, para6: int32, para7: int32, para8: int32,

+                 para9: int32, para10: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DrawStateW".}

+proc TabbedTextOutW*(hDC: HDC, X: int32, Y: int32, lpString: LPCWSTR,

+                     nCount: int32, nTabPositions: int32,

+                     lpnTabStopPositions: LPINT, nTabOrigin: int32): LONG{.

+    stdcall, dynlib: "user32", importc: "TabbedTextOutW".}

+proc GetTabbedTextExtentW*(hDC: HDC, lpString: LPCWSTR, nCount: int32,

+                           nTabPositions: int32, lpnTabStopPositions: LPINT): DWORD{.

+    stdcall, dynlib: "user32", importc: "GetTabbedTextExtentW".}

+proc SetPropW*(wnd: HWND, lpString: LPCWSTR, hData: HANDLE): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetPropW".}

+proc GetPropW*(wnd: HWND, lpString: LPCWSTR): HANDLE{.stdcall,

+    dynlib: "user32", importc: "GetPropW".}

+proc RemovePropW*(wnd: HWND, lpString: LPCWSTR): HANDLE{.stdcall,

+    dynlib: "user32", importc: "RemovePropW".}

+proc EnumPropsExW*(wnd: HWND, lpEnumFunc: PROPENUMPROCEX, lp: LPARAM): int32{.

+    stdcall, dynlib: "user32", importc: "EnumPropsExW".}

+proc EnumPropsW*(wnd: HWND, lpEnumFunc: PROPENUMPROC): int32{.stdcall,

+    dynlib: "user32", importc: "EnumPropsW".}

+proc SetWindowTextW*(wnd: HWND, lpString: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetWindowTextW".}

+proc GetWindowTextW*(wnd: HWND, lpString: LPWSTR, nMaxCount: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetWindowTextW".}

+proc GetWindowTextLengthW*(wnd: HWND): int32{.stdcall, dynlib: "user32",

+    importc: "GetWindowTextLengthW".}

+proc MessageBoxW*(wnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: WINUINT): int32{.

+    stdcall, dynlib: "user32", importc: "MessageBoxW".}

+proc MessageBoxExW*(wnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR,

+                    uType: WINUINT, wLanguageId: int16): int32{.stdcall,

+    dynlib: "user32", importc: "MessageBoxExW".}

+proc MessageBoxIndirectW*(para1: LPMSGBOXPARAMS): int32{.stdcall,

+    dynlib: "user32", importc: "MessageBoxIndirectW".}

+proc GetWindowLongW*(wnd: HWND, nIndex: int32): LONG{.stdcall,

+    dynlib: "user32", importc: "GetWindowLongW".}

+proc SetWindowLongW*(wnd: HWND, nIndex: int32, dwNewLong: LONG): LONG{.stdcall,

+    dynlib: "user32", importc: "SetWindowLongW".}

+proc GetClassLongW*(wnd: HWND, nIndex: int32): DWORD{.stdcall,

+    dynlib: "user32", importc: "GetClassLongW".}

+proc SetClassLongW*(wnd: HWND, nIndex: int32, dwNewLong: LONG): DWORD{.stdcall,

+    dynlib: "user32", importc: "SetClassLongW".}

+when defined(cpu64):

+  proc GetWindowLongPtrW*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetWindowLongPtrW".}

+  proc SetWindowLongPtrW*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetWindowLongPtrW".}

+  proc GetClassLongPtrW*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetClassLongPtrW".}

+  proc SetClassLongPtrW*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetClassLongPtrW".}

+else:

+  proc GetWindowLongPtrW*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetWindowLongW".}

+  proc SetWindowLongPtrW*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetWindowLongW".}

+  proc GetClassLongPtrW*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+      dynlib: "user32", importc: "GetClassLongW".}

+  proc SetClassLongPtrW*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+      stdcall, dynlib: "user32", importc: "SetClassLongW".}

+proc FindWindowW*(lpClassName: LPCWSTR, lpWindowName: LPCWSTR): HWND{.stdcall,

+    dynlib: "user32", importc: "FindWindowW".}

+proc FindWindowExW*(para1: HWND, para2: HWND, para3: LPCWSTR, para4: LPCWSTR): HWND{.

+    stdcall, dynlib: "user32", importc: "FindWindowExW".}

+proc GetClassNameW*(wnd: HWND, lpClassName: LPWSTR, nMaxCount: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetClassNameW".}

+proc SetWindowsHookExW*(idHook: int32, lpfn: HOOKPROC, hmod: HINST,

+                        dwThreadId: DWORD): HHOOK{.stdcall, dynlib: "user32",

+    importc: "SetWindowsHookExW".}

+proc LoadBitmapW*(hInstance: HINST, lpBitmapName: LPCWSTR): HBITMAP{.stdcall,

+    dynlib: "user32", importc: "LoadBitmapW".}

+proc LoadCursorW*(hInstance: HINST, lpCursorName: LPCWSTR): HCURSOR{.stdcall,

+    dynlib: "user32", importc: "LoadCursorW".}

+proc LoadCursorFromFileW*(lpFileName: LPCWSTR): HCURSOR{.stdcall,

+    dynlib: "user32", importc: "LoadCursorFromFileW".}

+proc LoadIconW*(hInstance: HINST, lpIconName: LPCWSTR): HICON{.stdcall,

+    dynlib: "user32", importc: "LoadIconW".}

+proc LoadImageW*(para1: HINST, para2: LPCWSTR, para3: WINUINT, para4: int32,

+                 para5: int32, para6: WINUINT): HANDLE{.stdcall, dynlib: "user32",

+    importc: "LoadImageW".}

+proc LoadStringW*(hInstance: HINST, uID: WINUINT, lpBuffer: LPWSTR,

+                  nBufferMax: int32): int32{.stdcall, dynlib: "user32",

+    importc: "LoadStringW".}

+proc IsDialogMessageW*(hDlg: HWND, lpMsg: LPMSG): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "IsDialogMessageW".}

+proc DlgDirListW*(hDlg: HWND, lpPathSpec: LPWSTR, nIDListBox: int32,

+                  nIDStaticPath: int32, uFileType: WINUINT): int32{.stdcall,

+    dynlib: "user32", importc: "DlgDirListW".}

+proc DlgDirSelectExW*(hDlg: HWND, lpString: LPWSTR, nCount: int32,

+                      nIDListBox: int32): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DlgDirSelectExW".}

+proc DlgDirListComboBoxW*(hDlg: HWND, lpPathSpec: LPWSTR, nIDComboBox: int32,

+                          nIDStaticPath: int32, uFiletype: WINUINT): int32{.

+    stdcall, dynlib: "user32", importc: "DlgDirListComboBoxW".}

+proc DlgDirSelectComboBoxExW*(hDlg: HWND, lpString: LPWSTR, nCount: int32,

+                              nIDComboBox: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DlgDirSelectComboBoxExW".}

+proc DefFrameProcW*(wnd: HWND, hWndMDIClient: HWND, uMsg: WINUINT, w: WPARAM,

+                    lp: LPARAM): LRESULT{.stdcall, dynlib: "user32",

+    importc: "DefFrameProcW".}

+proc DefMDIChildProcW*(wnd: HWND, uMsg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "DefMDIChildProcW".}

+proc CreateMDIWindowW*(lpClassName: LPWSTR, lpWindowName: LPWSTR,

+                       dwStyle: DWORD, X: int32, Y: int32, nWidth: int32,

+                       nHeight: int32, hWndParent: HWND, hInstance: HINST,

+                       lp: LPARAM): HWND{.stdcall, dynlib: "user32",

+    importc: "CreateMDIWindowW".}

+proc WinHelpW*(hWndMain: HWND, lpszHelp: LPCWSTR, uCommand: WINUINT, dwData: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "WinHelpW".}

+proc ChangeDisplaySettingsW*(lpDevMode: LPDEVMODEW, dwFlags: DWORD): LONG{.

+    stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsW".}

+proc EnumDisplaySettingsW*(lpszDeviceName: LPCWSTR, iModeNum: DWORD,

+                           lpDevMode: LPDEVMODEW): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EnumDisplaySettingsW".}

+proc SystemParametersInfoW*(uiAction: WINUINT, uiParam: WINUINT, pvParam: PVOID,

+                            fWinIni: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SystemParametersInfoW".}

+proc AddFontResourceW*(para1: LPCWSTR): int32{.stdcall, dynlib: "gdi32",

+    importc: "AddFontResourceW".}

+proc CopyMetaFileW*(para1: HMETAFILE, para2: LPCWSTR): HMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "CopyMetaFileW".}

+proc CreateFontIndirectW*(para1: PLOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+    importc: "CreateFontIndirectW".}

+proc CreateFontIndirectW*(para1: var LOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+    importc: "CreateFontIndirectW".}

+proc CreateFontW*(para1: int32, para2: int32, para3: int32, para4: int32,

+                  para5: int32, para6: DWORD, para7: DWORD, para8: DWORD,

+                  para9: DWORD, para10: DWORD, para11: DWORD, para12: DWORD,

+                  para13: DWORD, para14: LPCWSTR): HFONT{.stdcall,

+    dynlib: "gdi32", importc: "CreateFontW".}

+proc CreateICW*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR,

+                para4: LPDEVMODEw): HDC{.stdcall, dynlib: "gdi32",

+    importc: "CreateICW".}

+proc CreateMetaFileW*(para1: LPCWSTR): HDC{.stdcall, dynlib: "gdi32",

+    importc: "CreateMetaFileW".}

+proc CreateScalableFontResourceW*(para1: DWORD, para2: LPCWSTR, para3: LPCWSTR,

+                                  para4: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "CreateScalableFontResourceW".}

+proc EnumFontFamiliesExW*(para1: HDC, para2: LPLOGFONT, para3: FONTENUMEXPROC,

+                          para4: LPARAM, para5: DWORD): int32{.stdcall,

+    dynlib: "gdi32", importc: "EnumFontFamiliesExW".}

+proc EnumFontFamiliesW*(para1: HDC, para2: LPCWSTR, para3: FONTENUMPROC,

+                        para4: LPARAM): int32{.stdcall, dynlib: "gdi32",

+    importc: "EnumFontFamiliesW".}

+proc EnumFontsW*(para1: HDC, para2: LPCWSTR, para3: ENUMFONTSPROC, para4: LPARAM): int32{.

+    stdcall, dynlib: "gdi32", importc: "EnumFontsW".}

+proc EnumFontsW*(para1: HDC, para2: LPCWSTR, para3: ENUMFONTSPROC,

+                 para4: pointer): int32{.stdcall, dynlib: "gdi32",

+    importc: "EnumFontsW".}

+proc GetCharWidthW*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthW".}

+proc GetCharWidth32W*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidth32W".}

+proc GetCharWidthFloatW*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: ptr float32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatW".}

+proc GetCharABCWidthsW*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPABC): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsW".}

+proc GetCharABCWidthsFloatW*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                             para4: LPABCFLOAT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharABCWidthsFloatW".}

+proc GetGlyphOutlineW*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                       para4: LPGLYPHMETRICS, para5: DWORD, para6: LPVOID,

+                       para7: PMAT2): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GetGlyphOutlineW".}

+proc GetMetaFileW*(para1: LPCWSTR): HMETAFILE{.stdcall, dynlib: "gdi32",

+    importc: "GetMetaFileW".}

+proc GetOutlineTextMetricsW*(para1: HDC, para2: WINUINT, para3: LPOUTLINETEXTMETRIC): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetOutlineTextMetricsW".}

+proc GetTextExtentPointW*(para1: HDC, para2: LPCWSTR, para3: int32,

+                          para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentPointW".}

+proc GetTextExtentPoint32W*(para1: HDC, para2: LPCWSTR, para3: int32,

+                            para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentPoint32W".}

+proc GetTextExtentExPointW*(para1: HDC, para2: LPCWSTR, para3: int32,

+                            para4: int32, para5: LPINT, para6: LPINT,

+                            para7: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentExPointW".}

+proc GetCharacterPlacementW*(para1: HDC, para2: LPCWSTR, para3: int32,

+                             para4: int32, para5: LPGCP_RESULTS, para6: DWORD): DWORD{.

+    stdcall, dynlib: "gdi32", importc: "GetCharacterPlacementW".}

+proc ResetDCW*(para1: HDC, para2: LPDEVMODEW): HDC{.stdcall, dynlib: "gdi32",

+    importc: "ResetDCW".}

+proc RemoveFontResourceW*(para1: LPCWSTR): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "RemoveFontResourceW".}

+proc CopyEnhMetaFileW*(para1: HENHMETAFILE, para2: LPCWSTR): HENHMETAFILE{.

+    stdcall, dynlib: "gdi32", importc: "CopyEnhMetaFileW".}

+proc CreateEnhMetaFileW*(para1: HDC, para2: LPCWSTR, para3: LPRECT,

+                         para4: LPCWSTR): HDC{.stdcall, dynlib: "gdi32",

+    importc: "CreateEnhMetaFileW".}

+proc GetEnhMetaFileW*(para1: LPCWSTR): HENHMETAFILE{.stdcall, dynlib: "gdi32",

+    importc: "GetEnhMetaFileW".}

+proc GetEnhMetaFileDescriptionW*(para1: HENHMETAFILE, para2: WINUINT, para3: LPWSTR): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetEnhMetaFileDescriptionW".}

+proc GetTextMetricsW*(para1: HDC, para2: LPTEXTMETRIC): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetTextMetricsW".}

+proc StartDocW*(para1: HDC, para2: PDOCINFO): int32{.stdcall, dynlib: "gdi32",

+    importc: "StartDocW".}

+proc GetObjectW*(para1: HGDIOBJ, para2: int32, para3: LPVOID): int32{.stdcall,

+    dynlib: "gdi32", importc: "GetObjectW".}

+proc TextOutW*(para1: HDC, para2: int32, para3: int32, para4: LPCWSTR,

+               para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+                                       importc: "TextOutW".}

+proc ExtTextOutW*(para1: HDC, para2: int32, para3: int32, para4: WINUINT,

+                  para5: LPRECT, para6: LPCWSTR, para7: WINUINT, para8: LPINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "ExtTextOutW".}

+proc PolyTextOutW*(para1: HDC, para2: PPOLYTEXT, para3: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyTextOutW".}

+proc GetTextFaceW*(para1: HDC, para2: int32, para3: LPWSTR): int32{.stdcall,

+    dynlib: "gdi32", importc: "GetTextFaceW".}

+proc GetKerningPairsW*(para1: HDC, para2: DWORD, para3: LPKERNINGPAIR): DWORD{.

+    stdcall, dynlib: "gdi32", importc: "GetKerningPairsW".}

+proc GetLogColorSpaceW*(para1: HCOLORSPACE, para2: LPLOGCOLORSPACE, para3: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetLogColorSpaceW".}

+proc CreateColorSpaceW*(para1: LPLOGCOLORSPACE): HCOLORSPACE{.stdcall,

+    dynlib: "gdi32", importc: "CreateColorSpaceW".}

+proc GetICMProfileW*(para1: HDC, para2: DWORD, para3: LPWSTR): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetICMProfileW".}

+proc SetICMProfileW*(para1: HDC, para2: LPWSTR): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "SetICMProfileW".}

+proc UpdateICMRegKeyW*(para1: DWORD, para2: DWORD, para3: LPWSTR, para4: WINUINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "UpdateICMRegKeyW".}

+proc EnumICMProfilesW*(para1: HDC, para2: ICMENUMPROC, para3: LPARAM): int32{.

+    stdcall, dynlib: "gdi32", importc: "EnumICMProfilesW".}

+proc CreatePropertySheetPageW*(lppsp: LPCPROPSHEETPAGE): HPROPSHEETPAGE{.

+    stdcall, dynlib: "comctl32", importc: "CreatePropertySheetPageW".}

+proc PropertySheetW*(lppsph: LPCPROPSHEETHEADER): int32{.stdcall,

+    dynlib: "comctl32", importc: "PropertySheetW".}

+proc ImageList_LoadImageW*(hi: HINST, lpbmp: LPCWSTR, cx: int32, cGrow: int32,

+                           crMask: COLORREF, uType: WINUINT, uFlags: WINUINT): HIMAGELIST{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_LoadImageW".}

+proc CreateStatusWindowW*(style: LONG, lpszText: LPCWSTR, hwndParent: HWND,

+                          wID: WINUINT): HWND{.stdcall, dynlib: "comctl32",

+    importc: "CreateStatusWindowW".}

+proc DrawStatusTextW*(hDC: HDC, lprc: LPRECT, pszText: LPCWSTR, uFlags: WINUINT){.

+    stdcall, dynlib: "comctl32", importc: "DrawStatusTextW".}

+proc GetOpenFileNameW*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+    dynlib: "comdlg32", importc: "GetOpenFileNameW".}

+proc GetSaveFileNameW*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+    dynlib: "comdlg32", importc: "GetSaveFileNameW".}

+proc GetFileTitleW*(para1: LPCWSTR, para2: LPWSTR, para3: int16): int{.stdcall,

+    dynlib: "comdlg32", importc: "GetFileTitleW".}

+proc ChooseColorW*(para1: LPCHOOSECOLOR): WINBOOL{.stdcall, dynlib: "comdlg32",

+    importc: "ChooseColorW".}

+proc ReplaceTextW*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+    importc: "ReplaceTextW".}

+proc ChooseFontW*(para1: LPCHOOSEFONT): WINBOOL{.stdcall, dynlib: "comdlg32",

+    importc: "ChooseFontW".}

+proc FindTextW*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+    importc: "FindTextW".}

+proc PrintDlgW*(para1: LPPRINTDLG): WINBOOL{.stdcall, dynlib: "comdlg32",

+    importc: "PrintDlgW".}

+proc PageSetupDlgW*(para1: LPPAGESETUPDLG): WINBOOL{.stdcall,

+    dynlib: "comdlg32", importc: "PageSetupDlgW".}

+proc CreateProcessW*(lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR,

+                     lpProcessAttributes: LPSECURITY_ATTRIBUTES,

+                     lpThreadAttributes: LPSECURITY_ATTRIBUTES,

+                     bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                     lpEnvironment: LPVOID, lpCurrentDirectory: LPCWSTR,

+                     lpStartupInfo: LPSTARTUPINFO,

+                     lpProcessInformation: LPPROCESS_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateProcessW".}

+proc GetStartupInfoW*(lpStartupInfo: LPSTARTUPINFO){.stdcall,

+    dynlib: "kernel32", importc: "GetStartupInfoW".}

+proc FindFirstFileW*(lpFileName: LPCWSTR, lpFindFileData: LPWIN32_FIND_DATAW): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}

+proc FindNextFileW*(hFindFile: HANDLE, lpFindFileData: LPWIN32_FIND_DATAW): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FindNextFileW".}

+proc GetVersionExW*(VersionInformation: LPOSVERSIONINFOW): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVersionExW".}

+proc CreateWindowW*(lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD,

+                    X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                    hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                    lpParam: LPVOID): HWND

+proc CreateDialogW*(hInstance: HINST, lpName: LPCWSTR, hWndParent: HWND,

+                    lpDialogFunc: DLGPROC): HWND

+proc CreateDialogIndirectW*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                            hWndParent: HWND, lpDialogFunc: DLGPROC): HWND

+proc DialogBoxW*(hInstance: HINST, lpTemplate: LPCWSTR, hWndParent: HWND,

+                 lpDialogFunc: DLGPROC): int32

+proc DialogBoxIndirectW*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                         hWndParent: HWND, lpDialogFunc: DLGPROC): int32

+proc CreateDCW*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR, para4: PDEVMODEW): HDC{.

+    stdcall, dynlib: "gdi32", importc: "CreateDCW".}

+proc VerInstallFileW*(uFlags: DWORD, szSrcFileName: LPWSTR,

+                      szDestFileName: LPWSTR, szSrcDir: LPWSTR,

+                      szDestDir: LPWSTR, szCurDir: LPWSTR, szTmpFile: LPWSTR,

+                      lpuTmpFileLen: PUINT): DWORD{.stdcall, dynlib: "version",

+    importc: "VerInstallFileW".}

+proc GetFileVersionInfoSizeW*(lptstrFilename: LPWSTR, lpdwHandle: LPDWORD): DWORD{.

+    stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeW".}

+proc GetFileVersionInfoW*(lptstrFilename: LPWSTR, dwHandle: DWORD, dwLen: DWORD,

+                          lpData: LPVOID): WINBOOL{.stdcall, dynlib: "version",

+    importc: "GetFileVersionInfoW".}

+proc VerLanguageNameW*(wLang: DWORD, szLang: LPWSTR, nSize: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VerLanguageNameW".}

+proc VerQueryValueW*(pBlock: LPVOID, lpSubBlock: LPWSTR, lplpBuffer: LPVOID,

+                     puLen: PUINT): WINBOOL{.stdcall, dynlib: "version",

+    importc: "VerQueryValueW".}

+proc VerFindFileW*(uFlags: DWORD, szFileName: LPWSTR, szWinDir: LPWSTR,

+                   szAppDir: LPWSTR, szCurDir: LPWSTR, lpuCurDirLen: PUINT,

+                   szDestDir: LPWSTR, lpuDestDirLen: PUINT): DWORD{.stdcall,

+    dynlib: "version", importc: "VerFindFileW".}

+proc RegSetValueExW*(key: HKEY, lpValueName: LPCWSTR, Reserved: DWORD,

+                     dwType: DWORD, lpData: LPBYTE, cbData: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegSetValueExW".}

+proc RegUnLoadKeyW*(key: HKEY, lpSubKey: LPCWSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegUnLoadKeyW".}

+proc InitiateSystemShutdownW*(lpMachineName: LPWSTR, lpMessage: LPWSTR,

+                              dwTimeout: DWORD, bForceAppsClosed: WINBOOL,

+                              bRebootAfterShutdown: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "InitiateSystemShutdownW".}

+proc AbortSystemShutdownW*(lpMachineName: LPWSTR): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AbortSystemShutdownW".}

+proc RegRestoreKeyW*(key: HKEY, lpFile: LPCWSTR, dwFlags: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegRestoreKeyW".}

+proc RegSaveKeyW*(key: HKEY, lpFile: LPCWSTR,

+                  lpSecurityAttributes: LPSECURITY_ATTRIBUTES): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegSaveKeyW".}

+proc RegSetValueW*(key: HKEY, lpSubKey: LPCWSTR, dwType: DWORD,

+                   lpData: LPCWSTR, cbData: DWORD): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegSetValueW".}

+proc RegQueryValueW*(key: HKEY, lpSubKey: LPCWSTR, lpValue: LPWSTR,

+                     lpcbValue: PLONG): LONG{.stdcall, dynlib: "advapi32",

+    importc: "RegQueryValueW".}

+proc RegQueryMultipleValuesW*(key: HKEY, val_list: PVALENT, num_vals: DWORD,

+                              lpValueBuf: LPWSTR, ldwTotsize: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesW".}

+proc RegQueryValueExW*(key: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,

+                       lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryValueExW".}

+proc RegReplaceKeyW*(key: HKEY, lpSubKey: LPCWSTR, lpNewFile: LPCWSTR,

+                     lpOldFile: LPCWSTR): LONG{.stdcall, dynlib: "advapi32",

+    importc: "RegReplaceKeyW".}

+proc RegConnectRegistryW*(lpMachineName: LPWSTR, key: HKEY, phkResult: PHKEY): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegConnectRegistryW".}

+proc RegCreateKeyW*(key: HKEY, lpSubKey: LPCWSTR, phkResult: PHKEY): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyW".}

+proc RegCreateKeyExW*(key: HKEY, lpSubKey: LPCWSTR, Reserved: DWORD,

+                      lpClass: LPWSTR, dwOptions: DWORD, samDesired: REGSAM,

+                      lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                      phkResult: PHKEY, lpdwDisposition: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyExW".}

+proc RegDeleteKeyW*(key: HKEY, lpSubKey: LPCWSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegDeleteKeyW".}

+proc RegDeleteValueW*(key: HKEY, lpValueName: LPCWSTR): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegDeleteValueW".}

+proc RegEnumKeyW*(key: HKEY, dwIndex: DWORD, lpName: LPWSTR, cbName: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyW".}

+proc RegEnumKeyExW*(key: HKEY, dwIndex: DWORD, lpName: LPWSTR,

+                    lpcbName: LPDWORD, lpReserved: LPDWORD, lpClass: LPWSTR,

+                    lpcbClass: LPDWORD, lpftLastWriteTime: PFILETIME): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyExW".}

+proc RegEnumValueW*(key: HKEY, dwIndex: DWORD, lpValueName: LPWSTR,

+                    lpcbValueName: LPDWORD, lpReserved: LPDWORD,

+                    lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumValueW".}

+proc RegLoadKeyW*(key: HKEY, lpSubKey: LPCWSTR, lpFile: LPCWSTR): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegLoadKeyW".}

+proc RegOpenKeyW*(key: HKEY, lpSubKey: LPCWSTR, phkResult: PHKEY): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegOpenKeyW".}

+proc RegOpenKeyExW*(key: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD,

+                    samDesired: REGSAM, phkResult: PHKEY): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegOpenKeyExW".}

+proc RegQueryInfoKeyW*(key: HKEY, lpClass: LPWSTR, lpcbClass: LPDWORD,

+                       lpReserved: LPDWORD, lpcSubKeys: LPDWORD,

+                       lpcbMaxSubKeyLen: LPDWORD, lpcbMaxClassLen: LPDWORD,

+                       lpcValues: LPDWORD, lpcbMaxValueNameLen: LPDWORD,

+                       lpcbMaxValueLen: LPDWORD,

+                       lpcbSecurityDescriptor: LPDWORD,

+                       lpftLastWriteTime: PFILETIME): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegQueryInfoKeyW".}

+proc CompareStringW*(Locale: LCID, dwCmpFlags: DWORD, lpString1: LPCWSTR,

+                     cchCount1: int32, lpString2: LPCWSTR, cchCount2: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "CompareStringW".}

+proc LCMapStringW*(Locale: LCID, dwMapFlags: DWORD, lpSrcStr: LPCWSTR,

+                   cchSrc: int32, lpDestStr: LPWSTR, cchDest: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "LCMapStringW".}

+proc GetLocaleInfoW*(Locale: LCID, LCType: LCTYPE, lpLCData: LPWSTR,

+                     cchData: int32): int32{.stdcall, dynlib: "kernel32",

+    importc: "GetLocaleInfoW".}

+proc SetLocaleInfoW*(Locale: LCID, LCType: LCTYPE, lpLCData: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetLocaleInfoW".}

+proc GetTimeFormatW*(Locale: LCID, dwFlags: DWORD, lpTime: LPSYSTEMTIME,

+                     lpFormat: LPCWSTR, lpTimeStr: LPWSTR, cchTime: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "GetTimeFormatW".}

+proc GetDateFormatW*(Locale: LCID, dwFlags: DWORD, lpDate: LPSYSTEMTIME,

+                     lpFormat: LPCWSTR, lpDateStr: LPWSTR, cchDate: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "GetDateFormatW".}

+proc GetNumberFormatW*(Locale: LCID, dwFlags: DWORD, lpValue: LPCWSTR,

+                       lpFormat: PNUMBERFMT, lpNumberStr: LPWSTR,

+                       cchNumber: int32): int32{.stdcall, dynlib: "kernel32",

+    importc: "GetNumberFormatW".}

+proc GetCurrencyFormatW*(Locale: LCID, dwFlags: DWORD, lpValue: LPCWSTR,

+                         lpFormat: PCURRENCYFMT, lpCurrencyStr: LPWSTR,

+                         cchCurrency: int32): int32{.stdcall,

+    dynlib: "kernel32", importc: "GetCurrencyFormatW".}

+proc EnumCalendarInfoW*(lpCalInfoEnumProc: CALINFO_ENUMPROC, Locale: LCID,

+                        Calendar: CALID, CalType: CALTYPE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "EnumCalendarInfoW".}

+proc EnumTimeFormatsW*(lpTimeFmtEnumProc: TIMEFMT_ENUMPROC, Locale: LCID,

+                       dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "EnumTimeFormatsW".}

+proc EnumDateFormatsW*(lpDateFmtEnumProc: DATEFMT_ENUMPROC, Locale: LCID,

+                       dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "EnumDateFormatsW".}

+proc GetStringTypeExW*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCWSTR,

+                       cchSrc: int32, lpCharType: LPWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeExW".}

+proc GetStringTypeW*(dwInfoType: DWORD, lpSrcStr: LPCWSTR, cchSrc: int32,

+                     lpCharType: LPWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "GetStringTypeW".}

+proc FoldStringW*(dwMapFlags: DWORD, lpSrcStr: LPCWSTR, cchSrc: int32,

+                  lpDestStr: LPWSTR, cchDest: int32): int32{.stdcall,

+    dynlib: "kernel32", importc: "FoldStringW".}

+proc EnumSystemLocalesW*(lpLocaleEnumProc: LOCALE_ENUMPROC, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumSystemLocalesW".}

+proc EnumSystemCodePagesW*(lpCodePageEnumProc: CODEPAGE_ENUMPROC, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "EnumSystemCodePagesW".}

+proc PeekConsoleInputW*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                        nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "PeekConsoleInputW".}

+proc ReadConsoleInputW*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                        nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}

+proc WriteConsoleInputW*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                         nLength: DWORD, lpNumberOfEventsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleInputW".}

+proc ReadConsoleOutputW*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                         dwBufferSize: COORD, dwBufferCoord: COORD,

+                         lpReadRegion: PSMALL_RECT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadConsoleOutputW".}

+proc WriteConsoleOutputW*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                          dwBufferSize: COORD, dwBufferCoord: COORD,

+                          lpWriteRegion: PSMALL_RECT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteConsoleOutputW".}

+proc ReadConsoleOutputCharacterW*(hConsoleOutput: HANDLE, lpCharacter: LPWSTR,

+                                  nLength: DWORD, dwReadCoord: COORD,

+                                  lpNumberOfCharsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterW".}

+proc WriteConsoleOutputCharacterW*(hConsoleOutput: HANDLE, lpCharacter: LPCWSTR,

+                                   nLength: DWORD, dwWriteCoord: COORD,

+                                   lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterW".}

+proc FillConsoleOutputCharacterW*(hConsoleOutput: HANDLE, cCharacter: WCHAR,

+                                  nLength: DWORD, dwWriteCoord: COORD,

+                                  lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterW".}

+proc ScrollConsoleScreenBufferW*(hConsoleOutput: HANDLE,

+                                 lpScrollRectangle: PSMALL_RECT,

+                                 lpClipRectangle: PSMALL_RECT,

+                                 dwDestinationOrigin: COORD, lpFill: PCHAR_INFO): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ScrollConsoleScreenBufferW".}

+proc GetConsoleTitleW*(lpConsoleTitle: LPWSTR, nSize: DWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetConsoleTitleW".}

+proc SetConsoleTitleW*(lpConsoleTitle: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetConsoleTitleW".}

+proc ReadConsoleW*(hConsoleInput: HANDLE, lpBuffer: LPVOID,

+                   nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: LPDWORD,

+                   lpReserved: LPVOID): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ReadConsoleW".}

+proc WriteConsoleW*(hConsoleOutput: HANDLE, lpBuffer: pointer,

+                    nNumberOfCharsToWrite: DWORD,

+                    lpNumberOfCharsWritten: LPDWORD, lpReserved: LPVOID): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleW".}

+proc WNetAddConnectionW*(lpRemoteName: LPCWSTR, lpPassword: LPCWSTR,

+                         lpLocalName: LPCWSTR): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetAddConnectionW".}

+proc WNetAddConnection2W*(lpNetResource: LPNETRESOURCE, lpPassword: LPCWSTR,

+                          lpUserName: LPCWSTR, dwFlags: DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetAddConnection2W".}

+proc WNetAddConnection3W*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                          lpPassword: LPCWSTR, lpUserName: LPCWSTR,

+                          dwFlags: DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetAddConnection3W".}

+proc WNetCancelConnectionW*(lpName: LPCWSTR, fForce: WINBOOL): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetCancelConnectionW".}

+proc WNetCancelConnection2W*(lpName: LPCWSTR, dwFlags: DWORD, fForce: WINBOOL): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetCancelConnection2W".}

+proc WNetGetConnectionW*(lpLocalName: LPCWSTR, lpRemoteName: LPWSTR,

+                         lpnLength: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetConnectionW".}

+proc WNetUseConnectionW*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                         lpUserID: LPCWSTR, lpPassword: LPCWSTR, dwFlags: DWORD,

+                         lpAccessName: LPWSTR, lpBufferSize: LPDWORD,

+                         lpResult: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetUseConnectionW".}

+proc WNetSetConnectionW*(lpName: LPCWSTR, dwProperties: DWORD, pvValues: LPVOID): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetSetConnectionW".}

+proc WNetConnectionDialog1W*(lpConnDlgStruct: LPCONNECTDLGSTRUCT): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetConnectionDialog1W".}

+proc WNetDisconnectDialog1W*(lpConnDlgStruct: LPDISCDLGSTRUCT): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetDisconnectDialog1W".}

+proc WNetOpenEnumW*(dwScope: DWORD, dwType: DWORD, dwUsage: DWORD,

+                    lpNetResource: LPNETRESOURCE, lphEnum: LPHANDLE): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetOpenEnumW".}

+proc WNetEnumResourceW*(hEnum: HANDLE, lpcCount: LPDWORD, lpBuffer: LPVOID,

+                        lpBufferSize: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetEnumResourceW".}

+proc WNetGetUniversalNameW*(lpLocalPath: LPCWSTR, dwInfoLevel: DWORD,

+                            lpBuffer: LPVOID, lpBufferSize: LPDWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameW".}

+proc WNetGetUserW*(lpName: LPCWSTR, lpUserName: LPWSTR, lpnLength: LPDWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUserW".}

+proc WNetGetProviderNameW*(dwNetType: DWORD, lpProviderName: LPWSTR,

+                           lpBufferSize: LPDWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetGetProviderNameW".}

+proc WNetGetNetworkInformationW*(lpProvider: LPCWSTR,

+                                 lpNetInfoStruct: LPNETINFOSTRUCT): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationW".}

+proc WNetGetLastErrorW*(lpError: LPDWORD, lpErrorBuf: LPWSTR,

+                        nErrorBufSize: DWORD, lpNameBuf: LPWSTR,

+                        nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetLastErrorW".}

+proc MultinetGetConnectionPerformanceW*(lpNetResource: LPNETRESOURCE,

+    lpNetConnectInfoStruct: LPNETCONNECTINFOSTRUCT): DWORD{.stdcall,

+    dynlib: "mpr", importc: "MultinetGetConnectionPerformanceW".}

+proc ChangeServiceConfigW*(hService: SC_HANDLE, dwServiceType: DWORD,

+                           dwStartType: DWORD, dwErrorControl: DWORD,

+                           lpBinaryPathName: LPCWSTR, lpLoadOrderGroup: LPCWSTR,

+                           lpdwTagId: LPDWORD, lpDependencies: LPCWSTR,

+                           lpServiceStartName: LPCWSTR, lpPassword: LPCWSTR,

+                           lpDisplayName: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ChangeServiceConfigW".}

+proc CreateServiceW*(hSCManager: SC_HANDLE, lpServiceName: LPCWSTR,

+                     lpDisplayName: LPCWSTR, dwDesiredAccess: DWORD,

+                     dwServiceType: DWORD, dwStartType: DWORD,

+                     dwErrorControl: DWORD, lpBinaryPathName: LPCWSTR,

+                     lpLoadOrderGroup: LPCWSTR, lpdwTagId: LPDWORD,

+                     lpDependencies: LPCWSTR, lpServiceStartName: LPCWSTR,

+                     lpPassword: LPCWSTR): SC_HANDLE{.stdcall,

+    dynlib: "advapi32", importc: "CreateServiceW".}

+proc EnumDependentServicesW*(hService: SC_HANDLE, dwServiceState: DWORD,

+                             lpServices: LPENUM_SERVICE_STATUS,

+                             cbBufSize: DWORD, pcbBytesNeeded: LPDWORD,

+                             lpServicesReturned: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "EnumDependentServicesW".}

+proc EnumServicesStatusW*(hSCManager: SC_HANDLE, dwServiceType: DWORD,

+                          dwServiceState: DWORD,

+                          lpServices: LPENUM_SERVICE_STATUS, cbBufSize: DWORD,

+                          pcbBytesNeeded: LPDWORD, lpServicesReturned: LPDWORD,

+                          lpResumeHandle: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "EnumServicesStatusW".}

+proc GetServiceKeyNameW*(hSCManager: SC_HANDLE, lpDisplayName: LPCWSTR,

+                         lpServiceName: LPWSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetServiceKeyNameW".}

+proc GetServiceDisplayNameW*(hSCManager: SC_HANDLE, lpServiceName: LPCWSTR,

+                             lpDisplayName: LPWSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetServiceDisplayNameW".}

+proc OpenSCManagerW*(lpMachineName: LPCWSTR, lpDatabaseName: LPCWSTR,

+                     dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+    dynlib: "advapi32", importc: "OpenSCManagerW".}

+proc OpenServiceW*(hSCManager: SC_HANDLE, lpServiceName: LPCWSTR,

+                   dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+    dynlib: "advapi32", importc: "OpenServiceW".}

+proc QueryServiceConfigW*(hService: SC_HANDLE,

+                          lpServiceConfig: LPQUERY_SERVICE_CONFIG,

+                          cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "QueryServiceConfigW".}

+proc QueryServiceLockStatusW*(hSCManager: SC_HANDLE,

+                              lpLockStatus: LPQUERY_SERVICE_LOCK_STATUS,

+                              cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "QueryServiceLockStatusW".}

+proc RegisterServiceCtrlHandlerW*(lpServiceName: LPCWSTR,

+                                  lpHandlerProc: LPHANDLER_FUNCTION): SERVICE_STATUS_HANDLE{.

+    stdcall, dynlib: "advapi32", importc: "RegisterServiceCtrlHandlerW".}

+proc StartServiceCtrlDispatcherW*(lpServiceStartTable: LPSERVICE_TABLE_ENTRY): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "StartServiceCtrlDispatcherW".}

+proc StartServiceW*(hService: SC_HANDLE, dwNumServiceArgs: DWORD,

+                    lpServiceArgVectors: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "StartServiceW".}

+proc DragQueryFileW*(para1: HDROP, para2: int, para3: LPCWSTR, para4: int): int{.

+    stdcall, dynlib: "shell32", importc: "DragQueryFileW".}

+proc ExtractAssociatedIconW*(para1: HINST, para2: LPCWSTR, para3: LPWORD): HICON{.

+    stdcall, dynlib: "shell32", importc: "ExtractAssociatedIconW".}

+proc ExtractIconW*(para1: HINST, para2: LPCWSTR, para3: int): HICON{.stdcall,

+    dynlib: "shell32", importc: "ExtractIconW".}

+proc FindExecutableW*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR): HINST{.

+    stdcall, dynlib: "shell32", importc: "FindExecutableW".}

+proc ShellAboutW*(para1: HWND, para2: LPCWSTR, para3: LPCWSTR, para4: HICON): int32{.

+    stdcall, dynlib: "shell32", importc: "ShellAboutW".}

+proc ShellExecuteW*(para1: HWND, para2: LPCWSTR, para3: LPCWSTR, para4: LPCWSTR,

+                    para5: LPCWSTR, para6: int32): HINST{.stdcall,

+    dynlib: "shell32", importc: "ShellExecuteW".}

+proc Shell_NotifyIconW*(dwMessage: DWORD, lpData: PNotifyIconDataA): WINBOOL{.

+    stdcall, dynlib: "shell32", importc: "Shell_NotifyIconW".}

+proc DdeCreateStringHandleW*(para1: DWORD, para2: LPCWSTR, para3: int32): HSZ{.

+    stdcall, dynlib: "user32", importc: "DdeCreateStringHandleW".}

+proc DdeInitializeW*(para1: LPDWORD, para2: PFNCALLBACK, para3: DWORD,

+                     para4: DWORD): WINUINT{.stdcall, dynlib: "user32",

+    importc: "DdeInitializeW".}

+proc DdeQueryStringW*(para1: DWORD, para2: HSZ, para3: LPCWSTR, para4: DWORD,

+                      para5: int32): DWORD{.stdcall, dynlib: "user32",

+    importc: "DdeQueryStringW".}

+proc LogonUserW*(para1: LPWSTR, para2: LPWSTR, para3: LPWSTR, para4: DWORD,

+                 para5: DWORD, para6: PHANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LogonUserW".}

+proc CreateProcessAsUserW*(para1: HANDLE, para2: LPCWSTR, para3: LPWSTR,

+                           para4: LPSECURITY_ATTRIBUTES,

+                           para5: LPSECURITY_ATTRIBUTES, para6: WINBOOL,

+                           para7: DWORD, para8: LPVOID, para9: LPCWSTR,

+                           para10: LPSTARTUPINFO, para11: LPPROCESS_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "CreateProcessAsUserW".}

+when defined(winUnicode):

+  proc GetBinaryType*(lpApplicationName: LPCWSTR, lpBinaryType: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "GetBinaryTypeW".}

+  proc GetShortPathName*(lpszLongPath: LPCWSTR, lpszShortPath: LPWSTR,

+                         cchBuffer: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "GetShortPathNameW".}

+  proc GetEnvironmentStrings*(): LPWSTR{.stdcall, dynlib: "kernel32",

+      importc: "GetEnvironmentStringsW".}

+  proc FreeEnvironmentStrings*(para1: LPWSTR): WINBOOL{.stdcall,

+

+      dynlib: "kernel32", importc: "FreeEnvironmentStringsW".}

+  proc FormatMessage*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD,

+                      dwLanguageId: DWORD, lpBuffer: LPWSTR, nSize: DWORD,

+                      Arguments: va_list): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "FormatMessageW".}

+  proc CreateMailslot*(lpName: LPCWSTR, nMaxMessageSize: DWORD,

+                       lReadTimeout: DWORD,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateMailslotW".}

+  proc lstrcmp*(lpString1: LPCWSTR, lpString2: LPCWSTR): int32{.stdcall,

+      dynlib: "kernel32", importc: "lstrcmpW".}

+  proc lstrcmpi*(lpString1: LPCWSTR, lpString2: LPCWSTR): int32{.stdcall,

+      dynlib: "kernel32", importc: "lstrcmpiW".}

+  proc lstrcpyn*(lpString1: LPWSTR, lpString2: LPCWSTR, iMaxLength: int32): LPWSTR{.

+      stdcall, dynlib: "kernel32", importc: "lstrcpynW".}

+  proc lstrcpy*(lpString1: LPWSTR, lpString2: LPCWSTR): LPWSTR{.stdcall,

+      dynlib: "kernel32", importc: "lstrcpyW".}

+  proc lstrcat*(lpString1: LPWSTR, lpString2: LPCWSTR): LPWSTR{.stdcall,

+      dynlib: "kernel32", importc: "lstrcatW".}

+  proc lstrlen*(lpString: LPCWSTR): int32{.stdcall, dynlib: "kernel32",

+      importc: "lstrlenW".}

+  proc CreateMutex*(lpMutexAttributes: LPSECURITY_ATTRIBUTES,

+                    bInitialOwner: WINBOOL, lpName: LPCWSTR): HANDLE{.stdcall,

+      dynlib: "kernel32", importc: "CreateMutexW".}

+  proc OpenMutex*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                  lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenMutexW".}

+  proc CreateEvent*(lpEventAttributes: LPSECURITY_ATTRIBUTES,

+                    bManualReset: WINBOOL, bInitialState: WINBOOL,

+                    lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "CreateEventW".}

+  proc OpenEvent*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                  lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenEventW".}

+  proc CreateSemaphore*(lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES,

+                        lInitialCount: LONG, lMaximumCount: LONG,

+                        lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "CreateSemaphoreW".}

+  proc OpenSemaphore*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                      lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenSemaphoreW".}

+  proc CreateFileMapping*(hFile: HANDLE,

+                          lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,

+                          flProtect: DWORD, dwMaximumSizeHigh: DWORD,

+                          dwMaximumSizeLow: DWORD, lpName: LPCWSTR): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}

+  proc OpenFileMapping*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                        lpName: LPCWSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenFileMappingW".}

+  proc GetLogicalDriveStrings*(nBufferLength: DWORD, lpBuffer: LPWSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetLogicalDriveStringsW".}

+  proc LoadLibrary*(lpLibFileName: LPCWSTR): HINST{.stdcall, dynlib: "kernel32",

+      importc: "LoadLibraryW".}

+  proc LoadLibraryEx*(lpLibFileName: LPCWSTR, hFile: HANDLE, dwFlags: DWORD): HINST{.

+      stdcall, dynlib: "kernel32", importc: "LoadLibraryExW".}

+  proc GetModuleFileName*(hModule: HINST, lpFilename: LPWSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetModuleFileNameW".}

+  proc GetModuleHandle*(lpModuleName: LPCWSTR): HMODULE{.stdcall,

+      dynlib: "kernel32", importc: "GetModuleHandleW".}

+  proc FatalAppExit*(uAction: WINUINT, lpMessageText: LPCWSTR){.stdcall,

+      dynlib: "kernel32", importc: "FatalAppExitW".}

+  proc GetCommandLine*(): LPWSTR{.stdcall, dynlib: "kernel32",

+                                  importc: "GetCommandLineW".}

+  proc GetEnvironmentVariable*(lpName: LPCWSTR, lpBuffer: LPWSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetEnvironmentVariableW".}

+  proc SetEnvironmentVariable*(lpName: LPCWSTR, lpValue: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}

+  proc ExpandEnvironmentStrings*(lpSrc: LPCWSTR, lpDst: LPWSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "ExpandEnvironmentStringsW".}

+  proc OutputDebugString*(lpOutputString: LPCWSTR){.stdcall, dynlib: "kernel32",

+      importc: "OutputDebugStringW".}

+  proc FindResource*(hModule: HINST, lpName: LPCWSTR, lpType: LPCWSTR): HRSRC{.

+      stdcall, dynlib: "kernel32", importc: "FindResourceW".}

+  proc FindResourceEx*(hModule: HINST, lpType: LPCWSTR, lpName: LPCWSTR,

+                       wLanguage: int16): HRSRC{.stdcall, dynlib: "kernel32",

+      importc: "FindResourceExW".}

+  proc EnumResourceTypes*(hModule: HINST, lpEnumFunc: ENUMRESTYPEPROC,

+                          lParam: LONG): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "EnumResourceTypesW".}

+  proc EnumResourceNames*(hModule: HINST, lpType: LPCWSTR,

+                          lpEnumFunc: ENUMRESNAMEPROC, lParam: LONG): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "EnumResourceNamesW".}

+  proc EnumResourceLanguages*(hModule: HINST, lpType: LPCWSTR, lpName: LPCWSTR,

+                              lpEnumFunc: ENUMRESLANGPROC, lParam: LONG): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "EnumResourceLanguagesW".}

+  proc BeginUpdateResource*(pFileName: LPCWSTR,

+                            bDeleteExistingResources: WINBOOL): HANDLE{.stdcall,

+      dynlib: "kernel32", importc: "BeginUpdateResourceW".}

+  proc UpdateResource*(hUpdate: HANDLE, lpType: LPCWSTR, lpName: LPCWSTR,

+                       wLanguage: int16, lpData: LPVOID, cbData: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "UpdateResourceW".}

+  proc EndUpdateResource*(hUpdate: HANDLE, fDiscard: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "EndUpdateResourceW".}

+  proc GlobalAddAtom*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "GlobalAddAtomW".}

+  proc GlobalFindAtom*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "GlobalFindAtomW".}

+  proc GlobalGetAtomName*(nAtom: ATOM, lpBuffer: LPWSTR, nSize: int32): WINUINT{.

+      stdcall, dynlib: "kernel32", importc: "GlobalGetAtomNameW".}

+  proc AddAtom*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "AddAtomW".}

+  proc FindAtom*(lpString: LPCWSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "FindAtomW".}

+  proc GetAtomName*(nAtom: ATOM, lpBuffer: LPWSTR, nSize: int32): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetAtomNameW".}

+  proc GetProfileInt*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR, nDefault: WINT): WINUINT{.

+      stdcall, dynlib: "kernel32", importc: "GetProfileIntW".}

+  proc GetProfileString*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                         lpDefault: LPCWSTR, lpReturnedString: LPWSTR,

+                         nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "GetProfileStringW".}

+  proc WriteProfileString*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                           lpString: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "WriteProfileStringW".}

+  proc GetProfileSection*(lpAppName: LPCWSTR, lpReturnedString: LPWSTR,

+                          nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "GetProfileSectionW".}

+  proc WriteProfileSection*(lpAppName: LPCWSTR, lpString: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteProfileSectionW".}

+  proc GetPrivateProfileInt*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                             nDefault: WINT, lpFileName: LPCWSTR): WINUINT{.

+      stdcall, dynlib: "kernel32", importc: "GetPrivateProfileIntW".}

+  proc GetPrivateProfileString*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                                lpDefault: LPCWSTR, lpReturnedString: LPWSTR,

+                                nSize: DWORD, lpFileName: LPCWSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStringW".}

+  proc WritePrivateProfileString*(lpAppName: LPCWSTR, lpKeyName: LPCWSTR,

+                                  lpString: LPCWSTR, lpFileName: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStringW".}

+  proc GetPrivateProfileSection*(lpAppName: LPCWSTR, lpReturnedString: LPWSTR,

+                                 nSize: DWORD, lpFileName: LPCWSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetPrivateProfileSectionW".}

+  proc WritePrivateProfileSection*(lpAppName: LPCWSTR, lpString: LPCWSTR,

+                                   lpFileName: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "WritePrivateProfileSectionW".}

+  proc GetDriveType*(lpRootPathName: LPCWSTR): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetDriveTypeW".}

+  proc GetSystemDirectory*(lpBuffer: LPWSTR, uSize: WINUINT): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetSystemDirectoryW".}

+  proc GetTempPath*(nBufferLength: DWORD, lpBuffer: LPWSTR): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetTempPathW".}

+  proc GetTempFileName*(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR,

+                        uUnique: WINUINT, lpTempFileName: LPWSTR): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetTempFileNameW".}

+  proc GetWindowsDirectory*(lpBuffer: LPWSTR, uSize: WINUINT): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetWindowsDirectoryW".}

+  proc SetCurrentDirectory*(lpPathName: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetCurrentDirectoryW".}

+  proc GetCurrentDirectory*(nBufferLength: DWORD, lpBuffer: LPWSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetCurrentDirectoryW".}

+  proc GetDiskFreeSpace*(lpRootPathName: LPCWSTR, lpSectorsPerCluster: LPDWORD,

+                         lpBytesPerSector: LPDWORD,

+                         lpNumberOfFreeClusters: LPDWORD,

+                         lpTotalNumberOfClusters: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetDiskFreeSpaceW".}

+  proc CreateDirectory*(lpPathName: LPCWSTR,

+                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CreateDirectoryW".}

+  proc CreateDirectoryEx*(lpTemplateDirectory: LPCWSTR, lpNewDirectory: LPCWSTR,

+                          lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CreateDirectoryExW".}

+  proc RemoveDirectory*(lpPathName: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "RemoveDirectoryW".}

+  proc GetFullPathName*(lpFileName: LPCWSTR, nBufferLength: DWORD,

+                        lpBuffer: LPWSTR, lpFilePart: var LPWSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetFullPathNameW".}

+  proc DefineDosDevice*(dwFlags: DWORD, lpDeviceName: LPCWSTR,

+                        lpTargetPath: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "DefineDosDeviceW".}

+  proc QueryDosDevice*(lpDeviceName: LPCWSTR, lpTargetPath: LPWSTR,

+                       ucchMax: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "QueryDosDeviceW".}

+  proc CreateFile*(lpFileName: LPCWSTR, dwDesiredAccess: DWORD,

+                   dwShareMode: DWORD,

+                   lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                   dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD,

+                   hTemplateFile: HANDLE): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "CreateFileW".}

+  proc SetFileAttributes*(lpFileName: LPCWSTR, dwFileAttributes: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}

+  proc GetFileAttributes*(lpFileName: LPCWSTR): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetFileAttributesW".}

+  proc GetCompressedFileSize*(lpFileName: LPCWSTR, lpFileSizeHigh: LPDWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetCompressedFileSizeW".}

+  proc DeleteFile*(lpFileName: LPCWSTR): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "DeleteFileW".}

+  proc SearchPath*(lpPath: LPCWSTR, lpFileName: LPCWSTR, lpExtension: LPCWSTR,

+                   nBufferLength: DWORD, lpBuffer: LPWSTR, lpFilePart: LPWSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "SearchPathW".}

+  proc CopyFile*(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR,

+                 bFailIfExists: WINBOOL): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "CopyFileW".}

+  proc MoveFile*(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "MoveFileW".}

+  proc MoveFileEx*(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR,

+                   dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "MoveFileExW".}

+  proc CreateNamedPipe*(lpName: LPCWSTR, dwOpenMode: DWORD, dwPipeMode: DWORD,

+                        nMaxInstances: DWORD, nOutBufferSize: DWORD,

+                        nInBufferSize: DWORD, nDefaultTimeOut: DWORD,

+                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateNamedPipeW".}

+  proc GetNamedPipeHandleState*(hNamedPipe: HANDLE, lpState: LPDWORD,

+                                lpCurInstances: LPDWORD,

+                                lpMaxCollectionCount: LPDWORD,

+                                lpCollectDataTimeout: LPDWORD,

+                                lpUserName: LPWSTR, nMaxUserNameSize: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "GetNamedPipeHandleStateW".}

+  proc CallNamedPipe*(lpNamedPipeName: LPCWSTR, lpInBuffer: LPVOID,

+                      nInBufferSize: DWORD, lpOutBuffer: LPVOID,

+                      nOutBufferSize: DWORD, lpBytesRead: LPDWORD,

+                      nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "CallNamedPipeW".}

+  proc WaitNamedPipe*(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WaitNamedPipeW".}

+  proc SetVolumeLabel*(lpRootPathName: LPCWSTR, lpVolumeName: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetVolumeLabelW".}

+  proc GetVolumeInformation*(lpRootPathName: LPCWSTR,

+                             lpVolumeNameBuffer: LPWSTR, nVolumeNameSize: DWORD,

+                             lpVolumeSerialNumber: LPDWORD,

+                             lpMaximumComponentLength: LPDWORD,

+                             lpFileSystemFlags: LPDWORD,

+                             lpFileSystemNameBuffer: LPWSTR,

+                             nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetVolumeInformationW".}

+  proc ClearEventLog*(hEventLog: HANDLE, lpBackupFileName: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "ClearEventLogW".}

+  proc BackupEventLog*(hEventLog: HANDLE, lpBackupFileName: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "BackupEventLogW".}

+  proc OpenEventLog*(lpUNCServerName: LPCWSTR, lpSourceName: LPCWSTR): HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "OpenEventLogW".}

+  proc RegisterEventSource*(lpUNCServerName: LPCWSTR, lpSourceName: LPCWSTR): HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "RegisterEventSourceW".}

+  proc OpenBackupEventLog*(lpUNCServerName: LPCWSTR, lpFileName: LPCWSTR): HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "OpenBackupEventLogW".}

+  proc ReadEventLog*(hEventLog: HANDLE, dwReadFlags: DWORD,

+                     dwRecordOffset: DWORD, lpBuffer: LPVOID,

+                     nNumberOfBytesToRead: DWORD, pnBytesRead: LPDWORD,

+                     pnMinNumberOfBytesNeeded: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ReadEventLogW".}

+  proc ReportEvent*(hEventLog: HANDLE, wType: int16, wCategory: int16,

+                    dwEventID: DWORD, lpUserSid: PSID, wNumStrings: int16,

+                    dwDataSize: DWORD, lpStrings: LPPCWSTR, lpRawData: LPVOID): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "ReportEventW".}

+  proc AccessCheckAndAuditAlarm*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                                 ObjectTypeName: LPWSTR, ObjectName: LPWSTR,

+                                 SecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 DesiredAccess: DWORD,

+                                 GenericMapping: PGENERIC_MAPPING,

+                                 ObjectCreation: WINBOOL,

+                                 GrantedAccess: LPDWORD, AccessStatus: LPBOOL,

+                                 pfGenerateOnClose: LPBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "AccessCheckAndAuditAlarmW".}

+  proc ObjectOpenAuditAlarm*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                             ObjectTypeName: LPWSTR, ObjectName: LPWSTR,

+                             pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                             ClientToken: HANDLE, DesiredAccess: DWORD,

+                             GrantedAccess: DWORD, Privileges: PPRIVILEGE_SET,

+                             ObjectCreation: WINBOOL, AccessGranted: WINBOOL,

+                             GenerateOnClose: LPBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ObjectOpenAuditAlarmW".}

+  proc ObjectPrivilegeAuditAlarm*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                                  ClientToken: HANDLE, DesiredAccess: DWORD,

+                                  Privileges: PPRIVILEGE_SET,

+                                  AccessGranted: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmW".}

+  proc ObjectCloseAuditAlarm*(SubsystemName: LPCWSTR, HandleId: LPVOID,

+                              GenerateOnClose: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ObjectCloseAuditAlarmW".}

+  proc PrivilegedServiceAuditAlarm*(SubsystemName: LPCWSTR,

+                                    ServiceName: LPCWSTR, ClientToken: HANDLE,

+                                    Privileges: PPRIVILEGE_SET,

+                                    AccessGranted: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmW".}

+  proc SetFileSecurity*(lpFileName: LPCWSTR,

+                        SecurityInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "SetFileSecurityW".}

+  proc GetFileSecurity*(lpFileName: LPCWSTR,

+                        RequestedInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                        nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "GetFileSecurityW".}

+  proc FindFirstChangeNotification*(lpPathName: LPCWSTR, bWatchSubtree: WINBOOL,

+                                    dwNotifyFilter: DWORD): HANDLE{.stdcall,

+      dynlib: "kernel32", importc: "FindFirstChangeNotificationW".}

+  proc IsBadStringPtr*(lpsz: LPCWSTR, ucchMax: WINUINT): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "IsBadStringPtrW".}

+  proc LookupAccountSid*(lpSystemName: LPCWSTR, Sid: PSID, Name: LPWSTR,

+                         cbName: LPDWORD, ReferencedDomainName: LPWSTR,

+                         cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "LookupAccountSidW".}

+  proc LookupAccountName*(lpSystemName: LPCWSTR, lpAccountName: LPCWSTR,

+                          Sid: PSID, cbSid: LPDWORD,

+                          ReferencedDomainName: LPWSTR,

+                          cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "LookupAccountNameW".}

+  proc LookupPrivilegeValue*(lpSystemName: LPCWSTR, lpName: LPCWSTR,

+                             lpLuid: PLUID): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "LookupPrivilegeValueW".}

+  proc LookupPrivilegeName*(lpSystemName: LPCWSTR, lpLuid: PLUID,

+                            lpName: LPWSTR, cbName: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "LookupPrivilegeNameW".}

+  proc LookupPrivilegeDisplayName*(lpSystemName: LPCWSTR, lpName: LPCWSTR,

+                                   lpDisplayName: LPWSTR,

+                                   cbDisplayName: LPDWORD, lpLanguageId: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameW".}

+  proc BuildCommDCB*(lpDef: LPCWSTR, lpDCB: LPDCB): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "BuildCommDCBW".}

+  proc BuildCommDCBAndTimeouts*(lpDef: LPCWSTR, lpDCB: LPDCB,

+                                lpCommTimeouts: LPCOMMTIMEOUTS): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsW".}

+  proc CommConfigDialog*(lpszName: LPCWSTR, wnd: HWND, lpCC: LPCOMMCONFIG): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CommConfigDialogW".}

+  proc GetDefaultCommConfig*(lpszName: LPCWSTR, lpCC: LPCOMMCONFIG,

+                             lpdwSize: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetDefaultCommConfigW".}

+  proc SetDefaultCommConfig*(lpszName: LPCWSTR, lpCC: LPCOMMCONFIG,

+                             dwSize: DWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetDefaultCommConfigW".}

+  proc GetComputerName*(lpBuffer: LPWSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetComputerNameW".}

+  proc SetComputerName*(lpComputerName: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetComputerNameW".}

+  proc GetUserName*(lpBuffer: LPWSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "GetUserNameW".}

+  proc LoadKeyboardLayout*(pwszKLID: LPCWSTR, Flags: WINUINT): HKL{.stdcall,

+      dynlib: "user32", importc: "LoadKeyboardLayoutW".}

+  proc GetKeyboardLayoutName*(pwszKLID: LPWSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GetKeyboardLayoutNameW".}

+  proc CreateDesktop*(lpszDesktop: LPWSTR, lpszDevice: LPWSTR,

+                      pDevmode: LPDEVMODE, dwFlags: DWORD,

+                      dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HDESK{.

+      stdcall, dynlib: "user32", importc: "CreateDesktopW".}

+  proc OpenDesktop*(lpszDesktop: LPWSTR, dwFlags: DWORD, fInherit: WINBOOL,

+                    dwDesiredAccess: DWORD): HDESK{.stdcall, dynlib: "user32",

+      importc: "OpenDesktopW".}

+  proc EnumDesktops*(hwinsta: HWINSTA, lpEnumFunc: DESKTOPENUMPROC,

+                     lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "EnumDesktopsW".}

+  proc CreateWindowStation*(lpwinsta: LPWSTR, dwReserved: DWORD,

+                            dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HWINSTA{.

+      stdcall, dynlib: "user32", importc: "CreateWindowStationW".}

+  proc OpenWindowStation*(lpszWinSta: LPWSTR, fInherit: WINBOOL,

+                          dwDesiredAccess: DWORD): HWINSTA{.stdcall,

+      dynlib: "user32", importc: "OpenWindowStationW".}

+  proc EnumWindowStations*(lpEnumFunc: ENUMWINDOWSTATIONPROC, lp: LPARAM): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "EnumWindowStationsW".}

+  proc GetUserObjectInformation*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                 nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "GetUserObjectInformationW".}

+  proc SetUserObjectInformation*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                 nLength: DWORD): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetUserObjectInformationW".}

+  proc RegisterWindowMessage*(lpString: LPCWSTR): WINUINT{.stdcall,

+      dynlib: "user32", importc: "RegisterWindowMessageW".}

+  proc GetMessage*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                   wMsgFilterMax: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "GetMessageW".}

+  proc DispatchMessage*(lpMsg: LPMSG): LONG{.stdcall, dynlib: "user32",

+      importc: "DispatchMessageW".}

+  proc PeekMessage*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                    wMsgFilterMax: WINUINT, wRemoveMsg: WINUINT): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "PeekMessageW".}

+  proc SendMessage*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "SendMessageW".}

+  proc SendMessageTimeout*(wnd: HWND, Msg: WINUINT, wp: WPARAM,

+                           lp: LPARAM, fuFlags: WINUINT, uTimeout: WINUINT,

+                           lpdwResult: LPDWORD): LRESULT{.stdcall,

+      dynlib: "user32", importc: "SendMessageTimeoutW".}

+  proc SendNotifyMessage*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "SendNotifyMessageW".}

+  proc SendMessageCallback*(wnd: HWND, Msg: WINUINT, wp: WPARAM,

+                            lp: LPARAM, lpResultCallBack: SENDASYNCPROC,

+                            dwData: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "SendMessageCallbackW".}

+  proc PostMessage*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "PostMessageW".}

+  proc PostThreadMessage*(idThread: DWORD, Msg: WINUINT, wp: WPARAM,

+                          lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "PostThreadMessageW".}

+  proc DefWindowProc*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "DefWindowProcW".}

+  proc CallWindowProc*(lpPrevWndFunc: WNDPROC, wnd: HWND, Msg: WINUINT,

+                       wp: WPARAM, lp: LPARAM): LRESULT{.stdcall,

+      dynlib: "user32", importc: "CallWindowProcW".}

+  proc RegisterClass*(lpWndClass: LPWNDCLASS): ATOM{.stdcall, dynlib: "user32",

+      importc: "RegisterClassW".}

+  proc UnregisterClass*(lpClassName: LPCWSTR, hInstance: HINST): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "UnregisterClassW".}

+  proc GetClassInfo*(hInstance: HINST, lpClassName: LPCWSTR,

+                     lpWndClass: LPWNDCLASS): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GetClassInfoW".}

+  proc RegisterClassEx*(para1: LPWNDCLASSEXW): ATOM{.stdcall, dynlib: "user32",

+      importc: "RegisterClassExW".}

+  proc GetClassInfoEx*(para1: HINST, para2: LPCWSTR, para3: LPWNDCLASSEX): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "GetClassInfoExW".}

+  proc CreateWindowEx*(dwExStyle: DWORD, lpClassName: LPCWSTR,

+                       lpWindowName: LPCWSTR, dwStyle: DWORD, X: int32,

+                       Y: int32, nWidth: int32, nHeight: int32,

+                       hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                       lpParam: LPVOID): HWND{.stdcall, dynlib: "user32",

+      importc: "CreateWindowExW".}

+  proc CreateDialogParam*(hInstance: HINST, lpTemplateName: LPCWSTR,

+                          hWndParent: HWND, lpDialogFunc: DLGPROC,

+                          dwInitParam: LPARAM): HWND{.stdcall, dynlib: "user32",

+      importc: "CreateDialogParamW".}

+  proc CreateDialogIndirectParam*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                                  hWndParent: HWND, lpDialogFunc: DLGPROC,

+                                  dwInitParam: LPARAM): HWND{.stdcall,

+      dynlib: "user32", importc: "CreateDialogIndirectParamW".}

+  proc DialogBoxParam*(hInstance: HINST, lpTemplateName: LPCWSTR,

+                       hWndParent: HWND, lpDialogFunc: DLGPROC,

+                       dwInitParam: LPARAM): int32{.stdcall, dynlib: "user32",

+      importc: "DialogBoxParamW".}

+  proc DialogBoxIndirectParam*(hInstance: HINST,

+                               hDialogTemplate: LPCDLGTEMPLATE,

+                               hWndParent: HWND, lpDialogFunc: DLGPROC,

+                               dwInitParam: LPARAM): int32{.stdcall,

+      dynlib: "user32", importc: "DialogBoxIndirectParamW".}

+  proc SetDlgItemText*(hDlg: HWND, nIDDlgItem: int32, lpString: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "SetDlgItemTextW".}

+  proc GetDlgItemText*(hDlg: HWND, nIDDlgItem: int32, lpString: LPWSTR,

+                       nMaxCount: int32): WINUINT{.stdcall, dynlib: "user32",

+      importc: "GetDlgItemTextW".}

+  proc SendDlgItemMessage*(hDlg: HWND, nIDDlgItem: int32, Msg: WINUINT,

+                           wp: WPARAM, lp: LPARAM): LONG{.stdcall,

+      dynlib: "user32", importc: "SendDlgItemMessageW".}

+  proc DefDlgProc*(hDlg: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "DefDlgProcW".}

+  proc CallMsgFilter*(lpMsg: LPMSG, nCode: int32): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "CallMsgFilterW".}

+  proc RegisterClipboardFormat*(lpszFormat: LPCWSTR): WINUINT{.stdcall,

+      dynlib: "user32", importc: "RegisterClipboardFormatW".}

+  proc GetClipboardFormatName*(format: WINUINT, lpszFormatName: LPWSTR,

+                               cchMaxCount: int32): int32{.stdcall,

+      dynlib: "user32", importc: "GetClipboardFormatNameW".}

+  proc CharToOem*(lpszSrc: LPCWSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "CharToOemW".}

+  proc OemToChar*(lpszSrc: LPCSTR, lpszDst: LPWSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "OemToCharW".}

+  proc CharToOemBuff*(lpszSrc: LPCWSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "CharToOemBuffW".}

+  proc OemToCharBuff*(lpszSrc: LPCSTR, lpszDst: LPWSTR, cchDstLength: DWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "OemToCharBuffW".}

+  proc CharUpper*(lpsz: LPWSTR): LPWSTR{.stdcall, dynlib: "user32",

+      importc: "CharUpperW".}

+  proc CharUpperBuff*(lpsz: LPWSTR, cchLength: DWORD): DWORD{.stdcall,

+      dynlib: "user32", importc: "CharUpperBuffW".}

+  proc CharLower*(lpsz: LPWSTR): LPWSTR{.stdcall, dynlib: "user32",

+      importc: "CharLowerW".}

+  proc CharLowerBuff*(lpsz: LPWSTR, cchLength: DWORD): DWORD{.stdcall,

+      dynlib: "user32", importc: "CharLowerBuffW".}

+  proc CharNext*(lpsz: LPCWSTR): LPWSTR{.stdcall, dynlib: "user32",

+      importc: "CharNextW".}

+  proc CharPrev*(lpszStart: LPCWSTR, lpszCurrent: LPCWSTR): LPWSTR{.stdcall,

+      dynlib: "user32", importc: "CharPrevW".}

+  proc IsCharAlpha*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "IsCharAlphaW".}

+  proc IsCharAlphaNumeric*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "IsCharAlphaNumericW".}

+  proc IsCharUpper*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "IsCharUpperW".}

+  proc IsCharLower*(ch: WCHAR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "IsCharLowerW".}

+  proc GetKeyNameText*(lParam: LONG, lpString: LPWSTR, nSize: int32): int32{.

+      stdcall, dynlib: "user32", importc: "GetKeyNameTextW".}

+  proc VkKeyScan*(ch: WCHAR): SHORT{.stdcall, dynlib: "user32",

+                                     importc: "VkKeyScanW".}

+  proc VkKeyScanEx*(ch: WCHAR, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32",

+      importc: "VkKeyScanExW".}

+  proc MapVirtualKey*(uCode: WINUINT, uMapType: WINUINT): WINUINT{.stdcall,

+      dynlib: "user32", importc: "MapVirtualKeyW".}

+  proc MapVirtualKeyEx*(uCode: WINUINT, uMapType: WINUINT, dwhkl: HKL): WINUINT{.stdcall,

+      dynlib: "user32", importc: "MapVirtualKeyExW".}

+  proc LoadAccelerators*(hInstance: HINST, lpTableName: LPCWSTR): HACCEL{.

+      stdcall, dynlib: "user32", importc: "LoadAcceleratorsW".}

+  proc CreateAcceleratorTable*(para1: LPACCEL, para2: int32): HACCEL{.stdcall,

+      dynlib: "user32", importc: "CreateAcceleratorTableW".}

+  proc CopyAcceleratorTable*(hAccelSrc: HACCEL, lpAccelDst: LPACCEL,

+                             cAccelEntries: int32): int32{.stdcall,

+      dynlib: "user32", importc: "CopyAcceleratorTableW".}

+  proc TranslateAccelerator*(wnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG): int32{.

+      stdcall, dynlib: "user32", importc: "TranslateAcceleratorW".}

+  proc LoadMenu*(hInstance: HINST, lpMenuName: LPCWSTR): HMENU{.stdcall,

+      dynlib: "user32", importc: "LoadMenuW".}

+  proc LoadMenuIndirect*(lpMenuTemplate: LPMENUTEMPLATE): HMENU{.stdcall,

+      dynlib: "user32", importc: "LoadMenuIndirectW".}

+  proc ChangeMenu*(menu: HMENU, cmd: WINUINT, lpszNewItem: LPCWSTR,

+                   cmdInsert: WINUINT, flags: WINUINT): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "ChangeMenuW".}

+  proc GetMenuString*(menu: HMENU, uIDItem: WINUINT, lpString: LPWSTR,

+                      nMaxCount: int32, uFlag: WINUINT): int32{.stdcall,

+      dynlib: "user32", importc: "GetMenuStringW".}

+  proc InsertMenu*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT,

+                   uIDNewItem: WINUINT, lpNewItem: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "InsertMenuW".}

+  proc AppendMenu*(menu: HMENU, uFlags: WINUINT, uIDNewItem: WINUINT,

+                   lpNewItem: LPCWSTR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "AppendMenuW".}

+  proc ModifyMenu*(hMnu: HMENU, uPosition: WINUINT, uFlags: WINUINT, uIDNewItem: WINUINT,

+                   lpNewItem: LPCWSTR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "ModifyMenuW".}

+  proc InsertMenuItem*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                       para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "InsertMenuItemW".}

+  proc GetMenuItemInfo*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                        para4: LPMENUITEMINFO): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GetMenuItemInfoW".}

+  proc SetMenuItemInfo*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                        para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetMenuItemInfoW".}

+  proc DrawText*(hDC: HDC, lpString: LPCWSTR, nCount: int32, lpRect: LPRECT,

+                 uFormat: WINUINT): int32{.stdcall, dynlib: "user32",

+                                        importc: "DrawTextW".}

+  proc DrawTextEx*(para1: HDC, para2: LPWSTR, para3: int32, para4: LPRECT,

+                   para5: WINUINT, para6: LPDRAWTEXTPARAMS): int32{.stdcall,

+      dynlib: "user32", importc: "DrawTextExW".}

+  proc GrayString*(hDC: HDC, hBrush: HBRUSH, lpOutputFunc: GRAYSTRINGPROC,

+                   lpData: LPARAM, nCount: int32, X: int32, Y: int32,

+                   nWidth: int32, nHeight: int32): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GrayStringW".}

+  proc DrawState*(para1: HDC, para2: HBRUSH, para3: DRAWSTATEPROC,

+                  para4: LPARAM, para5: WPARAM, para6: int32, para7: int32,

+                  para8: int32, para9: int32, para10: WINUINT): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "DrawStateW".}

+  proc TabbedTextOut*(hDC: HDC, X: int32, Y: int32, lpString: LPCWSTR,

+                      nCount: int32, nTabPositions: int32,

+                      lpnTabStopPositions: LPINT, nTabOrigin: int32): LONG{.

+      stdcall, dynlib: "user32", importc: "TabbedTextOutW".}

+  proc GetTabbedTextExtent*(hDC: HDC, lpString: LPCWSTR, nCount: int32,

+                            nTabPositions: int32, lpnTabStopPositions: LPINT): DWORD{.

+      stdcall, dynlib: "user32", importc: "GetTabbedTextExtentW".}

+  proc SetProp*(wnd: HWND, lpString: LPCWSTR, hData: HANDLE): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetPropW".}

+  proc GetProp*(wnd: HWND, lpString: LPCWSTR): HANDLE{.stdcall,

+      dynlib: "user32", importc: "GetPropW".}

+  proc RemoveProp*(wnd: HWND, lpString: LPCWSTR): HANDLE{.stdcall,

+      dynlib: "user32", importc: "RemovePropW".}

+  proc EnumPropsEx*(wnd: HWND, lpEnumFunc: PROPENUMPROCEX, lp: LPARAM): int32{.

+      stdcall, dynlib: "user32", importc: "EnumPropsExW".}

+  proc EnumProps*(wnd: HWND, lpEnumFunc: PROPENUMPROC): int32{.stdcall,

+      dynlib: "user32", importc: "EnumPropsW".}

+  proc SetWindowText*(wnd: HWND, lpString: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetWindowTextW".}

+  proc GetWindowText*(wnd: HWND, lpString: LPWSTR, nMaxCount: int32): int32{.

+      stdcall, dynlib: "user32", importc: "GetWindowTextW".}

+  proc GetWindowTextLength*(wnd: HWND): int32{.stdcall, dynlib: "user32",

+      importc: "GetWindowTextLengthW".}

+  proc MessageBox*(wnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR, uType: WINUINT): int32{.

+      stdcall, dynlib: "user32", importc: "MessageBoxW".}

+  proc MessageBoxEx*(wnd: HWND, lpText: LPCWSTR, lpCaption: LPCWSTR,

+                     uType: WINUINT, wLanguageId: int16): int32{.stdcall,

+      dynlib: "user32", importc: "MessageBoxExW".}

+  proc MessageBoxIndirect*(para1: LPMSGBOXPARAMS): int32{.stdcall,

+      dynlib: "user32", importc: "MessageBoxIndirectW".}

+  proc GetWindowLong*(wnd: HWND, nIndex: int32): LONG{.stdcall,

+      dynlib: "user32", importc: "GetWindowLongW".}

+  proc SetWindowLong*(wnd: HWND, nIndex: int32, dwNewLong: LONG): LONG{.

+      stdcall, dynlib: "user32", importc: "SetWindowLongW".}

+  proc GetClassLong*(wnd: HWND, nIndex: int32): DWORD{.stdcall,

+      dynlib: "user32", importc: "GetClassLongW".}

+  proc SetClassLong*(wnd: HWND, nIndex: int32, dwNewLong: LONG): DWORD{.

+      stdcall, dynlib: "user32", importc: "SetClassLongW".}

+  when defined(cpu64):

+    proc GetWindowLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetWindowLongPtrW".}

+    proc SetWindowLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetWindowLongPtrW".}

+    proc GetClassLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetClassLongPtrW".}

+    proc SetClassLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetClassLongPtrW".}

+  else:

+    proc GetWindowLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetWindowLongW".}

+    proc SetWindowLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetWindowLongW".}

+    proc GetClassLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetClassLongW".}

+    proc SetClassLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetClassLongW".}

+  proc FindWindow*(lpClassName: LPCWSTR, lpWindowName: LPCWSTR): HWND{.stdcall,

+      dynlib: "user32", importc: "FindWindowW".}

+  proc FindWindowEx*(para1: HWND, para2: HWND, para3: LPCWSTR, para4: LPCWSTR): HWND{.

+      stdcall, dynlib: "user32", importc: "FindWindowExW".}

+  proc GetClassName*(wnd: HWND, lpClassName: LPWSTR, nMaxCount: int32): int32{.

+      stdcall, dynlib: "user32", importc: "GetClassNameW".}

+  proc SetWindowsHookEx*(idHook: int32, lpfn: HOOKPROC, hmod: HINST,

+                         dwThreadId: DWORD): HHOOK{.stdcall, dynlib: "user32",

+      importc: "SetWindowsHookExW".}

+  proc LoadBitmap*(hInstance: HINST, lpBitmapName: LPCWSTR): HBITMAP{.stdcall,

+      dynlib: "user32", importc: "LoadBitmapW".}

+  proc LoadCursor*(hInstance: HINST, lpCursorName: LPCWSTR): HCURSOR{.stdcall,

+      dynlib: "user32", importc: "LoadCursorW".}

+  proc LoadCursorFromFile*(lpFileName: LPCWSTR): HCURSOR{.stdcall,

+      dynlib: "user32", importc: "LoadCursorFromFileW".}

+  proc LoadIcon*(hInstance: HINST, lpIconName: LPCWSTR): HICON{.stdcall,

+      dynlib: "user32", importc: "LoadIconW".}

+  proc LoadImage*(para1: HINST, para2: LPCWSTR, para3: WINUINT, para4: int32,

+                  para5: int32, para6: WINUINT): HANDLE{.stdcall, dynlib: "user32",

+      importc: "LoadImageW".}

+  proc LoadString*(hInstance: HINST, uID: WINUINT, lpBuffer: LPWSTR,

+                   nBufferMax: int32): int32{.stdcall, dynlib: "user32",

+      importc: "LoadStringW".}

+  proc IsDialogMessage*(hDlg: HWND, lpMsg: LPMSG): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "IsDialogMessageW".}

+  proc DlgDirList*(hDlg: HWND, lpPathSpec: LPWSTR, nIDListBox: int32,

+                   nIDStaticPath: int32, uFileType: WINUINT): int32{.stdcall,

+      dynlib: "user32", importc: "DlgDirListW".}

+  proc DlgDirSelectEx*(hDlg: HWND, lpString: LPWSTR, nCount: int32,

+                       nIDListBox: int32): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "DlgDirSelectExW".}

+  proc DlgDirListComboBox*(hDlg: HWND, lpPathSpec: LPWSTR, nIDComboBox: int32,

+                           nIDStaticPath: int32, uFiletype: WINUINT): int32{.

+      stdcall, dynlib: "user32", importc: "DlgDirListComboBoxW".}

+  proc DlgDirSelectComboBoxEx*(hDlg: HWND, lpString: LPWSTR, nCount: int32,

+                               nIDComboBox: int32): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "DlgDirSelectComboBoxExW".}

+  proc DefFrameProc*(wnd: HWND, hWndMDIClient: HWND, uMsg: WINUINT,

+                     wp: WPARAM, lp: LPARAM): LRESULT{.stdcall,

+      dynlib: "user32", importc: "DefFrameProcW".}

+  proc DefMDIChildProc*(wnd: HWND, uMsg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "DefMDIChildProcW".}

+  proc CreateMDIWindow*(lpClassName: LPWSTR, lpWindowName: LPWSTR,

+                        dwStyle: DWORD, X: int32, Y: int32, nWidth: int32,

+                        nHeight: int32, hWndParent: HWND, hInstance: HINST,

+                        lp: LPARAM): HWND{.stdcall, dynlib: "user32",

+      importc: "CreateMDIWindowW".}

+  proc WinHelp*(hWndMain: HWND, lpszHelp: LPCWSTR, uCommand: WINUINT, dwData: DWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "WinHelpW".}

+  proc ChangeDisplaySettings*(lpDevMode: LPDEVMODE, dwFlags: DWORD): LONG{.

+      stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsW".}

+  proc EnumDisplaySettings*(lpszDeviceName: LPCWSTR, iModeNum: DWORD,

+                            lpDevMode: LPDEVMODEW): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "EnumDisplaySettingsW".}

+  proc SystemParametersInfo*(uiAction: WINUINT, uiParam: WINUINT, pvParam: PVOID,

+                             fWinIni: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "SystemParametersInfoW".}

+  proc AddFontResource*(para1: LPCWSTR): int32{.stdcall, dynlib: "gdi32",

+      importc: "AddFontResourceW".}

+  proc CopyMetaFile*(para1: HMETAFILE, para2: LPCWSTR): HMETAFILE{.stdcall,

+      dynlib: "gdi32", importc: "CopyMetaFileW".}

+  proc CreateFontIndirect*(para1: PLOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+      importc: "CreateFontIndirectW".}

+  proc CreateFontIndirect*(para1: var LOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+      importc: "CreateFontIndirectW".}

+  proc CreateFont*(para1: int32, para2: int32, para3: int32, para4: int32,

+                   para5: int32, para6: DWORD, para7: DWORD, para8: DWORD,

+                   para9: DWORD, para10: DWORD, para11: DWORD, para12: DWORD,

+                   para13: DWORD, para14: LPCWSTR): HFONT{.stdcall,

+      dynlib: "gdi32", importc: "CreateFontW".}

+  proc CreateIC*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR,

+                 para4: LPDEVMODE): HDC{.stdcall, dynlib: "gdi32",

+      importc: "CreateICW".}

+  proc CreateMetaFile*(para1: LPCWSTR): HDC{.stdcall, dynlib: "gdi32",

+      importc: "CreateMetaFileW".}

+  proc CreateScalableFontResource*(para1: DWORD, para2: LPCWSTR, para3: LPCWSTR,

+                                   para4: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "CreateScalableFontResourceW".}

+  proc EnumFontFamiliesEx*(para1: HDC, para2: LPLOGFONT, para3: FONTENUMEXPROC,

+                           para4: LPARAM, para5: DWORD): int32{.stdcall,

+      dynlib: "gdi32", importc: "EnumFontFamiliesExW".}

+  proc EnumFontFamilies*(para1: HDC, para2: LPCWSTR, para3: FONTENUMPROC,

+                         para4: LPARAM): int32{.stdcall, dynlib: "gdi32",

+      importc: "EnumFontFamiliesW".}

+  proc EnumFonts*(para1: HDC, para2: LPCWSTR, para3: ENUMFONTSPROC,

+                  para4: LPARAM): int32{.stdcall, dynlib: "gdi32",

+      importc: "EnumFontsW".}

+  proc EnumFonts*(para1: HDC, para2: LPCWSTR, para3: ENUMFONTSPROC,

+                  para4: pointer): int32{.stdcall, dynlib: "gdi32",

+      importc: "EnumFontsW".}

+  proc GetCharWidth*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharWidthW".}

+  proc GetCharWidth32*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharWidth32W".}

+  proc GetCharWidthFloat*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: ptr float32): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatW".}

+  proc GetCharABCWidths*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPABC): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsW".}

+  proc GetCharABCWidthsFloat*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                              para4: LPABCFLOAT): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "GetCharABCWidthsFloatW".}

+  proc GetGlyphOutline*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                        para4: LPGLYPHMETRICS, para5: DWORD, para6: LPVOID,

+                        para7: PMAT2): DWORD{.stdcall, dynlib: "gdi32",

+      importc: "GetGlyphOutlineW".}

+  proc GetMetaFile*(para1: LPCWSTR): HMETAFILE{.stdcall, dynlib: "gdi32",

+      importc: "GetMetaFileW".}

+  proc GetOutlineTextMetrics*(para1: HDC, para2: WINUINT,

+                              para3: LPOUTLINETEXTMETRIC): WINUINT{.stdcall,

+      dynlib: "gdi32", importc: "GetOutlineTextMetricsW".}

+  proc GetTextExtentPoint*(para1: HDC, para2: LPCWSTR, para3: int32,

+                           para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetTextExtentPointW".}

+  proc GetTextExtentPoint32*(para1: HDC, para2: LPCWSTR, para3: int32,

+                             para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetTextExtentPoint32W".}

+  proc GetTextExtentExPoint*(para1: HDC, para2: LPCWSTR, para3: int32,

+                             para4: int32, para5: LPINT, para6: LPINT,

+                             para7: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetTextExtentExPointW".}

+  proc GetCharacterPlacement*(para1: HDC, para2: LPCWSTR, para3: int32,

+                              para4: int32, para5: LPGCP_RESULTS, para6: DWORD): DWORD{.

+      stdcall, dynlib: "gdi32", importc: "GetCharacterPlacementW".}

+  proc ResetDC*(para1: HDC, para2: LPDEVMODE): HDC{.stdcall, dynlib: "gdi32",

+      importc: "ResetDCW".}

+  proc RemoveFontResource*(para1: LPCWSTR): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "RemoveFontResourceW".}

+  proc CopyEnhMetaFile*(para1: HENHMETAFILE, para2: LPCWSTR): HENHMETAFILE{.

+      stdcall, dynlib: "gdi32", importc: "CopyEnhMetaFileW".}

+  proc CreateEnhMetaFile*(para1: HDC, para2: LPCWSTR, para3: LPRECT,

+                          para4: LPCWSTR): HDC{.stdcall, dynlib: "gdi32",

+      importc: "CreateEnhMetaFileW".}

+  proc GetEnhMetaFile*(para1: LPCWSTR): HENHMETAFILE{.stdcall, dynlib: "gdi32",

+      importc: "GetEnhMetaFileW".}

+  proc GetEnhMetaFileDescription*(para1: HENHMETAFILE, para2: WINUINT,

+                                  para3: LPWSTR): WINUINT{.stdcall,

+      dynlib: "gdi32", importc: "GetEnhMetaFileDescriptionW".}

+  proc GetTextMetrics*(para1: HDC, para2: LPTEXTMETRIC): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "GetTextMetricsW".}

+  proc StartDoc*(para1: HDC, para2: PDOCINFO): int32{.stdcall, dynlib: "gdi32",

+      importc: "StartDocW".}

+  proc GetObject*(para1: HGDIOBJ, para2: int32, para3: LPVOID): int32{.stdcall,

+      dynlib: "gdi32", importc: "GetObjectW".}

+  proc TextOut*(para1: HDC, para2: int32, para3: int32, para4: LPCWSTR,

+                para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+                                        importc: "TextOutW".}

+  proc ExtTextOut*(para1: HDC, para2: int32, para3: int32, para4: WINUINT,

+                   para5: LPRECT, para6: LPCWSTR, para7: WINUINT, para8: LPINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "ExtTextOutW".}

+  proc PolyTextOut*(para1: HDC, para2: PPOLYTEXT, para3: int32): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "PolyTextOutW".}

+  proc GetTextFace*(para1: HDC, para2: int32, para3: LPWSTR): int32{.stdcall,

+      dynlib: "gdi32", importc: "GetTextFaceW".}

+  proc GetKerningPairs*(para1: HDC, para2: DWORD, para3: LPKERNINGPAIR): DWORD{.

+      stdcall, dynlib: "gdi32", importc: "GetKerningPairsW".}

+  proc GetLogColorSpace*(para1: HCOLORSPACE, para2: LPLOGCOLORSPACE,

+                         para3: DWORD): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetLogColorSpaceW".}

+  proc CreateColorSpace*(para1: LPLOGCOLORSPACE): HCOLORSPACE{.stdcall,

+      dynlib: "gdi32", importc: "CreateColorSpaceW".}

+  proc GetICMProfile*(para1: HDC, para2: DWORD, para3: LPWSTR): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetICMProfileW".}

+  proc SetICMProfile*(para1: HDC, para2: LPWSTR): WINBOOL{.stdcall,

+

+      dynlib: "gdi32", importc: "SetICMProfileW".}

+  proc UpdateICMRegKey*(para1: DWORD, para2: DWORD, para3: LPWSTR, para4: WINUINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "UpdateICMRegKeyW".}

+  proc EnumICMProfiles*(para1: HDC, para2: ICMENUMPROC, para3: LPARAM): int32{.

+      stdcall, dynlib: "gdi32", importc: "EnumICMProfilesW".}

+  proc CreatePropertySheetPage*(lppsp: LPCPROPSHEETPAGE): HPROPSHEETPAGE{.

+      stdcall, dynlib: "comctl32", importc: "CreatePropertySheetPageW".}

+  proc PropertySheet*(lppsph: LPCPROPSHEETHEADER): int32{.stdcall,

+      dynlib: "comctl32", importc: "PropertySheetW".}

+  proc ImageList_LoadImage*(hi: HINST, lpbmp: LPCWSTR, cx: int32, cGrow: int32,

+                            crMask: COLORREF, uType: WINUINT, uFlags: WINUINT): HIMAGELIST{.

+      stdcall, dynlib: "comctl32", importc: "ImageList_LoadImageW".}

+  proc CreateStatusWindow*(style: LONG, lpszText: LPCWSTR, hwndParent: HWND,

+                           wID: WINUINT): HWND{.stdcall, dynlib: "comctl32",

+      importc: "CreateStatusWindowW".}

+  proc DrawStatusText*(hDC: HDC, lprc: LPRECT, pszText: LPCWSTR, uFlags: WINUINT){.

+      stdcall, dynlib: "comctl32", importc: "DrawStatusTextW".}

+  proc GetOpenFileName*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+      dynlib: "comdlg32", importc: "GetOpenFileNameW".}

+  proc GetSaveFileName*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+      dynlib: "comdlg32", importc: "GetSaveFileNameW".}

+  proc GetFileTitle*(para1: LPCWSTR, para2: LPWSTR, para3: int16): int{.stdcall,

+      dynlib: "comdlg32", importc: "GetFileTitleW".}

+  proc ChooseColor*(para1: LPCHOOSECOLOR): WINBOOL{.stdcall, dynlib: "comdlg32",

+      importc: "ChooseColorW".}

+  proc ReplaceText*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+      importc: "ReplaceTextW".}

+  proc ChooseFont*(para1: LPCHOOSEFONT): WINBOOL{.stdcall, dynlib: "comdlg32",

+      importc: "ChooseFontW".}

+  proc FindText*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+      importc: "FindTextW".}

+  proc PrintDlg*(para1: LPPRINTDLG): WINBOOL{.stdcall, dynlib: "comdlg32",

+      importc: "PrintDlgW".}

+  proc PageSetupDlg*(para1: LPPAGESETUPDLG): WINBOOL{.stdcall,

+      dynlib: "comdlg32", importc: "PageSetupDlgW".}

+  proc CreateProcess*(lpApplicationName: LPCWSTR, lpCommandLine: LPWSTR,

+                      lpProcessAttributes: LPSECURITY_ATTRIBUTES,

+                      lpThreadAttributes: LPSECURITY_ATTRIBUTES,

+                      bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                      lpEnvironment: LPVOID, lpCurrentDirectory: LPCWSTR,

+                      lpStartupInfo: LPSTARTUPINFO,

+                      lpProcessInformation: LPPROCESS_INFORMATION): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CreateProcessW".}

+  proc GetStartupInfo*(lpStartupInfo: LPSTARTUPINFO){.stdcall,

+      dynlib: "kernel32", importc: "GetStartupInfoW".}

+  proc FindFirstFile*(lpFileName: LPCWSTR, lpFindFileData: LPWIN32_FIND_DATA): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}

+  proc FindNextFile*(hFindFile: HANDLE, lpFindFileData: LPWIN32_FIND_DATA): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "FindNextFileW".}

+  proc GetVersionEx*(VersionInformation: LPOSVERSIONINFOW): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetVersionExW".}

+  proc GetVersionExW*(VersionInformation: LPOSVERSIONINFOW): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetVersionExW".}

+  proc CreateWindow*(lpClassName: LPCWSTR, lpWindowName: LPCWSTR,

+                     dwStyle: DWORD, X: int32, Y: int32, nWidth: int32,

+                     nHeight: int32, hWndParent: HWND, menu: HMENU,

+                     hInstance: HINST, lpParam: LPVOID): HWND

+  proc CreateDialog*(hInstance: HINST, lpName: LPCWSTR, hWndParent: HWND,

+                     lpDialogFunc: DLGPROC): HWND

+  proc CreateDialogIndirect*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                             hWndParent: HWND, lpDialogFunc: DLGPROC): HWND

+  proc DialogBox*(hInstance: HINST, lpTemplate: LPCWSTR, hWndParent: HWND,

+                  lpDialogFunc: DLGPROC): int32

+  proc DialogBoxIndirect*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                          hWndParent: HWND, lpDialogFunc: DLGPROC): int32

+  proc CreateDC*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR, para4: PDEVMODE): HDC{.

+      stdcall, dynlib: "gdi32", importc: "CreateDCW".}

+  proc VerInstallFile*(uFlags: DWORD, szSrcFileName: LPWSTR,

+                       szDestFileName: LPWSTR, szSrcDir: LPWSTR,

+                       szDestDir: LPWSTR, szCurDir: LPWSTR, szTmpFile: LPWSTR,

+                       lpuTmpFileLen: PUINT): DWORD{.stdcall, dynlib: "version",

+      importc: "VerInstallFileW".}

+  proc GetFileVersionInfoSize*(lptstrFilename: LPWSTR, lpdwHandle: LPDWORD): DWORD{.

+      stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeW".}

+  proc GetFileVersionInfo*(lptstrFilename: LPWSTR, dwHandle: DWORD,

+                           dwLen: DWORD, lpData: LPVOID): WINBOOL{.stdcall,

+      dynlib: "version", importc: "GetFileVersionInfoW".}

+  proc VerLanguageName*(wLang: DWORD, szLang: LPWSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "VerLanguageNameW".}

+  proc VerQueryValue*(pBlock: LPVOID, lpSubBlock: LPWSTR, lplpBuffer: LPVOID,

+                      puLen: PUINT): WINBOOL{.stdcall, dynlib: "version",

+      importc: "VerQueryValueW".}

+  proc VerFindFile*(uFlags: DWORD, szFileName: LPWSTR, szWinDir: LPWSTR,

+                    szAppDir: LPWSTR, szCurDir: LPWSTR, lpuCurDirLen: PUINT,

+                    szDestDir: LPWSTR, lpuDestDirLen: PUINT): DWORD{.stdcall,

+      dynlib: "version", importc: "VerFindFileW".}

+  proc RegSetValueEx*(key: HKEY, lpValueName: LPCWSTR, Reserved: DWORD,

+                      dwType: DWORD, lpData: LPBYTE, cbData: DWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegSetValueExW".}

+  proc RegUnLoadKey*(key: HKEY, lpSubKey: LPCWSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegUnLoadKeyW".}

+  proc InitiateSystemShutdown*(lpMachineName: LPWSTR, lpMessage: LPWSTR,

+                               dwTimeout: DWORD, bForceAppsClosed: WINBOOL,

+                               bRebootAfterShutdown: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "InitiateSystemShutdownW".}

+  proc AbortSystemShutdown*(lpMachineName: LPWSTR): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "AbortSystemShutdownW".}

+  proc RegRestoreKey*(key: HKEY, lpFile: LPCWSTR, dwFlags: DWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegRestoreKeyW".}

+  proc RegSaveKey*(key: HKEY, lpFile: LPCWSTR,

+                   lpSecurityAttributes: LPSECURITY_ATTRIBUTES): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegSaveKeyW".}

+  proc RegSetValue*(key: HKEY, lpSubKey: LPCWSTR, dwType: DWORD,

+                    lpData: LPCWSTR, cbData: DWORD): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegSetValueW".}

+  proc RegQueryValue*(key: HKEY, lpSubKey: LPCWSTR, lpValue: LPWSTR,

+                      lpcbValue: PLONG): LONG{.stdcall, dynlib: "advapi32",

+      importc: "RegQueryValueW".}

+  proc RegQueryMultipleValues*(key: HKEY, val_list: PVALENT, num_vals: DWORD,

+                               lpValueBuf: LPWSTR, ldwTotsize: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesW".}

+  proc RegQueryValueEx*(key: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,

+                        lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegQueryValueExW".}

+  proc RegReplaceKey*(key: HKEY, lpSubKey: LPCWSTR, lpNewFile: LPCWSTR,

+                      lpOldFile: LPCWSTR): LONG{.stdcall, dynlib: "advapi32",

+      importc: "RegReplaceKeyW".}

+  proc RegConnectRegistry*(lpMachineName: LPWSTR, key: HKEY, phkResult: PHKEY): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegConnectRegistryW".}

+  proc RegCreateKey*(key: HKEY, lpSubKey: LPCWSTR, phkResult: PHKEY): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegCreateKeyW".}

+  proc RegCreateKeyEx*(key: HKEY, lpSubKey: LPCWSTR, Reserved: DWORD,

+                       lpClass: LPWSTR, dwOptions: DWORD, samDesired: REGSAM,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                       phkResult: PHKEY, lpdwDisposition: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegCreateKeyExW".}

+  proc RegDeleteKey*(key: HKEY, lpSubKey: LPCWSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegDeleteKeyW".}

+  proc RegDeleteValue*(key: HKEY, lpValueName: LPCWSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegDeleteValueW".}

+  proc RegEnumKey*(key: HKEY, dwIndex: DWORD, lpName: LPWSTR, cbName: DWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegEnumKeyW".}

+  proc RegEnumKeyEx*(key: HKEY, dwIndex: DWORD, lpName: LPWSTR,

+                     lpcbName: LPDWORD, lpReserved: LPDWORD, lpClass: LPWSTR,

+                     lpcbClass: LPDWORD, lpftLastWriteTime: PFILETIME): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegEnumKeyExW".}

+  proc RegEnumValue*(key: HKEY, dwIndex: DWORD, lpValueName: LPWSTR,

+                     lpcbValueName: LPDWORD, lpReserved: LPDWORD,

+                     lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegEnumValueW".}

+  proc RegLoadKey*(key: HKEY, lpSubKey: LPCWSTR, lpFile: LPCWSTR): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegLoadKeyW".}

+  proc RegOpenKey*(key: HKEY, lpSubKey: LPCWSTR, phkResult: PHKEY): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegOpenKeyW".}

+  proc RegOpenKeyEx*(key: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD,

+                     samDesired: REGSAM, phkResult: PHKEY): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegOpenKeyExW".}

+  proc RegQueryInfoKey*(key: HKEY, lpClass: LPWSTR, lpcbClass: LPDWORD,

+                        lpReserved: LPDWORD, lpcSubKeys: LPDWORD,

+                        lpcbMaxSubKeyLen: LPDWORD, lpcbMaxClassLen: LPDWORD,

+                        lpcValues: LPDWORD, lpcbMaxValueNameLen: LPDWORD,

+                        lpcbMaxValueLen: LPDWORD,

+                        lpcbSecurityDescriptor: LPDWORD,

+                        lpftLastWriteTime: PFILETIME): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegQueryInfoKeyW".}

+  proc CompareString*(Locale: LCID, dwCmpFlags: DWORD, lpString1: LPCWSTR,

+                      cchCount1: int32, lpString2: LPCWSTR, cchCount2: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "CompareStringW".}

+  proc LCMapString*(Locale: LCID, dwMapFlags: DWORD, lpSrcStr: LPCWSTR,

+                    cchSrc: int32, lpDestStr: LPWSTR, cchDest: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "LCMapStringW".}

+  proc GetLocaleInfo*(Locale: LCID, LCType: LCTYPE, lpLCData: LPWSTR,

+                      cchData: int32): int32{.stdcall, dynlib: "kernel32",

+      importc: "GetLocaleInfoW".}

+  proc SetLocaleInfo*(Locale: LCID, LCType: LCTYPE, lpLCData: LPCWSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetLocaleInfoW".}

+  proc GetTimeFormat*(Locale: LCID, dwFlags: DWORD, lpTime: LPSYSTEMTIME,

+                      lpFormat: LPCWSTR, lpTimeStr: LPWSTR, cchTime: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "GetTimeFormatW".}

+  proc GetDateFormat*(Locale: LCID, dwFlags: DWORD, lpDate: LPSYSTEMTIME,

+                      lpFormat: LPCWSTR, lpDateStr: LPWSTR, cchDate: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "GetDateFormatW".}

+  proc GetNumberFormat*(Locale: LCID, dwFlags: DWORD, lpValue: LPCWSTR,

+                        lpFormat: PNUMBERFMT, lpNumberStr: LPWSTR,

+                        cchNumber: int32): int32{.stdcall, dynlib: "kernel32",

+      importc: "GetNumberFormatW".}

+  proc GetCurrencyFormat*(Locale: LCID, dwFlags: DWORD, lpValue: LPCWSTR,

+                          lpFormat: PCURRENCYFMT, lpCurrencyStr: LPWSTR,

+                          cchCurrency: int32): int32{.stdcall,

+      dynlib: "kernel32", importc: "GetCurrencyFormatW".}

+  proc EnumCalendarInfo*(lpCalInfoEnumProc: CALINFO_ENUMPROC, Locale: LCID,

+                         Calendar: CALID, CalType: CALTYPE): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "EnumCalendarInfoW".}

+  proc EnumTimeFormats*(lpTimeFmtEnumProc: TIMEFMT_ENUMPROC, Locale: LCID,

+                        dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "EnumTimeFormatsW".}

+  proc EnumDateFormats*(lpDateFmtEnumProc: DATEFMT_ENUMPROC, Locale: LCID,

+                        dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "EnumDateFormatsW".}

+  proc GetStringTypeEx*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCWSTR,

+                        cchSrc: int32, lpCharType: LPWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetStringTypeExW".}

+  proc GetStringType*(dwInfoType: DWORD, lpSrcStr: LPCWSTR, cchSrc: int32,

+                      lpCharType: LPWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "GetStringTypeW".}

+  proc FoldString*(dwMapFlags: DWORD, lpSrcStr: LPCWSTR, cchSrc: int32,

+                   lpDestStr: LPWSTR, cchDest: int32): int32{.stdcall,

+      dynlib: "kernel32", importc: "FoldStringW".}

+  proc EnumSystemLocales*(lpLocaleEnumProc: LOCALE_ENUMPROC, dwFlags: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "EnumSystemLocalesW".}

+  proc EnumSystemCodePages*(lpCodePageEnumProc: CODEPAGE_ENUMPROC,

+                            dwFlags: DWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "EnumSystemCodePagesW".}

+  proc PeekConsoleInput*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                         nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "PeekConsoleInputW".}

+  proc ReadConsoleInput*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                         nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}

+  proc WriteConsoleInput*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                          nLength: DWORD, lpNumberOfEventsWritten: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteConsoleInputW".}

+  proc ReadConsoleOutput*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                          dwBufferSize: COORD, dwBufferCoord: COORD,

+                          lpReadRegion: PSMALL_RECT): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "ReadConsoleOutputW".}

+  proc WriteConsoleOutput*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                           dwBufferSize: COORD, dwBufferCoord: COORD,

+                           lpWriteRegion: PSMALL_RECT): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "WriteConsoleOutputW".}

+  proc ReadConsoleOutputCharacter*(hConsoleOutput: HANDLE, lpCharacter: LPWSTR,

+                                   nLength: DWORD, dwReadCoord: COORD,

+                                   lpNumberOfCharsRead: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterW".}

+  proc WriteConsoleOutputCharacter*(hConsoleOutput: HANDLE,

+                                    lpCharacter: LPCWSTR, nLength: DWORD,

+                                    dwWriteCoord: COORD,

+                                    lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterW".}

+  proc FillConsoleOutputCharacter*(hConsoleOutput: HANDLE, cCharacter: WCHAR,

+                                   nLength: DWORD, dwWriteCoord: COORD,

+                                   lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterW".}

+  proc ScrollConsoleScreenBuffer*(hConsoleOutput: HANDLE,

+                                  lpScrollRectangle: PSMALL_RECT,

+                                  lpClipRectangle: PSMALL_RECT,

+                                  dwDestinationOrigin: COORD, lpFill: PCHAR_INFO): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "ScrollConsoleScreenBufferW".}

+  proc GetConsoleTitle*(lpConsoleTitle: LPWSTR, nSize: DWORD): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetConsoleTitleW".}

+  proc SetConsoleTitle*(lpConsoleTitle: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetConsoleTitleW".}

+  proc ReadConsole*(hConsoleInput: HANDLE, lpBuffer: LPVOID,

+                    nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: LPDWORD,

+                    lpReserved: LPVOID): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "ReadConsoleW".}

+  proc WriteConsole*(hConsoleOutput: HANDLE, lpBuffer: pointer,

+                     nNumberOfCharsToWrite: DWORD,

+                     lpNumberOfCharsWritten: LPDWORD, lpReserved: LPVOID): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteConsoleW".}

+  proc WNetAddConnection*(lpRemoteName: LPCWSTR, lpPassword: LPCWSTR,

+                          lpLocalName: LPCWSTR): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetAddConnectionW".}

+  proc WNetAddConnection2*(lpNetResource: LPNETRESOURCE, lpPassword: LPCWSTR,

+                           lpUserName: LPCWSTR, dwFlags: DWORD): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetAddConnection2W".}

+  proc WNetAddConnection3*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                           lpPassword: LPCWSTR, lpUserName: LPCWSTR,

+                           dwFlags: DWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetAddConnection3W".}

+  proc WNetCancelConnection*(lpName: LPCWSTR, fForce: WINBOOL): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetCancelConnectionW".}

+  proc WNetCancelConnection2*(lpName: LPCWSTR, dwFlags: DWORD, fForce: WINBOOL): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetCancelConnection2W".}

+  proc WNetGetConnection*(lpLocalName: LPCWSTR, lpRemoteName: LPWSTR,

+                          lpnLength: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetGetConnectionW".}

+  proc WNetUseConnection*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                          lpUserID: LPCWSTR, lpPassword: LPCWSTR,

+                          dwFlags: DWORD, lpAccessName: LPWSTR,

+                          lpBufferSize: LPDWORD, lpResult: LPDWORD): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetUseConnectionW".}

+  proc WNetSetConnection*(lpName: LPCWSTR, dwProperties: DWORD, pvValues: LPVOID): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetSetConnectionW".}

+  proc WNetConnectionDialog1*(lpConnDlgStruct: LPCONNECTDLGSTRUCT): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetConnectionDialog1W".}

+  proc WNetDisconnectDialog1*(lpConnDlgStruct: LPDISCDLGSTRUCT): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetDisconnectDialog1W".}

+  proc WNetOpenEnum*(dwScope: DWORD, dwType: DWORD, dwUsage: DWORD,

+                     lpNetResource: LPNETRESOURCE, lphEnum: LPHANDLE): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetOpenEnumW".}

+  proc WNetEnumResource*(hEnum: HANDLE, lpcCount: LPDWORD, lpBuffer: LPVOID,

+                         lpBufferSize: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetEnumResourceW".}

+  proc WNetGetUniversalName*(lpLocalPath: LPCWSTR, dwInfoLevel: DWORD,

+                             lpBuffer: LPVOID, lpBufferSize: LPDWORD): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameW".}

+  proc WNetGetUser*(lpName: LPCWSTR, lpUserName: LPWSTR, lpnLength: LPDWORD): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetGetUserW".}

+  proc WNetGetProviderName*(dwNetType: DWORD, lpProviderName: LPWSTR,

+                            lpBufferSize: LPDWORD): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetGetProviderNameW".}

+  proc WNetGetNetworkInformation*(lpProvider: LPCWSTR,

+                                  lpNetInfoStruct: LPNETINFOSTRUCT): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationW".}

+  proc WNetGetLastError*(lpError: LPDWORD, lpErrorBuf: LPWSTR,

+                         nErrorBufSize: DWORD, lpNameBuf: LPWSTR,

+                         nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetGetLastErrorW".}

+  proc MultinetGetConnectionPerformance*(lpNetResource: LPNETRESOURCE,

+      lpNetConnectInfoStruct: LPNETCONNECTINFOSTRUCT): DWORD{.stdcall,

+      dynlib: "mpr", importc: "MultinetGetConnectionPerformanceW".}

+  proc ChangeServiceConfig*(hService: SC_HANDLE, dwServiceType: DWORD,

+                            dwStartType: DWORD, dwErrorControl: DWORD,

+                            lpBinaryPathName: LPCWSTR,

+                            lpLoadOrderGroup: LPCWSTR, lpdwTagId: LPDWORD,

+                            lpDependencies: LPCWSTR,

+                            lpServiceStartName: LPCWSTR, lpPassword: LPCWSTR,

+                            lpDisplayName: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ChangeServiceConfigW".}

+  proc CreateService*(hSCManager: SC_HANDLE, lpServiceName: LPCWSTR,

+                      lpDisplayName: LPCWSTR, dwDesiredAccess: DWORD,

+                      dwServiceType: DWORD, dwStartType: DWORD,

+                      dwErrorControl: DWORD, lpBinaryPathName: LPCWSTR,

+                      lpLoadOrderGroup: LPCWSTR, lpdwTagId: LPDWORD,

+                      lpDependencies: LPCWSTR, lpServiceStartName: LPCWSTR,

+                      lpPassword: LPCWSTR): SC_HANDLE{.stdcall,

+      dynlib: "advapi32", importc: "CreateServiceW".}

+  proc EnumDependentServices*(hService: SC_HANDLE, dwServiceState: DWORD,

+                              lpServices: LPENUM_SERVICE_STATUS,

+                              cbBufSize: DWORD, pcbBytesNeeded: LPDWORD,

+                              lpServicesReturned: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "EnumDependentServicesW".}

+  proc EnumServicesStatus*(hSCManager: SC_HANDLE, dwServiceType: DWORD,

+                           dwServiceState: DWORD,

+                           lpServices: LPENUM_SERVICE_STATUS, cbBufSize: DWORD,

+                           pcbBytesNeeded: LPDWORD, lpServicesReturned: LPDWORD,

+                           lpResumeHandle: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "EnumServicesStatusW".}

+  proc GetServiceKeyName*(hSCManager: SC_HANDLE, lpDisplayName: LPCWSTR,

+                          lpServiceName: LPWSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "GetServiceKeyNameW".}

+  proc GetServiceDisplayName*(hSCManager: SC_HANDLE, lpServiceName: LPCWSTR,

+                              lpDisplayName: LPWSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "GetServiceDisplayNameW".}

+  proc OpenSCManager*(lpMachineName: LPCWSTR, lpDatabaseName: LPCWSTR,

+                      dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+      dynlib: "advapi32", importc: "OpenSCManagerW".}

+  proc OpenService*(hSCManager: SC_HANDLE, lpServiceName: LPCWSTR,

+                    dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+      dynlib: "advapi32", importc: "OpenServiceW".}

+  proc QueryServiceConfig*(hService: SC_HANDLE,

+                           lpServiceConfig: LPQUERY_SERVICE_CONFIG,

+                           cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "QueryServiceConfigW".}

+  proc QueryServiceLockStatus*(hSCManager: SC_HANDLE,

+                               lpLockStatus: LPQUERY_SERVICE_LOCK_STATUS,

+                               cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "QueryServiceLockStatusW".}

+  proc RegisterServiceCtrlHandler*(lpServiceName: LPCWSTR,

+                                   lpHandlerProc: LPHANDLER_FUNCTION): SERVICE_STATUS_HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "RegisterServiceCtrlHandlerW".}

+  proc StartServiceCtrlDispatcher*(lpServiceStartTable: LPSERVICE_TABLE_ENTRY): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "StartServiceCtrlDispatcherW".}

+  proc StartService*(hService: SC_HANDLE, dwNumServiceArgs: DWORD,

+                     lpServiceArgVectors: LPCWSTR): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "StartServiceW".}

+  proc DragQueryFile*(para1: HDROP, para2: int, para3: LPCWSTR, para4: int): int{.

+      stdcall, dynlib: "shell32", importc: "DragQueryFileW".}

+  proc ExtractAssociatedIcon*(para1: HINST, para2: LPCWSTR, para3: LPWORD): HICON{.

+      stdcall, dynlib: "shell32", importc: "ExtractAssociatedIconW".}

+  proc ExtractIcon*(para1: HINST, para2: LPCWSTR, para3: int): HICON{.stdcall,

+      dynlib: "shell32", importc: "ExtractIconW".}

+  proc FindExecutable*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR): HINST{.

+      stdcall, dynlib: "shell32", importc: "FindExecutableW".}

+  proc ShellAbout*(para1: HWND, para2: LPCWSTR, para3: LPCWSTR, para4: HICON): int32{.

+      stdcall, dynlib: "shell32", importc: "ShellAboutW".}

+  proc ShellExecute*(para1: HWND, para2: LPCWSTR, para3: LPCWSTR,

+                     para4: LPCWSTR, para5: LPCWSTR, para6: int32): HINST{.

+      stdcall, dynlib: "shell32", importc: "ShellExecuteW".}

+  proc Shell_NotifyIcon*(dwMessage: DWORD, lpData: PNotifyIconDataA): WINBOOL{.

+      stdcall, dynlib: "shell32", importc: "Shell_NotifyIconW".}

+  proc DdeCreateStringHandle*(para1: DWORD, para2: LPCWSTR, para3: int32): HSZ{.

+      stdcall, dynlib: "user32", importc: "DdeCreateStringHandleW".}

+  proc DdeInitialize*(para1: LPDWORD, para2: PFNCALLBACK, para3: DWORD,

+                      para4: DWORD): WINUINT{.stdcall, dynlib: "user32",

+      importc: "DdeInitializeW".}

+  proc DdeQueryString*(para1: DWORD, para2: HSZ, para3: LPCWSTR, para4: DWORD,

+                       para5: int32): DWORD{.stdcall, dynlib: "user32",

+      importc: "DdeQueryStringW".}

+  proc LogonUser*(para1: LPWSTR, para2: LPWSTR, para3: LPWSTR, para4: DWORD,

+                  para5: DWORD, para6: PHANDLE): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "LogonUserW".}

+  proc CreateProcessAsUser*(para1: HANDLE, para2: LPCWSTR, para3: LPWSTR,

+                            para4: LPSECURITY_ATTRIBUTES,

+                            para5: LPSECURITY_ATTRIBUTES, para6: WINBOOL,

+                            para7: DWORD, para8: LPVOID, para9: LPCWSTR,

+                            para10: LPSTARTUPINFO, para11: LPPROCESS_INFORMATION): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "CreateProcessAsUserW".}

+else:

+  proc GetBinaryType*(lpApplicationName: LPCSTR, lpBinaryType: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "GetBinaryTypeA".}

+  proc GetShortPathName*(lpszLongPath: LPCSTR, lpszShortPath: LPSTR,

+                         cchBuffer: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "GetShortPathNameA".}

+  proc GetEnvironmentStrings*(): LPSTR{.stdcall, dynlib: "kernel32",

+                                        importc: "GetEnvironmentStringsA".}

+  proc FreeEnvironmentStrings*(para1: LPSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "FreeEnvironmentStringsA".}

+  proc FormatMessage*(dwFlags: DWORD, lpSource: LPCVOID, dwMessageId: DWORD,

+                      dwLanguageId: DWORD, lpBuffer: LPSTR, nSize: DWORD,

+                      Arguments: va_list): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "FormatMessageA".}

+  proc CreateMailslot*(lpName: LPCSTR, nMaxMessageSize: DWORD,

+                       lReadTimeout: DWORD,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateMailslotA".}

+  proc lstrcmp*(lpString1: LPCSTR, lpString2: LPCSTR): int32{.stdcall,

+      dynlib: "kernel32", importc: "lstrcmpA".}

+  proc lstrcmpi*(lpString1: LPCSTR, lpString2: LPCSTR): int32{.stdcall,

+      dynlib: "kernel32", importc: "lstrcmpiA".}

+  proc lstrcpyn*(lpString1: LPSTR, lpString2: LPCSTR, iMaxLength: int32): LPSTR{.

+      stdcall, dynlib: "kernel32", importc: "lstrcpynA".}

+  proc lstrcpy*(lpString1: LPSTR, lpString2: LPCSTR): LPSTR{.stdcall,

+      dynlib: "kernel32", importc: "lstrcpyA".}

+  proc lstrcat*(lpString1: LPSTR, lpString2: LPCSTR): LPSTR{.stdcall,

+      dynlib: "kernel32", importc: "lstrcatA".}

+  proc lstrlen*(lpString: LPCSTR): int32{.stdcall, dynlib: "kernel32",

+      importc: "lstrlenA".}

+  proc CreateMutex*(lpMutexAttributes: LPSECURITY_ATTRIBUTES,

+                    bInitialOwner: WINBOOL, lpName: LPCSTR): HANDLE{.stdcall,

+      dynlib: "kernel32", importc: "CreateMutexA".}

+  proc OpenMutex*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                  lpName: LPCSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenMutexA".}

+  proc CreateEvent*(lpEventAttributes: LPSECURITY_ATTRIBUTES,

+                    bManualReset: WINBOOL, bInitialState: WINBOOL,

+                    lpName: LPCSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "CreateEventA".}

+  proc OpenEvent*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                  lpName: LPCSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenEventA".}

+  proc CreateSemaphore*(lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES,

+                        lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateSemaphoreA".}

+  proc OpenSemaphore*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                      lpName: LPCSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenSemaphoreA".}

+  proc CreateFileMapping*(hFile: HANDLE,

+                          lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,

+                          flProtect: DWORD, dwMaximumSizeHigh: DWORD,

+                          dwMaximumSizeLow: DWORD, lpName: LPCSTR): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".}

+  proc OpenFileMapping*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                        lpName: LPCSTR): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "OpenFileMappingA".}

+  proc GetLogicalDriveStrings*(nBufferLength: DWORD, lpBuffer: LPSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetLogicalDriveStringsA".}

+  proc LoadLibrary*(lpLibFileName: LPCSTR): HINST{.stdcall, dynlib: "kernel32",

+      importc: "LoadLibraryA".}

+  proc LoadLibraryEx*(lpLibFileName: LPCSTR, hFile: HANDLE, dwFlags: DWORD): HINST{.

+      stdcall, dynlib: "kernel32", importc: "LoadLibraryExA".}

+  proc GetModuleFileName*(hModule: HINST, lpFilename: LPSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetModuleFileNameA".}

+  proc GetModuleHandle*(lpModuleName: LPCSTR): HMODULE{.stdcall,

+      dynlib: "kernel32", importc: "GetModuleHandleA".}

+  proc FatalAppExit*(uAction: WINUINT, lpMessageText: LPCSTR){.stdcall,

+      dynlib: "kernel32", importc: "FatalAppExitA".}

+  proc GetCommandLine*(): LPSTR{.stdcall, dynlib: "kernel32",

+                                 importc: "GetCommandLineA".}

+  proc GetEnvironmentVariable*(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetEnvironmentVariableA".}

+  proc SetEnvironmentVariable*(lpName: LPCSTR, lpValue: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}

+  proc ExpandEnvironmentStrings*(lpSrc: LPCSTR, lpDst: LPSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "ExpandEnvironmentStringsA".}

+  proc OutputDebugString*(lpOutputString: LPCSTR){.stdcall, dynlib: "kernel32",

+      importc: "OutputDebugStringA".}

+  proc FindResource*(hModule: HINST, lpName: LPCSTR, lpType: LPCSTR): HRSRC{.

+      stdcall, dynlib: "kernel32", importc: "FindResourceA".}

+  proc FindResourceEx*(hModule: HINST, lpType: LPCSTR, lpName: LPCSTR,

+                       wLanguage: int16): HRSRC{.stdcall, dynlib: "kernel32",

+      importc: "FindResourceExA".}

+  proc EnumResourceTypes*(hModule: HINST, lpEnumFunc: ENUMRESTYPEPROC,

+                          lParam: LONG): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "EnumResourceTypesA".}

+  proc EnumResourceNames*(hModule: HINST, lpType: LPCSTR,

+                          lpEnumFunc: ENUMRESNAMEPROC, lParam: LONG): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "EnumResourceNamesA".}

+  proc EnumResourceLanguages*(hModule: HINST, lpType: LPCSTR, lpName: LPCSTR,

+                              lpEnumFunc: ENUMRESLANGPROC, lParam: LONG): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "EnumResourceLanguagesA".}

+  proc BeginUpdateResource*(pFileName: LPCSTR, bDeleteExistingResources: WINBOOL): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "BeginUpdateResourceA".}

+  proc UpdateResource*(hUpdate: HANDLE, lpType: LPCSTR, lpName: LPCSTR,

+                       wLanguage: int16, lpData: LPVOID, cbData: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "UpdateResourceA".}

+  proc EndUpdateResource*(hUpdate: HANDLE, fDiscard: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "EndUpdateResourceA".}

+  proc GlobalAddAtom*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "GlobalAddAtomA".}

+  proc GlobalFindAtom*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "GlobalFindAtomA".}

+  proc GlobalGetAtomName*(nAtom: ATOM, lpBuffer: LPSTR, nSize: int32): WINUINT{.

+      stdcall, dynlib: "kernel32", importc: "GlobalGetAtomNameA".}

+  proc AddAtom*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "AddAtomA".}

+  proc FindAtom*(lpString: LPCSTR): ATOM{.stdcall, dynlib: "kernel32",

+      importc: "FindAtomA".}

+  proc GetAtomName*(nAtom: ATOM, lpBuffer: LPSTR, nSize: int32): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetAtomNameA".}

+  proc GetProfileInt*(lpAppName: LPCSTR, lpKeyName: LPCSTR, nDefault: WINT): WINUINT{.

+      stdcall, dynlib: "kernel32", importc: "GetProfileIntA".}

+  proc GetProfileString*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                         lpDefault: LPCSTR, lpReturnedString: LPSTR,

+                         nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "GetProfileStringA".}

+  proc WriteProfileString*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                           lpString: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "WriteProfileStringA".}

+  proc GetProfileSection*(lpAppName: LPCSTR, lpReturnedString: LPSTR,

+                          nSize: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+      importc: "GetProfileSectionA".}

+  proc WriteProfileSection*(lpAppName: LPCSTR, lpString: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteProfileSectionA".}

+  proc GetPrivateProfileInt*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                             nDefault: WINT, lpFileName: LPCSTR): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetPrivateProfileIntA".}

+  proc GetPrivateProfileString*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                                lpDefault: LPCSTR, lpReturnedString: LPSTR,

+                                nSize: DWORD, lpFileName: LPCSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStringA".}

+  proc WritePrivateProfileString*(lpAppName: LPCSTR, lpKeyName: LPCSTR,

+                                  lpString: LPCSTR, lpFileName: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStringA".}

+  proc GetPrivateProfileSection*(lpAppName: LPCSTR, lpReturnedString: LPSTR,

+                                 nSize: DWORD, lpFileName: LPCSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetPrivateProfileSectionA".}

+  proc WritePrivateProfileSection*(lpAppName: LPCSTR, lpString: LPCSTR,

+                                   lpFileName: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "WritePrivateProfileSectionA".}

+  proc GetDriveType*(lpRootPathName: LPCSTR): WINUINT{.stdcall, dynlib: "kernel32",

+      importc: "GetDriveTypeA".}

+  proc GetSystemDirectory*(lpBuffer: LPSTR, uSize: WINUINT): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetSystemDirectoryA".}

+  proc GetTempPath*(nBufferLength: DWORD, lpBuffer: LPSTR): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetTempPathA".}

+  proc GetTempFileName*(lpPathName: LPCSTR, lpPrefixString: LPCSTR,

+                        uUnique: WINUINT, lpTempFileName: LPSTR): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetTempFileNameA".}

+  proc GetWindowsDirectory*(lpBuffer: LPSTR, uSize: WINUINT): WINUINT{.stdcall,

+      dynlib: "kernel32", importc: "GetWindowsDirectoryA".}

+  proc SetCurrentDirectory*(lpPathName: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetCurrentDirectoryA".}

+  proc GetCurrentDirectory*(nBufferLength: DWORD, lpBuffer: LPSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetCurrentDirectoryA".}

+  proc GetDiskFreeSpace*(lpRootPathName: LPCSTR, lpSectorsPerCluster: LPDWORD,

+                         lpBytesPerSector: LPDWORD,

+                         lpNumberOfFreeClusters: LPDWORD,

+                         lpTotalNumberOfClusters: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetDiskFreeSpaceA".}

+  proc CreateDirectory*(lpPathName: LPCSTR,

+                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CreateDirectoryA".}

+  proc CreateDirectoryEx*(lpTemplateDirectory: LPCSTR, lpNewDirectory: LPCSTR,

+                          lpSecurityAttributes: LPSECURITY_ATTRIBUTES): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CreateDirectoryExA".}

+  proc RemoveDirectory*(lpPathName: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "RemoveDirectoryA".}

+  proc GetFullPathName*(lpFileName: LPCSTR, nBufferLength: DWORD,

+                        lpBuffer: LPSTR, lpFilePart: var LPSTR): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetFullPathNameA".}

+  proc DefineDosDevice*(dwFlags: DWORD, lpDeviceName: LPCSTR,

+                        lpTargetPath: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "DefineDosDeviceA".}

+  proc QueryDosDevice*(lpDeviceName: LPCSTR, lpTargetPath: LPSTR, ucchMax: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "QueryDosDeviceA".}

+  proc CreateFile*(lpFileName: LPCSTR, dwDesiredAccess: DWORD,

+                   dwShareMode: DWORD,

+                   lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                   dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD,

+                   hTemplateFile: HANDLE): HANDLE{.stdcall, dynlib: "kernel32",

+      importc: "CreateFileA".}

+  proc SetFileAttributes*(lpFileName: LPCSTR, dwFileAttributes: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}

+  proc GetFileAttributes*(lpFileName: LPCSTR): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetFileAttributesA".}

+  proc GetCompressedFileSize*(lpFileName: LPCSTR, lpFileSizeHigh: LPDWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "GetCompressedFileSizeA".}

+  proc DeleteFile*(lpFileName: LPCSTR): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "DeleteFileA".}

+  proc SearchPath*(lpPath: LPCSTR, lpFileName: LPCSTR, lpExtension: LPCSTR,

+                   nBufferLength: DWORD, lpBuffer: LPSTR, lpFilePart: LPSTR): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "SearchPathA".}

+  proc CopyFile*(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,

+                 bFailIfExists: WINBOOL): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "CopyFileA".}

+  proc MoveFile*(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "MoveFileA".}

+  proc MoveFileEx*(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR,

+                   dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "MoveFileExA".}

+  proc CreateNamedPipe*(lpName: LPCSTR, dwOpenMode: DWORD, dwPipeMode: DWORD,

+                        nMaxInstances: DWORD, nOutBufferSize: DWORD,

+                        nInBufferSize: DWORD, nDefaultTimeOut: DWORD,

+                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "CreateNamedPipeA".}

+  proc GetNamedPipeHandleState*(hNamedPipe: HANDLE, lpState: LPDWORD,

+                                lpCurInstances: LPDWORD,

+                                lpMaxCollectionCount: LPDWORD,

+                                lpCollectDataTimeout: LPDWORD,

+                                lpUserName: LPSTR, nMaxUserNameSize: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "GetNamedPipeHandleStateA".}

+  proc CallNamedPipe*(lpNamedPipeName: LPCSTR, lpInBuffer: LPVOID,

+                      nInBufferSize: DWORD, lpOutBuffer: LPVOID,

+                      nOutBufferSize: DWORD, lpBytesRead: LPDWORD,

+                      nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "CallNamedPipeA".}

+  proc WaitNamedPipe*(lpNamedPipeName: LPCSTR, nTimeOut: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WaitNamedPipeA".}

+  proc SetVolumeLabel*(lpRootPathName: LPCSTR, lpVolumeName: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetVolumeLabelA".}

+  proc GetVolumeInformation*(lpRootPathName: LPCSTR, lpVolumeNameBuffer: LPSTR,

+                             nVolumeNameSize: DWORD,

+                             lpVolumeSerialNumber: LPDWORD,

+                             lpMaximumComponentLength: LPDWORD,

+                             lpFileSystemFlags: LPDWORD,

+                             lpFileSystemNameBuffer: LPSTR,

+                             nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetVolumeInformationA".}

+  proc ClearEventLog*(hEventLog: HANDLE, lpBackupFileName: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "ClearEventLogA".}

+  proc BackupEventLog*(hEventLog: HANDLE, lpBackupFileName: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "BackupEventLogA".}

+  proc OpenEventLog*(lpUNCServerName: LPCSTR, lpSourceName: LPCSTR): HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "OpenEventLogA".}

+  proc RegisterEventSource*(lpUNCServerName: LPCSTR, lpSourceName: LPCSTR): HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "RegisterEventSourceA".}

+  proc OpenBackupEventLog*(lpUNCServerName: LPCSTR, lpFileName: LPCSTR): HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "OpenBackupEventLogA".}

+  proc ReadEventLog*(hEventLog: HANDLE, dwReadFlags: DWORD,

+                     dwRecordOffset: DWORD, lpBuffer: LPVOID,

+                     nNumberOfBytesToRead: DWORD, pnBytesRead: LPDWORD,

+                     pnMinNumberOfBytesNeeded: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ReadEventLogA".}

+  proc ReportEvent*(hEventLog: HANDLE, wType: int16, wCategory: int16,

+                    dwEventID: DWORD, lpUserSid: PSID, wNumStrings: int16,

+                    dwDataSize: DWORD, lpStrings: LPPCSTR, lpRawData: LPVOID): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "ReportEventA".}

+  proc AccessCheckAndAuditAlarm*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                                 ObjectTypeName: LPSTR, ObjectName: LPSTR,

+                                 SecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 DesiredAccess: DWORD,

+                                 GenericMapping: PGENERIC_MAPPING,

+                                 ObjectCreation: WINBOOL,

+                                 GrantedAccess: LPDWORD, AccessStatus: LPBOOL,

+                                 pfGenerateOnClose: LPBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "AccessCheckAndAuditAlarmA".}

+  proc ObjectOpenAuditAlarm*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                             ObjectTypeName: LPSTR, ObjectName: LPSTR,

+                             pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                             ClientToken: HANDLE, DesiredAccess: DWORD,

+                             GrantedAccess: DWORD, Privileges: PPRIVILEGE_SET,

+                             ObjectCreation: WINBOOL, AccessGranted: WINBOOL,

+                             GenerateOnClose: LPBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ObjectOpenAuditAlarmA".}

+  proc ObjectPrivilegeAuditAlarm*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                                  ClientToken: HANDLE, DesiredAccess: DWORD,

+                                  Privileges: PPRIVILEGE_SET,

+                                  AccessGranted: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmA".}

+  proc ObjectCloseAuditAlarm*(SubsystemName: LPCSTR, HandleId: LPVOID,

+                              GenerateOnClose: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ObjectCloseAuditAlarmA".}

+  proc PrivilegedServiceAuditAlarm*(SubsystemName: LPCSTR, ServiceName: LPCSTR,

+                                    ClientToken: HANDLE,

+                                    Privileges: PPRIVILEGE_SET,

+                                    AccessGranted: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmA".}

+  proc SetFileSecurity*(lpFileName: LPCSTR,

+                        SecurityInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "SetFileSecurityA".}

+  proc GetFileSecurity*(lpFileName: LPCSTR,

+                        RequestedInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                        nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "GetFileSecurityA".}

+  proc FindFirstChangeNotification*(lpPathName: LPCSTR, bWatchSubtree: WINBOOL,

+                                    dwNotifyFilter: DWORD): HANDLE{.stdcall,

+      dynlib: "kernel32", importc: "FindFirstChangeNotificationA".}

+  proc IsBadStringPtr*(lpsz: LPCSTR, ucchMax: WINUINT): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "IsBadStringPtrA".}

+  proc LookupAccountSid*(lpSystemName: LPCSTR, Sid: PSID, Name: LPSTR,

+                         cbName: LPDWORD, ReferencedDomainName: LPSTR,

+                         cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "LookupAccountSidA".}

+  proc LookupAccountName*(lpSystemName: LPCSTR, lpAccountName: LPCSTR,

+                          Sid: PSID, cbSid: LPDWORD,

+                          ReferencedDomainName: LPSTR,

+                          cbReferencedDomainName: LPDWORD, peUse: PSID_NAME_USE): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "LookupAccountNameA".}

+  proc LookupPrivilegeValue*(lpSystemName: LPCSTR, lpName: LPCSTR, lpLuid: PLUID): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "LookupPrivilegeValueA".}

+  proc LookupPrivilegeName*(lpSystemName: LPCSTR, lpLuid: PLUID, lpName: LPSTR,

+                            cbName: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "LookupPrivilegeNameA".}

+  proc LookupPrivilegeDisplayName*(lpSystemName: LPCSTR, lpName: LPCSTR,

+                                   lpDisplayName: LPSTR, cbDisplayName: LPDWORD,

+                                   lpLanguageId: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameA".}

+  proc BuildCommDCB*(lpDef: LPCSTR, lpDCB: LPDCB): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "BuildCommDCBA".}

+  proc BuildCommDCBAndTimeouts*(lpDef: LPCSTR, lpDCB: LPDCB,

+                                lpCommTimeouts: LPCOMMTIMEOUTS): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsA".}

+  proc CommConfigDialog*(lpszName: LPCSTR, wnd: HWND, lpCC: LPCOMMCONFIG): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CommConfigDialogA".}

+  proc GetDefaultCommConfig*(lpszName: LPCSTR, lpCC: LPCOMMCONFIG,

+                             lpdwSize: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetDefaultCommConfigA".}

+  proc SetDefaultCommConfig*(lpszName: LPCSTR, lpCC: LPCOMMCONFIG, dwSize: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetDefaultCommConfigA".}

+  proc GetComputerName*(lpBuffer: LPSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetComputerNameA".}

+  proc SetComputerName*(lpComputerName: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetComputerNameA".}

+  proc GetUserName*(lpBuffer: LPSTR, nSize: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "GetUserNameA".}

+  proc wvsprintf*(para1: LPSTR, para2: LPCSTR, arglist: va_list): int32{.

+      stdcall, dynlib: "user32", importc: "wvsprintfA".}

+  proc LoadKeyboardLayout*(pwszKLID: LPCSTR, Flags: WINUINT): HKL{.stdcall,

+      dynlib: "user32", importc: "LoadKeyboardLayoutA".}

+  proc GetKeyboardLayoutName*(pwszKLID: LPSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GetKeyboardLayoutNameA".}

+  proc CreateDesktop*(lpszDesktop: LPSTR, lpszDevice: LPSTR,

+                      pDevmode: LPDEVMODE, dwFlags: DWORD,

+                      dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HDESK{.

+      stdcall, dynlib: "user32", importc: "CreateDesktopA".}

+  proc OpenDesktop*(lpszDesktop: LPSTR, dwFlags: DWORD, fInherit: WINBOOL,

+                    dwDesiredAccess: DWORD): HDESK{.stdcall, dynlib: "user32",

+      importc: "OpenDesktopA".}

+  proc EnumDesktops*(hwinsta: HWINSTA, lpEnumFunc: DESKTOPENUMPROC,

+                     lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "EnumDesktopsA".}

+  proc CreateWindowStation*(lpwinsta: LPSTR, dwReserved: DWORD,

+                            dwDesiredAccess: DWORD, lpsa: LPSECURITY_ATTRIBUTES): HWINSTA{.

+      stdcall, dynlib: "user32", importc: "CreateWindowStationA".}

+  proc OpenWindowStation*(lpszWinSta: LPSTR, fInherit: WINBOOL,

+                          dwDesiredAccess: DWORD): HWINSTA{.stdcall,

+      dynlib: "user32", importc: "OpenWindowStationA".}

+  proc EnumWindowStations*(lpEnumFunc: ENUMWINDOWSTATIONPROC, lp: LPARAM): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "EnumWindowStationsA".}

+  proc GetUserObjectInformation*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                 nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "GetUserObjectInformationA".}

+  proc SetUserObjectInformation*(hObj: HANDLE, nIndex: int32, pvInfo: PVOID,

+                                 nLength: DWORD): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetUserObjectInformationA".}

+  proc RegisterWindowMessage*(lpString: LPCSTR): WINUINT{.stdcall,

+      dynlib: "user32", importc: "RegisterWindowMessageA".}

+  proc GetMessage*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                   wMsgFilterMax: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "GetMessageA".}

+  proc DispatchMessage*(lpMsg: LPMSG): LONG{.stdcall, dynlib: "user32",

+      importc: "DispatchMessageA".}

+  proc PeekMessage*(lpMsg: LPMSG, wnd: HWND, wMsgFilterMin: WINUINT,

+                    wMsgFilterMax: WINUINT, wRemoveMsg: WINUINT): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "PeekMessageA".}

+  proc SendMessage*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "SendMessageA".}

+  proc SendMessageTimeout*(wnd: HWND, Msg: WINUINT, wp: WPARAM,

+                           lp: LPARAM, fuFlags: WINUINT, uTimeout: WINUINT,

+                           lpdwResult: LPDWORD): LRESULT{.stdcall,

+      dynlib: "user32", importc: "SendMessageTimeoutA".}

+  proc SendNotifyMessage*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "SendNotifyMessageA".}

+  proc SendMessageCallback*(wnd: HWND, Msg: WINUINT, wp: WPARAM,

+                            lp: LPARAM, lpResultCallBack: SENDASYNCPROC,

+                            dwData: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "SendMessageCallbackA".}

+  proc PostMessage*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "PostMessageA".}

+  proc PostThreadMessage*(idThread: DWORD, Msg: WINUINT, wp: WPARAM,

+                          lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "PostThreadMessageA".}

+  proc DefWindowProc*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "DefWindowProcA".}

+  proc CallWindowProc*(lpPrevWndFunc: WNDPROC, wnd: HWND, Msg: WINUINT,

+                       wp: WPARAM, lp: LPARAM): LRESULT{.stdcall,

+      dynlib: "user32", importc: "CallWindowProcA".}

+  proc RegisterClass*(lpWndClass: LPWNDCLASS): ATOM{.stdcall, dynlib: "user32",

+      importc: "RegisterClassA".}

+  proc UnregisterClass*(lpClassName: LPCSTR, hInstance: HINST): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "UnregisterClassA".}

+  proc GetClassInfo*(hInstance: HINST, lpClassName: LPCSTR,

+                     lpWndClass: LPWNDCLASS): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GetClassInfoA".}

+  proc RegisterClassEx*(para1: LPWNDCLASSEX): ATOM{.stdcall, dynlib: "user32",

+      importc: "RegisterClassExA".}

+  proc GetClassInfoEx*(para1: HINST, para2: LPCSTR, para3: LPWNDCLASSEX): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "GetClassInfoExA".}

+  proc CreateWindowEx*(dwExStyle: DWORD, lpClassName: LPCSTR,

+                       lpWindowName: LPCSTR, dwStyle: DWORD, X: int32, Y: int32,

+                       nWidth: int32, nHeight: int32, hWndParent: HWND,

+                       menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND{.

+      stdcall, dynlib: "user32", importc: "CreateWindowExA".}

+  proc CreateDialogParam*(hInstance: HINST, lpTemplateName: LPCSTR,

+                          hWndParent: HWND, lpDialogFunc: DLGPROC,

+                          dwInitParam: LPARAM): HWND{.stdcall, dynlib: "user32",

+      importc: "CreateDialogParamA".}

+  proc CreateDialogIndirectParam*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+

+                                  hWndParent: HWND, lpDialogFunc: DLGPROC,

+                                  dwInitParam: LPARAM): HWND{.stdcall,

+      dynlib: "user32", importc: "CreateDialogIndirectParamA".}

+  proc DialogBoxParam*(hInstance: HINST, lpTemplateName: LPCSTR,

+                       hWndParent: HWND, lpDialogFunc: DLGPROC,

+                       dwInitParam: LPARAM): int32{.stdcall, dynlib: "user32",

+      importc: "DialogBoxParamA".}

+  proc DialogBoxIndirectParam*(hInstance: HINST,

+                               hDialogTemplate: LPCDLGTEMPLATE,

+                               hWndParent: HWND, lpDialogFunc: DLGPROC,

+                               dwInitParam: LPARAM): int32{.stdcall,

+      dynlib: "user32", importc: "DialogBoxIndirectParamA".}

+  proc SetDlgItemText*(hDlg: HWND, nIDDlgItem: int32, lpString: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "SetDlgItemTextA".}

+  proc GetDlgItemText*(hDlg: HWND, nIDDlgItem: int32, lpString: LPSTR,

+                       nMaxCount: int32): WINUINT{.stdcall, dynlib: "user32",

+      importc: "GetDlgItemTextA".}

+  proc SendDlgItemMessage*(hDlg: HWND, nIDDlgItem: int32, Msg: WINUINT,

+                           wp: WPARAM, lp: LPARAM): LONG{.stdcall,

+      dynlib: "user32", importc: "SendDlgItemMessageA".}

+  proc DefDlgProc*(hDlg: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "DefDlgProcA".}

+  proc CallMsgFilter*(lpMsg: LPMSG, nCode: int32): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "CallMsgFilterA".}

+  proc RegisterClipboardFormat*(lpszFormat: LPCSTR): WINUINT{.stdcall,

+      dynlib: "user32", importc: "RegisterClipboardFormatA".}

+  proc GetClipboardFormatName*(format: WINUINT, lpszFormatName: LPSTR,

+                               cchMaxCount: int32): int32{.stdcall,

+      dynlib: "user32", importc: "GetClipboardFormatNameA".}

+  proc CharToOem*(lpszSrc: LPCSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "CharToOemA".}

+  proc OemToChar*(lpszSrc: LPCSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "OemToCharA".}

+  proc CharToOemBuff*(lpszSrc: LPCSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "CharToOemBuffA".}

+  proc OemToCharBuff*(lpszSrc: LPCSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "OemToCharBuffA".}

+  proc CharUpper*(lpsz: LPSTR): LPSTR{.stdcall, dynlib: "user32",

+                                       importc: "CharUpperA".}

+  proc CharUpperBuff*(lpsz: LPSTR, cchLength: DWORD): DWORD{.stdcall,

+      dynlib: "user32", importc: "CharUpperBuffA".}

+  proc CharLower*(lpsz: LPSTR): LPSTR{.stdcall, dynlib: "user32",

+                                       importc: "CharLowerA".}

+  proc CharLowerBuff*(lpsz: LPSTR, cchLength: DWORD): DWORD{.stdcall,

+      dynlib: "user32", importc: "CharLowerBuffA".}

+  proc CharNext*(lpsz: LPCSTR): LPSTR{.stdcall, dynlib: "user32",

+                                       importc: "CharNextA".}

+  proc CharPrev*(lpszStart: LPCSTR, lpszCurrent: LPCSTR): LPSTR{.stdcall,

+      dynlib: "user32", importc: "CharPrevA".}

+  proc IsCharAlpha*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "IsCharAlphaA".}

+  proc IsCharAlphaNumeric*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "IsCharAlphaNumericA".}

+  proc IsCharUpper*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "IsCharUpperA".}

+  proc IsCharLower*(ch: char): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "IsCharLowerA".}

+  proc GetKeyNameText*(lParam: LONG, lpString: LPSTR, nSize: int32): int32{.

+      stdcall, dynlib: "user32", importc: "GetKeyNameTextA".}

+  proc VkKeyScan*(ch: char): SHORT{.stdcall, dynlib: "user32",

+                                    importc: "VkKeyScanA".}

+  proc VkKeyScanEx*(ch: char, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32",

+      importc: "VkKeyScanExA".}

+  proc MapVirtualKey*(uCode: WINUINT, uMapType: WINUINT): WINUINT{.stdcall,

+      dynlib: "user32", importc: "MapVirtualKeyA".}

+  proc MapVirtualKeyEx*(uCode: WINUINT, uMapType: WINUINT, dwhkl: HKL): WINUINT{.stdcall,

+      dynlib: "user32", importc: "MapVirtualKeyExA".}

+  proc LoadAccelerators*(hInstance: HINST, lpTableName: LPCSTR): HACCEL{.

+      stdcall, dynlib: "user32", importc: "LoadAcceleratorsA".}

+  proc CreateAcceleratorTable*(para1: LPACCEL, para2: int32): HACCEL{.stdcall,

+      dynlib: "user32", importc: "CreateAcceleratorTableA".}

+  proc CopyAcceleratorTable*(hAccelSrc: HACCEL, lpAccelDst: LPACCEL,

+                             cAccelEntries: int32): int32{.stdcall,

+      dynlib: "user32", importc: "CopyAcceleratorTableA".}

+  proc TranslateAccelerator*(wnd: HWND, hAccTable: HACCEL, lpMsg: LPMSG): int32{.

+      stdcall, dynlib: "user32", importc: "TranslateAcceleratorA".}

+  proc LoadMenu*(hInstance: HINST, lpMenuName: LPCSTR): HMENU{.stdcall,

+      dynlib: "user32", importc: "LoadMenuA".}

+  proc LoadMenuIndirect*(lpMenuTemplate: LPMENUTEMPLATE): HMENU{.stdcall,

+      dynlib: "user32", importc: "LoadMenuIndirectA".}

+  proc ChangeMenu*(menu: HMENU, cmd: WINUINT, lpszNewItem: LPCSTR,

+                   cmdInsert: WINUINT, flags: WINUINT): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "ChangeMenuA".}

+  proc GetMenuString*(menu: HMENU, uIDItem: WINUINT, lpString: LPSTR,

+                      nMaxCount: int32, uFlag: WINUINT): int32{.stdcall,

+      dynlib: "user32", importc: "GetMenuStringA".}

+  proc InsertMenu*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT,

+                   uIDNewItem: WINUINT, lpNewItem: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "InsertMenuA".}

+  proc AppendMenu*(menu: HMENU, uFlags: WINUINT, uIDNewItem: WINUINT,

+                   lpNewItem: LPCSTR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "AppendMenuA".}

+  proc ModifyMenu*(hMnu: HMENU, uPosition: WINUINT, uFlags: WINUINT, uIDNewItem: WINUINT,

+                   lpNewItem: LPCSTR): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "ModifyMenuA".}

+  proc InsertMenuItem*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                       para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "InsertMenuItemA".}

+  proc GetMenuItemInfo*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                        para4: LPMENUITEMINFO): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GetMenuItemInfoA".}

+  proc SetMenuItemInfo*(para1: HMENU, para2: WINUINT, para3: WINBOOL,

+                        para4: LPCMENUITEMINFO): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetMenuItemInfoA".}

+  proc DrawText*(hDC: HDC, lpString: LPCSTR, nCount: int32, lpRect: LPRECT,

+                 uFormat: WINUINT): int32{.stdcall, dynlib: "user32",

+                                        importc: "DrawTextA".}

+  proc DrawTextEx*(para1: HDC, para2: LPSTR, para3: int32, para4: LPRECT,

+                   para5: WINUINT, para6: LPDRAWTEXTPARAMS): int32{.stdcall,

+      dynlib: "user32", importc: "DrawTextExA".}

+  proc GrayString*(hDC: HDC, hBrush: HBRUSH, lpOutputFunc: GRAYSTRINGPROC,

+                   lpData: LPARAM, nCount: int32, X: int32, Y: int32,

+                   nWidth: int32, nHeight: int32): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "GrayStringA".}

+  proc DrawState*(para1: HDC, para2: HBRUSH, para3: DRAWSTATEPROC,

+                  para4: LPARAM, para5: WPARAM, para6: int32, para7: int32,

+                  para8: int32, para9: int32, para10: WINUINT): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "DrawStateA".}

+  proc TabbedTextOut*(dc: HDC, X: int32, Y: int32, lpString: LPCSTR,

+                      nCount: int32, nTabPositions: int32,

+                      lpnTabStopPositions: LPINT, nTabOrigin: int32): LONG{.

+      stdcall, dynlib: "user32", importc: "TabbedTextOutA".}

+  proc GetTabbedTextExtent*(hDC: HDC, lpString: LPCSTR, nCount: int32,

+                            nTabPositions: int32, lpnTabStopPositions: LPINT): DWORD{.

+      stdcall, dynlib: "user32", importc: "GetTabbedTextExtentA".}

+  proc SetProp*(wnd: HWND, lpString: LPCSTR, hData: HANDLE): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetPropA".}

+  proc GetProp*(wnd: HWND, lpString: LPCSTR): HANDLE{.stdcall,

+      dynlib: "user32", importc: "GetPropA".}

+  proc RemoveProp*(wnd: HWND, lpString: LPCSTR): HANDLE{.stdcall,

+      dynlib: "user32", importc: "RemovePropA".}

+  proc EnumPropsEx*(wnd: HWND, lpEnumFunc: PROPENUMPROCEX, lp: LPARAM): int32{.

+      stdcall, dynlib: "user32", importc: "EnumPropsExA".}

+  proc EnumProps*(wnd: HWND, lpEnumFunc: PROPENUMPROC): int32{.stdcall,

+      dynlib: "user32", importc: "EnumPropsA".}

+  proc SetWindowText*(wnd: HWND, lpString: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "SetWindowTextA".}

+  proc GetWindowText*(wnd: HWND, lpString: LPSTR, nMaxCount: int32): int32{.

+      stdcall, dynlib: "user32", importc: "GetWindowTextA".}

+  proc GetWindowTextLength*(wnd: HWND): int32{.stdcall, dynlib: "user32",

+      importc: "GetWindowTextLengthA".}

+  proc MessageBox*(wnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: WINUINT): int32{.

+      stdcall, dynlib: "user32", importc: "MessageBoxA".}

+  proc MessageBoxEx*(wnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: WINUINT,

+                     wLanguageId: int16): int32{.stdcall, dynlib: "user32",

+      importc: "MessageBoxExA".}

+  proc MessageBoxIndirect*(para1: LPMSGBOXPARAMS): int32{.stdcall,

+      dynlib: "user32", importc: "MessageBoxIndirectA".}

+  proc GetWindowLong*(wnd: HWND, nIndex: int32): LONG{.stdcall,

+      dynlib: "user32", importc: "GetWindowLongA".}

+  proc SetWindowLong*(wnd: HWND, nIndex: int32, dwNewLong: LONG): LONG{.

+      stdcall, dynlib: "user32", importc: "SetWindowLongA".}

+  proc GetClassLong*(wnd: HWND, nIndex: int32): DWORD{.stdcall,

+      dynlib: "user32", importc: "GetClassLongA".}

+  proc SetClassLong*(wnd: HWND, nIndex: int32, dwNewLong: LONG): DWORD{.

+      stdcall, dynlib: "user32", importc: "SetClassLongA".}

+  when defined(cpu64):

+    proc GetWindowLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetWindowLongPtrA".}

+    proc SetWindowLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetWindowLongPtrA".}

+    proc GetClassLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetClassLongPtrA".}

+    proc SetClassLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetClassLongPtrA".}

+  else:

+    proc GetWindowLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetWindowLongA".}

+    proc SetWindowLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetWindowLongA".}

+    proc GetClassLongPtr*(wnd: HWND, nIndex: int32): LONG_PTR{.stdcall,

+        dynlib: "user32", importc: "GetClassLongA".}

+    proc SetClassLongPtr*(wnd: HWND, nIndex: int32, dwNewLong: LONG_PTR): LONG_PTR{.

+        stdcall, dynlib: "user32", importc: "SetClassLongA".}

+  proc FindWindow*(lpClassName: LPCSTR, lpWindowName: LPCSTR): HWND{.stdcall,

+      dynlib: "user32", importc: "FindWindowA".}

+  proc FindWindowEx*(para1: HWND, para2: HWND, para3: LPCSTR, para4: LPCSTR): HWND{.

+      stdcall, dynlib: "user32", importc: "FindWindowExA".}

+  proc GetClassName*(wnd: HWND, lpClassName: LPSTR, nMaxCount: int32): int32{.

+      stdcall, dynlib: "user32", importc: "GetClassNameA".}

+  proc SetWindowsHookEx*(idHook: int32, lpfn: HOOKPROC, hmod: HINST,

+                         dwThreadId: DWORD): HHOOK{.stdcall, dynlib: "user32",

+      importc: "SetWindowsHookExA".}

+  proc LoadBitmap*(hInstance: HINST, lpBitmapName: LPCSTR): HBITMAP{.stdcall,

+      dynlib: "user32", importc: "LoadBitmapA".}

+  proc LoadCursor*(hInstance: HINST, lpCursorName: LPCSTR): HCURSOR{.stdcall,

+      dynlib: "user32", importc: "LoadCursorA".}

+  proc LoadCursorFromFile*(lpFileName: LPCSTR): HCURSOR{.stdcall,

+      dynlib: "user32", importc: "LoadCursorFromFileA".}

+  proc LoadIcon*(hInstance: HINST, lpIconName: LPCSTR): HICON{.stdcall,

+      dynlib: "user32", importc: "LoadIconA".}

+  proc LoadImage*(para1: HINST, para2: LPCSTR, para3: WINUINT, para4: int32,

+                  para5: int32, para6: WINUINT): HANDLE{.stdcall, dynlib: "user32",

+      importc: "LoadImageA".}

+  proc LoadString*(hInstance: HINST, uID: WINUINT, lpBuffer: LPSTR,

+                   nBufferMax: int32): int32{.stdcall, dynlib: "user32",

+      importc: "LoadStringA".}

+  proc IsDialogMessage*(hDlg: HWND, lpMsg: LPMSG): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "IsDialogMessageA".}

+  proc DlgDirList*(hDlg: HWND, lpPathSpec: LPSTR, nIDListBox: int32,

+                   nIDStaticPath: int32, uFileType: WINUINT): int32{.stdcall,

+      dynlib: "user32", importc: "DlgDirListA".}

+  proc DlgDirSelectEx*(hDlg: HWND, lpString: LPSTR, nCount: int32,

+                       nIDListBox: int32): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "DlgDirSelectExA".}

+  proc DlgDirListComboBox*(hDlg: HWND, lpPathSpec: LPSTR, nIDComboBox: int32,

+                           nIDStaticPath: int32, uFiletype: WINUINT): int32{.

+      stdcall, dynlib: "user32", importc: "DlgDirListComboBoxA".}

+  proc DlgDirSelectComboBoxEx*(hDlg: HWND, lpString: LPSTR, nCount: int32,

+                               nIDComboBox: int32): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "DlgDirSelectComboBoxExA".}

+  proc DefFrameProc*(wnd: HWND, hWndMDIClient: HWND, uMsg: WINUINT,

+                     wp: WPARAM, lp: LPARAM): LRESULT{.stdcall,

+      dynlib: "user32", importc: "DefFrameProcA".}

+  proc DefMDIChildProc*(wnd: HWND, uMsg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT{.

+      stdcall, dynlib: "user32", importc: "DefMDIChildProcA".}

+  proc CreateMDIWindow*(lpClassName: LPSTR, lpWindowName: LPSTR, dwStyle: DWORD,

+                        X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                        hWndParent: HWND, hInstance: HINST, lp: LPARAM): HWND{.

+      stdcall, dynlib: "user32", importc: "CreateMDIWindowA".}

+  proc WinHelp*(hWndMain: HWND, lpszHelp: LPCSTR, uCommand: WINUINT, dwData: DWORD): WINBOOL{.

+      stdcall, dynlib: "user32", importc: "WinHelpA".}

+  proc ChangeDisplaySettings*(lpDevMode: LPDEVMODE, dwFlags: DWORD): LONG{.

+      stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsA".}

+  proc EnumDisplaySettings*(lpszDeviceName: LPCSTR, iModeNum: DWORD,

+                            lpDevMode: LPDEVMODE): WINBOOL{.stdcall,

+      dynlib: "user32", importc: "EnumDisplaySettingsA".}

+  proc SystemParametersInfo*(uiAction: WINUINT, uiParam: WINUINT, pvParam: PVOID,

+                             fWinIni: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+      importc: "SystemParametersInfoA".}

+  proc AddFontResource*(para1: LPCSTR): int32{.stdcall, dynlib: "gdi32",

+      importc: "AddFontResourceA".}

+  proc CopyMetaFile*(para1: HMETAFILE, para2: LPCSTR): HMETAFILE{.stdcall,

+      dynlib: "gdi32", importc: "CopyMetaFileA".}

+  proc CreateFont*(para1: int32, para2: int32, para3: int32, para4: int32,

+                   para5: int32, para6: DWORD, para7: DWORD, para8: DWORD,

+                   para9: DWORD, para10: DWORD, para11: DWORD, para12: DWORD,

+                   para13: DWORD, para14: LPCSTR): HFONT{.stdcall,

+      dynlib: "gdi32", importc: "CreateFontA".}

+  proc CreateFontIndirect*(para1: LPLOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+      importc: "CreateFontIndirectA".}

+  proc CreateFontIndirect*(para1: var LOGFONT): HFONT{.stdcall, dynlib: "gdi32",

+      importc: "CreateFontIndirectA".}

+  proc CreateIC*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: LPDEVMODE): HDC{.

+      stdcall, dynlib: "gdi32", importc: "CreateICA".}

+  proc CreateMetaFile*(para1: LPCSTR): HDC{.stdcall, dynlib: "gdi32",

+      importc: "CreateMetaFileA".}

+  proc CreateScalableFontResource*(para1: DWORD, para2: LPCSTR, para3: LPCSTR,

+                                   para4: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "CreateScalableFontResourceA".}

+  proc EnumFontFamiliesEx*(para1: HDC, para2: LPLOGFONT, para3: FONTENUMEXPROC,

+                           para4: LPARAM, para5: DWORD): int32{.stdcall,

+      dynlib: "gdi32", importc: "EnumFontFamiliesExA".}

+  proc EnumFontFamilies*(para1: HDC, para2: LPCSTR, para3: FONTENUMPROC,

+                         para4: LPARAM): int32{.stdcall, dynlib: "gdi32",

+      importc: "EnumFontFamiliesA".}

+  proc EnumFonts*(para1: HDC, para2: LPCSTR, para3: ENUMFONTSPROC, para4: LPARAM): int32{.

+      stdcall, dynlib: "gdi32", importc: "EnumFontsA".}

+  proc EnumFonts*(para1: HDC, para2: LPCSTR, para3: ENUMFONTSPROC,

+                  para4: pointer): int32{.stdcall, dynlib: "gdi32",

+      importc: "EnumFontsA".}

+  proc GetCharWidth*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharWidthA".}

+  proc GetCharWidth32*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharWidth32A".}

+  proc GetCharWidthFloat*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: ptr float32): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatA".}

+  proc GetCharABCWidths*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: LPABC): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsA".}

+  proc GetCharABCWidthsFloat*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                              para4: LPABCFLOAT): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "GetCharABCWidthsFloatA".}

+  proc GetGlyphOutline*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                        para4: LPGLYPHMETRICS, para5: DWORD, para6: LPVOID,

+                        para7: PMAT2): DWORD{.stdcall, dynlib: "gdi32",

+      importc: "GetGlyphOutlineA".}

+  proc GetMetaFile*(para1: LPCSTR): HMETAFILE{.stdcall, dynlib: "gdi32",

+      importc: "GetMetaFileA".}

+  proc GetOutlineTextMetrics*(para1: HDC, para2: WINUINT,

+                              para3: LPOUTLINETEXTMETRIC): WINUINT{.stdcall,

+      dynlib: "gdi32", importc: "GetOutlineTextMetricsA".}

+  proc GetTextExtentPoint*(para1: HDC, para2: LPCSTR, para3: int32,

+                           para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetTextExtentPointA".}

+  proc GetTextExtentPoint32*(para1: HDC, para2: LPCSTR, para3: int32,

+                             para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetTextExtentPoint32A".}

+  proc GetTextExtentExPoint*(para1: HDC, para2: LPCSTR, para3: int32,

+                             para4: int32, para5: LPINT, para6: LPINT,

+                             para7: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetTextExtentExPointA".}

+  proc GetCharacterPlacement*(para1: HDC, para2: LPCSTR, para3: int32,

+                              para4: int32, para5: LPGCP_RESULTS, para6: DWORD): DWORD{.

+      stdcall, dynlib: "gdi32", importc: "GetCharacterPlacementA".}

+  proc ResetDC*(para1: HDC, para2: LPDEVMODE): HDC{.stdcall, dynlib: "gdi32",

+      importc: "ResetDCA".}

+  proc RemoveFontResource*(para1: LPCSTR): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "RemoveFontResourceA".}

+  proc CopyEnhMetaFile*(para1: HENHMETAFILE, para2: LPCSTR): HENHMETAFILE{.

+      stdcall, dynlib: "gdi32", importc: "CopyEnhMetaFileA".}

+  proc CreateEnhMetaFile*(para1: HDC, para2: LPCSTR, para3: LPRECT,

+                          para4: LPCSTR): HDC{.stdcall, dynlib: "gdi32",

+      importc: "CreateEnhMetaFileA".}

+  proc GetEnhMetaFile*(para1: LPCSTR): HENHMETAFILE{.stdcall, dynlib: "gdi32",

+      importc: "GetEnhMetaFileA".}

+  proc GetEnhMetaFileDescription*(para1: HENHMETAFILE, para2: WINUINT, para3: LPSTR): WINUINT{.

+      stdcall, dynlib: "gdi32", importc: "GetEnhMetaFileDescriptionA".}

+  proc GetTextMetrics*(para1: HDC, para2: LPTEXTMETRIC): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "GetTextMetricsA".}

+  proc StartDoc*(para1: HDC, para2: PDOCINFO): int32{.stdcall, dynlib: "gdi32",

+      importc: "StartDocA".}

+  proc GetObject*(para1: HGDIOBJ, para2: int32, para3: LPVOID): int32{.stdcall,

+      dynlib: "gdi32", importc: "GetObjectA".}

+  proc TextOut*(para1: HDC, para2: int32, para3: int32, para4: LPCSTR,

+                para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+                                        importc: "TextOutA".}

+  proc ExtTextOut*(para1: HDC, para2: int32, para3: int32, para4: WINUINT,

+                   para5: LPRECT, para6: LPCSTR, para7: WINUINT, para8: LPINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "ExtTextOutA".}

+  proc PolyTextOut*(para1: HDC, para2: PPOLYTEXT, para3: int32): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "PolyTextOutA".}

+  proc GetTextFace*(para1: HDC, para2: int32, para3: LPSTR): int32{.stdcall,

+      dynlib: "gdi32", importc: "GetTextFaceA".}

+  proc GetKerningPairs*(para1: HDC, para2: DWORD, para3: LPKERNINGPAIR): DWORD{.

+      stdcall, dynlib: "gdi32", importc: "GetKerningPairsA".}

+  proc CreateColorSpace*(para1: LPLOGCOLORSPACE): HCOLORSPACE{.stdcall,

+      dynlib: "gdi32", importc: "CreateColorSpaceA".}

+  proc GetLogColorSpace*(para1: HCOLORSPACE, para2: LPLOGCOLORSPACE,

+                         para3: DWORD): WINBOOL{.stdcall, dynlib: "gdi32",

+      importc: "GetLogColorSpaceA".}

+  proc GetICMProfile*(para1: HDC, para2: DWORD, para3: LPSTR): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "GetICMProfileA".}

+  proc SetICMProfile*(para1: HDC, para2: LPSTR): WINBOOL{.stdcall,

+      dynlib: "gdi32", importc: "SetICMProfileA".}

+  proc UpdateICMRegKey*(para1: DWORD, para2: DWORD, para3: LPSTR, para4: WINUINT): WINBOOL{.

+      stdcall, dynlib: "gdi32", importc: "UpdateICMRegKeyA".}

+  proc EnumICMProfiles*(para1: HDC, para2: ICMENUMPROC, para3: LPARAM): int32{.

+      stdcall, dynlib: "gdi32", importc: "EnumICMProfilesA".}

+  proc PropertySheet*(lppsph: LPCPROPSHEETHEADER): int32{.stdcall,

+      dynlib: "comctl32", importc: "PropertySheetA".}

+  proc ImageList_LoadImage*(hi: HINST, lpbmp: LPCSTR, cx: int32, cGrow: int32,

+                            crMask: COLORREF, uType: WINUINT, uFlags: WINUINT): HIMAGELIST{.

+      stdcall, dynlib: "comctl32", importc: "ImageList_LoadImageA".}

+  proc CreateStatusWindow*(style: LONG, lpszText: LPCSTR, hwndParent: HWND,

+                           wID: WINUINT): HWND{.stdcall, dynlib: "comctl32",

+      importc: "CreateStatusWindowA".}

+  proc DrawStatusText*(hDC: HDC, lprc: LPRECT, pszText: LPCSTR, uFlags: WINUINT){.

+      stdcall, dynlib: "comctl32", importc: "DrawStatusTextA".}

+  proc GetOpenFileName*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+      dynlib: "comdlg32", importc: "GetOpenFileNameA".}

+  proc GetSaveFileName*(para1: LPOPENFILENAME): WINBOOL{.stdcall,

+      dynlib: "comdlg32", importc: "GetSaveFileNameA".}

+  proc GetFileTitle*(para1: LPCSTR, para2: LPSTR, para3: int16): int{.stdcall,

+      dynlib: "comdlg32", importc: "GetFileTitleA".}

+  proc ChooseColor*(para1: LPCHOOSECOLOR): WINBOOL{.stdcall, dynlib: "comdlg32",

+      importc: "ChooseColorA".}

+  proc FindText*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+      importc: "FindTextA".}

+  proc ReplaceText*(para1: LPFINDREPLACE): HWND{.stdcall, dynlib: "comdlg32",

+      importc: "ReplaceTextA".}

+  proc ChooseFont*(para1: LPCHOOSEFONT): WINBOOL{.stdcall, dynlib: "comdlg32",

+      importc: "ChooseFontA".}

+  proc PrintDlg*(para1: LPPRINTDLG): WINBOOL{.stdcall, dynlib: "comdlg32",

+      importc: "PrintDlgA".}

+  proc PageSetupDlg*(para1: LPPAGESETUPDLG): WINBOOL{.stdcall,

+      dynlib: "comdlg32", importc: "PageSetupDlgA".}

+  proc CreateProcess*(lpApplicationName: LPCSTR, lpCommandLine: LPSTR,

+                      lpProcessAttributes: LPSECURITY_ATTRIBUTES,

+                      lpThreadAttributes: LPSECURITY_ATTRIBUTES,

+                      bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                      lpEnvironment: LPVOID, lpCurrentDirectory: LPCSTR,

+                      lpStartupInfo: LPSTARTUPINFO,

+                      lpProcessInformation: LPPROCESS_INFORMATION): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "CreateProcessA".}

+  proc GetStartupInfo*(lpStartupInfo: LPSTARTUPINFO){.stdcall,

+      dynlib: "kernel32", importc: "GetStartupInfoA".}

+  proc FindFirstFile*(lpFileName: LPCSTR, lpFindFileData: LPWIN32_FIND_DATA): HANDLE{.

+      stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}

+  proc FindNextFile*(hFindFile: HANDLE, lpFindFileData: LPWIN32_FIND_DATA): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "FindNextFileA".}

+  proc GetVersionEx*(VersionInformation: LPOSVERSIONINFO): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetVersionExA".}

+  proc CreateWindow*(lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD,

+                     X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                     hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                     lpParam: LPVOID): HWND

+  proc CreateDialog*(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                     lpDialogFunc: DLGPROC): HWND

+  proc CreateDialogIndirect*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                             hWndParent: HWND, lpDialogFunc: DLGPROC): HWND

+  proc DialogBox*(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                  lpDialogFunc: DLGPROC): int32

+  proc DialogBoxIndirect*(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE,

+                          hWndParent: HWND, lpDialogFunc: DLGPROC): int32

+  proc CreateDC*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: PDEVMODE): HDC{.

+      stdcall, dynlib: "gdi32", importc: "CreateDCA".}

+  proc VerInstallFile*(uFlags: DWORD, szSrcFileName: LPSTR,

+                       szDestFileName: LPSTR, szSrcDir: LPSTR, szDestDir: LPSTR,

+                       szCurDir: LPSTR, szTmpFile: LPSTR, lpuTmpFileLen: PUINT): DWORD{.

+      stdcall, dynlib: "version", importc: "VerInstallFileA".}

+  proc GetFileVersionInfoSize*(lptstrFilename: LPSTR, lpdwHandle: LPDWORD): DWORD{.

+      stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeA".}

+  proc GetFileVersionInfo*(lptstrFilename: LPSTR, dwHandle: DWORD, dwLen: DWORD,

+                           lpData: LPVOID): WINBOOL{.stdcall, dynlib: "version",

+      importc: "GetFileVersionInfoA".}

+  proc VerLanguageName*(wLang: DWORD, szLang: LPSTR, nSize: DWORD): DWORD{.

+      stdcall, dynlib: "kernel32", importc: "VerLanguageNameA".}

+  proc VerQueryValue*(pBlock: LPVOID, lpSubBlock: LPSTR, lplpBuffer: LPVOID,

+                      puLen: PUINT): WINBOOL{.stdcall, dynlib: "version",

+      importc: "VerQueryValueA".}

+  proc VerFindFile*(uFlags: DWORD, szFileName: LPSTR, szWinDir: LPSTR,

+                    szAppDir: LPSTR, szCurDir: LPSTR, lpuCurDirLen: PUINT,

+                    szDestDir: LPSTR, lpuDestDirLen: PUINT): DWORD{.stdcall,

+      dynlib: "version", importc: "VerFindFileA".}

+  proc RegConnectRegistry*(lpMachineName: LPSTR, key: HKEY, phkResult: PHKEY): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegConnectRegistryA".}

+  proc RegCreateKey*(key: HKEY, lpSubKey: LPCSTR, phkResult: PHKEY): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegCreateKeyA".}

+  proc RegCreateKeyEx*(key: HKEY, lpSubKey: LPCSTR, Reserved: DWORD,

+                       lpClass: LPSTR, dwOptions: DWORD, samDesired: REGSAM,

+                       lpSecurityAttributes: LPSECURITY_ATTRIBUTES,

+                       phkResult: PHKEY, lpdwDisposition: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegCreateKeyExA".}

+  proc RegDeleteKey*(key: HKEY, lpSubKey: LPCSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegDeleteKeyA".}

+  proc RegDeleteValue*(key: HKEY, lpValueName: LPCSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegDeleteValueA".}

+  proc RegEnumKey*(key: HKEY, dwIndex: DWORD, lpName: LPSTR, cbName: DWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegEnumKeyA".}

+  proc RegEnumKeyEx*(key: HKEY, dwIndex: DWORD, lpName: LPSTR,

+                     lpcbName: LPDWORD, lpReserved: LPDWORD, lpClass: LPSTR,

+                     lpcbClass: LPDWORD, lpftLastWriteTime: PFILETIME): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegEnumKeyExA".}

+  proc RegEnumValue*(key: HKEY, dwIndex: DWORD, lpValueName: LPSTR,

+                     lpcbValueName: LPDWORD, lpReserved: LPDWORD,

+                     lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegEnumValueA".}

+  proc RegLoadKey*(key: HKEY, lpSubKey: LPCSTR, lpFile: LPCSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegLoadKeyA".}

+  proc RegOpenKey*(key: HKEY, lpSubKey: LPCSTR, phkResult: PHKEY): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegOpenKeyA".}

+  proc RegOpenKeyEx*(key: HKEY, lpSubKey: LPCSTR, ulOptions: DWORD,

+                     samDesired: REGSAM, phkResult: PHKEY): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegOpenKeyExA".}

+  proc RegQueryInfoKey*(key: HKEY, lpClass: LPSTR, lpcbClass: LPDWORD,

+                        lpReserved: LPDWORD, lpcSubKeys: LPDWORD,

+                        lpcbMaxSubKeyLen: LPDWORD, lpcbMaxClassLen: LPDWORD,

+                        lpcValues: LPDWORD, lpcbMaxValueNameLen: LPDWORD,

+                        lpcbMaxValueLen: LPDWORD,

+                        lpcbSecurityDescriptor: LPDWORD,

+                        lpftLastWriteTime: PFILETIME): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegQueryInfoKeyA".}

+  proc RegQueryValue*(key: HKEY, lpSubKey: LPCSTR, lpValue: LPSTR,

+                      lpcbValue: PLONG): LONG{.stdcall, dynlib: "advapi32",

+      importc: "RegQueryValueA".}

+  proc RegQueryMultipleValues*(key: HKEY, val_list: PVALENT, num_vals: DWORD,

+                               lpValueBuf: LPSTR, ldwTotsize: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesA".}

+  proc RegQueryValueEx*(key: HKEY, lpValueName: LPCSTR, lpReserved: LPDWORD,

+                        lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegQueryValueExA".}

+  proc RegReplaceKey*(key: HKEY, lpSubKey: LPCSTR, lpNewFile: LPCSTR,

+                      lpOldFile: LPCSTR): LONG{.stdcall, dynlib: "advapi32",

+      importc: "RegReplaceKeyA".}

+  proc RegRestoreKey*(key: HKEY, lpFile: LPCSTR, dwFlags: DWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegRestoreKeyA".}

+  proc RegSaveKey*(key: HKEY, lpFile: LPCSTR,

+                   lpSecurityAttributes: LPSECURITY_ATTRIBUTES): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegSaveKeyA".}

+  proc RegSetValue*(key: HKEY, lpSubKey: LPCSTR, dwType: DWORD, lpData: LPCSTR,

+                    cbData: DWORD): LONG{.stdcall, dynlib: "advapi32",

+      importc: "RegSetValueA".}

+  proc RegSetValueEx*(key: HKEY, lpValueName: LPCSTR, Reserved: DWORD,

+                      dwType: DWORD, lpData: LPBYTE, cbData: DWORD): LONG{.

+      stdcall, dynlib: "advapi32", importc: "RegSetValueExA".}

+  proc RegUnLoadKey*(key: HKEY, lpSubKey: LPCSTR): LONG{.stdcall,

+      dynlib: "advapi32", importc: "RegUnLoadKeyA".}

+  proc InitiateSystemShutdown*(lpMachineName: LPSTR, lpMessage: LPSTR,

+                               dwTimeout: DWORD, bForceAppsClosed: WINBOOL,

+                               bRebootAfterShutdown: WINBOOL): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "InitiateSystemShutdownA".}

+  proc AbortSystemShutdown*(lpMachineName: LPSTR): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "AbortSystemShutdownA".}

+  proc CompareString*(Locale: LCID, dwCmpFlags: DWORD, lpString1: LPCSTR,

+                      cchCount1: int32, lpString2: LPCSTR, cchCount2: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "CompareStringA".}

+  proc LCMapString*(Locale: LCID, dwMapFlags: DWORD, lpSrcStr: LPCSTR,

+                    cchSrc: int32, lpDestStr: LPSTR, cchDest: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "LCMapStringA".}

+  proc GetLocaleInfo*(Locale: LCID, LCType: LCTYPE, lpLCData: LPSTR,

+                      cchData: int32): int32{.stdcall, dynlib: "kernel32",

+      importc: "GetLocaleInfoA".}

+  proc SetLocaleInfo*(Locale: LCID, LCType: LCTYPE, lpLCData: LPCSTR): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "SetLocaleInfoA".}

+  proc GetTimeFormat*(Locale: LCID, dwFlags: DWORD, lpTime: LPSYSTEMTIME,

+                      lpFormat: LPCSTR, lpTimeStr: LPSTR, cchTime: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "GetTimeFormatA".}

+  proc GetDateFormat*(Locale: LCID, dwFlags: DWORD, lpDate: LPSYSTEMTIME,

+                      lpFormat: LPCSTR, lpDateStr: LPSTR, cchDate: int32): int32{.

+      stdcall, dynlib: "kernel32", importc: "GetDateFormatA".}

+  proc GetNumberFormat*(Locale: LCID, dwFlags: DWORD, lpValue: LPCSTR,

+                        lpFormat: PNUMBERFMT, lpNumberStr: LPSTR,

+                        cchNumber: int32): int32{.stdcall, dynlib: "kernel32",

+      importc: "GetNumberFormatA".}

+  proc GetCurrencyFormat*(Locale: LCID, dwFlags: DWORD, lpValue: LPCSTR,

+                          lpFormat: PCURRENCYFMT, lpCurrencyStr: LPSTR,

+                          cchCurrency: int32): int32{.stdcall,

+      dynlib: "kernel32", importc: "GetCurrencyFormatA".}

+  proc EnumCalendarInfo*(lpCalInfoEnumProc: CALINFO_ENUMPROC, Locale: LCID,

+                         Calendar: CALID, CalType: CALTYPE): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "EnumCalendarInfoA".}

+  proc EnumTimeFormats*(lpTimeFmtEnumProc: TIMEFMT_ENUMPROC, Locale: LCID,

+                        dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "EnumTimeFormatsA".}

+  proc EnumDateFormats*(lpDateFmtEnumProc: DATEFMT_ENUMPROC, Locale: LCID,

+                        dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "EnumDateFormatsA".}

+  proc GetStringTypeEx*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCSTR,

+                        cchSrc: int32, lpCharType: LPWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetStringTypeExA".}

+  proc GetStringType*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCSTR,

+                      cchSrc: int32, lpCharType: LPWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "GetStringTypeA".}

+  proc FoldString*(dwMapFlags: DWORD, lpSrcStr: LPCSTR, cchSrc: int32,

+                   lpDestStr: LPSTR, cchDest: int32): int32{.stdcall,

+      dynlib: "kernel32", importc: "FoldStringA".}

+  proc EnumSystemLocales*(lpLocaleEnumProc: LOCALE_ENUMPROC, dwFlags: DWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "EnumSystemLocalesA".}

+  proc EnumSystemCodePages*(lpCodePageEnumProc: CODEPAGE_ENUMPROC,

+                            dwFlags: DWORD): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "EnumSystemCodePagesA".}

+  proc PeekConsoleInput*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                         nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "PeekConsoleInputA".}

+  proc ReadConsoleInput*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                         nLength: DWORD, lpNumberOfEventsRead: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "ReadConsoleInputA".}

+  proc WriteConsoleInput*(hConsoleInput: HANDLE, lpBuffer: PINPUTRECORD,

+                          nLength: DWORD, lpNumberOfEventsWritten: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteConsoleInputA".}

+  proc ReadConsoleOutput*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                          dwBufferSize: COORD, dwBufferCoord: COORD,

+                          lpReadRegion: PSMALL_RECT): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "ReadConsoleOutputA".}

+  proc WriteConsoleOutput*(hConsoleOutput: HANDLE, lpBuffer: PCHAR_INFO,

+                           dwBufferSize: COORD, dwBufferCoord: COORD,

+                           lpWriteRegion: PSMALL_RECT): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "WriteConsoleOutputA".}

+  proc ReadConsoleOutputCharacter*(hConsoleOutput: HANDLE, lpCharacter: LPSTR,

+                                   nLength: DWORD, dwReadCoord: COORD,

+                                   lpNumberOfCharsRead: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterA".}

+  proc WriteConsoleOutputCharacter*(hConsoleOutput: HANDLE, lpCharacter: LPCSTR,

+                                    nLength: DWORD, dwWriteCoord: COORD,

+                                    lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterA".}

+  proc FillConsoleOutputCharacter*(hConsoleOutput: HANDLE, cCharacter: char,

+                                   nLength: DWORD, dwWriteCoord: COORD,

+                                   lpNumberOfCharsWritten: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".}

+  proc ScrollConsoleScreenBuffer*(hConsoleOutput: HANDLE,

+                                  lpScrollRectangle: PSMALL_RECT,

+                                  lpClipRectangle: PSMALL_RECT,

+                                  dwDestinationOrigin: COORD, lpFill: PCHAR_INFO): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "ScrollConsoleScreenBufferA".}

+  proc GetConsoleTitle*(lpConsoleTitle: LPSTR, nSize: DWORD): DWORD{.stdcall,

+      dynlib: "kernel32", importc: "GetConsoleTitleA".}

+  proc SetConsoleTitle*(lpConsoleTitle: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "kernel32", importc: "SetConsoleTitleA".}

+  proc ReadConsole*(hConsoleInput: HANDLE, lpBuffer: LPVOID,

+                    nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: LPDWORD,

+                    lpReserved: LPVOID): WINBOOL{.stdcall, dynlib: "kernel32",

+      importc: "ReadConsoleA".}

+  proc WriteConsole*(hConsoleOutput: HANDLE, lpBuffer: pointer,

+                     nNumberOfCharsToWrite: DWORD,

+                     lpNumberOfCharsWritten: LPDWORD, lpReserved: LPVOID): WINBOOL{.

+      stdcall, dynlib: "kernel32", importc: "WriteConsoleA".}

+  proc WNetAddConnection*(lpRemoteName: LPCSTR, lpPassword: LPCSTR,

+                          lpLocalName: LPCSTR): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetAddConnectionA".}

+  proc WNetAddConnection2*(lpNetResource: LPNETRESOURCE, lpPassword: LPCSTR,

+                           lpUserName: LPCSTR, dwFlags: DWORD): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetAddConnection2A".}

+  proc WNetAddConnection3*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                           lpPassword: LPCSTR, lpUserName: LPCSTR,

+                           dwFlags: DWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetAddConnection3A".}

+  proc WNetCancelConnection*(lpName: LPCSTR, fForce: WINBOOL): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetCancelConnectionA".}

+  proc WNetCancelConnection2*(lpName: LPCSTR, dwFlags: DWORD, fForce: WINBOOL): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetCancelConnection2A".}

+  proc WNetGetConnection*(lpLocalName: LPCSTR, lpRemoteName: LPSTR,

+                          lpnLength: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetGetConnectionA".}

+  proc WNetUseConnection*(hwndOwner: HWND, lpNetResource: LPNETRESOURCE,

+                          lpUserID: LPCSTR, lpPassword: LPCSTR, dwFlags: DWORD,

+                          lpAccessName: LPSTR, lpBufferSize: LPDWORD,

+                          lpResult: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetUseConnectionA".}

+  proc WNetSetConnection*(lpName: LPCSTR, dwProperties: DWORD, pvValues: LPVOID): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetSetConnectionA".}

+  proc WNetConnectionDialog1*(lpConnDlgStruct: LPCONNECTDLGSTRUCT): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetConnectionDialog1A".}

+  proc WNetDisconnectDialog1*(lpConnDlgStruct: LPDISCDLGSTRUCT): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetDisconnectDialog1A".}

+  proc WNetOpenEnum*(dwScope: DWORD, dwType: DWORD, dwUsage: DWORD,

+                     lpNetResource: LPNETRESOURCE, lphEnum: LPHANDLE): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetOpenEnumA".}

+  proc WNetEnumResource*(hEnum: HANDLE, lpcCount: LPDWORD, lpBuffer: LPVOID,

+                         lpBufferSize: LPDWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetEnumResourceA".}

+  proc WNetGetUniversalName*(lpLocalPath: LPCSTR, dwInfoLevel: DWORD,

+                             lpBuffer: LPVOID, lpBufferSize: LPDWORD): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameA".}

+  proc WNetGetUser*(lpName: LPCSTR, lpUserName: LPSTR, lpnLength: LPDWORD): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetGetUserA".}

+  proc WNetGetProviderName*(dwNetType: DWORD, lpProviderName: LPSTR,

+                            lpBufferSize: LPDWORD): DWORD{.stdcall,

+      dynlib: "mpr", importc: "WNetGetProviderNameA".}

+  proc WNetGetNetworkInformation*(lpProvider: LPCSTR,

+                                  lpNetInfoStruct: LPNETINFOSTRUCT): DWORD{.

+      stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationA".}

+  proc WNetGetLastError*(lpError: LPDWORD, lpErrorBuf: LPSTR,

+                         nErrorBufSize: DWORD, lpNameBuf: LPSTR,

+                         nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+      importc: "WNetGetLastErrorA".}

+  proc MultinetGetConnectionPerformance*(lpNetResource: LPNETRESOURCE,

+      lpNetConnectInfoStruct: LPNETCONNECTINFOSTRUCT): DWORD{.stdcall,

+      dynlib: "mpr", importc: "MultinetGetConnectionPerformanceA".}

+  proc ChangeServiceConfig*(hService: SC_HANDLE, dwServiceType: DWORD,

+                            dwStartType: DWORD, dwErrorControl: DWORD,

+                            lpBinaryPathName: LPCSTR, lpLoadOrderGroup: LPCSTR,

+                            lpdwTagId: LPDWORD, lpDependencies: LPCSTR,

+                            lpServiceStartName: LPCSTR, lpPassword: LPCSTR,

+                            lpDisplayName: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "ChangeServiceConfigA".}

+  proc CreateService*(hSCManager: SC_HANDLE, lpServiceName: LPCSTR,

+                      lpDisplayName: LPCSTR, dwDesiredAccess: DWORD,

+                      dwServiceType: DWORD, dwStartType: DWORD,

+                      dwErrorControl: DWORD, lpBinaryPathName: LPCSTR,

+                      lpLoadOrderGroup: LPCSTR, lpdwTagId: LPDWORD,

+                      lpDependencies: LPCSTR, lpServiceStartName: LPCSTR,

+                      lpPassword: LPCSTR): SC_HANDLE{.stdcall,

+      dynlib: "advapi32", importc: "CreateServiceA".}

+  proc EnumDependentServices*(hService: SC_HANDLE, dwServiceState: DWORD,

+                              lpServices: LPENUM_SERVICE_STATUS,

+                              cbBufSize: DWORD, pcbBytesNeeded: LPDWORD,

+                              lpServicesReturned: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "EnumDependentServicesA".}

+  proc EnumServicesStatus*(hSCManager: SC_HANDLE, dwServiceType: DWORD,

+                           dwServiceState: DWORD,

+                           lpServices: LPENUM_SERVICE_STATUS, cbBufSize: DWORD,

+                           pcbBytesNeeded: LPDWORD, lpServicesReturned: LPDWORD,

+                           lpResumeHandle: LPDWORD): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "EnumServicesStatusA".}

+  proc GetServiceKeyName*(hSCManager: SC_HANDLE, lpDisplayName: LPCSTR,

+                          lpServiceName: LPSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "GetServiceKeyNameA".}

+  proc GetServiceDisplayName*(hSCManager: SC_HANDLE, lpServiceName: LPCSTR,

+                              lpDisplayName: LPSTR, lpcchBuffer: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "GetServiceDisplayNameA".}

+  proc OpenSCManager*(lpMachineName: LPCSTR, lpDatabaseName: LPCSTR,

+                      dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+      dynlib: "advapi32", importc: "OpenSCManagerA".}

+  proc OpenService*(hSCManager: SC_HANDLE, lpServiceName: LPCSTR,

+                    dwDesiredAccess: DWORD): SC_HANDLE{.stdcall,

+      dynlib: "advapi32", importc: "OpenServiceA".}

+  proc QueryServiceConfig*(hService: SC_HANDLE,

+                           lpServiceConfig: LPQUERY_SERVICE_CONFIG,

+                           cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "QueryServiceConfigA".}

+  proc QueryServiceLockStatus*(hSCManager: SC_HANDLE,

+                               lpLockStatus: LPQUERY_SERVICE_LOCK_STATUS,

+                               cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "QueryServiceLockStatusA".}

+  proc RegisterServiceCtrlHandler*(lpServiceName: LPCSTR,

+                                   lpHandlerProc: LPHANDLER_FUNCTION): SERVICE_STATUS_HANDLE{.

+      stdcall, dynlib: "advapi32", importc: "RegisterServiceCtrlHandlerA".}

+  proc StartServiceCtrlDispatcher*(lpServiceStartTable: LPSERVICE_TABLE_ENTRY): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "StartServiceCtrlDispatcherA".}

+  proc StartService*(hService: SC_HANDLE, dwNumServiceArgs: DWORD,

+                     lpServiceArgVectors: LPCSTR): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "StartServiceA".}

+  proc DragQueryFile*(para1: HDROP, para2: int, para3: cstring, para4: int): int{.

+      stdcall, dynlib: "shell32", importc: "DragQueryFileA".}

+  proc ExtractAssociatedIcon*(para1: HINST, para2: cstring, para3: LPWORD): HICON{.

+      stdcall, dynlib: "shell32", importc: "ExtractAssociatedIconA".}

+  proc ExtractIcon*(para1: HINST, para2: cstring, para3: int): HICON{.stdcall,

+      dynlib: "shell32", importc: "ExtractIconA".}

+  proc FindExecutable*(para1: cstring, para2: cstring, para3: cstring): HINST{.

+      stdcall, dynlib: "shell32", importc: "FindExecutableA".}

+  proc ShellAbout*(para1: HWND, para2: cstring, para3: cstring, para4: HICON): int32{.

+      stdcall, dynlib: "shell32", importc: "ShellAboutA".}

+  proc ShellExecute*(para1: HWND, para2: cstring, para3: cstring,

+                     para4: cstring, para5: cstring, para6: int32): HINST{.

+      stdcall, dynlib: "shell32", importc: "ShellExecuteA".}

+  proc Shell_NotifyIcon*(dwMessage: DWORD, lpData: PNotifyIconDataA): WINBOOL{.

+      stdcall, dynlib: "shell32", importc: "Shell_NotifyIconA".}

+  proc DdeCreateStringHandle*(para1: DWORD, para2: cstring, para3: int32): HSZ{.

+      stdcall, dynlib: "user32", importc: "DdeCreateStringHandleA".}

+  proc DdeInitialize*(para1: LPDWORD, para2: PFNCALLBACK, para3: DWORD,

+                      para4: DWORD): WINUINT{.stdcall, dynlib: "user32",

+      importc: "DdeInitializeA".}

+  proc DdeQueryString*(para1: DWORD, para2: HSZ, para3: cstring, para4: DWORD,

+                       para5: int32): DWORD{.stdcall, dynlib: "user32",

+      importc: "DdeQueryStringA".}

+  proc LogonUser*(para1: LPSTR, para2: LPSTR, para3: LPSTR, para4: DWORD,

+                  para5: DWORD, para6: PHANDLE): WINBOOL{.stdcall,

+      dynlib: "advapi32", importc: "LogonUserA".}

+  proc CreateProcessAsUser*(para1: HANDLE, para2: LPCTSTR, para3: LPTSTR,

+                            para4: LPSECURITY_ATTRIBUTES,

+                            para5: LPSECURITY_ATTRIBUTES, para6: WINBOOL,

+                            para7: DWORD, para8: LPVOID, para9: LPCTSTR,

+                            para10: LPSTARTUPINFO, para11: LPPROCESS_INFORMATION): WINBOOL{.

+      stdcall, dynlib: "advapi32", importc: "CreateProcessAsUserA".}

+proc GetRandomRgn*(aHDC: HDC, aHRGN: HRGN, iNum: WINT): WINT{.stdcall,

+     importc, dynlib: "gdi32".}

+

+proc AccessCheck*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                  ClientToken: HANDLE, DesiredAccess: DWORD,

+                  GenericMapping: PGENERIC_MAPPING,

+                  PrivilegeSet: PPRIVILEGE_SET, PrivilegeSetLength: LPDWORD,

+                  GrantedAccess: LPDWORD, AccessStatus: LPBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AccessCheck".}

+proc FreeResource*(hResData: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "FreeResource".}

+proc LockResource*(hResData: HGLOBAL): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "LockResource".}

+proc FreeLibrary*(hLibModule: HINST): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "FreeLibrary".}

+proc FreeLibraryAndExitThread*(hLibModule: HMODULE, dwExitCode: DWORD){.stdcall,

+    dynlib: "kernel32", importc: "FreeLibraryAndExitThread".}

+proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "DisableThreadLibraryCalls".}

+proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall,

+    dynlib: "kernel32", importc: "GetProcAddress".}

+proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".}

+proc GlobalAlloc*(uFlags: int32, dwBytes: SIZE_T): HGLOBAL{.stdcall,

+    dynlib: "kernel32", importc: "GlobalAlloc".}

+proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall,

+    dynlib: "kernel32", importc: "GlobalAlloc", deprecated.}

+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: SIZE_T, uFlags: int32): HGLOBAL{.

+    stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".}

+proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{.

+    stdcall, dynlib: "kernel32", importc: "GlobalReAlloc", deprecated.}

+proc GlobalSize*(hMem: HGLOBAL): SIZE_T{.stdcall, dynlib: "kernel32",

+                                        importc: "GlobalSize".}

+proc GlobalFlags*(hMem: HGLOBAL): WINUINT{.stdcall, dynlib: "kernel32",

+                                        importc: "GlobalFlags".}

+proc GlobalLock*(hMem: HGLOBAL): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "GlobalLock".}

+proc GlobalHandle*(pMem: LPCVOID): HGLOBAL{.stdcall, dynlib: "kernel32",

+    importc: "GlobalHandle".}

+proc GlobalUnlock*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "GlobalUnlock".}

+proc GlobalFree*(hMem: HGLOBAL): HGLOBAL{.stdcall, dynlib: "kernel32",

+    importc: "GlobalFree".}

+proc GlobalCompact*(dwMinFree: DWORD): WINUINT{.stdcall, dynlib: "kernel32",

+    importc: "GlobalCompact".}

+proc GlobalFix*(hMem: HGLOBAL){.stdcall, dynlib: "kernel32",

+                                importc: "GlobalFix".}

+proc GlobalUnfix*(hMem: HGLOBAL){.stdcall, dynlib: "kernel32",

+                                  importc: "GlobalUnfix".}

+proc GlobalWire*(hMem: HGLOBAL): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "GlobalWire".}

+proc GlobalUnWire*(hMem: HGLOBAL): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "GlobalUnWire".}

+proc GlobalMemoryStatus*(lpBuffer: LPMEMORYSTATUS){.stdcall, dynlib: "kernel32",

+    importc: "GlobalMemoryStatus".}

+proc LocalAlloc*(uFlags: WINUINT, uBytes: SIZE_T): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalAlloc".}

+proc LocalAlloc*(uFlags: WINUINT, uBytes: DWORD): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalAlloc", deprecated.}

+proc LocalReAlloc*(hMem: HLOCAL, uBytes: SIZE_T, uFlags: WINUINT): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalReAlloc".}

+proc LocalReAlloc*(hMem: HLOCAL, uBytes: DWORD, uFlags: WINUINT): HLOCAL{.stdcall,

+    dynlib: "kernel32", importc: "LocalReAlloc", deprecated.}

+proc LocalLock*(hMem: HLOCAL): LPVOID{.stdcall, dynlib: "kernel32",

+                                       importc: "LocalLock".}

+proc LocalHandle*(pMem: LPCVOID): HLOCAL{.stdcall, dynlib: "kernel32",

+    importc: "LocalHandle".}

+proc LocalUnlock*(hMem: HLOCAL): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "LocalUnlock".}

+proc LocalSize*(hMem: HLOCAL): WINUINT{.stdcall, dynlib: "kernel32",

+                                     importc: "LocalSize".}

+proc LocalFlags*(hMem: HLOCAL): WINUINT{.stdcall, dynlib: "kernel32",

+                                      importc: "LocalFlags".}

+proc LocalFree*(hMem: HLOCAL): HLOCAL{.stdcall, dynlib: "kernel32",

+                                       importc: "LocalFree".}

+proc LocalShrink*(hMem: HLOCAL, cbNewSize: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "LocalShrink".}

+proc LocalCompact*(uMinFree: WINUINT): WINUINT{.stdcall, dynlib: "kernel32",

+    importc: "LocalCompact".}

+proc FlushInstructionCache*(hProcess: HANDLE, lpBaseAddress: LPCVOID,

+                            dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FlushInstructionCache".}

+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD,

+                   flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "VirtualAlloc".}

+proc VirtualAlloc*(lpAddress: LPVOID, dwSize: DWORD, flAllocationType: DWORD,

+                   flProtect: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "VirtualAlloc", deprecated.}

+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                     flAllocationType: DWORD, flProtect: DWORD): LPVOID

+                     {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx".}

+proc VirtualAllocEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                     flAllocationType: DWORD, flProtect: DWORD): LPVOID

+                     {.stdcall, dynlib: "kernel32", importc: "VirtualAllocEx", 

+                       deprecated.}

+proc VirtualFree*(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualFree*(lpAddress: LPVOID, dwSize: DWORD, dwFreeType: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualFree", deprecated.}

+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                    dwFreeType: DWORD): WINBOOL

+                    {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualFreeEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                    dwFreeType: DWORD): WINBOOL

+                    {.stdcall, dynlib: "kernel32", importc: "VirtualFree".}

+proc VirtualProtect*(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD,

+                     lpflOldProtect: PDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualProtect".}

+proc VirtualProtect*(lpAddress: LPVOID, dwSize: DWORD, flNewProtect: DWORD,

+                     lpflOldProtect: PDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualProtect", deprecated.}

+proc VirtualQuery*(lpAddress: LPCVOID, lpBuffer: PMEMORY_BASIC_INFORMATION,

+                   dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "VirtualQuery".}

+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: SIZE_T,

+                       flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualProtectEx".}

+proc VirtualProtectEx*(hProcess: HANDLE, lpAddress: LPVOID, dwSize: DWORD,

+                       flNewProtect: DWORD, lpflOldProtect: PDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "VirtualProtectEx", deprecated.}

+proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,

+                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: SIZE_T): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".}

+proc VirtualQueryEx*(hProcess: HANDLE, lpAddress: LPCVOID,

+                     lpBuffer: PMEMORY_BASIC_INFORMATION, dwLength: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VirtualQueryEx", deprecated.}

+proc HeapCreate*(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "HeapCreate".}

+proc HeapCreate*(flOptions: DWORD, dwInitialSize: DWORD, dwMaximumSize: DWORD): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "HeapCreate", deprecated.}

+proc HeapDestroy*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "HeapDestroy".}

+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T): LPVOID{.stdcall,

+    dynlib: "kernel32", importc: "HeapAlloc".}

+proc HeapAlloc*(hHeap: HANDLE, dwFlags: DWORD, dwBytes: DWORD): LPVOID{.stdcall,

+    dynlib: "kernel32", importc: "HeapAlloc", deprecated.}

+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T): LPVOID{.

+    stdcall, dynlib: "kernel32", importc: "HeapReAlloc".}

+proc HeapReAlloc*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: DWORD): LPVOID{.

+    stdcall, dynlib: "kernel32", importc: "HeapReAlloc", deprecated.}

+proc HeapFree*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "HeapFree".}

+proc HeapSize*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): SIZE_T{.stdcall,

+    dynlib: "kernel32", importc: "HeapSize".}

+proc HeapValidate*(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPCVOID): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "HeapValidate".}

+proc HeapCompact*(hHeap: HANDLE, dwFlags: DWORD): SIZE_T{.stdcall,

+    dynlib: "kernel32", importc: "HeapCompact".}

+proc GetProcessHeap*(): HANDLE{.stdcall, dynlib: "kernel32",

+                                importc: "GetProcessHeap".}

+proc GetProcessHeaps*(NumberOfHeaps: DWORD, ProcessHeaps: PHANDLE): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetProcessHeaps".}

+proc HeapLock*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+                                        importc: "HeapLock".}

+proc HeapUnlock*(hHeap: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "HeapUnlock".}

+proc HeapWalk*(hHeap: HANDLE, lpEntry: LPPROCESS_HEAP_ENTRY): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "HeapWalk".}

+proc GetProcessAffinityMask*(hProcess: HANDLE, lpProcessAffinityMask: LPDWORD,

+                             lpSystemAffinityMask: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetProcessAffinityMask".}

+proc GetProcessTimes*(hProcess: HANDLE, lpCreationTime: LPFILETIME,

+                      lpExitTime: LPFILETIME, lpKernelTime: LPFILETIME,

+                      lpUserTime: LPFILETIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetProcessTimes".}

+proc GetProcessWorkingSetSize*(hProcess: HANDLE,

+                               lpMinimumWorkingSetSize: LPDWORD,

+                               lpMaximumWorkingSetSize: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetProcessWorkingSetSize".}

+proc SetProcessWorkingSetSize*(hProcess: HANDLE, dwMinimumWorkingSetSize: DWORD,

+                               dwMaximumWorkingSetSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetProcessWorkingSetSize".}

+proc OpenProcess*(dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                  dwProcessId: DWORD): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "OpenProcess".}

+proc GetCurrentProcess*(): HANDLE{.stdcall, dynlib: "kernel32",

+                                   importc: "GetCurrentProcess".}

+proc GetCurrentProcessId*(): DWORD{.stdcall, dynlib: "kernel32",

+                                    importc: "GetCurrentProcessId".}

+proc ExitProcess*(uExitCode: WINUINT){.stdcall, dynlib: "kernel32",

+                                    importc: "ExitProcess".}

+proc TerminateProcess*(hProcess: HANDLE, uExitCode: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "TerminateProcess".}

+proc SetProcessAffinityMask*(hProcess: THandle, dwProcessAffinityMask: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetProcessAffinityMask".}

+proc GetExitCodeProcess*(hProcess: HANDLE, lpExitCode: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}

+proc FatalExit*(ExitCode: int32){.stdcall, dynlib: "kernel32",

+                                  importc: "FatalExit".}

+proc RaiseException*(dwExceptionCode: DWORD, dwExceptionFlags: DWORD,

+                     nNumberOfArguments: DWORD, lpArguments: LPDWORD){.stdcall,

+    dynlib: "kernel32", importc: "RaiseException".}

+proc UnhandledExceptionFilter*(ExceptionInfo: lpemptyrecord): LONG{.stdcall,

+    dynlib: "kernel32", importc: "UnhandledExceptionFilter".}

+proc CreateRemoteThread*(hProcess: HANDLE,

+                         lpThreadAttributes: LPSECURITY_ATTRIBUTES,

+                         dwStackSize: DWORD,

+                         lpStartAddress: LPTHREAD_START_ROUTINE,

+                         lpParameter: LPVOID, dwCreationFlags: DWORD,

+                         lpThreadId: LPDWORD): HANDLE{.stdcall,

+    dynlib: "kernel32", importc: "CreateRemoteThread".}

+proc GetCurrentThread*(): HANDLE{.stdcall, dynlib: "kernel32",

+                                  importc: "GetCurrentThread".}

+proc GetCurrentThreadId*(): DWORD{.stdcall, dynlib: "kernel32",

+                                   importc: "GetCurrentThreadId".}

+proc SetThreadAffinityMask*(hThread: HANDLE, dwThreadAffinityMask: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "SetThreadAffinityMask".}

+proc SetThreadPriority*(hThread: HANDLE, nPriority: int32): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetThreadPriority".}

+proc GetThreadPriority*(hThread: HANDLE): int32{.stdcall, dynlib: "kernel32",

+    importc: "GetThreadPriority".}

+proc GetThreadTimes*(hThread: HANDLE, lpCreationTime: LPFILETIME,

+                     lpExitTime: LPFILETIME, lpKernelTime: LPFILETIME,

+                     lpUserTime: LPFILETIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetThreadTimes".}

+proc ExitThread*(dwExitCode: DWORD){.stdcall, dynlib: "kernel32",

+                                     importc: "ExitThread".}

+proc TerminateThread*(hThread: HANDLE, dwExitCode: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "TerminateThread".}

+proc GetExitCodeThread*(hThread: HANDLE, lpExitCode: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetExitCodeThread".}

+proc GetThreadSelectorEntry*(hThread: HANDLE, dwSelector: DWORD,

+                             lpSelectorEntry: LPLDT_ENTRY): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetThreadSelectorEntry".}

+proc GetLastError*(): DWORD{.stdcall, dynlib: "kernel32",

+                             importc: "GetLastError".}

+proc SetLastError*(dwErrCode: DWORD){.stdcall, dynlib: "kernel32",

+                                      importc: "SetLastError".}

+proc CreateIoCompletionPort*(FileHandle: HANDLE, ExistingCompletionPort: HANDLE,

+                             CompletionKey: DWORD,

+                             NumberOfConcurrentThreads: DWORD): HANDLE{.stdcall,

+    dynlib: "kernel32", importc: "CreateIoCompletionPort".}

+proc SetErrorMode*(uMode: WINUINT): WINUINT{.stdcall, dynlib: "kernel32",

+                                       importc: "SetErrorMode".}

+proc ReadProcessMemory*(hProcess: HANDLE, lpBaseAddress: LPCVOID,

+                        lpBuffer: LPVOID, nSize: DWORD,

+                        lpNumberOfBytesRead: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadProcessMemory".}

+proc WriteProcessMemory*(hProcess: HANDLE, lpBaseAddress: LPVOID,

+                         lpBuffer: LPVOID, nSize: DWORD,

+                         lpNumberOfBytesWritten: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteProcessMemory".}

+proc GetThreadContext*(hThread: HANDLE, lpContext: LPCONTEXT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetThreadContext".}

+proc SuspendThread*(hThread: HANDLE): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "SuspendThread".}

+proc ResumeThread*(hThread: HANDLE): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "ResumeThread".}

+proc DebugBreak*(){.stdcall, dynlib: "kernel32", importc: "DebugBreak".}

+proc WaitForDebugEvent*(lpDebugEvent: LPDEBUG_EVENT, dwMilliseconds: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WaitForDebugEvent".}

+proc ContinueDebugEvent*(dwProcessId: DWORD, dwThreadId: DWORD,

+                         dwContinueStatus: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ContinueDebugEvent".}

+proc DebugActiveProcess*(dwProcessId: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "DebugActiveProcess".}

+proc InitializeCriticalSection*(lpCriticalSection: LPCRITICAL_SECTION){.stdcall,

+    dynlib: "kernel32", importc: "InitializeCriticalSection".}

+proc EnterCriticalSection*(lpCriticalSection: LPCRITICAL_SECTION){.stdcall,

+    dynlib: "kernel32", importc: "EnterCriticalSection".}

+proc LeaveCriticalSection*(lpCriticalSection: LPCRITICAL_SECTION){.stdcall,

+    dynlib: "kernel32", importc: "LeaveCriticalSection".}

+proc DeleteCriticalSection*(lpCriticalSection: LPCRITICAL_SECTION){.stdcall,

+    dynlib: "kernel32", importc: "DeleteCriticalSection".}

+proc TryEnterCriticalSection*(lpCriticalSection: LPCRITICAL_SECTION): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "TryEnterCriticalSection".}

+proc SetEvent*(hEvent: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "SetEvent".}

+proc ResetEvent*(hEvent: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ResetEvent".}

+proc PulseEvent*(hEvent: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "PulseEvent".}

+proc ReleaseSemaphore*(hSemaphore: HANDLE, lReleaseCount: LONG,

+                       lpPreviousCount: LPLONG): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReleaseSemaphore".}

+proc ReleaseMutex*(hMutex: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ReleaseMutex".}

+proc WaitForSingleObject*(hHandle: HANDLE, dwMilliseconds: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}

+

+proc Sleep*(dwMilliseconds: DWORD){.stdcall, dynlib: "kernel32",

+                                    importc: "Sleep".}

+proc LoadResource*(hModule: HINST, hResInfo: HRSRC): HGLOBAL{.stdcall,

+    dynlib: "kernel32", importc: "LoadResource".}

+proc SizeofResource*(hModule: HINST, hResInfo: HRSRC): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "SizeofResource".}

+proc GlobalDeleteAtom*(nAtom: ATOM): ATOM{.stdcall, dynlib: "kernel32",

+    importc: "GlobalDeleteAtom".}

+proc InitAtomTable*(nSize: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "InitAtomTable".}

+proc DeleteAtom*(nAtom: ATOM): ATOM{.stdcall, dynlib: "kernel32",

+                                     importc: "DeleteAtom".}

+proc SetHandleCount*(uNumber: WINUINT): WINUINT{.stdcall, dynlib: "kernel32",

+    importc: "SetHandleCount".}

+proc GetLogicalDrives*(): DWORD{.stdcall, dynlib: "kernel32",

+                                 importc: "GetLogicalDrives".}

+proc LockFile*(hFile: HANDLE, dwFileOffsetLow: DWORD, dwFileOffsetHigh: DWORD,

+               nNumberOfBytesToLockLow: DWORD, nNumberOfBytesToLockHigh: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "LockFile".}

+proc UnlockFile*(hFile: HANDLE, dwFileOffsetLow: DWORD, dwFileOffsetHigh: DWORD,

+                 nNumberOfBytesToUnlockLow: DWORD,

+                 nNumberOfBytesToUnlockHigh: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "UnlockFile".}

+proc LockFileEx*(hFile: HANDLE, dwFlags: DWORD, dwReserved: DWORD,

+                 nNumberOfBytesToLockLow: DWORD,

+                 nNumberOfBytesToLockHigh: DWORD, lpOverlapped: LPOVERLAPPED): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "LockFileEx".}

+proc UnlockFileEx*(hFile: HANDLE, dwReserved: DWORD,

+                   nNumberOfBytesToUnlockLow: DWORD,

+                   nNumberOfBytesToUnlockHigh: DWORD, lpOverlapped: LPOVERLAPPED): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "UnlockFileEx".}

+proc GetFileInformationByHandle*(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}

+proc GetFileType*(hFile: HANDLE): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetFileType".}

+proc GetFileSize*(hFile: HANDLE, lpFileSizeHigh: LPDWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetFileSize".}

+proc GetStdHandle*(nStdHandle: DWORD): HANDLE{.stdcall, dynlib: "kernel32",

+    importc: "GetStdHandle".}

+proc SetStdHandle*(nStdHandle: DWORD, hHandle: HANDLE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetStdHandle".}

+proc FlushFileBuffers*(hFile: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "FlushFileBuffers".}

+proc DeviceIoControl*(hDevice: HANDLE, dwIoControlCode: DWORD,

+                      lpInBuffer: LPVOID, nInBufferSize: DWORD,

+                      lpOutBuffer: LPVOID, nOutBufferSize: DWORD,

+                      lpBytesReturned: LPDWORD, lpOverlapped: LPOVERLAPPED): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "DeviceIoControl".}

+proc SetEndOfFile*(hFile: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "SetEndOfFile".}

+proc SetFilePointer*(hFile: HANDLE, lDistanceToMove: LONG,

+                     lpDistanceToMoveHigh: PLONG, dwMoveMethod: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "SetFilePointer".}

+proc FindClose*(hFindFile: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "FindClose".}

+proc GetFileTime*(hFile: HANDLE, lpCreationTime: LPFILETIME,

+                  lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetFileTime".}

+proc SetFileTime*(hFile: HANDLE, lpCreationTime: LPFILETIME,

+                  lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetFileTime".}

+proc CloseHandle*(hObject: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CloseHandle".}

+proc DuplicateHandle*(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE,

+                      hTargetProcessHandle: HANDLE, lpTargetHandle: LPHANDLE,

+                      dwDesiredAccess: DWORD, bInheritHandle: WINBOOL,

+                      dwOptions: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "DuplicateHandle".}

+proc GetHandleInformation*(hObject: HANDLE, lpdwFlags: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetHandleInformation".}

+proc SetHandleInformation*(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetHandleInformation".}

+proc LoadModule*(lpModuleName: LPCSTR, lpParameterBlock: LPVOID): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "LoadModule".}

+proc WinExec*(lpCmdLine: LPCSTR, uCmdShow: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "WinExec".}

+proc ClearCommBreak*(hFile: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ClearCommBreak".}

+proc ClearCommError*(hFile: HANDLE, lpErrors: LPDWORD, lpStat: LPCOMSTAT): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ClearCommError".}

+proc SetupComm*(hFile: HANDLE, dwInQueue: DWORD, dwOutQueue: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetupComm".}

+proc EscapeCommFunction*(hFile: HANDLE, dwFunc: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "EscapeCommFunction".}

+proc GetCommConfig*(hCommDev: HANDLE, lpCC: LPCOMMCONFIG, lpdwSize: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetCommConfig".}

+proc GetCommProperties*(hFile: HANDLE, lpCommProp: LPCOMMPROP): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetCommProperties".}

+proc GetCommModemStatus*(hFile: HANDLE, lpModemStat: PDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetCommModemStatus".}

+proc GetCommState*(hFile: HANDLE, lpDCB: PDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetCommState".}

+proc GetCommTimeouts*(hFile: HANDLE, lpCommTimeouts: PCOMMTIMEOUTS): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetCommTimeouts".}

+proc PurgeComm*(hFile: HANDLE, dwFlags: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "PurgeComm".}

+proc SetCommBreak*(hFile: HANDLE): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "SetCommBreak".}

+proc SetCommConfig*(hCommDev: HANDLE, lpCC: LPCOMMCONFIG, dwSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetCommConfig".}

+proc SetCommMask*(hFile: HANDLE, dwEvtMask: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetCommMask".}

+proc SetCommState*(hFile: HANDLE, lpDCB: LPDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetCommState".}

+proc SetCommTimeouts*(hFile: HANDLE, lpCommTimeouts: LPCOMMTIMEOUTS): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetCommTimeouts".}

+proc TransmitCommChar*(hFile: HANDLE, cChar: char): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "TransmitCommChar".}

+proc WaitCommEvent*(hFile: HANDLE, lpEvtMask: LPDWORD,

+                    lpOverlapped: LPOVERLAPPED): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WaitCommEvent".}

+proc SetTapePosition*(hDevice: HANDLE, dwPositionMethod: DWORD,

+                      dwPartition: DWORD, dwOffsetLow: DWORD,

+                      dwOffsetHigh: DWORD, bImmediate: WINBOOL): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "SetTapePosition".}

+proc GetTapePosition*(hDevice: HANDLE, dwPositionType: DWORD,

+                      lpdwPartition: LPDWORD, lpdwOffsetLow: LPDWORD,

+                      lpdwOffsetHigh: LPDWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetTapePosition".}

+proc PrepareTape*(hDevice: HANDLE, dwOperation: DWORD, bImmediate: WINBOOL): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "PrepareTape".}

+proc EraseTape*(hDevice: HANDLE, dwEraseType: DWORD, bImmediate: WINBOOL): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "EraseTape".}

+proc CreateTapePartition*(hDevice: HANDLE, dwPartitionMethod: DWORD,

+                          dwCount: DWORD, dwSize: DWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "CreateTapePartition".}

+proc WriteTapemark*(hDevice: HANDLE, dwTapemarkType: DWORD,

+                    dwTapemarkCount: DWORD, bImmediate: WINBOOL): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "WriteTapemark".}

+proc GetTapeStatus*(hDevice: HANDLE): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetTapeStatus".}

+proc GetTapeParameters*(hDevice: HANDLE, dwOperation: DWORD, lpdwSize: LPDWORD,

+                        lpTapeInformation: LPVOID): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetTapeParameters".}

+proc SetTapeParameters*(hDevice: HANDLE, dwOperation: DWORD,

+                        lpTapeInformation: LPVOID): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "SetTapeParameters".}

+proc Beep*(dwFreq: DWORD, dwDuration: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "Beep".}

+proc MulDiv*(nNumber: int32, nNumerator: int32, nDenominator: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "MulDiv".}

+proc GetSystemTime*(lpSystemTime: LPSYSTEMTIME){.stdcall, dynlib: "kernel32",

+    importc: "GetSystemTime".}

+proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: LPFILETIME){.stdcall,

+    dynlib: "kernel32", importc: "GetSystemTimeAsFileTime".}

+proc SetSystemTime*(lpSystemTime: LPSYSTEMTIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetSystemTime".}

+proc GetLocalTime*(lpSystemTime: LPSYSTEMTIME){.stdcall, dynlib: "kernel32",

+    importc: "GetLocalTime".}

+proc SetLocalTime*(lpSystemTime: LPSYSTEMTIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetLocalTime".}

+proc GetSystemInfo*(lpSystemInfo: LPSYSTEM_INFO){.stdcall, dynlib: "kernel32",

+    importc: "GetSystemInfo".}

+proc SystemTimeToTzSpecificLocalTime*(lpTimeZoneInformation: LPTIME_ZONE_INFORMATION,

+                                      lpUniversalTime: LPSYSTEMTIME,

+                                      lpLocalTime: LPSYSTEMTIME): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SystemTimeToTzSpecificLocalTime".}

+proc GetTimeZoneInformation*(lpTimeZoneInformation: LPTIME_ZONE_INFORMATION): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetTimeZoneInformation".}

+proc SetTimeZoneInformation*(lpTimeZoneInformation: LPTIME_ZONE_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetTimeZoneInformation".}

+proc SystemTimeToFileTime*(lpSystemTime: LPSYSTEMTIME, lpFileTime: LPFILETIME): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SystemTimeToFileTime".}

+proc FileTimeToLocalFileTime*(FileTime: LPFILETIME,

+                              lpLocalFileTime: LPFILETIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FileTimeToLocalFileTime".}

+proc LocalFileTimeToFileTime*(lpLocalFileTime: LPFILETIME,

+                              lpFileTime: LPFILETIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "LocalFileTimeToFileTime".}

+proc FileTimeToSystemTime*(lpFileTime: LPFILETIME, lpSystemTime: LPSYSTEMTIME): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FileTimeToSystemTime".}

+proc CompareFileTime*(lpFileTime1: LPFILETIME, lpFileTime2: LPFILETIME): LONG{.

+    stdcall, dynlib: "kernel32", importc: "CompareFileTime".}

+proc FileTimeToDosDateTime*(lpFileTime: LPFILETIME, lpFatDate: LPWORD,

+                            lpFatTime: LPWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FileTimeToDosDateTime".}

+proc DosDateTimeToFileTime*(wFatDate: int16, wFatTime: int16,

+                            lpFileTime: LPFILETIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "DosDateTimeToFileTime".}

+proc GetTickCount*(): DWORD{.stdcall, dynlib: "kernel32",

+                             importc: "GetTickCount".}

+proc SetSystemTimeAdjustment*(dwTimeAdjustment: DWORD,

+                              bTimeAdjustmentDisabled: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetSystemTimeAdjustment".}

+proc GetSystemTimeAdjustment*(lpTimeAdjustment: PDWORD, lpTimeIncrement: PDWORD,

+                              lpTimeAdjustmentDisabled: PWINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetSystemTimeAdjustment".}

+proc CreatePipe*(hReadPipe: PHANDLE, hWritePipe: PHANDLE,

+                 lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreatePipe".}

+proc ConnectNamedPipe*(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ConnectNamedPipe".}

+proc DisconnectNamedPipe*(hNamedPipe: HANDLE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "DisconnectNamedPipe".}

+proc SetNamedPipeHandleState*(hNamedPipe: HANDLE, lpMode: LPDWORD,

+                              lpMaxCollectionCount: LPDWORD,

+                              lpCollectDataTimeout: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetNamedPipeHandleState".}

+proc GetNamedPipeInfo*(hNamedPipe: HANDLE, lpFlags: LPDWORD,

+                       lpOutBufferSize: LPDWORD, lpInBufferSize: LPDWORD,

+                       lpMaxInstances: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetNamedPipeInfo".}

+proc PeekNamedPipe*(hNamedPipe: HANDLE, lpBuffer: LPVOID, nBufferSize: DWORD,

+                    lpBytesRead: LPDWORD, lpTotalBytesAvail: LPDWORD,

+                    lpBytesLeftThisMessage: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "PeekNamedPipe".}

+proc TransactNamedPipe*(hNamedPipe: HANDLE, lpInBuffer: LPVOID,

+                        nInBufferSize: DWORD, lpOutBuffer: LPVOID,

+                        nOutBufferSize: DWORD, lpBytesRead: LPDWORD,

+                        lpOverlapped: LPOVERLAPPED): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "TransactNamedPipe".}

+proc GetMailslotInfo*(hMailslot: HANDLE, lpMaxMessageSize: LPDWORD,

+                      lpNextSize: LPDWORD, lpMessageCount: LPDWORD,

+                      lpReadTimeout: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetMailslotInfo".}

+proc SetMailslotInfo*(hMailslot: HANDLE, lReadTimeout: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetMailslotInfo".}

+proc MapViewOfFile*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD,

+                    dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD,

+                    dwNumberOfBytesToMap: DWORD): LPVOID{.stdcall,

+    dynlib: "kernel32", importc: "MapViewOfFile".}

+proc FlushViewOfFile*(lpBaseAddress: LPCVOID, dwNumberOfBytesToFlush: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FlushViewOfFile".}

+proc UnmapViewOfFile*(lpBaseAddress: LPVOID): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "UnmapViewOfFile".}

+proc OpenFile*(lpFileName: LPCSTR, lpReOpenBuff: LPOFSTRUCT, uStyle: WINUINT): HFILE{.

+    stdcall, dynlib: "kernel32", importc: "OpenFile".}

+proc lopen*(lpPathName: LPCSTR, iReadWrite: int32): HFILE{.stdcall,

+    dynlib: "kernel32", importc: "_lopen".}

+proc lcreat*(lpPathName: LPCSTR, iAttribute: int32): HFILE{.stdcall,

+    dynlib: "kernel32", importc: "_lcreat".}

+proc lread*(hFile: HFILE, lpBuffer: LPVOID, uBytes: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "_lread".}

+proc lwrite*(hFile: HFILE, lpBuffer: LPCSTR, uBytes: WINUINT): WINUINT{.stdcall,

+    dynlib: "kernel32", importc: "_lwrite".}

+proc hread*(hFile: HFILE, lpBuffer: LPVOID, lBytes: int32): int32{.stdcall,

+    dynlib: "kernel32", importc: "_hread".}

+proc hwrite*(hFile: HFILE, lpBuffer: LPCSTR, lBytes: int32): int32{.stdcall,

+    dynlib: "kernel32", importc: "_hwrite".}

+proc lclose*(file: HFILE): HFILE{.stdcall, dynlib: "kernel32",

+                                   importc: "_lclose".}

+proc llseek*(file: HFILE, lOffset: LONG, iOrigin: int32): LONG{.stdcall,

+    dynlib: "kernel32", importc: "_llseek".}

+proc IsTextUnicode*(lpBuffer: LPVOID, cb: int32, lpi: LPINT): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "IsTextUnicode".}

+proc TlsAlloc*(): DWORD{.stdcall, dynlib: "kernel32", importc: "TlsAlloc".}

+proc TlsGetValue*(dwTlsIndex: DWORD): LPVOID{.stdcall, dynlib: "kernel32",

+    importc: "TlsGetValue".}

+proc TlsSetValue*(dwTlsIndex: DWORD, lpTlsValue: LPVOID): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "TlsSetValue".}

+proc TlsFree*(dwTlsIndex: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "TlsFree".}

+proc SleepEx*(dwMilliseconds: DWORD, bAlertable: WINBOOL): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "SleepEx".}

+proc WaitForSingleObjectEx*(hHandle: HANDLE, dwMilliseconds: DWORD,

+                            bAlertable: WINBOOL): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "WaitForSingleObjectEx".}

+proc WaitForMultipleObjectsEx*(nCount: DWORD, lpHandles: LPHANDLE,

+                               bWaitAll: WINBOOL, dwMilliseconds: DWORD,

+                               bAlertable: WINBOOL): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "WaitForMultipleObjectsEx".}

+proc ReadFileEx*(hFile: HANDLE, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD,

+                 lpOverlapped: LPOVERLAPPED,

+                 lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadFileEx".}

+proc WriteFileEx*(hFile: HANDLE, lpBuffer: LPCVOID,

+                  nNumberOfBytesToWrite: DWORD, lpOverlapped: LPOVERLAPPED,

+                  lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteFileEx".}

+proc BackupRead*(hFile: HANDLE, lpBuffer: LPBYTE, nNumberOfBytesToRead: DWORD,

+                 lpNumberOfBytesRead: LPDWORD, bAbort: WINBOOL,

+                 bProcessSecurity: WINBOOL, lpContext: var LPVOID): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BackupRead".}

+proc BackupSeek*(hFile: HANDLE, dwLowBytesToSeek: DWORD,

+                 dwHighBytesToSeek: DWORD, lpdwLowByteSeeked: LPDWORD,

+                 lpdwHighByteSeeked: LPDWORD, lpContext: var LPVOID): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BackupSeek".}

+proc BackupWrite*(hFile: HANDLE, lpBuffer: LPBYTE, nNumberOfBytesToWrite: DWORD,

+                  lpNumberOfBytesWritten: LPDWORD, bAbort: WINBOOL,

+                  bProcessSecurity: WINBOOL, lpContext: var LPVOID): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BackupWrite".}

+proc SetProcessShutdownParameters*(dwLevel: DWORD, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetProcessShutdownParameters".}

+proc GetProcessShutdownParameters*(lpdwLevel: LPDWORD, lpdwFlags: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetProcessShutdownParameters".}

+proc SetFileApisToOEM*(){.stdcall, dynlib: "kernel32",

+                          importc: "SetFileApisToOEM".}

+proc SetFileApisToANSI*(){.stdcall, dynlib: "kernel32",

+                           importc: "SetFileApisToANSI".}

+proc AreFileApisANSI*(): WINBOOL{.stdcall, dynlib: "kernel32",

+                                  importc: "AreFileApisANSI".}

+proc CloseEventLog*(hEventLog: HANDLE): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "CloseEventLog".}

+proc DeregisterEventSource*(hEventLog: HANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "DeregisterEventSource".}

+proc NotifyChangeEventLog*(hEventLog: HANDLE, hEvent: HANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "NotifyChangeEventLog".}

+proc GetNumberOfEventLogRecords*(hEventLog: HANDLE, NumberOfRecords: PDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetNumberOfEventLogRecords".}

+proc GetOldestEventLogRecord*(hEventLog: HANDLE, OldestRecord: PDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetOldestEventLogRecord".}

+proc DuplicateToken*(ExistingTokenHandle: HANDLE,

+                     ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL,

+                     DuplicateTokenHandle: PHANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "DuplicateToken".}

+proc GetKernelObjectSecurity*(Handle: HANDLE,

+                              RequestedInformation: SECURITY_INFORMATION,

+                              pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                              nLength: DWORD, lpnLengthNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetKernelObjectSecurity".}

+proc ImpersonateNamedPipeClient*(hNamedPipe: HANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ImpersonateNamedPipeClient".}

+proc ImpersonateLoggedOnUser*(hToken: HANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ImpersonateLoggedOnUser".}

+proc ImpersonateSelf*(ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ImpersonateSelf".}

+proc RevertToSelf*(): WINBOOL{.stdcall, dynlib: "advapi32",

+                               importc: "RevertToSelf".}

+proc SetThreadToken*(Thread: PHANDLE, Token: HANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "SetThreadToken".}

+proc OpenProcessToken*(ProcessHandle: HANDLE, DesiredAccess: DWORD,

+                       TokenHandle: PHANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "OpenProcessToken".}

+proc OpenThreadToken*(ThreadHandle: HANDLE, DesiredAccess: DWORD,

+                      OpenAsSelf: WINBOOL, TokenHandle: PHANDLE): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "OpenThreadToken".}

+proc GetTokenInformation*(TokenHandle: HANDLE,

+                          TokenInformationClass: TOKEN_INFORMATION_CLASS,

+                          TokenInformation: LPVOID,

+                          TokenInformationLength: DWORD, ReturnLength: PDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetTokenInformation".}

+proc SetTokenInformation*(TokenHandle: HANDLE,

+                          TokenInformationClass: TOKEN_INFORMATION_CLASS,

+                          TokenInformation: LPVOID,

+                          TokenInformationLength: DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "SetTokenInformation".}

+proc AdjustTokenPrivileges*(TokenHandle: HANDLE, DisableAllPrivileges: WINBOOL,

+                            NewState: PTOKEN_PRIVILEGES, BufferLength: DWORD,

+                            PreviousState: PTOKEN_PRIVILEGES,

+                            ReturnLength: PDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AdjustTokenPrivileges".}

+proc AdjustTokenGroups*(TokenHandle: HANDLE, ResetToDefault: WINBOOL,

+                        NewState: PTOKEN_GROUPS, BufferLength: DWORD,

+                        PreviousState: PTOKEN_GROUPS, ReturnLength: PDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AdjustTokenGroups".}

+proc PrivilegeCheck*(ClientToken: HANDLE, RequiredPrivileges: PPRIVILEGE_SET,

+                     pfResult: LPBOOL): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "PrivilegeCheck".}

+proc IsValidSid*(pSid: PSID): WINBOOL{.stdcall, dynlib: "advapi32",

+                                       importc: "IsValidSid".}

+proc EqualSid*(pSid1: PSID, pSid2: PSID): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "EqualSid".}

+proc EqualPrefixSid*(pSid1: PSID, pSid2: PSID): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "EqualPrefixSid".}

+proc GetSidLengthRequired*(nSubAuthorityCount: UCHAR): DWORD{.stdcall,

+    dynlib: "advapi32", importc: "GetSidLengthRequired".}

+proc AllocateAndInitializeSid*(pIdentifierAuthority: PSID_IDENTIFIER_AUTHORITY,

+                               nSubAuthorityCount: int8, nSubAuthority0: DWORD,

+                               nSubAuthority1: DWORD, nSubAuthority2: DWORD,

+                               nSubAuthority3: DWORD, nSubAuthority4: DWORD,

+                               nSubAuthority5: DWORD, nSubAuthority6: DWORD,

+                               nSubAuthority7: DWORD, pSid: var PSID): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AllocateAndInitializeSid".}

+proc FreeSid*(pSid: PSID): PVOID{.stdcall, dynlib: "advapi32",

+                                  importc: "FreeSid".}

+proc InitializeSid*(Sid: PSID, pIdentifierAuthority: PSID_IDENTIFIER_AUTHORITY,

+                    nSubAuthorityCount: int8): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "InitializeSid".}

+proc GetSidIdentifierAuthority*(pSid: PSID): PSID_IDENTIFIER_AUTHORITY{.stdcall,

+    dynlib: "advapi32", importc: "GetSidIdentifierAuthority".}

+proc GetSidSubAuthority*(pSid: PSID, nSubAuthority: DWORD): PDWORD{.stdcall,

+    dynlib: "advapi32", importc: "GetSidSubAuthority".}

+proc GetSidSubAuthorityCount*(pSid: PSID): PUCHAR{.stdcall, dynlib: "advapi32",

+    importc: "GetSidSubAuthorityCount".}

+proc GetLengthSid*(pSid: PSID): DWORD{.stdcall, dynlib: "advapi32",

+                                       importc: "GetLengthSid".}

+proc CopySid*(nDestinationSidLength: DWORD, pDestinationSid: PSID,

+              pSourceSid: PSID): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "CopySid".}

+proc AreAllAccessesGranted*(GrantedAccess: DWORD, DesiredAccess: DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AreAllAccessesGranted".}

+proc AreAnyAccessesGranted*(GrantedAccess: DWORD, DesiredAccess: DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "AreAnyAccessesGranted".}

+proc MapGenericMask*(AccessMask: PDWORD, GenericMapping: PGENERIC_MAPPING){.

+    stdcall, dynlib: "advapi32", importc: "MapGenericMask".}

+proc IsValidAcl*(pAcl: PACL): WINBOOL{.stdcall, dynlib: "advapi32",

+                                       importc: "IsValidAcl".}

+proc InitializeAcl*(pAcl: PACL, nAclLength: DWORD, dwAclRevision: DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "InitializeAcl".}

+proc GetAclInformation*(pAcl: PACL, pAclInformation: LPVOID,

+                        nAclInformationLength: DWORD,

+                        dwAclInformationClass: ACL_INFORMATION_CLASS): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetAclInformation".}

+proc SetAclInformation*(pAcl: PACL, pAclInformation: LPVOID,

+                        nAclInformationLength: DWORD,

+                        dwAclInformationClass: ACL_INFORMATION_CLASS): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetAclInformation".}

+proc AddAce*(pAcl: PACL, dwAceRevision: DWORD, dwStartingAceIndex: DWORD,

+             pAceList: LPVOID, nAceListLength: DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AddAce".}

+proc DeleteAce*(pAcl: PACL, dwAceIndex: DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "DeleteAce".}

+proc GetAce*(pAcl: PACL, dwAceIndex: DWORD, pAce: var LPVOID): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetAce".}

+proc AddAccessAllowedAce*(pAcl: PACL, dwAceRevision: DWORD, AccessMask: DWORD,

+                          pSid: PSID): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "AddAccessAllowedAce".}

+proc AddAccessDeniedAce*(pAcl: PACL, dwAceRevision: DWORD, AccessMask: DWORD,

+                         pSid: PSID): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "AddAccessDeniedAce".}

+proc AddAuditAccessAce*(pAcl: PACL, dwAceRevision: DWORD, dwAccessMask: DWORD,

+                        pSid: PSID, bAuditSuccess: WINBOOL,

+                        bAuditFailure: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AddAuditAccessAce".}

+proc FindFirstFreeAce*(pAcl: PACL, pAce: var LPVOID): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "FindFirstFreeAce".}

+proc InitializeSecurityDescriptor*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                   dwRevision: DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "InitializeSecurityDescriptor".}

+proc IsValidSecurityDescriptor*(pSecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "IsValidSecurityDescriptor".}

+proc GetSecurityDescriptorLength*(pSecurityDescriptor: PSECURITY_DESCRIPTOR): DWORD{.

+    stdcall, dynlib: "advapi32", importc: "GetSecurityDescriptorLength".}

+proc GetSecurityDescriptorControl*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                   pControl: PSECURITY_DESCRIPTOR_CONTROL,

+                                   lpdwRevision: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetSecurityDescriptorControl".}

+proc SetSecurityDescriptorDacl*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                bDaclPresent: WINBOOL, pDacl: PACL,

+                                bDaclDefaulted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "SetSecurityDescriptorDacl".}

+proc GetSecurityDescriptorDacl*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                lpbDaclPresent: LPBOOL, pDacl: var PACL,

+                                lpbDaclDefaulted: LPBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetSecurityDescriptorDacl".}

+proc SetSecurityDescriptorSacl*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                bSaclPresent: WINBOOL, pSacl: PACL,

+                                bSaclDefaulted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "SetSecurityDescriptorSacl".}

+proc GetSecurityDescriptorSacl*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                lpbSaclPresent: LPBOOL, pSacl: var PACL,

+                                lpbSaclDefaulted: LPBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetSecurityDescriptorSacl".}

+proc SetSecurityDescriptorOwner*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 pOwner: PSID, bOwnerDefaulted: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetSecurityDescriptorOwner".}

+proc GetSecurityDescriptorOwner*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 pOwner: var PSID, lpbOwnerDefaulted: LPBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetSecurityDescriptorOwner".}

+proc SetSecurityDescriptorGroup*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 pGroup: PSID, bGroupDefaulted: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetSecurityDescriptorGroup".}

+proc GetSecurityDescriptorGroup*(pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 pGroup: var PSID, lpbGroupDefaulted: LPBOOL): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetSecurityDescriptorGroup".}

+proc CreatePrivateObjectSecurity*(ParentDescriptor: PSECURITY_DESCRIPTOR,

+                                  CreatorDescriptor: PSECURITY_DESCRIPTOR,

+                                  NewDescriptor: var PSECURITY_DESCRIPTOR,

+                                  IsDirectoryObject: WINBOOL, Token: HANDLE,

+                                  GenericMapping: PGENERIC_MAPPING): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "CreatePrivateObjectSecurity".}

+proc SetPrivateObjectSecurity*(SecurityInformation: SECURITY_INFORMATION,

+                               ModificationDescriptor: PSECURITY_DESCRIPTOR,

+    ObjectsSecurityDescriptor: var PSECURITY_DESCRIPTOR,

+                               GenericMapping: PGENERIC_MAPPING, Token: HANDLE): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetPrivateObjectSecurity".}

+proc GetPrivateObjectSecurity*(ObjectDescriptor: PSECURITY_DESCRIPTOR,

+                               SecurityInformation: SECURITY_INFORMATION,

+                               ResultantDescriptor: PSECURITY_DESCRIPTOR,

+                               DescriptorLength: DWORD, ReturnLength: PDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "GetPrivateObjectSecurity".}

+proc DestroyPrivateObjectSecurity*(ObjectDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "DestroyPrivateObjectSecurity".}

+proc MakeSelfRelativeSD*(pAbsoluteSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                         pSelfRelativeSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                         lpdwBufferLength: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "MakeSelfRelativeSD".}

+proc MakeAbsoluteSD*(pSelfRelativeSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                     pAbsoluteSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                     lpdwAbsoluteSecurityDescriptorSize: LPDWORD, pDacl: PACL,

+                     lpdwDaclSize: LPDWORD, pSacl: PACL, lpdwSaclSize: LPDWORD,

+                     pOwner: PSID, lpdwOwnerSize: LPDWORD, pPrimaryGroup: PSID,

+                     lpdwPrimaryGroupSize: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "MakeAbsoluteSD".}

+proc SetKernelObjectSecurity*(Handle: HANDLE,

+                              SecurityInformation: SECURITY_INFORMATION,

+                              SecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetKernelObjectSecurity".}

+proc FindNextChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FindNextChangeNotification".}

+proc FindCloseChangeNotification*(hChangeHandle: HANDLE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FindCloseChangeNotification".}

+proc VirtualLock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualLock".}

+proc VirtualLock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualLock", deprecated.}

+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: SIZE_T): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualUnlock".}

+proc VirtualUnlock*(lpAddress: LPVOID, dwSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "VirtualUnlock", deprecated.}

+proc MapViewOfFileEx*(hFileMappingObject: HANDLE, dwDesiredAccess: DWORD,

+                      dwFileOffsetHigh: DWORD, dwFileOffsetLow: DWORD,

+                      dwNumberOfBytesToMap: DWORD, lpBaseAddress: LPVOID): LPVOID{.

+    stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}

+proc SetPriorityClass*(hProcess: HANDLE, dwPriorityClass: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetPriorityClass".}

+proc GetPriorityClass*(hProcess: HANDLE): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "GetPriorityClass".}

+proc IsBadReadPtr*(lp: pointer, ucb: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsBadReadPtr".}

+proc IsBadWritePtr*(lp: LPVOID, ucb: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsBadWritePtr".}

+proc IsBadHugeReadPtr*(lp: pointer, ucb: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsBadHugeReadPtr".}

+proc IsBadHugeWritePtr*(lp: LPVOID, ucb: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsBadHugeWritePtr".}

+proc IsBadCodePtr*(lpfn: FARPROC): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "IsBadCodePtr".}

+proc AllocateLocallyUniqueId*(Luid: PLUID): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AllocateLocallyUniqueId".}

+proc QueryPerformanceCounter*(lpPerformanceCount: PLARGE_INTEGER): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "QueryPerformanceCounter".}

+proc QueryPerformanceFrequency*(lpFrequency: PLARGE_INTEGER): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "QueryPerformanceFrequency".}

+proc ActivateKeyboardLayout*(hkl: HKL, Flags: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ActivateKeyboardLayout".}

+proc UnloadKeyboardLayout*(hkl: HKL): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "UnloadKeyboardLayout".}

+proc GetKeyboardLayoutList*(nBuff: int32, lpList: var HKL): int32{.stdcall,

+    dynlib: "user32", importc: "GetKeyboardLayoutList".}

+proc GetKeyboardLayout*(dwLayout: DWORD): HKL{.stdcall, dynlib: "user32",

+    importc: "GetKeyboardLayout".}

+proc OpenInputDesktop*(dwFlags: DWORD, fInherit: WINBOOL, dwDesiredAccess: DWORD): HDESK{.

+    stdcall, dynlib: "user32", importc: "OpenInputDesktop".}

+proc EnumDesktopWindows*(hDesktop: HDESK, lpfn: ENUMWINDOWSPROC, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnumDesktopWindows".}

+proc SwitchDesktop*(hDesktop: HDESK): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SwitchDesktop".}

+proc SetThreadDesktop*(hDesktop: HDESK): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetThreadDesktop".}

+proc CloseDesktop*(hDesktop: HDESK): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "CloseDesktop".}

+proc GetThreadDesktop*(dwThreadId: DWORD): HDESK{.stdcall, dynlib: "user32",

+    importc: "GetThreadDesktop".}

+proc CloseWindowStation*(hWinSta: HWINSTA): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "CloseWindowStation".}

+proc SetProcessWindowStation*(hWinSta: HWINSTA): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetProcessWindowStation".}

+proc GetProcessWindowStation*(): HWINSTA{.stdcall, dynlib: "user32",

+    importc: "GetProcessWindowStation".}

+proc SetUserObjectSecurity*(hObj: HANDLE, pSIRequested: PSECURITY_INFORMATION,

+                            pSID: PSECURITY_DESCRIPTOR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetUserObjectSecurity".}

+proc GetUserObjectSecurity*(hObj: HANDLE, pSIRequested: PSECURITY_INFORMATION,

+                            pSID: PSECURITY_DESCRIPTOR, nLength: DWORD,

+                            lpnLengthNeeded: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetUserObjectSecurity".}

+proc TranslateMessage*(lpMsg: LPMSG): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "TranslateMessage".}

+proc SetMessageQueue*(cMessagesMax: int32): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetMessageQueue".}

+proc RegisterHotKey*(wnd: HWND, anID: int32, fsModifiers: WINUINT, vk: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "RegisterHotKey".}

+proc UnregisterHotKey*(wnd: HWND, anID: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "UnregisterHotKey".}

+proc ExitWindowsEx*(uFlags: WINUINT, dwReserved: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ExitWindowsEx".}

+proc SwapMouseButton*(fSwap: WINBOOL): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SwapMouseButton".}

+proc GetMessagePos*(): DWORD{.stdcall, dynlib: "user32",

+                              importc: "GetMessagePos".}

+proc GetMessageTime*(): LONG{.stdcall, dynlib: "user32",

+                              importc: "GetMessageTime".}

+proc GetMessageExtraInfo*(): LONG{.stdcall, dynlib: "user32",

+                                   importc: "GetMessageExtraInfo".}

+proc SetMessageExtraInfo*(lp: LPARAM): LPARAM{.stdcall, dynlib: "user32",

+    importc: "SetMessageExtraInfo".}

+proc BroadcastSystemMessage*(para1: DWORD, para2: LPDWORD, para3: WINUINT,

+                             para4: WPARAM, para5: LPARAM): int32{.stdcall,

+    dynlib: "user32", importc: "BroadcastSystemMessage".}

+proc AttachThreadInput*(idAttach: DWORD, idAttachTo: DWORD, fAttach: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "AttachThreadInput".}

+proc ReplyMessage*(lResult: LRESULT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ReplyMessage".}

+proc WaitMessage*(): WINBOOL{.stdcall, dynlib: "user32", importc: "WaitMessage".}

+proc WaitForInputIdle*(hProcess: HANDLE, dwMilliseconds: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "WaitForInputIdle".}

+proc PostQuitMessage*(nExitCode: int32){.stdcall, dynlib: "user32",

+    importc: "PostQuitMessage".}

+proc InSendMessage*(): WINBOOL{.stdcall, dynlib: "user32",

+                                importc: "InSendMessage".}

+proc GetDoubleClickTime*(): WINUINT{.stdcall, dynlib: "user32",

+                                  importc: "GetDoubleClickTime".}

+proc SetDoubleClickTime*(para1: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetDoubleClickTime".}

+proc IsWindow*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                     importc: "IsWindow".}

+proc IsMenu*(menu: HMENU): WINBOOL{.stdcall, dynlib: "user32",

+                                     importc: "IsMenu".}

+proc IsChild*(hWndParent: HWND, wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsChild".}

+proc DestroyWindow*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DestroyWindow".}

+proc ShowWindow*(wnd: HWND, nCmdShow: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ShowWindow".}

+proc ShowWindowAsync*(wnd: HWND, nCmdShow: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ShowWindowAsync".}

+proc FlashWindow*(wnd: HWND, bInvert: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "FlashWindow".}

+proc ShowOwnedPopups*(wnd: HWND, fShow: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ShowOwnedPopups".}

+proc OpenIcon*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                     importc: "OpenIcon".}

+proc CloseWindow*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "CloseWindow".}

+proc MoveWindow*(wnd: HWND, X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                 bRepaint: WINBOOL): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "MoveWindow".}

+proc SetWindowPos*(wnd: HWND, hWndInsertAfter: HWND, X: int32, Y: int32,

+                   cx: int32, cy: int32, uFlags: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetWindowPos".}

+proc GetWindowPlacement*(wnd: HWND, lpwndpl: var WINDOWPLACEMENT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetWindowPlacement".}

+proc SetWindowPlacement*(wnd: HWND, lpwndpl: var WINDOWPLACEMENT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetWindowPlacement".}

+proc GetWindowPlacement*(wnd: HWND, lpwndpl: PWINDOWPLACEMENT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetWindowPlacement".}

+proc SetWindowPlacement*(wnd: HWND, lpwndpl: PWINDOWPLACEMENT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetWindowPlacement".}

+proc BeginDeferWindowPos*(nNumWindows: int32): HDWP{.stdcall, dynlib: "user32",

+    importc: "BeginDeferWindowPos".}

+proc DeferWindowPos*(hWinPosInfo: HDWP, wnd: HWND, hWndInsertAfter: HWND,

+                     x: int32, y: int32, cx: int32, cy: int32, uFlags: WINUINT): HDWP{.

+    stdcall, dynlib: "user32", importc: "DeferWindowPos".}

+proc EndDeferWindowPos*(hWinPosInfo: HDWP): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "EndDeferWindowPos".}

+proc IsWindowVisible*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsWindowVisible".}

+proc IsIconic*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                     importc: "IsIconic".}

+proc AnyPopup*(): WINBOOL{.stdcall, dynlib: "user32", importc: "AnyPopup".}

+proc BringWindowToTop*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "BringWindowToTop".}

+proc IsZoomed*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                     importc: "IsZoomed".}

+proc EndDialog*(hDlg: HWND, nResult: int32): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "EndDialog".}

+proc GetDlgItem*(hDlg: HWND, nIDDlgItem: int32): HWND{.stdcall,

+    dynlib: "user32", importc: "GetDlgItem".}

+proc SetDlgItemInt*(hDlg: HWND, nIDDlgItem: int32, uValue: WINUINT,

+                    bSigned: WINBOOL): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetDlgItemInt".}

+proc GetDlgItemInt*(hDlg: HWND, nIDDlgItem: int32, lpTranslated: var WINBOOL,

+                    bSigned: WINBOOL): WINUINT{.stdcall, dynlib: "user32",

+    importc: "GetDlgItemInt".}

+proc CheckDlgButton*(hDlg: HWND, nIDButton: int32, uCheck: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "CheckDlgButton".}

+proc CheckRadioButton*(hDlg: HWND, nIDFirstButton: int32, nIDLastButton: int32,

+                       nIDCheckButton: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CheckRadioButton".}

+proc IsDlgButtonChecked*(hDlg: HWND, nIDButton: int32): WINUINT{.stdcall,

+    dynlib: "user32", importc: "IsDlgButtonChecked".}

+proc GetNextDlgGroupItem*(hDlg: HWND, hCtl: HWND, bPrevious: WINBOOL): HWND{.

+    stdcall, dynlib: "user32", importc: "GetNextDlgGroupItem".}

+proc GetNextDlgTabItem*(hDlg: HWND, hCtl: HWND, bPrevious: WINBOOL): HWND{.

+    stdcall, dynlib: "user32", importc: "GetNextDlgTabItem".}

+proc GetDlgCtrlID*(wnd: HWND): int32{.stdcall, dynlib: "user32",

+                                       importc: "GetDlgCtrlID".}

+proc GetDialogBaseUnits*(): int32{.stdcall, dynlib: "user32",

+                                   importc: "GetDialogBaseUnits".}

+proc OpenClipboard*(hWndNewOwner: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "OpenClipboard".}

+proc CloseClipboard*(): WINBOOL{.stdcall, dynlib: "user32",

+                                 importc: "CloseClipboard".}

+proc GetClipboardOwner*(): HWND{.stdcall, dynlib: "user32",

+                                 importc: "GetClipboardOwner".}

+proc SetClipboardViewer*(hWndNewViewer: HWND): HWND{.stdcall, dynlib: "user32",

+    importc: "SetClipboardViewer".}

+proc GetClipboardViewer*(): HWND{.stdcall, dynlib: "user32",

+                                  importc: "GetClipboardViewer".}

+proc ChangeClipboardChain*(hWndRemove: HWND, hWndNewNext: HWND): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "ChangeClipboardChain".}

+proc SetClipboardData*(uFormat: WINUINT, hMem: HANDLE): HANDLE{.stdcall,

+    dynlib: "user32", importc: "SetClipboardData".}

+proc GetClipboardData*(uFormat: WINUINT): HANDLE{.stdcall, dynlib: "user32",

+    importc: "GetClipboardData".}

+proc CountClipboardFormats*(): int32{.stdcall, dynlib: "user32",

+                                      importc: "CountClipboardFormats".}

+proc EnumClipboardFormats*(format: WINUINT): WINUINT{.stdcall, dynlib: "user32",

+    importc: "EnumClipboardFormats".}

+proc EmptyClipboard*(): WINBOOL{.stdcall, dynlib: "user32",

+                                 importc: "EmptyClipboard".}

+proc IsClipboardFormatAvailable*(format: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "IsClipboardFormatAvailable".}

+proc GetPriorityClipboardFormat*(paFormatPriorityList: var WINUINT, cFormats: int32): int32{.

+    stdcall, dynlib: "user32", importc: "GetPriorityClipboardFormat".}

+proc GetOpenClipboardWindow*(): HWND{.stdcall, dynlib: "user32",

+                                      importc: "GetOpenClipboardWindow".}

+proc CharNextExA*(CodePage: int16, lpCurrentChar: LPCSTR, dwFlags: DWORD): LPSTR{.

+    stdcall, dynlib: "user32", importc: "CharNextExA".}

+proc CharPrevExA*(CodePage: int16, lpStart: LPCSTR, lpCurrentChar: LPCSTR,

+                  dwFlags: DWORD): LPSTR{.stdcall, dynlib: "user32",

+    importc: "CharPrevExA".}

+proc SetFocus*(wnd: HWND): HWND{.stdcall, dynlib: "user32", importc: "SetFocus".}

+proc GetActiveWindow*(): HWND{.stdcall, dynlib: "user32",

+                               importc: "GetActiveWindow".}

+proc GetFocus*(): HWND{.stdcall, dynlib: "user32", importc: "GetFocus".}

+proc GetKBCodePage*(): WINUINT{.stdcall, dynlib: "user32", importc: "GetKBCodePage".}

+proc GetKeyState*(nVirtKey: int32): SHORT{.stdcall, dynlib: "user32",

+    importc: "GetKeyState".}

+proc GetAsyncKeyState*(vKey: int32): SHORT{.stdcall, dynlib: "user32",

+    importc: "GetAsyncKeyState".}

+proc GetKeyboardState*(lpKeyState: PBYTE): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetKeyboardState".}

+proc SetKeyboardState*(lpKeyState: LPBYTE): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetKeyboardState".}

+proc GetKeyboardType*(nTypeFlag: int32): int32{.stdcall, dynlib: "user32",

+    importc: "GetKeyboardType".}

+proc ToAscii*(uVirtKey: WINUINT, uScanCode: WINUINT, lpKeyState: PBYTE,

+              lpChar: LPWORD, uFlags: WINUINT): int32{.stdcall, dynlib: "user32",

+    importc: "ToAscii".}

+proc ToAsciiEx*(uVirtKey: WINUINT, uScanCode: WINUINT, lpKeyState: PBYTE,

+                lpChar: LPWORD, uFlags: WINUINT, dwhkl: HKL): int32{.stdcall,

+    dynlib: "user32", importc: "ToAsciiEx".}

+proc ToUnicode*(wVirtKey: WINUINT, wScanCode: WINUINT, lpKeyState: PBYTE,

+                pwszBuff: LPWSTR, cchBuff: int32, wFlags: WINUINT): int32{.stdcall,

+    dynlib: "user32", importc: "ToUnicode".}

+proc OemKeyScan*(wOemChar: int16): DWORD{.stdcall, dynlib: "user32",

+    importc: "OemKeyScan".}

+proc keybd_event*(bVk: int8, bScan: int8, dwFlags: DWORD, dwExtraInfo: DWORD){.

+    stdcall, dynlib: "user32", importc: "keybd_event".}

+proc mouse_event*(dwFlags: DWORD, dx: DWORD, dy: DWORD, cButtons: DWORD,

+                  dwExtraInfo: DWORD){.stdcall, dynlib: "user32",

+                                       importc: "mouse_event".}

+proc GetInputState*(): WINBOOL{.stdcall, dynlib: "user32",

+                                importc: "GetInputState".}

+proc GetQueueStatus*(flags: WINUINT): DWORD{.stdcall, dynlib: "user32",

+    importc: "GetQueueStatus".}

+proc GetCapture*(): HWND{.stdcall, dynlib: "user32", importc: "GetCapture".}

+proc SetCapture*(wnd: HWND): HWND{.stdcall, dynlib: "user32",

+                                    importc: "SetCapture".}

+proc ReleaseCapture*(): WINBOOL{.stdcall, dynlib: "user32",

+                                 importc: "ReleaseCapture".}

+proc MsgWaitForMultipleObjects*(nCount: DWORD, pHandles: LPHANDLE,

+                                fWaitAll: WINBOOL, dwMilliseconds: DWORD,

+                                dwWakeMask: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "MsgWaitForMultipleObjects".}

+proc SetTimer*(wnd: HWND, nIDEvent: WINUINT, uElapse: WINUINT, lpTimerFunc: TIMERPROC): WINUINT{.

+    stdcall, dynlib: "user32", importc: "SetTimer".}

+proc KillTimer*(wnd: HWND, uIDEvent: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "KillTimer".}

+proc IsWindowUnicode*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsWindowUnicode".}

+proc EnableWindow*(wnd: HWND, bEnable: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EnableWindow".}

+proc IsWindowEnabled*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsWindowEnabled".}

+proc DestroyAcceleratorTable*(hAccel: HACCEL): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DestroyAcceleratorTable".}

+proc GetSystemMetrics*(nIndex: int32): int32{.stdcall, dynlib: "user32",

+    importc: "GetSystemMetrics".}

+proc GetMenu*(wnd: HWND): HMENU{.stdcall, dynlib: "user32", importc: "GetMenu".}

+proc SetMenu*(wnd: HWND, menu: HMENU): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetMenu".}

+proc HiliteMenuItem*(wnd: HWND, menu: HMENU, uIDHiliteItem: WINUINT,

+                     uHilite: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "HiliteMenuItem".}

+proc GetMenuState*(menu: HMENU, uId: WINUINT, uFlags: WINUINT): WINUINT{.stdcall,

+    dynlib: "user32", importc: "GetMenuState".}

+proc DrawMenuBar*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "DrawMenuBar".}

+proc GetSystemMenu*(wnd: HWND, bRevert: WINBOOL): HMENU{.stdcall,

+    dynlib: "user32", importc: "GetSystemMenu".}

+proc CreateMenu*(): HMENU{.stdcall, dynlib: "user32", importc: "CreateMenu".}

+proc CreatePopupMenu*(): HMENU{.stdcall, dynlib: "user32",

+                                importc: "CreatePopupMenu".}

+proc DestroyMenu*(menu: HMENU): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DestroyMenu".}

+proc CheckMenuItem*(menu: HMENU, uIDCheckItem: WINUINT, uCheck: WINUINT): DWORD{.

+    stdcall, dynlib: "user32", importc: "CheckMenuItem".}

+proc EnableMenuItem*(menu: HMENU, uIDEnableItem: WINUINT, uEnable: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnableMenuItem".}

+proc GetSubMenu*(menu: HMENU, nPos: int32): HMENU{.stdcall, dynlib: "user32",

+    importc: "GetSubMenu".}

+proc GetMenuItemID*(menu: HMENU, nPos: int32): WINUINT{.stdcall, dynlib: "user32",

+    importc: "GetMenuItemID".}

+proc GetMenuItemCount*(menu: HMENU): int32{.stdcall, dynlib: "user32",

+    importc: "GetMenuItemCount".}

+proc RemoveMenu*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "RemoveMenu".}

+proc DeleteMenu*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DeleteMenu".}

+proc SetMenuItemBitmaps*(menu: HMENU, uPosition: WINUINT, uFlags: WINUINT,

+                         hBitmapUnchecked: HBITMAP, hBitmapChecked: HBITMAP): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetMenuItemBitmaps".}

+proc GetMenuCheckMarkDimensions*(): LONG{.stdcall, dynlib: "user32",

+    importc: "GetMenuCheckMarkDimensions".}

+proc TrackPopupMenu*(menu: HMENU, uFlags: WINUINT, x: int32, y: int32,

+                     nReserved: int32, wnd: HWND, prcRect: var RECT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "TrackPopupMenu".}

+proc GetMenuDefaultItem*(menu: HMENU, fByPos: WINUINT, gmdiFlags: WINUINT): WINUINT{.

+    stdcall, dynlib: "user32", importc: "GetMenuDefaultItem".}

+proc SetMenuDefaultItem*(menu: HMENU, uItem: WINUINT, fByPos: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetMenuDefaultItem".}

+proc GetMenuItemRect*(wnd: HWND, menu: HMENU, uItem: WINUINT, lprcItem: LPRECT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetMenuItemRect".}

+proc MenuItemFromPoint*(wnd: HWND, menu: HMENU, ptScreen: POINT): int32{.

+    stdcall, dynlib: "user32", importc: "MenuItemFromPoint".}

+proc DragObject*(para1: HWND, para2: HWND, para3: WINUINT, para4: DWORD,

+                 para5: HCURSOR): DWORD{.stdcall, dynlib: "user32",

+    importc: "DragObject".}

+proc DragDetect*(wnd: HWND, pt: POINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DragDetect".}

+proc DrawIcon*(hDC: HDC, X: int32, Y: int32, icon: HICON): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DrawIcon".}

+proc UpdateWindow*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "UpdateWindow".}

+proc SetActiveWindow*(wnd: HWND): HWND{.stdcall, dynlib: "user32",

+    importc: "SetActiveWindow".}

+proc GetForegroundWindow*(): HWND{.stdcall, dynlib: "user32",

+                                   importc: "GetForegroundWindow".}

+proc PaintDesktop*(hdc: HDC): WINBOOL{.stdcall, dynlib: "user32",

+                                       importc: "PaintDesktop".}

+proc SetForegroundWindow*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetForegroundWindow".}

+proc WindowFromDC*(hDC: HDC): HWND{.stdcall, dynlib: "user32",

+                                    importc: "WindowFromDC".}

+proc GetDC*(wnd: HWND): HDC{.stdcall, dynlib: "user32", importc: "GetDC".}

+proc GetDCEx*(wnd: HWND, hrgnClip: HRGN, flags: DWORD): HDC{.stdcall,

+    dynlib: "user32", importc: "GetDCEx".}

+proc GetWindowDC*(wnd: HWND): HDC{.stdcall, dynlib: "user32",

+                                    importc: "GetWindowDC".}

+proc ReleaseDC*(wnd: HWND, hDC: HDC): int32{.stdcall, dynlib: "user32",

+    importc: "ReleaseDC".}

+proc BeginPaint*(wnd: HWND, lpPaint: LPPAINTSTRUCT): HDC{.stdcall,

+    dynlib: "user32", importc: "BeginPaint".}

+proc EndPaint*(wnd: HWND, lpPaint: LPPAINTSTRUCT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EndPaint".}

+proc GetUpdateRect*(wnd: HWND, lpRect: LPRECT, bErase: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUpdateRect".}

+proc GetUpdateRgn*(wnd: HWND, hRgn: HRGN, bErase: WINBOOL): int32{.stdcall,

+    dynlib: "user32", importc: "GetUpdateRgn".}

+proc SetWindowRgn*(wnd: HWND, hRgn: HRGN, bRedraw: WINBOOL): int32{.stdcall,

+    dynlib: "user32", importc: "SetWindowRgn".}

+proc GetWindowRgn*(wnd: HWND, hRgn: HRGN): int32{.stdcall, dynlib: "user32",

+    importc: "GetWindowRgn".}

+proc ExcludeUpdateRgn*(hDC: HDC, wnd: HWND): int32{.stdcall, dynlib: "user32",

+    importc: "ExcludeUpdateRgn".}

+proc InvalidateRect*(wnd: HWND, lpRect: var RECT, bErase: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "InvalidateRect".}

+proc InvalidateRect*(wnd: HWND, lpRect: LPRECT, bErase: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "InvalidateRect".}

+proc ValidateRect*(wnd: HWND, lpRect: var RECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ValidateRect".}

+proc ValidateRect*(wnd: HWND, lpRect: LPRECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ValidateRect".}

+proc InvalidateRgn*(wnd: HWND, hRgn: HRGN, bErase: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "InvalidateRgn".}

+proc ValidateRgn*(wnd: HWND, hRgn: HRGN): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ValidateRgn".}

+proc RedrawWindow*(wnd: HWND, lprcUpdate: var RECT, hrgnUpdate: HRGN,

+                   flags: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "RedrawWindow".}

+proc RedrawWindow*(wnd: HWND, lprcUpdate: LPRECT, hrgnUpdate: HRGN, flags: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "RedrawWindow".}

+proc LockWindowUpdate*(hWndLock: HWND): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "LockWindowUpdate".}

+proc ScrollWindow*(wnd: HWND, XAmount: int32, YAmount: int32, lpRect: var RECT,

+                   lpClipRect: var RECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ScrollWindow".}

+proc ScrollDC*(hDC: HDC, dx: int32, dy: int32, lprcScroll: var RECT,

+               lprcClip: var RECT, hrgnUpdate: HRGN, lprcUpdate: LPRECT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "ScrollDC".}

+proc ScrollWindowEx*(wnd: HWND, dx: int32, dy: int32, prcScroll: var RECT,

+                     prcClip: var RECT, hrgnUpdate: HRGN, prcUpdate: LPRECT,

+                     flags: WINUINT): int32{.stdcall, dynlib: "user32",

+    importc: "ScrollWindowEx".}

+proc SetScrollPos*(wnd: HWND, nBar: int32, nPos: int32, bRedraw: WINBOOL): int32{.

+    stdcall, dynlib: "user32", importc: "SetScrollPos".}

+proc GetScrollPos*(wnd: HWND, nBar: int32): int32{.stdcall, dynlib: "user32",

+    importc: "GetScrollPos".}

+proc SetScrollRange*(wnd: HWND, nBar: int32, nMinPos: int32, nMaxPos: int32,

+                     bRedraw: WINBOOL): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetScrollRange".}

+proc GetScrollRange*(wnd: HWND, nBar: int32, lpMinPos: LPINT, lpMaxPos: LPINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetScrollRange".}

+proc ShowScrollBar*(wnd: HWND, wBar: int32, bShow: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ShowScrollBar".}

+proc EnableScrollBar*(wnd: HWND, wSBflags: WINUINT, wArrows: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnableScrollBar".}

+proc GetClientRect*(wnd: HWND, lpRect: LPRECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetClientRect".}

+proc GetWindowRect*(wnd: HWND, lpRect: LPRECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetWindowRect".}

+proc AdjustWindowRect*(lpRect: LPRECT, dwStyle: DWORD, bMenu: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "AdjustWindowRect".}

+proc AdjustWindowRectEx*(lpRect: LPRECT, dwStyle: DWORD, bMenu: WINBOOL,

+                         dwExStyle: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "AdjustWindowRectEx".}

+proc SetWindowContextHelpId*(para1: HWND, para2: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetWindowContextHelpId".}

+proc GetWindowContextHelpId*(para1: HWND): DWORD{.stdcall, dynlib: "user32",

+    importc: "GetWindowContextHelpId".}

+proc SetMenuContextHelpId*(para1: HMENU, para2: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetMenuContextHelpId".}

+proc GetMenuContextHelpId*(para1: HMENU): DWORD{.stdcall, dynlib: "user32",

+    importc: "GetMenuContextHelpId".}

+proc MessageBeep*(uType: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "MessageBeep".}

+proc ShowCursor*(bShow: WINBOOL): int32{.stdcall, dynlib: "user32",

+    importc: "ShowCursor".}

+proc SetCursorPos*(X: int32, Y: int32): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetCursorPos".}

+proc SetCursor*(cursor: HCURSOR): HCURSOR{.stdcall, dynlib: "user32",

+    importc: "SetCursor".}

+proc GetCursorPos*(lpPoint: LPPOINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetCursorPos".}

+proc ClipCursor*(lpRect: LPRECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ClipCursor".}

+proc GetClipCursor*(lpRect: LPRECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetClipCursor".}

+proc GetCursor*(): HCURSOR{.stdcall, dynlib: "user32", importc: "GetCursor".}

+proc CreateCaret*(wnd: HWND, hBitmap: HBITMAP, nWidth: int32, nHeight: int32): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "CreateCaret".}

+proc GetCaretBlinkTime*(): WINUINT{.stdcall, dynlib: "user32",

+                                 importc: "GetCaretBlinkTime".}

+proc SetCaretBlinkTime*(uMSeconds: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetCaretBlinkTime".}

+proc DestroyCaret*(): WINBOOL{.stdcall, dynlib: "user32",

+                               importc: "DestroyCaret".}

+proc HideCaret*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                      importc: "HideCaret".}

+proc ShowCaret*(wnd: HWND): WINBOOL{.stdcall, dynlib: "user32",

+                                      importc: "ShowCaret".}

+proc SetCaretPos*(X: int32, Y: int32): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetCaretPos".}

+proc GetCaretPos*(lpPoint: LPPOINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetCaretPos".}

+proc ClientToScreen*(wnd: HWND, lpPoint: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ClientToScreen".}

+proc ScreenToClient*(wnd: HWND, lpPoint: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ScreenToClient".}

+proc MapWindowPoints*(hWndFrom: HWND, hWndTo: HWND, lpPoints: LPPOINT,

+                      cPoints: WINUINT): int32{.stdcall, dynlib: "user32",

+    importc: "MapWindowPoints".}

+proc WindowFromPoint*(Point: POINT): HWND{.stdcall, dynlib: "user32",

+    importc: "WindowFromPoint".}

+proc ChildWindowFromPoint*(hWndParent: HWND, Point: POINT): HWND{.stdcall,

+    dynlib: "user32", importc: "ChildWindowFromPoint".}

+proc GetSysColor*(nIndex: int32): DWORD{.stdcall, dynlib: "user32",

+    importc: "GetSysColor".}

+proc GetSysColorBrush*(nIndex: int32): HBRUSH{.stdcall, dynlib: "user32",

+    importc: "GetSysColorBrush".}

+proc SetSysColors*(cElements: int32, lpaElements: var WINT,

+                   lpaRgbValues: var COLORREF): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetSysColors".}

+proc DrawFocusRect*(hDC: HDC, lprc: var RECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DrawFocusRect".}

+proc FillRect*(hDC: HDC, lprc: var RECT, hbr: HBRUSH): int32{.stdcall,

+    dynlib: "user32", importc: "FillRect".}

+proc FrameRect*(hDC: HDC, lprc: var RECT, hbr: HBRUSH): int32{.stdcall,

+    dynlib: "user32", importc: "FrameRect".}

+proc InvertRect*(hDC: HDC, lprc: var RECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "InvertRect".}

+proc SetRect*(lprc: LPRECT, xLeft: int32, yTop: int32, xRight: int32,

+              yBottom: int32): WINBOOL{.stdcall, dynlib: "user32",

+                                        importc: "SetRect".}

+proc SetRectEmpty*(lprc: LPRECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetRectEmpty".}

+proc CopyRect*(lprcDst: LPRECT, lprcSrc: var RECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CopyRect".}

+proc InflateRect*(lprc: LPRECT, dx: int32, dy: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "InflateRect".}

+proc IntersectRect*(lprcDst: LPRECT, lprcSrc1: var RECT, lprcSrc2: var RECT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "IntersectRect".}

+proc UnionRect*(lprcDst: LPRECT, lprcSrc1: var RECT, lprcSrc2: var RECT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "UnionRect".}

+proc SubtractRect*(lprcDst: LPRECT, lprcSrc1: var RECT, lprcSrc2: var RECT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SubtractRect".}

+proc OffsetRect*(lprc: LPRECT, dx: int32, dy: int32): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "OffsetRect".}

+proc IsRectEmpty*(lprc: var RECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "IsRectEmpty".}

+proc EqualRect*(lprc1: var RECT, lprc2: var RECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EqualRect".}

+proc PtInRect*(lprc: var RECT, pt: POINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "PtInRect".}

+proc PtInRect*(lprc: LPRECT, pt: POINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "PtInRect".}

+proc GetWindowWord*(wnd: HWND, nIndex: int32): int16{.stdcall,

+    dynlib: "user32", importc: "GetWindowWord".}

+proc SetWindowWord*(wnd: HWND, nIndex: int32, wNewWord: int16): int16{.stdcall,

+    dynlib: "user32", importc: "SetWindowWord".}

+proc GetClassWord*(wnd: HWND, nIndex: int32): int16{.stdcall, dynlib: "user32",

+    importc: "GetClassWord".}

+proc SetClassWord*(wnd: HWND, nIndex: int32, wNewWord: int16): int16{.stdcall,

+    dynlib: "user32", importc: "SetClassWord".}

+proc GetDesktopWindow*(): HWND{.stdcall, dynlib: "user32",

+                                importc: "GetDesktopWindow".}

+proc GetParent*(wnd: HWND): HWND{.stdcall, dynlib: "user32",

+                                   importc: "GetParent".}

+proc SetParent*(hWndChild: HWND, hWndNewParent: HWND): HWND{.stdcall,

+    dynlib: "user32", importc: "SetParent".}

+proc EnumChildWindows*(hWndParent: HWND, lpEnumFunc: ENUMWINDOWSPROC,

+                       lp: LPARAM): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "EnumChildWindows".}

+proc EnumWindows*(lpEnumFunc: ENUMWINDOWSPROC, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnumWindows".}

+proc EnumThreadWindows*(dwThreadId: DWORD, lpfn: ENUMWINDOWSPROC, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnumThreadWindows".}

+proc EnumTaskWindows*(hTask: HWND, lpfn: FARPROC, lp: LPARAM): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "EnumThreadWindows".}

+proc GetTopWindow*(wnd: HWND): HWND{.stdcall, dynlib: "user32",

+                                      importc: "GetTopWindow".}

+proc GetWindowThreadProcessId*(wnd: HWND, lpdwProcessId: LPDWORD): DWORD{.

+    stdcall, dynlib: "user32", importc: "GetWindowThreadProcessId".}

+proc GetLastActivePopup*(wnd: HWND): HWND{.stdcall, dynlib: "user32",

+    importc: "GetLastActivePopup".}

+proc GetWindow*(wnd: HWND, uCmd: WINUINT): HWND{.stdcall, dynlib: "user32",

+    importc: "GetWindow".}

+proc UnhookWindowsHook*(nCode: int32, pfnFilterProc: HOOKPROC): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "UnhookWindowsHook".}

+proc UnhookWindowsHookEx*(hhk: HHOOK): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "UnhookWindowsHookEx".}

+proc CallNextHookEx*(hhk: HHOOK, nCode: int32, wp: WPARAM, lp: LPARAM): LRESULT{.

+    stdcall, dynlib: "user32", importc: "CallNextHookEx".}

+proc CheckMenuRadioItem*(para1: HMENU, para2: WINUINT, para3: WINUINT, para4: WINUINT,

+                         para5: WINUINT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "CheckMenuRadioItem".}

+proc CreateCursor*(hInst: HINST, xHotSpot: int32, yHotSpot: int32,

+                   nWidth: int32, nHeight: int32, pvANDPlane: pointer,

+                   pvXORPlane: pointer): HCURSOR{.stdcall, dynlib: "user32",

+    importc: "CreateCursor".}

+proc DestroyCursor*(cursor: HCURSOR): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DestroyCursor".}

+proc SetSystemCursor*(hcur: HCURSOR, anID: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetSystemCursor".}

+proc CreateIcon*(hInstance: HINST, nWidth: int32, nHeight: int32, cPlanes: int8,

+                 cBitsPixel: int8, lpbANDbits: var int8, lpbXORbits: var int8): HICON{.

+    stdcall, dynlib: "user32", importc: "CreateIcon".}

+proc DestroyIcon*(icon: HICON): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DestroyIcon".}

+proc LookupIconIdFromDirectory*(presbits: PBYTE, fIcon: WINBOOL): int32{.

+    stdcall, dynlib: "user32", importc: "LookupIconIdFromDirectory".}

+proc LookupIconIdFromDirectoryEx*(presbits: PBYTE, fIcon: WINBOOL,

+                                  cxDesired: int32, cyDesired: int32,

+                                  Flags: WINUINT): int32{.stdcall,

+    dynlib: "user32", importc: "LookupIconIdFromDirectoryEx".}

+proc CreateIconFromResource*(presbits: PBYTE, dwResSize: DWORD, fIcon: WINBOOL,

+                             dwVer: DWORD): HICON{.stdcall, dynlib: "user32",

+    importc: "CreateIconFromResource".}

+proc CreateIconFromResourceEx*(presbits: PBYTE, dwResSize: DWORD,

+                               fIcon: WINBOOL, dwVer: DWORD, cxDesired: int32,

+                               cyDesired: int32, Flags: WINUINT): HICON{.stdcall,

+    dynlib: "user32", importc: "CreateIconFromResourceEx".}

+proc CopyImage*(para1: HANDLE, para2: WINUINT, para3: int32, para4: int32,

+                para5: WINUINT): HICON{.stdcall, dynlib: "user32",

+                                     importc: "CopyImage".}

+proc CreateIconIndirect*(piconinfo: PICONINFO): HICON{.stdcall,

+    dynlib: "user32", importc: "CreateIconIndirect".}

+proc CopyIcon*(icon: HICON): HICON{.stdcall, dynlib: "user32",

+                                     importc: "CopyIcon".}

+proc GetIconInfo*(icon: HICON, piconinfo: PICONINFO): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetIconInfo".}

+proc MapDialogRect*(hDlg: HWND, lpRect: LPRECT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "MapDialogRect".}

+proc SetScrollInfo*(para1: HWND, para2: int32, para3: LPCSCROLLINFO,

+                    para4: WINBOOL): int32{.stdcall, dynlib: "user32",

+    importc: "SetScrollInfo".}

+proc GetScrollInfo*(para1: HWND, para2: int32, para3: LPSCROLLINFO): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetScrollInfo".}

+proc TranslateMDISysAccel*(hWndClient: HWND, lpMsg: LPMSG): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "TranslateMDISysAccel".}

+proc ArrangeIconicWindows*(wnd: HWND): WINUINT{.stdcall, dynlib: "user32",

+    importc: "ArrangeIconicWindows".}

+proc TileWindows*(hwndParent: HWND, wHow: WINUINT, lpRect: var RECT, cKids: WINUINT,

+                  lpKids: var HWND): int16{.stdcall, dynlib: "user32",

+    importc: "TileWindows".}

+proc CascadeWindows*(hwndParent: HWND, wHow: WINUINT, lpRect: var RECT,

+                     cKids: WINUINT, lpKids: var HWND): int16{.stdcall,

+    dynlib: "user32", importc: "CascadeWindows".}

+proc SetLastErrorEx*(dwErrCode: DWORD, dwType: DWORD){.stdcall,

+    dynlib: "user32", importc: "SetLastErrorEx".}

+proc SetDebugErrorLevel*(dwLevel: DWORD){.stdcall, dynlib: "user32",

+    importc: "SetDebugErrorLevel".}

+proc DrawEdge*(hdc: HDC, qrc: LPRECT, edge: WINUINT, grfFlags: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DrawEdge".}

+proc DrawFrameControl*(para1: HDC, para2: LPRECT, para3: WINUINT, para4: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DrawFrameControl".}

+proc DrawCaption*(para1: HWND, para2: HDC, para3: var RECT, para4: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DrawCaption".}

+proc DrawAnimatedRects*(wnd: HWND, idAni: int32, lprcFrom: var RECT,

+                        lprcTo: var RECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DrawAnimatedRects".}

+proc TrackPopupMenuEx*(para1: HMENU, para2: WINUINT, para3: int32, para4: int32,

+                       para5: HWND, para6: LPTPMPARAMS): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "TrackPopupMenuEx".}

+proc ChildWindowFromPointEx*(para1: HWND, para2: POINT, para3: WINUINT): HWND{.

+    stdcall, dynlib: "user32", importc: "ChildWindowFromPointEx".}

+proc DrawIconEx*(hdc: HDC, xLeft: int32, yTop: int32, icon: HICON,

+                 cxWidth: int32, cyWidth: int32, istepIfAniCur: WINUINT,

+                 hbrFlickerFreeDraw: HBRUSH, diFlags: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DrawIconEx".}

+proc AnimatePalette*(para1: HPALETTE, para2: WINUINT, para3: WINUINT,

+                     para4: var PALETTEENTRY): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "AnimatePalette".}

+proc Arc*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32,

+          para6: int32, para7: int32, para8: int32, para9: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "Arc".}

+proc BitBlt*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32,

+             para6: HDC, para7: int32, para8: int32, para9: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "BitBlt".}

+proc CancelDC*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                     importc: "CancelDC".}

+proc Chord*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32,

+            para6: int32, para7: int32, para8: int32, para9: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "Chord".}

+proc CloseMetaFile*(para1: HDC): HMETAFILE{.stdcall, dynlib: "gdi32",

+    importc: "CloseMetaFile".}

+proc CombineRgn*(para1: HRGN, para2: HRGN, para3: HRGN, para4: int32): int32{.

+    stdcall, dynlib: "gdi32", importc: "CombineRgn".}

+proc CreateBitmap*(para1: int32, para2: int32, para3: WINUINT, para4: WINUINT,

+                   para5: pointer): HBITMAP{.stdcall, dynlib: "gdi32",

+    importc: "CreateBitmap".}

+proc CreateBitmapIndirect*(para1: var BITMAP): HBITMAP{.stdcall,

+    dynlib: "gdi32", importc: "CreateBitmapIndirect".}

+proc CreateBrushIndirect*(para1: var LOGBRUSH): HBRUSH{.stdcall,

+    dynlib: "gdi32", importc: "CreateBrushIndirect".}

+proc CreateCompatibleBitmap*(para1: HDC, para2: int32, para3: int32): HBITMAP{.

+    stdcall, dynlib: "gdi32", importc: "CreateCompatibleBitmap".}

+proc CreateDiscardableBitmap*(para1: HDC, para2: int32, para3: int32): HBITMAP{.

+    stdcall, dynlib: "gdi32", importc: "CreateDiscardableBitmap".}

+proc CreateCompatibleDC*(para1: HDC): HDC{.stdcall, dynlib: "gdi32",

+    importc: "CreateCompatibleDC".}

+proc CreateDIBitmap*(para1: HDC, para2: var BITMAPINFOHEADER, para3: DWORD,

+                     para4: pointer, para5: var BITMAPINFO, para6: WINUINT): HBITMAP{.

+    stdcall, dynlib: "gdi32", importc: "CreateDIBitmap".}

+proc CreateDIBPatternBrush*(para1: HGLOBAL, para2: WINUINT): HBRUSH{.stdcall,

+    dynlib: "gdi32", importc: "CreateDIBPatternBrush".}

+proc CreateDIBPatternBrushPt*(para1: pointer, para2: WINUINT): HBRUSH{.stdcall,

+    dynlib: "gdi32", importc: "CreateDIBPatternBrushPt".}

+proc CreateEllipticRgn*(para1: int32, para2: int32, para3: int32, para4: int32): HRGN{.

+    stdcall, dynlib: "gdi32", importc: "CreateEllipticRgn".}

+proc CreateEllipticRgnIndirect*(para1: var RECT): HRGN{.stdcall,

+    dynlib: "gdi32", importc: "CreateEllipticRgnIndirect".}

+proc CreateHatchBrush*(para1: int32, para2: COLORREF): HBRUSH{.stdcall,

+    dynlib: "gdi32", importc: "CreateHatchBrush".}

+proc CreatePalette*(para1: var LOGPALETTE): HPALETTE{.stdcall, dynlib: "gdi32",

+    importc: "CreatePalette".}

+proc CreatePen*(para1: int32, para2: int32, para3: COLORREF): HPEN{.stdcall,

+    dynlib: "gdi32", importc: "CreatePen".}

+proc CreatePenIndirect*(para1: var LOGPEN): HPEN{.stdcall, dynlib: "gdi32",

+    importc: "CreatePenIndirect".}

+proc CreatePolyPolygonRgn*(para1: var POINT, para2: var WINT, para3: int32,

+                           para4: int32): HRGN{.stdcall, dynlib: "gdi32",

+    importc: "CreatePolyPolygonRgn".}

+proc CreatePatternBrush*(para1: HBITMAP): HBRUSH{.stdcall, dynlib: "gdi32",

+    importc: "CreatePatternBrush".}

+proc CreateRectRgn*(para1: int32, para2: int32, para3: int32, para4: int32): HRGN{.

+    stdcall, dynlib: "gdi32", importc: "CreateRectRgn".}

+proc CreateRectRgnIndirect*(para1: var RECT): HRGN{.stdcall, dynlib: "gdi32",

+    importc: "CreateRectRgnIndirect".}

+proc CreateRoundRectRgn*(para1: int32, para2: int32, para3: int32, para4: int32,

+                         para5: int32, para6: int32): HRGN{.stdcall,

+    dynlib: "gdi32", importc: "CreateRoundRectRgn".}

+proc CreateSolidBrush*(para1: COLORREF): HBRUSH{.stdcall, dynlib: "gdi32",

+    importc: "CreateSolidBrush".}

+proc DeleteDC*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                     importc: "DeleteDC".}

+proc DeleteMetaFile*(para1: HMETAFILE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "DeleteMetaFile".}

+proc DeleteObject*(para1: HGDIOBJ): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "DeleteObject".}

+proc DrawEscape*(para1: HDC, para2: int32, para3: int32, para4: LPCSTR): int32{.

+    stdcall, dynlib: "gdi32", importc: "DrawEscape".}

+proc Ellipse*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "Ellipse".}

+proc EnumObjects*(para1: HDC, para2: int32, para3: ENUMOBJECTSPROC,

+                  para4: LPARAM): int32{.stdcall, dynlib: "gdi32",

+    importc: "EnumObjects".}

+proc EqualRgn*(para1: HRGN, para2: HRGN): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "EqualRgn".}

+proc Escape*(para1: HDC, para2: int32, para3: int32, para4: LPCSTR,

+             para5: LPVOID): int32{.stdcall, dynlib: "gdi32", importc: "Escape".}

+proc ExtEscape*(para1: HDC, para2: int32, para3: int32, para4: LPCSTR,

+                para5: int32, para6: LPSTR): int32{.stdcall, dynlib: "gdi32",

+    importc: "ExtEscape".}

+proc ExcludeClipRect*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                      para5: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "ExcludeClipRect".}

+proc ExtCreateRegion*(para1: var XFORM, para2: DWORD, para3: var RGNDATA): HRGN{.

+    stdcall, dynlib: "gdi32", importc: "ExtCreateRegion".}

+proc ExtFloodFill*(para1: HDC, para2: int32, para3: int32, para4: COLORREF,

+                   para5: WINUINT): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "ExtFloodFill".}

+proc FillRgn*(para1: HDC, para2: HRGN, para3: HBRUSH): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "FillRgn".}

+proc FloodFill*(para1: HDC, para2: int32, para3: int32, para4: COLORREF): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "FloodFill".}

+proc FrameRgn*(para1: HDC, para2: HRGN, para3: HBRUSH, para4: int32,

+               para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+                                       importc: "FrameRgn".}

+proc GetROP2*(para1: HDC): int32{.stdcall, dynlib: "gdi32", importc: "GetROP2".}

+proc GetAspectRatioFilterEx*(para1: HDC, para2: LPSIZE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetAspectRatioFilterEx".}

+proc GetBkColor*(para1: HDC): COLORREF{.stdcall, dynlib: "gdi32",

+                                        importc: "GetBkColor".}

+proc GetBkMode*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+                                    importc: "GetBkMode".}

+proc GetBitmapBits*(para1: HBITMAP, para2: LONG, para3: LPVOID): LONG{.stdcall,

+    dynlib: "gdi32", importc: "GetBitmapBits".}

+proc GetBitmapDimensionEx*(para1: HBITMAP, para2: LPSIZE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetBitmapDimensionEx".}

+proc GetBoundsRect*(para1: HDC, para2: LPRECT, para3: WINUINT): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetBoundsRect".}

+proc GetBrushOrgEx*(para1: HDC, para2: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetBrushOrgEx".}

+proc GetClipBox*(para1: HDC, para2: LPRECT): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetClipBox".}

+proc GetClipRgn*(para1: HDC, para2: HRGN): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetClipRgn".}

+proc GetMetaRgn*(para1: HDC, para2: HRGN): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetMetaRgn".}

+proc GetCurrentObject*(para1: HDC, para2: WINUINT): HGDIOBJ{.stdcall,

+    dynlib: "gdi32", importc: "GetCurrentObject".}

+proc GetCurrentPositionEx*(para1: HDC, para2: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCurrentPositionEx".}

+proc GetDeviceCaps*(para1: HDC, para2: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetDeviceCaps".}

+proc GetDIBits*(para1: HDC, para2: HBITMAP, para3: WINUINT, para4: WINUINT,

+                para5: LPVOID, para6: LPBITMAPINFO, para7: WINUINT): int32{.

+    stdcall, dynlib: "gdi32", importc: "GetDIBits".}

+proc GetFontData*(para1: HDC, para2: DWORD, para3: DWORD, para4: LPVOID,

+                  para5: DWORD): DWORD{.stdcall, dynlib: "gdi32",

+                                        importc: "GetFontData".}

+proc GetGraphicsMode*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetGraphicsMode".}

+proc GetMapMode*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+                                     importc: "GetMapMode".}

+proc GetMetaFileBitsEx*(para1: HMETAFILE, para2: WINUINT, para3: LPVOID): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetMetaFileBitsEx".}

+proc GetNearestColor*(para1: HDC, para2: COLORREF): COLORREF{.stdcall,

+    dynlib: "gdi32", importc: "GetNearestColor".}

+proc GetNearestPaletteIndex*(para1: HPALETTE, para2: COLORREF): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetNearestPaletteIndex".}

+proc GetObjectType*(h: HGDIOBJ): DWORD{.stdcall, dynlib: "gdi32",

+                                        importc: "GetObjectType".}

+proc GetPaletteEntries*(para1: HPALETTE, para2: WINUINT, para3: WINUINT,

+                        para4: LPPALETTEENTRY): WINUINT{.stdcall, dynlib: "gdi32",

+    importc: "GetPaletteEntries".}

+proc GetPixel*(para1: HDC, para2: int32, para3: int32): COLORREF{.stdcall,

+    dynlib: "gdi32", importc: "GetPixel".}

+proc GetPixelFormat*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetPixelFormat".}

+proc GetPolyFillMode*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetPolyFillMode".}

+proc GetRasterizerCaps*(para1: LPRASTERIZER_STATUS, para2: WINUINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetRasterizerCaps".}

+proc GetRegionData*(para1: HRGN, para2: DWORD, para3: LPRGNDATA): DWORD{.

+    stdcall, dynlib: "gdi32", importc: "GetRegionData".}

+proc GetRgnBox*(para1: HRGN, para2: LPRECT): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetRgnBox".}

+proc GetStockObject*(para1: int32): HGDIOBJ{.stdcall, dynlib: "gdi32",

+    importc: "GetStockObject".}

+proc GetStretchBltMode*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetStretchBltMode".}

+proc GetSystemPaletteEntries*(para1: HDC, para2: WINUINT, para3: WINUINT,

+                              para4: LPPALETTEENTRY): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetSystemPaletteEntries".}

+proc GetSystemPaletteUse*(para1: HDC): WINUINT{.stdcall, dynlib: "gdi32",

+    importc: "GetSystemPaletteUse".}

+proc GetTextCharacterExtra*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetTextCharacterExtra".}

+proc GetTextAlign*(para1: HDC): WINUINT{.stdcall, dynlib: "gdi32",

+                                      importc: "GetTextAlign".}

+proc GetTextColor*(para1: HDC): COLORREF{.stdcall, dynlib: "gdi32",

+    importc: "GetTextColor".}

+proc GetTextCharset*(hdc: HDC): int32{.stdcall, dynlib: "gdi32",

+                                       importc: "GetTextCharset".}

+proc GetTextCharsetInfo*(hdc: HDC, lpSig: LPFONTSIGNATURE, dwFlags: DWORD): int32{.

+    stdcall, dynlib: "gdi32", importc: "GetTextCharsetInfo".}

+proc TranslateCharsetInfo*(lpSrc: var DWORD, lpCs: LPCHARSETINFO, dwFlags: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "TranslateCharsetInfo".}

+proc GetFontLanguageInfo*(para1: HDC): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GetFontLanguageInfo".}

+proc GetViewportExtEx*(para1: HDC, para2: LPSIZE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetViewportExtEx".}

+proc GetViewportOrgEx*(para1: HDC, para2: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetViewportOrgEx".}

+proc GetWindowExtEx*(para1: HDC, para2: LPSIZE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetWindowExtEx".}

+proc GetWindowOrgEx*(para1: HDC, para2: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetWindowOrgEx".}

+proc IntersectClipRect*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                        para5: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "IntersectClipRect".}

+proc InvertRgn*(para1: HDC, para2: HRGN): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "InvertRgn".}

+proc LineDDA*(para1: int32, para2: int32, para3: int32, para4: int32,

+              para5: LINEDDAPROC, para6: LPARAM): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "LineDDA".}

+proc LineTo*(para1: HDC, para2: int32, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "LineTo".}

+proc MaskBlt*(para1: HDC, para2: int32, para3: int32, para4: int32,

+              para5: int32, para6: HDC, para7: int32, para8: int32,

+              para9: HBITMAP, para10: int32, para11: int32, para12: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "MaskBlt".}

+proc PlgBlt*(para1: HDC, para2: var POINT, para3: HDC, para4: int32,

+             para5: int32, para6: int32, para7: int32, para8: HBITMAP,

+             para9: int32, para10: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "PlgBlt".}

+proc OffsetClipRgn*(para1: HDC, para2: int32, para3: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "OffsetClipRgn".}

+proc OffsetRgn*(para1: HRGN, para2: int32, para3: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "OffsetRgn".}

+proc PatBlt*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32,

+             para6: DWORD): WINBOOL{.stdcall, dynlib: "gdi32", importc: "PatBlt".}

+proc Pie*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32,

+          para6: int32, para7: int32, para8: int32, para9: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "Pie".}

+proc PlayMetaFile*(para1: HDC, para2: HMETAFILE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PlayMetaFile".}

+proc PaintRgn*(para1: HDC, para2: HRGN): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "PaintRgn".}

+proc PolyPolygon*(para1: HDC, para2: var POINT, para3: var WINT, para4: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyPolygon".}

+proc PtInRegion*(para1: HRGN, para2: int32, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PtInRegion".}

+proc PtVisible*(para1: HDC, para2: int32, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PtVisible".}

+proc RectInRegion*(para1: HRGN, para2: var RECT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "RectInRegion".}

+proc RectVisible*(para1: HDC, para2: var RECT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "RectVisible".}

+proc Rectangle*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+                                        importc: "Rectangle".}

+proc RestoreDC*(para1: HDC, para2: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "RestoreDC".}

+proc RealizePalette*(para1: HDC): WINUINT{.stdcall, dynlib: "gdi32",

+                                        importc: "RealizePalette".}

+proc RoundRect*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                para5: int32, para6: int32, para7: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "RoundRect".}

+proc ResizePalette*(para1: HPALETTE, para2: WINUINT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "ResizePalette".}

+proc SaveDC*(para1: HDC): int32{.stdcall, dynlib: "gdi32", importc: "SaveDC".}

+proc SelectClipRgn*(para1: HDC, para2: HRGN): int32{.stdcall, dynlib: "gdi32",

+    importc: "SelectClipRgn".}

+proc ExtSelectClipRgn*(para1: HDC, para2: HRGN, para3: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "ExtSelectClipRgn".}

+proc SetMetaRgn*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+                                     importc: "SetMetaRgn".}

+proc SelectObject*(para1: HDC, para2: HGDIOBJ): HGDIOBJ{.stdcall,

+    dynlib: "gdi32", importc: "SelectObject".}

+proc SelectPalette*(para1: HDC, para2: HPALETTE, para3: WINBOOL): HPALETTE{.

+    stdcall, dynlib: "gdi32", importc: "SelectPalette".}

+proc SetBkColor*(para1: HDC, para2: COLORREF): COLORREF{.stdcall,

+    dynlib: "gdi32", importc: "SetBkColor".}

+proc SetBkMode*(para1: HDC, para2: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "SetBkMode".}

+proc SetBitmapBits*(para1: HBITMAP, para2: DWORD, para3: pointer): LONG{.

+    stdcall, dynlib: "gdi32", importc: "SetBitmapBits".}

+proc SetBoundsRect*(para1: HDC, para2: var RECT, para3: WINUINT): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "SetBoundsRect".}

+proc SetDIBits*(para1: HDC, para2: HBITMAP, para3: WINUINT, para4: WINUINT,

+                para5: pointer, para6: PBITMAPINFO, para7: WINUINT): int32{.

+    stdcall, dynlib: "gdi32", importc: "SetDIBits".}

+proc SetDIBitsToDevice*(para1: HDC, para2: int32, para3: int32, para4: DWORD,

+                        para5: DWORD, para6: int32, para7: int32, para8: WINUINT,

+                        para9: WINUINT, para10: pointer, para11: var BITMAPINFO,

+                        para12: WINUINT): int32{.stdcall, dynlib: "gdi32",

+    importc: "SetDIBitsToDevice".}

+proc SetMapperFlags*(para1: HDC, para2: DWORD): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "SetMapperFlags".}

+proc SetGraphicsMode*(hdc: HDC, iMode: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "SetGraphicsMode".}

+proc SetMapMode*(para1: HDC, para2: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "SetMapMode".}

+proc SetMetaFileBitsEx*(para1: WINUINT, para2: var int8): HMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "SetMetaFileBitsEx".}

+proc SetPaletteEntries*(para1: HPALETTE, para2: WINUINT, para3: WINUINT,

+                        para4: var PALETTEENTRY): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "SetPaletteEntries".}

+proc SetPixel*(para1: HDC, para2: int32, para3: int32, para4: COLORREF): COLORREF{.

+    stdcall, dynlib: "gdi32", importc: "SetPixel".}

+proc SetPixelV*(para1: HDC, para2: int32, para3: int32, para4: COLORREF): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetPixelV".}

+proc SetPolyFillMode*(para1: HDC, para2: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "SetPolyFillMode".}

+proc StretchBlt*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                 para5: int32, para6: HDC, para7: int32, para8: int32,

+                 para9: int32, para10: int32, para11: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "StretchBlt".}

+proc SetRectRgn*(para1: HRGN, para2: int32, para3: int32, para4: int32,

+                 para5: int32): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "SetRectRgn".}

+proc StretchDIBits*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                    para5: int32, para6: int32, para7: int32, para8: int32,

+                    para9: int32, para10: pointer, para11: var BITMAPINFO,

+                    para12: WINUINT, para13: DWORD): int32{.stdcall,

+    dynlib: "gdi32", importc: "StretchDIBits".}

+proc SetROP2*(para1: HDC, para2: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "SetROP2".}

+proc SetStretchBltMode*(para1: HDC, para2: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "SetStretchBltMode".}

+proc SetSystemPaletteUse*(para1: HDC, para2: WINUINT): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "SetSystemPaletteUse".}

+proc SetTextCharacterExtra*(para1: HDC, para2: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "SetTextCharacterExtra".}

+proc SetTextColor*(para1: HDC, para2: COLORREF): COLORREF{.stdcall,

+    dynlib: "gdi32", importc: "SetTextColor".}

+proc SetTextAlign*(para1: HDC, para2: WINUINT): WINUINT{.stdcall, dynlib: "gdi32",

+    importc: "SetTextAlign".}

+proc SetTextJustification*(para1: HDC, para2: int32, para3: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetTextJustification".}

+proc UpdateColors*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "UpdateColors".}

+proc PlayMetaFileRecord*(para1: HDC, para2: LPHANDLETABLE, para3: LPMETARECORD,

+                         para4: WINUINT): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "PlayMetaFileRecord".}

+proc EnumMetaFile*(para1: HDC, para2: HMETAFILE, para3: ENUMMETAFILEPROC,

+                   para4: LPARAM): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "EnumMetaFile".}

+proc CloseEnhMetaFile*(para1: HDC): HENHMETAFILE{.stdcall, dynlib: "gdi32",

+    importc: "CloseEnhMetaFile".}

+proc DeleteEnhMetaFile*(para1: HENHMETAFILE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "DeleteEnhMetaFile".}

+proc EnumEnhMetaFile*(para1: HDC, para2: HENHMETAFILE, para3: ENHMETAFILEPROC,

+                      para4: LPVOID, para5: var RECT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "EnumEnhMetaFile".}

+proc GetEnhMetaFileHeader*(para1: HENHMETAFILE, para2: WINUINT,

+                           para3: LPENHMETAHEADER): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetEnhMetaFileHeader".}

+proc GetEnhMetaFilePaletteEntries*(para1: HENHMETAFILE, para2: WINUINT,

+                                   para3: LPPALETTEENTRY): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetEnhMetaFilePaletteEntries".}

+proc GetEnhMetaFileBits*(para1: HENHMETAFILE, para2: WINUINT, para3: LPBYTE): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetEnhMetaFileBits".}

+proc GetWinMetaFileBits*(para1: HENHMETAFILE, para2: WINUINT, para3: LPBYTE,

+                         para4: WINT, para5: HDC): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetWinMetaFileBits".}

+proc PlayEnhMetaFile*(para1: HDC, para2: HENHMETAFILE, para3: RECT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PlayEnhMetaFile".}

+proc PlayEnhMetaFileRecord*(para1: HDC, para2: LPHANDLETABLE,

+                            para3: var TENHMETARECORD, para4: WINUINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PlayEnhMetaFileRecord".}

+proc SetEnhMetaFileBits*(para1: WINUINT, para2: var int8): HENHMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "SetEnhMetaFileBits".}

+proc SetWinMetaFileBits*(para1: WINUINT, para2: var int8, para3: HDC,

+                         para4: var METAFILEPICT): HENHMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "SetWinMetaFileBits".}

+proc GdiComment*(para1: HDC, para2: WINUINT, para3: var int8): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GdiComment".}

+proc AngleArc*(para1: HDC, para2: int32, para3: int32, para4: DWORD,

+               para5: float32, para6: float32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "AngleArc".}

+proc PolyPolyline*(para1: HDC, para2: var POINT, para3: var DWORD, para4: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyPolyline".}

+proc GetWorldTransform*(para1: HDC, para2: LPXFORM): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetWorldTransform".}

+proc SetWorldTransform*(para1: HDC, para2: var XFORM): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "SetWorldTransform".}

+proc ModifyWorldTransform*(para1: HDC, para2: var XFORM, para3: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "ModifyWorldTransform".}

+proc CombineTransform*(para1: LPXFORM, para2: var XFORM, para3: var XFORM): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "CombineTransform".}

+proc CreateDIBSection*(para1: HDC, para2: var BITMAPINFO, para3: WINUINT,

+                       para4: var pointer, para5: HANDLE, para6: DWORD): HBITMAP{.

+    stdcall, dynlib: "gdi32", importc: "CreateDIBSection".}

+proc GetDIBColorTable*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: var RGBQUAD): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetDIBColorTable".}

+proc SetDIBColorTable*(para1: HDC, para2: WINUINT, para3: WINUINT, para4: var RGBQUAD): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "SetDIBColorTable".}

+proc SetColorAdjustment*(para1: HDC, para2: var COLORADJUSTMENT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetColorAdjustment".}

+proc GetColorAdjustment*(para1: HDC, para2: LPCOLORADJUSTMENT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetColorAdjustment".}

+proc CreateHalftonePalette*(para1: HDC): HPALETTE{.stdcall, dynlib: "gdi32",

+    importc: "CreateHalftonePalette".}

+proc EndDoc*(para1: HDC): int32{.stdcall, dynlib: "gdi32", importc: "EndDoc".}

+proc StartPage*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+                                    importc: "StartPage".}

+proc EndPage*(para1: HDC): int32{.stdcall, dynlib: "gdi32", importc: "EndPage".}

+proc AbortDoc*(para1: HDC): int32{.stdcall, dynlib: "gdi32", importc: "AbortDoc".}

+proc SetAbortProc*(para1: HDC, para2: TABORTPROC): int32{.stdcall,

+    dynlib: "gdi32", importc: "SetAbortProc".}

+proc ArcTo*(para1: HDC, para2: int32, para3: int32, para4: int32, para5: int32,

+            para6: int32, para7: int32, para8: int32, para9: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "ArcTo".}

+proc BeginPath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                      importc: "BeginPath".}

+proc CloseFigure*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                        importc: "CloseFigure".}

+proc EndPath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32", importc: "EndPath".}

+proc FillPath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                     importc: "FillPath".}

+proc FlattenPath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                        importc: "FlattenPath".}

+proc GetPath*(para1: HDC, para2: LPPOINT, para3: LPBYTE, para4: int32): int32{.

+    stdcall, dynlib: "gdi32", importc: "GetPath".}

+proc PathToRegion*(para1: HDC): HRGN{.stdcall, dynlib: "gdi32",

+                                      importc: "PathToRegion".}

+proc PolyDraw*(para1: HDC, para2: var POINT, para3: var int8, para4: int32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyDraw".}

+proc SelectClipPath*(para1: HDC, para2: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "SelectClipPath".}

+proc SetArcDirection*(para1: HDC, para2: int32): int32{.stdcall,

+    dynlib: "gdi32", importc: "SetArcDirection".}

+proc SetMiterLimit*(para1: HDC, para2: float32, para3: ptr float32): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetMiterLimit".}

+proc StrokeAndFillPath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "StrokeAndFillPath".}

+proc StrokePath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                       importc: "StrokePath".}

+proc WidenPath*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                      importc: "WidenPath".}

+proc ExtCreatePen*(para1: DWORD, para2: DWORD, para3: var LOGBRUSH,

+                   para4: DWORD, para5: var DWORD): HPEN{.stdcall,

+    dynlib: "gdi32", importc: "ExtCreatePen".}

+proc GetMiterLimit*(para1: HDC, para2: ptr float32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetMiterLimit".}

+proc GetArcDirection*(para1: HDC): int32{.stdcall, dynlib: "gdi32",

+    importc: "GetArcDirection".}

+proc MoveToEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "MoveToEx".}

+proc CreatePolygonRgn*(para1: var POINT, para2: int32, para3: int32): HRGN{.

+    stdcall, dynlib: "gdi32", importc: "CreatePolygonRgn".}

+proc DPtoLP*(para1: HDC, para2: LPPOINT, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "DPtoLP".}

+proc LPtoDP*(para1: HDC, para2: LPPOINT, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "LPtoDP".}

+proc Polygon*(para1: HDC, para2: LPPOINT, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "Polygon".}

+proc Polyline*(para1: HDC, para2: LPPOINT, para3: int32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "Polyline".}

+proc PolyBezier*(para1: HDC, para2: LPPOINT, para3: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolyBezier".}

+proc PolyBezierTo*(para1: HDC, para2: POINT, para3: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolyBezierTo".}

+proc PolylineTo*(para1: HDC, para2: LPPOINT, para3: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolylineTo".}

+proc SetViewportExtEx*(para1: HDC, para2: int32, para3: int32, para4: LPSIZE): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetViewportExtEx".}

+proc SetViewportOrgEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetViewportOrgEx".}

+proc SetWindowExtEx*(para1: HDC, para2: int32, para3: int32, para4: LPSIZE): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetWindowExtEx".}

+proc SetWindowOrgEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetWindowOrgEx".}

+proc OffsetViewportOrgEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "OffsetViewportOrgEx".}

+proc OffsetWindowOrgEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "OffsetWindowOrgEx".}

+proc ScaleViewportExtEx*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                         para5: int32, para6: LPSIZE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "ScaleViewportExtEx".}

+proc ScaleWindowExtEx*(para1: HDC, para2: int32, para3: int32, para4: int32,

+                       para5: int32, para6: LPSIZE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "ScaleWindowExtEx".}

+proc SetBitmapDimensionEx*(para1: HBITMAP, para2: int32, para3: int32,

+                           para4: LPSIZE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "SetBitmapDimensionEx".}

+proc SetBrushOrgEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetBrushOrgEx".}

+proc GetDCOrgEx*(para1: HDC, para2: LPPOINT): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetDCOrgEx".}

+proc FixBrushOrgEx*(para1: HDC, para2: int32, para3: int32, para4: LPPOINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "FixBrushOrgEx".}

+proc UnrealizeObject*(para1: HGDIOBJ): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "UnrealizeObject".}

+proc GdiFlush*(): WINBOOL{.stdcall, dynlib: "gdi32", importc: "GdiFlush".}

+proc GdiSetBatchLimit*(para1: DWORD): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GdiSetBatchLimit".}

+proc GdiGetBatchLimit*(): DWORD{.stdcall, dynlib: "gdi32",

+                                 importc: "GdiGetBatchLimit".}

+proc SetICMMode*(para1: HDC, para2: int32): int32{.stdcall, dynlib: "gdi32",

+    importc: "SetICMMode".}

+proc CheckColorsInGamut*(para1: HDC, para2: LPVOID, para3: LPVOID, para4: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "CheckColorsInGamut".}

+proc GetColorSpace*(para1: HDC): HANDLE{.stdcall, dynlib: "gdi32",

+    importc: "GetColorSpace".}

+proc SetColorSpace*(para1: HDC, para2: HCOLORSPACE): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "SetColorSpace".}

+proc DeleteColorSpace*(para1: HCOLORSPACE): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "DeleteColorSpace".}

+proc GetDeviceGammaRamp*(para1: HDC, para2: LPVOID): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetDeviceGammaRamp".}

+proc SetDeviceGammaRamp*(para1: HDC, para2: LPVOID): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "SetDeviceGammaRamp".}

+proc ColorMatchToTarget*(para1: HDC, para2: HDC, para3: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "ColorMatchToTarget".}

+proc CreatePropertySheetPageA*(lppsp: LPCPROPSHEETPAGE): HPROPSHEETPAGE{.

+    stdcall, dynlib: "comctl32", importc: "CreatePropertySheetPageA".}

+proc DestroyPropertySheetPage*(hPSPage: HPROPSHEETPAGE): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "DestroyPropertySheetPage".}

+proc InitCommonControls*(){.stdcall, dynlib: "comctl32",

+                            importc: "InitCommonControls".}

+proc ImageList_AddIcon*(himl: HIMAGELIST, hicon: HICON): int32

+proc ImageList_Create*(cx: int32, cy: int32, flags: WINUINT, cInitial: int32,

+                       cGrow: int32): HIMAGELIST{.stdcall, dynlib: "comctl32",

+    importc: "ImageList_Create".}

+proc ImageList_Destroy*(himl: HIMAGELIST): WINBOOL{.stdcall, dynlib: "comctl32",

+    importc: "ImageList_Destroy".}

+proc ImageList_GetImageCount*(himl: HIMAGELIST): int32{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_GetImageCount".}

+proc ImageList_Add*(himl: HIMAGELIST, hbmImage: HBITMAP, hbmMask: HBITMAP): int32{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_Add".}

+proc ImageList_ReplaceIcon*(himl: HIMAGELIST, i: int32, hicon: HICON): int32{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_ReplaceIcon".}

+proc ImageList_SetBkColor*(himl: HIMAGELIST, clrBk: COLORREF): COLORREF{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_SetBkColor".}

+proc ImageList_GetBkColor*(himl: HIMAGELIST): COLORREF{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_GetBkColor".}

+proc ImageList_SetOverlayImage*(himl: HIMAGELIST, iImage: int32, iOverlay: int32): WINBOOL{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_SetOverlayImage".}

+proc ImageList_Draw*(himl: HIMAGELIST, i: int32, hdcDst: HDC, x: int32,

+                     y: int32, fStyle: WINUINT): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_Draw".}

+proc ImageList_Replace*(himl: HIMAGELIST, i: int32, hbmImage: HBITMAP,

+                        hbmMask: HBITMAP): WINBOOL{.stdcall, dynlib: "comctl32",

+    importc: "ImageList_Replace".}

+proc ImageList_AddMasked*(himl: HIMAGELIST, hbmImage: HBITMAP, crMask: COLORREF): int32{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_AddMasked".}

+proc ImageList_DrawEx*(himl: HIMAGELIST, i: int32, hdcDst: HDC, x: int32,

+                       y: int32, dx: int32, dy: int32, rgbBk: COLORREF,

+                       rgbFg: COLORREF, fStyle: WINUINT): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_DrawEx".}

+proc ImageList_Remove*(himl: HIMAGELIST, i: int32): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_Remove".}

+proc ImageList_GetIcon*(himl: HIMAGELIST, i: int32, flags: WINUINT): HICON{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_GetIcon".}

+proc ImageList_BeginDrag*(himlTrack: HIMAGELIST, iTrack: int32,

+                          dxHotspot: int32, dyHotspot: int32): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_BeginDrag".}

+proc ImageList_EndDrag*(){.stdcall, dynlib: "comctl32",

+                           importc: "ImageList_EndDrag".}

+proc ImageList_DragEnter*(hwndLock: HWND, x: int32, y: int32): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_DragEnter".}

+proc ImageList_DragLeave*(hwndLock: HWND): WINBOOL{.stdcall, dynlib: "comctl32",

+    importc: "ImageList_DragLeave".}

+proc ImageList_DragMove*(x: int32, y: int32): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_DragMove".}

+proc ImageList_SetDragCursorImage*(himlDrag: HIMAGELIST, iDrag: int32,

+                                   dxHotspot: int32, dyHotspot: int32): WINBOOL{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_SetDragCursorImage".}

+proc ImageList_DragShowNolock*(fShow: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_DragShowNolock".}

+proc ImageList_GetDragImage*(ppt: LPPOINT, pptHotspot: LPPOINT): HIMAGELIST{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_GetDragImage".}

+proc ImageList_GetIconSize*(himl: HIMAGELIST, cx: var int32, cy: var int32): WINBOOL{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_GetIconSize".}

+proc ImageList_SetIconSize*(himl: HIMAGELIST, cx: int32, cy: int32): WINBOOL{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_SetIconSize".}

+proc ImageList_GetImageInfo*(himl: HIMAGELIST, i: int32,

+                             pImageInfo: var IMAGEINFO): WINBOOL{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_GetImageInfo".}

+proc ImageList_Merge*(himl1: HIMAGELIST, i1: int32, himl2: HIMAGELIST,

+                      i2: int32, dx: int32, dy: int32): HIMAGELIST{.stdcall,

+    dynlib: "comctl32", importc: "ImageList_Merge".}

+proc ImageList_SetImageCount*(himl: HIMAGELIST, uNewCount: WINUINT): int{.stdcall,

+    dynlib: "comctl32.dll", importc: "ImageList_SetImageCount".}

+proc CreateToolbarEx*(wnd: HWND, ws: DWORD, wID: WINUINT, nBitmaps: int32,

+                      hBMInst: HINST, wBMID: WINUINT, lpButtons: LPCTBBUTTON,

+                      iNumButtons: int32, dxButton: int32, dyButton: int32,

+                      dxBitmap: int32, dyBitmap: int32, uStructSize: WINUINT): HWND{.

+    stdcall, dynlib: "comctl32", importc: "CreateToolbarEx".}

+proc CreateMappedBitmap*(hInstance: HINST, idBitmap: int32, wFlags: WINUINT,

+                         lpColorMap: LPCOLORMAP, iNumMaps: int32): HBITMAP{.

+    stdcall, dynlib: "comctl32", importc: "CreateMappedBitmap".}

+proc MenuHelp*(uMsg: WINUINT, wp: WPARAM, lp: LPARAM, hMainMenu: HMENU,

+               hInst: HINST, hwndStatus: HWND, lpwIDs: var WINUINT){.stdcall,

+    dynlib: "comctl32", importc: "MenuHelp".}

+proc ShowHideMenuCtl*(wnd: HWND, uFlags: WINUINT, lpInfo: LPINT): WINBOOL{.

+    stdcall, dynlib: "comctl32", importc: "ShowHideMenuCtl".}

+proc GetEffectiveClientRect*(wnd: HWND, lprc: LPRECT, lpInfo: LPINT){.stdcall,

+    dynlib: "comctl32", importc: "GetEffectiveClientRect".}

+proc MakeDragList*(hLB: HWND): WINBOOL{.stdcall, dynlib: "comctl32",

+                                        importc: "MakeDragList".}

+proc DrawInsert*(handParent: HWND, hLB: HWND, nItem: int32){.stdcall,

+    dynlib: "comctl32", importc: "DrawInsert".}

+proc LBItemFromPt*(hLB: HWND, pt: POINT, bAutoScroll: WINBOOL): int32{.stdcall,

+    dynlib: "comctl32", importc: "LBItemFromPt".}

+proc CreateUpDownControl*(dwStyle: DWORD, x: int32, y: int32, cx: int32,

+                          cy: int32, hParent: HWND, nID: int32, hInst: HINST,

+                          hBuddy: HWND, nUpper: int32, nLower: int32,

+                          nPos: int32): HWND{.stdcall, dynlib: "comctl32",

+    importc: "CreateUpDownControl".}

+proc RegCloseKey*(key: HKEY): LONG{.stdcall, dynlib: "advapi32",

+                                     importc: "RegCloseKey".}

+proc RegSetKeySecurity*(key: HKEY, SecurityInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSECURITY_DESCRIPTOR): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegSetKeySecurity".}

+proc RegFlushKey*(key: HKEY): LONG{.stdcall, dynlib: "advapi32",

+                                     importc: "RegFlushKey".}

+proc RegGetKeySecurity*(key: HKEY, SecurityInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                        lpcbSecurityDescriptor: LPDWORD): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegGetKeySecurity".}

+proc RegNotifyChangeKeyValue*(key: HKEY, bWatchSubtree: WINBOOL,

+                              dwNotifyFilter: DWORD, hEvent: HANDLE,

+                              fAsynchronus: WINBOOL): LONG{.stdcall,

+    dynlib: "advapi32", importc: "RegNotifyChangeKeyValue".}

+proc IsValidCodePage*(CodePage: WINUINT): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "IsValidCodePage".}

+proc GetACP*(): WINUINT{.stdcall, dynlib: "kernel32", importc: "GetACP".}

+proc GetOEMCP*(): WINUINT{.stdcall, dynlib: "kernel32", importc: "GetOEMCP".}

+proc GetCPInfo*(para1: WINUINT, para2: LPCPINFO): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetCPInfo".}

+proc IsDBCSLeadByte*(TestChar: int8): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "IsDBCSLeadByte".}

+proc IsDBCSLeadByteEx*(CodePage: WINUINT, TestChar: int8): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsDBCSLeadByteEx".}

+proc MultiByteToWideChar*(CodePage: WINUINT, dwFlags: DWORD,

+                          lpMultiByteStr: LPCSTR, cchMultiByte: int32,

+                          lpWideCharStr: LPWSTR, cchWideChar: int32): int32{.

+    stdcall, dynlib: "kernel32", importc: "MultiByteToWideChar".}

+proc WideCharToMultiByte*(CodePage: WINUINT, dwFlags: DWORD,

+                          lpWideCharStr: LPCWSTR, cchWideChar: int32,

+                          lpMultiByteStr: LPSTR, cchMultiByte: int32,

+                          lpDefaultChar: LPCSTR, lpUsedDefaultChar: LPBOOL): int32{.

+    stdcall, dynlib: "kernel32", importc: "WideCharToMultiByte".}

+proc IsValidLocale*(Locale: LCID, dwFlags: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "IsValidLocale".}

+proc ConvertDefaultLocale*(Locale: LCID): LCID{.stdcall, dynlib: "kernel32",

+    importc: "ConvertDefaultLocale".}

+proc GetThreadLocale*(): LCID{.stdcall, dynlib: "kernel32",

+                               importc: "GetThreadLocale".}

+proc SetThreadLocale*(Locale: LCID): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "SetThreadLocale".}

+proc GetSystemDefaultLangID*(): LANGID{.stdcall, dynlib: "kernel32",

+                                        importc: "GetSystemDefaultLangID".}

+proc GetUserDefaultLangID*(): LANGID{.stdcall, dynlib: "kernel32",

+                                      importc: "GetUserDefaultLangID".}

+proc GetSystemDefaultLCID*(): LCID{.stdcall, dynlib: "kernel32",

+                                    importc: "GetSystemDefaultLCID".}

+proc GetUserDefaultLCID*(): LCID{.stdcall, dynlib: "kernel32",

+                                  importc: "GetUserDefaultLCID".}

+proc ReadConsoleOutputAttribute*(hConsoleOutput: HANDLE, lpAttribute: LPWORD,

+                                 nLength: DWORD, dwReadCoord: COORD,

+                                 lpNumberOfAttrsRead: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputAttribute".}

+proc WriteConsoleOutputAttribute*(hConsoleOutput: HANDLE,

+                                  lpAttribute: var int16, nLength: DWORD,

+                                  dwWriteCoord: COORD,

+                                  lpNumberOfAttrsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputAttribute".}

+proc FillConsoleOutputAttribute*(hConsoleOutput: HANDLE, wAttribute: int16,

+                                 nLength: DWORD, dwWriteCoord: COORD,

+                                 lpNumberOfAttrsWritten: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputAttribute".}

+proc GetConsoleMode*(hConsoleHandle: HANDLE, lpMode: LPDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetConsoleMode".}

+proc GetNumberOfConsoleInputEvents*(hConsoleInput: HANDLE,

+                                    lpNumberOfEvents: PDWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetNumberOfConsoleInputEvents".}

+proc GetConsoleScreenBufferInfo*(hConsoleOutput: HANDLE,

+    lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetConsoleScreenBufferInfo".}

+proc GetLargestConsoleWindowSize*(hConsoleOutput: HANDLE): COORD

+proc GetConsoleCursorInfo*(hConsoleOutput: HANDLE,

+                           lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetConsoleCursorInfo".}

+proc GetNumberOfConsoleMouseButtons*(lpNumberOfMouseButtons: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetNumberOfConsoleMouseButtons".}

+proc SetConsoleMode*(hConsoleHandle: HANDLE, dwMode: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetConsoleMode".}

+proc SetConsoleActiveScreenBuffer*(hConsoleOutput: HANDLE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetConsoleActiveScreenBuffer".}

+proc FlushConsoleInputBuffer*(hConsoleInput: HANDLE): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FlushConsoleInputBuffer".}

+proc SetConsoleScreenBufferSize*(hConsoleOutput: HANDLE, dwSize: COORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetConsoleScreenBufferSize".}

+proc SetConsoleCursorPosition*(hConsoleOutput: HANDLE, dwCursorPosition: COORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetConsoleCursorPosition".}

+proc SetConsoleCursorInfo*(hConsoleOutput: HANDLE,

+                           lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetConsoleCursorInfo".}

+proc SetConsoleWindowInfo*(hConsoleOutput: HANDLE, bAbsolute: WINBOOL,

+                           lpConsoleWindow: var SMALL_RECT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetConsoleWindowInfo".}

+proc SetConsoleTextAttribute*(hConsoleOutput: HANDLE, wAttributes: int16): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetConsoleTextAttribute".}

+proc SetConsoleCtrlHandler*(HandlerRoutine: PHANDLER_ROUTINE, Add: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetConsoleCtrlHandler".}

+proc GenerateConsoleCtrlEvent*(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GenerateConsoleCtrlEvent".}

+proc AllocConsole*(): WINBOOL{.stdcall, dynlib: "kernel32",

+                               importc: "AllocConsole".}

+proc FreeConsole*(): WINBOOL{.stdcall, dynlib: "kernel32",

+                              importc: "FreeConsole".}

+proc CreateConsoleScreenBuffer*(dwDesiredAccess: DWORD, dwShareMode: DWORD,

+                                lpSecurityAttributes: var SECURITY_ATTRIBUTES,

+                                dwFlags: DWORD, lpScreenBufferData: LPVOID): HANDLE{.

+    stdcall, dynlib: "kernel32", importc: "CreateConsoleScreenBuffer".}

+proc GetConsoleCP*(): WINUINT{.stdcall, dynlib: "kernel32", importc: "GetConsoleCP".}

+proc SetConsoleCP*(wCodePageID: WINUINT): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "SetConsoleCP".}

+proc GetConsoleOutputCP*(): WINUINT{.stdcall, dynlib: "kernel32",

+                                  importc: "GetConsoleOutputCP".}

+proc SetConsoleOutputCP*(wCodePageID: WINUINT): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetConsoleOutputCP".}

+proc WNetConnectionDialog*(wnd: HWND, dwType: DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetConnectionDialog".}

+proc WNetDisconnectDialog*(wnd: HWND, dwType: DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetDisconnectDialog".}

+proc WNetCloseEnum*(hEnum: HANDLE): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetCloseEnum".}

+proc CloseServiceHandle*(hSCObject: SC_HANDLE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "CloseServiceHandle".}

+proc ControlService*(hService: SC_HANDLE, dwControl: DWORD,

+                     lpServiceStatus: LPSERVICE_STATUS): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ControlService".}

+proc DeleteService*(hService: SC_HANDLE): WINBOOL{.stdcall, dynlib: "advapi32",

+    importc: "DeleteService".}

+proc LockServiceDatabase*(hSCManager: SC_HANDLE): SC_LOCK{.stdcall,

+    dynlib: "advapi32", importc: "LockServiceDatabase".}

+proc NotifyBootConfigStatus*(BootAcceptable: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "NotifyBootConfigStatus".}

+proc QueryServiceObjectSecurity*(hService: SC_HANDLE,

+                                 dwSecurityInformation: SECURITY_INFORMATION,

+                                 lpSecurityDescriptor: PSECURITY_DESCRIPTOR,

+                                 cbBufSize: DWORD, pcbBytesNeeded: LPDWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "QueryServiceObjectSecurity".}

+proc QueryServiceStatus*(hService: SC_HANDLE, lpServiceStatus: LPSERVICE_STATUS): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "QueryServiceStatus".}

+proc SetServiceObjectSecurity*(hService: SC_HANDLE,

+                               dwSecurityInformation: SECURITY_INFORMATION,

+                               lpSecurityDescriptor: PSECURITY_DESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "SetServiceObjectSecurity".}

+proc SetServiceStatus*(hServiceStatus: SERVICE_STATUS_HANDLE,

+                       lpServiceStatus: LPSERVICE_STATUS): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "SetServiceStatus".}

+proc UnlockServiceDatabase*(ScLock: SC_LOCK): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "UnlockServiceDatabase".}

+proc ChoosePixelFormat*(para1: HDC, para2: PPIXELFORMATDESCRIPTOR): int32{.

+    stdcall, dynlib: "gdi32", importc: "ChoosePixelFormat".}

+proc DescribePixelFormat*(para1: HDC, para2: int32, para3: WINUINT,

+                          para4: LPPIXELFORMATDESCRIPTOR): int32{.stdcall,

+    dynlib: "gdi32", importc: "DescribePixelFormat".}

+proc SetPixelFormat*(para1: HDC, para2: int32, para3: PPIXELFORMATDESCRIPTOR): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "SetPixelFormat".}

+proc SwapBuffers*(para1: HDC): WINBOOL{.stdcall, dynlib: "gdi32",

+                                        importc: "SwapBuffers".}

+proc DragQueryPoint*(para1: HDROP, para2: LPPOINT): WINBOOL{.stdcall,

+    dynlib: "shell32", importc: "DragQueryPoint".}

+proc DragFinish*(para1: HDROP){.stdcall, dynlib: "shell32",

+                                importc: "DragFinish".}

+proc DragAcceptFiles*(para1: HWND, para2: WINBOOL){.stdcall, dynlib: "shell32",

+    importc: "DragAcceptFiles".}

+proc DuplicateIcon*(para1: HINST, para2: HICON): HICON{.stdcall,

+    dynlib: "shell32", importc: "DuplicateIcon".}

+proc DdeAbandonTransaction*(para1: DWORD, para2: HCONV, para3: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DdeAbandonTransaction".}

+proc DdeAccessData*(para1: HDDEDATA, para2: PDWORD): PBYTE{.stdcall,

+    dynlib: "user32", importc: "DdeAccessData".}

+proc DdeAddData*(para1: HDDEDATA, para2: PBYTE, para3: DWORD, para4: DWORD): HDDEDATA{.

+    stdcall, dynlib: "user32", importc: "DdeAddData".}

+proc DdeClientTransaction*(para1: PBYTE, para2: DWORD, para3: HCONV, para4: HSZ,

+                           para5: WINUINT, para6: WINUINT, para7: DWORD, para8: PDWORD): HDDEDATA{.

+    stdcall, dynlib: "user32", importc: "DdeClientTransaction".}

+proc DdeCmpStringHandles*(para1: HSZ, para2: HSZ): int32{.stdcall,

+    dynlib: "user32", importc: "DdeCmpStringHandles".}

+proc DdeConnect*(para1: DWORD, para2: HSZ, para3: HSZ, para4: var CONVCONTEXT): HCONV{.

+    stdcall, dynlib: "user32", importc: "DdeConnect".}

+proc DdeConnectList*(para1: DWORD, para2: HSZ, para3: HSZ, para4: HCONVLIST,

+                     para5: PCONVCONTEXT): HCONVLIST{.stdcall, dynlib: "user32",

+    importc: "DdeConnectList".}

+proc DdeCreateDataHandle*(para1: DWORD, para2: LPBYTE, para3: DWORD,

+                          para4: DWORD, para5: HSZ, para6: WINUINT, para7: WINUINT): HDDEDATA{.

+    stdcall, dynlib: "user32", importc: "DdeCreateDataHandle".}

+proc DdeDisconnect*(para1: HCONV): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DdeDisconnect".}

+proc DdeDisconnectList*(para1: HCONVLIST): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DdeDisconnectList".}

+proc DdeEnableCallback*(para1: DWORD, para2: HCONV, para3: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DdeEnableCallback".}

+proc DdeFreeDataHandle*(para1: HDDEDATA): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DdeFreeDataHandle".}

+proc DdeFreeStringHandle*(para1: DWORD, para2: HSZ): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DdeFreeStringHandle".}

+proc DdeGetData*(para1: HDDEDATA, para2: LPBYTE, para3: DWORD, para4: DWORD): DWORD{.

+    stdcall, dynlib: "user32", importc: "DdeGetData".}

+proc DdeGetLastError*(para1: DWORD): WINUINT{.stdcall, dynlib: "user32",

+    importc: "DdeGetLastError".}

+proc DdeImpersonateClient*(para1: HCONV): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DdeImpersonateClient".}

+proc DdeKeepStringHandle*(para1: DWORD, para2: HSZ): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DdeKeepStringHandle".}

+proc DdeNameService*(para1: DWORD, para2: HSZ, para3: HSZ, para4: WINUINT): HDDEDATA{.

+    stdcall, dynlib: "user32", importc: "DdeNameService".}

+proc DdePostAdvise*(para1: DWORD, para2: HSZ, para3: HSZ): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "DdePostAdvise".}

+proc DdeQueryConvInfo*(para1: HCONV, para2: DWORD, para3: PCONVINFO): WINUINT{.

+    stdcall, dynlib: "user32", importc: "DdeQueryConvInfo".}

+proc DdeQueryNextServer*(para1: HCONVLIST, para2: HCONV): HCONV{.stdcall,

+    dynlib: "user32", importc: "DdeQueryNextServer".}

+proc DdeReconnect*(para1: HCONV): HCONV{.stdcall, dynlib: "user32",

+    importc: "DdeReconnect".}

+proc DdeSetUserHandle*(para1: HCONV, para2: DWORD, para3: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DdeSetUserHandle".}

+proc DdeUnaccessData*(para1: HDDEDATA): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DdeUnaccessData".}

+proc DdeUninitialize*(para1: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "DdeUninitialize".}

+proc SHAddToRecentDocs*(para1: WINUINT, para2: LPCVOID){.stdcall,

+    dynlib: "shell32", importc: "SHAddToRecentDocs".}

+proc SHBrowseForFolder*(para1: LPBROWSEINFO): LPITEMIDLIST{.stdcall,

+    dynlib: "shell32", importc: "SHBrowseForFolder".}

+proc SHChangeNotify*(para1: LONG, para2: WINUINT, para3: LPCVOID, para4: LPCVOID){.

+    stdcall, dynlib: "shell32", importc: "SHChangeNotify".}

+proc SHFileOperation*(para1: LPSHFILEOPSTRUCT): int32{.stdcall,

+    dynlib: "shell32", importc: "SHFileOperation".}

+proc SHFreeNameMappings*(para1: HANDLE){.stdcall, dynlib: "shell32",

+    importc: "SHFreeNameMappings".}

+proc SHGetFileInfo*(para1: LPCTSTR, para2: DWORD, para3: var SHFILEINFO,

+                    para4: WINUINT, para5: WINUINT): DWORD{.stdcall,

+    dynlib: "shell32", importc: "SHGetFileInfo".}

+proc SHGetPathFromIDList*(para1: LPCITEMIDLIST, para2: LPTSTR): WINBOOL{.

+    stdcall, dynlib: "shell32", importc: "SHGetPathFromIDList".}

+proc SHGetSpecialFolderLocation*(para1: HWND, para2: int32,

+                                 para3: var LPITEMIDLIST): HRESULT{.stdcall,

+    dynlib: "shell32", importc: "SHGetSpecialFolderLocation".}

+proc CommDlgExtendedError*(): DWORD{.stdcall, dynlib: "comdlg32",

+                                     importc: "CommDlgExtendedError".}

+  # wgl Windows OpenGL helper functions

+proc wglUseFontBitmaps*(para1: HDC, para2: DWORD, para3: DWORD, para4: DWORD): WINBOOL{.

+    stdcall, dynlib: "opengl32", importc: "wglUseFontBitmapsA".}

+proc wglCreateContext*(para1: HDC): HGLRC{.stdcall, dynlib: "opengl32",

+    importc: "wglCreateContext".}

+proc wglCreateLayerContext*(para1: HDC, para2: int32): HGLRC{.stdcall,

+    dynlib: "opengl32", importc: "wglCreateLayerContext".}

+proc wglCopyContext*(para1: HGLRC, para2: HGLRC, para3: WINUINT): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglCopyContext".}

+proc wglDeleteContext*(para1: HGLRC): WINBOOL{.stdcall, dynlib: "opengl32",

+    importc: "wglDeleteContext".}

+proc wglGetCurrentContext*(): HGLRC{.stdcall, dynlib: "opengl32",

+                                     importc: "wglGetCurrentContext".}

+proc wglGetCurrentDC*(): HDC{.stdcall, dynlib: "opengl32",

+                              importc: "wglGetCurrentDC".}

+proc wglMakeCurrent*(para1: HDC, para2: HGLRC): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglMakeCurrent".}

+proc wglShareLists*(para1: HGLRC, para2: HGLRC): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglShareLists".}

+proc wglUseFontBitmapsW*(para1: HDC, para2: DWORD, para3: DWORD, para4: DWORD): WINBOOL{.

+    stdcall, dynlib: "opengl32", importc: "wglUseFontBitmapsW".}

+proc wglUseFontOutlines*(para1: HDC, para2: DWORD, para3: DWORD, para4: DWORD,

+                         para5: float32, para6: float32, para7: int32,

+                         para8: LPGLYPHMETRICSFLOAT): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglUseFontOutlinesA".}

+proc wglUseFontBitmapsA*(para1: HDC, para2: DWORD, para3: DWORD, para4: DWORD): WINBOOL{.

+    stdcall, dynlib: "opengl32", importc: "wglUseFontBitmapsA".}

+proc wglUseFontOutlinesA*(para1: HDC, para2: DWORD, para3: DWORD, para4: DWORD,

+                          para5: float32, para6: float32, para7: int32,

+                          para8: LPGLYPHMETRICSFLOAT): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglUseFontOutlinesA".}

+proc wglDescribeLayerPlane*(para1: HDC, para2: int32, para3: int32, para4: WINUINT,

+                            para5: LPLAYERPLANEDESCRIPTOR): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglDescribeLayerPlane".}

+proc wglGetLayerPaletteEntries*(para1: HDC, para2: int32, para3: int32,

+                                para4: int32, para5: var COLORREF): int32{.

+    stdcall, dynlib: "opengl32", importc: "wglGetLayerPaletteEntries".}

+proc wglGetProcAddress*(para1: LPCSTR): TProc{.stdcall, dynlib: "opengl32",

+    importc: "wglGetProcAddress".}

+proc wglRealizeLayerPalette*(para1: HDC, para2: int32, para3: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "opengl32", importc: "wglRealizeLayerPalette".}

+proc wglSetLayerPaletteEntries*(para1: HDC, para2: int32, para3: int32,

+                                para4: int32, para5: var COLORREF): int32{.

+    stdcall, dynlib: "opengl32", importc: "wglSetLayerPaletteEntries".}

+proc wglSwapLayerBuffers*(para1: HDC, para2: WINUINT): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglSwapLayerBuffers".}

+proc wglUseFontOutlinesW*(para1: HDC, para2: DWORD, para3: DWORD, para4: DWORD,

+                          para5: float32, para6: float32, para7: int32,

+                          para8: LPGLYPHMETRICSFLOAT): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglUseFontOutlinesW".}

+  # translated macros

+proc Animate_Create*(hWndP: HWND, id: HMENU, dwStyle: DWORD, hInstance: HINST): HWND

+proc Animate_Open*(wnd: HWND, szName: LPTSTR): LRESULT

+proc Animate_Play*(wnd: HWND, `from`, `to`: int32, rep: WINUINT): LRESULT

+

+proc Animate_Stop*(wnd: HWND): LRESULT

+proc Animate_Close*(wnd: HWND): LRESULT

+proc Animate_Seek*(wnd: HWND, frame: int32): LRESULT

+proc PropSheet_AddPage*(hPropSheetDlg: HWND, hpage: HPROPSHEETPAGE): LRESULT

+proc PropSheet_Apply*(hPropSheetDlg: HWND): LRESULT

+proc PropSheet_CancelToClose*(hPropSheetDlg: HWND): LRESULT

+proc PropSheet_Changed*(hPropSheetDlg, hwndPage: HWND): LRESULT

+proc PropSheet_GetCurrentPageHwnd*(hDlg: HWND): LRESULT

+proc PropSheet_GetTabControl*(hPropSheetDlg: HWND): LRESULT

+proc PropSheet_IsDialogMessage*(hDlg: HWND, pMsg: int32): LRESULT

+proc PropSheet_PressButton*(hPropSheetDlg: HWND, iButton: int32): LRESULT

+proc PropSheet_QuerySiblings*(hPropSheetDlg: HWND, param1, param2: int32): LRESULT

+proc PropSheet_RebootSystem*(hPropSheetDlg: HWND): LRESULT

+proc PropSheet_RemovePage*(hPropSheetDlg: HWND, hpage: HPROPSHEETPAGE,

+                           index: int32): LRESULT

+proc PropSheet_RestartWindows*(hPropSheetDlg: HWND): LRESULT

+proc PropSheet_SetCurSel*(hPropSheetDlg: HWND, hpage: HPROPSHEETPAGE,

+                          index: int32): LRESULT

+proc PropSheet_SetCurSelByID*(hPropSheetDlg: HWND, id: int32): LRESULT

+proc PropSheet_SetFinishText*(hPropSheetDlg: HWND, lpszText: LPTSTR): LRESULT

+proc PropSheet_SetTitle*(hPropSheetDlg: HWND, dwStyle: DWORD, lpszText: LPCTSTR): LRESULT

+proc PropSheet_SetWizButtons*(hPropSheetDlg: HWND, dwFlags: DWORD): LRESULT

+proc PropSheet_UnChanged*(hPropSheetDlg: HWND, hwndPage: HWND): LRESULT

+proc Header_DeleteItem*(hwndHD: HWND, index: int32): WINBOOL

+proc Header_GetItem*(hwndHD: HWND, index: int32, hdi: var HD_ITEM): WINBOOL

+proc Header_GetItemCount*(hwndHD: HWND): int32

+proc Header_InsertItem*(hwndHD: HWND, index: int32, hdi: var HD_ITEM): int32

+proc Header_Layout*(hwndHD: HWND, layout: var HD_LAYOUT): WINBOOL

+proc Header_SetItem*(hwndHD: HWND, index: int32, hdi: var HD_ITEM): WINBOOL

+proc ListView_Arrange*(hwndLV: HWND, code: WINUINT): LRESULT

+proc ListView_CreateDragImage*(wnd: HWND, i: int32, lpptUpLeft: LPPOINT): LRESULT

+proc ListView_DeleteAllItems*(wnd: HWND): LRESULT

+proc ListView_DeleteColumn*(wnd: HWND, iCol: int32): LRESULT

+proc ListView_DeleteItem*(wnd: HWND, iItem: int32): LRESULT

+proc ListView_EditLabel*(hwndLV: HWND, i: int32): LRESULT

+proc ListView_EnsureVisible*(hwndLV: HWND, i, fPartialOK: int32): LRESULT

+proc ListView_FindItem*(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32

+proc ListView_GetBkColor*(wnd: HWND): LRESULT

+proc ListView_GetCallbackMask*(wnd: HWND): LRESULT

+proc ListView_GetColumn*(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT

+proc ListView_GetColumnWidth*(wnd: HWND, iCol: int32): LRESULT

+proc ListView_GetCountPerPage*(hwndLV: HWND): LRESULT

+proc ListView_GetEditControl*(hwndLV: HWND): LRESULT

+proc ListView_GetImageList*(wnd: HWND, iImageList: WINT): LRESULT

+proc ListView_GetISearchString*(hwndLV: HWND, lpsz: LPTSTR): LRESULT

+proc ListView_GetItem*(wnd: HWND, item: var LV_ITEM): LRESULT

+proc ListView_GetItemCount*(wnd: HWND): LRESULT

+proc ListView_GetItemPosition*(hwndLV: HWND, i: int32, pt: var POINT): int32

+proc ListView_GetItemSpacing*(hwndLV: HWND, fSmall: int32): LRESULT

+proc ListView_GetItemState*(hwndLV: HWND, i, mask: int32): LRESULT

+proc ListView_GetNextItem*(wnd: HWND, iStart, flags: int32): LRESULT

+proc ListView_GetOrigin*(hwndLV: HWND, pt: var POINT): LRESULT

+proc ListView_GetSelectedCount*(hwndLV: HWND): LRESULT

+proc ListView_GetStringWidth*(hwndLV: HWND, psz: LPCTSTR): LRESULT

+proc ListView_GetTextBkColor*(wnd: HWND): LRESULT

+proc ListView_GetTextColor*(wnd: HWND): LRESULT

+proc ListView_GetTopIndex*(hwndLV: HWND): LRESULT

+proc ListView_GetViewRect*(wnd: HWND, rc: var RECT): LRESULT

+proc ListView_HitTest*(hwndLV: HWND, info: var LV_HITTESTINFO): LRESULT

+proc ListView_InsertColumn*(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT

+proc ListView_InsertItem*(wnd: HWND, item: var LV_ITEM): LRESULT

+proc ListView_RedrawItems*(hwndLV: HWND, iFirst, iLast: int32): LRESULT

+proc ListView_Scroll*(hwndLV: HWND, dx, dy: int32): LRESULT

+proc ListView_SetBkColor*(wnd: HWND, clrBk: COLORREF): LRESULT

+proc ListView_SetCallbackMask*(wnd: HWND, mask: WINUINT): LRESULT

+proc ListView_SetColumn*(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT

+proc ListView_SetColumnWidth*(wnd: HWND, iCol, cx: int32): LRESULT

+proc ListView_SetImageList*(wnd: HWND, himl: int32, iImageList: HIMAGELIST): LRESULT

+proc ListView_SetItem*(wnd: HWND, item: var LV_ITEM): LRESULT

+proc ListView_SetItemCount*(hwndLV: HWND, cItems: int32): LRESULT

+proc ListView_SetItemPosition*(hwndLV: HWND, i, x, y: int32): LRESULT

+proc ListView_SetItemPosition32*(hwndLV: HWND, i, x, y: int32): LRESULT

+proc ListView_SetItemState*(hwndLV: HWND, i, data, mask: int32): LRESULT

+proc ListView_SetItemText*(hwndLV: HWND, i, iSubItem: int32, pszText: LPTSTR): LRESULT

+proc ListView_SetTextBkColor*(wnd: HWND, clrTextBk: COLORREF): LRESULT

+proc ListView_SetTextColor*(wnd: HWND, clrText: COLORREF): LRESULT

+proc ListView_SortItems*(hwndLV: HWND, pfnCompare: PFNLVCOMPARE, lPrm: LPARAM): LRESULT

+proc ListView_Update*(hwndLV: HWND, i: int32): LRESULT

+proc TreeView_InsertItem*(wnd: HWND, lpis: LPTV_INSERTSTRUCT): LRESULT

+proc TreeView_DeleteItem*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_DeleteAllItems*(wnd: HWND): LRESULT

+proc TreeView_Expand*(wnd: HWND, hitem: HTREEITEM, code: int32): LRESULT

+proc TreeView_GetCount*(wnd: HWND): LRESULT

+proc TreeView_GetIndent*(wnd: HWND): LRESULT

+proc TreeView_SetIndent*(wnd: HWND, indent: int32): LRESULT

+proc TreeView_GetImageList*(wnd: HWND, iImage: WPARAM): LRESULT

+proc TreeView_SetImageList*(wnd: HWND, himl: HIMAGELIST, iImage: WPARAM): LRESULT

+proc TreeView_GetNextItem*(wnd: HWND, hitem: HTREEITEM, code: int32): LRESULT

+proc TreeView_GetChild*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetNextSibling*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetPrevSibling*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetParent*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetFirstVisible*(wnd: HWND): LRESULT

+proc TreeView_GetNextVisible*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetPrevVisible*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetSelection*(wnd: HWND): LRESULT

+proc TreeView_GetDropHilight*(wnd: HWND): LRESULT

+proc TreeView_GetRoot*(wnd: HWND): LRESULT

+proc TreeView_Select*(wnd: HWND, hitem: HTREEITEM, code: int32): LRESULT

+proc TreeView_SelectItem*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_SelectDropTarget*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_SelectSetFirstVisible*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetItem*(wnd: HWND, item: var TV_ITEM): LRESULT

+proc TreeView_SetItem*(wnd: HWND, item: var TV_ITEM): LRESULT

+proc TreeView_EditLabel*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_GetEditControl*(wnd: HWND): LRESULT

+proc TreeView_GetVisibleCount*(wnd: HWND): LRESULT

+proc TreeView_HitTest*(wnd: HWND, lpht: LPTV_HITTESTINFO): LRESULT

+proc TreeView_CreateDragImage*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_SortChildren*(wnd: HWND, hitem: HTREEITEM, recurse: int32): LRESULT

+proc TreeView_EnsureVisible*(wnd: HWND, hitem: HTREEITEM): LRESULT

+proc TreeView_SortChildrenCB*(wnd: HWND, psort: LPTV_SORTCB, recurse: int32): LRESULT

+proc TreeView_EndEditLabelNow*(wnd: HWND, fCancel: int32): LRESULT

+proc TreeView_GetISearchString*(hwndTV: HWND, lpsz: LPTSTR): LRESULT

+proc TabCtrl_GetImageList*(wnd: HWND): LRESULT

+proc TabCtrl_SetImageList*(wnd: HWND, himl: HIMAGELIST): LRESULT

+proc TabCtrl_GetItemCount*(wnd: HWND): LRESULT

+proc TabCtrl_GetItem*(wnd: HWND, iItem: int32, item: var TC_ITEM): LRESULT

+proc TabCtrl_SetItem*(wnd: HWND, iItem: int32, item: var TC_ITEM): LRESULT

+

+proc TabCtrl_InsertItem*(wnd: HWND, iItem: int32, item: var TC_ITEM): LRESULT

+proc TabCtrl_DeleteItem*(wnd: HWND, i: int32): LRESULT

+proc TabCtrl_DeleteAllItems*(wnd: HWND): LRESULT

+proc TabCtrl_GetItemRect*(wnd: HWND, i: int32, rc: var RECT): LRESULT

+proc TabCtrl_GetCurSel*(wnd: HWND): LRESULT

+proc TabCtrl_SetCurSel*(wnd: HWND, i: int32): LRESULT

+proc TabCtrl_HitTest*(hwndTC: HWND, info: var TC_HITTESTINFO): LRESULT

+proc TabCtrl_SetItemExtra*(hwndTC: HWND, cb: int32): LRESULT

+proc TabCtrl_AdjustRect*(wnd: HWND, bLarger: WINBOOL, rc: var RECT): LRESULT

+proc TabCtrl_SetItemSize*(wnd: HWND, x, y: int32): LRESULT

+proc TabCtrl_RemoveImage*(wnd: HWND, i: WPARAM): LRESULT

+proc TabCtrl_SetPadding*(wnd: HWND, cx, cy: int32): LRESULT

+proc TabCtrl_GetRowCount*(wnd: HWND): LRESULT

+proc TabCtrl_GetToolTips*(wnd: HWND): LRESULT

+proc TabCtrl_SetToolTips*(wnd: HWND, hwndTT: int32): LRESULT

+proc TabCtrl_GetCurFocus*(wnd: HWND): LRESULT

+proc TabCtrl_SetCurFocus*(wnd: HWND, i: int32): LRESULT

+proc SNDMSG*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT

+proc CommDlg_OpenSave_GetSpecA*(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_GetSpecW*(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT

+when defined(winUnicode):

+  proc CommDlg_OpenSave_GetSpec*(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT

+else:

+  proc CommDlg_OpenSave_GetSpec*(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_GetFilePathA*(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_GetFilePathW*(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT

+when defined(winUnicode):

+  proc CommDlg_OpenSave_GetFilePath*(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT

+else:

+  proc CommDlg_OpenSave_GetFilePath*(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_GetFolderPathA*(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_GetFolderPathW*(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT

+when defined(winUnicode):

+  proc CommDlg_OpenSave_GetFolderPath*(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT

+else:

+  proc CommDlg_OpenSave_GetFolderPath*(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_GetFolderIDList*(hdlg: HWND, pidl: LPVOID, cbmax: int32): LRESULT

+proc CommDlg_OpenSave_SetControlText*(hdlg: HWND, id: int32, text: LPSTR): LRESULT

+proc CommDlg_OpenSave_HideControl*(hdlg: HWND, id: int32): LRESULT

+proc CommDlg_OpenSave_SetDefExt*(hdlg: HWND, pszext: LPSTR): LRESULT

+proc GetNextWindow*(wnd: HWND, uCmd: WINUINT): HWND{.stdcall, dynlib: "user32",

+    importc: "GetWindow".}

+proc GlobalAllocPtr*(flags, cb: DWord): pointer

+proc GlobalFreePtr*(lp: pointer): pointer

+proc GlobalUnlockPtr*(lp: pointer): pointer

+proc GlobalLockPtr*(lp: pointer): pointer

+proc GlobalReAllocPtr*(lp: pointer, cbNew, flags: DWord): pointer

+proc GlobalPtrHandle*(lp: pointer): pointer

+proc SetLayeredWindowAttributes*(hwnd: HWND, crKey: COLORREF, bAlpha: int8,

+                                 dwFlags: DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetLayeredWindowAttributes".}

+type

+  PIID* = PGUID

+  TIID* = TGUID

+  TFNDlgProc* = FARPROC

+  TFNThreadStartRoutine* = FARPROC

+  TFNTimerAPCRoutine* = FARPROC

+  TFNFiberStartRoutine* = FARPROC

+  TFNHookProc* = HOOKPROC

+  PObjectTypeList* = ptr TObjectTypeList

+  OBJECT_TYPE_LIST* {.final, pure.} = object

+    Level*: int16

+    Sbz*: int16

+    ObjectType*: PGUID

+

+  TObjectTypeList* = OBJECT_TYPE_LIST

+  AUDIT_EVENT_TYPE* = DWORD

+  PBlendFunction* = ptr TBlendFunction

+  BLENDFUNCTION* {.final, pure.} = object

+    BlendOp*: int8

+    BlendFlags*: int8

+    SourceConstantAlpha*: int8

+    AlphaFormat*: int8

+

+  TBlendFunction* = BLENDFUNCTION

+  WIN_CERTIFICATE* {.final, pure.} = object

+    dwLength*: DWord

+    wRevision*: int16

+    wCertificateType*: int16

+    bCertificate*: array[0..0, int8]

+

+  TWinCertificate* = WIN_CERTIFICATE

+  PWinCertificate* = ptr TWinCertificate

+  TMaxLogPalette* {.final, pure.} = object

+    palVersion*: int16

+    palNumEntries*: int16

+    palPalEntry*: array[int8, TPaletteEntry]

+

+  PMaxLogPalette* = ptr TMaxLogPalette

+  POSVersionInfoA* = POSVERSIONINFO

+  TBitmapFileHeader* = BITMAPFILEHEADER

+  PBitmapFileHeader* = ptr TBitmapFileHeader

+

+const

+  # dll names

+  advapi32* = "advapi32.dll"

+  kernel32* = "kernel32.dll"

+  mpr* = "mpr.dll"

+  version* = "version.dll"

+  comctl32* = "comctl32.dll"

+  gdi32* = "gdi32.dll"

+  opengl32* = "opengl32.dll"

+  user32* = "user32.dll"

+  wintrust* = "wintrust.dll"

+  # Openfile Share modes normally declared in sysutils

+  fmShareCompat* = 0x00000000

+  fmShareExclusive* = 0x00000010

+  fmShareDenyWrite* = 0x00000020

+  fmShareDenyRead* = 0x00000030

+  fmShareDenyNone* = 0x00000040

+  # HRESULT codes, delphilike

+  SIF_TRACKPOS* = 0x00000010

+  HTBORDER* = 18

+  CP_UTF7* = 65000

+  CP_UTF8* = 65001

+  CREATE_NO_WINDOW* = 0x08000000

+  VK_ATTN* = 246

+  VK_CRSEL* = 247

+  VK_EXSEL* = 248

+  VK_EREOF* = 249

+  VK_PLAY* = 250

+  VK_ZOOM* = 251

+  VK_NONAME* = 252

+  VK_PA1* = 253

+  VK_OEM_CLEAR* = 254

+

+const                         # Severity values

+  FACILITY_NT_BIT* = 0x10000000

+

+                            #  A language ID is a 16 bit value which is the combination of a

+                            #  primary language ID and a secondary language ID.  The bits are

+                            #  allocated as follows:

+                            #

+                            #       +-----------------------+-------------------------+

+                            #       |     Sublanguage ID    |   Primary Language ID   |

+                            #       +-----------------------+-------------------------+

+                            #        15                   10 9                       0   bit

+                            #

+                            #

+                            #  Language ID creation/extraction macros:

+                            #

+                            #    MAKELANGID    - construct language id from a primary language id and

+                            #                    a sublanguage id.

+                            #    PRIMARYLANGID - extract primary language id from a language id.

+                            #    SUBLANGID     - extract sublanguage id from a language id.

+                            #

+proc MAKELANGID*(PrimaryLang, SubLang: USHORT): int16

+proc PRIMARYLANGID*(LangId: int16): int16

+proc SUBLANGID*(LangId: int16): int16

+

+  #

+  #  A locale ID is a 32 bit value which is the combination of a

+  #  language ID, a sort ID, and a reserved area.  The bits are

+  #  allocated as follows:

+  #

+  #       +-------------+---------+-------------------------+

+  #       |   Reserved  | Sort ID |      Language ID        |

+  #       +-------------+---------+-------------------------+

+  #        31         20 19     16 15                      0   bit

+  #

+  #

+  #  Locale ID creation/extraction macros:

+  #

+  #    MAKELCID            - construct the locale id from a language id and a sort id.

+  #    MAKESORTLCID        - construct the locale id from a language id, sort id, and sort version.

+  #    LANGIDFROMLCID      - extract the language id from a locale id.

+  #    SORTIDFROMLCID      - extract the sort id from a locale id.

+  #    SORTVERSIONFROMLCID - extract the sort version from a locale id.

+  #

+const

+  NLS_VALID_LOCALE_MASK* = 0x000FFFFF

+

+proc MAKELCID*(LangId, SortId: int16): DWORD

+proc MAKESORTLCID*(LangId, SortId, SortVersion: int16): DWORD

+proc LANGIDFROMLCID*(LocaleId: LCID): int16

+proc SORTIDFROMLCID*(LocaleId: LCID): int16

+proc SORTVERSIONFROMLCID*(LocaleId: LCID): int16

+

+  #

+  #  Default System and User IDs for language and locale.

+  #

+proc LANG_SYSTEM_DEFAULT*(): int16

+proc LANG_USER_DEFAULT*(): int16

+proc LOCALE_NEUTRAL*(): DWORD

+proc LOCALE_INVARIANT*(): DWORD

+proc Succeeded*(Status: HRESULT): WINBOOL

+proc Failed*(Status: HRESULT): WINBOOL

+proc IsError*(Status: HRESULT): WINBOOL

+proc HResultCode*(hr: HRESULT): int32

+proc HResultFacility*(hr: HRESULT): int32

+proc HResultSeverity*(hr: HRESULT): int32

+proc MakeResult*(p1, p2, mask: int32): HRESULT

+proc HResultFromWin32*(x: int32): HRESULT

+proc HResultFromNT*(x: int32): HRESULT

+proc InitializeCriticalSection*(CriticalSection: var TRTLCriticalSection){.

+    stdcall, dynlib: "kernel32", importc: "InitializeCriticalSection".}

+proc EnterCriticalSection*(CriticalSection: var TRTLCriticalSection){.stdcall,

+    dynlib: "kernel32", importc: "EnterCriticalSection".}

+proc LeaveCriticalSection*(CriticalSection: var TRTLCriticalSection){.stdcall,

+    dynlib: "kernel32", importc: "LeaveCriticalSection".}

+proc DeleteCriticalSection*(CriticalSection: var TRTLCriticalSection){.stdcall,

+    dynlib: "kernel32", importc: "DeleteCriticalSection".}

+proc InitializeCriticalSectionAndSpinCount*(

+    CriticalSection: var TRTLCriticalSection, dwSpinCount: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32",

+    importc: "InitializeCriticalSectionAndSpinCount".}

+proc SetCriticalSectionSpinCount*(CriticalSection: var TRTLCriticalSection,

+                                  dwSpinCount: DWORD): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "SetCriticalSectionSpinCount".}

+proc TryEnterCriticalSection*(CriticalSection: var TRTLCriticalSection): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "TryEnterCriticalSection".}

+proc ControlService*(hService: SC_HANDLE, dwControl: DWORD,

+                     ServiceStatus: var TSERVICESTATUS): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ControlService".}

+proc QueryServiceStatus*(hService: SC_HANDLE,

+                         lpServiceStatus: var TSERVICESTATUS): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "QueryServiceStatus".}

+proc SetServiceStatus*(hServiceStatus: SERVICE_STATUS_HANDLE,

+                       ServiceStatus: TSERVICESTATUS): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "SetServiceStatus".}

+proc AdjustTokenPrivileges*(TokenHandle: THandle, DisableAllPrivileges: WINBOOL,

+                            NewState: TTokenPrivileges, BufferLength: DWORD,

+                            PreviousState: var TTokenPrivileges,

+                            ReturnLength: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AdjustTokenPrivileges".}

+proc AdjustWindowRect*(lpRect: var TRect, dwStyle: DWORD, bMenu: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "AdjustWindowRect".}

+proc AdjustWindowRectEx*(lpRect: var TRect, dwStyle: DWORD, bMenu: WINBOOL,

+                         dwExStyle: DWORD): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "AdjustWindowRectEx".}

+proc AllocateAndInitializeSid*(pIdentifierAuthority: TSIDIdentifierAuthority,

+                               nSubAuthorityCount: int8,

+                               nSubAuthority0, nSubAuthority1: DWORD,

+    nSubAuthority2, nSubAuthority3, nSubAuthority4: DWORD, nSubAuthority5,

+    nSubAuthority6, nSubAuthority7: DWORD, pSid: var pointer): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AllocateAndInitializeSid".}

+proc AllocateLocallyUniqueId*(Luid: var TLargeInteger): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "AllocateLocallyUniqueId".}

+proc BackupRead*(hFile: THandle, lpBuffer: PByte, nNumberOfBytesToRead: DWORD,

+                 lpNumberOfBytesRead: var DWORD, bAbort: WINBOOL,

+                 bProcessSecurity: WINBOOL, lpContext: var pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BackupRead".}

+proc BackupSeek*(hFile: THandle, dwLowBytesToSeek, dwHighBytesToSeek: DWORD,

+                 lpdwLowByteSeeked, lpdwHighByteSeeked: var DWORD,

+                 lpContext: pointer): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "BackupSeek".}

+proc BackupWrite*(hFile: THandle, lpBuffer: PByte, nNumberOfBytesToWrite: DWORD,

+                  lpNumberOfBytesWritten: var DWORD,

+                  bAbort, bProcessSecurity: WINBOOL, lpContext: var pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BackupWrite".}

+proc BeginPaint*(wnd: HWND, lpPaint: var TPaintStruct): HDC{.stdcall,

+    dynlib: "user32", importc: "BeginPaint".}

+proc BuildCommDCB*(lpDef: cstring, lpDCB: var TDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "BuildCommDCBA".}

+proc BuildCommDCBA*(lpDef: LPCSTR, lpDCB: var TDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "BuildCommDCBA".}

+proc BuildCommDCBAndTimeouts*(lpDef: cstring, lpDCB: var TDCB,

+                              lpCommTimeouts: var TCommTimeouts): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsA".}

+proc BuildCommDCBAndTimeoutsA*(lpDef: LPCSTR, lpDCB: var TDCB,

+                               lpCommTimeouts: var TCommTimeouts): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsA".}

+proc BuildCommDCBAndTimeoutsW*(lpDef: LPWSTR, lpDCB: var TDCB,

+                               lpCommTimeouts: var TCommTimeouts): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "BuildCommDCBAndTimeoutsW".}

+proc BuildCommDCBW*(lpDef: LPWSTR, lpDCB: var TDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "BuildCommDCBW".}

+proc CallMsgFilter*(lpMsg: var TMsg, nCode: int): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CallMsgFilterA".}

+proc CallMsgFilterA*(lpMsg: var TMsg, nCode: int): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CallMsgFilterA".}

+proc CallMsgFilterW*(lpMsg: var TMsg, nCode: int): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CallMsgFilterW".}

+proc CallNamedPipe*(lpNamedPipeName: cstring, lpInBuffer: pointer,

+                    nInBufferSize: DWORD, lpOutBuffer: pointer,

+                    nOutBufferSize: DWORD, lpBytesRead: var DWORD,

+                    nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CallNamedPipeA".}

+proc CallNamedPipeA*(lpNamedPipeName: LPCSTR, lpInBuffer: pointer,

+                     nInBufferSize: DWORD, lpOutBuffer: pointer,

+                     nOutBufferSize: DWORD, lpBytesRead: var DWORD,

+                     nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CallNamedPipeA".}

+proc CallNamedPipeW*(lpNamedPipeName: LPWSTR, lpInBuffer: pointer,

+                     nInBufferSize: DWORD, lpOutBuffer: pointer,

+                     nOutBufferSize: DWORD, lpBytesRead: var DWORD,

+                     nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "CallNamedPipeW".}

+proc CoRegisterClassObject*(para1: TCLSID, para2: pointer, para3: DWORD,

+                            para4: DWORD, out_para5: DWORD): HRESULT{.stdcall,

+    dynlib: "ole32.dll", importc: "CoRegisterClassObject".}

+proc ChangeDisplaySettings*(lpDevMode: var TDeviceMode, dwFlags: DWORD): int32{.

+    stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsA".}

+proc ChangeDisplaySettingsA*(lpDevMode: var TDeviceModeA, dwFlags: DWORD): int32{.

+    stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsA".}

+proc ChangeDisplaySettingsEx*(lpszDeviceName: cstring,

+                              lpDevMode: var TDeviceMode, wnd: HWND,

+                              dwFlags: DWORD, lParam: pointer): int32{.stdcall,

+    dynlib: "user32", importc: "ChangeDisplaySettingsExA".}

+proc ChangeDisplaySettingsExA*(lpszDeviceName: LPCSTR,

+                               lpDevMode: var TDeviceModeA, wnd: HWND,

+                               dwFlags: DWORD, lParam: pointer): int32{.stdcall,

+    dynlib: "user32", importc: "ChangeDisplaySettingsExA".}

+proc ChangeDisplaySettingsExW*(lpszDeviceName: LPWSTR,

+                               lpDevMode: var TDeviceModeW, wnd: HWND,

+                               dwFlags: DWORD, lParam: pointer): int32{.stdcall,

+    dynlib: "user32", importc: "ChangeDisplaySettingsExW".}

+proc ChangeDisplaySettingsW*(lpDevMode: var TDeviceModeW, dwFlags: DWORD): int32{.

+    stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsW".}

+  #function CheckColorsInGamut(DC: HDC; var RGBQuads, Results; Count: DWORD): WINBOOL; stdcall; external 'gdi32' name 'CheckColorsInGamut';

+proc ChoosePixelFormat*(para1: HDC, para2: var PIXELFORMATDESCRIPTOR): int32{.

+    stdcall, dynlib: "gdi32", importc: "ChoosePixelFormat".}

+proc ClearCommError*(hFile: THandle, lpErrors: var DWORD, lpStat: PComStat): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ClearCommError".}

+proc ClientToScreen*(wnd: HWND, lpPoint: var TPoint): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ClientToScreen".}

+proc ClipCursor*(lpRect: var RECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ClipCursor".}

+  #function CombineTransform(var p1: TXForm; const p2, p3: TXForm): WINBOOL; stdcall; external 'gdi32' name 'CombineTransform';

+proc CommConfigDialog*(lpszName: cstring, wnd: HWND, lpCC: var TCommConfig): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CommConfigDialogA".}

+proc CommConfigDialogA*(lpszName: LPCSTR, wnd: HWND, lpCC: var TCommConfig): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CommConfigDialogA".}

+proc CommConfigDialogW*(lpszName: LPWSTR, wnd: HWND, lpCC: var TCommConfig): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CommConfigDialogW".}

+  #function CompareFileTime(const lpFileTime1, lpFileTime2: TFileTime): Longint; stdcall; external 'kernel32' name 'CompareFileTime';

+  #function ConvertToAutoInheritPrivateObjectSecurity(ParentDescriptor, CurrentSecurityDescriptor: PSecurityDescriptor; var NewDescriptor: PSecurityDescriptor; ObjectType: PGUID; IsDirectoryObject: WINBOOL; const GenericMapping: TGenericMapping): WINBOOL;

+  #  stdcall; external 'advapi32' name 'ConvertToAutoInheritPrivateObjectSecurity';

+proc CopyAcceleratorTable*(hAccelSrc: HACCEL, lpAccelDst: pointer,

+                           cAccelEntries: int): int{.stdcall, dynlib: "user32",

+    importc: "CopyAcceleratorTableA".}

+proc CopyAcceleratorTableA*(hAccelSrc: HACCEL, lpAccelDst: pointer,

+                            cAccelEntries: int): int{.stdcall, dynlib: "user32",

+    importc: "CopyAcceleratorTableA".}

+proc CopyAcceleratorTableW*(hAccelSrc: HACCEL, lpAccelDst: pointer,

+                            cAccelEntries: int): int{.stdcall, dynlib: "user32",

+    importc: "CopyAcceleratorTableW".}

+proc CopyRect*(lprcDst: var TRect, lprcSrc: TRect): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CopyRect".}

+proc CreateAcceleratorTable*(Accel: pointer, Count: int): HACCEL{.stdcall,

+    dynlib: "user32", importc: "CreateAcceleratorTableA".}

+proc CreateAcceleratorTableA*(Accel: pointer, Count: int): HACCEL{.stdcall,

+    dynlib: "user32", importc: "CreateAcceleratorTableA".}

+proc CreateAcceleratorTableW*(Accel: pointer, Count: int): HACCEL{.stdcall,

+    dynlib: "user32", importc: "CreateAcceleratorTableW".}

+  #function CreateBitmapIndirect(const p1: TBitmap): HBITMAP; stdcall; external 'gdi32' name 'CreateBitmapIndirect';

+  #function CreateBrushIndirect(const p1: TLogBrush): HBRUSH; stdcall; external 'gdi32' name 'CreateBrushIndirect';

+proc CreateColorSpace*(ColorSpace: var TLogColorSpace): HCOLORSPACE{.stdcall,

+    dynlib: "gdi32", importc: "CreateColorSpaceA".}

+proc CreateColorSpaceA*(ColorSpace: var TLogColorSpaceA): HCOLORSPACE{.stdcall,

+    dynlib: "gdi32", importc: "CreateColorSpaceA".}

+  #function CreateColorSpaceW(var ColorSpace: TLogColorSpaceW): HCOLORSPACE; stdcall; external 'gdi32' name 'CreateColorSpaceW';

+proc CreateDialogIndirectParam*(hInstance: HINST, lpTemplate: TDlgTemplate,

+                                hWndParent: HWND, lpDialogFunc: TFNDlgProc,

+                                dwInitParam: LPARAM): HWND{.stdcall,

+    dynlib: "user32", importc: "CreateDialogIndirectParamA".}

+  #function CreateDialogIndirectParamA(hInstance: HINST; const lpTemplate: TDlgTemplate; hWndParent: HWND; lpDialogFunc: TFNDlgProc; dwInitParam: LPARAM): HWND; stdcall; external 'user32' name 'CreateDialogIndirectParamA';

+  #function CreateDialogIndirectParamW(hInstance: HINST; const lpTemplate: TDlgTemplate; hWndParent: HWND; lpDialogFunc: TFNDlgProc; dwInitParam: LPARAM): HWND; stdcall; external 'user32' name 'CreateDialogIndirectParamW';

+  #function CreateDIBitmap(DC: HDC; var InfoHeader: TBitmapInfoHeader; dwUsage: DWORD; InitBits: PChar; var InitInfo: TBitmapInfo; wUsage: WINUINT): HBITMAP; stdcall; external 'gdi32' name 'CreateDIBitmap';

+  #function CreateDIBPatternBrushPt(const p1: pointer; p2: WINUINT): HBRUSH; stdcall; external 'gdi32' name 'CreateDIBPatternBrushPt';

+  #function CreateDIBSection(DC: HDC; const p2: TBitmapInfo; p3: WINUINT; var p4: pointer; p5: THandle; p6: DWORD): HBITMAP; stdcall; external 'gdi32' name 'CreateDIBSection';

+  #function CreateEllipticRgnIndirect(const p1: TRect): HRGN; stdcall; external 'gdi32' name 'CreateEllipticRgnIndirect';

+  #function CreateFontIndirect(const p1: TLogFont): HFONT;stdcall; external 'gdi32' name 'CreateFontIndirectA';

+  #function CreateFontIndirectA(const p1: TLogFontA): HFONT; stdcall; external 'gdi32' name 'CreateFontIndirectA';

+  #function CreateFontIndirectEx(const p1: PEnumLogFontExDV): HFONT;stdcall; external 'gdi32' name 'CreateFontIndirectExA';

+  #function CreateFontIndirectExA(const p1: PEnumLogFontExDVA): HFONT;stdcall; external 'gdi32' name 'CreateFontIndirectExA';

+  #function CreateFontIndirectExW(const p1: PEnumLogFontExDVW): HFONT;stdcall; external 'gdi32' name 'CreateFontIndirectExW';

+  #function CreateFontIndirectW(const p1: TLogFontW): HFONT; stdcall; external 'gdi32' name 'CreateFontIndirectW';

+proc CreateIconIndirect*(piconinfo: var TIconInfo): HICON{.stdcall,

+    dynlib: "user32", importc: "CreateIconIndirect".}

+  #function CreatePalette(const LogPalette: TLogPalette): HPalette; stdcall; external 'gdi32' name 'CreatePalette';

+  #function CreatePenIndirect(const LogPen: TLogPen): HPEN; stdcall; external 'gdi32' name 'CreatePenIndirect';

+proc CreatePipe*(hReadPipe, hWritePipe: var THandle,

+                 lpPipeAttributes: PSecurityAttributes, nSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreatePipe".}

+proc CreatePolygonRgn*(Points: pointer, Count, FillMode: int): HRGN{.stdcall,

+    dynlib: "gdi32", importc: "CreatePolygonRgn".}

+proc CreatePolyPolygonRgn*(pPtStructs: pointer, pIntArray: pointer, p3, p4: int): HRGN{.

+    stdcall, dynlib: "gdi32", importc: "CreatePolyPolygonRgn".}

+  #function CreatePrivateObjectSecurity(ParentDescriptor, CreatorDescriptor: PSecurityDescriptor; var NewDescriptor: PSecurityDescriptor; IsDirectoryObject: WINBOOL; Token: THandle; const GenericMapping: TGenericMapping): WINBOOL;

+  #  stdcall; external 'advapi32' name 'CreatePrivateObjectSecurity';

+  #function CreatePrivateObjectSecurityEx(ParentDescriptor, CreatorDescriptor: PSecurityDescriptor; var NewDescriptor: PSecurityDescriptor; ObjectType: PGUID; IsContainerObject: WINBOOL; AutoInheritFlags: ULONG; Token: THandle;

+  #  const GenericMapping: TGenericMapping): WINBOOL;stdcall; external 'advapi32' name 'CreatePrivateObjectSecurityEx';

+proc CreateProcess*(lpApplicationName: cstring, lpCommandLine: cstring,

+    lpProcessAttributes, lpThreadAttributes: PSecurityAttributes,

+                    bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                    lpEnvironment: pointer, lpCurrentDirectory: cstring,

+                    lpStartupInfo: TStartupInfo,

+                    lpProcessInformation: var TProcessInformation): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateProcessA".}

+proc CreateProcessA*(lpApplicationName: LPCSTR, lpCommandLine: LPCSTR,

+    lpProcessAttributes, lpThreadAttributes: PSecurityAttributes,

+                     bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                     lpEnvironment: pointer, lpCurrentDirectory: LPCSTR,

+                     lpStartupInfo: TStartupInfo,

+                     lpProcessInformation: var TProcessInformation): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateProcessA".}

+  #function CreateProcessAsUser(hToken: THandle; lpApplicationName: PChar; lpCommandLine: PChar; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: WINBOOL; dwCreationFlags: DWORD;

+  # lpEnvironment: pointer; lpCurrentDirectory: PChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL;stdcall; external 'advapi32' name 'CreateProcessAsUserA';

+  #function CreateProcessAsUserA(hToken: THandle; lpApplicationName: LPCSTR; lpCommandLine: LPCSTR; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: WINBOOL; dwCreationFlags: DWORD;

+  #  lpEnvironment: pointer; lpCurrentDirectory: LPCSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL; stdcall; external 'advapi32' name 'CreateProcessAsUserA';

+  #function CreateProcessAsUserW(hToken: THandle; lpApplicationName: LPWSTR; lpCommandLine: LPWSTR; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: WINBOOL; dwCreationFlags: DWORD;

+  #  lpEnvironment: pointer; lpCurrentDirectory: LPWSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL; stdcall; external 'advapi32' name 'CreateProcessAsUserW';

+proc CreateProcessW*(lpApplicationName: LPWSTR, lpCommandLine: LPWSTR,

+    lpProcessAttributes, lpThreadAttributes: PSecurityAttributes,

+                     bInheritHandles: WINBOOL, dwCreationFlags: DWORD,

+                     lpEnvironment: pointer, lpCurrentDirectory: LPWSTR,

+                     lpStartupInfo: TStartupInfo,

+                     lpProcessInformation: var TProcessInformation): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateProcessW".}

+  #function CreateRectRgnIndirect(const p1: TRect): HRGN; stdcall; external 'gdi32' name 'CreateRectRgnIndirect';

+proc CreateRemoteThread*(hProcess: THandle, lpThreadAttributes: pointer,

+                         dwStackSize: DWORD,

+                         lpStartAddress: TFNThreadStartRoutine,

+                         lpParameter: pointer, dwCreationFlags: DWORD,

+                         lpThreadId: var DWORD): THandle{.stdcall,

+    dynlib: "kernel32", importc: "CreateRemoteThread".}

+proc CreateThread*(lpThreadAttributes: pointer, dwStackSize: DWORD,

+                   lpStartAddress: TFNThreadStartRoutine, lpParameter: pointer,

+                   dwCreationFlags: DWORD, lpThreadId: var DWORD): THandle{.

+    stdcall, dynlib: "kernel32", importc: "CreateThread".}

+proc DdeSetQualityOfService*(hWndClient: HWnd,

+                             pqosNew: TSecurityQualityOfService,

+                             pqosPrev: PSecurityQualityOfService): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DdeSetQualityOfService".}

+  #function DeleteAce(var pAcl: TACL; dwAceIndex: DWORD): WINBOOL; stdcall; external 'advapi32' name 'DeleteAce';

+proc DescribePixelFormat*(DC: HDC, p2: int, p3: WINUINT,

+                          p4: var TPixelFormatDescriptor): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "DescribePixelFormat".}

+  #function DestroyPrivateObjectSecurity(var ObjectDescriptor: PSecurityDescriptor): WINBOOL; stdcall; external 'advapi32' name 'DestroyPrivateObjectSecurity';

+proc DeviceIoControl*(hDevice: THandle, dwIoControlCode: DWORD,

+                      lpInBuffer: pointer, nInBufferSize: DWORD,

+                      lpOutBuffer: pointer, nOutBufferSize: DWORD,

+                      lpBytesReturned: var DWORD, lpOverlapped: POverlapped): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "DeviceIoControl".}

+proc DialogBoxIndirectParam*(hInstance: HINST, lpDialogTemplate: TDlgTemplate,

+                             hWndParent: HWND, lpDialogFunc: TFNDlgProc,

+                             dwInitParam: LPARAM): int{.stdcall,

+    dynlib: "user32", importc: "DialogBoxIndirectParamA".}

+proc DialogBoxIndirectParamA*(hInstance: HINST, lpDialogTemplate: TDlgTemplate,

+                              hWndParent: HWND, lpDialogFunc: TFNDlgProc,

+                              dwInitParam: LPARAM): int{.stdcall,

+    dynlib: "user32", importc: "DialogBoxIndirectParamA".}

+proc DialogBoxIndirectParamW*(hInstance: HINST, lpDialogTemplate: TDlgTemplate,

+                              hWndParent: HWND, lpDialogFunc: TFNDlgProc,

+                              dwInitParam: LPARAM): int{.stdcall,

+    dynlib: "user32", importc: "DialogBoxIndirectParamW".}

+proc DispatchMessage*(lpMsg: TMsg): int32{.stdcall, dynlib: "user32",

+    importc: "DispatchMessageA".}

+proc DispatchMessageA*(lpMsg: TMsg): int32{.stdcall, dynlib: "user32",

+    importc: "DispatchMessageA".}

+proc DispatchMessageW*(lpMsg: TMsg): int32{.stdcall, dynlib: "user32",

+    importc: "DispatchMessageW".}

+proc DosDateTimeToFileTime*(wFatDate, wFatTime: int16, lpFileTime: var TFileTime): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "DosDateTimeToFileTime".}

+proc DPtoLP*(DC: HDC, Points: pointer, Count: int): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "DPtoLP".}

+  # function DrawAnimatedRects(wnd: HWND; idAni: Integer; const lprcFrom, lprcTo: TRect): WINBOOL; stdcall; external 'user32' name 'DrawAnimatedRects';

+  #function DrawCaption(p1: HWND; p2: HDC; const p3: TRect; p4: WINUINT): WINBOOL; stdcall; external 'user32' name 'DrawCaption';

+proc DrawEdge*(hdc: HDC, qrc: var TRect, edge: WINUINT, grfFlags: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DrawEdge".}

+  #function DrawFocusRect(hDC: HDC; const lprc: TRect): WINBOOL; stdcall; external 'user32' name 'DrawFocusRect';

+proc DrawFrameControl*(DC: HDC, Rect: TRect, uType, uState: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "DrawFrameControl".}

+proc DrawText*(hDC: HDC, lpString: cstring, nCount: int, lpRect: var TRect,

+               uFormat: WINUINT): int{.stdcall, dynlib: "user32",

+                                    importc: "DrawTextA".}

+proc DrawTextA*(hDC: HDC, lpString: LPCSTR, nCount: int, lpRect: var TRect,

+                uFormat: WINUINT): int{.stdcall, dynlib: "user32",

+                                     importc: "DrawTextA".}

+proc DrawTextEx*(DC: HDC, lpchText: cstring, cchText: int, p4: var TRect,

+                 dwDTFormat: WINUINT, DTParams: PDrawTextParams): int{.stdcall,

+    dynlib: "user32", importc: "DrawTextExA".}

+proc DrawTextExA*(DC: HDC, lpchText: LPCSTR, cchText: int, p4: var TRect,

+                  dwDTFormat: WINUINT, DTParams: PDrawTextParams): int{.stdcall,

+    dynlib: "user32", importc: "DrawTextExA".}

+proc DrawTextExW*(DC: HDC, lpchText: LPWSTR, cchText: int, p4: var TRect,

+                  dwDTFormat: WINUINT, DTParams: PDrawTextParams): int{.stdcall,

+    dynlib: "user32", importc: "DrawTextExW".}

+proc DrawTextW*(hDC: HDC, lpString: LPWSTR, nCount: int, lpRect: var TRect,

+                uFormat: WINUINT): int{.stdcall, dynlib: "user32",

+                                     importc: "DrawTextW".}

+  #function DuplicateTokenEx(hExistingToken: THandle; dwDesiredAccess: DWORD; lpTokenAttributes: PSecurityAttributes; ImpersonationLevel: TSecurityImpersonationLevel; TokenType: TTokenType; var phNewToken: THandle): WINBOOL;

+  #  stdcall; external 'advapi32' name 'DuplicateTokenEx';

+proc EndPaint*(wnd: HWND, lpPaint: TPaintStruct): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EndPaint".}

+  #function EnumDisplayDevices(Unused: pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDevice; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesA';

+  #function EnumDisplayDevicesA(Unused: pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDeviceA; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesA';

+  #function EnumDisplayDevicesW(Unused: pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDeviceW; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesW';

+proc EnumDisplaySettings*(lpszDeviceName: cstring, iModeNum: DWORD,

+                          lpDevMode: var TDeviceMode): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EnumDisplaySettingsA".}

+proc EnumDisplaySettingsA*(lpszDeviceName: LPCSTR, iModeNum: DWORD,

+                           lpDevMode: var TDeviceModeA): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EnumDisplaySettingsA".}

+proc EnumDisplaySettingsW*(lpszDeviceName: LPWSTR, iModeNum: DWORD,

+                           lpDevMode: var TDeviceModeW): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "EnumDisplaySettingsW".}

+  #function EnumEnhMetaFile(DC: HDC; p2: HENHMETAFILE; p3: TFNEnhMFEnumProc; p4: pointer; const p5: TRect): WINBOOL; stdcall; external 'gdi32' name 'EnumEnhMetaFile';

+  #function EnumFontFamiliesEx(DC: HDC; var p2: TLogFont; p3: TFNFontEnumProc; p4: LPARAM; p5: DWORD): WINBOOL;stdcall; external 'gdi32' name 'EnumFontFamiliesExA';

+  #function EnumFontFamiliesExA(DC: HDC; var p2: TLogFontA; p3: TFNFontEnumProcA; p4: LPARAM; p5: DWORD): WINBOOL; stdcall; external 'gdi32' name 'EnumFontFamiliesExA';

+  #function EnumFontFamiliesExW(DC: HDC; var p2: TLogFontW; p3: TFNFontEnumProcW; p4: LPARAM; p5: DWORD): WINBOOL; stdcall; external 'gdi32' name 'EnumFontFamiliesExW';

+  #function EqualRect(const lprc1, lprc2: TRect): WINBOOL; stdcall; external 'user32' name 'EqualRect';

+proc ExtCreatePen*(PenStyle, Width: DWORD, Brush: TLogBrush, StyleCount: DWORD,

+                   Style: pointer): HPEN{.stdcall, dynlib: "gdi32",

+    importc: "ExtCreatePen".}

+proc ExtCreateRegion*(p1: PXForm, p2: DWORD, p3: TRgnData): HRGN{.stdcall,

+    dynlib: "gdi32", importc: "ExtCreateRegion".}

+  # function ExtEscape(DC: HDC; p2, p3: Integer; const p4: LPCSTR; p5: Integer; p6: LPSTR): Integer; stdcall; external 'gdi32' name 'ExtEscape';

+proc FileTimeToDosDateTime*(lpFileTime: TFileTime,

+                            lpFatDate, lpFatTime: var int16): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FileTimeToDosDateTime".}

+proc FileTimeToLocalFileTime*(lpFileTime: TFileTime,

+                              lpLocalFileTime: var TFileTime): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "FileTimeToLocalFileTime".}

+proc FileTimeToSystemTime*(lpFileTime: TFileTime, lpSystemTime: var TSystemTime): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FileTimeToSystemTime".}

+proc FillConsoleOutputAttribute*(hConsoleOutput: THandle, wAttribute: int16,

+                                 nLength: DWORD, dwWriteCoord: TCoord,

+                                 lpNumberOfAttrsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputAttribute".}

+proc FillConsoleOutputCharacter*(hConsoleOutput: THandle, cCharacter: char,

+                                 nLength: DWORD, dwWriteCoord: TCoord,

+                                 lpNumberOfCharsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".}

+proc FillConsoleOutputCharacterA*(hConsoleOutput: THandle, cCharacter: char,

+                                  nLength: DWORD, dwWriteCoord: TCoord,

+                                  lpNumberOfCharsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".}

+proc FillConsoleOutputCharacterW*(hConsoleOutput: THandle, cCharacter: WideChar,

+                                  nLength: DWORD, dwWriteCoord: TCoord,

+                                  lpNumberOfCharsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterW".}

+  #function FillRect(hDC: HDC; const lprc: TRect; hbr: HBRUSH): Integer; stdcall; external 'user32' name 'FillRect';

+proc FindFirstFile*(lpFileName: cstring, lpFindFileData: var TWIN32FindData): THandle{.

+    stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}

+proc FindFirstFileA*(lpFileName: LPCSTR, lpFindFileData: var TWIN32FindDataA): THandle{.

+    stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}

+proc FindFirstFileW*(lpFileName: LPWSTR, lpFindFileData: var TWIN32FindDataW): THandle{.

+    stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}

+  #function FindFirstFreeAce(var pAcl: TACL; var pAce: pointer): WINBOOL; stdcall; external 'advapi32' name 'FindFirstFreeAce';

+proc FindNextFile*(hFindFile: THandle, lpFindFileData: var TWIN32FindData): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FindNextFileA".}

+proc FindNextFileA*(hFindFile: THandle, lpFindFileData: var TWIN32FindDataA): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FindNextFileA".}

+proc FindNextFileW*(hFindFile: THandle, lpFindFileData: var TWIN32FindDataW): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "FindNextFileW".}

+  #function FlushInstructionCache(hProcess: THandle; const lpBaseAddress: pointer; dwSize: DWORD): WINBOOL; stdcall; external 'kernel32' name 'FlushInstructionCache';

+  #function FlushViewOfFile(const lpBaseAddress: pointer; dwNumberOfBytesToFlush: DWORD): WINBOOL; stdcall; external 'kernel32' name 'FlushViewOfFile';

+  #function FrameRect(hDC: HDC; const lprc: TRect; hbr: HBRUSH): Integer; stdcall; external 'user32' name 'FrameRect';

+  #function GetAce(const pAcl: TACL; dwAceIndex: DWORD; var pAce: pointer): WINBOOL; stdcall; external 'advapi32' name 'GetAce';

+  #function GetAclInformation(const pAcl: TACL; pAclInformation: pointer; nAclInformationLength: DWORD; dwAclInformationClass: TAclInformationClass): WINBOOL; stdcall; external 'advapi32' name 'GetAclInformation';

+  #function GetAltTabInfo(wnd: HWND; iItem: Integer; var pati: TAltTabInfo; pszItemText: PChar; cchItemText: WINUINT): WINBOOL;stdcall; external 'user32' name 'GetAltTabInfoA';

+  #function GetAltTabInfoA(wnd: HWND; iItem: Integer; var pati: TAltTabInfo; pszItemText: LPCSTR; cchItemText: WINUINT): WINBOOL;stdcall; external 'user32' name 'GetAltTabInfoA';

+  #function GetAltTabInfoW(wnd: HWND; iItem: Integer; var pati: TAltTabInfo; pszItemText: LPWSTR; cchItemText: WINUINT): WINBOOL;stdcall; external 'user32' name 'GetAltTabInfoW';

+proc GetAspectRatioFilterEx*(DC: HDC, p2: var TSize): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetAspectRatioFilterEx".}

+proc GetBinaryType*(lpApplicationName: cstring, lpBinaryType: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetBinaryTypeA".}

+proc GetBinaryTypeA*(lpApplicationName: LPCSTR, lpBinaryType: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetBinaryTypeA".}

+proc GetBinaryTypeW*(lpApplicationName: LPWSTR, lpBinaryType: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetBinaryTypeW".}

+proc GetBitmapDimensionEx*(p1: HBITMAP, p2: var TSize): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetBitmapDimensionEx".}

+proc GetBoundsRect*(DC: HDC, p2: var TRect, p3: WINUINT): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetBoundsRect".}

+proc GetBrushOrgEx*(DC: HDC, p2: var TPoint): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetBrushOrgEx".}

+proc GetCaretPos*(lpPoint: var TPoint): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetCaretPos".}

+proc GetCharABCWidths*(DC: HDC, p2, p3: WINUINT, ABCStructs: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsA".}

+proc GetCharABCWidthsA*(DC: HDC, p2, p3: WINUINT, ABCStructs: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsA".}

+proc GetCharABCWidthsFloat*(DC: HDC, p2, p3: WINUINT, ABCFloatSturcts: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsFloatA".}

+proc GetCharABCWidthsFloatA*(DC: HDC, p2, p3: WINUINT, ABCFloatSturcts: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsFloatA".}

+proc GetCharABCWidthsFloatW*(DC: HDC, p2, p3: WINUINT, ABCFloatSturcts: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsFloatW".}

+  #function GetCharABCWidthsI(DC: HDC; p2, p3: WINUINT; p4: PWORD; const Widths): WINBOOL;stdcall; external 'gdi32' name 'GetCharABCWidthsI';

+proc GetCharABCWidthsW*(DC: HDC, p2, p3: WINUINT, ABCStructs: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharABCWidthsW".}

+proc GetCharacterPlacement*(DC: HDC, p2: cstring, p3, p4: WINBOOL,

+                            p5: var TGCPResults, p6: DWORD): DWORD{.stdcall,

+    dynlib: "gdi32", importc: "GetCharacterPlacementA".}

+proc GetCharacterPlacementA*(DC: HDC, p2: LPCSTR, p3, p4: WINBOOL,

+                             p5: var TGCPResults, p6: DWORD): DWORD{.stdcall,

+    dynlib: "gdi32", importc: "GetCharacterPlacementA".}

+proc GetCharacterPlacementW*(DC: HDC, p2: LPWSTR, p3, p4: WINBOOL,

+                             p5: var TGCPResults, p6: DWORD): DWORD{.stdcall,

+    dynlib: "gdi32", importc: "GetCharacterPlacementW".}

+proc GetCharWidth*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharWidthA".}

+proc GetCharWidth32*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharWidth32A".}

+proc GetCharWidth32A*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharWidth32A".}

+proc GetCharWidth32W*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharWidth32W".}

+proc GetCharWidthA*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharWidthA".}

+proc GetCharWidthFloat*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatA".}

+proc GetCharWidthFloatA*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatA".}

+proc GetCharWidthFloatW*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetCharWidthFloatW".}

+  #function GetCharWidthI(DC: HDC; p2, p3: WINUINT; p4: PWORD; const Widths:pointer): WINBOOL;stdcall; external 'gdi32' name 'GetCharWidthI';

+proc GetCharWidthW*(DC: HDC, p2, p3: WINUINT, Widths: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetCharWidthW".}

+proc GetClassInfo*(hInstance: HINST, lpClassName: cstring,

+                   lpWndClass: var TWndClass): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetClassInfoA".}

+proc GetClassInfoA*(hInstance: HINST, lpClassName: LPCSTR,

+                    lpWndClass: var TWndClassA): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetClassInfoA".}

+proc GetClassInfoEx*(Instance: HINST, Classname: cstring,

+                     WndClass: var TWndClassEx): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetClassInfoExA".}

+  #function GetClassInfoExA(Instance: HINST; Classname: LPCSTR; var WndClass: TWndClassExA): WINBOOL; stdcall; external 'user32' name 'GetClassInfoExA';

+  #function GetClassInfoExW(Instance: HINST; Classname: LPWSTR; var WndClass: TWndClassExW): WINBOOL; stdcall; external 'user32' name 'GetClassInfoExW';

+  #function GetClassInfoW(hInstance: HINST; lpClassName: LPWSTR; var lpWndClass: TWndClassW): WINBOOL; stdcall; external 'user32' name 'GetClassInfoW';

+proc GetClientRect*(wnd: HWND, lpRect: var TRect): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetClientRect".}

+proc GetClipBox*(DC: HDC, Rect: var TRect): int{.stdcall, dynlib: "gdi32",

+    importc: "GetClipBox".}

+proc GetClipCursor*(lpRect: var TRect): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetClipCursor".}

+proc GetColorAdjustment*(DC: HDC, p2: var TColorAdjustment): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetColorAdjustment".}

+proc GetCommConfig*(hCommDev: THandle, lpCC: var TCommConfig,

+                    lpdwSize: var DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "GetCommConfig".}

+proc GetCommMask*(hFile: THandle, lpEvtMask: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetCommMask".}

+proc GetCommModemStatus*(hFile: THandle, lpModemStat: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetCommModemStatus".}

+proc GetCommProperties*(hFile: THandle, lpCommProp: var TCommProp): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetCommProperties".}

+proc GetCommState*(hFile: THandle, lpDCB: var TDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetCommState".}

+proc GetCommTimeouts*(hFile: THandle, lpCommTimeouts: var TCommTimeouts): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetCommTimeouts".}

+proc GetComputerName*(lpBuffer: cstring, nSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetComputerNameA".}

+proc GetComputerNameA*(lpBuffer: LPCSTR, nSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetComputerNameA".}

+proc GetComputerNameW*(lpBuffer: LPWSTR, nSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetComputerNameW".}

+proc GetConsoleCursorInfo*(hConsoleOutput: THandle,

+                           lpConsoleCursorInfo: var TConsoleCursorInfo): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetConsoleCursorInfo".}

+proc GetConsoleMode*(hConsoleHandle: THandle, lpMode: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetConsoleMode".}

+proc GetConsoleScreenBufferInfo*(hConsoleOutput: THandle,

+    lpConsoleScreenBufferInfo: var TConsoleScreenBufferInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetConsoleScreenBufferInfo".}

+proc GetCPInfo*(CodePage: WINUINT, lpCPInfo: var TCPInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetCPInfo".}

+  #function GetCurrentHwProfile(var lpHwProfileInfo: THWProfileInfo): WINBOOL;stdcall; external 'advapi32' name 'GetCurrentHwProfileA';

+  #function GetCurrentHwProfileA(var lpHwProfileInfo: THWProfileInfoA): WINBOOL;stdcall; external 'advapi32' name 'GetCurrentHwProfileA';

+  #function GetCurrentHwProfileW(var lpHwProfileInfo: THWProfileInfoW): WINBOOL;stdcall; external 'advapi32' name 'GetCurrentHwProfileW';

+proc GetCursorInfo*(pci: var TCursorInfo): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetCursorInfo".}

+proc GetCursorPos*(lpPoint: var TPoint): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "GetCursorPos".}

+proc GetDCOrgEx*(DC: HDC, Origin: var TPoint): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetDCOrgEx".}

+proc GetDefaultCommConfig*(lpszName: cstring, lpCC: var TCommConfig,

+                           lpdwSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDefaultCommConfigA".}

+proc GetDefaultCommConfigA*(lpszName: LPCSTR, lpCC: var TCommConfig,

+                            lpdwSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDefaultCommConfigA".}

+proc GetDefaultCommConfigW*(lpszName: LPWSTR, lpCC: var TCommConfig,

+                            lpdwSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetDefaultCommConfigW".}

+proc GetDIBColorTable*(DC: HDC, p2, p3: WINUINT, RGBQuadStructs: pointer): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "GetDIBColorTable".}

+proc GetDIBits*(DC: HDC, Bitmap: HBitmap, StartScan, NumScans: WINUINT,

+                Bits: pointer, BitInfo: var TBitmapInfo, Usage: WINUINT): int{.

+    stdcall, dynlib: "gdi32", importc: "GetDIBits".}

+proc GetDiskFreeSpace*(lpRootPathName: cstring, lpSectorsPerCluster,

+    lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceA".}

+proc GetDiskFreeSpaceA*(lpRootPathName: LPCSTR, lpSectorsPerCluster,

+    lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceA".}

+proc GetDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,

+    lpTotalNumberOfBytes: var TLargeInteger,

+                         lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}

+proc GetDiskFreeSpaceExA*(lpDirectoryName: LPCSTR, lpFreeBytesAvailableToCaller,

+    lpTotalNumberOfBytes: var TLargeInteger,

+                          lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}

+proc GetDiskFreeSpaceExW*(lpDirectoryName: LPWSTR, lpFreeBytesAvailableToCaller,

+    lpTotalNumberOfBytes: var TLargeInteger,

+                          lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExW".}

+proc GetDiskFreeSpaceW*(lpRootPathName: LPWSTR, lpSectorsPerCluster,

+    lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceW".}

+proc GetDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,

+    lpTotalNumberOfBytes: PLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}

+proc GetDiskFreeSpaceExA*(lpDirectoryName: LPCSTR, lpFreeBytesAvailableToCaller,

+    lpTotalNumberOfBytes: PLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}

+proc GetDiskFreeSpaceExW*(lpDirectoryName: LPWSTR, lpFreeBytesAvailableToCaller,

+    lpTotalNumberOfBytes: PLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExW".}

+  #function GetEnhMetaFilePixelFormat(p1: HENHMETAFILE; p2: Cardinal; var p3: TPixelFormatDescriptor): WINUINT;stdcall; external 'gdi32' name 'GetEnhMetaFilePixelFormat';

+proc GetExitCodeProcess*(hProcess: THandle, lpExitCode: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}

+proc GetExitCodeThread*(hThread: THandle, lpExitCode: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetExitCodeThread".}

+proc GetFileInformationByHandle*(hFile: THandle, lpFileInformation: var TByHandleFileInformation): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}

+  #function GetFileSecurity(lpFileName: PChar; RequestedInformation: SECURITY_INFORMATION; pSecurityDescriptor: PSecurityDescriptor; nLength: DWORD; var lpnLengthNeeded: DWORD): WINBOOL;stdcall; external 'advapi32' name 'GetFileSecurityA';

+  #function GetFileSecurityA(lpFileName: LPCSTR; RequestedInformation: SECURITY_INFORMATION; pSecurityDescriptor: PSecurityDescriptor; nLength: DWORD; var lpnLengthNeeded: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetFileSecurityA';

+  #function GetFileSecurityW(lpFileName: LPWSTR; RequestedInformation: SECURITY_INFORMATION; pSecurityDescriptor: PSecurityDescriptor; nLength: DWORD; var lpnLengthNeeded: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetFileSecurityW';

+proc GetFileVersionInfoSize*(lptstrFilename: cstring, lpdwHandle: var DWORD): DWORD{.

+    stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeA".}

+proc GetFileVersionInfoSizeA*(lptstrFilename: LPCSTR, lpdwHandle: var DWORD): DWORD{.

+    stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeA".}

+proc GetFileVersionInfoSizeW*(lptstrFilename: LPWSTR, lpdwHandle: var DWORD): DWORD{.

+    stdcall, dynlib: "version", importc: "GetFileVersionInfoSizeW".}

+  # removed because old definition was wrong !

+  # function GetFullPathName(lpFileName: PChar; nBufferLength: DWORD; lpBuffer: PChar; var lpFilePart: PChar): DWORD;stdcall; external 'kernel32' name 'GetFullPathNameA';

+  # function GetFullPathNameA(lpFileName: LPCSTR; nBufferLength: DWORD; lpBuffer: LPCSTR; var lpFilePart: LPCSTR): DWORD; stdcall; external 'kernel32' name 'GetFullPathNameA';

+  # function GetFullPathNameW(lpFileName: LPWSTR; nBufferLength: DWORD; lpBuffer: LPWSTR; var lpFilePart: LPWSTR): DWORD; stdcall; external 'kernel32' name 'GetFullPathNameW';

+proc GetGlyphOutline*(DC: HDC, p2, p3: WINUINT, p4: TGlyphMetrics, p5: DWORD,

+                      p6: pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GetGlyphOutlineA".}

+proc GetGlyphOutlineA*(DC: HDC, p2, p3: WINUINT, p4: TGlyphMetrics, p5: DWORD,

+                       p6: pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GetGlyphOutlineA".}

+proc GetGlyphOutlineW*(DC: HDC, p2, p3: WINUINT, p4: TGlyphMetrics, p5: DWORD,

+                       p6: pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32",

+    importc: "GetGlyphOutlineW".}

+  #function GetGUIThreadInfo(idThread: DWORD; var pgui: TGUIThreadinfo): WINBOOL;stdcall; external 'user32' name 'GetGUIThreadInfo';

+proc GetHandleInformation*(hObject: THandle, lpdwFlags: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetHandleInformation".}

+  #function GetICMProfile(DC: HDC; var Size: DWORD; Name: PChar): WINBOOL;stdcall; external 'gdi32' name 'GetICMProfileA';

+  #function GetICMProfileA(DC: HDC; var Size: DWORD; Name: LPCSTR): WINBOOL; stdcall; external 'gdi32' name 'GetICMProfileA';

+  #function GetICMProfileW(DC: HDC; var Size: DWORD; Name: LPWSTR): WINBOOL; stdcall; external 'gdi32' name 'GetICMProfileW';

+proc GetIconInfo*(icon: HICON, piconinfo: var TIconInfo): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetIconInfo".}

+  #function GetKernelObjectSecurity(Handle: THandle; RequestedInformation: SECURITY_INFORMATION; pSecurityDescriptor: PSecurityDescriptor; nLength: DWORD; var lpnLengthNeeded: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetKernelObjectSecurity';

+proc GetKerningPairs*(DC: HDC, Count: DWORD, KerningPairs: pointer): DWORD{.

+    stdcall, dynlib: "gdi32", importc: "GetKerningPairs".}

+proc GetKeyboardLayoutList*(nBuff: int, List: pointer): WINUINT{.stdcall,

+    dynlib: "user32", importc: "GetKeyboardLayoutList".}

+  #function GetKeyboardState(var KeyState: TKeyboardState): WINBOOL; stdcall; external 'user32' name 'GetKeyboardState';

+  #function GetLastInputInfo(var plii: TLastInputInfo): WINBOOL;stdcall; external 'user32' name 'GetLastInputInfo';

+proc GetSystemTime*(lpSystemTime: var SYSTEMTIME){.stdcall, dynlib: "kernel32",

+    importc: "GetSystemTime".}

+proc GetLocalTime*(SystemTime: var SYSTEMTIME){.stdcall, dynlib: "kernel32",

+    importc: "GetLocalTime".}

+proc GetSystemInfo*(SystemInfo: var SYSTEM_INFO){.stdcall, dynlib: "kernel32",

+    importc: "GetSystemInfo".}

+proc SetSystemTime*(lpSystemTime: var SYSTEMTIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetSystemTime".}

+proc SetLocalTime*(lpSystemTime: var SYSTEMTIME): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetLocalTime".}

+proc GetLogColorSpace*(p1: HCOLORSPACE, ColorSpace: var TLogColorSpace,

+                       Size: DWORD): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetLogColorSpaceA".}

+proc GetLogColorSpaceA*(p1: HCOLORSPACE, ColorSpace: var TLogColorSpaceA,

+                        Size: DWORD): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetLogColorSpaceA".}

+  #function GetLogColorSpaceW(p1: HCOLORSPACE; var ColorSpace: TLogColorSpaceW; Size: DWORD): WINBOOL; stdcall; external 'gdi32' name 'GetLogColorSpaceW';

+proc GetMailslotInfo*(hMailslot: THandle, lpMaxMessageSize: pointer,

+                      lpNextSize: var DWORD,

+                      lpMessageCount, lpReadTimeout: pointer): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetMailslotInfo".}

+  #function GetMenuBarInfo(hend: HWND; idObject, idItem: Longint; var pmbi: TMenuBarInfo): WINBOOL;stdcall; external 'user32' name 'GetMenuBarInfo';

+  #function GetMenuInfo(menu: HMENU; var lpmi: TMenuInfo): WINBOOL;stdcall; external 'user32' name 'GetMenuInfo';

+proc GetMenuItemInfo*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: var TMenuItemInfo): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetMenuItemInfoA".}

+proc GetMenuItemInfoA*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: var TMenuItemInfoA): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetMenuItemInfoA".}

+  #function GetMenuItemInfoW(p1: HMENU; p2: WINUINT; p3: WINBOOL; var p4: TMenuItemInfoW): WINBOOL; stdcall; external 'user32' name 'GetMenuItemInfoW';

+proc GetMenuItemRect*(wnd: HWND, menu: HMENU, uItem: WINUINT, lprcItem: var TRect): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetMenuItemRect".}

+proc GetMessage*(lpMsg: var TMsg, wnd: HWND, wMsgFilterMin, wMsgFilterMax: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetMessageA".}

+proc GetMessageA*(lpMsg: var TMsg, wnd: HWND,

+                  wMsgFilterMin, wMsgFilterMax: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetMessageA".}

+proc GetMessageW*(lpMsg: var TMsg, wnd: HWND,

+                  wMsgFilterMin, wMsgFilterMax: WINUINT): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetMessageW".}

+proc GetMiterLimit*(DC: HDC, Limit: var float32): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetMiterLimit".}

+  #function GetMouseMovePoints(cbSize: WINUINT; var lppt, lpptBuf: TMouseMovePoint; nBufPoints: Integer; resolution: DWORD): Integer;stdcall; external 'user32' name 'GetMouseMovePoints';

+proc GetNamedPipeInfo*(hNamedPipe: THandle, lpFlags: var DWORD,

+                       lpOutBufferSize, lpInBufferSize, lpMaxInstances: pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetNamedPipeInfo".}

+proc GetNumberOfConsoleInputEvents*(hConsoleInput: THandle,

+                                    lpNumberOfEvents: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetNumberOfConsoleInputEvents".}

+proc GetNumberOfConsoleMouseButtons*(lpNumberOfMouseButtons: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetNumberOfConsoleMouseButtons".}

+  #function GetNumberOfEventLogRecords(hEventLog: THandle; var NumberOfRecords: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetNumberOfEventLogRecords';

+  #function GetOldestEventLogRecord(hEventLog: THandle; var OldestRecord: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetOldestEventLogRecord';

+proc GetOverlappedResult*(hFile: THandle, lpOverlapped: TOverlapped,

+                          lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}

+proc GetPaletteEntries*(Palette: HPALETTE, StartIndex, NumEntries: WINUINT,

+                        PaletteEntries: pointer): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetPaletteEntries".}

+proc GetPath*(DC: HDC, Points, Types: pointer, nSize: int): int{.stdcall,

+    dynlib: "gdi32", importc: "GetPath".}

+proc GetPriorityClipboardFormat*(paFormatPriorityList: pointer, cFormats: int): int{.

+    stdcall, dynlib: "user32", importc: "GetPriorityClipboardFormat".}

+  #function GetPrivateObjectSecurity(ObjectDescriptor: PSecurityDescriptor; SecurityInformation: SECURITY_INFORMATION; ResultantDescriptor: PSecurityDescriptor; DescriptorLength: DWORD; var ReturnLength: DWORD): WINBOOL;

+  #  stdcall; external 'advapi32' name 'GetPrivateObjectSecurity';

+proc GetPrivateProfileSectionNamesA*(lpszReturnBuffer: LPSTR, nSize: DWORD,

+                                     lpFileName: LPCSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetPrivateProfileSectionNamesA".}

+proc GetPrivateProfileSectionNamesW*(lpszReturnBuffer: LPWSTR, nSize: DWORD,

+                                     lpFileName: LPCWSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetPrivateProfileSectionNamesW".}

+proc GetPrivateProfileSectionNames*(lpszReturnBuffer: LPTSTR, nSize: DWORD,

+                                    lpFileName: LPCTSTR): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetPrivateProfileSectionNamesA".}

+proc GetPrivateProfileStructA*(lpszSection, lpszKey: LPCSTR, lpStruct: LPVOID,

+                               uSizeStruct: WINUINT, szFile: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStructA".}

+proc GetPrivateProfileStructW*(lpszSection, lpszKey: LPCWSTR, lpStruct: LPVOID,

+                               uSizeStruct: WINUINT, szFile: LPCWSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStructW".}

+proc GetPrivateProfileStruct*(lpszSection, lpszKey: LPCTSTR, lpStruct: LPVOID,

+                              uSizeStruct: WINUINT, szFile: LPCTSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetPrivateProfileStructA".}

+proc GetProcessAffinityMask*(hProcess: THandle, lpProcessAffinityMask,

+    lpSystemAffinityMask: var DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "GetProcessAffinityMask".}

+proc GetProcessHeaps*(NumberOfHeaps: DWORD, ProcessHeaps: var THandle): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetProcessHeaps".}

+proc GetProcessPriorityBoost*(hThread: THandle,

+                              DisablePriorityBoost: var WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetProcessPriorityBoost".}

+proc GetProcessShutdownParameters*(lpdwLevel, lpdwFlags: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetProcessShutdownParameters".}

+proc GetProcessTimes*(hProcess: THandle, lpCreationTime, lpExitTime,

+    lpKernelTime, lpUserTime: var TFileTime): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetProcessTimes".}

+proc GetProcessWorkingSetSize*(hProcess: THandle, lpMinimumWorkingSetSize,

+    lpMaximumWorkingSetSize: var DWORD): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "GetProcessWorkingSetSize".}

+proc GetQueuedCompletionStatus*(CompletionPort: THandle,

+    lpNumberOfBytesTransferred, lpCompletionKey: var DWORD,

+                                lpOverlapped: var POverlapped,

+                                dwMilliseconds: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}

+proc GetRasterizerCaps*(p1: var TRasterizerStatus, p2: WINUINT): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetRasterizerCaps".}

+proc GetRgnBox*(RGN: HRGN, p2: var TRect): int{.stdcall, dynlib: "gdi32",

+    importc: "GetRgnBox".}

+proc GetScrollInfo*(wnd: HWND, BarFlag: int, ScrollInfo: var TScrollInfo): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetScrollInfo".}

+proc GetScrollRange*(wnd: HWND, nBar: int, lpMinPos, lpMaxPos: var int): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetScrollRange".}

+  #function GetSecurityDescriptorControl(pSecurityDescriptor: PSecurityDescriptor; var pControl: SECURITY_DESCRIPTOR_CONTROL; var lpdwRevision: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetSecurityDescriptorControl';

+  #function GetSecurityDescriptorDacl(pSecurityDescriptor: PSecurityDescriptor; var lpbDaclPresent: WINBOOL; var pDacl: PACL; var lpbDaclDefaulted: WINBOOL): WINBOOL; stdcall; external 'advapi32' name 'GetSecurityDescriptorDacl';

+  #function GetSecurityDescriptorGroup(pSecurityDescriptor: PSecurityDescriptor; var pGroup: PSID; var lpbGroupDefaulted: WINBOOL): WINBOOL; stdcall; external 'advapi32' name 'GetSecurityDescriptorGroup';

+  #function GetSecurityDescriptorOwner(pSecurityDescriptor: PSecurityDescriptor; var pOwner: PSID; var lpbOwnerDefaulted: WINBOOL): WINBOOL; stdcall; external 'advapi32' name 'GetSecurityDescriptorOwner';

+  #function GetSecurityDescriptorSacl(pSecurityDescriptor: PSecurityDescriptor; var lpbSaclPresent: WINBOOL; var pSacl: PACL; var lpbSaclDefaulted: WINBOOL): WINBOOL; stdcall; external 'advapi32' name 'GetSecurityDescriptorSacl';

+proc GetStartupInfo*(lpStartupInfo: var TSTARTUPINFO){.stdcall,

+    dynlib: "kernel32", importc: "GetStartupInfoA".}

+proc GetStringTypeA*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCSTR,

+                     cchSrc: WINBOOL, lpCharType: var int16): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeA".}

+proc GetStringTypeEx*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: cstring,

+                      cchSrc: int, lpCharType: var int16): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeExA".}

+proc GetStringTypeExA*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPCSTR,

+                       cchSrc: int, lpCharType: var int16): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeExA".}

+proc GetStringTypeExW*(Locale: LCID, dwInfoType: DWORD, lpSrcStr: LPWSTR,

+                       cchSrc: int, lpCharType: var int16): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeExW".}

+proc GetStringTypeW*(dwInfoType: DWORD, lpSrcStr: WCHAR, cchSrc: WINBOOL,

+                     lpCharType: var int16): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetStringTypeW".}

+proc GetSystemPaletteEntries*(DC: HDC, StartIndex, NumEntries: WINUINT,

+                              PaletteEntries: pointer): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "GetSystemPaletteEntries".}

+proc GetSystemPowerStatus*(lpSystemPowerStatus: var TSystemPowerStatus): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetSystemPowerStatus".}

+proc GetSystemTimeAdjustment*(lpTimeAdjustment, lpTimeIncrement: var DWORD,

+                              lpTimeAdjustmentDisabled: var WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetSystemTimeAdjustment".}

+proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME){.stdcall,

+    dynlib: "kernel32", importc: "GetSystemTimeAsFileTime".}

+proc GetTabbedTextExtent*(hDC: HDC, lpString: cstring,

+                          nCount, nTabPositions: int,

+                          lpnTabStopPositions: pointer): DWORD{.stdcall,

+    dynlib: "user32", importc: "GetTabbedTextExtentA".}

+proc GetTabbedTextExtentA*(hDC: HDC, lpString: LPCSTR,

+                           nCount, nTabPositions: int,

+                           lpnTabStopPositions: pointer): DWORD{.stdcall,

+    dynlib: "user32", importc: "GetTabbedTextExtentA".}

+proc GetTabbedTextExtentW*(hDC: HDC, lpString: LPWSTR,

+                           nCount, nTabPositions: int,

+                           lpnTabStopPositions: pointer): DWORD{.stdcall,

+    dynlib: "user32", importc: "GetTabbedTextExtentW".}

+proc GetTapeParameters*(hDevice: THandle, dwOperation: DWORD,

+                        lpdwSize: var DWORD, lpTapeInformation: pointer): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetTapeParameters".}

+proc GetTapePosition*(hDevice: THandle, dwPositionType: DWORD,

+                      lpdwPartition, lpdwOffsetLow: var DWORD,

+                      lpdwOffsetHigh: pointer): DWORD{.stdcall,

+    dynlib: "kernel32", importc: "GetTapePosition".}

+proc GetTextExtentExPoint*(DC: HDC, p2: cstring, p3, p4: int, p5, p6: PInteger,

+                           p7: var TSize): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentExPointA".}

+proc GetTextExtentExPointA*(DC: HDC, p2: LPCSTR, p3, p4: int, p5, p6: PInteger,

+                            p7: var TSize): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentExPointA".}

+  #function GetTextExtentExPointI(DC: HDC; p2: PWORD; p3, p4: Integer; p5, p6: PINT; var p7: TSize): WINBOOL;stdcall; external 'gdi32' name 'GetTextExtentExPointI';

+proc GetTextExtentExPointW*(DC: HDC, p2: LPWSTR, p3, p4: int, p5, p6: PInteger,

+                            p7: var TSize): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "GetTextExtentExPointW".}

+proc GetTextExtentPoint*(DC: HDC, Str: cstring, Count: int, Size: var TSize): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPointA".}

+proc GetTextExtentPoint32*(DC: HDC, Str: cstring, Count: int, Size: var TSize): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPoint32A".}

+proc GetTextExtentPoint32A*(DC: HDC, Str: LPCSTR, Count: int, Size: var TSize): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPoint32A".}

+proc GetTextExtentPoint32W*(DC: HDC, Str: LPWSTR, Count: int, Size: var TSize): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPoint32W".}

+proc GetTextExtentPointA*(DC: HDC, Str: LPCSTR, Count: int, Size: var TSize): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPointA".}

+  #function GetTextExtentPointI(DC: HDC; p2: PWORD; p3: Integer; var p4: TSize): WINBOOL;stdcall; external 'gdi32' name 'GetTextExtentPointI';

+proc GetTextExtentPointW*(DC: HDC, Str: LPWSTR, Count: int, Size: var TSize): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "GetTextExtentPointW".}

+proc GetTextMetrics*(DC: HDC, TM: var TTextMetric): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetTextMetricsA".}

+  #function GetTextMetricsA(DC: HDC; var TM: TTextMetricA): WINBOOL; stdcall; external 'gdi32' name 'GetTextMetricsA';

+  #function GetTextMetricsW(DC: HDC; var TM: TTextMetricW): WINBOOL; stdcall; external 'gdi32' name 'GetTextMetricsW';

+proc GetThreadContext*(hThread: THandle, lpContext: var TContext): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetThreadContext".}

+proc GetThreadPriorityBoost*(hThread: THandle, DisablePriorityBoost: var WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetThreadPriorityBoost".}

+proc GetThreadSelectorEntry*(hThread: THandle, dwSelector: DWORD,

+                             lpSelectorEntry: var TLDTEntry): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetThreadSelectorEntry".}

+proc GetThreadTimes*(hThread: THandle, lpCreationTime, lpExitTime, lpKernelTime,

+                                       lpUserTime: var TFileTime): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetThreadTimes".}

+proc GetTimeZoneInformation*(lpTimeZoneInformation: var TTimeZoneInformation): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "GetTimeZoneInformation".}

+  #function GetTitleBarInfo(wnd: HWND; var pti: TTitleBarInfo): WINBOOL;stdcall; external 'user32' name 'GetTitleBarInfo';

+  #function GetTokenInformation(TokenHandle: THandle; TokenInformationClass: TTokenInformationClass; TokenInformation: pointer; TokenInformationLength: DWORD; var ReturnLength: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetTokenInformation';

+proc GetUpdateRect*(wnd: HWND, lpRect: var TRect, bErase: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUpdateRect".}

+proc GetUserName*(lpBuffer: cstring, nSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetUserNameA".}

+proc GetUserNameA*(lpBuffer: LPCSTR, nSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetUserNameA".}

+proc GetUserNameW*(lpBuffer: LPWSTR, nSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "GetUserNameW".}

+proc GetUserObjectInformation*(hObj: THandle, nIndex: int, pvInfo: pointer,

+                               nLength: DWORD, lpnLengthNeeded: var DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUserObjectInformationA".}

+proc GetUserObjectInformationA*(hObj: THandle, nIndex: int, pvInfo: pointer,

+                                nLength: DWORD, lpnLengthNeeded: var DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUserObjectInformationA".}

+proc GetUserObjectInformationW*(hObj: THandle, nIndex: int, pvInfo: pointer,

+                                nLength: DWORD, lpnLengthNeeded: var DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "GetUserObjectInformationW".}

+proc GetUserObjectSecurity*(hObj: THandle, pSIRequested: var DWORD,

+                            pSID: PSecurityDescriptor, nLength: DWORD,

+                            lpnLengthNeeded: var DWORD): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetUserObjectSecurity".}

+proc GetVersionEx*(lpVersionInformation: var TOSVersionInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVersionExA".}

+proc GetVersionExA*(lpVersionInformation: var TOSVersionInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVersionExA".}

+proc GetVersionExW*(lpVersionInformation: var TOSVersionInfoW): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "GetVersionExW".}

+proc GetViewportExtEx*(DC: HDC, Size: var TSize): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetViewportExtEx".}

+proc GetViewportOrgEx*(DC: HDC, Point: var TPoint): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetViewportOrgEx".}

+proc GetVolumeInformation*(lpRootPathName: cstring, lpVolumeNameBuffer: cstring,

+                           nVolumeNameSize: DWORD, lpVolumeSerialNumber: PDWORD,

+    lpMaximumComponentLength, lpFileSystemFlags: var DWORD,

+                           lpFileSystemNameBuffer: cstring,

+                           nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVolumeInformationA".}

+proc GetVolumeInformationA*(lpRootPathName: LPCSTR, lpVolumeNameBuffer: LPCSTR,

+                            nVolumeNameSize: DWORD,

+                            lpVolumeSerialNumber: PDWORD,

+    lpMaximumComponentLength, lpFileSystemFlags: var DWORD,

+                            lpFileSystemNameBuffer: LPCSTR,

+                            nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVolumeInformationA".}

+proc GetVolumeInformationW*(lpRootPathName: LPWSTR, lpVolumeNameBuffer: LPWSTR,

+                            nVolumeNameSize: DWORD,

+                            lpVolumeSerialNumber: PDWORD,

+    lpMaximumComponentLength, lpFileSystemFlags: var DWORD,

+                            lpFileSystemNameBuffer: LPWSTR,

+                            nFileSystemNameSize: DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "GetVolumeInformationW".}

+proc GetWindowExtEx*(DC: HDC, Size: var TSize): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetWindowExtEx".}

+  #function GetWindowInfo(wnd: HWND; var pwi: TWindowInfo): WINBOOL;stdcall; external 'user32' name 'GetWindowInfo';

+proc GetWindowOrgEx*(DC: HDC, Point: var TPoint): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetWindowOrgEx".}

+proc GetWindowRect*(wnd: HWND, lpRect: var TRect): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "GetWindowRect".}

+proc GetWorldTransform*(DC: HDC, p2: var TXForm): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "GetWorldTransform".}

+  #function GradientFill(DC: HDC; var p2: TTriVertex; p3: ULONG; p4: pointer; p5, p6: ULONG): WINBOOL;stdcall; external 'gdi32' name 'GradientFill';

+proc GlobalMemoryStatus*(Buffer: var MEMORYSTATUS){.stdcall, dynlib: "kernel32",

+    importc: "GlobalMemoryStatus".}

+proc HeapWalk*(hHeap: THandle, lpEntry: var TProcessHeapEntry): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "HeapWalk".}

+proc ImageList_GetDragImage*(ppt: var POINT, pptHotspot: var POINT): HIMAGELIST{.

+    stdcall, dynlib: "comctl32", importc: "ImageList_GetDragImage".}

+proc InflateRect*(lprc: var TRect, dx, dy: int): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "InflateRect".}

+proc InitializeAcl*(pAcl: var TACL, nAclLength, dwAclRevision: DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "InitializeAcl".}

+proc InitializeSid*(Sid: pointer, pIdentifierAuthority: TSIDIdentifierAuthority,

+                    nSubAuthorityCount: int8): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "InitializeSid".}

+proc InsertMenuItemA*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: TMenuItemInfoA): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "InsertMenuItemA".}

+  #function InsertMenuItemW(p1: HMENU; p2: WINUINT; p3: WINBOOL; const p4: TMenuItemInfoW): WINBOOL; stdcall; external 'user32' name 'InsertMenuItemW';

+proc IntersectRect*(lprcDst: var TRect, lprcSrc1, lprcSrc2: TRect): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "IntersectRect".}

+  #function InvertRect(hDC: HDC; const lprc: TRect): WINBOOL; stdcall; external 'user32' name 'InvertRect';

+proc IsDialogMessage*(hDlg: HWND, lpMsg: var TMsg): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "IsDialogMessageA".}

+proc IsDialogMessageA*(hDlg: HWND, lpMsg: var TMsg): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "IsDialogMessageA".}

+proc IsDialogMessageW*(hDlg: HWND, lpMsg: var TMsg): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "IsDialogMessageW".}

+  #function IsRectEmpty(const lprc: TRect): WINBOOL; stdcall; external 'user32' name 'IsRectEmpty';

+proc IsValidAcl*(pAcl: TACL): WINBOOL{.stdcall, dynlib: "advapi32",

+                                       importc: "IsValidAcl".}

+proc LocalFileTimeToFileTime*(lpLocalFileTime: TFileTime,

+                              lpFileTime: var TFileTime): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "LocalFileTimeToFileTime".}

+proc LockFileEx*(hFile: THandle, dwFlags, dwReserved: DWORD,

+                 nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh: DWORD,

+                 lpOverlapped: TOverlapped): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "LockFileEx".}

+proc LogonUser*(lpszUsername, lpszDomain, lpszPassword: cstring,

+                dwLogonType, dwLogonProvider: DWORD, phToken: var THandle): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LogonUserA".}

+proc LogonUserA*(lpszUsername, lpszDomain, lpszPassword: LPCSTR,

+                 dwLogonType, dwLogonProvider: DWORD, phToken: var THandle): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LogonUserA".}

+proc LogonUserW*(lpszUsername, lpszDomain, lpszPassword: LPWSTR,

+                 dwLogonType, dwLogonProvider: DWORD, phToken: var THandle): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LogonUserW".}

+proc LookupAccountName*(lpSystemName, lpAccountName: cstring, Sid: PSID,

+                        cbSid: var DWORD, ReferencedDomainName: cstring,

+                        cbReferencedDomainName: var DWORD,

+                        peUse: var SID_NAME_USE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupAccountNameA".}

+proc LookupAccountNameA*(lpSystemName, lpAccountName: LPCSTR, Sid: PSID,

+                         cbSid: var DWORD, ReferencedDomainName: LPCSTR,

+                         cbReferencedDomainName: var DWORD,

+                         peUse: var SID_NAME_USE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupAccountNameA".}

+proc LookupAccountNameW*(lpSystemName, lpAccountName: LPWSTR, Sid: PSID,

+                         cbSid: var DWORD, ReferencedDomainName: LPWSTR,

+                         cbReferencedDomainName: var DWORD,

+                         peUse: var SID_NAME_USE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupAccountNameW".}

+proc LookupAccountSid*(lpSystemName: cstring, Sid: PSID, Name: cstring,

+                       cbName: var DWORD, ReferencedDomainName: cstring,

+                       cbReferencedDomainName: var DWORD,

+                       peUse: var SID_NAME_USE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupAccountSidA".}

+proc LookupAccountSidA*(lpSystemName: LPCSTR, Sid: PSID, Name: LPCSTR,

+                        cbName: var DWORD, ReferencedDomainName: LPCSTR,

+                        cbReferencedDomainName: var DWORD,

+                        peUse: var SID_NAME_USE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupAccountSidA".}

+proc LookupAccountSidW*(lpSystemName: LPWSTR, Sid: PSID, Name: LPWSTR,

+                        cbName: var DWORD, ReferencedDomainName: LPWSTR,

+                        cbReferencedDomainName: var DWORD,

+                        peUse: var SID_NAME_USE): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupAccountSidW".}

+proc LookupPrivilegeDisplayName*(lpSystemName, lpName: LPCSTR,

+                                 lpDisplayName: cstring,

+                                 cbDisplayName, lpLanguageId: var DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameA".}

+proc LookupPrivilegeDisplayNameA*(lpSystemName, lpName: LPCSTR,

+                                  lpDisplayName: LPCSTR,

+                                  cbDisplayName, lpLanguageId: var DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameA".}

+proc LookupPrivilegeDisplayNameW*(lpSystemName, lpName: LPCSTR,

+                                  lpDisplayName: LPWSTR,

+                                  cbDisplayName, lpLanguageId: var DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "LookupPrivilegeDisplayNameW".}

+proc LookupPrivilegeName*(lpSystemName: cstring, lpLuid: var TLargeInteger,

+                          lpName: cstring, cbName: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeNameA".}

+proc LookupPrivilegeNameA*(lpSystemName: LPCSTR, lpLuid: var TLargeInteger,

+                           lpName: LPCSTR, cbName: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeNameA".}

+proc LookupPrivilegeNameW*(lpSystemName: LPWSTR, lpLuid: var TLargeInteger,

+                           lpName: LPWSTR, cbName: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeNameW".}

+proc LookupPrivilegeValue*(lpSystemName, lpName: cstring,

+                           lpLuid: var TLargeInteger): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeValueA".}

+proc LookupPrivilegeValueA*(lpSystemName, lpName: LPCSTR,

+                            lpLuid: var TLargeInteger): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeValueA".}

+proc LookupPrivilegeValueW*(lpSystemName, lpName: LPWSTR,

+                            lpLuid: var TLargeInteger): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "LookupPrivilegeValueW".}

+proc LPtoDP*(DC: HDC, Points: pointer, Count: int): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "LPtoDP".}

+proc MakeAbsoluteSD*(pSelfRelativeSecurityDescriptor: PSecurityDescriptor,

+                     pAbsoluteSecurityDescriptor: PSecurityDescriptor,

+                     lpdwAbsoluteSecurityDescriptorSi: var DWORD,

+                     pDacl: var TACL, lpdwDaclSize: var DWORD, pSacl: var TACL,

+

+                     lpdwSaclSize: var DWORD, pOwner: PSID,

+                     lpdwOwnerSize: var DWORD, pPrimaryGroup: pointer,

+                     lpdwPrimaryGroupSize: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "MakeAbsoluteSD".}

+proc MakeSelfRelativeSD*(pAbsoluteSecurityDescriptor: PSecurityDescriptor,

+                         pSelfRelativeSecurityDescriptor: PSecurityDescriptor,

+                         lpdwBufferLength: var DWORD): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "MakeSelfRelativeSD".}

+proc MapDialogRect*(hDlg: HWND, lpRect: var TRect): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "MapDialogRect".}

+proc MapWindowPoints*(hWndFrom, hWndTo: HWND, lpPoints: pointer, cPoints: WINUINT): int{.

+    stdcall, dynlib: "user32", importc: "MapWindowPoints".}

+proc MessageBoxIndirect*(MsgBoxParams: TMsgBoxParams): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "MessageBoxIndirectA".}

+proc MessageBoxIndirectA*(MsgBoxParams: TMsgBoxParamsA): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "MessageBoxIndirectA".}

+  #function MessageBoxIndirectW(const MsgBoxParams: TMsgBoxParamsW): WINBOOL; stdcall; external 'user32' name 'MessageBoxIndirectW';

+  #function ModifyWorldTransform(DC: HDC; const p2: TXForm; p3: DWORD): WINBOOL; stdcall; external 'gdi32' name 'ModifyWorldTransform';

+proc MsgWaitForMultipleObjects*(nCount: DWORD, pHandles: pointer,

+                                fWaitAll: WINBOOL,

+                                dwMilliseconds, dwWakeMask: DWORD): DWORD{.

+    stdcall, dynlib: "user32", importc: "MsgWaitForMultipleObjects".}

+proc MsgWaitForMultipleObjectsEx*(nCount: DWORD, pHandles: pointer,

+                                  dwMilliseconds, dwWakeMask, dwFlags: DWORD): DWORD{.

+    stdcall, dynlib: "user32", importc: "MsgWaitForMultipleObjectsEx".}

+  # function MultiByteToWideChar(CodePage: WINUINT; dwFlags: DWORD; const lpMultiByteStr: LPCSTR; cchMultiByte: Integer; lLPWSTRStr: LPWSTR; cchWideChar: Integer): Integer; stdcall; external 'kernel32' name 'MultiByteToWideChar';

+proc ObjectOpenAuditAlarm*(SubsystemName: cstring, HandleId: pointer,

+                           ObjectTypeName: cstring, ObjectName: cstring,

+                           pSecurityDescriptor: PSecurityDescriptor,

+                           ClientToken: THandle,

+                           DesiredAccess, GrantedAccess: DWORD,

+                           Privileges: var TPrivilegeSet,

+                           ObjectCreation, AccessGranted: WINBOOL,

+                           GenerateOnClose: var WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectOpenAuditAlarmA".}

+proc ObjectOpenAuditAlarmA*(SubsystemName: LPCSTR, HandleId: pointer,

+                            ObjectTypeName: LPCSTR, ObjectName: LPCSTR,

+                            pSecurityDescriptor: PSecurityDescriptor,

+                            ClientToken: THandle,

+                            DesiredAccess, GrantedAccess: DWORD,

+                            Privileges: var TPrivilegeSet,

+                            ObjectCreation, AccessGranted: WINBOOL,

+                            GenerateOnClose: var WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectOpenAuditAlarmA".}

+proc ObjectOpenAuditAlarmW*(SubsystemName: LPWSTR, HandleId: pointer,

+                            ObjectTypeName: LPWSTR, ObjectName: LPWSTR,

+                            pSecurityDescriptor: PSecurityDescriptor,

+                            ClientToken: THandle,

+                            DesiredAccess, GrantedAccess: DWORD,

+                            Privileges: var TPrivilegeSet,

+                            ObjectCreation, AccessGranted: WINBOOL,

+                            GenerateOnClose: var WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectOpenAuditAlarmW".}

+proc ObjectPrivilegeAuditAlarm*(SubsystemName: cstring, HandleId: pointer,

+                                ClientToken: THandle, DesiredAccess: DWORD,

+                                Privileges: var TPrivilegeSet,

+                                AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmA".}

+proc ObjectPrivilegeAuditAlarmA*(SubsystemName: LPCSTR, HandleId: pointer,

+                                 ClientToken: THandle, DesiredAccess: DWORD,

+                                 Privileges: var TPrivilegeSet,

+                                 AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmA".}

+proc ObjectPrivilegeAuditAlarmW*(SubsystemName: LPWSTR, HandleId: pointer,

+                                 ClientToken: THandle, DesiredAccess: DWORD,

+                                 Privileges: var TPrivilegeSet,

+                                 AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmW".}

+proc OffsetRect*(lprc: var TRect, dx, dy: int): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "OffsetRect".}

+proc OffsetViewportOrgEx*(DC: HDC, X, Y: int, Points: pointer): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "OffsetViewportOrgEx".}

+proc OffsetWindowOrgEx*(DC: HDC, X, Y: int, Points: pointer): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "OffsetWindowOrgEx".}

+proc OpenFile*(lpFileName: LPCSTR, lpReOpenBuff: var TOFStruct, uStyle: WINUINT): HFILE{.

+    stdcall, dynlib: "kernel32", importc: "OpenFile".}

+proc OpenProcessToken*(ProcessHandle: THandle, DesiredAccess: DWORD,

+                       TokenHandle: var THandle): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "OpenProcessToken".}

+proc OpenThreadToken*(ThreadHandle: THandle, DesiredAccess: DWORD,

+                      OpenAsSelf: WINBOOL, TokenHandle: var THandle): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "OpenThreadToken".}

+proc PeekConsoleInput*(hConsoleInput: THandle, lpBuffer: var TInputRecord,

+                       nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "PeekConsoleInputA".}

+proc PeekConsoleInputA*(hConsoleInput: THandle, lpBuffer: var TInputRecord,

+                        nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "PeekConsoleInputA".}

+proc PeekConsoleInputW*(hConsoleInput: THandle, lpBuffer: var TInputRecord,

+                        nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "PeekConsoleInputW".}

+proc PeekMessage*(lpMsg: var TMsg, wnd: HWND,

+                  wMsgFilterMin, wMsgFilterMax, wRemoveMsg: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "PeekMessageA".}

+proc PeekMessageA*(lpMsg: var TMsg, wnd: HWND,

+                   wMsgFilterMin, wMsgFilterMax, wRemoveMsg: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "PeekMessageA".}

+proc PeekMessageW*(lpMsg: var TMsg, wnd: HWND,

+                   wMsgFilterMin, wMsgFilterMax, wRemoveMsg: WINUINT): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "PeekMessageW".}

+  #function PlayEnhMetaFile(DC: HDC; p2: HENHMETAFILE; const p3: TRect): WINBOOL; stdcall; external 'gdi32' name 'PlayEnhMetaFile';

+proc PlayEnhMetaFileRecord*(DC: HDC, p2: var THandleTable, p3: TEnhMetaRecord,

+                            p4: WINUINT): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "PlayEnhMetaFileRecord".}

+proc PlayMetaFileRecord*(DC: HDC, p2: THandleTable, p3: TMetaRecord, p4: WINUINT): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PlayMetaFileRecord".}

+proc PlgBlt*(DC: HDC, PointsArray: pointer, p3: HDC, p4, p5, p6, p7: int,

+             p8: HBITMAP, p9, p10: int): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "PlgBlt".}

+proc PolyBezier*(DC: HDC, Points: pointer, Count: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolyBezier".}

+proc PolyBezierTo*(DC: HDC, Points: pointer, Count: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolyBezierTo".}

+proc PolyDraw*(DC: HDC, Points, Types: pointer, cCount: int): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolyDraw".}

+proc Polygon*(DC: HDC, Points: pointer, Count: int): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "Polygon".}

+proc Polyline*(DC: HDC, Points: pointer, Count: int): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "Polyline".}

+proc PolyLineTo*(DC: HDC, Points: pointer, Count: DWORD): WINBOOL{.stdcall,

+    dynlib: "gdi32", importc: "PolylineTo".}

+proc PolyPolygon*(DC: HDC, Points: pointer, nPoints: pointer, p4: int): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyPolygon".}

+proc PolyPolyline*(DC: HDC, PointStructs: pointer, Points: pointer, p4: DWORD): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyPolyline".}

+proc PolyTextOut*(DC: HDC, PolyTextArray: pointer, Strings: int): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyTextOutA".}

+proc PolyTextOutA*(DC: HDC, PolyTextArray: pointer, Strings: int): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyTextOutA".}

+proc PolyTextOutW*(DC: HDC, PolyTextArray: pointer, Strings: int): WINBOOL{.

+    stdcall, dynlib: "gdi32", importc: "PolyTextOutW".}

+proc PrivilegeCheck*(ClientToken: THandle, RequiredPrivileges: TPrivilegeSet,

+                     pfResult: var WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "PrivilegeCheck".}

+proc PrivilegedServiceAuditAlarm*(SubsystemName, ServiceName: cstring,

+                                  ClientToken: THandle,

+                                  Privileges: var TPrivilegeSet,

+                                  AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmA".}

+proc PrivilegedServiceAuditAlarmA*(SubsystemName, ServiceName: LPCSTR,

+                                   ClientToken: THandle,

+                                   Privileges: var TPrivilegeSet,

+                                   AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmA".}

+proc PrivilegedServiceAuditAlarmW*(SubsystemName, ServiceName: LPWSTR,

+                                   ClientToken: THandle,

+                                   Privileges: var TPrivilegeSet,

+                                   AccessGranted: WINBOOL): WINBOOL{.stdcall,

+    dynlib: "advapi32", importc: "PrivilegedServiceAuditAlarmW".}

+  #function PtInRect(const lprc: TRect; pt: TPoint): WINBOOL; stdcall; external 'user32' name 'PtInRect';

+proc QueryPerformanceCounter*(lpPerformanceCount: var TLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "QueryPerformanceCounter".}

+proc QueryPerformanceFrequency*(lpFrequency: var TLargeInteger): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "QueryPerformanceFrequency".}

+  #function QueryRecoveryAgents(p1: PChar; var p2: pointer; var p3: TRecoveryAgentInformation): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsA';

+  #function QueryRecoveryAgentsA(p1: LPCSTR; var p2: pointer; var p3: TRecoveryAgentInformationA): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsA';

+  #function QueryRecoveryAgentsW(p1: LPWSTR; var p2: pointer; var p3: TRecoveryAgentInformationW): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsW';

+proc RaiseException*(dwExceptionCode: DWORD, dwExceptionFlags: DWORD,

+                     nNumberOfArguments: DWORD, lpArguments: var DWORD){.

+    stdcall, dynlib: "kernel32", importc: "RaiseException".}

+proc UnhandledExceptionFilter*(ExceptionInfo: var emptyrecord): LONG{.stdcall,

+    dynlib: "kernel32", importc: "UnhandledExceptionFilter".}

+proc ReadConsole*(hConsoleInput: THandle, lpBuffer: pointer,

+                  nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: var DWORD,

+                  lpReserved: pointer): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ReadConsoleA".}

+proc ReadConsoleA*(hConsoleInput: THandle, lpBuffer: pointer,

+                   nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: var DWORD,

+                   lpReserved: pointer): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ReadConsoleA".}

+proc ReadConsoleInput*(hConsoleInput: THandle, lpBuffer: var TInputRecord,

+                       nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleInputA".}

+proc ReadConsoleInputA*(hConsoleInput: THandle, lpBuffer: var TInputRecord,

+                        nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleInputA".}

+proc ReadConsoleInputW*(hConsoleInput: THandle, lpBuffer: var TInputRecord,

+                        nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".}

+proc ReadConsoleOutput*(hConsoleOutput: THandle, lpBuffer: pointer,

+                        dwBufferSize, dwBufferCoord: TCoord,

+                        lpReadRegion: var TSmallRect): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadConsoleOutputA".}

+proc ReadConsoleOutputA*(hConsoleOutput: THandle, lpBuffer: pointer,

+                         dwBufferSize, dwBufferCoord: TCoord,

+                         lpReadRegion: var TSmallRect): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadConsoleOutputA".}

+proc ReadConsoleOutputAttribute*(hConsoleOutput: THandle, lpAttribute: pointer,

+                                 nLength: DWORD, dwReadCoord: TCoord,

+                                 lpNumberOfAttrsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputAttribute".}

+proc ReadConsoleOutputCharacter*(hConsoleOutput: THandle, lpCharacter: LPCSTR,

+                                 nLength: DWORD, dwReadCoord: TCoord,

+                                 lpNumberOfCharsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterA".}

+proc ReadConsoleOutputCharacterA*(hConsoleOutput: THandle, lpCharacter: LPCSTR,

+                                  nLength: DWORD, dwReadCoord: TCoord,

+                                  lpNumberOfCharsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterA".}

+proc ReadConsoleOutputCharacterW*(hConsoleOutput: THandle, lpCharacter: LPCSTR,

+                                  nLength: DWORD, dwReadCoord: TCoord,

+                                  lpNumberOfCharsRead: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterW".}

+proc ReadConsoleOutputW*(hConsoleOutput: THandle, lpBuffer: pointer,

+                         dwBufferSize, dwBufferCoord: TCoord,

+                         lpReadRegion: var TSmallRect): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadConsoleOutputW".}

+proc ReadConsoleW*(hConsoleInput: THandle, lpBuffer: pointer,

+                   nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: var DWORD,

+                   lpReserved: pointer): WINBOOL{.stdcall, dynlib: "kernel32",

+    importc: "ReadConsoleW".}

+proc ReadEventLog*(hEventLog: THandle, dwReadFlags, dwRecordOffset: DWORD,

+                   lpBuffer: pointer, nNumberOfBytesToRead: DWORD,

+                   pnBytesRead, pnMinNumberOfBytesNeeded: var DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ReadEventLogA".}

+proc ReadEventLogA*(hEventLog: THandle, dwReadFlags, dwRecordOffset: DWORD,

+                    lpBuffer: pointer, nNumberOfBytesToRead: DWORD,

+                    pnBytesRead, pnMinNumberOfBytesNeeded: var DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ReadEventLogA".}

+proc ReadEventLogW*(hEventLog: THandle, dwReadFlags, dwRecordOffset: DWORD,

+                    lpBuffer: pointer, nNumberOfBytesToRead: DWORD,

+                    pnBytesRead, pnMinNumberOfBytesNeeded: var DWORD): WINBOOL{.

+    stdcall, dynlib: "advapi32", importc: "ReadEventLogW".}

+proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: DWORD,

+               lpNumberOfBytesRead: var DWORD, lpOverlapped: POverlapped): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadFile".}

+proc ReadProcessMemory*(hProcess: THandle, lpBaseAddress: pointer,

+                        lpBuffer: pointer, nSize: DWORD,

+                        lpNumberOfBytesRead: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ReadProcessMemory".}

+  #function RectInRegion(RGN: HRGN; const p2: TRect): WINBOOL; stdcall; external 'gdi32' name 'RectInRegion';

+  #function RectVisible(DC: HDC; const Rect: TRect): WINBOOL; stdcall; external 'gdi32' name 'RectVisible';

+proc RegConnectRegistry*(lpMachineName: cstring, key: HKEY, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegConnectRegistryA".}

+proc RegConnectRegistryA*(lpMachineName: LPCSTR, key: HKEY, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegConnectRegistryA".}

+proc RegConnectRegistryW*(lpMachineName: LPWSTR, key: HKEY, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegConnectRegistryW".}

+proc RegCreateKey*(key: HKEY, lpSubKey: cstring, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyA".}

+proc RegCreateKeyA*(key: HKEY, lpSubKey: LPCSTR, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyA".}

+proc RegCreateKeyEx*(key: HKEY, lpSubKey: cstring, Reserved: DWORD,

+                     lpClass: cstring, dwOptions: DWORD, samDesired: REGSAM,

+                     lpSecurityAttributes: PSecurityAttributes,

+                     phkResult: var HKEY, lpdwDisposition: PDWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyExA".}

+proc RegCreateKeyExA*(key: HKEY, lpSubKey: LPCSTR, Reserved: DWORD,

+                      lpClass: LPCSTR, dwOptions: DWORD, samDesired: REGSAM,

+                      lpSecurityAttributes: PSecurityAttributes,

+                      phkResult: var HKEY, lpdwDisposition: PDWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyExA".}

+proc RegCreateKeyExW*(key: HKEY, lpSubKey: LPWSTR, Reserved: DWORD,

+                      lpClass: LPWSTR, dwOptions: DWORD, samDesired: REGSAM,

+                      lpSecurityAttributes: PSecurityAttributes,

+                      phkResult: var HKEY, lpdwDisposition: PDWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyExW".}

+proc RegCreateKeyW*(key: HKEY, lpSubKey: LPWSTR, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegCreateKeyW".}

+proc RegEnumKeyEx*(key: HKEY, dwIndex: DWORD, lpName: cstring,

+                   lpcbName: var DWORD, lpReserved: pointer, lpClass: cstring,

+                   lpcbClass: PDWORD, lpftLastWriteTime: PFileTime): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyExA".}

+proc RegEnumKeyExA*(key: HKEY, dwIndex: DWORD, lpName: LPCSTR,

+                    lpcbName: var DWORD, lpReserved: pointer, lpClass: LPCSTR,

+                    lpcbClass: PDWORD, lpftLastWriteTime: PFileTime): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyExA".}

+proc RegEnumKeyExW*(key: HKEY, dwIndex: DWORD, lpName: LPWSTR,

+                    lpcbName: var DWORD, lpReserved: pointer, lpClass: LPWSTR,

+                    lpcbClass: PDWORD, lpftLastWriteTime: PFileTime): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumKeyExW".}

+proc RegEnumValue*(key: HKEY, dwIndex: DWORD, lpValueName: cstring,

+                   lpcbValueName: var DWORD, lpReserved: pointer,

+                   lpType: PDWORD, lpData: PByte, lpcbData: PDWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumValueA".}

+proc RegEnumValueA*(key: HKEY, dwIndex: DWORD, lpValueName: cstring,

+                    lpcbValueName: var DWORD, lpReserved: pointer,

+                    lpType: PDWORD, lpData: PByte, lpcbData: PDWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumValueA".}

+proc RegEnumValueW*(key: HKEY, dwIndex: DWORD, lpValueName: cstring,

+                    lpcbValueName: var DWORD, lpReserved: pointer,

+                    lpType: PDWORD, lpData: PByte, lpcbData: PDWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegEnumValueW".}

+proc RegGetKeySecurity*(key: HKEY, SecurityInformation: SECURITY_INFORMATION,

+                        pSecurityDescriptor: PSecurityDescriptor,

+                        lpcbSecurityDescriptor: var DWORD): int32{.stdcall,

+    dynlib: "advapi32", importc: "RegGetKeySecurity".}

+proc RegSetValueEx*(key: HKEY, lpValueName: LPCSTR, Reserved: DWORD,

+                    dwType: DWORD, lpData: pointer, cbData: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegSetValueExA".}

+proc RegSetValueExA*(key: HKEY, lpValueName: LPCSTR, Reserved: DWORD,

+                     dwType: DWORD, lpData: pointer, cbData: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegSetValueExA".}

+proc RegSetValueExW*(key: HKEY, lpValueName: LPCWSTR, Reserved: DWORD,

+                     dwType: DWORD, lpData: pointer, cbData: DWORD): LONG{.

+    stdcall, dynlib: "advapi32", importc: "RegSetValueExW".}

+proc RegisterClass*(lpWndClass: TWndClass): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassA".}

+proc RegisterClassA*(lpWndClass: TWndClassA): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassA".}

+proc RegisterClassEx*(WndClass: TWndClassEx): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassExA".}

+proc RegisterClassExA*(WndClass: TWndClassExA): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassExA".}

+proc RegisterClassExW*(WndClass: TWndClassExW): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassExW".}

+proc RegisterClassW*(lpWndClass: TWndClassW): ATOM{.stdcall, dynlib: "user32",

+    importc: "RegisterClassW".}

+proc RegOpenKey*(key: HKEY, lpSubKey: cstring, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegOpenKeyA".}

+proc RegOpenKeyA*(key: HKEY, lpSubKey: LPCSTR, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegOpenKeyA".}

+proc RegOpenKeyEx*(key: HKEY, lpSubKey: cstring, ulOptions: DWORD,

+                   samDesired: REGSAM, phkResult: var HKEY): int32{.stdcall,

+    dynlib: "advapi32", importc: "RegOpenKeyExA".}

+proc RegOpenKeyExA*(key: HKEY, lpSubKey: LPCSTR, ulOptions: DWORD,

+                    samDesired: REGSAM, phkResult: var HKEY): int32{.stdcall,

+    dynlib: "advapi32", importc: "RegOpenKeyExA".}

+proc RegOpenKeyExW*(key: HKEY, lpSubKey: LPWSTR, ulOptions: DWORD,

+                    samDesired: REGSAM, phkResult: var HKEY): int32{.stdcall,

+    dynlib: "advapi32", importc: "RegOpenKeyExW".}

+proc RegOpenKeyW*(key: HKEY, lpSubKey: LPWSTR, phkResult: var HKEY): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegOpenKeyW".}

+proc RegQueryMultipleValues*(key: HKEY, ValList: pointer, NumVals: DWORD,

+                             lpValueBuf: cstring, ldwTotsize: var DWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesA".}

+proc RegQueryMultipleValuesA*(key: HKEY, ValList: pointer, NumVals: DWORD,

+                              lpValueBuf: LPCSTR, ldwTotsize: var DWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesA".}

+proc RegQueryMultipleValuesW*(key: HKEY, ValList: pointer, NumVals: DWORD,

+                              lpValueBuf: LPWSTR, ldwTotsize: var DWORD): int32{.

+    stdcall, dynlib: "advapi32", importc: "RegQueryMultipleValuesW".}

+proc RegQueryValue*(key: HKEY, lpSubKey: cstring, lpValue: cstring,

+                    lpcbValue: var int32): int32{.stdcall, dynlib: "advapi32",

+    importc: "RegQueryValueA".}

+proc RegQueryValueA*(key: HKEY, lpSubKey: LPCSTR, lpValue: LPCSTR,

+                     lpcbValue: var int32): int32{.stdcall, dynlib: "advapi32",

+    importc: "RegQueryValueA".}

+proc RegQueryValueW*(key: HKEY, lpSubKey: LPWSTR, lpValue: LPWSTR,

+                     lpcbValue: var int32): int32{.stdcall, dynlib: "advapi32",

+    importc: "RegQueryValueW".}

+proc ResetDC*(DC: HDC, p2: TDeviceMode): HDC{.stdcall, dynlib: "gdi32",

+    importc: "ResetDCA".}

+proc ResetDCA*(DC: HDC, p2: TDeviceModeA): HDC{.stdcall, dynlib: "gdi32",

+    importc: "ResetDCA".}

+  #function ResetDCW(DC: HDC; const p2: TDeviceModeW): HDC; stdcall; external 'gdi32' name 'ResetDCW';

+proc ScreenToClient*(wnd: HWND, lpPoint: var TPoint): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "ScreenToClient".}

+proc ScrollConsoleScreenBuffer*(hConsoleOutput: THandle,

+                                lpScrollRectangle: TSmallRect,

+                                lpClipRectangle: TSmallRect,

+                                dwDestinationOrigin: TCoord,

+                                lpFill: var TCharInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ScrollConsoleScreenBufferA".}

+proc ScrollConsoleScreenBufferA*(hConsoleOutput: THandle,

+                                 lpScrollRectangle: TSmallRect,

+                                 lpClipRectangle: TSmallRect,

+                                 dwDestinationOrigin: TCoord,

+                                 lpFill: var TCharInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ScrollConsoleScreenBufferA".}

+proc ScrollConsoleScreenBufferW*(hConsoleOutput: THandle,

+                                 lpScrollRectangle: TSmallRect,

+                                 lpClipRectangle: TSmallRect,

+                                 dwDestinationOrigin: TCoord,

+                                 lpFill: var TCharInfo): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "ScrollConsoleScreenBufferW".}

+proc ScrollWindow*(wnd: HWND, XAmount: int32, YAmount: int32, rect: LPRECT,

+                   lpClipRect: LPRECT): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "ScrollWindow".}

+proc ScrollWindowEx*(wnd: HWND, dx: int32, dy: int32, prcScroll: LPRECT,

+                     prcClip: LPRECT, hrgnUpdate: HRGN, prcUpdate: LPRECT,

+                     flags: WINUINT): int32{.stdcall, dynlib: "user32",

+    importc: "ScrollWindowEx".}

+  #function ScrollDC(DC: HDC; DX, DY: Integer; var Scroll, Clip: TRect; Rgn: HRGN; Update: PRect): WINBOOL; stdcall; external 'user32' name 'ScrollDC';

+  #function SearchPath(lpPath, lpFileName, lpExtension: PChar; nBufferLength: DWORD; lpBuffer: PChar; var lpFilePart: PChar): DWORD;stdcall; external 'kernel32' name 'SearchPathA';

+  #function SearchPathA(lpPath, lpFileName, lpExtension: LPCSTR; nBufferLength: DWORD; lpBuffer: LPCSTR; var lpFilePart: LPCSTR): DWORD; stdcall; external 'kernel32' name 'SearchPathA';

+  #function SearchPathW(lpPath, lpFileName, lpExtension: LPWSTR; nBufferLength: DWORD; lpBuffer: LPWSTR; var lpFilePart: LPWSTR): DWORD; stdcall; external 'kernel32' name 'SearchPathW';

+  #function SendInput(cInputs: WINUINT; var pInputs: TInput; cbSize: Integer): WINUINT;stdcall; external 'user32' name 'SendInput';

+proc SendMessageTimeout*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM,

+                         fuFlags, uTimeout: WINUINT, lpdwResult: var DWORD): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageTimeoutA".}

+proc SendMessageTimeoutA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM,

+                          fuFlags, uTimeout: WINUINT, lpdwResult: var DWORD): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageTimeoutA".}

+proc SendMessageTimeoutW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM,

+                          fuFlags, uTimeout: WINUINT, lpdwResult: var DWORD): LRESULT{.

+    stdcall, dynlib: "user32", importc: "SendMessageTimeoutW".}

+  #function SetAclInformation(var pAcl: TACL; pAclInformation: pointer; nAclInformationLength: DWORD; dwAclInformationClass: TAclInformationClass): WINBOOL; stdcall; external 'advapi32' name 'SetAclInformation';

+  #function SetColorAdjustment(DC: HDC; const p2: TColorAdjustment): WINBOOL; stdcall; external 'gdi32' name 'SetColorAdjustment';

+proc SetCommConfig*(hCommDev: THandle, lpCC: TCommConfig, dwSize: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetCommConfig".}

+proc SetCommState*(hFile: THandle, lpDCB: TDCB): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetCommState".}

+proc SetCommTimeouts*(hFile: THandle, lpCommTimeouts: TCommTimeouts): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetCommTimeouts".}

+proc SetConsoleCursorInfo*(hConsoleOutput: THandle,

+                           lpConsoleCursorInfo: TConsoleCursorInfo): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetConsoleCursorInfo".}

+  #function SetConsoleWindowInfo(hConsoleOutput: THandle; bAbsolute: WINBOOL; const lpConsoleWindow: TSmallRect): WINBOOL; stdcall; external 'kernel32' name 'SetConsoleWindowInfo';

+proc SetDIBColorTable*(DC: HDC, p2, p3: WINUINT, RGBQuadSTructs: pointer): WINUINT{.

+    stdcall, dynlib: "gdi32", importc: "SetDIBColorTable".}

+proc SetDIBits*(DC: HDC, Bitmap: HBITMAP, StartScan, NumScans: WINUINT,

+                Bits: pointer, BitsInfo: var TBitmapInfo, Usage: WINUINT): int{.

+    stdcall, dynlib: "gdi32", importc: "SetDIBits".}

+  #function SetDIBitsToDevice(DC: HDC; DestX, DestY: Integer; Width, Height: DWORD; SrcX, SrcY: Integer; nStartScan, NumScans: WINUINT; Bits: pointer; var BitsInfo: TBitmapInfo; Usage: WINUINT): Integer; stdcall; external 'gdi32' name 'SetDIBitsToDevice';

+proc SetEnhMetaFileBits*(para1: WINUINT, para2: pointer): HENHMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "SetEnhMetaFileBits".}

+proc SetFileTime*(hFile: HANDLE, lpCreationTime: var FILETIME,

+                  lpLastAccessTime: var FILETIME, lpLastWriteTime: var FILETIME): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetFileTime".}

+  #function SetKeyboardState(var KeyState: TKeyboardState): WINBOOL; stdcall; external 'user32' name 'SetKeyboardState';

+  #function SetLocalTime(const lpSystemTime: TSystemTime): WINBOOL; stdcall; external 'kernel32' name 'SetLocalTime';

+  #function SetMenuInfo(menu: HMENU; const lpcmi: TMenuInfo): WINBOOL;stdcall; external 'user32' name 'SetMenuInfo';

+proc SetMenuItemInfo*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: TMenuItemInfo): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetMenuItemInfoA".}

+proc SetMenuItemInfoA*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: TMenuItemInfoA): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetMenuItemInfoA".}

+  #function SetMenuItemInfoW(p1: HMENU; p2: WINUINT; p3: WINBOOL; const p4: TMenuItemInfoW): WINBOOL; stdcall; external 'user32' name 'SetMenuItemInfoW';

+proc SetMetaFileBitsEx*(p1: WINUINT, p2: cstring): HMETAFILE{.stdcall,

+    dynlib: "gdi32", importc: "SetMetaFileBitsEx".}

+proc SetNamedPipeHandleState*(hNamedPipe: THandle, lpMode: var DWORD,

+    lpMaxCollectionCount, lpCollectDataTimeout: pointer): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetNamedPipeHandleState".}

+proc SetPaletteEntries*(Palette: HPALETTE, StartIndex, NumEntries: WINUINT,

+                        PaletteEntries: pointer): WINUINT{.stdcall,

+    dynlib: "gdi32", importc: "SetPaletteEntries".}

+  #function SetPrivateObjectSecurity(SecurityInformation: SECURITY_INFORMATION; ModificationDescriptor: PSecurityDescriptor; var ObjectsSecurityDescriptor: PSecurityDescriptor; const GenericMapping: TGenericMapping; Token: THandle): WINBOOL;

+  #  stdcall; external 'advapi32' name 'SetPrivateObjectSecurity';

+  #function SetPrivateObjectSecurityEx(SecurityInformation: SECURITY_INFORMATION; ModificationDescriptor: PSecurityDescriptor; var ObjectsSecurityDescriptor: PSecurityDescriptor; AutoInheritFlags: ULONG;

+  #  const GenericMapping: TGenericMapping; Token: THandle): WINBOOL;stdcall; external 'advapi32' name 'SetPrivateObjectSecurityEx';

+proc SetRect*(lprc: var TRect, xLeft, yTop, xRight, yBottom: int): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetRect".}

+proc SetRectEmpty*(lprc: var TRect): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "SetRectEmpty".}

+proc SetScrollInfo*(wnd: HWND, BarFlag: int, ScrollInfo: TScrollInfo,

+                    Redraw: WINBOOL): int{.stdcall, dynlib: "user32",

+    importc: "SetScrollInfo".}

+proc SetSysColors*(cElements: int, lpaElements: pointer, lpaRgbValues: pointer): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SetSysColors".}

+  #function SetSystemTime(const lpSystemTime: TSystemTime): WINBOOL; stdcall; external 'kernel32' name 'SetSystemTime';

+proc SetThreadContext*(hThread: THandle, lpContext: TContext): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SetThreadContext".}

+  #function SetTimeZoneInformation(const lpTimeZoneInformation: TTimeZoneInformation): WINBOOL; stdcall; external 'kernel32' name 'SetTimeZoneInformation';

+proc SetUserObjectSecurity*(hObj: THandle, pSIRequested: var DWORD,

+                            pSID: PSecurityDescriptor): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "SetUserObjectSecurity".}

+proc SetWaitableTimer*(hTimer: THandle, lpDueTime: var TLargeInteger,

+                       lPeriod: int32, pfnCompletionRoutine: TFNTimerAPCRoutine,

+                       lpArgToCompletionRoutine: pointer, fResume: WINBOOL): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SetWaitableTimer".}

+proc SetWinMetaFileBits*(p1: WINUINT, p2: cstring, p3: HDC, p4: TMetaFilePict): HENHMETAFILE{.

+    stdcall, dynlib: "gdi32", importc: "SetWinMetaFileBits".}

+  #function SetWorldTransform(DC: HDC; const p2: TXForm): WINBOOL; stdcall; external 'gdi32' name 'SetWorldTransform';

+proc StartDoc*(DC: HDC, p2: TDocInfo): int{.stdcall, dynlib: "gdi32",

+    importc: "StartDocA".}

+proc StartDocA*(DC: HDC, p2: TDocInfoA): int{.stdcall, dynlib: "gdi32",

+    importc: "StartDocA".}

+  #function StartDocW(DC: HDC; const p2: TDocInfoW): Integer; stdcall; external 'gdi32' name 'StartDocW';

+  #function StretchDIBits(DC: HDC; DestX, DestY, DestWidth, DestHegiht, SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bits: pointer; var BitsInfo: TBitmapInfo; Usage: WINUINT; Rop: DWORD): Integer; stdcall; external 'gdi32' name 'StretchDIBits';

+proc SubtractRect*(lprcDst: var TRect, lprcSrc1, lprcSrc2: TRect): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "SubtractRect".}

+proc SystemTimeToFileTime*(lpSystemTime: TSystemTime, lpFileTime: var TFileTime): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "SystemTimeToFileTime".}

+proc SystemTimeToTzSpecificLocalTime*(lpTimeZoneInformation: PTimeZoneInformation,

+    lpUniversalTime, lpLocalTime: var TSystemTime): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "SystemTimeToTzSpecificLocalTime".}

+proc TabbedTextOut*(hDC: HDC, X, Y: int, lpString: cstring,

+                    nCount, nTabPositions: int, lpnTabStopPositions: pointer,

+                    nTabOrigin: int): int32{.stdcall, dynlib: "user32",

+    importc: "TabbedTextOutA".}

+proc TabbedTextOutA*(hDC: HDC, X, Y: int, lpString: LPCSTR,

+                     nCount, nTabPositions: int, lpnTabStopPositions: pointer,

+                     nTabOrigin: int): int32{.stdcall, dynlib: "user32",

+    importc: "TabbedTextOutA".}

+proc TabbedTextOutW*(hDC: HDC, X, Y: int, lpString: LPWSTR,

+                     nCount, nTabPositions: int, lpnTabStopPositions: pointer,

+                     nTabOrigin: int): int32{.stdcall, dynlib: "user32",

+    importc: "TabbedTextOutW".}

+  #function ToAscii(uVirtKey, uScanCode: WINUINT; const KeyState: TKeyboardState; lpChar: PChar; uFlags: WINUINT): Integer; stdcall; external 'user32' name 'ToAscii';

+  #function ToAsciiEx(uVirtKey: WINUINT; uScanCode: WINUINT; const KeyState: TKeyboardState; lpChar: PChar; uFlags: WINUINT; dwhkl: HKL): Integer; stdcall; external 'user32' name 'ToAsciiEx';

+  #function ToUnicode(wVirtKey, wScanCode: WINUINT; const KeyState: TKeyboardState; var pwszBuff; cchBuff: Integer; wFlags: WINUINT): Integer; stdcall; external 'user32' name 'ToUnicode';

+  # Careful, NT and higher only.

+proc TrackMouseEvent*(EventTrack: var TTrackMouseEvent): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "TrackMouseEvent".}

+proc TrackMouseEvent*(lpEventTrack: PTrackMouseEvent): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "TrackMouseEvent".}

+proc TrackPopupMenu*(menu: HMENU, uFlags: WINUINT, x: int32, y: int32,

+                     nReserved: int32, wnd: HWND, prcRect: PRect): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "TrackPopupMenu".}

+proc TransactNamedPipe*(hNamedPipe: THandle, lpInBuffer: pointer,

+                        nInBufferSize: DWORD, lpOutBuffer: pointer,

+                        nOutBufferSize: DWORD, lpBytesRead: var DWORD,

+                        lpOverlapped: POverlapped): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "TransactNamedPipe".}

+proc TranslateAccelerator*(wnd: HWND, hAccTable: HACCEL, lpMsg: var TMsg): int{.

+    stdcall, dynlib: "user32", importc: "TranslateAcceleratorA".}

+proc TranslateAcceleratorA*(wnd: HWND, hAccTable: HACCEL, lpMsg: var TMsg): int{.

+    stdcall, dynlib: "user32", importc: "TranslateAcceleratorA".}

+proc TranslateAcceleratorW*(wnd: HWND, hAccTable: HACCEL, lpMsg: var TMsg): int{.

+    stdcall, dynlib: "user32", importc: "TranslateAcceleratorW".}

+proc TranslateCharsetInfo*(lpSrc: var DWORD, lpCs: var TCharsetInfo,

+                           dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "gdi32",

+    importc: "TranslateCharsetInfo".}

+proc TranslateMDISysAccel*(hWndClient: HWND, lpMsg: TMsg): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "TranslateMDISysAccel".}

+proc TranslateMessage*(lpMsg: TMsg): WINBOOL{.stdcall, dynlib: "user32",

+    importc: "TranslateMessage".}

+  #function TransparentDIBits(DC: HDC; p2, p3, p4, p5: Integer; const p6: pointer; const p7: PBitmapInfo; p8: WINUINT; p9, p10, p11, p12: Integer; p13: WINUINT): WINBOOL;stdcall; external 'gdi32' name 'TransparentDIBits';

+proc UnhandledExceptionFilter*(ExceptionInfo: TExceptionpointers): int32{.

+    stdcall, dynlib: "kernel32", importc: "UnhandledExceptionFilter".}

+proc UnionRect*(lprcDst: var TRect, lprcSrc1, lprcSrc2: TRect): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "UnionRect".}

+proc UnlockFileEx*(hFile: THandle, dwReserved, nNumberOfBytesToUnlockLow: DWORD,

+                   nNumberOfBytesToUnlockHigh: DWORD, lpOverlapped: TOverlapped): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "UnlockFileEx".}

+proc VerFindFile*(uFlags: DWORD,

+                  szFileName, szWinDir, szAppDir, szCurDir: cstring,

+                  lpuCurDirLen: var WINUINT, szDestDir: cstring,

+                  lpuDestDirLen: var WINUINT): DWORD{.stdcall, dynlib: "version",

+    importc: "VerFindFileA".}

+proc VerFindFileA*(uFlags: DWORD,

+                   szFileName, szWinDir, szAppDir, szCurDir: LPCSTR,

+                   lpuCurDirLen: var WINUINT, szDestDir: LPCSTR,

+                   lpuDestDirLen: var WINUINT): DWORD{.stdcall, dynlib: "version",

+    importc: "VerFindFileA".}

+proc VerFindFileW*(uFlags: DWORD,

+                   szFileName, szWinDir, szAppDir, szCurDir: LPWSTR,

+                   lpuCurDirLen: var WINUINT, szDestDir: LPWSTR,

+                   lpuDestDirLen: var WINUINT): DWORD{.stdcall, dynlib: "version",

+    importc: "VerFindFileW".}

+proc VerInstallFile*(uFlags: DWORD, szSrcFileName, szDestFileName, szSrcDir,

+                                    szDestDir, szCurDir, szTmpFile: cstring,

+                     lpuTmpFileLen: var WINUINT): DWORD{.stdcall,

+    dynlib: "version", importc: "VerInstallFileA".}

+proc VerInstallFileA*(uFlags: DWORD, szSrcFileName, szDestFileName, szSrcDir,

+                                     szDestDir, szCurDir, szTmpFile: LPCSTR,

+                      lpuTmpFileLen: var WINUINT): DWORD{.stdcall,

+    dynlib: "version", importc: "VerInstallFileA".}

+proc VerInstallFileW*(uFlags: DWORD, szSrcFileName, szDestFileName, szSrcDir,

+                                     szDestDir, szCurDir, szTmpFile: LPWSTR,

+                      lpuTmpFileLen: var WINUINT): DWORD{.stdcall,

+    dynlib: "version", importc: "VerInstallFileW".}

+proc VerQueryValue*(pBlock: pointer, lpSubBlock: cstring,

+                    lplpBuffer: var pointer, puLen: var WINUINT): WINBOOL{.stdcall,

+    dynlib: "version", importc: "VerQueryValueA".}

+proc VerQueryValueA*(pBlock: pointer, lpSubBlock: LPCSTR,

+                     lplpBuffer: var pointer, puLen: var WINUINT): WINBOOL{.

+    stdcall, dynlib: "version", importc: "VerQueryValueA".}

+proc VerQueryValueW*(pBlock: pointer, lpSubBlock: LPWSTR,

+                     lplpBuffer: var pointer, puLen: var WINUINT): WINBOOL{.

+    stdcall, dynlib: "version", importc: "VerQueryValueW".}

+proc VirtualQuery*(lpAddress: pointer, lpBuffer: var TMemoryBasicInformation,

+                   dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32",

+    importc: "VirtualQuery".}

+proc VirtualQueryEx*(hProcess: THandle, lpAddress: pointer,

+                     lpBuffer: var TMemoryBasicInformation, dwLength: DWORD): DWORD{.

+    stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".}

+proc WaitCommEvent*(hFile: THandle, lpEvtMask: var DWORD,

+                    lpOverlapped: POverlapped): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WaitCommEvent".}

+proc WaitForDebugEvent*(lpDebugEvent: var TDebugEvent, dwMilliseconds: DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WaitForDebugEvent".}

+proc wglDescribeLayerPlane*(p1: HDC, p2, p3: int, p4: int,

+                            p5: var TLayerPlaneDescriptor): WINBOOL{.stdcall,

+    dynlib: "opengl32", importc: "wglDescribeLayerPlane".}

+proc wglGetLayerPaletteEntries*(p1: HDC, p2, p3, p4: int, pcr: pointer): int{.

+    stdcall, dynlib: "opengl32", importc: "wglGetLayerPaletteEntries".}

+proc wglSetLayerPaletteEntries*(p1: HDC, p2, p3, p4: int, pcr: pointer): int{.

+    stdcall, dynlib: "opengl32", importc: "wglSetLayerPaletteEntries".}

+  #function wglSwapMultipleBuffers(p1: WINUINT; const p2: PWGLSwap): DWORD;stdcall; external 'opengl32' name 'wglSwapMultipleBuffers';

+  #function WinSubmitCertificate(var lpCertificate: TWinCertificate): WINBOOL;stdcall; external 'imaghlp' name 'WinSubmitCertificate';

+  #function WinVerifyTrust(wnd: HWND; const ActionID: TGUID; ActionData: pointer): Longint;stdcall; external 'imaghlp' name 'WinVerifyTrust';

+proc WNetAddConnection2*(lpNetResource: var TNetResource,

+                         lpPassword, lpUserName: cstring, dwFlags: DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetAddConnection2A".}

+proc WNetAddConnection2A*(lpNetResource: var TNetResourceA,

+                          lpPassword, lpUserName: LPCSTR, dwFlags: DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetAddConnection2A".}

+  #function WNetAddConnection2W(var lpNetResource: TNetResourceW; lpPassword, lpUserName: LPWSTR; dwFlags: DWORD): DWORD; stdcall; external 'mpr' name 'WNetAddConnection2W';

+proc WNetAddConnection3*(hwndOwner: HWND, lpNetResource: var TNetResource,

+                         lpPassword, lpUserName: cstring, dwFlags: DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetAddConnection3A".}

+proc WNetAddConnection3A*(hwndOwner: HWND, lpNetResource: var TNetResourceA,

+                          lpPassword, lpUserName: LPCSTR, dwFlags: DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetAddConnection3A".}

+  #function WNetAddConnection3W(hwndOwner: HWND; var lpNetResource: TNetResourceW; lpPassword, lpUserName: LPWSTR; dwFlags: DWORD): DWORD; stdcall; external 'mpr' name 'WNetAddConnection3W';

+proc WNetConnectionDialog1*(lpConnDlgStruct: var TConnectDlgStruct): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetConnectionDialog1A".}

+proc WNetConnectionDialog1A*(lpConnDlgStruct: var TConnectDlgStruct): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetConnectionDialog1A".}

+  #function WNetConnectionDialog1W(var lpConnDlgStruct: TConnectDlgStruct): DWORD; stdcall; external 'mpr' name 'WNetConnectionDialog1W';

+proc WNetDisconnectDialog1*(lpConnDlgStruct: var TDiscDlgStruct): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetDisconnectDialog1A".}

+proc WNetDisconnectDialog1A*(lpConnDlgStruct: var TDiscDlgStructA): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetDisconnectDialog1A".}

+  #function WNetDisconnectDialog1W(var lpConnDlgStruct: TDiscDlgStructW): DWORD; stdcall; external 'mpr' name 'WNetDisconnectDialog1W';

+proc WNetEnumResource*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: pointer,

+                       lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetEnumResourceA".}

+proc WNetEnumResourceA*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: pointer,

+                        lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetEnumResourceA".}

+proc WNetEnumResourceW*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: pointer,

+                        lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetEnumResourceW".}

+proc WNetGetConnection*(lpLocalName: cstring, lpRemoteName: cstring,

+                        lpnLength: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetConnectionA".}

+proc WNetGetConnectionA*(lpLocalName: LPCSTR, lpRemoteName: LPCSTR,

+                         lpnLength: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetConnectionA".}

+proc WNetGetConnectionW*(lpLocalName: LPWSTR, lpRemoteName: LPWSTR,

+                         lpnLength: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetConnectionW".}

+proc WNetGetLastError*(lpError: var DWORD, lpErrorBuf: cstring,

+                       nErrorBufSize: DWORD, lpNameBuf: cstring,

+                       nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetLastErrorA".}

+proc WNetGetLastErrorA*(lpError: var DWORD, lpErrorBuf: LPCSTR,

+                        nErrorBufSize: DWORD, lpNameBuf: LPCSTR,

+                        nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetLastErrorA".}

+proc WNetGetLastErrorW*(lpError: var DWORD, lpErrorBuf: LPWSTR,

+                        nErrorBufSize: DWORD, lpNameBuf: LPWSTR,

+                        nNameBufSize: DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetLastErrorW".}

+proc WNetGetNetworkInformation*(lpProvider: cstring,

+                                lpNetInfoStruct: var TNetInfoStruct): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationA".}

+proc WNetGetNetworkInformationA*(lpProvider: LPCSTR,

+                                 lpNetInfoStruct: var TNetInfoStruct): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationA".}

+proc WNetGetNetworkInformationW*(lpProvider: LPWSTR,

+                                 lpNetInfoStruct: var TNetInfoStruct): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetNetworkInformationW".}

+proc WNetGetProviderName*(dwNetType: DWORD, lpProviderName: cstring,

+                          lpBufferSize: var DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetGetProviderNameA".}

+proc WNetGetProviderNameA*(dwNetType: DWORD, lpProviderName: LPCSTR,

+                           lpBufferSize: var DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetGetProviderNameA".}

+proc WNetGetProviderNameW*(dwNetType: DWORD, lpProviderName: LPWSTR,

+                           lpBufferSize: var DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetGetProviderNameW".}

+proc WNetGetResourceParent*(lpNetResource: PNetResource, lpBuffer: pointer,

+                            cbBuffer: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetGetResourceParentA".}

+proc WNetGetResourceParentA*(lpNetResource: PNetResourceA, lpBuffer: pointer,

+                             cbBuffer: var DWORD): DWORD{.stdcall,

+    dynlib: "mpr", importc: "WNetGetResourceParentA".}

+  #function WNetGetResourceParentW(lpNetResource: PNetResourceW; lpBuffer: pointer; var cbBuffer: DWORD): DWORD;stdcall; external 'mpr' name 'WNetGetResourceParentW';

+proc WNetGetUniversalName*(lpLocalPath: cstring, dwInfoLevel: DWORD,

+                           lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameA".}

+proc WNetGetUniversalNameA*(lpLocalPath: LPCSTR, dwInfoLevel: DWORD,

+                            lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameA".}

+proc WNetGetUniversalNameW*(lpLocalPath: LPWSTR, dwInfoLevel: DWORD,

+                            lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameW".}

+proc WNetGetUser*(lpName: cstring, lpUserName: cstring, lpnLength: var DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUserA".}

+proc WNetGetUserA*(lpName: LPCSTR, lpUserName: LPCSTR, lpnLength: var DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUserA".}

+proc WNetGetUserW*(lpName: LPWSTR, lpUserName: LPWSTR, lpnLength: var DWORD): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetGetUserW".}

+proc WNetOpenEnum*(dwScope, dwType, dwUsage: DWORD, lpNetResource: PNetResource,

+                   lphEnum: var THandle): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetOpenEnumA".}

+proc WNetOpenEnumA*(dwScope, dwType, dwUsage: DWORD,

+                    lpNetResource: PNetResourceA, lphEnum: var THandle): DWORD{.

+    stdcall, dynlib: "mpr", importc: "WNetOpenEnumA".}

+  #function WNetOpenEnumW(dwScope, dwType, dwUsage: DWORD; lpNetResource: PNetResourceW; var lphEnum: THandle): DWORD; stdcall; external 'mpr' name 'WNetOpenEnumW';

+proc WNetUseConnection*(hwndOwner: HWND, lpNetResource: var TNetResource,

+                        lpUserID: cstring, lpPassword: cstring, dwFlags: DWORD,

+                        lpAccessName: cstring, lpBufferSize: var DWORD,

+                        lpResult: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetUseConnectionA".}

+proc WNetUseConnectionA*(hwndOwner: HWND, lpNetResource: var TNetResourceA,

+                         lpUserID: LPCSTR, lpPassword: LPCSTR, dwFlags: DWORD,

+                         lpAccessName: LPCSTR, lpBufferSize: var DWORD,

+                         lpResult: var DWORD): DWORD{.stdcall, dynlib: "mpr",

+    importc: "WNetUseConnectionA".}

+  #function WNetUseConnectionW(hwndOwner: HWND; var lpNetResource: TNetResourceW; lpUserID: LPWSTR; lpPassword: LPWSTR; dwFlags: DWORD; lpAccessName: LPWSTR; var lpBufferSize: DWORD; var lpResult: DWORD): DWORD; stdcall; external 'mpr' name 'WNetUseConnectionW';

+proc WriteConsole*(hConsoleOutput: THandle, lpBuffer: pointer,

+                   nNumberOfCharsToWrite: DWORD,

+                   lpNumberOfCharsWritten: var DWORD, lpReserved: pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleA".}

+proc WriteConsoleA*(hConsoleOutput: THandle, lpBuffer: pointer,

+                    nNumberOfCharsToWrite: DWORD,

+                    lpNumberOfCharsWritten: var DWORD, lpReserved: pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleA".}

+proc WriteConsoleInput*(hConsoleInput: THandle, lpBuffer: TInputRecord,

+                        nLength: DWORD, lpNumberOfEventsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleInputA".}

+proc WriteConsoleInputA*(hConsoleInput: THandle, lpBuffer: TInputRecord,

+                         nLength: DWORD, lpNumberOfEventsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleInputA".}

+proc WriteConsoleInputW*(hConsoleInput: THandle, lpBuffer: TInputRecord,

+                         nLength: DWORD, lpNumberOfEventsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleInputW".}

+proc WriteConsoleOutput*(hConsoleOutput: THandle, lpBuffer: pointer,

+                         dwBufferSize, dwBufferCoord: TCoord,

+                         lpWriteRegion: var TSmallRect): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteConsoleOutputA".}

+proc WriteConsoleOutputA*(hConsoleOutput: THandle, lpBuffer: pointer,

+                          dwBufferSize, dwBufferCoord: TCoord,

+                          lpWriteRegion: var TSmallRect): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteConsoleOutputA".}

+proc WriteConsoleOutputAttribute*(hConsoleOutput: THandle, lpAttribute: pointer,

+                                  nLength: DWORD, dwWriteCoord: TCoord,

+                                  lpNumberOfAttrsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputAttribute".}

+proc WriteConsoleOutputCharacter*(hConsoleOutput: THandle, lpCharacter: cstring,

+                                  nLength: DWORD, dwWriteCoord: TCoord,

+                                  lpNumberOfCharsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterA".}

+proc WriteConsoleOutputCharacterA*(hConsoleOutput: THandle, lpCharacter: LPCSTR,

+                                   nLength: DWORD, dwWriteCoord: TCoord,

+                                   lpNumberOfCharsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterA".}

+proc WriteConsoleOutputCharacterW*(hConsoleOutput: THandle, lpCharacter: LPWSTR,

+                                   nLength: DWORD, dwWriteCoord: TCoord,

+                                   lpNumberOfCharsWritten: var DWORD): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterW".}

+proc WriteConsoleOutputW*(hConsoleOutput: THandle, lpBuffer: pointer,

+                          dwBufferSize, dwBufferCoord: TCoord,

+                          lpWriteRegion: var TSmallRect): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteConsoleOutputW".}

+proc WriteConsoleW*(hConsoleOutput: THandle, lpBuffer: pointer,

+                    nNumberOfCharsToWrite: DWORD,

+                    lpNumberOfCharsWritten: var DWORD, lpReserved: pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteConsoleW".}

+proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: DWORD,

+                lpNumberOfBytesWritten: var DWORD, lpOverlapped: POverlapped): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteFile".}

+proc WriteFileEx*(hFile: THandle, lpBuffer: pointer,

+                  nNumberOfBytesToWrite: DWORD, lpOverlapped: TOverlapped,

+                  lpCompletionRoutine: FARPROC): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteFileEx".}

+proc WritePrivateProfileStructA*(lpszSection, lpszKey: LPCSTR, lpStruct: LPVOID,

+                                 uSizeStruct: WINUINT, szFile: LPCSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStructA".}

+proc WritePrivateProfileStructW*(lpszSection, lpszKey: LPCWSTR,

+                                 lpStruct: LPVOID, uSizeStruct: WINUINT,

+                                 szFile: LPCWSTR): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WritePrivateProfileStructW".}

+proc WritePrivateProfileStruct*(lpszSection, lpszKey: LPCTSTR, lpStruct: LPVOID,

+                                uSizeStruct: WINUINT, szFile: LPCTSTR): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStructA".}

+proc WriteProcessMemory*(hProcess: THandle, lpBaseAddress: pointer,

+                         lpBuffer: pointer, nSize: DWORD,

+                         lpNumberOfBytesWritten: var DWORD): WINBOOL{.stdcall,

+    dynlib: "kernel32", importc: "WriteProcessMemory".}

+proc SHFileOperation*(para1: var SHFILEOPSTRUCT): int32{.stdcall,

+    dynlib: "shell32", importc: "SHFileOperation".}

+

+  # these are old Win16 funcs that under win32 are aliases for several char* funcs.

+# exist under Win32 (even in SDK's from 2002), but are officially "deprecated"

+proc AnsiNext*(lpsz: LPCSTR): LPSTR{.stdcall, dynlib: "user32",

+                                     importc: "CharNextA".}

+proc AnsiPrev*(lpszStart: LPCSTR, lpszCurrent: LPCSTR): LPSTR{.stdcall,

+    dynlib: "user32", importc: "CharPrevA".}

+proc AnsiToOem*(lpszSrc: LPCSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "CharToOemA".}

+proc OemToAnsi*(lpszSrc: LPCSTR, lpszDst: LPSTR): WINBOOL{.stdcall,

+    dynlib: "user32", importc: "OemToCharA".}

+proc AnsiToOemBuff*(lpszSrc: LPCSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "CharToOemBuffA".}

+proc OemToAnsiBuff*(lpszSrc: LPCSTR, lpszDst: LPSTR, cchDstLength: DWORD): WINBOOL{.

+    stdcall, dynlib: "user32", importc: "OemToCharBuffA".}

+proc AnsiUpper*(lpsz: LPSTR): LPSTR{.stdcall, dynlib: "user32",

+                                     importc: "CharUpperA".}

+proc AnsiUpperBuff*(lpsz: LPSTR, cchLength: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "CharUpperBuffA".}

+proc AnsiLower*(lpsz: LPSTR): LPSTR{.stdcall, dynlib: "user32",

+                                     importc: "CharLowerA".}

+proc AnsiLowerBuff*(lpsz: LPSTR, cchLength: DWORD): DWORD{.stdcall,

+    dynlib: "user32", importc: "CharLowerBuffA".}

+

+#== Implementation of macros

+

+# WinBase.h

+

+proc FreeModule*(h: HINST): WINBOOL =

+  result = FreeLibrary(h)

+

+proc MakeProcInstance*(p, i: pointer): pointer =

+  result = p

+

+proc FreeProcInstance*(p: pointer): pointer =

+  result = p

+

+proc GlobalDiscard*(hglbMem: HGLOBAL): HGLOBAL =

+  result = GlobalReAlloc(hglbMem, 0, GMEM_MOVEABLE)

+

+proc LocalDiscard*(hlocMem: HLOCAL): HLOCAL =

+  result = LocalReAlloc(hlocMem, 0, LMEM_MOVEABLE)

+

+# WinGDI.h

+

+discard """proc GetGValue*(rgb: int32): int8 =

+  result = toU8(rgb shr 8'i32)"""

+proc RGB*(r, g, b: int): COLORREF =

+  result = toU32(r) or (toU32(g) shl 8) or (toU32(b) shl 16)

+proc RGB*(r, g, b: range[0 .. 255]): COLORREF =

+  result = toU32(r) or (toU32(g) shl 8) or (toU32(b) shl 16)

+

+proc PALETTERGB*(r, g, b: range[0..255]): COLORREF =

+  result = 0x02000000 or RGB(r, g, b)

+

+proc PALETTEINDEX*(i: DWORD): COLORREF =

+  result = COLORREF(0x01000000'i32 or i and 0xffff'i32)

+

+

+proc GetRValue*(rgb: COLORREF): int8 =

+  result = toU8(rgb)

+

+proc GetGValue*(rgb: COLORREF): int8 =

+  result = toU8(rgb shr 8)

+

+proc GetBValue*(rgb: COLORREF): int8 =

+  result = toU8(rgb shr 16)

+

+#

+

+proc HIBYTE*(w: int32): int8 =

+  result = toU8(w shr 8'i32 and 0x000000FF'i32)

+

+proc HIWORD*(L: int32): int16 =

+  result = toU16(L shr 16'i32 and 0x0000FFFF'i32)

+

+proc LOBYTE*(w: int32): int8 =

+  result = toU8(w)

+

+proc LOWORD*(L: int32): int16 =

+  result = toU16(L)

+

+proc MAKELONG*(a, b: int32): LONG =

+  result = a and 0x0000ffff'i32 or b shl 16'i32

+

+proc MAKEWORD*(a, b: int32): int16 =

+  result = toU16(a and 0xff'i32) or toU16(b shl 8'i32)

+

+proc SEXT_HIWORD*(L: int32): int32 =

+  # return type might be wrong

+  result = HIWORD(L)

+

+proc ZEXT_HIWORD*(L: int32): int32 =

+  # return type might be wrong

+  result = HIWORD(L) and 0xffff'i32

+

+proc SEXT_LOWORD*(L: int32): int32 =

+  result = LOWORD(L)

+

+proc INDEXTOOVERLAYMASK*(i: int32): int32 =

+  # return type might be wrong

+  result = i shl 8'i32

+

+proc INDEXTOSTATEIMAGEMASK*(i: int32): int32 =

+  # return type might be wrong

+  result = i shl 12'i32

+

+proc MAKEINTATOM*(i: int32): LPTSTR =

+  result = cast[LPTSTR](cast[ULONG_PTR](toU16(i)))

+

+proc MAKELANGID*(p, s: int32): int32 =

+  # return type might be wrong

+  result = toU16(s) shl 10'i16 or toU16(p)

+

+proc PRIMARYLANGID*(lgid: int32): int16 =

+  result = toU16(lgid) and 0x000003FF'i16

+

+proc SUBLANGID*(lgid: int32): int32 =

+  # return type might be wrong

+  result = toU16(lgid) shr 10'i16

+

+proc MAKELCID*(lgid, srtid: int32): DWORD =

+  result = toU32(srtid shl 16'i32 or lgid and 0xffff'i32)

+

+proc MAKELPARAM*(L, h: int32): LPARAM =

+  result = LPARAM(MAKELONG(L, h))

+

+proc MAKELRESULT*(L, h: int32): LRESULT =

+  result = LRESULT(MAKELONG(L, h))

+

+proc MAKEROP4*(fore, back: int32): DWORD =

+  result = back shl 8'i32 and 0xFF000000'i32 or fore

+

+proc MAKEWPARAM*(L, h: int32): WPARAM =

+  result = WPARAM(MAKELONG(L, h))

+

+proc GET_X_LPARAM*(lp: windows.LParam): int32 =

+  result = LOWORD(lp.int32)

+

+proc GET_Y_LPARAM*(lp: windows.LParam): int32 =

+  result = HIWORD(lp.int32)

+

+proc UNICODE_NULL*(): WCHAR =

+  result = 0'u16

+

+

+

+proc GetFirstChild*(h: HWND): HWND =

+  result = GetTopWindow(h)

+

+proc GetNextSibling*(h: HWND): HWND =

+  result = GetWindow(h, GW_HWNDNEXT)

+

+proc GetWindowID*(h: HWND): int32 =

+  result = GetDlgCtrlID(h)

+

+proc SubclassWindow*(h: HWND, p: LONG): LONG =

+  result = SetWindowLong(h, GWL_WNDPROC, p)

+

+proc GET_WM_COMMAND_CMD*(w, L: int32): int32 =

+  # return type might be wrong

+  result = HIWORD(w)

+

+proc GET_WM_COMMAND_ID(w, L: int32): int32 =

+  # return type might be wrong

+  result = LOWORD(w)

+

+proc GET_WM_CTLCOLOR_HDC(w, L, msg: int32): HDC =

+  result = HDC(w)

+

+proc GET_WM_CTLCOLOR_HWND(w, L, msg: int32): HWND =

+  result = HWND(L)

+

+proc GET_WM_HSCROLL_CODE(w, L: int32): int32 =

+  # return type might be wrong

+  result = LOWORD(w)

+

+proc GET_WM_HSCROLL_HWND(w, L: int32): HWND =

+  result = HWND(L)

+

+proc GET_WM_HSCROLL_POS(w, L: int32): int32 =

+  # return type might be wrong

+  result = HIWORD(w)

+

+proc GET_WM_MDIACTIVATE_FACTIVATE(h, a, b: int32): int32 =

+  # return type might be wrong

+  result = ord(b == h)

+

+proc GET_WM_MDIACTIVATE_HWNDACTIVATE(a, b: int32): HWND =

+  result = HWND(b)

+

+proc GET_WM_MDIACTIVATE_HWNDDEACT(a, b: int32): HWND =

+  result = HWND(a)

+

+proc GET_WM_VSCROLL_CODE(w, L: int32): int32 =

+  # return type might be wrong

+  result = LOWORD(w)

+

+proc GET_WM_VSCROLL_HWND(w, L: int32): HWND =

+  result = HWND(L)

+

+proc GET_WM_VSCROLL_POS(w, L: int32): int32 =

+  # return type might be wrong

+  result = HIWORD(w)

+

+proc fBinary(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fBinary) shr bp_DCB_fBinary

+

+proc set_fBinary(a: var DCB, fBinary: DWORD) =

+  a.flags = a.flags or ((fBinary shl bp_DCB_fBinary) and bm_DCB_fBinary)

+

+proc fParity(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fParity) shr bp_DCB_fParity

+

+proc set_fParity(a: var DCB, fParity: DWORD) =

+  a.flags = a.flags or ((fParity shl bp_DCB_fParity) and bm_DCB_fParity)

+

+proc fOutxCtsFlow(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fOutxCtsFlow) shr bp_DCB_fOutxCtsFlow

+

+proc set_fOutxCtsFlow(a: var DCB, fOutxCtsFlow: DWORD) =

+  a.flags = a.flags or

+      ((fOutxCtsFlow shl bp_DCB_fOutxCtsFlow) and bm_DCB_fOutxCtsFlow)

+

+proc fOutxDsrFlow(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fOutxDsrFlow) shr bp_DCB_fOutxDsrFlow

+

+proc set_fOutxDsrFlow(a: var DCB, fOutxDsrFlow: DWORD) =

+  a.flags = a.flags or

+      ((fOutxDsrFlow shl bp_DCB_fOutxDsrFlow) and bm_DCB_fOutxDsrFlow)

+

+proc fDtrControl(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fDtrControl) shr bp_DCB_fDtrControl

+

+proc set_fDtrControl(a: var DCB, fDtrControl: DWORD) =

+  a.flags = a.flags or

+      ((fDtrControl shl bp_DCB_fDtrControl) and bm_DCB_fDtrControl)

+

+proc fDsrSensitivity(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fDsrSensitivity) shr bp_DCB_fDsrSensitivity

+

+proc set_fDsrSensitivity(a: var DCB, fDsrSensitivity: DWORD) =

+  a.flags = a.flags or

+      ((fDsrSensitivity shl bp_DCB_fDsrSensitivity) and

+      bm_DCB_fDsrSensitivity)

+

+proc fTXContinueOnXoff(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fTXContinueOnXoff) shr

+      bp_DCB_fTXContinueOnXoff

+

+proc set_fTXContinueOnXoff(a: var DCB, fTXContinueOnXoff: DWORD) =

+  a.flags = a.flags or

+      ((fTXContinueOnXoff shl bp_DCB_fTXContinueOnXoff) and

+      bm_DCB_fTXContinueOnXoff)

+

+proc fOutX(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fOutX) shr bp_DCB_fOutX

+

+proc set_fOutX(a: var DCB, fOutX: DWORD) =

+  a.flags = a.flags or ((fOutX shl bp_DCB_fOutX) and bm_DCB_fOutX)

+

+proc fInX(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fInX) shr bp_DCB_fInX

+

+proc set_fInX(a: var DCB, fInX: DWORD) =

+  a.flags = a.flags or ((fInX shl bp_DCB_fInX) and bm_DCB_fInX)

+

+proc fErrorChar(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fErrorChar) shr bp_DCB_fErrorChar

+

+proc set_fErrorChar(a: var DCB, fErrorChar: DWORD) =

+  a.flags = a.flags or

+      ((fErrorChar shl bp_DCB_fErrorChar) and bm_DCB_fErrorChar)

+

+proc fNull(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fNull) shr bp_DCB_fNull

+

+proc set_fNull(a: var DCB, fNull: DWORD) =

+  a.flags = a.flags or ((fNull shl bp_DCB_fNull) and bm_DCB_fNull)

+

+proc fRtsControl(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fRtsControl) shr bp_DCB_fRtsControl

+

+proc set_fRtsControl(a: var DCB, fRtsControl: DWORD) =

+  a.flags = a.flags or

+      ((fRtsControl shl bp_DCB_fRtsControl) and bm_DCB_fRtsControl)

+

+proc fAbortOnError(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fAbortOnError) shr bp_DCB_fAbortOnError

+

+proc set_fAbortOnError(a: var DCB, fAbortOnError: DWORD) =

+  a.flags = a.flags or

+      ((fAbortOnError shl bp_DCB_fAbortOnError) and bm_DCB_fAbortOnError)

+

+proc fDummy2(a: var DCB): DWORD =

+  result = (a.flags and bm_DCB_fDummy2) shr bp_DCB_fDummy2

+

+proc set_fDummy2(a: var DCB, fDummy2: DWORD) =

+  a.flags = a.flags or ((fDummy2 shl bp_DCB_fDummy2) and bm_DCB_fDummy2)

+

+proc fCtsHold(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fCtsHold) shr bp_COMSTAT_fCtsHold

+

+proc set_fCtsHold(a: var COMSTAT, fCtsHold: DWORD) =

+  a.flag0 = a.flag0 or

+      ((fCtsHold shl bp_COMSTAT_fCtsHold) and bm_COMSTAT_fCtsHold)

+

+proc fDsrHold(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fDsrHold) shr bp_COMSTAT_fDsrHold

+

+proc set_fDsrHold(a: var COMSTAT, fDsrHold: DWORD) =

+  a.flag0 = a.flag0 or

+      ((fDsrHold shl bp_COMSTAT_fDsrHold) and bm_COMSTAT_fDsrHold)

+

+proc fRlsdHold(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fRlsdHold) shr bp_COMSTAT_fRlsdHold

+

+proc set_fRlsdHold(a: var COMSTAT, fRlsdHold: DWORD) =

+  a.flag0 = a.flag0 or

+      ((fRlsdHold shl bp_COMSTAT_fRlsdHold) and bm_COMSTAT_fRlsdHold)

+

+proc fXoffHold(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fXoffHold) shr bp_COMSTAT_fXoffHold

+

+proc set_fXoffHold(a: var COMSTAT, fXoffHold: DWORD) =

+  a.flag0 = a.flag0 or

+      ((fXoffHold shl bp_COMSTAT_fXoffHold) and bm_COMSTAT_fXoffHold)

+

+proc fXoffSent(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fXoffSent) shr bp_COMSTAT_fXoffSent

+

+proc set_fXoffSent(a: var COMSTAT, fXoffSent: DWORD) =

+  a.flag0 = a.flag0 or

+      ((fXoffSent shl bp_COMSTAT_fXoffSent) and bm_COMSTAT_fXoffSent)

+

+proc fEof(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fEof) shr bp_COMSTAT_fEof

+

+proc set_fEof(a: var COMSTAT, fEof: DWORD) =

+  a.flag0 = a.flag0 or ((fEof shl bp_COMSTAT_fEof) and bm_COMSTAT_fEof)

+

+proc fTxim(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fTxim) shr bp_COMSTAT_fTxim

+

+proc set_fTxim(a: var COMSTAT, fTxim: DWORD) =

+  a.flag0 = a.flag0 or ((fTxim shl bp_COMSTAT_fTxim) and bm_COMSTAT_fTxim)

+

+proc fReserved(a: var COMSTAT): DWORD =

+  result = (a.flag0 and bm_COMSTAT_fReserved) shr bp_COMSTAT_fReserved

+

+proc set_fReserved(a: var COMSTAT, fReserved: DWORD) =

+  a.flag0 = a.flag0 or

+      ((fReserved shl bp_COMSTAT_fReserved) and bm_COMSTAT_fReserved)

+

+proc bAppReturnCode(a: var DDEACK): int16 =

+  result = (a.flag0 and bm_DDEACK_bAppReturnCode) shr

+      bp_DDEACK_bAppReturnCode

+

+proc set_bAppReturnCode(a: var DDEACK, bAppReturnCode: int16) =

+  a.flag0 = a.flag0 or

+      ((bAppReturnCode shl bp_DDEACK_bAppReturnCode) and

+      bm_DDEACK_bAppReturnCode)

+

+proc reserved(a: var DDEACK): int16 =

+  result = (a.flag0 and bm_DDEACK_reserved) shr bp_DDEACK_reserved

+

+proc set_reserved(a: var DDEACK, reserved: int16) =

+  a.flag0 = a.flag0 or

+      ((reserved shl bp_DDEACK_reserved) and bm_DDEACK_reserved)

+

+proc fBusy(a: var DDEACK): int16 =

+  result = (a.flag0 and bm_DDEACK_fBusy) shr bp_DDEACK_fBusy

+

+proc set_fBusy(a: var DDEACK, fBusy: int16) =

+  a.flag0 = a.flag0 or ((fBusy shl bp_DDEACK_fBusy) and bm_DDEACK_fBusy)

+

+proc fAck(a: var DDEACK): int16 =

+  result = (a.flag0 and bm_DDEACK_fAck) shr bp_DDEACK_fAck

+

+proc set_fAck(a: var DDEACK, fAck: int16) =

+  a.flag0 = a.flag0 or ((fAck shl bp_DDEACK_fAck) and bm_DDEACK_fAck)

+

+proc reserved(a: var DDEADVISE): int16 =

+  result = (a.flag0 and bm_DDEADVISE_reserved) shr bp_DDEADVISE_reserved

+

+proc set_reserved(a: var DDEADVISE, reserved: int16) =

+  a.flag0 = a.flag0 or

+      ((reserved shl bp_DDEADVISE_reserved) and bm_DDEADVISE_reserved)

+

+proc fDeferUpd(a: var DDEADVISE): int16 =

+  result = (a.flag0 and bm_DDEADVISE_fDeferUpd) shr bp_DDEADVISE_fDeferUpd

+

+proc set_fDeferUpd(a: var DDEADVISE, fDeferUpd: int16) =

+  a.flag0 = a.flag0 or

+      ((fDeferUpd shl bp_DDEADVISE_fDeferUpd) and bm_DDEADVISE_fDeferUpd)

+

+proc fAckReq(a: var DDEADVISE): int16 =

+  result = (a.flag0 and bm_DDEADVISE_fAckReq) shr bp_DDEADVISE_fAckReq

+

+proc set_fAckReq(a: var DDEADVISE, fAckReq: int16) =

+  a.flag0 = a.flag0 or

+      ((fAckReq shl bp_DDEADVISE_fAckReq) and bm_DDEADVISE_fAckReq)

+

+proc unused(a: var DDEDATA): int16 =

+  result = (a.flag0 and bm_DDEDATA_unused) shr bp_DDEDATA_unused

+

+proc set_unused(a: var DDEDATA, unused: int16) =

+  a.flag0 = a.flag0 or ((unused shl bp_DDEDATA_unused) and bm_DDEDATA_unused)

+

+proc fResponse(a: var DDEDATA): int16 =

+  result = (a.flag0 and bm_DDEDATA_fResponse) shr bp_DDEDATA_fResponse

+

+proc set_fResponse(a: var DDEDATA, fResponse: int16) =

+  a.flag0 = a.flag0 or

+      ((fResponse shl bp_DDEDATA_fResponse) and bm_DDEDATA_fResponse)

+

+proc fRelease(a: var DDEDATA): int16 =

+  result = (a.flag0 and bm_DDEDATA_fRelease) shr bp_DDEDATA_fRelease

+

+proc set_fRelease(a: var DDEDATA, fRelease: int16) =

+  a.flag0 = a.flag0 or

+      ((fRelease shl bp_DDEDATA_fRelease) and bm_DDEDATA_fRelease)

+

+proc reserved(a: var DDEDATA): int16 =

+  result = (a.flag0 and bm_DDEDATA_reserved) shr bp_DDEDATA_reserved

+

+proc set_reserved(a: var DDEDATA, reserved: int16) =

+  a.flag0 = a.flag0 or

+      ((reserved shl bp_DDEDATA_reserved) and bm_DDEDATA_reserved)

+

+proc fAckReq(a: var DDEDATA): int16 =

+  result = (a.flag0 and bm_DDEDATA_fAckReq) shr bp_DDEDATA_fAckReq

+

+proc set_fAckReq(a: var DDEDATA, fAckReq: int16) =

+  a.flag0 = a.flag0 or

+      ((fAckReq shl bp_DDEDATA_fAckReq) and bm_DDEDATA_fAckReq)

+

+proc unused(a: var DDELN): int16 =

+  result = (a.flag0 and bm_DDELN_unused) shr bp_DDELN_unused

+

+proc set_unused(a: var DDELN, unused: int16) =

+  a.flag0 = a.flag0 or ((unused shl bp_DDELN_unused) and bm_DDELN_unused)

+

+proc fRelease(a: var DDELN): int16 =

+  result = (a.flag0 and bm_DDELN_fRelease) shr bp_DDELN_fRelease

+

+proc set_fRelease(a: var DDELN, fRelease: int16) =

+  a.flag0 = a.flag0 or

+      ((fRelease shl bp_DDELN_fRelease) and bm_DDELN_fRelease)

+

+proc fDeferUpd(a: var DDELN): int16 =

+  result = (a.flag0 and bm_DDELN_fDeferUpd) shr bp_DDELN_fDeferUpd

+

+proc set_fDeferUpd(a: var DDELN, fDeferUpd: int16) =

+  a.flag0 = a.flag0 or

+      ((fDeferUpd shl bp_DDELN_fDeferUpd) and bm_DDELN_fDeferUpd)

+

+proc fAckReq(a: var DDELN): int16 =

+  result = (a.flag0 and bm_DDELN_fAckReq) shr bp_DDELN_fAckReq

+

+proc set_fAckReq(a: var DDELN, fAckReq: int16) =

+  a.flag0 = a.flag0 or ((fAckReq shl bp_DDELN_fAckReq) and bm_DDELN_fAckReq)

+

+proc unused(a: var DDEPOKE): int16 =

+  result = (a.flag0 and bm_DDEPOKE_unused) shr bp_DDEPOKE_unused

+

+proc set_unused(a: var DDEPOKE, unused: int16) =

+  a.flag0 = a.flag0 or ((unused shl bp_DDEPOKE_unused) and bm_DDEPOKE_unused)

+

+proc fRelease(a: var DDEPOKE): int16 =

+  result = (a.flag0 and bm_DDEPOKE_fRelease) shr bp_DDEPOKE_fRelease

+

+proc set_fRelease(a: var DDEPOKE, fRelease: int16) =

+  a.flag0 = a.flag0 or

+      ((fRelease shl bp_DDEPOKE_fRelease) and bm_DDEPOKE_fRelease)

+

+proc fReserved(a: var DDEPOKE): int16 =

+  result = (a.flag0 and bm_DDEPOKE_fReserved) shr bp_DDEPOKE_fReserved

+

+proc set_fReserved(a: var DDEPOKE, fReserved: int16) =

+  a.flag0 = a.flag0 or

+      ((fReserved shl bp_DDEPOKE_fReserved) and bm_DDEPOKE_fReserved)

+

+proc unused(a: var DDEUP): int16 =

+  result = (a.flag0 and bm_DDEUP_unused) shr bp_DDEUP_unused

+

+proc set_unused(a: var DDEUP, unused: int16) =

+  a.flag0 = a.flag0 or ((unused shl bp_DDEUP_unused) and bm_DDEUP_unused)

+

+proc fAck(a: var DDEUP): int16 =

+  result = (a.flag0 and bm_DDEUP_fAck) shr bp_DDEUP_fAck

+

+proc set_fAck(a: var DDEUP, fAck: int16) =

+  a.flag0 = a.flag0 or ((fAck shl bp_DDEUP_fAck) and bm_DDEUP_fAck)

+

+proc fRelease(a: var DDEUP): int16 =

+  result = (a.flag0 and bm_DDEUP_fRelease) shr bp_DDEUP_fRelease

+

+proc set_fRelease(a: var DDEUP, fRelease: int16) =

+  a.flag0 = a.flag0 or

+      ((fRelease shl bp_DDEUP_fRelease) and bm_DDEUP_fRelease)

+

+proc fReserved(a: var DDEUP): int16 =

+  result = (a.flag0 and bm_DDEUP_fReserved) shr bp_DDEUP_fReserved

+

+proc set_fReserved(a: var DDEUP, fReserved: int16) =

+  a.flag0 = a.flag0 or

+      ((fReserved shl bp_DDEUP_fReserved) and bm_DDEUP_fReserved)

+

+proc fAckReq(a: var DDEUP): int16 =

+  result = (a.flag0 and bm_DDEUP_fAckReq) shr bp_DDEUP_fAckReq

+

+proc set_fAckReq(a: var DDEUP, fAckReq: int16) =

+  a.flag0 = a.flag0 or ((fAckReq shl bp_DDEUP_fAckReq) and bm_DDEUP_fAckReq)

+

+proc CreateWindowA(lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD,

+                   X, Y, nWidth, nHeight: int32,

+                   hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                   lpParam: LPVOID): HWND =

+  result = CreateWindowExA(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth,

+                           nHeight, hWndParent, menu, hInstance, lpParam)

+

+proc CreateDialogA(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                   lpDialogFunc: DLGPROC): HWND =

+  result = CreateDialogParamA(hInstance, lpTemplateName, hWndParent,

+                              lpDialogFunc, 0)

+

+proc CreateDialogIndirectA(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                           hWndParent: HWND, lpDialogFunc: DLGPROC): HWND =

+  result = CreateDialogIndirectParamA(hInstance, lpTemplate, hWndParent,

+                                      lpDialogFunc, 0)

+

+proc DialogBoxA(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                lpDialogFunc: DLGPROC): int32 =

+  result = DialogBoxParamA(hInstance, lpTemplateName, hWndParent, lpDialogFunc,

+                           0)

+

+proc DialogBoxIndirectA(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE,

+                        hWndParent: HWND, lpDialogFunc: DLGPROC): int32 =

+  result = DialogBoxIndirectParamA(hInstance, hDialogTemplate, hWndParent,

+                                   lpDialogFunc, 0)

+

+proc CreateWindowW(lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD,

+                   X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                   hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                   lpParam: LPVOID): HWND =

+  result = CreateWindowExW(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth,

+                           nHeight, hWndParent, menu, hInstance, lpParam)

+

+proc CreateDialogW(hInstance: HINST, lpName: LPCWSTR, hWndParent: HWND,

+                   lpDialogFunc: DLGPROC): HWND =

+  result = CreateDialogParamW(hInstance, lpName, hWndParent, lpDialogFunc, 0)

+

+proc CreateDialogIndirectW(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                           hWndParent: HWND, lpDialogFunc: DLGPROC): HWND =

+  result = CreateDialogIndirectParamW(hInstance, lpTemplate, hWndParent,

+                                      lpDialogFunc, 0)

+

+proc DialogBoxW(hInstance: HINST, lpTemplate: LPCWSTR, hWndParent: HWND,

+                lpDialogFunc: DLGPROC): int32 =

+  result = DialogBoxParamW(hInstance, lpTemplate, hWndParent, lpDialogFunc, 0)

+

+proc DialogBoxIndirectW(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                        hWndParent: HWND, lpDialogFunc: DLGPROC): int32 =

+  result = DialogBoxIndirectParamW(hInstance, lpTemplate, hWndParent,

+                                   lpDialogFunc, 0)

+

+when defined(winUnicode):

+  proc CreateWindow(lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD,

+                    X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                    hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                    lpParam: LPVOID): HWND =

+    result = CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth,

+                            nHeight, hWndParent, hMenu, hInstance, lpParam)

+

+  proc CreateDialog(hInstance: HINST, lpName: LPCWSTR, hWndParent: HWND,

+                    lpDialogFunc: DLGPROC): HWND =

+    result = CreateDialogParam(hInstance, lpName, hWndParent, lpDialogFunc, 0)

+

+  proc CreateDialogIndirect(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                            hWndParent: HWND, lpDialogFunc: DLGPROC): HWND =

+    result = CreateDialogIndirectParam(hInstance, lpTemplate, hWndParent,

+                                       lpDialogFunc, 0)

+

+  proc DialogBox(hInstance: HINST, lpTemplate: LPCWSTR, hWndParent: HWND,

+                 lpDialogFunc: DLGPROC): int32 =

+    result = DialogBoxParam(hInstance, lpTemplate, hWndParent, lpDialogFunc, 0)

+

+  proc DialogBoxIndirect(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                         hWndParent: HWND, lpDialogFunc: DLGPROC): int32 =

+    result = DialogBoxIndirectParam(hInstance, lpTemplate, hWndParent,

+                                    lpDialogFunc, 0)

+

+else:

+  proc CreateWindow(lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD,

+                    X: int32, Y: int32, nWidth: int32, nHeight: int32,

+                    hWndParent: HWND, menu: HMENU, hInstance: HINST,

+                    lpParam: LPVOID): HWND =

+    result = CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth,

+                            nHeight, hWndParent, menu, hInstance, lpParam)

+

+  proc CreateDialog(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                    lpDialogFunc: DLGPROC): HWND =

+    result = CreateDialogParam(hInstance, lpTemplateName, hWndParent,

+                               lpDialogFunc, 0)

+

+  proc CreateDialogIndirect(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE,

+                            hWndParent: HWND, lpDialogFunc: DLGPROC): HWND =

+    result = CreateDialogIndirectParam(hInstance, lpTemplate, hWndParent,

+                                       lpDialogFunc, 0)

+

+  proc DialogBox(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND,

+                 lpDialogFunc: DLGPROC): int32 =

+    result = DialogBoxParam(hInstance, lpTemplateName, hWndParent, lpDialogFunc,

+                            0)

+

+  proc DialogBoxIndirect(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE,

+                         hWndParent: HWND, lpDialogFunc: DLGPROC): int32 =

+    result = DialogBoxIndirectParam(hInstance, hDialogTemplate, hWndParent,

+                                    lpDialogFunc, 0)

+

+proc GlobalAllocPtr(flags, cb: DWord): pointer =

+  result = GlobalLock(GlobalAlloc(flags, cb))

+

+proc GlobalFreePtr(lp: pointer): pointer =

+  result = cast[pointer](GlobalFree(cast[HWND](GlobalUnlockPtr(lp))))

+

+proc GlobalUnlockPtr(lp: pointer): pointer =

+  discard GlobalUnlock(GlobalHandle(lp))

+  result = lp

+

+proc GlobalLockPtr(lp: pointer): pointer =

+  result = GlobalLock(GlobalHandle(lp))

+

+proc GlobalReAllocPtr(lp: pointer, cbNew, flags: DWord): pointer =

+  result = GlobalLock(GlobalReAlloc(cast[HWND](GlobalUnlockPtr(lp)), cbNew, flags))

+

+proc GlobalPtrHandle(lp: pointer): pointer =

+  result = cast[pointer](GlobalHandle(lp))

+

+proc ImageList_AddIcon(himl: HIMAGELIST, hicon: HICON): int32 =

+  result = ImageList_ReplaceIcon(himl, -1, hicon)

+

+proc Animate_Create(hWndP: HWND, id: HMENU, dwStyle: DWORD, hInstance: HINST): HWND =

+  result = CreateWindow(cast[LPCSTR](ANIMATE_CLASS), nil, dwStyle, 0, 0, 0, 0, hwndP,

+                        id, hInstance, nil)

+

+proc Animate_Open(wnd: HWND, szName: LPTSTR): LRESULT =

+  result = SendMessage(wnd, ACM_OPEN, 0, cast[LPARAM](szName))

+

+proc Animate_Play(wnd: HWND, `from`, `to`: int32, rep: WINUINT): LRESULT =

+  result = SendMessage(wnd, ACM_PLAY, WPARAM(rep),

+                       LPARAM(MAKELONG(`from`, `to`)))

+

+proc Animate_Stop(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, ACM_STOP, 0, 0)

+

+proc Animate_Close(wnd: HWND): LRESULT =

+  result = Animate_Open(wnd, nil)

+

+proc Animate_Seek(wnd: HWND, frame: int32): LRESULT =

+  result = Animate_Play(wnd, frame, frame, 1)

+

+proc PropSheet_AddPage(hPropSheetDlg: HWND, hpage: HPROPSHEETPAGE): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_ADDPAGE, 0, cast[LPARAM](hpage))

+

+proc PropSheet_Apply(hPropSheetDlg: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_APPLY, 0, 0)

+

+proc PropSheet_CancelToClose(hPropSheetDlg: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_CANCELTOCLOSE, 0, 0)

+

+proc PropSheet_Changed(hPropSheetDlg, hwndPage: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_CHANGED, WPARAM(hwndPage), 0)

+

+proc PropSheet_GetCurrentPageHwnd(hDlg: HWND): LRESULT =

+  result = SendMessage(hDlg, PSM_GETCURRENTPAGEHWND, 0, 0)

+

+proc PropSheet_GetTabControl(hPropSheetDlg: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_GETTABCONTROL, 0, 0)

+

+proc PropSheet_IsDialogMessage(hDlg: HWND, pMsg: int32): LRESULT =

+  result = SendMessage(hDlg, PSM_ISDIALOGMESSAGE, 0, LPARAM(pMsg))

+

+proc PropSheet_PressButton(hPropSheetDlg: HWND, iButton: int32): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_PRESSBUTTON, WPARAM(int32(iButton)), 0)

+

+proc PropSheet_QuerySiblings(hPropSheetDlg: HWND, param1, param2: int32): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_QUERYSIBLINGS, WPARAM(param1),

+                       LPARAM(param2))

+

+proc PropSheet_RebootSystem(hPropSheetDlg: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_REBOOTSYSTEM, 0, 0)

+

+proc PropSheet_RemovePage(hPropSheetDlg: HWND, hpage: HPROPSHEETPAGE,

+                          index: int32): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_REMOVEPAGE, WPARAM(index),

+                       cast[LPARAM](hpage))

+

+proc PropSheet_RestartWindows(hPropSheetDlg: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_RESTARTWINDOWS, 0, 0)

+

+proc PropSheet_SetCurSel(hPropSheetDlg: HWND, hpage: HPROPSHEETPAGE,

+                         index: int32): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_SETCURSEL, WPARAM(index),

+                       cast[LPARAM](hpage))

+

+proc PropSheet_SetCurSelByID(hPropSheetDlg: HWND, id: int32): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_SETCURSELID, 0, LPARAM(id))

+

+proc PropSheet_SetFinishText(hPropSheetDlg: HWND, lpszText: LPTSTR): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_SETFINISHTEXT, 0, cast[LPARAM](lpszText))

+

+proc PropSheet_SetTitle(hPropSheetDlg: HWND, dwStyle: DWORD, lpszText: LPCTSTR): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_SETTITLE, WPARAM(dwStyle),

+                       cast[LPARAM](lpszText))

+

+proc PropSheet_SetWizButtons(hPropSheetDlg: HWND, dwFlags: DWORD): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_SETWIZBUTTONS, 0, LPARAM(dwFlags))

+

+proc PropSheet_UnChanged(hPropSheetDlg: HWND, hwndPage: HWND): LRESULT =

+  result = SendMessage(hPropSheetDlg, PSM_UNCHANGED, WPARAM(hwndPage), 0)

+

+proc Header_DeleteItem(hwndHD: HWND, index: int32): WINBOOL =

+  result = WINBOOL(SendMessage(hwndHD, HDM_DELETEITEM, WPARAM(index), 0))

+

+proc Header_GetItem(hwndHD: HWND, index: int32, hdi: var HD_ITEM): WINBOOL =

+  result = WINBOOL(SendMessage(hwndHD, HDM_GETITEM, WPARAM(index),

+                               cast[LPARAM](addr(hdi))))

+

+proc Header_GetItemCount(hwndHD: HWND): int32 =

+  result = int32(SendMessage(hwndHD, HDM_GETITEMCOUNT, 0, 0))

+

+proc Header_InsertItem(hwndHD: HWND, index: int32, hdi: var HD_ITEM): int32 =

+  result = int32(SendMessage(hwndHD, HDM_INSERTITEM, WPARAM(index),

+                             cast[LPARAM](addr(hdi))))

+

+proc Header_Layout(hwndHD: HWND, layout: var HD_LAYOUT): WINBOOL =

+  result = WINBOOL(SendMessage(hwndHD, HDM_LAYOUT, 0,

+                   cast[LPARAM](addr(layout))))

+

+proc Header_SetItem(hwndHD: HWND, index: int32, hdi: var HD_ITEM): WINBOOL =

+  result = WINBOOL(SendMessage(hwndHD, HDM_SETITEM, WPARAM(index),

+                               cast[LPARAM](addr(hdi))))

+

+proc ListView_Arrange(hwndLV: HWND, code: WINUINT): LRESULT =

+  result = SendMessage(hwndLV, LVM_ARRANGE, WPARAM(code), 0)

+

+proc ListView_CreateDragImage(wnd: HWND, i: int32, lpptUpLeft: LPPOINT): LRESULT =

+  result = SendMessage(wnd, LVM_CREATEDRAGIMAGE, WPARAM(i), cast[LPARAM](lpptUpLeft))

+

+proc ListView_DeleteAllItems(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, LVM_DELETEALLITEMS, 0, 0)

+

+proc ListView_DeleteColumn(wnd: HWND, iCol: int32): LRESULT =

+  result = SendMessage(wnd, LVM_DELETECOLUMN, WPARAM(iCol), 0)

+

+proc ListView_DeleteItem(wnd: HWND, iItem: int32): LRESULT =

+  result = SendMessage(wnd, LVM_DELETEITEM, WPARAM(iItem), 0)

+

+proc ListView_EditLabel(hwndLV: HWND, i: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_EDITLABEL, WPARAM(int32(i)), 0)

+

+proc ListView_EnsureVisible(hwndLV: HWND, i, fPartialOK: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_ENSUREVISIBLE, WPARAM(i),

+                       MAKELPARAM(fPartialOK, 0))

+

+proc ListView_FindItem(wnd: HWND, iStart: int32, lvfi: var LV_FINDINFO): int32 =

+  result = SendMessage(wnd, LVM_FINDITEM, WPARAM(iStart),

+                       cast[LPARAM](addr(lvfi))).int32

+

+proc ListView_GetBkColor(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, LVM_GETBKCOLOR, 0, 0)

+

+proc ListView_GetCallbackMask(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, LVM_GETCALLBACKMASK, 0, 0)

+

+proc ListView_GetColumn(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT =

+  result = SendMessage(wnd, LVM_GETCOLUMN, WPARAM(iCol), cast[LPARAM](addr(col)))

+

+proc ListView_GetColumnWidth(wnd: HWND, iCol: int32): LRESULT =

+  result = SendMessage(wnd, LVM_GETCOLUMNWIDTH, WPARAM(iCol), 0)

+

+proc ListView_GetCountPerPage(hwndLV: HWND): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETCOUNTPERPAGE, 0, 0)

+

+proc ListView_GetEditControl(hwndLV: HWND): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETEDITCONTROL, 0, 0)

+

+proc ListView_GetImageList(wnd: HWND, iImageList: WINT): LRESULT =

+  result = SendMessage(wnd, LVM_GETIMAGELIST, WPARAM(iImageList), 0)

+

+proc ListView_GetISearchString(hwndLV: HWND, lpsz: LPTSTR): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETISEARCHSTRING, 0, cast[LPARAM](lpsz))

+

+proc ListView_GetItem(wnd: HWND, item: var LV_ITEM): LRESULT =

+  result = SendMessage(wnd, LVM_GETITEM, 0, cast[LPARAM](addr(item)))

+

+proc ListView_GetItemCount(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, LVM_GETITEMCOUNT, 0, 0)

+

+proc ListView_GetItemPosition(hwndLV: HWND, i: int32, pt: var POINT): int32 =

+  result = SendMessage(hwndLV, LVM_GETITEMPOSITION, WPARAM(int32(i)),

+                       cast[LPARAM](addr(pt))).int32

+

+proc ListView_GetItemSpacing(hwndLV: HWND, fSmall: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETITEMSPACING, fSmall, 0)

+

+proc ListView_GetItemState(hwndLV: HWND, i, mask: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETITEMSTATE, WPARAM(i), LPARAM(mask))

+

+proc ListView_GetNextItem(wnd: HWND, iStart, flags: int32): LRESULT =

+  result = SendMessage(wnd, LVM_GETNEXTITEM, WPARAM(iStart), LPARAM(flags))

+

+proc ListView_GetOrigin(hwndLV: HWND, pt: var POINT): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETORIGIN, WPARAM(0), cast[LPARAM](addr(pt)))

+

+proc ListView_GetSelectedCount(hwndLV: HWND): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETSELECTEDCOUNT, 0, 0)

+

+proc ListView_GetStringWidth(hwndLV: HWND, psz: LPCTSTR): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETSTRINGWIDTH, 0, cast[LPARAM](psz))

+

+proc ListView_GetTextBkColor(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, LVM_GETTEXTBKCOLOR, 0, 0)

+

+proc ListView_GetTextColor(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, LVM_GETTEXTCOLOR, 0, 0)

+

+proc ListView_GetTopIndex(hwndLV: HWND): LRESULT =

+  result = SendMessage(hwndLV, LVM_GETTOPINDEX, 0, 0)

+

+proc ListView_GetViewRect(wnd: HWND, rc: var RECT): LRESULT =

+  result = SendMessage(wnd, LVM_GETVIEWRECT, 0, cast[LPARAM](addr(rc)))

+

+proc ListView_HitTest(hwndLV: HWND, info: var LV_HITTESTINFO): LRESULT =

+  result = SendMessage(hwndLV, LVM_HITTEST, 0, cast[LPARAM](addr(info)))

+

+proc ListView_InsertColumn(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT =

+  result = SendMessage(wnd, LVM_INSERTCOLUMN, WPARAM(iCol), cast[LPARAM](addr(col)))

+

+proc ListView_InsertItem(wnd: HWND, item: var LV_ITEM): LRESULT =

+  result = SendMessage(wnd, LVM_INSERTITEM, 0, cast[LPARAM](addr(item)))

+

+proc ListView_RedrawItems(hwndLV: HWND, iFirst, iLast: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_REDRAWITEMS, WPARAM(iFirst), LPARAM(iLast))

+

+proc ListView_Scroll(hwndLV: HWND, dx, dy: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_SCROLL, WPARAM(dx), LPARAM(dy))

+

+proc ListView_SetBkColor(wnd: HWND, clrBk: COLORREF): LRESULT =

+  result = SendMessage(wnd, LVM_SETBKCOLOR, 0, LPARAM(clrBk))

+

+proc ListView_SetCallbackMask(wnd: HWND, mask: WINUINT): LRESULT =

+  result = SendMessage(wnd, LVM_SETCALLBACKMASK, WPARAM(mask), 0)

+

+proc ListView_SetColumn(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT =

+  result = SendMessage(wnd, LVM_SETCOLUMN, WPARAM(iCol), cast[LPARAM](addr(col)))

+

+proc ListView_SetColumnWidth(wnd: HWND, iCol, cx: int32): LRESULT =

+  result = SendMessage(wnd, LVM_SETCOLUMNWIDTH, WPARAM(iCol), MAKELPARAM(cx, 0))

+

+proc ListView_SetImageList(wnd: HWND, himl: int32, iImageList: HIMAGELIST): LRESULT =

+  result = SendMessage(wnd, LVM_SETIMAGELIST, WPARAM(iImageList),

+                       LPARAM(WINUINT(himl)))

+

+proc ListView_SetItem(wnd: HWND, item: var LV_ITEM): LRESULT =

+  result = SendMessage(wnd, LVM_SETITEM, 0, cast[LPARAM](addr(item)))

+

+proc ListView_SetItemCount(hwndLV: HWND, cItems: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_SETITEMCOUNT, WPARAM(cItems), 0)

+

+proc ListView_SetItemPosition(hwndLV: HWND, i, x, y: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_SETITEMPOSITION, WPARAM(i), MAKELPARAM(x, y))

+

+proc ListView_SetItemPosition32(hwndLV: HWND, i, x, y: int32): LRESULT =

+  var ptNewPos: POINT

+  ptNewPos.x = x

+  ptNewPos.y = y

+  result = SendMessage(hwndLV, LVM_SETITEMPOSITION32, WPARAM(i),

+                       cast[LPARAM](addr(ptNewPos)))

+

+proc ListView_SetItemState(hwndLV: HWND, i, data, mask: int32): LRESULT =

+  var gnu_lvi: LV_ITEM

+  gnu_lvi.stateMask = WINUINT(mask)

+  gnu_lvi.state = WINUINT(data)

+  result = SendMessage(hwndLV, LVM_SETITEMSTATE, WPARAM(i),

+                       cast[LPARAM](addr(gnu_lvi)))

+

+proc ListView_SetItemText(hwndLV: HWND, i, iSubItem: int32, pszText: LPTSTR): LRESULT =

+  var gnu_lvi: LV_ITEM

+  gnu_lvi.iSubItem = iSubItem

+  gnu_lvi.pszText = pszText

+  result = SendMessage(hwndLV, LVM_SETITEMTEXT, WPARAM(i),

+                       cast[LPARAM](addr(gnu_lvi)))

+

+proc ListView_SetTextBkColor(wnd: HWND, clrTextBk: COLORREF): LRESULT =

+  result = SendMessage(wnd, LVM_SETTEXTBKCOLOR, 0, LPARAM(clrTextBk))

+

+proc ListView_SetTextColor(wnd: HWND, clrText: COLORREF): LRESULT =

+  result = SendMessage(wnd, LVM_SETTEXTCOLOR, 0, LPARAM(clrText))

+

+proc ListView_SortItems(hwndLV: HWND, pfnCompare: PFNLVCOMPARE,

+                        lPrm: LPARAM): LRESULT =

+  result = SendMessage(hwndLV, LVM_SORTITEMS, WPARAM(lPrm),

+                       cast[LPARAM](pfnCompare))

+

+proc ListView_Update(hwndLV: HWND, i: int32): LRESULT =

+  result = SendMessage(hwndLV, LVM_UPDATE, WPARAM(i), 0)

+

+proc TreeView_InsertItem(wnd: HWND, lpis: LPTV_INSERTSTRUCT): LRESULT =

+  result = SendMessage(wnd, TVM_INSERTITEM, 0, cast[LPARAM](lpis))

+

+proc TreeView_DeleteItem(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = SendMessage(wnd, TVM_DELETEITEM, 0, cast[LPARAM](hitem))

+

+proc TreeView_DeleteAllItems(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TVM_DELETEITEM, 0, cast[LPARAM](TVI_ROOT))

+

+proc TreeView_Expand(wnd: HWND, hitem: HTREEITEM, code: int32): LRESULT =

+  result = SendMessage(wnd, TVM_EXPAND, WPARAM(code), cast[LPARAM](hitem))

+

+proc TreeView_GetCount(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TVM_GETCOUNT, 0, 0)

+

+proc TreeView_GetIndent(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TVM_GETINDENT, 0, 0)

+

+proc TreeView_SetIndent(wnd: HWND, indent: int32): LRESULT =

+  result = SendMessage(wnd, TVM_SETINDENT, WPARAM(indent), 0)

+

+proc TreeView_GetImageList(wnd: HWND, iImage: WPARAM): LRESULT =

+  result = SendMessage(wnd, TVM_GETIMAGELIST, iImage, 0)

+

+proc TreeView_SetImageList(wnd: HWND, himl: HIMAGELIST, iImage: WPARAM): LRESULT =

+  result = SendMessage(wnd, TVM_SETIMAGELIST, iImage, LPARAM(WINUINT(himl)))

+

+proc TreeView_GetNextItem(wnd: HWND, hitem: HTREEITEM, code: int32): LRESULT =

+  result = SendMessage(wnd, TVM_GETNEXTITEM, WPARAM(code), cast[LPARAM](hitem))

+

+proc TreeView_GetChild(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_GetNextItem(wnd, hitem, TVGN_CHILD)

+

+proc TreeView_GetNextSibling(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_GetNextItem(wnd, hitem, TVGN_NEXT)

+

+proc TreeView_GetPrevSibling(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_GetNextItem(wnd, hitem, TVGN_PREVIOUS)

+

+proc TreeView_GetParent(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_GetNextItem(wnd, hitem, TVGN_PARENT)

+

+proc TreeView_GetFirstVisible(wnd: HWND): LRESULT =

+  result = TreeView_GetNextItem(wnd, HTREEITEM(nil), TVGN_FIRSTVISIBLE)

+

+proc TreeView_GetNextVisible(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_GetNextItem(wnd, hitem, TVGN_NEXTVISIBLE)

+

+proc TreeView_GetPrevVisible(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_GetNextItem(wnd, hitem, TVGN_PREVIOUSVISIBLE)

+

+proc TreeView_GetSelection(wnd: HWND): LRESULT =

+  result = TreeView_GetNextItem(wnd, HTREEITEM(nil), TVGN_CARET)

+

+proc TreeView_GetDropHilight(wnd: HWND): LRESULT =

+  result = TreeView_GetNextItem(wnd, HTREEITEM(nil), TVGN_DROPHILITE)

+

+proc TreeView_GetRoot(wnd: HWND): LRESULT =

+  result = TreeView_GetNextItem(wnd, HTREEITEM(nil), TVGN_ROOT)

+

+proc TreeView_Select(wnd: HWND, hitem: HTREEITEM, code: int32): LRESULT =

+  result = SendMessage(wnd, TVM_SELECTITEM, WPARAM(code), cast[LPARAM](hitem))

+

+proc TreeView_SelectItem(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_Select(wnd, hitem, TVGN_CARET)

+

+proc TreeView_SelectDropTarget(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_Select(wnd, hitem, TVGN_DROPHILITE)

+

+proc TreeView_SelectSetFirstVisible(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = TreeView_Select(wnd, hitem, TVGN_FIRSTVISIBLE)

+

+proc TreeView_GetItem(wnd: HWND, item: var TV_ITEM): LRESULT =

+  result = SendMessage(wnd, TVM_GETITEM, 0, cast[LPARAM](addr(item)))

+

+proc TreeView_SetItem(wnd: HWND, item: var TV_ITEM): LRESULT =

+  result = SendMessage(wnd, TVM_SETITEM, 0, cast[LPARAM](addr(item)))

+

+proc TreeView_EditLabel(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = SendMessage(wnd, TVM_EDITLABEL, 0, cast[LPARAM](hitem))

+

+proc TreeView_GetEditControl(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TVM_GETEDITCONTROL, 0, 0)

+

+proc TreeView_GetVisibleCount(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TVM_GETVISIBLECOUNT, 0, 0)

+

+proc TreeView_HitTest(wnd: HWND, lpht: LPTV_HITTESTINFO): LRESULT =

+  result = SendMessage(wnd, TVM_HITTEST, 0, cast[LPARAM](lpht))

+

+proc TreeView_CreateDragImage(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = SendMessage(wnd, TVM_CREATEDRAGIMAGE, 0, cast[LPARAM](hitem))

+

+proc TreeView_SortChildren(wnd: HWND, hitem: HTREEITEM, recurse: int32): LRESULT =

+  result = SendMessage(wnd, TVM_SORTCHILDREN, WPARAM(recurse), cast[LPARAM](hitem))

+

+proc TreeView_EnsureVisible(wnd: HWND, hitem: HTREEITEM): LRESULT =

+  result = SendMessage(wnd, TVM_ENSUREVISIBLE, 0, cast[LPARAM](hitem))

+

+proc TreeView_SortChildrenCB(wnd: HWND, psort: LPTV_SORTCB, recurse: int32): LRESULT =

+  result = SendMessage(wnd, TVM_SORTCHILDRENCB, WPARAM(recurse), cast[LPARAM](psort))

+

+proc TreeView_EndEditLabelNow(wnd: HWND, fCancel: int32): LRESULT =

+  result = SendMessage(wnd, TVM_ENDEDITLABELNOW, WPARAM(fCancel), 0)

+

+proc TreeView_GetISearchString(hwndTV: HWND, lpsz: LPTSTR): LRESULT =

+  result = SendMessage(hwndTV, TVM_GETISEARCHSTRING, 0, cast[LPARAM](lpsz))

+

+proc TabCtrl_GetImageList(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_GETIMAGELIST, 0, 0)

+

+proc TabCtrl_SetImageList(wnd: HWND, himl: HIMAGELIST): LRESULT =

+  result = SendMessage(wnd, TCM_SETIMAGELIST, 0, LPARAM(WINUINT(himl)))

+

+proc TabCtrl_GetItemCount(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_GETITEMCOUNT, 0, 0)

+

+proc TabCtrl_GetItem(wnd: HWND, iItem: int32, item: var TC_ITEM): LRESULT =

+  result = SendMessage(wnd, TCM_GETITEM, WPARAM(iItem), cast[LPARAM](addr(item)))

+

+proc TabCtrl_SetItem(wnd: HWND, iItem: int32, item: var TC_ITEM): LRESULT =

+  result = SendMessage(wnd, TCM_SETITEM, WPARAM(iItem), cast[LPARAM](addr(item)))

+

+proc TabCtrl_InsertItem(wnd: HWND, iItem: int32, item: var TC_ITEM): LRESULT =

+  result = SendMessage(wnd, TCM_INSERTITEM, WPARAM(iItem), cast[LPARAM](addr(item)))

+

+proc TabCtrl_DeleteItem(wnd: HWND, i: int32): LRESULT =

+  result = SendMessage(wnd, TCM_DELETEITEM, WPARAM(i), 0)

+

+proc TabCtrl_DeleteAllItems(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_DELETEALLITEMS, 0, 0)

+

+proc TabCtrl_GetItemRect(wnd: HWND, i: int32, rc: var RECT): LRESULT =

+  result = SendMessage(wnd, TCM_GETITEMRECT, WPARAM(int32(i)), cast[LPARAM](addr(rc)))

+

+proc TabCtrl_GetCurSel(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_GETCURSEL, 0, 0)

+

+proc TabCtrl_SetCurSel(wnd: HWND, i: int32): LRESULT =

+  result = SendMessage(wnd, TCM_SETCURSEL, WPARAM(i), 0)

+

+proc TabCtrl_HitTest(hwndTC: HWND, info: var TC_HITTESTINFO): LRESULT =

+  result = SendMessage(hwndTC, TCM_HITTEST, 0, cast[LPARAM](addr(info)))

+

+proc TabCtrl_SetItemExtra(hwndTC: HWND, cb: int32): LRESULT =

+  result = SendMessage(hwndTC, TCM_SETITEMEXTRA, WPARAM(cb), 0)

+

+proc TabCtrl_AdjustRect(wnd: HWND, bLarger: WINBOOL, rc: var RECT): LRESULT =

+  result = SendMessage(wnd, TCM_ADJUSTRECT, WPARAM(bLarger), cast[LPARAM](addr(rc)))

+

+proc TabCtrl_SetItemSize(wnd: HWND, x, y: int32): LRESULT =

+  result = SendMessage(wnd, TCM_SETITEMSIZE, 0, MAKELPARAM(x, y))

+

+proc TabCtrl_RemoveImage(wnd: HWND, i: WPARAM): LRESULT =

+  result = SendMessage(wnd, TCM_REMOVEIMAGE, i, 0)

+

+proc TabCtrl_SetPadding(wnd: HWND, cx, cy: int32): LRESULT =

+  result = SendMessage(wnd, TCM_SETPADDING, 0, MAKELPARAM(cx, cy))

+

+proc TabCtrl_GetRowCount(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_GETROWCOUNT, 0, 0)

+

+proc TabCtrl_GetToolTips(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_GETTOOLTIPS, 0, 0)

+

+proc TabCtrl_SetToolTips(wnd: HWND, hwndTT: int32): LRESULT =

+  result = SendMessage(wnd, TCM_SETTOOLTIPS, WPARAM(hwndTT), 0)

+

+proc TabCtrl_GetCurFocus(wnd: HWND): LRESULT =

+  result = SendMessage(wnd, TCM_GETCURFOCUS, 0, 0)

+

+proc TabCtrl_SetCurFocus(wnd: HWND, i: int32): LRESULT =

+  result = SendMessage(wnd, TCM_SETCURFOCUS, i, 0)

+

+proc SNDMSG(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM): LRESULT =

+  result = SendMessage(wnd, Msg, wp, lp)

+

+proc CommDlg_OpenSave_GetSpecA(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETSPEC, WPARAM(cbmax), cast[LPARAM](psz))

+

+proc CommDlg_OpenSave_GetSpecW(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETSPEC, WPARAM(cbmax), cast[LPARAM](psz))

+

+when defined(winUnicode):

+  proc CommDlg_OpenSave_GetSpec(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT =

+    result = SNDMSG(hdlg, CDM_GETSPEC, WPARAM(cbmax), cast[LPARAM](psz))

+else:

+  proc CommDlg_OpenSave_GetSpec(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT =

+    result = SNDMSG(hdlg, CDM_GETSPEC, WPARAM(cbmax), cast[LPARAM](psz))

+

+proc CommDlg_OpenSave_GetFilePathA(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETFILEPATH, WPARAM(cbmax), cast[LPARAM](psz))

+

+proc CommDlg_OpenSave_GetFilePathW(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETFILEPATH, WPARAM(cbmax), cast[LPARAM](psz))

+

+when defined(winUnicode):

+  proc CommDlg_OpenSave_GetFilePath(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT =

+    result = SNDMSG(hdlg, CDM_GETFILEPATH, WPARAM(cbmax), cast[LPARAM](psz))

+else:

+  proc CommDlg_OpenSave_GetFilePath(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT =

+    result = SNDMSG(hdlg, CDM_GETFILEPATH, WPARAM(cbmax), cast[LPARAM](psz))

+

+proc CommDlg_OpenSave_GetFolderPathA(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETFOLDERPATH, WPARAM(cbmax), cast[LPARAM](psz))

+

+proc CommDlg_OpenSave_GetFolderPathW(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETFOLDERPATH, WPARAM(cbmax), cast[LPARAM](psz))

+

+when defined(winUnicode):

+  proc CommDlg_OpenSave_GetFolderPath(hdlg: HWND, psz: LPWSTR, cbmax: int32): LRESULT =

+    result = SNDMSG(hdlg, CDM_GETFOLDERPATH, WPARAM(cbmax), cast[LPARAM]((psz)))

+else:

+  proc CommDlg_OpenSave_GetFolderPath(hdlg: HWND, psz: LPSTR, cbmax: int32): LRESULT =

+    result = SNDMSG(hdlg, CDM_GETFOLDERPATH, WPARAM(cbmax), cast[LPARAM](psz))

+

+proc CommDlg_OpenSave_GetFolderIDList(hdlg: HWND, pidl: LPVOID, cbmax: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_GETFOLDERIDLIST, WPARAM(cbmax), cast[LPARAM](pidl))

+

+proc CommDlg_OpenSave_SetControlText(hdlg: HWND, id: int32, text: LPSTR): LRESULT =

+  result = SNDMSG(hdlg, CDM_SETCONTROLTEXT, WPARAM(id), cast[LPARAM](text))

+

+proc CommDlg_OpenSave_HideControl(hdlg: HWND, id: int32): LRESULT =

+  result = SNDMSG(hdlg, CDM_HIDECONTROL, WPARAM(id), 0)

+

+proc CommDlg_OpenSave_SetDefExt(hdlg: HWND, pszext: LPSTR): LRESULT =

+  result = SNDMSG(hdlg, CDM_SETDEFEXT, 0, cast[LPARAM](pszext))

+

+proc InternalGetLargestConsoleWindowSize(hConsoleOutput: HANDLE): DWord{.

+    stdcall, dynlib: "kernel32", importc: "GetLargestConsoleWindowSize".}

+proc GetLargestConsoleWindowSize(hConsoleOutput: HANDLE): COORD =

+  var res: DWORD

+  res = InternalGetLargestConsoleWindowSize(hConsoleOutput)

+  result.Y = toU16(res and 0x0000ffff) # XXX: correct?

+  result.X = toU16(res shr 16)

+

+proc Succeeded(Status: HRESULT): WINBOOL =

+  result = (Status and 0x80000000).WinBool

+

+proc Failed(Status: HRESULT): WINBOOL =

+  result = (Status and 0x80000000).WinBool

+

+proc IsError(Status: HRESULT): WINBOOL =

+  result = ord((int(Status) shr 31) == SEVERITY_ERROR)

+

+proc HResultCode(hr: HRESULT): int32 =

+  result = hr and 0x0000FFFF'i32

+

+proc HResultFacility(hr: HRESULT): int32 =

+  result = (hr shr 16'i32) and 0x00001FFF'i32

+

+proc HResultSeverity(hr: HRESULT): int32 =

+  result = (hr shr 31'i32) and 0x00000001'i32

+

+proc MakeResult(p1, p2, mask: int32): HRESULT =

+  result = (p1 shl 31'i32) or (p2 shl 16'i32) or mask

+

+proc HResultFromWin32(x: int32): HRESULT =

+  result = x

+  if result != 0'i32:

+    result = ((result and 0x0000FFFF'i32) or (int32(FACILITY_WIN32) shl 16'i32) or

+        0x80000000'i32)

+

+proc HResultFromNT(x: int32): HRESULT =

+  result = x or int32(FACILITY_NT_BIT)

+

+proc MAKELANGID(PrimaryLang, SubLang: USHORT): int16 =

+  result = (SubLang shl 10'i16) or PrimaryLang

+

+proc PRIMARYLANGID(LangId: int16): int16 =

+  result = LangId and 0x000003FF'i16

+

+proc SUBLANGID(LangId: int16): int16 =

+  result = LangId shr 10'i16

+

+proc MAKELCID(LangId, SortId: int16): DWORD =

+  result = toU32((ze(SortId) shl 16) or ze(LangId))

+

+proc MAKESORTLCID(LangId, SortId, SortVersion: int16): DWORD =

+  result = MAKELCID(LangId, SortId) or (SortVersion shl 20'i32)

+

+proc LANGIDFROMLCID(LocaleId: LCID): int16 =

+  result = toU16(LocaleId)

+

+proc SORTIDFROMLCID(LocaleId: LCID): int16 =

+  result = toU16((DWORD(LocaleId) shr 16) and 0x0000000F)

+

+proc SORTVERSIONFROMLCID(LocaleId: LCID): int16 =

+  result = toU16((DWORD(LocaleId) shr 20) and 0x0000000F)

+

+proc LANG_SYSTEM_DEFAULT(): int16 =

+  result = toU16(MAKELANGID(toU16(LANG_NEUTRAL), SUBLANG_SYS_DEFAULT))

+

+proc LANG_USER_DEFAULT(): int16 =

+  result = toU16(MAKELANGID(toU16(LANG_NEUTRAL), SUBLANG_DEFAULT))

+

+proc LOCALE_NEUTRAL(): DWORD =

+  result = MAKELCID(MAKELANGID(toU16(LANG_NEUTRAL), SUBLANG_NEUTRAL), SORT_DEFAULT)

+

+proc LOCALE_INVARIANT(): DWORD =

+  result = MAKELCID(MAKELANGID(toU16(LANG_INVARIANT), SUBLANG_NEUTRAL), SORT_DEFAULT)

+

+{.pop.}

diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
new file mode 100644
index 000000000..57b79c7de
--- /dev/null
+++ b/lib/windows/winlean.nim
@@ -0,0 +1,757 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a small wrapper for some needed Win API procedures,
+## so that the Nim compiler does not depend on the huge Windows module.
+
+{.deadCodeElim:on.}
+
+const
+  useWinUnicode* = not defined(useWinAnsi)
+
+type
+  THandle* = int
+  LONG* = int32
+  ULONG* = int
+  PULONG* = ptr int
+  WINBOOL* = int32
+  DWORD* = int32
+  PDWORD* = ptr DWORD
+  LPINT* = ptr int32
+  HDC* = THandle
+  HGLRC* = THandle
+
+  TSECURITY_ATTRIBUTES* {.final, pure.} = object
+    nLength*: int32
+    lpSecurityDescriptor*: pointer
+    bInheritHandle*: WINBOOL
+
+  TSTARTUPINFO* {.final, pure.} = object
+    cb*: int32
+    lpReserved*: cstring
+    lpDesktop*: cstring
+    lpTitle*: cstring
+    dwX*: int32
+    dwY*: int32
+    dwXSize*: int32
+    dwYSize*: int32
+    dwXCountChars*: int32
+    dwYCountChars*: int32
+    dwFillAttribute*: int32
+    dwFlags*: int32
+    wShowWindow*: int16
+    cbReserved2*: int16
+    lpReserved2*: pointer
+    hStdInput*: THandle
+    hStdOutput*: THandle
+    hStdError*: THandle
+
+  TPROCESS_INFORMATION* {.final, pure.} = object
+    hProcess*: THandle
+    hThread*: THandle
+    dwProcessId*: int32
+    dwThreadId*: int32
+
+  TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
+    dwLowDateTime*: DWORD
+    dwHighDateTime*: DWORD
+
+  TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
+    dwFileAttributes*: DWORD
+    ftCreationTime*: TFILETIME
+    ftLastAccessTime*: TFILETIME
+    ftLastWriteTime*: TFILETIME
+    dwVolumeSerialNumber*: DWORD
+    nFileSizeHigh*: DWORD
+    nFileSizeLow*: DWORD
+    nNumberOfLinks*: DWORD
+    nFileIndexHigh*: DWORD
+    nFileIndexLow*: DWORD
+
+when useWinUnicode:
+  type TWinChar* = TUtf16Char
+else:
+  type TWinChar* = char
+
+const
+  STARTF_USESHOWWINDOW* = 1'i32
+  STARTF_USESTDHANDLES* = 256'i32
+  HIGH_PRIORITY_CLASS* = 128'i32
+  IDLE_PRIORITY_CLASS* = 64'i32
+  NORMAL_PRIORITY_CLASS* = 32'i32
+  REALTIME_PRIORITY_CLASS* = 256'i32
+  WAIT_OBJECT_0* = 0'i32
+  WAIT_TIMEOUT* = 0x00000102'i32
+  WAIT_FAILED* = 0xFFFFFFFF'i32
+  INFINITE* = -1'i32
+
+  STD_INPUT_HANDLE* = -10'i32
+  STD_OUTPUT_HANDLE* = -11'i32
+  STD_ERROR_HANDLE* = -12'i32
+
+  DETACHED_PROCESS* = 8'i32
+
+  SW_SHOWNORMAL* = 1'i32
+  INVALID_HANDLE_VALUE* = THandle(-1)
+
+  CREATE_UNICODE_ENVIRONMENT* = 1024'i32
+
+proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
+    importc: "CloseHandle".}
+
+proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
+               lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "ReadFile".}
+
+proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
+                lpNumberOfBytesWritten: ptr int32,
+                lpOverlapped: pointer): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "WriteFile".}
+
+proc createPipe*(hReadPipe, hWritePipe: var THandle,
+                 lpPipeAttributes: var TSECURITY_ATTRIBUTES,
+                 nSize: int32): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "CreatePipe".}
+
+when useWinUnicode:
+  proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
+                     lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
+                     lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
+                     bInheritHandles: WINBOOL, dwCreationFlags: int32,
+                     lpEnvironment, lpCurrentDirectory: WideCString,
+                     lpStartupInfo: var TSTARTUPINFO,
+                     lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "CreateProcessW".}
+
+else:
+  proc createProcessA*(lpApplicationName, lpCommandLine: cstring,
+                       lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
+                       lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
+                       bInheritHandles: WINBOOL, dwCreationFlags: int32,
+                       lpEnvironment: pointer, lpCurrentDirectory: cstring,
+                       lpStartupInfo: var TSTARTUPINFO,
+                       lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
+      stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
+
+
+proc suspendThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
+    importc: "SuspendThread".}
+proc resumeThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
+    importc: "ResumeThread".}
+
+proc waitForSingleObject*(hHandle: THandle, dwMilliseconds: int32): int32 {.
+    stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
+
+proc terminateProcess*(hProcess: THandle, uExitCode: int): WINBOOL {.stdcall,
+    dynlib: "kernel32", importc: "TerminateProcess".}
+
+proc getExitCodeProcess*(hProcess: THandle, lpExitCode: var int32): WINBOOL {.
+    stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
+
+proc getStdHandle*(nStdHandle: int32): THandle {.stdcall, dynlib: "kernel32",
+    importc: "GetStdHandle".}
+proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
+    dynlib: "kernel32", importc: "SetStdHandle".}
+proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
+    importc: "FlushFileBuffers".}
+
+proc getLastError*(): int32 {.importc: "GetLastError",
+    stdcall, dynlib: "kernel32".}
+
+when useWinUnicode:
+  proc formatMessageW*(dwFlags: int32, lpSource: pointer,
+                      dwMessageId, dwLanguageId: int32,
+                      lpBuffer: pointer, nSize: int32,
+                      Arguments: pointer): int32 {.
+                      importc: "FormatMessageW", stdcall, dynlib: "kernel32".}
+else:
+  proc formatMessageA*(dwFlags: int32, lpSource: pointer,
+                    dwMessageId, dwLanguageId: int32,
+                    lpBuffer: pointer, nSize: int32,
+                    Arguments: pointer): int32 {.
+                    importc: "FormatMessageA", stdcall, dynlib: "kernel32".}
+
+proc localFree*(p: pointer) {.
+  importc: "LocalFree", stdcall, dynlib: "kernel32".}
+
+when useWinUnicode:
+  proc getCurrentDirectoryW*(nBufferLength: int32,
+                             lpBuffer: WideCString): int32 {.
+    importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
+  proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {.
+    importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
+  proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {.
+    importc: "CreateDirectoryW", dynlib: "kernel32", stdcall.}
+  proc removeDirectoryW*(lpPathName: WideCString): int32 {.
+    importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall.}
+  proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
+    stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
+
+  proc getModuleFileNameW*(handle: THandle, buf: WideCString,
+                           size: int32): int32 {.importc: "GetModuleFileNameW",
+    dynlib: "kernel32", stdcall.}
+else:
+  proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {.
+    importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
+  proc setCurrentDirectoryA*(lpPathName: cstring): int32 {.
+    importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
+  proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {.
+    importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.}
+  proc removeDirectoryA*(lpPathName: cstring): int32 {.
+    importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.}
+  proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
+    stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
+
+  proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
+    importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
+
+when useWinUnicode:
+  proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString,
+                         flags: DWORD): int32 {.
+    importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall.}
+  proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString,
+                         security: pointer=nil): int32 {.
+    importc:"CreateHardLinkW", dynlib: "kernel32", stdcall.}
+else:
+  proc createSymbolicLinkA*(lpSymlinkFileName, lpTargetFileName: cstring,
+                           flags: DWORD): int32 {.
+    importc:"CreateSymbolicLinkA", dynlib: "kernel32", stdcall.}
+  proc createHardLinkA*(lpFileName, lpExistingFileName: cstring,
+                           security: pointer=nil): int32 {.
+    importc:"CreateHardLinkA", dynlib: "kernel32", stdcall.}
+
+const
+  FILE_ATTRIBUTE_ARCHIVE* = 32'i32
+  FILE_ATTRIBUTE_COMPRESSED* = 2048'i32
+  FILE_ATTRIBUTE_NORMAL* = 128'i32
+  FILE_ATTRIBUTE_DIRECTORY* = 16'i32
+  FILE_ATTRIBUTE_HIDDEN* = 2'i32
+  FILE_ATTRIBUTE_READONLY* = 1'i32
+  FILE_ATTRIBUTE_REPARSE_POINT* = 1024'i32
+  FILE_ATTRIBUTE_SYSTEM* = 4'i32
+  FILE_ATTRIBUTE_TEMPORARY* = 256'i32
+
+  MAX_PATH* = 260
+type
+  TWIN32_FIND_DATA* {.pure.} = object
+    dwFileAttributes*: int32
+    ftCreationTime*: TFILETIME
+    ftLastAccessTime*: TFILETIME
+    ftLastWriteTime*: TFILETIME
+    nFileSizeHigh*: int32
+    nFileSizeLow*: int32
+    dwReserved0: int32
+    dwReserved1: int32
+    cFileName*: array[0..(MAX_PATH) - 1, TWinChar]
+    cAlternateFileName*: array[0..13, TWinChar]
+
+when useWinUnicode:
+  proc findFirstFileW*(lpFileName: WideCString,
+                      lpFindFileData: var TWIN32_FIND_DATA): THandle {.
+      stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}
+  proc findNextFileW*(hFindFile: THandle,
+                     lpFindFileData: var TWIN32_FIND_DATA): int32 {.
+      stdcall, dynlib: "kernel32", importc: "FindNextFileW".}
+else:
+  proc findFirstFileA*(lpFileName: cstring,
+                      lpFindFileData: var TWIN32_FIND_DATA): THANDLE {.
+      stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}
+  proc findNextFileA*(hFindFile: THANDLE,
+                     lpFindFileData: var TWIN32_FIND_DATA): int32 {.
+      stdcall, dynlib: "kernel32", importc: "FindNextFileA".}
+
+proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
+  importc: "FindClose".}
+
+when useWinUnicode:
+  proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32,
+                        lpBuffer: WideCString,
+                        lpFilePart: var WideCString): int32 {.
+                        stdcall, dynlib: "kernel32",
+                        importc: "GetFullPathNameW".}
+  proc getFileAttributesW*(lpFileName: WideCString): int32 {.
+                          stdcall, dynlib: "kernel32",
+                          importc: "GetFileAttributesW".}
+  proc setFileAttributesW*(lpFileName: WideCString,
+                           dwFileAttributes: int32): WINBOOL {.
+      stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}
+
+  proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString,
+                 bFailIfExists: cint): cint {.
+    importc: "CopyFileW", stdcall, dynlib: "kernel32".}
+
+  proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString,
+                 bFailIfExists: cint): cint {.
+    importc: "MoveFileW", stdcall, dynlib: "kernel32".}
+
+  proc getEnvironmentStringsW*(): WideCString {.
+    stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
+  proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
+    stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW".}
+
+  proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW",
+    stdcall, dynlib: "kernel32".}
+
+else:
+  proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32,
+                        lpBuffer: cstring, lpFilePart: var cstring): int32 {.
+                        stdcall, dynlib: "kernel32",
+                        importc: "GetFullPathNameA".}
+  proc getFileAttributesA*(lpFileName: cstring): int32 {.
+                          stdcall, dynlib: "kernel32",
+                          importc: "GetFileAttributesA".}
+  proc setFileAttributesA*(lpFileName: cstring,
+                           dwFileAttributes: int32): WINBOOL {.
+      stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
+
+  proc copyFileA*(lpExistingFileName, lpNewFileName: cstring,
+                 bFailIfExists: cint): cint {.
+    importc: "CopyFileA", stdcall, dynlib: "kernel32".}
+
+  proc moveFileA*(lpExistingFileName, lpNewFileName: cstring,
+                 bFailIfExists: cint): cint {.
+    importc: "MoveFileA", stdcall, dynlib: "kernel32".}
+
+  proc getEnvironmentStringsA*(): cstring {.
+    stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
+  proc freeEnvironmentStringsA*(para1: cstring): int32 {.
+    stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsA".}
+
+  proc getCommandLineA*(): cstring {.
+    importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
+
+proc rdFileTime*(f: TFILETIME): int64 =
+  result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
+
+proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
+  result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
+
+proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
+  importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.}
+
+proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32",
+                                    importc: "Sleep".}
+
+when useWinUnicode:
+  proc shellExecuteW*(HWND: THandle, lpOperation, lpFile,
+                     lpParameters, lpDirectory: WideCString,
+                     nShowCmd: int32): THandle{.
+      stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".}
+
+else:
+  proc shellExecuteA*(HWND: THandle, lpOperation, lpFile,
+                     lpParameters, lpDirectory: cstring,
+                     nShowCmd: int32): THandle{.
+      stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
+
+proc getFileInformationByHandle*(hFile: THandle,
+  lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
+
+const
+  WSADESCRIPTION_LEN* = 256
+  WSASYS_STATUS_LEN* = 128
+  FD_SETSIZE* = 64
+  MSG_PEEK* = 2
+
+  INADDR_ANY* = 0
+  INADDR_LOOPBACK* = 0x7F000001
+  INADDR_BROADCAST* = -1
+  INADDR_NONE* = -1
+
+  ws2dll = "Ws2_32.dll"
+
+  WSAEWOULDBLOCK* = 10035
+  WSAEINPROGRESS* = 10036
+
+proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
+
+type
+  SocketHandle* = distinct int
+
+{.deprecated: [TSocketHandle: SocketHandle].}
+
+type
+  WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
+    wVersion, wHighVersion: int16
+    szDescription: array[0..WSADESCRIPTION_LEN, char]
+    szSystemStatus: array[0..WSASYS_STATUS_LEN, char]
+    iMaxSockets, iMaxUdpDg: int16
+    lpVendorInfo: cstring
+
+  SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object
+    sa_family*: int16 # unsigned
+    sa_data: array[0..13, char]
+
+  InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object
+    s_addr*: int32  # IP address
+
+  Sockaddr_in* {.importc: "SOCKADDR_IN",
+                  header: "winsock2.h".} = object
+    sin_family*: int16
+    sin_port*: int16 # unsigned
+    sin_addr*: InAddr
+    sin_zero*: array[0..7, char]
+
+  In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object
+    bytes*: array[0..15, char]
+
+  Sockaddr_in6* {.importc: "SOCKADDR_IN6",
+                   header: "winsock2.h".} = object
+    sin6_family*: int16
+    sin6_port*: int16 # unsigned
+    sin6_flowinfo*: int32 # unsigned
+    sin6_addr*: In6_addr
+    sin6_scope_id*: int32 # unsigned
+
+  Sockaddr_in6_old* = object
+    sin6_family*: int16
+    sin6_port*: int16 # unsigned
+    sin6_flowinfo*: int32 # unsigned
+    sin6_addr*: In6_addr
+
+  Servent* = object
+    s_name*: cstring
+    s_aliases*: cstringArray
+    when defined(cpu64):
+      s_proto*: cstring
+      s_port*: int16
+    else:
+      s_port*: int16
+      s_proto*: cstring
+
+  Hostent* = object
+    h_name*: cstring
+    h_aliases*: cstringArray
+    h_addrtype*: int16
+    h_length*: int16
+    h_addr_list*: cstringArray
+
+  TFdSet* = object
+    fd_count*: cint # unsigned
+    fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
+
+  Timeval* = object
+    tv_sec*, tv_usec*: int32
+
+  AddrInfo* = object
+    ai_flags*: cint         ## Input flags.
+    ai_family*: cint        ## Address family of socket.
+    ai_socktype*: cint      ## Socket type.
+    ai_protocol*: cint      ## Protocol of socket.
+    ai_addrlen*: int        ## Length of socket address.
+    ai_canonname*: cstring  ## Canonical name of service location.
+    ai_addr*: ptr SockAddr ## Socket address of socket.
+    ai_next*: ptr AddrInfo ## Pointer to next in list.
+
+  SockLen* = cuint
+
+{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
+    TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
+    TWSADATA: WSADATA, Thostent: Hostent, TServent: Servent,
+    TInAddr: InAddr, Tin6_addr: In6_addr, Tsockaddr_in6: Sockaddr_in6,
+    Tsockaddr_in6_old: Sockaddr_in6_old].}
+
+
+var
+  SOMAXCONN* {.importc, header: "winsock2.h".}: cint
+  INVALID_SOCKET* {.importc, header: "winsock2.h".}: SocketHandle
+  SOL_SOCKET* {.importc, header: "winsock2.h".}: cint
+  SO_DEBUG* {.importc, header: "winsock2.h".}: cint ## turn on debugging info recording
+  SO_ACCEPTCONN* {.importc, header: "winsock2.h".}: cint # socket has had listen()
+  SO_REUSEADDR* {.importc, header: "winsock2.h".}: cint # allow local address reuse
+  SO_KEEPALIVE* {.importc, header: "winsock2.h".}: cint # keep connections alive
+  SO_DONTROUTE* {.importc, header: "winsock2.h".}: cint # just use interface addresses
+  SO_BROADCAST* {.importc, header: "winsock2.h".}: cint # permit sending of broadcast msgs
+  SO_USELOOPBACK* {.importc, header: "winsock2.h".}: cint # bypass hardware when possible
+  SO_LINGER* {.importc, header: "winsock2.h".}: cint # linger on close if data present
+  SO_OOBINLINE* {.importc, header: "winsock2.h".}: cint # leave received OOB data in line
+
+  SO_DONTLINGER* {.importc, header: "winsock2.h".}: cint
+  SO_EXCLUSIVEADDRUSE* {.importc, header: "winsock2.h".}: cint # disallow local address reuse
+  SO_ERROR* {.importc, header: "winsock2.h".}: cint
+
+proc `==`*(x, y: SocketHandle): bool {.borrow.}
+
+proc getservbyname*(name, proto: cstring): ptr Servent {.
+  stdcall, importc: "getservbyname", dynlib: ws2dll.}
+
+proc getservbyport*(port: cint, proto: cstring): ptr Servent {.
+  stdcall, importc: "getservbyport", dynlib: ws2dll.}
+
+proc gethostbyaddr*(ip: ptr InAddr, len: cuint, theType: cint): ptr Hostent {.
+  stdcall, importc: "gethostbyaddr", dynlib: ws2dll.}
+
+proc gethostbyname*(name: cstring): ptr Hostent {.
+  stdcall, importc: "gethostbyname", dynlib: ws2dll.}
+
+proc socket*(af, typ, protocol: cint): SocketHandle {.
+  stdcall, importc: "socket", dynlib: ws2dll.}
+
+proc closesocket*(s: SocketHandle): cint {.
+  stdcall, importc: "closesocket", dynlib: ws2dll.}
+
+proc accept*(s: SocketHandle, a: ptr SockAddr, addrlen: ptr SockLen): SocketHandle {.
+  stdcall, importc: "accept", dynlib: ws2dll.}
+proc bindSocket*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
+  stdcall, importc: "bind", dynlib: ws2dll.}
+proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
+  stdcall, importc: "connect", dynlib: ws2dll.}
+proc getsockname*(s: SocketHandle, name: ptr SockAddr,
+                  namelen: ptr SockLen): cint {.
+  stdcall, importc: "getsockname", dynlib: ws2dll.}
+proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
+                 optlen: ptr SockLen): cint {.
+  stdcall, importc: "getsockopt", dynlib: ws2dll.}
+proc setsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
+                 optlen: SockLen): cint {.
+  stdcall, importc: "setsockopt", dynlib: ws2dll.}
+
+proc listen*(s: SocketHandle, backlog: cint): cint {.
+  stdcall, importc: "listen", dynlib: ws2dll.}
+proc recv*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
+  stdcall, importc: "recv", dynlib: ws2dll.}
+proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
+               fromm: ptr SockAddr, fromlen: ptr SockLen): cint {.
+  stdcall, importc: "recvfrom", dynlib: ws2dll.}
+proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
+             timeout: ptr Timeval): cint {.
+  stdcall, importc: "select", dynlib: ws2dll.}
+proc send*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
+  stdcall, importc: "send", dynlib: ws2dll.}
+proc sendto*(s: SocketHandle, buf: pointer, len, flags: cint,
+             to: ptr SockAddr, tolen: SockLen): cint {.
+  stdcall, importc: "sendto", dynlib: ws2dll.}
+
+proc shutdown*(s: SocketHandle, how: cint): cint {.
+  stdcall, importc: "shutdown", dynlib: ws2dll.}
+
+proc getnameinfo*(a1: ptr SockAddr, a2: SockLen,
+                  a3: cstring, a4: SockLen, a5: cstring,
+                  a6: SockLen, a7: cint): cint {.
+  stdcall, importc: "getnameinfo", dynlib: ws2dll.}
+
+proc inet_addr*(cp: cstring): int32 {.
+  stdcall, importc: "inet_addr", dynlib: ws2dll.}
+
+proc WSAFDIsSet(s: SocketHandle, set: var TFdSet): bool {.
+  stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.}
+
+proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint =
+  result = if WSAFDIsSet(socket, set): 1'i32 else: 0'i32
+
+proc FD_SET*(socket: SocketHandle, s: var TFdSet) =
+  if s.fd_count < FD_SETSIZE:
+    s.fd_array[int(s.fd_count)] = socket
+    inc(s.fd_count)
+
+proc FD_ZERO*(s: var TFdSet) =
+  s.fd_count = 0
+
+proc wsaStartup*(wVersionRequired: int16, WSData: ptr WSAData): cint {.
+  stdcall, importc: "WSAStartup", dynlib: ws2dll.}
+
+proc getaddrinfo*(nodename, servname: cstring, hints: ptr AddrInfo,
+                  res: var ptr AddrInfo): cint {.
+  stdcall, importc: "getaddrinfo", dynlib: ws2dll.}
+
+proc freeaddrinfo*(ai: ptr AddrInfo) {.
+  stdcall, importc: "freeaddrinfo", dynlib: ws2dll.}
+
+proc inet_ntoa*(i: InAddr): cstring {.
+  stdcall, importc, dynlib: ws2dll.}
+
+const
+  MAXIMUM_WAIT_OBJECTS* = 0x00000040
+
+type
+  TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THandle]
+  PWOHandleArray* = ptr TWOHandleArray
+
+proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
+                             bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
+    stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
+
+
+# for memfiles.nim:
+
+const
+  GENERIC_READ* = 0x80000000'i32
+  GENERIC_WRITE* = 0x40000000'i32
+  GENERIC_ALL* = 0x10000000'i32
+  FILE_SHARE_READ* = 1'i32
+  FILE_SHARE_DELETE* = 4'i32
+  FILE_SHARE_WRITE* = 2'i32
+
+  CREATE_ALWAYS* = 2'i32
+  CREATE_NEW* = 1'i32
+  OPEN_EXISTING* = 3'i32
+  FILE_BEGIN* = 0'i32
+  INVALID_SET_FILE_POINTER* = -1'i32
+  NO_ERROR* = 0'i32
+  PAGE_READONLY* = 2'i32
+  PAGE_READWRITE* = 4'i32
+  FILE_MAP_READ* = 4'i32
+  FILE_MAP_WRITE* = 2'i32
+  INVALID_FILE_SIZE* = -1'i32
+
+  FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
+  FILE_FLAG_OPEN_REPARSE_POINT* = 0x00200000'i32
+
+# Error Constants
+const
+  ERROR_ACCESS_DENIED* = 5
+  ERROR_HANDLE_EOF* = 38
+
+when useWinUnicode:
+  proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
+                    lpSecurityAttributes: pointer,
+                    dwCreationDisposition, dwFlagsAndAttributes: DWORD,
+                    hTemplateFile: THandle): THandle {.
+      stdcall, dynlib: "kernel32", importc: "CreateFileW".}
+  proc deleteFileW*(pathName: WideCString): int32 {.
+    importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
+else:
+  proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
+                    lpSecurityAttributes: pointer,
+                    dwCreationDisposition, dwFlagsAndAttributes: DWORD,
+                    hTemplateFile: THANDLE): THANDLE {.
+      stdcall, dynlib: "kernel32", importc: "CreateFileA".}
+  proc deleteFileA*(pathName: cstring): int32 {.
+    importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
+
+proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
+    importc: "SetEndOfFile".}
+
+proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
+                     lpDistanceToMoveHigh: ptr LONG,
+                     dwMoveMethod: DWORD): DWORD {.
+    stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
+
+proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
+    dynlib: "kernel32", importc: "GetFileSize".}
+
+proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
+                      dwFileOffsetHigh, dwFileOffsetLow: DWORD,
+                      dwNumberOfBytesToMap: DWORD,
+                      lpBaseAddress: pointer): pointer{.
+    stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
+
+proc createFileMappingW*(hFile: THandle,
+                       lpFileMappingAttributes: pointer,
+                       flProtect, dwMaximumSizeHigh: DWORD,
+                       dwMaximumSizeLow: DWORD,
+                       lpName: pointer): THandle {.
+  stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
+
+when not useWinUnicode:
+  proc createFileMappingA*(hFile: THANDLE,
+                           lpFileMappingAttributes: pointer,
+                           flProtect, dwMaximumSizeHigh: DWORD,
+                           dwMaximumSizeLow: DWORD, lpName: cstring): THANDLE {.
+      stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".}
+
+proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall,
+    dynlib: "kernel32", importc: "UnmapViewOfFile".}
+
+type
+  TOVERLAPPED* {.pure, inheritable.} = object
+    internal*: PULONG
+    internalHigh*: PULONG
+    offset*: DWORD
+    offsetHigh*: DWORD
+    hEvent*: THandle
+
+  POVERLAPPED* = ptr TOVERLAPPED
+
+  POVERLAPPED_COMPLETION_ROUTINE* = proc (para1: DWORD, para2: DWORD,
+      para3: POVERLAPPED){.stdcall.}
+
+  TGUID* {.final, pure.} = object
+    D1*: int32
+    D2*: int16
+    D3*: int16
+    D4*: array [0..7, int8]
+
+const
+  ERROR_IO_PENDING* = 997 # a.k.a WSA_IO_PENDING
+  FILE_FLAG_OVERLAPPED* = 1073741824
+  WSAECONNABORTED* = 10053
+  WSAECONNRESET* = 10054
+  WSAEDISCON* = 10101
+  WSAENETRESET* = 10052
+  WSAETIMEDOUT* = 10060
+  ERROR_NETNAME_DELETED* = 64
+
+proc createIoCompletionPort*(FileHandle: THandle, ExistingCompletionPort: THandle,
+                             CompletionKey: DWORD,
+                             NumberOfConcurrentThreads: DWORD): THandle{.stdcall,
+    dynlib: "kernel32", importc: "CreateIoCompletionPort".}
+
+proc getQueuedCompletionStatus*(CompletionPort: THandle,
+    lpNumberOfBytesTransferred: PDWORD, lpCompletionKey: PULONG,
+                                lpOverlapped: ptr POVERLAPPED,
+                                dwMilliseconds: DWORD): WINBOOL{.stdcall,
+    dynlib: "kernel32", importc: "GetQueuedCompletionStatus".}
+
+proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED,
+              lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
+    stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
+
+const
+ IOC_OUT* = 0x40000000
+ IOC_IN*  = 0x80000000
+ IOC_WS2* = 0x08000000
+ IOC_INOUT* = IOC_IN or IOC_OUT
+
+template WSAIORW*(x,y): expr = (IOC_INOUT or x or y)
+
+const
+  SIO_GET_EXTENSION_FUNCTION_POINTER* = WSAIORW(IOC_WS2,6).DWORD
+  SO_UPDATE_ACCEPT_CONTEXT* = 0x700B
+
+var
+  WSAID_CONNECTEX*: TGUID = TGUID(D1: 0x25a207b9, D2: 0xddf3'i16, D3: 0x4660, D4: [
+    0x8e'i8, 0xe9'i8, 0x76'i8, 0xe5'i8, 0x8c'i8, 0x74'i8, 0x06'i8, 0x3e'i8])
+  WSAID_ACCEPTEX*: TGUID = TGUID(D1: 0xb5367df1'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
+    0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
+  WSAID_GETACCEPTEXSOCKADDRS*: TGUID = TGUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [
+    0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8])
+
+proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
+  cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD,
+  lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED,
+  lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
+  {.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".}
+
+type
+  TWSABuf* {.importc: "WSABUF", header: "winsock2.h".} = object
+    len*: ULONG
+    buf*: cstring
+
+proc WSARecv*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
+  bytesReceived, flags: PDWORD, lpOverlapped: POVERLAPPED,
+  completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
+  stdcall, importc: "WSARecv", dynlib: "Ws2_32.dll".}
+
+proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
+  bytesSent: PDWORD, flags: DWORD, lpOverlapped: POVERLAPPED,
+  completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
+  stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
+
+proc get_osfhandle*(fd:FileHandle): THandle {.
+  importc: "_get_osfhandle", header:"<io.h>".}
+
+proc getSystemTimes*(lpIdleTime, lpKernelTime,
+                     lpUserTime: var TFILETIME): WINBOOL {.stdcall,
+  dynlib: "kernel32", importc: "GetSystemTimes".}
+
+proc getProcessTimes*(hProcess: THandle; lpCreationTime, lpExitTime,
+  lpKernelTime, lpUserTime: var TFILETIME): WINBOOL {.stdcall,
+  dynlib: "kernel32", importc: "GetProcessTimes".}
diff --git a/lib/wrappers/claro.nim b/lib/wrappers/claro.nim
new file mode 100644
index 000000000..0fb0882bf
--- /dev/null
+++ b/lib/wrappers/claro.nim
@@ -0,0 +1,2734 @@
+# Claro Graphics - an abstraction layer for native UI libraries

+#  

+#  $Id$

+#  

+#  The contents of this file are subject to the Mozilla Public License

+#  Version 1.1 (the "License"); you may not use this file except in

+#  compliance with the License. You may obtain a copy of the License at

+#  http://www.mozilla.org/MPL/

+#  

+#  Software distributed under the License is distributed on an "AS IS"

+#  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the

+#  License for the specific language governing rights and limitations

+#  under the License.

+#  

+#  See the LICENSE file for more details.

+# 

+

+## Wrapper for the Claro GUI library. 

+## This wrapper calls ``claro_base_init`` and ``claro_graphics_init`` 

+## automatically on startup, so you don't have to do it and in fact cannot do

+## it because they are not exported.

+

+{.deadCodeElim: on.}

+

+when defined(windows): 

+  const 

+    clarodll = "claro.dll"

+elif defined(macosx): 

+  const 

+    clarodll = "libclaro.dylib"

+else: 

+  const 

+    clarodll = "libclaro.so"

+

+import cairo

+

+type 

+  TNode* {.pure.} = object 

+    next*: ptr TNode

+    prev*: ptr TNode        # pointer to real structure 

+    data*: pointer

+

+  TList* {.pure.} = object 

+    head*: ptr TNode

+    tail*: ptr TNode        

+    count*: int32

+

+

+proc list_init*(){.cdecl, importc: "list_init", dynlib: clarodll.}

+proc list_create*(list: ptr TList){.cdecl, importc: "list_create", 

+                                      dynlib: clarodll.}

+proc node_create*(): ptr TNode{.cdecl, importc: "node_create", 

+                                  dynlib: clarodll.}

+proc node_free*(n: ptr TNode){.cdecl, importc: "node_free", dynlib: clarodll.}

+proc node_add*(data: pointer, n: ptr TNode, L: ptr TList){.cdecl, 

+    importc: "node_add", dynlib: clarodll.}

+proc node_prepend*(data: pointer, n: ptr TNode, L: ptr TList){.cdecl, 

+    importc: "node_prepend", dynlib: clarodll.}

+proc node_del*(n: ptr TNode, L: ptr TList){.cdecl, importc: "node_del", 

+    dynlib: clarodll.}

+proc node_find*(data: pointer, L: ptr TList): ptr TNode{.cdecl, 

+    importc: "node_find", dynlib: clarodll.}

+proc node_move*(n: ptr TNode, oldlist: ptr TList, newlist: ptr TList){.

+    cdecl, importc: "node_move", dynlib: clarodll.}

+

+type 

+  TClaroObj*{.pure, inheritable.} = object 

+    typ*: array[0..64 - 1, char]

+    destroy_pending*: cint

+    event_handlers*: TList

+    children*: TList

+    parent*: ptr TClaroObj

+    appdata*: pointer         # !! this is for APPLICATION USE ONLY !! 

+  

+  TEvent*{.pure.} = object 

+    obj*: ptr TClaroObj    # the object which this event was sent to 

+    name*: array[0..64 - 1, char]

+    handled*: cint

+    arg_num*: cint            # number of arguments 

+    format*: array[0..16 - 1, char] # format of the arguments sent 

+    arglist*: ptr pointer     # list of args, as per format. 

+  

+  TEventFunc* = proc (obj: ptr TClaroObj, event: ptr TEvent){.cdecl.}

+  TEventIfaceFunc* = proc (obj: ptr TClaroObj, event: ptr TEvent, 

+                           data: pointer){.cdecl.}

+  TEventHandler*{.pure.} = object 

+    typ*: array[0..32 - 1, char]

+    data*: pointer

+    fun*: TEventFunc   # the function that handles this event 

+  

+

+# #define event_handler(n) void n ( TClaroObj *object, event_t *event )

+#CLVEXP list_t object_list;

+

+proc object_init*(){.cdecl, importc: "object_init", dynlib: clarodll.}

+

+proc object_override_next_size*(size: cint){.cdecl, 

+    importc: "object_override_next_size", dynlib: clarodll.}

+  ## Overrides the size of next object to be created, providing the 

+  ## size is more than is requested by default.

+  ## 

+  ## `size` specifies the full size, which is greater than both TClaroObj

+  ## and the size that will be requested automatically.

+    

+proc event_get_arg_ptr*(e: ptr TEvent, arg: cint): pointer{.cdecl, 

+    importc: "event_get_arg_ptr", dynlib: clarodll.}

+proc event_get_arg_double*(e: ptr TEvent, arg: cint): cdouble{.cdecl, 

+    importc: "event_get_arg_double", dynlib: clarodll.}

+proc event_get_arg_int*(e: ptr TEvent, arg: cint): cint{.cdecl, 

+    importc: "event_get_arg_int", dynlib: clarodll.}

+proc object_create*(parent: ptr TClaroObj, size: int32, 

+                    typ: cstring): ptr TClaroObj{.

+    cdecl, importc: "object_create", dynlib: clarodll.}

+proc object_destroy*(obj: ptr TClaroObj){.cdecl, importc: "object_destroy", 

+    dynlib: clarodll.}

+proc object_set_parent*(obj: ptr TClaroObj, parent: ptr TClaroObj){.cdecl, 

+    importc: "object_set_parent", dynlib: clarodll.}

+

+##define object_cmptype(o,t) (!strcmp(((TClaroObj *)o)->type,t))

+

+# event functions 

+

+proc object_addhandler*(obj: ptr TClaroObj, event: cstring, 

+                        fun: TEventFunc){.cdecl, 

+    importc: "object_addhandler", dynlib: clarodll.}

+proc object_addhandler_interface*(obj: ptr TClaroObj, event: cstring, 

+                                  fun: TEventFunc, data: pointer){.cdecl, 

+    importc: "object_addhandler_interface", dynlib: clarodll.}

+proc event_send*(obj: ptr TClaroObj, event: cstring, fmt: cstring): cint{.

+    varargs, cdecl, importc: "event_send", dynlib: clarodll.}

+proc event_get_name*(event: ptr TEvent): cstring{.cdecl, 

+    importc: "event_get_name", dynlib: clarodll.}

+proc claro_base_init(){.cdecl, importc: "claro_base_init", dynlib: clarodll.}

+proc claro_loop*(){.cdecl, importc: "claro_loop", dynlib: clarodll.}

+proc claro_run*(){.cdecl, importc: "claro_run", dynlib: clarodll.}

+proc claro_shutdown*(){.cdecl, importc: "claro_shutdown", dynlib: clarodll.}

+proc mssleep*(ms: cint){.cdecl, importc: "mssleep", dynlib: clarodll.}

+proc claro_graphics_init(){.cdecl, importc: "claro_graphics_init", 

+                            dynlib: clarodll.}

+

+const 

+  cWidgetNoBorder* = (1 shl 24)

+  cWidgetCustomDraw* = (1 shl 25)

+

+type 

+  TBounds*{.pure.} = object 

+    x*: cint

+    y*: cint

+    w*: cint

+    h*: cint

+    owner*: ptr TClaroObj

+

+

+const 

+  cSizeRequestChanged* = 1

+

+type 

+  TFont*{.pure.} = object 

+    used*: cint

+    face*: cstring

+    size*: cint

+    weight*: cint

+    slant*: cint

+    decoration*: cint

+    native*: pointer

+

+  TColor*{.pure.} = object 

+    used*: cint

+    r*: cfloat

+    g*: cfloat

+    b*: cfloat

+    a*: cfloat

+

+  TWidget* {.pure.} = object of TClaroObj

+    size_req*: ptr TBounds

+    size*: TBounds

+    size_ct*: TBounds

+    supports_alpha*: cint

+    size_flags*: cint

+    flags*: cint

+    visible*: cint

+    notify_flags*: cint

+    font*: TFont

+    native*: pointer          # native widget 

+    ndata*: pointer           # additional native data 

+    container*: pointer       # native widget container (if not ->native) 

+    naddress*: array[0..3, pointer] # addressed for something 

+                                    # we override or need to remember 

+  

+proc clipboard_set_text*(w: ptr TWidget, text: cstring): cint{.cdecl, 

+    importc: "clipboard_set_text", dynlib: clarodll.}

+  ## Sets the (text) clipboard to the specified text value.

+  ##

+  ## `w` The widget requesting the action, some platforms may use this value.

+  ## `text` The text to place in the clipboard.

+  ## returns 1 on success, 0 on failure.

+

+const 

+  cNotifyMouse* = 1'i32

+  cNotifyKey* = 2'i32

+

+  cFontSlantNormal* = 0

+  cFontSlantItalic* = 1

+  cFontWeightNormal* = 0

+  cFontWeightBold* = 1

+  cFontDecorationNormal* = 0

+  cFontDecorationUnderline* = 1

+

+

+proc widget_set_font*(widget: ptr TClaroObj, face: cstring, size: cint, 

+                      weight: cint, slant: cint, decoration: cint){.cdecl, 

+    importc: "widget_set_font", dynlib: clarodll.}

+  ## Sets the font details of the specified widget.

+  ## 

+  ##  `widget` A widget

+  ##  `face` Font face string

+  ##  `size` Size of the font in pixels

+  ##  `weight` The weight of the font

+  ##  `slant` The sland of the font

+  ##  `decoration` The decoration of the font

+    

+proc widget_font_string_width*(widget: ptr TClaroObj, text: cstring, 

+                               chars: cint): cint {.

+    cdecl, importc: "widget_font_string_width", dynlib: clarodll.}

+  ## Calculates the pixel width of the text in the widget's font.

+  ## `chars` is the number of characters of text to calculate. Return value

+  ## is the width of the specified text in pixels.

+

+const 

+  CLARO_APPLICATION* = "claro.graphics"

+

+type 

+  TImage* {.pure.} = object of TClaroObj

+    width*: cint

+    height*: cint

+    native*: pointer

+    native2*: pointer

+    native3*: pointer

+    icon*: pointer

+

+

+proc image_load*(parent: ptr TClaroObj, file: cstring): ptr TImage{.cdecl, 

+    importc: "image_load", dynlib: clarodll.}

+  ## Loads an image from a file and returns a new image object.

+  ## 

+  ## The supported formats depend on the platform.

+  ## The main effort is to ensure that PNG images will always work.

+  ## Generally, JPEGs and possibly GIFs will also work.

+  ##

+  ## `Parent` object (usually the application's main window), can be nil.

+    

+proc image_load_inline_png*(parent: ptr TClaroObj, data: cstring, 

+                            len: cint): ptr TImage{.cdecl, 

+    importc: "image_load_inline_png", dynlib: clarodll.}

+  ## Loads an image from inline data and returns a new image object.

+  ## `Parent` object (usually the application's main window), can be nil.

+  ##  data raw PNG image

+  ##  len size of data

+

+when true:

+  discard

+else:

+  # status icons are not supported on all platforms yet:

+  type 

+    TStatusIcon* {.pure.} = object of TClaroObj

+      icon*: ptr TImage

+      native*: pointer

+      native2*: pointer

+

+  #*

+  #  \brief Creates a status icon

+  # 

+  #  \param parent Parent object (usually the application's main window),

+  #                can be NULL.

+  #  \param image The image object for the icon NOT NULL

+  #  \param flags Flags

+  #  \return New status_icon_t object

+  # 

+

+  proc status_icon_create*(parent: ptr TClaroObj, icon: ptr TImage, 

+                           flags: cint): ptr TStatusIcon {.

+      cdecl, importc: "status_icon_create", dynlib: clarodll.}

+

+  #*

+  #  \brief sets the status icon's image 

+  # 

+  #  \param status Status Icon

+  #  \param image The image object for the icon

+  # 

+

+  proc status_icon_set_icon*(status: ptr TStatusIcon, icon: ptr TImage){.cdecl, 

+      importc: "status_icon_set_icon", dynlib: clarodll.}

+

+  #*

+  #  \brief sets the status icons's menu

+  # 

+  #  \param status Status Icon

+  #  \param menu The menu object for the popup menu

+  # 

+

+  proc status_icon_set_menu*(status: ptr TStatusIcon, menu: ptr TClaroObj){.cdecl, 

+      importc: "status_icon_set_menu", dynlib: clarodll.}

+  #*

+  #  \brief sets the status icon's visibility

+  # 

+  #  \param status Status Icon

+  #  \param visible whether the status icon is visible or not

+  # 

+

+  proc status_icon_set_visible*(status: ptr TStatusIcon, visible: cint){.cdecl, 

+      importc: "status_icon_set_visible", dynlib: clarodll.}

+  #*

+  #  \brief sets the status icon's tooltip

+  # 

+  #  \param status Status Icon

+  #  \param tooltip Tooltip string

+  # 

+

+  proc status_icon_set_tooltip*(status: ptr TStatusIcon, tooltip: cstring){.cdecl, 

+      importc: "status_icon_set_tooltip", dynlib: clarodll.}

+    

+#*

+#  \brief Makes the specified widget visible.

+# 

+#  \param widget A widget

+# 

+

+proc widget_show*(widget: ptr TWidget){.cdecl, importc: "widget_show", 

+    dynlib: clarodll.}

+#*

+#  \brief Makes the specified widget invisible.

+# 

+#  \param widget A widget

+# 

+

+proc widget_hide*(widget: ptr TWidget){.cdecl, importc: "widget_hide", 

+    dynlib: clarodll.}

+#*

+#  \brief Enables the widget, allowing focus

+# 

+#  \param widget A widget

+# 

+

+proc widget_enable*(widget: ptr TWidget){.cdecl, importc: "widget_enable", 

+    dynlib: clarodll.}

+#*

+#  \brief Disables the widget

+#  When disabled, a widget appears greyed and cannot

+#  receive focus.

+# 

+#  \param widget A widget

+# 

+

+proc widget_disable*(widget: ptr TWidget){.cdecl, importc: "widget_disable", 

+    dynlib: clarodll.}

+#*

+#  \brief Give focus to the specified widget

+# 

+#  \param widget A widget

+# 

+

+proc widget_focus*(widget: ptr TWidget){.cdecl, importc: "widget_focus", 

+    dynlib: clarodll.}

+#*

+#  \brief Closes a widget

+# 

+#  Requests that a widget be closed by the platform code. 

+#  This may or may not result in immediate destruction of the widget,

+#  however the actual Claro widget object will remain valid until at

+#  least the next loop iteration.

+# 

+#  \param widget A widget

+# 

+

+proc widget_close*(widget: ptr TWidget){.cdecl, importc: "widget_close", 

+    dynlib: clarodll.}

+#*

+#  \brief Retrieve the screen offset of the specified widget.

+# 

+#  Retrieves the X and Y screen positions of the widget.

+# 

+#  \param widget A widget

+#  \param dx Pointer to the location to place the X position.

+#  \param dy Pointer to the location to place the Y position.

+# 

+

+proc widget_screen_offset*(widget: ptr TWidget, dx: ptr cint, dy: ptr cint){.

+    cdecl, importc: "widget_screen_offset", dynlib: clarodll.}

+#*

+#  \brief Sets the additional notify events that should be sent.

+# 

+#  For performance reasons, some events, like mouse and key events,

+#  are not sent by default. By specifying such events here, you can

+#  elect to receive these events.

+# 

+#  \param widget A widget

+#  \param flags Any number of cWidgetNotify flags ORed together.

+# 

+

+proc widget_set_notify*(widget: ptr TWidget, flags: cint){.cdecl, 

+    importc: "widget_set_notify", dynlib: clarodll.}

+

+

+type

+  TCursorType* {.size: sizeof(cint).} = enum

+    cCursorNormal = 0,

+    cCursorTextEdit = 1,

+    cCursorWait = 2,

+    cCursorPoint = 3

+

+#*

+#  \brief Sets the mouse cursor for the widget

+# 

+#  \param widget A widget

+#  \param cursor A valid cCursor* value

+# 

+

+proc widget_set_cursor*(widget: ptr TWidget, cursor: TCursorType){.cdecl, 

+    importc: "widget_set_cursor", dynlib: clarodll.}

+

+#*

+#  \brief Retrieves the key pressed in a key notify event.

+# 

+#  \param widget A widget

+#  \param event An event resource

+#  \return The keycode of the key pressed.

+# 

+

+proc widget_get_notify_key*(widget: ptr TWidget, event: ptr TEvent): cint{.

+    cdecl, importc: "widget_get_notify_key", dynlib: clarodll.}

+

+#*

+#  \brief Updates the bounds structure with new values

+# 

+#  This function should \b always be used instead of setting the

+#  members manually. In the future, there may be a \b real reason

+#  for this.

+# 

+#  \param bounds A bounds structure

+#  \param x The new X position

+#  \param y The new Y position

+#  \param w The new width

+#  \param h The new height

+# 

+

+proc bounds_set*(bounds: ptr TBounds, x: cint, y: cint, w: cint, h: cint){.

+    cdecl, importc: "bounds_set", dynlib: clarodll.}

+#*

+#  \brief Create a new bounds object

+# 

+#  Creates a new bounds_t for the specified bounds.

+# 

+#  \param x X position

+#  \param y Y position

+#  \param w Width

+#  \param h Height

+#  \return A new bounds_t structure

+# 

+

+proc new_bounds*(x: cint, y: cint, w: cint, h: cint): ptr TBounds{.cdecl, 

+    importc: "new_bounds", dynlib: clarodll.}

+proc get_req_bounds*(widget: ptr TWidget): ptr TBounds{.cdecl, 

+    importc: "get_req_bounds", dynlib: clarodll.}

+    

+var

+  noBoundsVar: TBounds # set to all zero which is correct

+    

+template noBounds*: expr = (addr(bind noBoundsVar))

+

+#* \internal

+#  \brief Internal pre-inititalisation hook

+# 

+#  \param widget A widget

+# 

+

+proc widget_pre_init*(widget: ptr TWidget){.cdecl, importc: "widget_pre_init", 

+    dynlib: clarodll.}

+#* \internal

+#  \brief Internal post-inititalisation hook

+# 

+#  \param widget A widget

+# 

+

+proc widget_post_init*(widget: ptr TWidget){.cdecl, 

+    importc: "widget_post_init", dynlib: clarodll.}

+#* \internal

+#  \brief Internal resize event handler

+# 

+#  \param obj An object

+#  \param event An event resource

+# 

+

+proc widget_resized_handle*(obj: ptr TWidget, event: ptr TEvent){.cdecl, 

+    importc: "widget_resized_handle", dynlib: clarodll.}

+# CLVEXP bounds_t no_bounds;

+#* \internal

+#  \brief Internal default widget creation function

+# 

+#  \param parent The parent of the widget

+#  \param widget_size The size in bytes of the widget's structure

+#  \param widget_name The object type of the widget (claro.graphics.widgets.*)

+#  \param size_req The initial bounds of the widget

+#  \param flags Widget flags

+#  \param creator The platform function that will be called to actually create

+#                 the widget natively.

+#  \return A new widget object

+# 

+

+type

+  TcgraphicsCreateFunction* = proc (widget: ptr TWidget) {.cdecl.}

+

+proc newdefault*(parent: ptr TWidget, widget_size: int, 

+                 widget_name: cstring, size_req: ptr TBounds, flags: cint, 

+                 creator: TcgraphicsCreateFunction): ptr TWidget{.cdecl, 

+    importc: "default_widget_create", dynlib: clarodll.}

+#* \internal

+#  \brief Retrieves the native container of the widget's children

+# 

+#  \param widget A widget

+#  \return A pointer to the native widget that will hold w's children

+# 

+

+proc widget_get_container*(widget: ptr TWidget): pointer{.cdecl, 

+    importc: "widget_get_container", dynlib: clarodll.}

+#* \internal

+#  \brief Sets the content size of the widget.

+# 

+#  \param widget A widget

+#  \param w New width of the content area of the widget

+#  \param h New height of the content area of the widget

+#  \param event Whether to send a content_size event

+# 

+

+proc widget_set_content_size*(widget: ptr TWidget, w: cint, h: cint, 

+                              event: cint){.cdecl, 

+    importc: "widget_set_content_size", dynlib: clarodll.}

+#* \internal

+#  \brief Sets the size of the widget.

+# 

+#  \param widget A widget

+#  \param w New width of the widget

+#  \param h New height of the widget

+#  \param event Whether to send a resize event

+# 

+

+proc widget_set_size*(widget: ptr TWidget, w: cint, h: cint, event: cint){.

+    cdecl, importc: "widget_set_size", dynlib: clarodll.}

+#* \internal

+#  \brief Sets the position of the widget's content area.

+# 

+#  \param widget A widget

+#  \param x New X position of the widget's content area

+#  \param y New Y position of the widget's content area

+#  \param event Whether to send a content_move event

+# 

+

+proc widget_set_content_position*(widget: ptr TWidget, x: cint, y: cint, 

+                                  event: cint){.cdecl, 

+    importc: "widget_set_content_position", dynlib: clarodll.}

+#* \internal

+#  \brief Sets the position of the widget.

+# 

+#  \param widget A widget

+#  \param x New X position of the widget's content area

+#  \param y New Y position of the widget's content area

+#  \param event Whether to send a moved event

+# 

+

+proc widget_set_position*(widget: ptr TWidget, x: cint, y: cint, event: cint){.

+    cdecl, importc: "widget_set_position", dynlib: clarodll.}

+#* \internal

+#  \brief Sends a destroy event to the specified widget.

+# 

+#  You should use widget_close() in application code instead.

+# 

+#  \param widget A widget

+# 

+

+proc widget_destroy*(widget: ptr TWidget){.cdecl, importc: "widget_destroy", 

+    dynlib: clarodll.}

+

+type 

+  TOpenglWidget* {.pure.} = object of TWidget

+    gldata*: pointer

+

+

+# functions 

+#*

+#  \brief Creates a OpenGL widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new OpenGL widget object.

+# 

+

+proc newopengl*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                flags: cint): ptr TOpenglWidget {.

+    cdecl, importc: "opengl_widget_create", dynlib: clarodll.}

+#*

+#  \brief Flips the front and back buffers

+#  

+#  \param widget A valid OpenGL widget object

+# 

+

+proc opengl_flip*(widget: ptr TOpenglWidget) {.cdecl, importc: "opengl_flip", 

+    dynlib: clarodll.}

+#*

+#  \brief Activates this OpenGL widget's context

+#  

+#  \param widget A valid OpenGL widget object

+# 

+

+proc opengl_activate*(widget: ptr TOpenglWidget) {.

+    cdecl, importc: "opengl_activate", dynlib: clarodll.}

+

+type 

+  TButton* {.pure.} = object of TWidget

+    text*: array[0..256-1, char]

+

+

+# functions 

+#*

+#  \brief Creates a Button widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Button widget object.

+# 

+

+proc newbutton*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                flags: cint): ptr TButton {.

+    cdecl, importc: "button_widget_create", dynlib: clarodll.}

+#*

+#  \brief Creates a Button widget with a label

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \param label The label for the button

+#  \return A new Button widget object.

+# 

+

+proc newbutton*(parent: ptr TClaroObj, 

+                bounds: ptr TBounds, flags: cint, 

+                label: cstring): ptr TButton{.cdecl, 

+    importc: "button_widget_create_with_label", dynlib: clarodll.}

+#*

+#  \brief Changes the label of the button

+#  

+#  \param obj A valid Button widget object

+#  \param label The new label for the button

+# 

+

+proc button_set_text*(obj: ptr TButton, label: cstring){.cdecl, 

+    importc: "button_set_label", dynlib: clarodll.}

+

+#*

+#  \brief Changes the image of the button

+# 

+#  \warning This function is not implemented yet and is not portable.

+#           Do not use it.

+#  

+#  \param obj A valid Button widget object

+#  \param image The new image for the button

+# 

+

+proc button_set_image*(obj: ptr TButton, image: ptr TImage){.cdecl, 

+    importc: "button_set_image", dynlib: clarodll.}

+

+const 

+  CTEXT_SLANT_NORMAL* = cFontSlantNormal

+  CTEXT_SLANT_ITALIC* = cFontSlantItalic

+  CTEXT_WEIGHT_NORMAL* = cFontWeightNormal

+  CTEXT_WEIGHT_BOLD* = cFontWeightBold

+  CTEXT_EXTRA_NONE* = cFontDecorationNormal

+  CTEXT_EXTRA_UNDERLINE* = cFontDecorationUnderline

+

+# END OLD 

+

+type 

+  TCanvas*{.pure.} = object of TWidget

+    surface*: cairo.PSurface

+    cr*: cairo.PContext

+    surfdata*: pointer

+    fontdata*: pointer

+    font_height*: cint

+    fr*: cfloat

+    fg*: cfloat

+    fb*: cfloat

+    fa*: cfloat

+    br*: cfloat

+    bg*: cfloat

+    bb*: cfloat

+    ba*: cfloat

+    charsize*: array[0..256 - 1, cairo.TTextExtents]

+    csz_loaded*: cint

+    fontsize*: cint

+

+# functions 

+#*

+#  \brief Creates a Canvas widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Canvas widget object.

+# 

+

+proc newcanvas*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                flags: cint): ptr TCanvas{.

+    cdecl, importc: "canvas_widget_create", dynlib: clarodll.}

+#*

+#  \brief Invalidates and redraws a canvas widget

+#  

+#  \param widget A valid Canvas widget object.

+# 

+

+proc canvas_redraw*(widget: ptr TCanvas){.cdecl, importc: "canvas_redraw", 

+    dynlib: clarodll.}

+# claro text functions 

+#*

+#  \brief Set the current text color

+#  

+#  \param widget A valid Canvas widget object.

+#  \param r Red component (0.0 - 1.0)

+#  \param g Green component (0.0 - 1.0)

+#  \param b Blue component (0.0 - 1.0)

+#  \param a Alpha component (0.0 - 1.0)

+# 

+

+proc canvas_set_text_color*(widget: ptr TCanvas, r: cdouble, g: cdouble, 

+                            b: cdouble, a: cdouble){.cdecl, 

+    importc: "canvas_set_text_color", dynlib: clarodll.}

+#*

+#  \brief Set the current text background color

+#  

+#  \param widget A valid Canvas widget object.

+#  \param r Red component (0.0 - 1.0)

+#  \param g Green component (0.0 - 1.0)

+#  \param b Blue component (0.0 - 1.0)

+#  \param a Alpha component (0.0 - 1.0)

+# 

+

+proc canvas_set_text_bgcolor*(widget: ptr TCanvas, r: cdouble, g: cdouble, 

+                              b: cdouble, a: cdouble){.cdecl, 

+    importc: "canvas_set_text_bgcolor", dynlib: clarodll.}

+#*

+#  \brief Set the current canvas font

+#  

+#  \param widget A valid Canvas widget object.

+#  \param face The font face

+#  \param size The font height in pixels

+#  \param weight The weight of the font

+#  \param slant The slant of the font

+#  \param decoration Font decorations

+# 

+

+proc canvas_set_text_font*(widget: ptr TCanvas, face: cstring, size: cint, 

+                           weight: cint, slant: cint, decoration: cint){.cdecl, 

+    importc: "canvas_set_text_font", dynlib: clarodll.}

+#*

+#  \brief Calculates the width of the specified text

+#  

+#  \param widget A valid Canvas widget object.

+#  \param text The text to calulate the length of

+#  \param len The number of characters of text to calulcate

+#  \return Width of the text in pixels

+# 

+

+proc canvas_text_width*(widget: ptr TCanvas, text: cstring, len: cint): cint{.

+    cdecl, importc: "canvas_text_width", dynlib: clarodll.}

+#*

+#  \brief Calculates the width of the specified text's bounding box

+#  

+#  \param widget A valid Canvas widget object.

+#  \param text The text to calulate the length of

+#  \param len The number of characters of text to calulcate

+#  \return Width of the text's bounding box in pixels

+# 

+

+proc canvas_text_box_width*(widget: ptr TCanvas, text: cstring, 

+                            len: cint): cint{.

+    cdecl, importc: "canvas_text_box_width", dynlib: clarodll.}

+#*

+#  \brief Calculates the number of characters of text that can be displayed

+#         before width pixels.

+#  

+#  \param widget A valid Canvas widget object.

+#  \param text The text to calulate the length of

+#  \param width The width to fit the text in

+#  \return The number of characters of text that will fit in width pixels.

+# 

+

+proc canvas_text_display_count*(widget: ptr TCanvas, text: cstring, 

+                                width: cint): cint{.cdecl, 

+    importc: "canvas_text_display_count", dynlib: clarodll.}

+#*

+#  \brief Displays the specified text on the canvas

+#  

+#  \param widget A valid Canvas widget object.

+#  \param x The X position at which the text will be drawn

+#  \param y The Y position at which the text will be drawn

+#  \param text The text to calulate the length of

+#  \param len The number of characters of text to calulcate

+# 

+

+proc canvas_show_text*(widget: ptr TCanvas, x: cint, y: cint, text: cstring, 

+                       len: cint){.cdecl, importc: "canvas_show_text", 

+                                   dynlib: clarodll.}

+#*

+#  \brief Draws a filled rectangle

+#  

+#  \param widget A valid Canvas widget object.

+#  \param x The X position at which the rectangle will start

+#  \param y The Y position at which the rectangle will start

+#  \param w The width of the rectangle

+#  \param h The height of the rectangle

+#  \param r Red component (0.0 - 1.0)

+#  \param g Green component (0.0 - 1.0)

+#  \param b Blue component (0.0 - 1.0)

+#  \param a Alpha component (0.0 - 1.0)

+# 

+

+proc canvas_fill_rect*(widget: ptr TCanvas, x: cint, y: cint, w: cint, 

+                       h: cint, r, g, b, a: cdouble){.

+    cdecl, importc: "canvas_fill_rect", dynlib: clarodll.}

+#*

+#  \brief Draws the specified image on the canvas

+#  

+#  \param widget A valid Canvas widget object.

+#  \param image The image to draw

+#  \param x The X position at which the image will be drawn

+#  \param y The Y position at which the image will be drawn

+# 

+

+proc canvas_draw_image*(widget: ptr TCanvas, image: ptr TImage, x: cint, 

+                        y: cint){.cdecl, importc: "canvas_draw_image", 

+                                  dynlib: clarodll.}

+# claro "extensions" of cairo 

+#* \internal

+#  \brief Internal claro extension of cairo text functions

+# 

+

+proc canvas_cairo_buffered_text_width*(widget: ptr TCanvas, 

+                                       text: cstring, len: cint): cint{.cdecl, 

+    importc: "canvas_cairo_buffered_text_width", dynlib: clarodll.}

+#* \internal

+#  \brief Internal claro extension of cairo text functions

+# 

+

+proc canvas_cairo_buffered_text_display_count*(widget: ptr TCanvas, 

+    text: cstring, width: cint): cint{.cdecl, 

+    importc: "canvas_cairo_buffered_text_display_count", 

+    dynlib: clarodll.}

+proc canvas_get_cairo_context*(widget: ptr TCanvas): cairo.PContext {.cdecl, 

+    importc: "canvas_get_cairo_context", dynlib: clarodll.}

+

+type 

+  TCheckBox*{.pure.} = object of TWidget

+    text*: array[0..256-1, char]

+    checked*: cint

+

+#*

+#  \brief Creates a Checkbox widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Checkbox widget object.

+# 

+

+proc newcheckbox*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                  flags: cint): ptr TCheckBox{.

+    cdecl, importc: "checkbox_widget_create", dynlib: clarodll.}

+#*

+#  \brief Creates a Checkbox widget with a label

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \param label The label for the checkbox

+#  \return A new Checkbox widget object.

+# 

+

+proc newcheckbox*(parent: ptr TClaroObj, 

+                  bounds: ptr TBounds, flags: cint, 

+                  label: cstring): ptr TCheckBox {.cdecl, 

+    importc: "checkbox_widget_create_with_label", dynlib: clarodll.}

+#*

+#  \brief Sets a new label for the Checkbox widget

+#  

+#  \param obj A valid Checkbox widget object.

+#  \param label The new label for the checkbox

+# 

+

+proc checkbox_set_text*(obj: ptr TCheckBox, label: cstring){.cdecl, 

+    importc: "checkbox_set_label", dynlib: clarodll.}

+#*

+#  \brief Retrieves the checkbox's check state

+#  

+#  \param obj A valid Checkbox widget object.

+#  \return 1 if the checkbox is checked, otherwise 0

+# 

+

+proc checkbox_checked*(obj: ptr TCheckBox): cint{.cdecl, 

+    importc: "checkbox_get_checked", dynlib: clarodll.}

+#*

+#  \brief Sets the checkbox's checked state

+#  

+#  \param obj A valid Checkbox widget object.

+#  \param checked 1 if the checkbox should become checked, otherwise 0

+# 

+

+proc checkbox_set_checked*(obj: ptr TCheckBox, checked: cint){.cdecl, 

+    importc: "checkbox_set_checked", dynlib: clarodll.}

+

+

+#*

+#  List items define items in a list_widget

+# 

+

+type 

+  TListItem*{.pure.} = object of TClaroObj

+    row*: cint

+    native*: pointer

+    nativeid*: int

+    menu*: ptr TClaroObj

+    enabled*: cint

+    data*: ptr pointer

+    ListItemChildren*: TList

+    ListItemParent*: ptr TList

+    parent_item*: ptr TListItem # drawing related info, not always required

+    text_color*: TColor

+    sel_text_color*: TColor

+    back_color*: TColor

+    sel_back_color*: TColor

+    font*: TFont

+

+  TListWidget* {.pure.} = object of TWidget ## List widget, base for 

+                                            ## widgets containing items

+    columns*: cint

+    coltypes*: ptr cint

+    items*: TList

+

+  TCombo*{.pure.} = object of TListWidget

+    selected*: ptr TListItem

+

+

+# functions 

+#*

+#  \brief Creates a Combo widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Combo widget object.

+# 

+

+proc newcombo*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+               flags: cint): ptr TCombo{.

+    cdecl, importc: "combo_widget_create", dynlib: clarodll.}

+#*

+#  \brief Append a row to a Combo widget

+#  

+#  \param combo A valid Combo widget object.

+#  \param text The text for the item.

+#  \return A new list item.

+# 

+

+proc combo_append_row*(combo: ptr TCombo, text: cstring): ptr TListItem {.

+    cdecl, importc: "combo_append_row", dynlib: clarodll.}

+#*

+#  \brief Insert a row at the specified position into a Combo widget

+#  

+#  \param combo A valid Combo widget object.

+#  \param pos The index at which this item will be placed.

+#  \param text The text for the item.

+#  \return A new list item.

+# 

+

+proc combo_insert_row*(combo: ptr TCombo, pos: cint, 

+                       text: cstring): ptr TListItem {.

+    cdecl, importc: "combo_insert_row", dynlib: clarodll.}

+#*

+#  \brief Move a row in a Combo widget

+#  

+#  \param combo A valid Combo widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc combo_move_row*(combo: ptr TCombo, item: ptr TListItem, row: cint){.

+    cdecl, importc: "combo_move_row", dynlib: clarodll.}

+#*

+#  \brief Remove a row from a Combo widget

+#  

+#  \param combo A valid Combo widget object.

+#  \param item A valid list item

+# 

+

+proc combo_remove_row*(combo: ptr TCombo, item: ptr TListItem){.cdecl, 

+    importc: "combo_remove_row", dynlib: clarodll.}

+#*

+#  \brief Returns the currently selected Combo item

+#  

+#  \param obj A valid Combo widget object.

+#  \return The currently selected Combo item, or NULL if no item is selected.

+# 

+

+proc combo_get_selected*(obj: ptr TCombo): ptr TListItem{.cdecl, 

+    importc: "combo_get_selected", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a Combo widget

+#  

+#  \param obj A valid Combo widget object.

+#  \return Number of rows

+# 

+

+proc combo_get_rows*(obj: ptr TCombo): cint{.cdecl, 

+    importc: "combo_get_rows", dynlib: clarodll.}

+#*

+#  \brief Selects a row in a Combo widget

+#  

+#  \param obj A valid Combo widget object.

+#  \param item A valid list item

+# 

+

+proc combo_select_item*(obj: ptr TCombo, item: ptr TListItem){.cdecl, 

+    importc: "combo_select_item", dynlib: clarodll.}

+#*

+#  \brief Removes all entries from a Combo widget

+#  

+#  \param obj A valid Combo widget object.

+# 

+

+proc combo_clear*(obj: ptr TCombo){.cdecl, importc: "combo_clear", 

+                                    dynlib: clarodll.}

+

+type 

+  TContainerWidget* {.pure.} = object of TWidget

+

+

+# functions 

+#*

+#  \brief Creates a Container widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Container widget object.

+# 

+

+proc newcontainer*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                   flags: cint): ptr TContainerWidget{.

+    cdecl, importc: "container_widget_create", dynlib: clarodll.}

+

+proc newdialog*(parent: ptr TClaroObj, bounds: ptr TBounds, format: cstring, 

+                flags: cint): ptr TClaroObj{.cdecl, 

+    importc: "dialog_widget_create", dynlib: clarodll.}

+proc dialog_set_text*(obj: ptr TClaroObj, text: cstring){.cdecl, 

+    importc: "dialog_set_text", dynlib: clarodll.}

+proc dialog_set_default_icon*(typ: cstring, file: cstring){.cdecl, 

+    importc: "dialog_set_default_icon", dynlib: clarodll.}

+proc dialog_get_default_icon*(dialog_type: cint): cstring{.cdecl, 

+    importc: "dialog_get_default_icon", dynlib: clarodll.}

+proc dialog_warning*(format: cstring, text: cstring): cint{.cdecl, 

+    importc: "dialog_warning", dynlib: clarodll.}

+proc dialog_info*(format: cstring, text: cstring): cint{.cdecl, 

+    importc: "dialog_info", dynlib: clarodll.}

+proc dialog_error*(format: cstring, text: cstring): cint{.cdecl, 

+    importc: "dialog_error", dynlib: clarodll.}

+proc dialog_other*(format: cstring, text: cstring, default_icon: cstring): cint{.

+    cdecl, importc: "dialog_other", dynlib: clarodll.}

+

+type 

+  TFontDialog* {.pure.} = object of TWidget

+    selected*: TFont

+

+# functions 

+#*

+#  \brief Creates a Font Selection widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param flags Widget flags.

+#  \return A new Font Selection widget object.

+# 

+

+proc newFontDialog*(parent: ptr TClaroObj, flags: cint): ptr TFontDialog {.

+    cdecl, importc: "font_dialog_widget_create", dynlib: clarodll.}

+#*

+#  \brief Changes the selected font

+#  

+#  \param obj A valid Font Selection widget object

+#  \param font The name of the font

+# 

+

+proc font_dialog_set_font*(obj: ptr TFontDialog, face: cstring, size: cint, 

+                           weight: cint, slant: cint, decoration: cint){.cdecl, 

+    importc: "font_dialog_set_font", dynlib: clarodll.}

+#*

+#  \brief Returns a structure representing the currently selected font

+#  

+#  \param obj A valid Font Selection widget object

+#  \return A font_t structure containing information about the selected font.

+# 

+

+proc font_dialog_get_font*(obj: ptr TFontDialog): ptr TFont{.cdecl, 

+    importc: "font_dialog_get_font", dynlib: clarodll.}

+

+type 

+  TFrame* {.pure.} = object of TWidget

+    text*: array[0..256-1, char]

+

+

+#*

+#  \brief Creates a Frame widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Frame widget object.

+# 

+

+proc newframe*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+               flags: cint): ptr TFrame{.

+    cdecl, importc: "frame_widget_create", dynlib: clarodll.}

+#*

+#  \brief Creates a Frame widget with a label

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \param label The initial label for the frame

+#  \return A new Frame widget object.

+# 

+

+proc newframe*(parent: ptr TClaroObj, bounds: ptr TBounds, flags: cint, 

+                                     label: cstring): ptr TFrame {.cdecl, 

+    importc: "frame_widget_create_with_label", dynlib: clarodll.}

+#*

+#  \brief Creates a Container widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Container widget object.

+# 

+

+proc frame_set_text*(frame: ptr TFrame, label: cstring){.cdecl, 

+    importc: "frame_set_label", dynlib: clarodll.}

+

+type 

+  TImageWidget* {.pure.} = object of TWidget

+    src*: ptr TImage

+

+

+#*

+#  \brief Creates an Image widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Image widget object.

+# 

+

+proc newimageWidget*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                     flags: cint): ptr TImageWidget{.

+    cdecl, importc: "image_widget_create", dynlib: clarodll.}

+#*

+#  \brief Creates an Image widget with an image

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \param image A valid Image object.

+#  \return A new Image widget object.

+# 

+

+proc newimageWidget*(parent: ptr TClaroObj, 

+                     bounds: ptr TBounds, flags: cint, 

+                     image: ptr TImage): ptr TImageWidget{.cdecl, 

+    importc: "image_widget_create_with_image", dynlib: clarodll.}

+#*

+#  \brief Sets the image object of the image widget

+#  

+#  \param image A valid image widget

+#  \param src The source image object

+# 

+

+proc image_set_image*(image: ptr TImageWidget, src: ptr TImage){.cdecl, 

+    importc: "image_set_image", dynlib: clarodll.}

+    

+type 

+  TLabel*{.pure.} = object of TWidget

+    text*: array[0..256-1, char]

+

+  TcLabelJustify* = enum 

+    cLabelLeft = 0x00000001, cLabelRight = 0x00000002, 

+    cLabelCenter = 0x00000004, cLabelFill = 0x00000008

+

+#*

+#  \brief Creates a Label widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Label widget object.

+# 

+

+proc newlabel*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+               flags: cint): ptr TLabel{.

+    cdecl, importc: "label_widget_create", dynlib: clarodll.}

+#*

+#  \brief Creates a Label widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Label widget object.

+# 

+

+proc newLabel*(parent: ptr TClaroObj, 

+               bounds: ptr TBounds, flags: cint, 

+               text: cstring): ptr TLabel{.cdecl, 

+    importc: "label_widget_create_with_text", dynlib: clarodll.}

+#*

+#  \brief Sets the text of a label widget

+#  

+#  \param obj A valid label widget

+#  \param text The text this label widget will show

+# 

+

+proc label_set_text*(obj: ptr TLabel, text: cstring){.cdecl, 

+    importc: "label_set_text", dynlib: clarodll.}

+    

+#*

+#  \brief Sets the alignment/justification of a label

+#  

+#  \param obj A valid label widget

+#  \param text The justification (see cLabelJustify enum)

+# 

+

+proc label_set_justify*(obj: ptr TLabel, flags: cint){.cdecl, 

+    importc: "label_set_justify", dynlib: clarodll.}

+    

+const 

+  CLIST_TYPE_PTR* = 0

+  CLIST_TYPE_STRING* = 1

+  CLIST_TYPE_INT* = 2

+  CLIST_TYPE_UINT* = 3

+  CLIST_TYPE_DOUBLE* = 4

+

+# functions 

+#*

+#  \brief Initialises a list_widget_t derivative's storage space.

+# 

+#  \param obj list widget

+#  \param col_num number of columns to be used

+#  \param cols An array of col_num integers, specifying the 

+#              types of the columns.

+# 

+

+proc list_widget_init_ptr*(obj: ptr TListWidget, col_num: cint, 

+                           cols: ptr cint) {.cdecl, 

+    importc: "list_widget_init_ptr", dynlib: clarodll.}

+#*

+#  \brief Copies and passes on the arg list to list_widget_init_ptr.

+# 

+#  \param obj list widget

+#  \param col_num number of columns to be used

+#  \param argpi A pointer to a va_list to parse

+# 

+

+#proc list_widget_init_vaptr*(obj: ptr TClaroObj, col_num: cunsignedint, 

+#                             argpi: va_list){.cdecl, 

+#    importc: "list_widget_init_vaptr", dynlib: clarodll.}

+

+#*

+#  Shortcut function, simply calls list_widget_init_ptr with

+#  it's own arguments, and a pointer to the first variable argument.

+# 

+

+proc list_widget_init*(obj: ptr TListWidget, col_num: cint){.varargs, 

+    cdecl, importc: "list_widget_init", dynlib: clarodll.}

+#*

+#  \brief Inserts a row to a list under parent at the position specified.

+# 

+#  \param list list to insert item in

+#  \param parent item in tree to be used as parent. NULL specifies

+#   that it should be a root node.

+#  \param row item will be inserted before the item currently at

+#   this position. -1 specifies an append.

+#  \param argp points to the first element of an array containing

+#  the column data as specified by the types in list_widget_init.

+# 

+

+#*

+#  Shortcut function, calls list_widget_row_insert_ptr with

+#  it's own arguments, a position at the end of the list, and

+#  a pointer to the first variable argument.

+# 

+

+proc list_widget_row_append*(list: ptr TListWidget, 

+                             parent: ptr TListItem): ptr TListItem{.

+    varargs, cdecl, importc: "list_widget_row_append", dynlib: clarodll.}

+#*

+#  Shortcut function, calls list_widget_row_insert_ptr with

+#  it's own arguments, and a pointer to the first variable argument.

+# 

+

+proc list_widget_row_insert*(list: ptr TListWidget, parent: ptr TListItem, 

+                             pos: cint): ptr TListItem {.varargs, cdecl, 

+    importc: "list_widget_row_insert", dynlib: clarodll.}

+#*

+#  \brief Removes a row from a list

+# 

+#  \param list List widget to operate on

+#  \param item The item to remove

+# 

+

+proc list_widget_row_remove*(list: ptr TListWidget, item: ptr TListItem){.

+    cdecl, importc: "list_widget_row_remove", dynlib: clarodll.}

+#*

+#  \brief Moves a row to a new position in the list

+# 

+#  \param list List widget to operate on

+#  \param item The item to move 

+#  \param row Row position to place item before. Passing the current

+#             position will result in no change.

+# 

+

+proc list_widget_row_move*(list: ptr TListWidget, item: ptr TListItem, 

+                           row: cint){.cdecl, importc: "list_widget_row_move", 

+                                       dynlib: clarodll.}

+#*

+#  \brief Return the nth row under parent in the list

+# 

+#  \param list List widget search

+#  \param parent Parent of the item

+#  \param row Row index of item to return

+# 

+

+proc list_widget_get_row*(list: ptr TListWidget, parent: ptr TListItem, 

+                          row: cint): ptr TListItem{.cdecl, 

+    importc: "list_widget_get_row", dynlib: clarodll.}

+#*

+#  \brief Edit items of a row in the list.

+# 

+#  \param list List widget to edit

+#  \param item Row to modify

+#  \param args num,val,...,-1 where num is the column and val is the new 

+#              value of the column's type. Terminate with -1. 

+#              Don't forget the -1.

+# 

+

+#*

+#  \brief Edit items of a row in the list.

+# 

+#  \param list List-based (list_widget_t) object

+#  \param item Row to modify

+#  \param ... num,val,...,-1 where num is the column and val is the new 

+#              value of the column's type. Terminate with -1. 

+#              Don't forget the -1.

+# 

+

+proc list_widget_edit_row*(list: ptr TListWidget, item: ptr TListItem){.

+    varargs, cdecl, importc: "list_widget_edit_row", dynlib: clarodll.}

+#*

+#  \brief Set the text color of an item.

+#  This is currently only supported by the TreeView widget.

+# 

+#  \param item Target list item

+#  \param r Red component between 0.0 and 1.0

+#  \param g Green component between 0.0 and 1.0

+#  \param b Blue component between 0.0 and 1.0

+#  \param a Alpha component between 0.0 and 1.0 (reserved for future use,

+#          should be 1.0)

+# 

+

+proc list_item_set_text_color*(item: ptr TListItem, r: cfloat, g: cfloat, 

+                               b: cfloat, a: cfloat){.cdecl, 

+    importc: "list_item_set_text_color", dynlib: clarodll.}

+#*

+#  \brief Set the text background color of an item.

+#  This is currently only supported by the TreeView widget.

+# 

+#  \param item Target list item

+#  \param r Red component between 0.0 and 1.0

+#  \param g Green component between 0.0 and 1.0

+#  \param b Blue component between 0.0 and 1.0

+#  \param a Alpha component between 0.0 and 1.0 (reserved for future use,

+#           should be 1.0)

+# 

+

+proc list_item_set_text_bgcolor*(item: ptr TListItem, r: cfloat, g: cfloat, 

+                                 b: cfloat, a: cfloat){.cdecl, 

+    importc: "list_item_set_text_bgcolor", dynlib: clarodll.}

+#*

+#  \brief Set the text color of a selected item.

+#  This is currently only supported by the TreeView widget.

+# 

+#  \param item Target list item

+#  \param r Red component between 0.0 and 1.0

+#  \param g Green component between 0.0 and 1.0

+#  \param b Blue component between 0.0 and 1.0

+#  \param a Alpha component between 0.0 and 1.0 (reserved for future use,

+#         should be 1.0)

+# 

+

+proc list_item_set_sel_text_color*(item: ptr TListItem, r: cfloat, g: cfloat, 

+                                   b: cfloat, a: cfloat){.cdecl, 

+    importc: "list_item_set_sel_text_color", dynlib: clarodll.}

+#*

+#  \brief Set the text background color of a selected item.

+#  This is currently only supported by the TreeView widget.

+# 

+#  \param item Target list item

+#  \param r Red component between 0.0 and 1.0

+#  \param g Green component between 0.0 and 1.0

+#  \param b Blue component between 0.0 and 1.0

+#  \param a Alpha component between 0.0 and 1.0 (reserved for future use,

+#          should be 1.0)

+# 

+

+proc list_item_set_sel_text_bgcolor*(item: ptr TListItem, r: cfloat, 

+                                     g: cfloat, b: cfloat, a: cfloat){.cdecl, 

+    importc: "list_item_set_sel_text_bgcolor", dynlib: clarodll.}

+#*

+#  \brief Set the font details of the specified item.

+# 

+#  \param item Target list item

+#  \param weight The weight of the font

+#  \param slant The slant of the font

+#  \param decoration Font decorations

+# 

+

+proc list_item_set_font_extra*(item: ptr TListItem, weight: cint, 

+                               slant: cint, decoration: cint){.cdecl, 

+    importc: "list_item_set_font_extra", dynlib: clarodll.}

+

+type 

+  TListbox* {.pure.} = object of TListWidget

+    selected*: ptr TListItem

+

+# functions 

+#*

+#  \brief Creates a ListBox widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new ListBox widget object.

+# 

+

+proc newlistbox*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                 flags: cint): ptr TListbox{.

+    cdecl, importc: "listbox_widget_create", dynlib: clarodll.}

+#*

+#  \brief Insert a row at the specified position into a ListBox widget

+#  

+#  \param listbox A valid ListBox widget object.

+#  \param pos The index at which this item will be placed.

+#  \param text The text for the item.

+#  \return A new list item.

+# 

+

+proc listbox_insert_row*(listbox: ptr TListbox, pos: cint, 

+                         text: cstring): ptr TListItem{.

+    cdecl, importc: "listbox_insert_row", dynlib: clarodll.}

+#*

+#  \brief Append a row to a ListBox widget

+#  

+#  \param listbox A valid ListBox widget object.

+#  \param text The text for the item.

+#  \return A new list item.

+# 

+

+proc listbox_append_row*(listbox: ptr TListbox, text: cstring): ptr TListItem{.

+    cdecl, importc: "listbox_append_row", dynlib: clarodll.}

+#*

+#  \brief Move a row in a ListBox widget

+#  

+#  \param listbox A valid ListBox widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc listbox_move_row*(listbox: ptr TListbox, item: ptr TListItem, row: cint){.

+    cdecl, importc: "listbox_move_row", dynlib: clarodll.}

+#*

+#  \brief Remove a row from a ListBox widget

+#  

+#  \param listbox A valid ListBox widget object.

+#  \param item A valid list item

+# 

+

+proc listbox_remove_row*(listbox: ptr TListbox, item: ptr TListItem){.cdecl, 

+    importc: "listbox_remove_row", dynlib: clarodll.}

+#*

+#  \brief Returns the currently selected ListBox item

+#  

+#  \param obj A valid ListBox widget object.

+#  \return The currently selected ListBox item, or NULL if no item is selected.

+# 

+

+proc listbox_get_selected*(obj: ptr TListbox): ptr TListItem{.cdecl, 

+    importc: "listbox_get_selected", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a ListBox widget

+#  

+#  \param obj A valid ListBox widget object.

+#  \return Number of rows

+# 

+

+proc listbox_get_rows*(obj: ptr TListbox): cint{.cdecl, 

+    importc: "listbox_get_rows", dynlib: clarodll.}

+#*

+#  \brief Selects a row in a ListBox widget

+#  

+#  \param obj A valid ListBox widget object.

+#  \param item A valid list item

+# 

+

+proc listbox_select_item*(obj: ptr TListbox, item: ptr TListItem){.cdecl, 

+    importc: "listbox_select_item", dynlib: clarodll.}

+

+const 

+  cListViewTypeNone* = 0

+  cListViewTypeText* = 1

+  cListViewTypeCheckBox* = 2

+  cListViewTypeProgress* = 3

+

+# whole row checkboxes.. will we really need this? hmm.

+

+const 

+  cListViewRowCheckBoxes* = 1

+

+type 

+  TListview* {.pure.} = object of TListWidget

+    titles*: cstringArray

+    nativep*: pointer

+    selected*: ptr TListItem

+

+

+# functions 

+#*

+#  \brief Creates a ListView widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \param columns The number of columns in the listview

+#  \param ... specifies the titles and types of each column. 

+#             ("Enable",cListViewTypeCheckBox,"Title",cListViewTypeText,...)

+#  \return A new ListView widget object.

+# 

+

+proc newlistview*(parent: ptr TClaroObj, bounds: ptr TBounds, columns: cint, 

+                  flags: cint): ptr TListview {.varargs, cdecl, 

+    importc: "listview_widget_create", dynlib: clarodll.}

+#*

+#  \brief Append a row to a ListView widget

+#  

+#  \param listview A valid ListView widget object.

+#  \param ... A list of values for each column

+#  \return A new list item.

+# 

+

+proc listview_append_row*(listview: ptr TListview): ptr TListItem{.varargs, 

+    cdecl, importc: "listview_append_row", dynlib: clarodll.}

+#*

+#  \brief Insert a row at the specified position into a ListView widget

+#  

+#  \param listview A valid ListView widget object.

+#  \param pos The index at which this item will be placed.

+#  \param ... A list of values for each column

+#  \return A new list item.

+# 

+

+proc listview_insert_row*(listview: ptr TListview, pos: cint): ptr TListItem{.

+    varargs, cdecl, importc: "listview_insert_row", dynlib: clarodll.}

+#*

+#  \brief Move a row in a ListView widget

+#  

+#  \param listview A valid ListView widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc listview_move_row*(listview: ptr TListview, item: ptr TListItem, 

+                        row: cint){.cdecl, importc: "listview_move_row", 

+                                    dynlib: clarodll.}

+#*

+#  \brief Remove a row from a ListView widget

+#  

+#  \param listview A valid ListView widget object.

+#  \param item A valid list item

+# 

+

+proc listview_remove_row*(listview: ptr TListview, item: ptr TListItem){.

+    cdecl, importc: "listview_remove_row", dynlib: clarodll.}

+#*

+#  \brief Returns the currently selected ListView item

+#  

+#  \param obj A valid ListView widget object.

+#  \return The currently selected ListView item, or NULL if no item is selected.

+# 

+

+proc listview_get_selected*(obj: ptr TListview): ptr TListItem{.cdecl, 

+    importc: "listview_get_selected", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a ListView widget

+#  

+#  \param obj A valid ListView widget object.

+#  \return Number of rows

+# 

+

+proc listview_get_rows*(obj: ptr TListview): cint{.cdecl, 

+    importc: "listview_get_rows", dynlib: clarodll.}

+#*

+#  \brief Selects a row in a ListView widget

+#  

+#  \param obj A valid ListView widget object.

+#  \param item A valid list item

+# 

+

+proc listview_select_item*(obj: ptr TListview, item: ptr TListItem){.cdecl, 

+    importc: "listview_select_item", dynlib: clarodll.}

+

+const 

+  cMenuPopupAtCursor* = 1

+

+type 

+  TMenu* {.pure.} = object of TListWidget

+

+

+#*

+#  \brief Creates a Menu widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param flags Widget flags.

+#  \return A new Menu widget object.

+# 

+

+proc newmenu*(parent: ptr TClaroObj, flags: cint): ptr TMenu {.cdecl, 

+    importc: "menu_widget_create", dynlib: clarodll.}

+#*

+#  \brief Append a row to a Menu widget

+#  

+#  \param menu A valid Menu widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \param image An image object, or NULL.

+#  \param title A string title, or NULL.

+#  \return A new list item.

+# 

+

+proc menu_append_item*(menu: ptr TMenu, parent: ptr TListItem, 

+                       image: ptr TImage, title: cstring): ptr TListItem{.

+    cdecl, importc: "menu_append_item", dynlib: clarodll.}

+#*

+#  \brief Insert a row into a Menu widget

+#  

+#  \param menu A valid Menu widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \param pos The position at which to insert this item

+#  \param image An image object, or NULL.

+#  \param title A string title, or NULL.

+#  \return A new list item.

+# 

+

+proc menu_insert_item*(menu: ptr TMenu, parent: ptr TListItem, pos: cint, 

+                       image: ptr TImage, title: cstring): ptr TListItem{.

+    cdecl, importc: "menu_insert_item", dynlib: clarodll.}

+#*

+#  \brief Append a separator to a Menu widget

+#  

+#  \param menu A valid Menu widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \return A new list item.

+# 

+

+proc menu_append_separator*(menu: ptr TMenu, 

+                            parent: ptr TListItem): ptr TListItem{.

+    cdecl, importc: "menu_append_separator", dynlib: clarodll.}

+#*

+#  \brief Insert a separator into a Menu widget

+#  

+#  \param menu A valid Menu widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \param pos The position at which to insert this item

+#  \return A new list item.

+# 

+

+proc menu_insert_separator*(menu: ptr TMenu, parent: ptr TListItem, 

+                            pos: cint): ptr TListItem{.cdecl, 

+    importc: "menu_insert_separator", dynlib: clarodll.}

+#*

+#  \brief Move a row in a Menu widget

+#  

+#  \param menu A valid Menu widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc menu_move_item*(menu: ptr TMenu, item: ptr TListItem, row: cint){.

+    cdecl, importc: "menu_move_item", dynlib: clarodll.}

+#*

+#  \brief Remove a row from a Menu widget

+#  

+#  \param menu A valid Menu widget object.

+#  \param item A valid list item

+# 

+

+proc menu_remove_item*(menu: ptr TMenu, item: ptr TListItem){.cdecl, 

+    importc: "menu_remove_item", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a Menu widget

+#  

+#  \param obj A valid Menu widget object.

+#  \param parent Item whose children count to return, 

+#  or NULL for root item count.

+#  \return Number of rows

+# 

+

+proc menu_item_count*(obj: ptr TMenu, parent: ptr TListItem): cint{.

+    cdecl, importc: "menu_item_count", dynlib: clarodll.}

+#*

+#  \brief Disables a menu item (no focus and greyed out)

+#  

+#  \param menu A valid Menu widget object.

+#  \param item A valid list item

+# 

+

+proc menu_disable_item*(menu: ptr TMenu, item: ptr TListItem){.cdecl, 

+    importc: "menu_disable_item", dynlib: clarodll.}

+#*

+#  \brief Enables a menu item (allows focus and not greyed out)

+#  

+#  \param menu A valid Menu widget object.

+#  \param item A valid list item

+# 

+

+proc menu_enable_item*(menu: ptr TMenu, item: ptr TListItem){.cdecl, 

+    importc: "menu_enable_item", dynlib: clarodll.}

+#*

+#  \brief Pops up the menu at the position specified

+#  

+#  \param menu A valid Menu widget object.

+#  \param x The X position

+#  \param y The Y position

+#  \param flags Flags

+# 

+

+proc menu_popup*(menu: ptr TMenu, x: cint, y: cint, flags: cint){.cdecl, 

+    importc: "menu_popup", dynlib: clarodll.}

+#

+#   Menu modifiers

+# 

+

+const 

+  cModifierShift* = 1 shl 0

+  cModifierCommand* = 1 shl 1

+

+type 

+  TMenubar* {.pure.} = object of TListWidget

+

+#*

+#  \brief Creates a MenuBar widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param flags Widget flags.

+#  \return A new MenuBar widget object.

+# 

+

+proc newmenubar*(parent: ptr TClaroObj, flags: cint): ptr TMenubar {.cdecl, 

+    importc: "menubar_widget_create", dynlib: clarodll.}

+#*

+#  \brief Add a key binding to a menu items

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param item The item

+#  \param utf8_key The key to use, NOT NULL.

+#  \param modifier The modifier key, or 0.

+# 

+

+proc menubar_add_key_binding*(menubar: ptr TMenubar, item: ptr TListItem, 

+                              utf8_key: cstring, modifier: cint){.cdecl, 

+    importc: "menubar_add_key_binding", dynlib: clarodll.}

+#*

+#  \brief Append a row to a MenuBar widget

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \param image An image object, or NULL.

+#  \param title A string title, or NULL.

+#  \return A new list item.

+# 

+

+proc menubar_append_item*(menubar: ptr TMenubar, parent: ptr TListItem, 

+                          image: ptr TImage, title: cstring): ptr TListItem{.

+    cdecl, importc: "menubar_append_item", dynlib: clarodll.}

+#*

+#  \brief Insert a row into a MenuBar widget

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \param pos The position at which to insert this item

+#  \param image An image object, or NULL.

+#  \param title A string title, or NULL.

+#  \return A new list item.

+# 

+

+proc menubar_insert_item*(menubar: ptr TMenubar, parent: ptr TListItem, 

+                          pos: cint, image: ptr TImage, 

+                          title: cstring): ptr TListItem{.

+    cdecl, importc: "menubar_insert_item", dynlib: clarodll.}

+#*

+#  \brief Append a separator to a MenuBar widget

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \return A new list item.

+# 

+

+proc menubar_append_separator*(menubar: ptr TMenubar, 

+                               parent: ptr TListItem): ptr TListItem{.

+    cdecl, importc: "menubar_append_separator", dynlib: clarodll.}

+#*

+#  \brief Insert a separator into a MenuBar widget

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param parent The item to place the new item under, or NULL for a root item.

+#  \param pos The position at which to insert this item

+#  \return A new list item.

+# 

+

+proc menubar_insert_separator*(menubar: ptr TMenubar, parent: ptr TListItem, 

+                               pos: cint): ptr TListItem{.cdecl, 

+    importc: "menubar_insert_separator", dynlib: clarodll.}

+#*

+#  \brief Move a row in a MenuBar widget

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc menubar_move_item*(menubar: ptr TMenubar, item: ptr TListItem, 

+                        row: cint){.cdecl, importc: "menubar_move_item", 

+                                    dynlib: clarodll.}

+#*

+#  \brief Remove a row from a MenuBar widget

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param item A valid list item

+# 

+

+proc menubar_remove_item*(menubar: ptr TMenubar, item: ptr TListItem) {.

+    cdecl, importc: "menubar_remove_item", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a MenuBar widget

+#  

+#  \param obj A valid MenuBar widget object.

+#  \param parent Item whose children count to return, or NULL for root

+#         item count.

+#  \return Number of rows

+# 

+

+proc menubar_item_count*(obj: ptr TMenubar, parent: ptr TListItem): cint{.

+    cdecl, importc: "menubar_item_count", dynlib: clarodll.}

+#*

+#  \brief Disables a menu item (no focus and greyed out)

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param item A valid list item

+# 

+

+proc menubar_disable_item*(menubar: ptr TMenubar, item: ptr TListItem){.

+    cdecl, importc: "menubar_disable_item", dynlib: clarodll.}

+#*

+#  \brief Enables a menu item (allows focus and not greyed out)

+#  

+#  \param menubar A valid MenuBar widget object.

+#  \param item A valid list item

+# 

+

+proc menubar_enable_item*(menubar: ptr TMenubar, item: ptr TListItem){.

+    cdecl, importc: "menubar_enable_item", dynlib: clarodll.}

+

+type 

+  TProgress* {.pure.} = object of TWidget

+

+  TcProgressStyle* = enum 

+    cProgressLeftRight = 0x00000000, cProgressRightLeft = 0x00000001, 

+    cProgressTopBottom = 0x00000002, cProgressBottomTop = 0x00000004

+

+#*

+#  \brief Creates a Progress widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Progress widget object.

+# 

+

+proc newprogress*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                  flags: cint): ptr TProgress {.

+    cdecl, importc: "progress_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the value of a progress widget

+#  

+#  \param progress A valid progress widget object

+#  \param percentage Progress value

+# 

+

+proc progress_set_level*(progress: ptr TProgress, percentage: cdouble){.cdecl, 

+    importc: "progress_set_level", dynlib: clarodll.}

+#*

+#  \brief Sets the orientation of a progress widget

+#  

+#  \param progress A valid progress widget object

+#  \param flags One of the cProgressStyle values

+# 

+

+proc progress_set_orientation*(progress: ptr TProgress, flags: cint){.cdecl, 

+    importc: "progress_set_orientation", dynlib: clarodll.}

+

+type 

+  TRadioGroup* {.pure.} = object of TClaroObj

+    buttons*: TList

+    selected*: ptr TClaroObj

+    ndata*: pointer

+

+  TRadioButton* {.pure.} = object of TWidget

+    text*: array[0..256-1, char]

+    group*: ptr TRadioGroup

+

+

+#*

+#  \brief Creates a Radio Group widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param flags Widget flags.

+#  \return A new Radio Group widget object.

+# 

+

+proc newRadiogroup*(parent: ptr TClaroObj, flags: cint): ptr TRadioGroup {.

+    cdecl, importc: "radiogroup_create", dynlib: clarodll.}

+#*

+#  \brief Creates a Radio Button widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param group A valid Radio Group widget object

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param label The label of the radio widget

+#  \param flags Widget flags.

+#  \return A new Radio Button widget object.

+# 

+

+proc newradiobutton*(parent: ptr TClaroObj, group: ptr TRadioGroup, 

+                     bounds: ptr TBounds, label: cstring, 

+                     flags: cint): ptr TRadioButton{.

+    cdecl, importc: "radiobutton_widget_create", dynlib: clarodll.}

+#*

+#  \brief Set the label of a Radio Button

+#  

+#  \param obj A valid Radio Button widget

+#  \param label The new label for the Radio Button

+# 

+

+proc radiobutton_set_text*(obj: ptr TRadioButton, label: cstring){.cdecl, 

+    importc: "radiobutton_set_label", dynlib: clarodll.}

+#*

+#  \brief Set the group of a Radio Button

+#  

+#  \param rbutton A valid Radio Button widget

+#  \param group A valid Radio Group widget object

+# 

+

+proc radiobutton_set_group*(rbutton: ptr TRadioButton, group: ptr TRadioGroup){.

+    cdecl, importc: "radiobutton_set_group", dynlib: clarodll.}

+

+const 

+  CLARO_SCROLLBAR_MAXIMUM* = 256

+

+type 

+  TScrollbar* {.pure.} = object of TWidget

+    min*: cint

+    max*: cint

+    pagesize*: cint

+

+

+const 

+  cScrollbarHorizontal* = 0

+  cScrollbarVertical* = 1

+

+# functions 

+#*

+#  \brief Creates a ScrollBar widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new ScrollBar widget object.

+# 

+

+proc newscrollbar*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                   flags: cint): ptr TScrollbar{.

+    cdecl, importc: "scrollbar_widget_create", dynlib: clarodll.}

+#*

+#  \brief Returns the width that scrollbars should be on this platform

+#  

+#  \return Width of vertical scrollbars

+# 

+

+proc scrollbar_get_sys_width*(): cint{.cdecl, 

+                                       importc: "scrollbar_get_sys_width", 

+                                       dynlib: clarodll.}

+#*

+#  \brief Sets the range of a ScrollBar widget

+#  

+#  \param w A valid ScrollBar widget object

+#  \param min The minimum value

+#  \param max The maximum value

+# 

+

+proc scrollbar_set_range*(w: ptr TScrollbar, min: cint, max: cint){.cdecl, 

+    importc: "scrollbar_set_range", dynlib: clarodll.}

+#*

+#  \brief Sets the position of a ScrollBar widget

+#  

+#  \param w A valid ScrollBar widget object

+#  \param pos The new position

+# 

+

+proc scrollbar_set_pos*(w: ptr TScrollbar, pos: cint){.cdecl, 

+    importc: "scrollbar_set_pos", dynlib: clarodll.}

+#*

+#  \brief Gets the position of a ScrollBar widget

+#  

+#  \param w A valid ScrollBar widget object

+#  \return The current position

+# 

+

+proc scrollbar_get_pos*(w: ptr TScrollbar): cint{.cdecl, 

+    importc: "scrollbar_get_pos", dynlib: clarodll.}

+#*

+#  \brief Sets the page size of a ScrollBar widget

+# 

+#  \param w A valid ScrollBar widget object

+#  \param pagesize The size of a page (the number of units visible at one time)

+# 

+

+proc scrollbar_set_pagesize*(w: ptr TScrollbar, pagesize: cint){.cdecl, 

+    importc: "scrollbar_set_pagesize", dynlib: clarodll.}

+    

+type 

+  TcSplitterChildren* = enum 

+    cSplitterFirst = 0, cSplitterSecond = 1

+  TSplitterChild* {.pure.} = object 

+    flex*: cint

+    size*: cint

+    w*: ptr TWidget

+

+  TSplitter* {.pure.} = object of TWidget

+    pair*: array[0..1, TSplitterChild]

+

+

+const 

+  cSplitterHorizontal* = 0

+  cSplitterVertical* = 1

+

+# functions 

+#*

+#  \brief Creates a Splitter widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Splitter widget object.

+# 

+

+proc newsplitter*(parent: ptr TClaroObj, bounds: ptr TBounds,

+                  flags: cint): ptr TSplitter{.

+    cdecl, importc: "splitter_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the sizing information of a child

+#  

+#  \param splitter A valid splitter widget object

+#  \param child The child number, either cSplitterFirst or cSplitterSecond.

+#  \param flex 1 if this child should receive extra space as the splitter 

+#         expands, 0 if not

+#  \param size The size of this child

+# 

+

+proc splitter_set_info*(splitter: ptr TSplitter, child: cint, flex: cint, 

+                        size: cint){.cdecl, importc: "splitter_set_info", 

+                                     dynlib: clarodll.}

+                                     

+type 

+  TStatusbar* {.pure.} = object of TWidget

+    text*: array[0..256 - 1, char]

+

+

+#*

+#  \brief Creates a StatusBar widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param flags Widget flags.

+#  \return A new StatusBar widget object.

+# 

+

+proc newstatusbar*(parent: ptr TClaroObj, flags: cint): ptr TStatusbar {.cdecl, 

+    importc: "statusbar_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the text of a statusbar

+#  

+#  \param obj A valid StatusBar widget

+#  \param text The new text

+# 

+

+proc statusbar_set_text*(obj: ptr TStatusbar, text: cstring){.cdecl, 

+    importc: "statusbar_set_text", dynlib: clarodll.}

+#*

+#  \brief obtains a stock image

+#  

+#  \param stock_id The string ID of the stock image, NOT NULL.

+#  \return The Image object.

+# 

+

+proc stock_get_image*(stock_id: cstring): ptr TImage{.cdecl, 

+    importc: "stock_get_image", dynlib: clarodll.}

+#*

+#  \brief adds a stock id image

+#  

+#  \param stock_id The string ID of the stock image, NOT NULL.

+#  \param img The Image object to add.

+#  \return The Image object.

+# 

+

+proc stock_add_image*(stock_id: cstring, img: ptr TImage){.cdecl, 

+    importc: "stock_add_image", dynlib: clarodll.}

+

+const 

+  CLARO_TEXTAREA_MAXIMUM = (1024 * 1024)

+

+type 

+  TTextArea* {.pure.} = object of TWidget

+    text*: array[0..CLARO_TEXTAREA_MAXIMUM - 1, char]

+

+

+#*

+#  \brief Creates a TextArea widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new TextArea widget object.

+# 

+

+proc newtextarea*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                  flags: cint): ptr TTextArea{.

+    cdecl, importc: "textarea_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the text of a textarea

+#  

+#  \param obj A valid TextArea widget

+#  \param text The new text

+# 

+

+proc textarea_set_text*(obj: ptr TTextArea, text: cstring){.cdecl, 

+    importc: "textarea_set_text", dynlib: clarodll.}

+#*

+#  \brief Retrieve the text of a textarea

+#  

+#  \param obj A valid TextArea widget

+#  \return Pointer to an internal reference of the text. Should not be changed.

+# 

+

+proc textarea_get_text*(obj: ptr TTextArea): cstring{.cdecl, 

+    importc: "textarea_get_text", dynlib: clarodll.}

+

+const 

+  CLARO_TEXTBOX_MAXIMUM = 8192

+

+type 

+  TTextBox* {.pure.} = object of TWidget

+    text*: array[0..CLARO_TEXTBOX_MAXIMUM-1, char]

+

+

+const 

+  cTextBoxTypePassword* = 1

+

+# functions 

+#*

+#  \brief Creates a TextBox widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new TextBox widget object.

+# 

+

+proc newtextbox*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                 flags: cint): ptr TTextBox{.

+    cdecl, importc: "textbox_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the text of a textbox

+#  

+#  \param obj A valid TextBox widget

+#  \param text The new text

+# 

+

+proc textbox_set_text*(obj: ptr TTextBox, text: cstring){.cdecl, 

+    importc: "textbox_set_text", dynlib: clarodll.}

+#*

+#  \brief Retrieve the text of a textbox

+#  

+#  \param obj A valid TextBox widget

+#  \return Pointer to an internal reference of the text. Should not be changed.

+# 

+

+proc textbox_get_text*(obj: ptr TTextBox): cstring{.cdecl, 

+    importc: "textbox_get_text", dynlib: clarodll.}

+#*

+#  \brief Retrieve the cursor position inside a textbox

+#  

+#  \param obj A valid TextBox widget

+#  \return Cursor position inside TextBox

+# 

+

+proc textbox_get_pos*(obj: ptr TTextBox): cint{.cdecl, 

+    importc: "textbox_get_pos", dynlib: clarodll.}

+#*

+#  \brief Sets the cursor position inside a textbox

+#  

+#  \param obj A valid TextBox widget

+#  \param pos New cursor position inside TextBox

+# 

+

+proc textbox_set_pos*(obj: ptr TTextBox, pos: cint){.cdecl, 

+    importc: "textbox_set_pos", dynlib: clarodll.}

+

+const 

+  cToolbarShowText* = 1

+  cToolbarShowImages* = 2

+  cToolbarShowBoth* = 3

+  cToolbarAutoSizeButtons* = 4

+

+type 

+  TToolbar* {.pure.} = object of TListWidget

+

+#*

+#  \brief Creates a ToolBar widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param flags Widget flags.

+#  \return A new ToolBar widget object.

+# 

+

+proc newtoolbar*(parent: ptr TClaroObj, flags: cint): ptr TToolbar{.cdecl, 

+    importc: "toolbar_widget_create", dynlib: clarodll.}

+#*

+#  \brief Append a row to a ToolBar widget

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \param image An image object, or NULL.

+#  \param title A string title, or NULL.

+#  \param tooltip A string tooltip, or NULL.

+#  \return A new list item.

+# 

+

+proc toolbar_append_icon*(toolbar: ptr TToolbar, image: ptr TImage, 

+                          title: cstring, tooltip: cstring): ptr TListItem{.

+    cdecl, importc: "toolbar_append_icon", dynlib: clarodll.}

+#*

+#  \brief Insert a row into a ToolBar widget

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \param pos The position at which to insert this item

+#  \param image An image object, or NULL.

+#  \param title A string title, or NULL.

+#  \param tooltip A string tooltip, or NULL.

+#  \return A new list item.

+# 

+

+proc toolbar_insert_icon*(toolbar: ptr TToolbar, pos: cint, 

+                          image: ptr TImage, title: cstring, 

+                          tooltip: cstring): ptr TListItem{.

+    cdecl, importc: "toolbar_insert_icon", dynlib: clarodll.}

+#*

+#  \brief Append a separator to a ToolBar widget

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \return A new list item.

+# 

+

+proc toolbar_append_separator*(toolbar: ptr TToolbar): ptr TListItem{.cdecl, 

+    importc: "toolbar_append_separator", dynlib: clarodll.}

+#*

+#  \brief Insert a separator into a ToolBar widget

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \param pos The position at which to insert this item

+#  \return A new list item.

+# 

+

+proc toolbar_insert_separator*(toolbar: ptr TToolbar, 

+                               pos: cint): ptr TListItem {.

+    cdecl, importc: "toolbar_insert_separator", dynlib: clarodll.}

+#*

+#  \brief Assign a menu widget to an item.

+# 

+#  This will show a small down arrow next to the item

+#  that will open this menu.

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \param item Toolbar item the menu is for.

+#  \param menu Menu widget object, or NULL to remove a menu.

+# 

+

+proc toolbar_set_item_menu*(toolbar: ptr TToolbar, item: ptr TListItem, 

+                            menu: ptr TMenu){.cdecl, 

+    importc: "toolbar_set_item_menu", dynlib: clarodll.}

+#*

+#  \brief Move a row in a ToolBar widget

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc toolbar_move_icon*(toolbar: ptr TToolbar, item: ptr TListItem, 

+                        row: cint){.cdecl, importc: "toolbar_move_icon", 

+                                    dynlib: clarodll.}

+#*

+#  \brief Remove a row from a ToolBar widget

+#  

+#  \param toolbar A valid ToolBar widget object.

+#  \param item A valid list item

+# 

+

+proc toolbar_remove_icon*(toolbar: ptr TToolbar, item: ptr TListItem){.

+    cdecl, importc: "toolbar_remove_icon", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a ToolBar widget

+#  

+#  \param obj A valid ToolBar widget object.

+#  \return Number of rows

+# 

+

+proc toolbar_item_count*(obj: ptr TToolbar): cint{.cdecl, 

+    importc: "toolbar_item_count", dynlib: clarodll.}

+#*

+#  \brief TreeView widget

+# 

+

+type 

+  TTreeview* {.pure.} = object of TListWidget

+    selected*: ptr TListItem

+

+

+# functions 

+#*

+#  \brief Creates a TreeView widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new TreeView widget object.

+# 

+

+proc newtreeview*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                  flags: cint): ptr TTreeview{.

+    cdecl, importc: "treeview_widget_create", dynlib: clarodll.}

+#*

+#  \brief Append a row to a TreeView

+#  

+#  \param treeview A valid TreeView widget object.

+#  \param parent The item under which to place the new item, or NULL for a root node.

+#  \param image An image to go to the left of the item, or NULL for no image.

+#  \param title The text for the item.

+#  \return A new list item.

+# 

+

+proc treeview_append_row*(treeview: ptr TTreeview, parent: ptr TListItem, 

+                          image: ptr TImage, title: cstring): ptr TListItem{.

+    cdecl, importc: "treeview_append_row", dynlib: clarodll.}

+#*

+#  \brief Insert a row at the specified position into a TreeView

+#  

+#  \param treeview A valid TreeView widget object.

+#  \param parent The item under which to place the new item, or NULL for a root node.

+#  \param pos The index at which this item will be placed.

+#  \param image An image to go to the left of the item, or NULL for no image.

+#  \param title The text for the item.

+#  \return A new list item.

+# 

+

+proc treeview_insert_row*(treeview: ptr TTreeview, parent: ptr TListItem, 

+                          pos: cint, image: ptr TImage, 

+                          title: cstring): ptr TListItem{.

+    cdecl, importc: "treeview_insert_row", dynlib: clarodll.}

+#*

+#  \brief Move a row in a TreeView

+#  

+#  \param treeview A valid TreeView widget object.

+#  \param item A valid list item

+#  \param row New position to place this item

+# 

+

+proc treeview_move_row*(treeview: ptr TTreeview, item: ptr TListItem, 

+                        row: cint){.cdecl, importc: "treeview_move_row", 

+                                    dynlib: clarodll.}

+#*

+#  \brief Remove a row from a TreeView

+#  

+#  \param treeview A valid TreeView widget object.

+#  \param item A valid list item

+# 

+

+proc treeview_remove_row*(treeview: ptr TTreeview, item: ptr TListItem){.

+    cdecl, importc: "treeview_remove_row", dynlib: clarodll.}

+#*

+#  \brief Expand a row in a TreeView

+#  

+#  \param treeview A valid TreeView widget object.

+#  \param item A valid list item

+# 

+

+proc treeview_expand*(treeview: ptr TTreeview, item: ptr TListItem){.cdecl, 

+    importc: "treeview_expand", dynlib: clarodll.}

+#*

+#  \brief Collapse a row in a TreeView

+#  

+#  \param treeview A valid TreeView widget object.

+#  \param item A valid list item

+# 

+

+proc treeview_collapse*(treeview: ptr TTreeview, item: ptr TListItem){.cdecl, 

+    importc: "treeview_collapse", dynlib: clarodll.}

+#*

+#  \brief Returns the currently selected TreeView item

+#  

+#  \param obj A valid TreeView widget object.

+#  \return The currently selected TreeView item, or NULL if no item is selected.

+# 

+

+proc treeview_get_selected*(obj: ptr TTreeview): ptr TListItem{.cdecl, 

+    importc: "treeview_get_selected", dynlib: clarodll.}

+#*

+#  \brief Returns the number of rows in a TreeView

+#  

+#  \param obj A valid TreeView widget object.

+#  \param parent Return the number of children of this item, or the number of

+#                root items if NULL

+#  \return Number of rows

+# 

+

+proc treeview_get_rows*(obj: ptr TTreeview, parent: ptr TListItem): cint{.

+    cdecl, importc: "treeview_get_rows", dynlib: clarodll.}

+#*

+#  \brief Selects a row in a TreeView

+#  

+#  \param obj A valid TreeView widget object.

+#  \param item A valid list item

+# 

+

+proc treeview_select_item*(obj: ptr TTreeview, item: ptr TListItem){.cdecl, 

+    importc: "treeview_select_item", dynlib: clarodll.}

+

+const 

+  cWindowModalDialog* = 1

+  cWindowCenterParent* = 2

+  cWindowNoResizing* = 4

+

+type 

+  TWindow* {.pure.} = object of TWidget

+    title*: array[0..512 - 1, char]

+    icon*: ptr TImage

+    menubar*: ptr TWidget

+    workspace*: ptr TWidget

+    exsp_tools*: cint

+    exsp_status*: cint

+    exsp_init*: cint

+

+

+const 

+  cWindowFixedSize* = 1

+

+# functions 

+#*

+#  \brief Creates a Window widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Window widget object.

+# 

+

+proc newwindow*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                flags: cint): ptr TWindow {.

+    cdecl, importc: "window_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets a Window's title

+#  

+#  \param w A valid Window widget object

+#  \param title The new title for the window

+# 

+

+proc window_set_title*(w: ptr TWindow, title: cstring){.cdecl, 

+    importc: "window_set_title", dynlib: clarodll.}

+#*

+#  \brief Makes a window visible

+#  

+#  \param w A valid Window widget object

+# 

+

+proc window_show*(w: ptr TWindow){.cdecl, importc: "window_show", 

+                                     dynlib: clarodll.}

+#*

+#  \brief Makes a window invisible

+#  

+#  \param w A valid Window widget object

+# 

+

+proc window_hide*(w: ptr TWindow){.cdecl, importc: "window_hide", 

+                                     dynlib: clarodll.}

+#*

+#  \brief Gives focus to a window

+#  

+#  \param w A valid Window widget object

+# 

+

+proc window_focus*(w: ptr TWindow){.cdecl, importc: "window_focus", 

+                                      dynlib: clarodll.}

+#*

+#  \brief Maximises a window

+#  

+#  \param w A valid Window widget object

+# 

+

+proc window_maximize*(w: ptr TWindow){.cdecl, importc: "window_maximise", 

+    dynlib: clarodll.}

+#*

+#  \brief Minimises a window

+#  

+#  \param w A valid Window widget object

+# 

+

+proc window_minimize*(w: ptr TWindow){.cdecl, importc: "window_minimise", 

+    dynlib: clarodll.}

+#*

+#  \brief Restores a window

+#  

+#  \param w A valid Window widget object

+# 

+

+proc window_restore*(w: ptr TWindow){.cdecl, importc: "window_restore", 

+                                        dynlib: clarodll.}

+#*

+#  \brief Sets a window's icon

+#  

+#  \param w A valid Window widget object

+#  \param icon A valid Image object

+# 

+

+proc window_set_icon*(w: ptr TWindow, icon: ptr TImage){.cdecl, 

+    importc: "window_set_icon", dynlib: clarodll.}

+

+const 

+  cWorkspaceTileHorizontally* = 0

+  cWorkspaceTileVertically* = 1

+

+type 

+  TWorkspace*{.pure.} = object of TWidget

+

+  TWorkspaceWindow*{.pure.} = object of TWidget

+    icon*: ptr TImage

+    title*: array[0..512 - 1, char]

+    workspace*: ptr TWorkspace

+

+

+# functions (workspace) 

+#*

+#  \brief Creates a Workspace widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Workspace widget object.

+# 

+

+proc newworkspace*(parent: ptr TClaroObj, bounds: ptr TBounds, 

+                   flags: cint): ptr TWorkspace{.

+    cdecl, importc: "workspace_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the active (visible) workspace child

+#  

+#  \param workspace A valid workspace widget

+#  \param child A valid workspace window widget

+# 

+

+proc workspace_set_active*(workspace: ptr TWorkspace, child: ptr TClaroObj){.

+    cdecl, importc: "workspace_set_active", dynlib: clarodll.}

+#*

+#  \brief Returns the active (visible) workspace child

+#  

+#  \param workspace A valid workspace widget

+#  \return The active workspace window widget

+# 

+

+proc workspace_get_active*(workspace: ptr TWorkspace): ptr TWorkspace{.cdecl, 

+    importc: "workspace_get_active", dynlib: clarodll.}

+#*

+#  \brief Cascades all workspace windows

+#  

+#  \param workspace A valid workspace widget

+# 

+

+proc workspace_cascade*(workspace: ptr TWorkspace){.cdecl, 

+    importc: "workspace_cascade", dynlib: clarodll.}

+#*

+#  \brief Tiles all workspace windows

+#  

+#  \param workspace A valid workspace widget

+#  \param dir The direction to tile child widgets

+# 

+

+proc workspace_tile*(workspace: ptr TWorkspace, dir: cint){.cdecl, 

+    importc: "workspace_tile", dynlib: clarodll.}

+# functions (workspace_window) 

+#*

+#  \brief Creates a Workspace widget

+#  

+#  \param parent The parent widget of this widget, NOT NULL.

+#  \param bounds The initial bounds of this widget, or NO_BOUNDS.

+#  \param flags Widget flags.

+#  \return A new Workspace widget object.

+# 

+

+proc newWorkspaceWindow*(parent: ptr TClaroObj, 

+                         bounds: ptr TBounds, 

+                         flags: cint): ptr TWorkspaceWindow{.

+    cdecl, importc: "workspace_window_widget_create", dynlib: clarodll.}

+#*

+#  \brief Sets the title of a Workspace Window widget

+#  

+#  \param window A valid Workspace Window widget

+#  \param title The new title for the widget

+# 

+

+proc workspace_window_set_title*(window: ptr TWorkspaceWindow, 

+                                 title: cstring){.cdecl, 

+    importc: "workspace_window_set_title", dynlib: clarodll.}

+#*

+#  \brief Makes a Workspace Window widget visible

+#  

+#  \param window A valid Workspace Window widget

+# 

+

+proc workspace_window_show*(window: ptr TWorkspaceWindow){.cdecl, 

+    importc: "workspace_window_show", dynlib: clarodll.}

+#*

+#  \brief Makes a Workspace Window widget invisible

+#  

+#  \param window A valid Workspace Window widget

+# 

+

+proc workspace_window_hide*(window: ptr TWorkspaceWindow){.cdecl, 

+    importc: "workspace_window_hide", dynlib: clarodll.}

+#*

+#  \brief Restores a Workspace Window widget

+#  

+#  \param window A valid Workspace Window widget

+# 

+

+proc workspace_window_restore*(window: ptr TWorkspaceWindow){.cdecl, 

+    importc: "workspace_window_restore", dynlib: clarodll.}

+# American spelling 

+

+#*

+#  \brief Minimises a Workspace Window widget

+#  

+#  \param window A valid Workspace Window widget

+# 

+

+proc workspace_window_minimize*(window: ptr TWorkspaceWindow){.cdecl, 

+    importc: "workspace_window_minimise", dynlib: clarodll.}

+#*

+#  \brief Maxmimises a Workspace Window widget

+#  

+#  \param window A valid Workspace Window widget

+# 

+

+proc workspace_window_maximize*(window: ptr TWorkspaceWindow){.cdecl, 

+    importc: "workspace_window_maximise", dynlib: clarodll.}

+#*

+#  \brief Sets the icon of a Workspace Window widget

+#  

+#  \param window A valid Workspace Window widget

+#  \param icon A valid Image object.

+# 

+

+proc workspace_window_set_icon*(w: ptr TWorkspaceWindow, icon: ptr TImage){.

+    cdecl, importc: "workspace_window_set_icon", dynlib: clarodll.}

+    

+claro_base_init()

+claro_graphics_init()

+

+when not defined(testing) and isMainModule:

+  var w = newWindow(nil, newBounds(100, 100, 230, 230), 0)

+  window_set_title(w, "Hello, World!")

+

+  var t = newTextbox(w, new_bounds(10, 10, 210, -1), 0)

+  widget_set_notify(t, cNotifyKey)

+  textbox_set_text(t, "Yeehaw!")

+

+  var b = newButton(w, new_bounds(40, 45, 150, -1), 0, "Push my button!")

+

+  proc push_my_button(obj: ptr TClaroObj, event: ptr TEvent) {.cdecl.} =

+    textbox_set_text(t, "You pushed my button!")

+    var button = cast[ptr TButton](obj)

+    button_set_text(button, "Ouch!")

+

+  object_addhandler(b, "pushed", push_my_button)

+

+  window_show(w)

+  window_focus(w)

+

+  claro_loop()

+

diff --git a/lib/wrappers/expat.nim b/lib/wrappers/expat.nim
new file mode 100644
index 000000000..a3d888201
--- /dev/null
+++ b/lib/wrappers/expat.nim
@@ -0,0 +1,877 @@
+# Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+#   See the file COPYING for copying permission.
+#
+
+when not defined(expatDll): 
+  when defined(windows): 
+    const 
+      expatDll = "expat.dll"
+  elif defined(macosx): 
+    const 
+      expatDll = "libexpat.dylib"
+  else: 
+    const 
+      expatDll = "libexpat.so(.1|)"
+type 
+  TParserStruct{.pure, final.} = object 
+  
+  PParser* = ptr TParserStruct
+
+# The XML_Status enum gives the possible return values for several
+#   API functions.  The preprocessor #defines are included so this
+#   stanza can be added to code that still needs to support older
+#   versions of Expat 1.95.x:
+#
+#   #ifndef XML_STATUS_OK
+#   #define XML_STATUS_OK    1
+#   #define XML_STATUS_ERROR 0
+#   #endif
+#
+#   Otherwise, the #define hackery is quite ugly and would have been
+#   dropped.
+#
+
+type 
+  TStatus*{.size: sizeof(cint).} = enum 
+    STATUS_ERROR = 0, STATUS_OK = 1, STATUS_SUSPENDED = 2
+  TError*{.size: sizeof(cint).} = enum 
+    ERROR_NONE, ERROR_NO_MEMORY, ERROR_SYNTAX, ERROR_NO_ELEMENTS, 
+    ERROR_INVALID_TOKEN, ERROR_UNCLOSED_TOKEN, ERROR_PARTIAL_CHAR, 
+    ERROR_TAG_MISMATCH, ERROR_DUPLICATE_ATTRIBUTE,
+    ERROR_JUNK_AFTER_DOC_ELEMENT, 
+    ERROR_PARAM_ENTITY_REF, ERROR_UNDEFINED_ENTITY, ERROR_RECURSIVE_ENTITY_REF, 
+    ERROR_ASYNC_ENTITY, ERROR_BAD_CHAR_REF, ERROR_BINARY_ENTITY_REF, 
+    ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, ERROR_MISPLACED_XML_PI, 
+    ERROR_UNKNOWN_ENCODING, ERROR_INCORRECT_ENCODING, 
+    ERROR_UNCLOSED_CDATA_SECTION, ERROR_EXTERNAL_ENTITY_HANDLING, 
+    ERROR_NOT_STANDALONE, ERROR_UNEXPECTED_STATE, ERROR_ENTITY_DECLARED_IN_PE, 
+    ERROR_FEATURE_REQUIRES_XML_DTD, ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,  
+    ERROR_UNBOUND_PREFIX,     
+    ERROR_UNDECLARING_PREFIX, ERROR_INCOMPLETE_PE, ERROR_XML_DECL, 
+    ERROR_TEXT_DECL, ERROR_PUBLICID, ERROR_SUSPENDED, ERROR_NOT_SUSPENDED, 
+    ERROR_ABORTED, ERROR_FINISHED, ERROR_SUSPEND_PE, 
+    ERROR_RESERVED_PREFIX_XML, ERROR_RESERVED_PREFIX_XMLNS, 
+    ERROR_RESERVED_NAMESPACE_URI
+  TContent_Type*{.size: sizeof(cint).} = enum 
+    CTYPE_EMPTY = 1, CTYPE_ANY, CTYPE_MIXED, CTYPE_NAME, CTYPE_CHOICE, CTYPE_SEQ
+  TContent_Quant*{.size: sizeof(cint).} = enum 
+    CQUANT_NONE, CQUANT_OPT, CQUANT_REP, CQUANT_PLUS
+
+# If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
+#   XML_CQUANT_NONE, and the other fields will be zero or NULL.
+#   If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
+#   numchildren will contain number of elements that may be mixed in
+#   and children point to an array of XML_Content cells that will be
+#   all of XML_CTYPE_NAME type with no quantification.
+#
+#   If type == XML_CTYPE_NAME, then the name points to the name, and
+#   the numchildren field will be zero and children will be NULL. The
+#   quant fields indicates any quantifiers placed on the name.
+#
+#   CHOICE and SEQ will have name NULL, the number of children in
+#   numchildren and children will point, recursively, to an array
+#   of XML_Content cells.
+#
+#   The EMPTY, ANY, and MIXED types will only occur at top level.
+#
+
+type 
+  TContent*{.pure, final.} = object 
+    typ*: TContentType
+    quant*: TContentQuant
+    name*: cstring
+    numchildren*: cint
+    children*: ptr TContent
+
+
+# This is called for an element declaration. See above for
+#   description of the model argument. It's the caller's responsibility
+#   to free model when finished with it.
+#
+
+type 
+  TElementDeclHandler* = proc (userData: pointer, name: cstring, 
+                               model: ptr TContent){.cdecl.}
+
+proc setElementDeclHandler*(parser: PParser, eldecl: TElementDeclHandler){.
+    cdecl, importc: "XML_SetElementDeclHandler", dynlib: expatDll.}
+# The Attlist declaration handler is called for *each* attribute. So
+#   a single Attlist declaration with multiple attributes declared will
+#   generate multiple calls to this handler. The "default" parameter
+#   may be NULL in the case of the "#IMPLIED" or "#REQUIRED"
+#   keyword. The "isrequired" parameter will be true and the default
+#   value will be NULL in the case of "#REQUIRED". If "isrequired" is
+#   true and default is non-NULL, then this is a "#FIXED" default.
+#
+
+type 
+  TAttlistDeclHandler* = proc (userData: pointer, elname: cstring, 
+                               attname: cstring, attType: cstring, 
+                               dflt: cstring, isrequired: cint){.cdecl.}
+
+proc setAttlistDeclHandler*(parser: PParser, attdecl: TAttlistDeclHandler){.
+    cdecl, importc: "XML_SetAttlistDeclHandler", dynlib: expatDll.}
+# The XML declaration handler is called for *both* XML declarations
+#   and text declarations. The way to distinguish is that the version
+#   parameter will be NULL for text declarations. The encoding
+#   parameter may be NULL for XML declarations. The standalone
+#   parameter will be -1, 0, or 1 indicating respectively that there
+#   was no standalone parameter in the declaration, that it was given
+#   as no, or that it was given as yes.
+#
+
+type 
+  TXmlDeclHandler* = proc (userData: pointer, version: cstring, 
+                           encoding: cstring, standalone: cint){.cdecl.}
+
+proc setXmlDeclHandler*(parser: PParser, xmldecl: TXmlDeclHandler){.cdecl, 
+    importc: "XML_SetXmlDeclHandler", dynlib: expatDll.}
+type 
+  TMemory_Handling_Suite*{.pure, final.} = object 
+    mallocFcn*: proc (size: int): pointer{.cdecl.}
+    reallocFcn*: proc (p: pointer, size: int): pointer{.cdecl.}
+    freeFcn*: proc (p: pointer){.cdecl.}
+
+
+# Constructs a new parser; encoding is the encoding specified by the
+#   external protocol or NULL if there is none specified.
+#
+
+proc parserCreate*(encoding: cstring): PParser{.cdecl, 
+    importc: "XML_ParserCreate", dynlib: expatDll.}
+# Constructs a new parser and namespace processor.  Element type
+#   names and attribute names that belong to a namespace will be
+#   expanded; unprefixed attribute names are never expanded; unprefixed
+#   element type names are expanded only if there is a default
+#   namespace. The expanded name is the concatenation of the namespace
+#   URI, the namespace separator character, and the local part of the
+#   name.  If the namespace separator is '\0' then the namespace URI
+#   and the local part will be concatenated without any separator.
+#   It is a programming error to use the separator '\0' with namespace
+#   triplets (see XML_SetReturnNSTriplet).
+#
+
+proc parserCreateNS*(encoding: cstring, namespaceSeparator: char): PParser{.
+    cdecl, importc: "XML_ParserCreateNS", dynlib: expatDll.}
+# Constructs a new parser using the memory management suite referred to
+#   by memsuite. If memsuite is NULL, then use the standard library memory
+#   suite. If namespaceSeparator is non-NULL it creates a parser with
+#   namespace processing as described above. The character pointed at
+#   will serve as the namespace separator.
+#
+#   All further memory operations used for the created parser will come from
+#   the given suite.
+#
+
+proc parserCreateMM*(encoding: cstring, memsuite: ptr TMemoryHandlingSuite, 
+                      namespaceSeparator: cstring): PParser{.cdecl, 
+    importc: "XML_ParserCreate_MM", dynlib: expatDll.}
+# Prepare a parser object to be re-used.  This is particularly
+#   valuable when memory allocation overhead is disproportionatly high,
+#   such as when a large number of small documnents need to be parsed.
+#   All handlers are cleared from the parser, except for the
+#   unknownEncodingHandler. The parser's external state is re-initialized
+#   except for the values of ns and ns_triplets.
+#
+#   Added in Expat 1.95.3.
+#
+
+proc parserReset*(parser: PParser, encoding: cstring): bool{.cdecl, 
+    importc: "XML_ParserReset", dynlib: expatDll.}
+# atts is array of name/value pairs, terminated by 0;
+#   names and values are 0 terminated.
+#
+
+type 
+  TStartElementHandler* = proc (userData: pointer, name: cstring, 
+                                atts: cstringArray){.cdecl.}
+  TEndElementHandler* = proc (userData: pointer, name: cstring){.cdecl.}
+
+# s is not 0 terminated. 
+
+type 
+  TCharacterDataHandler* = proc (userData: pointer, s: cstring, len: cint){.
+      cdecl.}
+
+# target and data are 0 terminated 
+
+type 
+  TProcessingInstructionHandler* = proc (userData: pointer, target: cstring, 
+      data: cstring){.cdecl.}
+
+# data is 0 terminated 
+
+type 
+  TCommentHandler* = proc (userData: pointer, data: cstring){.cdecl.}
+  TStartCdataSectionHandler* = proc (userData: pointer){.cdecl.}
+  TEndCdataSectionHandler* = proc (userData: pointer){.cdecl.}
+
+# This is called for any characters in the XML document for which
+#   there is no applicable handler.  This includes both characters that
+#   are part of markup which is of a kind that is not reported
+#   (comments, markup declarations), or characters that are part of a
+#   construct which could be reported but for which no handler has been
+#   supplied. The characters are passed exactly as they were in the XML
+#   document except that they will be encoded in UTF-8 or UTF-16.
+#   Line boundaries are not normalized. Note that a byte order mark
+#   character is not passed to the default handler. There are no
+#   guarantees about how characters are divided between calls to the
+#   default handler: for example, a comment might be split between
+#   multiple calls.
+#
+
+type 
+  TDefaultHandler* = proc (userData: pointer, s: cstring, len: cint){.cdecl.}
+
+# This is called for the start of the DOCTYPE declaration, before
+#   any DTD or internal subset is parsed.
+#
+
+type 
+  TStartDoctypeDeclHandler* = proc (userData: pointer, doctypeName: cstring, 
+                                    sysid: cstring, pubid: cstring, 
+                                    hasInternalSubset: cint){.cdecl.}
+
+# This is called for the start of the DOCTYPE declaration when the
+#   closing > is encountered, but after processing any external
+#   subset.
+#
+
+type 
+  TEndDoctypeDeclHandler* = proc (userData: pointer){.cdecl.}
+
+# This is called for entity declarations. The is_parameter_entity
+#   argument will be non-zero if the entity is a parameter entity, zero
+#   otherwise.
+#
+#   For internal entities (<!ENTITY foo "bar">), value will
+#   be non-NULL and systemId, publicID, and notationName will be NULL.
+#   The value string is NOT nul-terminated; the length is provided in
+#   the value_length argument. Since it is legal to have zero-length
+#   values, do not use this argument to test for internal entities.
+#
+#   For external entities, value will be NULL and systemId will be
+#   non-NULL. The publicId argument will be NULL unless a public
+#   identifier was provided. The notationName argument will have a
+#   non-NULL value only for unparsed entity declarations.
+#
+#   Note that is_parameter_entity can't be changed to XML_Bool, since
+#   that would break binary compatibility.
+#
+
+type 
+  TEntityDeclHandler* = proc (userData: pointer, entityName: cstring, 
+                              isParameterEntity: cint, value: cstring, 
+                              valueLength: cint, base: cstring, 
+                              systemId: cstring, publicId: cstring, 
+                              notationName: cstring){.cdecl.}
+
+proc setEntityDeclHandler*(parser: PParser, handler: TEntityDeclHandler){.cdecl, 
+    importc: "XML_SetEntityDeclHandler", dynlib: expatDll.}
+# OBSOLETE -- OBSOLETE -- OBSOLETE
+#   This handler has been superceded by the EntityDeclHandler above.
+#   It is provided here for backward compatibility.
+#
+#   This is called for a declaration of an unparsed (NDATA) entity.
+#   The base argument is whatever was set by XML_SetBase. The
+#   entityName, systemId and notationName arguments will never be
+#   NULL. The other arguments may be.
+#
+
+type 
+  TUnparsedEntityDeclHandler* = proc (userData: pointer, entityName: cstring, 
+                                      base: cstring, systemId: cstring, 
+                                      publicId, notationName: cstring){.
+      cdecl.}
+
+# This is called for a declaration of notation.  The base argument is
+#   whatever was set by XML_SetBase. The notationName will never be
+#   NULL.  The other arguments can be.
+#
+
+type 
+  TNotationDeclHandler* = proc (userData: pointer, notationName: cstring, 
+                                base: cstring, systemId: cstring, 
+                                publicId: cstring){.cdecl.}
+
+# When namespace processing is enabled, these are called once for
+#   each namespace declaration. The call to the start and end element
+#   handlers occur between the calls to the start and end namespace
+#   declaration handlers. For an xmlns attribute, prefix will be
+#   NULL.  For an xmlns="" attribute, uri will be NULL.
+#
+
+type 
+  TStartNamespaceDeclHandler* = proc (userData: pointer, prefix: cstring, 
+                                      uri: cstring){.cdecl.}
+  TEndNamespaceDeclHandler* = proc (userData: pointer, prefix: cstring){.cdecl.}
+
+# This is called if the document is not standalone, that is, it has an
+#   external subset or a reference to a parameter entity, but does not
+#   have standalone="yes". If this handler returns XML_STATUS_ERROR,
+#   then processing will not continue, and the parser will return a
+#   XML_ERROR_NOT_STANDALONE error.
+#   If parameter entity parsing is enabled, then in addition to the
+#   conditions above this handler will only be called if the referenced
+#   entity was actually read.
+#
+
+type 
+  TNotStandaloneHandler* = proc (userData: pointer): cint{.cdecl.}
+
+# This is called for a reference to an external parsed general
+#   entity.  The referenced entity is not automatically parsed.  The
+#   application can parse it immediately or later using
+#   XML_ExternalEntityParserCreate.
+#
+#   The parser argument is the parser parsing the entity containing the
+#   reference; it can be passed as the parser argument to
+#   XML_ExternalEntityParserCreate.  The systemId argument is the
+#   system identifier as specified in the entity declaration; it will
+#   not be NULL.
+#
+#   The base argument is the system identifier that should be used as
+#   the base for resolving systemId if systemId was relative; this is
+#   set by XML_SetBase; it may be NULL.
+#
+#   The publicId argument is the public identifier as specified in the
+#   entity declaration, or NULL if none was specified; the whitespace
+#   in the public identifier will have been normalized as required by
+#   the XML spec.
+#
+#   The context argument specifies the parsing context in the format
+#   expected by the context argument to XML_ExternalEntityParserCreate;
+#   context is valid only until the handler returns, so if the
+#   referenced entity is to be parsed later, it must be copied.
+#   context is NULL only when the entity is a parameter entity.
+#
+#   The handler should return XML_STATUS_ERROR if processing should not
+#   continue because of a fatal error in the handling of the external
+#   entity.  In this case the calling parser will return an
+#   XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
+#
+#   Note that unlike other handlers the first argument is the parser,
+#   not userData.
+#
+
+type 
+  TExternalEntityRefHandler* = proc (parser: PParser, context: cstring, 
+                                     base: cstring, systemId: cstring, 
+                                     publicId: cstring): cint{.cdecl.}
+
+# This is called in two situations:
+#   1) An entity reference is encountered for which no declaration
+#      has been read *and* this is not an error.
+#   2) An internal entity reference is read, but not expanded, because
+#      XML_SetDefaultHandler has been called.
+#   Note: skipped parameter entities in declarations and skipped general
+#         entities in attribute values cannot be reported, because
+#         the event would be out of sync with the reporting of the
+#         declarations or attribute values
+#
+
+type 
+  TSkippedEntityHandler* = proc (userData: pointer, entityName: cstring, 
+                                 isParameterEntity: cint){.cdecl.}
+
+# This structure is filled in by the XML_UnknownEncodingHandler to
+#   provide information to the parser about encodings that are unknown
+#   to the parser.
+#
+#   The map[b] member gives information about byte sequences whose
+#   first byte is b.
+#
+#   If map[b] is c where c is >= 0, then b by itself encodes the
+#   Unicode scalar value c.
+#
+#   If map[b] is -1, then the byte sequence is malformed.
+#
+#   If map[b] is -n, where n >= 2, then b is the first byte of an
+#   n-byte sequence that encodes a single Unicode scalar value.
+#
+#   The data member will be passed as the first argument to the convert
+#   function.
+#
+#   The convert function is used to convert multibyte sequences; s will
+#   point to a n-byte sequence where map[(unsigned char)*s] == -n.  The
+#   convert function must return the Unicode scalar value represented
+#   by this byte sequence or -1 if the byte sequence is malformed.
+#
+#   The convert function may be NULL if the encoding is a single-byte
+#   encoding, that is if map[b] >= -1 for all bytes b.
+#
+#   When the parser is finished with the encoding, then if release is
+#   not NULL, it will call release passing it the data member; once
+#   release has been called, the convert function will not be called
+#   again.
+#
+#   Expat places certain restrictions on the encodings that are supported
+#   using this mechanism.
+#
+#   1. Every ASCII character that can appear in a well-formed XML document,
+#      other than the characters
+#
+#      $@\^`{}~
+#
+#      must be represented by a single byte, and that byte must be the
+#      same byte that represents that character in ASCII.
+#
+#   2. No character may require more than 4 bytes to encode.
+#
+#   3. All characters encoded must have Unicode scalar values <=
+#      0xFFFF, (i.e., characters that would be encoded by surrogates in
+#      UTF-16 are  not allowed).  Note that this restriction doesn't
+#      apply to the built-in support for UTF-8 and UTF-16.
+#
+#   4. No Unicode character may be encoded by more than one distinct
+#      sequence of bytes.
+#
+
+type 
+  TEncoding*{.pure, final.} = object 
+    map*: array[0..256 - 1, cint]
+    data*: pointer
+    convert*: proc (data: pointer, s: cstring): cint{.cdecl.}
+    release*: proc (data: pointer){.cdecl.}
+
+
+# This is called for an encoding that is unknown to the parser.
+#
+#   The encodingHandlerData argument is that which was passed as the
+#   second argument to XML_SetUnknownEncodingHandler.
+#
+#   The name argument gives the name of the encoding as specified in
+#   the encoding declaration.
+#
+#   If the callback can provide information about the encoding, it must
+#   fill in the XML_Encoding structure, and return XML_STATUS_OK.
+#   Otherwise it must return XML_STATUS_ERROR.
+#
+#   If info does not describe a suitable encoding, then the parser will
+#   return an XML_UNKNOWN_ENCODING error.
+#
+
+type 
+  TUnknownEncodingHandler* = proc (encodingHandlerData: pointer, name: cstring, 
+                                   info: ptr TEncoding): cint{.cdecl.}
+
+proc setElementHandler*(parser: PParser, start: TStartElementHandler, 
+                        endHandler: TEndElementHandler){.cdecl, 
+    importc: "XML_SetElementHandler", dynlib: expatDll.}
+proc setStartElementHandler*(parser: PParser, handler: TStartElementHandler){.
+    cdecl, importc: "XML_SetStartElementHandler", dynlib: expatDll.}
+proc setEndElementHandler*(parser: PParser, handler: TEndElementHandler){.cdecl, 
+    importc: "XML_SetEndElementHandler", dynlib: expatDll.}
+proc setCharacterDataHandler*(parser: PParser, handler: TCharacterDataHandler){.
+    cdecl, importc: "XML_SetCharacterDataHandler", dynlib: expatDll.}
+proc setProcessingInstructionHandler*(parser: PParser, 
+                                      handler: TProcessingInstructionHandler){.
+    cdecl, importc: "XML_SetProcessingInstructionHandler", dynlib: expatDll.}
+proc setCommentHandler*(parser: PParser, handler: TCommentHandler){.cdecl, 
+    importc: "XML_SetCommentHandler", dynlib: expatDll.}
+proc setCdataSectionHandler*(parser: PParser, start: TStartCdataSectionHandler, 
+                             endHandler: TEndCdataSectionHandler){.cdecl, 
+    importc: "XML_SetCdataSectionHandler", dynlib: expatDll.}
+proc setStartCdataSectionHandler*(parser: PParser, 
+                                  start: TStartCdataSectionHandler){.cdecl, 
+    importc: "XML_SetStartCdataSectionHandler", dynlib: expatDll.}
+proc setEndCdataSectionHandler*(parser: PParser, 
+                                endHandler: TEndCdataSectionHandler){.cdecl, 
+    importc: "XML_SetEndCdataSectionHandler", dynlib: expatDll.}
+# This sets the default handler and also inhibits expansion of
+#   internal entities. These entity references will be passed to the
+#   default handler, or to the skipped entity handler, if one is set.
+#
+
+proc setDefaultHandler*(parser: PParser, handler: TDefaultHandler){.cdecl, 
+    importc: "XML_SetDefaultHandler", dynlib: expatDll.}
+# This sets the default handler but does not inhibit expansion of
+#   internal entities.  The entity reference will not be passed to the
+#   default handler.
+#
+
+proc setDefaultHandlerExpand*(parser: PParser, handler: TDefaultHandler){.cdecl, 
+    importc: "XML_SetDefaultHandlerExpand", dynlib: expatDll.}
+proc setDoctypeDeclHandler*(parser: PParser, start: TStartDoctypeDeclHandler, 
+                            endHandler: TEndDoctypeDeclHandler){.cdecl, 
+    importc: "XML_SetDoctypeDeclHandler", dynlib: expatDll.}
+proc setStartDoctypeDeclHandler*(parser: PParser, 
+                                 start: TStartDoctypeDeclHandler){.cdecl, 
+    importc: "XML_SetStartDoctypeDeclHandler", dynlib: expatDll.}
+proc setEndDoctypeDeclHandler*(parser: PParser, 
+                               endHandler: TEndDoctypeDeclHandler){.cdecl, 
+    importc: "XML_SetEndDoctypeDeclHandler", dynlib: expatDll.}
+proc setUnparsedEntityDeclHandler*(parser: PParser, 
+                                   handler: TUnparsedEntityDeclHandler){.cdecl, 
+    importc: "XML_SetUnparsedEntityDeclHandler", dynlib: expatDll.}
+proc setNotationDeclHandler*(parser: PParser, handler: TNotationDeclHandler){.
+    cdecl, importc: "XML_SetNotationDeclHandler", dynlib: expatDll.}
+proc setNamespaceDeclHandler*(parser: PParser, 
+                              start: TStartNamespaceDeclHandler, 
+                              endHandler: TEndNamespaceDeclHandler){.cdecl, 
+    importc: "XML_SetNamespaceDeclHandler", dynlib: expatDll.}
+proc setStartNamespaceDeclHandler*(parser: PParser, 
+                                   start: TStartNamespaceDeclHandler){.cdecl, 
+    importc: "XML_SetStartNamespaceDeclHandler", dynlib: expatDll.}
+proc setEndNamespaceDeclHandler*(parser: PParser, 
+                                 endHandler: TEndNamespaceDeclHandler){.cdecl, 
+    importc: "XML_SetEndNamespaceDeclHandler", dynlib: expatDll.}
+proc setNotStandaloneHandler*(parser: PParser, handler: TNotStandaloneHandler){.
+    cdecl, importc: "XML_SetNotStandaloneHandler", dynlib: expatDll.}
+proc setExternalEntityRefHandler*(parser: PParser, 
+                                  handler: TExternalEntityRefHandler){.cdecl, 
+    importc: "XML_SetExternalEntityRefHandler", dynlib: expatDll.}
+# If a non-NULL value for arg is specified here, then it will be
+#   passed as the first argument to the external entity ref handler
+#   instead of the parser object.
+#
+
+proc setExternalEntityRefHandlerArg*(parser: PParser, arg: pointer){.cdecl, 
+    importc: "XML_SetExternalEntityRefHandlerArg", dynlib: expatDll.}
+proc setSkippedEntityHandler*(parser: PParser, handler: TSkippedEntityHandler){.
+    cdecl, importc: "XML_SetSkippedEntityHandler", dynlib: expatDll.}
+proc setUnknownEncodingHandler*(parser: PParser, 
+                                handler: TUnknownEncodingHandler, 
+                                encodingHandlerData: pointer){.cdecl, 
+    importc: "XML_SetUnknownEncodingHandler", dynlib: expatDll.}
+# This can be called within a handler for a start element, end
+#   element, processing instruction or character data.  It causes the
+#   corresponding markup to be passed to the default handler.
+#
+
+proc defaultCurrent*(parser: PParser){.cdecl, importc: "XML_DefaultCurrent", 
+                                       dynlib: expatDll.}
+# If do_nst is non-zero, and namespace processing is in effect, and
+#   a name has a prefix (i.e. an explicit namespace qualifier) then
+#   that name is returned as a triplet in a single string separated by
+#   the separator character specified when the parser was created: URI
+#   + sep + local_name + sep + prefix.
+#
+#   If do_nst is zero, then namespace information is returned in the
+#   default manner (URI + sep + local_name) whether or not the name
+#   has a prefix.
+#
+#   Note: Calling XML_SetReturnNSTriplet after XML_Parse or
+#     XML_ParseBuffer has no effect.
+#
+
+proc setReturnNSTriplet*(parser: PParser, doNst: cint){.cdecl, 
+    importc: "XML_SetReturnNSTriplet", dynlib: expatDll.}
+# This value is passed as the userData argument to callbacks. 
+
+proc setUserData*(parser: PParser, userData: pointer){.cdecl, 
+    importc: "XML_SetUserData", dynlib: expatDll.}
+# Returns the last value set by XML_SetUserData or NULL. 
+
+template getUserData*(parser: expr): expr = 
+  (cast[ptr pointer]((parser))[] )
+
+# This is equivalent to supplying an encoding argument to
+#   XML_ParserCreate. On success XML_SetEncoding returns non-zero,
+#   zero otherwise.
+#   Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer
+#     has no effect and returns XML_STATUS_ERROR.
+#
+
+proc setEncoding*(parser: PParser, encoding: cstring): TStatus{.cdecl, 
+    importc: "XML_SetEncoding", dynlib: expatDll.}
+# If this function is called, then the parser will be passed as the
+#   first argument to callbacks instead of userData.  The userData will
+#   still be accessible using XML_GetUserData.
+#
+
+proc useParserAsHandlerArg*(parser: PParser){.cdecl, 
+    importc: "XML_UseParserAsHandlerArg", dynlib: expatDll.}
+# If useDTD == XML_TRUE is passed to this function, then the parser
+#   will assume that there is an external subset, even if none is
+#   specified in the document. In such a case the parser will call the
+#   externalEntityRefHandler with a value of NULL for the systemId
+#   argument (the publicId and context arguments will be NULL as well).
+#   Note: For the purpose of checking WFC: Entity Declared, passing
+#     useDTD == XML_TRUE will make the parser behave as if the document
+#     had a DTD with an external subset.
+#   Note: If this function is called, then this must be done before
+#     the first call to XML_Parse or XML_ParseBuffer, since it will
+#     have no effect after that.  Returns
+#     XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING.
+#   Note: If the document does not have a DOCTYPE declaration at all,
+#     then startDoctypeDeclHandler and endDoctypeDeclHandler will not
+#     be called, despite an external subset being parsed.
+#   Note: If XML_DTD is not defined when Expat is compiled, returns
+#     XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+#
+
+proc useForeignDTD*(parser: PParser, useDTD: bool): TError{.cdecl, 
+    importc: "XML_UseForeignDTD", dynlib: expatDll.}
+# Sets the base to be used for resolving relative URIs in system
+#   identifiers in declarations.  Resolving relative identifiers is
+#   left to the application: this value will be passed through as the
+#   base argument to the XML_ExternalEntityRefHandler,
+#   XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base
+#   argument will be copied.  Returns XML_STATUS_ERROR if out of memory,
+#   XML_STATUS_OK otherwise.
+#
+
+proc setBase*(parser: PParser, base: cstring): TStatus{.cdecl, 
+    importc: "XML_SetBase", dynlib: expatDll.}
+proc getBase*(parser: PParser): cstring{.cdecl, importc: "XML_GetBase", 
+    dynlib: expatDll.}
+# Returns the number of the attribute/value pairs passed in last call
+#   to the XML_StartElementHandler that were specified in the start-tag
+#   rather than defaulted. Each attribute/value pair counts as 2; thus
+#   this correspondds to an index into the atts array passed to the
+#   XML_StartElementHandler.
+#
+
+proc getSpecifiedAttributeCount*(parser: PParser): cint{.cdecl, 
+    importc: "XML_GetSpecifiedAttributeCount", dynlib: expatDll.}
+# Returns the index of the ID attribute passed in the last call to
+#   XML_StartElementHandler, or -1 if there is no ID attribute.  Each
+#   attribute/value pair counts as 2; thus this correspondds to an
+#   index into the atts array passed to the XML_StartElementHandler.
+#
+
+proc getIdAttributeIndex*(parser: PParser): cint{.cdecl, 
+    importc: "XML_GetIdAttributeIndex", dynlib: expatDll.}
+# Parses some input. Returns XML_STATUS_ERROR if a fatal error is
+#   detected.  The last call to XML_Parse must have isFinal true; len
+#   may be zero for this call (or any other).
+#
+#   Though the return values for these functions has always been
+#   described as a Boolean value, the implementation, at least for the
+#   1.95.x series, has always returned exactly one of the XML_Status
+#   values.
+#
+
+proc parse*(parser: PParser, s: cstring, len: cint, isFinal: cint): TStatus{.
+    cdecl, importc: "XML_Parse", dynlib: expatDll.}
+proc getBuffer*(parser: PParser, len: cint): pointer{.cdecl, 
+    importc: "XML_GetBuffer", dynlib: expatDll.}
+proc parseBuffer*(parser: PParser, len: cint, isFinal: cint): TStatus{.cdecl, 
+    importc: "XML_ParseBuffer", dynlib: expatDll.}
+# Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
+#   Must be called from within a call-back handler, except when aborting
+#   (resumable = 0) an already suspended parser. Some call-backs may
+#   still follow because they would otherwise get lost. Examples:
+#   - endElementHandler() for empty elements when stopped in
+#     startElementHandler(), 
+#   - endNameSpaceDeclHandler() when stopped in endElementHandler(), 
+#   and possibly others.
+#
+#   Can be called from most handlers, including DTD related call-backs,
+#   except when parsing an external parameter entity and resumable != 0.
+#   Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
+#   Possible error codes: 
+#   - XML_ERROR_SUSPENDED: when suspending an already suspended parser.
+#   - XML_ERROR_FINISHED: when the parser has already finished.
+#   - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
+#
+#   When resumable != 0 (true) then parsing is suspended, that is, 
+#   XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. 
+#   Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
+#   return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
+#
+#   Note*:
+#   This will be applied to the current parser instance only, that is, if
+#   there is a parent parser then it will continue parsing when the
+#   externalEntityRefHandler() returns. It is up to the implementation of
+#   the externalEntityRefHandler() to call XML_StopParser() on the parent
+#   parser (recursively), if one wants to stop parsing altogether.
+#
+#   When suspended, parsing can be resumed by calling XML_ResumeParser(). 
+#
+
+proc stopParser*(parser: PParser, resumable: bool): TStatus{.cdecl, 
+    importc: "XML_StopParser", dynlib: expatDll.}
+# Resumes parsing after it has been suspended with XML_StopParser().
+#   Must not be called from within a handler call-back. Returns same
+#   status codes as XML_Parse() or XML_ParseBuffer().
+#   Additional error code XML_ERROR_NOT_SUSPENDED possible.   
+#
+#   Note*:
+#   This must be called on the most deeply nested child parser instance
+#   first, and on its parent parser only after the child parser has finished,
+#   to be applied recursively until the document entity's parser is restarted.
+#   That is, the parent parser will not resume by itself and it is up to the
+#   application to call XML_ResumeParser() on it at the appropriate moment.
+#
+
+proc resumeParser*(parser: PParser): TStatus{.cdecl, 
+    importc: "XML_ResumeParser", dynlib: expatDll.}
+type 
+  TParsing* = enum 
+    INITIALIZED, PARSING, FINISHED, SUSPENDED
+  TParsingStatus*{.pure, final.} = object 
+    parsing*: TParsing
+    finalBuffer*: bool
+
+
+# Returns status of parser with respect to being initialized, parsing,
+#   finished, or suspended and processing the final buffer.
+#   XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus,
+#   XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
+#
+
+proc getParsingStatus*(parser: PParser, status: ptr TParsingStatus){.cdecl, 
+    importc: "XML_GetParsingStatus", dynlib: expatDll.}
+# Creates an XML_Parser object that can parse an external general
+#   entity; context is a '\0'-terminated string specifying the parse
+#   context; encoding is a '\0'-terminated string giving the name of
+#   the externally specified encoding, or NULL if there is no
+#   externally specified encoding.  The context string consists of a
+#   sequence of tokens separated by formfeeds (\f); a token consisting
+#   of a name specifies that the general entity of the name is open; a
+#   token of the form prefix=uri specifies the namespace for a
+#   particular prefix; a token of the form =uri specifies the default
+#   namespace.  This can be called at any point after the first call to
+#   an ExternalEntityRefHandler so longer as the parser has not yet
+#   been freed.  The new parser is completely independent and may
+#   safely be used in a separate thread.  The handlers and userData are
+#   initialized from the parser argument.  Returns NULL if out of memory.
+#   Otherwise returns a new XML_Parser object.
+#
+
+proc externalEntityParserCreate*(parser: PParser, context: cstring, 
+                                 encoding: cstring): PParser{.cdecl, 
+    importc: "XML_ExternalEntityParserCreate", dynlib: expatDll.}
+type 
+  TParamEntityParsing* = enum 
+    PARAM_ENTITY_PARSING_NEVER, PARAM_ENTITY_PARSING_UNLESS_STANDALONE, 
+    PARAM_ENTITY_PARSING_ALWAYS
+
+# Controls parsing of parameter entities (including the external DTD
+#   subset). If parsing of parameter entities is enabled, then
+#   references to external parameter entities (including the external
+#   DTD subset) will be passed to the handler set with
+#   XML_SetExternalEntityRefHandler.  The context passed will be 0.
+#
+#   Unlike external general entities, external parameter entities can
+#   only be parsed synchronously.  If the external parameter entity is
+#   to be parsed, it must be parsed during the call to the external
+#   entity ref handler: the complete sequence of
+#   XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
+#   XML_ParserFree calls must be made during this call.  After
+#   XML_ExternalEntityParserCreate has been called to create the parser
+#   for the external parameter entity (context must be 0 for this
+#   call), it is illegal to make any calls on the old parser until
+#   XML_ParserFree has been called on the newly created parser.
+#   If the library has been compiled without support for parameter
+#   entity parsing (ie without XML_DTD being defined), then
+#   XML_SetParamEntityParsing will return 0 if parsing of parameter
+#   entities is requested; otherwise it will return non-zero.
+#   Note: If XML_SetParamEntityParsing is called after XML_Parse or
+#      XML_ParseBuffer, then it has no effect and will always return 0.
+#
+
+proc setParamEntityParsing*(parser: PParser, parsing: TParamEntityParsing): cint{.
+    cdecl, importc: "XML_SetParamEntityParsing", dynlib: expatDll.}
+# If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
+#   XML_GetErrorCode returns information about the error.
+#
+
+proc getErrorCode*(parser: PParser): TError{.cdecl, importc: "XML_GetErrorCode", 
+    dynlib: expatDll.}
+# These functions return information about the current parse
+#   location.  They may be called from any callback called to report
+#   some parse event; in this case the location is the location of the
+#   first of the sequence of characters that generated the event.  When
+#   called from callbacks generated by declarations in the document
+#   prologue, the location identified isn't as neatly defined, but will
+#   be within the relevant markup.  When called outside of the callback
+#   functions, the position indicated will be just past the last parse
+#   event (regardless of whether there was an associated callback).
+#   
+#   They may also be called after returning from a call to XML_Parse
+#   or XML_ParseBuffer.  If the return value is XML_STATUS_ERROR then
+#   the location is the location of the character at which the error
+#   was detected; otherwise the location is the location of the last
+#   parse event, as described above.
+#
+
+proc getCurrentLineNumber*(parser: PParser): int{.cdecl, 
+    importc: "XML_GetCurrentLineNumber", dynlib: expatDll.}
+proc getCurrentColumnNumber*(parser: PParser): int{.cdecl, 
+    importc: "XML_GetCurrentColumnNumber", dynlib: expatDll.}
+proc getCurrentByteIndex*(parser: PParser): int{.cdecl, 
+    importc: "XML_GetCurrentByteIndex", dynlib: expatDll.}
+# Return the number of bytes in the current event.
+#   Returns 0 if the event is in an internal entity.
+#
+
+proc getCurrentByteCount*(parser: PParser): cint{.cdecl, 
+    importc: "XML_GetCurrentByteCount", dynlib: expatDll.}
+# If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+#   the integer pointed to by offset to the offset within this buffer
+#   of the current parse position, and sets the integer pointed to by size
+#   to the size of this buffer (the number of input bytes). Otherwise
+#   returns a NULL pointer. Also returns a NULL pointer if a parse isn't
+#   active.
+#
+#   NOTE: The character pointer returned should not be used outside
+#   the handler that makes the call.
+#
+
+proc getInputContext*(parser: PParser, offset: ptr cint, size: ptr cint): cstring{.
+    cdecl, importc: "XML_GetInputContext", dynlib: expatDll.}
+# Frees the content model passed to the element declaration handler 
+
+proc freeContentModel*(parser: PParser, model: ptr TContent){.cdecl, 
+    importc: "XML_FreeContentModel", dynlib: expatDll.}
+# Exposing the memory handling functions used in Expat 
+
+proc memMalloc*(parser: PParser, size: int): pointer{.cdecl, 
+    importc: "XML_MemMalloc", dynlib: expatDll.}
+proc memRealloc*(parser: PParser, p: pointer, size: int): pointer{.cdecl, 
+    importc: "XML_MemRealloc", dynlib: expatDll.}
+proc memFree*(parser: PParser, p: pointer){.cdecl, importc: "XML_MemFree", 
+    dynlib: expatDll.}
+# Frees memory used by the parser. 
+
+proc parserFree*(parser: PParser){.cdecl, importc: "XML_ParserFree", 
+                                   dynlib: expatDll.}
+# Returns a string describing the error. 
+
+proc errorString*(code: TError): cstring{.cdecl, importc: "XML_ErrorString", 
+    dynlib: expatDll.}
+# Return a string containing the version number of this expat 
+
+proc expatVersion*(): cstring{.cdecl, importc: "XML_ExpatVersion", 
+                               dynlib: expatDll.}
+type 
+  TExpat_Version*{.pure, final.} = object 
+    major*: cint
+    minor*: cint
+    micro*: cint
+
+
+# Return an XML_Expat_Version structure containing numeric version
+#   number information for this version of expat.
+#
+
+proc expatVersionInfo*(): TExpatVersion{.cdecl, 
+    importc: "XML_ExpatVersionInfo", dynlib: expatDll.}
+# Added in Expat 1.95.5. 
+
+type 
+  TFeatureEnum* = enum 
+    FEATURE_END = 0, FEATURE_UNICODE, FEATURE_UNICODE_WCHAR_T, FEATURE_DTD, 
+    FEATURE_CONTEXT_BYTES, FEATURE_MIN_SIZE, FEATURE_SIZEOF_XML_CHAR, 
+    FEATURE_SIZEOF_XML_LCHAR, FEATURE_NS, FEATURE_LARGE_SIZE # Additional features must be added to the end of this enum. 
+  TFeature*{.pure, final.} = object 
+    feature*: TFeatureEnum
+    name*: cstring
+    value*: int
+
+
+proc getFeatureList*(): ptr TFeature{.cdecl, importc: "XML_GetFeatureList", 
+                                      dynlib: expatDll.}
+# Expat follows the GNU/Linux convention of odd number minor version for
+#   beta/development releases and even number minor version for stable
+#   releases. Micro is bumped with each release, and set to 0 with each
+#   change to major or minor version.
+#
+
+const 
+  MAJOR_VERSION* = 2
+  MINOR_VERSION* = 0
+  MICRO_VERSION* = 1
diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim
new file mode 100644
index 000000000..93e14cccd
--- /dev/null
+++ b/lib/wrappers/iup.nim
@@ -0,0 +1,949 @@
+#
+#    Binding for the IUP GUI toolkit
+#       (c) 2012 Andreas Rumpf
+#    C header files translated by hand
+#    Licence of IUP follows:
+
+
+# ****************************************************************************
+# Copyright (C) 1994-2009 Tecgraf, PUC-Rio.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+# ****************************************************************************
+
+{.deadCodeElim: on.}
+
+when defined(windows):
+  const dllname = "iup(|30|27|26|25|24).dll"
+elif defined(macosx):
+  const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).dylib"
+else:
+  const dllname = "libiup(|3.0|2.7|2.6|2.5|2.4).so(|.1)"
+
+const
+  IUP_NAME* = "IUP - Portable User Interface"
+  IUP_COPYRIGHT* = "Copyright (C) 1994-2009 Tecgraf, PUC-Rio."
+  IUP_DESCRIPTION* = "Portable toolkit for building graphical user interfaces."
+  constIUP_VERSION* = "3.0"
+  constIUP_VERSION_NUMBER* = 300000
+  constIUP_VERSION_DATE* = "2009/07/18"
+
+type
+  Ihandle = object
+  PIhandle* = ptr Ihandle
+
+  Icallback* = proc (arg: PIhandle): cint {.cdecl.}
+
+#                      pre-defineded dialogs
+proc fileDlg*: PIhandle {.importc: "IupFileDlg", dynlib: dllname, cdecl.}
+proc messageDlg*: PIhandle {.importc: "IupMessageDlg", dynlib: dllname, cdecl.}
+proc colorDlg*: PIhandle {.importc: "IupColorDlg", dynlib: dllname, cdecl.}
+proc fontDlg*: PIhandle {.importc: "IupFontDlg", dynlib: dllname, cdecl.}
+
+proc getFile*(arq: cstring): cint {.
+  importc: "IupGetFile", dynlib: dllname, cdecl.}
+proc message*(title, msg: cstring) {.
+  importc: "IupMessage", dynlib: dllname, cdecl.}
+proc messagef*(title, format: cstring) {.
+  importc: "IupMessagef", dynlib: dllname, cdecl, varargs.}
+proc alarm*(title, msg, b1, b2, b3: cstring): cint {.
+  importc: "IupAlarm", dynlib: dllname, cdecl.}
+proc scanf*(format: cstring): cint {.
+  importc: "IupScanf", dynlib: dllname, cdecl, varargs.}
+proc listDialog*(theType: cint, title: cstring, size: cint,
+                 list: cstringArray, op, maxCol, maxLin: cint,
+                 marks: ptr cint): cint {.
+                 importc: "IupListDialog", dynlib: dllname, cdecl.}
+proc getText*(title, text: cstring): cint {.
+  importc: "IupGetText", dynlib: dllname, cdecl.}
+proc getColor*(x, y: cint, r, g, b: var byte): cint {.
+  importc: "IupGetColor", dynlib: dllname, cdecl.}
+
+type
+  Iparamcb* = proc (dialog: PIhandle, paramIndex: cint,
+                    userData: pointer): cint {.cdecl.}
+
+proc getParam*(title: cstring, action: Iparamcb, userData: pointer,
+               format: cstring): cint {.
+               importc: "IupGetParam", cdecl, varargs, dynlib: dllname.}
+proc getParamv*(title: cstring, action: Iparamcb, userData: pointer,
+                format: cstring, paramCount, paramExtra: cint,
+                paramData: pointer): cint {.
+                importc: "IupGetParamv", cdecl, dynlib: dllname.}
+
+
+#                      Functions
+
+proc open*(argc: ptr cint, argv: ptr cstringArray): cint {.
+  importc: "IupOpen", cdecl, dynlib: dllname.}
+proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.}
+proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.}
+
+proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname,
+                         discardable.}
+proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname,
+                         discardable.}
+proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl,
+                              dynlib: dllname, discardable.}
+proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.}
+proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.}
+
+proc update*(ih: PIhandle) {.importc: "IupUpdate", cdecl, dynlib: dllname.}
+proc updateChildren*(ih: PIhandle) {.importc: "IupUpdateChildren", cdecl, dynlib: dllname.}
+proc redraw*(ih: PIhandle, children: cint) {.importc: "IupRedraw", cdecl, dynlib: dllname.}
+proc refresh*(ih: PIhandle) {.importc: "IupRefresh", cdecl, dynlib: dllname.}
+
+proc mapFont*(iupfont: cstring): cstring {.importc: "IupMapFont", cdecl, dynlib: dllname.}
+proc unMapFont*(driverfont: cstring): cstring {.importc: "IupUnMapFont", cdecl, dynlib: dllname.}
+proc help*(url: cstring): cint {.importc: "IupHelp", cdecl, dynlib: dllname.}
+proc load*(filename: cstring): cstring {.importc: "IupLoad", cdecl, dynlib: dllname.}
+
+proc iupVersion*(): cstring {.importc: "IupVersion", cdecl, dynlib: dllname.}
+proc iupVersionDate*(): cstring {.importc: "IupVersionDate", cdecl, dynlib: dllname.}
+proc iupVersionNumber*(): cint {.importc: "IupVersionNumber", cdecl, dynlib: dllname.}
+proc setLanguage*(lng: cstring) {.importc: "IupSetLanguage", cdecl, dynlib: dllname.}
+proc getLanguage*(): cstring {.importc: "IupGetLanguage", cdecl, dynlib: dllname.}
+
+proc destroy*(ih: PIhandle) {.importc: "IupDestroy", cdecl, dynlib: dllname.}
+proc detach*(child: PIhandle) {.importc: "IupDetach", cdecl, dynlib: dllname.}
+proc append*(ih, child: PIhandle): PIhandle {.
+  importc: "IupAppend", cdecl, dynlib: dllname, discardable.}
+proc insert*(ih, refChild, child: PIhandle): PIhandle {.
+  importc: "IupInsert", cdecl, dynlib: dllname, discardable.}
+proc getChild*(ih: PIhandle, pos: cint): PIhandle {.
+  importc: "IupGetChild", cdecl, dynlib: dllname.}
+proc getChildPos*(ih, child: PIhandle): cint {.
+  importc: "IupGetChildPos", cdecl, dynlib: dllname.}
+proc getChildCount*(ih: PIhandle): cint {.
+  importc: "IupGetChildCount", cdecl, dynlib: dllname.}
+proc getNextChild*(ih, child: PIhandle): PIhandle {.
+  importc: "IupGetNextChild", cdecl, dynlib: dllname.}
+proc getBrother*(ih: PIhandle): PIhandle {.
+  importc: "IupGetBrother", cdecl, dynlib: dllname.}
+proc getParent*(ih: PIhandle): PIhandle {.
+  importc: "IupGetParent", cdecl, dynlib: dllname.}
+proc getDialog*(ih: PIhandle): PIhandle {.
+  importc: "IupGetDialog", cdecl, dynlib: dllname.}
+proc getDialogChild*(ih: PIhandle, name: cstring): PIhandle {.
+  importc: "IupGetDialogChild", cdecl, dynlib: dllname.}
+proc reparent*(ih, newParent: PIhandle): cint {.
+  importc: "IupReparent", cdecl, dynlib: dllname.}
+
+proc popup*(ih: PIhandle, x, y: cint): cint {.
+  importc: "IupPopup", cdecl, dynlib: dllname, discardable.}
+proc show*(ih: PIhandle): cint {.
+  importc: "IupShow", cdecl, dynlib: dllname, discardable.}
+proc showXY*(ih: PIhandle, x, y: cint): cint {.
+  importc: "IupShowXY", cdecl, dynlib: dllname, discardable.}
+proc hide*(ih: PIhandle): cint {.
+  importc: "IupHide", cdecl, dynlib: dllname, discardable.}
+proc map*(ih: PIhandle): cint {.
+  importc: "IupMap", cdecl, dynlib: dllname, discardable.}
+proc unmap*(ih: PIhandle) {.
+  importc: "IupUnmap", cdecl, dynlib: dllname, discardable.}
+
+proc setAttribute*(ih: PIhandle, name, value: cstring) {.
+  importc: "IupSetAttribute", cdecl, dynlib: dllname.}
+proc storeAttribute*(ih: PIhandle, name, value: cstring) {.
+  importc: "IupStoreAttribute", cdecl, dynlib: dllname.}
+proc setAttributes*(ih: PIhandle, str: cstring): PIhandle {.
+  importc: "IupSetAttributes", cdecl, dynlib: dllname.}
+proc getAttribute*(ih: PIhandle, name: cstring): cstring {.
+  importc: "IupGetAttribute", cdecl, dynlib: dllname.}
+proc getAttributes*(ih: PIhandle): cstring {.
+  importc: "IupGetAttributes", cdecl, dynlib: dllname.}
+proc getInt*(ih: PIhandle, name: cstring): cint {.
+  importc: "IupGetInt", cdecl, dynlib: dllname.}
+proc getInt2*(ih: PIhandle, name: cstring): cint {.
+  importc: "IupGetInt2", cdecl, dynlib: dllname.}
+proc getIntInt*(ih: PIhandle, name: cstring, i1, i2: var cint): cint {.
+  importc: "IupGetIntInt", cdecl, dynlib: dllname.}
+proc getFloat*(ih: PIhandle, name: cstring): cfloat {.
+  importc: "IupGetFloat", cdecl, dynlib: dllname.}
+proc setfAttribute*(ih: PIhandle, name, format: cstring) {.
+  importc: "IupSetfAttribute", cdecl, dynlib: dllname, varargs.}
+proc getAllAttributes*(ih: PIhandle, names: cstringArray, n: cint): cint {.
+  importc: "IupGetAllAttributes", cdecl, dynlib: dllname.}
+proc setAtt*(handleName: cstring, ih: PIhandle, name: cstring): PIhandle {.
+  importc: "IupSetAtt", cdecl, dynlib: dllname, varargs, discardable.}
+
+proc setGlobal*(name, value: cstring) {.
+  importc: "IupSetGlobal", cdecl, dynlib: dllname.}
+proc storeGlobal*(name, value: cstring) {.
+  importc: "IupStoreGlobal", cdecl, dynlib: dllname.}
+proc getGlobal*(name: cstring): cstring {.
+  importc: "IupGetGlobal", cdecl, dynlib: dllname.}
+
+proc setFocus*(ih: PIhandle): PIhandle {.
+  importc: "IupSetFocus", cdecl, dynlib: dllname.}
+proc getFocus*(): PIhandle {.
+  importc: "IupGetFocus", cdecl, dynlib: dllname.}
+proc previousField*(ih: PIhandle): PIhandle {.
+  importc: "IupPreviousField", cdecl, dynlib: dllname.}
+proc nextField*(ih: PIhandle): PIhandle {.
+  importc: "IupNextField", cdecl, dynlib: dllname.}
+
+proc getCallback*(ih: PIhandle, name: cstring): Icallback {.
+  importc: "IupGetCallback", cdecl, dynlib: dllname.}
+proc setCallback*(ih: PIhandle, name: cstring, fn: Icallback): Icallback {.
+  importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.}
+
+proc setCallbacks*(ih: PIhandle, name: cstring, fn: Icallback): PIhandle {.
+  importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.}
+
+proc getFunction*(name: cstring): Icallback {.
+  importc: "IupGetFunction", cdecl, dynlib: dllname.}
+proc setFunction*(name: cstring, fn: Icallback): Icallback {.
+  importc: "IupSetFunction", cdecl, dynlib: dllname, discardable.}
+proc getActionName*(): cstring {.
+  importc: "IupGetActionName", cdecl, dynlib: dllname.}
+
+proc getHandle*(name: cstring): PIhandle {.
+  importc: "IupGetHandle", cdecl, dynlib: dllname.}
+proc setHandle*(name: cstring, ih: PIhandle): PIhandle {.
+  importc: "IupSetHandle", cdecl, dynlib: dllname.}
+proc getAllNames*(names: cstringArray, n: cint): cint {.
+  importc: "IupGetAllNames", cdecl, dynlib: dllname.}
+proc getAllDialogs*(names: cstringArray, n: cint): cint {.
+  importc: "IupGetAllDialogs", cdecl, dynlib: dllname.}
+proc getName*(ih: PIhandle): cstring {.
+  importc: "IupGetName", cdecl, dynlib: dllname.}
+
+proc setAttributeHandle*(ih: PIhandle, name: cstring, ihNamed: PIhandle) {.
+  importc: "IupSetAttributeHandle", cdecl, dynlib: dllname.}
+proc getAttributeHandle*(ih: PIhandle, name: cstring): PIhandle {.
+  importc: "IupGetAttributeHandle", cdecl, dynlib: dllname.}
+
+proc getClassName*(ih: PIhandle): cstring {.
+  importc: "IupGetClassName", cdecl, dynlib: dllname.}
+proc getClassType*(ih: PIhandle): cstring {.
+  importc: "IupGetClassType", cdecl, dynlib: dllname.}
+proc getClassAttributes*(classname: cstring, names: cstringArray,
+                         n: cint): cint {.
+  importc: "IupGetClassAttributes", cdecl, dynlib: dllname.}
+proc saveClassAttributes*(ih: PIhandle) {.
+  importc: "IupSaveClassAttributes", cdecl, dynlib: dllname.}
+proc setClassDefaultAttribute*(classname, name, value: cstring) {.
+  importc: "IupSetClassDefaultAttribute", cdecl, dynlib: dllname.}
+
+proc create*(classname: cstring): PIhandle {.
+  importc: "IupCreate", cdecl, dynlib: dllname.}
+proc createv*(classname: cstring, params: pointer): PIhandle {.
+  importc: "IupCreatev", cdecl, dynlib: dllname.}
+proc createp*(classname: cstring, first: pointer): PIhandle {.
+  importc: "IupCreatep", cdecl, dynlib: dllname, varargs.}
+
+proc fill*(): PIhandle {.importc: "IupFill", cdecl, dynlib: dllname.}
+proc radio*(child: PIhandle): PIhandle {.
+  importc: "IupRadio", cdecl, dynlib: dllname.}
+proc vbox*(child: PIhandle): PIhandle {.
+  importc: "IupVbox", cdecl, dynlib: dllname, varargs.}
+proc vboxv*(children: ptr PIhandle): PIhandle {.
+  importc: "IupVboxv", cdecl, dynlib: dllname.}
+proc zbox*(child: PIhandle): PIhandle {.
+  importc: "IupZbox", cdecl, dynlib: dllname, varargs.}
+proc zboxv*(children: ptr PIhandle): PIhandle {.
+  importc: "IupZboxv", cdecl, dynlib: dllname.}
+proc hbox*(child: PIhandle): PIhandle {.
+  importc: "IupHbox", cdecl, dynlib: dllname, varargs.}
+proc hboxv*(children: ptr PIhandle): PIhandle {.
+  importc: "IupHboxv", cdecl, dynlib: dllname.}
+
+proc normalizer*(ihFirst: PIhandle): PIhandle {.
+  importc: "IupNormalizer", cdecl, dynlib: dllname, varargs.}
+proc normalizerv*(ihList: ptr PIhandle): PIhandle {.
+  importc: "IupNormalizerv", cdecl, dynlib: dllname.}
+
+proc cbox*(child: PIhandle): PIhandle {.
+  importc: "IupCbox", cdecl, dynlib: dllname, varargs.}
+proc cboxv*(children: ptr PIhandle): PIhandle {.
+  importc: "IupCboxv", cdecl, dynlib: dllname.}
+proc sbox*(child: PIhandle): PIhandle {.
+  importc: "IupSbox", cdecl, dynlib: dllname.}
+
+proc frame*(child: PIhandle): PIhandle {.
+  importc: "IupFrame", cdecl, dynlib: dllname.}
+
+proc image*(width, height: cint, pixmap: pointer): PIhandle {.
+  importc: "IupImage", cdecl, dynlib: dllname.}
+proc imageRGB*(width, height: cint, pixmap: pointer): PIhandle {.
+  importc: "IupImageRGB", cdecl, dynlib: dllname.}
+proc imageRGBA*(width, height: cint, pixmap: pointer): PIhandle {.
+  importc: "IupImageRGBA", cdecl, dynlib: dllname.}
+
+proc item*(title, action: cstring): PIhandle {.
+  importc: "IupItem", cdecl, dynlib: dllname.}
+proc submenu*(title: cstring, child: PIhandle): PIhandle {.
+  importc: "IupSubmenu", cdecl, dynlib: dllname.}
+proc separator*(): PIhandle {.
+  importc: "IupSeparator", cdecl, dynlib: dllname.}
+proc menu*(child: PIhandle): PIhandle {.
+  importc: "IupMenu", cdecl, dynlib: dllname, varargs.}
+proc menuv*(children: ptr PIhandle): PIhandle {.
+  importc: "IupMenuv", cdecl, dynlib: dllname.}
+
+proc button*(title, action: cstring): PIhandle {.
+  importc: "IupButton", cdecl, dynlib: dllname.}
+proc canvas*(action: cstring): PIhandle {.
+  importc: "IupCanvas", cdecl, dynlib: dllname.}
+proc dialog*(child: PIhandle): PIhandle {.
+  importc: "IupDialog", cdecl, dynlib: dllname.}
+proc user*(): PIhandle {.
+  importc: "IupUser", cdecl, dynlib: dllname.}
+proc label*(title: cstring): PIhandle {.
+  importc: "IupLabel", cdecl, dynlib: dllname.}
+proc list*(action: cstring): PIhandle {.
+  importc: "IupList", cdecl, dynlib: dllname.}
+proc text*(action: cstring): PIhandle {.
+  importc: "IupText", cdecl, dynlib: dllname.}
+proc multiLine*(action: cstring): PIhandle {.
+  importc: "IupMultiLine", cdecl, dynlib: dllname.}
+proc toggle*(title, action: cstring): PIhandle {.
+  importc: "IupToggle", cdecl, dynlib: dllname.}
+proc timer*(): PIhandle {.
+  importc: "IupTimer", cdecl, dynlib: dllname.}
+proc progressBar*(): PIhandle {.
+  importc: "IupProgressBar", cdecl, dynlib: dllname.}
+proc val*(theType: cstring): PIhandle {.
+  importc: "IupVal", cdecl, dynlib: dllname.}
+proc tabs*(child: PIhandle): PIhandle {.
+  importc: "IupTabs", cdecl, dynlib: dllname, varargs.}
+proc tabsv*(children: ptr PIhandle): PIhandle {.
+  importc: "IupTabsv", cdecl, dynlib: dllname.}
+proc tree*(): PIhandle {.importc: "IupTree", cdecl, dynlib: dllname.}
+
+proc spin*(): PIhandle {.importc: "IupSpin", cdecl, dynlib: dllname.}
+proc spinbox*(child: PIhandle): PIhandle {.
+  importc: "IupSpinbox", cdecl, dynlib: dllname.}
+
+# IupText utilities
+proc textConvertLinColToPos*(ih: PIhandle, lin, col: cint, pos: var cint) {.
+  importc: "IupTextConvertLinColToPos", cdecl, dynlib: dllname.}
+proc textConvertPosToLinCol*(ih: PIhandle, pos: cint, lin, col: var cint) {.
+  importc: "IupTextConvertPosToLinCol", cdecl, dynlib: dllname.}
+
+proc convertXYToPos*(ih: PIhandle, x, y: cint): cint {.
+  importc: "IupConvertXYToPos", cdecl, dynlib: dllname.}
+
+# IupTree utilities
+proc treeSetUserId*(ih: PIhandle, id: cint, userid: pointer): cint {.
+  importc: "IupTreeSetUserId", cdecl, dynlib: dllname, discardable.}
+proc treeGetUserId*(ih: PIhandle, id: cint): pointer {.
+  importc: "IupTreeGetUserId", cdecl, dynlib: dllname.}
+proc treeGetId*(ih: PIhandle, userid: pointer): cint {.
+  importc: "IupTreeGetId", cdecl, dynlib: dllname.}
+
+proc treeSetAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {.
+  importc: "IupTreeSetAttribute", cdecl, dynlib: dllname.}
+proc treeStoreAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {.
+  importc: "IupTreeStoreAttribute", cdecl, dynlib: dllname.}
+proc treeGetAttribute*(ih: PIhandle, name: cstring, id: cint): cstring {.
+  importc: "IupTreeGetAttribute", cdecl, dynlib: dllname.}
+proc treeGetInt*(ih: PIhandle, name: cstring, id: cint): cint {.
+  importc: "IupTreeGetInt", cdecl, dynlib: dllname.}
+proc treeGetFloat*(ih: PIhandle, name: cstring, id: cint): cfloat {.
+  importc: "IupTreeGetFloat", cdecl, dynlib: dllname.}
+proc treeSetfAttribute*(ih: PIhandle, name: cstring, id: cint, format: cstring) {.
+  importc: "IupTreeSetfAttribute", cdecl, dynlib: dllname, varargs.}
+
+
+#                   Common Return Values
+const
+  IUP_ERROR* = cint(1)
+  IUP_NOERROR* = cint(0)
+  IUP_OPENED* = cint(-1)
+  IUP_INVALID* = cint(-1)
+
+  # Callback Return Values
+  IUP_IGNORE* = cint(-1)
+  IUP_DEFAULT* = cint(-2)
+  IUP_CLOSE* = cint(-3)
+  IUP_CONTINUE* = cint(-4)
+
+  # IupPopup and IupShowXY Parameter Values
+  IUP_CENTER* = cint(0xFFFF)
+  IUP_LEFT* = cint(0xFFFE)
+  IUP_RIGHT* = cint(0xFFFD)
+  IUP_MOUSEPOS* = cint(0xFFFC)
+  IUP_CURRENT* = cint(0xFFFB)
+  IUP_CENTERPARENT* = cint(0xFFFA)
+  IUP_TOP* = IUP_LEFT
+  IUP_BOTTOM* = IUP_RIGHT
+
+  # SHOW_CB Callback Values
+  IUP_SHOW* = cint(0)
+  IUP_RESTORE* = cint(1)
+  IUP_MINIMIZE* = cint(2)
+  IUP_MAXIMIZE* = cint(3)
+  IUP_HIDE* = cint(4)
+
+  # SCROLL_CB Callback Values
+  IUP_SBUP* = cint(0)
+  IUP_SBDN* = cint(1)
+  IUP_SBPGUP* = cint(2)
+  IUP_SBPGDN* = cint(3)
+  IUP_SBPOSV* = cint(4)
+  IUP_SBDRAGV* = cint(5)
+  IUP_SBLEFT* = cint(6)
+  IUP_SBRIGHT* = cint(7)
+  IUP_SBPGLEFT* = cint(8)
+  IUP_SBPGRIGHT* = cint(9)
+  IUP_SBPOSH* = cint(10)
+  IUP_SBDRAGH* = cint(11)
+
+  # Mouse Button Values and Macros
+  IUP_BUTTON1* = cint(ord('1'))
+  IUP_BUTTON2* = cint(ord('2'))
+  IUP_BUTTON3* = cint(ord('3'))
+  IUP_BUTTON4* = cint(ord('4'))
+  IUP_BUTTON5* = cint(ord('5'))
+
+proc isShift*(s: cstring): bool = return s[0] == 'S'
+proc isControl*(s: cstring): bool = return s[1] == 'C'
+proc isButton1*(s: cstring): bool = return s[2] == '1'
+proc isButton2*(s: cstring): bool = return s[3] == '2'
+proc isbutton3*(s: cstring): bool = return s[4] == '3'
+proc isDouble*(s: cstring): bool = return s[5] == 'D'
+proc isAlt*(s: cstring): bool = return s[6] == 'A'
+proc isSys*(s: cstring): bool = return s[7] == 'Y'
+proc isButton4*(s: cstring): bool = return s[8] == '4'
+proc isButton5*(s: cstring): bool = return s[9] == '5'
+
+# Pre-Defined Masks
+const
+  IUP_MASK_FLOAT* = "[+/-]?(/d+/.?/d*|/./d+)"
+  IUP_MASK_UFLOAT* = "(/d+/.?/d*|/./d+)"
+  IUP_MASK_EFLOAT* = "[+/-]?(/d+/.?/d*|/./d+)([eE][+/-]?/d+)?"
+  IUP_MASK_INT* = "[+/-]?/d+"
+  IUP_MASK_UINT* = "/d+"
+
+# from 32 to 126, all character sets are equal,
+# the key code i the same as the character code.
+const
+  K_SP* = cint(ord(' '))
+  K_exclam* = cint(ord('!'))
+  K_quotedbl* = cint(ord('\"'))
+  K_numbersign* = cint(ord('#'))
+  K_dollar* = cint(ord('$'))
+  K_percent* = cint(ord('%'))
+  K_ampersand* = cint(ord('&'))
+  K_apostrophe* = cint(ord('\''))
+  K_parentleft* = cint(ord('('))
+  K_parentright* = cint(ord(')'))
+  K_asterisk* = cint(ord('*'))
+  K_plus* = cint(ord('+'))
+  K_comma* = cint(ord(','))
+  K_minus* = cint(ord('-'))
+  K_period* = cint(ord('.'))
+  K_slash* = cint(ord('/'))
+  K_0* = cint(ord('0'))
+  K_1* = cint(ord('1'))
+  K_2* = cint(ord('2'))
+  K_3* = cint(ord('3'))
+  K_4* = cint(ord('4'))
+  K_5* = cint(ord('5'))
+  K_6* = cint(ord('6'))
+  K_7* = cint(ord('7'))
+  K_8* = cint(ord('8'))
+  K_9* = cint(ord('9'))
+  K_colon* = cint(ord(':'))
+  K_semicolon* = cint(ord(';'))
+  K_less* = cint(ord('<'))
+  K_equal* = cint(ord('='))
+  K_greater* = cint(ord('>'))
+  K_question* = cint(ord('?'))
+  K_at* = cint(ord('@'))
+  K_upperA* = cint(ord('A'))
+  K_upperB* = cint(ord('B'))
+  K_upperC* = cint(ord('C'))
+  K_upperD* = cint(ord('D'))
+  K_upperE* = cint(ord('E'))
+  K_upperF* = cint(ord('F'))
+  K_upperG* = cint(ord('G'))
+  K_upperH* = cint(ord('H'))
+  K_upperI* = cint(ord('I'))
+  K_upperJ* = cint(ord('J'))
+  K_upperK* = cint(ord('K'))
+  K_upperL* = cint(ord('L'))
+  K_upperM* = cint(ord('M'))
+  K_upperN* = cint(ord('N'))
+  K_upperO* = cint(ord('O'))
+  K_upperP* = cint(ord('P'))
+  K_upperQ* = cint(ord('Q'))
+  K_upperR* = cint(ord('R'))
+  K_upperS* = cint(ord('S'))
+  K_upperT* = cint(ord('T'))
+  K_upperU* = cint(ord('U'))
+  K_upperV* = cint(ord('V'))
+  K_upperW* = cint(ord('W'))
+  K_upperX* = cint(ord('X'))
+  K_upperY* = cint(ord('Y'))
+  K_upperZ* = cint(ord('Z'))
+  K_bracketleft* = cint(ord('['))
+  K_backslash* = cint(ord('\\'))
+  K_bracketright* = cint(ord(']'))
+  K_circum* = cint(ord('^'))
+  K_underscore* = cint(ord('_'))
+  K_grave* = cint(ord('`'))
+  K_lowera* = cint(ord('a'))
+  K_lowerb* = cint(ord('b'))
+  K_lowerc* = cint(ord('c'))
+  K_lowerd* = cint(ord('d'))
+  K_lowere* = cint(ord('e'))
+  K_lowerf* = cint(ord('f'))
+  K_lowerg* = cint(ord('g'))
+  K_lowerh* = cint(ord('h'))
+  K_loweri* = cint(ord('i'))
+  K_lowerj* = cint(ord('j'))
+  K_lowerk* = cint(ord('k'))
+  K_lowerl* = cint(ord('l'))
+  K_lowerm* = cint(ord('m'))
+  K_lowern* = cint(ord('n'))
+  K_lowero* = cint(ord('o'))
+  K_lowerp* = cint(ord('p'))
+  K_lowerq* = cint(ord('q'))
+  K_lowerr* = cint(ord('r'))
+  K_lowers* = cint(ord('s'))
+  K_lowert* = cint(ord('t'))
+  K_loweru* = cint(ord('u'))
+  K_lowerv* = cint(ord('v'))
+  K_lowerw* = cint(ord('w'))
+  K_lowerx* = cint(ord('x'))
+  K_lowery* = cint(ord('y'))
+  K_lowerz* = cint(ord('z'))
+  K_braceleft* = cint(ord('{'))
+  K_bar* = cint(ord('|'))
+  K_braceright* = cint(ord('}'))
+  K_tilde* = cint(ord('~'))
+
+proc isPrint*(c: cint): bool = return c > 31 and c < 127
+
+# also define the escape sequences that have keys associated
+const
+  K_BS* = cint(ord('\b'))
+  K_TAB* = cint(ord('\t'))
+  K_LF* = cint(10)
+  K_CR* = cint(13)
+
+# IUP Extended Key Codes, range start at 128
+# Modifiers use 256 interval
+# These key code definitions are specific to IUP
+
+proc isXkey*(c: cint): bool = return c > 128
+proc isShiftXkey*(c: cint): bool = return c > 256 and c < 512
+proc isCtrlXkey*(c: cint): bool = return c > 512 and c < 768
+proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024
+proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280
+
+proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128)
+proc iUPsxCODE*(c: cint): cint =
+  return c + cint(256)
+  # Shift (must have range to include the standard keys and the normal
+  # extended keys, so must be above 256
+
+proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl
+proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt
+proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple)
+
+const
+  IUP_NUMMAXCODES* = 1280 ## 5*256=1280  Normal+Shift+Ctrl+Alt+Sys
+
+  K_HOME* = iUPxCODE(1)
+  K_UP* = iUPxCODE(2)
+  K_PGUP* = iUPxCODE(3)
+  K_LEFT* = iUPxCODE(4)
+  K_MIDDLE* = iUPxCODE(5)
+  K_RIGHT* = iUPxCODE(6)
+  K_END* = iUPxCODE(7)
+  K_DOWN* = iUPxCODE(8)
+  K_PGDN* = iUPxCODE(9)
+  K_INS* = iUPxCODE(10)
+  K_DEL* = iUPxCODE(11)
+  K_PAUSE* = iUPxCODE(12)
+  K_ESC* = iUPxCODE(13)
+  K_ccedilla* = iUPxCODE(14)
+  K_F1* = iUPxCODE(15)
+  K_F2* = iUPxCODE(16)
+  K_F3* = iUPxCODE(17)
+  K_F4* = iUPxCODE(18)
+  K_F5* = iUPxCODE(19)
+  K_F6* = iUPxCODE(20)
+  K_F7* = iUPxCODE(21)
+  K_F8* = iUPxCODE(22)
+  K_F9* = iUPxCODE(23)
+  K_F10* = iUPxCODE(24)
+  K_F11* = iUPxCODE(25)
+  K_F12* = iUPxCODE(26)
+  K_Print* = iUPxCODE(27)
+  K_Menu* = iUPxCODE(28)
+
+  K_acute* = iUPxCODE(29) # no Shift/Ctrl/Alt
+
+  K_sHOME* = iUPsxCODE(K_HOME)
+  K_sUP* = iUPsxCODE(K_UP)
+  K_sPGUP* = iUPsxCODE(K_PGUP)
+  K_sLEFT* = iUPsxCODE(K_LEFT)
+  K_sMIDDLE* = iUPsxCODE(K_MIDDLE)
+  K_sRIGHT* = iUPsxCODE(K_RIGHT)
+  K_sEND* = iUPsxCODE(K_END)
+  K_sDOWN* = iUPsxCODE(K_DOWN)
+  K_sPGDN* = iUPsxCODE(K_PGDN)
+  K_sINS* = iUPsxCODE(K_INS)
+  K_sDEL* = iUPsxCODE(K_DEL)
+  K_sSP* = iUPsxCODE(K_SP)
+  K_sTAB* = iUPsxCODE(K_TAB)
+  K_sCR* = iUPsxCODE(K_CR)
+  K_sBS* = iUPsxCODE(K_BS)
+  K_sPAUSE* = iUPsxCODE(K_PAUSE)
+  K_sESC* = iUPsxCODE(K_ESC)
+  K_sCcedilla* = iUPsxCODE(K_ccedilla)
+  K_sF1* = iUPsxCODE(K_F1)
+  K_sF2* = iUPsxCODE(K_F2)
+  K_sF3* = iUPsxCODE(K_F3)
+  K_sF4* = iUPsxCODE(K_F4)
+  K_sF5* = iUPsxCODE(K_F5)
+  K_sF6* = iUPsxCODE(K_F6)
+  K_sF7* = iUPsxCODE(K_F7)
+  K_sF8* = iUPsxCODE(K_F8)
+  K_sF9* = iUPsxCODE(K_F9)
+  K_sF10* = iUPsxCODE(K_F10)
+  K_sF11* = iUPsxCODE(K_F11)
+  K_sF12* = iUPsxCODE(K_F12)
+  K_sPrint* = iUPsxCODE(K_Print)
+  K_sMenu* = iUPsxCODE(K_Menu)
+
+  K_cHOME* = iUPcxCODE(K_HOME)
+  K_cUP* = iUPcxCODE(K_UP)
+  K_cPGUP* = iUPcxCODE(K_PGUP)
+  K_cLEFT* = iUPcxCODE(K_LEFT)
+  K_cMIDDLE* = iUPcxCODE(K_MIDDLE)
+  K_cRIGHT* = iUPcxCODE(K_RIGHT)
+  K_cEND* = iUPcxCODE(K_END)
+  K_cDOWN* = iUPcxCODE(K_DOWN)
+  K_cPGDN* = iUPcxCODE(K_PGDN)
+  K_cINS* = iUPcxCODE(K_INS)
+  K_cDEL* = iUPcxCODE(K_DEL)
+  K_cSP* = iUPcxCODE(K_SP)
+  K_cTAB* = iUPcxCODE(K_TAB)
+  K_cCR* = iUPcxCODE(K_CR)
+  K_cBS* = iUPcxCODE(K_BS)
+  K_cPAUSE* = iUPcxCODE(K_PAUSE)
+  K_cESC* = iUPcxCODE(K_ESC)
+  K_cCcedilla* = iUPcxCODE(K_ccedilla)
+  K_cF1* = iUPcxCODE(K_F1)
+  K_cF2* = iUPcxCODE(K_F2)
+  K_cF3* = iUPcxCODE(K_F3)
+  K_cF4* = iUPcxCODE(K_F4)
+  K_cF5* = iUPcxCODE(K_F5)
+  K_cF6* = iUPcxCODE(K_F6)
+  K_cF7* = iUPcxCODE(K_F7)
+  K_cF8* = iUPcxCODE(K_F8)
+  K_cF9* = iUPcxCODE(K_F9)
+  K_cF10* = iUPcxCODE(K_F10)
+  K_cF11* = iUPcxCODE(K_F11)
+  K_cF12* = iUPcxCODE(K_F12)
+  K_cPrint* = iUPcxCODE(K_Print)
+  K_cMenu* = iUPcxCODE(K_Menu)
+
+  K_mHOME* = iUPmxCODE(K_HOME)
+  K_mUP* = iUPmxCODE(K_UP)
+  K_mPGUP* = iUPmxCODE(K_PGUP)
+  K_mLEFT* = iUPmxCODE(K_LEFT)
+  K_mMIDDLE* = iUPmxCODE(K_MIDDLE)
+  K_mRIGHT* = iUPmxCODE(K_RIGHT)
+  K_mEND* = iUPmxCODE(K_END)
+  K_mDOWN* = iUPmxCODE(K_DOWN)
+  K_mPGDN* = iUPmxCODE(K_PGDN)
+  K_mINS* = iUPmxCODE(K_INS)
+  K_mDEL* = iUPmxCODE(K_DEL)
+  K_mSP* = iUPmxCODE(K_SP)
+  K_mTAB* = iUPmxCODE(K_TAB)
+  K_mCR* = iUPmxCODE(K_CR)
+  K_mBS* = iUPmxCODE(K_BS)
+  K_mPAUSE* = iUPmxCODE(K_PAUSE)
+  K_mESC* = iUPmxCODE(K_ESC)
+  K_mCcedilla* = iUPmxCODE(K_ccedilla)
+  K_mF1* = iUPmxCODE(K_F1)
+  K_mF2* = iUPmxCODE(K_F2)
+  K_mF3* = iUPmxCODE(K_F3)
+  K_mF4* = iUPmxCODE(K_F4)
+  K_mF5* = iUPmxCODE(K_F5)
+  K_mF6* = iUPmxCODE(K_F6)
+  K_mF7* = iUPmxCODE(K_F7)
+  K_mF8* = iUPmxCODE(K_F8)
+  K_mF9* = iUPmxCODE(K_F9)
+  K_mF10* = iUPmxCODE(K_F10)
+  K_mF11* = iUPmxCODE(K_F11)
+  K_mF12* = iUPmxCODE(K_F12)
+  K_mPrint* = iUPmxCODE(K_Print)
+  K_mMenu* = iUPmxCODE(K_Menu)
+
+  K_yHOME* = iUPyxCODE(K_HOME)
+  K_yUP* = iUPyxCODE(K_UP)
+  K_yPGUP* = iUPyxCODE(K_PGUP)
+  K_yLEFT* = iUPyxCODE(K_LEFT)
+  K_yMIDDLE* = iUPyxCODE(K_MIDDLE)
+  K_yRIGHT* = iUPyxCODE(K_RIGHT)
+  K_yEND* = iUPyxCODE(K_END)
+  K_yDOWN* = iUPyxCODE(K_DOWN)
+  K_yPGDN* = iUPyxCODE(K_PGDN)
+  K_yINS* = iUPyxCODE(K_INS)
+  K_yDEL* = iUPyxCODE(K_DEL)
+  K_ySP* = iUPyxCODE(K_SP)
+  K_yTAB* = iUPyxCODE(K_TAB)
+  K_yCR* = iUPyxCODE(K_CR)
+  K_yBS* = iUPyxCODE(K_BS)
+  K_yPAUSE* = iUPyxCODE(K_PAUSE)
+  K_yESC* = iUPyxCODE(K_ESC)
+  K_yCcedilla* = iUPyxCODE(K_ccedilla)
+  K_yF1* = iUPyxCODE(K_F1)
+  K_yF2* = iUPyxCODE(K_F2)
+  K_yF3* = iUPyxCODE(K_F3)
+  K_yF4* = iUPyxCODE(K_F4)
+  K_yF5* = iUPyxCODE(K_F5)
+  K_yF6* = iUPyxCODE(K_F6)
+  K_yF7* = iUPyxCODE(K_F7)
+  K_yF8* = iUPyxCODE(K_F8)
+  K_yF9* = iUPyxCODE(K_F9)
+  K_yF10* = iUPyxCODE(K_F10)
+  K_yF11* = iUPyxCODE(K_F11)
+  K_yF12* = iUPyxCODE(K_F12)
+  K_yPrint* = iUPyxCODE(K_Print)
+  K_yMenu* = iUPyxCODE(K_Menu)
+
+  K_sPlus* = iUPsxCODE(K_plus)
+  K_sComma* = iUPsxCODE(K_comma)
+  K_sMinus* = iUPsxCODE(K_minus)
+  K_sPeriod* = iUPsxCODE(K_period)
+  K_sSlash* = iUPsxCODE(K_slash)
+  K_sAsterisk* = iUPsxCODE(K_asterisk)
+
+  K_cupperA* = iUPcxCODE(K_upperA)
+  K_cupperB* = iUPcxCODE(K_upperB)
+  K_cupperC* = iUPcxCODE(K_upperC)
+  K_cupperD* = iUPcxCODE(K_upperD)
+  K_cupperE* = iUPcxCODE(K_upperE)
+  K_cupperF* = iUPcxCODE(K_upperF)
+  K_cupperG* = iUPcxCODE(K_upperG)
+  K_cupperH* = iUPcxCODE(K_upperH)
+  K_cupperI* = iUPcxCODE(K_upperI)
+  K_cupperJ* = iUPcxCODE(K_upperJ)
+  K_cupperK* = iUPcxCODE(K_upperK)
+  K_cupperL* = iUPcxCODE(K_upperL)
+  K_cupperM* = iUPcxCODE(K_upperM)
+  K_cupperN* = iUPcxCODE(K_upperN)
+  K_cupperO* = iUPcxCODE(K_upperO)
+  K_cupperP* = iUPcxCODE(K_upperP)
+  K_cupperQ* = iUPcxCODE(K_upperQ)
+  K_cupperR* = iUPcxCODE(K_upperR)
+  K_cupperS* = iUPcxCODE(K_upperS)
+  K_cupperT* = iUPcxCODE(K_upperT)
+  K_cupperU* = iUPcxCODE(K_upperU)
+  K_cupperV* = iUPcxCODE(K_upperV)
+  K_cupperW* = iUPcxCODE(K_upperW)
+  K_cupperX* = iUPcxCODE(K_upperX)
+  K_cupperY* = iUPcxCODE(K_upperY)
+  K_cupperZ* = iUPcxCODE(K_upperZ)
+  K_c1* = iUPcxCODE(K_1)
+  K_c2* = iUPcxCODE(K_2)
+  K_c3* = iUPcxCODE(K_3)
+  K_c4* = iUPcxCODE(K_4)
+  K_c5* = iUPcxCODE(K_5)
+  K_c6* = iUPcxCODE(K_6)
+  K_c7* = iUPcxCODE(K_7)
+  K_c8* = iUPcxCODE(K_8)
+  K_c9* = iUPcxCODE(K_9)
+  K_c0* = iUPcxCODE(K_0)
+  K_cPlus* = iUPcxCODE(K_plus)
+  K_cComma* = iUPcxCODE(K_comma)
+  K_cMinus* = iUPcxCODE(K_minus)
+  K_cPeriod* = iUPcxCODE(K_period)
+  K_cSlash* = iUPcxCODE(K_slash)
+  K_cSemicolon* = iUPcxCODE(K_semicolon)
+  K_cEqual* = iUPcxCODE(K_equal)
+  K_cBracketleft* = iUPcxCODE(K_bracketleft)
+  K_cBracketright* = iUPcxCODE(K_bracketright)
+  K_cBackslash* = iUPcxCODE(K_backslash)
+  K_cAsterisk* = iUPcxCODE(K_asterisk)
+
+  K_mupperA* = iUPmxCODE(K_upperA)
+  K_mupperB* = iUPmxCODE(K_upperB)
+  K_mupperC* = iUPmxCODE(K_upperC)
+  K_mupperD* = iUPmxCODE(K_upperD)
+  K_mupperE* = iUPmxCODE(K_upperE)
+  K_mupperF* = iUPmxCODE(K_upperF)
+  K_mupperG* = iUPmxCODE(K_upperG)
+  K_mupperH* = iUPmxCODE(K_upperH)
+  K_mupperI* = iUPmxCODE(K_upperI)
+  K_mupperJ* = iUPmxCODE(K_upperJ)
+  K_mupperK* = iUPmxCODE(K_upperK)
+  K_mupperL* = iUPmxCODE(K_upperL)
+  K_mupperM* = iUPmxCODE(K_upperM)
+  K_mupperN* = iUPmxCODE(K_upperN)
+  K_mupperO* = iUPmxCODE(K_upperO)
+  K_mupperP* = iUPmxCODE(K_upperP)
+  K_mupperQ* = iUPmxCODE(K_upperQ)
+  K_mupperR* = iUPmxCODE(K_upperR)
+  K_mupperS* = iUPmxCODE(K_upperS)
+  K_mupperT* = iUPmxCODE(K_upperT)
+  K_mupperU* = iUPmxCODE(K_upperU)
+  K_mupperV* = iUPmxCODE(K_upperV)
+  K_mupperW* = iUPmxCODE(K_upperW)
+  K_mupperX* = iUPmxCODE(K_upperX)
+  K_mupperY* = iUPmxCODE(K_upperY)
+  K_mupperZ* = iUPmxCODE(K_upperZ)
+  K_m1* = iUPmxCODE(K_1)
+  K_m2* = iUPmxCODE(K_2)
+  K_m3* = iUPmxCODE(K_3)
+  K_m4* = iUPmxCODE(K_4)
+  K_m5* = iUPmxCODE(K_5)
+  K_m6* = iUPmxCODE(K_6)
+  K_m7* = iUPmxCODE(K_7)
+  K_m8* = iUPmxCODE(K_8)
+  K_m9* = iUPmxCODE(K_9)
+  K_m0* = iUPmxCODE(K_0)
+  K_mPlus* = iUPmxCODE(K_plus)
+  K_mComma* = iUPmxCODE(K_comma)
+  K_mMinus* = iUPmxCODE(K_minus)
+  K_mPeriod* = iUPmxCODE(K_period)
+  K_mSlash* = iUPmxCODE(K_slash)
+  K_mSemicolon* = iUPmxCODE(K_semicolon)
+  K_mEqual* = iUPmxCODE(K_equal)
+  K_mBracketleft* = iUPmxCODE(K_bracketleft)
+  K_mBracketright* = iUPmxCODE(K_bracketright)
+  K_mBackslash* = iUPmxCODE(K_backslash)
+  K_mAsterisk* = iUPmxCODE(K_asterisk)
+
+  K_yA* = iUPyxCODE(K_upperA)
+  K_yB* = iUPyxCODE(K_upperB)
+  K_yC* = iUPyxCODE(K_upperC)
+  K_yD* = iUPyxCODE(K_upperD)
+  K_yE* = iUPyxCODE(K_upperE)
+  K_yF* = iUPyxCODE(K_upperF)
+  K_yG* = iUPyxCODE(K_upperG)
+  K_yH* = iUPyxCODE(K_upperH)
+  K_yI* = iUPyxCODE(K_upperI)
+  K_yJ* = iUPyxCODE(K_upperJ)
+  K_yK* = iUPyxCODE(K_upperK)
+  K_yL* = iUPyxCODE(K_upperL)
+  K_yM* = iUPyxCODE(K_upperM)
+  K_yN* = iUPyxCODE(K_upperN)
+  K_yO* = iUPyxCODE(K_upperO)
+  K_yP* = iUPyxCODE(K_upperP)
+  K_yQ* = iUPyxCODE(K_upperQ)
+  K_yR* = iUPyxCODE(K_upperR)
+  K_yS* = iUPyxCODE(K_upperS)
+  K_yT* = iUPyxCODE(K_upperT)
+  K_yU* = iUPyxCODE(K_upperU)
+  K_yV* = iUPyxCODE(K_upperV)
+  K_yW* = iUPyxCODE(K_upperW)
+  K_yX* = iUPyxCODE(K_upperX)
+  K_yY* = iUPyxCODE(K_upperY)
+  K_yZ* = iUPyxCODE(K_upperZ)
+  K_y1* = iUPyxCODE(K_1)
+  K_y2* = iUPyxCODE(K_2)
+  K_y3* = iUPyxCODE(K_3)
+  K_y4* = iUPyxCODE(K_4)
+  K_y5* = iUPyxCODE(K_5)
+  K_y6* = iUPyxCODE(K_6)
+  K_y7* = iUPyxCODE(K_7)
+  K_y8* = iUPyxCODE(K_8)
+  K_y9* = iUPyxCODE(K_9)
+  K_y0* = iUPyxCODE(K_0)
+  K_yPlus* = iUPyxCODE(K_plus)
+  K_yComma* = iUPyxCODE(K_comma)
+  K_yMinus* = iUPyxCODE(K_minus)
+  K_yPeriod* = iUPyxCODE(K_period)
+  K_ySlash* = iUPyxCODE(K_slash)
+  K_ySemicolon* = iUPyxCODE(K_semicolon)
+  K_yEqual* = iUPyxCODE(K_equal)
+  K_yBracketleft* = iUPyxCODE(K_bracketleft)
+  K_yBracketright* = iUPyxCODE(K_bracketright)
+  K_yBackslash* = iUPyxCODE(K_backslash)
+  K_yAsterisk* = iUPyxCODE(K_asterisk)
+
+proc controlsOpen*(): cint {.cdecl, importc: "IupControlsOpen", dynlib: dllname.}
+proc controlsClose*() {.cdecl, importc: "IupControlsClose", dynlib: dllname.}
+
+proc oldValOpen*() {.cdecl, importc: "IupOldValOpen", dynlib: dllname.}
+proc oldTabsOpen*() {.cdecl, importc: "IupOldTabsOpen", dynlib: dllname.}
+
+proc colorbar*(): PIhandle {.cdecl, importc: "IupColorbar", dynlib: dllname.}
+proc cells*(): PIhandle {.cdecl, importc: "IupCells", dynlib: dllname.}
+proc colorBrowser*(): PIhandle {.cdecl, importc: "IupColorBrowser", dynlib: dllname.}
+proc gauge*(): PIhandle {.cdecl, importc: "IupGauge", dynlib: dllname.}
+proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dllname.}
+proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.}
+
+# IupMatrix utilities
+proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                      value: cstring) {.
+                      cdecl, importc: "IupMatSetAttribute", dynlib: dllname.}
+proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                        value: cstring) {.cdecl,
+                        importc: "IupMatStoreAttribute", dynlib: dllname.}
+proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {.
+  cdecl, importc: "IupMatGetAttribute", dynlib: dllname.}
+proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {.
+  cdecl, importc: "IupMatGetInt", dynlib: dllname.}
+proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {.
+  cdecl, importc: "IupMatGetFloat", dynlib: dllname.}
+proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint,
+                       format: cstring) {.cdecl,
+                       importc: "IupMatSetfAttribute",
+                       dynlib: dllname, varargs.}
+
+# Used by IupColorbar
+const
+  IUP_PRIMARY* = -1
+  IUP_SECONDARY* = -2
+
+# Initialize PPlot widget class
+proc pPlotOpen*() {.cdecl, importc: "IupPPlotOpen", dynlib: dllname.}
+
+# Create an PPlot widget instance
+proc pPlot*: PIhandle {.cdecl, importc: "IupPPlot", dynlib: dllname.}
+
+# Add dataset to plot
+proc pPlotBegin*(ih: PIhandle, strXdata: cint) {.
+  cdecl, importc: "IupPPlotBegin", dynlib: dllname.}
+proc pPlotAdd*(ih: PIhandle, x, y: cfloat) {.
+  cdecl, importc: "IupPPlotAdd", dynlib: dllname.}
+proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {.
+  cdecl, importc: "IupPPlotAddStr", dynlib: dllname.}
+proc pPlotEnd*(ih: PIhandle): cint {.
+  cdecl, importc: "IupPPlotEnd", dynlib: dllname.}
+
+proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring,
+                     y: cfloat) {.cdecl, importc: "IupPPlotInsertStr",
+                     dynlib: dllname.}
+proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint,
+                  x, y: cfloat) {.
+                  cdecl, importc: "IupPPlotInsert", dynlib: dllname.}
+
+# convert from plot coordinates to pixels
+proc pPlotTransform*(ih: PIhandle, x, y: cfloat, ix, iy: var cint) {.
+  cdecl, importc: "IupPPlotTransform", dynlib: dllname.}
+
+# Plot on the given device. Uses a "cdCanvas*".
+proc pPlotPaintTo*(ih: PIhandle, cnv: pointer) {.
+  cdecl, importc: "IupPPlotPaintTo", dynlib: dllname.}
+
+
diff --git a/lib/wrappers/joyent_http_parser.nim b/lib/wrappers/joyent_http_parser.nim
new file mode 100644
index 000000000..a008da43e
--- /dev/null
+++ b/lib/wrappers/joyent_http_parser.nim
@@ -0,0 +1,81 @@
+type
+  csize = int
+  
+  HttpDataProc* = proc (a2: ptr THttpParser, at: cstring, length: csize): cint {.cdecl.}
+  HttpProc* = proc (a2: ptr THttpParser): cint {.cdecl.}
+
+  THttpMethod* = enum
+    HTTP_DELETE = 0, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_CONNECT,
+    HTTP_OPTIONS, HTTP_TRACE, HTTP_COPY, HTTP_LOCK, HTTP_MKCOL, HTTP_MOVE,
+    HTTP_PROPFIND, HTTP_PROPPATCH, HTTP_UNLOCK, HTTP_REPORT, HTTP_MKACTIVITY,
+    HTTP_CHECKOUT, HTTP_MERGE, HTTP_MSEARCH, HTTP_NOTIFY, HTTP_SUBSCRIBE,
+    HTTP_UNSUBSCRIBE, HTTP_PATCH
+
+  THttpParserType* = enum
+    HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH
+
+  TParserFlag* = enum
+    F_CHUNKED = 1 shl 0,
+    F_CONNECTION_KEEP_ALIVE = 1 shl 1,
+    F_CONNECTION_CLOSE = 1 shl 2,
+    F_TRAILING = 1 shl 3,
+    F_UPGRADE = 1 shl 4,
+    F_SKIPBODY = 1 shl 5
+
+  THttpErrNo* = enum
+    HPE_OK, HPE_CB_message_begin, HPE_CB_path, HPE_CB_query_string, HPE_CB_url,
+    HPE_CB_fragment, HPE_CB_header_field, HPE_CB_header_value,
+    HPE_CB_headers_complete, HPE_CB_body, HPE_CB_message_complete,
+    HPE_INVALID_EOF_STATE, HPE_HEADER_OVERFLOW, HPE_CLOSED_CONNECTION,
+    HPE_INVALID_VERSION, HPE_INVALID_STATUS, HPE_INVALID_METHOD,
+    HPE_INVALID_URL, HPE_INVALID_HOST, HPE_INVALID_PORT, HPE_INVALID_PATH,
+    HPE_INVALID_QUERY_STRING, HPE_INVALID_FRAGMENT, HPE_LF_EXPECTED,
+    HPE_INVALID_HEADER_TOKEN, HPE_INVALID_CONTENT_LENGTH,
+    HPE_INVALID_CHUNK_SIZE, HPE_INVALID_CONSTANT, HPE_INVALID_INTERNAL_STATE,
+    HPE_STRICT, HPE_UNKNOWN
+
+  THttpParser*{.pure, final, importc: "http_parser", header: "http_parser.h".} = object
+    typ {.importc: "type".}: char
+    flags {.importc: "flags".}: char
+    state*{.importc: "state".}: char
+    header_state*{.importc: "header_state".}: char
+    index*{.importc: "index".}: char
+    nread*{.importc: "nread".}: cint
+    content_length*{.importc: "content_length".}: int64
+    http_major*{.importc: "http_major".}: cshort
+    http_minor*{.importc: "http_minor".}: cshort
+    status_code*{.importc: "status_code".}: cshort
+    http_method*{.importc: "method".}: cshort
+    http_errno_bits {.importc: "http_errno".}: char
+    upgrade {.importc: "upgrade".}: bool
+    data*{.importc: "data".}: pointer
+
+  THttpParserSettings*{.pure, final, importc: "http_parser_settings", header: "http_parser.h".} = object
+    on_message_begin*{.importc: "on_message_begin".}: HttpProc
+    on_url*{.importc: "on_url".}: HttpDataProc
+    on_header_field*{.importc: "on_header_field".}: HttpDataProc
+    on_header_value*{.importc: "on_header_value".}: HttpDataProc
+    on_headers_complete*{.importc: "on_headers_complete".}: HttpProc
+    on_body*{.importc: "on_body".}: HttpDataProc
+    on_message_complete*{.importc: "on_message_complete".}: HttpProc
+
+proc http_parser_init*(parser: var THttpParser, typ: THttpParserType){.
+    importc: "http_parser_init", header: "http_parser.h".}
+
+proc http_parser_execute*(parser: var THttpParser,
+                          settings: var THttpParserSettings, data: cstring,
+                          len: csize): csize {.
+    importc: "http_parser_execute", header: "http_parser.h".}
+
+proc http_should_keep_alive*(parser: var THttpParser): cint{.
+    importc: "http_should_keep_alive", header: "http_parser.h".}
+
+proc http_method_str*(m: THttpMethod): cstring{.
+    importc: "http_method_str", header: "http_parser.h".}
+
+proc http_errno_name*(err: THttpErrNo): cstring{.
+    importc: "http_errno_name", header: "http_parser.h".}
+
+proc http_errno_description*(err: THttpErrNo): cstring{.
+    importc: "http_errno_description", header: "http_parser.h".}
+
diff --git a/lib/wrappers/libcurl.nim b/lib/wrappers/libcurl.nim
new file mode 100644
index 000000000..8c962f6cb
--- /dev/null
+++ b/lib/wrappers/libcurl.nim
@@ -0,0 +1,494 @@
+#
+#    $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
+#    This file is part of the Free Pascal packages
+#    Copyright (c) 1999-2000 by the Free Pascal development team
+#
+#    See the file COPYING.FPC, included in this distribution,
+#    for details about the copyright.
+#
+#    This program 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.
+#
+# **********************************************************************
+#
+#   the curl library is governed by its own copyright, see the curl
+#   website for this. 
+# 
+
+{.deadCodeElim: on.}
+
+import 
+  times
+
+when defined(windows): 
+  const 
+    libname = "libcurl.dll"
+elif defined(macosx): 
+  const 
+    libname = "libcurl-7.19.3.dylib"
+elif defined(unix): 
+  const 
+    libname = "libcurl.so.4"
+type 
+  Pcalloc_callback* = ptr Tcalloc_callback
+  Pclosepolicy* = ptr Tclosepolicy
+  Pforms* = ptr Tforms
+  Pftpauth* = ptr Tftpauth
+  Pftpmethod* = ptr Tftpmethod
+  Pftpssl* = ptr Tftpssl
+  PHTTP_VERSION* = ptr THTTP_VERSION
+  Phttppost* = ptr Thttppost
+  PPcurl_httppost* = ptr Phttppost
+  Pinfotype* = ptr Tinfotype
+  Plock_access* = ptr Tlock_access
+  Plock_data* = ptr Tlock_data
+  Pmalloc_callback* = ptr Tmalloc_callback
+  PNETRC_OPTION* = ptr TNETRC_OPTION
+  Pproxytype* = ptr Tproxytype
+  Prealloc_callback* = ptr Trealloc_callback
+  Pslist* = ptr Tslist
+  Psocket* = ptr Tsocket
+  PSSL_VERSION* = ptr TSSL_VERSION
+  Pstrdup_callback* = ptr Tstrdup_callback
+  PTIMECOND* = ptr TTIMECOND
+  Pversion_info_data* = ptr Tversion_info_data
+  Pcode* = ptr Tcode
+  PFORMcode* = ptr TFORMcode
+  Pformoption* = ptr Tformoption
+  PINFO* = ptr TINFO
+  Piocmd* = ptr Tiocmd
+  Pioerr* = ptr Tioerr
+  PM* = ptr TM
+  PMcode* = ptr TMcode
+  PMoption* = ptr TMoption
+  PMSG* = ptr TMSG
+  Poption* = ptr Toption
+  PSH* = ptr TSH
+  PSHcode* = ptr TSHcode
+  PSHoption* = ptr TSHoption
+  Pversion* = ptr Tversion
+  Pfd_set* = pointer
+  PCurl* = ptr TCurl
+  TCurl* = pointer
+  Thttppost*{.final, pure.} = object 
+    next*: Phttppost
+    name*: cstring
+    namelength*: int32
+    contents*: cstring
+    contentslength*: int32
+    buffer*: cstring
+    bufferlength*: int32
+    contenttype*: cstring
+    contentheader*: Pslist
+    more*: Phttppost
+    flags*: int32
+    showfilename*: cstring
+
+  Tprogress_callback* = proc (clientp: pointer, dltotal: float64, 
+                              dlnow: float64, ultotal: float64, 
+                              ulnow: float64): int32 {.cdecl.}
+  Twrite_callback* = proc (buffer: cstring, size: int, nitems: int, 
+                           outstream: pointer): int{.cdecl.}
+  Tread_callback* = proc (buffer: cstring, size: int, nitems: int, 
+                          instream: pointer): int{.cdecl.}
+  Tpasswd_callback* = proc (clientp: pointer, prompt: cstring, buffer: cstring, 
+                            buflen: int32): int32{.cdecl.}
+  Tioerr* = enum 
+    IOE_OK, IOE_UNKNOWNCMD, IOE_FAILRESTART, IOE_LAST
+  Tiocmd* = enum 
+    IOCMD_NOP, IOCMD_RESTARTREAD, IOCMD_LAST
+  Tioctl_callback* = proc (handle: PCurl, cmd: int32, clientp: pointer): Tioerr{.
+      cdecl.}
+  Tmalloc_callback* = proc (size: int): pointer{.cdecl.}
+  Tfree_callback* = proc (p: pointer){.cdecl.}
+  Trealloc_callback* = proc (p: pointer, size: int): pointer{.cdecl.}
+  Tstrdup_callback* = proc (str: cstring): cstring{.cdecl.}
+  Tcalloc_callback* = proc (nmemb: int, size: int): pointer{.noconv.}
+  Tinfotype* = enum 
+    INFO_TEXT = 0, INFO_HEADER_IN, INFO_HEADER_OUT, INFO_DATA_IN, INFO_DATA_OUT, 
+    INFO_SSL_DATA_IN, INFO_SSL_DATA_OUT, INFO_END
+  Tdebug_callback* = proc (handle: PCurl, theType: Tinfotype, data: cstring, 
+                           size: int, userptr: pointer): int32{.cdecl.}
+  Tcode* = enum 
+    E_OK = 0, E_UNSUPPORTED_PROTOCOL, E_FAILED_INIT, E_URL_MALFORMAT, 
+    E_URL_MALFORMAT_USER, E_COULDNT_RESOLVE_PROXY, E_COULDNT_RESOLVE_HOST, 
+    E_COULDNT_CONNECT, E_FTP_WEIRD_SERVER_REPLY, E_FTP_ACCESS_DENIED, 
+    E_FTP_USER_PASSWORD_INCORRECT, E_FTP_WEIRD_PASS_REPLY, 
+    E_FTP_WEIRD_USER_REPLY, E_FTP_WEIRD_PASV_REPLY, E_FTP_WEIRD_227_FORMAT, 
+    E_FTP_CANT_GET_HOST, E_FTP_CANT_RECONNECT, E_FTP_COULDNT_SET_BINARY, 
+    E_PARTIAL_FILE, E_FTP_COULDNT_RETR_FILE, E_FTP_WRITE_ERROR, 
+    E_FTP_QUOTE_ERROR, E_HTTP_RETURNED_ERROR, E_WRITE_ERROR, E_MALFORMAT_USER, 
+    E_FTP_COULDNT_STOR_FILE, E_READ_ERROR, E_OUT_OF_MEMORY, 
+    E_OPERATION_TIMEOUTED, E_FTP_COULDNT_SET_ASCII, E_FTP_PORT_FAILED, 
+    E_FTP_COULDNT_USE_REST, E_FTP_COULDNT_GET_SIZE, E_HTTP_RANGE_ERROR, 
+    E_HTTP_POST_ERROR, E_SSL_CONNECT_ERROR, E_BAD_DOWNLOAD_RESUME, 
+    E_FILE_COULDNT_READ_FILE, E_LDAP_CANNOT_BIND, E_LDAP_SEARCH_FAILED, 
+    E_LIBRARY_NOT_FOUND, E_FUNCTION_NOT_FOUND, E_ABORTED_BY_CALLBACK, 
+    E_BAD_FUNCTION_ARGUMENT, E_BAD_CALLING_ORDER, E_INTERFACE_FAILED, 
+    E_BAD_PASSWORD_ENTERED, E_TOO_MANY_REDIRECTS, E_UNKNOWN_TELNET_OPTION, 
+    E_TELNET_OPTION_SYNTAX, E_OBSOLETE, E_SSL_PEER_CERTIFICATE, E_GOT_NOTHING, 
+    E_SSL_ENGINE_NOTFOUND, E_SSL_ENGINE_SETFAILED, E_SEND_ERROR, E_RECV_ERROR, 
+    E_SHARE_IN_USE, E_SSL_CERTPROBLEM, E_SSL_CIPHER, E_SSL_CACERT, 
+    E_BAD_CONTENT_ENCODING, E_LDAP_INVALID_URL, E_FILESIZE_EXCEEDED, 
+    E_FTP_SSL_FAILED, E_SEND_FAIL_REWIND, E_SSL_ENGINE_INITFAILED, 
+    E_LOGIN_DENIED, E_TFTP_NOTFOUND, E_TFTP_PERM, E_TFTP_DISKFULL, 
+    E_TFTP_ILLEGAL, E_TFTP_UNKNOWNID, E_TFTP_EXISTS, E_TFTP_NOSUCHUSER, 
+    E_CONV_FAILED, E_CONV_REQD, LAST
+  Tconv_callback* = proc (buffer: cstring, len: int): Tcode{.cdecl.}
+  Tssl_ctx_callback* = proc (curl: PCurl, ssl_ctx, userptr: pointer): Tcode{.cdecl.}
+  Tproxytype* = enum 
+    PROXY_HTTP = 0, PROXY_SOCKS4 = 4, PROXY_SOCKS5 = 5
+  Tftpssl* = enum 
+    FTPSSL_NONE, FTPSSL_TRY, FTPSSL_CONTROL, FTPSSL_ALL, FTPSSL_LAST
+  Tftpauth* = enum 
+    FTPAUTH_DEFAULT, FTPAUTH_SSL, FTPAUTH_TLS, FTPAUTH_LAST
+  Tftpmethod* = enum 
+    FTPMETHOD_DEFAULT, FTPMETHOD_MULTICWD, FTPMETHOD_NOCWD, FTPMETHOD_SINGLECWD, 
+    FTPMETHOD_LAST
+  Toption* = enum 
+    OPT_PORT = 0 + 3, OPT_TIMEOUT = 0 + 13, OPT_INFILESIZE = 0 + 14, 
+    OPT_LOW_SPEED_LIMIT = 0 + 19, OPT_LOW_SPEED_TIME = 0 + 20, 
+    OPT_RESUME_FROM = 0 + 21, OPT_CRLF = 0 + 27, OPT_SSLVERSION = 0 + 32, 
+    OPT_TIMECONDITION = 0 + 33, OPT_TIMEVALUE = 0 + 34, OPT_VERBOSE = 0 + 41, 
+    OPT_HEADER = 0 + 42, OPT_NOPROGRESS = 0 + 43, OPT_NOBODY = 0 + 44, 
+    OPT_FAILONERROR = 0 + 45, OPT_UPLOAD = 0 + 46, OPT_POST = 0 + 47, 
+    OPT_FTPLISTONLY = 0 + 48, OPT_FTPAPPEND = 0 + 50, OPT_NETRC = 0 + 51, 
+    OPT_FOLLOWLOCATION = 0 + 52, OPT_TRANSFERTEXT = 0 + 53, OPT_PUT = 0 + 54, 
+    OPT_AUTOREFERER = 0 + 58, OPT_PROXYPORT = 0 + 59, 
+    OPT_POSTFIELDSIZE = 0 + 60, OPT_HTTPPROXYTUNNEL = 0 + 61, 
+    OPT_SSL_VERIFYPEER = 0 + 64, OPT_MAXREDIRS = 0 + 68, OPT_FILETIME = 0 + 69, 
+    OPT_MAXCONNECTS = 0 + 71, OPT_CLOSEPOLICY = 0 + 72, 
+    OPT_FRESH_CONNECT = 0 + 74, OPT_FORBID_REUSE = 0 + 75, 
+    OPT_CONNECTTIMEOUT = 0 + 78, OPT_HTTPGET = 0 + 80, 
+    OPT_SSL_VERIFYHOST = 0 + 81, OPT_HTTP_VERSION = 0 + 84, 
+    OPT_FTP_USE_EPSV = 0 + 85, OPT_SSLENGINE_DEFAULT = 0 + 90, 
+    OPT_DNS_USE_GLOBAL_CACHE = 0 + 91, OPT_DNS_CACHE_TIMEOUT = 0 + 92, 
+    OPT_COOKIESESSION = 0 + 96, OPT_BUFFERSIZE = 0 + 98, OPT_NOSIGNAL = 0 + 99, 
+    OPT_PROXYTYPE = 0 + 101, OPT_UNRESTRICTED_AUTH = 0 + 105, 
+    OPT_FTP_USE_EPRT = 0 + 106, OPT_HTTPAUTH = 0 + 107, 
+    OPT_FTP_CREATE_MISSING_DIRS = 0 + 110, OPT_PROXYAUTH = 0 + 111, 
+    OPT_FTP_RESPONSE_TIMEOUT = 0 + 112, OPT_IPRESOLVE = 0 + 113, 
+    OPT_MAXFILESIZE = 0 + 114, OPT_FTP_SSL = 0 + 119, OPT_TCP_NODELAY = 0 + 121, 
+    OPT_FTPSSLAUTH = 0 + 129, OPT_IGNORE_CONTENT_LENGTH = 0 + 136, 
+    OPT_FTP_SKIP_PASV_IP = 0 + 137, OPT_FTP_FILEMETHOD = 0 + 138, 
+    OPT_LOCALPORT = 0 + 139, OPT_LOCALPORTRANGE = 0 + 140, 
+    OPT_CONNECT_ONLY = 0 + 141, OPT_FILE = 10000 + 1, OPT_URL = 10000 + 2, 
+    OPT_PROXY = 10000 + 4, OPT_USERPWD = 10000 + 5, 
+    OPT_PROXYUSERPWD = 10000 + 6, OPT_RANGE = 10000 + 7, OPT_INFILE = 10000 + 9, 
+    OPT_ERRORBUFFER = 10000 + 10, OPT_POSTFIELDS = 10000 + 15, 
+    OPT_REFERER = 10000 + 16, OPT_FTPPORT = 10000 + 17, 
+    OPT_USERAGENT = 10000 + 18, OPT_COOKIE = 10000 + 22, 
+    OPT_HTTPHEADER = 10000 + 23, OPT_HTTPPOST = 10000 + 24, 
+    OPT_SSLCERT = 10000 + 25, OPT_SSLCERTPASSWD = 10000 + 26, 
+    OPT_QUOTE = 10000 + 28, OPT_WRITEHEADER = 10000 + 29, 
+    OPT_COOKIEFILE = 10000 + 31, OPT_CUSTOMREQUEST = 10000 + 36, 
+    OPT_STDERR = 10000 + 37, OPT_POSTQUOTE = 10000 + 39, 
+    OPT_WRITEINFO = 10000 + 40, OPT_PROGRESSDATA = 10000 + 57, 
+    OPT_INTERFACE = 10000 + 62, OPT_KRB4LEVEL = 10000 + 63, 
+    OPT_CAINFO = 10000 + 65, OPT_TELNETOPTIONS = 10000 + 70, 
+    OPT_RANDOM_FILE = 10000 + 76, OPT_EGDSOCKET = 10000 + 77, 
+    OPT_COOKIEJAR = 10000 + 82, OPT_SSL_CIPHER_LIST = 10000 + 83, 
+    OPT_SSLCERTTYPE = 10000 + 86, OPT_SSLKEY = 10000 + 87, 
+    OPT_SSLKEYTYPE = 10000 + 88, OPT_SSLENGINE = 10000 + 89, 
+    OPT_PREQUOTE = 10000 + 93, OPT_DEBUGDATA = 10000 + 95, 
+    OPT_CAPATH = 10000 + 97, OPT_SHARE = 10000 + 100, 
+    OPT_ENCODING = 10000 + 102, OPT_PRIVATE = 10000 + 103, 
+    OPT_HTTP200ALIASES = 10000 + 104, OPT_SSL_CTX_DATA = 10000 + 109, 
+    OPT_NETRC_FILE = 10000 + 118, OPT_SOURCE_USERPWD = 10000 + 123, 
+    OPT_SOURCE_PREQUOTE = 10000 + 127, OPT_SOURCE_POSTQUOTE = 10000 + 128, 
+    OPT_IOCTLDATA = 10000 + 131, OPT_SOURCE_URL = 10000 + 132, 
+    OPT_SOURCE_QUOTE = 10000 + 133, OPT_FTP_ACCOUNT = 10000 + 134, 
+    OPT_COOKIELIST = 10000 + 135, OPT_FTP_ALTERNATIVE_TO_USER = 10000 + 147, 
+    OPT_LASTENTRY = 10000 + 148, OPT_WRITEFUNCTION = 20000 + 11, 
+    OPT_READFUNCTION = 20000 + 12, OPT_PROGRESSFUNCTION = 20000 + 56, 
+    OPT_HEADERFUNCTION = 20000 + 79, OPT_DEBUGFUNCTION = 20000 + 94, 
+    OPT_SSL_CTX_FUNCTION = 20000 + 108, OPT_IOCTLFUNCTION = 20000 + 130, 
+    OPT_CONV_FROM_NETWORK_FUNCTION = 20000 + 142, 
+    OPT_CONV_TO_NETWORK_FUNCTION = 20000 + 143, 
+    OPT_CONV_FROM_UTF8_FUNCTION = 20000 + 144, 
+    OPT_INFILESIZE_LARGE = 30000 + 115, OPT_RESUME_FROM_LARGE = 30000 + 116, 
+    OPT_MAXFILESIZE_LARGE = 30000 + 117, OPT_POSTFIELDSIZE_LARGE = 30000 + 120, 
+    OPT_MAX_SEND_SPEED_LARGE = 30000 + 145, 
+    OPT_MAX_RECV_SPEED_LARGE = 30000 + 146
+  THTTP_VERSION* = enum 
+    HTTP_VERSION_NONE, HTTP_VERSION_1_0, HTTP_VERSION_1_1, HTTP_VERSION_LAST
+  TNETRC_OPTION* = enum 
+    NETRC_IGNORED, NETRC_OPTIONAL, NETRC_REQUIRED, NETRC_LAST
+  TSSL_VERSION* = enum 
+    SSLVERSION_DEFAULT, SSLVERSION_TLSv1, SSLVERSION_SSLv2, SSLVERSION_SSLv3, 
+    SSLVERSION_LAST
+  TTIMECOND* = enum 
+    TIMECOND_NONE, TIMECOND_IFMODSINCE, TIMECOND_IFUNMODSINCE, TIMECOND_LASTMOD, 
+    TIMECOND_LAST
+  Tformoption* = enum 
+    FORM_NOTHING, FORM_COPYNAME, FORM_PTRNAME, FORM_NAMELENGTH, 
+    FORM_COPYCONTENTS, FORM_PTRCONTENTS, FORM_CONTENTSLENGTH, FORM_FILECONTENT, 
+    FORM_ARRAY, FORM_OBSOLETE, FORM_FILE, FORM_BUFFER, FORM_BUFFERPTR, 
+    FORM_BUFFERLENGTH, FORM_CONTENTTYPE, FORM_CONTENTHEADER, FORM_FILENAME, 
+    FORM_END, FORM_OBSOLETE2, FORM_LASTENTRY
+  Tforms*{.pure, final.} = object 
+    option*: Tformoption
+    value*: cstring
+
+  TFORMcode* = enum 
+    FORMADD_OK, FORMADD_MEMORY, FORMADD_OPTION_TWICE, FORMADD_NULL, 
+    FORMADD_UNKNOWN_OPTION, FORMADD_INCOMPLETE, FORMADD_ILLEGAL_ARRAY, 
+    FORMADD_DISABLED, FORMADD_LAST
+  Tformget_callback* = proc (arg: pointer, buf: cstring, length: int): int{.
+      cdecl.}
+  Tslist*{.pure, final.} = object 
+    data*: cstring
+    next*: Pslist
+
+  TINFO* = enum 
+    INFO_NONE = 0, INFO_LASTONE = 30, INFO_EFFECTIVE_URL = 0x00100000 + 1, 
+    INFO_CONTENT_TYPE = 0x00100000 + 18, INFO_PRIVATE = 0x00100000 + 21, 
+    INFO_FTP_ENTRY_PATH = 0x00100000 + 30, INFO_RESPONSE_CODE = 0x00200000 + 2, 
+    INFO_HEADER_SIZE = 0x00200000 + 11, INFO_REQUEST_SIZE = 0x00200000 + 12, 
+    INFO_SSL_VERIFYRESULT = 0x00200000 + 13, INFO_FILETIME = 0x00200000 + 14, 
+    INFO_REDIRECT_COUNT = 0x00200000 + 20, 
+    INFO_HTTP_CONNECTCODE = 0x00200000 + 22, 
+    INFO_HTTPAUTH_AVAIL = 0x00200000 + 23, 
+    INFO_PROXYAUTH_AVAIL = 0x00200000 + 24, INFO_OS_ERRNO = 0x00200000 + 25, 
+    INFO_NUM_CONNECTS = 0x00200000 + 26, INFO_LASTSOCKET = 0x00200000 + 29, 
+    INFO_TOTAL_TIME = 0x00300000 + 3, INFO_NAMELOOKUP_TIME = 0x00300000 + 4, 
+    INFO_CONNECT_TIME = 0x00300000 + 5, INFO_PRETRANSFER_TIME = 0x00300000 + 6, 
+    INFO_SIZE_UPLOAD = 0x00300000 + 7, INFO_SIZE_DOWNLOAD = 0x00300000 + 8, 
+    INFO_SPEED_DOWNLOAD = 0x00300000 + 9, INFO_SPEED_UPLOAD = 0x00300000 + 10, 
+    INFO_CONTENT_LENGTH_DOWNLOAD = 0x00300000 + 15, 
+    INFO_CONTENT_LENGTH_UPLOAD = 0x00300000 + 16, 
+    INFO_STARTTRANSFER_TIME = 0x00300000 + 17, 
+    INFO_REDIRECT_TIME = 0x00300000 + 19, INFO_SSL_ENGINES = 0x00400000 + 27, 
+    INFO_COOKIELIST = 0x00400000 + 28
+  Tclosepolicy* = enum 
+    CLOSEPOLICY_NONE, CLOSEPOLICY_OLDEST, CLOSEPOLICY_LEAST_RECENTLY_USED, 
+    CLOSEPOLICY_LEAST_TRAFFIC, CLOSEPOLICY_SLOWEST, CLOSEPOLICY_CALLBACK, 
+    CLOSEPOLICY_LAST
+  Tlock_data* = enum 
+    LOCK_DATA_NONE = 0, LOCK_DATA_SHARE, LOCK_DATA_COOKIE, LOCK_DATA_DNS, 
+    LOCK_DATA_SSL_SESSION, LOCK_DATA_CONNECT, LOCK_DATA_LAST
+  Tlock_access* = enum 
+    LOCK_ACCESS_NONE = 0, LOCK_ACCESS_SHARED = 1, LOCK_ACCESS_SINGLE = 2, 
+    LOCK_ACCESS_LAST
+  Tlock_function* = proc (handle: PCurl, data: Tlock_data,
+                          locktype: Tlock_access, 
+                          userptr: pointer){.cdecl.}
+  Tunlock_function* = proc (handle: PCurl, data: Tlock_data, userptr: pointer){.
+      cdecl.}
+  TSH* = pointer
+  TSHcode* = enum 
+    SHE_OK, SHE_BAD_OPTION, SHE_IN_USE, SHE_INVALID, SHE_NOMEM, SHE_LAST
+  TSHoption* = enum 
+    SHOPT_NONE, SHOPT_SHARE, SHOPT_UNSHARE, SHOPT_LOCKFUNC, SHOPT_UNLOCKFUNC, 
+    SHOPT_USERDATA, SHOPT_LAST
+  Tversion* = enum 
+    VERSION_FIRST, VERSION_SECOND, VERSION_THIRD, VERSION_LAST
+  Tversion_info_data*{.pure, final.} = object 
+    age*: Tversion
+    version*: cstring
+    version_num*: int32
+    host*: cstring
+    features*: int32
+    ssl_version*: cstring
+    ssl_version_num*: int32
+    libz_version*: cstring
+    protocols*: cstringArray
+    ares*: cstring
+    ares_num*: int32
+    libidn*: cstring
+    iconv_ver_num*: int32
+
+  TM* = pointer
+  Tsocket* = int32
+  TMcode* = enum 
+    M_CALL_MULTI_PERFORM = - 1, M_OK = 0, M_BAD_HANDLE, M_BAD_EASY_HANDLE, 
+    M_OUT_OF_MEMORY, M_INTERNAL_ERROR, M_BAD_SOCKET, M_UNKNOWN_OPTION, M_LAST
+  TMSGEnum* = enum 
+    MSG_NONE, MSG_DONE, MSG_LAST
+  TMsg*{.pure, final.} = object 
+    msg*: TMSGEnum
+    easy_handle*: PCurl
+    whatever*: pointer        #data : record
+                              #      case longint of
+                              #        0 : ( whatever : pointer );
+                              #        1 : ( result : CURLcode );
+                              #    end;
+  
+  Tsocket_callback* = proc (easy: PCurl, s: Tsocket, what: int32, 
+                            userp, socketp: pointer): int32{.cdecl.}
+  TMoption* = enum 
+    MOPT_SOCKETDATA = 10000 + 2, MOPT_LASTENTRY = 10000 + 3, 
+    MOPT_SOCKETFUNCTION = 20000 + 1
+
+const 
+  OPT_SSLKEYPASSWD* = OPT_SSLCERTPASSWD
+  AUTH_ANY* = not (0)
+  AUTH_BASIC* = 1 shl 0
+  AUTH_ANYSAFE* = not (AUTH_BASIC)
+  AUTH_DIGEST* = 1 shl 1
+  AUTH_GSSNEGOTIATE* = 1 shl 2
+  AUTH_NONE* = 0
+  AUTH_NTLM* = 1 shl 3
+  E_ALREADY_COMPLETE* = 99999
+  E_FTP_BAD_DOWNLOAD_RESUME* = E_BAD_DOWNLOAD_RESUME
+  E_FTP_PARTIAL_FILE* = E_PARTIAL_FILE
+  E_HTTP_NOT_FOUND* = E_HTTP_RETURNED_ERROR
+  E_HTTP_PORT_FAILED* = E_INTERFACE_FAILED
+  E_OPERATION_TIMEDOUT* = E_OPERATION_TIMEOUTED
+  ERROR_SIZE* = 256
+  FORMAT_OFF_T* = "%ld"
+  GLOBAL_NOTHING* = 0
+  GLOBAL_SSL* = 1 shl 0
+  GLOBAL_WIN32* = 1 shl 1
+  GLOBAL_ALL* = GLOBAL_SSL or GLOBAL_WIN32
+  GLOBAL_DEFAULT* = GLOBAL_ALL
+  INFO_DOUBLE* = 0x00300000
+  INFO_HTTP_CODE* = INFO_RESPONSE_CODE
+  INFO_LONG* = 0x00200000
+  INFO_MASK* = 0x000FFFFF
+  INFO_SLIST* = 0x00400000
+  INFO_STRING* = 0x00100000
+  INFO_TYPEMASK* = 0x00F00000
+  IPRESOLVE_V4* = 1
+  IPRESOLVE_V6* = 2
+  IPRESOLVE_WHATEVER* = 0
+  MAX_WRITE_SIZE* = 16384
+  M_CALL_MULTI_SOCKET* = M_CALL_MULTI_PERFORM
+  OPT_CLOSEFUNCTION* = - (5)
+  OPT_FTPASCII* = OPT_TRANSFERTEXT
+  OPT_HEADERDATA* = OPT_WRITEHEADER
+  OPT_HTTPREQUEST* = - (1)
+  OPT_MUTE* = - (2)
+  OPT_PASSWDDATA* = - (4)
+  OPT_PASSWDFUNCTION* = - (3)
+  OPT_PASV_HOST* = - (9)
+  OPT_READDATA* = OPT_INFILE
+  OPT_SOURCE_HOST* = - (6)
+  OPT_SOURCE_PATH* = - (7)
+  OPT_SOURCE_PORT* = - (8)
+  OPTTYPE_FUNCTIONPOINT* = 20000
+  OPTTYPE_LONG* = 0
+  OPTTYPE_OBJECTPOINT* = 10000
+  OPTTYPE_OFF_T* = 30000
+  OPT_WRITEDATA* = OPT_FILE
+  POLL_IN* = 1
+  POLL_INOUT* = 3
+  POLL_NONE* = 0
+  POLL_OUT* = 2
+  POLL_REMOVE* = 4
+  READFUNC_ABORT* = 0x10000000
+  SOCKET_BAD* = - (1)
+  SOCKET_TIMEOUT* = SOCKET_BAD
+  VERSION_ASYNCHDNS* = 1 shl 7
+  VERSION_CONV* = 1 shl 12
+  VERSION_DEBUG* = 1 shl 6
+  VERSION_GSSNEGOTIATE* = 1 shl 5
+  VERSION_IDN* = 1 shl 10
+  VERSION_IPV6* = 1 shl 0
+  VERSION_KERBEROS4* = 1 shl 1
+  VERSION_LARGEFILE* = 1 shl 9
+  VERSION_LIBZ* = 1 shl 3
+  VERSION_NOW* = VERSION_THIRD
+  VERSION_NTLM* = 1 shl 4
+  VERSION_SPNEGO* = 1 shl 8
+  VERSION_SSL* = 1 shl 2
+  VERSION_SSPI* = 1 shl 11
+  FILE_OFFSET_BITS* = 0
+  FILESIZEBITS* = 0
+  FUNCTIONPOINT* = OPTTYPE_FUNCTIONPOINT
+  HTTPPOST_BUFFER* = 1 shl 4
+  HTTPPOST_FILENAME* = 1 shl 0
+  HTTPPOST_PTRBUFFER* = 1 shl 5
+  HTTPPOST_PTRCONTENTS* = 1 shl 3
+  HTTPPOST_PTRNAME* = 1 shl 2
+  HTTPPOST_READFILE* = 1 shl 1
+  LIBCURL_VERSION* = "7.15.5"
+  LIBCURL_VERSION_MAJOR* = 7
+  LIBCURL_VERSION_MINOR* = 15
+  LIBCURL_VERSION_NUM* = 0x00070F05
+  LIBCURL_VERSION_PATCH* = 5
+
+proc strequal*(s1, s2: cstring): int32{.cdecl, dynlib: libname, 
+                                        importc: "curl_strequal".}
+proc strnequal*(s1, s2: cstring, n: int): int32{.cdecl, dynlib: libname, 
+    importc: "curl_strnequal".}
+proc formadd*(httppost, last_post: PPcurl_httppost): TFORMcode{.cdecl, varargs, 
+    dynlib: libname, importc: "curl_formadd".}
+proc formget*(form: Phttppost, arg: pointer, append: Tformget_callback): int32{.
+    cdecl, dynlib: libname, importc: "curl_formget".}
+proc formfree*(form: Phttppost){.cdecl, dynlib: libname, 
+                                 importc: "curl_formfree".}
+proc getenv*(variable: cstring): cstring{.cdecl, dynlib: libname, 
+    importc: "curl_getenv".}
+proc version*(): cstring{.cdecl, dynlib: libname, importc: "curl_version".}
+proc easy_escape*(handle: PCurl, str: cstring, len: int32): cstring{.cdecl, 
+    dynlib: libname, importc: "curl_easy_escape".}
+proc escape*(str: cstring, len: int32): cstring{.cdecl, dynlib: libname, 
+    importc: "curl_escape".}
+proc easy_unescape*(handle: PCurl, str: cstring, len: int32, outlength: var int32): cstring{.
+    cdecl, dynlib: libname, importc: "curl_easy_unescape".}
+proc unescape*(str: cstring, len: int32): cstring{.cdecl, dynlib: libname, 
+    importc: "curl_unescape".}
+proc free*(p: pointer){.cdecl, dynlib: libname, importc: "curl_free".}
+proc global_init*(flags: int32): Tcode{.cdecl, dynlib: libname, 
+                                        importc: "curl_global_init".}
+proc global_init_mem*(flags: int32, m: Tmalloc_callback, f: Tfree_callback, 
+                      r: Trealloc_callback, s: Tstrdup_callback, 
+                      c: Tcalloc_callback): Tcode{.cdecl, dynlib: libname, 
+    importc: "curl_global_init_mem".}
+proc global_cleanup*(){.cdecl, dynlib: libname, importc: "curl_global_cleanup".}
+proc slist_append*(slist: Pslist, p: cstring): Pslist{.cdecl, dynlib: libname, 
+    importc: "curl_slist_append".}
+proc slist_free_all*(para1: Pslist){.cdecl, dynlib: libname, 
+                                     importc: "curl_slist_free_all".}
+proc getdate*(p: cstring, unused: ptr Time): Time{.cdecl, dynlib: libname, 
+    importc: "curl_getdate".}
+proc share_init*(): PSH{.cdecl, dynlib: libname, importc: "curl_share_init".}
+proc share_setopt*(para1: PSH, option: TSHoption): TSHcode{.cdecl, varargs, 
+    dynlib: libname, importc: "curl_share_setopt".}
+proc share_cleanup*(para1: PSH): TSHcode{.cdecl, dynlib: libname, 
+    importc: "curl_share_cleanup".}
+proc version_info*(para1: Tversion): Pversion_info_data{.cdecl, dynlib: libname, 
+    importc: "curl_version_info".}
+proc easy_strerror*(para1: Tcode): cstring{.cdecl, dynlib: libname, 
+    importc: "curl_easy_strerror".}
+proc share_strerror*(para1: TSHcode): cstring{.cdecl, dynlib: libname, 
+    importc: "curl_share_strerror".}
+proc easy_init*(): PCurl{.cdecl, dynlib: libname, importc: "curl_easy_init".}
+proc easy_setopt*(curl: PCurl, option: Toption): Tcode{.cdecl, varargs, dynlib: libname, 
+    importc: "curl_easy_setopt".}
+proc easy_perform*(curl: PCurl): Tcode{.cdecl, dynlib: libname, 
+                                importc: "curl_easy_perform".}
+proc easy_cleanup*(curl: PCurl){.cdecl, dynlib: libname, importc: "curl_easy_cleanup".}
+proc easy_getinfo*(curl: PCurl, info: TINFO): Tcode{.cdecl, varargs, dynlib: libname, 
+    importc: "curl_easy_getinfo".}
+proc easy_duphandle*(curl: PCurl): PCurl{.cdecl, dynlib: libname, 
+                              importc: "curl_easy_duphandle".}
+proc easy_reset*(curl: PCurl){.cdecl, dynlib: libname, importc: "curl_easy_reset".}
+proc multi_init*(): PM{.cdecl, dynlib: libname, importc: "curl_multi_init".}
+proc multi_add_handle*(multi_handle: PM, handle: PCurl): TMcode{.cdecl, 
+    dynlib: libname, importc: "curl_multi_add_handle".}
+proc multi_remove_handle*(multi_handle: PM, handle: PCurl): TMcode{.cdecl, 
+    dynlib: libname, importc: "curl_multi_remove_handle".}
+proc multi_fdset*(multi_handle: PM, read_fd_set: Pfd_set, write_fd_set: Pfd_set, 
+                  exc_fd_set: Pfd_set, max_fd: var int32): TMcode{.cdecl, 
+    dynlib: libname, importc: "curl_multi_fdset".}
+proc multi_perform*(multi_handle: PM, running_handles: var int32): TMcode{.
+    cdecl, dynlib: libname, importc: "curl_multi_perform".}
+proc multi_cleanup*(multi_handle: PM): TMcode{.cdecl, dynlib: libname, 
+    importc: "curl_multi_cleanup".}
+proc multi_info_read*(multi_handle: PM, msgs_in_queue: var int32): PMsg{.cdecl, 
+    dynlib: libname, importc: "curl_multi_info_read".}
+proc multi_strerror*(para1: TMcode): cstring{.cdecl, dynlib: libname, 
+    importc: "curl_multi_strerror".}
+proc multi_socket*(multi_handle: PM, s: Tsocket, running_handles: var int32): TMcode{.
+    cdecl, dynlib: libname, importc: "curl_multi_socket".}
+proc multi_socket_all*(multi_handle: PM, running_handles: var int32): TMcode{.
+    cdecl, dynlib: libname, importc: "curl_multi_socket_all".}
+proc multi_timeout*(multi_handle: PM, milliseconds: var int32): TMcode{.cdecl, 
+    dynlib: libname, importc: "curl_multi_timeout".}
+proc multi_setopt*(multi_handle: PM, option: TMoption): TMcode{.cdecl, varargs, 
+    dynlib: libname, importc: "curl_multi_setopt".}
+proc multi_assign*(multi_handle: PM, sockfd: Tsocket, sockp: pointer): TMcode{.
+    cdecl, dynlib: libname, importc: "curl_multi_assign".}
diff --git a/lib/wrappers/libffi/common/ffi.h b/lib/wrappers/libffi/common/ffi.h
new file mode 100644
index 000000000..07d650eac
--- /dev/null
+++ b/lib/wrappers/libffi/common/ffi.h
@@ -0,0 +1,331 @@
+/* -----------------------------------------------------------------*-C-*-
+   libffi 2.00-beta - Copyright (c) 1996-2003  Red Hat, Inc.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+
+   ----------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------
+   The basic API is described in the README file.
+
+   The raw API is designed to bypass some of the argument packing
+   and unpacking on architectures for which it can be avoided.
+
+   The closure API allows interpreted functions to be packaged up
+   inside a C function pointer, so that they can be called as C functions,
+   with no understanding on the client side that they are interpreted.
+   It can also be used in other cases in which it is necessary to package
+   up a user specified parameter and a function pointer as a single
+   function pointer.
+
+   The closure API must be implemented in order to get its functionality,
+   e.g. for use by gij.  Routines are provided to emulate the raw API
+   if the underlying platform doesn't allow faster implementation.
+
+   More details on the raw and cloure API can be found in:
+
+   http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
+
+   and
+
+   http://gcc.gnu.org/ml/java/1999-q3/msg00174.html
+   -------------------------------------------------------------------- */
+
+#ifndef LIBFFI_H
+#define LIBFFI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Specify which architecture libffi is configured for. */
+//XXX #define X86
+
+/* ---- System configuration information --------------------------------- */
+
+#include <ffitarget.h>
+
+#ifndef LIBFFI_ASM
+
+#include <stddef.h>
+#include <limits.h>
+
+/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example).
+   But we can find it either under the correct ANSI name, or under GNU
+   C's internal name.  */
+#ifdef LONG_LONG_MAX
+# define FFI_LONG_LONG_MAX LONG_LONG_MAX
+#else
+# ifdef LLONG_MAX
+#  define FFI_LONG_LONG_MAX LLONG_MAX
+# else
+#  ifdef __GNUC__
+#   define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
+#  endif
+#  ifdef _MSC_VER
+#   define FFI_LONG_LONG_MAX _I64_MAX
+#  endif
+# endif
+#endif
+
+#if SCHAR_MAX == 127
+# define ffi_type_uchar                ffi_type_uint8
+# define ffi_type_schar                ffi_type_sint8
+#else
+ #error "char size not supported"
+#endif
+
+#if SHRT_MAX == 32767
+# define ffi_type_ushort       ffi_type_uint16
+# define ffi_type_sshort       ffi_type_sint16
+#elif SHRT_MAX == 2147483647
+# define ffi_type_ushort       ffi_type_uint32
+# define ffi_type_sshort       ffi_type_sint32
+#else
+ #error "short size not supported"
+#endif
+
+#if INT_MAX == 32767
+# define ffi_type_uint         ffi_type_uint16
+# define ffi_type_sint         ffi_type_sint16
+#elif INT_MAX == 2147483647
+# define ffi_type_uint         ffi_type_uint32
+# define ffi_type_sint         ffi_type_sint32
+#elif INT_MAX == 9223372036854775807
+# define ffi_type_uint         ffi_type_uint64
+# define ffi_type_sint         ffi_type_sint64
+#else
+ #error "int size not supported"
+#endif
+
+#define ffi_type_ulong         ffi_type_uint64
+#define ffi_type_slong         ffi_type_sint64
+#if LONG_MAX == 2147483647
+# if FFI_LONG_LONG_MAX != 9223372036854775807
+  #error "no 64-bit data type supported"
+# endif
+#elif LONG_MAX != 9223372036854775807
+ #error "long size not supported"
+#endif
+
+/* The closure code assumes that this works on pointers, i.e. a size_t	*/
+/* can hold a pointer.							*/
+
+typedef struct _ffi_type
+{
+  size_t size;
+  unsigned short alignment;
+  unsigned short type;
+  /*@null@*/ struct _ffi_type **elements;
+} ffi_type;
+
+/* These are defined in types.c */
+extern const ffi_type ffi_type_void;
+extern const ffi_type ffi_type_uint8;
+extern const ffi_type ffi_type_sint8;
+extern const ffi_type ffi_type_uint16;
+extern const ffi_type ffi_type_sint16;
+extern const ffi_type ffi_type_uint32;
+extern const ffi_type ffi_type_sint32;
+extern const ffi_type ffi_type_uint64;
+extern const ffi_type ffi_type_sint64;
+extern const ffi_type ffi_type_float;
+extern const ffi_type ffi_type_double;
+extern const ffi_type ffi_type_longdouble;
+extern const ffi_type ffi_type_pointer;
+
+
+typedef enum {
+  FFI_OK = 0,
+  FFI_BAD_TYPEDEF,
+  FFI_BAD_ABI 
+} ffi_status;
+
+typedef unsigned FFI_TYPE;
+
+typedef struct {
+  ffi_abi abi;
+  unsigned nargs;
+  /*@dependent@*/ ffi_type **arg_types;
+  /*@dependent@*/ ffi_type *rtype;
+  unsigned bytes;
+  unsigned flags;
+#ifdef FFI_EXTRA_CIF_FIELDS
+  FFI_EXTRA_CIF_FIELDS;
+#endif
+} ffi_cif;
+
+/* ---- Definitions for the raw API -------------------------------------- */
+
+#ifdef _WIN64
+#define FFI_SIZEOF_ARG 8
+#else
+#define FFI_SIZEOF_ARG 4
+#endif
+
+typedef union {
+  ffi_sarg  sint;
+  ffi_arg   uint;
+  float	    flt;
+  char      data[FFI_SIZEOF_ARG];
+  void*     ptr;
+} ffi_raw;
+
+void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, 
+		   void (*fn)(), 
+		   /*@out@*/ void *rvalue, 
+		   /*@dependent@*/ ffi_raw *avalue);
+
+void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+size_t ffi_raw_size (ffi_cif *cif);
+
+/* This is analogous to the raw API, except it uses Java parameter	*/
+/* packing, even on 64-bit machines.  I.e. on 64-bit machines		*/
+/* longs and doubles are followed by an empty 64-bit word.		*/
+
+void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, 
+		        void (*fn)(), 
+		        /*@out@*/ void *rvalue, 
+		        /*@dependent@*/ ffi_raw *avalue);
+
+void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
+void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
+size_t ffi_java_raw_size (ffi_cif *cif);
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#if FFI_CLOSURES
+
+typedef struct {
+  char tramp[FFI_TRAMPOLINE_SIZE];
+  ffi_cif   *cif;
+  void     (*fun)(ffi_cif*,void*,void**,void*);
+  void      *user_data;
+} ffi_closure;
+
+void ffi_closure_free(void *);
+void *ffi_closure_alloc (size_t size, void **code);
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure*,
+		  ffi_cif *,
+		  void (*fun)(ffi_cif*,void*,void**,void*),
+		  void *user_data,
+		  void *codeloc);
+
+typedef struct {
+  char tramp[FFI_TRAMPOLINE_SIZE];
+
+  ffi_cif   *cif;
+
+#if !FFI_NATIVE_RAW_API
+
+  /* if this is enabled, then a raw closure has the same layout 
+     as a regular closure.  We use this to install an intermediate 
+     handler to do the transaltion, void** -> ffi_raw*. */
+
+  void     (*translate_args)(ffi_cif*,void*,void**,void*);
+  void      *this_closure;
+
+#endif
+
+  void     (*fun)(ffi_cif*,void*,ffi_raw*,void*);
+  void      *user_data;
+
+} ffi_raw_closure;
+
+ffi_status
+ffi_prep_raw_closure (ffi_raw_closure*,
+		      ffi_cif *cif,
+		      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+		      void *user_data);
+
+ffi_status
+ffi_prep_java_raw_closure (ffi_raw_closure*,
+		           ffi_cif *cif,
+		           void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+		           void *user_data);
+
+#endif /* FFI_CLOSURES */
+
+/* ---- Public interface definition -------------------------------------- */
+
+ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, 
+			ffi_abi abi,
+			unsigned int nargs, 
+			/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, 
+			/*@dependent@*/ ffi_type **atypes);
+
+void
+ffi_call(/*@dependent@*/ ffi_cif *cif, 
+	 void (*fn)(), 
+	 /*@out@*/ void *rvalue, 
+	 /*@dependent@*/ void **avalue);
+
+/* Useful for eliminating compiler warnings */
+#define FFI_FN(f) ((void (*)())f)
+
+/* ---- Definitions shared with assembly code ---------------------------- */
+
+#endif
+
+/* If these change, update src/mips/ffitarget.h. */
+#define FFI_TYPE_VOID       0    
+#define FFI_TYPE_INT        1
+#define FFI_TYPE_FLOAT      2    
+#define FFI_TYPE_DOUBLE     3
+#if 1
+#define FFI_TYPE_LONGDOUBLE 4
+#else
+#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
+#endif
+#define FFI_TYPE_UINT8      5   
+#define FFI_TYPE_SINT8      6
+#define FFI_TYPE_UINT16     7 
+#define FFI_TYPE_SINT16     8
+#define FFI_TYPE_UINT32     9
+#define FFI_TYPE_SINT32     10
+#define FFI_TYPE_UINT64     11
+#define FFI_TYPE_SINT64     12
+#define FFI_TYPE_STRUCT     13
+#define FFI_TYPE_POINTER    14
+
+/* This should always refer to the last type code (for sanity checks) */
+#define FFI_TYPE_LAST       FFI_TYPE_POINTER
+
+#define FFI_HIDDEN /* no idea what the origial definition looks like ... */
+
+#ifdef __GNUC__
+#  define LIKELY(x) __builtin_expect(x, 1)
+#  define UNLIKELY(x) __builtin_expect(x, 0)
+#else
+#  define LIKELY(x) (x)
+#  define UNLIKELY(x) (x)
+#endif
+
+#define MAYBE_UNUSED
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lib/wrappers/libffi/common/ffi_common.h b/lib/wrappers/libffi/common/ffi_common.h
new file mode 100644
index 000000000..43fb83b48
--- /dev/null
+++ b/lib/wrappers/libffi/common/ffi_common.h
@@ -0,0 +1,77 @@
+/* -----------------------------------------------------------------------
+   ffi_common.h - Copyright (c) 1996  Red Hat, Inc.
+
+   Common internal definitions and macros. Only necessary for building
+   libffi.
+   ----------------------------------------------------------------------- */
+
+#ifndef FFI_COMMON_H
+#define FFI_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <fficonfig.h>
+#include <malloc.h>
+
+/* Check for the existence of memcpy. */
+#if STDC_HEADERS
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+#  define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#if defined(FFI_DEBUG) 
+#include <stdio.h>
+#endif
+
+#ifdef FFI_DEBUG
+/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line);
+void ffi_stop_here(void);
+void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line);
+
+#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__))
+#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l)))
+#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__)
+#else
+#define FFI_ASSERT(x) 
+#define FFI_ASSERT_AT(x, f, l)
+#define FFI_ASSERT_VALID_TYPE(x)
+#endif
+
+#define ALIGN(v, a)  (((((size_t) (v))-1) | ((a)-1))+1)
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
+
+/* Extended cif, used in callback from assembly routine */
+typedef struct
+{
+  /*@dependent@*/ ffi_cif *cif;
+  /*@dependent@*/ void *rvalue;
+  /*@dependent@*/ void **avalue;
+} extended_cif;
+
+/* Terse sized type definitions.  */
+typedef unsigned int UINT8  __attribute__((__mode__(__QI__)));
+typedef signed int   SINT8  __attribute__((__mode__(__QI__)));
+typedef unsigned int UINT16 __attribute__((__mode__(__HI__)));
+typedef signed int   SINT16 __attribute__((__mode__(__HI__)));
+typedef unsigned int UINT32 __attribute__((__mode__(__SI__)));
+typedef signed int   SINT32 __attribute__((__mode__(__SI__)));
+typedef unsigned int UINT64 __attribute__((__mode__(__DI__)));
+typedef signed int   SINT64 __attribute__((__mode__(__DI__)));
+
+typedef float FLOAT32;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/lib/wrappers/libffi/common/fficonfig.h b/lib/wrappers/libffi/common/fficonfig.h
new file mode 100644
index 000000000..c14f653ec
--- /dev/null
+++ b/lib/wrappers/libffi/common/fficonfig.h
@@ -0,0 +1,96 @@
+/* fficonfig.h.  Originally created by configure, now hand_maintained for MSVC. */
+
+/* fficonfig.h.  Generated automatically by configure.  */
+/* fficonfig.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define this for MSVC, but not for mingw32! */
+#ifdef _MSC_VER
+#define __attribute__(x) /* */
+#endif
+#define alloca _alloca
+
+/*----------------------------------------------------------------*/
+
+/* Define if using alloca.c.  */
+/* #undef C_ALLOCA */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have alloca, as a function or macro.  */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+/* #define HAVE_ALLOCA_H 1 */
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you have the memcpy function.  */
+#define HAVE_MEMCPY 1
+
+/* Define if read-only mmap of a plain file works. */
+//#define HAVE_MMAP_FILE 1
+
+/* Define if mmap of /dev/zero works. */
+//#define HAVE_MMAP_DEV_ZERO 1
+
+/* Define if mmap with MAP_ANON(YMOUS) works. */
+//#define HAVE_MMAP_ANON 1
+
+/* The number of bytes in type double */
+#define SIZEOF_DOUBLE 8
+
+/* The number of bytes in type long double */
+#define SIZEOF_LONG_DOUBLE 12
+
+/* Define if you have the long double type and it is bigger than a double */
+#define HAVE_LONG_DOUBLE 1
+
+/* whether byteorder is bigendian */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define if the host machine stores words of multi-word integers in
+   big-endian order. */
+/* #undef HOST_WORDS_BIG_ENDIAN */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#define BYTEORDER 1234
+
+/* Define if your assembler and linker support unaligned PC relative relocs. */
+/* #undef HAVE_AS_SPARC_UA_PCREL */
+
+/* Define if your assembler supports .register. */
+/* #undef HAVE_AS_REGISTER_PSEUDO_OP */
+
+/* Define if .eh_frame sections should be read-only. */
+/* #undef HAVE_RO_EH_FRAME */
+
+/* Define to the flags needed for the .section .eh_frame directive. */
+/* #define EH_FRAME_FLAGS "aw" */
+
+/* Define to the flags needed for the .section .eh_frame directive. */
+/* #define EH_FRAME_FLAGS "aw" */
+
+/* Define this if you want extra debugging. */
+/* #undef FFI_DEBUG */
+
+/* Define this is you do not want support for aggregate types. */
+/* #undef FFI_NO_STRUCTS */
+
+/* Define this is you do not want support for the raw API. */
+/* #undef FFI_NO_RAW_API */
+
+/* Define this if you are using Purify and want to suppress spurious messages. */
+/* #undef USING_PURIFY */
+
diff --git a/lib/wrappers/libffi/common/ffitarget.h b/lib/wrappers/libffi/common/ffitarget.h
new file mode 100644
index 000000000..d8d60f2e7
--- /dev/null
+++ b/lib/wrappers/libffi/common/ffitarget.h
@@ -0,0 +1,150 @@
+/* -----------------------------------------------------------------*-C-*-
+   ffitarget.h - Copyright (c) 2012  Anthony Green
+                 Copyright (c) 1996-2003, 2010  Red Hat, Inc.
+                 Copyright (C) 2008  Free Software Foundation, Inc.
+
+   Target configuration macros for x86 and x86-64.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+
+   ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_H
+#error "Please do not include ffitarget.h directly into your source.  Use ffi.h instead."
+#endif
+
+/* ---- System specific configurations ----------------------------------- */
+
+/* For code common to all platforms on x86 and x86_64. */
+#define X86_ANY
+
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
+#  if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64)
+#    define X86_64
+#    define X86_WIN64
+#  else
+#    define X86_32
+#    define X86_WIN32
+#  endif
+#endif
+
+#if defined (X86_64) && defined (__i386__)
+#undef X86_64
+#define X86
+#endif
+
+#ifdef X86_WIN64
+#define FFI_SIZEOF_ARG 8
+#define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */
+#endif
+
+/* ---- Generic type definitions ----------------------------------------- */
+
+#ifndef LIBFFI_ASM
+#ifdef X86_WIN64
+#ifdef _MSC_VER
+typedef unsigned __int64       ffi_arg;
+typedef __int64                ffi_sarg;
+#else
+typedef unsigned long long     ffi_arg;
+typedef long long              ffi_sarg;
+#endif
+#else
+#if defined __x86_64__ && defined __ILP32__
+#define FFI_SIZEOF_ARG 8
+#define FFI_SIZEOF_JAVA_RAW  4
+typedef unsigned long long     ffi_arg;
+typedef long long              ffi_sarg;
+#else
+typedef unsigned long          ffi_arg;
+typedef signed long            ffi_sarg;
+#endif
+#endif
+
+typedef enum ffi_abi {
+  FFI_FIRST_ABI = 0,
+
+  /* ---- Intel x86 Win32 ---------- */
+#ifdef X86_WIN32
+  FFI_SYSV,
+  FFI_STDCALL,
+  FFI_THISCALL,
+  FFI_FASTCALL,
+  FFI_MS_CDECL,
+  FFI_LAST_ABI,
+#ifdef _MSC_VER
+  FFI_DEFAULT_ABI = FFI_MS_CDECL
+#else
+  FFI_DEFAULT_ABI = FFI_SYSV
+#endif
+
+#elif defined(X86_WIN64)
+  FFI_WIN64,
+  FFI_LAST_ABI,
+  FFI_DEFAULT_ABI = FFI_WIN64
+
+#else
+  /* ---- Intel x86 and AMD x86-64 - */
+  FFI_SYSV,
+  FFI_UNIX64,   /* Unix variants all use the same ABI for x86-64  */
+  FFI_LAST_ABI,
+#if defined(__i386__) || defined(__i386)
+  FFI_DEFAULT_ABI = FFI_SYSV
+#else
+  FFI_DEFAULT_ABI = FFI_UNIX64
+#endif
+#endif
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
+#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
+#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
+#define FFI_TYPE_MS_STRUCT       (FFI_TYPE_LAST + 4)
+
+#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
+#define FFI_TRAMPOLINE_SIZE 24
+#define FFI_NATIVE_RAW_API 0
+#else
+#ifdef X86_WIN32
+#define FFI_TRAMPOLINE_SIZE 52
+#else
+#ifdef X86_WIN64
+#define FFI_TRAMPOLINE_SIZE 29
+#define FFI_NATIVE_RAW_API 0
+#define FFI_NO_RAW_API 1
+#else
+#define FFI_TRAMPOLINE_SIZE 10
+#endif
+#endif
+#ifndef X86_WIN64
+#define FFI_NATIVE_RAW_API 1	/* x86 has native raw api support */
+#endif
+#endif
+
+#endif
+
diff --git a/lib/wrappers/libffi/common/malloc_closure.c b/lib/wrappers/libffi/common/malloc_closure.c
new file mode 100644
index 000000000..5b33aa4ca
--- /dev/null
+++ b/lib/wrappers/libffi/common/malloc_closure.c
@@ -0,0 +1,110 @@
+#include <ffi.h>
+#ifdef MS_WIN32
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#include <unistd.h>
+# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#  define MAP_ANONYMOUS MAP_ANON
+# endif
+#endif
+#include "ctypes.h"
+
+/* BLOCKSIZE can be adjusted.  Larger blocksize will take a larger memory
+   overhead, but allocate less blocks from the system.  It may be that some
+   systems have a limit of how many mmap'd blocks can be open.
+*/
+
+#define BLOCKSIZE _pagesize
+
+/* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */
+
+/******************************************************************/
+
+typedef union _tagITEM {
+    ffi_closure closure;
+    union _tagITEM *next;
+} ITEM;
+
+static ITEM *free_list;
+static int _pagesize;
+
+static void more_core(void)
+{
+    ITEM *item;
+    int count, i;
+
+/* determine the pagesize */
+#ifdef MS_WIN32
+    if (!_pagesize) {
+        SYSTEM_INFO systeminfo;
+        GetSystemInfo(&systeminfo);
+        _pagesize = systeminfo.dwPageSize;
+    }
+#else
+    if (!_pagesize) {
+#ifdef _SC_PAGESIZE
+        _pagesize = sysconf(_SC_PAGESIZE);
+#else
+        _pagesize = getpagesize();
+#endif
+    }
+#endif
+
+    /* calculate the number of nodes to allocate */
+    count = BLOCKSIZE / sizeof(ITEM);
+
+    /* allocate a memory block */
+#ifdef MS_WIN32
+    item = (ITEM *)VirtualAlloc(NULL,
+                                           count * sizeof(ITEM),
+                                           MEM_COMMIT,
+                                           PAGE_EXECUTE_READWRITE);
+    if (item == NULL)
+        return;
+#else
+    item = (ITEM *)mmap(NULL,
+                        count * sizeof(ITEM),
+                        PROT_READ | PROT_WRITE | PROT_EXEC,
+                        MAP_PRIVATE | MAP_ANONYMOUS,
+                        -1,
+                        0);
+    if (item == (void *)MAP_FAILED)
+        return;
+#endif
+
+#ifdef MALLOC_CLOSURE_DEBUG
+    printf("block at %p allocated (%d bytes), %d ITEMs\n",
+           item, count * sizeof(ITEM), count);
+#endif
+    /* put them into the free list */
+    for (i = 0; i < count; ++i) {
+        item->next = free_list;
+        free_list = item;
+        ++item;
+    }
+}
+
+/******************************************************************/
+
+/* put the item back into the free list */
+void ffi_closure_free(void *p)
+{
+    ITEM *item = (ITEM *)p;
+    item->next = free_list;
+    free_list = item;
+}
+
+/* return one item from the free list, allocating more if needed */
+void *ffi_closure_alloc(size_t ignored, void** codeloc)
+{
+    ITEM *item;
+    if (!free_list)
+        more_core();
+    if (!free_list)
+        return NULL;
+    item = free_list;
+    free_list = item->next;
+    *codeloc = (void *)item;
+    return (void *)item;
+}
diff --git a/lib/wrappers/libffi/common/raw_api.c b/lib/wrappers/libffi/common/raw_api.c
new file mode 100644
index 000000000..ce21372e2
--- /dev/null
+++ b/lib/wrappers/libffi/common/raw_api.c
@@ -0,0 +1,254 @@
+/* -----------------------------------------------------------------------
+   raw_api.c - Copyright (c) 1999, 2008  Red Hat, Inc.
+
+   Author: Kresten Krab Thorup <krab@gnu.org>
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+/* This file defines generic functions for use with the raw api. */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#if !FFI_NO_RAW_API
+
+size_t
+ffi_raw_size (ffi_cif *cif)
+{
+  size_t result = 0;
+  int i;
+
+  ffi_type **at = cif->arg_types;
+
+  for (i = cif->nargs-1; i >= 0; i--, at++)
+    {
+#if !FFI_NO_STRUCTS
+      if ((*at)->type == FFI_TYPE_STRUCT)
+	result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
+      else
+#endif
+	result += ALIGN ((*at)->size, FFI_SIZEOF_ARG);
+    }
+
+  return result;
+}
+
+
+void
+ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
+{
+  unsigned i;
+  ffi_type **tp = cif->arg_types;
+
+#if WORDS_BIGENDIAN
+
+  for (i = 0; i < cif->nargs; i++, tp++, args++)
+    {	  
+      switch ((*tp)->type)
+	{
+	case FFI_TYPE_UINT8:
+	case FFI_TYPE_SINT8:
+	  *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 1);
+	  break;
+	  
+	case FFI_TYPE_UINT16:
+	case FFI_TYPE_SINT16:
+	  *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 2);
+	  break;
+
+#if FFI_SIZEOF_ARG >= 4	  
+	case FFI_TYPE_UINT32:
+	case FFI_TYPE_SINT32:
+	  *args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 4);
+	  break;
+#endif
+	
+#if !FFI_NO_STRUCTS  
+	case FFI_TYPE_STRUCT:
+	  *args = (raw++)->ptr;
+	  break;
+#endif
+
+	case FFI_TYPE_POINTER:
+	  *args = (void*) &(raw++)->ptr;
+	  break;
+	  
+	default:
+	  *args = raw;
+	  raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+	}
+    }
+
+#else /* WORDS_BIGENDIAN */
+
+#if !PDP
+
+  /* then assume little endian */
+  for (i = 0; i < cif->nargs; i++, tp++, args++)
+    {	  
+#if !FFI_NO_STRUCTS
+      if ((*tp)->type == FFI_TYPE_STRUCT)
+	{
+	  *args = (raw++)->ptr;
+	}
+      else
+#endif
+	{
+	  *args = (void*) raw;
+	  raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
+	}
+    }
+
+#else
+#error "pdp endian not supported"
+#endif /* ! PDP */
+
+#endif /* WORDS_BIGENDIAN */
+}
+
+void
+ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
+{
+  unsigned i;
+  ffi_type **tp = cif->arg_types;
+
+  for (i = 0; i < cif->nargs; i++, tp++, args++)
+    {	  
+      switch ((*tp)->type)
+	{
+	case FFI_TYPE_UINT8:
+	  (raw++)->uint = *(UINT8*) (*args);
+	  break;
+
+	case FFI_TYPE_SINT8:
+	  (raw++)->sint = *(SINT8*) (*args);
+	  break;
+
+	case FFI_TYPE_UINT16:
+	  (raw++)->uint = *(UINT16*) (*args);
+	  break;
+
+	case FFI_TYPE_SINT16:
+	  (raw++)->sint = *(SINT16*) (*args);
+	  break;
+
+#if FFI_SIZEOF_ARG >= 4
+	case FFI_TYPE_UINT32:
+	  (raw++)->uint = *(UINT32*) (*args);
+	  break;
+
+	case FFI_TYPE_SINT32:
+	  (raw++)->sint = *(SINT32*) (*args);
+	  break;
+#endif
+
+#if !FFI_NO_STRUCTS
+	case FFI_TYPE_STRUCT:
+	  (raw++)->ptr = *args;
+	  break;
+#endif
+
+	case FFI_TYPE_POINTER:
+	  (raw++)->ptr = **(void***) args;
+	  break;
+
+	default:
+	  memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
+	  raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
+	}
+    }
+}
+
+#if !FFI_NATIVE_RAW_API
+
+
+/* This is a generic definition of ffi_raw_call, to be used if the
+ * native system does not provide a machine-specific implementation.
+ * Having this, allows code to be written for the raw API, without
+ * the need for system-specific code to handle input in that format;
+ * these following couple of functions will handle the translation forth
+ * and back automatically. */
+
+void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *raw)
+{
+  void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
+  ffi_raw_to_ptrarray (cif, raw, avalue);
+  ffi_call (cif, fn, rvalue, avalue);
+}
+
+#if FFI_CLOSURES		/* base system provides closures */
+
+static void
+ffi_translate_args (ffi_cif *cif, void *rvalue,
+		    void **avalue, void *user_data)
+{
+  ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
+  ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
+
+  ffi_ptrarray_to_raw (cif, avalue, raw);
+  (*cl->fun) (cif, rvalue, raw, cl->user_data);
+}
+
+ffi_status
+ffi_prep_raw_closure_loc (ffi_raw_closure* cl,
+			  ffi_cif *cif,
+			  void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+			  void *user_data,
+			  void *codeloc)
+{
+  ffi_status status;
+
+  status = ffi_prep_closure_loc ((ffi_closure*) cl,
+				 cif,
+				 &ffi_translate_args,
+				 codeloc,
+				 codeloc);
+  if (status == FFI_OK)
+    {
+      cl->fun       = fun;
+      cl->user_data = user_data;
+    }
+
+  return status;
+}
+
+#endif /* FFI_CLOSURES */
+#endif /* !FFI_NATIVE_RAW_API */
+
+#if FFI_CLOSURES
+
+/* Again, here is the generic version of ffi_prep_raw_closure, which
+ * will install an intermediate "hub" for translation of arguments from
+ * the pointer-array format, to the raw format */
+
+ffi_status
+ffi_prep_raw_closure (ffi_raw_closure* cl,
+		      ffi_cif *cif,
+		      void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+		      void *user_data)
+{
+  return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl);
+}
+
+#endif /* FFI_CLOSURES */
+
+#endif /* !FFI_NO_RAW_API */
diff --git a/lib/wrappers/libffi/gcc/closures.c b/lib/wrappers/libffi/gcc/closures.c
new file mode 100644
index 000000000..c0ee06891
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/closures.c
@@ -0,0 +1,627 @@
+/* -----------------------------------------------------------------------
+   closures.c - Copyright (c) 2007, 2009, 2010  Red Hat, Inc.
+                Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc
+                Copyright (c) 2011 Plausible Labs Cooperative, Inc.
+
+   Code to allocate and deallocate memory for closures.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#if defined __linux__ && !defined _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
+# if __gnu_linux__
+/* This macro indicates it may be forbidden to map anonymous memory
+   with both write and execute permission.  Code compiled when this
+   option is defined will attempt to map such pages once, but if it
+   fails, it falls back to creating a temporary file in a writable and
+   executable filesystem and mapping pages from it into separate
+   locations in the virtual memory space, one location writable and
+   another executable.  */
+#  define FFI_MMAP_EXEC_WRIT 1
+#  define HAVE_MNTENT 1
+# endif
+# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)
+/* Windows systems may have Data Execution Protection (DEP) enabled, 
+   which requires the use of VirtualMalloc/VirtualFree to alloc/free
+   executable memory. */
+#  define FFI_MMAP_EXEC_WRIT 1
+# endif
+#endif
+
+#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
+# ifdef __linux__
+/* When defined to 1 check for SELinux and if SELinux is active,
+   don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
+   might cause audit messages.  */
+#  define FFI_MMAP_EXEC_SELINUX 1
+# endif
+#endif
+
+#if FFI_CLOSURES
+
+# if FFI_EXEC_TRAMPOLINE_TABLE
+
+// Per-target implementation; It's unclear what can reasonable be shared
+// between two OS/architecture implementations.
+
+# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
+
+#define USE_LOCKS 1
+#define USE_DL_PREFIX 1
+#ifdef __GNUC__
+#ifndef USE_BUILTIN_FFS
+#define USE_BUILTIN_FFS 1
+#endif
+#endif
+
+/* We need to use mmap, not sbrk.  */
+#define HAVE_MORECORE 0
+
+/* We could, in theory, support mremap, but it wouldn't buy us anything.  */
+#define HAVE_MREMAP 0
+
+/* We have no use for this, so save some code and data.  */
+#define NO_MALLINFO 1
+
+/* We need all allocations to be in regular segments, otherwise we
+   lose track of the corresponding code address.  */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+
+/* Don't allocate more than a page unless needed.  */
+#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
+
+#if FFI_CLOSURE_TEST
+/* Don't release single pages, to avoid a worst-case scenario of
+   continuously allocating and releasing single pages, but release
+   pairs of pages, which should do just as well given that allocations
+   are likely to be small.  */
+#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#if !defined(X86_WIN32) && !defined(X86_WIN64)
+#ifdef HAVE_MNTENT
+#include <mntent.h>
+#endif /* HAVE_MNTENT */
+#include <sys/param.h>
+#include <pthread.h>
+
+/* We don't want sys/mman.h to be included after we redefine mmap and
+   dlmunmap.  */
+#include <sys/mman.h>
+#define LACKS_SYS_MMAN_H 1
+
+#if FFI_MMAP_EXEC_SELINUX
+#include <sys/statfs.h>
+#include <stdlib.h>
+
+static int selinux_enabled = -1;
+
+static int
+selinux_enabled_check (void)
+{
+  struct statfs sfs;
+  FILE *f;
+  char *buf = NULL;
+  size_t len = 0;
+
+  if (statfs ("/selinux", &sfs) >= 0
+      && (unsigned int) sfs.f_type == 0xf97cff8cU)
+    return 1;
+  f = fopen ("/proc/mounts", "r");
+  if (f == NULL)
+    return 0;
+  while (getline (&buf, &len, f) >= 0)
+    {
+      char *p = strchr (buf, ' ');
+      if (p == NULL)
+        break;
+      p = strchr (p + 1, ' ');
+      if (p == NULL)
+        break;
+      if (strncmp (p + 1, "selinuxfs ", 10) == 0)
+        {
+          free (buf);
+          fclose (f);
+          return 1;
+        }
+    }
+  free (buf);
+  fclose (f);
+  return 0;
+}
+
+#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
+			      : (selinux_enabled = selinux_enabled_check ()))
+
+#else
+
+#define is_selinux_enabled() 0
+
+#endif /* !FFI_MMAP_EXEC_SELINUX */
+
+/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */
+#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
+#include <stdlib.h>
+
+static int emutramp_enabled = -1;
+
+static int
+emutramp_enabled_check (void)
+{
+  if (getenv ("FFI_DISABLE_EMUTRAMP") == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
+                               : (emutramp_enabled = emutramp_enabled_check ()))
+#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
+
+#elif defined (__CYGWIN__) || defined(__INTERIX)
+
+#include <sys/mman.h>
+
+/* Cygwin is Linux-like, but not quite that Linux-like.  */
+#define is_selinux_enabled() 0
+
+#endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
+
+#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
+#define is_emutramp_enabled() 0
+#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
+
+#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
+/* Use these for mmap and munmap within dlmalloc.c.  */
+static void *dlmmap(void *, size_t, int, int, int, off_t);
+static int dlmunmap(void *, size_t);
+#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
+
+#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
+
+/* A mutex used to synchronize access to *exec* variables in this file.  */
+static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* A file descriptor of a temporary file from which we'll map
+   executable pages.  */
+static int execfd = -1;
+
+/* The amount of space already allocated from the temporary file.  */
+static size_t execsize = 0;
+
+/* Open a temporary file name, and immediately unlink it.  */
+static int
+open_temp_exec_file_name (char *name)
+{
+  int fd = mkstemp (name);
+
+  if (fd != -1)
+    unlink (name);
+
+  return fd;
+}
+
+/* Open a temporary file in the named directory.  */
+static int
+open_temp_exec_file_dir (const char *dir)
+{
+  static const char suffix[] = "/ffiXXXXXX";
+  int lendir = strlen (dir);
+  char *tempname = __builtin_alloca (lendir + sizeof (suffix));
+
+  if (!tempname)
+    return -1;
+
+  memcpy (tempname, dir, lendir);
+  memcpy (tempname + lendir, suffix, sizeof (suffix));
+
+  return open_temp_exec_file_name (tempname);
+}
+
+/* Open a temporary file in the directory in the named environment
+   variable.  */
+static int
+open_temp_exec_file_env (const char *envvar)
+{
+  const char *value = getenv (envvar);
+
+  if (!value)
+    return -1;
+
+  return open_temp_exec_file_dir (value);
+}
+
+#ifdef HAVE_MNTENT
+/* Open a temporary file in an executable and writable mount point
+   listed in the mounts file.  Subsequent calls with the same mounts
+   keep searching for mount points in the same file.  Providing NULL
+   as the mounts file closes the file.  */
+static int
+open_temp_exec_file_mnt (const char *mounts)
+{
+  static const char *last_mounts;
+  static FILE *last_mntent;
+
+  if (mounts != last_mounts)
+    {
+      if (last_mntent)
+	endmntent (last_mntent);
+
+      last_mounts = mounts;
+
+      if (mounts)
+	last_mntent = setmntent (mounts, "r");
+      else
+	last_mntent = NULL;
+    }
+
+  if (!last_mntent)
+    return -1;
+
+  for (;;)
+    {
+      int fd;
+      struct mntent mnt;
+      char buf[MAXPATHLEN * 3];
+
+      if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL)
+	return -1;
+
+      if (hasmntopt (&mnt, "ro")
+	  || hasmntopt (&mnt, "noexec")
+	  || access (mnt.mnt_dir, W_OK))
+	continue;
+
+      fd = open_temp_exec_file_dir (mnt.mnt_dir);
+
+      if (fd != -1)
+	return fd;
+    }
+}
+#endif /* HAVE_MNTENT */
+
+/* Instructions to look for a location to hold a temporary file that
+   can be mapped in for execution.  */
+static struct
+{
+  int (*func)(const char *);
+  const char *arg;
+  int repeat;
+} open_temp_exec_file_opts[] = {
+  { open_temp_exec_file_env, "TMPDIR", 0 },
+  { open_temp_exec_file_dir, "/tmp", 0 },
+  { open_temp_exec_file_dir, "/var/tmp", 0 },
+  { open_temp_exec_file_dir, "/dev/shm", 0 },
+  { open_temp_exec_file_env, "HOME", 0 },
+#ifdef HAVE_MNTENT
+  { open_temp_exec_file_mnt, "/etc/mtab", 1 },
+  { open_temp_exec_file_mnt, "/proc/mounts", 1 },
+#endif /* HAVE_MNTENT */
+};
+
+/* Current index into open_temp_exec_file_opts.  */
+static int open_temp_exec_file_opts_idx = 0;
+
+/* Reset a current multi-call func, then advances to the next entry.
+   If we're at the last, go back to the first and return nonzero,
+   otherwise return zero.  */
+static int
+open_temp_exec_file_opts_next (void)
+{
+  if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
+    open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
+
+  open_temp_exec_file_opts_idx++;
+  if (open_temp_exec_file_opts_idx
+      == (sizeof (open_temp_exec_file_opts)
+	  / sizeof (*open_temp_exec_file_opts)))
+    {
+      open_temp_exec_file_opts_idx = 0;
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Return a file descriptor of a temporary zero-sized file in a
+   writable and exexutable filesystem.  */
+static int
+open_temp_exec_file (void)
+{
+  int fd;
+
+  do
+    {
+      fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
+	(open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
+
+      if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
+	  || fd == -1)
+	{
+	  if (open_temp_exec_file_opts_next ())
+	    break;
+	}
+    }
+  while (fd == -1);
+
+  return fd;
+}
+
+/* Map in a chunk of memory from the temporary exec file into separate
+   locations in the virtual memory address space, one writable and one
+   executable.  Returns the address of the writable portion, after
+   storing an offset to the corresponding executable portion at the
+   last word of the requested chunk.  */
+static void *
+dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
+{
+  void *ptr;
+
+  if (execfd == -1)
+    {
+      open_temp_exec_file_opts_idx = 0;
+    retry_open:
+      execfd = open_temp_exec_file ();
+      if (execfd == -1)
+	return MFAIL;
+    }
+
+  offset = execsize;
+
+  if (ftruncate (execfd, offset + length))
+    return MFAIL;
+
+  flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
+  flags |= MAP_SHARED;
+
+  ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
+	      flags, execfd, offset);
+  if (ptr == MFAIL)
+    {
+      if (!offset)
+	{
+	  close (execfd);
+	  goto retry_open;
+	}
+      ftruncate (execfd, offset);
+      return MFAIL;
+    }
+  else if (!offset
+	   && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
+    open_temp_exec_file_opts_next ();
+
+  start = mmap (start, length, prot, flags, execfd, offset);
+
+  if (start == MFAIL)
+    {
+      munmap (ptr, length);
+      ftruncate (execfd, offset);
+      return start;
+    }
+
+  mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
+
+  execsize += length;
+
+  return start;
+}
+
+/* Map in a writable and executable chunk of memory if possible.
+   Failing that, fall back to dlmmap_locked.  */
+static void *
+dlmmap (void *start, size_t length, int prot,
+	int flags, int fd, off_t offset)
+{
+  void *ptr;
+
+  assert (start == NULL && length % malloc_getpagesize == 0
+	  && prot == (PROT_READ | PROT_WRITE)
+	  && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
+	  && fd == -1 && offset == 0);
+
+#if FFI_CLOSURE_TEST
+  printf ("mapping in %zi\n", length);
+#endif
+
+  if (execfd == -1 && is_emutramp_enabled ())
+    {
+      ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
+      return ptr;
+    }
+
+  if (execfd == -1 && !is_selinux_enabled ())
+    {
+      ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
+
+      if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
+	/* Cool, no need to mess with separate segments.  */
+	return ptr;
+
+      /* If MREMAP_DUP is ever introduced and implemented, try mmap
+	 with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
+	 MREMAP_DUP and prot at this point.  */
+    }
+
+  if (execsize == 0 || execfd == -1)
+    {
+      pthread_mutex_lock (&open_temp_exec_file_mutex);
+      ptr = dlmmap_locked (start, length, prot, flags, offset);
+      pthread_mutex_unlock (&open_temp_exec_file_mutex);
+
+      return ptr;
+    }
+
+  return dlmmap_locked (start, length, prot, flags, offset);
+}
+
+/* Release memory at the given address, as well as the corresponding
+   executable page if it's separate.  */
+static int
+dlmunmap (void *start, size_t length)
+{
+  /* We don't bother decreasing execsize or truncating the file, since
+     we can't quite tell whether we're unmapping the end of the file.
+     We don't expect frequent deallocation anyway.  If we did, we
+     could locate pages in the file by writing to the pages being
+     deallocated and checking that the file contents change.
+     Yuck.  */
+  msegmentptr seg = segment_holding (gm, start);
+  void *code;
+
+#if FFI_CLOSURE_TEST
+  printf ("unmapping %zi\n", length);
+#endif
+
+  if (seg && (code = add_segment_exec_offset (start, seg)) != start)
+    {
+      int ret = munmap (code, length);
+      if (ret)
+	return ret;
+    }
+
+  return munmap (start, length);
+}
+
+#if FFI_CLOSURE_FREE_CODE
+/* Return segment holding given code address.  */
+static msegmentptr
+segment_holding_code (mstate m, char* addr)
+{
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if (addr >= add_segment_exec_offset (sp->base, sp)
+	&& addr < add_segment_exec_offset (sp->base, sp) + sp->size)
+      return sp;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+#endif
+
+#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
+
+/* Allocate a chunk of memory with the given size.  Returns a pointer
+   to the writable address, and sets *CODE to the executable
+   corresponding virtual address.  */
+void *
+ffi_closure_alloc (size_t size, void **code)
+{
+  *code = malloc(size);
+  return *code;
+#if 0
+  void *ptr;
+
+  if (!code)
+    return NULL;
+
+  ptr = dlmalloc (size);
+
+  if (ptr)
+    {
+      msegmentptr seg = segment_holding (gm, ptr);
+
+      *code = add_segment_exec_offset (ptr, seg);
+    }
+
+  return ptr;
+#endif
+}
+
+/* Release a chunk of memory allocated with ffi_closure_alloc.  If
+   FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
+   writable or the executable address given.  Otherwise, only the
+   writable address can be provided here.  */
+void
+ffi_closure_free (void *ptr)
+{
+#if 0
+#if FFI_CLOSURE_FREE_CODE
+  msegmentptr seg = segment_holding_code(gm, ptr);
+
+  if (seg)
+    ptr = sub_segment_exec_offset(ptr, seg);
+#endif
+
+  dlfree(ptr);
+#endif
+  free(ptr);
+}
+
+
+#if FFI_CLOSURE_TEST
+/* Do some internal sanity testing to make sure allocation and
+   deallocation of pages are working as intended.  */
+int main ()
+{
+  void *p[3];
+#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
+#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
+  GET (0, malloc_getpagesize / 2);
+  GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
+  PUT (1);
+  GET (1, 2 * malloc_getpagesize);
+  GET (2, malloc_getpagesize / 2);
+  PUT (1);
+  PUT (0);
+  PUT (2);
+  return 0;
+}
+#endif /* FFI_CLOSURE_TEST */
+# else /* ! FFI_MMAP_EXEC_WRIT */
+
+/* On many systems, memory returned by malloc is writable and
+   executable, so just use it.  */
+
+#include <stdlib.h>
+
+void *
+ffi_closure_alloc (size_t size, void **code)
+{
+  if (!code)
+    return NULL;
+
+  return *code = malloc (size);
+}
+
+void
+ffi_closure_free (void *ptr)
+{
+  free (ptr);
+}
+
+# endif /* ! FFI_MMAP_EXEC_WRIT */
+#endif /* FFI_CLOSURES */
diff --git a/lib/wrappers/libffi/gcc/ffi.c b/lib/wrappers/libffi/gcc/ffi.c
new file mode 100644
index 000000000..0600414d4
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/ffi.c
@@ -0,0 +1,841 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008  Red Hat, Inc.
+           Copyright (c) 2002  Ranjit Mathew
+           Copyright (c) 2002  Bo Thorsen
+           Copyright (c) 2002  Roger Sayle
+           Copyright (C) 2008, 2010  Free Software Foundation, Inc.
+
+   x86 Foreign Function Interface
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#if !defined(__x86_64__) || defined(_WIN64)
+
+#ifdef _WIN64
+#include <windows.h>
+#endif
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments */
+
+void ffi_prep_args(char *stack, extended_cif *ecif)
+{
+  register unsigned int i;
+  register void **p_argv;
+  register char *argp;
+  register ffi_type **p_arg;
+#ifdef X86_WIN32
+  size_t p_stack_args[2];
+  void *p_stack_data[2];
+  char *argp2 = stack;
+  int stack_args_count = 0;
+  int cabi = ecif->cif->abi;
+#endif
+
+  argp = stack;
+
+  if ((ecif->cif->flags == FFI_TYPE_STRUCT
+       || ecif->cif->flags == FFI_TYPE_MS_STRUCT)
+#ifdef X86_WIN64
+      && (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
+          && ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
+#endif
+      )
+    {
+      *(void **) argp = ecif->rvalue;
+#ifdef X86_WIN32
+      /* For fastcall/thiscall this is first register-passed
+         argument.  */
+      if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
+	{
+	  p_stack_args[stack_args_count] = sizeof (void*);
+	  p_stack_data[stack_args_count] = argp;
+	  ++stack_args_count;
+	}
+#endif
+      argp += sizeof(void*);
+    }
+
+  p_argv = ecif->avalue;
+
+  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+       i != 0;
+       i--, p_arg++)
+    {
+      size_t z;
+
+      /* Align if necessary */
+      if ((sizeof(void*) - 1) & (size_t) argp)
+        argp = (char *) ALIGN(argp, sizeof(void*));
+
+      z = (*p_arg)->size;
+#ifdef X86_WIN64
+      if (z > sizeof(ffi_arg)
+          || ((*p_arg)->type == FFI_TYPE_STRUCT
+              && (z != 1 && z != 2 && z != 4 && z != 8))
+#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
+          || ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
+#endif
+          )
+        {
+          z = sizeof(ffi_arg);
+          *(void **)argp = *p_argv;
+        }
+      else if ((*p_arg)->type == FFI_TYPE_FLOAT)
+        {
+          memcpy(argp, *p_argv, z);
+        }
+      else
+#endif
+      if (z < sizeof(ffi_arg))
+        {
+          z = sizeof(ffi_arg);
+          switch ((*p_arg)->type)
+            {
+            case FFI_TYPE_SINT8:
+              *(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
+              break;
+
+            case FFI_TYPE_UINT8:
+              *(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
+              break;
+
+            case FFI_TYPE_SINT16:
+              *(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
+              break;
+
+            case FFI_TYPE_UINT16:
+              *(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
+              break;
+
+            case FFI_TYPE_SINT32:
+              *(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
+              break;
+
+            case FFI_TYPE_UINT32:
+              *(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
+              break;
+
+            case FFI_TYPE_STRUCT:
+              *(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
+              break;
+
+            default:
+              FFI_ASSERT(0);
+            }
+        }
+      else
+        {
+          memcpy(argp, *p_argv, z);
+        }
+
+#ifdef X86_WIN32
+    /* For thiscall/fastcall convention register-passed arguments
+       are the first two none-floating-point arguments with a size
+       smaller or equal to sizeof (void*).  */
+    if ((cabi == FFI_THISCALL && stack_args_count < 1)
+        || (cabi == FFI_FASTCALL && stack_args_count < 2))
+      {
+	if (z <= 4
+	    && ((*p_arg)->type != FFI_TYPE_FLOAT
+	        && (*p_arg)->type != FFI_TYPE_STRUCT))
+	  {
+	    p_stack_args[stack_args_count] = z;
+	    p_stack_data[stack_args_count] = argp;
+	    ++stack_args_count;
+	  }
+      }
+#endif
+      p_argv++;
+#ifdef X86_WIN64
+      argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+#else
+      argp += z;
+#endif
+    }
+
+#ifdef X86_WIN32
+  /* We need to move the register-passed arguments for thiscall/fastcall
+     on top of stack, so that those can be moved to registers ecx/edx by
+     call-handler.  */
+  if (stack_args_count > 0)
+    {
+      size_t zz = (p_stack_args[0] + 3) & ~3;
+      char *h;
+
+      /* Move first argument to top-stack position.  */
+      if (p_stack_data[0] != argp2)
+	{
+	  h = alloca (zz + 1);
+	  memcpy (h, p_stack_data[0], zz);
+	  memmove (argp2 + zz, argp2,
+	           (size_t) ((char *) p_stack_data[0] - (char*)argp2));
+	  memcpy (argp2, h, zz);
+	}
+
+      argp2 += zz;
+      --stack_args_count;
+      if (zz > 4)
+	stack_args_count = 0;
+
+      /* If we have a second argument, then move it on top
+         after the first one.  */
+      if (stack_args_count > 0 && p_stack_data[1] != argp2)
+	{
+	  zz = p_stack_args[1];
+	  zz = (zz + 3) & ~3;
+	  h = alloca (zz + 1);
+	  h = alloca (zz + 1);
+	  memcpy (h, p_stack_data[1], zz);
+	  memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2));
+	  memcpy (argp2, h, zz);
+	}
+    }
+#endif
+  return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  unsigned int i;
+  ffi_type **ptr;
+
+  /* Set the return type flag */
+  switch (cif->rtype->type)
+    {
+    case FFI_TYPE_VOID:
+    case FFI_TYPE_UINT8:
+    case FFI_TYPE_UINT16:
+    case FFI_TYPE_SINT8:
+    case FFI_TYPE_SINT16:
+#ifdef X86_WIN64
+    case FFI_TYPE_UINT32:
+    case FFI_TYPE_SINT32:
+#endif
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+#ifndef X86_WIN64
+#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
+    case FFI_TYPE_LONGDOUBLE:
+#endif
+#endif
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+
+    case FFI_TYPE_UINT64:
+#ifdef X86_WIN64
+    case FFI_TYPE_POINTER:
+#endif
+      cif->flags = FFI_TYPE_SINT64;
+      break;
+
+    case FFI_TYPE_STRUCT:
+#ifndef X86
+      if (cif->rtype->size == 1)
+        {
+          cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
+        }
+      else if (cif->rtype->size == 2)
+        {
+          cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
+        }
+      else if (cif->rtype->size == 4)
+        {
+#ifdef X86_WIN64
+          cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
+#else
+          cif->flags = FFI_TYPE_INT; /* same as int type */
+#endif
+        }
+      else if (cif->rtype->size == 8)
+        {
+          cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
+        }
+      else
+#endif
+        {
+#ifdef X86_WIN32
+          if (cif->abi == FFI_MS_CDECL)
+            cif->flags = FFI_TYPE_MS_STRUCT;
+          else
+#endif
+            cif->flags = FFI_TYPE_STRUCT;
+          /* allocate space for return value pointer */
+          cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
+        }
+      break;
+
+    default:
+#ifdef X86_WIN64
+      cif->flags = FFI_TYPE_SINT64;
+      break;
+    case FFI_TYPE_INT:
+      cif->flags = FFI_TYPE_SINT32;
+#else
+      cif->flags = FFI_TYPE_INT;
+#endif
+      break;
+    }
+
+  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+    {
+      if (((*ptr)->alignment - 1) & cif->bytes)
+        cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
+      cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
+    }
+
+#ifdef X86_WIN64
+  /* ensure space for storing four registers */
+  cif->bytes += 4 * sizeof(ffi_arg);
+#endif
+
+  cif->bytes = (cif->bytes + 15) & ~0xF;
+
+  return FFI_OK;
+}
+
+#ifdef X86_WIN64
+extern int
+ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
+               unsigned, unsigned, unsigned *, void (*fn)(void));
+#elif defined(X86_WIN32)
+extern void
+ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
+               unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
+#else
+extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
+                          unsigned, unsigned, unsigned *, void (*fn)(void));
+#endif
+
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  extended_cif ecif;
+
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+  
+  /* If the return value is a struct and we don't have a return */
+  /* value address then we need to make one                     */
+
+#ifdef X86_WIN64
+  if (rvalue == NULL
+      && cif->flags == FFI_TYPE_STRUCT
+      && cif->rtype->size != 1 && cif->rtype->size != 2
+      && cif->rtype->size != 4 && cif->rtype->size != 8)
+    {
+      ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
+    }
+#else
+  if (rvalue == NULL
+      && (cif->flags == FFI_TYPE_STRUCT
+          || cif->flags == FFI_TYPE_MS_STRUCT))
+    {
+      ecif.rvalue = alloca(cif->rtype->size);
+    }
+#endif
+  else
+    ecif.rvalue = rvalue;
+    
+  
+  switch (cif->abi) 
+    {
+#ifdef X86_WIN64
+    case FFI_WIN64:
+      ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
+                     cif->flags, ecif.rvalue, fn);
+      break;
+#elif defined(X86_WIN32)
+    case FFI_SYSV:
+    case FFI_STDCALL:
+    case FFI_MS_CDECL:
+      ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
+		     ecif.rvalue, fn);
+      break;
+    case FFI_THISCALL:
+    case FFI_FASTCALL:
+      {
+	unsigned int abi = cif->abi;
+	unsigned int i, passed_regs = 0;
+
+	if (cif->flags == FFI_TYPE_STRUCT)
+	  ++passed_regs;
+
+	for (i=0; i < cif->nargs && passed_regs < 2;i++)
+	  {
+	    size_t sz;
+
+	    if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
+	        || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
+	      continue;
+	    sz = (cif->arg_types[i]->size + 3) & ~3;
+	    if (sz == 0 || sz > 4)
+	      continue;
+	    ++passed_regs;
+	  }
+	if (passed_regs < 2 && abi == FFI_FASTCALL)
+	  abi = FFI_THISCALL;
+	if (passed_regs < 1 && abi == FFI_THISCALL)
+	  abi = FFI_STDCALL;
+        ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags,
+                       ecif.rvalue, fn);
+      }
+      break;
+#else
+    case FFI_SYSV:
+      ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
+                    fn);
+      break;
+#endif
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
+
+/** private members **/
+
+/* The following __attribute__((regparm(1))) decorations will have no effect
+   on MSVC or SUNPRO_C -- standard conventions apply. */
+static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
+                                         void** args, ffi_cif* cif);
+void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
+     __attribute__ ((regparm(1)));
+unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
+     __attribute__ ((regparm(1)));
+void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
+     __attribute__ ((regparm(1)));
+#ifdef X86_WIN32
+void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
+     __attribute__ ((regparm(1)));
+void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
+     __attribute__ ((regparm(1)));
+void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *)
+     __attribute__ ((regparm(1)));
+#endif
+#ifdef X86_WIN64
+void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
+#endif
+
+/* This function is jumped to by the trampoline */
+
+#ifdef X86_WIN64
+void * FFI_HIDDEN
+ffi_closure_win64_inner (ffi_closure *closure, void *args) {
+  ffi_cif       *cif;
+  void         **arg_area;
+  void          *result;
+  void          *resp = &result;
+
+  cif         = closure->cif;
+  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
+
+  /* this call will initialize ARG_AREA, such that each
+   * element in that array points to the corresponding 
+   * value on the stack; and if the function returns
+   * a structure, it will change RESP to point to the
+   * structure return address.  */
+
+  ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
+  
+  (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+  /* The result is returned in rax.  This does the right thing for
+     result types except for floats; we have to 'mov xmm0, rax' in the
+     caller to correct this.
+     TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
+  */
+  return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
+}
+
+#else
+unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
+ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
+{
+  /* our various things...  */
+  ffi_cif       *cif;
+  void         **arg_area;
+
+  cif         = closure->cif;
+  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
+
+  /* this call will initialize ARG_AREA, such that each
+   * element in that array points to the corresponding 
+   * value on the stack; and if the function returns
+   * a structure, it will change RESP to point to the
+   * structure return address.  */
+
+  ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
+
+  (closure->fun) (cif, *respp, arg_area, closure->user_data);
+
+  return cif->flags;
+}
+#endif /* !X86_WIN64 */
+
+static void
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
+                            ffi_cif *cif)
+{
+  register unsigned int i;
+  register void **p_argv;
+  register char *argp;
+  register ffi_type **p_arg;
+
+  argp = stack;
+
+#ifdef X86_WIN64
+  if (cif->rtype->size > sizeof(ffi_arg)
+      || (cif->flags == FFI_TYPE_STRUCT
+          && (cif->rtype->size != 1 && cif->rtype->size != 2
+              && cif->rtype->size != 4 && cif->rtype->size != 8))) {
+    *rvalue = *(void **) argp;
+    argp += sizeof(void *);
+  }
+#else
+  if ( cif->flags == FFI_TYPE_STRUCT
+       || cif->flags == FFI_TYPE_MS_STRUCT ) {
+    *rvalue = *(void **) argp;
+    argp += sizeof(void *);
+  }
+#endif
+
+  p_argv = avalue;
+
+  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+    {
+      size_t z;
+
+      /* Align if necessary */
+      if ((sizeof(void*) - 1) & (size_t) argp) {
+        argp = (char *) ALIGN(argp, sizeof(void*));
+      }
+
+#ifdef X86_WIN64
+      if ((*p_arg)->size > sizeof(ffi_arg)
+          || ((*p_arg)->type == FFI_TYPE_STRUCT
+              && ((*p_arg)->size != 1 && (*p_arg)->size != 2
+                  && (*p_arg)->size != 4 && (*p_arg)->size != 8)))
+        {
+          z = sizeof(void *);
+          *p_argv = *(void **)argp;
+        }
+      else
+#endif
+        {
+          z = (*p_arg)->size;
+          
+          /* because we're little endian, this is what it turns into.   */
+          
+          *p_argv = (void*) argp;
+        }
+          
+      p_argv++;
+#ifdef X86_WIN64
+      argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+#else
+      argp += z;
+#endif
+    }
+  
+  return;
+}
+
+#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
+{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
+   void*  __fun = (void*)(FUN); \
+   void*  __ctx = (void*)(CTX); \
+   *(unsigned char*) &__tramp[0] = 0x41; \
+   *(unsigned char*) &__tramp[1] = 0xbb; \
+   *(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
+   *(unsigned char*) &__tramp[6] = 0x48; \
+   *(unsigned char*) &__tramp[7] = 0xb8; \
+   *(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
+   *(unsigned char *)  &__tramp[16] = 0x49; \
+   *(unsigned char *)  &__tramp[17] = 0xba; \
+   *(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
+   *(unsigned char *)  &__tramp[26] = 0x41; \
+   *(unsigned char *)  &__tramp[27] = 0xff; \
+   *(unsigned char *)  &__tramp[28] = 0xe2; /* jmp %r10 */ \
+ }
+
+/* How to make a trampoline.  Derived from gcc/config/i386/i386.c. */
+
+#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
+{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
+   unsigned int  __fun = (unsigned int)(FUN); \
+   unsigned int  __ctx = (unsigned int)(CTX); \
+   unsigned int  __dis = __fun - (__ctx + 10);  \
+   *(unsigned char*) &__tramp[0] = 0xb8; \
+   *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
+   *(unsigned char *)  &__tramp[5] = 0xe9; \
+   *(unsigned int*)  &__tramp[6] = __dis; /* jmp __fun  */ \
+ }
+
+#define FFI_INIT_TRAMPOLINE_THISCALL(TRAMP,FUN,CTX,SIZE) \
+{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
+   unsigned int  __fun = (unsigned int)(FUN); \
+   unsigned int  __ctx = (unsigned int)(CTX); \
+   unsigned int  __dis = __fun - (__ctx + 49);  \
+   unsigned short __size = (unsigned short)(SIZE); \
+   *(unsigned int *) &__tramp[0] = 0x8324048b;	/* mov (%esp), %eax */ \
+   *(unsigned int *) &__tramp[4] = 0x4c890cec;	/* sub $12, %esp */ \
+   *(unsigned int *) &__tramp[8] = 0x04890424;	/* mov %ecx, 4(%esp) */ \
+   *(unsigned char*) &__tramp[12] = 0x24;	/* mov %eax, (%esp) */ \
+   *(unsigned char*) &__tramp[13] = 0xb8; \
+   *(unsigned int *) &__tramp[14] = __size;	/* mov __size, %eax */ \
+   *(unsigned int *) &__tramp[18] = 0x08244c8d;	/* lea 8(%esp), %ecx */ \
+   *(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \
+   *(unsigned short*) &__tramp[26] = 0x0b74;	/* jz 1f */ \
+   *(unsigned int *) &__tramp[28] = 0x8908518b;	/* 2b: mov 8(%ecx), %edx */ \
+   *(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \
+   *(unsigned char*) &__tramp[36] = 0x48;	/* dec %eax */ \
+   *(unsigned short*) &__tramp[37] = 0xf575;	/* jnz 2b ; 1f: */ \
+   *(unsigned char*) &__tramp[39] = 0xb8; \
+   *(unsigned int*)  &__tramp[40] = __ctx; /* movl __ctx, %eax */ \
+   *(unsigned char *)  &__tramp[44] = 0xe8; \
+   *(unsigned int*)  &__tramp[45] = __dis; /* call __fun  */ \
+   *(unsigned char*)  &__tramp[49] = 0xc2; /* ret  */ \
+   *(unsigned short*)  &__tramp[50] = (__size + 8); /* ret (__size + 8)  */ \
+ }
+
+#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE)  \
+{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
+   unsigned int  __fun = (unsigned int)(FUN); \
+   unsigned int  __ctx = (unsigned int)(CTX); \
+   unsigned int  __dis = __fun - (__ctx + 10); \
+   unsigned short __size = (unsigned short)(SIZE); \
+   *(unsigned char*) &__tramp[0] = 0xb8; \
+   *(unsigned int*)  &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
+   *(unsigned char *)  &__tramp[5] = 0xe8; \
+   *(unsigned int*)  &__tramp[6] = __dis; /* call __fun  */ \
+   *(unsigned char *)  &__tramp[10] = 0xc2; \
+   *(unsigned short*)  &__tramp[11] = __size; /* ret __size  */ \
+ }
+
+/* the cif must already be prep'ed */
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+                      ffi_cif* cif,
+                      void (*fun)(ffi_cif*,void*,void**,void*),
+                      void *user_data,
+                      void *codeloc)
+{
+#ifdef X86_WIN64
+#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
+#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
+  if (cif->abi == FFI_WIN64) 
+    {
+      int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
+      FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
+                                 &ffi_closure_win64,
+                                 codeloc, mask);
+      /* make sure we can execute here */
+    }
+#else
+  if (cif->abi == FFI_SYSV)
+    {
+      FFI_INIT_TRAMPOLINE (&closure->tramp[0],
+                           &ffi_closure_SYSV,
+                           (void*)codeloc);
+    }
+#ifdef X86_WIN32
+  else if (cif->abi == FFI_THISCALL)
+    {
+      FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
+				    &ffi_closure_THISCALL,
+				    (void*)codeloc,
+				    cif->bytes);
+    }
+  else if (cif->abi == FFI_STDCALL)
+    {
+      FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
+                                   &ffi_closure_STDCALL,
+                                   (void*)codeloc, cif->bytes);
+    }
+  else if (cif->abi == FFI_MS_CDECL)
+    {
+      FFI_INIT_TRAMPOLINE (&closure->tramp[0],
+                           &ffi_closure_SYSV,
+                           (void*)codeloc);
+    }
+#endif /* X86_WIN32 */
+#endif /* !X86_WIN64 */
+  else
+    {
+      return FFI_BAD_ABI;
+    }
+    
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
+}
+
+/* ------- Native raw API support -------------------------------- */
+
+#if !FFI_NO_RAW_API
+
+ffi_status
+ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
+                          ffi_cif* cif,
+                          void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
+                          void *user_data,
+                          void *codeloc)
+{
+  int i;
+
+  if (cif->abi != FFI_SYSV) {
+#ifdef X86_WIN32
+    if (cif->abi != FFI_THISCALL)
+#endif
+    return FFI_BAD_ABI;
+  }
+
+  /* we currently don't support certain kinds of arguments for raw
+     closures.  This should be implemented by a separate assembly
+     language routine, since it would require argument processing,
+     something we don't do now for performance.  */
+
+  for (i = cif->nargs-1; i >= 0; i--)
+    {
+      FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
+      FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
+    }
+  
+#ifdef X86_WIN32
+  if (cif->abi == FFI_SYSV)
+    {
+#endif
+  FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
+                       codeloc);
+#ifdef X86_WIN32
+    }
+  else if (cif->abi == FFI_THISCALL)
+    {
+      FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL,
+				    codeloc, cif->bytes);
+    }
+#endif
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+
+  return FFI_OK;
+}
+
+static void 
+ffi_prep_args_raw(char *stack, extended_cif *ecif)
+{
+  memcpy (stack, ecif->avalue, ecif->cif->bytes);
+}
+
+/* we borrow this routine from libffi (it must be changed, though, to
+ * actually call the function passed in the first argument.  as of
+ * libffi-1.20, this is not the case.)
+ */
+
+void
+ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
+{
+  extended_cif ecif;
+  void **avalue = (void **)fake_avalue;
+
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+  
+  /* If the return value is a struct and we don't have a return */
+  /* value address then we need to make one                     */
+
+  if (rvalue == NULL
+      && (cif->flags == FFI_TYPE_STRUCT
+          || cif->flags == FFI_TYPE_MS_STRUCT))
+    {
+      ecif.rvalue = alloca(cif->rtype->size);
+    }
+  else
+    ecif.rvalue = rvalue;
+    
+  
+  switch (cif->abi) 
+    {
+#ifdef X86_WIN32
+    case FFI_SYSV:
+    case FFI_STDCALL:
+    case FFI_MS_CDECL:
+      ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
+		     ecif.rvalue, fn);
+      break;
+    case FFI_THISCALL:
+    case FFI_FASTCALL:
+      {
+	unsigned int abi = cif->abi;
+	unsigned int i, passed_regs = 0;
+
+	if (cif->flags == FFI_TYPE_STRUCT)
+	  ++passed_regs;
+
+	for (i=0; i < cif->nargs && passed_regs < 2;i++)
+	  {
+	    size_t sz;
+
+	    if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
+	        || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
+	      continue;
+	    sz = (cif->arg_types[i]->size + 3) & ~3;
+	    if (sz == 0 || sz > 4)
+	      continue;
+	    ++passed_regs;
+	  }
+	if (passed_regs < 2 && abi == FFI_FASTCALL)
+	  cif->abi = abi = FFI_THISCALL;
+	if (passed_regs < 1 && abi == FFI_THISCALL)
+	  cif->abi = abi = FFI_STDCALL;
+        ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags,
+                       ecif.rvalue, fn);
+      }
+      break;
+#else
+    case FFI_SYSV:
+      ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
+                    ecif.rvalue, fn);
+      break;
+#endif
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+}
+
+#endif
+
+#endif /* !__x86_64__  || X86_WIN64 */
+
diff --git a/lib/wrappers/libffi/gcc/ffi64.c b/lib/wrappers/libffi/gcc/ffi64.c
new file mode 100644
index 000000000..2014af24c
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/ffi64.c
@@ -0,0 +1,673 @@
+/* -----------------------------------------------------------------------
+   ffi64.c - Copyright (c) 2013  The Written Word, Inc.
+             Copyright (c) 2011  Anthony Green
+             Copyright (c) 2008, 2010  Red Hat, Inc.
+             Copyright (c) 2002, 2007  Bo Thorsen <bo@suse.de>
+             
+   x86-64 Foreign Function Interface 
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#ifdef __x86_64__
+
+#define MAX_GPR_REGS 6
+#define MAX_SSE_REGS 8
+
+#if defined(__INTEL_COMPILER)
+#define UINT128 __m128
+#else
+#if defined(__SUNPRO_C)
+#include <sunmedia_types.h>
+#define UINT128 __m128i
+#else
+#define UINT128 __int128_t
+#endif
+#endif
+
+union big_int_union
+{
+  UINT32 i32;
+  UINT64 i64;
+  UINT128 i128;
+};
+
+struct register_args
+{
+  /* Registers for argument passing.  */
+  UINT64 gpr[MAX_GPR_REGS];
+  union big_int_union sse[MAX_SSE_REGS]; 
+};
+
+extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
+			     void *raddr, void (*fnaddr)(void), unsigned ssecount);
+
+/* All reference to register classes here is identical to the code in
+   gcc/config/i386/i386.c. Do *not* change one without the other.  */
+
+/* Register class used for passing given 64bit part of the argument.
+   These represent classes as documented by the PS ABI, with the
+   exception of SSESF, SSEDF classes, that are basically SSE class,
+   just gcc will use SF or DFmode move instead of DImode to avoid
+   reformatting penalties.
+
+   Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
+   whenever possible (upper half does contain padding).  */
+enum x86_64_reg_class
+  {
+    X86_64_NO_CLASS,
+    X86_64_INTEGER_CLASS,
+    X86_64_INTEGERSI_CLASS,
+    X86_64_SSE_CLASS,
+    X86_64_SSESF_CLASS,
+    X86_64_SSEDF_CLASS,
+    X86_64_SSEUP_CLASS,
+    X86_64_X87_CLASS,
+    X86_64_X87UP_CLASS,
+    X86_64_COMPLEX_X87_CLASS,
+    X86_64_MEMORY_CLASS
+  };
+
+#define MAX_CLASSES 4
+
+#define SSE_CLASS_P(X)	((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
+
+/* x86-64 register passing implementation.  See x86-64 ABI for details.  Goal
+   of this code is to classify each 8bytes of incoming argument by the register
+   class and assign registers accordingly.  */
+
+/* Return the union class of CLASS1 and CLASS2.
+   See the x86-64 PS ABI for details.  */
+
+static enum x86_64_reg_class
+merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
+{
+  /* Rule #1: If both classes are equal, this is the resulting class.  */
+  if (class1 == class2)
+    return class1;
+
+  /* Rule #2: If one of the classes is NO_CLASS, the resulting class is
+     the other class.  */
+  if (class1 == X86_64_NO_CLASS)
+    return class2;
+  if (class2 == X86_64_NO_CLASS)
+    return class1;
+
+  /* Rule #3: If one of the classes is MEMORY, the result is MEMORY.  */
+  if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
+    return X86_64_MEMORY_CLASS;
+
+  /* Rule #4: If one of the classes is INTEGER, the result is INTEGER.  */
+  if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
+      || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
+    return X86_64_INTEGERSI_CLASS;
+  if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
+      || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
+    return X86_64_INTEGER_CLASS;
+
+  /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
+     MEMORY is used.  */
+  if (class1 == X86_64_X87_CLASS
+      || class1 == X86_64_X87UP_CLASS
+      || class1 == X86_64_COMPLEX_X87_CLASS
+      || class2 == X86_64_X87_CLASS
+      || class2 == X86_64_X87UP_CLASS
+      || class2 == X86_64_COMPLEX_X87_CLASS)
+    return X86_64_MEMORY_CLASS;
+
+  /* Rule #6: Otherwise class SSE is used.  */
+  return X86_64_SSE_CLASS;
+}
+
+/* Classify the argument of type TYPE and mode MODE.
+   CLASSES will be filled by the register class used to pass each word
+   of the operand.  The number of words is returned.  In case the parameter
+   should be passed in memory, 0 is returned. As a special case for zero
+   sized containers, classes[0] will be NO_CLASS and 1 is returned.
+
+   See the x86-64 PS ABI for details.
+*/
+static int
+classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
+		   size_t byte_offset)
+{
+  switch (type->type)
+    {
+    case FFI_TYPE_UINT8:
+    case FFI_TYPE_SINT8:
+    case FFI_TYPE_UINT16:
+    case FFI_TYPE_SINT16:
+    case FFI_TYPE_UINT32:
+    case FFI_TYPE_SINT32:
+    case FFI_TYPE_UINT64:
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_POINTER:
+      {
+	int size = byte_offset + type->size;
+
+	if (size <= 4)
+	  {
+	    classes[0] = X86_64_INTEGERSI_CLASS;
+	    return 1;
+	  }
+	else if (size <= 8)
+	  {
+	    classes[0] = X86_64_INTEGER_CLASS;
+	    return 1;
+	  }
+	else if (size <= 12)
+	  {
+	    classes[0] = X86_64_INTEGER_CLASS;
+	    classes[1] = X86_64_INTEGERSI_CLASS;
+	    return 2;
+	  }
+	else if (size <= 16)
+	  {
+	    classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
+	    return 2;
+	  }
+	else
+	  FFI_ASSERT (0);
+      }
+    case FFI_TYPE_FLOAT:
+      if (!(byte_offset % 8))
+	classes[0] = X86_64_SSESF_CLASS;
+      else
+	classes[0] = X86_64_SSE_CLASS;
+      return 1;
+    case FFI_TYPE_DOUBLE:
+      classes[0] = X86_64_SSEDF_CLASS;
+      return 1;
+    case FFI_TYPE_LONGDOUBLE:
+      classes[0] = X86_64_X87_CLASS;
+      classes[1] = X86_64_X87UP_CLASS;
+      return 2;
+    case FFI_TYPE_STRUCT:
+      {
+	const int UNITS_PER_WORD = 8;
+	int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+	ffi_type **ptr; 
+	int i;
+	enum x86_64_reg_class subclasses[MAX_CLASSES];
+
+	/* If the struct is larger than 32 bytes, pass it on the stack.  */
+	if (type->size > 32)
+	  return 0;
+
+	for (i = 0; i < words; i++)
+	  classes[i] = X86_64_NO_CLASS;
+
+	/* Zero sized arrays or structures are NO_CLASS.  We return 0 to
+	   signalize memory class, so handle it as special case.  */
+	if (!words)
+	  {
+	    classes[0] = X86_64_NO_CLASS;
+	    return 1;
+	  }
+
+	/* Merge the fields of structure.  */
+	for (ptr = type->elements; *ptr != NULL; ptr++)
+	  {
+	    int num;
+
+	    byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
+
+	    num = classify_argument (*ptr, subclasses, byte_offset % 8);
+	    if (num == 0)
+	      return 0;
+	    for (i = 0; i < num; i++)
+	      {
+		int pos = byte_offset / 8;
+		classes[i + pos] =
+		  merge_classes (subclasses[i], classes[i + pos]);
+	      }
+
+	    byte_offset += (*ptr)->size;
+	  }
+
+	if (words > 2)
+	  {
+	    /* When size > 16 bytes, if the first one isn't
+	       X86_64_SSE_CLASS or any other ones aren't
+	       X86_64_SSEUP_CLASS, everything should be passed in
+	       memory.  */
+	    if (classes[0] != X86_64_SSE_CLASS)
+	      return 0;
+
+	    for (i = 1; i < words; i++)
+	      if (classes[i] != X86_64_SSEUP_CLASS)
+		return 0;
+	  }
+
+	/* Final merger cleanup.  */
+	for (i = 0; i < words; i++)
+	  {
+	    /* If one class is MEMORY, everything should be passed in
+	       memory.  */
+	    if (classes[i] == X86_64_MEMORY_CLASS)
+	      return 0;
+
+	    /* The X86_64_SSEUP_CLASS should be always preceded by
+	       X86_64_SSE_CLASS or X86_64_SSEUP_CLASS.  */
+	    if (classes[i] == X86_64_SSEUP_CLASS
+		&& classes[i - 1] != X86_64_SSE_CLASS
+		&& classes[i - 1] != X86_64_SSEUP_CLASS)
+	      {
+		/* The first one should never be X86_64_SSEUP_CLASS.  */
+		FFI_ASSERT (i != 0);
+		classes[i] = X86_64_SSE_CLASS;
+	      }
+
+	    /*  If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
+		everything should be passed in memory.  */
+	    if (classes[i] == X86_64_X87UP_CLASS
+		&& (classes[i - 1] != X86_64_X87_CLASS))
+	      {
+		/* The first one should never be X86_64_X87UP_CLASS.  */
+		FFI_ASSERT (i != 0);
+		return 0;
+	      }
+	  }
+	return words;
+      }
+
+    default:
+      FFI_ASSERT(0);
+    }
+  return 0; /* Never reached.  */
+}
+
+/* Examine the argument and return set number of register required in each
+   class.  Return zero iff parameter should be passed in memory, otherwise
+   the number of registers.  */
+
+static int
+examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
+		  _Bool in_return, int *pngpr, int *pnsse)
+{
+  int i, n, ngpr, nsse;
+
+  n = classify_argument (type, classes, 0);
+  if (n == 0)
+    return 0;
+
+  ngpr = nsse = 0;
+  for (i = 0; i < n; ++i)
+    switch (classes[i])
+      {
+      case X86_64_INTEGER_CLASS:
+      case X86_64_INTEGERSI_CLASS:
+	ngpr++;
+	break;
+      case X86_64_SSE_CLASS:
+      case X86_64_SSESF_CLASS:
+      case X86_64_SSEDF_CLASS:
+	nsse++;
+	break;
+      case X86_64_NO_CLASS:
+      case X86_64_SSEUP_CLASS:
+	break;
+      case X86_64_X87_CLASS:
+      case X86_64_X87UP_CLASS:
+      case X86_64_COMPLEX_X87_CLASS:
+	return in_return != 0;
+      default:
+	abort ();
+      }
+
+  *pngpr = ngpr;
+  *pnsse = nsse;
+
+  return n;
+}
+
+/* Perform machine dependent cif processing.  */
+
+ffi_status
+ffi_prep_cif_machdep (ffi_cif *cif)
+{
+  int gprcount, ssecount, i, avn, n, ngpr, nsse, flags;
+  enum x86_64_reg_class classes[MAX_CLASSES];
+  size_t bytes;
+
+  gprcount = ssecount = 0;
+
+  flags = cif->rtype->type;
+  if (flags != FFI_TYPE_VOID)
+    {
+      n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
+      if (n == 0)
+	{
+	  /* The return value is passed in memory.  A pointer to that
+	     memory is the first argument.  Allocate a register for it.  */
+	  gprcount++;
+	  /* We don't have to do anything in asm for the return.  */
+	  flags = FFI_TYPE_VOID;
+	}
+      else if (flags == FFI_TYPE_STRUCT)
+	{
+	  /* Mark which registers the result appears in.  */
+	  _Bool sse0 = SSE_CLASS_P (classes[0]);
+	  _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
+	  if (sse0 && !sse1)
+	    flags |= 1 << 8;
+	  else if (!sse0 && sse1)
+	    flags |= 1 << 9;
+	  else if (sse0 && sse1)
+	    flags |= 1 << 10;
+	  /* Mark the true size of the structure.  */
+	  flags |= cif->rtype->size << 12;
+	}
+    }
+
+  /* Go over all arguments and determine the way they should be passed.
+     If it's in a register and there is space for it, let that be so. If
+     not, add it's size to the stack byte count.  */
+  for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
+    {
+      if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
+	  || gprcount + ngpr > MAX_GPR_REGS
+	  || ssecount + nsse > MAX_SSE_REGS)
+	{
+	  long align = cif->arg_types[i]->alignment;
+
+	  if (align < 8)
+	    align = 8;
+
+	  bytes = ALIGN (bytes, align);
+	  bytes += cif->arg_types[i]->size;
+	}
+      else
+	{
+	  gprcount += ngpr;
+	  ssecount += nsse;
+	}
+    }
+  if (ssecount)
+    flags |= 1 << 11;
+  cif->flags = flags;
+  cif->bytes = ALIGN (bytes, 8);
+
+  return FFI_OK;
+}
+
+void
+ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+  enum x86_64_reg_class classes[MAX_CLASSES];
+  char *stack, *argp;
+  ffi_type **arg_types;
+  int gprcount, ssecount, ngpr, nsse, i, avn;
+  _Bool ret_in_memory;
+  struct register_args *reg_args;
+
+  /* Can't call 32-bit mode from 64-bit mode.  */
+  FFI_ASSERT (cif->abi == FFI_UNIX64);
+
+  /* If the return value is a struct and we don't have a return value
+     address then we need to make one.  Note the setting of flags to
+     VOID above in ffi_prep_cif_machdep.  */
+  ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
+		   && (cif->flags & 0xff) == FFI_TYPE_VOID);
+  if (rvalue == NULL && ret_in_memory)
+    rvalue = alloca (cif->rtype->size);
+
+  /* Allocate the space for the arguments, plus 4 words of temp space.  */
+  stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
+  reg_args = (struct register_args *) stack;
+  argp = stack + sizeof (struct register_args);
+
+  gprcount = ssecount = 0;
+
+  /* If the return value is passed in memory, add the pointer as the
+     first integer argument.  */
+  if (ret_in_memory)
+    reg_args->gpr[gprcount++] = (unsigned long) rvalue;
+
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+
+  for (i = 0; i < avn; ++i)
+    {
+      size_t size = arg_types[i]->size;
+      int n;
+
+      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
+      if (n == 0
+	  || gprcount + ngpr > MAX_GPR_REGS
+	  || ssecount + nsse > MAX_SSE_REGS)
+	{
+	  long align = arg_types[i]->alignment;
+
+	  /* Stack arguments are *always* at least 8 byte aligned.  */
+	  if (align < 8)
+	    align = 8;
+
+	  /* Pass this argument in memory.  */
+	  argp = (void *) ALIGN (argp, align);
+	  memcpy (argp, avalue[i], size);
+	  argp += size;
+	}
+      else
+	{
+	  /* The argument is passed entirely in registers.  */
+	  char *a = (char *) avalue[i];
+	  int j;
+
+	  for (j = 0; j < n; j++, a += 8, size -= 8)
+	    {
+	      switch (classes[j])
+		{
+		case X86_64_INTEGER_CLASS:
+		case X86_64_INTEGERSI_CLASS:
+		  /* Sign-extend integer arguments passed in general
+		     purpose registers, to cope with the fact that
+		     LLVM incorrectly assumes that this will be done
+		     (the x86-64 PS ABI does not specify this). */
+		  switch (arg_types[i]->type)
+		    {
+		    case FFI_TYPE_SINT8:
+		      *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
+		      break;
+		    case FFI_TYPE_SINT16:
+		      *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
+		      break;
+		    case FFI_TYPE_SINT32:
+		      *(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
+		      break;
+		    default:
+		      reg_args->gpr[gprcount] = 0;
+		      memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
+		    }
+		  gprcount++;
+		  break;
+		case X86_64_SSE_CLASS:
+		case X86_64_SSEDF_CLASS:
+		  reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
+		  break;
+		case X86_64_SSESF_CLASS:
+		  reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
+		  break;
+		default:
+		  abort();
+		}
+	    }
+	}
+    }
+
+  ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
+		   cif->flags, rvalue, fn, ssecount);
+}
+
+
+extern void ffi_closure_unix64(void);
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+		      ffi_cif* cif,
+		      void (*fun)(ffi_cif*, void*, void**, void*),
+		      void *user_data,
+		      void *codeloc)
+{
+  volatile unsigned short *tramp;
+
+  /* Sanity check on the cif ABI.  */
+  {
+    int abi = cif->abi;
+    if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
+      return FFI_BAD_ABI;
+  }
+
+  tramp = (volatile unsigned short *) &closure->tramp[0];
+
+  tramp[0] = 0xbb49;		/* mov <code>, %r11	*/
+  *((unsigned long long * volatile) &tramp[1])
+    = (unsigned long) ffi_closure_unix64;
+  tramp[5] = 0xba49;		/* mov <data>, %r10	*/
+  *((unsigned long long * volatile) &tramp[6])
+    = (unsigned long) codeloc;
+
+  /* Set the carry bit iff the function uses any sse registers.
+     This is clc or stc, together with the first byte of the jmp.  */
+  tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
+
+  tramp[11] = 0xe3ff;			/* jmp *%r11    */
+
+  closure->cif = cif;
+  closure->fun = fun;
+  closure->user_data = user_data;
+
+  return FFI_OK;
+}
+
+int
+ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
+			 struct register_args *reg_args, char *argp)
+{
+  ffi_cif *cif;
+  void **avalue;
+  ffi_type **arg_types;
+  long i, avn;
+  int gprcount, ssecount, ngpr, nsse;
+  int ret;
+
+  cif = closure->cif;
+  avalue = alloca(cif->nargs * sizeof(void *));
+  gprcount = ssecount = 0;
+
+  ret = cif->rtype->type;
+  if (ret != FFI_TYPE_VOID)
+    {
+      enum x86_64_reg_class classes[MAX_CLASSES];
+      int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
+      if (n == 0)
+	{
+	  /* The return value goes in memory.  Arrange for the closure
+	     return value to go directly back to the original caller.  */
+	  rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
+	  /* We don't have to do anything in asm for the return.  */
+	  ret = FFI_TYPE_VOID;
+	}
+      else if (ret == FFI_TYPE_STRUCT && n == 2)
+	{
+	  /* Mark which register the second word of the structure goes in.  */
+	  _Bool sse0 = SSE_CLASS_P (classes[0]);
+	  _Bool sse1 = SSE_CLASS_P (classes[1]);
+	  if (!sse0 && sse1)
+	    ret |= 1 << 8;
+	  else if (sse0 && !sse1)
+	    ret |= 1 << 9;
+	}
+    }
+
+  avn = cif->nargs;
+  arg_types = cif->arg_types;
+  
+  for (i = 0; i < avn; ++i)
+    {
+      enum x86_64_reg_class classes[MAX_CLASSES];
+      int n;
+
+      n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
+      if (n == 0
+	  || gprcount + ngpr > MAX_GPR_REGS
+	  || ssecount + nsse > MAX_SSE_REGS)
+	{
+	  long align = arg_types[i]->alignment;
+
+	  /* Stack arguments are *always* at least 8 byte aligned.  */
+	  if (align < 8)
+	    align = 8;
+
+	  /* Pass this argument in memory.  */
+	  argp = (void *) ALIGN (argp, align);
+	  avalue[i] = argp;
+	  argp += arg_types[i]->size;
+	}
+      /* If the argument is in a single register, or two consecutive
+	 integer registers, then we can use that address directly.  */
+      else if (n == 1
+	       || (n == 2 && !(SSE_CLASS_P (classes[0])
+			       || SSE_CLASS_P (classes[1]))))
+	{
+	  /* The argument is in a single register.  */
+	  if (SSE_CLASS_P (classes[0]))
+	    {
+	      avalue[i] = &reg_args->sse[ssecount];
+	      ssecount += n;
+	    }
+	  else
+	    {
+	      avalue[i] = &reg_args->gpr[gprcount];
+	      gprcount += n;
+	    }
+	}
+      /* Otherwise, allocate space to make them consecutive.  */
+      else
+	{
+	  char *a = alloca (16);
+	  int j;
+
+	  avalue[i] = a;
+	  for (j = 0; j < n; j++, a += 8)
+	    {
+	      if (SSE_CLASS_P (classes[j]))
+		memcpy (a, &reg_args->sse[ssecount++], 8);
+	      else
+		memcpy (a, &reg_args->gpr[gprcount++], 8);
+	    }
+	}
+    }
+
+  /* Invoke the closure.  */
+  closure->fun (cif, rvalue, avalue, closure->user_data);
+
+  /* Tell assembly how to perform return type promotions.  */
+  return ret;
+}
+
+#endif /* __x86_64__ */
diff --git a/lib/wrappers/libffi/gcc/prep_cif.c b/lib/wrappers/libffi/gcc/prep_cif.c
new file mode 100644
index 000000000..e8ec5cf1e
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/prep_cif.c
@@ -0,0 +1,237 @@
+/* -----------------------------------------------------------------------
+   prep_cif.c - Copyright (c) 2011, 2012  Anthony Green
+                Copyright (c) 1996, 1998, 2007  Red Hat, Inc.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+#include <stdlib.h>
+
+/* Round up to FFI_SIZEOF_ARG. */
+
+#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
+
+/* Perform machine independent initialization of aggregate type
+   specifications. */
+
+static ffi_status initialize_aggregate(ffi_type *arg)
+{
+  ffi_type **ptr;
+
+  if (UNLIKELY(arg == NULL || arg->elements == NULL))
+    return FFI_BAD_TYPEDEF;
+
+  arg->size = 0;
+  arg->alignment = 0;
+
+  ptr = &(arg->elements[0]);
+
+  if (UNLIKELY(ptr == 0))
+    return FFI_BAD_TYPEDEF;
+
+  while ((*ptr) != NULL)
+    {
+      if (UNLIKELY(((*ptr)->size == 0)
+		    && (initialize_aggregate((*ptr)) != FFI_OK)))
+	return FFI_BAD_TYPEDEF;
+
+      /* Perform a sanity check on the argument type */
+      FFI_ASSERT_VALID_TYPE(*ptr);
+
+      arg->size = ALIGN(arg->size, (*ptr)->alignment);
+      arg->size += (*ptr)->size;
+
+      arg->alignment = (arg->alignment > (*ptr)->alignment) ?
+	arg->alignment : (*ptr)->alignment;
+
+      ptr++;
+    }
+
+  /* Structure size includes tail padding.  This is important for
+     structures that fit in one register on ABIs like the PowerPC64
+     Linux ABI that right justify small structs in a register.
+     It's also needed for nested structure layout, for example
+     struct A { long a; char b; }; struct B { struct A x; char y; };
+     should find y at an offset of 2*sizeof(long) and result in a
+     total size of 3*sizeof(long).  */
+  arg->size = ALIGN (arg->size, arg->alignment);
+
+  if (arg->size == 0)
+    return FFI_BAD_TYPEDEF;
+  else
+    return FFI_OK;
+}
+
+#ifndef __CRIS__
+/* The CRIS ABI specifies structure elements to have byte
+   alignment only, so it completely overrides this functions,
+   which assumes "natural" alignment and padding.  */
+
+/* Perform machine independent ffi_cif preparation, then call
+   machine dependent routine. */
+
+/* For non variadic functions isvariadic should be 0 and
+   nfixedargs==ntotalargs.
+
+   For variadic calls, isvariadic should be 1 and nfixedargs
+   and ntotalargs set as appropriate. nfixedargs must always be >=1 */
+
+
+ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
+			     unsigned int isvariadic,
+                             unsigned int nfixedargs,
+                             unsigned int ntotalargs,
+			     ffi_type *rtype, ffi_type **atypes)
+{
+  unsigned bytes = 0;
+  unsigned int i;
+  ffi_type **ptr;
+
+  FFI_ASSERT(cif != NULL);
+  FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
+  FFI_ASSERT(nfixedargs <= ntotalargs);
+
+#ifndef X86_WIN32
+  if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
+    return FFI_BAD_ABI;
+#else
+  if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI || abi == FFI_THISCALL))
+    return FFI_BAD_ABI;
+#endif
+
+  cif->abi = abi;
+  cif->arg_types = atypes;
+  cif->nargs = ntotalargs;
+  cif->rtype = rtype;
+
+  cif->flags = 0;
+
+  /* Initialize the return type if necessary */
+  if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
+    return FFI_BAD_TYPEDEF;
+
+  /* Perform a sanity check on the return type */
+  FFI_ASSERT_VALID_TYPE(cif->rtype);
+
+  /* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
+#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
+  /* Make space for the return structure pointer */
+  if (cif->rtype->type == FFI_TYPE_STRUCT
+#ifdef SPARC
+      && (cif->abi != FFI_V9 || cif->rtype->size > 32)
+#endif
+#ifdef TILE
+      && (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
+#endif
+#ifdef XTENSA
+      && (cif->rtype->size > 16)
+#endif
+
+     )
+    bytes = STACK_ARG_SIZE(sizeof(void*));
+#endif
+
+  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+    {
+
+      /* Initialize any uninitialized aggregate type definitions */
+      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
+	return FFI_BAD_TYPEDEF;
+
+      /* Perform a sanity check on the argument type, do this
+	 check after the initialization.  */
+      FFI_ASSERT_VALID_TYPE(*ptr);
+
+#if !defined X86_ANY && !defined S390 && !defined PA
+#ifdef SPARC
+      if (((*ptr)->type == FFI_TYPE_STRUCT
+	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
+	  || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
+	      && cif->abi != FFI_V9))
+	bytes += sizeof(void*);
+      else
+#endif
+	{
+	  /* Add any padding if necessary */
+	  if (((*ptr)->alignment - 1) & bytes)
+	    bytes = ALIGN(bytes, (*ptr)->alignment);
+
+#ifdef TILE
+	  if (bytes < 10 * FFI_SIZEOF_ARG &&
+	      bytes + STACK_ARG_SIZE((*ptr)->size) > 10 * FFI_SIZEOF_ARG)
+	    {
+	      /* An argument is never split between the 10 parameter
+		 registers and the stack.  */
+	      bytes = 10 * FFI_SIZEOF_ARG;
+	    }
+#endif
+#ifdef XTENSA
+	  if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
+	    bytes = 6*4;
+#endif
+
+	  bytes += STACK_ARG_SIZE((*ptr)->size);
+	}
+#endif
+    }
+
+  cif->bytes = bytes;
+
+  /* Perform machine dependent cif processing */
+#ifdef FFI_TARGET_SPECIFIC_VARIADIC
+  if (isvariadic)
+	return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
+#endif
+
+  return ffi_prep_cif_machdep(cif);
+}
+#endif /* not __CRIS__ */
+
+ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
+			     ffi_type *rtype, ffi_type **atypes)
+{
+  return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
+}
+
+ffi_status ffi_prep_cif_var(ffi_cif *cif,
+                            ffi_abi abi,
+                            unsigned int nfixedargs,
+                            unsigned int ntotalargs,
+                            ffi_type *rtype,
+                            ffi_type **atypes)
+{
+  return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
+}
+
+#if FFI_CLOSURES
+
+ffi_status
+ffi_prep_closure (ffi_closure* closure,
+		  ffi_cif* cif,
+		  void (*fun)(ffi_cif*,void*,void**,void*),
+		  void *user_data)
+{
+  return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
+}
+
+#endif
diff --git a/lib/wrappers/libffi/gcc/types.c b/lib/wrappers/libffi/gcc/types.c
new file mode 100644
index 000000000..0a11eb0fb
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/types.c
@@ -0,0 +1,77 @@
+/* -----------------------------------------------------------------------
+   types.c - Copyright (c) 1996, 1998  Red Hat, Inc.
+   
+   Predefined ffi_types needed by libffi.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+/* Hide the basic type definitions from the header file, so that we
+   can redefine them here as "const".  */
+#define LIBFFI_HIDE_BASIC_TYPES
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+/* Type definitions */
+
+#define FFI_TYPEDEF(name, type, id)		\
+struct struct_align_##name {			\
+  char c;					\
+  type x;					\
+};						\
+const ffi_type ffi_type_##name = {		\
+  sizeof(type),					\
+  offsetof(struct struct_align_##name, x),	\
+  id, NULL					\
+}
+
+/* Size and alignment are fake here. They must not be 0. */
+const ffi_type ffi_type_void = {
+  1, 1, FFI_TYPE_VOID, NULL
+};
+
+FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8);
+FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8);
+FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16);
+FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16);
+FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32);
+FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32);
+FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64);
+FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64);
+
+FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER);
+
+FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT);
+FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
+
+#ifdef __alpha__
+/* Even if we're not configured to default to 128-bit long double, 
+   maintain binary compatibility, as -mlong-double-128 can be used
+   at any time.  */
+/* Validate the hard-coded number below.  */
+# if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4
+#  error FFI_TYPE_LONGDOUBLE out of date
+# endif
+const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
+#elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
+FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);
+#endif
diff --git a/lib/wrappers/libffi/gcc/win32_asm.asm b/lib/wrappers/libffi/gcc/win32_asm.asm
new file mode 100644
index 000000000..ce3c4f3f3
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/win32_asm.asm
@@ -0,0 +1,759 @@
+/* -----------------------------------------------------------------------
+   win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009  Red Hat, Inc.
+	     Copyright (c) 2001  John Beniton
+	     Copyright (c) 2002  Ranjit Mathew
+	     Copyright (c) 2009  Daniel Witte
+			
+ 
+   X86 Foreign Function Interface
+ 
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+ 
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+ 
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   -----------------------------------------------------------------------
+   */
+ 
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+#include <ffitarget.h>
+
+	.text
+ 
+        // This assumes we are using gas.
+        .balign 16
+	.globl	_ffi_call_win32
+#ifndef __OS2__
+	.def	_ffi_call_win32;	.scl	2;	.type	32;	.endef
+#endif
+_ffi_call_win32:
+.LFB1:
+        pushl %ebp
+.LCFI0:
+        movl  %esp,%ebp
+.LCFI1:
+        // Make room for all of the new args.
+        movl  20(%ebp),%ecx                                                     
+        subl  %ecx,%esp
+ 
+        movl  %esp,%eax
+ 
+        // Place all of the ffi_prep_args in position
+        pushl 12(%ebp)
+        pushl %eax
+        call  *8(%ebp)
+ 
+        // Return stack to previous state and call the function
+        addl  $8,%esp
+
+	// Handle fastcall and thiscall
+	cmpl $3, 16(%ebp)  // FFI_THISCALL
+	jz .do_thiscall
+	cmpl $4, 16(%ebp) // FFI_FASTCALL
+	jnz .do_fncall
+	movl (%esp), %ecx
+	movl 4(%esp), %edx
+	addl $8, %esp
+	jmp .do_fncall
+.do_thiscall:
+	movl (%esp), %ecx
+	addl $4, %esp
+
+.do_fncall:
+	 
+        // FIXME: Align the stack to a 128-bit boundary to avoid
+        // potential performance hits.
+
+        call  *32(%ebp)
+ 
+        // stdcall functions pop arguments off the stack themselves
+
+        // Load %ecx with the return type code
+        movl  24(%ebp),%ecx
+ 
+        // If the return value pointer is NULL, assume no return value.
+        cmpl  $0,28(%ebp)
+        jne   0f
+ 
+        // Even if there is no space for the return value, we are
+        // obliged to handle floating-point values.
+        cmpl  $FFI_TYPE_FLOAT,%ecx
+        jne   .Lnoretval
+        fstp  %st(0)
+ 
+        jmp   .Lepilogue
+
+0:
+	call	1f
+	// Do not insert anything here between the call and the jump table.
+.Lstore_table:
+	.long	.Lnoretval		/* FFI_TYPE_VOID */
+	.long	.Lretint		/* FFI_TYPE_INT */
+	.long	.Lretfloat		/* FFI_TYPE_FLOAT */
+	.long	.Lretdouble		/* FFI_TYPE_DOUBLE */
+	.long	.Lretlongdouble		/* FFI_TYPE_LONGDOUBLE */
+	.long	.Lretuint8		/* FFI_TYPE_UINT8 */
+	.long	.Lretsint8		/* FFI_TYPE_SINT8 */
+	.long	.Lretuint16		/* FFI_TYPE_UINT16 */
+	.long	.Lretsint16		/* FFI_TYPE_SINT16 */
+	.long	.Lretint		/* FFI_TYPE_UINT32 */
+	.long	.Lretint		/* FFI_TYPE_SINT32 */
+	.long	.Lretint64		/* FFI_TYPE_UINT64 */
+	.long	.Lretint64		/* FFI_TYPE_SINT64 */
+	.long	.Lretstruct		/* FFI_TYPE_STRUCT */
+	.long	.Lretint		/* FFI_TYPE_POINTER */
+	.long	.Lretstruct1b		/* FFI_TYPE_SMALL_STRUCT_1B */
+	.long	.Lretstruct2b		/* FFI_TYPE_SMALL_STRUCT_2B */
+	.long	.Lretstruct4b		/* FFI_TYPE_SMALL_STRUCT_4B */
+	.long	.Lretstruct		/* FFI_TYPE_MS_STRUCT */
+1:
+	add	%ecx, %ecx
+	add	%ecx, %ecx
+	add	(%esp),%ecx
+	add	$4, %esp
+	jmp	*(%ecx)
+
+	/* Sign/zero extend as appropriate.  */
+.Lretsint8:
+	movsbl	%al, %eax
+	jmp	.Lretint
+
+.Lretsint16:
+	movswl	%ax, %eax
+	jmp	.Lretint
+
+.Lretuint8:
+	movzbl	%al, %eax
+	jmp	.Lretint
+
+.Lretuint16:
+	movzwl	%ax, %eax
+	jmp	.Lretint
+
+.Lretint:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        movl  %eax,0(%ecx)
+        jmp   .Lepilogue
+ 
+.Lretfloat:
+         // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        fstps (%ecx)
+        jmp   .Lepilogue
+ 
+.Lretdouble:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        fstpl (%ecx)
+        jmp   .Lepilogue
+ 
+.Lretlongdouble:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        fstpt (%ecx)
+        jmp   .Lepilogue
+ 
+.Lretint64:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        movl  %eax,0(%ecx)
+        movl  %edx,4(%ecx)
+	jmp   .Lepilogue
+
+.Lretstruct1b:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        movb  %al,0(%ecx)
+        jmp   .Lepilogue
+ 
+.Lretstruct2b:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        movw  %ax,0(%ecx)
+        jmp   .Lepilogue
+
+.Lretstruct4b:
+        // Load %ecx with the pointer to storage for the return value
+        movl  28(%ebp),%ecx
+        movl  %eax,0(%ecx)
+        jmp   .Lepilogue
+
+.Lretstruct:
+        // Nothing to do!
+ 
+.Lnoretval:
+.Lepilogue:
+        movl %ebp,%esp
+        popl %ebp
+        ret
+.ffi_call_win32_end:
+        .balign 16
+	.globl	_ffi_closure_THISCALL
+#ifndef __OS2__
+	.def	_ffi_closure_THISCALL;	.scl	2;	.type	32;	.endef
+#endif
+_ffi_closure_THISCALL:
+	pushl	%ebp
+	movl	%esp, %ebp
+	subl	$40, %esp
+	leal	-24(%ebp), %edx
+	movl	%edx, -12(%ebp)	/* resp */
+	leal	12(%ebp), %edx  /* account for stub return address on stack */
+	jmp	.stub
+.LFE1:
+
+        // This assumes we are using gas.
+        .balign 16
+	.globl	_ffi_closure_SYSV
+#ifndef __OS2__
+	.def	_ffi_closure_SYSV;	.scl	2;	.type	32;	.endef
+#endif
+_ffi_closure_SYSV:
+.LFB3:
+	pushl	%ebp
+.LCFI4:
+	movl	%esp, %ebp
+.LCFI5:
+	subl	$40, %esp
+	leal	-24(%ebp), %edx
+	movl	%edx, -12(%ebp)	/* resp */
+	leal	8(%ebp), %edx
+.stub:
+	movl	%edx, 4(%esp)	/* args = __builtin_dwarf_cfa () */
+	leal	-12(%ebp), %edx
+	movl	%edx, (%esp)	/* &resp */
+	call	_ffi_closure_SYSV_inner
+	movl	-12(%ebp), %ecx
+
+0:
+	call	1f
+	// Do not insert anything here between the call and the jump table.
+.Lcls_store_table:
+	.long	.Lcls_noretval		/* FFI_TYPE_VOID */
+	.long	.Lcls_retint		/* FFI_TYPE_INT */
+	.long	.Lcls_retfloat		/* FFI_TYPE_FLOAT */
+	.long	.Lcls_retdouble		/* FFI_TYPE_DOUBLE */
+	.long	.Lcls_retldouble	/* FFI_TYPE_LONGDOUBLE */
+	.long	.Lcls_retuint8		/* FFI_TYPE_UINT8 */
+	.long	.Lcls_retsint8		/* FFI_TYPE_SINT8 */
+	.long	.Lcls_retuint16		/* FFI_TYPE_UINT16 */
+	.long	.Lcls_retsint16		/* FFI_TYPE_SINT16 */
+	.long	.Lcls_retint		/* FFI_TYPE_UINT32 */
+	.long	.Lcls_retint		/* FFI_TYPE_SINT32 */
+	.long	.Lcls_retllong		/* FFI_TYPE_UINT64 */
+	.long	.Lcls_retllong		/* FFI_TYPE_SINT64 */
+	.long	.Lcls_retstruct		/* FFI_TYPE_STRUCT */
+	.long	.Lcls_retint		/* FFI_TYPE_POINTER */
+	.long	.Lcls_retstruct1	/* FFI_TYPE_SMALL_STRUCT_1B */
+	.long	.Lcls_retstruct2	/* FFI_TYPE_SMALL_STRUCT_2B */
+	.long	.Lcls_retstruct4	/* FFI_TYPE_SMALL_STRUCT_4B */
+	.long	.Lcls_retmsstruct	/* FFI_TYPE_MS_STRUCT */
+
+1:
+	add	%eax, %eax
+	add	%eax, %eax
+	add	(%esp),%eax
+	add	$4, %esp
+	jmp	*(%eax)
+
+	/* Sign/zero extend as appropriate.  */
+.Lcls_retsint8:
+	movsbl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retsint16:
+	movswl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retuint8:
+	movzbl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retuint16:
+	movzwl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retint:
+	movl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retfloat:
+	flds	(%ecx)
+	jmp	.Lcls_epilogue
+
+.Lcls_retdouble:
+	fldl	(%ecx)
+	jmp	.Lcls_epilogue
+
+.Lcls_retldouble:
+	fldt	(%ecx)
+	jmp	.Lcls_epilogue
+
+.Lcls_retllong:
+	movl	(%ecx), %eax
+	movl	4(%ecx), %edx
+	jmp	.Lcls_epilogue
+
+.Lcls_retstruct1:
+	movsbl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retstruct2:
+	movswl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retstruct4:
+	movl	(%ecx), %eax
+	jmp	.Lcls_epilogue
+
+.Lcls_retstruct:
+        // Caller expects us to pop struct return value pointer hidden arg.
+	movl	%ebp, %esp
+	popl	%ebp
+	ret	$0x4
+
+.Lcls_retmsstruct:
+	// Caller expects us to return a pointer to the real return value.
+	mov	%ecx, %eax
+	// Caller doesn't expects us to pop struct return value pointer hidden arg.
+	jmp	.Lcls_epilogue
+
+.Lcls_noretval:
+.Lcls_epilogue:
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+.ffi_closure_SYSV_end:
+.LFE3:
+
+#if !FFI_NO_RAW_API
+
+#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
+#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
+#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
+#define CIF_FLAGS_OFFSET 20
+        .balign 16
+	.globl	_ffi_closure_raw_THISCALL
+#ifndef __OS2__
+	.def	_ffi_closure_raw_THISCALL;	.scl	2;	.type	32;	.endef
+#endif
+_ffi_closure_raw_THISCALL:
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%esi
+	subl	$36, %esp
+	movl	RAW_CLOSURE_CIF_OFFSET(%eax), %esi	 /* closure->cif */
+	movl	RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
+	movl	%edx, 12(%esp)	/* user_data */
+	leal	12(%ebp), %edx	/* __builtin_dwarf_cfa () */
+	jmp	.stubraw
+        // This assumes we are using gas.
+        .balign 16
+	.globl	_ffi_closure_raw_SYSV
+#ifndef __OS2__
+	.def	_ffi_closure_raw_SYSV;	.scl	2;	.type	32;	.endef
+#endif
+_ffi_closure_raw_SYSV:
+.LFB4:
+	pushl	%ebp
+.LCFI6:
+	movl	%esp, %ebp
+.LCFI7:
+	pushl	%esi
+.LCFI8:
+	subl	$36, %esp
+	movl	RAW_CLOSURE_CIF_OFFSET(%eax), %esi	 /* closure->cif */
+	movl	RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
+	movl	%edx, 12(%esp)	/* user_data */
+	leal	8(%ebp), %edx	/* __builtin_dwarf_cfa () */
+.stubraw:
+	movl	%edx, 8(%esp)	/* raw_args */
+	leal	-24(%ebp), %edx
+	movl	%edx, 4(%esp)	/* &res */
+	movl	%esi, (%esp)	/* cif */
+	call	*RAW_CLOSURE_FUN_OFFSET(%eax)		 /* closure->fun */
+	movl	CIF_FLAGS_OFFSET(%esi), %eax		 /* rtype */
+0:
+	call	1f
+	// Do not insert anything here between the call and the jump table.
+.Lrcls_store_table:
+	.long	.Lrcls_noretval		/* FFI_TYPE_VOID */
+	.long	.Lrcls_retint		/* FFI_TYPE_INT */
+	.long	.Lrcls_retfloat		/* FFI_TYPE_FLOAT */
+	.long	.Lrcls_retdouble	/* FFI_TYPE_DOUBLE */
+	.long	.Lrcls_retldouble	/* FFI_TYPE_LONGDOUBLE */
+	.long	.Lrcls_retuint8		/* FFI_TYPE_UINT8 */
+	.long	.Lrcls_retsint8		/* FFI_TYPE_SINT8 */
+	.long	.Lrcls_retuint16	/* FFI_TYPE_UINT16 */
+	.long	.Lrcls_retsint16	/* FFI_TYPE_SINT16 */
+	.long	.Lrcls_retint		/* FFI_TYPE_UINT32 */
+	.long	.Lrcls_retint		/* FFI_TYPE_SINT32 */
+	.long	.Lrcls_retllong		/* FFI_TYPE_UINT64 */
+	.long	.Lrcls_retllong		/* FFI_TYPE_SINT64 */
+	.long	.Lrcls_retstruct	/* FFI_TYPE_STRUCT */
+	.long	.Lrcls_retint		/* FFI_TYPE_POINTER */
+	.long	.Lrcls_retstruct1	/* FFI_TYPE_SMALL_STRUCT_1B */
+	.long	.Lrcls_retstruct2	/* FFI_TYPE_SMALL_STRUCT_2B */
+	.long	.Lrcls_retstruct4	/* FFI_TYPE_SMALL_STRUCT_4B */
+	.long	.Lrcls_retstruct	/* FFI_TYPE_MS_STRUCT */
+1:
+	add	%eax, %eax
+	add	%eax, %eax
+	add	(%esp),%eax
+	add	$4, %esp
+	jmp	*(%eax)
+
+	/* Sign/zero extend as appropriate.  */
+.Lrcls_retsint8:
+	movsbl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retsint16:
+	movswl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retuint8:
+	movzbl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retuint16:
+	movzwl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retint:
+	movl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retfloat:
+	flds	-24(%ebp)
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retdouble:
+	fldl	-24(%ebp)
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retldouble:
+	fldt	-24(%ebp)
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retllong:
+	movl	-24(%ebp), %eax
+	movl	-20(%ebp), %edx
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retstruct1:
+	movsbl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retstruct2:
+	movswl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retstruct4:
+	movl	-24(%ebp), %eax
+	jmp	.Lrcls_epilogue
+
+.Lrcls_retstruct:
+	// Nothing to do!
+
+.Lrcls_noretval:
+.Lrcls_epilogue:
+	addl	$36, %esp
+	popl	%esi
+	popl	%ebp
+	ret
+.ffi_closure_raw_SYSV_end:
+.LFE4:
+
+#endif /* !FFI_NO_RAW_API */
+
+        // This assumes we are using gas.
+	.balign	16
+	.globl	_ffi_closure_STDCALL
+#ifndef __OS2__
+	.def	_ffi_closure_STDCALL;	.scl	2;	.type	32;	.endef
+#endif
+_ffi_closure_STDCALL:
+.LFB5:
+	pushl	%ebp
+.LCFI9:
+	movl	%esp, %ebp
+.LCFI10:
+	subl	$40, %esp
+	leal	-24(%ebp), %edx
+	movl	%edx, -12(%ebp)	/* resp */
+	leal	12(%ebp), %edx  /* account for stub return address on stack */
+	movl	%edx, 4(%esp)	/* args */
+	leal	-12(%ebp), %edx
+	movl	%edx, (%esp)	/* &resp */
+	call	_ffi_closure_SYSV_inner
+	movl	-12(%ebp), %ecx
+0:
+	call	1f
+	// Do not insert anything here between the call and the jump table.
+.Lscls_store_table:
+	.long	.Lscls_noretval		/* FFI_TYPE_VOID */
+	.long	.Lscls_retint		/* FFI_TYPE_INT */
+	.long	.Lscls_retfloat		/* FFI_TYPE_FLOAT */
+	.long	.Lscls_retdouble	/* FFI_TYPE_DOUBLE */
+	.long	.Lscls_retldouble	/* FFI_TYPE_LONGDOUBLE */
+	.long	.Lscls_retuint8		/* FFI_TYPE_UINT8 */
+	.long	.Lscls_retsint8		/* FFI_TYPE_SINT8 */
+	.long	.Lscls_retuint16	/* FFI_TYPE_UINT16 */
+	.long	.Lscls_retsint16	/* FFI_TYPE_SINT16 */
+	.long	.Lscls_retint		/* FFI_TYPE_UINT32 */
+	.long	.Lscls_retint		/* FFI_TYPE_SINT32 */
+	.long	.Lscls_retllong		/* FFI_TYPE_UINT64 */
+	.long	.Lscls_retllong		/* FFI_TYPE_SINT64 */
+	.long	.Lscls_retstruct	/* FFI_TYPE_STRUCT */
+	.long	.Lscls_retint		/* FFI_TYPE_POINTER */
+	.long	.Lscls_retstruct1	/* FFI_TYPE_SMALL_STRUCT_1B */
+	.long	.Lscls_retstruct2	/* FFI_TYPE_SMALL_STRUCT_2B */
+	.long	.Lscls_retstruct4	/* FFI_TYPE_SMALL_STRUCT_4B */
+1:
+	add	%eax, %eax
+	add	%eax, %eax
+	add	(%esp),%eax
+	add	$4, %esp
+	jmp	*(%eax)
+
+	/* Sign/zero extend as appropriate.  */
+.Lscls_retsint8:
+	movsbl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retsint16:
+	movswl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retuint8:
+	movzbl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retuint16:
+	movzwl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retint:
+	movl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retfloat:
+	flds	(%ecx)
+	jmp	.Lscls_epilogue
+
+.Lscls_retdouble:
+	fldl	(%ecx)
+	jmp	.Lscls_epilogue
+
+.Lscls_retldouble:
+	fldt	(%ecx)
+	jmp	.Lscls_epilogue
+
+.Lscls_retllong:
+	movl	(%ecx), %eax
+	movl	4(%ecx), %edx
+	jmp	.Lscls_epilogue
+
+.Lscls_retstruct1:
+	movsbl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retstruct2:
+	movswl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retstruct4:
+	movl	(%ecx), %eax
+	jmp	.Lscls_epilogue
+
+.Lscls_retstruct:
+	// Nothing to do!
+
+.Lscls_noretval:
+.Lscls_epilogue:
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+.ffi_closure_STDCALL_end:
+.LFE5:
+
+#ifndef __OS2__
+	.section	.eh_frame,"w"
+#endif
+.Lframe1:
+.LSCIE1:
+	.long	.LECIE1-.LASCIE1  /* Length of Common Information Entry */
+.LASCIE1:
+	.long	0x0	/* CIE Identifier Tag */
+	.byte	0x1	/* CIE Version */
+#ifdef __PIC__
+	.ascii "zR\0"	/* CIE Augmentation */
+#else
+	.ascii "\0"	/* CIE Augmentation */
+#endif
+	.byte	0x1	/* .uleb128 0x1; CIE Code Alignment Factor */
+	.byte	0x7c	/* .sleb128 -4; CIE Data Alignment Factor */
+	.byte	0x8	/* CIE RA Column */
+#ifdef __PIC__
+	.byte	0x1	/* .uleb128 0x1; Augmentation size */
+	.byte	0x1b	/* FDE Encoding (pcrel sdata4) */
+#endif
+	.byte	0xc	/* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */
+	.byte	0x4	/* .uleb128 0x4 */
+	.byte	0x4	/* .uleb128 0x4 */
+	.byte	0x88	/* DW_CFA_offset, column 0x8 %eip at CFA + 1 * -4 */
+	.byte	0x1	/* .uleb128 0x1 */
+	.align 4
+.LECIE1:
+
+.LSFDE1:
+	.long	.LEFDE1-.LASFDE1	/* FDE Length */
+.LASFDE1:
+	.long	.LASFDE1-.Lframe1	/* FDE CIE offset */
+#if defined __PIC__ && defined HAVE_AS_X86_PCREL
+	.long	.LFB1-.	/* FDE initial location */
+#else
+	.long	.LFB1
+#endif
+	.long	.LFE1-.LFB1	/* FDE address range */
+#ifdef __PIC__
+	.byte	0x0	/* .uleb128 0x0; Augmentation size */
+#endif
+	/* DW_CFA_xxx CFI instructions go here.  */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI0-.LFB1
+	.byte	0xe	/* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
+	.byte	0x8	/* .uleb128 0x8 */
+	.byte	0x85	/* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
+	.byte	0x2	/* .uleb128 0x2 */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI1-.LCFI0
+	.byte	0xd	/* DW_CFA_def_cfa_register CFA = r5 = %ebp */
+	.byte	0x5	/* .uleb128 0x5 */
+
+	/* End of DW_CFA_xxx CFI instructions.  */
+	.align 4
+.LEFDE1:
+
+
+.LSFDE3:
+	.long	.LEFDE3-.LASFDE3	/* FDE Length */
+.LASFDE3:
+	.long	.LASFDE3-.Lframe1	/* FDE CIE offset */
+#if defined __PIC__ && defined HAVE_AS_X86_PCREL
+	.long	.LFB3-.	/* FDE initial location */
+#else
+	.long	.LFB3
+#endif
+	.long	.LFE3-.LFB3	/* FDE address range */
+#ifdef __PIC__
+	.byte	0x0	/* .uleb128 0x0; Augmentation size */
+#endif
+	/* DW_CFA_xxx CFI instructions go here.  */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI4-.LFB3
+	.byte	0xe	/* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
+	.byte	0x8	/* .uleb128 0x8 */
+	.byte	0x85	/* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
+	.byte	0x2	/* .uleb128 0x2 */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI5-.LCFI4
+	.byte	0xd	/* DW_CFA_def_cfa_register CFA = r5 = %ebp */
+	.byte	0x5	/* .uleb128 0x5 */
+
+	/* End of DW_CFA_xxx CFI instructions.  */
+	.align 4
+.LEFDE3:
+
+#if !FFI_NO_RAW_API
+
+.LSFDE4:
+	.long	.LEFDE4-.LASFDE4	/* FDE Length */
+.LASFDE4:
+	.long	.LASFDE4-.Lframe1	/* FDE CIE offset */
+#if defined __PIC__ && defined HAVE_AS_X86_PCREL
+	.long	.LFB4-.	/* FDE initial location */
+#else
+	.long	.LFB4
+#endif
+	.long	.LFE4-.LFB4	/* FDE address range */
+#ifdef __PIC__
+	.byte	0x0	/* .uleb128 0x0; Augmentation size */
+#endif
+	/* DW_CFA_xxx CFI instructions go here.  */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI6-.LFB4
+	.byte	0xe	/* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
+	.byte	0x8	/* .uleb128 0x8 */
+	.byte	0x85	/* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
+	.byte	0x2	/* .uleb128 0x2 */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI7-.LCFI6
+	.byte	0xd	/* DW_CFA_def_cfa_register CFA = r5 = %ebp */
+	.byte	0x5	/* .uleb128 0x5 */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI8-.LCFI7
+	.byte	0x86	/* DW_CFA_offset, column 0x6 %esi at CFA + 3 * -4 */
+	.byte	0x3	/* .uleb128 0x3 */
+
+	/* End of DW_CFA_xxx CFI instructions.  */
+	.align 4
+.LEFDE4:
+
+#endif /* !FFI_NO_RAW_API */
+
+.LSFDE5:
+	.long	.LEFDE5-.LASFDE5	/* FDE Length */
+.LASFDE5:
+	.long	.LASFDE5-.Lframe1	/* FDE CIE offset */
+#if defined __PIC__ && defined HAVE_AS_X86_PCREL
+	.long	.LFB5-.	/* FDE initial location */
+#else
+	.long	.LFB5
+#endif
+	.long	.LFE5-.LFB5	/* FDE address range */
+#ifdef __PIC__
+	.byte	0x0	/* .uleb128 0x0; Augmentation size */
+#endif
+	/* DW_CFA_xxx CFI instructions go here.  */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI9-.LFB5
+	.byte	0xe	/* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
+	.byte	0x8	/* .uleb128 0x8 */
+	.byte	0x85	/* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
+	.byte	0x2	/* .uleb128 0x2 */
+
+	.byte	0x4	/* DW_CFA_advance_loc4 */
+	.long	.LCFI10-.LCFI9
+	.byte	0xd	/* DW_CFA_def_cfa_register CFA = r5 = %ebp */
+	.byte	0x5	/* .uleb128 0x5 */
+
+	/* End of DW_CFA_xxx CFI instructions.  */
+	.align 4
+.LEFDE5:
diff --git a/lib/wrappers/libffi/gcc/win32_asm.s b/lib/wrappers/libffi/gcc/win32_asm.s
new file mode 100644
index 000000000..7a3e7f16c
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/win32_asm.s
@@ -0,0 +1,736 @@
+# 1 "gcc\\win32_asm.asm"

+# 1 "<command-line>"

+# 1 "gcc\\win32_asm.asm"

+# 33 "gcc\\win32_asm.asm"

+# 1 "common/fficonfig.h" 1

+# 34 "gcc\\win32_asm.asm" 2

+# 1 "common/ffi.h" 1

+# 63 "common/ffi.h"

+# 1 "common/ffitarget.h" 1

+# 64 "common/ffi.h" 2

+# 35 "gcc\\win32_asm.asm" 2

+

+

+ .text

+

+

+        .balign 16

+ .globl _ffi_call_win32

+

+ .def _ffi_call_win32; .scl 2; .type 32; .endef

+

+_ffi_call_win32:

+.LFB1:

+        pushl %ebp

+.LCFI0:

+        movl %esp,%ebp

+.LCFI1:

+

+        movl 20(%ebp),%ecx

+        subl %ecx,%esp

+

+        movl %esp,%eax

+

+

+        pushl 12(%ebp)

+        pushl %eax

+        call *8(%ebp)

+

+

+        addl $8,%esp

+

+

+ cmpl $3, 16(%ebp)

+ jz .do_thiscall

+ cmpl $4, 16(%ebp)

+ jnz .do_fncall

+ movl (%esp), %ecx

+ movl 4(%esp), %edx

+ addl $8, %esp

+ jmp .do_fncall

+.do_thiscall:

+ movl (%esp), %ecx

+ addl $4, %esp

+

+.do_fncall:

+

+

+

+

+        call *32(%ebp)

+

+

+

+

+        movl 24(%ebp),%ecx

+

+

+        cmpl $0,28(%ebp)

+        jne 0f

+

+

+

+        cmpl $2,%ecx

+        jne .Lnoretval

+        fstp %st(0)

+

+        jmp .Lepilogue

+

+0:

+ call 1f

+

+.Lstore_table:

+ .long .Lnoretval

+ .long .Lretint

+ .long .Lretfloat

+ .long .Lretdouble

+ .long .Lretlongdouble

+ .long .Lretuint8

+ .long .Lretsint8

+ .long .Lretuint16

+ .long .Lretsint16

+ .long .Lretint

+ .long .Lretint

+ .long .Lretint64

+ .long .Lretint64

+ .long .Lretstruct

+ .long .Lretint

+ .long .Lretstruct1b

+ .long .Lretstruct2b

+ .long .Lretstruct4b

+ .long .Lretstruct

+1:

+ add %ecx, %ecx

+ add %ecx, %ecx

+ add (%esp),%ecx

+ add $4, %esp

+ jmp *(%ecx)

+

+

+.Lretsint8:

+ movsbl %al, %eax

+ jmp .Lretint

+

+.Lretsint16:

+ movswl %ax, %eax

+ jmp .Lretint

+

+.Lretuint8:

+ movzbl %al, %eax

+ jmp .Lretint

+

+.Lretuint16:

+ movzwl %ax, %eax

+ jmp .Lretint

+

+.Lretint:

+

+        movl 28(%ebp),%ecx

+        movl %eax,0(%ecx)

+        jmp .Lepilogue

+

+.Lretfloat:

+

+        movl 28(%ebp),%ecx

+        fstps (%ecx)

+        jmp .Lepilogue

+

+.Lretdouble:

+

+        movl 28(%ebp),%ecx

+        fstpl (%ecx)

+        jmp .Lepilogue

+

+.Lretlongdouble:

+

+        movl 28(%ebp),%ecx

+        fstpt (%ecx)

+        jmp .Lepilogue

+

+.Lretint64:

+

+        movl 28(%ebp),%ecx

+        movl %eax,0(%ecx)

+        movl %edx,4(%ecx)

+ jmp .Lepilogue

+

+.Lretstruct1b:

+

+        movl 28(%ebp),%ecx

+        movb %al,0(%ecx)

+        jmp .Lepilogue

+

+.Lretstruct2b:

+

+        movl 28(%ebp),%ecx

+        movw %ax,0(%ecx)

+        jmp .Lepilogue

+

+.Lretstruct4b:

+

+        movl 28(%ebp),%ecx

+        movl %eax,0(%ecx)

+        jmp .Lepilogue

+

+.Lretstruct:

+

+

+.Lnoretval:

+.Lepilogue:

+        movl %ebp,%esp

+        popl %ebp

+        ret

+.ffi_call_win32_end:

+        .balign 16

+ .globl _ffi_closure_THISCALL

+

+ .def _ffi_closure_THISCALL; .scl 2; .type 32; .endef

+

+_ffi_closure_THISCALL:

+ pushl %ebp

+ movl %esp, %ebp

+ subl $40, %esp

+ leal -24(%ebp), %edx

+ movl %edx, -12(%ebp)

+ leal 12(%ebp), %edx

+ jmp .stub

+.LFE1:

+

+

+        .balign 16

+ .globl _ffi_closure_SYSV

+

+ .def _ffi_closure_SYSV; .scl 2; .type 32; .endef

+

+_ffi_closure_SYSV:

+.LFB3:

+ pushl %ebp

+.LCFI4:

+ movl %esp, %ebp

+.LCFI5:

+ subl $40, %esp

+ leal -24(%ebp), %edx

+ movl %edx, -12(%ebp)

+ leal 8(%ebp), %edx

+.stub:

+ movl %edx, 4(%esp)

+ leal -12(%ebp), %edx

+ movl %edx, (%esp)

+ call _ffi_closure_SYSV_inner

+ movl -12(%ebp), %ecx

+

+0:

+ call 1f

+

+.Lcls_store_table:

+ .long .Lcls_noretval

+ .long .Lcls_retint

+ .long .Lcls_retfloat

+ .long .Lcls_retdouble

+ .long .Lcls_retldouble

+ .long .Lcls_retuint8

+ .long .Lcls_retsint8

+ .long .Lcls_retuint16

+ .long .Lcls_retsint16

+ .long .Lcls_retint

+ .long .Lcls_retint

+ .long .Lcls_retllong

+ .long .Lcls_retllong

+ .long .Lcls_retstruct

+ .long .Lcls_retint

+ .long .Lcls_retstruct1

+ .long .Lcls_retstruct2

+ .long .Lcls_retstruct4

+ .long .Lcls_retmsstruct

+

+1:

+ add %eax, %eax

+ add %eax, %eax

+ add (%esp),%eax

+ add $4, %esp

+ jmp *(%eax)

+

+

+.Lcls_retsint8:

+ movsbl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retsint16:

+ movswl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retuint8:

+ movzbl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retuint16:

+ movzwl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retint:

+ movl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retfloat:

+ flds (%ecx)

+ jmp .Lcls_epilogue

+

+.Lcls_retdouble:

+ fldl (%ecx)

+ jmp .Lcls_epilogue

+

+.Lcls_retldouble:

+ fldt (%ecx)

+ jmp .Lcls_epilogue

+

+.Lcls_retllong:

+ movl (%ecx), %eax

+ movl 4(%ecx), %edx

+ jmp .Lcls_epilogue

+

+.Lcls_retstruct1:

+ movsbl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retstruct2:

+ movswl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retstruct4:

+ movl (%ecx), %eax

+ jmp .Lcls_epilogue

+

+.Lcls_retstruct:

+

+ movl %ebp, %esp

+ popl %ebp

+ ret $0x4

+

+.Lcls_retmsstruct:

+

+ mov %ecx, %eax

+

+ jmp .Lcls_epilogue

+

+.Lcls_noretval:

+.Lcls_epilogue:

+ movl %ebp, %esp

+ popl %ebp

+ ret

+.ffi_closure_SYSV_end:

+.LFE3:

+

+

+

+

+

+

+

+        .balign 16

+ .globl _ffi_closure_raw_THISCALL

+

+ .def _ffi_closure_raw_THISCALL; .scl 2; .type 32; .endef

+

+_ffi_closure_raw_THISCALL:

+ pushl %ebp

+ movl %esp, %ebp

+ pushl %esi

+ subl $36, %esp

+ movl ((52 + 3) & ~3)(%eax), %esi

+ movl ((((52 + 3) & ~3) + 4) + 4)(%eax), %edx

+ movl %edx, 12(%esp)

+ leal 12(%ebp), %edx

+ jmp .stubraw

+

+        .balign 16

+ .globl _ffi_closure_raw_SYSV

+

+ .def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef

+

+_ffi_closure_raw_SYSV:

+.LFB4:

+ pushl %ebp

+.LCFI6:

+ movl %esp, %ebp

+.LCFI7:

+ pushl %esi

+.LCFI8:

+ subl $36, %esp

+ movl ((52 + 3) & ~3)(%eax), %esi

+ movl ((((52 + 3) & ~3) + 4) + 4)(%eax), %edx

+ movl %edx, 12(%esp)

+ leal 8(%ebp), %edx

+.stubraw:

+ movl %edx, 8(%esp)

+ leal -24(%ebp), %edx

+ movl %edx, 4(%esp)

+ movl %esi, (%esp)

+ call *(((52 + 3) & ~3) + 4)(%eax)

+ movl 20(%esi), %eax

+0:

+ call 1f

+

+.Lrcls_store_table:

+ .long .Lrcls_noretval

+ .long .Lrcls_retint

+ .long .Lrcls_retfloat

+ .long .Lrcls_retdouble

+ .long .Lrcls_retldouble

+ .long .Lrcls_retuint8

+ .long .Lrcls_retsint8

+ .long .Lrcls_retuint16

+ .long .Lrcls_retsint16

+ .long .Lrcls_retint

+ .long .Lrcls_retint

+ .long .Lrcls_retllong

+ .long .Lrcls_retllong

+ .long .Lrcls_retstruct

+ .long .Lrcls_retint

+ .long .Lrcls_retstruct1

+ .long .Lrcls_retstruct2

+ .long .Lrcls_retstruct4

+ .long .Lrcls_retstruct

+1:

+ add %eax, %eax

+ add %eax, %eax

+ add (%esp),%eax

+ add $4, %esp

+ jmp *(%eax)

+

+

+.Lrcls_retsint8:

+ movsbl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retsint16:

+ movswl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retuint8:

+ movzbl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retuint16:

+ movzwl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retint:

+ movl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retfloat:

+ flds -24(%ebp)

+ jmp .Lrcls_epilogue

+

+.Lrcls_retdouble:

+ fldl -24(%ebp)

+ jmp .Lrcls_epilogue

+

+.Lrcls_retldouble:

+ fldt -24(%ebp)

+ jmp .Lrcls_epilogue

+

+.Lrcls_retllong:

+ movl -24(%ebp), %eax

+ movl -20(%ebp), %edx

+ jmp .Lrcls_epilogue

+

+.Lrcls_retstruct1:

+ movsbl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retstruct2:

+ movswl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retstruct4:

+ movl -24(%ebp), %eax

+ jmp .Lrcls_epilogue

+

+.Lrcls_retstruct:

+

+

+.Lrcls_noretval:

+.Lrcls_epilogue:

+ addl $36, %esp

+ popl %esi

+ popl %ebp

+ ret

+.ffi_closure_raw_SYSV_end:

+.LFE4:

+

+

+

+

+ .balign 16

+ .globl _ffi_closure_STDCALL

+

+ .def _ffi_closure_STDCALL; .scl 2; .type 32; .endef

+

+_ffi_closure_STDCALL:

+.LFB5:

+ pushl %ebp

+.LCFI9:

+ movl %esp, %ebp

+.LCFI10:

+ subl $40, %esp

+ leal -24(%ebp), %edx

+ movl %edx, -12(%ebp)

+ leal 12(%ebp), %edx

+ movl %edx, 4(%esp)

+ leal -12(%ebp), %edx

+ movl %edx, (%esp)

+ call _ffi_closure_SYSV_inner

+ movl -12(%ebp), %ecx

+0:

+ call 1f

+

+.Lscls_store_table:

+ .long .Lscls_noretval

+ .long .Lscls_retint

+ .long .Lscls_retfloat

+ .long .Lscls_retdouble

+ .long .Lscls_retldouble

+ .long .Lscls_retuint8

+ .long .Lscls_retsint8

+ .long .Lscls_retuint16

+ .long .Lscls_retsint16

+ .long .Lscls_retint

+ .long .Lscls_retint

+ .long .Lscls_retllong

+ .long .Lscls_retllong

+ .long .Lscls_retstruct

+ .long .Lscls_retint

+ .long .Lscls_retstruct1

+ .long .Lscls_retstruct2

+ .long .Lscls_retstruct4

+1:

+ add %eax, %eax

+ add %eax, %eax

+ add (%esp),%eax

+ add $4, %esp

+ jmp *(%eax)

+

+

+.Lscls_retsint8:

+ movsbl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retsint16:

+ movswl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retuint8:

+ movzbl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retuint16:

+ movzwl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retint:

+ movl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retfloat:

+ flds (%ecx)

+ jmp .Lscls_epilogue

+

+.Lscls_retdouble:

+ fldl (%ecx)

+ jmp .Lscls_epilogue

+

+.Lscls_retldouble:

+ fldt (%ecx)

+ jmp .Lscls_epilogue

+

+.Lscls_retllong:

+ movl (%ecx), %eax

+ movl 4(%ecx), %edx

+ jmp .Lscls_epilogue

+

+.Lscls_retstruct1:

+ movsbl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retstruct2:

+ movswl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retstruct4:

+ movl (%ecx), %eax

+ jmp .Lscls_epilogue

+

+.Lscls_retstruct:

+

+

+.Lscls_noretval:

+.Lscls_epilogue:

+ movl %ebp, %esp

+ popl %ebp

+ ret

+.ffi_closure_STDCALL_end:

+.LFE5:

+

+

+ .section .eh_frame,"w"

+

+.Lframe1:

+.LSCIE1:

+ .long .LECIE1-.LASCIE1

+.LASCIE1:

+ .long 0x0

+ .byte 0x1

+

+

+

+ .ascii "\0"

+

+ .byte 0x1

+ .byte 0x7c

+ .byte 0x8

+

+

+

+

+ .byte 0xc

+ .byte 0x4

+ .byte 0x4

+ .byte 0x88

+ .byte 0x1

+ .align 4

+.LECIE1:

+

+.LSFDE1:

+ .long .LEFDE1-.LASFDE1

+.LASFDE1:

+ .long .LASFDE1-.Lframe1

+

+

+

+ .long .LFB1

+

+ .long .LFE1-.LFB1

+

+

+

+

+

+ .byte 0x4

+ .long .LCFI0-.LFB1

+ .byte 0xe

+ .byte 0x8

+ .byte 0x85

+ .byte 0x2

+

+ .byte 0x4

+ .long .LCFI1-.LCFI0

+ .byte 0xd

+ .byte 0x5

+

+

+ .align 4

+.LEFDE1:

+

+

+.LSFDE3:

+ .long .LEFDE3-.LASFDE3

+.LASFDE3:

+ .long .LASFDE3-.Lframe1

+

+

+

+ .long .LFB3

+

+ .long .LFE3-.LFB3

+

+

+

+

+

+ .byte 0x4

+ .long .LCFI4-.LFB3

+ .byte 0xe

+ .byte 0x8

+ .byte 0x85

+ .byte 0x2

+

+ .byte 0x4

+ .long .LCFI5-.LCFI4

+ .byte 0xd

+ .byte 0x5

+

+

+ .align 4

+.LEFDE3:

+

+

+

+.LSFDE4:

+ .long .LEFDE4-.LASFDE4

+.LASFDE4:

+ .long .LASFDE4-.Lframe1

+

+

+

+ .long .LFB4

+

+ .long .LFE4-.LFB4

+

+

+

+

+

+ .byte 0x4

+ .long .LCFI6-.LFB4

+ .byte 0xe

+ .byte 0x8

+ .byte 0x85

+ .byte 0x2

+

+ .byte 0x4

+ .long .LCFI7-.LCFI6

+ .byte 0xd

+ .byte 0x5

+

+ .byte 0x4

+ .long .LCFI8-.LCFI7

+ .byte 0x86

+ .byte 0x3

+

+

+ .align 4

+.LEFDE4:

+

+

+

+.LSFDE5:

+ .long .LEFDE5-.LASFDE5

+.LASFDE5:

+ .long .LASFDE5-.Lframe1

+

+

+

+ .long .LFB5

+

+ .long .LFE5-.LFB5

+

+

+

+

+

+ .byte 0x4

+ .long .LCFI9-.LFB5

+ .byte 0xe

+ .byte 0x8

+ .byte 0x85

+ .byte 0x2

+

+ .byte 0x4

+ .long .LCFI10-.LCFI9

+ .byte 0xd

+ .byte 0x5

+

+

+ .align 4

+.LEFDE5:

diff --git a/lib/wrappers/libffi/gcc/win64_asm.asm b/lib/wrappers/libffi/gcc/win64_asm.asm
new file mode 100644
index 000000000..1dc98f99a
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/win64_asm.asm
@@ -0,0 +1,467 @@
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+	
+/* Constants for ffi_call_win64 */	
+#define STACK 0
+#define PREP_ARGS_FN 32
+#define ECIF 40
+#define CIF_BYTES 48
+#define CIF_FLAGS 56
+#define RVALUE 64
+#define FN 72
+
+/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
+                   extended_cif *ecif, unsigned bytes, unsigned flags,
+                   unsigned *rvalue, void (*fn)());
+ */
+
+#ifdef _MSC_VER
+PUBLIC	ffi_call_win64
+
+EXTRN	__chkstk:NEAR
+EXTRN	ffi_closure_win64_inner:NEAR
+
+_TEXT	SEGMENT
+
+;;; ffi_closure_win64 will be called with these registers set:
+;;;    rax points to 'closure'
+;;;    r11 contains a bit mask that specifies which of the
+;;;    first four parameters are float or double
+;;;
+;;; It must move the parameters passed in registers to their stack location,
+;;; call ffi_closure_win64_inner for the actual work, then return the result.
+;;; 
+ffi_closure_win64 PROC FRAME
+	;; copy register arguments onto stack
+	test	r11, 1
+	jne	first_is_float	
+	mov	QWORD PTR [rsp+8], rcx
+	jmp	second
+first_is_float:
+	movlpd	QWORD PTR [rsp+8], xmm0
+
+second:
+	test	r11, 2
+	jne	second_is_float	
+	mov	QWORD PTR [rsp+16], rdx
+	jmp	third
+second_is_float:
+	movlpd	QWORD PTR [rsp+16], xmm1
+
+third:
+	test	r11, 4
+	jne	third_is_float	
+	mov	QWORD PTR [rsp+24], r8
+	jmp	fourth
+third_is_float:
+	movlpd	QWORD PTR [rsp+24], xmm2
+
+fourth:
+	test	r11, 8
+	jne	fourth_is_float	
+	mov	QWORD PTR [rsp+32], r9
+	jmp	done
+fourth_is_float:
+	movlpd	QWORD PTR [rsp+32], xmm3
+
+done:
+        .ALLOCSTACK 40
+	sub	rsp, 40
+        .ENDPROLOG
+	mov	rcx, rax	; context is first parameter
+	mov	rdx, rsp	; stack is second parameter
+	add	rdx, 48		; point to start of arguments
+	mov	rax, ffi_closure_win64_inner
+	call	rax		; call the real closure function
+	add	rsp, 40
+	movd	xmm0, rax	; If the closure returned a float,
+                                ; ffi_closure_win64_inner wrote it to rax
+	ret	0
+ffi_closure_win64 ENDP
+
+ffi_call_win64 PROC FRAME
+        ;; copy registers onto stack
+	mov	QWORD PTR [rsp+32], r9
+	mov	QWORD PTR [rsp+24], r8
+	mov	QWORD PTR [rsp+16], rdx
+	mov	QWORD PTR [rsp+8], rcx
+        .PUSHREG rbp
+	push	rbp
+        .ALLOCSTACK 48
+	sub	rsp, 48					; 00000030H
+        .SETFRAME rbp, 32
+	lea	rbp, QWORD PTR [rsp+32]
+        .ENDPROLOG
+
+	mov	eax, DWORD PTR CIF_BYTES[rbp]
+	add	rax, 15
+	and	rax, -16
+	call	__chkstk
+	sub	rsp, rax
+	lea	rax, QWORD PTR [rsp+32]
+	mov	QWORD PTR STACK[rbp], rax
+
+	mov	rdx, QWORD PTR ECIF[rbp]
+	mov	rcx, QWORD PTR STACK[rbp]
+	call	QWORD PTR PREP_ARGS_FN[rbp]
+
+	mov	rsp, QWORD PTR STACK[rbp]
+
+	movlpd	xmm3, QWORD PTR [rsp+24]
+	movd	r9, xmm3
+
+	movlpd	xmm2, QWORD PTR [rsp+16]
+	movd	r8, xmm2
+
+	movlpd	xmm1, QWORD PTR [rsp+8]
+	movd	rdx, xmm1
+
+	movlpd	xmm0, QWORD PTR [rsp]
+	movd	rcx, xmm0
+
+	call	QWORD PTR FN[rbp]
+ret_struct4b$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B
+ 	jne	ret_struct2b$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	mov	DWORD PTR [rcx], eax
+	jmp	ret_void$
+
+ret_struct2b$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
+ 	jne	ret_struct1b$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	mov	WORD PTR [rcx], ax
+	jmp	ret_void$
+
+ret_struct1b$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
+ 	jne	ret_uint8$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	mov	BYTE PTR [rcx], al
+	jmp	ret_void$
+
+ret_uint8$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
+ 	jne	ret_sint8$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	movzx   rax, al
+	mov	QWORD PTR [rcx], rax
+	jmp	ret_void$
+
+ret_sint8$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
+ 	jne	ret_uint16$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	movsx   rax, al
+	mov	QWORD PTR [rcx], rax
+	jmp	ret_void$
+
+ret_uint16$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
+ 	jne	ret_sint16$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	movzx   rax, ax
+	mov	QWORD PTR [rcx], rax
+	jmp	SHORT ret_void$
+
+ret_sint16$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16
+ 	jne	ret_uint32$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	movsx   rax, ax
+	mov	QWORD PTR [rcx], rax
+	jmp	SHORT ret_void$
+
+ret_uint32$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32
+ 	jne	ret_sint32$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	mov     eax, eax
+	mov	QWORD PTR [rcx], rax
+	jmp	SHORT ret_void$
+
+ret_sint32$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
+ 	jne	ret_float$
+
+	mov	rcx, QWORD PTR RVALUE[rbp]
+	cdqe
+	mov	QWORD PTR [rcx], rax
+	jmp	SHORT ret_void$
+
+ret_float$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT
+ 	jne	SHORT ret_double$
+
+ 	mov	rax, QWORD PTR RVALUE[rbp]
+ 	movss	DWORD PTR [rax], xmm0
+ 	jmp	SHORT ret_void$
+
+ret_double$:
+ 	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE
+ 	jne	SHORT ret_sint64$
+
+ 	mov	rax, QWORD PTR RVALUE[rbp]
+ 	movlpd	QWORD PTR [rax], xmm0
+ 	jmp	SHORT ret_void$
+
+ret_sint64$:
+  	cmp	DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
+  	jne	ret_void$
+
+ 	mov	rcx, QWORD PTR RVALUE[rbp]
+ 	mov	QWORD PTR [rcx], rax
+ 	jmp	SHORT ret_void$
+	
+ret_void$:
+	xor	rax, rax
+
+	lea	rsp, QWORD PTR [rbp+16]
+	pop	rbp
+	ret	0
+ffi_call_win64 ENDP
+_TEXT	ENDS
+END
+
+#else
+
+#ifdef SYMBOL_UNDERSCORE
+#define SYMBOL_NAME(name) _##name
+#else
+#define SYMBOL_NAME(name) name
+#endif
+
+.text
+
+.extern SYMBOL_NAME(ffi_closure_win64_inner)
+
+// ffi_closure_win64 will be called with these registers set:
+//    rax points to 'closure'
+//    r11 contains a bit mask that specifies which of the
+//    first four parameters are float or double
+// // It must move the parameters passed in registers to their stack location,
+// call ffi_closure_win64_inner for the actual work, then return the result.
+// 
+	.balign 16
+        .globl SYMBOL_NAME(ffi_closure_win64)
+SYMBOL_NAME(ffi_closure_win64):
+	// copy register arguments onto stack
+	test	$1,%r11
+	jne	.Lfirst_is_float	
+	mov	%rcx, 8(%rsp)
+	jmp	.Lsecond
+.Lfirst_is_float:
+	movlpd	%xmm0, 8(%rsp)
+
+.Lsecond:
+	test	$2, %r11
+	jne	.Lsecond_is_float	
+	mov	%rdx, 16(%rsp)
+	jmp	.Lthird
+.Lsecond_is_float:
+	movlpd	%xmm1, 16(%rsp)
+
+.Lthird:
+	test	$4, %r11
+	jne	.Lthird_is_float	
+	mov	%r8,24(%rsp)
+	jmp	.Lfourth
+.Lthird_is_float:
+	movlpd	%xmm2, 24(%rsp)
+
+.Lfourth:
+	test	$8, %r11
+	jne	.Lfourth_is_float	
+	mov	%r9, 32(%rsp)
+	jmp	.Ldone
+.Lfourth_is_float:
+	movlpd	%xmm3, 32(%rsp)
+
+.Ldone:
+// ALLOCSTACK 40
+	sub	$40, %rsp
+// ENDPROLOG
+	mov	%rax, %rcx	// context is first parameter
+	mov	%rsp, %rdx	// stack is second parameter
+	add	$48, %rdx	// point to start of arguments
+	mov	$SYMBOL_NAME(ffi_closure_win64_inner), %rax
+	callq	*%rax		// call the real closure function
+	add	$40, %rsp
+	movq	%rax, %xmm0	// If the closure returned a float,
+                                // ffi_closure_win64_inner wrote it to rax
+	retq
+.ffi_closure_win64_end:
+
+	.balign 16
+        .globl	SYMBOL_NAME(ffi_call_win64)
+SYMBOL_NAME(ffi_call_win64):
+        // copy registers onto stack
+	mov	%r9,32(%rsp)
+	mov	%r8,24(%rsp)
+	mov	%rdx,16(%rsp)
+	mov	%rcx,8(%rsp)
+        // PUSHREG rbp
+	push	%rbp
+        // ALLOCSTACK 48
+	sub	$48,%rsp
+        // SETFRAME rbp, 32
+	lea	32(%rsp),%rbp
+        // ENDPROLOG
+
+	mov	CIF_BYTES(%rbp),%eax
+	add	$15, %rax
+	and	$-16, %rax
+	cmpq	$0x1000, %rax
+	jb	Lch_done
+Lch_probe:
+	subq	$0x1000,%rsp
+	orl	$0x0, (%rsp)
+	subq	$0x1000,%rax
+	cmpq	$0x1000,%rax
+	ja	Lch_probe
+Lch_done:
+	subq	%rax, %rsp
+	orl	$0x0, (%rsp)
+	lea	32(%rsp), %rax
+	mov	%rax, STACK(%rbp)
+
+	mov	ECIF(%rbp), %rdx
+	mov	STACK(%rbp), %rcx
+	callq	*PREP_ARGS_FN(%rbp)
+
+	mov	STACK(%rbp), %rsp
+
+	movlpd	24(%rsp), %xmm3
+	movd	%xmm3, %r9
+
+	movlpd	16(%rsp), %xmm2
+	movd	%xmm2, %r8
+
+	movlpd	8(%rsp), %xmm1
+	movd	%xmm1, %rdx
+
+	movlpd	(%rsp), %xmm0
+	movd	%xmm0, %rcx
+
+	callq	*FN(%rbp)
+.Lret_struct4b:
+ 	cmpl	$FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
+ 	jne .Lret_struct2b
+
+	mov	RVALUE(%rbp), %rcx
+	mov	%eax, (%rcx)
+	jmp	.Lret_void
+
+.Lret_struct2b:
+	cmpl	$FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
+	jne .Lret_struct1b
+	
+	mov	RVALUE(%rbp), %rcx
+	mov	%ax, (%rcx)
+	jmp .Lret_void
+	
+.Lret_struct1b:
+	cmpl	$FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
+	jne .Lret_uint8
+	
+	mov	RVALUE(%rbp), %rcx
+	mov	%al, (%rcx)
+	jmp .Lret_void
+
+.Lret_uint8:
+	cmpl	$FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
+	jne .Lret_sint8
+	
+        mov     RVALUE(%rbp), %rcx
+        movzbq  %al, %rax
+	movq    %rax, (%rcx)
+	jmp .Lret_void
+
+.Lret_sint8:
+	cmpl	$FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
+	jne .Lret_uint16
+	
+        mov     RVALUE(%rbp), %rcx
+        movsbq  %al, %rax
+	movq    %rax, (%rcx)
+	jmp .Lret_void
+
+.Lret_uint16:
+	cmpl	$FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
+	jne .Lret_sint16
+	
+        mov     RVALUE(%rbp), %rcx
+        movzwq  %ax, %rax
+	movq    %rax, (%rcx)
+	jmp .Lret_void
+
+.Lret_sint16:
+	cmpl	$FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
+	jne .Lret_uint32
+	
+        mov     RVALUE(%rbp), %rcx
+        movswq  %ax, %rax
+	movq    %rax, (%rcx)
+	jmp .Lret_void
+
+.Lret_uint32:
+	cmpl	$FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
+	jne .Lret_sint32
+	
+        mov     RVALUE(%rbp), %rcx
+        movl    %eax, %eax
+	movq    %rax, (%rcx)
+	jmp .Lret_void
+
+.Lret_sint32:
+ 	cmpl	$FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
+ 	jne	.Lret_float
+
+	mov	RVALUE(%rbp), %rcx
+	cltq
+	movq	%rax, (%rcx)
+	jmp	.Lret_void
+
+.Lret_float:
+ 	cmpl	$FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
+ 	jne	.Lret_double
+
+ 	mov	RVALUE(%rbp), %rax
+ 	movss	%xmm0, (%rax)
+ 	jmp	.Lret_void
+
+.Lret_double:
+ 	cmpl	$FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
+ 	jne	.Lret_sint64
+
+ 	mov	RVALUE(%rbp), %rax
+ 	movlpd	%xmm0, (%rax)
+ 	jmp	.Lret_void
+
+.Lret_sint64:
+  	cmpl	$FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
+  	jne	.Lret_void
+
+ 	mov	RVALUE(%rbp), %rcx
+ 	mov	%rax, (%rcx)
+ 	jmp	.Lret_void
+	
+.Lret_void:
+	xor	%rax, %rax
+
+	lea	16(%rbp), %rsp
+	pop	%rbp
+	retq
+.ffi_call_win64_end:
+#endif /* !_MSC_VER */
+
diff --git a/lib/wrappers/libffi/gcc/win64_asm.s b/lib/wrappers/libffi/gcc/win64_asm.s
new file mode 100644
index 000000000..f2c2df10d
--- /dev/null
+++ b/lib/wrappers/libffi/gcc/win64_asm.s
@@ -0,0 +1,227 @@
+# 1 "gcc\\win64_asm.asm"

+# 1 "<command-line>"

+# 1 "gcc\\win64_asm.asm"

+

+# 1 "common/fficonfig.h" 1

+# 3 "gcc\\win64_asm.asm" 2

+# 1 "common/ffi.h" 1

+# 63 "common/ffi.h"

+# 1 "common/ffitarget.h" 1

+# 64 "common/ffi.h" 2

+# 4 "gcc\\win64_asm.asm" 2

+# 244 "gcc\\win64_asm.asm"

+.text

+

+.extern ffi_closure_win64_inner

+# 255 "gcc\\win64_asm.asm"

+ .balign 16

+        .globl ffi_closure_win64

+ffi_closure_win64:

+

+ test $1,%r11

+ jne .Lfirst_is_float

+ mov %rcx, 8(%rsp)

+ jmp .Lsecond

+.Lfirst_is_float:

+ movlpd %xmm0, 8(%rsp)

+

+.Lsecond:

+ test $2, %r11

+ jne .Lsecond_is_float

+ mov %rdx, 16(%rsp)

+ jmp .Lthird

+.Lsecond_is_float:

+ movlpd %xmm1, 16(%rsp)

+

+.Lthird:

+ test $4, %r11

+ jne .Lthird_is_float

+ mov %r8,24(%rsp)

+ jmp .Lfourth

+.Lthird_is_float:

+ movlpd %xmm2, 24(%rsp)

+

+.Lfourth:

+ test $8, %r11

+ jne .Lfourth_is_float

+ mov %r9, 32(%rsp)

+ jmp .Ldone

+.Lfourth_is_float:

+ movlpd %xmm3, 32(%rsp)

+

+.Ldone:

+

+ sub $40, %rsp

+

+ mov %rax, %rcx

+ mov %rsp, %rdx

+ add $48, %rdx

+ mov $SYMBOL_NAME(ffi_closure_win64_inner), %rax

+ callq *%rax

+ add $40, %rsp

+ movq %rax, %xmm0

+

+ retq

+.ffi_closure_win64_end:

+

+ .balign 16

+        .globl ffi_call_win64

+ffi_call_win64:

+

+ mov %r9,32(%rsp)

+ mov %r8,24(%rsp)

+ mov %rdx,16(%rsp)

+ mov %rcx,8(%rsp)

+

+ push %rbp

+

+ sub $48,%rsp

+

+ lea 32(%rsp),%rbp

+

+

+ mov 48(%rbp),%eax

+ add $15, %rax

+ and $-16, %rax

+ cmpq $0x1000, %rax

+ jb Lch_done

+Lch_probe:

+ subq $0x1000,%rsp

+ orl $0x0, (%rsp)

+ subq $0x1000,%rax

+ cmpq $0x1000,%rax

+ ja Lch_probe

+Lch_done:

+ subq %rax, %rsp

+ orl $0x0, (%rsp)

+ lea 32(%rsp), %rax

+ mov %rax, 0(%rbp)

+

+ mov 40(%rbp), %rdx

+ mov 0(%rbp), %rcx

+ callq *32(%rbp)

+

+ mov 0(%rbp), %rsp

+

+ movlpd 24(%rsp), %xmm3

+ movd %xmm3, %r9

+

+ movlpd 16(%rsp), %xmm2

+ movd %xmm2, %r8

+

+ movlpd 8(%rsp), %xmm1

+ movd %xmm1, %rdx

+

+ movlpd (%rsp), %xmm0

+ movd %xmm0, %rcx

+

+ callq *72(%rbp)

+.Lret_struct4b:

+  cmpl $FFI_TYPE_SMALL_STRUCT_4B, 56(%rbp)

+  jne .Lret_struct2b

+

+ mov 64(%rbp), %rcx

+ mov %eax, (%rcx)

+ jmp .Lret_void

+

+.Lret_struct2b:

+ cmpl $FFI_TYPE_SMALL_STRUCT_2B, 56(%rbp)

+ jne .Lret_struct1b

+

+ mov 64(%rbp), %rcx

+ mov %ax, (%rcx)

+ jmp .Lret_void

+

+.Lret_struct1b:

+ cmpl $FFI_TYPE_SMALL_STRUCT_1B, 56(%rbp)

+ jne .Lret_uint8

+

+ mov 64(%rbp), %rcx

+ mov %al, (%rcx)

+ jmp .Lret_void

+

+.Lret_uint8:

+ cmpl $FFI_TYPE_UINT8, 56(%rbp)

+ jne .Lret_sint8

+

+        mov 64(%rbp), %rcx

+        movzbq %al, %rax

+ movq %rax, (%rcx)

+ jmp .Lret_void

+

+.Lret_sint8:

+ cmpl $FFI_TYPE_SINT8, 56(%rbp)

+ jne .Lret_uint16

+

+        mov 64(%rbp), %rcx

+        movsbq %al, %rax

+ movq %rax, (%rcx)

+ jmp .Lret_void

+

+.Lret_uint16:

+ cmpl $FFI_TYPE_UINT16, 56(%rbp)

+ jne .Lret_sint16

+

+        mov 64(%rbp), %rcx

+        movzwq %ax, %rax

+ movq %rax, (%rcx)

+ jmp .Lret_void

+

+.Lret_sint16:

+ cmpl $FFI_TYPE_SINT16, 56(%rbp)

+ jne .Lret_uint32

+

+        mov 64(%rbp), %rcx

+        movswq %ax, %rax

+ movq %rax, (%rcx)

+ jmp .Lret_void

+

+.Lret_uint32:

+ cmpl $9, 56(%rbp)

+ jne .Lret_sint32

+

+        mov 64(%rbp), %rcx

+        movl %eax, %eax

+ movq %rax, (%rcx)

+ jmp .Lret_void

+

+.Lret_sint32:

+  cmpl $10, 56(%rbp)

+  jne .Lret_float

+

+ mov 64(%rbp), %rcx

+ cltq

+ movq %rax, (%rcx)

+ jmp .Lret_void

+

+.Lret_float:

+  cmpl $2, 56(%rbp)

+  jne .Lret_double

+

+  mov 64(%rbp), %rax

+  movss %xmm0, (%rax)

+  jmp .Lret_void

+

+.Lret_double:

+  cmpl $3, 56(%rbp)

+  jne .Lret_sint64

+

+  mov 64(%rbp), %rax

+  movlpd %xmm0, (%rax)

+  jmp .Lret_void

+

+.Lret_sint64:

+   cmpl $12, 56(%rbp)

+   jne .Lret_void

+

+  mov 64(%rbp), %rcx

+  mov %rax, (%rcx)

+  jmp .Lret_void

+

+.Lret_void:

+ xor %rax, %rax

+

+ lea 16(%rbp), %rsp

+ pop %rbp

+ retq

+.ffi_call_win64_end:

diff --git a/lib/wrappers/libffi/libffi.nim b/lib/wrappers/libffi/libffi.nim
new file mode 100644
index 000000000..1b6130103
--- /dev/null
+++ b/lib/wrappers/libffi/libffi.nim
@@ -0,0 +1,171 @@
+# -----------------------------------------------------------------*-C-*-
+#   libffi 3.0.10 - Copyright (c) 2011 Anthony Green
+#                    - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
+#
+#   Permission is hereby granted, free of charge, to any person
+#   obtaining a copy of this software and associated documentation
+#   files (the ``Software''), to deal in the Software without
+#   restriction, including without limitation the rights to use, copy,
+#   modify, merge, publish, distribute, sublicense, and/or sell copies
+#   of the Software, and to permit persons to whom the Software is
+#   furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be
+#   included in all copies or substantial portions of the Software.
+#
+#   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+#   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+#   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+#   DEALINGS IN THE SOFTWARE.
+#
+#   ----------------------------------------------------------------------- 
+
+{.deadCodeElim: on.}
+
+when defined(windows):
+  # on Windows we don't use a DLL but instead embed libffi directly:
+  {.pragma: mylib, header: r"ffi.h".}
+
+  #{.compile: r"common\malloc_closure.c".}
+  {.compile: r"common\raw_api.c".}
+  when defined(vcc):
+    {.compile: r"msvc\ffi.c".}
+    {.compile: r"msvc\prep_cif.c".}
+    {.compile: r"msvc\win32.c".}
+    {.compile: r"msvc\types.c".}
+    when defined(cpu64):
+      {.compile: r"msvc\win64_asm.asm".}
+    else:
+      {.compile: r"msvc\win32_asm.asm".}
+  else:
+    {.compile: r"gcc\ffi.c".}
+    {.compile: r"gcc\prep_cif.c".}
+    {.compile: r"gcc\types.c".}
+    {.compile: r"gcc\closures.c".}
+    when defined(cpu64):
+      {.compile: r"gcc\ffi64.c".}
+      {.compile: r"gcc\win64_asm.S".}
+    else:
+      {.compile: r"gcc\win32_asm.S".}
+
+elif defined(macosx):
+  {.pragma: mylib, dynlib: "libffi.dylib".}
+else:
+  {.pragma: mylib, dynlib: "libffi.so".}
+
+type
+  TArg* = int
+  TSArg* = int
+
+when defined(windows) and defined(x86):
+  type
+    TABI* {.size: sizeof(cint).} = enum
+      FIRST_ABI, SYSV, STDCALL
+
+  const DEFAULT_ABI* = SYSV
+elif defined(amd64) and defined(windows):
+  type 
+    TABI* {.size: sizeof(cint).} = enum 
+      FIRST_ABI, WIN64
+  const DEFAULT_ABI* = WIN64
+else:
+  type 
+    TABI* {.size: sizeof(cint).} = enum
+      FIRST_ABI, SYSV, UNIX64
+
+  when defined(i386):
+    const DEFAULT_ABI* = SYSV
+  else: 
+    const DEFAULT_ABI* = UNIX64
+    
+const 
+  tkVOID* = 0
+  tkINT* = 1
+  tkFLOAT* = 2
+  tkDOUBLE* = 3
+  tkLONGDOUBLE* = 4
+  tkUINT8* = 5
+  tkSINT8* = 6
+  tkUINT16* = 7
+  tkSINT16* = 8
+  tkUINT32* = 9
+  tkSINT32* = 10
+  tkUINT64* = 11
+  tkSINT64* = 12
+  tkSTRUCT* = 13
+  tkPOINTER* = 14
+
+  tkLAST = tkPOINTER
+  tkSMALL_STRUCT_1B* = (tkLAST + 1)
+  tkSMALL_STRUCT_2B* = (tkLAST + 2)
+  tkSMALL_STRUCT_4B* = (tkLAST + 3)
+
+type
+  TType* = object
+    size*: int
+    alignment*: uint16
+    typ*: uint16
+    elements*: ptr ptr TType
+
+var
+  type_void* {.importc: "ffi_type_void", mylib.}: TType
+  type_uint8* {.importc: "ffi_type_uint8", mylib.}: TType
+  type_sint8* {.importc: "ffi_type_sint8", mylib.}: TType
+  type_uint16* {.importc: "ffi_type_uint16", mylib.}: TType
+  type_sint16* {.importc: "ffi_type_sint16", mylib.}: TType
+  type_uint32* {.importc: "ffi_type_uint32", mylib.}: TType
+  type_sint32* {.importc: "ffi_type_sint32", mylib.}: TType
+  type_uint64* {.importc: "ffi_type_uint64", mylib.}: TType
+  type_sint64* {.importc: "ffi_type_sint64", mylib.}: TType
+  type_float* {.importc: "ffi_type_float", mylib.}: TType
+  type_double* {.importc: "ffi_type_double", mylib.}: TType
+  type_pointer* {.importc: "ffi_type_pointer", mylib.}: TType
+  type_longdouble* {.importc: "ffi_type_longdouble", mylib.}: TType
+
+type 
+  Tstatus* {.size: sizeof(cint).} = enum 
+    OK, BAD_TYPEDEF, BAD_ABI
+  TTypeKind* = cuint
+  TCif* {.pure, final.} = object 
+    abi*: TABI
+    nargs*: cuint
+    arg_types*: ptr ptr TType
+    rtype*: ptr TType
+    bytes*: cuint
+    flags*: cuint
+
+type
+  TRaw* = object 
+    sint*: TSArg
+
+proc raw_call*(cif: var Tcif; fn: proc () {.cdecl.}; rvalue: pointer; 
+               avalue: ptr TRaw) {.cdecl, importc: "ffi_raw_call", mylib.}
+proc ptrarray_to_raw*(cif: var Tcif; args: ptr pointer; raw: ptr TRaw) {.cdecl, 
+    importc: "ffi_ptrarray_to_raw", mylib.}
+proc raw_to_ptrarray*(cif: var Tcif; raw: ptr TRaw; args: ptr pointer) {.cdecl, 
+    importc: "ffi_raw_to_ptrarray", mylib.}
+proc raw_size*(cif: var Tcif): int {.cdecl, importc: "ffi_raw_size", mylib.}
+
+proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr TType; 
+               atypes: ptr ptr TType): TStatus {.cdecl, importc: "ffi_prep_cif", 
+    mylib.}
+proc call*(cif: var Tcif; fn: proc () {.cdecl.}; rvalue: pointer; 
+           avalue: ptr pointer) {.cdecl, importc: "ffi_call", mylib.}
+
+# the same with an easier interface:
+type
+  TParamList* = array[0..100, ptr TType]
+  TArgList* = array[0..100, pointer]
+
+proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr TType; 
+               atypes: TParamList): TStatus {.cdecl, importc: "ffi_prep_cif",
+    mylib.}
+proc call*(cif: var Tcif; fn, rvalue: pointer;
+           avalue: TArgList) {.cdecl, importc: "ffi_call", mylib.}
+
+# Useful for eliminating compiler warnings 
+##define FFI_FN(f) ((void (*)(void))f)
diff --git a/lib/wrappers/libffi/msvc/ffi.c b/lib/wrappers/libffi/msvc/ffi.c
new file mode 100644
index 000000000..6e595e9fe
--- /dev/null
+++ b/lib/wrappers/libffi/msvc/ffi.c
@@ -0,0 +1,457 @@
+/* -----------------------------------------------------------------------
+   ffi.c - Copyright (c) 1996, 1998, 1999, 2001  Red Hat, Inc.
+           Copyright (c) 2002  Ranjit Mathew
+           Copyright (c) 2002  Bo Thorsen
+           Copyright (c) 2002  Roger Sayle
+   
+   x86 Foreign Function Interface 
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+#include <stdlib.h>
+
+/* ffi_prep_args is called by the assembly routine once stack space
+   has been allocated for the function's arguments */
+
+extern void Py_FatalError(const char *msg);
+
+/*@-exportheader@*/
+void ffi_prep_args(char *stack, extended_cif *ecif)
+/*@=exportheader@*/
+{
+  register unsigned int i;
+  register void **p_argv;
+  register char *argp;
+  register ffi_type **p_arg;
+
+  argp = stack;
+  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
+    {
+      *(void **) argp = ecif->rvalue;
+      argp += sizeof(void *);
+    }
+
+  p_argv = ecif->avalue;
+
+  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
+       i != 0;
+       i--, p_arg++)
+    {
+      size_t z;
+
+      /* Align if necessary */
+      if ((sizeof(void *) - 1) & (size_t) argp)
+	argp = (char *) ALIGN(argp, sizeof(void *));
+
+      z = (*p_arg)->size;
+      if (z < sizeof(int))
+	{
+	  z = sizeof(int);
+	  switch ((*p_arg)->type)
+	    {
+	    case FFI_TYPE_SINT8:
+	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_UINT8:
+	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_SINT16:
+	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_UINT16:
+	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_SINT32:
+	      *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_UINT32:
+	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+	      break;
+
+	    case FFI_TYPE_STRUCT:
+	      *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+	      break;
+
+	    default:
+	      FFI_ASSERT(0);
+	    }
+	}
+      else
+	{
+	  memcpy(argp, *p_argv, z);
+	}
+      p_argv++;
+      argp += z;
+    }
+
+  if (argp >= stack && (unsigned)(argp - stack) > ecif->cif->bytes) 
+    {
+      Py_FatalError("FFI BUG: not enough stack space for arguments");
+    }
+  return;
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+  /* Set the return type flag */
+  switch (cif->rtype->type)
+    {
+    case FFI_TYPE_VOID:
+    case FFI_TYPE_STRUCT:
+    case FFI_TYPE_SINT64:
+    case FFI_TYPE_FLOAT:
+    case FFI_TYPE_DOUBLE:
+    case FFI_TYPE_LONGDOUBLE:
+      cif->flags = (unsigned) cif->rtype->type;
+      break;
+
+    case FFI_TYPE_UINT64:
+#ifdef _WIN64
+    case FFI_TYPE_POINTER:
+#endif
+      cif->flags = FFI_TYPE_SINT64;
+      break;
+
+    default:
+      cif->flags = FFI_TYPE_INT;
+      break;
+    }
+
+  return FFI_OK;
+}
+
+#ifdef _WIN32
+extern int
+ffi_call_x86(void (*)(char *, extended_cif *), 
+	     /*@out@*/ extended_cif *, 
+	     unsigned, unsigned, 
+	     /*@out@*/ unsigned *, 
+	     void (*fn)());
+#endif
+
+#ifdef _WIN64
+extern int
+ffi_call_AMD64(void (*)(char *, extended_cif *),
+		 /*@out@*/ extended_cif *,
+		 unsigned, unsigned,
+		 /*@out@*/ unsigned *,
+		 void (*fn)());
+#endif
+
+int
+ffi_call(/*@dependent@*/ ffi_cif *cif, 
+	 void (*fn)(), 
+	 /*@out@*/ void *rvalue, 
+	 /*@dependent@*/ void **avalue)
+{
+  extended_cif ecif;
+
+  ecif.cif = cif;
+  ecif.avalue = avalue;
+  
+  /* If the return value is a struct and we don't have a return	*/
+  /* value address then we need to make one		        */
+
+  if ((rvalue == NULL) && 
+      (cif->rtype->type == FFI_TYPE_STRUCT))
+    {
+      /*@-sysunrecog@*/
+      ecif.rvalue = alloca(cif->rtype->size);
+      /*@=sysunrecog@*/
+    }
+  else
+    ecif.rvalue = rvalue;
+    
+  
+  switch (cif->abi) 
+    {
+#if !defined(_WIN64)
+    case FFI_SYSV:
+    case FFI_STDCALL:
+      return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes, 
+			  cif->flags, ecif.rvalue, fn);
+      break;
+#else
+    case FFI_SYSV:
+      /*@-usedef@*/
+      /* Function call needs at least 40 bytes stack size, on win64 AMD64 */
+      return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,
+			   cif->flags, ecif.rvalue, fn);
+      /*@=usedef@*/
+      break;
+#endif
+
+    default:
+      FFI_ASSERT(0);
+      break;
+    }
+  return -1; /* theller: Hrm. */
+}
+
+
+/** private members **/
+
+static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
+					  void** args, ffi_cif* cif);
+/* This function is jumped to by the trampoline */
+
+#ifdef _WIN64
+void *
+#else
+static void __fastcall
+#endif
+ffi_closure_SYSV (ffi_closure *closure, int *argp)
+{
+  // this is our return value storage
+  long double    res;
+
+  // our various things...
+  ffi_cif       *cif;
+  void         **arg_area;
+  unsigned short rtype;
+  void          *resp = (void*)&res;
+  void *args = &argp[1];
+
+  cif         = closure->cif;
+  arg_area    = (void**) alloca (cif->nargs * sizeof (void*));  
+
+  /* this call will initialize ARG_AREA, such that each
+   * element in that array points to the corresponding 
+   * value on the stack; and if the function returns
+   * a structure, it will re-set RESP to point to the
+   * structure return address.  */
+
+  ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
+  
+  (closure->fun) (cif, resp, arg_area, closure->user_data);
+
+  rtype = cif->flags;
+
+#if defined(_WIN32) && !defined(_WIN64)
+#ifdef _MSC_VER
+  /* now, do a generic return based on the value of rtype */
+  if (rtype == FFI_TYPE_INT)
+    {
+	    _asm mov eax, resp ;
+	    _asm mov eax, [eax] ;
+    }
+  else if (rtype == FFI_TYPE_FLOAT)
+    {
+	    _asm mov eax, resp ;
+	    _asm fld DWORD PTR [eax] ;
+//      asm ("flds (%0)" : : "r" (resp) : "st" );
+    }
+  else if (rtype == FFI_TYPE_DOUBLE)
+    {
+	    _asm mov eax, resp ;
+	    _asm fld QWORD PTR [eax] ;
+//      asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
+    }
+  else if (rtype == FFI_TYPE_LONGDOUBLE)
+    {
+//      asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
+    }
+  else if (rtype == FFI_TYPE_SINT64)
+    {
+	    _asm mov edx, resp ;
+	    _asm mov eax, [edx] ;
+	    _asm mov edx, [edx + 4] ;
+//      asm ("movl 0(%0),%%eax;"
+//	   "movl 4(%0),%%edx" 
+//	   : : "r"(resp)
+//	   : "eax", "edx");
+    }
+#else
+  /* now, do a generic return based on the value of rtype */
+  if (rtype == FFI_TYPE_INT)
+    {
+      asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
+    }
+  else if (rtype == FFI_TYPE_FLOAT)
+    {
+      asm ("flds (%0)" : : "r" (resp) : "st" );
+    }
+  else if (rtype == FFI_TYPE_DOUBLE)
+    {
+      asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
+    }
+  else if (rtype == FFI_TYPE_LONGDOUBLE)
+    {
+      asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
+    }
+  else if (rtype == FFI_TYPE_SINT64)
+    {
+      asm ("movl 0(%0),%%eax;"
+	   "movl 4(%0),%%edx" 
+	   : : "r"(resp)
+	   : "eax", "edx");
+    }
+#endif
+#endif
+
+#ifdef _WIN64
+  /* The result is returned in rax.  This does the right thing for
+     result types except for floats; we have to 'mov xmm0, rax' in the
+     caller to correct this.
+  */
+  return *(void **)resp;
+#endif
+}
+
+/*@-exportheader@*/
+static void 
+ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
+			    void **avalue, ffi_cif *cif)
+/*@=exportheader@*/
+{
+  register unsigned int i;
+  register void **p_argv;
+  register char *argp;
+  register ffi_type **p_arg;
+
+  argp = stack;
+
+  if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
+    *rvalue = *(void **) argp;
+    argp += 4;
+  }
+
+  p_argv = avalue;
+
+  for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
+    {
+      size_t z;
+
+      /* Align if necessary */
+      if ((sizeof(char *) - 1) & (size_t) argp) {
+	argp = (char *) ALIGN(argp, sizeof(char*));
+      }
+
+      z = (*p_arg)->size;
+
+      /* because we're little endian, this is what it turns into.   */
+
+      *p_argv = (void*) argp;
+
+      p_argv++;
+      argp += z;
+    }
+  
+  return;
+}
+
+/* the cif must already be prep'ed */
+extern void ffi_closure_OUTER();
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+					  ffi_cif* cif,
+					  void (*fun)(ffi_cif*,void*,void**,void*),
+					  void *user_data,
+					  void *codeloc)
+{
+  short bytes;
+  char *tramp;
+#ifdef _WIN64
+  int mask = 0;
+#endif
+  FFI_ASSERT (cif->abi == FFI_SYSV);
+  
+  if (cif->abi == FFI_SYSV)
+    bytes = 0;
+#if !defined(_WIN64)
+  else if (cif->abi == FFI_STDCALL)
+    bytes = cif->bytes;
+#endif
+  else
+    return FFI_BAD_ABI;
+
+  tramp = &closure->tramp[0];
+
+#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
+#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
+#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
+#define INT(x) *(int*)tramp = x, tramp += sizeof(int)
+
+#ifdef _WIN64
+  if (cif->nargs >= 1 &&
+      (cif->arg_types[0]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
+    mask |= 1;
+  if (cif->nargs >= 2 &&
+      (cif->arg_types[1]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
+    mask |= 2;
+  if (cif->nargs >= 3 &&
+      (cif->arg_types[2]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
+    mask |= 4;
+  if (cif->nargs >= 4 &&
+      (cif->arg_types[3]->type == FFI_TYPE_FLOAT
+       || cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
+    mask |= 8;
+
+  /* 41 BB ----         mov         r11d,mask */
+  BYTES("\x41\xBB"); INT(mask);
+
+  /* 48 B8 --------     mov         rax, closure			*/
+  BYTES("\x48\xB8"); POINTER(closure);
+
+  /* 49 BA --------     mov         r10, ffi_closure_OUTER */
+  BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
+
+  /* 41 FF E2           jmp         r10 */
+  BYTES("\x41\xFF\xE2");
+
+#else
+
+  /* mov ecx, closure */
+  BYTES("\xb9"); POINTER(closure);
+
+  /* mov edx, esp */
+  BYTES("\x8b\xd4");
+
+  /* call ffi_closure_SYSV */
+  BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
+
+  /* ret bytes */
+  BYTES("\xc2");
+  SHORT(bytes);
+  
+#endif
+
+  if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
+    Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
+
+  closure->cif  = cif;
+  closure->user_data = user_data;
+  closure->fun  = fun;
+  return FFI_OK;
+}
diff --git a/lib/wrappers/libffi/msvc/prep_cif.c b/lib/wrappers/libffi/msvc/prep_cif.c
new file mode 100644
index 000000000..2650fa052
--- /dev/null
+++ b/lib/wrappers/libffi/msvc/prep_cif.c
@@ -0,0 +1,175 @@
+/* -----------------------------------------------------------------------
+   prep_cif.c - Copyright (c) 1996, 1998  Red Hat, Inc.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+#include <stdlib.h>
+
+
+/* Round up to FFI_SIZEOF_ARG. */
+
+#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
+
+/* Perform machine independent initialization of aggregate type
+   specifications. */
+
+static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg)
+{
+  ffi_type **ptr; 
+
+  FFI_ASSERT(arg != NULL);
+
+  /*@-usedef@*/
+
+  FFI_ASSERT(arg->elements != NULL);
+  FFI_ASSERT(arg->size == 0);
+  FFI_ASSERT(arg->alignment == 0);
+
+  ptr = &(arg->elements[0]);
+
+  while ((*ptr) != NULL)
+    {
+      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
+	return FFI_BAD_TYPEDEF;
+      
+      /* Perform a sanity check on the argument type */
+      FFI_ASSERT_VALID_TYPE(*ptr);
+
+      arg->size = ALIGN(arg->size, (*ptr)->alignment);
+      arg->size += (*ptr)->size;
+
+      arg->alignment = (arg->alignment > (*ptr)->alignment) ? 
+	arg->alignment : (*ptr)->alignment;
+
+      ptr++;
+    }
+
+  /* Structure size includes tail padding.  This is important for
+     structures that fit in one register on ABIs like the PowerPC64
+     Linux ABI that right justify small structs in a register.
+     It's also needed for nested structure layout, for example
+     struct A { long a; char b; }; struct B { struct A x; char y; };
+     should find y at an offset of 2*sizeof(long) and result in a
+     total size of 3*sizeof(long).  */
+  arg->size = ALIGN (arg->size, arg->alignment);
+
+  if (arg->size == 0)
+    return FFI_BAD_TYPEDEF;
+  else
+    return FFI_OK;
+
+  /*@=usedef@*/
+}
+
+/* Perform machine independent ffi_cif preparation, then call
+   machine dependent routine. */
+
+ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, 
+			ffi_abi abi, unsigned int nargs, 
+			/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, 
+			/*@dependent@*/ ffi_type **atypes)
+{
+  unsigned bytes = 0;
+  unsigned int i;
+  ffi_type **ptr;
+
+  FFI_ASSERT(cif != NULL);
+  FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
+
+  cif->abi = abi;
+  cif->arg_types = atypes;
+  cif->nargs = nargs;
+  cif->rtype = rtype;
+
+  cif->flags = 0;
+
+  /* Initialize the return type if necessary */
+  /*@-usedef@*/
+  if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
+    return FFI_BAD_TYPEDEF;
+  /*@=usedef@*/
+
+  /* Perform a sanity check on the return type */
+  FFI_ASSERT_VALID_TYPE(cif->rtype);
+
+  /* x86-64 and s390 stack space allocation is handled in prep_machdep.  */
+#if !defined M68K && !defined __x86_64__ && !defined S390
+  /* Make space for the return structure pointer */
+  if (cif->rtype->type == FFI_TYPE_STRUCT
+      /* MSVC returns small structures in registers.  But we have a different
+      workaround: pretend int32 or int64 return type, and converting to
+      structure afterwards. */
+#ifdef SPARC
+      && (cif->abi != FFI_V9 || cif->rtype->size > 32)
+#endif
+      )
+    bytes = STACK_ARG_SIZE(sizeof(void*));
+#endif
+
+  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
+    {
+
+      /* Initialize any uninitialized aggregate type definitions */
+      if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
+	return FFI_BAD_TYPEDEF;
+
+      /* Perform a sanity check on the argument type, do this 
+	 check after the initialization.  */
+      FFI_ASSERT_VALID_TYPE(*ptr);
+
+#if !defined __x86_64__ && !defined S390
+#ifdef SPARC
+      if (((*ptr)->type == FFI_TYPE_STRUCT
+	   && ((*ptr)->size > 16 || cif->abi != FFI_V9))
+	  || ((*ptr)->type == FFI_TYPE_LONGDOUBLE
+	      && cif->abi != FFI_V9))
+	bytes += sizeof(void*);
+      else
+#endif
+	{
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+		/* Don't know if this is a libffi bug or not.  At least on
+		   Windows with MSVC, function call parameters are *not*
+		   aligned in the same way as structure fields are, they are
+		   only aligned in integer boundaries.
+
+		   This doesn't do any harm for cdecl functions and closures,
+		   since the caller cleans up the stack, but it is wrong for
+		   stdcall functions where the callee cleans.
+		*/
+
+	  /* Add any padding if necessary */
+	  if (((*ptr)->alignment - 1) & bytes)
+	    bytes = ALIGN(bytes, (*ptr)->alignment);
+	  
+#endif
+	  bytes += STACK_ARG_SIZE((*ptr)->size);
+	}
+#endif
+    }
+
+  cif->bytes = bytes;
+
+  /* Perform machine dependent cif processing */
+  return ffi_prep_cif_machdep(cif);
+}
diff --git a/lib/wrappers/libffi/msvc/types.c b/lib/wrappers/libffi/msvc/types.c
new file mode 100644
index 000000000..df32190d1
--- /dev/null
+++ b/lib/wrappers/libffi/msvc/types.c
@@ -0,0 +1,104 @@
+/* -----------------------------------------------------------------------
+   types.c - Copyright (c) 1996, 1998  Red Hat, Inc.
+   
+   Predefined ffi_types needed by libffi.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+/* Type definitions */
+
+#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL }
+#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e }
+
+/* Size and alignment are fake here. They must not be 0. */
+FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID);
+
+FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8);
+FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8);
+FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
+FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
+FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
+FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
+FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
+
+#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \
+    || defined IA64
+
+FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
+
+#endif
+
+#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
+
+#elif defined SH
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64);
+FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
+
+#endif
+
+
+#if defined X86 || defined X86_WIN32 || defined M68K
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
+
+#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE);
+
+#elif defined SPARC
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+#ifdef SPARC64
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+#else
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
+#endif
+
+#elif defined X86_64
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
+
+#else
+
+FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
+FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE);
+
+#endif
+
diff --git a/lib/wrappers/libffi/msvc/win32.c b/lib/wrappers/libffi/msvc/win32.c
new file mode 100644
index 000000000..2754fd35d
--- /dev/null
+++ b/lib/wrappers/libffi/msvc/win32.c
@@ -0,0 +1,162 @@
+/* -----------------------------------------------------------------------
+   win32.S - Copyright (c) 1996, 1998, 2001, 2002  Red Hat, Inc.
+	     Copyright (c) 2001  John Beniton
+	     Copyright (c) 2002  Ranjit Mathew
+			
+ 
+   X86 Foreign Function Interface
+ 
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+ 
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+ 
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+   OTHER DEALINGS IN THE SOFTWARE.
+   ----------------------------------------------------------------------- */
+
+/* theller: almost verbatim translation from gas syntax to MSVC inline
+   assembler code. */
+
+/* theller: ffi_call_x86 now returns an integer - the difference of the stack
+   pointer before and after the function call.  If everything is ok, zero is
+   returned.  If stdcall functions are passed the wrong number of arguments,
+   the difference will be nonzero. */
+
+#include <ffi.h>
+#include <ffi_common.h>
+
+__declspec(naked) int
+ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */
+	     extended_cif *ecif, /* 12 */
+	     unsigned bytes, /* 16 */
+	     unsigned flags, /* 20 */
+	     unsigned *rvalue, /* 24 */
+	     void (*fn)()) /* 28 */
+{
+	_asm {
+		push ebp
+		mov ebp, esp
+
+		push esi // NEW: this register must be preserved across function calls
+// XXX SAVE ESP NOW!
+		mov esi, esp		// save stack pointer before the call
+
+// Make room for all of the new args.
+		mov ecx, [ebp+16]
+		sub esp, ecx		// sub esp, bytes
+		
+		mov eax, esp
+
+// Place all of the ffi_prep_args in position
+		push [ebp + 12] // ecif
+		push eax
+		call [ebp + 8] // prepfunc
+
+// Return stack to previous state and call the function
+		add esp, 8
+// FIXME: Align the stack to a 128-bit boundary to avoid
+// potential performance hits.
+		call [ebp + 28]
+
+// Load ecif->cif->abi
+		mov ecx, [ebp + 12]
+		mov ecx, [ecx]ecif.cif
+		mov ecx, [ecx]ecif.cif.abi
+		
+		cmp ecx, FFI_STDCALL
+		je noclean
+// STDCALL: Remove the space we pushed for the args
+		mov ecx, [ebp + 16]
+		add esp, ecx
+// CDECL: Caller has already cleaned the stack
+noclean:
+// Check that esp has the same value as before!
+		sub esi, esp
+
+// Load %ecx with the return type code
+		mov ecx, [ebp + 20]
+
+// If the return value pointer is NULL, assume no return value.
+/*
+  Intel asm is weird. We have to explicitly specify 'DWORD PTR' in the nexr instruction,
+  otherwise only one BYTE will be compared (instead of a DWORD)!
+ */
+		cmp DWORD PTR [ebp + 24], 0
+		jne sc_retint
+
+// Even if there is no space for the return value, we are
+// obliged to handle floating-point values.
+		cmp ecx, FFI_TYPE_FLOAT
+		jne sc_noretval
+//        fstp  %st(0)
+		fstp st(0)
+
+		jmp sc_epilogue
+
+sc_retint:
+		cmp ecx, FFI_TYPE_INT
+		jne sc_retfloat
+//        # Load %ecx with the pointer to storage for the return value
+		mov ecx, [ebp + 24]
+		mov [ecx + 0], eax
+		jmp sc_epilogue
+
+sc_retfloat:
+		cmp ecx, FFI_TYPE_FLOAT
+		jne sc_retdouble
+// Load %ecx with the pointer to storage for the return value
+		mov ecx, [ebp+24]
+//        fstps (%ecx)
+		fstp DWORD PTR [ecx]
+		jmp sc_epilogue
+
+sc_retdouble:
+		cmp ecx, FFI_TYPE_DOUBLE
+		jne sc_retlongdouble
+//        movl  24(%ebp),%ecx
+		mov ecx, [ebp+24]
+		fstp QWORD PTR [ecx]
+		jmp sc_epilogue
+
+		jmp sc_retlongdouble // avoid warning about unused label
+sc_retlongdouble:
+		cmp ecx, FFI_TYPE_LONGDOUBLE
+		jne sc_retint64
+// Load %ecx with the pointer to storage for the return value
+		mov ecx, [ebp+24]
+//        fstpt (%ecx)
+		fstp QWORD PTR [ecx] /* XXX ??? */
+		jmp sc_epilogue
+
+sc_retint64:
+		cmp ecx, FFI_TYPE_SINT64
+		jne sc_retstruct
+// Load %ecx with the pointer to storage for the return value
+		mov ecx, [ebp+24]
+		mov [ecx+0], eax
+		mov [ecx+4], edx
+
+sc_retstruct:
+// Nothing to do!
+
+sc_noretval:
+sc_epilogue:
+		mov eax, esi
+		pop esi // NEW restore: must be preserved across function calls
+		mov esp, ebp
+		pop ebp
+		ret
+	}
+}
diff --git a/lib/wrappers/libffi/msvc/win32_asm.asm b/lib/wrappers/libffi/msvc/win32_asm.asm
new file mode 100644
index 000000000..407185e6a
--- /dev/null
+++ b/lib/wrappers/libffi/msvc/win32_asm.asm
@@ -0,0 +1,470 @@
+/* -----------------------------------------------------------------------
+   win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009  Red Hat, Inc.
+	     Copyright (c) 2001  John Beniton
+	     Copyright (c) 2002  Ranjit Mathew
+	     Copyright (c) 2009  Daniel Witte
+			
+ 
+   X86 Foreign Function Interface
+ 
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   ``Software''), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+ 
+   The above copyright notice and this permission notice shall be included
+   in all copies or substantial portions of the Software.
+ 
+   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   DEALINGS IN THE SOFTWARE.
+   -----------------------------------------------------------------------
+   */
+ 
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+.386
+.MODEL FLAT, C
+
+EXTRN ffi_closure_SYSV_inner:NEAR
+
+_TEXT SEGMENT
+
+ffi_call_win32 PROC NEAR,
+    ffi_prep_args : NEAR PTR DWORD,
+    ecif          : NEAR PTR DWORD,
+    cif_abi       : DWORD,
+    cif_bytes     : DWORD,
+    cif_flags     : DWORD,
+    rvalue        : NEAR PTR DWORD,
+    fn            : NEAR PTR DWORD
+
+        ;; Make room for all of the new args.
+        mov  ecx, cif_bytes
+        sub  esp, ecx
+
+        mov  eax, esp
+
+        ;; Place all of the ffi_prep_args in position
+        push ecif
+        push eax
+        call ffi_prep_args
+
+        ;; Return stack to previous state and call the function
+        add  esp, 8
+
+	;; Handle thiscall and fastcall
+	cmp cif_abi, 3 ;; FFI_THISCALL
+	jz do_thiscall
+	cmp cif_abi, 4 ;; FFI_FASTCALL
+	jnz do_stdcall
+	mov ecx, DWORD PTR [esp]
+	mov edx, DWORD PTR [esp+4]
+	add esp, 8
+	jmp do_stdcall
+do_thiscall:
+	mov ecx, DWORD PTR [esp]
+	add esp, 4
+do_stdcall:
+        call fn
+
+        ;; cdecl:   we restore esp in the epilogue, so there's no need to
+        ;;          remove the space we pushed for the args.
+        ;; stdcall: the callee has already cleaned the stack.
+
+        ;; Load ecx with the return type code
+        mov  ecx, cif_flags
+
+        ;; If the return value pointer is NULL, assume no return value.
+        cmp  rvalue, 0
+        jne  ca_jumptable
+
+        ;; Even if there is no space for the return value, we are
+        ;; obliged to handle floating-point values.
+        cmp  ecx, FFI_TYPE_FLOAT
+        jne  ca_epilogue
+        fstp st(0)
+
+        jmp  ca_epilogue
+
+ca_jumptable:
+        jmp  [ca_jumpdata + 4 * ecx]
+ca_jumpdata:
+        ;; Do not insert anything here between label and jump table.
+        dd offset ca_epilogue       ;; FFI_TYPE_VOID
+        dd offset ca_retint         ;; FFI_TYPE_INT
+        dd offset ca_retfloat       ;; FFI_TYPE_FLOAT
+        dd offset ca_retdouble      ;; FFI_TYPE_DOUBLE
+        dd offset ca_retlongdouble  ;; FFI_TYPE_LONGDOUBLE
+        dd offset ca_retuint8       ;; FFI_TYPE_UINT8
+        dd offset ca_retsint8       ;; FFI_TYPE_SINT8
+        dd offset ca_retuint16      ;; FFI_TYPE_UINT16
+        dd offset ca_retsint16      ;; FFI_TYPE_SINT16
+        dd offset ca_retint         ;; FFI_TYPE_UINT32
+        dd offset ca_retint         ;; FFI_TYPE_SINT32
+        dd offset ca_retint64       ;; FFI_TYPE_UINT64
+        dd offset ca_retint64       ;; FFI_TYPE_SINT64
+        dd offset ca_epilogue       ;; FFI_TYPE_STRUCT
+        dd offset ca_retint         ;; FFI_TYPE_POINTER
+        dd offset ca_retstruct1b    ;; FFI_TYPE_SMALL_STRUCT_1B
+        dd offset ca_retstruct2b    ;; FFI_TYPE_SMALL_STRUCT_2B
+        dd offset ca_retint         ;; FFI_TYPE_SMALL_STRUCT_4B
+        dd offset ca_epilogue       ;; FFI_TYPE_MS_STRUCT
+
+        /* Sign/zero extend as appropriate.  */
+ca_retuint8:
+        movzx eax, al
+        jmp   ca_retint
+
+ca_retsint8:
+        movsx eax, al
+        jmp   ca_retint
+
+ca_retuint16:
+        movzx eax, ax
+        jmp   ca_retint
+
+ca_retsint16:
+        movsx eax, ax
+        jmp   ca_retint
+
+ca_retint:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        mov   [ecx + 0], eax
+        jmp   ca_epilogue
+
+ca_retint64:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        mov   [ecx + 0], eax
+        mov   [ecx + 4], edx
+        jmp   ca_epilogue
+
+ca_retfloat:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        fstp  DWORD PTR [ecx]
+        jmp   ca_epilogue
+
+ca_retdouble:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        fstp  QWORD PTR [ecx]
+        jmp   ca_epilogue
+
+ca_retlongdouble:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        fstp  TBYTE PTR [ecx]
+        jmp   ca_epilogue
+
+ca_retstruct1b:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        mov   [ecx + 0], al
+        jmp   ca_epilogue
+
+ca_retstruct2b:
+        ;; Load %ecx with the pointer to storage for the return value
+        mov   ecx, rvalue
+        mov   [ecx + 0], ax
+        jmp   ca_epilogue
+
+ca_epilogue:
+        ;; Epilogue code is autogenerated.
+        ret
+ffi_call_win32 ENDP
+
+ffi_closure_THISCALL PROC NEAR FORCEFRAME
+	sub	esp, 40
+	lea	edx, [ebp -24]
+	mov	[ebp - 12], edx	/* resp */
+	lea	edx, [ebp + 12]  /* account for stub return address on stack */
+	jmp	stub
+ffi_closure_THISCALL ENDP
+
+ffi_closure_SYSV PROC NEAR FORCEFRAME
+    ;; the ffi_closure ctx is passed in eax by the trampoline.
+
+        sub  esp, 40
+        lea  edx, [ebp - 24]
+        mov  [ebp - 12], edx         ;; resp
+        lea  edx, [ebp + 8]
+stub::
+        mov  [esp + 8], edx          ;; args
+        lea  edx, [ebp - 12]
+        mov  [esp + 4], edx          ;; &resp
+        mov  [esp], eax              ;; closure
+        call ffi_closure_SYSV_inner
+        mov  ecx, [ebp - 12]
+
+cs_jumptable:
+        jmp  [cs_jumpdata + 4 * eax]
+cs_jumpdata:
+        ;; Do not insert anything here between the label and jump table.
+        dd offset cs_epilogue       ;; FFI_TYPE_VOID
+        dd offset cs_retint         ;; FFI_TYPE_INT
+        dd offset cs_retfloat       ;; FFI_TYPE_FLOAT
+        dd offset cs_retdouble      ;; FFI_TYPE_DOUBLE
+        dd offset cs_retlongdouble  ;; FFI_TYPE_LONGDOUBLE
+        dd offset cs_retuint8       ;; FFI_TYPE_UINT8
+        dd offset cs_retsint8       ;; FFI_TYPE_SINT8
+        dd offset cs_retuint16      ;; FFI_TYPE_UINT16
+        dd offset cs_retsint16      ;; FFI_TYPE_SINT16
+        dd offset cs_retint         ;; FFI_TYPE_UINT32
+        dd offset cs_retint         ;; FFI_TYPE_SINT32
+        dd offset cs_retint64       ;; FFI_TYPE_UINT64
+        dd offset cs_retint64       ;; FFI_TYPE_SINT64
+        dd offset cs_retstruct      ;; FFI_TYPE_STRUCT
+        dd offset cs_retint         ;; FFI_TYPE_POINTER
+        dd offset cs_retsint8       ;; FFI_TYPE_SMALL_STRUCT_1B
+        dd offset cs_retsint16      ;; FFI_TYPE_SMALL_STRUCT_2B
+        dd offset cs_retint         ;; FFI_TYPE_SMALL_STRUCT_4B
+        dd offset cs_retmsstruct    ;; FFI_TYPE_MS_STRUCT
+
+cs_retuint8:
+        movzx eax, BYTE PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retsint8:
+        movsx eax, BYTE PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retuint16:
+        movzx eax, WORD PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retsint16:
+        movsx eax, WORD PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retint:
+        mov   eax, [ecx]
+        jmp   cs_epilogue
+
+cs_retint64:
+        mov   eax, [ecx + 0]
+        mov   edx, [ecx + 4]
+        jmp   cs_epilogue
+
+cs_retfloat:
+        fld   DWORD PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retdouble:
+        fld   QWORD PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retlongdouble:
+        fld   TBYTE PTR [ecx]
+        jmp   cs_epilogue
+
+cs_retstruct:
+        ;; Caller expects us to pop struct return value pointer hidden arg.
+        ;; Epilogue code is autogenerated.
+        ret	4
+
+cs_retmsstruct:
+        ;; Caller expects us to return a pointer to the real return value.
+        mov   eax, ecx
+        ;; Caller doesn't expects us to pop struct return value pointer hidden arg.
+        jmp   cs_epilogue
+
+cs_epilogue:
+        ;; Epilogue code is autogenerated.
+        ret
+ffi_closure_SYSV ENDP
+
+#if !FFI_NO_RAW_API
+
+#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3)
+#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
+#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
+#define CIF_FLAGS_OFFSET 20
+
+ffi_closure_raw_THISCALL PROC NEAR USES esi FORCEFRAME
+	sub esp, 36
+	mov  esi, [eax + RAW_CLOSURE_CIF_OFFSET]        ;; closure->cif
+	mov  edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET]  ;; closure->user_data
+	mov [esp + 12], edx
+	lea edx, [ebp + 12]
+	jmp stubraw
+ffi_closure_raw_THISCALL ENDP
+
+ffi_closure_raw_SYSV PROC NEAR USES esi FORCEFRAME
+    ;; the ffi_closure ctx is passed in eax by the trampoline.
+
+        sub  esp, 40
+        mov  esi, [eax + RAW_CLOSURE_CIF_OFFSET]        ;; closure->cif
+        mov  edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET]  ;; closure->user_data
+        mov  [esp + 12], edx                            ;; user_data
+        lea  edx, [ebp + 8]
+stubraw::
+        mov  [esp + 8], edx                             ;; raw_args
+        lea  edx, [ebp - 24]
+        mov  [esp + 4], edx                             ;; &res
+        mov  [esp], esi                                 ;; cif
+        call DWORD PTR [eax + RAW_CLOSURE_FUN_OFFSET]   ;; closure->fun
+        mov  eax, [esi + CIF_FLAGS_OFFSET]              ;; cif->flags
+        lea  ecx, [ebp - 24]
+
+cr_jumptable:
+        jmp  [cr_jumpdata + 4 * eax]
+cr_jumpdata:
+        ;; Do not insert anything here between the label and jump table.
+        dd offset cr_epilogue       ;; FFI_TYPE_VOID
+        dd offset cr_retint         ;; FFI_TYPE_INT
+        dd offset cr_retfloat       ;; FFI_TYPE_FLOAT
+        dd offset cr_retdouble      ;; FFI_TYPE_DOUBLE
+        dd offset cr_retlongdouble  ;; FFI_TYPE_LONGDOUBLE
+        dd offset cr_retuint8       ;; FFI_TYPE_UINT8
+        dd offset cr_retsint8       ;; FFI_TYPE_SINT8
+        dd offset cr_retuint16      ;; FFI_TYPE_UINT16
+        dd offset cr_retsint16      ;; FFI_TYPE_SINT16
+        dd offset cr_retint         ;; FFI_TYPE_UINT32
+        dd offset cr_retint         ;; FFI_TYPE_SINT32
+        dd offset cr_retint64       ;; FFI_TYPE_UINT64
+        dd offset cr_retint64       ;; FFI_TYPE_SINT64
+        dd offset cr_epilogue       ;; FFI_TYPE_STRUCT
+        dd offset cr_retint         ;; FFI_TYPE_POINTER
+        dd offset cr_retsint8       ;; FFI_TYPE_SMALL_STRUCT_1B
+        dd offset cr_retsint16      ;; FFI_TYPE_SMALL_STRUCT_2B
+        dd offset cr_retint         ;; FFI_TYPE_SMALL_STRUCT_4B
+        dd offset cr_epilogue       ;; FFI_TYPE_MS_STRUCT
+
+cr_retuint8:
+        movzx eax, BYTE PTR [ecx]
+        jmp   cr_epilogue
+
+cr_retsint8:
+        movsx eax, BYTE PTR [ecx]
+        jmp   cr_epilogue
+
+cr_retuint16:
+        movzx eax, WORD PTR [ecx]
+        jmp   cr_epilogue
+
+cr_retsint16:
+        movsx eax, WORD PTR [ecx]
+        jmp   cr_epilogue
+
+cr_retint:
+        mov   eax, [ecx]
+        jmp   cr_epilogue
+
+cr_retint64:
+        mov   eax, [ecx + 0]
+        mov   edx, [ecx + 4]
+        jmp   cr_epilogue
+
+cr_retfloat:
+        fld   DWORD PTR [ecx]
+        jmp   cr_epilogue
+
+cr_retdouble:
+        fld   QWORD PTR [ecx]
+        jmp   cr_epilogue
+
+cr_retlongdouble:
+        fld   TBYTE PTR [ecx]
+        jmp   cr_epilogue
+
+cr_epilogue:
+        ;; Epilogue code is autogenerated.
+        ret
+ffi_closure_raw_SYSV ENDP
+
+#endif /* !FFI_NO_RAW_API */
+
+ffi_closure_STDCALL PROC NEAR FORCEFRAME
+    ;; the ffi_closure ctx is passed in eax by the trampoline.
+
+        sub  esp, 40
+        lea  edx, [ebp - 24]
+        mov  [ebp - 12], edx         ;; resp
+        lea  edx, [ebp + 12]         ;; account for stub return address on stack
+        mov  [esp + 8], edx          ;; args
+        lea  edx, [ebp - 12]
+        mov  [esp + 4], edx          ;; &resp
+        mov  [esp], eax              ;; closure
+        call ffi_closure_SYSV_inner
+        mov  ecx, [ebp - 12]
+
+cd_jumptable:
+        jmp  [cd_jumpdata + 4 * eax]
+cd_jumpdata:
+        ;; Do not insert anything here between the label and jump table.
+        dd offset cd_epilogue       ;; FFI_TYPE_VOID
+        dd offset cd_retint         ;; FFI_TYPE_INT
+        dd offset cd_retfloat       ;; FFI_TYPE_FLOAT
+        dd offset cd_retdouble      ;; FFI_TYPE_DOUBLE
+        dd offset cd_retlongdouble  ;; FFI_TYPE_LONGDOUBLE
+        dd offset cd_retuint8       ;; FFI_TYPE_UINT8
+        dd offset cd_retsint8       ;; FFI_TYPE_SINT8
+        dd offset cd_retuint16      ;; FFI_TYPE_UINT16
+        dd offset cd_retsint16      ;; FFI_TYPE_SINT16
+        dd offset cd_retint         ;; FFI_TYPE_UINT32
+        dd offset cd_retint         ;; FFI_TYPE_SINT32
+        dd offset cd_retint64       ;; FFI_TYPE_UINT64
+        dd offset cd_retint64       ;; FFI_TYPE_SINT64
+        dd offset cd_epilogue       ;; FFI_TYPE_STRUCT
+        dd offset cd_retint         ;; FFI_TYPE_POINTER
+        dd offset cd_retsint8       ;; FFI_TYPE_SMALL_STRUCT_1B
+        dd offset cd_retsint16      ;; FFI_TYPE_SMALL_STRUCT_2B
+        dd offset cd_retint         ;; FFI_TYPE_SMALL_STRUCT_4B
+
+cd_retuint8:
+        movzx eax, BYTE PTR [ecx]
+        jmp   cd_epilogue
+
+cd_retsint8:
+        movsx eax, BYTE PTR [ecx]
+        jmp   cd_epilogue
+
+cd_retuint16:
+        movzx eax, WORD PTR [ecx]
+        jmp   cd_epilogue
+
+cd_retsint16:
+        movsx eax, WORD PTR [ecx]
+        jmp   cd_epilogue
+
+cd_retint:
+        mov   eax, [ecx]
+        jmp   cd_epilogue
+
+cd_retint64:
+        mov   eax, [ecx + 0]
+        mov   edx, [ecx + 4]
+        jmp   cd_epilogue
+
+cd_retfloat:
+        fld   DWORD PTR [ecx]
+        jmp   cd_epilogue
+
+cd_retdouble:
+        fld   QWORD PTR [ecx]
+        jmp   cd_epilogue
+
+cd_retlongdouble:
+        fld   TBYTE PTR [ecx]
+        jmp   cd_epilogue
+
+cd_epilogue:
+        ;; Epilogue code is autogenerated.
+        ret
+ffi_closure_STDCALL ENDP
+
+_TEXT ENDS
+END
diff --git a/lib/wrappers/libffi/msvc/win64_asm.asm b/lib/wrappers/libffi/msvc/win64_asm.asm
new file mode 100644
index 000000000..301188bc9
--- /dev/null
+++ b/lib/wrappers/libffi/msvc/win64_asm.asm
@@ -0,0 +1,156 @@
+PUBLIC	ffi_call_AMD64
+
+EXTRN	__chkstk:NEAR
+EXTRN	ffi_closure_SYSV:NEAR
+
+_TEXT	SEGMENT
+
+;;; ffi_closure_OUTER will be called with these registers set:
+;;;    rax points to 'closure'
+;;;    r11 contains a bit mask that specifies which of the
+;;;    first four parameters are float or double
+;;;
+;;; It must move the parameters passed in registers to their stack location,
+;;; call ffi_closure_SYSV for the actual work, then return the result.
+;;; 
+ffi_closure_OUTER PROC FRAME
+	;; save actual arguments to their stack space.
+	test	r11, 1
+	jne	first_is_float	
+	mov	QWORD PTR [rsp+8], rcx
+	jmp	second
+first_is_float:
+	movlpd	QWORD PTR [rsp+8], xmm0
+
+second:
+	test	r11, 2
+	jne	second_is_float	
+	mov	QWORD PTR [rsp+16], rdx
+	jmp	third
+second_is_float:
+	movlpd	QWORD PTR [rsp+16], xmm1
+
+third:
+	test	r11, 4
+	jne	third_is_float	
+	mov	QWORD PTR [rsp+24], r8
+	jmp	forth
+third_is_float:
+	movlpd	QWORD PTR [rsp+24], xmm2
+
+forth:
+	test	r11, 8
+	jne	forth_is_float	
+	mov	QWORD PTR [rsp+32], r9
+	jmp	done
+forth_is_float:
+	movlpd	QWORD PTR [rsp+32], xmm3
+
+done:
+.ALLOCSTACK 40
+	sub	rsp, 40
+.ENDPROLOG
+	mov	rcx, rax	; context is first parameter
+	mov	rdx, rsp	; stack is second parameter
+	add	rdx, 40		; correct our own area
+	mov	rax, ffi_closure_SYSV
+	call	rax		; call the real closure function
+	;; Here, code is missing that handles float return values
+	add	rsp, 40
+	movd	xmm0, rax	; In case the closure returned a float.
+	ret	0
+ffi_closure_OUTER ENDP
+
+
+;;; ffi_call_AMD64
+
+stack$ = 0
+prepfunc$ = 32
+ecif$ = 40
+bytes$ = 48
+flags$ = 56
+rvalue$ = 64
+fn$ = 72
+
+ffi_call_AMD64 PROC FRAME
+
+	mov	QWORD PTR [rsp+32], r9
+	mov	QWORD PTR [rsp+24], r8
+	mov	QWORD PTR [rsp+16], rdx
+	mov	QWORD PTR [rsp+8], rcx
+.PUSHREG rbp
+	push	rbp
+.ALLOCSTACK 48
+	sub	rsp, 48					; 00000030H
+.SETFRAME rbp, 32
+	lea	rbp, QWORD PTR [rsp+32]
+.ENDPROLOG
+
+	mov	eax, DWORD PTR bytes$[rbp]
+	add	rax, 15
+	and	rax, -16
+	call	__chkstk
+	sub	rsp, rax
+	lea	rax, QWORD PTR [rsp+32]
+	mov	QWORD PTR stack$[rbp], rax
+
+	mov	rdx, QWORD PTR ecif$[rbp]
+	mov	rcx, QWORD PTR stack$[rbp]
+	call	QWORD PTR prepfunc$[rbp]
+
+	mov	rsp, QWORD PTR stack$[rbp]
+
+	movlpd	xmm3, QWORD PTR [rsp+24]
+	movd	r9, xmm3
+
+	movlpd	xmm2, QWORD PTR [rsp+16]
+	movd	r8, xmm2
+
+	movlpd	xmm1, QWORD PTR [rsp+8]
+	movd	rdx, xmm1
+
+	movlpd	xmm0, QWORD PTR [rsp]
+	movd	rcx, xmm0
+
+	call	QWORD PTR fn$[rbp]
+ret_int$:
+ 	cmp	DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT
+ 	jne	ret_float$
+
+	mov	rcx, QWORD PTR rvalue$[rbp]
+	mov	DWORD PTR [rcx], eax
+	jmp	SHORT ret_nothing$
+
+ret_float$:
+ 	cmp	DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT
+ 	jne	SHORT ret_double$
+
+ 	mov	rax, QWORD PTR rvalue$[rbp]
+ 	movlpd	QWORD PTR [rax], xmm0
+ 	jmp	SHORT ret_nothing$
+
+ret_double$:
+ 	cmp	DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE
+ 	jne	SHORT ret_int64$
+
+ 	mov	rax, QWORD PTR rvalue$[rbp]
+ 	movlpd	QWORD PTR [rax], xmm0
+ 	jmp	SHORT ret_nothing$
+
+ret_int64$:
+  	cmp	DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64
+  	jne	ret_nothing$
+
+ 	mov	rcx, QWORD PTR rvalue$[rbp]
+ 	mov	QWORD PTR [rcx], rax
+ 	jmp	SHORT ret_nothing$
+	
+ret_nothing$:
+	xor	eax, eax
+
+	lea	rsp, QWORD PTR [rbp+16]
+	pop	rbp
+	ret	0
+ffi_call_AMD64 ENDP
+_TEXT	ENDS
+END
diff --git a/lib/wrappers/libsvm.nim b/lib/wrappers/libsvm.nim
new file mode 100644
index 000000000..00d5ac73c
--- /dev/null
+++ b/lib/wrappers/libsvm.nim
@@ -0,0 +1,116 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module is a low level wrapper for `libsvm`:idx:.
+
+{.deadCodeElim: on.}
+const 
+  LIBSVM_VERSION* = 312
+  
+when defined(windows):
+  const svmdll* = "libsvm.dll"
+elif defined(macosx):
+  const svmdll* = "libsvm.dylib"
+else:
+  const svmdll* = "libsvm.so"
+
+type 
+  Tnode*{.pure, final.} = object 
+    index*: cint
+    value*: cdouble
+
+  Tproblem*{.pure, final.} = object 
+    L*: cint
+    y*: ptr cdouble
+    x*: ptr ptr Tnode
+
+  Ttype*{.size: sizeof(cint).} = enum 
+    C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR
+  
+  TKernelType*{.size: sizeof(cint).} = enum 
+    LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED
+  
+  Tparameter*{.pure, final.} = object 
+    typ*: TType
+    kernelType*: TKernelType
+    degree*: cint             # for poly 
+    gamma*: cdouble           # for poly/rbf/sigmoid 
+    coef0*: cdouble           # for poly/sigmoid 
+                              # these are for training only 
+    cache_size*: cdouble      # in MB 
+    eps*: cdouble             # stopping criteria 
+    C*: cdouble               # for C_SVC, EPSILON_SVR and NU_SVR 
+    nr_weight*: cint          # for C_SVC 
+    weight_label*: ptr cint   # for C_SVC 
+    weight*: ptr cdouble      # for C_SVC 
+    nu*: cdouble              # for NU_SVC, ONE_CLASS, and NU_SVR 
+    p*: cdouble               # for EPSILON_SVR 
+    shrinking*: cint          # use the shrinking heuristics 
+    probability*: cint        # do probability estimates 
+  
+
+#
+# svm_model
+# 
+
+type 
+  TModel*{.pure, final.} = object 
+    param*: Tparameter        # parameter 
+    nr_class*: cint           # number of classes, = 2 in regression/one class svm 
+    L*: cint                  # total #SV 
+    SV*: ptr ptr Tnode        # SVs (SV[l]) 
+    sv_coef*: ptr ptr cdouble # coefficients for SVs in decision functions (sv_coef[k-1][l]) 
+    rho*: ptr cdouble         # constants in decision functions (rho[k*(k-1)/2]) 
+    probA*: ptr cdouble       # pariwise probability information 
+    probB*: ptr cdouble       # for classification only 
+    label*: ptr cint          # label of each class (label[k]) 
+    nSV*: ptr cint            # number of SVs for each class (nSV[k]) 
+                              # nSV[0] + nSV[1] + ... + nSV[k-1] = l 
+                              # XXX 
+    free_sv*: cint            # 1 if svm_model is created by svm_load_model
+                              # 0 if svm_model is created by svm_train 
+  
+
+proc train*(prob: ptr Tproblem, param: ptr Tparameter): ptr Tmodel{.cdecl, 
+    importc: "svm_train", dynlib: svmdll.}
+proc cross_validation*(prob: ptr Tproblem, param: ptr Tparameter, nr_fold: cint, 
+                       target: ptr cdouble){.cdecl, 
+    importc: "svm_cross_validation", dynlib: svmdll.}
+proc save_model*(model_file_name: cstring, model: ptr Tmodel): cint{.cdecl, 
+    importc: "svm_save_model", dynlib: svmdll.}
+proc load_model*(model_file_name: cstring): ptr Tmodel{.cdecl, 
+    importc: "svm_load_model", dynlib: svmdll.}
+proc get_svm_type*(model: ptr Tmodel): cint{.cdecl, importc: "svm_get_svm_type", 
+    dynlib: svmdll.}
+proc get_nr_class*(model: ptr Tmodel): cint{.cdecl, importc: "svm_get_nr_class", 
+    dynlib: svmdll.}
+proc get_labels*(model: ptr Tmodel, label: ptr cint){.cdecl, 
+    importc: "svm_get_labels", dynlib: svmdll.}
+proc get_svr_probability*(model: ptr Tmodel): cdouble{.cdecl, 
+    importc: "svm_get_svr_probability", dynlib: svmdll.}
+proc predict_values*(model: ptr Tmodel, x: ptr Tnode, dec_values: ptr cdouble): cdouble{.
+    cdecl, importc: "svm_predict_values", dynlib: svmdll.}
+proc predict*(model: ptr Tmodel, x: ptr Tnode): cdouble{.cdecl, 
+    importc: "svm_predict", dynlib: svmdll.}
+proc predict_probability*(model: ptr Tmodel, x: ptr Tnode, 
+                          prob_estimates: ptr cdouble): cdouble{.cdecl, 
+    importc: "svm_predict_probability", dynlib: svmdll.}
+proc free_model_content*(model_ptr: ptr Tmodel){.cdecl, 
+    importc: "svm_free_model_content", dynlib: svmdll.}
+proc free_and_destroy_model*(model_ptr_ptr: ptr ptr Tmodel){.cdecl, 
+    importc: "svm_free_and_destroy_model", dynlib: svmdll.}
+proc destroy_param*(param: ptr Tparameter){.cdecl, importc: "svm_destroy_param", 
+    dynlib: svmdll.}
+proc check_parameter*(prob: ptr Tproblem, param: ptr Tparameter): cstring{.
+    cdecl, importc: "svm_check_parameter", dynlib: svmdll.}
+proc check_probability_model*(model: ptr Tmodel): cint{.cdecl, 
+    importc: "svm_check_probability_model", dynlib: svmdll.}
+
+proc set_print_string_function*(print_func: proc (arg: cstring) {.cdecl.}){.
+    cdecl, importc: "svm_set_print_string_function", dynlib: svmdll.}
diff --git a/lib/wrappers/libuv.nim b/lib/wrappers/libuv.nim
new file mode 100644
index 000000000..a52ae0f63
--- /dev/null
+++ b/lib/wrappers/libuv.nim
@@ -0,0 +1,701 @@
+## libuv is still fast moving target
+## This file was last updated against a development HEAD revision of https://github.com/joyent/libuv/
+
+## Use the following link to see changes (in uv.h) since then and don't forget to update the information here.
+## https://github.com/joyent/libuv/compare/9f6024a6fa9d254527b4b59af724257df870288b...master
+
+when defined(Windows):
+  import winlean
+else:
+  import posix
+
+type
+  TPort* = distinct int16  ## port type
+
+  cssize = int
+  coff = int
+  csize = int
+
+  AllocProc* = proc (handle: PHandle, suggested_size: csize): TBuf {.cdecl.}
+  ReadProc* = proc (stream: PStream, nread: cssize, buf: TBuf) {.cdecl.}
+  ReadProc2* = proc (stream: PPipe, nread: cssize, buf: TBuf, pending: THandleType) {.cdecl.}
+  WriteProc* = proc (req: PWrite, status: cint) {.cdecl.}
+  ConnectProc* = proc (req: PConnect, status: cint) {.cdecl.}
+  ShutdownProc* = proc (req: PShutdown, status: cint) {.cdecl.}
+  ConnectionProc* = proc (server: PStream, status: cint) {.cdecl.}
+  CloseProc* = proc (handle: PHandle) {.cdecl.}
+  TimerProc* = proc (handle: PTimer, status: cint) {.cdecl.}
+  AsyncProc* = proc (handle: PAsync, status: cint) {.cdecl.}
+  PrepareProc* = proc (handle: PPrepare, status: cint) {.cdecl.}
+  CheckProc* = proc (handle: PCheck, status: cint) {.cdecl.}
+  IdleProc* = proc (handle: PIdle, status: cint) {.cdecl.}
+
+  PSockAddr* = ptr SockAddr
+
+  GetAddrInfoProc* = proc (handle: PGetAddrInfo, status: cint, res: ptr AddrInfo)
+
+  ExitProc* = proc (a2: PProcess, exit_status: cint, term_signal: cint)
+  FsProc* = proc (req: PFS)
+  WorkProc* = proc (req: PWork)
+  AfterWorkProc* = proc (req: PWork)
+
+  FsEventProc* = proc (handle: PFsEvent, filename: cstring, events: cint, status: cint)
+
+  TErrorCode* {.size: sizeof(cint).} = enum
+    UNKNOWN = - 1, OK = 0, EOF, EACCESS, EAGAIN, EADDRINUSE, EADDRNOTAVAIL,
+    EAFNOSUPPORT, EALREADY, EBADF, EBUSY, ECONNABORTED, ECONNREFUSED,
+    ECONNRESET, EDESTADDRREQ, EFAULT, EHOSTUNREACH, EINTR, EINVAL, EISCONN,
+    EMFILE, EMSGSIZE, ENETDOWN, ENETUNREACH, ENFILE, ENOBUFS, ENOMEM, ENONET,
+    ENOPROTOOPT, ENOTCONN, ENOTSOCK, ENOTSUP, ENOENT, EPIPE, EPROTO,
+    EPROTONOSUPPORT, EPROTOTYPE, ETIMEDOUT, ECHARSET, EAIFAMNOSUPPORT,
+    EAINONAME, EAISERVICE, EAISOCKTYPE, ESHUTDOWN, EEXIST
+
+  THandleType* {.size: sizeof(cint).} = enum
+    UNKNOWN_HANDLE = 0, TCP, UDP, NAMED_PIPE, TTY, FILE, TIMER, PREPARE, CHECK,
+    IDLE, ASYNC, ARES_TASK, ARES_EVENT, PROCESS, FS_EVENT
+
+  TReqType* {.size: sizeof(cint).} = enum
+    rUNKNOWN_REQ = 0,
+    rCONNECT,
+    rACCEPT,
+    rREAD,
+    rWRITE,
+    rSHUTDOWN,
+    rWAKEUP,
+    rUDP_SEND,
+    rFS,
+    rWORK,
+    rGETADDRINFO,
+    rREQ_TYPE_PRIVATE
+
+  TErr* {.pure, final, importc: "uv_err_t", header: "uv.h".} = object
+    code* {.importc: "code".}: TErrorCode
+    sys_errno* {.importc: "sys_errno_".}: cint
+
+  TFsEventType* = enum
+    evRENAME = 1,
+    evCHANGE = 2
+
+  TFsEvent* {.pure, final, importc: "uv_fs_event_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    filename {.importc: "filename".}: cstring
+
+  PFsEvent* = ptr TFsEvent
+
+  TFsEvents* {.pure, final, importc: "uv_fs_event_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    filename* {.importc: "filename".}: cstring
+
+  TBuf* {.pure, final, importc: "uv_buf_t", header: "uv.h"} = object
+    base* {.importc: "base".}: cstring
+    len* {.importc: "len".}: csize
+
+  TAnyHandle* {.pure, final, importc: "uv_any_handle", header: "uv.h".} = object
+    tcp* {.importc: "tcp".}: TTcp
+    pipe* {.importc: "pipe".}: TPipe
+    prepare* {.importc: "prepare".}: TPrepare
+    check* {.importc: "check".}: TCheck
+    idle* {.importc: "idle".}: TIdle
+    async* {.importc: "async".}: TAsync
+    timer* {.importc: "timer".}: TTimer
+    getaddrinfo* {.importc: "getaddrinfo".}: TGetaddrinfo
+    fs_event* {.importc: "fs_event".}: TFsEvents
+
+  TAnyReq* {.pure, final, importc: "uv_any_req", header: "uv.h".} = object
+    req* {.importc: "req".}: TReq
+    write* {.importc: "write".}: TWrite
+    connect* {.importc: "connect".}: TConnect
+    shutdown* {.importc: "shutdown".}: TShutdown
+    fs_req* {.importc: "fs_req".}: Tfs
+    work_req* {.importc: "work_req".}: TWork
+
+  ## better import this
+  uint64 = int64
+
+  TCounters* {.pure, final, importc: "uv_counters_t", header: "uv.h".} = object
+    eio_init* {.importc: "eio_init".}: uint64
+    req_init* {.importc: "req_init".}: uint64
+    handle_init* {.importc: "handle_init".}: uint64
+    stream_init* {.importc: "stream_init".}: uint64
+    tcp_init* {.importc: "tcp_init".}: uint64
+    udp_init* {.importc: "udp_init".}: uint64
+    pipe_init* {.importc: "pipe_init".}: uint64
+    tty_init* {.importc: "tty_init".}: uint64
+    prepare_init* {.importc: "prepare_init".}: uint64
+    check_init* {.importc: "check_init".}: uint64
+    idle_init* {.importc: "idle_init".}: uint64
+    async_init* {.importc: "async_init".}: uint64
+    timer_init* {.importc: "timer_init".}: uint64
+    process_init* {.importc: "process_init".}: uint64
+    fs_event_init* {.importc: "fs_event_init".}: uint64
+
+  TLoop* {.pure, final, importc: "uv_loop_t", header: "uv.h".} = object
+    # ares_handles_* {.importc: "uv_ares_handles_".}: pointer # XXX: This seems to be a private field? 
+    eio_want_poll_notifier* {.importc: "uv_eio_want_poll_notifier".}: TAsync
+    eio_done_poll_notifier* {.importc: "uv_eio_done_poll_notifier".}: TAsync
+    eio_poller* {.importc: "uv_eio_poller".}: TIdle
+    counters* {.importc: "counters".}: TCounters
+    last_err* {.importc: "last_err".}: TErr
+    data* {.importc: "data".}: pointer
+
+  PLoop* = ptr TLoop
+
+  TShutdown* {.pure, final, importc: "uv_shutdown_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    handle* {.importc: "handle".}: PStream
+    cb* {.importc: "cb".}: ShutdownProc
+
+  PShutdown* = ptr TShutdown
+
+  THandle* {.pure, final, importc: "uv_handle_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PHandle* = ptr THandle
+
+  TStream* {.pure, final, importc: "uv_stream_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    alloc_cb* {.importc: "alloc_cb".}: AllocProc
+    read_cb* {.importc: "read_cb".}: ReadProc
+    read2_cb* {.importc: "read2_cb".}: ReadProc2
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    write_queue_size* {.importc: "write_queue_size".}: csize
+
+  PStream* = ptr TStream
+
+  TWrite* {.pure, final, importc: "uv_write_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    cb* {.importc: "cb".}: WriteProc
+    send_handle* {.importc: "send_handle".}: PStream
+    handle* {.importc: "handle".}: PStream
+
+  PWrite* = ptr TWrite
+
+  TTcp* {.pure, final, importc: "uv_tcp_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    alloc_cb* {.importc: "alloc_cb".}: AllocProc
+    read_cb* {.importc: "read_cb".}: ReadProc
+    read2_cb* {.importc: "read2_cb".}: ReadProc2
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    write_queue_size* {.importc: "write_queue_size".}: csize
+
+  PTcp* = ptr TTcp
+
+  TConnect* {.pure, final, importc: "uv_connect_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    cb* {.importc: "cb".}: ConnectProc
+    handle* {.importc: "handle".}: PStream
+
+  PConnect* = ptr TConnect
+
+  TUdpFlags* = enum
+    UDP_IPV6ONLY = 1, UDP_PARTIAL = 2
+
+  ## XXX: better import this
+  cunsigned = int
+
+  UdpSendProc* = proc (req: PUdpSend, status: cint)
+  UdpRecvProc* = proc (handle: PUdp, nread: cssize, buf: TBuf, adr: ptr SockAddr, flags: cunsigned)
+
+  TUdp* {.pure, final, importc: "uv_udp_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PUdp* = ptr TUdp
+
+  TUdpSend* {.pure, final, importc: "uv_udp_send_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    handle* {.importc: "handle".}: PUdp
+    cb* {.importc: "cb".}: UdpSendProc
+
+  PUdpSend* = ptr TUdpSend
+
+  tTTy* {.pure, final, importc: "uv_tty_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    alloc_cb* {.importc: "alloc_cb".}: AllocProc
+    read_cb* {.importc: "read_cb".}: ReadProc
+    read2_cb* {.importc: "read2_cb".}: ReadProc2
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    write_queue_size* {.importc: "write_queue_size".}: csize
+
+  pTTy* = ptr tTTy
+
+  TPipe* {.pure, final, importc: "uv_pipe_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    alloc_cb* {.importc: "alloc_cb".}: AllocProc
+    read_cb* {.importc: "read_cb".}: ReadProc
+    read2_cb* {.importc: "read2_cb".}: ReadProc2
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    write_queue_size* {.importc: "write_queue_size".}: csize
+    ipc {.importc: "ipc".}: int
+
+  PPipe* = ptr TPipe
+
+  TPrepare* {.pure, final, importc: "uv_prepare_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PPrepare* = ptr TPrepare
+
+  TCheck* {.pure, final, importc: "uv_check_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PCheck* = ptr TCheck
+
+  TIdle* {.pure, final, importc: "uv_idle_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PIdle* = ptr TIdle
+
+  TAsync* {.pure, final, importc: "uv_async_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PAsync* = ptr TAsync
+
+  TTimer* {.pure, final, importc: "uv_timer_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+
+  PTimer* = ptr TTimer
+
+  TGetAddrInfo* {.pure, final, importc: "uv_getaddrinfo_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    loop* {.importc: "loop".}: PLoop
+
+  PGetAddrInfo* = ptr TGetAddrInfo
+
+  TProcessOptions* {.pure, final, importc: "uv_process_options_t", header: "uv.h".} = object
+    exit_cb* {.importc: "exit_cb".}: ExitProc
+    file* {.importc: "file".}: cstring
+    args* {.importc: "args".}: cstringArray
+    env* {.importc: "env".}: cstringArray
+    cwd* {.importc: "cwd".}: cstring
+    windows_verbatim_arguments* {.importc: "windows_verbatim_arguments".}: cint
+    stdin_stream* {.importc: "stdin_stream".}: PPipe
+    stdout_stream* {.importc: "stdout_stream".}: PPipe
+    stderr_stream* {.importc: "stderr_stream".}: PPipe
+
+  PProcessOptions* = ptr TProcessOptions
+
+  TProcess* {.pure, final, importc: "uv_process_t", header: "uv.h".} = object
+    loop* {.importc: "loop".}: PLoop
+    typ* {.importc: "type".}: THandleType
+    close_cb* {.importc: "close_cb".}: CloseProc
+    data* {.importc: "data".}: pointer
+    exit_cb* {.importc: "exit_cb".}: ExitProc
+    pid* {.importc: "pid".}: cint
+
+  PProcess* = ptr TProcess
+
+  TWork* {.pure, final, importc: "uv_work_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    loop* {.importc: "loop".}: PLoop
+    work_cb* {.importc: "work_cb".}: WorkProc
+    after_work_cb* {.importc: "after_work_cb".}: AfterWorkProc
+
+  PWork* = ptr TWork
+
+  TFsType* {.size: sizeof(cint).} = enum
+    FS_UNKNOWN = - 1, FS_CUSTOM, FS_OPEN, FS_CLOSE, FS_READ, FS_WRITE,
+    FS_SENDFILE, FS_STAT, FS_LSTAT, FS_FSTAT, FS_FTRUNCATE, FS_UTIME, FS_FUTIME,
+    FS_CHMOD, FS_FCHMOD, FS_FSYNC, FS_FDATASYNC, FS_UNLINK, FS_RMDIR, FS_MKDIR,
+    FS_RENAME, FS_READDIR, FS_LINK, FS_SYMLINK, FS_READLINK, FS_CHOWN, FS_FCHOWN
+
+  TFS* {.pure, final, importc: "uv_fs_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+    loop* {.importc: "loop".}: PLoop
+    fs_type* {.importc: "fs_type".}: TFsType
+    cb* {.importc: "cb".}: FsProc
+    result* {.importc: "result".}: cssize
+    fsPtr* {.importc: "ptr".}: pointer
+    path* {.importc: "path".}: cstring
+    errorno* {.importc: "errorno".}: cint
+
+  PFS* = ptr TFS
+
+  TReq* {.pure, final, importc: "uv_req_t", header: "uv.h".} = object
+    typ* {.importc: "type".}: TReqType
+    data* {.importc: "data".}: pointer
+
+  PReq* = ptr TReq
+
+  TAresOptions* {.pure, final, importc: "ares_options", header: "uv.h".} = object
+    flags* {.importc: "flags".}: int
+    timeout* {.importc: "timeout".}: int
+    tries* {.importc: "tries".}: int
+    ndots* {.importc: "ndots".}: int
+    udp_port* {.importc: "udp_port".}: TPort
+    tcp_port* {.importc: "tcp_port".}: TPort
+    socket_send_buffer_size* {.importc: "socket_send_buffer_size".}: int
+    socket_recv_buffer_size* {.importc: "socket_receive_buffer_size".}: int
+    servers* {.importc: "servers".}: ptr InAddr
+    nservers* {.importc: "nservers".}: int
+    domains* {.importc: "domains".}: ptr cstring
+    ndomains* {.importc: "ndomains".}: int
+    lookups* {.importc: "lookups".}: cstring
+
+  #XXX: not yet exported
+  #ares_sock_state_cb sock_state_cb;
+  #void *sock_state_cb_data;
+  #struct apattern *sortlist;
+  #int nsort;
+
+  PAresOptions* = ptr TAresOptions
+  PAresChannel* = pointer
+
+proc loop_new*(): PLoop{.
+    importc: "uv_loop_new", header: "uv.h".}
+
+proc loop_delete*(a2: PLoop){.
+    importc: "uv_loop_delete", header: "uv.h".}
+
+proc default_loop*(): PLoop{.
+    importc: "uv_default_loop", header: "uv.h".}
+
+proc run*(a2: PLoop): cint{.
+    importc: "uv_run", header: "uv.h".}
+
+proc addref*(a2: PLoop){.
+    importc: "uv_ref", header: "uv.h".}
+
+proc unref*(a2: PLoop){.
+    importc: "uv_unref", header: "uv.h".}
+
+proc update_time*(a2: PLoop){.
+    importc: "uv_update_time", header: "uv.h".}
+
+proc now*(a2: PLoop): int64{.
+    importc: "uv_now", header: "uv.h".}
+
+proc last_error*(a2: PLoop): TErr{.
+    importc: "uv_last_error", header: "uv.h".}
+
+proc strerror*(err: TErr): cstring{.
+    importc: "uv_strerror", header: "uv.h".}
+
+proc err_name*(err: TErr): cstring{.
+    importc: "uv_err_name", header: "uv.h".}
+
+proc shutdown*(req: PShutdown, handle: PStream, cb: ShutdownProc): cint{.
+    importc: "uv_shutdown", header: "uv.h".}
+
+proc is_active*(handle: PHandle): cint{.
+    importc: "uv_is_active", header: "uv.h".}
+
+proc close*(handle: PHandle, close_cb: CloseProc){.
+    importc: "uv_close", header: "uv.h".}
+
+proc buf_init*(base: cstring, len: csize): TBuf{.
+    importc: "uv_buf_init", header: "uv.h".}
+
+proc listen*(stream: PStream, backlog: cint, cb: ConnectionProc): cint{.
+    importc: "uv_listen", header: "uv.h".}
+
+proc accept*(server: PStream, client: PStream): cint{.
+    importc: "uv_accept", header: "uv.h".}
+
+proc read_start*(a2: PStream, alloc_cb: AllocProc, read_cb: ReadProc): cint{.
+    importc: "uv_read_start", header: "uv.h".}
+
+proc read_start*(a2: PStream, alloc_cb: AllocProc, read_cb: ReadProc2): cint{.
+    importc: "uv_read2_start", header: "uv.h".}
+
+proc read_stop*(a2: PStream): cint{.
+    importc: "uv_read_stop", header: "uv.h".}
+
+proc write*(req: PWrite, handle: PStream, bufs: ptr TBuf, bufcnt: cint, cb: WriteProc): cint{.
+    importc: "uv_write", header: "uv.h".}
+
+proc write*(req: PWrite, handle: PStream, bufs: ptr TBuf, bufcnt: cint, send_handle: PStream, cb: WriteProc): cint{.
+    importc: "uv_write2", header: "uv.h".}
+
+proc tcp_init*(a2: PLoop, handle: PTcp): cint{.
+    importc: "uv_tcp_init", header: "uv.h".}
+
+proc tcp_bind*(handle: PTcp, a3: SockAddrIn): cint{.
+    importc: "uv_tcp_bind", header: "uv.h".}
+
+proc tcp_bind6*(handle: PTcp, a3: TSockAddrIn6): cint{.
+    importc: "uv_tcp_bind6", header: "uv.h".}
+
+proc tcp_getsockname*(handle: PTcp, name: ptr SockAddr, namelen: var cint): cint{.
+    importc: "uv_tcp_getsockname", header: "uv.h".}
+
+proc tcp_getpeername*(handle: PTcp, name: ptr SockAddr, namelen: var cint): cint{.
+    importc: "uv_tcp_getpeername", header: "uv.h".}
+
+proc tcp_connect*(req: PConnect, handle: PTcp, address: SockAddrIn, cb: ConnectProc): cint{.
+    importc: "uv_tcp_connect", header: "uv.h".}
+
+proc tcp_connect6*(req: PConnect, handle: PTcp, address: TSockAddrIn6, cb: ConnectProc): cint{.
+    importc: "uv_tcp_connect6", header: "uv.h".}
+
+proc udp_init*(a2: PLoop, handle: PUdp): cint{.
+    importc: "uv_udp_init", header: "uv.h".}
+
+proc udp_bind*(handle: PUdp, adr: SockAddrIn, flags: cunsigned): cint{.
+    importc: "uv_udp_bind", header: "uv.h".}
+
+proc udp_bind6*(handle: PUdp, adr: TSockAddrIn6, flags: cunsigned): cint{.
+    importc: "uv_udp_bind6", header: "uv.h".}
+
+proc udp_getsockname*(handle: PUdp, name: ptr SockAddr, namelen: var cint): cint{.
+    importc: "uv_udp_getsockname", header: "uv.h".}
+
+proc udp_send*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: SockAddrIn, send_cb: UdpSendProc): cint{.
+    importc: "uv_udp_send", header: "uv.h".}
+
+proc udp_send6*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: TSockAddrIn6, send_cb: UdpSendProc): cint{.
+    importc: "uv_udp_send6", header: "uv.h".}
+
+proc udp_recv_start*(handle: PUdp, alloc_cb: AllocProc, recv_cb: UdpRecvProc): cint{.
+    importc: "uv_udp_recv_start", header: "uv.h".}
+
+proc udp_recv_stop*(handle: PUdp): cint{.
+    importc: "uv_udp_recv_stop", header: "uv.h".}
+
+proc tty_init*(a2: PLoop, a3: pTTy, fd: File): cint{.
+    importc: "uv_tty_init", header: "uv.h".}
+
+proc tty_set_mode*(a2: pTTy, mode: cint): cint{.
+    importc: "uv_tty_set_mode", header: "uv.h".}
+
+proc tty_get_winsize*(a2: pTTy, width: var cint, height: var cint): cint{.
+    importc: "uv_tty_get_winsize", header: "uv.h".}
+
+proc tty_reset_mode*() {.
+    importc: "uv_tty_reset_mode", header: "uv.h".}
+
+proc guess_handle*(file: File): THandleType{.
+    importc: "uv_guess_handle", header: "uv.h".}
+
+proc pipe_init*(a2: PLoop, handle: PPipe, ipc: int): cint{.
+    importc: "uv_pipe_init", header: "uv.h".}
+
+proc pipe_open*(a2: PPipe, file: File){.
+    importc: "uv_pipe_open", header: "uv.h".}
+
+proc pipe_bind*(handle: PPipe, name: cstring): cint{.
+    importc: "uv_pipe_bind", header: "uv.h".}
+
+proc pipe_connect*(req: PConnect, handle: PPipe, name: cstring, cb: ConnectProc): cint{.
+    importc: "uv_pipe_connect", header: "uv.h".}
+
+proc prepare_init*(a2: PLoop, prepare: PPrepare): cint{.
+    importc: "uv_prepare_init", header: "uv.h".}
+
+proc prepare_start*(prepare: PPrepare, cb: PrepareProc): cint{.
+    importc: "uv_prepare_start", header: "uv.h".}
+
+proc prepare_stop*(prepare: PPrepare): cint{.
+    importc: "uv_prepare_stop", header: "uv.h".}
+
+proc check_init*(a2: PLoop, check: PCheck): cint{.
+    importc: "uv_check_init", header: "uv.h".}
+
+proc check_start*(check: PCheck, cb: CheckProc): cint{.
+    importc: "uv_check_start", header: "uv.h".}
+
+proc check_stop*(check: PCheck): cint{.
+    importc: "uv_check_stop", header: "uv.h".}
+
+proc idle_init*(a2: PLoop, idle: PIdle): cint{.
+    importc: "uv_idle_init", header: "uv.h".}
+
+proc idle_start*(idle: PIdle, cb: IdleProc): cint{.
+    importc: "uv_idle_start", header: "uv.h".}
+
+proc idle_stop*(idle: PIdle): cint{.
+    importc: "uv_idle_stop", header: "uv.h".}
+
+proc async_init*(a2: PLoop, async: PAsync, async_cb: AsyncProc): cint{.
+    importc: "uv_async_init", header: "uv.h".}
+
+proc async_send*(async: PAsync): cint{.
+    importc: "uv_async_send", header: "uv.h".}
+
+proc timer_init*(a2: PLoop, timer: PTimer): cint{.
+    importc: "uv_timer_init", header: "uv.h".}
+
+proc timer_start*(timer: PTimer, cb: TimerProc, timeout: int64, repeat: int64): cint{.
+    importc: "uv_timer_start", header: "uv.h".}
+
+proc timer_stop*(timer: PTimer): cint{.
+    importc: "uv_timer_stop", header: "uv.h".}
+
+proc timer_again*(timer: PTimer): cint{.
+    importc: "uv_timer_again", header: "uv.h".}
+
+proc timer_set_repeat*(timer: PTimer, repeat: int64){.
+    importc: "uv_timer_set_repeat", header: "uv.h".}
+
+proc timer_get_repeat*(timer: PTimer): int64{.
+    importc: "uv_timer_get_repeat", header: "uv.h".}
+
+proc ares_init_options*(a2: PLoop, channel: PAresChannel, options: PAresOptions, optmask: cint): cint{.
+    importc: "uv_ares_init_options", header: "uv.h".}
+
+proc ares_destroy*(a2: PLoop, channel: PAresChannel){.
+    importc: "uv_ares_destroy", header: "uv.h".}
+
+proc getaddrinfo*(a2: PLoop, handle: PGetAddrInfo,getaddrinfo_cb: GetAddrInfoProc, node: cstring, service: cstring, hints: ptr AddrInfo): cint{.
+    importc: "uv_getaddrinfo", header: "uv.h".}
+
+proc freeaddrinfo*(ai: ptr AddrInfo){.
+    importc: "uv_freeaddrinfo", header: "uv.h".}
+
+proc spawn*(a2: PLoop, a3: PProcess, options: TProcessOptions): cint{.
+    importc: "uv_spawn", header: "uv.h".}
+
+proc process_kill*(a2: PProcess, signum: cint): cint{.
+    importc: "uv_process_kill", header: "uv.h".}
+
+proc queue_work*(loop: PLoop, req: PWork, work_cb: WorkProc, after_work_cb: AfterWorkProc): cint{.
+    importc: "uv_queue_work", header: "uv.h".}
+
+proc req_cleanup*(req: PFS){.
+    importc: "uv_fs_req_cleanup", header: "uv.h".}
+
+proc close*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
+    importc: "uv_fs_close", header: "uv.h".}
+
+proc open*(loop: PLoop, req: PFS, path: cstring, flags: cint, mode: cint, cb: FsProc): cint{.
+    importc: "uv_fs_open", header: "uv.h".}
+
+proc read*(loop: PLoop, req: PFS, file: File, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{.
+    importc: "uv_fs_read", header: "uv.h".}
+
+proc unlink*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_unlink", header: "uv.h".}
+
+proc write*(loop: PLoop, req: PFS, file: File, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{.
+    importc: "uv_fs_write", header: "uv.h".}
+
+proc mkdir*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{.
+    importc: "uv_fs_mkdir", header: "uv.h".}
+
+proc rmdir*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_rmdir", header: "uv.h".}
+
+proc readdir*(loop: PLoop, req: PFS, path: cstring, flags: cint, cb: FsProc): cint{.
+    importc: "uv_fs_readdir", header: "uv.h".}
+
+proc stat*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_stat", header: "uv.h".}
+
+proc fstat*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
+    importc: "uv_fs_fstat", header: "uv.h".}
+
+proc rename*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_rename", header: "uv.h".}
+
+proc fsync*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
+    importc: "uv_fs_fsync", header: "uv.h".}
+
+proc fdatasync*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{.
+    importc: "uv_fs_fdatasync", header: "uv.h".}
+
+proc ftruncate*(loop: PLoop, req: PFS, file: File, offset: coff, cb: FsProc): cint{.
+    importc: "uv_fs_ftruncate", header: "uv.h".}
+
+proc sendfile*(loop: PLoop, req: PFS, out_fd: File, in_fd: File, in_offset: coff, length: csize, cb: FsProc): cint{.
+    importc: "uv_fs_sendfile", header: "uv.h".}
+
+proc chmod*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{.
+    importc: "uv_fs_chmod", header: "uv.h".}
+
+proc utime*(loop: PLoop, req: PFS, path: cstring, atime: cdouble, mtime: cdouble, cb: FsProc): cint{.
+    importc: "uv_fs_utime", header: "uv.h".}
+
+proc futime*(loop: PLoop, req: PFS, file: File, atime: cdouble, mtime: cdouble, cb: FsProc): cint{.
+    importc: "uv_fs_futime", header: "uv.h".}
+
+proc lstat*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_lstat", header: "uv.h".}
+
+proc link*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_link", header: "uv.h".}
+
+proc symlink*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, flags: cint, cb: FsProc): cint{.
+    importc: "uv_fs_symlink", header: "uv.h".}
+
+proc readlink*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{.
+    importc: "uv_fs_readlink", header: "uv.h".}
+
+proc fchmod*(loop: PLoop, req: PFS, file: File, mode: cint, cb: FsProc): cint{.
+    importc: "uv_fs_fchmod", header: "uv.h".}
+
+proc chown*(loop: PLoop, req: PFS, path: cstring, uid: cint, gid: cint, cb: FsProc): cint{.
+    importc: "uv_fs_chown", header: "uv.h".}
+
+proc fchown*(loop: PLoop, req: PFS, file: File, uid: cint, gid: cint, cb: FsProc): cint{.
+    importc: "uv_fs_fchown", header: "uv.h".}
+
+proc event_init*(loop: PLoop, handle: PFSEvent, filename: cstring, cb: FsEventProc): cint{.
+    importc: "uv_fs_event_init", header: "uv.h".}
+
+proc ip4_addr*(ip: cstring, port: cint): SockAddrIn{.
+    importc: "uv_ip4_addr", header: "uv.h".}
+
+proc ip6_addr*(ip: cstring, port: cint): TSockAddrIn6{.
+    importc: "uv_ip6_addr", header: "uv.h".}
+
+proc ip4_name*(src: ptr SockAddrIn, dst: cstring, size: csize): cint{.
+    importc: "uv_ip4_name", header: "uv.h".}
+
+proc ip6_name*(src: ptr TSockAddrIn6, dst: cstring, size: csize): cint{.
+    importc: "uv_ip6_name", header: "uv.h".}
+
+proc exepath*(buffer: cstring, size: var csize): cint{.
+    importc: "uv_exepath", header: "uv.h".}
+
+proc hrtime*(): uint64{.
+    importc: "uv_hrtime", header: "uv.h".}
+
+proc loadavg*(load: var array[0..2, cdouble]) {.
+    importc: "uv_loadavg", header: "uv.h"}
+
+proc get_free_memory*(): cdouble {.
+    importc: "uv_get_free_memory", header: "uv.h".}
+
+proc get_total_memory*(): cdouble {.
+    importc: "uv_get_total_memory", header: "uv.h".}
+
diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim
new file mode 100644
index 000000000..937a8952a
--- /dev/null
+++ b/lib/wrappers/mysql.nim
@@ -0,0 +1,1081 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim: on.}
+{.push, callconv: cdecl.}
+
+when defined(Unix):
+  when defined(macosx):
+    const
+      lib = "libmysqlclient.(15|16|17|18).dylib"
+  else:
+    const
+      lib = "libmysqlclient.so.(15|16|17|18)"
+when defined(Windows):
+  const
+    lib = "libmysql.dll"
+type 
+  my_bool* = bool
+  Pmy_bool* = ptr my_bool
+  PVIO* = pointer
+  Pgptr* = ptr gptr
+  gptr* = cstring
+  Pmy_socket* = ptr my_socket
+  my_socket* = cint
+  PPByte* = pointer
+  cuint* = cint
+
+#  ------------ Start of declaration in "mysql_com.h"   ---------------------  
+#
+#  ** Common definition between mysql server & client
+#   
+# Field/table name length
+
+const 
+  NAME_LEN* = 64
+  HOSTNAME_LENGTH* = 60
+  USERNAME_LENGTH* = 16
+  SERVER_VERSION_LENGTH* = 60
+  SQLSTATE_LENGTH* = 5
+  LOCAL_HOST* = "localhost"
+  LOCAL_HOST_NAMEDPIPE* = '.'
+
+const 
+  NAMEDPIPE* = "MySQL"
+  SERVICENAME* = "MySQL"
+
+type 
+  Tenum_server_command* = enum 
+    COM_SLEEP, COM_QUIT, COM_INIT_DB, COM_QUERY, COM_FIELD_LIST, COM_CREATE_DB, 
+    COM_DROP_DB, COM_REFRESH, COM_SHUTDOWN, COM_STATISTICS, COM_PROCESS_INFO, 
+    COM_CONNECT, COM_PROCESS_KILL, COM_DEBUG, COM_PING, COM_TIME, 
+    COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TABLE_DUMP, 
+    COM_CONNECT_OUT, COM_REGISTER_SLAVE, COM_STMT_PREPARE, COM_STMT_EXECUTE, 
+    COM_STMT_SEND_LONG_DATA, COM_STMT_CLOSE, COM_STMT_RESET, COM_SET_OPTION, 
+    COM_STMT_FETCH, COM_END
+
+const 
+  SCRAMBLE_LENGTH* = 20 # Length of random string sent by server on handshake; 
+                        # this is also length of obfuscated password, 
+                        # received from client
+  SCRAMBLE_LENGTH_323* = 8    # length of password stored in the db: 
+                              # new passwords are preceded with '*'  
+  SCRAMBLED_PASSWORD_CHAR_LENGTH* = SCRAMBLE_LENGTH * 2 + 1
+  SCRAMBLED_PASSWORD_CHAR_LENGTH_323* = SCRAMBLE_LENGTH_323 * 2
+  NOT_NULL_FLAG* = 1          #  Field can't be NULL
+  PRI_KEY_FLAG* = 2           #  Field is part of a primary key
+  UNIQUE_KEY_FLAG* = 4        #  Field is part of a unique key
+  MULTIPLE_KEY_FLAG* = 8      #  Field is part of a key
+  BLOB_FLAG* = 16             #  Field is a blob
+  UNSIGNED_FLAG* = 32         #  Field is unsigned
+  ZEROFILL_FLAG* = 64         #  Field is zerofill
+  BINARY_FLAG* = 128          #  Field is binary
+                              # The following are only sent to new clients  
+  ENUM_FLAG* = 256            # field is an enum
+  AUTO_INCREMENT_FLAG* = 512  # field is a autoincrement field
+  TIMESTAMP_FLAG* = 1024      # Field is a timestamp
+  SET_FLAG* = 2048            # field is a set
+  NO_DEFAULT_VALUE_FLAG* = 4096 # Field doesn't have default value
+  NUM_FLAG* = 32768           # Field is num (for clients)
+  PART_KEY_FLAG* = 16384      # Intern; Part of some key
+  GROUP_FLAG* = 32768         # Intern: Group field
+  UNIQUE_FLAG* = 65536        # Intern: Used by sql_yacc
+  BINCMP_FLAG* = 131072       # Intern: Used by sql_yacc
+  REFRESH_GRANT* = 1          # Refresh grant tables
+  REFRESH_LOG* = 2            # Start on new log file
+  REFRESH_TABLES* = 4         # close all tables
+  REFRESH_HOSTS* = 8          # Flush host cache
+  REFRESH_STATUS* = 16        # Flush status variables
+  REFRESH_THREADS* = 32       # Flush thread cache
+  REFRESH_SLAVE* = 64         # Reset master info and restart slave thread
+  REFRESH_MASTER* = 128 # Remove all bin logs in the index and truncate the index
+                        # The following can't be set with mysql_refresh()  
+  REFRESH_READ_LOCK* = 16384  # Lock tables for read
+  REFRESH_FAST* = 32768       # Intern flag
+  REFRESH_QUERY_CACHE* = 65536 # RESET (remove all queries) from query cache
+  REFRESH_QUERY_CACHE_FREE* = 0x00020000 # pack query cache
+  REFRESH_DES_KEY_FILE* = 0x00040000
+  REFRESH_USER_RESOURCES* = 0x00080000
+  CLIENT_LONG_PASSWORD* = 1   # new more secure passwords
+  CLIENT_FOUND_ROWS* = 2      # Found instead of affected rows
+  CLIENT_LONG_FLAG* = 4       # Get all column flags
+  CLIENT_CONNECT_WITH_DB* = 8 # One can specify db on connect
+  CLIENT_NO_SCHEMA* = 16      # Don't allow database.table.column
+  CLIENT_COMPRESS* = 32       # Can use compression protocol
+  CLIENT_ODBC* = 64           # Odbc client
+  CLIENT_LOCAL_FILES* = 128   # Can use LOAD DATA LOCAL
+  CLIENT_IGNORE_SPACE* = 256  # Ignore spaces before '('
+  CLIENT_PROTOCOL_41* = 512   # New 4.1 protocol
+  CLIENT_INTERACTIVE* = 1024  # This is an interactive client
+  CLIENT_SSL* = 2048          # Switch to SSL after handshake
+  CLIENT_IGNORE_SIGPIPE* = 4096 # IGNORE sigpipes
+  CLIENT_TRANSACTIONS* = 8192 # Client knows about transactions
+  CLIENT_RESERVED* = 16384    # Old flag for 4.1 protocol
+  CLIENT_SECURE_CONNECTION* = 32768 # New 4.1 authentication
+  CLIENT_MULTI_STATEMENTS* = 65536 # Enable/disable multi-stmt support
+  CLIENT_MULTI_RESULTS* = 131072 # Enable/disable multi-results
+  CLIENT_REMEMBER_OPTIONS*: int = 1 shl 31
+  SERVER_STATUS_IN_TRANS* = 1 # Transaction has started
+  SERVER_STATUS_AUTOCOMMIT* = 2 # Server in auto_commit mode
+  SERVER_STATUS_MORE_RESULTS* = 4 # More results on server
+  SERVER_MORE_RESULTS_EXISTS* = 8 # Multi query - next query exists
+  SERVER_QUERY_NO_GOOD_INDEX_USED* = 16
+  SERVER_QUERY_NO_INDEX_USED* = 32 # The server was able to fulfill the clients request and opened a
+                                   #      read-only non-scrollable cursor for a query. This flag comes
+                                   #      in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. 
+  SERVER_STATUS_CURSOR_EXISTS* = 64 # This flag is sent when a read-only cursor is exhausted, in reply to
+                                    #      COM_STMT_FETCH command. 
+  SERVER_STATUS_LAST_ROW_SENT* = 128
+  SERVER_STATUS_DB_DROPPED* = 256 # A database was dropped
+  SERVER_STATUS_NO_BACKSLASH_ESCAPES* = 512
+  ERRMSG_SIZE* = 200
+  NET_READ_TIMEOUT* = 30      # Timeout on read
+  NET_WRITE_TIMEOUT* = 60     # Timeout on write
+  NET_WAIT_TIMEOUT* = 8 * 60 * 60 # Wait for new query
+  ONLY_KILL_QUERY* = 1
+
+const 
+  MAX_TINYINT_WIDTH* = 3      # Max width for a TINY w.o. sign
+  MAX_SMALLINT_WIDTH* = 5     # Max width for a SHORT w.o. sign
+  MAX_MEDIUMINT_WIDTH* = 8    # Max width for a INT24 w.o. sign
+  MAX_INT_WIDTH* = 10         # Max width for a LONG w.o. sign
+  MAX_BIGINT_WIDTH* = 20      # Max width for a LONGLONG
+  MAX_CHAR_WIDTH* = 255       # Max length for a CHAR column
+  MAX_BLOB_WIDTH* = 8192      # Default width for blob
+
+type 
+  Pst_net* = ptr Tst_net
+  Tst_net*{.final.} = object 
+    vio*: PVio
+    buff*: cstring
+    buff_end*: cstring
+    write_pos*: cstring
+    read_pos*: cstring
+    fd*: my_socket            # For Perl DBI/dbd
+    max_packet*: int
+    max_packet_size*: int
+    pkt_nr*: cuint
+    compress_pkt_nr*: cuint
+    write_timeout*: cuint
+    read_timeout*: cuint
+    retry_count*: cuint
+    fcntl*: cint
+    compress*: my_bool #   The following variable is set if we are doing several queries in one
+                       #        command ( as in LOAD TABLE ... FROM MASTER ),
+                       #        and do not want to confuse the client with OK at the wrong time 
+    remain_in_buf*: int
+    len*: int
+    buf_length*: int
+    where_b*: int
+    return_status*: ptr cint
+    reading_or_writing*: char
+    save_char*: cchar
+    no_send_ok*: my_bool      # For SPs and other things that do multiple stmts
+    no_send_eof*: my_bool     # For SPs' first version read-only cursors
+    no_send_error*: my_bool # Set if OK packet is already sent, and
+                            # we do not need to send error messages
+                            #   Pointer to query object in query cache, do not equal NULL (0) for
+                            #        queries in cache that have not stored its results yet 
+                            # $endif
+    last_error*: array[0..(ERRMSG_SIZE) - 1, char]
+    sqlstate*: array[0..(SQLSTATE_LENGTH + 1) - 1, char]
+    last_errno*: cuint
+    error*: char
+    query_cache_query*: gptr
+    report_error*: my_bool    # We should report error (we have unreported error)
+    return_errno*: my_bool
+
+  TNET* = Tst_net
+  PNET* = ptr TNET
+
+const 
+  packet_error* = - 1
+
+type 
+  Tenum_field_types* = enum    # For backward compatibility  
+    TYPE_DECIMAL, TYPE_TINY, TYPE_SHORT, TYPE_LONG, TYPE_FLOAT, TYPE_DOUBLE, 
+    TYPE_NULL, TYPE_TIMESTAMP, TYPE_LONGLONG, TYPE_INT24, TYPE_DATE, TYPE_TIME, 
+    TYPE_DATETIME, TYPE_YEAR, TYPE_NEWDATE, TYPE_VARCHAR, TYPE_BIT, 
+    TYPE_NEWDECIMAL = 246, TYPE_ENUM = 247, TYPE_SET = 248, 
+    TYPE_TINY_BLOB = 249, TYPE_MEDIUM_BLOB = 250, TYPE_LONG_BLOB = 251, 
+    TYPE_BLOB = 252, TYPE_VAR_STRING = 253, TYPE_STRING = 254, 
+    TYPE_GEOMETRY = 255
+
+const 
+  CLIENT_MULTI_QUERIES* = CLIENT_MULTI_STATEMENTS
+  FIELD_TYPE_DECIMAL* = TYPE_DECIMAL
+  FIELD_TYPE_NEWDECIMAL* = TYPE_NEWDECIMAL
+  FIELD_TYPE_TINY* = TYPE_TINY
+  FIELD_TYPE_SHORT* = TYPE_SHORT
+  FIELD_TYPE_LONG* = TYPE_LONG
+  FIELD_TYPE_FLOAT* = TYPE_FLOAT
+  FIELD_TYPE_DOUBLE* = TYPE_DOUBLE
+  FIELD_TYPE_NULL* = TYPE_NULL
+  FIELD_TYPE_TIMESTAMP* = TYPE_TIMESTAMP
+  FIELD_TYPE_LONGLONG* = TYPE_LONGLONG
+  FIELD_TYPE_INT24* = TYPE_INT24
+  FIELD_TYPE_DATE* = TYPE_DATE
+  FIELD_TYPE_TIME* = TYPE_TIME
+  FIELD_TYPE_DATETIME* = TYPE_DATETIME
+  FIELD_TYPE_YEAR* = TYPE_YEAR
+  FIELD_TYPE_NEWDATE* = TYPE_NEWDATE
+  FIELD_TYPE_ENUM* = TYPE_ENUM
+  FIELD_TYPE_SET* = TYPE_SET
+  FIELD_TYPE_TINY_BLOB* = TYPE_TINY_BLOB
+  FIELD_TYPE_MEDIUM_BLOB* = TYPE_MEDIUM_BLOB
+  FIELD_TYPE_LONG_BLOB* = TYPE_LONG_BLOB
+  FIELD_TYPE_BLOB* = TYPE_BLOB
+  FIELD_TYPE_VAR_STRING* = TYPE_VAR_STRING
+  FIELD_TYPE_STRING* = TYPE_STRING
+  FIELD_TYPE_CHAR* = TYPE_TINY
+  FIELD_TYPE_INTERVAL* = TYPE_ENUM
+  FIELD_TYPE_GEOMETRY* = TYPE_GEOMETRY
+  FIELD_TYPE_BIT* = TYPE_BIT  # Shutdown/kill enums and constants  
+                              # Bits for THD::killable.  
+  SHUTDOWN_KILLABLE_CONNECT* = chr(1 shl 0)
+  SHUTDOWN_KILLABLE_TRANS* = chr(1 shl 1)
+  SHUTDOWN_KILLABLE_LOCK_TABLE* = chr(1 shl 2)
+  SHUTDOWN_KILLABLE_UPDATE* = chr(1 shl 3)
+
+type 
+  Tenum_shutdown_level* = enum 
+    SHUTDOWN_DEFAULT = 0, SHUTDOWN_WAIT_CONNECTIONS = 1, 
+    SHUTDOWN_WAIT_TRANSACTIONS = 2, SHUTDOWN_WAIT_UPDATES = 8, 
+    SHUTDOWN_WAIT_ALL_BUFFERS = 16, SHUTDOWN_WAIT_CRITICAL_BUFFERS = 17, 
+    KILL_QUERY = 254, KILL_CONNECTION = 255
+  Tenum_cursor_type* = enum    # options for mysql_set_option  
+    CURSOR_TYPE_NO_CURSOR = 0, CURSOR_TYPE_READ_ONLY = 1, 
+    CURSOR_TYPE_FOR_UPDATE = 2, CURSOR_TYPE_SCROLLABLE = 4
+  Tenum_mysql_set_option* = enum 
+    OPTION_MULTI_STATEMENTS_ON, OPTION_MULTI_STATEMENTS_OFF
+
+proc my_net_init*(net: PNET, vio: PVio): my_bool{.cdecl, dynlib: lib, 
+    importc: "my_net_init".}
+proc my_net_local_init*(net: PNET){.cdecl, dynlib: lib, 
+                                    importc: "my_net_local_init".}
+proc net_end*(net: PNET){.cdecl, dynlib: lib, importc: "net_end".}
+proc net_clear*(net: PNET){.cdecl, dynlib: lib, importc: "net_clear".}
+proc net_realloc*(net: PNET, len: int): my_bool{.cdecl, dynlib: lib, 
+    importc: "net_realloc".}
+proc net_flush*(net: PNET): my_bool{.cdecl, dynlib: lib, importc: "net_flush".}
+proc my_net_write*(net: PNET, packet: cstring, length: int): my_bool{.cdecl, 
+    dynlib: lib, importc: "my_net_write".}
+proc net_write_command*(net: PNET, command: char, header: cstring, 
+                        head_len: int, packet: cstring, length: int): my_bool{.
+    cdecl, dynlib: lib, importc: "net_write_command".}
+proc net_real_write*(net: PNET, packet: cstring, length: int): cint{.cdecl, 
+    dynlib: lib, importc: "net_real_write".}
+proc my_net_read*(net: PNET): int{.cdecl, dynlib: lib, importc: "my_net_read".}
+  # The following function is not meant for normal usage
+  #      Currently it's used internally by manager.c  
+type 
+  Psockaddr* = ptr Tsockaddr
+  Tsockaddr*{.final.} = object  # undefined structure
+
+proc my_connect*(s: my_socket, name: Psockaddr, namelen: cuint, timeout: cuint): cint{.
+    cdecl, dynlib: lib, importc: "my_connect".}
+type 
+  Prand_struct* = ptr Trand_struct
+  Trand_struct*{.final.} = object # The following is for user defined functions  
+    seed1*: int
+    seed2*: int
+    max_value*: int
+    max_value_dbl*: cdouble
+
+  TItem_result* = enum 
+    STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT
+  PItem_result* = ptr TItem_result
+  Pst_udf_args* = ptr Tst_udf_args
+  Tst_udf_args*{.final.} = object 
+    arg_count*: cuint         # Number of arguments
+    arg_type*: PItem_result   # Pointer to item_results
+    args*: cstringArray       # Pointer to item_results
+    lengths*: ptr int         # Length of string arguments
+    maybe_null*: cstring      # Length of string arguments
+    attributes*: cstringArray # Pointer to attribute name
+    attribute_lengths*: ptr int # Length of attribute arguments
+  
+  TUDF_ARGS* = Tst_udf_args
+  PUDF_ARGS* = ptr TUDF_ARGS   # This holds information about the result  
+  Pst_udf_init* = ptr Tst_udf_init
+  Tst_udf_init*{.final.} = object 
+    maybe_null*: my_bool      # 1 if function can return NULL
+    decimals*: cuint          # for real functions
+    max_length*: int          # For string functions
+    theptr*: cstring          # free pointer for function data
+    const_item*: my_bool      # free pointer for function data
+  
+  TUDF_INIT* = Tst_udf_init
+  PUDF_INIT* = ptr TUDF_INIT   # Constants when using compression  
+
+const 
+  NET_HEADER_SIZE* = 4        # standard header size
+  COMP_HEADER_SIZE* = 3 # compression header extra size
+                        # Prototypes to password functions  
+                        # These functions are used for authentication by client and server and
+                        #      implemented in sql/password.c     
+
+proc randominit*(para1: Prand_struct, seed1: int, seed2: int){.cdecl, 
+    dynlib: lib, importc: "randominit".}
+proc my_rnd*(para1: Prand_struct): cdouble{.cdecl, dynlib: lib, 
+    importc: "my_rnd".}
+proc create_random_string*(fto: cstring, len: cuint, rand_st: Prand_struct){.
+    cdecl, dynlib: lib, importc: "create_random_string".}
+proc hash_password*(fto: int, password: cstring, password_len: cuint){.cdecl, 
+    dynlib: lib, importc: "hash_password".}
+proc make_scrambled_password_323*(fto: cstring, password: cstring){.cdecl, 
+    dynlib: lib, importc: "make_scrambled_password_323".}
+proc scramble_323*(fto: cstring, message: cstring, password: cstring){.cdecl, 
+    dynlib: lib, importc: "scramble_323".}
+proc check_scramble_323*(para1: cstring, message: cstring, salt: int): my_bool{.
+    cdecl, dynlib: lib, importc: "check_scramble_323".}
+proc get_salt_from_password_323*(res: ptr int, password: cstring){.cdecl, 
+    dynlib: lib, importc: "get_salt_from_password_323".}
+proc make_password_from_salt_323*(fto: cstring, salt: ptr int){.cdecl, 
+    dynlib: lib, importc: "make_password_from_salt_323".}
+proc octet2hex*(fto: cstring, str: cstring, length: cuint): cstring{.cdecl, 
+    dynlib: lib, importc: "octet2hex".}
+proc make_scrambled_password*(fto: cstring, password: cstring){.cdecl, 
+    dynlib: lib, importc: "make_scrambled_password".}
+proc scramble*(fto: cstring, message: cstring, password: cstring){.cdecl, 
+    dynlib: lib, importc: "scramble".}
+proc check_scramble*(reply: cstring, message: cstring, hash_stage2: pointer): my_bool{.
+    cdecl, dynlib: lib, importc: "check_scramble".}
+proc get_salt_from_password*(res: pointer, password: cstring){.cdecl, 
+    dynlib: lib, importc: "get_salt_from_password".}
+proc make_password_from_salt*(fto: cstring, hash_stage2: pointer){.cdecl, 
+    dynlib: lib, importc: "make_password_from_salt".}
+  # end of password.c  
+proc get_tty_password*(opt_message: cstring): cstring{.cdecl, dynlib: lib, 
+    importc: "get_tty_password".}
+proc errno_to_sqlstate*(errno: cuint): cstring{.cdecl, dynlib: lib, 
+    importc: "mysql_errno_to_sqlstate".}
+  # Some other useful functions  
+proc modify_defaults_file*(file_location: cstring, option: cstring, 
+                           option_value: cstring, section_name: cstring, 
+                           remove_option: cint): cint{.cdecl, dynlib: lib, 
+    importc: "load_defaults".}
+proc load_defaults*(conf_file: cstring, groups: cstringArray, argc: ptr cint, 
+                    argv: ptr cstringArray): cint{.cdecl, dynlib: lib, 
+    importc: "load_defaults".}
+proc my_init*(): my_bool{.cdecl, dynlib: lib, importc: "my_init".}
+proc my_thread_init*(): my_bool{.cdecl, dynlib: lib, importc: "my_thread_init".}
+proc my_thread_end*(){.cdecl, dynlib: lib, importc: "my_thread_end".}
+const 
+  NULL_LENGTH*: int = int(not (0)) # For net_store_length
+
+const 
+  STMT_HEADER* = 4
+  LONG_DATA_HEADER* = 6 #  ------------ Stop of declaration in "mysql_com.h"   -----------------------  
+                        # $include "mysql_time.h"
+                        # $include "mysql_version.h"
+                        # $include "typelib.h"
+                        # $include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */
+                        #      var
+                        #         mysql_port : cuint;cvar;external;
+                        #         mysql_unix_port : Pchar;cvar;external;
+
+const 
+  CLIENT_NET_READ_TIMEOUT* = 365 * 24 * 3600 # Timeout on read
+  CLIENT_NET_WRITE_TIMEOUT* = 365 * 24 * 3600 # Timeout on write
+
+type 
+  Pst_mysql_field* = ptr Tst_mysql_field
+  Tst_mysql_field*{.final.} = object 
+    name*: cstring            # Name of column
+    org_name*: cstring        # Original column name, if an alias
+    table*: cstring           # Table of column if column was a field
+    org_table*: cstring       # Org table name, if table was an alias
+    db*: cstring              # Database for table
+    catalog*: cstring         # Catalog for table
+    def*: cstring             # Default value (set by mysql_list_fields)
+    len*: int                 # Width of column (create length)
+    max_length*: int          # Max width for selected set
+    name_length*: cuint
+    org_name_length*: cuint
+    table_length*: cuint
+    org_table_length*: cuint
+    db_length*: cuint
+    catalog_length*: cuint
+    def_length*: cuint
+    flags*: cuint             # Div flags
+    decimals*: cuint          # Number of decimals in field
+    charsetnr*: cuint         # Character set
+    ftype*: Tenum_field_types  # Type of field. See mysql_com.h for types
+  
+  TFIELD* = Tst_mysql_field
+  PFIELD* = ptr TFIELD
+  PROW* = ptr TROW             # return data as array of strings
+  TROW* = cstringArray
+  PFIELD_OFFSET* = ptr TFIELD_OFFSET # offset to current field
+  TFIELD_OFFSET* = cuint
+
+proc IS_PRI_KEY*(n: int32): bool
+proc IS_NOT_NULL*(n: int32): bool
+proc IS_BLOB*(n: int32): bool
+proc IS_NUM*(t: Tenum_field_types): bool
+proc INTERNAL_NUM_FIELD*(f: Pst_mysql_field): bool
+proc IS_NUM_FIELD*(f: Pst_mysql_field): bool
+type 
+  my_ulonglong* = int64
+  Pmy_ulonglong* = ptr my_ulonglong
+
+const 
+  COUNT_ERROR* = not (my_ulonglong(0))
+
+type 
+  Pst_mysql_rows* = ptr Tst_mysql_rows
+  Tst_mysql_rows*{.final.} = object 
+    next*: Pst_mysql_rows     # list of rows
+    data*: TROW
+    len*: int
+
+  TROWS* = Tst_mysql_rows
+  PROWS* = ptr TROWS
+  PROW_OFFSET* = ptr TROW_OFFSET # offset to current row
+  TROW_OFFSET* = TROWS 
+  
+const 
+  ALLOC_MAX_BLOCK_TO_DROP* = 4096
+  ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP* = 10 # struct for once_alloc (block)  
+
+type 
+  Pst_used_mem* = ptr Tst_used_mem
+  Tst_used_mem*{.final.} = object 
+    next*: Pst_used_mem       # Next block in use
+    left*: cuint              # memory left in block
+    size*: cuint              # size of block
+  
+  TUSED_MEM* = Tst_used_mem
+  PUSED_MEM* = ptr TUSED_MEM
+  Pst_mem_root* = ptr Tst_mem_root
+  Tst_mem_root*{.final.} = object 
+    free*: PUSED_MEM          # blocks with free memory in it
+    used*: PUSED_MEM          # blocks almost without free memory
+    pre_alloc*: PUSED_MEM     # preallocated block
+    min_malloc*: cuint        # if block have less memory it will be put in 'used' list
+    block_size*: cuint        # initial block size
+    block_num*: cuint # allocated blocks counter
+                      #    first free block in queue test counter (if it exceed
+                      #       MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list)     
+    first_block_usage*: cuint
+    error_handler*: proc (){.cdecl.}
+
+  TMEM_ROOT* = Tst_mem_root
+  PMEM_ROOT* = ptr TMEM_ROOT   #  ------------ Stop of declaration in "my_alloc.h"    ----------------------  
+
+type 
+  Pst_mysql_data* = ptr Tst_mysql_data
+  Tst_mysql_data*{.final.} = object 
+    rows*: my_ulonglong
+    fields*: cuint
+    data*: PROWS
+    alloc*: TMEM_ROOT
+    prev_ptr*: ptr PROWS
+
+  TDATA* = Tst_mysql_data
+  PDATA* = ptr TDATA
+  Toption* = enum 
+    OPT_CONNECT_TIMEOUT, OPT_COMPRESS, OPT_NAMED_PIPE, INIT_COMMAND, 
+    READ_DEFAULT_FILE, READ_DEFAULT_GROUP, SET_CHARSET_DIR, SET_CHARSET_NAME, 
+    OPT_LOCAL_INFILE, OPT_PROTOCOL, SHARED_MEMORY_BASE_NAME, OPT_READ_TIMEOUT, 
+    OPT_WRITE_TIMEOUT, OPT_USE_RESULT, OPT_USE_REMOTE_CONNECTION, 
+    OPT_USE_EMBEDDED_CONNECTION, OPT_GUESS_CONNECTION, SET_CLIENT_IP, 
+    SECURE_AUTH, REPORT_DATA_TRUNCATION, OPT_RECONNECT
+
+const 
+  MAX_MYSQL_MANAGER_ERR* = 256
+  MAX_MYSQL_MANAGER_MSG* = 256
+  MANAGER_OK* = 200
+  MANAGER_INFO* = 250
+  MANAGER_ACCESS* = 401
+  MANAGER_CLIENT_ERR* = 450
+  MANAGER_INTERNAL_ERR* = 500
+
+type 
+  Tst_dynamic_array*{.final.} = object 
+    buffer*: cstring
+    elements*: cuint
+    max_element*: cuint
+    alloc_increment*: cuint
+    size_of_element*: cuint
+
+  TDYNAMIC_ARRAY* = Tst_dynamic_array
+  Pst_dynamic_array* = ptr Tst_dynamic_array
+  Pst_mysql_options* = ptr Tst_mysql_options
+  Tst_mysql_options*{.final.} = object 
+    connect_timeout*: cuint
+    read_timeout*: cuint
+    write_timeout*: cuint
+    port*: cuint
+    protocol*: cuint
+    client_flag*: int
+    host*: cstring
+    user*: cstring
+    password*: cstring
+    unix_socket*: cstring
+    db*: cstring
+    init_commands*: Pst_dynamic_array
+    my_cnf_file*: cstring
+    my_cnf_group*: cstring
+    charset_dir*: cstring
+    charset_name*: cstring
+    ssl_key*: cstring         # PEM key file
+    ssl_cert*: cstring        # PEM cert file
+    ssl_ca*: cstring          # PEM CA file
+    ssl_capath*: cstring      # PEM directory of CA-s?
+    ssl_cipher*: cstring      # cipher to use
+    shared_memory_base_name*: cstring
+    max_allowed_packet*: int
+    use_ssl*: my_bool         # if to use SSL or not
+    compress*: my_bool
+    named_pipe*: my_bool #  On connect, find out the replication role of the server, and
+                         #       establish connections to all the peers  
+    rpl_probe*: my_bool #  Each call to mysql_real_query() will parse it to tell if it is a read
+                        #       or a write, and direct it to the slave or the master      
+    rpl_parse*: my_bool #  If set, never read from a master, only from slave, when doing
+                        #       a read that is replication-aware    
+    no_master_reads*: my_bool
+    separate_thread*: my_bool
+    methods_to_use*: Toption
+    client_ip*: cstring
+    secure_auth*: my_bool     # Refuse client connecting to server if it uses old (pre-4.1.1) protocol
+    report_data_truncation*: my_bool # 0 - never report, 1 - always report (default)
+                                     # function pointers for local infile support  
+    local_infile_init*: proc (para1: var pointer, para2: cstring, para3: pointer): cint{.
+        cdecl.}
+    local_infile_read*: proc (para1: pointer, para2: cstring, para3: cuint): cint
+    local_infile_end*: proc (para1: pointer)
+    local_infile_error*: proc (para1: pointer, para2: cstring, para3: cuint): cint
+    local_infile_userdata*: pointer
+
+  Tstatus* = enum 
+    STATUS_READY, STATUS_GET_RESULT, STATUS_USE_RESULT
+  Tprotocol_type* = enum  # There are three types of queries - the ones that have to go to
+                          # the master, the ones that go to a slave, and the administrative
+                          # type which must happen on the pivot connectioin 
+    PROTOCOL_DEFAULT, PROTOCOL_TCP, PROTOCOL_SOCKET, PROTOCOL_PIPE, 
+    PROTOCOL_MEMORY
+  Trpl_type* = enum 
+    RPL_MASTER, RPL_SLAVE, RPL_ADMIN
+  Tcharset_info_st*{.final.} = object 
+    number*: cuint
+    primary_number*: cuint
+    binary_number*: cuint
+    state*: cuint
+    csname*: cstring
+    name*: cstring
+    comment*: cstring
+    tailoring*: cstring
+    ftype*: cstring
+    to_lower*: cstring
+    to_upper*: cstring
+    sort_order*: cstring
+    contractions*: ptr int16
+    sort_order_big*: ptr ptr int16
+    tab_to_uni*: ptr int16
+    tab_from_uni*: pointer    # was ^MY_UNI_IDX
+    state_map*: cstring
+    ident_map*: cstring
+    strxfrm_multiply*: cuint
+    mbminlen*: cuint
+    mbmaxlen*: cuint
+    min_sort_char*: int16
+    max_sort_char*: int16
+    escape_with_backslash_is_dangerous*: my_bool
+    cset*: pointer            # was ^MY_CHARSET_HANDLER
+    coll*: pointer            # was ^MY_COLLATION_HANDLER;
+  
+  TCHARSET_INFO* = Tcharset_info_st
+  Pcharset_info_st* = ptr Tcharset_info_st
+  Pcharacter_set* = ptr Tcharacter_set
+  Tcharacter_set*{.final.} = object 
+    number*: cuint
+    state*: cuint
+    csname*: cstring
+    name*: cstring
+    comment*: cstring
+    dir*: cstring
+    mbminlen*: cuint
+    mbmaxlen*: cuint
+
+  TMY_CHARSET_INFO* = Tcharacter_set
+  PMY_CHARSET_INFO* = ptr TMY_CHARSET_INFO
+  Pst_mysql_methods* = ptr Tst_mysql_methods
+  Pst_mysql* = ptr Tst_mysql
+  Tst_mysql*{.final.} = object 
+    net*: TNET                 # Communication parameters
+    connector_fd*: gptr       # ConnectorFd for SSL
+    host*: cstring
+    user*: cstring
+    passwd*: cstring
+    unix_socket*: cstring
+    server_version*: cstring
+    host_info*: cstring
+    info*: cstring
+    db*: cstring
+    charset*: Pcharset_info_st
+    fields*: PFIELD
+    field_alloc*: TMEM_ROOT
+    affected_rows*: my_ulonglong
+    insert_id*: my_ulonglong  # id if insert on table with NEXTNR
+    extra_info*: my_ulonglong # Used by mysqlshow, not used by mysql 5.0 and up
+    thread_id*: int           # Id for connection in server
+    packet_length*: int
+    port*: cuint
+    client_flag*: int
+    server_capabilities*: int
+    protocol_version*: cuint
+    field_count*: cuint
+    server_status*: cuint
+    server_language*: cuint
+    warning_count*: cuint
+    options*: Tst_mysql_options
+    status*: Tstatus
+    free_me*: my_bool         # If free in mysql_close
+    reconnect*: my_bool       # set to 1 if automatic reconnect
+    scramble*: array[0..(SCRAMBLE_LENGTH + 1) - 1, char] # session-wide random string
+                                                         #  Set if this is the original connection, not a master or a slave we have
+                                                         #       added though mysql_rpl_probe() or mysql_set_master()/ mysql_add_slave()      
+    rpl_pivot*: my_bool #   Pointers to the master, and the next slave connections, points to
+                        #        itself if lone connection.       
+    master*: Pst_mysql
+    next_slave*: Pst_mysql
+    last_used_slave*: Pst_mysql # needed for round-robin slave pick
+    last_used_con*: Pst_mysql # needed for send/read/store/use result to work correctly with replication
+    stmts*: pointer           # was PList, list of all statements
+    methods*: Pst_mysql_methods
+    thd*: pointer #   Points to boolean flag in MYSQL_RES  or MYSQL_STMT. We set this flag
+                  #        from mysql_stmt_close if close had to cancel result set of this object.       
+    unbuffered_fetch_owner*: Pmy_bool
+
+  TMySQL* = Tst_mysql
+  PMySQL* = ptr TMySQL
+  Pst_mysql_res* = ptr Tst_mysql_res
+  Tst_mysql_res*{.final.} = object 
+    row_count*: my_ulonglong
+    fields*: PFIELD
+    data*: PDATA
+    data_cursor*: PROWS
+    lengths*: ptr int         # column lengths of current row
+    handle*: PMySQL                # for unbuffered reads
+    field_alloc*: TMEM_ROOT
+    field_count*: cuint
+    current_field*: cuint
+    row*: TROW                 # If unbuffered read
+    current_row*: TROW         # buffer to current row
+    eof*: my_bool             # Used by mysql_fetch_row
+    unbuffered_fetch_cancelled*: my_bool # mysql_stmt_close() had to cancel this result
+    methods*: Pst_mysql_methods
+
+  TRES* = Tst_mysql_res
+  PRES* = ptr TRES
+  Pst_mysql_stmt* = ptr Tst_mysql_stmt
+  PSTMT* = ptr TSTMT
+  Tst_mysql_methods*{.final.} = object 
+    read_query_result*: proc (MySQL:  PMySQL): my_bool{.cdecl.}
+    advanced_command*: proc (MySQL: PMySQL, command: Tenum_server_command, header: cstring, 
+                             header_length: int, arg: cstring, arg_length: int, 
+                             skip_check: my_bool): my_bool
+    read_rows*: proc (MySQL: PMySQL, fields: PFIELD, fields_count: cuint): PDATA
+    use_result*: proc (MySQL: PMySQL): PRES
+    fetch_lengths*: proc (fto: ptr int, column: TROW, field_count: cuint)
+    flush_use_result*: proc (MySQL: PMySQL)
+    list_fields*: proc (MySQL: PMySQL): PFIELD
+    read_prepare_result*: proc (MySQL: PMySQL, stmt: PSTMT): my_bool
+    stmt_execute*: proc (stmt: PSTMT): cint
+    read_binary_rows*: proc (stmt: PSTMT): cint
+    unbuffered_fetch*: proc (MySQL: PMySQL, row: cstringArray): cint
+    free_embedded_thd*: proc (MySQL: PMySQL)
+    read_statistics*: proc (MySQL: PMySQL): cstring
+    next_result*: proc (MySQL: PMySQL): my_bool
+    read_change_user_result*: proc (MySQL: PMySQL, buff: cstring, passwd: cstring): cint
+    read_rowsfrom_cursor*: proc (stmt: PSTMT): cint
+
+  TMETHODS* = Tst_mysql_methods
+  PMETHODS* = ptr TMETHODS
+  Pst_mysql_manager* = ptr Tst_mysql_manager
+  Tst_mysql_manager*{.final.} = object 
+    net*: TNET
+    host*: cstring
+    user*: cstring
+    passwd*: cstring
+    port*: cuint
+    free_me*: my_bool
+    eof*: my_bool
+    cmd_status*: cint
+    last_errno*: cint
+    net_buf*: cstring
+    net_buf_pos*: cstring
+    net_data_end*: cstring
+    net_buf_size*: cint
+    last_error*: array[0..(MAX_MYSQL_MANAGER_ERR) - 1, char]
+
+  TMANAGER* = Tst_mysql_manager
+  PMANAGER* = ptr TMANAGER
+  Pst_mysql_parameters* = ptr Tst_mysql_parameters
+  Tst_mysql_parameters*{.final.} = object 
+    p_max_allowed_packet*: ptr int
+    p_net_buffer_length*: ptr int
+
+  TPARAMETERS* = Tst_mysql_parameters
+  PPARAMETERS* = ptr TPARAMETERS
+  Tenum_mysql_stmt_state* = enum 
+    STMT_INIT_DONE = 1, STMT_PREPARE_DONE, STMT_EXECUTE_DONE, STMT_FETCH_DONE
+  Pst_mysql_bind* = ptr Tst_mysql_bind
+  Tst_mysql_bind*{.final.} = object 
+    len*: int                 # output length pointer
+    is_null*: Pmy_bool        # Pointer to null indicator
+    buffer*: pointer          # buffer to get/put data
+    error*: PMy_bool          # set this if you want to track data truncations happened during fetch
+    buffer_type*: Tenum_field_types # buffer type
+    buffer_length*: int       # buffer length, must be set for str/binary
+                              # Following are for internal use. Set by mysql_stmt_bind_param  
+    row_ptr*: ptr byte        # for the current data position
+    offset*: int              # offset position for char/binary fetch
+    length_value*: int        #  Used if length is 0
+    param_number*: cuint      # For null count and error messages
+    pack_length*: cuint       # Internal length for packed data
+    error_value*: my_bool     # used if error is 0
+    is_unsigned*: my_bool     # set if integer type is unsigned
+    long_data_used*: my_bool  # If used with mysql_send_long_data
+    is_null_value*: my_bool   # Used if is_null is 0
+    store_param_func*: proc (net: PNET, param: Pst_mysql_bind){.cdecl.}
+    fetch_result*: proc (para1: Pst_mysql_bind, para2: PFIELD, row: PPbyte)
+    skip_result*: proc (para1: Pst_mysql_bind, para2: PFIELD, row: PPbyte)
+
+  TBIND* = Tst_mysql_bind
+  PBIND* = ptr TBIND           # statement handler  
+  Tst_mysql_stmt*{.final.} = object 
+    mem_root*: TMEM_ROOT       # root allocations
+    mysql*: PMySQL                      # connection handle
+    params*: PBIND            # input parameters
+    `bind`*: PBIND            # input parameters
+    fields*: PFIELD           # result set metadata
+    result*: TDATA             # cached result set
+    data_cursor*: PROWS       # current row in cached result
+    affected_rows*: my_ulonglong # copy of mysql->affected_rows after statement execution
+    insert_id*: my_ulonglong
+    read_row_func*: proc (stmt: Pst_mysql_stmt, row: PPbyte): cint{.cdecl.}
+    stmt_id*: int             # Id for prepared statement
+    flags*: int               # i.e. type of cursor to open
+    prefetch_rows*: int       # number of rows per one COM_FETCH
+    server_status*: cuint # Copied from mysql->server_status after execute/fetch to know
+                          # server-side cursor status for this statement.
+    last_errno*: cuint        # error code
+    param_count*: cuint       # input parameter count
+    field_count*: cuint       # number of columns in result set
+    state*: Tenum_mysql_stmt_state # statement state
+    last_error*: array[0..(ERRMSG_SIZE) - 1, char] # error message
+    sqlstate*: array[0..(SQLSTATE_LENGTH + 1) - 1, char]
+    send_types_to_server*: my_bool # Types of input parameters should be sent to server
+    bind_param_done*: my_bool # input buffers were supplied
+    bind_result_done*: char   # output buffers were supplied
+    unbuffered_fetch_cancelled*: my_bool
+    update_max_length*: my_bool
+
+  TSTMT* = Tst_mysql_stmt 
+         
+  Tenum_stmt_attr_type* = enum 
+    STMT_ATTR_UPDATE_MAX_LENGTH, STMT_ATTR_CURSOR_TYPE, STMT_ATTR_PREFETCH_ROWS
+
+proc server_init*(argc: cint, argv: cstringArray, groups: cstringArray): cint{.
+    cdecl, dynlib: lib, importc: "mysql_server_init".}
+proc server_end*(){.cdecl, dynlib: lib, importc: "mysql_server_end".}
+  # mysql_server_init/end need to be called when using libmysqld or
+  #      libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so
+  #      you don't need to call it explicitly; but you need to call
+  #      mysql_server_end() to free memory). The names are a bit misleading
+  #      (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general
+  #      names which suit well whether you're using libmysqld or libmysqlclient. We
+  #      intend to promote these aliases over the mysql_server* ones.     
+proc library_init*(argc: cint, argv: cstringArray, groups: cstringArray): cint{.
+    cdecl, dynlib: lib, importc: "mysql_server_init".}
+proc library_end*(){.cdecl, dynlib: lib, importc: "mysql_server_end".}
+proc get_parameters*(): PPARAMETERS{.stdcall, dynlib: lib, 
+                                     importc: "mysql_get_parameters".}
+  # Set up and bring down a thread; these function should be called
+  #      for each thread in an application which opens at least one MySQL
+  #      connection.  All uses of the connection(s) should be between these
+  #      function calls.     
+proc thread_init*(): my_bool{.stdcall, dynlib: lib, importc: "mysql_thread_init".}
+proc thread_end*(){.stdcall, dynlib: lib, importc: "mysql_thread_end".}
+  # Functions to get information from the MYSQL and MYSQL_RES structures
+  #      Should definitely be used if one uses shared libraries.     
+proc num_rows*(res: PRES): my_ulonglong{.stdcall, dynlib: lib, 
+    importc: "mysql_num_rows".}
+proc num_fields*(res: PRES): cuint{.stdcall, dynlib: lib, 
+                                    importc: "mysql_num_fields".}
+proc eof*(res: PRES): my_bool{.stdcall, dynlib: lib, importc: "mysql_eof".}
+proc fetch_field_direct*(res: PRES, fieldnr: cuint): PFIELD{.stdcall, 
+    dynlib: lib, importc: "mysql_fetch_field_direct".}
+proc fetch_fields*(res: PRES): PFIELD{.stdcall, dynlib: lib, 
+                                       importc: "mysql_fetch_fields".}
+proc row_tell*(res: PRES): TROW_OFFSET{.stdcall, dynlib: lib, 
+                                       importc: "mysql_row_tell".}
+proc field_tell*(res: PRES): TFIELD_OFFSET{.stdcall, dynlib: lib, 
+    importc: "mysql_field_tell".}
+proc field_count*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, 
+                               importc: "mysql_field_count".}
+proc affected_rows*(MySQL: PMySQL): my_ulonglong{.stdcall, dynlib: lib, 
+                                        importc: "mysql_affected_rows".}
+proc insert_id*(MySQL: PMySQL): my_ulonglong{.stdcall, dynlib: lib, 
+                                    importc: "mysql_insert_id".}
+proc errno*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, importc: "mysql_errno".}
+proc error*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_error".}
+proc sqlstate*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_sqlstate".}
+proc warning_count*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, 
+                                 importc: "mysql_warning_count".}
+proc info*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_info".}
+proc thread_id*(MySQL: PMySQL): int{.stdcall, dynlib: lib, importc: "mysql_thread_id".}
+proc character_set_name*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, 
+                                        importc: "mysql_character_set_name".}
+proc set_character_set*(MySQL: PMySQL, csname: cstring): int32{.stdcall, dynlib: lib, 
+    importc: "mysql_set_character_set".}
+proc init*(MySQL: PMySQL): PMySQL{.stdcall, dynlib: lib, importc: "mysql_init".}
+proc ssl_set*(MySQL: PMySQL, key: cstring, cert: cstring, ca: cstring, capath: cstring, 
+              cipher: cstring): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_ssl_set".}
+proc change_user*(MySQL: PMySQL, user: cstring, passwd: cstring, db: cstring): my_bool{.
+    stdcall, dynlib: lib, importc: "mysql_change_user".}
+proc real_connect*(MySQL: PMySQL, host: cstring, user: cstring, passwd: cstring, 
+                   db: cstring, port: cuint, unix_socket: cstring, 
+                   clientflag: int): PMySQL{.stdcall, dynlib: lib, 
+                                        importc: "mysql_real_connect".}
+proc select_db*(MySQL: PMySQL, db: cstring): cint{.stdcall, dynlib: lib, 
+    importc: "mysql_select_db".}
+proc query*(MySQL: PMySQL, q: cstring): cint{.stdcall, dynlib: lib, importc: "mysql_query".}
+proc send_query*(MySQL: PMySQL, q: cstring, len: int): cint{.stdcall, dynlib: lib, 
+    importc: "mysql_send_query".}
+proc real_query*(MySQL: PMySQL, q: cstring, len: int): cint{.stdcall, dynlib: lib, 
+    importc: "mysql_real_query".}
+proc store_result*(MySQL: PMySQL): PRES{.stdcall, dynlib: lib, 
+                               importc: "mysql_store_result".}
+proc use_result*(MySQL: PMySQL): PRES{.stdcall, dynlib: lib, importc: "mysql_use_result".}
+  # perform query on master  
+proc master_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_master_query".}
+proc master_send_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, 
+    dynlib: lib, importc: "mysql_master_send_query".}
+  # perform query on slave  
+proc slave_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_slave_query".}
+proc slave_send_query*(MySQL: PMySQL, q: cstring, len: int): my_bool{.stdcall, 
+    dynlib: lib, importc: "mysql_slave_send_query".}
+proc get_character_set_info*(MySQL: PMySQL, charset: PMY_CHARSET_INFO){.stdcall, 
+    dynlib: lib, importc: "mysql_get_character_set_info".}
+  # local infile support  
+const 
+  LOCAL_INFILE_ERROR_LEN* = 512
+
+# procedure mysql_set_local_infile_handler(mysql:PMYSQL; local_infile_init:function (para1:Ppointer; para2:Pchar; para3:pointer):longint; local_infile_read:function (para1:pointer; para2:Pchar; para3:dword):longint; local_infile_end:procedure (_pa
+# para6:pointer);cdecl;external mysqllib name 'mysql_set_local_infile_handler';
+
+proc set_local_infile_default*(MySQL: PMySQL){.cdecl, dynlib: lib, 
+                                     importc: "mysql_set_local_infile_default".}
+  # enable/disable parsing of all queries to decide if they go on master or
+  #      slave     
+proc enable_rpl_parse*(MySQL: PMySQL){.stdcall, dynlib: lib, 
+                             importc: "mysql_enable_rpl_parse".}
+proc disable_rpl_parse*(MySQL: PMySQL){.stdcall, dynlib: lib, 
+                              importc: "mysql_disable_rpl_parse".}
+  # get the value of the parse flag  
+proc rpl_parse_enabled*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, 
+                                    importc: "mysql_rpl_parse_enabled".}
+  #  enable/disable reads from master  
+proc enable_reads_from_master*(MySQL: PMySQL){.stdcall, dynlib: lib, 
+                                     importc: "mysql_enable_reads_from_master".}
+proc disable_reads_from_master*(MySQL: PMySQL){.stdcall, dynlib: lib, importc: "mysql_disable_reads_from_master".}
+  # get the value of the master read flag  
+proc reads_from_master_enabled*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_reads_from_master_enabled".}
+proc rpl_query_type*(q: cstring, length: cint): Trpl_type{.stdcall, dynlib: lib, 
+    importc: "mysql_rpl_query_type".}
+  # discover the master and its slaves  
+proc rpl_probe*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, importc: "mysql_rpl_probe".}
+  # set the master, close/free the old one, if it is not a pivot  
+proc set_master*(MySQL: PMySQL, host: cstring, port: cuint, user: cstring, passwd: cstring): cint{.
+    stdcall, dynlib: lib, importc: "mysql_set_master".}
+proc add_slave*(MySQL: PMySQL, host: cstring, port: cuint, user: cstring, passwd: cstring): cint{.
+    stdcall, dynlib: lib, importc: "mysql_add_slave".}
+proc shutdown*(MySQL: PMySQL, shutdown_level: Tenum_shutdown_level): cint{.stdcall, 
+    dynlib: lib, importc: "mysql_shutdown".}
+proc dump_debug_info*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, 
+                                  importc: "mysql_dump_debug_info".}
+proc refresh*(sql: PMySQL, refresh_options: cuint): cint{.stdcall, dynlib: lib, 
+    importc: "mysql_refresh".}
+proc kill*(MySQL: PMySQL, pid: int): cint{.stdcall, dynlib: lib, importc: "mysql_kill".}
+proc set_server_option*(MySQL: PMySQL, option: Tenum_mysql_set_option): cint{.stdcall, 
+    dynlib: lib, importc: "mysql_set_server_option".}
+proc ping*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, importc: "mysql_ping".}
+proc stat*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, importc: "mysql_stat".}
+proc get_server_info*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, 
+                                     importc: "mysql_get_server_info".}
+proc get_client_info*(): cstring{.stdcall, dynlib: lib, 
+                                  importc: "mysql_get_client_info".}
+proc get_client_version*(): int{.stdcall, dynlib: lib, 
+                                 importc: "mysql_get_client_version".}
+proc get_host_info*(MySQL: PMySQL): cstring{.stdcall, dynlib: lib, 
+                                   importc: "mysql_get_host_info".}
+proc get_server_version*(MySQL: PMySQL): int{.stdcall, dynlib: lib, 
+                                    importc: "mysql_get_server_version".}
+proc get_proto_info*(MySQL: PMySQL): cuint{.stdcall, dynlib: lib, 
+                                  importc: "mysql_get_proto_info".}
+proc list_dbs*(MySQL: PMySQL, wild: cstring): PRES{.stdcall, dynlib: lib, 
+    importc: "mysql_list_dbs".}
+proc list_tables*(MySQL: PMySQL, wild: cstring): PRES{.stdcall, dynlib: lib, 
+    importc: "mysql_list_tables".}
+proc list_processes*(MySQL: PMySQL): PRES{.stdcall, dynlib: lib, 
+                                 importc: "mysql_list_processes".}
+proc options*(MySQL: PMySQL, option: Toption, arg: cstring): cint{.stdcall, dynlib: lib, 
+    importc: "mysql_options".}
+proc free_result*(result: PRES){.stdcall, dynlib: lib, 
+                                 importc: "mysql_free_result".}
+proc data_seek*(result: PRES, offset: my_ulonglong){.stdcall, dynlib: lib, 
+    importc: "mysql_data_seek".}
+proc row_seek*(result: PRES, offset: TROW_OFFSET): TROW_OFFSET{.stdcall, 
+    dynlib: lib, importc: "mysql_row_seek".}
+proc field_seek*(result: PRES, offset: TFIELD_OFFSET): TFIELD_OFFSET{.stdcall, 
+    dynlib: lib, importc: "mysql_field_seek".}
+proc fetch_row*(result: PRES): TROW{.stdcall, dynlib: lib, 
+                                    importc: "mysql_fetch_row".}
+proc fetch_lengths*(result: PRES): ptr int{.stdcall, dynlib: lib, 
+    importc: "mysql_fetch_lengths".}
+proc fetch_field*(result: PRES): PFIELD{.stdcall, dynlib: lib, 
+    importc: "mysql_fetch_field".}
+proc list_fields*(MySQL: PMySQL, table: cstring, wild: cstring): PRES{.stdcall, 
+    dynlib: lib, importc: "mysql_list_fields".}
+proc escape_string*(fto: cstring, `from`: cstring, from_length: int): int{.
+    stdcall, dynlib: lib, importc: "mysql_escape_string".}
+proc hex_string*(fto: cstring, `from`: cstring, from_length: int): int{.stdcall, 
+    dynlib: lib, importc: "mysql_hex_string".}
+proc real_escape_string*(MySQL: PMySQL, fto: cstring, `from`: cstring, len: int): int{.
+    stdcall, dynlib: lib, importc: "mysql_real_escape_string".}
+proc debug*(debug: cstring){.stdcall, dynlib: lib, importc: "mysql_debug".}
+  #    function mysql_odbc_escape_string(mysql:PMYSQL; fto:Pchar; to_length:dword; from:Pchar; from_length:dword;
+  #               param:pointer; extend_buffer:function (para1:pointer; to:Pchar; length:Pdword):Pchar):Pchar;stdcall;external mysqllib name 'mysql_odbc_escape_string';
+proc myodbc_remove_escape*(MySQL: PMySQL, name: cstring){.stdcall, dynlib: lib, 
+    importc: "myodbc_remove_escape".}
+proc thread_safe*(): cuint{.stdcall, dynlib: lib, importc: "mysql_thread_safe".}
+proc embedded*(): my_bool{.stdcall, dynlib: lib, importc: "mysql_embedded".}
+proc manager_init*(con: PMANAGER): PMANAGER{.stdcall, dynlib: lib, 
+    importc: "mysql_manager_init".}
+proc manager_connect*(con: PMANAGER, host: cstring, user: cstring, 
+                      passwd: cstring, port: cuint): PMANAGER{.stdcall, 
+    dynlib: lib, importc: "mysql_manager_connect".}
+proc manager_close*(con: PMANAGER){.stdcall, dynlib: lib, 
+                                    importc: "mysql_manager_close".}
+proc manager_command*(con: PMANAGER, cmd: cstring, cmd_len: cint): cint{.
+    stdcall, dynlib: lib, importc: "mysql_manager_command".}
+proc manager_fetch_line*(con: PMANAGER, res_buf: cstring, res_buf_size: cint): cint{.
+    stdcall, dynlib: lib, importc: "mysql_manager_fetch_line".}
+proc read_query_result*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, 
+                                       importc: "mysql_read_query_result".}
+proc stmt_init*(MySQL: PMySQL): PSTMT{.stdcall, dynlib: lib, importc: "mysql_stmt_init".}
+proc stmt_prepare*(stmt: PSTMT, query: cstring, len: int): cint{.stdcall, 
+    dynlib: lib, importc: "mysql_stmt_prepare".}
+proc stmt_execute*(stmt: PSTMT): cint{.stdcall, dynlib: lib, 
+                                       importc: "mysql_stmt_execute".}
+proc stmt_fetch*(stmt: PSTMT): cint{.stdcall, dynlib: lib, 
+                                     importc: "mysql_stmt_fetch".}
+proc stmt_fetch_column*(stmt: PSTMT, `bind`: PBIND, column: cuint, offset: int): cint{.
+    stdcall, dynlib: lib, importc: "mysql_stmt_fetch_column".}
+proc stmt_store_result*(stmt: PSTMT): cint{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_store_result".}
+proc stmt_param_count*(stmt: PSTMT): int{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_param_count".}
+proc stmt_attr_set*(stmt: PSTMT, attr_type: Tenum_stmt_attr_type, attr: pointer): my_bool{.
+    stdcall, dynlib: lib, importc: "mysql_stmt_attr_set".}
+proc stmt_attr_get*(stmt: PSTMT, attr_type: Tenum_stmt_attr_type, attr: pointer): my_bool{.
+    stdcall, dynlib: lib, importc: "mysql_stmt_attr_get".}
+proc stmt_bind_param*(stmt: PSTMT, bnd: PBIND): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_bind_param".}
+proc stmt_bind_result*(stmt: PSTMT, bnd: PBIND): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_bind_result".}
+proc stmt_close*(stmt: PSTMT): my_bool{.stdcall, dynlib: lib, 
+                                        importc: "mysql_stmt_close".}
+proc stmt_reset*(stmt: PSTMT): my_bool{.stdcall, dynlib: lib, 
+                                        importc: "mysql_stmt_reset".}
+proc stmt_free_result*(stmt: PSTMT): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_free_result".}
+proc stmt_send_long_data*(stmt: PSTMT, param_number: cuint, data: cstring, 
+                          len: int): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_send_long_data".}
+proc stmt_result_metadata*(stmt: PSTMT): PRES{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_result_metadata".}
+proc stmt_param_metadata*(stmt: PSTMT): PRES{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_param_metadata".}
+proc stmt_errno*(stmt: PSTMT): cuint{.stdcall, dynlib: lib, 
+                                      importc: "mysql_stmt_errno".}
+proc stmt_error*(stmt: PSTMT): cstring{.stdcall, dynlib: lib, 
+                                        importc: "mysql_stmt_error".}
+proc stmt_sqlstate*(stmt: PSTMT): cstring{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_sqlstate".}
+proc stmt_row_seek*(stmt: PSTMT, offset: TROW_OFFSET): TROW_OFFSET{.stdcall, 
+    dynlib: lib, importc: "mysql_stmt_row_seek".}
+proc stmt_row_tell*(stmt: PSTMT): TROW_OFFSET{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_row_tell".}
+proc stmt_data_seek*(stmt: PSTMT, offset: my_ulonglong){.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_data_seek".}
+proc stmt_num_rows*(stmt: PSTMT): my_ulonglong{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_num_rows".}
+proc stmt_affected_rows*(stmt: PSTMT): my_ulonglong{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_affected_rows".}
+proc stmt_insert_id*(stmt: PSTMT): my_ulonglong{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_insert_id".}
+proc stmt_field_count*(stmt: PSTMT): cuint{.stdcall, dynlib: lib, 
+    importc: "mysql_stmt_field_count".}
+proc commit*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, importc: "mysql_commit".}
+proc rollback*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, importc: "mysql_rollback".}
+proc autocommit*(MySQL: PMySQL, auto_mode: my_bool): my_bool{.stdcall, dynlib: lib, 
+    importc: "mysql_autocommit".}
+proc more_results*(MySQL: PMySQL): my_bool{.stdcall, dynlib: lib, 
+                                  importc: "mysql_more_results".}
+proc next_result*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, importc: "mysql_next_result".}
+proc close*(sock: PMySQL){.stdcall, dynlib: lib, importc: "mysql_close".}
+  # status return codes  
+const 
+  NO_DATA* = 100
+  DATA_TRUNCATED* = 101
+
+proc reload*(x: PMySQL): cint
+when defined(USE_OLD_FUNCTIONS): 
+  proc connect*(MySQL: PMySQL, host: cstring, user: cstring, passwd: cstring): PMySQL{.stdcall, 
+      dynlib: lib, importc: "mysql_connect".}
+  proc create_db*(MySQL: PMySQL, DB: cstring): cint{.stdcall, dynlib: lib, 
+      importc: "mysql_create_db".}
+  proc drop_db*(MySQL: PMySQL, DB: cstring): cint{.stdcall, dynlib: lib, 
+      importc: "mysql_drop_db".}
+proc net_safe_read*(MySQL: PMySQL): cuint{.cdecl, dynlib: lib, importc: "net_safe_read".}
+
+proc IS_PRI_KEY(n: int32): bool = 
+  result = (n and PRI_KEY_FLAG) != 0
+
+proc IS_NOT_NULL(n: int32): bool = 
+  result = (n and NOT_NULL_FLAG) != 0
+
+proc IS_BLOB(n: int32): bool = 
+  result = (n and BLOB_FLAG) != 0
+
+proc IS_NUM_FIELD(f: Pst_mysql_field): bool = 
+  result = (f.flags and NUM_FLAG) != 0
+
+proc IS_NUM(t: Tenum_field_types): bool = 
+  result = (t <= FIELD_TYPE_INT24) or (t == FIELD_TYPE_YEAR) or
+      (t == FIELD_TYPE_NEWDECIMAL)
+
+proc INTERNAL_NUM_FIELD(f: Pst_mysql_field): bool = 
+  result = (f.ftype <= FIELD_TYPE_INT24) and
+      ((f.ftype != FIELD_TYPE_TIMESTAMP) or (f.len == 14) or (f.len == 8)) or
+      (f.ftype == FIELD_TYPE_YEAR)
+
+proc reload(x: PMySQL): cint =
+  result = refresh(x, REFRESH_GRANT)
+
+{.pop.}
diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim
new file mode 100644
index 000000000..77719e85f
--- /dev/null
+++ b/lib/wrappers/odbcsql.nim
@@ -0,0 +1,788 @@
+
+{.deadCodeElim: on.}
+
+when not defined(ODBCVER):
+  const
+    ODBCVER = 0x0351 ## define ODBC version 3.51 by default
+
+when defined(windows):
+  {.push callconv: stdcall.}
+  const odbclib = "odbc32.dll"
+else:
+  {.push callconv: cdecl.}
+  const odbclib = "libodbc.so"
+
+# DATA TYPES CORRESPONDENCE
+#   BDE fields  ODBC types
+#   ----------  ------------------
+#   ftBlob      SQL_BINARY
+#   ftBoolean   SQL_BIT
+#   ftDate      SQL_TYPE_DATE
+#   ftTime      SQL_TYPE_TIME
+#   ftDateTime  SQL_TYPE_TIMESTAMP
+#   ftInteger   SQL_INTEGER
+#   ftSmallint  SQL_SMALLINT
+#   ftFloat     SQL_DOUBLE
+#   ftString    SQL_CHAR
+#   ftMemo      SQL_BINARY // SQL_VARCHAR
+#
+
+type 
+  TSqlChar* = char
+  TSqlSmallInt* = int16
+  TSqlUSmallInt* = int16
+  TSqlHandle* = pointer
+  TSqlHEnv* = TSqlHandle
+  TSqlHDBC* = TSqlHandle
+  TSqlHStmt* = TSqlHandle
+  TSqlHDesc* = TSqlHandle
+  TSqlInteger* = int
+  TSqlUInteger* = int
+  TSqlPointer* = pointer
+  TSqlReal* = cfloat
+  TSqlDouble* = cdouble
+  TSqlFloat* = cdouble
+  TSqlHWND* = pointer
+  PSQLCHAR* = cstring
+  PSQLINTEGER* = ptr TSqlInteger
+  PSQLUINTEGER* = ptr TSqlUInteger
+  PSQLSMALLINT* = ptr TSqlSmallInt
+  PSQLUSMALLINT* = ptr TSqlUSmallInt
+  PSQLREAL* = ptr TSqlReal
+  PSQLDOUBLE* = ptr TSqlDouble
+  PSQLFLOAT* = ptr TSqlFloat
+  PSQLHANDLE* = ptr TSqlHandle
+
+const                         # SQL data type codes 
+  SQL_UNKNOWN_TYPE* = 0
+  SQL_LONGVARCHAR* = (- 1)
+  SQL_BINARY* = (- 2)
+  SQL_VARBINARY* = (- 3)
+  SQL_LONGVARBINARY* = (- 4)
+  SQL_BIGINT* = (- 5)
+  SQL_TINYINT* = (- 6)
+  SQL_BIT* = (- 7)
+  SQL_WCHAR* = (- 8)
+  SQL_WVARCHAR* = (- 9)
+  SQL_WLONGVARCHAR* = (- 10)
+  SQL_CHAR* = 1
+  SQL_NUMERIC* = 2
+  SQL_DECIMAL* = 3
+  SQL_INTEGER* = 4
+  SQL_SMALLINT* = 5
+  SQL_FLOAT* = 6
+  SQL_REAL* = 7
+  SQL_DOUBLE* = 8
+  SQL_DATETIME* = 9
+  SQL_VARCHAR* = 12
+  SQL_TYPE_DATE* = 91
+  SQL_TYPE_TIME* = 92
+  SQL_TYPE_TIMESTAMP* = 93
+  SQL_DATE* = 9
+  SQL_TIME* = 10
+  SQL_TIMESTAMP* = 11
+  SQL_INTERVAL* = 10
+  SQL_GUID* = - 11            # interval codes
+
+when ODBCVER >= 0x0300: 
+  const 
+    SQL_CODE_YEAR* = 1
+    SQL_CODE_MONTH* = 2
+    SQL_CODE_DAY* = 3
+    SQL_CODE_HOUR* = 4
+    SQL_CODE_MINUTE* = 5
+    SQL_CODE_SECOND* = 6
+    SQL_CODE_YEAR_TO_MONTH* = 7
+    SQL_CODE_DAY_TO_HOUR* = 8
+    SQL_CODE_DAY_TO_MINUTE* = 9
+    SQL_CODE_DAY_TO_SECOND* = 10
+    SQL_CODE_HOUR_TO_MINUTE* = 11
+    SQL_CODE_HOUR_TO_SECOND* = 12
+    SQL_CODE_MINUTE_TO_SECOND* = 13
+    SQL_INTERVAL_YEAR* = 100 + SQL_CODE_YEAR
+    SQL_INTERVAL_MONTH* = 100 + SQL_CODE_MONTH
+    SQL_INTERVAL_DAY* = 100 + SQL_CODE_DAY
+    SQL_INTERVAL_HOUR* = 100 + SQL_CODE_HOUR
+    SQL_INTERVAL_MINUTE* = 100 + SQL_CODE_MINUTE
+    SQL_INTERVAL_SECOND* = 100 + SQL_CODE_SECOND
+    SQL_INTERVAL_YEAR_TO_MONTH* = 100 + SQL_CODE_YEAR_TO_MONTH
+    SQL_INTERVAL_DAY_TO_HOUR* = 100 + SQL_CODE_DAY_TO_HOUR
+    SQL_INTERVAL_DAY_TO_MINUTE* = 100 + SQL_CODE_DAY_TO_MINUTE
+    SQL_INTERVAL_DAY_TO_SECOND* = 100 + SQL_CODE_DAY_TO_SECOND
+    SQL_INTERVAL_HOUR_TO_MINUTE* = 100 + SQL_CODE_HOUR_TO_MINUTE
+    SQL_INTERVAL_HOUR_TO_SECOND* = 100 + SQL_CODE_HOUR_TO_SECOND
+    SQL_INTERVAL_MINUTE_TO_SECOND* = 100 + SQL_CODE_MINUTE_TO_SECOND
+else: 
+  const 
+    SQL_INTERVAL_YEAR* = - 80
+    SQL_INTERVAL_MONTH* = - 81
+    SQL_INTERVAL_YEAR_TO_MONTH* = - 82
+    SQL_INTERVAL_DAY* = - 83
+    SQL_INTERVAL_HOUR* = - 84
+    SQL_INTERVAL_MINUTE* = - 85
+    SQL_INTERVAL_SECOND* = - 86
+    SQL_INTERVAL_DAY_TO_HOUR* = - 87
+    SQL_INTERVAL_DAY_TO_MINUTE* = - 88
+    SQL_INTERVAL_DAY_TO_SECOND* = - 89
+    SQL_INTERVAL_HOUR_TO_MINUTE* = - 90
+    SQL_INTERVAL_HOUR_TO_SECOND* = - 91
+    SQL_INTERVAL_MINUTE_TO_SECOND* = - 92
+
+
+when ODBCVER < 0x0300: 
+  const 
+    SQL_UNICODE* = - 95
+    SQL_UNICODE_VARCHAR* = - 96
+    SQL_UNICODE_LONGVARCHAR* = - 97
+    SQL_UNICODE_CHAR* = SQL_UNICODE
+else: 
+  # The previous definitions for SQL_UNICODE_ are historical and obsolete 
+  const 
+    SQL_UNICODE* = SQL_WCHAR
+    SQL_UNICODE_VARCHAR* = SQL_WVARCHAR
+    SQL_UNICODE_LONGVARCHAR* = SQL_WLONGVARCHAR
+    SQL_UNICODE_CHAR* = SQL_WCHAR
+const                         # C datatype to SQL datatype mapping 
+  SQL_C_CHAR* = SQL_CHAR
+  SQL_C_LONG* = SQL_INTEGER
+  SQL_C_SHORT* = SQL_SMALLINT
+  SQL_C_FLOAT* = SQL_REAL
+  SQL_C_DOUBLE* = SQL_DOUBLE
+  SQL_C_NUMERIC* = SQL_NUMERIC
+  SQL_C_DEFAULT* = 99
+  SQL_SIGNED_OFFSET* = - 20
+  SQL_UNSIGNED_OFFSET* = - 22
+  SQL_C_DATE* = SQL_DATE
+  SQL_C_TIME* = SQL_TIME
+  SQL_C_TIMESTAMP* = SQL_TIMESTAMP
+  SQL_C_TYPE_DATE* = SQL_TYPE_DATE
+  SQL_C_TYPE_TIME* = SQL_TYPE_TIME
+  SQL_C_TYPE_TIMESTAMP* = SQL_TYPE_TIMESTAMP
+  SQL_C_INTERVAL_YEAR* = SQL_INTERVAL_YEAR
+  SQL_C_INTERVAL_MONTH* = SQL_INTERVAL_MONTH
+  SQL_C_INTERVAL_DAY* = SQL_INTERVAL_DAY
+  SQL_C_INTERVAL_HOUR* = SQL_INTERVAL_HOUR
+  SQL_C_INTERVAL_MINUTE* = SQL_INTERVAL_MINUTE
+  SQL_C_INTERVAL_SECOND* = SQL_INTERVAL_SECOND
+  SQL_C_INTERVAL_YEAR_TO_MONTH* = SQL_INTERVAL_YEAR_TO_MONTH
+  SQL_C_INTERVAL_DAY_TO_HOUR* = SQL_INTERVAL_DAY_TO_HOUR
+  SQL_C_INTERVAL_DAY_TO_MINUTE* = SQL_INTERVAL_DAY_TO_MINUTE
+  SQL_C_INTERVAL_DAY_TO_SECOND* = SQL_INTERVAL_DAY_TO_SECOND
+  SQL_C_INTERVAL_HOUR_TO_MINUTE* = SQL_INTERVAL_HOUR_TO_MINUTE
+  SQL_C_INTERVAL_HOUR_TO_SECOND* = SQL_INTERVAL_HOUR_TO_SECOND
+  SQL_C_INTERVAL_MINUTE_TO_SECOND* = SQL_INTERVAL_MINUTE_TO_SECOND
+  SQL_C_BINARY* = SQL_BINARY
+  SQL_C_BIT* = SQL_BIT
+  SQL_C_SBIGINT* = SQL_BIGINT + SQL_SIGNED_OFFSET # SIGNED BIGINT
+  SQL_C_UBIGINT* = SQL_BIGINT + SQL_UNSIGNED_OFFSET # UNSIGNED BIGINT
+  SQL_C_TINYINT* = SQL_TINYINT
+  SQL_C_SLONG* = SQL_C_LONG + SQL_SIGNED_OFFSET # SIGNED INTEGER
+  SQL_C_SSHORT* = SQL_C_SHORT + SQL_SIGNED_OFFSET # SIGNED SMALLINT
+  SQL_C_STINYINT* = SQL_TINYINT + SQL_SIGNED_OFFSET # SIGNED TINYINT
+  SQL_C_ULONG* = SQL_C_LONG + SQL_UNSIGNED_OFFSET # UNSIGNED INTEGER
+  SQL_C_USHORT* = SQL_C_SHORT + SQL_UNSIGNED_OFFSET # UNSIGNED SMALLINT
+  SQL_C_UTINYINT* = SQL_TINYINT + SQL_UNSIGNED_OFFSET # UNSIGNED TINYINT
+  SQL_C_BOOKMARK* = SQL_C_ULONG # BOOKMARK
+  SQL_C_GUID* = SQL_GUID
+  SQL_TYPE_NULL* = 0
+
+when ODBCVER < 0x0300: 
+  const 
+    SQL_TYPE_MIN* = SQL_BIT
+    SQL_TYPE_MAX* = SQL_VARCHAR
+
+const 
+  SQL_C_VARBOOKMARK* = SQL_C_BINARY
+  SQL_API_SQLDESCRIBEPARAM* = 58
+  SQL_NO_TOTAL* = - 4
+
+type 
+  SQL_DATE_STRUCT* {.final, pure.} = object 
+    Year*: TSqlSmallInt
+    Month*: TSqlUSmallInt
+    Day*: TSqlUSmallInt
+
+  PSQL_DATE_STRUCT* = ptr SQL_DATE_STRUCT
+  SQL_TIME_STRUCT* {.final, pure.} = object 
+    Hour*: TSqlUSmallInt
+    Minute*: TSqlUSmallInt
+    Second*: TSqlUSmallInt
+
+  PSQL_TIME_STRUCT* = ptr SQL_TIME_STRUCT
+  SQL_TIMESTAMP_STRUCT* {.final, pure.} = object 
+    Year*: TSqlUSmallInt
+    Month*: TSqlUSmallInt
+    Day*: TSqlUSmallInt
+    Hour*: TSqlUSmallInt
+    Minute*: TSqlUSmallInt
+    Second*: TSqlUSmallInt
+    Fraction*: TSqlUInteger
+
+  PSQL_TIMESTAMP_STRUCT* = ptr SQL_TIMESTAMP_STRUCT
+
+const 
+  SQL_NAME_LEN* = 128
+  SQL_OV_ODBC3* = 3
+  SQL_OV_ODBC2* = 2
+  SQL_ATTR_ODBC_VERSION* = 200 # Options for SQLDriverConnect 
+  SQL_DRIVER_NOPROMPT* = 0
+  SQL_DRIVER_COMPLETE* = 1
+  SQL_DRIVER_PROMPT* = 2
+  SQL_DRIVER_COMPLETE_REQUIRED* = 3 
+  SQL_IS_POINTER* = (- 4)  # whether an attribute is a pointer or not 
+  SQL_IS_UINTEGER* = (- 5)
+  SQL_IS_INTEGER* = (- 6)
+  SQL_IS_USMALLINT* = (- 7)
+  SQL_IS_SMALLINT* = (- 8)    # SQLExtendedFetch "fFetchType" values 
+  SQL_FETCH_BOOKMARK* = 8
+  SQL_SCROLL_OPTIONS* = 44    # SQL_USE_BOOKMARKS options 
+  SQL_UB_OFF* = 0
+  SQL_UB_ON* = 1
+  SQL_UB_DEFAULT* = SQL_UB_OFF
+  SQL_UB_FIXED* = SQL_UB_ON
+  SQL_UB_VARIABLE* = 2        # SQL_SCROLL_OPTIONS masks 
+  SQL_SO_FORWARD_ONLY* = 0x00000001
+  SQL_SO_KEYSET_DRIVEN* = 0x00000002
+  SQL_SO_DYNAMIC* = 0x00000004
+  SQL_SO_MIXED* = 0x00000008
+  SQL_SO_STATIC* = 0x00000010
+  SQL_BOOKMARK_PERSISTENCE* = 82
+  SQL_STATIC_SENSITIVITY* = 83 # SQL_BOOKMARK_PERSISTENCE values 
+  SQL_BP_CLOSE* = 0x00000001
+  SQL_BP_DELETE* = 0x00000002
+  SQL_BP_DROP* = 0x00000004
+  SQL_BP_TRANSACTION* = 0x00000008
+  SQL_BP_UPDATE* = 0x00000010
+  SQL_BP_OTHER_HSTMT* = 0x00000020
+  SQL_BP_SCROLL* = 0x00000040
+  SQL_DYNAMIC_CURSOR_ATTRIBUTES1* = 144
+  SQL_DYNAMIC_CURSOR_ATTRIBUTES2* = 145
+  SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1* = 146
+  SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2* = 147
+  SQL_INDEX_KEYWORDS* = 148
+  SQL_INFO_SCHEMA_VIEWS* = 149
+  SQL_KEYSET_CURSOR_ATTRIBUTES1* = 150
+  SQL_KEYSET_CURSOR_ATTRIBUTES2* = 151
+  SQL_STATIC_CURSOR_ATTRIBUTES1* = 167
+  SQL_STATIC_CURSOR_ATTRIBUTES2* = 168 # supported SQLFetchScroll FetchOrientation's 
+  SQL_CA1_NEXT* = 1
+  SQL_CA1_ABSOLUTE* = 2
+  SQL_CA1_RELATIVE* = 4
+  SQL_CA1_BOOKMARK* = 8       # supported SQLSetPos LockType's 
+  SQL_CA1_LOCK_NO_CHANGE* = 0x00000040
+  SQL_CA1_LOCK_EXCLUSIVE* = 0x00000080
+  SQL_CA1_LOCK_UNLOCK* = 0x00000100 # supported SQLSetPos Operations 
+  SQL_CA1_POS_POSITION* = 0x00000200
+  SQL_CA1_POS_UPDATE* = 0x00000400
+  SQL_CA1_POS_DELETE* = 0x00000800
+  SQL_CA1_POS_REFRESH* = 0x00001000 # positioned updates and deletes 
+  SQL_CA1_POSITIONED_UPDATE* = 0x00002000
+  SQL_CA1_POSITIONED_DELETE* = 0x00004000
+  SQL_CA1_SELECT_FOR_UPDATE* = 0x00008000 # supported SQLBulkOperations operations 
+  SQL_CA1_BULK_ADD* = 0x00010000
+  SQL_CA1_BULK_UPDATE_BY_BOOKMARK* = 0x00020000
+  SQL_CA1_BULK_DELETE_BY_BOOKMARK* = 0x00040000
+  SQL_CA1_BULK_FETCH_BY_BOOKMARK* = 0x00080000 # supported values for SQL_ATTR_SCROLL_CONCURRENCY 
+  SQL_CA2_READ_ONLY_CONCURRENCY* = 1
+  SQL_CA2_LOCK_CONCURRENCY* = 2
+  SQL_CA2_OPT_ROWVER_CONCURRENCY* = 4
+  SQL_CA2_OPT_VALUES_CONCURRENCY* = 8 # sensitivity of the cursor to its own inserts, deletes, and updates 
+  SQL_CA2_SENSITIVITY_ADDITIONS* = 0x00000010
+  SQL_CA2_SENSITIVITY_DELETIONS* = 0x00000020
+  SQL_CA2_SENSITIVITY_UPDATES* = 0x00000040 #  semantics of SQL_ATTR_MAX_ROWS 
+  SQL_CA2_MAX_ROWS_SELECT* = 0x00000080
+  SQL_CA2_MAX_ROWS_INSERT* = 0x00000100
+  SQL_CA2_MAX_ROWS_DELETE* = 0x00000200
+  SQL_CA2_MAX_ROWS_UPDATE* = 0x00000400
+  SQL_CA2_MAX_ROWS_CATALOG* = 0x00000800
+  SQL_CA2_MAX_ROWS_AFFECTS_ALL* = (SQL_CA2_MAX_ROWS_SELECT or
+      SQL_CA2_MAX_ROWS_INSERT or SQL_CA2_MAX_ROWS_DELETE or
+      SQL_CA2_MAX_ROWS_UPDATE or SQL_CA2_MAX_ROWS_CATALOG) # semantics of 
+                                                           # SQL_DIAG_CURSOR_ROW_COUNT 
+  SQL_CA2_CRC_EXACT* = 0x00001000
+  SQL_CA2_CRC_APPROXIMATE* = 0x00002000 #  the kinds of positioned statements that can be simulated 
+  SQL_CA2_SIMULATE_NON_UNIQUE* = 0x00004000
+  SQL_CA2_SIMULATE_TRY_UNIQUE* = 0x00008000
+  SQL_CA2_SIMULATE_UNIQUE* = 0x00010000 #  Operations in SQLBulkOperations 
+  SQL_ADD* = 4
+  SQL_SETPOS_MAX_OPTION_VALUE* = SQL_ADD
+  SQL_UPDATE_BY_BOOKMARK* = 5
+  SQL_DELETE_BY_BOOKMARK* = 6
+  SQL_FETCH_BY_BOOKMARK* = 7  # Operations in SQLSetPos 
+  SQL_POSITION* = 0
+  SQL_REFRESH* = 1
+  SQL_UPDATE* = 2
+  SQL_DELETE* = 3             # Lock options in SQLSetPos 
+  SQL_LOCK_NO_CHANGE* = 0
+  SQL_LOCK_EXCLUSIVE* = 1
+  SQL_LOCK_UNLOCK* = 2        # SQLExtendedFetch "rgfRowStatus" element values 
+  SQL_ROW_SUCCESS* = 0
+  SQL_ROW_DELETED* = 1
+  SQL_ROW_UPDATED* = 2
+  SQL_ROW_NOROW* = 3
+  SQL_ROW_ADDED* = 4
+  SQL_ROW_ERROR* = 5
+  SQL_ROW_SUCCESS_WITH_INFO* = 6
+  SQL_ROW_PROCEED* = 0
+  SQL_ROW_IGNORE* = 1
+  SQL_MAX_DSN_LENGTH* = 32    # maximum data source name size 
+  SQL_MAX_OPTION_STRING_LENGTH* = 256
+  SQL_ODBC_CURSORS* = 110
+  SQL_ATTR_ODBC_CURSORS* = SQL_ODBC_CURSORS # SQL_ODBC_CURSORS options 
+  SQL_CUR_USE_IF_NEEDED* = 0
+  SQL_CUR_USE_ODBC* = 1
+  SQL_CUR_USE_DRIVER* = 2
+  SQL_CUR_DEFAULT* = SQL_CUR_USE_DRIVER
+  SQL_PARAM_TYPE_UNKNOWN* = 0
+  SQL_PARAM_INPUT* = 1
+  SQL_PARAM_INPUT_OUTPUT* = 2
+  SQL_RESULT_COL* = 3
+  SQL_PARAM_OUTPUT* = 4
+  SQL_RETURN_VALUE* = 5       # special length/indicator values 
+  SQL_NULL_DATA* = (- 1)
+  SQL_DATA_AT_EXEC* = (- 2)
+  SQL_SUCCESS* = 0
+  SQL_SUCCESS_WITH_INFO* = 1
+  SQL_NO_DATA* = 100
+  SQL_ERROR* = (- 1)
+  SQL_INVALID_HANDLE* = (- 2)
+  SQL_STILL_EXECUTING* = 2
+  SQL_NEED_DATA* = 99         # flags for null-terminated string 
+  SQL_NTS* = (- 3)            # maximum message length 
+  SQL_MAX_MESSAGE_LENGTH* = 512 # date/time length constants 
+  SQL_DATE_LEN* = 10
+  SQL_TIME_LEN* = 8           # add P+1 if precision is nonzero 
+  SQL_TIMESTAMP_LEN* = 19     # add P+1 if precision is nonzero 
+                              # handle type identifiers 
+  SQL_HANDLE_ENV* = 1
+  SQL_HANDLE_DBC* = 2
+  SQL_HANDLE_STMT* = 3
+  SQL_HANDLE_DESC* = 4        # environment attribute 
+  SQL_ATTR_OUTPUT_NTS* = 10001 # connection attributes 
+  SQL_ATTR_AUTO_IPD* = 10001
+  SQL_ATTR_METADATA_ID* = 10014 # statement attributes 
+  SQL_ATTR_APP_ROW_DESC* = 10010
+  SQL_ATTR_APP_PARAM_DESC* = 10011
+  SQL_ATTR_IMP_ROW_DESC* = 10012
+  SQL_ATTR_IMP_PARAM_DESC* = 10013
+  SQL_ATTR_CURSOR_SCROLLABLE* = (- 1)
+  SQL_ATTR_CURSOR_SENSITIVITY* = (- 2)
+  SQL_QUERY_TIMEOUT* = 0
+  SQL_MAX_ROWS* = 1
+  SQL_NOSCAN* = 2
+  SQL_MAX_LENGTH* = 3
+  SQL_ASYNC_ENABLE* = 4       # same as SQL_ATTR_ASYNC_ENABLE */
+  SQL_BIND_TYPE* = 5
+  SQL_CURSOR_TYPE* = 6
+  SQL_CONCURRENCY* = 7
+  SQL_KEYSET_SIZE* = 8
+  SQL_ROWSET_SIZE* = 9
+  SQL_SIMULATE_CURSOR* = 10
+  SQL_RETRIEVE_DATA* = 11
+  SQL_USE_BOOKMARKS* = 12
+  SQL_GET_BOOKMARK* = 13      #      GetStmtOption Only */
+  SQL_ROW_NUMBER* = 14        #      GetStmtOption Only */
+  SQL_ATTR_CURSOR_TYPE* = SQL_CURSOR_TYPE
+  SQL_ATTR_CONCURRENCY* = SQL_CONCURRENCY
+  SQL_ATTR_FETCH_BOOKMARK_PTR* = 16
+  SQL_ATTR_ROW_STATUS_PTR* = 25
+  SQL_ATTR_ROWS_FETCHED_PTR* = 26
+  SQL_AUTOCOMMIT* = 102
+  SQL_ATTR_AUTOCOMMIT* = SQL_AUTOCOMMIT
+  SQL_ATTR_ROW_NUMBER* = SQL_ROW_NUMBER
+  SQL_TXN_ISOLATION* = 108
+  SQL_ATTR_TXN_ISOLATION* = SQL_TXN_ISOLATION
+  SQL_ATTR_MAX_ROWS* = SQL_MAX_ROWS
+  SQL_ATTR_USE_BOOKMARKS* = SQL_USE_BOOKMARKS #* connection attributes */
+  SQL_ACCESS_MODE* = 101      #  SQL_AUTOCOMMIT              =102;
+  SQL_LOGIN_TIMEOUT* = 103
+  SQL_OPT_TRACE* = 104
+  SQL_OPT_TRACEFILE* = 105
+  SQL_TRANSLATE_DLL* = 106
+  SQL_TRANSLATE_OPTION* = 107 #  SQL_TXN_ISOLATION           =108;
+  SQL_CURRENT_QUALIFIER* = 109 #  SQL_ODBC_CURSORS            =110;
+  SQL_QUIET_MODE* = 111
+  SQL_PACKET_SIZE* = 112      #* connection attributes with new names */
+  SQL_ATTR_ACCESS_MODE* = SQL_ACCESS_MODE #  SQL_ATTR_AUTOCOMMIT                       =SQL_AUTOCOMMIT;
+  SQL_ATTR_CONNECTION_DEAD* = 1209 #* GetConnectAttr only */
+  SQL_ATTR_CONNECTION_TIMEOUT* = 113
+  SQL_ATTR_CURRENT_CATALOG* = SQL_CURRENT_QUALIFIER
+  SQL_ATTR_DISCONNECT_BEHAVIOR* = 114
+  SQL_ATTR_ENLIST_IN_DTC* = 1207
+  SQL_ATTR_ENLIST_IN_XA* = 1208
+  SQL_ATTR_LOGIN_TIMEOUT* = SQL_LOGIN_TIMEOUT #  SQL_ATTR_ODBC_CURSORS             =SQL_ODBC_CURSORS;
+  SQL_ATTR_PACKET_SIZE* = SQL_PACKET_SIZE
+  SQL_ATTR_QUIET_MODE* = SQL_QUIET_MODE
+  SQL_ATTR_TRACE* = SQL_OPT_TRACE
+  SQL_ATTR_TRACEFILE* = SQL_OPT_TRACEFILE
+  SQL_ATTR_TRANSLATE_LIB* = SQL_TRANSLATE_DLL
+  SQL_ATTR_TRANSLATE_OPTION* = SQL_TRANSLATE_OPTION #  SQL_ATTR_TXN_ISOLATION                  =SQL_TXN_ISOLATION;
+                                                    #* SQL_ACCESS_MODE options */
+  SQL_MODE_READ_WRITE* = 0
+  SQL_MODE_READ_ONLY* = 1
+  SQL_MODE_DEFAULT* = SQL_MODE_READ_WRITE #* SQL_AUTOCOMMIT options */
+  SQL_AUTOCOMMIT_OFF* = 0
+  SQL_AUTOCOMMIT_ON* = 1
+  SQL_AUTOCOMMIT_DEFAULT* = SQL_AUTOCOMMIT_ON # SQL_ATTR_CURSOR_SCROLLABLE values 
+  SQL_NONSCROLLABLE* = 0
+  SQL_SCROLLABLE* = 1         # SQL_CURSOR_TYPE options 
+  SQL_CURSOR_FORWARD_ONLY* = 0
+  SQL_CURSOR_KEYSET_DRIVEN* = 1
+  SQL_CURSOR_DYNAMIC* = 2
+  SQL_CURSOR_STATIC* = 3
+  SQL_CURSOR_TYPE_DEFAULT* = SQL_CURSOR_FORWARD_ONLY # Default value 
+                                                     # SQL_CONCURRENCY options 
+  SQL_CONCUR_READ_ONLY* = 1
+  SQL_CONCUR_LOCK* = 2
+  SQL_CONCUR_ROWVER* = 3
+  SQL_CONCUR_VALUES* = 4
+  SQL_CONCUR_DEFAULT* = SQL_CONCUR_READ_ONLY # Default value 
+                                             # identifiers of fields in the SQL descriptor 
+  SQL_DESC_COUNT* = 1001
+  SQL_DESC_TYPE* = 1002
+  SQL_DESC_LENGTH* = 1003
+  SQL_DESC_OCTET_LENGTH_PTR* = 1004
+  SQL_DESC_PRECISION* = 1005
+  SQL_DESC_SCALE* = 1006
+  SQL_DESC_DATETIME_INTERVAL_CODE* = 1007
+  SQL_DESC_NULLABLE* = 1008
+  SQL_DESC_INDICATOR_PTR* = 1009
+  SQL_DESC_DATA_PTR* = 1010
+  SQL_DESC_NAME* = 1011
+  SQL_DESC_UNNAMED* = 1012
+  SQL_DESC_OCTET_LENGTH* = 1013
+  SQL_DESC_ALLOC_TYPE* = 1099 # identifiers of fields in the diagnostics area 
+  SQL_DIAG_RETURNCODE* = 1
+  SQL_DIAG_NUMBER* = 2
+  SQL_DIAG_ROW_COUNT* = 3
+  SQL_DIAG_SQLSTATE* = 4
+  SQL_DIAG_NATIVE* = 5
+  SQL_DIAG_MESSAGE_TEXT* = 6
+  SQL_DIAG_DYNAMIC_FUNCTION* = 7
+  SQL_DIAG_CLASS_ORIGIN* = 8
+  SQL_DIAG_SUBCLASS_ORIGIN* = 9
+  SQL_DIAG_CONNECTION_NAME* = 10
+  SQL_DIAG_SERVER_NAME* = 11
+  SQL_DIAG_DYNAMIC_FUNCTION_CODE* = 12 # dynamic function codes 
+  SQL_DIAG_ALTER_TABLE* = 4
+  SQL_DIAG_CREATE_INDEX* = (- 1)
+  SQL_DIAG_CREATE_TABLE* = 77
+  SQL_DIAG_CREATE_VIEW* = 84
+  SQL_DIAG_DELETE_WHERE* = 19
+  SQL_DIAG_DROP_INDEX* = (- 2)
+  SQL_DIAG_DROP_TABLE* = 32
+  SQL_DIAG_DROP_VIEW* = 36
+  SQL_DIAG_DYNAMIC_DELETE_CURSOR* = 38
+  SQL_DIAG_DYNAMIC_UPDATE_CURSOR* = 81
+  SQL_DIAG_GRANT* = 48
+  SQL_DIAG_INSERT* = 50
+  SQL_DIAG_REVOKE* = 59
+  SQL_DIAG_SELECT_CURSOR* = 85
+  SQL_DIAG_UNKNOWN_STATEMENT* = 0
+  SQL_DIAG_UPDATE_WHERE* = 82 # Statement attribute values for cursor sensitivity 
+  SQL_UNSPECIFIED* = 0
+  SQL_INSENSITIVE* = 1
+  SQL_SENSITIVE* = 2          # GetTypeInfo() request for all data types 
+  SQL_ALL_TYPES* = 0          # Default conversion code for SQLBindCol(), SQLBindParam() and SQLGetData() 
+  SQL_DEFAULT* = 99 # SQLGetData() code indicating that the application row descriptor
+                    #    specifies the data type 
+  SQL_ARD_TYPE* = (- 99)      # SQL date/time type subcodes 
+  SQL_CODE_DATE* = 1
+  SQL_CODE_TIME* = 2
+  SQL_CODE_TIMESTAMP* = 3     # CLI option values 
+  SQL_FALSE* = 0
+  SQL_TRUE* = 1               # values of NULLABLE field in descriptor 
+  SQL_NO_NULLS* = 0
+  SQL_NULLABLE* = 1 # Value returned by SQLGetTypeInfo() to denote that it is
+                    # not known whether or not a data type supports null values. 
+  SQL_NULLABLE_UNKNOWN* = 2 
+  SQL_CLOSE* = 0
+  SQL_DROP* = 1
+  SQL_UNBIND* = 2
+  SQL_RESET_PARAMS* = 3 # Codes used for FetchOrientation in SQLFetchScroll(),
+                        #   and in SQLDataSources() 
+  SQL_FETCH_NEXT* = 1
+  SQL_FETCH_FIRST* = 2
+  SQL_FETCH_FIRST_USER* = 31
+  SQL_FETCH_FIRST_SYSTEM* = 32 # Other codes used for FetchOrientation in SQLFetchScroll() 
+  SQL_FETCH_LAST* = 3
+  SQL_FETCH_PRIOR* = 4
+  SQL_FETCH_ABSOLUTE* = 5
+  SQL_FETCH_RELATIVE* = 6   
+  SQL_NULL_HENV* = TSqlHEnv(nil)
+  SQL_NULL_HDBC* = TSqlHDBC(nil)
+  SQL_NULL_HSTMT* = TSqlHStmt(nil)
+  SQL_NULL_HDESC* = TSqlHDesc(nil) #* null handle used in place of parent handle when allocating HENV */
+  SQL_NULL_HANDLE* = TSqlHandle(nil) #* Values that may appear in the result set of SQLSpecialColumns() */
+  SQL_SCOPE_CURROW* = 0
+  SQL_SCOPE_TRANSACTION* = 1
+  SQL_SCOPE_SESSION* = 2      #* Column types and scopes in SQLSpecialColumns.  */
+  SQL_BEST_ROWID* = 1
+  SQL_ROWVER* = 2             
+  SQL_ROW_IDENTIFIER* = 1     #* Reserved values for UNIQUE argument of SQLStatistics() */
+  SQL_INDEX_UNIQUE* = 0
+  SQL_INDEX_ALL* = 1          #* Reserved values for RESERVED argument of SQLStatistics() */
+  SQL_QUICK* = 0
+  SQL_ENSURE* = 1             #* Values that may appear in the result set of SQLStatistics() */
+  SQL_TABLE_STAT* = 0
+  SQL_INDEX_CLUSTERED* = 1
+  SQL_INDEX_HASHED* = 2
+  SQL_INDEX_OTHER* = 3 
+  SQL_SCROLL_CONCURRENCY* = 43
+  SQL_TXN_CAPABLE* = 46
+  SQL_TRANSACTION_CAPABLE* = SQL_TXN_CAPABLE
+  SQL_USER_NAME* = 47
+  SQL_TXN_ISOLATION_OPTION* = 72
+  SQL_TRANSACTION_ISOLATION_OPTION* = SQL_TXN_ISOLATION_OPTION 
+  SQL_OJ_CAPABILITIES* = 115
+  SQL_OUTER_JOIN_CAPABILITIES* = SQL_OJ_CAPABILITIES
+  SQL_XOPEN_CLI_YEAR* = 10000
+  SQL_CURSOR_SENSITIVITY* = 10001
+  SQL_DESCRIBE_PARAMETER* = 10002
+  SQL_CATALOG_NAME* = 10003
+  SQL_COLLATION_SEQ* = 10004
+  SQL_MAX_IDENTIFIER_LEN* = 10005
+  SQL_MAXIMUM_IDENTIFIER_LENGTH* = SQL_MAX_IDENTIFIER_LEN
+  SQL_SCCO_READ_ONLY* = 1
+  SQL_SCCO_LOCK* = 2
+  SQL_SCCO_OPT_ROWVER* = 4
+  SQL_SCCO_OPT_VALUES* = 8    #* SQL_TXN_CAPABLE values */
+  SQL_TC_NONE* = 0
+  SQL_TC_DML* = 1
+  SQL_TC_ALL* = 2
+  SQL_TC_DDL_COMMIT* = 3
+  SQL_TC_DDL_IGNORE* = 4      #* SQL_TXN_ISOLATION_OPTION bitmasks */
+  SQL_TXN_READ_UNCOMMITTED* = 1
+  SQL_TRANSACTION_READ_UNCOMMITTED* = SQL_TXN_READ_UNCOMMITTED
+  SQL_TXN_READ_COMMITTED* = 2
+  SQL_TRANSACTION_READ_COMMITTED* = SQL_TXN_READ_COMMITTED
+  SQL_TXN_REPEATABLE_READ* = 4
+  SQL_TRANSACTION_REPEATABLE_READ* = SQL_TXN_REPEATABLE_READ
+  SQL_TXN_SERIALIZABLE* = 8
+  SQL_TRANSACTION_SERIALIZABLE* = SQL_TXN_SERIALIZABLE 
+  SQL_SS_ADDITIONS* = 1
+  SQL_SS_DELETIONS* = 2
+  SQL_SS_UPDATES* = 4         # SQLColAttributes defines 
+  SQL_COLUMN_COUNT* = 0
+  SQL_COLUMN_NAME* = 1
+  SQL_COLUMN_TYPE* = 2
+  SQL_COLUMN_LENGTH* = 3
+  SQL_COLUMN_PRECISION* = 4
+  SQL_COLUMN_SCALE* = 5
+  SQL_COLUMN_DISPLAY_SIZE* = 6
+  SQL_COLUMN_NULLABLE* = 7
+  SQL_COLUMN_UNSIGNED* = 8
+  SQL_COLUMN_MONEY* = 9
+  SQL_COLUMN_UPDATABLE* = 10
+  SQL_COLUMN_AUTO_INCREMENT* = 11
+  SQL_COLUMN_CASE_SENSITIVE* = 12
+  SQL_COLUMN_SEARCHABLE* = 13
+  SQL_COLUMN_TYPE_NAME* = 14
+  SQL_COLUMN_TABLE_NAME* = 15
+  SQL_COLUMN_OWNER_NAME* = 16
+  SQL_COLUMN_QUALIFIER_NAME* = 17
+  SQL_COLUMN_LABEL* = 18
+  SQL_COLATT_OPT_MAX* = SQL_COLUMN_LABEL
+  SQL_COLUMN_DRIVER_START* = 1000
+  SQL_DESC_ARRAY_SIZE* = 20
+  SQL_DESC_ARRAY_STATUS_PTR* = 21
+  SQL_DESC_AUTO_UNIQUE_VALUE* = SQL_COLUMN_AUTO_INCREMENT
+  SQL_DESC_BASE_COLUMN_NAME* = 22
+  SQL_DESC_BASE_TABLE_NAME* = 23
+  SQL_DESC_BIND_OFFSET_PTR* = 24
+  SQL_DESC_BIND_TYPE* = 25
+  SQL_DESC_CASE_SENSITIVE* = SQL_COLUMN_CASE_SENSITIVE
+  SQL_DESC_CATALOG_NAME* = SQL_COLUMN_QUALIFIER_NAME
+  SQL_DESC_CONCISE_TYPE* = SQL_COLUMN_TYPE
+  SQL_DESC_DATETIME_INTERVAL_PRECISION* = 26
+  SQL_DESC_DISPLAY_SIZE* = SQL_COLUMN_DISPLAY_SIZE
+  SQL_DESC_FIXED_PREC_SCALE* = SQL_COLUMN_MONEY
+  SQL_DESC_LABEL* = SQL_COLUMN_LABEL
+  SQL_DESC_LITERAL_PREFIX* = 27
+  SQL_DESC_LITERAL_SUFFIX* = 28
+  SQL_DESC_LOCAL_TYPE_NAME* = 29
+  SQL_DESC_MAXIMUM_SCALE* = 30
+  SQL_DESC_MINIMUM_SCALE* = 31
+  SQL_DESC_NUM_PREC_RADIX* = 32
+  SQL_DESC_PARAMETER_TYPE* = 33
+  SQL_DESC_ROWS_PROCESSED_PTR* = 34
+  SQL_DESC_SCHEMA_NAME* = SQL_COLUMN_OWNER_NAME
+  SQL_DESC_SEARCHABLE* = SQL_COLUMN_SEARCHABLE
+  SQL_DESC_TYPE_NAME* = SQL_COLUMN_TYPE_NAME
+  SQL_DESC_TABLE_NAME* = SQL_COLUMN_TABLE_NAME
+  SQL_DESC_UNSIGNED* = SQL_COLUMN_UNSIGNED
+  SQL_DESC_UPDATABLE* = SQL_COLUMN_UPDATABLE #* SQLEndTran() options */
+  SQL_COMMIT* = 0
+  SQL_ROLLBACK* = 1
+  SQL_ATTR_ROW_ARRAY_SIZE* = 27 #* SQLConfigDataSource() options */
+  ODBC_ADD_DSN* = 1
+  ODBC_CONFIG_DSN* = 2
+  ODBC_REMOVE_DSN* = 3
+  ODBC_ADD_SYS_DSN* = 4
+  ODBC_CONFIG_SYS_DSN* = 5
+  ODBC_REMOVE_SYS_DSN* = 6
+
+proc SQLAllocHandle*(HandleType: TSqlSmallInt, InputHandle: TSqlHandle, 
+                     OutputHandlePtr: var TSqlHandle): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLSetEnvAttr*(EnvironmentHandle: TSqlHEnv, Attribute: TSqlInteger, 
+                    Value: TSqlPointer, StringLength: TSqlInteger): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLGetEnvAttr*(EnvironmentHandle: TSqlHEnv, Attribute: TSqlInteger, 
+                    Value: TSqlPointer, BufferLength: TSqlInteger, 
+                    StringLength: PSQLINTEGER): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLFreeHandle*(HandleType: TSqlSmallInt, Handle: TSqlHandle): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLGetDiagRec*(HandleType: TSqlSmallInt, Handle: TSqlHandle, 
+                    RecNumber: TSqlSmallInt, Sqlstate: PSQLCHAR, 
+                    NativeError: var TSqlInteger, MessageText: PSQLCHAR, 
+                    BufferLength: TSqlSmallInt, TextLength: var TSqlSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLGetDiagField*(HandleType: TSqlSmallInt, Handle: TSqlHandle, 
+                      RecNumber: TSqlSmallInt, DiagIdentifier: TSqlSmallInt, 
+                      DiagInfoPtr: TSqlPointer, BufferLength: TSqlSmallInt, 
+                      StringLengthPtr: var TSqlSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLConnect*(ConnectionHandle: TSqlHDBC, ServerName: PSQLCHAR, 
+                 NameLength1: TSqlSmallInt, UserName: PSQLCHAR, 
+                 NameLength2: TSqlSmallInt, Authentication: PSQLCHAR, 
+                 NameLength3: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLDisconnect*(ConnectionHandle: TSqlHDBC): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLDriverConnect*(hdbc: TSqlHDBC, hwnd: TSqlHWND, szCsin: cstring, 
+                       szCLen: TSqlSmallInt, szCsout: cstring, 
+                       cbCSMax: TSqlSmallInt, cbCsOut: var TSqlSmallInt, 
+                       f: TSqlUSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLBrowseConnect*(hdbc: TSqlHDBC, szConnStrIn: PSQLCHAR, 
+                       cbConnStrIn: TSqlSmallInt, szConnStrOut: PSQLCHAR, 
+                       cbConnStrOutMax: TSqlSmallInt, 
+                       cbConnStrOut: var TSqlSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLExecDirect*(StatementHandle: TSqlHStmt, StatementText: PSQLCHAR, 
+                    TextLength: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLPrepare*(StatementHandle: TSqlHStmt, StatementText: PSQLCHAR, 
+                 TextLength: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLCloseCursor*(StatementHandle: TSqlHStmt): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLExecute*(StatementHandle: TSqlHStmt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLFetch*(StatementHandle: TSqlHStmt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLNumResultCols*(StatementHandle: TSqlHStmt, ColumnCount: var TSqlSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLDescribeCol*(StatementHandle: TSqlHStmt, ColumnNumber: TSqlUSmallInt, 
+                     ColumnName: PSQLCHAR, BufferLength: TSqlSmallInt, 
+                     NameLength: var TSqlSmallInt, DataType: var TSqlSmallInt, 
+                     ColumnSize: var TSqlUInteger, 
+                     DecimalDigits: var TSqlSmallInt, Nullable: var TSqlSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLFetchScroll*(StatementHandle: TSqlHStmt, FetchOrientation: TSqlSmallInt, 
+                     FetchOffset: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLExtendedFetch*(hstmt: TSqlHStmt, fFetchType: TSqlUSmallInt, 
+                       irow: TSqlInteger, pcrow: PSQLUINTEGER, 
+                       rgfRowStatus: PSQLUSMALLINT): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLGetData*(StatementHandle: TSqlHStmt, ColumnNumber: TSqlUSmallInt, 
+                 TargetType: TSqlSmallInt, TargetValue: TSqlPointer, 
+                 BufferLength: TSqlInteger, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLSetStmtAttr*(StatementHandle: TSqlHStmt, Attribute: TSqlInteger, 
+                     Value: TSqlPointer, StringLength: TSqlInteger): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLGetStmtAttr*(StatementHandle: TSqlHStmt, Attribute: TSqlInteger, 
+                     Value: TSqlPointer, BufferLength: TSqlInteger, 
+                     StringLength: PSQLINTEGER): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLGetInfo*(ConnectionHandle: TSqlHDBC, InfoType: TSqlUSmallInt, 
+                 InfoValue: TSqlPointer, BufferLength: TSqlSmallInt, 
+                 StringLength: PSQLSMALLINT): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLBulkOperations*(StatementHandle: TSqlHStmt, Operation: TSqlSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLPutData*(StatementHandle: TSqlHStmt, Data: TSqlPointer, 
+                 StrLen_or_Ind: TSqlInteger): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLBindCol*(StatementHandle: TSqlHStmt, ColumnNumber: TSqlUSmallInt, 
+                 TargetType: TSqlSmallInt, TargetValue: TSqlPointer, 
+                 BufferLength: TSqlInteger, StrLen_or_Ind: PSQLINTEGER): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLSetPos*(hstmt: TSqlHStmt, irow: TSqlUSmallInt, fOption: TSqlUSmallInt, 
+                fLock: TSqlUSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLDataSources*(EnvironmentHandle: TSqlHEnv, Direction: TSqlUSmallInt, 
+                     ServerName: PSQLCHAR, BufferLength1: TSqlSmallInt, 
+                     NameLength1: PSQLSMALLINT, Description: PSQLCHAR, 
+                     BufferLength2: TSqlSmallInt, NameLength2: PSQLSMALLINT): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLDrivers*(EnvironmentHandle: TSqlHEnv, Direction: TSqlUSmallInt, 
+                 DriverDescription: PSQLCHAR, BufferLength1: TSqlSmallInt, 
+                 DescriptionLength1: PSQLSMALLINT, DriverAttributes: PSQLCHAR, 
+                 BufferLength2: TSqlSmallInt, AttributesLength2: PSQLSMALLINT): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLSetConnectAttr*(ConnectionHandle: TSqlHDBC, Attribute: TSqlInteger, 
+                        Value: TSqlPointer, StringLength: TSqlInteger): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLGetCursorName*(StatementHandle: TSqlHStmt, CursorName: PSQLCHAR, 
+                       BufferLength: TSqlSmallInt, NameLength: PSQLSMALLINT): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLSetCursorName*(StatementHandle: TSqlHStmt, CursorName: PSQLCHAR, 
+                       NameLength: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLRowCount*(StatementHandle: TSqlHStmt, RowCount: var TSqlInteger): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLBindParameter*(hstmt: TSqlHStmt, ipar: TSqlUSmallInt, 
+                       fParamType: TSqlSmallInt, fCType: TSqlSmallInt, 
+                       fSqlType: TSqlSmallInt, cbColDef: TSqlUInteger, 
+                       ibScale: TSqlSmallInt, rgbValue: TSqlPointer, 
+                       cbValueMax: TSqlInteger, pcbValue: PSQLINTEGER): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLFreeStmt*(StatementHandle: TSqlHStmt, Option: TSqlUSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLColAttribute*(StatementHandle: TSqlHStmt, ColumnNumber: TSqlUSmallInt, 
+                      FieldIdentifier: TSqlUSmallInt, 
+                      CharacterAttribute: PSQLCHAR, BufferLength: TSqlSmallInt, 
+                      StringLength: PSQLSMALLINT, 
+                      NumericAttribute: TSqlPointer): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLEndTran*(HandleType: TSqlSmallInt, Handle: TSqlHandle, 
+                 CompletionType: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLTables*(hstmt: TSqlHStmt, szTableQualifier: PSQLCHAR, 
+                cbTableQualifier: TSqlSmallInt, szTableOwner: PSQLCHAR, 
+                cbTableOwner: TSqlSmallInt, szTableName: PSQLCHAR, 
+                cbTableName: TSqlSmallInt, szTableType: PSQLCHAR, 
+                cbTableType: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLColumns*(hstmt: TSqlHStmt, szTableQualifier: PSQLCHAR, 
+                 cbTableQualifier: TSqlSmallInt, szTableOwner: PSQLCHAR, 
+                 cbTableOwner: TSqlSmallInt, szTableName: PSQLCHAR, 
+                 cbTableName: TSqlSmallInt, szColumnName: PSQLCHAR, 
+                 cbColumnName: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, importc.}
+proc SQLSpecialColumns*(StatementHandle: TSqlHStmt, IdentifierType: TSqlUSmallInt, 
+                        CatalogName: PSQLCHAR, NameLength1: TSqlSmallInt, 
+                        SchemaName: PSQLCHAR, NameLength2: TSqlSmallInt, 
+                        TableName: PSQLCHAR, NameLength3: TSqlSmallInt, 
+                        Scope: TSqlUSmallInt, 
+                        Nullable: TSqlUSmallInt): TSqlSmallInt{.
+    dynlib: odbclib, importc.}
+proc SQLProcedures*(hstmt: TSqlHStmt, szTableQualifier: PSQLCHAR, 
+                    cbTableQualifier: TSqlSmallInt, szTableOwner: PSQLCHAR, 
+                    cbTableOwner: TSqlSmallInt, szTableName: PSQLCHAR, 
+                    cbTableName: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLPrimaryKeys*(hstmt: TSqlHStmt, CatalogName: PSQLCHAR, 
+                     NameLength1: TSqlSmallInt, SchemaName: PSQLCHAR, 
+                     NameLength2: TSqlSmallInt, TableName: PSQLCHAR, 
+                     NameLength3: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLProcedureColumns*(hstmt: TSqlHStmt, CatalogName: PSQLCHAR, 
+                          NameLength1: TSqlSmallInt, SchemaName: PSQLCHAR, 
+                          NameLength2: TSqlSmallInt, ProcName: PSQLCHAR, 
+                          NameLength3: TSqlSmallInt, ColumnName: PSQLCHAR, 
+                          NameLength4: TSqlSmallInt): TSqlSmallInt{.dynlib: odbclib, 
+    importc.}
+proc SQLStatistics*(hstmt: TSqlHStmt, CatalogName: PSQLCHAR, 
+                    NameLength1: TSqlSmallInt, SchemaName: PSQLCHAR, 
+                    NameLength2: TSqlSmallInt, TableName: PSQLCHAR, 
+                    NameLength3: TSqlSmallInt, Unique: TSqlUSmallInt, 
+                    Reserved: TSqlUSmallInt): TSqlSmallInt {.
+                    dynlib: odbclib, importc.}
+
+{.pop.}
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
new file mode 100644
index 000000000..03729dbab
--- /dev/null
+++ b/lib/wrappers/openssl.nim
@@ -0,0 +1,576 @@
+#==============================================================================#
+# Project: Ararat Synapse                                        | 003.004.001 #
+#==============================================================================#
+# Content: SSL support by OpenSSL                                              #
+#==============================================================================#
+# Copyright (c)1999-2005, Lukas Gebauer                                        #
+# All rights reserved.                                                         #
+#                                                                              #
+# Redistribution and use in source and binary forms, with or without           #
+# modification, are permitted provided that the following conditions are met:  #
+#                                                                              #
+# Redistributions of source code must retain the above copyright notice, this  #
+# list of conditions and the following disclaimer.                             #
+#                                                                              #
+# Redistributions in binary form must reproduce the above copyright notice,    #
+# this list of conditions and the following disclaimer in the documentation    #
+# and/or other materials provided with the distribution.                       #
+#                                                                              #
+# Neither the name of Lukas Gebauer nor the names of its contributors may      #
+# be used to endorse or promote products derived from this software without    #
+# specific prior written permission.                                           #
+#                                                                              #
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  #
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE    #
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE   #
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR  #
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL       #
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR   #
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER   #
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT           #
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY    #
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  #
+# DAMAGE.                                                                      #
+#==============================================================================#
+# The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).#
+# Portions created by Lukas Gebauer are Copyright (c)2002-2005.                #
+# All Rights Reserved.                                                         #
+#==============================================================================#
+
+## OpenSSL support
+
+{.deadCodeElim: on.}
+
+const useWinVersion = defined(Windows) or defined(nimdoc)
+
+when useWinVersion: 
+  const 
+    DLLSSLName = "(ssleay32|libssl32).dll"
+    DLLUtilName = "libeay32.dll"
+  from winlean import SocketHandle
+else:
+  const
+    versions = "(.10|.1.0.1|.1.0.0|.0.9.9|.0.9.8)"
+  when defined(macosx):
+    const
+      DLLSSLName = "libssl" & versions & ".dylib"
+      DLLUtilName = "libcrypto" & versions & ".dylib"
+  else:
+    const 
+      DLLSSLName = "libssl.so" & versions
+      DLLUtilName = "libcrypto.so" & versions
+  from posix import SocketHandle
+
+type 
+  SslStruct {.final, pure.} = object
+  SslPtr* = ptr SslStruct
+  PSslPtr* = ptr SslPtr
+  SslCtx* = SslPtr
+  PSSL_METHOD* = SslPtr
+  PX509* = SslPtr
+  PX509_NAME* = SslPtr
+  PEVP_MD* = SslPtr
+  PBIO_METHOD* = SslPtr
+  BIO* = SslPtr
+  EVP_PKEY* = SslPtr
+  PRSA* = SslPtr
+  PASN1_UTCTIME* = SslPtr
+  PASN1_cInt* = SslPtr
+  PPasswdCb* = SslPtr
+  PFunction* = proc () {.cdecl.}
+  DES_cblock* = array[0..7, int8]
+  PDES_cblock* = ptr DES_cblock
+  des_ks_struct*{.final.} = object 
+    ks*: DES_cblock
+    weak_key*: cInt
+
+  des_key_schedule* = array[1..16, des_ks_struct]
+
+{.deprecated: [PSSL: SslPtr, PSSL_CTX: SslCtx, PBIO: BIO].}
+
+const 
+  SSL_SENT_SHUTDOWN* = 1
+  SSL_RECEIVED_SHUTDOWN* = 2
+  EVP_MAX_MD_SIZE* = 16 + 20
+  SSL_ERROR_NONE* = 0
+  SSL_ERROR_SSL* = 1
+  SSL_ERROR_WANT_READ* = 2
+  SSL_ERROR_WANT_WRITE* = 3
+  SSL_ERROR_WANT_X509_LOOKUP* = 4
+  SSL_ERROR_SYSCALL* = 5      #look at error stack/return value/errno
+  SSL_ERROR_ZERO_RETURN* = 6
+  SSL_ERROR_WANT_CONNECT* = 7
+  SSL_ERROR_WANT_ACCEPT* = 8
+  SSL_CTRL_NEED_TMP_RSA* = 1
+  SSL_CTRL_SET_TMP_RSA* = 2
+  SSL_CTRL_SET_TMP_DH* = 3
+  SSL_CTRL_SET_TMP_ECDH* = 4
+  SSL_CTRL_SET_TMP_RSA_CB* = 5
+  SSL_CTRL_SET_TMP_DH_CB* = 6
+  SSL_CTRL_SET_TMP_ECDH_CB* = 7
+  SSL_CTRL_GET_SESSION_REUSED* = 8
+  SSL_CTRL_GET_CLIENT_CERT_REQUEST* = 9
+  SSL_CTRL_GET_NUM_RENEGOTIATIONS* = 10
+  SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS* = 11
+  SSL_CTRL_GET_TOTAL_RENEGOTIATIONS* = 12
+  SSL_CTRL_GET_FLAGS* = 13
+  SSL_CTRL_EXTRA_CHAIN_CERT* = 14
+  SSL_CTRL_SET_MSG_CALLBACK* = 15
+  SSL_CTRL_SET_MSG_CALLBACK_ARG* = 16 # only applies to datagram connections  
+  SSL_CTRL_SET_MTU* = 17      # Stats  
+  SSL_CTRL_SESS_NUMBER* = 20
+  SSL_CTRL_SESS_CONNECT* = 21
+  SSL_CTRL_SESS_CONNECT_GOOD* = 22
+  SSL_CTRL_SESS_CONNECT_RENEGOTIATE* = 23
+  SSL_CTRL_SESS_ACCEPT* = 24
+  SSL_CTRL_SESS_ACCEPT_GOOD* = 25
+  SSL_CTRL_SESS_ACCEPT_RENEGOTIATE* = 26
+  SSL_CTRL_SESS_HIT* = 27
+  SSL_CTRL_SESS_CB_HIT* = 28
+  SSL_CTRL_SESS_MISSES* = 29
+  SSL_CTRL_SESS_TIMEOUTS* = 30
+  SSL_CTRL_SESS_CACHE_FULL* = 31
+  SSL_CTRL_OPTIONS* = 32
+  SSL_CTRL_MODE* = 33
+  SSL_CTRL_GET_READ_AHEAD* = 40
+  SSL_CTRL_SET_READ_AHEAD* = 41
+  SSL_CTRL_SET_SESS_CACHE_SIZE* = 42
+  SSL_CTRL_GET_SESS_CACHE_SIZE* = 43
+  SSL_CTRL_SET_SESS_CACHE_MODE* = 44
+  SSL_CTRL_GET_SESS_CACHE_MODE* = 45
+  SSL_CTRL_GET_MAX_CERT_LIST* = 50
+  SSL_CTRL_SET_MAX_CERT_LIST* = 51 #* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
+                                   # * when just a single record has been written): *
+  SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53
+  SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG = 54
+  SSL_CTRL_SET_TLSEXT_HOSTNAME = 55
+  TLSEXT_NAMETYPE_host_name* = 0
+  SSL_TLSEXT_ERR_OK* = 0
+  SSL_TLSEXT_ERR_ALERT_WARNING* = 1
+  SSL_TLSEXT_ERR_ALERT_FATAL* = 2
+  SSL_TLSEXT_ERR_NOACK* = 3
+  SSL_MODE_ENABLE_PARTIAL_WRITE* = 1 #* Make it possible to retry SSL_write() with changed buffer location
+                                     # * (buffer contents must stay the same!); this is not the default to avoid
+                                     # * the misconception that non-blocking SSL_write() behaves like
+                                     # * non-blocking write(): *
+  SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER* = 2 #* Never bother the application with retries if the transport
+                                           # * is blocking: *
+  SSL_MODE_AUTO_RETRY* = 4    #* Don't attempt to automatically build certificate chain *
+  SSL_MODE_NO_AUTO_CHAIN* = 8
+  SSL_OP_NO_SSLv2* = 0x01000000
+  SSL_OP_NO_SSLv3* = 0x02000000
+  SSL_OP_NO_TLSv1* = 0x04000000
+  SSL_OP_ALL* = 0x000FFFFF
+  SSL_VERIFY_NONE* = 0x00000000
+  SSL_VERIFY_PEER* = 0x00000001
+  OPENSSL_DES_DECRYPT* = 0
+  OPENSSL_DES_ENCRYPT* = 1
+  X509_V_OK* = 0
+  X509_V_ILLEGAL* = 1
+  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT* = 2
+  X509_V_ERR_UNABLE_TO_GET_CRL* = 3
+  X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE* = 4
+  X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE* = 5
+  X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY* = 6
+  X509_V_ERR_CERT_SIGNATURE_FAILURE* = 7
+  X509_V_ERR_CRL_SIGNATURE_FAILURE* = 8
+  X509_V_ERR_CERT_NOT_YET_VALID* = 9
+  X509_V_ERR_CERT_HAS_EXPIRED* = 10
+  X509_V_ERR_CRL_NOT_YET_VALID* = 11
+  X509_V_ERR_CRL_HAS_EXPIRED* = 12
+  X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD* = 13
+  X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD* = 14
+  X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD* = 15
+  X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD* = 16
+  X509_V_ERR_OUT_OF_MEM* = 17
+  X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT* = 18
+  X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN* = 19
+  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY* = 20
+  X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE* = 21
+  X509_V_ERR_CERT_CHAIN_TOO_LONG* = 22
+  X509_V_ERR_CERT_REVOKED* = 23
+  X509_V_ERR_INVALID_CA* = 24
+  X509_V_ERR_PATH_LENGTH_EXCEEDED* = 25
+  X509_V_ERR_INVALID_PURPOSE* = 26
+  X509_V_ERR_CERT_UNTRUSTED* = 27
+  X509_V_ERR_CERT_REJECTED* = 28 #These are 'informational' when looking for issuer cert
+  X509_V_ERR_SUBJECT_ISSUER_MISMATCH* = 29
+  X509_V_ERR_AKID_SKID_MISMATCH* = 30
+  X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH* = 31
+  X509_V_ERR_KEYUSAGE_NO_CERTSIGN* = 32
+  X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER* = 33
+  X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION* = 34 #The application is not happy
+  X509_V_ERR_APPLICATION_VERIFICATION* = 50
+  SSL_FILETYPE_ASN1* = 2
+  SSL_FILETYPE_PEM* = 1
+  EVP_PKEY_RSA* = 6           # libssl.dll
+  
+  BIO_C_SET_CONNECT = 100
+  BIO_C_DO_STATE_MACHINE = 101
+  BIO_C_GET_SSL = 110
+
+proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc, discardable.}
+proc SSL_load_error_strings*(){.cdecl, dynlib: DLLSSLName, importc.}
+proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.}
+
+proc SSLv23_client_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSLv23_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSLv2_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSLv3_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_new*(meth: PSSL_METHOD): SslCtx{.cdecl,
+    dynlib: DLLSSLName, importc.}
+proc SSL_CTX_load_verify_locations*(ctx: SslCtx, CAfile: cstring,
+    CApath: cstring): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_free*(arg0: SslCtx){.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_set_verify*(s: SslCtx, mode: int, cb: proc (a: int, b: pointer): int {.cdecl.}){.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_get_verify_result*(ssl: SslPtr): int{.cdecl,
+    dynlib: DLLSSLName, importc.}
+
+proc SSL_CTX_set_cipher_list*(s: SslCtx, ciphers: cstring): cint{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_use_certificate_file*(ctx: SslCtx, filename: cstring, typ: cInt): cInt{.
+    stdcall, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_use_certificate_chain_file*(ctx: SslCtx, filename: cstring): cInt{.
+    stdcall, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_use_PrivateKey_file*(ctx: SslCtx,
+    filename: cstring, typ: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_CTX_check_private_key*(ctx: SslCtx): cInt{.cdecl, dynlib: DLLSSLName, 
+    importc.}
+
+proc SSL_set_fd*(ssl: SslPtr, fd: SocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSL_shutdown*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_set_shutdown*(ssl: SslPtr, mode: cint) {.cdecl, dynlib: DLLSSLName, importc: "SSL_set_shutdown".}
+proc SSL_get_shutdown*(ssl: SslPtr): cint {.cdecl, dynlib: DLLSSLName, importc: "SSL_get_shutdown".}
+proc SSL_connect*(ssl: SslPtr): cint{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_read*(ssl: SslPtr, buf: pointer, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_write*(ssl: SslPtr, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_get_error*(s: SslPtr, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_accept*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+proc SSL_pending*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+
+proc BIO_new_ssl_connect*(ctx: SslCtx): BIO{.cdecl,
+    dynlib: DLLSSLName, importc.}
+proc BIO_ctrl*(bio: BIO, cmd: cint, larg: int, arg: cstring): int{.cdecl,
+    dynlib: DLLSSLName, importc.}
+proc BIO_get_ssl*(bio: BIO, ssl: ptr SslPtr): int = 
+  return BIO_ctrl(bio, BIO_C_GET_SSL, 0, cast[cstring](ssl))
+proc BIO_set_conn_hostname*(bio: BIO, name: cstring): int =
+  return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, name)
+proc BIO_do_handshake*(bio: BIO): int =
+  return BIO_ctrl(bio, BIO_C_DO_STATE_MACHINE, 0, nil)
+proc BIO_do_connect*(bio: BIO): int =
+  return BIO_do_handshake(bio)
+
+when not defined(nimfix):
+  proc BIO_read*(b: BIO, data: cstring, length: cInt): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc BIO_write*(b: BIO, data: cstring, length: cInt): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+
+proc BIO_free*(b: BIO): cInt{.cdecl, dynlib: DLLUtilName, importc.}
+
+proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLSSLName, importc.}
+
+proc ERR_error_string*(e: cInt, buf: cstring): cstring{.cdecl, 
+    dynlib: DLLUtilName, importc.}
+proc ERR_get_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
+proc ERR_peek_last_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.}
+
+proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSSL_add_all_algorithms_conf".}
+
+proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.}
+
+when not useWinVersion:
+  proc CRYPTO_set_mem_functions(a,b,c: pointer){.cdecl, 
+    dynlib: DLLUtilName, importc.}
+
+  proc allocWrapper(size: int): pointer {.cdecl.} = alloc(size)
+  proc reallocWrapper(p: pointer; newsize: int): pointer {.cdecl.} =
+    if p == nil:
+      if newSize > 0: result = alloc(newsize)
+    elif newsize == 0: dealloc(p)
+    else: result = realloc(p, newsize)
+  proc deallocWrapper(p: pointer) {.cdecl.} =
+    if p != nil: dealloc(p)
+
+proc CRYPTO_malloc_init*() =
+  when not useWinVersion and not defined(macosx):
+    CRYPTO_set_mem_functions(allocWrapper, reallocWrapper, deallocWrapper)
+
+proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSL_CTX_callback_ctrl(ctx: SslCtx, typ: cInt, fp: PFunction): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int =
+  result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil)
+
+proc SSL_ctrl*(ssl: SslPtr, cmd: cInt, larg: int, parg: pointer): int{.
+  cdecl, dynlib: DLLSSLName, importc.}
+
+proc SSL_set_tlsext_host_name*(ssl: SslPtr, name: cstring): int =
+  result = SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name)
+  ## Set the SNI server name extension to be used in a client hello.
+  ## Returns 1 if SNI was set, 0 if current SSL configuration doesn't support SNI.
+
+
+proc SSL_get_servername*(ssl: SslPtr, typ: cInt = TLSEXT_NAMETYPE_host_name): cstring {.cdecl, dynlib: DLLSSLName, importc.}
+  ## Retrieve the server name requested in the client hello. This can be used
+  ## in the callback set in `SSL_CTX_set_tlsext_servername_callback` to
+  ## implement virtual hosting. May return `nil`.
+
+proc SSL_CTX_set_tlsext_servername_callback*(ctx: SslCtx, cb: proc(ssl: SslPtr, cb_id: int, arg: pointer): int {.cdecl.}): int =
+  ## Set the callback to be used on listening SSL connections when the client hello is received.
+  ##
+  ## The callback should return one of:
+  ## * SSL_TLSEXT_ERR_OK
+  ## * SSL_TLSEXT_ERR_ALERT_WARNING
+  ## * SSL_TLSEXT_ERR_ALERT_FATAL
+  ## * SSL_TLSEXT_ERR_NOACK
+  result = SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast[PFunction](cb))
+
+proc SSL_CTX_set_tlsext_servername_arg*(ctx: SslCtx, arg: pointer): int =
+  ## Set the pointer to be used in the callback registered to ``SSL_CTX_set_tlsext_servername_callback``.
+  result = SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, arg)
+
+
+proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".}
+proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".}
+proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".}
+proc bioCtrlPending*(b: BIO): cInt{.cdecl, dynlib: DLLUtilName, importc: "BIO_ctrl_pending".}
+proc bioRead*(b: BIO, Buf: cstring, length: cInt): cInt{.cdecl,
+    dynlib: DLLUtilName, importc: "BIO_read".}
+proc bioWrite*(b: BIO, Buf: cstring, length: cInt): cInt{.cdecl,
+    dynlib: DLLUtilName, importc: "BIO_write".}
+
+proc sslSetConnectState*(s: SslPtr) {.cdecl,
+    dynlib: DLLSSLName, importc: "SSL_set_connect_state".}
+proc sslSetAcceptState*(s: SslPtr) {.cdecl,
+    dynlib: DLLSSLName, importc: "SSL_set_accept_state".}
+
+proc sslRead*(ssl: SslPtr, buf: cstring, num: cInt): cInt{.cdecl,
+      dynlib: DLLSSLName, importc: "SSL_read".}
+proc sslPeek*(ssl: SslPtr, buf: cstring, num: cInt): cInt{.cdecl,
+    dynlib: DLLSSLName, importc: "SSL_peek".}
+proc sslWrite*(ssl: SslPtr, buf: cstring, num: cInt): cInt{.cdecl,
+    dynlib: DLLSSLName, importc: "SSL_write".}
+
+proc sslSetBio*(ssl: SslPtr, rbio, wbio: BIO) {.cdecl,
+    dynlib: DLLSSLName, importc: "SSL_set_bio".}
+
+proc sslDoHandshake*(ssl: SslPtr): cint {.cdecl,
+    dynlib: DLLSSLName, importc: "SSL_do_handshake".}
+
+
+
+proc ErrClearError*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_clear_error".}
+proc ErrFreeStrings*(){.cdecl, dynlib: DLLUtilName, importc: "ERR_free_strings".}
+proc ErrRemoveState*(pid: cInt){.cdecl, dynlib: DLLUtilName, importc: "ERR_remove_state".}
+
+when true:
+  discard
+else:
+  proc SslCtxSetCipherList*(arg0: PSSL_CTX, str: cstring): cInt{.cdecl, 
+      dynlib: DLLSSLName, importc.}
+  proc SslCtxNew*(meth: PSSL_METHOD): PSSL_CTX{.cdecl,
+      dynlib: DLLSSLName, importc.}
+
+  proc SslSetFd*(s: PSSL, fd: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SslCTXCtrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: Pointer): int{.
+      cdecl, dynlib: DLLSSLName, importc.}
+
+  proc SSLSetMode*(s: PSSL, mode: int): int
+  proc SSLCTXGetMode*(ctx: PSSL_CTX): int
+  proc SSLGetMode*(s: PSSL): int
+  proc SslMethodV2*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SslMethodV3*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SslMethodTLSV1*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SslMethodV23*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SslCtxUsePrivateKey*(ctx: PSSL_CTX, pkey: SslPtr): cInt{.cdecl, 
+      dynlib: DLLSSLName, importc.}
+  proc SslCtxUsePrivateKeyASN1*(pk: cInt, ctx: PSSL_CTX,
+      d: cstring, length: int): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+
+  proc SslCtxUseCertificate*(ctx: PSSL_CTX, x: SslPtr): cInt{.cdecl, 
+      dynlib: DLLSSLName, importc.}
+  proc SslCtxUseCertificateASN1*(ctx: PSSL_CTX, length: int, d: cstring): cInt{.
+      cdecl, dynlib: DLLSSLName, importc.}
+
+    #  function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const filename: PChar):cInt;
+  proc SslCtxUseCertificateChainFile*(ctx: PSSL_CTX, filename: cstring): cInt{.
+      cdecl, dynlib: DLLSSLName, importc.}
+  proc SslCtxSetDefaultPasswdCb*(ctx: PSSL_CTX, cb: PPasswdCb){.cdecl, 
+      dynlib: DLLSSLName, importc.}
+  proc SslCtxSetDefaultPasswdCbUserdata*(ctx: PSSL_CTX, u: SslPtr){.cdecl, 
+      dynlib: DLLSSLName, importc.}
+    #  function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):cInt;
+  proc SslCtxLoadVerifyLocations*(ctx: PSSL_CTX, CAfile: cstring, CApath: cstring): cInt{.
+      cdecl, dynlib: DLLSSLName, importc.}
+  proc SslNew*(ctx: PSSL_CTX): PSSL{.cdecl, dynlib: DLLSSLName, importc.}
+
+
+  proc SslConnect*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.}
+
+  
+  proc SslGetVersion*(ssl: PSSL): cstring{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SslGetPeerCertificate*(ssl: PSSL): PX509{.cdecl, dynlib: DLLSSLName, 
+      importc.}
+  proc SslCtxSetVerify*(ctx: PSSL_CTX, mode: cInt, arg2: PFunction){.cdecl, 
+      dynlib: DLLSSLName, importc.}
+  proc SSLGetCurrentCipher*(s: PSSL): SslPtr{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SSLCipherGetName*(c: SslPtr): cstring{.cdecl, dynlib: DLLSSLName, importc.}
+  proc SSLCipherGetBits*(c: SslPtr, alg_bits: var cInt): cInt{.cdecl, 
+      dynlib: DLLSSLName, importc.}
+  proc SSLGetVerifyResult*(ssl: PSSL): int{.cdecl, dynlib: DLLSSLName, importc.}
+    # libeay.dll
+  proc X509New*(): PX509{.cdecl, dynlib: DLLUtilName, importc.}
+  proc X509Free*(x: PX509){.cdecl, dynlib: DLLUtilName, importc.}
+  proc X509NameOneline*(a: PX509_NAME, buf: cstring, size: cInt): cstring{.
+      cdecl, dynlib: DLLUtilName, importc.}
+  proc X509GetSubjectName*(a: PX509): PX509_NAME{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc X509GetIssuerName*(a: PX509): PX509_NAME{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc X509NameHash*(x: PX509_NAME): int{.cdecl, dynlib: DLLUtilName, importc.}
+    #  function SslX509Digest(data: PX509; typ: PEVP_MD; md: PChar; len: PcInt):cInt;
+  proc X509Digest*(data: PX509, typ: PEVP_MD, md: cstring, length: var cInt): cInt{.
+      cdecl, dynlib: DLLUtilName, importc.}
+  proc X509print*(b: PBIO, a: PX509): cInt{.cdecl, dynlib: DLLUtilName, importc.}
+  proc X509SetVersion*(x: PX509, version: cInt): cInt{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc X509SetPubkey*(x: PX509, pkey: EVP_PKEY): cInt{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc X509SetIssuerName*(x: PX509, name: PX509_NAME): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc X509NameAddEntryByTxt*(name: PX509_NAME, field: cstring, typ: cInt, 
+                              bytes: cstring, length, loc, theSet: cInt): cInt{.
+      cdecl, dynlib: DLLUtilName, importc.}
+  proc X509Sign*(x: PX509, pkey: EVP_PKEY, md: PEVP_MD): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc X509GmtimeAdj*(s: PASN1_UTCTIME, adj: cInt): PASN1_UTCTIME{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc X509SetNotBefore*(x: PX509, tm: PASN1_UTCTIME): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc X509SetNotAfter*(x: PX509, tm: PASN1_UTCTIME): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc X509GetSerialNumber*(x: PX509): PASN1_cInt{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc EvpPkeyNew*(): EVP_PKEY{.cdecl, dynlib: DLLUtilName, importc.}
+  proc EvpPkeyFree*(pk: EVP_PKEY){.cdecl, dynlib: DLLUtilName, importc.}
+  proc EvpPkeyAssign*(pkey: EVP_PKEY, typ: cInt, key: Prsa): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+  proc EvpGetDigestByName*(Name: cstring): PEVP_MD{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc EVPcleanup*(){.cdecl, dynlib: DLLUtilName, importc.}
+    #  function ErrErrorString(e: cInt; buf: PChar): PChar;
+  proc SSLeayversion*(t: cInt): cstring{.cdecl, dynlib: DLLUtilName, importc.}
+
+
+  proc OPENSSLaddallalgorithms*(){.cdecl, dynlib: DLLUtilName, importc.}
+  proc CRYPTOcleanupAllExData*(){.cdecl, dynlib: DLLUtilName, importc.}
+  proc RandScreen*(){.cdecl, dynlib: DLLUtilName, importc.}
+
+  proc d2iPKCS12bio*(b: PBIO, Pkcs12: SslPtr): SslPtr{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc PKCS12parse*(p12: SslPtr, pass: cstring, pkey, cert, ca: var SslPtr): cint{.
+      dynlib: DLLUtilName, importc, cdecl.}
+
+  proc PKCS12free*(p12: SslPtr){.cdecl, dynlib: DLLUtilName, importc.}
+  proc RsaGenerateKey*(bits, e: cInt, callback: PFunction, cb_arg: SslPtr): PRSA{.
+      cdecl, dynlib: DLLUtilName, importc.}
+  proc Asn1UtctimeNew*(): PASN1_UTCTIME{.cdecl, dynlib: DLLUtilName, importc.}
+  proc Asn1UtctimeFree*(a: PASN1_UTCTIME){.cdecl, dynlib: DLLUtilName, importc.}
+  proc Asn1cIntSet*(a: PASN1_cInt, v: cInt): cInt{.cdecl, dynlib: DLLUtilName, 
+      importc.}
+  proc i2dX509bio*(b: PBIO, x: PX509): cInt{.cdecl, dynlib: DLLUtilName, importc.}
+  proc i2dPrivateKeyBio*(b: PBIO, pkey: EVP_PKEY): cInt{.cdecl, 
+      dynlib: DLLUtilName, importc.}
+    # 3DES functions
+  proc DESsetoddparity*(Key: des_cblock){.cdecl, dynlib: DLLUtilName, importc.}
+  proc DESsetkeychecked*(key: des_cblock, schedule: des_key_schedule): cInt{.
+      cdecl, dynlib: DLLUtilName, importc.}
+  proc DESecbencrypt*(Input: des_cblock, output: des_cblock, ks: des_key_schedule, 
+                      enc: cInt){.cdecl, dynlib: DLLUtilName, importc.}
+  # implementation
+
+  proc SSLSetMode(s: PSSL, mode: int): int = 
+    result = SSLctrl(s, SSL_CTRL_MODE, mode, nil)
+
+  proc SSLCTXGetMode(ctx: PSSL_CTX): int = 
+    result = SSLCTXctrl(ctx, SSL_CTRL_MODE, 0, nil)
+
+  proc SSLGetMode(s: PSSL): int = 
+    result = SSLctrl(s, SSL_CTRL_MODE, 0, nil)
+
+# <openssl/md5.h>
+type 
+  MD5_LONG* = cuint
+const 
+  MD5_CBLOCK* = 64
+  MD5_LBLOCK* = int(MD5_CBLOCK div 4)
+  MD5_DIGEST_LENGTH* = 16
+type 
+  MD5_CTX* = object 
+    A,B,C,D,Nl,Nh: MD5_LONG
+    data: array[MD5_LBLOCK, MD5_LONG]
+    num: cuint
+
+{.pragma: ic, importc: "$1".}
+{.push callconv:cdecl, dynlib:DLLUtilName.}
+proc md5_Init*(c: var MD5_CTX): cint{.ic.}
+proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.ic.}
+proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.ic.}
+proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.ic.}
+proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.ic.}
+{.pop.}
+
+from strutils import toHex,toLower
+
+proc hexStr (buf:cstring): string =
+  # turn md5s output into a nice hex str 
+  result = newStringOfCap(32)
+  for i in 0 .. <16:
+    result.add toHex(buf[i].ord, 2).toLower
+
+proc md5_File* (file: string): string {.raises: [IOError,Exception].} =
+  ## Generate MD5 hash for a file. Result is a 32 character
+  # hex string with lowercase characters (like the output
+  # of `md5sum`
+  const
+    sz = 512
+  let f = open(file,fmRead)
+  var
+    buf: array[sz,char]
+    ctx: MD5_CTX
+
+  discard md5_init(ctx)
+  while(let bytes = f.readChars(buf, 0, sz); bytes > 0):
+    discard md5_update(ctx, buf[0].addr, bytes)
+
+  discard md5_final( buf[0].addr, ctx )
+  f.close
+  
+  result = hexStr(buf)
+
+proc md5_Str* (str:string): string {.raises:[IOError].} =
+  ##Generate MD5 hash for a string. Result is a 32 character
+  #hex string with lowercase characters
+  var 
+    ctx: MD5_CTX
+    res: array[MD5_DIGEST_LENGTH,char]
+    input = str.cstring
+  discard md5_init(ctx)
+
+  var i = 0
+  while i < str.len:
+    let L = min(str.len - i, 512)
+    discard md5_update(ctx, input[i].addr, L)
+    i += L
+
+  discard md5_final(res,ctx)
+  result = hexStr(res)
diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim
new file mode 100644
index 000000000..67436f026
--- /dev/null
+++ b/lib/wrappers/pcre.nim
@@ -0,0 +1,501 @@
+#************************************************
+#       Perl-Compatible Regular Expressions     *
+#************************************************
+# This is the public header file for the PCRE library, to be #included by
+# applications that call the PCRE functions.
+#
+#           Copyright (c) 1997-2014 University of Cambridge
+#
+#-----------------------------------------------------------------------------
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#    * Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#    * Redistributions in binary form must reproduce the above copyright
+#      notice, this list of conditions and the following disclaimer in the
+#      documentation and/or other materials provided with the distribution.
+#
+#    * Neither the name of the University of Cambridge nor the names of its
+#      contributors may be used to endorse or promote products derived from
+#      this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#-----------------------------------------------------------------------------
+
+{.deadCodeElim: on.}
+
+# The current PCRE version information.
+
+const
+  PCRE_MAJOR* = 8
+  PCRE_MINOR* = 36
+  PCRE_PRERELEASE* = true
+  PCRE_DATE* = "2014-09-26"
+
+# When an application links to a PCRE DLL in Windows, the symbols that are
+# imported have to be identified as such. When building PCRE, the appropriate
+# export setting is defined in pcre_internal.h, which includes this file. So we
+# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
+
+# By default, we use the standard "extern" declarations.
+
+# Allow for C++ users
+
+# Public options. Some are compile-time only, some are run-time only, and some
+# are both. Most of the compile-time options are saved with the compiled regex
+# so that they can be inspected during studying (and therefore JIT compiling).
+# Note that pcre_study() has its own set of options. Originally, all the options
+# defined here used distinct bits. However, almost all the bits in a 32-bit word
+# are now used, so in order to conserve them, option bits that were previously
+# only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
+# also be used for compile-time options that affect only compiling and are not
+# relevant for studying or JIT compiling.
+#
+# Some options for pcre_compile() change its behaviour but do not affect the
+# behaviour of the execution functions. Other options are passed through to the
+# execution functions and affect their behaviour, with or without affecting the
+# behaviour of pcre_compile().
+#
+# Options that can be passed to pcre_compile() are tagged Cx below, with these
+# variants:
+#
+# C1   Affects compile only
+# C2   Does not affect compile; affects exec, dfa_exec
+# C3   Affects compile, exec, dfa_exec
+# C4   Affects compile, exec, dfa_exec, study
+# C5   Affects compile, exec, study
+#
+# Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged 
+# with E and D, respectively. They take precedence over C3, C4, and C5 settings 
+# passed from pcre_compile(). Those that are compatible with JIT execution are 
+# flagged with J.
+
+const
+  CASELESS*          = 0x00000001  # C1
+  MULTILINE*         = 0x00000002  # C1
+  DOTALL*            = 0x00000004  # C1
+  EXTENDED*          = 0x00000008  # C1
+  ANCHORED*          = 0x00000010  # C4 E D
+  DOLLAR_ENDONLY*    = 0x00000020  # C2
+  EXTRA*             = 0x00000040  # C1
+  NOTBOL*            = 0x00000080  #    E D J
+  NOTEOL*            = 0x00000100  #    E D J
+  UNGREEDY*          = 0x00000200  # C1
+  NOTEMPTY*          = 0x00000400  #    E D J
+  UTF8*              = 0x00000800  # C4        )
+  UTF16*             = 0x00000800  # C4        ) Synonyms
+  UTF32*             = 0x00000800  # C4        )
+  NO_AUTO_CAPTURE*   = 0x00001000  # C1
+  NO_UTF8_CHECK*     = 0x00002000  # C1 E D J  )
+  NO_UTF16_CHECK*    = 0x00002000  # C1 E D J  ) Synonyms
+  NO_UTF32_CHECK*    = 0x00002000  # C1 E D J  )
+  AUTO_CALLOUT*      = 0x00004000  # C1
+  PARTIAL_SOFT*      = 0x00008000  #    E D J  ) Synonyms
+  PARTIAL*           = 0x00008000  #    E D J  )
+
+# This pair use the same bit.
+const
+  NEVER_UTF*         = 0x00010000  # C1        ) Overlaid
+  DFA_SHORTEST*      = 0x00010000  #      D    ) Overlaid
+
+# This pair use the same bit.
+const
+  NO_AUTO_POSSESS*   = 0x00020000  # C1        ) Overlaid
+  DFA_RESTART*       = 0x00020000  #      D    ) Overlaid
+
+const
+  FIRSTLINE*         = 0x00040000  # C3
+  DUPNAMES*          = 0x00080000  # C1
+  NEWLINE_CR*        = 0x00100000  # C3 E D
+  NEWLINE_LF*        = 0x00200000  # C3 E D
+  NEWLINE_CRLF*      = 0x00300000  # C3 E D
+  NEWLINE_ANY*       = 0x00400000  # C3 E D
+  NEWLINE_ANYCRLF*   = 0x00500000  # C3 E D
+  BSR_ANYCRLF*       = 0x00800000  # C3 E D
+  BSR_UNICODE*       = 0x01000000  # C3 E D
+  JAVASCRIPT_COMPAT* = 0x02000000  # C5
+  NO_START_OPTIMIZE* = 0x04000000  # C2 E D    ) Synonyms
+  NO_START_OPTIMISE* = 0x04000000  # C2 E D    )
+  PARTIAL_HARD*      = 0x08000000  #    E D J
+  NOTEMPTY_ATSTART*  = 0x10000000  #    E D J
+  UCP*               = 0x20000000  # C3
+
+## Exec-time and get/set-time error codes
+const
+  ERROR_NOMATCH*          =  -1
+  ERROR_NULL*             =  -2
+  ERROR_BADOPTION*        =  -3
+  ERROR_BADMAGIC*         =  -4
+  ERROR_UNKNOWN_OPCODE*   =  -5
+  ERROR_UNKNOWN_NODE*     =  -5 ## For backward compatibility
+  ERROR_NOMEMORY*         =  -6
+  ERROR_NOSUBSTRING*      =  -7
+  ERROR_MATCHLIMIT*       =  -8
+  ERROR_CALLOUT*          =  -9 ## Never used by PCRE itself
+  ERROR_BADUTF8*          = -10 ## Same for 8/16/32
+  ERROR_BADUTF16*         = -10 ## Same for 8/16/32
+  ERROR_BADUTF32*         = -10 ## Same for 8/16/32
+  ERROR_BADUTF8_OFFSET*   = -11 ## Same for 8/16
+  ERROR_BADUTF16_OFFSET*  = -11 ## Same for 8/16
+  ERROR_PARTIAL*          = -12
+  ERROR_BADPARTIAL*       = -13
+  ERROR_INTERNAL*         = -14
+  ERROR_BADCOUNT*         = -15
+  ERROR_DFA_UITEM*        = -16
+  ERROR_DFA_UCOND*        = -17
+  ERROR_DFA_UMLIMIT*      = -18
+  ERROR_DFA_WSSIZE*       = -19
+  ERROR_DFA_RECURSE*      = -20
+  ERROR_RECURSIONLIMIT*   = -21
+  ERROR_NULLWSLIMIT*      = -22 ## No longer actually used
+  ERROR_BADNEWLINE*       = -23
+  ERROR_BADOFFSET*        = -24
+  ERROR_SHORTUTF8*        = -25
+  ERROR_SHORTUTF16*       = -25 ## Same for 8/16
+  ERROR_RECURSELOOP*      = -26
+  ERROR_JIT_STACKLIMIT*   = -27
+  ERROR_BADMODE*          = -28
+  ERROR_BADENDIANNESS*    = -29
+  ERROR_DFA_BADRESTART*   = -30
+  ERROR_JIT_BADOPTION*    = -31
+  ERROR_BADLENGTH*        = -32
+  ERROR_UNSET*            = -33
+
+## Specific error codes for UTF-8 validity checks
+const
+  UTF8_ERR0*  =  0
+  UTF8_ERR1*  =  1
+  UTF8_ERR2*  =  2
+  UTF8_ERR3*  =  3
+  UTF8_ERR4*  =  4
+  UTF8_ERR5*  =  5
+  UTF8_ERR6*  =  6
+  UTF8_ERR7*  =  7
+  UTF8_ERR8*  =  8
+  UTF8_ERR9*  =  9
+  UTF8_ERR10* = 10
+  UTF8_ERR11* = 11
+  UTF8_ERR12* = 12
+  UTF8_ERR13* = 13
+  UTF8_ERR14* = 14
+  UTF8_ERR15* = 15
+  UTF8_ERR16* = 16
+  UTF8_ERR17* = 17
+  UTF8_ERR18* = 18
+  UTF8_ERR19* = 19
+  UTF8_ERR20* = 20
+  UTF8_ERR21* = 21
+  UTF8_ERR22* = 22 # Unused (was non-character)
+
+## Specific error codes for UTF-16 validity checks
+const
+  UTF16_ERR0* = 0
+  UTF16_ERR1* = 1
+  UTF16_ERR2* = 2
+  UTF16_ERR3* = 3
+  UTF16_ERR4* = 4 # Unused (was non-character)
+
+## Specific error codes for UTF-32 validity checks
+const
+  UTF32_ERR0* = 0
+  UTF32_ERR1* = 1
+  UTF32_ERR2* = 2 # Unused (was non-character)
+  UTF32_ERR3* = 3
+
+## Request types for pcre_fullinfo()
+const
+  INFO_OPTIONS*             =  0
+  INFO_SIZE*                =  1
+  INFO_CAPTURECOUNT*        =  2
+  INFO_BACKREFMAX*          =  3
+  INFO_FIRSTBYTE*           =  4
+  INFO_FIRSTCHAR*           =  4 ## For backwards compatibility
+  INFO_FIRSTTABLE*          =  5
+  INFO_LASTLITERAL*         =  6
+  INFO_NAMEENTRYSIZE*       =  7
+  INFO_NAMECOUNT*           =  8
+  INFO_NAMETABLE*           =  9
+  INFO_STUDYSIZE*           = 10
+  INFO_DEFAULT_TABLES*      = 11
+  INFO_OKPARTIAL*           = 12
+  INFO_JCHANGED*            = 13
+  INFO_HASCRORLF*           = 14
+  INFO_MINLENGTH*           = 15
+  INFO_JIT*                 = 16
+  INFO_JITSIZE*             = 17
+  INFO_MAXLOOKBEHIND*       = 18
+  INFO_FIRSTCHARACTER*      = 19
+  INFO_FIRSTCHARACTERFLAGS* = 20
+  INFO_REQUIREDCHAR*        = 21
+  INFO_REQUIREDCHARFLAGS*   = 22
+  INFO_MATCHLIMIT*          = 23
+  INFO_RECURSIONLIMIT*      = 24
+  INFO_MATCH_EMPTY*         = 25
+
+## Request types for pcre_config(). Do not re-arrange, in order to remain
+## compatible.
+const
+  CONFIG_UTF8*                   =  0
+  CONFIG_NEWLINE*                =  1
+  CONFIG_LINK_SIZE*              =  2
+  CONFIG_POSIX_MALLOC_THRESHOLD* =  3
+  CONFIG_MATCH_LIMIT*            =  4
+  CONFIG_STACKRECURSE*           =  5
+  CONFIG_UNICODE_PROPERTIES*     =  6
+  CONFIG_MATCH_LIMIT_RECURSION*  =  7
+  CONFIG_BSR*                    =  8
+  CONFIG_JIT*                    =  9
+  CONFIG_UTF16*                  = 10
+  CONFIG_JITTARGET*              = 11
+  CONFIG_UTF32*                  = 12
+  CONFIG_PARENS_LIMIT*           = 13
+
+## Request types for pcre_study(). Do not re-arrange, in order to remain
+## compatible.
+const
+  STUDY_JIT_COMPILE*              = 0x0001
+  STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x0002
+  STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x0004
+  STUDY_EXTRA_NEEDED*             = 0x0008
+
+## Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
+## these bits, just add new ones on the end, in order to remain compatible.
+const
+  EXTRA_STUDY_DATA*            = 0x0001
+  EXTRA_MATCH_LIMIT*           = 0x0002
+  EXTRA_CALLOUT_DATA*          = 0x0004
+  EXTRA_TABLES*                = 0x0008
+  EXTRA_MATCH_LIMIT_RECURSION* = 0x0010
+  EXTRA_MARK*                  = 0x0020
+  EXTRA_EXECUTABLE_JIT*        = 0x0040
+
+## Types
+type
+  Pcre* = object
+  Pcre16* = object
+  Pcre32* = object
+  JitStack* = object
+  JitStack16* = object
+  JitStack32* = object
+
+
+## The structure for passing additional data to pcre_exec(). This is defined in
+## such as way as to be extensible. Always add new fields at the end, in order
+## to remain compatible.
+type
+  ExtraData* = object
+    flags*: clong                  ## Bits for which fields are set
+    study_data*: pointer           ## Opaque data from pcre_study()
+    match_limit*: clong            ## Maximum number of calls to match()
+    callout_data*: pointer         ## Data passed back in callouts
+    tables*: pointer               ## Pointer to character tables
+    match_limit_recursion*: clong  ## Max recursive calls to match()
+    mark*: pointer                 ## For passing back a mark pointer
+    executable_jit*: pointer       ## Contains a pointer to a compiled jit code
+
+## The structure for passing out data via the pcre_callout_function. We use a
+## structure so that new fields can be added on the end in future versions,
+## without changing the API of the function, thereby allowing old clients to
+## work without modification.
+type
+  CalloutBlock* = object
+    version*         : cint       ## Identifies version of block
+    # ------------------------ Version 0 -------------------------------
+    callout_number*  : cint       ## Number compiled into pattern
+    offset_vector*   : ptr cint   ## The offset vector
+    subject*         : cstring    ## The subject being matched
+    subject_length*  : cint       ## The length of the subject
+    start_match*     : cint       ## Offset to start of this match attempt
+    current_position*: cint       ## Where we currently are in the subject
+    capture_top*     : cint       ## Max current capture
+    capture_last*    : cint       ## Most recently closed capture
+    callout_data*    : pointer    ## Data passed in with the call
+    # ------------------- Added for Version 1 --------------------------
+    pattern_position*: cint       ## Offset to next item in the pattern
+    next_item_length*: cint       ## Length of next item in the pattern
+    # ------------------- Added for Version 2 --------------------------
+    mark*            : pointer    ## Pointer to current mark or NULL
+    # ------------------------------------------------------------------
+
+
+## User defined callback which provides a stack just before the match starts.
+type
+  JitCallback* = proc (a: pointer): ptr JitStack {.cdecl.}
+
+
+when not defined(usePcreHeader):
+  when hostOS == "windows":
+    const pcreDll = "pcre.dll"
+  elif hostOS == "macosx":
+    const pcreDll = "libpcre(.3|.1|).dylib"
+  else:
+    const pcreDll = "libpcre.so(.3|.1|)"
+  {.push dynlib: pcreDll.}
+else:
+  {.push header: "<pcre.h>".}
+
+{.push cdecl, importc: "pcre_$1".}
+
+# Exported PCRE functions
+
+proc compile*(pattern: cstring,
+              options: cint,
+              errptr: ptr cstring,
+              erroffset: ptr cint,
+              tableptr: pointer): ptr Pcre
+
+proc compile2*(pattern: cstring,
+               options: cint,
+               errorcodeptr: ptr cint,
+               errptr: ptr cstring,
+               erroffset: ptr cint,
+               tableptr: pointer): ptr Pcre
+
+proc config*(what: cint,
+             where: pointer): cint
+
+proc copy_named_substring*(code: ptr Pcre,
+                           subject: cstring,
+                           ovector: ptr cint,
+                           stringcount: cint,
+                           stringname: cstring,
+                           buffer: cstring,
+                           buffersize: cint): cint
+
+proc copy_substring*(subject: cstring,
+                     ovector: ptr cint,
+                     stringcount: cint,
+                     stringnumber: cint,
+                     buffer: cstring,
+                     buffersize: cint): cint
+
+proc dfa_exec*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               subject: cstring,
+               length: cint,
+               startoffset: cint,
+               options: cint,
+               ovector: ptr cint,
+               ovecsize: cint,
+               workspace: ptr cint,
+               wscount: cint): cint
+
+proc exec*(code: ptr Pcre,
+           extra: ptr ExtraData,
+           subject: cstring,
+           length: cint,
+           startoffset: cint,
+           options: cint,
+           ovector: ptr cint,
+           ovecsize: cint): cint
+
+proc jit_exec*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               subject: cstring,
+               length: cint,
+               startoffset: cint,
+               options: cint,
+               ovector: ptr cint,
+               ovecsize: cint,
+               jstack: ptr JitStack): cint
+
+proc free_substring*(stringptr: cstring)
+
+proc free_substring_list*(stringptr: cstringArray)
+
+proc fullinfo*(code: ptr Pcre,
+               extra: ptr ExtraData,
+               what: cint,
+               where: pointer): cint
+
+proc get_named_substring*(code: ptr Pcre,
+                          subject: cstring,
+                          ovector: ptr cint,
+                          stringcount: cint,
+                          stringname: cstring,
+                          stringptr: cstringArray): cint
+
+proc get_stringnumber*(code: ptr Pcre,
+                       name: cstring): cint
+
+proc get_stringtable_entries*(code: ptr Pcre,
+                              name: cstring,
+                              first: cstringArray,
+                              last: cstringArray): cint
+
+proc get_substring*(subject: cstring,
+                    ovector: ptr cint,
+                    stringcount: cint,
+                    stringnumber: cint,
+                    stringptr: cstringArray): cint
+
+proc get_substring_list*(subject: cstring,
+                         ovector: ptr cint,
+                         stringcount: cint,
+                         listptr: ptr cstringArray): cint
+
+proc maketables*(): pointer
+
+proc refcount*(code: ptr Pcre,
+               adjust: cint): cint
+
+proc study*(code: ptr Pcre,
+            options: cint,
+            errptr: ptr cstring): ptr ExtraData
+
+proc free_study*(extra: ptr ExtraData)
+
+proc version*(): cstring
+
+# Utility functions for byte order swaps.
+
+proc pattern_to_host_byte_order*(code: ptr Pcre,
+                                 extra: ptr ExtraData,
+                                 tables: pointer): cint
+
+# JIT compiler related functions.
+
+proc jit_stack_alloc*(startsize: cint,
+                      maxsize: cint): ptr JitStack
+
+proc jit_stack_free*(stack: ptr JitStack)
+
+proc assign_jit_stack*(extra: ptr ExtraData,
+                       callback: JitCallback,
+                       data: pointer)
+
+proc jit_free_unused_memory*()
+
+
+# There was an odd function with `var cstring` instead of `ptr`
+proc study*(code: ptr Pcre,
+            options: cint,
+            errptr: var cstring): ptr ExtraData {.deprecated.}
+
+{.pop.}
+{.pop.}
+
+
+{.deprecated: [MAJOR: PCRE_MAJOR, MINOR: PCRE_MINOR,
+               PRERELEASE: PCRE_PRERELEASE, DATE: PCRE_DATE].}
+
+{.deprecated: [TPcre: Pcre, TJitStack: JitStack].}
+type
+  PPcre* {.deprecated.} = ptr Pcre
+  PJitStack* {.deprecated.} = ptr JitStack
+
+{.deprecated: [TExtra: ExtraData].}
+{.deprecated: [TCalloutBlock: CalloutBlock].}
+{.deprecated: [TJitCallback: JitCallback].}
diff --git a/lib/wrappers/pdcurses.nim b/lib/wrappers/pdcurses.nim
new file mode 100644
index 000000000..bed69648a
--- /dev/null
+++ b/lib/wrappers/pdcurses.nim
@@ -0,0 +1,1539 @@
+{.deadCodeElim: on.}
+
+discard """
+
+curses.h:
+#ifdef C2NIM
+#dynlib pdcursesdll
+#skipinclude
+#prefix PDC_
+#def FALSE
+#def TRUE
+#def NULL
+#def bool unsigned char
+#def chtype unsigned long
+#def cchar_t unsigned long
+#def attr_t unsigned long
+#def mmask_t unsigned long
+#def wchar_t char
+#def PDCEX
+#cdecl
+#endif
+
+pdcwin.h:
+#ifdef C2NIM
+#dynlib pdcursesdll
+#skipinclude
+#prefix pdc_
+#prefix PDC_
+#stdcall
+#endif
+"""
+
+when defined(windows):
+  import windows
+  
+  const
+    pdcursesdll = "pdcurses.dll"
+    unixOS = false
+  {.pragma: extdecl, stdcall.}
+
+when not defined(windows):
+  const
+    unixOS = true
+  {.pragma: extdecl, cdecl.}
+
+type
+  cunsignedchar = char
+  cunsignedlong = uint32
+
+const 
+  BUILD* = 3401
+  PDCURSES* = 1               # PDCurses-only routines 
+  XOPEN* = 1                  # X/Open Curses routines 
+  SYSVcurses* = 1             # System V Curses routines 
+  BSDcurses* = 1              # BSD Curses routines 
+  CHTYPE_LONG* = 1            # size of chtype; long 
+  ERR* = (- 1)
+  OK* = 0
+  BUTTON_RELEASED* = 0x00000000
+  BUTTON_PRESSED* = 0x00000001
+  BUTTON_CLICKED* = 0x00000002
+  BUTTON_DOUBLE_CLICKED* = 0x00000003
+  BUTTON_TRIPLE_CLICKED* = 0x00000004
+  BUTTON_MOVED* = 0x00000005  # PDCurses 
+  WHEEL_SCROLLED* = 0x00000006 # PDCurses 
+  BUTTON_ACTION_MASK* = 0x00000007 # PDCurses 
+  BUTTON_MODIFIER_MASK* = 0x00000038 # PDCurses 
+  MOUSE_MOVED* = 0x00000008
+  MOUSE_POSITION* = 0x00000010
+  MOUSE_WHEEL_UP* = 0x00000020
+  MOUSE_WHEEL_DOWN* = 0x00000040
+  BUTTON1_RELEASED* = 0x00000001
+  BUTTON1_PRESSED* = 0x00000002
+  BUTTON1_CLICKED* = 0x00000004
+  BUTTON1_DOUBLE_CLICKED* = 0x00000008
+  BUTTON1_TRIPLE_CLICKED* = 0x00000010
+  BUTTON1_MOVED* = 0x00000010 # PDCurses 
+  BUTTON2_RELEASED* = 0x00000020
+  BUTTON2_PRESSED* = 0x00000040
+  BUTTON2_CLICKED* = 0x00000080
+  BUTTON2_DOUBLE_CLICKED* = 0x00000100
+  BUTTON2_TRIPLE_CLICKED* = 0x00000200
+  BUTTON2_MOVED* = 0x00000200 # PDCurses 
+  BUTTON3_RELEASED* = 0x00000400
+  BUTTON3_PRESSED* = 0x00000800
+  BUTTON3_CLICKED* = 0x00001000
+  BUTTON3_DOUBLE_CLICKED* = 0x00002000
+  BUTTON3_TRIPLE_CLICKED* = 0x00004000
+  BUTTON3_MOVED* = 0x00004000 # PDCurses 
+  BUTTON4_RELEASED* = 0x00008000
+  BUTTON4_PRESSED* = 0x00010000
+  BUTTON4_CLICKED* = 0x00020000
+  BUTTON4_DOUBLE_CLICKED* = 0x00040000
+  BUTTON4_TRIPLE_CLICKED* = 0x00080000
+  BUTTON5_RELEASED* = 0x00100000
+  BUTTON5_PRESSED* = 0x00200000
+  BUTTON5_CLICKED* = 0x00400000
+  BUTTON5_DOUBLE_CLICKED* = 0x00800000
+  BUTTON5_TRIPLE_CLICKED* = 0x01000000
+  MOUSE_WHEEL_SCROLL* = 0x02000000 # PDCurses 
+  BUTTON_MODIFIER_SHIFT* = 0x04000000 # PDCurses 
+  BUTTON_MODIFIER_CONTROL* = 0x08000000 # PDCurses 
+  BUTTON_MODIFIER_ALT* = 0x10000000 # PDCurses 
+  ALL_MOUSE_EVENTS* = 0x1FFFFFFF
+  REPORT_MOUSE_POSITION* = 0x20000000
+  A_NORMAL* = 0
+  A_ALTCHARSET* = 0x00010000
+  A_RIGHTLINE* = 0x00020000
+  A_LEFTLINE* = 0x00040000
+  A_INVIS* = 0x00080000
+  A_UNDERLINE* = 0x00100000
+  A_REVERSE* = 0x00200000
+  A_BLINK* = 0x00400000
+  A_BOLD* = 0x00800000
+  A_ATTRIBUTES* = 0xFFFF0000
+  A_CHARTEXT* = 0x0000FFFF
+  A_COLOR* = 0xFF000000
+  A_ITALIC* = A_INVIS
+  A_PROTECT* = (A_UNDERLINE or A_LEFTLINE or A_RIGHTLINE)
+  ATTR_SHIFT* = 19
+  COLOR_SHIFT* = 24
+  A_STANDOUT* = (A_REVERSE or A_BOLD) # X/Open 
+  A_DIM* = A_NORMAL
+  CHR_MSK* = A_CHARTEXT       # Obsolete 
+  ATR_MSK* = A_ATTRIBUTES     # Obsolete 
+  ATR_NRM* = A_NORMAL         # Obsolete 
+  WA_ALTCHARSET* = A_ALTCHARSET
+  WA_BLINK* = A_BLINK
+  WA_BOLD* = A_BOLD
+  WA_DIM* = A_DIM
+  WA_INVIS* = A_INVIS
+  WA_LEFT* = A_LEFTLINE
+  WA_PROTECT* = A_PROTECT
+  WA_REVERSE* = A_REVERSE
+  WA_RIGHT* = A_RIGHTLINE
+  WA_STANDOUT* = A_STANDOUT
+  WA_UNDERLINE* = A_UNDERLINE
+  WA_HORIZONTAL* = A_NORMAL
+  WA_LOW* = A_NORMAL
+  WA_TOP* = A_NORMAL
+  WA_VERTICAL* = A_NORMAL
+  COLOR_BLACK* = 0
+  COLOR_RED* = 1
+  COLOR_GREEN* = 2
+  COLOR_BLUE* = 4
+  COLOR_CYAN* = (COLOR_BLUE or COLOR_GREEN)
+  COLOR_MAGENTA* = (COLOR_RED or COLOR_BLUE)
+  COLOR_YELLOW* = (COLOR_RED or COLOR_GREEN)
+  COLOR_WHITE* = 7
+  KEY_CODE_YES* = 0x00000100  # If get_wch() gives a key code 
+  KEY_BREAK* = 0x00000101     # Not on PC KBD 
+  KEY_DOWN* = 0x00000102      # Down arrow key 
+  KEY_UP* = 0x00000103        # Up arrow key 
+  KEY_LEFT* = 0x00000104      # Left arrow key 
+  KEY_RIGHT* = 0x00000105     # Right arrow key 
+  KEY_HOME* = 0x00000106      # home key 
+  KEY_BACKSPACE* = 0x00000107 # not on pc 
+  KEY_F0* = 0x00000108        # function keys; 64 reserved 
+  KEY_DL* = 0x00000148        # delete line 
+  KEY_IL* = 0x00000149        # insert line 
+  KEY_DC* = 0x0000014A        # delete character 
+  KEY_IC* = 0x0000014B        # insert char or enter ins mode 
+  KEY_EIC* = 0x0000014C       # exit insert char mode 
+  KEY_CLEAR* = 0x0000014D     # clear screen 
+  KEY_EOS* = 0x0000014E       # clear to end of screen 
+  KEY_EOL* = 0x0000014F       # clear to end of line 
+  KEY_SF* = 0x00000150        # scroll 1 line forward 
+  KEY_SR* = 0x00000151        # scroll 1 line back (reverse) 
+  KEY_NPAGE* = 0x00000152     # next page 
+  KEY_PPAGE* = 0x00000153     # previous page 
+  KEY_STAB* = 0x00000154      # set tab 
+  KEY_CTAB* = 0x00000155      # clear tab 
+  KEY_CATAB* = 0x00000156     # clear all tabs 
+  KEY_ENTER* = 0x00000157     # enter or send (unreliable) 
+  KEY_SRESET* = 0x00000158    # soft/reset (partial/unreliable) 
+  KEY_RESET* = 0x00000159     # reset/hard reset (unreliable) 
+  KEY_PRINT* = 0x0000015A     # print/copy 
+  KEY_LL* = 0x0000015B        # home down/bottom (lower left) 
+  KEY_ABORT* = 0x0000015C     # abort/terminate key (any) 
+  KEY_SHELP* = 0x0000015D     # short help 
+  KEY_LHELP* = 0x0000015E     # long help 
+  KEY_BTAB* = 0x0000015F      # Back tab key 
+  KEY_BEG* = 0x00000160       # beg(inning) key 
+  KEY_CANCEL* = 0x00000161    # cancel key 
+  KEY_CLOSE* = 0x00000162     # close key 
+  KEY_COMMAND* = 0x00000163   # cmd (command) key 
+  KEY_COPY* = 0x00000164      # copy key 
+  KEY_CREATE* = 0x00000165    # create key 
+  KEY_END* = 0x00000166       # end key 
+  KEY_EXIT* = 0x00000167      # exit key 
+  KEY_FIND* = 0x00000168      # find key 
+  KEY_HELP* = 0x00000169      # help key 
+  KEY_MARK* = 0x0000016A      # mark key 
+  KEY_MESSAGE* = 0x0000016B   # message key 
+  KEY_MOVE* = 0x0000016C      # move key 
+  KEY_NEXT* = 0x0000016D      # next object key 
+  KEY_OPEN* = 0x0000016E      # open key 
+  KEY_OPTIONS* = 0x0000016F   # options key 
+  KEY_PREVIOUS* = 0x00000170  # previous object key 
+  KEY_REDO* = 0x00000171      # redo key 
+  KEY_REFERENCE* = 0x00000172 # ref(erence) key 
+  KEY_REFRESH* = 0x00000173   # refresh key 
+  KEY_REPLACE* = 0x00000174   # replace key 
+  KEY_RESTART* = 0x00000175   # restart key 
+  KEY_RESUME* = 0x00000176    # resume key 
+  KEY_SAVE* = 0x00000177      # save key 
+  KEY_SBEG* = 0x00000178      # shifted beginning key 
+  KEY_SCANCEL* = 0x00000179   # shifted cancel key 
+  KEY_SCOMMAND* = 0x0000017A  # shifted command key 
+  KEY_SCOPY* = 0x0000017B     # shifted copy key 
+  KEY_SCREATE* = 0x0000017C   # shifted create key 
+  KEY_SDC* = 0x0000017D       # shifted delete char key 
+  KEY_SDL* = 0x0000017E       # shifted delete line key 
+  KEY_SELECT* = 0x0000017F    # select key 
+  KEY_SEND* = 0x00000180      # shifted end key 
+  KEY_SEOL* = 0x00000181      # shifted clear line key 
+  KEY_SEXIT* = 0x00000182     # shifted exit key 
+  KEY_SFIND* = 0x00000183     # shifted find key 
+  KEY_SHOME* = 0x00000184     # shifted home key 
+  KEY_SIC* = 0x00000185       # shifted input key 
+  KEY_SLEFT* = 0x00000187     # shifted left arrow key 
+  KEY_SMESSAGE* = 0x00000188  # shifted message key 
+  KEY_SMOVE* = 0x00000189     # shifted move key 
+  KEY_SNEXT* = 0x0000018A     # shifted next key 
+  KEY_SOPTIONS* = 0x0000018B  # shifted options key 
+  KEY_SPREVIOUS* = 0x0000018C # shifted prev key 
+  KEY_SPRINT* = 0x0000018D    # shifted print key 
+  KEY_SREDO* = 0x0000018E     # shifted redo key 
+  KEY_SREPLACE* = 0x0000018F  # shifted replace key 
+  KEY_SRIGHT* = 0x00000190    # shifted right arrow 
+  KEY_SRSUME* = 0x00000191    # shifted resume key 
+  KEY_SSAVE* = 0x00000192     # shifted save key 
+  KEY_SSUSPEND* = 0x00000193  # shifted suspend key 
+  KEY_SUNDO* = 0x00000194     # shifted undo key 
+  KEY_SUSPEND* = 0x00000195   # suspend key 
+  KEY_UNDO* = 0x00000196      # undo key 
+  ALT_0* = 0x00000197
+  ALT_1* = 0x00000198
+  ALT_2* = 0x00000199
+  ALT_3* = 0x0000019A
+  ALT_4* = 0x0000019B
+  ALT_5* = 0x0000019C
+  ALT_6* = 0x0000019D
+  ALT_7* = 0x0000019E
+  ALT_8* = 0x0000019F
+  ALT_9* = 0x000001A0
+  ALT_A* = 0x000001A1
+  ALT_B* = 0x000001A2
+  ALT_C* = 0x000001A3
+  ALT_D* = 0x000001A4
+  ALT_E* = 0x000001A5
+  ALT_F* = 0x000001A6
+  ALT_G* = 0x000001A7
+  ALT_H* = 0x000001A8
+  ALT_I* = 0x000001A9
+  ALT_J* = 0x000001AA
+  ALT_K* = 0x000001AB
+  ALT_L* = 0x000001AC
+  ALT_M* = 0x000001AD
+  ALT_N* = 0x000001AE
+  ALT_O* = 0x000001AF
+  ALT_P* = 0x000001B0
+  ALT_Q* = 0x000001B1
+  ALT_R* = 0x000001B2
+  ALT_S* = 0x000001B3
+  ALT_T* = 0x000001B4
+  ALT_U* = 0x000001B5
+  ALT_V* = 0x000001B6
+  ALT_W* = 0x000001B7
+  ALT_X* = 0x000001B8
+  ALT_Y* = 0x000001B9
+  ALT_Z* = 0x000001BA
+  CTL_LEFT* = 0x000001BB      # Control-Left-Arrow 
+  CTL_RIGHT* = 0x000001BC
+  CTL_PGUP* = 0x000001BD
+  CTL_PGDN* = 0x000001BE
+  CTL_HOME* = 0x000001BF
+  CTL_END* = 0x000001C0
+  KEY_A1* = 0x000001C1        # upper left on Virtual keypad 
+  KEY_A2* = 0x000001C2        # upper middle on Virt. keypad 
+  KEY_A3* = 0x000001C3        # upper right on Vir. keypad 
+  KEY_B1* = 0x000001C4        # middle left on Virt. keypad 
+  KEY_B2* = 0x000001C5        # center on Virt. keypad 
+  KEY_B3* = 0x000001C6        # middle right on Vir. keypad 
+  KEY_C1* = 0x000001C7        # lower left on Virt. keypad 
+  KEY_C2* = 0x000001C8        # lower middle on Virt. keypad 
+  KEY_C3* = 0x000001C9        # lower right on Vir. keypad 
+  PADSLASH* = 0x000001CA      # slash on keypad 
+  PADENTER* = 0x000001CB      # enter on keypad 
+  CTL_PADENTER* = 0x000001CC  # ctl-enter on keypad 
+  ALT_PADENTER* = 0x000001CD  # alt-enter on keypad 
+  PADSTOP* = 0x000001CE       # stop on keypad 
+  PADSTAR* = 0x000001CF       # star on keypad 
+  PADMINUS* = 0x000001D0      # minus on keypad 
+  PADPLUS* = 0x000001D1       # plus on keypad 
+  CTL_PADSTOP* = 0x000001D2   # ctl-stop on keypad 
+  CTL_PADCENTER* = 0x000001D3 # ctl-enter on keypad 
+  CTL_PADPLUS* = 0x000001D4   # ctl-plus on keypad 
+  CTL_PADMINUS* = 0x000001D5  # ctl-minus on keypad 
+  CTL_PADSLASH* = 0x000001D6  # ctl-slash on keypad 
+  CTL_PADSTAR* = 0x000001D7   # ctl-star on keypad 
+  ALT_PADPLUS* = 0x000001D8   # alt-plus on keypad 
+  ALT_PADMINUS* = 0x000001D9  # alt-minus on keypad 
+  ALT_PADSLASH* = 0x000001DA  # alt-slash on keypad 
+  ALT_PADSTAR* = 0x000001DB   # alt-star on keypad 
+  ALT_PADSTOP* = 0x000001DC   # alt-stop on keypad 
+  CTL_INS* = 0x000001DD       # ctl-insert 
+  ALT_DEL* = 0x000001DE       # alt-delete 
+  ALT_INS* = 0x000001DF       # alt-insert 
+  CTL_UP* = 0x000001E0        # ctl-up arrow 
+  CTL_DOWN* = 0x000001E1      # ctl-down arrow 
+  CTL_TAB* = 0x000001E2       # ctl-tab 
+  ALT_TAB* = 0x000001E3
+  ALT_MINUS* = 0x000001E4
+  ALT_EQUAL* = 0x000001E5
+  ALT_HOME* = 0x000001E6
+  ALT_PGUP* = 0x000001E7
+  ALT_PGDN* = 0x000001E8
+  ALT_END* = 0x000001E9
+  ALT_UP* = 0x000001EA        # alt-up arrow 
+  ALT_DOWN* = 0x000001EB      # alt-down arrow 
+  ALT_RIGHT* = 0x000001EC     # alt-right arrow 
+  ALT_LEFT* = 0x000001ED      # alt-left arrow 
+  ALT_ENTER* = 0x000001EE     # alt-enter 
+  ALT_ESC* = 0x000001EF       # alt-escape 
+  ALT_BQUOTE* = 0x000001F0    # alt-back quote 
+  ALT_LBRACKET* = 0x000001F1  # alt-left bracket 
+  ALT_RBRACKET* = 0x000001F2  # alt-right bracket 
+  ALT_SEMICOLON* = 0x000001F3 # alt-semi-colon 
+  ALT_FQUOTE* = 0x000001F4    # alt-forward quote 
+  ALT_COMMA* = 0x000001F5     # alt-comma 
+  ALT_STOP* = 0x000001F6      # alt-stop 
+  ALT_FSLASH* = 0x000001F7    # alt-forward slash 
+  ALT_BKSP* = 0x000001F8      # alt-backspace 
+  CTL_BKSP* = 0x000001F9      # ctl-backspace 
+  PAD0* = 0x000001FA          # keypad 0 
+  CTL_PAD0* = 0x000001FB      # ctl-keypad 0 
+  CTL_PAD1* = 0x000001FC
+  CTL_PAD2* = 0x000001FD
+  CTL_PAD3* = 0x000001FE
+  CTL_PAD4* = 0x000001FF
+  CTL_PAD5* = 0x00000200
+  CTL_PAD6* = 0x00000201
+  CTL_PAD7* = 0x00000202
+  CTL_PAD8* = 0x00000203
+  CTL_PAD9* = 0x00000204
+  ALT_PAD0* = 0x00000205      # alt-keypad 0 
+  ALT_PAD1* = 0x00000206
+  ALT_PAD2* = 0x00000207
+  ALT_PAD3* = 0x00000208
+  ALT_PAD4* = 0x00000209
+  ALT_PAD5* = 0x0000020A
+  ALT_PAD6* = 0x0000020B
+  ALT_PAD7* = 0x0000020C
+  ALT_PAD8* = 0x0000020D
+  ALT_PAD9* = 0x0000020E
+  CTL_DEL* = 0x0000020F       # clt-delete 
+  ALT_BSLASH* = 0x00000210    # alt-back slash 
+  CTL_ENTER* = 0x00000211     # ctl-enter 
+  SHF_PADENTER* = 0x00000212  # shift-enter on keypad 
+  SHF_PADSLASH* = 0x00000213  # shift-slash on keypad 
+  SHF_PADSTAR* = 0x00000214   # shift-star  on keypad 
+  SHF_PADPLUS* = 0x00000215   # shift-plus  on keypad 
+  SHF_PADMINUS* = 0x00000216  # shift-minus on keypad 
+  SHF_UP* = 0x00000217        # shift-up on keypad 
+  SHF_DOWN* = 0x00000218      # shift-down on keypad 
+  SHF_IC* = 0x00000219        # shift-insert on keypad 
+  SHF_DC* = 0x0000021A        # shift-delete on keypad 
+  KEY_MOUSE* = 0x0000021B     # "mouse" key 
+  KEY_SHIFT_L* = 0x0000021C   # Left-shift 
+  KEY_SHIFT_R* = 0x0000021D   # Right-shift 
+  KEY_CONTROL_L* = 0x0000021E # Left-control 
+  KEY_CONTROL_R* = 0x0000021F # Right-control 
+  KEY_ALT_L* = 0x00000220     # Left-alt 
+  KEY_ALT_R* = 0x00000221     # Right-alt 
+  KEY_RESIZE* = 0x00000222    # Window resize 
+  KEY_SUP* = 0x00000223       # Shifted up arrow 
+  KEY_SDOWN* = 0x00000224     # Shifted down arrow 
+  KEY_MIN* = KEY_BREAK        # Minimum curses key value 
+  KEY_MAX* = KEY_SDOWN        # Maximum curses key 
+  CLIP_SUCCESS* = 0
+  CLIP_ACCESS_ERROR* = 1
+  CLIP_EMPTY* = 2
+  CLIP_MEMORY_ERROR* = 3
+  KEY_MODIFIER_SHIFT* = 1
+  KEY_MODIFIER_CONTROL* = 2
+  KEY_MODIFIER_ALT* = 4
+  KEY_MODIFIER_NUMLOCK* = 8
+
+when appType == "gui":
+  const
+    BUTTON_SHIFT* = BUTTON_MODIFIER_SHIFT
+    BUTTON_CONTROL* = BUTTON_MODIFIER_CONTROL
+    BUTTON_CTRL* = BUTTON_MODIFIER_CONTROL
+    BUTTON_ALT* = BUTTON_MODIFIER_ALT
+else:
+  const 
+    BUTTON_SHIFT* = 0x00000008
+    BUTTON_CONTROL* = 0x00000010
+    BUTTON_ALT* = 0x00000020
+
+type 
+  TMOUSE_STATUS*{.pure, final.} = object 
+    x*: cint                  # absolute column, 0 based, measured in characters 
+    y*: cint                  # absolute row, 0 based, measured in characters 
+    button*: array[0..3 - 1, cshort] # state of each button 
+    changes*: cint            # flags indicating what has changed with the mouse 
+  
+  TMEVENT*{.pure, final.} = object 
+    id*: cshort               # unused, always 0 
+    x*: cint
+    y*: cint
+    z*: cint                  # x, y same as MOUSE_STATUS; z unused 
+    bstate*: cunsignedlong    # equivalent to changes + button[], but
+                              #                           in the same format as used for mousemask() 
+  
+  TWINDOW*{.pure, final.} = object 
+    cury*: cint              # current pseudo-cursor 
+    curx*: cint
+    maxy*: cint              # max window coordinates 
+    maxx*: cint
+    begy*: cint              # origin on screen 
+    begx*: cint
+    flags*: cint             # window properties 
+    attrs*: cunsignedlong    # standard attributes and colors 
+    bkgd*: cunsignedlong     # background, normally blank 
+    clear*: cunsignedchar    # causes clear at next refresh 
+    leaveit*: cunsignedchar  # leaves cursor where it is 
+    scroll*: cunsignedchar   # allows window scrolling 
+    nodelay*: cunsignedchar  # input character wait flag 
+    immed*: cunsignedchar    # immediate update flag 
+    sync*: cunsignedchar     # synchronise window ancestors 
+    use_keypad*: cunsignedchar # flags keypad key mode active 
+    y*: ptr ptr cunsignedlong # pointer to line pointer array 
+    firstch*: ptr cint       # first changed character in line 
+    lastch*: ptr cint        # last changed character in line 
+    tmarg*: cint             # top of scrolling region 
+    bmarg*: cint             # bottom of scrolling region 
+    delayms*: cint           # milliseconds of delay for getch() 
+    parx*: cint
+    pary*: cint              # coords relative to parent (0,0) 
+    parent*: ptr TWINDOW        # subwin's pointer to parent win 
+  
+  TPANELOBS*{.pure, final.} = object 
+    above*: ptr TPANELOBS
+    pan*: ptr TPANEL
+
+  TPANEL*{.pure, final.} = object 
+    win*: ptr TWINDOW
+    wstarty*: cint
+    wendy*: cint
+    wstartx*: cint
+    wendx*: cint
+    below*: ptr TPANEL
+    above*: ptr TPANEL
+    user*: pointer
+    obscure*: ptr TPANELOBS
+
+when unixOS:
+  type
+    TSCREEN*{.pure, final.} = object 
+      alive*: cunsignedchar     # if initscr() called, and not endwin() 
+      autocr*: cunsignedchar    # if cr -> lf 
+      cbreak*: cunsignedchar    # if terminal unbuffered 
+      echo*: cunsignedchar      # if terminal echo 
+      raw_inp*: cunsignedchar   # raw input mode (v. cooked input) 
+      raw_out*: cunsignedchar   # raw output mode (7 v. 8 bits) 
+      audible*: cunsignedchar   # FALSE if the bell is visual 
+      mono*: cunsignedchar      # TRUE if current screen is mono 
+      resized*: cunsignedchar   # TRUE if TERM has been resized 
+      orig_attr*: cunsignedchar # TRUE if we have the original colors 
+      orig_fore*: cshort        # original screen foreground color 
+      orig_back*: cshort        # original screen foreground color 
+      cursrow*: cint            # position of physical cursor 
+      curscol*: cint            # position of physical cursor 
+      visibility*: cint         # visibility of cursor 
+      orig_cursor*: cint        # original cursor size 
+      lines*: cint              # new value for LINES 
+      cols*: cint               # new value for COLS 
+      trap_mbe*: cunsignedlong # trap these mouse button events 
+      map_mbe_to_key*: cunsignedlong # map mouse buttons to slk 
+      mouse_wait*: cint # time to wait (in ms) for a button release after a press
+      slklines*: cint           # lines in use by slk_init() 
+      slk_winptr*: ptr TWINDOW   # window for slk 
+      linesrippedoff*: cint     # lines ripped off via ripoffline() 
+      linesrippedoffontop*: cint # lines ripped off on top via ripoffline() 
+      delaytenths*: cint        # 1/10ths second to wait block getch() for 
+      preserve*: cunsignedchar # TRUE if screen background to be preserved 
+      restore*: cint           # specifies if screen background to be restored, and how 
+      save_key_modifiers*: cunsignedchar # TRUE if each key modifiers saved with each key press 
+      return_key_modifiers*: cunsignedchar # TRUE if modifier keys are returned as "real" keys 
+      key_code*: cunsignedchar # TRUE if last key is a special key;
+      XcurscrSize*: cint        # size of Xcurscr shared memory block 
+      sb_on*: cunsignedchar
+      sb_viewport_y*: cint
+      sb_viewport_x*: cint
+      sb_total_y*: cint
+      sb_total_x*: cint
+      sb_cur_y*: cint
+      sb_cur_x*: cint
+      line_color*: cshort       # color of line attributes - default -1 
+else:
+  type
+    TSCREEN*{.pure, final.} = object 
+      alive*: cunsignedchar     # if initscr() called, and not endwin() 
+      autocr*: cunsignedchar    # if cr -> lf 
+      cbreak*: cunsignedchar    # if terminal unbuffered 
+      echo*: cunsignedchar      # if terminal echo 
+      raw_inp*: cunsignedchar   # raw input mode (v. cooked input) 
+      raw_out*: cunsignedchar   # raw output mode (7 v. 8 bits) 
+      audible*: cunsignedchar   # FALSE if the bell is visual 
+      mono*: cunsignedchar      # TRUE if current screen is mono 
+      resized*: cunsignedchar   # TRUE if TERM has been resized 
+      orig_attr*: cunsignedchar # TRUE if we have the original colors 
+      orig_fore*: cshort        # original screen foreground color 
+      orig_back*: cshort        # original screen foreground color 
+      cursrow*: cint            # position of physical cursor 
+      curscol*: cint            # position of physical cursor 
+      visibility*: cint         # visibility of cursor 
+      orig_cursor*: cint        # original cursor size 
+      lines*: cint              # new value for LINES 
+      cols*: cint               # new value for COLS 
+      trap_mbe*: cunsignedlong # trap these mouse button events 
+      map_mbe_to_key*: cunsignedlong # map mouse buttons to slk 
+      mouse_wait*: cint # time to wait (in ms) for a button release after a press
+      slklines*: cint           # lines in use by slk_init() 
+      slk_winptr*: ptr TWINDOW   # window for slk 
+      linesrippedoff*: cint     # lines ripped off via ripoffline() 
+      linesrippedoffontop*: cint # lines ripped off on top via ripoffline() 
+      delaytenths*: cint        # 1/10ths second to wait block getch() for 
+      preserve*: cunsignedchar # TRUE if screen background to be preserved 
+      restore*: cint           # specifies if screen background to be restored, and how 
+      save_key_modifiers*: cunsignedchar # TRUE if each key modifiers saved with each key press 
+      return_key_modifiers*: cunsignedchar # TRUE if modifier keys are returned as "real" keys 
+      key_code*: cunsignedchar # TRUE if last key is a special key;
+      line_color*: cshort       # color of line attributes - default -1 
+
+var
+  LINES*{.importc: "LINES", dynlib: pdcursesdll.}: cint
+  COLS*{.importc: "COLS", dynlib: pdcursesdll.}: cint
+  stdscr*{.importc: "stdscr", dynlib: pdcursesdll.}: ptr TWINDOW
+  curscr*{.importc: "curscr", dynlib: pdcursesdll.}: ptr TWINDOW
+  SP*{.importc: "SP", dynlib: pdcursesdll.}: ptr TSCREEN
+  Mouse_status*{.importc: "Mouse_status", dynlib: pdcursesdll.}: TMOUSE_STATUS
+  COLORS*{.importc: "COLORS", dynlib: pdcursesdll.}: cint
+  COLOR_PAIRS*{.importc: "COLOR_PAIRS", dynlib: pdcursesdll.}: cint
+  TABSIZE*{.importc: "TABSIZE", dynlib: pdcursesdll.}: cint
+  acs_map*{.importc: "acs_map", dynlib: pdcursesdll.}: ptr cunsignedlong
+  ttytype*{.importc: "ttytype", dynlib: pdcursesdll.}: cstring
+
+template BUTTON_CHANGED*(x: expr): expr = 
+  (Mouse_status.changes and (1 shl ((x) - 1)))
+
+template BUTTON_STATUS*(x: expr): expr = 
+  (Mouse_status.button[(x) - 1])
+
+template ACS_PICK*(w, n: expr): expr = int32(w) or A_ALTCHARSET
+
+template KEY_F*(n: expr): expr = KEY_F0 + n
+
+template COLOR_PAIR*(n: expr): expr = 
+  ((cunsignedlong(n) shl COLOR_SHIFT) and A_COLOR)
+
+template PAIR_NUMBER*(n: expr): expr = 
+  (((n) and A_COLOR) shr COLOR_SHIFT)
+
+const
+  #MOUSE_X_POS* = (Mouse_status.x)
+  #MOUSE_Y_POS* = (Mouse_status.y)
+  #A_BUTTON_CHANGED* = (Mouse_status.changes and 7)
+  #MOUSE_MOVED* = (Mouse_status.changes and MOUSE_MOVED)
+  #MOUSE_POS_REPORT* = (Mouse_status.changes and MOUSE_POSITION)
+  #MOUSE_WHEEL_UP* = (Mouse_status.changes and MOUSE_WHEEL_UP)
+  #MOUSE_WHEEL_DOWN* = (Mouse_status.changes and MOUSE_WHEEL_DOWN)
+  ACS_ULCORNER* = ACS_PICK('l', '+')
+  ACS_LLCORNER* = ACS_PICK('m', '+')
+  ACS_URCORNER* = ACS_PICK('k', '+')
+  ACS_LRCORNER* = ACS_PICK('j', '+')
+  ACS_RTEE* = ACS_PICK('u', '+')
+  ACS_LTEE* = ACS_PICK('t', '+')
+  ACS_BTEE* = ACS_PICK('v', '+')
+  ACS_TTEE* = ACS_PICK('w', '+')
+  ACS_HLINE* = ACS_PICK('q', '-')
+  ACS_VLINE* = ACS_PICK('x', '|')
+  ACS_PLUS* = ACS_PICK('n', '+')
+  ACS_S1* = ACS_PICK('o', '-')
+  ACS_S9* = ACS_PICK('s', '_')
+  ACS_DIAMOND* = ACS_PICK('`', '+')
+  ACS_CKBOARD* = ACS_PICK('a', ':')
+  ACS_DEGREE* = ACS_PICK('f', '\'')
+  ACS_PLMINUS* = ACS_PICK('g', '#')
+  ACS_BULLET* = ACS_PICK('~', 'o')
+  ACS_LARROW* = ACS_PICK(',', '<')
+  ACS_RARROW* = ACS_PICK('+', '>')
+  ACS_DARROW* = ACS_PICK('.', 'v')
+  ACS_UARROW* = ACS_PICK('-', '^')
+  ACS_BOARD* = ACS_PICK('h', '#')
+  ACS_LANTERN* = ACS_PICK('i', '*')
+  ACS_BLOCK* = ACS_PICK('0', '#')
+  ACS_S3* = ACS_PICK('p', '-')
+  ACS_S7* = ACS_PICK('r', '-')
+  ACS_LEQUAL* = ACS_PICK('y', '<')
+  ACS_GEQUAL* = ACS_PICK('z', '>')
+  ACS_PI* = ACS_PICK('{', 'n')
+  ACS_NEQUAL* = ACS_PICK('|', '+')
+  ACS_STERLING* = ACS_PICK('}', 'L')
+  ACS_BSSB* = ACS_ULCORNER
+  ACS_SSBB* = ACS_LLCORNER
+  ACS_BBSS* = ACS_URCORNER
+  ACS_SBBS* = ACS_LRCORNER
+  ACS_SBSS* = ACS_RTEE
+  ACS_SSSB* = ACS_LTEE
+  ACS_SSBS* = ACS_BTEE
+  ACS_BSSS* = ACS_TTEE
+  ACS_BSBS* = ACS_HLINE
+  ACS_SBSB* = ACS_VLINE
+  ACS_SSSS* = ACS_PLUS
+discard """WACS_ULCORNER* = (addr((acs_map['l'])))
+  WACS_LLCORNER* = (addr((acs_map['m'])))
+  WACS_URCORNER* = (addr((acs_map['k'])))
+  WACS_LRCORNER* = (addr((acs_map['j'])))
+  WACS_RTEE* = (addr((acs_map['u'])))
+  WACS_LTEE* = (addr((acs_map['t'])))
+  WACS_BTEE* = (addr((acs_map['v'])))
+  WACS_TTEE* = (addr((acs_map['w'])))
+  WACS_HLINE* = (addr((acs_map['q'])))
+  WACS_VLINE* = (addr((acs_map['x'])))
+  WACS_PLUS* = (addr((acs_map['n'])))
+  WACS_S1* = (addr((acs_map['o'])))
+  WACS_S9* = (addr((acs_map['s'])))
+  WACS_DIAMOND* = (addr((acs_map['`'])))
+  WACS_CKBOARD* = (addr((acs_map['a'])))
+  WACS_DEGREE* = (addr((acs_map['f'])))
+  WACS_PLMINUS* = (addr((acs_map['g'])))
+  WACS_BULLET* = (addr((acs_map['~'])))
+  WACS_LARROW* = (addr((acs_map[','])))
+  WACS_RARROW* = (addr((acs_map['+'])))
+  WACS_DARROW* = (addr((acs_map['.'])))
+  WACS_UARROW* = (addr((acs_map['-'])))
+  WACS_BOARD* = (addr((acs_map['h'])))
+  WACS_LANTERN* = (addr((acs_map['i'])))
+  WACS_BLOCK* = (addr((acs_map['0'])))
+  WACS_S3* = (addr((acs_map['p'])))
+  WACS_S7* = (addr((acs_map['r'])))
+  WACS_LEQUAL* = (addr((acs_map['y'])))
+  WACS_GEQUAL* = (addr((acs_map['z'])))
+  WACS_PI* = (addr((acs_map['{'])))
+  WACS_NEQUAL* = (addr((acs_map['|'])))
+  WACS_STERLING* = (addr((acs_map['}'])))
+  WACS_BSSB* = WACS_ULCORNER
+  WACS_SSBB* = WACS_LLCORNER
+  WACS_BBSS* = WACS_URCORNER
+  WACS_SBBS* = WACS_LRCORNER
+  WACS_SBSS* = WACS_RTEE
+  WACS_SSSB* = WACS_LTEE
+  WACS_SSBS* = WACS_BTEE
+  WACS_BSSS* = WACS_TTEE
+  WACS_BSBS* = WACS_HLINE
+  WACS_SBSB* = WACS_VLINE
+  WACS_SSSS* = WACS_PLUS"""
+
+proc addch*(a2: cunsignedlong): cint{.extdecl, importc: "addch", 
+                                      dynlib: pdcursesdll.}
+proc addchnstr*(a2: ptr cunsignedlong; a3: cint): cint{.extdecl, 
+    importc: "addchnstr", dynlib: pdcursesdll.}
+proc addchstr*(a2: ptr cunsignedlong): cint{.extdecl, importc: "addchstr", 
+    dynlib: pdcursesdll.}
+proc addnstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "addnstr", 
+    dynlib: pdcursesdll.}
+proc addstr*(a2: cstring): cint{.extdecl, importc: "addstr", dynlib: pdcursesdll.}
+proc attroff*(a2: cunsignedlong): cint{.extdecl, importc: "attroff", 
+                                        dynlib: pdcursesdll.}
+proc attron*(a2: cunsignedlong): cint{.extdecl, importc: "attron", 
+                                       dynlib: pdcursesdll.}
+proc attrset*(a2: cunsignedlong): cint{.extdecl, importc: "attrset", 
+                                        dynlib: pdcursesdll.}
+proc attr_get*(a2: ptr cunsignedlong; a3: ptr cshort; a4: pointer): cint{.extdecl, 
+    importc: "attr_get", dynlib: pdcursesdll.}
+proc attr_off*(a2: cunsignedlong; a3: pointer): cint{.extdecl, 
+    importc: "attr_off", dynlib: pdcursesdll.}
+proc attr_on*(a2: cunsignedlong; a3: pointer): cint{.extdecl, importc: "attr_on", 
+    dynlib: pdcursesdll.}
+proc attr_set*(a2: cunsignedlong; a3: cshort; a4: pointer): cint{.extdecl, 
+    importc: "attr_set", dynlib: pdcursesdll.}
+proc baudrate*(): cint{.extdecl, importc: "baudrate", dynlib: pdcursesdll.}
+proc beep*(): cint{.extdecl, importc: "beep", dynlib: pdcursesdll.}
+proc bkgd*(a2: cunsignedlong): cint{.extdecl, importc: "bkgd", dynlib: pdcursesdll.}
+proc bkgdset*(a2: cunsignedlong){.extdecl, importc: "bkgdset", dynlib: pdcursesdll.}
+proc border*(a2: cunsignedlong; a3: cunsignedlong; a4: cunsignedlong; 
+             a5: cunsignedlong; a6: cunsignedlong; a7: cunsignedlong; 
+             a8: cunsignedlong; a9: cunsignedlong): cint{.extdecl, 
+    importc: "border", dynlib: pdcursesdll.}
+proc box*(a2: ptr TWINDOW; a3: cunsignedlong; a4: cunsignedlong): cint{.extdecl, 
+    importc: "box", dynlib: pdcursesdll.}
+proc can_change_color*(): cunsignedchar{.extdecl, importc: "can_change_color", 
+    dynlib: pdcursesdll.}
+proc cbreak*(): cint{.extdecl, importc: "cbreak", dynlib: pdcursesdll.}
+proc chgat*(a2: cint; a3: cunsignedlong; a4: cshort; a5: pointer): cint{.extdecl, 
+    importc: "chgat", dynlib: pdcursesdll.}
+proc clearok*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, 
+    importc: "clearok", dynlib: pdcursesdll.}
+proc clear*(): cint{.extdecl, importc: "clear", dynlib: pdcursesdll.}
+proc clrtobot*(): cint{.extdecl, importc: "clrtobot", dynlib: pdcursesdll.}
+proc clrtoeol*(): cint{.extdecl, importc: "clrtoeol", dynlib: pdcursesdll.}
+proc color_content*(a2: cshort; a3: ptr cshort; a4: ptr cshort; a5: ptr cshort): cint{.
+    extdecl, importc: "color_content", dynlib: pdcursesdll.}
+proc color_set*(a2: cshort; a3: pointer): cint{.extdecl, importc: "color_set", 
+    dynlib: pdcursesdll.}
+proc copywin*(a2: ptr TWINDOW; a3: ptr TWINDOW; a4: cint; a5: cint; a6: cint; 
+              a7: cint; a8: cint; a9: cint; a10: cint): cint{.extdecl, 
+    importc: "copywin", dynlib: pdcursesdll.}
+proc curs_set*(a2: cint): cint{.extdecl, importc: "curs_set", dynlib: pdcursesdll.}
+proc def_prog_mode*(): cint{.extdecl, importc: "def_prog_mode", 
+                             dynlib: pdcursesdll.}
+proc def_shell_mode*(): cint{.extdecl, importc: "def_shell_mode", 
+                              dynlib: pdcursesdll.}
+proc delay_output*(a2: cint): cint{.extdecl, importc: "delay_output", 
+                                    dynlib: pdcursesdll.}
+proc delch*(): cint{.extdecl, importc: "delch", dynlib: pdcursesdll.}
+proc deleteln*(): cint{.extdecl, importc: "deleteln", dynlib: pdcursesdll.}
+proc delscreen*(a2: ptr TSCREEN){.extdecl, importc: "delscreen", 
+                                 dynlib: pdcursesdll.}
+proc delwin*(a2: ptr TWINDOW): cint{.extdecl, importc: "delwin", 
+                                    dynlib: pdcursesdll.}
+proc derwin*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cint): ptr TWINDOW{.
+    extdecl, importc: "derwin", dynlib: pdcursesdll.}
+proc doupdate*(): cint{.extdecl, importc: "doupdate", dynlib: pdcursesdll.}
+proc dupwin*(a2: ptr TWINDOW): ptr TWINDOW{.extdecl, importc: "dupwin", 
+    dynlib: pdcursesdll.}
+proc echochar*(a2: cunsignedlong): cint{.extdecl, importc: "echochar", 
+    dynlib: pdcursesdll.}
+proc echo*(): cint{.extdecl, importc: "echo", dynlib: pdcursesdll.}
+proc endwin*(): cint{.extdecl, importc: "endwin", dynlib: pdcursesdll.}
+proc erasechar*(): char{.extdecl, importc: "erasechar", dynlib: pdcursesdll.}
+proc erase*(): cint{.extdecl, importc: "erase", dynlib: pdcursesdll.}
+proc filter*(){.extdecl, importc: "filter", dynlib: pdcursesdll.}
+proc flash*(): cint{.extdecl, importc: "flash", dynlib: pdcursesdll.}
+proc flushinp*(): cint{.extdecl, importc: "flushinp", dynlib: pdcursesdll.}
+proc getbkgd*(a2: ptr TWINDOW): cunsignedlong{.extdecl, importc: "getbkgd", 
+    dynlib: pdcursesdll.}
+proc getnstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "getnstr", 
+    dynlib: pdcursesdll.}
+proc getstr*(a2: cstring): cint{.extdecl, importc: "getstr", dynlib: pdcursesdll.}
+proc getwin*(a2: File): ptr TWINDOW{.extdecl, importc: "getwin", 
+                                        dynlib: pdcursesdll.}
+proc halfdelay*(a2: cint): cint{.extdecl, importc: "halfdelay", 
+                                 dynlib: pdcursesdll.}
+proc has_colors*(): cunsignedchar{.extdecl, importc: "has_colors", 
+                                   dynlib: pdcursesdll.}
+proc has_ic*(): cunsignedchar{.extdecl, importc: "has_ic", dynlib: pdcursesdll.}
+proc has_il*(): cunsignedchar{.extdecl, importc: "has_il", dynlib: pdcursesdll.}
+proc hline*(a2: cunsignedlong; a3: cint): cint{.extdecl, importc: "hline", 
+    dynlib: pdcursesdll.}
+proc idcok*(a2: ptr TWINDOW; a3: cunsignedchar){.extdecl, importc: "idcok", 
+    dynlib: pdcursesdll.}
+proc idlok*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, importc: "idlok", 
+    dynlib: pdcursesdll.}
+proc immedok*(a2: ptr TWINDOW; a3: cunsignedchar){.extdecl, importc: "immedok", 
+    dynlib: pdcursesdll.}
+proc inchnstr*(a2: ptr cunsignedlong; a3: cint): cint{.extdecl, 
+    importc: "inchnstr", dynlib: pdcursesdll.}
+proc inchstr*(a2: ptr cunsignedlong): cint{.extdecl, importc: "inchstr", 
+    dynlib: pdcursesdll.}
+proc inch*(): cunsignedlong{.extdecl, importc: "inch", dynlib: pdcursesdll.}
+proc init_color*(a2: cshort; a3: cshort; a4: cshort; a5: cshort): cint{.extdecl, 
+    importc: "init_color", dynlib: pdcursesdll.}
+proc init_pair*(a2: cshort; a3: cshort; a4: cshort): cint{.extdecl, 
+    importc: "init_pair", dynlib: pdcursesdll.}
+proc initscr*(): ptr TWINDOW{.extdecl, importc: "initscr", dynlib: pdcursesdll.}
+proc innstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "innstr", 
+    dynlib: pdcursesdll.}
+proc insch*(a2: cunsignedlong): cint{.extdecl, importc: "insch", 
+                                      dynlib: pdcursesdll.}
+proc insdelln*(a2: cint): cint{.extdecl, importc: "insdelln", dynlib: pdcursesdll.}
+proc insertln*(): cint{.extdecl, importc: "insertln", dynlib: pdcursesdll.}
+proc insnstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "insnstr", 
+    dynlib: pdcursesdll.}
+proc insstr*(a2: cstring): cint{.extdecl, importc: "insstr", dynlib: pdcursesdll.}
+proc instr*(a2: cstring): cint{.extdecl, importc: "instr", dynlib: pdcursesdll.}
+proc intrflush*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, 
+    importc: "intrflush", dynlib: pdcursesdll.}
+proc isendwin*(): cunsignedchar{.extdecl, importc: "isendwin", dynlib: pdcursesdll.}
+proc is_linetouched*(a2: ptr TWINDOW; a3: cint): cunsignedchar{.extdecl, 
+    importc: "is_linetouched", dynlib: pdcursesdll.}
+proc is_wintouched*(a2: ptr TWINDOW): cunsignedchar{.extdecl, 
+    importc: "is_wintouched", dynlib: pdcursesdll.}
+proc keyname*(a2: cint): cstring{.extdecl, importc: "keyname", dynlib: pdcursesdll.}
+proc keypad*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, importc: "keypad", 
+    dynlib: pdcursesdll.}
+proc killchar*(): char{.extdecl, importc: "killchar", dynlib: pdcursesdll.}
+proc leaveok*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, 
+    importc: "leaveok", dynlib: pdcursesdll.}
+proc longname*(): cstring{.extdecl, importc: "longname", dynlib: pdcursesdll.}
+proc meta*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, importc: "meta", 
+    dynlib: pdcursesdll.}
+proc move*(a2: cint; a3: cint): cint{.extdecl, importc: "move", 
+                                      dynlib: pdcursesdll.}
+proc mvaddch*(a2: cint; a3: cint; a4: cunsignedlong): cint{.extdecl, 
+    importc: "mvaddch", dynlib: pdcursesdll.}
+proc mvaddchnstr*(a2: cint; a3: cint; a4: ptr cunsignedlong; a5: cint): cint{.
+    extdecl, importc: "mvaddchnstr", dynlib: pdcursesdll.}
+proc mvaddchstr*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvaddchstr", dynlib: pdcursesdll.}
+proc mvaddnstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvaddnstr", dynlib: pdcursesdll.}
+proc mvaddstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, 
+    importc: "mvaddstr", dynlib: pdcursesdll.}
+proc mvchgat*(a2: cint; a3: cint; a4: cint; a5: cunsignedlong; a6: cshort; 
+              a7: pointer): cint{.extdecl, importc: "mvchgat", dynlib: pdcursesdll.}
+proc mvcur*(a2: cint; a3: cint; a4: cint; a5: cint): cint{.extdecl, 
+    importc: "mvcur", dynlib: pdcursesdll.}
+proc mvdelch*(a2: cint; a3: cint): cint{.extdecl, importc: "mvdelch", 
+    dynlib: pdcursesdll.}
+proc mvderwin*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "mvderwin", dynlib: pdcursesdll.}
+proc mvgetch*(a2: cint; a3: cint): cint{.extdecl, importc: "mvgetch", 
+    dynlib: pdcursesdll.}
+proc mvgetnstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvgetnstr", dynlib: pdcursesdll.}
+proc mvgetstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, 
+    importc: "mvgetstr", dynlib: pdcursesdll.}
+proc mvhline*(a2: cint; a3: cint; a4: cunsignedlong; a5: cint): cint{.extdecl, 
+    importc: "mvhline", dynlib: pdcursesdll.}
+proc mvinch*(a2: cint; a3: cint): cunsignedlong{.extdecl, importc: "mvinch", 
+    dynlib: pdcursesdll.}
+proc mvinchnstr*(a2: cint; a3: cint; a4: ptr cunsignedlong; a5: cint): cint{.
+    extdecl, importc: "mvinchnstr", dynlib: pdcursesdll.}
+proc mvinchstr*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvinchstr", dynlib: pdcursesdll.}
+proc mvinnstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvinnstr", dynlib: pdcursesdll.}
+proc mvinsch*(a2: cint; a3: cint; a4: cunsignedlong): cint{.extdecl, 
+    importc: "mvinsch", dynlib: pdcursesdll.}
+proc mvinsnstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvinsnstr", dynlib: pdcursesdll.}
+proc mvinsstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, 
+    importc: "mvinsstr", dynlib: pdcursesdll.}
+proc mvinstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, importc: "mvinstr", 
+    dynlib: pdcursesdll.}
+proc mvprintw*(a2: cint; a3: cint; a4: cstring): cint{.varargs, extdecl, 
+    importc: "mvprintw", dynlib: pdcursesdll.}
+proc mvscanw*(a2: cint; a3: cint; a4: cstring): cint{.varargs, extdecl, 
+    importc: "mvscanw", dynlib: pdcursesdll.}
+proc mvvline*(a2: cint; a3: cint; a4: cunsignedlong; a5: cint): cint{.extdecl, 
+    importc: "mvvline", dynlib: pdcursesdll.}
+proc mvwaddchnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong; 
+                   a6: cint): cint{.extdecl, importc: "mvwaddchnstr", 
+                                    dynlib: pdcursesdll.}
+proc mvwaddchstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwaddchstr", dynlib: pdcursesdll.}
+proc mvwaddch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong): cint{.
+    extdecl, importc: "mvwaddch", dynlib: pdcursesdll.}
+proc mvwaddnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwaddnstr", dynlib: pdcursesdll.}
+proc mvwaddstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.extdecl, 
+    importc: "mvwaddstr", dynlib: pdcursesdll.}
+proc mvwchgat*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cunsignedlong; 
+               a7: cshort; a8: pointer): cint{.extdecl, importc: "mvwchgat", 
+    dynlib: pdcursesdll.}
+proc mvwdelch*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "mvwdelch", dynlib: pdcursesdll.}
+proc mvwgetch*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "mvwgetch", dynlib: pdcursesdll.}
+proc mvwgetnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwgetnstr", dynlib: pdcursesdll.}
+proc mvwgetstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.extdecl, 
+    importc: "mvwgetstr", dynlib: pdcursesdll.}
+proc mvwhline*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong; a6: cint): cint{.
+    extdecl, importc: "mvwhline", dynlib: pdcursesdll.}
+proc mvwinchnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong; 
+                  a6: cint): cint{.extdecl, importc: "mvwinchnstr", 
+                                   dynlib: pdcursesdll.}
+proc mvwinchstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwinchstr", dynlib: pdcursesdll.}
+proc mvwinch*(a2: ptr TWINDOW; a3: cint; a4: cint): cunsignedlong{.extdecl, 
+    importc: "mvwinch", dynlib: pdcursesdll.}
+proc mvwinnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwinnstr", dynlib: pdcursesdll.}
+proc mvwinsch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong): cint{.
+    extdecl, importc: "mvwinsch", dynlib: pdcursesdll.}
+proc mvwinsnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwinsnstr", dynlib: pdcursesdll.}
+proc mvwinsstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.extdecl, 
+    importc: "mvwinsstr", dynlib: pdcursesdll.}
+proc mvwinstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.extdecl, 
+    importc: "mvwinstr", dynlib: pdcursesdll.}
+proc mvwin*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, importc: "mvwin", 
+    dynlib: pdcursesdll.}
+proc mvwprintw*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.varargs, 
+    extdecl, importc: "mvwprintw", dynlib: pdcursesdll.}
+proc mvwscanw*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.varargs, 
+    extdecl, importc: "mvwscanw", dynlib: pdcursesdll.}
+proc mvwvline*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong; a6: cint): cint{.
+    extdecl, importc: "mvwvline", dynlib: pdcursesdll.}
+proc napms*(a2: cint): cint{.extdecl, importc: "napms", dynlib: pdcursesdll.}
+proc newpad*(a2: cint; a3: cint): ptr TWINDOW{.extdecl, importc: "newpad", 
+    dynlib: pdcursesdll.}
+proc newterm*(a2: cstring; a3: File; a4: File): ptr TSCREEN{.extdecl, 
+    importc: "newterm", dynlib: pdcursesdll.}
+proc newwin*(a2: cint; a3: cint; a4: cint; a5: cint): ptr TWINDOW{.extdecl, 
+    importc: "newwin", dynlib: pdcursesdll.}
+proc nl*(): cint{.extdecl, importc: "nl", dynlib: pdcursesdll.}
+proc nocbreak*(): cint{.extdecl, importc: "nocbreak", dynlib: pdcursesdll.}
+proc nodelay*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, 
+    importc: "nodelay", dynlib: pdcursesdll.}
+proc noecho*(): cint{.extdecl, importc: "noecho", dynlib: pdcursesdll.}
+proc nonl*(): cint{.extdecl, importc: "nonl", dynlib: pdcursesdll.}
+proc noqiflush*(){.extdecl, importc: "noqiflush", dynlib: pdcursesdll.}
+proc noraw*(): cint{.extdecl, importc: "noraw", dynlib: pdcursesdll.}
+proc notimeout*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, 
+    importc: "notimeout", dynlib: pdcursesdll.}
+proc overlay*(a2: ptr TWINDOW; a3: ptr TWINDOW): cint{.extdecl, importc: "overlay", 
+    dynlib: pdcursesdll.}
+proc overwrite*(a2: ptr TWINDOW; a3: ptr TWINDOW): cint{.extdecl, 
+    importc: "overwrite", dynlib: pdcursesdll.}
+proc pair_content*(a2: cshort; a3: ptr cshort; a4: ptr cshort): cint{.extdecl, 
+    importc: "pair_content", dynlib: pdcursesdll.}
+proc pechochar*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "pechochar", dynlib: pdcursesdll.}
+proc pnoutrefresh*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cint; 
+                   a7: cint; a8: cint): cint{.extdecl, importc: "pnoutrefresh", 
+    dynlib: pdcursesdll.}
+proc prefresh*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cint; a7: cint; 
+               a8: cint): cint{.extdecl, importc: "prefresh", dynlib: pdcursesdll.}
+proc printw*(a2: cstring): cint{.varargs, extdecl, importc: "printw", 
+                                 dynlib: pdcursesdll.}
+proc putwin*(a2: ptr TWINDOW; a3: File): cint{.extdecl, importc: "putwin", 
+    dynlib: pdcursesdll.}
+proc qiflush*(){.extdecl, importc: "qiflush", dynlib: pdcursesdll.}
+proc raw*(): cint{.extdecl, importc: "raw", dynlib: pdcursesdll.}
+proc redrawwin*(a2: ptr TWINDOW): cint{.extdecl, importc: "redrawwin", 
+                                       dynlib: pdcursesdll.}
+proc refresh*(): cint{.extdecl, importc: "refresh", dynlib: pdcursesdll.}
+proc reset_prog_mode*(): cint{.extdecl, importc: "reset_prog_mode", 
+                               dynlib: pdcursesdll.}
+proc reset_shell_mode*(): cint{.extdecl, importc: "reset_shell_mode", 
+                                dynlib: pdcursesdll.}
+proc resetty*(): cint{.extdecl, importc: "resetty", dynlib: pdcursesdll.}
+#int     ripoffline(int, int (*)(TWINDOW *, int));
+proc savetty*(): cint{.extdecl, importc: "savetty", dynlib: pdcursesdll.}
+proc scanw*(a2: cstring): cint{.varargs, extdecl, importc: "scanw", 
+                                dynlib: pdcursesdll.}
+proc scr_dump*(a2: cstring): cint{.extdecl, importc: "scr_dump", 
+                                   dynlib: pdcursesdll.}
+proc scr_init*(a2: cstring): cint{.extdecl, importc: "scr_init", 
+                                   dynlib: pdcursesdll.}
+proc scr_restore*(a2: cstring): cint{.extdecl, importc: "scr_restore", 
+                                      dynlib: pdcursesdll.}
+proc scr_set*(a2: cstring): cint{.extdecl, importc: "scr_set", dynlib: pdcursesdll.}
+proc scrl*(a2: cint): cint{.extdecl, importc: "scrl", dynlib: pdcursesdll.}
+proc scroll*(a2: ptr TWINDOW): cint{.extdecl, importc: "scroll", 
+                                    dynlib: pdcursesdll.}
+proc scrollok*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, 
+    importc: "scrollok", dynlib: pdcursesdll.}
+proc set_term*(a2: ptr TSCREEN): ptr TSCREEN{.extdecl, importc: "set_term", 
+    dynlib: pdcursesdll.}
+proc setscrreg*(a2: cint; a3: cint): cint{.extdecl, importc: "setscrreg", 
+    dynlib: pdcursesdll.}
+proc slk_attroff*(a2: cunsignedlong): cint{.extdecl, importc: "slk_attroff", 
+    dynlib: pdcursesdll.}
+proc slk_attr_off*(a2: cunsignedlong; a3: pointer): cint{.extdecl, 
+    importc: "slk_attr_off", dynlib: pdcursesdll.}
+proc slk_attron*(a2: cunsignedlong): cint{.extdecl, importc: "slk_attron", 
+    dynlib: pdcursesdll.}
+proc slk_attr_on*(a2: cunsignedlong; a3: pointer): cint{.extdecl, 
+    importc: "slk_attr_on", dynlib: pdcursesdll.}
+proc slk_attrset*(a2: cunsignedlong): cint{.extdecl, importc: "slk_attrset", 
+    dynlib: pdcursesdll.}
+proc slk_attr_set*(a2: cunsignedlong; a3: cshort; a4: pointer): cint{.extdecl, 
+    importc: "slk_attr_set", dynlib: pdcursesdll.}
+proc slk_clear*(): cint{.extdecl, importc: "slk_clear", dynlib: pdcursesdll.}
+proc slk_color*(a2: cshort): cint{.extdecl, importc: "slk_color", 
+                                   dynlib: pdcursesdll.}
+proc slk_init*(a2: cint): cint{.extdecl, importc: "slk_init", dynlib: pdcursesdll.}
+proc slk_label*(a2: cint): cstring{.extdecl, importc: "slk_label", 
+                                    dynlib: pdcursesdll.}
+proc slk_noutrefresh*(): cint{.extdecl, importc: "slk_noutrefresh", 
+                               dynlib: pdcursesdll.}
+proc slk_refresh*(): cint{.extdecl, importc: "slk_refresh", dynlib: pdcursesdll.}
+proc slk_restore*(): cint{.extdecl, importc: "slk_restore", dynlib: pdcursesdll.}
+proc slk_set*(a2: cint; a3: cstring; a4: cint): cint{.extdecl, importc: "slk_set", 
+    dynlib: pdcursesdll.}
+proc slk_touch*(): cint{.extdecl, importc: "slk_touch", dynlib: pdcursesdll.}
+proc standend*(): cint{.extdecl, importc: "standend", dynlib: pdcursesdll.}
+proc standout*(): cint{.extdecl, importc: "standout", dynlib: pdcursesdll.}
+proc start_color*(): cint{.extdecl, importc: "start_color", dynlib: pdcursesdll.}
+proc subpad*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cint): ptr TWINDOW{.
+    extdecl, importc: "subpad", dynlib: pdcursesdll.}
+proc subwin*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cint): ptr TWINDOW{.
+    extdecl, importc: "subwin", dynlib: pdcursesdll.}
+proc syncok*(a2: ptr TWINDOW; a3: cunsignedchar): cint{.extdecl, importc: "syncok", 
+    dynlib: pdcursesdll.}
+proc termattrs*(): cunsignedlong{.extdecl, importc: "termattrs", 
+                                  dynlib: pdcursesdll.}
+proc termattrs2*(): cunsignedlong{.extdecl, importc: "term_attrs", 
+                                   dynlib: pdcursesdll.}
+proc termname*(): cstring{.extdecl, importc: "termname", dynlib: pdcursesdll.}
+proc timeout*(a2: cint){.extdecl, importc: "timeout", dynlib: pdcursesdll.}
+proc touchline*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "touchline", dynlib: pdcursesdll.}
+proc touchwin*(a2: ptr TWINDOW): cint{.extdecl, importc: "touchwin", 
+                                      dynlib: pdcursesdll.}
+proc typeahead*(a2: cint): cint{.extdecl, importc: "typeahead", 
+                                 dynlib: pdcursesdll.}
+proc untouchwin*(a2: ptr TWINDOW): cint{.extdecl, importc: "untouchwin", 
+                                        dynlib: pdcursesdll.}
+proc use_env*(a2: cunsignedchar){.extdecl, importc: "use_env", dynlib: pdcursesdll.}
+proc vidattr*(a2: cunsignedlong): cint{.extdecl, importc: "vidattr", 
+                                        dynlib: pdcursesdll.}
+proc vid_attr*(a2: cunsignedlong; a3: cshort; a4: pointer): cint{.extdecl, 
+    importc: "vid_attr", dynlib: pdcursesdll.}
+#int     vidputs(chtype, int (*)(int));
+#int     vid_puts(attr_t, short, void *, int (*)(int));
+proc vline*(a2: cunsignedlong; a3: cint): cint{.extdecl, importc: "vline", 
+    dynlib: pdcursesdll.}
+proc vwprintw*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, varargs,
+    importc: "vw_printw", dynlib: pdcursesdll.}
+proc vwprintw2*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, varargs,
+    importc: "vwprintw", dynlib: pdcursesdll.}
+proc vwscanw*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, varargs,
+    importc: "vw_scanw", dynlib: pdcursesdll.}
+proc vwscanw2*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, varargs,
+    importc: "vwscanw", dynlib: pdcursesdll.}
+proc waddchnstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "waddchnstr", dynlib: pdcursesdll.}
+proc waddchstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "waddchstr", dynlib: pdcursesdll.}
+proc waddch*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, importc: "waddch", 
+    dynlib: pdcursesdll.}
+proc waddnstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "waddnstr", dynlib: pdcursesdll.}
+proc waddstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, importc: "waddstr", 
+    dynlib: pdcursesdll.}
+proc wattroff*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "wattroff", dynlib: pdcursesdll.}
+proc wattron*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "wattron", dynlib: pdcursesdll.}
+proc wattrset*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "wattrset", dynlib: pdcursesdll.}
+proc wattr_get*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: ptr cshort; 
+                a5: pointer): cint{.extdecl, importc: "wattr_get", 
+                                    dynlib: pdcursesdll.}
+proc wattr_off*(a2: ptr TWINDOW; a3: cunsignedlong; a4: pointer): cint{.extdecl, 
+    importc: "wattr_off", dynlib: pdcursesdll.}
+proc wattr_on*(a2: ptr TWINDOW; a3: cunsignedlong; a4: pointer): cint{.extdecl, 
+    importc: "wattr_on", dynlib: pdcursesdll.}
+proc wattr_set*(a2: ptr TWINDOW; a3: cunsignedlong; a4: cshort; a5: pointer): cint{.
+    extdecl, importc: "wattr_set", dynlib: pdcursesdll.}
+proc wbkgdset*(a2: ptr TWINDOW; a3: cunsignedlong){.extdecl, importc: "wbkgdset", 
+    dynlib: pdcursesdll.}
+proc wbkgd*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, importc: "wbkgd", 
+    dynlib: pdcursesdll.}
+proc wborder*(a2: ptr TWINDOW; a3: cunsignedlong; a4: cunsignedlong; 
+              a5: cunsignedlong; a6: cunsignedlong; a7: cunsignedlong; 
+              a8: cunsignedlong; a9: cunsignedlong; a10: cunsignedlong): cint{.
+    extdecl, importc: "wborder", dynlib: pdcursesdll.}
+proc wchgat*(a2: ptr TWINDOW; a3: cint; a4: cunsignedlong; a5: cshort; 
+             a6: pointer): cint{.extdecl, importc: "wchgat", dynlib: pdcursesdll.}
+proc wclear*(a2: ptr TWINDOW): cint{.extdecl, importc: "wclear", 
+                                    dynlib: pdcursesdll.}
+proc wclrtobot*(a2: ptr TWINDOW): cint{.extdecl, importc: "wclrtobot", 
+                                       dynlib: pdcursesdll.}
+proc wclrtoeol*(a2: ptr TWINDOW): cint{.extdecl, importc: "wclrtoeol", 
+                                       dynlib: pdcursesdll.}
+proc wcolor_set*(a2: ptr TWINDOW; a3: cshort; a4: pointer): cint{.extdecl, 
+    importc: "wcolor_set", dynlib: pdcursesdll.}
+proc wcursyncup*(a2: ptr TWINDOW){.extdecl, importc: "wcursyncup", 
+                                  dynlib: pdcursesdll.}
+proc wdelch*(a2: ptr TWINDOW): cint{.extdecl, importc: "wdelch", 
+                                    dynlib: pdcursesdll.}
+proc wdeleteln*(a2: ptr TWINDOW): cint{.extdecl, importc: "wdeleteln", 
+                                       dynlib: pdcursesdll.}
+proc wechochar*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "wechochar", dynlib: pdcursesdll.}
+proc werase*(a2: ptr TWINDOW): cint{.extdecl, importc: "werase", 
+                                    dynlib: pdcursesdll.}
+proc wgetch*(a2: ptr TWINDOW): cint{.extdecl, importc: "wgetch", 
+                                    dynlib: pdcursesdll.}
+proc wgetnstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "wgetnstr", dynlib: pdcursesdll.}
+proc wgetstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, importc: "wgetstr", 
+    dynlib: pdcursesdll.}
+proc whline*(a2: ptr TWINDOW; a3: cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "whline", dynlib: pdcursesdll.}
+proc winchnstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "winchnstr", dynlib: pdcursesdll.}
+proc winchstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "winchstr", dynlib: pdcursesdll.}
+proc winch*(a2: ptr TWINDOW): cunsignedlong{.extdecl, importc: "winch", 
+    dynlib: pdcursesdll.}
+proc winnstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "winnstr", dynlib: pdcursesdll.}
+proc winsch*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, importc: "winsch", 
+    dynlib: pdcursesdll.}
+proc winsdelln*(a2: ptr TWINDOW; a3: cint): cint{.extdecl, importc: "winsdelln", 
+    dynlib: pdcursesdll.}
+proc winsertln*(a2: ptr TWINDOW): cint{.extdecl, importc: "winsertln", 
+                                       dynlib: pdcursesdll.}
+proc winsnstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "winsnstr", dynlib: pdcursesdll.}
+proc winsstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, importc: "winsstr", 
+    dynlib: pdcursesdll.}
+proc winstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, importc: "winstr", 
+    dynlib: pdcursesdll.}
+proc wmove*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, importc: "wmove", 
+    dynlib: pdcursesdll.}
+proc wnoutrefresh*(a2: ptr TWINDOW): cint{.extdecl, importc: "wnoutrefresh", 
+    dynlib: pdcursesdll.}
+proc wprintw*(a2: ptr TWINDOW; a3: cstring): cint{.varargs, extdecl, 
+    importc: "wprintw", dynlib: pdcursesdll.}
+proc wredrawln*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "wredrawln", dynlib: pdcursesdll.}
+proc wrefresh*(a2: ptr TWINDOW): cint{.extdecl, importc: "wrefresh", 
+                                      dynlib: pdcursesdll.}
+proc wscanw*(a2: ptr TWINDOW; a3: cstring): cint{.varargs, extdecl, 
+    importc: "wscanw", dynlib: pdcursesdll.}
+proc wscrl*(a2: ptr TWINDOW; a3: cint): cint{.extdecl, importc: "wscrl", 
+    dynlib: pdcursesdll.}
+proc wsetscrreg*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "wsetscrreg", dynlib: pdcursesdll.}
+proc wstandend*(a2: ptr TWINDOW): cint{.extdecl, importc: "wstandend", 
+                                       dynlib: pdcursesdll.}
+proc wstandout*(a2: ptr TWINDOW): cint{.extdecl, importc: "wstandout", 
+                                       dynlib: pdcursesdll.}
+proc wsyncdown*(a2: ptr TWINDOW){.extdecl, importc: "wsyncdown", 
+                                 dynlib: pdcursesdll.}
+proc wsyncup*(a2: ptr TWINDOW){.extdecl, importc: "wsyncup", dynlib: pdcursesdll.}
+proc wtimeout*(a2: ptr TWINDOW; a3: cint){.extdecl, importc: "wtimeout", 
+    dynlib: pdcursesdll.}
+proc wtouchln*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint): cint{.extdecl, 
+    importc: "wtouchln", dynlib: pdcursesdll.}
+proc wvline*(a2: ptr TWINDOW; a3: cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "wvline", dynlib: pdcursesdll.}
+proc addnwstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "addnwstr", 
+    dynlib: pdcursesdll.}
+proc addwstr*(a2: cstring): cint{.extdecl, importc: "addwstr", 
+                                      dynlib: pdcursesdll.}
+proc add_wch*(a2: ptr cunsignedlong): cint{.extdecl, importc: "add_wch", 
+    dynlib: pdcursesdll.}
+proc add_wchnstr*(a2: ptr cunsignedlong; a3: cint): cint{.extdecl, 
+    importc: "add_wchnstr", dynlib: pdcursesdll.}
+proc add_wchstr*(a2: ptr cunsignedlong): cint{.extdecl, importc: "add_wchstr", 
+    dynlib: pdcursesdll.}
+proc border_set*(a2: ptr cunsignedlong; a3: ptr cunsignedlong; 
+                 a4: ptr cunsignedlong; a5: ptr cunsignedlong; 
+                 a6: ptr cunsignedlong; a7: ptr cunsignedlong; 
+                 a8: ptr cunsignedlong; a9: ptr cunsignedlong): cint{.extdecl, 
+    importc: "border_set", dynlib: pdcursesdll.}
+proc box_set*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: ptr cunsignedlong): cint{.
+    extdecl, importc: "box_set", dynlib: pdcursesdll.}
+proc echo_wchar*(a2: ptr cunsignedlong): cint{.extdecl, importc: "echo_wchar", 
+    dynlib: pdcursesdll.}
+proc erasewchar*(a2: cstring): cint{.extdecl, importc: "erasewchar", 
+    dynlib: pdcursesdll.}
+proc getbkgrnd*(a2: ptr cunsignedlong): cint{.extdecl, importc: "getbkgrnd", 
+    dynlib: pdcursesdll.}
+proc getcchar*(a2: ptr cunsignedlong; a3: cstring; a4: ptr cunsignedlong; 
+               a5: ptr cshort; a6: pointer): cint{.extdecl, importc: "getcchar", 
+    dynlib: pdcursesdll.}
+proc getn_wstr*(a2: ptr cint; a3: cint): cint{.extdecl, importc: "getn_wstr", 
+    dynlib: pdcursesdll.}
+proc get_wch*(a2: ptr cint): cint{.extdecl, importc: "get_wch", 
+                                     dynlib: pdcursesdll.}
+proc get_wstr*(a2: ptr cint): cint{.extdecl, importc: "get_wstr", 
+                                      dynlib: pdcursesdll.}
+proc hline_set*(a2: ptr cunsignedlong; a3: cint): cint{.extdecl, 
+    importc: "hline_set", dynlib: pdcursesdll.}
+proc innwstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "innwstr", 
+    dynlib: pdcursesdll.}
+proc ins_nwstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "ins_nwstr", 
+    dynlib: pdcursesdll.}
+proc ins_wch*(a2: ptr cunsignedlong): cint{.extdecl, importc: "ins_wch", 
+    dynlib: pdcursesdll.}
+proc ins_wstr*(a2: cstring): cint{.extdecl, importc: "ins_wstr", 
+                                       dynlib: pdcursesdll.}
+proc inwstr*(a2: cstring): cint{.extdecl, importc: "inwstr", 
+                                     dynlib: pdcursesdll.}
+proc in_wch*(a2: ptr cunsignedlong): cint{.extdecl, importc: "in_wch", 
+    dynlib: pdcursesdll.}
+proc in_wchnstr*(a2: ptr cunsignedlong; a3: cint): cint{.extdecl, 
+    importc: "in_wchnstr", dynlib: pdcursesdll.}
+proc in_wchstr*(a2: ptr cunsignedlong): cint{.extdecl, importc: "in_wchstr", 
+    dynlib: pdcursesdll.}
+proc key_name*(a2: char): cstring{.extdecl, importc: "key_name", 
+                                      dynlib: pdcursesdll.}
+proc killwchar*(a2: cstring): cint{.extdecl, importc: "killwchar", 
+                                        dynlib: pdcursesdll.}
+proc mvaddnwstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvaddnwstr", dynlib: pdcursesdll.}
+proc mvaddwstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, 
+    importc: "mvaddwstr", dynlib: pdcursesdll.}
+proc mvadd_wch*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvadd_wch", dynlib: pdcursesdll.}
+proc mvadd_wchnstr*(a2: cint; a3: cint; a4: ptr cunsignedlong; a5: cint): cint{.
+    extdecl, importc: "mvadd_wchnstr", dynlib: pdcursesdll.}
+proc mvadd_wchstr*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvadd_wchstr", dynlib: pdcursesdll.}
+proc mvgetn_wstr*(a2: cint; a3: cint; a4: ptr cint; a5: cint): cint{.extdecl, 
+    importc: "mvgetn_wstr", dynlib: pdcursesdll.}
+proc mvget_wch*(a2: cint; a3: cint; a4: ptr cint): cint{.extdecl, 
+    importc: "mvget_wch", dynlib: pdcursesdll.}
+proc mvget_wstr*(a2: cint; a3: cint; a4: ptr cint): cint{.extdecl, 
+    importc: "mvget_wstr", dynlib: pdcursesdll.}
+proc mvhline_set*(a2: cint; a3: cint; a4: ptr cunsignedlong; a5: cint): cint{.
+    extdecl, importc: "mvhline_set", dynlib: pdcursesdll.}
+proc mvinnwstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvinnwstr", dynlib: pdcursesdll.}
+proc mvins_nwstr*(a2: cint; a3: cint; a4: cstring; a5: cint): cint{.extdecl, 
+    importc: "mvins_nwstr", dynlib: pdcursesdll.}
+proc mvins_wch*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvins_wch", dynlib: pdcursesdll.}
+proc mvins_wstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, 
+    importc: "mvins_wstr", dynlib: pdcursesdll.}
+proc mvinwstr*(a2: cint; a3: cint; a4: cstring): cint{.extdecl, 
+    importc: "mvinwstr", dynlib: pdcursesdll.}
+proc mvin_wch*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvin_wch", dynlib: pdcursesdll.}
+proc mvin_wchnstr*(a2: cint; a3: cint; a4: ptr cunsignedlong; a5: cint): cint{.
+    extdecl, importc: "mvin_wchnstr", dynlib: pdcursesdll.}
+proc mvin_wchstr*(a2: cint; a3: cint; a4: ptr cunsignedlong): cint{.extdecl, 
+    importc: "mvin_wchstr", dynlib: pdcursesdll.}
+proc mvvline_set*(a2: cint; a3: cint; a4: ptr cunsignedlong; a5: cint): cint{.
+    extdecl, importc: "mvvline_set", dynlib: pdcursesdll.}
+proc mvwaddnwstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwaddnwstr", dynlib: pdcursesdll.}
+proc mvwaddwstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.
+    extdecl, importc: "mvwaddwstr", dynlib: pdcursesdll.}
+proc mvwadd_wch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwadd_wch", dynlib: pdcursesdll.}
+proc mvwadd_wchnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong; 
+                     a6: cint): cint{.extdecl, importc: "mvwadd_wchnstr", 
+                                      dynlib: pdcursesdll.}
+proc mvwadd_wchstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwadd_wchstr", dynlib: pdcursesdll.}
+proc mvwgetn_wstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cint; a6: cint): cint{.
+    extdecl, importc: "mvwgetn_wstr", dynlib: pdcursesdll.}
+proc mvwget_wch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cint): cint{.
+    extdecl, importc: "mvwget_wch", dynlib: pdcursesdll.}
+proc mvwget_wstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cint): cint{.
+    extdecl, importc: "mvwget_wstr", dynlib: pdcursesdll.}
+proc mvwhline_set*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong; 
+                   a6: cint): cint{.extdecl, importc: "mvwhline_set", 
+                                    dynlib: pdcursesdll.}
+proc mvwinnwstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwinnwstr", dynlib: pdcursesdll.}
+proc mvwins_nwstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring; a6: cint): cint{.
+    extdecl, importc: "mvwins_nwstr", dynlib: pdcursesdll.}
+proc mvwins_wch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwins_wch", dynlib: pdcursesdll.}
+proc mvwins_wstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.
+    extdecl, importc: "mvwins_wstr", dynlib: pdcursesdll.}
+proc mvwin_wch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwin_wch", dynlib: pdcursesdll.}
+proc mvwin_wchnstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong; 
+                    a6: cint): cint{.extdecl, importc: "mvwin_wchnstr", 
+                                     dynlib: pdcursesdll.}
+proc mvwin_wchstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong): cint{.
+    extdecl, importc: "mvwin_wchstr", dynlib: pdcursesdll.}
+proc mvwinwstr*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cstring): cint{.
+    extdecl, importc: "mvwinwstr", dynlib: pdcursesdll.}
+proc mvwvline_set*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: ptr cunsignedlong; 
+                   a6: cint): cint{.extdecl, importc: "mvwvline_set", 
+                                    dynlib: pdcursesdll.}
+proc pecho_wchar*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "pecho_wchar", dynlib: pdcursesdll.}
+proc setcchar*(a2: ptr cunsignedlong; a3: cstring; a4: cunsignedlong; 
+               a5: cshort; a6: pointer): cint{.extdecl, importc: "setcchar", 
+    dynlib: pdcursesdll.}
+proc slk_wset*(a2: cint; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "slk_wset", dynlib: pdcursesdll.}
+proc unget_wch*(a2: char): cint{.extdecl, importc: "unget_wch", 
+                                    dynlib: pdcursesdll.}
+proc vline_set*(a2: ptr cunsignedlong; a3: cint): cint{.extdecl, 
+    importc: "vline_set", dynlib: pdcursesdll.}
+proc waddnwstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "waddnwstr", dynlib: pdcursesdll.}
+proc waddwstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, 
+    importc: "waddwstr", dynlib: pdcursesdll.}
+proc wadd_wch*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wadd_wch", dynlib: pdcursesdll.}
+proc wadd_wchnstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: cint): cint{.
+    extdecl, importc: "wadd_wchnstr", dynlib: pdcursesdll.}
+proc wadd_wchstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wadd_wchstr", dynlib: pdcursesdll.}
+proc wbkgrnd*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wbkgrnd", dynlib: pdcursesdll.}
+proc wbkgrndset*(a2: ptr TWINDOW; a3: ptr cunsignedlong){.extdecl, 
+    importc: "wbkgrndset", dynlib: pdcursesdll.}
+proc wborder_set*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: ptr cunsignedlong; 
+                  a5: ptr cunsignedlong; a6: ptr cunsignedlong; 
+                  a7: ptr cunsignedlong; a8: ptr cunsignedlong; 
+                  a9: ptr cunsignedlong; a10: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wborder_set", dynlib: pdcursesdll.}
+proc wecho_wchar*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wecho_wchar", dynlib: pdcursesdll.}
+proc wgetbkgrnd*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wgetbkgrnd", dynlib: pdcursesdll.}
+proc wgetn_wstr*(a2: ptr TWINDOW; a3: ptr cint; a4: cint): cint{.extdecl, 
+    importc: "wgetn_wstr", dynlib: pdcursesdll.}
+proc wget_wch*(a2: ptr TWINDOW; a3: ptr cint): cint{.extdecl, 
+    importc: "wget_wch", dynlib: pdcursesdll.}
+proc wget_wstr*(a2: ptr TWINDOW; a3: ptr cint): cint{.extdecl, 
+    importc: "wget_wstr", dynlib: pdcursesdll.}
+proc whline_set*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "whline_set", dynlib: pdcursesdll.}
+proc winnwstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "winnwstr", dynlib: pdcursesdll.}
+proc wins_nwstr*(a2: ptr TWINDOW; a3: cstring; a4: cint): cint{.extdecl, 
+    importc: "wins_nwstr", dynlib: pdcursesdll.}
+proc wins_wch*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "wins_wch", dynlib: pdcursesdll.}
+proc wins_wstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, 
+    importc: "wins_wstr", dynlib: pdcursesdll.}
+proc winwstr*(a2: ptr TWINDOW; a3: cstring): cint{.extdecl, importc: "winwstr", 
+    dynlib: pdcursesdll.}
+proc win_wch*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "win_wch", dynlib: pdcursesdll.}
+proc win_wchnstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "win_wchnstr", dynlib: pdcursesdll.}
+proc win_wchstr*(a2: ptr TWINDOW; a3: ptr cunsignedlong): cint{.extdecl, 
+    importc: "win_wchstr", dynlib: pdcursesdll.}
+proc wunctrl*(a2: ptr cunsignedlong): cstring{.extdecl, importc: "wunctrl", 
+    dynlib: pdcursesdll.}
+proc wvline_set*(a2: ptr TWINDOW; a3: ptr cunsignedlong; a4: cint): cint{.extdecl, 
+    importc: "wvline_set", dynlib: pdcursesdll.}
+proc getattrs*(a2: ptr TWINDOW): cunsignedlong{.extdecl, importc: "getattrs", 
+    dynlib: pdcursesdll.}
+proc getbegx*(a2: ptr TWINDOW): cint{.extdecl, importc: "getbegx", 
+                                     dynlib: pdcursesdll.}
+proc getbegy*(a2: ptr TWINDOW): cint{.extdecl, importc: "getbegy", 
+                                     dynlib: pdcursesdll.}
+proc getmaxx*(a2: ptr TWINDOW): cint{.extdecl, importc: "getmaxx", 
+                                     dynlib: pdcursesdll.}
+proc getmaxy*(a2: ptr TWINDOW): cint{.extdecl, importc: "getmaxy", 
+                                     dynlib: pdcursesdll.}
+proc getparx*(a2: ptr TWINDOW): cint{.extdecl, importc: "getparx", 
+                                     dynlib: pdcursesdll.}
+proc getpary*(a2: ptr TWINDOW): cint{.extdecl, importc: "getpary", 
+                                     dynlib: pdcursesdll.}
+proc getcurx*(a2: ptr TWINDOW): cint{.extdecl, importc: "getcurx", 
+                                     dynlib: pdcursesdll.}
+proc getcury*(a2: ptr TWINDOW): cint{.extdecl, importc: "getcury", 
+                                     dynlib: pdcursesdll.}
+proc traceoff*(){.extdecl, importc: "traceoff", dynlib: pdcursesdll.}
+proc traceon*(){.extdecl, importc: "traceon", dynlib: pdcursesdll.}
+proc unctrl*(a2: cunsignedlong): cstring{.extdecl, importc: "unctrl", 
+    dynlib: pdcursesdll.}
+proc crmode*(): cint{.extdecl, importc: "crmode", dynlib: pdcursesdll.}
+proc nocrmode*(): cint{.extdecl, importc: "nocrmode", dynlib: pdcursesdll.}
+proc draino*(a2: cint): cint{.extdecl, importc: "draino", dynlib: pdcursesdll.}
+proc resetterm*(): cint{.extdecl, importc: "resetterm", dynlib: pdcursesdll.}
+proc fixterm*(): cint{.extdecl, importc: "fixterm", dynlib: pdcursesdll.}
+proc saveterm*(): cint{.extdecl, importc: "saveterm", dynlib: pdcursesdll.}
+proc setsyx*(a2: cint; a3: cint): cint{.extdecl, importc: "setsyx", 
+                                        dynlib: pdcursesdll.}
+proc mouse_set*(a2: cunsignedlong): cint{.extdecl, importc: "mouse_set", 
+    dynlib: pdcursesdll.}
+proc mouse_on*(a2: cunsignedlong): cint{.extdecl, importc: "mouse_on", 
+    dynlib: pdcursesdll.}
+proc mouse_off*(a2: cunsignedlong): cint{.extdecl, importc: "mouse_off", 
+    dynlib: pdcursesdll.}
+proc request_mouse_pos*(): cint{.extdecl, importc: "request_mouse_pos", 
+                                 dynlib: pdcursesdll.}
+proc map_button*(a2: cunsignedlong): cint{.extdecl, importc: "map_button", 
+    dynlib: pdcursesdll.}
+proc wmouse_position*(a2: ptr TWINDOW; a3: ptr cint; a4: ptr cint){.extdecl, 
+    importc: "wmouse_position", dynlib: pdcursesdll.}
+proc getmouse*(): cunsignedlong{.extdecl, importc: "getmouse", dynlib: pdcursesdll.}
+proc getbmap*(): cunsignedlong{.extdecl, importc: "getbmap", dynlib: pdcursesdll.}
+proc assume_default_colors*(a2: cint; a3: cint): cint{.extdecl, 
+    importc: "assume_default_colors", dynlib: pdcursesdll.}
+proc curses_version*(): cstring{.extdecl, importc: "curses_version", 
+                                 dynlib: pdcursesdll.}
+proc has_key*(a2: cint): cunsignedchar{.extdecl, importc: "has_key", 
+                                        dynlib: pdcursesdll.}
+proc use_default_colors*(): cint{.extdecl, importc: "use_default_colors", 
+                                  dynlib: pdcursesdll.}
+proc wresize*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "wresize", dynlib: pdcursesdll.}
+proc mouseinterval*(a2: cint): cint{.extdecl, importc: "mouseinterval", 
+                                     dynlib: pdcursesdll.}
+proc mousemask*(a2: cunsignedlong; a3: ptr cunsignedlong): cunsignedlong{.extdecl, 
+    importc: "mousemask", dynlib: pdcursesdll.}
+proc mouse_trafo*(a2: ptr cint; a3: ptr cint; a4: cunsignedchar): cunsignedchar{.
+    extdecl, importc: "mouse_trafo", dynlib: pdcursesdll.}
+proc nc_getmouse*(a2: ptr TMEVENT): cint{.extdecl, importc: "nc_getmouse", 
+    dynlib: pdcursesdll.}
+proc ungetmouse*(a2: ptr TMEVENT): cint{.extdecl, importc: "ungetmouse", 
+                                        dynlib: pdcursesdll.}
+proc wenclose*(a2: ptr TWINDOW; a3: cint; a4: cint): cunsignedchar{.extdecl, 
+    importc: "wenclose", dynlib: pdcursesdll.}
+proc wmouse_trafo*(a2: ptr TWINDOW; a3: ptr cint; a4: ptr cint; a5: cunsignedchar): cunsignedchar{.
+    extdecl, importc: "wmouse_trafo", dynlib: pdcursesdll.}
+proc addrawch*(a2: cunsignedlong): cint{.extdecl, importc: "addrawch", 
+    dynlib: pdcursesdll.}
+proc insrawch*(a2: cunsignedlong): cint{.extdecl, importc: "insrawch", 
+    dynlib: pdcursesdll.}
+proc is_termresized*(): cunsignedchar{.extdecl, importc: "is_termresized", 
+                                       dynlib: pdcursesdll.}
+proc mvaddrawch*(a2: cint; a3: cint; a4: cunsignedlong): cint{.extdecl, 
+    importc: "mvaddrawch", dynlib: pdcursesdll.}
+proc mvdeleteln*(a2: cint; a3: cint): cint{.extdecl, importc: "mvdeleteln", 
+    dynlib: pdcursesdll.}
+proc mvinsertln*(a2: cint; a3: cint): cint{.extdecl, importc: "mvinsertln", 
+    dynlib: pdcursesdll.}
+proc mvinsrawch*(a2: cint; a3: cint; a4: cunsignedlong): cint{.extdecl, 
+    importc: "mvinsrawch", dynlib: pdcursesdll.}
+proc mvwaddrawch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong): cint{.
+    extdecl, importc: "mvwaddrawch", dynlib: pdcursesdll.}
+proc mvwdeleteln*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "mvwdeleteln", dynlib: pdcursesdll.}
+proc mvwinsertln*(a2: ptr TWINDOW; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "mvwinsertln", dynlib: pdcursesdll.}
+proc mvwinsrawch*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong): cint{.
+    extdecl, importc: "mvwinsrawch", dynlib: pdcursesdll.}
+proc raw_output*(a2: cunsignedchar): cint{.extdecl, importc: "raw_output", 
+    dynlib: pdcursesdll.}
+proc resize_term*(a2: cint; a3: cint): cint{.extdecl, importc: "resize_term", 
+    dynlib: pdcursesdll.}
+proc resize_window*(a2: ptr TWINDOW; a3: cint; a4: cint): ptr TWINDOW{.extdecl, 
+    importc: "resize_window", dynlib: pdcursesdll.}
+proc waddrawch*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "waddrawch", dynlib: pdcursesdll.}
+proc winsrawch*(a2: ptr TWINDOW; a3: cunsignedlong): cint{.extdecl, 
+    importc: "winsrawch", dynlib: pdcursesdll.}
+proc wordchar*(): char{.extdecl, importc: "wordchar", dynlib: pdcursesdll.}
+proc slk_wlabel*(a2: cint): cstring{.extdecl, importc: "slk_wlabel", 
+    dynlib: pdcursesdll.}
+proc debug*(a2: cstring){.varargs, extdecl, importc: "PDC_debug", 
+                          dynlib: pdcursesdll.}
+proc ungetch*(a2: cint): cint{.extdecl, importc: "PDC_ungetch", 
+                               dynlib: pdcursesdll.}
+proc set_blink*(a2: cunsignedchar): cint{.extdecl, importc: "PDC_set_blink", 
+    dynlib: pdcursesdll.}
+proc set_line_color*(a2: cshort): cint{.extdecl, importc: "PDC_set_line_color", 
+                                        dynlib: pdcursesdll.}
+proc set_title*(a2: cstring){.extdecl, importc: "PDC_set_title", 
+                              dynlib: pdcursesdll.}
+proc clearclipboard*(): cint{.extdecl, importc: "PDC_clearclipboard", 
+                              dynlib: pdcursesdll.}
+proc freeclipboard*(a2: cstring): cint{.extdecl, importc: "PDC_freeclipboard", 
+                                        dynlib: pdcursesdll.}
+proc getclipboard*(a2: cstringArray; a3: ptr clong): cint{.extdecl, 
+    importc: "PDC_getclipboard", dynlib: pdcursesdll.}
+proc setclipboard*(a2: cstring; a3: clong): cint{.extdecl, 
+    importc: "PDC_setclipboard", dynlib: pdcursesdll.}
+proc get_input_fd*(): cunsignedlong{.extdecl, importc: "PDC_get_input_fd", 
+                                     dynlib: pdcursesdll.}
+proc get_key_modifiers*(): cunsignedlong{.extdecl, 
+    importc: "PDC_get_key_modifiers", dynlib: pdcursesdll.}
+proc return_key_modifiers*(a2: cunsignedchar): cint{.extdecl, 
+    importc: "PDC_return_key_modifiers", dynlib: pdcursesdll.}
+proc save_key_modifiers*(a2: cunsignedchar): cint{.extdecl, 
+    importc: "PDC_save_key_modifiers", dynlib: pdcursesdll.}
+proc bottom_panel*(pan: ptr TPANEL): cint{.extdecl, importc: "bottom_panel", 
+    dynlib: pdcursesdll.}
+proc del_panel*(pan: ptr TPANEL): cint{.extdecl, importc: "del_panel", 
+                                       dynlib: pdcursesdll.}
+proc hide_panel*(pan: ptr TPANEL): cint{.extdecl, importc: "hide_panel", 
+                                        dynlib: pdcursesdll.}
+proc move_panel*(pan: ptr TPANEL; starty: cint; startx: cint): cint{.extdecl, 
+    importc: "move_panel", dynlib: pdcursesdll.}
+proc new_panel*(win: ptr TWINDOW): ptr TPANEL{.extdecl, importc: "new_panel", 
+    dynlib: pdcursesdll.}
+proc panel_above*(pan: ptr TPANEL): ptr TPANEL{.extdecl, importc: "panel_above", 
+    dynlib: pdcursesdll.}
+proc panel_below*(pan: ptr TPANEL): ptr TPANEL{.extdecl, importc: "panel_below", 
+    dynlib: pdcursesdll.}
+proc panel_hidden*(pan: ptr TPANEL): cint{.extdecl, importc: "panel_hidden", 
+    dynlib: pdcursesdll.}
+proc panel_userptr*(pan: ptr TPANEL): pointer{.extdecl, importc: "panel_userptr", 
+    dynlib: pdcursesdll.}
+proc panel_window*(pan: ptr TPANEL): ptr TWINDOW{.extdecl, importc: "panel_window", 
+    dynlib: pdcursesdll.}
+proc replace_panel*(pan: ptr TPANEL; win: ptr TWINDOW): cint{.extdecl, 
+    importc: "replace_panel", dynlib: pdcursesdll.}
+proc set_panel_userptr*(pan: ptr TPANEL; uptr: pointer): cint{.extdecl, 
+    importc: "set_panel_userptr", dynlib: pdcursesdll.}
+proc show_panel*(pan: ptr TPANEL): cint{.extdecl, importc: "show_panel", 
+                                        dynlib: pdcursesdll.}
+proc top_panel*(pan: ptr TPANEL): cint{.extdecl, importc: "top_panel", 
+                                       dynlib: pdcursesdll.}
+proc update_panels*(){.extdecl, importc: "update_panels", dynlib: pdcursesdll.}
+
+when unixOS:
+  proc Xinitscr*(a2: cint; a3: cstringArray): ptr TWINDOW{.extdecl, 
+    importc: "Xinitscr", dynlib: pdcursesdll.}
+  proc XCursesExit*(){.extdecl, importc: "XCursesExit", dynlib: pdcursesdll.}
+  proc sb_init*(): cint{.extdecl, importc: "sb_init", dynlib: pdcursesdll.}
+  proc sb_set_horz*(a2: cint; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "sb_set_horz", dynlib: pdcursesdll.}
+  proc sb_set_vert*(a2: cint; a3: cint; a4: cint): cint{.extdecl, 
+    importc: "sb_set_vert", dynlib: pdcursesdll.}
+  proc sb_get_horz*(a2: ptr cint; a3: ptr cint; a4: ptr cint): cint{.extdecl, 
+    importc: "sb_get_horz", dynlib: pdcursesdll.}
+  proc sb_get_vert*(a2: ptr cint; a3: ptr cint; a4: ptr cint): cint{.extdecl, 
+    importc: "sb_get_vert", dynlib: pdcursesdll.}
+  proc sb_refresh*(): cint{.extdecl, importc: "sb_refresh", dynlib: pdcursesdll.}
+
+template getch*(): expr = 
+  wgetch(stdscr)
+
+template ungetch*(ch: expr): expr = 
+  ungetch(ch)
+
+template getbegyx*(w, y, x: expr): expr =
+  y = getbegy(w)
+  x = getbegx(w)
+
+template getmaxyx*(w, y, x: expr): expr =
+  y = getmaxy(w)
+  x = getmaxx(w)
+
+template getparyx*(w, y, x: expr): expr =
+  y = getpary(w)
+  x = getparx(w)
+
+template getyx*(w, y, x: expr): expr =
+  y = getcury(w)
+  x = getcurx(w)
+
+template getsyx*(y, x: expr): stmt = 
+  if curscr.leaveit:
+    (x) = - 1
+    (y) = (x)
+  else: getyx(curscr, (y), (x))
+  
+template getmouse*(x: expr): expr = 
+  nc_getmouse(x)
+
+when defined(windows):
+  var
+    atrtab*{.importc: "pdc_atrtab", dynlib: pdcursesdll.}: cstring
+    con_out*{.importc: "pdc_con_out", dynlib: pdcursesdll.}: HANDLE
+    con_in*{.importc: "pdc_con_in", dynlib: pdcursesdll.}: HANDLE
+    quick_edit*{.importc: "pdc_quick_edit", dynlib: pdcursesdll.}: DWORD
+
+  proc get_buffer_rows*(): cint{.extdecl, importc: "PDC_get_buffer_rows", 
+                               dynlib: pdcursesdll.}
\ No newline at end of file
diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim
new file mode 100644
index 000000000..cb39c41bb
--- /dev/null
+++ b/lib/wrappers/postgres.nim
@@ -0,0 +1,352 @@
+# This module contains the definitions for structures and externs for
+# functions used by frontend postgres applications. It is based on
+# Postgresql's libpq-fe.h.
+#
+# It is for postgreSQL version 7.4 and higher with support for the v3.0
+# connection-protocol.
+#
+
+{.deadCodeElim: on.}
+
+when defined(windows): 
+  const 
+    dllName = "libpq.dll"
+elif defined(macosx): 
+  const 
+    dllName = "libpq.dylib"
+else: 
+  const 
+    dllName = "libpq.so(.5|)"
+type 
+  POid* = ptr Oid
+  Oid* = int32
+
+const 
+  ERROR_MSG_LENGTH* = 4096
+  CMDSTATUS_LEN* = 40
+
+type 
+  TSockAddr* = array[1..112, int8]
+  TPGresAttDesc*{.pure, final.} = object 
+    name*: cstring
+    adtid*: Oid
+    adtsize*: int
+
+  PPGresAttDesc* = ptr TPGresAttDesc
+  PPPGresAttDesc* = ptr PPGresAttDesc
+  TPGresAttValue*{.pure, final.} = object 
+    length*: int32
+    value*: cstring
+
+  PPGresAttValue* = ptr TPGresAttValue
+  PPPGresAttValue* = ptr PPGresAttValue
+  PExecStatusType* = ptr TExecStatusType
+  TExecStatusType* = enum 
+    PGRES_EMPTY_QUERY = 0, PGRES_COMMAND_OK, PGRES_TUPLES_OK, PGRES_COPY_OUT, 
+    PGRES_COPY_IN, PGRES_BAD_RESPONSE, PGRES_NONFATAL_ERROR, PGRES_FATAL_ERROR
+  TPGlobjfuncs*{.pure, final.} = object 
+    fn_lo_open*: Oid
+    fn_lo_close*: Oid
+    fn_lo_creat*: Oid
+    fn_lo_unlink*: Oid
+    fn_lo_lseek*: Oid
+    fn_lo_tell*: Oid
+    fn_lo_read*: Oid
+    fn_lo_write*: Oid
+
+  PPGlobjfuncs* = ptr TPGlobjfuncs
+  PConnStatusType* = ptr TConnStatusType
+  TConnStatusType* = enum 
+    CONNECTION_OK, CONNECTION_BAD, CONNECTION_STARTED, CONNECTION_MADE, 
+    CONNECTION_AWAITING_RESPONSE, CONNECTION_AUTH_OK, CONNECTION_SETENV, 
+    CONNECTION_SSL_STARTUP, CONNECTION_NEEDED
+  TPGconn*{.pure, final.} = object 
+    pghost*: cstring
+    pgtty*: cstring
+    pgport*: cstring
+    pgoptions*: cstring
+    dbName*: cstring
+    status*: TConnStatusType
+    errorMessage*: array[0..(ERROR_MSG_LENGTH) - 1, char]
+    Pfin*: File
+    Pfout*: File
+    Pfdebug*: File
+    sock*: int32
+    laddr*: TSockAddr
+    raddr*: TSockAddr
+    salt*: array[0..(2) - 1, char]
+    asyncNotifyWaiting*: int32
+    notifyList*: pointer
+    pguser*: cstring
+    pgpass*: cstring
+    lobjfuncs*: PPGlobjfuncs
+
+  PPGconn* = ptr TPGconn
+  TPGresult*{.pure, final.} = object 
+    ntups*: int32
+    numAttributes*: int32
+    attDescs*: PPGresAttDesc
+    tuples*: PPPGresAttValue
+    tupArrSize*: int32
+    resultStatus*: TExecStatusType
+    cmdStatus*: array[0..(CMDSTATUS_LEN) - 1, char]
+    binary*: int32
+    conn*: PPGconn
+
+  PPGresult* = ptr TPGresult
+  PPostgresPollingStatusType* = ptr PostgresPollingStatusType
+  PostgresPollingStatusType* = enum 
+    PGRES_POLLING_FAILED = 0, PGRES_POLLING_READING, PGRES_POLLING_WRITING, 
+    PGRES_POLLING_OK, PGRES_POLLING_ACTIVE
+  PPGTransactionStatusType* = ptr PGTransactionStatusType
+  PGTransactionStatusType* = enum 
+    PQTRANS_IDLE, PQTRANS_ACTIVE, PQTRANS_INTRANS, PQTRANS_INERROR, 
+    PQTRANS_UNKNOWN
+  PPGVerbosity* = ptr PGVerbosity
+  PGVerbosity* = enum 
+    PQERRORS_TERSE, PQERRORS_DEFAULT, PQERRORS_VERBOSE
+  PpgNotify* = ptr pgNotify
+  pgNotify*{.pure, final.} = object 
+    relname*: cstring
+    be_pid*: int32
+    extra*: cstring
+
+  PQnoticeReceiver* = proc (arg: pointer, res: PPGresult){.cdecl.}
+  PQnoticeProcessor* = proc (arg: pointer, message: cstring){.cdecl.}
+  Ppqbool* = ptr pqbool
+  pqbool* = char
+  P_PQprintOpt* = ptr PQprintOpt
+  PQprintOpt*{.pure, final.} = object 
+    header*: pqbool
+    align*: pqbool
+    standard*: pqbool
+    html3*: pqbool
+    expanded*: pqbool
+    pager*: pqbool
+    fieldSep*: cstring
+    tableOpt*: cstring
+    caption*: cstring
+    fieldName*: ptr cstring
+
+  P_PQconninfoOption* = ptr PQconninfoOption
+  PQconninfoOption*{.pure, final.} = object 
+    keyword*: cstring
+    envvar*: cstring
+    compiled*: cstring
+    val*: cstring
+    label*: cstring
+    dispchar*: cstring
+    dispsize*: int32
+
+  PPQArgBlock* = ptr PQArgBlock
+  PQArgBlock*{.pure, final.} = object 
+    length*: int32
+    isint*: int32
+    p*: pointer
+
+
+proc pqconnectStart*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, 
+    importc: "PQconnectStart".}
+proc pqconnectPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, 
+    dynlib: dllName, importc: "PQconnectPoll".}
+proc pqconnectdb*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, 
+    importc: "PQconnectdb".}
+proc pqsetdbLogin*(pghost: cstring, pgport: cstring, pgoptions: cstring, 
+                   pgtty: cstring, dbName: cstring, login: cstring, pwd: cstring): PPGconn{.
+    cdecl, dynlib: dllName, importc: "PQsetdbLogin".}
+proc pqsetdb*(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): Ppgconn
+proc pqfinish*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQfinish".}
+proc pqconndefaults*(): PPQconninfoOption{.cdecl, dynlib: dllName, 
+    importc: "PQconndefaults".}
+proc pqconninfoFree*(connOptions: PPQconninfoOption){.cdecl, dynlib: dllName, 
+    importc: "PQconninfoFree".}
+proc pqresetStart*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQresetStart".}
+proc pqresetPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, 
+    dynlib: dllName, importc: "PQresetPoll".}
+proc pqreset*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQreset".}
+proc pqrequestCancel*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQrequestCancel".}
+proc pqdb*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQdb".}
+proc pquser*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQuser".}
+proc pqpass*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQpass".}
+proc pqhost*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQhost".}
+proc pqport*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQport".}
+proc pqtty*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQtty".}
+proc pqoptions*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQoptions".}
+proc pqstatus*(conn: PPGconn): TConnStatusType{.cdecl, dynlib: dllName, 
+    importc: "PQstatus".}
+proc pqtransactionStatus*(conn: PPGconn): PGTransactionStatusType{.cdecl, 
+    dynlib: dllName, importc: "PQtransactionStatus".}
+proc pqparameterStatus*(conn: PPGconn, paramName: cstring): cstring{.cdecl, 
+    dynlib: dllName, importc: "PQparameterStatus".}
+proc pqprotocolVersion*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQprotocolVersion".}
+proc pqerrorMessage*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQerrorMessage".}
+proc pqsocket*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+                                      importc: "PQsocket".}
+proc pqbackendPID*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQbackendPID".}
+proc pqclientEncoding*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQclientEncoding".}
+proc pqsetClientEncoding*(conn: PPGconn, encoding: cstring): int32{.cdecl, 
+    dynlib: dllName, importc: "PQsetClientEncoding".}
+when defined(USE_SSL): 
+  # Get the SSL structure associated with a connection  
+  proc pqgetssl*(conn: PPGconn): PSSL{.cdecl, dynlib: dllName, 
+                                       importc: "PQgetssl".}
+proc pqsetErrorVerbosity*(conn: PPGconn, verbosity: PGVerbosity): PGVerbosity{.
+    cdecl, dynlib: dllName, importc: "PQsetErrorVerbosity".}
+proc pqtrace*(conn: PPGconn, debug_port: File){.cdecl, dynlib: dllName, 
+    importc: "PQtrace".}
+proc pquntrace*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQuntrace".}
+proc pqsetNoticeReceiver*(conn: PPGconn, theProc: PQnoticeReceiver, arg: pointer): PQnoticeReceiver{.
+    cdecl, dynlib: dllName, importc: "PQsetNoticeReceiver".}
+proc pqsetNoticeProcessor*(conn: PPGconn, theProc: PQnoticeProcessor, 
+                           arg: pointer): PQnoticeProcessor{.cdecl, 
+    dynlib: dllName, importc: "PQsetNoticeProcessor".}
+proc pqexec*(conn: PPGconn, query: cstring): PPGresult{.cdecl, dynlib: dllName, 
+    importc: "PQexec".}
+proc pqexecParams*(conn: PPGconn, command: cstring, nParams: int32, 
+                   paramTypes: POid, paramValues: cstringArray, 
+                   paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{.
+    cdecl, dynlib: dllName, importc: "PQexecParams".}
+proc pqprepare*(conn: PPGconn, stmtName, query: cstring, nParams: int32,
+    paramTypes: POid): PPGresult{.cdecl, dynlib: dllName, importc: "PQprepare".}
+proc pqexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32,
+                     paramValues: cstringArray,
+                     paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{.
+    cdecl, dynlib: dllName, importc: "PQexecPrepared".}
+proc pqsendQuery*(conn: PPGconn, query: cstring): int32{.cdecl, dynlib: dllName, 
+    importc: "PQsendQuery".}
+proc pqsendQueryParams*(conn: PPGconn, command: cstring, nParams: int32, 
+                        paramTypes: POid, paramValues: cstringArray, 
+                        paramLengths, paramFormats: ptr int32, 
+                        resultFormat: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "PQsendQueryParams".}
+proc pqsendQueryPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, 
+                          paramValues: cstringArray, 
+                          paramLengths, paramFormats: ptr int32, 
+                          resultFormat: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "PQsendQueryPrepared".}
+proc pqgetResult*(conn: PPGconn): PPGresult{.cdecl, dynlib: dllName, 
+    importc: "PQgetResult".}
+proc pqisBusy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+                                      importc: "PQisBusy".}
+proc pqconsumeInput*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQconsumeInput".}
+proc pqnotifies*(conn: PPGconn): PPGnotify{.cdecl, dynlib: dllName, 
+    importc: "PQnotifies".}
+proc pqputCopyData*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{.
+    cdecl, dynlib: dllName, importc: "PQputCopyData".}
+proc pqputCopyEnd*(conn: PPGconn, errormsg: cstring): int32{.cdecl, 
+    dynlib: dllName, importc: "PQputCopyEnd".}
+proc pqgetCopyData*(conn: PPGconn, buffer: cstringArray, async: int32): int32{.
+    cdecl, dynlib: dllName, importc: "PQgetCopyData".}
+proc pqgetline*(conn: PPGconn, str: cstring, len: int32): int32{.cdecl, 
+    dynlib: dllName, importc: "PQgetline".}
+proc pqputline*(conn: PPGconn, str: cstring): int32{.cdecl, dynlib: dllName, 
+    importc: "PQputline".}
+proc pqgetlineAsync*(conn: PPGconn, buffer: cstring, bufsize: int32): int32{.
+    cdecl, dynlib: dllName, importc: "PQgetlineAsync".}
+proc pqputnbytes*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{.cdecl, 
+    dynlib: dllName, importc: "PQputnbytes".}
+proc pqendcopy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+                                       importc: "PQendcopy".}
+proc pqsetnonblocking*(conn: PPGconn, arg: int32): int32{.cdecl, 
+    dynlib: dllName, importc: "PQsetnonblocking".}
+proc pqisnonblocking*(conn: PPGconn): int32{.cdecl, dynlib: dllName, 
+    importc: "PQisnonblocking".}
+proc pqflush*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQflush".}
+proc pqfn*(conn: PPGconn, fnid: int32, result_buf, result_len: ptr int32, 
+           result_is_int: int32, args: PPQArgBlock, nargs: int32): PPGresult{.
+    cdecl, dynlib: dllName, importc: "PQfn".}
+proc pqresultStatus*(res: PPGresult): TExecStatusType{.cdecl, dynlib: dllName, 
+    importc: "PQresultStatus".}
+proc pqresStatus*(status: TExecStatusType): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQresStatus".}
+proc pqresultErrorMessage*(res: PPGresult): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQresultErrorMessage".}
+proc pqresultErrorField*(res: PPGresult, fieldcode: int32): cstring{.cdecl, 
+    dynlib: dllName, importc: "PQresultErrorField".}
+proc pqntuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, 
+                                        importc: "PQntuples".}
+proc pqnfields*(res: PPGresult): int32{.cdecl, dynlib: dllName, 
+                                        importc: "PQnfields".}
+proc pqbinaryTuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, 
+    importc: "PQbinaryTuples".}
+proc pqfname*(res: PPGresult, field_num: int32): cstring{.cdecl, 
+    dynlib: dllName, importc: "PQfname".}
+proc pqfnumber*(res: PPGresult, field_name: cstring): int32{.cdecl, 
+    dynlib: dllName, importc: "PQfnumber".}
+proc pqftable*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, 
+    importc: "PQftable".}
+proc pqftablecol*(res: PPGresult, field_num: int32): int32{.cdecl, 
+    dynlib: dllName, importc: "PQftablecol".}
+proc pqfformat*(res: PPGresult, field_num: int32): int32{.cdecl, 
+    dynlib: dllName, importc: "PQfformat".}
+proc pqftype*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, 
+    importc: "PQftype".}
+proc pqfsize*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "PQfsize".}
+proc pqfmod*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "PQfmod".}
+proc pqcmdStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQcmdStatus".}
+proc pqoidStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQoidStatus".}
+proc pqoidValue*(res: PPGresult): Oid{.cdecl, dynlib: dllName, 
+                                       importc: "PQoidValue".}
+proc pqcmdTuples*(res: PPGresult): cstring{.cdecl, dynlib: dllName, 
+    importc: "PQcmdTuples".}
+proc pqgetvalue*(res: PPGresult, tup_num: int32, field_num: int32): cstring{.
+    cdecl, dynlib: dllName, importc: "PQgetvalue".}
+proc pqgetlength*(res: PPGresult, tup_num: int32, field_num: int32): int32{.
+    cdecl, dynlib: dllName, importc: "PQgetlength".}
+proc pqgetisnull*(res: PPGresult, tup_num: int32, field_num: int32): int32{.
+    cdecl, dynlib: dllName, importc: "PQgetisnull".}
+proc pqclear*(res: PPGresult){.cdecl, dynlib: dllName, importc: "PQclear".}
+proc pqfreemem*(p: pointer){.cdecl, dynlib: dllName, importc: "PQfreemem".}
+proc pqmakeEmptyPGresult*(conn: PPGconn, status: TExecStatusType): PPGresult{.
+    cdecl, dynlib: dllName, importc: "PQmakeEmptyPGresult".}
+proc pqescapeString*(till, `from`: cstring, len: int): int{.cdecl, 
+    dynlib: dllName, importc: "PQescapeString".}
+proc pqescapeBytea*(bintext: cstring, binlen: int, bytealen: var int): cstring{.
+    cdecl, dynlib: dllName, importc: "PQescapeBytea".}
+proc pqunescapeBytea*(strtext: cstring, retbuflen: var int): cstring{.cdecl, 
+    dynlib: dllName, importc: "PQunescapeBytea".}
+proc pqprint*(fout: File, res: PPGresult, ps: PPQprintOpt){.cdecl, 
+    dynlib: dllName, importc: "PQprint".}
+proc pqdisplayTuples*(res: PPGresult, fp: File, fillAlign: int32, 
+                      fieldSep: cstring, printHeader: int32, quiet: int32){.
+    cdecl, dynlib: dllName, importc: "PQdisplayTuples".}
+proc pqprintTuples*(res: PPGresult, fout: File, printAttName: int32, 
+                    terseOutput: int32, width: int32){.cdecl, dynlib: dllName, 
+    importc: "PQprintTuples".}
+proc lo_open*(conn: PPGconn, lobjId: Oid, mode: int32): int32{.cdecl, 
+    dynlib: dllName, importc: "lo_open".}
+proc lo_close*(conn: PPGconn, fd: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "lo_close".}
+proc lo_read*(conn: PPGconn, fd: int32, buf: cstring, length: int): int32{.
+    cdecl, dynlib: dllName, importc: "lo_read".}
+proc lo_write*(conn: PPGconn, fd: int32, buf: cstring, length: int): int32{.
+    cdecl, dynlib: dllName, importc: "lo_write".}
+proc lo_lseek*(conn: PPGconn, fd: int32, offset: int32, whence: int32): int32{.
+    cdecl, dynlib: dllName, importc: "lo_lseek".}
+proc lo_creat*(conn: PPGconn, mode: int32): Oid{.cdecl, dynlib: dllName, 
+    importc: "lo_creat".}
+proc lo_tell*(conn: PPGconn, fd: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "lo_tell".}
+proc lo_unlink*(conn: PPGconn, lobjId: Oid): int32{.cdecl, dynlib: dllName, 
+    importc: "lo_unlink".}
+proc lo_import*(conn: PPGconn, filename: cstring): Oid{.cdecl, dynlib: dllName, 
+    importc: "lo_import".}
+proc lo_export*(conn: PPGconn, lobjId: Oid, filename: cstring): int32{.cdecl, 
+    dynlib: dllName, importc: "lo_export".}
+proc pqmblen*(s: cstring, encoding: int32): int32{.cdecl, dynlib: dllName, 
+    importc: "PQmblen".}
+proc pqenv2encoding*(): int32{.cdecl, dynlib: dllName, importc: "PQenv2encoding".}
+proc pqsetdb(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): PPgConn = 
+  result = pqSetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, "", "")
diff --git a/lib/wrappers/readline/history.nim b/lib/wrappers/readline/history.nim
new file mode 100644
index 000000000..495bc15e4
--- /dev/null
+++ b/lib/wrappers/readline/history.nim
@@ -0,0 +1,277 @@
+# history.h -- the names of functions that you can call in history. 
+# Copyright (C) 1989-2009 Free Software Foundation, Inc.
+#
+#   This file contains the GNU History Library (History), a set of
+#   routines for managing the text of previously typed lines.
+#
+#   History is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   History 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 General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with History.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+{.deadCodeElim: on.}
+
+import readline
+
+const 
+  historyDll = readlineDll
+
+import times, rltypedefs
+
+type 
+  Thistdata* = pointer
+
+# The structure used to store a history entry. 
+
+type 
+  THIST_ENTRY*{.pure, final.} = object 
+    line*: cstring
+    timestamp*: cstring       # char * rather than time_t for read/write 
+    data*: Thistdata
+
+
+# Size of the history-library-managed space in history entry HS. 
+
+template HISTENT_BYTES*(hs: expr): expr = 
+  (strlen(hs.line) + strlen(hs.timestamp))
+
+# A structure used to pass the current state of the history stuff around. 
+
+type 
+  THISTORY_STATE*{.pure, final.} = object 
+    entries*: ptr ptr THIST_ENTRY # Pointer to the entries themselves. 
+    offset*: cint             # The location pointer within this array. 
+    length*: cint             # Number of elements within this array. 
+    size*: cint               # Number of slots allocated to this array. 
+    flags*: cint
+
+
+# Flag values for the `flags' member of HISTORY_STATE. 
+
+const 
+  HS_STIFLED* = 0x00000001
+
+# Initialization and state management. 
+# Begin a session in which the history functions might be used.  This
+#   just initializes the interactive variables. 
+
+proc using_history*(){.cdecl, importc: "using_history", dynlib: historyDll.}
+# Return the current HISTORY_STATE of the history. 
+
+proc history_get_history_state*(): ptr THISTORY_STATE{.cdecl, 
+    importc: "history_get_history_state", dynlib: historyDll.}
+# Set the state of the current history array to STATE. 
+
+proc history_set_history_state*(a2: ptr THISTORY_STATE){.cdecl, 
+    importc: "history_set_history_state", dynlib: historyDll.}
+# Manage the history list. 
+# Place STRING at the end of the history list.
+#   The associated data field (if any) is set to NULL. 
+
+proc add_history*(a2: cstring){.cdecl, importc: "add_history", 
+                                dynlib: historyDll.}
+# Change the timestamp associated with the most recent history entry to
+#   STRING. 
+
+proc add_history_time*(a2: cstring){.cdecl, importc: "add_history_time", 
+                                     dynlib: historyDll.}
+# A reasonably useless function, only here for completeness.  WHICH
+#   is the magic number that tells us which element to delete.  The
+#   elements are numbered from 0. 
+
+proc remove_history*(a2: cint): ptr THIST_ENTRY{.cdecl, 
+    importc: "remove_history", dynlib: historyDll.}
+# Free the history entry H and return any application-specific data
+#   associated with it. 
+
+proc free_history_entry*(a2: ptr THIST_ENTRY): Thistdata{.cdecl, 
+    importc: "free_history_entry", dynlib: historyDll.}
+# Make the history entry at WHICH have LINE and DATA.  This returns
+#   the old entry so you can dispose of the data.  In the case of an
+#   invalid WHICH, a NULL pointer is returned. 
+
+proc replace_history_entry*(a2: cint, a3: cstring, a4: Thistdata): ptr THIST_ENTRY{.
+    cdecl, importc: "replace_history_entry", dynlib: historyDll.}
+# Clear the history list and start over. 
+
+proc clear_history*(){.cdecl, importc: "clear_history", dynlib: historyDll.}
+# Stifle the history list, remembering only MAX number of entries. 
+
+proc stifle_history*(a2: cint){.cdecl, importc: "stifle_history", 
+                                dynlib: historyDll.}
+# Stop stifling the history.  This returns the previous amount the
+#   history was stifled by.  The value is positive if the history was
+#   stifled, negative if it wasn't. 
+
+proc unstifle_history*(): cint{.cdecl, importc: "unstifle_history", 
+                                dynlib: historyDll.}
+# Return 1 if the history is stifled, 0 if it is not. 
+
+proc history_is_stifled*(): cint{.cdecl, importc: "history_is_stifled", 
+                                  dynlib: historyDll.}
+# Information about the history list. 
+# Return a NULL terminated array of HIST_ENTRY which is the current input
+#   history.  Element 0 of this list is the beginning of time.  If there
+#   is no history, return NULL. 
+
+proc history_list*(): ptr ptr THIST_ENTRY{.cdecl, importc: "history_list", 
+    dynlib: historyDll.}
+# Returns the number which says what history element we are now
+#   looking at.  
+
+proc where_history*(): cint{.cdecl, importc: "where_history", dynlib: historyDll.}
+# Return the history entry at the current position, as determined by
+#   history_offset.  If there is no entry there, return a NULL pointer. 
+
+proc current_history*(): ptr THIST_ENTRY{.cdecl, importc: "current_history", 
+    dynlib: historyDll.}
+# Return the history entry which is logically at OFFSET in the history
+#   array.  OFFSET is relative to history_base. 
+
+proc history_get*(a2: cint): ptr THIST_ENTRY{.cdecl, importc: "history_get", 
+    dynlib: historyDll.}
+# Return the timestamp associated with the HIST_ENTRY * passed as an
+#   argument 
+
+proc history_get_time*(a2: ptr THIST_ENTRY): Time{.cdecl, 
+    importc: "history_get_time", dynlib: historyDll.}
+# Return the number of bytes that the primary history entries are using.
+#   This just adds up the lengths of the_history->lines. 
+
+proc history_total_bytes*(): cint{.cdecl, importc: "history_total_bytes", 
+                                   dynlib: historyDll.}
+# Moving around the history list. 
+# Set the position in the history list to POS. 
+
+proc history_set_pos*(a2: cint): cint{.cdecl, importc: "history_set_pos", 
+                                       dynlib: historyDll.}
+# Back up history_offset to the previous history entry, and return
+#   a pointer to that entry.  If there is no previous entry, return
+#   a NULL pointer. 
+
+proc previous_history*(): ptr THIST_ENTRY{.cdecl, importc: "previous_history", 
+    dynlib: historyDll.}
+# Move history_offset forward to the next item in the input_history,
+#   and return the a pointer to that entry.  If there is no next entry,
+#   return a NULL pointer. 
+
+proc next_history*(): ptr THIST_ENTRY{.cdecl, importc: "next_history", 
+                                       dynlib: historyDll.}
+# Searching the history list. 
+# Search the history for STRING, starting at history_offset.
+#   If DIRECTION < 0, then the search is through previous entries,
+#   else through subsequent.  If the string is found, then
+#   current_history () is the history entry, and the value of this function
+#   is the offset in the line of that history entry that the string was
+#   found in.  Otherwise, nothing is changed, and a -1 is returned. 
+
+proc history_search*(a2: cstring, a3: cint): cint{.cdecl, 
+    importc: "history_search", dynlib: historyDll.}
+# Search the history for STRING, starting at history_offset.
+#   The search is anchored: matching lines must begin with string.
+#   DIRECTION is as in history_search(). 
+
+proc history_search_prefix*(a2: cstring, a3: cint): cint{.cdecl, 
+    importc: "history_search_prefix", dynlib: historyDll.}
+# Search for STRING in the history list, starting at POS, an
+#   absolute index into the list.  DIR, if negative, says to search
+#   backwards from POS, else forwards.
+#   Returns the absolute index of the history element where STRING
+#   was found, or -1 otherwise. 
+
+proc history_search_pos*(a2: cstring, a3: cint, a4: cint): cint{.cdecl, 
+    importc: "history_search_pos", dynlib: historyDll.}
+# Managing the history file. 
+# Add the contents of FILENAME to the history list, a line at a time.
+#   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
+#   successful, or errno if not. 
+
+proc read_history*(a2: cstring): cint{.cdecl, importc: "read_history", 
+                                       dynlib: historyDll.}
+# Read a range of lines from FILENAME, adding them to the history list.
+#   Start reading at the FROM'th line and end at the TO'th.  If FROM
+#   is zero, start at the beginning.  If TO is less than FROM, read
+#   until the end of the file.  If FILENAME is NULL, then read from
+#   ~/.history.  Returns 0 if successful, or errno if not. 
+
+proc read_history_range*(a2: cstring, a3: cint, a4: cint): cint{.cdecl, 
+    importc: "read_history_range", dynlib: historyDll.}
+# Write the current history to FILENAME.  If FILENAME is NULL,
+#   then write the history list to ~/.history.  Values returned
+#   are as in read_history ().  
+
+proc write_history*(a2: cstring): cint{.cdecl, importc: "write_history", 
+                                        dynlib: historyDll.}
+# Append NELEMENT entries to FILENAME.  The entries appended are from
+#   the end of the list minus NELEMENTs up to the end of the list. 
+
+proc append_history*(a2: cint, a3: cstring): cint{.cdecl, 
+    importc: "append_history", dynlib: historyDll.}
+# Truncate the history file, leaving only the last NLINES lines. 
+
+proc history_truncate_file*(a2: cstring, a3: cint): cint{.cdecl, 
+    importc: "history_truncate_file", dynlib: historyDll.}
+# History expansion. 
+# Expand the string STRING, placing the result into OUTPUT, a pointer
+#   to a string.  Returns:
+#
+#   0) If no expansions took place (or, if the only change in
+#      the text was the de-slashifying of the history expansion
+#      character)
+#   1) If expansions did take place
+#  -1) If there was an error in expansion.
+#   2) If the returned line should just be printed.
+#
+#  If an error occurred in expansion, then OUTPUT contains a descriptive
+#  error message. 
+
+proc history_expand*(a2: cstring, a3: cstringArray): cint{.cdecl, 
+    importc: "history_expand", dynlib: historyDll.}
+# Extract a string segment consisting of the FIRST through LAST
+#   arguments present in STRING.  Arguments are broken up as in
+#   the shell. 
+
+proc history_arg_extract*(a2: cint, a3: cint, a4: cstring): cstring{.cdecl, 
+    importc: "history_arg_extract", dynlib: historyDll.}
+# Return the text of the history event beginning at the current
+#   offset into STRING.  Pass STRING with *INDEX equal to the
+#   history_expansion_char that begins this specification.
+#   DELIMITING_QUOTE is a character that is allowed to end the string
+#   specification for what to search for in addition to the normal
+#   characters `:', ` ', `\t', `\n', and sometimes `?'. 
+
+proc get_history_event*(a2: cstring, a3: ptr cint, a4: cint): cstring{.cdecl, 
+    importc: "get_history_event", dynlib: historyDll.}
+# Return an array of tokens, much as the shell might.  The tokens are
+#   parsed out of STRING. 
+
+proc history_tokenize*(a2: cstring): cstringArray{.cdecl, 
+    importc: "history_tokenize", dynlib: historyDll.}
+when false: 
+  # Exported history variables. 
+  var history_base*{.importc: "history_base", dynlib: historyDll.}: cint
+  var history_length*{.importc: "history_length", dynlib: historyDll.}: cint
+  var history_max_entries*{.importc: "history_max_entries", dynlib: historyDll.}: cint
+  var history_expansion_char*{.importc: "history_expansion_char", 
+                               dynlib: historyDll.}: char
+  var history_subst_char*{.importc: "history_subst_char", dynlib: historyDll.}: char
+  var history_word_delimiters*{.importc: "history_word_delimiters", 
+                                dynlib: historyDll.}: cstring
+  var history_comment_char*{.importc: "history_comment_char", dynlib: historyDll.}: char
+  var history_no_expand_chars*{.importc: "history_no_expand_chars", 
+                                dynlib: historyDll.}: cstring
+  var history_search_delimiter_chars*{.importc: "history_search_delimiter_chars", 
+                                       dynlib: historyDll.}: cstring
+  var history_quotes_inhibit_expansion*{.
+      importc: "history_quotes_inhibit_expansion", dynlib: historyDll.}: cint
+  var history_write_timestamps*{.importc: "history_write_timestamps", 
+                                 dynlib: historyDll.}: cint
diff --git a/lib/wrappers/readline/readline.nim b/lib/wrappers/readline/readline.nim
new file mode 100644
index 000000000..5a319243e
--- /dev/null
+++ b/lib/wrappers/readline/readline.nim
@@ -0,0 +1,1202 @@
+# Readline.h -- the names of functions callable from within readline. 
+# Copyright (C) 1987-2009 Free Software Foundation, Inc.
+#
+#   This file is part of the GNU Readline Library (Readline), a library
+#   for reading lines of text with interactive input and history editing.      
+#
+#   Readline is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   Readline 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 General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+{.deadCodeElim: on.}
+when defined(windows): 
+  const 
+    readlineDll* = "readline.dll"
+elif defined(macosx): 
+  # Mac OS X ships with 'libedit'
+  const 
+    readlineDll* = "libedit(.2|.1|).dylib"
+else: 
+  const 
+    readlineDll* = "libreadline.so.6(|.0)"
+#  mangle "'TCommandFunc'" TCommandFunc
+#  mangle TvcpFunc TvcpFunc
+
+import rltypedefs
+
+# Some character stuff. 
+
+const 
+  control_character_threshold* = 0x00000020 # Smaller than this is control. 
+  control_character_mask* = 0x0000001F # 0x20 - 1 
+  meta_character_threshold* = 0x0000007F # Larger than this is Meta. 
+  control_character_bit* = 0x00000040 # 0x000000, must be off. 
+  meta_character_bit* = 0x00000080 # x0000000, must be on. 
+  largest_char* = 255         # Largest character value. 
+
+template CTRL_CHAR*(c: expr): expr = 
+  (c < control_character_threshold and ((c and 0x00000080) == 0))
+
+template META_CHAR*(c: expr): expr = 
+  (c > meta_character_threshold and c <= largest_char)
+
+template CTRL*(c: expr): expr = 
+  (c and control_character_mask)
+
+template META*(c: expr): expr = 
+  (c or meta_character_bit)
+
+template UNMETA*(c: expr): expr = 
+  (c and not meta_character_bit)
+
+template UNCTRL*(c: expr): expr = 
+  (c or 32 or control_character_bit)
+
+# Beware:  these only work with single-byte ASCII characters. 
+
+const 
+  RETURN_CHAR* = CTRL('M'.ord)
+  RUBOUT_CHAR* = 0x0000007F
+  ABORT_CHAR* = CTRL('G'.ord)
+  PAGE_CHAR* = CTRL('L'.ord)
+  ESC_CHAR* = CTRL('['.ord)
+
+# A keymap contains one entry for each key in the ASCII set.
+#   Each entry consists of a type and a pointer.
+#   FUNCTION is the address of a function to run, or the
+#   address of a keymap to indirect through.
+#   TYPE says which kind of thing FUNCTION is. 
+
+type 
+  TKEYMAP_ENTRY*{.pure, final.} = object 
+    typ*: char
+    function*: TCommandFunc
+
+
+# This must be large enough to hold bindings for all of the characters
+#   in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x,
+#   and so on) plus one for subsequence matching. 
+
+const 
+  KEYMAP_SIZE* = 257
+  ANYOTHERKEY* = KEYMAP_SIZE - 1
+
+# I wanted to make the above structure contain a union of:
+#   union { rl_TCommandFunc_t *function; struct _keymap_entry *keymap; } value;
+#   but this made it impossible for me to create a static array.
+#   Maybe I need C lessons. 
+
+type 
+  TKEYMAP_ENTRY_ARRAY* = array[0..KEYMAP_SIZE - 1, TKEYMAP_ENTRY]
+  PKeymap* = ptr TKEYMAP_ENTRY
+
+# The values that TYPE can have in a keymap entry. 
+
+const 
+  ISFUNC* = 0
+  ISKMAP* = 1
+  ISMACR* = 2
+
+when false: 
+  var 
+    emacs_standard_keymap*{.importc: "emacs_standard_keymap", 
+                            dynlib: readlineDll.}: TKEYMAP_ENTRY_ARRAY
+    emacs_meta_keymap*{.importc: "emacs_meta_keymap", dynlib: readlineDll.}: TKEYMAP_ENTRY_ARRAY
+    emacs_ctlx_keymap*{.importc: "emacs_ctlx_keymap", dynlib: readlineDll.}: TKEYMAP_ENTRY_ARRAY
+  var 
+    vi_insertion_keymap*{.importc: "vi_insertion_keymap", dynlib: readlineDll.}: TKEYMAP_ENTRY_ARRAY
+    vi_movement_keymap*{.importc: "vi_movement_keymap", dynlib: readlineDll.}: TKEYMAP_ENTRY_ARRAY
+# Return a new, empty keymap.
+#   Free it with free() when you are done. 
+
+proc make_bare_keymap*(): PKeymap{.cdecl, importc: "rl_make_bare_keymap", 
+                                   dynlib: readlineDll.}
+# Return a new keymap which is a copy of MAP. 
+
+proc copy_keymap*(a2: PKeymap): PKeymap{.cdecl, importc: "rl_copy_keymap", 
+    dynlib: readlineDll.}
+# Return a new keymap with the printing characters bound to rl_insert,
+#   the lowercase Meta characters bound to run their equivalents, and
+#   the Meta digits bound to produce numeric arguments. 
+
+proc make_keymap*(): PKeymap{.cdecl, importc: "rl_make_keymap", 
+                              dynlib: readlineDll.}
+# Free the storage associated with a keymap. 
+
+proc discard_keymap*(a2: PKeymap){.cdecl, importc: "rl_discard_keymap", 
+                                   dynlib: readlineDll.}
+# These functions actually appear in bind.c 
+# Return the keymap corresponding to a given name.  Names look like
+#   `emacs' or `emacs-meta' or `vi-insert'.  
+
+proc get_keymap_by_name*(a2: cstring): PKeymap{.cdecl, 
+    importc: "rl_get_keymap_by_name", dynlib: readlineDll.}
+# Return the current keymap. 
+
+proc get_keymap*(): PKeymap{.cdecl, importc: "rl_get_keymap", 
+                             dynlib: readlineDll.}
+# Set the current keymap to MAP. 
+
+proc set_keymap*(a2: PKeymap){.cdecl, importc: "rl_set_keymap", 
+                               dynlib: readlineDll.}
+
+const 
+  tildeDll = readlineDll
+
+type 
+  Thook_func* = proc (a2: cstring): cstring{.cdecl.}
+
+when not defined(macosx):
+  # If non-null, this contains the address of a function that the application
+  #   wants called before trying the standard tilde expansions.  The function
+  #   is called with the text sans tilde, and returns a malloc()'ed string
+  #   which is the expansion, or a NULL pointer if the expansion fails. 
+
+  var expansion_preexpansion_hook*{.importc: "tilde_expansion_preexpansion_hook", 
+                                    dynlib: tildeDll.}: Thook_func
+
+  # If non-null, this contains the address of a function to call if the
+  #   standard meaning for expanding a tilde fails.  The function is called
+  #   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+  #   which is the expansion, or a NULL pointer if there is no expansion. 
+
+  var expansion_failure_hook*{.importc: "tilde_expansion_failure_hook", 
+                               dynlib: tildeDll.}: Thook_func
+
+  # When non-null, this is a NULL terminated array of strings which
+  #   are duplicates for a tilde prefix.  Bash uses this to expand
+  #   `=~' and `:~'. 
+
+  var additional_prefixes*{.importc: "tilde_additional_prefixes", dynlib: tildeDll.}: cstringArray
+
+  # When non-null, this is a NULL terminated array of strings which match
+  #   the end of a username, instead of just "/".  Bash sets this to
+  #   `:' and `=~'. 
+
+  var additional_suffixes*{.importc: "tilde_additional_suffixes", dynlib: tildeDll.}: cstringArray
+
+# Return a new string which is the result of tilde expanding STRING. 
+
+proc expand*(a2: cstring): cstring{.cdecl, importc: "tilde_expand", 
+                                    dynlib: tildeDll.}
+# Do the work of tilde expansion on FILENAME.  FILENAME starts with a
+#   tilde.  If there is no expansion, call tilde_expansion_failure_hook. 
+
+proc expand_word*(a2: cstring): cstring{.cdecl, importc: "tilde_expand_word", 
+    dynlib: tildeDll.}
+# Find the portion of the string beginning with ~ that should be expanded. 
+
+proc find_word*(a2: cstring, a3: cint, a4: ptr cint): cstring{.cdecl, 
+    importc: "tilde_find_word", dynlib: tildeDll.}
+
+# Hex-encoded Readline version number. 
+
+const 
+  READLINE_VERSION* = 0x00000600 # Readline 6.0 
+  VERSION_MAJOR* = 6
+  VERSION_MINOR* = 0
+
+# Readline data structures. 
+# Maintaining the state of undo.  We remember individual deletes and inserts
+#   on a chain of things to do. 
+# The actions that undo knows how to undo.  Notice that UNDO_DELETE means
+#   to insert some text, and UNDO_INSERT means to delete some text.   I.e.,
+#   the code tells undo what to undo, not how to undo it. 
+
+type 
+  Tundo_code* = enum 
+    UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END
+
+# What an element of THE_UNDO_LIST looks like. 
+
+type 
+  TUNDO_LIST*{.pure, final.} = object 
+    next*: ptr Tundo_list
+    start*: cint
+    theEnd*: cint             # Where the change took place. 
+    text*: cstring            # The text to insert, if undoing a delete. 
+    what*: Tundo_code         # Delete, Insert, Begin, End. 
+  
+
+# The current undo list for RL_LINE_BUFFER. 
+
+when not defined(macosx):
+  var undo_list*{.importc: "rl_undo_list", dynlib: readlineDll.}: ptr TUNDO_LIST
+
+# The data structure for mapping textual names to code addresses. 
+
+type 
+  TFUNMAP*{.pure, final.} = object 
+    name*: cstring
+    function*: TCommandFunc
+
+
+when not defined(macosx):
+  var funmap*{.importc: "funmap", dynlib: readlineDll.}: ptr ptr TFUNMAP
+
+# **************************************************************** 
+#								    
+#	     Functions available to bind to key sequences	    
+#								    
+# **************************************************************** 
+# Bindable commands for numeric arguments. 
+
+proc digit_argument*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_digit_argument", dynlib: readlineDll.}
+proc universal_argument*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_universal_argument", dynlib: readlineDll.}
+# Bindable commands for moving the cursor. 
+
+proc forward_byte*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_forward_byte", 
+    dynlib: readlineDll.}
+proc forward_char*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_forward_char", 
+    dynlib: readlineDll.}
+proc forward*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_forward", 
+    dynlib: readlineDll.}
+proc backward_byte*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_byte", dynlib: readlineDll.}
+proc backward_char*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_char", dynlib: readlineDll.}
+proc backward*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_backward", 
+    dynlib: readlineDll.}
+proc beg_of_line*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_beg_of_line", 
+    dynlib: readlineDll.}
+proc end_of_line*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_end_of_line", 
+    dynlib: readlineDll.}
+proc forward_word*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_forward_word", 
+    dynlib: readlineDll.}
+proc backward_word*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_word", dynlib: readlineDll.}
+proc refresh_line*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_refresh_line", 
+    dynlib: readlineDll.}
+proc clear_screen*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_clear_screen", 
+    dynlib: readlineDll.}
+proc skip_csi_sequence*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_skip_csi_sequence", dynlib: readlineDll.}
+proc arrow_keys*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_arrow_keys", 
+    dynlib: readlineDll.}
+# Bindable commands for inserting and deleting text. 
+
+proc insert*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_insert", 
+                                        dynlib: readlineDll.}
+proc quoted_insert*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_quoted_insert", dynlib: readlineDll.}
+proc tab_insert*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_tab_insert", 
+    dynlib: readlineDll.}
+proc newline*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_newline", 
+    dynlib: readlineDll.}
+proc do_lowercase_version*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_do_lowercase_version", dynlib: readlineDll.}
+proc rubout*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_rubout", 
+                                        dynlib: readlineDll.}
+proc delete*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_delete", 
+                                        dynlib: readlineDll.}
+proc rubout_or_delete*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_rubout_or_delete", dynlib: readlineDll.}
+proc delete_horizontal_space*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_delete_horizontal_space", dynlib: readlineDll.}
+proc delete_or_show_completions*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_delete_or_show_completions", dynlib: readlineDll.}
+proc insert_comment*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_insert_comment", dynlib: readlineDll.}
+# Bindable commands for changing case. 
+
+proc upcase_word*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_upcase_word", 
+    dynlib: readlineDll.}
+proc downcase_word*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_downcase_word", dynlib: readlineDll.}
+proc capitalize_word*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_capitalize_word", dynlib: readlineDll.}
+# Bindable commands for transposing characters and words. 
+
+proc transpose_words*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_transpose_words", dynlib: readlineDll.}
+proc transpose_chars*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_transpose_chars", dynlib: readlineDll.}
+# Bindable commands for searching within a line. 
+
+proc char_search*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_char_search", 
+    dynlib: readlineDll.}
+proc backward_char_search*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_char_search", dynlib: readlineDll.}
+# Bindable commands for readline's interface to the command history. 
+
+proc beginning_of_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_beginning_of_history", dynlib: readlineDll.}
+proc end_of_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_end_of_history", dynlib: readlineDll.}
+proc get_next_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_get_next_history", dynlib: readlineDll.}
+proc get_previous_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_get_previous_history", dynlib: readlineDll.}
+# Bindable commands for managing the mark and region. 
+
+proc set_mark*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_set_mark", 
+    dynlib: readlineDll.}
+proc exchange_point_and_mark*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_exchange_point_and_mark", dynlib: readlineDll.}
+# Bindable commands to set the editing mode (emacs or vi). 
+
+proc vi_editing_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_editing_mode", dynlib: readlineDll.}
+proc emacs_editing_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_emacs_editing_mode", dynlib: readlineDll.}
+# Bindable commands to change the insert mode (insert or overwrite) 
+
+proc overwrite_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_overwrite_mode", dynlib: readlineDll.}
+# Bindable commands for managing key bindings. 
+
+proc re_read_init_file*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_re_read_init_file", dynlib: readlineDll.}
+proc dump_functions*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_dump_functions", dynlib: readlineDll.}
+proc dump_macros*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_dump_macros", 
+    dynlib: readlineDll.}
+proc dump_variables*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_dump_variables", dynlib: readlineDll.}
+# Bindable commands for word completion. 
+
+proc complete*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_complete", 
+    dynlib: readlineDll.}
+proc possible_completions*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_possible_completions", dynlib: readlineDll.}
+proc insert_completions*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_insert_completions", dynlib: readlineDll.}
+proc old_menu_complete*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_old_menu_complete", dynlib: readlineDll.}
+proc menu_complete*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_menu_complete", dynlib: readlineDll.}
+proc backward_menu_complete*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_menu_complete", dynlib: readlineDll.}
+# Bindable commands for killing and yanking text, and managing the kill ring. 
+
+proc kill_word*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_kill_word", 
+    dynlib: readlineDll.}
+proc backward_kill_word*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_kill_word", dynlib: readlineDll.}
+proc kill_line*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_kill_line", 
+    dynlib: readlineDll.}
+proc backward_kill_line*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_backward_kill_line", dynlib: readlineDll.}
+proc kill_full_line*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_kill_full_line", dynlib: readlineDll.}
+proc unix_word_rubout*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_unix_word_rubout", dynlib: readlineDll.}
+proc unix_filename_rubout*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_unix_filename_rubout", dynlib: readlineDll.}
+proc unix_line_discard*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_unix_line_discard", dynlib: readlineDll.}
+proc copy_region_to_kill*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_copy_region_to_kill", dynlib: readlineDll.}
+proc kill_region*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_kill_region", 
+    dynlib: readlineDll.}
+proc copy_forward_word*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_copy_forward_word", dynlib: readlineDll.}
+proc copy_backward_word*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_copy_backward_word", dynlib: readlineDll.}
+proc yank*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_yank", 
+                                      dynlib: readlineDll.}
+proc yank_pop*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_yank_pop", 
+    dynlib: readlineDll.}
+proc yank_nth_arg*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_yank_nth_arg", 
+    dynlib: readlineDll.}
+proc yank_last_arg*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_yank_last_arg", dynlib: readlineDll.}
+when defined(Windows): 
+  proc paste_from_clipboard*(a2: cint, a3: cint): cint{.cdecl, 
+      importc: "rl_paste_from_clipboard", dynlib: readlineDll.}
+# Bindable commands for incremental searching. 
+
+proc reverse_search_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_reverse_search_history", dynlib: readlineDll.}
+proc forward_search_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_forward_search_history", dynlib: readlineDll.}
+# Bindable keyboard macro commands. 
+
+proc start_kbd_macro*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_start_kbd_macro", dynlib: readlineDll.}
+proc end_kbd_macro*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_end_kbd_macro", dynlib: readlineDll.}
+proc call_last_kbd_macro*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_call_last_kbd_macro", dynlib: readlineDll.}
+# Bindable undo commands. 
+
+proc revert_line*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_revert_line", 
+    dynlib: readlineDll.}
+proc undo_command*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_undo_command", 
+    dynlib: readlineDll.}
+# Bindable tilde expansion commands. 
+
+proc tilde_expand*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_tilde_expand", 
+    dynlib: readlineDll.}
+# Bindable terminal control commands. 
+
+proc restart_output*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_restart_output", dynlib: readlineDll.}
+proc stop_output*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_stop_output", 
+    dynlib: readlineDll.}
+# Miscellaneous bindable commands. 
+
+proc abort*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_abort", 
+                                       dynlib: readlineDll.}
+proc tty_status*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_tty_status", 
+    dynlib: readlineDll.}
+# Bindable commands for incremental and non-incremental history searching. 
+
+proc history_search_forward*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_history_search_forward", dynlib: readlineDll.}
+proc history_search_backward*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_history_search_backward", dynlib: readlineDll.}
+proc noninc_forward_search*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_noninc_forward_search", dynlib: readlineDll.}
+proc noninc_reverse_search*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_noninc_reverse_search", dynlib: readlineDll.}
+proc noninc_forward_search_again*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_noninc_forward_search_again", dynlib: readlineDll.}
+proc noninc_reverse_search_again*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_noninc_reverse_search_again", dynlib: readlineDll.}
+# Bindable command used when inserting a matching close character. 
+
+proc insert_close*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_insert_close", 
+    dynlib: readlineDll.}
+# Not available unless READLINE_CALLBACKS is defined. 
+
+proc callback_handler_install*(a2: cstring, a3: TvcpFunc){.cdecl, 
+    importc: "rl_callback_handler_install", dynlib: readlineDll.}
+proc callback_read_char*(){.cdecl, importc: "rl_callback_read_char", 
+                            dynlib: readlineDll.}
+proc callback_handler_remove*(){.cdecl, importc: "rl_callback_handler_remove", 
+                                 dynlib: readlineDll.}
+# Things for vi mode. Not available unless readline is compiled -DVI_MODE. 
+# VI-mode bindable commands. 
+
+proc vi_redo*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_redo", 
+    dynlib: readlineDll.}
+proc vi_undo*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_undo", 
+    dynlib: readlineDll.}
+proc vi_yank_arg*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_yank_arg", 
+    dynlib: readlineDll.}
+proc vi_fetch_history*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_fetch_history", dynlib: readlineDll.}
+proc vi_search_again*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_search_again", dynlib: readlineDll.}
+proc vi_search*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_search", 
+    dynlib: readlineDll.}
+proc vi_complete*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_complete", 
+    dynlib: readlineDll.}
+proc vi_tilde_expand*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_tilde_expand", dynlib: readlineDll.}
+proc vi_prev_word*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_prev_word", 
+    dynlib: readlineDll.}
+proc vi_next_word*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_next_word", 
+    dynlib: readlineDll.}
+proc vi_end_word*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_end_word", 
+    dynlib: readlineDll.}
+proc vi_insert_beg*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_insert_beg", dynlib: readlineDll.}
+proc vi_append_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_append_mode", dynlib: readlineDll.}
+proc vi_append_eol*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_append_eol", dynlib: readlineDll.}
+proc vi_eof_maybe*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_eof_maybe", 
+    dynlib: readlineDll.}
+proc vi_insertion_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_insertion_mode", dynlib: readlineDll.}
+proc vi_insert_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_insert_mode", dynlib: readlineDll.}
+proc vi_movement_mode*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_movement_mode", dynlib: readlineDll.}
+proc vi_arg_digit*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_arg_digit", 
+    dynlib: readlineDll.}
+proc vi_change_case*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_change_case", dynlib: readlineDll.}
+proc vi_put*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_put", 
+                                        dynlib: readlineDll.}
+proc vi_column*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_column", 
+    dynlib: readlineDll.}
+proc vi_delete_to*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_delete_to", 
+    dynlib: readlineDll.}
+proc vi_change_to*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_change_to", 
+    dynlib: readlineDll.}
+proc vi_yank_to*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_yank_to", 
+    dynlib: readlineDll.}
+proc vi_rubout*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_rubout", 
+    dynlib: readlineDll.}
+proc vi_delete*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_delete", 
+    dynlib: readlineDll.}
+proc vi_back_to_indent*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_back_to_indent", dynlib: readlineDll.}
+proc vi_first_print*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_first_print", dynlib: readlineDll.}
+proc vi_char_search*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_char_search", dynlib: readlineDll.}
+proc vi_match*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_match", 
+    dynlib: readlineDll.}
+proc vi_change_char*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_change_char", dynlib: readlineDll.}
+proc vi_subst*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_subst", 
+    dynlib: readlineDll.}
+proc vi_overstrike*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_overstrike", dynlib: readlineDll.}
+proc vi_overstrike_delete*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_vi_overstrike_delete", dynlib: readlineDll.}
+proc vi_replace*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_replace", 
+    dynlib: readlineDll.}
+proc vi_set_mark*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_set_mark", 
+    dynlib: readlineDll.}
+proc vi_goto_mark*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_goto_mark", 
+    dynlib: readlineDll.}
+# VI-mode utility functions. 
+
+proc vi_check*(): cint{.cdecl, importc: "rl_vi_check", dynlib: readlineDll.}
+proc vi_domove*(a2: cint, a3: ptr cint): cint{.cdecl, importc: "rl_vi_domove", 
+    dynlib: readlineDll.}
+proc vi_bracktype*(a2: cint): cint{.cdecl, importc: "rl_vi_bracktype", 
+                                    dynlib: readlineDll.}
+proc vi_start_inserting*(a2: cint, a3: cint, a4: cint){.cdecl, 
+    importc: "rl_vi_start_inserting", dynlib: readlineDll.}
+# VI-mode pseudo-bindable commands, used as utility functions. 
+
+proc vi_fXWord*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_fWord", 
+    dynlib: readlineDll.}
+proc vi_bXWord*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_bWord", 
+    dynlib: readlineDll.}
+proc vi_eXWord*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_eWord", 
+    dynlib: readlineDll.}
+proc vi_fword*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_fword", 
+    dynlib: readlineDll.}
+proc vi_bword*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_bword", 
+    dynlib: readlineDll.}
+proc vi_eword*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_vi_eword", 
+    dynlib: readlineDll.}
+# **************************************************************** 
+#								    
+#			Well Published Functions		    
+#								    
+# **************************************************************** 
+# Readline functions. 
+# Read a line of input.  Prompt with PROMPT.  A NULL PROMPT means none. 
+
+proc readline*(a2: cstring): cstring{.cdecl, importc: "readline", 
+                                      dynlib: readlineDll.}
+proc free*(mem: cstring) {.importc: "free", nodecl.}
+  ## free the buffer that `readline` returned.
+
+proc set_prompt*(a2: cstring): cint{.cdecl, importc: "rl_set_prompt", 
+                                     dynlib: readlineDll.}
+proc expand_prompt*(a2: cstring): cint{.cdecl, importc: "rl_expand_prompt", 
+                                        dynlib: readlineDll.}
+proc initialize*(): cint{.cdecl, importc: "rl_initialize", dynlib: readlineDll.}
+# Undocumented; unused by readline 
+
+proc discard_argument*(): cint{.cdecl, importc: "rl_discard_argument", 
+                                dynlib: readlineDll.}
+# Utility functions to bind keys to readline commands. 
+
+proc add_defun*(a2: cstring, a3: TCommandFunc, a4: cint): cint{.cdecl, 
+    importc: "rl_add_defun", dynlib: readlineDll.}
+proc bind_key*(a2: cint, a3: TCommandFunc): cint{.cdecl, 
+    importc: "rl_bind_key", dynlib: readlineDll.}
+proc bind_key_in_map*(a2: cint, a3: TCommandFunc, a4: PKeymap): cint{.cdecl, 
+    importc: "rl_bind_key_in_map", dynlib: readlineDll.}
+proc unbind_key*(a2: cint): cint{.cdecl, importc: "rl_unbind_key", 
+                                  dynlib: readlineDll.}
+proc unbind_key_in_map*(a2: cint, a3: PKeymap): cint{.cdecl, 
+    importc: "rl_unbind_key_in_map", dynlib: readlineDll.}
+proc bind_key_if_unbound*(a2: cint, a3: TCommandFunc): cint{.cdecl, 
+    importc: "rl_bind_key_if_unbound", dynlib: readlineDll.}
+proc bind_key_if_unbound_in_map*(a2: cint, a3: TCommandFunc, a4: PKeymap): cint{.
+    cdecl, importc: "rl_bind_key_if_unbound_in_map", dynlib: readlineDll.}
+proc unbind_function_in_map*(a2: TCommandFunc, a3: PKeymap): cint{.cdecl, 
+    importc: "rl_unbind_function_in_map", dynlib: readlineDll.}
+proc unbind_command_in_map*(a2: cstring, a3: PKeymap): cint{.cdecl, 
+    importc: "rl_unbind_command_in_map", dynlib: readlineDll.}
+proc bind_keyseq*(a2: cstring, a3: TCommandFunc): cint{.cdecl, 
+    importc: "rl_bind_keyseq", dynlib: readlineDll.}
+proc bind_keyseq_in_map*(a2: cstring, a3: TCommandFunc, a4: PKeymap): cint{.
+    cdecl, importc: "rl_bind_keyseq_in_map", dynlib: readlineDll.}
+proc bind_keyseq_if_unbound*(a2: cstring, a3: TCommandFunc): cint{.cdecl, 
+    importc: "rl_bind_keyseq_if_unbound", dynlib: readlineDll.}
+proc bind_keyseq_if_unbound_in_map*(a2: cstring, a3: TCommandFunc, 
+                                    a4: PKeymap): cint{.cdecl, 
+    importc: "rl_bind_keyseq_if_unbound_in_map", dynlib: readlineDll.}
+proc generic_bind*(a2: cint, a3: cstring, a4: cstring, a5: PKeymap): cint{.
+    cdecl, importc: "rl_generic_bind", dynlib: readlineDll.}
+proc variable_value*(a2: cstring): cstring{.cdecl, importc: "rl_variable_value", 
+    dynlib: readlineDll.}
+proc variable_bind*(a2: cstring, a3: cstring): cint{.cdecl, 
+    importc: "rl_variable_bind", dynlib: readlineDll.}
+# Backwards compatibility, use rl_bind_keyseq_in_map instead. 
+
+proc set_key*(a2: cstring, a3: TCommandFunc, a4: PKeymap): cint{.cdecl, 
+    importc: "rl_set_key", dynlib: readlineDll.}
+# Backwards compatibility, use rl_generic_bind instead. 
+
+proc macro_bind*(a2: cstring, a3: cstring, a4: PKeymap): cint{.cdecl, 
+    importc: "rl_macro_bind", dynlib: readlineDll.}
+# Undocumented in the texinfo manual; not really useful to programs. 
+
+proc translate_keyseq*(a2: cstring, a3: cstring, a4: ptr cint): cint{.cdecl, 
+    importc: "rl_translate_keyseq", dynlib: readlineDll.}
+proc untranslate_keyseq*(a2: cint): cstring{.cdecl, 
+    importc: "rl_untranslate_keyseq", dynlib: readlineDll.}
+proc named_function*(a2: cstring): TCommandFunc{.cdecl, 
+    importc: "rl_named_function", dynlib: readlineDll.}
+proc function_of_keyseq*(a2: cstring, a3: PKeymap, a4: ptr cint): TCommandFunc{.
+    cdecl, importc: "rl_function_of_keyseq", dynlib: readlineDll.}
+proc list_funmap_names*(){.cdecl, importc: "rl_list_funmap_names", 
+                           dynlib: readlineDll.}
+proc invoking_keyseqs_in_map*(a2: TCommandFunc, a3: PKeymap): cstringArray{.
+    cdecl, importc: "rl_invoking_keyseqs_in_map", dynlib: readlineDll.}
+proc invoking_keyseqs*(a2: TCommandFunc): cstringArray{.cdecl, 
+    importc: "rl_invoking_keyseqs", dynlib: readlineDll.}
+proc function_dumper*(a2: cint){.cdecl, importc: "rl_function_dumper", 
+                                 dynlib: readlineDll.}
+proc macro_dumper*(a2: cint){.cdecl, importc: "rl_macro_dumper", 
+                              dynlib: readlineDll.}
+proc variable_dumper*(a2: cint){.cdecl, importc: "rl_variable_dumper", 
+                                 dynlib: readlineDll.}
+proc read_init_file*(a2: cstring): cint{.cdecl, importc: "rl_read_init_file", 
+    dynlib: readlineDll.}
+proc parse_and_bind*(a2: cstring): cint{.cdecl, importc: "rl_parse_and_bind", 
+    dynlib: readlineDll.}
+
+proc get_keymap_name*(a2: PKeymap): cstring{.cdecl, 
+    importc: "rl_get_keymap_name", dynlib: readlineDll.}
+
+proc set_keymap_from_edit_mode*(){.cdecl, 
+                                   importc: "rl_set_keymap_from_edit_mode", 
+                                   dynlib: readlineDll.}
+proc get_keymap_name_from_edit_mode*(): cstring{.cdecl, 
+    importc: "rl_get_keymap_name_from_edit_mode", dynlib: readlineDll.}
+# Functions for manipulating the funmap, which maps command names to functions. 
+
+proc add_funmap_entry*(a2: cstring, a3: TCommandFunc): cint{.cdecl, 
+    importc: "rl_add_funmap_entry", dynlib: readlineDll.}
+proc funmap_names*(): cstringArray{.cdecl, importc: "rl_funmap_names", 
+                                    dynlib: readlineDll.}
+# Undocumented, only used internally -- there is only one funmap, and this
+#   function may be called only once. 
+
+proc initialize_funmap*(){.cdecl, importc: "rl_initialize_funmap", 
+                           dynlib: readlineDll.}
+# Utility functions for managing keyboard macros. 
+
+proc push_macro_input*(a2: cstring){.cdecl, importc: "rl_push_macro_input", 
+                                     dynlib: readlineDll.}
+# Functions for undoing, from undo.c 
+
+proc add_undo*(a2: Tundo_code, a3: cint, a4: cint, a5: cstring){.cdecl, 
+    importc: "rl_add_undo", dynlib: readlineDll.}
+proc free_undo_list*(){.cdecl, importc: "rl_free_undo_list", dynlib: readlineDll.}
+proc do_undo*(): cint{.cdecl, importc: "rl_do_undo", dynlib: readlineDll.}
+proc begin_undo_group*(): cint{.cdecl, importc: "rl_begin_undo_group", 
+                                dynlib: readlineDll.}
+proc end_undo_group*(): cint{.cdecl, importc: "rl_end_undo_group", 
+                              dynlib: readlineDll.}
+proc modifying*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_modifying", 
+    dynlib: readlineDll.}
+# Functions for redisplay. 
+
+proc redisplay*(){.cdecl, importc: "rl_redisplay", dynlib: readlineDll.}
+proc on_new_line*(): cint{.cdecl, importc: "rl_on_new_line", dynlib: readlineDll.}
+proc on_new_line_with_prompt*(): cint{.cdecl, 
+                                       importc: "rl_on_new_line_with_prompt", 
+                                       dynlib: readlineDll.}
+proc forced_update_display*(): cint{.cdecl, importc: "rl_forced_update_display", 
+                                     dynlib: readlineDll.}
+proc clear_message*(): cint{.cdecl, importc: "rl_clear_message", 
+                             dynlib: readlineDll.}
+proc reset_line_state*(): cint{.cdecl, importc: "rl_reset_line_state", 
+                                dynlib: readlineDll.}
+proc crlf*(): cint{.cdecl, importc: "rl_crlf", dynlib: readlineDll.}
+proc message*(a2: cstring): cint{.varargs, cdecl, importc: "rl_message", 
+                                  dynlib: readlineDll.}
+proc show_char*(a2: cint): cint{.cdecl, importc: "rl_show_char", 
+                                 dynlib: readlineDll.}
+# Undocumented in texinfo manual. 
+
+proc character_len*(a2: cint, a3: cint): cint{.cdecl, 
+    importc: "rl_character_len", dynlib: readlineDll.}
+# Save and restore internal prompt redisplay information. 
+
+proc save_prompt*(){.cdecl, importc: "rl_save_prompt", dynlib: readlineDll.}
+proc restore_prompt*(){.cdecl, importc: "rl_restore_prompt", dynlib: readlineDll.}
+# Modifying text. 
+
+proc replace_line*(a2: cstring, a3: cint){.cdecl, importc: "rl_replace_line", 
+    dynlib: readlineDll.}
+proc insert_text*(a2: cstring): cint{.cdecl, importc: "rl_insert_text", 
+                                      dynlib: readlineDll.}
+proc delete_text*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_delete_text", 
+    dynlib: readlineDll.}
+proc kill_text*(a2: cint, a3: cint): cint{.cdecl, importc: "rl_kill_text", 
+    dynlib: readlineDll.}
+proc copy_text*(a2: cint, a3: cint): cstring{.cdecl, importc: "rl_copy_text", 
+    dynlib: readlineDll.}
+# Terminal and tty mode management. 
+
+proc prep_terminal*(a2: cint){.cdecl, importc: "rl_prep_terminal", 
+                               dynlib: readlineDll.}
+proc deprep_terminal*(){.cdecl, importc: "rl_deprep_terminal", 
+                         dynlib: readlineDll.}
+proc tty_set_default_bindings*(a2: PKeymap){.cdecl, 
+    importc: "rl_tty_set_default_bindings", dynlib: readlineDll.}
+proc tty_unset_default_bindings*(a2: PKeymap){.cdecl, 
+    importc: "rl_tty_unset_default_bindings", dynlib: readlineDll.}
+proc reset_terminal*(a2: cstring): cint{.cdecl, importc: "rl_reset_terminal", 
+    dynlib: readlineDll.}
+proc resize_terminal*(){.cdecl, importc: "rl_resize_terminal", 
+                         dynlib: readlineDll.}
+proc set_screen_size*(a2: cint, a3: cint){.cdecl, importc: "rl_set_screen_size", 
+    dynlib: readlineDll.}
+proc get_screen_size*(a2: ptr cint, a3: ptr cint){.cdecl, 
+    importc: "rl_get_screen_size", dynlib: readlineDll.}
+proc reset_screen_size*(){.cdecl, importc: "rl_reset_screen_size", 
+                           dynlib: readlineDll.}
+proc get_termcap*(a2: cstring): cstring{.cdecl, importc: "rl_get_termcap", 
+    dynlib: readlineDll.}
+# Functions for character input. 
+
+proc stuff_char*(a2: cint): cint{.cdecl, importc: "rl_stuff_char", 
+                                  dynlib: readlineDll.}
+proc execute_next*(a2: cint): cint{.cdecl, importc: "rl_execute_next", 
+                                    dynlib: readlineDll.}
+proc clear_pending_input*(): cint{.cdecl, importc: "rl_clear_pending_input", 
+                                   dynlib: readlineDll.}
+proc read_key*(): cint{.cdecl, importc: "rl_read_key", dynlib: readlineDll.}
+proc getc*(a2: File): cint{.cdecl, importc: "rl_getc", dynlib: readlineDll.}
+proc set_keyboard_input_timeout*(a2: cint): cint{.cdecl, 
+    importc: "rl_set_keyboard_input_timeout", dynlib: readlineDll.}
+# `Public' utility functions . 
+
+proc extend_line_buffer*(a2: cint){.cdecl, importc: "rl_extend_line_buffer", 
+                                    dynlib: readlineDll.}
+proc ding*(): cint{.cdecl, importc: "rl_ding", dynlib: readlineDll.}
+proc alphabetic*(a2: cint): cint{.cdecl, importc: "rl_alphabetic", 
+                                  dynlib: readlineDll.}
+proc free*(a2: pointer){.cdecl, importc: "rl_free", dynlib: readlineDll.}
+# Readline signal handling, from signals.c 
+
+proc set_signals*(): cint{.cdecl, importc: "rl_set_signals", dynlib: readlineDll.}
+proc clear_signals*(): cint{.cdecl, importc: "rl_clear_signals", 
+                             dynlib: readlineDll.}
+proc cleanup_after_signal*(){.cdecl, importc: "rl_cleanup_after_signal", 
+                              dynlib: readlineDll.}
+proc reset_after_signal*(){.cdecl, importc: "rl_reset_after_signal", 
+                            dynlib: readlineDll.}
+proc free_line_state*(){.cdecl, importc: "rl_free_line_state", 
+                         dynlib: readlineDll.}
+proc echo_signal_char*(a2: cint){.cdecl, importc: "rl_echo_signal_char", 
+                                  dynlib: readlineDll.}
+proc set_paren_blink_timeout*(a2: cint): cint{.cdecl, 
+    importc: "rl_set_paren_blink_timeout", dynlib: readlineDll.}
+# Undocumented. 
+
+proc maybe_save_line*(): cint{.cdecl, importc: "rl_maybe_save_line", 
+                               dynlib: readlineDll.}
+proc maybe_unsave_line*(): cint{.cdecl, importc: "rl_maybe_unsave_line", 
+                                 dynlib: readlineDll.}
+proc maybe_replace_line*(): cint{.cdecl, importc: "rl_maybe_replace_line", 
+                                  dynlib: readlineDll.}
+# Completion functions. 
+
+proc complete_internal*(a2: cint): cint{.cdecl, importc: "rl_complete_internal", 
+    dynlib: readlineDll.}
+proc display_match_list*(a2: cstringArray, a3: cint, a4: cint){.cdecl, 
+    importc: "rl_display_match_list", dynlib: readlineDll.}
+proc completion_matches*(a2: cstring, a3: Tcompentry_func): cstringArray{.
+    cdecl, importc: "rl_completion_matches", dynlib: readlineDll.}
+proc username_completion_function*(a2: cstring, a3: cint): cstring{.cdecl, 
+    importc: "rl_username_completion_function", dynlib: readlineDll.}
+proc filename_completion_function*(a2: cstring, a3: cint): cstring{.cdecl, 
+    importc: "rl_filename_completion_function", dynlib: readlineDll.}
+proc completion_mode*(a2: TCommandFunc): cint{.cdecl, 
+    importc: "rl_completion_mode", dynlib: readlineDll.}
+# **************************************************************** 
+#								    
+#			Well Published Variables		    
+#								    
+# **************************************************************** 
+
+when false: 
+  # The version of this incarnation of the readline library. 
+  var library_version*{.importc: "rl_library_version", dynlib: readlineDll.}: cstring
+  # e.g., "4.2" 
+  var readline_version*{.importc: "rl_readline_version", dynlib: readlineDll.}: cint
+  # e.g., 0x0402 
+  # True if this is real GNU readline. 
+  var gnu_readline_p*{.importc: "rl_gnu_readline_p", dynlib: readlineDll.}: cint
+  # Flags word encapsulating the current readline state. 
+  var readline_state*{.importc: "rl_readline_state", dynlib: readlineDll.}: cint
+  # Says which editing mode readline is currently using.  1 means emacs mode;
+  #   0 means vi mode. 
+  var editing_mode*{.importc: "rl_editing_mode", dynlib: readlineDll.}: cint
+  # Insert or overwrite mode for emacs mode.  1 means insert mode; 0 means
+  #   overwrite mode.  Reset to insert mode on each input line. 
+  var insert_mode*{.importc: "rl_insert_mode", dynlib: readlineDll.}: cint
+  # The name of the calling program.  You should initialize this to
+  #   whatever was in argv[0].  It is used when parsing conditionals. 
+  var readline_name*{.importc: "rl_readline_name", dynlib: readlineDll.}: cstring
+  # The prompt readline uses.  This is set from the argument to
+  #   readline (), and should not be assigned to directly. 
+  var prompt*{.importc: "rl_prompt", dynlib: readlineDll.}: cstring
+  # The prompt string that is actually displayed by rl_redisplay.  Public so
+  #   applications can more easily supply their own redisplay functions. 
+  var display_prompt*{.importc: "rl_display_prompt", dynlib: readlineDll.}: cstring
+  # The line buffer that is in use. 
+  var line_buffer*{.importc: "rl_line_buffer", dynlib: readlineDll.}: cstring
+  # The location of point, and end. 
+  var point*{.importc: "rl_point", dynlib: readlineDll.}: cint
+  var theEnd*{.importc: "rl_end", dynlib: readlineDll.}: cint
+  # The mark, or saved cursor position. 
+  var mark*{.importc: "rl_mark", dynlib: readlineDll.}: cint
+  # Flag to indicate that readline has finished with the current input
+  #   line and should return it. 
+  var done*{.importc: "rl_done", dynlib: readlineDll.}: cint
+  # If set to a character value, that will be the next keystroke read. 
+  var pending_input*{.importc: "rl_pending_input", dynlib: readlineDll.}: cint
+  # Non-zero if we called this function from _rl_dispatch().  It's present
+  #   so functions can find out whether they were called from a key binding
+  #   or directly from an application. 
+  var dispatching*{.importc: "rl_dispatching", dynlib: readlineDll.}: cint
+  # Non-zero if the user typed a numeric argument before executing the
+  #   current function. 
+  var explicit_arg*{.importc: "rl_explicit_arg", dynlib: readlineDll.}: cint
+  # The current value of the numeric argument specified by the user. 
+  var numeric_arg*{.importc: "rl_numeric_arg", dynlib: readlineDll.}: cint
+  # The address of the last command function Readline executed. 
+  var last_func*{.importc: "rl_last_func", dynlib: readlineDll.}: TCommandFunc
+  # The name of the terminal to use. 
+  var terminal_name*{.importc: "rl_terminal_name", dynlib: readlineDll.}: cstring
+  # The input and output streams. 
+  var instream*{.importc: "rl_instream", dynlib: readlineDll.}: File
+  var outstream*{.importc: "rl_outstream", dynlib: readlineDll.}: File
+  # If non-zero, Readline gives values of LINES and COLUMNS from the environment
+  #   greater precedence than values fetched from the kernel when computing the
+  #   screen dimensions. 
+  var prefer_env_winsize*{.importc: "rl_prefer_env_winsize", dynlib: readlineDll.}: cint
+  # If non-zero, then this is the address of a function to call just
+  #   before readline_internal () prints the first prompt. 
+  var startup_hook*{.importc: "rl_startup_hook", dynlib: readlineDll.}:  hook_func
+  # If non-zero, this is the address of a function to call just before
+  #   readline_internal_setup () returns and readline_internal starts
+  #   reading input characters. 
+  var pre_input_hook*{.importc: "rl_pre_input_hook", dynlib: readlineDll.}: hook_func
+  # The address of a function to call periodically while Readline is
+  #   awaiting character input, or NULL, for no event handling. 
+  var event_hook*{.importc: "rl_event_hook", dynlib: readlineDll.}: hook_func
+  # The address of the function to call to fetch a character from the current
+  #   Readline input stream 
+  var getc_function*{.importc: "rl_getc_function", dynlib: readlineDll.}: getc_func
+  var redisplay_function*{.importc: "rl_redisplay_function", dynlib: readlineDll.}: voidfunc
+  var prep_term_function*{.importc: "rl_prep_term_function", dynlib: readlineDll.}: vintfunc
+  var deprep_term_function*{.importc: "rl_deprep_term_function", 
+                             dynlib: readlineDll.}: voidfunc
+  # Dispatch variables. 
+  var executing_keymap*{.importc: "rl_executing_keymap", dynlib: readlineDll.}: PKeymap
+  var binding_keymap*{.importc: "rl_binding_keymap", dynlib: readlineDll.}: PKeymap
+  # Display variables. 
+  # If non-zero, readline will erase the entire line, including any prompt,
+  #   if the only thing typed on an otherwise-blank line is something bound to
+  #   rl_newline. 
+  var erase_empty_line*{.importc: "rl_erase_empty_line", dynlib: readlineDll.}: cint
+  # If non-zero, the application has already printed the prompt (rl_prompt)
+  #   before calling readline, so readline should not output it the first time
+  #   redisplay is done. 
+  var already_prompted*{.importc: "rl_already_prompted", dynlib: readlineDll.}: cint
+  # A non-zero value means to read only this many characters rather than
+  #   up to a character bound to accept-line. 
+  var num_chars_to_read*{.importc: "rl_num_chars_to_read", dynlib: readlineDll.}: cint
+  # The text of a currently-executing keyboard macro. 
+  var executing_macro*{.importc: "rl_executing_macro", dynlib: readlineDll.}: cstring
+  # Variables to control readline signal handling. 
+  # If non-zero, readline will install its own signal handlers for
+  #   SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. 
+  var catch_signals*{.importc: "rl_catch_signals", dynlib: readlineDll.}: cint
+  # If non-zero, readline will install a signal handler for SIGWINCH
+  #   that also attempts to call any calling application's SIGWINCH signal
+  #   handler.  Note that the terminal is not cleaned up before the
+  #   application's signal handler is called; use rl_cleanup_after_signal()
+  #   to do that. 
+  var catch_sigwinch*{.importc: "rl_catch_sigwinch", dynlib: readlineDll.}: cint
+  # Completion variables. 
+  # Pointer to the generator function for completion_matches ().
+  #   NULL means to use rl_filename_completion_function (), the default
+  #   filename completer. 
+  var completion_entry_function*{.importc: "rl_completion_entry_function", 
+                                  dynlib: readlineDll.}: compentry_func
+  # Optional generator for menu completion.  Default is
+  #   rl_completion_entry_function (rl_filename_completion_function). 
+  var menu_completion_entry_function*{.importc: "rl_menu_completion_entry_function", 
+                                       dynlib: readlineDll.}: compentry_func
+  # If rl_ignore_some_completions_function is non-NULL it is the address
+  #   of a function to call after all of the possible matches have been
+  #   generated, but before the actual completion is done to the input line.
+  #   The function is called with one argument; a NULL terminated array
+  #   of (char *).  If your function removes any of the elements, they
+  #   must be free()'ed. 
+  var ignore_some_completions_function*{.
+      importc: "rl_ignore_some_completions_function", dynlib: readlineDll.}: compignore_func
+  # Pointer to alternative function to create matches.
+  #   Function is called with TEXT, START, and END.
+  #   START and END are indices in RL_LINE_BUFFER saying what the boundaries
+  #   of TEXT are.
+  #   If this function exists and returns NULL then call the value of
+  #   rl_completion_entry_function to try to match, otherwise use the
+  #   array of strings returned. 
+  var attempted_completion_function*{.importc: "rl_attempted_completion_function", 
+                                      dynlib: readlineDll.}: completion_func
+  # The basic list of characters that signal a break between words for the
+  #   completer routine.  The initial contents of this variable is what
+  #   breaks words in the shell, i.e. "n\"\\'`@$>". 
+  var basic_word_break_characters*{.importc: "rl_basic_word_break_characters", 
+                                    dynlib: readlineDll.}: cstring
+  # The list of characters that signal a break between words for
+  #   rl_complete_internal.  The default list is the contents of
+  #   rl_basic_word_break_characters.  
+  var completer_word_break_characters*{.importc: "rl_completer_word_break_characters", 
+                                        dynlib: readlineDll.}: cstring
+  # Hook function to allow an application to set the completion word
+  #   break characters before readline breaks up the line.  Allows
+  #   position-dependent word break characters. 
+  var completion_word_break_hook*{.importc: "rl_completion_word_break_hook", 
+                                   dynlib: readlineDll.}: cpvfunc
+  # List of characters which can be used to quote a substring of the line.
+  #   Completion occurs on the entire substring, and within the substring   
+  #   rl_completer_word_break_characters are treated as any other character,
+  #   unless they also appear within this list. 
+  var completer_quote_characters*{.importc: "rl_completer_quote_characters", 
+                                   dynlib: readlineDll.}: cstring
+  # List of quote characters which cause a word break. 
+  var basic_quote_characters*{.importc: "rl_basic_quote_characters", 
+                               dynlib: readlineDll.}: cstring
+  # List of characters that need to be quoted in filenames by the completer. 
+  var filename_quote_characters*{.importc: "rl_filename_quote_characters", 
+                                  dynlib: readlineDll.}: cstring
+  # List of characters that are word break characters, but should be left
+  #   in TEXT when it is passed to the completion function.  The shell uses
+  #   this to help determine what kind of completing to do. 
+  var special_prefixes*{.importc: "rl_special_prefixes", dynlib: readlineDll.}: cstring
+  # If non-zero, then this is the address of a function to call when
+  #   completing on a directory name.  The function is called with
+  #   the address of a string (the current directory name) as an arg.  It
+  #   changes what is displayed when the possible completions are printed
+  #   or inserted. 
+  var directory_completion_hook*{.importc: "rl_directory_completion_hook", 
+                                  dynlib: readlineDll.}: icppfunc
+  # If non-zero, this is the address of a function to call when completing
+  #   a directory name.  This function takes the address of the directory name
+  #   to be modified as an argument.  Unlike rl_directory_completion_hook, it
+  #   only modifies the directory name used in opendir(2), not what is displayed
+  #   when the possible completions are printed or inserted.  It is called
+  #   before rl_directory_completion_hook.  I'm not happy with how this works
+  #   yet, so it's undocumented. 
+  var directory_rewrite_hook*{.importc: "rl_directory_rewrite_hook", 
+                               dynlib: readlineDll.}: icppfunc
+  # If non-zero, this is the address of a function to call when reading
+  #   directory entries from the filesystem for completion and comparing
+  #   them to the partial word to be completed.  The function should
+  #   either return its first argument (if no conversion takes place) or
+  #   newly-allocated memory.  This can, for instance, convert filenames
+  #   between character sets for comparison against what's typed at the
+  #   keyboard.  The returned value is what is added to the list of
+  #   matches.  The second argument is the length of the filename to be
+  #   converted. 
+  var filename_rewrite_hook*{.importc: "rl_filename_rewrite_hook", 
+                              dynlib: readlineDll.}: dequote_func
+  # If non-zero, then this is the address of a function to call when
+  #   completing a word would normally display the list of possible matches.
+  #   This function is called instead of actually doing the display.
+  #   It takes three arguments: (char **matches, int num_matches, int max_length)
+  #   where MATCHES is the array of strings that matched, NUM_MATCHES is the
+  #   number of strings in that array, and MAX_LENGTH is the length of the
+  #   longest string in that array. 
+  var completion_display_matches_hook*{.importc: "rl_completion_display_matches_hook", 
+                                        dynlib: readlineDll.}: compdisp_func
+  # Non-zero means that the results of the matches are to be treated
+  #   as filenames.  This is ALWAYS zero on entry, and can only be changed
+  #   within a completion entry finder function. 
+  var filename_completion_desired*{.importc: "rl_filename_completion_desired", 
+                                    dynlib: readlineDll.}: cint
+  # Non-zero means that the results of the matches are to be quoted using
+  #   double quotes (or an application-specific quoting mechanism) if the
+  #   filename contains any characters in rl_word_break_chars.  This is
+  #   ALWAYS non-zero on entry, and can only be changed within a completion
+  #   entry finder function. 
+  var filename_quoting_desired*{.importc: "rl_filename_quoting_desired", 
+                                 dynlib: readlineDll.}: cint
+  # Set to a function to quote a filename in an application-specific fashion.
+  #   Called with the text to quote, the type of match found (single or multiple)
+  #   and a pointer to the quoting character to be used, which the function can
+  #   reset if desired. 
+  var filename_quoting_function*{.importc: "rl_filename_quoting_function", 
+                                  dynlib: readlineDll.}: quote_func
+  # Function to call to remove quoting characters from a filename.  Called
+  #   before completion is attempted, so the embedded quotes do not interfere
+  #   with matching names in the file system. 
+  var filename_dequoting_function*{.importc: "rl_filename_dequoting_function", 
+                                    dynlib: readlineDll.}: dequote_func
+  # Function to call to decide whether or not a word break character is
+  #   quoted.  If a character is quoted, it does not break words for the
+  #   completer. 
+  var char_is_quoted_p*{.importc: "rl_char_is_quoted_p", dynlib: readlineDll.}: linebuf_func
+  # Non-zero means to suppress normal filename completion after the
+  #   user-specified completion function has been called. 
+  var attempted_completion_over*{.importc: "rl_attempted_completion_over", 
+                                  dynlib: readlineDll.}: cint
+  # Set to a character describing the type of completion being attempted by
+  #   rl_complete_internal; available for use by application completion
+  #   functions. 
+  var completion_type*{.importc: "rl_completion_type", dynlib: readlineDll.}: cint
+  # Set to the last key used to invoke one of the completion functions 
+  var completion_invoking_key*{.importc: "rl_completion_invoking_key", 
+                                dynlib: readlineDll.}: cint
+  # Up to this many items will be displayed in response to a
+  #   possible-completions call.  After that, we ask the user if she
+  #   is sure she wants to see them all.  The default value is 100. 
+  var completion_query_items*{.importc: "rl_completion_query_items", 
+                               dynlib: readlineDll.}: cint
+  # Character appended to completed words when at the end of the line.  The
+  #   default is a space.  Nothing is added if this is '\0'. 
+  var completion_append_character*{.importc: "rl_completion_append_character", 
+                                    dynlib: readlineDll.}: cint
+  # If set to non-zero by an application completion function,
+  #   rl_completion_append_character will not be appended. 
+  var completion_suppress_append*{.importc: "rl_completion_suppress_append", 
+                                   dynlib: readlineDll.}: cint
+  # Set to any quote character readline thinks it finds before any application
+  #   completion function is called. 
+  var completion_quote_character*{.importc: "rl_completion_quote_character", 
+                                   dynlib: readlineDll.}: cint
+  # Set to a non-zero value if readline found quoting anywhere in the word to
+  #   be completed; set before any application completion function is called. 
+  var completion_found_quote*{.importc: "rl_completion_found_quote", 
+                               dynlib: readlineDll.}: cint
+  # If non-zero, the completion functions don't append any closing quote.
+  #   This is set to 0 by rl_complete_internal and may be changed by an
+  #   application-specific completion function. 
+  var completion_suppress_quote*{.importc: "rl_completion_suppress_quote", 
+                                  dynlib: readlineDll.}: cint
+  # If non-zero, readline will sort the completion matches.  On by default. 
+  var sort_completion_matches*{.importc: "rl_sort_completion_matches", 
+                                dynlib: readlineDll.}: cint
+  # If non-zero, a slash will be appended to completed filenames that are
+  #   symbolic links to directory names, subject to the value of the
+  #   mark-directories variable (which is user-settable).  This exists so
+  #   that application completion functions can override the user's preference
+  #   (set via the mark-symlinked-directories variable) if appropriate.
+  #   It's set to the value of _rl_complete_mark_symlink_dirs in
+  #   rl_complete_internal before any application-specific completion
+  #   function is called, so without that function doing anything, the user's
+  #   preferences are honored. 
+  var completion_mark_symlink_dirs*{.importc: "rl_completion_mark_symlink_dirs", 
+                                     dynlib: readlineDll.}: cint
+  # If non-zero, then disallow duplicates in the matches. 
+  var ignore_completion_duplicates*{.importc: "rl_ignore_completion_duplicates", 
+                                     dynlib: readlineDll.}: cint
+  # If this is non-zero, completion is (temporarily) inhibited, and the
+  #   completion character will be inserted as any other. 
+  var inhibit_completion*{.importc: "rl_inhibit_completion", dynlib: readlineDll.}: cint
+# Input error; can be returned by (*rl_getc_function) if readline is reading
+#   a top-level command (RL_ISSTATE (RL_STATE_READCMD)). 
+
+const 
+  READERR* = (- 2)
+
+# Definitions available for use by readline clients. 
+
+const 
+  PROMPT_START_IGNORE* = '\x01'
+  PROMPT_END_IGNORE* = '\x02'
+
+# Possible values for do_replace argument to rl_filename_quoting_function,
+#   called by rl_complete_internal. 
+
+const 
+  NO_MATCH* = 0
+  SINGLE_MATCH* = 1
+  MULT_MATCH* = 2
+
+# Possible state values for rl_readline_state 
+
+const 
+  STATE_NONE* = 0x00000000    # no state; before first call 
+  STATE_INITIALIZING* = 0x00000001 # initializing 
+  STATE_INITIALIZED* = 0x00000002 # initialization done 
+  STATE_TERMPREPPED* = 0x00000004 # terminal is prepped 
+  STATE_READCMD* = 0x00000008 # reading a command key 
+  STATE_METANEXT* = 0x00000010 # reading input after ESC 
+  STATE_DISPATCHING* = 0x00000020 # dispatching to a command 
+  STATE_MOREINPUT* = 0x00000040 # reading more input in a command function 
+  STATE_ISEARCH* = 0x00000080 # doing incremental search 
+  STATE_NSEARCH* = 0x00000100 # doing non-inc search 
+  STATE_SEARCH* = 0x00000200  # doing a history search 
+  STATE_NUMERICARG* = 0x00000400 # reading numeric argument 
+  STATE_MACROINPUT* = 0x00000800 # getting input from a macro 
+  STATE_MACRODEF* = 0x00001000 # defining keyboard macro 
+  STATE_OVERWRITE* = 0x00002000 # overwrite mode 
+  STATE_COMPLETING* = 0x00004000 # doing completion 
+  STATE_SIGHANDLER* = 0x00008000 # in readline sighandler 
+  STATE_UNDOING* = 0x00010000 # doing an undo 
+  STATE_INPUTPENDING* = 0x00020000 # rl_execute_next called 
+  STATE_TTYCSAVED* = 0x00040000 # tty special chars saved 
+  STATE_CALLBACK* = 0x00080000 # using the callback interface 
+  STATE_VIMOTION* = 0x00100000 # reading vi motion arg 
+  STATE_MULTIKEY* = 0x00200000 # reading multiple-key command 
+  STATE_VICMDONCE* = 0x00400000 # entered vi command mode at least once 
+  STATE_REDISPLAYING* = 0x00800000 # updating terminal display 
+  STATE_DONE* = 0x01000000    # done; accepted line 
+
+template SETSTATE*(x: expr): stmt = 
+  readline_state = readline_state or (x)
+
+template UNSETSTATE*(x: expr): stmt = 
+  readline_state = readline_state and not (x)
+
+template ISSTATE*(x: expr): expr = 
+  (readline_state and x) != 0
+
+type 
+  Treadline_state*{.pure, final.} = object 
+    point*: cint              # line state 
+    theEnd*: cint
+    mark*: cint
+    buffer*: cstring
+    buflen*: cint
+    ul*: ptr TUNDO_LIST
+    prompt*: cstring          # global state 
+    rlstate*: cint
+    done*: cint
+    kmap*: PKeymap            # input state 
+    lastfunc*: TCommandFunc
+    insmode*: cint
+    edmode*: cint
+    kseqlen*: cint
+    inf*: File
+    outf*: File
+    pendingin*: cint
+    theMacro*: cstring        # signal state 
+    catchsigs*: cint
+    catchsigwinch*: cint      # search state 
+                              # completion state 
+                              # options state 
+                              # reserved for future expansion, so the struct size doesn't change 
+    reserved*: array[0..64 - 1, char]
+
+
+proc save_state*(a2: ptr Treadline_state): cint{.cdecl, 
+    importc: "rl_save_state", dynlib: readlineDll.}
+proc restore_state*(a2: ptr Treadline_state): cint{.cdecl, 
+    importc: "rl_restore_state", dynlib: readlineDll.}
diff --git a/lib/wrappers/readline/rltypedefs.nim b/lib/wrappers/readline/rltypedefs.nim
new file mode 100644
index 000000000..847834e80
--- /dev/null
+++ b/lib/wrappers/readline/rltypedefs.nim
@@ -0,0 +1,74 @@
+# rltypedefs.h -- Type declarations for readline functions. 
+# Copyright (C) 2000-2009 Free Software Foundation, Inc.
+#
+#   This file is part of the GNU Readline Library (Readline), a library
+#   for reading lines of text with interactive input and history editing.      
+#
+#   Readline is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   Readline 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 General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+type 
+  TFunction* = proc (): cint{.cdecl.}
+  TVFunction* = proc (){.cdecl.}
+  TCPFunction* = proc (): cstring{.cdecl.}
+  TCPPFunction* = proc (): cstringArray{.cdecl.}
+
+# Bindable functions 
+
+type 
+  Tcommand_func* = proc (a2: cint, a3: cint): cint{.cdecl.}
+
+# Typedefs for the completion system 
+
+type 
+  Tcompentry_func* = proc (a2: cstring, a3: cint): cstring{.cdecl.}
+  Tcompletion_func* = proc (a2: cstring, a3: cint, a4: cint): cstringArray{.
+      cdecl.}
+  Tquote_func* = proc (a2: cstring, a3: cint, a4: cstring): cstring{.cdecl.}
+  Tdequote_func* = proc (a2: cstring, a3: cint): cstring{.cdecl.}
+  Tcompignore_func* = proc (a2: cstringArray): cint{.cdecl.}
+  Tcompdisp_func* = proc (a2: cstringArray, a3: cint, a4: cint){.cdecl.}
+
+# Type for input and pre-read hook functions like rl_event_hook 
+
+type 
+  Thook_func* = proc (): cint{.cdecl.}
+
+# Input function type 
+
+type 
+  Tgetc_func* = proc (a2: File): cint{.cdecl.}
+
+# Generic function that takes a character buffer (which could be the readline
+#   line buffer) and an index into it (which could be rl_point) and returns
+#   an int. 
+
+type 
+  Tlinebuf_func* = proc (a2: cstring, a3: cint): cint{.cdecl.}
+
+# `Generic' function pointer typedefs 
+
+type 
+  Tintfunc* = proc (a2: cint): cint{.cdecl.}
+  Tivoidfunc* = proc (): cint{.cdecl.}
+  Ticpfunc* = proc (a2: cstring): cint{.cdecl.}
+  Ticppfunc* = proc (a2: cstringArray): cint{.cdecl.}
+  Tvoidfunc* = proc (){.cdecl.}
+  Tvintfunc* = proc (a2: cint){.cdecl.}
+  Tvcpfunc* = proc (a2: cstring){.cdecl.}
+  Tvcppfunc* = proc (a2: cstringArray){.cdecl.}
+  Tcpvfunc* = proc (): cstring{.cdecl.}
+  Tcpifunc* = proc (a2: cint): cstring{.cdecl.}
+  Tcpcpfunc* = proc (a2: cstring): cstring{.cdecl.}
+  Tcpcppfunc* = proc (a2: cstringArray): cstring{.cdecl.}
diff --git a/lib/wrappers/readline/tweaked/history.h b/lib/wrappers/readline/tweaked/history.h
new file mode 100644
index 000000000..b79123790
--- /dev/null
+++ b/lib/wrappers/readline/tweaked/history.h
@@ -0,0 +1,257 @@
+/* history.h -- the names of functions that you can call in history. */
+
+/* Copyright (C) 1989-2009 Free Software Foundation, Inc.
+
+   This file contains the GNU History Library (History), a set of
+   routines for managing the text of previously typed lines.
+
+   History is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   History 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with History.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef C2NIM
+#  private historyDll
+#  dynlib historyDll
+#  cdecl
+#  if defined(windows)
+#    define historyDll "history.dll"
+#  elif defined(macosx)
+#    define historyDll "libhistory.dynlib"
+#  else
+#    define historyDll "libhistory.so.6(|.0)"
+#  endif
+#  prefix rl_
+#  prefix RL_
+#  suffix _t
+#  typeprefixes
+#  def PARAMS(x) x
+#  def time_t TTime
+#endif
+
+#  include "times"
+#  include "rltypedefs.h"
+
+typedef void *histdata_t;
+
+/* The structure used to store a history entry. */
+typedef struct _hist_entry {
+  char *line;
+  char *timestamp;		/* char * rather than time_t for read/write */
+  histdata_t data;
+} HIST_ENTRY;
+
+/* Size of the history-library-managed space in history entry HS. */
+#define HISTENT_BYTES(hs)	(strlen(hs.line) + strlen(hs.timestamp))
+
+/* A structure used to pass the current state of the history stuff around. */
+typedef struct _hist_state {
+  HIST_ENTRY **entries;		/* Pointer to the entries themselves. */
+  int offset;			/* The location pointer within this array. */
+  int length;			/* Number of elements within this array. */
+  int size;			/* Number of slots allocated to this array. */
+  int flags;
+} HISTORY_STATE;
+
+/* Flag values for the `flags' member of HISTORY_STATE. */
+#define HS_STIFLED	0x01
+
+/* Initialization and state management. */
+
+/* Begin a session in which the history functions might be used.  This
+   just initializes the interactive variables. */
+extern void using_history PARAMS((void));
+
+/* Return the current HISTORY_STATE of the history. */
+extern HISTORY_STATE *history_get_history_state PARAMS((void));
+
+/* Set the state of the current history array to STATE. */
+extern void history_set_history_state PARAMS((HISTORY_STATE *));
+
+/* Manage the history list. */
+
+/* Place STRING at the end of the history list.
+   The associated data field (if any) is set to NULL. */
+extern void add_history PARAMS((const char *));
+
+/* Change the timestamp associated with the most recent history entry to
+   STRING. */
+extern void add_history_time PARAMS((const char *));
+
+/* A reasonably useless function, only here for completeness.  WHICH
+   is the magic number that tells us which element to delete.  The
+   elements are numbered from 0. */
+extern HIST_ENTRY *remove_history PARAMS((int));
+
+/* Free the history entry H and return any application-specific data
+   associated with it. */
+extern histdata_t free_history_entry PARAMS((HIST_ENTRY *));
+
+/* Make the history entry at WHICH have LINE and DATA.  This returns
+   the old entry so you can dispose of the data.  In the case of an
+   invalid WHICH, a NULL pointer is returned. */
+extern HIST_ENTRY *replace_history_entry PARAMS((int, const char *, histdata_t));
+
+/* Clear the history list and start over. */
+extern void clear_history PARAMS((void));
+
+/* Stifle the history list, remembering only MAX number of entries. */
+extern void stifle_history PARAMS((int));
+
+/* Stop stifling the history.  This returns the previous amount the
+   history was stifled by.  The value is positive if the history was
+   stifled, negative if it wasn't. */
+extern int unstifle_history PARAMS((void));
+
+/* Return 1 if the history is stifled, 0 if it is not. */
+extern int history_is_stifled PARAMS((void));
+
+/* Information about the history list. */
+
+/* Return a NULL terminated array of HIST_ENTRY which is the current input
+   history.  Element 0 of this list is the beginning of time.  If there
+   is no history, return NULL. */
+extern HIST_ENTRY **history_list PARAMS((void));
+
+/* Returns the number which says what history element we are now
+   looking at.  */
+extern int where_history PARAMS((void));
+  
+/* Return the history entry at the current position, as determined by
+   history_offset.  If there is no entry there, return a NULL pointer. */
+extern HIST_ENTRY *current_history PARAMS((void));
+
+/* Return the history entry which is logically at OFFSET in the history
+   array.  OFFSET is relative to history_base. */
+extern HIST_ENTRY *history_get PARAMS((int));
+
+/* Return the timestamp associated with the HIST_ENTRY * passed as an
+   argument */
+extern time_t history_get_time PARAMS((HIST_ENTRY *));
+
+/* Return the number of bytes that the primary history entries are using.
+   This just adds up the lengths of the_history->lines. */
+extern int history_total_bytes PARAMS((void));
+
+/* Moving around the history list. */
+
+/* Set the position in the history list to POS. */
+extern int history_set_pos PARAMS((int));
+
+/* Back up history_offset to the previous history entry, and return
+   a pointer to that entry.  If there is no previous entry, return
+   a NULL pointer. */
+extern HIST_ENTRY *previous_history PARAMS((void));
+
+/* Move history_offset forward to the next item in the input_history,
+   and return the a pointer to that entry.  If there is no next entry,
+   return a NULL pointer. */
+extern HIST_ENTRY *next_history PARAMS((void));
+
+/* Searching the history list. */
+
+/* Search the history for STRING, starting at history_offset.
+   If DIRECTION < 0, then the search is through previous entries,
+   else through subsequent.  If the string is found, then
+   current_history () is the history entry, and the value of this function
+   is the offset in the line of that history entry that the string was
+   found in.  Otherwise, nothing is changed, and a -1 is returned. */
+extern int history_search PARAMS((const char *, int));
+
+/* Search the history for STRING, starting at history_offset.
+   The search is anchored: matching lines must begin with string.
+   DIRECTION is as in history_search(). */
+extern int history_search_prefix PARAMS((const char *, int));
+
+/* Search for STRING in the history list, starting at POS, an
+   absolute index into the list.  DIR, if negative, says to search
+   backwards from POS, else forwards.
+   Returns the absolute index of the history element where STRING
+   was found, or -1 otherwise. */
+extern int history_search_pos PARAMS((const char *, int, int));
+
+/* Managing the history file. */
+
+/* Add the contents of FILENAME to the history list, a line at a time.
+   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
+   successful, or errno if not. */
+extern int read_history PARAMS((const char *));
+
+/* Read a range of lines from FILENAME, adding them to the history list.
+   Start reading at the FROM'th line and end at the TO'th.  If FROM
+   is zero, start at the beginning.  If TO is less than FROM, read
+   until the end of the file.  If FILENAME is NULL, then read from
+   ~/.history.  Returns 0 if successful, or errno if not. */
+extern int read_history_range PARAMS((const char *, int, int));
+
+/* Write the current history to FILENAME.  If FILENAME is NULL,
+   then write the history list to ~/.history.  Values returned
+   are as in read_history ().  */
+extern int write_history PARAMS((const char *));
+
+/* Append NELEMENT entries to FILENAME.  The entries appended are from
+   the end of the list minus NELEMENTs up to the end of the list. */
+extern int append_history PARAMS((int, const char *));
+
+/* Truncate the history file, leaving only the last NLINES lines. */
+extern int history_truncate_file PARAMS((const char *, int));
+
+/* History expansion. */
+
+/* Expand the string STRING, placing the result into OUTPUT, a pointer
+   to a string.  Returns:
+
+   0) If no expansions took place (or, if the only change in
+      the text was the de-slashifying of the history expansion
+      character)
+   1) If expansions did take place
+  -1) If there was an error in expansion.
+   2) If the returned line should just be printed.
+
+  If an error occurred in expansion, then OUTPUT contains a descriptive
+  error message. */
+extern int history_expand PARAMS((char *, char **));
+
+/* Extract a string segment consisting of the FIRST through LAST
+   arguments present in STRING.  Arguments are broken up as in
+   the shell. */
+extern char *history_arg_extract PARAMS((int, int, const char *));
+
+/* Return the text of the history event beginning at the current
+   offset into STRING.  Pass STRING with *INDEX equal to the
+   history_expansion_char that begins this specification.
+   DELIMITING_QUOTE is a character that is allowed to end the string
+   specification for what to search for in addition to the normal
+   characters `:', ` ', `\t', `\n', and sometimes `?'. */
+extern char *get_history_event PARAMS((const char *, int *, int));
+
+/* Return an array of tokens, much as the shell might.  The tokens are
+   parsed out of STRING. */
+extern char **history_tokenize PARAMS((const char *));
+
+#if false
+/* Exported history variables. */
+extern int history_base;
+extern int history_length;
+extern int history_max_entries;
+extern char history_expansion_char;
+extern char history_subst_char;
+extern char *history_word_delimiters;
+extern char history_comment_char;
+extern char *history_no_expand_chars;
+extern char *history_search_delimiter_chars;
+extern int history_quotes_inhibit_expansion;
+
+extern int history_write_timestamps;
+
+#endif
+
diff --git a/lib/wrappers/readline/tweaked/readline.h b/lib/wrappers/readline/tweaked/readline.h
new file mode 100644
index 000000000..b13fbdbbe
--- /dev/null
+++ b/lib/wrappers/readline/tweaked/readline.h
@@ -0,0 +1,956 @@
+/* Readline.h -- the names of functions callable from within readline. */
+
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library (Readline), a library
+   for reading lines of text with interactive input and history editing.      
+
+   Readline is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   Readline 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef C2NIM
+#  private readlineDll
+#  dynlib readlineDll
+#  cdecl
+#  if defined(windows)
+#    define readlineDll "readline.dll"
+#  elif defined(macosx)
+#    define readlineDll "libreadline.dynlib"
+#  else
+#    define readlineDll "libreadline.so.6(|.0)"
+#  endif
+#  prefix rl_
+#  prefix RL_
+#  suffix _t
+#  typeprefixes
+#  def PARAMS(x) x
+#  mangle end theEnd
+#  mangle type typ
+#  mangle macro theMacro
+/*#  mangle "'command_func'" TCommandFunc
+#  mangle vcpfunc TvcpFunc*/
+#endif
+
+#  include "rltypedefs.h"
+
+
+/* Some character stuff. */
+#define control_character_threshold 0x020   /* Smaller than this is control. */
+#define control_character_mask 0x1f	    /* 0x20 - 1 */
+#define meta_character_threshold 0x07f	    /* Larger than this is Meta. */
+#define control_character_bit 0x40	    /* 0x000000, must be off. */
+#define meta_character_bit 0x080	    /* x0000000, must be on. */
+#define largest_char 255		    /* Largest character value. */
+
+#define CTRL_CHAR(c) (c < control_character_threshold && ((c & 0x80) == 0))
+#define META_CHAR(c) (c > meta_character_threshold && c <= largest_char)
+
+#define CTRL(c) (c & control_character_mask)
+#define META(c) (c | meta_character_bit)
+
+#define UNMETA(c) (c & ~meta_character_bit)
+#define UNCTRL(c) (c|32|control_character_bit)
+
+/* Beware:  these only work with single-byte ASCII characters. */
+
+#define RETURN_CHAR CTRL('M'.ord)
+#define RUBOUT_CHAR 0x7f
+#define ABORT_CHAR CTRL('G'.ord)
+#define PAGE_CHAR CTRL('L'.ord)
+#define ESC_CHAR CTRL('['.ord)
+
+/* A keymap contains one entry for each key in the ASCII set.
+   Each entry consists of a type and a pointer.
+   FUNCTION is the address of a function to run, or the
+   address of a keymap to indirect through.
+   TYPE says which kind of thing FUNCTION is. */
+typedef struct _keymap_entry {
+  char type;
+  rl_command_func_t *function;
+} KEYMAP_ENTRY;
+
+/* This must be large enough to hold bindings for all of the characters
+   in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x,
+   and so on) plus one for subsequence matching. */
+#define KEYMAP_SIZE 257
+#define ANYOTHERKEY KEYMAP_SIZE-1
+
+/* I wanted to make the above structure contain a union of:
+   union { rl_command_func_t *function; struct _keymap_entry *keymap; } value;
+   but this made it impossible for me to create a static array.
+   Maybe I need C lessons. */
+
+typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE];
+typedef KEYMAP_ENTRY *Keymap;
+
+/* The values that TYPE can have in a keymap entry. */
+#define ISFUNC 0
+#define ISKMAP 1
+#define ISMACR 2
+
+#if false
+extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, emacs_meta_keymap, emacs_ctlx_keymap;
+extern KEYMAP_ENTRY_ARRAY vi_insertion_keymap, vi_movement_keymap;
+#endif
+
+/* Return a new, empty keymap.
+   Free it with free() when you are done. */
+extern Keymap rl_make_bare_keymap PARAMS((void));
+
+/* Return a new keymap which is a copy of MAP. */
+extern Keymap rl_copy_keymap PARAMS((Keymap));
+
+/* Return a new keymap with the printing characters bound to rl_insert,
+   the lowercase Meta characters bound to run their equivalents, and
+   the Meta digits bound to produce numeric arguments. */
+extern Keymap rl_make_keymap PARAMS((void));
+
+/* Free the storage associated with a keymap. */
+extern void rl_discard_keymap PARAMS((Keymap));
+
+/* These functions actually appear in bind.c */
+
+/* Return the keymap corresponding to a given name.  Names look like
+   `emacs' or `emacs-meta' or `vi-insert'.  */
+extern Keymap rl_get_keymap_by_name PARAMS((const char *));
+
+/* Return the current keymap. */
+extern Keymap rl_get_keymap PARAMS((void));
+
+/* Set the current keymap to MAP. */
+extern void rl_set_keymap PARAMS((Keymap));
+
+#  include "tilde.h"
+
+/* Hex-encoded Readline version number. */
+#define RL_READLINE_VERSION	0x0600		/* Readline 6.0 */
+#define RL_VERSION_MAJOR	6
+#define RL_VERSION_MINOR	0
+
+/* Readline data structures. */
+
+/* Maintaining the state of undo.  We remember individual deletes and inserts
+   on a chain of things to do. */
+
+/* The actions that undo knows how to undo.  Notice that UNDO_DELETE means
+   to insert some text, and UNDO_INSERT means to delete some text.   I.e.,
+   the code tells undo what to undo, not how to undo it. */
+enum undo_code { UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END };
+
+/* What an element of THE_UNDO_LIST looks like. */
+typedef struct undo_list {
+  struct undo_list *next;
+  int start, end;		/* Where the change took place. */
+  char *text;			/* The text to insert, if undoing a delete. */
+  enum undo_code what;		/* Delete, Insert, Begin, End. */
+} UNDO_LIST;
+
+/* The current undo list for RL_LINE_BUFFER. */
+extern UNDO_LIST *rl_undo_list;
+
+/* The data structure for mapping textual names to code addresses. */
+typedef struct _funmap {
+  const char *name;
+  rl_command_func_t *function;
+} FUNMAP;
+
+extern FUNMAP **funmap;
+
+/* **************************************************************** */
+/*								    */
+/*	     Functions available to bind to key sequences	    */
+/*								    */
+/* **************************************************************** */
+
+/* Bindable commands for numeric arguments. */
+extern int rl_digit_argument PARAMS((int, int));
+extern int rl_universal_argument PARAMS((int, int));
+
+/* Bindable commands for moving the cursor. */
+extern int rl_forward_byte PARAMS((int, int));
+extern int rl_forward_char PARAMS((int, int));
+extern int rl_forward PARAMS((int, int));
+extern int rl_backward_byte PARAMS((int, int));
+extern int rl_backward_char PARAMS((int, int));
+extern int rl_backward PARAMS((int, int));
+extern int rl_beg_of_line PARAMS((int, int));
+extern int rl_end_of_line PARAMS((int, int));
+extern int rl_forward_word PARAMS((int, int));
+extern int rl_backward_word PARAMS((int, int));
+extern int rl_refresh_line PARAMS((int, int));
+extern int rl_clear_screen PARAMS((int, int));
+extern int rl_skip_csi_sequence PARAMS((int, int));
+extern int rl_arrow_keys PARAMS((int, int));
+
+/* Bindable commands for inserting and deleting text. */
+extern int rl_insert PARAMS((int, int));
+extern int rl_quoted_insert PARAMS((int, int));
+extern int rl_tab_insert PARAMS((int, int));
+extern int rl_newline PARAMS((int, int));
+extern int rl_do_lowercase_version PARAMS((int, int));
+extern int rl_rubout PARAMS((int, int));
+extern int rl_delete PARAMS((int, int));
+extern int rl_rubout_or_delete PARAMS((int, int));
+extern int rl_delete_horizontal_space PARAMS((int, int));
+extern int rl_delete_or_show_completions PARAMS((int, int));
+extern int rl_insert_comment PARAMS((int, int));
+
+/* Bindable commands for changing case. */
+extern int rl_upcase_word PARAMS((int, int));
+extern int rl_downcase_word PARAMS((int, int));
+extern int rl_capitalize_word PARAMS((int, int));
+
+/* Bindable commands for transposing characters and words. */
+extern int rl_transpose_words PARAMS((int, int));
+extern int rl_transpose_chars PARAMS((int, int));
+
+/* Bindable commands for searching within a line. */
+extern int rl_char_search PARAMS((int, int));
+extern int rl_backward_char_search PARAMS((int, int));
+
+/* Bindable commands for readline's interface to the command history. */
+extern int rl_beginning_of_history PARAMS((int, int));
+extern int rl_end_of_history PARAMS((int, int));
+extern int rl_get_next_history PARAMS((int, int));
+extern int rl_get_previous_history PARAMS((int, int));
+
+/* Bindable commands for managing the mark and region. */
+extern int rl_set_mark PARAMS((int, int));
+extern int rl_exchange_point_and_mark PARAMS((int, int));
+
+/* Bindable commands to set the editing mode (emacs or vi). */
+extern int rl_vi_editing_mode PARAMS((int, int));
+extern int rl_emacs_editing_mode PARAMS((int, int));
+
+/* Bindable commands to change the insert mode (insert or overwrite) */
+extern int rl_overwrite_mode PARAMS((int, int));
+
+/* Bindable commands for managing key bindings. */
+extern int rl_re_read_init_file PARAMS((int, int));
+extern int rl_dump_functions PARAMS((int, int));
+extern int rl_dump_macros PARAMS((int, int));
+extern int rl_dump_variables PARAMS((int, int));
+
+/* Bindable commands for word completion. */
+extern int rl_complete PARAMS((int, int));
+extern int rl_possible_completions PARAMS((int, int));
+extern int rl_insert_completions PARAMS((int, int));
+extern int rl_old_menu_complete PARAMS((int, int));
+extern int rl_menu_complete PARAMS((int, int));
+extern int rl_backward_menu_complete PARAMS((int, int));
+
+/* Bindable commands for killing and yanking text, and managing the kill ring. */
+extern int rl_kill_word PARAMS((int, int));
+extern int rl_backward_kill_word PARAMS((int, int));
+extern int rl_kill_line PARAMS((int, int));
+extern int rl_backward_kill_line PARAMS((int, int));
+extern int rl_kill_full_line PARAMS((int, int));
+extern int rl_unix_word_rubout PARAMS((int, int));
+extern int rl_unix_filename_rubout PARAMS((int, int));
+extern int rl_unix_line_discard PARAMS((int, int));
+extern int rl_copy_region_to_kill PARAMS((int, int));
+extern int rl_kill_region PARAMS((int, int));
+extern int rl_copy_forward_word PARAMS((int, int));
+extern int rl_copy_backward_word PARAMS((int, int));
+extern int rl_yank PARAMS((int, int));
+extern int rl_yank_pop PARAMS((int, int));
+extern int rl_yank_nth_arg PARAMS((int, int));
+extern int rl_yank_last_arg PARAMS((int, int));
+
+#ifdef Windows
+extern int rl_paste_from_clipboard PARAMS((int, int));
+#endif
+
+/* Bindable commands for incremental searching. */
+extern int rl_reverse_search_history PARAMS((int, int));
+extern int rl_forward_search_history PARAMS((int, int));
+
+/* Bindable keyboard macro commands. */
+extern int rl_start_kbd_macro PARAMS((int, int));
+extern int rl_end_kbd_macro PARAMS((int, int));
+extern int rl_call_last_kbd_macro PARAMS((int, int));
+
+/* Bindable undo commands. */
+extern int rl_revert_line PARAMS((int, int));
+extern int rl_undo_command PARAMS((int, int));
+
+/* Bindable tilde expansion commands. */
+extern int rl_tilde_expand PARAMS((int, int));
+
+/* Bindable terminal control commands. */
+extern int rl_restart_output PARAMS((int, int));
+extern int rl_stop_output PARAMS((int, int));
+
+/* Miscellaneous bindable commands. */
+extern int rl_abort PARAMS((int, int));
+extern int rl_tty_status PARAMS((int, int));
+
+/* Bindable commands for incremental and non-incremental history searching. */
+extern int rl_history_search_forward PARAMS((int, int));
+extern int rl_history_search_backward PARAMS((int, int));
+extern int rl_noninc_forward_search PARAMS((int, int));
+extern int rl_noninc_reverse_search PARAMS((int, int));
+extern int rl_noninc_forward_search_again PARAMS((int, int));
+extern int rl_noninc_reverse_search_again PARAMS((int, int));
+
+/* Bindable command used when inserting a matching close character. */
+extern int rl_insert_close PARAMS((int, int));
+
+/* Not available unless READLINE_CALLBACKS is defined. */
+extern void rl_callback_handler_install PARAMS((const char *, rl_vcpfunc_t *));
+extern void rl_callback_read_char PARAMS((void));
+extern void rl_callback_handler_remove PARAMS((void));
+
+/* Things for vi mode. Not available unless readline is compiled -DVI_MODE. */
+/* VI-mode bindable commands. */
+extern int rl_vi_redo PARAMS((int, int));
+extern int rl_vi_undo PARAMS((int, int));
+extern int rl_vi_yank_arg PARAMS((int, int));
+extern int rl_vi_fetch_history PARAMS((int, int));
+extern int rl_vi_search_again PARAMS((int, int));
+extern int rl_vi_search PARAMS((int, int));
+extern int rl_vi_complete PARAMS((int, int));
+extern int rl_vi_tilde_expand PARAMS((int, int));
+extern int rl_vi_prev_word PARAMS((int, int));
+extern int rl_vi_next_word PARAMS((int, int));
+extern int rl_vi_end_word PARAMS((int, int));
+extern int rl_vi_insert_beg PARAMS((int, int));
+extern int rl_vi_append_mode PARAMS((int, int));
+extern int rl_vi_append_eol PARAMS((int, int));
+extern int rl_vi_eof_maybe PARAMS((int, int));
+extern int rl_vi_insertion_mode PARAMS((int, int));
+extern int rl_vi_insert_mode PARAMS((int, int));
+extern int rl_vi_movement_mode PARAMS((int, int));
+extern int rl_vi_arg_digit PARAMS((int, int));
+extern int rl_vi_change_case PARAMS((int, int));
+extern int rl_vi_put PARAMS((int, int));
+extern int rl_vi_column PARAMS((int, int));
+extern int rl_vi_delete_to PARAMS((int, int));
+extern int rl_vi_change_to PARAMS((int, int));
+extern int rl_vi_yank_to PARAMS((int, int));
+extern int rl_vi_rubout PARAMS((int, int));
+extern int rl_vi_delete PARAMS((int, int));
+extern int rl_vi_back_to_indent PARAMS((int, int));
+extern int rl_vi_first_print PARAMS((int, int));
+extern int rl_vi_char_search PARAMS((int, int));
+extern int rl_vi_match PARAMS((int, int));
+extern int rl_vi_change_char PARAMS((int, int));
+extern int rl_vi_subst PARAMS((int, int));
+extern int rl_vi_overstrike PARAMS((int, int));
+extern int rl_vi_overstrike_delete PARAMS((int, int));
+extern int rl_vi_replace PARAMS((int, int));
+extern int rl_vi_set_mark PARAMS((int, int));
+extern int rl_vi_goto_mark PARAMS((int, int));
+
+/* VI-mode utility functions. */
+extern int rl_vi_check PARAMS((void));
+extern int rl_vi_domove PARAMS((int, int *));
+extern int rl_vi_bracktype PARAMS((int));
+
+extern void rl_vi_start_inserting PARAMS((int, int, int));
+
+/* VI-mode pseudo-bindable commands, used as utility functions. */
+extern int rl_vi_fWord PARAMS((int, int));
+extern int rl_vi_bWord PARAMS((int, int));
+extern int rl_vi_eWord PARAMS((int, int));
+extern int rl_vi_fword PARAMS((int, int));
+extern int rl_vi_bword PARAMS((int, int));
+extern int rl_vi_eword PARAMS((int, int));
+
+/* **************************************************************** */
+/*								    */
+/*			Well Published Functions		    */
+/*								    */
+/* **************************************************************** */
+
+/* Readline functions. */
+/* Read a line of input.  Prompt with PROMPT.  A NULL PROMPT means none. */
+extern char *readline PARAMS((const char *));
+
+extern int rl_set_prompt PARAMS((const char *));
+extern int rl_expand_prompt PARAMS((char *));
+
+extern int rl_initialize PARAMS((void));
+
+/* Undocumented; unused by readline */
+extern int rl_discard_argument PARAMS((void));
+
+/* Utility functions to bind keys to readline commands. */
+extern int rl_add_defun PARAMS((const char *, rl_command_func_t *, int));
+extern int rl_bind_key PARAMS((int, rl_command_func_t *));
+extern int rl_bind_key_in_map PARAMS((int, rl_command_func_t *, Keymap));
+extern int rl_unbind_key PARAMS((int));
+extern int rl_unbind_key_in_map PARAMS((int, Keymap));
+extern int rl_bind_key_if_unbound PARAMS((int, rl_command_func_t *));
+extern int rl_bind_key_if_unbound_in_map PARAMS((int, rl_command_func_t *, Keymap));
+extern int rl_unbind_function_in_map PARAMS((rl_command_func_t *, Keymap));
+extern int rl_unbind_command_in_map PARAMS((const char *, Keymap));
+extern int rl_bind_keyseq PARAMS((const char *, rl_command_func_t *));
+extern int rl_bind_keyseq_in_map PARAMS((const char *, rl_command_func_t *, Keymap));
+extern int rl_bind_keyseq_if_unbound PARAMS((const char *, rl_command_func_t *));
+extern int rl_bind_keyseq_if_unbound_in_map PARAMS((const char *, rl_command_func_t *, Keymap));
+extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap));
+
+extern char *rl_variable_value PARAMS((const char *));
+extern int rl_variable_bind PARAMS((const char *, const char *));
+
+/* Backwards compatibility, use rl_bind_keyseq_in_map instead. */
+extern int rl_set_key PARAMS((const char *, rl_command_func_t *, Keymap));
+
+/* Backwards compatibility, use rl_generic_bind instead. */
+extern int rl_macro_bind PARAMS((const char *, const char *, Keymap));
+
+/* Undocumented in the texinfo manual; not really useful to programs. */
+extern int rl_translate_keyseq PARAMS((const char *, char *, int *));
+extern char *rl_untranslate_keyseq PARAMS((int));
+
+extern rl_command_func_t *rl_named_function PARAMS((const char *));
+extern rl_command_func_t *rl_function_of_keyseq PARAMS((const char *, Keymap, int *));
+
+extern void rl_list_funmap_names PARAMS((void));
+extern char **rl_invoking_keyseqs_in_map PARAMS((rl_command_func_t *, Keymap));
+extern char **rl_invoking_keyseqs PARAMS((rl_command_func_t *));
+ 
+extern void rl_function_dumper PARAMS((int));
+extern void rl_macro_dumper PARAMS((int));
+extern void rl_variable_dumper PARAMS((int));
+
+extern int rl_read_init_file PARAMS((const char *));
+extern int rl_parse_and_bind PARAMS((char *));
+
+/* Functions for manipulating keymaps. */
+extern Keymap rl_make_bare_keymap PARAMS((void));
+extern Keymap rl_copy_keymap PARAMS((Keymap));
+extern Keymap rl_make_keymap PARAMS((void));
+extern void rl_discard_keymap PARAMS((Keymap));
+
+extern Keymap rl_get_keymap_by_name PARAMS((const char *));
+extern char *rl_get_keymap_name PARAMS((Keymap));
+extern void rl_set_keymap PARAMS((Keymap));
+extern Keymap rl_get_keymap PARAMS((void));
+/* Undocumented; used internally only. */
+extern void rl_set_keymap_from_edit_mode PARAMS((void));
+extern char *rl_get_keymap_name_from_edit_mode PARAMS((void));
+
+/* Functions for manipulating the funmap, which maps command names to functions. */
+extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *));
+extern const char **rl_funmap_names PARAMS((void));
+/* Undocumented, only used internally -- there is only one funmap, and this
+   function may be called only once. */
+extern void rl_initialize_funmap PARAMS((void));
+
+/* Utility functions for managing keyboard macros. */
+extern void rl_push_macro_input PARAMS((char *));
+
+/* Functions for undoing, from undo.c */
+extern void rl_add_undo PARAMS((enum undo_code, int, int, char *));
+extern void rl_free_undo_list PARAMS((void));
+extern int rl_do_undo PARAMS((void));
+extern int rl_begin_undo_group PARAMS((void));
+extern int rl_end_undo_group PARAMS((void));
+extern int rl_modifying PARAMS((int, int));
+
+/* Functions for redisplay. */
+extern void rl_redisplay PARAMS((void));
+extern int rl_on_new_line PARAMS((void));
+extern int rl_on_new_line_with_prompt PARAMS((void));
+extern int rl_forced_update_display PARAMS((void));
+extern int rl_clear_message PARAMS((void));
+extern int rl_reset_line_state PARAMS((void));
+extern int rl_crlf PARAMS((void));
+
+extern int rl_message (const char *, ...);
+
+extern int rl_show_char PARAMS((int));
+
+/* Undocumented in texinfo manual. */
+extern int rl_character_len PARAMS((int, int));
+
+/* Save and restore internal prompt redisplay information. */
+extern void rl_save_prompt PARAMS((void));
+extern void rl_restore_prompt PARAMS((void));
+
+/* Modifying text. */
+extern void rl_replace_line PARAMS((const char *, int));
+extern int rl_insert_text PARAMS((const char *));
+extern int rl_delete_text PARAMS((int, int));
+extern int rl_kill_text PARAMS((int, int));
+extern char *rl_copy_text PARAMS((int, int));
+
+/* Terminal and tty mode management. */
+extern void rl_prep_terminal PARAMS((int));
+extern void rl_deprep_terminal PARAMS((void));
+extern void rl_tty_set_default_bindings PARAMS((Keymap));
+extern void rl_tty_unset_default_bindings PARAMS((Keymap));
+
+extern int rl_reset_terminal PARAMS((const char *));
+extern void rl_resize_terminal PARAMS((void));
+extern void rl_set_screen_size PARAMS((int, int));
+extern void rl_get_screen_size PARAMS((int *, int *));
+extern void rl_reset_screen_size PARAMS((void));
+
+extern char *rl_get_termcap PARAMS((const char *));
+
+/* Functions for character input. */
+extern int rl_stuff_char PARAMS((int));
+extern int rl_execute_next PARAMS((int));
+extern int rl_clear_pending_input PARAMS((void));
+extern int rl_read_key PARAMS((void));
+extern int rl_getc PARAMS((TFile));
+extern int rl_set_keyboard_input_timeout PARAMS((int));
+
+/* `Public' utility functions . */
+extern void rl_extend_line_buffer PARAMS((int));
+extern int rl_ding PARAMS((void));
+extern int rl_alphabetic PARAMS((int));
+extern void rl_free PARAMS((void *));
+
+/* Readline signal handling, from signals.c */
+extern int rl_set_signals PARAMS((void));
+extern int rl_clear_signals PARAMS((void));
+extern void rl_cleanup_after_signal PARAMS((void));
+extern void rl_reset_after_signal PARAMS((void));
+extern void rl_free_line_state PARAMS((void));
+
+extern void rl_echo_signal_char PARAMS((int)); 
+
+extern int rl_set_paren_blink_timeout PARAMS((int));
+
+/* Undocumented. */
+extern int rl_maybe_save_line PARAMS((void));
+extern int rl_maybe_unsave_line PARAMS((void));
+extern int rl_maybe_replace_line PARAMS((void));
+
+/* Completion functions. */
+extern int rl_complete_internal PARAMS((int));
+extern void rl_display_match_list PARAMS((char **, int, int));
+
+extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *));
+extern char *rl_username_completion_function PARAMS((const char *, int));
+extern char *rl_filename_completion_function PARAMS((const char *, int));
+
+extern int rl_completion_mode PARAMS((rl_command_func_t *));
+
+/* **************************************************************** */
+/*								    */
+/*			Well Published Variables		    */
+/*								    */
+/* **************************************************************** */
+
+#if false
+
+/* The version of this incarnation of the readline library. */
+extern const char *rl_library_version;		/* e.g., "4.2" */
+extern int rl_readline_version;			/* e.g., 0x0402 */
+
+/* True if this is real GNU readline. */
+extern int rl_gnu_readline_p;
+
+/* Flags word encapsulating the current readline state. */
+extern int rl_readline_state;
+
+/* Says which editing mode readline is currently using.  1 means emacs mode;
+   0 means vi mode. */
+extern int rl_editing_mode;
+
+/* Insert or overwrite mode for emacs mode.  1 means insert mode; 0 means
+   overwrite mode.  Reset to insert mode on each input line. */
+extern int rl_insert_mode;
+
+/* The name of the calling program.  You should initialize this to
+   whatever was in argv[0].  It is used when parsing conditionals. */
+extern const char *rl_readline_name;
+
+/* The prompt readline uses.  This is set from the argument to
+   readline (), and should not be assigned to directly. */
+extern char *rl_prompt;
+
+/* The prompt string that is actually displayed by rl_redisplay.  Public so
+   applications can more easily supply their own redisplay functions. */
+extern char *rl_display_prompt;
+
+/* The line buffer that is in use. */
+extern char *rl_line_buffer;
+
+/* The location of point, and end. */
+extern int rl_point;
+extern int rl_end;
+
+/* The mark, or saved cursor position. */
+extern int rl_mark;
+
+/* Flag to indicate that readline has finished with the current input
+   line and should return it. */
+extern int rl_done;
+
+/* If set to a character value, that will be the next keystroke read. */
+extern int rl_pending_input;
+
+/* Non-zero if we called this function from _rl_dispatch().  It's present
+   so functions can find out whether they were called from a key binding
+   or directly from an application. */
+extern int rl_dispatching;
+
+/* Non-zero if the user typed a numeric argument before executing the
+   current function. */
+extern int rl_explicit_arg;
+
+/* The current value of the numeric argument specified by the user. */
+extern int rl_numeric_arg;
+
+/* The address of the last command function Readline executed. */
+extern rl_command_func_t *rl_last_func;
+
+/* The name of the terminal to use. */
+extern const char *rl_terminal_name;
+
+/* The input and output streams. */
+extern FILE *rl_instream;
+extern FILE *rl_outstream;
+
+/* If non-zero, Readline gives values of LINES and COLUMNS from the environment
+   greater precedence than values fetched from the kernel when computing the
+   screen dimensions. */
+extern int rl_prefer_env_winsize;
+
+/* If non-zero, then this is the address of a function to call just
+   before readline_internal () prints the first prompt. */
+extern rl_hook_func_t *rl_startup_hook;
+
+/* If non-zero, this is the address of a function to call just before
+   readline_internal_setup () returns and readline_internal starts
+   reading input characters. */
+extern rl_hook_func_t *rl_pre_input_hook;
+      
+/* The address of a function to call periodically while Readline is
+   awaiting character input, or NULL, for no event handling. */
+extern rl_hook_func_t *rl_event_hook;
+
+/* The address of the function to call to fetch a character from the current
+   Readline input stream */
+extern rl_getc_func_t *rl_getc_function;
+
+extern rl_voidfunc_t *rl_redisplay_function;
+
+extern rl_vintfunc_t *rl_prep_term_function;
+extern rl_voidfunc_t *rl_deprep_term_function;
+
+/* Dispatch variables. */
+extern Keymap rl_executing_keymap;
+extern Keymap rl_binding_keymap;
+
+/* Display variables. */
+/* If non-zero, readline will erase the entire line, including any prompt,
+   if the only thing typed on an otherwise-blank line is something bound to
+   rl_newline. */
+extern int rl_erase_empty_line;
+
+/* If non-zero, the application has already printed the prompt (rl_prompt)
+   before calling readline, so readline should not output it the first time
+   redisplay is done. */
+extern int rl_already_prompted;
+
+/* A non-zero value means to read only this many characters rather than
+   up to a character bound to accept-line. */
+extern int rl_num_chars_to_read;
+
+/* The text of a currently-executing keyboard macro. */
+extern char *rl_executing_macro;
+
+/* Variables to control readline signal handling. */
+/* If non-zero, readline will install its own signal handlers for
+   SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
+extern int rl_catch_signals;
+
+/* If non-zero, readline will install a signal handler for SIGWINCH
+   that also attempts to call any calling application's SIGWINCH signal
+   handler.  Note that the terminal is not cleaned up before the
+   application's signal handler is called; use rl_cleanup_after_signal()
+   to do that. */
+extern int rl_catch_sigwinch;
+
+/* Completion variables. */
+/* Pointer to the generator function for completion_matches ().
+   NULL means to use rl_filename_completion_function (), the default
+   filename completer. */
+extern rl_compentry_func_t *rl_completion_entry_function;
+
+/* Optional generator for menu completion.  Default is
+   rl_completion_entry_function (rl_filename_completion_function). */
+ extern rl_compentry_func_t *rl_menu_completion_entry_function;
+
+/* If rl_ignore_some_completions_function is non-NULL it is the address
+   of a function to call after all of the possible matches have been
+   generated, but before the actual completion is done to the input line.
+   The function is called with one argument; a NULL terminated array
+   of (char *).  If your function removes any of the elements, they
+   must be free()'ed. */
+extern rl_compignore_func_t *rl_ignore_some_completions_function;
+
+/* Pointer to alternative function to create matches.
+   Function is called with TEXT, START, and END.
+   START and END are indices in RL_LINE_BUFFER saying what the boundaries
+   of TEXT are.
+   If this function exists and returns NULL then call the value of
+   rl_completion_entry_function to try to match, otherwise use the
+   array of strings returned. */
+extern rl_completion_func_t *rl_attempted_completion_function;
+
+/* The basic list of characters that signal a break between words for the
+   completer routine.  The initial contents of this variable is what
+   breaks words in the shell, i.e. "n\"\\'`@$>". */
+extern const char *rl_basic_word_break_characters;
+
+/* The list of characters that signal a break between words for
+   rl_complete_internal.  The default list is the contents of
+   rl_basic_word_break_characters.  */
+extern /*const*/ char *rl_completer_word_break_characters;
+
+/* Hook function to allow an application to set the completion word
+   break characters before readline breaks up the line.  Allows
+   position-dependent word break characters. */
+extern rl_cpvfunc_t *rl_completion_word_break_hook;
+
+/* List of characters which can be used to quote a substring of the line.
+   Completion occurs on the entire substring, and within the substring   
+   rl_completer_word_break_characters are treated as any other character,
+   unless they also appear within this list. */
+extern const char *rl_completer_quote_characters;
+
+/* List of quote characters which cause a word break. */
+extern const char *rl_basic_quote_characters;
+
+/* List of characters that need to be quoted in filenames by the completer. */
+extern const char *rl_filename_quote_characters;
+
+/* List of characters that are word break characters, but should be left
+   in TEXT when it is passed to the completion function.  The shell uses
+   this to help determine what kind of completing to do. */
+extern const char *rl_special_prefixes;
+
+/* If non-zero, then this is the address of a function to call when
+   completing on a directory name.  The function is called with
+   the address of a string (the current directory name) as an arg.  It
+   changes what is displayed when the possible completions are printed
+   or inserted. */
+extern rl_icppfunc_t *rl_directory_completion_hook;
+
+/* If non-zero, this is the address of a function to call when completing
+   a directory name.  This function takes the address of the directory name
+   to be modified as an argument.  Unlike rl_directory_completion_hook, it
+   only modifies the directory name used in opendir(2), not what is displayed
+   when the possible completions are printed or inserted.  It is called
+   before rl_directory_completion_hook.  I'm not happy with how this works
+   yet, so it's undocumented. */
+extern rl_icppfunc_t *rl_directory_rewrite_hook;
+
+/* If non-zero, this is the address of a function to call when reading
+   directory entries from the filesystem for completion and comparing
+   them to the partial word to be completed.  The function should
+   either return its first argument (if no conversion takes place) or
+   newly-allocated memory.  This can, for instance, convert filenames
+   between character sets for comparison against what's typed at the
+   keyboard.  The returned value is what is added to the list of
+   matches.  The second argument is the length of the filename to be
+   converted. */
+extern rl_dequote_func_t *rl_filename_rewrite_hook;
+
+/* If non-zero, then this is the address of a function to call when
+   completing a word would normally display the list of possible matches.
+   This function is called instead of actually doing the display.
+   It takes three arguments: (char **matches, int num_matches, int max_length)
+   where MATCHES is the array of strings that matched, NUM_MATCHES is the
+   number of strings in that array, and MAX_LENGTH is the length of the
+   longest string in that array. */
+extern rl_compdisp_func_t *rl_completion_display_matches_hook;
+
+/* Non-zero means that the results of the matches are to be treated
+   as filenames.  This is ALWAYS zero on entry, and can only be changed
+   within a completion entry finder function. */
+extern int rl_filename_completion_desired;
+
+/* Non-zero means that the results of the matches are to be quoted using
+   double quotes (or an application-specific quoting mechanism) if the
+   filename contains any characters in rl_word_break_chars.  This is
+   ALWAYS non-zero on entry, and can only be changed within a completion
+   entry finder function. */
+extern int rl_filename_quoting_desired;
+
+/* Set to a function to quote a filename in an application-specific fashion.
+   Called with the text to quote, the type of match found (single or multiple)
+   and a pointer to the quoting character to be used, which the function can
+   reset if desired. */
+extern rl_quote_func_t *rl_filename_quoting_function;
+
+/* Function to call to remove quoting characters from a filename.  Called
+   before completion is attempted, so the embedded quotes do not interfere
+   with matching names in the file system. */
+extern rl_dequote_func_t *rl_filename_dequoting_function;
+
+/* Function to call to decide whether or not a word break character is
+   quoted.  If a character is quoted, it does not break words for the
+   completer. */
+extern rl_linebuf_func_t *rl_char_is_quoted_p;
+
+/* Non-zero means to suppress normal filename completion after the
+   user-specified completion function has been called. */
+extern int rl_attempted_completion_over;
+
+/* Set to a character describing the type of completion being attempted by
+   rl_complete_internal; available for use by application completion
+   functions. */
+extern int rl_completion_type;
+
+/* Set to the last key used to invoke one of the completion functions */
+extern int rl_completion_invoking_key;
+
+/* Up to this many items will be displayed in response to a
+   possible-completions call.  After that, we ask the user if she
+   is sure she wants to see them all.  The default value is 100. */
+extern int rl_completion_query_items;
+
+/* Character appended to completed words when at the end of the line.  The
+   default is a space.  Nothing is added if this is '\0'. */
+extern int rl_completion_append_character;
+
+/* If set to non-zero by an application completion function,
+   rl_completion_append_character will not be appended. */
+extern int rl_completion_suppress_append;
+
+/* Set to any quote character readline thinks it finds before any application
+   completion function is called. */
+extern int rl_completion_quote_character;
+
+/* Set to a non-zero value if readline found quoting anywhere in the word to
+   be completed; set before any application completion function is called. */
+extern int rl_completion_found_quote;
+
+/* If non-zero, the completion functions don't append any closing quote.
+   This is set to 0 by rl_complete_internal and may be changed by an
+   application-specific completion function. */
+extern int rl_completion_suppress_quote;
+
+/* If non-zero, readline will sort the completion matches.  On by default. */
+extern int rl_sort_completion_matches;
+
+/* If non-zero, a slash will be appended to completed filenames that are
+   symbolic links to directory names, subject to the value of the
+   mark-directories variable (which is user-settable).  This exists so
+   that application completion functions can override the user's preference
+   (set via the mark-symlinked-directories variable) if appropriate.
+   It's set to the value of _rl_complete_mark_symlink_dirs in
+   rl_complete_internal before any application-specific completion
+   function is called, so without that function doing anything, the user's
+   preferences are honored. */
+extern int rl_completion_mark_symlink_dirs;
+
+/* If non-zero, then disallow duplicates in the matches. */
+extern int rl_ignore_completion_duplicates;
+
+/* If this is non-zero, completion is (temporarily) inhibited, and the
+   completion character will be inserted as any other. */
+extern int rl_inhibit_completion;
+
+#endif
+
+/* Input error; can be returned by (*rl_getc_function) if readline is reading
+   a top-level command (RL_ISSTATE (RL_STATE_READCMD)). */
+#define READERR			(-2)
+
+/* Definitions available for use by readline clients. */
+#define RL_PROMPT_START_IGNORE	'\001'
+#define RL_PROMPT_END_IGNORE	'\002'
+
+/* Possible values for do_replace argument to rl_filename_quoting_function,
+   called by rl_complete_internal. */
+#define NO_MATCH        0
+#define SINGLE_MATCH    1
+#define MULT_MATCH      2
+
+/* Possible state values for rl_readline_state */
+#define RL_STATE_NONE		0x000000		/* no state; before first call */
+
+#define RL_STATE_INITIALIZING	0x000001	/* initializing */
+#define RL_STATE_INITIALIZED	0x000002	/* initialization done */
+#define RL_STATE_TERMPREPPED	0x000004	/* terminal is prepped */
+#define RL_STATE_READCMD	0x000008	/* reading a command key */
+#define RL_STATE_METANEXT	0x000010	/* reading input after ESC */
+#define RL_STATE_DISPATCHING	0x000020	/* dispatching to a command */
+#define RL_STATE_MOREINPUT	0x000040	/* reading more input in a command function */
+#define RL_STATE_ISEARCH	0x000080	/* doing incremental search */
+#define RL_STATE_NSEARCH	0x000100	/* doing non-inc search */
+#define RL_STATE_SEARCH		0x000200	/* doing a history search */
+#define RL_STATE_NUMERICARG	0x000400	/* reading numeric argument */
+#define RL_STATE_MACROINPUT	0x000800	/* getting input from a macro */
+#define RL_STATE_MACRODEF	0x001000	/* defining keyboard macro */
+#define RL_STATE_OVERWRITE	0x002000	/* overwrite mode */
+#define RL_STATE_COMPLETING	0x004000	/* doing completion */
+#define RL_STATE_SIGHANDLER	0x008000	/* in readline sighandler */
+#define RL_STATE_UNDOING	0x010000	/* doing an undo */
+#define RL_STATE_INPUTPENDING	0x020000	/* rl_execute_next called */
+#define RL_STATE_TTYCSAVED	0x040000	/* tty special chars saved */
+#define RL_STATE_CALLBACK	0x080000	/* using the callback interface */
+#define RL_STATE_VIMOTION	0x100000	/* reading vi motion arg */
+#define RL_STATE_MULTIKEY	0x200000	/* reading multiple-key command */
+#define RL_STATE_VICMDONCE	0x400000	/* entered vi command mode at least once */
+#define RL_STATE_REDISPLAYING	0x800000	/* updating terminal display */
+
+#define RL_STATE_DONE		0x1000000	/* done; accepted line */
+
+#define RL_SETSTATE(x)		(rl_readline_state |= (x))
+#define RL_UNSETSTATE(x)	(rl_readline_state &= ~(x))
+#define RL_ISSTATE(x)		(rl_readline_state & (x))
+
+struct readline_state {
+  /* line state */
+  int point;
+  int end;
+  int mark;
+  char *buffer;
+  int buflen;
+  UNDO_LIST *ul;
+  char *prompt;
+
+  /* global state */
+  int rlstate;
+  int done;
+  Keymap kmap;
+
+  /* input state */
+  rl_command_func_t *lastfunc;
+  int insmode;
+  int edmode;
+  int kseqlen;
+  FILE *inf;
+  FILE *outf;
+  int pendingin;
+  char *macro;
+
+  /* signal state */
+  int catchsigs;
+  int catchsigwinch;
+
+  /* search state */
+
+  /* completion state */
+
+  /* options state */
+
+  /* reserved for future expansion, so the struct size doesn't change */
+  char reserved[64];
+};
+
+extern int rl_save_state PARAMS((struct readline_state *));
+extern int rl_restore_state PARAMS((struct readline_state *));
+
diff --git a/lib/wrappers/readline/tweaked/rltypedefs.h b/lib/wrappers/readline/tweaked/rltypedefs.h
new file mode 100644
index 000000000..46bb42567
--- /dev/null
+++ b/lib/wrappers/readline/tweaked/rltypedefs.h
@@ -0,0 +1,78 @@
+/* rltypedefs.h -- Type declarations for readline functions. */
+
+/* Copyright (C) 2000-2009 Free Software Foundation, Inc.
+
+   This file is part of the GNU Readline Library (Readline), a library
+   for reading lines of text with interactive input and history editing.      
+
+   Readline is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   Readline 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef C2NIM
+#  cdecl
+#  prefix rl_
+#  prefix RL_
+#  suffix _t
+#  typeprefixes
+#  def PARAMS(x) x
+#endif
+
+typedef int (*Function) ();
+typedef void VFunction ();
+typedef char *CPFunction ();
+typedef char **CPPFunction ();
+
+/* Bindable functions */
+typedef int rl_command_func_t PARAMS((int, int));
+
+/* Typedefs for the completion system */
+typedef char *rl_compentry_func_t PARAMS((const char *, int));
+typedef char **rl_completion_func_t PARAMS((const char *, int, int));
+
+typedef char *rl_quote_func_t PARAMS((char *, int, char *));
+typedef char *rl_dequote_func_t PARAMS((char *, int));
+
+typedef int rl_compignore_func_t PARAMS((char **));
+
+typedef void rl_compdisp_func_t PARAMS((char **, int, int));
+
+/* Type for input and pre-read hook functions like rl_event_hook */
+typedef int rl_hook_func_t PARAMS((void));
+
+/* Input function type */
+typedef int rl_getc_func_t PARAMS((TFile));
+
+/* Generic function that takes a character buffer (which could be the readline
+   line buffer) and an index into it (which could be rl_point) and returns
+   an int. */
+typedef int rl_linebuf_func_t PARAMS((char *, int));
+
+/* `Generic' function pointer typedefs */
+typedef int rl_intfunc_t PARAMS((int));
+typedef int rl_ivoidfunc_t PARAMS((void));
+
+typedef int rl_icpfunc_t PARAMS((char *));
+typedef int rl_icppfunc_t PARAMS((char **));
+
+typedef void rl_voidfunc_t PARAMS((void));
+typedef void rl_vintfunc_t PARAMS((int));
+typedef void rl_vcpfunc_t PARAMS((char *));
+typedef void rl_vcppfunc_t PARAMS((char **));
+
+typedef char *rl_cpvfunc_t PARAMS((void));
+typedef char *rl_cpifunc_t PARAMS((int));
+typedef char *rl_cpcpfunc_t PARAMS((char  *));
+typedef char *rl_cpcppfunc_t PARAMS((char  **));
+
+
diff --git a/lib/wrappers/readline/tweaked/tilde.h b/lib/wrappers/readline/tweaked/tilde.h
new file mode 100644
index 000000000..d91d0418d
--- /dev/null
+++ b/lib/wrappers/readline/tweaked/tilde.h
@@ -0,0 +1,77 @@
+/* tilde.h: Externally available variables and function in libtilde.a. */
+
+/* Copyright (C) 1992-2009 Free Software Foundation, Inc.
+
+   This file contains the Readline Library (Readline), a set of
+   routines for providing Emacs style line input to programs that ask
+   for it.
+
+   Readline is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   Readline 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Readline.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef C2NIM
+#  private tildeDll
+#  dynlib tildeDll
+#  cdecl
+#  if defined(windows)
+#    define tildeDll "tilde.dll"
+#  elif defined(macosx)
+#    define tildeDll "libtilde.dynlib"
+#  else
+#    define tildeDll "libtilde.so.6(|.0)"
+#  endif
+#  prefix tilde_
+#  suffix _t
+#  typeprefixes
+#  def PARAMS(x) x
+#endif
+
+typedef char *tilde_hook_func_t PARAMS((char *));
+
+#if false
+
+/* If non-null, this contains the address of a function that the application
+   wants called before trying the standard tilde expansions.  The function
+   is called with the text sans tilde, and returns a malloc()'ed string
+   which is the expansion, or a NULL pointer if the expansion fails. */
+extern tilde_hook_func_t *tilde_expansion_preexpansion_hook;
+
+/* If non-null, this contains the address of a function to call if the
+   standard meaning for expanding a tilde fails.  The function is called
+   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
+   which is the expansion, or a NULL pointer if there is no expansion. */
+extern tilde_hook_func_t *tilde_expansion_failure_hook;
+
+/* When non-null, this is a NULL terminated array of strings which
+   are duplicates for a tilde prefix.  Bash uses this to expand
+   `=~' and `:~'. */
+extern char **tilde_additional_prefixes;
+
+/* When non-null, this is a NULL terminated array of strings which match
+   the end of a username, instead of just "/".  Bash sets this to
+   `:' and `=~'. */
+extern char **tilde_additional_suffixes;
+
+/* Return a new string which is the result of tilde expanding STRING. */
+extern char *tilde_expand PARAMS((const char *));
+
+/* Do the work of tilde expansion on FILENAME.  FILENAME starts with a
+   tilde.  If there is no expansion, call tilde_expansion_failure_hook. */
+extern char *tilde_expand_word PARAMS((const char *));
+
+/* Find the portion of the string beginning with ~ that should be expanded. */
+extern char *tilde_find_word PARAMS((const char *, int, int *));
+
+#endif
+
diff --git a/lib/wrappers/sdl/sdl.nim b/lib/wrappers/sdl/sdl.nim
new file mode 100644
index 000000000..5bb5b7ec2
--- /dev/null
+++ b/lib/wrappers/sdl/sdl.nim
@@ -0,0 +1,2538 @@
+#******************************************************************************
+#
+#          JEDI-SDL : Pascal units for SDL - Simple DirectMedia Layer
+#             Conversion of the Simple DirectMedia Layer Headers
+#
+# Portions created by Sam Lantinga <slouken@devolution.com> are
+# Copyright (C) 1997-2004  Sam Lantinga
+# 5635-34 Springhouse Dr.
+# Pleasanton, CA 94588 (USA)
+#
+# All Rights Reserved.
+#
+# The original files are : SDL.h
+#                          SDL_main.h
+#                          SDL_types.h
+#                          SDL_rwops.h
+#                          SDL_timer.h
+#                          SDL_audio.h
+#                          SDL_cdrom.h
+#                          SDL_joystick.h
+#                          SDL_mouse.h
+#                          SDL_keyboard.h
+#                          SDL_events.h
+#                          SDL_video.h
+#                          SDL_byteorder.h
+#                          SDL_version.h
+#                          SDL_active.h
+#                          SDL_thread.h
+#                          SDL_mutex .h
+#                          SDL_getenv.h
+#                          SDL_loadso.h
+#
+# The initial developer of this Pascal code was :
+# Dominique Louis <Dominique@SavageSoftware.com.au>
+#
+# Portions created by Dominique Louis are
+# Copyright (C) 2000 - 2004 Dominique Louis.
+#
+#
+# Contributor(s)
+# --------------
+# Tom Jones <tigertomjones@gmx.de>  His Project inspired this conversion
+# Matthias Thoma <ma.thoma@gmx.de>
+#
+# Obtained through:
+# Joint Endeavour of Delphi Innovators ( Project JEDI )
+#
+# You may retrieve the latest version of this file at the Project
+# JEDI home page, located at http://delphi-jedi.org
+#
+# The contents of this file are used with permission, subject to
+# the Mozilla Public License Version 1.1 (the "License"); you may
+# not use this file except in compliance with the License. You may
+# obtain a copy of the License at
+# http://www.mozilla.org/MPL/MPL-1.1.html
+#
+# Software distributed under the License is distributed on an
+# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# Description
+# -----------
+#
+#
+#
+#
+#
+#
+#
+# Requires
+# --------
+#   The SDL Runtime libraris on Win32  : SDL.dll on Linux : libSDL.so
+#   They are available from...
+#   http://www.libsdl.org .
+#
+# Programming Notes
+# -----------------
+#
+#
+#
+#
+# Revision History
+# ----------------
+#   May      08 2001 - DL : Added Keyboard  State Array ( See demos for how to
+#                           use )
+#                           PKeyStateArr = ^TKeyStateArr;
+#                           TKeyStateArr = array[0..65000] of byte;
+#                           As most games will need it.
+#
+#   April    02 2001 - DL : Added SDL_getenv.h definitions and tested version
+#                           1.2.0 compatibility.
+#
+#   March    13 2001 - MT : Added Linux compatibility.
+#
+#   March    10 2001 - MT : Added externalsyms for DEFINES
+#                           Changed the license header
+#
+#   March    09 2001 - MT : Added Kylix Ifdefs/Deleted the uses mmsystem
+#
+#   March    01 2001 - DL : Update conversion of version 1.1.8
+#
+#   July     22 2001 - DL : Added TUInt8Array and PUIntArray after suggestions
+#                           from Matthias Thoma and Eric Grange.
+#
+#   October  12 2001 - DL : Various changes as suggested by Matthias Thoma and
+#                           David Acklam
+#
+#   October  24 2001 - DL : Added FreePascal support as per suggestions from
+#                           Dean Ellis.
+#
+#   October  27 2001 - DL : Added SDL_BUTTON macro
+#
+#  November  08 2001 - DL : Bug fix as pointed out by Puthoon.
+#
+#  November  29 2001 - DL : Bug fix of SDL_SetGammaRamp as pointed out by Simon
+#                           Rushton.
+#
+#  November  30 2001 - DL : SDL_NOFRAME added as pointed out by Simon Rushton.
+#
+#  December  11 2001 - DL : Added $WEAKPACKAGEUNIT ON to facilitate usage in
+#                           Components
+#
+#  January   05 2002 - DL : Added SDL_Swap32 function as suggested by Matthias
+#                           Thoma and also made sure the _getenv from
+#                           MSVCRT.DLL uses the right calling convention
+#
+#  January   25 2002 - DL : Updated conversion of SDL_AddTimer &
+#                           SDL_RemoveTimer as per suggestions from Matthias
+#                           Thoma.
+#
+#  January   27 2002 - DL : Commented out exported function putenv and getenv
+#                           So that developers get used to using SDL_putenv
+#                           SDL_getenv, as they are more portable
+#
+#  March     05 2002 - DL : Added FreeAnNil procedure for Delphi 4 users.
+#
+#  October   23 2002 - DL : Added Delphi 3 Define of Win32.
+#                           If you intend to you Delphi 3...
+#                           ( which is officially unsupported ) make sure you
+#                           remove references to $EXTERNALSYM in this and other
+#                           SDL files.
+#
+# November  29 2002 - DL : Fixed bug in Declaration of SDL_GetRGBA that was
+#                          pointed out by Todd Lang
+#
+#   April   03 2003 - DL : Added jedi-sdl.inc include file to support more
+#                          Pascal compilers. Initial support is now included
+#                          for GnuPascal, VirtualPascal, TMT and obviously
+#                          continue support for Delphi Kylix and FreePascal.
+#
+#   April   08 2003 - MK : Aka Mr Kroket - Added Better FPC support
+#
+#   April   24 2003 - DL : under instruction from Alexey Barkovoy, I have added
+#                          better TMT Pascal support and under instruction
+#                          from Prof. Abimbola Olowofoyeku (The African Chief),
+#                          I have added better Gnu Pascal support
+#
+#   April   30 2003 - DL : under instruction from David Mears AKA
+#                          Jason Siletto, I have added FPC Linux support.
+#                          This was compiled with fpc 1.1, so remember to set
+#                          include file path. ie. -Fi/usr/share/fpcsrc/rtl/*
+#
+#
+#
+#  Revision 1.31  2007/05/29 21:30:48  savage
+#  Changes as suggested by Almindor for 64bit compatibility.
+#
+#  Revision 1.30  2007/05/29 19:31:03  savage
+#  Fix to TSDL_Overlay structure - thanks David Pethes (aka imcold)
+#
+#  Revision 1.29  2007/05/20 20:29:11  savage
+#  Initial Changes to Handle 64 Bits
+#
+#  Revision 1.26  2007/02/11 13:38:04  savage
+#  Added Nintendo DS support - Thanks Dean.
+#
+#  Revision 1.25  2006/12/02 00:12:52  savage
+#  Updated to latest version
+#
+#  Revision 1.24  2006/05/18 21:10:04  savage
+#  Added 1.2.10 Changes
+#
+#  Revision 1.23  2005/12/04 23:17:52  drellis
+#  Added declaration of SInt8 and PSInt8
+#
+#  Revision 1.22  2005/05/24 21:59:03  savage
+#  Re-arranged uses clause to work on Win32 and Linux, Thanks again Michalis.
+#
+#  Revision 1.21  2005/05/22 18:42:31  savage
+#  Changes as suggested by Michalis Kamburelis. Thanks again.
+#
+#  Revision 1.20  2005/04/10 11:48:33  savage
+#  Changes as suggested by Michalis, thanks.
+#
+#  Revision 1.19  2005/01/05 01:47:06  savage
+#  Changed LibName to reflect what MacOS X should have. ie libSDL*-1.2.0.dylib respectively.
+#
+#  Revision 1.18  2005/01/04 23:14:41  savage
+#  Changed LibName to reflect what most Linux distros will have. ie libSDL*-1.2.so.0 respectively.
+#
+#  Revision 1.17  2005/01/03 18:40:59  savage
+#  Updated Version number to reflect latest one
+#
+#  Revision 1.16  2005/01/01 02:02:06  savage
+#  Updated to v1.2.8
+#
+#  Revision 1.15  2004/12/24 18:57:11  savage
+#  forgot to apply Michalis Kamburelis' patch to the implementation section. now fixed
+#
+#  Revision 1.14  2004/12/23 23:42:18  savage
+#  Applied Patches supplied by Michalis Kamburelis ( THANKS! ), for greater FreePascal compatibility.
+#
+#  Revision 1.13  2004/09/30 22:31:59  savage
+#  Updated with slightly different header comments
+#
+#  Revision 1.12  2004/09/12 21:52:58  savage
+#  Slight changes to fix some issues with the sdl classes.
+#
+#  Revision 1.11  2004/08/14 22:54:30  savage
+#  Updated so that Library name defines are correctly defined for MacOS X.
+#
+#  Revision 1.10  2004/07/20 23:57:33  savage
+#  Thanks to Paul Toth for spotting an error in the SDL Audio Conversion structures.
+#  In TSDL_AudioCVT the filters variable should point to and array of pointers and not what I had there previously.
+#
+#  Revision 1.9  2004/07/03 22:07:22  savage
+#  Added Bitwise Manipulation Functions for TSDL_VideoInfo struct.
+#
+#  Revision 1.8  2004/05/10 14:10:03  savage
+#  Initial MacOS X support. Fixed defines for MACOS ( Classic ) and DARWIN ( MacOS X ).
+#
+#  Revision 1.7  2004/04/13 09:32:08  savage
+#  Changed Shared object names back to just the .so extension to avoid conflicts on various Linux/Unix distros. Therefore developers will need to create Symbolic links to the actual Share Objects if necessary.
+#
+#  Revision 1.6  2004/04/01 20:53:23  savage
+#  Changed Linux Shared Object names so they reflect the Symbolic Links that are created when installing the RPMs from the SDL site.
+#
+#  Revision 1.5  2004/02/22 15:32:10  savage
+#  SDL_GetEnv Fix so it also works on FPC/Linux. Thanks to Rodrigo for pointing this out.
+#
+#  Revision 1.4  2004/02/21 23:24:29  savage
+#  SDL_GetEnv Fix so that it is not define twice for FPC. Thanks to Rene Hugentobler for pointing out this bug,
+#
+#  Revision 1.3  2004/02/18 22:35:51  savage
+#  Brought sdl.pas up to 1.2.7 compatibility
+#  Thus...
+#  Added SDL_GL_STEREO,
+#      SDL_GL_MULTISAMPLEBUFFERS,
+#      SDL_GL_MULTISAMPLESAMPLES
+#
+#  Add DLL/Shared object functions
+#  function SDL_LoadObject( const sofile : PChar ) : pointer;
+#
+#  function SDL_LoadFunction( handle : pointer; const name : PChar ) : pointer;
+#
+#  procedure SDL_UnloadObject( handle : pointer );
+#
+#  Added function to create RWops from const memory: SDL_RWFromConstMem()
+#  function SDL_RWFromConstMem(const mem: pointer; size: Integer) : PSDL_RWops;
+#
+#  Ported SDL_cpuinfo.h so Now you can test for Specific CPU types.
+#
+#  Revision 1.2  2004/02/17 21:37:12  savage
+#  Tidying up of units
+#
+#  Revision 1.1  2004/02/05 00:08:20  savage
+#  Module 1.0 release
+#
+#
+
+{.deadCodeElim: on.}
+import unsigned
+when defined(windows): 
+  const 
+    LibName = "SDL.dll"
+elif defined(macosx): 
+  const 
+    LibName = "libSDL-1.2.0.dylib"
+else: 
+  const 
+    LibName = "libSDL.so(|.1|.0)"
+const 
+  MAJOR_VERSION* = 1
+  MINOR_VERSION* = 2
+  PATCHLEVEL* = 11         # SDL.h constants
+  INIT_TIMER* = 0x00000001
+  INIT_AUDIO* = 0x00000010
+  INIT_VIDEO* = 0x00000020
+  INIT_CDROM* = 0x00000100
+  INIT_JOYSTICK* = 0x00000200
+  INIT_NOPARACHUTE* = 0x00100000 # Don't catch fatal signals
+  INIT_EVENTTHREAD* = 0x01000000 # Not supported on all OS's
+  INIT_EVERYTHING* = 0x0000FFFF # SDL_error.h constants
+  ERR_MAX_STRLEN* = 128
+  ERR_MAX_ARGS* = 5           # SDL_types.h constants
+  PRESSED* = 0x00000001
+  RELEASED* = 0x00000000      # SDL_timer.h constants
+                              # This is the OS scheduler timeslice, in milliseconds
+  TIMESLICE* = 10             # This is the maximum resolution of the SDL timer on all platforms
+  TIMER_RESOLUTION* = 10      # Experimentally determined
+                              # SDL_audio.h constants
+  AUDIO_U8* = 0x00000008      # Unsigned 8-bit samples
+  AUDIO_S8* = 0x00008008      # Signed 8-bit samples
+  AUDIO_U16LSB* = 0x00000010  # Unsigned 16-bit samples
+  AUDIO_S16LSB* = 0x00008010  # Signed 16-bit samples
+  AUDIO_U16MSB* = 0x00001010  # As above, but big-endian byte order
+  AUDIO_S16MSB* = 0x00009010  # As above, but big-endian byte order
+  AUDIO_U16* = AUDIO_U16LSB
+  AUDIO_S16* = AUDIO_S16LSB   # SDL_cdrom.h constants
+                              # The maximum number of CD-ROM tracks on a disk
+  MAX_TRACKS* = 99            # The types of CD-ROM track possible
+  AUDIO_TRACK* = 0x00000000
+  DATA_TRACK* = 0x00000004    # Conversion functions from frames to Minute/Second/Frames and vice versa
+  CD_FPS* = 75                # SDL_byteorder.h constants
+                              # The two types of endianness
+  LIL_ENDIAN* = 1234
+  BIG_ENDIAN* = 4321
+
+when cpuEndian == littleEndian: 
+  const 
+    BYTEORDER* = LIL_ENDIAN   # Native audio byte ordering
+    AUDIO_U16SYS* = AUDIO_U16LSB
+    AUDIO_S16SYS* = AUDIO_S16LSB
+else: 
+  const 
+    BYTEORDER* = BIG_ENDIAN   # Native audio byte ordering
+    AUDIO_U16SYS* = AUDIO_U16MSB
+    AUDIO_S16SYS* = AUDIO_S16MSB
+const 
+  MIX_MAXVOLUME* = 128        # SDL_joystick.h constants
+  MAX_JOYSTICKS* = 2          # only 2 are supported in the multimedia API
+  MAX_AXES* = 6               # each joystick can have up to 6 axes
+  MAX_BUTTONS* = 32           # and 32 buttons
+  AXIS_MIN* = - 32768         # minimum value for axis coordinate
+  AXIS_MAX* = 32767           # maximum value for axis coordinate
+  JOY_AXIS_THRESHOLD* = (toFloat((AXIS_MAX) - (AXIS_MIN)) / 100.000) # 1% motion
+  HAT_CENTERED* = 0x00000000
+  HAT_UP* = 0x00000001
+  HAT_RIGHT* = 0x00000002
+  HAT_DOWN* = 0x00000004
+  HAT_LEFT* = 0x00000008
+  HAT_RIGHTUP* = HAT_RIGHT or HAT_UP
+  HAT_RIGHTDOWN* = HAT_RIGHT or HAT_DOWN
+  HAT_LEFTUP* = HAT_LEFT or HAT_UP
+  HAT_LEFTDOWN* = HAT_LEFT or HAT_DOWN # SDL_events.h constants
+
+type 
+  TEventKind* = enum          # kind of an SDL event
+    NOEVENT = 0,              # Unused (do not remove)
+    ACTIVEEVENT = 1,          # Application loses/gains visibility
+    KEYDOWN = 2,              # Keys pressed
+    KEYUP = 3,                # Keys released
+    MOUSEMOTION = 4,          # Mouse moved
+    MOUSEBUTTONDOWN = 5,      # Mouse button pressed
+    MOUSEBUTTONUP = 6,        # Mouse button released
+    JOYAXISMOTION = 7,        # Joystick axis motion
+    JOYBALLMOTION = 8,        # Joystick trackball motion
+    JOYHATMOTION = 9,         # Joystick hat position change
+    JOYBUTTONDOWN = 10,       # Joystick button pressed
+    JOYBUTTONUP = 11,         # Joystick button released
+    QUITEV = 12,              # User-requested quit ( Changed due to procedure conflict )
+    SYSWMEVENT = 13,          # System specific event
+    EVENT_RESERVEDA = 14,     # Reserved for future use..
+    EVENT_RESERVED = 15,      # Reserved for future use..
+    VIDEORESIZE = 16,         # User resized video mode
+    VIDEOEXPOSE = 17,         # Screen needs to be redrawn
+    EVENT_RESERVED2 = 18,     # Reserved for future use..
+    EVENT_RESERVED3 = 19,     # Reserved for future use..
+    EVENT_RESERVED4 = 20,     # Reserved for future use..
+    EVENT_RESERVED5 = 21,     # Reserved for future use..
+    EVENT_RESERVED6 = 22,     # Reserved for future use..
+    EVENT_RESERVED7 = 23,     # Reserved for future use..
+                              # Events SDL_USEREVENT through SDL_MAXEVENTS-1 are for your use
+    USEREVENT = 24 # This last event is only for bounding internal arrays
+                   # It is the number of bits in the event mask datatype -- int32
+
+const 
+  NUMEVENTS* = 32
+  ALLEVENTS* = 0xFFFFFFFF
+  ACTIVEEVENTMASK* = 1 shl ord(ACTIVEEVENT)
+  KEYDOWNMASK* = 1 shl ord(KEYDOWN)
+  KEYUPMASK* = 1 shl ord(KEYUP)
+  MOUSEMOTIONMASK* = 1 shl ord(MOUSEMOTION)
+  MOUSEBUTTONDOWNMASK* = 1 shl ord(MOUSEBUTTONDOWN)
+  MOUSEBUTTONUPMASK* = 1 shl ord(MOUSEBUTTONUP)
+  MOUSEEVENTMASK* = 1 shl ord(MOUSEMOTION) or 1 shl ord(MOUSEBUTTONDOWN) or
+      1 shl ord(MOUSEBUTTONUP)
+  JOYAXISMOTIONMASK* = 1 shl ord(JOYAXISMOTION)
+  JOYBALLMOTIONMASK* = 1 shl ord(JOYBALLMOTION)
+  JOYHATMOTIONMASK* = 1 shl ord(JOYHATMOTION)
+  JOYBUTTONDOWNMASK* = 1 shl ord(JOYBUTTONDOWN)
+  JOYBUTTONUPMASK* = 1 shl ord(JOYBUTTONUP)
+  JOYEVENTMASK* = 1 shl ord(JOYAXISMOTION) or 1 shl ord(JOYBALLMOTION) or
+      1 shl ord(JOYHATMOTION) or 1 shl ord(JOYBUTTONDOWN) or
+      1 shl ord(JOYBUTTONUP)
+  VIDEORESIZEMASK* = 1 shl ord(VIDEORESIZE)
+  QUITMASK* = 1 shl ord(QUITEV)
+  SYSWMEVENTMASK* = 1 shl ord(SYSWMEVENT)
+  QUERY* = - 1
+  IGNORE* = 0
+  DISABLE* = 0
+  ENABLE* = 1                 #SDL_keyboard.h constants
+                              # This is the mask which refers to all hotkey bindings
+  ALL_HOTKEYS* = 0xFFFFFFFF # Enable/Disable keyboard repeat.  Keyboard repeat defaults to off.
+                            #  'delay' is the initial delay in ms between the time when a key is
+                            #  pressed, and keyboard repeat begins.
+                            #  'interval' is the time in ms between keyboard repeat events.
+  DEFAULT_REPEAT_DELAY* = 500
+  DEFAULT_REPEAT_INTERVAL* = 30 # The keyboard syms have been cleverly chosen to map to ASCII
+  K_UNKNOWN* = 0
+  K_FIRST* = 0
+  K_BACKSPACE* = 8
+  K_TAB* = 9
+  K_CLEAR* = 12
+  K_RETURN* = 13
+  K_PAUSE* = 19
+  K_ESCAPE* = 27
+  K_SPACE* = 32
+  K_EXCLAIM* = 33
+  K_QUOTEDBL* = 34
+  K_HASH* = 35
+  K_DOLLAR* = 36
+  K_AMPERSAND* = 38
+  K_QUOTE* = 39
+  K_LEFTPAREN* = 40
+  K_RIGHTPAREN* = 41
+  K_ASTERISK* = 42
+  K_PLUS* = 43
+  K_COMMA* = 44
+  K_MINUS* = 45
+  K_PERIOD* = 46
+  K_SLASH* = 47
+  K_0* = 48
+  K_1* = 49
+  K_2* = 50
+  K_3* = 51
+  K_4* = 52
+  K_5* = 53
+  K_6* = 54
+  K_7* = 55
+  K_8* = 56
+  K_9* = 57
+  K_COLON* = 58
+  K_SEMICOLON* = 59
+  K_LESS* = 60
+  K_EQUALS* = 61
+  K_GREATER* = 62
+  K_QUESTION* = 63
+  K_AT* = 64                  # Skip uppercase letters
+  K_LEFTBRACKET* = 91
+  K_BACKSLASH* = 92
+  K_RIGHTBRACKET* = 93
+  K_CARET* = 94
+  K_UNDERSCORE* = 95
+  K_BACKQUOTE* = 96
+  K_a* = 97
+  K_b* = 98
+  K_c* = 99
+  K_d* = 100
+  K_e* = 101
+  K_f* = 102
+  K_g* = 103
+  K_h* = 104
+  K_i* = 105
+  K_j* = 106
+  K_k* = 107
+  K_l* = 108
+  K_m* = 109
+  K_n* = 110
+  K_o* = 111
+  K_p* = 112
+  K_q* = 113
+  K_r* = 114
+  K_s* = 115
+  K_t* = 116
+  K_u* = 117
+  K_v* = 118
+  K_w* = 119
+  K_x* = 120
+  K_y* = 121
+  K_z* = 122
+  K_DELETE* = 127             # End of ASCII mapped keysyms
+                              # International keyboard syms
+  K_WORLD_0* = 160            # 0xA0
+  K_WORLD_1* = 161
+  K_WORLD_2* = 162
+  K_WORLD_3* = 163
+  K_WORLD_4* = 164
+  K_WORLD_5* = 165
+  K_WORLD_6* = 166
+  K_WORLD_7* = 167
+  K_WORLD_8* = 168
+  K_WORLD_9* = 169
+  K_WORLD_10* = 170
+  K_WORLD_11* = 171
+  K_WORLD_12* = 172
+  K_WORLD_13* = 173
+  K_WORLD_14* = 174
+  K_WORLD_15* = 175
+  K_WORLD_16* = 176
+  K_WORLD_17* = 177
+  K_WORLD_18* = 178
+  K_WORLD_19* = 179
+  K_WORLD_20* = 180
+  K_WORLD_21* = 181
+  K_WORLD_22* = 182
+  K_WORLD_23* = 183
+  K_WORLD_24* = 184
+  K_WORLD_25* = 185
+  K_WORLD_26* = 186
+  K_WORLD_27* = 187
+  K_WORLD_28* = 188
+  K_WORLD_29* = 189
+  K_WORLD_30* = 190
+  K_WORLD_31* = 191
+  K_WORLD_32* = 192
+  K_WORLD_33* = 193
+  K_WORLD_34* = 194
+  K_WORLD_35* = 195
+  K_WORLD_36* = 196
+  K_WORLD_37* = 197
+  K_WORLD_38* = 198
+  K_WORLD_39* = 199
+  K_WORLD_40* = 200
+  K_WORLD_41* = 201
+  K_WORLD_42* = 202
+  K_WORLD_43* = 203
+  K_WORLD_44* = 204
+  K_WORLD_45* = 205
+  K_WORLD_46* = 206
+  K_WORLD_47* = 207
+  K_WORLD_48* = 208
+  K_WORLD_49* = 209
+  K_WORLD_50* = 210
+  K_WORLD_51* = 211
+  K_WORLD_52* = 212
+  K_WORLD_53* = 213
+  K_WORLD_54* = 214
+  K_WORLD_55* = 215
+  K_WORLD_56* = 216
+  K_WORLD_57* = 217
+  K_WORLD_58* = 218
+  K_WORLD_59* = 219
+  K_WORLD_60* = 220
+  K_WORLD_61* = 221
+  K_WORLD_62* = 222
+  K_WORLD_63* = 223
+  K_WORLD_64* = 224
+  K_WORLD_65* = 225
+  K_WORLD_66* = 226
+  K_WORLD_67* = 227
+  K_WORLD_68* = 228
+  K_WORLD_69* = 229
+  K_WORLD_70* = 230
+  K_WORLD_71* = 231
+  K_WORLD_72* = 232
+  K_WORLD_73* = 233
+  K_WORLD_74* = 234
+  K_WORLD_75* = 235
+  K_WORLD_76* = 236
+  K_WORLD_77* = 237
+  K_WORLD_78* = 238
+  K_WORLD_79* = 239
+  K_WORLD_80* = 240
+  K_WORLD_81* = 241
+  K_WORLD_82* = 242
+  K_WORLD_83* = 243
+  K_WORLD_84* = 244
+  K_WORLD_85* = 245
+  K_WORLD_86* = 246
+  K_WORLD_87* = 247
+  K_WORLD_88* = 248
+  K_WORLD_89* = 249
+  K_WORLD_90* = 250
+  K_WORLD_91* = 251
+  K_WORLD_92* = 252
+  K_WORLD_93* = 253
+  K_WORLD_94* = 254
+  K_WORLD_95* = 255           # 0xFF
+                              # Numeric keypad
+  K_KP0* = 256
+  K_KP1* = 257
+  K_KP2* = 258
+  K_KP3* = 259
+  K_KP4* = 260
+  K_KP5* = 261
+  K_KP6* = 262
+  K_KP7* = 263
+  K_KP8* = 264
+  K_KP9* = 265
+  K_KP_PERIOD* = 266
+  K_KP_DIVIDE* = 267
+  K_KP_MULTIPLY* = 268
+  K_KP_MINUS* = 269
+  K_KP_PLUS* = 270
+  K_KP_ENTER* = 271
+  K_KP_EQUALS* = 272          # Arrows + Home/End pad
+  K_UP* = 273
+  K_DOWN* = 274
+  K_RIGHT* = 275
+  K_LEFT* = 276
+  K_INSERT* = 277
+  K_HOME* = 278
+  K_END* = 279
+  K_PAGEUP* = 280
+  K_PAGEDOWN* = 281           # Function keys
+  K_F1* = 282
+  K_F2* = 283
+  K_F3* = 284
+  K_F4* = 285
+  K_F5* = 286
+  K_F6* = 287
+  K_F7* = 288
+  K_F8* = 289
+  K_F9* = 290
+  K_F10* = 291
+  K_F11* = 292
+  K_F12* = 293
+  K_F13* = 294
+  K_F14* = 295
+  K_F15* = 296                # Key state modifier keys
+  K_NUMLOCK* = 300
+  K_CAPSLOCK* = 301
+  K_SCROLLOCK* = 302
+  K_RSHIFT* = 303
+  K_LSHIFT* = 304
+  K_RCTRL* = 305
+  K_LCTRL* = 306
+  K_RALT* = 307
+  K_LALT* = 308
+  K_RMETA* = 309
+  K_LMETA* = 310
+  K_LSUPER* = 311             # Left "Windows" key
+  K_RSUPER* = 312             # Right "Windows" key
+  K_MODE* = 313               # "Alt Gr" key
+  K_COMPOSE* = 314            # Multi-key compose key
+                              # Miscellaneous function keys
+  K_HELP* = 315
+  K_PRINT* = 316
+  K_SYSREQ* = 317
+  K_BREAK* = 318
+  K_MENU* = 319
+  K_POWER* = 320              # Power Macintosh power key
+  K_EURO* = 321               # Some european keyboards
+  K_GP2X_UP* = 0
+  K_GP2X_UPLEFT* = 1
+  K_GP2X_LEFT* = 2
+  K_GP2X_DOWNLEFT* = 3
+  K_GP2X_DOWN* = 4
+  K_GP2X_DOWNRIGHT* = 5
+  K_GP2X_RIGHT* = 6
+  K_GP2X_UPRIGHT* = 7
+  K_GP2X_START* = 8
+  K_GP2X_SELECT* = 9
+  K_GP2X_L* = 10
+  K_GP2X_R* = 11
+  K_GP2X_A* = 12
+  K_GP2X_B* = 13
+  K_GP2X_Y* = 14
+  K_GP2X_X* = 15
+  K_GP2X_VOLUP* = 16
+  K_GP2X_VOLDOWN* = 17
+  K_GP2X_CLICK* = 18
+
+const                         # Enumeration of valid key mods (possibly OR'd together)
+  KMOD_NONE* = 0x00000000
+  KMOD_LSHIFT* = 0x00000001
+  KMOD_RSHIFT* = 0x00000002
+  KMOD_LCTRL* = 0x00000040
+  KMOD_RCTRL* = 0x00000080
+  KMOD_LALT* = 0x00000100
+  KMOD_RALT* = 0x00000200
+  KMOD_LMETA* = 0x00000400
+  KMOD_RMETA* = 0x00000800
+  KMOD_NUM* = 0x00001000
+  KMOD_CAPS* = 0x00002000
+  KMOD_MODE* = 44000
+  KMOD_RESERVED* = 0x00008000
+  KMOD_CTRL* = (KMOD_LCTRL or KMOD_RCTRL)
+  KMOD_SHIFT* = (KMOD_LSHIFT or KMOD_RSHIFT)
+  KMOD_ALT* = (KMOD_LALT or KMOD_RALT)
+  KMOD_META* = (KMOD_LMETA or KMOD_RMETA) #SDL_video.h constants
+                                          # Transparency definitions: These define alpha as the opacity of a surface */
+  ALPHA_OPAQUE* = 255
+  ALPHA_TRANSPARENT* = 0 # These are the currently supported flags for the SDL_surface
+                         # Available for SDL_CreateRGBSurface() or SDL_SetVideoMode()
+  SWSURFACE* = 0x00000000     # Surface is in system memory
+  HWSURFACE* = 0x00000001     # Surface is in video memory
+  ASYNCBLIT* = 0x00000004     # Use asynchronous blits if possible
+                              # Available for SDL_SetVideoMode()
+  ANYFORMAT* = 0x10000000     # Allow any video depth/pixel-format
+  HWPALETTE* = 0x20000000     # Surface has exclusive palette
+  DOUBLEBUF* = 0x40000000     # Set up double-buffered video mode
+  FULLSCREEN* = 0x80000000    # Surface is a full screen display
+  OPENGL* = 0x00000002        # Create an OpenGL rendering context
+  OPENGLBLIT* = 0x00000002    # Create an OpenGL rendering context
+  RESIZABLE* = 0x00000010     # This video mode may be resized
+  NOFRAME* = 0x00000020       # No window caption or edge frame
+                              # Used internally (read-only)
+  HWACCEL* = 0x00000100       # Blit uses hardware acceleration
+  SRCCOLORKEY* = 0x00001000   # Blit uses a source color key
+  RLEACCELOK* = 0x00002000    # Private flag
+  RLEACCEL* = 0x00004000      # Colorkey blit is RLE accelerated
+  SRCALPHA* = 0x00010000      # Blit uses source alpha blending
+  SRCCLIPPING* = 0x00100000   # Blit uses source clipping
+  PREALLOC* = 0x01000000 # Surface uses preallocated memory
+                         # The most common video overlay formats.
+                         #    For an explanation of these pixel formats, see:
+                         #    http://www.webartz.com/fourcc/indexyuv.htm
+                         #
+                         #   For information on the relationship between color spaces, see:
+                         #
+                         #   
+                         #   http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html
+  YV12_OVERLAY* = 0x32315659  # Planar mode: Y + V + U  (3 planes)
+  IYUV_OVERLAY* = 0x56555949  # Planar mode: Y + U + V  (3 planes)
+  YUY2_OVERLAY* = 0x32595559  # Packed mode: Y0+U0+Y1+V0 (1 plane)
+  UYVY_OVERLAY* = 0x59565955  # Packed mode: U0+Y0+V0+Y1 (1 plane)
+  YVYU_OVERLAY* = 0x55595659  # Packed mode: Y0+V0+Y1+U0 (1 plane)
+                              # flags for SDL_SetPalette()
+  LOGPAL* = 0x00000001
+  PHYSPAL* = 0x00000002 #SDL_mouse.h constants
+                        # Used as a mask when testing buttons in buttonstate
+                        #    Button 1:	Left mouse button
+                        #    Button 2:	Middle mouse button
+                        #    Button 3:	Right mouse button
+                        #    Button 4:	Mouse Wheel Up
+                        #    Button 5:	Mouse Wheel Down
+                        #
+  BUTTON_LEFT* = 1
+  BUTTON_MIDDLE* = 2
+  BUTTON_RIGHT* = 3
+  BUTTON_WHEELUP* = 4
+  BUTTON_WHEELDOWN* = 5
+  BUTTON_LMASK* = PRESSED shl (BUTTON_LEFT - 1)
+  BUTTON_MMASK* = PRESSED shl (BUTTON_MIDDLE - 1)
+  BUTTON_RMask* = PRESSED shl (BUTTON_RIGHT - 1) # SDL_active.h constants
+                                                 # The available application states
+  APPMOUSEFOCUS* = 0x00000001 # The app has mouse coverage
+  APPINPUTFOCUS* = 0x00000002 # The app has input focus
+  APPACTIVE* = 0x00000004 # The application is active
+                          # SDL_mutex.h constants
+                          # Synchronization functions which can time out return this value
+                          #  they time out.
+  MUTEX_TIMEDOUT* = 1         # This is the timeout value which corresponds to never time out
+  MUTEX_MAXWAIT* = not int(0)
+  GRAB_QUERY* = - 1
+  GRAB_OFF* = 0
+  GRAB_ON* = 1                #SDL_GRAB_FULLSCREEN // Used internally
+
+type 
+  THandle* = int              #SDL_types.h types
+                              # Basic data types
+  TBool* = enum
+    sdlFALSE, sdlTRUE
+  PUInt8Array* = ptr TUInt8Array
+  TUInt8Array* = array[0..high(int) shr 1, byte]
+  PUInt16* = ptr uint16
+  PUInt32* = ptr uint32
+  PUInt64* = ptr UInt64
+  UInt64*{.final.} = object 
+    hi*: int32
+    lo*: int32
+
+  PSInt64* = ptr SInt64
+  SInt64*{.final.} = object 
+    hi*: int32
+    lo*: int32
+
+  TGrabMode* = int32         # SDL_error.h types
+  Terrorcode* = enum 
+    ENOMEM, EFREAD, EFWRITE, EFSEEK, LASTERROR
+  Errorcode* = Terrorcode
+  TArg*{.final.} = object 
+    buf*: array[0..ERR_MAX_STRLEN - 1, int8]
+
+  Perror* = ptr Terror
+  TError*{.final.} = object  # This is a numeric value corresponding to the current error
+                             # SDL_rwops.h types
+                             # This is the read/write operation structure -- very basic
+                             # some helper types to handle the unions
+                             # "packed" is only guessed
+    error*: int # This is a key used to index into a language hashtable containing
+                #       internationalized versions of the SDL error messages.  If the key
+                #       is not in the hashtable, or no hashtable is available, the key is
+                #       used directly as an error message format string.
+    key*: array[0..ERR_MAX_STRLEN - 1, int8] # These are the arguments for the error functions
+    argc*: int
+    args*: array[0..ERR_MAX_ARGS - 1, TArg]
+
+  TStdio*{.final.} = object 
+    autoclose*: int           # FILE * is only defined in Kylix so we use a simple pointer
+    fp*: pointer
+
+  TMem*{.final.} = object 
+    base*: ptr byte
+    here*: ptr byte
+    stop*: ptr byte
+
+  PRWops* = ptr TRWops        # now the pointer to function types
+  TSeek* = proc (context: PRWops, offset: int, whence: int): int{.cdecl.}
+  TRead* = proc (context: PRWops, thePtr: pointer, size: int, maxnum: int): int{.
+      cdecl.}
+  TWrite* = proc (context: PRWops, thePtr: pointer, size: int, num: int): int{.
+      cdecl.}
+  TClose* = proc (context: PRWops): int{.cdecl.} # the variant record itself
+  TRWops*{.final.} = object 
+    seek*: TSeek
+    read*: TRead
+    write*: TWrite
+    closeFile*: TClose        # a keyword as name is not allowed
+                              # be warned! structure alignment may arise at this point
+    theType*: cint
+    mem*: TMem
+  
+  RWops* = TRWops             # SDL_timer.h types
+                              # Function prototype for the timer callback function
+  TTimerCallback* = proc (interval: int32): int32{.cdecl.}
+  TNewTimerCallback* = proc (interval: int32, param: pointer): int32{.cdecl.}
+
+  PTimerID* = ptr TTimerID
+  TTimerID*{.final.} = object 
+    interval*: int32
+    callback*: TNewTimerCallback
+    param*: pointer
+    lastAlarm*: int32
+    next*: PTimerID
+
+  TAudioSpecCallback* = proc (userdata: pointer, stream: ptr byte, length: int){.
+      cdecl.}                 # SDL_audio.h types
+                              # The calculated values in this structure are calculated by SDL_OpenAudio()
+  PAudioSpec* = ptr TAudioSpec
+  TAudioSpec*{.final.} = object  # A structure to hold a set of audio conversion filters and buffers
+    freq*: int                # DSP frequency -- samples per second
+    format*: uint16           # Audio data format
+    channels*: byte          # Number of channels: 1 mono, 2 stereo
+    silence*: byte           # Audio buffer silence value (calculated)
+    samples*: uint16          # Audio buffer size in samples
+    padding*: uint16          # Necessary for some compile environments
+    size*: int32 # Audio buffer size in bytes (calculated)
+                 # This function is called when the audio device needs more data.
+                 # 'stream' is a pointer to the audio data buffer
+                 # 'len' is the length of that buffer in bytes.
+                 # Once the callback returns, the buffer will no longer be valid.
+                 # Stereo samples are stored in a LRLRLR ordering.
+    callback*: TAudioSpecCallback
+    userdata*: pointer
+
+  PAudioCVT* = ptr TAudioCVT
+  PAudioCVTFilter* = ptr TAudioCVTFilter
+  TAudioCVTFilter*{.final.} = object 
+    cvt*: PAudioCVT
+    format*: uint16
+
+  PAudioCVTFilterArray* = ptr TAudioCVTFilterArray
+  TAudioCVTFilterArray* = array[0..9, PAudioCVTFilter]
+  TAudioCVT*{.final.} = object 
+    needed*: int              # Set to 1 if conversion possible
+    srcFormat*: uint16       # Source audio format
+    dstFormat*: uint16       # Target audio format
+    rateIncr*: float64       # Rate conversion increment
+    buf*: ptr byte              # Buffer to hold entire audio data
+    length*: int              # Length of original audio buffer
+    lenCvt*: int             # Length of converted audio buffer
+    lenMult*: int            # buffer must be len*len_mult big
+    lenRatio*: float64       # Given len, final size is len*len_ratio
+    filters*: TAudioCVTFilterArray
+    filterIndex*: int        # Current audio conversion function
+  
+  TAudiostatus* = enum        # SDL_cdrom.h types
+    AUDIO_STOPPED, AUDIO_PLAYING, AUDIO_PAUSED
+  TCDStatus* = enum 
+    CD_ERROR, CD_TRAYEMPTY, CD_STOPPED, CD_PLAYING, CD_PAUSED
+  PCDTrack* = ptr TCDTrack
+  TCDTrack*{.final.} = object  # This structure is only current as of the last call to SDL_CDStatus()
+    id*: byte                # Track number
+    theType*: byte           # Data or audio track
+    unused*: uint16
+    len*: int32              # Length, in frames, of this track
+    offset*: int32           # Offset, in frames, from start of disk
+  
+  PCD* = ptr TCD
+  TCD*{.final.} = object      #SDL_joystick.h types
+    id*: int                  # Private drive identifier
+    status*: TCDStatus        # Current drive status
+                              # The rest of this structure is only valid if there's a CD in drive
+    numtracks*: int           # Number of tracks on disk
+    curTrack*: int           # Current track position
+    curFrame*: int           # Current frame offset within current track
+    track*: array[0..MAX_TRACKS, TCDTrack]
+
+  PTransAxis* = ptr TTransAxis
+  TTransAxis*{.final.} = object  # The private structure used to keep track of a joystick
+    offset*: int
+    scale*: float32
+
+  PJoystickHwdata* = ptr TJoystickHwdata
+  TJoystick_hwdata*{.final.} = object  # joystick ID
+    id*: int                  # values used to translate device-specific coordinates into  SDL-standard ranges
+    transaxis*: array[0..5, TTransAxis]
+
+  PBallDelta* = ptr TBallDelta
+  TBallDelta*{.final.} = object  # Current ball motion deltas
+                                 # The SDL joystick structure
+    dx*: int
+    dy*: int
+
+  PJoystick* = ptr TJoystick
+  TJoystick*{.final.} = object  # SDL_verion.h types
+    index*: byte             # Device index
+    name*: cstring            # Joystick name - system dependent
+    naxes*: int               # Number of axis controls on the joystick
+    axes*: PUInt16            # Current axis states
+    nhats*: int               # Number of hats on the joystick
+    hats*: ptr byte             # Current hat states
+    nballs*: int              # Number of trackballs on the joystick
+    balls*: PBallDelta        # Current ball motion deltas
+    nbuttons*: int            # Number of buttons on the joystick
+    buttons*: ptr byte          # Current button states
+    hwdata*: PJoystickHwdata # Driver dependent information
+    refCount*: int           # Reference count for multiple opens
+  
+  Pversion* = ptr Tversion
+  Tversion*{.final.} = object  # SDL_keyboard.h types
+    major*: byte
+    minor*: byte
+    patch*: byte
+
+  TKey* = int32
+  TMod* = int32
+  PKeySym* = ptr TKeySym
+  TKeySym*{.final.} = object  # SDL_events.h types
+                              #Checks the event queue for messages and optionally returns them.
+                              #   If 'action' is SDL_ADDEVENT, up to 'numevents' events will be added to
+                              #   the back of the event queue.
+                              #   If 'action' is SDL_PEEKEVENT, up to 'numevents' events at the front
+                              #   of the event queue, matching 'mask', will be returned and will not
+                              #   be removed from the queue.
+                              #   If 'action' is SDL_GETEVENT, up to 'numevents' events at the front
+                              #   of the event queue, matching 'mask', will be returned and will be
+                              #   removed from the queue.
+                              #   This function returns the number of events actually stored, or -1
+                              #   if there was an error.  This function is thread-safe.
+    scancode*: byte           # hardware specific scancode
+    sym*: TKey                # SDL virtual keysym
+    modifier*: TMod           # current key modifiers
+    unicode*: uint16          # translated character
+  
+  TEventAction* = enum        # Application visibility event structure
+    ADDEVENT, PEEKEVENT, GETEVENT
+
+  PActiveEvent* = ptr TActiveEvent
+  TActiveEvent*{.final.} = object  # SDL_ACTIVEEVENT
+                                   # Keyboard event structure
+    kind*: TEventKind
+    gain*: byte              # Whether given states were gained or lost (1/0)
+    state*: byte             # A mask of the focus states
+  
+  PKeyboardEvent* = ptr TKeyboardEvent
+  TKeyboardEvent*{.final.} = object  # SDL_KEYDOWN or SDL_KEYUP
+                                     # Mouse motion event structure
+    kind*: TEventKind
+    which*: byte             # The keyboard device index
+    state*: byte             # SDL_PRESSED or SDL_RELEASED
+    keysym*: TKeySym
+
+  PMouseMotionEvent* = ptr TMouseMotionEvent
+  TMouseMotionEvent*{.final.} = object  # SDL_MOUSEMOTION
+                                        # Mouse button event structure
+    kind*: TEventKind
+    which*: byte             # The mouse device index
+    state*: byte             # The current button state
+    x*, y*: uint16            # The X/Y coordinates of the mouse
+    xrel*: int16             # The relative motion in the X direction
+    yrel*: int16             # The relative motion in the Y direction
+  
+  PMouseButtonEvent* = ptr TMouseButtonEvent
+  TMouseButtonEvent*{.final.} = object  # SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP
+                                        # Joystick axis motion event structure
+    kind*: TEventKind
+    which*: byte             # The mouse device index
+    button*: byte            # The mouse button index
+    state*: byte             # SDL_PRESSED or SDL_RELEASED
+    x*: uint16                # The X coordinates of the mouse at press time
+    y*: uint16                # The Y coordinates of the mouse at press time
+  
+  PJoyAxisEvent* = ptr TJoyAxisEvent
+  TJoyAxisEvent*{.final.} = object  # SDL_JOYAXISMOTION
+                                    # Joystick trackball motion event structure
+    kind*: TEventKind
+    which*: byte             # The joystick device index
+    axis*: byte              # The joystick axis index
+    value*: int16            # The axis value (range: -32768 to 32767)
+  
+  PJoyBallEvent* = ptr TJoyBallEvent
+  TJoyBallEvent*{.final.} = object  # SDL_JOYAVBALLMOTION
+                                    # Joystick hat position change event structure
+    kind*: TEventKind
+    which*: byte             # The joystick device index
+    ball*: byte              # The joystick trackball index
+    xrel*: int16             # The relative motion in the X direction
+    yrel*: int16             # The relative motion in the Y direction
+  
+  PJoyHatEvent* = ptr TJoyHatEvent
+  TJoyHatEvent*{.final.} = object  # SDL_JOYHATMOTION */
+                                   # Joystick button event structure
+    kind*: TEventKind
+    which*: byte             # The joystick device index */
+    hat*: byte               # The joystick hat index */
+    value*: byte             # The hat position value:
+                             # 8   1   2
+                             # 7   0   3
+                             # 6   5   4
+                             # Note that zero means the POV is centered.
+  
+  PJoyButtonEvent* = ptr TJoyButtonEvent
+  TJoyButtonEvent*{.final.} = object  # SDL_JOYBUTTONDOWN or SDL_JOYBUTTONUP
+                                      # The "window resized" event
+                                      # When you get this event, you are
+                                      # responsible for setting a new video
+                                      # mode with the new width and height.
+    kind*: TEventKind
+    which*: byte             # The joystick device index
+    button*: byte            # The joystick button index
+    state*: byte             # SDL_PRESSED or SDL_RELEASED
+  
+  PResizeEvent* = ptr TResizeEvent
+  TResizeEvent*{.final.} = object  # SDL_VIDEORESIZE
+                                   # A user-defined event type
+    kind*: TEventKind
+    w*: cint                   # New width
+    h*: cint                   # New height
+  
+  PUserEvent* = ptr TUserEvent
+  TUserEvent*{.final.} = object  # SDL_USEREVENT through SDL_NUMEVENTS-1
+    kind*: TEventKind
+    code*: cint                # User defined event code
+    data1*: pointer           # User defined data pointer
+    data2*: pointer           # User defined data pointer 
+  
+
+when defined(Unix): 
+  type                        #These are the various supported subsystems under UNIX
+    TSysWm* = enum 
+      SYSWM_X11
+when defined(WINDOWS): 
+  type 
+    PSysWMmsg* = ptr TSysWMmsg
+    TSysWMmsg*{.final.} = object 
+      version*: Tversion
+      hwnd*: THandle          # The window for the message
+      msg*: int               # The type of message
+      wParam*: int32         # WORD message parameter
+      lParam*: int32          # LONG message parameter
+    
+elif defined(Unix): 
+  type                        # The Linux custom event structure
+    PSysWMmsg* = ptr TSysWMmsg
+    TSysWMmsg*{.final.} = object 
+      version*: Tversion
+      subsystem*: TSysWm
+      when false: 
+          event*: TXEvent
+
+    
+else: 
+  type                        # The generic custom event structure
+    PSysWMmsg* = ptr TSysWMmsg
+    TSysWMmsg*{.final.} = object 
+      version*: Tversion
+      data*: int
+
+# The Windows custom window manager information structure
+
+when defined(WINDOWS): 
+  type 
+    PSysWMinfo* = ptr TSysWMinfo
+    TSysWMinfo*{.final.} = object 
+      version*: Tversion
+      window*: THandle        # The display window
+    
+elif defined(Unix): 
+  type 
+    TX11*{.final.} = object 
+      when false: 
+          display*: PDisplay  # The X11 display
+          window*: TWindow    # The X11 display window
+                              # These locking functions should be called around
+                              # any X11 functions using the display variable.
+                              # They lock the event thread, so should not be
+                              # called around event functions or from event filters.
+          lock_func*: pointer
+          unlock_func*: pointer # Introduced in SDL 1.0.2
+          fswindow*: TWindow  # The X11 fullscreen window
+          wmwindow*: TWindow  # The X11 managed input window
+        
+    
+  type 
+    PSysWMinfo* = ptr TSysWMinfo
+    TSysWMinfo*{.final.} = object 
+      version*: Tversion
+      subsystem*: TSysWm
+      X11*: TX11
+
+else: 
+  type # The generic custom window manager information structure
+    PSysWMinfo* = ptr TSysWMinfo
+    TSysWMinfo*{.final.} = object 
+      version*: Tversion
+      data*: int
+
+type 
+  PSysWMEvent* = ptr TSysWMEvent
+  TSysWMEvent*{.final.} = object 
+    kind*: TEventKind
+    msg*: PSysWMmsg
+
+  PExposeEvent* = ptr TExposeEvent
+  TExposeEvent*{.final.} = object
+    kind*: TEventKind
+
+  PQuitEvent* = ptr TQuitEvent
+  TQuitEvent*{.final.} = object
+    kind*: TEventKind
+
+  PEvent* = ptr TEvent
+  TEvent*{.final.} = object  
+    kind*: TEventKind
+    pad: array[0..19, byte]
+  
+  TEventFilter* = proc (event: PEvent): int{.cdecl.} # SDL_video.h types
+                                                     # Useful data types
+  PPSDL_Rect* = ptr PRect
+  PRect* = ptr TRect
+  TRect*{.final.} = object 
+    x*, y*: int16
+    w*, h*: uint16
+
+  Rect* = TRect
+  PColor* = ptr TColor
+  TColor*{.final.} = object 
+    r*: byte
+    g*: byte
+    b*: byte
+    unused*: byte
+
+  PColorArray* = ptr TColorArray
+  TColorArray* = array[0..65000, TColor]
+  PPalette* = ptr TPalette
+  TPalette*{.final.} = object  # Everything in the pixel format structure is read-only
+    ncolors*: int
+    colors*: PColorArray
+
+  PPixelFormat* = ptr TPixelFormat
+  TPixelFormat*{.final.} = object  # The structure passed to the low level blit functions
+    palette*: PPalette
+    bitsPerPixel*: byte
+    bytesPerPixel*: byte
+    rloss*: byte
+    gloss*: byte
+    bloss*: byte
+    aloss*: byte
+    rshift*: byte
+    gshift*: byte
+    bshift*: byte
+    ashift*: byte
+    rMask*: int32
+    gMask*: int32
+    bMask*: int32
+    aMask*: int32
+    colorkey*: int32         # RGB color key information
+    alpha*: byte             # Alpha value information (per-surface alpha)
+  
+  PBlitInfo* = ptr TBlitInfo
+  TBlitInfo*{.final.} = object  # typedef for private surface blitting functions
+    sPixels*: ptr byte
+    sWidth*: int
+    sHeight*: int
+    sSkip*: int
+    dPixels*: ptr byte
+    dWidth*: int
+    dHeight*: int
+    dSkip*: int
+    auxData*: pointer
+    src*: PPixelFormat
+    table*: ptr byte
+    dst*: PPixelFormat
+
+  PSurface* = ptr TSurface
+  TBlit* = proc (src: PSurface, srcrect: PRect, 
+                 dst: PSurface, dstrect: PRect): int{.cdecl.}
+  TSurface*{.final.} = object  # Useful for determining the video hardware capabilities
+    flags*: int32            # Read-only
+    format*: PPixelFormat     # Read-only
+    w*, h*: cint              # Read-only
+    pitch*: uint16            # Read-only
+    pixels*: pointer          # Read-write
+    offset*: cint             # Private
+    hwdata*: pointer          #TPrivate_hwdata;  Hardware-specific surface info
+                              # clipping information:
+    clipRect*: TRect         # Read-only
+    unused1*: int32           # for binary compatibility
+                              # Allow recursive locks
+    locked*: int32            # Private
+                              # info for fast blit mapping to other surfaces
+    blitmap*: pointer         # PSDL_BlitMap; //   Private
+                              # format version, bumped at every change to invalidate blit maps
+    formatVersion*: cint      # Private
+    refcount*: cint
+
+  PVideoInfo* = ptr TVideoInfo
+  TVideoInfo*{.final.} = object  # The YUV hardware video overlay
+    hwAvailable*: byte 
+    blitHw*: byte 
+    unusedBits3*: byte       # Unused at this point
+    videoMem*: int32        # The total amount of video memory (in K)
+    vfmt*: PPixelFormat       # Value: The format of the video surface
+    currentW*: int32        # Value: The current video mode width
+    currentH*: int32        # Value: The current video mode height
+  
+  POverlay* = ptr TOverlay
+  TOverlay*{.final.} = object  # Public enumeration for setting the OpenGL window attributes.
+    format*: int32           # Overlay format
+    w*, h*: int               # Width and height of overlay
+    planes*: int              # Number of planes in the overlay. Usually either 1 or 3
+    pitches*: PUInt16         # An array of pitches, one for each plane. Pitch is the length of a row in bytes.
+    pixels*: ptr ptr byte # An array of pointers to the data of each plane. The overlay should be locked before these pointers are used.
+    hwOverlay*: int32    # This will be set to 1 if the overlay is hardware accelerated.
+  
+  TGLAttr* = enum 
+    GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_ALPHA_SIZE, GL_BUFFER_SIZE, 
+    GL_DOUBLEBUFFER, GL_DEPTH_SIZE, GL_STENCIL_SIZE, GL_ACCUM_RED_SIZE, 
+    GL_ACCUM_GREEN_SIZE, GL_ACCUM_BLUE_SIZE, GL_ACCUM_ALPHA_SIZE, GL_STEREO, 
+    GL_MULTISAMPLEBUFFERS, GL_MULTISAMPLESAMPLES, GL_ACCELERATED_VISUAL, 
+    GL_SWAP_CONTROL
+  PCursor* = ptr TCursor
+  TCursor*{.final.} = object  # SDL_mutex.h types
+    area*: TRect              # The area of the mouse cursor
+    hotX*, hot_y*: int16    # The "tip" of the cursor
+    data*: ptr byte             # B/W cursor data
+    mask*: ptr byte             # B/W cursor mask
+    save*: array[1..2, ptr byte] # Place to save cursor area
+    wmCursor*: pointer       # Window-manager cursor
+  
+
+type 
+  PMutex* = ptr TMutex
+  TMutex*{.final.} = object 
+  Psemaphore* = ptr Tsemaphore
+  Tsemaphore*{.final.} = object 
+  PSem* = ptr TSem
+  TSem* = Tsemaphore
+  PCond* = ptr TCond
+  TCond*{.final.} = object    # SDL_thread.h types
+
+when defined(WINDOWS): 
+  type 
+    TSYS_ThreadHandle* = THandle
+when defined(Unix): 
+  type 
+    TSYS_ThreadHandle* = pointer
+type                          # This is the system-independent thread info structure
+  PThread* = ptr TThread
+  TThread*{.final.} = object  # Helper Types
+                              # Keyboard  State Array ( See demos for how to use )
+    threadid*: int32
+    handle*: TSYS_ThreadHandle
+    status*: int
+    errbuf*: Terror
+    data*: pointer
+
+  PKeyStateArr* = ptr TKeyStateArr
+  TKeyStateArr* = array[0..65000, byte] # Types required so we don't need to use Windows.pas
+  PInteger* = ptr int
+  PByte* = ptr int8
+  PWord* = ptr int16
+  PLongWord* = ptr int32      # General arrays
+  PByteArray* = ptr TByteArray
+  TByteArray* = array[0..32767, int8]
+  PWordArray* = ptr TWordArray
+  TWordArray* = array[0..16383, int16] # Generic procedure pointer
+
+type TEventSeq = set[TEventKind]
+template evconv(procName: expr, ptrName: typedesc, assertions: TEventSeq): stmt {.immediate.} =
+  proc `procName`*(event: PEvent): ptrName =
+    assert(contains(assertions, event.kind))
+    result = cast[ptrName](event)
+
+evconv(evActive, PActiveEvent, {ACTIVEEVENT})
+evconv(evKeyboard, PKeyboardEvent, {KEYDOWN, KEYUP})
+evconv(evMouseMotion, PMouseMotionEvent, {MOUSEMOTION})
+evconv(evMouseButton, PMouseButtonEvent, {MOUSEBUTTONDOWN, MOUSEBUTTONUP})
+evconv(evJoyAxis, PJoyAxisEvent,{JOYAXISMOTION})
+evconv(evJoyBall, PJoyBallEvent, {JOYBALLMOTION})
+evconv(evJoyHat, PJoyHatEvent, {JOYHATMOTION})
+evconv(evJoyButton, PJoyButtonEvent, {JOYBUTTONDOWN, JOYBUTTONUP})
+evconv(evResize, PResizeEvent, {VIDEORESIZE})
+evconv(evExpose, PExposeEvent, {VIDEOEXPOSE})
+evconv(evQuit, PQuitEvent, {QUITEV})
+evconv(evUser, PUserEvent, {USEREVENT})
+evconv(evSysWM, PSysWMEvent, {SYSWMEVENT})
+
+#------------------------------------------------------------------------------
+# initialization
+#------------------------------------------------------------------------------
+# This function loads the SDL dynamically linked library and initializes
+#  the subsystems specified by 'flags' (and those satisfying dependencies)
+#  Unless the SDL_INIT_NOPARACHUTE flag is set, it will install cleanup
+#  signal handlers for some commonly ignored fatal signals (like SIGSEGV)
+
+proc init*(flags: int32): int{.cdecl, importc: "SDL_Init", dynlib: LibName.}
+  # This function initializes specific SDL subsystems
+proc initSubSystem*(flags: int32): int{.cdecl, importc: "SDL_InitSubSystem", 
+    dynlib: LibName.}
+  # This function cleans up specific SDL subsystems
+proc quitSubSystem*(flags: int32){.cdecl, importc: "SDL_QuitSubSystem", 
+                                    dynlib: LibName.}
+  # This function returns mask of the specified subsystems which have
+  #  been initialized.
+  #  If 'flags' is 0, it returns a mask of all initialized subsystems.
+proc wasInit*(flags: int32): int32{.cdecl, importc: "SDL_WasInit", 
+                                      dynlib: LibName.}
+  # This function cleans up all initialized subsystems and unloads the
+  #  dynamically linked library.  You should call it upon all exit conditions.
+proc quit*(){.cdecl, importc: "SDL_Quit", dynlib: LibName.}
+when defined(WINDOWS): 
+  # This should be called from your WinMain() function, if any
+  proc registerApp*(name: cstring, style: int32, hInst: pointer): int{.cdecl, 
+      importc: "SDL_RegisterApp", dynlib: LibName.}
+proc tableSize*(table: cstring): int
+  #------------------------------------------------------------------------------
+  # error-handling
+  #------------------------------------------------------------------------------
+  # Public functions
+proc getError*(): cstring{.cdecl, importc: "SDL_GetError", dynlib: LibName.}
+proc setError*(fmt: cstring){.cdecl, importc: "SDL_SetError", dynlib: LibName.}
+proc clearError*(){.cdecl, importc: "SDL_ClearError", dynlib: LibName.}
+when not (defined(WINDOWS)):
+  proc error*(Code: Terrorcode){.cdecl, importc: "SDL_Error", dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # io handling
+  #------------------------------------------------------------------------------
+  # Functions to create SDL_RWops structures from various data sources
+proc rwFromFile*(filename, mode: cstring): PRWops{.cdecl, 
+    importc: "SDL_RWFromFile", dynlib: LibName.}
+proc freeRW*(area: PRWops){.cdecl, importc: "SDL_FreeRW", dynlib: LibName.}
+  #fp is FILE *fp ???
+proc rwFromFP*(fp: pointer, autoclose: int): PRWops{.cdecl, 
+    importc: "SDL_RWFromFP", dynlib: LibName.}
+proc rwFromMem*(mem: pointer, size: int): PRWops{.cdecl, 
+    importc: "SDL_RWFromMem", dynlib: LibName.}
+proc rwFromConstMem*(mem: pointer, size: int): PRWops{.cdecl, 
+    importc: "SDL_RWFromConstMem", dynlib: LibName.}
+proc allocRW*(): PRWops{.cdecl, importc: "SDL_AllocRW", dynlib: LibName.}
+proc rwSeek*(context: PRWops, offset: int, whence: int): int
+proc rwTell*(context: PRWops): int
+proc rwRead*(context: PRWops, theptr: pointer, size: int, n: int): int
+proc rwWrite*(context: PRWops, theptr: pointer, size: int, n: int): int
+proc rwClose*(context: PRWops): int
+  #------------------------------------------------------------------------------
+  # time-handling
+  #------------------------------------------------------------------------------
+  # Get the number of milliseconds since the SDL library initialization.
+  # Note that this value wraps if the program runs for more than ~49 days.
+proc getTicks*(): int32{.cdecl, importc: "SDL_GetTicks", dynlib: LibName.}
+  # Wait a specified number of milliseconds before returning
+proc delay*(msec: int32){.cdecl, importc: "SDL_Delay", dynlib: LibName.}
+  # Add a new timer to the pool of timers already running.
+  # Returns a timer ID, or NULL when an error occurs.
+proc addTimer*(interval: int32, callback: TNewTimerCallback, param: pointer): PTimerID{.
+    cdecl, importc: "SDL_AddTimer", dynlib: LibName.}
+  # Remove one of the multiple timers knowing its ID.
+  # Returns a boolean value indicating success.
+proc removeTimer*(t: PTimerID): TBool{.cdecl, importc: "SDL_RemoveTimer", 
+                                       dynlib: LibName.}
+proc setTimer*(interval: int32, callback: TTimerCallback): int{.cdecl, 
+    importc: "SDL_SetTimer", dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # audio-routines
+  #------------------------------------------------------------------------------
+  # These functions are used internally, and should not be used unless you
+  #  have a specific need to specify the audio driver you want to use.
+  #  You should normally use SDL_Init() or SDL_InitSubSystem().
+proc audioInit*(driverName: cstring): int{.cdecl, importc: "SDL_AudioInit", 
+    dynlib: LibName.}
+proc audioQuit*(){.cdecl, importc: "SDL_AudioQuit", dynlib: LibName.}
+  # This function fills the given character buffer with the name of the
+  #  current audio driver, and returns a pointer to it if the audio driver has
+  #  been initialized.  It returns NULL if no driver has been initialized.
+proc audioDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, 
+    importc: "SDL_AudioDriverName", dynlib: LibName.}
+  # This function opens the audio device with the desired parameters, and
+  #  returns 0 if successful, placing the actual hardware parameters in the
+  #  structure pointed to by 'obtained'.  If 'obtained' is NULL, the audio
+  #  data passed to the callback function will be guaranteed to be in the
+  #  requested format, and will be automatically converted to the hardware
+  #  audio format if necessary.  This function returns -1 if it failed
+  #  to open the audio device, or couldn't set up the audio thread.
+  #
+  #  When filling in the desired audio spec structure,
+  #   'desired->freq' should be the desired audio frequency in samples-per-second.
+  #   'desired->format' should be the desired audio format.
+  #   'desired->samples' is the desired size of the audio buffer, in samples.
+  #      This number should be a power of two, and may be adjusted by the audio
+  #      driver to a value more suitable for the hardware.  Good values seem to
+  #      range between 512 and 8096 inclusive, depending on the application and
+  #      CPU speed.  Smaller values yield faster response time, but can lead
+  #      to underflow if the application is doing heavy processing and cannot
+  #      fill the audio buffer in time.  A stereo sample consists of both right
+  #      and left channels in LR ordering.
+  #      Note that the number of samples is directly related to time by the
+  #      following formula:  ms = (samples*1000)/freq
+  #   'desired->size' is the size in bytes of the audio buffer, and is
+  #      calculated by SDL_OpenAudio().
+  #   'desired->silence' is the value used to set the buffer to silence,
+  #      and is calculated by SDL_OpenAudio().
+  #   'desired->callback' should be set to a function that will be called
+  #      when the audio device is ready for more data.  It is passed a pointer
+  #      to the audio buffer, and the length in bytes of the audio buffer.
+  #      This function usually runs in a separate thread, and so you should
+  #      protect data structures that it accesses by calling SDL_LockAudio()
+  #      and SDL_UnlockAudio() in your code.
+  #   'desired->userdata' is passed as the first parameter to your callback
+  #      function.
+  #
+  #  The audio device starts out playing silence when it's opened, and should
+  #  be enabled for playing by calling SDL_PauseAudio(0) when you are ready
+  #  for your audio callback function to be called.  Since the audio driver
+  #  may modify the requested size of the audio buffer, you should allocate
+  #  any local mixing buffers after you open the audio device.
+proc openAudio*(desired, obtained: PAudioSpec): int{.cdecl, 
+    importc: "SDL_OpenAudio", dynlib: LibName.}
+  # Get the current audio state:
+proc getAudioStatus*(): TAudiostatus{.cdecl, importc: "SDL_GetAudioStatus", 
+                                      dynlib: LibName.}
+  # This function pauses and unpauses the audio callback processing.
+  #  It should be called with a parameter of 0 after opening the audio
+  #  device to start playing sound.  This is so you can safely initialize
+  #  data for your callback function after opening the audio device.
+  #  Silence will be written to the audio device during the pause.
+proc pauseAudio*(pauseOn: int){.cdecl, importc: "SDL_PauseAudio", 
+                                 dynlib: LibName.}
+  # This function loads a WAVE from the data source, automatically freeing
+  #  that source if 'freesrc' is non-zero.  For example, to load a WAVE file,
+  #  you could do:
+  #  SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
+  #
+  #  If this function succeeds, it returns the given SDL_AudioSpec,
+  #  filled with the audio data format of the wave data, and sets
+  #  'audio_buf' to a malloc()'d buffer containing the audio data,
+  #  and sets 'audio_len' to the length of that audio buffer, in bytes.
+  #  You need to free the audio buffer with SDL_FreeWAV() when you are
+  #  done with it.
+  #
+  #  This function returns NULL and sets the SDL error message if the
+  #  wave file cannot be opened, uses an unknown data format, or is
+  #  corrupt.  Currently raw and MS-ADPCM WAVE files are supported.
+proc loadWAV_RW*(src: PRWops, freesrc: int, spec: PAudioSpec, audioBuf: ptr byte, 
+                 audiolen: PUInt32): PAudioSpec{.cdecl, 
+    importc: "SDL_LoadWAV_RW", dynlib: LibName.}
+  # Compatibility convenience function -- loads a WAV from a file
+proc loadWAV*(filename: cstring, spec: PAudioSpec, audioBuf: ptr byte, 
+              audiolen: PUInt32): PAudioSpec
+  # This function frees data previously allocated with SDL_LoadWAV_RW()
+proc freeWAV*(audioBuf: ptr byte){.cdecl, importc: "SDL_FreeWAV", dynlib: LibName.}
+  # This function takes a source format and rate and a destination format
+  #  and rate, and initializes the 'cvt' structure with information needed
+  #  by SDL_ConvertAudio() to convert a buffer of audio data from one format
+  #  to the other.
+  #  This function returns 0, or -1 if there was an error.
+proc buildAudioCVT*(cvt: PAudioCVT, srcFormat: uint16, srcChannels: byte, 
+                    srcRate: int, dstFormat: uint16, dstChannels: byte, 
+                    dstRate: int): int{.cdecl, importc: "SDL_BuildAudioCVT", 
+    dynlib: LibName.}
+  # Once you have initialized the 'cvt' structure using SDL_BuildAudioCVT(),
+  #  created an audio buffer cvt->buf, and filled it with cvt->len bytes of
+  #  audio data in the source format, this function will convert it in-place
+  #  to the desired format.
+  #  The data conversion may expand the size of the audio data, so the buffer
+  #  cvt->buf should be allocated after the cvt structure is initialized by
+  #  SDL_BuildAudioCVT(), and should be cvt->len*cvt->len_mult bytes long.
+proc convertAudio*(cvt: PAudioCVT): int{.cdecl, importc: "SDL_ConvertAudio", 
+    dynlib: LibName.}
+  # This takes two audio buffers of the playing audio format and mixes
+  #  them, performing addition, volume adjustment, and overflow clipping.
+  #  The volume ranges from 0 - 128, and should be set to SDL_MIX_MAXVOLUME
+  #  for full audio volume.  Note this does not change hardware volume.
+  #  This is provided for convenience -- you can mix your own audio data.
+proc mixAudio*(dst, src: ptr byte, length: int32, volume: int){.cdecl, 
+    importc: "SDL_MixAudio", dynlib: LibName.}
+  # The lock manipulated by these functions protects the callback function.
+  #  During a LockAudio/UnlockAudio pair, you can be guaranteed that the
+  #  callback function is not running.  Do not call these from the callback
+  #  function or you will cause deadlock.
+proc lockAudio*(){.cdecl, importc: "SDL_LockAudio", dynlib: LibName.}
+proc unlockAudio*(){.cdecl, importc: "SDL_UnlockAudio", dynlib: LibName.}
+  # This function shuts down audio processing and closes the audio device.
+proc closeAudio*(){.cdecl, importc: "SDL_CloseAudio", dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # CD-routines
+  #------------------------------------------------------------------------------
+  # Returns the number of CD-ROM drives on the system, or -1 if
+  #  SDL_Init() has not been called with the SDL_INIT_CDROM flag.
+proc cdNumDrives*(): int{.cdecl, importc: "SDL_CDNumDrives", dynlib: LibName.}
+  # Returns a human-readable, system-dependent identifier for the CD-ROM.
+  #   Example:
+  #   "/dev/cdrom"
+  #   "E:"
+  #   "/dev/disk/ide/1/master"
+proc cdName*(drive: int): cstring{.cdecl, importc: "SDL_CDName", dynlib: LibName.}
+  # Opens a CD-ROM drive for access.  It returns a drive handle on success,
+  #  or NULL if the drive was invalid or busy.  This newly opened CD-ROM
+  #  becomes the default CD used when other CD functions are passed a NULL
+  #  CD-ROM handle.
+  #  Drives are numbered starting with 0.  Drive 0 is the system default CD-ROM.
+proc cdOpen*(drive: int): PCD{.cdecl, importc: "SDL_CDOpen", dynlib: LibName.}
+  # This function returns the current status of the given drive.
+  #  If the drive has a CD in it, the table of contents of the CD and current
+  #  play position of the CD will be stored in the SDL_CD structure.
+proc cdStatus*(cdrom: PCD): TCDStatus{.cdecl, importc: "SDL_CDStatus", 
+                                       dynlib: LibName.}
+  #  Play the given CD starting at 'start_track' and 'start_frame' for 'ntracks'
+  #   tracks and 'nframes' frames.  If both 'ntrack' and 'nframe' are 0, play
+  #   until the end of the CD.  This function will skip data tracks.
+  #   This function should only be called after calling SDL_CDStatus() to
+  #   get track information about the CD.
+  #
+  #   For example:
+  #   // Play entire CD:
+  #  if ( CD_INDRIVE(SDL_CDStatus(cdrom)) ) then
+  #    SDL_CDPlayTracks(cdrom, 0, 0, 0, 0);
+  #   // Play last track:
+  #   if ( CD_INDRIVE(SDL_CDStatus(cdrom)) ) then
+  #   begin
+  #    SDL_CDPlayTracks(cdrom, cdrom->numtracks-1, 0, 0, 0);
+  #   end;
+  #
+  #   // Play first and second track and 10 seconds of third track:
+  #   if ( CD_INDRIVE(SDL_CDStatus(cdrom)) )
+  #    SDL_CDPlayTracks(cdrom, 0, 0, 2, 10);
+  #
+  #   This function returns 0, or -1 if there was an error.
+proc cdPlayTracks*(cdrom: PCD, startTrack: int, startFrame: int, ntracks: int, 
+                   nframes: int): int{.cdecl, importc: "SDL_CDPlayTracks", 
+                                       dynlib: LibName.}
+  #  Play the given CD starting at 'start' frame for 'length' frames.
+  #   It returns 0, or -1 if there was an error.
+proc cdPlay*(cdrom: PCD, start: int, len: int): int{.cdecl, 
+    importc: "SDL_CDPlay", dynlib: LibName.}
+  # Pause play -- returns 0, or -1 on error
+proc cdPause*(cdrom: PCD): int{.cdecl, importc: "SDL_CDPause", dynlib: LibName.}
+  # Resume play -- returns 0, or -1 on error
+proc cdResume*(cdrom: PCD): int{.cdecl, importc: "SDL_CDResume", dynlib: LibName.}
+  # Stop play -- returns 0, or -1 on error
+proc cdStop*(cdrom: PCD): int{.cdecl, importc: "SDL_CDStop", dynlib: LibName.}
+  # Eject CD-ROM -- returns 0, or -1 on error
+proc cdEject*(cdrom: PCD): int{.cdecl, importc: "SDL_CDEject", dynlib: LibName.}
+  # Closes the handle for the CD-ROM drive
+proc cdClose*(cdrom: PCD){.cdecl, importc: "SDL_CDClose", dynlib: LibName.}
+  # Given a status, returns true if there's a disk in the drive
+proc cdInDrive*(status: TCDStatus): bool
+
+proc numJoysticks*(): int{.cdecl, importc: "SDL_NumJoysticks", dynlib: LibName.}
+  # Get the implementation dependent name of a joystick.
+  #  This can be called before any joysticks are opened.
+  #  If no name can be found, this function returns NULL.
+proc joystickName*(index: int): cstring{.cdecl, importc: "SDL_JoystickName", 
+    dynlib: LibName.}
+  # Open a joystick for use - the index passed as an argument refers to
+  #  the N'th joystick on the system.  This index is the value which will
+  #  identify this joystick in future joystick events.
+  #
+  #  This function returns a joystick identifier, or NULL if an error occurred.
+proc joystickOpen*(index: int): PJoystick{.cdecl, importc: "SDL_JoystickOpen", 
+    dynlib: LibName.}
+  # Returns 1 if the joystick has been opened, or 0 if it has not.
+proc joystickOpened*(index: int): int{.cdecl, importc: "SDL_JoystickOpened", 
+                                       dynlib: LibName.}
+  # Get the device index of an opened joystick.
+proc joystickIndex*(joystick: PJoystick): int{.cdecl, 
+    importc: "SDL_JoystickIndex", dynlib: LibName.}
+  # Get the number of general axis controls on a joystick
+proc joystickNumAxes*(joystick: PJoystick): int{.cdecl, 
+    importc: "SDL_JoystickNumAxes", dynlib: LibName.}
+  # Get the number of trackballs on a joystick
+  #  Joystick trackballs have only relative motion events associated
+  #  with them and their state cannot be polled.
+proc joystickNumBalls*(joystick: PJoystick): int{.cdecl, 
+    importc: "SDL_JoystickNumBalls", dynlib: LibName.}
+  # Get the number of POV hats on a joystick
+proc joystickNumHats*(joystick: PJoystick): int{.cdecl, 
+    importc: "SDL_JoystickNumHats", dynlib: LibName.}
+  # Get the number of buttons on a joystick
+proc joystickNumButtons*(joystick: PJoystick): int{.cdecl, 
+    importc: "SDL_JoystickNumButtons", dynlib: LibName.}
+  # Update the current state of the open joysticks.
+  #  This is called automatically by the event loop if any joystick
+  #  events are enabled.
+proc joystickUpdate*(){.cdecl, importc: "SDL_JoystickUpdate", dynlib: LibName.}
+  # Enable/disable joystick event polling.
+  #  If joystick events are disabled, you must call SDL_JoystickUpdate()
+  #  yourself and check the state of the joystick when you want joystick
+  #  information.
+  #  The state can be one of SDL_QUERY, SDL_ENABLE or SDL_IGNORE.
+proc joystickEventState*(state: int): int{.cdecl, 
+    importc: "SDL_JoystickEventState", dynlib: LibName.}
+  # Get the current state of an axis control on a joystick
+  #  The state is a value ranging from -32768 to 32767.
+  #  The axis indices start at index 0.
+proc joystickGetAxis*(joystick: PJoystick, axis: int): int16{.cdecl, 
+    importc: "SDL_JoystickGetAxis", dynlib: LibName.}
+  # The hat indices start at index 0.
+proc joystickGetHat*(joystick: PJoystick, hat: int): byte{.cdecl, 
+    importc: "SDL_JoystickGetHat", dynlib: LibName.}
+  # Get the ball axis change since the last poll
+  #  This returns 0, or -1 if you passed it invalid parameters.
+  #  The ball indices start at index 0.
+proc joystickGetBall*(joystick: PJoystick, ball: int, dx: var int, dy: var int): int{.
+    cdecl, importc: "SDL_JoystickGetBall", dynlib: LibName.}
+  # Get the current state of a button on a joystick
+  #  The button indices start at index 0.
+proc joystickGetButton*(joystick: PJoystick, button: int): byte{.cdecl, 
+    importc: "SDL_JoystickGetButton", dynlib: LibName.}
+  # Close a joystick previously opened with SDL_JoystickOpen()
+proc joystickClose*(joystick: PJoystick){.cdecl, importc: "SDL_JoystickClose", 
+    dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # event-handling
+  #------------------------------------------------------------------------------
+  # Pumps the event loop, gathering events from the input devices.
+  #  This function updates the event queue and internal input device state.
+  #  This should only be run in the thread that sets the video mode.
+proc pumpEvents*(){.cdecl, importc: "SDL_PumpEvents", dynlib: LibName.}
+  # Checks the event queue for messages and optionally returns them.
+  #  If 'action' is SDL_ADDEVENT, up to 'numevents' events will be added to
+  #  the back of the event queue.
+  #  If 'action' is SDL_PEEKEVENT, up to 'numevents' events at the front
+  #  of the event queue, matching 'mask', will be returned and will not
+  #  be removed from the queue.
+  #  If 'action' is SDL_GETEVENT, up to 'numevents' events at the front
+  #  of the event queue, matching 'mask', will be returned and will be
+  #  removed from the queue.
+  #  This function returns the number of events actually stored, or -1
+  #  if there was an error.  This function is thread-safe.
+proc peepEvents*(events: PEvent, numevents: int, action: TEventAction, 
+                 mask: int32): int{.cdecl, importc: "SDL_PeepEvents", 
+                                     dynlib: LibName.}
+  # Polls for currently pending events, and returns 1 if there are any pending
+  #   events, or 0 if there are none available.  If 'event' is not NULL, the next
+  #   event is removed from the queue and stored in that area.
+proc pollEvent*(event: PEvent): int{.cdecl, importc: "SDL_PollEvent", 
+                                     dynlib: LibName.}
+  #  Waits indefinitely for the next available event, returning 1, or 0 if there
+  #   was an error while waiting for events.  If 'event' is not NULL, the next
+  #   event is removed from the queue and stored in that area.
+proc waitEvent*(event: PEvent): int{.cdecl, importc: "SDL_WaitEvent", 
+                                     dynlib: LibName.}
+proc pushEvent*(event: PEvent): int{.cdecl, importc: "SDL_PushEvent", 
+                                     dynlib: LibName.}
+  # If the filter returns 1, then the event will be added to the internal queue.
+  #  If it returns 0, then the event will be dropped from the queue, but the
+  #  internal state will still be updated.  This allows selective filtering of
+  #  dynamically arriving events.
+  #
+  #  WARNING:  Be very careful of what you do in the event filter function, as
+  #            it may run in a different thread!
+  #
+  #  There is one caveat when dealing with the SDL_QUITEVENT event type.  The
+  #  event filter is only called when the window manager desires to close the
+  #  application window.  If the event filter returns 1, then the window will
+  #  be closed, otherwise the window will remain open if possible.
+  #  If the quit event is generated by an interrupt signal, it will bypass the
+  #  internal queue and be delivered to the application at the next event poll.
+proc setEventFilter*(filter: TEventFilter){.cdecl, 
+    importc: "SDL_SetEventFilter", dynlib: LibName.}
+  # Return the current event filter - can be used to "chain" filters.
+  #  If there is no event filter set, this function returns NULL.
+proc getEventFilter*(): TEventFilter{.cdecl, importc: "SDL_GetEventFilter", 
+                                      dynlib: LibName.}
+  # This function allows you to set the state of processing certain events.
+  #  If 'state' is set to SDL_IGNORE, that event will be automatically dropped
+  #  from the event queue and will not event be filtered.
+  #  If 'state' is set to SDL_ENABLE, that event will be processed normally.
+  #  If 'state' is set to SDL_QUERY, SDL_EventState() will return the
+  #  current processing state of the specified event.
+proc eventState*(theType: byte, state: int): byte{.cdecl, 
+    importc: "SDL_EventState", dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # Version Routines
+  #------------------------------------------------------------------------------
+  # This macro can be used to fill a version structure with the compile-time
+  #  version of the SDL library.
+proc version*(x: var Tversion)
+  # This macro turns the version numbers into a numeric value:
+  #   (1,2,3) -> (1203)
+  #   This assumes that there will never be more than 100 patchlevels
+proc versionnum*(x, y, z: int): int
+  # This is the version number macro for the current SDL version
+proc compiledversion*(): int
+  # This macro will evaluate to true if compiled with SDL at least X.Y.Z
+proc versionAtleast*(x, y, z: int): bool
+  # This function gets the version of the dynamically linked SDL library.
+  #  it should NOT be used to fill a version structure, instead you should
+  #  use the SDL_Version() macro.
+proc linkedVersion*(): PVersion{.cdecl, importc: "SDL_Linked_Version", 
+                                  dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # video
+  #------------------------------------------------------------------------------
+  # These functions are used internally, and should not be used unless you
+  #  have a specific need to specify the video driver you want to use.
+  #  You should normally use SDL_Init() or SDL_InitSubSystem().
+  #
+  #  SDL_VideoInit() initializes the video subsystem -- sets up a connection
+  #  to the window manager, etc, and determines the current video mode and
+  #  pixel format, but does not initialize a window or graphics mode.
+  #  Note that event handling is activated by this routine.
+  #
+  #  If you use both sound and video in your application, you need to call
+  #  SDL_Init() before opening the sound device, otherwise under Win32 DirectX,
+  #  you won't be able to set full-screen display modes.
+proc videoInit*(driverName: cstring, flags: int32): int{.cdecl, 
+    importc: "SDL_VideoInit", dynlib: LibName.}
+proc videoQuit*(){.cdecl, importc: "SDL_VideoQuit", dynlib: LibName.}
+  # This function fills the given character buffer with the name of the
+  #  video driver, and returns a pointer to it if the video driver has
+  #  been initialized.  It returns NULL if no driver has been initialized.
+proc videoDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, 
+    importc: "SDL_VideoDriverName", dynlib: LibName.}
+  # This function returns a pointer to the current display surface.
+  #  If SDL is doing format conversion on the display surface, this
+  #  function returns the publicly visible surface, not the real video
+  #  surface.
+proc getVideoSurface*(): PSurface{.cdecl, importc: "SDL_GetVideoSurface", 
+                                   dynlib: LibName.}
+  # This function returns a read-only pointer to information about the
+  #  video hardware.  If this is called before SDL_SetVideoMode(), the 'vfmt'
+  #  member of the returned structure will contain the pixel format of the
+  #  "best" video mode.
+proc getVideoInfo*(): PVideoInfo{.cdecl, importc: "SDL_GetVideoInfo", 
+                                  dynlib: LibName.}
+  # Check to see if a particular video mode is supported.
+  #  It returns 0 if the requested mode is not supported under any bit depth,
+  #  or returns the bits-per-pixel of the closest available mode with the
+  #  given width and height.  If this bits-per-pixel is different from the
+  #  one used when setting the video mode, SDL_SetVideoMode() will succeed,
+  #  but will emulate the requested bits-per-pixel with a shadow surface.
+  #
+  #  The arguments to SDL_VideoModeOK() are the same ones you would pass to
+  #  SDL_SetVideoMode()
+proc videoModeOK*(width, height, bpp: int, flags: int32): int{.cdecl, 
+    importc: "SDL_VideoModeOK", importc: "SDL_VideoModeOK", dynlib: LibName.}
+  # Return a pointer to an array of available screen dimensions for the
+  #  given format and video flags, sorted largest to smallest.  Returns
+  #  NULL if there are no dimensions available for a particular format,
+  #  or (SDL_Rect **)-1 if any dimension is okay for the given format.
+  #
+  #  if 'format' is NULL, the mode list will be for the format given
+  #  by SDL_GetVideoInfo( ) - > vfmt
+proc listModes*(format: PPixelFormat, flags: int32): PPSDL_Rect{.cdecl, 
+    importc: "SDL_ListModes", dynlib: LibName.}
+  # Set up a video mode with the specified width, height and bits-per-pixel.
+  #
+  #  If 'bpp' is 0, it is treated as the current display bits per pixel.
+  #
+  #  If SDL_ANYFORMAT is set in 'flags', the SDL library will try to set the
+  #  requested bits-per-pixel, but will return whatever video pixel format is
+  #  available.  The default is to emulate the requested pixel format if it
+  #  is not natively available.
+  #
+  #  If SDL_HWSURFACE is set in 'flags', the video surface will be placed in
+  #  video memory, if possible, and you may have to call SDL_LockSurface()
+  #  in order to access the raw framebuffer.  Otherwise, the video surface
+  #  will be created in system memory.
+  #
+  #  If SDL_ASYNCBLIT is set in 'flags', SDL will try to perform rectangle
+  #  updates asynchronously, but you must always lock before accessing pixels.
+  #  SDL will wait for updates to complete before returning from the lock.
+  #
+  #  If SDL_HWPALETTE is set in 'flags', the SDL library will guarantee
+  #  that the colors set by SDL_SetColors() will be the colors you get.
+  #  Otherwise, in 8-bit mode, SDL_SetColors() may not be able to set all
+  #  of the colors exactly the way they are requested, and you should look
+  #  at the video surface structure to determine the actual palette.
+  #  If SDL cannot guarantee that the colors you request can be set,
+  #  i.e. if the colormap is shared, then the video surface may be created
+  #  under emulation in system memory, overriding the SDL_HWSURFACE flag.
+  #
+  #  If SDL_FULLSCREEN is set in 'flags', the SDL library will try to set
+  #  a fullscreen video mode.  The default is to create a windowed mode
+  #  if the current graphics system has a window manager.
+  #  If the SDL library is able to set a fullscreen video mode, this flag
+  #  will be set in the surface that is returned.
+  #
+  #  If SDL_DOUBLEBUF is set in 'flags', the SDL library will try to set up
+  #  two surfaces in video memory and swap between them when you call
+  #  SDL_Flip().  This is usually slower than the normal single-buffering
+  #  scheme, but prevents "tearing" artifacts caused by modifying video
+  #  memory while the monitor is refreshing.  It should only be used by
+  #  applications that redraw the entire screen on every update.
+  #
+  #  This function returns the video framebuffer surface, or NULL if it fails.
+proc setVideoMode*(width, height, bpp: int, flags: uint32): PSurface{.cdecl, 
+    importc: "SDL_SetVideoMode", dynlib: LibName.}
+  # Makes sure the given list of rectangles is updated on the given screen.
+  #  If 'x', 'y', 'w' and 'h' are all 0, SDL_UpdateRect will update the entire
+  #  screen.
+  #  These functions should not be called while 'screen' is locked.
+proc updateRects*(screen: PSurface, numrects: int, rects: PRect){.cdecl, 
+    importc: "SDL_UpdateRects", dynlib: LibName.}
+proc updateRect*(screen: PSurface, x, y: int32, w, h: int32){.cdecl, 
+    importc: "SDL_UpdateRect", dynlib: LibName.}
+  # On hardware that supports double-buffering, this function sets up a flip
+  #  and returns.  The hardware will wait for vertical retrace, and then swap
+  #  video buffers before the next video surface blit or lock will return.
+  #  On hardware that doesn not support double-buffering, this is equivalent
+  #  to calling SDL_UpdateRect(screen, 0, 0, 0, 0);
+  #  The SDL_DOUBLEBUF flag must have been passed to SDL_SetVideoMode() when
+  #  setting the video mode for this function to perform hardware flipping.
+  #  This function returns 0 if successful, or -1 if there was an error.
+proc flip*(screen: PSurface): int{.cdecl, importc: "SDL_Flip", dynlib: LibName.}
+  # Set the gamma correction for each of the color channels.
+  #  The gamma values range (approximately) between 0.1 and 10.0
+  #
+  #  If this function isn't supported directly by the hardware, it will
+  #  be emulated using gamma ramps, if available.  If successful, this
+  #  function returns 0, otherwise it returns -1.
+proc setGamma*(redgamma: float32, greengamma: float32, bluegamma: float32): int{.
+    cdecl, importc: "SDL_SetGamma", dynlib: LibName.}
+  # Set the gamma translation table for the red, green, and blue channels
+  #  of the video hardware.  Each table is an array of 256 16-bit quantities,
+  #  representing a mapping between the input and output for that channel.
+  #  The input is the index into the array, and the output is the 16-bit
+  #  gamma value at that index, scaled to the output color precision.
+  #
+  #  You may pass NULL for any of the channels to leave it unchanged.
+  #  If the call succeeds, it will return 0.  If the display driver or
+  #  hardware does not support gamma translation, or otherwise fails,
+  #  this function will return -1.
+proc setGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): int{.
+    cdecl, importc: "SDL_SetGammaRamp", dynlib: LibName.}
+  # Retrieve the current values of the gamma translation tables.
+  #
+  #  You must pass in valid pointers to arrays of 256 16-bit quantities.
+  #  Any of the pointers may be NULL to ignore that channel.
+  #  If the call succeeds, it will return 0.  If the display driver or
+  #  hardware does not support gamma translation, or otherwise fails,
+  #  this function will return -1.
+proc getGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): int{.
+    cdecl, importc: "SDL_GetGammaRamp", dynlib: LibName.}
+  # Sets a portion of the colormap for the given 8-bit surface.  If 'surface'
+  #  is not a palettized surface, this function does nothing, returning 0.
+  #  If all of the colors were set as passed to SDL_SetColors(), it will
+  #  return 1.  If not all the color entries were set exactly as given,
+  #  it will return 0, and you should look at the surface palette to
+  #  determine the actual color palette.
+  #
+  #  When 'surface' is the surface associated with the current display, the
+  #  display colormap will be updated with the requested colors.  If
+  #  SDL_HWPALETTE was set in SDL_SetVideoMode() flags, SDL_SetColors()
+  #  will always return 1, and the palette is guaranteed to be set the way
+  #  you desire, even if the window colormap has to be warped or run under
+  #  emulation.
+proc setColors*(surface: PSurface, colors: PColor, firstcolor: int, ncolors: int): int{.
+    cdecl, importc: "SDL_SetColors", dynlib: LibName.}
+  # Sets a portion of the colormap for a given 8-bit surface.
+  #  'flags' is one or both of:
+  #  SDL_LOGPAL  -- set logical palette, which controls how blits are mapped
+  #                 to/from the surface,
+  #  SDL_PHYSPAL -- set physical palette, which controls how pixels look on
+  #                 the screen
+  #  Only screens have physical palettes. Separate change of physical/logical
+  #  palettes is only possible if the screen has SDL_HWPALETTE set.
+  #
+  #  The return value is 1 if all colours could be set as requested, and 0
+  #  otherwise.
+  #
+  #  SDL_SetColors() is equivalent to calling this function with
+  #  flags = (SDL_LOGPAL or SDL_PHYSPAL).
+proc setPalette*(surface: PSurface, flags: int, colors: PColor, firstcolor: int, 
+                 ncolors: int): int{.cdecl, importc: "SDL_SetPalette", 
+                                     dynlib: LibName.}
+  # Maps an RGB triple to an opaque pixel value for a given pixel format
+proc mapRGB*(format: PPixelFormat, r: byte, g: byte, b: byte): int32{.cdecl, 
+    importc: "SDL_MapRGB", dynlib: LibName.}
+  # Maps an RGBA quadruple to a pixel value for a given pixel format
+proc mapRGBA*(format: PPixelFormat, r: byte, g: byte, b: byte, a: byte): int32{.
+    cdecl, importc: "SDL_MapRGBA", dynlib: LibName.}
+  # Maps a pixel value into the RGB components for a given pixel format
+proc getRGB*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr byte){.
+    cdecl, importc: "SDL_GetRGB", dynlib: LibName.}
+  # Maps a pixel value into the RGBA components for a given pixel format
+proc getRGBA*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr byte, 
+              a: ptr byte){.cdecl, importc: "SDL_GetRGBA", dynlib: LibName.}
+  # Allocate and free an RGB surface (must be called after SDL_SetVideoMode)
+  #  If the depth is 4 or 8 bits, an empty palette is allocated for the surface.
+  #  If the depth is greater than 8 bits, the pixel format is set using the
+  #  flags '[RGB]mask'.
+  #  If the function runs out of memory, it will return NULL.
+  #
+  #  The 'flags' tell what kind of surface to create.
+  #  SDL_SWSURFACE means that the surface should be created in system memory.
+  #  SDL_HWSURFACE means that the surface should be created in video memory,
+  #  with the same format as the display surface.  This is useful for surfaces
+  #  that will not change much, to take advantage of hardware acceleration
+  #  when being blitted to the display surface.
+  #  SDL_ASYNCBLIT means that SDL will try to perform asynchronous blits with
+  #  this surface, but you must always lock it before accessing the pixels.
+  #  SDL will wait for current blits to finish before returning from the lock.
+  #  SDL_SRCCOLORKEY indicates that the surface will be used for colorkey blits.
+  #  If the hardware supports acceleration of colorkey blits between
+  #  two surfaces in video memory, SDL will try to place the surface in
+  #  video memory. If this isn't possible or if there is no hardware
+  #  acceleration available, the surface will be placed in system memory.
+  #  SDL_SRCALPHA means that the surface will be used for alpha blits and
+  #  if the hardware supports hardware acceleration of alpha blits between
+  #  two surfaces in video memory, to place the surface in video memory
+  #  if possible, otherwise it will be placed in system memory.
+  #  If the surface is created in video memory, blits will be _much_ faster,
+  #  but the surface format must be identical to the video surface format,
+  #  and the only way to access the pixels member of the surface is to use
+  #  the SDL_LockSurface() and SDL_UnlockSurface() calls.
+  #  If the requested surface actually resides in video memory, SDL_HWSURFACE
+  #  will be set in the flags member of the returned surface.  If for some
+  #  reason the surface could not be placed in video memory, it will not have
+  #  the SDL_HWSURFACE flag set, and will be created in system memory instead.
+proc allocSurface*(flags: int32, width, height, depth: int, 
+                   rMask, gMask, bMask, aMask: int32): PSurface
+proc createRGBSurface*(flags: int32, width, height, depth: int, 
+                       rMask, gMask, bMask, aMask: int32): PSurface{.cdecl, 
+    importc: "SDL_CreateRGBSurface", dynlib: LibName.}
+proc createRGBSurfaceFrom*(pixels: pointer, width, height, depth, pitch: int, 
+                           rMask, gMask, bMask, aMask: int32): PSurface{.cdecl, 
+    importc: "SDL_CreateRGBSurfaceFrom", dynlib: LibName.}
+proc freeSurface*(surface: PSurface){.cdecl, importc: "SDL_FreeSurface", 
+                                      dynlib: LibName.}
+proc mustLock*(surface: PSurface): bool
+  # SDL_LockSurface() sets up a surface for directly accessing the pixels.
+  #  Between calls to SDL_LockSurface()/SDL_UnlockSurface(), you can write
+  #  to and read from 'surface->pixels', using the pixel format stored in
+  #  'surface->format'.  Once you are done accessing the surface, you should
+  #  use SDL_UnlockSurface() to release it.
+  #
+  #  Not all surfaces require locking.  If SDL_MUSTLOCK(surface) evaluates
+  #  to 0, then you can read and write to the surface at any time, and the
+  #  pixel format of the surface will not change.  In particular, if the
+  #  SDL_HWSURFACE flag is not given when calling SDL_SetVideoMode(), you
+  #  will not need to lock the display surface before accessing it.
+  #
+  #  No operating system or library calls should be made between lock/unlock
+  #  pairs, as critical system locks may be held during this time.
+  #
+  #  SDL_LockSurface() returns 0, or -1 if the surface couldn't be locked.
+proc lockSurface*(surface: PSurface): int{.cdecl, importc: "SDL_LockSurface", 
+    dynlib: LibName.}
+proc unlockSurface*(surface: PSurface){.cdecl, importc: "SDL_UnlockSurface", 
+                                        dynlib: LibName.}
+  # Load a surface from a seekable SDL data source (memory or file.)
+  #  If 'freesrc' is non-zero, the source will be closed after being read.
+  #  Returns the new surface, or NULL if there was an error.
+  #  The new surface should be freed with SDL_FreeSurface().
+proc loadBMP_RW*(src: PRWops, freesrc: int): PSurface{.cdecl, 
+    importc: "SDL_LoadBMP_RW", dynlib: LibName.}
+  # Convenience macro -- load a surface from a file
+proc loadBMP*(filename: cstring): PSurface
+  # Save a surface to a seekable SDL data source (memory or file.)
+  #  If 'freedst' is non-zero, the source will be closed after being written.
+  #  Returns 0 if successful or -1 if there was an error.
+proc saveBMP_RW*(surface: PSurface, dst: PRWops, freedst: int): int{.cdecl, 
+    importc: "SDL_SaveBMP_RW", dynlib: LibName.}
+  # Convenience macro -- save a surface to a file
+proc saveBMP*(surface: PSurface, filename: cstring): int
+  # Sets the color key (transparent pixel) in a blittable surface.
+  #  If 'flag' is SDL_SRCCOLORKEY (optionally OR'd with SDL_RLEACCEL),
+  #  'key' will be the transparent pixel in the source image of a blit.
+  #  SDL_RLEACCEL requests RLE acceleration for the surface if present,
+  #  and removes RLE acceleration if absent.
+  #  If 'flag' is 0, this function clears any current color key.
+  #  This function returns 0, or -1 if there was an error.
+proc setColorKey*(surface: PSurface, flag, key: int32): int{.cdecl, 
+    importc: "SDL_SetColorKey", dynlib: LibName.}
+  # This function sets the alpha value for the entire surface, as opposed to
+  #  using the alpha component of each pixel. This value measures the range
+  #  of transparency of the surface, 0 being completely transparent to 255
+  #  being completely opaque. An 'alpha' value of 255 causes blits to be
+  #  opaque, the source pixels copied to the destination (the default). Note
+  #  that per-surface alpha can be combined with colorkey transparency.
+  #
+  #  If 'flag' is 0, alpha blending is disabled for the surface.
+  #  If 'flag' is SDL_SRCALPHA, alpha blending is enabled for the surface.
+  #  OR:ing the flag with SDL_RLEACCEL requests RLE acceleration for the
+  #  surface; if SDL_RLEACCEL is not specified, the RLE accel will be removed.
+proc setAlpha*(surface: PSurface, flag: int32, alpha: byte): int{.cdecl, 
+    importc: "SDL_SetAlpha", dynlib: LibName.}
+  # Sets the clipping rectangle for the destination surface in a blit.
+  #
+  #  If the clip rectangle is NULL, clipping will be disabled.
+  #  If the clip rectangle doesn't intersect the surface, the function will
+  #  return SDL_FALSE and blits will be completely clipped.  Otherwise the
+  #  function returns SDL_TRUE and blits to the surface will be clipped to
+  #  the intersection of the surface area and the clipping rectangle.
+  #
+  #  Note that blits are automatically clipped to the edges of the source
+  #  and destination surfaces.
+proc setClipRect*(surface: PSurface, rect: PRect){.cdecl, 
+    importc: "SDL_SetClipRect", dynlib: LibName.}
+  # Gets the clipping rectangle for the destination surface in a blit.
+  #  'rect' must be a pointer to a valid rectangle which will be filled
+  #  with the correct values.
+proc getClipRect*(surface: PSurface, rect: PRect){.cdecl, 
+    importc: "SDL_GetClipRect", dynlib: LibName.}
+  # Creates a new surface of the specified format, and then copies and maps
+  #  the given surface to it so the blit of the converted surface will be as
+  #  fast as possible.  If this function fails, it returns NULL.
+  #
+  #  The 'flags' parameter is passed to SDL_CreateRGBSurface() and has those
+  #  semantics.  You can also pass SDL_RLEACCEL in the flags parameter and
+  #  SDL will try to RLE accelerate colorkey and alpha blits in the resulting
+  #  surface.
+  #
+  #  This function is used internally by SDL_DisplayFormat().
+proc convertSurface*(src: PSurface, fmt: PPixelFormat, flags: int32): PSurface{.
+    cdecl, importc: "SDL_ConvertSurface", dynlib: LibName.}
+  #
+  #  This performs a fast blit from the source surface to the destination
+  #  surface.  It assumes that the source and destination rectangles are
+  #  the same size.  If either 'srcrect' or 'dstrect' are NULL, the entire
+  #  surface (src or dst) is copied.  The final blit rectangles are saved
+  #  in 'srcrect' and 'dstrect' after all clipping is performed.
+  #  If the blit is successful, it returns 0, otherwise it returns -1.
+  #
+  #  The blit function should not be called on a locked surface.
+  #
+  #  The blit semantics for surfaces with and without alpha and colorkey
+  #  are defined as follows:
+  #
+  #  RGBA->RGB:
+  #      SDL_SRCALPHA set:
+  #   alpha-blend (using alpha-channel).
+  #   SDL_SRCCOLORKEY ignored.
+  #      SDL_SRCALPHA not set:
+  #   copy RGB.
+  #   if SDL_SRCCOLORKEY set, only copy the pixels matching the
+  #   RGB values of the source colour key, ignoring alpha in the
+  #   comparison.
+  #
+  #  RGB->RGBA:
+  #      SDL_SRCALPHA set:
+  #   alpha-blend (using the source per-surface alpha value);
+  #   set destination alpha to opaque.
+  #      SDL_SRCALPHA not set:
+  #   copy RGB, set destination alpha to opaque.
+  #      both:
+  #   if SDL_SRCCOLORKEY set, only copy the pixels matching the
+  #   source colour key.
+  #
+  #  RGBA->RGBA:
+  #      SDL_SRCALPHA set:
+  #   alpha-blend (using the source alpha channel) the RGB values;
+  #   leave destination alpha untouched. [Note: is this correct?]
+  #   SDL_SRCCOLORKEY ignored.
+  #      SDL_SRCALPHA not set:
+  #   copy all of RGBA to the destination.
+  #   if SDL_SRCCOLORKEY set, only copy the pixels matching the
+  #   RGB values of the source colour key, ignoring alpha in the
+  #   comparison.
+  #
+  #  RGB->RGB:
+  #      SDL_SRCALPHA set:
+  #   alpha-blend (using the source per-surface alpha value).
+  #      SDL_SRCALPHA not set:
+  #   copy RGB.
+  #      both:
+  #   if SDL_SRCCOLORKEY set, only copy the pixels matching the
+  #   source colour key.
+  #
+  #  If either of the surfaces were in video memory, and the blit returns -2,
+  #  the video memory was lost, so it should be reloaded with artwork and
+  #  re-blitted:
+  #  while ( SDL_BlitSurface(image, imgrect, screen, dstrect) = -2 ) do
+  #  begin
+  #  while ( SDL_LockSurface(image) < 0 ) do
+  #   Sleep(10);
+  #  -- Write image pixels to image->pixels --
+  #  SDL_UnlockSurface(image);
+  # end;
+  #
+  #  This happens under DirectX 5.0 when the system switches away from your
+  #  fullscreen application.  The lock will also fail until you have access
+  #  to the video memory again.
+  # You should call SDL_BlitSurface() unless you know exactly how SDL
+  #   blitting works internally and how to use the other blit functions.
+proc blitSurface*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int
+  #  This is the public blit function, SDL_BlitSurface(), and it performs
+  #   rectangle validation and clipping before passing it to SDL_LowerBlit()
+proc upperBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int{.
+    cdecl, importc: "SDL_UpperBlit", dynlib: LibName.}
+  # This is a semi-private blit function and it performs low-level surface
+  #  blitting only.
+proc lowerBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int{.
+    cdecl, importc: "SDL_LowerBlit", dynlib: LibName.}
+  # This function performs a fast fill of the given rectangle with 'color'
+  #  The given rectangle is clipped to the destination surface clip area
+  #  and the final fill rectangle is saved in the passed in pointer.
+  #  If 'dstrect' is NULL, the whole surface will be filled with 'color'
+  #  The color should be a pixel of the format used by the surface, and
+  #  can be generated by the SDL_MapRGB() function.
+  #  This function returns 0 on success, or -1 on error.
+proc fillRect*(dst: PSurface, dstrect: PRect, color: int32): int{.cdecl, 
+    importc: "SDL_FillRect", dynlib: LibName.}
+  # This function takes a surface and copies it to a new surface of the
+  #  pixel format and colors of the video framebuffer, suitable for fast
+  #  blitting onto the display surface.  It calls SDL_ConvertSurface()
+  #
+  #  If you want to take advantage of hardware colorkey or alpha blit
+  #  acceleration, you should set the colorkey and alpha value before
+  #  calling this function.
+  #
+  #  If the conversion fails or runs out of memory, it returns NULL
+proc displayFormat*(surface: PSurface): PSurface{.cdecl, 
+    importc: "SDL_DisplayFormat", dynlib: LibName.}
+  # This function takes a surface and copies it to a new surface of the
+  #  pixel format and colors of the video framebuffer (if possible),
+  #  suitable for fast alpha blitting onto the display surface.
+  #  The new surface will always have an alpha channel.
+  #
+  #  If you want to take advantage of hardware colorkey or alpha blit
+  #  acceleration, you should set the colorkey and alpha value before
+  #  calling this function.
+  #
+  #  If the conversion fails or runs out of memory, it returns NULL
+proc displayFormatAlpha*(surface: PSurface): PSurface{.cdecl, 
+    importc: "SDL_DisplayFormatAlpha", dynlib: LibName.}
+  #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+  #* YUV video surface overlay functions                                       */
+  #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+  # This function creates a video output overlay
+  #  Calling the returned surface an overlay is something of a misnomer because
+  #  the contents of the display surface underneath the area where the overlay
+  #  is shown is undefined - it may be overwritten with the converted YUV data.
+proc createYUVOverlay*(width: int, height: int, format: int32, 
+                       display: PSurface): POverlay{.cdecl, 
+    importc: "SDL_CreateYUVOverlay", dynlib: LibName.}
+  # Lock an overlay for direct access, and unlock it when you are done
+proc lockYUVOverlay*(overlay: POverlay): int{.cdecl, 
+    importc: "SDL_LockYUVOverlay", dynlib: LibName.}
+proc unlockYUVOverlay*(overlay: POverlay){.cdecl, 
+    importc: "SDL_UnlockYUVOverlay", dynlib: LibName.}
+  # Blit a video overlay to the display surface.
+  #  The contents of the video surface underneath the blit destination are
+  #  not defined.
+  #  The width and height of the destination rectangle may be different from
+  #  that of the overlay, but currently only 2x scaling is supported.
+proc displayYUVOverlay*(overlay: POverlay, dstrect: PRect): int{.cdecl, 
+    importc: "SDL_DisplayYUVOverlay", dynlib: LibName.}
+  # Free a video overlay
+proc freeYUVOverlay*(overlay: POverlay){.cdecl, importc: "SDL_FreeYUVOverlay", 
+    dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # OpenGL Routines
+  #------------------------------------------------------------------------------
+  # Dynamically load a GL driver, if SDL is built with dynamic GL.
+  #
+  #  SDL links normally with the OpenGL library on your system by default,
+  #  but you can compile it to dynamically load the GL driver at runtime.
+  #  If you do this, you need to retrieve all of the GL functions used in
+  #  your program from the dynamic library using SDL_GL_GetProcAddress().
+  #
+  #  This is disabled in default builds of SDL.
+proc glLoadLibrary*(filename: cstring): int{.cdecl, 
+    importc: "SDL_GL_LoadLibrary", dynlib: LibName.}
+  # Get the address of a GL function (for extension functions)
+proc glGetProcAddress*(procname: cstring): pointer{.cdecl, 
+    importc: "SDL_GL_GetProcAddress", dynlib: LibName.}
+  # Set an attribute of the OpenGL subsystem before intialization.
+proc glSetAttribute*(attr: TGLAttr, value: int): int{.cdecl, 
+    importc: "SDL_GL_SetAttribute", dynlib: LibName.}
+  # Get an attribute of the OpenGL subsystem from the windowing
+  #  interface, such as glX. This is of course different from getting
+  #  the values from SDL's internal OpenGL subsystem, which only
+  #  stores the values you request before initialization.
+  #
+  #  Developers should track the values they pass into SDL_GL_SetAttribute
+  #  themselves if they want to retrieve these values.
+proc glGetAttribute*(attr: TGLAttr, value: var int): int{.cdecl, 
+    importc: "SDL_GL_GetAttribute", dynlib: LibName.}
+  # Swap the OpenGL buffers, if double-buffering is supported.
+proc glSwapBuffers*(){.cdecl, importc: "SDL_GL_SwapBuffers", dynlib: LibName.}
+  # Internal functions that should not be called unless you have read
+  #  and understood the source code for these functions.
+proc glUpdateRects*(numrects: int, rects: PRect){.cdecl, 
+    importc: "SDL_GL_UpdateRects", dynlib: LibName.}
+proc glLock*(){.cdecl, importc: "SDL_GL_Lock", dynlib: LibName.}
+proc glUnlock*(){.cdecl, importc: "SDL_GL_Unlock", dynlib: LibName.}
+  #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  #* These functions allow interaction with the window manager, if any.        *
+  #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Sets/Gets the title and icon text of the display window
+proc wmGetCaption*(title: var cstring, icon: var cstring){.cdecl, 
+    importc: "SDL_WM_GetCaption", dynlib: LibName.}
+proc wmSetCaption*(title: cstring, icon: cstring){.cdecl, 
+    importc: "SDL_WM_SetCaption", dynlib: LibName.}
+  # Sets the icon for the display window.
+  #  This function must be called before the first call to SDL_SetVideoMode().
+  #  It takes an icon surface, and a mask in MSB format.
+  #  If 'mask' is NULL, the entire icon surface will be used as the icon.
+proc wmSetIcon*(icon: PSurface, mask: byte){.cdecl, importc: "SDL_WM_SetIcon", 
+    dynlib: LibName.}
+  # This function iconifies the window, and returns 1 if it succeeded.
+  #  If the function succeeds, it generates an SDL_APPACTIVE loss event.
+  #  This function is a noop and returns 0 in non-windowed environments.
+proc wmIconifyWindow*(): int{.cdecl, importc: "SDL_WM_IconifyWindow", 
+                               dynlib: LibName.}
+  # Toggle fullscreen mode without changing the contents of the screen.
+  #  If the display surface does not require locking before accessing
+  #  the pixel information, then the memory pointers will not change.
+  #
+  #  If this function was able to toggle fullscreen mode (change from
+  #  running in a window to fullscreen, or vice-versa), it will return 1.
+  #  If it is not implemented, or fails, it returns 0.
+  #
+  #  The next call to SDL_SetVideoMode() will set the mode fullscreen
+  #  attribute based on the flags parameter - if SDL_FULLSCREEN is not
+  #  set, then the display will be windowed by default where supported.
+  #
+  #  This is currently only implemented in the X11 video driver.
+proc wmToggleFullScreen*(surface: PSurface): int{.cdecl, 
+    importc: "SDL_WM_ToggleFullScreen", dynlib: LibName.}
+  # Grabbing means that the mouse is confined to the application window,
+  #  and nearly all keyboard input is passed directly to the application,
+  #  and not interpreted by a window manager, if any.
+proc wmGrabInput*(mode: TGrabMode): TGrabMode{.cdecl, 
+    importc: "SDL_WM_GrabInput", dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # mouse-routines
+  #------------------------------------------------------------------------------
+  # Retrieve the current state of the mouse.
+  #  The current button state is returned as a button bitmask, which can
+  #  be tested using the SDL_BUTTON(X) macros, and x and y are set to the
+  #  current mouse cursor position.  You can pass NULL for either x or y.
+proc getMouseState*(x: var int, y: var int): byte{.cdecl, 
+    importc: "SDL_GetMouseState", dynlib: LibName.}
+  # Retrieve the current state of the mouse.
+  #  The current button state is returned as a button bitmask, which can
+  #  be tested using the SDL_BUTTON(X) macros, and x and y are set to the
+  #  mouse deltas since the last call to SDL_GetRelativeMouseState().
+proc getRelativeMouseState*(x: var int, y: var int): byte{.cdecl, 
+    importc: "SDL_GetRelativeMouseState", dynlib: LibName.}
+  # Set the position of the mouse cursor (generates a mouse motion event)
+proc warpMouse*(x, y: uint16){.cdecl, importc: "SDL_WarpMouse", dynlib: LibName.}
+  # Create a cursor using the specified data and mask (in MSB format).
+  #  The cursor width must be a multiple of 8 bits.
+  #
+  #  The cursor is created in black and white according to the following:
+  #  data  mask    resulting pixel on screen
+  #   0     1       White
+  #   1     1       Black
+  #   0     0       Transparent
+  #   1     0       Inverted color if possible, black if not.
+  #
+  #  Cursors created with this function must be freed with SDL_FreeCursor().
+proc createCursor*(data, mask: ptr byte, w, h, hotX, hotY: int): PCursor{.cdecl, 
+    importc: "SDL_CreateCursor", dynlib: LibName.}
+  # Set the currently active cursor to the specified one.
+  #  If the cursor is currently visible, the change will be immediately
+  #  represented on the display.
+proc setCursor*(cursor: PCursor){.cdecl, importc: "SDL_SetCursor", 
+                                  dynlib: LibName.}
+  # Returns the currently active cursor.
+proc getCursor*(): PCursor{.cdecl, importc: "SDL_GetCursor", dynlib: LibName.}
+  # Deallocates a cursor created with SDL_CreateCursor().
+proc freeCursor*(cursor: PCursor){.cdecl, importc: "SDL_FreeCursor", 
+                                   dynlib: LibName.}
+  # Toggle whether or not the cursor is shown on the screen.
+  #  The cursor start off displayed, but can be turned off.
+  #  SDL_ShowCursor() returns 1 if the cursor was being displayed
+  #  before the call, or 0 if it was not.  You can query the current
+  #  state by passing a 'toggle' value of -1.
+proc showCursor*(toggle: int): int{.cdecl, importc: "SDL_ShowCursor", 
+                                    dynlib: LibName.}
+proc button*(b: int): int
+  #------------------------------------------------------------------------------
+  # Keyboard-routines
+  #------------------------------------------------------------------------------
+  # Enable/Disable UNICODE translation of keyboard input.
+  #  This translation has some overhead, so translation defaults off.
+  #  If 'enable' is 1, translation is enabled.
+  #  If 'enable' is 0, translation is disabled.
+  #  If 'enable' is -1, the translation state is not changed.
+  #  It returns the previous state of keyboard translation.
+proc enableUNICODE*(enable: int): int{.cdecl, importc: "SDL_EnableUNICODE", 
+                                       dynlib: LibName.}
+  # If 'delay' is set to 0, keyboard repeat is disabled.
+proc enableKeyRepeat*(delay: int, interval: int): int{.cdecl, 
+    importc: "SDL_EnableKeyRepeat", dynlib: LibName.}
+proc getKeyRepeat*(delay: PInteger, interval: PInteger){.cdecl, 
+    importc: "SDL_GetKeyRepeat", dynlib: LibName.}
+  # Get a snapshot of the current state of the keyboard.
+  #  Returns an array of keystates, indexed by the SDLK_* syms.
+  #  Used:
+  #
+  #  byte *keystate = SDL_GetKeyState(NULL);
+  #  if ( keystate[SDLK_RETURN] ) ... <RETURN> is pressed
+proc getKeyState*(numkeys: pointer): ptr byte{.cdecl, importc: "SDL_GetKeyState", 
+    dynlib: LibName.}
+  # Get the current key modifier state
+proc getModState*(): TMod{.cdecl, importc: "SDL_GetModState", dynlib: LibName.}
+  # Set the current key modifier state
+  #  This does not change the keyboard state, only the key modifier flags.
+proc setModState*(modstate: TMod){.cdecl, importc: "SDL_SetModState", 
+                                   dynlib: LibName.}
+  # Get the name of an SDL virtual keysym
+proc getKeyName*(key: TKey): cstring{.cdecl, importc: "SDL_GetKeyName", 
+                                      dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # Active Routines
+  #------------------------------------------------------------------------------
+  # This function returns the current state of the application, which is a
+  #  bitwise combination of SDL_APPMOUSEFOCUS, SDL_APPINPUTFOCUS, and
+  #  SDL_APPACTIVE.  If SDL_APPACTIVE is set, then the user is able to
+  #  see your application, otherwise it has been iconified or disabled.
+proc getAppState*(): byte{.cdecl, importc: "SDL_GetAppState", dynlib: LibName.}
+  # Mutex functions
+  # Create a mutex, initialized unlocked
+proc createMutex*(): PMutex{.cdecl, importc: "SDL_CreateMutex", dynlib: LibName.}
+  # Lock the mutex  (Returns 0, or -1 on error)
+proc mutexP*(mutex: PMutex): int{.cdecl, importc: "SDL_mutexP", dynlib: LibName.}
+proc lockMutex*(mutex: PMutex): int
+  # Unlock the mutex  (Returns 0, or -1 on error)
+proc mutexV*(mutex: PMutex): int{.cdecl, importc: "SDL_mutexV", dynlib: LibName.}
+proc unlockMutex*(mutex: PMutex): int
+  # Destroy a mutex
+proc destroyMutex*(mutex: PMutex){.cdecl, importc: "SDL_DestroyMutex", 
+                                   dynlib: LibName.}
+  # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Semaphore functions
+  # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Create a semaphore, initialized with value, returns NULL on failure.
+proc createSemaphore*(initialValue: int32): PSem{.cdecl, 
+    importc: "SDL_CreateSemaphore", dynlib: LibName.}
+  # Destroy a semaphore
+proc destroySemaphore*(sem: PSem){.cdecl, importc: "SDL_DestroySemaphore", 
+                                   dynlib: LibName.}
+  # This function suspends the calling thread until the semaphore pointed
+  #  to by sem has a positive count. It then atomically decreases the semaphore
+  #  count.
+proc semWait*(sem: PSem): int{.cdecl, importc: "SDL_SemWait", dynlib: LibName.}
+  # Non-blocking variant of SDL_SemWait(), returns 0 if the wait succeeds,
+  #   SDL_MUTEX_TIMEDOUT if the wait would block, and -1 on error.
+proc semTryWait*(sem: PSem): int{.cdecl, importc: "SDL_SemTryWait", 
+                                  dynlib: LibName.}
+  # Variant of SDL_SemWait() with a timeout in milliseconds, returns 0 if
+  #   the wait succeeds, SDL_MUTEX_TIMEDOUT if the wait does not succeed in
+  #   the allotted time, and -1 on error.
+  #   On some platforms this function is implemented by looping with a delay
+  #   of 1 ms, and so should be avoided if possible.
+proc semWaitTimeout*(sem: PSem, ms: int32): int{.cdecl, 
+    importc: "SDL_SemWaitTimeout", dynlib: LibName.}
+  # Atomically increases the semaphore's count (not blocking), returns 0,
+  #   or -1 on error.
+proc semPost*(sem: PSem): int{.cdecl, importc: "SDL_SemPost", dynlib: LibName.}
+  # Returns the current count of the semaphore
+proc semValue*(sem: PSem): int32{.cdecl, importc: "SDL_SemValue", 
+                                   dynlib: LibName.}
+  # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Condition variable functions
+  # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Create a condition variable
+proc createCond*(): PCond{.cdecl, importc: "SDL_CreateCond", dynlib: LibName.}
+  # Destroy a condition variable
+proc destroyCond*(cond: PCond){.cdecl, importc: "SDL_DestroyCond", 
+                                dynlib: LibName.}
+  # Restart one of the threads that are waiting on the condition variable,
+  #   returns 0 or -1 on error.
+proc condSignal*(cond: PCond): int{.cdecl, importc: "SDL_CondSignal", 
+                                    dynlib: LibName.}
+  # Restart all threads that are waiting on the condition variable,
+  #  returns 0 or -1 on error.
+proc condBroadcast*(cond: PCond): int{.cdecl, importc: "SDL_CondBroadcast", 
+                                       dynlib: LibName.}
+  # Wait on the condition variable, unlocking the provided mutex.
+  #  The mutex must be locked before entering this function!
+  #  Returns 0 when it is signaled, or -1 on error.
+proc condWait*(cond: PCond, mut: PMutex): int{.cdecl, importc: "SDL_CondWait", 
+    dynlib: LibName.}
+  # Waits for at most 'ms' milliseconds, and returns 0 if the condition
+  #  variable is signaled, SDL_MUTEX_TIMEDOUT if the condition is not
+  #  signaled in the allotted time, and -1 on error.
+  #  On some platforms this function is implemented by looping with a delay
+  #  of 1 ms, and so should be avoided if possible.
+proc condWaitTimeout*(cond: PCond, mut: PMutex, ms: int32): int{.cdecl, 
+    importc: "SDL_CondWaitTimeout", dynlib: LibName.}
+  # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Condition variable functions
+  # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+  # Create a thread
+proc createThread*(fn, data: pointer): PThread{.cdecl, 
+    importc: "SDL_CreateThread", dynlib: LibName.}
+  # Get the 32-bit thread identifier for the current thread
+proc threadID*(): int32{.cdecl, importc: "SDL_ThreadID", dynlib: LibName.}
+  # Get the 32-bit thread identifier for the specified thread,
+  #  equivalent to SDL_ThreadID() if the specified thread is NULL.
+proc getThreadID*(thread: PThread): int32{.cdecl, importc: "SDL_GetThreadID", 
+    dynlib: LibName.}
+  # Wait for a thread to finish.
+  #  The return code for the thread function is placed in the area
+  #  pointed to by 'status', if 'status' is not NULL.
+proc waitThread*(thread: PThread, status: var int){.cdecl, 
+    importc: "SDL_WaitThread", dynlib: LibName.}
+  # Forcefully kill a thread without worrying about its state
+proc killThread*(thread: PThread){.cdecl, importc: "SDL_KillThread", 
+                                   dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  # Get Environment Routines
+  #------------------------------------------------------------------------------
+  #*
+  # * This function gives you custom hooks into the window manager information.
+  # * It fills the structure pointed to by 'info' with custom information and
+  # * returns 1 if the function is implemented.  If it's not implemented, or
+  # * the version member of the 'info' structure is invalid, it returns 0.
+  # *
+proc getWMInfo*(info: PSysWMinfo): int{.cdecl, importc: "SDL_GetWMInfo", 
+                                        dynlib: LibName.}
+  #------------------------------------------------------------------------------
+  #SDL_loadso.h
+  #* This function dynamically loads a shared object and returns a pointer
+  # * to the object handle (or NULL if there was an error).
+  # * The 'sofile' parameter is a system dependent name of the object file.
+  # *
+proc loadObject*(sofile: cstring): pointer{.cdecl, importc: "SDL_LoadObject", 
+    dynlib: LibName.}
+  #* Given an object handle, this function looks up the address of the
+  # * named function in the shared object and returns it.  This address
+  # * is no longer valid after calling SDL_UnloadObject().
+  # *
+proc loadFunction*(handle: pointer, name: cstring): pointer{.cdecl, 
+    importc: "SDL_LoadFunction", dynlib: LibName.}
+  #* Unload a shared object from memory *
+proc unloadObject*(handle: pointer){.cdecl, importc: "SDL_UnloadObject", 
+                                     dynlib: LibName.}
+  #------------------------------------------------------------------------------
+proc swap32*(d: int32): int32
+  # Bitwise Checking functions
+proc isBitOn*(value: int, bit: int8): bool
+proc turnBitOn*(value: int, bit: int8): int
+proc turnBitOff*(value: int, bit: int8): int
+# implementation
+
+proc tablesize(table: cstring): int = 
+  result = sizeOf(table) div sizeOf(table[0])
+
+proc rwSeek(context: PRWops, offset: int, whence: int): int = 
+  result = context.seek(context, offset, whence)
+
+proc rwTell(context: PRWops): int = 
+  result = context.seek(context, 0, 1)
+
+proc rwRead(context: PRWops, theptr: pointer, size: int, n: int): int = 
+  result = context.read(context, theptr, size, n)
+
+proc rwWrite(context: PRWops, theptr: pointer, size: int, n: int): int = 
+  result = context.write(context, theptr, size, n)
+
+proc rwClose(context: PRWops): int = 
+  result = context.closeFile(context)
+
+proc loadWAV(filename: cstring, spec: PAudioSpec, audioBuf: ptr byte, 
+             audiolen: PUInt32): PAudioSpec = 
+  result = loadWAV_RW(rWFromFile(filename, "rb"), 1, spec, audioBuf, audiolen)
+
+proc cdInDrive(status: TCDStatus): bool = 
+  result = ord(status) > ord(CD_ERROR)
+
+proc framesToMsf*(frames: int; m, s, f: var int) =
+  var value = frames
+  f = value mod CD_FPS
+  value = value div CD_FPS
+  s = value mod 60
+  value = value div 60
+  m = value
+
+proc msfToFrames*(m, s, f: int): int = 
+  result = m * 60 * CD_FPS + s * CD_FPS + f
+
+proc version(x: var Tversion) = 
+  x.major = MAJOR_VERSION
+  x.minor = MINOR_VERSION
+  x.patch = PATCHLEVEL
+
+proc versionnum(x, y, z: int): int = 
+  result = x * 1000 + y * 100 + z
+
+proc compiledversion(): int = 
+  result = versionnum(MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL)
+
+proc versionAtleast(x, y, z: int): bool = 
+  result = (compiledversion() >= versionnum(x, y, z))
+
+proc loadBMP(filename: cstring): PSurface = 
+  result = loadBMP_RW(rWFromFile(filename, "rb"), 1)
+
+proc saveBMP(surface: PSurface, filename: cstring): int = 
+  result = saveBMP_RW(surface, rWFromFile(filename, "wb"), 1)
+
+proc blitSurface(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int = 
+  result = upperBlit(src, srcrect, dst, dstrect)
+
+proc allocSurface(flags: int32, width, height, depth: int, 
+                  rMask, gMask, bMask, aMask: int32): PSurface = 
+  result = createRGBSurface(flags, width, height, depth, rMask, gMask, bMask, 
+                            aMask)
+
+proc mustLock(surface: PSurface): bool = 
+  result = ((surface.offset != 0) or
+      ((surface.flags and (HWSURFACE or ASYNCBLIT or RLEACCEL)) != 0))
+
+proc lockMutex(mutex: PMutex): int = 
+  result = mutexP(mutex)
+
+proc unlockMutex(mutex: PMutex): int = 
+  result = mutexV(mutex)
+
+proc button(b: int): int = 
+  result = PRESSED shl (b - 1)
+
+proc swap32(d: int32): int32 = 
+  result = ((d shl 24) or ((d shl 8) and 0x00FF0000) or
+      ((d shr 8) and 0x0000FF00) or (d shr 24))
+
+proc isBitOn(value: int, bit: int8): bool = 
+  result = ((value and (1 shl ze(bit))) != 0)
+
+proc turnBitOn(value: int, bit: int8): int = 
+  result = (value or (1 shl ze(bit)))
+
+proc turnBitOff(value: int, bit: int8): int = 
+  result = (value and not (1 shl ze(bit)))
diff --git a/lib/wrappers/sdl/sdl_gfx.nim b/lib/wrappers/sdl/sdl_gfx.nim
new file mode 100644
index 000000000..5523ad0a2
--- /dev/null
+++ b/lib/wrappers/sdl/sdl_gfx.nim
@@ -0,0 +1,452 @@
+#
+#  $Id: sdl_gfx.pas,v 1.3 2007/05/29 21:31:04 savage Exp $
+#
+#
+#
+#  $Log: sdl_gfx.pas,v $
+#  Revision 1.3  2007/05/29 21:31:04  savage
+#  Changes as suggested by Almindor for 64bit compatibility.
+#
+#  Revision 1.2  2007/05/20 20:30:18  savage
+#  Initial Changes to Handle 64 Bits
+#
+#  Revision 1.1  2005/01/03 19:08:32  savage
+#  Header for the SDL_Gfx library.
+#
+#
+#
+#
+
+import 
+  sdl
+
+when defined(windows): 
+  const 
+    gfxLibName = "SDL_gfx.dll"
+elif defined(macosx): 
+  const 
+    gfxLibName = "libSDL_gfx.dylib"
+else: 
+  const 
+    gfxLibName = "libSDL_gfx.so"
+const                         # Some rates in Hz
+  FPS_UPPER_LIMIT* = 200
+  FPS_LOWER_LIMIT* = 1
+  FPS_DEFAULT* = 30           # ---- Defines
+  SMOOTHING_OFF* = 0
+  SMOOTHING_ON* = 1
+
+type 
+  PFPSmanager* = ptr TFPSmanager
+  TFPSmanager*{.final.} = object  # ---- Structures
+    framecount*: uint32
+    rateticks*: float32
+    lastticks*: uint32
+    rate*: uint32
+
+  PColorRGBA* = ptr TColorRGBA
+  TColorRGBA*{.final.} = object 
+    r*: byte
+    g*: byte
+    b*: byte
+    a*: byte
+
+  PColorY* = ptr TColorY
+  TColorY*{.final.} = object  #
+                              #
+                              # SDL_framerate: framerate manager
+                              #
+                              # LGPL (c) A. Schiffler
+                              #
+                              #
+    y*: byte
+
+
+proc initFramerate*(manager: PFPSmanager){.cdecl, importc: "SDL_initFramerate", 
+    dynlib: gfxLibName.}
+proc setFramerate*(manager: PFPSmanager, rate: cint): cint{.cdecl, 
+    importc: "SDL_setFramerate", dynlib: gfxLibName.}
+proc getFramerate*(manager: PFPSmanager): cint{.cdecl, 
+    importc: "SDL_getFramerate", dynlib: gfxLibName.}
+proc framerateDelay*(manager: PFPSmanager){.cdecl, 
+    importc: "SDL_framerateDelay", dynlib: gfxLibName.}
+  #
+  #
+  # SDL_gfxPrimitives: graphics primitives for SDL
+  #
+  # LGPL (c) A. Schiffler
+  #
+  #
+  # Note: all ___Color routines expect the color to be in format 0xRRGGBBAA 
+  # Pixel 
+proc pixelColor*(dst: PSurface, x: int16, y: int16, color: uint32): cint{.
+    cdecl, importc: "pixelColor", dynlib: gfxLibName.}
+proc pixelRGBA*(dst: PSurface, x: int16, y: int16, r: byte, g: byte, 
+                b: byte, a: byte): cint{.cdecl, importc: "pixelRGBA", 
+    dynlib: gfxLibName.}
+  # Horizontal line 
+proc hlineColor*(dst: PSurface, x1: int16, x2: int16, y: int16, color: uint32): cint{.
+    cdecl, importc: "hlineColor", dynlib: gfxLibName.}
+proc hlineRGBA*(dst: PSurface, x1: int16, x2: int16, y: int16, r: byte, 
+                g: byte, b: byte, a: byte): cint{.cdecl, importc: "hlineRGBA", 
+    dynlib: gfxLibName.}
+  # Vertical line 
+proc vlineColor*(dst: PSurface, x: int16, y1: int16, y2: int16, color: uint32): cint{.
+    cdecl, importc: "vlineColor", dynlib: gfxLibName.}
+proc vlineRGBA*(dst: PSurface, x: int16, y1: int16, y2: int16, r: byte, 
+                g: byte, b: byte, a: byte): cint{.cdecl, importc: "vlineRGBA", 
+    dynlib: gfxLibName.}
+  # Rectangle 
+proc rectangleColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, 
+                     y2: int16, color: uint32): cint{.cdecl, 
+    importc: "rectangleColor", dynlib: gfxLibName.}
+proc rectangleRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, 
+                    y2: int16, r: byte, g: byte, b: byte, a: byte): cint{.
+    cdecl, importc: "rectangleRGBA", dynlib: gfxLibName.}
+  # Filled rectangle (Box) 
+proc boxColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+               color: uint32): cint{.cdecl, importc: "boxColor", 
+                                    dynlib: gfxLibName.}
+proc boxRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+              r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "boxRGBA", dynlib: gfxLibName.}
+  # Line 
+proc lineColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+                color: uint32): cint{.cdecl, importc: "lineColor", 
+                                     dynlib: gfxLibName.}
+proc lineRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+               r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "lineRGBA", dynlib: gfxLibName.}
+  # AA Line 
+proc aalineColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+                  color: uint32): cint{.cdecl, importc: "aalineColor", 
+                                       dynlib: gfxLibName.}
+proc aalineRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+                 r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "aalineRGBA", dynlib: gfxLibName.}
+  # Circle 
+proc circleColor*(dst: PSurface, x: int16, y: int16, r: int16, color: uint32): cint{.
+    cdecl, importc: "circleColor", dynlib: gfxLibName.}
+proc circleRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, r: byte, 
+                 g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "circleRGBA", dynlib: gfxLibName.}
+  # AA Circle 
+proc aacircleColor*(dst: PSurface, x: int16, y: int16, r: int16, 
+                    color: uint32): cint{.cdecl, importc: "aacircleColor", 
+    dynlib: gfxLibName.}
+proc aacircleRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, r: byte, 
+                   g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "aacircleRGBA", dynlib: gfxLibName.}
+  # Filled Circle 
+proc filledCircleColor*(dst: PSurface, x: int16, y: int16, r: int16, 
+                        color: uint32): cint{.cdecl, 
+    importc: "filledCircleColor", dynlib: gfxLibName.}
+proc filledCircleRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, 
+                       r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "filledCircleRGBA", dynlib: gfxLibName.}
+  # Ellipse 
+proc ellipseColor*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, 
+                   color: uint32): cint{.cdecl, importc: "ellipseColor", 
+                                        dynlib: gfxLibName.}
+proc ellipseRGBA*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, 
+                  r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "ellipseRGBA", dynlib: gfxLibName.}
+  # AA Ellipse 
+proc aaellipseColor*(dst: PSurface, xc: int16, yc: int16, rx: int16, 
+                     ry: int16, color: uint32): cint{.cdecl, 
+    importc: "aaellipseColor", dynlib: gfxLibName.}
+proc aaellipseRGBA*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, 
+                    r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "aaellipseRGBA", dynlib: gfxLibName.}
+  # Filled Ellipse 
+proc filledEllipseColor*(dst: PSurface, x: int16, y: int16, rx: int16, 
+                         ry: int16, color: uint32): cint{.cdecl, 
+    importc: "filledEllipseColor", dynlib: gfxLibName.}
+proc filledEllipseRGBA*(dst: PSurface, x: int16, y: int16, rx: int16, 
+                        ry: int16, r: byte, g: byte, b: byte, a: byte): cint{.
+    cdecl, importc: "filledEllipseRGBA", dynlib: gfxLibName.}
+  # Pie
+proc pieColor*(dst: PSurface, x: int16, y: int16, rad: int16, start: int16, 
+               finish: int16, color: uint32): cint{.cdecl, importc: "pieColor", 
+    dynlib: gfxLibName.}
+proc pieRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, start: int16, 
+              finish: int16, r: byte, g: byte, b: byte, a: byte): cint{.
+    cdecl, importc: "pieRGBA", dynlib: gfxLibName.}
+  # Filled Pie
+proc filledPieColor*(dst: PSurface, x: int16, y: int16, rad: int16, 
+                     start: int16, finish: int16, color: uint32): cint{.cdecl, 
+    importc: "filledPieColor", dynlib: gfxLibName.}
+proc filledPieRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, 
+                    start: int16, finish: int16, r: byte, g: byte, b: byte, 
+                    a: byte): cint{.cdecl, importc: "filledPieRGBA", 
+                                    dynlib: gfxLibName.}
+  # Trigon
+proc trigonColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+                  x3: int16, y3: int16, color: uint32): cint{.cdecl, 
+    importc: "trigonColor", dynlib: gfxLibName.}
+proc trigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, 
+                 x3: int16, y3: int16, r: byte, g: byte, b: byte, a: byte): cint{.
+    cdecl, importc: "trigonRGBA", dynlib: gfxLibName.}
+  # AA-Trigon
+proc aatrigonColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, 
+                    y2: int16, x3: int16, y3: int16, color: uint32): cint{.
+    cdecl, importc: "aatrigonColor", dynlib: gfxLibName.}
+proc aatrigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, 
+                   y2: int16, x3: int16, y3: int16, r: byte, g: byte, 
+                   b: byte, a: byte): cint{.cdecl, importc: "aatrigonRGBA", 
+    dynlib: gfxLibName.}
+  # Filled Trigon
+proc filledTrigonColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, 
+                        y2: int16, x3: int16, y3: int16, color: uint32): cint{.
+    cdecl, importc: "filledTrigonColor", dynlib: gfxLibName.}
+proc filledTrigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, 
+                       y2: int16, x3: int16, y3: int16, r: byte, g: byte, 
+                       b: byte, a: byte): cint{.cdecl, 
+    importc: "filledTrigonRGBA", dynlib: gfxLibName.}
+  # Polygon
+proc polygonColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, 
+                   color: uint32): cint{.cdecl, importc: "polygonColor", 
+                                        dynlib: gfxLibName.}
+proc polygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, r: byte, 
+                  g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "polygonRGBA", dynlib: gfxLibName.}
+  # AA-Polygon
+proc aapolygonColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, 
+                     color: uint32): cint{.cdecl, importc: "aapolygonColor", 
+    dynlib: gfxLibName.}
+proc aapolygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, r: byte, 
+                    g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "aapolygonRGBA", dynlib: gfxLibName.}
+  # Filled Polygon
+proc filledPolygonColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, 
+                         color: uint32): cint{.cdecl, 
+    importc: "filledPolygonColor", dynlib: gfxLibName.}
+proc filledPolygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, 
+                        r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "filledPolygonRGBA", dynlib: gfxLibName.}
+  # Bezier
+  # s = number of steps
+proc bezierColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, s: cint, 
+                  color: uint32): cint{.cdecl, importc: "bezierColor", 
+                                       dynlib: gfxLibName.}
+proc bezierRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, s: cint, 
+                 r: byte, g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "bezierRGBA", dynlib: gfxLibName.}
+  # Characters/Strings
+proc characterColor*(dst: PSurface, x: int16, y: int16, c: char, color: uint32): cint{.
+    cdecl, importc: "characterColor", dynlib: gfxLibName.}
+proc characterRGBA*(dst: PSurface, x: int16, y: int16, c: char, r: byte, 
+                    g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "characterRGBA", dynlib: gfxLibName.}
+proc stringColor*(dst: PSurface, x: int16, y: int16, c: cstring, color: uint32): cint{.
+    cdecl, importc: "stringColor", dynlib: gfxLibName.}
+proc stringRGBA*(dst: PSurface, x: int16, y: int16, c: cstring, r: byte, 
+                 g: byte, b: byte, a: byte): cint{.cdecl, 
+    importc: "stringRGBA", dynlib: gfxLibName.}
+proc gfxPrimitivesSetFont*(fontdata: pointer, cw: cint, ch: cint){.cdecl, 
+    importc: "gfxPrimitivesSetFont", dynlib: gfxLibName.}
+  #
+  #
+  # SDL_imageFilter - bytes-image "filter" routines
+  # (uses inline x86 MMX optimizations if available)
+  #
+  # LGPL (c) A. Schiffler
+  #
+  #
+  # Comments:                                                                           
+  #  1.) MMX functions work best if all data blocks are aligned on a 32 bytes boundary. 
+  #  2.) Data that is not within an 8 byte boundary is processed using the C routine.   
+  #  3.) Convolution routines do not have C routines at this time.                      
+  # Detect MMX capability in CPU
+proc imageFilterMMXdetect*(): cint{.cdecl, importc: "SDL_imageFilterMMXdetect", 
+                                   dynlib: gfxLibName.}
+  # Force use of MMX off (or turn possible use back on)
+proc imageFilterMMXoff*(){.cdecl, importc: "SDL_imageFilterMMXoff", 
+                           dynlib: gfxLibName.}
+proc imageFilterMMXon*(){.cdecl, importc: "SDL_imageFilterMMXon", 
+                          dynlib: gfxLibName.}
+  #
+  # All routines return:
+  #   0   OK
+  #  -1   Error (internal error, parameter error)
+  #
+  #  SDL_imageFilterAdd: D = saturation255(S1 + S2)
+proc imageFilterAdd*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterAdd", dynlib: gfxLibName.}
+  #  SDL_imageFilterMean: D = S1/2 + S2/2
+proc imageFilterMean*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterMean", dynlib: gfxLibName.}
+  #  SDL_imageFilterSub: D = saturation0(S1 - S2)
+proc imageFilterSub*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterSub", dynlib: gfxLibName.}
+  #  SDL_imageFilterAbsDiff: D = | S1 - S2 |
+proc imageFilterAbsDiff*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterAbsDiff", dynlib: gfxLibName.}
+  #  SDL_imageFilterMult: D = saturation(S1 * S2)
+proc imageFilterMult*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterMult", dynlib: gfxLibName.}
+  #  SDL_imageFilterMultNor: D = S1 * S2   (non-MMX)
+proc imageFilterMultNor*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterMultNor", dynlib: gfxLibName.}
+  #  SDL_imageFilterMultDivby2: D = saturation255(S1/2 * S2)
+proc imageFilterMultDivby2*(src1: cstring, src2: cstring, dest: cstring, 
+                            len: cint): cint{.cdecl, 
+    importc: "SDL_imageFilterMultDivby2", dynlib: gfxLibName.}
+  #  SDL_imageFilterMultDivby4: D = saturation255(S1/2 * S2/2)
+proc imageFilterMultDivby4*(src1: cstring, src2: cstring, dest: cstring, 
+                            len: cint): cint{.cdecl, 
+    importc: "SDL_imageFilterMultDivby4", dynlib: gfxLibName.}
+  #  SDL_imageFilterBitAnd: D = S1 & S2
+proc imageFilterBitAnd*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterBitAnd", dynlib: gfxLibName.}
+  #  SDL_imageFilterBitOr: D = S1 | S2
+proc imageFilterBitOr*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterBitOr", dynlib: gfxLibName.}
+  #  SDL_imageFilterDiv: D = S1 / S2   (non-MMX)
+proc imageFilterDiv*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterDiv", dynlib: gfxLibName.}
+  #  SDL_imageFilterBitNegation: D = !S
+proc imageFilterBitNegation*(src1: cstring, dest: cstring, len: cint): cint{.
+    cdecl, importc: "SDL_imageFilterBitNegation", dynlib: gfxLibName.}
+  #  SDL_imageFilterAddByte: D = saturation255(S + C)
+proc imageFilterAddByte*(src1: cstring, dest: cstring, len: cint, c: char): cint{.
+    cdecl, importc: "SDL_imageFilterAddByte", dynlib: gfxLibName.}
+  #  SDL_imageFilterAddUint: D = saturation255(S + (uint)C)
+proc imageFilterAddUint*(src1: cstring, dest: cstring, len: cint, c: cint): cint{.
+    cdecl, importc: "SDL_imageFilterAddUint", dynlib: gfxLibName.}
+  #  SDL_imageFilterAddByteToHalf: D = saturation255(S/2 + C)
+proc imageFilterAddByteToHalf*(src1: cstring, dest: cstring, len: cint, c: char): cint{.
+    cdecl, importc: "SDL_imageFilterAddByteToHalf", dynlib: gfxLibName.}
+  #  SDL_imageFilterSubByte: D = saturation0(S - C)
+proc imageFilterSubByte*(src1: cstring, dest: cstring, len: cint, c: char): cint{.
+    cdecl, importc: "SDL_imageFilterSubByte", dynlib: gfxLibName.}
+  #  SDL_imageFilterSubUint: D = saturation0(S - (uint)C)
+proc imageFilterSubUint*(src1: cstring, dest: cstring, len: cint, c: cint): cint{.
+    cdecl, importc: "SDL_imageFilterSubUint", dynlib: gfxLibName.}
+  #  SDL_imageFilterShiftRight: D = saturation0(S >> N)
+proc imageFilterShiftRight*(src1: cstring, dest: cstring, len: cint, n: char): cint{.
+    cdecl, importc: "SDL_imageFilterShiftRight", dynlib: gfxLibName.}
+  #  SDL_imageFilterShiftRightUint: D = saturation0((uint)S >> N)
+proc imageFilterShiftRightUint*(src1: cstring, dest: cstring, len: cint, n: char): cint{.
+    cdecl, importc: "SDL_imageFilterShiftRightUint", dynlib: gfxLibName.}
+  #  SDL_imageFilterMultByByte: D = saturation255(S * C)
+proc imageFilterMultByByte*(src1: cstring, dest: cstring, len: cint, c: char): cint{.
+    cdecl, importc: "SDL_imageFilterMultByByte", dynlib: gfxLibName.}
+  #  SDL_imageFilterShiftRightAndMultByByte: D = saturation255((S >> N) * C)
+proc imageFilterShiftRightAndMultByByte*(src1: cstring, dest: cstring, len: cint, 
+    n: char, c: char): cint{.cdecl, 
+                            importc: "SDL_imageFilterShiftRightAndMultByByte", 
+                            dynlib: gfxLibName.}
+  #  SDL_imageFilterShiftLeftByte: D = (S << N)
+proc imageFilterShiftLeftByte*(src1: cstring, dest: cstring, len: cint, n: char): cint{.
+    cdecl, importc: "SDL_imageFilterShiftLeftByte", dynlib: gfxLibName.}
+  #  SDL_imageFilterShiftLeftUint: D = ((uint)S << N)
+proc imageFilterShiftLeftUint*(src1: cstring, dest: cstring, len: cint, n: char): cint{.
+    cdecl, importc: "SDL_imageFilterShiftLeftUint", dynlib: gfxLibName.}
+  #  SDL_imageFilterShiftLeft: D = saturation255(S << N)
+proc imageFilterShiftLeft*(src1: cstring, dest: cstring, len: cint, n: char): cint{.
+    cdecl, importc: "SDL_imageFilterShiftLeft", dynlib: gfxLibName.}
+  #  SDL_imageFilterBinarizeUsingThreshold: D = S >= T ? 255:0
+proc imageFilterBinarizeUsingThreshold*(src1: cstring, dest: cstring, len: cint, 
+                                        t: char): cint{.cdecl, 
+    importc: "SDL_imageFilterBinarizeUsingThreshold", dynlib: gfxLibName.}
+  #  SDL_imageFilterClipToRange: D = (S >= Tmin) & (S <= Tmax) 255:0
+proc imageFilterClipToRange*(src1: cstring, dest: cstring, len: cint, tmin: int8, 
+                             tmax: int8): cint{.cdecl, 
+    importc: "SDL_imageFilterClipToRange", dynlib: gfxLibName.}
+  #  SDL_imageFilterNormalizeLinear: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin)
+proc imageFilterNormalizeLinear*(src1: cstring, dest: cstring, len: cint, 
+                                 cmin: cint, cmax: cint, nmin: cint, nmax: cint): cint{.
+    cdecl, importc: "SDL_imageFilterNormalizeLinear", dynlib: gfxLibName.}
+  # !!! NO C-ROUTINE FOR THESE FUNCTIONS YET !!! 
+  #  SDL_imageFilterConvolveKernel3x3Divide: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel3x3Divide*(src: cstring, dest: cstring, rows: cint, 
+    columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel3x3Divide", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel5x5Divide: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel5x5Divide*(src: cstring, dest: cstring, rows: cint, 
+    columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel5x5Divide", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel7x7Divide: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel7x7Divide*(src: cstring, dest: cstring, rows: cint, 
+    columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel7x7Divide", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel9x9Divide: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel9x9Divide*(src: cstring, dest: cstring, rows: cint, 
+    columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel9x9Divide", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel3x3ShiftRight: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel3x3ShiftRight*(src: cstring, dest: cstring, 
+    rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel3x3ShiftRight", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel5x5ShiftRight: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel5x5ShiftRight*(src: cstring, dest: cstring, 
+    rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel5x5ShiftRight", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel7x7ShiftRight: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel7x7ShiftRight*(src: cstring, dest: cstring, 
+    rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel7x7ShiftRight", dynlib: gfxLibName.}
+  #  SDL_imageFilterConvolveKernel9x9ShiftRight: Dij = saturation0and255( ... )
+proc imageFilterConvolveKernel9x9ShiftRight*(src: cstring, dest: cstring, 
+    rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, 
+    importc: "SDL_imageFilterConvolveKernel9x9ShiftRight", dynlib: gfxLibName.}
+  #  SDL_imageFilterSobelX: Dij = saturation255( ... )
+proc imageFilterSobelX*(src: cstring, dest: cstring, rows: cint, columns: cint): cint{.
+    cdecl, importc: "SDL_imageFilterSobelX", dynlib: gfxLibName.}
+  #  SDL_imageFilterSobelXShiftRight: Dij = saturation255( ... )
+proc imageFilterSobelXShiftRight*(src: cstring, dest: cstring, rows: cint, 
+                                  columns: cint, nRightShift: char): cint{.cdecl, 
+    importc: "SDL_imageFilterSobelXShiftRight", dynlib: gfxLibName.}
+  # Align/restore stack to 32 byte boundary -- Functionality untested! --
+proc imageFilterAlignStack*(){.cdecl, importc: "SDL_imageFilterAlignStack", 
+                               dynlib: gfxLibName.}
+proc imageFilterRestoreStack*(){.cdecl, importc: "SDL_imageFilterRestoreStack", 
+                                 dynlib: gfxLibName.}
+  #
+  #
+  # SDL_rotozoom - rotozoomer
+  #
+  # LGPL (c) A. Schiffler
+  #
+  #
+  # 
+  # 
+  # rotozoomSurface()
+  #
+  # Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+  # 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
+  # then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+  # or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+  #
+  #
+proc rotozoomSurface*(src: PSurface, angle: float64, zoom: float64, smooth: cint): PSurface{.
+    cdecl, importc: "rotozoomSurface", dynlib: gfxLibName.}
+proc rotozoomSurfaceXY*(src: PSurface, angle: float64, zoomx: float64, 
+                        zoomy: float64, smooth: cint): PSurface{.cdecl, 
+    importc: "rotozoomSurfaceXY", dynlib: gfxLibName.}
+  # Returns the size of the target surface for a rotozoomSurface() call 
+proc rotozoomSurfaceSize*(width: cint, height: cint, angle: float64, 
+                          zoom: float64, dstwidth: var cint, dstheight: var cint){.
+    cdecl, importc: "rotozoomSurfaceSize", dynlib: gfxLibName.}
+proc rotozoomSurfaceSizeXY*(width: cint, height: cint, angle: float64, 
+                            zoomx: float64, zoomy: float64, dstwidth: var cint, 
+                            dstheight: var cint){.cdecl, 
+    importc: "rotozoomSurfaceSizeXY", dynlib: gfxLibName.}
+  #
+  #
+  # zoomSurface()
+  #
+  # Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+  # 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
+  # then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+  # or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+  #
+  #
+proc zoomSurface*(src: PSurface, zoomx: float64, zoomy: float64, smooth: cint): PSurface{.
+    cdecl, importc: "zoomSurface", dynlib: gfxLibName.}
+  # Returns the size of the target surface for a zoomSurface() call 
+proc zoomSurfaceSize*(width: cint, height: cint, zoomx: float64, zoomy: float64, 
+                      dstwidth: var cint, dstheight: var cint){.cdecl, 
+    importc: "zoomSurfaceSize", dynlib: gfxLibName.}
+# implementation
diff --git a/lib/wrappers/sdl/sdl_image.nim b/lib/wrappers/sdl/sdl_image.nim
new file mode 100644
index 000000000..9c56e6a46
--- /dev/null
+++ b/lib/wrappers/sdl/sdl_image.nim
@@ -0,0 +1,243 @@
+#
+#  $Id: sdl_image.pas,v 1.14 2007/05/29 21:31:13 savage Exp $
+#  
+#
+#******************************************************************************
+#                                                                              
+#       Borland Delphi SDL_Image - An example image loading library for use    
+#                                  with SDL                                    
+#       Conversion of the Simple DirectMedia Layer Image Headers               
+#                                                                              
+# Portions created by Sam Lantinga <slouken@devolution.com> are                
+# Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga                     
+# 5635-34 Springhouse Dr.                                                      
+# Pleasanton, CA 94588 (USA)                                                   
+#                                                                              
+# All Rights Reserved.                                                         
+#                                                                              
+# The original files are : SDL_image.h                                         
+#                                                                              
+# The initial developer of this Pascal code was :                              
+# Matthias Thoma <ma.thoma@gmx.de>                                             
+#                                                                              
+# Portions created by Matthias Thoma are                                       
+# Copyright (C) 2000 - 2001 Matthias Thoma.                                    
+#                                                                              
+#                                                                              
+# Contributor(s)                                                               
+# --------------                                                               
+# Dominique Louis <Dominique@SavageSoftware.com.au>                            
+#                                                                              
+# Obtained through:                                                            
+# Joint Endeavour of Delphi Innovators ( Project JEDI )                        
+#                                                                              
+# You may retrieve the latest version of this file at the Project              
+# JEDI home page, located at http://delphi-jedi.org                            
+#                                                                              
+# The contents of this file are used with permission, subject to               
+# the Mozilla Public License Version 1.1 (the "License"); you may              
+# not use this file except in compliance with the License. You may             
+# obtain a copy of the License at                                              
+# http://www.mozilla.org/MPL/MPL-1.1.html                                      
+#                                                                              
+# Software distributed under the License is distributed on an                  
+# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               
+# implied. See the License for the specific language governing                 
+# rights and limitations under the License.                                    
+#                                                                              
+# Description                                                                  
+# -----------                                                                  
+#   A simple library to load images of various formats as SDL surfaces         
+#                                                                              
+# Requires                                                                     
+# --------                                                                     
+#   SDL.pas in your search path.                                               
+#                                                                              
+# Programming Notes                                                            
+# -----------------                                                            
+#   See the Aliens Demo on how to make use of this libaray                     
+#                                                                              
+# Revision History                                                             
+# ----------------                                                             
+#   April    02 2001 - MT : Initial Translation                                
+#                                                                              
+#   May      08 2001 - DL : Added ExternalSym derectives and copyright header  
+#                                                                              
+#   April   03 2003 - DL : Added jedi-sdl.inc include file to support more     
+#                          Pascal compilers. Initial support is now included   
+#                          for GnuPascal, VirtualPascal, TMT and obviously     
+#                          continue support for Delphi Kylix and FreePascal.   
+#                                                                              
+#   April   08 2003 - MK : Aka Mr Kroket - Added Better FPC support            
+#                                                                              
+#   April   24 2003 - DL : under instruction from Alexey Barkovoy, I have added
+#                          better TMT Pascal support and under instruction     
+#                          from Prof. Abimbola Olowofoyeku (The African Chief),
+#                          I have added better Gnu Pascal support              
+#                                                                              
+#   April   30 2003 - DL : under instruction from David Mears AKA              
+#                          Jason Siletto, I have added FPC Linux support.      
+#                          This was compiled with fpc 1.1, so remember to set  
+#                          include file path. ie. -Fi/usr/share/fpcsrc/rtl/*   
+#                                                                              
+#
+#  $Log: sdl_image.pas,v $
+#  Revision 1.14  2007/05/29 21:31:13  savage
+#  Changes as suggested by Almindor for 64bit compatibility.
+#
+#  Revision 1.13  2007/05/20 20:30:54  savage
+#  Initial Changes to Handle 64 Bits
+#
+#  Revision 1.12  2006/12/02 00:14:40  savage
+#  Updated to latest version
+#
+#  Revision 1.11  2005/04/10 18:22:59  savage
+#  Changes as suggested by Michalis, thanks.
+#
+#  Revision 1.10  2005/04/10 11:48:33  savage
+#  Changes as suggested by Michalis, thanks.
+#
+#  Revision 1.9  2005/01/05 01:47:07  savage
+#  Changed LibName to reflect what MacOS X should have. ie libSDL*-1.2.0.dylib respectively.
+#
+#  Revision 1.8  2005/01/04 23:14:44  savage
+#  Changed LibName to reflect what most Linux distros will have. ie libSDL*-1.2.so.0 respectively.
+#
+#  Revision 1.7  2005/01/01 02:03:12  savage
+#  Updated to v1.2.4
+#
+#  Revision 1.6  2004/08/14 22:54:30  savage
+#  Updated so that Library name defines are correctly defined for MacOS X.
+#
+#  Revision 1.5  2004/05/10 14:10:04  savage
+#  Initial MacOS X support. Fixed defines for MACOS ( Classic ) and DARWIN ( MacOS X ).
+#
+#  Revision 1.4  2004/04/13 09:32:08  savage
+#  Changed Shared object names back to just the .so extension to avoid conflicts on various Linux/Unix distros. Therefore developers will need to create Symbolic links to the actual Share Objects if necessary.
+#
+#  Revision 1.3  2004/04/01 20:53:23  savage
+#  Changed Linux Shared Object names so they reflect the Symbolic Links that are created when installing the RPMs from the SDL site.
+#
+#  Revision 1.2  2004/03/30 20:23:28  savage
+#  Tidied up use of UNIX compiler directive.
+#
+#  Revision 1.1  2004/02/14 23:35:42  savage
+#  version 1 of sdl_image, sdl_mixer and smpeg.
+#
+#
+#
+#******************************************************************************
+
+import
+  sdl
+
+when defined(windows):
+  const
+    ImageLibName = "SDL_Image.dll"
+elif defined(macosx):
+  const
+    ImageLibName = "libSDL_image-1.2.0.dylib"
+else:
+  const
+    ImageLibName = "libSDL_image(.so|-1.2.so.0)"
+const
+  IMAGE_MAJOR_VERSION* = 1
+  IMAGE_MINOR_VERSION* = 2
+  IMAGE_PATCHLEVEL* = 5
+
+# This macro can be used to fill a version structure with the compile-time
+#  version of the SDL_image library. 
+
+proc imageVersion*(x: var Tversion)
+  # This function gets the version of the dynamically linked SDL_image library.
+  #   it should NOT be used to fill a version structure, instead you should
+  #   use the SDL_IMAGE_VERSION() macro.
+  # 
+proc imgLinkedVersion*(): Pversion{.importc: "IMG_Linked_Version", 
+                                    dynlib: ImageLibName.}
+  # Load an image from an SDL data source.
+  #   The 'type' may be one of: "BMP", "GIF", "PNG", etc.
+  #
+  #   If the image format supports a transparent pixel, SDL will set the
+  #   colorkey for the surface.  You can enable RLE acceleration on the
+  #   surface afterwards by calling:
+  #        SDL_SetColorKey(image, SDL_RLEACCEL, image.format.colorkey);
+  #
+
+const
+  IMG_INIT_JPG* = 0x00000001
+  IMG_INIT_PNG* = 0x00000002
+  IMG_INIT_TIF* = 0x00000004
+  IMG_INIT_WEBP* = 0x00000008
+
+proc imgInit*(flags: cint): int {.cdecl, importc: "IMG_Init",
+                                  dynlib: ImageLibName.}
+proc imgQuit*() {.cdecl, importc: "IMG_Quit",
+                                  dynlib: ImageLibName.}
+proc imgLoadTypedRW*(src: PRWops, freesrc: cint, theType: cstring): PSurface{.
+    cdecl, importc: "IMG_LoadTyped_RW", dynlib: ImageLibName.}
+  # Convenience functions 
+proc imgLoad*(theFile: cstring): PSurface{.cdecl, importc: "IMG_Load", 
+    dynlib: ImageLibName.}
+proc imgLoadRW*(src: PRWops, freesrc: cint): PSurface{.cdecl, 
+    importc: "IMG_Load_RW", dynlib: ImageLibName.}
+  # Invert the alpha of a surface for use with OpenGL
+  #  This function is now a no-op, and only provided for backwards compatibility. 
+proc imgInvertAlpha*(theOn: cint): cint{.cdecl, importc: "IMG_InvertAlpha", 
+                                        dynlib: ImageLibName.}
+  # Functions to detect a file type, given a seekable source 
+proc imgIsBMP*(src: PRWops): cint{.cdecl, importc: "IMG_isBMP", 
+                                   dynlib: ImageLibName.}
+proc imgIsGIF*(src: PRWops): cint{.cdecl, importc: "IMG_isGIF", 
+                                   dynlib: ImageLibName.}
+proc imgIsJPG*(src: PRWops): cint{.cdecl, importc: "IMG_isJPG", 
+                                   dynlib: ImageLibName.}
+proc imgIsLBM*(src: PRWops): cint{.cdecl, importc: "IMG_isLBM", 
+                                   dynlib: ImageLibName.}
+proc imgIsPCX*(src: PRWops): cint{.cdecl, importc: "IMG_isPCX", 
+                                   dynlib: ImageLibName.}
+proc imgIsPNG*(src: PRWops): cint{.cdecl, importc: "IMG_isPNG", 
+                                   dynlib: ImageLibName.}
+proc imgIsPNM*(src: PRWops): cint{.cdecl, importc: "IMG_isPNM", 
+                                   dynlib: ImageLibName.}
+proc imgIsTIF*(src: PRWops): cint{.cdecl, importc: "IMG_isTIF", 
+                                   dynlib: ImageLibName.}
+proc imgIsXCF*(src: PRWops): cint{.cdecl, importc: "IMG_isXCF", 
+                                   dynlib: ImageLibName.}
+proc imgIsXPM*(src: PRWops): cint{.cdecl, importc: "IMG_isXPM", 
+                                   dynlib: ImageLibName.}
+proc imgIsXV*(src: PRWops): cint{.cdecl, importc: "IMG_isXV", 
+                                  dynlib: ImageLibName.}
+  # Individual loading functions 
+proc imgLoadBMP_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadBMP_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadGIF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadGIF_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadJPG_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadJPG_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadLBM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadLBM_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadPCX_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPCX_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadPNM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPNM_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadPNG_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPNG_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadTGA_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadTGA_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadTIF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadTIF_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadXCF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXCF_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadXPM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXPM_RW", 
+    dynlib: ImageLibName.}
+proc imgLoadXV_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXV_RW", 
+    dynlib: ImageLibName.}
+proc imgReadXPMFromArray*(xpm: cstringArray): PSurface{.cdecl, 
+    importc: "IMG_ReadXPMFromArray", dynlib: ImageLibName.}
+
+proc imageVersion(x: var Tversion) = 
+  x.major = IMAGE_MAJOR_VERSION
+  x.minor = IMAGE_MINOR_VERSION
+  x.patch = IMAGE_PATCHLEVEL
+
diff --git a/lib/wrappers/sdl/sdl_mixer.nim b/lib/wrappers/sdl/sdl_mixer.nim
new file mode 100644
index 000000000..2f8664635
--- /dev/null
+++ b/lib/wrappers/sdl/sdl_mixer.nim
@@ -0,0 +1,484 @@
+#******************************************************************************
+#
+#  $Id: sdl_mixer.pas,v 1.18 2007/05/29 21:31:44 savage Exp $
+#
+#
+#
+#       Borland Delphi SDL_Mixer - Simple DirectMedia Layer Mixer Library
+#       Conversion of the Simple DirectMedia Layer Headers
+#
+# Portions created by Sam Lantinga <slouken@devolution.com> are
+# Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
+# 5635-34 Springhouse Dr.
+# Pleasanton, CA 94588 (USA)
+#
+# All Rights Reserved.
+#
+# The original files are : SDL_mixer.h
+#                          music_cmd.h
+#                          wavestream.h
+#                          timidity.h
+#                          playmidi.h
+#                          music_ogg.h
+#                          mikmod.h
+#
+# The initial developer of this Pascal code was :
+# Dominqiue Louis <Dominique@SavageSoftware.com.au>
+#
+# Portions created by Dominqiue Louis are
+# Copyright (C) 2000 - 2001 Dominqiue Louis.
+#
+#
+# Contributor(s)
+# --------------
+# Matthias Thoma <ma.thoma@gmx.de>
+#
+# Obtained through:
+# Joint Endeavour of Delphi Innovators ( Project JEDI )
+#
+# You may retrieve the latest version of this file at the Project
+# JEDI home page, located at http://delphi-jedi.org
+#
+# The contents of this file are used with permission, subject to
+# the Mozilla Public License Version 1.1 (the "License"); you may
+# not use this file except in compliance with the License. You may
+# obtain a copy of the License at
+# http://www.mozilla.org/MPL/MPL-1.1.html
+#
+# Software distributed under the License is distributed on an
+# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# Description
+# -----------
+#
+#
+#
+#
+#
+#
+#
+# Requires
+# --------
+#   SDL.pas & SMPEG.pas somewhere within your search path.
+#
+# Programming Notes
+# -----------------
+#   See the Aliens Demo to see how this library is used
+#
+# Revision History
+# ----------------
+#   April    02 2001 - DL : Initial Translation
+#
+#  February  02 2002 - DL : Update to version 1.2.1
+#
+#   April   03 2003 - DL : Added jedi-sdl.inc include file to support more
+#                          Pascal compilers. Initial support is now included
+#                          for GnuPascal, VirtualPascal, TMT and obviously
+#                          continue support for Delphi Kylix and FreePascal.
+#
+#   April   24 2003 - DL : under instruction from Alexey Barkovoy, I have added
+#                          better TMT Pascal support and under instruction
+#                          from Prof. Abimbola Olowofoyeku (The African Chief),
+#                          I have added better Gnu Pascal support
+#
+#   April   30 2003 - DL : under instruction from David Mears AKA
+#                          Jason Siletto, I have added FPC Linux support.
+#                          This was compiled with fpc 1.1, so remember to set
+#                          include file path. ie. -Fi/usr/share/fpcsrc/rtl/*
+#
+#
+#  $Log: sdl_mixer.pas,v $
+#  Revision 1.18  2007/05/29 21:31:44  savage
+#  Changes as suggested by Almindor for 64bit compatibility.
+#
+#  Revision 1.17  2007/05/20 20:31:17  savage
+#  Initial Changes to Handle 64 Bits
+#
+#  Revision 1.16  2006/12/02 00:16:17  savage
+#  Updated to latest version
+#
+#  Revision 1.15  2005/04/10 11:48:33  savage
+#  Changes as suggested by Michalis, thanks.
+#
+#  Revision 1.14  2005/02/24 20:20:07  savage
+#  Changed definition of MusicType and added GetMusicType function
+#
+#  Revision 1.13  2005/01/05 01:47:09  savage
+#  Changed LibName to reflect what MacOS X should have. ie libSDL*-1.2.0.dylib respectively.
+#
+#  Revision 1.12  2005/01/04 23:14:56  savage
+#  Changed LibName to reflect what most Linux distros will have. ie libSDL*-1.2.so.0 respectively.
+#
+#  Revision 1.11  2005/01/01 02:05:19  savage
+#  Updated to v1.2.6
+#
+#  Revision 1.10  2004/09/12 21:45:17  savage
+#  Robert Reed spotted that Mix_SetMusicPosition was missing from the conversion, so this has now been added.
+#
+#  Revision 1.9  2004/08/27 21:48:24  savage
+#  IFDEFed out Smpeg support on MacOS X
+#
+#  Revision 1.8  2004/08/14 22:54:30  savage
+#  Updated so that Library name defines are correctly defined for MacOS X.
+#
+#  Revision 1.7  2004/05/10 14:10:04  savage
+#  Initial MacOS X support. Fixed defines for MACOS ( Classic ) and DARWIN ( MacOS X ).
+#
+#  Revision 1.6  2004/04/13 09:32:08  savage
+#  Changed Shared object names back to just the .so extension to avoid conflicts on various Linux/Unix distros. Therefore developers will need to create Symbolic links to the actual Share Objects if necessary.
+#
+#  Revision 1.5  2004/04/01 20:53:23  savage
+#  Changed Linux Shared Object names so they reflect the Symbolic Links that are created when installing the RPMs from the SDL site.
+#
+#  Revision 1.4  2004/03/31 22:20:02  savage
+#  Windows unit not used in this file, so it was removed to keep the code tidy.
+#
+#  Revision 1.3  2004/03/31 10:05:08  savage
+#  Better defines for Endianness under FreePascal and Borland compilers.
+#
+#  Revision 1.2  2004/03/30 20:23:28  savage
+#  Tidied up use of UNIX compiler directive.
+#
+#  Revision 1.1  2004/02/14 23:35:42  savage
+#  version 1 of sdl_image, sdl_mixer and smpeg.
+#
+#
+#
+#******************************************************************************
+
+import 
+  sdl, smpeg
+
+when defined(windows): 
+  const 
+    MixerLibName = "SDL_mixer.dll"
+elif defined(macosx): 
+  const 
+    MixerLibName = "libSDL_mixer-1.2.0.dylib"
+else: 
+  const 
+    MixerLibName = "libSDL_mixer.so"
+const 
+  MAJOR_VERSION* = 1
+  MINOR_VERSION* = 2
+  PATCHLEVEL* = 7    # Backwards compatibility
+  
+  CHANNELS* = 8           # Good default values for a PC soundcard
+  DEFAULT_FREQUENCY* = 22050
+
+when defined(IA32): 
+  const 
+    DEFAULT_FORMAT* = AUDIO_S16LSB
+else: 
+  const 
+    DEFAULT_FORMAT* = AUDIO_S16MSB
+const 
+  DEFAULT_CHANNELS* = 2
+  MAX_VOLUME* = 128       # Volume of a chunk
+  PATH_MAX* = 255             # mikmod.h constants
+                              #*
+                              #  * Library version
+                              #  *
+  LIBMIKMOD_VERSION_MAJOR* = 3
+  LIBMIKMOD_VERSION_MINOR* = 1
+  LIBMIKMOD_REVISION* = 8
+  LIBMIKMOD_VERSION* = ((LIBMIKMOD_VERSION_MAJOR shl 16) or
+      (LIBMIKMOD_VERSION_MINOR shl 8) or (LIBMIKMOD_REVISION))
+
+type                          #music_cmd.h types
+  PMusicCMD* = ptr TMusicCMD
+  TMusicCMD*{.final.} = object  #wavestream.h types
+    filename*: array[0..PATH_MAX - 1, char]
+    cmd*: array[0..PATH_MAX - 1, char]
+    pid*: TSYS_ThreadHandle
+
+  PWAVStream* = ptr TWAVStream
+  TWAVStream*{.final.} = object  #playmidi.h types
+    wavefp*: pointer
+    start*: int32
+    stop*: int32
+    cvt*: TAudioCVT
+
+  PMidiEvent* = ptr TMidiEvent
+  TMidiEvent*{.final.} = object 
+    time*: int32
+    channel*: byte
+    typ*: byte
+    a*: byte
+    b*: byte
+
+  PMidiSong* = ptr TMidiSong
+  TMidiSong*{.final.} = object  #music_ogg.h types
+    samples*: int32
+    events*: PMidiEvent
+
+  POGG_Music* = ptr TOGG_Music
+  TOGG_Music*{.final.} = object  # mikmod.h types
+                                 #*
+                                 #  * Error codes
+                                 #  *
+    playing*: int32
+    volume*: int32              #vf: OggVorbis_File;
+    section*: int32
+    cvt*: TAudioCVT
+    lenAvailable*: int32
+    sndAvailable*: pointer
+
+  TErrorEnum* = enum 
+    MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING, 
+    MMERR_SAMPLE_TOO_BIG, MMERR_OUT_OF_HANDLES, MMERR_UNKNOWN_WAVE_TYPE, 
+    MMERR_LOADING_PATTERN, MMERR_LOADING_TRACK, MMERR_LOADING_HEADER, 
+    MMERR_LOADING_SAMPLEINFO, MMERR_NOT_A_MODULE, MMERR_NOT_A_STREAM, 
+    MMERR_MED_SYNTHSAMPLES, MMERR_ITPACK_INVALID_DATA, MMERR_DETECTING_DEVICE, 
+    MMERR_INVALID_DEVICE, MMERR_INITIALIZING_MIXER, MMERR_OPENING_AUDIO, 
+    MMERR_8BIT_ONLY, MMERR_16BIT_ONLY, MMERR_STEREO_ONLY, MMERR_ULAW, 
+    MMERR_NON_BLOCK, MMERR_AF_AUDIO_PORT, MMERR_AIX_CONFIG_INIT, 
+    MMERR_AIX_CONFIG_CONTROL, MMERR_AIX_CONFIG_START, MMERR_GUS_SETTINGS, 
+    MMERR_GUS_RESET, MMERR_GUS_TIMER, MMERR_HP_SETSAMPLESIZE, MMERR_HP_SETSPEED, 
+    MMERR_HP_CHANNELS, MMERR_HP_AUDIO_OUTPUT, MMERR_HP_AUDIO_DESC, 
+    MMERR_HP_BUFFERSIZE, MMERR_OSS_SETFRAGMENT, MMERR_OSS_SETSAMPLESIZE, 
+    MMERR_OSS_SETSTEREO, MMERR_OSS_SETSPEED, MMERR_SGI_SPEED, MMERR_SGI_16BIT, 
+    MMERR_SGI_8BIT, MMERR_SGI_STEREO, MMERR_SGI_MONO, MMERR_SUN_INIT, 
+    MMERR_OS2_MIXSETUP, MMERR_OS2_SEMAPHORE, MMERR_OS2_TIMER, MMERR_OS2_THREAD, 
+    MMERR_DS_PRIORITY, MMERR_DS_BUFFER, MMERR_DS_FORMAT, MMERR_DS_NOTIFY, 
+    MMERR_DS_EVENT, MMERR_DS_THREAD, MMERR_DS_UPDATE, MMERR_WINMM_HANDLE, 
+    MMERR_WINMM_ALLOCATED, MMERR_WINMM_DEVICEID, MMERR_WINMM_FORMAT, 
+    MMERR_WINMM_UNKNOWN, MMERR_MAC_SPEED, MMERR_MAC_START, MMERR_MAX
+  PMODULE* = ptr TMODULE
+  TMODULE*{.final.} = object 
+  PUNIMOD* = ptr TUNIMOD
+  TUNIMOD* = TMODULE          #SDL_mixer.h types
+                              # The internal format for an audio chunk
+  PChunk* = ptr TChunk
+  TChunk*{.final.} = object 
+    allocated*: cint
+    abuf*: pointer
+    alen*: uint32
+    volume*: byte            # Per-sample volume, 0-128
+  
+  TFading* = enum 
+    MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN
+  TMusicType* = enum 
+    MUS_NONE, MUS_CMD, MUS_WAV, MUS_MOD, MUS_MID, MUS_OGG, MUS_MP3
+  PMusic* = ptr TMusic
+  TMusic*{.final.} = object  # The internal format for a music chunk interpreted via mikmod
+    mixtype*: TMusicType      # other fields are not aviable
+                              #    data : TMusicUnion;
+                              #    fading : TMix_Fading;
+                              #    fade_volume : integer;
+                              #    fade_step : integer;
+                              #    fade_steps : integer;
+                              #    error : integer;
+  
+  TMixFunction* = proc (udata, stream: pointer, length: cint): pointer{.
+      cdecl.} # This macro can be used to fill a version structure with the compile-time
+              #  version of the SDL_mixer library.
+
+proc version*(x: var sdl.Tversion)
+  # This function gets the version of the dynamically linked SDL_mixer library.
+  #     It should NOT be used to fill a version structure, instead you should use the
+  #     SDL_MIXER_VERSION() macro.
+proc linkedVersion*(): sdl.Pversion{.cdecl, importc: "Mix_Linked_Version", 
+                                      dynlib: MixerLibName.}
+  # Open the mixer with a certain audio format
+proc openAudio*(frequency: cint, format: uint16, channels: cint, 
+                    chunksize: cint): cint{.cdecl, importc: "Mix_OpenAudio", 
+    dynlib: MixerLibName.}
+  # Dynamically change the number of channels managed by the mixer.
+  #   If decreasing the number of channels, the upper channels are
+  #   stopped.
+  #   This function returns the new number of allocated channels.
+  #
+proc allocateChannels*(numchannels: cint): cint{.cdecl, 
+    importc: "Mix_AllocateChannels", dynlib: MixerLibName.}
+  # Find out what the actual audio device parameters are.
+  #   This function returns 1 if the audio has been opened, 0 otherwise.
+  #
+proc querySpec*(frequency: var cint, format: var uint16, channels: var cint): cint{.
+    cdecl, importc: "Mix_QuerySpec", dynlib: MixerLibName.}
+  # Load a wave file or a music (.mod .s3m .it .xm) file
+proc loadWAV_RW*(src: PRWops, freesrc: cint): PChunk{.cdecl, 
+    importc: "Mix_LoadWAV_RW", dynlib: MixerLibName.}
+proc loadWAV*(filename: cstring): PChunk
+proc loadMUS*(filename: cstring): PMusic{.cdecl, importc: "Mix_LoadMUS", 
+    dynlib: MixerLibName.}
+  # Load a wave file of the mixer format from a memory buffer
+proc quickLoadWAV*(mem: pointer): PChunk{.cdecl, 
+    importc: "Mix_QuickLoad_WAV", dynlib: MixerLibName.}
+  # Free an audio chunk previously loaded
+proc freeChunk*(chunk: PChunk){.cdecl, importc: "Mix_FreeChunk", 
+                                        dynlib: MixerLibName.}
+proc freeMusic*(music: PMusic){.cdecl, importc: "Mix_FreeMusic", 
+                                        dynlib: MixerLibName.}
+  # Find out the music format of a mixer music, or the currently playing
+  #   music, if 'music' is NULL.
+proc getMusicType*(music: PMusic): TMusicType{.cdecl, 
+    importc: "Mix_GetMusicType", dynlib: MixerLibName.}
+  # Set a function that is called after all mixing is performed.
+  #   This can be used to provide real-time visual display of the audio stream
+  #   or add a custom mixer filter for the stream data.
+  #
+proc setPostMix*(mixFunc: TMixFunction, arg: pointer){.cdecl, 
+    importc: "Mix_SetPostMix", dynlib: MixerLibName.}
+  # Add your own music player or additional mixer function.
+  #   If 'mix_func' is NULL, the default music player is re-enabled.
+  #
+proc hookMusic*(mixFunc: TMixFunction, arg: pointer){.cdecl, 
+    importc: "Mix_HookMusic", dynlib: MixerLibName.}
+  # Add your own callback when the music has finished playing.
+  #
+proc hookMusicFinished*(musicFinished: pointer){.cdecl, 
+    importc: "Mix_HookMusicFinished", dynlib: MixerLibName.}
+  # Get a pointer to the user data for the current music hook
+proc getMusicHookData*(): pointer{.cdecl, importc: "Mix_GetMusicHookData", 
+                                       dynlib: MixerLibName.}
+  #* Add your own callback when a channel has finished playing. NULL
+  # * to disable callback.*
+type 
+  TChannelFinished* = proc (channel: cint){.cdecl.}
+
+proc channelFinished*(channelFinished: TChannelFinished){.cdecl, 
+    importc: "Mix_ChannelFinished", dynlib: MixerLibName.}
+const 
+  CHANNEL_POST* = - 2     
+
+type 
+  TEffectFunc* = proc (chan: cint, stream: pointer, length: cint, 
+                       udata: pointer): pointer{.cdecl.}     
+  TEffectDone* = proc (chan: cint, udata: pointer): pointer{.cdecl.} 
+proc registerEffect*(chan: cint, f: TEffectFunc, d: TEffectDone, 
+                         arg: pointer): cint{.cdecl, 
+    importc: "Mix_RegisterEffect", dynlib: MixerLibName.}
+
+proc unregisterEffect*(channel: cint, f: TEffectFunc): cint{.cdecl, 
+    importc: "Mix_UnregisterEffect", dynlib: MixerLibName.}
+
+proc unregisterAllEffects*(channel: cint): cint{.cdecl, 
+    importc: "Mix_UnregisterAllEffects", dynlib: MixerLibName.}
+const 
+  EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED"
+  
+proc setPanning*(channel: cint, left: byte, right: byte): cint{.cdecl, 
+    importc: "Mix_SetPanning", dynlib: MixerLibName.}
+
+proc setPosition*(channel: cint, angle: int16, distance: byte): cint{.cdecl, 
+    importc: "Mix_SetPosition", dynlib: MixerLibName.}
+
+proc setDistance*(channel: cint, distance: byte): cint{.cdecl, 
+    importc: "Mix_SetDistance", dynlib: MixerLibName.}
+
+proc setReverseStereo*(channel: cint, flip: cint): cint{.cdecl, 
+    importc: "Mix_SetReverseStereo", dynlib: MixerLibName.}
+
+proc reserveChannels*(num: cint): cint{.cdecl, importc: "Mix_ReserveChannels", 
+    dynlib: MixerLibName.}
+
+proc groupChannel*(which: cint, tag: cint): cint{.cdecl, 
+    importc: "Mix_GroupChannel", dynlib: MixerLibName.}
+proc groupChannels*(`from`: cint, `to`: cint, tag: cint): cint{.cdecl, 
+    importc: "Mix_GroupChannels", dynlib: MixerLibName.}
+proc groupAvailable*(tag: cint): cint{.cdecl, importc: "Mix_GroupAvailable", 
+    dynlib: MixerLibName.}
+proc groupCount*(tag: cint): cint{.cdecl, importc: "Mix_GroupCount", 
+                                     dynlib: MixerLibName.}
+proc groupOldest*(tag: cint): cint{.cdecl, importc: "Mix_GroupOldest", 
+                                      dynlib: MixerLibName.}
+proc groupNewer*(tag: cint): cint{.cdecl, importc: "Mix_GroupNewer", 
+                                     dynlib: MixerLibName.}
+proc playChannelTimed*(channel: cint, chunk: PChunk, loops: cint, 
+                           ticks: cint): cint{.cdecl, 
+    importc: "Mix_PlayChannelTimed", dynlib: MixerLibName.}
+proc playChannel*(channel: cint, chunk: PChunk, loops: cint): cint
+proc playMusic*(music: PMusic, loops: cint): cint{.cdecl, 
+    importc: "Mix_PlayMusic", dynlib: MixerLibName.}
+proc fadeInMusic*(music: PMusic, loops: cint, ms: cint): cint{.cdecl, 
+    importc: "Mix_FadeInMusic", dynlib: MixerLibName.}
+proc fadeInChannelTimed*(channel: cint, chunk: PChunk, loops: cint, 
+                             ms: cint, ticks: cint): cint{.cdecl, 
+    importc: "Mix_FadeInChannelTimed", dynlib: MixerLibName.}
+proc fadeInChannel*(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint
+
+proc volume*(channel: cint, volume: cint): cint{.cdecl, importc: "Mix_Volume", 
+    dynlib: MixerLibName.}
+proc volumeChunk*(chunk: PChunk, volume: cint): cint{.cdecl, 
+    importc: "Mix_VolumeChunk", dynlib: MixerLibName.}
+proc volumeMusic*(volume: cint): cint{.cdecl, importc: "Mix_VolumeMusic", 
+    dynlib: MixerLibName.}
+
+proc haltChannel*(channel: cint): cint{.cdecl, importc: "Mix_HaltChannel", 
+    dynlib: MixerLibName.}
+proc haltGroup*(tag: cint): cint{.cdecl, importc: "Mix_HaltGroup", 
+                                    dynlib: MixerLibName.}
+proc haltMusic*(): cint{.cdecl, importc: "Mix_HaltMusic", 
+                            dynlib: MixerLibName.}
+  # Change the expiration delay for a particular channel.
+  #   The sample will stop playing after the 'ticks' milliseconds have elapsed,
+  #   or remove the expiration if 'ticks' is -1
+  #
+proc expireChannel*(channel: cint, ticks: cint): cint{.cdecl, 
+    importc: "Mix_ExpireChannel", dynlib: MixerLibName.}
+  # Halt a channel, fading it out progressively till it's silent
+  #   The ms parameter indicates the number of milliseconds the fading
+  #   will take.
+  #
+proc fadeOutChannel*(which: cint, ms: cint): cint{.cdecl, 
+    importc: "Mix_FadeOutChannel", dynlib: MixerLibName.}
+proc fadeOutGroup*(tag: cint, ms: cint): cint{.cdecl, 
+    importc: "Mix_FadeOutGroup", dynlib: MixerLibName.}
+proc fadeOutMusic*(ms: cint): cint{.cdecl, importc: "Mix_FadeOutMusic", 
+                                      dynlib: MixerLibName.}
+  # Query the fading status of a channel
+proc fadingMusic*(): TFading{.cdecl, importc: "Mix_FadingMusic", 
+                                      dynlib: MixerLibName.}
+proc fadingChannel*(which: cint): TFading{.cdecl, 
+    importc: "Mix_FadingChannel", dynlib: MixerLibName.}
+
+proc pause*(channel: cint){.cdecl, importc: "Mix_Pause", dynlib: MixerLibName.}
+proc resume*(channel: cint){.cdecl, importc: "Mix_Resume", 
+                                dynlib: MixerLibName.}
+proc paused*(channel: cint): cint{.cdecl, importc: "Mix_Paused", 
+                                     dynlib: MixerLibName.}
+
+proc pauseMusic*(){.cdecl, importc: "Mix_PauseMusic", dynlib: MixerLibName.}
+proc resumeMusic*(){.cdecl, importc: "Mix_ResumeMusic", dynlib: MixerLibName.}
+proc rewindMusic*(){.cdecl, importc: "Mix_RewindMusic", dynlib: MixerLibName.}
+proc pausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", 
+                              dynlib: MixerLibName.}
+
+proc setMusicPosition*(position: float64): cint{.cdecl, 
+    importc: "Mix_SetMusicPosition", dynlib: MixerLibName.}
+
+proc playing*(channel: cint): cint{.cdecl, importc: "Mix_Playing", 
+                                      dynlib: MixerLibName.}
+proc playingMusic*(): cint{.cdecl, importc: "Mix_PlayingMusic", 
+                               dynlib: MixerLibName.}
+
+proc setMusicCMD*(command: cstring): cint{.cdecl, importc: "Mix_SetMusicCMD", 
+    dynlib: MixerLibName.}
+
+proc setSynchroValue*(value: cint): cint{.cdecl, 
+    importc: "Mix_SetSynchroValue", dynlib: MixerLibName.}
+proc getSynchroValue*(): cint{.cdecl, importc: "Mix_GetSynchroValue", 
+                                  dynlib: MixerLibName.}
+
+proc getChunk*(channel: cint): PChunk{.cdecl, importc: "Mix_GetChunk", 
+    dynlib: MixerLibName.}
+
+proc closeAudio*(){.cdecl, importc: "Mix_CloseAudio", dynlib: MixerLibName.}
+
+proc version(x: var sdl.Tversion) = 
+  x.major = MAJOR_VERSION
+  x.minor = MINOR_VERSION
+  x.patch = PATCHLEVEL
+
+proc loadWAV(filename: cstring): PChunk = 
+  result = loadWAV_RW(rWFromFile(filename, "rb"), 1)
+
+proc playChannel(channel: cint, chunk: PChunk, loops: cint): cint = 
+  result = playChannelTimed(channel, chunk, loops, - 1)
+
+proc fadeInChannel(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint = 
+  result = fadeInChannelTimed(channel, chunk, loops, ms, - 1)
+
diff --git a/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim b/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim
new file mode 100644
index 000000000..7a8c41af1
--- /dev/null
+++ b/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim
@@ -0,0 +1,351 @@
+#******************************************************************************
+# Copy of SDL_Mixer without smpeg dependency and mp3 support                    
+#******************************************************************************
+
+import 
+  sdl
+
+when defined(windows): 
+  const 
+    MixerLibName = "SDL_mixer.dll"
+elif defined(macosx): 
+  const 
+    MixerLibName = "libSDL_mixer-1.2.0.dylib"
+else: 
+  const 
+    MixerLibName = "libSDL_mixer.so"
+const 
+  MAJOR_VERSION* = 1
+  MINOR_VERSION* = 2
+  PATCHLEVEL* = 7    # Backwards compatibility
+   
+  CHANNELS* = 8           # Good default values for a PC soundcard 
+  DEFAULT_FREQUENCY* = 22050
+
+when defined(IA32): 
+  const 
+    DEFAULT_FORMAT* = AUDIO_S16LSB
+else: 
+  const 
+    DEFAULT_FORMAT* = AUDIO_S16MSB
+const 
+  DEFAULT_CHANNELS* = 2
+  MAX_VOLUME* = 128       # Volume of a chunk 
+  PATH_MAX* = 255
+  
+  LIBMIKMOD_VERSION_MAJOR* = 3
+  LIBMIKMOD_VERSION_MINOR* = 1
+  LIBMIKMOD_REVISION* = 8
+  LIBMIKMOD_VERSION* = ((LIBMIKMOD_VERSION_MAJOR shl 16) or
+      (LIBMIKMOD_VERSION_MINOR shl 8) or (LIBMIKMOD_REVISION))
+
+type                          #music_cmd.h types
+  PMusicCMD* = ptr TMusicCMD
+  TMusicCMD*{.final.} = object  #wavestream.h types
+    filename*: array[0..PATH_MAX - 1, char]
+    cmd*: array[0..PATH_MAX - 1, char]
+    pid*: TSYS_ThreadHandle
+
+  PWAVStream* = ptr TWAVStream
+  TWAVStream*{.final.} = object  #playmidi.h types
+    wavefp*: pointer
+    start*: int32
+    stop*: int32
+    cvt*: TAudioCVT
+
+  PMidiEvent* = ptr TMidiEvent
+  TMidiEvent*{.final.} = object 
+    time*: int32
+    channel*: byte
+    typ*: byte
+    a*: byte
+    b*: byte
+
+  PMidiSong* = ptr TMidiSong
+  TMidiSong*{.final.} = object  #music_ogg.h types
+    samples*: int32
+    events*: PMidiEvent
+
+  POGG_Music* = ptr TOGG_Music
+  TOGG_Music*{.final.} = object  # mikmod.h types
+                                 #*
+                                 #  * Error codes
+                                 #  *
+    playing*: cint
+    volume*: cint              #vf: OggVorbis_File;
+    section*: cint
+    cvt*: TAudioCVT
+    lenAvailable*: cint
+    sndAvailable*: pointer
+
+  TErrorEnum* = enum 
+    MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING, 
+    MMERR_SAMPLE_TOO_BIG, MMERR_OUT_OF_HANDLES, MMERR_UNKNOWN_WAVE_TYPE, 
+    MMERR_LOADING_PATTERN, MMERR_LOADING_TRACK, MMERR_LOADING_HEADER, 
+    MMERR_LOADING_SAMPLEINFO, MMERR_NOT_A_MODULE, MMERR_NOT_A_STREAM, 
+    MMERR_MED_SYNTHSAMPLES, MMERR_ITPACK_INVALID_DATA, MMERR_DETECTING_DEVICE, 
+    MMERR_INVALID_DEVICE, MMERR_INITIALIZING_MIXER, MMERR_OPENING_AUDIO, 
+    MMERR_8BIT_ONLY, MMERR_16BIT_ONLY, MMERR_STEREO_ONLY, MMERR_ULAW, 
+    MMERR_NON_BLOCK, MMERR_AF_AUDIO_PORT, MMERR_AIX_CONFIG_INIT, 
+    MMERR_AIX_CONFIG_CONTROL, MMERR_AIX_CONFIG_START, MMERR_GUS_SETTINGS, 
+    MMERR_GUS_RESET, MMERR_GUS_TIMER, MMERR_HP_SETSAMPLESIZE, MMERR_HP_SETSPEED, 
+    MMERR_HP_CHANNELS, MMERR_HP_AUDIO_OUTPUT, MMERR_HP_AUDIO_DESC, 
+    MMERR_HP_BUFFERSIZE, MMERR_OSS_SETFRAGMENT, MMERR_OSS_SETSAMPLESIZE, 
+    MMERR_OSS_SETSTEREO, MMERR_OSS_SETSPEED, MMERR_SGI_SPEED, MMERR_SGI_16BIT, 
+    MMERR_SGI_8BIT, MMERR_SGI_STEREO, MMERR_SGI_MONO, MMERR_SUN_INIT, 
+    MMERR_OS2_MIXSETUP, MMERR_OS2_SEMAPHORE, MMERR_OS2_TIMER, MMERR_OS2_THREAD, 
+    MMERR_DS_PRIORITY, MMERR_DS_BUFFER, MMERR_DS_FORMAT, MMERR_DS_NOTIFY, 
+    MMERR_DS_EVENT, MMERR_DS_THREAD, MMERR_DS_UPDATE, MMERR_WINMM_HANDLE, 
+    MMERR_WINMM_ALLOCATED, MMERR_WINMM_DEVICEID, MMERR_WINMM_FORMAT, 
+    MMERR_WINMM_UNKNOWN, MMERR_MAC_SPEED, MMERR_MAC_START, MMERR_MAX
+  PMODULE* = ptr TMODULE
+  TMODULE*{.final.} = object 
+  PUNIMOD* = ptr TUNIMOD
+  TUNIMOD* = TMODULE          #SDL_mixer.h types
+                              # The internal format for an audio chunk 
+  PChunk* = ptr TChunk
+  TChunk*{.final.} = object 
+    allocated*: cint
+    abuf*: pointer
+    alen*: uint32
+    volume*: byte            # Per-sample volume, 0-128 
+  
+  TFading* = enum 
+    MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN
+  TMusicType* = enum 
+    MUS_NONE, MUS_CMD, MUS_WAV, MUS_MOD, MUS_MID, MUS_OGG
+  PMusic* = ptr TMusic
+  TMusic*{.final.} = object 
+    typ*: TMusicType
+
+  TMixFunction* = proc (udata, stream: pointer, length: cint): pointer{.
+      cdecl.} # This macro can be used to fill a version structure with the compile-time
+              #  version of the SDL_mixer library. 
+
+proc version*(x: var sdl.Tversion)
+  # This function gets the version of the dynamically linked SDL_mixer library.
+  #     It should NOT be used to fill a version structure, instead you should use the
+  #     SDL_MIXER_VERSION() macro. 
+proc linkedVersion*(): sdl.Pversion{.cdecl, importc: "Mix_Linked_Version", 
+                                      dynlib: MixerLibName.}
+  # Open the mixer with a certain audio format 
+proc openAudio*(frequency: cint, format: uint16, channels: cint, 
+                    chunksize: cint): cint{.cdecl, importc: "Mix_OpenAudio", 
+    dynlib: MixerLibName.}
+  # Dynamically change the number of channels managed by the mixer.
+  #   If decreasing the number of channels, the upper channels are
+  #   stopped.
+  #   This function returns the new number of allocated channels.
+  # 
+proc allocateChannels*(numchannels: cint): cint{.cdecl, 
+    importc: "Mix_AllocateChannels", dynlib: MixerLibName.}
+  # Find out what the actual audio device parameters are.
+  #   This function returns 1 if the audio has been opened, 0 otherwise.
+  # 
+proc querySpec*(frequency: var cint, format: var uint16, channels: var cint): cint{.
+    cdecl, importc: "Mix_QuerySpec", dynlib: MixerLibName.}
+  # Load a wave file or a music (.mod .s3m .it .xm) file 
+proc LoadWAV_RW*(src: PRWops, freesrc: cint): PChunk{.cdecl, 
+    importc: "Mix_LoadWAV_RW", dynlib: MixerLibName.}
+proc loadWAV*(filename: cstring): PChunk
+proc loadMUS*(filename: cstring): PMusic{.cdecl, importc: "Mix_LoadMUS", 
+    dynlib: MixerLibName.}
+  # Load a wave file of the mixer format from a memory buffer 
+proc quickLoadWAV*(mem: pointer): PChunk{.cdecl, 
+    importc: "Mix_QuickLoad_WAV", dynlib: MixerLibName.}
+  # Free an audio chunk previously loaded 
+proc freeChunk*(chunk: PChunk){.cdecl, importc: "Mix_FreeChunk", 
+                                        dynlib: MixerLibName.}
+proc freeMusic*(music: PMusic){.cdecl, importc: "Mix_FreeMusic", 
+                                        dynlib: MixerLibName.}
+  # Find out the music format of a mixer music, or the currently playing
+  #   music, if 'music' is NULL.
+proc getMusicType*(music: PMusic): TMusicType{.cdecl, 
+    importc: "Mix_GetMusicType", dynlib: MixerLibName.}
+  # Set a function that is called after all mixing is performed.
+  #   This can be used to provide real-time visual display of the audio stream
+  #   or add a custom mixer filter for the stream data.
+  #
+proc setPostMix*(mixfunc: TMixFunction, arg: pointer){.cdecl, 
+    importc: "Mix_SetPostMix", dynlib: MixerLibName.}
+  # Add your own music player or additional mixer function.
+  #   If 'mix_func' is NULL, the default music player is re-enabled.
+  # 
+proc hookMusic*(mixFunc: TMixFunction, arg: pointer){.cdecl, 
+    importc: "Mix_HookMusic", dynlib: MixerLibName.}
+  # Add your own callback when the music has finished playing.
+  # 
+proc hookMusicFinished*(musicFinished: pointer){.cdecl, 
+    importc: "Mix_HookMusicFinished", dynlib: MixerLibName.}
+  # Get a pointer to the user data for the current music hook 
+proc getMusicHookData*(): pointer{.cdecl, importc: "Mix_GetMusicHookData", 
+                                       dynlib: MixerLibName.}
+  #* Add your own callback when a channel has finished playing. NULL
+  # * to disable callback.*
+type 
+  TChannelFinished* = proc (channel: cint){.cdecl.}
+
+proc channelFinished*(channelFinished: TChannelFinished){.cdecl, 
+    importc: "Mix_ChannelFinished", dynlib: MixerLibName.}
+const 
+  CHANNEL_POST* = - 2 
+  
+type 
+  TEffectFunc* = proc (chan: cint, stream: pointer, length: cint, 
+                           udata: pointer): pointer{.cdecl.} 
+  TEffectDone* = proc (chan: cint, udata: pointer): pointer{.cdecl.} 
+
+proc registerEffect*(chan: cint, f: TEffectFunc, d: TEffectDone, 
+                         arg: pointer): cint{.cdecl, 
+    importc: "Mix_RegisterEffect", dynlib: MixerLibName.}
+
+proc unregisterEffect*(channel: cint, f: TEffectFunc): cint{.cdecl, 
+    importc: "Mix_UnregisterEffect", dynlib: MixerLibName.}
+
+proc unregisterAllEffects*(channel: cint): cint{.cdecl, 
+    importc: "Mix_UnregisterAllEffects", dynlib: MixerLibName.}
+
+const 
+  EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED"  
+  
+proc setPanning*(channel: cint, left: byte, right: byte): cint{.cdecl, 
+    importc: "Mix_SetPanning", dynlib: MixerLibName.}
+   
+proc setPosition*(channel: cint, angle: int16, distance: byte): cint{.cdecl, 
+    importc: "Mix_SetPosition", dynlib: MixerLibName.}
+   
+proc setDistance*(channel: cint, distance: byte): cint{.cdecl, 
+    importc: "Mix_SetDistance", dynlib: MixerLibName.}
+
+proc setReverseStereo*(channel: cint, flip: cint): cint{.cdecl, 
+    importc: "Mix_SetReverseStereo", dynlib: MixerLibName.}
+
+proc reserveChannels*(num: cint): cint{.cdecl, importc: "Mix_ReserveChannels", 
+    dynlib: MixerLibName.}
+
+proc groupChannel*(which: cint, tag: cint): cint{.cdecl, 
+    importc: "Mix_GroupChannel", dynlib: MixerLibName.}
+  # Assign several consecutive channels to a group 
+proc groupChannels*(`from`: cint, `to`: cint, tag: cint): cint{.cdecl, 
+    importc: "Mix_GroupChannels", dynlib: MixerLibName.}
+  # Finds the first available channel in a group of channels 
+proc groupAvailable*(tag: cint): cint{.cdecl, importc: "Mix_GroupAvailable", 
+    dynlib: MixerLibName.}
+  # Returns the number of channels in a group. This is also a subtle
+  #   way to get the total number of channels when 'tag' is -1
+  # 
+proc groupCount*(tag: cint): cint{.cdecl, importc: "Mix_GroupCount", 
+                                     dynlib: MixerLibName.}
+  # Finds the "oldest" sample playing in a group of channels 
+proc groupOldest*(tag: cint): cint{.cdecl, importc: "Mix_GroupOldest", 
+                                      dynlib: MixerLibName.}
+  # Finds the "most recent" (i.e. last) sample playing in a group of channels 
+proc groupNewer*(tag: cint): cint{.cdecl, importc: "Mix_GroupNewer", 
+                                     dynlib: MixerLibName.}
+  # The same as above, but the sound is played at most 'ticks' milliseconds 
+proc playChannelTimed*(channel: cint, chunk: PChunk, loops: cint, 
+                           ticks: cint): cint{.cdecl, 
+    importc: "Mix_PlayChannelTimed", dynlib: MixerLibName.}
+
+proc playChannel*(channel: cint, chunk: PChunk, loops: cint): cint
+proc playMusic*(music: PMusic, loops: cint): cint{.cdecl, 
+    importc: "Mix_PlayMusic", dynlib: MixerLibName.}
+  # Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions 
+proc fadeInMusic*(music: PMusic, loops: cint, ms: cint): cint{.cdecl, 
+    importc: "Mix_FadeInMusic", dynlib: MixerLibName.}
+proc fadeInChannelTimed*(channel: cint, chunk: PChunk, loops: cint, 
+                             ms: cint, ticks: cint): cint{.cdecl, 
+    importc: "Mix_FadeInChannelTimed", dynlib: MixerLibName.}
+proc fadeInChannel*(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint
+  # Set the volume in the range of 0-128 of a specific channel or chunk.
+  #   If the specified channel is -1, set volume for all channels.
+  #   Returns the original volume.
+  #   If the specified volume is -1, just return the current volume.
+  #
+proc volume*(channel: cint, volume: cint): cint{.cdecl, importc: "Mix_Volume", 
+    dynlib: MixerLibName.}
+proc volumeChunk*(chunk: PChunk, volume: cint): cint{.cdecl, 
+    importc: "Mix_VolumeChunk", dynlib: MixerLibName.}
+proc volumeMusic*(volume: cint): cint{.cdecl, importc: "Mix_VolumeMusic", 
+    dynlib: MixerLibName.}
+  # Halt playing of a particular channel 
+proc haltChannel*(channel: cint): cint{.cdecl, importc: "Mix_HaltChannel", 
+    dynlib: MixerLibName.}
+proc haltGroup*(tag: cint): cint{.cdecl, importc: "Mix_HaltGroup", 
+                                    dynlib: MixerLibName.}
+proc haltMusic*(): cint{.cdecl, importc: "Mix_HaltMusic", 
+                            dynlib: MixerLibName.}
+
+proc expireChannel*(channel: cint, ticks: cint): cint{.cdecl, 
+    importc: "Mix_ExpireChannel", dynlib: MixerLibName.}
+
+proc fadeOutChannel*(which: cint, ms: cint): cint{.cdecl, 
+    importc: "Mix_FadeOutChannel", dynlib: MixerLibName.}
+proc fadeOutGroup*(tag: cint, ms: cint): cint{.cdecl, 
+    importc: "Mix_FadeOutGroup", dynlib: MixerLibName.}
+proc fadeOutMusic*(ms: cint): cint{.cdecl, importc: "Mix_FadeOutMusic", 
+                                      dynlib: MixerLibName.}
+  # Query the fading status of a channel 
+proc fadingMusic*(): TFading{.cdecl, importc: "Mix_FadingMusic", 
+                                      dynlib: MixerLibName.}
+proc fadingChannel*(which: cint): TFading{.cdecl, 
+    importc: "Mix_FadingChannel", dynlib: MixerLibName.}
+  # Pause/Resume a particular channel 
+proc pause*(channel: cint){.cdecl, importc: "Mix_Pause", dynlib: MixerLibName.}
+proc resume*(channel: cint){.cdecl, importc: "Mix_Resume", 
+                                dynlib: MixerLibName.}
+proc paused*(channel: cint): cint{.cdecl, importc: "Mix_Paused", 
+                                     dynlib: MixerLibName.}
+  # Pause/Resume the music stream 
+proc pauseMusic*(){.cdecl, importc: "Mix_PauseMusic", dynlib: MixerLibName.}
+proc resumeMusic*(){.cdecl, importc: "Mix_ResumeMusic", dynlib: MixerLibName.}
+proc rewindMusic*(){.cdecl, importc: "Mix_RewindMusic", dynlib: MixerLibName.}
+proc pausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", 
+                              dynlib: MixerLibName.}
+  # Set the current position in the music stream.
+  #  This returns 0 if successful, or -1 if it failed or isn't implemented.
+  #  This function is only implemented for MOD music formats (set pattern
+  #  order number) and for OGG music (set position in seconds), at the
+  #  moment.
+  #
+proc setMusicPosition*(position: float64): cint{.cdecl, 
+    importc: "Mix_SetMusicPosition", dynlib: MixerLibName.}
+  # Check the status of a specific channel.
+  #   If the specified channel is -1, check all channels.
+  #
+proc playing*(channel: cint): cint{.cdecl, importc: "Mix_Playing", 
+                                      dynlib: MixerLibName.}
+proc playingMusic*(): cint{.cdecl, importc: "Mix_PlayingMusic", 
+                               dynlib: MixerLibName.}
+  # Stop music and set external music playback command 
+proc setMusicCMD*(command: cstring): cint{.cdecl, importc: "Mix_SetMusicCMD", 
+    dynlib: MixerLibName.}
+  # Synchro value is set by MikMod from modules while playing 
+proc setSynchroValue*(value: cint): cint{.cdecl, 
+    importc: "Mix_SetSynchroValue", dynlib: MixerLibName.}
+proc getSynchroValue*(): cint{.cdecl, importc: "Mix_GetSynchroValue", 
+                                  dynlib: MixerLibName.}
+  #
+  #  Get the Mix_Chunk currently associated with a mixer channel
+  #    Returns nil if it's an invalid channel, or there's no chunk associated.
+  #
+proc getChunk*(channel: cint): PChunk{.cdecl, importc: "Mix_GetChunk", 
+    dynlib: MixerLibName.}
+  # Close the mixer, halting all playing audio 
+proc closeAudio*(){.cdecl, importc: "Mix_CloseAudio", dynlib: MixerLibName.}
+  # We'll use SDL for reporting errors 
+
+proc version(x: var Tversion) = 
+  x.major = MAJOR_VERSION
+  x.minor = MINOR_VERSION
+  x.patch = PATCHLEVEL
+
+proc loadWAV(filename: cstring): PChunk = 
+  result = LoadWAV_RW(rWFromFile(filename, "rb"), 1)
+
+proc playChannel(channel: cint, chunk: PChunk, loops: cint): cint = 
+  result = playChannelTimed(channel, chunk, loops, - 1)
+
+proc fadeInChannel(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint = 
+  result = fadeInChannelTimed(channel, chunk, loops, ms, - 1)
+
diff --git a/lib/wrappers/sdl/sdl_net.nim b/lib/wrappers/sdl/sdl_net.nim
new file mode 100644
index 000000000..1ffdb5cca
--- /dev/null
+++ b/lib/wrappers/sdl/sdl_net.nim
@@ -0,0 +1,426 @@
+#******************************************************************************
+#
+#  $Id: sdl_net.pas,v 1.7 2005/01/01 02:14:21 savage Exp $
+#
+#
+#                                                                              
+#       Borland Delphi SDL_Net - A x-platform network library for use with SDL.
+#       Conversion of the Simple DirectMedia Layer Network Headers             
+#                                                                              
+# Portions created by Sam Lantinga <slouken@devolution.com> are                
+# Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga                     
+# 5635-34 Springhouse Dr.                                                      
+# Pleasanton, CA 94588 (USA)                                                   
+#                                                                              
+# All Rights Reserved.                                                         
+#                                                                              
+# The original files are : SDL_net.h                                           
+#                                                                              
+# The initial developer of this Pascal code was :                              
+# Dominqiue Louis <Dominique@SavageSoftware.com.au>                            
+#                                                                              
+# Portions created by Dominqiue Louis are                                      
+# Copyright (C) 2000 - 2001 Dominqiue Louis.                                   
+#                                                                              
+#                                                                              
+# Contributor(s)                                                               
+# --------------                                                               
+# Matthias Thoma <ma.thoma@gmx.de>                                             
+#                                                                              
+# Obtained through:                                                            
+# Joint Endeavour of Delphi Innovators ( Project JEDI )                        
+#                                                                              
+# You may retrieve the latest version of this file at the Project              
+# JEDI home page, located at http://delphi-jedi.org                            
+#                                                                              
+# The contents of this file are used with permission, subject to               
+# the Mozilla Public License Version 1.1 (the "License"); you may              
+# not use this file except in compliance with the License. You may             
+# obtain a copy of the License at                                              
+# http://www.mozilla.org/MPL/MPL-1.1.html                                      
+#                                                                              
+# Software distributed under the License is distributed on an                  
+# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               
+# implied. See the License for the specific language governing                 
+# rights and limitations under the License.                                    
+#                                                                              
+# Description                                                                  
+# -----------                                                                  
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+# Requires                                                                     
+# --------                                                                     
+#   SDL.pas somehere in your search path                                       
+#                                                                              
+# Programming Notes                                                            
+# -----------------                                                            
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+# Revision History                                                             
+# ----------------                                                             
+#   April   09 2001 - DL : Initial Translation                                 
+#                                                                              
+#   April   03 2003 - DL : Added jedi-sdl.inc include file to support more     
+#                          Pascal compilers. Initial support is now included   
+#                          for GnuPascal, VirtualPascal, TMT and obviously     
+#                          continue support for Delphi Kylix and FreePascal.   
+#                                                                              
+#   April   24 2003 - DL : under instruction from Alexey Barkovoy, I have added
+#                          better TMT Pascal support and under instruction     
+#                          from Prof. Abimbola Olowofoyeku (The African Chief),
+#                          I have added better Gnu Pascal support              
+#                                                                              
+#   April   30 2003 - DL : under instruction from David Mears AKA              
+#                          Jason Siletto, I have added FPC Linux support.      
+#                          This was compiled with fpc 1.1, so remember to set  
+#                          include file path. ie. -Fi/usr/share/fpcsrc/rtl/*   
+#                                                                              
+#
+#  $Log: sdl_net.pas,v $
+#  Revision 1.7  2005/01/01 02:14:21  savage
+#  Updated to v1.2.5
+#
+#  Revision 1.6  2004/08/14 22:54:30  savage
+#  Updated so that Library name defines are correctly defined for MacOS X.
+#
+#  Revision 1.5  2004/05/10 14:10:04  savage
+#  Initial MacOS X support. Fixed defines for MACOS ( Classic ) and DARWIN ( MacOS X ).
+#
+#  Revision 1.4  2004/04/13 09:32:08  savage
+#  Changed Shared object names back to just the .so extension to avoid conflicts on various Linux/Unix distros. Therefore developers will need to create Symbolic links to the actual Share Objects if necessary.
+#
+#  Revision 1.3  2004/04/01 20:53:23  savage
+#  Changed Linux Shared Object names so they reflect the Symbolic Links that are created when installing the RPMs from the SDL site.
+#
+#  Revision 1.2  2004/03/30 20:23:28  savage
+#  Tidied up use of UNIX compiler directive.
+#
+#  Revision 1.1  2004/02/16 22:16:40  savage
+#  v1.0 changes
+#
+#
+#
+#******************************************************************************
+
+import 
+  sdl
+
+when defined(windows): 
+  const 
+    NetLibName = "SDL_net.dll"
+elif defined(macosx): 
+  const 
+    NetLibName = "libSDL_net.dylib"
+else: 
+  const 
+    NetLibName = "libSDL_net.so"
+const                         #* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL *
+  MAJOR_VERSION* = 1
+  MINOR_VERSION* = 2
+  PATCHLEVEL* = 5        # SDL_Net.h constants
+                         #* Resolve a host name and port to an IP address in network form.
+                         #   If the function succeeds, it will return 0.
+                         #   If the host couldn't be resolved, the host portion of the returned
+                         #   address will be INADDR_NONE, and the function will return -1.
+                         #   If 'host' is NULL, the resolved host will be set to INADDR_ANY.
+                         # *
+  INADDR_ANY* = 0x00000000
+  INADDR_NONE* = 0xFFFFFFFF #***********************************************************************
+                            #* UDP network API                                                     *
+                            #***********************************************************************
+                            #* The maximum channels on a a UDP socket *
+  MAX_UDPCHANNELS* = 32   #* The maximum addresses bound to a single UDP socket channel *
+  MAX_UDPADDRESSES* = 4
+
+type  # SDL_net.h types
+      #***********************************************************************
+      #* IPv4 hostname resolution API                                        *
+      #***********************************************************************
+  PIPAddress* = ptr TIPAddress
+  TIPAddress*{.final.} = object  #* TCP network API                                                     
+    host*: uint32             # 32-bit IPv4 host address */
+    port*: uint16             # 16-bit protocol port */
+  
+  PTCPSocket* = ptr TTCPSocket
+  TTCPSocket*{.final.} = object  # UDP network API
+    ready*: int
+    channel*: int
+    remoteAddress*: TIPAddress
+    localAddress*: TIPAddress
+    sflag*: int
+
+  PUDP_Channel* = ptr TUDP_Channel
+  TUDP_Channel*{.final.} = object 
+    numbound*: int
+    address*: array[0..MAX_UDPADDRESSES - 1, TIPAddress]
+
+  PUDPSocket* = ptr TUDPSocket
+  TUDPSocket*{.final.} = object 
+    ready*: int
+    channel*: int
+    address*: TIPAddress
+    binding*: array[0..MAX_UDPCHANNELS - 1, TUDP_Channel]
+
+  PUDPpacket* = ptr TUDPpacket
+  PPUDPpacket* = ptr PUDPpacket
+  TUDPpacket*{.final.} = object  #***********************************************************************
+                                 #* Hooks for checking sockets for available data                       *
+                                 #***********************************************************************
+    channel*: int             #* The src/dst channel of the packet *
+    data*: pointer            #* The packet data *
+    length*: int              #* The length of the packet data *
+    maxlen*: int              #* The size of the data buffer *
+    status*: int              #* packet status after sending *
+    address*: TIPAddress      #* The source/dest address of an incoming/outgoing packet *
+  
+  PSocket* = ptr TSocket
+  TSocket*{.final.} = object 
+    ready*: int
+    channel*: int
+
+  PSocketSet* = ptr TSocketSet
+  TSocketSet*{.final.} = object  # Any network socket can be safely cast to this socket type *
+    numsockets*: int
+    maxsockets*: int
+    sockets*: PSocket
+
+  PGenericSocket* = ptr TGenericSocket
+  TGenericSocket*{.final.} = object 
+    ready*: int
+
+
+proc version*(x: var Tversion)
+  #* Initialize/Cleanup the network API
+  #   SDL must be initialized before calls to functions in this library,
+  #   because this library uses utility functions from the SDL library.
+  #*
+proc init*(): int{.cdecl, importc: "SDLNet_Init", dynlib: NetLibName.}
+proc quit*(){.cdecl, importc: "SDLNet_Quit", dynlib: NetLibName.}
+  #* Resolve a host name and port to an IP address in network form.
+  #   If the function succeeds, it will return 0.
+  #   If the host couldn't be resolved, the host portion of the returned
+  #   address will be INADDR_NONE, and the function will return -1.
+  #   If 'host' is NULL, the resolved host will be set to INADDR_ANY.
+  # *
+proc resolveHost*(address: var TIPAddress, host: cstring, port: uint16): int{.
+    cdecl, importc: "SDLNet_ResolveHost", dynlib: NetLibName.}
+  #* Resolve an ip address to a host name in canonical form.
+  #   If the ip couldn't be resolved, this function returns NULL,
+  #   otherwise a pointer to a static buffer containing the hostname
+  #   is returned.  Note that this function is not thread-safe.
+  #*
+proc resolveIP*(ip: var TIPAddress): cstring{.cdecl, 
+    importc: "SDLNet_ResolveIP", dynlib: NetLibName.}
+  #***********************************************************************
+  #* TCP network API                                                     *
+  #***********************************************************************
+  #* Open a TCP network socket
+  #   If ip.host is INADDR_NONE, this creates a local server socket on the
+  #   given port, otherwise a TCP connection to the remote host and port is
+  #   attempted.  The address passed in should already be swapped to network
+  #   byte order (addresses returned from SDLNet_ResolveHost() are already
+  #   in the correct form).
+  #   The newly created socket is returned, or NULL if there was an error.
+  #*
+proc tcpOpen*(ip: var TIPAddress): PTCPSocket{.cdecl, 
+    importc: "SDLNet_TCP_Open", dynlib: NetLibName.}
+  #* Accept an incoming connection on the given server socket.
+  #   The newly created socket is returned, or NULL if there was an error.
+  #*
+proc tcpAccept*(server: PTCPSocket): PTCPSocket{.cdecl, 
+    importc: "SDLNet_TCP_Accept", dynlib: NetLibName.}
+  #* Get the IP address of the remote system associated with the socket.
+  #   If the socket is a server socket, this function returns NULL.
+  #*
+proc tcpGetPeerAddress*(sock: PTCPSocket): PIPAddress{.cdecl, 
+    importc: "SDLNet_TCP_GetPeerAddress", dynlib: NetLibName.}
+  #* Send 'len' bytes of 'data' over the non-server socket 'sock'
+  #   This function returns the actual amount of data sent.  If the return value
+  #   is less than the amount of data sent, then either the remote connection was
+  #   closed, or an unknown socket error occurred.
+  #*
+proc tcpSend*(sock: PTCPSocket, data: pointer, length: int): int{.cdecl, 
+    importc: "SDLNet_TCP_Send", dynlib: NetLibName.}
+  #* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
+  #   and store them in the buffer pointed to by 'data'.
+  #   This function returns the actual amount of data received.  If the return
+  #   value is less than or equal to zero, then either the remote connection was
+  #   closed, or an unknown socket error occurred.
+  #*
+proc tcpRecv*(sock: PTCPSocket, data: pointer, maxlen: int): int{.cdecl, 
+    importc: "SDLNet_TCP_Recv", dynlib: NetLibName.}
+  #* Close a TCP network socket *
+proc tcpClose*(sock: PTCPSocket){.cdecl, importc: "SDLNet_TCP_Close", 
+                                       dynlib: NetLibName.}
+  #***********************************************************************
+  #* UDP network API                                                     *
+  #***********************************************************************
+  #* Allocate/resize/free a single UDP packet 'size' bytes long.
+  #   The new packet is returned, or NULL if the function ran out of memory.
+  # *
+proc allocPacket*(size: int): PUDPpacket{.cdecl, 
+    importc: "SDLNet_AllocPacket", dynlib: NetLibName.}
+proc resizePacket*(packet: PUDPpacket, newsize: int): int{.cdecl, 
+    importc: "SDLNet_ResizePacket", dynlib: NetLibName.}
+proc freePacket*(packet: PUDPpacket){.cdecl, importc: "SDLNet_FreePacket", 
+    dynlib: NetLibName.}
+  #* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets,
+  #   each 'size' bytes long.
+  #   A pointer to the first packet in the array is returned, or NULL if the
+  #   function ran out of memory.
+  # *
+proc allocPacketV*(howmany: int, size: int): PUDPpacket{.cdecl, 
+    importc: "SDLNet_AllocPacketV", dynlib: NetLibName.}
+proc freePacketV*(packetV: PUDPpacket){.cdecl, 
+    importc: "SDLNet_FreePacketV", dynlib: NetLibName.}
+  #* Open a UDP network socket
+  #   If 'port' is non-zero, the UDP socket is bound to a local port.
+  #   This allows other systems to send to this socket via a known port.
+  #*
+proc udpOpen*(port: uint16): PUDPSocket{.cdecl, importc: "SDLNet_UDP_Open", 
+    dynlib: NetLibName.}
+  #* Bind the address 'address' to the requested channel on the UDP socket.
+  #   If the channel is -1, then the first unbound channel will be bound with
+  #   the given address as it's primary address.
+  #   If the channel is already bound, this new address will be added to the
+  #   list of valid source addresses for packets arriving on the channel.
+  #   If the channel is not already bound, then the address becomes the primary
+  #   address, to which all outbound packets on the channel are sent.
+  #   This function returns the channel which was bound, or -1 on error.
+  #*
+proc udpBind*(sock: PUDPSocket, channel: int, address: var TIPAddress): int{.
+    cdecl, importc: "SDLNet_UDP_Bind", dynlib: NetLibName.}
+  #* Unbind all addresses from the given channel *
+proc udpUnbind*(sock: PUDPSocket, channel: int){.cdecl, 
+    importc: "SDLNet_UDP_Unbind", dynlib: NetLibName.}
+  #* Get the primary IP address of the remote system associated with the
+  #   socket and channel.  If the channel is -1, then the primary IP port
+  #   of the UDP socket is returned -- this is only meaningful for sockets
+  #   opened with a specific port.
+  #   If the channel is not bound and not -1, this function returns NULL.
+  # *
+proc udpGetPeerAddress*(sock: PUDPSocket, channel: int): PIPAddress{.cdecl, 
+    importc: "SDLNet_UDP_GetPeerAddress", dynlib: NetLibName.}
+  #* Send a vector of packets to the the channels specified within the packet.
+  #   If the channel specified in the packet is -1, the packet will be sent to
+  #   the address in the 'src' member of the packet.
+  #   Each packet will be updated with the status of the packet after it has
+  #   been sent, -1 if the packet send failed.
+  #   This function returns the number of packets sent.
+  #*
+proc udpSendV*(sock: PUDPSocket, packets: PPUDPpacket, npackets: int): int{.
+    cdecl, importc: "SDLNet_UDP_SendV", dynlib: NetLibName.}
+  #* Send a single packet to the specified channel.
+  #   If the channel specified in the packet is -1, the packet will be sent to
+  #   the address in the 'src' member of the packet.
+  #   The packet will be updated with the status of the packet after it has
+  #   been sent.
+  #   This function returns 1 if the packet was sent, or 0 on error.
+  #*
+proc udpSend*(sock: PUDPSocket, channel: int, packet: PUDPpacket): int{.
+    cdecl, importc: "SDLNet_UDP_Send", dynlib: NetLibName.}
+  #* Receive a vector of pending packets from the UDP socket.
+  #   The returned packets contain the source address and the channel they arrived
+  #   on.  If they did not arrive on a bound channel, the the channel will be set
+  #   to -1.
+  #   The channels are checked in highest to lowest order, so if an address is
+  #   bound to multiple channels, the highest channel with the source address
+  #   bound will be returned.
+  #   This function returns the number of packets read from the network, or -1
+  #   on error.  This function does not block, so can return 0 packets pending.
+  #*
+proc udpRecvV*(sock: PUDPSocket, packets: PPUDPpacket): int{.cdecl, 
+    importc: "SDLNet_UDP_RecvV", dynlib: NetLibName.}
+  #* Receive a single packet from the UDP socket.
+  #   The returned packet contains the source address and the channel it arrived
+  #   on.  If it did not arrive on a bound channel, the the channel will be set
+  #   to -1.
+  #   The channels are checked in highest to lowest order, so if an address is
+  #   bound to multiple channels, the highest channel with the source address
+  #   bound will be returned.
+  #   This function returns the number of packets read from the network, or -1
+  #   on error.  This function does not block, so can return 0 packets pending.
+  #*
+proc udpRecv*(sock: PUDPSocket, packet: PUDPpacket): int{.cdecl, 
+    importc: "SDLNet_UDP_Recv", dynlib: NetLibName.}
+  #* Close a UDP network socket *
+proc udpClose*(sock: PUDPSocket){.cdecl, importc: "SDLNet_UDP_Close", 
+                                       dynlib: NetLibName.}
+  #***********************************************************************
+  #* Hooks for checking sockets for available data                       *
+  #***********************************************************************
+  #* Allocate a socket set for use with SDLNet_CheckSockets()
+  #   This returns a socket set for up to 'maxsockets' sockets, or NULL if
+  #   the function ran out of memory.
+  # *
+proc allocSocketSet*(maxsockets: int): PSocketSet{.cdecl, 
+    importc: "SDLNet_AllocSocketSet", dynlib: NetLibName.}
+  #* Add a socket to a set of sockets to be checked for available data *
+proc addSocket*(theSet: PSocketSet, sock: PGenericSocket): int{.
+    cdecl, importc: "SDLNet_AddSocket", dynlib: NetLibName.}
+proc tcpAddSocket*(theSet: PSocketSet, sock: PTCPSocket): int
+proc udpAddSocket*(theSet: PSocketSet, sock: PUDPSocket): int
+  #* Remove a socket from a set of sockets to be checked for available data *
+proc delSocket*(theSet: PSocketSet, sock: PGenericSocket): int{.
+    cdecl, importc: "SDLNet_DelSocket", dynlib: NetLibName.}
+proc tcpDelSocket*(theSet: PSocketSet, sock: PTCPSocket): int
+  # SDLNet_DelSocket(set, (SDLNet_GenericSocket)sock)
+proc udpDelSocket*(theSet: PSocketSet, sock: PUDPSocket): int
+  #SDLNet_DelSocket(set, (SDLNet_GenericSocket)sock)
+  #* This function checks to see if data is available for reading on the
+  #   given set of sockets.  If 'timeout' is 0, it performs a quick poll,
+  #   otherwise the function returns when either data is available for
+  #   reading, or the timeout in milliseconds has elapsed, which ever occurs
+  #   first.  This function returns the number of sockets ready for reading,
+  #   or -1 if there was an error with the select() system call.
+  #*
+proc checkSockets*(theSet: PSocketSet, timeout: int32): int{.cdecl, 
+    importc: "SDLNet_CheckSockets", dynlib: NetLibName.}
+  #* After calling SDLNet_CheckSockets(), you can use this function on a
+  #   socket that was in the socket set, to find out if data is available
+  #   for reading.
+  #*
+proc socketReady*(sock: PGenericSocket): bool
+  #* Free a set of sockets allocated by SDL_NetAllocSocketSet() *
+proc freeSocketSet*(theSet: PSocketSet){.cdecl, 
+    importc: "SDLNet_FreeSocketSet", dynlib: NetLibName.}
+  #***********************************************************************
+  #* Platform-independent data conversion functions                      *
+  #***********************************************************************
+  #* Write a 16/32 bit value to network packet buffer *
+proc write16*(value: uint16, area: pointer){.cdecl, 
+    importc: "SDLNet_Write16", dynlib: NetLibName.}
+proc write32*(value: uint32, area: pointer){.cdecl, 
+    importc: "SDLNet_Write32", dynlib: NetLibName.}
+  #* Read a 16/32 bit value from network packet buffer *
+proc read16*(area: pointer): uint16{.cdecl, importc: "SDLNet_Read16", 
+    dynlib: NetLibName.}
+proc read32*(area: pointer): uint32{.cdecl, importc: "SDLNet_Read32", 
+    dynlib: NetLibName.}
+
+proc version(x: var Tversion) = 
+  x.major = MAJOR_VERSION
+  x.minor = MINOR_VERSION
+  x.patch = PATCHLEVEL
+
+proc tcpAddSocket(theSet: PSocketSet, sock: PTCPSocket): int = 
+  result = addSocket(theSet, cast[PGenericSocket](sock))
+
+proc udpAddSocket(theSet: PSocketSet, sock: PUDPSocket): int = 
+  result = addSocket(theSet, cast[PGenericSocket](sock))
+
+proc tcpDelSocket(theSet: PSocketSet, sock: PTCPSocket): int = 
+  result = delSocket(theSet, cast[PGenericSocket](sock))
+
+proc udpDelSocket(theSet: PSocketSet, sock: PUDPSocket): int = 
+  result = delSocket(theSet, cast[PGenericSocket](sock))
+
+proc socketReady(sock: PGenericSocket): bool = 
+  result = sock != nil and sock.ready == 1
diff --git a/lib/wrappers/sdl/sdl_ttf.nim b/lib/wrappers/sdl/sdl_ttf.nim
new file mode 100644
index 000000000..9ebe70b9d
--- /dev/null
+++ b/lib/wrappers/sdl/sdl_ttf.nim
@@ -0,0 +1,337 @@
+#
+#  $Id: sdl_ttf.pas,v 1.18 2007/06/01 11:16:33 savage Exp $
+#
+#
+#******************************************************************************
+#                                                                              
+#          JEDI-SDL : Pascal units for SDL - Simple DirectMedia Layer          
+#       Conversion of the Simple DirectMedia Layer Headers                     
+#                                                                              
+# Portions created by Sam Lantinga <slouken@devolution.com> are                
+# Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga                     
+# 5635-34 Springhouse Dr.                                                      
+# Pleasanton, CA 94588 (USA)                                                   
+#                                                                              
+# All Rights Reserved.                                                         
+#                                                                              
+# The original files are : SDL_ttf.h                                           
+#                                                                              
+# The initial developer of this Pascal code was :                              
+# Dominqiue Louis <Dominique@SavageSoftware.com.au>                            
+#                                                                              
+# Portions created by Dominqiue Louis are                                      
+# Copyright (C) 2000 - 2001 Dominqiue Louis.                                   
+#                                                                              
+#                                                                              
+# Contributor(s)                                                               
+# --------------                                                               
+# Tom Jones <tigertomjones@gmx.de>  His Project inspired this conversion       
+#                                                                              
+# Obtained through:                                                            
+# Joint Endeavour of Delphi Innovators ( Project JEDI )                        
+#                                                                              
+# You may retrieve the latest version of this file at the Project              
+# JEDI home page, located at http://delphi-jedi.org                            
+#                                                                              
+# The contents of this file are used with permission, subject to               
+# the Mozilla Public License Version 1.1 (the "License"); you may              
+# not use this file except in compliance with the License. You may             
+# obtain a copy of the License at                                              
+# http://www.mozilla.org/MPL/MPL-1.1.html                                      
+#                                                                              
+# Software distributed under the License is distributed on an                  
+# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               
+# implied. See the License for the specific language governing                 
+# rights and limitations under the License.                                    
+#                                                                              
+# Description                                                                  
+# -----------                                                                  
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+# Requires                                                                     
+# --------                                                                     
+#   The SDL Runtime libraris on Win32  : SDL.dll on Linux : libSDL.so          
+#   They are available from...                                                 
+#   http://www.libsdl.org .                                                    
+#                                                                              
+# Programming Notes                                                            
+# -----------------                                                            
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+# Revision History                                                             
+# ----------------                                                             
+#   December 08 2002 - DL : Fixed definition of TTF_RenderUnicode_Solid        
+#                                                                              
+#   April   03 2003 - DL : Added jedi-sdl.inc include file to support more     
+#                          Pascal compilers. Initial support is now included   
+#                          for GnuPascal, VirtualPascal, TMT and obviously     
+#                          continue support for Delphi Kylix and FreePascal.   
+#                                                                              
+#   April   24 2003 - DL : under instruction from Alexey Barkovoy, I have added
+#                          better TMT Pascal support and under instruction     
+#                          from Prof. Abimbola Olowofoyeku (The African Chief),
+#                          I have added better Gnu Pascal support              
+#                                                                              
+#   April   30 2003 - DL : under instruction from David Mears AKA              
+#                          Jason Siletto, I have added FPC Linux support.      
+#                          This was compiled with fpc 1.1, so remember to set  
+#                          include file path. ie. -Fi/usr/share/fpcsrc/rtl/*   
+#                                                                              
+#
+#  $Log: sdl_ttf.pas,v $
+#  Revision 1.18  2007/06/01 11:16:33  savage
+#  Added IFDEF UNIX for Workaround.
+#
+#  Revision 1.17  2007/06/01 08:38:21  savage
+#  Added TTF_RenderText_Solid workaround as suggested by Michalis Kamburelis
+#
+#  Revision 1.16  2007/05/29 21:32:14  savage
+#  Changes as suggested by Almindor for 64bit compatibility.
+#
+#  Revision 1.15  2007/05/20 20:32:45  savage
+#  Initial Changes to Handle 64 Bits
+#
+#  Revision 1.14  2006/12/02 00:19:01  savage
+#  Updated to latest version
+#
+#  Revision 1.13  2005/04/10 11:48:33  savage
+#  Changes as suggested by Michalis, thanks.
+#
+#  Revision 1.12  2005/01/05 01:47:14  savage
+#  Changed LibName to reflect what MacOS X should have. ie libSDL*-1.2.0.dylib respectively.
+#
+#  Revision 1.11  2005/01/04 23:14:57  savage
+#  Changed LibName to reflect what most Linux distros will have. ie libSDL*-1.2.so.0 respectively.
+#
+#  Revision 1.10  2005/01/02 19:07:32  savage
+#  Slight bug fix to use LongInt instead of Long ( Thanks Michalis Kamburelis )
+#
+#  Revision 1.9  2005/01/01 02:15:20  savage
+#  Updated to v2.0.7
+#
+#  Revision 1.8  2004/10/07 21:02:32  savage
+#  Fix for FPC
+#
+#  Revision 1.7  2004/09/30 22:39:50  savage
+#  Added a true type font class which contains a wrap text function.
+#  Changed the sdl_ttf.pas header to reflect the future of jedi-sdl.
+#
+#  Revision 1.6  2004/08/14 22:54:30  savage
+#  Updated so that Library name defines are correctly defined for MacOS X.
+#
+#  Revision 1.5  2004/05/10 14:10:04  savage
+#  Initial MacOS X support. Fixed defines for MACOS ( Classic ) and DARWIN ( MacOS X ).
+#
+#  Revision 1.4  2004/04/13 09:32:08  savage
+#  Changed Shared object names back to just the .so extension to avoid conflicts on various Linux/Unix distros. Therefore developers will need to create Symbolic links to the actual Share Objects if necessary.
+#
+#  Revision 1.3  2004/04/01 20:53:24  savage
+#  Changed Linux Shared Object names so they reflect the Symbolic Links that are created when installing the RPMs from the SDL site.
+#
+#  Revision 1.2  2004/03/30 20:23:28  savage
+#  Tidied up use of UNIX compiler directive.
+#
+#  Revision 1.1  2004/02/16 22:16:40  savage
+#  v1.0 changes
+#
+#  
+#
+#******************************************************************************
+#
+#  Define this to workaround a known bug in some freetype versions.
+#  The error manifests as TTF_RenderGlyph_Solid returning nil (error)
+#  and error message (in SDL_Error) is
+#  "Failed loading DPMSDisable: /usr/lib/libX11.so.6: undefined symbol: DPMSDisable"
+#  See [http://lists.libsdl.org/pipermail/sdl-libsdl.org/2007-March/060459.html]
+#
+
+import 
+  sdl
+
+when defined(windows): 
+  const 
+    ttfLibName = "SDL_ttf.dll"
+elif defined(macosx): 
+  const 
+    ttfLibName = "libSDL_ttf-2.0.0.dylib"
+else: 
+  const 
+    ttfLibName = "libSDL_ttf(|-2.0).so(|.1|.0)"
+const 
+  MAJOR_VERSION* = 2
+  MINOR_VERSION* = 0
+  PATCHLEVEL* = 8      # Backwards compatibility
+
+  STYLE_NORMAL* = 0x00000000
+  STYLE_BOLD* = 0x00000001
+  STYLE_ITALIC* = 0x00000002
+  STYLE_UNDERLINE* = 0x00000004 # ZERO WIDTH NO-BREAKSPACE (Unicode byte order mark)
+  UNICODE_BOM_NATIVE* = 0x0000FEFF
+  UNICODE_BOM_SWAPPED* = 0x0000FFFE
+
+type 
+  PFont* = ptr TFont
+  TFont = object  
+  
+  
+# This macro can be used to fill a version structure with the compile-time
+# version of the SDL_ttf library. 
+
+proc linkedVersion*(): sdl.Pversion{.cdecl, importc: "TTF_Linked_Version", 
+                                      dynlib: ttfLibName.}
+  # This function tells the library whether UNICODE text is generally
+  #   byteswapped.  A UNICODE BOM character in a string will override
+  #   this setting for the remainder of that string.
+  #
+proc byteSwappedUNICODE*(swapped: cint){.cdecl, 
+    importc: "TTF_ByteSwappedUNICODE", dynlib: ttfLibName.}
+  #returns 0 on succes, -1 if error occurs
+proc init*(): cint{.cdecl, importc: "TTF_Init", dynlib: ttfLibName.}
+  #
+  # Open a font file and create a font of the specified point size.
+  # Some .fon fonts will have several sizes embedded in the file, so the
+  # point size becomes the index of choosing which size.  If the value
+  # is too high, the last indexed size will be the default.
+  #
+proc openFont*(filename: cstring, ptsize: cint): PFont{.cdecl, 
+    importc: "TTF_OpenFont", dynlib: ttfLibName.}
+proc openFontIndex*(filename: cstring, ptsize: cint, index: int32): PFont{.
+    cdecl, importc: "TTF_OpenFontIndex", dynlib: ttfLibName.}
+proc openFontRW*(src: PRWops, freesrc: cint, ptsize: cint): PFont{.cdecl, 
+    importc: "TTF_OpenFontRW", dynlib: ttfLibName.}
+proc openFontIndexRW*(src: PRWops, freesrc: cint, ptsize: cint, index: int32): PFont{.
+    cdecl, importc: "TTF_OpenFontIndexRW", dynlib: ttfLibName.}
+proc getFontStyle*(font: PFont): cint{.cdecl, 
+    importc: "TTF_GetFontStyle", dynlib: ttfLibName.}
+proc setFontStyle*(font: PFont, style: cint){.cdecl, 
+    importc: "TTF_SetFontStyle", dynlib: ttfLibName.}
+  # Get the total height of the font - usually equal to point size 
+proc fontHeight*(font: PFont): cint{.cdecl, importc: "TTF_FontHeight", 
+    dynlib: ttfLibName.}
+  # Get the offset from the baseline to the top of the font
+  #   This is a positive value, relative to the baseline.
+  #
+proc fontAscent*(font: PFont): cint{.cdecl, importc: "TTF_FontAscent", 
+    dynlib: ttfLibName.}
+  # Get the offset from the baseline to the bottom of the font
+  #   This is a negative value, relative to the baseline.
+  #
+proc fontDescent*(font: PFont): cint{.cdecl, importc: "TTF_FontDescent", 
+    dynlib: ttfLibName.}
+  # Get the recommended spacing between lines of text for this font 
+proc fontLineSkip*(font: PFont): cint{.cdecl, 
+    importc: "TTF_FontLineSkip", dynlib: ttfLibName.}
+  # Get the number of faces of the font 
+proc fontFaces*(font: PFont): int32{.cdecl, importc: "TTF_FontFaces", 
+    dynlib: ttfLibName.}
+  # Get the font face attributes, if any 
+proc fontFaceIsFixedWidth*(font: PFont): cint{.cdecl, 
+    importc: "TTF_FontFaceIsFixedWidth", dynlib: ttfLibName.}
+proc fontFaceFamilyName*(font: PFont): cstring{.cdecl, 
+    importc: "TTF_FontFaceFamilyName", dynlib: ttfLibName.}
+proc fontFaceStyleName*(font: PFont): cstring{.cdecl, 
+    importc: "TTF_FontFaceStyleName", dynlib: ttfLibName.}
+  # Get the metrics (dimensions) of a glyph 
+proc glyphMetrics*(font: PFont, ch: uint16, minx: var cint, 
+                       maxx: var cint, miny: var cint, maxy: var cint, 
+                       advance: var cint): cint{.cdecl, 
+    importc: "TTF_GlyphMetrics", dynlib: ttfLibName.}
+  # Get the dimensions of a rendered string of text 
+proc sizeText*(font: PFont, text: cstring, w: var cint, y: var cint): cint{.
+    cdecl, importc: "TTF_SizeText", dynlib: ttfLibName.}
+proc sizeUTF8*(font: PFont, text: cstring, w: var cint, y: var cint): cint{.
+    cdecl, importc: "TTF_SizeUTF8", dynlib: ttfLibName.}
+proc sizeUNICODE*(font: PFont, text: PUInt16, w: var cint, y: var cint): cint{.
+    cdecl, importc: "TTF_SizeUNICODE", dynlib: ttfLibName.}
+  # Create an 8-bit palettized surface and render the given text at
+  #   fast quality with the given font and color.  The 0 pixel is the
+  #   colorkey, giving a transparent background, and the 1 pixel is set
+  #   to the text color.
+  #   This function returns the new surface, or NULL if there was an error.
+  #
+proc renderUTF8Solid*(font: PFont, text: cstring, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderUTF8_Solid", dynlib: ttfLibName.}
+proc renderUNICODE_Solid*(font: PFont, text: PUInt16, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderUNICODE_Solid", dynlib: ttfLibName.}
+  #
+  #Create an 8-bit palettized surface and render the given glyph at
+  #   fast quality with the given font and color.  The 0 pixel is the
+  #   colorkey, giving a transparent background, and the 1 pixel is set
+  #   to the text color.  The glyph is rendered without any padding or
+  #   centering in the X direction, and aligned normally in the Y direction.
+  #   This function returns the new surface, or NULL if there was an error.
+  #
+proc renderGlyphSolid*(font: PFont, ch: uint16, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderGlyph_Solid", dynlib: ttfLibName.}
+  # Create an 8-bit palettized surface and render the given text at
+  #   high quality with the given font and colors.  The 0 pixel is background,
+  #   while other pixels have varying degrees of the foreground color.
+  #   This function returns the new surface, or NULL if there was an error.
+  #
+proc renderTextShaded*(font: PFont, text: cstring, fg: TColor, 
+                            bg: TColor): PSurface{.cdecl, 
+    importc: "TTF_RenderText_Shaded", dynlib: ttfLibName.}
+proc renderUTF8Shaded*(font: PFont, text: cstring, fg: TColor, 
+                            bg: TColor): PSurface{.cdecl, 
+    importc: "TTF_RenderUTF8_Shaded", dynlib: ttfLibName.}
+proc renderUNICODE_Shaded*(font: PFont, text: PUInt16, fg: TColor, 
+                               bg: TColor): PSurface{.cdecl, 
+    importc: "TTF_RenderUNICODE_Shaded", dynlib: ttfLibName.}
+  # Create an 8-bit palettized surface and render the given glyph at
+  #   high quality with the given font and colors.  The 0 pixel is background,
+  #   while other pixels have varying degrees of the foreground color.
+  #   The glyph is rendered without any padding or centering in the X
+  #   direction, and aligned normally in the Y direction.
+  #   This function returns the new surface, or NULL if there was an error.
+  #
+proc renderGlyphShaded*(font: PFont, ch: uint16, fg: TColor, bg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderGlyph_Shaded", dynlib: ttfLibName.}
+  # Create a 32-bit ARGB surface and render the given text at high quality,
+  #   using alpha blending to dither the font with the given color.
+  #   This function returns the new surface, or NULL if there was an error.
+  #
+proc renderTextBlended*(font: PFont, text: cstring, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderText_Blended", dynlib: ttfLibName.}
+proc renderUTF8Blended*(font: PFont, text: cstring, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderUTF8_Blended", dynlib: ttfLibName.}
+proc RenderUNICODE_Blended*(font: PFont, text: PUInt16, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderUNICODE_Blended", dynlib: ttfLibName.}
+  # Create a 32-bit ARGB surface and render the given glyph at high quality,
+  #   using alpha blending to dither the font with the given color.
+  #   The glyph is rendered without any padding or centering in the X
+  #   direction, and aligned normally in the Y direction.
+  #   This function returns the new surface, or NULL if there was an error.
+  #
+proc renderGlyphBlended*(font: PFont, ch: uint16, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderGlyph_Blended", dynlib: ttfLibName.}
+  # For compatibility with previous versions, here are the old functions 
+  # #define TTF_RenderText(font, text, fg, bg)
+  #	TTF_RenderText_Shaded(font, text, fg, bg)
+  # #define TTF_RenderUTF8(font, text, fg, bg)
+  #	TTF_RenderUTF8_Shaded(font, text, fg, bg)
+  # #define TTF_RenderUNICODE(font, text, fg, bg)
+  #	TTF_RenderUNICODE_Shaded(font, text, fg, bg)
+  # Close an opened font file
+proc closeFont*(font: PFont){.cdecl, importc: "TTF_CloseFont", 
+                                      dynlib: ttfLibName.}
+  # De-initialize TTF engine
+proc quit*(){.cdecl, importc: "TTF_Quit", dynlib: ttfLibName.}
+  # Check if the TTF engine is initialized
+proc wasInit*(): cint{.cdecl, importc: "TTF_WasInit", dynlib: ttfLibName.}
+
+
+proc version*(x: var sdl.Tversion) = 
+  x.major = MAJOR_VERSION
+  x.minor = MINOR_VERSION
+  x.patch = PATCHLEVEL
+
+
+proc renderTextSolid*(font: PFont, text: cstring, fg: TColor): PSurface{.
+    cdecl, importc: "TTF_RenderText_Solid", dynlib: ttfLibName.}
diff --git a/lib/wrappers/sdl/smpeg.nim b/lib/wrappers/sdl/smpeg.nim
new file mode 100644
index 000000000..318c0b3df
--- /dev/null
+++ b/lib/wrappers/sdl/smpeg.nim
@@ -0,0 +1,332 @@
+#******************************************************************************
+#
+#  $Id: smpeg.pas,v 1.7 2004/08/14 22:54:30 savage Exp $
+#  
+#
+#                                                                              
+#       Borland Delphi SMPEG - SDL MPEG Player Library                         
+#       Conversion of the SMPEG - SDL MPEG Player Library                      
+#                                                                              
+# Portions created by Sam Lantinga <slouken@devolution.com> are                
+# Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga                     
+# 5635-34 Springhouse Dr.                                                      
+# Pleasanton, CA 94588 (USA)                                                   
+#                                                                              
+# All Rights Reserved.                                                         
+#                                                                              
+# The original files are : smpeg.h                                             
+#                                                                              
+# The initial developer of this Pascal code was :                              
+# Matthias Thoma <ma.thoma@gmx.de>                                             
+#                                                                              
+# Portions created by Matthias Thoma are                                       
+# Copyright (C) 2000 - 2001 Matthias Thoma.                                    
+#                                                                              
+#                                                                              
+# Contributor(s)                                                               
+# --------------                                                               
+# Tom Jones <tigertomjones@gmx.de>  His Project inspired this conversion       
+# Matthias Thoma <ma.thoma@gmx.de>                                             
+#                                                                              
+# Obtained through:                                                            
+# Joint Endeavour of Delphi Innovators ( Project JEDI )                        
+#                                                                              
+# You may retrieve the latest version of this file at the Project              
+# JEDI home page, located at http://delphi-jedi.org                            
+#                                                                              
+# The contents of this file are used with permission, subject to               
+# the Mozilla Public License Version 1.1 (the "License"); you may              
+# not use this file except in compliance with the License. You may             
+# obtain a copy of the License at                                              
+# http://www.mozilla.org/MPL/MPL-1.1.html                                      
+#                                                                              
+# Software distributed under the License is distributed on an                  
+# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               
+# implied. See the License for the specific language governing                 
+# rights and limitations under the License.                                    
+#                                                                              
+# Description                                                                  
+# -----------                                                                  
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+# Requires                                                                     
+# --------                                                                     
+#   The SDL Runtime libraris on Win32  : SDL.dll on Linux : libSDL-1.2.so.0    
+#   They are available from...                                                 
+#   http://www.libsdl.org .                                                    
+#                                                                              
+# Programming Notes                                                            
+# -----------------                                                            
+#                                                                              
+#                                                                              
+#                                                                              
+#                                                                              
+# Revision History                                                             
+# ----------------                                                             
+#   May      08 2001 - MT : Initial conversion                                 
+#                                                                              
+#   October  12 2001 - DA : Various changes as suggested by David Acklam       
+#                                                                              
+#   April   03 2003 - DL : Added jedi-sdl.inc include file to support more     
+#                          Pascal compilers. Initial support is now included   
+#                          for GnuPascal, VirtualPascal, TMT and obviously     
+#                          continue support for Delphi Kylix and FreePascal.   
+#                                                                              
+#   April   08 2003 - MK : Aka Mr Kroket - Added Better FPC support            
+#                          Fixed all invalid calls to DLL.                     
+#                          Changed constant names to:                          
+#                          const                                               
+#                          STATUS_SMPEG_ERROR = -1;                            
+#                          STATUS_SMPEG_STOPPED = 0;                           
+#                          STATUS_SMPEG_PLAYING = 1;                           
+#                          because SMPEG_ERROR is a function (_SMPEG_error     
+#                          isn't correct), and cannot be two elements with the 
+#                          same name                                           
+#                                                                              
+#   April   24 2003 - DL : under instruction from Alexey Barkovoy, I have added
+#                          better TMT Pascal support and under instruction     
+#                          from Prof. Abimbola Olowofoyeku (The African Chief),
+#                          I have added better Gnu Pascal support              
+#                                                                              
+#   April   30 2003 - DL : under instruction from David Mears AKA              
+#                          Jason Siletto, I have added FPC Linux support.      
+#                          This was compiled with fpc 1.1, so remember to set  
+#                          include file path. ie. -Fi/usr/share/fpcsrc/rtl/*   
+#                                                                              
+#
+#  $Log: smpeg.pas,v $
+#  Revision 1.7  2004/08/14 22:54:30  savage
+#  Updated so that Library name defines are correctly defined for MacOS X.
+#
+#  Revision 1.6  2004/05/10 14:10:04  savage
+#  Initial MacOS X support. Fixed defines for MACOS ( Classic ) and DARWIN ( MacOS X ).
+#
+#  Revision 1.5  2004/04/13 09:32:08  savage
+#  Changed Shared object names back to just the .so extension to avoid conflicts on various Linux/Unix distros. Therefore developers will need to create Symbolic links to the actual Share Objects if necessary.
+#
+#  Revision 1.4  2004/04/02 10:40:55  savage
+#  Changed Linux Shared Object name so they reflect the Symbolic Links that are created when installing the RPMs from the SDL site.
+#
+#  Revision 1.3  2004/03/31 22:20:02  savage
+#  Windows unit not used in this file, so it was removed to keep the code tidy.
+#
+#  Revision 1.2  2004/03/30 20:23:28  savage
+#  Tidied up use of UNIX compiler directive.
+#
+#  Revision 1.1  2004/02/14 23:35:42  savage
+#  version 1 of sdl_image, sdl_mixer and smpeg.
+#
+#  
+#
+#******************************************************************************
+
+import
+  sdl
+
+when defined(windows): 
+  const 
+    SmpegLibName = "smpeg.dll"
+elif defined(macosx): 
+  const 
+    SmpegLibName = "libsmpeg.dylib"
+else: 
+  const 
+    SmpegLibName = "libsmpeg.so"
+const 
+  FILTER_INFO_MB_ERROR* = 1
+  FILTER_INFO_PIXEL_ERROR* = 2 # Filter info from SMPEG 
+
+type 
+  TFilterInfo*{.final.} = object 
+    yuvMbSquareError*: PUInt16
+    yuvPixelSquareError*: PUInt16
+
+  PFilterInfo* = ptr TFilterInfo # MPEG filter definition 
+  PFilter* = ptr TFilter # Callback functions for the filter 
+  TFilterCallback* = proc (dest, source: POverlay, region: PRect, 
+                                 filterInfo: PFilterInfo, data: pointer): pointer{.
+      cdecl.}
+  TFilterDestroy* = proc (filter: PFilter): pointer{.cdecl.} # The filter definition itself 
+  TFilter*{.final.} = object  # The null filter (default). It simply copies the source rectangle to the video overlay. 
+    flags*: uint32
+    data*: pointer
+    callback*: TFilterCallback
+    destroy*: TFilterDestroy
+
+
+proc filterNull*(): PFilter{.cdecl, importc: "SMPEGfilter_null", 
+    dynlib: SmpegLibName.}
+  # The bilinear filter. A basic low-pass filter that will produce a smoother image. 
+proc filterBilinear*(): PFilter{.cdecl, 
+    importc: "SMPEGfilter_bilinear", dynlib: SmpegLibName.}
+  # The deblocking filter. It filters block borders and non-intra coded blocks to reduce blockiness 
+proc filterDeblocking*(): PFilter{.cdecl, 
+    importc: "SMPEGfilter_deblocking", dynlib: SmpegLibName.}
+  #------------------------------------------------------------------------------
+  # SMPEG.h
+  #------------------------------------------------------------------------------
+const 
+  MAJOR_VERSION* = 0
+  MINOR_VERSION* = 4
+  PATCHLEVEL* = 2
+
+type
+  TVersion* = object
+    major*: byte
+    minor*: byte
+    patch*: byte
+
+  Pversion* = ptr TVersion # This is the actual SMPEG object
+  TSMPEG* = object 
+  PSMPEG* = ptr TSMPEG        # Used to get information about the SMPEG object 
+  TInfo* = object 
+    hasAudio*: int32
+    hasVideo*: int32
+    width*: int32
+    height*: int32
+    currentFrame*: int32
+    currentFps*: float64
+    audioString*: array[0..79, char]
+    audioCurrentFrame*: int32
+    currentOffset*: uint32
+    totalSize*: uint32
+    currentTime*: float64
+    totalTime*: float64
+
+  PInfo* = ptr TInfo # Possible MPEG status codes 
+
+const 
+  STATUS_ERROR* = - 1
+  STATUS_STOPPED* = 0
+  STATUS_PLAYING* = 1
+
+type 
+  Tstatus* = int32
+  Pstatus* = ptr int32     # Matches the declaration of SDL_UpdateRect() 
+  TDisplayCallback* = proc (dst: PSurface, x, y: int, w, h: int): pointer{.
+      cdecl.} # Create a new SMPEG object from an MPEG file.
+              #  On return, if 'info' is not NULL, it will be filled with information
+              #  about the MPEG object.
+              #  This function returns a new SMPEG object.  Use error() to find out
+              #  whether or not there was a problem building the MPEG stream.
+              #  The sdl_audio parameter indicates if SMPEG should initialize the SDL audio
+              #  subsystem. If not, you will have to use the playaudio() function below
+              #  to extract the decoded data. 
+
+proc new*(theFile: cstring, info: PInfo, audio: int): PSMPEG{.cdecl, 
+    importc: "SMPEG_new", dynlib: SmpegLibName.}
+  # The same as above for a file descriptor 
+proc newDescr*(theFile: int, info: PInfo, audio: int): PSMPEG{.
+    cdecl, importc: "SMPEG_new_descr", dynlib: SmpegLibName.}
+  #  The same as above but for a raw chunk of data.  SMPEG makes a copy of the
+  #   data, so the application is free to delete after a successful call to this
+  #   function. 
+proc newData*(data: pointer, size: int, info: PInfo, audio: int): PSMPEG{.
+    cdecl, importc: "SMPEG_new_data", dynlib: SmpegLibName.}
+  # Get current information about an SMPEG object 
+proc getinfo*(mpeg: PSMPEG, info: PInfo){.cdecl, 
+    importc: "SMPEG_getinfo", dynlib: SmpegLibName.}
+  #procedure getinfo(mpeg: PSMPEG; info: Pointer);
+  #cdecl; external  SmpegLibName;
+  # Enable or disable audio playback in MPEG stream 
+proc enableaudio*(mpeg: PSMPEG, enable: int){.cdecl, 
+    importc: "SMPEG_enableaudio", dynlib: SmpegLibName.}
+  # Enable or disable video playback in MPEG stream 
+proc enablevideo*(mpeg: PSMPEG, enable: int){.cdecl, 
+    importc: "SMPEG_enablevideo", dynlib: SmpegLibName.}
+  # Delete an SMPEG object 
+proc delete*(mpeg: PSMPEG){.cdecl, importc: "SMPEG_delete", 
+                                  dynlib: SmpegLibName.}
+  # Get the current status of an SMPEG object 
+proc status*(mpeg: PSMPEG): Tstatus{.cdecl, importc: "SMPEG_status", 
+    dynlib: SmpegLibName.}
+  # status
+  # Set the audio volume of an MPEG stream, in the range 0-100 
+proc setVolume*(mpeg: PSMPEG, volume: int){.cdecl, 
+    importc: "SMPEG_setvolume", dynlib: SmpegLibName.}
+  # Set the destination surface for MPEG video playback
+  #  'surfLock' is a mutex used to synchronize access to 'dst', and can be NULL.
+  #  'callback' is a function called when an area of 'dst' needs to be updated.
+  #  If 'callback' is NULL, the default function (SDL_UpdateRect) will be used. 
+proc setDisplay*(mpeg: PSMPEG, dst: PSurface, surfLock: PMutex, 
+                       callback: TDisplayCallback){.cdecl, 
+    importc: "SMPEG_setdisplay", dynlib: SmpegLibName.}
+  # Set or clear looping play on an SMPEG object 
+proc loop*(mpeg: PSMPEG, repeat: int){.cdecl, importc: "SMPEG_loop", 
+    dynlib: SmpegLibName.}
+  # Scale pixel display on an SMPEG object 
+proc scaleXY*(mpeg: PSMPEG, width, height: int){.cdecl, 
+    importc: "SMPEG_scaleXY", dynlib: SmpegLibName.}
+proc scale*(mpeg: PSMPEG, scale: int){.cdecl, importc: "SMPEG_scale", 
+    dynlib: SmpegLibName.}
+proc double*(mpeg: PSMPEG, doubleit: bool)
+  # Move the video display area within the destination surface 
+proc move*(mpeg: PSMPEG, x, y: int){.cdecl, importc: "SMPEG_move", 
+    dynlib: SmpegLibName.}
+  # Set the region of the video to be shown 
+proc setDisplayRegion*(mpeg: PSMPEG, x, y, w, h: int){.cdecl, 
+    importc: "SMPEG_setdisplayregion", dynlib: SmpegLibName.}
+  # Play an SMPEG object 
+proc play*(mpeg: PSMPEG){.cdecl, importc: "SMPEG_play", 
+                                dynlib: SmpegLibName.}
+  # Pause/Resume playback of an SMPEG object
+proc pause*(mpeg: PSMPEG){.cdecl, importc: "SMPEG_pause", 
+                                 dynlib: SmpegLibName.}
+  # Stop playback of an SMPEG object 
+proc stop*(mpeg: PSMPEG){.cdecl, importc: "SMPEG_stop", 
+                                dynlib: SmpegLibName.}
+  # Rewind the play position of an SMPEG object to the beginning of the MPEG 
+proc rewind*(mpeg: PSMPEG){.cdecl, importc: "SMPEG_rewind", 
+                                  dynlib: SmpegLibName.}
+  # Seek 'bytes' bytes in the MPEG stream 
+proc seek*(mpeg: PSMPEG, bytes: int){.cdecl, importc: "SMPEG_seek", 
+    dynlib: SmpegLibName.}
+  # Skip 'seconds' seconds in the MPEG stream 
+proc skip*(mpeg: PSMPEG, seconds: float32){.cdecl, importc: "SMPEG_skip", 
+    dynlib: SmpegLibName.}
+  # Render a particular frame in the MPEG video
+  #   API CHANGE: This function no longer takes a target surface and position.
+  #               Use setdisplay() and move() to set this information. 
+proc renderFrame*(mpeg: PSMPEG, framenum: int){.cdecl, 
+    importc: "SMPEG_renderFrame", dynlib: SmpegLibName.}
+  # Render the last frame of an MPEG video 
+proc renderFinal*(mpeg: PSMPEG, dst: PSurface, x, y: int){.cdecl, 
+    importc: "SMPEG_renderFinal", dynlib: SmpegLibName.}
+  # Set video filter 
+proc filter*(mpeg: PSMPEG, filter: PFilter): PFilter{.cdecl, 
+    importc: "SMPEG_filter", dynlib: SmpegLibName.}
+  # Return NULL if there is no error in the MPEG stream, or an error message
+  #   if there was a fatal error in the MPEG stream for the SMPEG object. 
+proc error*(mpeg: PSMPEG): cstring{.cdecl, importc: "SMPEG_error", 
+    dynlib: SmpegLibName.}
+  # Exported callback function for audio playback.
+  #   The function takes a buffer and the amount of data to fill, and returns
+  #   the amount of data in bytes that was actually written.  This will be the
+  #   amount requested unless the MPEG audio has finished.
+  #
+proc playAudio*(mpeg: PSMPEG, stream: pointer, length: int): int{.cdecl, 
+    importc: "SMPEG_playAudio", dynlib: SmpegLibName.}
+  # Wrapper for playAudio() that can be passed to SDL and SDL_mixer 
+proc playAudioSDL*(mpeg: pointer, stream: pointer, length: int){.cdecl, 
+    importc: "SMPEG_playAudioSDL", dynlib: SmpegLibName.}
+  # Get the best SDL audio spec for the audio stream 
+proc wantedSpec*(mpeg: PSMPEG, wanted: PAudioSpec): int{.cdecl, 
+    importc: "SMPEG_wantedSpec", dynlib: SmpegLibName.}
+  # Inform SMPEG of the actual SDL audio spec used for sound playback 
+proc actualSpec*(mpeg: PSMPEG, spec: PAudioSpec){.cdecl, 
+    importc: "SMPEG_actualSpec", dynlib: SmpegLibName.}
+  # This macro can be used to fill a version structure with the compile-time
+  #  version of the SDL library. 
+proc getversion*(x: var TVersion) =
+  x.major = MAJOR_VERSION
+  x.minor = MINOR_VERSION
+  x.patch = PATCHLEVEL
+
+proc double(mpeg: PSMPEG, doubleit: bool) = 
+  if doubleit: scale(mpeg, 2)
+  else: scale(mpeg, 1)
diff --git a/lib/wrappers/sphinx.nim b/lib/wrappers/sphinx.nim
new file mode 100644
index 000000000..e4a282968
--- /dev/null
+++ b/lib/wrappers/sphinx.nim
@@ -0,0 +1,261 @@
+#
+# $Id: sphinxclient.h 2654 2011-01-31 01:20:58Z kevg $
+#
+#
+# Copyright (c) 2001-2011, Andrew Aksyonoff
+# Copyright (c) 2008-2011, Sphinx Technologies Inc
+# All rights reserved
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Library General Public License. You should
+# have received a copy of the LGPL license along with this program; if you
+# did not, you can find it at http://www.gnu.org/
+#
+
+## Nim wrapper for ``sphinx``.
+
+{.deadCodeElim: on.}
+when defined(windows):
+  const
+    sphinxDll* = "spinx.dll"
+elif defined(macosx):
+  const
+    sphinxDll* = "libspinx.dylib"
+else:
+  const
+    sphinxDll* = "libspinxclient.so"
+
+#/ known searchd status codes:
+const
+  SEARCHD_OK* = 0
+  SEARCHD_ERROR* = 1
+  SEARCHD_RETRY* = 2
+  SEARCHD_WARNING* = 3
+
+#/ known match modes
+
+const
+  SPH_MATCH_ALL* = 0
+  SPH_MATCH_ANY* = 1
+  SPH_MATCH_PHRASE* = 2
+  SPH_MATCH_BOOLEAN* = 3
+  SPH_MATCH_EXTENDED* = 4
+  SPH_MATCH_FULLSCAN* = 5
+  SPH_MATCH_EXTENDED2* = 6
+
+#/ known ranking modes (ext2 only)
+
+const
+  SPH_RANK_PROXIMITY_BM25* = 0
+  SPH_RANK_BM25* = 1
+  SPH_RANK_NONE* = 2
+  SPH_RANK_WORDCOUNT* = 3
+  SPH_RANK_PROXIMITY* = 4
+  SPH_RANK_MATCHANY* = 5
+  SPH_RANK_FIELDMASK* = 6
+  SPH_RANK_SPH04* = 7
+  SPH_RANK_DEFAULT* = SPH_RANK_PROXIMITY_BM25
+
+#/ known sort modes
+
+const
+  SPH_SORT_RELEVANCE* = 0
+  SPH_SORT_ATTR_DESC* = 1
+  SPH_SORT_ATTR_ASC* = 2
+  SPH_SORT_TIME_SEGMENTS* = 3
+  SPH_SORT_EXTENDED* = 4
+  SPH_SORT_EXPR* = 5
+
+#/ known filter types
+
+const
+  SPH_FILTER_VALUES* = 0
+  SPH_FILTER_RANGE* = 1
+  SPH_FILTER_FLOATRANGE* = 2
+
+#/ known attribute types
+
+const
+  SPH_ATTR_INTEGER* = 1
+  SPH_ATTR_TIMESTAMP* = 2
+  SPH_ATTR_ORDINAL* = 3
+  SPH_ATTR_BOOL* = 4
+  SPH_ATTR_FLOAT* = 5
+  SPH_ATTR_BIGINT* = 6
+  SPH_ATTR_STRING* = 7
+  SPH_ATTR_MULTI* = 0x40000000
+
+#/ known grouping functions
+
+const
+  SPH_GROUPBY_DAY* = 0
+  SPH_GROUPBY_WEEK* = 1
+  SPH_GROUPBY_MONTH* = 2
+  SPH_GROUPBY_YEAR* = 3
+  SPH_GROUPBY_ATTR* = 4
+  SPH_GROUPBY_ATTRPAIR* = 5
+
+type
+  TSphinxBool* {.size: sizeof(cint).} = enum
+    SPH_FALSE = 0,
+    SPH_TRUE = 1
+
+  Tclient {.pure, final.} = object
+  PClient* = ptr TClient
+  Twordinfo*{.pure, final.} = object
+    word*: cstring
+    docs*: cint
+    hits*: cint
+
+  Tresult*{.pure, final.} = object
+    error*: cstring
+    warning*: cstring
+    status*: cint
+    num_fields*: cint
+    fields*: cstringArray
+    num_attrs*: cint
+    attr_names*: cstringArray
+    attr_types*: ptr array [0..100_000, cint]
+    num_matches*: cint
+    values_pool*: pointer
+    total*: cint
+    total_found*: cint
+    time_msec*: cint
+    num_words*: cint
+    words*: ptr array [0..100_000, TWordinfo]
+
+  Texcerpt_options*{.pure, final.} = object
+    before_match*: cstring
+    after_match*: cstring
+    chunk_separator*: cstring
+    html_strip_mode*: cstring
+    passage_boundary*: cstring
+    limit*: cint
+    limit_passages*: cint
+    limit_words*: cint
+    around*: cint
+    start_passage_id*: cint
+    exact_phrase*: TSphinxBool
+    single_passage*: TSphinxBool
+    use_boundaries*: TSphinxBool
+    weight_order*: TSphinxBool
+    query_mode*: TSphinxBool
+    force_all_words*: TSphinxBool
+    load_files*: TSphinxBool
+    allow_empty*: TSphinxBool
+    emit_zones*: TSphinxBool
+
+  Tkeyword_info*{.pure, final.} = object
+    tokenized*: cstring
+    normalized*: cstring
+    num_docs*: cint
+    num_hits*: cint
+
+
+proc create*(copy_args: TSphinxBool): PClient{.cdecl, importc: "sphinx_create",
+    dynlib: sphinxDll.}
+proc cleanup*(client: PClient){.cdecl, importc: "sphinx_cleanup",
+                                    dynlib: sphinxDll.}
+proc destroy*(client: PClient){.cdecl, importc: "sphinx_destroy",
+                                    dynlib: sphinxDll.}
+proc error*(client: PClient): cstring{.cdecl, importc: "sphinx_error",
+    dynlib: sphinxDll.}
+proc warning*(client: PClient): cstring{.cdecl, importc: "sphinx_warning",
+    dynlib: sphinxDll.}
+proc set_server*(client: PClient, host: cstring, port: cint): TSphinxBool{.cdecl,
+    importc: "sphinx_set_server", dynlib: sphinxDll.}
+proc set_connect_timeout*(client: PClient, seconds: float32): TSphinxBool{.cdecl,
+    importc: "sphinx_set_connect_timeout", dynlib: sphinxDll.}
+proc open*(client: PClient): TSphinxBool{.cdecl, importc: "sphinx_open",
+                                        dynlib: sphinxDll.}
+proc close*(client: PClient): TSphinxBool{.cdecl, importc: "sphinx_close",
+    dynlib: sphinxDll.}
+proc set_limits*(client: PClient, offset: cint, limit: cint,
+                 max_matches: cint, cutoff: cint): TSphinxBool{.cdecl,
+    importc: "sphinx_set_limits", dynlib: sphinxDll.}
+proc set_max_query_time*(client: PClient, max_query_time: cint): TSphinxBool{.
+    cdecl, importc: "sphinx_set_max_query_time", dynlib: sphinxDll.}
+proc set_match_mode*(client: PClient, mode: cint): TSphinxBool{.cdecl,
+    importc: "sphinx_set_match_mode", dynlib: sphinxDll.}
+proc set_ranking_mode*(client: PClient, ranker: cint): TSphinxBool{.cdecl,
+    importc: "sphinx_set_ranking_mode", dynlib: sphinxDll.}
+proc set_sort_mode*(client: PClient, mode: cint, sortby: cstring): TSphinxBool{.
+    cdecl, importc: "sphinx_set_sort_mode", dynlib: sphinxDll.}
+proc set_field_weights*(client: PClient, num_weights: cint,
+                        field_names: cstringArray, field_weights: ptr cint): TSphinxBool{.
+    cdecl, importc: "sphinx_set_field_weights", dynlib: sphinxDll.}
+proc set_index_weights*(client: PClient, num_weights: cint,
+                        index_names: cstringArray, index_weights: ptr cint): TSphinxBool{.
+    cdecl, importc: "sphinx_set_index_weights", dynlib: sphinxDll.}
+proc set_id_range*(client: PClient, minid: int64, maxid: int64): TSphinxBool{.
+    cdecl, importc: "sphinx_set_id_range", dynlib: sphinxDll.}
+proc add_filter*(client: PClient, attr: cstring, num_values: cint,
+                 values: ptr int64, exclude: TSphinxBool): TSphinxBool{.cdecl,
+    importc: "sphinx_add_filter", dynlib: sphinxDll.}
+proc add_filter_range*(client: PClient, attr: cstring, umin: int64,
+                       umax: int64, exclude: TSphinxBool): TSphinxBool{.cdecl,
+    importc: "sphinx_add_filter_range", dynlib: sphinxDll.}
+proc add_filter_float_range*(client: PClient, attr: cstring, fmin: float32,
+                             fmax: float32, exclude: TSphinxBool): TSphinxBool{.cdecl,
+    importc: "sphinx_add_filter_float_range", dynlib: sphinxDll.}
+proc set_geoanchor*(client: PClient, attr_latitude: cstring,
+                    attr_longitude: cstring, latitude: float32, longitude: float32): TSphinxBool{.
+    cdecl, importc: "sphinx_set_geoanchor", dynlib: sphinxDll.}
+proc set_groupby*(client: PClient, attr: cstring, groupby_func: cint,
+                  group_sort: cstring): TSphinxBool{.cdecl,
+    importc: "sphinx_set_groupby", dynlib: sphinxDll.}
+proc set_groupby_distinct*(client: PClient, attr: cstring): TSphinxBool{.cdecl,
+    importc: "sphinx_set_groupby_distinct", dynlib: sphinxDll.}
+proc set_retries*(client: PClient, count: cint, delay: cint): TSphinxBool{.cdecl,
+    importc: "sphinx_set_retries", dynlib: sphinxDll.}
+proc add_override*(client: PClient, attr: cstring, docids: ptr int64,
+                   num_values: cint, values: ptr cint): TSphinxBool{.cdecl,
+    importc: "sphinx_add_override", dynlib: sphinxDll.}
+proc set_select*(client: PClient, select_list: cstring): TSphinxBool{.cdecl,
+    importc: "sphinx_set_select", dynlib: sphinxDll.}
+proc reset_filters*(client: PClient){.cdecl,
+    importc: "sphinx_reset_filters", dynlib: sphinxDll.}
+proc reset_groupby*(client: PClient){.cdecl,
+    importc: "sphinx_reset_groupby", dynlib: sphinxDll.}
+proc query*(client: PClient, query: cstring, index_list: cstring,
+            comment: cstring): ptr Tresult{.cdecl, importc: "sphinx_query",
+    dynlib: sphinxDll.}
+proc add_query*(client: PClient, query: cstring, index_list: cstring,
+                comment: cstring): cint{.cdecl, importc: "sphinx_add_query",
+    dynlib: sphinxDll.}
+proc run_queries*(client: PClient): ptr Tresult{.cdecl,
+    importc: "sphinx_run_queries", dynlib: sphinxDll.}
+proc get_num_results*(client: PClient): cint{.cdecl,
+    importc: "sphinx_get_num_results", dynlib: sphinxDll.}
+proc get_id*(result: ptr Tresult, match: cint): int64{.cdecl,
+    importc: "sphinx_get_id", dynlib: sphinxDll.}
+proc get_weight*(result: ptr Tresult, match: cint): cint{.cdecl,
+    importc: "sphinx_get_weight", dynlib: sphinxDll.}
+proc get_int*(result: ptr Tresult, match: cint, attr: cint): int64{.cdecl,
+    importc: "sphinx_get_int", dynlib: sphinxDll.}
+proc get_float*(result: ptr Tresult, match: cint, attr: cint): float32{.cdecl,
+    importc: "sphinx_get_float", dynlib: sphinxDll.}
+proc get_mva*(result: ptr Tresult, match: cint, attr: cint): ptr cint{.
+    cdecl, importc: "sphinx_get_mva", dynlib: sphinxDll.}
+proc get_string*(result: ptr Tresult, match: cint, attr: cint): cstring{.cdecl,
+    importc: "sphinx_get_string", dynlib: sphinxDll.}
+proc init_excerpt_options*(opts: ptr Texcerpt_options){.cdecl,
+    importc: "sphinx_init_excerpt_options", dynlib: sphinxDll.}
+proc build_excerpts*(client: PClient, num_docs: cint, docs: cstringArray,
+                     index: cstring, words: cstring, opts: ptr Texcerpt_options): cstringArray{.
+    cdecl, importc: "sphinx_build_excerpts", dynlib: sphinxDll.}
+proc update_attributes*(client: PClient, index: cstring, num_attrs: cint,
+                        attrs: cstringArray, num_docs: cint,
+                        docids: ptr int64, values: ptr int64): cint{.
+    cdecl, importc: "sphinx_update_attributes", dynlib: sphinxDll.}
+proc update_attributes_mva*(client: PClient, index: cstring, attr: cstring,
+                            docid: int64, num_values: cint,
+                            values: ptr cint): cint{.cdecl,
+    importc: "sphinx_update_attributes_mva", dynlib: sphinxDll.}
+proc build_keywords*(client: PClient, query: cstring, index: cstring,
+                     hits: TSphinxBool, out_num_keywords: ptr cint): ptr Tkeyword_info{.
+    cdecl, importc: "sphinx_build_keywords", dynlib: sphinxDll.}
+proc status*(client: PClient, num_rows: ptr cint, num_cols: ptr cint): cstringArray{.
+    cdecl, importc: "sphinx_status", dynlib: sphinxDll.}
+proc status_destroy*(status: cstringArray, num_rows: cint, num_cols: cint){.
+    cdecl, importc: "sphinx_status_destroy", dynlib: sphinxDll.}
diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim
new file mode 100644
index 000000000..e3a3fa0b8
--- /dev/null
+++ b/lib/wrappers/sqlite3.nim
@@ -0,0 +1,357 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+{.deadCodeElim: on.}
+when defined(windows): 
+  const 
+    Lib = "sqlite3.dll"
+elif defined(macosx): 
+  const 
+    Lib = "(libsqlite3(|.0).dylib|sqlite-3.6.13.dylib)"
+else: 
+  const 
+    Lib = "libsqlite3.so(|.0)"
+    
+const 
+  SQLITE_INTEGER* = 1
+  SQLITE_FLOAT* = 2
+  SQLITE_BLOB* = 4
+  SQLITE_NULL* = 5
+  SQLITE_TEXT* = 3
+  SQLITE_UTF8* = 1
+  SQLITE_UTF16LE* = 2
+  SQLITE_UTF16BE* = 3         # Use native byte order  
+  SQLITE_UTF16* = 4           # sqlite3_create_function only  
+  SQLITE_ANY* = 5             #sqlite_exec return values
+  SQLITE_OK* = 0
+  SQLITE_ERROR* = 1           # SQL error or missing database  
+  SQLITE_INTERNAL* = 2        # An internal logic error in SQLite  
+  SQLITE_PERM* = 3            # Access permission denied  
+  SQLITE_ABORT* = 4           # Callback routine requested an abort  
+  SQLITE_BUSY* = 5            # The database file is locked  
+  SQLITE_LOCKED* = 6          # A table in the database is locked  
+  SQLITE_NOMEM* = 7           # A malloc() failed  
+  SQLITE_READONLY* = 8        # Attempt to write a readonly database  
+  SQLITE_INTERRUPT* = 9       # Operation terminated by sqlite3_interrupt() 
+  SQLITE_IOERR* = 10          # Some kind of disk I/O error occurred  
+  SQLITE_CORRUPT* = 11        # The database disk image is malformed  
+  SQLITE_NOTFOUND* = 12       # (Internal Only) Table or record not found  
+  SQLITE_FULL* = 13           # Insertion failed because database is full  
+  SQLITE_CANTOPEN* = 14       # Unable to open the database file  
+  SQLITE_PROTOCOL* = 15       # Database lock protocol error  
+  SQLITE_EMPTY* = 16          # Database is empty  
+  SQLITE_SCHEMA* = 17         # The database schema changed  
+  SQLITE_TOOBIG* = 18         # Too much data for one row of a table  
+  SQLITE_CONSTRAINT* = 19     # Abort due to contraint violation  
+  SQLITE_MISMATCH* = 20       # Data type mismatch  
+  SQLITE_MISUSE* = 21         # Library used incorrectly  
+  SQLITE_NOLFS* = 22          # Uses OS features not supported on host  
+  SQLITE_AUTH* = 23           # Authorization denied  
+  SQLITE_FORMAT* = 24         # Auxiliary database format error  
+  SQLITE_RANGE* = 25          # 2nd parameter to sqlite3_bind out of range  
+  SQLITE_NOTADB* = 26         # File opened that is not a database file  
+  SQLITE_ROW* = 100           # sqlite3_step() has another row ready  
+  SQLITE_DONE* = 101          # sqlite3_step() has finished executing  
+  SQLITE_COPY* = 0
+  SQLITE_CREATE_INDEX* = 1
+  SQLITE_CREATE_TABLE* = 2
+  SQLITE_CREATE_TEMP_INDEX* = 3
+  SQLITE_CREATE_TEMP_TABLE* = 4
+  SQLITE_CREATE_TEMP_TRIGGER* = 5
+  SQLITE_CREATE_TEMP_VIEW* = 6
+  SQLITE_CREATE_TRIGGER* = 7
+  SQLITE_CREATE_VIEW* = 8
+  SQLITE_DELETE* = 9
+  SQLITE_DROP_INDEX* = 10
+  SQLITE_DROP_TABLE* = 11
+  SQLITE_DROP_TEMP_INDEX* = 12
+  SQLITE_DROP_TEMP_TABLE* = 13
+  SQLITE_DROP_TEMP_TRIGGER* = 14
+  SQLITE_DROP_TEMP_VIEW* = 15
+  SQLITE_DROP_TRIGGER* = 16
+  SQLITE_DROP_VIEW* = 17
+  SQLITE_INSERT* = 18
+  SQLITE_PRAGMA* = 19
+  SQLITE_READ* = 20
+  SQLITE_SELECT* = 21
+  SQLITE_TRANSACTION* = 22
+  SQLITE_UPDATE* = 23
+  SQLITE_ATTACH* = 24
+  SQLITE_DETACH* = 25
+  SQLITE_ALTER_TABLE* = 26
+  SQLITE_REINDEX* = 27
+  SQLITE_DENY* = 1
+  SQLITE_IGNORE* = 2          # Original from sqlite3.h: 
+                              #define SQLITE_STATIC      ((void(*)(void *))0)
+                              #define SQLITE_TRANSIENT   ((void(*)(void *))-1)
+  SQLITE_DETERMINISTIC* = 0x800
+
+const 
+  SQLITE_STATIC* = nil
+  SQLITE_TRANSIENT* = cast[pointer](- 1)
+
+type 
+  TSqlite3 {.pure, final.} = object 
+  PSqlite3* = ptr TSqlite3
+  PPSqlite3* = ptr PSqlite3
+  TContext{.pure, final.} = object 
+  Pcontext* = ptr TContext
+  Tstmt{.pure, final.} = object 
+  Pstmt* = ptr Tstmt
+  Tvalue{.pure, final.} = object 
+  Pvalue* = ptr Tvalue
+  PValueArg* = array[0..127, Pvalue]
+  
+  Tcallback* = proc (para1: pointer, para2: int32, para3, 
+                     para4: cstringArray): int32{.cdecl.}
+  Tbind_destructor_func* = proc (para1: pointer){.cdecl.}
+  Tcreate_function_step_func* = proc (para1: Pcontext, para2: int32, 
+                                      para3: PValueArg){.cdecl.}
+  Tcreate_function_func_func* = proc (para1: Pcontext, para2: int32, 
+                                      para3: PValueArg){.cdecl.}
+  Tcreate_function_final_func* = proc (para1: Pcontext){.cdecl.}
+  Tresult_func* = proc (para1: pointer){.cdecl.}
+  Tcreate_collation_func* = proc (para1: pointer, para2: int32, para3: pointer, 
+                                  para4: int32, para5: pointer): int32{.cdecl.}
+  Tcollation_needed_func* = proc (para1: pointer, para2: PSqlite3, eTextRep: int32, 
+                                  para4: cstring){.cdecl.}
+
+proc close*(para1: PSqlite3): int32{.cdecl, dynlib: Lib, importc: "sqlite3_close".}
+proc exec*(para1: PSqlite3, sql: cstring, para3: Tcallback, para4: pointer, 
+           errmsg: var cstring): int32{.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_exec".}
+proc last_insert_rowid*(para1: PSqlite3): int64{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_last_insert_rowid".}
+proc changes*(para1: PSqlite3): int32{.cdecl, dynlib: Lib, importc: "sqlite3_changes".}
+proc total_changes*(para1: PSqlite3): int32{.cdecl, dynlib: Lib, 
+                                      importc: "sqlite3_total_changes".}
+proc interrupt*(para1: PSqlite3){.cdecl, dynlib: Lib, importc: "sqlite3_interrupt".}
+proc complete*(sql: cstring): int32{.cdecl, dynlib: Lib, 
+                                     importc: "sqlite3_complete".}
+proc complete16*(sql: pointer): int32{.cdecl, dynlib: Lib, 
+                                       importc: "sqlite3_complete16".}
+proc busy_handler*(para1: PSqlite3, 
+                   para2: proc (para1: pointer, para2: int32): int32{.cdecl.}, 
+                   para3: pointer): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_busy_handler".}
+proc busy_timeout*(para1: PSqlite3, ms: int32): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_busy_timeout".}
+proc get_table*(para1: PSqlite3, sql: cstring, resultp: var cstringArray, 
+                nrow, ncolumn: var cint, errmsg: ptr cstring): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_get_table".}
+proc free_table*(result: cstringArray){.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_free_table".}
+  # Todo: see how translate sqlite3_mprintf, sqlite3_vmprintf, sqlite3_snprintf
+  # function sqlite3_mprintf(_para1:Pchar; args:array of const):Pchar;cdecl; external Sqlite3Lib name 'sqlite3_mprintf';
+proc mprintf*(para1: cstring): cstring{.cdecl, varargs, dynlib: Lib, 
+                                        importc: "sqlite3_mprintf".}
+  #function sqlite3_vmprintf(_para1:Pchar; _para2:va_list):Pchar;cdecl; external Sqlite3Lib name 'sqlite3_vmprintf';
+proc free*(z: cstring){.cdecl, dynlib: Lib, importc: "sqlite3_free".}
+  #function sqlite3_snprintf(_para1:longint; _para2:Pchar; _para3:Pchar; args:array of const):Pchar;cdecl; external Sqlite3Lib name 'sqlite3_snprintf';
+proc snprintf*(para1: int32, para2: cstring, para3: cstring): cstring{.cdecl, 
+    dynlib: Lib, varargs, importc: "sqlite3_snprintf".}
+proc set_authorizer*(para1: PSqlite3, xAuth: proc (para1: pointer, para2: int32, 
+    para3: cstring, para4: cstring, para5: cstring, para6: cstring): int32{.
+    cdecl.}, pUserData: pointer): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_set_authorizer".}
+proc trace*(para1: PSqlite3, xTrace: proc (para1: pointer, para2: cstring){.cdecl.}, 
+            para3: pointer): pointer{.cdecl, dynlib: Lib, 
+                                      importc: "sqlite3_trace".}
+proc progress_handler*(para1: PSqlite3, para2: int32, 
+                       para3: proc (para1: pointer): int32{.cdecl.}, 
+                       para4: pointer){.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_progress_handler".}
+proc commit_hook*(para1: PSqlite3, para2: proc (para1: pointer): int32{.cdecl.}, 
+                  para3: pointer): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_commit_hook".}
+proc open*(filename: cstring, ppDb: var PSqlite3): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_open".}
+proc open16*(filename: pointer, ppDb: var PSqlite3): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_open16".}
+proc errcode*(db: PSqlite3): int32{.cdecl, dynlib: Lib, importc: "sqlite3_errcode".}
+proc errmsg*(para1: PSqlite3): cstring{.cdecl, dynlib: Lib, importc: "sqlite3_errmsg".}
+proc errmsg16*(para1: PSqlite3): pointer{.cdecl, dynlib: Lib, 
+                                   importc: "sqlite3_errmsg16".}
+proc prepare*(db: PSqlite3, zSql: cstring, nBytes: int32, ppStmt: var Pstmt, 
+              pzTail: ptr cstring): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_prepare".}
+    
+proc prepare_v2*(db: PSqlite3, zSql: cstring, nByte: cint, ppStmt: var Pstmt,
+                pzTail: ptr cstring): cint {.
+                importc: "sqlite3_prepare_v2", cdecl, dynlib: Lib.}
+    
+proc prepare16*(db: PSqlite3, zSql: pointer, nBytes: int32, ppStmt: var Pstmt, 
+                pzTail: var pointer): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_prepare16".}
+proc bind_blob*(para1: Pstmt, para2: int32, para3: pointer, n: int32, 
+                para5: Tbind_destructor_func): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_bind_blob".}
+proc bind_double*(para1: Pstmt, para2: int32, para3: float64): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_bind_double".}
+proc bind_int*(para1: Pstmt, para2: int32, para3: int32): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_bind_int".}
+proc bind_int64*(para1: Pstmt, para2: int32, para3: int64): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_bind_int64".}
+proc bind_null*(para1: Pstmt, para2: int32): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_bind_null".}
+proc bind_text*(para1: Pstmt, para2: int32, para3: cstring, n: int32, 
+                para5: Tbind_destructor_func): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_bind_text".}
+proc bind_text16*(para1: Pstmt, para2: int32, para3: pointer, para4: int32, 
+                  para5: Tbind_destructor_func): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_bind_text16".}
+  #function sqlite3_bind_value(_para1:Psqlite3_stmt; _para2:longint; _para3:Psqlite3_value):longint;cdecl; external Sqlite3Lib name 'sqlite3_bind_value';
+  #These overloaded functions were introduced to allow the use of SQLITE_STATIC and SQLITE_TRANSIENT
+  #It's the c world man ;-)
+proc bind_blob*(para1: Pstmt, para2: int32, para3: pointer, n: int32, 
+                para5: int32): int32{.cdecl, dynlib: Lib, 
+                                      importc: "sqlite3_bind_blob".}
+proc bind_text*(para1: Pstmt, para2: int32, para3: cstring, n: int32, 
+                para5: int32): int32{.cdecl, dynlib: Lib, 
+                                      importc: "sqlite3_bind_text".}
+proc bind_text16*(para1: Pstmt, para2: int32, para3: pointer, para4: int32, 
+                  para5: int32): int32{.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_bind_text16".}
+proc bind_parameter_count*(para1: Pstmt): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_bind_parameter_count".}
+proc bind_parameter_name*(para1: Pstmt, para2: int32): cstring{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_bind_parameter_name".}
+proc bind_parameter_index*(para1: Pstmt, zName: cstring): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_bind_parameter_index".}
+  #function sqlite3_clear_bindings(_para1:Psqlite3_stmt):longint;cdecl; external Sqlite3Lib name 'sqlite3_clear_bindings';
+proc column_count*(pStmt: Pstmt): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_count".}
+proc column_name*(para1: Pstmt, para2: int32): cstring{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_name".}
+proc column_name16*(para1: Pstmt, para2: int32): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_name16".}
+proc column_decltype*(para1: Pstmt, i: int32): cstring{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_decltype".}
+proc column_decltype16*(para1: Pstmt, para2: int32): pointer{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_column_decltype16".}
+proc step*(para1: Pstmt): int32{.cdecl, dynlib: Lib, importc: "sqlite3_step".}
+proc data_count*(pStmt: Pstmt): int32{.cdecl, dynlib: Lib, 
+                                       importc: "sqlite3_data_count".}
+proc column_blob*(para1: Pstmt, iCol: int32): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_blob".}
+proc column_bytes*(para1: Pstmt, iCol: int32): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_bytes".}
+proc column_bytes16*(para1: Pstmt, iCol: int32): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_bytes16".}
+proc column_double*(para1: Pstmt, iCol: int32): float64{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_double".}
+proc column_int*(para1: Pstmt, iCol: int32): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_int".}
+proc column_int64*(para1: Pstmt, iCol: int32): int64{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_int64".}
+proc column_text*(para1: Pstmt, iCol: int32): cstring{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_text".}
+proc column_text16*(para1: Pstmt, iCol: int32): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_text16".}
+proc column_type*(para1: Pstmt, iCol: int32): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_column_type".}
+proc finalize*(pStmt: Pstmt): int32{.cdecl, dynlib: Lib, 
+                                     importc: "sqlite3_finalize".}
+proc reset*(pStmt: Pstmt): int32{.cdecl, dynlib: Lib, importc: "sqlite3_reset".}
+proc create_function*(para1: PSqlite3, zFunctionName: cstring, nArg: int32, 
+                      eTextRep: int32, para5: pointer, 
+                      xFunc: Tcreate_function_func_func, 
+                      xStep: Tcreate_function_step_func, 
+                      xFinal: Tcreate_function_final_func): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_create_function".}
+proc create_function16*(para1: PSqlite3, zFunctionName: pointer, nArg: int32, 
+                        eTextRep: int32, para5: pointer, 
+                        xFunc: Tcreate_function_func_func, 
+                        xStep: Tcreate_function_step_func, 
+                        xFinal: Tcreate_function_final_func): int32{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_create_function16".}
+proc aggregate_count*(para1: Pcontext): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_aggregate_count".}
+proc value_blob*(para1: Pvalue): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_blob".}
+proc value_bytes*(para1: Pvalue): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_bytes".}
+proc value_bytes16*(para1: Pvalue): int32{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_bytes16".}
+proc value_double*(para1: Pvalue): float64{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_double".}
+proc value_int*(para1: Pvalue): int32{.cdecl, dynlib: Lib, 
+                                       importc: "sqlite3_value_int".}
+proc value_int64*(para1: Pvalue): int64{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_int64".}
+proc value_text*(para1: Pvalue): cstring{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_text".}
+proc value_text16*(para1: Pvalue): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_text16".}
+proc value_text16le*(para1: Pvalue): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_text16le".}
+proc value_text16be*(para1: Pvalue): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_value_text16be".}
+proc value_type*(para1: Pvalue): int32{.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_value_type".}
+proc aggregate_context*(para1: Pcontext, nBytes: int32): pointer{.cdecl, 
+    dynlib: Lib, importc: "sqlite3_aggregate_context".}
+proc user_data*(para1: Pcontext): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_user_data".}
+proc get_auxdata*(para1: Pcontext, para2: int32): pointer{.cdecl, dynlib: Lib, 
+    importc: "sqlite3_get_auxdata".}
+proc set_auxdata*(para1: Pcontext, para2: int32, para3: pointer, 
+                  para4: proc (para1: pointer){.cdecl.}){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_set_auxdata".}
+proc result_blob*(para1: Pcontext, para2: pointer, para3: int32, 
+                  para4: Tresult_func){.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_result_blob".}
+proc result_double*(para1: Pcontext, para2: float64){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_double".}
+proc result_error*(para1: Pcontext, para2: cstring, para3: int32){.cdecl, 
+    dynlib: Lib, importc: "sqlite3_result_error".}
+proc result_error16*(para1: Pcontext, para2: pointer, para3: int32){.cdecl, 
+    dynlib: Lib, importc: "sqlite3_result_error16".}
+proc result_int*(para1: Pcontext, para2: int32){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_int".}
+proc result_int64*(para1: Pcontext, para2: int64){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_int64".}
+proc result_null*(para1: Pcontext){.cdecl, dynlib: Lib, 
+                                    importc: "sqlite3_result_null".}
+proc result_text*(para1: Pcontext, para2: cstring, para3: int32, 
+                  para4: Tresult_func){.cdecl, dynlib: Lib, 
+                                        importc: "sqlite3_result_text".}
+proc result_text16*(para1: Pcontext, para2: pointer, para3: int32, 
+                    para4: Tresult_func){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_text16".}
+proc result_text16le*(para1: Pcontext, para2: pointer, para3: int32, 
+                      para4: Tresult_func){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_text16le".}
+proc result_text16be*(para1: Pcontext, para2: pointer, para3: int32, 
+                      para4: Tresult_func){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_text16be".}
+proc result_value*(para1: Pcontext, para2: Pvalue){.cdecl, dynlib: Lib, 
+    importc: "sqlite3_result_value".}
+proc create_collation*(para1: PSqlite3, zName: cstring, eTextRep: int32, 
+                       para4: pointer, xCompare: Tcreate_collation_func): int32{.
+    cdecl, dynlib: Lib, importc: "sqlite3_create_collation".}
+proc create_collation16*(para1: PSqlite3, zName: cstring, eTextRep: int32, 
+                         para4: pointer, xCompare: Tcreate_collation_func): int32{.
+    cdecl, dynlib: Lib, importc: "sqlite3_create_collation16".}
+proc collation_needed*(para1: PSqlite3, para2: pointer, para3: Tcollation_needed_func): int32{.
+    cdecl, dynlib: Lib, importc: "sqlite3_collation_needed".}
+proc collation_needed16*(para1: PSqlite3, para2: pointer, para3: Tcollation_needed_func): int32{.
+    cdecl, dynlib: Lib, importc: "sqlite3_collation_needed16".}
+proc libversion*(): cstring{.cdecl, dynlib: Lib, importc: "sqlite3_libversion".}
+  #Alias for allowing better code portability (win32 is not working with external variables) 
+proc version*(): cstring{.cdecl, dynlib: Lib, importc: "sqlite3_libversion".}
+  # Not published functions
+proc libversion_number*(): int32{.cdecl, dynlib: Lib, 
+                                  importc: "sqlite3_libversion_number".}
+  #function sqlite3_key(db:Psqlite3; pKey:pointer; nKey:longint):longint;cdecl; external Sqlite3Lib name 'sqlite3_key';
+  #function sqlite3_rekey(db:Psqlite3; pKey:pointer; nKey:longint):longint;cdecl; external Sqlite3Lib name 'sqlite3_rekey';
+  #function sqlite3_sleep(_para1:longint):longint;cdecl; external Sqlite3Lib name 'sqlite3_sleep';
+  #function sqlite3_expired(_para1:Psqlite3_stmt):longint;cdecl; external Sqlite3Lib name 'sqlite3_expired';
+  #function sqlite3_global_recover:longint;cdecl; external Sqlite3Lib name 'sqlite3_global_recover';
+# implementation
diff --git a/lib/wrappers/tinyc.nim b/lib/wrappers/tinyc.nim
new file mode 100644
index 000000000..ac6cb70f1
--- /dev/null
+++ b/lib/wrappers/tinyc.nim
@@ -0,0 +1,118 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2010 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+type
+  TccState {.pure, final.} = object
+  PccState* = ptr TccState
+  
+  TErrorFunc* = proc (opaque: pointer, msg: cstring) {.cdecl.}
+
+proc openCCState*(): PccState {.importc: "tcc_new", cdecl.}
+  ## create a new TCC compilation context
+
+proc closeCCState*(s: PccState) {.importc: "tcc_delete", cdecl.}
+  ## free a TCC compilation context
+
+proc enableDebug*(s: PccState) {.importc: "tcc_enable_debug", cdecl.}
+  ## add debug information in the generated code
+
+proc setErrorFunc*(s: PccState, errorOpaque: pointer, errorFun: TErrorFunc) {.
+  cdecl, importc: "tcc_set_error_func".}
+  ## set error/warning display callback
+
+proc setWarning*(s: PccState, warningName: cstring, value: int) {.cdecl,
+  importc: "tcc_set_warning".}
+  ## set/reset a warning
+
+# preprocessor 
+
+proc addIncludePath*(s: PccState, pathname: cstring) {.cdecl, 
+  importc: "tcc_add_include_path".}
+  ## add include path
+
+proc addSysincludePath*(s: PccState, pathname: cstring) {.cdecl, 
+  importc: "tcc_add_sysinclude_path".}
+  ## add in system include path
+
+
+proc defineSymbol*(s: PccState, sym, value: cstring) {.cdecl, 
+  importc: "tcc_define_symbol".}
+  ## define preprocessor symbol 'sym'. Can put optional value
+
+proc undefineSymbol*(s: PccState, sym: cstring) {.cdecl, 
+  importc: "tcc_undefine_symbol".}
+  ## undefine preprocess symbol 'sym'
+
+# compiling 
+
+proc addFile*(s: PccState, filename: cstring): cint {.cdecl, 
+  importc: "tcc_add_file".}
+  ## add a file (either a C file, dll, an object, a library or an ld
+  ## script). Return -1 if error.
+
+proc compileString*(s: PccState, buf: cstring): cint {.cdecl, 
+  importc: "tcc_compile_string".}
+  ## compile a string containing a C source. Return non zero if error.
+
+# linking commands
+
+
+const
+  OutputMemory*: cint = 0 ## output will be ran in memory (no
+                          ## output file) (default)
+  OutputExe*: cint = 1 ## executable file
+  OutputDll*: cint = 2 ## dynamic library
+  OutputObj*: cint = 3 ## object file
+  OutputPreprocess*: cint = 4 ## preprocessed file (used internally)
+  
+  OutputFormatElf*: cint = 0 ## default output format: ELF
+  OutputFormatBinary*: cint = 1 ## binary image output
+  OutputFormatCoff*: cint = 2 ## COFF
+
+proc setOutputType*(s: PCCState, outputType: cint): cint {.cdecl, 
+  importc: "tcc_set_output_type".}
+  ## set output type. MUST BE CALLED before any compilation
+
+proc addLibraryPath*(s: PccState, pathname: cstring): cint {.cdecl,
+  importc: "tcc_add_library_path".}
+  ## equivalent to -Lpath option
+
+proc addLibrary*(s: PCCState, libraryname: cstring): cint {.cdecl,
+  importc: "tcc_add_library".}
+  ## the library name is the same as the argument of the '-l' option
+
+proc addSymbol*(s: PccState, name: cstring, val: pointer): cint {.cdecl,
+  importc: "tcc_add_symbol".}
+  ## add a symbol to the compiled program
+
+proc outputFile*(s: PccState, filename: cstring): cint {.cdecl,
+  importc: "tcc_output_file".}
+  ## output an executable, library or object file. DO NOT call
+  ## tcc_relocate() before.
+
+proc run*(s: PccState, argc: cint, argv: cstringArray): cint {.cdecl,
+  importc: "tcc_run".}
+  ## link and run main() function and return its value. DO NOT call
+  ## tcc_relocate() before.
+
+proc relocate*(s: PccState, p: pointer): cint {.cdecl,
+  importc: "tcc_relocate".}
+  ## copy code into memory passed in by the caller and do all relocations
+  ## (needed before using tcc_get_symbol()).
+  ## returns -1 on error and required size if ptr is NULL
+
+proc getSymbol*(s: PccState, name: cstring): pointer {.cdecl,
+  importc: "tcc_get_symbol".}
+  ## return symbol value or NULL if not found
+
+proc setLibPath*(s: PccState, path: cstring) {.cdecl,
+  importc: "tcc_set_lib_path".}
+  ## set CONFIG_TCCDIR at runtime
+  
+
diff --git a/lib/wrappers/tre.nim b/lib/wrappers/tre.nim
new file mode 100644
index 000000000..92cd16333
--- /dev/null
+++ b/lib/wrappers/tre.nim
@@ -0,0 +1,186 @@
+#
+#  tre.h - TRE public API definitions
+#
+#  This software is released under a BSD-style license.
+#  See the file LICENSE for details and copyright.
+#
+#
+
+when not defined(treDll):
+  when hostOS == "windows":
+    const treDll = "tre.dll"
+  elif hostOS == "macosx":
+    const treDll = "libtre.dylib"
+  else:
+    const treDll = "libtre.so(.5|)"
+
+const 
+  APPROX* = 1 ## approximate matching functionality
+  MULTIBYTE* = 1 ## multibyte character set support. 
+  VERSION* = "0.8.0" ## TRE version string. 
+  VERSION_1* = 0 ## TRE version level 1. 
+  VERSION_2* = 8 ## TRE version level 2. 
+  VERSION_3* = 0 ## TRE version level 3. 
+
+
+# If the we're not using system regex.h, we need to define the
+#   structs and enums ourselves. 
+
+type 
+  TRegoff* = cint
+  TRegex*{.pure, final.} = object 
+    re_nsub*: int          ## Number of parenthesized subexpressions. 
+    value*: pointer        ## For internal use only. 
+  
+  TRegmatch*{.pure, final.} = object 
+    rm_so*: TRegoff
+    rm_eo*: TRegoff
+
+  TReg_errcode*{.size: 4.} = enum  ## POSIX tre_regcomp() return error codes. 
+                                   ## (In the order listed in the standard.)	 
+    REG_OK = 0,               ## No error. 
+    REG_NOMATCH,              ## No match. 
+    REG_BADPAT,               ## Invalid regexp. 
+    REG_ECOLLATE,             ## Unknown collating element. 
+    REG_ECTYPE,               ## Unknown character class name. 
+    REG_EESCAPE,              ## Trailing backslash. 
+    REG_ESUBREG,              ## Invalid back reference. 
+    REG_EBRACK,               ## "[]" imbalance 
+    REG_EPAREN,               ## "\(\)" or "()" imbalance 
+    REG_EBRACE,               ## "\{\}" or "{}" imbalance 
+    REG_BADBR,                ## Invalid content of {} 
+    REG_ERANGE,               ## Invalid use of range operator 
+    REG_ESPACE,               ## Out of memory.  
+    REG_BADRPT                ## Invalid use of repetition operators. 
+
+# POSIX tre_regcomp() flags. 
+
+const 
+  REG_EXTENDED* = 1
+  REG_ICASE* = (REG_EXTENDED shl 1)
+  REG_NEWLINE* = (REG_ICASE shl 1)
+  REG_NOSUB* = (REG_NEWLINE shl 1)
+
+# Extra tre_regcomp() flags. 
+
+const 
+  REG_BASIC* = 0
+  REG_LITERAL* = (REG_NOSUB shl 1)
+  REG_RIGHT_ASSOC* = (REG_LITERAL shl 1)
+  REG_UNGREEDY* = (REG_RIGHT_ASSOC shl 1)
+
+# POSIX tre_regexec() flags. 
+
+const 
+  REG_NOTBOL* = 1
+  REG_NOTEOL* = (REG_NOTBOL shl 1)
+
+# Extra tre_regexec() flags. 
+
+const 
+  REG_APPROX_MATCHER* = (REG_NOTEOL shl 1)
+  REG_BACKTRACKING_MATCHER* = (REG_APPROX_MATCHER shl 1)
+
+# The maximum number of iterations in a bound expression. 
+
+const 
+  RE_DUP_MAX* = 255
+
+# The POSIX.2 regexp functions 
+
+proc regcomp*(preg: var TRegex, regex: cstring, cflags: cint): cint{.cdecl, 
+    importc: "tre_regcomp", dynlib: treDll.}
+proc regexec*(preg: var TRegex, string: cstring, nmatch: int, 
+              pmatch: ptr TRegmatch, eflags: cint): cint{.cdecl, 
+    importc: "tre_regexec", dynlib: treDll.}
+proc regerror*(errcode: cint, preg: var TRegex, errbuf: cstring, 
+               errbuf_size: int): int{.cdecl, importc: "tre_regerror", 
+    dynlib: treDll.}
+proc regfree*(preg: var TRegex){.cdecl, importc: "tre_regfree", dynlib: treDll.}
+# Versions with a maximum length argument and therefore the capability to
+#   handle null characters in the middle of the strings (not in POSIX.2). 
+
+proc regncomp*(preg: var TRegex, regex: cstring, len: int, cflags: cint): cint{.
+    cdecl, importc: "tre_regncomp", dynlib: treDll.}
+proc regnexec*(preg: var TRegex, string: cstring, len: int, nmatch: int, 
+               pmatch: ptr TRegmatch, eflags: cint): cint{.cdecl, 
+    importc: "tre_regnexec", dynlib: treDll.}
+# Approximate matching parameter struct. 
+
+type 
+  TRegaparams*{.pure, final.} = object 
+    cost_ins*: cint           ## Default cost of an inserted character. 
+    cost_del*: cint           ## Default cost of a deleted character. 
+    cost_subst*: cint         ## Default cost of a substituted character. 
+    max_cost*: cint           ## Maximum allowed cost of a match. 
+    max_ins*: cint            ## Maximum allowed number of inserts. 
+    max_del*: cint            ## Maximum allowed number of deletes. 
+    max_subst*: cint          ## Maximum allowed number of substitutes. 
+    max_err*: cint            ## Maximum allowed number of errors total. 
+  
+
+# Approximate matching result struct. 
+
+type 
+  TRegamatch*{.pure, final.} = object 
+    nmatch*: int              ## Length of pmatch[] array. 
+    pmatch*: ptr TRegmatch    ## Submatch data. 
+    cost*: cint               ## Cost of the match. 
+    num_ins*: cint            ## Number of inserts in the match. 
+    num_del*: cint            ## Number of deletes in the match. 
+    num_subst*: cint          ## Number of substitutes in the match. 
+  
+
+# Approximate matching functions. 
+
+proc regaexec*(preg: var TRegex, string: cstring, match: ptr TRegamatch, 
+               params: TRegaparams, eflags: cint): cint{.cdecl, 
+    importc: "tre_regaexec", dynlib: treDll.}
+proc reganexec*(preg: var TRegex, string: cstring, len: int, 
+                match: ptr TRegamatch, params: TRegaparams, 
+                eflags: cint): cint{.
+    cdecl, importc: "tre_reganexec", dynlib: treDll.}
+# Sets the parameters to default values. 
+
+proc regaparams_default*(params: ptr TRegaparams){.cdecl, 
+    importc: "tre_regaparams_default", dynlib: treDll.}
+
+type 
+  TStrSource*{.pure, final.} = object 
+    get_next_char*: proc (c: cstring, pos_add: ptr cint, 
+                          context: pointer): cint{.cdecl.}
+    rewind*: proc (pos: int, context: pointer){.cdecl.}
+    compare*: proc (pos1: int, pos2: int, len: int, context: pointer): cint{.
+        cdecl.}
+    context*: pointer
+
+
+proc reguexec*(preg: var TRegex, string: ptr TStrSource, nmatch: int, 
+               pmatch: ptr TRegmatch, eflags: cint): cint{.cdecl, 
+    importc: "tre_reguexec", dynlib: treDll.}
+
+proc runtimeVersion*(): cstring{.cdecl, importc: "tre_version", dynlib: treDll.}
+  # Returns the version string.	The returned string is static. 
+
+proc config*(query: cint, result: pointer): cint{.cdecl, importc: "tre_config", 
+    dynlib: treDll.}
+  # Returns the value for a config parameter.  The type to which `result`
+  # must point to depends of the value of `query`, see documentation for
+  # more details. 
+
+const 
+  CONFIG_APPROX* = 0
+  CONFIG_WCHAR* = 1
+  CONFIG_MULTIBYTE* = 2
+  CONFIG_SYSTEM_ABI* = 3
+  CONFIG_VERSION* = 4
+
+# Returns 1 if the compiled pattern has back references, 0 if not. 
+
+proc have_backrefs*(preg: var TRegex): cint{.cdecl, 
+    importc: "tre_have_backrefs", dynlib: treDll.}
+# Returns 1 if the compiled pattern uses approximate matching features,
+#   0 if not. 
+
+proc have_approx*(preg: var TRegex): cint{.cdecl, importc: "tre_have_approx", 
+    dynlib: treDll.}
diff --git a/lib/wrappers/zip/libzip.nim b/lib/wrappers/zip/libzip.nim
new file mode 100644
index 000000000..86670b450
--- /dev/null
+++ b/lib/wrappers/zip/libzip.nim
@@ -0,0 +1,249 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Interface to the `libzip <http://www.nih.at/libzip/index.html>`_ library by
+## Dieter Baron and Thomas Klausner. This version links
+## against ``libzip2.so.2`` unless you define the symbol ``useLibzipSrc``; then
+## it is compiled against some old ``libizp_all.c`` file.
+
+#
+#  zip.h -- exported declarations.
+#  Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner
+#
+#  This file is part of libzip, a library to manipulate ZIP archives.
+#  The authors can be contacted at <libzip@nih.at>
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions
+#  are met:
+#  1. Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#  2. Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+#  3. The names of the authors may not be used to endorse or promote
+#     products derived from this software without specific prior
+#     written permission.
+# 
+#  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+#  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+#  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+#  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+#  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+#  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+import times
+
+when defined(unix) and not defined(useLibzipSrc):
+  when defined(macosx):
+    {.pragma: mydll, dynlib: "libzip2.dylib".}
+  else:
+    {.pragma: mydll, dynlib: "libzip(|2).so(|.2|.1|.0)".}
+else:
+  when defined(unix):
+    {.passl: "-lz".}
+  {.compile: "libzip_all.c".}
+  {.pragma: mydll.}
+
+type 
+  TZipSourceCmd* = int32
+
+  TZipSourceCallback* = proc (state: pointer, data: pointer, length: int, 
+                              cmd: TZipSourceCmd): int {.cdecl.}
+  PZipStat* = ptr TZipStat
+  TZipStat* = object          ## the 'zip_stat' struct
+    name*: cstring            ## name of the file  
+    index*: int32             ## index within archive  
+    crc*: int32               ## crc of file data  
+    mtime*: Time              ## modification time  
+    size*: int                ## size of file (uncompressed)  
+    compSize*: int            ## size of file (compressed)  
+    compMethod*: int16        ## compression method used  
+    encryptionMethod*: int16  ## encryption method used  
+  
+  TZip = object
+  TZipSource = object 
+  TZipFile = object
+
+  PZip* = ptr TZip ## represents a zip archive
+  PZipFile* = ptr TZipFile ## represents a file within an archive
+  PZipSource* = ptr TZipSource ## represents a source for an archive
+
+
+# flags for zip_name_locate, zip_fopen, zip_stat, ...  
+const 
+  ZIP_CREATE* = 1'i32
+  ZIP_EXCL* = 2'i32
+  ZIP_CHECKCONS* = 4'i32 
+  ZIP_FL_NOCASE* = 1'i32        ## ignore case on name lookup  
+  ZIP_FL_NODIR* = 2'i32         ## ignore directory component  
+  ZIP_FL_COMPRESSED* = 4'i32    ## read compressed data  
+  ZIP_FL_UNCHANGED* = 8'i32     ## use original data, ignoring changes  
+  ZIP_FL_RECOMPRESS* = 16'i32   ## force recompression of data  
+
+const  # archive global flags flags  
+  ZIP_AFL_TORRENT* = 1'i32      ##  torrent zipped  
+
+const # libzip error codes  
+  ZIP_ER_OK* = 0'i32            ## N No error  
+  ZIP_ER_MULTIDISK* = 1'i32     ## N Multi-disk zip archives not supported  
+  ZIP_ER_RENAME* = 2'i32        ## S Renaming temporary file failed  
+  ZIP_ER_CLOSE* = 3'i32         ## S Closing zip archive failed  
+  ZIP_ER_SEEK* = 4'i32          ## S Seek error  
+  ZIP_ER_READ* = 5'i32          ## S Read error  
+  ZIP_ER_WRITE* = 6'i32         ## S Write error  
+  ZIP_ER_CRC* = 7'i32           ## N CRC error  
+  ZIP_ER_ZIPCLOSED* = 8'i32     ## N Containing zip archive was closed  
+  ZIP_ER_NOENT* = 9'i32         ## N No such file  
+  ZIP_ER_EXISTS* = 10'i32       ## N File already exists  
+  ZIP_ER_OPEN* = 11'i32         ## S Can't open file  
+  ZIP_ER_TMPOPEN* = 12'i32      ## S Failure to create temporary file  
+  ZIP_ER_ZLIB* = 13'i32         ## Z Zlib error  
+  ZIP_ER_MEMORY* = 14'i32       ## N Malloc failure  
+  ZIP_ER_CHANGED* = 15'i32      ## N Entry has been changed  
+  ZIP_ER_COMPNOTSUPP* = 16'i32  ## N Compression method not supported  
+  ZIP_ER_EOF* = 17'i32          ## N Premature EOF  
+  ZIP_ER_INVAL* = 18'i32        ## N Invalid argument  
+  ZIP_ER_NOZIP* = 19'i32        ## N Not a zip archive  
+  ZIP_ER_INTERNAL* = 20'i32     ## N Internal error  
+  ZIP_ER_INCONS* = 21'i32       ## N Zip archive inconsistent  
+  ZIP_ER_REMOVE* = 22'i32       ## S Can't remove file  
+  ZIP_ER_DELETED* = 23'i32      ## N Entry has been deleted  
+   
+const # type of system error value  
+  ZIP_ET_NONE* = 0'i32          ## sys_err unused  
+  ZIP_ET_SYS* = 1'i32           ## sys_err is errno  
+  ZIP_ET_ZLIB* = 2'i32          ## sys_err is zlib error code  
+
+const # compression methods  
+  ZIP_CM_DEFAULT* = -1'i32      ## better of deflate or store  
+  ZIP_CM_STORE* = 0'i32         ## stored (uncompressed)  
+  ZIP_CM_SHRINK* = 1'i32        ## shrunk  
+  ZIP_CM_REDUCE_1* = 2'i32      ## reduced with factor 1  
+  ZIP_CM_REDUCE_2* = 3'i32      ## reduced with factor 2  
+  ZIP_CM_REDUCE_3* = 4'i32      ## reduced with factor 3  
+  ZIP_CM_REDUCE_4* = 5'i32      ## reduced with factor 4  
+  ZIP_CM_IMPLODE* = 6'i32       ## imploded  
+                                ## 7 - Reserved for Tokenizing compression algorithm  
+  ZIP_CM_DEFLATE* = 8'i32       ## deflated  
+  ZIP_CM_DEFLATE64* = 9'i32     ## deflate64  
+  ZIP_CM_PKWARE_IMPLODE* = 10'i32 ## PKWARE imploding  
+                                  ## 11 - Reserved by PKWARE  
+  ZIP_CM_BZIP2* = 12'i32        ## compressed using BZIP2 algorithm  
+                                ## 13 - Reserved by PKWARE  
+  ZIP_CM_LZMA* = 14'i32         ## LZMA (EFS)  
+                                ## 15-17 - Reserved by PKWARE  
+  ZIP_CM_TERSE* = 18'i32        ## compressed using IBM TERSE (new)  
+  ZIP_CM_LZ77* = 19'i32         ## IBM LZ77 z Architecture (PFS)  
+  ZIP_CM_WAVPACK* = 97'i32      ## WavPack compressed data  
+  ZIP_CM_PPMD* = 98'i32         ## PPMd version I, Rev 1  
+
+const  # encryption methods                              
+  ZIP_EM_NONE* = 0'i32            ## not encrypted  
+  ZIP_EM_TRAD_PKWARE* = 1'i32     ## traditional PKWARE encryption 
+
+const 
+  ZIP_EM_UNKNOWN* = 0x0000FFFF'i32 ## unknown algorithm  
+
+const 
+  ZIP_SOURCE_OPEN* = 0'i32        ## prepare for reading  
+  ZIP_SOURCE_READ* = 1'i32        ## read data  
+  ZIP_SOURCE_CLOSE* = 2'i32       ## reading is done  
+  ZIP_SOURCE_STAT* = 3'i32        ## get meta information  
+  ZIP_SOURCE_ERROR* = 4'i32       ## get error information  
+  constZIP_SOURCE_FREE* = 5'i32   ## cleanup and free resources  
+
+proc zip_add*(para1: PZip, para2: cstring, para3: PZipSource): int32 {.cdecl, 
+    importc: "zip_add", mydll.}
+proc zip_add_dir*(para1: PZip, para2: cstring): int32 {.cdecl,  
+    importc: "zip_add_dir", mydll.}
+proc zip_close*(para1: PZip) {.cdecl, importc: "zip_close", mydll.}
+proc zip_delete*(para1: PZip, para2: int32): int32 {.cdecl, mydll,
+    importc: "zip_delete".}
+proc zip_error_clear*(para1: PZip) {.cdecl, importc: "zip_error_clear", mydll.}
+proc zip_error_get*(para1: PZip, para2: ptr int32, para3: ptr int32) {.cdecl, 
+    importc: "zip_error_get", mydll.}
+proc zip_error_get_sys_type*(para1: int32): int32 {.cdecl, mydll,
+    importc: "zip_error_get_sys_type".}
+proc zip_error_to_str*(para1: cstring, para2: int, para3: int32, 
+                       para4: int32): int32 {.cdecl, mydll,
+    importc: "zip_error_to_str".}
+proc zip_fclose*(para1: PZipFile) {.cdecl, mydll,
+    importc: "zip_fclose".}
+proc zip_file_error_clear*(para1: PZipFile) {.cdecl, mydll,
+    importc: "zip_file_error_clear".}
+proc zip_file_error_get*(para1: PZipFile, para2: ptr int32, para3: ptr int32) {.
+    cdecl, mydll, importc: "zip_file_error_get".}
+proc zip_file_strerror*(para1: PZipFile): cstring {.cdecl, mydll,
+    importc: "zip_file_strerror".}
+proc zip_fopen*(para1: PZip, para2: cstring, para3: int32): PZipFile {.cdecl, 
+    mydll, importc: "zip_fopen".}
+proc zip_fopen_index*(para1: PZip, para2: int32, para3: int32): PZipFile {.
+    cdecl, mydll, importc: "zip_fopen_index".}
+proc zip_fread*(para1: PZipFile, para2: pointer, para3: int): int {.
+    cdecl, mydll, importc: "zip_fread".}
+proc zip_get_archive_comment*(para1: PZip, para2: ptr int32, para3: int32): cstring {.
+    cdecl, mydll, importc: "zip_get_archive_comment".}
+proc zip_get_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {.
+    cdecl, mydll, importc: "zip_get_archive_flag".}
+proc zip_get_file_comment*(para1: PZip, para2: int32, para3: ptr int32, 
+                           para4: int32): cstring {.cdecl, mydll,
+    importc: "zip_get_file_comment".}
+proc zip_get_name*(para1: PZip, para2: int32, para3: int32): cstring {.cdecl, 
+    mydll, importc: "zip_get_name".}
+proc zip_get_num_files*(para1: PZip): int32 {.cdecl,
+    mydll, importc: "zip_get_num_files".}
+proc zip_name_locate*(para1: PZip, para2: cstring, para3: int32): int32 {.cdecl, 
+    mydll, importc: "zip_name_locate".}
+proc zip_open*(para1: cstring, para2: int32, para3: ptr int32): PZip {.cdecl, 
+    mydll, importc: "zip_open".}
+proc zip_rename*(para1: PZip, para2: int32, para3: cstring): int32 {.cdecl, 
+    mydll, importc: "zip_rename".}
+proc zip_replace*(para1: PZip, para2: int32, para3: PZipSource): int32 {.cdecl, 
+    mydll, importc: "zip_replace".}
+proc zip_set_archive_comment*(para1: PZip, para2: cstring, para3: int32): int32 {.
+    cdecl, mydll, importc: "zip_set_archive_comment".}
+proc zip_set_archive_flag*(para1: PZip, para2: int32, para3: int32): int32 {.
+    cdecl, mydll, importc: "zip_set_archive_flag".}
+proc zip_set_file_comment*(para1: PZip, para2: int32, para3: cstring, 
+                           para4: int32): int32 {.cdecl, mydll,
+    importc: "zip_set_file_comment".}
+proc zip_source_buffer*(para1: PZip, para2: pointer, para3: int, para4: int32): PZipSource {.
+    cdecl, mydll, importc: "zip_source_buffer".}
+proc zip_source_file*(para1: PZip, para2: cstring, para3: int, para4: int): PZipSource {.
+    cdecl, mydll, importc: "zip_source_file".}
+proc zip_source_filep*(para1: PZip, para2: File, para3: int, para4: int): PZipSource {.
+    cdecl, mydll, importc: "zip_source_filep".}
+proc zip_source_free*(para1: PZipSource) {.cdecl, mydll,
+    importc: "zip_source_free".}
+proc zip_source_function*(para1: PZip, para2: TZipSourceCallback, 
+                          para3: pointer): PZipSource {.cdecl, mydll,
+    importc: "zip_source_function".}
+proc zip_source_zip*(para1: PZip, para2: PZip, para3: int32, para4: int32, 
+                     para5: int, para6: int): PZipSource {.cdecl, mydll,
+    importc: "zip_source_zip".}
+proc zip_stat*(para1: PZip, para2: cstring, para3: int32, para4: PZipStat): int32 {.
+    cdecl, mydll, importc: "zip_stat".}
+proc zip_stat_index*(para1: PZip, para2: int32, para3: int32, para4: PZipStat): int32 {.
+    cdecl, mydll, importc: "zip_stat_index".}
+proc zip_stat_init*(para1: PZipStat) {.cdecl, mydll, importc: "zip_stat_init".}
+proc zip_strerror*(para1: PZip): cstring {.cdecl, mydll, importc: "zip_strerror".}
+proc zip_unchange*(para1: PZip, para2: int32): int32 {.cdecl, mydll,
+    importc: "zip_unchange".}
+proc zip_unchange_all*(para1: PZip): int32 {.cdecl, mydll,
+    importc: "zip_unchange_all".}
+proc zip_unchange_archive*(para1: PZip): int32 {.cdecl, mydll,
+    importc: "zip_unchange_archive".}
diff --git a/lib/wrappers/zip/libzip_all.c b/lib/wrappers/zip/libzip_all.c
new file mode 100644
index 000000000..797374b29
--- /dev/null
+++ b/lib/wrappers/zip/libzip_all.c
@@ -0,0 +1,4189 @@
+/*
+  zipint.h -- internal declarations.
+  Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <zlib.h>
+
+/*
+#ifdef _MSC_VER
+#define ZIP_EXTERN __declspec(dllimport)
+#endif
+*/
+
+/*
+  zip.h -- exported declarations.
+  Copyright (C) 1999-2008 Dieter Baron and Thomas Klausner
+
+  This file is part of libzip, a library to manipulate ZIP archives.
+  The authors can be contacted at <libzip@nih.at>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  3. The names of the authors may not be used to endorse or promote
+     products derived from this software without specific prior
+     written permission.
+ 
+  THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef ZIP_EXTERN
+#define ZIP_EXTERN
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <time.h>
+
+/* flags for zip_open */
+
+#define ZIP_CREATE           1
+#define ZIP_EXCL             2
+#define ZIP_CHECKCONS        4
+
+
+/* flags for zip_name_locate, zip_fopen, zip_stat, ... */
+
+#define ZIP_FL_NOCASE                1 /* ignore case on name lookup */
+#define ZIP_FL_NODIR                2 /* ignore directory component */
+#define ZIP_FL_COMPRESSED        4 /* read compressed data */
+#define ZIP_FL_UNCHANGED        8 /* use original data, ignoring changes */
+#define ZIP_FL_RECOMPRESS      16 /* force recompression of data */
+
+/* archive global flags flags */
+
+#define ZIP_AFL_TORRENT                1 /* torrent zipped */
+
+/* libzip error codes */
+
+#define ZIP_ER_OK             0  /* N No error */
+#define ZIP_ER_MULTIDISK      1  /* N Multi-disk zip archives not supported */
+#define ZIP_ER_RENAME         2  /* S Renaming temporary file failed */
+#define ZIP_ER_CLOSE          3  /* S Closing zip archive failed */
+#define ZIP_ER_SEEK           4  /* S Seek error */
+#define ZIP_ER_READ           5  /* S Read error */
+#define ZIP_ER_WRITE          6  /* S Write error */
+#define ZIP_ER_CRC            7  /* N CRC error */
+#define ZIP_ER_ZIPCLOSED      8  /* N Containing zip archive was closed */
+#define ZIP_ER_NOENT          9  /* N No such file */
+#define ZIP_ER_EXISTS        10  /* N File already exists */
+#define ZIP_ER_OPEN          11  /* S Can't open file */
+#define ZIP_ER_TMPOPEN       12  /* S Failure to create temporary file */
+#define ZIP_ER_ZLIB          13  /* Z Zlib error */
+#define ZIP_ER_MEMORY        14  /* N Malloc failure */
+#define ZIP_ER_CHANGED       15  /* N Entry has been changed */
+#define ZIP_ER_COMPNOTSUPP   16  /* N Compression method not supported */
+#define ZIP_ER_EOF           17  /* N Premature EOF */
+#define ZIP_ER_INVAL         18  /* N Invalid argument */
+#define ZIP_ER_NOZIP         19  /* N Not a zip archive */
+#define ZIP_ER_INTERNAL      20  /* N Internal error */
+#define ZIP_ER_INCONS        21  /* N Zip archive inconsistent */
+#define ZIP_ER_REMOVE        22  /* S Can't remove file */
+#define ZIP_ER_DELETED       23  /* N Entry has been deleted */
+
+
+/* type of system error value */
+
+#define ZIP_ET_NONE              0  /* sys_err unused */
+#define ZIP_ET_SYS              1  /* sys_err is errno */
+#define ZIP_ET_ZLIB              2  /* sys_err is zlib error code */
+
+/* compression methods */
+
+#define ZIP_CM_DEFAULT              -1  /* better of deflate or store */
+#define ZIP_CM_STORE               0  /* stored (uncompressed) */
+#define ZIP_CM_SHRINK               1  /* shrunk */
+#define ZIP_CM_REDUCE_1               2  /* reduced with factor 1 */
+#define ZIP_CM_REDUCE_2               3  /* reduced with factor 2 */
+#define ZIP_CM_REDUCE_3               4  /* reduced with factor 3 */
+#define ZIP_CM_REDUCE_4               5  /* reduced with factor 4 */
+#define ZIP_CM_IMPLODE               6  /* imploded */
+/* 7 - Reserved for Tokenizing compression algorithm */
+#define ZIP_CM_DEFLATE               8  /* deflated */
+#define ZIP_CM_DEFLATE64       9  /* deflate64 */
+#define ZIP_CM_PKWARE_IMPLODE 10  /* PKWARE imploding */
+/* 11 - Reserved by PKWARE */
+#define ZIP_CM_BZIP2          12  /* compressed using BZIP2 algorithm */
+/* 13 - Reserved by PKWARE */
+#define ZIP_CM_LZMA              14  /* LZMA (EFS) */
+/* 15-17 - Reserved by PKWARE */
+#define ZIP_CM_TERSE              18  /* compressed using IBM TERSE (new) */
+#define ZIP_CM_LZ77           19  /* IBM LZ77 z Architecture (PFS) */
+#define ZIP_CM_WAVPACK              97  /* WavPack compressed data */
+#define ZIP_CM_PPMD              98  /* PPMd version I, Rev 1 */
+
+/* encryption methods */
+
+#define ZIP_EM_NONE               0  /* not encrypted */
+#define ZIP_EM_TRAD_PKWARE     1  /* traditional PKWARE encryption */
+#if 0 /* Strong Encryption Header not parsed yet */
+#define ZIP_EM_DES        0x6601  /* strong encryption: DES */
+#define ZIP_EM_RC2_OLD    0x6602  /* strong encryption: RC2, version < 5.2 */
+#define ZIP_EM_3DES_168   0x6603
+#define ZIP_EM_3DES_112   0x6609
+#define ZIP_EM_AES_128    0x660e
+#define ZIP_EM_AES_192    0x660f
+#define ZIP_EM_AES_256    0x6610
+#define ZIP_EM_RC2        0x6702  /* strong encryption: RC2, version >= 5.2 */
+#define ZIP_EM_RC4        0x6801
+#endif
+#define ZIP_EM_UNKNOWN    0xffff  /* unknown algorithm */
+
+typedef long myoff_t; /* XXX: 64 bit support */
+
+enum zip_source_cmd {
+    ZIP_SOURCE_OPEN,        /* prepare for reading */
+    ZIP_SOURCE_READ,         /* read data */
+    ZIP_SOURCE_CLOSE,        /* reading is done */
+    ZIP_SOURCE_STAT,        /* get meta information */
+    ZIP_SOURCE_ERROR,        /* get error information */
+    ZIP_SOURCE_FREE        /* cleanup and free resources */
+};
+
+typedef ssize_t (*zip_source_callback)(void *state, void *data,
+                                       size_t len, enum zip_source_cmd cmd);
+
+struct zip_stat {
+    const char *name;                        /* name of the file */
+    int index;                                /* index within archive */
+    unsigned int crc;                        /* crc of file data */
+    time_t mtime;                        /* modification time */
+    myoff_t size;                                /* size of file (uncompressed) */
+    myoff_t comp_size;                        /* size of file (compressed) */
+    unsigned short comp_method;                /* compression method used */
+    unsigned short encryption_method;        /* encryption method used */
+};
+
+struct zip;
+struct zip_file;
+struct zip_source;
+
+
+ZIP_EXTERN int zip_add(struct zip *, const char *, struct zip_source *);
+ZIP_EXTERN int zip_add_dir(struct zip *, const char *);
+ZIP_EXTERN int zip_close(struct zip *);
+ZIP_EXTERN int zip_delete(struct zip *, int);
+ZIP_EXTERN void zip_error_clear(struct zip *);
+ZIP_EXTERN void zip_error_get(struct zip *, int *, int *);
+ZIP_EXTERN int zip_error_get_sys_type(int);
+ZIP_EXTERN int zip_error_to_str(char *, size_t, int, int);
+ZIP_EXTERN int zip_fclose(struct zip_file *);
+ZIP_EXTERN void zip_file_error_clear(struct zip_file *);
+ZIP_EXTERN void zip_file_error_get(struct zip_file *, int *, int *);
+ZIP_EXTERN const char *zip_file_strerror(struct zip_file *);
+ZIP_EXTERN struct zip_file *zip_fopen(struct zip *, const char *, int);
+ZIP_EXTERN struct zip_file *zip_fopen_index(struct zip *, int, int);
+ZIP_EXTERN ssize_t zip_fread(struct zip_file *, void *, size_t);
+ZIP_EXTERN const char *zip_get_archive_comment(struct zip *, int *, int);
+ZIP_EXTERN int zip_get_archive_flag(struct zip *, int, int);
+ZIP_EXTERN const char *zip_get_file_comment(struct zip *, int, int *, int);
+ZIP_EXTERN const char *zip_get_name(struct zip *, int, int);
+ZIP_EXTERN int zip_get_num_files(struct zip *);
+ZIP_EXTERN int zip_name_locate(struct zip *, const char *, int);
+ZIP_EXTERN struct zip *zip_open(const char *, int, int *);
+ZIP_EXTERN int zip_rename(struct zip *, int, const char *);
+ZIP_EXTERN int zip_replace(struct zip *, int, struct zip_source *);
+ZIP_EXTERN int zip_set_archive_comment(struct zip *, const char *, int);
+ZIP_EXTERN int zip_set_archive_flag(struct zip *, int, int);
+ZIP_EXTERN int zip_set_file_comment(struct zip *, int, const char *, int);
+ZIP_EXTERN struct zip_source *zip_source_buffer(struct zip *, const void *,
+                                                myoff_t, int);
+ZIP_EXTERN struct zip_source *zip_source_file(struct zip *, const char *,
+                                              myoff_t, myoff_t);
+ZIP_EXTERN struct zip_source *zip_source_filep(struct zip *, FILE *,
+                                               myoff_t, myoff_t);
+ZIP_EXTERN void zip_source_free(struct zip_source *);
+ZIP_EXTERN struct zip_source *zip_source_function(struct zip *,
+                                                  zip_source_callback, void *);
+ZIP_EXTERN struct zip_source *zip_source_zip(struct zip *, struct zip *,
+                                             int, int, myoff_t, myoff_t);
+ZIP_EXTERN int zip_stat(struct zip *, const char *, int, struct zip_stat *);
+ZIP_EXTERN int zip_stat_index(struct zip *, int, int, struct zip_stat *);
+ZIP_EXTERN void zip_stat_init(struct zip_stat *);
+ZIP_EXTERN const char *zip_strerror(struct zip *);
+ZIP_EXTERN int zip_unchange(struct zip *, int);
+ZIP_EXTERN int zip_unchange_all(struct zip *);
+ZIP_EXTERN int zip_unchange_archive(struct zip *);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+   */
+/* #undef HAVE_DECL_TZNAME */
+
+#define HAVE_CONFIG_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `fseeko' function. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `ftello' function. */
+#define HAVE_FTELLO 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `MoveFileExA' function. */
+/* #undef HAVE_MOVEFILEEXA */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+   `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#define HAVE_TM_ZONE 1
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+   `tzname'. */
+/* #undef HAVE_TZNAME */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "libzip"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libzip@nih.at"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libzip"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libzip 0.9"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libzip"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.9"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Version number of package */
+#define VERSION "0.9"
+
+
+#ifndef HAVE_MKSTEMP
+int _zip_mkstemp(char *);
+#define mkstemp _zip_mkstemp
+#endif
+
+#ifdef HAVE_MOVEFILEEXA
+#include <windows.h>
+#define _zip_rename(s, t)                                                \
+        (!MoveFileExA((s), (t),                                                \
+                     MOVEFILE_COPY_ALLOWED|MOVEFILE_REPLACE_EXISTING))
+#else
+#define _zip_rename        rename
+#endif
+
+#ifndef HAVE_FSEEKO
+#define fseeko(s, o, w)        (fseek((s), (long int)(o), (w)))
+#endif
+#ifndef HAVE_FTELLO
+#define ftello(s)        ((long)ftell((s)))
+#endif
+
+
+#define CENTRAL_MAGIC "PK\1\2"
+#define LOCAL_MAGIC   "PK\3\4"
+#define EOCD_MAGIC    "PK\5\6"
+#define DATADES_MAGIC "PK\7\8"
+#define TORRENT_SIG        "TORRENTZIPPED-"
+#define TORRENT_SIG_LEN        14
+#define TORRENT_CRC_LEN 8
+#define TORRENT_MEM_LEVEL        8
+#define CDENTRYSIZE         46u
+#define LENTRYSIZE          30
+#define MAXCOMLEN        65536
+#define EOCDLEN             22
+#define CDBUFSIZE       (MAXCOMLEN+EOCDLEN)
+#define BUFSIZE                8192
+
+
+/* state of change of a file in zip archive */
+
+enum zip_state { ZIP_ST_UNCHANGED, ZIP_ST_DELETED, ZIP_ST_REPLACED,
+                 ZIP_ST_ADDED, ZIP_ST_RENAMED };
+
+/* constants for struct zip_file's member flags */
+
+#define ZIP_ZF_EOF        1 /* EOF reached */
+#define ZIP_ZF_DECOMP        2 /* decompress data */
+#define ZIP_ZF_CRC        4 /* compute and compare CRC */
+
+/* directory entry: general purpose bit flags */
+
+#define ZIP_GPBF_ENCRYPTED                0x0001        /* is encrypted */
+#define ZIP_GPBF_DATA_DESCRIPTOR        0x0008        /* crc/size after file data */
+#define ZIP_GPBF_STRONG_ENCRYPTION        0x0040  /* uses strong encryption */
+
+/* error information */
+
+struct zip_error {
+    int zip_err;        /* libzip error code (ZIP_ER_*) */
+    int sys_err;        /* copy of errno (E*) or zlib error code */
+    char *str;                /* string representation or NULL */
+};
+
+/* zip archive, part of API */
+
+struct zip {
+    char *zn;                        /* file name */
+    FILE *zp;                        /* file */
+    struct zip_error error;        /* error information */
+
+    unsigned int flags;                /* archive global flags */
+    unsigned int ch_flags;        /* changed archive global flags */
+
+    struct zip_cdir *cdir;        /* central directory */
+    char *ch_comment;                /* changed archive comment */
+    int ch_comment_len;                /* length of changed zip archive
+                                 * comment, -1 if unchanged */
+    int nentry;                        /* number of entries */
+    int nentry_alloc;                /* number of entries allocated */
+    struct zip_entry *entry;        /* entries */
+    int nfile;                        /* number of opened files within archive */
+    int nfile_alloc;                /* number of files allocated */
+    struct zip_file **file;        /* opened files within archive */
+};
+
+/* file in zip archive, part of API */
+
+struct zip_file {
+    struct zip *za;                /* zip archive containing this file */
+    struct zip_error error;        /* error information */
+    int flags;                        /* -1: eof, >0: error */
+
+    int method;                        /* compression method */
+    myoff_t fpos;                        /* position within zip file (fread/fwrite) */
+    unsigned long bytes_left;        /* number of bytes left to read */
+    unsigned long cbytes_left;  /* number of bytes of compressed data left */
+    
+    unsigned long crc;                /* CRC so far */
+    unsigned long crc_orig;        /* CRC recorded in archive */
+    
+    char *buffer;
+    z_stream *zstr;
+};
+
+/* zip archive directory entry (central or local) */
+
+struct zip_dirent {
+    unsigned short version_madeby;        /* (c)  version of creator */
+    unsigned short version_needed;        /* (cl) version needed to extract */
+    unsigned short bitflags;                /* (cl) general purpose bit flag */
+    unsigned short comp_method;                /* (cl) compression method used */
+    time_t last_mod;                        /* (cl) time of last modification */
+    unsigned int crc;                        /* (cl) CRC-32 of uncompressed data */
+    unsigned int comp_size;                /* (cl) size of commpressed data */
+    unsigned int uncomp_size;                /* (cl) size of uncommpressed data */
+    char *filename;                        /* (cl) file name (NUL-terminated) */
+    unsigned short filename_len;        /* (cl) length of filename (w/o NUL) */
+    char *extrafield;                        /* (cl) extra field */
+    unsigned short extrafield_len;        /* (cl) length of extra field */
+    char *comment;                        /* (c)  file comment */
+    unsigned short comment_len;                /* (c)  length of file comment */
+    unsigned short disk_number;                /* (c)  disk number start */
+    unsigned short int_attrib;                /* (c)  internal file attributes */
+    unsigned int ext_attrib;                /* (c)  external file attributes */
+    unsigned int offset;                /* (c)  offset of local header  */
+};
+
+/* zip archive central directory */
+
+struct zip_cdir {
+    struct zip_dirent *entry;        /* directory entries */
+    int nentry;                        /* number of entries */
+
+    unsigned int size;                /* size of central direcotry */
+    unsigned int offset;        /* offset of central directory in file */
+    char *comment;                /* zip archive comment */
+    unsigned short comment_len;        /* length of zip archive comment */
+};
+
+
+
+struct zip_source {
+    zip_source_callback f;
+    void *ud;
+};
+
+/* entry in zip archive directory */
+
+struct zip_entry {
+    enum zip_state state;
+    struct zip_source *source;
+    char *ch_filename;
+    char *ch_comment;
+    int ch_comment_len;
+};
+
+
+
+extern const char * const _zip_err_str[];
+extern const int _zip_nerr_str;
+extern const int _zip_err_type[];
+
+
+
+#define ZIP_ENTRY_DATA_CHANGED(x)        \
+                        ((x)->state == ZIP_ST_REPLACED  \
+                         || (x)->state == ZIP_ST_ADDED)
+
+
+
+int _zip_cdir_compute_crc(struct zip *, uLong *);
+void _zip_cdir_free(struct zip_cdir *);
+struct zip_cdir *_zip_cdir_new(int, struct zip_error *);
+int _zip_cdir_write(struct zip_cdir *, FILE *, struct zip_error *);
+
+void _zip_dirent_finalize(struct zip_dirent *);
+void _zip_dirent_init(struct zip_dirent *);
+int _zip_dirent_read(struct zip_dirent *, FILE *,
+                     unsigned char **, unsigned int, int, struct zip_error *);
+void _zip_dirent_torrent_normalize(struct zip_dirent *);
+int _zip_dirent_write(struct zip_dirent *, FILE *, int, struct zip_error *);
+
+void _zip_entry_free(struct zip_entry *);
+void _zip_entry_init(struct zip *, int);
+struct zip_entry *_zip_entry_new(struct zip *);
+
+void _zip_error_clear(struct zip_error *);
+void _zip_error_copy(struct zip_error *, struct zip_error *);
+void _zip_error_fini(struct zip_error *);
+void _zip_error_get(struct zip_error *, int *, int *);
+void _zip_error_init(struct zip_error *);
+void _zip_error_set(struct zip_error *, int, int);
+const char *_zip_error_strerror(struct zip_error *);
+
+int _zip_file_fillbuf(void *, size_t, struct zip_file *);
+unsigned int _zip_file_get_offset(struct zip *, int);
+
+int _zip_filerange_crc(FILE *, myoff_t, myoff_t, uLong *, struct zip_error *);
+
+struct zip_source *_zip_source_file_or_p(struct zip *, const char *, FILE *,
+                                         myoff_t, myoff_t);
+
+void _zip_free(struct zip *);
+const char *_zip_get_name(struct zip *, int, int, struct zip_error *);
+int _zip_local_header_read(struct zip *, int);
+void *_zip_memdup(const void *, size_t, struct zip_error *);
+int _zip_name_locate(struct zip *, const char *, int, struct zip_error *);
+struct zip *_zip_new(struct zip_error *);
+unsigned short _zip_read2(unsigned char **);
+unsigned int _zip_read4(unsigned char **);
+int _zip_replace(struct zip *, int, const char *, struct zip_source *);
+int _zip_set_name(struct zip *, int, const char *);
+int _zip_unchange(struct zip *, int, int);
+void _zip_unchange_data(struct zip_entry *);
+
+         
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *
+_zip_error_strerror(struct zip_error *err)
+{
+    const char *zs, *ss;
+    char buf[128], *s;
+
+    _zip_error_fini(err);
+
+    if (err->zip_err < 0 || err->zip_err >= _zip_nerr_str) {
+        sprintf(buf, "Unknown error %d", err->zip_err);
+        zs = NULL;
+        ss = buf;
+    }
+    else {
+        zs = _zip_err_str[err->zip_err];
+        
+        switch (_zip_err_type[err->zip_err]) {
+        case ZIP_ET_SYS:
+            ss = strerror(err->sys_err);
+            break;
+
+        case ZIP_ET_ZLIB:
+            ss = zError(err->sys_err);
+            break;
+
+        default:
+            ss = NULL;
+        }
+    }
+
+    if (ss == NULL)
+        return zs;
+    else {
+        if ((s=(char *)malloc(strlen(ss)
+                              + (zs ? strlen(zs)+2 : 0) + 1)) == NULL)
+            return _zip_err_str[ZIP_ER_MEMORY];
+        
+        sprintf(s, "%s%s%s",
+                (zs ? zs : ""),
+                (zs ? ": " : ""),
+                ss);
+        err->str = s;
+
+        return s;
+    }
+}
+
+#include <stdlib.h>
+
+
+
+void
+_zip_error_clear(struct zip_error *err)
+{
+    err->zip_err = ZIP_ER_OK;
+    err->sys_err = 0;
+}
+
+
+
+void
+_zip_error_copy(struct zip_error *dst, struct zip_error *src)
+{
+    dst->zip_err = src->zip_err;
+    dst->sys_err = src->sys_err;
+}
+
+
+
+void
+_zip_error_fini(struct zip_error *err)
+{
+    free(err->str);
+    err->str = NULL;
+}
+
+
+
+void
+_zip_error_get(struct zip_error *err, int *zep, int *sep)
+{
+    if (zep)
+        *zep = err->zip_err;
+    if (sep) {
+        if (zip_error_get_sys_type(err->zip_err) != ZIP_ET_NONE)
+            *sep = err->sys_err;
+        else
+            *sep = 0;
+    }
+}
+
+
+
+void
+_zip_error_init(struct zip_error *err)
+{
+    err->zip_err = ZIP_ER_OK;
+    err->sys_err = 0;
+    err->str = NULL;
+}
+
+
+
+void
+_zip_error_set(struct zip_error *err, int ze, int se)
+{
+    if (err) {
+        err->zip_err = ze;
+        err->sys_err = se;
+    }
+}
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+
+
+int
+_zip_mkstemp(char *path)
+{
+        int fd;   
+        char *start, *trv;
+        struct stat sbuf;
+        pid_t pid;
+
+        /* To guarantee multiple calls generate unique names even if
+           the file is not created. 676 different possibilities with 7
+           or more X's, 26 with 6 or less. */
+        static char xtra[2] = "aa";
+        int xcnt = 0;
+
+        pid = getpid();
+
+        /* Move to end of path and count trailing X's. */
+        for (trv = path; *trv; ++trv)
+                if (*trv == 'X')
+                        xcnt++;
+                else
+                        xcnt = 0;        
+
+        /* Use at least one from xtra.  Use 2 if more than 6 X's. */
+        if (*(trv - 1) == 'X')
+                *--trv = xtra[0];
+        if (xcnt > 6 && *(trv - 1) == 'X')
+                *--trv = xtra[1];
+
+        /* Set remaining X's to pid digits with 0's to the left. */
+        while (*--trv == 'X') {
+                *trv = (pid % 10) + '0';
+                pid /= 10;
+        }
+
+        /* update xtra for next call. */
+        if (xtra[0] != 'z')
+                xtra[0]++;
+        else {
+                xtra[0] = 'a';
+                if (xtra[1] != 'z')
+                        xtra[1]++;
+                else
+                        xtra[1] = 'a';
+        }
+
+        /*
+         * check the target directory; if you have six X's and it
+         * doesn't exist this runs for a *very* long time.
+         */
+        for (start = trv + 1;; --trv) {
+                if (trv <= path)
+                        break;
+                if (*trv == '/') {
+                        *trv = '\0';
+                        if (stat(path, &sbuf))
+                                return (0);
+                        if (!S_ISDIR(sbuf.st_mode)) {
+                                errno = ENOTDIR;
+                                return (0);
+                        }
+                        *trv = '/';
+                        break;
+                }
+        }
+
+        for (;;) {
+                if ((fd=open(path, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600)) >= 0)
+                        return (fd);
+                if (errno != EEXIST)
+                        return (0);
+
+                /* tricky little algorithm for backward compatibility */
+                for (trv = start;;) {
+                        if (!*trv)
+                                return (0);
+                        if (*trv == 'z')
+                                *trv++ = 'a';
+                        else {
+                                if (isdigit((unsigned char)*trv))
+                                        *trv = 'a';
+                                else
+                                        ++*trv;
+                                break;
+                        }
+                }
+        }
+        /*NOTREACHED*/
+}
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static time_t _zip_d2u_time(int, int);
+static char *_zip_readfpstr(FILE *, unsigned int, int, struct zip_error *);
+static char *_zip_readstr(unsigned char **, int, int, struct zip_error *);
+static void _zip_u2d_time(time_t, unsigned short *, unsigned short *);
+static void _zip_write2(unsigned short, FILE *);
+static void _zip_write4(unsigned int, FILE *);
+
+
+
+void
+_zip_cdir_free(struct zip_cdir *cd)
+{
+    int i;
+
+    if (!cd)
+        return;
+
+    for (i=0; i<cd->nentry; i++)
+        _zip_dirent_finalize(cd->entry+i);
+    free(cd->comment);
+    free(cd->entry);
+    free(cd);
+}
+
+
+
+struct zip_cdir *
+_zip_cdir_new(int nentry, struct zip_error *error)
+{
+    struct zip_cdir *cd;
+    
+    if ((cd=(struct zip_cdir *)malloc(sizeof(*cd))) == NULL) {
+        _zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    if ((cd->entry=(struct zip_dirent *)malloc(sizeof(*(cd->entry))*nentry))
+        == NULL) {
+        _zip_error_set(error, ZIP_ER_MEMORY, 0);
+        free(cd);
+        return NULL;
+    }
+
+    /* entries must be initialized by caller */
+
+    cd->nentry = nentry;
+    cd->size = cd->offset = 0;
+    cd->comment = NULL;
+    cd->comment_len = 0;
+
+    return cd;
+}
+
+
+
+int
+_zip_cdir_write(struct zip_cdir *cd, FILE *fp, struct zip_error *error)
+{
+    int i;
+
+    cd->offset = ftello(fp);
+
+    for (i=0; i<cd->nentry; i++) {
+        if (_zip_dirent_write(cd->entry+i, fp, 0, error) != 0)
+            return -1;
+    }
+
+    cd->size = ftello(fp) - cd->offset;
+    
+    /* clearerr(fp); */
+    fwrite(EOCD_MAGIC, 1, 4, fp);
+    _zip_write4(0, fp);
+    _zip_write2((unsigned short)cd->nentry, fp);
+    _zip_write2((unsigned short)cd->nentry, fp);
+    _zip_write4(cd->size, fp);
+    _zip_write4(cd->offset, fp);
+    _zip_write2(cd->comment_len, fp);
+    fwrite(cd->comment, 1, cd->comment_len, fp);
+
+    if (ferror(fp)) {
+        _zip_error_set(error, ZIP_ER_WRITE, errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+void
+_zip_dirent_finalize(struct zip_dirent *zde)
+{
+    free(zde->filename);
+    zde->filename = NULL;
+    free(zde->extrafield);
+    zde->extrafield = NULL;
+    free(zde->comment);
+    zde->comment = NULL;
+}
+
+
+
+void
+_zip_dirent_init(struct zip_dirent *de)
+{
+    de->version_madeby = 0;
+    de->version_needed = 20; /* 2.0 */
+    de->bitflags = 0;
+    de->comp_method = 0;
+    de->last_mod = 0;
+    de->crc = 0;
+    de->comp_size = 0;
+    de->uncomp_size = 0;
+    de->filename = NULL;
+    de->filename_len = 0;
+    de->extrafield = NULL;
+    de->extrafield_len = 0;
+    de->comment = NULL;
+    de->comment_len = 0;
+    de->disk_number = 0;
+    de->int_attrib = 0;
+    de->ext_attrib = 0;
+    de->offset = 0;
+}
+
+
+
+/* _zip_dirent_read(zde, fp, bufp, left, localp, error):
+   Fills the zip directory entry zde.
+
+   If bufp is non-NULL, data is taken from there and bufp is advanced
+   by the amount of data used; no more than left bytes are used.
+   Otherwise data is read from fp as needed.
+
+   If localp != 0, it reads a local header instead of a central
+   directory entry.
+
+   Returns 0 if successful. On error, error is filled in and -1 is
+   returned.
+*/
+
+int
+_zip_dirent_read(struct zip_dirent *zde, FILE *fp,
+                 unsigned char **bufp, unsigned int left, int localp,
+                 struct zip_error *error)
+{
+    unsigned char buf[CDENTRYSIZE];
+    unsigned char *cur;
+    unsigned short dostime, dosdate;
+    unsigned int size;
+
+    if (localp)
+        size = LENTRYSIZE;
+    else
+        size = CDENTRYSIZE;
+    
+    if (bufp) {
+        /* use data from buffer */
+        cur = *bufp;
+        if (left < size) {
+            _zip_error_set(error, ZIP_ER_NOZIP, 0);
+            return -1;
+        }
+    }
+    else {
+        /* read entry from disk */
+        if ((fread(buf, 1, size, fp)<size)) {
+            _zip_error_set(error, ZIP_ER_READ, errno);
+            return -1;
+        }
+        left = size;
+        cur = buf;
+    }
+
+    if (memcmp(cur, (localp ? LOCAL_MAGIC : CENTRAL_MAGIC), 4) != 0) {
+        _zip_error_set(error, ZIP_ER_NOZIP, 0);
+        return -1;
+    }
+    cur += 4;
+
+    
+    /* convert buffercontents to zip_dirent */
+    
+    if (!localp)
+        zde->version_madeby = _zip_read2(&cur);
+    else
+        zde->version_madeby = 0;
+    zde->version_needed = _zip_read2(&cur);
+    zde->bitflags = _zip_read2(&cur);
+    zde->comp_method = _zip_read2(&cur);
+    
+    /* convert to time_t */
+    dostime = _zip_read2(&cur);
+    dosdate = _zip_read2(&cur);
+    zde->last_mod = _zip_d2u_time(dostime, dosdate);
+    
+    zde->crc = _zip_read4(&cur);
+    zde->comp_size = _zip_read4(&cur);
+    zde->uncomp_size = _zip_read4(&cur);
+    
+    zde->filename_len = _zip_read2(&cur);
+    zde->extrafield_len = _zip_read2(&cur);
+    
+    if (localp) {
+        zde->comment_len = 0;
+        zde->disk_number = 0;
+        zde->int_attrib = 0;
+        zde->ext_attrib = 0;
+        zde->offset = 0;
+    } else {
+        zde->comment_len = _zip_read2(&cur);
+        zde->disk_number = _zip_read2(&cur);
+        zde->int_attrib = _zip_read2(&cur);
+        zde->ext_attrib = _zip_read4(&cur);
+        zde->offset = _zip_read4(&cur);
+    }
+
+    zde->filename = NULL;
+    zde->extrafield = NULL;
+    zde->comment = NULL;
+
+    if (bufp) {
+        if (left < CDENTRYSIZE + (zde->filename_len+zde->extrafield_len
+                                  +zde->comment_len)) {
+            _zip_error_set(error, ZIP_ER_NOZIP, 0);
+            return -1;
+        }
+
+        if (zde->filename_len) {
+            zde->filename = _zip_readstr(&cur, zde->filename_len, 1, error);
+            if (!zde->filename)
+                    return -1;
+        }
+
+        if (zde->extrafield_len) {
+            zde->extrafield = _zip_readstr(&cur, zde->extrafield_len, 0,
+                                           error);
+            if (!zde->extrafield)
+                return -1;
+        }
+
+        if (zde->comment_len) {
+            zde->comment = _zip_readstr(&cur, zde->comment_len, 0, error);
+            if (!zde->comment)
+                return -1;
+        }
+    }
+    else {
+        if (zde->filename_len) {
+            zde->filename = _zip_readfpstr(fp, zde->filename_len, 1, error);
+            if (!zde->filename)
+                    return -1;
+        }
+
+        if (zde->extrafield_len) {
+            zde->extrafield = _zip_readfpstr(fp, zde->extrafield_len, 0,
+                                             error);
+            if (!zde->extrafield)
+                return -1;
+        }
+
+        if (zde->comment_len) {
+            zde->comment = _zip_readfpstr(fp, zde->comment_len, 0, error);
+            if (!zde->comment)
+                return -1;
+        }
+    }
+
+    if (bufp)
+      *bufp = cur;
+
+    return 0;
+}
+
+
+
+/* _zip_dirent_torrent_normalize(de);
+   Set values suitable for torrentzip.
+*/
+
+void
+_zip_dirent_torrent_normalize(struct zip_dirent *de)
+{
+    static struct tm torrenttime;
+    static time_t last_mod = 0;
+
+    if (last_mod == 0) {
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+        time_t now;
+        struct tm *l;
+#endif
+
+        torrenttime.tm_sec = 0;
+        torrenttime.tm_min = 32;
+        torrenttime.tm_hour = 23;
+        torrenttime.tm_mday = 24;
+        torrenttime.tm_mon = 11;
+        torrenttime.tm_year = 96;
+        torrenttime.tm_wday = 0;
+        torrenttime.tm_yday = 0;
+        torrenttime.tm_isdst = 0;
+
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+        time(&now);
+        l = localtime(&now);
+        torrenttime.tm_gmtoff = l->tm_gmtoff;
+        torrenttime.tm_zone = l->tm_zone;
+#endif
+
+        last_mod = mktime(&torrenttime);
+    }
+    
+    de->version_madeby = 0;
+    de->version_needed = 20; /* 2.0 */
+    de->bitflags = 2; /* maximum compression */
+    de->comp_method = ZIP_CM_DEFLATE;
+    de->last_mod = last_mod;
+
+    de->disk_number = 0;
+    de->int_attrib = 0;
+    de->ext_attrib = 0;
+    de->offset = 0;
+
+    free(de->extrafield);
+    de->extrafield = NULL;
+    de->extrafield_len = 0;
+    free(de->comment);
+    de->comment = NULL;
+    de->comment_len = 0;
+}
+
+
+
+/* _zip_dirent_write(zde, fp, localp, error):
+   Writes zip directory entry zde to file fp.
+
+   If localp != 0, it writes a local header instead of a central
+   directory entry.
+
+   Returns 0 if successful. On error, error is filled in and -1 is
+   returned.
+*/
+
+int
+_zip_dirent_write(struct zip_dirent *zde, FILE *fp, int localp,
+                  struct zip_error *error)
+{
+    unsigned short dostime, dosdate;
+
+    fwrite(localp ? LOCAL_MAGIC : CENTRAL_MAGIC, 1, 4, fp);
+
+    if (!localp)
+        _zip_write2(zde->version_madeby, fp);
+    _zip_write2(zde->version_needed, fp);
+    _zip_write2(zde->bitflags, fp);
+    _zip_write2(zde->comp_method, fp);
+
+    _zip_u2d_time(zde->last_mod, &dostime, &dosdate);
+    _zip_write2(dostime, fp);
+    _zip_write2(dosdate, fp);
+    
+    _zip_write4(zde->crc, fp);
+    _zip_write4(zde->comp_size, fp);
+    _zip_write4(zde->uncomp_size, fp);
+    
+    _zip_write2(zde->filename_len, fp);
+    _zip_write2(zde->extrafield_len, fp);
+    
+    if (!localp) {
+        _zip_write2(zde->comment_len, fp);
+        _zip_write2(zde->disk_number, fp);
+        _zip_write2(zde->int_attrib, fp);
+        _zip_write4(zde->ext_attrib, fp);
+        _zip_write4(zde->offset, fp);
+    }
+
+    if (zde->filename_len)
+        fwrite(zde->filename, 1, zde->filename_len, fp);
+
+    if (zde->extrafield_len)
+        fwrite(zde->extrafield, 1, zde->extrafield_len, fp);
+
+    if (!localp) {
+        if (zde->comment_len)
+            fwrite(zde->comment, 1, zde->comment_len, fp);
+    }
+
+    if (ferror(fp)) {
+        _zip_error_set(error, ZIP_ER_WRITE, errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static time_t
+_zip_d2u_time(int dtime, int ddate)
+{
+    struct tm *tm;
+    time_t now;
+
+    now = time(NULL);
+    tm = localtime(&now);
+    /* let mktime decide if DST is in effect */
+    tm->tm_isdst = -1;
+    
+    tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
+    tm->tm_mon = ((ddate>>5)&15) - 1;
+    tm->tm_mday = ddate&31;
+
+    tm->tm_hour = (dtime>>11)&31;
+    tm->tm_min = (dtime>>5)&63;
+    tm->tm_sec = (dtime<<1)&62;
+
+    return mktime(tm);
+}
+
+
+
+unsigned short
+_zip_read2(unsigned char **a)
+{
+    unsigned short ret;
+
+    ret = (*a)[0]+((*a)[1]<<8);
+    *a += 2;
+
+    return ret;
+}
+
+
+
+unsigned int
+_zip_read4(unsigned char **a)
+{
+    unsigned int ret;
+
+    ret = ((((((*a)[3]<<8)+(*a)[2])<<8)+(*a)[1])<<8)+(*a)[0];
+    *a += 4;
+
+    return ret;
+}
+
+
+
+static char *
+_zip_readfpstr(FILE *fp, unsigned int len, int nulp, struct zip_error *error)
+{
+    char *r, *o;
+
+    r = (char *)malloc(nulp ? len+1 : len);
+    if (!r) {
+        _zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    if (fread(r, 1, len, fp)<len) {
+        free(r);
+        _zip_error_set(error, ZIP_ER_READ, errno);
+        return NULL;
+    }
+
+    if (nulp) {
+        /* replace any in-string NUL characters with spaces */
+        r[len] = 0;
+        for (o=r; o<r+len; o++)
+            if (*o == '\0')
+                *o = ' ';
+    }
+    
+    return r;
+}
+
+
+
+static char *
+_zip_readstr(unsigned char **buf, int len, int nulp, struct zip_error *error)
+{
+    char *r, *o;
+
+    r = (char *)malloc(nulp ? len+1 : len);
+    if (!r) {
+        _zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+    
+    memcpy(r, *buf, len);
+    *buf += len;
+
+    if (nulp) {
+        /* replace any in-string NUL characters with spaces */
+        r[len] = 0;
+        for (o=r; o<r+len; o++)
+            if (*o == '\0')
+                *o = ' ';
+    }
+
+    return r;
+}
+
+
+
+static void
+_zip_write2(unsigned short i, FILE *fp)
+{
+    putc(i&0xff, fp);
+    putc((i>>8)&0xff, fp);
+
+    return;
+}
+
+
+
+static void
+_zip_write4(unsigned int i, FILE *fp)
+{
+    putc(i&0xff, fp);
+    putc((i>>8)&0xff, fp);
+    putc((i>>16)&0xff, fp);
+    putc((i>>24)&0xff, fp);
+    
+    return;
+}
+
+
+
+static void
+_zip_u2d_time(time_t time, unsigned short *dtime, unsigned short *ddate)
+{
+    struct tm *tm;
+
+    tm = localtime(&time);
+    *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5)
+        + tm->tm_mday;
+    *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5)
+        + ((tm->tm_sec)>>1);
+
+    return;
+}
+
+
+
+ZIP_EXTERN int
+zip_delete(struct zip *za, int idx)
+{
+    if (idx < 0 || idx >= za->nentry) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    /* allow duplicate file names, because the file will
+     * be removed directly afterwards */
+    if (_zip_unchange(za, idx, 1) != 0)
+        return -1;
+
+    za->entry[idx].state = ZIP_ST_DELETED;
+
+    return 0;
+}
+
+
+
+ZIP_EXTERN void
+zip_error_clear(struct zip *za)
+{
+    _zip_error_clear(&za->error);
+}
+
+
+ZIP_EXTERN int
+zip_add(struct zip *za, const char *name, struct zip_source *source)
+{
+    if (name == NULL || source == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+        
+    return _zip_replace(za, -1, name, source);
+}
+
+
+ZIP_EXTERN int
+zip_error_get_sys_type(int ze)
+{
+    if (ze < 0 || ze >= _zip_nerr_str)
+        return 0;
+
+    return _zip_err_type[ze];
+}
+
+
+ZIP_EXTERN void
+zip_error_get(struct zip *za, int *zep, int *sep)
+{
+    _zip_error_get(&za->error, zep, sep);
+}
+
+
+const char * const _zip_err_str[] = {
+    "No error",
+    "Multi-disk zip archives not supported",
+    "Renaming temporary file failed",
+    "Closing zip archive failed",
+    "Seek error",
+    "Read error",
+    "Write error",
+    "CRC error",
+    "Containing zip archive was closed",
+    "No such file",
+    "File already exists",
+    "Can't open file",
+    "Failure to create temporary file",
+    "Zlib error",
+    "Malloc failure",
+    "Entry has been changed",
+    "Compression method not supported",
+    "Premature EOF",
+    "Invalid argument",
+    "Not a zip archive",
+    "Internal error",
+    "Zip archive inconsistent",
+    "Can't remove file",
+    "Entry has been deleted",
+};
+
+const int _zip_nerr_str = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
+
+#define N ZIP_ET_NONE
+#define S ZIP_ET_SYS
+#define Z ZIP_ET_ZLIB
+
+const int _zip_err_type[] = {
+    N,
+    N,
+    S,
+    S,
+    S,
+    S,
+    S,
+    N,
+    N,
+    N,
+    N,
+    S,
+    S,
+    Z,
+    N,
+    N,
+    N,
+    N,
+    N,
+    N,
+    N,
+    N,
+    S,
+    N,
+};
+
+
+struct zip_entry *
+_zip_entry_new(struct zip *za)
+{
+    struct zip_entry *ze;
+    if (!za) {
+        ze = (struct zip_entry *)malloc(sizeof(struct zip_entry));
+        if (!ze) {
+            _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+            return NULL;
+        }
+    }
+    else {
+        if (za->nentry >= za->nentry_alloc-1) {
+            za->nentry_alloc += 16;
+            za->entry = (struct zip_entry *)realloc(za->entry,
+                                                    sizeof(struct zip_entry)
+                                                    * za->nentry_alloc);
+            if (!za->entry) {
+                _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+                return NULL;
+            }
+        }
+        ze = za->entry+za->nentry;
+    }
+
+    ze->state = ZIP_ST_UNCHANGED;
+
+    ze->ch_filename = NULL;
+    ze->ch_comment = NULL;
+    ze->ch_comment_len = -1;
+    ze->source = NULL;
+
+    if (za)
+        za->nentry++;
+
+    return ze;
+}
+
+
+void
+_zip_entry_free(struct zip_entry *ze)
+{
+    free(ze->ch_filename);
+    ze->ch_filename = NULL;
+    free(ze->ch_comment);
+    ze->ch_comment = NULL;
+    ze->ch_comment_len = -1;
+
+    _zip_unchange_data(ze);
+}
+
+
+static int add_data(struct zip *, struct zip_source *, struct zip_dirent *,
+                    FILE *);
+static int add_data_comp(zip_source_callback, void *, struct zip_stat *,
+                         FILE *, struct zip_error *);
+static int add_data_uncomp(struct zip *, zip_source_callback, void *,
+                           struct zip_stat *, FILE *);
+static void ch_set_error(struct zip_error *, zip_source_callback, void *);
+static int copy_data(FILE *, myoff_t, FILE *, struct zip_error *);
+static int write_cdir(struct zip *, struct zip_cdir *, FILE *);
+static int _zip_cdir_set_comment(struct zip_cdir *, struct zip *);
+static int _zip_changed(struct zip *, int *);
+static char *_zip_create_temp_output(struct zip *, FILE **);
+static int _zip_torrentzip_cmp(const void *, const void *);
+
+
+
+struct filelist {
+    int idx;
+    const char *name;
+};
+
+
+
+ZIP_EXTERN int
+zip_close(struct zip *za)
+{
+    int survivors;
+    int i, j, error;
+    char *temp;
+    FILE *out;
+    mode_t mask;
+    struct zip_cdir *cd;
+    struct zip_dirent de;
+    struct filelist *filelist;
+    int reopen_on_error;
+    int new_torrentzip;
+
+    reopen_on_error = 0;
+
+    if (za == NULL)
+        return -1;
+
+    if (!_zip_changed(za, &survivors)) {
+        _zip_free(za);
+        return 0;
+    }
+
+    /* don't create zip files with no entries */
+    if (survivors == 0) {
+        if (za->zn && za->zp) {
+            if (remove(za->zn) != 0) {
+                _zip_error_set(&za->error, ZIP_ER_REMOVE, errno);
+                return -1;
+            }
+        }
+        _zip_free(za);
+        return 0;
+    }               
+
+    if ((filelist=(struct filelist *)malloc(sizeof(filelist[0])*survivors))
+        == NULL)
+        return -1;
+
+    if ((cd=_zip_cdir_new(survivors, &za->error)) == NULL) {
+        free(filelist);
+        return -1;
+    }
+
+    for (i=0; i<survivors; i++)
+        _zip_dirent_init(&cd->entry[i]);
+
+    /* archive comment is special for torrentzip */
+    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0)) {
+        cd->comment = _zip_memdup(TORRENT_SIG "XXXXXXXX",
+                                  TORRENT_SIG_LEN + TORRENT_CRC_LEN,
+                                  &za->error);
+        if (cd->comment == NULL) {
+            _zip_cdir_free(cd);
+            free(filelist);
+            return -1;
+        }
+        cd->comment_len = TORRENT_SIG_LEN + TORRENT_CRC_LEN;
+    }
+    else if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, ZIP_FL_UNCHANGED) == 0) {
+        if (_zip_cdir_set_comment(cd, za) == -1) {
+            _zip_cdir_free(cd);
+            free(filelist);
+            return -1;
+        }
+    }
+
+    if ((temp=_zip_create_temp_output(za, &out)) == NULL) {
+        _zip_cdir_free(cd);
+        return -1;
+    }
+
+
+    /* create list of files with index into original archive  */
+    for (i=j=0; i<za->nentry; i++) {
+        if (za->entry[i].state == ZIP_ST_DELETED)
+            continue;
+
+        filelist[j].idx = i;
+        filelist[j].name = zip_get_name(za, i, 0);
+        j++;
+    }
+    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
+        qsort(filelist, survivors, sizeof(filelist[0]),
+              _zip_torrentzip_cmp);
+
+    new_torrentzip = (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 1
+                      && zip_get_archive_flag(za, ZIP_AFL_TORRENT,
+                                              ZIP_FL_UNCHANGED) == 0);
+    error = 0;
+    for (j=0; j<survivors; j++) {
+        i = filelist[j].idx;
+
+        /* create new local directory entry */
+        if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) {
+            _zip_dirent_init(&de);
+
+            if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
+                _zip_dirent_torrent_normalize(&de);
+                
+            /* use it as central directory entry */
+            memcpy(cd->entry+j, &de, sizeof(cd->entry[j]));
+
+            /* set/update file name */
+            if (za->entry[i].ch_filename == NULL) {
+                if (za->entry[i].state == ZIP_ST_ADDED) {
+                    de.filename = strdup("-");
+                    de.filename_len = 1;
+                    cd->entry[j].filename = "-";
+                }
+                else {
+                    de.filename = strdup(za->cdir->entry[i].filename);
+                    de.filename_len = strlen(de.filename);
+                    cd->entry[j].filename = za->cdir->entry[i].filename;
+                    cd->entry[j].filename_len = de.filename_len;
+                }
+            }
+        }
+        else {
+            /* copy existing directory entries */
+            if (fseeko(za->zp, za->cdir->entry[i].offset, SEEK_SET) != 0) {
+                _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
+                error = 1;
+                break;
+            }
+            if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0) {
+                error = 1;
+                break;
+            }
+            if (de.bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
+                de.crc = za->cdir->entry[i].crc;
+                de.comp_size = za->cdir->entry[i].comp_size;
+                de.uncomp_size = za->cdir->entry[i].uncomp_size;
+                de.bitflags &= ~ZIP_GPBF_DATA_DESCRIPTOR;
+            }
+            memcpy(cd->entry+j, za->cdir->entry+i, sizeof(cd->entry[j]));
+        }
+
+        if (za->entry[i].ch_filename) {
+            free(de.filename);
+            if ((de.filename=strdup(za->entry[i].ch_filename)) == NULL) {
+                error = 1;
+                break;
+            }
+            de.filename_len = strlen(de.filename);
+            cd->entry[j].filename = za->entry[i].ch_filename;
+            cd->entry[j].filename_len = de.filename_len;
+        }
+
+        if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0
+            && za->entry[i].ch_comment_len != -1) {
+            /* as the rest of cd entries, its malloc/free is done by za */
+            cd->entry[j].comment = za->entry[i].ch_comment;
+            cd->entry[j].comment_len = za->entry[i].ch_comment_len;
+        }
+
+        cd->entry[j].offset = ftello(out);
+
+        if (ZIP_ENTRY_DATA_CHANGED(za->entry+i) || new_torrentzip) {
+            struct zip_source *zs;
+
+            zs = NULL;
+            if (!ZIP_ENTRY_DATA_CHANGED(za->entry+i)) {
+                if ((zs=zip_source_zip(za, za, i, ZIP_FL_RECOMPRESS, 0, -1))
+                    == NULL) {
+                    error = 1;
+                    break;
+                }
+            }
+
+            if (add_data(za, zs ? zs : za->entry[i].source, &de, out) < 0) {
+                error = 1;
+                break;
+            }
+            cd->entry[j].last_mod = de.last_mod;
+            cd->entry[j].comp_method = de.comp_method;
+            cd->entry[j].comp_size = de.comp_size;
+            cd->entry[j].uncomp_size = de.uncomp_size;
+            cd->entry[j].crc = de.crc;
+        }
+        else {
+            if (_zip_dirent_write(&de, out, 1, &za->error) < 0) {
+                error = 1;
+                break;
+            }
+            /* we just read the local dirent, file is at correct position */
+            if (copy_data(za->zp, cd->entry[j].comp_size, out,
+                          &za->error) < 0) {
+                error = 1;
+                break;
+            }
+        }
+
+        _zip_dirent_finalize(&de);
+    }
+
+    if (!error) {
+        if (write_cdir(za, cd, out) < 0)
+            error = 1;
+    }
+   
+    /* pointers in cd entries are owned by za */
+    cd->nentry = 0;
+    _zip_cdir_free(cd);
+
+    if (error) {
+        _zip_dirent_finalize(&de);
+        fclose(out);
+        remove(temp);
+        free(temp);
+        return -1;
+    }
+
+    if (fclose(out) != 0) {
+        _zip_error_set(&za->error, ZIP_ER_CLOSE, errno);
+        remove(temp);
+        free(temp);
+        return -1;
+    }
+    
+    if (za->zp) {
+        fclose(za->zp);
+        za->zp = NULL;
+        reopen_on_error = 1;
+    }
+    if (_zip_rename(temp, za->zn) != 0) {
+        _zip_error_set(&za->error, ZIP_ER_RENAME, errno);
+        remove(temp);
+        free(temp);
+        if (reopen_on_error) {
+            /* ignore errors, since we're already in an error case */
+            za->zp = fopen(za->zn, "rb");
+        }
+        return -1;
+    }
+    mask = umask(0);
+    umask(mask);
+    chmod(za->zn, 0666&~mask);
+
+    _zip_free(za);
+    free(temp);
+    
+    return 0;
+}
+
+
+
+static int
+add_data(struct zip *za, struct zip_source *zs, struct zip_dirent *de, FILE *ft)
+{
+    myoff_t offstart, offend;
+    zip_source_callback cb;
+    void *ud;
+    struct zip_stat st;
+    
+    cb = zs->f;
+    ud = zs->ud;
+
+    if (cb(ud, &st, sizeof(st), ZIP_SOURCE_STAT) < (ssize_t)sizeof(st)) {
+        ch_set_error(&za->error, cb, ud);
+        return -1;
+    }
+
+    if (cb(ud, NULL, 0, ZIP_SOURCE_OPEN) < 0) {
+        ch_set_error(&za->error, cb, ud);
+        return -1;
+    }
+
+    offstart = ftello(ft);
+
+    if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
+        return -1;
+
+    if (st.comp_method != ZIP_CM_STORE) {
+        if (add_data_comp(cb, ud, &st, ft, &za->error) < 0)
+            return -1;
+    }
+    else {
+        if (add_data_uncomp(za, cb, ud, &st, ft) < 0)
+            return -1;
+    }
+
+    if (cb(ud, NULL, 0, ZIP_SOURCE_CLOSE) < 0) {
+        ch_set_error(&za->error, cb, ud);
+        return -1;
+    }
+
+    offend = ftello(ft);
+
+    if (fseeko(ft, offstart, SEEK_SET) < 0) {
+        _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
+        return -1;
+    }
+
+    
+    de->last_mod = st.mtime;
+    de->comp_method = st.comp_method;
+    de->crc = st.crc;
+    de->uncomp_size = st.size;
+    de->comp_size = st.comp_size;
+
+    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
+        _zip_dirent_torrent_normalize(de);
+
+    if (_zip_dirent_write(de, ft, 1, &za->error) < 0)
+        return -1;
+    
+    if (fseeko(ft, offend, SEEK_SET) < 0) {
+        _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+add_data_comp(zip_source_callback cb, void *ud, struct zip_stat *st,FILE *ft,
+              struct zip_error *error)
+{
+    char buf[BUFSIZE];
+    ssize_t n;
+
+    st->comp_size = 0;
+    while ((n=cb(ud, buf, sizeof(buf), ZIP_SOURCE_READ)) > 0) {
+        if (fwrite(buf, 1, n, ft) != (size_t)n) {
+            _zip_error_set(error, ZIP_ER_WRITE, errno);
+            return -1;
+        }
+        
+        st->comp_size += n;
+    }
+    if (n < 0) {
+        ch_set_error(error, cb, ud);
+        return -1;
+    }        
+
+    return 0;
+}
+
+
+
+static int
+add_data_uncomp(struct zip *za, zip_source_callback cb, void *ud,
+                struct zip_stat *st, FILE *ft)
+{
+    char b1[BUFSIZE], b2[BUFSIZE];
+    int end, flush, ret;
+    ssize_t n;
+    size_t n2;
+    z_stream zstr;
+    int mem_level;
+
+    st->comp_method = ZIP_CM_DEFLATE;
+    st->comp_size = st->size = 0;
+    st->crc = crc32(0, NULL, 0);
+
+    zstr.zalloc = Z_NULL;
+    zstr.zfree = Z_NULL;
+    zstr.opaque = NULL;
+    zstr.avail_in = 0;
+    zstr.avail_out = 0;
+
+    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0))
+        mem_level = TORRENT_MEM_LEVEL;
+    else
+        mem_level = MAX_MEM_LEVEL;
+
+    /* -MAX_WBITS: undocumented feature of zlib to _not_ write a zlib header */
+    deflateInit2(&zstr, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, mem_level,
+                 Z_DEFAULT_STRATEGY);
+
+    zstr.next_out = (Bytef *)b2;
+    zstr.avail_out = sizeof(b2);
+    zstr.avail_in = 0;
+
+    flush = 0;
+    end = 0;
+    while (!end) {
+        if (zstr.avail_in == 0 && !flush) {
+            if ((n=cb(ud, b1, sizeof(b1), ZIP_SOURCE_READ)) < 0) {
+                ch_set_error(&za->error, cb, ud);
+                deflateEnd(&zstr);
+                return -1;
+            }
+            if (n > 0) {
+                zstr.avail_in = n;
+                zstr.next_in = (Bytef *)b1;
+                st->size += n;
+                st->crc = crc32(st->crc, (Bytef *)b1, n);
+            }
+            else
+                flush = Z_FINISH;
+        }
+
+        ret = deflate(&zstr, flush);
+        if (ret != Z_OK && ret != Z_STREAM_END) {
+            _zip_error_set(&za->error, ZIP_ER_ZLIB, ret);
+            return -1;
+        }
+        
+        if (zstr.avail_out != sizeof(b2)) {
+            n2 = sizeof(b2) - zstr.avail_out;
+            
+            if (fwrite(b2, 1, n2, ft) != n2) {
+                _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
+                return -1;
+            }
+        
+            zstr.next_out = (Bytef *)b2;
+            zstr.avail_out = sizeof(b2);
+            st->comp_size += n2;
+        }
+
+        if (ret == Z_STREAM_END) {
+            deflateEnd(&zstr);
+            end = 1;
+        }
+    }
+
+    return 0;
+}
+
+
+
+static void
+ch_set_error(struct zip_error *error, zip_source_callback cb, void *ud)
+{
+    int e[2];
+
+    if ((cb(ud, e, sizeof(e), ZIP_SOURCE_ERROR)) < (ssize_t)sizeof(e)) {
+        error->zip_err = ZIP_ER_INTERNAL;
+        error->sys_err = 0;
+    }
+    else {
+        error->zip_err = e[0];
+        error->sys_err = e[1];
+    }
+}
+
+
+
+static int
+copy_data(FILE *fs, myoff_t len, FILE *ft, struct zip_error *error)
+{
+    char buf[BUFSIZE];
+    int n, nn;
+
+    if (len == 0)
+        return 0;
+
+    while (len > 0) {
+        nn = len > sizeof(buf) ? sizeof(buf) : len;
+        if ((n=fread(buf, 1, nn, fs)) < 0) {
+            _zip_error_set(error, ZIP_ER_READ, errno);
+            return -1;
+        }
+        else if (n == 0) {
+            _zip_error_set(error, ZIP_ER_EOF, 0);
+            return -1;
+        }
+
+        if (fwrite(buf, 1, n, ft) != (size_t)n) {
+            _zip_error_set(error, ZIP_ER_WRITE, errno);
+            return -1;
+        }
+        
+        len -= n;
+    }
+
+    return 0;
+}
+
+
+
+static int
+write_cdir(struct zip *za, struct zip_cdir *cd, FILE *out)
+{
+    myoff_t offset;
+    uLong crc;
+    char buf[TORRENT_CRC_LEN+1];
+    
+    if (_zip_cdir_write(cd, out, &za->error) < 0)
+        return -1;
+    
+    if (zip_get_archive_flag(za, ZIP_AFL_TORRENT, 0) == 0)
+        return 0;
+
+
+    /* fix up torrentzip comment */
+
+    offset = ftello(out);
+
+    if (_zip_filerange_crc(out, cd->offset, cd->size, &crc, &za->error) < 0)
+        return -1;
+
+    snprintf(buf, sizeof(buf), "%08lX", (long)crc);
+
+    if (fseeko(out, offset-TORRENT_CRC_LEN, SEEK_SET) < 0) {
+        _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
+        return -1;
+    }
+
+    if (fwrite(buf, TORRENT_CRC_LEN, 1, out) != 1) {
+        _zip_error_set(&za->error, ZIP_ER_WRITE, errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+
+static int
+_zip_cdir_set_comment(struct zip_cdir *dest, struct zip *src)
+{
+    if (src->ch_comment_len != -1) {
+        dest->comment = _zip_memdup(src->ch_comment,
+                                    src->ch_comment_len, &src->error);
+        if (dest->comment == NULL)
+            return -1;
+        dest->comment_len = src->ch_comment_len;
+    } else {
+        if (src->cdir && src->cdir->comment) {
+            dest->comment = _zip_memdup(src->cdir->comment,
+                                        src->cdir->comment_len, &src->error);
+            if (dest->comment == NULL)
+                return -1;
+            dest->comment_len = src->cdir->comment_len;
+        }
+    }
+
+    return 0;
+}
+
+
+
+static int
+_zip_changed(struct zip *za, int *survivorsp)
+{
+    int changed, i, survivors;
+
+    changed = survivors = 0;
+
+    if (za->ch_comment_len != -1
+        || za->ch_flags != za->flags)
+        changed = 1;
+
+    for (i=0; i<za->nentry; i++) {
+        if ((za->entry[i].state != ZIP_ST_UNCHANGED)
+            || (za->entry[i].ch_comment_len != -1))
+            changed = 1;
+        if (za->entry[i].state != ZIP_ST_DELETED)
+            survivors++;
+    }
+
+    *survivorsp = survivors;
+
+    return changed;
+}
+
+
+
+static char *
+_zip_create_temp_output(struct zip *za, FILE **outp)
+{
+    char *temp;
+    int tfd;
+    FILE *tfp;
+    
+    if ((temp=(char *)malloc(strlen(za->zn)+8)) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    sprintf(temp, "%s.XXXXXX", za->zn);
+
+    if ((tfd=mkstemp(temp)) == -1) {
+        _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno);
+        free(temp);
+        return NULL;
+    }
+    
+    if ((tfp=fdopen(tfd, "r+b")) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_TMPOPEN, errno);
+        close(tfd);
+        remove(temp);
+        free(temp);
+        return NULL;
+    }
+
+    *outp = tfp;
+    return temp;
+}
+
+
+
+static int
+_zip_torrentzip_cmp(const void *a, const void *b)
+{
+    return strcasecmp(((const struct filelist *)a)->name,
+                      ((const struct filelist *)b)->name);
+}
+
+
+
+ZIP_EXTERN int
+zip_add_dir(struct zip *za, const char *name)
+{
+    int len, ret;
+    char *s;
+    struct zip_source *source;
+
+    if (name == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    s = NULL;
+    len = strlen(name);
+
+    if (name[len-1] != '/') {
+        if ((s=(char *)malloc(len+2)) == NULL) {
+            _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+            return -1;
+        }
+        strcpy(s, name);
+        s[len] = '/';
+        s[len+1] = '\0';
+    }
+
+    if ((source=zip_source_buffer(za, NULL, 0, 0)) == NULL) {
+        free(s);
+        return -1;
+    }
+        
+    ret = _zip_replace(za, -1, s ? s : name, source);
+
+    free(s);
+    if (ret < 0)
+        zip_source_free(source);
+
+    return ret;
+}
+
+
+ZIP_EXTERN int
+zip_error_to_str(char *buf, size_t len, int ze, int se)
+{
+    const char *zs, *ss;
+
+    if (ze < 0 || ze >= _zip_nerr_str)
+        return snprintf(buf, len, "Unknown error %d", ze);
+
+    zs = _zip_err_str[ze];
+        
+    switch (_zip_err_type[ze]) {
+    case ZIP_ET_SYS:
+        ss = strerror(se);
+        break;
+        
+    case ZIP_ET_ZLIB:
+        ss = zError(se);
+        break;
+        
+    default:
+        ss = NULL;
+    }
+
+    return snprintf(buf, len, "%s%s%s",
+                    zs, (ss ? ": " : ""), (ss ? ss : ""));
+}
+
+
+ZIP_EXTERN void
+zip_file_error_clear(struct zip_file *zf)
+{
+    _zip_error_clear(&zf->error);
+}
+
+
+ZIP_EXTERN int
+zip_fclose(struct zip_file *zf)
+{
+    int i, ret;
+    
+    if (zf->zstr)
+        inflateEnd(zf->zstr);
+    free(zf->buffer);
+    free(zf->zstr);
+
+    for (i=0; i<zf->za->nfile; i++) {
+        if (zf->za->file[i] == zf) {
+            zf->za->file[i] = zf->za->file[zf->za->nfile-1];
+            zf->za->nfile--;
+            break;
+        }
+    }
+
+    ret = 0;
+    if (zf->error.zip_err)
+        ret = zf->error.zip_err;
+    else if ((zf->flags & ZIP_ZF_CRC) && (zf->flags & ZIP_ZF_EOF)) {
+        /* if EOF, compare CRC */
+        if (zf->crc_orig != zf->crc)
+            ret = ZIP_ER_CRC;
+    }
+
+    free(zf);
+    return ret;
+}
+
+
+int
+_zip_filerange_crc(FILE *fp, myoff_t start, myoff_t len, uLong *crcp,
+                   struct zip_error *errp)
+{
+    Bytef buf[BUFSIZE];
+    size_t n;
+
+    *crcp = crc32(0L, Z_NULL, 0);
+
+    if (fseeko(fp, start, SEEK_SET) != 0) {
+        _zip_error_set(errp, ZIP_ER_SEEK, errno);
+        return -1;
+    }
+    
+    while (len > 0) {
+        n = len > BUFSIZE ? BUFSIZE : len;
+        if ((n=fread(buf, 1, n, fp)) <= 0) {
+            _zip_error_set(errp, ZIP_ER_READ, errno);
+            return -1;
+        }
+
+        *crcp = crc32(*crcp, buf, n);
+
+        len-= n;
+    }
+
+    return 0;
+}
+
+
+ZIP_EXTERN const char *
+zip_file_strerror(struct zip_file *zf)
+{
+    return _zip_error_strerror(&zf->error);
+}
+
+
+/* _zip_file_get_offset(za, ze):
+   Returns the offset of the file data for entry ze.
+
+   On error, fills in za->error and returns 0.
+*/
+
+unsigned int
+_zip_file_get_offset(struct zip *za, int idx)
+{
+    struct zip_dirent de;
+    unsigned int offset;
+
+    offset = za->cdir->entry[idx].offset;
+
+    if (fseeko(za->zp, offset, SEEK_SET) != 0) {
+        _zip_error_set(&za->error, ZIP_ER_SEEK, errno);
+        return 0;
+    }
+
+    if (_zip_dirent_read(&de, za->zp, NULL, 0, 1, &za->error) != 0)
+        return 0;
+
+    offset += LENTRYSIZE + de.filename_len + de.extrafield_len;
+
+    _zip_dirent_finalize(&de);
+
+    return offset;
+}
+
+
+ZIP_EXTERN void
+zip_file_error_get(struct zip_file *zf, int *zep, int *sep)
+{
+    _zip_error_get(&zf->error, zep, sep);
+}
+
+
+static struct zip_file *_zip_file_new(struct zip *za);
+
+
+
+ZIP_EXTERN struct zip_file *
+zip_fopen_index(struct zip *za, int fileno, int flags)
+{
+    int len, ret;
+    int zfflags;
+    struct zip_file *zf;
+
+    if ((fileno < 0) || (fileno >= za->nentry)) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+        && ZIP_ENTRY_DATA_CHANGED(za->entry+fileno)) {
+        _zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
+        return NULL;
+    }
+
+    if (fileno >= za->cdir->nentry) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    zfflags = 0;
+    switch (za->cdir->entry[fileno].comp_method) {
+    case ZIP_CM_STORE:
+        zfflags |= ZIP_ZF_CRC;
+        break;
+
+    case ZIP_CM_DEFLATE:
+        if ((flags & ZIP_FL_COMPRESSED) == 0)
+            zfflags |= ZIP_ZF_CRC | ZIP_ZF_DECOMP;
+        break;
+    default:
+        if ((flags & ZIP_FL_COMPRESSED) == 0) {
+            _zip_error_set(&za->error, ZIP_ER_COMPNOTSUPP, 0);
+            return NULL;
+        }
+        break;
+    }
+
+    zf = _zip_file_new(za);
+
+    zf->flags = zfflags;
+    /* zf->name = za->cdir->entry[fileno].filename; */
+    zf->method = za->cdir->entry[fileno].comp_method;
+    zf->bytes_left = za->cdir->entry[fileno].uncomp_size;
+    zf->cbytes_left = za->cdir->entry[fileno].comp_size;
+    zf->crc_orig = za->cdir->entry[fileno].crc;
+
+    if ((zf->fpos=_zip_file_get_offset(za, fileno)) == 0) {
+        zip_fclose(zf);
+        return NULL;
+    }
+    
+    if ((zf->flags & ZIP_ZF_DECOMP) == 0)
+        zf->bytes_left = zf->cbytes_left;
+    else {
+        if ((zf->buffer=(char *)malloc(BUFSIZE)) == NULL) {
+            _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+            zip_fclose(zf);
+            return NULL;
+        }
+
+        len = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf);
+        if (len <= 0) {
+            _zip_error_copy(&za->error, &zf->error);
+            zip_fclose(zf);
+        return NULL;
+        }
+
+        if ((zf->zstr = (z_stream *)malloc(sizeof(z_stream))) == NULL) {
+            _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+            zip_fclose(zf);
+            return NULL;
+        }
+        zf->zstr->zalloc = Z_NULL;
+        zf->zstr->zfree = Z_NULL;
+        zf->zstr->opaque = NULL;
+        zf->zstr->next_in = (Bytef *)zf->buffer;
+        zf->zstr->avail_in = len;
+        
+        /* negative value to tell zlib that there is no header */
+        if ((ret=inflateInit2(zf->zstr, -MAX_WBITS)) != Z_OK) {
+            _zip_error_set(&za->error, ZIP_ER_ZLIB, ret);
+            zip_fclose(zf);
+            return NULL;
+        }
+    }
+    
+    return zf;
+}
+
+
+
+int
+_zip_file_fillbuf(void *buf, size_t buflen, struct zip_file *zf)
+{
+    int i, j;
+
+    if (zf->error.zip_err != ZIP_ER_OK)
+        return -1;
+
+    if ((zf->flags & ZIP_ZF_EOF) || zf->cbytes_left <= 0 || buflen <= 0)
+        return 0;
+    
+    if (fseeko(zf->za->zp, zf->fpos, SEEK_SET) < 0) {
+        _zip_error_set(&zf->error, ZIP_ER_SEEK, errno);
+        return -1;
+    }
+    if (buflen < zf->cbytes_left)
+        i = buflen;
+    else
+        i = zf->cbytes_left;
+
+    j = fread(buf, 1, i, zf->za->zp);
+    if (j == 0) {
+        _zip_error_set(&zf->error, ZIP_ER_EOF, 0);
+        j = -1;
+    }
+    else if (j < 0)
+        _zip_error_set(&zf->error, ZIP_ER_READ, errno);
+    else {
+        zf->fpos += j;
+        zf->cbytes_left -= j;
+    }
+
+    return j;        
+}
+
+
+
+static struct zip_file *
+_zip_file_new(struct zip *za)
+{
+    struct zip_file *zf, **file;
+    int n;
+
+    if ((zf=(struct zip_file *)malloc(sizeof(struct zip_file))) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+    
+    if (za->nfile >= za->nfile_alloc-1) {
+        n = za->nfile_alloc + 10;
+        file = (struct zip_file **)realloc(za->file,
+                                           n*sizeof(struct zip_file *));
+        if (file == NULL) {
+            _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+            free(zf);
+            return NULL;
+        }
+        za->nfile_alloc = n;
+        za->file = file;
+    }
+
+    za->file[za->nfile++] = zf;
+
+    zf->za = za;
+    _zip_error_init(&zf->error);
+    zf->flags = 0;
+    zf->crc = crc32(0L, Z_NULL, 0);
+    zf->crc_orig = 0;
+    zf->method = -1;
+    zf->bytes_left = zf->cbytes_left = 0;
+    zf->fpos = 0;
+    zf->buffer = NULL;
+    zf->zstr = NULL;
+
+    return zf;
+}
+
+
+ZIP_EXTERN struct zip_file *
+zip_fopen(struct zip *za, const char *fname, int flags)
+{
+    int idx;
+
+    if ((idx=zip_name_locate(za, fname, flags)) < 0)
+        return NULL;
+
+    return zip_fopen_index(za, idx, flags);
+}
+
+
+ZIP_EXTERN int
+zip_set_file_comment(struct zip *za, int idx, const char *comment, int len)
+{
+    char *tmpcom;
+
+    if (idx < 0 || idx >= za->nentry
+        || len < 0 || len > MAXCOMLEN
+        || (len > 0 && comment == NULL)) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if (len > 0) {
+        if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL)
+            return -1;
+    }
+    else
+        tmpcom = NULL;
+
+    free(za->entry[idx].ch_comment);
+    za->entry[idx].ch_comment = tmpcom;
+    za->entry[idx].ch_comment_len = len;
+    
+    return 0;
+}
+
+
+ZIP_EXTERN struct zip_source *
+zip_source_file(struct zip *za, const char *fname, myoff_t start, myoff_t len)
+{
+    if (za == NULL)
+        return NULL;
+
+    if (fname == NULL || start < 0 || len < -1) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    return _zip_source_file_or_p(za, fname, NULL, start, len);
+}
+
+
+struct read_data {
+    const char *buf, *data, *end;
+    time_t mtime;
+    int freep;
+};
+
+static ssize_t read_data(void *state, void *data, size_t len,
+                         enum zip_source_cmd cmd);
+
+
+
+ZIP_EXTERN struct zip_source *
+zip_source_buffer(struct zip *za, const void *data, myoff_t len, int freep)
+{
+    struct read_data *f;
+    struct zip_source *zs;
+
+    if (za == NULL)
+        return NULL;
+
+    if (len < 0 || (data == NULL && len > 0)) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    if ((f=(struct read_data *)malloc(sizeof(*f))) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    f->data = (const char *)data;
+    f->end = ((const char *)data)+len;
+    f->freep = freep;
+    f->mtime = time(NULL);
+    
+    if ((zs=zip_source_function(za, read_data, f)) == NULL) {
+        free(f);
+        return NULL;
+    }
+
+    return zs;
+}
+
+
+
+static ssize_t
+read_data(void *state, void *data, size_t len, enum zip_source_cmd cmd)
+{
+    struct read_data *z;
+    char *buf;
+    size_t n;
+
+    z = (struct read_data *)state;
+    buf = (char *)data;
+
+    switch (cmd) {
+    case ZIP_SOURCE_OPEN:
+        z->buf = z->data;
+        return 0;
+        
+    case ZIP_SOURCE_READ:
+        n = z->end - z->buf;
+        if (n > len)
+            n = len;
+
+        if (n) {
+            memcpy(buf, z->buf, n);
+            z->buf += n;
+        }
+
+        return n;
+        
+    case ZIP_SOURCE_CLOSE:
+        return 0;
+
+    case ZIP_SOURCE_STAT:
+        {
+            struct zip_stat *st;
+            
+            if (len < sizeof(*st))
+                return -1;
+
+            st = (struct zip_stat *)data;
+
+            zip_stat_init(st);
+            st->mtime = z->mtime;
+            st->size = z->end - z->data;
+            
+            return sizeof(*st);
+        }
+
+    case ZIP_SOURCE_ERROR:
+        {
+            int *e;
+
+            if (len < sizeof(int)*2)
+                return -1;
+
+            e = (int *)data;
+            e[0] = e[1] = 0;
+        }
+        return sizeof(int)*2;
+
+    case ZIP_SOURCE_FREE:
+        if (z->freep) {
+            free((void *)z->data);
+            z->data = NULL;
+        }
+        free(z);
+        return 0;
+
+    default:
+        ;
+    }
+
+    return -1;
+}
+
+
+int
+_zip_set_name(struct zip *za, int idx, const char *name)
+{
+    char *s;
+    int i;
+    
+    if (idx < 0 || idx >= za->nentry || name == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if ((i=_zip_name_locate(za, name, 0, NULL)) != -1 && i != idx) {
+        _zip_error_set(&za->error, ZIP_ER_EXISTS, 0);
+        return -1;
+    }
+
+    /* no effective name change */
+    if (i == idx)
+        return 0;
+    
+    if ((s=strdup(name)) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return -1;
+    }
+    
+    if (za->entry[idx].state == ZIP_ST_UNCHANGED) 
+        za->entry[idx].state = ZIP_ST_RENAMED;
+
+    free(za->entry[idx].ch_filename);
+    za->entry[idx].ch_filename = s;
+
+    return 0;
+}
+
+
+ZIP_EXTERN int
+zip_set_archive_flag(struct zip *za, int flag, int value)
+{
+    if (value)
+        za->ch_flags |= flag;
+    else
+        za->ch_flags &= ~flag;
+
+    return 0;
+}
+
+
+void
+_zip_unchange_data(struct zip_entry *ze)
+{
+    if (ze->source) {
+        (void)ze->source->f(ze->source->ud, NULL, 0, ZIP_SOURCE_FREE);
+        free(ze->source);
+        ze->source = NULL;
+    }
+    
+    ze->state = ze->ch_filename ? ZIP_ST_RENAMED : ZIP_ST_UNCHANGED;
+}
+
+
+ZIP_EXTERN int
+zip_unchange_archive(struct zip *za)
+{
+    free(za->ch_comment);
+    za->ch_comment = NULL;
+    za->ch_comment_len = -1;
+
+    za->ch_flags = za->flags;
+
+    return 0;
+}
+
+ZIP_EXTERN int
+zip_unchange(struct zip *za, int idx)
+{
+    return _zip_unchange(za, idx, 0);
+}
+
+
+
+int
+_zip_unchange(struct zip *za, int idx, int allow_duplicates)
+{
+    int i;
+    
+    if (idx < 0 || idx >= za->nentry) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if (za->entry[idx].ch_filename) {
+        if (!allow_duplicates) {
+            i = _zip_name_locate(za,
+                         _zip_get_name(za, idx, ZIP_FL_UNCHANGED, NULL),
+                                 0, NULL);
+            if (i != -1 && i != idx) {
+                _zip_error_set(&za->error, ZIP_ER_EXISTS, 0);
+                return -1;
+            }
+        }
+
+        free(za->entry[idx].ch_filename);
+        za->entry[idx].ch_filename = NULL;
+    }
+
+    free(za->entry[idx].ch_comment);
+    za->entry[idx].ch_comment = NULL;
+    za->entry[idx].ch_comment_len = -1;
+
+    _zip_unchange_data(za->entry+idx);
+
+    return 0;
+}
+
+ZIP_EXTERN int
+zip_unchange_all(struct zip *za)
+{
+    int ret, i;
+
+    ret = 0;
+    for (i=0; i<za->nentry; i++)
+        ret |= _zip_unchange(za, i, 1);
+
+    ret |= zip_unchange_archive(za);
+
+    return ret;
+}
+
+
+ZIP_EXTERN int
+zip_set_archive_comment(struct zip *za, const char *comment, int len)
+{
+    char *tmpcom;
+
+    if (len < 0 || len > MAXCOMLEN
+        || (len > 0 && comment == NULL)) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if (len > 0) {
+        if ((tmpcom=(char *)_zip_memdup(comment, len, &za->error)) == NULL)
+            return -1;
+    }
+    else
+        tmpcom = NULL;
+
+    free(za->ch_comment);
+    za->ch_comment = tmpcom;
+    za->ch_comment_len = len;
+    
+    return 0;
+}
+
+
+ZIP_EXTERN int
+zip_replace(struct zip *za, int idx, struct zip_source *source)
+{
+    if (idx < 0 || idx >= za->nentry || source == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if (_zip_replace(za, idx, NULL, source) == -1)
+        return -1;
+
+    return 0;
+}
+
+
+
+
+int
+_zip_replace(struct zip *za, int idx, const char *name,
+             struct zip_source *source)
+{
+    if (idx == -1) {
+        if (_zip_entry_new(za) == NULL)
+            return -1;
+
+        idx = za->nentry - 1;
+    }
+    
+    _zip_unchange_data(za->entry+idx);
+
+    if (name && _zip_set_name(za, idx, name) != 0)
+        return -1;
+    
+    za->entry[idx].state = ((za->cdir == NULL || idx >= za->cdir->nentry)
+                            ? ZIP_ST_ADDED : ZIP_ST_REPLACED);
+    za->entry[idx].source = source;
+
+    return idx;
+}
+
+
+ZIP_EXTERN int
+zip_rename(struct zip *za, int idx, const char *name)
+{
+    const char *old_name;
+    int old_is_dir, new_is_dir;
+    
+    if (idx >= za->nentry || idx < 0 || name[0] == '\0') {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if ((old_name=zip_get_name(za, idx, 0)) == NULL)
+        return -1;
+                                                                    
+    new_is_dir = (name[strlen(name)-1] == '/');
+    old_is_dir = (old_name[strlen(old_name)-1] == '/');
+
+    if (new_is_dir != old_is_dir) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    return _zip_set_name(za, idx, name);
+}
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void set_error(int *, struct zip_error *, int);
+static struct zip *_zip_allocate_new(const char *, int *);
+static int _zip_checkcons(FILE *, struct zip_cdir *, struct zip_error *);
+static void _zip_check_torrentzip(struct zip *);
+static struct zip_cdir *_zip_find_central_dir(FILE *, int, int *, myoff_t);
+static int _zip_file_exists(const char *, int, int *);
+static int _zip_headercomp(struct zip_dirent *, int,
+                           struct zip_dirent *, int);
+static unsigned char *_zip_memmem(const unsigned char *, int,
+                                  const unsigned char *, int);
+static struct zip_cdir *_zip_readcdir(FILE *, unsigned char *, unsigned char *,
+                                 int, int, struct zip_error *);
+
+
+
+ZIP_EXTERN struct zip *
+zip_open(const char *fn, int flags, int *zep)
+{
+    FILE *fp;
+    struct zip *za;
+    struct zip_cdir *cdir;
+    int i;
+    myoff_t len;
+    
+    switch (_zip_file_exists(fn, flags, zep)) {
+    case -1:
+        return NULL;
+    case 0:
+        return _zip_allocate_new(fn, zep);
+    default:
+        break;
+    }
+
+    if ((fp=fopen(fn, "rb")) == NULL) {
+        set_error(zep, NULL, ZIP_ER_OPEN);
+        return NULL;
+    }
+
+    fseeko(fp, 0, SEEK_END);
+    len = ftello(fp);
+
+    /* treat empty files as empty archives */
+    if (len == 0) {
+        if ((za=_zip_allocate_new(fn, zep)) == NULL)
+            fclose(fp);
+        else
+            za->zp = fp;
+        return za;
+    }
+
+    cdir = _zip_find_central_dir(fp, flags, zep, len);
+    if (cdir == NULL) {
+        fclose(fp);
+        return NULL;
+    }
+
+    if ((za=_zip_allocate_new(fn, zep)) == NULL) {
+        _zip_cdir_free(cdir);
+        fclose(fp);
+        return NULL;
+    }
+
+    za->cdir = cdir;
+    za->zp = fp;
+
+    if ((za->entry=(struct zip_entry *)malloc(sizeof(*(za->entry))
+                                              * cdir->nentry)) == NULL) {
+        set_error(zep, NULL, ZIP_ER_MEMORY);
+        _zip_free(za);
+        return NULL;
+    }
+    for (i=0; i<cdir->nentry; i++)
+        _zip_entry_new(za);
+
+    _zip_check_torrentzip(za);
+    za->ch_flags = za->flags;
+
+    return za;
+}
+
+
+
+static void
+set_error(int *zep, struct zip_error *err, int ze)
+{
+    int se;
+
+    if (err) {
+        _zip_error_get(err, &ze, &se);
+        if (zip_error_get_sys_type(ze) == ZIP_ET_SYS)
+            errno = se;
+    }
+
+    if (zep)
+        *zep = ze;
+}
+
+
+
+/* _zip_readcdir:
+   tries to find a valid end-of-central-directory at the beginning of
+   buf, and then the corresponding central directory entries.
+   Returns a struct zip_cdir which contains the central directory 
+   entries, or NULL if unsuccessful. */
+
+static struct zip_cdir *
+_zip_readcdir(FILE *fp, unsigned char *buf, unsigned char *eocd, int buflen,
+              int flags, struct zip_error *error)
+{
+    struct zip_cdir *cd;
+    unsigned char *cdp, **bufp;
+    int i, comlen, nentry;
+
+    comlen = buf + buflen - eocd - EOCDLEN;
+    if (comlen < 0) {
+        /* not enough bytes left for comment */
+        _zip_error_set(error, ZIP_ER_NOZIP, 0);
+        return NULL;
+    }
+
+    /* check for end-of-central-dir magic */
+    if (memcmp(eocd, EOCD_MAGIC, 4) != 0) {
+        _zip_error_set(error, ZIP_ER_NOZIP, 0);
+        return NULL;
+    }
+
+    if (memcmp(eocd+4, "\0\0\0\0", 4) != 0) {
+        _zip_error_set(error, ZIP_ER_MULTIDISK, 0);
+        return NULL;
+    }
+
+    cdp = eocd + 8;
+    /* number of cdir-entries on this disk */
+    i = _zip_read2(&cdp);
+    /* number of cdir-entries */
+    nentry = _zip_read2(&cdp);
+
+    if ((cd=_zip_cdir_new(nentry, error)) == NULL)
+        return NULL;
+
+    cd->size = _zip_read4(&cdp);
+    cd->offset = _zip_read4(&cdp);
+    cd->comment = NULL;
+    cd->comment_len = _zip_read2(&cdp);
+
+    if ((comlen < cd->comment_len) || (cd->nentry != i)) {
+        _zip_error_set(error, ZIP_ER_NOZIP, 0);
+        free(cd);
+        return NULL;
+    }
+    if ((flags & ZIP_CHECKCONS) && comlen != cd->comment_len) {
+        _zip_error_set(error, ZIP_ER_INCONS, 0);
+        free(cd);
+        return NULL;
+    }
+
+    if (cd->comment_len) {
+        if ((cd->comment=(char *)_zip_memdup(eocd+EOCDLEN,
+                                             cd->comment_len, error))
+            == NULL) {
+            free(cd);
+            return NULL;
+        }
+    }
+
+    cdp = eocd;
+    if (cd->size < (unsigned int)(eocd-buf)) {
+        /* if buffer already read in, use it */
+        cdp = eocd - cd->size;
+        bufp = &cdp;
+    }
+    else {
+        /* go to start of cdir and read it entry by entry */
+        bufp = NULL;
+        clearerr(fp);
+        fseeko(fp, cd->offset, SEEK_SET);
+        /* possible consistency check: cd->offset =
+           len-(cd->size+cd->comment_len+EOCDLEN) ? */
+        if (ferror(fp) || ((unsigned long)ftello(fp) != cd->offset)) {
+            /* seek error or offset of cdir wrong */
+            if (ferror(fp))
+                _zip_error_set(error, ZIP_ER_SEEK, errno);
+            else
+                _zip_error_set(error, ZIP_ER_NOZIP, 0);
+            free(cd);
+            return NULL;
+        }
+    }
+
+    for (i=0; i<cd->nentry; i++) {
+        if ((_zip_dirent_read(cd->entry+i, fp, bufp, eocd-cdp, 0,
+                              error)) < 0) {
+            cd->nentry = i;
+            _zip_cdir_free(cd);
+            return NULL;
+        }
+    }
+    
+    return cd;
+}
+
+
+
+/* _zip_checkcons:
+   Checks the consistency of the central directory by comparing central
+   directory entries with local headers and checking for plausible
+   file and header offsets. Returns -1 if not plausible, else the
+   difference between the lowest and the highest fileposition reached */
+
+static int
+_zip_checkcons(FILE *fp, struct zip_cdir *cd, struct zip_error *error)
+{
+    int i;
+    unsigned int min, max, j;
+    struct zip_dirent temp;
+
+    if (cd->nentry) {
+        max = cd->entry[0].offset;
+        min = cd->entry[0].offset;
+    }
+    else
+        min = max = 0;
+
+    for (i=0; i<cd->nentry; i++) {
+        if (cd->entry[i].offset < min)
+            min = cd->entry[i].offset;
+        if (min > cd->offset) {
+            _zip_error_set(error, ZIP_ER_NOZIP, 0);
+            return -1;
+        }
+        
+        j = cd->entry[i].offset + cd->entry[i].comp_size
+            + cd->entry[i].filename_len + LENTRYSIZE;
+        if (j > max)
+            max = j;
+        if (max > cd->offset) {
+            _zip_error_set(error, ZIP_ER_NOZIP, 0);
+            return -1;
+        }
+        
+        if (fseeko(fp, cd->entry[i].offset, SEEK_SET) != 0) {
+            _zip_error_set(error, ZIP_ER_SEEK, 0);
+            return -1;
+        }
+        
+        if (_zip_dirent_read(&temp, fp, NULL, 0, 1, error) == -1)
+            return -1;
+        
+        if (_zip_headercomp(cd->entry+i, 0, &temp, 1) != 0) {
+            _zip_error_set(error, ZIP_ER_INCONS, 0);
+            _zip_dirent_finalize(&temp);
+            return -1;
+        }
+        _zip_dirent_finalize(&temp);
+    }
+
+    return max - min;
+}
+
+
+
+/* _zip_check_torrentzip:
+   check wether ZA has a valid TORRENTZIP comment, i.e. is torrentzipped */
+
+static void
+_zip_check_torrentzip(struct zip *za)
+{
+    uLong crc_got, crc_should;
+    char buf[8+1];
+    char *end;
+
+    if (za->zp == NULL || za->cdir == NULL)
+        return;
+
+    if (za->cdir->comment_len != TORRENT_SIG_LEN+8
+        || strncmp(za->cdir->comment, TORRENT_SIG, TORRENT_SIG_LEN) != 0)
+        return;
+
+    memcpy(buf, za->cdir->comment+TORRENT_SIG_LEN, 8);
+    buf[8] = '\0';
+    errno = 0;
+    crc_should = strtoul(buf, &end, 16);
+    if ((crc_should == UINT_MAX && errno != 0) || (end && *end))
+        return;
+
+    if (_zip_filerange_crc(za->zp, za->cdir->offset, za->cdir->size,
+                           &crc_got, NULL) < 0)
+        return;
+
+    if (crc_got == crc_should)
+        za->flags |= ZIP_AFL_TORRENT;
+}
+
+
+
+
+/* _zip_headercomp:
+   compares two headers h1 and h2; if they are local headers, set
+   local1p or local2p respectively to 1, else 0. Return 0 if they
+   are identical, -1 if not. */
+
+static int
+_zip_headercomp(struct zip_dirent *h1, int local1p, struct zip_dirent *h2,
+           int local2p)
+{
+    if ((h1->version_needed != h2->version_needed)
+#if 0
+        /* some zip-files have different values in local
+           and global headers for the bitflags */
+        || (h1->bitflags != h2->bitflags)
+#endif
+        || (h1->comp_method != h2->comp_method)
+        || (h1->last_mod != h2->last_mod)
+        || (h1->filename_len != h2->filename_len)
+        || !h1->filename || !h2->filename
+        || strcmp(h1->filename, h2->filename))
+        return -1;
+
+    /* check that CRC and sizes are zero if data descriptor is used */
+    if ((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local1p
+        && (h1->crc != 0
+            || h1->comp_size != 0
+            || h1->uncomp_size != 0))
+        return -1;
+    if ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) && local2p
+        && (h2->crc != 0
+            || h2->comp_size != 0
+            || h2->uncomp_size != 0))
+        return -1;
+    
+    /* check that CRC and sizes are equal if no data descriptor is used */
+    if (((h1->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local1p == 0)
+        && ((h2->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0 || local2p == 0)) {
+        if ((h1->crc != h2->crc)
+            || (h1->comp_size != h2->comp_size)
+            || (h1->uncomp_size != h2->uncomp_size))
+            return -1;
+    }
+    
+    if ((local1p == local2p)
+        && ((h1->extrafield_len != h2->extrafield_len)
+            || (h1->extrafield_len && h2->extrafield
+                && memcmp(h1->extrafield, h2->extrafield,
+                          h1->extrafield_len))))
+        return -1;
+
+    /* if either is local, nothing more to check */
+    if (local1p || local2p)
+        return 0;
+
+    if ((h1->version_madeby != h2->version_madeby)
+        || (h1->disk_number != h2->disk_number)
+        || (h1->int_attrib != h2->int_attrib)
+        || (h1->ext_attrib != h2->ext_attrib)
+        || (h1->offset != h2->offset)
+        || (h1->comment_len != h2->comment_len)
+        || (h1->comment_len && h2->comment
+            && memcmp(h1->comment, h2->comment, h1->comment_len)))
+        return -1;
+
+    return 0;
+}
+
+
+
+static struct zip *
+_zip_allocate_new(const char *fn, int *zep)
+{
+    struct zip *za;
+    struct zip_error error;
+
+    if ((za=_zip_new(&error)) == NULL) {
+        set_error(zep, &error, 0);
+        return NULL;
+    }
+        
+    za->zn = strdup(fn);
+    if (!za->zn) {
+        _zip_free(za);
+        set_error(zep, NULL, ZIP_ER_MEMORY);
+        return NULL;
+    }
+    return za;
+}
+
+
+
+static int
+_zip_file_exists(const char *fn, int flags, int *zep)
+{
+    struct stat st;
+
+    if (fn == NULL) {
+        set_error(zep, NULL, ZIP_ER_INVAL);
+        return -1;
+    }
+    
+    if (stat(fn, &st) != 0) {
+        if (flags & ZIP_CREATE)
+            return 0;
+        else {
+            set_error(zep, NULL, ZIP_ER_OPEN);
+            return -1;
+        }
+    }
+    else if ((flags & ZIP_EXCL)) {
+        set_error(zep, NULL, ZIP_ER_EXISTS);
+        return -1;
+    }
+    /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL,
+       just like open() */
+
+    return 1;
+}
+
+
+
+static struct zip_cdir *
+_zip_find_central_dir(FILE *fp, int flags, int *zep, myoff_t len)
+{
+    struct zip_cdir *cdir, *cdirnew;
+    unsigned char *buf, *match;
+    int a, best, buflen, i;
+    struct zip_error zerr;
+
+    i = fseeko(fp, -(len < CDBUFSIZE ? len : CDBUFSIZE), SEEK_END);
+    if (i == -1 && errno != EFBIG) {
+        /* seek before start of file on my machine */
+        set_error(zep, NULL, ZIP_ER_SEEK);
+        return NULL;
+    }
+
+    /* 64k is too much for stack */
+    if ((buf=(unsigned char *)malloc(CDBUFSIZE)) == NULL) {
+        set_error(zep, NULL, ZIP_ER_MEMORY);
+        return NULL;
+    }
+
+    clearerr(fp);
+    buflen = fread(buf, 1, CDBUFSIZE, fp);
+
+    if (ferror(fp)) {
+        set_error(zep, NULL, ZIP_ER_READ);
+        free(buf);
+        return NULL;
+    }
+    
+    best = -1;
+    cdir = NULL;
+    match = buf;
+    _zip_error_set(&zerr, ZIP_ER_NOZIP, 0);
+
+    while ((match=_zip_memmem(match, buflen-(match-buf)-18,
+                              (const unsigned char *)EOCD_MAGIC, 4))!=NULL) {
+        /* found match -- check, if good */
+        /* to avoid finding the same match all over again */
+        match++;
+        if ((cdirnew=_zip_readcdir(fp, buf, match-1, buflen, flags,
+                                   &zerr)) == NULL)
+            continue;
+
+        if (cdir) {
+            if (best <= 0)
+                best = _zip_checkcons(fp, cdir, &zerr);
+            a = _zip_checkcons(fp, cdirnew, &zerr);
+            if (best < a) {
+                _zip_cdir_free(cdir);
+                cdir = cdirnew;
+                best = a;
+            }
+            else
+                _zip_cdir_free(cdirnew);
+        }
+        else {
+            cdir = cdirnew;
+            if (flags & ZIP_CHECKCONS)
+                best = _zip_checkcons(fp, cdir, &zerr);
+            else
+                best = 0;
+        }
+        cdirnew = NULL;
+    }
+
+    free(buf);
+    
+    if (best < 0) {
+        set_error(zep, &zerr, 0);
+        _zip_cdir_free(cdir);
+        return NULL;
+    }
+
+    return cdir;
+}
+
+
+
+static unsigned char *
+_zip_memmem(const unsigned char *big, int biglen, const unsigned char *little, 
+       int littlelen)
+{
+    const unsigned char *p;
+    
+    if ((biglen < littlelen) || (littlelen == 0))
+        return NULL;
+    p = big-1;
+    while ((p=(const unsigned char *)
+                memchr(p+1, little[0], (size_t)(big-(p+1)+biglen-littlelen+1)))
+           != NULL) {
+        if (memcmp(p+1, little+1, littlelen-1)==0)
+            return (unsigned char *)p;
+    }
+
+    return NULL;
+}
+
+
+/* _zip_new:
+   creates a new zipfile struct, and sets the contents to zero; returns
+   the new struct. */
+
+struct zip *
+_zip_new(struct zip_error *error)
+{
+    struct zip *za;
+
+    za = (struct zip *)malloc(sizeof(struct zip));
+    if (!za) {
+        _zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    za->zn = NULL;
+    za->zp = NULL;
+    _zip_error_init(&za->error);
+    za->cdir = NULL;
+    za->ch_comment = NULL;
+    za->ch_comment_len = -1;
+    za->nentry = za->nentry_alloc = 0;
+    za->entry = NULL;
+    za->nfile = za->nfile_alloc = 0;
+    za->file = NULL;
+    za->flags = za->ch_flags = 0;
+    
+    return za;
+}
+
+
+void *
+_zip_memdup(const void *mem, size_t len, struct zip_error *error)
+{
+    void *ret;
+
+    ret = malloc(len);
+    if (!ret) {
+        _zip_error_set(error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    memcpy(ret, mem, len);
+
+    return ret;
+}
+
+
+ZIP_EXTERN int
+zip_get_num_files(struct zip *za)
+{
+    if (za == NULL)
+        return -1;
+
+    return za->nentry;
+}
+
+ZIP_EXTERN const char *
+zip_get_name(struct zip *za, int idx, int flags)
+{
+    return _zip_get_name(za, idx, flags, &za->error);
+}
+
+
+
+const char *
+_zip_get_name(struct zip *za, int idx, int flags, struct zip_error *error)
+{
+    if (idx < 0 || idx >= za->nentry) {
+        _zip_error_set(error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    if ((flags & ZIP_FL_UNCHANGED) == 0) {
+        if (za->entry[idx].state == ZIP_ST_DELETED) {
+            _zip_error_set(error, ZIP_ER_DELETED, 0);
+            return NULL;
+        }
+        if (za->entry[idx].ch_filename)
+            return za->entry[idx].ch_filename;
+    }
+
+    if (za->cdir == NULL || idx >= za->cdir->nentry) {
+        _zip_error_set(error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+    
+    return za->cdir->entry[idx].filename;
+}
+
+
+ZIP_EXTERN const char *
+zip_get_file_comment(struct zip *za, int idx, int *lenp, int flags)
+{
+    if (idx < 0 || idx >= za->nentry) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    if ((flags & ZIP_FL_UNCHANGED)
+        || (za->entry[idx].ch_comment_len == -1)) {
+        if (lenp != NULL)
+            *lenp = za->cdir->entry[idx].comment_len;
+        return za->cdir->entry[idx].comment;
+    }
+    
+    if (lenp != NULL)
+        *lenp = za->entry[idx].ch_comment_len;
+    return za->entry[idx].ch_comment;
+}
+
+
+ZIP_EXTERN int
+zip_get_archive_flag(struct zip *za, int flag, int flags)
+{
+    int fl;
+
+    fl = (flags & ZIP_FL_UNCHANGED) ? za->flags : za->ch_flags;
+
+    return (fl & flag) ? 1 : 0;
+}
+
+
+ZIP_EXTERN const char *
+zip_get_archive_comment(struct zip *za, int *lenp, int flags)
+{
+    if ((flags & ZIP_FL_UNCHANGED)
+        || (za->ch_comment_len == -1)) {
+        if (za->cdir) {
+            if (lenp != NULL)
+                *lenp = za->cdir->comment_len;
+            return za->cdir->comment;
+        }
+        else {
+            if (lenp != NULL)
+                *lenp = -1;
+            return NULL;
+        }
+    }
+    
+    if (lenp != NULL)
+        *lenp = za->ch_comment_len;
+    return za->ch_comment;
+}
+
+
+/* _zip_free:
+   frees the space allocated to a zipfile struct, and closes the
+   corresponding file. */
+
+void
+_zip_free(struct zip *za)
+{
+    int i;
+
+    if (za == NULL)
+        return;
+
+    if (za->zn)
+        free(za->zn);
+
+    if (za->zp)
+        fclose(za->zp);
+
+    _zip_cdir_free(za->cdir);
+
+    if (za->entry) {
+        for (i=0; i<za->nentry; i++) {
+            _zip_entry_free(za->entry+i);
+        }
+        free(za->entry);
+    }
+
+    for (i=0; i<za->nfile; i++) {
+        if (za->file[i]->error.zip_err == ZIP_ER_OK) {
+            _zip_error_set(&za->file[i]->error, ZIP_ER_ZIPCLOSED, 0);
+            za->file[i]->za = NULL;
+        }
+    }
+
+    free(za->file);
+    
+    free(za);
+
+    return;
+}
+
+
+ZIP_EXTERN ssize_t
+zip_fread(struct zip_file *zf, void *outbuf, size_t toread)
+{
+    int ret;
+    size_t out_before, len;
+    int i;
+
+    if (!zf)
+        return -1;
+
+    if (zf->error.zip_err != 0)
+        return -1;
+
+    if ((zf->flags & ZIP_ZF_EOF) || (toread == 0))
+        return 0;
+
+    if (zf->bytes_left == 0) {
+        zf->flags |= ZIP_ZF_EOF;
+        if (zf->flags & ZIP_ZF_CRC) {
+            if (zf->crc != zf->crc_orig) {
+                _zip_error_set(&zf->error, ZIP_ER_CRC, 0);
+                return -1;
+            }
+        }
+        return 0;
+    }
+    
+    if ((zf->flags & ZIP_ZF_DECOMP) == 0) {
+        ret = _zip_file_fillbuf(outbuf, toread, zf);
+        if (ret > 0) {
+            if (zf->flags & ZIP_ZF_CRC)
+                zf->crc = crc32(zf->crc, (Bytef *)outbuf, ret);
+            zf->bytes_left -= ret;
+        }
+        return ret;
+    }
+    
+    zf->zstr->next_out = (Bytef *)outbuf;
+    zf->zstr->avail_out = toread;
+    out_before = zf->zstr->total_out;
+    
+    /* endless loop until something has been accomplished */
+    for (;;) {
+        ret = inflate(zf->zstr, Z_SYNC_FLUSH);
+
+        switch (ret) {
+        case Z_OK:
+        case Z_STREAM_END:
+            /* all ok */
+            /* Z_STREAM_END probably won't happen, since we didn't
+               have a header */
+            len = zf->zstr->total_out - out_before;
+            if (len >= zf->bytes_left || len >= toread) {
+                if (zf->flags & ZIP_ZF_CRC)
+                    zf->crc = crc32(zf->crc, (Bytef *)outbuf, len);
+                zf->bytes_left -= len;
+                return len;
+            }
+            break;
+
+        case Z_BUF_ERROR:
+            if (zf->zstr->avail_in == 0) {
+                i = _zip_file_fillbuf(zf->buffer, BUFSIZE, zf);
+                if (i == 0) {
+                    _zip_error_set(&zf->error, ZIP_ER_INCONS, 0);
+                    return -1;
+                }
+                else if (i < 0)
+                    return -1;
+                zf->zstr->next_in = (Bytef *)zf->buffer;
+                zf->zstr->avail_in = i;
+                continue;
+            }
+            /* fallthrough */
+        case Z_NEED_DICT:
+        case Z_DATA_ERROR:
+        case Z_STREAM_ERROR:
+        case Z_MEM_ERROR:
+            _zip_error_set(&zf->error, ZIP_ER_ZLIB, ret);
+            return -1;
+        }
+    }
+}
+
+
+ZIP_EXTERN const char *
+zip_strerror(struct zip *za)
+{
+    return _zip_error_strerror(&za->error);
+}
+
+
+ZIP_EXTERN void
+zip_stat_init(struct zip_stat *st)
+{
+    st->name = NULL;
+    st->index = -1;
+    st->crc = 0;
+    st->mtime = (time_t)-1;
+    st->size = -1;
+    st->comp_size = -1;
+    st->comp_method = ZIP_CM_STORE;
+    st->encryption_method = ZIP_EM_NONE;
+}
+
+
+ZIP_EXTERN int
+zip_stat_index(struct zip *za, int index, int flags, struct zip_stat *st)
+{
+    const char *name;
+    
+    if (index < 0 || index >= za->nentry) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+
+    if ((name=zip_get_name(za, index, flags)) == NULL)
+        return -1;
+    
+
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+        && ZIP_ENTRY_DATA_CHANGED(za->entry+index)) {
+        if (za->entry[index].source->f(za->entry[index].source->ud,
+                                     st, sizeof(*st), ZIP_SOURCE_STAT) < 0) {
+            _zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
+            return -1;
+        }
+    }
+    else {
+        if (za->cdir == NULL || index >= za->cdir->nentry) {
+            _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+            return -1;
+        }
+        
+        st->crc = za->cdir->entry[index].crc;
+        st->size = za->cdir->entry[index].uncomp_size;
+        st->mtime = za->cdir->entry[index].last_mod;
+        st->comp_size = za->cdir->entry[index].comp_size;
+        st->comp_method = za->cdir->entry[index].comp_method;
+        if (za->cdir->entry[index].bitflags & ZIP_GPBF_ENCRYPTED) {
+            if (za->cdir->entry[index].bitflags & ZIP_GPBF_STRONG_ENCRYPTION) {
+                /* XXX */
+                st->encryption_method = ZIP_EM_UNKNOWN;
+            }
+            else
+                st->encryption_method = ZIP_EM_TRAD_PKWARE;
+        }
+        else
+            st->encryption_method = ZIP_EM_NONE;
+        /* st->bitflags = za->cdir->entry[index].bitflags; */
+    }
+
+    st->index = index;
+    st->name = name;
+    
+    return 0;
+}
+
+
+ZIP_EXTERN int
+zip_stat(struct zip *za, const char *fname, int flags, struct zip_stat *st)
+{
+    int idx;
+
+    if ((idx=zip_name_locate(za, fname, flags)) < 0)
+        return -1;
+
+    return zip_stat_index(za, idx, flags, st);
+}
+
+
+struct read_zip {
+    struct zip_file *zf;
+    struct zip_stat st;
+    myoff_t off, len;
+};
+
+static ssize_t read_zip(void *st, void *data, size_t len,
+                        enum zip_source_cmd cmd);
+
+
+
+ZIP_EXTERN struct zip_source *
+zip_source_zip(struct zip *za, struct zip *srcza, int srcidx, int flags,
+               myoff_t start, myoff_t len)
+{
+    struct zip_error error;
+    struct zip_source *zs;
+    struct read_zip *p;
+
+    /* XXX: ZIP_FL_RECOMPRESS */
+
+    if (za == NULL)
+        return NULL;
+
+    if (srcza == NULL || start < 0 || len < -1 || srcidx < 0 || srcidx >= srcza->nentry) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    if ((flags & ZIP_FL_UNCHANGED) == 0
+        && ZIP_ENTRY_DATA_CHANGED(srcza->entry+srcidx)) {
+        _zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
+        return NULL;
+    }
+
+    if (len == 0)
+        len = -1;
+
+    if (start == 0 && len == -1 && (flags & ZIP_FL_RECOMPRESS) == 0)
+        flags |= ZIP_FL_COMPRESSED;
+    else
+        flags &= ~ZIP_FL_COMPRESSED;
+
+    if ((p=(struct read_zip *)malloc(sizeof(*p))) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+        
+    _zip_error_copy(&error, &srcza->error);
+        
+    if (zip_stat_index(srcza, srcidx, flags, &p->st) < 0
+        || (p->zf=zip_fopen_index(srcza, srcidx, flags)) == NULL) {
+        free(p);
+        _zip_error_copy(&za->error, &srcza->error);
+        _zip_error_copy(&srcza->error, &error);
+        
+        return NULL;
+    }
+    p->off = start;
+    p->len = len;
+
+    if ((flags & ZIP_FL_COMPRESSED) == 0) {
+        p->st.size = p->st.comp_size = len;
+        p->st.comp_method = ZIP_CM_STORE;
+        p->st.crc = 0;
+    }
+    
+    if ((zs=zip_source_function(za, read_zip, p)) == NULL) {
+        free(p);
+        return NULL;
+    }
+
+    return zs;
+}
+
+
+
+static ssize_t
+read_zip(void *state, void *data, size_t len, enum zip_source_cmd cmd)
+{
+    struct read_zip *z;
+    char b[8192], *buf;
+    int i, n;
+
+    z = (struct read_zip *)state;
+    buf = (char *)data;
+
+    switch (cmd) {
+    case ZIP_SOURCE_OPEN:
+        for (n=0; n<z->off; n+= i) {
+            i = (z->off-n > sizeof(b) ? sizeof(b) : z->off-n);
+            if ((i=zip_fread(z->zf, b, i)) < 0) {
+                zip_fclose(z->zf);
+                z->zf = NULL;
+                return -1;
+            }
+        }
+        return 0;
+        
+    case ZIP_SOURCE_READ:
+        if (z->len != -1)
+            n = len > z->len ? z->len : len;
+        else
+            n = len;
+        
+
+        if ((i=zip_fread(z->zf, buf, n)) < 0)
+            return -1;
+
+        if (z->len != -1)
+            z->len -= i;
+
+        return i;
+        
+    case ZIP_SOURCE_CLOSE:
+        return 0;
+
+    case ZIP_SOURCE_STAT:
+        if (len < sizeof(z->st))
+            return -1;
+        len = sizeof(z->st);
+
+        memcpy(data, &z->st, len);
+        return len;
+
+    case ZIP_SOURCE_ERROR:
+        {
+            int *e;
+
+            if (len < sizeof(int)*2)
+                return -1;
+
+            e = (int *)data;
+            zip_file_error_get(z->zf, e, e+1);
+        }
+        return sizeof(int)*2;
+
+    case ZIP_SOURCE_FREE:
+        zip_fclose(z->zf);
+        free(z);
+        return 0;
+
+    default:
+        ;
+    }
+
+    return -1;
+}
+
+
+ZIP_EXTERN struct zip_source *
+zip_source_function(struct zip *za, zip_source_callback zcb, void *ud)
+{
+    struct zip_source *zs;
+
+    if (za == NULL)
+        return NULL;
+
+    if ((zs=(struct zip_source *)malloc(sizeof(*zs))) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    zs->f = zcb;
+    zs->ud = ud;
+    
+    return zs;
+}
+
+
+ZIP_EXTERN void
+zip_source_free(struct zip_source *source)
+{
+    if (source == NULL)
+        return;
+
+    (void)source->f(source->ud, NULL, 0, ZIP_SOURCE_FREE);
+
+    free(source);
+}
+
+
+struct read_file {
+    char *fname;        /* name of file to copy from */
+    FILE *f;                /* file to copy from */
+    myoff_t off;                /* start offset of */
+    myoff_t len;                /* lengt of data to copy */
+    myoff_t remain;        /* bytes remaining to be copied */
+    int e[2];                /* error codes */
+};
+
+static ssize_t read_file(void *state, void *data, size_t len,
+                     enum zip_source_cmd cmd);
+
+
+
+ZIP_EXTERN struct zip_source *
+zip_source_filep(struct zip *za, FILE *file, myoff_t start, myoff_t len)
+{
+    if (za == NULL)
+        return NULL;
+
+    if (file == NULL || start < 0 || len < -1) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    return _zip_source_file_or_p(za, NULL, file, start, len);
+}
+
+
+
+struct zip_source *
+_zip_source_file_or_p(struct zip *za, const char *fname, FILE *file,
+                      myoff_t start, myoff_t len)
+{
+    struct read_file *f;
+    struct zip_source *zs;
+
+    if (file == NULL && fname == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_INVAL, 0);
+        return NULL;
+    }
+
+    if ((f=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
+        _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+        return NULL;
+    }
+
+    f->fname = NULL;
+    if (fname) {
+        if ((f->fname=strdup(fname)) == NULL) {
+            _zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
+            free(f);
+            return NULL;
+        }
+    }
+    f->f = file;
+    f->off = start;
+    f->len = (len ? len : -1);
+    
+    if ((zs=zip_source_function(za, read_file, f)) == NULL) {
+        free(f);
+        return NULL;
+    }
+
+    return zs;
+}
+
+
+
+static ssize_t
+read_file(void *state, void *data, size_t len, enum zip_source_cmd cmd)
+{
+    struct read_file *z;
+    char *buf;
+    int i, n;
+
+    z = (struct read_file *)state;
+    buf = (char *)data;
+
+    switch (cmd) {
+    case ZIP_SOURCE_OPEN:
+        if (z->fname) {
+            if ((z->f=fopen(z->fname, "rb")) == NULL) {
+                z->e[0] = ZIP_ER_OPEN;
+                z->e[1] = errno;
+                return -1;
+            }
+        }
+
+        if (fseeko(z->f, z->off, SEEK_SET) < 0) {
+            z->e[0] = ZIP_ER_SEEK;
+            z->e[1] = errno;
+            return -1;
+        }
+        z->remain = z->len;
+        return 0;
+        
+    case ZIP_SOURCE_READ:
+        if (z->remain != -1)
+            n = len > z->remain ? z->remain : len;
+        else
+            n = len;
+        
+        if ((i=fread(buf, 1, n, z->f)) < 0) {
+            z->e[0] = ZIP_ER_READ;
+            z->e[1] = errno;
+            return -1;
+        }
+
+        if (z->remain != -1)
+            z->remain -= i;
+
+        return i;
+        
+    case ZIP_SOURCE_CLOSE:
+        if (z->fname) {
+            fclose(z->f);
+            z->f = NULL;
+        }
+        return 0;
+
+    case ZIP_SOURCE_STAT:
+        {
+            struct zip_stat *st;
+            struct stat fst;
+            int err;
+            
+            if (len < sizeof(*st))
+                return -1;
+
+            if (z->f)
+                err = fstat(fileno(z->f), &fst);
+            else
+                err = stat(z->fname, &fst);
+
+            if (err != 0) {
+                z->e[0] = ZIP_ER_READ; /* best match */
+                z->e[1] = errno;
+                return -1;
+            }
+
+            st = (struct zip_stat *)data;
+
+            zip_stat_init(st);
+            st->mtime = fst.st_mtime;
+            if (z->len != -1)
+                st->size = z->len;
+            else if ((fst.st_mode&S_IFMT) == S_IFREG)
+                st->size = fst.st_size;
+
+            return sizeof(*st);
+        }
+
+    case ZIP_SOURCE_ERROR:
+        if (len < sizeof(int)*2)
+            return -1;
+
+        memcpy(data, z->e, sizeof(int)*2);
+        return sizeof(int)*2;
+
+    case ZIP_SOURCE_FREE:
+        free(z->fname);
+        if (z->f)
+            fclose(z->f);
+        free(z);
+        return 0;
+
+    default:
+        ;
+    }
+
+    return -1;
+}
+
+
+ZIP_EXTERN int
+zip_name_locate(struct zip *za, const char *fname, int flags)
+{
+    return _zip_name_locate(za, fname, flags, &za->error);
+}
+
+
+
+int
+_zip_name_locate(struct zip *za, const char *fname, int flags,
+                 struct zip_error *error)
+{
+    int (*cmp)(const char *, const char *);
+    const char *fn, *p;
+    int i, n;
+
+    if (fname == NULL) {
+        _zip_error_set(error, ZIP_ER_INVAL, 0);
+        return -1;
+    }
+    
+    cmp = (flags & ZIP_FL_NOCASE) ? strcasecmp : strcmp;
+
+    n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry;
+    for (i=0; i<n; i++) {
+        if (flags & ZIP_FL_UNCHANGED)
+            fn = za->cdir->entry[i].filename;
+        else
+            fn = _zip_get_name(za, i, flags, error);
+
+        /* newly added (partially filled) entry */
+        if (fn == NULL)
+            continue;
+        
+        if (flags & ZIP_FL_NODIR) {
+            p = strrchr(fn, '/');
+            if (p)
+                fn = p+1;
+        }
+
+        if (cmp(fname, fn) == 0)
+            return i;
+    }
+
+    _zip_error_set(error, ZIP_ER_NOENT, 0);
+    return -1;
+}
+
diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim
new file mode 100644
index 000000000..8bdb47106
--- /dev/null
+++ b/lib/wrappers/zip/zlib.nim
@@ -0,0 +1,310 @@
+# Converted from Pascal
+
+## Interface to the zlib http://www.zlib.net/ compression library.
+
+when defined(windows):
+  const libz = "zlib1.dll"
+elif defined(macosx):
+  const libz = "libz.dylib"
+else:
+  const libz = "libz.so.1"
+
+type
+  Uint* = int32
+  Ulong* = int
+  Ulongf* = int
+  Pulongf* = ptr Ulongf
+  ZOffT* = int32
+  Pbyte* = cstring
+  Pbytef* = cstring
+  TAllocfunc* = proc (p: pointer, items: Uint, size: Uint): pointer{.cdecl.}
+  TFreeFunc* = proc (p: pointer, address: pointer){.cdecl.}
+  TInternalState*{.final, pure.} = object 
+  PInternalState* = ptr TInternalState
+  TZStream*{.final, pure.} = object 
+    nextIn*: Pbytef
+    availIn*: Uint
+    totalIn*: Ulong
+    nextOut*: Pbytef
+    availOut*: Uint
+    totalOut*: Ulong
+    msg*: Pbytef
+    state*: PInternalState
+    zalloc*: TAllocfunc
+    zfree*: TFreeFunc
+    opaque*: pointer
+    dataType*: int32
+    adler*: Ulong
+    reserved*: Ulong
+
+  TZStreamRec* = TZStream
+  PZstream* = ptr TZStream
+  GzFile* = pointer
+
+const 
+  Z_NO_FLUSH* = 0
+  Z_PARTIAL_FLUSH* = 1
+  Z_SYNC_FLUSH* = 2
+  Z_FULL_FLUSH* = 3
+  Z_FINISH* = 4
+  Z_OK* = 0
+  Z_STREAM_END* = 1
+  Z_NEED_DICT* = 2
+  Z_ERRNO* = -1
+  Z_STREAM_ERROR* = -2
+  Z_DATA_ERROR* = -3
+  Z_MEM_ERROR* = -4
+  Z_BUF_ERROR* = -5
+  Z_VERSION_ERROR* = -6
+  Z_NO_COMPRESSION* = 0
+  Z_BEST_SPEED* = 1
+  Z_BEST_COMPRESSION* = 9
+  Z_DEFAULT_COMPRESSION* = -1
+  Z_FILTERED* = 1
+  Z_HUFFMAN_ONLY* = 2
+  Z_DEFAULT_STRATEGY* = 0
+  Z_BINARY* = 0
+  Z_ASCII* = 1
+  Z_UNKNOWN* = 2
+  Z_DEFLATED* = 8
+  Z_NULL* = 0
+
+proc zlibVersion*(): cstring{.cdecl, dynlib: libz, importc: "zlibVersion".}
+proc deflate*(strm: var TZStream, flush: int32): int32{.cdecl, dynlib: libz, 
+    importc: "deflate".}
+proc deflateEnd*(strm: var TZStream): int32{.cdecl, dynlib: libz, 
+    importc: "deflateEnd".}
+proc inflate*(strm: var TZStream, flush: int32): int32{.cdecl, dynlib: libz, 
+    importc: "inflate".}
+proc inflateEnd*(strm: var TZStream): int32{.cdecl, dynlib: libz, 
+    importc: "inflateEnd".}
+proc deflateSetDictionary*(strm: var TZStream, dictionary: Pbytef, 
+                           dictLength: Uint): int32{.cdecl, dynlib: libz, 
+    importc: "deflateSetDictionary".}
+proc deflateCopy*(dest, source: var TZStream): int32{.cdecl, dynlib: libz, 
+    importc: "deflateCopy".}
+proc deflateReset*(strm: var TZStream): int32{.cdecl, dynlib: libz, 
+    importc: "deflateReset".}
+proc deflateParams*(strm: var TZStream, level: int32, strategy: int32): int32{.
+    cdecl, dynlib: libz, importc: "deflateParams".}
+proc inflateSetDictionary*(strm: var TZStream, dictionary: Pbytef, 
+                           dictLength: Uint): int32{.cdecl, dynlib: libz, 
+    importc: "inflateSetDictionary".}
+proc inflateSync*(strm: var TZStream): int32{.cdecl, dynlib: libz, 
+    importc: "inflateSync".}
+proc inflateReset*(strm: var TZStream): int32{.cdecl, dynlib: libz, 
+    importc: "inflateReset".}
+proc compress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, sourceLen: Ulong): cint{.
+    cdecl, dynlib: libz, importc: "compress".}
+proc compress2*(dest: Pbytef, destLen: Pulongf, source: Pbytef, 
+                sourceLen: Ulong, level: cint): cint{.cdecl, dynlib: libz, 
+    importc: "compress2".}
+proc uncompress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, 
+                 sourceLen: Ulong): cint{.cdecl, dynlib: libz, 
+    importc: "uncompress".}
+proc compressBound*(sourceLen: Ulong): Ulong {.cdecl, dynlib: libz, importc.}
+proc gzopen*(path: cstring, mode: cstring): GzFile{.cdecl, dynlib: libz, 
+    importc: "gzopen".}
+proc gzdopen*(fd: int32, mode: cstring): GzFile{.cdecl, dynlib: libz, 
+    importc: "gzdopen".}
+proc gzsetparams*(thefile: GzFile, level: int32, strategy: int32): int32{.cdecl, 
+    dynlib: libz, importc: "gzsetparams".}
+proc gzread*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, 
+    dynlib: libz, importc: "gzread".}
+proc gzwrite*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, 
+    dynlib: libz, importc: "gzwrite".}
+proc gzprintf*(thefile: GzFile, format: Pbytef): int32{.varargs, cdecl, 
+    dynlib: libz, importc: "gzprintf".}
+proc gzputs*(thefile: GzFile, s: Pbytef): int32{.cdecl, dynlib: libz, 
+    importc: "gzputs".}
+proc gzgets*(thefile: GzFile, buf: Pbytef, length: int32): Pbytef{.cdecl, 
+    dynlib: libz, importc: "gzgets".}
+proc gzputc*(thefile: GzFile, c: char): char{.cdecl, dynlib: libz, 
+    importc: "gzputc".}
+proc gzgetc*(thefile: GzFile): char{.cdecl, dynlib: libz, importc: "gzgetc".}
+proc gzflush*(thefile: GzFile, flush: int32): int32{.cdecl, dynlib: libz, 
+    importc: "gzflush".}
+proc gzseek*(thefile: GzFile, offset: ZOffT, whence: int32): ZOffT{.cdecl, 
+    dynlib: libz, importc: "gzseek".}
+proc gzrewind*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzrewind".}
+proc gztell*(thefile: GzFile): ZOffT{.cdecl, dynlib: libz, importc: "gztell".}
+proc gzeof*(thefile: GzFile): int {.cdecl, dynlib: libz, importc: "gzeof".}
+proc gzclose*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzclose".}
+proc gzerror*(thefile: GzFile, errnum: var int32): Pbytef{.cdecl, dynlib: libz, 
+    importc: "gzerror".}
+proc adler32*(adler: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, 
+    dynlib: libz, importc: "adler32".}
+  ## **Warning**: Adler-32 requires at least a few hundred bytes to get rolling.
+proc crc32*(crc: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, dynlib: libz, 
+    importc: "crc32".}
+proc deflateInitu*(strm: var TZStream, level: int32, version: cstring, 
+                   streamSize: int32): int32{.cdecl, dynlib: libz, 
+    importc: "deflateInit_".}
+proc inflateInitu*(strm: var TZStream, version: cstring,
+                   streamSize: int32): int32 {.
+    cdecl, dynlib: libz, importc: "inflateInit_".}
+proc deflateInit*(strm: var TZStream, level: int32): int32
+proc inflateInit*(strm: var TZStream): int32
+proc deflateInit2u*(strm: var TZStream, level: int32, `method`: int32, 
+                    windowBits: int32, memLevel: int32, strategy: int32, 
+                    version: cstring, streamSize: int32): int32 {.cdecl, 
+                    dynlib: libz, importc: "deflateInit2_".}
+proc inflateInit2u*(strm: var TZStream, windowBits: int32, version: cstring, 
+                    streamSize: int32): int32{.cdecl, dynlib: libz, 
+    importc: "inflateInit2_".}
+proc deflateInit2*(strm: var TZStream, 
+                   level, `method`, windowBits, memLevel,
+                   strategy: int32): int32
+proc inflateInit2*(strm: var TZStream, windowBits: int32): int32
+proc zError*(err: int32): cstring{.cdecl, dynlib: libz, importc: "zError".}
+proc inflateSyncPoint*(z: PZstream): int32{.cdecl, dynlib: libz, 
+    importc: "inflateSyncPoint".}
+proc getCrcTable*(): pointer{.cdecl, dynlib: libz, importc: "get_crc_table".}
+
+proc deflateInit(strm: var TZStream, level: int32): int32 = 
+  result = deflateInitu(strm, level, zlibVersion(), sizeof(TZStream).cint)
+
+proc inflateInit(strm: var TZStream): int32 = 
+  result = inflateInitu(strm, zlibVersion(), sizeof(TZStream).cint)
+
+proc deflateInit2(strm: var TZStream, 
+                  level, `method`, windowBits, memLevel,
+                  strategy: int32): int32 = 
+  result = deflateInit2u(strm, level, `method`, windowBits, memLevel, 
+                         strategy, zlibVersion(), sizeof(TZStream).cint)
+
+proc inflateInit2(strm: var TZStream, windowBits: int32): int32 = 
+  result = inflateInit2u(strm, windowBits, zlibVersion(), 
+                         sizeof(TZStream).cint)
+
+proc zlibAllocMem*(appData: pointer, items, size: int): pointer {.cdecl.} = 
+  result = alloc(items * size)
+
+proc zlibFreeMem*(appData, `block`: pointer) {.cdecl.} = 
+  dealloc(`block`)
+
+proc uncompress*(sourceBuf: cstring, sourceLen: int): string =
+  ## Given a deflated cstring returns its inflated version.
+  ##
+  ## Passing a nil cstring will crash this proc in release mode and assert in
+  ## debug mode.
+  ##
+  ## Returns nil on problems. Failure is a very loose concept, it could be you
+  ## passing a non deflated string, or it could mean not having enough memory
+  ## for the inflated version.
+  ##
+  ## The uncompression algorithm is based on
+  ## http://stackoverflow.com/questions/17820664 but does ignore some of the
+  ## original signed/unsigned checks, so may fail with big chunks of data
+  ## exceeding the positive size of an int32. The algorithm can deal with
+  ## concatenated deflated values properly.
+  assert (not sourceBuf.isNil)
+
+  var z: TZStream
+  # Initialize input.
+  z.nextIn = sourceBuf
+
+  # Input left to decompress.
+  var left = zlib.Uint(sourceLen)
+  if left < 1:
+    # Incomplete gzip stream, or overflow?
+    return
+
+  # Create starting space for output (guess double the input size, will grow if
+  # needed -- in an extreme case, could end up needing more than 1000 times the
+  # input size)
+  var space = zlib.Uint(left shl 1)
+  if space < left:
+    space = left
+
+  var decompressed = newStringOfCap(space)
+
+  # Initialize output.
+  z.nextOut = addr(decompressed[0])
+  # Output generated so far.
+  var have = 0
+
+  # Set up for gzip decoding.
+  z.availIn = 0;
+  var status = inflateInit2(z, (15+16))
+  if status != Z_OK:
+    # Out of memory.
+    return
+
+  # Make sure memory allocated by inflateInit2() is freed eventually.
+  defer: discard inflateEnd(z)
+
+  # Decompress all of self.
+  while true:
+    # Allow for concatenated gzip streams (per RFC 1952).
+    if status == Z_STREAM_END:
+      discard inflateReset(z)
+
+    # Provide input for inflate.
+    if z.availIn == 0:
+      # This only makes sense in the C version using unsigned values.
+      z.availIn = left
+      left -= z.availIn
+
+    # Decompress the available input.
+    while true:
+      # Allocate more output space if none left.
+      if space == have:
+        # Double space, handle overflow.
+        space = space shl 1
+        if space < have:
+          # Space was likely already maxed out.
+          discard inflateEnd(z)
+          return
+
+        # Increase space.
+        decompressed.setLen(space)
+        # Update output pointer (might have moved).
+        z.nextOut = addr(decompressed[have])
+
+      # Provide output space for inflate.
+      z.availOut = zlib.Uint(space - have)
+      have += z.availOut;
+
+      # Inflate and update the decompressed size.
+      status = inflate(z, Z_SYNC_FLUSH);
+      have -= z.availOut;
+
+      # Bail out if any errors.
+      if status != Z_OK and status != Z_BUF_ERROR and status != Z_STREAM_END:
+        # Invalid gzip stream.
+        discard inflateEnd(z)
+        return
+
+      # Repeat until all output is generated from provided input (note
+      # that even if z.avail_in is zero, there may still be pending
+      # output -- we're not done until the output buffer isn't filled)
+      if z.availOut != 0:
+        break
+    # Continue until all input consumed.
+    if left == 0 and z.availIn == 0:
+      break
+
+  # Verify that the input is a valid gzip stream.
+  if status != Z_STREAM_END:
+    # Incomplete gzip stream.
+    return
+
+  decompressed.setLen(have)
+  swap(result, decompressed)
+
+
+proc inflate*(buffer: var string): bool {.discardable.} =
+  ## Convenience proc which inflates a string containing compressed data.
+  ##
+  ## Passing a nil string will crash this proc in release mode and assert in
+  ## debug mode. It is ok to pass a buffer which doesn't contain deflated data,
+  ## in this case the proc won't modify the buffer.
+  ##
+  ## Returns true if `buffer` was successfully inflated.
+  assert (not buffer.isNil)
+  if buffer.len < 1: return
+  var temp = uncompress(addr(buffer[0]), buffer.len)
+  if not temp.isNil:
+    swap(buffer, temp)
+    result = true
diff --git a/lib/wrappers/zip/zzip.nim b/lib/wrappers/zip/zzip.nim
new file mode 100644
index 000000000..73fd53c34
--- /dev/null
+++ b/lib/wrappers/zip/zzip.nim
@@ -0,0 +1,172 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2008 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module is an interface to the zzip library. 
+
+#   Author: 
+#   Guido Draheim <guidod@gmx.de>
+#   Tomi Ollila <Tomi.Ollila@iki.fi>
+#   Copyright (c) 1999,2000,2001,2002,2003,2004 Guido Draheim
+#          All rights reserved, 
+#             usage allowed under the restrictions of the
+#         Lesser GNU General Public License 
+#             or alternatively the restrictions 
+#             of the Mozilla Public License 1.1
+
+when defined(windows):
+  const
+    dllname = "zzip.dll"
+else:
+  const 
+    dllname = "libzzip.so"
+
+type 
+  TZZipError* = int32
+const
+  ZZIP_ERROR* = -4096'i32
+  ZZIP_NO_ERROR* = 0'i32            # no error, may be used if user sets it.
+  ZZIP_OUTOFMEM* = ZZIP_ERROR - 20'i32  # out of memory  
+  ZZIP_DIR_OPEN* = ZZIP_ERROR - 21'i32  # failed to open zipfile, see errno for details 
+  ZZIP_DIR_STAT* = ZZIP_ERROR - 22'i32  # failed to fstat zipfile, see errno for details
+  ZZIP_DIR_SEEK* = ZZIP_ERROR - 23'i32  # failed to lseek zipfile, see errno for details
+  ZZIP_DIR_READ* = ZZIP_ERROR - 24'i32  # failed to read zipfile, see errno for details  
+  ZZIP_DIR_TOO_SHORT* = ZZIP_ERROR - 25'i32
+  ZZIP_DIR_EDH_MISSING* = ZZIP_ERROR - 26'i32
+  ZZIP_DIRSIZE* = ZZIP_ERROR - 27'i32
+  ZZIP_ENOENT* = ZZIP_ERROR - 28'i32
+  ZZIP_UNSUPP_COMPR* = ZZIP_ERROR - 29'i32
+  ZZIP_CORRUPTED* = ZZIP_ERROR - 31'i32
+  ZZIP_UNDEF* = ZZIP_ERROR - 32'i32
+  ZZIP_DIR_LARGEFILE* = ZZIP_ERROR - 33'i32
+
+  ZZIP_CASELESS* = 1'i32 shl 12'i32
+  ZZIP_NOPATHS* = 1'i32 shl 13'i32
+  ZZIP_PREFERZIP* = 1'i32 shl 14'i32
+  ZZIP_ONLYZIP* = 1'i32 shl 16'i32
+  ZZIP_FACTORY* = 1'i32 shl 17'i32
+  ZZIP_ALLOWREAL* = 1'i32 shl 18'i32
+  ZZIP_THREADED* = 1'i32 shl 19'i32
+  
+type
+  TZZipDir* {.final, pure.} = object
+  TZZipFile* {.final, pure.} = object
+  TZZipPluginIO* {.final, pure.} = object
+
+  TZZipDirent* {.final, pure.} = object  
+    d_compr*: int32  ## compression method
+    d_csize*: int32  ## compressed size  
+    st_size*: int32  ## file size / decompressed size
+    d_name*: cstring ## file name / strdupped name
+
+  TZZipStat* = TZZipDirent    
+
+proc zzip_strerror*(errcode: int32): cstring  {.cdecl, dynlib: dllname, 
+    importc: "zzip_strerror".}
+proc zzip_strerror_of*(dir: ptr TZZipDir): cstring  {.cdecl, dynlib: dllname, 
+    importc: "zzip_strerror_of".}
+proc zzip_errno*(errcode: int32): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_errno".}
+
+proc zzip_geterror*(dir: ptr TZZipDir): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_error".}
+proc zzip_seterror*(dir: ptr TZZipDir, errcode: int32) {.cdecl, dynlib: dllname, 
+    importc: "zzip_seterror".}
+proc zzip_compr_str*(compr: int32): cstring {.cdecl, dynlib: dllname, 
+    importc: "zzip_compr_str".}
+proc zzip_dirhandle*(fp: ptr TZZipFile): ptr TZZipDir {.cdecl, dynlib: dllname, 
+    importc: "zzip_dirhandle".}
+proc zzip_dirfd*(dir: ptr TZZipDir): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_dirfd".}
+proc zzip_dir_real*(dir: ptr TZZipDir): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_dir_real".}
+proc zzip_file_real*(fp: ptr TZZipFile): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_file_real".}
+proc zzip_realdir*(dir: ptr TZZipDir): pointer {.cdecl, dynlib: dllname, 
+    importc: "zzip_realdir".}
+proc zzip_realfd*(fp: ptr TZZipFile): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_realfd".}
+
+proc zzip_dir_alloc*(fileext: cstringArray): ptr TZZipDir {.cdecl, 
+    dynlib: dllname, importc: "zzip_dir_alloc".}
+proc zzip_dir_free*(para1: ptr TZZipDir): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_dir_free".}
+
+proc zzip_dir_fdopen*(fd: int32, errcode_p: ptr TZZipError): ptr TZZipDir {.cdecl, 
+    dynlib: dllname, importc: "zzip_dir_fdopen".}
+proc zzip_dir_open*(filename: cstring, errcode_p: ptr TZZipError): ptr TZZipDir {.
+    cdecl, dynlib: dllname, importc: "zzip_dir_open".}
+proc zzip_dir_close*(dir: ptr TZZipDir) {.cdecl, dynlib: dllname, 
+    importc: "zzip_dir_close".}
+proc zzip_dir_read*(dir: ptr TZZipDir, dirent: ptr TZZipDirent): int32 {.cdecl, 
+    dynlib: dllname, importc: "zzip_dir_read".}
+
+proc zzip_opendir*(filename: cstring): ptr TZZipDir {.cdecl, dynlib: dllname, 
+    importc: "zzip_opendir".}
+proc zzip_closedir*(dir: ptr TZZipDir) {.cdecl, dynlib: dllname, 
+    importc: "zzip_closedir".}
+proc zzip_readdir*(dir: ptr TZZipDir): ptr TZZipDirent {.cdecl, dynlib: dllname, 
+    importc: "zzip_readdir".}
+proc zzip_rewinddir*(dir: ptr TZZipDir) {.cdecl, dynlib: dllname, 
+                                      importc: "zzip_rewinddir".}
+proc zzip_telldir*(dir: ptr TZZipDir): int {.cdecl, dynlib: dllname, 
+    importc: "zzip_telldir".}
+proc zzip_seekdir*(dir: ptr TZZipDir, offset: int) {.cdecl, dynlib: dllname, 
+    importc: "zzip_seekdir".}
+
+proc zzip_file_open*(dir: ptr TZZipDir, name: cstring, flags: int32): ptr TZZipFile {.
+    cdecl, dynlib: dllname, importc: "zzip_file_open".}
+proc zzip_file_close*(fp: ptr TZZipFile) {.cdecl, dynlib: dllname, 
+    importc: "zzip_file_close".}
+proc zzip_file_read*(fp: ptr TZZipFile, buf: pointer, length: int): int {.
+    cdecl, dynlib: dllname, importc: "zzip_file_read".}
+proc zzip_open*(name: cstring, flags: int32): ptr TZZipFile {.cdecl, 
+    dynlib: dllname, importc: "zzip_open".}
+proc zzip_close*(fp: ptr TZZipFile) {.cdecl, dynlib: dllname, 
+    importc: "zzip_close".}
+proc zzip_read*(fp: ptr TZZipFile, buf: pointer, length: int): int {.
+    cdecl, dynlib: dllname, importc: "zzip_read".}
+
+proc zzip_freopen*(name: cstring, mode: cstring, para3: ptr TZZipFile): ptr TZZipFile {.
+    cdecl, dynlib: dllname, importc: "zzip_freopen".}
+proc zzip_fopen*(name: cstring, mode: cstring): ptr TZZipFile {.cdecl, 
+    dynlib: dllname, importc: "zzip_fopen".}
+proc zzip_fread*(p: pointer, size: int, nmemb: int, 
+                 file: ptr TZZipFile): int {.cdecl, dynlib: dllname, 
+    importc: "zzip_fread".}
+proc zzip_fclose*(fp: ptr TZZipFile) {.cdecl, dynlib: dllname, 
+    importc: "zzip_fclose".}
+
+proc zzip_rewind*(fp: ptr TZZipFile): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_rewind".}
+proc zzip_seek*(fp: ptr TZZipFile, offset: int, whence: int32): int {.
+    cdecl, dynlib: dllname, importc: "zzip_seek".}
+proc zzip_tell*(fp: ptr TZZipFile): int {.cdecl, dynlib: dllname, 
+    importc: "zzip_tell".}
+
+proc zzip_dir_stat*(dir: ptr TZZipDir, name: cstring, zs: ptr TZZipStat, 
+                    flags: int32): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_dir_stat".}
+proc zzip_file_stat*(fp: ptr TZZipFile, zs: ptr TZZipStat): int32 {.cdecl, 
+    dynlib: dllname, importc: "zzip_file_stat".}
+proc zzip_fstat*(fp: ptr TZZipFile, zs: ptr TZZipStat): int32 {.cdecl, dynlib: dllname, 
+    importc: "zzip_fstat".}
+
+proc zzip_open_shared_io*(stream: ptr TZZipFile, name: cstring, 
+                          o_flags: int32, o_modes: int32, ext: cstringArray, 
+                          io: ptr TZZipPluginIO): ptr TZZipFile {.cdecl, 
+    dynlib: dllname, importc: "zzip_open_shared_io".}
+proc zzip_open_ext_io*(name: cstring, o_flags: int32, o_modes: int32, 
+                       ext: cstringArray, io: ptr TZZipPluginIO): ptr TZZipFile {.
+    cdecl, dynlib: dllname, importc: "zzip_open_ext_io".}
+proc zzip_opendir_ext_io*(name: cstring, o_modes: int32, 
+                          ext: cstringArray, io: ptr TZZipPluginIO): ptr TZZipDir {.
+    cdecl, dynlib: dllname, importc: "zzip_opendir_ext_io".}
+proc zzip_dir_open_ext_io*(filename: cstring, errcode_p: ptr TZZipError, 
+                           ext: cstringArray, io: ptr TZZipPluginIO): ptr TZZipDir {.
+    cdecl, dynlib: dllname, importc: "zzip_dir_open_ext_io".}
diff --git a/readme.md b/readme.md
new file mode 100644
index 000000000..740296f4f
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,84 @@
+# Nim Compiler
+This repo contains the Nim compiler, Nim's stdlib, tools and
+documentation.
+
+## Compiling
+Compiling the Nim compiler is quite straightforward. Because
+the Nim compiler itself is written in the Nim programming language
+the C source of an older version of the compiler are needed to bootstrap the
+latest version. The C sources are available in a separate repo [here](http://github.com/nim-lang/csources).
+
+The compiler currently supports the following platform and architecture
+combinations:
+
+  * Windows (Windows XP or greater) - x86 and x86_64
+  * Linux (most, if not all, distributions) - x86, x86_64, ppc64 and armv6l
+  * Mac OS X 10.04 or higher - x86, x86_64 and ppc64
+
+In reality a lot more are supported, however they are not tested regularly.
+
+To build from source you will need:
+
+  * gcc 3.x or later recommended. Other alternatives which may work
+    are: clang, Visual C++, Intel's C++ compiler
+  * git or wget
+
+If you are on a fairly modern *nix system, the following steps should work:
+
+```
+$ git clone git://github.com/Araq/Nim.git
+$ cd Nim
+$ git clone --depth 1 git://github.com/nim-lang/csources
+$ cd csources && sh build.sh
+$ cd ..
+$ bin/nim c koch
+$ ./koch boot -d:release
+```
+
+``koch install [dir]`` may then be used to install Nim, but lots of things don't work then so don't do that. Add it to your PATH instead. More ``koch`` related options are documented in
+[doc/koch.txt](doc/koch.txt).
+
+The above steps can be performed on Windows in a similar fashion, the
+``build.bat`` and ``build64.bat`` (for x86_64 systems) are provided to be used
+instead of ``build.sh``.
+
+## Getting help
+A [forum](http://forum.nim-lang.org/) is available if you have any
+questions, and you can also get help in the IRC channel on
+[Freenode](irc://irc.freenode.net/nim) in #nim. If you ask questions on
+[StackOverflow use the nim
+tag](http://stackoverflow.com/questions/tagged/nim).
+
+## License
+The compiler and the standard library are licensed under the MIT license,
+except for some modules where the documentation suggests otherwise. This means
+that you can use any license for your own programs developed with Nim,
+allowing you to create commercial applications.
+
+Read copying.txt for more details.
+
+Copyright (c) 2006-2015 Andreas Rumpf.
+All rights reserved.
+
+# Build Status
+[**Build Waterfall**][waterfall]
+
+|        | Linux                                                                                                  | Windows                               | Mac                           |
+| ------ | -----                                                                                                  | -------                               | ---                           |
+| x86    | ![linux-x86][linux-x86-img]                                                                            | ![windows-x86][windows-x86-img]       | ![mac-x86][mac-x86-img]       |
+| x86_64 | ![linux-x86_64][linux-x86_64-img]                                                                      | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] |
+| arm    | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] |                                       |                               |
+
+[linux-x86-img]:      http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder
+[linux-x86_64-img]:   http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder
+[linux-arm5-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder
+[linux-arm6-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder
+[linux-arm7-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder
+
+[windows-x86-img]:    http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder
+[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder
+
+[mac-x86-img]:        http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder
+[mac-x86_64-img]:     http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder
+
+[waterfall]: http://buildbot.nim-lang.org/waterfall
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 000000000..e3119f83d
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,18 @@
+This package contains the Nim compiler, Nim's stdlib, tools and 
+documentation.
+
+Nim is a compiled, garbage-collected systems programming language which has
+an excellent productivity/performance ratio. Nim's design focuses on
+efficiency, expressiveness, elegance (in the order of priority).
+
+Read install.txt for instructions of how to build and install it.
+
+The compiler and the standard library are licensed under the MIT license, 
+except for some modules where the documentation suggests otherwise. This means 
+that you can use any license for your own programs developed with Nim, 
+allowing you to create commercial applications.
+
+Read copying.txt for more details.
+
+Copyright (c) 2006-2014 Andreas Rumpf.
+All rights reserved.
diff --git a/start.bat b/start.bat
new file mode 100644
index 000000000..7328211ca
--- /dev/null
+++ b/start.bat
@@ -0,0 +1,6 @@
+@echo off

+REM COLOR 0A

+SET NIMRODPATH=.

+SET PATH=%NIMRODPATH%\bin;%NIMRODPATH%\dist\mingw\bin;%PATH%

+cmd

+
diff --git a/tests/actiontable/tactiontable.nim b/tests/actiontable/tactiontable.nim
new file mode 100644
index 000000000..e2f19a099
--- /dev/null
+++ b/tests/actiontable/tactiontable.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "action 3 arg"
+"""
+
+import tables
+
+proc action1(arg: string) = 
+  echo "action 1 ", arg
+
+proc action2(arg: string) = 
+  echo "action 2 ", arg
+
+proc action3(arg: string) = 
+  echo "action 3 ", arg
+
+proc action4(arg: string) = 
+  echo "action 4 ", arg
+
+var
+  actionTable = {
+    "A": action1, 
+    "B": action2, 
+    "C": action3, 
+    "D": action4}.toTable
+
+actionTable["C"]("arg")
+
diff --git a/tests/actiontable/tactiontable2.nim b/tests/actiontable/tactiontable2.nim
new file mode 100644
index 000000000..fbc65a67d
--- /dev/null
+++ b/tests/actiontable/tactiontable2.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "action 3 arg"
+"""
+
+import tables
+
+proc action1(arg: string) =
+  echo "action 1 ", arg
+
+proc action2(arg: string) =
+  echo "action 2 ", arg
+
+proc action3(arg: string) =
+  echo "action 3 ", arg
+
+proc action4(arg: string) =
+  echo "action 4 ", arg
+
+const
+  actionTable = {
+    "A": action1,
+    "B": action2,
+    "C": action3,
+    "D": action4}.toTable
+
+actionTable["C"]("arg")
+
diff --git a/tests/alias/talias.nim b/tests/alias/talias.nim
new file mode 100644
index 000000000..819289c2e
--- /dev/null
+++ b/tests/alias/talias.nim
@@ -0,0 +1,66 @@
+# Test the alias analysis
+
+type
+  TAnalysisResult* = enum
+    arNo, arMaybe, arYes
+
+proc isPartOf*[S, T](a: S, b: T): TAnalysisResult {.
+  magic: "IsPartOf", noSideEffect.}
+  ## not yet exported properly. 
+
+template compileTimeAssert(cond: expr) =
+  when not cond:
+    {.compile: "is false: " & astToStr(cond).}
+
+template `<|` (a, b: expr) =
+  compileTimeAssert isPartOf(a, b) == arYes
+
+template `!<|` (a, b: expr) =
+  compileTimeAssert isPartOf(a, b) == arNo
+
+template `?<|` (a, b: expr) =
+  compileTimeAssert isPartOf(a, b) == arMaybe
+
+type
+  TA {.inheritable.} = object
+  TC = object of TA
+    arr: array[0..3, int]
+    le, ri: ref TC
+    f: string
+    c: char
+    se: seq[TA]
+
+proc p(param1, param2: TC): TC =
+  var
+    local: TC
+    plocal: ptr TC
+    plocal2: ptr TA
+    
+  local.arr <| local
+  local.arr[0] <| local
+  local.arr[2] !<| local.arr[1]
+  
+  plocal2[] ?<| local
+
+  param1 ?<| param2
+  
+  local.arr[0] !<| param1
+  local.arr !<| param1
+  local.le[] ?<| param1
+  
+  param1 !<| local.arr[0]
+  param1 !<| local.arr
+  param1 ?<| local.le[]
+  
+  result !<| local
+  result <| result
+
+var
+  a, b: int
+  x: TC
+  
+a <| a
+a !<| b
+
+discard p(x, x)
+
diff --git a/tests/ambsym/mambsym1.nim b/tests/ambsym/mambsym1.nim
new file mode 100644
index 000000000..d9d57b5e5
--- /dev/null
+++ b/tests/ambsym/mambsym1.nim
@@ -0,0 +1,10 @@
+import mambsym2 # import TExport

+

+type

+  TExport* = enum x, y, z

+  TOtherEnum* = enum mDec, mInc, mAssign

+

+proc ha() =

+  var

+    x: TExport # no error

+  discard

diff --git a/tests/ambsym/mambsym2.nim b/tests/ambsym/mambsym2.nim
new file mode 100644
index 000000000..eac8de6ba
--- /dev/null
+++ b/tests/ambsym/mambsym2.nim
@@ -0,0 +1,3 @@
+type

+  TExport* = enum a, b, c

+  

diff --git a/tests/ambsym/mambsys1.nim b/tests/ambsym/mambsys1.nim
new file mode 100644
index 000000000..04f9561d3
--- /dev/null
+++ b/tests/ambsym/mambsys1.nim
@@ -0,0 +1,7 @@
+import mambsys2 # import TExport

+

+type

+  TExport* = enum x, y, z

+

+proc foo*(x: int) =

+  discard

diff --git a/tests/ambsym/mambsys2.nim b/tests/ambsym/mambsys2.nim
new file mode 100644
index 000000000..d59706865
--- /dev/null
+++ b/tests/ambsym/mambsys2.nim
@@ -0,0 +1,4 @@
+type

+  TExport* = enum x, y, z # exactly the same type!

+

+proc foo*(x: int) = discard

diff --git a/tests/ambsym/tambsym.nim b/tests/ambsym/tambsym.nim
new file mode 100644
index 000000000..902274648
--- /dev/null
+++ b/tests/ambsym/tambsym.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tambsym.nim"
+  line: 11
+  errormsg: "ambiguous identifier"
+"""
+# Test ambiguous symbols

+

+import mambsym1, mambsym2

+

+var

+  v: TExport #ERROR_MSG ambiguous identifier

+

+v = y

+
+
diff --git a/tests/ambsym/tambsym2.nim b/tests/ambsym/tambsym2.nim
new file mode 100644
index 000000000..745427c54
--- /dev/null
+++ b/tests/ambsym/tambsym2.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tambsym2.nim"
+  output: "7"
+"""
+# Test overloading of procs with locals
+
+type
+  TMyType = object
+    len: int
+    data: string
+    
+proc len(x: TMyType): int {.inline.} = return x.len
+
+proc x(s: TMyType, len: int) = 
+  writeln(stdout, len(s))
+  
+var
+  m: TMyType
+m.len = 7
+m.data = "1234"
+
+x(m, 5) #OUT 7
+
+
diff --git a/tests/ambsym/tambsym3.nim b/tests/ambsym/tambsym3.nim
new file mode 100644
index 000000000..0155f258c
--- /dev/null
+++ b/tests/ambsym/tambsym3.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tambsym3.nim"
+  line: 11
+  errormsg: "ambiguous identifier"
+"""
+# Test ambiguous symbols

+

+import mambsym1, times

+

+var

+  v = mDec #ERROR_MSG ambiguous identifier

+

+writeln(stdout, ord(v))

+
+
diff --git a/tests/ambsym/tambsys.nim b/tests/ambsym/tambsys.nim
new file mode 100644
index 000000000..67522d7c9
--- /dev/null
+++ b/tests/ambsym/tambsys.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "tambsys.nim"
+  output: ""
+"""
+# Test ambiguous symbols
+
+import mambsys1, mambsys2
+
+var
+  v: mambsys1.TExport
+mambsys2.foo(3) #OUT
+
+
diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim
new file mode 100644
index 000000000..01fbdf422
--- /dev/null
+++ b/tests/array/tarray.nim
@@ -0,0 +1,40 @@
+discard """
+  file: "tarray.nim"
+  output: "100124"
+"""
+# simple check for one dimensional arrays

+

+type

+  TMyArray = array[0..2, int]

+  TMyRecord = tuple[x, y: int]

+

+proc sum(a: TMyarray): int =

+  result = 0

+  var i = 0

+  while i < len(a):

+    inc(result, a[i])

+    inc(i)

+

+proc sum(a: openarray[int]): int =

+  result = 0

+  var i = 0

+  while i < len(a):

+    inc(result, a[i])

+    inc(i)

+

+proc getPos(r: TMyRecord): int =

+  result = r.x + r.y

+

+write(stdout, sum([1, 2, 3, 4]))

+write(stdout, sum([]))

+write(stdout, getPos( (x: 5, y: 7) ))

+#OUT 10012

+
+# bug #1669
+let filesToCreate = ["tempdir/fl1.a", "tempdir/fl2.b",
+            "tempdir/tempdir2/fl3.e", "tempdir/tempdir2/tempdir3/fl4.f"]
+
+var found: array[0..filesToCreate.high, bool]
+
+echo found.len
+
diff --git a/tests/array/tarray2.nim b/tests/array/tarray2.nim
new file mode 100644
index 000000000..b6adabb45
--- /dev/null
+++ b/tests/array/tarray2.nim
@@ -0,0 +1,36 @@
+discard """
+  file: "tarray2.nim"
+  output: "[4, 5, 6]\n\n[16, 25, 36]\n\n[16, 25, 36]"
+"""
+# simple check for one dimensional arrays
+
+type
+  TMyArray = array[0..2, int]
+
+  TObj = object
+    arr: TMyarray
+  
+proc mul(a, b: TMyarray): TMyArray =
+  result = a
+  for i in 0..len(a)-1:
+    result[i] = a[i] * b[i]
+
+var
+  x, y: TMyArray
+  o: TObj
+
+proc varArr1(x: var TMyArray): var TMyArray = x
+proc varArr2(x: var TObj): var TMyArray = x.arr
+
+x = [ 4, 5, 6 ]
+echo repr(varArr1(x))
+
+y = x
+echo repr(mul(x, y))
+
+o.arr = mul(x, y)
+echo repr(varArr2(o))
+
+#OUT [16, 25, 36]
+
+
diff --git a/tests/array/tarray3.nim b/tests/array/tarray3.nim
new file mode 100644
index 000000000..d28778357
--- /dev/null
+++ b/tests/array/tarray3.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "tarray3.nim"
+  output: "3"
+"""
+# simple check for two dimensional arrays

+
+const  
+  myData = [[1,2,3], [4, 5, 6]]
+
+echo myData[0][2] #OUT 3
+
+
+
diff --git a/tests/array/tarraycons.nim b/tests/array/tarraycons.nim
new file mode 100644
index 000000000..7de518b6e
--- /dev/null
+++ b/tests/array/tarraycons.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tarraycons.nim"
+  line: 14
+  errormsg: "invalid order in array constructor"
+"""
+
+type
+  TEnum = enum
+    eA, eB, eC, eD, eE, eF
+    
+const
+  myMapping: array[TEnum, array[0..1, int]] = [
+    eA: [1, 2],
+    eC: [3, 4],
+    eB: [5, 6],
+    eD: [0: 8, 1: 9],
+    eE: [0: 8, 9],
+    eF: [2, 1: 9]
+  ]
+
+echo myMapping[eC][1]
+
+
+
diff --git a/tests/array/tarraycons2.nim b/tests/array/tarraycons2.nim
new file mode 100644
index 000000000..0b2a42c2f
--- /dev/null
+++ b/tests/array/tarraycons2.nim
@@ -0,0 +1,23 @@
+discard """
+  file: "tarraycons.nim"
+  output: "6"
+"""
+
+type
+  TEnum = enum
+    eA, eB, eC, eD, eE, eF
+    
+const
+  myMapping: array[TEnum, array[0..1, int]] = [
+    eA: [1, 2],
+    eB: [3, 4],
+    [5, 6],
+    eD: [0: 8, 1: 9],
+    eE: [0: 8, 9],
+    eF: [2, 1: 9]
+  ]
+
+echo myMapping[eC][1]
+
+
+
diff --git a/tests/array/tarrayplus.nim b/tests/array/tarrayplus.nim
new file mode 100644
index 000000000..0ea349f4f
--- /dev/null
+++ b/tests/array/tarrayplus.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "type mismatch: got (array[0..2, float], array[0..1, float])"
+"""
+
+proc `+`*[R, T] (v1, v2: array[R, T]): array[R, T] =
+  for i in low(v1)..high(v1):
+    result[i] = v1[i] + v2[i]
+
+var 
+  v1: array[0..2, float] = [3.0, 1.2, 3.0]
+  v2: array[0..1, float] = [2.0, 1.0]
+  v3 = v1 + v2
+
diff --git a/tests/array/tarrindx.nim b/tests/array/tarrindx.nim
new file mode 100644
index 000000000..13919cc2c
--- /dev/null
+++ b/tests/array/tarrindx.nim
@@ -0,0 +1,13 @@
+# test another strange bug ... (I hate this compiler; it is much too buggy!)

+

+proc putEnv(key, val: string) =

+  # XXX: we have to leak memory here, as we cannot

+  # free it before the program ends (says Borland's

+  # documentation)

+  var

+    env: ptr array[0..500000, char]

+  env = cast[ptr array[0..500000, char]](alloc(len(key) + len(val) + 2))

+  for i in 0..len(key)-1: env[i] = key[i]

+  env[len(key)] = '='

+  for i in 0..len(val)-1:

+    env[len(key)+1+i] = val[i]

diff --git a/tests/array/troof1.nim b/tests/array/troof1.nim
new file mode 100644
index 000000000..96669a121
--- /dev/null
+++ b/tests/array/troof1.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''@[2, 3, 4]321
+9.0 4.0
+(a: 1.0, b: 2.0, c: 8.0)2.0'''
+"""
+
+proc foo[T](x, y: T): T = x
+
+var a = @[1, 2, 3, 4]
+var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
+echo a[1.. ^1], a[^2], a[^3], a[^4]
+echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
+
+type
+  MyArray = object
+    a, b, c: float
+
+var
+  ma = MyArray(a: 1.0, b: 2.0, c: 3.0)
+
+proc len(x: MyArray): int = 3
+
+proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) =
+  case idx
+  of 0: x.a = val
+  of 1: x.b = val
+  of 2: x.c = val
+
+proc `[]`(x: var MyArray; idx: range[0..2]): float =
+  case idx
+  of 0: result = x.a
+  of 1: result = x.b
+  of 2: result = x.c
+
+ma[^1] = 8.0
+echo ma, ma[^2]
diff --git a/tests/array/troof2.nim b/tests/array/troof2.nim
new file mode 100644
index 000000000..d4c1a4982
--- /dev/null
+++ b/tests/array/troof2.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "invalid context for '^' as 'foo()' has side effects"
+  line: "9"
+"""
+
+proc foo(): seq[int] =
+  echo "ha"
+
+let f = foo()[^1]
+
diff --git a/tests/array/troof3.nim b/tests/array/troof3.nim
new file mode 100644
index 000000000..4b6e22223
--- /dev/null
+++ b/tests/array/troof3.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "invalid context for '^' as len!=high+1 for 'a'"
+  line: "8"
+"""
+
+var a: array[1..3, string]
+
+echo a[^1]
diff --git a/tests/array/troof4.nim b/tests/array/troof4.nim
new file mode 100644
index 000000000..7a262d9de
--- /dev/null
+++ b/tests/array/troof4.nim
@@ -0,0 +1,37 @@
+discard """
+  errormsg: "no surrounding array access context for '^'"
+  line: "37"
+"""
+
+proc foo[T](x, y: T): T = x
+
+var a = @[1, 2, 3, 4]
+var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
+echo a[1.. ^1], a[^2], a[^3], a[^4]
+echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
+
+type
+  MyArray = object
+    a, b, c: float
+
+var
+  ma = MyArray(a: 1.0, b: 2.0, c: 3.0)
+
+proc len(x: MyArray): int = 3
+
+proc `[]=`(x: var MyArray; idx: range[0..2]; val: float) =
+  case idx
+  of 0: x.a = val
+  of 1: x.b = val
+  of 2: x.c = val
+
+proc `[]`(x: var MyArray; idx: range[0..2]): float =
+  case idx
+  of 0: result = x.a
+  of 1: result = x.b
+  of 2: result = x.c
+
+ma[^1] = 8.0
+echo ma, ma[^2]
+
+echo(^1)
diff --git a/tests/assert/tassert.nim b/tests/assert/tassert.nim
new file mode 100644
index 000000000..b3df30bd1
--- /dev/null
+++ b/tests/assert/tassert.nim
@@ -0,0 +1,23 @@
+discard """
+  file: "tassert.nim"
+  outputsub: "assertion failure!this shall be always written"
+  exitcode: "1"
+"""
+# test assert and exception handling
+
+proc callB() = assert(false)
+proc callA() = callB()
+proc callC() = callA()
+
+try:
+  callC()
+except EAssertionFailed:
+  write(stdout, "assertion failure!")
+except:
+  write(stdout, "unknown exception!")
+finally:
+  system.write(stdout, "this shall be always written")
+
+assert(false) #OUT assertion failure!this shall be always written
+
+
diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim
new file mode 100644
index 000000000..1e6764471
--- /dev/null
+++ b/tests/assert/tfailedassert.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''
+WARNING: false first assertion from bar
+ERROR: false second assertion from bar
+-1
+tests/assert/tfailedassert.nim:27 false assertion from foo
+'''
+"""
+
+type
+  TLineInfo = tuple[filename: string, line: int]
+
+  TMyError = object of Exception
+    lineinfo: TLineInfo
+
+  EMyError = ref TMyError
+
+# module-wide policy to change the failed assert
+# exception type in order to include a lineinfo
+onFailedAssert(msg):
+  var e = new(TMyError)
+  e.msg = msg
+  e.lineinfo = instantiationInfo(-2)
+  raise e
+
+proc foo =
+  assert(false, "assertion from foo")
+
+proc bar: int =
+  # local overrides that are active only
+  # in this proc
+  onFailedAssert(msg): echo "WARNING: " & msg
+
+  assert(false, "first assertion from bar")
+
+  onFailedAssert(msg):
+    echo "ERROR: " & msg
+    return -1
+
+  assert(false, "second assertion from bar")
+  return 10
+
+echo("")
+echo(bar())
+
+try:
+  foo()
+except:
+  let e = EMyError(getCurrentException())
+  echo e.lineinfo.filename, ":", e.lineinfo.line, " ", e.msg
+
diff --git a/tests/assert/tunittests.nim b/tests/assert/tunittests.nim
new file mode 100644
index 000000000..cbbfe63c6
--- /dev/null
+++ b/tests/assert/tunittests.nim
@@ -0,0 +1 @@
+import "../template/utemplates", "../closure/uclosures"
diff --git a/tests/assert/tuserassert.nim b/tests/assert/tuserassert.nim
new file mode 100644
index 000000000..57b229ca9
--- /dev/null
+++ b/tests/assert/tuserassert.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "x == 45ugh"
+"""
+
+template myAssert(cond: expr) = 
+  when 3 <= 3:
+    let c = cond.astToStr
+    if not cond:
+      echo c, "ugh"
+  
+var x = 454
+myAssert(x == 45)
+
diff --git a/tests/assign/moverload_asgn2.nim b/tests/assign/moverload_asgn2.nim
new file mode 100644
index 000000000..6620adbeb
--- /dev/null
+++ b/tests/assign/moverload_asgn2.nim
@@ -0,0 +1,10 @@
+type
+  Concrete* = object
+    a*, b*: string
+    rc*: int # refcount
+
+proc `=`(d: var Concrete; src: Concrete) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  dec d.rc
+  d.rc = src.rc + 1
diff --git a/tests/assign/tassign.nim b/tests/assign/tassign.nim
new file mode 100644
index 000000000..f51c20783
--- /dev/null
+++ b/tests/assign/tassign.nim
@@ -0,0 +1,31 @@
+# Test the assignment operator for complex types which need RTTI

+

+type

+  TRec = object

+    x, y: int

+    s: string

+    seq: seq[string]

+    arr: seq[seq[array[0..3, string]]]

+  TRecSeq = seq[TRec]

+

+proc test() =

+  var

+    a, b: TRec

+  a.x = 1

+  a.y = 2

+  a.s = "Hallo!"

+  a.seq = @["abc", "def", "ghi", "jkl"]

+  a.arr = @[]

+  setLen(a.arr, 4)

+  a.arr[0] = @[]

+  a.arr[1] = @[]

+

+  b = a # perform a deep copy here!

+  b.seq = @["xyz", "huch", "was", "soll"]

+  writeln(stdout, len(a.seq))

+  writeln(stdout, a.seq[3])

+  writeln(stdout, len(b.seq))

+  writeln(stdout, b.seq[3])

+  writeln(stdout, b.y)

+

+test()

diff --git a/tests/assign/tcopy.nim b/tests/assign/tcopy.nim
new file mode 100644
index 000000000..5feb0d6b3
--- /dev/null
+++ b/tests/assign/tcopy.nim
@@ -0,0 +1,25 @@
+discard """
+  file: "tcopy.nim"
+  output: "TEMP=C:\\Programs\\xyz\\bin"
+"""
+# tests the substr proc
+
+import
+  strutils
+
+proc main() =
+  const
+    example = r"TEMP=C:\Programs\xyz\bin"
+  var
+    a, b: string
+    p: int
+  p = find(example, "=")
+  a = substr(example, 0, p-1)
+  b = substr(example, p+1)
+  writeln(stdout, a & '=' & b)
+  #writeln(stdout, b)
+
+main()
+#OUT TEMP=C:\Programs\xyz\bin
+
+
diff --git a/tests/assign/tgenericassign.nim b/tests/assign/tgenericassign.nim
new file mode 100644
index 000000000..654b0ab8f
--- /dev/null
+++ b/tests/assign/tgenericassign.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''came here'''
+"""
+
+type
+  TAny* = object {.pure.}
+    value*: pointer
+    rawType: pointer
+    
+proc newAny(value, rawType: pointer): TAny =
+  result.value = value
+  result.rawType = rawType
+
+var name: cstring = "example"
+
+var ret: seq[tuple[name: string, a: TAny]] = @[]
+for i in 0..8000:
+  var tup = ($name, newAny(nil, nil))
+  assert(tup[0] == "example")
+  ret.add(tup)
+  assert(ret[ret.len()-1][0] == "example")
+
+echo "came here"
+
diff --git a/tests/assign/tgenericassigntuples.nim b/tests/assign/tgenericassigntuples.nim
new file mode 100644
index 000000000..6dd63a984
--- /dev/null
+++ b/tests/assign/tgenericassigntuples.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''abc232'''
+"""
+
+var t, s: tuple[x: string, c: int]
+
+proc ugh: seq[tuple[x: string, c: int]] = 
+  result = @[("abc", 232)]
+
+t = ugh()[0]
+s = t
+s = ugh()[0]
+
+echo s[0], t[1]
+
+
diff --git a/tests/assign/tobjasgn.nim b/tests/assign/tobjasgn.nim
new file mode 100644
index 000000000..23a31252d
--- /dev/null
+++ b/tests/assign/tobjasgn.nim
@@ -0,0 +1,44 @@
+discard """
+  output: '''8 5 0 0
+pre test a:test b:1 c:2 haha:3
+assignment test a:test b:1 c:2 haha:3
+'''
+"""
+
+# bug #1005
+
+type
+  TSomeObj = object of TObject
+    a, b: int
+  PSomeObj = ref object
+    a, b: int
+ 
+var a = TSomeObj(a: 8)
+var b = PSomeObj(a: 5)
+echo a.a, " ", b.a, " ", a.b, " ", b.b
+
+# bug #575
+
+type
+  Something = object of Tobject
+    a: string
+    b, c: int32
+
+type
+  Other = object of Something
+    haha: int
+
+proc `$`(x: Other): string =
+  result = "a:" & x.a & " b:" & $x.b & " c:" & $x.c & " haha:" & $x.haha
+
+var
+  t: Other
+
+t.a = "test"
+t.b = 1
+t.c = 2
+t.haha = 3
+
+echo "pre test ", $t
+var x = t
+echo "assignment test ", x
diff --git a/tests/assign/toverload_asgn1.nim b/tests/assign/toverload_asgn1.nim
new file mode 100644
index 000000000..dbc3a71c4
--- /dev/null
+++ b/tests/assign/toverload_asgn1.nim
@@ -0,0 +1,75 @@
+discard """
+  output: '''Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+GenericT[T] '=' int
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' string
+GenericT[T] '=' int8
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool'''
+"""
+
+import typetraits
+
+type
+  Concrete = object
+    a, b: string
+
+proc `=`(d: var Concrete; src: Concrete) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  echo "Concrete '='"
+
+var x, y: array[0..2, Concrete]
+var cA, cB: Concrete
+
+var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+x = y
+cA = cB
+cATup = cBTup
+
+type
+  GenericT[T] = object
+    a, b: T
+
+proc `=`[T](d: var GenericT[T]; src: GenericT[T]) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  echo "GenericT[T] '=' ", type(T).name
+
+var ag: GenericT[int]
+var bg: GenericT[int]
+
+ag = bg
+
+var xg, yg: array[0..2, GenericT[float]]
+var cAg, cBg: GenericT[string]
+
+var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]]
+
+xg = yg
+cAg = cBg
+cATupg = cBTupg
+
+var caSeqg, cbSeqg: seq[GenericT[bool]]
+newSeq(cbSeqg, 4)
+caSeqg = cbSeqg
+
+when false:
+  type
+    Foo = object
+      case b: bool
+      of false: xx: GenericT[int]
+      of true: yy: bool
+
+  var
+    a, b: Foo
+  a = b
diff --git a/tests/assign/toverload_asgn2.nim b/tests/assign/toverload_asgn2.nim
new file mode 100644
index 000000000..243c90494
--- /dev/null
+++ b/tests/assign/toverload_asgn2.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''i value 88
+2aa'''
+"""
+
+import moverload_asgn2
+
+proc passAround(i: int): Concrete =
+  echo "i value ", i
+  result = Concrete(a: "aa", b: "bb", rc: 0)
+
+proc main =
+  let
+    i = 88
+    v = passAround(i)
+    z = v.a
+  var
+    x: Concrete
+  x = v
+  echo x.rc, z # 2aa
+
+main()
diff --git a/tests/assign/tvariantasgn.nim b/tests/assign/tvariantasgn.nim
new file mode 100644
index 000000000..46cc23dd1
--- /dev/null
+++ b/tests/assign/tvariantasgn.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tvariantasgn.nim"
+  output: "came here"
+"""
+#BUG
+type
+  TAnyKind = enum
+    nkInt,
+    nkFloat,
+    nkString
+  TAny = object
+    case kind: TAnyKind
+    of nkInt: intVal: int
+    of nkFloat: floatVal: float
+    of nkString: strVal: string
+
+var s: TAny
+s.kind = nkString
+s.strVal = "test"
+
+var nr: TAny
+nr.kind = nkint
+nr.intVal = 78
+
+
+# s = nr # works
+nr = s # fails!
+echo "came here"
+
+
diff --git a/tests/astoverload/tastoverload1.nim b/tests/astoverload/tastoverload1.nim
new file mode 100644
index 000000000..c8705547a
--- /dev/null
+++ b/tests/astoverload/tastoverload1.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''string literal
+no string literal
+no string literal'''
+"""
+
+proc optLit(a: string{lit}) =
+  echo "string literal"
+
+proc optLit(a: string) =
+  echo "no string literal"
+
+const
+  constant = "abc"
+
+var
+  variable = "xyz"
+
+optLit("literal")
+optLit(constant)
+optLit(variable)
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
new file mode 100644
index 000000000..13d531387
--- /dev/null
+++ b/tests/async/tasyncawait.nim
@@ -0,0 +1,65 @@
+discard """
+  file: "tasyncawait.nim"
+  output: "5000"
+"""
+import asyncdispatch, rawsockets, net, strutils, os
+
+var msgCount = 0
+
+const
+  swarmSize = 50
+  messagesToSend = 100
+
+var clientCount = 0
+
+proc sendMessages(client: TAsyncFD) {.async.} =
+  for i in 0 .. <messagesToSend:
+    await send(client, "Message " & $i & "\c\L")
+
+proc launchSwarm(port: TPort) {.async.} =
+  for i in 0 .. <swarmSize:
+    var sock = newAsyncRawSocket()
+
+    await connect(sock, "localhost", port)
+    await sendMessages(sock)
+    closeSocket(sock)
+
+proc readMessages(client: TAsyncFD) {.async.} =
+  while true:
+    var line = await recvLine(client)
+    if line == "":
+      closeSocket(client)
+      clientCount.inc
+      break
+    else:
+      if line.startswith("Message "):
+        msgCount.inc
+      else:
+        doAssert false
+
+proc createServer(port: TPort) {.async.} =
+  var server = newAsyncRawSocket()
+  block:
+    var name: Sockaddr_in
+    when defined(windows):
+      name.sin_family = toInt(AF_INET).int16
+    else:
+      name.sin_family = toInt(AF_INET)
+    name.sin_port = htons(int16(port))
+    name.sin_addr.s_addr = htonl(INADDR_ANY)
+    if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)),
+                sizeof(name).Socklen) < 0'i32:
+      raiseOSError(osLastError())
+  
+  discard server.SocketHandle.listen()
+  while true:
+    asyncCheck readMessages(await accept(server))
+
+asyncCheck createServer(TPort(10335))
+asyncCheck launchSwarm(TPort(10335))
+while true:
+  poll()
+  if clientCount == swarmSize: break
+
+assert msgCount == swarmSize * messagesToSend
+echo msgCount
diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim
new file mode 100644
index 000000000..71aba29e2
--- /dev/null
+++ b/tests/async/tasyncdiscard.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+1
+2
+3
+4
+1
+2
+1
+6
+'''
+"""
+import asyncio, asyncdispatch, asyncnet
+
+proc main {.async.} =
+  proc f: Future[int] {.async.} =
+    discard
+    echo 1
+    discard
+    result = 2
+    discard
+
+  let x = await f()
+  echo x
+  echo 3
+
+  proc g: Future[int] {.async.} =
+    discard
+    echo 4
+    discard
+    result = 6
+    discard
+    echo await f()
+    discard await f()
+
+  discard await g()
+  echo 6
+
+asyncCheck main()
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
new file mode 100644
index 000000000..c4379f7d8
--- /dev/null
+++ b/tests/async/tasyncexceptions.nim
@@ -0,0 +1,39 @@
+discard """
+  file: "tasyncexceptions.nim"
+  exitcode: 1
+  outputsub: "Error: unhandled exception: foobar [Exception]"
+"""
+import asyncdispatch
+
+proc accept(): Future[int] {.async.} =
+  await sleepAsync(100)
+  result = 4
+
+proc recvLine(fd: int): Future[string] {.async.} =
+  await sleepAsync(100)
+  return "get"
+
+proc processClient(fd: int) {.async.} =
+  # these finish synchronously, we need some async delay to emulate this bug.
+  var line = await recvLine(fd)
+  var foo = line[0]
+  if foo == 'g':
+    raise newException(EBase, "foobar")
+
+proc serve() {.async.} =
+
+  while true:
+    var fut = await accept()
+    await processClient(fut)
+
+when isMainModule:
+  proc main =
+    var fut = serve()
+    fut.callback =
+      proc () =
+        if fut.failed:
+          # This test ensures that this exception crashes the application
+          # as it is not handled.
+          raise fut.error
+    runForever()
+  main()
diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim
new file mode 100644
index 000000000..c3cf33512
--- /dev/null
+++ b/tests/async/tasyncfile.nim
@@ -0,0 +1,36 @@
+discard """
+  file: "tasyncfile.nim"
+  exitcode: 0
+"""
+import asyncfile, asyncdispatch, os
+
+proc main() {.async.} =
+  let fn = getTempDir() / "foobar.txt"
+  removeFile(fn)
+
+  # Simple write/read test.
+  block:
+    var file = openAsync(fn, fmReadWrite)
+    await file.write("test")
+    file.setFilePos(0)
+    await file.write("foo")
+    file.setFilePos(0)
+    let data = await file.readAll()
+    doAssert data == "foot"
+    file.close()
+  
+  # Append test
+  block:
+    var file = openAsync(fn, fmAppend)
+    await file.write("\ntest2")
+    let errorTest = file.readAll()
+    await errorTest
+    doAssert errorTest.failed
+    file.close()
+    file = openAsync(fn, fmRead)
+    let data = await file.readAll()
+    
+    doAssert data == "foot\ntest2"
+    file.close()
+  
+waitFor main()
diff --git a/tests/async/tasynciossl.nim b/tests/async/tasynciossl.nim
new file mode 100644
index 000000000..118b9e74d
--- /dev/null
+++ b/tests/async/tasynciossl.nim
@@ -0,0 +1,92 @@
+discard """
+  file: "tasynciossl.nim"
+  cmd: "nim $target --hints:on --define:ssl $options $file"
+  output: "20000"
+"""
+import sockets, asyncio, strutils, times
+
+var disp {.threadvar.}: PDispatcher
+disp = newDispatcher()
+var msgCount = 0
+
+when defined(ssl):
+  var ctx = newContext(verifyMode = CVerifyNone, 
+      certFile = "tests/testdata/mycert.pem", keyFile = "tests/testdata/mycert.pem")
+
+  var ctx1 = newContext(verifyMode = CVerifyNone)
+
+const 
+  swarmSize = 50
+  messagesToSend = 100
+
+proc swarmConnect(s: PAsyncSocket) =
+  #echo("Connected")
+  for i in 1..messagesToSend:
+    s.send("Message " & $i & "\c\L")
+  s.close()
+
+proc serverRead(s: PAsyncSocket) =
+  var line = ""
+  assert s.readLine(line)
+  if line != "":
+    #echo(line)
+    if line.startsWith("Message "):
+      msgCount.inc()
+    else:
+      assert(false)
+  else:
+    s.close()
+
+proc serverAccept(s: PAsyncSocket) =
+  var client: PAsyncSocket
+  new(client)
+  s.accept(client)
+  client.handleRead = serverRead
+  disp.register(client)
+
+proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
+                 buffered = true, useSSL = false) =
+  for i in 1..count:
+    var client = asyncSocket()
+    when defined(ssl):
+      if useSSL:
+        ctx1.wrapSocket(client)
+    client.handleConnect = swarmConnect
+    disp.register(client)
+    client.connect("localhost", port)
+
+proc createSwarm(port: TPort, buffered = true, useSSL = false) =
+  var server = asyncSocket()
+  when defined(ssl):
+    if useSSL:
+      ctx.wrapSocket(server)
+  server.handleAccept = serverAccept
+  disp.register(server)
+  server.bindAddr(port)
+  server.listen()
+  disp.launchSwarm(port, swarmSize, buffered, useSSL)
+
+when defined(ssl):
+  const serverCount = 4
+else:
+  const serverCount = 2
+
+createSwarm(TPort(10235))
+createSwarm(TPort(10236), false)
+
+when defined(ssl):
+  createSwarm(TPort(10237), true, true)
+  createSwarm(TPort(10238), false, true)
+
+var startTime = epochTime()
+while true:
+  if epochTime() - startTime >= 300.0:
+    break
+  if not disp.poll(): break
+  if disp.len == serverCount:
+    # Only the servers are left in the dispatcher. All clients finished,
+    # we need to therefore break.
+    break
+
+assert msgCount == (swarmSize * messagesToSend) * serverCount
+echo(msgCount)
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
new file mode 100644
index 000000000..f77198e2e
--- /dev/null
+++ b/tests/async/tasynctry.nim
@@ -0,0 +1,104 @@
+discard """
+  file: "tasynctry.nim"
+  exitcode: 0
+  output: '''
+Generic except: Test
+Specific except
+Multiple idents in except
+Multiple except branches
+Multiple except branches 2
+'''
+"""
+import asyncdispatch
+
+# Here we are testing the ability to catch exceptions.
+
+proc foobar() {.async.} =
+  if 5 == 5:
+    raise newException(EInvalidIndex, "Test")
+
+proc catch() {.async.} =
+  # TODO: Create a test for when exceptions are not caught.
+  try:
+    await foobar()
+  except:
+    echo("Generic except: ", getCurrentExceptionMsg())
+
+  try:
+    await foobar()
+  except EInvalidIndex:
+    echo("Specific except")
+
+  try:
+    await foobar()
+  except OSError, EInvalidField, EInvalidIndex:
+    echo("Multiple idents in except")
+
+  try:
+    await foobar()
+  except OSError, EInvalidField:
+    assert false
+  except EInvalidIndex:
+    echo("Multiple except branches")
+
+  try:
+    await foobar()
+  except EInvalidIndex:
+    echo("Multiple except branches 2")
+  except OSError, EInvalidField:
+    assert false
+
+asyncCheck catch()
+
+proc test(): Future[bool] {.async.} =
+  result = false
+  try:
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test2(): Future[bool] {.async.} =
+  result = false
+  try:
+    discard await foo()
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc test3(): Future[int] {.async.} =
+  result = 0
+  try:
+    try:
+      discard await foo()
+      raise newException(OSError, "Hello")
+    except:
+      result = 1
+      raise
+  except:
+    result = 2
+    return
+
+proc test4(): Future[int] {.async.} =
+  try:
+    discard await foo()
+    raise newException(ValueError, "Test4")
+  except OSError:
+    result = 1
+  except:
+    result = 2
+
+var x = test()
+assert x.read
+
+x = test2()
+assert x.read
+
+var y = test3()
+assert y.read == 2
+
+y = test4()
+assert y.read == 2
diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim
new file mode 100644
index 000000000..444a058be
--- /dev/null
+++ b/tests/async/tasynctry2.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tasynctry2.nim"
+  errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
+  line: 15
+"""
+import asyncdispatch
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test5(): Future[int] {.async.} =
+  try:
+    discard await foo()
+    raise newException(ValueError, "Test5")
+  except:
+    discard await foo()
+    result = 0
diff --git a/tests/async/tasyncudp.nim b/tests/async/tasyncudp.nim
new file mode 100644
index 000000000..2a7ed40bf
--- /dev/null
+++ b/tests/async/tasyncudp.nim
@@ -0,0 +1,78 @@
+discard """
+  file: "tasyncudp.nim"
+  output: "2000"
+"""
+import asyncio, sockets, strutils, times
+
+const
+  swarmSize = 5
+  messagesToSend = 200
+
+var
+  disp = newDispatcher()
+  msgCount = 0
+  currentClient = 0
+
+proc serverRead(s: PAsyncSocket) =
+  var data = ""
+  var address = ""
+  var port: TPort
+  if s.recvFromAsync(data, 9, address, port):
+    assert address == "127.0.0.1"
+    msgCount.inc()
+  
+  discard """
+  
+  var line = ""
+  assert s.recvLine(line)
+  
+  if line == "":
+    assert(false)
+  else:
+    if line.startsWith("Message "):
+      msgCount.inc()
+    else:
+      assert(false)
+  """
+
+proc swarmConnect(s: PAsyncSocket) =
+  for i in 1..messagesToSend:
+    s.send("Message\c\L")
+
+proc createClient(disp: var PDispatcher, port: TPort,
+                  buffered = true) =
+  currentClient.inc()
+  var client = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
+                           buffered = buffered)
+  client.handleConnect = swarmConnect
+  disp.register(client)
+  client.connect("localhost", port)
+
+proc createServer(port: TPort, buffered = true) =
+  var server = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
+                           buffered = buffered)
+  server.handleRead = serverRead
+  disp.register(server)
+  server.bindAddr(port)
+
+let serverCount = 2
+
+createServer(TPort(10335), false)
+createServer(TPort(10336), true)
+var startTime = epochTime()
+while true:
+  if epochTime() - startTime >= 300.0:
+    break
+
+  if not disp.poll():
+    break
+  
+  if (msgCount div messagesToSend) * serverCount == currentClient:
+    createClient(disp, TPort(10335), false)
+    createClient(disp, TPort(10336), true)
+  
+  if msgCount == messagesToSend * serverCount * swarmSize:
+    break
+
+assert msgCount == messagesToSend * serverCount * swarmSize
+echo(msgCount)
diff --git a/tests/async/tnestedpfuturetypeparam.nim b/tests/async/tnestedpfuturetypeparam.nim
new file mode 100644
index 000000000..bf346ff8e
--- /dev/null
+++ b/tests/async/tnestedpfuturetypeparam.nim
@@ -0,0 +1,8 @@
+import asyncdispatch, asyncnet
+
+proc main {.async.} =
+  proc f: Future[seq[int]] {.async.} =
+    await newAsyncSocket().connect("www.google.com", Port(80))
+  let x = await f()
+
+asyncCheck main()
diff --git a/tests/benchmark.nim b/tests/benchmark.nim
new file mode 100644
index 000000000..0613d1bf9
--- /dev/null
+++ b/tests/benchmark.nim
@@ -0,0 +1,47 @@
+#
+#
+#            Nim Benchmark tool
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This program runs benchmarks
+import osproc, os, times, json
+
+type
+  TBenchResult = tuple[file: string, success: bool, time: float]
+
+proc compileBench(file: string) =
+  ## Compiles ``file``.
+  doAssert(execCmdEx("nim c -d:release " & file).exitCode == QuitSuccess)
+
+proc runBench(file: string): TBenchResult =
+  ## Runs ``file`` and returns info on how long it took to run.
+  var start = epochTime()
+  if execCmdEx(file.addFileExt(ExeExt)).exitCode == QuitSuccess:
+    var t = epochTime() - start
+    result = (file, true, t)
+  else: result = (file, false, -1.0)
+
+proc genOutput(benches: seq[TBenchResult]): PJsonNode =
+  result = newJObject()
+  for i in benches:
+    if i.success:
+      result[i.file.extractFilename] = newJFloat(i.time)
+    else:
+      result[i.file.extractFilename] = newJNull()
+
+proc doBench(): seq[TBenchResult] =
+  result = @[]
+  for i in walkFiles("tests/benchmarks/*.nim"):
+    echo(i.extractFilename)
+    compileBench(i)
+    result.add(runBench(i))
+
+when isMainModule:
+  var b = doBench()
+  var output = genOutput(b)
+  writeFile("benchmarkResults.json", pretty(output))
+  
\ No newline at end of file
diff --git a/tests/benchmarks/fannkuch.nim b/tests/benchmarks/fannkuch.nim
new file mode 100644
index 000000000..15f78f50c
--- /dev/null
+++ b/tests/benchmarks/fannkuch.nim
@@ -0,0 +1,69 @@
+import os
+import strutils
+
+proc fannkuch (n: int): int =
+    var 
+        count: seq[int]
+        maxFlips = 0
+        m        = n-1
+        r        = n
+        check    = 0
+        perm1: seq[int]
+        perm:  seq[int]
+
+    newSeq (count, n+1)
+    newSeq (perm1, n)
+    newSeq (perm, n)
+    for i in 0 .. n-1:
+        count[i] = i+1
+        perm1[i] = i
+        perm[i]  = i
+    count[n] = n+1
+
+    while True:
+        if check < 30:
+            for i in items (perm1):
+                write (stdout, $(i+1))
+            echo ("")
+            inc (check)
+
+        while r != 1:
+            count[r-1] = r
+            dec (r)
+
+        if perm1[0] != 0 and perm1[m] != m:
+            # perm = perm1
+            # The above line is between 3 and 4 times slower than the loop below!
+            for i in 0 .. n-1:
+                perm[i] = perm1[i]
+            var flipsCount = 0
+            var k = perm[0]
+            while k != 0:
+                for i in 0 .. (k div 2):
+                    swap (perm[i], perm[k-i])
+                inc (flipsCount)
+                k = perm[0]
+
+            if flipsCount > maxFlips:
+                maxFlips = flipsCount
+
+        block makePerm:
+            while r != n:
+                var tmp = perm1[0]
+                # # perm1.delete (0)
+                # # perm1.insert (tmp, r)
+                # # The above is about twice as slow as the following:
+                # moveMem (addr (perm1[0]), addr (perm1[1]), r * sizeof (int))
+                # The call to moveMem is about 50% slower than the loop below!
+                for i in 0 .. r-1:
+                    perm1[i] = perm1[i+1]
+                perm1[r] = tmp
+                
+                dec (count[r])
+                if count[r] > 0:
+                    break makePerm
+                inc (r)
+            return maxFlips
+
+var n = 10
+echo ("Pfannkuchen(" & $n & ") = " & $fannkuch (n))
\ No newline at end of file
diff --git a/tests/benchmarks/quicksort.nim b/tests/benchmarks/quicksort.nim
new file mode 100644
index 000000000..599e3674c
--- /dev/null
+++ b/tests/benchmarks/quicksort.nim
@@ -0,0 +1,54 @@
+import os
+import strutils
+
+# Generate some pseudo-random data
+var seed: tuple[s1, s2, s3: int32] = (2'i32, 8'i32, 16'i32)
+
+proc random(): int32 =
+    seed = (((((((seed[0] and 0x0007_FFFF'i32) shl 13'i32) xor seed[0]) shr
+               19'i32) and 0x0000_1FFF'i32) xor
+             ((seed[0] and 0x000F_FFFE'i32) shl 12'i32)),
+
+            ((((((seed[1] and 0x3FFF_FFFF'i32) shl  2'i32) xor seed[1]) shr
+               25'i32) and 0x0000_007F'i32) xor
+             ((seed[1] and 0x0FFF_FFF8'i32) shl  4'i32)),
+
+            ((((((seed[2] and 0x1FFF_FFFF'i32) shl  3'i32) xor seed[2]) shr
+               11'i32) and 0x001F_FFFF'i32) xor
+             ((seed[2] and 0x0000_7FF0'i32) shl 17'i32)))
+    return seed[0] xor seed[1] xor seed[2]
+
+var n = 9999999
+
+var data: seq[int32]
+newSeq (data, n)
+for i in 0 .. data.high():
+    data[i] = random()
+
+
+proc `$` (d: seq[int32]): string =
+    result = "[ "
+    for i in items (d):
+        result.addSep (", ", 2)
+        result.add ($(i and 0xFFFF_FFFF'i64))
+    result.add (" ]")
+
+# Sort the data
+proc sort (start, stop: int) =
+    if stop <= start+1:
+        return
+
+    var j = start
+    for i in start..stop-2:
+        if data[i] <% data[stop-1]:
+            swap (data[i], data[j])
+            inc (j)
+    swap (data[j], data[stop-1])
+
+    sort (start, j)
+    sort (j+1, stop)
+
+sort (0, data.len)
+echo (data[n div 2 - 1] and 0xFFFF_FFFF'i64, ", ",
+      data[n div 2] and 0xFFFF_FFFF'i64, ", ",
+      data[n div 2 + 1] and 0xFFFF_FFFF'i64)
\ No newline at end of file
diff --git a/tests/bind/mbind3.nim b/tests/bind/mbind3.nim
new file mode 100644
index 000000000..d02bc79d0
--- /dev/null
+++ b/tests/bind/mbind3.nim
@@ -0,0 +1,10 @@
+# Module A
+var 
+  lastId = 0
+
+template genId*: expr =
+  bind lastId
+  inc(lastId)
+  lastId
+
+
diff --git a/tests/bind/tbind1.nim b/tests/bind/tbind1.nim
new file mode 100644
index 000000000..6593b2307
--- /dev/null
+++ b/tests/bind/tbind1.nim
@@ -0,0 +1,21 @@
+discard """
+  file: "tbind1.nim"
+  output: "3"
+"""
+# Test the new ``bind`` keyword for templates
+
+proc p1(x: int8, y: int): int = return x + y
+
+template tempBind(x, y: expr): expr = 
+  bind p1
+  p1(x, y) 
+
+proc p1(x: int, y: int8): int = return x - y
+
+# This is tricky: the call to ``p1(1'i8, 2'i8)`` should not fail in line 6, 
+# because it is not ambiguous there. But it is ambiguous after line 8. 
+
+echo tempBind(1'i8, 2'i8) #OUT 3
+
+
+
diff --git a/tests/bind/tbind2.nim b/tests/bind/tbind2.nim
new file mode 100644
index 000000000..e8e21ad02
--- /dev/null
+++ b/tests/bind/tbind2.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tbind2.nim"
+  line: 14
+  errormsg: "ambiguous call"
+"""
+# Test the new ``bind`` keyword for templates
+
+proc p1(x: int8, y: int): int = return x + y
+proc p1(x: int, y: int8): int = return x - y
+
+template tempBind(x, y: expr): expr = 
+  (bind p1(x, y))  #ERROR_MSG ambiguous call
+
+echo tempBind(1'i8, 2'i8)
+
+
+
diff --git a/tests/bind/tbind3.nim b/tests/bind/tbind3.nim
new file mode 100644
index 000000000..551acc10f
--- /dev/null
+++ b/tests/bind/tbind3.nim
@@ -0,0 +1,11 @@
+discard """
+  file: "tbind3.nim"
+  output: "1"
+"""
+# Module B
+import mbind3
+
+echo genId() #OUT 1
+
+
+
diff --git a/tests/bind/tbindoverload.nim b/tests/bind/tbindoverload.nim
new file mode 100644
index 000000000..6f5bb339e
--- /dev/null
+++ b/tests/bind/tbindoverload.nim
@@ -0,0 +1,12 @@
+import strtabs
+
+template t*() =
+  block:
+    bind newStringTable
+    discard {"Content-Type": "text/html"}.newStringTable()
+
+    discard {:}.newStringTable
+
+#discard {"Content-Type": "text/html"}.newStringTable()
+
+t()
diff --git a/tests/bind/tdatabind.nim b/tests/bind/tdatabind.nim
new file mode 100644
index 000000000..afa8aa47b
--- /dev/null
+++ b/tests/bind/tdatabind.nim
@@ -0,0 +1,95 @@
+discard """
+  disabled: true
+"""
+
+import events
+type
+  TProperty*[T] = object of TObject
+    getProc: proc(property: TProperty[T]): T {.nimcall.}
+    setProc: proc(property: var TProperty[T], value: T) {.nimcall.}
+    value: T
+    ValueChanged*: TEventHandler
+    Binders: seq[TProperty[T]]
+    EEmitter: TEventEmitter
+  # Not a descriptive name but it was that or TPropertyValueChangeEventArgs.
+  TValueEventArgs[T] = object of TEventArgs
+    Property*: TProperty[T]
+
+
+proc newProperty*[T](value: T): TProperty[T] =
+  var prop: TProperty[T]
+
+  prop.EEmitter = initEventEmitter()
+  prop.Binders = @[]
+  prop.ValueChanged = initEventHandler("ValueChanged")
+  prop.value = value
+
+  proc getter(property: TProperty[T]): T =
+   return property.value
+
+  prop.getProc = getter
+
+  proc setter(property: var TProperty[T], v: T) =
+    property.value = v
+    
+    # fire event here
+    var args: TValueEventArgs[T]
+    args.Property = property
+    property.EEmitter.emit(property.ValueChanged, args)
+  
+  prop.setProc = setter
+   
+  return prop
+
+proc `prop`[T] (p: TProperty[T]): T =
+  # I'm assuming this is trying to get a value from the property.
+  # i.e. myVar = myProperty
+  return p.getProc(p)
+
+proc `~=`[T] (p: var TProperty[T], v: T) =
+  # Assuming this is setting the value.
+  p.setProc(p, v)
+
+proc `$`[T] (p: TProperty[T]): string =
+  var value = p.getProc(p)
+  return $value
+
+proc propertyBind*[T](p1: var TProperty[T], p2: var TProperty[T]) =
+  p1.Binders.add(p2)
+  
+  # make handler -> handler[T] so trigger even more generics bugs ...
+  proc handler(e: TEventArgs) =
+    type TEA = TValueEventArgs[T]
+    var args = TEA(e)
+    var val = args.Property.getProc(p1)
+    for i in countup(0, len(e.Property.ValueChanged.Binders) -1):
+      var binded = e.Property.ValueChanged.Binders[i]
+      binded.setProc(binded, val)
+
+    echo("Property 1 has changed to " & $val)
+
+  if p1.ValueChanged.containsHandler(handler) == false:
+    addHandler(p1.ValueChanged, handler)
+
+proc `->`[T](p1: var TProperty[T], p2: var TProperty[T]) =
+  propertyBind(p2,p1)
+
+when isMainModule:
+  # Initial value testing
+  var myProp = newProperty(5)
+  
+  echo(myProp)
+  
+  myProp ~= 7 # Temp operator until overloading of '=' is implemented.
+  echo(myProp)
+
+  # Binding testing
+
+  var prop1 = newProperty(9)
+  var prop2: TProperty[int]
+
+  prop2 -> prop1 # Binds prop2 to prop1
+
+  prop1 ~= 7
+  echo(prop2) # Output: 7
+
diff --git a/tests/bind/tinvalidbindtypedesc.nim b/tests/bind/tinvalidbindtypedesc.nim
new file mode 100644
index 000000000..5b2f51110
--- /dev/null
+++ b/tests/bind/tinvalidbindtypedesc.nim
@@ -0,0 +1,11 @@
+discard """
+  line: 10
+  errormsg: "type mismatch: got (typedesc[float], string)"
+"""
+
+proc foo(T: typedesc; some: T) =
+  echo($some)
+
+foo int, 4
+foo float, "bad"
+
diff --git a/tests/bind/tmixin.nim b/tests/bind/tmixin.nim
new file mode 100644
index 000000000..d841326a5
--- /dev/null
+++ b/tests/bind/tmixin.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "1\n2"
+"""
+
+type
+  TFoo1 = object of TObject
+    v: int
+  TFoo2 = object of TFoo1
+    v2: int
+
+proc test(f: TFoo1) =
+  echo "1"
+
+proc Foo[T](f: T) =
+  mixin test
+  test(f)
+
+var
+  a: TFoo1
+  b: TFoo2
+
+
+proc test(f: TFoo2) =
+  echo "2"
+
+Foo(a)
+Foo(b)
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
new file mode 100644
index 000000000..5145fdcff
--- /dev/null
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -0,0 +1,18 @@
+discard """
+  line: 18
+  errormsg: "type mismatch: got (proc (s: TScgi) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.gcsafe, locks: 0.}"
+"""
+
+#bug #442
+import scgi, sockets, asyncio, strtabs
+proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) =
+  discard
+proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
+                       input: string) =
+  discard
+
+proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
+                        input: string), b: int) =
+  discard
+
+test(handleSCGIRequest)
diff --git a/tests/borrow/tborrow.nim b/tests/borrow/tborrow.nim
new file mode 100644
index 000000000..d4df5f524
--- /dev/null
+++ b/tests/borrow/tborrow.nim
@@ -0,0 +1,21 @@
+discard """
+  output: "4887 true"
+"""
+
+# test the new borrow feature that works with generics:
+
+proc `++`*[T: int | float](a, b: T): T =
+  result = a + b
+  
+type
+  DI = distinct int
+  DF = distinct float
+  DS = distinct string
+  
+proc `++`(x, y: DI): DI {.borrow.}
+proc `++`(x, y: DF): DF {.borrow.}
+
+proc `$`(x: DI): string {.borrow.}
+proc `$`(x: DF): string {.borrow.}
+
+echo  4544.DI ++ 343.DI, " ", (4.5.DF ++ 0.5.DF).float == 5.0
diff --git a/tests/borrow/tinvalidborrow.nim b/tests/borrow/tinvalidborrow.nim
new file mode 100644
index 000000000..9ab9e8d64
--- /dev/null
+++ b/tests/borrow/tinvalidborrow.nim
@@ -0,0 +1,17 @@
+discard """
+  line: 11
+  errormsg: "no symbol to borrow from found"
+"""
+
+# bug #516
+
+type
+  TAtom = culong
+
+proc `==`*(a, b: TAtom): bool {.borrow.}
+
+var
+  d, e: TAtom
+
+echo( $(d == e) )
+
diff --git a/tests/caas/absurd_nesting.nim b/tests/caas/absurd_nesting.nim
new file mode 100644
index 000000000..136d65cc7
--- /dev/null
+++ b/tests/caas/absurd_nesting.nim
@@ -0,0 +1,29 @@
+# Tries to test the full ownership path generated by idetools.
+
+proc lev1(t1: string) =
+  var temp = t1
+  for i in 0..len(temp)-1:
+    temp[i] = chr(int(temp[i]) + 1)
+
+  proc lev2(t2: string) =
+    var temp = t2
+    for i in 0..len(temp)-1:
+      temp[i] = chr(int(temp[i]) + 1)
+
+    proc lev3(t3: string) =
+      var temp = t3
+      for i in 0..len(temp)-1:
+        temp[i] = chr(int(temp[i]) + 1)
+
+      proc lev4(t4: string) =
+        var temp = t4
+        for i in 0..len(temp)-1:
+          temp[i] = chr(int(temp[i]) + 1)
+
+        echo temp & "(lev4)"
+      lev4(temp & "(lev3)")
+    lev3(temp & "(lev2)")
+  lev2(temp & "(lev1)")
+
+when isMainModule:
+  lev1("abcd")
diff --git a/tests/caas/absurd_nesting.txt b/tests/caas/absurd_nesting.txt
new file mode 100644
index 000000000..986e34836
--- /dev/null
+++ b/tests/caas/absurd_nesting.txt
@@ -0,0 +1,29 @@
+absurd_nesting.nim
+
+> c --verbosity:0 --hints:on
+SuccessX
+
+> idetools --track:$TESTNIM,6,6 --def $SILENT
+skVar\tabsurd_nesting.lev1.temp\tstring
+
+> idetools --track:$TESTNIM,21,13 --def $SILENT
+skVar\tabsurd_nesting.lev1.lev2.lev3.lev4.temp\tstring
+
+> idetools --track:$TESTNIM,6,27 --def $SILENT
+skForVar\tabsurd_nesting.lev1.i\tint
+
+> idetools --track:$TESTNIM,21,33 --def $SILENT
+skForVar\tabsurd_nesting.lev1.lev1.lev3.lev4.i\tint
+
+> idetools --track:$TESTNIM,24,8 --def $SILENT
+skProc\tabsurd_nesting.lev1.lev1.lev3.lev4\tproc \(string\)
+
+> idetools --track:$TESTNIM,4,13 --def $SILENT
+skParam\tabsurd_nesting.lev1.t1\tstring
+
+> idetools --track:$TESTNIM,4,13 --def $SILENT
+skParam\tabsurd_nesting.lev1.t1\tstring
+
+> idetools --track:$TESTNIM,19,19 --def $SILENT
+skParam\tabsurd_nesting.lev1.lev2.lev3.lev4.t4\tstring
+
diff --git a/tests/caas/basic-recompile.txt b/tests/caas/basic-recompile.txt
new file mode 100644
index 000000000..620e0c059
--- /dev/null
+++ b/tests/caas/basic-recompile.txt
@@ -0,0 +1,10 @@
+main.nim
+> c --verbosity:0 --hints:on
+SuccessX
+# The "Processing" string will be found always in proc mode since each
+# compilation command will generate it. We need to test it only in Caas mode to
+# verify the server is not recompiling again the file.
+CaasRun > c --verbosity:0 --hints:on
+CaasRun ! Processing
+CaasRun SuccessX
+
diff --git a/tests/caas/compile-suggest.txt b/tests/caas/compile-suggest.txt
new file mode 100644
index 000000000..378320014
--- /dev/null
+++ b/tests/caas/compile-suggest.txt
@@ -0,0 +1,7 @@
+main.nim
+> c --verbosity:0 --hints:on
+SuccessX
+> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
+skField\tx
+skField\ty
+
diff --git a/tests/caas/compile-then-def.txt b/tests/caas/compile-then-def.txt
new file mode 100644
index 000000000..72ba46b04
--- /dev/null
+++ b/tests/caas/compile-then-def.txt
@@ -0,0 +1,11 @@
+main.nim
+> c --verbosity:0 --hints:on
+SuccessX
+
+> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
+strutils.toUpper
+! SuccessX
+
+> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
+strutils.toUpper
+! SuccessX
diff --git a/tests/caas/completion_dot_syntax.txt b/tests/caas/completion_dot_syntax.txt
new file mode 100644
index 000000000..4a975e5df
--- /dev/null
+++ b/tests/caas/completion_dot_syntax.txt
@@ -0,0 +1,9 @@
+completion_dot_syntax_main.nim
+> idetools --track:$TESTNIM,24,15 --def
+def\tskProc\t$MODULE.echoRemainingDollars
+> idetools --trackDirty:completion_dot_syntax_dirty.nim,$TESTNIM,25,12 --suggest
+sug\tskProc\techoRemainingDollars
+# The suggestion should not mention the other echoRemaining* variants.
+!echoRemainingEuros
+!echoRemainingBugs
+
diff --git a/tests/caas/completion_dot_syntax_dirty.nim b/tests/caas/completion_dot_syntax_dirty.nim
new file mode 100644
index 000000000..6237c4e79
--- /dev/null
+++ b/tests/caas/completion_dot_syntax_dirty.nim
@@ -0,0 +1,25 @@
+import strutils
+
+# Verifies if the --suggestion switch differentiates types for dot notation.
+
+type
+  TDollar = distinct int
+  TEuro = distinct int
+
+proc echoRemainingDollars(amount: TDollar) =
+  echo "You have $1 dollars" % [$int(amount)]
+
+proc echoRemainingEuros(amount: TEuro) =
+  echo "You have $1 euros" % [$int(amount)]
+
+proc echoRemainingBugs() =
+  echo "You still have bugs"
+
+proc main =
+  var
+    d: TDollar
+    e: TEuro
+  d = TDollar(23)
+  e = TEuro(32)
+  d.echoRemainingDollars()
+  e.echoRemai
diff --git a/tests/caas/completion_dot_syntax_main.nim b/tests/caas/completion_dot_syntax_main.nim
new file mode 100644
index 000000000..0be8c7f4f
--- /dev/null
+++ b/tests/caas/completion_dot_syntax_main.nim
@@ -0,0 +1,24 @@
+import strutils
+
+# Verifies if the --suggestion switch differentiates types for dot notation.
+
+type
+  TDollar = distinct int
+  TEuro = distinct int
+
+proc echoRemainingDollars(amount: TDollar) =
+  echo "You have $1 dollars" % [$int(amount)]
+
+proc echoRemainingEuros(amount: TEuro) =
+  echo "You have $1 euros" % [$int(amount)]
+
+proc echoRemainingBugs() =
+  echo "You still have bugs"
+
+proc main =
+  var
+    d: TDollar
+    e: TEuro
+  d = TDollar(23)
+  e = TEuro(32)
+  d.echoRemainingDollars()
diff --git a/tests/caas/def-def-compile.txt b/tests/caas/def-def-compile.txt
new file mode 100644
index 000000000..21d5ea962
--- /dev/null
+++ b/tests/caas/def-def-compile.txt
@@ -0,0 +1,12 @@
+main.nim
+> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
+strutils.toUpper
+! SuccessX
+
+> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
+strutils.toUpper
+! SuccessX
+
+> c --verbosity:0 --hints:on
+SuccessX
+
diff --git a/tests/caas/def-then-compile.txt b/tests/caas/def-then-compile.txt
new file mode 100644
index 000000000..2214bf02c
--- /dev/null
+++ b/tests/caas/def-then-compile.txt
@@ -0,0 +1,8 @@
+main.nim
+> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
+strutils.toUpper
+! SuccessX
+
+> c --verbosity:0 --hints:on
+SuccessX
+
diff --git a/tests/caas/forward_declarations.nim b/tests/caas/forward_declarations.nim
new file mode 100644
index 000000000..177d82f20
--- /dev/null
+++ b/tests/caas/forward_declarations.nim
@@ -0,0 +1,15 @@
+# This example shows that idetools returns an empty signature for a forward
+# declared proc in proc/symproc runs, but correctly returns the full signature
+# in caas mode.
+
+proc echoHello(text: string)
+
+proc testForward() =
+  echo "T"
+  echoHello("T")
+
+proc echoHello(text: string) =
+  echo "Hello Mr." & text
+
+when isMainModule:
+  testForward()
diff --git a/tests/caas/forward_declarations.txt b/tests/caas/forward_declarations.txt
new file mode 100644
index 000000000..b1695b9c7
--- /dev/null
+++ b/tests/caas/forward_declarations.txt
@@ -0,0 +1,9 @@
+forward_declarations.nim
+
+> idetools --track:$TESTNIM,9,5 --def $SILENT
+skProc
+proc \(string\)
+
+> idetools --track:$TESTNIM,5,9 --def $SILENT
+skProc
+proc \(string\)
diff --git a/tests/caas/forward_usages.txt b/tests/caas/forward_usages.txt
new file mode 100644
index 000000000..05ef517dc
--- /dev/null
+++ b/tests/caas/forward_usages.txt
@@ -0,0 +1,17 @@
+forward_declarations.nim
+
+> c --verbosity:0 --hints:on
+SuccessX
+
+# None of the following return three instances of the echoHello proc, the first
+# being the forward declaration, the second being the usage inside testForward,
+# and the third being the actual implementation.
+
+> idetools --track:$TESTNIM,5,5 --usages $SILENT
+skProc.*\n.*skProc.*\n.*skProc
+
+> idetools --track:$TESTNIM,9,5 --usages $SILENT
+skProc.*\n.*skProc.*\n.*skProc
+
+> idetools --track:$TESTNIM,11,5 --usages $SILENT
+skProc.*\n.*skProc.*\n.*skProc
diff --git a/tests/caas/idetools_api.nim b/tests/caas/idetools_api.nim
new file mode 100644
index 000000000..281e562d7
--- /dev/null
+++ b/tests/caas/idetools_api.nim
@@ -0,0 +1,84 @@
+import unicode, sequtils, macros, re
+
+proc test_enums() =
+  var o: Tfile
+  if o.open("files " & "test.txt", fmWrite):
+    o.write("test")
+    o.close()
+
+proc test_iterators(filename = "tests.nim") =
+  let
+    input = readFile(filename)
+    letters = toSeq(runes(string(input)))
+  for letter in letters: echo int(letter)
+
+const SOME_SEQUENCE = @[1, 2]
+type
+  bad_string = distinct string
+  TPerson = object of TObject
+    name*: bad_string
+    age: int
+
+proc adder(a, b: int): int =
+  result = a + b
+
+type
+  PExpr = ref object of TObject ## abstract base class for an expression
+  PLiteral = ref object of PExpr
+    x: int
+  PPlusExpr = ref object of PExpr
+    a, b: PExpr
+
+# watch out: 'eval' relies on dynamic binding
+method eval(e: PExpr): int =
+  # override this base method
+  quit "to override!"
+
+method eval(e: PLiteral): int = e.x
+method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
+
+proc newLit(x: int): PLiteral = PLiteral(x: x)
+proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
+
+echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
+
+proc findVowelPosition(text: string) =
+  var found = -1
+  block loops:
+    for i, letter in pairs(text):
+      for j in ['a', 'e', 'i', 'o', 'u']:
+        if letter == j:
+          found = i
+          break loops # leave both for-loops
+  echo found
+
+findVowelPosition("Zerg") # should output 1, position of vowel.
+
+macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
+  ## Expect docstrings
+  let exp = callsite()
+  template expectBody(errorTypes, lineInfoLit: expr,
+                      body: stmt): NimNode {.dirty.} =
+    try:
+      body
+      assert false
+    except errorTypes:
+      nil
+
+  var body = exp[exp.len - 1]
+
+  var errorTypes = newNimNode(nnkBracket)
+  for i in countup(1, exp.len - 2):
+    errorTypes.add(exp[i])
+
+  result = getAst(expectBody(errorTypes, exp.lineinfo, body))
+
+proc err =
+  raise newException(EArithmetic, "some exception")
+
+proc testMacro() =
+  expect(EArithmetic):
+    err()
+
+testMacro()
+let notAModule = re"(\w+)=(.*)"
diff --git a/tests/caas/idetools_api.txt b/tests/caas/idetools_api.txt
new file mode 100644
index 000000000..035590dc3
--- /dev/null
+++ b/tests/caas/idetools_api.txt
@@ -0,0 +1,59 @@
+idetools_api.nim
+> c --verbosity:0 --hints:on
+SuccessX
+> idetools --track:$TESTNIM,4,11 --def $SILENT
+def\tskType\tsystem.TFile\tTFile
+> idetools --track:$TESTNIM,5,7 --def $SILENT
+def\tskProc\tsystem.Open\tproc \(var TFile, string, TFileMode, int\): bool
+> idetools --track:$TESTNIM,5,21 --def $SILENT
+def\tskProc\tsystem.\&\tproc \(string, string\): string\{.noSideEffect.\}
+> idetools --track:$TESTNIM,5,38 --def $SILENT
+def\tskEnumField\tsystem.TFileMode.fmWrite\tTFileMode
+> idetools --track:$TESTNIM,7,6 --def $SILENT
+def\tskProc\tsystem.Close\tproc \(TFile\)
+> idetools --track:$TESTNIM,12,23 --def $SILENT
+def\tskIterator\tunicode.runes\titerator \(string\): TRune
+> idetools --track:$TESTNIM,12,15 --def $SILENT
+def\tskTemplate\tsequtils.toSeq\tproc \(expr\): expr
+> idetools --track:$TESTNIM,15,7 --def $SILENT
+
+# ProcRun mode will fail the next line, because the type is returned empty.
+def\tskConst\t$MODULE.SOME_SEQUENCE\tseq\[int\]\t
+> idetools --track:$TESTNIM,15,23 --def $SILENT
+def\tskProc\tsystem.@\tproc \(array\[IDX, T\]\): seq\[T\]\{.noSideEffect.\}
+> idetools --track:$TESTNIM,17,3 --def $SILENT
+
+# ProcRun mode will fail the next line, because the type is returned empty.
+def\tskType\t$MODULE.bad_string\tbad_string\t
+> idetools --track:$TESTNIM,11,24 --def $SILENT
+def\tskParam\t$MODULE.test_iterators.filename\tstring
+> idetools --track:$TESTNIM,6,5 --def $SILENT
+def\tskVar\t$MODULE.test_enums.o\tTFile
+> idetools --track:$TESTNIM,12,34 --def $SILENT
+def\tskLet\t$MODULE.test_iterators.input\tTaintedString
+> idetools --track:$TESTNIM,13,35 --def $SILENT
+def\tskForVar\t$MODULE.test_iterators.letter\tTRune
+> idetools --track:$TESTNIM,23,3 --def $SILENT
+def\tskResult\t$MODULE.adder.result\tint
+> idetools --track:$TESTNIM,19,6 --def $SILENT
+
+# ProcRun mode will fail the next line, because the type is returned empty.
+def\tskField\t$MODULE.TPerson.name\tbad_string\t
+
+> idetools --track:$TESTNIM,43,7 --def $SILENT
+def\tskMethod\t$MODULE.eval\tproc \(PPlusExpr\): int\t
+
+> idetools --track:$TESTNIM,47,8 --def $SILENT
+def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
+# For some reason the use of the label with break displaces its position.
+> idetools --track:$TESTNIM,52,16 --def $SILENT
+def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
+
+# Displaced macro usage by one character.
+> idetools --track:$TESTNIM,80,2 --def $SILENT
+def\tskMacro\t$MODULE.expect\tproc \(varargs\[expr\], stmt\): stmt\t
+
+# The syntax for extended raw string literals should not be returned as module
+# but as the proc re() inside the re module.
+> idetools --track:$TESTNIM,84,17 --def $SILENT
+!def\tskModule
diff --git a/tests/caas/imported.nim b/tests/caas/imported.nim
new file mode 100644
index 000000000..a4bc5c0e6
--- /dev/null
+++ b/tests/caas/imported.nim
@@ -0,0 +1,3 @@
+proc `+++`*(a,b: string): string =
+  return a & "  " & b
+
diff --git a/tests/caas/issue_416_template_shift.nim b/tests/caas/issue_416_template_shift.nim
new file mode 100644
index 000000000..d52f611d6
--- /dev/null
+++ b/tests/caas/issue_416_template_shift.nim
@@ -0,0 +1,17 @@
+import unicode, sequtils
+
+proc test() =
+  let input = readFile("weird.nim")
+  for letter in runes(string(input)):
+    echo int(letter)
+
+when 1 > 0:
+  proc failtest() =
+    let
+      input = readFile("weird.nim")
+      letters = toSeq(runes(string(input)))
+    for letter in letters:
+      echo int(letter)
+
+when isMainModule:
+  test()
diff --git a/tests/caas/issue_416_template_shift.txt b/tests/caas/issue_416_template_shift.txt
new file mode 100644
index 000000000..e911c1360
--- /dev/null
+++ b/tests/caas/issue_416_template_shift.txt
@@ -0,0 +1,14 @@
+issue_416_template_shift.nim
+> c --verbosity:0 --hints:on
+SuccessX
+> idetools --track:$TESTNIM,12,28 --def $SILENT
+def\tskType\tsystem.string\tstring
+> idetools --track:$TESTNIM,12,35 --def $SILENT
+def\tskLet\t$MODULE.failtest.input\tTaintedString
+
+# The following fail because they seem shifted one column to the right.
+> idetools --track:$TESTNIM,12,16 --def $SILENT
+def\tskTemplate\tsequtils.toSeq\tproc \(expr\): expr
+> idetools --track:$TESTNIM,12,22 --def $SILENT
+def\tskIterator\tunicode.runes\titerator \(string\): TRune
+
diff --git a/tests/caas/issue_452_export_shift.nim b/tests/caas/issue_452_export_shift.nim
new file mode 100644
index 000000000..46cff6241
--- /dev/null
+++ b/tests/caas/issue_452_export_shift.nim
@@ -0,0 +1,8 @@
+const
+  VERSION_STR1* = "0.5.0" ## Idetools shifts this one column.
+  VERSION_STR2 = "0.5.0" ## This one is ok.
+  VERSION_STR3* = "0.5.0" ## Bad.
+  VERSION_STR4 = "0.5.0" ## Ok.
+
+proc forward1*(): string = result = ""
+proc forward2(): string = result = ""
diff --git a/tests/caas/issue_452_export_shift.txt b/tests/caas/issue_452_export_shift.txt
new file mode 100644
index 000000000..4676ed71e
--- /dev/null
+++ b/tests/caas/issue_452_export_shift.txt
@@ -0,0 +1,11 @@
+issue_452_export_shift.nim
+> c --verbosity:0 --hints:on
+SuccessX
+> idetools --track:$TESTNIM,2,2 --def $SILENT
+def\tskConst\t$MODULE.VERSION_STR1\tstring
+> idetools --track:$TESTNIM,3,2 --def $SILENT
+def\tskConst\t$MODULE.VERSION_STR2\tstring
+> idetools --track:$TESTNIM,7,5 --def $SILENT
+def\tskProc\t$MODULE.forward1\tproc \(\): string\t
+> idetools --track:$TESTNIM,8,5 --def $SILENT
+def\tskProc\t$MODULE.forward2\tproc \(\): string\t
diff --git a/tests/caas/issue_477_dynamic_dispatch.nim b/tests/caas/issue_477_dynamic_dispatch.nim
new file mode 100644
index 000000000..6e6b21ef0
--- /dev/null
+++ b/tests/caas/issue_477_dynamic_dispatch.nim
@@ -0,0 +1,19 @@
+type
+  TThing = object of TObject
+  TUnit = object of TThing
+    x: int
+
+method collide(a, b: TThing) {.inline.} =
+  quit "to override!"
+
+method collide(a: TThing, b: TUnit) {.inline.} =
+  echo "collide1"
+
+method collide(a: TUnit, b: TThing) {.inline.} =
+  echo "collide2"
+
+var
+  a, b: TUnit
+
+when isMainModule:
+  collide(a, b) # output: 2
diff --git a/tests/caas/issue_477_dynamic_dispatch.txt b/tests/caas/issue_477_dynamic_dispatch.txt
new file mode 100644
index 000000000..12fd750de
--- /dev/null
+++ b/tests/caas/issue_477_dynamic_dispatch.txt
@@ -0,0 +1,5 @@
+issue_477_dynamic_dispatch.nim
+> c --run
+SuccessX
+> idetools --track:issue_477_dynamic_dispatch.nim,19,5 --def $SILENT
+def\tskMethod\tissue_477_dynamic_dispatch.collide\tproc \(TUnit, TThing\)\{.inline.\}
diff --git a/tests/caas/its_full_of_procs.nim b/tests/caas/its_full_of_procs.nim
new file mode 100644
index 000000000..8f8b66764
--- /dev/null
+++ b/tests/caas/its_full_of_procs.nim
@@ -0,0 +1,29 @@
+import unicode, sequtils
+
+# This example shows that idetools returns proc as signature for everything
+# which can be called. While a clever person would use the second column to
+# differentiate between procs, methods and others, why does the output contain
+# incorrect information?
+
+type
+  TThing = object of TObject
+  TUnit = object of TThing
+    x: int
+
+method collide(a, b: TThing) {.inline.} =
+  quit "to override!"
+
+method collide(a: TThing, b: TUnit) {.inline.} =
+  echo "1"
+
+method collide(a: TUnit, b: TThing) {.inline.} =
+  echo "2"
+
+var
+  a, b: TUnit
+
+let
+  input = readFile("its_full_of_procs.nim")
+  letters = toSeq(runes(string(input)))
+
+collide(a, b) # output: 2
diff --git a/tests/caas/its_full_of_procs.txt b/tests/caas/its_full_of_procs.txt
new file mode 100644
index 000000000..31a2d3baa
--- /dev/null
+++ b/tests/caas/its_full_of_procs.txt
@@ -0,0 +1,20 @@
+its_full_of_procs.nim
+
+> idetools --track:$TESTNIM,26,15 --def $SILENT
+skProc
+proc \(
+
+> idetools --track:$TESTNIM,27,21 --def $SILENT
+skIterator
+iterator \(
+!proc \(
+
+> idetools --track:$TESTNIM,29,0 --def $SILENT
+skMethod
+method \(
+!proc \(
+
+> idetools --track:$TESTNIM,27,15 --def $SILENT
+skTemplate
+template \(
+!proc \(
diff --git a/tests/caas/main.nim b/tests/caas/main.nim
new file mode 100644
index 000000000..fafeff93b
--- /dev/null
+++ b/tests/caas/main.nim
@@ -0,0 +1,7 @@
+import imported, strutils
+
+proc main =
+  var t1 = "text"
+  var t2 = t1.toUpper
+  echo(t1 +++ t2)
+
diff --git a/tests/caas/main_dirty.nim b/tests/caas/main_dirty.nim
new file mode 100644
index 000000000..95fb6c624
--- /dev/null
+++ b/tests/caas/main_dirty.nim
@@ -0,0 +1,14 @@
+import imported, strutils
+
+type
+  TFoo = object
+    x: int
+    y: string
+
+proc main =
+  var t1 = "text"
+  var t2 = t1.toUpper
+  var foo = TFoo(x: 10, y: "test")
+  foo.
+  echo(t1 +++ t2)
+
diff --git a/tests/caas/suggest-compile.txt b/tests/caas/suggest-compile.txt
new file mode 100644
index 000000000..a322908ac
--- /dev/null
+++ b/tests/caas/suggest-compile.txt
@@ -0,0 +1,13 @@
+main.nim
+# This example shows how the suggest feature can be used on a partial file
+# using the --trackDirty switch.
+> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
+skField\tx
+skField\ty
+# Repeating the query in caas should work always and retrieve same output.
+CaasRun > idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
+CaasRun skField\tx
+CaasRun skField\ty
+> c --verbosity:0 --hints:on
+SuccessX
+
diff --git a/tests/caas/suggest-invalid-source.txt b/tests/caas/suggest-invalid-source.txt
new file mode 100644
index 000000000..7f8f1213d
--- /dev/null
+++ b/tests/caas/suggest-invalid-source.txt
@@ -0,0 +1,26 @@
+main_dirty.nim
+# A variant of the suggest-compile.txt, instead of using a "base" correct
+# source, this one uses the "broken" main_dirty.nim which won't compile. The
+# test tries to stress idetools to still provide a valid answer if possible,
+# and at least provide the same output with repeated queries rather than dying
+# after the first compilation error.
+
+# The first query should work and provide valid suggestions.
+> idetools --track:$TESTNIM,12,6 --suggest $SILENT
+skField\tx
+skField\ty
+
+# Repeating the query should work too.
+> idetools --track:$TESTNIM,12,6 --suggest $SILENT
+skField\tx
+skField\ty
+
+# Expect now a compilation failure.
+> c
+!SuccessX
+invalid indentation
+
+# Repeating suggestions *after broken compilation* should work too.
+> idetools --track:$TESTNIM,12,6 --suggest $SILENT
+skField\tx
+skField\ty
diff --git a/tests/casestmt/tcase_arrayconstr.nim b/tests/casestmt/tcase_arrayconstr.nim
new file mode 100644
index 000000000..cd7156600
--- /dev/null
+++ b/tests/casestmt/tcase_arrayconstr.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''Not found!
+Found!'''
+"""
+
+const
+  md_extension = [".md", ".markdown"]
+
+proc test(ext: string) =
+  case ext
+  of ".txt", md_extension:
+    echo "Found!"
+  else:
+    echo "Not found!"
+
+test(".something")
+# ensure it's not evaluated at compile-time:
+var foo = ".markdown"
+test(foo)
diff --git a/tests/casestmt/tcase_emptyset_when.nim b/tests/casestmt/tcase_emptyset_when.nim
new file mode 100644
index 000000000..e9b1ec2df
--- /dev/null
+++ b/tests/casestmt/tcase_emptyset_when.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tcaseofwhen.nim"
+  outputsub: "compiles for 1\ni am always two\ndefault for 3\nset is 4 not 5\narray is 6 not 7\ndefault for 8"
+  exitcode: "0"
+"""
+
+proc whenCase(a: int) =
+  case a
+  of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1"
+  of {}: echo "me not fail"
+  of 2: echo "i am always two"
+  of []: echo "me neither"
+  of {4,5}: echo "set is 4 not 5"
+  of [6,7]: echo "array is 6 not 7"
+  of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3"
+  #of {},[]: echo "me neither"
+  else: echo "default for ", a
+
+whenCase(1)
+whenCase(2)
+whenCase(3)
+whenCase(4)
+whenCase(6)
+whenCase(8)
diff --git a/tests/casestmt/tcase_setconstr.nim b/tests/casestmt/tcase_setconstr.nim
new file mode 100644
index 000000000..21f657c2b
--- /dev/null
+++ b/tests/casestmt/tcase_setconstr.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "an identifier"
+"""
+
+const
+  SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
+
+proc classify(s: string) =
+  case s[0]
+  of SymChars, '_': echo "an identifier"
+  of {'0'..'9'}: echo "a number"
+  else: echo "other"
+
+classify("Hurra")
+
diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim
new file mode 100644
index 000000000..e5e08e25e
--- /dev/null
+++ b/tests/casestmt/tcaseexpr1.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tcaseexpr1.nim"
+
+  line: 29
+  errormsg: "type mismatch: got (string) but expected 'int'"
+
+  line: 23
+  errormsg: "not all cases are covered"
+"""
+
+type
+  E = enum A, B, C
+
+proc foo(x): auto =
+  return case x
+    of 1..9: "digit"
+    else: "number"
+
+var r = foo(10)
+
+var x = C
+
+var t1 = case x:
+  of A: "a"
+  of B: "b"
+
+var t2 = case x:
+  of A: 10
+  of B, C: "23"
+
diff --git a/tests/casestmt/tcaseoverlaprange.nim b/tests/casestmt/tcaseoverlaprange.nim
new file mode 100644
index 000000000..5f24c3ca9
--- /dev/null
+++ b/tests/casestmt/tcaseoverlaprange.nim
@@ -0,0 +1,15 @@
+discard """
+  line: 13
+  errormsg: "duplicate case label"
+"""
+
+type
+  TE = enum A, B, C, D
+
+var
+  e: TE
+  
+case e
+of A..D, B..C: 
+  echo "redundant"
+else: nil
diff --git a/tests/casestmt/tcaseoverlaprange2.nim b/tests/casestmt/tcaseoverlaprange2.nim
new file mode 100644
index 000000000..d6e301508
--- /dev/null
+++ b/tests/casestmt/tcaseoverlaprange2.nim
@@ -0,0 +1,18 @@
+discard """
+  line: 13
+  errormsg: "duplicate case label"
+"""
+
+
+
+
+proc checkDuplicates(myval: int32): bool = 
+  case myval
+  of 0x7B:
+    echo "this should not compile"
+  of 0x78 .. 0x7D:
+    result = true
+  else:
+    nil
+
+echo checkDuplicates(0x7B)
diff --git a/tests/casestmt/tcasestm.nim b/tests/casestmt/tcasestm.nim
new file mode 100644
index 000000000..a21b6be0d
--- /dev/null
+++ b/tests/casestmt/tcasestm.nim
@@ -0,0 +1,40 @@
+discard """
+  file: "tcasestm.nim"
+  output: "ayyydd"
+"""
+# Test the case statement
+
+type
+  Tenum = enum eA, eB, eC
+
+var
+  x: string = "yyy"
+  y: Tenum = eA
+  i: int
+
+case y
+of eA: write(stdout, "a")
+of eB, eC: write(stdout, "b or c")
+
+case x
+of "Andreas", "Rumpf": write(stdout, "Hallo Meister!")
+of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
+of "cc", "hash", "when": discard
+of "will", "it", "finally", "be", "generated": discard
+
+var z = case i
+  of 1..5, 8, 9: "aa"
+  of 6, 7: "bb"
+  elif x == "Ha": 
+    "cc"
+  elif x == "yyy":
+    write(stdout, x)
+    "dd"
+  else:
+    "zz"
+
+echo z
+#OUT ayyy
+
+
+
diff --git a/tests/casestmt/tcomputedgoto.nim b/tests/casestmt/tcomputedgoto.nim
new file mode 100644
index 000000000..f567174af
--- /dev/null
+++ b/tests/casestmt/tcomputedgoto.nim
@@ -0,0 +1,48 @@
+discard """
+  output: '''yeah A enumB
+yeah A enumB
+yeah CD enumD
+yeah CD enumE
+yeah A enumB
+yeah CD enumE
+yeah CD enumD
+yeah A enumB
+yeah B enumC
+yeah A enumB
+yeah A enumB
+yeah A enumB'''
+"""
+
+type
+  MyEnum = enum
+    enumA, enumB, enumC, enumD, enumE, enumLast
+
+proc vm() =
+  var instructions: array [0..100, MyEnum]
+  instructions[2] = enumC
+  instructions[3] = enumD
+  instructions[4] = enumA
+  instructions[5] = enumD
+  instructions[6] = enumC
+  instructions[7] = enumA
+  instructions[8] = enumB
+
+  instructions[12] = enumE
+  var pc = 0
+  while true:
+    {.computedGoto.}
+    let instr = instructions[pc]
+    let ra = instr.succ # instr.regA
+    case instr
+    of enumA:
+      echo "yeah A ", ra
+    of enumC, enumD:
+      echo "yeah CD ", ra
+    of enumB:
+      echo "yeah B ", ra
+    of enumE:
+      break
+    of enumLast: discard
+    inc(pc)
+
+vm()
diff --git a/tests/casestmt/tlinearscanend.nim b/tests/casestmt/tlinearscanend.nim
new file mode 100644
index 000000000..15fd0c70a
--- /dev/null
+++ b/tests/casestmt/tlinearscanend.nim
@@ -0,0 +1,24 @@
+
+import strutils
+
+var x = 343
+
+case stdin.readline.parseInt
+of 0: 
+  echo "most common case"
+of 1: 
+  {.linearScanEnd.}
+  echo "second most common case"
+of 2: echo "unlikely: use branch table"
+else: 
+  echo "unlikely too: use branch table"
+
+
+case x
+of 23: echo "23"
+of 343: echo "343"
+of 21: echo "21"
+else: 
+  {.linearScanEnd.}
+  echo "default"
+
diff --git a/tests/ccgbugs/tarray_equality.nim b/tests/ccgbugs/tarray_equality.nim
new file mode 100644
index 000000000..66a953439
--- /dev/null
+++ b/tests/ccgbugs/tarray_equality.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''true
+true'''
+"""
+
+# bug #2489
+
+let a = [1]
+let b = [1]
+echo a == b
+
+# bug #2498
+var x: array[0, int]
+var y: array[0, int]
+echo x == y
diff --git a/tests/ccgbugs/tbug1081.nim b/tests/ccgbugs/tbug1081.nim
new file mode 100644
index 000000000..71628feec
--- /dev/null
+++ b/tests/ccgbugs/tbug1081.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''1
+0
+0
+0'''
+"""
+
+proc `1/1`() = echo(1 div 1)
+template `1/2`() = echo(1 div 2)
+var `1/3` = 1 div 4
+`1/3` = 1 div 3 # oops, 1/3!=1/4
+let `1/4` = 1 div 4
+
+`1/1`()
+`1/2`()
+echo `1/3`
+echo `1/4`
diff --git a/tests/ccgbugs/tccgen1.nim b/tests/ccgbugs/tccgen1.nim
new file mode 100644
index 000000000..9234bbd6c
--- /dev/null
+++ b/tests/ccgbugs/tccgen1.nim
@@ -0,0 +1,67 @@
+
+
+type
+  Feature = tuple[name: string, version: string]
+  PDOMImplementation* = ref DOMImplementation
+  DOMImplementation = object
+    Features: seq[Feature] # Read-Only
+
+  PNode* = ref Node
+  Node = object {.inheritable.}
+    attributes*: seq[PAttr]
+    childNodes*: seq[PNode]
+    FLocalName: string # Read-only
+    FNamespaceURI: string # Read-only
+    FNodeName: string # Read-only
+    nodeValue*: string
+    FNodeType: int # Read-only
+    FOwnerDocument: PDocument # Read-Only
+    FParentNode: PNode # Read-Only
+    prefix*: string # Setting this should change some values... TODO!
+  
+  PElement* = ref Element
+  Element = object of Node
+    FTagName: string # Read-only
+  
+  PCharacterData = ref CharacterData
+  CharacterData = object of Node
+    data*: string
+    
+  PDocument* = ref Document
+  Document = object of Node
+    FImplementation: PDOMImplementation # Read-only
+    FDocumentElement: PElement # Read-only
+    
+  PAttr* = ref Attr  
+  Attr = object of Node
+    FName: string # Read-only
+    FSpecified: bool # Read-only
+    value*: string
+    FOwnerElement: PElement # Read-only
+
+  PDocumentFragment* = ref DocumentFragment
+  DocumentFragment = object of Node
+
+  PText* = ref Text
+  Text = object of CharacterData
+  
+  PComment* = ref Comment
+  Comment = object of CharacterData
+  
+  PCDataSection* = ref CDataSection
+  CDataSection = object of Text
+    
+  PProcessingInstruction* = ref ProcessingInstruction
+  ProcessingInstruction = object of Node
+    data*: string
+    FTarget: string # Read-only
+
+proc `namespaceURI=`*(n: var PNode, value: string) = 
+  n.FNamespaceURI = value
+  
+proc main = 
+  var n: PNode
+  new(n)
+  n.namespaceURI = "test"
+
+main()
diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim
new file mode 100644
index 000000000..92e7b3a66
--- /dev/null
+++ b/tests/ccgbugs/tcgbug.nim
@@ -0,0 +1,38 @@
+discard """
+  file: "tcgbug.nim"
+  output: "success"
+"""
+
+type
+  TObj = object
+    x, y: int
+  PObj = ref TObj
+
+proc p(a: PObj) =
+  a.x = 0
+
+proc q(a: var PObj) =
+  a.p()
+
+var 
+  a: PObj
+new(a)
+q(a)
+
+# bug #914
+when defined(windows):
+  var x = newWideCString("Hello")
+
+echo "success"
+
+
+# bug #833
+
+type
+  PFuture*[T] = ref object
+    value*: T
+    finished*: bool
+    cb: proc (future: PFuture[T]) {.closure.}
+
+var k = PFuture[void]()
+
diff --git a/tests/ccgbugs/tcodegenbug1.nim b/tests/ccgbugs/tcodegenbug1.nim
new file mode 100644
index 000000000..9b9771485
--- /dev/null
+++ b/tests/ccgbugs/tcodegenbug1.nim
@@ -0,0 +1,67 @@
+import os
+
+type
+  TStatusEnum* = enum
+    sUnknown = -1, sBuildFailure, sBuildInProgress, sBuildSuccess,
+    sTestFailure, sTestInProgress, sTestSuccess, # ORDER MATTERS!
+    sDocGenFailure, sDocGenInProgress, sDocGenSuccess,
+    sCSrcGenFailure, sCSrcGenInProgress, sCSrcGenSuccess
+
+  TStatus* = object
+    status*: TStatusEnum
+    desc*: string
+    hash*: string
+    
+proc initStatus*(): TStatus =
+  result.status = sUnknown
+  result.desc = ""
+  result.hash = ""
+
+proc isInProgress*(status: TStatusEnum): bool =
+  return status in {sBuildInProgress, sTestInProgress, sDocGenInProgress,
+                    sCSrcGenInProgress}
+
+proc `$`*(status: TStatusEnum): string =
+  case status
+  of sBuildFailure:
+    return "build failure"
+  of sBuildInProgress:
+    return "build in progress"
+  of sBuildSuccess:
+    return "build finished"
+  of sTestFailure:
+    return "testing failure"
+  of sTestInProgress:
+    return "testing in progress"
+  of sTestSuccess:
+    return "testing finished"
+  of sDocGenFailure:
+    return "documentation generation failed"
+  of sDocGenInProgress:
+    return "generating documentation"
+  of sDocGenSuccess:
+    return "documentation generation succeeded"
+  of sCSrcGenFailure:
+    return "csource generation failed"
+  of sCSrcGenInProgress:
+    return "csource generation in progress"
+  of sCSrcGenSuccess:
+    return "csource generation succeeded"
+  of sUnknown:
+    return "unknown"
+    
+proc makeCommitPath*(platform, hash: string): string =
+  return platform / "nim_" & hash.substr(0, 11) # 11 Chars.
+
+type
+  TFlag = enum
+    A, B, C, D
+
+  TFlags = set[TFlag]
+
+  TObj = object
+    x: int
+    flags: TFlags
+
+# have a proc taking TFlags as param and returning object having TFlags field
+proc foo(flags: TFlags): TObj = nil
diff --git a/tests/ccgbugs/tconstobj.nim b/tests/ccgbugs/tconstobj.nim
new file mode 100644
index 000000000..98f441e83
--- /dev/null
+++ b/tests/ccgbugs/tconstobj.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''(FirstName: James, LastName: Franco)'''
+"""
+
+# bug #1547
+import tables
+
+type Person* = object
+    FirstName*: string
+    LastName*: string
+
+let people = {
+    "001": Person(FirstName: "James", LastName: "Franco")
+}.toTable()
+
+echo people["001"]
diff --git a/tests/ccgbugs/tcvarargs.nim b/tests/ccgbugs/tcvarargs.nim
new file mode 100644
index 000000000..ebaf83a4a
--- /dev/null
+++ b/tests/ccgbugs/tcvarargs.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''17
+17
+17
+17
+17
+17
+'''
+"""
+
+# bug #1593
+
+{.emit: """
+#include <stdarg.h>
+
+void foo(int n, ...) {
+  NI64 k;
+  int i;
+  va_list argp;
+  va_start(argp, n);
+  for (i = 1; i <= n; i++) {
+    k = va_arg(argp, NI64);
+    printf("%lld\n", (long long)k);
+  }
+  va_end(argp);
+}
+""".}
+
+proc foo(x: cint) {.importc, varargs, nodecl.}
+
+proc main() =
+  const k = 17'i64
+  foo(6, k, k, k, k, k, k)
+main()
diff --git a/tests/ccgbugs/tmissingbracket.nim b/tests/ccgbugs/tmissingbracket.nim
new file mode 100644
index 000000000..886884d0c
--- /dev/null
+++ b/tests/ccgbugs/tmissingbracket.nim
@@ -0,0 +1,52 @@
+discard """
+  output: '''Subobject test called
+5'''
+"""
+
+type
+  TClassOfTCustomObject {.pure, inheritable.} = object
+    base* : ptr TClassOfTCustomObject
+    className* : string
+  TClassOfTobj = object of TClassOfTCustomObject
+    nil
+  TCustomObject = ref object {.inheritable.}
+    class* : ptr TClassOfTCustomObject
+  TObj = ref object of TCustomObject
+    data: int
+
+var ClassOfTObj: TClassOfTObj
+
+proc initClassOfTObj() =
+  ClassOfTObj.base = nil
+  ClassOfTObj.className = "TObj"
+
+initClassOfTObj()
+
+proc initialize*(self: TObj) =
+  self.class = addr ClassOfTObj
+  # this generates wrong C code: && instead of &
+
+proc newInstance(T: typedesc): T =
+  mixin initialize
+  new(result)
+  initialize(result)
+
+var o = TObj.newInstance()
+
+type
+    TestObj* = object of RootObj
+        t:int
+    SubObject* = object of TestObj
+
+method test*(t:var TestObj) =
+    echo "test called"
+
+method test*(t:var SubObject) =
+    echo "Subobject test called"
+    t.t= 5
+
+var a: SubObject
+
+a.test()
+echo a.t
+
diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim
new file mode 100644
index 000000000..edff1dd4e
--- /dev/null
+++ b/tests/ccgbugs/tmissingderef.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''255
+1 1
+0.5'''
+"""
+
+# bug #1181
+
+type
+  TFoo = object
+    x: int32
+
+proc mainowar =
+  var foo: TFoo
+  foo.x = 0xff
+  var arr1 = cast[ptr array[4, uint8]](addr foo)[] # Fails.
+  echo arr1[when cpuEndian == littleEndian: 0 else: 3]
+
+  var i = 1i32
+  let x = addr i
+  var arr2 = cast[ptr array[4, uint8]](x)[] # Fails.
+  echo arr2[when cpuEndian == littleEndian: 0 else: 3], " ", i
+
+  # bug #1715
+  var a: array[2, float32] = [0.5'f32, 0.7]
+  let p = addr a
+  var b = p[]
+  echo b[0]
+
+mainowar()
diff --git a/tests/ccgbugs/tmissinginit.nim b/tests/ccgbugs/tmissinginit.nim
new file mode 100644
index 000000000..d440608e6
--- /dev/null
+++ b/tests/ccgbugs/tmissinginit.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''0
+0
+0
+0
+[[a = nil,
+b = nil]]'''
+"""
+
+# bug #1475
+type
+  Crash = object
+    a: string
+    b: seq[string]
+
+proc initCrash(): Crash = discard
+
+proc test() =
+  var blongname = [initCrash()]
+  echo repr(blongname)
+
+# bug #1434
+proc bug: array[1, int] = discard
+
+echo bug()[0]
+echo bug()[0]
+echo bug()[0]
+echo bug()[0]
+
+when isMainModule: test()
diff --git a/tests/ccgbugs/tmissingvolatile.nim b/tests/ccgbugs/tmissingvolatile.nim
new file mode 100644
index 000000000..4d25e5c22
--- /dev/null
+++ b/tests/ccgbugs/tmissingvolatile.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "1"
+  cmd: r"nim c --hints:on $options -d:release $file"
+  ccodecheck: "'NI volatile state;'"
+"""
+
+# bug #1539
+
+proc err() =
+  raise newException(Exception, "test")
+
+proc main() =
+  var state: int
+  try:
+    state = 1
+    err()
+  except:
+    echo state
+
+main()
diff --git a/tests/ccgbugs/tpartialcs.nim b/tests/ccgbugs/tpartialcs.nim
new file mode 100644
index 000000000..12ff65c37
--- /dev/null
+++ b/tests/ccgbugs/tpartialcs.nim
@@ -0,0 +1,20 @@
+
+# bug #2551
+
+type Tup = tuple
+  A, a: int
+
+type Obj = object
+  A, a: int
+
+var x: Tup # This works.
+var y: Obj # This doesn't.
+
+# bug #2212
+
+proc f() =
+  let
+    p = 1.0
+    P = 0.25 + 0.5
+
+f()
diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim
new file mode 100644
index 000000000..50c363a4a
--- /dev/null
+++ b/tests/ccgbugs/trecursive_closure.nim
@@ -0,0 +1,8 @@
+# bug #2233
+type MalType = object
+  fun: proc: MalType
+
+proc f(x: proc: MalType) =
+  discard x()
+
+f(nil)
diff --git a/tests/ccgbugs/trecursive_table.nim b/tests/ccgbugs/trecursive_table.nim
new file mode 100644
index 000000000..3406a1c31
--- /dev/null
+++ b/tests/ccgbugs/trecursive_table.nim
@@ -0,0 +1,17 @@
+
+# bug #1700
+import tables
+
+type
+  E* = enum
+    eX
+    eY
+  T* = object
+    case kind: E
+    of eX:
+      xVal: Table[string, T]
+    of eY:
+      nil
+
+proc p*(x: Table[string, T]) =
+  discard
diff --git a/tests/ccgbugs/tstringslice.nim b/tests/ccgbugs/tstringslice.nim
new file mode 100644
index 000000000..00c1adf74
--- /dev/null
+++ b/tests/ccgbugs/tstringslice.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+1234
+1234
+2
+234
+234
+3
+34
+34
+4
+4
+4'''
+"""
+
+# bug #794
+type TRange = range[0..3]
+
+const str = "123456789"
+
+for i in TRange.low .. TRange.high:
+  echo str[i]                          #This works fine
+  echo str[int(i) .. int(TRange.high)] #So does this
+  echo str[i .. TRange.high]           #The compiler complains about this
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
new file mode 100644
index 000000000..960e2aae9
--- /dev/null
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -0,0 +1,80 @@
+# bug #2250
+
+import
+    math, strutils
+
+type
+    Meters = float
+    Point2[T] = tuple[x, y: T]
+
+    HexState* = enum
+        hsOn, hsOff
+
+    Index = uint16
+
+    HexGrid* = object
+        w, h: int                       ## Width and height of the hex grid.
+        radius: Meters                  ## Radius of circle that circumscribes a hexagon.
+        grid: seq[HexState]             ## Information on what hexes are drawn.
+
+    HexVtxIndex = enum
+        hiA, hiB, hiC, hiD, hiE, hiF
+
+    HexCoord* = Point2[int]
+
+const
+    HexDY = sqrt(1.0 - (0.5 * 0.5))     # dy from center to midpoint of 1-2
+    HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
+
+
+let
+    hexOffsets : array[HexVtxIndex, Point2[float]] = [
+                  (-1.0, 0.0),
+                  (-HexDX, -HexDY),
+                  (HexDX, -HexDY),
+                  (1.0, 0.0),
+                  (HexDX, HexDY),
+                  (-HexDX, HexDY)]
+
+    evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,-1), hiA),
+            ((1,0), hiB),
+            ((1,0), hiA),
+            ((0,1), hiB)]
+
+    oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,0), hiA),
+            ((1,1), hiB),
+            ((1,1), hiA),
+            ((0,1), hiB)]
+
+template odd*(i: int) : expr =
+    (i and 1) != 0
+
+proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
+    #NOTE: this variation compiles
+    #var offset : type(evenSharingOffsets[i])
+    #
+    #if odd(col):
+    #    offset = oddSharingOffsets[i]
+    #else:
+    #    offset = evenSharingOffsets[i]
+
+    let
+        #NOTE: this line generates the bad code
+        offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
+        x = col + 1 + offset.hc.x
+        y = row + 1 + offset.hc.y
+
+    result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
+
+proc go() =
+    var hg : HexGrid
+
+    echo "vidx ", $vidx(hg, 1, 2, hiC)
+
+go()
diff --git a/tests/ccgbugs/twrong_tupleconv.nim b/tests/ccgbugs/twrong_tupleconv.nim
new file mode 100644
index 000000000..68413e96e
--- /dev/null
+++ b/tests/ccgbugs/twrong_tupleconv.nim
@@ -0,0 +1,20 @@
+# bug #1833
+iterator myitems*[T](a: var seq[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "seq modified while iterating over it")
+
+# Works fine
+var xs = @[1,2,3]
+for x in myitems(xs):
+  inc x
+
+# Tuples don't work
+var ys = @[(1,"a"),(2,"b"),(3,"c")]
+for y in myitems(ys):
+  inc y[0]
+
diff --git a/tests/clearmsg/mb.nim b/tests/clearmsg/mb.nim
new file mode 100644
index 000000000..2d21e2396
--- /dev/null
+++ b/tests/clearmsg/mb.nim
@@ -0,0 +1,2 @@
+type
+  typ* = distinct string
diff --git a/tests/clearmsg/mc.nim b/tests/clearmsg/mc.nim
new file mode 100644
index 000000000..79d7431df
--- /dev/null
+++ b/tests/clearmsg/mc.nim
@@ -0,0 +1,3 @@
+
+type
+  typ* = distinct int
diff --git a/tests/clearmsg/ta.nim b/tests/clearmsg/ta.nim
new file mode 100644
index 000000000..38449c319
--- /dev/null
+++ b/tests/clearmsg/ta.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got (mc.typ)"
+  line: 12
+"""
+
+import mb, mc
+
+proc test(testing: mb.typ) =
+  discard
+
+var s: mc.typ
+test(s)
diff --git a/tests/clearmsg/tconsttypemismatch.nim b/tests/clearmsg/tconsttypemismatch.nim
new file mode 100644
index 000000000..edf480348
--- /dev/null
+++ b/tests/clearmsg/tconsttypemismatch.nim
@@ -0,0 +1,8 @@
+discard """
+  file: "tconsttypemismatch.nim"
+  line: 7
+  errormsg: "type mismatch"
+"""
+# bug #2252
+const foo: int = 1000 / 30
+
diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim
new file mode 100644
index 000000000..445a99b6d
--- /dev/null
+++ b/tests/closure/tclosure.nim
@@ -0,0 +1,47 @@
+discard """
+  file: "tclosure.nim"
+  output: "1 3 6 11 20"
+"""
+# Test the closure implementation
+
+proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) =
+  for i in 0..n.len-1: n[i] = fn(n[i])
+
+proc foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int =
+  for i in 0..n.len-1:
+    result = fn(result, n[i])
+
+proc each(n: openarray[int], fn: proc(x: int) {.closure.}) =
+  for i in 0..n.len-1:
+    fn(n[i])
+
+var
+  myData: array[0..4, int] = [0, 1, 2, 3, 4]
+
+proc testA() =
+  var p = 0
+  map(myData, proc (x: int): int =
+                result = x + 1 shl (proc (y: int): int =
+                  return y + p
+                )(0)
+                inc(p))
+
+testA()
+
+myData.each do (x: int):
+  write(stdout, x)
+  write(stdout, " ")
+
+#OUT 2 4 6 8 10
+
+type
+  ITest = tuple[
+    setter: proc(v: int),
+    getter: proc(): int]
+
+proc getInterf(): ITest =
+  var shared: int
+  
+  return (setter: proc (x: int) = shared = x,
+          getter: proc (): int = return shared)
+
diff --git a/tests/closure/tclosure2.nim b/tests/closure/tclosure2.nim
new file mode 100644
index 000000000..d2c16eac9
--- /dev/null
+++ b/tests/closure/tclosure2.nim
@@ -0,0 +1,101 @@
+discard """
+  output: '''0
+11
+1
+11
+2
+11
+3
+11
+4
+11
+5
+11
+6
+11
+7
+11
+8
+11
+9
+11
+11
+py
+py
+py
+py
+px
+6'''
+"""
+
+when true:
+  proc ax =
+    for xxxx in 0..9:
+      var i = 0
+      proc bx =
+        if i > 10: 
+          echo xxxx
+          return
+        i += 1
+        #for j in 0 .. 0: echo i
+        bx()
+      
+      bx()
+      echo i
+
+  ax()
+
+when true:
+  proc accumulator(start: int): (proc(): int {.closure.}) =
+    var x = start-1
+    #let dummy = proc =
+    #  discard start
+    
+    result = proc (): int = 
+      #var x = 9
+      for i in 0 .. 0: x = x + 1
+      
+      return x
+
+  var a = accumulator(3)
+  let b = accumulator(4)
+  echo a() + b() + a()
+
+
+  proc outer =
+
+    proc py() =
+      # no closure here:
+      for i in 0..3: echo "py"
+
+    py()
+    
+  outer()
+
+
+when true:
+  proc outer2 =
+    var errorValue = 3
+    proc fac[T](n: T): T =
+      if n < 0: result = errorValue
+      elif n <= 1: result = 1
+      else: result = n * fac(n-1)
+  
+    proc px() {.closure.} =
+      echo "px"
+
+    proc py() {.closure.} =
+      echo "py"
+
+    const
+      mapping = {
+        "abc": px,
+        "xyz": py
+      }
+    mapping[0][1]()
+    
+    echo fac(3)
+
+
+  outer2()
+
diff --git a/tests/closure/tclosure3.nim b/tests/closure/tclosure3.nim
new file mode 100644
index 000000000..bb217387f
--- /dev/null
+++ b/tests/closure/tclosure3.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "tclosure3.nim"
+  output: "success"
+"""
+
+proc main =
+  const n = 30
+  for iterations in 0..50_000:
+    var s: seq[proc(): string {.closure.}] = @[]
+    for i in 0 .. n-1:
+      let ii = i
+      s.add(proc(): string = return $(ii*ii))
+    for i in 0 .. n-1:
+      let val = s[i]()
+      if val != $(i*i): echo "bug  ", val
+    
+    if getOccupiedMem() > 3000_000: quit("still a leak!")
+  echo "success"
+
+main()
diff --git a/tests/closure/tclosure4.nim b/tests/closure/tclosure4.nim
new file mode 100644
index 000000000..8e08376b6
--- /dev/null
+++ b/tests/closure/tclosure4.nim
@@ -0,0 +1,13 @@
+
+import json, tables
+
+proc run(json_params: TTable) =
+  let json_elems = json_params["files"].elems
+  # These fail compilation.
+  var files = map(json_elems, proc (x: PJsonNode): string = x.str)
+  #var files = json_elems.map do (x: PJsonNode) -> string: x.str
+  echo "Hey!"
+
+when isMainModule:
+  let text = """{"files": ["a", "b", "c"]}"""
+  run(toTable((text.parseJson).fields))
diff --git a/tests/closure/tclosurebug2.nim b/tests/closure/tclosurebug2.nim
new file mode 100644
index 000000000..12e4e3509
--- /dev/null
+++ b/tests/closure/tclosurebug2.nim
@@ -0,0 +1,194 @@
+import hashes, math
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+
+  TOrderedKeyValuePair[A, B] = tuple[
+    slot: TSlotEnum, next: int, key: A, val: B]
+  TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]]
+  TOrderedTable*[A, B] = object ## table that remembers insertion order
+    data: TOrderedKeyValuePairSeq[A, B]
+    counter, first, last: int
+
+const
+  growthFactor = 2
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+template rawGetImpl() {.dirty.} =
+  var h: THash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].slot != seEmpty:
+    if t.data[h].key == key and t.data[h].slot == seFilled:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+template rawInsertImpl() {.dirty.} =
+  var h: THash = hash(key) and high(data)
+  while data[h].slot == seFilled:
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+  data[h].slot = seFilled
+
+template addImpl() {.dirty.} =
+  if mustRehash(len(t.data), t.counter): enlarge(t)
+  rawInsert(t, t.data, key, val)
+  inc(t.counter)
+
+template putImpl() {.dirty.} =
+  var index = rawGet(t, key)
+  if index >= 0:
+    t.data[index].val = val
+  else:
+    addImpl()
+
+proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} =
+  var h = t.first
+  while h >= 0:
+    var nxt = t.data[h].next
+    if t.data[h].slot == seFilled: yieldStmt
+    h = nxt
+
+iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator mpairs*[A, B](t: var TOrderedTable[A, B]): tuple[key: A, val: var B] =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order. The values can be modified.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: TOrderedTable[A, B]): A =
+  ## iterates over any key in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].key
+
+iterator values*[A, B](t: TOrderedTable[A, B]): B =
+  ## iterates over any value in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B =
+  ## iterates over any value in the table `t` in insertion order. The values
+  ## can be modified.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+proc rawGet[A, B](t: TOrderedTable[A, B], key: A): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B =
+  ## retrieves the value at ``t[key]``. The value can be modified.
+  ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: raise newException(KeyError, "key not found: " & $key)
+
+proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc rawInsert[A, B](t: var TOrderedTable[A, B], 
+                     data: var TOrderedKeyValuePairSeq[A, B],
+                     key: A, val: B) =
+  rawInsertImpl()
+  data[h].next = -1
+  if t.first < 0: t.first = h
+  if t.last >= 0: data[t.last].next = h
+  t.last = h
+
+proc enlarge[A, B](t: var TOrderedTable[A, B]) =
+  var n: TOrderedKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  var h = t.first
+  t.first = -1
+  t.last = -1
+  while h >= 0:
+    var nxt = t.data[h].next
+    if t.data[h].slot == seFilled: 
+      rawInsert(t, n, t.data[h].key, t.data[h].val)
+    h = nxt
+  swap(t.data, n)
+
+proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
+  ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
+  addImpl()
+
+proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] =
+  ## creates a new ordered hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  result.first = -1
+  result.last = -1
+  newSeq(result.data, initialSize)
+
+proc toOrderedTable*[A, B](pairs: openarray[tuple[key: A, 
+                           val: B]]): TOrderedTable[A, B] =
+  ## creates a new ordered hash table that contains the given `pairs`.
+  result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
+  for key, val in items(pairs): result[key] = val
+
+proc sort*[A, B](t: var TOrderedTable[A,B], 
+                 cmp: proc (x, y: tuple[key: A, val: B]): int {.closure.}) =
+  ## sorts the ordered table so that the entry with the highest counter comes
+  ## first. This is destructive (with the advantage of being efficient)! 
+  ## You must not modify `t` afterwards!
+  ## You can use the iterators `pairs`,  `keys`, and `values` to iterate over
+  ## `t` in the sorted order.
+
+  # we use shellsort here; fast enough and simple
+  var h = 1
+  while true:
+    h = 3 * h + 1
+    if h >= high(t.data): break
+  while true:
+    h = h div 3
+    for i in countup(h, high(t.data)):
+      var j = i
+      #echo(t.data.len, " ", j, " - ", h)
+      #echo(repr(t.data[j-h]))
+      proc rawCmp(x, y: TOrderedKeyValuePair[A, B]): int =
+        if x.slot in {seEmpty, seDeleted} and y.slot in {seEmpty, seDeleted}:
+          return 0
+        elif x.slot in {seEmpty, seDeleted}:
+          return -1
+        elif y.slot in {seEmpty, seDeleted}:
+          return 1
+        else:
+          let item1 = (x.key, x.val)
+          let item2 = (y.key, y.val)
+          return cmp(item1, item2)
+      
+      while rawCmp(t.data[j-h], t.data[j]) <= 0:
+        swap(t.data[j], t.data[j-h])
+        j = j-h
+        if j < h: break
+    if h == 1: break
diff --git a/tests/closure/tfib50.nim b/tests/closure/tfib50.nim
new file mode 100644
index 000000000..719aa3ad5
--- /dev/null
+++ b/tests/closure/tfib50.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "20365011074"
+"""
+
+import tables
+
+proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 =
+    var previous = initTable[int64, int64]()
+    return proc(i: int64): int64 =
+        if not previous.hasKey i:
+            previous[i] = f(i)
+        return previous[i]
+
+var fib: proc(a: int64): int64
+
+fib = memoize(proc (i: int64): int64 =
+    if i == 0 or i == 1:
+        return 1
+    return fib(i-1) + fib(i-2)
+)
+
+echo fib(50)
diff --git a/tests/closure/tforum.nim b/tests/closure/tforum.nim
new file mode 100644
index 000000000..4f6a16ff7
--- /dev/null
+++ b/tests/closure/tforum.nim
@@ -0,0 +1,44 @@
+discard """
+  output: '''asdas
+processClient end
+false
+'''
+"""
+
+type
+  PAsyncHttpServer = ref object
+    value: string
+  PFutureBase = ref object
+    callback: proc () {.closure.}
+    value: string
+    failed: bool
+
+proc accept(server: PAsyncHttpServer): PFutureBase =
+  new(result)
+  result.callback = proc () =
+    discard
+  server.value = "hahaha"
+
+proc processClient(): PFutureBase =
+  new(result)
+
+proc serve(server: PAsyncHttpServer): PFutureBase =
+  iterator serveIter(): PFutureBase {.closure.} =
+    echo server.value
+    while true:
+      var acceptAddrFut = server.accept()
+      yield acceptAddrFut
+      var fut = acceptAddrFut.value
+
+      var f = processClient()
+      f.callback =
+        proc () =
+          echo("processClient end")
+          echo(f.failed)
+      yield f
+  var x = serveIter
+  for i in 0 .. 1:
+    result = x()
+    result.callback()
+
+discard serve(PAsyncHttpServer(value: "asdas"))
diff --git a/tests/closure/tinterf.nim b/tests/closure/tinterf.nim
new file mode 100644
index 000000000..726fac9f6
--- /dev/null
+++ b/tests/closure/tinterf.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''56 66'''
+"""
+
+type
+  ITest = tuple[
+    setter: proc(v: int) {.closure.},
+    getter1: proc(): int {.closure.},
+    getter2: proc(): int {.closure.}]
+
+proc getInterf(): ITest =
+  var shared1, shared2: int
+  
+  return (setter: proc (x: int) = 
+            shared1 = x
+            shared2 = x + 10,
+          getter1: proc (): int = result = shared1,
+          getter2: proc (): int = return shared2)
+
+var i = getInterf()
+i.setter(56)
+
+echo i.getter1(), " ", i.getter2()
+
diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
new file mode 100644
index 000000000..c9136a736
--- /dev/null
+++ b/tests/closure/tinvalidclosure.nim
@@ -0,0 +1,12 @@
+discard """
+  line: 12
+  errormsg: "type mismatch: got (proc (x: int){.closure, gcsafe, locks: 0.})"
+"""
+
+proc ugh[T](x: T) {.closure.} =
+  echo "ugha"
+
+
+proc takeCdecl(p: proc (x: int) {.cdecl.}) = discard
+
+takeCDecl(ugh[int])
diff --git a/tests/closure/tinvalidclosure2.nim b/tests/closure/tinvalidclosure2.nim
new file mode 100644
index 000000000..20e465c12
--- /dev/null
+++ b/tests/closure/tinvalidclosure2.nim
@@ -0,0 +1,14 @@
+discard """
+  line: 10
+  errormsg: "illegal capture 'A'"
+"""
+
+proc outer() = 
+  var A: int
+
+  proc ugh[T](x: T) {.cdecl.} =
+    echo "ugha", A, x
+    
+  ugh[int](12)
+
+outer()
diff --git a/tests/closure/tissue1642.nim b/tests/closure/tissue1642.nim
new file mode 100644
index 000000000..e3028c88e
--- /dev/null
+++ b/tests/closure/tissue1642.nim
@@ -0,0 +1,7 @@
+discard """
+  file: "tissue1642.nim"
+  disabled: true
+"""
+block:
+  var i = 0
+  proc p() = inc(i)
diff --git a/tests/closure/tjester.nim b/tests/closure/tjester.nim
new file mode 100644
index 000000000..48e5186f0
--- /dev/null
+++ b/tests/closure/tjester.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''baro0'''
+"""
+
+type
+  Future[T] = ref object
+    data: T
+    callback: proc () {.closure.}
+
+proc cbOuter(response: string) {.closure, discardable.} =
+  iterator cbIter(): Future[int] {.closure.} =
+    for i in 0..7:
+      proc foo(): int =
+        iterator fooIter(): Future[int] {.closure.} =
+          echo response, i
+          yield Future[int](data: 17)
+        var iterVar = fooIter
+        iterVar().data
+      yield Future[int](data: foo())
+      
+  var iterVar2 = cbIter
+  proc cb2() {.closure.} =
+    try:
+      if not finished(iterVar2):
+        let next = iterVar2()
+        if next != nil:
+          next.callback = cb2
+    except:
+      echo "WTF"
+  cb2()
+
+cbOuter "baro"
diff --git a/tests/closure/tnamedparamanonproc.nim b/tests/closure/tnamedparamanonproc.nim
new file mode 100644
index 000000000..94e32894f
--- /dev/null
+++ b/tests/closure/tnamedparamanonproc.nim
@@ -0,0 +1,14 @@
+
+type
+  PButton = ref object
+  TButtonClicked = proc(button: PButton) {.nimcall.}
+
+proc newButton*(onClick: TButtonClicked) =
+  discard
+
+proc main() =
+  newButton(onClick = proc(b: PButton) =
+    var requestomat = 12
+    )
+
+main()
diff --git a/tests/closure/tnestedclosure.nim b/tests/closure/tnestedclosure.nim
new file mode 100644
index 000000000..c8f1e231b
--- /dev/null
+++ b/tests/closure/tnestedclosure.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''foo88
+23 24foo 88
+foo88
+23 24foo 88
+hohoho'''
+"""
+
+# test nested closure
+proc main(param: int) =
+  var foo = 23
+  proc outer(outerParam: string) =
+    var outerVar = 88
+    echo outerParam, outerVar
+    proc inner() =
+      block Test:
+        echo foo, " ", param, outerParam, " ", outerVar
+    inner()
+  outer("foo")
+
+# test simple closure within dummy 'main':
+proc dummy =
+  proc main2(param: int) =
+    var foo = 23
+    proc outer(outerParam: string) =
+      var outerVar = 88
+      echo outerParam, outerVar
+      proc inner() =
+        block Test:
+          echo foo, " ", param, outerParam, " ", outerVar
+      inner()
+    outer("foo")
+  main2(24)
+
+dummy()
+
+main(24)
+
+# Jester + async triggered this bug:
+proc cbOuter() =
+  var response = "hohoho"
+  block:
+    proc cbIter() =
+      block:
+        proc fooIter() =
+          echo response
+        fooIter()
+        
+    cbIter()
+
+cbOuter()
diff --git a/tests/closure/tnestedproc.nim b/tests/closure/tnestedproc.nim
new file mode 100644
index 000000000..49ec6f9a7
--- /dev/null
+++ b/tests/closure/tnestedproc.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "11"
+"""
+
+proc p(x, y: int): int = 
+  result = x + y
+
+echo p((proc (): int = 
+          var x = 7
+          return x)(),
+       (proc (): int = return 4)())
+
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
new file mode 100644
index 000000000..3138ae72e
--- /dev/null
+++ b/tests/closure/ttimeinfo.nim
@@ -0,0 +1,15 @@
+# bug #2073
+
+import sequtils
+import times
+
+# 1
+proc f(n: int): TimeInfo =
+  TimeInfo(year: n, month: mJan, monthday: 1)
+
+echo toSeq(2000 || 2015).map(f)
+
+# 2
+echo toSeq(2000 || 2015).map(proc (n: int): TimeInfo =
+  TimeInfo(year: n, month: mJan, monthday: 1)
+)
diff --git a/tests/closure/uclosures.nim b/tests/closure/uclosures.nim
new file mode 100644
index 000000000..6eea29ca1
--- /dev/null
+++ b/tests/closure/uclosures.nim
@@ -0,0 +1,12 @@
+import unittest
+
+test "loop variables are captured by copy":
+  var funcs: seq[proc (): int {.closure.}] = @[]
+  
+  for i in 0..10:
+    let ii = i
+    funcs.add do -> int: return ii * ii
+
+  check funcs[0]() == 0
+  check funcs[3]() == 9
+
diff --git a/tests/cnstseq/tcnstseq.nim b/tests/cnstseq/tcnstseq.nim
new file mode 100644
index 000000000..e7d2333b4
--- /dev/null
+++ b/tests/cnstseq/tcnstseq.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tcnstseq.nim"
+  output: "AngelikaAnneAnnaAnkaAnja"
+"""
+# Test the new implicit conversion from sequences to arrays in a constant
+# context.
+
+import strutils
+
+const
+  myWords = "Angelika Anne Anna Anka Anja".split()
+  
+for x in items(myWords): 
+  write(stdout, x) #OUT AngelikaAnneAnnaAnkaAnja
+
+
+
diff --git a/tests/cnstseq/tcnstseq2.nim b/tests/cnstseq/tcnstseq2.nim
new file mode 100644
index 000000000..1a27b2ba7
--- /dev/null
+++ b/tests/cnstseq/tcnstseq2.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "AngelikaAnneAnnaAnkaAnja"
+"""
+
+const
+  myWords = @["Angelika", "Anne", "Anna", "Anka", "Anja"]
+  
+for i in 0 .. high(myWords): 
+  write(stdout, myWords[i]) #OUT AngelikaAnneAnnaAnkaAnja
+
+
+
diff --git a/tests/cnstseq/tcnstseq3.nim b/tests/cnstseq/tcnstseq3.nim
new file mode 100644
index 000000000..e59516e85
--- /dev/null
+++ b/tests/cnstseq/tcnstseq3.nim
@@ -0,0 +1,7 @@
+discard """
+  output: "AngelikaAnneAnnaAnkaAnja"
+"""
+
+for w in items(["Angelika", "Anne", "Anna", "Anka", "Anja"]):
+  write(stdout, w) #OUT AngelikaAnneAnnaAnkaAnja
+
diff --git a/tests/collections/tcounttable.nim b/tests/collections/tcounttable.nim
new file mode 100644
index 000000000..ebbb1c8e5
--- /dev/null
+++ b/tests/collections/tcounttable.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "And we get here"
+"""
+
+# bug #2625
+
+const s_len = 32
+
+import tables
+var substr_counts: CountTable[string] = initCountTable[string]()
+var my_string = "Hello, this is sadly broken for strings over 64 characters. Note that it *does* appear to work for short strings."
+for i in 0..(my_string.len - s_len):
+  let s = my_string[i..i+s_len-1]
+  substr_counts[s] = 1
+  # substr_counts[s] = substr_counts[s] + 1  # Also breaks, + 2 as well, etc.
+  # substr_counts.inc(s)  # This works
+  #echo "Iteration ", i
+
+echo "And we get here"
diff --git a/tests/collections/tindexby.nim b/tests/collections/tindexby.nim
new file mode 100644
index 000000000..f374d5504
--- /dev/null
+++ b/tests/collections/tindexby.nim
@@ -0,0 +1,22 @@
+import tables
+
+doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
+
+var tbl1 = initTable[int, int]()
+tbl1.add(1,1)
+tbl1.add(2,2)
+doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
+
+type
+  TElem = object
+    foo: int
+    bar: string
+    
+let
+  elem1 = TElem(foo: 1, bar: "bar")
+  elem2 = TElem(foo: 2, bar: "baz")
+  
+var tbl2 = initTable[string, TElem]()
+tbl2.add("bar", elem1)
+tbl2.add("baz", elem2)
+doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
diff --git a/tests/collections/tsets.nim b/tests/collections/tsets.nim
new file mode 100644
index 000000000..a5bbe8dbd
--- /dev/null
+++ b/tests/collections/tsets.nim
@@ -0,0 +1,37 @@
+import sets
+
+block setEquality:
+  var
+    a = initSet[int]()
+    b = initSet[int]()
+    c = initSet[string]()
+
+  for i in 0..5: a.incl(i)
+  for i in 1..6: b.incl(i)
+  for i in 0..5: c.incl($i)
+
+  doAssert map(a, proc(x: int): int = x + 1) == b
+  doAssert map(a, proc(x: int): string = $x) == c
+
+
+block setsContainingTuples:
+  var set = initSet[tuple[i: int, i64: int64, f: float]]()
+  set.incl( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
+
+
+block setWithTuplesWithSeqs:
+  var s = initSet[tuple[s: seq[int]]]()
+  s.incl( (s: @[1, 2, 3]) )
+  doAssert s.contains( (s: @[1, 2, 3]) )
+  doAssert( not s.contains((s: @[4, 5, 6])) )
+
+
+block setWithSequences:
+  var s = initSet[seq[int]]()
+  s.incl( @[1, 2, 3] )
+  doAssert s.contains(@[1, 2, 3])
+  doAssert( not s.contains(@[4, 5, 6]) )
+
+
diff --git a/tests/collections/ttableconstr.nim b/tests/collections/ttableconstr.nim
new file mode 100644
index 000000000..1a21a18d1
--- /dev/null
+++ b/tests/collections/ttableconstr.nim
@@ -0,0 +1,16 @@
+# Test if the new table constructor syntax works:
+
+template ignoreExpr(e: expr): stmt {.immediate.} =
+  discard
+
+# test first class '..' syntactical citizen:  
+ignoreExpr x <> 2..4
+# test table constructor:
+ignoreExpr({:})
+ignoreExpr({2: 3, "key": "value"})
+
+# NEW:
+assert 56 in 50..100
+
+assert 56 in ..60
+
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
new file mode 100644
index 000000000..a10606843
--- /dev/null
+++ b/tests/collections/ttables.nim
@@ -0,0 +1,154 @@
+discard """
+  output: '''true'''
+"""
+
+import hashes, tables
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484,
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454,
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490,
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
+block tableTest1:
+  var t = initTable[tuple[x, y: int], string]()
+  t[(0,0)] = "00"
+  t[(1,0)] = "10"
+  t[(0,1)] = "01"
+  t[(1,1)] = "11"
+  for x in 0..1:
+    for y in 0..1:
+      assert t[(x,y)] == $x & $y
+  assert($t ==
+    "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
+
+block tableTest2:
+  var t = initTable[string, float]()
+  t["test"] = 1.2345
+  t["111"] = 1.000043
+  t["123"] = 1.23
+  t.del("111")
+
+  t["012"] = 67.9
+  t["123"] = 1.5 # test overwriting
+
+  assert t["123"] == 1.5
+  assert t["111"] == 0.0 # deleted
+  assert(not hasKey(t, "111"))
+  assert "123" in t
+  assert("111" notin t)
+
+  for key, val in items(data): t[key] = val.toFloat
+  for key, val in items(data): assert t[key] == val.toFloat
+
+  assert(not t.hasKeyOrPut("456", 4.0))     # test absent key
+  assert t.hasKeyOrPut("012", 3.0)          # test present key
+  var x = t.mgetOrPut("111", 1.5)           # test absent key
+  x = x * 2
+  assert x == 3.0
+  x = t.mgetOrPut("test", 1.5)              # test present key
+  x = x * 2
+  assert x == 2 * 1.2345
+
+block orderedTableTest1:
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  var i = 0
+  # `pairs` needs to yield in insertion order:
+  for key, val in pairs(t):
+    assert key == data[i][0]
+    assert val == data[i][1]
+    inc(i)
+
+  for key, val in mpairs(t): val = 99
+  for val in mvalues(t): assert val == 99
+
+block countTableTest1:
+  var s = data.toTable
+  var t = initCountTable[string]()
+  for k in s.keys: t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert t.largest()[0] == "90"
+
+  t.sort()
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+block mpairsTableTest1:
+  var t = initTable[string, int]()
+  t["a"] = 1
+  t["b"] = 2
+  t["c"] = 3
+  t["d"] = 4
+  for k, v in t.mpairs:
+    if k == "a" or k == "c":
+      v = 9
+
+  for k, v in t.pairs:
+    if k == "a" or k == "c":
+      assert v == 9
+    else:
+      assert v != 1 and v != 3
+
+block SyntaxTest:
+  var x = toTable[int, string]({:})
+
+proc orderedTableSortTest() =
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
+  var i = 0
+  # `pairs` needs to yield in sorted order:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+
+orderedTableSortTest()
+echo "true"
+
diff --git a/tests/collections/ttables2.nim b/tests/collections/ttables2.nim
new file mode 100644
index 000000000..6f3fa841a
--- /dev/null
+++ b/tests/collections/ttables2.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''true'''
+"""
+
+import tables
+
+proc TestHashIntInt() =
+  var tab = initTable[int,int]()
+  for i in 1..1_000_000:
+    tab[i] = i
+  for i in 1..1_000_000:
+    var x = tab[i]
+    if x != i : echo "not found ", i
+
+proc run1() =         # occupied Memory stays constant, but
+  for i in 1 .. 50:   # aborts at run: 44 on win32 with 3.2GB with out of memory
+    TestHashIntInt()
+
+# bug #2107
+
+var delTab = initTable[int,int](4)
+
+for i in 1..4:
+  delTab[i] = i
+  delTab.del(i)
+delTab[5] = 5
+
+
+run1()
+echo "true"
diff --git a/tests/collections/ttablesref.nim b/tests/collections/ttablesref.nim
new file mode 100644
index 000000000..0b641ebc7
--- /dev/null
+++ b/tests/collections/ttablesref.nim
@@ -0,0 +1,144 @@
+discard """
+  output: '''true'''
+"""
+
+import hashes, tables, sequtils
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484,
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454,
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490,
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
+block tableTest1:
+  var t = newTable[tuple[x, y: int], string]()
+  t[(0,0)] = "00"
+  t[(1,0)] = "10"
+  t[(0,1)] = "01"
+  t[(1,1)] = "11"
+  for x in 0..1:
+    for y in 0..1:
+      assert t[(x,y)] == $x & $y
+  assert($t ==
+    "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
+
+block tableTest2:
+  var t = newTable[string, float]()
+  t["test"] = 1.2345
+  t["111"] = 1.000043
+  t["123"] = 1.23
+  t.del("111")
+
+  t["012"] = 67.9
+  t["123"] = 1.5 # test overwriting
+
+  assert t["123"] == 1.5
+  assert t["111"] == 0.0 # deleted
+  assert "123" in t
+  assert(not hasKey(t, "111"))
+  assert "111" notin t
+
+  for key, val in items(data): t[key] = val.toFloat
+  for key, val in items(data): assert t[key] == val.toFloat
+
+
+block orderedTableTest1:
+  var t = newOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  var i = 0
+  # `pairs` needs to yield in insertion order:
+  for key, val in pairs(t):
+    assert key == data[i][0]
+    assert val == data[i][1]
+    inc(i)
+
+  for key, val in mpairs(t): val = 99
+  for val in mvalues(t): assert val == 99
+
+block countTableTest1:
+  var s = data.toTable
+  var t = newCountTable[string]()
+  for k in s.keys: t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert t.largest()[0] == "90"
+
+  t.sort()
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+block SyntaxTest:
+  var x = newTable[int, string]({:})
+  discard x
+
+block nilTest:
+  var i, j: TableRef[int, int] = nil
+  assert i == j
+  j = newTable[int, int]()
+  assert i != j
+  assert j != i
+  i = newTable[int, int]()
+  assert i == j
+
+proc orderedTableSortTest() =
+  var t = newOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): assert t[key] == val
+  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
+  var i = 0
+  # `pairs` needs to yield in sorted order:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+block anonZipTest:
+  let keys = @['a','b','c']
+  let values = @[1, 2, 3]
+  doAssert "{a: 1, b: 2, c: 3}" == $ toTable zip(keys, values)
+
+orderedTableSortTest()
+echo "true"
+
diff --git a/tests/collections/ttablesref2.nim b/tests/collections/ttablesref2.nim
new file mode 100644
index 000000000..939de2b84
--- /dev/null
+++ b/tests/collections/ttablesref2.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''true'''
+"""
+
+import tables
+
+proc TestHashIntInt() =
+  var tab = newTable[int,int]()
+  for i in 1..1_000_000:
+    tab[i] = i
+  for i in 1..1_000_000:
+    var x = tab[i]
+    if x != i : echo "not found ", i
+
+proc run1() =         # occupied Memory stays constant, but
+  for i in 1 .. 50:   # aborts at run: 44 on win32 with 3.2GB with out of memory
+    TestHashIntInt()
+
+run1()
+echo "true"
diff --git a/tests/compiles/tcompiles.nim b/tests/compiles/tcompiles.nim
new file mode 100644
index 000000000..b3d9c17ce
--- /dev/null
+++ b/tests/compiles/tcompiles.nim
@@ -0,0 +1,28 @@
+# test the new 'compiles' feature:
+
+template supports(opr, x: expr): bool {.immediate.} =
+  compiles(opr(x)) or compiles(opr(x, x))
+
+template ok(x: expr): stmt =
+  static: assert(x)
+
+template no(x: expr): stmt =
+  static: assert(not x)
+
+type
+  TObj = object
+
+var
+  myObj {.compileTime.}: TObj
+
+ok supports(`==`, myObj)
+ok supports(`==`, 45)
+
+no supports(`++`, 34)
+ok supports(`not`, true)
+ok supports(`+`, 34)
+
+no compiles(4+5.0 * "hallo")
+
+no compiles(undeclaredIdentifier)
+no compiles(undeclaredIdentifier)
diff --git a/tests/compiles/tevilcompiles.nim b/tests/compiles/tevilcompiles.nim
new file mode 100644
index 000000000..0930507d1
--- /dev/null
+++ b/tests/compiles/tevilcompiles.nim
@@ -0,0 +1,12 @@
+# bug #1055
+import unittest
+type TMatrix*[N,M: static[int], T] = object
+  data*: array[0..N*M-1, T]
+proc `==`*(a: distinct TMatrix; b: distinct TMatrix): bool =
+  result = a.data == b.data
+
+test "c":
+  var a = TMatrix[2,2,int](data: [1,2,3,4])
+  var b = TMatrix[2,2,int](data: [1,2,3,4])
+  check(a == b)
+
diff --git a/tests/concat/tconcat.nim b/tests/concat/tconcat.nim
new file mode 100644
index 000000000..fdce3ea00
--- /dev/null
+++ b/tests/concat/tconcat.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "DabcD"
+"""
+
+const
+  x = "abc"
+
+var v = "D" & x & "D"
+
+echo v
+
diff --git a/tests/concepts/mvarconcept.nim b/tests/concepts/mvarconcept.nim
new file mode 100644
index 000000000..0f9d0beff
--- /dev/null
+++ b/tests/concepts/mvarconcept.nim
@@ -0,0 +1,13 @@
+type RNG* = concept var rng
+  rng.randomUint32() is uint32
+
+type MersenneTwister* = object
+
+proc randomUint32*(self: var MersenneTwister): uint32 = 5
+
+proc randomInt*(rng: var RNG; max: Positive): Natural = 5
+
+var mersenneTwisterInst = MersenneTwister()
+
+proc randomInt*(max: Positive): Natural =
+  mersenneTwisterInst.randomInt(max)
diff --git a/tests/concepts/tmanual.nim b/tests/concepts/tmanual.nim
new file mode 100644
index 000000000..7cf08af06
--- /dev/null
+++ b/tests/concepts/tmanual.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+6
+a
+b
+t
+e
+s
+t
+'''
+"""
+
+template accept(e: expr) =
+  static: assert compiles(e)
+
+template reject(e: expr) =
+  static: assert(not compiles(e))
+
+type
+  Container[T] = concept c
+    c.len is Ordinal
+    items(c) is iterator
+    for value in c:
+      type(value) is T
+
+proc takesIntContainer(c: Container[int]) =
+  for e in c: echo e
+
+takesIntContainer(@[1, 2, 3])
+reject takesIntContainer(@["x", "y"])
+
+proc takesContainer(c: Container) =
+  for e in c: echo e
+
+takesContainer(@[4, 5, 6])
+takesContainer(@["a", "b"])
+takesContainer "test"
+reject takesContainer(10)
+
diff --git a/tests/concepts/tswizzle.nim b/tests/concepts/tswizzle.nim
new file mode 100644
index 000000000..07205d454
--- /dev/null
+++ b/tests/concepts/tswizzle.nim
@@ -0,0 +1,80 @@
+discard """
+  output: '''3
+[1, 3]
+[2, 1, 2]
+'''
+  disabled: "true"
+"""
+
+import macros, strutils
+
+template accept(e: expr) =
+  static: assert(compiles(e))
+
+template reject(e: expr) =
+  static: assert(not compiles(e))
+
+proc swizzleIdx(c: char): int =
+  return case c
+    of 'x': 0
+    of 'y': 1
+    of 'z': 2
+    of 'w': 3
+    of 'r': 0
+    of 'g': 1
+    of 'b': 2
+    of 'a': 3
+    else: 0
+
+proc isSwizzle(s: string): bool {.compileTime.} =
+  template trySet(name, set) =
+    block search:
+      for c in s:
+        if c notin set:
+          break search
+      return true
+
+  trySet coords, {'x', 'y', 'z', 'w'}
+  trySet colors, {'r', 'g', 'b', 'a'}
+
+  return false
+
+type
+  StringIsSwizzle = concept value
+    value.isSwizzle
+
+  SwizzleStr = static[string] and StringIsSwizzle
+
+proc foo(x: SwizzleStr) =
+  echo "sw"
+
+#foo("xx")
+reject foo("xe")
+
+type
+  Vec[N: static[int]; T] = array[N, T]
+
+when false:
+  proc card(x: Vec): int = x.N
+  proc `$`(x: Vec): string = x.repr.strip
+
+  macro `.`(x: Vec, swizzle: SwizzleStr): expr =
+    var
+      cardinality = swizzle.len
+      values = newNimNode(nnkBracket)
+      v = genSym()
+
+    for c in swizzle:
+      values.add newNimNode(nnkBracketExpr).add(
+        v, c.swizzleIdx.newIntLitNode)
+
+    return quote do:
+      let `v` = `x`
+      Vec[`cardinality`, `v`.T](`values`)
+
+var z = Vec([1, 2, 3])
+
+#echo z.card
+#echo z.xz
+#echo z.yxy
+
diff --git a/tests/concepts/tusertypeclasses.nim b/tests/concepts/tusertypeclasses.nim
new file mode 100644
index 000000000..612556949
--- /dev/null
+++ b/tests/concepts/tusertypeclasses.nim
@@ -0,0 +1,68 @@
+discard """
+  output: '''Sortable
+Sortable
+Container
+true
+true
+false
+false
+false
+'''
+"""
+
+import typetraits
+
+type
+  TObj = object
+    x: int
+
+  Sortable = concept x, y
+    (x < y) is bool
+
+  ObjectContainer = concept C
+    C.len is Ordinal
+    for v in items(C):
+      v.type is tuple|object
+
+proc foo(c: ObjectContainer) =
+  echo "Container"
+
+proc foo(x: Sortable) =
+  echo "Sortable"
+
+foo 10
+foo "test"
+foo(@[TObj(x: 10), TObj(x: 20)])
+
+proc intval(x: int): int = 10
+
+# check real and virtual fields
+type
+  TFoo = concept T
+    T.x
+    y(T)
+    intval T.y
+    let z = intval(T.y)
+
+proc y(x: TObj): int = 10
+
+proc testFoo(x: TFoo) = discard
+testFoo(TObj(x: 10))
+
+type
+  Matrix[Rows, Cols: static[int]; T] = concept M
+    M.M == Rows
+    M.N == Cols
+    M.T is T
+
+  MyMatrix[M, N: static[int]; T] = object
+    data: array[M*N, T]
+
+var x: MyMatrix[3, 3, int]
+
+echo x is Matrix
+echo x is Matrix[3, 3, int]
+echo x is Matrix[3, 3, float]
+echo x is Matrix[4, 3, int]
+echo x is Matrix[3, 4, int]
+
diff --git a/tests/concepts/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim
new file mode 100644
index 000000000..ae05540cd
--- /dev/null
+++ b/tests/concepts/tusertypeclasses2.nim
@@ -0,0 +1,24 @@
+type
+  hasFieldX = concept z
+    z.x is int
+
+  obj_x = object
+    x: int
+
+  ref_obj_x = ref object
+    x: int
+
+  ref_to_obj_x = ref obj_x
+
+  p_o_x = ptr obj_x
+  v_o_x = var obj_x
+
+template check(x) =
+  static: assert(x)
+
+check obj_x is hasFieldX
+check ref_obj_x is hasFieldX
+check ref_to_obj_x is hasFieldX
+check p_o_x is hasFieldX
+check v_o_x is hasFieldX
+
diff --git a/tests/concepts/tvarconcept.nim b/tests/concepts/tvarconcept.nim
new file mode 100644
index 000000000..203ef3cdc
--- /dev/null
+++ b/tests/concepts/tvarconcept.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "5"
+"""
+
+# bug #2346, bug #2404
+
+import mvarconcept
+
+echo randomInt(5)
diff --git a/tests/constr/tconstr1.nim b/tests/constr/tconstr1.nim
new file mode 100644
index 000000000..45e303554
--- /dev/null
+++ b/tests/constr/tconstr1.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tconstr1.nim"
+  line: 25
+  errormsg: "type mismatch"
+"""
+# Test array, record constructors

+

+type

+  TComplexRecord = tuple[

+    s: string,

+    x, y: int,

+    z: float,

+    chars: set[char]]

+

+proc testSem =

+  var

+    things: array [0..1, TComplexRecord] = [

+      (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

+      (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a', 'b', 'c'})]

+  write(stdout, things[0].x)

+

+const

+  things: array [0..1, TComplexRecord] = [

+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

+    (s: "hi", x: 69, y: 45, z: 1.0)] #ERROR

+  otherThings = [  # the same

+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

+    (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]

+
+
diff --git a/tests/constr/tconstr2.nim b/tests/constr/tconstr2.nim
new file mode 100644
index 000000000..30cec5cb8
--- /dev/null
+++ b/tests/constr/tconstr2.nim
@@ -0,0 +1,26 @@
+discard """
+  file: "tconstr2.nim"
+  output: "69"
+"""
+# Test array, record constructors

+

+type

+  TComplexRecord = tuple[

+    s: string,

+    x, y: int,

+    z: float,

+    chars: set[char]]

+

+const

+  things: array [0..1, TComplexRecord] = [

+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

+    (s: "hi", x: 69, y: 45, z: 1.0, chars: {})] 

+  otherThings = [  # the same

+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

+    (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]

+

+write(stdout, things[0].x)

+#OUT 69

+

+
+
diff --git a/tests/constraints/tconstraints.nim b/tests/constraints/tconstraints.nim
new file mode 100644
index 000000000..e61095fff
--- /dev/null
+++ b/tests/constraints/tconstraints.nim
@@ -0,0 +1,18 @@
+discard """
+  line: 16
+  errormsg: "type mismatch: got (int literal(232))"
+"""
+
+proc myGenericProc[T: object|tuple|ptr|ref|distinct](x: T): string = 
+  result = $x
+
+type
+  TMyObj = tuple[x, y: int]
+
+var
+  x: TMyObj
+
+assert myGenericProc(x) == "(x: 0, y: 0)"
+assert myGenericProc(232) == "232"
+
+
diff --git a/tests/controlflow/tblock1.nim b/tests/controlflow/tblock1.nim
new file mode 100644
index 000000000..5c41aaf82
--- /dev/null
+++ b/tests/controlflow/tblock1.nim
@@ -0,0 +1,18 @@
+discard """
+  file: "tblock1.nim"
+  line: 14
+  errormsg: "undeclared identifier: \'ha\'"
+"""
+# check for forward label and

+# for failure when label is not declared

+

+proc main =

+  block endLess:

+    write(stdout, "Muaahh!\N")

+    break endLess

+

+  break ha #ERROR

+

+main()

+
+
diff --git a/tests/controlflow/tbreak.nim b/tests/controlflow/tbreak.nim
new file mode 100644
index 000000000..7deab4caf
--- /dev/null
+++ b/tests/controlflow/tbreak.nim
@@ -0,0 +1,44 @@
+discard """
+  output: '''10
+true true
+true false
+false true
+false false'''
+"""
+
+var
+  x = false
+  run = true
+
+while run:
+  run = false
+  block myblock:
+    if true:
+      break
+    echo "leaving myblock"
+  x = true
+doAssert(x)
+
+# bug #1418
+iterator foo: int =
+  for x in 0 .. 9:
+    for y in [10,20,30,40,50,60,70,80,90]:
+      yield x + y
+
+for p in foo():
+  echo p
+  break
+
+iterator permutations: int =
+  yield 10
+
+for p in permutations():
+  break
+
+# regression:
+proc main =
+  for x in [true, false]:
+    for y in [true, false]:
+      echo x, " ", y
+
+main()
diff --git a/tests/controlflow/tcontinue.nim b/tests/controlflow/tcontinue.nim
new file mode 100644
index 000000000..092026e8c
--- /dev/null
+++ b/tests/controlflow/tcontinue.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "came here"
+"""
+
+var i = 0
+while i < 400:
+
+  if i == 10: break
+  elif i == 3: 
+    inc i
+    continue
+  inc i
+
+var f = "failure"
+var j = 0
+while j < 300:
+  for x in 0..34:
+    if j < 300: continue
+    if x == 10: 
+      echo "failure: should never happen"
+      break
+  f = "came here"
+  break
+
+if i == 10:
+  echo f
+else:
+  echo "failure"
diff --git a/tests/controlflow/tnestif.nim b/tests/controlflow/tnestif.nim
new file mode 100644
index 000000000..bfcd8751c
--- /dev/null
+++ b/tests/controlflow/tnestif.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tnestif.nim"
+  output: "i == 2"
+"""
+# test nested ifs

+

+var

+    x, y: int

+x = 2

+if x == 0:

+    write(stdout, "i == 0")

+    if y == 0:

+        write(stdout, x)

+    else:

+        write(stdout, y)

+elif x == 1:

+    write(stdout, "i == 1")

+elif x == 2:

+    write(stdout, "i == 2")

+else:

+    write(stdout, "looks like Python")

+#OUT i == 2

+
+
diff --git a/tests/controlflow/tstatret.nim b/tests/controlflow/tstatret.nim
new file mode 100644
index 000000000..bf90255a0
--- /dev/null
+++ b/tests/controlflow/tstatret.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tstatret.nim"
+  line: 9
+  errormsg: "statement not allowed after"
+"""
+# no statement after return

+proc main() =

+  return

+  echo("huch?") #ERROR_MSG statement not allowed after

+

+
+
diff --git a/tests/converter/tconvcolors.nim b/tests/converter/tconvcolors.nim
new file mode 100644
index 000000000..07e829550
--- /dev/null
+++ b/tests/converter/tconvcolors.nim
@@ -0,0 +1,5 @@
+
+import colors
+
+echo int32(colWhite), 'A'
+
diff --git a/tests/converter/tconvert.nim b/tests/converter/tconvert.nim
new file mode 100644
index 000000000..a37140234
--- /dev/null
+++ b/tests/converter/tconvert.nim
@@ -0,0 +1,20 @@
+
+converter FloatConversion64(x: int): float64 = return toFloat(x)
+converter FloatConversion32(x: int): float32 = return toFloat(x)
+converter FloatConversionPlain(x: int): float = return toFloat(x)
+
+const width = 500
+const height = 500
+
+proc ImageSurfaceCreate(w, h: float) = discard
+
+ImageSurfaceCreate(width, height)
+
+type TFoo = object
+
+converter toPtr*(some: var TFoo): ptr TFoo = (addr some)
+
+
+proc zoot(x: ptr TFoo) = nil
+var x: Tfoo
+zoot(x)
diff --git a/tests/converter/tgenericconverter.nim b/tests/converter/tgenericconverter.nim
new file mode 100644
index 000000000..e1c9f7c4c
--- /dev/null
+++ b/tests/converter/tgenericconverter.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''666
+666'''
+"""
+
+# test the new generic converters:
+
+type
+  TFoo2[T] = object
+    x: T
+
+  TFoo[T] = object
+    data: array[0..100, T]
+
+converter toFoo[T](a: TFoo2[T]): TFoo[T] =
+  result.data[0] = a.x
+
+proc p(a: TFoo[int]) =
+  echo a.data[0]
+
+proc q[T](a: TFoo[T]) =
+  echo a.data[0]
+
+
+var
+  aa: TFoo2[int]
+aa.x = 666
+
+p aa
+q aa
diff --git a/tests/converter/ttypeconverter1.nim b/tests/converter/ttypeconverter1.nim
new file mode 100644
index 000000000..510b84700
--- /dev/null
+++ b/tests/converter/ttypeconverter1.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''foo
+true'''
+"""
+
+converter p(i: int): bool = return i != 0
+
+if 1:
+  echo if 4: "foo" else: "barr"
+while 0: 
+  echo "bar"
+
+var a: array[3, bool]
+a[0] = 3
+echo a[0]
diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim
new file mode 100644
index 000000000..a9ea8e6ce
--- /dev/null
+++ b/tests/cpp/tcppraise.nim
@@ -0,0 +1,17 @@
+discard """
+  cmd: "nim cpp $file"
+  output: '''foo
+bar
+Need odd and >= 3 digits##
+baz'''
+"""
+
+# bug #1888
+echo "foo"
+try:
+  echo "bar"
+  raise newException(ValueError, "Need odd and >= 3 digits")
+#  echo "baz"
+except ValueError:
+  echo getCurrentExceptionMsg(), "##"
+echo "baz"
diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim
new file mode 100644
index 000000000..461914739
--- /dev/null
+++ b/tests/cpp/tget_subsystem.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+namespace System {
+  struct Input {};
+}
+
+struct SystemManager {
+  template <class T>
+  static T* getSubsystem() { return new T; }
+};
+
+""".}
+
+type Input {.importcpp: "System::Input".} = object
+proc getSubsystem*[T](): ptr T {.
+  importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+let input: ptr Input = getSubsystem[Input]()
+
diff --git a/tests/cpp/trawsockets.nim b/tests/cpp/trawsockets.nim
new file mode 100644
index 000000000..bc129de57
--- /dev/null
+++ b/tests/cpp/trawsockets.nim
@@ -0,0 +1,5 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+import rawsockets
diff --git a/tests/cpp/tstaticvar_via_typedesc.nim b/tests/cpp/tstaticvar_via_typedesc.nim
new file mode 100644
index 000000000..7a9fa2afc
--- /dev/null
+++ b/tests/cpp/tstaticvar_via_typedesc.nim
@@ -0,0 +1,20 @@
+discard """
+  cmd: "nim cpp $file"
+  output: "42"
+"""
+
+# bug #2324
+
+static: assert defined(cpp), "compile in cpp mode"
+
+{.emit: """
+class Foo {
+public:
+    static int x;
+};
+int Foo::x = 42;
+""".}
+
+type Foo {.importcpp:"Foo".} = object
+proc x* (this: typedesc[Foo]): int {.importcpp:"Foo::x@", nodecl.}
+echo Foo.x
diff --git a/tests/cpp/tthread_createthread.nim b/tests/cpp/tthread_createthread.nim
new file mode 100644
index 000000000..0dc081268
--- /dev/null
+++ b/tests/cpp/tthread_createthread.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim cpp --hints:on --threads:on $options $file"
+"""
+
+proc threadMain(a: int) {.thread.} =
+    discard
+
+proc main() =
+    var thread: TThread[int]
+
+    thread.createThread(threadMain, 0)
+    thread.joinThreads()
+
+main()
\ No newline at end of file
diff --git a/tests/cpp/ttypeinfo.nim b/tests/cpp/ttypeinfo.nim
new file mode 100644
index 000000000..1529c86e9
--- /dev/null
+++ b/tests/cpp/ttypeinfo.nim
@@ -0,0 +1,5 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+import typeinfo
diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim
new file mode 100644
index 000000000..cb5ab33af
--- /dev/null
+++ b/tests/cpp/tvector_iterator.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit: """
+
+template <class T>
+struct Vector {
+  struct Iterator {};
+};
+
+""".}
+
+type
+  Vector {.importcpp: "Vector".} [T] = object
+  VectorIterator {.importcpp: "Vector<'0>::Iterator".} [T] = object
+
+var x: VectorIterator[void]
+
diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim
new file mode 100644
index 000000000..6eb5dc9e4
--- /dev/null
+++ b/tests/cpp/tvectorseq.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''(x: 1.0)
+(x: 0.0)'''
+  cmd: "nim cpp $file"
+  disabled: "true"
+"""
+
+# This cannot work yet because we omit type information for importcpp'ed types.
+# Fixing this is not hard, but also requires fixing Urhonimo.
+
+# bug #2536
+
+{.emit: """/*TYPESECTION*/
+struct Vector3 {
+public:
+  Vector3(): x(5) {}
+  Vector3(float x_): x(x_) {}
+  float x;
+};
+""".}
+
+type Vector3 {.importcpp: "Vector3", nodecl} = object
+  x: cfloat
+
+proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+# hack around another codegen issue: Generics are attached to where they came
+# from:
+proc `$!`(v:  seq[Vector3]): string = "(x: " & $v[0].x & ")"
+
+proc vec3List*(): seq[Vector3] =
+  let s = @[constructVector3(cfloat(1))]
+  echo($!s)
+  result = s
+  echo($!result)
+
+let f = vec3List()
+#echo($!f)
diff --git a/tests/defaultprocparam/mdefaultprocparam.nim b/tests/defaultprocparam/mdefaultprocparam.nim
new file mode 100644
index 000000000..4a17277c0
--- /dev/null
+++ b/tests/defaultprocparam/mdefaultprocparam.nim
@@ -0,0 +1,5 @@
+
+
+proc p*(f = (proc(): string = "hi")) =
+  echo f()
+
diff --git a/tests/defaultprocparam/tdefaultprocparam.nim b/tests/defaultprocparam/tdefaultprocparam.nim
new file mode 100644
index 000000000..23ecf72e9
--- /dev/null
+++ b/tests/defaultprocparam/tdefaultprocparam.nim
@@ -0,0 +1,4 @@
+
+import mdefaultprocparam
+
+p()
diff --git a/tests/deprecated/tdeprecated.nim b/tests/deprecated/tdeprecated.nim
new file mode 100644
index 000000000..955a7f6ad
--- /dev/null
+++ b/tests/deprecated/tdeprecated.nim
@@ -0,0 +1,9 @@
+discard """
+  nimout: "a is deprecated [Deprecated]"
+"""
+
+var
+  a {.deprecated.}: array[0..11, int]
+
+a[8] = 1
+
diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim
new file mode 100644
index 000000000..639dba941
--- /dev/null
+++ b/tests/destructor/tdestructor.nim
@@ -0,0 +1,130 @@
+discard """
+  output: '''----
+myobj constructed
+myobj destroyed
+----
+mygeneric1 constructed
+mygeneric1 destroyed
+----
+mygeneric2 constructed
+mygeneric2 destroyed
+myobj destroyed
+----
+mygeneric3 constructed
+mygeneric1 destroyed
+----
+mygeneric1 destroyed
+----
+myobj destroyed
+----
+----
+myobj destroyed
+'''
+"""
+
+{.experimental.}
+
+type
+  TMyObj = object
+    x, y: int
+    p: pointer
+
+  TMyGeneric1[T] = object
+    x: T
+
+  TMyGeneric2[A, B] = object
+    x: A
+    y: B
+
+  TMyGeneric3[A, B, C] = object
+    x: A
+    y: B
+    z: C
+
+  TObjKind = enum A, B, C, D
+
+  TCaseObj = object
+    case kind: TObjKind
+    of A:
+      x: TMyGeneric1[int]
+    of B, C:
+      y: TMyObj
+    else:
+      case innerKind: TObjKind
+      of A, B, C:
+        p: TMyGeneric3[int, float, string]
+      of D:
+        q: TMyGeneric3[TMyObj, int, int]
+      r: string
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil: dealloc o.p
+  echo "myobj destroyed"
+
+proc `=destroy`(o: var TMyGeneric1) =
+  echo "mygeneric1 destroyed"
+
+proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
+  echo "mygeneric2 destroyed"
+
+proc open: TMyObj =
+  # allow for superfluous ()
+  result = (TMyObj(x: 1, y: 2, p: alloc(3)))
+
+proc `$`(x: TMyObj): string = $x.y
+
+proc myobj() =
+  var x = open()
+  echo "myobj constructed"
+
+proc mygeneric1() =
+  var x = TMyGeneric1[int](x: 10)
+  echo "mygeneric1 constructed"
+
+proc mygeneric2[T](val: T) =
+  var a = open()
+
+  var b = TMyGeneric2[int, T](x: 10, y: val)
+  echo "mygeneric2 constructed"
+
+  var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")
+
+proc mygeneric3 =
+  var x = TMyGeneric3[int, string, TMyGeneric1[int]](
+    x: 10, y: "test", z: TMyGeneric1[int](x: 10))
+
+  echo "mygeneric3 constructed"
+
+echo "----"
+myobj()
+
+echo "----"
+mygeneric1()
+
+echo "----"
+mygeneric2[int](10)
+
+echo "----"
+mygeneric3()
+
+proc caseobj =
+  block:
+    echo "----"
+    var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
+
+  block:
+    echo "----"
+    var o2 = TCaseObj(kind: B, y: open())
+
+  block:
+    echo "----"
+    var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
+                      p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test"))
+
+  block:
+    echo "----"
+    var o4 = TCaseObj(kind: D, innerKind: D, r: "test",
+                      q: TMyGeneric3[TMyObj, int, int](x: open(), y: 1, z: 0))
+
+caseobj()
+
diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim
new file mode 100644
index 000000000..34fa466af
--- /dev/null
+++ b/tests/destructor/tdestructor2.nim
@@ -0,0 +1,27 @@
+discard """
+  line: 23
+  nimout: " usage of a type with a destructor in a non destructible context"
+"""
+
+{.experimental.}
+
+type
+  TMyObj = object
+    x, y: int
+    p: pointer
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil: dealloc o.p
+
+proc open: TMyObj =
+  result = TMyObj(x: 1, y: 2, p: alloc(3))
+
+
+proc `$`(x: TMyObj): string = $x.y
+
+proc foo =
+  discard open()
+
+# XXX doesn't trigger this yet:
+#echo open()
+
diff --git a/tests/destructor/tdictdestruct.nim b/tests/destructor/tdictdestruct.nim
new file mode 100644
index 000000000..17ded4853
--- /dev/null
+++ b/tests/destructor/tdictdestruct.nim
@@ -0,0 +1,20 @@
+
+type
+  TDict[TK, TV] = object
+    k: TK
+    v: TV
+  PDict[TK, TV] = ref TDict[TK, TV]
+
+proc fakeNew[T](x: var ref T, destroy: proc (a: ref T) {.nimcall.}) =
+  discard
+
+proc destroyDict[TK, TV](a: PDict[TK, TV]) =
+    return
+proc newDict[TK, TV](a: TK, b: TV): PDict[TK, TV] =
+    fakeNew(result, destroyDict[TK, TV])
+
+# Problem: destroyDict is not instantiated when newDict is instantiated!    
+
+discard newDict("a", "b")    
+
+
diff --git a/tests/dir with space/tspace.nim b/tests/dir with space/tspace.nim
new file mode 100644
index 000000000..8db4b52f2
--- /dev/null
+++ b/tests/dir with space/tspace.nim
@@ -0,0 +1,3 @@
+# Test for the compiler to be able to compile a Nim file with spaces in it.
+
+echo("Successful")
\ No newline at end of file
diff --git a/tests/discard/tdiscardable.nim b/tests/discard/tdiscardable.nim
new file mode 100644
index 000000000..a806ccdce
--- /dev/null
+++ b/tests/discard/tdiscardable.nim
@@ -0,0 +1,29 @@
+# Test the discardable pragma
+
+proc p(x, y: int): int {.discardable.} = 
+  return x + y
+
+# test that it is inherited from generic procs too:
+proc q[T](x, y: T): T {.discardable.} = 
+  return x + y
+
+
+p(8, 2)
+q[float](0.8, 0.2)
+
+# bug #942
+
+template maybeMod(x: Tinteger, module:Natural):expr =
+  if module > 0: x mod module
+  else: x
+
+proc foo(b: int):int =
+  var x = 1
+  result = x.maybeMod(b) # Works fine
+
+proc bar(b: int):int =
+  result = 1
+  result = result.maybeMod(b) # Error: value returned by statement has to be discarded
+
+echo foo(0)
+echo bar(0)
diff --git a/tests/discard/tneedsdiscard.nim b/tests/discard/tneedsdiscard.nim
new file mode 100644
index 000000000..2a7856b4a
--- /dev/null
+++ b/tests/discard/tneedsdiscard.nim
@@ -0,0 +1,12 @@
+discard """
+  line: 10
+  errormsg: "value of type 'bool' has to be discarded"
+"""
+
+proc p =
+  var f: TFile
+  echo "hi"
+  
+  open(f, "arg.txt")
+  
+p()
diff --git a/tests/distinct/tborrowdot.nim b/tests/distinct/tborrowdot.nim
new file mode 100644
index 000000000..820ee3b71
--- /dev/null
+++ b/tests/distinct/tborrowdot.nim
@@ -0,0 +1,13 @@
+
+type
+  Foo = object
+    a, b: int
+    s: string
+
+  Bar {.borrow: `.`.} = distinct Foo
+
+var bb: ref Bar
+new bb
+bb.a = 90
+bb.s = "abc"
+
diff --git a/tests/distinct/tcurrncy.nim b/tests/distinct/tcurrncy.nim
new file mode 100644
index 000000000..78dbc2a89
--- /dev/null
+++ b/tests/distinct/tcurrncy.nim
@@ -0,0 +1,38 @@
+discard """
+  file: "tcurrncy.nim"
+  output: "25"
+"""
+template Additive(typ: typeDesc): stmt =
+  proc `+` *(x, y: typ): typ {.borrow.}
+  proc `-` *(x, y: typ): typ {.borrow.}
+  
+  # unary operators:
+  proc `+` *(x: typ): typ {.borrow.}
+  proc `-` *(x: typ): typ {.borrow.}
+
+template Multiplicative(typ, base: typeDesc): stmt {.immediate.} =
+  proc `*` *(x: typ, y: base): typ {.borrow.}
+  proc `*` *(x: base, y: typ): typ {.borrow.}
+  proc `div` *(x: typ, y: base): typ {.borrow.}
+  proc `mod` *(x: typ, y: base): typ {.borrow.}
+
+template Comparable(typ: typeDesc): stmt =
+  proc `<` * (x, y: typ): bool {.borrow.}
+  proc `<=` * (x, y: typ): bool {.borrow.}
+  proc `==` * (x, y: typ): bool {.borrow.}
+
+template DefineCurrency(typ, base: expr): stmt {.immediate.} =
+  type
+    typ* = distinct base
+  Additive(typ)
+  Multiplicative(typ, base)
+  Comparable(typ)
+  
+  proc `$` * (t: typ): string {.borrow.}
+
+DefineCurrency(TDollar, int)
+DefineCurrency(TEuro, int)
+echo($( 12.TDollar + 13.TDollar )) #OUT 25
+
+
+
diff --git a/tests/distinct/tdistinct_consts.nim b/tests/distinct/tdistinct_consts.nim
new file mode 100644
index 000000000..4f6ced2d2
--- /dev/null
+++ b/tests/distinct/tdistinct_consts.nim
@@ -0,0 +1,20 @@
+
+# bug #2641
+
+type MyChar = distinct char
+const c:MyChar = MyChar('a')
+
+type MyBool = distinct bool
+const b:MyBool = MyBool(true)
+
+type MyBoolSet = distinct set[bool]
+const bs:MyBoolSet = MyBoolSet({true})
+
+type MyCharSet= distinct set[char]
+const cs:MyCharSet = MyCharSet({'a'})
+
+type MyBoolSeq = distinct seq[bool]
+const bseq:MyBoolSeq = MyBoolSeq(@[true, false])
+
+type MyBoolArr = distinct array[3, bool]
+const barr:MyBoolArr = MyBoolArr([true, false, true])
diff --git a/tests/dll/client.nim b/tests/dll/client.nim
new file mode 100644
index 000000000..d535e8750
--- /dev/null
+++ b/tests/dll/client.nim
@@ -0,0 +1,41 @@
+discard """
+  output: "Done"
+  cmd: "nim $target --debuginfo --hints:on --define:useNimRtl $options $file"
+"""
+
+type
+  TNodeKind = enum nkLit, nkSub, nkAdd, nkDiv, nkMul
+  TNode = object
+    case k: TNodeKind
+    of nkLit: x: int
+    else: a, b: ref TNode
+
+  PNode = ref TNode
+
+
+when defined(windows):
+  const dllname = "server.dll"
+elif defined(macosx):
+  const dllname = "libserver.dylib"
+else:
+  const dllname = "libserver.so"
+
+proc newLit(x: int): PNode {.importc: "newLit", dynlib: dllname.}
+proc newOp(k: TNodeKind, a, b: PNode): PNode {.
+  importc: "newOp", dynlib: dllname.}  
+proc buildTree(x: int): PNode {.importc: "buildTree", dynlib: dllname.} 
+
+proc eval(n: PNode): int =
+  case n.k
+  of nkLit: result = n.x
+  of nkSub: result = eval(n.a) - eval(n.b)
+  of nkAdd: result = eval(n.a) + eval(n.b)
+  of nkDiv: result = eval(n.a) div eval(n.b)
+  of nkMul: result = eval(n.a) * eval(n.b)
+
+# Test the GC:
+for i in 0..100_000:
+  discard eval(buildTree(2))
+  
+echo "Done"
+
diff --git a/tests/dll/client.nim.cfg b/tests/dll/client.nim.cfg
new file mode 100644
index 000000000..0e044a829
--- /dev/null
+++ b/tests/dll/client.nim.cfg
@@ -0,0 +1 @@
+--define:useNimRtl
diff --git a/tests/dll/server.nim b/tests/dll/server.nim
new file mode 100644
index 000000000..df3223444
--- /dev/null
+++ b/tests/dll/server.nim
@@ -0,0 +1,34 @@
+discard """
+  cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file"
+"""
+
+type
+  TNodeKind = enum nkLit, nkSub, nkAdd, nkDiv, nkMul
+  TNode = object
+    case k: TNodeKind
+    of nkLit: x: int
+    else: a, b: ref TNode
+
+  PNode = ref TNode
+    
+proc newLit(x: int): PNode {.exportc: "newLit", dynlib.} =
+  new(result)
+  result.x = x
+  
+proc newOp(k: TNodeKind, a, b: PNode): PNode {.exportc: "newOp", dynlib.} =
+  assert a != nil
+  assert b != nil
+  new(result)
+  result.k = k
+  result.a = a
+  result.b = b
+  
+proc buildTree(x: int): PNode {.exportc: "buildTree", dynlib.} = 
+  result = newOp(nkMul, newOp(nkAdd, newLit(x), newLit(x)), newLit(x))
+
+when false:
+  # Test the GC:
+  for i in 0..100_000:
+    discard buildTree(2)
+    
+  echo "Done"
diff --git a/tests/dll/server.nim.cfg b/tests/dll/server.nim.cfg
new file mode 100644
index 000000000..02393ba8b
--- /dev/null
+++ b/tests/dll/server.nim.cfg
@@ -0,0 +1,2 @@
+--define:useNimRtl
+--app:lib
diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim
new file mode 100644
index 000000000..ea1ea7b21
--- /dev/null
+++ b/tests/effects/teffects1.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "system.nim"
+  errormsg: "can raise an unlisted exception: ref IOError"
+"""
+
+type
+  TObj = object {.pure, inheritable.}
+  TObjB = object of TObj
+    a, b, c: string
+  
+  IO2Error = ref object of IOError
+  
+proc forw: int {. .}
+  
+proc lier(): int {.raises: [IO2Error].} =
+  writeln stdout, "arg"
+
+proc forw: int =
+  raise newException(IOError, "arg")
+
diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim
new file mode 100644
index 000000000..89ad16edc
--- /dev/null
+++ b/tests/effects/teffects2.nim
@@ -0,0 +1,20 @@
+discard """
+  line: 19
+  errormsg: "can raise an unlisted exception: ref IOError"
+"""
+
+type
+  TObj = object {.pure, inheritable.}
+  TObjB = object of TObj
+    a, b, c: string
+  
+  EIO2 = ref object of IOError
+  
+proc forw: int {.raises: [].}
+
+proc lier(): int {.raises: [IOError].} =
+  writeln stdout, "arg"
+
+proc forw: int =
+  raise newException(IOError, "arg")
+
diff --git a/tests/effects/teffects3.nim b/tests/effects/teffects3.nim
new file mode 100644
index 000000000..78543a929
--- /dev/null
+++ b/tests/effects/teffects3.nim
@@ -0,0 +1,19 @@
+discard """
+  line: 18
+  errormsg: "type mismatch"
+"""
+
+type
+  TObj = object {.pure, inheritable.}
+  TObjB = object of TObj
+    a, b, c: string
+    fn: proc (): int {.tags: [].}
+  
+  EIO2 = ref object of EIO
+  
+proc raiser(): int {.tags: [TObj, FWriteIO].} =
+  writeln stdout, "arg"
+
+var o: TObjB
+o.fn = raiser
+
diff --git a/tests/effects/teffects4.nim b/tests/effects/teffects4.nim
new file mode 100644
index 000000000..4584e6dc8
--- /dev/null
+++ b/tests/effects/teffects4.nim
@@ -0,0 +1,24 @@
+discard """
+  line: 23
+  errormsg: "type mismatch"
+"""
+
+type
+  TObj = object {.pure, inheritable.}
+  TObjB = object of TObj
+    a, b, c: string
+    fn: proc (): int {.tags: [FReadIO].}
+  
+  EIO2 = ref object of EIO
+
+proc q() {.tags: [FIO].} =
+  nil
+  
+proc raiser(): int =
+  writeln stdout, "arg"
+  if true:
+    q()
+
+var o: TObjB
+o.fn = raiser
+
diff --git a/tests/effects/teffects5.nim b/tests/effects/teffects5.nim
new file mode 100644
index 000000000..d630a6fc4
--- /dev/null
+++ b/tests/effects/teffects5.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "type mismatch"
+  line: 7
+"""
+
+proc p(q: proc() ): proc() {.tags: [], raises: [], closure.} =
+  return proc () =
+    q()
+  
+let yay = p(proc () = raise newException(EIO, "IO"))
+
+proc main() {.raises: [], tags: [].} = yay()
+
+main()
diff --git a/tests/effects/teffects6.nim b/tests/effects/teffects6.nim
new file mode 100644
index 000000000..47c85c160
--- /dev/null
+++ b/tests/effects/teffects6.nim
@@ -0,0 +1,31 @@
+
+type
+  PMenu = ref object
+  PMenuItem = ref object
+
+proc createMenuItem*(menu: PMenu, label: string, 
+                    action: proc (i: PMenuItem, p: pointer) {.cdecl.}) = discard
+
+var s: PMenu
+createMenuItem(s, "Go to definition...",
+      proc (i: PMenuItem, p: pointer) {.cdecl.} =
+        try:
+          echo(i.repr)
+        except EInvalidValue:
+          echo("blah")
+)
+
+
+proc noRaise(x: proc()) {.raises: [].} =
+  # unknown call that might raise anything, but valid:
+  x()
+  
+proc doRaise() {.raises: [EIO].} =
+  raise newException(EIO, "IO")
+
+proc use*() =
+  noRaise(doRaise)
+  # Here the compiler inferes that EIO can be raised.
+
+
+use()
diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim
new file mode 100644
index 000000000..d146794b6
--- /dev/null
+++ b/tests/effects/tgcsafe.nim
@@ -0,0 +1,17 @@
+discard """
+  line: 17
+  errormsg: "'mainUnsafe' is not GC-safe"
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+proc mymap(x: proc ()) =
+  x()
+
+var
+  myglob: string
+
+proc mainSafe() {.gcsafe.} =
+  mymap(proc () = echo "foo")
+
+proc mainUnsafe() {.gcsafe.} =
+  mymap(proc () = myglob = "bar"; echo "foo", myglob)
diff --git a/tests/effects/tsidee1.nim b/tests/effects/tsidee1.nim
new file mode 100644
index 000000000..bd5b32dd7
--- /dev/null
+++ b/tests/effects/tsidee1.nim
@@ -0,0 +1,18 @@
+discard """
+  file: "tsidee1.nim"
+  line: 12
+  errormsg: "\'SideEffectLyer\' can have side effects"
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int = return x + global
+
+proc SideEffectLyer(x, y: int): int {.noSideEffect.} = #ERROR_MSG 'SideEffectLyer' can have side effects
+  return x + y + dontcare(x)
+  
+echo SideEffectLyer(1, 3) 
+
+
+
diff --git a/tests/effects/tsidee2.nim b/tests/effects/tsidee2.nim
new file mode 100644
index 000000000..e73c89608
--- /dev/null
+++ b/tests/effects/tsidee2.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tsidee2.nim"
+  output: "5"
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int = return x
+
+proc SideEffectLyer(x, y: int): int {.noSideEffect.} = 
+  return x + y + dontcare(x)
+  
+echo SideEffectLyer(1, 3) #OUT 5
+
+
+
diff --git a/tests/effects/tsidee3.nim b/tests/effects/tsidee3.nim
new file mode 100644
index 000000000..e0c427ab6
--- /dev/null
+++ b/tests/effects/tsidee3.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tsidee3.nim"
+  output: "5"
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int {.noSideEffect.} = return x
+
+proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} = 
+  return x + y + dontcare(x)
+  
+echo noSideEffect(1, 3, dontcare) #OUT 5
+
+
+
diff --git a/tests/effects/tsidee4.nim b/tests/effects/tsidee4.nim
new file mode 100644
index 000000000..cbebfbd36
--- /dev/null
+++ b/tests/effects/tsidee4.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tsidee4.nim"
+  line: 15
+  errormsg: "type mismatch"
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int = return x
+
+proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} = 
+  return x + y + dontcare(x)
+  
+echo noSideEffect(1, 3, dontcare) #ERROR_MSG type mismatch
+
+
diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim
new file mode 100644
index 000000000..6e53b9c08
--- /dev/null
+++ b/tests/enum/tenum.nim
@@ -0,0 +1,8 @@
+# Test enums

+

+type

+  E = enum a, b, c, x, y, z

+

+var

+  en: E

+en = a

diff --git a/tests/enum/tenum2.nim b/tests/enum/tenum2.nim
new file mode 100644
index 000000000..feba36dd6
--- /dev/null
+++ b/tests/enum/tenum2.nim
@@ -0,0 +1,16 @@
+# Test that enum with holes is handled correctly by case statement
+
+type
+  TEnumHole = enum 
+    eA = 0,
+    eB = 4,
+    eC = 5
+    
+var
+  e: TEnumHole = eB
+  
+case e
+of eA: echo "A"
+of eB: echo "B"
+of eC: echo "C"
+
diff --git a/tests/enum/tenum3.nim b/tests/enum/tenum3.nim
new file mode 100644
index 000000000..09a516932
--- /dev/null
+++ b/tests/enum/tenum3.nim
@@ -0,0 +1,16 @@
+# Test enum with explicit size
+
+type
+  TEnumHole {.size: sizeof(int).} = enum 
+    eA = 0,
+    eB = 4,
+    eC = 5
+    
+var
+  e: TEnumHole = eB
+  
+case e
+of eA: echo "A"
+of eB: echo "B"
+of eC: echo "C"
+
diff --git a/tests/enum/tenumhole.nim b/tests/enum/tenumhole.nim
new file mode 100644
index 000000000..a35526378
--- /dev/null
+++ b/tests/enum/tenumhole.nim
@@ -0,0 +1,25 @@
+discard """
+  file: "tenumhole.nim"
+  output: "my value A1my value Bconc2valueCabc4abc"
+"""
+
+const
+  strValB = "my value B"
+
+type
+  TMyEnum = enum
+    valueA = (1, "my value A"),
+    valueB = strValB & "conc",
+    valueC,
+    valueD = (4, "abc")
+ 
+# test the new "proc body can be an expr" feature:
+proc getValue: TMyEnum = valueD
+ 
+# trick the optimizer with a variable:
+var x = getValue()
+echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x
+
+
+
+
diff --git a/tests/enum/tenumitems.nim b/tests/enum/tenumitems.nim
new file mode 100644
index 000000000..04737fa9e
--- /dev/null
+++ b/tests/enum/tenumitems.nim
@@ -0,0 +1,9 @@
+discard """
+  line: 7
+  errormsg: "undeclared identifier: 'items'"
+"""
+
+type a = enum b,c,d
+a.items()
+
+
diff --git a/tests/enum/tenumitems2.nim b/tests/enum/tenumitems2.nim
new file mode 100644
index 000000000..db4c6b554
--- /dev/null
+++ b/tests/enum/tenumitems2.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "A\nB\nC"
+"""
+
+type TAlphabet = enum
+  A, B, C
+
+iterator items(E: typedesc[enum]): E =
+  for v in low(E)..high(E):
+    yield v
+
+for c in TAlphabet:
+  echo($c)
+
diff --git a/tests/enum/tenummix.nim b/tests/enum/tenummix.nim
new file mode 100644
index 000000000..aaf0be2cb
--- /dev/null
+++ b/tests/enum/tenummix.nim
@@ -0,0 +1,11 @@
+discard """
+  file: "tenummix.nim"
+  line: 11
+  errormsg: "type mismatch"
+"""
+
+type
+  TE1 = enum eA, eB
+  TE2 = enum eC, eD
+  
+assert eA != eC
diff --git a/tests/enum/tnamedenumfields.nim b/tests/enum/tnamedenumfields.nim
new file mode 100644
index 000000000..e9ac88a42
--- /dev/null
+++ b/tests/enum/tnamedenumfields.nim
@@ -0,0 +1,23 @@
+discard """
+  file: "tnamedenumfields.nim"
+  output: "my value A0my value Bconc1valueCabc3abc"
+"""
+
+const
+  strValB = "my value B"
+
+type
+  TMyEnum = enum
+    valueA = (0, "my value A"),
+    valueB = strValB & "conc",
+    valueC,
+    valueD = (3, "abc"),
+    valueE = 4
+
+# trick the optimizer with a variable:
+var x = valueD
+echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x
+
+
+
+
diff --git a/tests/enum/toptions.nim b/tests/enum/toptions.nim
new file mode 100644
index 000000000..3c841de2c
--- /dev/null
+++ b/tests/enum/toptions.nim
@@ -0,0 +1,18 @@
+

+type

+  # please make sure we have under 32 options (improves code efficiency!)

+  TOption = enum

+    optNone, optForceFullMake, optBoehmGC, optRefcGC, optRangeCheck,

+    optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir,

+    optWarns, optHints, optDeadCodeElim, optListCmd, optCompileOnly,

+    optSafeCode,             # only allow safe code

+    optStyleCheck, optOptimizeSpeed, optOptimizeSize, optGenDynLib,

+    optGenGuiApp, optStackTrace

+

+  TOptionset = set[TOption]

+

+var

+  gOptions: TOptionset = {optRefcGC, optRangeCheck, optBoundsCheck,

+    optOverflowCheck, optAssert, optWarns, optHints, optLineDir, optStackTrace}

+  compilerArgs: int

+  gExitcode: int8

diff --git a/tests/exception/tcontinuexc.nim b/tests/exception/tcontinuexc.nim
new file mode 100644
index 000000000..f618abc14
--- /dev/null
+++ b/tests/exception/tcontinuexc.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tcontinuexc.nim"
+  outputsub: "ECcaught"
+  exitcode: "1"
+"""
+type
+  ESomething = object of E_Base
+  ESomeOtherErr = object of E_Base
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+try:
+  for i in 0..3:
+    try:
+      genErrors("error!")
+    except ESomething:
+      stdout.write("E")
+    stdout.write("C")
+    raise newException(EsomeotherErr, "bla")
+finally:  
+  echo "caught"
+
+#OUT ECcaught
+
+
+
diff --git a/tests/exception/tdefer1.nim b/tests/exception/tdefer1.nim
new file mode 100644
index 000000000..61439530a
--- /dev/null
+++ b/tests/exception/tdefer1.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''hi
+hi'''
+"""
+
+# bug #1742
+
+template test(): expr =
+    let a = 0
+    defer: echo "hi"
+    a
+
+let i = test()
+
+import strutils
+let x = try: parseInt("133a")
+        except: -1
+        finally: echo "hi"
diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim
new file mode 100644
index 000000000..00dd8ed9f
--- /dev/null
+++ b/tests/exception/texceptionbreak.nim
@@ -0,0 +1,45 @@
+discard """
+  file: "tnestedbreak.nim"
+  output: "1\n2\n3\n4"
+"""
+
+# First variety
+try:
+  raise newException(OSError, "Problem")
+except OSError:
+  for y in [1, 2, 3]:
+    discard
+  try:
+    discard
+  except OSError:
+    discard
+echo "1"
+
+# Second Variety
+try:
+  raise newException(OSError, "Problem")
+except OSError:
+  for y in [1, 2, 3]:
+    discard
+  for y in [1, 2, 3]:
+    discard
+
+echo "2"
+
+# Third Variety
+try:
+  raise newException(OSError, "Problem")
+except OSError:
+  block:
+    break
+
+echo "3"
+
+# Fourth Variety
+block:
+  try:
+    raise newException(OSError, "Problem")
+  except OSError:
+    break
+
+echo "4"
diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim
new file mode 100644
index 000000000..bdf338599
--- /dev/null
+++ b/tests/exception/texceptions.nim
@@ -0,0 +1,66 @@
+discard """
+  output: '''
+BEFORE
+FINALLY
+
+BEFORE
+EXCEPT
+FINALLY
+RECOVER
+
+BEFORE
+EXCEPT
+FINALLY
+'''
+"""
+
+echo ""
+
+proc no_expcetion =
+  try:
+    echo "BEFORE"
+
+  except:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: no_expcetion()
+except: echo "RECOVER"
+
+echo ""
+
+proc reraise_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "")
+
+  except IOError:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: reraise_in_except()
+except: echo "RECOVER"
+
+echo ""
+
+proc return_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "")
+
+  except:
+    echo "EXCEPT"
+    return
+
+  finally:
+    echo "FINALLY"
+
+try: return_in_except()
+except: echo "RECOVER"
+
diff --git a/tests/exception/texcpt1.nim b/tests/exception/texcpt1.nim
new file mode 100644
index 000000000..50a95eeec
--- /dev/null
+++ b/tests/exception/texcpt1.nim
@@ -0,0 +1,30 @@
+discard """
+  outputsub: "-6"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+proc raiseBla(): int =
+  try:
+    genErrors("errssor!")
+  except ESomething:
+    echo("Error happened")
+  except:
+    raise
+
+proc blah(): int =
+  try:
+    result = raiseBla()
+  except ESomeOtherErr:
+    result = -6
+
+echo blah()
+
+
diff --git a/tests/exception/texcsub.nim b/tests/exception/texcsub.nim
new file mode 100644
index 000000000..02125d2c0
--- /dev/null
+++ b/tests/exception/texcsub.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "texcsub.nim"
+  output: "caught!"
+"""
+# Test inheritance for exception matching:
+
+try:
+  raise newException(OSError, "dummy message")
+except Exception:
+  echo "caught!"
+except:
+  echo "wtf!?"
+
+#OUT caught!
+
+
+
diff --git a/tests/exception/tfinally.nim b/tests/exception/tfinally.nim
new file mode 100644
index 000000000..16fb3e7da
--- /dev/null
+++ b/tests/exception/tfinally.nim
@@ -0,0 +1,19 @@
+discard """
+  file: "tfinally.nim"
+  output: "came\nhere\n3"
+"""
+# Test return in try statement:
+
+proc main: int = 
+  try:
+    try:
+      return 1
+    finally:
+      echo("came")
+      return 2
+  finally: 
+    echo("here")
+    return 3
+
+echo main() #OUT came here 3
+
diff --git a/tests/exception/tfinally2.nim b/tests/exception/tfinally2.nim
new file mode 100644
index 000000000..e1e8d4c7e
--- /dev/null
+++ b/tests/exception/tfinally2.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tfinally2.nim"
+  output: '''A
+B
+C
+D'''
+"""
+# Test break in try statement:
+
+proc main: int = 
+  try:
+    block AB:
+      try:
+        try:
+          break AB
+        finally:
+          echo("A")
+        echo("skipped")
+      finally: 
+        block B:
+          echo("B")
+      echo("skipped")
+    echo("C")
+  finally:
+    echo("D")
+    
+discard main() #OUT ABCD
+
+
+
diff --git a/tests/exception/tfinally3.nim b/tests/exception/tfinally3.nim
new file mode 100644
index 000000000..e65661cd0
--- /dev/null
+++ b/tests/exception/tfinally3.nim
@@ -0,0 +1,18 @@
+discard """
+  file: "tfinally3.nim"
+  output: "false"
+"""
+# Test break in try statement:
+
+proc main: bool = 
+  while true:
+    try:
+      return true
+    finally:
+      break
+  return false
+
+echo main() #OUT false
+
+
+
diff --git a/tests/exception/tfinally4.nim b/tests/exception/tfinally4.nim
new file mode 100644
index 000000000..3aa707ff6
--- /dev/null
+++ b/tests/exception/tfinally4.nim
@@ -0,0 +1,40 @@
+discard """
+  file: "tfinally4.nim"
+  output: "B1\nA1\n1\nB1\nB2\ncatch\nA1\n1\nB1\nA1\nA2\n2\nB1\nB2\ncatch\nA1\nA2\n0\nB1\nA1\n1\nB1\nB2\nA1\n1\nB1\nA1\nA2\n2\nB1\nB2\nA1\nA2\n3"
+"""
+
+# More thorough test of return-in-finaly
+
+var raiseEx = true
+var returnA = true
+var returnB = false
+
+proc main: int =
+  try: #A
+    try: #B
+      if raiseEx:
+        raise newException(OSError, "")
+      return 3
+    finally: #B
+      echo "B1"
+      if returnB:
+        return 2
+      echo "B2"
+  except OSError: #A
+    echo "catch"
+  finally: #A
+    echo "A1"
+    if returnA:
+      return 1
+    echo "A2"
+
+for x in [true, false]:
+  for y in [true, false]:
+    for z in [true, false]:
+      # echo "raiseEx: " & $x
+      # echo "returnA: " & $y
+      # echo "returnB: " & $z
+      raiseEx = x
+      returnA = y
+      returnB = z
+      echo main()
diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim
new file mode 100644
index 000000000..1480764f1
--- /dev/null
+++ b/tests/exception/tnestedreturn.nim
@@ -0,0 +1,40 @@
+discard """
+  file: "tnestedreturn.nim"
+  output: "A\nB\nC\n"
+"""
+
+# Various tests of return nested in double try/except statements
+
+proc test1() =
+
+  defer: echo "A"
+
+  try:
+    raise newException(OSError, "Problem")
+  except OSError:
+    return
+
+test1()
+
+
+proc test2() =
+
+  defer: echo "B"
+
+  try:
+    return
+  except OSError:
+    discard
+
+test2()
+
+proc test3() =
+  try:
+    try:
+      raise newException(OSError, "Problem")
+    except OSError:
+      return
+  finally:
+    echo "C"
+
+test3()
diff --git a/tests/exception/tnestedreturn2.nim b/tests/exception/tnestedreturn2.nim
new file mode 100644
index 000000000..4bd2d535d
--- /dev/null
+++ b/tests/exception/tnestedreturn2.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "tnestedreturn2.nim"
+  outputsub: "Error: unhandled exception: Problem [OSError]"
+  exitcode: "1"
+"""
+
+proc test4() =
+  try:
+    try:
+      raise newException(OSError, "Problem")
+    except OSError:
+      return
+  finally:
+    discard
+
+# Should cause unhandled exception error,
+# but could cause segmentation fault if 
+# exceptions are not handled properly.
+test4()
+raise newException(OSError, "Problem")
diff --git a/tests/exception/tonraise.nim b/tests/exception/tonraise.nim
new file mode 100644
index 000000000..a155f0b8e
--- /dev/null
+++ b/tests/exception/tonraise.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''i: 1
+success'''
+"""
+
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+proc foo() =
+  var i = 0
+  try:
+    inc i
+    onRaise(proc (e: ref Exception): bool =
+      echo "i: ", i)
+    genErrors("errssor!")
+  except ESomething:
+    echo("ESomething happened")
+  except:
+    echo("Some other error happened")
+
+  # test that raise handler is gone:
+  try:
+    genErrors("error!")
+  except ESomething:
+    echo "success"
+
+foo()
diff --git a/tests/exception/treraise.nim b/tests/exception/treraise.nim
new file mode 100644
index 000000000..b2a11d34f
--- /dev/null
+++ b/tests/exception/treraise.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "treraise.nim"
+  outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
+  exitcode: "1"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+try:
+  genErrors("errssor!")
+except ESomething:
+  echo("Error happened")
+except:
+  raise
+
+
+
diff --git a/tests/exception/tunhandledexc.nim b/tests/exception/tunhandledexc.nim
new file mode 100644
index 000000000..aa9d61236
--- /dev/null
+++ b/tests/exception/tunhandledexc.nim
@@ -0,0 +1,23 @@
+discard """
+  file: "tunhandledexc.nim"
+  outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
+  exitcode: "1"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+when true:
+  try:
+    genErrors("errssor!")
+  except ESomething:
+    echo("Error happened")
+  
+
+
diff --git a/tests/exception/twrongexc.nim b/tests/exception/twrongexc.nim
new file mode 100644
index 000000000..4e921b8a3
--- /dev/null
+++ b/tests/exception/twrongexc.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "twrongexc.nim"
+  outputsub: "Error: unhandled exception:  [ValueError]"
+  exitcode: "1"
+"""
+try:
+  raise newException(ValueError, "")
+except OverflowError:
+  echo("Error caught")
+  
+
+
+
diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim
new file mode 100644
index 000000000..79323d82a
--- /dev/null
+++ b/tests/exprs/texprstmt.nim
@@ -0,0 +1,12 @@
+discard """
+  line: 10
+  errormsg: "value of type 'string' has to be discarded"
+"""
+
+# bug #578
+
+proc test: string =
+  result = "blah"
+  result[1 .. ^1]
+
+echo test()
diff --git a/tests/exprs/thighCString.nim b/tests/exprs/thighCString.nim
new file mode 100644
index 000000000..543966df4
--- /dev/null
+++ b/tests/exprs/thighCString.nim
@@ -0,0 +1,6 @@
+discard """
+  output: "5"
+"""
+let test = cstring("foobar")
+
+echo high(test)
diff --git a/tests/exprs/tifexpr_typeinference.nim b/tests/exprs/tifexpr_typeinference.nim
new file mode 100644
index 000000000..3ae95c571
--- /dev/null
+++ b/tests/exprs/tifexpr_typeinference.nim
@@ -0,0 +1,20 @@
+#bug #712
+
+import tables
+
+proc test(): TTable[string, string] =
+  discard
+
+proc test2(): TTable[string, string] =
+  discard
+
+var x = 5
+let blah =
+  case x
+  of 5:
+    test2()
+  of 2:
+    test()
+  else: test()
+
+echo blah.len
diff --git a/tests/exprs/tresultwarning.nim b/tests/exprs/tresultwarning.nim
new file mode 100644
index 000000000..32934408e
--- /dev/null
+++ b/tests/exprs/tresultwarning.nim
@@ -0,0 +1,6 @@
+discard """
+  nimout: "Special variable 'result' is shadowed. [ResultShadowed]"
+"""
+
+proc test(): string =
+  var result = "foo"
diff --git a/tests/exprs/tstmtexp.nim b/tests/exprs/tstmtexp.nim
new file mode 100644
index 000000000..fe60dd3ba
--- /dev/null
+++ b/tests/exprs/tstmtexp.nim
@@ -0,0 +1,9 @@
+discard """
+  file: "tstmtexp.nim"
+  line: 8
+  errormsg: "value of type 'int literal(5)' has to be discarded"
+"""
+# Test 3
+
+1+4
+
diff --git a/tests/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim
new file mode 100644
index 000000000..d6b827b6d
--- /dev/null
+++ b/tests/exprs/tstmtexprs.nim
@@ -0,0 +1,124 @@
+discard """
+  output: '''24
+(bar: bar)
+1244
+6
+abcdefghijklmnopqrstuvwxyz
+145 23
+3'''
+"""
+
+import strutils
+
+const fac4 = (var x = 1; for i in 1..4: x *= i; x)
+
+echo fac4
+
+when true:
+  proc test(foo: proc (x, y: int): bool) =
+    echo foo(5, 5)
+
+
+  type Foo = object
+    bar: string
+
+  proc newfoo(): Foo =
+    result.bar = "bar"
+
+  echo($newfoo())
+   
+
+  proc retInt(x, y: int): int = 
+    if (var yy = 0; yy != 0):
+      echo yy
+    else:
+      echo(try: parseInt("1244") except EINvalidValue: -1)
+    result = case x
+             of 23: 3
+             of 64: 
+                    case y
+                    of 1: 2
+                    of 2: 3
+                    of 3: 6
+                    else: 8
+             else: 1
+
+  echo retInt(64, 3)
+
+  proc buildString(): string =
+    result = ""
+    for x in 'a'..'z':
+      result.add(x)
+
+  echo buildString()
+
+#test(
+#  proc (x, y: int): bool =
+#  if x == 5: return true
+#  if x == 2: return false
+#  if y == 78: return true
+#)
+
+proc q(): int {.discardable.} = 145
+proc p(): int =
+  q()
+
+proc p2(a: int): int =
+  # result enforces a void context:
+  if a == 2:
+    result = 23
+  q()
+
+echo p(), " ", p2(2)
+
+proc semiProblem() =
+  if false: echo "aye"; echo "indeed"
+
+semiProblem()
+
+
+# bug #844
+
+import json 
+proc parseResponse(): PJsonNode =
+  result = % { "key1": % { "key2": % "value" } }
+  for key, val in result["key1"]:
+    var excMsg = key & "("
+    if (var n=result["key2"]; n != nil):
+      excMsg &= n.str
+    raise newException(ESynch, excMsg)
+
+
+
+#bug #992
+var se = @[1,2]
+let b = (se[1] = 1; 1)
+
+
+# bug #1161
+
+type
+  PFooBase = ref object of PObject
+    field: int
+
+  PFoo[T] = ref object of PFooBase
+    field2: T
+
+var testIf =
+  if true:
+    2
+  else:
+    3
+
+var testCase =
+  case 8
+  of 8: 9
+  else: 10
+
+var testTry =
+  try:
+    PFoo[string](field: 3, field2: "asfasf")
+  except:
+    PFooBase(field: 5)
+
+echo(testTry.field)
diff --git a/tests/fields/tfieldindex.nim b/tests/fields/tfieldindex.nim
new file mode 100644
index 000000000..f0674af54
--- /dev/null
+++ b/tests/fields/tfieldindex.nim
@@ -0,0 +1,21 @@
+discard """
+  output: "1"
+"""
+
+type
+  TMyTuple = tuple[a, b: int]
+
+proc indexOf*(t: typedesc, name: string): int =
+  ## takes a tuple and looks for the field by name.
+  ## returs index of that field.
+  var
+    d: t
+    i = 0
+  for n, x in fieldPairs(d):
+    if n == name: return i
+    i.inc
+  raise newException(EInvalidValue, "No field " & name & " in type " & 
+    astToStr(t))
+
+echo TMyTuple.indexOf("b")
+
diff --git a/tests/fields/tfielditerator.nim b/tests/fields/tfielditerator.nim
new file mode 100644
index 000000000..2919aab41
--- /dev/null
+++ b/tests/fields/tfielditerator.nim
@@ -0,0 +1,46 @@
+discard """
+  output: '''
+a char: true
+a char: false
+an int: 5
+an int: 6
+a string: abc
+false
+true
+true
+false
+true
+a: a
+b: b
+x: 5
+y: 6
+z: abc
+'''
+"""
+
+type
+  TMyTuple = tuple[a, b: char, x, y: int, z: string]
+
+proc p(x: char) = echo "a char: ", x <= 'a'
+proc p(x: int) = echo "an int: ", x
+proc p(x: string) = echo "a string: ", x
+
+var x: TMyTuple = ('a', 'b', 5, 6, "abc")
+var y: TMyTuple = ('A', 'b', 5, 9, "abc")
+
+for f in fields(x): 
+  p f
+
+for a, b in fields(x, y):
+  echo a == b
+
+for key, val in fieldPairs(x):
+  echo key, ": ", val
+
+assert x != y
+assert x == x
+assert(not (x < x))
+assert x <= x
+assert y < x
+assert y <= x
+
diff --git a/tests/fields/tfielditerator2.nim b/tests/fields/tfielditerator2.nim
new file mode 100644
index 000000000..70ab9e2ab
--- /dev/null
+++ b/tests/fields/tfielditerator2.nim
@@ -0,0 +1,70 @@
+discard """
+  output: '''
+a char: true
+a char: false
+an int: 5
+an int: 6
+a string: abc
+a string: I'm root!
+CMP false
+CMP true
+CMP true
+CMP false
+CMP true
+CMP true
+a: a
+b: b
+x: 5
+y: 6
+z: abc
+thaRootMan: I'm root!
+myDisc: enC
+c: Z
+enC
+Z
+'''
+"""
+
+type
+  SomeRootObj = object of RootObj
+    thaRootMan: string
+  TMyObj = object of SomeRootObj
+    a, b: char
+    x, y: int
+    z: string
+    
+  TEnum = enum enA, enB, enC
+  TMyCaseObj = object
+    case myDisc: TEnum
+    of enA: a: int
+    of enB: b: string
+    of enC: c: char
+
+proc p(x: char) = echo "a char: ", x <= 'a'
+proc p(x: int) = echo "an int: ", x
+proc p(x: string) = echo "a string: ", x
+
+proc myobj(a, b: char, x, y: int, z: string): TMyObj =
+  result.a = a; result.b = b; result.x = x; result.y = y; result.z = z
+  result.thaRootMan = "I'm root!"
+
+var x = myobj('a', 'b', 5, 6, "abc")
+var y = myobj('A', 'b', 5, 9, "abc")
+
+for f in fields(x): 
+  p f
+
+for a, b in fields(x, y):
+  echo "CMP ", a == b
+
+for key, val in fieldPairs(x):
+  echo key, ": ", val
+
+var co: TMyCaseObj
+co.myDisc = enC
+co.c = 'Z'
+for key, val in fieldPairs(co):
+  echo key, ": ", val
+
+for val in fields(co):
+  echo val
diff --git a/tests/fields/tfields_in_template.nim b/tests/fields/tfields_in_template.nim
new file mode 100644
index 000000000..9352a7a51
--- /dev/null
+++ b/tests/fields/tfields_in_template.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''n
+n'''
+"""
+
+# bug #1902
+# This works.
+for name, value in (n: "v").fieldPairs:
+  echo name
+
+# This doesn't compile - "expression 'name' has no type (or is ambiguous)".
+template wrapper: stmt =
+  for name, value in (n: "v").fieldPairs:
+    echo name
+wrapper()
diff --git a/tests/fields/tfields_with_break.nim b/tests/fields/tfields_with_break.nim
new file mode 100644
index 000000000..1f2632692
--- /dev/null
+++ b/tests/fields/tfields_with_break.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''(one: 1, two: 2, three: 3)
+1
+2
+3
+(one: 4, two: 5, three: 6)
+4
+(one: 7, two: 8, three: 9)
+7
+8
+9'''
+"""
+
+# bug #2134
+type
+    TestType = object
+        one: int
+        two: int
+        three: int
+
+var
+    ab = TestType(one:1, two:2, three:3)
+    ac = TestType(one:4, two:5, three:6)
+    ad = TestType(one:7, two:8, three:9)
+    tstSeq = [ab, ac, ad]
+
+for tstElement in mitems(tstSeq):
+    echo tstElement
+    for tstField in fields(tstElement):
+        #for tstField in [1,2,4,6]:
+        echo tstField
+        if tstField == 4:
+            break
diff --git a/tests/float/tfloat1.nim b/tests/float/tfloat1.nim
new file mode 100644
index 000000000..ed99260ea
--- /dev/null
+++ b/tests/float/tfloat1.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tfloat1.nim"
+  outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowError]"
+  exitcode: "1"
+"""
+# Test new floating point exceptions
+
+{.floatChecks: on.}
+
+var x = 0.8
+var y = 0.0
+
+echo x / y #OUT Error: unhandled exception: FPU operation caused an overflow
+
+
diff --git a/tests/float/tfloat2.nim b/tests/float/tfloat2.nim
new file mode 100644
index 000000000..b84120fba
--- /dev/null
+++ b/tests/float/tfloat2.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tfloat2.nim"
+  outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpError]"
+  exitcode: "1"
+"""
+# Test new floating point exceptions
+
+{.floatChecks: on.}
+
+var x = 0.0
+var y = 0.0
+
+echo x / y #OUT Error: unhandled exception: FPU operation caused a NaN result
+
+
diff --git a/tests/float/tfloat3.nim b/tests/float/tfloat3.nim
new file mode 100644
index 000000000..a3f5a2fc7
--- /dev/null
+++ b/tests/float/tfloat3.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tfloat3.nim"
+  output: "Nim    3.4368930843, 0.3299290698 C double: 3.4368930843, 0.3299290698"
+"""
+
+import math, strutils
+
+{.emit: """
+void printFloats(void) {
+    double y = 1.234567890123456789;
+    
+    printf("C double: %.10f, %.10f ", exp(y), cos(y));
+}
+""".}
+
+proc c_printf(frmt: cstring) {.importc: "printf", header: "<stdio.h>", varargs.}
+proc printFloats {.importc, nodecl.}
+
+var x: float = 1.234567890123456789
+c_printf("Nim    %.10f, %.10f ", exp(x), cos(x))
+printFloats()
+
+
+
diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim
new file mode 100644
index 000000000..960c4e5f7
--- /dev/null
+++ b/tests/float/tfloat4.nim
@@ -0,0 +1,42 @@
+import math, strutils
+
+proc c_sprintf(buf, fmt: cstring) {.importc:"sprintf", header: "<stdio.h>", varargs.}
+
+proc floatToStr(f: float64): string =
+  var buffer: array[128, char]
+  c_sprintf(buffer, "%.16e", f)
+  result = ""
+  for ch in buffer:
+    if ch == '\0':
+      return
+    add(result, ch)
+
+let testFloats = [
+  "0", "-1", "1", "1.", ".3", "3.3", "-.3", "-99.99",
+  "1.1e10", "-2e100", "1.234e-10", "1.234e+10",
+  "-inf", "inf", "+inf",
+  "3.14159265358979323846264338327950288",
+  "1.57079632679489661923132169163975144",
+  "0.785398163397448309615660845819875721",
+  "1.41421356237309504880168872420969808",
+  "0.707106781186547524400844362104849039",
+  "2.71828182845904523536028747135266250",
+  "0.00097656250000000021684043449710088680149056017398834228515625"
+]
+
+for num in testFloats:
+  assert num.parseFloat.floatToStr.parseFloat == num.parseFloat
+
+assert "0".parseFloat == 0.0
+assert "-.1".parseFloat == -0.1
+assert "2.5e1".parseFloat == 25.0
+assert "1e10".parseFloat == 10_000_000_000.0
+assert "0.000_005".parseFloat == 5.000_000e-6
+assert "1.234_567e+2".parseFloat == 123.4567
+assert "1e1_00".parseFloat == "1e100".parseFloat
+assert "3.1415926535897932384626433".parseFloat ==
+       3.1415926535897932384626433
+assert "2.71828182845904523536028747".parseFloat ==
+       2.71828182845904523536028747
+assert 0.00097656250000000021684043449710088680149056017398834228515625 ==
+     "0.00097656250000000021684043449710088680149056017398834228515625".parseFloat
diff --git a/tests/friends/mfriends.nim b/tests/friends/mfriends.nim
new file mode 100644
index 000000000..f1c663655
--- /dev/null
+++ b/tests/friends/mfriends.nim
@@ -0,0 +1,11 @@
+
+type
+  TMyObj = object 
+    x: int
+    
+proc gen*[T](): T = 
+  var d: TMyObj
+  # access private field here
+  d.x = 3
+  result = d.x
+
diff --git a/tests/friends/tfriends.nim b/tests/friends/tfriends.nim
new file mode 100644
index 000000000..1e70d50a5
--- /dev/null
+++ b/tests/friends/tfriends.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "3"
+"""
+
+# Tests that a generic instantiation from a different module may access
+# private object fields:
+
+import mfriends
+
+echo gen[int]()
+
diff --git a/tests/gc/bintrees.nim b/tests/gc/bintrees.nim
new file mode 100644
index 000000000..5b65bb437
--- /dev/null
+++ b/tests/gc/bintrees.nim
@@ -0,0 +1,54 @@
+# -*- nim -*-
+
+import os, strutils
+
+type
+  PNode = ref TNode
+  TNode {.final, acyclic.} = object
+    left, right: PNode
+    item: int
+
+proc checkTree(node: PNode): int =
+  result = node.item
+  if node.left != nil:
+    inc result, checkTree(node.left) - checkTree(node.right)
+
+proc makeTreeAux(item, depth: int): PNode =
+  new(result)
+  result.item = item
+  if depth > 0:
+    result.left = makeTreeAux(2 * item - 1, depth - 1)
+    result.right = makeTreeAux(2 * item,    depth - 1)
+
+proc makeTree(item, depth: int): PNode =
+  #GC_disable()
+  result = makeTreeAux(item, depth)
+  #GC_enable()
+
+proc main =
+  var n = parseInt(paramStr(1))
+  const minDepth = 4
+  var maxDepth = if minDepth+2 > n: minDepth+2 else: n
+
+  var stretchDepth = maxDepth + 1
+
+  echo("stretch tree of depth ", stretchDepth, "\t check: ", checkTree(
+      makeTree(0, stretchDepth)))
+
+  var longLivedTree = makeTree(0, maxDepth)
+
+  var iterations = 1 shl maxDepth
+  for depth in countup (minDepth, stretchDepth-1, 2):
+    var check = 0
+    for i in 1..iterations:
+      check += checkTree(makeTree(i, depth)) + checkTree(makeTree(-i, depth))
+
+    echo(iterations*2, "\t trees of depth ", depth, "\t check: ", check)
+    iterations = iterations div 4
+
+  echo("long lived tree of depth ", maxDepth, "\t check: ",
+      longLivedTree.checkTree)
+  echo GC_getstatistics()
+
+main()
+
diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim
new file mode 100644
index 000000000..1c39f43d5
--- /dev/null
+++ b/tests/gc/closureleak.nim
@@ -0,0 +1,33 @@
+discard """
+  outputsub: "true"
+"""
+
+from strutils import join
+
+type
+  TFoo * = object
+    id: int
+    fn: proc(){.closure.}
+var foo_counter = 0
+var alive_foos = newseq[int](0)
+
+proc free*(some: ref TFoo) =
+  #echo "Tfoo #", some.id, " freed"
+  alive_foos.del alive_foos.find(some.id)
+proc newFoo*(): ref TFoo =
+  new result, free
+  
+  result.id = foo_counter
+  alive_foos.add result.id
+  inc foo_counter
+
+for i in 0 .. <10:
+ discard newFoo()
+
+for i in 0 .. <10:
+  let f = newFoo()
+  f.fn = proc = 
+    echo f.id
+
+GC_fullcollect()
+echo alive_foos.len <= 3
diff --git a/tests/gc/cyclecollector.nim b/tests/gc/cyclecollector.nim
new file mode 100644
index 000000000..46fed6c45
--- /dev/null
+++ b/tests/gc/cyclecollector.nim
@@ -0,0 +1,21 @@
+
+# Program to detect bug #1796 reliably
+
+type
+  Node = ref object
+    a, b: Node
+    leaf: string
+
+proc createCycle(leaf: string): Node =
+  new result
+  result.a = result
+  shallowCopy result.leaf, leaf
+
+proc main =
+  for i in 0 .. 100_000:
+    var leaf = "this is the leaf. it allocates"
+    let x = createCycle(leaf)
+    let y = createCycle(leaf)
+  echo "done ", getOccupiedMem()
+
+main()
diff --git a/tests/gc/cycleleak.nim b/tests/gc/cycleleak.nim
new file mode 100644
index 000000000..9f5c30ebd
--- /dev/null
+++ b/tests/gc/cycleleak.nim
@@ -0,0 +1,56 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  Module = object
+    nodes*: seq[PNode]
+    id: int
+
+  PModule = ref Module
+
+  Node = object
+    owner*: PModule
+    data*: array[0..200, char] # some fat to drain memory faster
+    id: int
+
+  PNode = ref Node
+
+var
+  gid: int
+
+when false:
+  proc finalizeNode(x: PNode) =
+    echo "node id: ", x.id
+  proc finalizeModule(x: PModule) =
+    echo "module id: ", x.id
+
+proc newNode(owner: PModule): PNode =
+  new(result)
+  result.owner = owner
+  inc gid
+  result.id = gid
+
+proc compileModule: PModule =
+  new(result)
+  result.nodes = @[]
+  for i in 0..100:
+    result.nodes.add newNode(result)
+  inc gid
+  result.id = gid
+
+var gModuleCache: PModule
+
+proc loop =
+  for i in 0..1000:
+    gModuleCache = compileModule()
+    gModuleCache = nil
+    GC_fullCollect()
+
+    if getOccupiedMem() > 9_000_000:
+      echo "still a leak! ", getOccupiedMem()
+      quit(1)
+  echo "no leak: ", getOccupiedMem()
+
+loop()
+
diff --git a/tests/gc/gcbench.nim b/tests/gc/gcbench.nim
new file mode 100644
index 000000000..44d952baa
--- /dev/null
+++ b/tests/gc/gcbench.nim
@@ -0,0 +1,168 @@
+discard """

+  outputsub: "Success!"

+"""

+

+# This is adapted from a benchmark written by John Ellis and Pete Kovac

+# of Post Communications.

+# It was modified by Hans Boehm of Silicon Graphics.

+#

+# This is no substitute for real applications. No actual application

+# is likely to behave in exactly this way. However, this benchmark was

+# designed to be more representative of real applications than other

+# Java GC benchmarks of which we are aware.

+# It attempts to model those properties of allocation requests that

+# are important to current GC techniques.

+# It is designed to be used either to obtain a single overall performance

+# number, or to give a more detailed estimate of how collector

+# performance varies with object lifetimes. It prints the time

+# required to allocate and collect balanced binary trees of various

+# sizes. Smaller trees result in shorter object lifetimes. Each cycle

+# allocates roughly the same amount of memory.

+# Two data structures are kept around during the entire process, so

+# that the measured performance is representative of applications

+# that maintain some live in-memory data. One of these is a tree

+# containing many pointers. The other is a large array containing

+# double precision floating point numbers. Both should be of comparable

+# size.

+#

+# The results are only really meaningful together with a specification

+# of how much memory was used. It is possible to trade memory for

+# better time performance. This benchmark should be run in a 32 MB

+# heap, though we don't currently know how to enforce that uniformly.

+#

+# Unlike the original Ellis and Kovac benchmark, we do not attempt

+# measure pause times. This facility should eventually be added back

+# in. There are several reasons for omitting it for now.  The original

+# implementation depended on assumptions about the thread scheduler

+# that don't hold uniformly. The results really measure both the

+# scheduler and GC. Pause time measurements tend to not fit well with

+# current benchmark suites. As far as we know, none of the current

+# commercial Java implementations seriously attempt to minimize GC pause

+# times.

+#

+# Known deficiencies:

+# - No way to check on memory use

+# - No cyclic data structures

+# - No attempt to measure variation with object size

+# - Results are sensitive to locking cost, but we dont

+#   check for proper locking

+#

+

+import

+  strutils, times

+

+type

+  PNode = ref TNode

+  TNode {.final.} = object

+    left, right: PNode

+    i, j: int

+

+proc newNode(L, r: PNode): PNode =

+  new(result)

+  result.left = L

+  result.right = r

+

+const

+  kStretchTreeDepth = 18 # about 16Mb

+  kLongLivedTreeDepth = 16  # about 4Mb

+  kArraySize  = 500000  # about 4Mb

+  kMinTreeDepth = 4

+  kMaxTreeDepth = 16

+

+# Nodes used by a tree of a given size

+proc TreeSize(i: int): int = return ((1 shl (i + 1)) - 1)

+

+# Number of iterations to use for a given tree depth

+proc NumIters(i: int): int =

+  return 2 * TreeSize(kStretchTreeDepth) div TreeSize(i)

+

+# Build tree top down, assigning to older objects.

+proc Populate(iDepth: int, thisNode: PNode) =

+  if iDepth <= 0:

+    return

+  else:

+    new(thisNode.left)

+    new(thisNode.right)

+    Populate(iDepth-1, thisNode.left)

+    Populate(iDepth-1, thisNode.right)

+

+# Build tree bottom-up

+proc MakeTree(iDepth: int): PNode =

+  if iDepth <= 0:

+    new(result)

+  else:

+    return newNode(MakeTree(iDepth-1), MakeTree(iDepth-1))

+

+proc PrintDiagnostics() =

+  echo("Total memory available: " & $getTotalMem() & " bytes")

+  echo("Free memory: " & $getFreeMem() & " bytes")

+

+proc TimeConstruction(depth: int) =

+  var

+    root, tempTree: PNode

+    iNumIters: int

+

+  iNumIters = NumIters(depth)

+

+  echo("Creating " & $iNumIters & " trees of depth " & $depth)

+  var t = epochTime()

+  for i in 0..iNumIters-1:

+    new(tempTree)

+    Populate(depth, tempTree)

+    tempTree = nil

+  echo("\tTop down construction took " & $(epochTime() - t) & "msecs")

+  t = epochTime()

+  for i in 0..iNumIters-1:

+    tempTree = MakeTree(depth)

+    tempTree = nil

+  echo("\tBottom up construction took " & $(epochTime() - t) & "msecs")

+

+type

+  tMyArray = seq[float]

+

+proc main() =

+  var

+    root, longLivedTree, tempTree: PNode

+    myarray: tMyArray

+

+  echo("Garbage Collector Test")

+  echo(" Stretching memory with a binary tree of depth " & $kStretchTreeDepth)

+  PrintDiagnostics()

+  var t = epochTime()

+

+  # Stretch the memory space quickly

+  tempTree = MakeTree(kStretchTreeDepth)

+  tempTree = nil

+

+  # Create a long lived object

+  echo(" Creating a long-lived binary tree of depth " &

+        $kLongLivedTreeDepth)

+  new(longLivedTree)

+  Populate(kLongLivedTreeDepth, longLivedTree)

+

+  # Create long-lived array, filling half of it

+  echo(" Creating a long-lived array of " & $kArraySize & " doubles")

+  newSeq(myarray, kArraySize)

+  for i in 0..kArraySize div 2 -1:

+    myarray[i] = 1.0 / toFloat(i)

+

+  PrintDiagnostics()

+

+  var d = kMinTreeDepth

+  while d <= kMaxTreeDepth:

+    TimeConstruction(d)

+    inc(d, 2)

+

+  if longLivedTree == nil or myarray[1000] != 1.0/1000.0:

+    echo("Failed")

+    # fake reference to LongLivedTree

+    # and array to keep them from being optimized away

+

+  var elapsed = epochTime() - t

+  PrintDiagnostics()

+  echo("Completed in " & $elapsed & "ms. Success!")

+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+

+main()

diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim
new file mode 100644
index 000000000..4e47db609
--- /dev/null
+++ b/tests/gc/gcleak.nim
@@ -0,0 +1,23 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TTestObj = object of TObject
+    x: string
+
+proc MakeObj(): TTestObj =
+  result.x = "Hello"
+
+for i in 1 .. 1_000_000:
+  when defined(gcMarkAndSweep):
+    GC_fullcollect()
+  var obj = MakeObj()
+  if getOccupiedMem() > 300_000: quit("still a leak!")
+#  echo GC_getstatistics()
+
+echo "no leak: ", getOccupiedMem()
+
diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim
new file mode 100644
index 000000000..41d149bed
--- /dev/null
+++ b/tests/gc/gcleak2.nim
@@ -0,0 +1,28 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TTestObj = object of TObject
+    x: string
+    s: seq[int]
+
+proc MakeObj(): TTestObj =
+  result.x = "Hello"
+  result.s = @[1,2,3]
+
+proc inProc() = 
+  for i in 1 .. 1_000_000:
+    when defined(gcMarkAndSweep):
+      GC_fullcollect()
+    var obj: TTestObj
+    obj = MakeObj()
+    if getOccupiedMem() > 300_000: quit("still a leak!")
+
+inProc()
+echo "no leak: ", getOccupiedMem()
+
+
diff --git a/tests/gc/gcleak3.nim b/tests/gc/gcleak3.nim
new file mode 100644
index 000000000..588e238e9
--- /dev/null
+++ b/tests/gc/gcleak3.nim
@@ -0,0 +1,30 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TSomething = object
+    s: string
+    s1: string
+var s: seq[TSomething] = @[]
+for i in 0..1024:
+  var obj: TSomething
+  obj.s = "blah"
+  obj.s1 = "asd"
+  s.add(obj)
+
+proc limit*[t](a: var seq[t]) =
+  var loop = s.len() - 512
+  for i in 0..loop:
+    #echo i
+    #GC_fullCollect()
+    if getOccupiedMem() > 3000_000: quit("still a leak!")
+    s.delete(i)
+
+s.limit()
+
+echo "no leak: ", getOccupiedMem()
+
diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim
new file mode 100644
index 000000000..54e74ac7b
--- /dev/null
+++ b/tests/gc/gcleak4.nim
@@ -0,0 +1,51 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TExpr = object {.inheritable.} ## abstract base class for an expression
+  PLiteral = ref TLiteral
+  TLiteral = object of TExpr
+    x: int
+    op1: string
+  TPlusExpr = object of TExpr
+    a, b: ref TExpr
+    op2: string
+    
+method eval(e: ref TExpr): int =
+  # override this base method
+  quit "to override!"
+
+method eval(e: ref TLiteral): int = return e.x
+
+method eval(e: ref TPlusExpr): int =
+  # watch out: relies on dynamic binding
+  return eval(e.a) + eval(e.b)
+
+proc newLit(x: int): ref TLiteral =
+  new(result)
+  {.watchpoint: result.}
+  result.x = x
+  result.op1 = $getOccupiedMem()
+  
+proc newPlus(a, b: ref TExpr): ref TPlusExpr =
+  new(result)
+  {.watchpoint: result.}
+  result.a = a
+  result.b = b
+  result.op2 = $getOccupiedMem()
+
+const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 500_000
+
+for i in 0..100_000:
+  var s: array[0..11, ref TExpr]
+  for j in 0..high(s):
+    s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4))
+    if eval(s[j]) != j+6:
+      quit "error: wrong result"
+  if getOccupiedMem() > Limit: quit("still a leak!")
+
+echo "no leak: ", getOccupiedMem()
diff --git a/tests/gc/gcleak5.nim b/tests/gc/gcleak5.nim
new file mode 100644
index 000000000..9e2948729
--- /dev/null
+++ b/tests/gc/gcleak5.nim
@@ -0,0 +1,25 @@
+discard """
+  output: "success"
+"""
+
+import os, times
+
+proc main =
+  var i = 0
+  for ii in 0..50_000:
+    #while true:
+    var t = getTime()
+    var g = t.getGMTime()
+    #echo isOnStack(addr g)
+    
+    if i mod 100 == 0:
+      let om = getOccupiedMem()
+      #echo "memory: ", om
+      if om > 100_000: quit "leak"
+     
+    inc(i)
+    sleep(1)
+
+  echo "success"
+
+main()
diff --git a/tests/gc/gctest.nim b/tests/gc/gctest.nim
new file mode 100644
index 000000000..2213a83ac
--- /dev/null
+++ b/tests/gc/gctest.nim
@@ -0,0 +1,203 @@
+discard """
+  outputsub: "finished"
+"""
+
+# Test the garbage collector.
+
+import
+  strutils
+
+type
+  PNode = ref TNode
+  TNode {.final.} = object
+    le, ri: PNode
+    data: string
+
+  TTable {.final.} = object
+    counter, max: int
+    data: seq[string]
+
+  TBNode {.final.} = object
+    other: PNode  # a completely different tree
+    data: string
+    sons: seq[TBNode] # directly embedded!
+    t: TTable
+    
+  TCaseKind = enum nkStr, nkWhole, nkList
+  PCaseNode = ref TCaseNode
+  TCaseNode {.final.} = object
+    case kind: TCaseKind
+    of nkStr: data: string
+    of nkList: sons: seq[PCaseNode]
+    else: unused: seq[string]
+
+  TIdObj* = object of TObject
+    id*: int  # unique id; use this for comparisons and not the pointers
+  
+  PIdObj* = ref TIdObj
+  PIdent* = ref TIdent
+  TIdent*{.acyclic.} = object of TIdObj
+    s*: string
+    next*: PIdent             # for hash-table chaining
+    h*: int                   # hash value of s
+
+var
+  flip: int
+
+proc newCaseNode(data: string): PCaseNode =
+  new(result)
+  if flip == 0:
+    result.kind = nkStr
+    result.data = data
+  else:
+    result.kind = nkWhole
+    result.unused = @["", "abc", "abdc"]
+  flip = 1 - flip
+  
+proc newCaseNode(a, b: PCaseNode): PCaseNode =
+  new(result)
+  result.kind = nkList
+  result.sons = @[a, b]
+  
+proc caseTree(lvl: int = 0): PCaseNode =
+  if lvl == 3: result = newCaseNode("data item")
+  else: result = newCaseNode(caseTree(lvl+1), caseTree(lvl+1))
+
+proc finalizeBNode(n: TBNode) = writeln(stdout, n.data)
+proc finalizeNode(n: PNode) =
+  assert(n != nil)
+  write(stdout, "finalizing: ")
+  if isNil(n.data): writeln(stdout, "nil!")
+  else: writeln(stdout, n.data)
+
+var
+  id: int = 1
+
+proc buildTree(depth = 1): PNode =
+  if depth == 7: return nil
+  new(result, finalizeNode)
+  result.le = buildTree(depth+1)
+  result.ri = buildTree(depth+1)
+  result.data = $id
+  inc(id)
+
+proc returnTree(): PNode =
+  writeln(stdout, "creating id: " & $id)
+  new(result, finalizeNode)
+  result.data = $id
+  new(result.le, finalizeNode)
+  result.le.data = $id & ".1"
+  new(result.ri, finalizeNode)
+  result.ri.data = $id & ".2"
+  inc(id)
+
+  # now create a cycle:
+  writeln(stdout, "creating id (cyclic): " & $id)
+  var cycle: PNode
+  new(cycle, finalizeNode)
+  cycle.data = $id
+  cycle.le = cycle
+  cycle.ri = cycle
+  inc(id)
+  #writeln(stdout, "refcount: " & $refcount(cycle))
+  #writeln(stdout, "refcount le: " & $refcount(cycle.le))
+  #writeln(stdout, "refcount ri: " & $refcount(cycle.ri))
+
+proc printTree(t: PNode) =
+  if t == nil: return
+  writeln(stdout, "printing")
+  writeln(stdout, t.data)
+  printTree(t.le)
+  printTree(t.ri)
+
+proc unsureNew(result: var PNode) =
+  writeln(stdout, "creating unsure id: " & $id)
+  new(result, finalizeNode)
+  result.data = $id
+  new(result.le, finalizeNode)
+  result.le.data = $id & ".a"
+  new(result.ri, finalizeNode)
+  result.ri.data = $id & ".b"
+  inc(id)
+
+proc setSons(n: var TBNode) =
+  n.sons = @[] # free memory of the sons
+  n.t.data = @[]
+  var
+    m: seq[string]
+  m = @[]
+  setLen(m, len(n.t.data) * 2)
+  for i in 0..high(m):
+    m[i] = "..."
+  n.t.data = m
+
+proc buildBTree(father: var TBNode) =
+  father.data = "father"
+  father.other = nil
+  father.sons = @[]
+  for i in 1..10:
+    write(stdout, "next iteration!\n")
+    var n: TBNode
+    n.other = returnTree()
+    n.data = "B node: " & $i
+    if i mod 2 == 0: n.sons = @[] # nil and [] need to be handled correctly!
+    add father.sons, n
+    father.t.counter = 0
+    father.t.max = 3
+    father.t.data = @["ha", "lets", "stress", "it"]
+  setSons(father)
+
+proc getIdent(identifier: cstring, length: int, h: int): PIdent = 
+  new(result)
+  result.h = h
+  result.s = newString(length)
+
+proc main() =
+  discard getIdent("addr", 4, 0)
+  discard getIdent("hall", 4, 0)
+  discard getIdent("echo", 4, 0)
+  discard getIdent("huch", 4, 0)
+  
+  var
+    father: TBNode
+  for i in 1..1_00:
+    buildBTree(father)
+
+  for i in 1..1_00:
+    var t = returnTree()
+    var t2: PNode
+    unsureNew(t2)
+  write(stdout, "now building bigger trees: ")
+  var t2: PNode
+  for i in 1..100:
+    t2 = buildTree()
+  printTree(t2)
+  write(stdout, "now test sequences of strings:")
+  var s: seq[string] = @[]
+  for i in 1..100:
+    add s, "hohoho" # test reallocation
+  writeln(stdout, s[89])
+  write(stdout, "done!\n")
+
+var
+    father: TBNode
+    s: string
+s = ""
+s = ""
+writeln(stdout, repr(caseTree()))
+father.t.data = @["ha", "lets", "stress", "it"]
+father.t.data = @["ha", "lets", "stress", "it"]
+var t = buildTree()
+write(stdout, repr(t[]))
+buildBTree(father)
+write(stdout, repr(father))
+
+write(stdout, "starting main...\n")
+main()
+
+GC_fullCollect()
+# the M&S GC fails with this call and it's unclear why. Definitely something
+# we need to fix!
+GC_fullCollect()
+writeln(stdout, GC_getStatistics())
+write(stdout, "finished\n")
diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim
new file mode 100644
index 000000000..a16468c7e
--- /dev/null
+++ b/tests/gc/growobjcrash.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "works"
+"""
+
+import cgi, strtabs
+
+proc handleRequest(query: string): StringTableRef =
+  iterator foo(): StringTableRef {.closure.} =
+    var params = {:}.newStringTable()
+    for key, val in cgi.decodeData(query):
+      params[key] = val
+    yield params
+
+  let x = foo
+  result = x()
+
+const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000
+
+proc main =
+  var counter = 0
+  for i in 0 .. 100_000:
+    for k, v in handleRequest("nick=Elina2&type=activate"):
+      inc counter
+      if counter mod 100 == 0:
+        if getOccupiedMem() > Limit:
+          quit "but now a leak"
+
+main()
+echo "works"
diff --git a/tests/gc/refarrayleak.nim b/tests/gc/refarrayleak.nim
new file mode 100644
index 000000000..12c9145f8
--- /dev/null
+++ b/tests/gc/refarrayleak.nim
@@ -0,0 +1,39 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  TNode = object
+    data: array[0..300, char]
+
+  PNode = ref TNode
+
+  TNodeArray = array[0..10, PNode]
+
+  TArrayHolder = object
+    sons: TNodeArray
+
+proc nullify(a: var TNodeArray) =
+  for i in 0..high(a):
+    a[i] = nil
+
+proc newArrayHolder: ref TArrayHolder =
+  new result
+
+  for i in 0..high(result.sons):
+    new result.sons[i]
+
+  nullify result.sons
+
+proc loop =
+  for i in 0..10000:
+    discard newArrayHolder()
+    
+  if getOccupiedMem() > 300_000:
+    echo "still a leak! ", getOccupiedMem()
+    quit 1
+  else:
+    echo "no leak: ", getOccupiedMem()
+
+loop()
+
diff --git a/tests/gc/stackrefleak.nim b/tests/gc/stackrefleak.nim
new file mode 100644
index 000000000..302ef3599
--- /dev/null
+++ b/tests/gc/stackrefleak.nim
@@ -0,0 +1,31 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  Cyclic = object
+    sibling: PCyclic
+    data: array[0..200, char]
+
+  PCyclic = ref Cyclic
+
+proc makePair: PCyclic =
+  new(result)
+  new(result.sibling)
+  result.sibling.sibling = result
+
+proc loop =
+  for i in 0..10000:
+    var x = makePair()
+    GC_fullCollect()
+    x = nil
+    GC_fullCollect()
+
+  if getOccupiedMem() > 300_000:
+    echo "still a leak! ", getOccupiedMem()
+    quit(1)
+  else:
+    echo "no leak: ", getOccupiedMem()
+
+loop()
+
diff --git a/tests/gc/weakrefs.nim b/tests/gc/weakrefs.nim
new file mode 100644
index 000000000..0a6d4b873
--- /dev/null
+++ b/tests/gc/weakrefs.nim
@@ -0,0 +1,50 @@
+discard """
+  output: "true"
+"""
+
+import intsets
+
+type
+  TMyObject = object
+    id: int
+  StrongObject = ref TMyObject
+  WeakObject = object
+    id: int
+    data: ptr TMyObject
+
+var
+  gid: int # for id generation
+  valid = initIntSet()
+
+proc finalizer(x: StrongObject) =
+  valid.excl(x.id)
+
+proc create: StrongObject =
+  new(result, finalizer)
+  result.id = gid
+  valid.incl(gid)
+  inc gid
+
+proc register(s: StrongObject): WeakObject =
+  result.data = cast[ptr TMyObject](s)
+  result.id = s.id
+
+proc access(w: WeakObject): StrongObject =
+  ## returns nil if the object doesn't exist anymore
+  if valid.contains(w.id):
+    result = cast[StrongObject](w.data)
+
+proc main =
+  var s: seq[WeakObject]
+  newSeq(s, 10_000)
+  for i in 0 .. s.high:
+    s[i] = register(create())
+  # test that we have at least 80% unreachable weak objects by now:
+  when defined(gcMarkAndSweep):
+    GC_fullcollect()
+  var unreachable = 0
+  for i in 0 .. s.high:
+    if access(s[i]) == nil: inc unreachable
+  echo unreachable > 8_000
+
+main()
diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim
new file mode 100644
index 000000000..2984574c2
--- /dev/null
+++ b/tests/generics/mdotlookup.nim
@@ -0,0 +1,16 @@
+proc baz(o: any): int = 5 # if bar is exported, it works
+
+type MyObj = object
+  x: int
+
+proc foo*(b: any) =
+  var o: MyObj
+  echo b.baz, " ", o.x.baz, " ", b.baz()
+
+import sets
+
+var intset = initSet[int]()
+
+proc fn*[T](a: T) =
+  if a in intset: echo("true")
+  else: echo("false")
diff --git a/tests/generics/t1050.nim b/tests/generics/t1050.nim
new file mode 100644
index 000000000..a6f9a2482
--- /dev/null
+++ b/tests/generics/t1050.nim
@@ -0,0 +1,16 @@
+discard """
+  msg: "int"
+  output: "4"
+"""
+
+import typetraits
+
+type ArrayType[T] = distinct T
+
+proc arrayItem(a: ArrayType): auto =
+  static: echo(name(type(a).T))
+  result = (type(a).T)(4)
+
+var arr: ArrayType[int]
+echo arrayItem(arr)
+
diff --git a/tests/generics/t1056.nim b/tests/generics/t1056.nim
new file mode 100644
index 000000000..b1fe25894
--- /dev/null
+++ b/tests/generics/t1056.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''TMatrix[3, 3, system.int]
+3'''
+"""
+
+import typetraits
+
+type
+  TMatrix*[N,M: static[int], T] = object
+    data*: array[0..N*M-1, T]
+
+  TMat2[T] = TMatrix[2,2,T]
+
+proc echoMatrix(a: TMatrix) =
+  echo a.type.name
+  echo TMatrix.N
+
+proc echoMat2(a: TMat2) =
+  echo TMat2.M
+  
+var m = TMatrix[3,3,int](data: [1,2,3,4,5,6,7,8,9])
+
+echoMatrix m
+#echoMat2 m
+
diff --git a/tests/generics/t1789.nim b/tests/generics/t1789.nim
new file mode 100644
index 000000000..188db88f6
--- /dev/null
+++ b/tests/generics/t1789.nim
@@ -0,0 +1,44 @@
+discard """
+  output: "3\n0"
+"""
+
+# https://github.com/Araq/Nim/issues/1789
+
+type
+  Foo[N: static[int]] = object
+
+proc bindStaticN[N](foo: Foo[N]) =
+  var ar0: array[3, int]
+  var ar1: array[N, int]
+  var ar2: array[1..N, int]
+  var ar3: array[0..(N+10), float]
+  echo N
+
+var f: Foo[3]
+f.bindStaticN
+
+# case 2
+
+type
+  ObjectWithStatic[X, Y: static[int], T] = object
+    bar: array[X * Y, T]   # this one works
+
+  AliasWithStatic[X, Y: static[int], T] = array[X * Y, T]
+
+var
+  x: ObjectWithStatic[1, 2, int]
+  y: AliasWithStatic[2, 3, int]
+
+# case 3
+
+type
+  Bar[N: static[int], T] = object
+    bar: array[N, T]
+
+proc `[]`*[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T =
+  assert high(n) == N-1
+  result = f.bar[n]
+  
+var b: Bar[3, int]
+echo b[2]
+
diff --git a/tests/generics/tableref_is_nil.nim b/tests/generics/tableref_is_nil.nim
new file mode 100644
index 000000000..1ad4b3b0c
--- /dev/null
+++ b/tests/generics/tableref_is_nil.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "true"
+"""
+
+# bug #2221
+import tables
+
+var tblo: TableRef[string, int]
+echo tblo == nil
diff --git a/tests/generics/tarray_with_somenumber.nim b/tests/generics/tarray_with_somenumber.nim
new file mode 100644
index 000000000..0bf2537a1
--- /dev/null
+++ b/tests/generics/tarray_with_somenumber.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''@[0.9, 0.1]'''
+"""
+
+# bug #2304
+
+type TV2*[T:SomeNumber] = array[0..1, T]
+proc newV2T*[T](x, y: T=0): TV2[T] = [x, y]
+
+let x = newV2T[float](0.9, 0.1)
+echo(@x)
diff --git a/tests/generics/tbadgenericlambda.nim b/tests/generics/tbadgenericlambda.nim
new file mode 100644
index 000000000..2ab8e724d
--- /dev/null
+++ b/tests/generics/tbadgenericlambda.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "nested proc can have generic parameters only when"
+  line: 6
+"""
+
+let x = proc (x, y): auto = x + y
+
diff --git a/tests/generics/tbintre2.nim b/tests/generics/tbintre2.nim
new file mode 100644
index 000000000..2a7225411
--- /dev/null
+++ b/tests/generics/tbintre2.nim
@@ -0,0 +1,31 @@
+discard """
+  file: "tbintre2.nim"
+  output: "helloworld99110223"
+"""
+# Same test, but check module boundaries
+
+import tbintree
+
+var
+  root: PBinaryTree[string]
+  x = newNode("hello")
+add(root, x)
+add(root, "world")
+if find(root, "world"):
+  for str in items(root):
+    stdout.write(str)
+else:
+  stdout.writeln("BUG")
+
+var
+  r2: PBinaryTree[int]
+add(r2, newNode(110))
+add(r2, 223)
+add(r2, 99)
+for y in items(r2):
+  stdout.write(y)
+
+#OUT helloworld99110223
+
+
+
diff --git a/tests/generics/tbintree.nim b/tests/generics/tbintree.nim
new file mode 100644
index 000000000..8cc8acb82
--- /dev/null
+++ b/tests/generics/tbintree.nim
@@ -0,0 +1,107 @@
+discard """
+  file: "tbintree.nim"
+  output: "helloworld99110223"
+"""
+type
+  TBinaryTree[T] = object      # TBinaryTree is a generic type with
+                               # with generic param ``T``
+    le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil
+    data: T                    # the data stored in a node
+  PBinaryTree*[A] = ref TBinaryTree[A] # type that is exported
+
+proc newNode*[T](data: T): PBinaryTree[T] =
+  # constructor for a node
+  new(result)
+  result.data = data
+
+proc add*[Ty](root: var PBinaryTree[Ty], n: PBinaryTree[Ty]) =
+  # insert a node into the tree
+  if root == nil:
+    root = n
+  else:
+    var it = root
+    while it != nil:
+      # compare the data items; uses the generic ``cmp`` proc that works for
+      # any type that has a ``==`` and ``<`` operator
+      var c = cmp(n.data, it.data)
+      if c < 0:
+        if it.le == nil:
+          it.le = n
+          return
+        it = it.le
+      else:
+        if it.ri == nil:
+          it.ri = n
+          return
+        it = it.ri
+
+proc add*[Ty](root: var PBinaryTree[Ty], data: Ty) =
+  # convenience proc:
+  add(root, newNode(data))
+
+proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool =
+  # for testing this needs to be recursive, so that the
+  # instantiated type is checked for proper tyGenericInst envelopes
+  if b == nil:
+    result = false
+  else:
+    var c = cmp(data, b.data)
+    if c < 0: result = find(b.le, data)
+    elif c > 0: result = find(b.ri, data)
+    else: result = true
+
+iterator preorder*[T](root: PBinaryTree[T]): T =
+  # Preorder traversal of a binary tree.
+  # Since recursive iterators are not yet implemented,
+  # this uses an explicit stack:
+  var stack: seq[PBinaryTree[T]] = @[root]
+  while stack.len > 0:
+    var n = stack.pop()
+    while n != nil:
+      yield n.data
+      add(stack, n.ri)  # push right subtree onto the stack
+      n = n.le          # and follow the left pointer
+
+iterator items*[T](root: PBinaryTree[T]): T =
+  ## Inorder traversal of the binary tree.
+  var stack: seq[PBinaryTree[T]] = @[]
+  var n = root
+  while true:
+    while n != nil:
+      add(stack, n)
+      n = n.le
+    if stack.len > 0:
+      n = stack.pop()
+      yield n.data
+      n = n.ri
+    if stack.len == 0 and n == nil: break
+
+proc debug[T](a: PBinaryTree[T]) =
+  if a != nil:
+    debug(a.le)
+    echo a.data
+    debug(a.ri)
+
+when isMainModule:
+  var
+    root: PBinaryTree[string]
+    x = newNode("hello")
+  add(root, x)
+  add(root, "world")
+  if find(root, "world"):
+    for str in items(root):
+      stdout.write(str)
+  else:
+    stdout.writeln("BUG")
+
+  var
+    r2: PBinaryTree[int]
+  add(r2, newNode(110))
+  add(r2, 223)
+  add(r2, 99)
+  for y in items(r2):
+    stdout.write(y)
+
+#OUT helloworld99110223
+
+
diff --git a/tests/generics/tcan_alias_generic.nim b/tests/generics/tcan_alias_generic.nim
new file mode 100644
index 000000000..780a47841
--- /dev/null
+++ b/tests/generics/tcan_alias_generic.nim
@@ -0,0 +1,11 @@
+##
+## can_alias_generic Nim Module
+##
+## Created by Eric Doughty-Papassideris on 2011-02-16.
+## Copyright (c) 2011 FWA. All rights reserved.
+
+type
+  TGen[T] = object
+  TGen2[T] = TGen[T]
+  
+
diff --git a/tests/generics/tcan_alias_specialised_generic.nim b/tests/generics/tcan_alias_specialised_generic.nim
new file mode 100644
index 000000000..a737d3580
--- /dev/null
+++ b/tests/generics/tcan_alias_specialised_generic.nim
@@ -0,0 +1,17 @@
+discard """
+  disabled: false
+"""
+
+##
+## can_alias_specialised_generic Nim Module
+##
+## Created by Eric Doughty-Papassideris on 2011-02-16.
+## Copyright (c) 2011 FWA. All rights reserved.
+
+type
+  TGen[T] = object
+  TSpef = TGen[string]
+  
+var
+  s: TSpef
+
diff --git a/tests/generics/tcan_inherit_generic.nim b/tests/generics/tcan_inherit_generic.nim
new file mode 100644
index 000000000..ce2b6452f
--- /dev/null
+++ b/tests/generics/tcan_inherit_generic.nim
@@ -0,0 +1,17 @@
+##
+## can_inherit_generic Nim Module
+##
+## Created by Eric Doughty-Papassideris on 2011-02-16.
+## Copyright (c) 2011 FWA. All rights reserved.
+
+type
+  TGen[T] = object of TObject
+    x, y: T
+  
+  TSpef[T] = object of TGen[T]
+
+
+var s: TSpef[float]
+s.x = 0.4
+s.y = 0.6
+
diff --git a/tests/generics/tcan_specialise_generic.nim b/tests/generics/tcan_specialise_generic.nim
new file mode 100644
index 000000000..c510910e8
--- /dev/null
+++ b/tests/generics/tcan_specialise_generic.nim
@@ -0,0 +1,11 @@
+##
+## can_specialise_generic Nim Module
+##
+## Created by Eric Doughty-Papassideris on 2011-02-16.
+## Copyright (c) 2011 FWA. All rights reserved.
+
+type
+  TGen[T] = object {.inheritable.}
+  TSpef = object of TGen[string]
+  
+
diff --git a/tests/generics/tcannot_pass_empty_seq_to_generic.nim b/tests/generics/tcannot_pass_empty_seq_to_generic.nim
new file mode 100644
index 000000000..5f0363af8
--- /dev/null
+++ b/tests/generics/tcannot_pass_empty_seq_to_generic.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "type mismatch: got (seq[empty])"
+  line: 16
+"""
+
+# bug #836
+
+type
+  TOption*[T] = object
+    case FIsSome: bool
+    of false: nil
+    of true: FData: T
+
+proc some*[T](value: T): TOption[T] = TOption[T](FIsSome: true, FData: value)
+
+echo some(@[]).FIsSome
+
diff --git a/tests/generics/tconfusing_arrow.nim b/tests/generics/tconfusing_arrow.nim
new file mode 100644
index 000000000..6a5a9d682
--- /dev/null
+++ b/tests/generics/tconfusing_arrow.nim
@@ -0,0 +1,15 @@
+import algorithm, future
+
+type Deck = object
+  value: int
+
+proc sort(h: var seq[Deck]) =
+  # works:
+  h.sort(proc (x, y: Deck): auto = 
+    cmp(x.value, y.value))
+  # fails:
+  h.sort((x, y: Deck) => cmp(ord(x.value), ord(y.value)))
+
+var player: seq[Deck] = @[]
+
+player.sort()
diff --git a/tests/generics/tdotlookup.nim b/tests/generics/tdotlookup.nim
new file mode 100644
index 000000000..17c60ded2
--- /dev/null
+++ b/tests/generics/tdotlookup.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''5 5 5
+false'''
+"""
+
+import mdotlookup
+
+foo(7)
+# bug #1444
+fn(4)
diff --git a/tests/generics/texplicitgeneric1.nim b/tests/generics/texplicitgeneric1.nim
new file mode 100644
index 000000000..d54044368
--- /dev/null
+++ b/tests/generics/texplicitgeneric1.nim
@@ -0,0 +1,38 @@
+discard """
+  file: "texplicitgeneric1.nim"
+  output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13"
+"""
+# test explicit type instantiation
+
+type
+  TDict*[TKey, TValue] = object 
+    data: seq[tuple[k: TKey, v: TValue]]
+  PDict*[TKey, #with `==`(a, b: TKey): bool
+               #     hash(a: TKey): int, 
+         TValue] = ref TDict[TKey, TValue]
+  
+proc newDict*[TKey, TValue](): PDict[TKey, TValue] = 
+  new(result)
+  result.data = @[]
+  
+proc add*[TKey, TValue](d: PDict[TKey, TValue], k: TKey, v: TValue) = 
+  d.data.add((k, v))
+  
+iterator items*[Tkey, TValue](d: PDict[TKey, TValue]): tuple[k: TKey, 
+               v: TValue] = 
+  for k, v in items(d.data): yield (k, v)
+    
+var d = newDict[int, string]()
+d.add(12, "12")
+d.add(13, "13")
+for k, v in items(d): 
+  stdout.write("Key: ", $k, " value: ", v)
+
+var c = newDict[char, string]()
+c.add('A', "12")
+c.add('B', "13")
+for k, v in items(c): 
+  stdout.write(" Key: ", $k, " value: ", v)
+
+
+
diff --git a/tests/generics/texplicitgeneric2.nim b/tests/generics/texplicitgeneric2.nim
new file mode 100644
index 000000000..95461d023
--- /dev/null
+++ b/tests/generics/texplicitgeneric2.nim
@@ -0,0 +1,35 @@
+discard """
+  output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13"
+  disabled: true
+"""
+
+# test explicit type instantiation
+
+type
+  TDict*[TKey, TValue] = object 
+    data: seq[tuple[k: TKey, v: TValue]]
+  PDict*[TKey, TValue] = ref TDict[TKey, TValue]
+  
+proc newDict*[TKey, TValue](): PDict[TKey, TValue] = 
+  new(result)
+  result.data = @[]
+  
+proc add*(d: PDict, k: TKey, v: TValue) = 
+  d.data.add((k, v))
+  
+
+#iterator items*(d: PDict): tuple[k: TKey, v: TValue] = 
+#  for k, v in items(d.data): yield (k, v)
+    
+var d = newDict[int, string]()
+d.add(12, "12")
+d.add(13, "13")
+for k, v in items(d): 
+  stdout.write("Key: ", $k, " value: ", v)
+
+var c = newDict[char, string]()
+c.add('A', "12")
+c.add('B', "13")
+for k, v in items(c): 
+  stdout.write(" Key: ", $k, " value: ", v)
+
diff --git a/tests/generics/tforwardgeneric.nim b/tests/generics/tforwardgeneric.nim
new file mode 100644
index 000000000..af0c7daf4
--- /dev/null
+++ b/tests/generics/tforwardgeneric.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "1.1000000000000001e+00 11"
+  ccodecheck: "!@'ClEnv'"
+  disabled: "true"
+"""
+
+proc p[T](a, b: T): T
+
+echo p(0.9, 0.1), " ", p(9, 1)
+
+proc p[T](a, b: T): T =
+  let c = b
+  result = a + b + c
+
diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim
new file mode 100644
index 000000000..45450ccca
--- /dev/null
+++ b/tests/generics/tgeneric0.nim
@@ -0,0 +1,27 @@
+import tables
+
+type
+  TX = Table[string, int]
+
+proc foo(models: seq[Table[string, float]]): seq[float] =
+  result = @[]
+  for model in models.items:
+    result.add model["foobar"]
+
+# bug #686
+type TType[T; A] = array[A, T]
+
+proc foo[T](p: TType[T, range[0..1]]) =
+  echo "foo"
+proc foo[T](p: TType[T, range[0..2]]) =
+  echo "bar"
+
+#bug #1366
+
+proc reversed(x) =
+  for i in countdown(x.low, x.high):
+    echo i
+
+reversed(@[-19, 7, -4, 6])
+
+
diff --git a/tests/generics/tgeneric1.nim b/tests/generics/tgeneric1.nim
new file mode 100644
index 000000000..5d20a864b
--- /dev/null
+++ b/tests/generics/tgeneric1.nim
@@ -0,0 +1,53 @@
+discard """
+  output: "100 0"
+"""
+
+# A min-heap.
+type
+  TNode[T] = tuple[priority: int, data: T]
+
+  TBinHeap[T] = object
+    heap: seq[TNode[T]]
+    last: int
+  
+  PBinHeap[T] = ref TBinHeap[T]
+
+proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
+  new(heap)
+  heap.last = 0
+  newSeq(heap.heap, size)
+  #newSeq(heap.seq, size)
+ 
+proc parent(elem: int): int {.inline.} =
+  return (elem-1) div 2
+
+proc siftUp[T](heap: PBinHeap[T], elem: int) =
+  var idx = elem
+  while idx != 0:
+    var p = parent(idx)
+    if heap.heap[idx].priority < heap.heap[p].priority:
+      swap(heap.heap[idx], heap.heap[p])
+      idx = p
+    else:
+      break
+
+proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
+  var node: TNode[T]
+  node.priority = priority
+  node.data = data
+  heap.heap[heap.last] = node
+  siftUp(heap, heap.last)
+  inc(heap.last)
+
+proc print*[T](heap: PBinHeap[T]) =
+  for i in countup(0, heap.last):
+    stdout.write($heap.heap[i].data, " ")
+
+var
+  heap: PBinHeap[int]
+
+newBinHeap(heap, 256)
+add(heap, 1, 100)
+print(heap)
+
+
diff --git a/tests/generics/tgeneric2.nim b/tests/generics/tgeneric2.nim
new file mode 100644
index 000000000..21eb4693e
--- /dev/null
+++ b/tests/generics/tgeneric2.nim
@@ -0,0 +1,15 @@
+import tables
+
+type
+  TX = Table[string, int]
+
+proc foo(models: seq[TX]): seq[int] =
+  result = @[]
+  for model in models.items:
+    result.add model["foobar"]
+
+type
+  Obj = object
+    field: Table[string, string]
+var t: Obj
+discard initTable[type(t.field), string]()
diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim
new file mode 100644
index 000000000..289bf1fd5
--- /dev/null
+++ b/tests/generics/tgeneric3.nim
@@ -0,0 +1,474 @@
+import strutils
+
+type
+  PNode[T,D] = ref TNode[T,D]
+  TItem {.acyclic, pure, final, shallow.} [T,D] = object
+        key: T
+        value: D
+        node: PNode[T,D]
+        when not (D is string):
+          val_set: bool
+
+  TItems[T,D] = seq[ref TItem[T,D]]
+  TNode {.acyclic, pure, final, shallow.} [T,D] = object
+        slots: TItems[T,D]
+        left: PNode[T,D]
+        count: int32
+
+
+  RPath[T,D] = tuple[
+    Xi: int,
+    Nd: PNode[T,D] ]
+
+const
+  cLen1 = 2
+  cLen2 = 16
+  cLen3 = 32
+  cLenCenter = 80
+  clen4 = 96
+  cLenMax = 128
+  cCenter = cLenMax div 2
+
+proc len[T,D] (n:PNode[T,D]): int {.inline.} =
+  return n.count
+
+proc clean[T: SomeOrdinal|SomeNumber](o: var T) {.inline.} = discard
+
+proc clean[T: string|seq](o: var T) {.inline.} =
+  o = nil
+
+proc clean[T,D] (o: ref TItem[T,D]) {.inline.} = 
+  when (D is string) :
+    o.value = nil
+  else :
+    o.val_set = false
+
+proc isClean[T,D] (it: ref TItem[T,D]): bool {.inline.} = 
+  when (D is string) :
+    return it.value == nil
+  else :
+    return not it.val_set
+
+proc isClean[T,D](n: PNode[T,D], x: int): bool {.inline.} = 
+  when (D is string):
+    return n.slots[x].value == nil
+  else:
+    return not n.slots[x].val_set
+
+proc setItem[T,D](Akey: T, Avalue: D, ANode: PNode[T,D]): ref TItem[T,D] {.inline.} = 
+  new(result)
+  result.key = Akey
+  result.value = Avalue
+  result.node = ANode
+  when not (D is string) :
+    result.val_set = true
+
+proc cmp[T:int8|int16|int32|int64|int] (a,b: T): T {.inline.} =
+  return a-b
+
+template binSearchImpl *(docmp: expr) {.immediate.} =
+  var bFound = false
+  result = 0
+  var H = haystack.len -1
+  while result <= H :
+    var I {.inject.} = (result + H) shr 1
+    var SW = docmp 
+    if SW < 0: result = I + 1 
+    else:
+      H = I - 1
+      if SW == 0 : bFound = true
+  if bFound: inc(result)
+  else: result = - result
+
+proc bSearch[T,D] (haystack: PNode[T,D], needle:T): int {.inline.} =
+  binSearchImpl(haystack.slots[I].key.cmp(needle))
+
+proc DeleteItem[T,D] (n: PNode[T,D], x: int): PNode[T,D] {.inline.} =
+  var w = n.slots[x]
+  if w.node != nil : 
+    clean(w)
+    return n
+  dec(n.count)
+  if n.count > 0 :
+    for i in countup(x, n.count -1) : n.slots[i] = n.slots[i + 1]
+    n.slots[n.count] = nil
+    case n.count 
+    of cLen1 : setLen(n.slots, cLen1)
+    of cLen2 : setLen(n.slots, cLen2)
+    of cLen3 : setLen(n.slots, cLen3)
+    of cLenCenter : setLen(n.slots, cLenCenter)
+    of cLen4 : setLen(n.slots, cLen4)
+    else: discard
+    result = n
+
+  else :
+    result = n.left
+    n.slots = nil
+    n.left = nil
+
+proc internalDelete[T,D] (ANode: PNode[T,D], key: T, Avalue: var D): PNode[T,D] = 
+  var Path: array[0..20, RPath[T,D]]
+  var n = ANode
+  result = n
+  clean(Avalue)
+  var h = 0
+  while n != nil:
+    var x = bSearch(n, key)
+    if x <= 0 :
+      Path[h].Nd = n
+      Path[h].Xi = - x
+      inc(h)
+      if x == 0 :
+        n = n.left
+      else :
+        x = (-x) -1
+        if x < n.count :
+          n = n.slots[x].node
+        else :
+          n = nil
+    else : 
+      dec(x)
+      if isClean(n, x) : return
+      Avalue = n.slots[x].value
+      var n2 = DeleteItem(n, x)
+      dec(h)
+      while (n2 != n) and (h >=0) :
+        n = n2 
+        var w = addr Path[h]
+        x  = w.Xi -1
+        if x >= 0 :
+          if (n == nil) and isClean(w.Nd, x) :
+            n = w.Nd
+            n.slots[x].node = nil 
+            n2 = DeleteItem(n, x)
+          else :
+            w.Nd.slots[x].node = n
+            return
+        else :
+          w.Nd.left = n
+          return
+        dec(h)
+      if h < 0:
+        result = n2
+      return
+
+proc internalFind[T,D] (n: PNode[T,D], key: T): ref TItem[T,D] {.inline.} =
+  var wn = n
+  while wn != nil :
+    var x = bSearch(wn, key)
+    if x <= 0 :
+      if x == 0 :
+        wn = wn.left
+      else :
+        x = (-x) -1
+        if x < wn.count : 
+          wn = wn.slots[x].node
+        else :
+          return nil
+
+    else :
+      return wn.slots[x - 1]
+  return nil
+
+proc traceTree[T,D](root: PNode[T,D]) =
+  proc traceX(x: int) = 
+    write stdout, "("
+    write stdout, x
+    write stdout, ") "
+
+  proc traceEl(el: ref TItem[T,D]) =
+    write stdout, " key: "
+    write stdout, el.key
+    write stdout, " value: "
+    write stdout, el.value
+
+
+  proc traceln(space: string) =
+    writeln stdout, ""
+    write stdout, space
+
+  proc doTrace(n: PNode[T,D], level: int) =
+    var space = spaces(2 * level)
+    traceln(space)
+    write stdout, "node: "
+    if n == nil:
+      writeln stdout, "is empty"
+      return
+    write stdout, n.count
+    write stdout, " elements: "
+    if n.left != nil:
+      traceln(space)
+      write stdout, "left: "
+      doTrace(n.left, level +1)
+    for i, el in n.slots :
+      if el != nil and not isClean(el):
+        traceln(space)
+        traceX(i)
+        if i >= n.count: 
+          write stdout, "error "
+        else:
+          traceEl(el)
+          if el.node != nil: doTrace(el.node, level +1)
+          else : write stdout, " empty "
+      elif i < n.count :
+        traceln(space)
+        traceX(i)
+        write stdout, "clean: "
+        when T is string :
+          if el.key != nil: write stdout, el.key
+        else : write stdout, el.key
+        if el.node != nil: doTrace(el.node, level +1)
+        else : write stdout, " empty "
+    writeln stdout,""
+
+  doTrace(root, 0)
+
+proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], Akey: T, Avalue: D) =
+  var x = - APath.Xi
+  inc(APath.Nd.count)
+  case APath.Nd.count 
+  of cLen1: setLen(APath.Nd.slots, cLen2)
+  of cLen2: setLen(APath.Nd.slots, cLen3)
+  of cLen3: setLen(APath.Nd.slots, cLenCenter)
+  of cLenCenter: setLen(APath.Nd.slots, cLen4)
+  of cLen4: setLen(APath.Nd.slots, cLenMax)
+  else: discard
+  for i in countdown(APath.Nd.count.int - 1, x + 1): shallowCopy(APath.Nd.slots[i], APath.Nd.slots[i - 1])
+  APath.Nd.slots[x] = setItem(Akey, Avalue, ANode)
+
+
+proc SplitPage[T,D](n, left: PNode[T,D], xi: int, Akey:var T, Avalue:var D): PNode[T,D] =
+  var x = -xi
+  var it1: TItems[T,D]
+  it1.newSeq(cLenCenter)
+  new(result)
+  result.slots.newSeq(cLenCenter)
+  result.count = cCenter
+  if x == cCenter:
+    for i in 0..cCenter -1: shallowCopy(it1[i], left.slots[i])
+    for i in 0..cCenter -1: shallowCopy(result.slots[i], left.slots[cCenter + i])
+    result.left = n
+  else :
+    if x < cCenter :
+      for i in 0..x-1: shallowCopy(it1[i], left.slots[i])
+      it1[x] = setItem(Akey, Avalue, n)
+      for i in x+1 .. cCenter -1: shallowCopy(it1[i], left.slots[i-1])
+      var w = left.slots[cCenter -1]
+      Akey = w.key
+      Avalue = w.value
+      result.left = w.node
+      for i in 0..cCenter -1: shallowCopy(result.slots[i], left.slots[cCenter + i])
+    else :
+      for i in 0..cCenter -1: shallowCopy(it1[i], left.slots[i])
+      x = x - (cCenter + 1)
+      for i in 0..x-1: shallowCopy(result.slots[i], left.slots[cCenter + i + 1])
+      result.slots[x] = setItem(Akey, Avalue, n)
+      for i in x+1 .. cCenter -1: shallowCopy(result.slots[i], left.slots[cCenter + i])
+      var w = left.slots[cCenter]
+      Akey = w.key
+      Avalue = w.value
+      result.left = w.node
+  left.count = cCenter
+  shallowCopy(left.slots, it1)
+
+
+proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, Oldvalue: var D): ref TNode[T,D] =
+  var h: int
+  var Path: array[0..30, RPath[T,D]]
+  var left: PNode[T,D]
+  var n = ANode
+
+
+  result = ANode
+  h = 0
+  while n != nil:
+    var x = bSearch[T,D](n, Akey)
+    if x <= 0 :
+      Path[h].Nd = n
+      Path[h].Xi = x
+      inc(h) 
+      if x == 0 :
+        n = n.left
+      else :
+        x = (-x) -1
+        if x < n.count :
+          n = n.slots[x].node
+        else :
+          n = nil
+    else :
+      var w = n.slots[x - 1]
+      Oldvalue = w.value
+      w.value = Avalue
+      return
+
+  dec(h)
+  left = nil
+  var lkey = Akey
+  var lvalue = Avalue
+  while h >= 0 :
+    if Path[h].Nd.count < cLenMax :
+      InsertItem(Path[h], n, lkey, lvalue)
+      return
+    else :
+      left = Path[h].Nd
+      n = SplitPage(n, left, Path[h].Xi, lkey, lvalue)
+    dec(h)
+
+  new(result)
+  result.slots.newSeq(cLen1)
+  result.count = 1
+  result.left = left
+  result.slots[0] = setItem(lkey, lvalue, n)
+
+
+proc CleanTree[T,D](n: PNode[T,D]): PNode[T,D] =
+  if n.left != nil :
+    n.left = CleanTree(n.left)
+  for i in 0 .. n.count - 1 :
+    var w = n.slots[i]
+    if w.node != nil :
+        w.node = CleanTree(w.node)
+    clean(w.value)
+    clean(w.key)
+  n.slots = nil
+  return nil
+
+
+proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]): PNode[T,D] {.closure.} ): PNode[T,D] =
+  if n != nil :
+    if n.left != nil :
+      n.left = VisitAllNodes(n.left, visit)    
+    for i in 0 .. n.count - 1 :
+      var w = n.slots[i]
+      if w.node != nil :
+        w.node = VisitAllNodes(w.node, visit)    
+    return visit(n)
+  return nil
+
+proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]) {.closure.} ) =
+  if n != nil:
+    if n.left != nil :
+      VisitAllNodes(n.left, visit)    
+    for i in 0 .. n.count - 1 :
+      var w = n.slots[i]
+      if w.node != nil :
+        VisitAllNodes(w.node, visit)    
+    visit(n)
+
+proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: D) {.closure.} ) =
+  if n != nil:
+    if n.left != nil :
+      VisitAll(n.left, visit) 
+    for i in 0 .. n.count - 1 :
+      var w = n.slots[i]
+      if not w.isClean :
+        visit(w.key, w.value)   
+      if w.node != nil :
+        VisitAll(w.node, visit)    
+
+proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: var D):bool {.closure.} ): PNode[T,D] =
+  if n != nil:
+    var n1 = n.left
+    if n1 != nil :
+      var n2 = VisitAll(n1, visit) 
+      if n1 != n2 :
+        n.left = n2
+    var i = 0
+    while i < n.count :
+      var w = n.slots[i]
+      if not w.isClean :
+        if visit(w.key, w.value) :
+          result = DeleteItem(n, i)
+          if result == nil : return
+          dec(i)
+      n1 = w.node
+      if n1 != nil :
+        var n2 = VisitAll(n1, visit)
+        if n1 != n2 :
+          w.node = n2
+      inc(i)
+  return n
+
+iterator keys* [T,D] (n: PNode[T,D]): T =
+  if n != nil :
+    var Path: array[0..20, RPath[T,D]]
+    var level = 0
+    var nd = n
+    var i = -1
+    while true : 
+      if i < nd.count :
+        Path[level].Nd = nd
+        Path[level].Xi = i
+        if i < 0 :
+          if nd.left != nil :
+            nd = nd.left
+            inc(level)
+          else : inc(i)
+        else :
+          var w = nd.slots[i]
+          if not w.isClean() :
+            yield w.key
+          if w.node != nil :
+            nd = w.node
+            i = -1
+            inc(level)
+          else : inc(i)
+      else :
+        dec(level)
+        if level < 0 : break
+        nd = Path[level].Nd
+        i = Path[level].Xi
+        inc(i)
+
+
+when isMainModule:
+
+  proc test() =
+    var oldvalue: int
+    var root = internalPut[int, int](nil, 312, 312, oldvalue)
+    var someOtherRoot = internalPut[string, int](nil, "312", 312, oldvalue)
+    var it1 = internalFind(root, 312)
+    echo it1.value
+
+    for i in 1..1_000_000:
+      root = internalPut(root, i, i, oldvalue)
+
+    var cnt = 0
+    oldvalue = -1
+    when true : # code compiles, when this or the other when is switched to false
+      for k in root.keys :
+        if k <= oldvalue :
+          echo k
+        oldvalue = k
+        inc(cnt)
+      echo cnt
+    when true :
+      cnt = 0
+      VisitAll(root, proc(key, val: int) = inc(cnt))
+      echo cnt
+      when true :
+        root = VisitAll(root, proc(key: int, value: var int): bool =
+          return key mod 2 == 0 )
+      cnt = 0
+      oldvalue = -1
+      VisitAll(root, proc(key: int, value: int) {.closure.} =
+        if key <= oldvalue :
+          echo key
+        oldvalue = key
+        inc(cnt) )
+      echo cnt
+      root = VisitAll(root, proc(key: int, value: var int): bool =
+        return key mod 2 != 0 )
+      cnt = 0
+      oldvalue = -1
+      VisitAll(root, proc(key: int, value: int) {.closure.} =
+        if key <= oldvalue :
+          echo "error ", key
+        oldvalue = key
+        inc(cnt) )
+      echo cnt
+      #traceTree(root)
+
+
+
+  test()  
\ No newline at end of file
diff --git a/tests/generics/tgeneric4.nim b/tests/generics/tgeneric4.nim
new file mode 100644
index 000000000..f79096636
--- /dev/null
+++ b/tests/generics/tgeneric4.nim
@@ -0,0 +1,10 @@
+type
+  TIDGen*[A: Ordinal] = object
+    next: A
+    free: seq[A]
+
+proc newIDGen*[A]: TIDGen[A] =
+    newSeq result.free, 0
+
+var x = newIDGen[int]()
+
diff --git a/tests/generics/tgeneric_closure.nim b/tests/generics/tgeneric_closure.nim
new file mode 100644
index 000000000..7198dce96
--- /dev/null
+++ b/tests/generics/tgeneric_closure.nim
@@ -0,0 +1,37 @@
+# Test to ensure TEventHandler is '.closure'
+
+# bug #1187
+
+type
+  TEventArgs* = object
+    skip*: bool
+  TEventHandler[T] = proc (e: var TEventArgs, data: T) {.closure.}
+  TEvent*[T] = object
+    #handlers: seq[TEventHandler[T]] # Does not work
+    handlers: seq[proc (e: var TEventArgs, data: T) {.closure.}] # works
+
+  TData = object
+    x: int
+
+  TSomething = object
+    s: TEvent[TData]
+
+proc init*[T](e: var TEvent[T]) =
+  e.handlers.newSeq(0)
+
+#proc add*[T](e: var TEvent[T], h: proc (e: var TEventArgs, data: T) {.closure.}) =
+# this line works
+proc add*[T](e: var TEvent[T], h: TEventHandler[T]) =
+  # this line does not work
+  e.handlers.add(h)
+
+proc main () =
+  var something: TSomething
+  something.s.init()
+  var fromOutside = 4711
+
+  something.s.add() do (e: var TEventArgs, data: TData):
+    var x = data.x
+    x = fromOutside
+
+main()
diff --git a/tests/generics/tgeneric_inheritance.nim b/tests/generics/tgeneric_inheritance.nim
new file mode 100644
index 000000000..432228797
--- /dev/null
+++ b/tests/generics/tgeneric_inheritance.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "0.0"
+"""
+
+# bug #1919
+
+type
+  Base[M] = object of RootObj
+    a : M
+
+  Sub1[M] = object of Base[M]
+    b : int
+
+  Sub2[M] = object of Sub1[M]
+    c : int
+
+var x: Sub2[float]
+
+echo x.a
diff --git a/tests/generics/tgenericdefaults.nim b/tests/generics/tgenericdefaults.nim
new file mode 100644
index 000000000..ad96f1851
--- /dev/null
+++ b/tests/generics/tgenericdefaults.nim
@@ -0,0 +1,29 @@
+type 
+  TFoo[T, U, R = int] = object
+    x: T
+    y: U
+    z: R
+
+  TBar[T] = TFoo[T, array[4, T], T]
+
+var x1: TFoo[int, float]
+
+static:
+  assert type(x1.x) is int
+  assert type(x1.y) is float
+  assert type(x1.z) is int
+  
+var x2: TFoo[string, R = float, U = seq[int]]
+
+static:
+  assert type(x2.x) is string
+  assert type(x2.y) is seq[int]
+  assert type(x2.z) is float
+
+var x3: TBar[float]
+
+static:
+  assert type(x3.x) is float
+  assert type(x3.y) is array[4, float]
+  assert type(x3.z) is float
+
diff --git a/tests/generics/tgenericlambda.nim b/tests/generics/tgenericlambda.nim
new file mode 100644
index 000000000..eb6ada3e5
--- /dev/null
+++ b/tests/generics/tgenericlambda.nim
@@ -0,0 +1,23 @@
+discard """
+  output: "10\n10\n1\n2\n3\n15"
+"""
+
+proc test(x: proc (a, b: int): int) =
+  echo x(5, 5)
+
+test(proc (a, b): auto = a + b)
+
+test do (a, b) -> auto: a + b
+
+proc foreach[T](s: seq[T], body: proc(x: T)) =
+  for e in s:
+    body(e)
+
+foreach(@[1,2,3]) do (x):
+  echo x
+
+proc foo =
+  let x = proc (a, b: int): auto = a + b
+  echo x(5, 10)
+
+foo()
diff --git a/tests/generics/tgenericmatcher.nim b/tests/generics/tgenericmatcher.nim
new file mode 100644
index 000000000..edd0c4cf1
--- /dev/null
+++ b/tests/generics/tgenericmatcher.nim
@@ -0,0 +1,22 @@
+discard """
+  disabled: false
+"""
+
+type
+  TMatcherKind = enum
+    mkTerminal, mkSequence, mkAlternation, mkRepeat
+  TMatcher[T] = object
+    case kind: TMatcherKind
+    of mkTerminal:
+      value: T
+    of mkSequence, mkAlternation:
+      matchers: seq[TMatcher[T]]
+    of mkRepeat:
+      matcher: PMatcher[T]
+      min, max: int
+  PMatcher[T] = ref TMatcher[T]
+
+var 
+  m: PMatcher[int]
+
+
diff --git a/tests/generics/tgenericmatcher2.nim b/tests/generics/tgenericmatcher2.nim
new file mode 100644
index 000000000..aa2f9dbb3
--- /dev/null
+++ b/tests/generics/tgenericmatcher2.nim
@@ -0,0 +1,18 @@
+
+type
+  TMatcherKind = enum
+    mkTerminal, mkSequence, mkAlternation, mkRepeat
+  TMatcher[T] = object
+    case kind: TMatcherKind
+    of mkTerminal:
+      value: T
+    of mkSequence, mkAlternation:
+      matchers: seq[TMatcher[T]]
+    of mkRepeat:
+      matcher: ref TMatcher[T]
+      min, max: int
+
+var 
+  m: ref TMatcher[int]
+
+
diff --git a/tests/generics/tgenericprocvar.nim b/tests/generics/tgenericprocvar.nim
new file mode 100644
index 000000000..dca9c8538
--- /dev/null
+++ b/tests/generics/tgenericprocvar.nim
@@ -0,0 +1,36 @@
+discard """
+  output: "0false12"
+"""
+
+# Test multiple generic instantiation of generic proc vars:
+
+proc threadProcWrapper[TMsg]() =
+  var x: TMsg
+  stdout.write($x)
+
+#var x = threadProcWrapper[int]
+#x()
+
+#var y = threadProcWrapper[bool]
+#y()
+
+threadProcWrapper[int]()
+threadProcWrapper[bool]()
+
+type
+  TFilterProc[T,D] = proc (item: T, env:D): bool {.nimcall.}
+
+proc filter[T,D](data: seq[T], env:D, pred: TFilterProc[T,D]): seq[T] =
+  result = @[]
+  for e in data:
+    if pred(e, env): result.add(e)
+
+proc predTest(item: int, value: int): bool =
+  return item <= value
+
+proc test(data: seq[int], value: int): seq[int] =
+  return filter(data, value, predTest)
+
+for x in items(test(@[1,2,3], 2)):
+  stdout.write(x)
+
diff --git a/tests/generics/tgenericprop.nim b/tests/generics/tgenericprop.nim
new file mode 100644
index 000000000..7cddf5617
--- /dev/null
+++ b/tests/generics/tgenericprop.nim
@@ -0,0 +1,12 @@
+
+type
+  TProperty[T] = object of TObject
+    getProc: proc(property: TProperty[T]): T {.nimcall.}
+    setProc: proc(property: TProperty[T], value: T) {.nimcall.}
+    value: T
+
+proc newProperty[T](value: TObject): TProperty[T] =
+  result.getProc = proc (property: TProperty[T]) =
+    return property.value
+
+
diff --git a/tests/generics/tgenericrefs.nim b/tests/generics/tgenericrefs.nim
new file mode 100644
index 000000000..a44b96af9
--- /dev/null
+++ b/tests/generics/tgenericrefs.nim
@@ -0,0 +1,38 @@
+type 
+  PA[T] = ref TA[T]
+  TA[T] = object
+    field: T
+var a: PA[string]
+new(a)
+a.field = "some string"
+
+
+proc someOther[T](len: string): seq[T] = discard
+proc someOther[T](len: int): seq[T] = echo "we"
+
+proc foo[T](x: T) =
+  var s = someOther[T](34)
+  #newSeq[T](34)
+
+foo 23
+
+
+
+when false:
+  # Compiles unless you use var a: PA[string]
+  type 
+    PA = ref TA
+    TA[T] = object
+
+
+  # Cannot instantiate:
+  type 
+    TA[T] = object
+      a: PA[T]
+    PA[T] = ref TA[T]
+
+  type 
+    PA[T] = ref TA[T]
+    TA[T] = object
+
+
diff --git a/tests/generics/tgenericshardcases.nim b/tests/generics/tgenericshardcases.nim
new file mode 100644
index 000000000..e3b805db6
--- /dev/null
+++ b/tests/generics/tgenericshardcases.nim
@@ -0,0 +1,42 @@
+discard """
+  file: "tgenericshardcases.nim"
+  output: "2\n5\n126\n3"
+"""
+
+import typetraits
+
+proc typeNameLen(x: typedesc): int {.compileTime.} =
+  result = x.name.len
+  
+macro selectType(a, b: typedesc): typedesc =
+  result = a
+
+type
+  Foo[T] = object
+    data1: array[T.high, int]
+    data2: array[typeNameLen(T), float]
+    data3: array[0..T.typeNameLen, selectType(float, int)]
+
+  MyEnum = enum A, B, C, D
+
+var f1: Foo[MyEnum]
+var f2: Foo[int8]
+
+echo high(f1.data1) # (D = 3) - 1 == 2
+echo high(f1.data2) # (MyEnum.len = 6) - 1 == 5
+
+echo high(f2.data1) # 127 - 1 == 126
+echo high(f2.data2) # int8.len - 1 == 3
+
+static:
+  assert high(f1.data1) == ord(C)
+  assert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high
+
+  assert high(f2.data1) == 126
+  assert high(f2.data2) == 3 
+
+  assert high(f1.data3) == 6 # length of MyEnum
+  assert high(f2.data3) == 4 # length of int8
+
+  assert f2.data3[0] is float
+
diff --git a/tests/generics/tgenerictmpl.nim b/tests/generics/tgenerictmpl.nim
new file mode 100644
index 000000000..a749e6570
--- /dev/null
+++ b/tests/generics/tgenerictmpl.nim
@@ -0,0 +1,12 @@
+
+template tmp[T](x: var seq[T]) =
+  #var yz: T  # XXX doesn't work yet
+  x = @[1, 2, 3]
+
+macro tmp2[T](x: var seq[T]): stmt =
+  nil
+
+var y: seq[int]
+tmp(y)
+tmp(y)
+echo y.repr
diff --git a/tests/generics/tgenericvariant.nim b/tests/generics/tgenericvariant.nim
new file mode 100644
index 000000000..0150cda8d
--- /dev/null
+++ b/tests/generics/tgenericvariant.nim
@@ -0,0 +1,23 @@
+type  
+  TMaybe[T] = object
+    case empty: bool
+    of false: value: T
+    else: nil
+
+proc Just*[T](val: T): TMaybe[T] =
+  result.empty = false
+  result.value = val
+
+proc Nothing[T](): TMaybe[T] =
+  result.empty = true
+
+proc safeReadLine(): TMaybe[string] =
+  var r = stdin.readLine()
+  if r == "": return Nothing[string]()
+  else: return Just(r)
+
+when isMainModule:
+  var Test = Just("Test")
+  echo(Test.value)
+  var mSomething = safeReadLine()
+  echo(mSomething.value)
diff --git a/tests/generics/tinferredgenericprocs.nim b/tests/generics/tinferredgenericprocs.nim
new file mode 100644
index 000000000..12adfe965
--- /dev/null
+++ b/tests/generics/tinferredgenericprocs.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''123
+1
+2
+3'''
+"""
+
+# https://github.com/Araq/Nim/issues/797
+proc foo[T](s:T):string = $s
+
+type IntStringProc = proc(x: int): string 
+
+var f1 = IntStringProc(foo)
+var f2: proc(x: int): string = foo
+var f3: IntStringProc = foo
+
+echo f1(1), f2(2), f3(3)
+
+for x in map([1,2,3], foo): echo x
+
diff --git a/tests/generics/tlateboundstatic.nim b/tests/generics/tlateboundstatic.nim
new file mode 100644
index 000000000..f68f95f8d
--- /dev/null
+++ b/tests/generics/tlateboundstatic.nim
@@ -0,0 +1,16 @@
+discard """
+  msg: "array[0..3, int]"
+"""
+
+type
+  KK[I: static[int]] = object
+   x: array[I, int]
+
+proc foo(a: static[string]): KK[a.len] =
+  result.x[0] = 12
+
+var x = foo "test"
+
+import typetraits
+static: echo x.x.type.name
+
diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim
new file mode 100644
index 000000000..7a2375abe
--- /dev/null
+++ b/tests/generics/tmetafield.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim check $options $file"
+  errormsg: "'proc' is not a concrete type"
+  errormsg: "'Foo' is not a concrete type."
+  errormsg: "invalid type: 'proc' in this context: 'TBaseMed'"
+"""
+
+type
+  Foo[T] = object
+    x: T
+
+  TBaseMed =  object
+    doSmth: proc
+    data: seq[Foo]
+
+var a: TBaseMed
+
+# issue 188
diff --git a/tests/generics/tsigtypeop.nim b/tests/generics/tsigtypeop.nim
new file mode 100644
index 000000000..4c863cba1
--- /dev/null
+++ b/tests/generics/tsigtypeop.nim
@@ -0,0 +1,9 @@
+type
+  Vec3[T] = array[3, T]
+
+proc foo(x: Vec3, y: Vec3.T, z: x.T): x.type.T =
+  return 10
+
+var y: Vec3[int] = [1, 2, 3]
+var z: int = foo(y, 3, 4)
+
diff --git a/tests/generics/tspecialised_is_equivalent.nim b/tests/generics/tspecialised_is_equivalent.nim
new file mode 100644
index 000000000..ace562862
--- /dev/null
+++ b/tests/generics/tspecialised_is_equivalent.nim
@@ -0,0 +1,15 @@
+##
+## specialised_is_equivalent Nim Module
+##
+## Created by Eric Doughty-Papassideris on 2011-02-16.
+## Copyright (c) 2011 FWA. All rights reserved.
+
+type
+  TGen[T] = tuple[a: T]
+  TSpef = tuple[a: string]
+
+var
+  a: TGen[string]
+  b: TSpef
+a = b
+
diff --git a/tests/generics/tsubtypeconstraint.nim b/tests/generics/tsubtypeconstraint.nim
new file mode 100644
index 000000000..2f0954522
--- /dev/null
+++ b/tests/generics/tsubtypeconstraint.nim
@@ -0,0 +1,13 @@
+
+# bug #1684
+type
+  BaseType {.inheritable pure.} = object
+    idx: int
+
+  DerivedType* {.final pure.} = object of BaseType
+
+proc index*[Toohoo: BaseType](h: Toohoo): int {.inline.} = h.idx
+proc newDerived(idx: int): DerivedType {.inline.} = DerivedType(idx: idx)
+
+let d = newDerived(2)
+assert(d.index == 2)
diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim
new file mode 100644
index 000000000..fdd11d9d1
--- /dev/null
+++ b/tests/generics/tthread_generic.nim
@@ -0,0 +1,39 @@
+discard """
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+type
+  TThreadFuncArgs[T] = object of TObject
+    a: proc(): T {.thread.}
+    b: proc(val: T) {.thread.}
+
+proc handleThreadFunc(arg: TThreadFuncArgs[int]){.thread.} =
+  var fn = arg.a
+  var callback = arg.b
+  var output = fn()
+  callback(output)
+
+proc `@||->`*[T](fn: proc(): T {.thread.}, 
+                 callback: proc(val: T){.thread.}): TThread[TThreadFuncArgs[T]] =
+  var thr: TThread[TThreadFuncArgs[T]]
+  var args: TThreadFuncArgs[T]
+  args.a = fn
+  args.b = callback
+  createThread(thr, handleThreadFunc, args)
+  return thr
+
+proc `||->`*[T](fn: proc(): T{.thread.}, callback: proc(val: T){.thread.}) =
+  discard fn @||-> callback
+
+when isMainModule:
+  import os
+  proc testFunc(): int {.thread.} =
+    return 1
+  proc callbackFunc(val: int) {.thread.} =
+    echo($(val))
+   
+  var thr = (testFunc @||-> callbackFunc)
+  echo("test")
+  joinThread(thr)
+  os.sleep(3000)
+
diff --git a/tests/generics/tunique_type.nim b/tests/generics/tunique_type.nim
new file mode 100644
index 000000000..da2f9e4b2
--- /dev/null
+++ b/tests/generics/tunique_type.nim
@@ -0,0 +1,67 @@
+# Bug #2022
+
+discard """
+  output: '''@[97, 45]
+@[true, false]
+@[false, false]'''
+"""
+
+## The goal of this snippet is to provide and test a construct for general-
+## purpose, random-access mapping. I use an AST-manipulation-based approach
+## because it's more efficient than using procedure pointers and less
+## verbose than defining a new callable type for every invocation of `map`.
+
+import future
+import macros
+import strutils
+
+#===============================================================================
+# Define a system for storing copies of ASTs as static strings.
+# This serves the same purpose as D's `alias` parameters for types, used heavily
+# in its popular `ranges` and `algorithm` modules.
+
+var exprNodes {.compileTime.} = newSeq[NimNode]()
+
+proc refExpr(exprNode: NimNode): string {.compileTime.} =
+  exprNodes.add exprNode.copy
+  "expr" & $(exprNodes.len - 1)
+
+proc derefExpr(exprRef: string): NimNode {.compileTime.} =
+  exprNodes[parseInt(exprRef[4 .. ^1])]
+
+#===============================================================================
+# Define a type that allows a callable expression to be mapped onto elements
+# of an indexable collection.
+
+type Mapped[Input; predicate: static[string]] = object
+  input: Input
+
+macro map(input, predicate: expr): expr =
+  let predicate = callsite()[2]
+  newNimNode(nnkObjConstr).add(
+    newNimNode(nnkBracketExpr).add(
+      ident"Mapped",
+      newNimNode(nnkTypeOfExpr).add(input),
+      newLit(refExpr(predicate))),
+    newNimNode(nnkExprColonExpr).add(
+      ident"input", input))
+
+proc `[]`(m: Mapped, i: int): auto =
+  macro buildResult: expr =
+    newCall(
+      derefExpr(m.predicate),
+      newNimNode(nnkBracketExpr).add(
+        newDotExpr(ident"m", ident"input"),
+        ident"i"))
+  buildResult()
+
+#===============================================================================
+# Test out our generic mapping construct.
+
+let a = "a-string".map(ord)
+let b = @["a", "seq"].map((e: string) => e == "a")
+let c = "another-string".map((e: char) => e == 'o')
+
+echo(@[a[0], a[1]]) # @[97, 45]
+echo(@[b[0], b[1]]) # @[true, false]
+echo(@[c[0], c[1]]) # @[false, false]
diff --git a/tests/generics/tvarargs_vs_generic.nim b/tests/generics/tvarargs_vs_generic.nim
new file mode 100644
index 000000000..122f3e453
--- /dev/null
+++ b/tests/generics/tvarargs_vs_generic.nim
@@ -0,0 +1,26 @@
+discard """
+  output: "direct\ngeneric\ngeneric"
+"""
+
+proc withDirectType(args: string) =
+  echo "direct"
+
+proc withDirectType[T](arg: T) =
+  echo "generic"
+
+proc withOpenArray(args: openarray[string]) =
+  echo "openarray"
+
+proc withOpenArray[T](arg: T) =
+  echo "generic"
+
+proc withVarargs(args: varargs[string]) =
+  echo "varargs"
+
+proc withVarargs[T](arg: T) =
+  echo "generic"
+
+withDirectType "string"
+withOpenArray "string"
+withVarargs "string"
+
diff --git a/tests/generics/twrong_field_caching.nim b/tests/generics/twrong_field_caching.nim
new file mode 100644
index 000000000..595c58eb7
--- /dev/null
+++ b/tests/generics/twrong_field_caching.nim
@@ -0,0 +1,68 @@
+discard """
+  output: '''a23: 2x3
+a32: 3x2
+transpose A
+t32: 3x2
+transpose B
+x23: 2x3 (2x3)
+x32: 3x2 (3x2)'''
+"""
+
+# bug #2125
+# Suppose we have the following type for a rectangular array:
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+ 
+var a23: RectArray[2, 3, int]
+var a32: RectArray[3, 2, int]
+ 
+echo "a23: ", a23.R, "x", a23.C
+echo "a32: ", a32.R, "x", a32.C
+
+# Output:
+# a23: 2x3
+# a32: 3x2
+
+# Looking good. Let's add a proc:
+proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] =
+  echo "transpose A"
+
+var t32 = a23.transpose
+
+echo "t32: ", t32.R, "x", t32.C
+
+# Output:
+# t32: 3x2
+ 
+ 
+# Everything is still OK. Now let's use the rectangular array inside another
+# generic type:
+type
+  Matrix*[R, C: static[int], T] = object
+    theArray*: RectArray[R, C, T]
+
+#var m23: Matrix[2, 3, int]
+#var m32: Matrix[3, 2, int]
+
+#echo "m23: ", m23.R, "x", m23.C, " (", m23.theArray.R, "x", m23.theArray.C, ")"
+#echo "m32: ", m32.R, "x", m32.C, " (", m32.theArray.R, "x", m32.theArray.C, ")"
+
+# Output:
+# m23: 2x3 (2x3)
+# m32: 3x2 (3x2)
+
+
+# Everything is still as expected. Now let's add the following proc:
+proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] =
+  echo "transpose B"
+
+var x23: Matrix[2, 3, int]
+var x32 = x23.transpose
+
+echo "x23: ", x23.R, "x", x23.C, " (", x23.theArray.R, "x", x23.theArray.C, ")"
+echo "x32: ", x32.R, "x", x32.C, " (", x32.theArray.R, "x", x32.theArray.C, ")"
+ 
+# Output:
+# x23: 2x3 (2x3)
+# x32: 3x2 (3x2)  <--- this is incorrect. R and C do not match!
diff --git a/tests/generics/twrong_floatlit_type.nim b/tests/generics/twrong_floatlit_type.nim
new file mode 100644
index 000000000..2db8b4353
--- /dev/null
+++ b/tests/generics/twrong_floatlit_type.nim
@@ -0,0 +1,118 @@
+discard """
+  errormsg: "type mismatch"
+  line: 116
+"""
+
+# bug #2169
+import strutils, math
+
+type
+  Point2D*[S] = object
+    x*, y*: S
+  Matrix2x3*[S] = distinct array[6, S] ## Row major order
+
+  Vector2D*[S] = object
+    x*, y*: S
+
+proc `[]`*[T](m: Matrix2x3[T], i: int): T = array[6, T](m)[i]
+
+template M11*[T](m: Matrix2x3[T]): T = m[0]
+template M12*[T](m: Matrix2x3[T]): T = m[1]
+template M13*[T](m: Matrix2x3[T]): T = m[2]
+template M21*[T](m: Matrix2x3[T]): T = m[3]
+template M22*[T](m: Matrix2x3[T]): T = m[4]
+template M23*[T](m: Matrix2x3[T]): T = m[5]
+
+proc identity*[T](): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), 0.0, 0.0,   0.0, 1.0, 0.0])
+
+proc translation*[T](p: Point2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y])
+
+proc translation*[T](p: Vector2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y])
+
+proc scale*[T](v: Vector2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([v.x, T(0.0), T(0.0), T(0.0), v.y, T(0.0)])
+
+proc rotation*[T](th: T): Matrix2x3[T] = 
+    let 
+        c = T(cos(th.float))
+        s = T(sin(th.float))
+ 
+    Matrix2x3[T]([c, -s, T(0.0),   s, c, T(0.0)])
+ 
+proc `*`*[T](a, b: Matrix2x3[T]): Matrix2x3[T] = 
+    # Here we pretend that row 3 is [0,0,0,1] without
+    # actually storing it in the matrix.
+    Matrix2x3[T]([a.M11*b.M11 + a.M12*b.M21, 
+                  a.M11*b.M12 + a.M12*b.M22, 
+                  a.M11*b.M13 + a.M12*b.M23 + a.M13, 
+ 
+                  a.M21*b.M11 + a.M22*b.M21,
+                  a.M21*b.M12 + a.M22*b.M22,
+                  a.M21*b.M13 + a.M22*b.M23 + a.M23])
+ 
+proc `*`*[T](a: Matrix2x3[T], p: Point2D[T]): Point2D[T] = 
+    let 
+        x = a.M11*p.x + a.M12*p.y + a.M13
+        y = a.M21*p.x + a.M22*p.y + a.M23
+ 
+    Point2D[T](x: x, y: y)
+ 
+# making these so things like "line" that need a constructor don't stick out.
+# 2x2 determinant:  |a b|
+#                   |c d|  = ad - bc
+ 
+# String rendering
+#
+template ff[S](x: S): string = 
+    formatFloat(float(x), ffDefault, 0)
+ 
+proc `$`*[S](p: Point2D[S]): string = 
+    "P($1, $2)" % [ff(p.x), ff(p.y)]
+ 
+proc `$`*[S](p: Vector2D[S]): string = 
+    "V($1, $2)" % [ff(p.x), ff(p.y)]
+ 
+proc `$`*[S](m: Matrix2x3[S]): string =
+    "M($1 $2 $3/$4 $5 $6)" % [ff(m.M11), ff(m.M12), ff(m.M13), 
+                              ff(m.M21), ff(m.M22), ff(m.M23)]
+
+#
+# Vector operators.
+proc `-`*[S](a: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: -a.x, y: -a.y)
+
+proc `+`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x + b.x, y: a.y + b.y)
+
+proc `-`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x - b.x, y: a.y - b.y)
+
+proc `*`*[S](v: Vector2D[S], sc: S): Vector2D[S] =
+  Vector2D[S](x: v.x*sc, y: v.y*sc)
+
+proc `*`*[S](sc: S, v: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: v.x*sc, y: v.y*sc)
+
+proc `/`*[S](v: Vector2D[S], sc: S): Vector2D[S] =
+  Vector2D[S](x: v.x/sc, y: v.y/sc)
+
+proc `/`*[S](sc: S; v: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: sc/v.x, y: sc/v.y)
+
+proc `/`*[S](a, b: Vector2D[S]): Vector2D[S] = 
+  Vector2D[S](x: a.x/b.x, y: a.y/b.y)
+#proc vec[S](x, y: S): Vector2D[S]
+proc vec[S](x, y: S): Vector2D[S] =
+  Vector2D[S](x: x, y: y)
+
+if isMainModule:
+  # Comment out this let, and the program will fail to
+  # compile with a type mismatch, as expected.
+
+  let s3 = scale(vec(4.0, 4.0))
+  let barf = translation(Point2D[float32](x: 1, y: 1)) * rotation(float(0.7))
+
+  echo "Badness ", barf
diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim
new file mode 100644
index 000000000..00d90c55e
--- /dev/null
+++ b/tests/generics/twrong_generic_object.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "cannot instantiate: 'GenericNodeObj'"
+  line: 21
+"""
+# bug #2509
+type
+  GenericNodeObj[T] = ref object
+    obj: T
+
+  Node* = ref object
+    children*: seq[Node]
+    parent*: Node
+
+    nodeObj*: GenericNodeObj # [int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+  result = Node(nodeObj: nodeObj)
+  newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+var myNode = newNode(genericObj)
diff --git a/tests/gensym/tgensym.nim b/tests/gensym/tgensym.nim
new file mode 100644
index 000000000..3c85b0b83
--- /dev/null
+++ b/tests/gensym/tgensym.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "123100"
+"""
+
+template hygienic(val: expr) =
+  var x = val
+  stdout.write x
+
+var x = 100
+
+hygienic 1
+hygienic 2
+hygienic 3
+
+echo x
+
diff --git a/tests/gensym/tgensymgeneric.nim b/tests/gensym/tgensymgeneric.nim
new file mode 100644
index 000000000..54390a4ef
--- /dev/null
+++ b/tests/gensym/tgensymgeneric.nim
@@ -0,0 +1,31 @@
+# We need to open the gensym'ed symbol again so that the instantiation
+# creates a fresh copy; but this is wrong the very first reason for gensym
+# is that scope rules cannot be used! So simply removing 'sfGenSym' does
+# not work. Copying the symbol does not work either because we're already
+# the owner of the symbol! What we need to do is to copy the symbol
+# in the generic instantiation process...
+
+type
+  TA = object
+    x: int
+  TB = object
+    x: string
+
+template genImpl() =
+  var gensymed: T
+  when T is TB:
+    gensymed.x = "abc"
+  else:
+    gensymed.x = 123
+  shallowCopy(result, gensymed)
+
+proc gen[T](x: T): T =
+  genImpl()
+
+var
+  a: TA
+  b: TB
+let x = gen(a)
+let y = gen(b)
+
+echo x.x, " ", y.x
diff --git a/tests/global/globalaux.nim b/tests/global/globalaux.nim
new file mode 100644
index 000000000..5f6f72721
--- /dev/null
+++ b/tests/global/globalaux.nim
@@ -0,0 +1,15 @@
+type 
+  TObj*[T] = object
+    val*: T
+
+var
+  totalGlobals* = 0
+
+proc makeObj[T](x: T): TObj[T] =
+  totalGlobals += 1
+  result.val = x
+
+proc globalInstance*[T]: var TObj[T] =
+  var g {.global.} = when T is int: makeObj(10) else: makeObj("hello")
+  result = g
+
diff --git a/tests/global/globalaux2.nim b/tests/global/globalaux2.nim
new file mode 100644
index 000000000..6c77f1f48
--- /dev/null
+++ b/tests/global/globalaux2.nim
@@ -0,0 +1,4 @@
+import globalaux
+
+echo "in globalaux2: ", globalInstance[int]().val
+
diff --git a/tests/global/tglobal.nim b/tests/global/tglobal.nim
new file mode 100644
index 000000000..d44a62afc
--- /dev/null
+++ b/tests/global/tglobal.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
+  disabled: "true"
+"""
+
+import globalaux, globalaux2
+
+echo "total globals: ", totalGlobals
+
+globalInstance[int]().val = 100
+echo "int value: ", globalInstance[int]().val
+
+globalInstance[string]().val = "first"
+globalInstance[string]().val = "second"
+echo "string value: ", globalInstance[string]().val
+
diff --git a/tests/global/tglobalforvar.nim b/tests/global/tglobalforvar.nim
new file mode 100644
index 000000000..af75df5c8
--- /dev/null
+++ b/tests/global/tglobalforvar.nim
@@ -0,0 +1,7 @@
+
+var funcs: seq[proc (): int {.nimcall.}] = @[]
+for i in 0..10:
+  funcs.add((proc (): int = return i * i))
+
+echo(funcs[3]())
+
diff --git a/tests/implicit/timplicititems.nim b/tests/implicit/timplicititems.nim
new file mode 100644
index 000000000..dbe321cb6
--- /dev/null
+++ b/tests/implicit/timplicititems.nim
@@ -0,0 +1,4 @@
+
+for x in [1, 2, 3, 4]:
+  echo x
+
diff --git a/tests/implicit/timplictderef.nim b/tests/implicit/timplictderef.nim
new file mode 100644
index 000000000..fcb647217
--- /dev/null
+++ b/tests/implicit/timplictderef.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''2
+88'''
+"""
+
+type
+  TValue* {.pure, final.} = object of RootObj
+    a: int
+  PValue = ref TValue
+  PPValue = ptr PValue
+
+
+var x: PValue
+new x
+var sp: PPValue = addr x
+
+sp.a = 2
+if sp.a == 2: echo 2  # with sp[].a the error is gone
+
+# Test the new auto-deref a little
+
+{.experimental.}
+
+proc p(x: var int; y: int) = x += y
+
+block:
+  var x: ref int
+  new(x)
+
+  x.p(44)
+
+  var indirect = p
+  x.indirect(44)
+
+  echo x[]
diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim
new file mode 100644
index 000000000..57443a7d3
--- /dev/null
+++ b/tests/init/tuninit1.nim
@@ -0,0 +1,36 @@
+discard """
+  msg: "Warning: 'y' might not have been initialized [Uninit]"
+  line:34
+"""
+
+import strutils
+
+{.warning[Uninit]:on.}
+
+proc p =
+  var x, y, z: int
+  if stdin.readLine == "true":
+    x = 34
+    
+    while false:
+      y = 999
+      break
+      
+    while true:
+      if x == 12: break
+      y = 9999
+      
+    try:
+      z = parseInt("1233")
+    except E_Base:
+      case x
+      of 34: z = 123
+      of 13: z = 34
+      else: z = 8
+  else:
+    y = 3444
+    x = 3111
+    z = 0
+  echo x, y, z
+  
+p()
diff --git a/tests/init/tuninit2.nim b/tests/init/tuninit2.nim
new file mode 100644
index 000000000..950895c02
--- /dev/null
+++ b/tests/init/tuninit2.nim
@@ -0,0 +1,54 @@
+# bug #2316
+
+type
+    EventType = enum
+      QuitEvent = 5
+    AppMain* = ref object of RootObj
+        width: int
+        height: int
+        title: string
+        running: bool
+        event_type: EventType
+    App* = ref object of AppMain
+        draw_proc: proc(app: AppMain): void {.closure.}
+        events_proc: proc(app: AppMain): void {.closure.}
+        update_proc: proc(app: AppMain, dt: float): void {.closure.}
+        load_proc: proc(app: AppMain): void {.closure.}
+
+
+proc initApp*(t: string, w, h: int): App =
+    App(width: w, height: h, title: t, event_type: EventType.QuitEvent)
+
+
+method getTitle*(self: AppMain): string = self.title
+method getWidth*(self: AppMain): int = self.width
+method getHeight*(self: AppMain): int = self.height
+
+
+method draw*(self: App, draw: proc(app: AppMain)): void =
+    self.draw_proc = draw
+
+method load*(self: App, load: proc(a: AppMain)): void =
+    self.load_proc = load
+
+method events*(self: App, events: proc(app: AppMain)): void =
+    self.events_proc = events
+
+method update*(self: App, update: proc(app: AppMain, delta: float)): void =
+    self.update_proc = update
+
+method run*(self: App): void = discard
+
+var mygame = initApp("Example", 800, 600)
+
+mygame.load(proc(app: AppMain): void =
+    echo app.getTitle()
+    echo app.getWidth()
+    echo app.getHeight()
+)
+
+mygame.events(proc(app: AppMain): void =
+    discard
+)
+
+mygame.run()
diff --git a/tests/init/tzeroarray.nim b/tests/init/tzeroarray.nim
new file mode 100644
index 000000000..b784b601e
--- /dev/null
+++ b/tests/init/tzeroarray.nim
@@ -0,0 +1,18 @@
+discard """
+  output: done
+"""
+
+for i in 0 .. 1:
+  var a: array[0..4, int]
+  if a[0] != 0: quit "bug"
+  a[0] = 6
+
+proc main =
+  for i in 0 .. 1:
+    var a: array[0..4, int]
+    if a[0] != 0: quit "bug"
+    a[0] = 6
+
+main()
+echo "done"
+
diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim
new file mode 100644
index 000000000..9f0d0a74b
--- /dev/null
+++ b/tests/iter/tanoniter1.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''1
+2
+3
+4
+1
+2'''
+"""
+
+proc factory(a, b: int): iterator (): int =
+  iterator foo(): int {.closure.} =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+  return foo
+
+proc factory2(a, b: int): iterator (): int =
+  return iterator (): int =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+
+let foo = factory(1, 4)
+
+for f in foo():
+  echo f
+
+let foo2 = factory2(1,2)
+
+for f in foo2(): echo f
diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim
new file mode 100644
index 000000000..796672783
--- /dev/null
+++ b/tests/iter/tchainediterators.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''16
+32
+48
+64
+128
+192
+'''
+  disabled: "true"
+"""
+
+# This all relies on non-documented and questionable features.
+
+iterator gaz(it: iterator{.inline.}): type(it) =
+  for x in it:
+    yield x*2
+
+iterator baz(it: iterator{.inline.}): auto =
+  for x in gaz(it):
+    yield x*2
+
+type T1 = auto
+
+iterator bar(it: iterator: T1{.inline.}): T1 =
+  for x in baz(it):
+    yield x*2
+
+iterator foo[T](x: iterator: T{.inline.}): T =
+  for e in bar(x):
+    yield e*2
+
+var s = @[1, 2, 3]
+
+# pass an iterator several levels deep:
+for x in s.items.foo:
+  echo x
+
+# use some complex iterator as an input for another one:
+for x in s.items.baz.foo:
+  echo x
+
diff --git a/tests/iter/tconcat.nim b/tests/iter/tconcat.nim
new file mode 100644
index 000000000..477ac5e26
--- /dev/null
+++ b/tests/iter/tconcat.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+2
+3
+4
+20
+21
+22
+23'''
+"""
+
+proc toIter*[T](s: Slice[T]): iterator: T =
+  iterator it: T {.closure.} =
+    for x in s.a..s.b:
+      yield x
+  return it
+
+iterator concat*[T](its: varargs[T, toIter]): auto =
+  for i in its:
+    for x in i():
+      yield x
+
+for i in concat(1..4, 20..23):
+  echo i
diff --git a/tests/iter/tcountup.nim b/tests/iter/tcountup.nim
new file mode 100644
index 000000000..e68a614b0
--- /dev/null
+++ b/tests/iter/tcountup.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "tcountup.nim"
+  output: "0123456789"
+"""
+
+# Test new countup and unary < 
+
+for i in 0 .. < 10'i64: 
+  stdout.write(i)
+  
+#OUT 0123456789
+
+
+
diff --git a/tests/iter/timplicit_auto.nim b/tests/iter/timplicit_auto.nim
new file mode 100644
index 000000000..ccb279fe0
--- /dev/null
+++ b/tests/iter/timplicit_auto.nim
@@ -0,0 +1,18 @@
+# bug #1838
+
+type State = enum Empty, Tree, Fire
+
+const
+  disp: array[State, string] = ["  ", "\e[32m/\\\e[m", "\e[07;31m/\\\e[m"]
+
+proc univ(x, y: int): State = Tree
+
+var w, h = 30
+
+iterator fields(a = (0,0), b = (h-1,w-1)) =
+  for y in max(a[0], 0) .. min(b[0], h-1):
+    for x in max(a[1], 0) .. min(b[1], w-1):
+      yield (y,x)
+
+for y,x in fields():
+  stdout.write disp[univ(x, y)]
diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim
new file mode 100644
index 000000000..19a11dc4e
--- /dev/null
+++ b/tests/iter/titer.nim
@@ -0,0 +1,44 @@
+# Test the new iterators

+

+iterator xrange(fromm, to: int, step = 1): int =

+  var a = fromm

+  while a <= to:

+    yield a

+    inc(a, step)

+

+iterator interval[T](a, b: T): T =

+  var x = a

+  while x <= b:

+    yield x

+    inc(x)

+

+#

+#iterator lines(filename: string): (line: string) =

+#  var

+#    f: tTextfile

+#    shouldClose = open(f, filename)

+#  if shouldClose:

+#    setSpace(line, 256)

+#    while readTextLine(f, line):

+#      yield line

+#  finally:

+#    if shouldClose: close(f)

+#

+

+for i in xrange(0, 5):

+  for k in xrange(1, 7):

+    write(stdout, "test")

+

+for j in interval(45, 45):

+  write(stdout, "test2!")

+  write(stdout, "test3?")

+

+for x in items(["hi", "what's", "your", "name"]):

+  echo(x)

+  

+const

+  stringArray = ["hi", "what's", "your", "name"]

+

+for i in 0..len(stringArray)-1:

+  echo(stringArray[i])

+

diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim
new file mode 100644
index 000000000..4a7f76883
--- /dev/null
+++ b/tests/iter/titer2.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''true
+3
+4
+5'''
+  cmd: "nim $target --gc:none --hints:on --warnings:off $options $file"
+"""
+
+import hashes
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+  TTable* {.final.}[A, B] = object
+    data: TKeyValuePairSeq[A, B]
+    counter: int
+
+iterator mycountup(a, b: int): int =
+  var res = a
+  while res <= b:
+    yield res
+    inc(res)
+
+when true:
+  iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
+    ## iterates over any (key, value) pair in the table `t`.
+    for h in mycountup(0, high(t.data)):
+      var k = t.data[h].key
+      if t.data[h].slot == seFilled: yield (k, t.data[h].val)
+else:
+  iterator pairs*(t: TTable[int, string]): tuple[key: int, val: string] =
+    ## iterates over any (key, value) pair in the table `t`.
+    for h in mycountup(0, high(t.data)):
+      var k = t.data[h].key
+      if t.data[h].slot == seFilled: yield (k, t.data[h].val)
+
+proc initTable*[A, B](initialSize=64): TTable[A, B] =
+  ## creates a new hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+block Test1:
+  # generic cache does not instantiate the same iterator[types] twice. This
+  # means we have only one instantiation of 'h'. However, this is the same for
+  # a non-generic iterator!
+
+  var t = initTable[int, string]()
+  for k, v in t.pairs: discard
+  for k, v in t.pairs: discard
+
+echo "true"
+
+# bug #1560
+for i in @[3, 4, 5]:
+  echo($i)
diff --git a/tests/iter/titer3.nim b/tests/iter/titer3.nim
new file mode 100644
index 000000000..ab95dd7bd
--- /dev/null
+++ b/tests/iter/titer3.nim
@@ -0,0 +1,22 @@
+discard """
+  file: "titer3.nim"
+  output: "1231"
+"""
+
+iterator count1_3: int =
+  yield 1
+  yield 2
+  yield 3
+
+for x in count1_3():
+  write(stdout, $x)
+
+# yield inside an iterator, but not in a loop:
+iterator iter1(a: openArray[int]): int =
+  yield a[0]
+
+var x = [[1, 2, 3], [4, 5, 6]]
+for y in iter1(x[0]): write(stdout, $y)
+
+#OUT 1231
+
diff --git a/tests/iter/titer4.nim b/tests/iter/titer4.nim
new file mode 100644
index 000000000..9b52f8055
--- /dev/null
+++ b/tests/iter/titer4.nim
@@ -0,0 +1,10 @@
+discard """
+  file: "titer4.nim"
+  line: 7
+  errormsg: "iterator within for loop context expected"
+"""
+# implicit items/pairs, but not if we have 3 for loop vars:
+for x, y, z in {'a'..'z'}: #ERROR_MSG iterator within for loop context expected
+  nil
+
+
diff --git a/tests/iter/titer5.nim b/tests/iter/titer5.nim
new file mode 100644
index 000000000..bbd50fcb1
--- /dev/null
+++ b/tests/iter/titer5.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "titer5.nim"
+  output: "abcxyz"
+"""
+# Test method call syntax for iterators:
+import strutils
+
+const lines = """abc  xyz"""
+
+for x in lines.split():
+  stdout.write(x)
+
+#OUT abcxyz
+
+
+
diff --git a/tests/iter/titer6.nim b/tests/iter/titer6.nim
new file mode 100644
index 000000000..2abfa0860
--- /dev/null
+++ b/tests/iter/titer6.nim
@@ -0,0 +1,37 @@
+discard """
+  file: "titer6.nim"
+  output: "000"
+"""
+# Test iterator with more than 1 yield statement
+
+import strutils
+
+iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] =
+  var i = 0
+  while i < s.len:
+    var j = i
+    if s[j] in seps:
+      while j < s.len and s[j] in seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), true)
+    else:
+      while j < s.len and s[j] notin seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), false)
+    i = j
+
+for word, isSep in tokenize2("ta da", WhiteSpace):
+  var titer2TestVar = 0 
+  stdout.write(titer2TestVar)
+
+proc wordWrap2(s: string, maxLineWidth = 80, 
+               splitLongWords = true,
+               seps: set[char] = Whitespace,
+               newLine = "\n"): string  = 
+  result = ""
+  for word, isSep in tokenize2(s, seps):
+    var w = 0 
+
+
+
diff --git a/tests/iter/titer7.nim b/tests/iter/titer7.nim
new file mode 100644
index 000000000..d0337b7bd
--- /dev/null
+++ b/tests/iter/titer7.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''--- evens
+2
+4
+6
+8
+--- squares
+1
+4
+9
+16
+25
+36
+49
+64
+81
+--- squares of evens, only
+4
+16
+36
+64'''
+"""
+
+iterator `/`[T](sequence: seq[T],
+                filter: proc(e:T):bool {.closure.}) : T =
+    for element in sequence:
+        if (filter(element)):
+            yield element
+
+iterator `>>`[I,O](sequence: seq[I],
+                   map: proc(e:I):O {.closure.}) : O =
+    for element in sequence:
+        yield map(element)
+
+iterator `/>>`[I,O](sequence: seq[I],
+                    filtermap:tuple[
+                        f:proc(e:I):bool {.closure.},
+                        m:proc(e:I):O {.closure.}]) : O =
+    for element in sequence:
+        if (filtermap.f(element)):
+            yield filtermap.m(element)
+
+proc isEven(x:int): bool {.closure.} = result =
+    (x and 1) == 0
+
+proc square(x:int): int {.closure.} = result =
+    x * x
+
+let list = @[1,2,3,4,5,6,7,8,9]
+
+echo ("--- evens")
+for item in list / isEven : echo(item)
+echo ("--- squares")
+for item in list >> square : echo(item)
+echo ("--- squares of evens, only")
+# next line doesn't compile. Generic types are not inferred
+for item in list />> (isEven, square) : echo(item)
diff --git a/tests/iter/titer8.nim b/tests/iter/titer8.nim
new file mode 100644
index 000000000..3bc01122f
--- /dev/null
+++ b/tests/iter/titer8.nim
@@ -0,0 +1,117 @@
+discard """
+  output: '''tada
+1
+2
+3
+ta da1 1
+1 2
+1 3
+2 1
+2 2
+2 3
+3 1
+3 2
+3 3
+0
+1
+2
+a1: A
+a2: A
+a1: B
+a2: B
+a1: C
+a2: C
+a1: D'''
+"""
+# Test first class iterator:
+
+import strutils
+
+iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] {.closure.} =
+  var i = 0
+  while i < s.len:
+    var j = i
+    if s[j] in seps:
+      while j < s.len and s[j] in seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), true)
+    else:
+      while j < s.len and s[j] notin seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), false)
+    i = j
+
+iterator count3(): int {.closure.} =
+  yield 1
+  yield 2
+  yield 3
+
+for word, isSep in tokenize2("ta da", WhiteSpace):
+  if not isSep:
+    stdout.write(word)
+echo ""
+
+proc inProc() =
+  for c in count3():
+    echo c
+  
+  for word, isSep in tokenize2("ta da", WhiteSpace):
+    stdout.write(word)
+
+  for c in count3():
+    for d in count3():
+      echo c, " ", d
+
+
+inProc()
+
+iterator count0(): int {.closure.} =
+  # note: doesn't require anything in its closure (except 'state')
+  yield 0
+ 
+iterator count2(): int {.closure.} =
+  # note: requires 'x' in its closure
+  var x = 1
+  yield x
+  inc x
+  yield x
+
+# a first class iterator has the type 'proc {.closure.}', but maybe
+# it shouldn't:
+proc invoke(iter: iterator(): int {.closure.}) =
+  for x in iter(): echo x
+
+invoke(count0)
+invoke(count2)
+
+
+# simple tasking:
+type
+  TTask = iterator (ticker: int)
+
+iterator a1(ticker: int) {.closure.} =
+  echo "a1: A"
+  yield
+  echo "a1: B"
+  yield
+  echo "a1: C"
+  yield
+  echo "a1: D"
+
+iterator a2(ticker: int) {.closure.} =
+  echo "a2: A"
+  yield
+  echo "a2: B"
+  yield
+  echo "a2: C"
+
+proc runTasks(t: varargs[TTask]) =
+  var ticker = 0
+  while true:
+    let x = t[ticker mod t.len]
+    if finished(x): break
+    x(ticker)
+    inc ticker
+
+runTasks(a1, a2)
diff --git a/tests/iter/titer9.nim b/tests/iter/titer9.nim
new file mode 100644
index 000000000..99874e70a
--- /dev/null
+++ b/tests/iter/titer9.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''5
+14
+0'''
+"""
+
+iterator count[T](x: T, skip: bool): int {.closure.} =
+  if skip: return x+10
+  else: yield x+1
+
+  if skip: return x+10
+  else: yield x+2
+
+proc takeProc[T](x: iterator (x: T, skip: bool): int) =
+  echo x(4, false)
+  echo x(4, true)
+  echo x(4, false)
+
+takeProc(count[int])
+
diff --git a/tests/iter/titer_no_tuple_unpack.nim b/tests/iter/titer_no_tuple_unpack.nim
new file mode 100644
index 000000000..da5e1bc46
--- /dev/null
+++ b/tests/iter/titer_no_tuple_unpack.nim
@@ -0,0 +1,13 @@
+

+iterator xrange(fromm, to: int, step = 1): tuple[x, y: int] =

+  var a = fromm

+  while a <= to:

+    yield (a, a+1)

+    inc(a, step)

+
+for a, b in xrange(3, 7):
+  echo a, " ", b
+  
+for tup in xrange(3, 7):
+  echo tup
+
diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim
new file mode 100644
index 000000000..3ec79f68d
--- /dev/null
+++ b/tests/iter/titerable.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''2
+4
+6
+4
+8
+12
+'''
+"""
+
+iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
+  for e in s: yield f(e)
+
+template toSeq(s: expr): expr =
+  var res = newSeq[type(s)](0)
+  for e in s: res.add(e)
+  res
+
+var s1 = @[1, 2, 3]
+for x in map(s1.items, proc (a:int): int = a*2):
+  echo x
+
+var s2 = toSeq(map(s1.items, proc (a:int): int = a*4))
+for x in s2:
+  echo x
+
diff --git a/tests/iter/titerovl.nim b/tests/iter/titerovl.nim
new file mode 100644
index 000000000..be665b2b7
--- /dev/null
+++ b/tests/iter/titerovl.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''9
+1
+2
+3
+'''
+"""
+
+# Test the new overloading rules for iterators:
+
+# test that iterator 'p' is preferred:
+proc p(): seq[int] = @[1, 2, 3]
+iterator p(): int = yield 9
+
+for x in p(): echo x
+
+# test that 'q' works in this position:
+proc q(): seq[int] = @[1, 2, 3]
+
+for x in q(): echo x
+
diff --git a/tests/iter/titerslice.nim b/tests/iter/titerslice.nim
new file mode 100644
index 000000000..e5d2e14a3
--- /dev/null
+++ b/tests/iter/titerslice.nim
@@ -0,0 +1,9 @@
+discard """
+  output: '''2
+3
+4'''
+"""
+
+var t1 = @["1", "2", "3", "4"]
+for t in t1[1..3]:
+  echo t
diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim
new file mode 100644
index 000000000..1e70ce247
--- /dev/null
+++ b/tests/iter/titervaropenarray.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "titer2.nim"
+  output: "123"
+"""
+# Try to break the transformation pass:
+iterator iterAndZero(a: var openArray[int]): int =
+  for i in 0..len(a)-1:
+    yield a[i]
+    a[i] = 0
+
+var x = [[1, 2, 3], [4, 5, 6]]
+for y in iterAndZero(x[0]): write(stdout, $y)
+#OUT 123
+
+
+
diff --git a/tests/iter/tmoditer.nim b/tests/iter/tmoditer.nim
new file mode 100644
index 000000000..1e6be37e4
--- /dev/null
+++ b/tests/iter/tmoditer.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "XXXXX01234"
+"""
+
+iterator modPairs(a: var array[0..4,string]): tuple[key: int, val: var string] =
+  for i in 0..a.high:
+    yield (i, a[i])
+
+iterator modItems*[T](a: var array[0..4,T]): var T =
+  for i in 0..a.high:
+    yield a[i]
+
+var
+  arr = ["a", "b", "c", "d", "e"]
+
+for a in modItems(arr):
+  a = "X"
+
+for a in items(arr):
+  stdout.write(a)
+
+for i, a in modPairs(arr):
+  a = $i
+
+for a in items(arr):
+  stdout.write(a)
+
+echo ""
+
diff --git a/tests/iter/tobj_iter.nim b/tests/iter/tobj_iter.nim
new file mode 100644
index 000000000..eb0e37b23
--- /dev/null
+++ b/tests/iter/tobj_iter.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "7"
+"""
+
+# bug #2023
+
+{.deadCodeElim:on.}
+
+type
+    Obj = object
+        iter: iterator (): int8 {.closure.}
+
+iterator test(): int8 {.closure.} =
+    yield 7
+
+proc init():Obj=
+    result.iter = test
+
+var o = init()
+echo(o.iter())
diff --git a/tests/iter/treciter.nim b/tests/iter/treciter.nim
new file mode 100644
index 000000000..dacdbdfd7
--- /dev/null
+++ b/tests/iter/treciter.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "treciter.nim"
+  line: 9
+  errormsg: "recursive dependency: \'myrec\'"
+"""
+# Test that an error message occurs for a recursive iterator
+
+iterator myrec(n: int): int =
+  for x in myrec(n-1): #ERROR_MSG recursive dependency: 'myrec'
+    yield x
+
+for x in myrec(10): echo x
+
+
diff --git a/tests/iter/tscheduler.nim b/tests/iter/tscheduler.nim
new file mode 100644
index 000000000..a267f15c4
--- /dev/null
+++ b/tests/iter/tscheduler.nim
@@ -0,0 +1,76 @@
+discard """
+  output: '''a1 5
+a2 10
+a1 3
+a1 1
+a2 8
+a2 6
+a2 4
+a2 2'''
+"""
+
+import os, strutils, times, algorithm
+
+
+type TaskFn = iterator (): float
+
+type Task = object
+    coro: TaskFn
+    next_run: float
+
+
+type Scheduler = object
+    tasks: seq[Task]
+
+
+proc newScheduler(): Scheduler =
+    var s = Scheduler()
+    s.tasks = @[]
+    return s
+
+
+proc start(this: var Scheduler, task: TaskFn) =
+    var t = Task()
+    t.coro = task
+    t.next_run = 0.0
+    this.tasks.add(t)
+
+
+proc run(this: var Scheduler) =
+    while this.tasks.len > 0:
+        var dead: seq[int] = @[]
+        for i in this.tasks.low..this.tasks.high:
+            var task = this.tasks[i]
+            if finished(task.coro):
+                dead.add(i)
+                continue
+            if task.next_run <= epochTime():
+                task.next_run = task.coro() + epochTime()
+            this.tasks[i] = task
+        for i in dead:
+            this.tasks.delete(i)
+        if this.tasks.len > 0:
+            sort(this.tasks, proc (t1: Task, t2: Task): int = cmp(t1.next_run, t2.next_run))
+            sleep(int((this.tasks[0].next_run - epochTime()) * 1000))
+
+
+iterator a1(): float {.closure.} =
+    var k = 5
+    while k > 0:
+        echo "a1 $1" % [$k]
+        dec k, 2
+        yield 0.5
+
+
+iterator a2(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a2 $1" % [$k]
+        dec k, 2
+        yield 1.5
+
+
+var sched = newScheduler()
+sched.start(a1)
+sched.start(a2)
+sched.run()
diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim
new file mode 100644
index 000000000..2f024ee7e
--- /dev/null
+++ b/tests/iter/tshallowcopy_closures.nim
@@ -0,0 +1,31 @@
+discard """
+  ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')"
+"""
+
+# bug #1803
+type TaskFn = iterator (): float
+
+iterator a1(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a1 ", k
+        dec k
+        yield 1.0
+
+
+iterator a2(): float {.closure.} =
+    var k = 15
+    while k > 0:
+        echo "a2 ", k
+        dec k
+        yield 2.0
+
+var
+  x = a1
+  y = a2
+  z: TaskFn
+
+discard x()
+z = x #shallowCopy(z, x)
+z = y #shallowCopy(z, y)
+discard x()
diff --git a/tests/iter/twrongiter.nim b/tests/iter/twrongiter.nim
new file mode 100644
index 000000000..33394219b
--- /dev/null
+++ b/tests/iter/twrongiter.nim
@@ -0,0 +1,13 @@
+discard """
+line: 12
+errormsg: "type mismatch"
+"""
+
+proc first(it: iterator(): int): seq[int] =
+  return @[]
+
+iterator primes(): int =
+  yield 1
+
+for i in first(primes):
+  break
diff --git a/tests/js.html b/tests/js.html
new file mode 100644
index 000000000..81baef784
--- /dev/null
+++ b/tests/js.html
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!--  This has been written by hand. (c) 2010 Andreas Rumpf -->
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Nimrod JavaScript Generator Test</title>
+<style type="text/css">
+span.DecNumber {color: blue}
+</style>
+<script src="nimcache/js.js" type="text/javascript"></script>
+</head>
+<body onload="OnLoad()">
+<form name="form1" action="js.html">
+  <input type="text" name="input1" size="10" />
+  <input type="button" value="Calculate square" onclick="OnButtonClick()" />
+</form>
+
+</body>
+</html>
diff --git a/tests/js.nim b/tests/js.nim
new file mode 100644
index 000000000..e5e432366
--- /dev/null
+++ b/tests/js.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: "nim js --hints:on $options $file"
+"""
+
+# This file tests the JavaScript generator
+
+import
+  dom, strutils
+
+# We need to declare the used elements here. This is annoying but
+# prevents any kind of typo:
+var
+  inputElement {.importc: "document.form1.input1", nodecl.}: ref TElement
+
+proc OnButtonClick() {.exportc.} =
+  let v = $inputElement.value
+  if v.allCharsInSet(whiteSpace):
+    echo "only whitespace, hu?"
+  else:
+    var x = parseInt(v)
+    echo x*x
+
+proc OnLoad() {.exportc.} = 
+  echo "Welcome! Please take your time to fill in this formular!"
diff --git a/tests/js/taddr.nim b/tests/js/taddr.nim
new file mode 100644
index 000000000..6a60aa902
--- /dev/null
+++ b/tests/js/taddr.nim
@@ -0,0 +1,36 @@
+type T = object
+  x: int
+  s: string
+
+var obj: T
+var fieldAddr = addr(obj.x)
+var objAddr = addr(obj)
+
+# Integer tests
+var field = fieldAddr[]
+doAssert field == 0
+
+var objDeref = objAddr[]
+doAssert objDeref.x == 0
+
+# Change value
+obj.x = 42
+
+doAssert field == 0
+doAssert objDeref.x == 0
+
+field = fieldAddr[]
+objDeref = objAddr[]
+
+doAssert field == 42
+doAssert objDeref.x == 42
+
+# String tests
+obj.s = "lorem ipsum dolor sit amet"
+var indexAddr = addr(obj.s[2])
+
+doAssert indexAddr[] == '4'
+
+indexAddr[] = 'd'
+
+doAssert indexAddr[] == 'd'
diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim
new file mode 100644
index 000000000..1269e6f66
--- /dev/null
+++ b/tests/js/tbyvar.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''foo 12
+bar 12
+2
+foo 12
+bar 12
+2
+'''
+"""
+
+# bug #1489
+proc foo(x: int) = echo "foo ", x
+proc bar(y: var int) = echo "bar ", y
+
+var x = 12
+foo(x)
+bar(x)
+
+# bug #1490
+var y = 1
+y *= 2
+echo y
+
+proc main =
+  var x = 12
+  foo(x)
+  bar(x)
+
+  var y = 1
+  y *= 2
+  echo y
+
+main()
diff --git a/tests/js/test1.nim b/tests/js/test1.nim
new file mode 100644
index 000000000..7f1d346f0
--- /dev/null
+++ b/tests/js/test1.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "1261129"
+"""
+
+# This file tests the JavaScript generator
+
+import
+  dom, strutils
+
+var
+  inputElement = "1123"
+
+proc onButtonClick(inputElement: string) {.exportc.} =
+  let v = $inputElement
+  if v.allCharsInSet(WhiteSpace):
+    echo "only whitespace, hu?"
+  else:
+    var x = parseInt(v)
+    echo x*x
+
+onButtonClick(inputElement)
+
diff --git a/tests/js/test2.nim b/tests/js/test2.nim
new file mode 100644
index 000000000..1a42fbfda
--- /dev/null
+++ b/tests/js/test2.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''foo
+js 3.14
+7'''
+"""
+
+# This file tests the JavaScript generator
+
+#  #335 
+proc foo() =
+  var bar = "foo"
+  proc baz() =
+    echo bar
+  baz()
+foo()
+  
+# #376
+when not defined(JS):
+  proc foo(val: float): string = "no js " & $val
+else:
+  proc foo(val: float): string = "js " & $val
+
+echo foo(3.14)
+
+# #2495
+type C = concept x
+
+proc test(x: C, T: typedesc): T =
+  cast[T](x)
+
+echo 7.test(int8)
diff --git a/tests/js/testmagic.nim b/tests/js/testmagic.nim
new file mode 100644
index 000000000..5f793ae05
--- /dev/null
+++ b/tests/js/testmagic.nim
@@ -0,0 +1,9 @@
+discard """
+  output: '''true'''
+"""
+
+# This file tests some magic
+
+var foo = cstring("foo")
+var bar = cstring("foo")
+echo(foo == bar)
diff --git a/tests/js/testobjs.nim b/tests/js/testobjs.nim
new file mode 100644
index 000000000..4fb9a83dc
--- /dev/null
+++ b/tests/js/testobjs.nim
@@ -0,0 +1,34 @@
+## Tests javascript object generation
+
+type
+  Kg = distinct float
+  Price = int
+  Item = object of RootObj
+    weight: Kg
+    price: Price
+    desc: cstring
+  Person = object of RootObj
+    name: cstring
+    age: int
+    item: Item
+  Test = object
+    name: cstring
+  Recurse[T] = object
+    data: T
+    next: ref Recurse[T]
+
+var
+  test = Test(name: "Jorden")
+  sword = Item(desc: "pointy", weight: Kg(10.0),
+                price: Price(50))
+  knight = Person(name: "robert", age: 19, item: sword)
+  recurse4 = (ref Recurse[int])(data: 4, next: nil)
+  recurse3 = (ref Recurse[int])(data: 3, next: recurse4)
+  recurse2 = (ref Recurse[int])(data: 2, next: recurse3)
+  recurse1 = Recurse[int](data: 1, next: recurse2)
+
+
+assert(test.name == "Jorden")
+assert(knight.age == 19)
+assert(knight.item.price == 50)
+assert(recurse1.next.next.data == 3)
diff --git a/tests/js/tfloatround.nim b/tests/js/tfloatround.nim
new file mode 100644
index 000000000..7bc5430e6
--- /dev/null
+++ b/tests/js/tfloatround.nim
@@ -0,0 +1,7 @@
+discard """
+  output: '''
+3
+'''
+"""
+
+echo int(22 / 7)
diff --git a/tests/js/tobjfieldbyvar.nim b/tests/js/tobjfieldbyvar.nim
new file mode 100644
index 000000000..91a3c1315
--- /dev/null
+++ b/tests/js/tobjfieldbyvar.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''5
+'''
+"""
+
+# bug #2798
+
+type Inner = object
+  value: int
+
+type Outer = object
+  i: Inner
+
+proc test(i: var Inner) =
+  i.value += 5
+
+var o: Outer
+test(o.i)
+
+echo o.i.value
diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim
new file mode 100644
index 000000000..f4ea02fec
--- /dev/null
+++ b/tests/js/tstringitems.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''Hello
+Hello'''
+"""
+
+# bug #2581
+
+const someVars = [ "Hello" ]
+var someVars2 = [ "Hello" ]
+
+proc getSomeVar: string =
+    for i in someVars:
+        if i == "Hello":
+            result = i
+            break
+
+proc getSomeVar2: string =
+    for i in someVars2:
+        if i == "Hello":
+            result = i
+            break
+
+echo getSomeVar()
+echo getSomeVar2()
diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim
new file mode 100644
index 000000000..8a264a5e0
--- /dev/null
+++ b/tests/js/tunittests.nim
@@ -0,0 +1,12 @@
+discard """
+  disabled: "true"
+"""
+
+# Unittest uses lambdalifting at compile-time which we disable for the JS
+# codegen! So this cannot and will not work for quite some time.
+
+import unittest
+
+suite "Bacon":
+  test ">:)":
+    check(true == true)
diff --git a/tests/let/tlet.nim b/tests/let/tlet.nim
new file mode 100644
index 000000000..6703ba254
--- /dev/null
+++ b/tests/let/tlet.nim
@@ -0,0 +1,11 @@
+discard """
+  line: "10"
+  errormsg: "'name' cannot be assigned to"
+"""
+
+echo("What's your name? ")
+let name = readLine(stdin)
+while name == "":
+  echo("Please tell me your name: ")
+  name = readLine(stdin)
+
diff --git a/tests/let/tlet2.nim b/tests/let/tlet2.nim
new file mode 100644
index 000000000..66dd5a55b
--- /dev/null
+++ b/tests/let/tlet2.nim
@@ -0,0 +1,16 @@
+discard """
+  line: "13"
+  errormsg: "type mismatch: got (int literal(8), int literal(5), int, int)"
+"""
+
+proc divmod(a, b: int, res, remainder: var int) =
+  res = a div b        # integer division
+  remainder = a mod b  # integer modulo operation
+
+let
+  x = 9
+  y = 3
+divmod(8, 5, x, y) # modifies x and y
+echo(x)
+echo(y)
+
diff --git a/tests/lexer/thexlit.nim b/tests/lexer/thexlit.nim
new file mode 100644
index 000000000..04a530c9c
--- /dev/null
+++ b/tests/lexer/thexlit.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "thexlit.nim"
+  output: "equal"
+"""
+
+var t=0x950412DE
+
+if t==0x950412DE:
+    echo "equal"
+else:
+    echo "not equal"
+    
diff --git a/tests/lexer/thexrange.nim b/tests/lexer/thexrange.nim
new file mode 100644
index 000000000..e5e4c10c6
--- /dev/null
+++ b/tests/lexer/thexrange.nim
@@ -0,0 +1,8 @@
+
+type
+  TArray = array[0x0012..0x0013, int]
+  
+var a: TArray
+
+echo a[0x0012] #OUT 0
+
diff --git a/tests/lexer/tident.nim b/tests/lexer/tident.nim
new file mode 100644
index 000000000..1ed9894c6
--- /dev/null
+++ b/tests/lexer/tident.nim
@@ -0,0 +1,22 @@
+
+type
+  TIdObj* = object of TObject

+    id*: int                  # unique id; use this for comparisons and not the pointers

+  

+  PIdObj* = ref TIdObj

+  PIdent* = ref TIdent

+  TIdent*{.acyclic.} = object

+    s*: string

+
+proc myNewString(L: int): string {.inline.} =
+  result = newString(L)
+  if result.len == L: echo("Length correct")
+  else: echo("bug")
+  for i in 0..L-1:
+    if result[i] == '\0':
+      echo("Correct")
+    else: 
+      echo("Wrong")
+  
+var s = myNewString(8)
+
diff --git a/tests/lexer/tind1.nim b/tests/lexer/tind1.nim
new file mode 100644
index 000000000..f3fd952cc
--- /dev/null
+++ b/tests/lexer/tind1.nim
@@ -0,0 +1,27 @@
+discard """
+  line: 24
+  errormsg: "expression expected, but found 'keyword else'"
+"""
+
+import macros
+
+# finally optional indentation in 'if' expressions :-):
+var x = if 4 != 5:
+    "yes"
+  else:
+    "no"
+
+macro mymacro(n: expr): stmt {.immediate.} = nil
+
+mymacro:
+  echo "test"
+else:
+  echo "else part"
+  
+
+if 4 == 3:
+  echo "bug"
+  else:
+  echo "no bug"
+
+
diff --git a/tests/lexer/tindent1.nim b/tests/lexer/tindent1.nim
new file mode 100644
index 000000000..78a303783
--- /dev/null
+++ b/tests/lexer/tindent1.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''Success'''
+"""
+
+const romanNumbers1 =
+    [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1) ]
+
+const romanNumbers2 =
+    [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1)
+    ]
+
+const romanNumbers3 =
+  [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1)
+  ]
+
+const romanNumbers4 = [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1)
+    ]
+
+
+proc main =
+  var j = 0
+  while j < 10:
+    inc(j);
+
+  if j == 5: doAssert false
+
+var j = 0
+while j < 10:
+  inc(j);
+
+if j == 5: doAssert false
+
+main()
+echo "Success"
diff --git a/tests/lexer/tlexer.nim b/tests/lexer/tlexer.nim
new file mode 100644
index 000000000..10a8ab51d
--- /dev/null
+++ b/tests/lexer/tlexer.nim
@@ -0,0 +1,60 @@
+discard """

+  disabled: true

+"""

+

+# We start with a comment

+# This is the same comment

+

+# This is a new one!

+

+import

+  lexbase, os, strutils

+

+type

+  TMyRec {.final.} = object

+    x, y: int     # coordinates

+    c: char       # a character

+    a: int32      # an integer

+

+  PMyRec = ref TMyRec # a reference to `TMyRec`

+

+proc splitText(txt: string): seq[string] # splits a text into several lines

+                                         # the comment continues here

+                                         # this is not easy to parse!

+

+proc anotherSplit(txt: string): seq[string] =

+  # the comment should belong to `anotherSplit`!

+  # another problem: comments are statements!

+

+const

+  x = 0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64 # x ~~ 1.72826e35

+  myNan = 0B01111111100000101100000000001000'f32 # NAN

+  y = """

+    a rather long text.

+    Over many

+    lines.

+  """

+  s = "\xff"

+  a = {0..234}

+  b = {0..high(int)}

+  v = 0'i32

+  z = 6767566'f32

+

+# small test program for lexbase

+

+proc main*(infile: string, a, b: int, someverylongnamewithtype = 0,

+           anotherlongthingie = 3) =

+  var

+    myInt: int = 0

+    s: seq[string]

+  # this should be an error!

+  if initBaseLexer(L, infile, 30): nil

+  else:

+    writeln(stdout, "could not open: " & infile)

+  writeln(stdout, "Success!")

+  call(3, # we use 3

+       12, # we use 12

+       43) # we use 43

+       

+

+main(ParamStr(1), 9, 0)

diff --git a/tests/lexer/tmissingnl.nim b/tests/lexer/tmissingnl.nim
new file mode 100644
index 000000000..33b7debf1
--- /dev/null
+++ b/tests/lexer/tmissingnl.nim
@@ -0,0 +1,10 @@
+discard """
+  file: "tmissingnl.nim"
+  line: 7
+  errormsg: "invalid indentation"
+"""
+
+import strutils var s: seq[int] = @[0, 1, 2, 3, 4, 5, 6]
+
+#s[1..3] = @[]
+
diff --git a/tests/lexer/tstrlits.nim b/tests/lexer/tstrlits.nim
new file mode 100644
index 000000000..1cd43975a
--- /dev/null
+++ b/tests/lexer/tstrlits.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "tstrlits.nim"
+  output: "a\"\"long string\"\"\"\"\"abc\"def"
+"""
+# Test the new different string literals
+
+const
+  tripleEmpty = """"long string"""""""" # "long string """""
+  
+  rawQuote = r"a"""
+  
+  raw = r"abc""def"
+
+stdout.write(rawQuote)
+stdout.write(tripleEmpty)
+stdout.write(raw)
+#OUT a""long string"""""abc"def
+
+
+
diff --git a/tests/lexer/tunderscores.nim b/tests/lexer/tunderscores.nim
new file mode 100644
index 000000000..8075fdae4
--- /dev/null
+++ b/tests/lexer/tunderscores.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "tunderscores.nim"
+  line: 8
+  errormsg: "invalid token: _"
+"""
+# Bug #502670 
+
+var ef_ = 3  #ERROR_MSG invalid token: _
+var a__b = 1
+var c___d = 2
+echo(ab, cd, ef_)
+
+
+
diff --git a/tests/lookups/tkoeniglookup.nim b/tests/lookups/tkoeniglookup.nim
new file mode 100644
index 000000000..6c42798ae
--- /dev/null
+++ b/tests/lookups/tkoeniglookup.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''x: 0 y: 0'''
+"""
+
+proc toString*[T](x: T): string = return $x
+
+
+type
+  TMyObj = object
+    x, y: int
+
+proc `$`*(a: TMyObj): string = 
+  result = "x: " & $a.x & " y: " & $a.y
+
+var a: TMyObj
+echo toString(a)
+
diff --git a/tests/lookups/tredef.nim b/tests/lookups/tredef.nim
new file mode 100644
index 000000000..a1647000c
--- /dev/null
+++ b/tests/lookups/tredef.nim
@@ -0,0 +1,29 @@
+template foo(a: int, b: string) = discard
+foo(1, "test")
+
+proc bar(a: int, b: string) = discard
+bar(1, "test")
+
+template foo(a: int, b: string) = bar(a, b)
+foo(1, "test")
+
+block:
+  proc bar(a: int, b: string) = discard
+  template foo(a: int, b: string) = discard
+  foo(1, "test")
+  bar(1, "test")
+  
+proc baz =
+  proc foo(a: int, b: string) = discard
+  proc foo(b: string) =
+    template bar(a: int, b: string) = discard
+    bar(1, "test")
+    
+  foo("test")
+
+  block:
+    proc foo(b: string) = discard
+    foo("test")
+    foo(1, "test")
+
+baz()
diff --git a/tests/macros/macro_bug.nim b/tests/macros/macro_bug.nim
new file mode 100644
index 000000000..0d0fa76ac
--- /dev/null
+++ b/tests/macros/macro_bug.nim
@@ -0,0 +1,17 @@
+import macros
+
+macro macro_bug*(s: stmt): stmt {.immediate.} =
+  s.expectKind({nnkProcDef, nnkMethodDef})
+
+  var params = s.params
+
+  let genericParams = s[2]
+  result = newNimNode(nnkProcDef).add(
+    s.name, s[1], genericParams, params, pragma(s), newEmptyNode())
+
+  var body = body(s)
+
+  # Fails here.
+  var call = newCall("macro_bug", s.params[1][0])
+  body.insert(0, call)
+  result.add(body)
diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim
new file mode 100644
index 000000000..e1e3b5112
--- /dev/null
+++ b/tests/macros/tbindsym.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''TFoo
+TBar'''
+"""
+
+# bug #1319
+
+import macros
+
+type
+  TTextKind = enum
+    TFoo, TBar
+
+macro test: stmt =
+  var x = @[TFoo, TBar]
+  result = newStmtList()
+  for i in x:
+    result.add newCall(newIdentNode("echo"),
+      case i
+      of TFoo:
+        bindSym("TFoo")
+      of TBar:
+        bindSym("TBar"))
+
+test()
diff --git a/tests/macros/tbugs.nim b/tests/macros/tbugs.nim
new file mode 100644
index 000000000..1ecb0d4cc
--- /dev/null
+++ b/tests/macros/tbugs.nim
@@ -0,0 +1,90 @@
+discard """
+msg: '''a
+s
+d
+f
+TTaa
+TTaa
+TTaa
+TTaa
+true
+true
+nil'''
+
+output: '''test
+2'''
+"""
+
+type
+  Foo = object
+    s: char
+
+iterator test2(f: string): Foo =
+  for i in f:
+    yield Foo(s: i)
+
+macro test(): stmt =
+  for i in test2("asdf"):
+    echo i.s
+
+test()
+
+
+# bug 1297
+
+import macros
+
+type TType = tuple[s: string]
+
+macro echotest(): stmt =
+  var t: TType
+  t.s = ""
+  t.s.add("test")
+  result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
+
+echotest()
+
+# bug #1103
+
+type
+    Td = tuple
+        a:string
+        b:int
+
+proc get_data(d: Td) : string {.compileTime.} =
+    result = d.a # Works if a literal string is used here.
+    # Bugs if line A or B is active. Works with C
+    result &= "aa"          # A
+    #result.add("aa")       # B
+    #result = result & "aa" # C
+
+macro m(s:static[Td]) : stmt =
+    echo get_data(s)
+    echo get_data(s)
+    result = newEmptyNode()
+
+const s=("TT", 3)
+m(s)
+m(s)
+
+# bug #933
+
+proc nilcheck(): NimNode {.compileTime.} =
+  echo(result == nil) # true
+  echo(result.isNil) # true
+  echo(repr(result)) # nil
+
+macro testnilcheck(): stmt =
+  result = newNimNode(nnkStmtList)
+  discard nilcheck()
+
+testnilcheck()
+
+# bug #1323
+
+proc calc(): array[1, int] =
+  result[0].inc()
+  result[0].inc()
+
+const c = calc()
+echo c[0]
diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim
new file mode 100644
index 000000000..d5d9b656c
--- /dev/null
+++ b/tests/macros/tclosuremacro.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''10
+10
+10
+3
+3
+noReturn
+6
+'''
+"""
+
+import future
+
+proc twoParams(x: (int, int) -> int): int =
+  result = x(5, 5)
+
+proc oneParam(x: int -> int): int =
+  x(5)
+
+proc noParams(x: () -> int): int =
+  result = x()
+
+proc noReturn(x: () -> void) =
+  x()
+
+proc doWithOneAndTwo(f: (int, int) -> int): int =
+  f(1,2)
+
+echo twoParams(proc (a, b): auto = a + b)
+echo twoParams((x, y) => x + y)
+
+echo oneParam(x => x+5) 
+
+echo noParams(() => 3)
+
+echo doWithOneAndTwo((x, y) => x + y)
+
+noReturn((() -> void) => echo("noReturn"))
+
+proc pass2(f: (int, int) -> int): (int) -> int =
+  ((x: int) -> int) => f(2, x)
+
+echo pass2((x, y) => x + y)(4)
diff --git a/tests/macros/tdebugstmt.nim b/tests/macros/tdebugstmt.nim
new file mode 100644
index 000000000..00c55ccd8
--- /dev/null
+++ b/tests/macros/tdebugstmt.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''a[0]: 42
+a[1]: 45
+x: some string'''
+"""
+
+import macros
+
+macro debug(n: varargs[expr]): stmt =
+  # `n` is a Nim AST that contains the whole macro invocation
+  # this macro returns a list of statements:
+  result = newNimNode(nnkStmtList, n)
+  # iterate over any argument that is passed to this macro:
+  for i in 0..n.len-1:
+    # add a call to the statement list that writes the expression;
+    # `toStrLit` converts an AST to its string representation:
+    add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+    # add a call to the statement list that writes ": "
+    add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+    # add a call to the statement list that writes the expressions value:
+    add(result, newCall("writeln", newIdentNode("stdout"), n[i]))
+
+var
+  a: array [0..10, int]
+  x = "some string"
+a[0] = 42
+a[1] = 45
+
+debug(a[0], a[1], x)
diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim
new file mode 100644
index 000000000..e3388591a
--- /dev/null
+++ b/tests/macros/tdumpast.nim
@@ -0,0 +1,33 @@
+# Dump the contents of a NimNode
+
+import macros
+
+template plus(a, b: expr): expr {.dirty} =
+  a + b
+
+macro call(e: expr): expr =
+  result = newCall("foo", newStrLitNode("bar"))
+
+macro dumpAST(n: stmt): stmt {.immediate.} =
+  # dump AST as a side-effect and return the inner node
+  let n = callsite()
+  echo n.lispRepr
+  echo n.treeRepr
+
+  var plusAst = getAst(plus(1, 2))
+  echo plusAst.lispRepr
+
+  var callAst = getAst(call())
+  echo callAst.lispRepr
+
+  var e = parseExpr("foo(bar + baz)")
+  echo e.lispRepr
+
+  result = n[1]
+
+dumpAST:
+  proc add(x, y: int): int =
+    return x + y
+
+  proc sub(x, y: int): int = return x - y
+
diff --git a/tests/macros/tdumpast2.nim b/tests/macros/tdumpast2.nim
new file mode 100644
index 000000000..6b694fa77
--- /dev/null
+++ b/tests/macros/tdumpast2.nim
@@ -0,0 +1,36 @@
+# Dump the contents of a NimNode
+
+import macros
+
+proc dumpit(n: NimNode): string {.compileTime.} =
+  if n == nil: return "nil"
+  result = $n.kind
+  add(result, "(")
+  case n.kind
+  of nnkEmpty: discard # same as nil node in this representation
+  of nnkNilLit:                  add(result, "nil")
+  of nnkCharLit..nnkInt64Lit:    add(result, $n.intVal)
+  of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
+  of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
+  of nnkIdent:                   add(result, $n.ident)
+  of nnkSym, nnkNone:            assert false
+  else:
+    add(result, dumpit(n[0]))
+    for j in 1..n.len-1:
+      add(result, ", ")
+      add(result, dumpit(n[j]))
+  add(result, ")")
+
+macro dumpAST(n: stmt): stmt {.immediate.} =
+  # dump AST as a side-effect and return the inner node
+  let n = callsite()
+  echo dumpit(n)
+  result = n[1]
+
+dumpAST:
+  proc add(x, y: int): int =
+    return x + y
+
+  proc sub(x, y: int): int = return x - y
+
+
diff --git a/tests/macros/tdumptree.nim b/tests/macros/tdumptree.nim
new file mode 100644
index 000000000..e5160b7ba
--- /dev/null
+++ b/tests/macros/tdumptree.nim
@@ -0,0 +1,26 @@
+discard """
+msg: '''StmtList
+  VarSection
+    IdentDefs
+      Ident !"x"
+      nil
+      Call
+        DotExpr
+          Ident !"foo"
+          Ident !"create"
+        IntLit 56'''
+"""
+
+# disabled; can't work as the output is done by the compiler
+
+import macros
+
+#emit("type\n  TFoo = object\n    bar: int")
+
+#var f: TFoo
+#f.bar = 5
+#echo(f.bar)
+
+dumpTree:
+  var x = foo.create(56)
+
diff --git a/tests/macros/texprcolonexpr.nim b/tests/macros/texprcolonexpr.nim
new file mode 100644
index 000000000..3b2c86b77
--- /dev/null
+++ b/tests/macros/texprcolonexpr.nim
@@ -0,0 +1,19 @@
+discard """
+  msg: '''
+Infix
+  Ident !"=>"
+  Call
+    Ident !"name"
+    Ident !"a"
+    ExprColonExpr
+      Ident !"b"
+      Ident !"cint"
+  NilLit nil
+'''
+"""
+import macros
+
+macro def(x: stmt): stmt {.immediate.} =
+  echo treeRepr(x)
+
+def name(a, b:cint) => nil
diff --git a/tests/macros/tgensym.nim b/tests/macros/tgensym.nim
new file mode 100644
index 000000000..b3aef0a2c
--- /dev/null
+++ b/tests/macros/tgensym.nim
@@ -0,0 +1,63 @@
+import rawsockets, asyncdispatch, macros
+var p = newDispatcher()
+var sock = newAsyncRawSocket()
+
+proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} =
+  case node.kind
+  of nnkReturnStmt:
+    result = newCall(newIdentNode("complete"), retFutureSym, node[0])
+  else:
+    result = node
+    for i in 0 .. <node.len:
+      result[i] = convertReturns(node[i], retFutureSym)
+
+macro async2(prc: stmt): stmt {.immediate.} =
+  expectKind(prc, nnkProcDef)
+
+  var outerProcBody = newNimNode(nnkStmtList)
+
+  # -> var retFuture = newFuture[T]()
+  var retFutureSym = newIdentNode("retFuture") #genSym(nskVar, "retFuture")
+  outerProcBody.add(
+    newVarStmt(retFutureSym,
+      newCall(
+        newNimNode(nnkBracketExpr).add(
+          newIdentNode("newFuture"),
+          prc[3][0][1])))) # Get type from return type of this proc.
+
+  # -> iterator nameIter(): FutureBase {.closure.} = <proc_body>
+  # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work.
+  var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter")
+  #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter")
+  var procBody = prc[6].convertReturns(retFutureSym)
+
+  var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
+                                procBody, nnkIteratorDef)
+  closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure"))
+  outerProcBody.add(closureIterator)
+
+  # -> var nameIterVar = nameIter
+  # -> var first = nameIterVar()
+  var varNameIterSym = newIdentNode($prc[0].ident & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar")
+  var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym)
+  outerProcBody.add varNameIter
+  var varFirstSym = genSym(nskVar, "first")
+  var varFirst = newVarStmt(varFirstSym, newCall(varNameIterSym))
+  outerProcBody.add varFirst
+
+
+  result = prc
+
+  # Remove the 'closure' pragma.
+  for i in 0 .. <result[4].len:
+    if result[4][i].ident == !"async":
+      result[4].del(i)
+
+  result[6] = outerProcBody
+
+proc readStuff(): Future[string] {.async2.} =
+  var fut = connect(sock, "irc.freenode.org", Port(6667))
+  yield fut
+  var fut2 = recv(sock, 50)
+  yield fut2
+  return fut2.read
diff --git a/tests/macros/tgentemplates.nim b/tests/macros/tgentemplates.nim
new file mode 100644
index 000000000..764b94bc7
--- /dev/null
+++ b/tests/macros/tgentemplates.nim
@@ -0,0 +1,35 @@
+# bug #1140
+
+import parseutils, macros
+
+proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
+    var splitValue: string
+    var read = value.parseUntil(splitValue, '$', index)
+
+    # when false:
+    if false:
+        var identifier: string
+        read = value.parseWhile(identifier, {}, index)
+        node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
+
+    if splitValue.len > 0:
+        node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
+
+proc parse_template(node: NimNode, value: string) {.compiletime.} =
+    var index = 0
+    while index < value.len and
+        parse_until_symbol(node, value, index): discard
+
+macro tmpli*(body: expr): stmt =
+    result = newStmtList()
+    result.add parseExpr("result = \"\"")
+    result.parse_template body[1].strVal
+
+
+proc actual: string = tmpli html"""
+    <p>Test!</p>
+    """
+
+proc another: string = tmpli html"""
+    <p>what</p>
+    """
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
new file mode 100644
index 000000000..0eab6c0a0
--- /dev/null
+++ b/tests/macros/tgettype.nim
@@ -0,0 +1,20 @@
+discard """
+msg: '''ObjectTy(Sym(Model), RecList(Sym(name), Sym(password)))
+BracketExpr(Sym(typeDesc), Sym(User))'''
+"""
+import strutils, macros
+
+type
+  Model = object of RootObj
+  User = object of Model
+    name : string
+    password : string
+
+macro testUser: expr =
+  return newLit(User.getType.lispRepr)
+
+macro testGeneric(T: typedesc[Model]): expr =
+  return newLit(T.getType.lispRepr)
+
+echo testUser
+echo User.testGeneric
diff --git a/tests/macros/tidgen.nim b/tests/macros/tidgen.nim
new file mode 100644
index 000000000..2fe9e0f82
--- /dev/null
+++ b/tests/macros/tidgen.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "3 4"
+"""
+
+import macros
+
+# Test compile-time state in same module
+
+var gid {.compileTime.} = 3
+
+macro genId(): expr =
+  result = newIntLitNode(gid)
+  inc gid
+
+proc Id1(): int {.compileTime.} = return genId()
+proc Id2(): int {.compileTime.} = return genId()
+
+echo Id1(), " ", Id2()
+
diff --git a/tests/macros/tlexerex.nim b/tests/macros/tlexerex.nim
new file mode 100644
index 000000000..d348a4bcc
--- /dev/null
+++ b/tests/macros/tlexerex.nim
@@ -0,0 +1,16 @@
+
+import macros
+
+macro match*(s: cstring|string; pos: int; sections: untyped): untyped =
+  for sec in sections.children:
+    expectKind sec, nnkOfBranch
+    expectLen sec, 2
+  result = newStmtList()
+
+when isMainModule:
+  var input = "the input"
+  var pos = 0
+  match input, pos:
+  of r"[a-zA-Z_]\w+": echo "an identifier"
+  of r"\d+": echo "an integer"
+  of r".": echo "something else"
diff --git a/tests/macros/tmacro1.nim b/tests/macros/tmacro1.nim
new file mode 100644
index 000000000..2dd5c31df
--- /dev/null
+++ b/tests/macros/tmacro1.nim
@@ -0,0 +1,23 @@
+import  macros
+
+from uri import `/`
+
+macro test*(a: stmt): stmt {.immediate.} =
+  var nodes: tuple[a, b: int]
+  nodes.a = 4
+  nodes[1] = 45
+
+  type
+    TTypeEx = object
+      x, y: int
+      case b: bool
+      of false: nil
+      of true: z: float
+
+  var t: TTypeEx
+  t.b = true
+  t.z = 4.5
+
+test:
+  "hi"
+
diff --git a/tests/macros/tmacro2.nim b/tests/macros/tmacro2.nim
new file mode 100644
index 000000000..8515322d5
--- /dev/null
+++ b/tests/macros/tmacro2.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "ta-da Your value sir: 'HE!!!!o Wor!!d'"
+"""
+
+import macros, strutils
+
+proc testBlock(): string {.compileTime.} = 
+  block myBlock:
+    while true:
+      echo "inner block"
+      break myBlock
+    echo "outer block"
+  result = "ta-da"
+
+macro mac(n: expr): expr =
+  let n = callsite()
+  expectKind(n, nnkCall)
+  expectLen(n, 2)
+  expectKind(n[1], nnkStrLit)
+  var s: string = n[1].strVal
+  s = s.replace("l", "!!")
+  result = newStrLitNode("Your value sir: '$#'" % [s])
+
+const s = testBlock() 
+const t = mac("HEllo World")
+echo s, " ", t
+
+
diff --git a/tests/macros/tmacro3.nim b/tests/macros/tmacro3.nim
new file mode 100644
index 000000000..d7421ff7f
--- /dev/null
+++ b/tests/macros/tmacro3.nim
@@ -0,0 +1,31 @@
+discard """
+  output: ""
+"""
+
+import  macros
+
+type
+    TA = tuple[a: int]
+    PA = ref TA
+
+macro test*(a: stmt): stmt {.immediate.} =
+  var val: PA
+  new(val)
+  val.a = 4
+
+test:
+  "hi"
+
+macro test2*(a: stmt): stmt {.immediate.} =
+  proc testproc(recurse: int) =
+    echo "Thats weird"
+    var o : NimNode = nil
+    echo "  no its not!"
+    o = newNimNode(nnkNone)
+    if recurse > 0:
+      testproc(recurse - 1)
+  testproc(5)
+
+test2:
+  "hi"
+
diff --git a/tests/macros/tmacro4.nim b/tests/macros/tmacro4.nim
new file mode 100644
index 000000000..a56369369
--- /dev/null
+++ b/tests/macros/tmacro4.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "after"
+"""
+
+import
+  macros, strutils
+
+macro test_macro*(n: stmt): stmt {.immediate.} =
+  result = newNimNode(nnkStmtList)
+  var ass : NimNode = newNimNode(nnkAsgn)
+  add(ass, newIdentNode("str"))
+  add(ass, newStrLitNode("after"))
+  add(result, ass)
+when isMainModule:
+  var str: string = "before"
+  test_macro(str):
+    var i : integer = 123
+  echo str
+
diff --git a/tests/macros/tmacro5.nim b/tests/macros/tmacro5.nim
new file mode 100644
index 000000000..d7a4fe8c8
--- /dev/null
+++ b/tests/macros/tmacro5.nim
@@ -0,0 +1,59 @@
+import macros,json
+
+var decls{.compileTime.}: seq[NimNode] = @[]
+var impls{.compileTime.}: seq[NimNode] = @[]
+
+macro importImpl_forward(name, returns): stmt {.immediate.} =
+  result = newNimNode(nnkEmpty)
+  var func_name = newNimNode(nnkAccQuoted)
+  func_name.add newIdentNode("import")
+  func_name.add name
+
+  var res = newNimNode(nnkProcDef)
+  res.add newNimNode(nnkPostfix)
+  res[0].add newIdentNode("*")
+  res[0].add func_name
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkFormalParams)
+  res[3].add returns
+  var p1 = newNimNode(nnkIdentDefs)
+  p1.add newIdentNode("dat")
+  p1.add newIdentNOde("PJsonNode")
+  p1.add newNimNode(nnkEmpty)
+  res[3].add p1
+  var p2 = newNimNode(nnkIdentDefs)
+  p2.add newIdentNode("errors")
+  p2.add newNimNode(nnkVarTy)
+  p2.add newNimNode(nnkEmpty)
+  p2[1].add newNimNode(nnkBracketExpr)
+  p2[1][0].add newIdentNode("seq")
+  p2[1][0].add newIdentNode("string")
+  res[3].add p2
+
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+
+  decls.add res
+  echo(repr(res))
+
+macro importImpl(name, returns: expr, body: stmt): stmt {.immediate.} =
+  #var res = getAST(importImpl_forward(name, returns))
+  discard getAST(importImpl_forward(name, returns))
+  var res = copyNimTree(decls[decls.high])
+  res[6] = body
+  echo repr(res)
+  impls.add res
+
+macro okayy:stmt =
+  result = newNimNode(nnkStmtList)
+  for node in decls: result.add node
+  for node in impls: result.add node
+
+importImpl(Item, int):
+  echo 42
+importImpl(Foo, int16):
+  echo 77
+
+okayy
diff --git a/tests/macros/tmacro_in_template.nim b/tests/macros/tmacro_in_template.nim
new file mode 100644
index 000000000..8f7753cea
--- /dev/null
+++ b/tests/macros/tmacro_in_template.nim
@@ -0,0 +1,10 @@
+
+# bug #1944
+import macros
+
+template t(e: expr): stmt =
+  macro m(eNode: expr): stmt =
+    echo eNode.treeRepr
+  m e
+
+t 5
diff --git a/tests/macros/tmacroaspragma.nim b/tests/macros/tmacroaspragma.nim
new file mode 100644
index 000000000..0e5c352b3
--- /dev/null
+++ b/tests/macros/tmacroaspragma.nim
@@ -0,0 +1,8 @@
+import macros
+
+macro foo(x: stmt): stmt =
+  echo treerepr(callsite())
+  result = newNimNode(nnkStmtList)
+
+proc zoo() {.foo.} = echo "hi"
+
diff --git a/tests/macros/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
new file mode 100644
index 000000000..b886f4fa5
--- /dev/null
+++ b/tests/macros/tmacrogenerics.nim
@@ -0,0 +1,37 @@
+discard """
+  file: "tmacrogenerics.nim"
+  msg: '''
+instantiation 1 with typedesc and typedesc
+counter: 1
+'''
+  output: "int\nfloat\nint\nstring"
+"""
+
+import typetraits, macros
+
+var counter {.compileTime.} = 0
+
+macro makeBar(A, B: typedesc): typedesc =
+  inc counter
+  echo "instantiation ", counter, " with ", A.name, " and ", B.name
+  result = A
+
+type 
+  Bar[T, U] = makeBar(T, U)
+
+var bb1: Bar[int, float]
+var bb2: Bar[float, string]
+var bb3: Bar[int, float]
+var bb4: Bar[string, string]
+
+proc match(a: int)    = echo "int"
+proc match(a: string) = echo "string"
+proc match(a: float)  = echo "float"
+
+match(bb1)
+match(bb2)
+match(bb3)
+match(bb4)
+
+static:
+  echo "counter: ", counter
diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim
new file mode 100644
index 000000000..1a1073a44
--- /dev/null
+++ b/tests/macros/tmacros1.nim
@@ -0,0 +1,31 @@
+discard """
+  output: "Got: 'nnkCall' hi"
+"""
+
+import
+  macros, strutils
+
+macro outterMacro*(n: stmt): stmt {.immediate.} =
+  let n = callsite()
+  var j : string = "hi"
+  proc innerProc(i: int): string =
+    echo "Using arg ! " & n.repr
+    result = "Got: '" & $n.kind & "' " & $j
+  var callNode = n[0]
+  expectKind(n, TNimrodNodeKind.nnkCall)
+  if n.len != 3 or n[1].kind != TNimrodNodeKind.nnkIdent:
+    error("Macro " & callNode.repr &
+      " requires the ident passed as parameter (eg: " & callNode.repr &
+      "(the_name_you_want)): statements.")
+  result = newNimNode(TNimrodNodeKind.nnkStmtList)
+  var ass : NimNode = newNimNode(nnkAsgn)
+  ass.add(newIdentNode(n[1].ident))
+  ass.add(newStrLitNode(innerProc(4)))
+  result.add(ass)
+
+var str: string
+outterMacro(str):
+  "hellow"
+echo str
+
+
diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim
new file mode 100644
index 000000000..d9c70197d
--- /dev/null
+++ b/tests/macros/tmacrostmt.nim
@@ -0,0 +1,26 @@
+import macros
+macro case_token(n: stmt): stmt {.immediate.} =
+  # creates a lexical analyzer from regular expressions
+  # ... (implementation is an exercise for the reader :-)
+  nil
+
+case_token: # this colon tells the parser it is a macro statement
+of r"[A-Za-z_]+[A-Za-z_0-9]*":
+  return tkIdentifier
+of r"0-9+":
+  return tkInteger
+of r"[\+\-\*\?]+":
+  return tkOperator
+else:
+  return tkUnknown
+  
+case_token: inc i
+
+#bug #488
+
+macro foo: stmt =
+  var exp = newCall("whatwhat", newIntLitNode(1))
+  if compiles(getAst(exp)): return exp
+  else: echo "Does not compute!"
+
+foo()
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
new file mode 100644
index 000000000..991668930
--- /dev/null
+++ b/tests/macros/tmacrotypes.nim
@@ -0,0 +1,16 @@
+discard """
+  nimout: '''void
+int'''
+"""
+
+import macros
+
+macro checkType(ex: stmt; expected: expr): stmt =
+  var t = ex.getType()
+  echo t
+
+proc voidProc = echo "hello"
+proc intProc(a: int, b: float): int = 10
+
+checkType(voidProc(), "void")
+checkType(intProc(10, 20.0), "int")
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
new file mode 100644
index 000000000..e5aed3172
--- /dev/null
+++ b/tests/macros/tmemit.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''HELLO WORLD
+c_func'''
+"""
+
+import macros, strutils
+
+emit("echo " & '"' & "hello world".toUpper & '"')
+
+# bug #1025
+
+macro foo(icname): stmt =
+  let ic = newStrLitNode($icname)
+  result = quote do:
+    proc x* =
+      proc private {.exportc: `ic`.} = discard
+      echo `ic`
+      private()
+
+foo(c_func)
+x()
diff --git a/tests/macros/tnimnode_for_runtime.nim b/tests/macros/tnimnode_for_runtime.nim
new file mode 100644
index 000000000..0520cd0dd
--- /dev/null
+++ b/tests/macros/tnimnode_for_runtime.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "bla"
+"""
+
+import macros
+proc makeMacro: NimNode =
+  result = nil
+
+var p = makeMacro()
+
+echo "bla"
+
diff --git a/tests/macros/tprintf.nim b/tests/macros/tprintf.nim
new file mode 100644
index 000000000..c8fb51cdc
--- /dev/null
+++ b/tests/macros/tprintf.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tprintf.nim"
+  output: "Andreas Rumpf"
+"""
+# Test a printf proc

+

+proc printf(file: TFile, args: openarray[string]) =

+  var i = 0

+  while i < args.len:

+    write(file, args[i])

+    inc(i)

+

+printf(stdout, ["Andreas ", "Rumpf\n"])

+#OUT Andreas Rumpf

+
+
diff --git a/tests/macros/tquotewords.nim b/tests/macros/tquotewords.nim
new file mode 100644
index 000000000..76b8d8af7
--- /dev/null
+++ b/tests/macros/tquotewords.nim
@@ -0,0 +1,26 @@
+discard """
+  file: "tquotewords.nim"
+  output: "thisanexample"
+"""
+# Test an idea I recently had:
+
+import macros
+
+macro quoteWords(n: expr): expr {.immediate.} = 
+  let n = callsite()
+  result = newNimNode(nnkBracket, n)
+  for i in 1..n.len-1:
+    expectKind(n[i], nnkIdent)
+    result.add(toStrLit(n[i]))
+  
+const
+  myWordList = quoteWords(this, an, example)
+
+var s = ""
+for w in items(myWordList):
+  s.add(w)
+
+echo s #OUT thisanexample
+
+
+
diff --git a/tests/macros/trecmacro.nim b/tests/macros/trecmacro.nim
new file mode 100644
index 000000000..28b6db530
--- /dev/null
+++ b/tests/macros/trecmacro.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "trecmacro.nim"
+  line: 8
+  errormsg: "recursive dependency: 'dump'"
+"""
+
+macro dump(n: stmt): stmt =
+  dump(n)
+  if kind(n) == nnkNone:
+    nil
+  else:
+    hint($kind(n))
+    for i in countUp(0, len(n)-1):
+      nil
diff --git a/tests/macros/treturnsempty.nim b/tests/macros/treturnsempty.nim
new file mode 100644
index 000000000..7af26a747
--- /dev/null
+++ b/tests/macros/treturnsempty.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch"
+  line: 11
+"""
+# bug #2372
+macro foo(dummy: int): stmt =
+  discard
+
+proc takeStr(s: string) = echo s
+
+takeStr foo(12)
+
diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim
new file mode 100644
index 000000000..ed5d5c6d8
--- /dev/null
+++ b/tests/macros/tsame_name_497.nim
@@ -0,0 +1,9 @@
+discard """
+  disabled: true
+"""
+
+import macro_bug
+
+type TObj = object
+
+proc f(o: TObj) {.macro_bug.} = discard
diff --git a/tests/macros/tstringinterp.nim b/tests/macros/tstringinterp.nim
new file mode 100644
index 000000000..bc79cdaba
--- /dev/null
+++ b/tests/macros/tstringinterp.nim
@@ -0,0 +1,74 @@
+discard """
+  file: "tstringinterp.nim"
+  output: "Hello Alice, 64 | Hello Bob, 10$"
+"""
+
+import macros, parseutils, strutils
+
+proc concat(strings: varargs[string]): string =
+  result = newString(0)
+  for s in items(strings): result.add(s)
+
+template processInterpolations(e: expr) =
+  var s = e[1].strVal
+  for f in interpolatedFragments(s):
+    case f.kind
+    of ikStr:         addString(f.value)
+    of ikDollar:      addDollar()
+    of ikVar, ikExpr: addExpr(newCall("$", parseExpr(f.value)))
+
+macro formatStyleInterpolation(e: expr): expr =
+  let e = callsite()
+  var
+    formatString = ""
+    arrayNode = newNimNode(nnkBracket)
+    idx = 1
+
+  proc addString(s: string) =
+    formatString.add(s)
+
+  proc addExpr(e: NimNode) =
+    arrayNode.add(e)
+    formatString.add("$" & $(idx))
+    inc idx
+
+  proc addDollar() =
+    formatString.add("$$")
+
+  processInterpolations(e)
+
+  result = parseExpr("\"x\" % [y]")
+  result[1].strVal = formatString
+  result[2] = arrayNode
+
+macro concatStyleInterpolation(e: expr): expr =
+  let e = callsite()
+  var args: seq[NimNode]
+  newSeq(args, 0)
+
+  proc addString(s: string)    = args.add(newStrLitNode(s))
+  proc addExpr(e: NimNode) = args.add(e)
+  proc addDollar()             = args.add(newStrLitNode"$")
+
+  processInterpolations(e)
+
+  result = newCall("concat", args)
+
+###
+
+proc sum(a, b, c: int): int =
+  return (a + b + c)
+
+var
+  alice = "Alice"
+  bob = "Bob"
+  a = 10
+  b = 20
+  c = 34
+
+var
+  s1 = concatStyleInterpolation"Hello ${alice}, ${sum(a, b, c)}"
+  s2 = formatStyleInterpolation"Hello ${bob}, ${sum(alice.len, bob.len, 2)}$$"
+
+write(stdout, s1 & " | " & s2)
+
diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim
new file mode 100644
index 000000000..c7bbc8e5b
--- /dev/null
+++ b/tests/macros/ttryparseexpr.nim
@@ -0,0 +1,20 @@
+discard """
+  outputsub: '''Error: invalid indentation 45'''
+"""
+
+# feature request #1473
+import macros
+
+macro test(text: string): expr =
+  try:
+    result = parseExpr(text.strVal)
+  except ValueError:
+    result = newLit getCurrentExceptionMsg()
+
+const
+  valid = 45
+  a = test("foo&&")
+  b = test("valid")
+  c = test("\"") # bug #2504
+
+echo a, " ", b
diff --git a/tests/macros/tvarnimnode.nim b/tests/macros/tvarnimnode.nim
new file mode 100644
index 000000000..ab0f66caa
--- /dev/null
+++ b/tests/macros/tvarnimnode.nim
@@ -0,0 +1,19 @@
+discard """
+  output: 10
+"""
+
+#bug #926
+
+import macros
+
+proc test(f: var NimNode) {.compileTime.} =
+  f = newNimNode(nnkStmtList)
+  f.add newCall(newIdentNode("echo"), newLit(10))
+
+macro blah(prc: stmt): stmt =
+  result = prc
+
+  test(result)
+
+proc test() {.blah.} =
+  echo 5
diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim
new file mode 100644
index 000000000..3e3b9c0e6
--- /dev/null
+++ b/tests/macros/tvtable.nim
@@ -0,0 +1,74 @@
+discard """
+  output: '''
+OBJ 1 foo
+10
+OBJ 1 bar
+OBJ 2 foo
+5
+OBJ 2 bar
+'''
+"""
+
+type
+  # these are the signatures of the virtual procs for each type
+  fooProc[T] = proc (o: var T): int {.nimcall.}
+  barProc[T] = proc (o: var T) {.nimcall.}
+
+  # an untyped table to store the proc pointers
+  # it's also possible to use a strongly typed tuple here
+  VTable = array[0..1, pointer]
+  
+  TBase = object {.inheritable.}
+    vtbl: ptr VTable
+
+  TUserObject1 = object of TBase
+    x: int
+
+  TUserObject2 = object of TBase
+    y: int
+
+proc foo(o: var TUserObject1): int =
+  echo "OBJ 1 foo"
+  return 10
+
+proc bar(o: var TUserObject1) =
+  echo "OBJ 1 bar"
+
+proc foo(o: var TUserObject2): int =
+  echo "OBJ 2 foo"
+  return 5
+
+proc bar(o: var TUserObject2) =
+  echo "OBJ 2 bar"
+
+proc getVTable(T: typedesc): ptr VTable =
+  # pay attention to what's going on here
+  # this will initialize the vtable for each type at program start-up
+  #
+  # fooProc[T](foo) is a type coercion - it looks for a proc named foo
+  # matching the signature fooProc[T] (e.g. proc (o: var TUserObject1): int)
+  var vtbl {.global.} = [
+    cast[pointer](fooProc[T](foo)),
+    cast[pointer](barProc[T](bar))
+  ]
+
+  return vtbl.addr
+
+proc create(T: typedesc): T =
+  result.vtbl = getVTable(T)
+
+proc baseFoo(o: var TBase): int =
+  return cast[fooProc[TBase]](o.vtbl[0]) (o)
+
+proc baseBar(o: var TBase) =
+  cast[barProc[TBase]](o.vtbl[1]) (o)
+
+var a = TUserObject1.create
+var b = TUserObject2.create
+
+echo a.baseFoo
+a.baseBar
+
+echo b.baseFoo
+b.baseBar
+
diff --git a/tests/macros/typesapi.nim b/tests/macros/typesapi.nim
new file mode 100644
index 000000000..670b39c9e
--- /dev/null
+++ b/tests/macros/typesapi.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout: '''proc (x: int): string => typeDesc[proc[string, int]]
+proc (x: int): void => typeDesc[proc[void, int]]
+proc (x: int) => typeDesc[proc[void, int]]'''
+"""
+
+#2211
+
+import macros
+
+macro showType(t:stmt): stmt =
+  let ty = t.getType
+  echo t.repr, " => ", ty.repr
+
+showType(proc(x:int): string)
+showType(proc(x:int): void)
+showType(proc(x:int))
diff --git a/tests/macros/typesapi2.nim b/tests/macros/typesapi2.nim
new file mode 100644
index 000000000..2e59d2154
--- /dev/null
+++ b/tests/macros/typesapi2.nim
@@ -0,0 +1,49 @@
+# tests to see if a symbol returned from macros.getType() can
+# be used as a type
+import macros
+
+macro testTypesym (t:stmt): expr =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    assert ty[0].kind == nnkSym
+    result = ty[0]
+    return
+
+type TestFN = proc(a,b:int):int
+var iii: testTypesym(TestFN)
+static: assert iii is TestFN
+
+proc foo11 : testTypesym(void) =
+    echo "HI!"
+static: assert foo11 is (proc():void {.nimcall.})
+
+var sss: testTypesym(seq[int])
+static: assert sss is seq[int]
+# very nice :>
+
+static: assert array[2,int] is testTypesym(array[2,int])
+static: assert(ref int is testTypesym(ref int))
+static: assert(void is testTypesym(void))
+
+
+macro tts2 (t:stmt, idx:int): expr =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    return ty[idx.intval.int]
+type TestFN2 = proc(a:int,b:float):string
+static:
+    assert(tts2(TestFN2, 0) is TestFN2)
+    assert(tts2(TestFN2, 1) is string)
+    assert(tts2(TestFN2, 2) is int)
+    assert(tts2(TestFN2, 3) is float)
+
diff --git a/tests/magics/tlowhigh.nim b/tests/magics/tlowhigh.nim
new file mode 100644
index 000000000..d1cbd3272
--- /dev/null
+++ b/tests/magics/tlowhigh.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tlowhigh.nim"
+  output: "10"
+"""
+# Test the magic low() and high() procs

+

+type

+  myEnum = enum e1, e2, e3, e4, e5

+

+var

+  a: array [myEnum, int]

+

+for i in low(a) .. high(a):

+  a[i] = 0

+

+proc sum(a: openarray[int]): int =

+  result = 0

+  for i in low(a)..high(a):

+    inc(result, a[i])

+

+write(stdout, sum([1, 2, 3, 4]))

+#OUT 10

+
+
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
new file mode 100644
index 000000000..060610ae0
--- /dev/null
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -0,0 +1,494 @@
+## Command line parsing module for Nimrod.
+##
+## `Nim <http://nim-lang.org>`_ provides the `parseopt module
+## <http://nim-lang.org/parseopt.html>`_ to parse options from the
+## commandline. This module tries to provide functionality to prevent you from
+## writing commandline parsing and let you concentrate on providing the best
+## possible experience for your users.
+##
+## Source code for this module can be found at
+## https://github.com/gradha/argument_parser.
+
+import os, strutils, tables, math, parseutils, sequtils, sets, algorithm,
+  unicode
+
+const
+  VERSION_STR* = "0.1.2" ## Module version as a string.
+  VERSION_INT* = (major: 0, minor: 1, maintenance: 2) ## \
+  ## Module version as an integer tuple.
+  ##
+  ## Major versions changes mean a break in API backwards compatibility, either
+  ## through removal of symbols or modification of their purpose.
+  ##
+  ## Minor version changes can add procs (and maybe default parameters). Minor
+  ## odd versions are development/git/unstable versions. Minor even versions
+  ## are public stable releases.
+  ##
+  ## Maintenance version changes mean bugfixes or non API changes.
+
+# - Types
+
+type
+  Tparam_kind* = enum ## Different types of results for parameter parsing.
+    PK_EMPTY, PK_INT, PK_FLOAT, PK_STRING, PK_BOOL,
+    PK_BIGGEST_INT, PK_BIGGEST_FLOAT, PK_HELP
+
+  Tparameter_callback* =
+    proc (parameter: string; value: var Tparsed_parameter): string ## \
+    ## Prototype of parameter callbacks
+    ##
+    ## A parameter callback is just a custom proc you provide which is invoked
+    ## after a parameter is parsed passing the basic type validation. The
+    ## `parameter` parameter is the string which triggered the option. The
+    ## `value` parameter contains the string passed by the user already parsed
+    ## into the basic type you specified for it.
+    ##
+    ## The callback proc has modification access to the Tparsed_parameter
+    ## `value` parameter that will be put into Tcommandline_results: you can
+    ## read it and also modify it, maybe changing its type. In fact, if you
+    ## need special parsing, most likely you will end up specifying PK_STRING
+    ## in the parameter input specification so that the parse() proc doesn't
+    ## *mangle* the string before you can process it yourself.
+    ##
+    ## If the callback decides to abort the validation of the parameter, it has
+    ## to put into result a non zero length string with a message for the user
+    ## explaining why the validation failed, and maybe offer a hint as to what
+    ## can be done to pass validation.
+
+  Tparameter_specification* = object ## \
+    ## Holds the expectations of a parameter.
+    ##
+    ## You create these objects and feed them to the parse() proc, which then
+    ## uses them to detect parameters and turn them into something uself.
+    names*: seq[string]  ## List of possible parameters to catch for this.
+    consumes*: Tparam_kind ## Expected type of the parameter (empty for none)
+    custom_validator*: Tparameter_callback  ## Optional custom callback
+                                            ## to run after type conversion.
+    help_text*: string    ## Help for this group of parameters.
+
+  Tparsed_parameter* = object ## \
+    ## Contains the parsed value from the user.
+    ##
+    ## This implements an object variant through the kind field. You can 'case'
+    ## this field to write a generic proc to deal with parsed parameters, but
+    ## nothing prevents you from accessing directly the type of field you want
+    ## if you expect only one kind.
+    case kind*: Tparam_kind
+    of PK_EMPTY: nil
+    of PK_INT: int_val*: int
+    of PK_BIGGEST_INT: big_int_val*: BiggestInt
+    of PK_FLOAT: float_val*: float
+    of PK_BIGGEST_FLOAT: big_float_val*: BiggestFloat
+    of PK_STRING: str_val*: string
+    of PK_BOOL: bool_val*: bool
+    of PK_HELP: nil
+
+  Tcommandline_results* = object of RootObj ## \
+    ## Contains the results of the parsing.
+    ##
+    ## Usually this is the result of the parse() call, but you can inherit from
+    ## it to add your own fields for convenience.
+    ##
+    ## Note that you always have to access the ``options`` ordered table with
+    ## the first variant of a parameter name. For instance, if you have an
+    ## option specified like ``@["-s", "--silent"]`` and the user types
+    ## ``--silent`` at the commandline, you have to use
+    ## ``options.hasKey("-s")`` to test for it. This standarizes access through
+    ## the first name variant for all options to avoid you repeating the test
+    ## with different keys.
+    positional_parameters*: seq[Tparsed_parameter]
+    options*: OrderedTable[string, Tparsed_parameter]
+
+
+# - Tparam_kind procs
+
+proc `$`*(value: Tparam_kind): string {.procvar.} =
+  ## Stringifies the type, used to generate help texts.
+  case value:
+  of PK_EMPTY: result = ""
+  of PK_INT: result = "INT"
+  of PK_BIGGEST_INT: result = "BIG_INT"
+  of PK_FLOAT: result = "FLOAT"
+  of PK_BIGGEST_FLOAT: result = "BIG_FLOAG"
+  of PK_STRING: result = "STRING"
+  of PK_BOOL: result = "BOOL"
+  of PK_HELP: result = ""
+
+# - Tparameter_specification procs
+
+proc init*(param: var Tparameter_specification, consumes = PK_EMPTY,
+    custom_validator: Tparameter_callback = nil, help_text = "",
+    names: varargs[string]) =
+  ## Initialization helper with default parameters.
+  ##
+  ## You can decide to miss some if you like the defaults, reducing code. You
+  ## can also use new_parameter_specification() for single assignment
+  ## variables.
+  param.names = @names
+  param.consumes = consumes
+  param.custom_validator = custom_validator
+  param.help_text = help_text
+
+proc new_parameter_specification*(consumes = PK_EMPTY,
+    custom_validator: Tparameter_callback = nil, help_text = "",
+    names: varargs[string]): Tparameter_specification =
+  ## Initialization helper for single assignment variables.
+  result.init(consumes, custom_validator, help_text, names)
+
+# - Tparsed_parameter procs
+
+proc `$`*(data: Tparsed_parameter): string {.procvar.} =
+  ## Stringifies the value, mostly for debug purposes.
+  ##
+  ## The proc will display the value followed by non string type in brackets.
+  ## The non string types would be PK_INT (i), PK_BIGGEST_INT (I), PK_FLOAT
+  ## (f), PK_BIGGEST_FLOAT (F), PK_BOOL (b). The string type would be enclosed
+  ## inside quotes. PK_EMPTY produces the word `nil`, and PK_HELP produces the
+  ## world `help`.
+  case data.kind:
+  of PK_EMPTY: result = "nil"
+  of PK_INT: result = "$1(i)" % $data.int_val
+  of PK_BIGGEST_INT: result = "$1(I)" % $data.big_int_val
+  of PK_FLOAT: result = "$1(f)" % $data.float_val
+  of PK_BIGGEST_FLOAT: result = "$1(F)" % $data.big_float_val
+  of PK_STRING: result = "\"" & $data.str_val & "\""
+  of PK_BOOL: result = "$1(b)" % $data.bool_val
+  of PK_HELP: result = "help"
+
+
+template new_parsed_parameter*(tkind: Tparam_kind, expr): Tparsed_parameter =
+  ## Handy compile time template to build Tparsed_parameter object variants.
+  ##
+  ## The problem with object variants is that you first have to initialise them
+  ## to a kind, then assign values to the correct variable, and it is a little
+  ## bit annoying.
+  ##
+  ## Through this template you specify as the first parameter the kind of the
+  ## Tparsed_parameter you want to build, and directly the value it will be
+  ## initialised with. The template figures out at compile time what field to
+  ## assign the variable to, and thus you reduce code clutter and may use this
+  ## to initialise single assignments variables in `let` blocks. Example:
+  ##
+  ## .. code-block:: nim
+  ##   let
+  ##     parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41)
+  ##     parsed_param2 = new_parsed_parameter(PK_BIGGEST_INT, 2358123 * 23123)
+  ##     # The following line doesn't compile due to
+  ##     # type mismatch: got (string) but expected 'int'
+  ##     #parsed_param3 = new_parsed_parameter(PK_INT, "231")
+  var result {.gensym.}: Tparsed_parameter
+  result.kind = tkind
+  when tkind == PK_EMPTY: discard
+  elif tkind == PK_INT: result.int_val = expr
+  elif tkind == PK_BIGGEST_INT: result.big_int_val = expr
+  elif tkind == PK_FLOAT: result.float_val = expr
+  elif tkind == PK_BIGGEST_FLOAT: result.big_float_val = expr
+  elif tkind == PK_STRING: result.str_val = expr
+  elif tkind == PK_BOOL: result.bool_val = expr
+  elif tkind == PK_HELP: discard
+  else: {.error: "unknown kind".}
+  result
+
+# - Tcommandline_results procs
+
+proc init*(param: var Tcommandline_results;
+    positional_parameters: seq[Tparsed_parameter] = @[];
+    options: OrderedTable[string, Tparsed_parameter] =
+      initOrderedTable[string, Tparsed_parameter](4)) =
+  ## Initialization helper with default parameters.
+  param.positional_parameters = positional_parameters
+  param.options = options
+
+proc `$`*(data: Tcommandline_results): string =
+  ## Stringifies a Tcommandline_results structure for debug output
+  var dict: seq[string] = @[]
+  for key, value in data.options:
+    dict.add("$1: $2" % [escape(key), $value])
+  result = "Tcommandline_result{positional_parameters:[$1], options:{$2}}" % [
+    join(map(data.positional_parameters, `$`), ", "), join(dict, ", ")]
+
+# - Parse code
+
+template raise_or_quit(exception, message: expr): stmt {.immediate.} =
+  ## Avoids repeating if check based on the default quit_on_failure variable.
+  ##
+  ## As a special case, if message has a zero length the call to quit won't
+  ## generate any messages or errors (used by the mechanism to echo help to the
+  ## user).
+  if quit_on_failure:
+    if len(message) > 0:
+      quit(message)
+    else:
+      quit()
+  else:
+    raise newException(exception, message)
+
+template run_custom_proc(parsed_parameter: Tparsed_parameter,
+    custom_validator: Tparameter_callback,
+    parameter: TaintedString) =
+  ## Runs the custom validator if it is not nil.
+  ##
+  ## Pass in the string of the parameter triggering the call. If the
+  if not custom_validator.isNil:
+    except:
+      raise_or_quit(ValueError, ("Couldn't run custom proc for " &
+        "parameter $1:\n$2" % [escape(parameter),
+        getCurrentExceptionMsg()]))
+    let message = custom_validator(parameter, parsed_parameter)
+    if not message.isNil and message.len > 0:
+      raise_or_quit(ValueError, ("Failed to validate value for " &
+        "parameter $1:\n$2" % [escape(parameter), message]))
+
+
+proc parse_parameter(quit_on_failure: bool, param, value: string,
+    param_kind: Tparam_kind): Tparsed_parameter =
+  ## Tries to parse a text according to the specified type.
+  ##
+  ## Pass the parameter string which requires a value and the text the user
+  ## passed in for it. It will be parsed according to the param_kind. This proc
+  ## will raise (ValueError, EOverflow) if something can't be parsed.
+  result.kind = param_kind
+  case param_kind:
+  of PK_INT:
+    try: result.int_val = value.parseInt
+    except OverflowError:
+      raise_or_quit(OverflowError, ("parameter $1 requires an " &
+        "integer, but $2 is too large to fit into one") % [param,
+        escape(value)])
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires an " &
+        "integer, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_STRING:
+    result.str_val = value
+  of PK_FLOAT:
+    try: result.float_val = value.parseFloat
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires a " &
+        "float, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_BOOL:
+    try: result.bool_val = value.parseBool
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires a " &
+        "boolean, but $2 can't be parsed into one. Valid values are: " &
+        "y, yes, true, 1, on, n, no, false, 0, off") % [param, escape(value)])
+  of PK_BIGGEST_INT:
+    try:
+      let parsed_len = parseBiggestInt(value, result.big_int_val)
+      if value.len != parsed_len or parsed_len < 1:
+        raise_or_quit(ValueError, ("parameter $1 requires an " &
+          "integer, but $2 can't be parsed completely into one") % [
+          param, escape(value)])
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires an " &
+        "integer, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_BIGGEST_FLOAT:
+    try:
+      let parsed_len = parseBiggestFloat(value, result.big_float_val)
+      if value.len != parsed_len or parsed_len < 1:
+        raise_or_quit(ValueError, ("parameter $1 requires a " &
+          "float, but $2 can't be parsed completely into one") % [
+          param, escape(value)])
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires a " &
+        "float, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_EMPTY:
+    discard
+  of PK_HELP:
+    discard
+
+
+template build_specification_lookup():
+    OrderedTable[string, ptr Tparameter_specification] =
+  ## Returns the table used to keep pointers to all of the specifications.
+  var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification]
+  result = initOrderedTable[string, ptr Tparameter_specification](
+    tables.rightSize(expected.len))
+  for i in 0..expected.len-1:
+    for param_to_detect in expected[i].names:
+      if result.hasKey(param_to_detect):
+        raise_or_quit(KeyError,
+          "Parameter $1 repeated in input specification" % param_to_detect)
+      else:
+        result[param_to_detect] = addr(expected[i])
+  result
+
+
+proc echo_help*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING,
+    bad_prefixes = @["-", "--"], end_of_options = "--")
+
+
+proc parse*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = nil,
+    bad_prefixes = @["-", "--"], end_of_options = "--",
+    quit_on_failure = true): Tcommandline_results =
+  ## Parses parameters and returns results.
+  ##
+  ## The expected array should contain a list of the parameters you want to
+  ## detect, which can capture additional values. Uncaptured parameters are
+  ## considered positional parameters for which you can specify a type with
+  ## type_of_positional_parameters.
+  ##
+  ## Before accepting a positional parameter, the list of bad_prefixes is
+  ## compared against it. If the positional parameter starts with any of them,
+  ## an error is displayed to the user due to ambiguity. The user can overcome
+  ## the ambiguity by typing the special string specified by end_of_options.
+  ## Note that values captured by parameters are not checked against bad
+  ## prefixes, otherwise it would be a problem to specify the dash as synonim
+  ## for standard input for many programs.
+  ##
+  ## The args sequence should be the list of parameters passed to your program
+  ## without the program binary (usually OSes provide the path to the binary as
+  ## the zeroth parameter). If args is nil, the list will be retrieved from the
+  ## OS.
+  ##
+  ## If there is any kind of error and quit_on_failure is true, the quit proc
+  ## will be called with a user error message. If quit_on_failure is false
+  ## errors will raise exceptions (usually ValueError or EOverflow) instead
+  ## for you to catch and handle.
+
+  assert type_of_positional_parameters != PK_EMPTY and
+    type_of_positional_parameters != PK_HELP
+  for bad_prefix in bad_prefixes:
+    assert bad_prefix.len > 0, "Can't pass in a bad prefix of zero length"
+  var
+    expected = expected
+    adding_options = true
+  result.init()
+
+  # Prepare the input parameter list, maybe get it from the OS if not available.
+  var args = args
+  if args == nil:
+    let total_params = paramCount()
+    #echo "Got no explicit args, retrieving from OS. Count: ", total_params
+    newSeq(args, total_params)
+    for i in 0..total_params - 1:
+      #echo ($i)
+      args[i] = paramStr(i + 1)
+
+  # Generate lookup table for each type of parameter based on strings.
+  var lookup = build_specification_lookup()
+
+  # Loop through the input arguments detecting their type and doing stuff.
+  var i = 0
+  while i < args.len:
+    let arg = args[i]
+    block adding_positional_parameter:
+      if arg.len > 0 and adding_options:
+        if arg == end_of_options:
+          # Looks like we found the end_of_options marker, disable options.
+          adding_options = false
+          break adding_positional_parameter
+        elif lookup.hasKey(arg):
+          var parsed: Tparsed_parameter
+          let param = lookup[arg]
+
+          # Insert check here for help, which aborts parsing.
+          if param.consumes == PK_HELP:
+            echo_help(expected, type_of_positional_parameters,
+              bad_prefixes, end_of_options)
+            raise_or_quit(KeyError, "")
+
+          if param.consumes != PK_EMPTY:
+            if i + 1 < args.len:
+              parsed = parse_parameter(quit_on_failure,
+                arg, args[i + 1], param.consumes)
+              run_custom_proc(parsed, param.custom_validator, arg)
+              i += 1
+            else:
+              raise_or_quit(ValueError, ("parameter $1 requires a " &
+                "value, but none was provided") % [arg])
+          result.options[param.names[0]] = parsed
+          break adding_positional_parameter
+        else:
+          for bad_prefix in bad_prefixes:
+            if arg.startsWith(bad_prefix):
+              raise_or_quit(ValueError, ("Found ambiguos parameter '$1' " &
+                "starting with '$2', put '$3' as the previous parameter " &
+                "if you want to force it as positional parameter.") % [arg,
+                bad_prefix, end_of_options])
+
+      # Unprocessed, add the parameter to the list of positional parameters.
+      result.positional_parameters.add(parse_parameter(quit_on_failure,
+        $(1 + i), arg, type_of_positional_parameters))
+
+    i += 1
+
+
+proc toString(runes: seq[Rune]): string =
+  result = ""
+  for rune in runes: result.add(rune.toUTF8)
+
+
+proc ascii_cmp(a, b: string): int =
+  ## Comparison ignoring non ascii characters, for better switch sorting.
+  let a = filterIt(toSeq(runes(a)), it.isAlpha())
+  # Can't use filterIt twice, github bug #351.
+  let b = filter(toSeq(runes(b)), proc(x: Rune): bool = x.isAlpha())
+  return system.cmp(toString(a), toString(b))
+
+
+proc build_help*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING,
+    bad_prefixes = @["-", "--"], end_of_options = "--"): seq[string] =
+  ## Builds basic help text and returns it as a sequence of strings.
+  ##
+  ## Note that this proc doesn't do as much sanity checks as the normal parse()
+  ## proc, though it's unlikely you will be using one without the other, so if
+  ## you had a parameter specification problem you would find out soon.
+  result = @["Usage parameters: "]
+
+  # Generate lookup table for each type of parameter based on strings.
+  let quit_on_failure = false
+  var
+    expected = expected
+    lookup = build_specification_lookup()
+    keys = toSeq(lookup.keys())
+
+  # First generate the joined version of input parameters in a list.
+  var
+    seen = initSet[string]()
+    prefixes: seq[string] = @[]
+    helps: seq[string] = @[]
+  for key in keys:
+    if seen.contains(key):
+      continue
+
+    # Add the joined string to the list.
+    let param = lookup[key][]
+    var param_names = param.names
+    sort(param_names, ascii_cmp)
+    var prefix = join(param_names, ", ")
+    # Don't forget about the type, if the parameter consumes values
+    if param.consumes != PK_EMPTY and param.consumes != PK_HELP:
+      prefix &= " " & $param.consumes
+    prefixes.add(prefix)
+    helps.add(param.help_text)
+    # Ignore future elements.
+    for name in param.names: seen.incl(name)
+
+  # Calculate the biggest width and try to use that
+  let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
+
+  for line in zip(prefixes, helps):
+    result.add(line.a & spaces(width - line.a.len) & line.b)
+
+
+proc echo_help*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING,
+    bad_prefixes = @["-", "--"], end_of_options = "--") =
+  ## Prints out help on the terminal.
+  ##
+  ## This is just a wrapper around build_help. Note that calling this proc
+  ## won't exit your program, you should call quit() yourself.
+  for line in build_help(expected,
+      type_of_positional_parameters, bad_prefixes, end_of_options):
+    echo line
+
+
+when isMainModule:
+  # Simply tests code embedded in docs.
+  let
+    parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41)
+    parsed_param2 = new_parsed_parameter(PK_BIGGEST_INT, 2358123 * 23123)
+    #parsed_param3 = new_parsed_parameter(PK_INT, "231")
diff --git a/tests/manyloc/argument_parser/ex_wget.nim b/tests/manyloc/argument_parser/ex_wget.nim
new file mode 100644
index 000000000..625a6f595
--- /dev/null
+++ b/tests/manyloc/argument_parser/ex_wget.nim
@@ -0,0 +1,87 @@
+import argument_parser, tables, strutils, parseutils
+
+## Example defining a subset of wget's functionality
+
+const
+  PARAM_VERSION = @["-V", "--version"]
+  PARAM_HELP = @["-h", "--help"]
+  PARAM_BACKGROUND = @["-b", "--background"]
+  PARAM_OUTPUT = @["-o", "--output"]
+  PARAM_NO_CLOBBER = @["-nc", "--no-clobber"]
+  PARAM_PROGRESS = @["--progress"]
+  PARAM_NO_PROXY = @["--no-proxy"]
+
+
+template P(tnames: varargs[string], thelp: string, ttype = PK_EMPTY,
+    tcallback: Tparameter_callback = nil) =
+  ## Helper to avoid repetition of parameter adding boilerplate.
+  params.add(new_parameter_specification(ttype, custom_validator = tcallback,
+    help_text = thelp, names = tnames))
+
+
+template got(param: varargs[string]) =
+  ## Just dump the detected options on output.
+  if result.options.hasKey(param[0]): echo("Found option '$1'." % [param[0]])
+
+
+proc parse_progress(parameter: string; value: var Tparsed_parameter): string =
+  ## Custom parser and validator of progress types for PARAM_PROGRESS.
+  ##
+  ## If the user specifies the PARAM_PROGRESS option this proc will be called
+  ## so we can validate the input. The proc returns a non empty string if
+  ## something went wrong with the description of the error, otherwise
+  ## execution goes ahead.
+  ##
+  ## This validator only accepts values without changing the final output.
+  if value.str_val == "bar" or value.str_val == "dot":
+    return
+
+  result = "The string $1 is not valid, use bar or dot." % [value.str_val]
+
+
+proc process_commandline(): Tcommandline_results =
+  ## Parses the commandline.
+  ##
+  ## Returns a Tcommandline_results with at least two positional parameter,
+  ## where the last parameter is implied to be the destination of the copying.
+  var params: seq[Tparameter_specification] = @[]
+
+  P(PARAM_VERSION, "Shows the version of the program")
+  P(PARAM_HELP, "Shows this help on the commandline", PK_HELP)
+  P(PARAM_BACKGROUND, "Continues execution in the background")
+  P(PARAM_OUTPUT, "Specifies a specific output file name", PK_STRING)
+  P(PARAM_NO_CLOBBER, "Skip downloads that would overwrite existing files")
+  P(PARAM_PROGRESS, "Select progress look (bar or dot)",
+    PK_STRING, parse_progress)
+  P(PARAM_NO_PROXY, "Don't use proxies even if available")
+
+  result = parse(params)
+
+  if result.positional_parameters.len < 1:
+    echo "Missing URL(s) to download"
+    echo_help(params)
+    quit()
+
+  got(PARAM_NO_CLOBBER)
+  got(PARAM_BACKGROUND)
+  got(PARAM_NO_PROXY)
+
+  if result.options.hasKey(PARAM_VERSION[0]):
+    echo "Version 3.1415"
+    quit()
+
+  if result.options.hasKey(PARAM_OUTPUT[0]):
+    if result.positional_parameters.len > 1:
+      echo "Error: can't use $1 option with multiple URLs" % [PARAM_OUTPUT[0]]
+      echo_help(params)
+      quit()
+    echo "Will download to $1" % [result.options[PARAM_OUTPUT[0]].str_val]
+
+  if result.options.hasKey(PARAM_PROGRESS[0]):
+    echo "Will use progress type $1" % [result.options[PARAM_PROGRESS[0]].str_val]
+
+
+when isMainModule:
+  let args = process_commandline()
+  for param in args.positional_parameters:
+    echo "Downloading $1" % param.str_val
diff --git a/tests/manyloc/argument_parser/ex_wget.nim.cfg b/tests/manyloc/argument_parser/ex_wget.nim.cfg
new file mode 100644
index 000000000..4ea571d31
--- /dev/null
+++ b/tests/manyloc/argument_parser/ex_wget.nim.cfg
@@ -0,0 +1 @@
+# This file exists only to mark 'ex_wget' as the project file
diff --git a/tests/manyloc/keineschweine/README.md b/tests/manyloc/keineschweine/README.md
new file mode 100644
index 000000000..1323f4ae3
--- /dev/null
+++ b/tests/manyloc/keineschweine/README.md
@@ -0,0 +1,26 @@
+keineSchweine
+========================
+Just a dumb little game
+
+### Dependencies
+
+* nim 0.8.15, Until this version is released I'm working off nim HEAD: https://github.com/Araq/nim
+* SFML 2.0 (git), https://github.com/LaurentGomila/SFML
+* CSFML 2.0 (git), https://github.com/LaurentGomila/CSFML
+* Chipmunk 6.1.1 http://chipmunk-physics.net/downloads.php
+
+### How to build?
+
+* `git clone --recursive git://github.com/fowlmouth/keineSchweine.git somedir`
+* `cd somedir`
+*  `nim c -r nakefile test` or `nim c -r keineschweine && ./keineschweine`
+
+### Download the game data
+
+You need to download the game data before you can play:
+http://dl.dropbox.com/u/37533467/data-08-01-2012.7z
+
+Unpack it to the root directory. You can use the nakefile to do this easily: 
+
+* `nim c -r nakefile`
+* `./nakefile download`
diff --git a/tests/manyloc/keineschweine/TODO.md b/tests/manyloc/keineschweine/TODO.md
new file mode 100644
index 000000000..1145949aa
--- /dev/null
+++ b/tests/manyloc/keineschweine/TODO.md
@@ -0,0 +1,21 @@
+##Main State
+* Add GUI:
+  * Player list
+  * Chat box
+  * Escape menu
+
+##Lobby
+* Add GUI: 
+  * options menu
+  * key configuration
+
+## Animations
+* Need one-shot explosion animations
+  * Thrusters (maybe a particle system instead)
+
+## Networking
+* zone server should verify users through the dir server or handle its own users
+* directory server should handle asset patching
+
+## Genpacket
+* add support for branching types with case
diff --git a/tests/manyloc/keineschweine/client_settings.json b/tests/manyloc/keineschweine/client_settings.json
new file mode 100644
index 000000000..59facf1ad
--- /dev/null
+++ b/tests/manyloc/keineschweine/client_settings.json
@@ -0,0 +1,10 @@
+{
+ "resolution": [800,600,32],
+ "default-file": "alphazone.json",
+ "alias": "foo",
+ "directory-server":{
+  "host":"localhost",
+  "port":8024
+ },
+ "website":"https://github.com/fowlmouth/keineSchweine"
+}
diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
new file mode 100644
index 000000000..493a2106c
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
@@ -0,0 +1,1515 @@
+# Copyright (c) 2007 Scott Lembcke
+#  
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to deal
+#  in the Software without restriction, including without limitation the rights
+#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#  
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+#  SOFTWARE.
+# 
+
+const Lib = "libchipmunk.so.6.1.1"
+
+when defined(MoreNim):
+  {.hint: "MoreNim defined; some Chipmunk functions replaced in Nim".}
+{.deadCodeElim: on.}
+from math import sqrt, sin, cos, arctan2
+when defined(CpUseFloat):
+  {.hint: "CpUseFloat defined; using float32 as float".}
+  type CpFloat* = cfloat
+else:
+  type CpFloat* = cdouble
+const 
+  CP_BUFFER_BYTES* = (32 * 1024)  
+  CP_MAX_CONTACTS_PER_ARBITER* = 4
+  CpInfinity*: CpFloat = 1.0/0
+{.pragma: pf, pure, final.}
+type 
+  Bool32* = cint  #replace one day with cint-compatible bool
+  CpDataPointer* = pointer
+  TVector* {.final, pure.} = object
+    x*, y*: CpFloat
+  TTimestamp* = cuint
+  TBodyVelocityFunc* = proc(body: PBody, gravity: TVector,
+                            damping: CpFloat; dt: CpFloat){.cdecl.}
+  TBodyPositionFunc* = proc(body: PBody; dt: CpFloat){.cdecl.}
+  TComponentNode*{.pf.} = object 
+    root*: PBody
+    next*: PBody
+    idleTime*: CpFloat
+  
+  THashValue = cuint  # uintptr_t 
+  TCollisionType* = cuint #uintptr_t
+  TGroup * = cuint #uintptr_t
+  TLayers* = cuint
+  PArray = ptr TArray
+  TArray{.pure,final.} = object
+  PHashSet = ptr THashSet
+  THashSet{.pf.} = object
+  PContact* = ptr TContact
+  TContact*{.pure,final.} = object
+  PArbiter* = ptr TArbiter
+  TArbiter*{.pf.} = object 
+    e*: CpFloat
+    u*: CpFloat 
+    surface_vr*: TVector
+    a*: PShape
+    b*: PShape
+    body_a*: PBody
+    body_b*: PBody
+    thread_a*: TArbiterThread
+    thread_b*: TArbiterThread
+    numContacts*: cint
+    contacts*: PContact
+    stamp*: TTimestamp
+    handler*: PCollisionHandler
+    swappedColl*: Bool32
+    state*: TArbiterState
+  PCollisionHandler* = ptr TCollisionHandler
+  TCollisionHandler*{.pf.} = object 
+    a*: TCollisionType
+    b*: TCollisionType
+    begin*: TCollisionBeginFunc
+    preSolve*: TCollisionPreSolveFunc
+    postSolve*: TCollisionPostSolveFunc
+    separate*: TCollisionSeparateFunc
+    data*: pointer
+  TArbiterState*{.size: sizeof(cint).} = enum 
+    ArbiterStateFirstColl,    # Arbiter is active and its not the first collision.
+    ArbiterStateNormal,       # Collision has been explicitly ignored.
+                              # Either by returning false from a begin collision handler or calling cpArbiterIgnore().
+    ArbiterStateIgnore,       # Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.
+    ArbiterStateCached
+  TArbiterThread*{.pf.} = object 
+    next*: PArbiter        # Links to next and previous arbiters in the contact graph.
+    prev*: PArbiter
+  
+  TContactPoint*{.pf.} = object 
+    point*: TVector    #/ The position of the contact point.
+    normal*: TVector   #/ The normal of the contact point.
+    dist*: CpFloat     #/ The depth of the contact point.
+  #/ A struct that wraps up the important collision data for an arbiter.
+  PContactPointSet* = ptr TContactPointSet
+  TContactPointSet*{.pf.} = object 
+    count*: cint              #/ The number of contact points in the set.
+    points*: array[0..CP_MAX_CONTACTS_PER_ARBITER - 1, TContactPoint] #/ The array of contact points.
+  
+  #/ Collision begin event function callback type.
+  #/ Returning false from a begin callback causes the collision to be ignored until
+  #/ the the separate callback is called when the objects stop colliding.
+  TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{.
+      cdecl.}
+  #/ Collision pre-solve event function callback type.
+  #/ Returning false from a pre-step callback causes the collision to be ignored until the next step.
+  TCollisionPreSolveFunc* = proc (arb: PArbiter; space: PSpace; 
+                                  data: pointer): bool {.cdecl.}
+  #/ Collision post-solve event function callback type.
+  TCollisionPostSolveFunc* = proc (arb: PArbiter; space: PSpace; 
+                                   data: pointer){.cdecl.}
+  #/ Collision separate event function callback type.
+  TCollisionSeparateFunc* = proc (arb: PArbiter; space: PSpace; 
+                                  data: pointer){.cdecl.}
+  
+  #/ Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top)
+  PBB* = ptr TBB
+  TBB* {.pf.} = object 
+    l*, b*, r*, t*: CpFloat
+  
+  #/ Spatial index bounding box callback function type.
+  #/ The spatial index calls this function and passes you a pointer to an object you added
+  #/ when it needs to get the bounding box associated with that object.
+  TSpatialIndexBBFunc* = proc (obj: pointer): TBB{.cdecl.}
+  #/ Spatial index/object iterator callback function type.
+  TSpatialIndexIteratorFunc* = proc (obj: pointer; data: pointer){.cdecl.}
+  #/ Spatial query callback function type. 
+  TSpatialIndexQueryFunc* = proc (obj1: pointer; obj2: pointer; data: pointer){.
+      cdecl.}
+  #/ Spatial segment query callback function type.
+  TSpatialIndexSegmentQueryFunc* = proc (obj1: pointer; obj2: pointer; 
+      data: pointer): CpFloat {.cdecl.}
+  #/ private
+  PSpatialIndex = ptr TSpatialIndex
+  TSpatialIndex{.pf.} = object 
+    klass: PSpatialIndexClass
+    bbfun: TSpatialIndexBBFunc
+    staticIndex: PSpatialIndex
+    dynamicIndex: PSpatialIndex
+
+  TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.}
+  TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.}
+  TSpatialIndexEachImpl* = proc (index: PSpatialIndex; 
+                                 fun: TSpatialIndexIteratorFunc; data: pointer){.
+      cdecl.}
+  TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                     hashid: THashValue): Bool32 {.cdecl.}
+  TSpatialIndexInsertImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                   hashid: THashValue){.cdecl.}
+  TSpatialIndexRemoveImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                   hashid: THashValue){.cdecl.}
+  TSpatialIndexReindexImpl* = proc (index: PSpatialIndex){.cdecl.}
+  TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex; 
+      obj: pointer; hashid: THashValue){.cdecl.}
+  TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex; 
+      fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.}
+  TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector; 
+                                       fun: TSpatialIndexQueryFunc; 
+                                       data: pointer){.cdecl.}
+  TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer; 
+      a: TVector; b: TVector; t_exit: CpFloat; fun: TSpatialIndexSegmentQueryFunc; 
+      data: pointer){.cdecl.}
+  TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                  bb: TBB; fun: TSpatialIndexQueryFunc; 
+                                  data: pointer){.cdecl.}
+  PSpatialIndexClass* = ptr TSpatialIndexClass
+  TSpatialIndexClass*{.pf.} = object 
+    destroy*: TSpatialIndexDestroyImpl
+    count*: TSpatialIndexCountImpl
+    each*: TSpatialIndexEachImpl
+    contains*: TSpatialIndexContainsImpl
+    insert*: TSpatialIndexInsertImpl
+    remove*: TSpatialIndexRemoveImpl
+    reindex*: TSpatialIndexReindexImpl
+    reindexObject*: TSpatialIndexReindexObjectImpl
+    reindexQuery*: TSpatialIndexReindexQueryImpl
+    pointQuery*: TSpatialIndexPointQueryImpl
+    segmentQuery*: TSpatialIndexSegmentQueryImpl
+    query*: TSpatialIndexQueryImpl
+  
+  PSpaceHash* = ptr TSpaceHash
+  TSpaceHash* {.pf.} = object
+  PBBTree* = ptr TBBTree
+  TBBTree* {.pf.} = object
+  PSweep1D* = ptr TSweep1D
+  TSweep1D* {.pf.} = object
+  
+  #/ Bounding box tree velocity callback function.
+  #/ This function should return an estimate for the object's velocity.
+  TBBTreeVelocityFunc* = proc (obj: pointer): TVector {.cdecl.}
+  
+  PContactBufferHeader* = ptr TContentBufferHeader
+  TContentBufferHeader* {.pf.} = object
+  TSpaceArbiterApplyImpulseFunc* = proc (arb: PArbiter){.cdecl.}
+  
+  PSpace* = ptr TSpace
+  TSpace* {.pf.} = object
+    iterations*: cint 
+    gravity*: TVector
+    damping*: CpFloat
+    idleSpeedThreshold*: CpFloat 
+    sleepTimeThreshold*: CpFloat 
+    collisionSlop*: CpFloat 
+    collisionBias*: CpFloat
+    collisionPersistence*: TTimestamp        
+    enableContactGraph*: cint ##BOOL
+    data*: pointer
+    staticBody*: PBody
+    stamp: TTimestamp
+    currDT: CpFloat
+    bodies: PArray
+    rousedBodies: PArray
+    sleepingComponents: PArray
+    staticShapes: PSpatialIndex
+    activeShapes: PSpatialIndex
+    arbiters: PArray
+    contactBuffersHead: PContactBufferHeader
+    cachedArbiters: PHashSet
+    pooledArbiters: PArray
+    constraints: PArray
+    allocatedBuffers: PArray
+    locked: cint
+    collisionHandlers: PHashSet
+    defaultHandler: TCollisionHandler
+    postStepCallbacks: PHashSet
+    arbiterApplyImpulse: TSpaceArbiterApplyImpulseFunc
+    staticBody2: TBody  #_staticBody 
+  PBody* = ptr TBody
+  TBody*{.pf.} = object 
+    velocityFunc*: TBodyVelocityFunc 
+    positionFunc*: TBodyPositionFunc                                       
+    m*: CpFloat           
+    mInv*: CpFloat       
+    i*: CpFloat           
+    iInv*: CpFloat       
+    p*: TVector            
+    v*: TVector            
+    f*: TVector 
+    a*: CpFloat 
+    w*: CpFloat 
+    t*: CpFloat 
+    rot*: TVector 
+    data*: pointer
+    vLimit*: CpFloat   
+    wLimit*: CpFloat
+    vBias*: TVector
+    wBias*: CpFloat
+    space*: PSpace
+    shapeList*: PShape
+    arbiterList*: PArbiter
+    constraintList*: PConstraint
+    node*: TComponentNode
+  #/ Body/shape iterator callback function type. 
+  TBodyShapeIteratorFunc* = proc (body: PBody; shape: PShape; 
+                                   data: pointer) {.cdecl.}
+  #/ Body/constraint iterator callback function type. 
+  TBodyConstraintIteratorFunc* = proc (body: PBody; 
+                                        constraint: PConstraint; 
+                                        data: pointer) {.cdecl.}
+  #/ Body/arbiter iterator callback function type. 
+  TBodyArbiterIteratorFunc* = proc (body: PBody; arbiter: PArbiter; 
+                                     data: pointer) {.cdecl.}
+  
+  PNearestPointQueryInfo* = ptr TNearestPointQueryInfo
+  #/ Nearest point query info struct.
+  TNearestPointQueryInfo*{.pf.} = object
+    shape: PShape  #/ The nearest shape, NULL if no shape was within range.
+    p: TVector     #/ The closest point on the shape's surface. (in world space coordinates)
+    d: CpFloat      #/ The distance to the point. The distance is negative if the point is inside the shape.
+  
+  PSegmentQueryInfo* = ptr TSegmentQueryInfo
+  #/ Segment query info struct.
+  TSegmentQueryInfo*{.pf.} = object 
+    shape*: PShape         #/ The shape that was hit, NULL if no collision occurred.
+    t*: CpFloat            #/ The normalized distance along the query segment in the range [0, 1].
+    n*: TVector            #/ The normal of the surface hit.
+  TShapeType*{.size: sizeof(cint).} = enum 
+    CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES
+  TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.}
+  TShapeDestroyImpl* = proc (shape: PShape){.cdecl.}
+  TShapePointQueryImpl* = proc (shape: PShape; p: TVector): Bool32 {.cdecl.}
+  TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector; 
+                                  info: PSegmentQueryInfo){.cdecl.}
+  PShapeClass* = ptr TShapeClass
+  TShapeClass*{.pf.} = object 
+    kind*: TShapeType
+    cacheData*: TShapeCacheDataImpl
+    destroy*: TShapeDestroyImpl
+    pointQuery*: TShapePointQueryImpl
+    segmentQuery*: TShapeSegmentQueryImpl
+  PShape* = ptr TShape
+  TShape*{.pf.} = object 
+    klass: PShapeClass   #/ PRIVATE
+    body*: PBody           #/ The rigid body this collision shape is attached to.
+    bb*: TBB               #/ The current bounding box of the shape.   
+    sensor*: Bool32        #/ Sensor flag.
+                           #/ Sensor shapes call collision callbacks but don't produce collisions.  
+    e*: CpFloat            #/ Coefficient of restitution. (elasticity)
+    u*: CpFloat            #/ Coefficient of friction.
+    surface_v*: TVector    #/ Surface velocity used when solving for friction.
+    data*: pointer        #/ User definable data pointer. Generally this points to your the game object class so you can access it when given a cpShape reference in a callback.
+    collision_type*: TCollisionType #/ Collision type of this shape used when picking collision handlers.
+    group*: TGroup      #/ Group of this shape. Shapes in the same group don't collide.
+    layers*: TLayers   #/ Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero.
+    space: PSpace        #PRIVATE
+    next: PShape         #PRIVATE
+    prev: PShape         #PRIVATE
+    hashid: THashValue  #PRIVATE
+  PCircleShape* = ptr TCircleShape
+  TCircleShape*{.pf.} = object
+    shape: PShape
+    c, tc: TVector
+    r: CpFloat
+  PPolyShape* = ptr TPolyShape
+  TPolyShape*{.pf.} = object
+    shape: PShape
+    numVerts: cint
+    verts, tVerts: TVector
+    planes, tPlanes: PSplittingPlane
+  PSegmentShape* = ptr TSegmentShape
+  TSegmentShape*{.pf.} = object
+    shape: PShape
+    a, b, n: TVector
+    ta, tb, tn: TVector
+    r: CpFloat
+    aTangent, bTangent: TVector
+  PSplittingPlane* = ptr TSplittingPlane
+  TSplittingPlane*{.pf.} = object
+    n: TVector
+    d: CpFloat
+  
+  #/ Post Step callback function type.
+  TPostStepFunc* = proc (space: PSpace; obj: pointer; data: pointer){.cdecl.}
+  #/ Point query callback function type.
+  TSpacePointQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Segment query callback function type.
+  TSpaceSegmentQueryFunc* = proc (shape: PShape; t: CpFloat; n: TVector; 
+                                  data: pointer){.cdecl.}
+  #/ Rectangle Query callback function type.
+  TSpaceBBQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Shape query callback function type.
+  TSpaceShapeQueryFunc* = proc (shape: PShape; points: PContactPointSet; 
+                                data: pointer){.cdecl.}
+  #/ Space/body iterator callback function type.
+  TSpaceBodyIteratorFunc* = proc (body: PBody; data: pointer){.cdecl.}
+  #/ Space/body iterator callback function type.
+  TSpaceShapeIteratorFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Space/constraint iterator callback function type.
+  TSpaceConstraintIteratorFunc* = proc (constraint: PConstraint; 
+                                        data: pointer){.cdecl.}
+  #/ Opaque cpConstraint struct.
+  PConstraint* = ptr TConstraint
+  TConstraint*{.pf.} = object 
+    klass: PConstraintClass #/PRIVATE
+    a*: PBody            #/ The first body connected to this constraint.
+    b*: PBody              #/ The second body connected to this constraint.
+    space: PSpace         #/PRIVATE
+    next_a: PConstraint  #/PRIVATE
+    next_b: PConstraint #/PRIVATE
+    maxForce*: CpFloat  #/ The maximum force that this constraint is allowed to use. Defaults to infinity.
+    errorBias*: CpFloat #/ The rate at which joint error is corrected. Defaults to pow(1.0 - 0.1, 60.0) meaning that it will correct 10% of the error every 1/60th of a second.
+    maxBias*: CpFloat    #/ The maximum rate at which joint error is corrected. Defaults to infinity.       
+    preSolve*: TConstraintPreSolveFunc  #/ Function called before the solver runs. Animate your joint anchors, update your motor torque, etc.
+    postSolve*: TConstraintPostSolveFunc #/ Function called after the solver runs. Use the applied impulse to perform effects like breakable joints.
+    data*: CpDataPointer  # User definable data pointer. Generally this points to your the game object class so you can access it when given a cpConstraint reference in a callback.
+  TConstraintPreStepImpl = proc (constraint: PConstraint; dt: CpFloat){.cdecl.}
+  TConstraintApplyCachedImpulseImpl = proc (constraint: PConstraint; dt_coef: CpFloat){.cdecl.}
+  TConstraintApplyImpulseImpl = proc (constraint: PConstraint){.cdecl.}
+  TConstraintGetImpulseImpl = proc (constraint: PConstraint): CpFloat{.cdecl.}
+  PConstraintClass = ptr TConstraintClass
+  TConstraintClass{.pf.} = object 
+    preStep*: TConstraintPreStepImpl
+    applyCachedImpulse*: TConstraintApplyCachedImpulseImpl
+    applyImpulse*: TConstraintApplyImpulseImpl
+    getImpulse*: TConstraintGetImpulseImpl
+  #/ Callback function type that gets called before solving a joint.
+  TConstraintPreSolveFunc* = proc (constraint: PConstraint; space: PSpace){.
+    cdecl.}
+  #/ Callback function type that gets called after solving a joint.
+  TConstraintPostSolveFunc* = proc (constraint: PConstraint; space: PSpace){.
+    cdecl.}
+
+##cp property emulators
+template defGetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
+  proc `get procName`*(obj: otype): memberType {.cdecl.} =
+    return obj.memberName
+template defSetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
+  proc `set procName`*(obj: otype, value: memberType) {.cdecl.} =
+    obj.memberName = value
+template defProp(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
+  defGetter(otype, memberType, memberName, procName)
+  defSetter(otype, memberType, memberName, procName)
+
+
+##cpspace.h
+proc allocSpace*(): PSpace {.
+  importc: "cpSpaceAlloc", dynlib: Lib.}
+proc Init*(space: PSpace): PSpace {.
+  importc: "cpSpaceInit", dynlib: Lib.}
+proc newSpace*(): PSpace {.
+  importc: "cpSpaceNew", dynlib: Lib.}
+proc destroy*(space: PSpace) {.
+  importc: "cpSpaceDestroy", dynlib: Lib.}
+proc free*(space: PSpace) {.
+  importc: "cpSpaceFree", dynlib: Lib.}
+
+defProp(PSpace, cint, iterations, Iterations)
+defProp(PSpace, TVector, gravity, Gravity)
+defProp(PSpace, CpFloat, damping, Damping)
+defProp(PSpace, CpFloat, idleSpeedThreshold, IdleSpeedThreshold)
+defProp(PSpace, CpFloat, sleepTimeThreshold, SleepTimeThreshold)
+defProp(PSpace, CpFloat, collisionSlop, CollisionSlop)
+defProp(PSpace, CpFloat, collisionBias, CollisionBias)
+defProp(PSpace, TTimestamp, collisionPersistence, CollisionPersistence)
+defProp(PSpace, Bool32, enableContactGraph, EnableContactGraph)
+defProp(PSpace, pointer, data, UserData)
+defGetter(PSpace, PBody, staticBody, StaticBody)
+defGetter(PSpace, CpFloat, currDt, CurrentTimeStep)
+
+
+#/ returns true from inside a callback and objects cannot be added/removed.
+proc isLocked*(space: PSpace): bool{.inline.} = 
+  result = space.locked.bool
+
+#/ Set a default collision handler for this space.
+#/ The default collision handler is invoked for each colliding pair of shapes
+#/ that isn't explicitly handled by a specific collision handler.
+#/ You can pass NULL for any function you don't want to implement.
+proc setDefaultCollisionHandler*(space: PSpace; begin: TCollisionBeginFunc; 
+                                  preSolve: TCollisionPreSolveFunc; 
+                                  postSolve: TCollisionPostSolveFunc; 
+                                  separate: TCollisionSeparateFunc; 
+                                  data: pointer){.
+  cdecl, importc: "cpSpaceSetDefaultCollisionHandler", dynlib: Lib.}
+#/ Set a collision handler to be used whenever the two shapes with the given collision types collide.
+#/ You can pass NULL for any function you don't want to implement.
+proc addCollisionHandler*(space: PSpace; a, b: TCollisionType; 
+                           begin: TCollisionBeginFunc; 
+                           preSolve: TCollisionPreSolveFunc; 
+                           postSolve: TCollisionPostSolveFunc; 
+                           separate: TCollisionSeparateFunc; data: pointer){.
+  cdecl, importc: "cpSpaceAddCollisionHandler", dynlib: Lib.}
+#/ Unset a collision handler.
+proc removeCollisionHandler*(space: PSpace; a: TCollisionType; 
+                                  b: TCollisionType){.
+  cdecl, importc: "cpSpaceRemoveCollisionHandler", dynlib: Lib.}
+#/ Add a collision shape to the simulation.
+#/ If the shape is attached to a static body, it will be added as a static shape.
+proc addShape*(space: PSpace; shape: PShape): PShape{.
+  cdecl, importc: "cpSpaceAddShape", dynlib: Lib.}
+#/ Explicity add a shape as a static shape to the simulation.
+proc addStaticShape*(space: PSpace; shape: PShape): PShape{.
+  cdecl, importc: "cpSpaceAddStaticShape", dynlib: Lib.}
+#/ Add a rigid body to the simulation.
+proc addBody*(space: PSpace; body: PBody): PBody{.
+  cdecl, importc: "cpSpaceAddBody", dynlib: Lib.}
+#/ Add a constraint to the simulation.
+proc addConstraint*(space: PSpace; constraint: PConstraint): PConstraint{.
+    cdecl, importc: "cpSpaceAddConstraint", dynlib: Lib.}
+#/ Remove a collision shape from the simulation.
+proc removeShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceRemoveShape", dynlib: Lib.}
+#/ Remove a collision shape added using cpSpaceAddStaticShape() from the simulation.
+proc removeStaticShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceRemoveStaticShape", dynlib: Lib.}
+#/ Remove a rigid body from the simulation.
+proc removeBody*(space: PSpace; body: PBody){.
+  cdecl, importc: "cpSpaceRemoveBody", dynlib: Lib.}
+#/ Remove a constraint from the simulation.
+proc RemoveConstraint*(space: PSpace; constraint: PConstraint){.
+  cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.}
+#/ Test if a collision shape has been added to the space.
+proc containsShape*(space: PSpace; shape: PShape): bool{.
+  cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.}
+#/ Test if a rigid body has been added to the space.
+proc containsBody*(space: PSpace; body: PBody): bool{.
+  cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.}
+#/ Test if a constraint has been added to the space.
+
+proc containsConstraint*(space: PSpace; constraint: PConstraint): bool{.
+  cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.}
+#/ Schedule a post-step callback to be called when cpSpaceStep() finishes.
+#/ @c obj is used a key, you can only register one callback per unique value for @c obj
+proc addPostStepCallback*(space: PSpace; fun: TPostStepFunc; 
+                               obj: pointer; data: pointer){.
+  cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.}
+                                        
+#/ Query the space at a point and call @c func for each shape found.
+proc pointQuery*(space: PSpace; point: TVector; layers: TLayers; 
+                      group: TGroup; fun: TSpacePointQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpacePointQuery", dynlib: Lib.}
+
+#/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
+proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers; 
+                       group: TGroup): PShape{.
+  cdecl, importc: "cpSpacePointQueryFirst", dynlib: Lib.}
+
+#/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.
+proc segmentQuery*(space: PSpace; start: TVector; to: TVector; 
+                    layers: TLayers; group: TGroup; 
+                    fun: TSpaceSegmentQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.}
+#/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.
+proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; 
+                         layers: TLayers; group: TGroup; 
+                         res: PSegmentQueryInfo): PShape{.
+  cdecl, importc: "cpSpaceSegmentQueryFirst", dynlib: Lib.}
+
+#/ Perform a fast rectangle query on the space calling @c func for each shape found.
+#/ Only the shape's bounding boxes are checked for overlap, not their full shape.
+proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup; 
+                   fun: TSpaceBBQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.}
+
+#/ Query a space for any shapes overlapping the given shape and call @c func for each shape found.
+proc shapeQuery*(space: PSpace; shape: PShape; fun: TSpaceShapeQueryFunc; data: pointer): bool {.
+  cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.}
+#/ Call cpBodyActivate() for any shape that is overlaps the given shape.
+proc activateShapesTouchingShape*(space: PSpace; shape: PShape){.
+    cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.}
+
+#/ Call @c func for each body in the space.
+proc eachBody*(space: PSpace; fun: TSpaceBodyIteratorFunc; data: pointer){.
+  cdecl, importc: "cpSpaceEachBody", dynlib: Lib.}
+
+#/ Call @c func for each shape in the space.
+proc eachShape*(space: PSpace; fun: TSpaceShapeIteratorFunc; 
+                     data: pointer){.
+  cdecl, importc: "cpSpaceEachShape", dynlib: Lib.}
+#/ Call @c func for each shape in the space.
+proc eachConstraint*(space: PSpace; fun: TSpaceConstraintIteratorFunc; 
+                          data: pointer){.
+  cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.}
+#/ Update the collision detection info for the static shapes in the space.
+proc reindexStatic*(space: PSpace){.
+  cdecl, importc: "cpSpaceReindexStatic", dynlib: Lib.}
+#/ Update the collision detection data for a specific shape in the space.
+proc reindexShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceReindexShape", dynlib: Lib.}
+#/ Update the collision detection data for all shapes attached to a body.
+proc reindexShapesForBody*(space: PSpace; body: PBody){.
+  cdecl, importc: "cpSpaceReindexShapesForBody", dynlib: Lib.}
+#/ Switch the space to use a spatial has as it's spatial index.
+proc SpaceUseSpatialHash*(space: PSpace; dim: CpFloat; count: cint){.
+  cdecl, importc: "cpSpaceUseSpatialHash", dynlib: Lib.}
+#/ Step the space forward in time by @c dt.
+proc step*(space: PSpace; dt: CpFloat) {.
+  cdecl, importc: "cpSpaceStep", dynlib: Lib.}
+
+
+#/ Convenience constructor for cpVect structs.
+proc vector*(x, y: CpFloat): TVector {.inline.} =
+  result.x = x
+  result.y = y
+proc newVector*(x, y: CpFloat): TVector {.inline.} =
+  return vector(x, y)
+#let VectorZero* = newVector(0.0, 0.0)
+var VectorZero* = newVector(0.0, 0.0)
+
+#/ Vector dot product.
+proc dot*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = v1.x * v2.x + v1.y * v2.y
+
+#/ Returns the length of v.
+#proc len*(v: TVector): CpFloat {.
+#  cdecl, importc: "cpvlength", dynlib: Lib.}
+proc len*(v: TVector): CpFloat {.inline.} =
+  result = v.dot(v).sqrt
+#/ Spherical linearly interpolate between v1 and v2.
+proc slerp*(v1, v2: TVector; t: CpFloat): TVector {.
+  cdecl, importc: "cpvslerp", dynlib: Lib.}
+#/ Spherical linearly interpolate between v1 towards v2 by no more than angle a radians
+proc slerpconst*(v1, v2: TVector; a: CpFloat): TVector {.
+  cdecl, importc: "cpvslerpconst", dynlib: Lib.}
+#/ Returns the unit length vector for the given angle (in radians).
+#proc vectorForAngle*(a: CpFloat): TVector {.
+#  cdecl, importc: "cpvforangle", dynlib: Lib.}
+proc vectorForAngle*(a: CpFloat): TVector {.inline.} =
+  result = newVector(math.cos(a), math.sin(a))
+#/ Returns the angular direction v is pointing in (in radians).
+proc toAngle*(v: TVector): CpFloat {.inline.} =
+  result = math.arctan2(v.y, v.x)
+#/	Returns a string representation of v. Intended mostly for debugging purposes and not production use.
+#/	@attention The string points to a static local and is reset every time the function is called.
+#/	If you want to print more than one vector you will have to split up your printing onto separate lines.
+proc `$`*(v: TVector): cstring {.cdecl, importc: "cpvstr", dynlib: Lib.}
+
+
+#/ Check if two vectors are equal. (Be careful when comparing floating point numbers!)
+proc `==`*(v1, v2: TVector): bool {.inline.} =
+  result = v1.x == v2.x and v1.y == v2.y
+
+#/ Add two vectors
+proc `+`*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x + v2.x, v1.y + v2.y)
+proc `+=`*(v1: var TVector; v2: TVector) =
+  v1.x = v1.x + v2.x
+  v1.y = v1.y + v2.y
+
+#/ Subtract two vectors.
+proc `-`*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x - v2.x, v1.y - v2.y)
+proc `-=`*(v1: var TVector; v2: TVector) =
+  v1.x = v1.x - v2.x
+  v1.y = v1.y - v2.y
+
+#/ Negate a vector.
+proc `-`*(v: TVector): TVector {.inline.} = 
+  result = newVector(- v.x, - v.y)
+
+#/ Scalar multiplication.
+proc `*`*(v: TVector, s: CpFloat): TVector {.inline.} =
+  result.x = v.x * s
+  result.y = v.y * s
+proc `*=`*(v: var TVector; s: CpFloat) =
+  v.x = v.x * s
+  v.y = v.y * s
+
+#/ 2D vector cross product analog.
+#/ The cross product of 2D vectors results in a 3D vector with only a z component.
+#/ This function returns the magnitude of the z value.
+proc cross*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = v1.x * v2.y - v1.y * v2.x
+
+#/ Returns a perpendicular vector. (90 degree rotation)
+proc perp*(v: TVector): TVector {.inline.} = 
+  result = newVector(- v.y, v.x)
+
+#/ Returns a perpendicular vector. (-90 degree rotation)
+proc rperp*(v: TVector): TVector {.inline.} = 
+  result = newVector(v.y, - v.x)
+
+#/ Returns the vector projection of v1 onto v2.
+proc project*(v1,v2: TVector): TVector {.inline.} = 
+  result = v2 * (v1.dot(v2) / v2.dot(v2))
+
+#/ Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
+
+proc rotate*(v1, v2: TVector): TVector {.inline.} = 
+  result = newVector(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x)
+#/ Inverse of cpvrotate().
+proc unrotate*(v1, v2: TVector): TVector {.inline.} = 
+  result = newVector(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y)
+#/ Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
+proc lenSq*(v: TVector): CpFloat {.inline.} = 
+  result = v.dot(v)
+#/ Linearly interpolate between v1 and v2.
+proc lerp*(v1, v2: TVector; t: CpFloat): TVector {.inline.} = 
+  result = (v1 * (1.0 - t)) + (v2 * t)
+#/ Returns a normalized copy of v.
+proc normalize*(v: TVector): TVector {.inline.} = 
+  result = v * (1.0 / v.len)
+#/ Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
+proc normalizeSafe*(v: TVector): TVector {.inline.} = 
+  result = if v.x == 0.0 and v.y == 0.0: VectorZero else: v.normalize
+#/ Clamp v to length len.
+proc clamp*(v: TVector; len: CpFloat): TVector {.inline.} = 
+  result = if v.dot(v) > len * len: v.normalize * len else: v
+#/ Linearly interpolate between v1 towards v2 by distance d.
+proc lerpconst*(v1, v2: TVector; d: CpFloat): TVector {.inline.} = 
+  result = v1 + clamp(v2 - v1, d)             #vadd(v1 + vclamp(vsub(v2, v1), d))
+#/ Returns the distance between v1 and v2.
+proc dist*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = (v1 - v2).len #vlength(vsub(v1, v2))
+#/ Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
+proc distsq*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = (v1 - v2).lenSq  #vlengthsq(vsub(v1, v2))
+#/ Returns true if the distance between v1 and v2 is less than dist.
+proc near*(v1, v2: TVector; dist: CpFloat): bool{.inline.} = 
+  result = v1.distSq(v2) < dist * dist
+
+
+
+##cpBody.h
+proc allocBody*(): PBody {.importc: "cpBodyAlloc", dynlib: Lib.}
+proc init*(body: PBody; m: CpFloat; i: CpFloat): PBody {.
+  importc: "cpBodyInit", dynlib: Lib.}
+proc newBody*(m: CpFloat; i: CpFloat): PBody {.
+  importc: "cpBodyNew", dynlib: Lib.}
+
+proc initStaticBody*(body: PBody): PBody{.
+  importc: "cpBodyInitStatic", dynlib: Lib.}
+#/ Allocate and initialize a static cpBody.
+proc newStatic*(): PBody{.importc: "cpBodyNewStatic", dynlib: Lib.}
+#/ Destroy a cpBody.
+proc destroy*(body: PBody){.importc: "cpBodyDestroy", dynlib: Lib.}
+#/ Destroy and free a cpBody.
+proc free*(body: PBody){.importc: "cpBodyFree", dynlib: Lib.}
+
+#/ Wake up a sleeping or idle body.
+proc activate*(body: PBody){.importc: "cpBodyActivate", dynlib: Lib.}
+#/ Wake up any sleeping or idle bodies touching a static body.
+proc activateStatic*(body: PBody; filter: PShape){.
+    importc: "cpBodyActivateStatic", dynlib: Lib.}
+#/ Force a body to fall asleep immediately.
+proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.}
+#/ Force a body to fall asleep immediately along with other bodies in a group.
+proc SleepWithGroup*(body: PBody; group: PBody){.
+    importc: "cpBodySleepWithGroup", dynlib: Lib.}
+#/ Returns true if the body is sleeping.
+proc isSleeping*(body: PBody): bool {.inline.} = 
+  return body.node.root != nil
+#/ Returns true if the body is static.
+proc isStatic*(body: PBody): bool {.inline.} = 
+  return body.node.idleTime == CpInfinity
+#/ Returns true if the body has not been added to a space.
+proc isRogue*(body: PBody): bool {.inline.} = 
+  return body.space == nil
+
+# #define CP_DefineBodyStructGetter(type, member, name) \
+# static inline type cpBodyGet##name(const cpBody *body){return body->member;}
+# #define CP_DefineBodyStructSetter(type, member, name) \
+# static inline void cpBodySet##name(cpBody *body, const type value){ \
+# 	cpBodyActivate(body); \
+# 	cpBodyAssertSane(body); \
+# 	body->member = value; \
+# }
+# #define CP_DefineBodyStructProperty(type, member, name) \
+# CP_DefineBodyStructGetter(type, member, name) \
+# CP_DefineBodyStructSetter(type, member, name)
+
+defGetter(PBody, CpFloat, m, Mass)
+#/ Set the mass of a body.
+when defined(MoreNim):
+  defSetter(PBody, CpFloat, m, Mass)
+else:
+  proc setMass*(body: PBody; m: CpFloat){.
+    cdecl, importc: "cpBodySetMass", dynlib: Lib.}
+
+#/ Get the moment of a body.
+defGetter(PBody, CpFloat, i, Moment)
+#/ Set the moment of a body.
+when defined(MoreNim):
+  defSetter(PBody, CpFloat, i, Moment)
+else: 
+  proc SetMoment*(body: PBody; i: CpFloat) {.
+    cdecl, importc: "cpBodySetMoment", dynlib: Lib.}
+
+#/ Get the position of a body.
+defGetter(PBody, TVector, p, Pos)
+#/ Set the position of a body.
+when defined(MoreNim):
+  defSetter(PBody, TVector, p, Pos)
+else:
+  proc setPos*(body: PBody; pos: TVector) {.
+    cdecl, importc: "cpBodySetPos", dynlib: Lib.}
+
+defProp(PBody, TVector, v, Vel)
+defProp(PBody, TVector, f, Force)
+
+#/ Get the angle of a body.
+defGetter(PBody, CpFloat, a, Angle)
+#/ Set the angle of a body.
+proc setAngle*(body: PBody; a: CpFloat){.
+  cdecl, importc: "cpBodySetAngle", dynlib: Lib.}
+
+defProp(PBody, CpFloat, w, AngVel)
+defProp(PBody, CpFloat, t, Torque)
+defGetter(PBody, TVector, rot, Rot)
+defProp(PBody, CpFloat, v_limit, VelLimit)
+defProp(PBody, CpFloat, w_limit, AngVelLimit)
+defProp(PBody, pointer, data, UserData)
+
+#/ Default Integration functions.
+proc UpdateVelocity*(body: PBody; gravity: TVector; damping: CpFloat; dt: CpFloat){.
+  cdecl, importc: "cpBodyUpdateVelocity", dynlib: Lib.}
+proc UpdatePosition*(body: PBody; dt: CpFloat){.
+  cdecl, importc: "cpBodyUpdatePosition", dynlib: Lib.}
+#/ Convert body relative/local coordinates to absolute/world coordinates.
+proc Local2World*(body: PBody; v: TVector): TVector{.inline.} = 
+  result = body.p + v.rotate(body.rot) ##return cpvadd(body.p, cpvrotate(v, body.rot))
+#/ Convert body absolute/world coordinates to  relative/local coordinates.
+proc world2Local*(body: PBody; v: TVector): TVector{.inline.} = 
+  result = (v - body.p).unrotate(body.rot)
+#/ Set the forces and torque or a body to zero.
+proc resetForces*(body: PBody){.
+  cdecl, importc: "cpBodyResetForces", dynlib: Lib.}
+#/ Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
+proc applyForce*(body: PBody; f, r: TVector){.
+  cdecl, importc: "cpBodyApplyForce", dynlib: Lib.}
+#/ Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
+proc applyImpulse*(body: PBody; j, r: TVector){.
+  cdecl, importc: "cpBodyApplyImpulse", dynlib: Lib.}
+#/ Get the velocity on a body (in world units) at a point on the body in world coordinates.
+
+proc getVelAtWorldPoint*(body: PBody; point: TVector): TVector{.
+  cdecl, importc: "cpBodyGetVelAtWorldPoint", dynlib: Lib.}
+#/ Get the velocity on a body (in world units) at a point on the body in local coordinates.
+proc getVelAtLocalPoint*(body: PBody; point: TVector): TVector{.
+  cdecl, importc: "cpBodyGetVelAtLocalPoint", dynlib: Lib.}
+#/ Get the kinetic energy of a body.
+# static inline CpFloat cpBodyKineticEnergy(const cpBody *body)
+# {
+# 	// Need to do some fudging to avoid NaNs
+# 	cpFloat vsq = cpvdot(body->v, body->v);
+# 	cpFloat wsq = body->w*body->w;
+# 	return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f);
+# }
+proc kineticEnergy*(body: PBOdy): CpFloat =
+  result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i)
+
+#/ Call @c func once for each shape attached to @c body and added to the space.
+proc eachShape*(body: PBody; fun: TBodyShapeIteratorFunc; 
+                      data: pointer){.
+  cdecl, importc: "cpBodyEachShape", dynlib: Lib.}
+#/ Call @c func once for each constraint attached to @c body and added to the space.
+proc eachConstraint*(body: PBody; fun: TBodyConstraintIteratorFunc; 
+                           data: pointer) {.
+  cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.}
+#/ Call @c func once for each arbiter that is currently active on the body.
+proc eachArbiter*(body: PBody; fun: TBodyArbiterIteratorFunc; 
+                        data: pointer){.
+  cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.}
+#/ Allocate a spatial hash.
+proc SpaceHashAlloc*(): PSpaceHash{.
+  cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.}
+#/ Initialize a spatial hash. 
+proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint; 
+                    bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+  cdecl, importc: "cpSpaceHashInit", dynlib: Lib.}
+#/ Allocate and initialize a spatial hash.
+proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfun: TSpatialIndexBBFunc; 
+                   staticIndex: PSpatialIndex): PSpatialIndex{.
+  cdecl, importc: "cpSpaceHashNew", dynlib: Lib.}
+#/ Change the cell dimensions and table size of the spatial hash to tune it.
+#/ The cell dimensions should roughly match the average size of your objects
+#/ and the table size should be ~10 larger than the number of objects inserted.
+#/ Some trial and error is required to find the optimum numbers for efficiency.
+proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){.
+  cdecl, importc: "cpSpaceHashResize", dynlib: Lib.}
+#MARK: AABB Tree
+
+
+#/ Allocate a bounding box tree.
+proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.}
+#/ Initialize a bounding box tree.
+proc BBTreeInit*(tree: PBBTree; bbfun: TSpatialIndexBBFunc; 
+                 staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, 
+    importc: "cpBBTreeInit", dynlib: Lib.}
+#/ Allocate and initialize a bounding box tree.
+proc BBTreeNew*(bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+    cdecl, importc: "cpBBTreeNew", dynlib: Lib.}
+#/ Perform a static top down optimization of the tree.
+proc BBTreeOptimize*(index: PSpatialIndex){.
+  cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.}
+#/ Set the velocity function for the bounding box tree to enable temporal coherence.
+
+proc BBTreeSetVelocityFunc*(index: PSpatialIndex; fun: TBBTreeVelocityFunc){.
+    cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.}
+#MARK: Single Axis Sweep
+
+
+#/ Allocate a 1D sort and sweep broadphase.
+
+proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc", 
+                                    dynlib: Lib.}
+#/ Initialize a 1D sort and sweep broadphase.
+
+proc Sweep1DInit*(sweep: ptr TSweep1D; bbfun: TSpatialIndexBBFunc; 
+                  staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, 
+    importc: "cpSweep1DInit", dynlib: Lib.}
+#/ Allocate and initialize a 1D sort and sweep broadphase.
+
+proc Sweep1DNew*(bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.
+    cdecl, importc: "cpSweep1DNew", dynlib: Lib.}
+
+
+
+defProp(PArbiter, CpFloat, e, Elasticity)
+defProp(PArbiter, CpFloat, u, Friction)
+defProp(PArbiter, TVector, surface_vr, SurfaceVelocity)
+
+#/ Calculate the total impulse that was applied by this 
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalImpulse*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulse", dynlib: Lib.}
+
+#/ Calculate the total impulse including the friction that was applied by this arbiter.
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalImpulseWithFriction*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulseWithFriction", dynlib: Lib.}
+
+#/ Calculate the amount of energy lost in a collision including static, but not dynamic friction.
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalKE*(obj: PArbiter): CpFloat {.cdecl, importc: "cpArbiterTotalKE", dynlib: Lib.}
+
+
+#/ Causes a collision pair to be ignored as if you returned false from a begin callback.
+#/ If called from a pre-step callback, you will still need to return false
+#/ if you want it to be ignored in the current step.
+proc ignore*(arb: PArbiter) {.cdecl, importc: "cpArbiterIgnore", dynlib: Lib.}
+
+#/ Return the colliding shapes involved for this arbiter.
+#/ The order of their cpSpace.collision_type values will match
+#/ the order set when the collision handler was registered.
+proc getShapes*(arb: PArbiter, a, b: var PShape) {.inline.} =
+  if arb.swappedColl.bool:
+    a = arb.b
+    b = arb.a
+  else:
+    a = arb.a
+    b = arb.b
+
+#/ A macro shortcut for defining and retrieving the shapes from an arbiter.
+#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
+template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
+  var name1, name2: PShape
+  getShapes(arb, name1, name2)
+
+
+#/ Return the colliding bodies involved for this arbiter.
+#/ The order of the cpSpace.collision_type the bodies are associated with values will match
+#/ the order set when the collision handler was registered.
+#proc getBodies*(arb: PArbiter, a, b: var PBody) {.inline.} = 
+#  getShapes(arb, shape1, shape2)
+#  a = shape1.body
+#  b = shape2.body
+
+#/ A macro shortcut for defining and retrieving the bodies from an arbiter.
+#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
+template getBodies*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
+  var name1, name2: PBOdy
+  getBodies(arb, name1, name2)
+
+proc isFirstContact*(arb: PArbiter): bool {.inline.} =
+  result = arb.state == ArbiterStateFirstColl
+
+proc getCount*(arb: PArbiter): cint {.inline.} =
+  result = arb.numContacts
+
+#/ Return a contact set from an arbiter.
+proc getContactPointSet*(arb: PArbiter): TContactPointSet {.
+  cdecl, importc: "cpArbiterGetContactPointSet", dynlib: Lib.}
+#/ Get the normal of the @c ith contact point.
+proc getNormal*(arb: PArbiter; i: cint): TVector {.
+  cdecl, importc: "cpArbiterGetNormal", dynlib: Lib.}
+#/ Get the position of the @c ith contact point.
+proc getPoint*(arb: PArbiter; i: cint): TVector {.
+  cdecl, importc: "cpArbiterGetPoint", dynlib: Lib.}
+#/ Get the depth of the @c ith contact point.
+proc getDepth*(arb: PArbiter; i: cint): CpFloat {.
+  cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.}
+
+##Shapes
+template defShapeSetter(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} =
+  proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} =
+    if activates and obj.body != nil: obj.body.activate()
+    obj.memberName = value
+template defShapeProp(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} =
+  defGetter(PShape, memberType, memberName, procName)
+  defShapeSetter(memberType, memberName, procName, activates)
+
+#/ Destroy a shape.
+proc destroy*(shape: PShape) {.
+  cdecl, importc: "cpShapeDestroy", dynlib: Lib.}
+#/ Destroy and Free a shape.
+proc free*(shape: PShape){.
+  cdecl, importc: "cpShapeFree", dynlib: Lib.}
+#/ Update, cache and return the bounding box of a shape based on the body it's attached to.
+proc cacheBB*(shape: PShape): TBB{.
+  cdecl, importc: "cpShapeCacheBB", dynlib: Lib.}
+#/ Update, cache and return the bounding box of a shape with an explicit transformation.
+proc update*(shape: PShape; pos: TVector; rot: TVector): TBB {.
+  cdecl, importc: "cpShapeUpdate", dynlib: Lib.}
+#/ Test if a point lies within a shape.
+proc pointQuery*(shape: PShape; p: TVector): Bool32 {.
+  cdecl, importc: "cpShapePointQuery", dynlib: Lib.}
+
+#/ Perform a nearest point query. It finds the closest point on the surface of shape to a specific point.
+#/ The value returned is the distance between the points. A negative distance means the point is inside the shape.
+proc nearestPointQuery*(shape: PShape; p: TVector; res: PNearestPointQueryInfo): CpFloat {.
+  cdecl, importc: "cpShapeNearestPointQuery", dynlib: Lib.}
+#/ Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure.
+proc segmentQuery*(shape: PShape, a, b: TVector, info: PSegmentQueryInfo): bool {.
+  cdecl, importc: "cpShapeSegmentQuery", dynlib: Lib.}
+
+#/ Get the hit point for a segment query.
+## Possibly change; info to PSegmentQueryInfo 
+proc queryHitPoint*(start, to: TVector, info: TSegmentQueryInfo): TVector {.inline.} =
+  result = start.lerp(to, info.t)
+
+#/ Get the hit distance for a segment query.
+proc queryHitDist*(start, to: TVector, info: TSegmentQueryInfo): CpFloat {.inline.} =
+  result = start.dist(to) * info.t
+
+defGetter(PShape, PSpace, space, Space)
+
+defGetter(PShape, PBody, body, Body)
+proc setBody*(shape: PShape, value: PBody) {.
+  cdecl, importc: "cpShapeSetBody", dynlib: Lib.}
+
+
+defGetter(PShape, TBB, bb, BB)
+defShapeProp(Bool32, sensor, Sensor, true)
+defShapeProp(CpFloat, e, Elasticity, false)
+defShapeProp(CpFloat, u, Friction, true)
+defShapeProp(TVector, surface_v, SurfaceVelocity, true)
+defShapeProp(pointer, data, UserData, false)
+defShapeProp(TCollisionType, collision_type, CollisionType, true)
+defShapeProp(TGroup, group, Group, true)
+defShapeProp(TLayers, layers, Layers, true)
+
+#/ When initializing a shape, it's hash value comes from a counter.
+#/ Because the hash value may affect iteration order, you can reset the shape ID counter
+#/ when recreating a space. This will make the simulation be deterministic.
+proc resetShapeIdCounter*(): void {.cdecl, importc: "cpResetShapeIdCounter", dynlib: Lib.}
+#/ Allocate a circle shape.
+proc CircleShapeAlloc*(): PCircleShape {.cdecl, importc: "cpCircleShapeAlloc", dynlib: Lib.}
+#/ Initialize a circle shape.
+proc init*(circle: PCircleShape, body: PBody, radius: CpFloat, offset: TVector): PCircleShape {.
+  cdecl, importc: "cpCircleShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a circle shape.
+proc newCircleShape*(body: PBody, radius: CpFloat, offset: TVector): PShape {.
+  cdecl, importc: "cpCircleShapeNew", dynlib: Lib.}
+
+proc getCircleOffset*(shape: PShape): TVector {.
+  cdecl, importc: "cpCircleShapeGetOffset", dynlib: Lib.}
+proc getCircleRadius*(shape: PShape): CpFloat {.
+  cdecl, importc: "cpCircleShapeGetRadius", dynlib: Lib.}
+
+
+#/ Allocate a polygon shape.
+proc allocPolyShape*(): PPolyShape {.
+  cdecl, importc: "cpPolyShapeAlloc", dynlib: Lib.}
+#/ Initialize a polygon shape.
+#/ A convex hull will be created from the vertexes.
+proc init*(poly: PPolyShape; body: PBody, numVerts: cint;
+            verts: ptr TVector; offset: TVector): PPolyShape {.
+  cdecl, importc: "cpPolyShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a polygon shape.
+#/ A convex hull will be created from the vertexes.
+proc newPolyShape*(body: PBody; numVerts: cint; verts: ptr TVector; 
+                    offset: TVector): PShape {.
+  cdecl, importc: "cpPolyShapeNew", dynlib: Lib.}
+#/ Initialize a box shaped polygon shape.
+proc init*(poly: PPolyShape; body: PBody; width, height: CpFloat): PPolyShape {.
+  cdecl, importc: "cpBoxShapeInit", dynlib: Lib.}
+#/ Initialize an offset box shaped polygon shape.
+proc init*(poly: PPolyShape; body: PBody; box: TBB): PPolyShape {.
+  cdecl, importc: "cpBoxShapeInit2", dynlib: Lib.}
+#/ Allocate and initialize a box shaped polygon shape.
+proc newBoxShape*(body: PBody; width, height: CpFloat): PShape {.
+  cdecl, importc: "cpBoxShapeNew", dynlib: Lib.}
+#/ Allocate and initialize an offset box shaped polygon shape.
+proc newBoxShape*(body: PBody; box: TBB): PShape {.
+  cdecl, importc: "cpBoxShapeNew2", dynlib: Lib.}
+
+#/ Check that a set of vertexes is convex and has a clockwise winding.
+#/ NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
+proc validatePoly*(verts: ptr TVector; numVerts: cint): bool {.
+  cdecl, importc: "cpPolyValidate", dynlib: Lib.}
+#/ Get the number of verts in a polygon shape.
+proc getNumVerts*(shape: PShape): cint {.
+  cdecl, importc: "cpPolyShapeGetNumVerts", dynlib: Lib.}
+#/ Get the @c ith vertex of a polygon shape.
+proc getVert*(shape: PShape; index: cint): TVector {.
+  cdecl, importc: "cpPolyShapeGetVert", dynlib: Lib.}
+
+#/ Allocate a segment shape.
+proc allocSegmentShape*(): PSegmentShape {.
+  cdecl, importc: "cpSegmentShapeAlloc", dynlib: Lib.}
+#/ Initialize a segment shape.
+proc init*(seg: PSegmentShape, body: PBody, a, b: TVector, radius: CpFloat): PSegmentShape {.
+  cdecl, importc: "cpSegmentShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a segment shape.
+proc newSegmentShape*(body: PBody, a, b: TVector, radius: CpFloat): PShape {.
+  cdecl, importc: "cpSegmentShapeNew", dynlib: Lib.}
+
+proc setSegmentNeighbors*(shape: PShape, prev, next: TVector) {.
+  cdecl, importc: "cpSegmentShapeSetNeighbors", dynlib: Lib.}
+proc getSegmentA*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetA", dynlib: Lib.}
+proc getSegmentB*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetB", dynlib: Lib.}
+proc getSegmentNormal*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetNormal", dynlib: Lib.}
+proc getSegmentRadius*(shape: PShape): CpFloat {.
+  cdecl, importc: "cpSegmentShapeGetRadius", dynlib: Lib.}
+
+
+#/ Version string.
+#var VersionString*{.importc: "cpVersionString", dynlib: Lib.}: cstring
+#/ Calculate the moment of inertia for a circle.
+#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+when defined(MoreNim):
+  proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.cdecl.} =
+    result = m * (0.5 * (r1 * r1 + r2 * r2) + lenSq(offset))
+else:
+  proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.
+    cdecl, importc: "cpMomentForCircle", dynlib: Lib.}
+
+#/ Calculate area of a hollow circle.
+#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+proc AreaForCircle*(r1: CpFloat; r2: CpFloat): CpFloat {.
+  cdecl, importc: "cpAreaForCircle", dynlib: Lib.}
+#/ Calculate the moment of inertia for a line segment.
+#/ Beveling radius is not supported.
+proc MomentForSegment*(m: CpFloat; a, b: TVector): CpFloat {.
+  cdecl, importc: "cpMomentForSegment", dynlib: Lib.}
+#/ Calculate the area of a fattened (capsule shaped) line segment.
+proc AreaForSegment*(a, b: TVector; r: CpFloat): CpFloat {.
+  cdecl, importc: "cpAreaForSegment", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex.
+proc MomentForPoly*(m: CpFloat; numVerts: cint; verts: ptr TVector; offset: TVector): CpFloat {.
+  cdecl, importc: "cpMomentForPoly", dynlib: Lib.}
+#/ Calculate the signed area of a polygon. A Clockwise winding gives positive area.
+#/ This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes.
+proc AreaForPoly*(numVerts: cint; verts: ptr TVector): CpFloat {.
+  cdecl, importc: "cpAreaForPoly", dynlib: Lib.}
+#/ Calculate the natural centroid of a polygon.
+proc CentroidForPoly*(numVerts: cint; verts: ptr TVector): TVector {.
+  cdecl, importc: "cpCentroidForPoly", dynlib: Lib.}
+#/ Center the polygon on the origin. (Subtracts the centroid of the polygon from each vertex)
+proc RecenterPoly*(numVerts: cint; verts: ptr TVector) {.
+  cdecl, importc: "cpRecenterPoly", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid box.
+proc MomentForBox*(m, width, height: CpFloat): CpFloat {.
+  cdecl, importc: "cpMomentForBox", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid box.
+proc MomentForBox2*(m: CpFloat; box: TBB): CpFloat {.
+  cdecl, importc: "cpMomentForBox2", dynlib: Lib.}
+
+
+
+##constraints
+type 
+  #TODO: all these are private
+  #TODO: defConstraintProp()
+  PPinJoint = ptr TPinJoint
+  TPinJoint{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    dist: CpFloat
+    r1: TVector
+    r2: TVector
+    n: TVector
+    nMass: CpFloat
+    jnAcc: CpFloat
+    jnMax: CpFloat
+    bias: CpFloat
+  PSlideJoint = ptr TSlideJoint
+  TSlideJoint{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    min: CpFloat
+    max: CpFloat
+    r1: TVector
+    r2: TVector
+    n: TVector
+    nMass: CpFloat
+    jnAcc: CpFloat
+    jnMax: CpFloat
+    bias: CpFloat
+  PPivotJoint = ptr TPivotJoint
+  TPivotJoint{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    r1: TVector
+    r2: TVector
+    k1: TVector
+    k2: TVector
+    jAcc: TVector
+    jMaxLen: CpFloat
+    bias: TVector
+  PGrooveJoint = ptr TGrooveJoint
+  TGrooveJoint{.pf.} = object 
+    constraint: PConstraint
+    grv_n: TVector
+    grv_a: TVector
+    grv_b: TVector
+    anchr2: TVector
+    grv_tn: TVector
+    clamp: CpFloat
+    r1: TVector
+    r2: TVector
+    k1: TVector
+    k2: TVector
+    jAcc: TVector
+    jMaxLen: CpFloat
+    bias: TVector
+  PDampedSpring = ptr TDampedSpring
+  TDampedSpring{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    restLength: CpFloat
+    stiffness: CpFloat
+    damping: CpFloat
+    springForceFunc: TDampedSpringForceFunc
+    target_vrn: CpFloat
+    v_coef: CpFloat
+    r1: TVector
+    r2: TVector
+    nMass: CpFloat
+    n: TVector
+  PDampedRotarySpring = ptr TDampedRotarySpring
+  TDampedRotarySpring{.pf.} = object 
+    constraint: PConstraint
+    restAngle: CpFloat
+    stiffness: CpFloat
+    damping: CpFloat
+    springTorqueFunc: TDampedRotarySpringTorqueFunc
+    target_wrn: CpFloat
+    w_coef: CpFloat
+    iSum: CpFloat
+  PRotaryLimitJoint = ptr TRotaryLimitJoint
+  TRotaryLimitJoint{.pf.} = object 
+    constraint: PConstraint
+    min: CpFloat
+    max: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PRatchetJoint = ptr TRatchetJoint
+  TRatchetJoint{.pf.} = object 
+    constraint: PConstraint
+    angle: CpFloat
+    phase: CpFloat
+    ratchet: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PGearJoint = ptr TGearJoint
+  TGearJoint{.pf.} = object 
+    constraint: PConstraint
+    phase: CpFloat
+    ratio: CpFloat
+    ratio_inv: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PSimpleMotor = ptr TSimpleMotor
+  TSimpleMotor{.pf.} = object 
+    constraint: PConstraint
+    rate: CpFloat
+    iSum: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  TDampedSpringForceFunc* = proc (spring: PConstraint; dist: CpFloat): CpFloat{.
+    cdecl.}
+  TDampedRotarySpringTorqueFunc* = proc (spring: PConstraint; 
+      relativeAngle: CpFloat): CpFloat {.cdecl.}
+#/ Destroy a constraint.
+proc destroy*(constraint: PConstraint){.
+  cdecl, importc: "cpConstraintDestroy", dynlib: Lib.}
+#/ Destroy and free a constraint.111
+proc free*(constraint: PConstraint){.
+  cdecl, importc: "cpConstraintFree", dynlib: Lib.}
+
+#/ @private
+proc activateBodies(constraint: PConstraint) {.inline.} = 
+  if not constraint.a.isNil: constraint.a.activate()
+  if not constraint.b.isNil: constraint.b.activate()
+
+# /// @private
+# #define CP_DefineConstraintStructGetter(type, member, name) \
+# static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;}
+# /// @private
+# #define CP_DefineConstraintStructSetter(type, member, name) \
+# static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \
+# 	cpConstraintActivateBodies(constraint); \
+# 	constraint->member = value; \
+# }
+template defConstraintSetter(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
+    activateBodies(constraint)
+    constraint.member = value
+template defConstraintProp(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  defGetter(PConstraint, memberType, member, name)
+  defConstraintSetter(memberType, member, name)
+# CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
+defGetter(PConstraint, PSpace, space, Space)
+defGetter(PConstraint, PBody, a, A)
+defGetter(PConstraint, PBody, a, B)
+defGetter(PConstraint, CpFloat, maxForce, MaxForce)
+defGetter(PConstraint, CpFloat, errorBias, ErrorBias)
+defGetter(PConstraint, CpFloat, maxBias, MaxBias)
+defGetter(PConstraint, TConstraintPreSolveFunc, preSolve, PreSolveFunc)
+defGetter(PConstraint, TConstraintPostSolveFunc, postSolve, PostSolveFunc)
+defGetter(PConstraint, CpDataPointer, data, UserData)
+# Get the last impulse applied by this constraint.
+proc getImpulse*(constraint: PConstraint): CpFloat {.inline.} = 
+  return constraint.klass.getImpulse(constraint)
+
+# #define cpConstraintCheckCast(constraint, struct) \
+# 	cpAssertHard(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct)
+# #define CP_DefineConstraintGetter(struct, type, member, name) \
+# static inline type struct##Get##name(const cpConstraint *constraint){ \
+# 	cpConstraintCheckCast(constraint, struct); \
+# 	return ((struct *)constraint)->member; \
+# }
+# #define CP_DefineConstraintSetter(struct, type, member, name) \
+# static inline void struct##Set##name(cpConstraint *constraint, type value){ \
+# 	cpConstraintCheckCast(constraint, struct); \
+# 	cpConstraintActivateBodies(constraint); \
+# 	((struct *)constraint)->member = value; \
+# }
+template constraintCheckCast(constraint: PConstraint, ctype: expr): stmt {.immediate.} =
+  assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class")
+template defCGetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = 
+  proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} =
+    constraintCheckCast(constraint, ctype)
+    result = cast[`P ctype`](constraint).member
+template defCSetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
+    constraintCheckCast(constraint, ctype)
+    activateBodies(constraint)
+    cast[`P ctype`](constraint).member = value
+template defCProp(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  defCGetter(ctype, memberType, member, name)
+  defCSetter(ctype, memberType, member, name)
+
+proc PinJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpPinJointGetClass", dynlib: Lib.}
+#/ @private
+
+#/ Allocate a pin joint.
+proc AllocPinJoint*(): PPinJoint{.
+  cdecl, importc: "cpPinJointAlloc", dynlib: Lib.}
+#/ Initialize a pin joint.
+proc PinJointInit*(joint: PPinJoint; a: PBody; b: PBody; anchr1: TVector; 
+                   anchr2: TVector): PPinJoint{.
+  cdecl, importc: "cpPinJointInit", dynlib: Lib.}
+#/ Allocate and initialize a pin joint.
+proc newPinJoint*(a: PBody; b: PBody; anchr1: TVector; anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpPinJointNew", dynlib: Lib.}
+# CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1)
+defCProp(PinJoint, TVector, anchr1, Anchr1)
+defCProp(PinJoint, TVector, anchr2, Anchr2)
+defCProp(PinJoint, CpFloat, dist, Dist)
+
+proc SlideJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpSlideJointGetClass", dynlib: Lib.}
+#/ Allocate a slide joint.
+proc AllocSlideJoint*(): PSlideJoint{.
+  cdecl, importc: "cpSlideJointAlloc", dynlib: Lib.}
+#/ Initialize a slide joint.
+proc init*(joint: PSlideJoint; a, b: PBody; anchr1, anchr2: TVector;
+            min, max: CpFloat): PSlideJoint{.
+  cdecl, importc: "cpSlideJointInit", dynlib: Lib.}
+#/ Allocate and initialize a slide joint.
+proc newSlideJoint*(a, b: PBody; anchr1, anchr2: TVector; min, max: CpFloat): PConstraint{.
+  cdecl, importc: "cpSlideJointNew", dynlib: Lib.}
+
+defCProp(SlideJoint, TVector, anchr1, Anchr1)
+defCProp(SlideJoint, TVector, anchr2, Anchr2)
+defCProp(SlideJoint, CpFloat, min, Min)
+defCProp(SlideJoint, CpFloat, max, Max)
+
+proc PivotJointGetClass*(): PConstraintClass {.
+  cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.}
+
+#/ Allocate a pivot joint
+proc allocPivotJoint*(): PPivotJoint{.
+  cdecl, importc: "cpPivotJointAlloc", dynlib: Lib.}
+#/ Initialize a pivot joint.
+proc init*(joint: PPivotJoint; a, b: PBody; anchr1, anchr2: TVector): PPivotJoint{.
+  cdecl, importc: "cpPivotJointInit", dynlib: Lib.}
+#/ Allocate and initialize a pivot joint.
+proc newPivotJoint*(a, b: PBody; pivot: TVector): PConstraint{.
+  cdecl, importc: "cpPivotJointNew", dynlib: Lib.}
+#/ Allocate and initialize a pivot joint with specific anchors.
+proc newPivotJoint*(a, b: PBody; anchr1, anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpPivotJointNew2", dynlib: Lib.}
+
+defCProp(PivotJoint, TVector, anchr1, Anchr1)
+defCProp(PivotJoint, TVector, anchr2, Anchr2)
+
+
+proc GrooveJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpGrooveJointGetClass", dynlib: Lib.}
+#/ Allocate a groove joint.
+proc GrooveJointAlloc*(): ptr TGrooveJoint{.
+  cdecl, importc: "cpGrooveJointAlloc", dynlib: Lib.}
+#/ Initialize a groove joint.
+proc Init*(joint: PGrooveJoint; a, b: PBody; groove_a, groove_b, anchr2: TVector): PGrooveJoint{.
+  cdecl, importc: "cpGrooveJointInit", dynlib: Lib.}
+#/ Allocate and initialize a groove joint.
+proc newGrooveJoint*(a, b: PBody; groove_a, groove_b, anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpGrooveJointNew", dynlib: Lib.}
+
+defCGetter(GrooveJoint, TVector, grv_a, GrooveA)
+defCGetter(GrooveJoint, TVector, grv_b, GrooveB)
+# /// Set endpoint a of a groove joint's groove
+proc SetGrooveA*(constraint: PConstraint, value: TVector) {.
+  cdecl, importc: "cpGrooveJointSetGrooveA", dynlib: Lib.}
+# /// Set endpoint b of a groove joint's groove
+proc SetGrooveB*(constraint: PConstraint, value: TVector) {.
+  cdecl, importc: "cpGrooveJointSetGrooveB", dynlib: Lib.}
+defCProp(GrooveJoint, TVector, anchr2, Anchr2)
+
+proc DampedSpringGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpDampedSpringGetClass", dynlib: Lib.}
+#/ Allocate a damped spring.
+proc AllocDampedSpring*(): PDampedSpring{.
+  cdecl, importc: "cpDampedSpringAlloc", dynlib: Lib.}
+#/ Initialize a damped spring.
+proc init*(joint: PDampedSpring; a, b: PBody; anchr1, anchr2: TVector;
+            restLength, stiffness, damping: CpFloat): PDampedSpring{.
+  cdecl, importc: "cpDampedSpringInit", dynlib: Lib.}
+#/ Allocate and initialize a damped spring.
+proc newDampedSpring*(a, b: PBody; anchr1, anchr2: TVector; 
+                      restLength, stiffness, damping: CpFloat): PConstraint{.
+  cdecl, importc: "cpDampedSpringNew", dynlib: Lib.}
+
+# CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1)
+defCProp(DampedSpring, TVector, anchr1, Anchr1)
+defCProp(DampedSpring, TVector, anchr2, Anchr2)
+defCProp(DampedSpring, CpFloat, restLength, RestLength)
+defCProp(DampedSpring, CpFloat, stiffness, Stiffness)
+defCProp(DampedSpring, CpFloat, damping, Damping)
+defCProp(DampedSpring, TDampedSpringForceFunc, springForceFunc, SpringForceFunc)
+
+
+proc DampedRotarySpringGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpDampedRotarySpringGetClass", dynlib: Lib.}
+
+#/ Allocate a damped rotary spring.
+proc DampedRotarySpringAlloc*(): PDampedRotarySpring{.
+  cdecl, importc: "cpDampedRotarySpringAlloc", dynlib: Lib.}
+#/ Initialize a damped rotary spring.
+proc init*(joint: PDampedRotarySpring; a, b: PBody; 
+            restAngle, stiffness, damping: CpFloat): PDampedRotarySpring{.
+  cdecl, importc: "cpDampedRotarySpringInit", dynlib: Lib.}
+#/ Allocate and initialize a damped rotary spring.
+proc DampedRotarySpringNew*(a, b: PBody; restAngle, stiffness, damping: CpFloat): PConstraint{.
+  cdecl, importc: "cpDampedRotarySpringNew", dynlib: Lib.}
+
+defCProp(DampedRotarySpring, CpFloat, restAngle, RestAngle)
+defCProp(DampedRotarySpring, CpFloat, stiffness, Stiffness)
+defCProp(DampedRotarySpring, CpFloat, damping, Damping)
+defCProp(DampedRotarySpring, TDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc)
+
+
+proc RotaryLimitJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpRotaryLimitJointGetClass", dynlib: Lib.}
+#/ Allocate a damped rotary limit joint.
+proc allocRotaryLimitJoint*(): PRotaryLimitJoint{.
+  cdecl, importc: "cpRotaryLimitJointAlloc", dynlib: Lib.}
+#/ Initialize a damped rotary limit joint.
+proc init*(joint: PRotaryLimitJoint; a, b: PBody; min, max: CpFloat): PRotaryLimitJoint{.
+  cdecl, importc: "cpRotaryLimitJointInit", dynlib: Lib.}
+#/ Allocate and initialize a damped rotary limit joint.
+proc newRotaryLimitJoint*(a, b: PBody; min, max: CpFloat): PConstraint{.
+  cdecl, importc: "cpRotaryLimitJointNew", dynlib: Lib.}
+
+defCProp(RotaryLimitJoint, CpFloat, min, Min)
+defCProp(RotaryLimitJoint, CpFloat, max, Max)
+
+
+proc RatchetJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpRatchetJointGetClass", dynlib: Lib.}
+#/ Allocate a ratchet joint.
+proc AllocRatchetJoint*(): PRatchetJoint{.
+  cdecl, importc: "cpRatchetJointAlloc", dynlib: Lib.}
+#/ Initialize a ratched joint.
+proc init*(joint: PRatchetJoint; a, b: PBody; phase, ratchet: CpFloat): PRatchetJoint{.
+  cdecl, importc: "cpRatchetJointInit", dynlib: Lib.}
+#/ Allocate and initialize a ratchet joint.
+proc NewRatchetJoint*(a, b: PBody; phase, ratchet: CpFloat): PConstraint{.
+  cdecl, importc: "cpRatchetJointNew", dynlib: Lib.}
+
+defCProp(RatchetJoint, CpFloat, angle, Angle)
+defCProp(RatchetJoint, CpFloat, phase, Phase)
+defCProp(RatchetJoint, CpFloat, ratchet, Ratchet)
+
+
+proc GearJointGetClass*(): PConstraintClass{.cdecl, 
+    importc: "cpGearJointGetClass", dynlib: Lib.}
+#/ Allocate a gear joint.
+proc AllocGearJoint*(): PGearJoint{.
+  cdecl, importc: "cpGearJointAlloc", dynlib: Lib.}
+#/ Initialize a gear joint.
+proc init*(joint: PGearJoint; a, b: PBody, phase, ratio: CpFloat): PGearJoint{.
+  cdecl, importc: "cpGearJointInit", dynlib: Lib.}
+#/ Allocate and initialize a gear joint.
+proc NewGearJoint*(a, b: PBody; phase, ratio: CpFloat): PConstraint{.
+  cdecl, importc: "cpGearJointNew", dynlib: Lib.}
+
+defCProp(GearJoint, CpFloat, phase, Phase)
+defCGetter(GearJoint, CpFloat, ratio, Ratio)
+#/ Set the ratio of a gear joint.
+proc GearJointSetRatio*(constraint: PConstraint; value: CpFloat){.
+  cdecl, importc: "cpGearJointSetRatio", dynlib: Lib.}
+
+
+proc SimpleMotorGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpSimpleMotorGetClass", dynlib: Lib.}
+#/ Allocate a simple motor.
+proc AllocSimpleMotor*(): PSimpleMotor{.
+  cdecl, importc: "cpSimpleMotorAlloc", dynlib: Lib.}
+#/ initialize a simple motor.
+proc init*(joint: PSimpleMotor; a, b: PBody; 
+                      rate: CpFloat): PSimpleMotor{.
+  cdecl, importc: "cpSimpleMotorInit", dynlib: Lib.}
+#/ Allocate and initialize a simple motor.
+proc newSimpleMotor*(a, b: PBody; rate: CpFloat): PConstraint{.
+  cdecl, importc: "cpSimpleMotorNew", dynlib: Lib.}
+
+defCProp(SimpleMotor, CpFloat, rate, Rate)
+
+
+
diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
new file mode 100644
index 000000000..93857207a
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
@@ -0,0 +1,613 @@
+discard """Copyright (c) 2002-2012 Lee Salzman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of 
+this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+const Lib = "libenet.so.1(|.0.3)"
+
+{.deadCodeElim: on.}
+const 
+  ENET_VERSION_MAJOR* = 1
+  ENET_VERSION_MINOR* = 3
+  ENET_VERSION_PATCH* = 3
+template ENET_VERSION_CREATE(major, minor, patch: expr): expr = 
+  (((major) shl 16) or ((minor) shl 8) or (patch))
+
+const 
+  ENET_VERSION* = ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, 
+                                      ENET_VERSION_PATCH)
+type 
+  TVersion* = cuint
+  TSocketType*{.size: sizeof(cint).} = enum 
+    ENET_SOCKET_TYPE_STREAM = 1, ENET_SOCKET_TYPE_DATAGRAM = 2
+  TSocketWait*{.size: sizeof(cint).} = enum 
+    ENET_SOCKET_WAIT_NONE = 0, ENET_SOCKET_WAIT_SEND = (1 shl 0), 
+    ENET_SOCKET_WAIT_RECEIVE = (1 shl 1)
+  TSocketOption*{.size: sizeof(cint).} = enum 
+    ENET_SOCKOPT_NONBLOCK = 1, ENET_SOCKOPT_BROADCAST = 2, 
+    ENET_SOCKOPT_RCVBUF = 3, ENET_SOCKOPT_SNDBUF = 4, 
+    ENET_SOCKOPT_REUSEADDR = 5
+const 
+  ENET_HOST_ANY* = 0
+  ENET_HOST_BROADCAST* = 0xFFFFFFFF
+  ENET_PORT_ANY* = 0
+  
+  ENET_PROTOCOL_MINIMUM_MTU* = 576
+  ENET_PROTOCOL_MAXIMUM_MTU* = 4096
+  ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS* = 32
+  ENET_PROTOCOL_MINIMUM_WINDOW_SIZE* = 4096
+  ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE* = 32768
+  ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT* = 1
+  ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT* = 255
+  ENET_PROTOCOL_MAXIMUM_PEER_ID* = 0x00000FFF
+type
+  PAddress* = ptr TAddress
+  TAddress*{.pure, final.} = object 
+    host*: cuint
+    port*: cushort
+  
+  TPacketFlag*{.size: sizeof(cint).} = enum 
+    FlagReliable = (1 shl 0), 
+    FlagUnsequenced = (1 shl 1), 
+    NoAllocate = (1 shl 2), 
+    UnreliableFragment = (1 shl 3)
+  
+  TENetListNode*{.pure, final.} = object 
+      next*: ptr T_ENetListNode
+      previous*: ptr T_ENetListNode
+
+  PENetListIterator* = ptr TENetListNode
+  TENetList*{.pure, final.} = object 
+    sentinel*: TENetListNode
+  
+  T_ENetPacket*{.pure, final.} = object 
+  TPacketFreeCallback* = proc (a2: ptr T_ENetPacket){.cdecl.}
+  
+  PPacket* = ptr TPacket
+  TPacket*{.pure, final.} = object 
+    referenceCount: csize
+    flags*: cint
+    data*: cstring#ptr cuchar
+    dataLength*: csize
+    freeCallback*: TPacketFreeCallback
+
+  PAcknowledgement* = ptr TAcknowledgement
+  TAcknowledgement*{.pure, final.} = object 
+    acknowledgementList*: TEnetListNode
+    sentTime*: cuint
+    command*: TEnetProtocol
+
+  POutgoingCommand* = ptr TOutgoingCommand
+  TOutgoingCommand*{.pure, final.} = object 
+    outgoingCommandList*: TEnetListNode
+    reliableSequenceNumber*: cushort
+    unreliableSequenceNumber*: cushort
+    sentTime*: cuint
+    roundTripTimeout*: cuint
+    roundTripTimeoutLimit*: cuint
+    fragmentOffset*: cuint
+    fragmentLength*: cushort
+    sendAttempts*: cushort
+    command*: TEnetProtocol
+    packet*: PPacket
+
+  PIncomingCommand* = ptr TIncomingCommand
+  TIncomingCommand*{.pure, final.} = object 
+    incomingCommandList*: TEnetListNode
+    reliableSequenceNumber*: cushort
+    unreliableSequenceNumber*: cushort
+    command*: TEnetProtocol
+    fragmentCount*: cuint
+    fragmentsRemaining*: cuint
+    fragments*: ptr cuint
+    packet*: ptr TPacket
+
+  TPeerState*{.size: sizeof(cint).} = enum 
+    ENET_PEER_STATE_DISCONNECTED = 0, ENET_PEER_STATE_CONNECTING = 1, 
+    ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, 
+    ENET_PEER_STATE_CONNECTION_PENDING = 3, 
+    ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, ENET_PEER_STATE_CONNECTED = 5, 
+    ENET_PEER_STATE_DISCONNECT_LATER = 6, ENET_PEER_STATE_DISCONNECTING = 7, 
+    ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, ENET_PEER_STATE_ZOMBIE = 9
+  
+  TENetProtocolCommand*{.size: sizeof(cint).} = enum 
+    ENET_PROTOCOL_COMMAND_NONE = 0, ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, 
+    ENET_PROTOCOL_COMMAND_CONNECT = 2, 
+    ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, 
+    ENET_PROTOCOL_COMMAND_DISCONNECT = 4, ENET_PROTOCOL_COMMAND_PING = 5, 
+    ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, 
+    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, 
+    ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, 
+    ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, 
+    ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, 
+    ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, 
+    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, 
+    ENET_PROTOCOL_COMMAND_COUNT = 13, ENET_PROTOCOL_COMMAND_MASK = 0x0000000F
+  TENetProtocolFlag*{.size: sizeof(cint).} = enum 
+    ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12,
+    ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 shl 6), 
+    ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 shl 7), 
+    ENET_PROTOCOL_HEADER_SESSION_MASK = (3 shl 12), 
+    ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 shl 14), 
+    ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 shl 15),
+    ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED.cint or
+        ENET_PROTOCOL_HEADER_FLAG_SENT_TIME.cint
+  
+  TENetProtocolHeader*{.pure, final.} = object 
+    peerID*: cushort
+    sentTime*: cushort
+
+  TENetProtocolCommandHeader*{.pure, final.} = object 
+    command*: cuchar
+    channelID*: cuchar
+    reliableSequenceNumber*: cushort
+
+  TENetProtocolAcknowledge*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    receivedReliableSequenceNumber*: cushort
+    receivedSentTime*: cushort
+
+  TENetProtocolConnect*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    outgoingPeerID*: cushort
+    incomingSessionID*: cuchar
+    outgoingSessionID*: cuchar
+    mtu*: cuint
+    windowSize*: cuint
+    channelCount*: cuint
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    connectID*: cuint
+    data*: cuint
+
+  TENetProtocolVerifyConnect*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    outgoingPeerID*: cushort
+    incomingSessionID*: cuchar
+    outgoingSessionID*: cuchar
+    mtu*: cuint
+    windowSize*: cuint
+    channelCount*: cuint
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    connectID*: cuint
+
+  TENetProtocolBandwidthLimit*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+
+  TENetProtocolThrottleConfigure*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+
+  TENetProtocolDisconnect*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    data*: cuint
+
+  TENetProtocolPing*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+
+  TENetProtocolSendReliable*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    dataLength*: cushort
+
+  TENetProtocolSendUnreliable*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    unreliableSequenceNumber*: cushort
+    dataLength*: cushort
+
+  TENetProtocolSendUnsequenced*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    unsequencedGroup*: cushort
+    dataLength*: cushort
+
+  TENetProtocolSendFragment*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    startSequenceNumber*: cushort
+    dataLength*: cushort
+    fragmentCount*: cuint
+    fragmentNumber*: cuint
+    totalLength*: cuint
+    fragmentOffset*: cuint
+  
+  ## this is incomplete; need helper templates or something
+  ## ENetProtocol
+  TENetProtocol*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+const 
+  ENET_BUFFER_MAXIMUM* = (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
+  ENET_HOST_RECEIVE_BUFFER_SIZE          = 256 * 1024
+  ENET_HOST_SEND_BUFFER_SIZE             = 256 * 1024
+  ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL  = 1000
+  ENET_HOST_DEFAULT_MTU                  = 1400
+
+  ENET_PEER_DEFAULT_ROUND_TRIP_TIME      = 500
+  ENET_PEER_DEFAULT_PACKET_THROTTLE      = 32
+  ENET_PEER_PACKET_THROTTLE_SCALE        = 32
+  ENET_PEER_PACKET_THROTTLE_COUNTER      = 7
+  ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2
+  ENET_PEER_PACKET_THROTTLE_DECELERATION = 2
+  ENET_PEER_PACKET_THROTTLE_INTERVAL     = 5000
+  ENET_PEER_PACKET_LOSS_SCALE            = (1 shl 16)
+  ENET_PEER_PACKET_LOSS_INTERVAL         = 10000
+  ENET_PEER_WINDOW_SIZE_SCALE            = 64 * 1024
+  ENET_PEER_TIMEOUT_LIMIT                = 32
+  ENET_PEER_TIMEOUT_MINIMUM              = 5000
+  ENET_PEER_TIMEOUT_MAXIMUM              = 30000
+  ENET_PEER_PING_INTERVAL                = 500
+  ENET_PEER_UNSEQUENCED_WINDOWS          = 64
+  ENET_PEER_UNSEQUENCED_WINDOW_SIZE      = 1024
+  ENET_PEER_FREE_UNSEQUENCED_WINDOWS     = 32
+  ENET_PEER_RELIABLE_WINDOWS             = 16
+  ENET_PEER_RELIABLE_WINDOW_SIZE         = 0x1000
+  ENET_PEER_FREE_RELIABLE_WINDOWS        = 8
+
+when defined(Linux) or true:
+  import posix
+  const
+    ENET_SOCKET_NULL*: cint = -1
+  type 
+    TENetSocket* = cint
+    PEnetBuffer* = ptr object
+    TENetBuffer*{.pure, final.} = object 
+      data*: pointer
+      dataLength*: csize
+    TENetSocketSet* = Tfd_set
+  ## see if these are different on win32, if not then get rid of these
+  template ENET_HOST_TO_NET_16*(value: expr): expr = 
+    (htons(value))
+  template ENET_HOST_TO_NET_32*(value: expr): expr = 
+    (htonl(value))
+  template ENET_NET_TO_HOST_16*(value: expr): expr = 
+    (ntohs(value))
+  template ENET_NET_TO_HOST_32*(value: expr): expr = 
+    (ntohl(value))
+
+  template ENET_SOCKETSET_EMPTY*(sockset: expr): expr = 
+    FD_ZERO(addr((sockset)))
+  template ENET_SOCKETSET_ADD*(sockset, socket: expr): expr = 
+    FD_SET(socket, addr((sockset)))
+  template ENET_SOCKETSET_REMOVE*(sockset, socket: expr): expr = 
+    FD_CLEAR(socket, addr((sockset)))
+  template ENET_SOCKETSET_CHECK*(sockset, socket: expr): expr = 
+    FD_ISSET(socket, addr((sockset)))
+
+when defined(Windows):
+  ## put the content of win32.h in here
+
+
+type 
+  PChannel* = ptr TChannel
+  TChannel*{.pure, final.} = object 
+    outgoingReliableSequenceNumber*: cushort
+    outgoingUnreliableSequenceNumber*: cushort
+    usedReliableWindows*: cushort
+    reliableWindows*: array[0..ENET_PEER_RELIABLE_WINDOWS - 1, cushort]
+    incomingReliableSequenceNumber*: cushort
+    incomingUnreliableSequenceNumber*: cushort
+    incomingReliableCommands*: TENetList
+    incomingUnreliableCommands*: TENetList
+
+  PPeer* = ptr TPeer
+  TPeer*{.pure, final.} = object 
+    dispatchList*: TEnetListNode
+    host*: ptr THost
+    outgoingPeerID*: cushort
+    incomingPeerID*: cushort
+    connectID*: cuint
+    outgoingSessionID*: cuchar
+    incomingSessionID*: cuchar
+    address*: TAddress
+    data*: pointer
+    state*: TPeerState
+    channels*: PChannel
+    channelCount*: csize
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    incomingBandwidthThrottleEpoch*: cuint
+    outgoingBandwidthThrottleEpoch*: cuint
+    incomingDataTotal*: cuint
+    outgoingDataTotal*: cuint
+    lastSendTime*: cuint
+    lastReceiveTime*: cuint
+    nextTimeout*: cuint
+    earliestTimeout*: cuint
+    packetLossEpoch*: cuint
+    packetsSent*: cuint
+    packetsLost*: cuint
+    packetLoss*: cuint
+    packetLossVariance*: cuint
+    packetThrottle*: cuint
+    packetThrottleLimit*: cuint
+    packetThrottleCounter*: cuint
+    packetThrottleEpoch*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    packetThrottleInterval*: cuint
+    lastRoundTripTime*: cuint
+    lowestRoundTripTime*: cuint
+    lastRoundTripTimeVariance*: cuint
+    highestRoundTripTimeVariance*: cuint
+    roundTripTime*: cuint
+    roundTripTimeVariance*: cuint
+    mtu*: cuint
+    windowSize*: cuint
+    reliableDataInTransit*: cuint
+    outgoingReliableSequenceNumber*: cushort
+    acknowledgements*: TENetList
+    sentReliableCommands*: TENetList
+    sentUnreliableCommands*: TENetList
+    outgoingReliableCommands*: TENetList
+    outgoingUnreliableCommands*: TENetList
+    dispatchedCommands*: TENetList
+    needsDispatch*: cint
+    incomingUnsequencedGroup*: cushort
+    outgoingUnsequencedGroup*: cushort
+    unsequencedWindow*: array[0..ENET_PEER_UNSEQUENCED_WINDOW_SIZE div 32 - 1, 
+                              cuint]
+    eventData*: cuint
+
+  PCompressor* = ptr TCompressor
+  TCompressor*{.pure, final.} = object 
+    context*: pointer
+    compress*: proc (context: pointer; inBuffers: ptr TEnetBuffer; 
+                     inBufferCount: csize; inLimit: csize; 
+                     outData: ptr cuchar; outLimit: csize): csize{.cdecl.}
+    decompress*: proc (context: pointer; inData: ptr cuchar; inLimit: csize; 
+                       outData: ptr cuchar; outLimit: csize): csize{.cdecl.}
+    destroy*: proc (context: pointer){.cdecl.}
+
+  TChecksumCallback* = proc (buffers: ptr TEnetBuffer; bufferCount: csize): cuint{.
+      cdecl.}
+  
+  PHost* = ptr THost
+  THost*{.pure, final.} = object 
+    socket*: TEnetSocket
+    address*: TAddress
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    bandwidthThrottleEpoch*: cuint
+    mtu*: cuint
+    randomSeed*: cuint
+    recalculateBandwidthLimits*: cint
+    peers*: ptr TPeer
+    peerCount*: csize
+    channelLimit*: csize
+    serviceTime*: cuint
+    dispatchQueue*: TEnetList
+    continueSending*: cint
+    packetSize*: csize
+    headerFlags*: cushort
+    commands*: array[0..ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS - 1, 
+                     TEnetProtocol]
+    commandCount*: csize
+    buffers*: array[0..ENET_BUFFER_MAXIMUM - 1, TEnetBuffer]
+    bufferCount*: csize
+    checksum*: TChecksumCallback
+    compressor*: TCompressor
+    packetData*: array[0..ENET_PROTOCOL_MAXIMUM_MTU - 1, 
+                       array[0..2 - 1, cuchar]]
+    receivedAddress*: TAddress
+    receivedData*: ptr cuchar
+    receivedDataLength*: csize
+    totalSentData*: cuint
+    totalSentPackets*: cuint
+    totalReceivedData*: cuint
+    totalReceivedPackets*: cuint
+  
+  TEventType*{.size: sizeof(cint).} = enum 
+    EvtNone = 0, EvtConnect = 1, 
+    EvtDisconnect = 2, EvtReceive = 3
+  PEvent* = ptr TEvent
+  TEvent*{.pure, final.} = object 
+    kind*: TEventType
+    peer*: ptr TPeer
+    channelID*: cuchar
+    data*: cuint
+    packet*: ptr TPacket
+
+  TENetCallbacks*{.pure, final.} = object 
+    malloc*: proc (size: csize): pointer{.cdecl.}
+    free*: proc (memory: pointer){.cdecl.}
+    no_memory*: proc (){.cdecl.}
+
+{.push callConv:cdecl.}
+proc enet_malloc*(a2: csize): pointer{.
+  importc: "enet_malloc", dynlib: Lib.}
+proc enet_free*(a2: pointer){.
+  importc: "enet_free", dynlib: Lib.}
+
+proc enetInit*(): cint{.
+  importc: "enet_initialize", dynlib: Lib.}
+proc enetInit*(version: TVersion; inits: ptr TENetCallbacks): cint{.
+  importc: "enet_initialize_with_callbacks", dynlib: Lib.}
+proc enetDeinit*(){.
+  importc: "enet_deinitialize", dynlib: Lib.}
+proc enet_time_get*(): cuint{.
+  importc: "enet_time_get", dynlib: Lib.}
+proc enet_time_set*(a2: cuint){.
+  importc: "enet_time_set", dynlib: Lib.}
+
+#enet docs are pretty lacking, i'm not sure what the names of these arguments should be
+proc createSocket*(kind: TSocketType): TEnetSocket{.
+  importc: "enet_socket_create", dynlib: Lib.}
+proc bindTo*(socket: TEnetSocket; address: var TAddress): cint{.
+  importc: "enet_socket_bind", dynlib: Lib.}
+proc bindTo*(socket: TEnetSocket; address: ptr TAddress): cint{.
+  importc: "enet_socket_bind", dynlib: Lib.}
+proc listen*(socket: TEnetSocket; a3: cint): cint{.
+  importc: "enet_socket_listen", dynlib: Lib.}
+proc accept*(socket: TEnetSocket; address: var TAddress): TEnetSocket{.
+  importc: "enet_socket_accept", dynlib: Lib.}
+proc accept*(socket: TEnetSocket; address: ptr TAddress): TEnetSocket{.
+  importc: "enet_socket_accept", dynlib: Lib.}
+proc connect*(socket: TEnetSocket; address: var TAddress): cint{.
+  importc: "enet_socket_connect", dynlib: Lib.}
+proc connect*(socket: TEnetSocket; address: ptr TAddress): cint{.
+  importc: "enet_socket_connect", dynlib: Lib.}
+proc send*(socket: TEnetSocket; address: var TAddress; buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_send", dynlib: Lib.}
+proc send*(socket: TEnetSocket; address: ptr TAddress; buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_send", dynlib: Lib.}
+proc receive*(socket: TEnetSocket; address: var TAddress; 
+               buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_receive", dynlib: Lib.}
+proc receive*(socket: TEnetSocket; address: ptr TAddress; 
+               buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_receive", dynlib: Lib.}
+proc wait*(socket: TEnetSocket; a3: ptr cuint; a4: cuint): cint{.
+  importc: "enet_socket_wait", dynlib: Lib.}
+proc setOption*(socket: TEnetSocket; a3: TSocketOption; a4: cint): cint{.
+  importc: "enet_socket_set_option", dynlib: Lib.}
+proc destroy*(socket: TEnetSocket){.
+  importc: "enet_socket_destroy", dynlib: Lib.}
+proc select*(socket: TEnetSocket; a3: ptr TENetSocketSet; 
+              a4: ptr TENetSocketSet; a5: cuint): cint{.
+  importc: "enet_socketset_select", dynlib: Lib.}
+
+proc setHost*(address: PAddress; hostName: cstring): cint{.
+  importc: "enet_address_set_host", dynlib: Lib.}
+proc setHost*(address: var TAddress; hostName: cstring): cint{.
+  importc: "enet_address_set_host", dynlib: Lib.}
+proc getHostIP*(address: var TAddress; hostName: cstring; nameLength: csize): cint{.
+  importc: "enet_address_get_host_ip", dynlib: Lib.}
+proc getHost*(address: var TAddress; hostName: cstring; nameLength: csize): cint{.
+  importc: "enet_address_get_host", dynlib: Lib.}
+
+## Call the above two funcs but trim the result string
+proc getHostIP*(address: var TAddress; hostName: var string; nameLength: csize): cint{.inline.} =
+  hostName.setLen nameLength
+  result = getHostIP(address, cstring(hostName), nameLength)
+  if result == 0:
+    hostName.setLen(len(cstring(hostName)))
+proc getHost*(address: var TAddress; hostName: var string; nameLength: csize): cint{.inline.} =
+  hostName.setLen nameLength
+  result = getHost(address, cstring(hostName), nameLength)
+  if result == 0:
+    hostName.setLen(len(cstring(hostName)))
+
+proc createPacket*(data: pointer; len: csize; flag: TPacketFlag): PPacket{.
+  importc: "enet_packet_create", dynlib: Lib.}
+proc destroy*(packet: PPacket){.
+  importc: "enet_packet_destroy", dynlib: Lib.}
+proc resize*(packet: PPacket; dataLength: csize): cint{.
+  importc: "enet_packet_resize", dynlib: Lib.}
+
+proc crc32*(buffers: ptr TEnetBuffer; bufferCount: csize): cuint{.
+  importc: "enet_crc32", dynlib: Lib.}
+
+proc createHost*(address: ptr TAddress; maxConnections, maxChannels: csize; downSpeed, upSpeed: cuint): PHost{.
+  importc: "enet_host_create", dynlib: Lib.}
+proc createHost*(address: var TAddress; maxConnections, maxChannels: csize; downSpeed, upSpeed: cuint): PHost{.
+  importc: "enet_host_create", dynlib: Lib.}
+proc destroy*(host: PHost){.
+  importc: "enet_host_destroy", dynlib: Lib.}
+proc connect*(host: PHost; address: ptr TAddress; channelCount: csize; data: cuint): PPeer{.
+  importc: "enet_host_connect", dynlib: Lib.}
+proc connect*(host: PHost; address: var TAddress; channelCount: csize; data: cuint): PPeer{.
+  importc: "enet_host_connect", dynlib: Lib.}
+
+proc checkEvents*(host: PHost; event: var TEvent): cint{.
+  importc: "enet_host_check_events", dynlib: Lib.}
+proc checkEvents*(host: PHost; event: ptr TEvent): cint{.
+  importc: "enet_host_check_events", dynlib: Lib.}
+proc hostService*(host: PHost; event: var TEvent; timeout: cuint): cint{.
+  importc: "enet_host_service", dynlib: Lib.}
+proc hostService*(host: PHost; event: ptr TEvent; timeout: cuint): cint{.
+  importc: "enet_host_service", dynlib: Lib.}
+proc flush*(host: PHost){.
+  importc: "enet_host_flush", dynlib: Lib.}
+proc broadcast*(host: PHost; channelID: cuchar; packet: PPacket){.
+  importc: "enet_host_broadcast", dynlib: Lib.}
+proc compress*(host: PHost; compressor: PCompressor){.
+  importc: "enet_host_compress", dynlib: Lib.}
+proc compressWithRangeCoder*(host: PHost): cint{.
+  importc: "enet_host_compress_with_range_coder", dynlib: Lib.}
+proc channelLimit*(host: PHost; channelLimit: csize){.
+  importc: "enet_host_channel_limit", dynlib: Lib.}
+proc bandwidthLimit*(host: PHost; incoming, outgoing: cuint){.
+  importc: "enet_host_bandwidth_limit", dynlib: Lib.}
+proc bandwidthThrottle*(host: PHost){.
+  importc: "enet_host_bandwidth_throttle", dynlib: Lib.}
+
+
+proc send*(peer: PPeer; channel: cuchar; packet: PPacket): cint{.
+  importc: "enet_peer_send", dynlib: Lib.}
+proc receive*(peer: PPeer; channelID: ptr cuchar): PPacket{.
+  importc: "enet_peer_receive", dynlib: Lib.}
+proc ping*(peer: PPeer){.
+  importc: "enet_peer_ping", dynlib: Lib.}
+proc reset*(peer: PPeer){.
+  importc: "enet_peer_reset", dynlib: Lib.}
+proc disconnect*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect", dynlib: Lib.}
+proc disconnectNow*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect_now", dynlib: Lib.}
+proc disconnectLater*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect_later", dynlib: Lib.}
+proc throttleConfigure*(peer: PPeer; interval, acceleration, deceleration: cuint){.
+  importc: "enet_peer_throttle_configure", dynlib: Lib.}
+proc throttle*(peer: PPeer; rtt: cuint): cint{.
+  importc: "enet_peer_throttle", dynlib: Lib.}
+proc resetQueues*(peer: PPeer){.
+  importc: "enet_peer_reset_queues", dynlib: Lib.}
+proc setupOutgoingCommand*(peer: PPeer; outgoingCommand: POutgoingCommand){.
+  importc: "enet_peer_setup_outgoing_command", dynlib: Lib.}
+
+proc queueOutgoingCommand*(peer: PPeer; command: ptr TEnetProtocol; 
+          packet: PPacket; offset: cuint; length: cushort): POutgoingCommand{.
+  importc: "enet_peer_queue_outgoing_command", dynlib: Lib.}
+proc queueIncomingCommand*(peer: PPeer; command: ptr TEnetProtocol; 
+                    packet: PPacket; fragmentCount: cuint): PIncomingCommand{.
+  importc: "enet_peer_queue_incoming_command", dynlib: Lib.}
+proc queueAcknowledgement*(peer: PPeer; command: ptr TEnetProtocol; 
+                            sentTime: cushort): PAcknowledgement{.
+  importc: "enet_peer_queue_acknowledgement", dynlib: Lib.}
+proc dispatchIncomingUnreliableCommands*(peer: PPeer; channel: PChannel){.
+  importc: "enet_peer_dispatch_incoming_unreliable_commands", dynlib: Lib.}
+proc dispatchIncomingReliableCommands*(peer: PPeer; channel: PChannel){.
+  importc: "enet_peer_dispatch_incoming_reliable_commands", dynlib: Lib.}
+
+proc createRangeCoder*(): pointer{.
+  importc: "enet_range_coder_create", dynlib: Lib.}
+proc rangeCoderDestroy*(context: pointer){.
+  importc: "enet_range_coder_destroy", dynlib: Lib.}
+proc rangeCoderCompress*(context: pointer; inBuffers: PEnetBuffer; inLimit, 
+               bufferCount: csize; outData: cstring; outLimit: csize): csize{.
+  importc: "enet_range_coder_compress", dynlib: Lib.}
+proc rangeCoderDecompress*(context: pointer; inData: cstring; inLimit: csize; 
+                            outData: cstring; outLimit: csize): csize{.
+  importc: "enet_range_coder_decompress", dynlib: Lib.}
+proc protocolCommandSize*(commandNumber: cuchar): csize{.
+  importc: "enet_protocol_command_size", dynlib: Lib.}
+
+{.pop.}
+
+from hashes import `!$`, `!&`, THash, hash
+proc hash*(x: TAddress): THash {.nimcall, noSideEffect.} =
+  result = !$(hash(x.host.int32) !& hash(x.port.int16))
+
diff --git a/tests/manyloc/keineschweine/dependencies/enet/testclient.nim b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim
new file mode 100644
index 000000000..2447a1fb5
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim
@@ -0,0 +1,49 @@
+import enet, strutils
+
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+var
+  address: enet.TAddress
+  event: TEvent
+  peer: PPeer
+  client: PHost
+
+client = createHost(nil, 1, 2, 0, 0)
+if client == nil:
+  quit "Could not create client!"
+
+if setHost(addr address, "localhost") != 0:
+  quit "Could not set host"
+address.port = 8024
+
+peer = client.connect(addr address, 2, 0)
+if peer == nil:
+  quit "No available peers"
+
+block:
+  var bConnected = false
+  while not bConnected:
+    if client.hostService(event, 5000) > 0 and event.kind == EvtConnect:
+      echo "Connected"
+      bConnected = true
+    else:
+      echo "Connection failed"
+      quit 0
+
+var runServer = true
+while client.hostService(event, 1000) >= 0 and runServer:
+  case event.kind
+  of EvtReceive:
+    echo "Recvd ($1) $2 ".format(
+      event.packet.dataLength,
+      event.packet.data)
+  of EvtDisconnect:
+    echo "Disconnected"
+    event.peer.data = nil
+    runServer = false
+  of EvtNone: discard
+  else:
+    echo repr(event)
+
+
+client.destroy()
diff --git a/tests/manyloc/keineschweine/dependencies/enet/testserver.nim b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim
new file mode 100644
index 000000000..28a6bd1f7
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim
@@ -0,0 +1,45 @@
+import enet, strutils
+var
+  address: enet.TAddress
+  server: PHost
+  event: TEvent
+
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+
+address.host = EnetHostAny
+address.port = 8024
+
+server = enet.createHost(
+  addr address, 32, 2,  0,  0)
+if server == nil:
+  quit "Could not create the server!"
+
+while server.hostService(addr event, 2500) >= 0:
+  case event.kind
+  of EvtConnect:
+    echo "New client from $1:$2".format(event.peer.address.host, event.peer.address.port)
+    
+    var
+      msg = "hello" 
+      resp = createPacket(cstring(msg), msg.len + 1, FlagReliable)
+      
+    if event.peer.send(0.cuchar, resp) < 0:
+      echo "FAILED"
+    else:
+      echo "Replied"
+  of EvtReceive:
+    echo "Recvd ($1) $2 ".format(
+      event.packet.dataLength,
+      event.packet.data)
+    
+    destroy(event.packet)
+    
+  of EvtDisconnect:
+    echo "Disconnected"
+    event.peer.data = nil
+  else:
+    discard
+
+server.destroy()
+enetDeinit()
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
new file mode 100644
index 000000000..3026cc4b9
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
@@ -0,0 +1,295 @@
+import macros, macro_dsl, streams, streams_enh
+from strutils import format
+
+template newLenName(): stmt {.immediate.} =
+  let lenName {.inject.} = ^("len"& $lenNames)
+  inc(lenNames)
+
+template defPacketImports*(): stmt {.immediate, dirty.} =
+  import macros, macro_dsl, streams, streams_enh
+  from strutils import format
+
+proc `$`*[T](x: seq[T]): string =
+  result = "[seq len="
+  result.add($x.len)
+  result.add ':'
+  for i in 0.. <len(x):
+    result.add "   "
+    result.add($x[i])
+  result.add ']'
+
+macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
+  result = newNimNode(nnkStmtList)
+  let
+    typeName = quoted2ident(typeNameN)
+    packetID = ^"p"
+    streamID = ^"s"
+  var
+    constructorParams = newNimNode(nnkFormalParams).und(typeName)
+    constructor = newNimNode(nnkProcDef).und(
+      postfix(^("new"& $typeName.ident), "*"),
+      emptyNode(),
+      emptyNode(),
+      constructorParams,
+      emptyNode(),
+      emptyNode())
+    pack = newNimNode(nnkProcDef).und(
+      postfix(^"pack", "*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        emptyNode(),   # : void
+        newNimNode(nnkIdentDefs).und(
+          packetID,    # p: var typeName
+          newNimNode(nnkVarTy).und(typeName),
+          emptyNode()),
+        newNimNode(nnkIdentDefs).und(
+          streamID,    # s: PStream
+          ^"PStream",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    read = newNimNode(nnkProcDef).und(
+      newIdentNode("read"& $typeName.ident).postfix("*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        typeName,   #result type
+        newNimNode(nnkIdentDefs).und(
+          streamID, # s: PStream = nil
+          ^"PStream",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    constructorBody = newNimNode(nnkStmtList)
+    packBody = newNimNode(nnkStmtList)
+    readBody = newNimNode(nnkStmtList)
+    lenNames = 0
+  for i in 0.. typeFields.len - 1:
+    let
+      name = typeFields[i][0]
+      dotName = packetID.dot(name)
+      resName = newIdentNode(!"result").dot(name)
+    case typeFields[i][1].kind
+    of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
+      case $typeFields[i][1][0].ident
+      of "paddedstring":
+        let length = typeFields[i][1][1]
+        let padChar = typeFields[i][1][2]
+        packBody.add(newCall(
+          "writePaddedStr", streamID, dotName, length, padChar))
+        ## result.name = readPaddedStr(s, length, char)
+        readBody.add(resName := newCall(
+          "readPaddedStr", streamID, length, padChar))
+        ## make the type a string
+        typeFields[i] = newNimNode(nnkIdentDefs).und(
+          name,
+          ^"string",
+          newNimNode(nnkEmpty))
+      of "array":
+        readBody.add(
+          newNimNode(nnkDiscardStmt).und(
+            newCall("readData", streamID, newNimNode(nnkAddr).und(resName), newCall("sizeof", resName))))
+        packBody.add(
+          newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName)))
+      of "seq":
+        ## let lenX = readInt16(s)
+        newLenName()
+        let
+          item = ^"item"  ## item name in our iterators
+          seqType = typeFields[i][1][1] ## type of seq
+          readName = newIdentNode("read"& $seqType.ident)
+        readBody.add(newNimNode(nnkLetSection).und(
+          newNimNode(nnkIdentDefs).und(
+            lenName,
+            newNimNode(nnkEmpty),
+            newCall("readInt16", streamID))))
+        readBody.add(      ## result.name = @[]
+          resName := ("@".prefix(newNimNode(nnkBracket))),
+          newNimNode(nnkForStmt).und(  ## for item in 1..len:
+            item,
+            infix(1.lit, "..", lenName),
+            newNimNode(nnkStmtList).und(
+              newCall(  ## add(result.name, unpack[seqType](stream))
+                "add", resName, newNimNode(nnkCall).und(readName, streamID)
+        ) ) ) )
+        packbody.add(
+          newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
+            lenName,  ## var lenName = int16(len(p.name))
+            newIdentNode("int16"),
+            newCall("int16", newCall("len", dotName)))),
+          newCall("writeData", streamID, newNimNode(nnkAddr).und(lenName), 2.lit),
+          newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
+            item,
+            infix(0.lit, "..", infix(lenName, "-", 1.lit)),
+            newNimNode(nnkStmtList).und(
+              newCall("echo", item, ": ".lit),
+              newCall("pack", dotName[item], streamID))))
+        #set the default value to @[] (new sequence)
+        typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
+      else:
+        error("Unknown type: "& treeRepr(typeFields[i]))
+    of nnkIdent: ##normal type
+      case $typeFields[i][1].ident
+      of "string": # length encoded string
+        packBody.add(newCall("writeLEStr", streamID, dotName))
+        readBody.add(resName := newCall("readLEStr", streamID))
+      of "int8", "int16", "int32", "float32", "float64", "char", "bool":
+        packBody.add(newCall(
+          "writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName)))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+      else:  ## hopefully the type you specified was another defpacket() type
+        packBody.add(newCall("pack", dotName, streamID))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+    else:
+      error("I dont know what to do with: "& treerepr(typeFields[i]))
+
+  var
+    toStringFunc = newNimNode(nnkProcDef).und(
+      newNimNode(nnkPostfix).und(
+        ^"*",
+        newNimNode(nnkAccQuoted).und(^"$")),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        ^"string",
+        newNimNode(nnkIdentDefs).und(
+          packetID, # p: typeName
+          typeName,
+          emptyNode())),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkStmtList).und(#[6]
+        newNimNode(nnkAsgn).und(
+          ^"result",                  ## result =
+          newNimNode(nnkCall).und(#[6][0][1]
+            ^"format",  ## format
+            emptyNode()))))  ## "[TypeName   $1   $2]"
+    formatStr = "["& $typeName.ident
+
+  const emptyFields = {nnkEmpty, nnkNilLit}
+  var objFields = newNimNode(nnkRecList)
+  for i in 0.. < len(typeFields):
+    let fname = typeFields[i][0]
+    constructorParams.add(newNimNode(nnkIdentDefs).und(
+      fname,
+      typeFields[i][1],
+      typeFields[i][2]))
+    constructorBody.add((^"result").dot(fname) := fname)
+    #export the name
+    typeFields[i][0] = fname.postfix("*")
+    if not(typeFields[i][2].kind in emptyFields):
+      ## empty the type default for the type def
+      typeFields[i][2] = newNimNode(nnkEmpty)
+    objFields.add(typeFields[i])
+    toStringFunc[6][0][1].add(
+      prefix("$", packetID.dot(fname)))
+    formatStr.add "   $"
+    formatStr.add($(i + 1))
+
+  formatStr.add ']'
+  toStringFunc[6][0][1][1] = formatStr.lit()
+
+  result.add(
+    newNimNode(nnkTypeSection).und(
+      newNimNode(nnkTypeDef).und(
+        typeName.postfix("*"),
+        newNimNode(nnkEmpty),
+        newNimNode(nnkObjectTy).und(
+          newNimNode(nnkEmpty), #not sure what this is
+          newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
+          objFields))))
+  result.add(constructor.und(constructorBody))
+  result.add(pack.und(packBody))
+  result.add(read.und(readBody))
+  result.add(toStringFunc)
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+proc `->`(a: string, b: string): NimNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty))
+proc `->`(a: string, b: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty))
+proc `->`(a, b: NimNode): NimNode {.compileTime.} =
+  a[2] = b
+  result = a
+
+proc newProc*(name: string, params: varargs[NimNode], resultType: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkProcDef).und(
+    ^name,
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkFormalParams).und(resultType),
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkStmtList))
+  result[3].add(params)
+macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} =
+  result = newNimNode(nnkStmtList).und(
+    newProc(
+      "read"& $typeName.ident,
+      ["s" -> "PStream" -> newNimNode(nnkNilLit)],
+      typeName),
+    newProc(
+      "pack",
+      [ "p" -> newNimNode(nnkVarTy).und(typeName),
+        "s" -> "PStream" -> newNimNode(nnkNilLit)],
+      emptyNode()))
+  result[0][6].add(newNimNode(nnkDiscardStmt).und(
+    newCall(
+      "readData", ^"s", newNimNode(nnkAddr).und(^"result"), newCall("sizeof", ^"result")
+    )))
+  result[1][6].add(
+    newCall(
+      "writeData", ^"s", newNimNode(nnkAddr).und(^"p"), newCall(
+        "sizeof", ^"p")))
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+template forwardPacketT*(typeName: expr): stmt {.dirty, immediate.} =
+  proc `read typeName`*(s: PStream): typeName =
+    discard readData(s, addr result, sizeof(result))
+  proc `pack typeName`*(p: var typeName; s: PStream) =
+    writeData(s, addr p, sizeof(p))
+
+when isMainModule:
+  type
+    SomeEnum = enum
+      A = 0'i8,
+      B, C
+  forwardPacket(SomeEnum, int8)
+
+
+  defPacket(Foo, tuple[x: array[0..4, int8]])
+  var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
+  var s2 = newStringStream("")
+  f.pack(s2)
+  assert s2.data == "\4\3\2\1\0"
+
+  var s = newStringStream()
+  s.flushImpl = proc(s: PStream) =
+    var z = PStringStream(s)
+    z.setPosition(0)
+    z.data.setLen(0)
+
+
+  s.setPosition(0)
+  s.data.setLen(0)
+  var o = B
+  o.pack(s)
+  o = A
+  o.pack(s)
+  o = C
+  o.pack(s)
+  assert s.data == "\1\0\2"
+  s.flush
+
+  defPacket(Y, tuple[z: int8])
+  proc `$`(z: Y): string = result = "Y("& $z.z &")"
+  defPacket(TestPkt, tuple[x: seq[Y]])
+  var test = newTestPkt()
+  test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
+  for itm in test.x:
+    echo(itm)
+  test.pack(s)
+  echo(repr(s.data))
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
new file mode 100644
index 000000000..7cfd67c49
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
@@ -0,0 +1,287 @@
+import macros, macro_dsl, estreams
+from strutils import format
+
+template newLenName(): stmt {.immediate.} =
+  let lenName {.inject.} = ^("len"& $lenNames)
+  inc(lenNames)
+
+template defPacketImports*(): stmt {.immediate, dirty.} =
+  import macros, macro_dsl, estreams
+  from strutils import format
+
+macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
+  result = newNimNode(nnkStmtList)
+  let
+    typeName = quoted2ident(typeNameN)
+    packetID = ^"p"
+    streamID = ^"s"
+  var
+    constructorParams = newNimNode(nnkFormalParams).und(typeName)
+    constructor = newNimNode(nnkProcDef).und(
+      postfix(^("new"& $typeName.ident), "*"),
+      emptyNode(),
+      emptyNode(),
+      constructorParams,
+      emptyNode(),
+      emptyNode())
+    pack = newNimNode(nnkProcDef).und(
+      postfix(^"pack", "*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        emptyNode(),   # : void
+        newNimNode(nnkIdentDefs).und(
+          streamID,    # s: PBuffer
+          ^"PBuffer",
+          newNimNode(nnkNilLit)),
+        newNimNode(nnkIdentDefs).und(
+          packetID,    # p: var typeName
+          newNimNode(nnkVarTy).und(typeName),
+          emptyNode())),
+      emptyNode(),
+      emptyNode())
+    read = newNimNode(nnkProcDef).und(
+      newIdentNode("read"& $typeName.ident).postfix("*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        typeName,   #result type
+        newNimNode(nnkIdentDefs).und(
+          streamID, # s: PBuffer = nil
+          ^"PBuffer",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    constructorBody = newNimNode(nnkStmtList)
+    packBody = newNimNode(nnkStmtList)
+    readBody = newNimNode(nnkStmtList)
+    lenNames = 0
+  for i in 0.. typeFields.len - 1:
+    let
+      name = typeFields[i][0]
+      dotName = packetID.dot(name)
+      resName = newIdentNode(!"result").dot(name)
+    case typeFields[i][1].kind
+    of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
+      case $typeFields[i][1][0].ident
+      of "seq":
+        ## let lenX = readInt16(s)
+        newLenName()
+        let
+          item = ^"item"  ## item name in our iterators
+          seqType = typeFields[i][1][1] ## type of seq
+          readName = newIdentNode("read"& $seqType.ident)
+        readBody.add(newNimNode(nnkLetSection).und(
+          newNimNode(nnkIdentDefs).und(
+            lenName,
+            newNimNode(nnkEmpty),
+            newCall("readInt16", streamID))))
+        readBody.add(      ## result.name = @[]
+          resName := ("@".prefix(newNimNode(nnkBracket))),
+          newNimNode(nnkForStmt).und(  ## for item in 1..len:
+            item,
+            infix(1.lit, "..", lenName),
+            newNimNode(nnkStmtList).und(
+              newCall(  ## add(result.name, unpack[seqType](stream))
+                "add", resName, newNimNode(nnkCall).und(readName, streamID)
+        ) ) ) )
+        packbody.add(
+          newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
+            lenName,  ## var lenName = int16(len(p.name))
+            newIdentNode("int16"),
+            newCall("int16", newCall("len", dotName)))),
+          newCall("writeBE", streamID, lenName),
+          newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
+            item,
+            infix(0.lit, "..", infix(lenName, "-", 1.lit)),
+            newNimNode(nnkStmtList).und(
+              newCall("echo", item, ": ".lit),
+              newCall("pack", streamID, dotName[item]))))
+        #set the default value to @[] (new sequence)
+        typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
+      else:
+        error("Unknown type: "& treeRepr(typeFields[i]))
+    of nnkIdent: ##normal type
+      case $typeFields[i][1].ident
+      of "string": # length encoded string
+        packBody.add(newCall("write", streamID, dotName))
+        readBody.add(resName := newCall("readStr", streamID))
+      of "int8", "int16", "int32", "float32", "float64", "char", "bool":
+        packBody.add(newCall(
+          "writeBE", streamID, dotName))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+      else:  ## hopefully the type you specified was another defpacket() type
+        packBody.add(newCall("pack", streamID, dotName))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+    else:
+      error("I dont know what to do with: "& treerepr(typeFields[i]))
+
+  var
+    toStringFunc = newNimNode(nnkProcDef).und(
+      newNimNode(nnkPostfix).und(
+        ^"*",
+        newNimNode(nnkAccQuoted).und(^"$")),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        ^"string",
+        newNimNode(nnkIdentDefs).und(
+          packetID, # p: typeName
+          typeName,
+          emptyNode())),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkStmtList).und(#[6]
+        newNimNode(nnkAsgn).und(
+          ^"result",                  ## result =
+          newNimNode(nnkCall).und(#[6][0][1]
+            ^"format",  ## format
+            emptyNode()))))  ## "[TypeName   $1   $2]"
+    formatStr = "["& $typeName.ident
+
+  const emptyFields = {nnkEmpty, nnkNilLit}
+  var objFields = newNimNode(nnkRecList)
+  for i in 0.. < len(typeFields):
+    let fname = typeFields[i][0]
+    constructorParams.add(newNimNode(nnkIdentDefs).und(
+      fname,
+      typeFields[i][1],
+      typeFields[i][2]))
+    constructorBody.add((^"result").dot(fname) := fname)
+    #export the name
+    typeFields[i][0] = fname.postfix("*")
+    if not(typeFields[i][2].kind in emptyFields):
+      ## empty the type default for the type def
+      typeFields[i][2] = newNimNode(nnkEmpty)
+    objFields.add(typeFields[i])
+    toStringFunc[6][0][1].add(
+      prefix("$", packetID.dot(fname)))
+    formatStr.add "   $"
+    formatStr.add($(i + 1))
+
+  formatStr.add ']'
+  toStringFunc[6][0][1][1] = formatStr.lit()
+
+  result.add(
+    newNimNode(nnkTypeSection).und(
+      newNimNode(nnkTypeDef).und(
+        typeName.postfix("*"),
+        newNimNode(nnkEmpty),
+        newNimNode(nnkObjectTy).und(
+          newNimNode(nnkEmpty), #not sure what this is
+          newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
+          objFields))))
+  result.add(constructor.und(constructorBody))
+  result.add(pack.und(packBody))
+  result.add(read.und(readBody))
+  result.add(toStringFunc)
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+proc newProc*(name: NimNode; params: varargs[NimNode]; resultType: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkProcDef).und(
+    name,
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkFormalParams).und(resultType),
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkStmtList))
+  result[3].add(params)
+
+proc body*(procNode: NimNode): NimNode {.compileTime.} =
+  assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
+  result = procNode[6]
+
+proc iddefs*(a, b: string; c: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
+proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
+proc varTy*(a: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkVarTy).und(a)
+
+macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
+  var
+    packetID = ^"p"
+    streamID = ^"s"
+  result = newNimNode(nnkStmtList).und(
+    newProc(
+      (^("read"& $typeName.ident)).postfix("*"),
+      [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
+      typeName),
+    newProc(
+      (^"pack").postfix("*"),
+      [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)),
+        iddefs("p", varTy(typeName)) ],
+      emptyNode()))
+  var
+    readBody = result[0][6]
+    packBody = result[1][6]
+    resName = ^"result"
+
+  case underlyingType.kind
+  of nnkBracketExpr:
+    case $underlyingType[0].ident
+    of "array":
+      for i in underlyingType[1][1].intval.int .. underlyingType[1][2].intval.int:
+        readBody.add(
+          newCall("read", ^"s", resName[lit(i)]))
+        packBody.add(
+          newCall("writeBE", ^"s", packetID[lit(i)]))
+    else:
+      echo "Unknown type: ", repr(underlyingtype)
+  else:
+    echo "unknown type:", repr(underlyingtype)
+  echo(repr(result))
+
+template forwardPacketT*(typeName: expr; underlyingType: expr): stmt {.dirty, immediate.} =
+  proc `read typeName`*(buffer: PBuffer): typeName =
+    #discard readData(s, addr result, sizeof(result))
+    var res: underlyingType
+    buffer.read(res)
+    result = typeName(res)
+  proc `pack`*(buffer: PBuffer; ord: var typeName) =
+    #writeData(s, addr p, sizeof(p))
+    buffer.write(underlyingType(ord))
+
+when isMainModule:
+  type
+    SomeEnum = enum
+      A = 0'i8,
+      B, C
+  forwardPacket(SomeEnum, int8)
+
+
+  defPacket(Foo, tuple[x: array[0..4, int8]])
+  var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
+  var s2 = newStringStream("")
+  f.pack(s2)
+  assert s2.data == "\4\3\2\1\0"
+
+  var s = newStringStream()
+  s.flushImpl = proc(s: PStream) =
+    var z = PStringStream(s)
+    z.setPosition(0)
+    z.data.setLen(0)
+
+
+  s.setPosition(0)
+  s.data.setLen(0)
+  var o = B
+  o.pack(s)
+  o = A
+  o.pack(s)
+  o = C
+  o.pack(s)
+  assert s.data == "\1\0\2"
+  s.flush
+
+  defPacket(Y, tuple[z: int8])
+  proc `$`(z: Y): string = result = "Y("& $z.z &")"
+  defPacket(TestPkt, tuple[x: seq[Y]])
+  var test = newTestPkt()
+  test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
+  for itm in test.x:
+    echo(itm)
+  test.pack(s)
+  echo(repr(s.data))
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
new file mode 100644
index 000000000..d3a0c701d
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
@@ -0,0 +1,64 @@
+import macros
+{.deadCodeElim: on.}
+#Inline macro.add() to allow for easier nesting
+proc und*(a: NimNode; b: NimNode): NimNode {.compileTime.} =
+  a.add(b)
+  result = a
+proc und*(a: NimNode; b: varargs[NimNode]): NimNode {.compileTime.} =
+  a.add(b)
+  result = a
+
+proc `^`*(a: string): NimNode {.compileTime.} =
+  ## new ident node
+  result = newIdentNode(!a)
+proc `[]`*(a, b: NimNode): NimNode {.compileTime.} =
+  ## new bracket expression: node[node] not to be confused with node[indx]
+  result = newNimNode(nnkBracketExpr).und(a, b)
+proc `:=`*(left, right: NimNode): NimNode {.compileTime.} =
+  ## new Asgn node:  left = right
+  result = newNimNode(nnkAsgn).und(left, right)
+
+proc lit*(a: string): NimNode {.compileTime.} =
+  result = newStrLitNode(a)
+proc lit*(a: int): NimNode {.compileTime.} =
+  result = newIntLitNode(a)
+proc lit*(a: float): NimNode {.compileTime.} =
+  result = newFloatLitNode(a)
+proc lit*(a: char): NimNode {.compileTime.} =
+  result = newNimNode(nnkCharLit)
+  result.intval = a.ord
+
+proc emptyNode*(): NimNode {.compileTime.} =
+  result = newNimNode(nnkEmpty)
+
+proc dot*(left, right: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkDotExpr).und(left, right)
+proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkPrefix).und(newIdentNode(!a), b)
+
+proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
+  if a.kind != nnkAccQuoted:
+    return a
+  var pname = ""
+  for piece in 0..a.len - 1:
+    pname.add($a[piece].ident)
+  result = ^pname
+
+
+macro `?`(a: expr): expr =
+  ## Character literal ?A #=> 'A'
+  result = ($a[1].ident)[0].lit
+## echo(?F,?a,?t,?t,?y)
+
+when isMainModule:
+  macro foo(x: stmt): stmt =
+    result = newNimNode(nnkStmtList)
+    result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit))
+    result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit))))
+    let stmtlist = x[1]
+    for i in countdown(len(stmtlist)-1, 0):
+      result.add(stmtlist[i])
+  foo:
+    echo y, " * 2 = ", y * 2
+    let y = 320
+
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
new file mode 100644
index 000000000..3c5a7835c
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
@@ -0,0 +1,47 @@
+import streams
+from strutils import repeat
+
+proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = 
+  var lastChr = length
+  result = s.readStr(length)
+  while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr)
+  result.setLen(lastChr)
+
+proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
+  if str.len < length:
+    s.write(str)
+    s.write(repeat(padChar, length - str.len))
+  elif str.len > length:
+    s.write(str.substr(0, length - 1))
+  else:
+    s.write(str)
+
+proc readLEStr*(s: PStream): TaintedString =
+  var len = s.readInt16()
+  result = s.readStr(len)
+
+proc writeLEStr*(s: PStream, str: string) =
+  s.write(str.len.int16)
+  s.write(str)
+
+when isMainModule:
+  var testStream = newStringStream()
+  
+  testStream.writeLEStr("Hello")
+  doAssert testStream.data == "\5\0Hello"
+  
+  testStream.setPosition 0
+  var res = testStream.readLEStr()
+  doAssert res == "Hello"
+  
+  testStream.setPosition 0
+  testStream.writePaddedStr("Sup", 10)
+  echo(repr(testStream), testStream.data.len)
+  doAssert testStream.data == "Sup"&repeat('\0', 7)
+  
+  testStream.setPosition 0
+  res = testStream.readPaddedStr(10)
+  doAssert res == "Sup"
+  
+  testStream.close()
+
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
new file mode 100644
index 000000000..5828e400c
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
@@ -0,0 +1,83 @@
+discard """
+DO AS THOU WILST PUBLIC LICENSE
+
+Whoever should stumble upon this document is henceforth and forever
+entitled to DO AS THOU WILST with aforementioned document and the
+contents thereof. 
+
+As said in the Olde Country, `Keepe it Gangster'."""
+
+import strutils, parseopt, tables, os
+
+type
+  PTask* = ref object
+    desc*: string
+    action*: TTaskFunction
+  TTaskFunction* = proc() {.closure.}
+var 
+  tasks* = initTable[string, PTask](16)
+
+proc newTask*(desc: string; action: TTaskFunction): PTask
+proc runTask*(name: string) {.inline.}
+proc shell*(cmd: varargs[string, `$`]): int {.discardable.}
+proc cd*(dir: string) {.inline.}
+
+template nakeImports*(): stmt {.immediate.} =
+  import tables, parseopt, strutils, os
+
+template task*(name: string; description: string; body: stmt): stmt {.dirty, immediate.} =
+  block:
+    var t = newTask(description, proc() {.closure.} =
+      body)
+    tasks[name] = t
+
+proc newTask*(desc: string; action: TTaskFunction): PTask =
+  new(result)
+  result.desc = desc
+  result.action = action
+proc runTask*(name: string) = tasks[name].action()
+
+proc shell*(cmd: varargs[string, `$`]): int =
+  result = execShellCmd(cmd.join(" "))
+proc cd*(dir: string) = setCurrentDir(dir)
+template withDir*(dir: string; body: stmt): stmt =
+  ## temporary cd
+  ## withDir "foo":
+  ##   # inside foo
+  ## #back to last dir
+  var curDir = getCurrentDir()
+  cd(dir)
+  body
+  cd(curDir)
+
+when isMainModule:
+  if not existsFile("nakefile.nim"):
+    echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
+    quit 1
+  var args = ""
+  for i in 1..paramCount():
+    args.add paramStr(i)
+    args.add " "
+  quit(shell("nim", "c", "-r", "nakefile.nim", args))
+else:
+  addQuitProc(proc() {.noconv.} =
+    var 
+      task: string
+      printTaskList: bool
+    for kind, key, val in getOpt():
+      case kind
+      of cmdLongOption, cmdShortOption:
+        case key.tolower
+        of "tasks", "t":
+          printTaskList = true
+        else: 
+          echo "Unknown option: ", key, ": ", val
+      of cmdArgument:
+        task = key
+      else: nil
+    if printTaskList or task.isNil or not(tasks.hasKey(task)):
+      echo "Available tasks:"
+      for name, task in pairs(tasks):
+        echo name, " - ", task.desc
+      quit 0
+    tasks[task].action())
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim
new file mode 100644
index 000000000..bdf2139c9
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim
@@ -0,0 +1,23 @@
+import nake
+nakeImports
+
+task "install", "compile and install nake binary":
+  if shell("nim", "c", "nake") == 0:
+    let path = getEnv("PATH").split(PathSep)
+    for index, dir in pairs(path):
+      echo "  ", index, ". ", dir
+    echo "Where to install nake binary? (quit with ^C or quit or exit)"
+    let ans = stdin.readLine().toLower
+    var index = 0
+    case ans
+    of "q", "quit", "x", "exit":
+      quit 0
+    else:
+      index = parseInt(ans)
+    if index > path.len or index < 0:
+      echo "Invalid index."
+      quit 1
+    moveFile "nake", path[index]/"nake"
+    echo "Great success!"
+
+
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/README.md b/tests/manyloc/keineschweine/dependencies/sfml/README.md
new file mode 100644
index 000000000..bd9b3d0e7
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/README.md
@@ -0,0 +1,13 @@
+sfml-nimrod
+===========
+
+Nimrod binding of SFML 2.0
+
+This is only tested for Linux at the moment
+
+### What is needed for Windows / OS X?
+
+* The library names need filling in
+* TWindowHandle is handled differently on those platforms
+
+I believe that is it
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
new file mode 100644
index 000000000..1071ec767
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
@@ -0,0 +1,1121 @@
+import 
+  strutils, math
+when defined(linux):
+  const
+    LibG = "libcsfml-graphics.so.2.0"
+    LibS = "libcsfml-system.so.2.0"
+    LibW = "libcsfml-window.so.2.0"
+else:
+  # We only compile for testing here, so it doesn't matter it's not supported
+  const
+    LibG = "libcsfml-graphics.so.2.0"
+    LibS = "libcsfml-system.so.2.0"
+    LibW = "libcsfml-window.so.2.0"
+  #{.error: "Platform unsupported".}
+{.deadCodeElim: on.}
+{.pragma: pf, pure, final.}
+type
+  PClock* = ptr TClock
+  TClock* {.pf.} = object
+  TTime* {.pf.} = object
+    microseconds*: int64
+  TVector2i* {.pf.} = object
+    x*, y*: cint
+  TVector2f* {.pf.} = object
+    x*, y*: cfloat
+  TVector3f* {.pf.} = object
+    x*, y*, z*: cfloat
+
+  PInputStream* = ptr TInputStream
+  TInputStream* {.pf.} = object 
+    read*: TInputStreamReadFunc
+    seek*: TInputStreamSeekFunc
+    tell*: TInputStreamTellFunc
+    getSize*: TInputStreamGetSizeFunc
+    userData*: pointer
+  TInputStreamReadFunc* = proc (data: pointer, size: int64, userData: pointer): int64{.
+    cdecl.}
+  TInputStreamSeekFunc* = proc (position: int16, userData: pointer): int64{.
+    cdecl.}
+  TInputStreamTellFunc* = proc (userData: pointer): int64 {.cdecl.}
+  TInputStreamGetSizeFunc* = proc (userData: pointer): int64 {.cdecl.}
+  PWindow* = ptr TWindow
+  TWindow* {.pf.} = object
+  PContextSettings* = ptr TContextSettings
+  TContextSettings*{.pf.} = object
+    depthBits: cint
+    stencilBits: cint
+    antialiasingLevel: cint
+    majorVersion: cint
+    minorVersion: cint
+  TVideoMode* {.pf.} = object
+    width*: cint
+    height*: cint
+    bitsPerPixel*: cint
+  TEventType*{.size: sizeof(cint).} = enum 
+    EvtClosed, EvtResized, EvtLostFocus, EvtGainedFocus, 
+    EvtTextEntered, EvtKeyPressed, EvtKeyReleased, EvtMouseWheelMoved, 
+    EvtMouseButtonPressed, EvtMouseButtonReleased, EvtMouseMoved, 
+    EvtMouseEntered, EvtMouseLeft, EvtJoystickButtonPressed, 
+    EvtJoystickButtonReleased, EvtJoystickMoved, EvtJoystickConnected, 
+    EvtJoystickDisconnected
+  TKeyEvent*{.pf.} = object 
+    code*: TKeyCode
+    alt*    : bool
+    control*: bool
+    shift*  : bool
+    system* : bool
+  TJoystickConnectEvent*{.pf.} = object
+    joystickId*: cint
+  TJoystickButtonEvent*{.pf.} = object
+    joystickId*: cint
+    button*: cint
+  TJoystickMoveEvent*{.pf.} = object
+    joystickId*: cint
+    axis*: TJoystickAxis
+    position*: cfloat
+  TMouseWheelEvent*{.pf.} = object 
+    delta*: cint
+    x*: cint
+    y*: cint
+  TMouseButtonEvent*{.pf.} = object
+    button*: TMouseButton
+    x*: cint
+    y*: cint
+  TMouseMoveEvent*{.pf.} = object
+    x*: cint
+    y*: cint
+  TTextEvent*{.pf.} = object
+    unicode*: cint
+  PEvent* = ptr TEvent
+  TEvent*{.pf.} = object
+    case kind*: TEventType
+    of EvtKeyPressed, EvtKeyReleased: 
+      key*: TKeyEvent
+    of EvtMouseButtonPressed, EvtMouseButtonReleased:
+      mouseButton*: TMouseButtonEvent
+    of EvtTextEntered:
+      text*: TTextEvent
+    of EvtJoystickConnected, EvtJoystickDisconnected:
+      joystickConnect*: TJoystickConnectEvent
+    of EvtJoystickMoved:
+      joystickMove*: TJoystickMoveEvent
+    of EvtJoystickButtonPressed, EvtJoystickButtonReleased:
+      joystickButton*: TJoystickButtonEvent
+    of EvtResized:
+      size*: TSizeEvent
+    of EvtMouseMoved, EvtMouseEntered, EvtMouseLeft:
+      mouseMove*: TMouseMoveEvent
+    of EvtMouseWheelMoved:
+      mouseWheel*: TMouseWheelEvent
+    else: nil
+  TJoystickAxis*{.size: sizeof(cint).} = enum 
+    JoystickX, JoystickY, JoystickZ, JoystickR,      
+    JoystickU, JoystickV, JoystickPovX, JoystickPovY
+  TSizeEvent*{.pf.} = object
+    width*: cint
+    height*: cint
+  TMouseButton*{.size: sizeof(cint).} = enum 
+    MouseLeft, MouseRight, MouseMiddle,  
+    MouseXButton1, MouseXButton2, MouseButtonCount
+  TKeyCode*{.size: sizeof(cint).} = enum 
+    KeyUnknown = - 1, KeyA, KeyB, KeyC, KeyD, KeyE,
+    KeyF, KeyG, KeyH, KeyI, KeyJ, KeyK, KeyL, KeyM,                 #/< The M key
+    KeyN, KeyO, KeyP, KeyQ, KeyR, KeyS, KeyT, KeyU,                 #/< The U key
+    KeyV, KeyW, KeyX, KeyY, KeyZ, KeyNum0, KeyNum1,              #/< The 1 key
+    KeyNum2, KeyNum3, KeyNum4, KeyNum5, KeyNum6,              #/< The 6 key
+    KeyNum7, KeyNum8, KeyNum9, KeyEscape, KeyLControl,          #/< The left Control key
+    KeyLShift, KeyLAlt, KeyLSystem, KeyRControl,          #/< The right Control key
+    KeyRShift, KeyRAlt, KeyRSystem, KeyMenu,              #/< The Menu key
+    KeyLBracket, KeyRBracket, KeySemiColon, KeyComma,             #/< The , key
+    KeyPeriod, KeyQuote, KeySlash, KeyBackSlash,         #/< The \ key
+    KeyTilde, KeyEqual, KeyDash, KeySpace, KeyReturn,            #/< The Return key
+    KeyBack, KeyTab, KeyPageUp, KeyPageDown, KeyEnd,               #/< The End key
+    KeyHome, KeyInsert, KeyDelete, KeyAdd, KeySubtract,          #/< -
+    KeyMultiply, KeyDivide, KeyLeft, KeyRight, KeyUp,                #/< Up arrow
+    KeyDown, KeyNumpad0, KeyNumpad1, KeyNumpad2,           #/< The numpad 2 key
+    KeyNumpad3,           #/< The numpad 3 key
+    KeyNumpad4,           #/< The numpad 4 key
+    KeyNumpad5,           #/< The numpad 5 key
+    KeyNumpad6,           #/< The numpad 6 key
+    KeyNumpad7,           #/< The numpad 7 key
+    KeyNumpad8,           #/< The numpad 8 key
+    KeyNumpad9,           #/< The numpad 9 key
+    KeyF1,                #/< The F1 key
+    KeyF2,                #/< The F2 key
+    KeyF3,                #/< The F3 key
+    KeyF4,                #/< The F4 key
+    KeyF5,                #/< The F5 key
+    KeyF6,                #/< The F6 key
+    KeyF7,                #/< The F7 key
+    KeyF8,                #/< The F8 key
+    KeyF9,                #/< The F8 key
+    KeyF10,               #/< The F10 key
+    KeyF11,               #/< The F11 key
+    KeyF12,               #/< The F12 key
+    KeyF13,               #/< The F13 key
+    KeyF14,               #/< The F14 key
+    KeyF15,               #/< The F15 key
+    KeyPause,             #/< The Pause key
+    KeyCount              #/< Keep last -- the total number of keyboard keys
+
+type TWindowHandle* = clong
+
+#elif defined(mac):
+#  type TWindowHandle* = pointer ##typedef void* sfWindowHandle; <- whatever the hell that is
+#elif defined(windows):
+#  type TWindowHandle* = HWND__ ? windows is crazy. ##struct HWND__; typedef struct HWND__* sfWindowHandle;
+const
+  sfNone*         = 0
+  sfTitlebar*     = 1 shl 0
+  sfResize*       = 1 shl 1
+  sfClose*        = 1 shl 2
+  sfFullscreen*   = 1 shl 3
+  sfDefaultStyle* = sfTitlebar or sfResize or sfClose
+type
+  PRenderWindow* = ptr TRenderWindow
+  TRenderWindow* {.pf.} = object
+
+  PFont* = ptr TFont
+  TFont* {.pf.} = object
+  PImage* = ptr TImage
+  TImage* {.pf.} = object
+  PShader* = ptr TShader
+  TShader* {.pf.} = object
+  PSprite* = ptr TSprite
+  TSprite* {.pf.} = object
+  PText* = ptr TText
+  TText* {.pf.} = object
+  PTexture* = ptr TTexture
+  TTexture* {.pf.} = object
+  PVertexArray* = ptr TVertexArray
+  TVertexArray* {.pf.} = object
+  PView* = ptr TView
+  TView* {.pf.} = object
+  PRenderTexture* = ptr TRenderTexture
+  TRenderTexture* {.pf.} = object
+
+  PShape* = ptr TShape
+  TShape* {.pf.} = object
+  PCircleShape* = ptr TCircleShape
+  TCircleShape* {.pf.} = object
+  PRectangleShape* = ptr TRectangleShape
+  TRectangleShape* {.pf.} = object
+  PConvexShape* = ptr TConvexShape
+  TConvexShape* {.pf.} = object
+
+  TTextStyle*{.size: sizeof(cint).} = enum 
+    TextRegular = 0, TextBold = 1 shl 0, TextItalic = 1 shl 1, 
+    TextUnderlined = 1 shl 2
+
+  TBlendMode*{.size: sizeof(cint).} = enum 
+      BlendAlpha, BlendAdd, BlendMultiply, BlendNone
+  PRenderStates* = ptr TRenderStates
+  TRenderStates* {.pf.} = object
+    blendMode*: TBlendMode
+    transform*: TTransform
+    texture*: PTexture
+    shader*: PShader
+
+  PTransform* = ptr TTransform
+  TTransform* {.pf.} = object
+    matrix*: array[0..8, cfloat]
+  TColor* {.pf.} = object 
+    r*: uint8
+    g*: uint8
+    b*: uint8
+    a*: uint8
+  PFloatRect* = ptr TFloatRect
+  TFloatRect*{.pf.} = object 
+    left*: cfloat
+    top*: cfloat
+    width*: cfloat
+    height*: cfloat
+  PIntRect* = ptr TIntRect
+  TIntRect*{.pf.} = object 
+    left*: cint
+    top*: cint
+    width*: cint
+    height*: cint
+  TGlyph* {.pf.} = object
+    advance*: cint
+    bounds*: TIntRect
+    textureRect*: TIntRect
+  PVertex* = ptr TVertex
+  TVertex* {.pf.} = object
+    position*: TVector2f
+    color*: TColor
+    texCoords*: TVector2f
+  TPrimitiveType*{.size: sizeof(cint).} = enum 
+    Points,               #/< List of individual points
+    Lines,                #/< List of individual lines
+    LinesStrip,           #/< List of connected lines, a point uses the previous point to form a line
+    Triangles,            #/< List of individual triangles
+    TrianglesStrip,       #/< List of connected triangles, a point uses the two previous points to form a triangle
+    TrianglesFan,         #/< List of connected triangles, a point uses the common center and the previous point to form a triangle
+    Quads
+
+
+proc newWindow*(mode: TVideoMode, title: cstring, style: uint32, settings: PContextSettings = nil): PWindow {.
+  cdecl, importc: "sfWindow_create", dynlib: LibW.}
+
+proc close*(window: PWindow) {.
+  cdecl, importc: "sfWindow_close", dynlib: LibW.}
+proc isOpen*(window: PWindow): bool {.cdecl, importc: "sfWindow_isOpen", dynlib: LibW.}
+
+proc pollEvent*(window: PWindow, event: PEvent): bool {.
+  cdecl, importc: "sfWindow_pollEvent", dynlib: LibW.}
+proc waitEvent*(window: PWindow, event: PEvent): bool {.
+  cdecl, importc: "sfWindow_waitEvent", dynlib: LibW.}
+
+proc getDesktopMode*(): TVideoMode {.
+  cdecl, importc: "sfVideoMode_getDesktopMode", dynlib: LibW.}
+proc isKeyPressed*(key: TKeyCode): bool {.
+  cdecl, importc: "sfKeyboard_isKeyPressed", dynlib: LibW.}
+
+proc mouseIsButtonPressed*(button: TMouseButton): bool {.
+  cdecl, importc: "sfMouse_isButtonPressed", dynlib: LibW.}
+proc mouseGetPosition*(relativeTo: PWindow): TVector2i {.
+  cdecl, importc: "sfMouse_getPosition", dynlib: LibW.}
+proc mouseSetPosition*(position: TVector2i, relativeTo: PWindow) {.
+  cdecl, importc: "sfMouse_setPosition", dynlib: LibW.}
+
+proc joystickIsConnected*(joystick: cint): bool {.
+  cdecl, importc: "sfJoystick_isConnected", dynlib: LibW.}
+proc joystickGetButtonCount*(joystick: cint): cint {.
+  cdecl, importc: "sfJoystick_getButtonCount", dynlib: LibW.}
+proc joystickHasAxis*(joystick: cint, axis: TJoystickAxis): bool {.
+  cdecl, importc: "sfJoystick_hasAxis", dynlib: LibW.}
+proc joystickIsButtonPressed*(joystick: cint, button: cint): bool {.
+  cdecl, importc: "sfJoystick_isButtonPressed", dynlib: LibW.}
+proc joystickGetAxisPosition*(joystick: cint, axis: TJoystickAxis): float {.
+  cdecl, importc: "sfJoystick_getAxisPosition", dynlib: LibW.}
+proc joystickUpdate*(): void {.
+  cdecl, importc: "sfJoystick_update", dynlib: LibW.}
+
+
+proc newRenderWindow*(handle: TWindowHandle, settings: PContextSettings = nil): PRenderWindow{.
+  cdecl, importc: "sfRenderWindow_createFromHandle", dynlib: LibG.}
+proc newRenderWindow*(mode: TVideoMode, title: cstring, style: int32, settings: PContextSettings = nil): PRenderWindow {.
+  cdecl, importc: "sfRenderWindow_create", dynlib: LibG.}
+
+proc destroy*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_destroy", dynlib: LibG.}
+proc close*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_close", dynlib: LibG.}
+proc isOpen*(window: PRenderWindow): bool {.
+  cdecl, importc: "sfRenderWindow_isOpen", dynlib: LibG.}
+
+#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfuint8* pixels);
+#proc setIcon*(window: PRenderWindow, width, height: cint, pixels: seq[uint8]) {.
+#  cdecl, importc: "sfRenderWindow_setIcon", dynlib: LibG.}
+
+proc getSettings*(window: PRenderWindow): TContextSettings {.
+  cdecl, importc: "sfRenderWindow_getSettings", dynlib: LibG.}
+
+proc pollEvent*(window: PRenderWindow, event: PEvent): bool {.
+  cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.}
+proc pollEvent*(window: PRenderWindow; event: var TEvent): bool {.
+  cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.}
+proc waitEvent*(window: PRenderWindow, event: PEvent): bool {.
+  cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.}
+proc waitEvent*(window: PRenderWindow, event: var TEvent): bool {.
+  cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.}
+proc getPosition*(window: PRenderWindow): TVector2i {.
+  cdecl, importc: "sfRenderWindow_getPosition", dynlib: LibG.}
+proc setPosition*(window: PRenderWindow, position: TVector2i) {.
+  cdecl, importc: "sfRenderWindow_setPosition", dynlib: LibG.}
+proc getSize*(window: PRenderWindow): TVector2i {.
+  cdecl, importc: "sfRenderWindow_getSize", dynlib: LibG.}
+proc setSize*(window: PRenderWindow, size: TVector2i): void {.
+  cdecl, importc: "sfRenderWindow_setSize", dynlib: LibG.}
+proc setTitle*(window: PRenderWindow, title: cstring): void {.
+  cdecl, importc: "sfRenderWindow_setTitle", dynlib: LibG.}
+
+proc setVisible*(window: PRenderWindow, visible: bool) {.
+  cdecl, importc: "sfRenderWindow_setVisible", dynlib: LibG.}
+proc setMouseCursorVisible*(window: PRenderWindow, show: bool) {.
+  cdecl, importc: "sfRenderWindow_setMouseCursorVisible", dynlib: LibG.}
+proc setVerticalSyncEnabled*(window: PRenderWindow, enabled: bool) {.
+  cdecl, importc: "sfRenderWindow_setVerticalSyncEnabled", dynlib: LibG.}
+proc setKeyRepeatEnabled*(window: PRenderWindow, enabled: bool) {.
+  cdecl, importc: "sfRenderWindow_setKeyRepeatEnabled", dynlib: LibG.}
+proc setActive*(window: PRenderWindow, active: bool): bool {.
+  cdecl, importc: "sfRenderWindow_setActive", dynlib: LibG.}
+proc display*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_display", dynlib: LibG.}
+proc setFramerateLimit*(window: PRenderWindow, limit: uint) {.
+  cdecl, importc: "sfRenderWindow_setFramerateLimit", dynlib: LibG.}
+proc setJoystickThreshold*(window: PRenderWindow, threshold: float) {.
+  cdecl, importc: "sfRenderWindow_setJoystickThreshold", dynlib: LibG.}
+proc getSystemHandle*(window: PRenderWindow): TWindowHandle {.
+  cdecl, importc: "sfRenderWindow_getSystemHandle", dynlib: LibG.}
+
+proc clear*(window: PRenderWindow, color: TColor) {.
+  cdecl, importc: "sfRenderWindow_clear", dynlib: LibG.}
+
+proc setView*(window: PRenderWindow, view: PView) {.
+  cdecl, importc: "sfRenderWindow_setView", dynlib: LibG.}
+proc getView*(window: PRenderWindow): PView {.
+  cdecl, importc: "sfRenderWindow_getView", dynlib: LibG.}
+proc getDefaultView*(window: PRenderWindow): PView {.
+  cdecl, importc: "sfRenderWindow_getDefaultView", dynlib: LibG.}
+proc getViewport*(window: PRenderWindow, view: PView): TIntRect {.
+  cdecl, importc: "sfRenderWindow_getViewport", dynlib: LibG.}
+
+proc convertCoords*(window: PRenderWindow, point: TVector2i, targetView: PView): TVector2f {.
+  cdecl, importc: "sfRenderWindow_convertCoords", dynlib: LibG.}
+
+proc draw*(window: PRenderWindow, sprite: PSprite, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawSprite", dynlib: LibG.}
+proc draw*(window: PRenderWindow, text: PText, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawText", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PCircleShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawCircleShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PRectangleShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawRectangleShape", dynlib: LibG.}
+
+proc draw*(window: PRenderWindow, shape: PConvexShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawConvexShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PVertexArray, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawVertexArray", dynlib: LibG.}
+proc draw*(window: PRenderWindow, vertices: PVertex, vertexCount: cint, 
+           vertexType: TPrimitiveType, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawPrimitives", dynlib: LibG.}
+
+proc pushGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_pushGLStates", dynlib: LibG.}
+proc popGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_popGLStates", dynlib: LibG.}
+proc resetGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_resetGLStates", dynlib: LibG.}
+proc capture*(window: PRenderWindow): PImage {.
+  cdecl, importc: "sfRenderWindow_capture", dynlib: LibG.}
+
+#Construct a new render texture
+proc newRenderTexture*(width, height: cint; depthBuffer: bool): PRenderTexture {.
+  cdecl, importc: "sfRenderTexture_create", dynlib: LibG.}
+#Destroy an existing render texture
+proc destroy*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_destroy", dynlib: LibG.}
+#Get the size of the rendering region of a render texture
+proc getSize*(renderTexture: PRenderTexture): TVector2i {.
+  cdecl, importc: "sfRenderTexture_getSize", dynlib: LibG.}
+#Activate or deactivate a render texture as the current target for rendering
+proc setActive*(renderTexture: PRenderTexture; active: bool): bool{.
+  cdecl, importc: "sfRenderTexture_setActive", dynlib: LibG.}
+#Update the contents of the target texture
+proc display*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_display", dynlib: LibG.}
+#Clear the rendertexture with the given color
+proc clear*(renderTexture: PRenderTexture; color: TColor){.
+  cdecl, importc: "sfRenderTexture_clear", dynlib: LibG.}
+#Change the current active view of a render texture
+proc setView*(renderTexture: PRenderTexture; view: PView){.
+  cdecl, importc: "sfRenderTexture_setView", dynlib: LibG.}
+#Get the current active view of a render texture
+proc getView*(renderTexture: PRenderTexture): PView{.
+  cdecl, importc: "sfRenderTexture_getView", dynlib: LibG.}
+#Get the default view of a render texture
+proc getDefaultView*(renderTexture: PRenderTexture): PView{.
+  cdecl, importc: "sfRenderTexture_getDefaultView", dynlib: LibG.}
+#Get the viewport of a view applied to this target
+proc getViewport*(renderTexture: PRenderTexture; view: PView): TIntRect{.
+  cdecl, importc: "sfRenderTexture_getViewport", dynlib: LibG.}
+#Convert a point in texture coordinates into view coordinates
+proc convertCoords*(renderTexture: PRenderTexture; point: TVector2i; targetView: PView): TVector2f{.
+  cdecl, importc: "sfRenderTexture_convertCoords", dynlib: LibG.}
+#Draw a drawable object to the render-target
+proc draw*(renderTexture: PRenderTexture; sprite: PSprite; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawSprite", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; text: PText; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawText", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PShape; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PCircleShape; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawCircleShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PConvexShape; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawConvexShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PRectangleShape; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawRectangleShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; va: PVertexArray; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawVertexArray", dynlib: LibG.}
+#Draw primitives defined by an array of vertices to a render texture
+proc draw*(renderTexture: PRenderTexture; vertices: PVertex; vertexCount: cint; 
+            primitiveType: TPrimitiveType; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawPrimitives", dynlib: LibG.}
+#Save the current OpenGL render states and matrices
+#/
+#/ This function can be used when you mix SFML drawing
+#/ and direct OpenGL rendering. Combined with popGLStates,
+#/ it ensures that:
+#/ * SFML's internal states are not messed up by your OpenGL code
+#/ * your OpenGL states are not modified by a call to a SFML function
+#/
+#/ Note that this function is quite expensive: it saves all the
+#/ possible OpenGL states and matrices, even the ones you
+#/ don't care about. Therefore it should be used wisely.
+#/ It is provided for convenience, but the best results will
+#/ be achieved if you handle OpenGL states yourself (because
+#/ you know which states have really changed, and need to be
+#/ saved and restored). Take a look at the resetGLStates
+#/ function if you do so.
+proc pushGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_pushGLStates", dynlib: LibG.}
+#Restore the previously saved OpenGL render states and matrices
+#/
+#/ See the description of pushGLStates to get a detailed
+#/ description of these functions.
+proc popGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_popGLStates", dynlib: LibG.}
+#Reset the internal OpenGL states so that the target is ready for drawing
+#/
+#/ This function can be used when you mix SFML drawing
+#/ and direct OpenGL rendering, if you choose not to use
+#/ pushGLStates/popGLStates. It makes sure that all OpenGL
+#/ states needed by SFML are set, so that subsequent sfRenderTexture_draw*()
+#/ calls will work as expected.
+proc resetGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_resetGLStates", dynlib: LibG.}
+#Get the target texture of a render texture
+proc getTexture*(renderTexture: PRenderTexture): PTexture{.
+  cdecl, importc: "sfRenderTexture_getTexture", dynlib: LibG.}
+#Enable or disable the smooth filter on a render texture
+proc setSmooth*(renderTexture: PRenderTexture; smooth: bool){.
+  cdecl, importc: "sfRenderTexture_setSmooth", dynlib: LibG.}
+#Tell whether the smooth filter is enabled or not for a render texture
+proc isSmooth*(renderTexture: PRenderTexture): bool {.
+  cdecl, importc: "sfRenderTexture_isSmooth", dynlib: LibG.}
+
+proc intRect*(left, top, width, height: cint): TIntRect =
+  result.left   = left
+  result.top    = top
+  result.width  = width
+  result.height = height
+proc floatRect*(left, top, width, height: cfloat): TFloatRect =
+  result.left   = left
+  result.top    = top 
+  result.width  = width
+  result.height = height
+proc contains*(rect: PFloatRect, x, y: cfloat): bool {.
+  cdecl, importc: "sfFloatRect_contains", dynlib: LibG.}
+proc contains*(rect: PIntRect, x: cint, y: cint): bool{.cdecl, 
+  importc: "sfIntRect_contains", dynlib: LibG.}
+proc intersects*(rect1, rect2, intersection: PFloatRect): bool {.
+  cdecl, importc: "sfFloatRect_intersects", dynlib: LibG.}
+proc intersects*(rect1, rect2, intersection: PIntRect): bool {.
+  cdecl, importc: "sfIntRect_intersects", dynlib: LibG.}
+
+proc newFont*(filename: cstring): PFont {.
+  cdecl, importc: "sfFont_createFromFile", dynlib: LibG.}
+proc newFont*(data: pointer, sizeInBytes: cint): PFont {.
+  cdecl, importc: "sfFont_createFromMemory", dynlib: LibG.}
+proc newFont*(stream: PInputStream): PFont {.
+  cdecl, importc: "sfFont_createFromStream", dynlib: LibG.}
+proc copy*(font: PFont): PFont {.
+  cdecl, importc: "sfFont_copy", dynlib: LibG.}
+proc destroy*(font: PFont) {.
+  cdecl, importc: "sfFont_destroy", dynlib: LibG.}
+proc getGlyph*(font: PFont, codePoint: uint32, characterSize: cint, bold: bool): TGlyph{.
+  cdecl, importc: "sfFont_getGlyph", dynlib: LibG.}
+proc getKerning*(font: PFont, first: uint32, second: uint32, characterSize: cint): cint {.
+  cdecl, importc: "sfFont_getKerning", dynlib: LibG.}
+proc getLineSpacing*(font: PFont, characterSize: cint): cint {.
+  cdecl, importc: "sfFont_getLineSpacing", dynlib: LibG.}
+proc getTexture*(font: PFont, characterSize: cint): PTexture {.
+  cdecl, importc: "sfFont_getTexture", dynlib: LibG.}
+#getDefaultFont() has been removed from CSFML
+proc getDefaultFont*(): PFont {.
+  error, cdecl, importc: "sfFont_getDefaultFont", dynlib: LibG.}
+
+proc newCircleShape*(): PCircleShape {.
+  cdecl, importc: "sfCircleShape_create", dynlib: LibG.}
+proc copy*(shape: PCircleShape): PCircleShape {.
+  cdecl, importc: "sfCircleShape_copy", dynlib: LibG.}
+proc destroy*(shape: PCircleShape) {.
+  cdecl, importc: "sfCircleShape_destroy", dynlib: LibG.}
+proc setPosition*(shape: PCircleShape, position: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setPosition", dynlib: LibG.}
+proc setRotation*(shape: PCircleShape, angle: cfloat) {.
+  cdecl, importc: "sfCircleShape_setRotation", dynlib: LibG.}
+proc setScale*(shape: PCircleShape, scale: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setScale", dynlib: LibG.}
+proc setOrigin*(shape: PCircleShape, origin: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setOrigin", dynlib: LibG.}
+proc getPosition*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getPosition", dynlib: LibG.}
+proc getRotation*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getRotation", dynlib: LibG.}
+proc getScale*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getScale", dynlib: LibG.}
+proc getOrigin*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getOrigin", dynlib: LibG.}
+proc move*(shape: PCircleShape, offset: TVector2f) {.
+  cdecl, importc: "sfCircleShape_move", dynlib: LibG.}
+proc rotate*(shape: PCircleShape, angle: cfloat){.
+  cdecl, importc: "sfCircleShape_rotate", dynlib: LibG.}
+proc scale*(shape: PCircleShape, factors: TVector2f) {.
+  cdecl, importc: "sfCircleShape_scale", dynlib: LibG.}
+proc getTransform*(shape: PCircleShape): TTransform {.
+  cdecl, importc: "sfCircleShape_getTransform", dynlib: LibG.}
+proc getInverseTransform*(shape: PCircleShape): TTransform {.
+  cdecl, importc: "sfCircleShape_getInverseTransform", dynlib: LibG.}
+proc setTexture*(shape: PCircleShape, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfCircleShape_setTexture", dynlib: LibG.}
+proc setTextureRect*(shape: PCircleShape, rect: TIntRect) {.
+  cdecl, importc: "sfCircleShape_setTextureRect", dynlib: LibG.}
+proc setFillColor*(shape: PCircleShape, color: TColor) {.
+  cdecl, importc: "sfCircleShape_setFillColor", dynlib: LibG.}
+proc setOutlineColor*(shape: PCircleShape, color: TColor) {.
+  cdecl, importc: "sfCircleShape_setOutlineColor", dynlib: LibG.}
+proc setOutlineThickness*(shape: PCircleShape, thickness: cfloat) {.
+  cdecl, importc: "sfCircleShape_setOutlineThickness", dynlib: LibG.}
+proc getTexture*(shape: PCircleShape): PTexture {.
+  cdecl, importc: "sfCircleShape_getTexture", dynlib: LibG.}
+proc getTextureRect*(shape: PCircleShape): TIntRect {.
+  cdecl, importc: "sfCircleShape_getTextureRect", dynlib: LibG.}
+proc getFillColor*(shape: PCircleShape): TColor {.
+  cdecl, importc: "sfCircleShape_getFillColor", dynlib: LibG.}
+proc getOutlineColor*(shape: PCircleShape): TColor {.
+  cdecl, importc: "sfCircleShape_getOutlineColor", dynlib: LibG.}
+proc getOutlineThickness*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getOutlineThickness", dynlib: LibG.}
+proc getPointCount*(shape: PCircleShape): cint {.
+  cdecl, importc: "sfCircleShape_getPointCount", dynlib: LibG.}
+proc getPoint*(shape: PCircleShape, index: cint): TVector2f {.
+  cdecl, importc: "sfCircleShape_getPoint", dynlib: LibG.}
+proc setRadius*(shape: PCircleShape, radius: cfloat) {.
+  cdecl, importc: "sfCircleShape_setRadius", dynlib: LibG.}
+proc getRadius*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getRadius", dynlib: LibG.}
+proc setPointCount*(shape: PCircleShape, count: cint) {.
+  cdecl, importc: "sfCircleShape_setPointCount", dynlib: LibG.}
+proc getLocalBounds*(shape: PCircleShape): TFloatRect {.
+  cdecl, importc: "sfCircleShape_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(shape: PCircleShape): TFloatRect {.
+  cdecl, importc: "sfCircleShape_getGlobalBounds", dynlib: LibG.}
+
+proc newRectangleShape*(): PRectangleShape {.
+  cdecl, importc: "sfRectangleShape_create", dynlib: LibG.}
+proc copy*(shape: PRectangleShape): PRectangleShape {.
+  cdecl, importc: "sfRectangleShape_copy", dynlib: LibG.}
+proc destroy*(shape: PRectangleShape){.
+  cdecl, importc: "sfRectangleShape_destroy", dynlib: LibG.}
+proc setPosition*(shape: PRectangleShape, position: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setPosition", dynlib: LibG.}
+proc setRotation*(shape: PRectangleShape, angle: cfloat) {.
+  cdecl, importc: "sfRectangleShape_setRotation", dynlib: LibG.}
+proc setScale*(shape: PRectangleShape, scale: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setScale", dynlib: LibG.}
+proc setOrigin*(shape: PRectangleShape, origin: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setOrigin", dynlib: LibG.}
+proc getPosition*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getPosition", dynlib: LibG.}
+proc getRotation*(shape: PRectangleShape): cfloat {.
+  cdecl, importc: "sfRectangleShape_getRotation", dynlib: LibG.}
+proc getScale*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getScale", dynlib: LibG.}
+proc getOrigin*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getOrigin", dynlib: LibG.}
+proc move*(shape: PRectangleShape, offset: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_move", dynlib: LibG.}
+proc rotate*(shape: PRectangleShape, angle: cfloat) {.
+  cdecl, importc: "sfRectangleShape_rotate", dynlib: LibG.}
+proc scale*(shape: PRectangleShape, factors: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_scale", dynlib: LibG.}
+proc getTransform*(shape: PRectangleShape): TTransform {.
+  cdecl, importc: "sfRectangleShape_getTransform", dynlib: LibG.}
+proc getInverseTransform*(shape: PRectangleShape): TTransform {.
+  cdecl, importc: "sfRectangleShape_getInverseTransform", dynlib: LibG.}
+proc setTexture*(shape: PRectangleShape, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfRectangleShape_setTexture", dynlib: LibG.}
+proc setTextureRect*(shape: PRectangleShape, rect: TIntRect) {.
+  cdecl, importc: "sfRectangleShape_setTextureRect", dynlib: LibG.}
+proc setFillColor*(shape: PRectangleShape, color: TColor) {.
+  cdecl, importc: "sfRectangleShape_setFillColor", dynlib: LibG.}
+proc setOutlineColor*(shape: PRectangleShape, color: TColor) {.
+  cdecl, importc: "sfRectangleShape_setOutlineColor", dynlib: LibG.}
+proc setOutlineThickness*(shape: PRectangleShape, thickness: cfloat) {.
+  cdecl, importc: "sfRectangleShape_setOutlineThickness", dynlib: LibG.}
+proc getTexture*(shape: PRectangleShape): PTexture {.
+  cdecl, importc: "sfRectangleShape_getTexture", dynlib: LibG.}
+proc getTextureRect*(shape: PRectangleShape): TIntRect {.
+  cdecl, importc: "sfRectangleShape_getTextureRect", dynlib: LibG.}
+proc getFillColor*(shape: PRectangleShape): TColor {.
+  cdecl, importc: "sfRectangleShape_getFillColor", dynlib: LibG.}
+proc getOutlineColor*(shape: PRectangleShape): TColor {.
+  cdecl, importc: "sfRectangleShape_getOutlineColor", dynlib: LibG.}
+proc getOutlineThickness*(shape: PRectangleShape): cfloat {.
+  cdecl, importc: "sfRectangleShape_getOutlineThickness", dynlib: LibG.}
+proc getPointCount*(shape: PRectangleShape): cint {.
+  cdecl, importc: "sfRectangleShape_getPointCount", dynlib: LibG.}
+proc getPoint*(shape: PRectangleShape, index: cint): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getPoint", dynlib: LibG.}
+proc setSize*(shape: PRectangleShape, size: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setSize", dynlib: LibG.}
+proc getSize*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getSize", dynlib: LibG.}
+proc getLocalBounds*(shape: PRectangleShape): TFloatRect {.
+  cdecl, importc: "sfRectangleShape_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(shape: PRectangleShape): TFloatRect {.
+  cdecl, importc: "sfRectangleShape_getGlobalBounds", dynlib: LibG.}
+
+
+proc newView*(): PView {.
+  cdecl, importc: "sfView_create", dynlib: LibG.}
+proc viewFromRect*(rectangle: TFloatRect): PView{.
+  cdecl, importc: "sfView_createFromRect", dynlib: LibG.}
+proc copy*(view: PView): PView {.
+  cdecl, importc: "sfView_copy", dynlib: LibG.}
+proc destroy*(view: PView) {.
+  cdecl, importc: "sfView_destroy", dynlib: LibG.}
+proc setCenter*(view: PView, center: TVector2f) {.
+  cdecl, importc: "sfView_setCenter", dynlib: LibG.}
+proc setSize*(view: PView, size: TVector2f) {.
+  cdecl, importc: "sfView_setSize", dynlib: LibG.}
+proc setRotation*(view: PView, angle: cfloat) {.
+  cdecl, importc: "sfView_setRotation", dynlib: LibG.}
+proc setViewport*(view: PView, viewport: TFloatRect) {.
+  cdecl, importc: "sfView_setViewport", dynlib: LibG.}
+proc reset*(view: PView, rectangle: TFloatRect) {.
+  cdecl, importc: "sfView_reset", dynlib: LibG.}
+proc getCenter*(view: PView): TVector2f {.
+  cdecl, importc: "sfView_getCenter", dynlib: LibG.}
+proc getSize*(view: PView): TVector2f {.
+  cdecl, importc: "sfView_getSize", dynlib: LibG.}
+proc getRotation*(view: PView): cfloat {.
+  cdecl, importc: "sfView_getRotation", dynlib: LibG.}
+proc getViewport*(view: PView): TFloatRect {.
+  cdecl, importc: "sfView_getViewport", dynlib: LibG.}
+proc move*(view: PView, offset: TVector2f) {.
+  cdecl, importc: "sfView_move", dynlib: LibG.}
+proc rotate*(view: PView, angle: cfloat) {.
+  cdecl, importc: "sfView_rotate", dynlib: LibG.}
+proc zoom*(view: PView, factor: cfloat) {.
+  cdecl, importc: "sfView_zoom", dynlib: LibG.}
+
+proc newImage*(width, height: cint): PImage {.
+  cdecl, importc: "sfImage_create", dynlib: LibG.}
+proc newImage*(width, height: cint, color: TColor): PImage {.
+  cdecl, importc: "sfImage_createFromColor", dynlib: LibG.}
+proc newImage*(width, height: cint, pixels: pointer): PImage {. ##same deal as setIcon()
+  cdecl, importc: "sfImage_createFromPixels", dynlib: LibG.}
+proc newImage*(filename: cstring): PImage {.
+  cdecl, importc: "sfImage_createFromFile", dynlib: LibG.}
+proc newImage*(data: pointer, size: cint): PImage {.
+  cdecl, importc: "sfImage_createFromMemory", dynlib: LibG.}
+proc newImage*(stream: PInputStream): PImage {.
+  cdecl, importc: "sfImage_createFromStream", dynlib: LibG.}
+proc copy*(image: PImage): PImage {.
+  cdecl, importc: "sfImage_copy", dynlib: LibG.}
+proc destroy*(image: PImage) {.
+  cdecl, importc: "sfImage_destroy", dynlib: LibG.}
+proc save*(image: PImage, filename: cstring): bool {.
+  cdecl, importc: "sfImage_saveToFile", dynlib: LibG.}
+proc getSize*(image: PImage): TVector2i {.
+  cdecl, importc: "sfImage_getSize", dynlib: LibG.}
+proc createMask*(image: PImage, color: TColor, alpha: cchar) {.
+  cdecl, importc: "sfImage_createMaskFromColor", dynlib: LibG.}
+proc copy*(destination, source: PImage, destX, destY: cint;
+            sourceRect: TIntRect, applyAlpha: bool) {.
+  cdecl, importc: "sfImage_copyImage", dynlib: LibG.}
+proc setPixel*(image: PImage, x, y: cint, color: TColor) {.
+  cdecl, importc: "sfImage_setPixel", dynlib: LibG.}
+proc getPixel*(image: PImage, x, y: cint): TColor {.
+  cdecl, importc: "sfImage_getPixel", dynlib: LibG.}
+proc getPixels*(image: PImage): pointer {.
+  cdecl, importc: "sfImage_getPixelsPtr", dynlib: LibG.}
+proc flipHorizontally*(image: PImage) {.
+  cdecl, importc: "sfImage_flipHorizontally", dynlib: LibG.}
+proc flipVertically*(image: PImage) {.
+  cdecl, importc: "sfImage_flipVertically", dynlib: LibG.}
+
+proc newSprite*(): PSprite {.
+  cdecl, importc: "sfSprite_create", dynlib: LibG.}
+proc copy*(sprite: PSprite): PSprite {.
+  cdecl, importc: "sfSprite_copy", dynlib: LibG.}
+proc destroy*(sprite: PSprite) {.
+  cdecl, importc: "sfSprite_destroy", dynlib: LibG.}
+proc setPosition*(sprite: PSprite, position: TVector2f) {.
+  cdecl, importc: "sfSprite_setPosition", dynlib: LibG.}
+proc setRotation*(sprite: PSprite, angle: cfloat) {.
+  cdecl, importc: "sfSprite_setRotation", dynlib: LibG.}
+proc setScale*(sprite: PSprite, scale: TVector2f) {.
+  cdecl, importc: "sfSprite_setScale", dynlib: LibG.}
+proc setOrigin*(sprite: PSprite, origin: TVector2f) {.
+  cdecl, importc: "sfSprite_setOrigin", dynlib: LibG.}
+proc getPosition*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getPosition", dynlib: LibG.}
+proc getRotation*(sprite: PSprite): cfloat {.
+  cdecl, importc: "sfSprite_getRotation", dynlib: LibG.}
+proc getScale*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getScale", dynlib: LibG.}
+proc getOrigin*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getOrigin", dynlib: LibG.}
+proc move*(sprite: PSprite, offset: TVector2f) {.
+  cdecl, importc: "sfSprite_move", dynlib: LibG.}
+proc rotate*(sprite: PSprite, angle: cfloat) {.
+  cdecl, importc: "sfSprite_rotate", dynlib: LibG.}
+proc scale*(sprite: PSprite, factor: TVector2f) {.
+  cdecl, importc: "sfSprite_scale", dynlib: LibG.}
+proc getTransform*(sprite: PSprite): TTransform {.
+  cdecl, importc: "sfSprite_getTransform", dynlib: LibG.}
+proc getInverseTransform*(sprite: PSprite): TTransform {.
+  cdecl, importc: "sfSprite_getInverseTransform", dynlib: LibG.}
+proc setTexture*(sprite: PSprite, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfSprite_setTexture", dynlib: LibG.}
+proc setTextureRect*(sprite: PSprite, rectangle: TIntRect) {.
+  cdecl, importc: "sfSprite_setTextureRect", dynlib: LibG.}
+proc setColor*(sprite: PSprite, color: TColor) {.
+  cdecl, importc: "sfSprite_setColor", dynlib: LibG.}
+proc getTexture*(sprite: PSprite): TTexture {.
+  cdecl, importc: "sfSprite_getTexture", dynlib: LibG.}
+proc getTextureRect*(sprite: PSprite): TIntRect {.
+  cdecl, importc: "sfSprite_getTextureRect", dynlib: LibG.}
+proc getColor*(sprite: PSprite): TColor {.
+  cdecl, importc: "sfSprite_getColor", dynlib: LibG.}
+proc getLocalBounds*(sprite: PSprite): TFloatRect {.
+  cdecl, importc: "sfSprite_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(sprite: PSprite): TFloatRect {.
+  cdecl, importc: "sfSprite_getGlobalBounds", dynlib: LibG.}
+
+proc newTexture*(width, height: cint): PTexture {.
+  cdecl, importc: "sfTexture_create", dynlib: LibG.}
+proc newTexture*(filename: cstring): PTexture {.
+  cdecl, importc: "sfTexture_createFromFile", dynlib: LibG.}
+proc newTexture*(data: pointer, size: cint, area: PIntRect): PTexture {.
+  cdecl, importc: "sfTexture_createFromMemory", dynlib: LibG.}
+proc newTexture*(stream: PInputStream, area: PIntRect): PTexture {.
+  cdecl, importc: "sfTexture_createFromStream", dynlib: LibG.}
+proc newTexture*(image: PImage, area: PIntRect = nil): PTexture {.
+  cdecl, importc: "sfTexture_createFromImage", dynlib: LibG.}
+proc copy*(texture: PTexture): PTexture {.
+  cdecl, importc: "sfTexture_copy", dynlib: LibG.}
+proc destroy*(texture: PTexture) {.
+  cdecl, importc: "sfTexture_destroy", dynlib: LibG.}
+proc getSize*(texture: PTexture): TVector2i {.
+  cdecl, importc: "sfTexture_getSize", dynlib: LibG.}
+proc copyToImage*(texture: PTexture): PImage {.
+  cdecl, importc: "sfTexture_copyToImage", dynlib: LibG.}
+proc updateFromPixels*(texture: PTexture, pixels: pointer, width, height, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromPixels", dynlib: LibG.}
+proc updateFromImage*(texture: PTexture, image: PImage, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromImage", dynlib: LibG.}
+proc updateFromWindow*(texture: PTexture, window: PWindow, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromWindow", dynlib: LibG.}
+proc updateFromWindow*(texture: PTexture, window: PRenderWindow, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromRenderWindow", dynlib: LibG.}
+proc bindGL*(texture: PTexture) {.
+  cdecl, importc: "sfTexture_bind", dynlib: LibG.}
+proc setSmooth*(texture: PTexture, smooth: bool) {.
+  cdecl, importc: "sfTexture_setSmooth", dynlib: LibG.}
+proc isSmooth*(texture: PTexture): bool {.
+  cdecl, importc: "sfTexture_isSmooth", dynlib: LibG.}
+proc setRepeated*(texture: PTexture, repeated: bool) {.
+  cdecl, importc: "sfTexture_setRepeated", dynlib: LibG.}
+proc isRepeated*(texture: PTexture): bool {.
+  cdecl, importc: "sfTexture_isRepeated", dynlib: LibG.}
+proc textureMaxSize*(): cint {.
+  cdecl, importc: "sfTexture_getMaximumSize", dynlib: LibG.}
+
+proc newVertexArray*(): PVertexArray {.
+  cdecl, importc: "sfVertexArray_create", dynlib: LibG.}
+proc copy*(vertexArray: PVertexArray): PVertexArray {.
+  cdecl, importc: "sfVertexArray_copy", dynlib: LibG.}
+proc destroy*(va: PVertexArray) {.
+  cdecl, importc: "sfVertexArray_destroy", dynlib: LibG.}
+proc getVertexCount*(va: PVertexArray): cint {.
+  cdecl, importc: "sfVertexArray_getVertexCount", dynlib: LibG.}
+proc getVertex*(va: PVertexArray, index: cint): PVertex {.
+  cdecl, importc: "sfVertexArray_getVertex", dynlib: LibG.}
+proc clear*(va: PVertexArray) {.
+  cdecl, importc: "sfVertexArray_clear", dynlib: LibG.}
+proc resize*(va: PVertexArray, size: cint) {.
+  cdecl, importc: "sfVertexArray_resize", dynlib: LibG.}
+proc append*(va: PVertexArray, vertex: TVertex) {.
+  cdecl, importc: "sfVertexArray_append", dynlib: LibG.}
+proc setPrimitiveType*(va: PVertexArray, primitiveType: TPrimitiveType) {.
+  cdecl, importc: "sfVertexArray_setPrimitiveType", dynlib: LibG.}
+proc getPrimitiveType*(va: PVertexArray): TPrimitiveType {.
+  cdecl, importc: "sfVertexArray_getPrimitiveType", dynlib: LibG.}
+proc getBounds*(va: PVertexArray): TFloatRect {.
+  cdecl, importc: "sfVertexArray_getBounds", dynlib: LibG.}
+
+
+proc newText*(): PText {.
+  cdecl, importc: "sfText_create", dynlib: LibG.}
+proc copy*(text: PText): PText {.
+  cdecl, importc: "sfText_copy", dynlib: LibG.}
+proc destroy*(text: PText) {.
+  cdecl, importc: "sfText_destroy", dynlib: LibG.}
+proc setPosition*(text: PText, position: TVector2f) {.
+  cdecl, importc: "sfText_setPosition", dynlib: LibG.}
+proc setRotation*(text: PText, angle: cfloat) {.
+  cdecl, importc: "sfText_setRotation", dynlib: LibG.}
+proc setScale*(text: PText, scale: TVector2f) {.
+  cdecl, importc: "sfText_setScale", dynlib: LibG.}
+proc setOrigin*(text: PText, origin: TVector2f) {.
+  cdecl, importc: "sfText_setOrigin", dynlib: LibG.}
+proc getPosition*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getPosition", dynlib: LibG.}
+proc getRotation*(text: PText): cfloat {.
+  cdecl, importc: "sfText_getRotation", dynlib: LibG.}
+proc getScale*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getScale", dynlib: LibG.}
+proc getOrigin*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getOrigin", dynlib: LibG.}
+proc move*(text: PText, offset: TVector2f) {.
+  cdecl, importc: "sfText_move", dynlib: LibG.}
+proc rotate*(text: PText, angle: cfloat) {.
+  cdecl, importc: "sfText_rotate", dynlib: LibG.}
+proc scale*(text: PText, factors: TVector2f) {.
+  cdecl, importc: "sfText_scale", dynlib: LibG.}
+proc getTransform*(text: PText): TTransform {.
+  cdecl, importc: "sfText_getTransform", dynlib: LibG.}
+proc getInverseTransform*(text: PText): TTransform {.
+  cdecl, importc: "sfText_getInverseTransform", dynlib: LibG.}
+proc setString*(text: PText, string: cstring) {.
+  cdecl, importc: "sfText_setString", dynlib: LibG.}
+proc setUnicodeString*(text: PText, string: ptr uint32) {.
+  cdecl, importc: "sfText_setUnicodeString", dynlib: LibG.}
+proc setFont*(text: PText, font: PFont) {.
+  cdecl, importc: "sfText_setFont", dynlib: LibG.}
+proc setCharacterSize*(text: PText, size: cint) {.
+  cdecl, importc: "sfText_setCharacterSize", dynlib: LibG.}
+proc setStyle*(text: PText, style: TTextStyle) {.
+  cdecl, importc: "sfText_setStyle", dynlib: LibG.}
+proc setColor*(text: PText, color: TColor) {.
+  cdecl, importc: "sfText_setColor", dynlib: LibG.}
+proc getString*(text: PText): cstring {.
+  cdecl, importc: "sfText_getString", dynlib: LibG.}
+proc getUnicodeString*(text: PText): ptr uint32 {.cdecl, 
+  importc: "sfText_getUnicodeString", dynlib: LibG.}
+proc getFont*(text: PText): PFont {.
+  cdecl, importc: "sfText_getFont", dynlib: LibG.}
+proc getCharacterSize*(text: PText): cint {.
+  cdecl, importc: "sfText_getCharacterSize", dynlib: LibG.}
+proc getStyle*(text: PText): uint32 {.
+  cdecl, importc: "sfText_getStyle", dynlib: LibG.}
+proc getColor*(text: PText): TColor {.
+  cdecl, importc: "sfText_getColor", dynlib: LibG.}
+proc findCharacterPos*(text: PText, index: cint): TVector2f {.
+  cdecl, importc: "sfText_findCharacterPos", dynlib: LibG.}
+proc getLocalBounds*(text: PText): TFloatRect {.
+  cdecl, importc: "sfText_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(text: PText): TFloatRect {.
+  cdecl, importc: "sfText_getGlobalBounds", dynlib: LibG.}
+
+proc transformFromMatrix*(a00, a01, a02, a10, a11, a12, a20, a21, a22: cfloat): TTransform {.
+  cdecl, importc: "sfTransform_fromMatrix", dynlib: LibG.}
+proc getMatrix*(transform: PTransform, matrix: ptr cfloat) {.
+  cdecl, importc: "sfTransform_getMatrix", dynlib: LibG.}
+proc getInverse*(transform: PTransform): TTransform {.
+  cdecl, importc: "sfTransform_getInverse", dynlib: LibG.}
+proc transformPoint*(transform: PTransform, point: TVector2f): TVector2f {.
+  cdecl, importc: "sfTransform_transformPoint", dynlib: LibG.}
+proc transformRect*(transform: PTransform, rectangle: TFloatRect): TFloatRect {.
+  cdecl, importc: "sfTransform_transformRect", dynlib: LibG.}
+proc combine*(transform: PTransform, other: PTransform) {.
+  cdecl, importc: "sfTransform_combine", dynlib: LibG.}
+proc translate*(transform: PTransform, x, y: cfloat) {.
+  cdecl, importc: "sfTransform_translate", dynlib: LibG.}
+proc rotate*(transform: PTransform, angle: cfloat) {.
+  cdecl, importc: "sfTransform_rotate", dynlib: LibG.}
+proc rotateWithCenter*(transform: PTransform, angle, centerX, centerY: cfloat){.
+  cdecl, importc: "sfTransform_rotateWithCenter", dynlib: LibG.}
+proc scale*(transform: PTransform, scaleX, scaleY: cfloat) {.
+  cdecl, importc: "sfTransform_scale", dynlib: LibG.}
+proc scaleWithCenter*(transform: PTransform, scaleX, scaleY, centerX, centerY: cfloat) {.
+  cdecl, importc: "sfTransform_scaleWithCenter", dynlib: LibG.}
+let IdentityMatrix*: TTransform = transformFromMatrix(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
+
+
+proc newShader*(VSfilename: cstring, fragmentShaderFilename: cstring): PShader {.
+  cdecl, importc: "sfShader_createFromFile", dynlib: LibG.}
+proc newShaderFromStr*(vertexShader: cstring, fragmentShader: cstring): PShader {.
+  cdecl, importc: "sfShader_createFromMemory", dynlib: LibG.}
+proc newShader*(vertexShaderStream: PInputStream, fragmentShaderStream: PInputStream): PShader {.
+  cdecl, importc: "sfShader_createFromStream", dynlib: LibG.}
+proc destroy*(shader: PShader) {.
+  cdecl, importc: "sfShader_destroy", dynlib: LibG.}
+proc setFloatParameter*(shader: PShader, name: cstring, x: cfloat) {.
+  cdecl, importc: "sfShader_setFloatParameter", dynlib: LibG.}
+proc setFloat2Parameter*(shader: PShader, name: cstring, x, y: cfloat) {.
+  cdecl, importc: "sfShader_setFloat2Parameter", dynlib: LibG.}
+proc setFloat3Parameter*(shader: PShader, name: cstring, x, y, z: cfloat) {.
+  cdecl, importc: "sfShader_setFloat3Parameter", dynlib: LibG.}
+proc setFloat4Parameter*(shader: PShader, name: cstring, x, y, z, w: cfloat) {.
+  cdecl, importc: "sfShader_setFloat4Parameter", dynlib: LibG.}
+proc setVector2Parameter*(shader: PShader, name: cstring, vector: TVector2f) {.
+  cdecl, importc: "sfShader_setVector2Parameter", dynlib: LibG.}
+proc setVector3Parameter*(shader: PShader, name: cstring, vector: TVector3f) {.
+  cdecl, importc: "sfShader_setVector3Parameter", dynlib: LibG.}
+proc setColorParameter*(shader: PShader, name: cstring, color: TColor) {.
+  cdecl, importc: "sfShader_setColorParameter", dynlib: LibG.}
+proc setTransformParameter*(shader: PShader, name: cstring, transform: TTransform) {.
+  cdecl, importc: "sfShader_setTransformParameter", dynlib: LibG.}
+proc setTextureParameter*(shader: PShader, name: cstring, texture: PTexture) {.
+  cdecl, importc: "sfShader_setTextureParameter", dynlib: LibG.}
+proc setCurrentTextureParameter*(shader: PShader, name: cstring) {.
+  cdecl, importc: "sfShader_setCurrentTextureParameter", dynlib: LibG.}
+proc bindGL*(shader: PShader) {.
+  cdecl, importc: "sfShader_bind", dynlib: LibG.}
+proc unbindGL*(shader: PShader) {.
+  cdecl, importc: "sfShader_unbind", dynlib: LibG.}
+proc shaderIsAvailable*(): bool {.
+  cdecl, importc: "sfShader_isAvailable", dynlib: LibG.}
+
+proc color*(red, green, blue: cchar): TColor {.
+  cdecl, importc: "sfColor_fromRGB", dynlib: LibG.}
+proc color*(red, green, blue: int): TColor {.inline.} =
+  return color(red.cchar, green.cchar, blue.cchar)
+proc color*(red, green, blue, alpha: cchar): TColor {.
+  cdecl, importc: "sfColor_fromRGBA", dynlib: LibG.}
+proc color*(red, green, blue, alpha: int): TColor {.inline.} =
+  return color(red.cchar, green.cchar, blue.cchar, alpha.cchar)
+proc `+`*(color1, color2: TColor): TColor {.
+  cdecl, importc: "sfColor_add", dynlib: LibG.}
+proc `*`*(color1, color2: TColor): TColor {.
+  cdecl, importc: "sfColor_modulate", dynlib: LibG.}
+proc newColor*(r,g,b: int): TColor {.inline.} =
+  return color(r,g,b)
+proc newColor*(r,g,b,a: int): TColor {.inline.} = 
+  return color(r,g,b,a)
+
+proc newClock*(): PClock {.
+  cdecl, importc: "sfClock_create", dynlib: LibS.}
+proc copy*(clocK: PClock): PClock {.
+  cdecl, importc: "sfClock_copy", dynlib: LibS.}
+proc destroy*(clock: PClock): PClock {.
+  cdecl, importc: "sfClock_destroy", dynlib: LibS.}
+proc getElapsedTime*(clock: PClock): TTime {.
+  cdecl, importc: "sfClock_getElapsedTime", dynlib: LibS.}
+proc restart*(clock: PClock): TTime {.
+  cdecl, importc: "sfClock_restart", dynlib: LibS, discardable.}
+proc asSeconds*(time: TTime): cfloat {.
+  cdecl, importc: "sfTime_asSeconds", dynlib: LibS.}
+proc asMilliseconds*(time: TTime): int32 {.
+  cdecl, importc: "sfTime_asMilliseconds", dynlib: LibS.}
+proc asMicroseconds*(time: TTime): int64 {.
+  cdecl, importc: "sfTime_asMicroseconds", dynlib: LibS.}
+proc seconds*(seconds: cfloat): TTime {.
+  cdecl, importc: "sfSeconds", dynlib: LibS.}
+proc milliseconds*(ms: int32): TTime {.
+  cdecl, importc: "sfMilliseconds", dynlib: LibS.}
+proc microseconds*(us: int64): TTime {.
+  cdecl, importc: "sfMicroseconds", dynlib: LibS.}
+
+proc newContextSettings*(depthBits: cint = 0,
+                         stencilBits: cint = 0,
+                         antialiasingLevel: cint = 0,
+                         majorVersion: cint = 0,
+                         minorVersion: cint = 0): TContextSettings =
+  result.depthBits = depthBits
+  result.stencilBits = stencilBits
+  result.antialiasingLevel = antialiasingLevel
+  result.majorVersion = majorVersion
+  result.minorVersion = minorVersion
+
+proc newCircleShape*(radius: cfloat; pointCount: cint = 30): PCircleShape = 
+  result = newCircleShape()
+  result.setRadius radius
+  result.setPointCount pointCount
+proc newText*(str: string, font: PFont, size: int): PText =
+  result = newText()
+  result.setString(str)
+  result.setFont(font)
+  result.setCharacterSize(size.cint)
+proc newVertexArray*(primitiveType: TPrimitiveType, vertexCount: cint = 0): PVertexArray =
+  result = newVertexArray()
+  result.setPrimitiveType(primitiveType)
+  if vertexCount != 0:
+    result.resize(vertexCount)
+proc videoMode*(width, height, bpp: cint): TVideoMode =
+  result.width = width
+  result.height = height
+  result.bitsPerPixel = bpp
+
+proc `[]`*(a: PVertexArray, index: int): PVertex =
+  return getVertex(a, index.cint)
+
+proc `$` *(a: TContextSettings): string =
+  return "<TContextSettings stencil=$1 aa=$2 major=$3 minor=$4 depth=$5>" % [
+    $a.stencilBits, $a.antialiasingLevel, $a.majorVersion, $a.minorVersion, $a.depthBits]
+proc `$` *(a: TVideoMode): string = 
+  return "<TVideoMode $1x$2 $3bpp>" % [$a.width, $a.height, $a.bitsPerPixel]
+proc `$` *(a: TFloatRect): string = 
+  return "<TFloatRect $1,$2 $3x$4>" % [$a.left, $a.top, $a.width, $a.height]
+proc `$` *(a: PView): string = 
+  return $a.getViewport()
+proc `$` *(a: TVector2f): string = 
+  return "<TVector2f $1,$2>" % [$a.x, $a.y]
+
+proc vec2i*(x, y: int): TVector2i =
+  result.x = x.cint
+  result.y = y.cint
+proc vec2f*(x, y: float): TVector2f =
+  result.x = x.cfloat
+  result.y = y.cfloat
+
+proc `+`*(a, b: TVector2f): TVector2f {.inline.} =
+  result.x = a.x + b.x
+  result.y = a.y + b.y
+proc `-`*(a: TVector2f): TVector2f {.inline.} =
+  result.x = -a.x
+  result.y = -a.y
+proc `-`*(a, b: TVector2f): TVector2f {.inline.}=
+  result.x = a.x - b.x
+  result.y = a.y - b.y
+proc `*`*(a: TVector2f, b: cfloat): TVector2f {.inline.} =
+  result.x = a.x * b
+  result.y = a.y * b
+proc `*`*(a, b: TVector2f): TVector2f {.inline.} =
+  result.x = a.x * b.x
+  result.y = a.y * b.y
+proc `/`*(a: TVector2f, b: cfloat): TVector2f {.inline.} =
+  result.x = a.x / b
+  result.y = a.y / b
+proc `+=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a + b
+proc `-=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a - b
+proc `*=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} =
+  a = a * b
+proc `*=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a * b
+proc `/=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} =
+  a = a / b
+proc `<` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x < b.x or (a.x == b.x and a.y < b.y)
+proc `<=` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x <= b.x and a.y <= b.y
+proc `==` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x == b.x and a.y == b.y
+proc length*(a: TVector2f): float {.inline.} =
+  return sqrt(pow(a.x, 2.0) + pow(a.y, 2.0))
+proc lengthSq*(a: TVector2f): float {.inline.} =
+  return pow(a.x, 2.0) + pow(a.y, 2.0)
+proc distanceSq*(a, b: TVector2f): float {.inline.} =
+  return pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0)
+proc distance*(a, b: TVector2f): float {.inline.} =
+  return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0))
+proc permul*(a, b: TVector2f): TVector2f =
+  result.x = a.x * b.x
+  result.y = a.y * b.y
+proc rotate*(a: TVector2f, phi: float): TVector2f =
+  var c = cos(phi)
+  var s = sin(phi)
+  result.x = a.x * c - a.y * s
+  result.y = a.x * s + a.y * c
+proc perpendicular(a: TVector2f): TVector2f =
+  result.x = -a.x
+  result.y =  a.y
+proc cross(a, b: TVector2f): float =
+  return a.x * b.y - a.y * b.x
+
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
new file mode 100644
index 000000000..5aa017ac4
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
@@ -0,0 +1,899 @@
+import
+  sfml
+const
+  Lib = "libcsfml-audio.so.2.0"
+type
+  PMusic* = ptr TMusic
+  TMusic* {.pure, final.} = object
+  PSound* = ptr TSound
+  TSound* {.pure, final.} = object
+  PSoundBuffer* = ptr TSoundBuffer
+  TSoundBuffer* {.pure, final.} = object
+  PSoundBufferRecorder* = ptr TSoundBufferRecorder
+  TSoundBufferRecorder* {.pure, final.} = object
+  PSoundRecorder* = ptr TSoundRecorder
+  TSoundRecorder* {.pure, final.} = object
+  PSoundStream* = ptr TSoundStream
+  TSoundStream* {.pure, final.} = object
+  TSoundStatus* {.size: sizeof(cint).} = enum
+    Stopped, Paused, Playing
+
+proc newMusic*(filename: cstring): PMusic {.
+  cdecl, importc: "sfMusic_createFromFile", dynlib: Lib.}
+proc newMusic*(data: pointer, size: cint): PMusic {.
+  cdecl, importc: "sfMusic_createFromMemory", dynlib: Lib.}
+proc newMusic*(stream: PInputStream): PMusic {.
+  cdecl, importc: "sfMusic_createFromStream", dynlib: Lib.}
+proc destroy*(music: PMusic) {.
+  cdecl, importc: "sfMusic_destroy", dynlib: Lib.}
+proc setLoop*(music: PMusic, loop: bool) {.
+  cdecl, importc: "sfMusic_setLoop", dynlib: Lib.}
+proc getLoop*(music: PMusic): bool {.
+  cdecl, importc: "sfMusic_getLoop", dynlib: Lib.}
+proc getDuration*(music: PMusic): TTime {.
+  cdecl, importc: "sfMusic_getDuration", dynlib: Lib.}
+proc play*(music: PMusic) {.
+  cdecl, importc: "sfMusic_play", dynlib: Lib.}
+proc pause*(music: PMusic) {.
+  cdecl, importc: "sfMusic_pause", dynlib: Lib.}
+proc stop*(music: PMusic) {.
+  cdecl, importc: "sfMusic_stop", dynlib: Lib.}
+proc getChannelCount*(music: PMusic): cint {.
+  cdecl, importc: "sfMusic_getChannelCount", dynlib: Lib.}
+proc getSampleRate*(music: PMusic): cint {.
+  cdecl, importc: "sfMusic_getSampleRate", dynlib: Lib.}
+proc getStatus*(music: PMusic): TSoundStatus {.
+  cdecl, importc: "sfMusic_getStatus", dynlib: Lib.}
+proc getPlayingOffset*(music: PMusic): TTime {.
+  cdecl, importc: "sfMusic_getPlayingOffset", dynlib: Lib.}
+proc setPitch*(music: PMusic, pitch: cfloat) {.
+  cdecl, importc: "sfMusic_setPitch", dynlib: Lib.}
+proc setVolume*(music: PMusic, volume: float) {.
+  cdecl, importc: "sfMusic_setVolume", dynlib: Lib.}
+proc setPosition*(music: PMusic, position: TVector3f) {.
+  cdecl, importc: "sfMusic_setPosition", dynlib: Lib.}
+proc setRelativeToListener*(music: PMusic, relative: bool) {.
+  cdecl, importc: "sfMusic_setRelativeToListener", dynlib: Lib.}
+proc setMinDistance*(music: PMusic, distance: cfloat) {.
+  cdecl, importc: "sfMusic_setMinDistance", dynlib: Lib.}
+proc setAttenuation*(music: PMusic, attenuation: cfloat) {.
+  cdecl, importc: "sfMusic_setAttenuation", dynlib: Lib.}
+proc setPlayingOffset*(music: PMusic, time: TTime) {.
+  cdecl, importc: "sfMusic_setPlayingOffset", dynlib: Lib.}
+proc getPitch*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_getPitch", dynlib: Lib.}
+proc getVolume*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_getVolume", dynlib: Lib.}
+proc getPosition*(music: PMusic): TVector3f {.
+  cdecl, importc: "sfMusic_getPosition", dynlib: Lib.}
+proc isRelativeToListener*(music: PMusic): bool {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+proc getMinDistance*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+proc getAttenuation*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+
+#/ \brief Create a new sound
+proc newSound*(): PSound{.
+  cdecl, importc: "sfSound_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound by copying an existing one
+#/
+#/ \param sound Sound to copy
+#/
+#/ \return A new sfSound object which is a copy of \a sound
+#/
+#//////////////////////////////////////////////////////////
+proc copy*(sound: PSound): PSound{.
+  cdecl, importc: "sfSound_copy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound
+proc destroy*(sound: PSound){.
+  cdecl, importc: "sfSound_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start or resume playing a sound
+#/
+#/ This function starts the sound if it was stopped, resumes
+#/ it if it was paused, and restarts it from beginning if it
+#/ was it already playing.
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the sound is played.
+proc play*(sound: PSound){.
+  cdecl, importc: "sfSound_play", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ This function pauses the sound if it was playing,
+#/ otherwise (sound already paused or stopped) it has no effect.
+proc pause*(sound: PSound){.
+  cdecl, importc: "sfSound_pause", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ This function stops the sound if it was playing or paused,
+#/ and does nothing if it was already stopped.
+#/ It also resets the playing position (unlike sfSound_pause).
+proc stop*(sound: PSound){.
+  cdecl, importc: "sfSound_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ It is important to note that the sound buffer is not copied,
+#/ thus the sfSoundBuffer object must remain alive as long
+#/ as it is attached to the sound.
+proc setBuffer*(sound: PSound; buffer: PSoundBuffer){.
+  cdecl, importc: "sfSound_setBuffer", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the audio buffer attached to a sound
+proc getBuffer*(sound: PSound): PSoundBuffer{.
+  cdecl, importc: "sfSound_getBuffer", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set whether or not a sound should loop after reaching the end
+#/
+#/ If set, the sound will restart from beginning after
+#/ reaching the end and so on, until it is stopped or
+#/ sfSound_setLoop(sound, sfFalse) is called.
+#/ The default looping state for sounds is false.
+proc setLoop*(sound: PSound; loop: bool){.
+  cdecl, importc: "sfSound_setLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether or not a soud is in loop mode
+proc getLoop*(sound: PSound): bool {.
+  cdecl, importc: "sfSound_getLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current status of a sound (stopped, paused, playing)
+proc getStatus*(sound: PSound): TSoundStatus{.
+  cdecl, importc: "sfSound_getStatus", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the pitch of a sound
+#/
+#/ The pitch represents the perceived fundamental frequency
+#/ of a sound; thus you can make a sound more acute or grave
+#/ by changing its pitch. A side effect of changing the pitch
+#/ is to modify the playing speed of the sound as well.
+#/ The default value for the pitch is 1.
+proc setPitch*(sound: PSound; pitch: cfloat){.
+  cdecl, importc: "sfSound_setPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the volume of a sound
+#/
+#/ The volume is a value between 0 (mute) and 100 (full volume).
+#/ The default value for the volume is 100.
+proc setVolume*(sound: PSound; volume: cfloat){.
+  cdecl, importc: "sfSound_setVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the 3D position of a sound in the audio scene
+#/
+#/ Only sounds with one channel (mono sounds) can be
+#/ spatialized.
+#/ The default position of a sound is (0, 0, 0).
+proc setPosition*(sound: PSound; position: TVector3f){.
+  cdecl, importc: "sfSound_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Make the sound's position relative to the listener or absolute
+#/
+#/ Making a sound relative to the listener will ensure that it will always
+#/ be played the same way regardless the position of the listener.
+#/ This can be useful for non-spatialized sounds, sounds that are
+#/ produced by the listener, or sounds attached to it.
+#/ The default value is false (position is absolute).
+proc setRelativeToListener*(sound: PSound; relative: bool){.
+  cdecl, importc: "sfSound_setRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the minimum distance of a sound
+#/
+#/ The "minimum distance" of a sound is the maximum
+#/ distance at which it is heard at its maximum volume. Further
+#/ than the minimum distance, it will start to fade out according
+#/ to its attenuation factor. A value of 0 ("inside the head
+#/ of the listener") is an invalid value and is forbidden.
+#/ The default value of the minimum distance is 1.
+proc setMinDistance*(sound: PSound; distance: cfloat){.
+  cdecl, importc: "sfSound_setMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the attenuation factor of a sound
+#/
+#/ The attenuation is a multiplicative factor which makes
+#/ the sound more or less loud according to its distance
+#/ from the listener. An attenuation of 0 will produce a
+#/ non-attenuated sound, i.e. its volume will always be the same
+#/ whether it is heard from near or from far. On the other hand,
+#/ an attenuation value such as 100 will make the sound fade out
+#/ very quickly as it gets further from the listener.
+#/ The default value of the attenuation is 1.
+proc setAttenuation*(sound: PSound; attenuation: cfloat){.
+  cdecl, importc: "sfSound_setAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Change the current playing position of a sound
+#/
+#/ The playing position can be changed when the sound is
+#/ either paused or playing.
+proc setPlayingOffset*(sound: PSound; timeOffset: sfml.TTime){.
+  cdecl, importc: "sfSound_setPlayingOffset", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the pitch of a sound
+proc getPitch*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the volume of a sound
+proc getVolume*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the 3D position of a sound in the audio scene
+proc getPosition*(sound: PSound): TVector3f{.
+  cdecl, importc: "sfSound_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether a sound's position is relative to the
+#/        listener or is absolute
+proc isRelativeToListener*(sound: PSound): bool{.
+  cdecl, importc: "sfSound_isRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the minimum distance of a sound
+proc getMinDistance*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the attenuation factor of a sound
+proc getAttenuation*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current playing position of a sound
+proc getPlayingOffset*(sound: PSound): TTime{.
+  cdecl, importc: "sfSound_getPlayingOffset", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+# Headers
+#//////////////////////////////////////////////////////////
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a file
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param filename Path of the sound file to load
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(filename: cstring): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromFile", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a file in memory
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param data        Pointer to the file data in memory
+#/ \param sizeInBytes Size of the data to load, in bytes
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(data: pointer; sizeInBytes: cint): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromMemory", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a custom stream
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param stream Source stream to read from
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(stream: PInputStream): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromStream", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from an array of samples in memory
+#/
+#/ The assumed format of the audio samples is 16 bits signed integer
+#/ (sfint16).
+#/
+#/ \param samples      Pointer to the array of samples in memory
+#/ \param sampleCount  Number of samples in the array
+#/ \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
+#/ \param sampleRate   Sample rate (number of samples to play per second)
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc createFromSamples*(samples: ptr int16; sampleCount: cuint; 
+                         channelCount: cuint; sampleRate: cuint): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromSamples", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer by copying an existing one
+#/
+#/ \param soundBuffer Sound buffer to copy
+#/
+#/ \return A new sfSoundBuffer object which is a copy of \a soundBuffer
+#/
+#//////////////////////////////////////////////////////////
+proc copy*(soundBuffer: PSoundBuffer): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_copy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound buffer
+#/
+#/ \param soundBuffer Sound buffer to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundBuffer: PSoundBuffer){.
+  cdecl, importc: "sfSoundBuffer_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Save a sound buffer to an audio file
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param soundBuffer Sound buffer object
+#/ \param filename    Path of the sound file to write
+#/
+#/ \return sfTrue if saving succeeded, sfFalse if it failed
+#/
+#//////////////////////////////////////////////////////////
+proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {.
+  cdecl, importc: "sfSoundBuffer_saveToFile", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the array of audio samples stored in a sound buffer
+#/
+#/ The format of the returned samples is 16 bits signed integer
+#/ (sfint16). The total number of samples in this array
+#/ is given by the sfSoundBuffer_getSampleCount function.
+#/
+#/ \param soundBuffer Sound buffer object
+#/
+#/ \return Read-only pointer to the array of sound samples
+#/
+#//////////////////////////////////////////////////////////
+proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr int16{.
+  cdecl, importc: "sfSoundBuffer_getSamples", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the number of samples stored in a sound buffer
+#/
+#/ The array of samples can be accessed with the
+#/ sfSoundBuffer_getSamples function.
+proc getSampleCount*(soundBuffer: PSoundBuffer): cint{.
+  cdecl, importc: "sfSoundBuffer_getSampleCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound buffer
+#/
+#/ The sample rate is the number of samples played per second.
+#/ The higher, the better the quality (for example, 44100
+#/ samples/s is CD quality).
+proc getSampleRate*(soundBuffer: PSoundBuffer): cuint{.
+  cdecl, importc: "sfSoundBuffer_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the number of channels used by a sound buffer
+#/
+#/ If the sound is mono then the number of channels will
+#/ be 1, 2 for stereo, etc.
+proc getChannelCount*(soundBuffer: PSoundBuffer): cuint{.
+  cdecl, importc: "sfSoundBuffer_getChannelCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the total duration of a sound buffer
+#/
+#/ \param soundBuffer Sound buffer object
+#/
+#/ \return Sound duration
+#/
+#//////////////////////////////////////////////////////////
+proc getDuration*(soundBuffer: PSoundBuffer): TTime{.
+  cdecl, importc: "sfSoundBuffer_getDuration", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+#/ \brief Change the global volume of all the sounds and musics
+#/
+#/ The volume is a number between 0 and 100; it is combined with
+#/ the individual volume of each sound / music.
+#/ The default value for the volume is 100 (maximum).
+#/
+#/ \param volume New global volume, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetGlobalVolume*(volume: cfloat){.
+  cdecl, importc: "sfListener_setGlobalVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current value of the global volume
+#/
+#/ \return Current global volume, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetGlobalVolume*(): cfloat{.
+  cdecl, importc: "sfListener_getGlobalVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the position of the listener in the scene
+#/
+#/ The default listener's position is (0, 0, 0).
+#/
+#/ \param position New position of the listener
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetPosition*(position: TVector3f){.
+  cdecl, importc: "sfListener_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current position of the listener in the scene
+#/
+#/ \return The listener's position
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetPosition*(): TVector3f{.
+  cdecl, importc: "sfListener_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the orientation of the listener in the scene
+#/
+#/ The orientation defines the 3D axes of the listener
+#/ (left, up, front) in the scene. The orientation vector
+#/ doesn't have to be normalized.
+#/ The default listener's orientation is (0, 0, -1).
+#/
+#/ \param position New direction of the listener
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetDirection*(orientation: TVector3f){.
+  cdecl, importc: "sfListener_setDirection", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current orientation of the listener in the scene
+#/
+#/ \return The listener's direction
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetDirection*(): TVector3f{.
+  cdecl, importc: "sfListener_getDirection", dynlib: Lib.}
+
+type 
+  TSoundRecorderStartCallback* = proc (a2: pointer): bool {.cdecl.}
+  #/< Type of the callback used when starting a capture 
+  TSoundRecorderProcessCallback* = proc(a2: ptr int16; a3: cuint; 
+    a4: pointer): bool {.cdecl.}
+  #/< Type of the callback used to process audio data
+  TSoundRecorderStopCallback* = proc (a2: pointer){.cdecl.}
+  #/< Type of the callback used when stopping a capture
+#//////////////////////////////////////////////////////////
+#/ \brief Construct a new sound recorder from callback functions
+#/
+#/ \param onStart   Callback function which will be called when a new capture starts (can be NULL)
+#/ \param onProcess Callback function which will be called each time there's audio data to process
+#/ \param onStop    Callback function which will be called when the current capture stops (can be NULL)
+#/ \param userData  Data to pass to the callback function (can be NULL)
+#/
+#/ \return A new sfSoundRecorder object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundRecorder*(onStart: TSoundRecorderStartCallback; 
+                        onProcess: TSoundRecorderProcessCallback; 
+                        onStop: TSoundRecorderStopCallback; 
+                        userData: pointer = nil): PSoundRecorder{.
+  cdecl, importc: "sfSoundRecorder_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound recorder
+#/
+#/ \param soundRecorder Sound recorder to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundRecorder: PSoundRecorder){.
+  cdecl, importc: "sfSoundRecorder_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start the capture of a sound recorder
+#/
+#/ The \a sampleRate parameter defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the capture runs.
+#/ Please note that only one capture can happen at the same time.
+#/
+#/ \param soundRecorder Sound recorder object
+#/ \param sampleRate    Desired capture rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc start*(soundRecorder: PSoundRecorder; sampleRate: cuint){.
+  cdecl, importc: "sfSoundRecorder_start", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop the capture of a sound recorder
+#/
+#/ \param soundRecorder Sound recorder object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundRecorder: PSoundRecorder){.
+  cdecl, importc: "sfSoundRecorder_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound recorder
+#/
+#/ The sample rate defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/
+#/ \param soundRecorder Sound recorder object
+#/
+#/ \return Sample rate, in samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundRecorder: PSoundRecorder): cuint{.
+  cdecl, importc: "sfSoundRecorder_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Check if the system supports audio capture
+#/
+#/ This function should always be called before using
+#/ the audio capture features. If it returns false, then
+#/ any attempt to use sfSoundRecorder will fail.
+#/
+#/ \return sfTrue if audio capture is supported, sfFalse otherwise
+#/
+#//////////////////////////////////////////////////////////
+proc soundRecorderIsAvailable*(): bool {.
+  cdecl, importc: "sfSoundRecorder_isAvailable", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer recorder
+#/
+#/ \return A new sfSoundBufferRecorder object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBufferRecorder*(): PSoundBufferRecorder{.
+  cdecl, importc: "sfSoundBufferRecorder_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound buffer recorder
+#/
+#/ \param soundBufferRecorder Sound buffer recorder to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundBufferRecorder: PSoundBufferRecorder){.
+  cdecl, importc: "sfSoundBufferRecorder_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start the capture of a sound recorder recorder
+#/
+#/ The \a sampleRate parameter defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the capture runs.
+#/ Please note that only one capture can happen at the same time.
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/ \param sampleRate          Desired capture rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc start*(soundBufferRecorder: PSoundBufferRecorder; sampleRate: cuint){.
+  cdecl, importc: "sfSoundBufferRecorder_start", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop the capture of a sound recorder
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundBufferRecorder: PSoundBufferRecorder){.
+  cdecl, importc: "sfSoundBufferRecorder_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound buffer recorder
+#/
+#/ The sample rate defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#/ \return Sample rate, in samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundBufferRecorder: PSoundBufferRecorder): cuint{.
+  cdecl, importc: "sfSoundBufferRecorder_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sound buffer containing the captured audio data
+#/
+#/ The sound buffer is valid only after the capture has ended.
+#/ This function provides a read-only access to the internal
+#/ sound buffer, but it can be copied if you need to
+#/ make any modification to it.
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#/ \return Read-only access to the sound buffer
+#/
+#//////////////////////////////////////////////////////////
+proc getBuffer*(soundBufferRecorder: PSoundBufferRecorder): PSoundBuffer{.
+  cdecl, importc: "sfSoundBufferRecorder_getBuffer", dynlib: Lib.}
+
+
+#//////////////////////////////////////////////////////////
+#/ \brief defines the data to fill by the OnGetData callback
+#/
+#//////////////////////////////////////////////////////////
+type 
+  PSoundStreamChunk* = ptr TSoundStreamChunk
+  TSoundStreamChunk*{.pure, final.} = object 
+    samples*: ptr int16   #/< Pointer to the audio samples
+    sampleCount*: cuint     #/< Number of samples pointed by Samples
+  
+  TSoundStreamGetDataCallback* = proc (a2: PSoundStreamChunk; 
+      a3: pointer): bool{.cdecl.}
+  #/< Type of the callback used to get a sound stream data
+  TSoundStreamSeekCallback* = proc (a2: TTime; a3: pointer){.cdecl.}
+  #/< Type of the callback used to seek in a sound stream
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound stream
+#/
+#/ \param onGetData    Function called when the stream needs more data (can't be NULL)
+#/ \param onSeek       Function called when the stream seeks (can't be NULL)
+#/ \param channelCount Number of channels to use (1 = mono, 2 = stereo)
+#/ \param sampleRate   Sample rate of the sound (44100 = CD quality)
+#/ \param userData     Data to pass to the callback functions
+#/
+#/ \return A new sfSoundStream object
+#/
+#//////////////////////////////////////////////////////////
+proc create*(onGetData: TSoundStreamGetDataCallback; onSeek: TSoundStreamSeekCallback; 
+              channelCount: cuint; sampleRate: cuint; userData: pointer): PSoundStream{.
+  cdecl, importc: "sfSoundStream_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound stream
+#/
+#/ \param soundStream Sound stream to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start or resume playing a sound stream
+#/
+#/ This function starts the stream if it was stopped, resumes
+#/ it if it was paused, and restarts it from beginning if it
+#/ was it already playing.
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the music is played.
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc play*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_play", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Pause a sound stream
+#/
+#/ This function pauses the stream if it was playing,
+#/ otherwise (stream already paused or stopped) it has no effect.
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc pause*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_pause", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop playing a sound stream
+#/
+#/ This function stops the stream if it was playing or paused,
+#/ and does nothing if it was already stopped.
+#/ It also resets the playing position (unlike sfSoundStream_pause).
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current status of a sound stream (stopped, paused, playing)
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Current status
+#/
+#//////////////////////////////////////////////////////////
+proc getStatus*(soundStream: PSoundStream): TSoundStatus{.
+  cdecl, importc: "sfSoundStream_getStatus", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Return the number of channels of a sound stream
+#/
+#/ 1 channel means a mono sound, 2 means stereo, etc.
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Number of channels
+#/
+#//////////////////////////////////////////////////////////
+proc getChannelCount*(soundStream: PSoundStream): cuint{.
+  cdecl, importc: "sfSoundStream_getChannelCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound stream
+#/
+#/ The sample rate is the number of audio samples played per
+#/ second. The higher, the better the quality.
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Sample rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundStream: PSoundStream): cuint{.
+  cdecl, importc: "sfSoundStream_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the pitch of a sound stream
+#/
+#/ The pitch represents the perceived fundamental frequency
+#/ of a sound; thus you can make a stream more acute or grave
+#/ by changing its pitch. A side effect of changing the pitch
+#/ is to modify the playing speed of the stream as well.
+#/ The default value for the pitch is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param pitch       New pitch to apply to the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setPitch*(soundStream: PSoundStream; pitch: cfloat){.
+  cdecl, importc: "sfSoundStream_setPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the volume of a sound stream
+#/
+#/ The volume is a value between 0 (mute) and 100 (full volume).
+#/ The default value for the volume is 100.
+#/
+#/ \param soundStream Sound stream object
+#/ \param volume      Volume of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setVolume*(soundStream: PSoundStream; volume: cfloat){.
+  cdecl, importc: "sfSoundStream_setVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the 3D position of a sound stream in the audio scene
+#/
+#/ Only streams with one channel (mono streams) can be
+#/ spatialized.
+#/ The default position of a stream is (0, 0, 0).
+#/
+#/ \param soundStream Sound stream object
+#/ \param position    Position of the stream in the scene
+#/
+#//////////////////////////////////////////////////////////
+proc setPosition*(soundStream: PSoundStream; position: TVector3f){.
+  cdecl, importc: "sfSoundStream_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Make a sound stream's position relative to the listener or absolute
+#/
+#/ Making a stream relative to the listener will ensure that it will always
+#/ be played the same way regardless the position of the listener.
+#/ This can be useful for non-spatialized streams, streams that are
+#/ produced by the listener, or streams attached to it.
+#/ The default value is false (position is absolute).
+#/
+#/ \param soundStream Sound stream object
+#/ \param relative    sfTrue to set the position relative, sfFalse to set it absolute
+#/
+#//////////////////////////////////////////////////////////
+proc setRelativeToListener*(soundStream: PSoundStream; relative: bool){.
+  cdecl, importc: "sfSoundStream_setRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the minimum distance of a sound stream
+#/
+#/ The "minimum distance" of a stream is the maximum
+#/ distance at which it is heard at its maximum volume. Further
+#/ than the minimum distance, it will start to fade out according
+#/ to its attenuation factor. A value of 0 ("inside the head
+#/ of the listener") is an invalid value and is forbidden.
+#/ The default value of the minimum distance is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param distance    New minimum distance of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setMinDistance*(soundStream: PSoundStream; distance: cfloat){.
+  cdecl, importc: "sfSoundStream_setMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the attenuation factor of a sound stream
+#/
+#/ The attenuation is a multiplicative factor which makes
+#/ the stream more or less loud according to its distance
+#/ from the listener. An attenuation of 0 will produce a
+#/ non-attenuated stream, i.e. its volume will always be the same
+#/ whether it is heard from near or from far. On the other hand,
+#/ an attenuation value such as 100 will make the stream fade out
+#/ very quickly as it gets further from the listener.
+#/ The default value of the attenuation is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param attenuation New attenuation factor of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setAttenuation*(soundStream: PSoundStream; attenuation: cfloat){.
+  cdecl, importc: "sfSoundStream_setAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Change the current playing position of a sound stream
+#/
+#/ The playing position can be changed when the stream is
+#/ either paused or playing.
+#/
+#/ \param soundStream Sound stream object
+#/ \param timeOffset  New playing position
+#/
+#//////////////////////////////////////////////////////////
+proc setPlayingOffset*(soundStream: PSoundStream; timeOffset: TTime){.
+  cdecl, importc: "sfSoundStream_setPlayingOffset", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set whether or not a sound stream should loop after reaching the end
+#/
+#/ If set, the stream will restart from beginning after
+#/ reaching the end and so on, until it is stopped or
+#/ sfSoundStream_setLoop(stream, sfFalse) is called.
+#/ The default looping state for sound streams is false.
+#/
+#/ \param soundStream Sound stream object
+#/ \param loop        sfTrue to play in loop, sfFalse to play once
+#/
+#//////////////////////////////////////////////////////////
+proc setLoop*(soundStream: PSoundStream; loop: bool){.
+  cdecl, importc: "sfSoundStream_setLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the pitch of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Pitch of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getPitch*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the volume of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Volume of the stream, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc getVolume*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the 3D position of a sound stream in the audio scene
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Position of the stream in the world
+#/
+#//////////////////////////////////////////////////////////
+proc getPosition*(soundStream: PSoundStream): TVector3f{.
+  cdecl, importc: "sfSoundStream_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether a sound stream's position is relative to the
+#/        listener or is absolute
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return sfTrue if the position is relative, sfFalse if it's absolute
+#/
+#//////////////////////////////////////////////////////////
+proc isRelativeToListener*(soundStream: PSoundStream): bool{.
+  cdecl, importc: "sfSoundStream_isRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the minimum distance of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Minimum distance of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getMinDistance*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the attenuation factor of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Attenuation factor of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getAttenuation*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether or not a sound stream is in loop mode
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return sfTrue if the music is looping, sfFalse otherwise
+#/
+#//////////////////////////////////////////////////////////
+proc getLoop*(soundStream: PSoundStream): bool{.
+  cdecl, importc: "sfSoundStream_getLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current playing position of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Current playing position
+#/
+#//////////////////////////////////////////////////////////
+proc getPlayingOffset*(soundStream: PSoundStream): TTime{.
+  cdecl, importc: "sfSoundStream_getPlayingOffset", dynlib: Lib.}
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim
new file mode 100644
index 000000000..31473b17a
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim
@@ -0,0 +1,15 @@
+import sfml
+{.deadCodeElim: on.}
+let
+  Black*: TColor = color(0, 0, 0)
+  White*: TColor = color(255, 255, 255)
+  Red*: TColor = color(255, 0, 0)
+  Green*: TColor = color(0, 255, 0)
+  Blue*: TColor = color(0, 0, 255)
+  Yellow*: TColor = color(255, 255, 0)
+  Magenta*: TColor = color(255, 0, 255)
+  Cyan*: TColor = color(0, 255, 255)
+  Transparent*: TColor = color(0, 0, 0, 0)
+  Gray* = color(84, 84, 84)
+  RoyalBlue* = color(65, 105, 225)
+##todo: define more colors lul
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim
new file mode 100644
index 000000000..474d249aa
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim
@@ -0,0 +1,2 @@
+import sfml, math, strutils
+{.deadCodeElim: on.}
diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim
new file mode 100644
index 000000000..5ebbdb88b
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim
@@ -0,0 +1,229 @@
+import enet, strutils,
+  sfml, sfml_colors, sg_gui, input_helpers,
+  math_helpers, sg_packets, estreams, tables,
+  json, sg_assets, client_helpers
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+type
+  TClientSettings = object
+    resolution*: TVideoMode
+    offlineFile: string
+    dirserver: tuple[host: string, port: int16]
+    website*: string
+var
+  clientSettings: TClientSettings
+  event: enet.TEvent
+  bConnected = false
+  runServer = true
+  gui = newGuiContainer()
+  zonelist = newGuiContainer()
+  kc = newKeyClient(setActive = true)
+  clock = newClock()
+  chatBox: PMessageArea
+  chatInput: PTextEntry
+  loginBtn, playBtn: PButton
+  fpsText = newText("", guiFont, 18)
+  connectionButtons: seq[PButton]
+  connectButton: PButton
+  u_alias, u_passwd: PTextEntry
+  dirServer: PServer
+  zone: PServer
+  showZoneList = false
+  myCreds = newScLogin(0, "", "") ##my session token
+
+proc handleChat(server: PServer; buf: PBuffer) =
+  let msg = readScChat(buf)
+  chatBox.add msg
+proc handlePlayerLogin(server: PServer; buf: PBuffer) =
+  let login = readScLogin(buf)
+  myCreds = login
+  echo("I am ", $myCreds)
+
+
+kc.registerHandler MouseLeft, down, proc() =
+  gui.click(input_helpers.getMousePos())
+
+block:
+  var pos = vec2f(15, 550)
+  chatBox = gui.newMessageArea(pos)
+  pos.y += 20
+  chatInput = gui.newTextEntry("...", pos, proc() =
+    sendPubChat dirServer, chatInput.getText()
+    chatInput.clearText())
+
+gui.setActive(chatInput)
+
+proc dispMessage(args: varargs[string, `$`]) =
+  var s = ""
+  for it in items(args):
+    s.add it
+  chatbox.add(s)
+proc dispMessage(text: string) {.inline.} =
+  chatbox.add(text)
+proc dispError(text: string) {.inline.} =
+  chatBox.add(newScChat(kind = CError, text = text))
+
+proc updateButtons() =
+  let conn = dirServer.connected
+  for b in connectionButtons: setEnabled(b, conn)
+  if conn:
+    connectButton.setString "Disconnect"
+  else:
+    connectButton.setString "Connect"
+
+proc poll(serv: PServer; timeout: cuint = 30) =
+  if serv.isNil or serv.host.isNil: return
+  if serv.connected:
+    while serv.host.hostService(event, timeout) > 0:
+      case event.kind
+      of EvtReceive:
+        var buf = newBuffer(event.packet)
+        
+        serv.handlePackets(buf)
+        
+        event.packet.destroy()
+      of EvtDisconnect:        
+        dispMessage "Disconnected"
+        serv.connected = false
+        event.peer.data = nil
+        updateButtons()
+      of EvtNone: discard
+      else:
+        echo repr(event)
+  else:
+    if serv.host.hostService(event, timeout) > 0 and event.kind == EvtConnect:
+      dispMessage "Connected"
+      serv.connected = true
+      if serv.peer != event.peer:
+        serv.peer = event.peer
+      event.peer.data = serv
+      updateButtons()
+
+proc tryLogin*(b: PButton) =
+  var login = newCsLogin(
+    alias = u_alias.getText(),
+    passwd = u_passwd.getText())
+  dirServer.send HLogin, login
+proc tryTransition*(b: PButton) =
+  discard
+  #zone.writePkt HZoneJoinReq, myCreds
+proc tryConnect*(b: PButton) =
+  if not dirServer.connected:
+    var error: string
+    if not dirServer.connect(
+            clientSettings.dirServer.host, 
+            clientSettings.dirServer.port, 
+            error):
+      dispError(error)
+  else:
+    dirServer.peer.disconnect(1)
+
+proc playOffline*(b: PButton) =
+  var errors: seq[string] = @[]
+  if loadSettingsFromFile(clientSettings.offlineFile, errors):
+    transition()
+  else:
+    dispMessage "Errors reading the file (", clientSettings.offlineFile, "):"
+    for e in errors: dispError(e)
+
+proc getClientSettings*(): TClientSettings =
+  result = clientSettings
+
+
+proc lobbyInit*() =
+  var s = json.parseFile("./client_settings.json")
+  clientSettings.offlineFile = "data/"
+  clientSettings.offlineFile.add s["default-file"].str
+  let dirserv = s["directory-server"]
+  clientSettings.dirserver.host = dirserv["host"].str
+  clientSettings.dirserver.port = dirserv["port"].num.int16
+  clientSettings.resolution.width = s["resolution"][0].num.cint
+  clientSettings.resolution.height= s["resolution"][1].num.cint
+  clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint
+  clientSettings.website = s["website"].str
+  zonelist.setPosition(vec2f(200.0, 100.0))
+  connectionButtons = @[]
+  
+  var pos = vec2f(10, 10)
+  u_alias = gui.newTextEntry(
+    if s.hasKey("alias"): s["alias"].str else: "alias", 
+    pos)
+  pos.y += 20
+  u_passwd = gui.newTextEntry("buzz", pos)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Login", 
+    position = pos,
+    onClick = tryLogin,
+    startEnabled = false))
+  pos.y += 20
+  fpsText.setPosition pos
+  pos.y += 20
+  connectButton = gui.newButton(
+    text = "Connect",
+    position = pos,
+    onClick = tryConnect)
+  pos.y += 20
+  gui.newButton("Test Files", position = pos, onClick = proc(b: PButton) =
+    var req = newCsZoneJoinReq(myCreds)
+    dirServer.send HZoneJoinReq, req)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Test Chat",
+    position = pos,
+    onClick = (proc(b: PButton) = 
+      var pkt = newCsChat(text = "ohai")
+      dirServer.send HChat, pkt),
+    startEnabled = false))
+  pos.y += 20
+  downloadProgress.setPosition(pos) 
+  downloadProgress.bg.setFillColor(color(34, 139, 34))
+  downloadProgress.bg.setSize(vec2f(0, 0))
+  gui.add(downloadProgress)
+  
+  playBtn = gui.newButton(
+    text = "Play",
+    position = vec2f(680.0, 8.0),
+    onClick = tryTransition,
+    startEnabled = false)
+  gui.newButton(
+    text = "Play Offline",
+    position = vec2f(680.0, 28.0),
+    onClick = playOffline)
+  discard """gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack += 1
+    update(messageArea))
+  gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = 
+    messageArea.scrollBack -= 1
+    update(messageArea))
+  gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) =
+    for i in 0.. <30: 
+      dispMessage($i))"""
+  dirServer = newServer() 
+  dirServer.addHandler HChat, handleChat
+  dirServer.addHandler HLogin, handlePlayerLogin
+  dirServer.addHandler HFileTransfer, client_helpers.handleFilePartRecv
+  dirServer.addHandler HChallengeResult, client_helpers.handleFileChallengeResult
+  dirServer.addHandler HFileChallenge, client_helpers.handleFileChallenge
+
+proc lobbyReady*() = 
+  kc.setActive()
+  gui.setActive(u_alias)
+
+var i = 0
+proc lobbyUpdate*(dt: float) =
+  dirServer.poll()
+  #let res = disp.poll()
+  gui.update(dt)
+  i = (i + 1) mod 60
+  if i == 0:
+    fpsText.setString("FPS: "& ff(1.0/dt))
+
+proc lobbyDraw*(window: PRenderWindow) =
+  window.clear(Black)
+  window.draw chatBox
+  window.draw gui
+  window.draw fpsText
+  if showZonelist: window.draw zonelist
+  window.display()
+
diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim
new file mode 100644
index 000000000..c2e893273
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim
@@ -0,0 +1,294 @@
+import enet, strutils, idgen, tables, math_helpers, 
+  estreams, sg_packets, server_utils, sg_assets, client_helpers
+when appType == "gui":
+  import sfml, sfml_colors, sg_gui,
+    input_helpers, sfml_stuff
+else:
+  import times
+type
+  TCallback = proc(client: PClient; buffer: PBuffer)
+var
+  server: PHost
+  dirServer: PServer
+  standAloneMode = true
+  event: enet.TEvent
+  clientID = newIDGen[int32]()
+  clients = initTable[int32, PClient](64)
+  handlers = initTable[char, TCallback](32) 
+
+when appType == "gui":
+  var
+    gui = newGuiContainer()
+    chatBox = gui.newMessageArea(vec2f(15, 550))
+    window = newRenderWindow(videoMode(800, 600, 32), "Sup yo", sfDefaultSTyle)
+    mousepos = newText("", guiFont, 16)
+    fpsText = mousePos.copy()
+    inputClient = newKeyClient(setActive = true)
+  chatBox.sizeVisible = 30
+  mousePos.setColor(Green)
+  fpsText.setposition(vec2f(0, 20))
+  inputClient.registerHandler MouseLeft, down, proc() =
+    gui.click(input_helpers.getMousePos())
+  inputClient.registerHandler MouseMiddle, down, proc() =
+    let pos = input_helpers.getMousePos()
+    mousePos.setString("($1,$2)".format(ff(pos.x), ff(pos.y)))
+    mousePos.setPosition(pos)
+  proc dispMessage(args: varargs[string, `$`]) =
+    var s = ""
+    for it in items(args):
+      s.add it
+    chatbox.add(s)
+  proc dispError(args: varargs[string, `$`]) =
+    var s = ""
+    for it in items(args): s.add(it)
+    chatBox.add(newScChat(kind = CError, text = s))
+else:
+  proc dispMessage(args: varargs[string, `$`]) =
+    var m = ""
+    for it in items(args): m.add(it)
+    echo "<msg> ", m
+  proc dispError(args: varargs[string, `$`]) =
+    var m = ""
+    for it in items(args): m.add(it)
+    echo "**", m
+
+
+var pubChatQueue = newBuffer(1024)
+proc queuePub(sender: PClient, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender.alias, text = msg.text)
+  pubChatQueue.write(HChat)
+  pubChatQueue.pack(chat)
+proc flushPubChat() =
+  if pubChatQueue.isDirty:
+    let packet = pubChatQueue.toPacket(FlagReliable)
+    for id, client in pairs(clients):
+      discard client.peer.send(0.cuchar, packet)
+    pubChatQueue.flush()
+
+handlers[HChat] = proc(client: PClient; buffer: PBuffer) =
+  var chat = readCsChat(buffer)
+  
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  #if chat.target != "": ##private
+  #  if alias2client.hasKey(chat.target):
+  #    alias2client[chat.target].forwardPrivate(client, chat.text)
+  #else:
+  
+  dispmessage("<", client.alias, "> ", chat.text)
+  queuePub(client, chat)
+
+handlers[HLogin] = proc(client: PClient; buffer: PBuffer) =
+  var info = readCsLogin(buffer)
+  if client.auth:
+    client.sendError "You are already logged in."
+    return
+  client.alias = info.alias
+  client.auth = true
+  var resp = newScLogin(client.id, client.alias, "sessionkeylulz")
+  client.send HLogin, resp
+  client.sendMessage "welcome"
+  dispMessage("Client logged in: ", client)
+
+
+handlers[HFileTransfer] = server_utils.handleFilePartAck
+handlers[HFileChallenge] = server_utils.handleFileChallengeResp
+
+handlers[HZoneJoinReq] = proc(client: PClient; buffer: PBuffer) =
+  var info = readCsZoneJoinReq(buffer)
+  dispmessage "Got zone join request"
+  client.startVerifyingFiles()
+
+
+
+when isMainModule:
+  import parseopt, matchers, os, json
+  
+  
+  if enetInit() != 0:
+    quit "Could not initialize ENet"
+  
+  var address: enet.TAddress
+  
+  block:
+    var zoneCfgFile = "./server_settings.json"
+    for kind, key, val in getOpt():
+      case kind
+      of cmdShortOption, cmdLongOption:
+        case key
+        of "f", "file": 
+          if existsFile(val):
+            zoneCfgFile = val
+          else:
+            echo("File does not exist: ", val)
+        else:
+          echo("Unknown option: ", key," ", val)
+      else:
+        echo("Unknown option: ", key, " ", val)
+    var jsonSettings = parseFile(zoneCfgFile)
+    let 
+      port = uint16(jsonSettings["port"].num)
+      zoneFile = jsonSettings["settings"].str
+      dirServerInfo = jsonSettings["dirserver"]
+    
+    address.host = EnetHostAny
+    address.port = port
+    
+    var path = getAppDir()/../"data"/zoneFile
+    if not existsFile(path):
+      echo("Zone settings file does not exist: ../data/", zoneFile)
+      echo(path)
+      quit(1)
+    
+    discard """block:
+      var 
+        TestFile: FileChallengePair
+        contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
+      testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
+      testFile.file = checksumStr(contents)
+      myAssets.add testFile"""
+    
+    setCurrentDir getAppDir().parentDir()
+    let zonesettings = readFile(path)
+    var 
+      errors: seq[string] = @[]
+    if not loadSettings(zoneSettings, errors):
+      echo("You have errors in your zone settings:")
+      for e in errors: echo("**", e)
+      quit(1)
+    errors.setLen 0
+    
+    var pair: FileChallengePair
+    pair.challenge.file = zoneFile
+    pair.challenge.assetType = FZoneCfg
+    pair.challenge.fullLen = zoneSettings.len.int32
+    pair.file = checksumStr(zoneSettings)
+    myAssets.add pair
+    
+    allAssets:
+      if not load(asset):
+        echo "Invalid or missing file ", file
+      else:
+        var pair: FileChallengePair
+        pair.challenge.file = file
+        pair.challenge.assetType = assetType
+        pair.challenge.fullLen = getFileSize(
+          expandPath(assetType, file)).int32
+        pair.file = asset.contents
+        myAssets.add pair
+    
+    echo "Zone has ", myAssets.len, " associated assets"
+    
+    dirServer = newServer()
+    
+    dirServer.addHandler HDsMsg, proc(serv: PServer; buffer: PBuffer) =
+      var m = readDsMsg(buffer)
+      dispMessage("<DirServer> ", m.msg)
+    dirServer.addHandler HZoneLogin, proc(serv: PServer; buffer: PBuffer) =
+      let loggedIn = readDsZoneLogin(buffer).status
+      if loggedIn:
+        #dirServerConnected = true
+    
+    if dirServerInfo.kind == JArray:
+      var error: string
+      if not dirServer.connect(dirServerInfo[0].str, dirServerInfo[1].num.int16, error):
+        dispError("<DirServer> "&error)
+    
+  
+  server = enet.createHost(address, 32, 2,  0,  0)
+  if server == nil:
+    quit "Could not create the server!"
+  
+  dispMessage("Listening on port ", address.port)
+  
+  var 
+    serverRunning = true
+  when appType == "gui":
+    var frameRate = newClock()
+    var pubChatDelay = newClock()
+  else:
+    var frameRate = epochTime()
+    var pubChatDelay = frameRate
+  
+  while serverRunning:
+    when appType == "gui":
+      let dt = frameRate.restart.asMilliseconds().float / 1000.0
+      
+      for event in window.filterEvents():
+        case event.kind
+        of sfml.EvtClosed:
+          window.close()
+          serverRunning = false
+        else:
+          discard
+    else:
+      let dt = epochTime() - frameRate ##is this right? probably not
+      frameRate = epochTime()
+    
+    while server.hostService(event, 10) > 0:
+      case event.kind
+      of EvtConnect:
+        var client = newClient()
+        clients[client.id] = client
+
+        event.peer.data = addr client.id
+        client.peer = event.peer
+        
+        dispMessage("New client connected ", client)
+        
+        var
+          msg = "hello" 
+          resp = createPacket(cstring(msg), msg.len + 1, FlagReliable)
+          
+        if event.peer.send(0.cuchar, resp) < 0:
+          echo "FAILED"
+        else:
+          echo "Replied"
+      of EvtReceive:
+        let client = clients[cast[ptr int32](event.peer.data)[]] 
+        
+        var buf = newBuffer(event.packet)
+        let k = buf.readChar()
+        if handlers.hasKey(k):
+          handlers[k](client, buf)
+        else:
+          dispError("Unknown packet from ", client)
+        
+        destroy(event.packet)
+      of EvtDisconnect:
+        var
+          id = cast[ptr int32](event.peer.data)[]
+          client = clients[id]
+        if client.isNil:
+          disperror("CLIENT IS NIL!")
+          dispmessage(event.peer.data.isNil)
+        else:
+          dispMessage(clients[id], " disconnected")
+          GCUnref(clients[id])
+          clients.del id
+        
+        event.peer.data = nil
+      else:
+        discard
+    
+    when appType == "gui":
+      fpsText.setString(ff(1.0/dt))
+      if pubChatDelay.getElapsedTime.asSeconds > 0.25:
+        pubChatDelay.restart()
+        flushPubChat()
+    else:
+      pubChatDelay -= dt
+      if frameRate - pubChatDelay > 0.25:
+        flushPubChat()
+    
+    when appType == "gui":
+      window.clear(Black)
+      window.draw(GUI)
+      window.draw chatbox
+      window.draw mousePos
+      window.draw fpstext
+      window.display()  
+
+  server.destroy()
+  enetDeinit()
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/enet_server/nakefile.nim b/tests/manyloc/keineschweine/enet_server/nakefile.nim
new file mode 100644
index 000000000..3764c6271
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/nakefile.nim
@@ -0,0 +1,13 @@
+import nake
+nakeimports
+
+const
+  ServerDefines = "-d:NoSFML --forceBuild"
+
+task "server", "build the server":
+  if shell("nim", ServerDefines, "-r", "compile", "enet_server") != 0:
+    quit "Failed to build"
+task "gui", "build the server GUI mode":
+  if shell("nim", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0:
+    quit "Failed to build"
+
diff --git a/tests/manyloc/keineschweine/enet_server/nim.cfg b/tests/manyloc/keineschweine/enet_server/nim.cfg
new file mode 100644
index 000000000..72ef47ee0
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/nim.cfg
@@ -0,0 +1,9 @@
+path = ".."
+path = "../dependencies/sfml"
+path = "../dependencies/enet"
+path = "../dependencies/nake"
+path = "../dependencies/genpacket"
+path = "../lib"
+define = "noChipmunk"
+define = "noSFML"
+
diff --git a/tests/manyloc/keineschweine/enet_server/server_settings.json b/tests/manyloc/keineschweine/enet_server/server_settings.json
new file mode 100644
index 000000000..7d2f1d822
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/server_settings.json
@@ -0,0 +1,8 @@
+{
+ "name": "Alpha Zone",
+ "desc": "Beta Testing",
+ "host": "localhost",
+ "port": 8024,
+ "settings": "alphazone.json",
+ "dirserver":["localhost",2049,"alphazone","skittles"]
+}
diff --git a/tests/manyloc/keineschweine/enet_server/server_utils.nim b/tests/manyloc/keineschweine/enet_server/server_utils.nim
new file mode 100644
index 000000000..8e8141075
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/server_utils.nim
@@ -0,0 +1,120 @@
+import enet, sg_packets, estreams, md5, zlib_helpers, client_helpers, strutils,
+  idgen, sg_assets, tables, os
+type
+  PClient* = ref object
+    id*: int32
+    auth*: bool
+    alias*: string
+    peer*: PPeer
+  
+  FileChallengePair* = tuple[challenge: ScFileChallenge; file: TChecksumFile]
+  PFileChallengeSequence* = ref TFileChallengeSequence 
+  TFileChallengeSequence = object
+    index: int  #which file is active
+    transfer: ScFileTransfer
+    file: ptr FileChallengePair
+var
+  clientID = newIdGen[int32]()
+  myAssets*: seq[FileChallengePair] = @[]
+  fileChallenges = initTable[int32, PFileChallengeSequence](32)
+const FileChunkSize = 256
+
+proc free(client: PClient) =
+  if client.id != 0:
+    fileChallenges.del client.id
+    clientID.del client.id
+proc newClient*(): PClient =
+  new(result, free)
+  result.id = clientID.next()
+  result.alias = "billy"
+
+proc `$`*(client: PClient): string =
+  result = "$1:$2".format(client.id, client.alias)
+
+proc send*[T](client: PClient; pktType: char; pkt: var T) =
+  var buf = newBuffer(128)
+  buf.write pktType
+  buf.pack pkt
+  discard client.peer.send(0.cuchar, buf, flagReliable)
+
+proc sendMessage*(client: PClient; txt: string) =
+  var m = newScChat(CSystem, text = txt)
+  client.send HChat, m
+proc sendError*(client: PClient; error: string) =
+  var m = newScChat(CError, text = error)
+  client.send HChat, m
+
+
+
+
+proc next*(challenge: PFileChallengeSequence, client: PClient)
+proc sendChunk*(challenge: PFileChallengeSequence, client: PClient)
+
+proc startVerifyingFiles*(client: PClient) =
+  var fcs: PFileChallengeSequence
+  new(fcs)
+  fcs.index = -1
+  fileChallenges[client.id] = fcs
+  next(fcs, client)
+
+proc next*(challenge: PFileChallengeSequence, client: PClient) =
+  inc(challenge.index)
+  if challenge.index >= myAssets.len:
+    client.sendMessage "You are cleared to enter"
+    fileChallenges.del client.id
+    return
+  else:
+    echo myAssets.len, "assets"
+  challenge.file = addr myAssets[challenge.index]
+  client.send HFileChallenge, challenge.file.challenge # :rolleyes:
+  echo "sent challenge"
+
+proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) =
+  let size = min(FileChunkSize, challenge.transfer.fileSize - challenge.transfer.pos)
+  challenge.transfer.data.setLen size
+  copyMem(
+    addr challenge.transfer.data[0], 
+    addr challenge.file.file.compressed[challenge.transfer.pos],
+    size)
+  client.send HFileTransfer, challenge.transfer
+  echo "chunk sent"
+
+proc startSend*(challenge: PFileChallengeSequence, client: PClient) =
+  challenge.transfer.fileSize = challenge.file.file.compressed.len().int32
+  challenge.transfer.pos = 0
+  challenge.transfer.data = ""
+  challenge.transfer.data.setLen FileChunkSize
+  challenge.sendChunk(client)
+  echo "starting xfer"
+
+## HFileTransfer
+proc handleFilePartAck*(client: PClient; buffer: PBuffer) =
+  echo "got filepartack"
+  var 
+    ftrans = readCsFilepartAck(buffer)
+    fcSeq = fileChallenges[client.id]
+  fcSeq.transfer.pos = ftrans.lastPos
+  fcSeq.sendChunk client
+
+## HFileCHallenge
+proc handleFileChallengeResp*(client: PClient; buffer: PBuffer) =
+  echo "got file challenge resp"
+  var 
+    fcResp = readCsFileChallenge(buffer)
+    fcSeq = fileChallenges[client.id]
+  let index = $(fcSeq.index + 1) / $(myAssets.len)
+  if fcResp.needFile:
+    client.sendMessage "Sending file... "&index
+    fcSeq.startSend(client)
+  else:
+    var resp = newScChallengeResult(false)
+    if fcResp.checksum == fcSeq.file.file.sum: ##client is good
+      client.sendMessage "Checksum is good. "&index
+      resp.status = true
+      client.send HChallengeResult, resp
+      fcSeq.next(client)
+    else:
+      client.sendMessage "Checksum is bad, sending file... "&index
+      client.send HChallengeResult, resp
+      fcSeq.startSend(client)
+
diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
new file mode 100644
index 000000000..525d8a054
--- /dev/null
+++ b/tests/manyloc/keineschweine/keineschweine.nim
@@ -0,0 +1,725 @@
+import 
+  os, math, strutils, gl, tables,
+  sfml, sfml_audio, sfml_colors, chipmunk, math_helpers,
+  input_helpers, animations, game_objects, sfml_stuff, map_filter,
+  sg_gui, sg_assets, sound_buffer, enet_client
+when defined(profiler):
+  import nimprof
+{.deadCodeElim: on.}
+type
+  PPlayer* = ref TPlayer
+  TPlayer* = object
+    id: uint16
+    vehicle: PVehicle
+    spectator: bool
+    alias: string
+    nameTag: PText
+    items: seq[PItem]
+  PVehicle* = ref TVehicle
+  TVehicle* = object
+    body*:      chipmunk.PBody
+    shape*:     chipmunk.PShape
+    record*:   PVehicleRecord
+    sprite*:   PSprite
+    spriteRect*: TIntRect
+    occupant: PPlayer
+    when false:
+      position*: TVector2f
+      velocity*: TVector2f
+      angle*:    float
+  PItem* = ref object
+    record: PItemRecord
+    cooldown: float 
+  PLiveBullet* = ref TLiveBullet ##represents a live bullet in the arena
+  TLiveBullet* = object
+    lifetime*: float
+    dead: bool
+    anim*: PAnimation
+    record*: PBulletRecord
+    fromPlayer*: PPlayer
+    trailDelay*: float
+    body: chipmunk.PBody
+    shape: chipmunk.PShape
+import vehicles
+const
+  LGrabbable*  = (1 shl 0).TLayers
+  LBorders*    = (1 shl 1).TLayers
+  LPlayer*     = ((1 shl 2) and LBorders.int).TLayers
+  LEnemy*      = ((1 shl 4) and LBorders.int).TLayers
+  LEnemyFire*  = (LPlayer).TLayers
+  LPlayerFire* = (LEnemy).TLayers
+  CTBullet = 1.TCollisionType
+  CTVehicle= 2.TCollisionType
+  ##temporary constants
+  W_LIMIT = 2.3
+  V_LIMIT = 35
+  MaxLocalBots = 3
+var
+  localPlayer: PPlayer
+  localBots: seq[PPlayer] = @[]
+  activeVehicle: PVehicle
+  myVehicles: seq[PVehicle] = @[]
+  objects: seq[PGameObject] = @[]
+  liveBullets: seq[PLiveBullet] = @[]
+  explosions: seq[PAnimation] = @[]
+  gameRunning = true
+  frameRate = newClock()
+  showStars = off
+  levelArea: TIntRect
+  videoMode: TVideoMode
+  window: PRenderWindow
+  worldView: PView
+  guiView: PView
+  space = newSpace()
+  ingameClient = newKeyClient("ingame")
+  specInputClient = newKeyClient("spec")
+  specGui = newGuiContainer()
+  stars: seq[PSpriteSheet] = @[]
+  playBtn: PButton
+  shipSelect = newGuiContainer()
+  delObjects: seq[int] = @[]
+  showShipSelect = false
+  myPosition: array[0..1, TVector3f] ##for audio positioning
+let 
+  nameTagOffset = vec2f(0.0, 1.0)
+when defined(escapeMenuTest):
+  import browsers
+  var
+    escMenu = newGuiContainer(vec2f(100, 100))
+    escMenuOpen = false
+    pos = vec2f(0, 0)
+  escMenu.newButton("Some Website", pos, proc(b: PButton) =
+    openDefaultBrowser(getClientSettings().website))
+  pos.y += 20.0
+  escMenu.newButton("Back to Lobby", pos, proc(b: PButton) =
+    echo "herro")
+  proc toggleEscape() =
+    escMenuOpen = not escMenuOpen
+  ingameClient.registerHandler(KeyEscape, down, toggleEscape)
+  specInputClient.registerHandler(KeyEscape, down, toggleEscape)
+when defined(foo):
+  var mouseSprite: sfml.PCircleShape
+when defined(recordMode):
+  var 
+    snapshots: seq[PImage] = @[]
+    isRecording = false
+  proc startRecording() = 
+    if snapshots.len > 100: return
+    echo "Started recording"
+    isRecording = true
+  proc stopRecording() =
+    if isRecording:
+      echo "Stopped recording. ", snapshots.len, " images."
+    isRecording = false
+  proc zeroPad*(s: string; minLen: int): string =
+    if s.len < minLen:
+      result = repeat(0, minLen - s.len)
+      result.add s
+    else:
+      result = s
+  var
+    recordButton = newButton(
+      nil, text = "Record", position = vec2f(680, 50),
+      onClick = proc(b: PButton) = startRecording())
+
+proc newNameTag*(text: string): PText =
+  result = newText()
+  result.setFont(guiFont)
+  result.setCharacterSize(14)
+  result.setColor(Red)
+  result.setString(text)
+
+var debugText = newNameTag("Loading...")
+debugText.setPosition(vec2f(0.0, 600.0 - 50.0))
+
+when defined(showFPS):
+  var fpsText = newNameTag("0")
+  #fpsText.setCharacterSize(16)
+  fpsText.setPosition(vec2f(300.0, (800 - 50).float))
+
+proc mouseToSpace*(): TVector =
+  result = window.convertCoords(vec2i(getMousePos()), worldView).sfml2cp()
+
+proc explode*(b: PLiveBullet)
+## TCollisionBeginFunc
+proc collisionBulletPlayer(arb: PArbiter; space: PSpace; 
+                            data: pointer): bool{.cdecl.} =
+  var 
+    bullet = cast[PLiveBullet](arb.a.data)
+    target = cast[PVehicle](arb.b.data)
+  if target.occupant.isNil or target.occupant == bullet.fromPlayer: return
+  bullet.explode()
+
+proc angularDampingSim(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
+  body.w -= (body.w * 0.98 * dt) 
+  body.UpdateVelocity(gravity, damping, dt)
+
+proc initLevel() =
+  loadAllAssets()
+  
+  if not space.isNil: space.destroy()
+  space = newSpace()
+  space.addCollisionHandler CTBullet, CTVehicle, collisionBulletPlayer,
+    nil, nil, nil, nil
+  
+  let levelSettings = getLevelSettings()
+  levelArea.width = levelSettings.size.x
+  levelArea.height= levelSettings.size.y
+  let borderSeq = @[
+    vector(0, 0), vector(levelArea.width.float, 0.0),
+    vector(levelArea.width.float, levelArea.height.float), vector(0.0, levelArea.height.float)]
+  for i in 0..3:
+    var seg = space.addShape(
+      newSegmentShape(
+        space.staticBody, 
+        borderSeq[i], 
+        borderSeq[(i + 1) mod 4],
+        8.0))
+    seg.setElasticity 0.96
+    seg.setLayers(LBorders)
+  if levelSettings.starfield.len > 0:
+    showStars = true
+    for sprite in levelSettings.starfield:
+      sprite.tex.setRepeated(true)
+      sprite.sprite.setTextureRect(levelArea)
+      sprite.sprite.setOrigin(vec2f(0, 0))
+      stars.add(sprite)
+  var pos = vec2f(0.0, 0.0)
+  for veh in playableVehicles():
+    shipSelect.newButton(
+      veh.name,
+      position = pos, 
+      onClick = proc(b: PButton) = 
+        echo "-__-")
+    pos.y += 18.0
+
+
+proc newItem*(record: PItemRecord): PItem =
+  new(result)
+  result.record = record
+proc newItem*(name: string): PItem {.inline.} =
+  return newItem(fetchItm(name))
+proc canUse*(itm: PItem): bool = 
+  if itm.cooldown > 0.0: return
+  return true
+proc update*(itm: PItem; dt: float) =
+  if itm.cooldown > 0:
+    itm.cooldown -= dt
+
+proc free(obj: PLiveBullet) =
+  obj.shape.free
+  obj.body.free
+  obj.record = nil
+
+
+template newExplosion(obj, animation): stmt =
+  explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, obj.body.getAngle))
+template newExplosion(obj, animation, angle): stmt =
+  explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, angle))
+
+proc explode*(b: PLiveBullet) =
+  if b.dead: return
+  b.dead = true
+  space.removeShape b.shape
+  space.removeBody b.body
+  if not b.record.explosion.anim.isNil:
+    newExplosion(b, b.record.explosion.anim)
+  playSound(b.record.explosion.sound, b.body.getPos())
+
+proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
+  body.UpdateVelocity(gravity, damping, dt)
+
+template getPhysical() {.immediate.} =
+  result.body = space.addBody(newBody(
+    record.physics.mass,
+    record.physics.moment))
+  result.shape = space.addShape(
+    chipmunk.newCircleShape(
+      result.body,
+      record.physics.radius,
+      VectorZero))
+
+proc newBullet*(record: PBulletRecord; fromPlayer: PPlayer): PLiveBullet =
+  new(result, free)
+  result.anim = newAnimation(record.anim, AnimLoop)
+  result.fromPlayer = fromPlayer
+  result.lifetime = record.lifetime
+  result.record = record
+  getPhysical()
+  if fromPlayer == localPlayer:
+    result.shape.setLayers(LPlayerFire)
+  else:
+    result.shape.setLayers(LEnemyFire)
+  result.shape.setCollisionType CTBullet
+  result.shape.setUserData(cast[ptr TLiveBullet](result))
+  let 
+    fireAngle = fromPlayer.vehicle.body.getAngle()
+    fireAngleV = vectorForAngle(fireAngle)
+  result.body.setAngle fireAngle
+  result.body.setPos(fromPlayer.vehicle.body.getPos() + (fireAngleV * fromPlayer.vehicle.shape.getCircleRadius()))
+  #result.body.velocityFunc = bulletUpdate
+  result.body.setVel((fromPlayer.vehicle.body.getVel() * record.inheritVelocity) + (fireAngleV * record.baseVelocity))
+
+proc update*(b: PLiveBullet; dt: float): bool =
+  if b.dead: return true
+  b.lifetime -= dt
+  b.anim.next(dt)
+  #b.anim.sprite.setPosition(b.body.getPos.floor())
+  b.anim.setPos(b.body.getPos)
+  b.anim.setAngle(b.body.getAngle())
+  if b.lifetime <= 0.0:
+    b.explode()
+    return true
+  b.trailDelay -= dt
+  if b.trailDelay <= 0.0:
+    b.trailDelay += b.record.trail.timer
+    if b.record.trail.anim.isNil: return
+    newExplosion(b, b.record.trail.anim)
+proc draw*(window: PRenderWindow; b: PLiveBullet) {.inline.} =
+  draw(window, b.anim.sprite)
+
+
+proc free*(veh: PVehicle) =
+  ("Destroying vehicle "& veh.record.name).echo
+  destroy(veh.sprite)
+  if veh.shape.isNil: "Free'd vehicle's shape was NIL!".echo
+  else: space.removeShape(veh.shape)
+  if veh.body.isNil: "Free'd vehicle's BODY was NIL!".echo
+  else: space.removeBody(veh.body)
+  veh.body.free()
+  veh.shape.free()
+  veh.sprite = nil
+  veh.body   = nil
+  veh.shape  = nil
+
+
+proc newVehicle*(record: PVehicleRecord): PVehicle =
+  echo("Creating "& record.name)
+  new(result, free)
+  result.record = record
+  result.sprite = result.record.anim.spriteSheet.sprite.copy()
+  result.spriteRect = result.sprite.getTextureRect()
+  getPhysical()
+  result.body.setAngVelLimit W_LIMIT
+  result.body.setVelLimit result.record.handling.topSpeed
+  result.body.velocityFunc = angularDampingSim
+  result.shape.setCollisionType CTVehicle
+  result.shape.setUserData(cast[ptr TVehicle](result))
+proc newVehicle*(name: string): PVehicle =
+  result = newVehicle(fetchVeh(name))
+
+proc update*(obj: PVehicle) =
+  obj.sprite.setPosition(obj.body.getPos.floor)
+  obj.spriteRect.left = (((-obj.body.getAngVel + W_LIMIT) / (W_LIMIT*2.0) * (obj.record.anim.spriteSheet.cols - 1).float).floor.int * obj.record.anim.spriteSheet.framew).cint
+  obj.spriteRect.top = ((obj.offsetAngle.wmod(TAU) / TAU) * obj.record.anim.spriteSheet.rows.float).floor.cint * obj.record.anim.spriteSheet.frameh.cint
+  obj.sprite.setTextureRect(obj.spriteRect)
+
+
+proc newPlayer*(alias: string = "poo"): PPlayer =
+  new(result)
+  result.spectator = true
+  result.alias     = alias
+  result.nameTag   = newNameTag(result.alias)
+  result.items     = @[]
+proc updateItems*(player: PPlayer, dt: float) =
+  for i in items(player.items):
+    update(i, dt)
+proc addItem*(player: PPlayer; name: string) =
+  player.items.add newItem(name)
+proc useItem*(player: PPlayer; slot: int) =
+  if slot > player.items.len - 1: return
+  let item = player.items[slot]
+  if item.canUse:
+    item.cooldown += item.record.cooldown
+    let b = newBullet(item.record.bullet, player)
+    liveBullets.add(b)
+    sound_buffer.playSound(item.record.useSound, b.body.getPos)
+
+proc update*(obj: PPlayer) =
+  if not obj.spectator:
+    obj.vehicle.update()
+    obj.nameTag.setPosition(obj.vehicle.body.getPos.floor + (nameTagOffset * (obj.vehicle.record.physics.radius + 5).cfloat))
+
+proc draw(window: PRenderWindow, player: PPlayer) {.inline.} =
+  if not player.spectator: 
+    if player.vehicle != nil:
+      window.draw(player.vehicle.sprite)
+    window.draw(player.nameTag)
+
+proc setVehicle(p: PPlayer; v: PVehicle) = 
+  p.vehicle = v  #sorry mom, this is just how things worked out ;(
+  if not v.isNil: 
+    v.occupant = p
+
+proc createBot() =
+  if localBots.len < MaxLocalBots:
+    var bot = newPlayer("Dodo Brown")
+    bot.setVehicle(newVehicle("Turret0"))
+    if bot.isNil:
+      echo "BOT IS NIL"
+      return
+    elif bot.vehicle.isNil:
+      echo "BOT VEH IS NIL"
+      return
+    localBots.add(bot)
+    bot.vehicle.body.setPos(vector(100, 100))
+    echo "new bot at ", $bot.vehicle.body.getPos()
+
+var inputCursor = newVertexArray(sfml.Lines, 2)
+inputCursor[0].position = vec2f(10.0, 10.0)
+inputCursor[1].position = vec2f(50.0, 90.0)
+
+proc hasVehicle(p: PPlayer): bool {.inline.} = 
+  result = not p.spectator and not p.vehicle.isNil
+
+proc setMyVehicle(v: PVehicle) {.inline.} =
+  activeVehicle = v
+  localPlayer.setVehicle v
+
+proc unspec() =
+  var veh = newVehicle("Turret0")
+  if not veh.isNil:
+    setMyVehicle veh
+    localPlayer.spectator = false
+    ingameClient.setActive
+    veh.body.setPos vector(100, 100)
+    veh.shape.setLayers(LPlayer)
+    when defined(debugWeps):
+      localPlayer.addItem("Mass Driver")
+      localPlayer.addItem("Neutron Bomb")
+      localPlayer.additem("Dem Lasers")
+      localPlayer.addItem("Mold Spore Beam")
+      localPlayer.addItem("Genericorp Mine")
+      localPlayer.addItem("Gravitic Bomb")
+proc spec() =
+  setMyVehicle nil
+  localPlayer.spectator = true
+  specInputClient.setActive
+
+var 
+  specLimiter = newClock()
+  timeBetweenSpeccing = 1.0 #seconds
+proc toggleSpec() {.inline.} =
+  if specLimiter.getElapsedTime.asSeconds < timeBetweenSpeccing:
+    return
+  specLimiter.restart()
+  if localPlayer.isNil: 
+    echo("OMG WTF PLAYER IS NILL!!")
+  elif localPlayer.spectator: unspec()
+  else: spec()
+
+proc addObject*(name: string) =
+  var o = newObject(name)
+  if not o.isNil: 
+    echo "Adding object ", o
+    discard space.addBody(o.body)
+    discard space.addShape(o.shape)
+    o.shape.setLayers(LGrabbable)
+    objects.add(o)
+proc explode(obj: PGameObject) = 
+  echo obj, " exploded"
+  let ind = objects.find(obj)
+  if ind != -1:
+    delObjects.add ind
+proc update(obj: PGameObject; dt: float) =
+  if not(obj.anim.next(dt)):
+    obj.explode()
+  else:
+    obj.anim.setPos(obj.body.getPos)
+    obj.anim.setAngle(obj.body.getAngle)
+
+proc toggleShipSelect() = 
+  showShipSelect = not showShipSelect
+proc handleLClick() =
+  let pos = input_helpers.getMousePos()
+  when defined(escapeMenuTest):
+    if escMenuOpen:
+      escMenu.click(pos)
+      return
+  if showShipSelect:
+    shipSelect.click(pos)
+  if localPlayer.spectator:
+    specGui.click(pos)
+
+ingameClient.registerHandler(KeyF12, down, proc() = toggleSpec())
+ingameClient.registerHandler(KeyF11, down, toggleShipSelect)
+ingameClient.registerHandler(MouseLeft, down, handleLClick)
+when defined(recordMode):
+  if not existsDir("data/snapshots"):
+    createDir("data/snapshots")
+  ingameClient.registerHandler(keynum9, down, proc() =
+    if not isRecording: startRecording()
+    else: stopRecording())
+  ingameClient.registerHandler(keynum0, down, proc() =
+    if snapshots.len > 0 and not isRecording:
+      echo "Saving images (LOL)"
+      for i in 0..high(snapshots):
+        if not(snapshots[i].save("data/snapshots/image"&(zeroPad($i, 3))&".jpg")):
+          echo "Could not save"
+        snapshots[i].destroy()
+      snapshots.setLen 0)
+when defined(DebugKeys):
+  ingameClient.registerHandler MouseRight, down, proc() = 
+    echo($activevehicle.body.getAngle.vectorForAngle())
+  ingameClient.registerHandler KeyBackslash, down, proc() = 
+    createBot()
+  ingameClient.registerHandler(KeyNum1, down, proc() =
+    if localPlayer.items.len == 0:
+      localPlayer.addItem("Mass Driver")
+      echo "Gave you a mass driverz")
+  ingameClient.registerHandler(KeyL, down, proc() =
+    echo("len(livebullets) = ", len(livebullets)))
+  ingameClient.registerHandler(KeyRShift, down, proc() =
+    if keyPressed(KeyR):
+      echo("Friction: ", ff(activeVehicle.shape.getFriction()))
+      echo("Damping: ", ff(space.getDamping()))
+    elif keypressed(KeyM):
+      echo("Mass: ", activeVehicle.body.getMass.ff())
+      echo("Moment: ", activeVehicle.body.getMoment.ff())
+    elif keypressed(KeyI):
+      echo(repr(activeVehicle.record))
+    elif keyPressed(KeyH):
+      activeVehicle.body.setPos(vector(100.0, 100.0))
+      activeVehicle.body.setVel(VectorZero)
+    elif keyPressed(KeyComma):
+      activeVehicle.body.setPos mouseToSpace())
+  ingameClient.registerHandler(KeyY, down, proc() =
+    const looloo = ["Asteroid1", "Asteroid2"]
+    addObject(looloo[random(looloo.len)]))
+  ingameClient.registerHandler(KeyO, down, proc() =
+    if objects.len == 0:
+      echo "Objects is empty"
+      return
+    for i, o in pairs(objects):
+      echo i, " ", o)
+  ingameClient.registerHandler(KeyLBracket, down, sound_buffer.report)
+  var 
+    mouseJoint: PConstraint
+    mouseBody = space.addBody(newBody(CpInfinity, CpInfinity))
+  ingameClient.registerHandler(MouseMiddle, down, proc() =
+    var point = mouseToSpace()
+    var shape = space.pointQueryFirst(point, LGrabbable, 0)
+    if not mouseJoint.isNil:
+      space.removeConstraint mouseJoint
+      mouseJoint.destroy()
+      mouseJoint = nil
+    if shape.isNil: 
+      return
+    let body = shape.getBody()
+    mouseJoint = space.addConstraint(
+      newPivotJoint(mouseBody, body, VectorZero, body.world2local(point)))
+    mouseJoint.maxForce = 50000.0
+    mouseJoint.errorBias = pow(1.0 - 0.15, 60))
+
+var specCameraSpeed = 5.0
+specInputClient.registerHandler(MouseLeft, down, handleLClick)
+specInputClient.registerHandler(KeyF11, down, toggleShipSelect)
+specInputClient.registerHandler(KeyF12, down, proc() = toggleSpec())
+specInputClient.registerHandler(KeyLShift, down, proc() = specCameraSpeed *= 2)
+specInputClient.registerHandler(KeyLShift, up, proc() = specCameraSpeed /= 2)
+
+specInputClient.registerHandler(KeyP, down, proc() =
+  echo("addObject(solar mold)")
+  addObject("Solar Mold"))
+
+proc resetForcesCB(body: PBody; data: pointer) {.cdecl.} =
+  body.resetForces()
+
+var frameCount= 0
+proc mainUpdate(dt: float) =
+  if localPlayer.spectator:
+    if keyPressed(KeyLeft):
+      worldView.move(vec2f(-1.0, 0.0) * specCameraSpeed)
+    elif keyPressed(KeyRight):
+      worldView.move(vec2f( 1.0, 0.0) * specCameraSpeed)
+    if keyPressed(KeyUp):
+      worldView.move(vec2f(0.0, -1.0) * specCameraSpeed)
+    elif keyPressed(KeyDown):
+      worldView.move(vec2f(0.0,  1.0) * specCameraSpeed)
+  elif not activeVehicle.isNil:
+    if keyPressed(KeyUp):
+      activeVehicle.accel(dt)
+    elif keyPressed(KeyDown):
+      activeVehicle.reverse(dt)
+    if keyPressed(KeyRight):
+      activeVehicle.turn_right(dt)
+    elif keyPressed(KeyLeft):
+      activeVehicle.turn_left(dt)
+    if keyPressed(Keyz):
+      activeVehicle.strafe_left(dt)
+    elif keyPressed(Keyx):
+      activeVehicle.strafe_right(dt)
+    if keyPressed(KeyLControl):
+      localPlayer.useItem 0
+    if keyPressed(KeyTab):
+      localPlayer.useItem 1
+    if keyPressed(KeyQ):
+      localPlayer.useItem 2
+    if keyPressed(KeyW):
+      localPlayer.useItem 3
+    if keyPressed(KeyA):
+      localPlayer.useItem 4
+    if keyPressed(sfml.KeyS):
+      localPlayer.useItem 5
+    if keyPressed(KeyD):
+      localPlayer.useItem 6
+    worldView.setCenter(activeVehicle.body.getPos.floor)#cp2sfml)
+  
+  if localPlayer != nil: 
+    localPlayer.update()
+    localPlayer.updateItems(dt)
+  for b in localBots:
+    b.update()
+  
+  for o in items(objects):
+    o.update(dt)
+  for i in countdown(high(delObjects), 0):
+    objects.del i
+  delObjects.setLen 0
+  
+  var i = 0
+  while i < len(liveBullets):
+    if liveBullets[i].update(dt):
+      liveBullets.del i
+    else: 
+      inc i
+  i = 0
+  while i < len(explosions):
+    if explosions[i].next(dt): inc i
+    else: explosions.del i
+  
+  when defined(DebugKeys):
+    mouseBody.setPos(mouseToSpace())
+  
+  space.step(dt)
+  space.eachBody(resetForcesCB, nil)
+  
+  when defined(foo):
+    var coords = window.convertCoords(vec2i(getMousePos()), worldView)
+    mouseSprite.setPosition(coords)
+  
+  if localPlayer != nil and localPlayer.vehicle != nil:
+    let 
+      pos = localPlayer.vehicle.body.getPos()
+      ang = localPlayer.vehicle.body.getAngle.vectorForAngle()
+    myPosition[0].x = pos.x
+    myPosition[0].z = pos.y
+    myPosition[1].x = ang.x
+    myPosition[1].z = ang.y
+    listenerSetPosition(myPosition[0])
+    listenerSetDirection(myPosition[1])
+  
+  inc frameCount
+  when defined(showFPS):
+    if frameCount mod 60 == 0:
+      fpsText.setString($(1.0/dt).round)
+  if frameCount mod 250 == 0:
+    updateSoundBuffer()
+    frameCount = 0
+
+proc mainRender() =
+  window.clear(Black)
+  window.setView(worldView)
+  
+  if showStars:
+    for star in stars:
+      window.draw(star.sprite)
+  window.draw(localPlayer)
+  
+  for b in localBots:
+    window.draw(b)
+  for o in objects:
+    window.draw(o)
+  
+  for b in explosions: window.draw(b)
+  for b in liveBullets: window.draw(b)
+  
+  when defined(Foo):
+    window.draw(mouseSprite)
+  
+  window.setView(guiView)
+  
+  when defined(EscapeMenuTest):
+    if escMenuOpen:
+      window.draw escMenu
+  when defined(showFPS):
+    window.draw(fpsText)
+  when defined(recordMode):
+    window.draw(recordButton)
+  
+  if localPlayer.spectator:
+    window.draw(specGui)
+  if showShipSelect: window.draw shipSelect
+  window.display()
+  
+  when defined(recordMode):
+    if isRecording:
+      if snapshots.len < 100:
+        if frameCount mod 5 == 0:
+          snapshots.add(window.capture())
+      else: stopRecording()
+
+proc readyMainState() =
+  specInputClient.setActive()
+
+when isMainModule:
+  import parseopt
+  
+  localPlayer = newPlayer()
+  lobbyInit()
+  
+  videoMode = getClientSettings().resolution
+  window = newRenderWindow(videoMode, "sup", sfDefaultStyle)
+  window.setFrameRateLimit 60
+  
+  worldView = window.getView.copy()
+  guiView = worldView.copy()
+  shipSelect.setPosition vec2f(665.0, 50.0)
+  
+  when defined(foo):
+    mouseSprite = sfml.newCircleShape(14)
+    mouseSprite.setFillColor Transparent
+    mouseSprite.setOutlineColor RoyalBlue
+    mouseSprite.setOutlineThickness 1.4
+    mouseSprite.setOrigin vec2f(14, 14)
+  
+  lobbyReady()
+  playBtn = specGui.newButton(
+    "Unspec - F12", position = vec2f(680.0, 8.0), onClick = proc(b: PButton) =
+      toggleSpec())
+  
+  block:
+    var bPlayOffline = false
+    for kind, key, val in getOpt():
+      case kind
+      of cmdArgument:
+        if key == "offline": bPlayOffline = true
+      else:
+        echo "Invalid argument ", key, " ", val
+    if bPlayOffline:
+      playoffline(nil)
+  
+  gameRunning = true
+  while gameRunning:
+    for event in window.filterEvents:
+      if event.kind == EvtClosed:
+        gameRunning = false
+        break
+      elif event.kind == EvtMouseWheelMoved and getActiveState() == Field:
+        if event.mouseWheel.delta == 1:
+          worldView.zoom(0.9)
+        else:
+          worldView.zoom(1.1)
+    let dt = frameRate.restart.asMilliSeconds().float / 1000.0
+    case getActiveState()
+    of Field:
+      mainUpdate(dt)
+      mainRender()
+    of Lobby:
+      lobbyUpdate(dt)
+      lobbyDraw(window)
+    else:
+      initLevel()
+      echo("Done? lol")
+      doneWithSaidTransition()
+      readyMainState()
diff --git a/tests/manyloc/keineschweine/keineschweine.nim.cfg b/tests/manyloc/keineschweine/keineschweine.nim.cfg
new file mode 100644
index 000000000..ca6c75f6e
--- /dev/null
+++ b/tests/manyloc/keineschweine/keineschweine.nim.cfg
@@ -0,0 +1,9 @@
+path = "lib"
+path = "dependencies/sfml"
+path = "dependencies/chipmunk"
+path = "dependencies/nake"
+path = "dependencies/enet"
+path = "dependencies/genpacket"
+path = "enet_server"
+debugger = off
+warning[SmallLshouldNotBeUsed] = off
diff --git a/tests/manyloc/keineschweine/lib/animations.nim b/tests/manyloc/keineschweine/lib/animations.nim
new file mode 100644
index 000000000..a021005f0
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/animations.nim
@@ -0,0 +1,75 @@
+import
+  math,
+  sfml, chipmunk,
+  sg_assets, sfml_stuff, math_helpers
+type
+  PAnimation* = ref TAnimation
+  TAnimation* = object
+    sprite*: PSprite
+    record*: PAnimationRecord
+    delay*: float
+    index*: int
+    direction*: int
+    spriteRect*: TIntRect
+    style*: TAnimationStyle
+  TAnimationStyle* = enum
+    AnimLoop = 0'i8, AnimBounce, AnimOnce
+
+proc setPos*(obj: PAnimation; pos: TVector) {.inline.}
+proc setPos*(obj: PAnimation; pos: TVector2f) {.inline.}
+proc setAngle*(obj: PAnimation; radians: float) {.inline.}
+
+proc free*(obj: PAnimation) =
+  obj.sprite.destroy()
+  obj.record = nil
+
+proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle): PAnimation =
+  new(result, free)
+  result.sprite = src.spriteSheet.sprite.copy()
+  result.record = src
+  result.delay = src.delay
+  result.index = 0
+  result.direction = 1
+  result.spriteRect = result.sprite.getTextureRect()
+  result.style = style
+proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle;
+                    pos: TVector2f; angle: float): PAnimation =
+  result = newAnimation(src, style)
+  result.setPos pos
+  setAngle(result, angle)
+
+proc next*(obj: PAnimation; dt: float): bool {.discardable.} =
+  ## step the animation. Returns false if the object is out of frames
+  result = true
+  obj.delay -= dt
+  if obj.delay <= 0.0:
+    obj.delay += obj.record.delay
+    obj.index += obj.direction
+    #if obj.index > (obj.record.spriteSheet.cols - 1) or obj.index < 0:
+    if not(obj.index in 0..(obj.record.spriteSheet.cols - 1)):
+      case obj.style
+      of AnimOnce:
+        return false
+      of AnimBounce:
+        obj.direction *= -1
+        obj.index += obj.direction * 2
+      of AnimLoop:
+        obj.index = 0
+    obj.spriteRect.left = obj.index.cint * obj.record.spriteSheet.frameW.cint
+    obj.sprite.setTextureRect obj.spriteRect
+
+proc setPos*(obj: PAnimation; pos: TVector) =
+  setPosition(obj.sprite, pos.floor())
+proc setPos*(obj: PAnimation; pos: TVector2f) =
+  setPosition(obj.sprite, pos)
+proc setAngle*(obj: PAnimation; radians: float)  =
+  let rads = (radians + obj.record.angle).wmod(TAU)
+  if obj.record.spriteSheet.rows > 1:
+    ## (rotation percent * rows).floor * frameheight
+    obj.spriteRect.top = (rads / TAU * obj.record.spriteSheet.rows.float).floor.cint * obj.record.spriteSheet.frameh.cint
+    obj.sprite.setTextureRect obj.spriteRect
+  else:
+    setRotation(obj.sprite, degrees(rads)) #stupid sfml, who uses degrees these days? -__-
+
+proc draw*(window: PRenderWindow; obj: PAnimation) {.inline.} =
+  window.draw(obj.sprite)
diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim
new file mode 100644
index 000000000..84e42b62e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/client_helpers.nim
@@ -0,0 +1,142 @@
+import  
+  tables, sg_packets, enet, estreams, sg_gui, sfml,
+  zlib_helpers, md5, sg_assets, os
+type
+  PServer* = ptr TServer
+  TServer* = object
+    connected*: bool
+    addy: enet.TAddress
+    host*: PHost
+    peer*: PPeer
+    handlers*: TTable[char, TScPktHandler]
+  TScPktHandler* = proc(serv: PServer; buffer: PBuffer)
+  TFileTransfer = object
+    fileName: string
+    assetType: TAssetType
+    fullLen: int
+    pos: int32
+    data: string
+    readyToSave: bool
+var 
+  currentFileTransfer: TFileTransfer
+  downloadProgress* = newButton(nil, "", vec2f(0,0), nil)
+currentFileTransfer.data = ""
+
+proc addHandler*(serv: PServer; packetType: char; handler: TScPktHandler) =
+  serv.handlers[packetType] = handler
+
+proc newServer*(): PServer =
+  result = cast[PServer](alloc0(sizeof(TServer)))
+  result.connected = false
+  result.host = createHost(nil, 1, 2, 0, 0)
+  result.handlers = initTable[char, TScPktHandler](32)
+
+proc connect*(serv: PServer; host: string; port: int16; error: var string): bool =
+  if setHost(serv.addy, host) != 0:
+    error = "Could not resolve host "
+    error.add host
+    return false
+  serv.addy.port = port.cushort
+  serv.peer = serv.host.connect(serv.addy, 2, 0)
+  if serv.peer.isNil:
+    error = "Could not connect to host "
+    error.add host
+    return false
+  return true
+
+proc send*[T](serv: PServer; packetType: char; pkt: var T) =
+  if serv.connected:
+    var b = newBuffer(100)
+    b.write packetType
+    b.pack pkt
+    serv.peer.send(0.cuchar, b, FlagUnsequenced)
+
+proc sendPubChat*(server: PServer; msg: string) =
+  var chat = newCsChat("", msg)
+  server.send HChat, chat
+
+proc handlePackets*(server: PServer; buf: PBuffer) =
+  while not buf.atEnd():
+    let typ = readChar(buf)
+    if server.handlers.hasKey(typ):
+      server.handlers[typ](server, buf)
+    else:
+      break
+
+proc updateFileProgress*() =
+  let progress = currentFileTransfer.pos / currentFileTransfer.fullLen
+  downloadProgress.bg.setSize(vec2f(progress * 100, 20))
+  downloadProgress.setString($currentFileTransfer.pos &'/'& $currentFileTransfer.fullLen)
+
+## HFileTransfer
+proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) {.procvar.} =
+  var
+    f = readScFileTransfer(buffer)
+  updateFileProgress()
+  if not(f.pos == currentFileTransfer.pos): 
+    echo "returning early from filepartrecv"
+    return ##issues, probably
+  if currentFileTransfer.data.len == 0:
+    echo "setting current file size"
+    currentFileTransfer.data.setLen f.fileSize
+  let len = f.data.len
+  copymem(
+    addr currentFileTransfer.data[f.pos],
+    addr f.data[0],
+    len)
+  currentFileTransfer.pos = f.pos + len.int32
+  if currentFileTransfer.pos == f.fileSize: #file should be done, rizzight
+    currentFileTransfer.data = uncompress(
+      currentFileTransfer.data, currentFileTransfer.fullLen)
+    currentFileTransfer.readyToSave = true
+    var resp: CsFileChallenge
+    resp.checksum = toMD5(currentFileTransfer.data)
+    serv.send HFileChallenge, resp
+    echo "responded with challenge (ready to save)"
+  else:
+    var resp = newCsFilepartAck(currentFileTransfer.pos)
+    serv.send HFileTransfer, resp
+    echo "responded for next part"
+
+proc saveCurrentFile() =
+  if not currentFileTransfer.readyToSave: return
+  let 
+    path = expandPath(currentFileTransfer.assetType, currentFileTransfer.fileName)
+    parent = parentDir(path)
+  if not existsDir(parent):
+    createDir(parent)
+    echo("Created dir")
+  writeFile path, currentFIleTransfer.data
+  echo "Write file"
+
+## HChallengeResult
+proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) {.procvar.} =
+  var res = readScChallengeResult(buffer).status
+  echo "got challnege result: ", res
+  if res and currentFileTransfer.readyToSave:
+    echo "saving"
+    saveCurrentFile()
+  else:
+    currentFileTransfer.readyToSave = false
+    currentFileTransfer.pos = 0
+    echo "REsetting current file"
+
+## HFileCHallenge
+proc handleFileChallenge*(serv: PServer; buffer: PBuffer) {.procvar.} =
+  var 
+    challenge = readScFileChallenge(buffer)
+    path = expandPath(challenge)
+    resp: CsFileChallenge
+  if not existsFile(path):
+    resp.needFile = true
+    echo "Got file challenge, need file."
+  else:
+    resp.checksum = toMD5(readFile(path))
+    echo "got file challenge, sending sum"
+  currentFileTransfer.fileName = challenge.file
+  currentFileTransfer.assetType = challenge.assetType
+  currentFileTransfer.fullLen = challenge.fullLen.int
+  currentFileTransfer.pos = 0
+  currentFileTransfer.data.setLen 0
+  currentFileTransfer.readyToSave = false
+  serv.send HFileChallenge, resp
diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim
new file mode 100644
index 000000000..ecafaed89
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/estreams.nim
@@ -0,0 +1,122 @@
+import endians
+
+proc swapEndian16*(outp, inp: pointer) = 
+  ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
+  ## contain at least 2 bytes.
+  var i = cast[cstring](inp)
+  var o = cast[cstring](outp)
+  o[0] = i[1]
+  o[1] = i[0]
+
+import enet
+
+type
+  PBuffer* = ref object
+    data*: string
+    pos: int
+
+proc free(b: PBuffer) =
+  GCunref b.data
+proc newBuffer*(len: int): PBuffer =
+  new result, free
+  result.data = newString(len)
+proc newBuffer*(pkt: PPacket): PBuffer =
+  new result, free
+  result.data = newString(pkt.dataLength)
+  copyMem(addr result.data[0], pkt.data, pkt.dataLength)
+proc toPacket*(buffer: PBuffer; flags: TPacketFlag): PPacket =
+  buffer.data.setLen buffer.pos
+  result = createPacket(cstring(buffer.data), buffer.pos, flags)
+
+proc isDirty*(buffer: PBuffer): bool {.inline.} =
+  result = (buffer.pos != 0)
+proc atEnd*(buffer: PBuffer): bool {.inline.} =
+  result = (buffer.pos == buffer.data.len)
+proc reset*(buffer: PBuffer) {.inline.} =
+  buffer.pos = 0
+
+proc flush*(buf: PBuffer) =
+  buf.pos = 0
+  buf.data.setLen(0)
+proc send*(peer: PPeer; channel: cuchar; buf: PBuffer; flags: TPacketFlag): cint {.discardable.} =
+  result = send(peer, channel, buf.toPacket(flags))
+
+proc read*[T: int16|uint16](buffer: PBuffer; outp: var T) =
+  bigEndian16(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 2
+proc read*[T: float32|int32|uint32](buffer: PBuffer; outp: var T) =
+  bigEndian32(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 4
+proc read*[T: float64|int64|uint64](buffer: PBuffer; outp: var T) =
+  bigEndian64(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 8
+proc read*[T: int8|uint8|byte|bool|char](buffer: PBuffer; outp: var T) =
+  copyMem(addr outp, addr buffer.data[buffer.pos], 1)
+  inc buffer.pos, 1
+
+proc writeBE*[T: int16|uint16](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 2
+  bigEndian16(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 2
+proc writeBE*[T: int32|uint32|float32](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 4
+  bigEndian32(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 4
+proc writeBE*[T: int64|uint64|float64](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 8
+  bigEndian64(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 8
+proc writeBE*[T: char|int8|uint8|byte|bool](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 1
+  copyMem(addr buffer.data[buffer.pos], addr val, 1)
+  inc buffer.pos, 1
+
+
+proc write*(buffer: PBuffer; val: var string) =
+  var length = len(val).uint16
+  writeBE buffer, length
+  setLen buffer.data, buffer.pos + length.int
+  copyMem(addr buffer.data[buffer.pos], addr val[0], length.int)
+  inc buffer.pos, length.int
+proc write*[T: TNumber|bool|char|byte](buffer: PBuffer; val: T) =
+  var v: T
+  shallowCopy v, val
+  writeBE buffer, v
+
+proc readInt8*(buffer: PBuffer): int8 =
+  read buffer, result
+proc readInt16*(buffer: PBuffer): int16 =
+  read buffer, result
+proc readInt32*(buffer: PBuffer): int32 =
+  read buffer, result
+proc readInt64*(buffer: PBuffer): int64 =
+  read buffer, result
+proc readFloat32*(buffer: PBuffer): float32 =
+  read buffer, result
+proc readFloat64*(buffer: PBuffer): float64 =
+  read buffer, result
+proc readStr*(buffer: PBuffer): string =
+  let len = readInt16(buffer).int
+  result = ""
+  if len > 0:
+    result.setLen len
+    copyMem(addr result[0], addr buffer.data[buffer.pos], len)
+    inc buffer.pos, len
+proc readChar*(buffer: PBuffer): char {.inline.} = return readInt8(buffer).char
+proc readBool*(buffer: PBuffer): bool {.inline.} = return readInt8(buffer).bool
+
+
+when isMainModule:
+  var b = newBuffer(100)
+  var str = "hello there"
+  b.write str
+  echo(repr(b))
+  b.pos = 0
+  echo(repr(b.readStr()))
+  
+  b.flush()
+  echo "flushed"
+  b.writeC([1,2,3])
+  echo(repr(b))
+  
+  
diff --git a/tests/manyloc/keineschweine/lib/game_objects.nim b/tests/manyloc/keineschweine/lib/game_objects.nim
new file mode 100644
index 000000000..277ffb6cb
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/game_objects.nim
@@ -0,0 +1,34 @@
+import chipmunk, sfml, animations, sg_assets
+type
+  PGameObject* = ref TGameObject
+  TGameObject = object
+    body*: chipmunk.PBody
+    shape*: chipmunk.PShape
+    record*: PObjectRecord
+    anim*: PAnimation
+
+
+proc `$`*(obj: PGameObject): string =
+  result = "<Object "
+  result.add obj.record.name
+  result.add ' '
+  result.add($obj.body.getpos())
+  result.add '>'
+proc free(obj: PGameObject) =
+  obj.record = nil
+  free(obj.anim)
+  obj.anim = nil
+proc newObject*(record: PObjectRecord): PGameObject =
+  if record.isNil: return nil
+  new(result, free)
+  result.record = record
+  result.anim = newAnimation(record.anim, AnimLoop)
+  when false:
+    result.sprite = record.anim.spriteSheet.sprite.copy()
+  result.body = newBody(result.record.physics.mass, 10.0)
+  result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, VectorZero)
+  result.body.setPos(vector(100, 100))
+proc newObject*(name: string): PGameObject =
+  result = newObject(fetchObj(name))
+proc draw*(window: PRenderWindow, obj: PGameObject) {.inline.} =
+  window.draw(obj.anim.sprite)
diff --git a/tests/manyloc/keineschweine/lib/gl.nim b/tests/manyloc/keineschweine/lib/gl.nim
new file mode 100644
index 000000000..c577f3404
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/gl.nim
@@ -0,0 +1,1536 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#
+#******************************************************************************
+# Converted to Delphi by Tom Nuydens (tom@delphi3d.net)                        
+# For the latest updates, visit Delphi3D: http://www.delphi3d.net              
+#******************************************************************************
+
+when defined(windows): 
+  {.push, callconv: stdcall.}
+else: 
+  {.push, callconv: cdecl.}
+when defined(windows): 
+  const 
+    dllname* = "opengl32.dll"
+elif defined(macosx): 
+  const 
+    dllname* = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
+else: 
+  const 
+    dllname* = "libGL.so.1"
+type 
+  PGLenum* = ptr TGLenum
+  PGLboolean* = ptr TGLboolean
+  PGLbitfield* = ptr TGLbitfield
+  TGLbyte* = int8
+  PGLbyte* = ptr TGlbyte
+  PGLshort* = ptr TGLshort
+  PGLint* = ptr TGLint
+  PGLsizei* = ptr TGLsizei
+  PGLubyte* = ptr TGLubyte
+  PGLushort* = ptr TGLushort
+  PGLuint* = ptr TGLuint
+  PGLfloat* = ptr TGLfloat
+  PGLclampf* = ptr TGLclampf
+  PGLdouble* = ptr TGLdouble
+  PGLclampd* = ptr TGLclampd
+  PGLvoid* = pointer
+  PPGLvoid* = ptr PGLvoid
+  TGLenum* = cint
+  TGLboolean* = bool
+  TGLbitfield* = cint
+  TGLshort* = int16
+  TGLint* = cint
+  TGLsizei* = int
+  TGLubyte* = int8
+  TGLushort* = int16
+  TGLuint* = cint
+  TGLfloat* = float32
+  TGLclampf* = float32
+  TGLdouble* = float
+  TGLclampd* = float
+
+const                         # Version
+  GL_VERSION_1_1* = 1         # AccumOp
+  constGL_ACCUM* = 0x00000100
+  GL_LOAD* = 0x00000101
+  GL_RETURN* = 0x00000102
+  GL_MULT* = 0x00000103
+  GL_ADD* = 0x00000104        # AlphaFunction
+  GL_NEVER* = 0x00000200
+  GL_LESS* = 0x00000201
+  GL_EQUAL* = 0x00000202
+  GL_LEQUAL* = 0x00000203
+  GL_GREATER* = 0x00000204
+  GL_NOTEQUAL* = 0x00000205
+  GL_GEQUAL* = 0x00000206
+  GL_ALWAYS* = 0x00000207     # AttribMask
+  GL_CURRENT_BIT* = 0x00000001
+  GL_POINT_BIT* = 0x00000002
+  GL_LINE_BIT* = 0x00000004
+  GL_POLYGON_BIT* = 0x00000008
+  GL_POLYGON_STIPPLE_BIT* = 0x00000010
+  GL_PIXEL_MODE_BIT* = 0x00000020
+  GL_LIGHTING_BIT* = 0x00000040
+  GL_FOG_BIT* = 0x00000080
+  GL_DEPTH_BUFFER_BIT* = 0x00000100
+  GL_ACCUM_BUFFER_BIT* = 0x00000200
+  GL_STENCIL_BUFFER_BIT* = 0x00000400
+  GL_VIEWPORT_BIT* = 0x00000800
+  GL_TRANSFORM_BIT* = 0x00001000
+  GL_ENABLE_BIT* = 0x00002000
+  GL_COLOR_BUFFER_BIT* = 0x00004000
+  GL_HINT_BIT* = 0x00008000
+  GL_EVAL_BIT* = 0x00010000
+  GL_LIST_BIT* = 0x00020000
+  GL_TEXTURE_BIT* = 0x00040000
+  GL_SCISSOR_BIT* = 0x00080000
+  GL_ALL_ATTRIB_BITS* = 0x000FFFFF # BeginMode
+  GL_POINTS* = 0x00000000
+  GL_LINES* = 0x00000001
+  GL_LINE_LOOP* = 0x00000002
+  GL_LINE_STRIP* = 0x00000003
+  GL_TRIANGLES* = 0x00000004
+  GL_TRIANGLE_STRIP* = 0x00000005
+  GL_TRIANGLE_FAN* = 0x00000006
+  GL_QUADS* = 0x00000007
+  GL_QUAD_STRIP* = 0x00000008
+  GL_POLYGON* = 0x00000009    # BlendingFactorDest
+  GL_ZERO* = 0
+  GL_ONE* = 1
+  GL_SRC_COLOR* = 0x00000300
+  GL_ONE_MINUS_SRC_COLOR* = 0x00000301
+  GL_SRC_ALPHA* = 0x00000302
+  GL_ONE_MINUS_SRC_ALPHA* = 0x00000303
+  GL_DST_ALPHA* = 0x00000304
+  GL_ONE_MINUS_DST_ALPHA* = 0x00000305 # BlendingFactorSrc
+                                       #      GL_ZERO
+                                       #      GL_ONE
+  GL_DST_COLOR* = 0x00000306
+  GL_ONE_MINUS_DST_COLOR* = 0x00000307
+  GL_SRC_ALPHA_SATURATE* = 0x00000308 #      GL_SRC_ALPHA
+                                      #      GL_ONE_MINUS_SRC_ALPHA
+                                      #      GL_DST_ALPHA
+                                      #      GL_ONE_MINUS_DST_ALPHA
+                                      # Boolean
+  GL_TRUE* = 1
+  GL_FALSE* = 0               # ClearBufferMask
+                              #      GL_COLOR_BUFFER_BIT
+                              #      GL_ACCUM_BUFFER_BIT
+                              #      GL_STENCIL_BUFFER_BIT
+                              #      GL_DEPTH_BUFFER_BIT
+                              # ClientArrayType
+                              #      GL_VERTEX_ARRAY
+                              #      GL_NORMAL_ARRAY
+                              #      GL_COLOR_ARRAY
+                              #      GL_INDEX_ARRAY
+                              #      GL_TEXTURE_COORD_ARRAY
+                              #      GL_EDGE_FLAG_ARRAY
+                              # ClipPlaneName
+  GL_CLIP_PLANE0* = 0x00003000
+  GL_CLIP_PLANE1* = 0x00003001
+  GL_CLIP_PLANE2* = 0x00003002
+  GL_CLIP_PLANE3* = 0x00003003
+  GL_CLIP_PLANE4* = 0x00003004
+  GL_CLIP_PLANE5* = 0x00003005 # ColorMaterialFace
+                               #      GL_FRONT
+                               #      GL_BACK
+                               #      GL_FRONT_AND_BACK
+                               # ColorMaterialParameter
+                               #      GL_AMBIENT
+                               #      GL_DIFFUSE
+                               #      GL_SPECULAR
+                               #      GL_EMISSION
+                               #      GL_AMBIENT_AND_DIFFUSE
+                               # ColorPointerType
+                               #      GL_BYTE
+                               #      GL_UNSIGNED_BYTE
+                               #      GL_SHORT
+                               #      GL_UNSIGNED_SHORT
+                               #      GL_INT
+                               #      GL_UNSIGNED_INT
+                               #      GL_FLOAT
+                               #      GL_DOUBLE
+                               # CullFaceMode
+                               #      GL_FRONT
+                               #      GL_BACK
+                               #      GL_FRONT_AND_BACK
+                               # DataType
+  GL_BYTE* = 0x00001400
+  GL_UNSIGNED_BYTE* = 0x00001401
+  GL_SHORT* = 0x00001402
+  GL_UNSIGNED_SHORT* = 0x00001403
+  GL_INT* = 0x00001404
+  GL_UNSIGNED_INT* = 0x00001405
+  GL_FLOAT* = 0x00001406
+  GL_2_BYTES* = 0x00001407
+  GL_3_BYTES* = 0x00001408
+  GL_4_BYTES* = 0x00001409
+  GL_DOUBLE* = 0x0000140A     # DepthFunction
+                              #      GL_NEVER
+                              #      GL_LESS
+                              #      GL_EQUAL
+                              #      GL_LEQUAL
+                              #      GL_GREATER
+                              #      GL_NOTEQUAL
+                              #      GL_GEQUAL
+                              #      GL_ALWAYS
+                              # DrawBufferMode
+  GL_NONE* = 0
+  GL_FRONT_LEFT* = 0x00000400
+  GL_FRONT_RIGHT* = 0x00000401
+  GL_BACK_LEFT* = 0x00000402
+  GL_BACK_RIGHT* = 0x00000403
+  GL_FRONT* = 0x00000404
+  GL_BACK* = 0x00000405
+  GL_LEFT* = 0x00000406
+  GL_RIGHT* = 0x00000407
+  GL_FRONT_AND_BACK* = 0x00000408
+  GL_AUX0* = 0x00000409
+  GL_AUX1* = 0x0000040A
+  GL_AUX2* = 0x0000040B
+  GL_AUX3* = 0x0000040C       # Enable
+                              #      GL_FOG
+                              #      GL_LIGHTING
+                              #      GL_TEXTURE_1D
+                              #      GL_TEXTURE_2D
+                              #      GL_LINE_STIPPLE
+                              #      GL_POLYGON_STIPPLE
+                              #      GL_CULL_FACE
+                              #      GL_ALPHA_TEST
+                              #      GL_BLEND
+                              #      GL_INDEX_LOGIC_OP
+                              #      GL_COLOR_LOGIC_OP
+                              #      GL_DITHER
+                              #      GL_STENCIL_TEST
+                              #      GL_DEPTH_TEST
+                              #      GL_CLIP_PLANE0
+                              #      GL_CLIP_PLANE1
+                              #      GL_CLIP_PLANE2
+                              #      GL_CLIP_PLANE3
+                              #      GL_CLIP_PLANE4
+                              #      GL_CLIP_PLANE5
+                              #      GL_LIGHT0
+                              #      GL_LIGHT1
+                              #      GL_LIGHT2
+                              #      GL_LIGHT3
+                              #      GL_LIGHT4
+                              #      GL_LIGHT5
+                              #      GL_LIGHT6
+                              #      GL_LIGHT7
+                              #      GL_TEXTURE_GEN_S
+                              #      GL_TEXTURE_GEN_T
+                              #      GL_TEXTURE_GEN_R
+                              #      GL_TEXTURE_GEN_Q
+                              #      GL_MAP1_VERTEX_3
+                              #      GL_MAP1_VERTEX_4
+                              #      GL_MAP1_COLOR_4
+                              #      GL_MAP1_INDEX
+                              #      GL_MAP1_NORMAL
+                              #      GL_MAP1_TEXTURE_COORD_1
+                              #      GL_MAP1_TEXTURE_COORD_2
+                              #      GL_MAP1_TEXTURE_COORD_3
+                              #      GL_MAP1_TEXTURE_COORD_4
+                              #      GL_MAP2_VERTEX_3
+                              #      GL_MAP2_VERTEX_4
+                              #      GL_MAP2_COLOR_4
+                              #      GL_MAP2_INDEX
+                              #      GL_MAP2_NORMAL
+                              #      GL_MAP2_TEXTURE_COORD_1
+                              #      GL_MAP2_TEXTURE_COORD_2
+                              #      GL_MAP2_TEXTURE_COORD_3
+                              #      GL_MAP2_TEXTURE_COORD_4
+                              #      GL_POINT_SMOOTH
+                              #      GL_LINE_SMOOTH
+                              #      GL_POLYGON_SMOOTH
+                              #      GL_SCISSOR_TEST
+                              #      GL_COLOR_MATERIAL
+                              #      GL_NORMALIZE
+                              #      GL_AUTO_NORMAL
+                              #      GL_VERTEX_ARRAY
+                              #      GL_NORMAL_ARRAY
+                              #      GL_COLOR_ARRAY
+                              #      GL_INDEX_ARRAY
+                              #      GL_TEXTURE_COORD_ARRAY
+                              #      GL_EDGE_FLAG_ARRAY
+                              #      GL_POLYGON_OFFSET_POINT
+                              #      GL_POLYGON_OFFSET_LINE
+                              #      GL_POLYGON_OFFSET_FILL
+                              # ErrorCode
+  GL_NO_ERROR* = 0
+  GL_INVALID_ENUM* = 0x00000500
+  GL_INVALID_VALUE* = 0x00000501
+  GL_INVALID_OPERATION* = 0x00000502
+  GL_STACK_OVERFLOW* = 0x00000503
+  GL_STACK_UNDERFLOW* = 0x00000504
+  GL_OUT_OF_MEMORY* = 0x00000505 # FeedBackMode
+  GL_2D* = 0x00000600
+  GL_3D* = 0x00000601
+  GL_3D_COLOR* = 0x00000602
+  GL_3D_COLOR_TEXTURE* = 0x00000603
+  GL_4D_COLOR_TEXTURE* = 0x00000604 # FeedBackToken
+  GL_PASS_THROUGH_TOKEN* = 0x00000700
+  GL_POINT_TOKEN* = 0x00000701
+  GL_LINE_TOKEN* = 0x00000702
+  GL_POLYGON_TOKEN* = 0x00000703
+  GL_BITMAP_TOKEN* = 0x00000704
+  GL_DRAW_PIXEL_TOKEN* = 0x00000705
+  GL_COPY_PIXEL_TOKEN* = 0x00000706
+  GL_LINE_RESET_TOKEN* = 0x00000707 # FogMode
+                                    #      GL_LINEAR
+  GL_EXP* = 0x00000800
+  GL_EXP2* = 0x00000801       # FogParameter
+                              #      GL_FOG_COLOR
+                              #      GL_FOG_DENSITY
+                              #      GL_FOG_END
+                              #      GL_FOG_INDEX
+                              #      GL_FOG_MODE
+                              #      GL_FOG_START
+                              # FrontFaceDirection
+  GL_CW* = 0x00000900
+  GL_CCW* = 0x00000901        # GetMapTarget
+  GL_COEFF* = 0x00000A00
+  GL_ORDER* = 0x00000A01
+  GL_DOMAIN* = 0x00000A02     # GetPixelMap
+                              #      GL_PIXEL_MAP_I_TO_I
+                              #      GL_PIXEL_MAP_S_TO_S
+                              #      GL_PIXEL_MAP_I_TO_R
+                              #      GL_PIXEL_MAP_I_TO_G
+                              #      GL_PIXEL_MAP_I_TO_B
+                              #      GL_PIXEL_MAP_I_TO_A
+                              #      GL_PIXEL_MAP_R_TO_R
+                              #      GL_PIXEL_MAP_G_TO_G
+                              #      GL_PIXEL_MAP_B_TO_B
+                              #      GL_PIXEL_MAP_A_TO_A
+                              # GetPointerTarget
+                              #      GL_VERTEX_ARRAY_POINTER
+                              #      GL_NORMAL_ARRAY_POINTER
+                              #      GL_COLOR_ARRAY_POINTER
+                              #      GL_INDEX_ARRAY_POINTER
+                              #      GL_TEXTURE_COORD_ARRAY_POINTER
+                              #      GL_EDGE_FLAG_ARRAY_POINTER
+                              # GetTarget
+  GL_CURRENT_COLOR* = 0x00000B00
+  GL_CURRENT_INDEX* = 0x00000B01
+  GL_CURRENT_NORMAL* = 0x00000B02
+  GL_CURRENT_TEXTURE_COORDS* = 0x00000B03
+  GL_CURRENT_RASTER_COLOR* = 0x00000B04
+  GL_CURRENT_RASTER_INDEX* = 0x00000B05
+  GL_CURRENT_RASTER_TEXTURE_COORDS* = 0x00000B06
+  GL_CURRENT_RASTER_POSITION* = 0x00000B07
+  GL_CURRENT_RASTER_POSITION_VALID* = 0x00000B08
+  GL_CURRENT_RASTER_DISTANCE* = 0x00000B09
+  GL_POINT_SMOOTH* = 0x00000B10
+  constGL_POINT_SIZE* = 0x00000B11
+  GL_POINT_SIZE_RANGE* = 0x00000B12
+  GL_POINT_SIZE_GRANULARITY* = 0x00000B13
+  GL_LINE_SMOOTH* = 0x00000B20
+  constGL_LINE_WIDTH* = 0x00000B21
+  GL_LINE_WIDTH_RANGE* = 0x00000B22
+  GL_LINE_WIDTH_GRANULARITY* = 0x00000B23
+  constGL_LINE_STIPPLE* = 0x00000B24
+  GL_LINE_STIPPLE_PATTERN* = 0x00000B25
+  GL_LINE_STIPPLE_REPEAT* = 0x00000B26
+  GL_LIST_MODE* = 0x00000B30
+  GL_MAX_LIST_NESTING* = 0x00000B31
+  constGL_LIST_BASE* = 0x00000B32
+  GL_LIST_INDEX* = 0x00000B33
+  constGL_POLYGON_MODE* = 0x00000B40
+  GL_POLYGON_SMOOTH* = 0x00000B41
+  constGL_POLYGON_STIPPLE* = 0x00000B42
+  constGL_EDGE_FLAG* = 0x00000B43
+  constGL_CULL_FACE* = 0x00000B44
+  GL_CULL_FACE_MODE* = 0x00000B45
+  constGL_FRONT_FACE* = 0x00000B46
+  GL_LIGHTING* = 0x00000B50
+  GL_LIGHT_MODEL_LOCAL_VIEWER* = 0x00000B51
+  GL_LIGHT_MODEL_TWO_SIDE* = 0x00000B52
+  GL_LIGHT_MODEL_AMBIENT* = 0x00000B53
+  constGL_SHADE_MODEL* = 0x00000B54
+  GL_COLOR_MATERIAL_FACE* = 0x00000B55
+  GL_COLOR_MATERIAL_PARAMETER* = 0x00000B56
+  constGL_COLOR_MATERIAL* = 0x00000B57
+  GL_FOG* = 0x00000B60
+  GL_FOG_INDEX* = 0x00000B61
+  GL_FOG_DENSITY* = 0x00000B62
+  GL_FOG_START* = 0x00000B63
+  GL_FOG_END* = 0x00000B64
+  GL_FOG_MODE* = 0x00000B65
+  GL_FOG_COLOR* = 0x00000B66
+  constGL_DEPTH_RANGE* = 0x00000B70
+  GL_DEPTH_TEST* = 0x00000B71
+  GL_DEPTH_WRITEMASK* = 0x00000B72
+  GL_DEPTH_CLEAR_VALUE* = 0x00000B73
+  constGL_DEPTH_FUNC* = 0x00000B74
+  GL_ACCUM_CLEAR_VALUE* = 0x00000B80
+  GL_STENCIL_TEST* = 0x00000B90
+  GL_STENCIL_CLEAR_VALUE* = 0x00000B91
+  constGL_STENCIL_FUNC* = 0x00000B92
+  GL_STENCIL_VALUE_MASK* = 0x00000B93
+  GL_STENCIL_FAIL* = 0x00000B94
+  GL_STENCIL_PASS_DEPTH_FAIL* = 0x00000B95
+  GL_STENCIL_PASS_DEPTH_PASS* = 0x00000B96
+  GL_STENCIL_REF* = 0x00000B97
+  GL_STENCIL_WRITEMASK* = 0x00000B98
+  constGL_MATRIX_MODE* = 0x00000BA0
+  GL_NORMALIZE* = 0x00000BA1
+  constGL_VIEWPORT* = 0x00000BA2
+  GL_MODELVIEW_STACK_DEPTH* = 0x00000BA3
+  GL_PROJECTION_STACK_DEPTH* = 0x00000BA4
+  GL_TEXTURE_STACK_DEPTH* = 0x00000BA5
+  GL_MODELVIEW_MATRIX* = 0x00000BA6
+  GL_PROJECTION_MATRIX* = 0x00000BA7
+  GL_TEXTURE_MATRIX* = 0x00000BA8
+  GL_ATTRIB_STACK_DEPTH* = 0x00000BB0
+  GL_CLIENT_ATTRIB_STACK_DEPTH* = 0x00000BB1
+  GL_ALPHA_TEST* = 0x00000BC0
+  GL_ALPHA_TEST_FUNC* = 0x00000BC1
+  GL_ALPHA_TEST_REF* = 0x00000BC2
+  GL_DITHER* = 0x00000BD0
+  GL_BLEND_DST* = 0x00000BE0
+  GL_BLEND_SRC* = 0x00000BE1
+  GL_BLEND* = 0x00000BE2
+  GL_LOGIC_OP_MODE* = 0x00000BF0
+  GL_INDEX_LOGIC_OP* = 0x00000BF1
+  GL_COLOR_LOGIC_OP* = 0x00000BF2
+  GL_AUX_BUFFERS* = 0x00000C00
+  constGL_DRAW_BUFFER* = 0x00000C01
+  constGL_READ_BUFFER* = 0x00000C02
+  GL_SCISSOR_BOX* = 0x00000C10
+  GL_SCISSOR_TEST* = 0x00000C11
+  GL_INDEX_CLEAR_VALUE* = 0x00000C20
+  GL_INDEX_WRITEMASK* = 0x00000C21
+  GL_COLOR_CLEAR_VALUE* = 0x00000C22
+  GL_COLOR_WRITEMASK* = 0x00000C23
+  GL_INDEX_MODE* = 0x00000C30
+  GL_RGBA_MODE* = 0x00000C31
+  GL_DOUBLEBUFFER* = 0x00000C32
+  GL_STEREO* = 0x00000C33
+  constGL_RENDER_MODE* = 0x00000C40
+  GL_PERSPECTIVE_CORRECTION_HINT* = 0x00000C50
+  GL_POINT_SMOOTH_HINT* = 0x00000C51
+  GL_LINE_SMOOTH_HINT* = 0x00000C52
+  GL_POLYGON_SMOOTH_HINT* = 0x00000C53
+  GL_FOG_HINT* = 0x00000C54
+  GL_TEXTURE_GEN_S* = 0x00000C60
+  GL_TEXTURE_GEN_T* = 0x00000C61
+  GL_TEXTURE_GEN_R* = 0x00000C62
+  GL_TEXTURE_GEN_Q* = 0x00000C63
+  GL_PIXEL_MAP_I_TO_I* = 0x00000C70
+  GL_PIXEL_MAP_S_TO_S* = 0x00000C71
+  GL_PIXEL_MAP_I_TO_R* = 0x00000C72
+  GL_PIXEL_MAP_I_TO_G* = 0x00000C73
+  GL_PIXEL_MAP_I_TO_B* = 0x00000C74
+  GL_PIXEL_MAP_I_TO_A* = 0x00000C75
+  GL_PIXEL_MAP_R_TO_R* = 0x00000C76
+  GL_PIXEL_MAP_G_TO_G* = 0x00000C77
+  GL_PIXEL_MAP_B_TO_B* = 0x00000C78
+  GL_PIXEL_MAP_A_TO_A* = 0x00000C79
+  GL_PIXEL_MAP_I_TO_I_SIZE* = 0x00000CB0
+  GL_PIXEL_MAP_S_TO_S_SIZE* = 0x00000CB1
+  GL_PIXEL_MAP_I_TO_R_SIZE* = 0x00000CB2
+  GL_PIXEL_MAP_I_TO_G_SIZE* = 0x00000CB3
+  GL_PIXEL_MAP_I_TO_B_SIZE* = 0x00000CB4
+  GL_PIXEL_MAP_I_TO_A_SIZE* = 0x00000CB5
+  GL_PIXEL_MAP_R_TO_R_SIZE* = 0x00000CB6
+  GL_PIXEL_MAP_G_TO_G_SIZE* = 0x00000CB7
+  GL_PIXEL_MAP_B_TO_B_SIZE* = 0x00000CB8
+  GL_PIXEL_MAP_A_TO_A_SIZE* = 0x00000CB9
+  GL_UNPACK_SWAP_BYTES* = 0x00000CF0
+  GL_UNPACK_LSB_FIRST* = 0x00000CF1
+  GL_UNPACK_ROW_LENGTH* = 0x00000CF2
+  GL_UNPACK_SKIP_ROWS* = 0x00000CF3
+  GL_UNPACK_SKIP_PIXELS* = 0x00000CF4
+  GL_UNPACK_ALIGNMENT* = 0x00000CF5
+  GL_PACK_SWAP_BYTES* = 0x00000D00
+  GL_PACK_LSB_FIRST* = 0x00000D01
+  GL_PACK_ROW_LENGTH* = 0x00000D02
+  GL_PACK_SKIP_ROWS* = 0x00000D03
+  GL_PACK_SKIP_PIXELS* = 0x00000D04
+  GL_PACK_ALIGNMENT* = 0x00000D05
+  GL_MAP_COLOR* = 0x00000D10
+  GL_MAP_STENCIL* = 0x00000D11
+  GL_INDEX_SHIFT* = 0x00000D12
+  GL_INDEX_OFFSET* = 0x00000D13
+  GL_RED_SCALE* = 0x00000D14
+  GL_RED_BIAS* = 0x00000D15
+  GL_ZOOM_X* = 0x00000D16
+  GL_ZOOM_Y* = 0x00000D17
+  GL_GREEN_SCALE* = 0x00000D18
+  GL_GREEN_BIAS* = 0x00000D19
+  GL_BLUE_SCALE* = 0x00000D1A
+  GL_BLUE_BIAS* = 0x00000D1B
+  GL_ALPHA_SCALE* = 0x00000D1C
+  GL_ALPHA_BIAS* = 0x00000D1D
+  GL_DEPTH_SCALE* = 0x00000D1E
+  GL_DEPTH_BIAS* = 0x00000D1F
+  GL_MAX_EVAL_ORDER* = 0x00000D30
+  GL_MAX_LIGHTS* = 0x00000D31
+  GL_MAX_CLIP_PLANES* = 0x00000D32
+  GL_MAX_TEXTURE_SIZE* = 0x00000D33
+  GL_MAX_PIXEL_MAP_TABLE* = 0x00000D34
+  GL_MAX_ATTRIB_STACK_DEPTH* = 0x00000D35
+  GL_MAX_MODELVIEW_STACK_DEPTH* = 0x00000D36
+  GL_MAX_NAME_STACK_DEPTH* = 0x00000D37
+  GL_MAX_PROJECTION_STACK_DEPTH* = 0x00000D38
+  GL_MAX_TEXTURE_STACK_DEPTH* = 0x00000D39
+  GL_MAX_VIEWPORT_DIMS* = 0x00000D3A
+  GL_MAX_CLIENT_ATTRIB_STACK_DEPTH* = 0x00000D3B
+  GL_SUBPIXEL_BITS* = 0x00000D50
+  GL_INDEX_BITS* = 0x00000D51
+  GL_RED_BITS* = 0x00000D52
+  GL_GREEN_BITS* = 0x00000D53
+  GL_BLUE_BITS* = 0x00000D54
+  GL_ALPHA_BITS* = 0x00000D55
+  GL_DEPTH_BITS* = 0x00000D56
+  GL_STENCIL_BITS* = 0x00000D57
+  GL_ACCUM_RED_BITS* = 0x00000D58
+  GL_ACCUM_GREEN_BITS* = 0x00000D59
+  GL_ACCUM_BLUE_BITS* = 0x00000D5A
+  GL_ACCUM_ALPHA_BITS* = 0x00000D5B
+  GL_NAME_STACK_DEPTH* = 0x00000D70
+  GL_AUTO_NORMAL* = 0x00000D80
+  GL_MAP1_COLOR_4* = 0x00000D90
+  GL_MAP1_INDEX* = 0x00000D91
+  GL_MAP1_NORMAL* = 0x00000D92
+  GL_MAP1_TEXTURE_COORD_1* = 0x00000D93
+  GL_MAP1_TEXTURE_COORD_2* = 0x00000D94
+  GL_MAP1_TEXTURE_COORD_3* = 0x00000D95
+  GL_MAP1_TEXTURE_COORD_4* = 0x00000D96
+  GL_MAP1_VERTEX_3* = 0x00000D97
+  GL_MAP1_VERTEX_4* = 0x00000D98
+  GL_MAP2_COLOR_4* = 0x00000DB0
+  GL_MAP2_INDEX* = 0x00000DB1
+  GL_MAP2_NORMAL* = 0x00000DB2
+  GL_MAP2_TEXTURE_COORD_1* = 0x00000DB3
+  GL_MAP2_TEXTURE_COORD_2* = 0x00000DB4
+  GL_MAP2_TEXTURE_COORD_3* = 0x00000DB5
+  GL_MAP2_TEXTURE_COORD_4* = 0x00000DB6
+  GL_MAP2_VERTEX_3* = 0x00000DB7
+  GL_MAP2_VERTEX_4* = 0x00000DB8
+  GL_MAP1_GRID_DOMAIN* = 0x00000DD0
+  GL_MAP1_GRID_SEGMENTS* = 0x00000DD1
+  GL_MAP2_GRID_DOMAIN* = 0x00000DD2
+  GL_MAP2_GRID_SEGMENTS* = 0x00000DD3
+  GL_TEXTURE_1D* = 0x00000DE0
+  GL_TEXTURE_2D* = 0x00000DE1
+  GL_FEEDBACK_BUFFER_POINTER* = 0x00000DF0
+  GL_FEEDBACK_BUFFER_SIZE* = 0x00000DF1
+  GL_FEEDBACK_BUFFER_TYPE* = 0x00000DF2
+  GL_SELECTION_BUFFER_POINTER* = 0x00000DF3
+  GL_SELECTION_BUFFER_SIZE* = 0x00000DF4 #      GL_TEXTURE_BINDING_1D
+                                         #      GL_TEXTURE_BINDING_2D
+                                         #      GL_VERTEX_ARRAY
+                                         #      GL_NORMAL_ARRAY
+                                         #      GL_COLOR_ARRAY
+                                         #      GL_INDEX_ARRAY
+                                         #      GL_TEXTURE_COORD_ARRAY
+                                         #      GL_EDGE_FLAG_ARRAY
+                                         #      GL_VERTEX_ARRAY_SIZE
+                                         #      GL_VERTEX_ARRAY_TYPE
+                                         #      GL_VERTEX_ARRAY_STRIDE
+                                         #      GL_NORMAL_ARRAY_TYPE
+                                         #      GL_NORMAL_ARRAY_STRIDE
+                                         #      GL_COLOR_ARRAY_SIZE
+                                         #      GL_COLOR_ARRAY_TYPE
+                                         #      GL_COLOR_ARRAY_STRIDE
+                                         #      GL_INDEX_ARRAY_TYPE
+                                         #      GL_INDEX_ARRAY_STRIDE
+                                         #      GL_TEXTURE_COORD_ARRAY_SIZE
+                                         #      GL_TEXTURE_COORD_ARRAY_TYPE
+                                         #      GL_TEXTURE_COORD_ARRAY_STRIDE
+                                         #      GL_EDGE_FLAG_ARRAY_STRIDE
+                                         #      GL_POLYGON_OFFSET_FACTOR
+                                         #      GL_POLYGON_OFFSET_UNITS
+                                         # GetTextureParameter
+                                         #      GL_TEXTURE_MAG_FILTER
+                                         #      GL_TEXTURE_MIN_FILTER
+                                         #      GL_TEXTURE_WRAP_S
+                                         #      GL_TEXTURE_WRAP_T
+  GL_TEXTURE_WIDTH* = 0x00001000
+  GL_TEXTURE_HEIGHT* = 0x00001001
+  GL_TEXTURE_INTERNAL_FORMAT* = 0x00001003
+  GL_TEXTURE_BORDER_COLOR* = 0x00001004
+  GL_TEXTURE_BORDER* = 0x00001005 #      GL_TEXTURE_RED_SIZE
+                                  #      GL_TEXTURE_GREEN_SIZE
+                                  #      GL_TEXTURE_BLUE_SIZE
+                                  #      GL_TEXTURE_ALPHA_SIZE
+                                  #      GL_TEXTURE_LUMINANCE_SIZE
+                                  #      GL_TEXTURE_INTENSITY_SIZE
+                                  #      GL_TEXTURE_PRIORITY
+                                  #      GL_TEXTURE_RESIDENT
+                                  # HintMode
+  GL_DONT_CARE* = 0x00001100
+  GL_FASTEST* = 0x00001101
+  GL_NICEST* = 0x00001102     # HintTarget
+                              #      GL_PERSPECTIVE_CORRECTION_HINT
+                              #      GL_POINT_SMOOTH_HINT
+                              #      GL_LINE_SMOOTH_HINT
+                              #      GL_POLYGON_SMOOTH_HINT
+                              #      GL_FOG_HINT
+                              # IndexPointerType
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # LightModelParameter
+                              #      GL_LIGHT_MODEL_AMBIENT
+                              #      GL_LIGHT_MODEL_LOCAL_VIEWER
+                              #      GL_LIGHT_MODEL_TWO_SIDE
+                              # LightName
+  GL_LIGHT0* = 0x00004000
+  GL_LIGHT1* = 0x00004001
+  GL_LIGHT2* = 0x00004002
+  GL_LIGHT3* = 0x00004003
+  GL_LIGHT4* = 0x00004004
+  GL_LIGHT5* = 0x00004005
+  GL_LIGHT6* = 0x00004006
+  GL_LIGHT7* = 0x00004007     # LightParameter
+  GL_AMBIENT* = 0x00001200
+  GL_DIFFUSE* = 0x00001201
+  GL_SPECULAR* = 0x00001202
+  GL_POSITION* = 0x00001203
+  GL_SPOT_DIRECTION* = 0x00001204
+  GL_SPOT_EXPONENT* = 0x00001205
+  GL_SPOT_CUTOFF* = 0x00001206
+  GL_CONSTANT_ATTENUATION* = 0x00001207
+  GL_LINEAR_ATTENUATION* = 0x00001208
+  GL_QUADRATIC_ATTENUATION* = 0x00001209 # InterleavedArrays
+                                         #      GL_V2F
+                                         #      GL_V3F
+                                         #      GL_C4UB_V2F
+                                         #      GL_C4UB_V3F
+                                         #      GL_C3F_V3F
+                                         #      GL_N3F_V3F
+                                         #      GL_C4F_N3F_V3F
+                                         #      GL_T2F_V3F
+                                         #      GL_T4F_V4F
+                                         #      GL_T2F_C4UB_V3F
+                                         #      GL_T2F_C3F_V3F
+                                         #      GL_T2F_N3F_V3F
+                                         #      GL_T2F_C4F_N3F_V3F
+                                         #      GL_T4F_C4F_N3F_V4F
+                                         # ListMode
+  GL_COMPILE* = 0x00001300
+  GL_COMPILE_AND_EXECUTE* = 0x00001301 # ListNameType
+                                       #      GL_BYTE
+                                       #      GL_UNSIGNED_BYTE
+                                       #      GL_SHORT
+                                       #      GL_UNSIGNED_SHORT
+                                       #      GL_INT
+                                       #      GL_UNSIGNED_INT
+                                       #      GL_FLOAT
+                                       #      GL_2_BYTES
+                                       #      GL_3_BYTES
+                                       #      GL_4_BYTES
+                                       # LogicOp
+  constGL_CLEAR* = 0x00001500
+  GL_AND* = 0x00001501
+  GL_AND_REVERSE* = 0x00001502
+  GL_COPY* = 0x00001503
+  GL_AND_INVERTED* = 0x00001504
+  GL_NOOP* = 0x00001505
+  GL_XOR* = 0x00001506
+  GL_OR* = 0x00001507
+  GL_NOR* = 0x00001508
+  GL_EQUIV* = 0x00001509
+  GL_INVERT* = 0x0000150A
+  GL_OR_REVERSE* = 0x0000150B
+  GL_COPY_INVERTED* = 0x0000150C
+  GL_OR_INVERTED* = 0x0000150D
+  GL_NAND* = 0x0000150E
+  GL_SET* = 0x0000150F        # MapTarget
+                              #      GL_MAP1_COLOR_4
+                              #      GL_MAP1_INDEX
+                              #      GL_MAP1_NORMAL
+                              #      GL_MAP1_TEXTURE_COORD_1
+                              #      GL_MAP1_TEXTURE_COORD_2
+                              #      GL_MAP1_TEXTURE_COORD_3
+                              #      GL_MAP1_TEXTURE_COORD_4
+                              #      GL_MAP1_VERTEX_3
+                              #      GL_MAP1_VERTEX_4
+                              #      GL_MAP2_COLOR_4
+                              #      GL_MAP2_INDEX
+                              #      GL_MAP2_NORMAL
+                              #      GL_MAP2_TEXTURE_COORD_1
+                              #      GL_MAP2_TEXTURE_COORD_2
+                              #      GL_MAP2_TEXTURE_COORD_3
+                              #      GL_MAP2_TEXTURE_COORD_4
+                              #      GL_MAP2_VERTEX_3
+                              #      GL_MAP2_VERTEX_4
+                              # MaterialFace
+                              #      GL_FRONT
+                              #      GL_BACK
+                              #      GL_FRONT_AND_BACK
+                              # MaterialParameter
+  GL_EMISSION* = 0x00001600
+  GL_SHININESS* = 0x00001601
+  GL_AMBIENT_AND_DIFFUSE* = 0x00001602
+  GL_COLOR_INDEXES* = 0x00001603 #      GL_AMBIENT
+                                 #      GL_DIFFUSE
+                                 #      GL_SPECULAR
+                                 # MatrixMode
+  GL_MODELVIEW* = 0x00001700
+  GL_PROJECTION* = 0x00001701
+  GL_TEXTURE* = 0x00001702    # MeshMode1
+                              #      GL_POINT
+                              #      GL_LINE
+                              # MeshMode2
+                              #      GL_POINT
+                              #      GL_LINE
+                              #      GL_FILL
+                              # NormalPointerType
+                              #      GL_BYTE
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # PixelCopyType
+  GL_COLOR* = 0x00001800
+  GL_DEPTH* = 0x00001801
+  GL_STENCIL* = 0x00001802    # PixelFormat
+  GL_COLOR_INDEX* = 0x00001900
+  GL_STENCIL_INDEX* = 0x00001901
+  GL_DEPTH_COMPONENT* = 0x00001902
+  GL_RED* = 0x00001903
+  GL_GREEN* = 0x00001904
+  GL_BLUE* = 0x00001905
+  GL_ALPHA* = 0x00001906
+  GL_RGB* = 0x00001907
+  GL_RGBA* = 0x00001908
+  GL_LUMINANCE* = 0x00001909
+  GL_LUMINANCE_ALPHA* = 0x0000190A # PixelMap
+                                   #      GL_PIXEL_MAP_I_TO_I
+                                   #      GL_PIXEL_MAP_S_TO_S
+                                   #      GL_PIXEL_MAP_I_TO_R
+                                   #      GL_PIXEL_MAP_I_TO_G
+                                   #      GL_PIXEL_MAP_I_TO_B
+                                   #      GL_PIXEL_MAP_I_TO_A
+                                   #      GL_PIXEL_MAP_R_TO_R
+                                   #      GL_PIXEL_MAP_G_TO_G
+                                   #      GL_PIXEL_MAP_B_TO_B
+                                   #      GL_PIXEL_MAP_A_TO_A
+                                   # PixelStore
+                                   #      GL_UNPACK_SWAP_BYTES
+                                   #      GL_UNPACK_LSB_FIRST
+                                   #      GL_UNPACK_ROW_LENGTH
+                                   #      GL_UNPACK_SKIP_ROWS
+                                   #      GL_UNPACK_SKIP_PIXELS
+                                   #      GL_UNPACK_ALIGNMENT
+                                   #      GL_PACK_SWAP_BYTES
+                                   #      GL_PACK_LSB_FIRST
+                                   #      GL_PACK_ROW_LENGTH
+                                   #      GL_PACK_SKIP_ROWS
+                                   #      GL_PACK_SKIP_PIXELS
+                                   #      GL_PACK_ALIGNMENT
+                                   # PixelTransfer
+                                   #      GL_MAP_COLOR
+                                   #      GL_MAP_STENCIL
+                                   #      GL_INDEX_SHIFT
+                                   #      GL_INDEX_OFFSET
+                                   #      GL_RED_SCALE
+                                   #      GL_RED_BIAS
+                                   #      GL_GREEN_SCALE
+                                   #      GL_GREEN_BIAS
+                                   #      GL_BLUE_SCALE
+                                   #      GL_BLUE_BIAS
+                                   #      GL_ALPHA_SCALE
+                                   #      GL_ALPHA_BIAS
+                                   #      GL_DEPTH_SCALE
+                                   #      GL_DEPTH_BIAS
+                                   # PixelType
+  constGL_BITMAP* = 0x00001A00
+  GL_POINT* = 0x00001B00
+  GL_LINE* = 0x00001B01
+  GL_FILL* = 0x00001B02       # ReadBufferMode
+                              #      GL_FRONT_LEFT
+                              #      GL_FRONT_RIGHT
+                              #      GL_BACK_LEFT
+                              #      GL_BACK_RIGHT
+                              #      GL_FRONT
+                              #      GL_BACK
+                              #      GL_LEFT
+                              #      GL_RIGHT
+                              #      GL_AUX0
+                              #      GL_AUX1
+                              #      GL_AUX2
+                              #      GL_AUX3
+                              # RenderingMode
+  GL_RENDER* = 0x00001C00
+  GL_FEEDBACK* = 0x00001C01
+  GL_SELECT* = 0x00001C02     # ShadingModel
+  GL_FLAT* = 0x00001D00
+  GL_SMOOTH* = 0x00001D01     # StencilFunction
+                              #      GL_NEVER
+                              #      GL_LESS
+                              #      GL_EQUAL
+                              #      GL_LEQUAL
+                              #      GL_GREATER
+                              #      GL_NOTEQUAL
+                              #      GL_GEQUAL
+                              #      GL_ALWAYS
+                              # StencilOp
+                              #      GL_ZERO
+  GL_KEEP* = 0x00001E00
+  GL_REPLACE* = 0x00001E01
+  GL_INCR* = 0x00001E02
+  GL_DECR* = 0x00001E03       #      GL_INVERT
+                              # StringName
+  GL_VENDOR* = 0x00001F00
+  GL_RENDERER* = 0x00001F01
+  GL_VERSION* = 0x00001F02
+  GL_EXTENSIONS* = 0x00001F03 # TextureCoordName
+  GL_S* = 0x00002000
+  GL_T* = 0x00002001
+  GL_R* = 0x00002002
+  GL_Q* = 0x00002003          # TexCoordPointerType
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # TextureEnvMode
+  GL_MODULATE* = 0x00002100
+  GL_DECAL* = 0x00002101      #      GL_BLEND
+                              #      GL_REPLACE
+                              # TextureEnvParameter
+  GL_TEXTURE_ENV_MODE* = 0x00002200
+  GL_TEXTURE_ENV_COLOR* = 0x00002201 # TextureEnvTarget
+  GL_TEXTURE_ENV* = 0x00002300 # TextureGenMode
+  GL_EYE_LINEAR* = 0x00002400
+  GL_OBJECT_LINEAR* = 0x00002401
+  GL_SPHERE_MAP* = 0x00002402 # TextureGenParameter
+  GL_TEXTURE_GEN_MODE* = 0x00002500
+  GL_OBJECT_PLANE* = 0x00002501
+  GL_EYE_PLANE* = 0x00002502  # TextureMagFilter
+  GL_NEAREST* = 0x00002600
+  GL_LINEAR* = 0x00002601     # TextureMinFilter
+                              #      GL_NEAREST
+                              #      GL_LINEAR
+  GL_NEAREST_MIPMAP_NEAREST* = 0x00002700
+  GL_LINEAR_MIPMAP_NEAREST* = 0x00002701
+  GL_NEAREST_MIPMAP_LINEAR* = 0x00002702
+  GL_LINEAR_MIPMAP_LINEAR* = 0x00002703 # TextureParameterName
+  GL_TEXTURE_MAG_FILTER* = 0x00002800
+  GL_TEXTURE_MIN_FILTER* = 0x00002801
+  GL_TEXTURE_WRAP_S* = 0x00002802
+  GL_TEXTURE_WRAP_T* = 0x00002803 #      GL_TEXTURE_BORDER_COLOR
+                                  #      GL_TEXTURE_PRIORITY
+                                  # TextureTarget
+                                  #      GL_TEXTURE_1D
+                                  #      GL_TEXTURE_2D
+                                  #      GL_PROXY_TEXTURE_1D
+                                  #      GL_PROXY_TEXTURE_2D
+                                  # TextureWrapMode
+  GL_CLAMP* = 0x00002900
+  GL_REPEAT* = 0x00002901     # VertexPointerType
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # ClientAttribMask
+  GL_CLIENT_PIXEL_STORE_BIT* = 0x00000001
+  GL_CLIENT_VERTEX_ARRAY_BIT* = 0x00000002
+  GL_CLIENT_ALL_ATTRIB_BITS* = 0xFFFFFFFF # polygon_offset
+  GL_POLYGON_OFFSET_FACTOR* = 0x00008038
+  GL_POLYGON_OFFSET_UNITS* = 0x00002A00
+  GL_POLYGON_OFFSET_POINT* = 0x00002A01
+  GL_POLYGON_OFFSET_LINE* = 0x00002A02
+  GL_POLYGON_OFFSET_FILL* = 0x00008037 # texture
+  GL_ALPHA4* = 0x0000803B
+  GL_ALPHA8* = 0x0000803C
+  GL_ALPHA12* = 0x0000803D
+  GL_ALPHA16* = 0x0000803E
+  GL_LUMINANCE4* = 0x0000803F
+  GL_LUMINANCE8* = 0x00008040
+  GL_LUMINANCE12* = 0x00008041
+  GL_LUMINANCE16* = 0x00008042
+  GL_LUMINANCE4_ALPHA4* = 0x00008043
+  GL_LUMINANCE6_ALPHA2* = 0x00008044
+  GL_LUMINANCE8_ALPHA8* = 0x00008045
+  GL_LUMINANCE12_ALPHA4* = 0x00008046
+  GL_LUMINANCE12_ALPHA12* = 0x00008047
+  GL_LUMINANCE16_ALPHA16* = 0x00008048
+  GL_INTENSITY* = 0x00008049
+  GL_INTENSITY4* = 0x0000804A
+  GL_INTENSITY8* = 0x0000804B
+  GL_INTENSITY12* = 0x0000804C
+  GL_INTENSITY16* = 0x0000804D
+  GL_R3_G3_B2* = 0x00002A10
+  GL_RGB4* = 0x0000804F
+  GL_RGB5* = 0x00008050
+  GL_RGB8* = 0x00008051
+  GL_RGB10* = 0x00008052
+  GL_RGB12* = 0x00008053
+  GL_RGB16* = 0x00008054
+  GL_RGBA2* = 0x00008055
+  GL_RGBA4* = 0x00008056
+  GL_RGB5_A1* = 0x00008057
+  GL_RGBA8* = 0x00008058
+  GL_RGB10_A2* = 0x00008059
+  GL_RGBA12* = 0x0000805A
+  GL_RGBA16* = 0x0000805B
+  GL_TEXTURE_RED_SIZE* = 0x0000805C
+  GL_TEXTURE_GREEN_SIZE* = 0x0000805D
+  GL_TEXTURE_BLUE_SIZE* = 0x0000805E
+  GL_TEXTURE_ALPHA_SIZE* = 0x0000805F
+  GL_TEXTURE_LUMINANCE_SIZE* = 0x00008060
+  GL_TEXTURE_INTENSITY_SIZE* = 0x00008061
+  GL_PROXY_TEXTURE_1D* = 0x00008063
+  GL_PROXY_TEXTURE_2D* = 0x00008064 # texture_object
+  GL_TEXTURE_PRIORITY* = 0x00008066
+  GL_TEXTURE_RESIDENT* = 0x00008067
+  GL_TEXTURE_BINDING_1D* = 0x00008068
+  GL_TEXTURE_BINDING_2D* = 0x00008069 # vertex_array
+  GL_VERTEX_ARRAY* = 0x00008074
+  GL_NORMAL_ARRAY* = 0x00008075
+  GL_COLOR_ARRAY* = 0x00008076
+  GL_INDEX_ARRAY* = 0x00008077
+  GL_TEXTURE_COORD_ARRAY* = 0x00008078
+  GL_EDGE_FLAG_ARRAY* = 0x00008079
+  GL_VERTEX_ARRAY_SIZE* = 0x0000807A
+  GL_VERTEX_ARRAY_TYPE* = 0x0000807B
+  GL_VERTEX_ARRAY_STRIDE* = 0x0000807C
+  GL_NORMAL_ARRAY_TYPE* = 0x0000807E
+  GL_NORMAL_ARRAY_STRIDE* = 0x0000807F
+  GL_COLOR_ARRAY_SIZE* = 0x00008081
+  GL_COLOR_ARRAY_TYPE* = 0x00008082
+  GL_COLOR_ARRAY_STRIDE* = 0x00008083
+  GL_INDEX_ARRAY_TYPE* = 0x00008085
+  GL_INDEX_ARRAY_STRIDE* = 0x00008086
+  GL_TEXTURE_COORD_ARRAY_SIZE* = 0x00008088
+  GL_TEXTURE_COORD_ARRAY_TYPE* = 0x00008089
+  GL_TEXTURE_COORD_ARRAY_STRIDE* = 0x0000808A
+  GL_EDGE_FLAG_ARRAY_STRIDE* = 0x0000808C
+  GL_VERTEX_ARRAY_POINTER* = 0x0000808E
+  GL_NORMAL_ARRAY_POINTER* = 0x0000808F
+  GL_COLOR_ARRAY_POINTER* = 0x00008090
+  GL_INDEX_ARRAY_POINTER* = 0x00008091
+  GL_TEXTURE_COORD_ARRAY_POINTER* = 0x00008092
+  GL_EDGE_FLAG_ARRAY_POINTER* = 0x00008093
+  GL_V2F* = 0x00002A20
+  GL_V3F* = 0x00002A21
+  GL_C4UB_V2F* = 0x00002A22
+  GL_C4UB_V3F* = 0x00002A23
+  GL_C3F_V3F* = 0x00002A24
+  GL_N3F_V3F* = 0x00002A25
+  GL_C4F_N3F_V3F* = 0x00002A26
+  GL_T2F_V3F* = 0x00002A27
+  GL_T4F_V4F* = 0x00002A28
+  GL_T2F_C4UB_V3F* = 0x00002A29
+  GL_T2F_C3F_V3F* = 0x00002A2A
+  GL_T2F_N3F_V3F* = 0x00002A2B
+  GL_T2F_C4F_N3F_V3F* = 0x00002A2C
+  GL_T4F_C4F_N3F_V4F* = 0x00002A2D # Extensions
+  GL_EXT_vertex_array* = 1
+  GL_WIN_swap_hint* = 1
+  GL_EXT_bgra* = 1
+  GL_EXT_paletted_texture* = 1 # EXT_vertex_array
+  GL_VERTEX_ARRAY_EXT* = 0x00008074
+  GL_NORMAL_ARRAY_EXT* = 0x00008075
+  GL_COLOR_ARRAY_EXT* = 0x00008076
+  GL_INDEX_ARRAY_EXT* = 0x00008077
+  GL_TEXTURE_COORD_ARRAY_EXT* = 0x00008078
+  GL_EDGE_FLAG_ARRAY_EXT* = 0x00008079
+  GL_VERTEX_ARRAY_SIZE_EXT* = 0x0000807A
+  GL_VERTEX_ARRAY_TYPE_EXT* = 0x0000807B
+  GL_VERTEX_ARRAY_STRIDE_EXT* = 0x0000807C
+  GL_VERTEX_ARRAY_COUNT_EXT* = 0x0000807D
+  GL_NORMAL_ARRAY_TYPE_EXT* = 0x0000807E
+  GL_NORMAL_ARRAY_STRIDE_EXT* = 0x0000807F
+  GL_NORMAL_ARRAY_COUNT_EXT* = 0x00008080
+  GL_COLOR_ARRAY_SIZE_EXT* = 0x00008081
+  GL_COLOR_ARRAY_TYPE_EXT* = 0x00008082
+  GL_COLOR_ARRAY_STRIDE_EXT* = 0x00008083
+  GL_COLOR_ARRAY_COUNT_EXT* = 0x00008084
+  GL_INDEX_ARRAY_TYPE_EXT* = 0x00008085
+  GL_INDEX_ARRAY_STRIDE_EXT* = 0x00008086
+  GL_INDEX_ARRAY_COUNT_EXT* = 0x00008087
+  GL_TEXTURE_COORD_ARRAY_SIZE_EXT* = 0x00008088
+  GL_TEXTURE_COORD_ARRAY_TYPE_EXT* = 0x00008089
+  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT* = 0x0000808A
+  GL_TEXTURE_COORD_ARRAY_COUNT_EXT* = 0x0000808B
+  GL_EDGE_FLAG_ARRAY_STRIDE_EXT* = 0x0000808C
+  GL_EDGE_FLAG_ARRAY_COUNT_EXT* = 0x0000808D
+  GL_VERTEX_ARRAY_POINTER_EXT* = 0x0000808E
+  GL_NORMAL_ARRAY_POINTER_EXT* = 0x0000808F
+  GL_COLOR_ARRAY_POINTER_EXT* = 0x00008090
+  GL_INDEX_ARRAY_POINTER_EXT* = 0x00008091
+  GL_TEXTURE_COORD_ARRAY_POINTER_EXT* = 0x00008092
+  GL_EDGE_FLAG_ARRAY_POINTER_EXT* = 0x00008093
+  GL_DOUBLE_EXT* = GL_DOUBLE  # EXT_bgra
+  GL_BGR_EXT* = 0x000080E0
+  GL_BGRA_EXT* = 0x000080E1   # EXT_paletted_texture
+                              # These must match the GL_COLOR_TABLE_*_SGI enumerants
+  GL_COLOR_TABLE_FORMAT_EXT* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH_EXT* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE_EXT* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE_EXT* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE_EXT* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE_EXT* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE_EXT* = 0x000080DF
+  GL_COLOR_INDEX1_EXT* = 0x000080E2
+  GL_COLOR_INDEX2_EXT* = 0x000080E3
+  GL_COLOR_INDEX4_EXT* = 0x000080E4
+  GL_COLOR_INDEX8_EXT* = 0x000080E5
+  GL_COLOR_INDEX12_EXT* = 0x000080E6
+  GL_COLOR_INDEX16_EXT* = 0x000080E7 # For compatibility with OpenGL v1.0
+  constGL_LOGIC_OP* = GL_INDEX_LOGIC_OP
+  GL_TEXTURE_COMPONENTS* = GL_TEXTURE_INTERNAL_FORMAT
+
+proc glAccum*(op: TGLenum, value: TGLfloat){.dynlib: dllname, importc: "glAccum".}
+proc glAlphaFunc*(fun: TGLenum, theref: TGLclampf){.dynlib: dllname, 
+    importc: "glAlphaFunc".}
+proc glAreTexturesResident*(n: TGLsizei, textures: PGLuint, 
+                            residences: PGLboolean): TGLboolean{.
+    dynlib: dllname, importc: "glAreTexturesResident".}
+proc glArrayElement*(i: TGLint){.dynlib: dllname, importc: "glArrayElement".}
+proc glBegin*(mode: TGLenum){.dynlib: dllname, importc: "glBegin".}
+proc glBindTexture*(target: TGLenum, texture: TGLuint){.dynlib: dllname, 
+    importc: "glBindTexture".}
+proc glBitmap*(width, height: TGLsizei, xorig, yorig: TGLfloat, 
+               xmove, ymove: TGLfloat, bitmap: PGLubyte){.dynlib: dllname, 
+    importc: "glBitmap".}
+proc glBlendFunc*(sfactor, dfactor: TGLenum){.dynlib: dllname, 
+    importc: "glBlendFunc".}
+proc glCallList*(list: TGLuint){.dynlib: dllname, importc: "glCallList".}
+proc glCallLists*(n: TGLsizei, atype: TGLenum, lists: pointer){.dynlib: dllname, 
+    importc: "glCallLists".}
+proc glClear*(mask: TGLbitfield){.dynlib: dllname, importc: "glClear".}
+proc glClearAccum*(red, green, blue, alpha: TGLfloat){.dynlib: dllname, 
+    importc: "glClearAccum".}
+proc glClearColor*(red, green, blue, alpha: TGLclampf){.dynlib: dllname, 
+    importc: "glClearColor".}
+proc glClearDepth*(depth: TGLclampd){.dynlib: dllname, importc: "glClearDepth".}
+proc glClearIndex*(c: TGLfloat){.dynlib: dllname, importc: "glClearIndex".}
+proc glClearStencil*(s: TGLint){.dynlib: dllname, importc: "glClearStencil".}
+proc glClipPlane*(plane: TGLenum, equation: PGLdouble){.dynlib: dllname, 
+    importc: "glClipPlane".}
+proc glColor3b*(red, green, blue: TGlbyte){.dynlib: dllname, 
+    importc: "glColor3b".}
+proc glColor3bv*(v: PGLbyte){.dynlib: dllname, importc: "glColor3bv".}
+proc glColor3d*(red, green, blue: TGLdouble){.dynlib: dllname, 
+    importc: "glColor3d".}
+proc glColor3dv*(v: PGLdouble){.dynlib: dllname, importc: "glColor3dv".}
+proc glColor3f*(red, green, blue: TGLfloat){.dynlib: dllname, 
+    importc: "glColor3f".}
+proc glColor3fv*(v: PGLfloat){.dynlib: dllname, importc: "glColor3fv".}
+proc glColor3i*(red, green, blue: TGLint){.dynlib: dllname, importc: "glColor3i".}
+proc glColor3iv*(v: PGLint){.dynlib: dllname, importc: "glColor3iv".}
+proc glColor3s*(red, green, blue: TGLshort){.dynlib: dllname, 
+    importc: "glColor3s".}
+proc glColor3sv*(v: PGLshort){.dynlib: dllname, importc: "glColor3sv".}
+proc glColor3ub*(red, green, blue: TGLubyte){.dynlib: dllname, 
+    importc: "glColor3ub".}
+proc glColor3ubv*(v: PGLubyte){.dynlib: dllname, importc: "glColor3ubv".}
+proc glColor3ui*(red, green, blue: TGLuint){.dynlib: dllname, 
+    importc: "glColor3ui".}
+proc glColor3uiv*(v: PGLuint){.dynlib: dllname, importc: "glColor3uiv".}
+proc glColor3us*(red, green, blue: TGLushort){.dynlib: dllname, 
+    importc: "glColor3us".}
+proc glColor3usv*(v: PGLushort){.dynlib: dllname, importc: "glColor3usv".}
+proc glColor4b*(red, green, blue, alpha: TGlbyte){.dynlib: dllname, 
+    importc: "glColor4b".}
+proc glColor4bv*(v: PGLbyte){.dynlib: dllname, importc: "glColor4bv".}
+proc glColor4d*(red, green, blue, alpha: TGLdouble){.dynlib: dllname, 
+    importc: "glColor4d".}
+proc glColor4dv*(v: PGLdouble){.dynlib: dllname, importc: "glColor4dv".}
+proc glColor4f*(red, green, blue, alpha: TGLfloat){.dynlib: dllname, 
+    importc: "glColor4f".}
+proc glColor4fv*(v: PGLfloat){.dynlib: dllname, importc: "glColor4fv".}
+proc glColor4i*(red, green, blue, alpha: TGLint){.dynlib: dllname, 
+    importc: "glColor4i".}
+proc glColor4iv*(v: PGLint){.dynlib: dllname, importc: "glColor4iv".}
+proc glColor4s*(red, green, blue, alpha: TGLshort){.dynlib: dllname, 
+    importc: "glColor4s".}
+proc glColor4sv*(v: PGLshort){.dynlib: dllname, importc: "glColor4sv".}
+proc glColor4ub*(red, green, blue, alpha: TGLubyte){.dynlib: dllname, 
+    importc: "glColor4ub".}
+proc glColor4ubv*(v: PGLubyte){.dynlib: dllname, importc: "glColor4ubv".}
+proc glColor4ui*(red, green, blue, alpha: TGLuint){.dynlib: dllname, 
+    importc: "glColor4ui".}
+proc glColor4uiv*(v: PGLuint){.dynlib: dllname, importc: "glColor4uiv".}
+proc glColor4us*(red, green, blue, alpha: TGLushort){.dynlib: dllname, 
+    importc: "glColor4us".}
+proc glColor4usv*(v: PGLushort){.dynlib: dllname, importc: "glColor4usv".}
+proc glColorMask*(red, green, blue, alpha: TGLboolean){.dynlib: dllname, 
+    importc: "glColorMask".}
+proc glColorMaterial*(face, mode: TGLenum){.dynlib: dllname, 
+    importc: "glColorMaterial".}
+proc glColorPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, 
+                     p: pointer){.dynlib: dllname, 
+                                        importc: "glColorPointer".}
+proc glCopyPixels*(x, y: TGLint, width, height: TGLsizei, atype: TGLenum){.
+    dynlib: dllname, importc: "glCopyPixels".}
+proc glCopyTexImage1D*(target: TGLenum, level: TGLint, internalFormat: TGLenum, 
+                       x, y: TGLint, width: TGLsizei, border: TGLint){.
+    dynlib: dllname, importc: "glCopyTexImage1D".}
+proc glCopyTexImage2D*(target: TGLenum, level: TGLint, internalFormat: TGLenum, 
+                       x, y: TGLint, width, height: TGLsizei, border: TGLint){.
+    dynlib: dllname, importc: "glCopyTexImage2D".}
+proc glCopyTexSubImage1D*(target: TGLenum, level, xoffset, x, y: TGLint, 
+                          width: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyTexSubImage1D".}
+proc glCopyTexSubImage2D*(target: TGLenum, 
+                          level, xoffset, yoffset, x, y: TGLint, 
+                          width, height: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyTexSubImage2D".}
+proc glCullFace*(mode: TGLenum){.dynlib: dllname, importc: "glCullFace".}
+proc glDeleteLists*(list: TGLuint, range: TGLsizei){.dynlib: dllname, 
+    importc: "glDeleteLists".}
+proc glDeleteTextures*(n: TGLsizei, textures: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteTextures".}
+proc glDepthFunc*(fun: TGLenum){.dynlib: dllname, importc: "glDepthFunc".}
+proc glDepthMask*(flag: TGLboolean){.dynlib: dllname, importc: "glDepthMask".}
+proc glDepthRange*(zNear, zFar: TGLclampd){.dynlib: dllname, 
+    importc: "glDepthRange".}
+proc glDisable*(cap: TGLenum){.dynlib: dllname, importc: "glDisable".}
+proc glDisableClientState*(aarray: TGLenum){.dynlib: dllname, 
+    importc: "glDisableClientState".}
+proc glDrawArrays*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawArrays".}
+proc glDrawBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glDrawBuffer".}
+proc glDrawElements*(mode: TGLenum, count: TGLsizei, atype: TGLenum, 
+                     indices: pointer){.dynlib: dllname, 
+                                        importc: "glDrawElements".}
+proc glDrawPixels*(width, height: TGLsizei, format, atype: TGLenum, 
+                   pixels: pointer){.dynlib: dllname, importc: "glDrawPixels".}
+proc glEdgeFlag*(flag: TGLboolean){.dynlib: dllname, importc: "glEdgeFlag".}
+proc glEdgeFlagPointer*(stride: TGLsizei, p: pointer){.dynlib: dllname, 
+    importc: "glEdgeFlagPointer".}
+proc glEdgeFlagv*(flag: PGLboolean){.dynlib: dllname, importc: "glEdgeFlagv".}
+proc glEnable*(cap: TGLenum){.dynlib: dllname, importc: "glEnable".}
+proc glEnableClientState*(aarray: TGLenum){.dynlib: dllname, 
+    importc: "glEnableClientState".}
+proc glEnd*(){.dynlib: dllname, importc: "glEnd".}
+proc glEndList*(){.dynlib: dllname, importc: "glEndList".}
+proc glEvalCoord1d*(u: TGLdouble){.dynlib: dllname, importc: "glEvalCoord1d".}
+proc glEvalCoord1dv*(u: PGLdouble){.dynlib: dllname, importc: "glEvalCoord1dv".}
+proc glEvalCoord1f*(u: TGLfloat){.dynlib: dllname, importc: "glEvalCoord1f".}
+proc glEvalCoord1fv*(u: PGLfloat){.dynlib: dllname, importc: "glEvalCoord1fv".}
+proc glEvalCoord2d*(u, v: TGLdouble){.dynlib: dllname, importc: "glEvalCoord2d".}
+proc glEvalCoord2dv*(u: PGLdouble){.dynlib: dllname, importc: "glEvalCoord2dv".}
+proc glEvalCoord2f*(u, v: TGLfloat){.dynlib: dllname, importc: "glEvalCoord2f".}
+proc glEvalCoord2fv*(u: PGLfloat){.dynlib: dllname, importc: "glEvalCoord2fv".}
+proc glEvalMesh1*(mode: TGLenum, i1, i2: TGLint){.dynlib: dllname, 
+    importc: "glEvalMesh1".}
+proc glEvalMesh2*(mode: TGLenum, i1, i2, j1, j2: TGLint){.dynlib: dllname, 
+    importc: "glEvalMesh2".}
+proc glEvalPoint1*(i: TGLint){.dynlib: dllname, importc: "glEvalPoint1".}
+proc glEvalPoint2*(i, j: TGLint){.dynlib: dllname, importc: "glEvalPoint2".}
+proc glFeedbackBuffer*(size: TGLsizei, atype: TGLenum, buffer: PGLfloat){.
+    dynlib: dllname, importc: "glFeedbackBuffer".}
+proc glFinish*(){.dynlib: dllname, importc: "glFinish".}
+proc glFlush*(){.dynlib: dllname, importc: "glFlush".}
+proc glFogf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glFogf".}
+proc glFogfv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glFogfv".}
+proc glFogi*(pname: TGLenum, param: TGLint){.dynlib: dllname, importc: "glFogi".}
+proc glFogiv*(pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glFogiv".}
+proc glFrontFace*(mode: TGLenum){.dynlib: dllname, importc: "glFrontFace".}
+proc glFrustum*(left, right, bottom, top, zNear, zFar: TGLdouble){.
+    dynlib: dllname, importc: "glFrustum".}
+proc glGenLists*(range: TGLsizei): TGLuint{.dynlib: dllname, 
+    importc: "glGenLists".}
+proc glGenTextures*(n: TGLsizei, textures: PGLuint){.dynlib: dllname, 
+    importc: "glGenTextures".}
+proc glGetBooleanv*(pname: TGLenum, params: PGLboolean){.dynlib: dllname, 
+    importc: "glGetBooleanv".}
+proc glGetClipPlane*(plane: TGLenum, equation: PGLdouble){.dynlib: dllname, 
+    importc: "glGetClipPlane".}
+proc glGetDoublev*(pname: TGLenum, params: PGLdouble){.dynlib: dllname, 
+    importc: "glGetDoublev".}
+proc glGetError*(): TGLenum{.dynlib: dllname, importc: "glGetError".}
+proc glGetFloatv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetFloatv".}
+proc glGetIntegerv*(pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glGetIntegerv".}
+proc glGetLightfv*(light, pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetLightfv".}
+proc glGetLightiv*(light, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glGetLightiv".}
+proc glGetMapdv*(target, query: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glGetMapdv".}
+proc glGetMapfv*(target, query: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glGetMapfv".}
+proc glGetMapiv*(target, query: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glGetMapiv".}
+proc glGetMaterialfv*(face, pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetMaterialfv".}
+proc glGetMaterialiv*(face, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glGetMaterialiv".}
+proc glGetPixelMapfv*(map: TGLenum, values: PGLfloat){.dynlib: dllname, 
+    importc: "glGetPixelMapfv".}
+proc glGetPixelMapuiv*(map: TGLenum, values: PGLuint){.dynlib: dllname, 
+    importc: "glGetPixelMapuiv".}
+proc glGetPixelMapusv*(map: TGLenum, values: PGLushort){.dynlib: dllname, 
+    importc: "glGetPixelMapusv".}
+proc glGetPointerv*(pname: TGLenum, params: pointer){.dynlib: dllname, 
+    importc: "glGetPointerv".}
+proc glGetPolygonStipple*(mask: PGLubyte){.dynlib: dllname, 
+    importc: "glGetPolygonStipple".}
+proc glGetString*(name: TGLenum): cstring{.dynlib: dllname, 
+    importc: "glGetString".}
+proc glGetTexEnvfv*(target, pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetTexEnvfv".}
+proc glGetTexEnviv*(target, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glGetTexEnviv".}
+proc glGetTexGendv*(coord, pname: TGLenum, params: PGLdouble){.dynlib: dllname, 
+    importc: "glGetTexGendv".}
+proc glGetTexGenfv*(coord, pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetTexGenfv".}
+proc glGetTexGeniv*(coord, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glGetTexGeniv".}
+proc glGetTexImage*(target: TGLenum, level: TGLint, format: TGLenum, 
+                    atype: TGLenum, pixels: pointer){.dynlib: dllname, 
+    importc: "glGetTexImage".}
+proc glGetTexLevelParameterfv*(target: TGLenum, level: TGLint, pname: TGLenum, 
+                               params: pointer){.dynlib: dllname, 
+    importc: "glGetTexLevelParameterfv".}
+proc glGetTexLevelParameteriv*(target: TGLenum, level: TGLint, pname: TGLenum, 
+                               params: PGLint){.dynlib: dllname, 
+    importc: "glGetTexLevelParameteriv".}
+proc glGetTexParameterfv*(target, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetTexParameterfv".}
+proc glGetTexParameteriv*(target, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetTexParameteriv".}
+proc glHint*(target, mode: TGLenum){.dynlib: dllname, importc: "glHint".}
+proc glIndexMask*(mask: TGLuint){.dynlib: dllname, importc: "glIndexMask".}
+proc glIndexPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){.
+    dynlib: dllname, importc: "glIndexPointer".}
+proc glIndexd*(c: TGLdouble){.dynlib: dllname, importc: "glIndexd".}
+proc glIndexdv*(c: PGLdouble){.dynlib: dllname, importc: "glIndexdv".}
+proc glIndexf*(c: TGLfloat){.dynlib: dllname, importc: "glIndexf".}
+proc glIndexfv*(c: PGLfloat){.dynlib: dllname, importc: "glIndexfv".}
+proc glIndexi*(c: TGLint){.dynlib: dllname, importc: "glIndexi".}
+proc glIndexiv*(c: PGLint){.dynlib: dllname, importc: "glIndexiv".}
+proc glIndexs*(c: TGLshort){.dynlib: dllname, importc: "glIndexs".}
+proc glIndexsv*(c: PGLshort){.dynlib: dllname, importc: "glIndexsv".}
+proc glIndexub*(c: TGLubyte){.dynlib: dllname, importc: "glIndexub".}
+proc glIndexubv*(c: PGLubyte){.dynlib: dllname, importc: "glIndexubv".}
+proc glInitNames*(){.dynlib: dllname, importc: "glInitNames".}
+proc glInterleavedArrays*(format: TGLenum, stride: TGLsizei, p: pointer){.
+    dynlib: dllname, importc: "glInterleavedArrays".}
+proc glIsEnabled*(cap: TGLenum): TGLboolean{.dynlib: dllname, 
+    importc: "glIsEnabled".}
+proc glIsList*(list: TGLuint): TGLboolean{.dynlib: dllname, importc: "glIsList".}
+proc glIsTexture*(texture: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsTexture".}
+proc glLightModelf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glLightModelf".}
+proc glLightModelfv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glLightModelfv".}
+proc glLightModeli*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glLightModeli".}
+proc glLightModeliv*(pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glLightModeliv".}
+proc glLightf*(light, pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glLightf".}
+proc glLightfv*(light, pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glLightfv".}
+proc glLighti*(light, pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glLighti".}
+proc glLightiv*(light, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glLightiv".}
+proc glLineStipple*(factor: TGLint, pattern: TGLushort){.dynlib: dllname, 
+    importc: "glLineStipple".}
+proc glLineWidth*(width: TGLfloat){.dynlib: dllname, importc: "glLineWidth".}
+proc glListBase*(base: TGLuint){.dynlib: dllname, importc: "glListBase".}
+proc glLoadIdentity*(){.dynlib: dllname, importc: "glLoadIdentity".}
+proc glLoadMatrixd*(m: PGLdouble){.dynlib: dllname, importc: "glLoadMatrixd".}
+proc glLoadMatrixf*(m: PGLfloat){.dynlib: dllname, importc: "glLoadMatrixf".}
+proc glLoadName*(name: TGLuint){.dynlib: dllname, importc: "glLoadName".}
+proc glLogicOp*(opcode: TGLenum){.dynlib: dllname, importc: "glLogicOp".}
+proc glMap1d*(target: TGLenum, u1, u2: TGLdouble, stride, order: TGLint, 
+              points: PGLdouble){.dynlib: dllname, importc: "glMap1d".}
+proc glMap1f*(target: TGLenum, u1, u2: TGLfloat, stride, order: TGLint, 
+              points: PGLfloat){.dynlib: dllname, importc: "glMap1f".}
+proc glMap2d*(target: TGLenum, u1, u2: TGLdouble, ustride, uorder: TGLint, 
+              v1, v2: TGLdouble, vstride, vorder: TGLint, points: PGLdouble){.
+    dynlib: dllname, importc: "glMap2d".}
+proc glMap2f*(target: TGLenum, u1, u2: TGLfloat, ustride, uorder: TGLint, 
+              v1, v2: TGLfloat, vstride, vorder: TGLint, points: PGLfloat){.
+    dynlib: dllname, importc: "glMap2f".}
+proc glMapGrid1d*(un: TGLint, u1, u2: TGLdouble){.dynlib: dllname, 
+    importc: "glMapGrid1d".}
+proc glMapGrid1f*(un: TGLint, u1, u2: TGLfloat){.dynlib: dllname, 
+    importc: "glMapGrid1f".}
+proc glMapGrid2d*(un: TGLint, u1, u2: TGLdouble, vn: TGLint, v1, v2: TGLdouble){.
+    dynlib: dllname, importc: "glMapGrid2d".}
+proc glMapGrid2f*(un: TGLint, u1, u2: TGLfloat, vn: TGLint, v1, v2: TGLfloat){.
+    dynlib: dllname, importc: "glMapGrid2f".}
+proc glMaterialf*(face, pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glMaterialf".}
+proc glMaterialfv*(face, pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glMaterialfv".}
+proc glMateriali*(face, pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glMateriali".}
+proc glMaterialiv*(face, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glMaterialiv".}
+proc glMatrixMode*(mode: TGLenum){.dynlib: dllname, importc: "glMatrixMode".}
+proc glMultMatrixd*(m: PGLdouble){.dynlib: dllname, importc: "glMultMatrixd".}
+proc glMultMatrixf*(m: PGLfloat){.dynlib: dllname, importc: "glMultMatrixf".}
+proc glNewList*(list: TGLuint, mode: TGLenum){.dynlib: dllname, 
+    importc: "glNewList".}
+proc glNormal3b*(nx, ny, nz: TGlbyte){.dynlib: dllname, importc: "glNormal3b".}
+proc glNormal3bv*(v: PGLbyte){.dynlib: dllname, importc: "glNormal3bv".}
+proc glNormal3d*(nx, ny, nz: TGLdouble){.dynlib: dllname, importc: "glNormal3d".}
+proc glNormal3dv*(v: PGLdouble){.dynlib: dllname, importc: "glNormal3dv".}
+proc glNormal3f*(nx, ny, nz: TGLfloat){.dynlib: dllname, importc: "glNormal3f".}
+proc glNormal3fv*(v: PGLfloat){.dynlib: dllname, importc: "glNormal3fv".}
+proc glNormal3i*(nx, ny, nz: TGLint){.dynlib: dllname, importc: "glNormal3i".}
+proc glNormal3iv*(v: PGLint){.dynlib: dllname, importc: "glNormal3iv".}
+proc glNormal3s*(nx, ny, nz: TGLshort){.dynlib: dllname, importc: "glNormal3s".}
+proc glNormal3sv*(v: PGLshort){.dynlib: dllname, importc: "glNormal3sv".}
+proc glNormalPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){.
+    dynlib: dllname, importc: "glNormalPointer".}
+proc glOrtho*(left, right, bottom, top, zNear, zFar: TGLdouble){.
+    dynlib: dllname, importc: "glOrtho".}
+proc glPassThrough*(token: TGLfloat){.dynlib: dllname, importc: "glPassThrough".}
+proc glPixelMapfv*(map: TGLenum, mapsize: TGLsizei, values: PGLfloat){.
+    dynlib: dllname, importc: "glPixelMapfv".}
+proc glPixelMapuiv*(map: TGLenum, mapsize: TGLsizei, values: PGLuint){.
+    dynlib: dllname, importc: "glPixelMapuiv".}
+proc glPixelMapusv*(map: TGLenum, mapsize: TGLsizei, values: PGLushort){.
+    dynlib: dllname, importc: "glPixelMapusv".}
+proc glPixelStoref*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glPixelStoref".}
+proc glPixelStorei*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glPixelStorei".}
+proc glPixelTransferf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glPixelTransferf".}
+proc glPixelTransferi*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glPixelTransferi".}
+proc glPixelZoom*(xfactor, yfactor: TGLfloat){.dynlib: dllname, 
+    importc: "glPixelZoom".}
+proc glPointSize*(size: TGLfloat){.dynlib: dllname, importc: "glPointSize".}
+proc glPolygonMode*(face, mode: TGLenum){.dynlib: dllname, 
+    importc: "glPolygonMode".}
+proc glPolygonOffset*(factor, units: TGLfloat){.dynlib: dllname, 
+    importc: "glPolygonOffset".}
+proc glPolygonStipple*(mask: PGLubyte){.dynlib: dllname, 
+                                        importc: "glPolygonStipple".}
+proc glPopAttrib*(){.dynlib: dllname, importc: "glPopAttrib".}
+proc glPopClientAttrib*(){.dynlib: dllname, importc: "glPopClientAttrib".}
+proc glPopMatrix*(){.dynlib: dllname, importc: "glPopMatrix".}
+proc glPopName*(){.dynlib: dllname, importc: "glPopName".}
+proc glPrioritizeTextures*(n: TGLsizei, textures: PGLuint, priorities: PGLclampf){.
+    dynlib: dllname, importc: "glPrioritizeTextures".}
+proc glPushAttrib*(mask: TGLbitfield){.dynlib: dllname, importc: "glPushAttrib".}
+proc glPushClientAttrib*(mask: TGLbitfield){.dynlib: dllname, 
+    importc: "glPushClientAttrib".}
+proc glPushMatrix*(){.dynlib: dllname, importc: "glPushMatrix".}
+proc glPushName*(name: TGLuint){.dynlib: dllname, importc: "glPushName".}
+proc glRasterPos2d*(x, y: TGLdouble){.dynlib: dllname, importc: "glRasterPos2d".}
+proc glRasterPos2dv*(v: PGLdouble){.dynlib: dllname, importc: "glRasterPos2dv".}
+proc glRasterPos2f*(x, y: TGLfloat){.dynlib: dllname, importc: "glRasterPos2f".}
+proc glRasterPos2fv*(v: PGLfloat){.dynlib: dllname, importc: "glRasterPos2fv".}
+proc glRasterPos2i*(x, y: TGLint){.dynlib: dllname, importc: "glRasterPos2i".}
+proc glRasterPos2iv*(v: PGLint){.dynlib: dllname, importc: "glRasterPos2iv".}
+proc glRasterPos2s*(x, y: TGLshort){.dynlib: dllname, importc: "glRasterPos2s".}
+proc glRasterPos2sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos2sv".}
+proc glRasterPos3d*(x, y, z: TGLdouble){.dynlib: dllname, 
+    importc: "glRasterPos3d".}
+proc glRasterPos3dv*(v: PGLdouble){.dynlib: dllname, importc: "glRasterPos3dv".}
+proc glRasterPos3f*(x, y, z: TGLfloat){.dynlib: dllname, 
+                                        importc: "glRasterPos3f".}
+proc glRasterPos3fv*(v: PGLfloat){.dynlib: dllname, importc: "glRasterPos3fv".}
+proc glRasterPos3i*(x, y, z: TGLint){.dynlib: dllname, importc: "glRasterPos3i".}
+proc glRasterPos3iv*(v: PGLint){.dynlib: dllname, importc: "glRasterPos3iv".}
+proc glRasterPos3s*(x, y, z: TGLshort){.dynlib: dllname, 
+                                        importc: "glRasterPos3s".}
+proc glRasterPos3sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos3sv".}
+proc glRasterPos4d*(x, y, z, w: TGLdouble){.dynlib: dllname, 
+    importc: "glRasterPos4d".}
+proc glRasterPos4dv*(v: PGLdouble){.dynlib: dllname, importc: "glRasterPos4dv".}
+proc glRasterPos4f*(x, y, z, w: TGLfloat){.dynlib: dllname, 
+    importc: "glRasterPos4f".}
+proc glRasterPos4fv*(v: PGLfloat){.dynlib: dllname, importc: "glRasterPos4fv".}
+proc glRasterPos4i*(x, y, z, w: TGLint){.dynlib: dllname, 
+    importc: "glRasterPos4i".}
+proc glRasterPos4iv*(v: PGLint){.dynlib: dllname, importc: "glRasterPos4iv".}
+proc glRasterPos4s*(x, y, z, w: TGLshort){.dynlib: dllname, 
+    importc: "glRasterPos4s".}
+proc glRasterPos4sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos4sv".}
+proc glReadBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glReadBuffer".}
+proc glReadPixels*(x, y: TGLint, width, height: TGLsizei, 
+                   format, atype: TGLenum, pixels: pointer){.dynlib: dllname, 
+    importc: "glReadPixels".}
+proc glRectd*(x1, y1, x2, y2: TGLdouble){.dynlib: dllname, importc: "glRectd".}
+proc glRectdv*(v1: PGLdouble, v2: PGLdouble){.dynlib: dllname, 
+    importc: "glRectdv".}
+proc glRectf*(x1, y1, x2, y2: TGLfloat){.dynlib: dllname, importc: "glRectf".}
+proc glRectfv*(v1: PGLfloat, v2: PGLfloat){.dynlib: dllname, importc: "glRectfv".}
+proc glRecti*(x1, y1, x2, y2: TGLint){.dynlib: dllname, importc: "glRecti".}
+proc glRectiv*(v1: PGLint, v2: PGLint){.dynlib: dllname, importc: "glRectiv".}
+proc glRects*(x1, y1, x2, y2: TGLshort){.dynlib: dllname, importc: "glRects".}
+proc glRectsv*(v1: PGLshort, v2: PGLshort){.dynlib: dllname, importc: "glRectsv".}
+proc glRenderMode*(mode: TGLint): TGLint{.dynlib: dllname, 
+    importc: "glRenderMode".}
+proc glRotated*(angle, x, y, z: TGLdouble){.dynlib: dllname, 
+    importc: "glRotated".}
+proc glRotatef*(angle, x, y, z: TGLfloat){.dynlib: dllname, importc: "glRotatef".}
+proc glScaled*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glScaled".}
+proc glScalef*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glScalef".}
+proc glScissor*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname, 
+    importc: "glScissor".}
+proc glSelectBuffer*(size: TGLsizei, buffer: PGLuint){.dynlib: dllname, 
+    importc: "glSelectBuffer".}
+proc glShadeModel*(mode: TGLenum){.dynlib: dllname, importc: "glShadeModel".}
+proc glStencilFunc*(fun: TGLenum, theref: TGLint, mask: TGLuint){.
+    dynlib: dllname, importc: "glStencilFunc".}
+proc glStencilMask*(mask: TGLuint){.dynlib: dllname, importc: "glStencilMask".}
+proc glStencilOp*(fail, zfail, zpass: TGLenum){.dynlib: dllname, 
+    importc: "glStencilOp".}
+proc glTexCoord1d*(s: TGLdouble){.dynlib: dllname, importc: "glTexCoord1d".}
+proc glTexCoord1dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord1dv".}
+proc glTexCoord1f*(s: TGLfloat){.dynlib: dllname, importc: "glTexCoord1f".}
+proc glTexCoord1fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord1fv".}
+proc glTexCoord1i*(s: TGLint){.dynlib: dllname, importc: "glTexCoord1i".}
+proc glTexCoord1iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord1iv".}
+proc glTexCoord1s*(s: TGLshort){.dynlib: dllname, importc: "glTexCoord1s".}
+proc glTexCoord1sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord1sv".}
+proc glTexCoord2d*(s, t: TGLdouble){.dynlib: dllname, importc: "glTexCoord2d".}
+proc glTexCoord2dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord2dv".}
+proc glTexCoord2f*(s, t: TGLfloat){.dynlib: dllname, importc: "glTexCoord2f".}
+proc glTexCoord2fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord2fv".}
+proc glTexCoord2i*(s, t: TGLint){.dynlib: dllname, importc: "glTexCoord2i".}
+proc glTexCoord2iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord2iv".}
+proc glTexCoord2s*(s, t: TGLshort){.dynlib: dllname, importc: "glTexCoord2s".}
+proc glTexCoord2sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord2sv".}
+proc glTexCoord3d*(s, t, r: TGLdouble){.dynlib: dllname, importc: "glTexCoord3d".}
+proc glTexCoord3dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord3dv".}
+proc glTexCoord3f*(s, t, r: TGLfloat){.dynlib: dllname, importc: "glTexCoord3f".}
+proc glTexCoord3fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord3fv".}
+proc glTexCoord3i*(s, t, r: TGLint){.dynlib: dllname, importc: "glTexCoord3i".}
+proc glTexCoord3iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord3iv".}
+proc glTexCoord3s*(s, t, r: TGLshort){.dynlib: dllname, importc: "glTexCoord3s".}
+proc glTexCoord3sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord3sv".}
+proc glTexCoord4d*(s, t, r, q: TGLdouble){.dynlib: dllname, 
+    importc: "glTexCoord4d".}
+proc glTexCoord4dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord4dv".}
+proc glTexCoord4f*(s, t, r, q: TGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord4f".}
+proc glTexCoord4fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord4fv".}
+proc glTexCoord4i*(s, t, r, q: TGLint){.dynlib: dllname, importc: "glTexCoord4i".}
+proc glTexCoord4iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord4iv".}
+proc glTexCoord4s*(s, t, r, q: TGLshort){.dynlib: dllname, 
+    importc: "glTexCoord4s".}
+proc glTexCoord4sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord4sv".}
+proc glTexCoordPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, 
+                        p: pointer){.dynlib: dllname, 
+    importc: "glTexCoordPointer".}
+proc glTexEnvf*(target: TGLenum, pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glTexEnvf".}
+proc glTexEnvfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glTexEnvfv".}
+proc glTexEnvi*(target: TGLenum, pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glTexEnvi".}
+proc glTexEnviv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glTexEnviv".}
+proc glTexGend*(coord: TGLenum, pname: TGLenum, param: TGLdouble){.
+    dynlib: dllname, importc: "glTexGend".}
+proc glTexGendv*(coord: TGLenum, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glTexGendv".}
+proc glTexGenf*(coord: TGLenum, pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glTexGenf".}
+proc glTexGenfv*(coord: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glTexGenfv".}
+proc glTexGeni*(coord: TGLenum, pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glTexGeni".}
+proc glTexGeniv*(coord: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glTexGeniv".}
+proc glTexImage1D*(target: TGLenum, level, internalformat: TGLint, 
+                   width: TGLsizei, border: TGLint, format, atype: TGLenum, 
+                   pixels: pointer){.dynlib: dllname, importc: "glTexImage1D".}
+proc glTexImage2D*(target: TGLenum, level, internalformat: TGLint, 
+                   width, height: TGLsizei, border: TGLint, 
+                   format, atype: TGLenum, pixels: pointer){.dynlib: dllname, 
+    importc: "glTexImage2D".}
+proc glTexParameterf*(target: TGLenum, pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glTexParameterf".}
+proc glTexParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glTexParameterfv".}
+proc glTexParameteri*(target: TGLenum, pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glTexParameteri".}
+proc glTexParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glTexParameteriv".}
+proc glTexSubImage1D*(target: TGLenum, level, xoffset: TGLint, width: TGLsizei, 
+                      format, atype: TGLenum, pixels: pointer){.dynlib: dllname, 
+    importc: "glTexSubImage1D".}
+proc glTexSubImage2D*(target: TGLenum, level, xoffset, yoffset: TGLint, 
+                      width, height: TGLsizei, format, atype: TGLenum, 
+                      pixels: pointer){.dynlib: dllname, 
+                                        importc: "glTexSubImage2D".}
+proc glTranslated*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glTranslated".}
+proc glTranslatef*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glTranslatef".}
+proc glVertex2d*(x, y: TGLdouble){.dynlib: dllname, importc: "glVertex2d".}
+proc glVertex2dv*(v: PGLdouble){.dynlib: dllname, importc: "glVertex2dv".}
+proc glVertex2f*(x, y: TGLfloat){.dynlib: dllname, importc: "glVertex2f".}
+proc glVertex2fv*(v: PGLfloat){.dynlib: dllname, importc: "glVertex2fv".}
+proc glVertex2i*(x, y: TGLint){.dynlib: dllname, importc: "glVertex2i".}
+proc glVertex2iv*(v: PGLint){.dynlib: dllname, importc: "glVertex2iv".}
+proc glVertex2s*(x, y: TGLshort){.dynlib: dllname, importc: "glVertex2s".}
+proc glVertex2sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex2sv".}
+proc glVertex3d*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glVertex3d".}
+proc glVertex3dv*(v: PGLdouble){.dynlib: dllname, importc: "glVertex3dv".}
+proc glVertex3f*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glVertex3f".}
+proc glVertex3fv*(v: PGLfloat){.dynlib: dllname, importc: "glVertex3fv".}
+proc glVertex3i*(x, y, z: TGLint){.dynlib: dllname, importc: "glVertex3i".}
+proc glVertex3iv*(v: PGLint){.dynlib: dllname, importc: "glVertex3iv".}
+proc glVertex3s*(x, y, z: TGLshort){.dynlib: dllname, importc: "glVertex3s".}
+proc glVertex3sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex3sv".}
+proc glVertex4d*(x, y, z, w: TGLdouble){.dynlib: dllname, importc: "glVertex4d".}
+proc glVertex4dv*(v: PGLdouble){.dynlib: dllname, importc: "glVertex4dv".}
+proc glVertex4f*(x, y, z, w: TGLfloat){.dynlib: dllname, importc: "glVertex4f".}
+proc glVertex4fv*(v: PGLfloat){.dynlib: dllname, importc: "glVertex4fv".}
+proc glVertex4i*(x, y, z, w: TGLint){.dynlib: dllname, importc: "glVertex4i".}
+proc glVertex4iv*(v: PGLint){.dynlib: dllname, importc: "glVertex4iv".}
+proc glVertex4s*(x, y, z, w: TGLshort){.dynlib: dllname, importc: "glVertex4s".}
+proc glVertex4sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex4sv".}
+proc glVertexPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, 
+                      p: pointer){.dynlib: dllname, 
+    importc: "glVertexPointer".}
+proc glViewport*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname, 
+    importc: "glViewport".}
+type 
+  PFN_GLARRAY_ELEMENT_EXTPROC* = proc (i: TGLint)
+  PFN_GLDRAW_ARRAYS_EXTPROC* = proc (mode: TGLenum, first: TGLint, 
+                                     count: TGLsizei)
+  PFN_GLVERTEX_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, 
+                                        stride, count: TGLsizei, 
+                                        p: pointer)
+  PFN_GLNORMAL_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei, 
+                                        p: pointer)
+  PFN_GLCOLOR_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, 
+                                       stride, count: TGLsizei, p: pointer)
+  PFN_GLINDEX_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei, 
+                                       p: pointer)
+  PFN_GLTEXCOORD_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, 
+      stride, count: TGLsizei, p: pointer)
+  PFN_GLEDGEFLAG_POINTER_EXTPROC* = proc (stride, count: TGLsizei, 
+      pointer: PGLboolean)
+  PFN_GLGET_POINTER_VEXT_PROC* = proc (pname: TGLenum, params: pointer)
+  PFN_GLARRAY_ELEMENT_ARRAY_EXTPROC* = proc (mode: TGLenum, count: TGLsizei, 
+      pi: pointer)            # WIN_swap_hint
+  PFN_GLADDSWAPHINT_RECT_WINPROC* = proc (x, y: TGLint, width, height: TGLsizei)
+  PFN_GLCOLOR_TABLE_EXTPROC* = proc (target, internalFormat: TGLenum, 
+                                     width: TGLsizei, format, atype: TGLenum, 
+                                     data: pointer)
+  PFN_GLCOLOR_SUBTABLE_EXTPROC* = proc (target: TGLenum, start, count: TGLsizei, 
+                                        format, atype: TGLenum, data: pointer)
+  PFN_GLGETCOLOR_TABLE_EXTPROC* = proc (target, format, atype: TGLenum, 
+                                        data: pointer)
+  PFN_GLGETCOLOR_TABLE_PARAMETER_IVEXTPROC* = proc (target, pname: TGLenum, 
+      params: PGLint)
+  PFN_GLGETCOLOR_TABLE_PARAMETER_FVEXTPROC* = proc (target, pname: TGLenum, 
+      params: PGLfloat)
+
+{.pop.}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/glext.nim b/tests/manyloc/keineschweine/lib/glext.nim
new file mode 100644
index 000000000..32871df0e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glext.nim
@@ -0,0 +1,4673 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#
+#
+
+#*************************************************
+# *        OpenGL extension loading library        *
+# * Generated by MetaGLext, written by Tom Nuydens *
+# *  (tom@delphi3d.net -- http://www.delphi3d.net  *
+# *************************************************
+#*** Generated on 10/11/2002
+
+when defined(windows): 
+  {.push, callconv: stdcall.}
+else: 
+  {.push, callconv: cdecl.}
+import 
+  gl
+
+type 
+  GLcharARB* = Char
+  TGLcharARB* = GLcharARB
+  PGLcharARB* = ptr GLcharARB
+  GLhandleARB* = int
+  TGLhandleARB* = GLhandleARB
+  PGLhandleARB* = ptr GLhandleARB
+  GLintptr* = int
+  TGLintptr* = GLintptr
+  PGLintptr* = ptr GLintptr
+  GLsizeiptr* = int
+  TGLsizeiptr* = GLsizeiptr
+  PGLsizeiptr* = ptr GLsizeiptr
+  GLchar* = Char
+  TGLchar* = GLchar
+  PGLchar* = cstring          #***** GL_version_1_2 *****//
+
+const 
+  GL_UNSIGNED_BYTE_3_3_2* = 0x00008032
+  GL_UNSIGNED_SHORT_4_4_4_4* = 0x00008033
+  GL_UNSIGNED_SHORT_5_5_5_1* = 0x00008034
+  GL_UNSIGNED_INT_8_8_8_8* = 0x00008035
+  GL_UNSIGNED_INT_10_10_10_2* = 0x00008036
+  GL_RESCALE_NORMAL* = 0x0000803A
+  GL_UNSIGNED_BYTE_2_3_3_REV* = 0x00008362
+  GL_UNSIGNED_SHORT_5_6_5* = 0x00008363
+  GL_UNSIGNED_SHORT_5_6_5_REV* = 0x00008364
+  GL_UNSIGNED_SHORT_4_4_4_4_REV* = 0x00008365
+  GL_UNSIGNED_SHORT_1_5_5_5_REV* = 0x00008366
+  GL_UNSIGNED_INT_8_8_8_8_REV* = 0x00008367
+  GL_UNSIGNED_INT_2_10_10_10_REV* = 0x00008368
+  GL_BGR* = 0x000080E0
+  GL_BGRA* = 0x000080E1
+  GL_MAX_ELEMENTS_VERTICES* = 0x000080E8
+  GL_MAX_ELEMENTS_INDICES* = 0x000080E9
+  GL_CLAMP_TO_EDGE* = 0x0000812F
+  GL_TEXTURE_MIN_LOD* = 0x0000813A
+  GL_TEXTURE_MAX_LOD* = 0x0000813B
+  GL_TEXTURE_BASE_LEVEL* = 0x0000813C
+  GL_TEXTURE_MAX_LEVEL* = 0x0000813D
+  GL_LIGHT_MODEL_COLOR_CONTROL* = 0x000081F8
+  GL_SINGLE_COLOR* = 0x000081F9
+  GL_SEPARATE_SPECULAR_COLOR* = 0x000081FA
+  GL_SMOOTH_POINT_SIZE_RANGE* = 0x00000B12
+  GL_SMOOTH_POINT_SIZE_GRANULARITY* = 0x00000B13
+  GL_SMOOTH_LINE_WIDTH_RANGE* = 0x00000B22
+  GL_SMOOTH_LINE_WIDTH_GRANULARITY* = 0x00000B23
+  GL_ALIASED_POINT_SIZE_RANGE* = 0x0000846D
+  GL_ALIASED_LINE_WIDTH_RANGE* = 0x0000846E
+  GL_PACK_SKIP_IMAGES* = 0x0000806B
+  GL_PACK_IMAGE_HEIGHT* = 0x0000806C
+  GL_UNPACK_SKIP_IMAGES* = 0x0000806D
+  GL_UNPACK_IMAGE_HEIGHT* = 0x0000806E
+  GL_TEXTURE_3D* = 0x0000806F
+  GL_PROXY_TEXTURE_3D* = 0x00008070
+  GL_TEXTURE_DEPTH* = 0x00008071
+  GL_TEXTURE_WRAP_R* = 0x00008072
+  GL_MAX_3D_TEXTURE_SIZE* = 0x00008073
+
+proc glBlendColor*(red: TGLclampf, green: TGLclampf, blue: TGLclampf, 
+                   alpha: TGLclampf){.dynlib: dllname, importc: "glBlendColor".}
+proc glBlendEquation*(mode: TGLenum){.dynlib: dllname, 
+                                      importc: "glBlendEquation".}
+proc glDrawRangeElements*(mode: TGLenum, start: TGLuint, theend: TGLuint, 
+                          count: TGLsizei, thetype: TGLenum, indices: PGLvoid){.
+    dynlib: dllname, importc: "glDrawRangeElements".}
+proc glColorTable*(target: TGLenum, internalformat: TGLenum, width: TGLsizei, 
+                   format: TGLenum, thetype: TGLenum, table: PGLvoid){.
+    dynlib: dllname, importc: "glColorTable".}
+proc glColorTableParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glColorTableParameterfv".}
+proc glColorTableParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glColorTableParameteriv".}
+proc glCopyColorTable*(target: TGLenum, internalformat: TGLenum, x: TGLint, 
+                       y: TGLint, width: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyColorTable".}
+proc glGetColorTable*(target: TGLenum, format: TGLenum, thetype: TGLenum, 
+                      table: PGLvoid){.dynlib: dllname, 
+                                       importc: "glGetColorTable".}
+proc glGetColorTableParameterfv*(target: TGLenum, pname: TGLenum, 
+                                 params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetColorTableParameterfv".}
+proc glGetColorTableParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetColorTableParameteriv".}
+proc glColorSubTable*(target: TGLenum, start: TGLsizei, count: TGLsizei, 
+                      format: TGLenum, thetype: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glColorSubTable".}
+proc glCopyColorSubTable*(target: TGLenum, start: TGLsizei, x: TGLint, 
+                          y: TGLint, width: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyColorSubTable".}
+proc glConvolutionFilter1D*(target: TGLenum, internalformat: TGLenum, 
+                            width: TGLsizei, format: TGLenum, thetype: TGLenum, 
+                            image: PGLvoid){.dynlib: dllname, 
+    importc: "glConvolutionFilter1D".}
+proc glConvolutionFilter2D*(target: TGLenum, internalformat: TGLenum, 
+                            width: TGLsizei, height: TGLsizei, format: TGLenum, 
+                            thetype: TGLenum, image: PGLvoid){.dynlib: dllname, 
+    importc: "glConvolutionFilter2D".}
+proc glConvolutionParameterf*(target: TGLenum, pname: TGLenum, params: TGLfloat){.
+    dynlib: dllname, importc: "glConvolutionParameterf".}
+proc glConvolutionParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glConvolutionParameterfv".}
+proc glConvolutionParameteri*(target: TGLenum, pname: TGLenum, params: TGLint){.
+    dynlib: dllname, importc: "glConvolutionParameteri".}
+proc glConvolutionParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glConvolutionParameteriv".}
+proc glCopyConvolutionFilter1D*(target: TGLenum, internalformat: TGLenum, 
+                                x: TGLint, y: TGLint, width: TGLsizei){.
+    dynlib: dllname, importc: "glCopyConvolutionFilter1D".}
+proc glCopyConvolutionFilter2D*(target: TGLenum, internalformat: TGLenum, 
+                                x: TGLint, y: TGLint, width: TGLsizei, 
+                                height: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyConvolutionFilter2D".}
+proc glGetConvolutionFilter*(target: TGLenum, format: TGLenum, thetype: TGLenum, 
+                             image: PGLvoid){.dynlib: dllname, 
+    importc: "glGetConvolutionFilter".}
+proc glGetConvolutionParameterfv*(target: TGLenum, pname: TGLenum, 
+                                  params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetConvolutionParameterfv".}
+proc glGetConvolutionParameteriv*(target: TGLenum, pname: TGLenum, 
+                                  params: PGLint){.dynlib: dllname, 
+    importc: "glGetConvolutionParameteriv".}
+proc glGetSeparableFilter*(target: TGLenum, format: TGLenum, thetype: TGLenum, 
+                           row: PGLvoid, column: PGLvoid, span: PGLvoid){.
+    dynlib: dllname, importc: "glGetSeparableFilter".}
+proc glSeparableFilter2D*(target: TGLenum, internalformat: TGLenum, 
+                          width: TGLsizei, height: TGLsizei, format: TGLenum, 
+                          thetype: TGLenum, row: PGLvoid, column: PGLvoid){.
+    dynlib: dllname, importc: "glSeparableFilter2D".}
+proc glGetHistogram*(target: TGLenum, reset: TGLboolean, format: TGLenum, 
+                     thetype: TGLenum, values: PGLvoid){.dynlib: dllname, 
+    importc: "glGetHistogram".}
+proc glGetHistogramParameterfv*(target: TGLenum, pname: TGLenum, 
+                                params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetHistogramParameterfv".}
+proc glGetHistogramParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetHistogramParameteriv".}
+proc glGetMinmax*(target: TGLenum, reset: TGLboolean, format: TGLenum, 
+                  thetype: TGLenum, values: PGLvoid){.dynlib: dllname, 
+    importc: "glGetMinmax".}
+proc glGetMinmaxParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetMinmaxParameterfv".}
+proc glGetMinmaxParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMinmaxParameteriv".}
+proc glHistogram*(target: TGLenum, width: TGLsizei, internalformat: TGLenum, 
+                  sink: TGLboolean){.dynlib: dllname, importc: "glHistogram".}
+proc glMinmax*(target: TGLenum, internalformat: TGLenum, sink: TGLboolean){.
+    dynlib: dllname, importc: "glMinmax".}
+proc glResetHistogram*(target: TGLenum){.dynlib: dllname, 
+    importc: "glResetHistogram".}
+proc glResetMinmax*(target: TGLenum){.dynlib: dllname, importc: "glResetMinmax".}
+proc glTexImage3D*(target: TGLenum, level: TGLint, internalformat: TGLint, 
+                   width: TGLsizei, height: TGLsizei, depth: TGLsizei, 
+                   border: TGLint, format: TGLenum, thetype: TGLenum, 
+                   pixels: PGLvoid){.dynlib: dllname, importc: "glTexImage3D".}
+proc glTexSubImage3D*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                      yoffset: TGLint, zoffset: TGLint, width: TGLsizei, 
+                      height: TGLsizei, depth: TGLsizei, format: TGLenum, 
+                      thetype: TGLenum, pixels: PGLvoid){.dynlib: dllname, 
+    importc: "glTexSubImage3D".}
+proc glCopyTexSubImage3D*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                          yoffset: TGLint, zoffset: TGLint, x: TGLint, 
+                          y: TGLint, width: TGLsizei, height: TGLsizei){.
+    dynlib: dllname, importc: "glCopyTexSubImage3D".}
+proc glActiveTextureARB*(texture: TGLenum){.dynlib: dllname, 
+    importc: "glActiveTextureARB".}
+proc glClientActiveTextureARB*(texture: TGLenum){.dynlib: dllname, 
+    importc: "glClientActiveTextureARB".}
+proc glMultiTexCoord1dARB*(target: TGLenum, s: TGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord1dARB".}
+proc glMultiTexCoord1dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord1dvARB".}
+proc glMultiTexCoord1fARB*(target: TGLenum, s: TGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord1fARB".}
+proc glMultiTexCoord1fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord1fvARB".}
+proc glMultiTexCoord1iARB*(target: TGLenum, s: TGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord1iARB".}
+proc glMultiTexCoord1ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord1ivARB".}
+proc glMultiTexCoord1sARB*(target: TGLenum, s: TGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord1sARB".}
+proc glMultiTexCoord1svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord1svARB".}
+proc glMultiTexCoord2dARB*(target: TGLenum, s: TGLdouble, t: TGLdouble){.
+    dynlib: dllname, importc: "glMultiTexCoord2dARB".}
+proc glMultiTexCoord2dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord2dvARB".}
+proc glMultiTexCoord2fARB*(target: TGLenum, s: TGLfloat, t: TGLfloat){.
+    dynlib: dllname, importc: "glMultiTexCoord2fARB".}
+proc glMultiTexCoord2fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord2fvARB".}
+proc glMultiTexCoord2iARB*(target: TGLenum, s: TGLint, t: TGLint){.
+    dynlib: dllname, importc: "glMultiTexCoord2iARB".}
+proc glMultiTexCoord2ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord2ivARB".}
+proc glMultiTexCoord2sARB*(target: TGLenum, s: TGLshort, t: TGLshort){.
+    dynlib: dllname, importc: "glMultiTexCoord2sARB".}
+proc glMultiTexCoord2svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord2svARB".}
+proc glMultiTexCoord3dARB*(target: TGLenum, s: TGLdouble, t: TGLdouble, 
+                           r: TGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord3dARB".}
+proc glMultiTexCoord3dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord3dvARB".}
+proc glMultiTexCoord3fARB*(target: TGLenum, s: TGLfloat, t: TGLfloat, 
+                           r: TGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord3fARB".}
+proc glMultiTexCoord3fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord3fvARB".}
+proc glMultiTexCoord3iARB*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint){.
+    dynlib: dllname, importc: "glMultiTexCoord3iARB".}
+proc glMultiTexCoord3ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord3ivARB".}
+proc glMultiTexCoord3sARB*(target: TGLenum, s: TGLshort, t: TGLshort, 
+                           r: TGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord3sARB".}
+proc glMultiTexCoord3svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord3svARB".}
+proc glMultiTexCoord4dARB*(target: TGLenum, s: TGLdouble, t: TGLdouble, 
+                           r: TGLdouble, q: TGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord4dARB".}
+proc glMultiTexCoord4dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord4dvARB".}
+proc glMultiTexCoord4fARB*(target: TGLenum, s: TGLfloat, t: TGLfloat, 
+                           r: TGLfloat, q: TGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord4fARB".}
+proc glMultiTexCoord4fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord4fvARB".}
+proc glMultiTexCoord4iARB*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint, 
+                           q: TGLint){.dynlib: dllname, 
+                                       importc: "glMultiTexCoord4iARB".}
+proc glMultiTexCoord4ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord4ivARB".}
+proc glMultiTexCoord4sARB*(target: TGLenum, s: TGLshort, t: TGLshort, 
+                           r: TGLshort, q: TGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord4sARB".}
+proc glMultiTexCoord4svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord4svARB".}
+proc glSampleCoverageARB*(value: TGLclampf, invert: TGLboolean){.
+    dynlib: dllname, importc: "glSampleCoverageARB".}
+  #***** GL_ARB_texture_env_add *****//
+proc glWeightbvARB*(size: TGLint, weights: PGLbyte){.dynlib: dllname, 
+    importc: "glWeightbvARB".}
+proc glWeightsvARB*(size: TGLint, weights: PGLshort){.dynlib: dllname, 
+    importc: "glWeightsvARB".}
+proc glWeightivARB*(size: TGLint, weights: PGLint){.dynlib: dllname, 
+    importc: "glWeightivARB".}
+proc glWeightfvARB*(size: TGLint, weights: PGLfloat){.dynlib: dllname, 
+    importc: "glWeightfvARB".}
+proc glWeightdvARB*(size: TGLint, weights: PGLdouble){.dynlib: dllname, 
+    importc: "glWeightdvARB".}
+proc glWeightvARB*(size: TGLint, weights: PGLdouble){.dynlib: dllname, 
+    importc: "glWeightvARB".}
+proc glWeightubvARB*(size: TGLint, weights: PGLubyte){.dynlib: dllname, 
+    importc: "glWeightubvARB".}
+proc glWeightusvARB*(size: TGLint, weights: PGLushort){.dynlib: dllname, 
+    importc: "glWeightusvARB".}
+proc glWeightuivARB*(size: TGLint, weights: PGLuint){.dynlib: dllname, 
+    importc: "glWeightuivARB".}
+proc glWeightPointerARB*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                         pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glWeightPointerARB".}
+proc glVertexBlendARB*(count: TGLint){.dynlib: dllname, 
+                                       importc: "glVertexBlendARB".}
+proc glVertexAttrib1sARB*(index: TGLuint, x: TGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib1sARB".}
+proc glVertexAttrib1fARB*(index: TGLuint, x: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib1fARB".}
+proc glVertexAttrib1dARB*(index: TGLuint, x: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib1dARB".}
+proc glVertexAttrib2sARB*(index: TGLuint, x: TGLshort, y: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib2sARB".}
+proc glVertexAttrib2fARB*(index: TGLuint, x: TGLfloat, y: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib2fARB".}
+proc glVertexAttrib2dARB*(index: TGLuint, x: TGLdouble, y: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib2dARB".}
+proc glVertexAttrib3sARB*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib3sARB".}
+proc glVertexAttrib3fARB*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib3fARB".}
+proc glVertexAttrib3dARB*(index: TGLuint, x: TGLdouble, y: TGLdouble, 
+                          z: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib3dARB".}
+proc glVertexAttrib4sARB*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort, 
+                          w: TGLshort){.dynlib: dllname, 
+                                        importc: "glVertexAttrib4sARB".}
+proc glVertexAttrib4fARB*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat, 
+                          w: TGLfloat){.dynlib: dllname, 
+                                        importc: "glVertexAttrib4fARB".}
+proc glVertexAttrib4dARB*(index: TGLuint, x: TGLdouble, y: TGLdouble, 
+                          z: TGLdouble, w: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib4dARB".}
+proc glVertexAttrib4NubARB*(index: TGLuint, x: TGLubyte, y: TGLubyte, 
+                            z: TGLubyte, w: TGLubyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4NubARB".}
+proc glVertexAttrib1svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib1svARB".}
+proc glVertexAttrib1fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib1fvARB".}
+proc glVertexAttrib1dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib1dvARB".}
+proc glVertexAttrib2svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib2svARB".}
+proc glVertexAttrib2fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib2fvARB".}
+proc glVertexAttrib2dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib2dvARB".}
+proc glVertexAttrib3svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib3svARB".}
+proc glVertexAttrib3fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib3fvARB".}
+proc glVertexAttrib3dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib3dvARB".}
+proc glVertexAttrib4bvARB*(index: TGLuint, v: PGLbyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4bvARB".}
+proc glVertexAttrib4svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib4svARB".}
+proc glVertexAttrib4ivARB*(index: TGLuint, v: PGLint){.dynlib: dllname, 
+    importc: "glVertexAttrib4ivARB".}
+proc glVertexAttrib4ubvARB*(index: TGLuint, v: PGLubyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4ubvARB".}
+proc glVertexAttrib4usvARB*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib4usvARB".}
+proc glVertexAttrib4uivARB*(index: TGLuint, v: PGLuint){.dynlib: dllname, 
+    importc: "glVertexAttrib4uivARB".}
+proc glVertexAttrib4fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib4fvARB".}
+proc glVertexAttrib4dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib4dvARB".}
+proc glVertexAttrib4NbvARB*(index: TGLuint, v: PGLbyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4NbvARB".}
+proc glVertexAttrib4NsvARB*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib4NsvARB".}
+proc glVertexAttrib4NivARB*(index: TGLuint, v: PGLint){.dynlib: dllname, 
+    importc: "glVertexAttrib4NivARB".}
+proc glVertexAttrib4NubvARB*(index: TGLuint, v: PGLubyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4NubvARB".}
+proc glVertexAttrib4NusvARB*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib4NusvARB".}
+proc glVertexAttrib4NuivARB*(index: TGLuint, v: PGLuint){.dynlib: dllname, 
+    importc: "glVertexAttrib4NuivARB".}
+proc glVertexAttribPointerARB*(index: TGLuint, size: TGLint, thetype: TGLenum, 
+                               normalized: TGLboolean, stride: TGLsizei, 
+                               pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glVertexAttribPointerARB".}
+proc glEnableVertexAttribArrayARB*(index: TGLuint){.dynlib: dllname, 
+    importc: "glEnableVertexAttribArrayARB".}
+proc glDisableVertexAttribArrayARB*(index: TGLuint){.dynlib: dllname, 
+    importc: "glDisableVertexAttribArrayARB".}
+proc glProgramStringARB*(target: TGLenum, format: TGLenum, length: TGLsizei, 
+                         str: PGLvoid){.dynlib: dllname, 
+                                        importc: "glProgramStringARB".}
+proc glBindProgramARB*(target: TGLenum, theProgram: TGLuint){.dynlib: dllname, 
+    importc: "glBindProgramARB".}
+proc glDeleteProgramsARB*(n: TGLsizei, programs: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteProgramsARB".}
+proc glGenProgramsARB*(n: TGLsizei, programs: PGLuint){.dynlib: dllname, 
+    importc: "glGenProgramsARB".}
+proc glProgramEnvParameter4dARB*(target: TGLenum, index: TGLuint, x: TGLdouble, 
+                                 y: TGLdouble, z: TGLdouble, w: TGLdouble){.
+    dynlib: dllname, importc: "glProgramEnvParameter4dARB".}
+proc glProgramEnvParameter4dvARB*(target: TGLenum, index: TGLuint, 
+                                  params: PGLdouble){.dynlib: dllname, 
+    importc: "glProgramEnvParameter4dvARB".}
+proc glProgramEnvParameter4fARB*(target: TGLenum, index: TGLuint, x: TGLfloat, 
+                                 y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glProgramEnvParameter4fARB".}
+proc glProgramEnvParameter4fvARB*(target: TGLenum, index: TGLuint, 
+                                  params: PGLfloat){.dynlib: dllname, 
+    importc: "glProgramEnvParameter4fvARB".}
+proc glProgramLocalParameter4dARB*(target: TGLenum, index: TGLuint, 
+                                   x: TGLdouble, y: TGLdouble, z: TGLdouble, 
+                                   w: TGLdouble){.dynlib: dllname, 
+    importc: "glProgramLocalParameter4dARB".}
+proc glProgramLocalParameter4dvARB*(target: TGLenum, index: TGLuint, 
+                                    params: PGLdouble){.dynlib: dllname, 
+    importc: "glProgramLocalParameter4dvARB".}
+proc glProgramLocalParameter4fARB*(target: TGLenum, index: TGLuint, x: TGLfloat, 
+                                   y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glProgramLocalParameter4fARB".}
+proc glProgramLocalParameter4fvARB*(target: TGLenum, index: TGLuint, 
+                                    params: PGLfloat){.dynlib: dllname, 
+    importc: "glProgramLocalParameter4fvARB".}
+proc glGetProgramEnvParameterdvARB*(target: TGLenum, index: TGLuint, 
+                                    params: PGLdouble){.dynlib: dllname, 
+    importc: "glGetProgramEnvParameterdvARB".}
+proc glGetProgramEnvParameterfvARB*(target: TGLenum, index: TGLuint, 
+                                    params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetProgramEnvParameterfvARB".}
+proc glGetProgramLocalParameterdvARB*(target: TGLenum, index: TGLuint, 
+                                      params: PGLdouble){.dynlib: dllname, 
+    importc: "glGetProgramLocalParameterdvARB".}
+proc glGetProgramLocalParameterfvARB*(target: TGLenum, index: TGLuint, 
+                                      params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetProgramLocalParameterfvARB".}
+proc glGetProgramivARB*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetProgramivARB".}
+proc glGetProgramStringARB*(target: TGLenum, pname: TGLenum, str: PGLvoid){.
+    dynlib: dllname, importc: "glGetProgramStringARB".}
+proc glGetVertexAttribdvARB*(index: TGLuint, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetVertexAttribdvARB".}
+proc glGetVertexAttribfvARB*(index: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVertexAttribfvARB".}
+proc glGetVertexAttribivARB*(index: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVertexAttribivARB".}
+proc glGetVertexAttribPointervARB*(index: TGLuint, pname: TGLenum, 
+                                   pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glGetVertexAttribPointervARB".}
+proc glIsProgramARB*(theProgram: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsProgramARB".}
+  #***** GL_ARB_window_pos *****//
+proc glWindowPos2dARB*(x: TGLdouble, y: TGLdouble){.dynlib: dllname, 
+    importc: "glWindowPos2dARB".}
+proc glWindowPos2fARB*(x: TGLfloat, y: TGLfloat){.dynlib: dllname, 
+    importc: "glWindowPos2fARB".}
+proc glWindowPos2iARB*(x: TGLint, y: TGLint){.dynlib: dllname, 
+    importc: "glWindowPos2iARB".}
+proc glWindowPos2sARB*(x: TGLshort, y: TGLshort){.dynlib: dllname, 
+    importc: "glWindowPos2sARB".}
+proc glWindowPos2dvARB*(p: PGLdouble){.dynlib: dllname, 
+                                       importc: "glWindowPos2dvARB".}
+proc glWindowPos2fvARB*(p: PGLfloat){.dynlib: dllname, 
+                                      importc: "glWindowPos2fvARB".}
+proc glWindowPos2ivARB*(p: PGLint){.dynlib: dllname, 
+                                    importc: "glWindowPos2ivARB".}
+proc glWindowPos2svARB*(p: PGLshort){.dynlib: dllname, 
+                                      importc: "glWindowPos2svARB".}
+proc glWindowPos3dARB*(x: TGLdouble, y: TGLdouble, z: TGLdouble){.
+    dynlib: dllname, importc: "glWindowPos3dARB".}
+proc glWindowPos3fARB*(x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glWindowPos3fARB".}
+proc glWindowPos3iARB*(x: TGLint, y: TGLint, z: TGLint){.dynlib: dllname, 
+    importc: "glWindowPos3iARB".}
+proc glWindowPos3sARB*(x: TGLshort, y: TGLshort, z: TGLshort){.dynlib: dllname, 
+    importc: "glWindowPos3sARB".}
+proc glWindowPos3dvARB*(p: PGLdouble){.dynlib: dllname, 
+                                       importc: "glWindowPos3dvARB".}
+proc glWindowPos3fvARB*(p: PGLfloat){.dynlib: dllname, 
+                                      importc: "glWindowPos3fvARB".}
+proc glWindowPos3ivARB*(p: PGLint){.dynlib: dllname, 
+                                    importc: "glWindowPos3ivARB".}
+proc glWindowPos3svARB*(p: PGLshort){.dynlib: dllname, 
+                                      importc: "glWindowPos3svARB".}
+proc glBlendEquationSeparate*(modeRGB: TGLenum, modeAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendEquationSeparate".}
+proc glDrawBuffers*(n: TGLsizei, bufs: PGLenum){.dynlib: dllname, 
+    importc: "glDrawBuffers".}
+proc glStencilOpSeparate*(face: TGLenum, sfail: TGLenum, dpfail: TGLenum, 
+                          dppass: TGLenum){.dynlib: dllname, 
+    importc: "glStencilOpSeparate".}
+proc glStencilFuncSeparate*(frontfunc: TGLenum, backfunc: TGLenum, 
+                            theRef: TGLint, mask: TGLuint){.dynlib: dllname, 
+    importc: "glStencilFuncSeparate".}
+proc glStencilMaskSeparate*(face: TGLenum, mask: TGLuint){.dynlib: dllname, 
+    importc: "glStencilMaskSeparate".}
+proc glAttachShader*(theProgram: TGLuint, shader: TGLuint){.dynlib: dllname, 
+    importc: "glAttachShader".}
+proc glBindAttribLocation*(theProgram: TGLuint, index: TGLuint, name: PGLchar){.
+    dynlib: dllname, importc: "glBindAttribLocation".}
+proc glCompileShader*(shader: TGLuint){.dynlib: dllname, 
+                                        importc: "glCompileShader".}
+proc glCreateProgram*(): TGLuint{.dynlib: dllname, importc: "glCreateProgram".}
+proc glCreateShader*(thetype: TGLenum): TGLuint{.dynlib: dllname, 
+    importc: "glCreateShader".}
+proc glDeleteProgram*(theProgram: TGLuint){.dynlib: dllname, 
+    importc: "glDeleteProgram".}
+proc glDeleteShader*(shader: TGLuint){.dynlib: dllname, 
+                                       importc: "glDeleteShader".}
+proc glDetachShader*(theProgram: TGLuint, shader: TGLuint){.dynlib: dllname, 
+    importc: "glDetachShader".}
+proc glDisableVertexAttribArray*(index: TGLuint){.dynlib: dllname, 
+    importc: "glDisableVertexAttribArray".}
+proc glEnableVertexAttribArray*(index: TGLuint){.dynlib: dllname, 
+    importc: "glEnableVertexAttribArray".}
+proc glGetActiveAttrib*(theProgram: TGLuint, index: TGLuint, bufSize: TGLsizei, 
+                        len: PGLsizei, size: PGLint, thetype: PGLenum, 
+                        name: PGLchar){.dynlib: dllname, 
+                                        importc: "glGetActiveAttrib".}
+proc glGetActiveUniform*(theProgram: TGLuint, index: TGLuint, bufSize: TGLsizei, 
+                         len: PGLsizei, size: PGLint, thetype: PGLenum, 
+                         name: PGLchar){.dynlib: dllname, 
+    importc: "glGetActiveUniform".}
+proc glGetAttachedShaders*(theProgram: TGLuint, maxCount: TGLsizei, 
+                           count: PGLsizei, obj: PGLuint){.dynlib: dllname, 
+    importc: "glGetAttachedShaders".}
+proc glGetAttribLocation*(theProgram: TGLuint, name: PGLchar): TGLint{.
+    dynlib: dllname, importc: "glGetAttribLocation".}
+proc glGetProgramiv*(theProgram: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetProgramiv".}
+proc glGetProgramInfoLog*(theProgram: TGLuint, bufSize: TGLsizei, len: PGLsizei, 
+                          infoLog: PGLchar){.dynlib: dllname, 
+    importc: "glGetProgramInfoLog".}
+proc glGetShaderiv*(shader: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetShaderiv".}
+proc glGetShaderInfoLog*(shader: TGLuint, bufSize: TGLsizei, len: PGLsizei, 
+                         infoLog: PGLchar){.dynlib: dllname, 
+    importc: "glGetShaderInfoLog".}
+proc glGetShaderSource*(shader: TGLuint, bufSize: TGLsizei, len: PGLsizei, 
+                        source: PGLchar){.dynlib: dllname, 
+    importc: "glGetShaderSource".}
+proc glGetUniformLocation*(theProgram: TGLuint, name: PGLchar): TGLint{.
+    dynlib: dllname, importc: "glGetUniformLocation".}
+proc glGetUniformfv*(theProgram: TGLuint, location: TGLint, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetUniformfv".}
+proc glGetUniformiv*(theProgram: TGLuint, location: TGLint, params: PGLint){.
+    dynlib: dllname, importc: "glGetUniformiv".}
+proc glGetVertexAttribdv*(index: TGLuint, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetVertexAttribdv".}
+proc glGetVertexAttribfv*(index: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVertexAttribfv".}
+proc glGetVertexAttribiv*(index: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVertexAttribiv".}
+proc glGetVertexAttribPointerv*(index: TGLuint, pname: TGLenum, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glGetVertexAttribPointerv".}
+proc glIsProgram*(theProgram: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsProgram".}
+proc glIsShader*(shader: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsShader".}
+proc glLinkProgram*(theProgram: TGLuint){.dynlib: dllname, 
+    importc: "glLinkProgram".}
+proc glShaderSource*(shader: TGLuint, count: TGLsizei, str: PGLchar, len: PGLint){.
+    dynlib: dllname, importc: "glShaderSource".}
+proc glUseProgram*(theProgram: TGLuint){.dynlib: dllname, 
+    importc: "glUseProgram".}
+proc glUniform1f*(location: TGLint, v0: TGLfloat){.dynlib: dllname, 
+    importc: "glUniform1f".}
+proc glUniform2f*(location: TGLint, v0: TGLfloat, v1: TGLfloat){.
+    dynlib: dllname, importc: "glUniform2f".}
+proc glUniform3f*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat){.
+    dynlib: dllname, importc: "glUniform3f".}
+proc glUniform4f*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat, 
+                  v3: TGLfloat){.dynlib: dllname, importc: "glUniform4f".}
+proc glUniform1i*(location: TGLint, v0: TGLint){.dynlib: dllname, 
+    importc: "glUniform1i".}
+proc glUniform2i*(location: TGLint, v0: TGLint, v1: TGLint){.dynlib: dllname, 
+    importc: "glUniform2i".}
+proc glUniform3i*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint){.
+    dynlib: dllname, importc: "glUniform3i".}
+proc glUniform4i*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint, 
+                  v3: TGLint){.dynlib: dllname, importc: "glUniform4i".}
+proc glUniform1fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform1fv".}
+proc glUniform2fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform2fv".}
+proc glUniform3fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform3fv".}
+proc glUniform4fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform4fv".}
+proc glUniform1iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform1iv".}
+proc glUniform2iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform2iv".}
+proc glUniform3iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform3iv".}
+proc glUniform4iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform4iv".}
+proc glUniformMatrix2fv*(location: TGLint, count: TGLsizei, 
+                         transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix2fv".}
+proc glUniformMatrix3fv*(location: TGLint, count: TGLsizei, 
+                         transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix3fv".}
+proc glUniformMatrix4fv*(location: TGLint, count: TGLsizei, 
+                         transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix4fv".}
+proc glValidateProgram*(theProgram: TGLuint){.dynlib: dllname, 
+    importc: "glValidateProgram".}
+proc glVertexAttrib1d*(index: TGLuint, x: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib1d".}
+proc glVertexAttrib1dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib1dv".}
+proc glVertexAttrib1f*(index: TGLuint, x: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib1f".}
+proc glVertexAttrib1fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib1fv".}
+proc glVertexAttrib1s*(index: TGLuint, x: TGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib1s".}
+proc glVertexAttrib1sv*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib1sv".}
+proc glVertexAttrib2d*(index: TGLuint, x: TGLdouble, y: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib2d".}
+proc glVertexAttrib2dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib2dv".}
+proc glVertexAttrib2f*(index: TGLuint, x: TGLfloat, y: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib2f".}
+proc glVertexAttrib2fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib2fv".}
+proc glVertexAttrib2s*(index: TGLuint, x: TGLshort, y: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib2s".}
+proc glVertexAttrib2sv*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib2sv".}
+proc glVertexAttrib3d*(index: TGLuint, x: TGLdouble, y: TGLdouble, z: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib3d".}
+proc glVertexAttrib3dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib3dv".}
+proc glVertexAttrib3f*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib3f".}
+proc glVertexAttrib3fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib3fv".}
+proc glVertexAttrib3s*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib3s".}
+proc glVertexAttrib3sv*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib3sv".}
+proc glVertexAttrib4Nbv*(index: TGLuint, v: PGLbyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4Nbv".}
+proc glVertexAttrib4Niv*(index: TGLuint, v: PGLint){.dynlib: dllname, 
+    importc: "glVertexAttrib4Niv".}
+proc glVertexAttrib4Nsv*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib4Nsv".}
+proc glVertexAttrib4Nub*(index: TGLuint, x: TGLubyte, y: TGLubyte, z: TGLubyte, 
+                         w: TGLubyte){.dynlib: dllname, 
+                                       importc: "glVertexAttrib4Nub".}
+proc glVertexAttrib4Nubv*(index: TGLuint, v: PGLubyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4Nubv".}
+proc glVertexAttrib4Nuiv*(index: TGLuint, v: PGLuint){.dynlib: dllname, 
+    importc: "glVertexAttrib4Nuiv".}
+proc glVertexAttrib4Nusv*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib4Nusv".}
+proc glVertexAttrib4bv*(index: TGLuint, v: PGLbyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4bv".}
+proc glVertexAttrib4d*(index: TGLuint, x: TGLdouble, y: TGLdouble, z: TGLdouble, 
+                       w: TGLdouble){.dynlib: dllname, 
+                                      importc: "glVertexAttrib4d".}
+proc glVertexAttrib4dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib4dv".}
+proc glVertexAttrib4f*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat, 
+                       w: TGLfloat){.dynlib: dllname, 
+                                     importc: "glVertexAttrib4f".}
+proc glVertexAttrib4fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib4fv".}
+proc glVertexAttrib4iv*(index: TGLuint, v: PGLint){.dynlib: dllname, 
+    importc: "glVertexAttrib4iv".}
+proc glVertexAttrib4s*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort, 
+                       w: TGLshort){.dynlib: dllname, 
+                                     importc: "glVertexAttrib4s".}
+proc glVertexAttrib4sv*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib4sv".}
+proc glVertexAttrib4ubv*(index: TGLuint, v: PGLubyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4ubv".}
+proc glVertexAttrib4uiv*(index: TGLuint, v: PGLuint){.dynlib: dllname, 
+    importc: "glVertexAttrib4uiv".}
+proc glVertexAttrib4usv*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib4usv".}
+proc glVertexAttribPointer*(index: TGLuint, size: TGLint, thetype: TGLenum, 
+                            normalized: TGLboolean, stride: TGLsizei, 
+                            pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glVertexAttribPointer".}
+const 
+  GL_CONSTANT_COLOR* = 0x00008001
+  GL_ONE_MINUS_CONSTANT_COLOR* = 0x00008002
+  GL_CONSTANT_ALPHA* = 0x00008003
+  GL_ONE_MINUS_CONSTANT_ALPHA* = 0x00008004
+  constGL_BLEND_COLOR* = 0x00008005
+  GL_FUNC_ADD* = 0x00008006
+  GL_MIN* = 0x00008007
+  GL_MAX* = 0x00008008
+  constGL_BLEND_EQUATION* = 0x00008009
+  GL_FUNC_SUBTRACT* = 0x0000800A
+  GL_FUNC_REVERSE_SUBTRACT* = 0x0000800B
+  GL_CONVOLUTION_1D* = 0x00008010
+  GL_CONVOLUTION_2D* = 0x00008011
+  GL_SEPARABLE_2D* = 0x00008012
+  GL_CONVOLUTION_BORDER_MODE* = 0x00008013
+  GL_CONVOLUTION_FILTER_SCALE* = 0x00008014
+  GL_CONVOLUTION_FILTER_BIAS* = 0x00008015
+  GL_REDUCE* = 0x00008016
+  GL_CONVOLUTION_FORMAT* = 0x00008017
+  GL_CONVOLUTION_WIDTH* = 0x00008018
+  GL_CONVOLUTION_HEIGHT* = 0x00008019
+  GL_MAX_CONVOLUTION_WIDTH* = 0x0000801A
+  GL_MAX_CONVOLUTION_HEIGHT* = 0x0000801B
+  GL_POST_CONVOLUTION_RED_SCALE* = 0x0000801C
+  GL_POST_CONVOLUTION_GREEN_SCALE* = 0x0000801D
+  GL_POST_CONVOLUTION_BLUE_SCALE* = 0x0000801E
+  GL_POST_CONVOLUTION_ALPHA_SCALE* = 0x0000801F
+  GL_POST_CONVOLUTION_RED_BIAS* = 0x00008020
+  GL_POST_CONVOLUTION_GREEN_BIAS* = 0x00008021
+  GL_POST_CONVOLUTION_BLUE_BIAS* = 0x00008022
+  GL_POST_CONVOLUTION_ALPHA_BIAS* = 0x00008023
+  constGL_HISTOGRAM* = 0x00008024
+  GL_PROXY_HISTOGRAM* = 0x00008025
+  GL_HISTOGRAM_WIDTH* = 0x00008026
+  GL_HISTOGRAM_FORMAT* = 0x00008027
+  GL_HISTOGRAM_RED_SIZE* = 0x00008028
+  GL_HISTOGRAM_GREEN_SIZE* = 0x00008029
+  GL_HISTOGRAM_BLUE_SIZE* = 0x0000802A
+  GL_HISTOGRAM_ALPHA_SIZE* = 0x0000802B
+  GL_HISTOGRAM_LUMINANCE_SIZE* = 0x0000802C
+  GL_HISTOGRAM_SINK* = 0x0000802D
+  constGL_MINMAX* = 0x0000802E
+  GL_MINMAX_FORMAT* = 0x0000802F
+  GL_MINMAX_SINK* = 0x00008030
+  GL_TABLE_TOO_LARGE* = 0x00008031
+  GL_COLOR_MATRIX* = 0x000080B1
+  GL_COLOR_MATRIX_STACK_DEPTH* = 0x000080B2
+  GL_MAX_COLOR_MATRIX_STACK_DEPTH* = 0x000080B3
+  GL_POST_COLOR_MATRIX_RED_SCALE* = 0x000080B4
+  GL_POST_COLOR_MATRIX_GREEN_SCALE* = 0x000080B5
+  GL_POST_COLOR_MATRIX_BLUE_SCALE* = 0x000080B6
+  GL_POST_COLOR_MATRIX_ALPHA_SCALE* = 0x000080B7
+  GL_POST_COLOR_MATRIX_RED_BIAS* = 0x000080B8
+  GL_POST_COLOR_MATRIX_GREEN_BIAS* = 0x000080B9
+  GL_POST_COLOR_MATRIX_BLUE_BIAS* = 0x000080BA
+  GL_POST_COLOR_MATIX_ALPHA_BIAS* = 0x000080BB
+  constGL_COLOR_TABLE* = 0x000080D0
+  GL_POST_CONVOLUTION_COLOR_TABLE* = 0x000080D1
+  GL_POST_COLOR_MATRIX_COLOR_TABLE* = 0x000080D2
+  GL_PROXY_COLOR_TABLE* = 0x000080D3
+  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE* = 0x000080D4
+  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE* = 0x000080D5
+  GL_COLOR_TABLE_SCALE* = 0x000080D6
+  GL_COLOR_TABLE_BIAS* = 0x000080D7
+  GL_COLOR_TABLE_FORMAT* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE* = 0x000080DF
+  GL_IGNORE_BORDER* = 0x00008150
+  GL_CONSTANT_BORDER* = 0x00008151
+  GL_WRAP_BORDER* = 0x00008152
+  GL_REPLICATE_BORDER* = 0x00008153
+  GL_CONVOLUTION_BORDER_COLOR* = 0x00008154
+
+proc glActiveTexture*(texture: TGLenum){.dynlib: dllname, 
+    importc: "glActiveTexture".}
+proc glClientActiveTexture*(texture: TGLenum){.dynlib: dllname, 
+    importc: "glClientActiveTexture".}
+proc glMultiTexCoord1d*(target: TGLenum, s: TGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord1d".}
+proc glMultiTexCoord1dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord1dv".}
+proc glMultiTexCoord1f*(target: TGLenum, s: TGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord1f".}
+proc glMultiTexCoord1fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord1fv".}
+proc glMultiTexCoord1i*(target: TGLenum, s: TGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord1i".}
+proc glMultiTexCoord1iv*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord1iv".}
+proc glMultiTexCoord1s*(target: TGLenum, s: TGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord1s".}
+proc glMultiTexCoord1sv*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord1sv".}
+proc glMultiTexCoord2d*(target: TGLenum, s: TGLdouble, t: TGLdouble){.
+    dynlib: dllname, importc: "glMultiTexCoord2d".}
+proc glMultiTexCoord2dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord2dv".}
+proc glMultiTexCoord2f*(target: TGLenum, s: TGLfloat, t: TGLfloat){.
+    dynlib: dllname, importc: "glMultiTexCoord2f".}
+proc glMultiTexCoord2fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord2fv".}
+proc glMultiTexCoord2i*(target: TGLenum, s: TGLint, t: TGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord2i".}
+proc glMultiTexCoord2iv*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord2iv".}
+proc glMultiTexCoord2s*(target: TGLenum, s: TGLshort, t: TGLshort){.
+    dynlib: dllname, importc: "glMultiTexCoord2s".}
+proc glMultiTexCoord2sv*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord2sv".}
+proc glMultiTexCoord3d*(target: TGLenum, s: TGLdouble, t: TGLdouble, 
+                        r: TGLdouble){.dynlib: dllname, 
+                                       importc: "glMultiTexCoord3d".}
+proc glMultiTexCoord3dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord3dv".}
+proc glMultiTexCoord3f*(target: TGLenum, s: TGLfloat, t: TGLfloat, r: TGLfloat){.
+    dynlib: dllname, importc: "glMultiTexCoord3f".}
+proc glMultiTexCoord3fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord3fv".}
+proc glMultiTexCoord3i*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint){.
+    dynlib: dllname, importc: "glMultiTexCoord3i".}
+proc glMultiTexCoord3iv*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord3iv".}
+proc glMultiTexCoord3s*(target: TGLenum, s: TGLshort, t: TGLshort, r: TGLshort){.
+    dynlib: dllname, importc: "glMultiTexCoord3s".}
+proc glMultiTexCoord3sv*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord3sv".}
+proc glMultiTexCoord4d*(target: TGLenum, s: TGLdouble, t: TGLdouble, 
+                        r: TGLdouble, q: TGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord4d".}
+proc glMultiTexCoord4dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname, 
+    importc: "glMultiTexCoord4dv".}
+proc glMultiTexCoord4f*(target: TGLenum, s: TGLfloat, t: TGLfloat, r: TGLfloat, 
+                        q: TGLfloat){.dynlib: dllname, 
+                                      importc: "glMultiTexCoord4f".}
+proc glMultiTexCoord4fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname, 
+    importc: "glMultiTexCoord4fv".}
+proc glMultiTexCoord4i*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint, 
+                        q: TGLint){.dynlib: dllname, 
+                                    importc: "glMultiTexCoord4i".}
+proc glMultiTexCoord4iv*(target: TGLenum, v: PGLint){.dynlib: dllname, 
+    importc: "glMultiTexCoord4iv".}
+proc glMultiTexCoord4s*(target: TGLenum, s: TGLshort, t: TGLshort, r: TGLshort, 
+                        q: TGLshort){.dynlib: dllname, 
+                                      importc: "glMultiTexCoord4s".}
+proc glMultiTexCoord4sv*(target: TGLenum, v: PGLshort){.dynlib: dllname, 
+    importc: "glMultiTexCoord4sv".}
+proc glLoadTransposeMatrixf*(m: PGLfloat){.dynlib: dllname, 
+    importc: "glLoadTransposeMatrixf".}
+proc glLoadTransposeMatrixd*(m: PGLdouble){.dynlib: dllname, 
+    importc: "glLoadTransposeMatrixd".}
+proc glMultTransposeMatrixf*(m: PGLfloat){.dynlib: dllname, 
+    importc: "glMultTransposeMatrixf".}
+proc glMultTransposeMatrixd*(m: PGLdouble){.dynlib: dllname, 
+    importc: "glMultTransposeMatrixd".}
+proc glSampleCoverage*(value: TGLclampf, invert: TGLboolean){.dynlib: dllname, 
+    importc: "glSampleCoverage".}
+proc glCompressedTexImage3D*(target: TGLenum, level: TGLint, 
+                             internalformat: TGLenum, width: TGLsizei, 
+                             height: TGLsizei, depth: TGLsizei, border: TGLint, 
+                             imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage3D".}
+proc glCompressedTexImage2D*(target: TGLenum, level: TGLint, 
+                             internalformat: TGLenum, width: TGLsizei, 
+                             height: TGLsizei, border: TGLint, 
+                             imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage2D".}
+proc glCompressedTexImage1D*(target: TGLenum, level: TGLint, 
+                             internalformat: TGLenum, width: TGLsizei, 
+                             border: TGLint, imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage1D".}
+proc glCompressedTexSubImage3D*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                                yoffset: TGLint, zoffset: TGLint, 
+                                width: TGLsizei, height: TGLsizei, 
+                                depth: TGLsizei, format: TGLenum, 
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexSubImage3D".}
+proc glCompressedTexSubImage2D*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                                yoffset: TGLint, width: TGLsizei, 
+                                height: TGLsizei, format: TGLenum, 
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexSubImage2D".}
+proc glCompressedTexSubImage1D*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                                width: TGLsizei, format: TGLenum, 
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexSubImage1D".}
+proc glGetCompressedTexImage*(target: TGLenum, level: TGLint, img: PGLvoid){.
+    dynlib: dllname, importc: "glGetCompressedTexImage".}
+  #***** GL_version_1_3 *****//
+const 
+  GL_TEXTURE0* = 0x000084C0
+  GL_TEXTURE1* = 0x000084C1
+  GL_TEXTURE2* = 0x000084C2
+  GL_TEXTURE3* = 0x000084C3
+  GL_TEXTURE4* = 0x000084C4
+  GL_TEXTURE5* = 0x000084C5
+  GL_TEXTURE6* = 0x000084C6
+  GL_TEXTURE7* = 0x000084C7
+  GL_TEXTURE8* = 0x000084C8
+  GL_TEXTURE9* = 0x000084C9
+  GL_TEXTURE10* = 0x000084CA
+  GL_TEXTURE11* = 0x000084CB
+  GL_TEXTURE12* = 0x000084CC
+  GL_TEXTURE13* = 0x000084CD
+  GL_TEXTURE14* = 0x000084CE
+  GL_TEXTURE15* = 0x000084CF
+  GL_TEXTURE16* = 0x000084D0
+  GL_TEXTURE17* = 0x000084D1
+  GL_TEXTURE18* = 0x000084D2
+  GL_TEXTURE19* = 0x000084D3
+  GL_TEXTURE20* = 0x000084D4
+  GL_TEXTURE21* = 0x000084D5
+  GL_TEXTURE22* = 0x000084D6
+  GL_TEXTURE23* = 0x000084D7
+  GL_TEXTURE24* = 0x000084D8
+  GL_TEXTURE25* = 0x000084D9
+  GL_TEXTURE26* = 0x000084DA
+  GL_TEXTURE27* = 0x000084DB
+  GL_TEXTURE28* = 0x000084DC
+  GL_TEXTURE29* = 0x000084DD
+  GL_TEXTURE30* = 0x000084DE
+  GL_TEXTURE31* = 0x000084DF
+  constGL_ACTIVE_TEXTURE* = 0x000084E0
+  constGL_CLIENT_ACTIVE_TEXTURE* = 0x000084E1
+  GL_MAX_TEXTURE_UNITS* = 0x000084E2
+  GL_TRANSPOSE_MODELVIEW_MATRIX* = 0x000084E3
+  GL_TRANSPOSE_PROJECTION_MATRIX* = 0x000084E4
+  GL_TRANSPOSE_TEXTURE_MATRIX* = 0x000084E5
+  GL_TRANSPOSE_COLOR_MATRIX* = 0x000084E6
+  GL_MULTISAMPLE* = 0x0000809D
+  GL_SAMPLE_ALPHA_TO_COVERAGE* = 0x0000809E
+  GL_SAMPLE_ALPHA_TO_ONE* = 0x0000809F
+  constGL_SAMPLE_COVERAGE* = 0x000080A0
+  GL_SAMPLE_BUFFERS* = 0x000080A8
+  GL_SAMPLES* = 0x000080A9
+  GL_SAMPLE_COVERAGE_VALUE* = 0x000080AA
+  GL_SAMPLE_COVERAGE_INVERT* = 0x000080AB
+  GL_MULTISAMPLE_BIT* = 0x20000000
+  GL_NORMAL_MAP* = 0x00008511
+  GL_REFLECTION_MAP* = 0x00008512
+  GL_TEXTURE_CUBE_MAP* = 0x00008513
+  GL_TEXTURE_BINDING_CUBE_MAP* = 0x00008514
+  GL_TEXTURE_CUBE_MAP_POSITIVE_X* = 0x00008515
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_X* = 0x00008516
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Y* = 0x00008517
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y* = 0x00008518
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Z* = 0x00008519
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z* = 0x0000851A
+  GL_PROXY_TEXTURE_CUBE_MAP* = 0x0000851B
+  GL_MAX_CUBE_MAP_TEXTURE_SIZE* = 0x0000851C
+  GL_COMPRESSED_ALPHA* = 0x000084E9
+  GL_COMPRESSED_LUMINANCE* = 0x000084EA
+  GL_COMPRESSED_LUMINANCE_ALPHA* = 0x000084EB
+  GL_COMPRESSED_INTENSITY* = 0x000084EC
+  GL_COMPRESSED_RGB* = 0x000084ED
+  GL_COMPRESSED_RGBA* = 0x000084EE
+  GL_TEXTURE_COMPRESSION_HINT* = 0x000084EF
+  GL_TEXTURE_COMPRESSED_IMAGE_SIZE* = 0x000086A0
+  GL_TEXTURE_COMPRESSED* = 0x000086A1
+  GL_NUM_COMPRESSED_TEXTURE_FORMATS* = 0x000086A2
+  GL_COMPRESSED_TEXTURE_FORMATS* = 0x000086A3
+  GL_CLAMP_TO_BORDER* = 0x0000812D
+  GL_CLAMP_TO_BORDER_SGIS* = 0x0000812D
+  GL_COMBINE* = 0x00008570
+  GL_COMBINE_RGB* = 0x00008571
+  GL_COMBINE_ALPHA* = 0x00008572
+  GL_SOURCE0_RGB* = 0x00008580
+  GL_SOURCE1_RGB* = 0x00008581
+  GL_SOURCE2_RGB* = 0x00008582
+  GL_SOURCE0_ALPHA* = 0x00008588
+  GL_SOURCE1_ALPHA* = 0x00008589
+  GL_SOURCE2_ALPHA* = 0x0000858A
+  GL_OPERAND0_RGB* = 0x00008590
+  GL_OPERAND1_RGB* = 0x00008591
+  GL_OPERAND2_RGB* = 0x00008592
+  GL_OPERAND0_ALPHA* = 0x00008598
+  GL_OPERAND1_ALPHA* = 0x00008599
+  GL_OPERAND2_ALPHA* = 0x0000859A
+  GL_RGB_SCALE* = 0x00008573
+  GL_ADD_SIGNED* = 0x00008574
+  GL_INTERPOLATE* = 0x00008575
+  GL_SUBTRACT* = 0x000084E7
+  GL_CONSTANT* = 0x00008576
+  GL_PRIMARY_COLOR* = 0x00008577
+  GL_PREVIOUS* = 0x00008578
+  GL_DOT3_RGB* = 0x000086AE
+  GL_DOT3_RGBA* = 0x000086AF
+
+const 
+  GL_TEXTURE0_ARB* = 0x000084C0
+  GL_TEXTURE1_ARB* = 0x000084C1
+  GL_TEXTURE2_ARB* = 0x000084C2
+  GL_TEXTURE3_ARB* = 0x000084C3
+  GL_TEXTURE4_ARB* = 0x000084C4
+  GL_TEXTURE5_ARB* = 0x000084C5
+  GL_TEXTURE6_ARB* = 0x000084C6
+  GL_TEXTURE7_ARB* = 0x000084C7
+  GL_TEXTURE8_ARB* = 0x000084C8
+  GL_TEXTURE9_ARB* = 0x000084C9
+  GL_TEXTURE10_ARB* = 0x000084CA
+  GL_TEXTURE11_ARB* = 0x000084CB
+  GL_TEXTURE12_ARB* = 0x000084CC
+  GL_TEXTURE13_ARB* = 0x000084CD
+  GL_TEXTURE14_ARB* = 0x000084CE
+  GL_TEXTURE15_ARB* = 0x000084CF
+  GL_TEXTURE16_ARB* = 0x000084D0
+  GL_TEXTURE17_ARB* = 0x000084D1
+  GL_TEXTURE18_ARB* = 0x000084D2
+  GL_TEXTURE19_ARB* = 0x000084D3
+  GL_TEXTURE20_ARB* = 0x000084D4
+  GL_TEXTURE21_ARB* = 0x000084D5
+  GL_TEXTURE22_ARB* = 0x000084D6
+  GL_TEXTURE23_ARB* = 0x000084D7
+  GL_TEXTURE24_ARB* = 0x000084D8
+  GL_TEXTURE25_ARB* = 0x000084D9
+  GL_TEXTURE26_ARB* = 0x000084DA
+  GL_TEXTURE27_ARB* = 0x000084DB
+  GL_TEXTURE28_ARB* = 0x000084DC
+  GL_TEXTURE29_ARB* = 0x000084DD
+  GL_TEXTURE30_ARB* = 0x000084DE
+  GL_TEXTURE31_ARB* = 0x000084DF
+  constGL_ACTIVE_TEXTURE_ARB* = 0x000084E0
+  constGL_CLIENT_ACTIVE_TEXTURE_ARB* = 0x000084E1
+  GL_MAX_TEXTURE_UNITS_ARB* = 0x000084E2
+  #***** GL_ARB_transpose_matrix *****//
+
+const 
+  GL_TRANSPOSE_MODELVIEW_MATRIX_ARB* = 0x000084E3
+  GL_TRANSPOSE_PROJECTION_MATRIX_ARB* = 0x000084E4
+  GL_TRANSPOSE_TEXTURE_MATRIX_ARB* = 0x000084E5
+  GL_TRANSPOSE_COLOR_MATRIX_ARB* = 0x000084E6
+
+proc glLoadTransposeMatrixfARB*(m: PGLfloat){.dynlib: dllname, 
+    importc: "glLoadTransposeMatrixfARB".}
+proc glLoadTransposeMatrixdARB*(m: PGLdouble){.dynlib: dllname, 
+    importc: "glLoadTransposeMatrixdARB".}
+proc glMultTransposeMatrixfARB*(m: PGLfloat){.dynlib: dllname, 
+    importc: "glMultTransposeMatrixfARB".}
+proc glMultTransposeMatrixdARB*(m: PGLdouble){.dynlib: dllname, 
+    importc: "glMultTransposeMatrixdARB".}
+const 
+  WGL_SAMPLE_BUFFERS_ARB* = 0x00002041
+  WGL_SAMPLES_ARB* = 0x00002042
+  GL_MULTISAMPLE_ARB* = 0x0000809D
+  GL_SAMPLE_ALPHA_TO_COVERAGE_ARB* = 0x0000809E
+  GL_SAMPLE_ALPHA_TO_ONE_ARB* = 0x0000809F
+  constGL_SAMPLE_COVERAGE_ARB* = 0x000080A0
+  GL_MULTISAMPLE_BIT_ARB* = 0x20000000
+  GL_SAMPLE_BUFFERS_ARB* = 0x000080A8
+  GL_SAMPLES_ARB* = 0x000080A9
+  GL_SAMPLE_COVERAGE_VALUE_ARB* = 0x000080AA
+  GL_SAMPLE_COVERAGE_INVERT_ARB* = 0x000080AB
+
+const 
+  GL_NORMAL_MAP_ARB* = 0x00008511
+  GL_REFLECTION_MAP_ARB* = 0x00008512
+  GL_TEXTURE_CUBE_MAP_ARB* = 0x00008513
+  GL_TEXTURE_BINDING_CUBE_MAP_ARB* = 0x00008514
+  GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB* = 0x00008515
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB* = 0x00008516
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB* = 0x00008517
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB* = 0x00008518
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB* = 0x00008519
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB* = 0x0000851A
+  GL_PROXY_TEXTURE_CUBE_MAP_ARB* = 0x0000851B
+  GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB* = 0x0000851C
+
+const 
+  GL_DEPTH_COMPONENT16_ARB* = 0x000081A5
+  GL_DEPTH_COMPONENT24_ARB* = 0x000081A6
+  GL_DEPTH_COMPONENT32_ARB* = 0x000081A7
+  GL_TEXTURE_DEPTH_SIZE_ARB* = 0x0000884A
+  GL_DEPTH_TEXTURE_MODE_ARB* = 0x0000884B
+  #***** GL_ARB_point_parameters *****//
+
+const 
+  GL_POINT_SIZE_MIN_ARB* = 0x00008126
+  GL_POINT_SIZE_MAX_ARB* = 0x00008127
+  GL_POINT_FADE_THRESHOLD_SIZE_ARB* = 0x00008128
+  GL_POINT_DISTANCE_ATTENUATION_ARB* = 0x00008129
+
+proc glPointParameterfARB*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glPointParameterfARB".}
+proc glPointParameterfvARB*(pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glPointParameterfvARB".}
+const 
+  GL_TEXTURE_COMPARE_MODE_ARB* = 0x0000884C
+  GL_TEXTURE_COMPARE_FUNC_ARB* = 0x0000884D
+  GL_COMPARE_R_TO_TEXTURE_ARB* = 0x0000884E
+
+const 
+  GL_TEXTURE_COMPARE_FAIL_VALUE_ARB* = 0x000080BF
+  GL_CLAMP_TO_BORDER_ARB* = 0x0000812D
+
+const 
+  GL_COMPRESSED_ALPHA_ARB* = 0x000084E9
+  GL_COMPRESSED_LUMINANCE_ARB* = 0x000084EA
+  GL_COMPRESSED_LUMINANCE_ALPHA_ARB* = 0x000084EB
+  GL_COMPRESSED_INTENSITY_ARB* = 0x000084EC
+  GL_COMPRESSED_RGB_ARB* = 0x000084ED
+  GL_COMPRESSED_RGBA_ARB* = 0x000084EE
+  GL_TEXTURE_COMPRESSION_HINT_ARB* = 0x000084EF
+  GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB* = 0x000086A0
+  GL_TEXTURE_COMPRESSED_ARB* = 0x000086A1
+  GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB* = 0x000086A2
+  GL_COMPRESSED_TEXTURE_FORMATS_ARB* = 0x000086A3
+
+proc glCompressedTexImage3DARB*(target: TGLenum, level: TGLint, 
+                                internalformat: TGLenum, width: TGLsizei, 
+                                height: TGLsizei, depth: TGLsizei, 
+                                border: TGLint, imageSize: TGLsizei, 
+                                data: PGLvoid){.dynlib: dllname, 
+    importc: "glCompressedTexImage3DARB".}
+proc glCompressedTexImage2DARB*(target: TGLenum, level: TGLint, 
+                                internalformat: TGLenum, width: TGLsizei, 
+                                height: TGLsizei, border: TGLint, 
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage2DARB".}
+proc glCompressedTexImage1DARB*(target: TGLenum, level: TGLint, 
+                                internalformat: TGLenum, width: TGLsizei, 
+                                border: TGLint, imageSize: TGLsizei, 
+                                data: PGLvoid){.dynlib: dllname, 
+    importc: "glCompressedTexImage1DARB".}
+proc glCompressedTexSubImage3DARB*(target: TGLenum, level: TGLint, 
+                                   xoffset: TGLint, yoffset: TGLint, 
+                                   zoffset: TGLint, width: TGLsizei, 
+                                   height: TGLsizei, depth: TGLsizei, 
+                                   format: TGLenum, imageSize: TGLsizei, 
+                                   data: PGLvoid){.dynlib: dllname, 
+    importc: "glCompressedTexSubImage3DARB".}
+proc glCompressedTexSubImage2DARB*(target: TGLenum, level: TGLint, 
+                                   xoffset: TGLint, yoffset: TGLint, 
+                                   width: TGLsizei, height: TGLsizei, 
+                                   format: TGLenum, imageSize: TGLsizei, 
+                                   data: PGLvoid){.dynlib: dllname, 
+    importc: "glCompressedTexSubImage2DARB".}
+proc glCompressedTexSubImage1DARB*(target: TGLenum, level: TGLint, 
+                                   xoffset: TGLint, width: TGLsizei, 
+                                   format: TGLenum, imageSize: TGLsizei, 
+                                   data: PGLvoid){.dynlib: dllname, 
+    importc: "glCompressedTexSubImage1DARB".}
+proc glGetCompressedTexImageARB*(target: TGLenum, lod: TGLint, img: PGLvoid){.
+    dynlib: dllname, importc: "glGetCompressedTexImageARB".}
+  #***** GL_ARB_texture_env_combine *****//
+const 
+  GL_COMBINE_ARB* = 0x00008570
+  GL_COMBINE_RGB_ARB* = 0x00008571
+  GL_COMBINE_ALPHA_ARB* = 0x00008572
+  GL_SOURCE0_RGB_ARB* = 0x00008580
+  GL_SOURCE1_RGB_ARB* = 0x00008581
+  GL_SOURCE2_RGB_ARB* = 0x00008582
+  GL_SOURCE0_ALPHA_ARB* = 0x00008588
+  GL_SOURCE1_ALPHA_ARB* = 0x00008589
+  GL_SOURCE2_ALPHA_ARB* = 0x0000858A
+  GL_OPERAND0_RGB_ARB* = 0x00008590
+  GL_OPERAND1_RGB_ARB* = 0x00008591
+  GL_OPERAND2_RGB_ARB* = 0x00008592
+  GL_OPERAND0_ALPHA_ARB* = 0x00008598
+  GL_OPERAND1_ALPHA_ARB* = 0x00008599
+  GL_OPERAND2_ALPHA_ARB* = 0x0000859A
+  GL_RGB_SCALE_ARB* = 0x00008573
+  GL_ADD_SIGNED_ARB* = 0x00008574
+  GL_INTERPOLATE_ARB* = 0x00008575
+  GL_SUBTRACT_ARB* = 0x000084E7
+  GL_CONSTANT_ARB* = 0x00008576
+  GL_PRIMARY_COLOR_ARB* = 0x00008577
+  GL_PREVIOUS_ARB* = 0x00008578
+  #***** GL_ARB_texture_env_crossbar *****//
+  #***** GL_ARB_texture_env_dot3 *****//
+
+const 
+  GL_DOT3_RGB_ARB* = 0x000086AE
+  GL_DOT3_RGBA_ARB* = 0x000086AF
+  #***** GL_ARB_texture_mirrored_repeat *****//
+
+const 
+  GL_MIRRORED_REPEAT_ARB* = 0x00008370
+  #***** GL_ARB_vertex_blend *****//
+
+const 
+  GL_MAX_VERTEX_UNITS_ARB* = 0x000086A4
+  GL_ACTIVE_VERTEX_UNITS_ARB* = 0x000086A5
+  GL_WEIGHT_SUM_UNITY_ARB* = 0x000086A6
+  constGL_VERTEX_BLEND_ARB* = 0x000086A7
+  GL_MODELVIEW0_ARB* = 0x00001700
+  GL_MODELVIEW1_ARB* = 0x0000850A
+  GL_MODELVIEW2_ARB* = 0x00008722
+  GL_MODELVIEW3_ARB* = 0x00008723
+  GL_MODELVIEW4_ARB* = 0x00008724
+  GL_MODELVIEW5_ARB* = 0x00008725
+  GL_MODELVIEW6_ARB* = 0x00008726
+  GL_MODELVIEW7_ARB* = 0x00008727
+  GL_MODELVIEW8_ARB* = 0x00008728
+  GL_MODELVIEW9_ARB* = 0x00008729
+  GL_MODELVIEW10_ARB* = 0x0000872A
+  GL_MODELVIEW11_ARB* = 0x0000872B
+  GL_MODELVIEW12_ARB* = 0x0000872C
+  GL_MODELVIEW13_ARB* = 0x0000872D
+  GL_MODELVIEW14_ARB* = 0x0000872E
+  GL_MODELVIEW15_ARB* = 0x0000872F
+  GL_MODELVIEW16_ARB* = 0x00008730
+  GL_MODELVIEW17_ARB* = 0x00008731
+  GL_MODELVIEW18_ARB* = 0x00008732
+  GL_MODELVIEW19_ARB* = 0x00008733
+  GL_MODELVIEW20_ARB* = 0x00008734
+  GL_MODELVIEW21_ARB* = 0x00008735
+  GL_MODELVIEW22_ARB* = 0x00008736
+  GL_MODELVIEW23_ARB* = 0x00008737
+  GL_MODELVIEW24_ARB* = 0x00008738
+  GL_MODELVIEW25_ARB* = 0x00008739
+  GL_MODELVIEW26_ARB* = 0x0000873A
+  GL_MODELVIEW27_ARB* = 0x0000873B
+  GL_MODELVIEW28_ARB* = 0x0000873C
+  GL_MODELVIEW29_ARB* = 0x0000873D
+  GL_MODELVIEW30_ARB* = 0x0000873E
+  GL_MODELVIEW31_ARB* = 0x0000873F
+  GL_CURRENT_WEIGHT_ARB* = 0x000086A8
+  GL_WEIGHT_ARRAY_TYPE_ARB* = 0x000086A9
+  GL_WEIGHT_ARRAY_STRIDE_ARB* = 0x000086AA
+  GL_WEIGHT_ARRAY_SIZE_ARB* = 0x000086AB
+  GL_WEIGHT_ARRAY_POINTER_ARB* = 0x000086AC
+  GL_WEIGHT_ARRAY_ARB* = 0x000086AD
+
+const 
+  GL_VERTEX_PROGRAM_ARB* = 0x00008620
+  GL_VERTEX_PROGRAM_POINT_SIZE_ARB* = 0x00008642
+  GL_VERTEX_PROGRAM_TWO_SIDE_ARB* = 0x00008643
+  GL_COLOR_SUM_ARB* = 0x00008458
+  GL_PROGRAM_FORMAT_ASCII_ARB* = 0x00008875
+  GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB* = 0x00008622
+  GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB* = 0x00008623
+  GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB* = 0x00008624
+  GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB* = 0x00008625
+  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB* = 0x0000886A
+  GL_CURRENT_VERTEX_ATTRIB_ARB* = 0x00008626
+  GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB* = 0x00008645
+  GL_PROGRAM_LENGTH_ARB* = 0x00008627
+  GL_PROGRAM_FORMAT_ARB* = 0x00008876
+  GL_PROGRAM_BINDING_ARB* = 0x00008677
+  GL_PROGRAM_INSTRUCTIONS_ARB* = 0x000088A0
+  GL_MAX_PROGRAM_INSTRUCTIONS_ARB* = 0x000088A1
+  GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB* = 0x000088A2
+  GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB* = 0x000088A3
+  GL_PROGRAM_TEMPORARIES_ARB* = 0x000088A4
+  GL_MAX_PROGRAM_TEMPORARIES_ARB* = 0x000088A5
+  GL_PROGRAM_NATIVE_TEMPORARIES_ARB* = 0x000088A6
+  GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB* = 0x000088A7
+  GL_PROGRAM_PARAMETERS_ARB* = 0x000088A8
+  GL_MAX_PROGRAM_PARAMETERS_ARB* = 0x000088A9
+  GL_PROGRAM_NATIVE_PARAMETERS_ARB* = 0x000088AA
+  GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB* = 0x000088AB
+  GL_PROGRAM_ATTRIBS_ARB* = 0x000088AC
+  GL_MAX_PROGRAM_ATTRIBS_ARB* = 0x000088AD
+  GL_PROGRAM_NATIVE_ATTRIBS_ARB* = 0x000088AE
+  GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB* = 0x000088AF
+  GL_PROGRAM_ADDRESS_REGISTERS_ARB* = 0x000088B0
+  GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB* = 0x000088B1
+  GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB* = 0x000088B2
+  GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB* = 0x000088B3
+  GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB* = 0x000088B4
+  GL_MAX_PROGRAM_ENV_PARAMETERS_ARB* = 0x000088B5
+  GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB* = 0x000088B6
+  constGL_PROGRAM_STRING_ARB* = 0x00008628
+  GL_PROGRAM_ERROR_POSITION_ARB* = 0x0000864B
+  GL_CURRENT_MATRIX_ARB* = 0x00008641
+  GL_TRANSPOSE_CURRENT_MATRIX_ARB* = 0x000088B7
+  GL_CURRENT_MATRIX_STACK_DEPTH_ARB* = 0x00008640
+  GL_MAX_VERTEX_ATTRIBS_ARB* = 0x00008869
+  GL_MAX_PROGRAM_MATRICES_ARB* = 0x0000862F
+  GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB* = 0x0000862E
+  GL_PROGRAM_ERROR_STRING_ARB* = 0x00008874
+  GL_MATRIX0_ARB* = 0x000088C0
+  GL_MATRIX1_ARB* = 0x000088C1
+  GL_MATRIX2_ARB* = 0x000088C2
+  GL_MATRIX3_ARB* = 0x000088C3
+  GL_MATRIX4_ARB* = 0x000088C4
+  GL_MATRIX5_ARB* = 0x000088C5
+  GL_MATRIX6_ARB* = 0x000088C6
+  GL_MATRIX7_ARB* = 0x000088C7
+  GL_MATRIX8_ARB* = 0x000088C8
+  GL_MATRIX9_ARB* = 0x000088C9
+  GL_MATRIX10_ARB* = 0x000088CA
+  GL_MATRIX11_ARB* = 0x000088CB
+  GL_MATRIX12_ARB* = 0x000088CC
+  GL_MATRIX13_ARB* = 0x000088CD
+  GL_MATRIX14_ARB* = 0x000088CE
+  GL_MATRIX15_ARB* = 0x000088CF
+  GL_MATRIX16_ARB* = 0x000088D0
+  GL_MATRIX17_ARB* = 0x000088D1
+  GL_MATRIX18_ARB* = 0x000088D2
+  GL_MATRIX19_ARB* = 0x000088D3
+  GL_MATRIX20_ARB* = 0x000088D4
+  GL_MATRIX21_ARB* = 0x000088D5
+  GL_MATRIX22_ARB* = 0x000088D6
+  GL_MATRIX23_ARB* = 0x000088D7
+  GL_MATRIX24_ARB* = 0x000088D8
+  GL_MATRIX25_ARB* = 0x000088D9
+  GL_MATRIX26_ARB* = 0x000088DA
+  GL_MATRIX27_ARB* = 0x000088DB
+  GL_MATRIX28_ARB* = 0x000088DC
+  GL_MATRIX29_ARB* = 0x000088DD
+  GL_MATRIX30_ARB* = 0x000088DE
+  GL_MATRIX31_ARB* = 0x000088DF
+
+const 
+  GL_422_EXT* = 0x000080CC
+  GL_422_REV_EXT* = 0x000080CD
+  GL_422_AVERAGE_EXT* = 0x000080CE
+  GL_422_REV_AVERAGE_EXT* = 0x000080CF
+  #***** GL_EXT_abgr *****//
+
+const 
+  GL_ABGR_EXT* = 0x00008000
+  #***** GL_EXT_bgra *****//
+
+const 
+  GL_BGR_EXT* = 0x000080E0
+  GL_BGRA_EXT* = 0x000080E1
+  #***** GL_EXT_blend_color *****//
+
+const 
+  GL_CONSTANT_COLOR_EXT* = 0x00008001
+  GL_ONE_MINUS_CONSTANT_COLOR_EXT* = 0x00008002
+  GL_CONSTANT_ALPHA_EXT* = 0x00008003
+  GL_ONE_MINUS_CONSTANT_ALPHA_EXT* = 0x00008004
+  constGL_BLEND_COLOR_EXT* = 0x00008005
+
+proc glBlendColorEXT*(red: TGLclampf, green: TGLclampf, blue: TGLclampf, 
+                      alpha: TGLclampf){.dynlib: dllname, 
+    importc: "glBlendColorEXT".}
+  #***** GL_EXT_blend_func_separate *****//
+const 
+  GL_BLEND_DST_RGB_EXT* = 0x000080C8
+  GL_BLEND_SRC_RGB_EXT* = 0x000080C9
+  GL_BLEND_DST_ALPHA_EXT* = 0x000080CA
+  GL_BLEND_SRC_ALPHA_EXT* = 0x000080CB
+
+proc glBlendFuncSeparateEXT*(sfactorRGB: TGLenum, dfactorRGB: TGLenum, 
+                             sfactorAlpha: TGLenum, dfactorAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendFuncSeparateEXT".}
+  #***** GL_EXT_blend_logic_op *****//
+  #***** GL_EXT_blend_minmax *****//
+const 
+  GL_FUNC_ADD_EXT* = 0x00008006
+  GL_MIN_EXT* = 0x00008007
+  GL_MAX_EXT* = 0x00008008
+  constGL_BLEND_EQUATION_EXT* = 0x00008009
+
+proc glBlendEquationEXT*(mode: TGLenum){.dynlib: dllname, 
+    importc: "glBlendEquationEXT".}
+  #***** GL_EXT_blend_subtract *****//
+const 
+  GL_FUNC_SUBTRACT_EXT* = 0x0000800A
+  GL_FUNC_REVERSE_SUBTRACT_EXT* = 0x0000800B
+  #***** GL_EXT_clip_volume_hint *****//
+
+const 
+  GL_CLIP_VOLUME_CLIPPING_HINT_EXT* = 0x000080F0
+  #***** GL_EXT_color_subtable *****//
+
+proc glColorSubTableEXT*(target: TGLenum, start: TGLsizei, count: TGLsizei, 
+                         format: TGLenum, thetype: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glColorSubTableEXT".}
+proc glCopyColorSubTableEXT*(target: TGLenum, start: TGLsizei, x: TGLint, 
+                             y: TGLint, width: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyColorSubTableEXT".}
+  #***** GL_EXT_compiled_vertex_array *****//
+const 
+  GL_ARRAY_ELEMENT_LOCK_FIRST_EXT* = 0x000081A8
+  GL_ARRAY_ELEMENT_LOCK_COUNT_EXT* = 0x000081A9
+
+proc glLockArraysEXT*(first: TGLint, count: TGLsizei){.dynlib: dllname, 
+    importc: "glLockArraysEXT".}
+proc glUnlockArraysEXT*(){.dynlib: dllname, importc: "glUnlockArraysEXT".}
+  #***** GL_EXT_convolution *****//
+const 
+  GL_CONVOLUTION_1D_EXT* = 0x00008010
+  GL_CONVOLUTION_2D_EXT* = 0x00008011
+  GL_SEPARABLE_2D_EXT* = 0x00008012
+  GL_CONVOLUTION_BORDER_MODE_EXT* = 0x00008013
+  GL_CONVOLUTION_FILTER_SCALE_EXT* = 0x00008014
+  GL_CONVOLUTION_FILTER_BIAS_EXT* = 0x00008015
+  GL_REDUCE_EXT* = 0x00008016
+  GL_CONVOLUTION_FORMAT_EXT* = 0x00008017
+  GL_CONVOLUTION_WIDTH_EXT* = 0x00008018
+  GL_CONVOLUTION_HEIGHT_EXT* = 0x00008019
+  GL_MAX_CONVOLUTION_WIDTH_EXT* = 0x0000801A
+  GL_MAX_CONVOLUTION_HEIGHT_EXT* = 0x0000801B
+  GL_POST_CONVOLUTION_RED_SCALE_EXT* = 0x0000801C
+  GL_POST_CONVOLUTION_GREEN_SCALE_EXT* = 0x0000801D
+  GL_POST_CONVOLUTION_BLUE_SCALE_EXT* = 0x0000801E
+  GL_POST_CONVOLUTION_ALPHA_SCALE_EXT* = 0x0000801F
+  GL_POST_CONVOLUTION_RED_BIAS_EXT* = 0x00008020
+  GL_POST_CONVOLUTION_GREEN_BIAS_EXT* = 0x00008021
+  GL_POST_CONVOLUTION_BLUE_BIAS_EXT* = 0x00008022
+  GL_POST_CONVOLUTION_ALPHA_BIAS_EXT* = 0x00008023
+
+proc glConvolutionFilter1DEXT*(target: TGLenum, internalformat: TGLenum, 
+                               width: TGLsizei, format: TGLenum, 
+                               thetype: TGLenum, image: PGLvoid){.
+    dynlib: dllname, importc: "glConvolutionFilter1DEXT".}
+proc glConvolutionFilter2DEXT*(target: TGLenum, internalformat: TGLenum, 
+                               width: TGLsizei, height: TGLsizei, 
+                               format: TGLenum, thetype: TGLenum, image: PGLvoid){.
+    dynlib: dllname, importc: "glConvolutionFilter2DEXT".}
+proc glCopyConvolutionFilter1DEXT*(target: TGLenum, internalformat: TGLenum, 
+                                   x: TGLint, y: TGLint, width: TGLsizei){.
+    dynlib: dllname, importc: "glCopyConvolutionFilter1DEXT".}
+proc glCopyConvolutionFilter2DEXT*(target: TGLenum, internalformat: TGLenum, 
+                                   x: TGLint, y: TGLint, width: TGLsizei, 
+                                   height: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyConvolutionFilter2DEXT".}
+proc glGetConvolutionFilterEXT*(target: TGLenum, format: TGLenum, 
+                                thetype: TGLenum, image: PGLvoid){.
+    dynlib: dllname, importc: "glGetConvolutionFilterEXT".}
+proc glSeparableFilter2DEXT*(target: TGLenum, internalformat: TGLenum, 
+                             width: TGLsizei, height: TGLsizei, format: TGLenum, 
+                             thetype: TGLenum, row: PGLvoid, column: PGLvoid){.
+    dynlib: dllname, importc: "glSeparableFilter2DEXT".}
+proc glGetSeparableFilterEXT*(target: TGLenum, format: TGLenum, 
+                              thetype: TGLenum, row: PGLvoid, column: PGLvoid, 
+                              span: PGLvoid){.dynlib: dllname, 
+    importc: "glGetSeparableFilterEXT".}
+proc glConvolutionParameteriEXT*(target: TGLenum, pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glConvolutionParameteriEXT".}
+proc glConvolutionParameterivEXT*(target: TGLenum, pname: TGLenum, 
+                                  params: PGLint){.dynlib: dllname, 
+    importc: "glConvolutionParameterivEXT".}
+proc glConvolutionParameterfEXT*(target: TGLenum, pname: TGLenum, 
+                                 param: TGLfloat){.dynlib: dllname, 
+    importc: "glConvolutionParameterfEXT".}
+proc glConvolutionParameterfvEXT*(target: TGLenum, pname: TGLenum, 
+                                  params: PGLfloat){.dynlib: dllname, 
+    importc: "glConvolutionParameterfvEXT".}
+proc glGetConvolutionParameterivEXT*(target: TGLenum, pname: TGLenum, 
+                                     params: PGLint){.dynlib: dllname, 
+    importc: "glGetConvolutionParameterivEXT".}
+proc glGetConvolutionParameterfvEXT*(target: TGLenum, pname: TGLenum, 
+                                     params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetConvolutionParameterfvEXT".}
+  #***** GL_EXT_fog_coord *****//
+const 
+  GL_FOG_COORDINATE_SOURCE_EXT* = 0x00008450
+  GL_FOG_COORDINATE_EXT* = 0x00008451
+  GL_FRAGMENT_DEPTH_EXT* = 0x00008452
+  GL_CURRENT_FOG_COORDINATE_EXT* = 0x00008453
+  GL_FOG_COORDINATE_ARRAY_TYPE_EXT* = 0x00008454
+  GL_FOG_COORDINATE_ARRAY_STRIDE_EXT* = 0x00008455
+  GL_FOG_COORDINATE_ARRAY_POINTER_EXT* = 0x00008456
+  GL_FOG_COORDINATE_ARRAY_EXT* = 0x00008457
+
+proc glFogCoordfEXfloat*(coord: TGLfloat){.dynlib: dllname, 
+    importc: "glFogCoordfEXfloat".}
+proc glFogCoorddEXdouble*(coord: TGLdouble){.dynlib: dllname, 
+    importc: "glFogCoorddEXdouble".}
+proc glFogCoordfvEXfloat*(coord: TGLfloat){.dynlib: dllname, 
+    importc: "glFogCoordfvEXfloat".}
+proc glFogCoorddvEXdouble*(coord: TGLdouble){.dynlib: dllname, 
+    importc: "glFogCoorddvEXdouble".}
+proc glFogCoordPointerEXT*(thetype: TGLenum, stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glFogCoordPointerEXT".}
+  #***** GL_EXT_histogram *****//
+const 
+  constGL_HISTOGRAM_EXT* = 0x00008024
+  GL_PROXY_HISTOGRAM_EXT* = 0x00008025
+  GL_HISTOGRAM_WIDTH_EXT* = 0x00008026
+  GL_HISTOGRAM_FORMAT_EXT* = 0x00008027
+  GL_HISTOGRAM_RED_SIZE_EXT* = 0x00008028
+  GL_HISTOGRAM_GREEN_SIZE_EXT* = 0x00008029
+  GL_HISTOGRAM_BLUE_SIZE_EXT* = 0x0000802A
+  GL_HISTOGRAM_ALPHA_SIZE_EXT* = 0x0000802B
+  GL_HISTOGRAM_LUMINANCE_SIZE_EXT* = 0x0000802C
+  GL_HISTOGRAM_SINK_EXT* = 0x0000802D
+  constGL_MINMAX_EXT* = 0x0000802E
+  GL_MINMAX_FORMAT_EXT* = 0x0000802F
+  GL_MINMAX_SINK_EXT* = 0x00008030
+
+proc glHistogramEXT*(target: TGLenum, width: TGLsizei, internalformat: TGLenum, 
+                     sink: TGLboolean){.dynlib: dllname, 
+                                        importc: "glHistogramEXT".}
+proc glResetHistogramEXT*(target: TGLenum){.dynlib: dllname, 
+    importc: "glResetHistogramEXT".}
+proc glGetHistogramEXT*(target: TGLenum, reset: TGLboolean, format: TGLenum, 
+                        thetype: TGLenum, values: PGLvoid){.dynlib: dllname, 
+    importc: "glGetHistogramEXT".}
+proc glGetHistogramParameterivEXT*(target: TGLenum, pname: TGLenum, 
+                                   params: PGLint){.dynlib: dllname, 
+    importc: "glGetHistogramParameterivEXT".}
+proc glGetHistogramParameterfvEXT*(target: TGLenum, pname: TGLenum, 
+                                   params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetHistogramParameterfvEXT".}
+proc glMinmaxEXT*(target: TGLenum, internalformat: TGLenum, sink: TGLboolean){.
+    dynlib: dllname, importc: "glMinmaxEXT".}
+proc glResetMinmaxEXT*(target: TGLenum){.dynlib: dllname, 
+    importc: "glResetMinmaxEXT".}
+proc glGetMinmaxEXT*(target: TGLenum, reset: TGLboolean, format: TGLenum, 
+                     thetype: TGLenum, values: PGLvoid){.dynlib: dllname, 
+    importc: "glGetMinmaxEXT".}
+proc glGetMinmaxParameterivEXT*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMinmaxParameterivEXT".}
+proc glGetMinmaxParameterfvEXT*(target: TGLenum, pname: TGLenum, 
+                                params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetMinmaxParameterfvEXT".}
+  #***** GL_EXT_multi_draw_arrays *****//
+proc glMultiDrawArraysEXT*(mode: TGLenum, first: PGLint, count: PGLsizei, 
+                           primcount: TGLsizei){.dynlib: dllname, 
+    importc: "glMultiDrawArraysEXT".}
+proc glMultiDrawElementsEXT*(mode: TGLenum, count: PGLsizei, thetype: TGLenum, 
+                             indices: PGLvoid, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawElementsEXT".}
+  #***** GL_EXT_packed_pixels *****//
+const 
+  GL_UNSIGNED_BYTE_3_3_2_EXT* = 0x00008032
+  GL_UNSIGNED_SHORT_4_4_4_4_EXT* = 0x00008033
+  GL_UNSIGNED_SHORT_5_5_5_1_EXT* = 0x00008034
+  GL_UNSIGNED_INT_8_8_8_8_EXT* = 0x00008035
+  GL_UNSIGNED_INT_10_10_10_2_EXT* = 0x00008036
+  #***** GL_EXT_paletted_texture *****//
+
+const 
+  GL_COLOR_INDEX1_EXT* = 0x000080E2
+  GL_COLOR_INDEX2_EXT* = 0x000080E3
+  GL_COLOR_INDEX4_EXT* = 0x000080E4
+  GL_COLOR_INDEX8_EXT* = 0x000080E5
+  GL_COLOR_INDEX12_EXT* = 0x000080E6
+  GL_COLOR_INDEX16_EXT* = 0x000080E7
+  GL_COLOR_TABLE_FORMAT_EXT* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH_EXT* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE_EXT* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE_EXT* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE_EXT* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE_EXT* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE_EXT* = 0x000080DF
+  GL_TEXTURE_INDEX_SIZE_EXT* = 0x000080ED
+  GL_TEXTURE_1D* = 0x00000DE0
+  GL_TEXTURE_2D* = 0x00000DE1
+  GL_TEXTURE_3D_EXT* = 0x0000806F # GL_TEXTURE_CUBE_MAP_ARB  { already defined }
+  GL_PROXY_TEXTURE_1D* = 0x00008063
+  GL_PROXY_TEXTURE_2D* = 0x00008064
+  GL_PROXY_TEXTURE_3D_EXT* = 0x00008070 # GL_PROXY_TEXTURE_CUBE_MAP_ARB  { already defined }
+                                        # GL_TEXTURE_1D  { already defined }
+                                        # GL_TEXTURE_2D  { already defined }
+                                        # GL_TEXTURE_3D_EXT  { already defined }
+                                        # GL_TEXTURE_CUBE_MAP_ARB  { already defined }
+
+proc glColorTableEXT*(target: TGLenum, internalFormat: TGLenum, width: TGLsizei, 
+                      format: TGLenum, thetype: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glColorTableEXT".}
+  # glColorSubTableEXT  { already defined }
+proc glGetColorTableEXT*(target: TGLenum, format: TGLenum, thetype: TGLenum, 
+                         data: PGLvoid){.dynlib: dllname, 
+    importc: "glGetColorTableEXT".}
+proc glGetColorTableParameterivEXT*(target: TGLenum, pname: TGLenum, 
+                                    params: PGLint){.dynlib: dllname, 
+    importc: "glGetColorTableParameterivEXT".}
+proc glGetColorTableParameterfvEXT*(target: TGLenum, pname: TGLenum, 
+                                    params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetColorTableParameterfvEXT".}
+  #***** GL_EXT_point_parameters *****//
+const 
+  GL_POINT_SIZE_MIN_EXT* = 0x00008126
+  GL_POINT_SIZE_MAX_EXT* = 0x00008127
+  GL_POINT_FADE_THRESHOLD_SIZE_EXT* = 0x00008128
+  GL_DISTANCE_ATTENUATION_EXT* = 0x00008129
+
+proc glPointParameterfEXT*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glPointParameterfEXT".}
+proc glPointParameterfvEXT*(pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glPointParameterfvEXT".}
+  #***** GL_EXT_polygon_offset *****//
+const 
+  constGL_POLYGON_OFFSET_EXT* = 0x00008037
+  GL_POLYGON_OFFSET_FACTOR_EXT* = 0x00008038
+  GL_POLYGON_OFFSET_BIAS_EXT* = 0x00008039
+
+proc glPolygonOffsetEXT*(factor: TGLfloat, bias: TGLfloat){.dynlib: dllname, 
+    importc: "glPolygonOffsetEXT".}
+  #***** GL_EXT_secondary_color *****//
+const 
+  GL_COLOR_SUM_EXT* = 0x00008458
+  GL_CURRENT_SECONDARY_COLOR_EXT* = 0x00008459
+  GL_SECONDARY_COLOR_ARRAY_SIZE_EXT* = 0x0000845A
+  GL_SECONDARY_COLOR_ARRAY_TYPE_EXT* = 0x0000845B
+  GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT* = 0x0000845C
+  GL_SECONDARY_COLOR_ARRAY_POINTER_EXT* = 0x0000845D
+  GL_SECONDARY_COLOR_ARRAY_EXT* = 0x0000845E
+
+proc glSecondaryColor3bEXT*(components: TGLbyte){.dynlib: dllname, 
+    importc: "glSecondaryColor3bEXT".}
+proc glSecondaryColor3sEXT*(components: TGLshort){.dynlib: dllname, 
+    importc: "glSecondaryColor3sEXT".}
+proc glSecondaryColor3iEXT*(components: TGLint){.dynlib: dllname, 
+    importc: "glSecondaryColor3iEXT".}
+proc glSecondaryColor3fEXT*(components: TGLfloat){.dynlib: dllname, 
+    importc: "glSecondaryColor3fEXT".}
+proc glSecondaryColor3dEXT*(components: TGLdouble){.dynlib: dllname, 
+    importc: "glSecondaryColor3dEXT".}
+proc glSecondaryColor3ubEXT*(components: TGLubyte){.dynlib: dllname, 
+    importc: "glSecondaryColor3ubEXT".}
+proc glSecondaryColor3usEXT*(components: TGLushort){.dynlib: dllname, 
+    importc: "glSecondaryColor3usEXT".}
+proc glSecondaryColor3uiEXT*(components: TGLuint){.dynlib: dllname, 
+    importc: "glSecondaryColor3uiEXT".}
+proc glSecondaryColor3bvEXT*(components: TGLbyte){.dynlib: dllname, 
+    importc: "glSecondaryColor3bvEXT".}
+proc glSecondaryColor3svEXT*(components: TGLshort){.dynlib: dllname, 
+    importc: "glSecondaryColor3svEXT".}
+proc glSecondaryColor3ivEXT*(components: TGLint){.dynlib: dllname, 
+    importc: "glSecondaryColor3ivEXT".}
+proc glSecondaryColor3fvEXT*(components: TGLfloat){.dynlib: dllname, 
+    importc: "glSecondaryColor3fvEXT".}
+proc glSecondaryColor3dvEXT*(components: TGLdouble){.dynlib: dllname, 
+    importc: "glSecondaryColor3dvEXT".}
+proc glSecondaryColor3ubvEXT*(components: TGLubyte){.dynlib: dllname, 
+    importc: "glSecondaryColor3ubvEXT".}
+proc glSecondaryColor3usvEXT*(components: TGLushort){.dynlib: dllname, 
+    importc: "glSecondaryColor3usvEXT".}
+proc glSecondaryColor3uivEXT*(components: TGLuint){.dynlib: dllname, 
+    importc: "glSecondaryColor3uivEXT".}
+proc glSecondaryColorPointerEXT*(size: TGLint, thetype: TGLenum, 
+                                 stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glSecondaryColorPointerEXT".}
+  #***** GL_EXT_separate_specular_color *****//
+const 
+  GL_LIGHT_MODEL_COLOR_CONTROL_EXT* = 0x000081F8
+  GL_SINGLE_COLOR_EXT* = 0x000081F9
+  GL_SEPARATE_SPECULAR_COLOR_EXT* = 0x000081FA
+  #***** GL_EXT_shadow_funcs *****//
+  #***** GL_EXT_shared_texture_palette *****//
+
+const 
+  GL_SHARED_TEXTURE_PALETTE_EXT* = 0x000081FB
+  #***** GL_EXT_stencil_two_side *****//
+
+const 
+  GL_STENCIL_TEST_TWO_SIDE_EXT* = 0x00008910
+  constGL_ACTIVE_STENCIL_FACE_EXT* = 0x00008911
+
+proc glActiveStencilFaceEXT*(face: TGLenum){.dynlib: dllname, 
+    importc: "glActiveStencilFaceEXT".}
+  #***** GL_EXT_stencil_wrap *****//
+const 
+  GL_INCR_WRAP_EXT* = 0x00008507
+  GL_DECR_WRAP_EXT* = 0x00008508
+  #***** GL_EXT_subtexture *****//
+
+proc glTexSubImage1DEXT*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                         width: TGLsizei, format: TGLenum, thetype: TGLenum, 
+                         pixels: PGLvoid){.dynlib: dllname, 
+    importc: "glTexSubImage1DEXT".}
+proc glTexSubImage2DEXT*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                         yoffset: TGLint, width: TGLsizei, height: TGLsizei, 
+                         format: TGLenum, thetype: TGLenum, pixels: PGLvoid){.
+    dynlib: dllname, importc: "glTexSubImage2DEXT".}
+proc glTexSubImage3DEXT*(target: TGLenum, level: TGLint, xoffset: TGLint, 
+                         yoffset: TGLint, zoffset: TGLint, width: TGLsizei, 
+                         height: TGLsizei, depth: TGLsizei, format: TGLenum, 
+                         thetype: TGLenum, pixels: PGLvoid){.dynlib: dllname, 
+    importc: "glTexSubImage3DEXT".}
+  #***** GL_EXT_texture3D *****//
+const 
+  GL_PACK_SKIP_IMAGES_EXT* = 0x0000806B
+  GL_PACK_IMAGE_HEIGHT_EXT* = 0x0000806C
+  GL_UNPACK_SKIP_IMAGES_EXT* = 0x0000806D
+  GL_UNPACK_IMAGE_HEIGHT_EXT* = 0x0000806E # GL_TEXTURE_3D_EXT  { already defined }
+                                           # GL_PROXY_TEXTURE_3D_EXT  { already defined }
+  GL_TEXTURE_DEPTH_EXT* = 0x00008071
+  GL_TEXTURE_WRAP_R_EXT* = 0x00008072
+  GL_MAX_3D_TEXTURE_SIZE_EXT* = 0x00008073
+
+proc glTexImage3DEXT*(target: TGLenum, level: TGLint, internalformat: TGLenum, 
+                      width: TGLsizei, height: TGLsizei, depth: TGLsizei, 
+                      border: TGLint, format: TGLenum, thetype: TGLenum, 
+                      pixels: PGLvoid){.dynlib: dllname, 
+                                        importc: "glTexImage3DEXT".}
+  #***** GL_EXT_texture_compression_s3tc *****//
+const 
+  GL_COMPRESSED_RGB_S3TC_DXT1_EXT* = 0x000083F0
+  GL_COMPRESSED_RGBA_S3TC_DXT1_EXT* = 0x000083F1
+  GL_COMPRESSED_RGBA_S3TC_DXT3_EXT* = 0x000083F2
+  GL_COMPRESSED_RGBA_S3TC_DXT5_EXT* = 0x000083F3
+  #***** GL_EXT_texture_env_add *****//
+  #***** GL_EXT_texture_env_combine *****//
+
+const 
+  GL_COMBINE_EXT* = 0x00008570
+  GL_COMBINE_RGB_EXT* = 0x00008571
+  GL_COMBINE_ALPHA_EXT* = 0x00008572
+  GL_SOURCE0_RGB_EXT* = 0x00008580
+  GL_SOURCE1_RGB_EXT* = 0x00008581
+  GL_SOURCE2_RGB_EXT* = 0x00008582
+  GL_SOURCE0_ALPHA_EXT* = 0x00008588
+  GL_SOURCE1_ALPHA_EXT* = 0x00008589
+  GL_SOURCE2_ALPHA_EXT* = 0x0000858A
+  GL_OPERAND0_RGB_EXT* = 0x00008590
+  GL_OPERAND1_RGB_EXT* = 0x00008591
+  GL_OPERAND2_RGB_EXT* = 0x00008592
+  GL_OPERAND0_ALPHA_EXT* = 0x00008598
+  GL_OPERAND1_ALPHA_EXT* = 0x00008599
+  GL_OPERAND2_ALPHA_EXT* = 0x0000859A
+  GL_RGB_SCALE_EXT* = 0x00008573
+  GL_ADD_SIGNED_EXT* = 0x00008574
+  GL_INTERPOLATE_EXT* = 0x00008575
+  GL_CONSTANT_EXT* = 0x00008576
+  GL_PRIMARY_COLOR_EXT* = 0x00008577
+  GL_PREVIOUS_EXT* = 0x00008578
+  #***** GL_EXT_texture_env_dot3 *****//
+
+const 
+  GL_DOT3_RGB_EXT* = 0x00008740
+  GL_DOT3_RGBA_EXT* = 0x00008741
+  #***** GL_EXT_texture_filter_anisotropic *****//
+
+const 
+  GL_TEXTURE_MAX_ANISOTROPY_EXT* = 0x000084FE
+  GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT* = 0x000084FF
+  #***** GL_EXT_texture_lod_bias *****//
+
+const 
+  GL_TEXTURE_FILTER_CONTROL_EXT* = 0x00008500
+  GL_TEXTURE_LOD_BIAS_EXT* = 0x00008501
+  GL_MAX_TEXTURE_LOD_BIAS_EXT* = 0x000084FD
+  #***** GL_EXT_texture_object *****//
+
+const 
+  GL_TEXTURE_PRIORITY_EXT* = 0x00008066
+  GL_TEXTURE_RESIDENT_EXT* = 0x00008067
+  GL_TEXTURE_1D_BINDING_EXT* = 0x00008068
+  GL_TEXTURE_2D_BINDING_EXT* = 0x00008069
+  GL_TEXTURE_3D_BINDING_EXT* = 0x0000806A
+
+proc glGenTexturesEXT*(n: TGLsizei, textures: PGLuint){.dynlib: dllname, 
+    importc: "glGenTexturesEXT".}
+proc glDeleteTexturesEXT*(n: TGLsizei, textures: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteTexturesEXT".}
+proc glBindTextureEXT*(target: TGLenum, texture: TGLuint){.dynlib: dllname, 
+    importc: "glBindTextureEXT".}
+proc glPrioritizeTexturesEXT*(n: TGLsizei, textures: PGLuint, 
+                              priorities: PGLclampf){.dynlib: dllname, 
+    importc: "glPrioritizeTexturesEXT".}
+proc glAreTexturesResidentEXT*(n: TGLsizei, textures: PGLuint, 
+                               residences: PGLboolean): TGLboolean{.
+    dynlib: dllname, importc: "glAreTexturesResidentEXT".}
+proc glIsTextureEXT*(texture: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsTextureEXT".}
+  #***** GL_EXT_vertex_array *****//
+const 
+  GL_VERTEX_ARRAY_EXT* = 0x00008074
+  GL_NORMAL_ARRAY_EXT* = 0x00008075
+  GL_COLOR_ARRAY_EXT* = 0x00008076
+  GL_INDEX_ARRAY_EXT* = 0x00008077
+  GL_TEXTURE_COORD_ARRAY_EXT* = 0x00008078
+  GL_EDGE_FLAG_ARRAY_EXT* = 0x00008079
+  GL_DOUBLE_EXT* = 0x0000140A
+  GL_VERTEX_ARRAY_SIZE_EXT* = 0x0000807A
+  GL_VERTEX_ARRAY_TYPE_EXT* = 0x0000807B
+  GL_VERTEX_ARRAY_STRIDE_EXT* = 0x0000807C
+  GL_VERTEX_ARRAY_COUNT_EXT* = 0x0000807D
+  GL_NORMAL_ARRAY_TYPE_EXT* = 0x0000807E
+  GL_NORMAL_ARRAY_STRIDE_EXT* = 0x0000807F
+  GL_NORMAL_ARRAY_COUNT_EXT* = 0x00008080
+  GL_COLOR_ARRAY_SIZE_EXT* = 0x00008081
+  GL_COLOR_ARRAY_TYPE_EXT* = 0x00008082
+  GL_COLOR_ARRAY_STRIDE_EXT* = 0x00008083
+  GL_COLOR_ARRAY_COUNT_EXT* = 0x00008084
+  GL_INDEX_ARRAY_TYPE_EXT* = 0x00008085
+  GL_INDEX_ARRAY_STRIDE_EXT* = 0x00008086
+  GL_INDEX_ARRAY_COUNT_EXT* = 0x00008087
+  GL_TEXTURE_COORD_ARRAY_SIZE_EXT* = 0x00008088
+  GL_TEXTURE_COORD_ARRAY_TYPE_EXT* = 0x00008089
+  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT* = 0x0000808A
+  GL_TEXTURE_COORD_ARRAY_COUNT_EXT* = 0x0000808B
+  GL_EDGE_FLAG_ARRAY_STRIDE_EXT* = 0x0000808C
+  GL_EDGE_FLAG_ARRAY_COUNT_EXT* = 0x0000808D
+  GL_VERTEX_ARRAY_POINTER_EXT* = 0x0000808E
+  GL_NORMAL_ARRAY_POINTER_EXT* = 0x0000808F
+  GL_COLOR_ARRAY_POINTER_EXT* = 0x00008090
+  GL_INDEX_ARRAY_POINTER_EXT* = 0x00008091
+  GL_TEXTURE_COORD_ARRAY_POINTER_EXT* = 0x00008092
+  GL_EDGE_FLAG_ARRAY_POINTER_EXT* = 0x00008093
+
+proc glArrayElementEXT*(i: TGLint){.dynlib: dllname, 
+                                    importc: "glArrayElementEXT".}
+proc glDrawArraysEXT*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawArraysEXT".}
+proc glVertexPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                         count: TGLsizei, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glVertexPointerEXT".}
+proc glNormalPointerEXT*(thetype: TGLenum, stride: TGLsizei, count: TGLsizei, 
+                         pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glNormalPointerEXT".}
+proc glColorPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                        count: TGLsizei, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glColorPointerEXT".}
+proc glIndexPointerEXT*(thetype: TGLenum, stride: TGLsizei, count: TGLsizei, 
+                        pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glIndexPointerEXT".}
+proc glTexCoordPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                           count: TGLsizei, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glTexCoordPointerEXT".}
+proc glEdgeFlagPointerEXT*(stride: TGLsizei, count: TGLsizei, 
+                           pointer: PGLboolean){.dynlib: dllname, 
+    importc: "glEdgeFlagPointerEXT".}
+proc glGetPointervEXT*(pname: TGLenum, params: PGLvoid){.dynlib: dllname, 
+    importc: "glGetPointervEXT".}
+  #***** GL_EXT_vertex_shader *****//
+const 
+  GL_VERTEX_SHADER_EXT* = 0x00008780
+  GL_VARIANT_VALUE_EXT* = 0x000087E4
+  GL_VARIANT_DATATYPE_EXT* = 0x000087E5
+  GL_VARIANT_ARRAY_STRIDE_EXT* = 0x000087E6
+  GL_VARIANT_ARRAY_TYPE_EXT* = 0x000087E7
+  GL_VARIANT_ARRAY_EXT* = 0x000087E8
+  GL_VARIANT_ARRAY_POINTER_EXT* = 0x000087E9
+  GL_INVARIANT_VALUE_EXT* = 0x000087EA
+  GL_INVARIANT_DATATYPE_EXT* = 0x000087EB
+  GL_LOCAL_CONSTANT_VALUE_EXT* = 0x000087EC
+  GL_LOCAL_CONSTANT_DATATYPE_EXT* = 0x000087ED
+  GL_OP_INDEX_EXT* = 0x00008782
+  GL_OP_NEGATE_EXT* = 0x00008783
+  GL_OP_DOT3_EXT* = 0x00008784
+  GL_OP_DOT4_EXT* = 0x00008785
+  GL_OP_MUL_EXT* = 0x00008786
+  GL_OP_ADD_EXT* = 0x00008787
+  GL_OP_MADD_EXT* = 0x00008788
+  GL_OP_FRAC_EXT* = 0x00008789
+  GL_OP_MAX_EXT* = 0x0000878A
+  GL_OP_MIN_EXT* = 0x0000878B
+  GL_OP_SET_GE_EXT* = 0x0000878C
+  GL_OP_SET_LT_EXT* = 0x0000878D
+  GL_OP_CLAMP_EXT* = 0x0000878E
+  GL_OP_FLOOR_EXT* = 0x0000878F
+  GL_OP_ROUND_EXT* = 0x00008790
+  GL_OP_EXP_BASE_2_EXT* = 0x00008791
+  GL_OP_LOG_BASE_2_EXT* = 0x00008792
+  GL_OP_POWER_EXT* = 0x00008793
+  GL_OP_RECIP_EXT* = 0x00008794
+  GL_OP_RECIP_SQRT_EXT* = 0x00008795
+  GL_OP_SUB_EXT* = 0x00008796
+  GL_OP_CROSS_PRODUCT_EXT* = 0x00008797
+  GL_OP_MULTIPLY_MATRIX_EXT* = 0x00008798
+  GL_OP_MOV_EXT* = 0x00008799
+  GL_OUTPUT_VERTEX_EXT* = 0x0000879A
+  GL_OUTPUT_COLOR0_EXT* = 0x0000879B
+  GL_OUTPUT_COLOR1_EXT* = 0x0000879C
+  GL_OUTPUT_TEXTURE_COORD0_EXT* = 0x0000879D
+  GL_OUTPUT_TEXTURE_COORD1_EXT* = 0x0000879E
+  GL_OUTPUT_TEXTURE_COORD2_EXT* = 0x0000879F
+  GL_OUTPUT_TEXTURE_COORD3_EXT* = 0x000087A0
+  GL_OUTPUT_TEXTURE_COORD4_EXT* = 0x000087A1
+  GL_OUTPUT_TEXTURE_COORD5_EXT* = 0x000087A2
+  GL_OUTPUT_TEXTURE_COORD6_EXT* = 0x000087A3
+  GL_OUTPUT_TEXTURE_COORD7_EXT* = 0x000087A4
+  GL_OUTPUT_TEXTURE_COORD8_EXT* = 0x000087A5
+  GL_OUTPUT_TEXTURE_COORD9_EXT* = 0x000087A6
+  GL_OUTPUT_TEXTURE_COORD10_EXT* = 0x000087A7
+  GL_OUTPUT_TEXTURE_COORD11_EXT* = 0x000087A8
+  GL_OUTPUT_TEXTURE_COORD12_EXT* = 0x000087A9
+  GL_OUTPUT_TEXTURE_COORD13_EXT* = 0x000087AA
+  GL_OUTPUT_TEXTURE_COORD14_EXT* = 0x000087AB
+  GL_OUTPUT_TEXTURE_COORD15_EXT* = 0x000087AC
+  GL_OUTPUT_TEXTURE_COORD16_EXT* = 0x000087AD
+  GL_OUTPUT_TEXTURE_COORD17_EXT* = 0x000087AE
+  GL_OUTPUT_TEXTURE_COORD18_EXT* = 0x000087AF
+  GL_OUTPUT_TEXTURE_COORD19_EXT* = 0x000087B0
+  GL_OUTPUT_TEXTURE_COORD20_EXT* = 0x000087B1
+  GL_OUTPUT_TEXTURE_COORD21_EXT* = 0x000087B2
+  GL_OUTPUT_TEXTURE_COORD22_EXT* = 0x000087B3
+  GL_OUTPUT_TEXTURE_COORD23_EXT* = 0x000087B4
+  GL_OUTPUT_TEXTURE_COORD24_EXT* = 0x000087B5
+  GL_OUTPUT_TEXTURE_COORD25_EXT* = 0x000087B6
+  GL_OUTPUT_TEXTURE_COORD26_EXT* = 0x000087B7
+  GL_OUTPUT_TEXTURE_COORD27_EXT* = 0x000087B8
+  GL_OUTPUT_TEXTURE_COORD28_EXT* = 0x000087B9
+  GL_OUTPUT_TEXTURE_COORD29_EXT* = 0x000087BA
+  GL_OUTPUT_TEXTURE_COORD30_EXT* = 0x000087BB
+  GL_OUTPUT_TEXTURE_COORD31_EXT* = 0x000087BC
+  GL_OUTPUT_FOG_EXT* = 0x000087BD
+  GL_SCALAR_EXT* = 0x000087BE
+  GL_VECTOR_EXT* = 0x000087BF
+  GL_MATRIX_EXT* = 0x000087C0
+  GL_VARIANT_EXT* = 0x000087C1
+  GL_INVARIANT_EXT* = 0x000087C2
+  GL_LOCAL_CONSTANT_EXT* = 0x000087C3
+  GL_LOCAL_EXT* = 0x000087C4
+  GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x000087C5
+  GL_MAX_VERTEX_SHADER_VARIANTS_EXT* = 0x000087C6
+  GL_MAX_VERTEX_SHADER_INVARIANTS_EXT* = 0x000087C7
+  GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x000087C8
+  GL_MAX_VERTEX_SHADER_LOCALS_EXT* = 0x000087C9
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x000087CA
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT* = 0x000087CB
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x000087CC
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT* = 0x000087CD
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT* = 0x000087CE
+  GL_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x000087CF
+  GL_VERTEX_SHADER_VARIANTS_EXT* = 0x000087D0
+  GL_VERTEX_SHADER_INVARIANTS_EXT* = 0x000087D1
+  GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x000087D2
+  GL_VERTEX_SHADER_LOCALS_EXT* = 0x000087D3
+  GL_VERTEX_SHADER_BINDING_EXT* = 0x00008781
+  GL_VERTEX_SHADER_OPTIMIZED_EXT* = 0x000087D4
+  GL_X_EXT* = 0x000087D5
+  GL_Y_EXT* = 0x000087D6
+  GL_Z_EXT* = 0x000087D7
+  GL_W_EXT* = 0x000087D8
+  GL_NEGATIVE_X_EXT* = 0x000087D9
+  GL_NEGATIVE_Y_EXT* = 0x000087DA
+  GL_NEGATIVE_Z_EXT* = 0x000087DB
+  GL_NEGATIVE_W_EXT* = 0x000087DC
+  GL_ZERO_EXT* = 0x000087DD
+  GL_ONE_EXT* = 0x000087DE
+  GL_NEGATIVE_ONE_EXT* = 0x000087DF
+  GL_NORMALIZED_RANGE_EXT* = 0x000087E0
+  GL_FULL_RANGE_EXT* = 0x000087E1
+  GL_CURRENT_VERTEX_EXT* = 0x000087E2
+  GL_MVP_MATRIX_EXT* = 0x000087E3
+
+proc glBeginVertexShaderEXT*(){.dynlib: dllname, 
+                                importc: "glBeginVertexShaderEXT".}
+proc glEndVertexShaderEXT*(){.dynlib: dllname, importc: "glEndVertexShaderEXT".}
+proc glBindVertexShaderEXT*(id: TGLuint){.dynlib: dllname, 
+    importc: "glBindVertexShaderEXT".}
+proc glGenVertexShadersEXT*(range: TGLuint): TGLuint{.dynlib: dllname, 
+    importc: "glGenVertexShadersEXT".}
+proc glDeleteVertexShaderEXT*(id: TGLuint){.dynlib: dllname, 
+    importc: "glDeleteVertexShaderEXT".}
+proc glShaderOp1EXT*(op: TGLenum, res: TGLuint, arg1: TGLuint){.dynlib: dllname, 
+    importc: "glShaderOp1EXT".}
+proc glShaderOp2EXT*(op: TGLenum, res: TGLuint, arg1: TGLuint, arg2: TGLuint){.
+    dynlib: dllname, importc: "glShaderOp2EXT".}
+proc glShaderOp3EXT*(op: TGLenum, res: TGLuint, arg1: TGLuint, arg2: TGLuint, 
+                     arg3: TGLuint){.dynlib: dllname, importc: "glShaderOp3EXT".}
+proc glSwizzleEXT*(res: TGLuint, theIn: TGLuint, outX: TGLenum, outY: TGLenum, 
+                   outZ: TGLenum, outW: TGLenum){.dynlib: dllname, 
+    importc: "glSwizzleEXT".}
+proc glWriteMaskEXT*(res: TGLuint, theIn: TGLuint, outX: TGLenum, outY: TGLenum, 
+                     outZ: TGLenum, outW: TGLenum){.dynlib: dllname, 
+    importc: "glWriteMaskEXT".}
+proc glInsertComponentEXT*(res: TGLuint, src: TGLuint, num: TGLuint){.
+    dynlib: dllname, importc: "glInsertComponentEXT".}
+proc glExtractComponentEXT*(res: TGLuint, src: TGLuint, num: TGLuint){.
+    dynlib: dllname, importc: "glExtractComponentEXT".}
+proc glGenSymbolsEXT*(datatype: TGLenum, storagetype: TGLenum, range: TGLenum, 
+                      components: TGLuint): TGLuint{.dynlib: dllname, 
+    importc: "glGenSymbolsEXT".}
+proc glSetInvariantEXT*(id: TGLuint, thetype: TGLenum, address: PGLvoid){.
+    dynlib: dllname, importc: "glSetInvariantEXT".}
+proc glSetLocalConstantEXT*(id: TGLuint, thetype: TGLenum, address: PGLvoid){.
+    dynlib: dllname, importc: "glSetLocalConstantEXT".}
+proc glVariantbvEXT*(id: TGLuint, address: PGLbyte){.dynlib: dllname, 
+    importc: "glVariantbvEXT".}
+proc glVariantsvEXT*(id: TGLuint, address: PGLshort){.dynlib: dllname, 
+    importc: "glVariantsvEXT".}
+proc glVariantivEXT*(id: TGLuint, address: PGLint){.dynlib: dllname, 
+    importc: "glVariantivEXT".}
+proc glVariantfvEXT*(id: TGLuint, address: PGLfloat){.dynlib: dllname, 
+    importc: "glVariantfvEXT".}
+proc glVariantdvEXT*(id: TGLuint, address: PGLdouble){.dynlib: dllname, 
+    importc: "glVariantdvEXT".}
+proc glVariantubvEXT*(id: TGLuint, address: PGLubyte){.dynlib: dllname, 
+    importc: "glVariantubvEXT".}
+proc glVariantusvEXT*(id: TGLuint, address: PGLushort){.dynlib: dllname, 
+    importc: "glVariantusvEXT".}
+proc glVariantuivEXT*(id: TGLuint, address: PGLuint){.dynlib: dllname, 
+    importc: "glVariantuivEXT".}
+proc glVariantPointerEXT*(id: TGLuint, thetype: TGLenum, stride: TGLuint, 
+                          address: PGLvoid){.dynlib: dllname, 
+    importc: "glVariantPointerEXT".}
+proc glEnableVariantClientStateEXT*(id: TGLuint){.dynlib: dllname, 
+    importc: "glEnableVariantClientStateEXT".}
+proc glDisableVariantClientStateEXT*(id: TGLuint){.dynlib: dllname, 
+    importc: "glDisableVariantClientStateEXT".}
+proc glBindLightParameterEXT*(light: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindLightParameterEXT".}
+proc glBindMaterialParameterEXT*(face: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindMaterialParameterEXT".}
+proc glBindTexGenParameterEXT*(theunit: TGLenum, coord: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindTexGenParameterEXT".}
+proc glBindTextureUnitParameterEXT*(theunit: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindTextureUnitParameterEXT".}
+proc glBindParameterEXT*(value: TGLenum): TGLuint{.dynlib: dllname, 
+    importc: "glBindParameterEXT".}
+proc glIsVariantEnabledEXT*(id: TGLuint, cap: TGLenum): TGLboolean{.
+    dynlib: dllname, importc: "glIsVariantEnabledEXT".}
+proc glGetVariantBooleanvEXT*(id: TGLuint, value: TGLenum, data: PGLboolean){.
+    dynlib: dllname, importc: "glGetVariantBooleanvEXT".}
+proc glGetVariantIntegervEXT*(id: TGLuint, value: TGLenum, data: PGLint){.
+    dynlib: dllname, importc: "glGetVariantIntegervEXT".}
+proc glGetVariantFloatvEXT*(id: TGLuint, value: TGLenum, data: PGLfloat){.
+    dynlib: dllname, importc: "glGetVariantFloatvEXT".}
+proc glGetVariantPointervEXT*(id: TGLuint, value: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glGetVariantPointervEXT".}
+proc glGetInvariantBooleanvEXT*(id: TGLuint, value: TGLenum, data: PGLboolean){.
+    dynlib: dllname, importc: "glGetInvariantBooleanvEXT".}
+proc glGetInvariantIntegervEXT*(id: TGLuint, value: TGLenum, data: PGLint){.
+    dynlib: dllname, importc: "glGetInvariantIntegervEXT".}
+proc glGetInvariantFloatvEXT*(id: TGLuint, value: TGLenum, data: PGLfloat){.
+    dynlib: dllname, importc: "glGetInvariantFloatvEXT".}
+proc glGetLocalConstantBooleanvEXT*(id: TGLuint, value: TGLenum, 
+                                    data: PGLboolean){.dynlib: dllname, 
+    importc: "glGetLocalConstantBooleanvEXT".}
+proc glGetLocalConstantIntegervEXT*(id: TGLuint, value: TGLenum, data: PGLint){.
+    dynlib: dllname, importc: "glGetLocalConstantIntegervEXT".}
+proc glGetLocalConstantFloatvEXT*(id: TGLuint, value: TGLenum, data: PGLfloat){.
+    dynlib: dllname, importc: "glGetLocalConstantFloatvEXT".}
+  #***** GL_EXT_vertex_weighting *****//
+const 
+  GL_VERTEX_WEIGHTING_EXT* = 0x00008509
+  GL_MODELVIEW0_EXT* = 0x00001700
+  GL_MODELVIEW1_EXT* = 0x0000850A
+  GL_MODELVIEW0_MATRIX_EXT* = 0x00000BA6
+  GL_MODELVIEW1_MATRIX_EXT* = 0x00008506
+  GL_CURRENT_VERTEX_WEIGHT_EXT* = 0x0000850B
+  GL_VERTEX_WEIGHT_ARRAY_EXT* = 0x0000850C
+  GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT* = 0x0000850D
+  GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT* = 0x0000850E
+  GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT* = 0x0000850F
+  GL_MODELVIEW0_STACK_DEPTH_EXT* = 0x00000BA3
+  GL_MODELVIEW1_STACK_DEPTH_EXT* = 0x00008502
+  GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT* = 0x00008510
+
+proc glVertexWeightfEXT*(weight: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexWeightfEXT".}
+proc glVertexWeightfvEXT*(weight: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexWeightfvEXT".}
+proc glVertexWeightPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                               pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glVertexWeightPointerEXT".}
+  #***** GL_HP_occlusion_test *****//
+const 
+  GL_OCCLUSION_TEST_HP* = 0x00008165
+  GL_OCCLUSION_TEST_RESULT_HP* = 0x00008166
+  #***** GL_NV_blend_square *****//
+  #***** GL_NV_copy_depth_to_color *****//
+
+const 
+  GL_DEPTH_STENCIL_TO_RGBA_NV* = 0x0000886E
+  GL_DEPTH_STENCIL_TO_BGRA_NV* = 0x0000886F
+  #***** GL_NV_depth_clamp *****//
+
+const 
+  GL_DEPTH_CLAMP_NV* = 0x0000864F
+  #***** GL_NV_evaluators *****//
+
+const 
+  GL_EVAL_2D_NV* = 0x000086C0
+  GL_EVAL_TRIANGULAR_2D_NV* = 0x000086C1
+  GL_MAP_TESSELLATION_NV* = 0x000086C2
+  GL_MAP_ATTRIB_U_ORDER_NV* = 0x000086C3
+  GL_MAP_ATTRIB_V_ORDER_NV* = 0x000086C4
+  GL_EVAL_FRACTIONAL_TESSELLATION_NV* = 0x000086C5
+  GL_EVAL_VERTEX_ATTRIB0_NV* = 0x000086C6
+  GL_EVAL_VERTEX_ATTRIB1_NV* = 0x000086C7
+  GL_EVAL_VERTEX_ATTRIB2_NV* = 0x000086C8
+  GL_EVAL_VERTEX_ATTRIB3_NV* = 0x000086C9
+  GL_EVAL_VERTEX_ATTRIB4_NV* = 0x000086CA
+  GL_EVAL_VERTEX_ATTRIB5_NV* = 0x000086CB
+  GL_EVAL_VERTEX_ATTRIB6_NV* = 0x000086CC
+  GL_EVAL_VERTEX_ATTRIB7_NV* = 0x000086CD
+  GL_EVAL_VERTEX_ATTRIB8_NV* = 0x000086CE
+  GL_EVAL_VERTEX_ATTRIB9_NV* = 0x000086CF
+  GL_EVAL_VERTEX_ATTRIB10_NV* = 0x000086D0
+  GL_EVAL_VERTEX_ATTRIB11_NV* = 0x000086D1
+  GL_EVAL_VERTEX_ATTRIB12_NV* = 0x000086D2
+  GL_EVAL_VERTEX_ATTRIB13_NV* = 0x000086D3
+  GL_EVAL_VERTEX_ATTRIB14_NV* = 0x000086D4
+  GL_EVAL_VERTEX_ATTRIB15_NV* = 0x000086D5
+  GL_MAX_MAP_TESSELLATION_NV* = 0x000086D6
+  GL_MAX_RATIONAL_EVAL_ORDER_NV* = 0x000086D7
+
+proc glMapControlPointsNV*(target: TGLenum, index: TGLuint, thetype: TGLenum, 
+                           ustride: TGLsizei, vstride: TGLsizei, uorder: TGLint, 
+                           vorder: TGLint, thepacked: TGLboolean, 
+                           points: PGLvoid){.dynlib: dllname, 
+    importc: "glMapControlPointsNV".}
+proc glMapParameterivNV*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glMapParameterivNV".}
+proc glMapParameterfvNV*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glMapParameterfvNV".}
+proc glGetMapControlPointsNV*(target: TGLenum, index: TGLuint, thetype: TGLenum, 
+                              ustride: TGLsizei, vstride: TGLsizei, 
+                              thepacked: TGLboolean, points: PGLvoid){.
+    dynlib: dllname, importc: "glGetMapControlPointsNV".}
+proc glGetMapParameterivNV*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMapParameterivNV".}
+proc glGetMapParameterfvNV*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetMapParameterfvNV".}
+proc glGetMapAttribParameterivNV*(target: TGLenum, index: TGLuint, 
+                                  pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMapAttribParameterivNV".}
+proc glGetMapAttribParameterfvNV*(target: TGLenum, index: TGLuint, 
+                                  pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetMapAttribParameterfvNV".}
+proc glEvalMapsNV*(target: TGLenum, mode: TGLenum){.dynlib: dllname, 
+    importc: "glEvalMapsNV".}
+  #***** GL_NV_fence *****//
+const 
+  GL_ALL_COMPLETED_NV* = 0x000084F2
+  GL_FENCE_STATUS_NV* = 0x000084F3
+  GL_FENCE_CONDITION_NV* = 0x000084F4
+
+proc glGenFencesNV*(n: TGLsizei, fences: PGLuint){.dynlib: dllname, 
+    importc: "glGenFencesNV".}
+proc glDeleteFencesNV*(n: TGLsizei, fences: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteFencesNV".}
+proc glSetFenceNV*(fence: TGLuint, condition: TGLenum){.dynlib: dllname, 
+    importc: "glSetFenceNV".}
+proc glTestFenceNV*(fence: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glTestFenceNV".}
+proc glFinishFenceNV*(fence: TGLuint){.dynlib: dllname, 
+                                       importc: "glFinishFenceNV".}
+proc glIsFenceNV*(fence: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsFenceNV".}
+proc glGetFenceivNV*(fence: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetFenceivNV".}
+  #***** GL_NV_fog_distance *****//
+const 
+  GL_FOG_DISTANCE_MODE_NV* = 0x0000855A
+  GL_EYE_RADIAL_NV* = 0x0000855B
+  GL_EYE_PLANE_ABSOLUTE_NV* = 0x0000855C
+  #***** GL_NV_light_max_exponent *****//
+
+const 
+  GL_MAX_SHININESS_NV* = 0x00008504
+  GL_MAX_SPOT_EXPONENT_NV* = 0x00008505
+  #***** GL_NV_multisample_filter_hint *****//
+
+const 
+  GL_MULTISAMPLE_FILTER_HINT_NV* = 0x00008534
+  #***** GL_NV_occlusion_query *****//
+  # GL_OCCLUSION_TEST_HP  { already defined }
+  # GL_OCCLUSION_TEST_RESULT_HP  { already defined }
+
+const 
+  GL_PIXEL_COUNTER_BITS_NV* = 0x00008864
+  GL_CURRENT_OCCLUSION_QUERY_ID_NV* = 0x00008865
+  GL_PIXEL_COUNT_NV* = 0x00008866
+  GL_PIXEL_COUNT_AVAILABLE_NV* = 0x00008867
+
+proc glGenOcclusionQueriesNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glGenOcclusionQueriesNV".}
+proc glDeleteOcclusionQueriesNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteOcclusionQueriesNV".}
+proc glIsOcclusionQueryNV*(id: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsOcclusionQueryNV".}
+proc glBeginOcclusionQueryNV*(id: TGLuint){.dynlib: dllname, 
+    importc: "glBeginOcclusionQueryNV".}
+proc glEndOcclusionQueryNV*(){.dynlib: dllname, importc: "glEndOcclusionQueryNV".}
+proc glGetOcclusionQueryivNV*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetOcclusionQueryivNV".}
+proc glGetOcclusionQueryuivNV*(id: TGLuint, pname: TGLenum, params: PGLuint){.
+    dynlib: dllname, importc: "glGetOcclusionQueryuivNV".}
+  #***** GL_NV_packed_depth_stencil *****//
+const 
+  GL_DEPTH_STENCIL_NV* = 0x000084F9
+  GL_UNSIGNED_INT_24_8_NV* = 0x000084FA
+  #***** GL_NV_point_sprite *****//
+
+const 
+  GL_POINT_SPRITE_NV* = 0x00008861
+  GL_COORD_REPLACE_NV* = 0x00008862
+  GL_POINT_SPRITE_R_MODE_NV* = 0x00008863
+
+proc glPointParameteriNV*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glPointParameteriNV".}
+proc glPointParameterivNV*(pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glPointParameterivNV".}
+  #***** GL_NV_register_combiners *****//
+const 
+  GL_REGISTER_COMBINERS_NV* = 0x00008522
+  GL_COMBINER0_NV* = 0x00008550
+  GL_COMBINER1_NV* = 0x00008551
+  GL_COMBINER2_NV* = 0x00008552
+  GL_COMBINER3_NV* = 0x00008553
+  GL_COMBINER4_NV* = 0x00008554
+  GL_COMBINER5_NV* = 0x00008555
+  GL_COMBINER6_NV* = 0x00008556
+  GL_COMBINER7_NV* = 0x00008557
+  GL_VARIABLE_A_NV* = 0x00008523
+  GL_VARIABLE_B_NV* = 0x00008524
+  GL_VARIABLE_C_NV* = 0x00008525
+  GL_VARIABLE_D_NV* = 0x00008526
+  GL_VARIABLE_E_NV* = 0x00008527
+  GL_VARIABLE_F_NV* = 0x00008528
+  GL_VARIABLE_G_NV* = 0x00008529
+  GL_CONSTANT_COLOR0_NV* = 0x0000852A
+  GL_CONSTANT_COLOR1_NV* = 0x0000852B
+  GL_PRIMARY_COLOR_NV* = 0x0000852C
+  GL_SECONDARY_COLOR_NV* = 0x0000852D
+  GL_SPARE0_NV* = 0x0000852E
+  GL_SPARE1_NV* = 0x0000852F
+  GL_UNSIGNED_IDENTITY_NV* = 0x00008536
+  GL_UNSIGNED_INVERT_NV* = 0x00008537
+  GL_EXPAND_NORMAL_NV* = 0x00008538
+  GL_EXPAND_NEGATE_NV* = 0x00008539
+  GL_HALF_BIAS_NORMAL_NV* = 0x0000853A
+  GL_HALF_BIAS_NEGATE_NV* = 0x0000853B
+  GL_SIGNED_IDENTITY_NV* = 0x0000853C
+  GL_SIGNED_NEGATE_NV* = 0x0000853D
+  GL_E_TIMES_F_NV* = 0x00008531
+  GL_SPARE0_PLUS_SECONDARY_COLOR_NV* = 0x00008532
+  GL_SCALE_BY_TWO_NV* = 0x0000853E
+  GL_SCALE_BY_FOUR_NV* = 0x0000853F
+  GL_SCALE_BY_ONE_HALF_NV* = 0x00008540
+  GL_BIAS_BY_NEGATIVE_ONE_HALF_NV* = 0x00008541
+  GL_DISCARD_NV* = 0x00008530
+  constGL_COMBINER_INPUT_NV* = 0x00008542
+  GL_COMBINER_MAPPING_NV* = 0x00008543
+  GL_COMBINER_COMPONENT_USAGE_NV* = 0x00008544
+  GL_COMBINER_AB_DOT_PRODUCT_NV* = 0x00008545
+  GL_COMBINER_CD_DOT_PRODUCT_NV* = 0x00008546
+  GL_COMBINER_MUX_SUM_NV* = 0x00008547
+  GL_COMBINER_SCALE_NV* = 0x00008548
+  GL_COMBINER_BIAS_NV* = 0x00008549
+  GL_COMBINER_AB_OUTPUT_NV* = 0x0000854A
+  GL_COMBINER_CD_OUTPUT_NV* = 0x0000854B
+  GL_COMBINER_SUM_OUTPUT_NV* = 0x0000854C
+  GL_NUM_GENERAL_COMBINERS_NV* = 0x0000854E
+  GL_COLOR_SUM_CLAMP_NV* = 0x0000854F
+  GL_MAX_GENERAL_COMBINERS_NV* = 0x0000854D
+
+proc glCombinerParameterfvNV*(pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glCombinerParameterfvNV".}
+proc glCombinerParameterivNV*(pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glCombinerParameterivNV".}
+proc glCombinerParameterfNV*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glCombinerParameterfNV".}
+proc glCombinerParameteriNV*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glCombinerParameteriNV".}
+proc glCombinerInputNV*(stage: TGLenum, portion: TGLenum, variable: TGLenum, 
+                        input: TGLenum, mapping: TGLenum, 
+                        componentUsage: TGLenum){.dynlib: dllname, 
+    importc: "glCombinerInputNV".}
+proc glCombinerOutputNV*(stage: TGLenum, portion: TGLenum, abOutput: TGLenum, 
+                         cdOutput: TGLenum, sumOutput: TGLenum, scale: TGLenum, 
+                         bias: TGLenum, abDotProduct: TGLboolean, 
+                         cdDotProduct: TGLboolean, muxSum: TGLboolean){.
+    dynlib: dllname, importc: "glCombinerOutputNV".}
+proc glFinalCombinerInputNV*(variable: TGLenum, input: TGLenum, 
+                             mapping: TGLenum, componentUsage: TGLenum){.
+    dynlib: dllname, importc: "glFinalCombinerInputNV".}
+proc glGetCombinerInputParameterfvNV*(stage: TGLenum, portion: TGLenum, 
+                                      variable: TGLenum, pname: TGLenum, 
+                                      params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetCombinerInputParameterfvNV".}
+proc glGetCombinerInputParameterivNV*(stage: TGLenum, portion: TGLenum, 
+                                      variable: TGLenum, pname: TGLenum, 
+                                      params: PGLint){.dynlib: dllname, 
+    importc: "glGetCombinerInputParameterivNV".}
+proc glGetCombinerOutputParameterfvNV*(stage: TGLenum, portion: TGLenum, 
+                                       pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetCombinerOutputParameterfvNV".}
+proc glGetCombinerOutputParameterivNV*(stage: TGLenum, portion: TGLenum, 
+                                       pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetCombinerOutputParameterivNV".}
+proc glGetFinalCombinerInputParameterfvNV*(variable: TGLenum, pname: TGLenum, 
+    params: PGLfloat){.dynlib: dllname, 
+                       importc: "glGetFinalCombinerInputParameterfvNV".}
+proc glGetFinalCombinerInputParameterivNV*(variable: TGLenum, pname: TGLenum, 
+    params: PGLint){.dynlib: dllname, 
+                     importc: "glGetFinalCombinerInputParameterivNV".}
+  #***** GL_NV_register_combiners2 *****//
+const 
+  GL_PER_STAGE_CONSTANTS_NV* = 0x00008535
+
+proc glCombinerStageParameterfvNV*(stage: TGLenum, pname: TGLenum, 
+                                   params: PGLfloat){.dynlib: dllname, 
+    importc: "glCombinerStageParameterfvNV".}
+proc glGetCombinerStageParameterfvNV*(stage: TGLenum, pname: TGLenum, 
+                                      params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetCombinerStageParameterfvNV".}
+  #***** GL_NV_texgen_emboss *****//
+const 
+  GL_EMBOSS_MAP_NV* = 0x0000855F
+  GL_EMBOSS_LIGHT_NV* = 0x0000855D
+  GL_EMBOSS_CONSTANT_NV* = 0x0000855E
+  #***** GL_NV_texgen_reflection *****//
+
+const 
+  GL_NORMAL_MAP_NV* = 0x00008511
+  GL_REFLECTION_MAP_NV* = 0x00008512
+  #***** GL_NV_texture_compression_vtc *****//
+  # GL_COMPRESSED_RGB_S3TC_DXT1_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  { already defined }
+  #***** GL_NV_texture_env_combine4 *****//
+
+const 
+  GL_COMBINE4_NV* = 0x00008503
+  GL_SOURCE3_RGB_NV* = 0x00008583
+  GL_SOURCE3_ALPHA_NV* = 0x0000858B
+  GL_OPERAND3_RGB_NV* = 0x00008593
+  GL_OPERAND3_ALPHA_NV* = 0x0000859B
+  #***** GL_NV_texture_rectangle *****//
+
+const 
+  GL_TEXTURE_RECTANGLE_NV* = 0x000084F5
+  GL_TEXTURE_BINDING_RECTANGLE_NV* = 0x000084F6
+  GL_PROXY_TEXTURE_RECTANGLE_NV* = 0x000084F7
+  GL_MAX_RECTANGLE_TEXTURE_SIZE_NV* = 0x000084F8
+  #***** GL_NV_texture_shader *****//
+
+const 
+  GL_TEXTURE_SHADER_NV* = 0x000086DE
+  GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV* = 0x000086D9
+  GL_SHADER_OPERATION_NV* = 0x000086DF
+  GL_CULL_MODES_NV* = 0x000086E0
+  GL_OFFSET_TEXTURE_MATRIX_NV* = 0x000086E1
+  GL_OFFSET_TEXTURE_SCALE_NV* = 0x000086E2
+  GL_OFFSET_TEXTURE_BIAS_NV* = 0x000086E3
+  GL_PREVIOUS_TEXTURE_INPUT_NV* = 0x000086E4
+  GL_CONST_EYE_NV* = 0x000086E5
+  GL_SHADER_CONSISTENT_NV* = 0x000086DD
+  GL_PASS_THROUGH_NV* = 0x000086E6
+  GL_CULL_FRAGMENT_NV* = 0x000086E7
+  GL_OFFSET_TEXTURE_2D_NV* = 0x000086E8
+  GL_OFFSET_TEXTURE_RECTANGLE_NV* = 0x0000864C
+  GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV* = 0x0000864D
+  GL_DEPENDENT_AR_TEXTURE_2D_NV* = 0x000086E9
+  GL_DEPENDENT_GB_TEXTURE_2D_NV* = 0x000086EA
+  GL_DOT_PRODUCT_NV* = 0x000086EC
+  GL_DOT_PRODUCT_DEPTH_REPLACE_NV* = 0x000086ED
+  GL_DOT_PRODUCT_TEXTURE_2D_NV* = 0x000086EE
+  GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV* = 0x0000864E
+  GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV* = 0x000086F0
+  GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV* = 0x000086F1
+  GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV* = 0x000086F2
+  GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV* = 0x000086F3
+  GL_HILO_NV* = 0x000086F4
+  GL_DSDT_NV* = 0x000086F5
+  GL_DSDT_MAG_NV* = 0x000086F6
+  GL_DSDT_MAG_VIB_NV* = 0x000086F7
+  GL_UNSIGNED_INT_S8_S8_8_8_NV* = 0x000086DA
+  GL_UNSIGNED_INT_8_8_S8_S8_REV_NV* = 0x000086DB
+  GL_SIGNED_RGBA_NV* = 0x000086FB
+  GL_SIGNED_RGBA8_NV* = 0x000086FC
+  GL_SIGNED_RGB_NV* = 0x000086FE
+  GL_SIGNED_RGB8_NV* = 0x000086FF
+  GL_SIGNED_LUMINANCE_NV* = 0x00008701
+  GL_SIGNED_LUMINANCE8_NV* = 0x00008702
+  GL_SIGNED_LUMINANCE_ALPHA_NV* = 0x00008703
+  GL_SIGNED_LUMINANCE8_ALPHA8_NV* = 0x00008704
+  GL_SIGNED_ALPHA_NV* = 0x00008705
+  GL_SIGNED_ALPHA8_NV* = 0x00008706
+  GL_SIGNED_INTENSITY_NV* = 0x00008707
+  GL_SIGNED_INTENSITY8_NV* = 0x00008708
+  GL_SIGNED_RGB_UNSIGNED_ALPHA_NV* = 0x0000870C
+  GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV* = 0x0000870D
+  GL_HILO16_NV* = 0x000086F8
+  GL_SIGNED_HILO_NV* = 0x000086F9
+  GL_SIGNED_HILO16_NV* = 0x000086FA
+  GL_DSDT8_NV* = 0x00008709
+  GL_DSDT8_MAG8_NV* = 0x0000870A
+  GL_DSDT_MAG_INTENSITY_NV* = 0x000086DC
+  GL_DSDT8_MAG8_INTENSITY8_NV* = 0x0000870B
+  GL_HI_SCALE_NV* = 0x0000870E
+  GL_LO_SCALE_NV* = 0x0000870F
+  GL_DS_SCALE_NV* = 0x00008710
+  GL_DT_SCALE_NV* = 0x00008711
+  GL_MAGNITUDE_SCALE_NV* = 0x00008712
+  GL_VIBRANCE_SCALE_NV* = 0x00008713
+  GL_HI_BIAS_NV* = 0x00008714
+  GL_LO_BIAS_NV* = 0x00008715
+  GL_DS_BIAS_NV* = 0x00008716
+  GL_DT_BIAS_NV* = 0x00008717
+  GL_MAGNITUDE_BIAS_NV* = 0x00008718
+  GL_VIBRANCE_BIAS_NV* = 0x00008719
+  GL_TEXTURE_BORDER_VALUES_NV* = 0x0000871A
+  GL_TEXTURE_HI_SIZE_NV* = 0x0000871B
+  GL_TEXTURE_LO_SIZE_NV* = 0x0000871C
+  GL_TEXTURE_DS_SIZE_NV* = 0x0000871D
+  GL_TEXTURE_DT_SIZE_NV* = 0x0000871E
+  GL_TEXTURE_MAG_SIZE_NV* = 0x0000871F
+  #***** GL_NV_texture_shader2 *****//
+
+const 
+  GL_DOT_PRODUCT_TEXTURE_3D_NV* = 0x000086EF # GL_HILO_NV  { already defined }
+                                             # GL_DSDT_NV  { already defined }
+                                             # GL_DSDT_MAG_NV  { already defined }
+                                             # GL_DSDT_MAG_VIB_NV  { already defined }
+                                             # GL_UNSIGNED_INT_S8_S8_8_8_NV  { already defined }
+                                             # GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  { already defined }
+                                             # GL_SIGNED_RGBA_NV  { already defined }
+                                             # GL_SIGNED_RGBA8_NV  { already defined }
+                                             # GL_SIGNED_RGB_NV  { already defined }
+                                             # GL_SIGNED_RGB8_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE8_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE_ALPHA_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE8_ALPHA8_NV  { already defined }
+                                             # GL_SIGNED_ALPHA_NV  { already defined }
+                                             # GL_SIGNED_ALPHA8_NV  { already defined }
+                                             # GL_SIGNED_INTENSITY_NV  { already defined }
+                                             # GL_SIGNED_INTENSITY8_NV  { already defined }
+                                             # GL_SIGNED_RGB_UNSIGNED_ALPHA_NV  { already defined }
+                                             # GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV  { already defined }
+                                             # GL_HILO16_NV  { already defined }
+                                             # GL_SIGNED_HILO_NV  { already defined }
+                                             # GL_SIGNED_HILO16_NV  { already defined }
+                                             # GL_DSDT8_NV  { already defined }
+                                             # GL_DSDT8_MAG8_NV  { already defined }
+                                             # GL_DSDT_MAG_INTENSITY_NV  { already defined }
+                                             # GL_DSDT8_MAG8_INTENSITY8_NV  { already defined }
+  #***** GL_NV_texture_shader3 *****//
+
+const 
+  GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV* = 0x00008850
+  GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV* = 0x00008851
+  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV* = 0x00008852
+  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV* = 0x00008853
+  GL_OFFSET_HILO_TEXTURE_2D_NV* = 0x00008854
+  GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV* = 0x00008855
+  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV* = 0x00008856
+  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV* = 0x00008857
+  GL_DEPENDENT_HILO_TEXTURE_2D_NV* = 0x00008858
+  GL_DEPENDENT_RGB_TEXTURE_3D_NV* = 0x00008859
+  GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV* = 0x0000885A
+  GL_DOT_PRODUCT_PASS_THROUGH_NV* = 0x0000885B
+  GL_DOT_PRODUCT_TEXTURE_1D_NV* = 0x0000885C
+  GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV* = 0x0000885D
+  GL_HILO8_NV* = 0x0000885E
+  GL_SIGNED_HILO8_NV* = 0x0000885F
+  GL_FORCE_BLUE_TO_ONE_NV* = 0x00008860
+  #***** GL_NV_vertex_array_range *****//
+
+const 
+  constGL_VERTEX_ARRAY_RANGE_NV* = 0x0000851D
+  GL_VERTEX_ARRAY_RANGE_LENGTH_NV* = 0x0000851E
+  GL_VERTEX_ARRAY_RANGE_VALID_NV* = 0x0000851F
+  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV* = 0x00008520
+  GL_VERTEX_ARRAY_RANGE_POINTER_NV* = 0x00008521
+
+proc glVertexArrayRangeNV*(len: TGLsizei, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glVertexArrayRangeNV".}
+proc glFlushVertexArrayRangeNV*(){.dynlib: dllname, 
+                                   importc: "glFlushVertexArrayRangeNV".}
+  #***** GL_NV_vertex_array_range2 *****//
+const 
+  GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV* = 0x00008533
+  #***** GL_NV_vertex_program *****//
+
+const 
+  GL_VERTEX_PROGRAM_NV* = 0x00008620
+  GL_VERTEX_PROGRAM_POINT_SIZE_NV* = 0x00008642
+  GL_VERTEX_PROGRAM_TWO_SIDE_NV* = 0x00008643
+  GL_VERTEX_STATE_PROGRAM_NV* = 0x00008621
+  GL_ATTRIB_ARRAY_SIZE_NV* = 0x00008623
+  GL_ATTRIB_ARRAY_STRIDE_NV* = 0x00008624
+  GL_ATTRIB_ARRAY_TYPE_NV* = 0x00008625
+  GL_CURRENT_ATTRIB_NV* = 0x00008626
+  GL_PROGRAM_PARAMETER_NV* = 0x00008644
+  GL_ATTRIB_ARRAY_POINTER_NV* = 0x00008645
+  GL_PROGRAM_TARGET_NV* = 0x00008646
+  GL_PROGRAM_LENGTH_NV* = 0x00008627
+  GL_PROGRAM_RESIDENT_NV* = 0x00008647
+  GL_PROGRAM_STRING_NV* = 0x00008628
+  constGL_TRACK_MATRIX_NV* = 0x00008648
+  GL_TRACK_MATRIX_TRANSFORM_NV* = 0x00008649
+  GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV* = 0x0000862E
+  GL_MAX_TRACK_MATRICES_NV* = 0x0000862F
+  GL_CURRENT_MATRIX_STACK_DEPTH_NV* = 0x00008640
+  GL_CURRENT_MATRIX_NV* = 0x00008641
+  GL_VERTEX_PROGRAM_BINDING_NV* = 0x0000864A
+  GL_PROGRAM_ERROR_POSITION_NV* = 0x0000864B
+  GL_MODELVIEW_PROJECTION_NV* = 0x00008629
+  GL_MATRIX0_NV* = 0x00008630
+  GL_MATRIX1_NV* = 0x00008631
+  GL_MATRIX2_NV* = 0x00008632
+  GL_MATRIX3_NV* = 0x00008633
+  GL_MATRIX4_NV* = 0x00008634
+  GL_MATRIX5_NV* = 0x00008635
+  GL_MATRIX6_NV* = 0x00008636
+  GL_MATRIX7_NV* = 0x00008637
+  GL_IDENTITY_NV* = 0x0000862A
+  GL_INVERSE_NV* = 0x0000862B
+  GL_TRANSPOSE_NV* = 0x0000862C
+  GL_INVERSE_TRANSPOSE_NV* = 0x0000862D
+  GL_VERTEX_ATTRIB_ARRAY0_NV* = 0x00008650
+  GL_VERTEX_ATTRIB_ARRAY1_NV* = 0x00008651
+  GL_VERTEX_ATTRIB_ARRAY2_NV* = 0x00008652
+  GL_VERTEX_ATTRIB_ARRAY3_NV* = 0x00008653
+  GL_VERTEX_ATTRIB_ARRAY4_NV* = 0x00008654
+  GL_VERTEX_ATTRIB_ARRAY5_NV* = 0x00008655
+  GL_VERTEX_ATTRIB_ARRAY6_NV* = 0x00008656
+  GL_VERTEX_ATTRIB_ARRAY7_NV* = 0x00008657
+  GL_VERTEX_ATTRIB_ARRAY8_NV* = 0x00008658
+  GL_VERTEX_ATTRIB_ARRAY9_NV* = 0x00008659
+  GL_VERTEX_ATTRIB_ARRAY10_NV* = 0x0000865A
+  GL_VERTEX_ATTRIB_ARRAY11_NV* = 0x0000865B
+  GL_VERTEX_ATTRIB_ARRAY12_NV* = 0x0000865C
+  GL_VERTEX_ATTRIB_ARRAY13_NV* = 0x0000865D
+  GL_VERTEX_ATTRIB_ARRAY14_NV* = 0x0000865E
+  GL_VERTEX_ATTRIB_ARRAY15_NV* = 0x0000865F
+  GL_MAP1_VERTEX_ATTRIB0_4_NV* = 0x00008660
+  GL_MAP1_VERTEX_ATTRIB1_4_NV* = 0x00008661
+  GL_MAP1_VERTEX_ATTRIB2_4_NV* = 0x00008662
+  GL_MAP1_VERTEX_ATTRIB3_4_NV* = 0x00008663
+  GL_MAP1_VERTEX_ATTRIB4_4_NV* = 0x00008664
+  GL_MAP1_VERTEX_ATTRIB5_4_NV* = 0x00008665
+  GL_MAP1_VERTEX_ATTRIB6_4_NV* = 0x00008666
+  GL_MAP1_VERTEX_ATTRIB7_4_NV* = 0x00008667
+  GL_MAP1_VERTEX_ATTRIB8_4_NV* = 0x00008668
+  GL_MAP1_VERTEX_ATTRIB9_4_NV* = 0x00008669
+  GL_MAP1_VERTEX_ATTRIB10_4_NV* = 0x0000866A
+  GL_MAP1_VERTEX_ATTRIB11_4_NV* = 0x0000866B
+  GL_MAP1_VERTEX_ATTRIB12_4_NV* = 0x0000866C
+  GL_MAP1_VERTEX_ATTRIB13_4_NV* = 0x0000866D
+  GL_MAP1_VERTEX_ATTRIB14_4_NV* = 0x0000866E
+  GL_MAP1_VERTEX_ATTRIB15_4_NV* = 0x0000866F
+  GL_MAP2_VERTEX_ATTRIB0_4_NV* = 0x00008670
+  GL_MAP2_VERTEX_ATTRIB1_4_NV* = 0x00008671
+  GL_MAP2_VERTEX_ATTRIB2_4_NV* = 0x00008672
+  GL_MAP2_VERTEX_ATTRIB3_4_NV* = 0x00008673
+  GL_MAP2_VERTEX_ATTRIB4_4_NV* = 0x00008674
+  GL_MAP2_VERTEX_ATTRIB5_4_NV* = 0x00008675
+  GL_MAP2_VERTEX_ATTRIB6_4_NV* = 0x00008676
+  GL_MAP2_VERTEX_ATTRIB7_4_NV* = 0x00008677
+  GL_MAP2_VERTEX_ATTRIB8_4_NV* = 0x00008678
+  GL_MAP2_VERTEX_ATTRIB9_4_NV* = 0x00008679
+  GL_MAP2_VERTEX_ATTRIB10_4_NV* = 0x0000867A
+  GL_MAP2_VERTEX_ATTRIB11_4_NV* = 0x0000867B
+  GL_MAP2_VERTEX_ATTRIB12_4_NV* = 0x0000867C
+  GL_MAP2_VERTEX_ATTRIB13_4_NV* = 0x0000867D
+  GL_MAP2_VERTEX_ATTRIB14_4_NV* = 0x0000867E
+  GL_MAP2_VERTEX_ATTRIB15_4_NV* = 0x0000867F
+
+proc glBindProgramNV*(target: TGLenum, id: TGLuint){.dynlib: dllname, 
+    importc: "glBindProgramNV".}
+proc glDeleteProgramsNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteProgramsNV".}
+proc glExecuteProgramNV*(target: TGLenum, id: TGLuint, params: PGLfloat){.
+    dynlib: dllname, importc: "glExecuteProgramNV".}
+proc glGenProgramsNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glGenProgramsNV".}
+proc glAreProgramsResidentNV*(n: TGLsizei, ids: PGLuint, residences: PGLboolean): TGLboolean{.
+    dynlib: dllname, importc: "glAreProgramsResidentNV".}
+proc glRequestResidentProgramsNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glRequestResidentProgramsNV".}
+proc glGetProgramParameterfvNV*(target: TGLenum, index: TGLuint, pname: TGLenum, 
+                                params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetProgramParameterfvNV".}
+proc glGetProgramParameterdvNV*(target: TGLenum, index: TGLuint, pname: TGLenum, 
+                                params: PGLdouble){.dynlib: dllname, 
+    importc: "glGetProgramParameterdvNV".}
+proc glGetProgramivNV*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetProgramivNV".}
+proc glGetProgramStringNV*(id: TGLuint, pname: TGLenum, theProgram: PGLubyte){.
+    dynlib: dllname, importc: "glGetProgramStringNV".}
+proc glGetTrackMatrixivNV*(target: TGLenum, address: TGLuint, pname: TGLenum, 
+                           params: PGLint){.dynlib: dllname, 
+    importc: "glGetTrackMatrixivNV".}
+proc glGetVertexAttribdvNV*(index: TGLuint, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetVertexAttribdvNV".}
+proc glGetVertexAttribfvNV*(index: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVertexAttribfvNV".}
+proc glGetVertexAttribivNV*(index: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVertexAttribivNV".}
+proc glGetVertexAttribPointervNV*(index: TGLuint, pname: TGLenum, 
+                                  pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glGetVertexAttribPointervNV".}
+proc glIsProgramNV*(id: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsProgramNV".}
+proc glLoadProgramNV*(target: TGLenum, id: TGLuint, length: TGLsizei, 
+                      theProgram: PGLubyte){.dynlib: dllname, 
+    importc: "glLoadProgramNV".}
+proc glProgramParameter4fNV*(target: TGLenum, index: TGLuint, x: TGLfloat, 
+                             y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glProgramParameter4fNV".}
+proc glProgramParameter4fvNV*(target: TGLenum, index: TGLuint, params: PGLfloat){.
+    dynlib: dllname, importc: "glProgramParameter4fvNV".}
+proc glProgramParameters4dvNV*(target: TGLenum, index: TGLuint, num: TGLuint, 
+                               params: PGLdouble){.dynlib: dllname, 
+    importc: "glProgramParameters4dvNV".}
+proc glProgramParameters4fvNV*(target: TGLenum, index: TGLuint, num: TGLuint, 
+                               params: PGLfloat){.dynlib: dllname, 
+    importc: "glProgramParameters4fvNV".}
+proc glTrackMatrixNV*(target: TGLenum, address: TGLuint, matrix: TGLenum, 
+                      transform: TGLenum){.dynlib: dllname, 
+    importc: "glTrackMatrixNV".}
+proc glVertexAttribPointerNV*(index: TGLuint, size: TGLint, thetype: TGLenum, 
+                              stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glVertexAttribPointerNV".}
+proc glVertexAttrib1sNV*(index: TGLuint, x: TGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib1sNV".}
+proc glVertexAttrib1fNV*(index: TGLuint, x: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib1fNV".}
+proc glVertexAttrib1dNV*(index: TGLuint, x: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib1dNV".}
+proc glVertexAttrib2sNV*(index: TGLuint, x: TGLshort, y: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib2sNV".}
+proc glVertexAttrib2fNV*(index: TGLuint, x: TGLfloat, y: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib2fNV".}
+proc glVertexAttrib2dNV*(index: TGLuint, x: TGLdouble, y: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib2dNV".}
+proc glVertexAttrib3sNV*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib3sNV".}
+proc glVertexAttrib3fNV*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib3fNV".}
+proc glVertexAttrib3dNV*(index: TGLuint, x: TGLdouble, y: TGLdouble, 
+                         z: TGLdouble){.dynlib: dllname, 
+                                        importc: "glVertexAttrib3dNV".}
+proc glVertexAttrib4sNV*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort, 
+                         w: TGLshort){.dynlib: dllname, 
+                                       importc: "glVertexAttrib4sNV".}
+proc glVertexAttrib4fNV*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat, 
+                         w: TGLfloat){.dynlib: dllname, 
+                                       importc: "glVertexAttrib4fNV".}
+proc glVertexAttrib4dNV*(index: TGLuint, x: TGLdouble, y: TGLdouble, 
+                         z: TGLdouble, w: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib4dNV".}
+proc glVertexAttrib4ubNV*(index: TGLuint, x: TGLubyte, y: TGLubyte, z: TGLubyte, 
+                          w: TGLubyte){.dynlib: dllname, 
+                                        importc: "glVertexAttrib4ubNV".}
+proc glVertexAttrib1svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib1svNV".}
+proc glVertexAttrib1fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib1fvNV".}
+proc glVertexAttrib1dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib1dvNV".}
+proc glVertexAttrib2svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib2svNV".}
+proc glVertexAttrib2fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib2fvNV".}
+proc glVertexAttrib2dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib2dvNV".}
+proc glVertexAttrib3svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib3svNV".}
+proc glVertexAttrib3fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib3fvNV".}
+proc glVertexAttrib3dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib3dvNV".}
+proc glVertexAttrib4svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname, 
+    importc: "glVertexAttrib4svNV".}
+proc glVertexAttrib4fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname, 
+    importc: "glVertexAttrib4fvNV".}
+proc glVertexAttrib4dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname, 
+    importc: "glVertexAttrib4dvNV".}
+proc glVertexAttrib4ubvNV*(index: TGLuint, v: PGLubyte){.dynlib: dllname, 
+    importc: "glVertexAttrib4ubvNV".}
+proc glVertexAttribs1svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs1svNV".}
+proc glVertexAttribs1fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs1fvNV".}
+proc glVertexAttribs1dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs1dvNV".}
+proc glVertexAttribs2svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs2svNV".}
+proc glVertexAttribs2fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs2fvNV".}
+proc glVertexAttribs2dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs2dvNV".}
+proc glVertexAttribs3svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs3svNV".}
+proc glVertexAttribs3fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs3fvNV".}
+proc glVertexAttribs3dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs3dvNV".}
+proc glVertexAttribs4svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs4svNV".}
+proc glVertexAttribs4fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs4fvNV".}
+proc glVertexAttribs4dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs4dvNV".}
+proc glVertexAttribs4ubvNV*(index: TGLuint, n: TGLsizei, v: PGLubyte){.
+    dynlib: dllname, importc: "glVertexAttribs4ubvNV".}
+  #***** GL_NV_vertex_program1_1 *****//
+  #***** GL_ATI_element_array *****//
+const 
+  GL_ELEMENT_ARRAY_ATI* = 0x00008768
+  GL_ELEMENT_ARRAY_TYPE_ATI* = 0x00008769
+  GL_ELEMENT_ARRAY_POINTER_ATI* = 0x0000876A
+
+proc glElementPointerATI*(thetype: TGLenum, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glElementPointerATI".}
+proc glDrawElementArrayATI*(mode: TGLenum, count: TGLsizei){.dynlib: dllname, 
+    importc: "glDrawElementArrayATI".}
+proc glDrawRangeElementArrayATI*(mode: TGLenum, start: TGLuint, theend: TGLuint, 
+                                 count: TGLsizei){.dynlib: dllname, 
+    importc: "glDrawRangeElementArrayATI".}
+  #***** GL_ATI_envmap_bumpmap *****//
+const 
+  GL_BUMP_ROT_MATRIX_ATI* = 0x00008775
+  GL_BUMP_ROT_MATRIX_SIZE_ATI* = 0x00008776
+  GL_BUMP_NUM_TEX_UNITS_ATI* = 0x00008777
+  GL_BUMP_TEX_UNITS_ATI* = 0x00008778
+  GL_DUDV_ATI* = 0x00008779
+  GL_DU8DV8_ATI* = 0x0000877A
+  GL_BUMP_ENVMAP_ATI* = 0x0000877B
+  GL_BUMP_TARGET_ATI* = 0x0000877C
+
+proc glTexBumpParameterivATI*(pname: TGLenum, param: PGLint){.dynlib: dllname, 
+    importc: "glTexBumpParameterivATI".}
+proc glTexBumpParameterfvATI*(pname: TGLenum, param: PGLfloat){.dynlib: dllname, 
+    importc: "glTexBumpParameterfvATI".}
+proc glGetTexBumpParameterivATI*(pname: TGLenum, param: PGLint){.
+    dynlib: dllname, importc: "glGetTexBumpParameterivATI".}
+proc glGetTexBumpParameterfvATI*(pname: TGLenum, param: PGLfloat){.
+    dynlib: dllname, importc: "glGetTexBumpParameterfvATI".}
+  #***** GL_ATI_fragment_shader *****//
+const 
+  GL_FRAGMENT_SHADER_ATI* = 0x00008920
+  GL_REG_0_ATI* = 0x00008921
+  GL_REG_1_ATI* = 0x00008922
+  GL_REG_2_ATI* = 0x00008923
+  GL_REG_3_ATI* = 0x00008924
+  GL_REG_4_ATI* = 0x00008925
+  GL_REG_5_ATI* = 0x00008926
+  GL_CON_0_ATI* = 0x00008941
+  GL_CON_1_ATI* = 0x00008942
+  GL_CON_2_ATI* = 0x00008943
+  GL_CON_3_ATI* = 0x00008944
+  GL_CON_4_ATI* = 0x00008945
+  GL_CON_5_ATI* = 0x00008946
+  GL_CON_6_ATI* = 0x00008947
+  GL_CON_7_ATI* = 0x00008948
+  GL_MOV_ATI* = 0x00008961
+  GL_ADD_ATI* = 0x00008963
+  GL_MUL_ATI* = 0x00008964
+  GL_SUB_ATI* = 0x00008965
+  GL_DOT3_ATI* = 0x00008966
+  GL_DOT4_ATI* = 0x00008967
+  GL_MAD_ATI* = 0x00008968
+  GL_LERP_ATI* = 0x00008969
+  GL_CND_ATI* = 0x0000896A
+  GL_CND0_ATI* = 0x0000896B
+  GL_DOT2_ADD_ATI* = 0x0000896C
+  GL_SECONDARY_INTERPOLATOR_ATI* = 0x0000896D
+  GL_SWIZZLE_STR_ATI* = 0x00008976
+  GL_SWIZZLE_STQ_ATI* = 0x00008977
+  GL_SWIZZLE_STR_DR_ATI* = 0x00008978
+  GL_SWIZZLE_STQ_DQ_ATI* = 0x00008979
+  GL_RED_BIT_ATI* = 0x00000001
+  GL_GREEN_BIT_ATI* = 0x00000002
+  GL_BLUE_BIT_ATI* = 0x00000004
+  GL_2X_BIT_ATI* = 0x00000001
+  GL_4X_BIT_ATI* = 0x00000002
+  GL_8X_BIT_ATI* = 0x00000004
+  GL_HALF_BIT_ATI* = 0x00000008
+  GL_QUARTER_BIT_ATI* = 0x00000010
+  GL_EIGHTH_BIT_ATI* = 0x00000020
+  GL_SATURATE_BIT_ATI* = 0x00000040 # GL_2X_BIT_ATI  { already defined }
+  GL_COMP_BIT_ATI* = 0x00000002
+  GL_NEGATE_BIT_ATI* = 0x00000004
+  GL_BIAS_BIT_ATI* = 0x00000008
+
+proc glGenFragmentShadersATI*(range: TGLuint): TGLuint{.dynlib: dllname, 
+    importc: "glGenFragmentShadersATI".}
+proc glBindFragmentShaderATI*(id: TGLuint){.dynlib: dllname, 
+    importc: "glBindFragmentShaderATI".}
+proc glDeleteFragmentShaderATI*(id: TGLuint){.dynlib: dllname, 
+    importc: "glDeleteFragmentShaderATI".}
+proc glBeginFragmentShaderATI*(){.dynlib: dllname, 
+                                  importc: "glBeginFragmentShaderATI".}
+proc glEndFragmentShaderATI*(){.dynlib: dllname, 
+                                importc: "glEndFragmentShaderATI".}
+proc glPassTexCoordATI*(dst: TGLuint, coord: TGLuint, swizzle: TGLenum){.
+    dynlib: dllname, importc: "glPassTexCoordATI".}
+proc glSampleMapATI*(dst: TGLuint, interp: TGLuint, swizzle: TGLenum){.
+    dynlib: dllname, importc: "glSampleMapATI".}
+proc glColorFragmentOp1ATI*(op: TGLenum, dst: TGLuint, dstMask: TGLuint, 
+                            dstMod: TGLuint, arg1: TGLuint, arg1Rep: TGLuint, 
+                            arg1Mod: TGLuint){.dynlib: dllname, 
+    importc: "glColorFragmentOp1ATI".}
+proc glColorFragmentOp2ATI*(op: TGLenum, dst: TGLuint, dstMask: TGLuint, 
+                            dstMod: TGLuint, arg1: TGLuint, arg1Rep: TGLuint, 
+                            arg1Mod: TGLuint, arg2: TGLuint, arg2Rep: TGLuint, 
+                            arg2Mod: TGLuint){.dynlib: dllname, 
+    importc: "glColorFragmentOp2ATI".}
+proc glColorFragmentOp3ATI*(op: TGLenum, dst: TGLuint, dstMask: TGLuint, 
+                            dstMod: TGLuint, arg1: TGLuint, arg1Rep: TGLuint, 
+                            arg1Mod: TGLuint, arg2: TGLuint, arg2Rep: TGLuint, 
+                            arg2Mod: TGLuint, arg3: TGLuint, arg3Rep: TGLuint, 
+                            arg3Mod: TGLuint){.dynlib: dllname, 
+    importc: "glColorFragmentOp3ATI".}
+proc glAlphaFragmentOp1ATI*(op: TGLenum, dst: TGLuint, dstMod: TGLuint, 
+                            arg1: TGLuint, arg1Rep: TGLuint, arg1Mod: TGLuint){.
+    dynlib: dllname, importc: "glAlphaFragmentOp1ATI".}
+proc glAlphaFragmentOp2ATI*(op: TGLenum, dst: TGLuint, dstMod: TGLuint, 
+                            arg1: TGLuint, arg1Rep: TGLuint, arg1Mod: TGLuint, 
+                            arg2: TGLuint, arg2Rep: TGLuint, arg2Mod: TGLuint){.
+    dynlib: dllname, importc: "glAlphaFragmentOp2ATI".}
+proc glAlphaFragmentOp3ATI*(op: TGLenum, dst: TGLuint, dstMod: TGLuint, 
+                            arg1: TGLuint, arg1Rep: TGLuint, arg1Mod: TGLuint, 
+                            arg2: TGLuint, arg2Rep: TGLuint, arg2Mod: TGLuint, 
+                            arg3: TGLuint, arg3Rep: TGLuint, arg3Mod: TGLuint){.
+    dynlib: dllname, importc: "glAlphaFragmentOp3ATI".}
+proc glSetFragmentShaderConstantATI*(dst: TGLuint, value: PGLfloat){.
+    dynlib: dllname, importc: "glSetFragmentShaderConstantATI".}
+  #***** GL_ATI_pn_triangles *****//
+const 
+  GL_PN_TRIANGLES_ATI* = 0x000087F0
+  GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI* = 0x000087F1
+  GL_PN_TRIANGLES_POINT_MODE_ATI* = 0x000087F2
+  GL_PN_TRIANGLES_NORMAL_MODE_ATI* = 0x000087F3
+  GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI* = 0x000087F4
+  GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI* = 0x000087F5
+  GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI* = 0x000087F6
+  GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI* = 0x000087F7
+  GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI* = 0x000087F8
+
+proc glPNTrianglesiATI*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glPNTrianglesiATI".}
+proc glPNTrianglesfATI*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glPNTrianglesfATI".}
+  #***** GL_ATI_texture_mirror_once *****//
+const 
+  GL_MIRROR_CLAMP_ATI* = 0x00008742
+  GL_MIRROR_CLAMP_TO_EDGE_ATI* = 0x00008743
+  #***** GL_ATI_vertex_array_object *****//
+
+const 
+  GL_STATIC_ATI* = 0x00008760
+  GL_DYNAMIC_ATI* = 0x00008761
+  GL_PRESERVE_ATI* = 0x00008762
+  GL_DISCARD_ATI* = 0x00008763
+  GL_OBJECT_BUFFER_SIZE_ATI* = 0x00008764
+  GL_OBJECT_BUFFER_USAGE_ATI* = 0x00008765
+  GL_ARRAY_OBJECT_BUFFER_ATI* = 0x00008766
+  GL_ARRAY_OBJECT_OFFSET_ATI* = 0x00008767
+
+proc glNewObjectBufferATI*(size: TGLsizei, pointer: PGLvoid, usage: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glNewObjectBufferATI".}
+proc glIsObjectBufferATI*(buffer: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsObjectBufferATI".}
+proc glUpdateObjectBufferATI*(buffer: TGLuint, offset: TGLuint, size: TGLsizei, 
+                              pointer: PGLvoid, preserve: TGLenum){.
+    dynlib: dllname, importc: "glUpdateObjectBufferATI".}
+proc glGetObjectBufferfvATI*(buffer: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetObjectBufferfvATI".}
+proc glGetObjectBufferivATI*(buffer: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetObjectBufferivATI".}
+proc glDeleteObjectBufferATI*(buffer: TGLuint){.dynlib: dllname, 
+    importc: "glDeleteObjectBufferATI".}
+proc glArrayObjectATI*(thearray: TGLenum, size: TGLint, thetype: TGLenum, 
+                       stride: TGLsizei, buffer: TGLuint, offset: TGLuint){.
+    dynlib: dllname, importc: "glArrayObjectATI".}
+proc glGetArrayObjectfvATI*(thearray: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetArrayObjectfvATI".}
+proc glGetArrayObjectivATI*(thearray: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetArrayObjectivATI".}
+proc glVariantArrayObjectATI*(id: TGLuint, thetype: TGLenum, stride: TGLsizei, 
+                              buffer: TGLuint, offset: TGLuint){.
+    dynlib: dllname, importc: "glVariantArrayObjectATI".}
+proc glGetVariantArrayObjectfvATI*(id: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVariantArrayObjectfvATI".}
+proc glGetVariantArrayObjectivATI*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVariantArrayObjectivATI".}
+  #***** GL_ATI_vertex_streams *****//
+const 
+  GL_MAX_VERTEX_STREAMS_ATI* = 0x0000876B
+  GL_VERTEX_STREAM0_ATI* = 0x0000876C
+  GL_VERTEX_STREAM1_ATI* = 0x0000876D
+  GL_VERTEX_STREAM2_ATI* = 0x0000876E
+  GL_VERTEX_STREAM3_ATI* = 0x0000876F
+  GL_VERTEX_STREAM4_ATI* = 0x00008770
+  GL_VERTEX_STREAM5_ATI* = 0x00008771
+  GL_VERTEX_STREAM6_ATI* = 0x00008772
+  GL_VERTEX_STREAM7_ATI* = 0x00008773
+  GL_VERTEX_SOURCE_ATI* = 0x00008774
+
+proc glVertexStream1s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream1s".}
+proc glVertexStream1i*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream1i".}
+proc glVertexStream1f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream1f".}
+proc glVertexStream1d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream1d".}
+proc glVertexStream1sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream1sv".}
+proc glVertexStream1iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream1iv".}
+proc glVertexStream1fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream1fv".}
+proc glVertexStream1dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream1dv".}
+proc glVertexStream2s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream2s".}
+proc glVertexStream2i*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream2i".}
+proc glVertexStream2f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream2f".}
+proc glVertexStream2d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream2d".}
+proc glVertexStream2sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream2sv".}
+proc glVertexStream2iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream2iv".}
+proc glVertexStream2fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream2fv".}
+proc glVertexStream2dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream2dv".}
+proc glVertexStream3s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream3s".}
+proc glVertexStream3i*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream3i".}
+proc glVertexStream3f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream3f".}
+proc glVertexStream3d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream3d".}
+proc glVertexStream3sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream3sv".}
+proc glVertexStream3iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream3iv".}
+proc glVertexStream3fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream3fv".}
+proc glVertexStream3dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream3dv".}
+proc glVertexStream4s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream4s".}
+proc glVertexStream4i*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream4i".}
+proc glVertexStream4f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream4f".}
+proc glVertexStream4d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream4d".}
+proc glVertexStream4sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glVertexStream4sv".}
+proc glVertexStream4iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glVertexStream4iv".}
+proc glVertexStream4fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexStream4fv".}
+proc glVertexStream4dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glVertexStream4dv".}
+proc glNormalStream3b*(stream: TGLenum, coords: TGLByte){.dynlib: dllname, 
+    importc: "glNormalStream3b".}
+proc glNormalStream3s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glNormalStream3s".}
+proc glNormalStream3i*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glNormalStream3i".}
+proc glNormalStream3f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glNormalStream3f".}
+proc glNormalStream3d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glNormalStream3d".}
+proc glNormalStream3bv*(stream: TGLenum, coords: TGLByte){.dynlib: dllname, 
+    importc: "glNormalStream3bv".}
+proc glNormalStream3sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname, 
+    importc: "glNormalStream3sv".}
+proc glNormalStream3iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname, 
+    importc: "glNormalStream3iv".}
+proc glNormalStream3fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname, 
+    importc: "glNormalStream3fv".}
+proc glNormalStream3dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname, 
+    importc: "glNormalStream3dv".}
+proc glClientActiveVertexStream*(stream: TGLenum){.dynlib: dllname, 
+    importc: "glClientActiveVertexStream".}
+proc glVertexBlendEnvi*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glVertexBlendEnvi".}
+proc glVertexBlendEnvf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glVertexBlendEnvf".}
+  #***** GL_3DFX_texture_compression_FXT1 *****//
+const 
+  GL_COMPRESSED_RGB_FXT1_3DFX* = 0x000086B0
+  GL_COMPRESSED_RGBA_FXT1_3DFX* = 0x000086B1
+  #***** GL_IBM_cull_vertex *****//
+
+const 
+  GL_CULL_VERTEX_IBM* = 0x0001928A
+  #***** GL_IBM_multimode_draw_arrays *****//
+
+proc glMultiModeDrawArraysIBM*(mode: PGLenum, first: PGLint, count: PGLsizei, 
+                               primcount: TGLsizei, modestride: TGLint){.
+    dynlib: dllname, importc: "glMultiModeDrawArraysIBM".}
+proc glMultiModeDrawElementsIBM*(mode: PGLenum, count: PGLsizei, 
+                                 thetype: TGLenum, indices: PGLvoid, 
+                                 primcount: TGLsizei, modestride: TGLint){.
+    dynlib: dllname, importc: "glMultiModeDrawElementsIBM".}
+  #***** GL_IBM_raster_pos_clip *****//
+const 
+  GL_RASTER_POSITION_UNCLIPPED_IBM* = 0x00019262
+  #***** GL_IBM_texture_mirrored_repeat *****//
+
+const 
+  GL_MIRRORED_REPEAT_IBM* = 0x00008370
+  #***** GL_IBM_vertex_array_lists *****//
+
+const 
+  GL_VERTEX_ARRAY_LIST_IBM* = 0x0001929E
+  GL_NORMAL_ARRAY_LIST_IBM* = 0x0001929F
+  GL_COLOR_ARRAY_LIST_IBM* = 0x000192A0
+  GL_INDEX_ARRAY_LIST_IBM* = 0x000192A1
+  GL_TEXTURE_COORD_ARRAY_LIST_IBM* = 0x000192A2
+  GL_EDGE_FLAG_ARRAY_LIST_IBM* = 0x000192A3
+  GL_FOG_COORDINATE_ARRAY_LIST_IBM* = 0x000192A4
+  GL_SECONDARY_COLOR_ARRAY_LIST_IBM* = 0x000192A5
+  GL_VERTEX_ARRAY_LIST_STRIDE_IBM* = 0x000192A8
+  GL_NORMAL_ARRAY_LIST_STRIDE_IBM* = 0x000192A9
+  GL_COLOR_ARRAY_LIST_STRIDE_IBM* = 0x000192AA
+  GL_INDEX_ARRAY_LIST_STRIDE_IBM* = 0x000192AB
+  GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM* = 0x000192AC
+  GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM* = 0x000192AD
+  GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM* = 0x000192AE
+  GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM* = 0x000192AF
+
+proc glColorPointerListIBM*(size: TGLint, thetype: TGLenum, stride: TGLint, 
+                            pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glColorPointerListIBM".}
+proc glSecondaryColorPointerListIBM*(size: TGLint, thetype: TGLenum, 
+                                     stride: TGLint, pointer: PGLvoid, 
+                                     ptrstride: TGLint){.dynlib: dllname, 
+    importc: "glSecondaryColorPointerListIBM".}
+proc glEdgeFlagPointerListIBM*(stride: TGLint, pointer: PGLboolean, 
+                               ptrstride: TGLint){.dynlib: dllname, 
+    importc: "glEdgeFlagPointerListIBM".}
+proc glFogCoordPointerListIBM*(thetype: TGLenum, stride: TGLint, 
+                               pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glFogCoordPointerListIBM".}
+proc glNormalPointerListIBM*(thetype: TGLenum, stride: TGLint, pointer: PGLvoid, 
+                             ptrstride: TGLint){.dynlib: dllname, 
+    importc: "glNormalPointerListIBM".}
+proc glTexCoordPointerListIBM*(size: TGLint, thetype: TGLenum, stride: TGLint, 
+                               pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glTexCoordPointerListIBM".}
+proc glVertexPointerListIBM*(size: TGLint, thetype: TGLenum, stride: TGLint, 
+                             pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glVertexPointerListIBM".}
+  #***** GL_MESA_resize_buffers *****//
+proc glResizeBuffersMESA*(){.dynlib: dllname, importc: "glResizeBuffersMESA".}
+  #***** GL_MESA_window_pos *****//
+proc glWindowPos2dMESA*(x: TGLdouble, y: TGLdouble){.dynlib: dllname, 
+    importc: "glWindowPos2dMESA".}
+proc glWindowPos2fMESA*(x: TGLfloat, y: TGLfloat){.dynlib: dllname, 
+    importc: "glWindowPos2fMESA".}
+proc glWindowPos2iMESA*(x: TGLint, y: TGLint){.dynlib: dllname, 
+    importc: "glWindowPos2iMESA".}
+proc glWindowPos2sMESA*(x: TGLshort, y: TGLshort){.dynlib: dllname, 
+    importc: "glWindowPos2sMESA".}
+proc glWindowPos2ivMESA*(p: PGLint){.dynlib: dllname, 
+                                     importc: "glWindowPos2ivMESA".}
+proc glWindowPos2svMESA*(p: PGLshort){.dynlib: dllname, 
+                                       importc: "glWindowPos2svMESA".}
+proc glWindowPos2fvMESA*(p: PGLfloat){.dynlib: dllname, 
+                                       importc: "glWindowPos2fvMESA".}
+proc glWindowPos2dvMESA*(p: PGLdouble){.dynlib: dllname, 
+                                        importc: "glWindowPos2dvMESA".}
+proc glWindowPos3iMESA*(x: TGLint, y: TGLint, z: TGLint){.dynlib: dllname, 
+    importc: "glWindowPos3iMESA".}
+proc glWindowPos3sMESA*(x: TGLshort, y: TGLshort, z: TGLshort){.dynlib: dllname, 
+    importc: "glWindowPos3sMESA".}
+proc glWindowPos3fMESA*(x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glWindowPos3fMESA".}
+proc glWindowPos3dMESA*(x: TGLdouble, y: TGLdouble, z: TGLdouble){.
+    dynlib: dllname, importc: "glWindowPos3dMESA".}
+proc glWindowPos3ivMESA*(p: PGLint){.dynlib: dllname, 
+                                     importc: "glWindowPos3ivMESA".}
+proc glWindowPos3svMESA*(p: PGLshort){.dynlib: dllname, 
+                                       importc: "glWindowPos3svMESA".}
+proc glWindowPos3fvMESA*(p: PGLfloat){.dynlib: dllname, 
+                                       importc: "glWindowPos3fvMESA".}
+proc glWindowPos3dvMESA*(p: PGLdouble){.dynlib: dllname, 
+                                        importc: "glWindowPos3dvMESA".}
+proc glWindowPos4iMESA*(x: TGLint, y: TGLint, z: TGLint, w: TGLint){.
+    dynlib: dllname, importc: "glWindowPos4iMESA".}
+proc glWindowPos4sMESA*(x: TGLshort, y: TGLshort, z: TGLshort, w: TGLshort){.
+    dynlib: dllname, importc: "glWindowPos4sMESA".}
+proc glWindowPos4fMESA*(x: TGLfloat, y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glWindowPos4fMESA".}
+proc glWindowPos4dMESA*(x: TGLdouble, y: TGLdouble, z: TGLdouble, w: TGLdouble){.
+    dynlib: dllname, importc: "glWindowPos4dMESA".}
+proc glWindowPos4ivMESA*(p: PGLint){.dynlib: dllname, 
+                                     importc: "glWindowPos4ivMESA".}
+proc glWindowPos4svMESA*(p: PGLshort){.dynlib: dllname, 
+                                       importc: "glWindowPos4svMESA".}
+proc glWindowPos4fvMESA*(p: PGLfloat){.dynlib: dllname, 
+                                       importc: "glWindowPos4fvMESA".}
+proc glWindowPos4dvMESA*(p: PGLdouble){.dynlib: dllname, 
+                                        importc: "glWindowPos4dvMESA".}
+  #***** GL_OML_interlace *****//
+const 
+  GL_INTERLACE_OML* = 0x00008980
+  GL_INTERLACE_READ_OML* = 0x00008981
+  #***** GL_OML_resample *****//
+
+const 
+  GL_PACK_RESAMPLE_OML* = 0x00008984
+  GL_UNPACK_RESAMPLE_OML* = 0x00008985
+  GL_RESAMPLE_REPLICATE_OML* = 0x00008986
+  GL_RESAMPLE_ZERO_FILL_OML* = 0x00008987
+  GL_RESAMPLE_AVERAGE_OML* = 0x00008988
+  GL_RESAMPLE_DECIMATE_OML* = 0x00008989 # GL_RESAMPLE_AVERAGE_OML  { already defined }
+  #***** GL_OML_subsample *****//
+
+const 
+  GL_FORMAT_SUBSAMPLE_24_24_OML* = 0x00008982
+  GL_FORMAT_SUBSAMPLE_244_244_OML* = 0x00008983
+  #***** GL_SGIS_generate_mipmap *****//
+
+const 
+  GL_GENERATE_MIPMAP_SGIS* = 0x00008191
+  GL_GENERATE_MIPMAP_HINT_SGIS* = 0x00008192
+  #***** GL_SGIS_multisample *****//
+
+const 
+  GLX_SAMPLE_BUFFERS_SGIS* = 0x000186A0
+  GLX_SAMPLES_SGIS* = 0x000186A1
+  GL_MULTISAMPLE_SGIS* = 0x0000809D
+  GL_SAMPLE_ALPHA_TO_MASK_SGIS* = 0x0000809E
+  GL_SAMPLE_ALPHA_TO_ONE_SGIS* = 0x0000809F
+  constGL_SAMPLE_MASK_SGIS* = 0x000080A0
+  GL_MULTISAMPLE_BIT_EXT* = 0x20000000
+  GL_1PASS_SGIS* = 0x000080A1
+  GL_2PASS_0_SGIS* = 0x000080A2
+  GL_2PASS_1_SGIS* = 0x000080A3
+  GL_4PASS_0_SGIS* = 0x000080A4
+  GL_4PASS_1_SGIS* = 0x000080A5
+  GL_4PASS_2_SGIS* = 0x000080A6
+  GL_4PASS_3_SGIS* = 0x000080A7
+  GL_SAMPLE_BUFFERS_SGIS* = 0x000080A8
+  GL_SAMPLES_SGIS* = 0x000080A9
+  GL_SAMPLE_MASK_VALUE_SGIS* = 0x000080AA
+  GL_SAMPLE_MASK_INVERT_SGIS* = 0x000080AB
+  constGL_SAMPLE_PATTERN_SGIS* = 0x000080AC
+
+proc glSampleMaskSGIS*(value: TGLclampf, invert: TGLboolean){.dynlib: dllname, 
+    importc: "glSampleMaskSGIS".}
+proc glSamplePatternSGIS*(pattern: TGLenum){.dynlib: dllname, 
+    importc: "glSamplePatternSGIS".}
+  #***** GL_SGIS_pixel_texture *****//
+const 
+  GL_PIXEL_TEXTURE_SGIS* = 0x00008353
+  GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS* = 0x00008354
+  GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS* = 0x00008355
+  GL_PIXEL_GROUP_COLOR_SGIS* = 0x00008356
+
+proc glPixelTexGenParameteriSGIS*(pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glPixelTexGenParameteriSGIS".}
+proc glPixelTexGenParameterfSGIS*(pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glPixelTexGenParameterfSGIS".}
+proc glGetPixelTexGenParameterivSGIS*(pname: TGLenum, params: TGLint){.
+    dynlib: dllname, importc: "glGetPixelTexGenParameterivSGIS".}
+proc glGetPixelTexGenParameterfvSGIS*(pname: TGLenum, params: TGLfloat){.
+    dynlib: dllname, importc: "glGetPixelTexGenParameterfvSGIS".}
+  #***** GL_SGIS_texture_border_clamp *****//
+  # GL_CLAMP_TO_BORDER_SGIS  { already defined }
+  #***** GL_SGIS_texture_color_mask *****//
+const 
+  GL_TEXTURE_COLOR_WRITEMASK_SGIS* = 0x000081EF
+
+proc glTextureColorMaskSGIS*(r: TGLboolean, g: TGLboolean, b: TGLboolean, 
+                             a: TGLboolean){.dynlib: dllname, 
+    importc: "glTextureColorMaskSGIS".}
+  #***** GL_SGIS_texture_edge_clamp *****//
+const 
+  GL_CLAMP_TO_EDGE_SGIS* = 0x0000812F
+  #***** GL_SGIS_texture_lod *****//
+
+const 
+  GL_TEXTURE_MIN_LOD_SGIS* = 0x0000813A
+  GL_TEXTURE_MAX_LOD_SGIS* = 0x0000813B
+  GL_TEXTURE_BASE_LEVEL_SGIS* = 0x0000813C
+  GL_TEXTURE_MAX_LEVEL_SGIS* = 0x0000813D
+  #***** GL_SGIS_depth_texture *****//
+
+const 
+  GL_DEPTH_COMPONENT16_SGIX* = 0x000081A5
+  GL_DEPTH_COMPONENT24_SGIX* = 0x000081A6
+  GL_DEPTH_COMPONENT32_SGIX* = 0x000081A7
+  #***** GL_SGIX_fog_offset *****//
+
+const 
+  GL_FOG_OFFSET_SGIX* = 0x00008198
+  GL_FOG_OFFSET_VALUE_SGIX* = 0x00008199
+  #***** GL_SGIX_interlace *****//
+
+const 
+  GL_INTERLACE_SGIX* = 0x00008094
+  #***** GL_SGIX_shadow_ambient *****//
+
+const 
+  GL_SHADOW_AMBIENT_SGIX* = 0x000080BF
+  #***** GL_SGI_color_matrix *****//
+
+const 
+  GL_COLOR_MATRIX_SGI* = 0x000080B1
+  GL_COLOR_MATRIX_STACK_DEPTH_SGI* = 0x000080B2
+  GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI* = 0x000080B3
+  GL_POST_COLOR_MATRIX_RED_SCALE_SGI* = 0x000080B4
+  GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI* = 0x000080B5
+  GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI* = 0x000080B6
+  GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI* = 0x000080B7
+  GL_POST_COLOR_MATRIX_RED_BIAS_SGI* = 0x000080B8
+  GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI* = 0x000080B9
+  GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI* = 0x000080BA
+  GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI* = 0x000080BB
+  #***** GL_SGI_color_table *****//
+
+const 
+  constGL_COLOR_TABLE_SGI* = 0x000080D0
+  GL_POST_CONVOLUTION_COLOR_TABLE_SGI* = 0x000080D1
+  GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI* = 0x000080D2
+  GL_PROXY_COLOR_TABLE_SGI* = 0x000080D3
+  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI* = 0x000080D4
+  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI* = 0x000080D5
+  GL_COLOR_TABLE_SCALE_SGI* = 0x000080D6
+  GL_COLOR_TABLE_BIAS_SGI* = 0x000080D7
+  GL_COLOR_TABLE_FORMAT_SGI* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH_SGI* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE_SGI* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE_SGI* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE_SGI* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE_SGI* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE_SGI* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE_SGI* = 0x000080DF
+
+proc glColorTableSGI*(target: TGLenum, internalformat: TGLenum, width: TGLsizei, 
+                      format: TGLenum, thetype: TGLenum, table: PGLvoid){.
+    dynlib: dllname, importc: "glColorTableSGI".}
+proc glCopyColorTableSGI*(target: TGLenum, internalformat: TGLenum, x: TGLint, 
+                          y: TGLint, width: TGLsizei){.dynlib: dllname, 
+    importc: "glCopyColorTableSGI".}
+proc glColorTableParameterivSGI*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glColorTableParameterivSGI".}
+proc glColorTableParameterfvSGI*(target: TGLenum, pname: TGLenum, 
+                                 params: PGLfloat){.dynlib: dllname, 
+    importc: "glColorTableParameterfvSGI".}
+proc glGetColorTableSGI*(target: TGLenum, format: TGLenum, thetype: TGLenum, 
+                         table: PGLvoid){.dynlib: dllname, 
+    importc: "glGetColorTableSGI".}
+proc glGetColorTableParameterivSGI*(target: TGLenum, pname: TGLenum, 
+                                    params: PGLint){.dynlib: dllname, 
+    importc: "glGetColorTableParameterivSGI".}
+proc glGetColorTableParameterfvSGI*(target: TGLenum, pname: TGLenum, 
+                                    params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetColorTableParameterfvSGI".}
+  #***** GL_SGI_texture_color_table *****//
+const 
+  GL_TEXTURE_COLOR_TABLE_SGI* = 0x000080BC
+  GL_PROXY_TEXTURE_COLOR_TABLE_SGI* = 0x000080BD
+  #***** GL_SUN_vertex *****//
+
+proc glColor4ubVertex2fSUN*(r: TGLubyte, g: TGLubyte, b: TGLubyte, a: TGLubyte, 
+                            x: TGLfloat, y: TGLfloat){.dynlib: dllname, 
+    importc: "glColor4ubVertex2fSUN".}
+proc glColor4ubVertex2fvSUN*(c: PGLubyte, v: PGLfloat){.dynlib: dllname, 
+    importc: "glColor4ubVertex2fvSUN".}
+proc glColor4ubVertex3fSUN*(r: TGLubyte, g: TGLubyte, b: TGLubyte, a: TGLubyte, 
+                            x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glColor4ubVertex3fSUN".}
+proc glColor4ubVertex3fvSUN*(c: PGLubyte, v: PGLfloat){.dynlib: dllname, 
+    importc: "glColor4ubVertex3fvSUN".}
+proc glColor3fVertex3fSUN*(r: TGLfloat, g: TGLfloat, b: TGLfloat, x: TGLfloat, 
+                           y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glColor3fVertex3fSUN".}
+proc glColor3fVertex3fvSUN*(c: PGLfloat, v: PGLfloat){.dynlib: dllname, 
+    importc: "glColor3fVertex3fvSUN".}
+proc glNormal3fVertex3fSUN*(nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, 
+                            x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glNormal3fVertex3fSUN".}
+proc glNormal3fVertex3fvSUN*(n: PGLfloat, v: PGLfloat){.dynlib: dllname, 
+    importc: "glNormal3fVertex3fvSUN".}
+proc glColor4fNormal3fVertex3fSUN*(r: TGLfloat, g: TGLfloat, b: TGLfloat, 
+                                   a: TGLfloat, nx: TGLfloat, ny: TGLfloat, 
+                                   nz: TGLfloat, x: TGLfloat, y: TGLfloat, 
+                                   z: TGLfloat){.dynlib: dllname, 
+    importc: "glColor4fNormal3fVertex3fSUN".}
+proc glColor4fNormal3fVertex3fvSUN*(c: PGLfloat, n: PGLfloat, v: PGLfloat){.
+    dynlib: dllname, importc: "glColor4fNormal3fVertex3fvSUN".}
+proc glTexCoord2fVertex3fSUN*(s: TGLfloat, t: TGLfloat, x: TGLfloat, 
+                              y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord2fVertex3fSUN".}
+proc glTexCoord2fVertex3fvSUN*(tc: PGLfloat, v: PGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord2fVertex3fvSUN".}
+proc glTexCoord4fVertex4fSUN*(s: TGLfloat, t: TGLfloat, p: TGLfloat, 
+                              q: TGLfloat, x: TGLfloat, y: TGLfloat, 
+                              z: TGLfloat, w: TGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord4fVertex4fSUN".}
+proc glTexCoord4fVertex4fvSUN*(tc: PGLfloat, v: PGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord4fVertex4fvSUN".}
+proc glTexCoord2fColor4ubVertex3fSUN*(s: TGLfloat, t: TGLfloat, r: TGLubyte, 
+                                      g: TGLubyte, b: TGLubyte, a: TGLubyte, 
+                                      x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor4ubVertex3fSUN".}
+proc glTexCoord2fColor4ubVertex3fvSUN*(tc: PGLfloat, c: PGLubyte, v: PGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor4ubVertex3fvSUN".}
+proc glTexCoord2fColor3fVertex3fSUN*(s: TGLfloat, t: TGLfloat, r: TGLfloat, 
+                                     g: TGLfloat, b: TGLfloat, x: TGLfloat, 
+                                     y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord2fColor3fVertex3fSUN".}
+proc glTexCoord2fColor3fVertex3fvSUN*(tc: PGLfloat, c: PGLfloat, v: PGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor3fVertex3fvSUN".}
+proc glTexCoord2fNormal3fVertex3fSUN*(s: TGLfloat, t: TGLfloat, nx: TGLfloat, 
+                                      ny: TGLfloat, nz: TGLfloat, x: TGLfloat, 
+                                      y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fNormal3fVertex3fSUN".}
+proc glTexCoord2fNormal3fVertex3fvSUN*(tc: PGLfloat, n: PGLfloat, v: PGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fNormal3fVertex3fvSUN".}
+proc glTexCoord2fColor4fNormal3fVertex3fSUN*(s: TGLfloat, t: TGLfloat, 
+    r: TGLfloat, g: TGLfloat, b: TGLfloat, a: TGLfloat, nx: TGLfloat, 
+    ny: TGLfloat, nz: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor4fNormal3fVertex3fSUN".}
+proc glTexCoord2fColor4fNormal3fVertex3fvSUN*(tc: PGLfloat, c: PGLfloat, 
+    n: PGLfloat, v: PGLfloat){.dynlib: dllname, importc: "glTexCoord2fColor4fNormal3fVertex3fvSUN".}
+proc glTexCoord4fColor4fNormal3fVertex4fSUN*(s: TGLfloat, t: TGLfloat, 
+    p: TGLfloat, q: TGLfloat, r: TGLfloat, g: TGLfloat, b: TGLfloat, 
+    a: TGLfloat, nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, x: TGLfloat, 
+    y: TGLfloat, z: TGLfloat, w: TGLfloat){.dynlib: dllname, 
+    importc: "glTexCoord4fColor4fNormal3fVertex4fSUN".}
+proc glTexCoord4fColor4fNormal3fVertex4fvSUN*(tc: PGLfloat, c: PGLfloat, 
+    n: PGLfloat, v: PGLfloat){.dynlib: dllname, importc: "glTexCoord4fColor4fNormal3fVertex4fvSUN".}
+proc glReplacementCodeuiVertex3fSUN*(rc: TGLuint, x: TGLfloat, y: TGLfloat, 
+                                     z: TGLfloat){.dynlib: dllname, 
+    importc: "glReplacementCodeuiVertex3fSUN".}
+proc glReplacementCodeuiVertex3fvSUN*(rc: PGLuint, v: PGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiVertex3fvSUN".}
+proc glReplacementCodeuiColor4ubVertex3fSUN*(rc: TGLuint, r: TGLubyte, 
+    g: TGLubyte, b: TGLubyte, a: TGLubyte, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiColor4ubVertex3fSUN".}
+proc glReplacementCodeuiColor4ubVertex3fvSUN*(rc: PGLuint, c: PGLubyte, 
+    v: PGLfloat){.dynlib: dllname, 
+                  importc: "glReplacementCodeuiColor4ubVertex3fvSUN".}
+proc glReplacementCodeuiColor3fVertex3fSUN*(rc: TGLuint, r: TGLfloat, 
+    g: TGLfloat, b: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiColor3fVertex3fSUN".}
+proc glReplacementCodeuiColor3fVertex3fvSUN*(rc: PGLuint, c: PGLfloat, 
+    v: PGLfloat){.dynlib: dllname, 
+                  importc: "glReplacementCodeuiColor3fVertex3fvSUN".}
+proc glReplacementCodeuiNormal3fVertex3fSUN*(rc: TGLuint, nx: TGLfloat, 
+    ny: TGLfloat, nz: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiNormal3fVertex3fSUN".}
+proc glReplacementCodeuiNormal3fVertex3fvSUN*(rc: PGLuint, n: PGLfloat, 
+    v: PGLfloat){.dynlib: dllname, 
+                  importc: "glReplacementCodeuiNormal3fVertex3fvSUN".}
+proc glReplacementCodeuiColor4fNormal3fVertex3fSUN*(rc: TGLuint, r: TGLfloat, 
+    g: TGLfloat, b: TGLfloat, a: TGLfloat, nx: TGLfloat, ny: TGLfloat, 
+    nz: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glReplacementCodeuiColor4fNormal3fVertex3fSUN".}
+proc glReplacementCodeuiColor4fNormal3fVertex3fvSUN*(rc: PGLuint, c: PGLfloat, 
+    n: PGLfloat, v: PGLfloat){.dynlib: dllname, importc: "glReplacementCodeuiColor4fNormal3fVertex3fvSUN".}
+proc glReplacementCodeuiTexCoord2fVertex3fSUN*(rc: TGLuint, s: TGLfloat, 
+    t: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glReplacementCodeuiTexCoord2fVertex3fSUN".}
+proc glReplacementCodeuiTexCoord2fVertex3fvSUN*(rc: PGLuint, tc: PGLfloat, 
+    v: PGLfloat){.dynlib: dllname, 
+                  importc: "glReplacementCodeuiTexCoord2fVertex3fvSUN".}
+proc glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN*(rc: TGLuint, s: TGLfloat, 
+    t: TGLfloat, nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, x: TGLfloat, 
+    y: TGLfloat, z: TGLfloat){.dynlib: dllname, importc: "glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN".}
+proc glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN*(rc: PGLuint, 
+    tc: PGLfloat, n: PGLfloat, v: PGLfloat){.dynlib: dllname, 
+    importc: "glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN".}
+proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN*(rc: TGLuint, 
+    s: TGLfloat, t: TGLfloat, r: TGLfloat, g: TGLfloat, b: TGLfloat, 
+    a: TGLfloat, nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, x: TGLfloat, 
+    y: TGLfloat, z: TGLfloat){.dynlib: dllname, importc: "glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN".}
+proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN*(rc: PGLuint, 
+    tc: PGLfloat, c: PGLfloat, n: PGLfloat, v: PGLfloat){.dynlib: dllname, 
+    importc: "glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN".}
+  #***** GL_ARB_fragment_program *****//
+const 
+  GL_FRAGMENT_PROGRAM_ARB* = 0x00008804 # GL_PROGRAM_FORMAT_ASCII_ARB  { already defined }
+                                        # GL_PROGRAM_LENGTH_ARB  { already defined }
+                                        # GL_PROGRAM_FORMAT_ARB  { already defined }
+                                        # GL_PROGRAM_BINDING_ARB  { already defined }
+                                        # GL_PROGRAM_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_PROGRAM_TEMPORARIES_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_TEMPORARIES_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_TEMPORARIES_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB  { already defined }
+                                        # GL_PROGRAM_PARAMETERS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_PARAMETERS_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_PARAMETERS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB  { already defined }
+                                        # GL_PROGRAM_ATTRIBS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_ATTRIBS_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_ATTRIBS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_ENV_PARAMETERS_ARB  { already defined }
+                                        # GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB  { already defined }
+  GL_PROGRAM_ALU_INSTRUCTIONS_ARB* = 0x00008805
+  GL_PROGRAM_TEX_INSTRUCTIONS_ARB* = 0x00008806
+  GL_PROGRAM_TEX_INDIRECTIONS_ARB* = 0x00008807
+  GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB* = 0x00008808
+  GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB* = 0x00008809
+  GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB* = 0x0000880A
+  GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB* = 0x0000880B
+  GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB* = 0x0000880C
+  GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB* = 0x0000880D
+  GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB* = 0x0000880E
+  GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB* = 0x0000880F
+  GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB* = 0x00008810 # GL_PROGRAM_STRING_ARB  { already defined }
+                                                           # 
+                                                           # 
+                                                           # GL_PROGRAM_ERROR_POSITION_ARB  { already defined }
+                                                           # GL_CURRENT_MATRIX_ARB  { already defined }
+                                                           # 
+                                                           # 
+                                                           # GL_TRANSPOSE_CURRENT_MATRIX_ARB  { already defined }
+                                                           # 
+                                                           # 
+                                                           # GL_CURRENT_MATRIX_STACK_DEPTH_ARB  { already defined }
+                                                           # 
+                                                           # 
+                                                           # GL_MAX_PROGRAM_MATRICES_ARB  { already defined }
+                                                           # 
+                                                           # 
+                                                           # GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB  { already defined }
+  GL_MAX_TEXTURE_COORDS_ARB* = 0x00008871
+  GL_MAX_TEXTURE_IMAGE_UNITS_ARB* = 0x00008872 # GL_PROGRAM_ERROR_STRING_ARB  { already defined }
+                                               # GL_MATRIX0_ARB  { already defined }
+                                               # GL_MATRIX1_ARB  { already defined }
+                                               # GL_MATRIX2_ARB  { already defined }
+                                               # GL_MATRIX3_ARB  { already defined }
+                                               # GL_MATRIX4_ARB  { already defined }
+                                               # GL_MATRIX5_ARB  { already defined }
+                                               # GL_MATRIX6_ARB  { already defined }
+                                               # GL_MATRIX7_ARB  { already defined }
+                                               # GL_MATRIX8_ARB  { already defined }
+                                               # GL_MATRIX9_ARB  { already defined }
+                                               # GL_MATRIX10_ARB  { already defined }
+                                               # GL_MATRIX11_ARB  { already defined }
+                                               # GL_MATRIX12_ARB  { already defined }
+                                               # GL_MATRIX13_ARB  { already defined }
+                                               # GL_MATRIX14_ARB  { already defined }
+                                               # GL_MATRIX15_ARB  { already defined }
+                                               # GL_MATRIX16_ARB  { already defined }
+                                               # GL_MATRIX17_ARB  { already defined }
+                                               # GL_MATRIX18_ARB  { already defined }
+                                               # GL_MATRIX19_ARB  { already defined }
+                                               # GL_MATRIX20_ARB  { already defined }
+                                               # GL_MATRIX21_ARB  { already defined }
+                                               # GL_MATRIX22_ARB  { already defined }
+                                               # GL_MATRIX23_ARB  { already defined }
+                                               # GL_MATRIX24_ARB  { already defined }
+                                               # GL_MATRIX25_ARB  { already defined }
+                                               # GL_MATRIX26_ARB  { already defined }
+                                               # GL_MATRIX27_ARB  { already defined }
+                                               # GL_MATRIX28_ARB  { already defined }
+                                               # GL_MATRIX29_ARB  { already defined }
+                                               # GL_MATRIX30_ARB  { already defined }
+                                               # GL_MATRIX31_ARB  { already defined }
+                                               # glProgramStringARB  { already defined }
+                                               # glBindProgramARB  { already defined }
+                                               # glDeleteProgramsARB  { already defined }
+                                               # glGenProgramsARB  { already defined }
+                                               # glProgramEnvParameter4dARB  { already defined }
+                                               # glProgramEnvParameter4dvARB  { already defined }
+                                               # glProgramEnvParameter4fARB  { already defined }
+                                               # glProgramEnvParameter4fvARB  { already defined }
+                                               # glProgramLocalParameter4dARB  { already defined }
+                                               # glProgramLocalParameter4dvARB  { already defined }
+                                               # glProgramLocalParameter4fARB  { already defined }
+                                               # glProgramLocalParameter4fvARB  { already defined }
+                                               # glGetProgramEnvParameterdvARB  { already defined }
+                                               # glGetProgramEnvParameterfvARB  { already defined }
+                                               # glGetProgramLocalParameterdvARB  { already defined }
+                                               # glGetProgramLocalParameterfvARB  { already defined }
+                                               # glGetProgramivARB  { already defined }
+                                               # glGetProgramStringARB  { already defined }
+                                               # glIsProgramARB  { already defined }
+  #***** GL_ATI_text_fragment_shader *****
+
+const 
+  GL_TEXT_FRAGMENT_SHADER_ATI* = 0x00008200 #***** GL_ARB_vertex_buffer_object *****
+
+const 
+  GL_BUFFER_SIZE_ARB* = 0x00008764
+  GL_BUFFER_USAGE_ARB* = 0x00008765
+  GL_ARRAY_BUFFER_ARB* = 0x00008892
+  GL_ELEMENT_ARRAY_BUFFER_ARB* = 0x00008893
+  GL_ARRAY_BUFFER_BINDING_ARB* = 0x00008894
+  GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB* = 0x00008895
+  GL_VERTEX_ARRAY_BUFFER_BINDING_ARB* = 0x00008896
+  GL_NORMAL_ARRAY_BUFFER_BINDING_ARB* = 0x00008897
+  GL_COLOR_ARRAY_BUFFER_BINDING_ARB* = 0x00008898
+  GL_INDEX_ARRAY_BUFFER_BINDING_ARB* = 0x00008899
+  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB* = 0x0000889A
+  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB* = 0x0000889B
+  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB* = 0x0000889C
+  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB* = 0x0000889D
+  GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB* = 0x0000889E
+  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB* = 0x0000889F
+  GL_READ_ONLY_ARB* = 0x000088B8
+  GL_WRITE_ONLY_ARB* = 0x000088B9
+  GL_READ_WRITE_ARB* = 0x000088BA
+  GL_BUFFER_ACCESS_ARB* = 0x000088BB
+  GL_BUFFER_MAPPED_ARB* = 0x000088BC
+  GL_BUFFER_MAP_POINTER_ARB* = 0x000088BD
+  GL_STREAM_DRAW_ARB* = 0x000088E0
+  GL_STREAM_READ_ARB* = 0x000088E1
+  GL_STREAM_COPY_ARB* = 0x000088E2
+  GL_STATIC_DRAW_ARB* = 0x000088E4
+  GL_STATIC_READ_ARB* = 0x000088E5
+  GL_STATIC_COPY_ARB* = 0x000088E6
+  GL_DYNAMIC_DRAW_ARB* = 0x000088E8
+  GL_DYNAMIC_READ_ARB* = 0x000088E9
+  GL_DYNAMIC_COPY_ARB* = 0x000088EA
+
+proc glBindBufferARB*(target: TGLenum, buffer: TGLuint){.dynlib: dllname, 
+    importc: "glBindBufferARB".}
+proc glDeleteBuffersARB*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteBuffersARB".}
+proc glGenBuffersARB*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname, 
+    importc: "glGenBuffersARB".}
+proc glIsBufferARB*(buffer: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsBufferARB".}
+proc glBufferDataARB*(target: TGLenum, size: TGLsizei, data: PGLvoid, 
+                      usage: TGLenum){.dynlib: dllname, 
+                                       importc: "glBufferDataARB".}
+proc glBufferSubDataARB*(target: TGLenum, offset: TGLint, size: TGLsizei, 
+                         data: PGLvoid){.dynlib: dllname, 
+    importc: "glBufferSubDataARB".}
+proc glGetBufferSubDataARB*(target: TGLenum, offset: TGLint, size: TGLsizei, 
+                            data: PGLvoid){.dynlib: dllname, 
+    importc: "glGetBufferSubDataARB".}
+proc glMapBufferARB*(target: TGLenum, access: TGLenum): PGLvoid{.
+    dynlib: dllname, importc: "glMapBufferARB".}
+proc glUnmapBufferARB*(target: TGLenum): TGLboolean{.dynlib: dllname, 
+    importc: "glUnmapBufferARB".}
+proc glGetBufferParameterivARB*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetBufferParameterivARB".}
+proc glGetBufferPointervARB*(target: TGLenum, pname: TGLenum, params: PPGLvoid){.
+    dynlib: dllname, importc: "glGetBufferPointervARB".}
+  #***** GL_APPLE_client_storage *****//
+const 
+  GL_UNPACK_CLIENT_STORAGE_APPLE* = 0x000085B2
+  #***** GL_APPLE_element_array *****//
+
+const 
+  GL_ELEMENT_ARRAY_APPLE* = 0x00008768
+  GL_ELEMENT_ARRAY_TYPE_APPLE* = 0x00008769
+  GL_ELEMENT_ARRAY_POINTER_APPLE* = 0x0000876A
+
+proc glElementPointerAPPLE*(thetype: TGLenum, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glElementPointerAPPLE".}
+proc glDrawElementArrayAPPLE*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawElementArrayAPPLE".}
+proc glDrawRangeElementArrayAPPLE*(mode: TGLenum, start: TGLuint, 
+                                   theend: TGLuint, first: TGLint, 
+                                   count: TGLsizei){.dynlib: dllname, 
+    importc: "glDrawRangeElementArrayAPPLE".}
+proc glMultiDrawElementArrayAPPLE*(mode: TGLenum, first: PGLint, 
+                                   count: PGLsizei, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawElementArrayAPPLE".}
+proc glMultiDrawRangeElementArrayAPPLE*(mode: TGLenum, start: TGLuint, 
+                                        theend: TGLuint, first: PGLint, 
+                                        count: PGLsizei, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawRangeElementArrayAPPLE".}
+  #***** GL_APPLE_fence *****//
+const 
+  GL_DRAW_PIXELS_APPLE* = 0x00008A0A
+  GL_FENCE_APPLE* = 0x00008A0B
+
+proc glGenFencesAPPLE*(n: TGLsizei, fences: PGLuint){.dynlib: dllname, 
+    importc: "glGenFencesAPPLE".}
+proc glDeleteFencesAPPLE*(n: TGLsizei, fences: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteFencesAPPLE".}
+proc glSetFenceAPPLE*(fence: TGLuint){.dynlib: dllname, 
+                                       importc: "glSetFenceAPPLE".}
+proc glIsFenceAPPLE*(fence: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsFenceAPPLE".}
+proc glTestFenceAPPLE*(fence: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glTestFenceAPPLE".}
+proc glFinishFenceAPPLE*(fence: TGLuint){.dynlib: dllname, 
+    importc: "glFinishFenceAPPLE".}
+proc glTestObjectAPPLE*(theobject: TGLenum, name: TGLuint): TGLboolean{.
+    dynlib: dllname, importc: "glTestObjectAPPLE".}
+proc glFinishObjectAPPLE*(theobject: TGLenum, name: TGLint){.dynlib: dllname, 
+    importc: "glFinishObjectAPPLE".}
+  #***** GL_APPLE_vertex_array_object *****//
+const 
+  GL_VERTEX_ARRAY_BINDING_APPLE* = 0x000085B5
+
+proc glBindVertexArrayAPPLE*(thearray: TGLuint){.dynlib: dllname, 
+    importc: "glBindVertexArrayAPPLE".}
+proc glDeleteVertexArraysAPPLE*(n: TGLsizei, arrays: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteVertexArraysAPPLE".}
+proc glGenVertexArraysAPPLE*(n: TGLsizei, arrays: PGLuint){.dynlib: dllname, 
+    importc: "glGenVertexArraysAPPLE".}
+proc glIsVertexArrayAPPLE*(thearray: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsVertexArrayAPPLE".}
+  #***** GL_APPLE_vertex_array_range *****//
+const 
+  constGL_VERTEX_ARRAY_RANGE_APPLE* = 0x0000851D
+  GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE* = 0x0000851E
+  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE* = 0x00008520
+  GL_VERTEX_ARRAY_RANGE_POINTER_APPLE* = 0x00008521
+  GL_VERTEX_ARRAY_STORAGE_HINT_APPLE* = 0x0000851F
+  GL_STORAGE_CACHED_APPLE* = 0x000085BE
+  GL_STORAGE_SHARED_APPLE* = 0x000085BF
+
+proc glVertexArrayRangeAPPLE*(len: TGLsizei, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glVertexArrayRangeAPPLE".}
+proc glFlushVertexArrayRangeAPPLE*(len: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glFlushVertexArrayRangeAPPLE".}
+proc glVertexArrayParameteriAPPLE*(pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glVertexArrayParameteriAPPLE".}
+  #***** GL_ARB_matrix_palette *****//
+const 
+  GL_MATRIX_PALETTE_ARB* = 0x00008840
+  GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB* = 0x00008841
+  GL_MAX_PALETTE_MATRICES_ARB* = 0x00008842
+  constGL_CURRENT_PALETTE_MATRIX_ARB* = 0x00008843
+  GL_MATRIX_INDEX_ARRAY_ARB* = 0x00008844
+  GL_CURRENT_MATRIX_INDEX_ARB* = 0x00008845
+  GL_MATRIX_INDEX_ARRAY_SIZE_ARB* = 0x00008846
+  GL_MATRIX_INDEX_ARRAY_TYPE_ARB* = 0x00008847
+  GL_MATRIX_INDEX_ARRAY_STRIDE_ARB* = 0x00008848
+  GL_MATRIX_INDEX_ARRAY_POINTER_ARB* = 0x00008849
+
+proc glCurrentPaletteMatrixARB*(index: TGLint){.dynlib: dllname, 
+    importc: "glCurrentPaletteMatrixARB".}
+proc glMatrixIndexubvARB*(size: TGLint, indices: PGLubyte){.dynlib: dllname, 
+    importc: "glMatrixIndexubvARB".}
+proc glMatrixIndexusvARB*(size: TGLint, indices: PGLushort){.dynlib: dllname, 
+    importc: "glMatrixIndexusvARB".}
+proc glMatrixIndexuivARB*(size: TGLint, indices: PGLuint){.dynlib: dllname, 
+    importc: "glMatrixIndexuivARB".}
+proc glMatrixIndexPointerARB*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                              pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glMatrixIndexPointerARB".}
+  #***** GL_NV_element_array *****//
+const 
+  GL_ELEMENT_ARRAY_TYPE_NV* = 0x00008769
+  GL_ELEMENT_ARRAY_POINTER_NV* = 0x0000876A
+
+proc glElementPointerNV*(thetype: TGLenum, pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glElementPointerNV".}
+proc glDrawElementArrayNV*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawElementArrayNV".}
+proc glDrawRangeElementArrayNV*(mode: TGLenum, start: TGLuint, theend: TGLuint, 
+                                first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawRangeElementArrayNV".}
+proc glMultiDrawElementArrayNV*(mode: TGLenum, first: PGLint, count: PGLsizei, 
+                                primcount: TGLsizei){.dynlib: dllname, 
+    importc: "glMultiDrawElementArrayNV".}
+proc glMultiDrawRangeElementArrayNV*(mode: TGLenum, start: TGLuint, 
+                                     theend: TGLuint, first: PGLint, 
+                                     count: PGLsizei, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawRangeElementArrayNV".}
+  #***** GL_NV_float_buffer *****//
+const 
+  GL_FLOAT_R_NV* = 0x00008880
+  GL_FLOAT_RG_NV* = 0x00008881
+  GL_FLOAT_RGB_NV* = 0x00008882
+  GL_FLOAT_RGBA_NV* = 0x00008883
+  GL_FLOAT_R16_NV* = 0x00008884
+  GL_FLOAT_R32_NV* = 0x00008885
+  GL_FLOAT_RG16_NV* = 0x00008886
+  GL_FLOAT_RG32_NV* = 0x00008887
+  GL_FLOAT_RGB16_NV* = 0x00008888
+  GL_FLOAT_RGB32_NV* = 0x00008889
+  GL_FLOAT_RGBA16_NV* = 0x0000888A
+  GL_FLOAT_RGBA32_NV* = 0x0000888B
+  GL_TEXTURE_FLOAT_COMPONENTS_NV* = 0x0000888C
+  GL_FLOAT_CLEAR_COLOR_VALUE_NV* = 0x0000888D
+  GL_FLOAT_RGBA_MODE_NV* = 0x0000888E
+  #***** GL_NV_fragment_program *****//
+
+const 
+  GL_FRAGMENT_PROGRAM_NV* = 0x00008870
+  GL_MAX_TEXTURE_COORDS_NV* = 0x00008871
+  GL_MAX_TEXTURE_IMAGE_UNITS_NV* = 0x00008872
+  GL_FRAGMENT_PROGRAM_BINDING_NV* = 0x00008873
+  GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV* = 0x00008868
+  GL_PROGRAM_ERROR_STRING_NV* = 0x00008874
+
+proc glProgramNamedParameter4fNV*(id: TGLuint, length: TGLsizei, name: PGLubyte, 
+                                  x: TGLfloat, y: TGLfloat, z: TGLfloat, 
+                                  w: TGLfloat){.dynlib: dllname, 
+    importc: "glProgramNamedParameter4fNV".}
+proc glProgramNamedParameter4dNV*(id: TGLuint, length: TGLsizei, name: PGLubyte, 
+                                  x: TGLdouble, y: TGLdouble, z: TGLdouble, 
+                                  w: TGLdouble){.dynlib: dllname, 
+    importc: "glProgramNamedParameter4dNV".}
+proc glGetProgramNamedParameterfvNV*(id: TGLuint, length: TGLsizei, 
+                                     name: PGLubyte, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetProgramNamedParameterfvNV".}
+proc glGetProgramNamedParameterdvNV*(id: TGLuint, length: TGLsizei, 
+                                     name: PGLubyte, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetProgramNamedParameterdvNV".}
+  # glProgramLocalParameter4dARB  { already defined }
+  # glProgramLocalParameter4dvARB  { already defined }
+  # glProgramLocalParameter4fARB  { already defined }
+  # glProgramLocalParameter4fvARB  { already defined }
+  # glGetProgramLocalParameterdvARB  { already defined }
+  # glGetProgramLocalParameterfvARB  { already defined }
+  #***** GL_NV_primitive_restart *****//
+const 
+  constGL_PRIMITIVE_RESTART_NV* = 0x00008558
+  constGL_PRIMITIVE_RESTART_INDEX_NV* = 0x00008559
+
+proc glPrimitiveRestartNV*(){.dynlib: dllname, importc: "glPrimitiveRestartNV".}
+proc glPrimitiveRestartIndexNV*(index: TGLuint){.dynlib: dllname, 
+    importc: "glPrimitiveRestartIndexNV".}
+  #***** GL_NV_vertex_program2 *****//
+  #***** GL_NV_pixel_data_range *****//
+const 
+  GL_WRITE_PIXEL_DATA_RANGE_NV* = 0x00008878
+  GL_READ_PIXEL_DATA_RANGE_NV* = 0x00008879
+  GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV* = 0x0000887A
+  GL_READ_PIXEL_DATA_RANGE_LENGTH_NV* = 0x0000887B
+  GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV* = 0x0000887C
+  GL_READ_PIXEL_DATA_RANGE_POINTER_NV* = 0x0000887D
+
+proc glPixelDataRangeNV*(target: TGLenum, len: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glPixelDataRangeNV".}
+proc glFlushPixelDataRangeNV*(target: TGLenum){.dynlib: dllname, 
+    importc: "glFlushPixelDataRangeNV".}
+  # wglAllocateMemoryNV  { already defined }
+  # wglFreeMemoryNV  { already defined }
+  #***** GL_EXT_texture_rectangle *****//
+const 
+  GL_TEXTURE_RECTANGLE_EXT* = 0x000084F5
+  GL_TEXTURE_BINDING_RECTANGLE_EXT* = 0x000084F6
+  GL_PROXY_TEXTURE_RECTANGLE_EXT* = 0x000084F7
+  GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT* = 0x000084F8
+  #***** GL_S3_s3tc *****//
+
+const 
+  GL_RGB_S3TC* = 0x000083A0
+  GL_RGB4_S3TC* = 0x000083A1
+  GL_RGBA_S3TC* = 0x000083A2
+  GL_RGBA4_S3TC* = 0x000083A3
+  #***** GL_ATI_draw_buffers *****//
+
+const 
+  GL_MAX_DRAW_BUFFERS_ATI* = 0x00008824
+  GL_DRAW_BUFFER0_ATI* = 0x00008825
+  GL_DRAW_BUFFER1_ATI* = 0x00008826
+  GL_DRAW_BUFFER2_ATI* = 0x00008827
+  GL_DRAW_BUFFER3_ATI* = 0x00008828
+  GL_DRAW_BUFFER4_ATI* = 0x00008829
+  GL_DRAW_BUFFER5_ATI* = 0x0000882A
+  GL_DRAW_BUFFER6_ATI* = 0x0000882B
+  GL_DRAW_BUFFER7_ATI* = 0x0000882C
+  GL_DRAW_BUFFER8_ATI* = 0x0000882D
+  GL_DRAW_BUFFER9_ATI* = 0x0000882E
+  GL_DRAW_BUFFER10_ATI* = 0x0000882F
+  GL_DRAW_BUFFER11_ATI* = 0x00008830
+  GL_DRAW_BUFFER12_ATI* = 0x00008831
+  GL_DRAW_BUFFER13_ATI* = 0x00008832
+  GL_DRAW_BUFFER14_ATI* = 0x00008833
+  GL_DRAW_BUFFER15_ATI* = 0x00008834
+
+proc glDrawBuffersATI*(n: TGLsizei, bufs: PGLenum){.dynlib: dllname, 
+    importc: "glDrawBuffersATI".}
+  #***** GL_ATI_texture_env_combine3 *****//
+const 
+  GL_MODULATE_ADD_ATI* = 0x00008744
+  GL_MODULATE_SIGNED_ADD_ATI* = 0x00008745
+  GL_MODULATE_SUBTRACT_ATI* = 0x00008746
+  #***** GL_ATI_texture_float *****//
+
+const 
+  GL_RGBA_FLOAT32_ATI* = 0x00008814
+  GL_RGB_FLOAT32_ATI* = 0x00008815
+  GL_ALPHA_FLOAT32_ATI* = 0x00008816
+  GL_INTENSITY_FLOAT32_ATI* = 0x00008817
+  GL_LUMINANCE_FLOAT32_ATI* = 0x00008818
+  GL_LUMINANCE_ALPHA_FLOAT32_ATI* = 0x00008819
+  GL_RGBA_FLOAT16_ATI* = 0x0000881A
+  GL_RGB_FLOAT16_ATI* = 0x0000881B
+  GL_ALPHA_FLOAT16_ATI* = 0x0000881C
+  GL_INTENSITY_FLOAT16_ATI* = 0x0000881D
+  GL_LUMINANCE_FLOAT16_ATI* = 0x0000881E
+  GL_LUMINANCE_ALPHA_FLOAT16_ATI* = 0x0000881F
+  #***** GL_NV_texture_expand_normal *****//
+
+const 
+  GL_TEXTURE_UNSIGNED_REMAP_MODE_NV* = 0x0000888F
+  #***** GL_NV_half_float *****//
+
+const 
+  GL_HALF_FLOAT_NV* = 0x0000140B
+
+proc glVertex2hNV*(x: TGLushort, y: TGLushort){.dynlib: dllname, 
+    importc: "glVertex2hNV".}
+proc glVertex2hvNV*(v: PGLushort){.dynlib: dllname, importc: "glVertex2hvNV".}
+proc glVertex3hNV*(x: TGLushort, y: TGLushort, z: TGLushort){.dynlib: dllname, 
+    importc: "glVertex3hNV".}
+proc glVertex3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glVertex3hvNV".}
+proc glVertex4hNV*(x: TGLushort, y: TGLushort, z: TGLushort, w: TGLushort){.
+    dynlib: dllname, importc: "glVertex4hNV".}
+proc glVertex4hvNV*(v: PGLushort){.dynlib: dllname, importc: "glVertex4hvNV".}
+proc glNormal3hNV*(nx: TGLushort, ny: TGLushort, nz: TGLushort){.
+    dynlib: dllname, importc: "glNormal3hNV".}
+proc glNormal3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glNormal3hvNV".}
+proc glColor3hNV*(red: TGLushort, green: TGLushort, blue: TGLushort){.
+    dynlib: dllname, importc: "glColor3hNV".}
+proc glColor3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glColor3hvNV".}
+proc glColor4hNV*(red: TGLushort, green: TGLushort, blue: TGLushort, 
+                  alpha: TGLushort){.dynlib: dllname, importc: "glColor4hNV".}
+proc glColor4hvNV*(v: PGLushort){.dynlib: dllname, importc: "glColor4hvNV".}
+proc glTexCoord1hNV*(s: TGLushort){.dynlib: dllname, importc: "glTexCoord1hNV".}
+proc glTexCoord1hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord1hvNV".}
+proc glTexCoord2hNV*(s: TGLushort, t: TGLushort){.dynlib: dllname, 
+    importc: "glTexCoord2hNV".}
+proc glTexCoord2hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord2hvNV".}
+proc glTexCoord3hNV*(s: TGLushort, t: TGLushort, r: TGLushort){.dynlib: dllname, 
+    importc: "glTexCoord3hNV".}
+proc glTexCoord3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord3hvNV".}
+proc glTexCoord4hNV*(s: TGLushort, t: TGLushort, r: TGLushort, q: TGLushort){.
+    dynlib: dllname, importc: "glTexCoord4hNV".}
+proc glTexCoord4hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord4hvNV".}
+proc glMultiTexCoord1hNV*(target: TGLenum, s: TGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord1hNV".}
+proc glMultiTexCoord1hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord1hvNV".}
+proc glMultiTexCoord2hNV*(target: TGLenum, s: TGLushort, t: TGLushort){.
+    dynlib: dllname, importc: "glMultiTexCoord2hNV".}
+proc glMultiTexCoord2hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord2hvNV".}
+proc glMultiTexCoord3hNV*(target: TGLenum, s: TGLushort, t: TGLushort, 
+                          r: TGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord3hNV".}
+proc glMultiTexCoord3hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord3hvNV".}
+proc glMultiTexCoord4hNV*(target: TGLenum, s: TGLushort, t: TGLushort, 
+                          r: TGLushort, q: TGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord4hNV".}
+proc glMultiTexCoord4hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname, 
+    importc: "glMultiTexCoord4hvNV".}
+proc glFogCoordhNV*(fog: TGLushort){.dynlib: dllname, importc: "glFogCoordhNV".}
+proc glFogCoordhvNV*(fog: PGLushort){.dynlib: dllname, importc: "glFogCoordhvNV".}
+proc glSecondaryColor3hNV*(red: TGLushort, green: TGLushort, blue: TGLushort){.
+    dynlib: dllname, importc: "glSecondaryColor3hNV".}
+proc glSecondaryColor3hvNV*(v: PGLushort){.dynlib: dllname, 
+    importc: "glSecondaryColor3hvNV".}
+proc glVertexWeighthNV*(weight: TGLushort){.dynlib: dllname, 
+    importc: "glVertexWeighthNV".}
+proc glVertexWeighthvNV*(weight: PGLushort){.dynlib: dllname, 
+    importc: "glVertexWeighthvNV".}
+proc glVertexAttrib1hNV*(index: TGLuint, x: TGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib1hNV".}
+proc glVertexAttrib1hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib1hvNV".}
+proc glVertexAttrib2hNV*(index: TGLuint, x: TGLushort, y: TGLushort){.
+    dynlib: dllname, importc: "glVertexAttrib2hNV".}
+proc glVertexAttrib2hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib2hvNV".}
+proc glVertexAttrib3hNV*(index: TGLuint, x: TGLushort, y: TGLushort, 
+                         z: TGLushort){.dynlib: dllname, 
+                                        importc: "glVertexAttrib3hNV".}
+proc glVertexAttrib3hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib3hvNV".}
+proc glVertexAttrib4hNV*(index: TGLuint, x: TGLushort, y: TGLushort, 
+                         z: TGLushort, w: TGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib4hNV".}
+proc glVertexAttrib4hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname, 
+    importc: "glVertexAttrib4hvNV".}
+proc glVertexAttribs1hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs1hvNV".}
+proc glVertexAttribs2hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs2hvNV".}
+proc glVertexAttribs3hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs3hvNV".}
+proc glVertexAttribs4hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs4hvNV".}
+  #***** GL_ATI_map_object_buffer *****//
+proc glMapObjectBufferATI*(buffer: TGLuint): PGLvoid{.dynlib: dllname, 
+    importc: "glMapObjectBufferATI".}
+proc glUnmapObjectBufferATI*(buffer: TGLuint){.dynlib: dllname, 
+    importc: "glUnmapObjectBufferATI".}
+  #***** GL_ATI_separate_stencil *****//
+const 
+  GL_KEEP* = 0x00001E00
+  GL_ZERO* = 0x00000000
+  GL_REPLACE* = 0x00001E01
+  GL_INCR* = 0x00001E02
+  GL_DECR* = 0x00001E03
+  GL_INVERT* = 0x0000150A
+  GL_NEVER* = 0x00000200
+  GL_LESS* = 0x00000201
+  GL_LEQUAL* = 0x00000203
+  GL_GREATER* = 0x00000204
+  GL_GEQUAL* = 0x00000206
+  GL_EQUAL* = 0x00000202
+  GL_NOTEQUAL* = 0x00000205
+  GL_ALWAYS* = 0x00000207
+  GL_FRONT* = 0x00000404
+  GL_BACK* = 0x00000405
+  GL_FRONT_AND_BACK* = 0x00000408
+  GL_STENCIL_BACK_FUNC_ATI* = 0x00008800
+  GL_STENCIL_BACK_FAIL_ATI* = 0x00008801
+  GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI* = 0x00008802
+  GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI* = 0x00008803
+
+proc glStencilOpSeparateATI*(face: TGLenum, sfail: TGLenum, dpfail: TGLenum, 
+                             dppass: TGLenum){.dynlib: dllname, 
+    importc: "glStencilOpSeparateATI".}
+proc glStencilFuncSeparateATI*(frontfunc: TGLenum, backfunc: TGLenum, 
+                               theRef: TGLint, mask: TGLuint){.dynlib: dllname, 
+    importc: "glStencilFuncSeparateATI".}
+  #***** GL_ATI_vertex_attrib_array_object *****//
+proc glVertexAttribArrayObjectATI*(index: TGLuint, size: TGLint, 
+                                   thetype: TGLenum, normalized: TGLboolean, 
+                                   stride: TGLsizei, buffer: TGLuint, 
+                                   offset: TGLuint){.dynlib: dllname, 
+    importc: "glVertexAttribArrayObjectATI".}
+proc glGetVertexAttribArrayObjectfvATI*(index: TGLuint, pname: TGLenum, 
+                                        params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetVertexAttribArrayObjectfvATI".}
+proc glGetVertexAttribArrayObjectivATI*(index: TGLuint, pname: TGLenum, 
+                                        params: PGLint){.dynlib: dllname, 
+    importc: "glGetVertexAttribArrayObjectivATI".}
+  #***** GL_ARB_occlusion_query *****//
+const 
+  GL_SAMPLES_PASSED_ARB* = 0x00008914
+  GL_QUERY_COUNTER_BITS_ARB* = 0x00008864
+  GL_CURRENT_QUERY_ARB* = 0x00008865
+  GL_QUERY_RESULT_ARB* = 0x00008866
+  GL_QUERY_RESULT_AVAILABLE_ARB* = 0x00008867
+
+proc glGenQueriesARB*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glGenQueriesARB".}
+proc glDeleteQueriesARB*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteQueriesARB".}
+proc glIsQueryARB*(id: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsQueryARB".}
+proc glBeginQueryARB*(target: TGLenum, id: TGLuint){.dynlib: dllname, 
+    importc: "glBeginQueryARB".}
+proc glEndQueryARB*(target: TGLenum){.dynlib: dllname, importc: "glEndQueryARB".}
+proc glGetQueryivARB*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryivARB".}
+proc glGetQueryObjectivARB*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryObjectivARB".}
+proc glGetQueryObjectuivARB*(id: TGLuint, pname: TGLenum, params: PGLuint){.
+    dynlib: dllname, importc: "glGetQueryObjectuivARB".}
+  #***** GL_ARB_shader_objects *****//
+const 
+  GL_PROGRAM_OBJECT_ARB* = 0x00008B40
+  GL_OBJECT_TYPE_ARB* = 0x00008B4E
+  GL_OBJECT_SUBTYPE_ARB* = 0x00008B4F
+  GL_OBJECT_DELETE_STATUS_ARB* = 0x00008B80
+  GL_OBJECT_COMPILE_STATUS_ARB* = 0x00008B81
+  GL_OBJECT_LINK_STATUS_ARB* = 0x00008B82
+  GL_OBJECT_VALIDATE_STATUS_ARB* = 0x00008B83
+  GL_OBJECT_INFO_LOG_LENGTH_ARB* = 0x00008B84
+  GL_OBJECT_ATTACHED_OBJECTS_ARB* = 0x00008B85
+  GL_OBJECT_ACTIVE_UNIFORMS_ARB* = 0x00008B86
+  GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB* = 0x00008B87
+  GL_OBJECT_SHADER_SOURCE_LENGTH_ARB* = 0x00008B88
+  GL_SHADER_OBJECT_ARB* = 0x00008B48
+  GL_FLOAT* = 0x00001406
+  GL_FLOAT_VEC2_ARB* = 0x00008B50
+  GL_FLOAT_VEC3_ARB* = 0x00008B51
+  GL_FLOAT_VEC4_ARB* = 0x00008B52
+  GL_INT* = 0x00001404
+  GL_INT_VEC2_ARB* = 0x00008B53
+  GL_INT_VEC3_ARB* = 0x00008B54
+  GL_INT_VEC4_ARB* = 0x00008B55
+  GL_BOOL_ARB* = 0x00008B56
+  GL_BOOL_VEC2_ARB* = 0x00008B57
+  GL_BOOL_VEC3_ARB* = 0x00008B58
+  GL_BOOL_VEC4_ARB* = 0x00008B59
+  GL_FLOAT_MAT2_ARB* = 0x00008B5A
+  GL_FLOAT_MAT3_ARB* = 0x00008B5B
+  GL_FLOAT_MAT4_ARB* = 0x00008B5C
+
+proc glDeleteObjectARB*(obj: GLhandleARB){.dynlib: dllname, 
+    importc: "glDeleteObjectARB".}
+proc glGetHandleARB*(pname: TGLenum): GLhandleARB{.dynlib: dllname, 
+    importc: "glGetHandleARB".}
+proc glDetachObjectARB*(containerObj: GLhandleARB, attachedObj: GLhandleARB){.
+    dynlib: dllname, importc: "glDetachObjectARB".}
+proc glCreateShaderObjectARB*(shaderType: TGLenum): GLhandleARB{.
+    dynlib: dllname, importc: "glCreateShaderObjectARB".}
+proc glShaderSourceARB*(shaderObj: GLhandleARB, count: TGLsizei, str: PGLvoid, 
+                        len: PGLint){.dynlib: dllname, 
+                                      importc: "glShaderSourceARB".}
+proc glCompileShaderARB*(shaderObj: GLhandleARB){.dynlib: dllname, 
+    importc: "glCompileShaderARB".}
+proc glCreateProgramObjectARB*(): GLhandleARB{.dynlib: dllname, 
+    importc: "glCreateProgramObjectARB".}
+proc glAttachObjectARB*(containerObj: GLhandleARB, obj: GLhandleARB){.
+    dynlib: dllname, importc: "glAttachObjectARB".}
+proc glLinkProgramARB*(programObj: GLhandleARB){.dynlib: dllname, 
+    importc: "glLinkProgramARB".}
+proc glUseProgramObjectARB*(programObj: GLhandleARB){.dynlib: dllname, 
+    importc: "glUseProgramObjectARB".}
+proc glValidateProgramARB*(programObj: GLhandleARB){.dynlib: dllname, 
+    importc: "glValidateProgramARB".}
+proc glUniform1fARB*(location: TGLint, v0: TGLfloat){.dynlib: dllname, 
+    importc: "glUniform1fARB".}
+proc glUniform2fARB*(location: TGLint, v0: TGLfloat, v1: TGLfloat){.
+    dynlib: dllname, importc: "glUniform2fARB".}
+proc glUniform3fARB*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat){.
+    dynlib: dllname, importc: "glUniform3fARB".}
+proc glUniform4fARB*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat, 
+                     v3: TGLfloat){.dynlib: dllname, importc: "glUniform4fARB".}
+proc glUniform1iARB*(location: TGLint, v0: TGLint){.dynlib: dllname, 
+    importc: "glUniform1iARB".}
+proc glUniform2iARB*(location: TGLint, v0: TGLint, v1: TGLint){.dynlib: dllname, 
+    importc: "glUniform2iARB".}
+proc glUniform3iARB*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint){.
+    dynlib: dllname, importc: "glUniform3iARB".}
+proc glUniform4iARB*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint, 
+                     v3: TGLint){.dynlib: dllname, importc: "glUniform4iARB".}
+proc glUniform1fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform1fvARB".}
+proc glUniform2fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform2fvARB".}
+proc glUniform3fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform3fvARB".}
+proc glUniform4fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform4fvARB".}
+proc glUniform1ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform1ivARB".}
+proc glUniform2ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform2ivARB".}
+proc glUniform3ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform3ivARB".}
+proc glUniform4ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform4ivARB".}
+proc glUniformMatrix2fvARB*(location: TGLint, count: TGLsizei, 
+                            transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix2fvARB".}
+proc glUniformMatrix3fvARB*(location: TGLint, count: TGLsizei, 
+                            transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix3fvARB".}
+proc glUniformMatrix4fvARB*(location: TGLint, count: TGLsizei, 
+                            transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix4fvARB".}
+proc glGetObjectParameterfvARB*(obj: GLhandleARB, pname: TGLenum, 
+                                params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetObjectParameterfvARB".}
+proc glGetObjectParameterivARB*(obj: GLhandleARB, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetObjectParameterivARB".}
+proc glGetInfoLogARB*(obj: GLhandleARB, maxLength: TGLsizei, len: PGLsizei, 
+                      infoLog: PGLcharARB){.dynlib: dllname, 
+    importc: "glGetInfoLogARB".}
+proc glGetAttachedObjectsARB*(containerObj: GLhandleARB, maxCount: TGLsizei, 
+                              count: PGLsizei, obj: PGLhandleARB){.
+    dynlib: dllname, importc: "glGetAttachedObjectsARB".}
+proc glGetUniformLocationARB*(programObj: GLhandleARB, name: PGLcharARB): TGLint{.
+    dynlib: dllname, importc: "glGetUniformLocationARB".}
+proc glGetActiveUniformARB*(programObj: GLhandleARB, index: TGLuint, 
+                            maxLength: TGLsizei, len: PGLsizei, size: PGLint, 
+                            thetype: PGLenum, name: PGLcharARB){.
+    dynlib: dllname, importc: "glGetActiveUniformARB".}
+proc glGetUniformfvARB*(programObj: GLhandleARB, location: TGLint, 
+                        params: PGLfloat){.dynlib: dllname, 
+    importc: "glGetUniformfvARB".}
+proc glGetUniformivARB*(programObj: GLhandleARB, location: TGLint, 
+                        params: PGLint){.dynlib: dllname, 
+    importc: "glGetUniformivARB".}
+proc glGetShaderSourceARB*(obj: GLhandleARB, maxLength: TGLsizei, len: PGLsizei, 
+                           source: PGLcharARB){.dynlib: dllname, 
+    importc: "glGetShaderSourceARB".}
+const 
+  GL_VERTEX_SHADER_ARB* = 0x00008B31
+  GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB* = 0x00008B4A
+  GL_MAX_VARYING_FLOATS_ARB* = 0x00008B4B # GL_MAX_VERTEX_ATTRIBS_ARB  { already defined }
+                                          # GL_MAX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
+  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB* = 0x00008B4C
+  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB* = 0x00008B4D # 
+                                                        # 
+                                                        # GL_MAX_TEXTURE_COORDS_ARB  { already defined }
+                                                        # 
+                                                        # 
+                                                        # GL_VERTEX_PROGRAM_POINT_SIZE_ARB  { already defined }
+                                                        # 
+                                                        # 
+                                                        # GL_VERTEX_PROGRAM_TWO_SIDE_ARB  { already defined }
+                                                        # GL_OBJECT_TYPE_ARB  { already defined }
+                                                        # GL_OBJECT_SUBTYPE_ARB  { already defined }
+  GL_OBJECT_ACTIVE_ATTRIBUTES_ARB* = 0x00008B89
+  GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB* = 0x00008B8A # GL_SHADER_OBJECT_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_CURRENT_VERTEX_ATTRIB_ARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB  { already defined }
+                                                          # GL_FLOAT  { already defined }
+                                                          # GL_FLOAT_VEC2_ARB  { already defined }
+                                                          # GL_FLOAT_VEC3_ARB  { already defined }
+                                                          # GL_FLOAT_VEC4_ARB  { already defined }
+                                                          # GL_FLOAT_MAT2_ARB  { already defined }
+                                                          # GL_FLOAT_MAT3_ARB  { already defined }
+                                                          # GL_FLOAT_MAT4_ARB  { already defined }
+                                                          # glVertexAttrib1fARB  { already defined }
+                                                          # glVertexAttrib1sARB  { already defined }
+                                                          # glVertexAttrib1dARB  { already defined }
+                                                          # glVertexAttrib2fARB  { already defined }
+                                                          # glVertexAttrib2sARB  { already defined }
+                                                          # glVertexAttrib2dARB  { already defined }
+                                                          # glVertexAttrib3fARB  { already defined }
+                                                          # glVertexAttrib3sARB  { already defined }
+                                                          # glVertexAttrib3dARB  { already defined }
+                                                          # glVertexAttrib4fARB  { already defined }
+                                                          # glVertexAttrib4sARB  { already defined }
+                                                          # glVertexAttrib4dARB  { already defined }
+                                                          # glVertexAttrib4NubARB  { already defined }
+                                                          # glVertexAttrib1fvARB  { already defined }
+                                                          # glVertexAttrib1svARB  { already defined }
+                                                          # glVertexAttrib1dvARB  { already defined }
+                                                          # glVertexAttrib2fvARB  { already defined }
+                                                          # glVertexAttrib2svARB  { already defined }
+                                                          # glVertexAttrib2dvARB  { already defined }
+                                                          # glVertexAttrib3fvARB  { already defined }
+                                                          # glVertexAttrib3svARB  { already defined }
+                                                          # glVertexAttrib3dvARB  { already defined }
+                                                          # glVertexAttrib4fvARB  { already defined }
+                                                          # glVertexAttrib4svARB  { already defined }
+                                                          # glVertexAttrib4dvARB  { already defined }
+                                                          # glVertexAttrib4ivARB  { already defined }
+                                                          # glVertexAttrib4bvARB  { already defined }
+                                                          # glVertexAttrib4ubvARB  { already defined }
+                                                          # glVertexAttrib4usvARB  { already defined }
+                                                          # glVertexAttrib4uivARB  { already defined }
+                                                          # glVertexAttrib4NbvARB  { already defined }
+                                                          # glVertexAttrib4NsvARB  { already defined }
+                                                          # glVertexAttrib4NivARB  { already defined }
+                                                          # glVertexAttrib4NubvARB  { already defined }
+                                                          # glVertexAttrib4NusvARB  { already defined }
+                                                          # glVertexAttrib4NuivARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # glVertexAttribPointerARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # glEnableVertexAttribArrayARB  { already defined }
+                                                          # 
+                                                          # 
+                                                          # glDisableVertexAttribArrayARB  { already defined }
+
+proc glBindAttribLocationARB*(programObj: GLhandleARB, index: TGLuint, 
+                              name: PGLcharARB){.dynlib: dllname, 
+    importc: "glBindAttribLocationARB".}
+proc glGetActiveAttribARB*(programObj: GLhandleARB, index: TGLuint, 
+                           maxLength: TGLsizei, len: PGLsizei, size: PGLint, 
+                           thetype: PGLenum, name: PGLcharARB){.dynlib: dllname, 
+    importc: "glGetActiveAttribARB".}
+proc glGetAttribLocationARB*(programObj: GLhandleARB, name: PGLcharARB): TGLint{.
+    dynlib: dllname, importc: "glGetAttribLocationARB".}
+  # glGetVertexAttribdvARB  { already defined }
+  # glGetVertexAttribfvARB  { already defined }
+  # glGetVertexAttribivARB  { already defined }
+  # glGetVertexAttribPointervARB  { already defined }
+  #***** GL_ARB_fragment_shader *****//
+const 
+  GL_FRAGMENT_SHADER_ARB* = 0x00008B30
+  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB* = 0x00008B49 # GL_MAX_TEXTURE_COORDS_ARB  { already defined }
+                                                       # 
+                                                       # 
+                                                       # GL_MAX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
+                                                       # GL_OBJECT_TYPE_ARB  { already defined }
+                                                       # GL_OBJECT_SUBTYPE_ARB  { already defined }
+                                                       # GL_SHADER_OBJECT_ARB  { already defined }
+  #***** GL_ARB_shading_language_100 *****//
+  #***** GL_ARB_texture_non_power_of_two *****//
+  #***** GL_ARB_point_sprite *****//
+
+const 
+  GL_POINT_SPRITE_ARB* = 0x00008861
+  GL_COORD_REPLACE_ARB* = 0x00008862
+  #***** GL_EXT_depth_bounds_test *****//
+
+const 
+  constGL_DEPTH_BOUNDS_TEST_EXT* = 0x00008890
+  constGL_DEPTH_BOUNDS_EXT* = 0x00008891
+
+proc glDepthBoundsEXT*(zmin: TGLclampd, zmax: TGLclampd){.dynlib: dllname, 
+    importc: "glDepthBoundsEXT".}
+  #***** GL_EXT_texture_mirror_clamp *****//
+const 
+  GL_MIRROR_CLAMP_EXT* = 0x00008742
+  GL_MIRROR_CLAMP_TO_EDGE_EXT* = 0x00008743
+  GL_MIRROR_CLAMP_TO_BORDER_EXT* = 0x00008912
+  #***** GL_EXT_blend_equation_separate *****//
+
+const 
+  GL_BLEND_EQUATION_RGB_EXT* = 0x00008009
+  GL_BLEND_EQUATION_ALPHA_EXT* = 0x0000883D
+
+proc glBlendEquationSeparateEXT*(modeRGB: TGLenum, modeAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendEquationSeparateEXT".}
+  #***** GL_MESA_pack_invert *****//
+const 
+  GL_PACK_INVERT_MESA* = 0x00008758
+  #***** GL_MESA_ycbcr_texture *****//
+
+const 
+  GL_YCBCR_MESA* = 0x00008757
+  GL_UNSIGNED_SHORT_8_8_MESA* = 0x000085BA
+  GL_UNSIGNED_SHORT_8_8_REV_MESA* = 0x000085BB
+  #***** GL_ARB_fragment_program_shadow *****//
+  #***** GL_NV_fragment_program_option *****//
+  #***** GL_EXT_pixel_buffer_object *****//
+
+const 
+  GL_PIXEL_PACK_BUFFER_EXT* = 0x000088EB
+  GL_PIXEL_UNPACK_BUFFER_EXT* = 0x000088EC
+  GL_PIXEL_PACK_BUFFER_BINDING_EXT* = 0x000088ED
+  GL_PIXEL_UNPACK_BUFFER_BINDING_EXT* = 0x000088EF
+  #***** GL_NV_fragment_program2 *****//
+
+const 
+  GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV* = 0x000088F4
+  GL_MAX_PROGRAM_CALL_DEPTH_NV* = 0x000088F5
+  GL_MAX_PROGRAM_IF_DEPTH_NV* = 0x000088F6
+  GL_MAX_PROGRAM_LOOP_DEPTH_NV* = 0x000088F7
+  GL_MAX_PROGRAM_LOOP_COUNT_NV* = 0x000088F8
+  #***** GL_NV_vertex_program2_option *****//
+  # GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV  { already defined }
+  # GL_MAX_PROGRAM_CALL_DEPTH_NV  { already defined }
+  #***** GL_NV_vertex_program3 *****//
+  # GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
+  #***** GL_ARB_draw_buffers *****//
+
+const 
+  GL_MAX_DRAW_BUFFERS_ARB* = 0x00008824
+  GL_DRAW_BUFFER0_ARB* = 0x00008825
+  GL_DRAW_BUFFER1_ARB* = 0x00008826
+  GL_DRAW_BUFFER2_ARB* = 0x00008827
+  GL_DRAW_BUFFER3_ARB* = 0x00008828
+  GL_DRAW_BUFFER4_ARB* = 0x00008829
+  GL_DRAW_BUFFER5_ARB* = 0x0000882A
+  GL_DRAW_BUFFER6_ARB* = 0x0000882B
+  GL_DRAW_BUFFER7_ARB* = 0x0000882C
+  GL_DRAW_BUFFER8_ARB* = 0x0000882D
+  GL_DRAW_BUFFER9_ARB* = 0x0000882E
+  GL_DRAW_BUFFER10_ARB* = 0x0000882F
+  GL_DRAW_BUFFER11_ARB* = 0x00008830
+  GL_DRAW_BUFFER12_ARB* = 0x00008831
+  GL_DRAW_BUFFER13_ARB* = 0x00008832
+  GL_DRAW_BUFFER14_ARB* = 0x00008833
+  GL_DRAW_BUFFER15_ARB* = 0x00008834
+
+proc glDrawBuffersARB*(n: TGLsizei, bufs: PGLenum){.dynlib: dllname, 
+    importc: "glDrawBuffersARB".}
+  #***** GL_ARB_texture_rectangle *****//
+const 
+  GL_TEXTURE_RECTANGLE_ARB* = 0x000084F5
+  GL_TEXTURE_BINDING_RECTANGLE_ARB* = 0x000084F6
+  GL_PROXY_TEXTURE_RECTANGLE_ARB* = 0x000084F7
+  GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB* = 0x000084F8
+  #***** GL_ARB_color_buffer_float *****//
+
+const 
+  GL_RGBA_FLOAT_MODE_ARB* = 0x00008820
+  GL_CLAMP_VERTEX_COLOR_ARB* = 0x0000891A
+  GL_CLAMP_FRAGMENT_COLOR_ARB* = 0x0000891B
+  GL_CLAMP_READ_COLOR_ARB* = 0x0000891C
+  GL_FIXED_ONLY_ARB* = 0x0000891D
+  WGL_TYPE_RGBA_FLOAT_ARB* = 0x000021A0
+
+proc glClampColorARB*(target: TGLenum, clamp: TGLenum){.dynlib: dllname, 
+    importc: "glClampColorARB".}
+  #***** GL_ARB_half_float_pixel *****//
+const 
+  GL_HALF_FLOAT_ARB* = 0x0000140B
+  #***** GL_ARB_texture_float *****//
+
+const 
+  GL_TEXTURE_RED_TYPE_ARB* = 0x00008C10
+  GL_TEXTURE_GREEN_TYPE_ARB* = 0x00008C11
+  GL_TEXTURE_BLUE_TYPE_ARB* = 0x00008C12
+  GL_TEXTURE_ALPHA_TYPE_ARB* = 0x00008C13
+  GL_TEXTURE_LUMINANCE_TYPE_ARB* = 0x00008C14
+  GL_TEXTURE_INTENSITY_TYPE_ARB* = 0x00008C15
+  GL_TEXTURE_DEPTH_TYPE_ARB* = 0x00008C16
+  GL_UNSIGNED_NORMALIZED_ARB* = 0x00008C17
+  GL_RGBA32F_ARB* = 0x00008814
+  GL_RGB32F_ARB* = 0x00008815
+  GL_ALPHA32F_ARB* = 0x00008816
+  GL_INTENSITY32F_ARB* = 0x00008817
+  GL_LUMINANCE32F_ARB* = 0x00008818
+  GL_LUMINANCE_ALPHA32F_ARB* = 0x00008819
+  GL_RGBA16F_ARB* = 0x0000881A
+  GL_RGB16F_ARB* = 0x0000881B
+  GL_ALPHA16F_ARB* = 0x0000881C
+  GL_INTENSITY16F_ARB* = 0x0000881D
+  GL_LUMINANCE16F_ARB* = 0x0000881E
+  GL_LUMINANCE_ALPHA16F_ARB* = 0x0000881F
+  #***** GL_EXT_texture_compression_dxt1 *****//
+  # GL_COMPRESSED_RGB_S3TC_DXT1_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  { already defined }
+  #***** GL_ARB_pixel_buffer_object *****//
+
+const 
+  GL_PIXEL_PACK_BUFFER_ARB* = 0x000088EB
+  GL_PIXEL_UNPACK_BUFFER_ARB* = 0x000088EC
+  GL_PIXEL_PACK_BUFFER_BINDING_ARB* = 0x000088ED
+  GL_PIXEL_UNPACK_BUFFER_BINDING_ARB* = 0x000088EF
+  #***** GL_EXT_framebuffer_object *****//
+
+const 
+  GL_FRAMEBUFFER_EXT* = 0x00008D40
+  GL_RENDERBUFFER_EXT* = 0x00008D41
+  GL_STENCIL_INDEX_EXT* = 0x00008D45
+  GL_STENCIL_INDEX1_EXT* = 0x00008D46
+  GL_STENCIL_INDEX4_EXT* = 0x00008D47
+  GL_STENCIL_INDEX8_EXT* = 0x00008D48
+  GL_STENCIL_INDEX16_EXT* = 0x00008D49
+  GL_RENDERBUFFER_WIDTH_EXT* = 0x00008D42
+  GL_RENDERBUFFER_HEIGHT_EXT* = 0x00008D43
+  GL_RENDERBUFFER_INTERNAL_FORMAT_EXT* = 0x00008D44
+  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT* = 0x00008CD0
+  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT* = 0x00008CD1
+  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT* = 0x00008CD2
+  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT* = 0x00008CD3
+  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT* = 0x00008CD4
+  GL_COLOR_ATTACHMENT0_EXT* = 0x00008CE0
+  GL_COLOR_ATTACHMENT1_EXT* = 0x00008CE1
+  GL_COLOR_ATTACHMENT2_EXT* = 0x00008CE2
+  GL_COLOR_ATTACHMENT3_EXT* = 0x00008CE3
+  GL_COLOR_ATTACHMENT4_EXT* = 0x00008CE4
+  GL_COLOR_ATTACHMENT5_EXT* = 0x00008CE5
+  GL_COLOR_ATTACHMENT6_EXT* = 0x00008CE6
+  GL_COLOR_ATTACHMENT7_EXT* = 0x00008CE7
+  GL_COLOR_ATTACHMENT8_EXT* = 0x00008CE8
+  GL_COLOR_ATTACHMENT9_EXT* = 0x00008CE9
+  GL_COLOR_ATTACHMENT10_EXT* = 0x00008CEA
+  GL_COLOR_ATTACHMENT11_EXT* = 0x00008CEB
+  GL_COLOR_ATTACHMENT12_EXT* = 0x00008CEC
+  GL_COLOR_ATTACHMENT13_EXT* = 0x00008CED
+  GL_COLOR_ATTACHMENT14_EXT* = 0x00008CEE
+  GL_COLOR_ATTACHMENT15_EXT* = 0x00008CEF
+  GL_DEPTH_ATTACHMENT_EXT* = 0x00008D00
+  GL_STENCIL_ATTACHMENT_EXT* = 0x00008D20
+  GL_FRAMEBUFFER_COMPLETE_EXT* = 0x00008CD5
+  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT* = 0x00008CD6
+  GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT* = 0x00008CD7
+  GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT* = 0x00008CD8
+  GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT* = 0x00008CD9
+  GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT* = 0x00008CDA
+  GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT* = 0x00008CDB
+  GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT* = 0x00008CDC
+  GL_FRAMEBUFFER_UNSUPPORTED_EXT* = 0x00008CDD
+  GL_FRAMEBUFFER_STATUS_ERROR_EXT* = 0x00008CDE
+  GL_FRAMEBUFFER_BINDING_EXT* = 0x00008CA6
+  GL_RENDERBUFFER_BINDING_EXT* = 0x00008CA7
+  GL_MAX_COLOR_ATTACHMENTS_EXT* = 0x00008CDF
+  GL_MAX_RENDERBUFFER_SIZE_EXT* = 0x000084E8
+  GL_INVALID_FRAMEBUFFER_OPERATION_EXT* = 0x00000506
+
+proc glIsRenderbufferEXT*(renderbuffer: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsRenderbufferEXT".}
+proc glBindRenderbufferEXT*(target: TGLenum, renderbuffer: TGLuint){.
+    dynlib: dllname, importc: "glBindRenderbufferEXT".}
+proc glDeleteRenderbuffersEXT*(n: TGLsizei, renderbuffers: PGLuint){.
+    dynlib: dllname, importc: "glDeleteRenderbuffersEXT".}
+proc glGenRenderbuffersEXT*(n: TGLsizei, renderbuffers: PGLuint){.
+    dynlib: dllname, importc: "glGenRenderbuffersEXT".}
+proc glRenderbufferStorageEXT*(target: TGLenum, internalformat: TGLenum, 
+                               width: TGLsizei, height: TGLsizei){.
+    dynlib: dllname, importc: "glRenderbufferStorageEXT".}
+proc glGetRenderbufferParameterivEXT*(target: TGLenum, pname: TGLenum, 
+                                      params: PGLint){.dynlib: dllname, 
+    importc: "glGetRenderbufferParameterivEXT".}
+proc glIsFramebufferEXT*(framebuffer: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsFramebufferEXT".}
+proc glBindFramebufferEXT*(target: TGLenum, framebuffer: TGLuint){.
+    dynlib: dllname, importc: "glBindFramebufferEXT".}
+proc glDeleteFramebuffersEXT*(n: TGLsizei, framebuffers: PGLuint){.
+    dynlib: dllname, importc: "glDeleteFramebuffersEXT".}
+proc glGenFramebuffersEXT*(n: TGLsizei, framebuffers: PGLuint){.dynlib: dllname, 
+    importc: "glGenFramebuffersEXT".}
+proc glCheckFramebufferStatusEXT*(target: TGLenum): TGLenum{.dynlib: dllname, 
+    importc: "glCheckFramebufferStatusEXT".}
+proc glFramebufferTexture1DEXT*(target: TGLenum, attachment: TGLenum, 
+                                textarget: TGLenum, texture: TGLuint, 
+                                level: TGLint){.dynlib: dllname, 
+    importc: "glFramebufferTexture1DEXT".}
+proc glFramebufferTexture2DEXT*(target: TGLenum, attachment: TGLenum, 
+                                textarget: TGLenum, texture: TGLuint, 
+                                level: TGLint){.dynlib: dllname, 
+    importc: "glFramebufferTexture2DEXT".}
+proc glFramebufferTexture3DEXT*(target: TGLenum, attachment: TGLenum, 
+                                textarget: TGLenum, texture: TGLuint, 
+                                level: TGLint, zoffset: TGLint){.
+    dynlib: dllname, importc: "glFramebufferTexture3DEXT".}
+proc glFramebufferRenderbufferEXT*(target: TGLenum, attachment: TGLenum, 
+                                   renderbuffertarget: TGLenum, 
+                                   renderbuffer: TGLuint){.dynlib: dllname, 
+    importc: "glFramebufferRenderbufferEXT".}
+proc glGetFramebufferAttachmentParameterivEXT*(target: TGLenum, 
+    attachment: TGLenum, pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glGetFramebufferAttachmentParameterivEXT".}
+proc glGenerateMipmapEXT*(target: TGLenum){.dynlib: dllname, 
+    importc: "glGenerateMipmapEXT".}
+  #***** GL_version_1_4 *****//
+const 
+  GL_BLEND_DST_RGB* = 0x000080C8
+  GL_BLEND_SRC_RGB* = 0x000080C9
+  GL_BLEND_DST_ALPHA* = 0x000080CA
+  GL_BLEND_SRC_ALPHA* = 0x000080CB
+  GL_POINT_SIZE_MIN* = 0x00008126
+  GL_POINT_SIZE_MAX* = 0x00008127
+  GL_POINT_FADE_THRESHOLD_SIZE* = 0x00008128
+  GL_POINT_DISTANCE_ATTENUATION* = 0x00008129
+  GL_GENERATE_MIPMAP* = 0x00008191
+  GL_GENERATE_MIPMAP_HINT* = 0x00008192
+  GL_DEPTH_COMPONENT16* = 0x000081A5
+  GL_DEPTH_COMPONENT24* = 0x000081A6
+  GL_DEPTH_COMPONENT32* = 0x000081A7
+  GL_MIRRORED_REPEAT* = 0x00008370
+  GL_FOG_COORDINATE_SOURCE* = 0x00008450
+  GL_FOG_COORDINATE* = 0x00008451
+  GL_FRAGMENT_DEPTH* = 0x00008452
+  GL_CURRENT_FOG_COORDINATE* = 0x00008453
+  GL_FOG_COORDINATE_ARRAY_TYPE* = 0x00008454
+  GL_FOG_COORDINATE_ARRAY_STRIDE* = 0x00008455
+  GL_FOG_COORDINATE_ARRAY_POINTER* = 0x00008456
+  GL_FOG_COORDINATE_ARRAY* = 0x00008457
+  GL_COLOR_SUM* = 0x00008458
+  GL_CURRENT_SECONDARY_COLOR* = 0x00008459
+  GL_SECONDARY_COLOR_ARRAY_SIZE* = 0x0000845A
+  GL_SECONDARY_COLOR_ARRAY_TYPE* = 0x0000845B
+  GL_SECONDARY_COLOR_ARRAY_STRIDE* = 0x0000845C
+  GL_SECONDARY_COLOR_ARRAY_POINTER* = 0x0000845D
+  GL_SECONDARY_COLOR_ARRAY* = 0x0000845E
+  GL_MAX_TEXTURE_LOD_BIAS* = 0x000084FD
+  GL_TEXTURE_FILTER_CONTROL* = 0x00008500
+  GL_TEXTURE_LOD_BIAS* = 0x00008501
+  GL_INCR_WRAP* = 0x00008507
+  GL_DECR_WRAP* = 0x00008508
+  GL_TEXTURE_DEPTH_SIZE* = 0x0000884A
+  GL_DEPTH_TEXTURE_MODE* = 0x0000884B
+  GL_TEXTURE_COMPARE_MODE* = 0x0000884C
+  GL_TEXTURE_COMPARE_FUNC* = 0x0000884D
+  GL_COMPARE_R_TO_TEXTURE* = 0x0000884E
+
+proc glBlendFuncSeparate*(sfactorRGB: TGLenum, dfactorRGB: TGLenum, 
+                          sfactorAlpha: TGLenum, dfactorAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendFuncSeparate".}
+proc glFogCoordf*(coord: TGLfloat){.dynlib: dllname, importc: "glFogCoordf".}
+proc glFogCoordfv*(coord: PGLfloat){.dynlib: dllname, importc: "glFogCoordfv".}
+proc glFogCoordd*(coord: TGLdouble){.dynlib: dllname, importc: "glFogCoordd".}
+proc glFogCoorddv*(coord: PGLdouble){.dynlib: dllname, importc: "glFogCoorddv".}
+proc glFogCoordPointer*(thetype: TGLenum, stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glFogCoordPointer".}
+proc glMultiDrawArrays*(mode: TGLenum, first: PGLint, count: PGLsizei, 
+                        primcount: TGLsizei){.dynlib: dllname, 
+    importc: "glMultiDrawArrays".}
+proc glMultiDrawElements*(mode: TGLenum, count: PGLsizei, thetype: TGLenum, 
+                          indices: PGLvoid, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawElements".}
+proc glPointParameterf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname, 
+    importc: "glPointParameterf".}
+proc glPointParameterfv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname, 
+    importc: "glPointParameterfv".}
+proc glPointParameteri*(pname: TGLenum, param: TGLint){.dynlib: dllname, 
+    importc: "glPointParameteri".}
+proc glPointParameteriv*(pname: TGLenum, params: PGLint){.dynlib: dllname, 
+    importc: "glPointParameteriv".}
+proc glSecondaryColor3b*(red: TGLByte, green: TGLByte, blue: TGLByte){.
+    dynlib: dllname, importc: "glSecondaryColor3b".}
+proc glSecondaryColor3bv*(v: PGLbyte){.dynlib: dllname, 
+                                       importc: "glSecondaryColor3bv".}
+proc glSecondaryColor3d*(red: TGLdouble, green: TGLdouble, blue: TGLdouble){.
+    dynlib: dllname, importc: "glSecondaryColor3d".}
+proc glSecondaryColor3dv*(v: PGLdouble){.dynlib: dllname, 
+    importc: "glSecondaryColor3dv".}
+proc glSecondaryColor3f*(red: TGLfloat, green: TGLfloat, blue: TGLfloat){.
+    dynlib: dllname, importc: "glSecondaryColor3f".}
+proc glSecondaryColor3fv*(v: PGLfloat){.dynlib: dllname, 
+                                        importc: "glSecondaryColor3fv".}
+proc glSecondaryColor3i*(red: TGLint, green: TGLint, blue: TGLint){.
+    dynlib: dllname, importc: "glSecondaryColor3i".}
+proc glSecondaryColor3iv*(v: PGLint){.dynlib: dllname, 
+                                      importc: "glSecondaryColor3iv".}
+proc glSecondaryColor3s*(red: TGLshort, green: TGLshort, blue: TGLshort){.
+    dynlib: dllname, importc: "glSecondaryColor3s".}
+proc glSecondaryColor3sv*(v: PGLshort){.dynlib: dllname, 
+                                        importc: "glSecondaryColor3sv".}
+proc glSecondaryColor3ub*(red: TGLubyte, green: TGLubyte, blue: TGLubyte){.
+    dynlib: dllname, importc: "glSecondaryColor3ub".}
+proc glSecondaryColor3ubv*(v: PGLubyte){.dynlib: dllname, 
+    importc: "glSecondaryColor3ubv".}
+proc glSecondaryColor3ui*(red: TGLuint, green: TGLuint, blue: TGLuint){.
+    dynlib: dllname, importc: "glSecondaryColor3ui".}
+proc glSecondaryColor3uiv*(v: PGLuint){.dynlib: dllname, 
+                                        importc: "glSecondaryColor3uiv".}
+proc glSecondaryColor3us*(red: TGLushort, green: TGLushort, blue: TGLushort){.
+    dynlib: dllname, importc: "glSecondaryColor3us".}
+proc glSecondaryColor3usv*(v: PGLushort){.dynlib: dllname, 
+    importc: "glSecondaryColor3usv".}
+proc glSecondaryColorPointer*(size: TGLint, thetype: TGLenum, stride: TGLsizei, 
+                              pointer: PGLvoid){.dynlib: dllname, 
+    importc: "glSecondaryColorPointer".}
+proc glWindowPos2d*(x: TGLdouble, y: TGLdouble){.dynlib: dllname, 
+    importc: "glWindowPos2d".}
+proc glWindowPos2dv*(v: PGLdouble){.dynlib: dllname, importc: "glWindowPos2dv".}
+proc glWindowPos2f*(x: TGLfloat, y: TGLfloat){.dynlib: dllname, 
+    importc: "glWindowPos2f".}
+proc glWindowPos2fv*(v: PGLfloat){.dynlib: dllname, importc: "glWindowPos2fv".}
+proc glWindowPos2i*(x: TGLint, y: TGLint){.dynlib: dllname, 
+    importc: "glWindowPos2i".}
+proc glWindowPos2iv*(v: PGLint){.dynlib: dllname, importc: "glWindowPos2iv".}
+proc glWindowPos2s*(x: TGLshort, y: TGLshort){.dynlib: dllname, 
+    importc: "glWindowPos2s".}
+proc glWindowPos2sv*(v: PGLshort){.dynlib: dllname, importc: "glWindowPos2sv".}
+proc glWindowPos3d*(x: TGLdouble, y: TGLdouble, z: TGLdouble){.dynlib: dllname, 
+    importc: "glWindowPos3d".}
+proc glWindowPos3dv*(v: PGLdouble){.dynlib: dllname, importc: "glWindowPos3dv".}
+proc glWindowPos3f*(x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname, 
+    importc: "glWindowPos3f".}
+proc glWindowPos3fv*(v: PGLfloat){.dynlib: dllname, importc: "glWindowPos3fv".}
+proc glWindowPos3i*(x: TGLint, y: TGLint, z: TGLint){.dynlib: dllname, 
+    importc: "glWindowPos3i".}
+proc glWindowPos3iv*(v: PGLint){.dynlib: dllname, importc: "glWindowPos3iv".}
+proc glWindowPos3s*(x: TGLshort, y: TGLshort, z: TGLshort){.dynlib: dllname, 
+    importc: "glWindowPos3s".}
+proc glWindowPos3sv*(v: PGLshort){.dynlib: dllname, importc: "glWindowPos3sv".}
+  #***** GL_version_1_5 *****//
+const 
+  GL_BUFFER_SIZE* = 0x00008764
+  GL_BUFFER_USAGE* = 0x00008765
+  GL_QUERY_COUNTER_BITS* = 0x00008864
+  GL_CURRENT_QUERY* = 0x00008865
+  GL_QUERY_RESULT* = 0x00008866
+  GL_QUERY_RESULT_AVAILABLE* = 0x00008867
+  GL_ARRAY_BUFFER* = 0x00008892
+  GL_ELEMENT_ARRAY_BUFFER* = 0x00008893
+  GL_ARRAY_BUFFER_BINDING* = 0x00008894
+  GL_ELEMENT_ARRAY_BUFFER_BINDING* = 0x00008895
+  GL_VERTEX_ARRAY_BUFFER_BINDING* = 0x00008896
+  GL_NORMAL_ARRAY_BUFFER_BINDING* = 0x00008897
+  GL_COLOR_ARRAY_BUFFER_BINDING* = 0x00008898
+  GL_INDEX_ARRAY_BUFFER_BINDING* = 0x00008899
+  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING* = 0x0000889A
+  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING* = 0x0000889B
+  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING* = 0x0000889C
+  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING* = 0x0000889D
+  GL_WEIGHT_ARRAY_BUFFER_BINDING* = 0x0000889E
+  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING* = 0x0000889F
+  GL_READ_ONLY* = 0x000088B8
+  GL_WRITE_ONLY* = 0x000088B9
+  GL_READ_WRITE* = 0x000088BA
+  GL_BUFFER_ACCESS* = 0x000088BB
+  GL_BUFFER_MAPPED* = 0x000088BC
+  GL_BUFFER_MAP_POINTER* = 0x000088BD
+  GL_STREAM_DRAW* = 0x000088E0
+  GL_STREAM_READ* = 0x000088E1
+  GL_STREAM_COPY* = 0x000088E2
+  GL_STATIC_DRAW* = 0x000088E4
+  GL_STATIC_READ* = 0x000088E5
+  GL_STATIC_COPY* = 0x000088E6
+  GL_DYNAMIC_DRAW* = 0x000088E8
+  GL_DYNAMIC_READ* = 0x000088E9
+  GL_DYNAMIC_COPY* = 0x000088EA
+  GL_SAMPLES_PASSED* = 0x00008914
+  GL_FOG_COORD_SRC* = 0x00008450
+  GL_FOG_COORD* = 0x00008451
+  GL_CURRENT_FOG_COORD* = 0x00008453
+  GL_FOG_COORD_ARRAY_TYPE* = 0x00008454
+  GL_FOG_COORD_ARRAY_STRIDE* = 0x00008455
+  GL_FOG_COORD_ARRAY_POINTER* = 0x00008456
+  GL_FOG_COORD_ARRAY* = 0x00008457
+  GL_FOG_COORD_ARRAY_BUFFER_BINDING* = 0x0000889D
+  GL_SRC0_RGB* = 0x00008580
+  GL_SRC1_RGB* = 0x00008581
+  GL_SRC2_RGB* = 0x00008582
+  GL_SRC0_ALPHA* = 0x00008588
+  GL_SRC1_ALPHA* = 0x00008589
+  GL_SRC2_ALPHA* = 0x0000858A
+
+proc glGenQueries*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glGenQueries".}
+proc glDeleteQueries*(n: TGLsizei, ids: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteQueries".}
+proc glIsQuery*(id: TGLuint): TGLboolean{.dynlib: dllname, importc: "glIsQuery".}
+proc glBeginQuery*(target: TGLenum, id: TGLuint){.dynlib: dllname, 
+    importc: "glBeginQuery".}
+proc glEndQuery*(target: TGLenum){.dynlib: dllname, importc: "glEndQuery".}
+proc glGetQueryiv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryiv".}
+proc glGetQueryObjectiv*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryObjectiv".}
+proc glGetQueryObjectuiv*(id: TGLuint, pname: TGLenum, params: PGLuint){.
+    dynlib: dllname, importc: "glGetQueryObjectuiv".}
+proc glBindBuffer*(target: TGLenum, buffer: TGLuint){.dynlib: dllname, 
+    importc: "glBindBuffer".}
+proc glDeleteBuffers*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname, 
+    importc: "glDeleteBuffers".}
+proc glGenBuffers*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname, 
+    importc: "glGenBuffers".}
+proc glIsBuffer*(buffer: TGLuint): TGLboolean{.dynlib: dllname, 
+    importc: "glIsBuffer".}
+proc glBufferData*(target: TGLenum, size: GLsizeiptr, data: PGLvoid, 
+                   usage: TGLenum){.dynlib: dllname, importc: "glBufferData".}
+proc glBufferSubData*(target: TGLenum, offset: GLintptr, size: GLsizeiptr, 
+                      data: PGLvoid){.dynlib: dllname, 
+                                      importc: "glBufferSubData".}
+proc glGetBufferSubData*(target: TGLenum, offset: GLintptr, size: GLsizeiptr, 
+                         data: PGLvoid){.dynlib: dllname, 
+    importc: "glGetBufferSubData".}
+proc glMapBuffer*(target: TGLenum, access: TGLenum): PGLvoid{.dynlib: dllname, 
+    importc: "glMapBuffer".}
+proc glUnmapBuffer*(target: TGLenum): TGLboolean{.dynlib: dllname, 
+    importc: "glUnmapBuffer".}
+proc glGetBufferParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetBufferParameteriv".}
+proc glGetBufferPointerv*(target: TGLenum, pname: TGLenum, params: PGLvoid){.
+    dynlib: dllname, importc: "glGetBufferPointerv".}
+  #***** GL_version_2_0 *****//
+const 
+  GL_BLEND_EQUATION_RGB* = 0x00008009
+  GL_VERTEX_ATTRIB_ARRAY_ENABLED* = 0x00008622
+  GL_VERTEX_ATTRIB_ARRAY_SIZE* = 0x00008623
+  GL_VERTEX_ATTRIB_ARRAY_STRIDE* = 0x00008624
+  GL_VERTEX_ATTRIB_ARRAY_TYPE* = 0x00008625
+  GL_CURRENT_VERTEX_ATTRIB* = 0x00008626
+  GL_VERTEX_PROGRAM_POINT_SIZE* = 0x00008642
+  GL_VERTEX_PROGRAM_TWO_SIDE* = 0x00008643
+  GL_VERTEX_ATTRIB_ARRAY_POINTER* = 0x00008645
+  GL_STENCIL_BACK_FUNC* = 0x00008800
+  GL_STENCIL_BACK_FAIL* = 0x00008801
+  GL_STENCIL_BACK_PASS_DEPTH_FAIL* = 0x00008802
+  GL_STENCIL_BACK_PASS_DEPTH_PASS* = 0x00008803
+  GL_MAX_DRAW_BUFFERS* = 0x00008824
+  GL_DRAW_BUFFER0* = 0x00008825
+  GL_DRAW_BUFFER1* = 0x00008826
+  GL_DRAW_BUFFER2* = 0x00008827
+  GL_DRAW_BUFFER3* = 0x00008828
+  GL_DRAW_BUFFER4* = 0x00008829
+  GL_DRAW_BUFFER5* = 0x0000882A
+  GL_DRAW_BUFFER6* = 0x0000882B
+  GL_DRAW_BUFFER7* = 0x0000882C
+  GL_DRAW_BUFFER8* = 0x0000882D
+  GL_DRAW_BUFFER9* = 0x0000882E
+  GL_DRAW_BUFFER10* = 0x0000882F
+  GL_DRAW_BUFFER11* = 0x00008830
+  GL_DRAW_BUFFER12* = 0x00008831
+  GL_DRAW_BUFFER13* = 0x00008832
+  GL_DRAW_BUFFER14* = 0x00008833
+  GL_DRAW_BUFFER15* = 0x00008834
+  GL_BLEND_EQUATION_ALPHA* = 0x0000883D
+  GL_POINT_SPRITE* = 0x00008861
+  GL_COORD_REPLACE* = 0x00008862
+  GL_MAX_VERTEX_ATTRIBS* = 0x00008869
+  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED* = 0x0000886A
+  GL_MAX_TEXTURE_COORDS* = 0x00008871
+  GL_MAX_TEXTURE_IMAGE_UNITS* = 0x00008872
+  GL_FRAGMENT_SHADER* = 0x00008B30
+  GL_VERTEX_SHADER* = 0x00008B31
+  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS* = 0x00008B49
+  GL_MAX_VERTEX_UNIFORM_COMPONENTS* = 0x00008B4A
+  GL_MAX_VARYING_FLOATS* = 0x00008B4B
+  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS* = 0x00008B4C
+  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS* = 0x00008B4D
+  GL_SHADER_TYPE* = 0x00008B4F
+  GL_FLOAT_VEC2* = 0x00008B50
+  GL_FLOAT_VEC3* = 0x00008B51
+  GL_FLOAT_VEC4* = 0x00008B52
+  GL_INT_VEC2* = 0x00008B53
+  GL_INT_VEC3* = 0x00008B54
+  GL_INT_VEC4* = 0x00008B55
+  GL_BOOL* = 0x00008B56
+  GL_BOOL_VEC2* = 0x00008B57
+  GL_BOOL_VEC3* = 0x00008B58
+  GL_BOOL_VEC4* = 0x00008B59
+  GL_FLOAT_MAT2* = 0x00008B5A
+  GL_FLOAT_MAT3* = 0x00008B5B
+  GL_FLOAT_MAT4* = 0x00008B5C
+  GL_SAMPLER_1D* = 0x00008B5D
+  GL_SAMPLER_2D* = 0x00008B5E
+  GL_SAMPLER_3D* = 0x00008B5F
+  GL_SAMPLER_CUBE* = 0x00008B60
+  GL_SAMPLER_1D_SHADOW* = 0x00008B61
+  GL_SAMPLER_2D_SHADOW* = 0x00008B62
+  GL_DELETE_STATUS* = 0x00008B80
+  GL_COMPILE_STATUS* = 0x00008B81
+  GL_LINK_STATUS* = 0x00008B82
+  GL_VALIDATE_STATUS* = 0x00008B83
+  GL_INFO_LOG_LENGTH* = 0x00008B84
+  GL_ATTACHED_SHADERS* = 0x00008B85
+  GL_ACTIVE_UNIFORMS* = 0x00008B86
+  GL_ACTIVE_UNIFORM_MAX_LENGTH* = 0x00008B87
+  GL_SHADER_SOURCE_LENGTH* = 0x00008B88
+  GL_ACTIVE_ATTRIBUTES* = 0x00008B89
+  GL_ACTIVE_ATTRIBUTE_MAX_LENGTH* = 0x00008B8A
+  GL_FRAGMENT_SHADER_DERIVATIVE_HINT* = 0x00008B8B
+  GL_SHADING_LANGUAGE_VERSION* = 0x00008B8C
+  GL_CURRENT_PROGRAM* = 0x00008B8D
+  GL_POINT_SPRITE_COORD_ORIGIN* = 0x00008CA0
+  GL_LOWER_LEFT* = 0x00008CA1
+  GL_UPPER_LEFT* = 0x00008CA2
+  GL_STENCIL_BACK_REF* = 0x00008CA3
+  GL_STENCIL_BACK_VALUE_MASK* = 0x00008CA4
+  GL_STENCIL_BACK_WRITEMASK* = 0x00008CA5
+
+{.pop.}
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/lib/glu.nim b/tests/manyloc/keineschweine/lib/glu.nim
new file mode 100644
index 000000000..e00120d83
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glu.nim
@@ -0,0 +1,335 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#******************************************************************************
+# Converted to Delphi by Tom Nuydens (tom@delphi3d.net)                        
+# For the latest updates, visit Delphi3D: http://www.delphi3d.net              
+#******************************************************************************
+
+import 
+  GL
+
+when defined(windows): 
+  {.push, callconv: stdcall.}
+else: 
+  {.push, callconv: cdecl.}
+
+when defined(windows): 
+  const 
+    dllname = "glu32.dll"
+elif defined(macosx): 
+  const 
+    dllname = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib"
+else: 
+  const 
+    dllname = "libGLU.so.1"
+type 
+  TViewPortArray* = array[0..3, TGLint]
+  T16dArray* = array[0..15, TGLdouble]
+  TCallBack* = proc ()
+  T3dArray* = array[0..2, TGLdouble]
+  T4pArray* = array[0..3, Pointer]
+  T4fArray* = array[0..3, TGLfloat]
+  PPointer* = ptr Pointer
+
+type 
+  GLUnurbs*{.final.} = object 
+  PGLUnurbs* = ptr GLUnurbs
+  GLUquadric*{.final.} = object 
+  PGLUquadric* = ptr GLUquadric
+  GLUtesselator*{.final.} = object 
+  PGLUtesselator* = ptr GLUtesselator # backwards compatibility:
+  GLUnurbsObj* = GLUnurbs
+  PGLUnurbsObj* = PGLUnurbs
+  GLUquadricObj* = GLUquadric
+  PGLUquadricObj* = PGLUquadric
+  GLUtesselatorObj* = GLUtesselator
+  PGLUtesselatorObj* = PGLUtesselator
+  GLUtriangulatorObj* = GLUtesselator
+  PGLUtriangulatorObj* = PGLUtesselator
+  TGLUnurbs* = GLUnurbs
+  TGLUquadric* = GLUquadric
+  TGLUtesselator* = GLUtesselator
+  TGLUnurbsObj* = GLUnurbsObj
+  TGLUquadricObj* = GLUquadricObj
+  TGLUtesselatorObj* = GLUtesselatorObj
+  TGLUtriangulatorObj* = GLUtriangulatorObj
+
+proc gluErrorString*(errCode: TGLenum): cstring{.dynlib: dllname, 
+    importc: "gluErrorString".}
+proc gluErrorUnicodeStringEXT*(errCode: TGLenum): ptr int16{.dynlib: dllname, 
+    importc: "gluErrorUnicodeStringEXT".}
+proc gluGetString*(name: TGLenum): cstring{.dynlib: dllname, 
+    importc: "gluGetString".}
+proc gluOrtho2D*(left, right, bottom, top: TGLdouble){.dynlib: dllname, 
+    importc: "gluOrtho2D".}
+proc gluPerspective*(fovy, aspect, zNear, zFar: TGLdouble){.dynlib: dllname, 
+    importc: "gluPerspective".}
+proc gluPickMatrix*(x, y, width, height: TGLdouble, viewport: var TViewPortArray){.
+    dynlib: dllname, importc: "gluPickMatrix".}
+proc gluLookAt*(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz: TGLdouble){.
+    dynlib: dllname, importc: "gluLookAt".}
+proc gluProject*(objx, objy, objz: TGLdouble, 
+                 modelMatrix, projMatrix: var T16dArray, 
+                 viewport: var TViewPortArray, winx, winy, winz: PGLdouble): int{.
+    dynlib: dllname, importc: "gluProject".}
+proc gluUnProject*(winx, winy, winz: TGLdouble, 
+                   modelMatrix, projMatrix: var T16dArray, 
+                   viewport: var TViewPortArray, objx, objy, objz: PGLdouble): int{.
+    dynlib: dllname, importc: "gluUnProject".}
+proc gluScaleImage*(format: TGLenum, widthin, heightin: TGLint, typein: TGLenum, 
+                    datain: Pointer, widthout, heightout: TGLint, 
+                    typeout: TGLenum, dataout: Pointer): int{.dynlib: dllname, 
+    importc: "gluScaleImage".}
+proc gluBuild1DMipmaps*(target: TGLenum, components, width: TGLint, 
+                        format, atype: TGLenum, data: Pointer): int{.
+    dynlib: dllname, importc: "gluBuild1DMipmaps".}
+proc gluBuild2DMipmaps*(target: TGLenum, components, width, height: TGLint, 
+                        format, atype: TGLenum, data: Pointer): int{.
+    dynlib: dllname, importc: "gluBuild2DMipmaps".}
+proc gluNewQuadric*(): PGLUquadric{.dynlib: dllname, importc: "gluNewQuadric".}
+proc gluDeleteQuadric*(state: PGLUquadric){.dynlib: dllname, 
+    importc: "gluDeleteQuadric".}
+proc gluQuadricNormals*(quadObject: PGLUquadric, normals: TGLenum){.
+    dynlib: dllname, importc: "gluQuadricNormals".}
+proc gluQuadricTexture*(quadObject: PGLUquadric, textureCoords: TGLboolean){.
+    dynlib: dllname, importc: "gluQuadricTexture".}
+proc gluQuadricOrientation*(quadObject: PGLUquadric, orientation: TGLenum){.
+    dynlib: dllname, importc: "gluQuadricOrientation".}
+proc gluQuadricDrawStyle*(quadObject: PGLUquadric, drawStyle: TGLenum){.
+    dynlib: dllname, importc: "gluQuadricDrawStyle".}
+proc gluCylinder*(qobj: PGLUquadric, baseRadius, topRadius, height: TGLdouble, 
+                  slices, stacks: TGLint){.dynlib: dllname, 
+    importc: "gluCylinder".}
+proc gluDisk*(qobj: PGLUquadric, innerRadius, outerRadius: TGLdouble, 
+              slices, loops: TGLint){.dynlib: dllname, importc: "gluDisk".}
+proc gluPartialDisk*(qobj: PGLUquadric, innerRadius, outerRadius: TGLdouble, 
+                     slices, loops: TGLint, startAngle, sweepAngle: TGLdouble){.
+    dynlib: dllname, importc: "gluPartialDisk".}
+proc gluSphere*(qobj: PGLuquadric, radius: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "gluSphere".}
+proc gluQuadricCallback*(qobj: PGLUquadric, which: TGLenum, fn: TCallBack){.
+    dynlib: dllname, importc: "gluQuadricCallback".}
+proc gluNewTess*(): PGLUtesselator{.dynlib: dllname, importc: "gluNewTess".}
+proc gluDeleteTess*(tess: PGLUtesselator){.dynlib: dllname, 
+    importc: "gluDeleteTess".}
+proc gluTessBeginPolygon*(tess: PGLUtesselator, polygon_data: Pointer){.
+    dynlib: dllname, importc: "gluTessBeginPolygon".}
+proc gluTessBeginContour*(tess: PGLUtesselator){.dynlib: dllname, 
+    importc: "gluTessBeginContour".}
+proc gluTessVertex*(tess: PGLUtesselator, coords: var T3dArray, data: Pointer){.
+    dynlib: dllname, importc: "gluTessVertex".}
+proc gluTessEndContour*(tess: PGLUtesselator){.dynlib: dllname, 
+    importc: "gluTessEndContour".}
+proc gluTessEndPolygon*(tess: PGLUtesselator){.dynlib: dllname, 
+    importc: "gluTessEndPolygon".}
+proc gluTessProperty*(tess: PGLUtesselator, which: TGLenum, value: TGLdouble){.
+    dynlib: dllname, importc: "gluTessProperty".}
+proc gluTessNormal*(tess: PGLUtesselator, x, y, z: TGLdouble){.dynlib: dllname, 
+    importc: "gluTessNormal".}
+proc gluTessCallback*(tess: PGLUtesselator, which: TGLenum, fn: TCallBack){.
+    dynlib: dllname, importc: "gluTessCallback".}
+proc gluGetTessProperty*(tess: PGLUtesselator, which: TGLenum, value: PGLdouble){.
+    dynlib: dllname, importc: "gluGetTessProperty".}
+proc gluNewNurbsRenderer*(): PGLUnurbs{.dynlib: dllname, 
+                                        importc: "gluNewNurbsRenderer".}
+proc gluDeleteNurbsRenderer*(nobj: PGLUnurbs){.dynlib: dllname, 
+    importc: "gluDeleteNurbsRenderer".}
+proc gluBeginSurface*(nobj: PGLUnurbs){.dynlib: dllname, 
+                                        importc: "gluBeginSurface".}
+proc gluBeginCurve*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluBeginCurve".}
+proc gluEndCurve*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluEndCurve".}
+proc gluEndSurface*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluEndSurface".}
+proc gluBeginTrim*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluBeginTrim".}
+proc gluEndTrim*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluEndTrim".}
+proc gluPwlCurve*(nobj: PGLUnurbs, count: TGLint, aarray: PGLfloat, 
+                  stride: TGLint, atype: TGLenum){.dynlib: dllname, 
+    importc: "gluPwlCurve".}
+proc gluNurbsCurve*(nobj: PGLUnurbs, nknots: TGLint, knot: PGLfloat, 
+                    stride: TGLint, ctlarray: PGLfloat, order: TGLint, 
+                    atype: TGLenum){.dynlib: dllname, importc: "gluNurbsCurve".}
+proc gluNurbsSurface*(nobj: PGLUnurbs, sknot_count: TGLint, sknot: PGLfloat, 
+                      tknot_count: TGLint, tknot: PGLfloat, 
+                      s_stride, t_stride: TGLint, ctlarray: PGLfloat, 
+                      sorder, torder: TGLint, atype: TGLenum){.dynlib: dllname, 
+    importc: "gluNurbsSurface".}
+proc gluLoadSamplingMatrices*(nobj: PGLUnurbs, 
+                              modelMatrix, projMatrix: var T16dArray, 
+                              viewport: var TViewPortArray){.dynlib: dllname, 
+    importc: "gluLoadSamplingMatrices".}
+proc gluNurbsProperty*(nobj: PGLUnurbs, aproperty: TGLenum, value: TGLfloat){.
+    dynlib: dllname, importc: "gluNurbsProperty".}
+proc gluGetNurbsProperty*(nobj: PGLUnurbs, aproperty: TGLenum, value: PGLfloat){.
+    dynlib: dllname, importc: "gluGetNurbsProperty".}
+proc gluNurbsCallback*(nobj: PGLUnurbs, which: TGLenum, fn: TCallBack){.
+    dynlib: dllname, importc: "gluNurbsCallback".}
+  #*** Callback function prototypes ***
+type                          # gluQuadricCallback
+  GLUquadricErrorProc* = proc (p: TGLenum) # gluTessCallback
+  GLUtessBeginProc* = proc (p: TGLenum)
+  GLUtessEdgeFlagProc* = proc (p: TGLboolean)
+  GLUtessVertexProc* = proc (p: Pointer)
+  GLUtessEndProc* = proc ()
+  GLUtessErrorProc* = proc (p: TGLenum)
+  GLUtessCombineProc* = proc (p1: var T3dArray, p2: T4pArray, p3: T4fArray, 
+                              p4: PPointer)
+  GLUtessBeginDataProc* = proc (p1: TGLenum, p2: Pointer)
+  GLUtessEdgeFlagDataProc* = proc (p1: TGLboolean, p2: Pointer)
+  GLUtessVertexDataProc* = proc (p1, p2: Pointer)
+  GLUtessEndDataProc* = proc (p: Pointer)
+  GLUtessErrorDataProc* = proc (p1: TGLenum, p2: Pointer)
+  GLUtessCombineDataProc* = proc (p1: var T3dArray, p2: var T4pArray, 
+                                  p3: var T4fArray, p4: PPointer, p5: Pointer) # 
+                                                                               # 
+                                                                               # gluNurbsCallback
+  GLUnurbsErrorProc* = proc (p: TGLenum) #***           Generic constants               ****/
+
+const                         # Version
+  GLU_VERSION_1_1* = 1
+  GLU_VERSION_1_2* = 1        # Errors: (return value 0 = no error)
+  GLU_INVALID_ENUM* = 100900
+  GLU_INVALID_VALUE* = 100901
+  GLU_OUT_OF_MEMORY* = 100902
+  GLU_INCOMPATIBLE_GL_VERSION* = 100903 # StringName
+  GLU_VERSION* = 100800
+  GLU_EXTENSIONS* = 100801    # Boolean
+  GLU_TRUE* = GL_TRUE
+  GLU_FALSE* = GL_FALSE #***           Quadric constants               ****/
+                        # QuadricNormal
+  GLU_SMOOTH* = 100000
+  GLU_FLAT* = 100001
+  GLU_NONE* = 100002          # QuadricDrawStyle
+  GLU_POINT* = 100010
+  GLU_LINE* = 100011
+  GLU_FILL* = 100012
+  GLU_SILHOUETTE* = 100013    # QuadricOrientation
+  GLU_OUTSIDE* = 100020
+  GLU_INSIDE* = 100021        # Callback types:
+                              #      GLU_ERROR       = 100103;
+                              #***           Tesselation constants           ****/
+  GLU_TESS_MAX_COORD* = 1.00000e+150 # TessProperty
+  GLU_TESS_WINDING_RULE* = 100140
+  GLU_TESS_BOUNDARY_ONLY* = 100141
+  GLU_TESS_TOLERANCE* = 100142 # TessWinding
+  GLU_TESS_WINDING_ODD* = 100130
+  GLU_TESS_WINDING_NONZERO* = 100131
+  GLU_TESS_WINDING_POSITIVE* = 100132
+  GLU_TESS_WINDING_NEGATIVE* = 100133
+  GLU_TESS_WINDING_ABS_GEQ_TWO* = 100134 # TessCallback
+  GLU_TESS_BEGIN* = 100100    # void (CALLBACK*)(TGLenum    type)
+  constGLU_TESS_VERTEX* = 100101 # void (CALLBACK*)(void      *data)
+  GLU_TESS_END* = 100102      # void (CALLBACK*)(void)
+  GLU_TESS_ERROR* = 100103    # void (CALLBACK*)(TGLenum    errno)
+  GLU_TESS_EDGE_FLAG* = 100104 # void (CALLBACK*)(TGLboolean boundaryEdge)
+  GLU_TESS_COMBINE* = 100105 # void (CALLBACK*)(TGLdouble  coords[3],
+                             #                                                            void      *data[4],
+                             #                                                            TGLfloat   weight[4],
+                             #                                                            void      **dataOut) 
+  GLU_TESS_BEGIN_DATA* = 100106 # void (CALLBACK*)(TGLenum    type,
+                                #                                                            void      *polygon_data) 
+  GLU_TESS_VERTEX_DATA* = 100107 # void (CALLBACK*)(void      *data,
+                                 #                                                            void      *polygon_data) 
+  GLU_TESS_END_DATA* = 100108 # void (CALLBACK*)(void      *polygon_data)
+  GLU_TESS_ERROR_DATA* = 100109 # void (CALLBACK*)(TGLenum    errno,
+                                #                                                            void      *polygon_data) 
+  GLU_TESS_EDGE_FLAG_DATA* = 100110 # void (CALLBACK*)(TGLboolean boundaryEdge,
+                                    #                                                            void      *polygon_data) 
+  GLU_TESS_COMBINE_DATA* = 100111 # void (CALLBACK*)(TGLdouble  coords[3],
+                                  #                                                            void      *data[4],
+                                  #                                                            TGLfloat   weight[4],
+                                  #                                                            void      **dataOut,
+                                  #                                                            void      *polygon_data) 
+                                  # TessError
+  GLU_TESS_ERROR1* = 100151
+  GLU_TESS_ERROR2* = 100152
+  GLU_TESS_ERROR3* = 100153
+  GLU_TESS_ERROR4* = 100154
+  GLU_TESS_ERROR5* = 100155
+  GLU_TESS_ERROR6* = 100156
+  GLU_TESS_ERROR7* = 100157
+  GLU_TESS_ERROR8* = 100158
+  GLU_TESS_MISSING_BEGIN_POLYGON* = GLU_TESS_ERROR1
+  GLU_TESS_MISSING_BEGIN_CONTOUR* = GLU_TESS_ERROR2
+  GLU_TESS_MISSING_END_POLYGON* = GLU_TESS_ERROR3
+  GLU_TESS_MISSING_END_CONTOUR* = GLU_TESS_ERROR4
+  GLU_TESS_COORD_TOO_LARGE* = GLU_TESS_ERROR5
+  GLU_TESS_NEED_COMBINE_CALLBACK* = GLU_TESS_ERROR6 #***           NURBS constants                 ****/
+                                                    # NurbsProperty
+  GLU_AUTO_LOAD_MATRIX* = 100200
+  GLU_CULLING* = 100201
+  GLU_SAMPLING_TOLERANCE* = 100203
+  GLU_DISPLAY_MODE* = 100204
+  GLU_PARAMETRIC_TOLERANCE* = 100202
+  GLU_SAMPLING_METHOD* = 100205
+  GLU_U_STEP* = 100206
+  GLU_V_STEP* = 100207        # NurbsSampling
+  GLU_PATH_LENGTH* = 100215
+  GLU_PARAMETRIC_ERROR* = 100216
+  GLU_DOMAIN_DISTANCE* = 100217 # NurbsTrim
+  GLU_MAP1_TRIM_2* = 100210
+  GLU_MAP1_TRIM_3* = 100211   # NurbsDisplay
+                              #      GLU_FILL                = 100012;
+  GLU_OUTLINE_POLYGON* = 100240
+  GLU_OUTLINE_PATCH* = 100241 # NurbsCallback
+                              #      GLU_ERROR               = 100103;
+                              # NurbsErrors
+  GLU_NURBS_ERROR1* = 100251
+  GLU_NURBS_ERROR2* = 100252
+  GLU_NURBS_ERROR3* = 100253
+  GLU_NURBS_ERROR4* = 100254
+  GLU_NURBS_ERROR5* = 100255
+  GLU_NURBS_ERROR6* = 100256
+  GLU_NURBS_ERROR7* = 100257
+  GLU_NURBS_ERROR8* = 100258
+  GLU_NURBS_ERROR9* = 100259
+  GLU_NURBS_ERROR10* = 100260
+  GLU_NURBS_ERROR11* = 100261
+  GLU_NURBS_ERROR12* = 100262
+  GLU_NURBS_ERROR13* = 100263
+  GLU_NURBS_ERROR14* = 100264
+  GLU_NURBS_ERROR15* = 100265
+  GLU_NURBS_ERROR16* = 100266
+  GLU_NURBS_ERROR17* = 100267
+  GLU_NURBS_ERROR18* = 100268
+  GLU_NURBS_ERROR19* = 100269
+  GLU_NURBS_ERROR20* = 100270
+  GLU_NURBS_ERROR21* = 100271
+  GLU_NURBS_ERROR22* = 100272
+  GLU_NURBS_ERROR23* = 100273
+  GLU_NURBS_ERROR24* = 100274
+  GLU_NURBS_ERROR25* = 100275
+  GLU_NURBS_ERROR26* = 100276
+  GLU_NURBS_ERROR27* = 100277
+  GLU_NURBS_ERROR28* = 100278
+  GLU_NURBS_ERROR29* = 100279
+  GLU_NURBS_ERROR30* = 100280
+  GLU_NURBS_ERROR31* = 100281
+  GLU_NURBS_ERROR32* = 100282
+  GLU_NURBS_ERROR33* = 100283
+  GLU_NURBS_ERROR34* = 100284
+  GLU_NURBS_ERROR35* = 100285
+  GLU_NURBS_ERROR36* = 100286
+  GLU_NURBS_ERROR37* = 100287 #***           Backwards compatibility for old tesselator           ****/
+
+proc gluBeginPolygon*(tess: PGLUtesselator){.dynlib: dllname, 
+    importc: "gluBeginPolygon".}
+proc gluNextContour*(tess: PGLUtesselator, atype: TGLenum){.dynlib: dllname, 
+    importc: "gluNextContour".}
+proc gluEndPolygon*(tess: PGLUtesselator){.dynlib: dllname, 
+    importc: "gluEndPolygon".}
+const                         # Contours types -- obsolete!
+  GLU_CW* = 100120
+  GLU_CCW* = 100121
+  GLU_INTERIOR* = 100122
+  GLU_EXTERIOR* = 100123
+  GLU_UNKNOWN* = 100124       # Names without "TESS_" prefix
+  GLU_BEGIN* = GLU_TESS_BEGIN
+  GLU_VERTEX* = constGLU_TESS_VERTEX
+  GLU_END* = GLU_TESS_END
+  GLU_ERROR* = GLU_TESS_ERROR
+  GLU_EDGE_FLAG* = GLU_TESS_EDGE_FLAG
+
+{.pop.}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/glut.nim b/tests/manyloc/keineschweine/lib/glut.nim
new file mode 100644
index 000000000..ff157c327
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glut.nim
@@ -0,0 +1,438 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#
+
+# Copyright (c) Mark J. Kilgard, 1994, 1995, 1996.
+# This program is freely distributable without licensing fees  and is
+#   provided without guarantee or warrantee expressed or  implied. This
+#   program is -not- in the public domain.
+#******************************************************************************
+# Converted to Delphi by Tom Nuydens (tom@delphi3d.net)
+#   Contributions by Igor Karpov (glygrik@hotbox.ru)
+#   For the latest updates, visit Delphi3D: http://www.delphi3d.net
+#******************************************************************************
+
+import 
+  GL
+
+when defined(windows): 
+  const 
+    dllname = "glut32.dll"
+elif defined(macosx): 
+  const 
+    dllname = "/System/Library/Frameworks/GLUT.framework/GLUT"
+else: 
+  const 
+    dllname = "libglut.so.3"
+type
+  TGlutVoidCallback* = proc (){.cdecl.}
+  TGlut1IntCallback* = proc (value: cint){.cdecl.}
+  TGlut2IntCallback* = proc (v1, v2: cint){.cdecl.}
+  TGlut3IntCallback* = proc (v1, v2, v3: cint){.cdecl.}
+  TGlut4IntCallback* = proc (v1, v2, v3, v4: cint){.cdecl.}
+  TGlut1Char2IntCallback* = proc (c: int8, v1, v2: cint){.cdecl.}
+  TGlut1UInt3IntCallback* = proc (u, v1, v2, v3: cint){.cdecl.}
+
+const 
+  GLUT_API_VERSION* = 3
+  GLUT_XLIB_IMPLEMENTATION* = 12 # Display mode bit masks.
+  GLUT_RGB* = 0
+  GLUT_RGBA* = GLUT_RGB
+  GLUT_INDEX* = 1
+  GLUT_SINGLE* = 0
+  GLUT_DOUBLE* = 2
+  GLUT_ACCUM* = 4
+  GLUT_ALPHA* = 8
+  GLUT_DEPTH* = 16
+  GLUT_STENCIL* = 32
+  GLUT_MULTISAMPLE* = 128
+  GLUT_STEREO* = 256
+  GLUT_LUMINANCE* = 512       # Mouse buttons.
+  GLUT_LEFT_BUTTON* = 0
+  GLUT_MIDDLE_BUTTON* = 1
+  GLUT_RIGHT_BUTTON* = 2      # Mouse button state.
+  GLUT_DOWN* = 0
+  GLUT_UP* = 1                # function keys
+  GLUT_KEY_F1* = 1
+  GLUT_KEY_F2* = 2
+  GLUT_KEY_F3* = 3
+  GLUT_KEY_F4* = 4
+  GLUT_KEY_F5* = 5
+  GLUT_KEY_F6* = 6
+  GLUT_KEY_F7* = 7
+  GLUT_KEY_F8* = 8
+  GLUT_KEY_F9* = 9
+  GLUT_KEY_F10* = 10
+  GLUT_KEY_F11* = 11
+  GLUT_KEY_F12* = 12          # directional keys
+  GLUT_KEY_LEFT* = 100
+  GLUT_KEY_UP* = 101
+  GLUT_KEY_RIGHT* = 102
+  GLUT_KEY_DOWN* = 103
+  GLUT_KEY_PAGE_UP* = 104
+  GLUT_KEY_PAGE_DOWN* = 105
+  GLUT_KEY_HOME* = 106
+  GLUT_KEY_END* = 107
+  GLUT_KEY_INSERT* = 108      # Entry/exit  state.
+  GLUT_LEFT* = 0
+  GLUT_ENTERED* = 1           # Menu usage state.
+  GLUT_MENU_NOT_IN_USE* = 0
+  GLUT_MENU_IN_USE* = 1       # Visibility  state.
+  GLUT_NOT_VISIBLE* = 0
+  GLUT_VISIBLE* = 1           # Window status  state.
+  GLUT_HIDDEN* = 0
+  GLUT_FULLY_RETAINED* = 1
+  GLUT_PARTIALLY_RETAINED* = 2
+  GLUT_FULLY_COVERED* = 3     # Color index component selection values.
+  GLUT_RED* = 0
+  GLUT_GREEN* = 1
+  GLUT_BLUE* = 2              # Layers for use.
+  GLUT_NORMAL* = 0
+  GLUT_OVERLAY* = 1
+
+when defined(Windows): 
+  const                       # Stroke font constants (use these in GLUT program).
+    GLUT_STROKE_ROMAN* = cast[Pointer](0)
+    GLUT_STROKE_MONO_ROMAN* = cast[Pointer](1) # Bitmap font constants (use these in GLUT program).
+    GLUT_BITMAP_9_BY_15* = cast[Pointer](2)
+    GLUT_BITMAP_8_BY_13* = cast[Pointer](3)
+    GLUT_BITMAP_TIMES_ROMAN_10* = cast[Pointer](4)
+    GLUT_BITMAP_TIMES_ROMAN_24* = cast[Pointer](5)
+    GLUT_BITMAP_HELVETICA_10* = cast[Pointer](6)
+    GLUT_BITMAP_HELVETICA_12* = cast[Pointer](7)
+    GLUT_BITMAP_HELVETICA_18* = cast[Pointer](8)
+else: 
+  var                         # Stroke font constants (use these in GLUT program).
+    GLUT_STROKE_ROMAN*: Pointer
+    GLUT_STROKE_MONO_ROMAN*: Pointer # Bitmap font constants (use these in GLUT program).
+    GLUT_BITMAP_9_BY_15*: Pointer
+    GLUT_BITMAP_8_BY_13*: Pointer
+    GLUT_BITMAP_TIMES_ROMAN_10*: Pointer
+    GLUT_BITMAP_TIMES_ROMAN_24*: Pointer
+    GLUT_BITMAP_HELVETICA_10*: Pointer
+    GLUT_BITMAP_HELVETICA_12*: Pointer
+    GLUT_BITMAP_HELVETICA_18*: Pointer
+const                         # glutGet parameters.
+  GLUT_WINDOW_X* = 100
+  GLUT_WINDOW_Y* = 101
+  GLUT_WINDOW_WIDTH* = 102
+  GLUT_WINDOW_HEIGHT* = 103
+  GLUT_WINDOW_BUFFER_SIZE* = 104
+  GLUT_WINDOW_STENCIL_SIZE* = 105
+  GLUT_WINDOW_DEPTH_SIZE* = 106
+  GLUT_WINDOW_RED_SIZE* = 107
+  GLUT_WINDOW_GREEN_SIZE* = 108
+  GLUT_WINDOW_BLUE_SIZE* = 109
+  GLUT_WINDOW_ALPHA_SIZE* = 110
+  GLUT_WINDOW_ACCUM_RED_SIZE* = 111
+  GLUT_WINDOW_ACCUM_GREEN_SIZE* = 112
+  GLUT_WINDOW_ACCUM_BLUE_SIZE* = 113
+  GLUT_WINDOW_ACCUM_ALPHA_SIZE* = 114
+  GLUT_WINDOW_DOUBLEBUFFER* = 115
+  GLUT_WINDOW_RGBA* = 116
+  GLUT_WINDOW_PARENT* = 117
+  GLUT_WINDOW_NUM_CHILDREN* = 118
+  GLUT_WINDOW_COLORMAP_SIZE* = 119
+  GLUT_WINDOW_NUM_SAMPLES* = 120
+  GLUT_WINDOW_STEREO* = 121
+  GLUT_WINDOW_CURSOR* = 122
+  GLUT_SCREEN_WIDTH* = 200
+  GLUT_SCREEN_HEIGHT* = 201
+  GLUT_SCREEN_WIDTH_MM* = 202
+  GLUT_SCREEN_HEIGHT_MM* = 203
+  GLUT_MENU_NUM_ITEMS* = 300
+  GLUT_DISPLAY_MODE_POSSIBLE* = 400
+  GLUT_INIT_WINDOW_X* = 500
+  GLUT_INIT_WINDOW_Y* = 501
+  GLUT_INIT_WINDOW_WIDTH* = 502
+  GLUT_INIT_WINDOW_HEIGHT* = 503
+  constGLUT_INIT_DISPLAY_MODE* = 504
+  GLUT_ELAPSED_TIME* = 700
+  GLUT_WINDOW_FORMAT_ID* = 123 # glutDeviceGet parameters.
+  GLUT_HAS_KEYBOARD* = 600
+  GLUT_HAS_MOUSE* = 601
+  GLUT_HAS_SPACEBALL* = 602
+  GLUT_HAS_DIAL_AND_BUTTON_BOX* = 603
+  GLUT_HAS_TABLET* = 604
+  GLUT_NUM_MOUSE_BUTTONS* = 605
+  GLUT_NUM_SPACEBALL_BUTTONS* = 606
+  GLUT_NUM_BUTTON_BOX_BUTTONS* = 607
+  GLUT_NUM_DIALS* = 608
+  GLUT_NUM_TABLET_BUTTONS* = 609
+  GLUT_DEVICE_IGNORE_KEY_REPEAT* = 610
+  GLUT_DEVICE_KEY_REPEAT* = 611
+  GLUT_HAS_JOYSTICK* = 612
+  GLUT_OWNS_JOYSTICK* = 613
+  GLUT_JOYSTICK_BUTTONS* = 614
+  GLUT_JOYSTICK_AXES* = 615
+  GLUT_JOYSTICK_POLL_RATE* = 616 # glutLayerGet parameters.
+  GLUT_OVERLAY_POSSIBLE* = 800
+  GLUT_LAYER_IN_USE* = 801
+  GLUT_HAS_OVERLAY* = 802
+  GLUT_TRANSPARENT_INDEX* = 803
+  GLUT_NORMAL_DAMAGED* = 804
+  GLUT_OVERLAY_DAMAGED* = 805 # glutVideoResizeGet parameters.
+  GLUT_VIDEO_RESIZE_POSSIBLE* = 900
+  GLUT_VIDEO_RESIZE_IN_USE* = 901
+  GLUT_VIDEO_RESIZE_X_DELTA* = 902
+  GLUT_VIDEO_RESIZE_Y_DELTA* = 903
+  GLUT_VIDEO_RESIZE_WIDTH_DELTA* = 904
+  GLUT_VIDEO_RESIZE_HEIGHT_DELTA* = 905
+  GLUT_VIDEO_RESIZE_X* = 906
+  GLUT_VIDEO_RESIZE_Y* = 907
+  GLUT_VIDEO_RESIZE_WIDTH* = 908
+  GLUT_VIDEO_RESIZE_HEIGHT* = 909 # glutGetModifiers return mask.
+  GLUT_ACTIVE_SHIFT* = 1
+  GLUT_ACTIVE_CTRL* = 2
+  GLUT_ACTIVE_ALT* = 4        # glutSetCursor parameters.
+                              # Basic arrows.
+  GLUT_CURSOR_RIGHT_ARROW* = 0
+  GLUT_CURSOR_LEFT_ARROW* = 1 # Symbolic cursor shapes.
+  GLUT_CURSOR_INFO* = 2
+  GLUT_CURSOR_DESTROY* = 3
+  GLUT_CURSOR_HELP* = 4
+  GLUT_CURSOR_CYCLE* = 5
+  GLUT_CURSOR_SPRAY* = 6
+  GLUT_CURSOR_WAIT* = 7
+  GLUT_CURSOR_TEXT* = 8
+  GLUT_CURSOR_CROSSHAIR* = 9  # Directional cursors.
+  GLUT_CURSOR_UP_DOWN* = 10
+  GLUT_CURSOR_LEFT_RIGHT* = 11 # Sizing cursors.
+  GLUT_CURSOR_TOP_SIDE* = 12
+  GLUT_CURSOR_BOTTOM_SIDE* = 13
+  GLUT_CURSOR_LEFT_SIDE* = 14
+  GLUT_CURSOR_RIGHT_SIDE* = 15
+  GLUT_CURSOR_TOP_LEFT_CORNER* = 16
+  GLUT_CURSOR_TOP_RIGHT_CORNER* = 17
+  GLUT_CURSOR_BOTTOM_RIGHT_CORNER* = 18
+  GLUT_CURSOR_BOTTOM_LEFT_CORNER* = 19 # Inherit from parent window.
+  GLUT_CURSOR_INHERIT* = 100  # Blank cursor.
+  GLUT_CURSOR_NONE* = 101     # Fullscreen crosshair (if available).
+  GLUT_CURSOR_FULL_CROSSHAIR* = 102 # GLUT device control sub-API.
+                                    # glutSetKeyRepeat modes.
+  GLUT_KEY_REPEAT_OFF* = 0
+  GLUT_KEY_REPEAT_ON* = 1
+  GLUT_KEY_REPEAT_DEFAULT* = 2 # Joystick button masks.
+  GLUT_JOYSTICK_BUTTON_A* = 1
+  GLUT_JOYSTICK_BUTTON_B* = 2
+  GLUT_JOYSTICK_BUTTON_C* = 4
+  GLUT_JOYSTICK_BUTTON_D* = 8 # GLUT game mode sub-API.
+                              # glutGameModeGet.
+  GLUT_GAME_MODE_ACTIVE* = 0
+  GLUT_GAME_MODE_POSSIBLE* = 1
+  GLUT_GAME_MODE_WIDTH* = 2
+  GLUT_GAME_MODE_HEIGHT* = 3
+  GLUT_GAME_MODE_PIXEL_DEPTH* = 4
+  GLUT_GAME_MODE_REFRESH_RATE* = 5
+  GLUT_GAME_MODE_DISPLAY_CHANGED* = 6 # GLUT initialization sub-API.
+
+proc glutInit*(argcp: ptr cint, argv: pointer){.dynlib: dllname, 
+    importc: "glutInit".}
+
+proc glutInit*() =
+  ## version that passes `argc` and `argc` implicitely.
+  var
+    cmdLine {.importc: "cmdLine".}: array[0..255, cstring]
+    cmdCount {.importc: "cmdCount".}: cint
+  glutInit(addr(cmdCount), addr(cmdLine))
+
+proc glutInitDisplayMode*(mode: int16){.dynlib: dllname, 
+                                        importc: "glutInitDisplayMode".}
+proc glutInitDisplayString*(str: cstring){.dynlib: dllname, 
+    importc: "glutInitDisplayString".}
+proc glutInitWindowPosition*(x, y: int){.dynlib: dllname, 
+    importc: "glutInitWindowPosition".}
+proc glutInitWindowSize*(width, height: int){.dynlib: dllname, 
+    importc: "glutInitWindowSize".}
+proc glutMainLoop*(){.dynlib: dllname, importc: "glutMainLoop".}
+  # GLUT window sub-API.
+proc glutCreateWindow*(title: cstring): int{.dynlib: dllname, 
+    importc: "glutCreateWindow".}
+proc glutCreateSubWindow*(win, x, y, width, height: int): int{.dynlib: dllname, 
+    importc: "glutCreateSubWindow".}
+proc glutDestroyWindow*(win: int){.dynlib: dllname, importc: "glutDestroyWindow".}
+proc glutPostRedisplay*(){.dynlib: dllname, importc: "glutPostRedisplay".}
+proc glutPostWindowRedisplay*(win: int){.dynlib: dllname, 
+    importc: "glutPostWindowRedisplay".}
+proc glutSwapBuffers*(){.dynlib: dllname, importc: "glutSwapBuffers".}
+proc glutGetWindow*(): int{.dynlib: dllname, importc: "glutGetWindow".}
+proc glutSetWindow*(win: int){.dynlib: dllname, importc: "glutSetWindow".}
+proc glutSetWindowTitle*(title: cstring){.dynlib: dllname, 
+    importc: "glutSetWindowTitle".}
+proc glutSetIconTitle*(title: cstring){.dynlib: dllname, 
+                                        importc: "glutSetIconTitle".}
+proc glutPositionWindow*(x, y: int){.dynlib: dllname, 
+                                     importc: "glutPositionWindow".}
+proc glutReshapeWindow*(width, height: int){.dynlib: dllname, 
+    importc: "glutReshapeWindow".}
+proc glutPopWindow*(){.dynlib: dllname, importc: "glutPopWindow".}
+proc glutPushWindow*(){.dynlib: dllname, importc: "glutPushWindow".}
+proc glutIconifyWindow*(){.dynlib: dllname, importc: "glutIconifyWindow".}
+proc glutShowWindow*(){.dynlib: dllname, importc: "glutShowWindow".}
+proc glutHideWindow*(){.dynlib: dllname, importc: "glutHideWindow".}
+proc glutFullScreen*(){.dynlib: dllname, importc: "glutFullScreen".}
+proc glutSetCursor*(cursor: int){.dynlib: dllname, importc: "glutSetCursor".}
+proc glutWarpPointer*(x, y: int){.dynlib: dllname, importc: "glutWarpPointer".}
+  # GLUT overlay sub-API.
+proc glutEstablishOverlay*(){.dynlib: dllname, importc: "glutEstablishOverlay".}
+proc glutRemoveOverlay*(){.dynlib: dllname, importc: "glutRemoveOverlay".}
+proc glutUseLayer*(layer: TGLenum){.dynlib: dllname, importc: "glutUseLayer".}
+proc glutPostOverlayRedisplay*(){.dynlib: dllname, 
+                                  importc: "glutPostOverlayRedisplay".}
+proc glutPostWindowOverlayRedisplay*(win: int){.dynlib: dllname, 
+    importc: "glutPostWindowOverlayRedisplay".}
+proc glutShowOverlay*(){.dynlib: dllname, importc: "glutShowOverlay".}
+proc glutHideOverlay*(){.dynlib: dllname, importc: "glutHideOverlay".}
+  # GLUT menu sub-API.
+proc glutCreateMenu*(callback: TGlut1IntCallback): int{.dynlib: dllname, 
+    importc: "glutCreateMenu".}
+proc glutDestroyMenu*(menu: int){.dynlib: dllname, importc: "glutDestroyMenu".}
+proc glutGetMenu*(): int{.dynlib: dllname, importc: "glutGetMenu".}
+proc glutSetMenu*(menu: int){.dynlib: dllname, importc: "glutSetMenu".}
+proc glutAddMenuEntry*(caption: cstring, value: int){.dynlib: dllname, 
+    importc: "glutAddMenuEntry".}
+proc glutAddSubMenu*(caption: cstring, submenu: int){.dynlib: dllname, 
+    importc: "glutAddSubMenu".}
+proc glutChangeToMenuEntry*(item: int, caption: cstring, value: int){.
+    dynlib: dllname, importc: "glutChangeToMenuEntry".}
+proc glutChangeToSubMenu*(item: int, caption: cstring, submenu: int){.
+    dynlib: dllname, importc: "glutChangeToSubMenu".}
+proc glutRemoveMenuItem*(item: int){.dynlib: dllname, 
+                                     importc: "glutRemoveMenuItem".}
+proc glutAttachMenu*(button: int){.dynlib: dllname, importc: "glutAttachMenu".}
+proc glutDetachMenu*(button: int){.dynlib: dllname, importc: "glutDetachMenu".}
+  # GLUT window callback sub-API.
+proc glutDisplayFunc*(f: TGlutVoidCallback){.dynlib: dllname, 
+    importc: "glutDisplayFunc".}
+proc glutReshapeFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutReshapeFunc".}
+proc glutKeyboardFunc*(f: TGlut1Char2IntCallback){.dynlib: dllname, 
+    importc: "glutKeyboardFunc".}
+proc glutMouseFunc*(f: TGlut4IntCallback){.dynlib: dllname, 
+    importc: "glutMouseFunc".}
+proc glutMotionFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutMotionFunc".}
+proc glutPassiveMotionFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutPassiveMotionFunc".}
+proc glutEntryFunc*(f: TGlut1IntCallback){.dynlib: dllname, 
+    importc: "glutEntryFunc".}
+proc glutVisibilityFunc*(f: TGlut1IntCallback){.dynlib: dllname, 
+    importc: "glutVisibilityFunc".}
+proc glutIdleFunc*(f: TGlutVoidCallback){.dynlib: dllname, 
+    importc: "glutIdleFunc".}
+proc glutTimerFunc*(millis: int16, f: TGlut1IntCallback, value: int){.
+    dynlib: dllname, importc: "glutTimerFunc".}
+proc glutMenuStateFunc*(f: TGlut1IntCallback){.dynlib: dllname, 
+    importc: "glutMenuStateFunc".}
+proc glutSpecialFunc*(f: TGlut3IntCallback){.dynlib: dllname, 
+    importc: "glutSpecialFunc".}
+proc glutSpaceballMotionFunc*(f: TGlut3IntCallback){.dynlib: dllname, 
+    importc: "glutSpaceballMotionFunc".}
+proc glutSpaceballRotateFunc*(f: TGlut3IntCallback){.dynlib: dllname, 
+    importc: "glutSpaceballRotateFunc".}
+proc glutSpaceballButtonFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutSpaceballButtonFunc".}
+proc glutButtonBoxFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutButtonBoxFunc".}
+proc glutDialsFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutDialsFunc".}
+proc glutTabletMotionFunc*(f: TGlut2IntCallback){.dynlib: dllname, 
+    importc: "glutTabletMotionFunc".}
+proc glutTabletButtonFunc*(f: TGlut4IntCallback){.dynlib: dllname, 
+    importc: "glutTabletButtonFunc".}
+proc glutMenuStatusFunc*(f: TGlut3IntCallback){.dynlib: dllname, 
+    importc: "glutMenuStatusFunc".}
+proc glutOverlayDisplayFunc*(f: TGlutVoidCallback){.dynlib: dllname, 
+    importc: "glutOverlayDisplayFunc".}
+proc glutWindowStatusFunc*(f: TGlut1IntCallback){.dynlib: dllname, 
+    importc: "glutWindowStatusFunc".}
+proc glutKeyboardUpFunc*(f: TGlut1Char2IntCallback){.dynlib: dllname, 
+    importc: "glutKeyboardUpFunc".}
+proc glutSpecialUpFunc*(f: TGlut3IntCallback){.dynlib: dllname, 
+    importc: "glutSpecialUpFunc".}
+proc glutJoystickFunc*(f: TGlut1UInt3IntCallback, pollInterval: int){.
+    dynlib: dllname, importc: "glutJoystickFunc".}
+  # GLUT color index sub-API.
+proc glutSetColor*(cell: int, red, green, blue: TGLfloat){.dynlib: dllname, 
+    importc: "glutSetColor".}
+proc glutGetColor*(ndx, component: int): TGLfloat{.dynlib: dllname, 
+    importc: "glutGetColor".}
+proc glutCopyColormap*(win: int){.dynlib: dllname, importc: "glutCopyColormap".}
+  # GLUT state retrieval sub-API.
+proc glutGet*(t: TGLenum): int{.dynlib: dllname, importc: "glutGet".}
+proc glutDeviceGet*(t: TGLenum): int{.dynlib: dllname, importc: "glutDeviceGet".}
+  # GLUT extension support sub-API
+proc glutExtensionSupported*(name: cstring): int{.dynlib: dllname, 
+    importc: "glutExtensionSupported".}
+proc glutGetModifiers*(): int{.dynlib: dllname, importc: "glutGetModifiers".}
+proc glutLayerGet*(t: TGLenum): int{.dynlib: dllname, importc: "glutLayerGet".}
+  # GLUT font sub-API
+proc glutBitmapCharacter*(font: pointer, character: int){.dynlib: dllname, 
+    importc: "glutBitmapCharacter".}
+proc glutBitmapWidth*(font: pointer, character: int): int{.dynlib: dllname, 
+    importc: "glutBitmapWidth".}
+proc glutStrokeCharacter*(font: pointer, character: int){.dynlib: dllname, 
+    importc: "glutStrokeCharacter".}
+proc glutStrokeWidth*(font: pointer, character: int): int{.dynlib: dllname, 
+    importc: "glutStrokeWidth".}
+proc glutBitmapLength*(font: pointer, str: cstring): int{.dynlib: dllname, 
+    importc: "glutBitmapLength".}
+proc glutStrokeLength*(font: pointer, str: cstring): int{.dynlib: dllname, 
+    importc: "glutStrokeLength".}
+  # GLUT pre-built models sub-API
+proc glutWireSphere*(radius: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutWireSphere".}
+proc glutSolidSphere*(radius: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutSolidSphere".}
+proc glutWireCone*(base, height: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutWireCone".}
+proc glutSolidCone*(base, height: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutSolidCone".}
+proc glutWireCube*(size: TGLdouble){.dynlib: dllname, importc: "glutWireCube".}
+proc glutSolidCube*(size: TGLdouble){.dynlib: dllname, importc: "glutSolidCube".}
+proc glutWireTorus*(innerRadius, outerRadius: TGLdouble, sides, rings: TGLint){.
+    dynlib: dllname, importc: "glutWireTorus".}
+proc glutSolidTorus*(innerRadius, outerRadius: TGLdouble, sides, rings: TGLint){.
+    dynlib: dllname, importc: "glutSolidTorus".}
+proc glutWireDodecahedron*(){.dynlib: dllname, importc: "glutWireDodecahedron".}
+proc glutSolidDodecahedron*(){.dynlib: dllname, importc: "glutSolidDodecahedron".}
+proc glutWireTeapot*(size: TGLdouble){.dynlib: dllname, 
+                                       importc: "glutWireTeapot".}
+proc glutSolidTeapot*(size: TGLdouble){.dynlib: dllname, 
+                                        importc: "glutSolidTeapot".}
+proc glutWireOctahedron*(){.dynlib: dllname, importc: "glutWireOctahedron".}
+proc glutSolidOctahedron*(){.dynlib: dllname, importc: "glutSolidOctahedron".}
+proc glutWireTetrahedron*(){.dynlib: dllname, importc: "glutWireTetrahedron".}
+proc glutSolidTetrahedron*(){.dynlib: dllname, importc: "glutSolidTetrahedron".}
+proc glutWireIcosahedron*(){.dynlib: dllname, importc: "glutWireIcosahedron".}
+proc glutSolidIcosahedron*(){.dynlib: dllname, importc: "glutSolidIcosahedron".}
+  # GLUT video resize sub-API.
+proc glutVideoResizeGet*(param: TGLenum): int{.dynlib: dllname, 
+    importc: "glutVideoResizeGet".}
+proc glutSetupVideoResizing*(){.dynlib: dllname, 
+                                importc: "glutSetupVideoResizing".}
+proc glutStopVideoResizing*(){.dynlib: dllname, importc: "glutStopVideoResizing".}
+proc glutVideoResize*(x, y, width, height: int){.dynlib: dllname, 
+    importc: "glutVideoResize".}
+proc glutVideoPan*(x, y, width, height: int){.dynlib: dllname, 
+    importc: "glutVideoPan".}
+  # GLUT debugging sub-API.
+proc glutReportErrors*(){.dynlib: dllname, importc: "glutReportErrors".}
+  # GLUT device control sub-API.
+proc glutIgnoreKeyRepeat*(ignore: int){.dynlib: dllname, 
+                                        importc: "glutIgnoreKeyRepeat".}
+proc glutSetKeyRepeat*(repeatMode: int){.dynlib: dllname, 
+    importc: "glutSetKeyRepeat".}
+proc glutForceJoystickFunc*(){.dynlib: dllname, importc: "glutForceJoystickFunc".}
+  # GLUT game mode sub-API.
+  #example glutGameModeString('1280x1024:32@75');
+proc glutGameModeString*(AString: cstring){.dynlib: dllname, 
+    importc: "glutGameModeString".}
+proc glutEnterGameMode*(): int{.dynlib: dllname, importc: "glutEnterGameMode".}
+proc glutLeaveGameMode*(){.dynlib: dllname, importc: "glutLeaveGameMode".}
+proc glutGameModeGet*(mode: TGLenum): int{.dynlib: dllname, 
+    importc: "glutGameModeGet".}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/glx.nim b/tests/manyloc/keineschweine/lib/glx.nim
new file mode 100644
index 000000000..76c052d70
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glx.nim
@@ -0,0 +1,153 @@
+#
+#
+#  Translation of the Mesa GLX headers for FreePascal
+#  Copyright (C) 1999 Sebastian Guenther
+#
+#
+#  Mesa 3-D graphics library
+#  Version:  3.0
+#  Copyright (C) 1995-1998  Brian Paul
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Library General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 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
+#  Library General Public License for more details.
+#
+#  You should have received a copy of the GNU Library General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import 
+  X, XLib, XUtil, gl
+
+when defined(windows): 
+  const 
+    dllname = "GL.dll"
+elif defined(macosx): 
+  const 
+    dllname = "/usr/X11R6/lib/libGL.dylib"
+else: 
+  const 
+    dllname = "libGL.so"
+const 
+  GLX_USE_GL* = 1
+  GLX_BUFFER_SIZE* = 2
+  GLX_LEVEL* = 3
+  GLX_RGBA* = 4
+  GLX_DOUBLEBUFFER* = 5
+  GLX_STEREO* = 6
+  GLX_AUX_BUFFERS* = 7
+  GLX_RED_SIZE* = 8
+  GLX_GREEN_SIZE* = 9
+  GLX_BLUE_SIZE* = 10
+  GLX_ALPHA_SIZE* = 11
+  GLX_DEPTH_SIZE* = 12
+  GLX_STENCIL_SIZE* = 13
+  GLX_ACCUM_RED_SIZE* = 14
+  GLX_ACCUM_GREEN_SIZE* = 15
+  GLX_ACCUM_BLUE_SIZE* = 16
+  GLX_ACCUM_ALPHA_SIZE* = 17  # GLX_EXT_visual_info extension
+  GLX_X_VISUAL_TYPE_EXT* = 0x00000022
+  GLX_TRANSPARENT_TYPE_EXT* = 0x00000023
+  GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024
+  GLX_TRANSPARENT_RED_VALUE_EXT* = 0x00000025
+  GLX_TRANSPARENT_GREEN_VALUE_EXT* = 0x00000026
+  GLX_TRANSPARENT_BLUE_VALUE_EXT* = 0x00000027
+  GLX_TRANSPARENT_ALPHA_VALUE_EXT* = 0x00000028 # Error codes returned by glXGetConfig:
+  GLX_BAD_SCREEN* = 1
+  GLX_BAD_ATTRIBUTE* = 2
+  GLX_NO_EXTENSION* = 3
+  GLX_BAD_VISUAL* = 4
+  GLX_BAD_CONTEXT* = 5
+  GLX_BAD_VALUE* = 6
+  GLX_BAD_ENUM* = 7           # GLX 1.1 and later:
+  GLX_VENDOR* = 1
+  GLX_VERSION* = 2
+  GLX_EXTENSIONS* = 3         # GLX_visual_info extension
+  GLX_TRUE_COLOR_EXT* = 0x00008002
+  GLX_DIRECT_COLOR_EXT* = 0x00008003
+  GLX_PSEUDO_COLOR_EXT* = 0x00008004
+  GLX_STATIC_COLOR_EXT* = 0x00008005
+  GLX_GRAY_SCALE_EXT* = 0x00008006
+  GLX_STATIC_GRAY_EXT* = 0x00008007
+  GLX_NONE_EXT* = 0x00008000
+  GLX_TRANSPARENT_RGB_EXT* = 0x00008008
+  GLX_TRANSPARENT_INDEX_EXT* = 0x00008009
+
+type                          # From XLib:
+  XPixmap* = TXID
+  XFont* = TXID
+  XColormap* = TXID
+  GLXContext* = Pointer
+  GLXPixmap* = TXID
+  GLXDrawable* = TXID
+  GLXContextID* = TXID
+  TXPixmap* = XPixmap
+  TXFont* = XFont
+  TXColormap* = XColormap
+  TGLXContext* = GLXContext
+  TGLXPixmap* = GLXPixmap
+  TGLXDrawable* = GLXDrawable
+  TGLXContextID* = GLXContextID
+
+proc glXChooseVisual*(dpy: PDisplay, screen: int, attribList: ptr int32): PXVisualInfo{.
+    cdecl, dynlib: dllname, importc: "glXChooseVisual".}
+proc glXCreateContext*(dpy: PDisplay, vis: PXVisualInfo, shareList: GLXContext, 
+                       direct: bool): GLXContext{.cdecl, dynlib: dllname, 
+    importc: "glXCreateContext".}
+proc glXDestroyContext*(dpy: PDisplay, ctx: GLXContext){.cdecl, dynlib: dllname, 
+    importc: "glXDestroyContext".}
+proc glXMakeCurrent*(dpy: PDisplay, drawable: GLXDrawable, ctx: GLXContext): bool{.
+    cdecl, dynlib: dllname, importc: "glXMakeCurrent".}
+proc glXCopyContext*(dpy: PDisplay, src, dst: GLXContext, mask: int32){.cdecl, 
+    dynlib: dllname, importc: "glXCopyContext".}
+proc glXSwapBuffers*(dpy: PDisplay, drawable: GLXDrawable){.cdecl, 
+    dynlib: dllname, importc: "glXSwapBuffers".}
+proc glXCreateGLXPixmap*(dpy: PDisplay, visual: PXVisualInfo, pixmap: XPixmap): GLXPixmap{.
+    cdecl, dynlib: dllname, importc: "glXCreateGLXPixmap".}
+proc glXDestroyGLXPixmap*(dpy: PDisplay, pixmap: GLXPixmap){.cdecl, 
+    dynlib: dllname, importc: "glXDestroyGLXPixmap".}
+proc glXQueryExtension*(dpy: PDisplay, errorb, event: var int): bool{.cdecl, 
+    dynlib: dllname, importc: "glXQueryExtension".}
+proc glXQueryVersion*(dpy: PDisplay, maj, min: var int): bool{.cdecl, 
+    dynlib: dllname, importc: "glXQueryVersion".}
+proc glXIsDirect*(dpy: PDisplay, ctx: GLXContext): bool{.cdecl, dynlib: dllname, 
+    importc: "glXIsDirect".}
+proc glXGetConfig*(dpy: PDisplay, visual: PXVisualInfo, attrib: int, 
+                   value: var int): int{.cdecl, dynlib: dllname, 
+    importc: "glXGetConfig".}
+proc glXGetCurrentContext*(): GLXContext{.cdecl, dynlib: dllname, 
+    importc: "glXGetCurrentContext".}
+proc glXGetCurrentDrawable*(): GLXDrawable{.cdecl, dynlib: dllname, 
+    importc: "glXGetCurrentDrawable".}
+proc glXWaitGL*(){.cdecl, dynlib: dllname, importc: "glXWaitGL".}
+proc glXWaitX*(){.cdecl, dynlib: dllname, importc: "glXWaitX".}
+proc glXUseXFont*(font: XFont, first, count, list: int){.cdecl, dynlib: dllname, 
+    importc: "glXUseXFont".}
+  # GLX 1.1 and later
+proc glXQueryExtensionsString*(dpy: PDisplay, screen: int): cstring{.cdecl, 
+    dynlib: dllname, importc: "glXQueryExtensionsString".}
+proc glXQueryServerString*(dpy: PDisplay, screen, name: int): cstring{.cdecl, 
+    dynlib: dllname, importc: "glXQueryServerString".}
+proc glXGetClientString*(dpy: PDisplay, name: int): cstring{.cdecl, 
+    dynlib: dllname, importc: "glXGetClientString".}
+  # Mesa GLX Extensions
+proc glXCreateGLXPixmapMESA*(dpy: PDisplay, visual: PXVisualInfo, 
+                             pixmap: XPixmap, cmap: XColormap): GLXPixmap{.
+    cdecl, dynlib: dllname, importc: "glXCreateGLXPixmapMESA".}
+proc glXReleaseBufferMESA*(dpy: PDisplay, d: GLXDrawable): bool{.cdecl, 
+    dynlib: dllname, importc: "glXReleaseBufferMESA".}
+proc glXCopySubBufferMESA*(dpy: PDisplay, drawbale: GLXDrawable, 
+                           x, y, width, height: int){.cdecl, dynlib: dllname, 
+    importc: "glXCopySubBufferMESA".}
+proc glXGetVideoSyncSGI*(counter: var int32): int{.cdecl, dynlib: dllname, 
+    importc: "glXGetVideoSyncSGI".}
+proc glXWaitVideoSyncSGI*(divisor, remainder: int, count: var int32): int{.
+    cdecl, dynlib: dllname, importc: "glXWaitVideoSyncSGI".}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/idgen.nim b/tests/manyloc/keineschweine/lib/idgen.nim
new file mode 100644
index 000000000..8124ba9bd
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/idgen.nim
@@ -0,0 +1,23 @@
+type
+  PIDGen*[T: Ordinal] = ref TIDGen[T]
+  TIDGen*[T: Ordinal] = object
+    max: T
+    freeIDs: seq[T]
+  EOutOfIDs* = object of EInvalidKey
+
+#proc free[T](idg: PIDgen[T]) = 
+#  result.freeIDs = nil
+proc newIDGen*[T: Ordinal](): PIDGen[T] =
+  new(result)#, free)
+  result.max = 0.T
+  result.freeIDs = @[]
+proc next*[T](idg: PIDGen[T]): T =
+  if idg.freeIDs.len > 0:
+    result = idg.freeIDs.pop
+  elif idg.max < high(T)-T(1):
+    inc idg.max
+    result = idg.max
+  else:
+    raise newException(EOutOfIDs, "ID generator hit max value")
+proc del*[T](idg: PIDGen[T]; id: T) =
+  idg.freeIDs.add id
diff --git a/tests/manyloc/keineschweine/lib/input_helpers.nim b/tests/manyloc/keineschweine/lib/input_helpers.nim
new file mode 100644
index 000000000..120576dfb
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/input_helpers.nim
@@ -0,0 +1,138 @@
+import
+  sfml, tables, hashes
+type
+  TKeyEventKind* = enum down, up
+  TInputFinishedProc* = proc() 
+  TKeyCallback = proc()
+  PKeyClient* = ref object
+    onKeyDown: TTable[int32, TKeyCallback]
+    onKeyUp: TTable[int32, TKeyCallback]
+    name: string
+  PTextInput* = ref object
+    text*: string
+    cursor: int
+    onEnter: TInputFinishedProc
+var
+  keyState:    array[-MouseButtonCount.int32 .. KeyCount.int32, bool]
+  mousePos: TVector2f
+  activeClient: PKeyClient = nil
+  activeInput: PTextInput  = nil
+
+proc setActive*(client: PKeyClient) = 
+  activeClient = client
+  echo("** set active client ", client.name)
+proc newKeyClient*(name: string = "unnamed", setactive = false): PKeyClient =
+  new(result)
+  result.onKeyDown = initTable[int32, TKeyCallback](16)
+  result.onKeyUp   = initTable[int32, TKeyCallback](16)
+  result.name = name
+  if setActive:
+    setActive(result)
+
+proc keyPressed*(key: TKeyCode): bool {.inline.} =
+  return keyState[key.int32]
+proc buttonPressed*(btn: TMouseButton): bool {.inline.} =
+  return keyState[-btn.int32]
+
+proc clearKey*(key: TKeyCode) {.inline.} =
+  keyState[key.int32]  = false
+proc clearButton*(btn: TMouseButton) {.inline.} =
+  keyState[-btn.int32] = false
+
+proc addKeyEvent*(key: TKeyCode, ev: TKeyEventKind) {.inline.} =
+  if activeClient.isNil: return
+  let k = key.int32
+  case ev
+  of down: 
+    keyState[k] = true
+    if activeClient.onKeyDown.hasKey(k):
+      activeClient.onKeyDown[k]()
+  else:    
+    keyState[k] = false
+    if activeClient.onKeyUp.hasKey(k):
+      activeClient.onKeyUp[k]()
+proc addButtonEvent*(btn: TMouseButton, ev: TKeyEventKind) {.inline.} =
+  if activeClient.isNil: return 
+  let b = -btn.int32
+  case ev
+  of down: 
+    keyState[b] = true 
+    if activeClient.onKeyDown.hasKey(b):
+      activeClient.onKeyDown[b]()
+  else: 
+    keyState[b] = false
+    if activeClient.onKeyUp.hasKey(b):
+      activeClient.onKeyUp[b]()
+proc registerHandler*(client: PKeyClient; key: TKeyCode;
+                       ev: TKeyEventKind; fn: TKeyCallback) = 
+  case ev
+  of down: client.onKeyDown[key.int32] = fn
+  of up:   client.onKeyUp[key.int32]   = fn
+proc registerHandler*(client: PKeyClient; btn: TMouseButton;
+                       ev: TKeyEventKind; fn: TKeyCallback) =
+  case ev
+  of down: client.onKeyDown[-btn.int32] = fn
+  of up:   client.onKeyUp[-btn.int32]   = fn
+
+proc newTextInput*(text = "", pos = 0, onEnter: TInputFinishedProc = nil): PTextInput =
+  new(result)
+  result.text = text
+  result.cursor = pos
+  result.onEnter = onEnter
+proc setActive*(i: PTextInput) =
+  activeInput = i
+proc stopCapturingText*() =
+  activeInput = nil
+proc clear*(i: PTextInput) =
+  i.text.setLen 0
+  i.cursor = 0
+proc recordText*(i: PTextInput; c: cint) =
+  if c > 127 or i.isNil: return
+  if c in 32..126: ##printable
+    if i.cursor == i.text.len: i.text.add(c.int.chr)
+    else: 
+      let rem = i.text.substr(i.cursor)
+      i.text.setLen(i.cursor)
+      i.text.add(chr(c.int))
+      i.text.add(rem)
+    inc(i.cursor)
+  elif c == 8: ## \b  backspace
+    if i.text.len > 0 and i.cursor > 0:
+      dec(i.cursor)
+      let rem = i.text.substr(i.cursor + 1)
+      i.text.setLen(i.cursor)
+      i.text.add(rem)
+  elif c == 10 or c == 13:## \n, \r  enter
+    if not i.onEnter.isNil: i.onEnter()
+proc recordText*(i: PTextInput; e: TTextEvent) {.inline.} = 
+  recordText(i, e.unicode)
+
+proc setMousePos*(x, y: cint) {.inline.} =
+  mousePos.x = x.float
+  mousePos.y = y.float
+proc getMousePos*(): TVector2f {.inline.} = result = mousePos
+
+var event: TEvent
+# Handle and filter input-related events
+iterator filterEvents*(window: PRenderWindow): PEvent =
+  while window.pollEvent(addr event):
+    case event.kind
+    of EvtKeyPressed: addKeyEvent(event.key.code, down)
+    of EvtKeyReleased: addKeyEvent(event.key.code, up)
+    of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
+    of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
+    of EvtTextEntered: recordText(activeInput, event.text)
+    of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
+    else: yield(addr event)
+# Handle and return input-related events
+iterator pollEvents*(window: PRenderWindow): PEvent =
+  while window.pollEvent(addr event):
+    case event.kind
+    of EvtKeyPressed: addKeyEvent(event.key.code, down)
+    of EvtKeyReleased: addKeyEvent(event.key.code, up)
+    of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
+    of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
+    of EvtTextEntered: recordText(activeInput, event.text)
+    of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
+    else: nil
+    yield(addr event)
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim
new file mode 100644
index 000000000..5776c9225
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/map_filter.nim
@@ -0,0 +1,41 @@
+template filterIt2*(seq, pred: expr, body: stmt): stmt {.immediate, dirty.} =
+  ## sequtils defines a filterIt() that returns a new seq, but this one is called
+  ## with a statement body to iterate directly over it
+  for it in items(seq):
+    if pred: body
+
+proc map*[A, B](x: seq[A], fun: proc(y: A): B {.closure.}): seq[B] =
+  result = @[]
+  for item in x.items:
+    result.add fun(item)
+
+proc mapInPlace*[A](x: var seq[A], fun: proc(y: A): A {.closure.}) =
+  for i in 0..x.len-1:
+    x[i] = fun(x[i])
+
+template unless*(condition: expr; body: stmt): stmt {.dirty.} =
+  if not(condition):
+    body
+
+when isMainModule:
+  proc dumpSeq[T](x: seq[T]) =
+    for index, item in x.pairs: 
+      echo index, " ", item
+    echo "-------"
+
+  var t= @[1,2,3,4,5]
+  var res = t.map(proc(z: int): int = result = z * 10)
+  dumpSeq res
+
+  from strutils import toHex
+  var foocakes = t.map(proc(z: int): string = 
+    result = toHex((z * 23).BiggestInt, 4))
+  dumpSeq foocakes
+
+  t.mapInPlace(proc(z: int): int = result = z * 30)
+  dumpSeq t
+  
+  var someSeq = @[9,8,7,6,5,4,3,2,1] ## numbers < 6 or even
+  filterIt2 someSeq, it < 6 or (it and 1) == 0:
+    echo(it)
+  echo "-----------"
diff --git a/tests/manyloc/keineschweine/lib/math_helpers.nim b/tests/manyloc/keineschweine/lib/math_helpers.nim
new file mode 100644
index 000000000..8af56d1ed
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/math_helpers.nim
@@ -0,0 +1,10 @@
+import strutils, math
+
+proc degrees*(rad: float): float =
+  return rad * 180.0 / PI
+proc radians*(deg: float): float =
+  return deg * PI / 180.0
+
+## V not math, sue me
+proc ff*(f: float, precision = 2): string {.inline.} = 
+  return formatFloat(f, ffDecimal, precision)
diff --git a/tests/manyloc/keineschweine/lib/sfml_stuff.nim b/tests/manyloc/keineschweine/lib/sfml_stuff.nim
new file mode 100644
index 000000000..a5ac91195
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sfml_stuff.nim
@@ -0,0 +1,37 @@
+import 
+  math, strutils,
+  sfml, input_helpers
+when not defined(NoChipmunk):
+  import chipmunk
+  proc floor*(a: TVector): TVector2f {.inline.} =
+    result.x = a.x.floor
+    result.y = a.y.floor
+  proc sfml2cp*(a: TVector2f): TVector {.inline.} =
+    result.x = a.x
+    result.y = a.y
+  proc cp2sfml*(a: TVector): TVector2f {.inline.} =
+    result.x = a.x
+    result.y = a.y
+
+proc vec2f*(a: TVector2i): TVector2f =
+  result.x = a.x.cfloat
+  result.y = a.y.cfloat
+proc vec2i*(a: TVector2f): TVector2i =
+  result.x = a.x.cint
+  result.y = a.y.cint
+proc vec3f*(x, y, z: float): TVector3f =
+  result.x = x.cfloat
+  result.y = y.cfloat
+  result.z = z.cfloat
+
+proc `$`*(a: var TIntRect): string =
+  result = "[TIntRect $1,$2 $3x$4]".format($a.left, $a.top, $a.width, $a.height)
+proc `$`*(a: TKeyEvent): string =
+  return "KeyEvent: code=$1 alt=$2 control=$3 shift=$4 system=$5".format(
+    $a.code, $a.alt, $a.control, $a.shift, $a.system)
+
+proc `wmod`*(x, y: float): float = return x - y * (x/y).floor
+proc move*(a: var TIntRect, left, top: cint): bool =
+  if a.left != left or a.top != top: result = true
+  a.left = left
+  a.top  = top
diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim
new file mode 100644
index 000000000..c5a39550a
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_assets.nim
@@ -0,0 +1,610 @@
+import
+  re, json, strutils, tables, math, os, math_helpers, 
+  sg_packets, md5, zlib_helpers
+
+when defined(NoSFML):
+  import server_utils
+  type TVector2i = object
+    x*, y*: int32
+  proc vec2i(x, y: int32): TVector2i =
+    result.x = x
+    result.y = y
+else:
+  import sfml, sfml_audio, sfml_stuff
+when not defined(NoChipmunk):
+  import chipmunk
+
+type
+  TChecksumFile* = object
+    unpackedSize*: int
+    sum*: MD5Digest
+    compressed*: string
+  PZoneSettings* = ref TZoneSettings
+  TZoneSettings* = object
+    vehicles: seq[PVehicleRecord]
+    items: seq[PItemRecord]
+    objects: seq[PObjectRecord]
+    bullets: seq[PBulletRecord]
+    levelSettings: PLevelSettings
+  PLevelSettings* = ref TLevelSettings
+  TLevelSettings* = object
+    size*: TVector2i
+    starfield*: seq[PSpriteSheet]
+  PVehicleRecord* = ref TVehicleRecord
+  TVehicleRecord* = object
+    id*: int16
+    name*: string
+    playable*: bool
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+    handling*: THandlingRecord
+  TItemKind* = enum
+    Projectile, Utility, Ammo
+  PObjectRecord* = ref TObjectRecord
+  TObjectRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+  PItemRecord* = ref TItemRecord
+  TItemRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord ##apply when the item is dropped in the arena
+    cooldown*: float
+    energyCost*: float
+    useSound*: PSoundRecord
+    case kind*: TItemKind
+    of Projectile: 
+      bullet*: PBulletRecord
+    else: 
+      nil
+  PBulletRecord* = ref TBulletRecord
+  TBulletRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+    lifetime*, inheritVelocity*, baseVelocity*: float
+    explosion*: TExplosionRecord
+    trail*: TTrailRecord
+  TTrailRecord* = object
+    anim*: PAnimationRecord
+    timer*: float ##how often it should be created
+  TPhysicsRecord* = object
+    mass*: float
+    radius*: float
+    moment*: float
+  THandlingRecord = object
+    thrust*, top_speed*: float
+    reverse*, strafe*, rotation*: float
+  TSoulRecord = object
+    energy*: int
+    health*: int
+  TExplosionRecord* = object
+    anim*: PAnimationRecord
+    sound*: PSoundRecord 
+  PAnimationRecord* = ref TAnimationRecord
+  TAnimationRecord* = object
+    spriteSheet*: PSpriteSheet
+    angle*: float
+    delay*: float  ##animation delay
+  PSoundRecord* = ref TSoundRecord
+  TSoundRecord* = object
+    file*: string
+    when defined(NoSFML):
+      contents*: TChecksumFile
+    else:
+      soundBuf*: PSoundBuffer 
+  PSpriteSheet* = ref TSpriteSheet
+  TSpriteSheet* = object 
+    file*: string
+    framew*,frameh*: int
+    rows*, cols*: int
+    when defined(NoSFML):
+      contents*: TChecksumFile
+    when not defined(NoSFML):
+      sprite*: PSprite
+      tex*: PTexture
+  TGameState* = enum
+    Lobby, Transitioning, Field
+const
+  TAU* = PI * 2.0
+  MomentMult* = 0.62 ## global moment of inertia multiplier
+var 
+  cfg: PZoneSettings
+  SpriteSheets* = initTable[string, PSpriteSheet](64)
+  SoundCache  * = initTable[string, PSoundRecord](64)
+  nameToVehID*: TTable[string, int]
+  nameToItemID*: TTable[string, int]
+  nameToObjID*: TTable[string, int]
+  nameToBulletID*: TTable[string, int]
+  activeState = Lobby
+
+proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet
+proc load*(ss: PSpriteSheet): bool {.discardable.}
+proc newSound*(filename: string; errors: var seq[string]): PSoundRecord
+proc load*(s: PSoundRecord): bool {.discardable.}
+
+proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool
+proc loadSettings*(rawJson: string, errors: var seq[string]): bool
+proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool
+
+proc fetchVeh*(name: string): PVehicleRecord
+proc fetchItm*(itm: string): PItemRecord
+proc fetchObj*(name: string): PObjectRecord
+proc fetchBullet(name: string): PBulletRecord
+
+proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings
+proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord
+proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord
+proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord
+proc importPhys(data: PJsonNode): TPhysicsRecord
+proc importAnim(data: PJsonNode; errors: var seq[string]): PAnimationRecord
+proc importHandling(data: PJsonNode): THandlingRecord
+proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord
+proc importSoul(data: PJsonNode): TSoulRecord
+proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord
+proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
+
+## this is the only pipe between lobby and main.nim
+proc getActiveState*(): TGameState =
+  result = activeState
+proc transition*() = 
+  assert activeState == Lobby, "Transition() called from a state other than lobby!"
+  activeState = Transitioning
+proc doneWithSaidTransition*() =
+  assert activeState == Transitioning, "Finished() called from a state other than transitioning!"
+  activeState = Field
+
+
+proc checksumFile*(filename: string): TChecksumFile =
+  let fullText = readFile(filename)
+  result.unpackedSize = fullText.len
+  result.sum = toMD5(fullText)
+  result.compressed = compress(fullText)
+proc checksumStr*(str: string): TChecksumFile =
+  result.unpackedSize = str.len
+  result.sum = toMD5(str)
+  result.compressed = compress(str)
+
+
+##at this point none of these should ever be freed
+proc free*(obj: PZoneSettings) =
+  echo "Free'd zone settings"
+proc free*(obj: PSpriteSheet) =
+  echo "Free'd ", obj.file
+proc free*(obj: PSoundRecord) =
+  echo "Free'd ", obj.file
+
+proc loadAllAssets*() =
+  var 
+    loaded = 0
+    failed = 0
+  for name, ss in SpriteSheets.pairs():
+    if load(ss):
+      inc loaded
+    else:
+      inc failed
+  echo loaded," sprites loaded. ", failed, " sprites failed."
+  loaded = 0
+  failed = 0
+  for name, s in SoundCache.pairs():
+    if load(s):
+      inc loaded
+    else:
+      inc failed
+  echo loaded, " sounds loaded. ", failed, " sounds failed."
+proc getLevelSettings*(): PLevelSettings =
+  result = cfg.levelSettings
+
+iterator playableVehicles*(): PVehicleRecord =
+  for v in cfg.vehicles.items():
+    if v.playable:
+      yield v
+
+template allAssets*(body: stmt) {.dirty.}=
+  block: 
+    var assetType = FGraphics
+    for file, asset in pairs(SpriteSheets):
+      body
+    assetType = FSound
+    for file, asset in pairs(SoundCache):
+      body
+
+template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, immediate.} =
+  proc procName*(filename: string; errors: var seq[string]): resulttype =
+    if hasKey(cacheName, filename):
+      return cacheName[filename]
+    new(result, free)
+    body
+    cacheName[filename] = result
+
+template checkFile(path: expr): stmt {.dirty, immediate.} =
+  if not existsFile(path):
+    errors.add("File missing: "& path)
+
+cacheImpl newSprite, SpriteSheets, PSpriteSheet:
+  result.file = filename
+  if filename =~ re"\S+_(\d+)x(\d+)\.\S\S\S":
+    result.framew = strutils.parseInt(matches[0])
+    result.frameh = strutils.parseInt(matches[1])
+    checkFile("data/gfx"/result.file)  
+  else:
+    errors.add "Bad file: "&filename&" must be in format name_WxH.png"
+    return
+
+cacheImpl newSound, SoundCache, PSoundRecord:
+  result.file = filename
+  checkFile("data/sfx"/result.file)
+
+proc expandPath*(assetType: TAssetType; fileName: string): string =
+  result = "data/"
+  case assetType
+  of FGraphics: result.add "gfx/"
+  of FSound:    result.add "sfx/"
+  else: nil
+  result.add fileName
+proc expandPath*(fc: ScFileChallenge): string {.inline.} =
+  result = expandPath(fc.assetType, fc.file)
+
+when defined(NoSFML):
+  proc load*(ss: PSpriteSheet): bool =
+    if not ss.contents.unpackedSize == 0: return
+    ss.contents = checksumFile(expandPath(FGraphics, ss.file))
+    result = true
+  proc load*(s: PSoundRecord): bool =
+    if not s.contents.unpackedSize == 0: return
+    s.contents = checksumFile(expandPath(FSound, s.file))
+    result = true
+else:
+  proc load*(ss: PSpriteSheet): bool =
+    if not ss.sprite.isNil: 
+      return
+    var image = sfml.newImage("data/gfx/"/ss.file)
+    if image == nil:
+      echo "Image could not be loaded"
+      return
+    let size = image.getSize()
+    ss.rows = int(size.y / ss.frameh) #y is h
+    ss.cols = int(size.x / ss.framew) #x is w
+    ss.tex = newTexture(image)
+    image.destroy()
+    ss.sprite = newSprite()
+    ss.sprite.setTexture(ss.tex, true)
+    ss.sprite.setTextureRect(intrect(0, 0, ss.framew.cint, ss.frameh.cint))
+    ss.sprite.setOrigin(vec2f(ss.framew / 2, ss.frameh / 2))
+    result = true
+  proc load*(s: PSoundRecord): bool =
+    s.soundBuf = newSoundBuffer("data/sfx"/s.file)
+    if not s.soundBuf.isNil:
+      result = true
+
+template addError(e: expr): stmt {.immediate.} =
+  errors.add(e)
+  result = false
+proc validateSettings*(settings: PJsonNode, errors: var seq[string]): bool =
+  result = true
+  if settings.kind != JObject:
+    addError("Settings root must be an object")
+    return
+  if not settings.hasKey("vehicles"):
+    addError("Vehicles section missing")
+  if not settings.hasKey("objects"):
+    errors.add("Objects section is missing")
+    result = false
+  if not settings.hasKey("level"):
+    errors.add("Level settings section is missing")
+    result = false
+  else:
+    let lvl = settings["level"]
+    if lvl.kind != JObject or not lvl.hasKey("size"):
+      errors.add("Invalid level settings")
+      result = false
+    elif not lvl.hasKey("size") or lvl["size"].kind != JArray or lvl["size"].len != 2:
+      errors.add("Invalid/missing level size")
+      result = false
+  if not settings.hasKey("items"):
+    errors.add("Items section missing")
+    result = false
+  else:
+    let items = settings["items"]
+    if items.kind != JArray or items.len == 0:
+      errors.add "Invalid or empty item list"
+    else:
+      var id = 0
+      for i in items.items:
+        if i.kind != JArray: errors.add("Item #$1 is not an array"% $id)
+        elif i.len != 3: errors.add("($1) Item record should have 3 fields"%($id))
+        elif i[0].kind != JString or i[1].kind != JString or i[2].kind != JObject:
+          errors.add("($1) Item should be in form [name, type, {item: data}]"% $id)
+          result = false
+        inc id
+
+proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool =
+  if not existsFile(filename):
+    errors.add("File does not exist: "&filename)
+  else:
+    result = loadSettings(readFile(filename), errors)
+
+proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
+  var settings: PJsonNode
+  try:
+    settings = parseJson(rawJson)
+  except EJsonParsingError:
+    errors.add("JSON parsing error: "& getCurrentExceptionMsg())
+    return
+  except: 
+    errors.add("Unknown exception: "& getCurrentExceptionMsg())
+    return
+  if not validateSettings(settings, errors):
+    return
+  if cfg != nil: #TODO try this
+    echo("Overwriting zone settings")
+    free(cfg)
+    cfg = nil
+  new(cfg, free)
+  cfg.levelSettings = importLevel(settings, errors)
+  cfg.vehicles = @[]
+  cfg.items = @[]
+  cfg.objects = @[]
+  cfg.bullets = @[]
+  nameToVehID = initTable[string, int](32)
+  nameToItemID = initTable[string, int](32)
+  nameToObjID = initTable[string, int](32)
+  nameToBulletID = initTable[string, int](32)
+  var 
+    vID = 0'i16
+    bID = 0'i16
+  for vehicle in settings["vehicles"].items:
+    var veh = importVeh(vehicle, errors)
+    veh.id = vID
+    cfg.vehicles.add veh
+    nameToVehID[veh.name] = veh.id
+    inc vID
+  vID = 0
+  if settings.hasKey("bullets"):
+    for blt in settings["bullets"].items:
+      var bullet = importBullet(blt, errors)
+      bullet.id = bID
+      cfg.bullets.add bullet
+      nameToBulletID[bullet.name] = bullet.id
+      inc bID
+  for item in settings["items"].items:
+    var itm = importItem(item, errors)
+    itm.id = vID
+    cfg.items.add itm
+    nameToItemID[itm.name] = itm.id
+    inc vID
+    if itm.kind == Projectile:
+      if itm.bullet.isNil:
+        errors.add("Projectile #$1 has no bullet!"% $vID)
+      elif itm.bullet.id == -1:
+        ## this item has an anonymous bullet, fix the ID and name
+        itm.bullet.id = bID 
+        itm.bullet.name = itm.name
+        cfg.bullets.add itm.bullet
+        nameToBulletID[itm.bullet.name] = itm.bullet.id
+        inc bID
+  vID = 0
+  for obj in settings["objects"].items:
+    var o = importObject(obj, errors)
+    o.id = vID
+    cfg.objects.add o
+    nameToObjID[o.name] = o.id
+    inc vID
+  result = (errors.len == 0)
+
+proc `$`*(obj: PSpriteSheet): string =
+  return "<Sprite $1 ($2x$3) $4 rows $5 cols>" % [obj.file, $obj.framew, $obj.frameh, $obj.rows, $obj.cols]
+
+proc fetchVeh*(name: string): PVehicleRecord =
+  return cfg.vehicles[nameToVehID[name]]
+proc fetchItm*(itm: string): PItemRecord =
+  return cfg.items[nameToItemID[itm]]
+proc fetchObj*(name: string): PObjectRecord =
+  return cfg.objects[nameToObjID[name]]
+proc fetchBullet(name: string): PBulletRecord =
+  return cfg.bullets[nameToBulletID[name]]
+
+proc getField(node: PJsonNode, field: string, target: var float) =
+  if not node.hasKey(field):
+    return
+  if node[field].kind == JFloat:
+    target = node[field].fnum
+  elif node[field].kind == JInt:
+    target = node[field].num.float
+proc getField(node: PJsonNode, field: string, target: var int) =
+  if not node.hasKey(field):
+    return
+  if node[field].kind == JInt:
+    target = node[field].num.int
+  elif node[field].kind == JFloat:
+    target = node[field].fnum.int
+proc getField(node: PJsonNode; field: string; target: var bool) =
+  if not node.hasKey(field):
+    return
+  case node[field].kind
+  of JBool:
+    target = node[field].bval
+  of JInt:
+    target = (node[field].num != 0)
+  of JFloat:
+    target = (node[field].fnum != 0.0)
+  else: nil
+
+template checkKey(node: expr; key: string): stmt =
+  if not hasKey(node, key):
+    return
+
+proc importTrail(data: PJsonNode; errors: var seq[string]): TTrailRecord =
+  checkKey(data, "trail")
+  result.anim = importAnim(data["trail"], errors)
+  result.timer = 1000.0
+  getField(data["trail"], "timer", result.timer)
+  result.timer /= 1000.0
+proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings =
+  new(result)
+  result.size = vec2i(5000, 5000)
+  result.starfield = @[]
+  
+  checkKey(data, "level")
+  var level = data["level"]
+  if level.hasKey("size") and level["size"].kind == JArray and level["size"].len == 2:
+    result.size.x = level["size"][0].num.cint
+    result.size.y = level["size"][1].num.cint
+  if level.hasKey("starfield"):
+    for star in level["starfield"].items:
+      result.starfield.add(newSprite(star.str, errors))
+proc importPhys(data: PJsonNode): TPhysicsRecord =
+  result.radius = 20.0
+  result.mass = 10.0
+  
+  if data.hasKey("physics") and data["physics"].kind == JObject:
+    let phys = data["physics"]
+    phys.getField("radius", result.radius)
+    phys.getField("mass", result.mass)
+  when not defined(NoChipmunk):
+    result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult
+proc importHandling(data: PJsonNode): THandlingRecord =
+  result.thrust = 45.0
+  result.topSpeed = 100.0 #unused
+  result.reverse = 30.0
+  result.strafe = 30.0
+  result.rotation = 2200.0
+  
+  checkKey(data, "handling")
+  if data["handling"].kind != JObject:
+    return
+  
+  let hand = data["handling"]
+  hand.getField("thrust", result.thrust)
+  hand.getField("top_speed", result.topSpeed)
+  hand.getField("reverse", result.reverse)
+  hand.getField("strafe", result.strafe)
+  hand.getField("rotation", result.rotation)
+proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord =
+  new(result)
+  result.angle = 0.0
+  result.delay = 1000.0
+  result.spriteSheet = nil
+  
+  if data.hasKey("anim"):
+    let anim = data["anim"]
+    if anim.kind == JObject:
+      if anim.hasKey("file"):
+        result.spriteSheet = newSprite(anim["file"].str, errors)
+      
+      anim.getField "angle", result.angle
+      anim.getField "delay", result.delay
+    elif data["anim"].kind == JString:
+      result.spriteSheet = newSprite(anim.str, errors)
+  
+  result.angle = radians(result.angle) ## comes in as degrees 
+  result.delay /= 1000 ## delay comes in as milliseconds
+proc importSoul(data: PJsonNode): TSoulRecord =
+  result.energy = 10000
+  result.health = 1
+  checkKey(data, "soul")
+  let soul = data["soul"]
+  soul.getField("energy", result.energy)
+  soul.getField("health", result.health)
+proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord =
+  checkKey(data, "explode")
+  let expl = data["explode"]
+  result.anim = importAnim(expl, errors)
+  result.sound = importSound(expl, errors, "sound")
+proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord =
+  if data.kind == JObject:
+    checkKey(data, fieldName)
+    result = newSound(data[fieldName].str, errors)
+  elif data.kind == JString:
+    result = newSound(data.str, errors)
+
+proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord =
+  new(result)
+  result.playable = false
+  if data.kind != JArray or data.len != 2 or 
+    (data.kind == JArray and 
+      (data[0].kind != JString or data[1].kind != JObject)):
+    result.name = "(broken)"
+    errors.add "Vehicle record is malformed"
+    return
+  var vehData = data[1]
+  result.name = data[0].str
+  result.anim = importAnim(vehdata, errors)
+  result.physics = importPhys(vehdata)
+  result.handling = importHandling(vehdata)
+  vehdata.getField("playable", result.playable)
+  if result.anim.spriteSheet.isNil and result.playable:
+    result.playable = false
+proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord =
+  new(result)
+  if data.kind != JArray or data.len != 2:
+    result.name = "(broken)"
+    return
+  result.name = data[0].str
+  result.anim = importAnim(data[1], errors)
+  result.physics = importPhys(data[1])
+proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
+  new(result)
+  if data.kind != JArray or data.len != 3:
+    result.name = "(broken)"
+    errors.add "Item record is malformed"
+    return
+  result.name = data[0].str
+  result.anim = importAnim(data[2], errors)
+  result.physics = importPhys(data[2])
+  
+  result.cooldown = 100.0 
+  data[2].getField("cooldown", result.cooldown)
+  result.cooldown /= 1000.0  ##cooldown is stored in ms 
+  
+  result.useSound = importSound(data[2], errors, "useSound")
+  
+  case data[1].str.toLower
+  of "projectile":
+    result.kind = Projectile
+    if data[2]["bullet"].kind == JString:
+      result.bullet = fetchBullet(data[2]["bullet"].str)
+    elif data[2]["bullet"].kind == JInt:
+      result.bullet = cfg.bullets[data[2]["bullet"].num.int]
+    elif data[2]["bullet"].kind == JObject: 
+      result.bullet = importBullet(data[2]["bullet"], errors)
+    else:
+      errors.add "UNKNOWN BULLET TYPE for item "& result.name
+  of "ammo":
+    result.kind = Ammo
+  of "utility":
+    nil
+  else:
+    errors.add "Invalid item type \""& data[1].str &"\" for item "& result.name
+
+proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord =
+  new(result)
+  result.id = -1
+  
+  var bdata: PJsonNode
+  if data.kind == JArray:
+    result.name = data[0].str
+    bdata = data[1]
+  elif data.kind == JObject:
+    bdata = data
+  else: 
+    errors.add "Malformed bullet record"
+    return
+  
+  result.anim = importAnim(bdata, errors)
+  result.physics = importPhys(bdata)
+  
+  result.lifetime = 2000.0
+  result.inheritVelocity = 1000.0
+  result.baseVelocity = 30.0
+  getField(bdata, "lifetime", result.lifetime)
+  getField(bdata, "inheritVelocity", result.inheritVelocity)
+  getField(bdata, "baseVelocity", result.baseVelocity)
+  result.lifetime /= 1000.0 ## lifetime is stored as milliseconds
+  result.inheritVelocity /= 1000.0 ## inherit velocity 1000 = 1.0 (100%)
+  result.explosion = importExplosion(bdata, errors)
+  result.trail = importTrail(bdata, errors)
diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim
new file mode 100644
index 000000000..6741fe55e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_gui.nim
@@ -0,0 +1,281 @@
+import
+  sfml, sfml_colors, 
+  input_helpers, sg_packets
+from strutils import countlines
+{.deadCodeElim: on.}
+type
+  PGuiContainer* = ref TGuiContainer
+  TGuiContainer* = object of TObject
+    position: TVector2f
+    activeEntry: PTextEntry
+    widgets: seq[PGuiObject]
+    buttons: seq[PButton]
+  PGuiObject* = ref TGuiObject
+  TGuiObject* = object of TObject
+  PButton* = ref TButton
+  TButton* = object of TGuiObject
+    enabled: bool
+    bg*: sfml.PRectangleShape
+    text*: PText
+    onClick*: TButtonClicked
+    bounds: TFloatRect
+  PButtonCollection* = ref TButtonCollection
+  TButtonCollection* = object of TGuiContainer
+  PTextEntry* = ref TTextEntry
+  TTextEntry* = object of TButton
+    inputClient: input_helpers.PTextInput
+  PMessageArea* = ref TMessageArea
+  TMessageArea* = object of TGuiObject
+    pos: TVector2f
+    messages: seq[TMessage]
+    texts: seq[PText]
+    scrollBack*: int
+    sizeVisible*: int
+    direction*: int
+  TMessage = object
+    color: TColor
+    text: string
+    lines: int
+  TButtonClicked = proc(button: PButton)
+var
+  guiFont* = newFont("data/fnt/LiberationMono-Regular.ttf")
+  messageProto* = newText("", guiFont, 16)
+let
+  vectorZeroF* = vec2f(0.0, 0.0)
+
+proc newGuiContainer*(): PGuiContainer
+proc newGuiContainer*(pos: TVector2f): PGuiContainer {.inline.}
+proc free*(container: PGuiContainer)
+proc add*(container: PGuiContainer; widget: PGuiObject)
+proc clearButtons*(container: PGuiContainer)
+proc click*(container: PGuiContainer; position: TVector2f)
+proc setActive*(container: PGuiContainer; entry: PTextEntry)
+proc setPosition*(container: PGuiContainer; position: TVector2f)
+
+proc update*(container: PGuiContainer; dt: float)
+proc draw*(window: PRenderWindow; container: PGuiContainer) {.inline.}
+
+proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea {.discardable.}
+proc add*(m: PMessageArea; msg: ScChat)
+
+proc draw*(window: PRenderWindow; b: PButton) {.inline.}
+proc click*(b: PButton; p: TVector2f)
+proc setPosition*(b: PButton; p: TVector2f)
+proc setString*(b: PButton; s: string) {.inline.}
+
+proc newButton*(container: PGuiContainer; text: string; position: TVector2f; 
+  onClick: TButtonClicked; startEnabled: bool = true): PButton {.discardable.}
+proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked)
+proc setEnabled*(b: PButton; enabled: bool)
+proc disable*(b: PButton) {.inline.}
+proc enable*(b: PButton) {.inline.}
+
+proc newTextEntry*(container: PGuiContainer; text: string;
+                    position: TVector2f; onEnter: TInputFinishedProc = nil): PTextEntry {.discardable.}
+proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc)
+proc draw*(window: PRenderWindow, t: PTextEntry) {.inline.}
+proc setActive*(t: PTextEntry) {.inline.}
+proc clearText*(t: PTextEntry) {.inline.}
+proc getText*(t: PTextEntry): string {.inline.}
+
+proc update*(m: PMessageArea)
+
+if guiFont == nil:
+  echo("Could not load font, crying softly to myself.")
+  quit(1)
+
+proc newGuiContainer*(): PGuiContainer =
+  new(result, free)
+  result.widgets = @[]
+  result.buttons = @[]
+proc newGuiContainer*(pos: TVector2f): PGuiContainer =
+  result = newGuiContainer()
+  result.setPosition pos
+proc free*(container: PGuiContainer) = 
+  container.widgets = nil
+  container.buttons = nil
+proc add*(container: PGuiContainer; widget: PGuiObject) =
+  container.widgets.add(widget)
+proc add*(container: PGuiContainer; button: PButton) =
+  if container.isNil: return
+  container.buttons.add(button)
+proc clearButtons*(container: PGuiContainer) =
+  container.buttons.setLen 0
+proc click*(container: PGuiContainer; position: TVector2f) =
+  for b in container.buttons:
+    click(b, position)
+proc setActive*(container: PGuiContainer; entry: PTextEntry) =
+  container.activeEntry = entry
+  setActive(entry)
+proc setPosition*(container: PGuiContainer; position: TVector2f) =
+  container.position = position
+
+
+proc update*(container: PGuiContainer; dt: float) =
+  if not container.activeEntry.isNil:
+    container.activeEntry.setString(container.activeEntry.getText())
+proc draw*(window: PRenderWindow; container: PGuiContainer) =
+  for b in container.buttons:
+    window.draw b
+
+proc free(c: PButton) =
+  c.bg.destroy()
+  c.text.destroy()
+  c.bg = nil
+  c.text = nil
+  c.onClick = nil
+proc newButton*(container: PGuiContainer; text: string;
+                 position: TVector2f; onClick: TButtonClicked;
+                 startEnabled: bool = true): PButton =
+  new(result, free)
+  init(result, 
+       text, 
+       if not container.isNil: position + container.position else: position, 
+       onClick)
+  container.add result
+  if not startEnabled: disable(result)
+
+proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked) =
+  b.bg = newRectangleShape()
+  b.bg.setSize(vec2f(80.0, 16.0))
+  b.bg.setFillColor(color(20, 30, 15))
+  b.text = newText(text, guiFont, 16)
+  b.onClick = onClick
+  b.setPosition(position)
+  b.enabled = true
+proc copy*(c: PButton): PButton =
+  new(result, free)
+  result.bg = c.bg.copy()
+  result.text = c.text.copy()
+  result.onClick = c.onClick
+  result.setPosition(result.bg.getPosition())
+
+proc setEnabled*(b: PButton; enabled: bool) =
+  b.enabled = enabled
+  if enabled:
+    b.text.setColor(White)
+  else:
+    b.text.setColor(Gray)
+proc enable*(b: PButton) = setEnabled(b, true)
+proc disable*(b: PButton) = setEnabled(b, false)
+
+proc draw*(window: PRenderWindow; b: PButton) =
+  window.draw b.bg
+  window.draw b.text
+proc setPosition*(b: PButton, p: TVector2f) =
+  b.bg.setPosition(p)
+  b.text.setPosition(p)
+  b.bounds = b.text.getGlobalBounds()
+proc setString*(b: PButton; s: string) =
+  b.text.setString(s)
+proc click*(b: PButton, p: TVector2f) = 
+  if b.enabled and (addr b.bounds).contains(p.x, p.y): 
+    b.onClick(b)
+
+proc free(obj: PTextEntry) =
+  free(PButton(obj))
+proc newTextEntry*(container: PGuiContainer; text: string; 
+                    position: TVector2F; onEnter: TInputFinishedProc = nil): PTextEntry =
+  new(result, free)
+  init(PButton(result), text, position + container.position, proc(b: PButton) =
+    setActive(container, PTextEntry(b)))
+  init(result, text, onEnter)
+  container.add result
+proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc) =
+  t.inputClient = newTextInput(text, text.len, onEnter)
+proc draw(window: PRenderWindow; t: PTextEntry) =
+  window.draw PButton(t)
+proc clearText*(t: PTextEntry) =
+  t.inputClient.clear()
+proc getText*(t: PTextEntry): string =
+  return t.inputClient.text
+proc setActive*(t: PTextEntry) =
+  if not t.isNil and not t.inputClient.isNil:
+    input_helpers.setActive(t.inputClient)
+
+
+discard """proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea =
+  new(result)
+  result.messages = @[]
+  result.pos = position
+  container.add(result)
+proc add*(m: PMessageArea, text: string): PText =
+  result = messageProto.copy()
+  result.setString(text)
+  m.messages.add(result)
+  let nmsgs = len(m.messages)
+  var pos   = vec2f(m.pos.x, m.pos.y)
+  for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)):
+    setPosition(m.messages[i], pos)
+    pos.y -= 16.0
+
+proc draw*(window: PRenderWindow; m: PMessageArea) =
+  let nmsgs = len(m.messages) 
+  if nmsgs == 0: return
+  for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)):
+    window.draw(m.messages[i])
+"""
+proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea =
+  new(result)
+  result.messages = @[]
+  result.texts = @[]
+  result.pos = position + container.position
+  result.sizeVisible = 10
+  result.scrollBack = 0
+  result.direction = -1 ## to push old messages up
+  container.add(result)
+  
+proc add*(m: PMessageArea, msg: ScChat) =
+  const prependName = {CPub, CPriv}
+  var mmm: TMessage
+  if msg.kind in prependName: 
+    mmm.text = "<"
+    mmm.text.add msg.fromPlayer
+    mmm.text.add "> "
+    mmm.text.add msg.text
+  else:
+    mmm.text = msg.text
+  case msg.kind
+  of CPub:  mmm.color = RoyalBlue
+  of CPriv, CSystem: mmm.color = Green
+  of CError: mmm.color = Red
+  
+  mmm.lines = countLines(mmm.text)+1
+  
+  m.messages.add mmm
+  update m
+proc add*(m: PMessageArea, msg: string) {.inline.} =
+  var chat = newScChat(kind = CSystem, text = msg)
+  add(m, chat)
+
+proc proctor*(m: PText; msg: ptr TMessage; pos: ptr TVector2f) =
+  m.setString msg.text 
+  m.setColor msg.color
+  m.setPosition pos[]
+proc update*(m: PMessageArea) =
+  if m.texts.len < m.sizeVisible:
+    echo "adding ", m.sizeVisible - m.texts.len, " fields"
+    for i in 1..m.sizeVisible - m.texts.len:
+      var t = messageProto.copy()
+      m.texts.add messageProto.copy()
+  elif m.texts.len > m.sizeVisible:
+    echo "cutting ", m.texts.len - m.sizeVisible, " fields"
+    for i in m.sizeVisible.. < m.texts.len:
+      m.texts.pop().destroy()
+  let nmsgs = m.messages.len()
+  if m.sizeVisible == 0 or nmsgs == 0: 
+    echo "no messages? ", m.sizeVisible, ", ", nmsgs
+    return
+  var pos = vec2f(m.pos.x, m.pos.y)
+  for i in 0.. min(m.sizeVisible, nmsgs)-1:
+    ##echo nmsgs - i - 1 - m.scrollBack
+    let msg = addr m.messages[nmsgs - i - 1 - m.scrollBack]
+    proctor(m.texts[i], msg, addr pos)
+    pos.y += (16 * m.direction * msg.lines).cfloat  
+
+proc draw*(window: PRenderWindow; m: PMessageArea) =
+  let nmsgs = len(m.texts)
+  if nmsgs == 0: return
+  for i in countdown(nmsgs - 1, max(nmsgs - m.sizeVisible, 0)):
+    window.draw m.texts[i]
+
diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim
new file mode 100644
index 000000000..601054b47
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_packets.nim
@@ -0,0 +1,108 @@
+import genpacket_enet, sockets, md5, enet
+defPacketImports()
+
+type
+  PacketID* = char
+
+template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} =
+  let `H pktName`* {.inject.} = id
+  defPacket(`Sc pktName`, s2c)
+  defPacket(`Cs pktName`, c2s)
+
+forwardPacketT(uint8, int8)
+forwardPacketT(uint16, int16)
+forwardPacketT(TPort, int16)
+
+idPacket(Login, 'a',
+  tuple[id: int32; alias: string; sessionKey: string],
+  tuple[alias: string, passwd: string])
+
+let HZoneJoinReq* = 'j'
+defPacket(CsZoneJoinReq, tuple[session: ScLogin])
+
+defPacket(ScZoneRecord, tuple[
+  name: string = "", desc: string = "",
+  ip: string = "", port: TPort = 0.Tport])
+idPacket(ZoneList, 'z',
+  tuple[network: string = "", zones: seq[ScZoneRecord]],
+  tuple[time: string])
+
+let HPoing* = 'p'
+defPacket(Poing, tuple[id: int32, time: float32])
+
+type ChatType* = enum
+  CPub = 0'i8, CPriv, CSystem, CError
+forwardPacketT(ChatType, int8)
+idPacket(Chat, 'C', 
+  tuple[kind: ChatType = CPub; fromPlayer: string = ""; text: string = ""],
+  tuple[target: string = ""; text: string = ""])
+
+idPacket(Hello, 'h',
+  tuple[resp: string],
+  tuple[i: int8 = 14])
+
+let HPlayerList* = 'P'
+defPacket(ScPlayerRec, tuple[id: int32; alias: string = ""])
+defPacket(ScPlayerList, tuple[players: seq[ScPlayerRec]])
+
+let HTeamList* = 'T'
+defPacket(ScTeam, tuple[id: int8; name: string = ""])
+defPacket(ScTeamList, tuple[teams: seq[ScTeam]])
+let HTeamChange* = 't'
+
+idPacket(ZoneQuery, 'Q',
+  tuple[playerCount: uint16], ##i should include a time here or something
+  tuple[pad: char = '\0'])
+
+type SpawnKind = enum
+  SpawnDummy,
+  SpawnItem, SpawnVehicle, SpawnObject
+forwardPacketT(SpawnKind, int8)
+defPacket(ScSpawn, tuple[
+  kind: SpawnKind; id: uint16; record: uint16; amount: uint16])
+
+
+
+
+type TAssetType* = enum
+  FDummy, 
+  FZoneCfg, FGraphics, FSound 
+
+forwardPacketT(TAssetType, int8)
+forwardPacket(MD5Digest, array[0..15, int8])
+
+idPacket(FileChallenge, 'F',
+  tuple[file: string; assetType: TAssetType; fullLen: int32],
+  tuple[needFile: bool; checksum: MD5Digest])
+
+
+let HChallengeResult* = '('
+defPacket(ScChallengeResult, tuple[status: bool])
+
+let HFileTransfer* = 'f'
+defPacket(ScFileTransfer, tuple[fileSize: int32; pos: int32; data: string])
+defPacket(CsFilepartAck, tuple[lastpos: int32])
+
+##dir server messages
+let HZoneLogin* = 'u'
+defPacket(SdZoneLogin, tuple[name: string; key: string; record: ScZoneRecord])
+defPacket(DsZoneLogin, tuple[status: bool])
+let HDsMsg* = 'c'
+defPacket(DsMsg, tuple[msg: string])
+let HVerifyClient* = 'v'
+defPacket(SdVerifyClient, tuple[session: ScLogin])
+
+when isMainModule:
+  
+  var buf = newBuffer(100)
+  var m = toMd5("hello there")
+  echo(repr(m))
+  buf.pack m
+
+  echo(repr(buf.data))
+  echo(len(buf.data))
+  
+  buf.reset()
+
+  var x = buf.readMD5Digest()
+  echo(repr(x))
diff --git a/tests/manyloc/keineschweine/lib/sound_buffer.nim b/tests/manyloc/keineschweine/lib/sound_buffer.nim
new file mode 100644
index 000000000..a88eb08de
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sound_buffer.nim
@@ -0,0 +1,38 @@
+when defined(NoSFML) or defined(NoChipmunk):
+  {.error.}
+import sfml_audio, sfml_stuff, sg_assets, chipmunk
+const
+  MinDistance* = 350.0
+  Attenuation* = 20.0
+var
+  liveSounds: seq[PSound] = @[]
+  deadSounds: seq[PSound] = @[]
+
+proc playSound*(sound: PSoundRecord, pos: TVector) =
+  if sound.isNil or sound.soundBuf.isNil: return
+  var s: PSound
+  if deadSounds.len == 0:
+    s = sfml_audio.newSound()
+    s.setLoop false
+    s.setRelativeToListener true
+    s.setAttenuation Attenuation
+    s.setMinDistance MinDistance
+  else:
+    s = deadSounds.pop()
+  s.setPosition(vec3f(pos.x, 0, pos.y))
+  s.setBuffer(sound.soundBuf)
+  s.play()
+  liveSounds.add s
+
+proc updateSoundBuffer*() =
+  var i = 0
+  while i < len(liveSounds):
+    if liveSounds[i].getStatus == Stopped:
+      deadSounds.add liveSounds[i]
+      liveSounds.del i
+    else:
+      inc i
+
+proc report*() =
+  echo "live: ", liveSounds.len
+  echo "dead: ", deadSounds.len
diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim
new file mode 100644
index 000000000..4b11856c6
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/vehicles.nim
@@ -0,0 +1,35 @@
+import
+  sfml, chipmunk, 
+  sg_assets, sfml_stuff, keineschweine
+
+
+proc accel*(obj: PVehicle, dt: float) =
+  #obj.velocity += vec2f(
+  #  cos(obj.angle) * obj.record.handling.thrust.float * dt,
+  #  sin(obj.angle) * obj.record.handling.thrust.float * dt)
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.thrust,
+    VectorZero)
+proc reverse*(obj: PVehicle, dt: float) =
+  #obj.velocity += vec2f(
+  #  -cos(obj.angle) * obj.record.handling.reverse.float * dt,
+  #  -sin(obj.angle) * obj.record.handling.reverse.float * dt)
+  obj.body.applyImpulse(
+    -vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.reverse,
+    VectorZero)
+proc strafe_left*(obj: PVehicle, dt: float) =
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()).perp() * obj.record.handling.strafe * dt,
+    VectorZero)
+proc strafe_right*(obj: PVehicle, dt: float) =
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()).rperp()* obj.record.handling.strafe * dt,
+    VectorZero)
+proc turn_right*(obj: PVehicle, dt: float) =
+  #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
+  obj.body.setTorque(obj.record.handling.rotation)
+proc turn_left*(obj: PVehicle, dt: float) =
+  #obj.angle = (obj.angle - (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
+  obj.body.setTorque(-obj.record.handling.rotation)
+proc offsetAngle*(obj: PVehicle): float {.inline.} =
+  return (obj.record.anim.angle + obj.body.getAngle())
diff --git a/tests/manyloc/keineschweine/lib/wingl.nim b/tests/manyloc/keineschweine/lib/wingl.nim
new file mode 100644
index 000000000..7ed78f970
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/wingl.nim
@@ -0,0 +1,368 @@
+import 
+  gl, windows
+
+proc wglGetExtensionsStringARB*(hdc: HDC): cstring{.dynlib: dllname, 
+    importc: "wglGetExtensionsStringARB".}
+const 
+  WGL_FRONT_COLOR_BUFFER_BIT_ARB* = 0x00000001
+  WGL_BACK_COLOR_BUFFER_BIT_ARB* = 0x00000002
+  WGL_DEPTH_BUFFER_BIT_ARB* = 0x00000004
+  WGL_STENCIL_BUFFER_BIT_ARB* = 0x00000008
+
+proc WinChoosePixelFormat*(DC: HDC, p2: PPixelFormatDescriptor): int{.
+    dynlib: "gdi32", importc: "ChoosePixelFormat".}
+proc wglCreateBufferRegionARB*(hDC: HDC, iLayerPlane: TGLint, uType: TGLuint): THandle{.
+    dynlib: dllname, importc: "wglCreateBufferRegionARB".}
+proc wglDeleteBufferRegionARB*(hRegion: THandle){.dynlib: dllname, 
+    importc: "wglDeleteBufferRegionARB".}
+proc wglSaveBufferRegionARB*(hRegion: THandle, x: TGLint, y: TGLint, 
+                             width: TGLint, height: TGLint): BOOL{.
+    dynlib: dllname, importc: "wglSaveBufferRegionARB".}
+proc wglRestoreBufferRegionARB*(hRegion: THandle, x: TGLint, y: TGLint, 
+                                width: TGLint, height: TGLint, xSrc: TGLint, 
+                                ySrc: TGLint): BOOL{.dynlib: dllname, 
+    importc: "wglRestoreBufferRegionARB".}
+proc wglAllocateMemoryNV*(size: TGLsizei, readFrequency: TGLfloat, 
+                          writeFrequency: TGLfloat, priority: TGLfloat): PGLvoid{.
+    dynlib: dllname, importc: "wglAllocateMemoryNV".}
+proc wglFreeMemoryNV*(pointer: PGLvoid){.dynlib: dllname, 
+    importc: "wglFreeMemoryNV".}
+const 
+  WGL_IMAGE_BUFFER_MIN_ACCESS_I3D* = 0x00000001
+  WGL_IMAGE_BUFFER_LOCK_I3D* = 0x00000002
+
+proc wglCreateImageBufferI3D*(hDC: HDC, dwSize: DWORD, uFlags: UINT): PGLvoid{.
+    dynlib: dllname, importc: "wglCreateImageBufferI3D".}
+proc wglDestroyImageBufferI3D*(hDC: HDC, pAddress: PGLvoid): BOOL{.
+    dynlib: dllname, importc: "wglDestroyImageBufferI3D".}
+proc wglAssociateImageBufferEventsI3D*(hdc: HDC, pEvent: PHandle, 
+                                       pAddress: PGLvoid, pSize: PDWORD, 
+                                       count: UINT): BOOL{.dynlib: dllname, 
+    importc: "wglAssociateImageBufferEventsI3D".}
+proc wglReleaseImageBufferEventsI3D*(hdc: HDC, pAddress: PGLvoid, count: UINT): BOOL{.
+    dynlib: dllname, importc: "wglReleaseImageBufferEventsI3D".}
+proc wglEnableFrameLockI3D*(): BOOL{.dynlib: dllname, 
+                                     importc: "wglEnableFrameLockI3D".}
+proc wglDisableFrameLockI3D*(): BOOL{.dynlib: dllname, 
+                                      importc: "wglDisableFrameLockI3D".}
+proc wglIsEnabledFrameLockI3D*(pFlag: PBOOL): BOOL{.dynlib: dllname, 
+    importc: "wglIsEnabledFrameLockI3D".}
+proc wglQueryFrameLockMasterI3D*(pFlag: PBOOL): BOOL{.dynlib: dllname, 
+    importc: "wglQueryFrameLockMasterI3D".}
+proc wglGetFrameUsageI3D*(pUsage: PGLfloat): BOOL{.dynlib: dllname, 
+    importc: "wglGetFrameUsageI3D".}
+proc wglBeginFrameTrackingI3D*(): BOOL{.dynlib: dllname, 
+                                        importc: "wglBeginFrameTrackingI3D".}
+proc wglEndFrameTrackingI3D*(): BOOL{.dynlib: dllname, 
+                                      importc: "wglEndFrameTrackingI3D".}
+proc wglQueryFrameTrackingI3D*(pFrameCount: PDWORD, pMissedFrames: PDWORD, 
+                               pLastMissedUsage: PGLfloat): BOOL{.
+    dynlib: dllname, importc: "wglQueryFrameTrackingI3D".}
+const 
+  WGL_NUMBER_PIXEL_FORMATS_ARB* = 0x00002000
+  WGL_DRAW_TO_WINDOW_ARB* = 0x00002001
+  WGL_DRAW_TO_BITMAP_ARB* = 0x00002002
+  WGL_ACCELERATION_ARB* = 0x00002003
+  WGL_NEED_PALETTE_ARB* = 0x00002004
+  WGL_NEED_SYSTEM_PALETTE_ARB* = 0x00002005
+  WGL_SWAP_LAYER_BUFFERS_ARB* = 0x00002006
+  WGL_SWAP_METHOD_ARB* = 0x00002007
+  WGL_NUMBER_OVERLAYS_ARB* = 0x00002008
+  WGL_NUMBER_UNDERLAYS_ARB* = 0x00002009
+  WGL_TRANSPARENT_ARB* = 0x0000200A
+  WGL_TRANSPARENT_RED_VALUE_ARB* = 0x00002037
+  WGL_TRANSPARENT_GREEN_VALUE_ARB* = 0x00002038
+  WGL_TRANSPARENT_BLUE_VALUE_ARB* = 0x00002039
+  WGL_TRANSPARENT_ALPHA_VALUE_ARB* = 0x0000203A
+  WGL_TRANSPARENT_INDEX_VALUE_ARB* = 0x0000203B
+  WGL_SHARE_DEPTH_ARB* = 0x0000200C
+  WGL_SHARE_STENCIL_ARB* = 0x0000200D
+  WGL_SHARE_ACCUM_ARB* = 0x0000200E
+  WGL_SUPPORT_GDI_ARB* = 0x0000200F
+  WGL_SUPPORT_OPENGL_ARB* = 0x00002010
+  WGL_DOUBLE_BUFFER_ARB* = 0x00002011
+  WGL_STEREO_ARB* = 0x00002012
+  WGL_PIXEL_TYPE_ARB* = 0x00002013
+  WGL_COLOR_BITS_ARB* = 0x00002014
+  WGL_RED_BITS_ARB* = 0x00002015
+  WGL_RED_SHIFT_ARB* = 0x00002016
+  WGL_GREEN_BITS_ARB* = 0x00002017
+  WGL_GREEN_SHIFT_ARB* = 0x00002018
+  WGL_BLUE_BITS_ARB* = 0x00002019
+  WGL_BLUE_SHIFT_ARB* = 0x0000201A
+  WGL_ALPHA_BITS_ARB* = 0x0000201B
+  WGL_ALPHA_SHIFT_ARB* = 0x0000201C
+  WGL_ACCUM_BITS_ARB* = 0x0000201D
+  WGL_ACCUM_RED_BITS_ARB* = 0x0000201E
+  WGL_ACCUM_GREEN_BITS_ARB* = 0x0000201F
+  WGL_ACCUM_BLUE_BITS_ARB* = 0x00002020
+  WGL_ACCUM_ALPHA_BITS_ARB* = 0x00002021
+  WGL_DEPTH_BITS_ARB* = 0x00002022
+  WGL_STENCIL_BITS_ARB* = 0x00002023
+  WGL_AUX_BUFFERS_ARB* = 0x00002024
+  WGL_NO_ACCELERATION_ARB* = 0x00002025
+  WGL_GENERIC_ACCELERATION_ARB* = 0x00002026
+  WGL_FULL_ACCELERATION_ARB* = 0x00002027
+  WGL_SWAP_EXCHANGE_ARB* = 0x00002028
+  WGL_SWAP_COPY_ARB* = 0x00002029
+  WGL_SWAP_UNDEFINED_ARB* = 0x0000202A
+  WGL_TYPE_RGBA_ARB* = 0x0000202B
+  WGL_TYPE_COLORINDEX_ARB* = 0x0000202C
+
+proc wglGetPixelFormatAttribivARB*(hdc: HDC, iPixelFormat: TGLint, 
+                                   iLayerPlane: TGLint, nAttributes: TGLuint, 
+                                   piAttributes: PGLint, piValues: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribivARB".}
+proc wglGetPixelFormatAttribfvARB*(hdc: HDC, iPixelFormat: TGLint, 
+                                   iLayerPlane: TGLint, nAttributes: TGLuint, 
+                                   piAttributes: PGLint, pfValues: PGLfloat): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribfvARB".}
+proc wglChoosePixelFormatARB*(hdc: HDC, piAttribIList: PGLint, 
+                              pfAttribFList: PGLfloat, nMaxFormats: TGLuint, 
+                              piFormats: PGLint, nNumFormats: PGLuint): BOOL{.
+    dynlib: dllname, importc: "wglChoosePixelFormatARB".}
+const 
+  WGL_ERROR_INVALID_PIXEL_TYPE_ARB* = 0x00002043
+  WGL_ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB* = 0x00002054
+
+proc wglMakeContextCurrentARB*(hDrawDC: HDC, hReadDC: HDC, hglrc: HGLRC): BOOL{.
+    dynlib: dllname, importc: "wglMakeContextCurrentARB".}
+proc wglGetCurrentReadDCARB*(): HDC{.dynlib: dllname, 
+                                     importc: "wglGetCurrentReadDCARB".}
+const 
+  WGL_DRAW_TO_PBUFFER_ARB* = 0x0000202D # WGL_DRAW_TO_PBUFFER_ARB  { already defined }
+  WGL_MAX_PBUFFER_PIXELS_ARB* = 0x0000202E
+  WGL_MAX_PBUFFER_WIDTH_ARB* = 0x0000202F
+  WGL_MAX_PBUFFER_HEIGHT_ARB* = 0x00002030
+  WGL_PBUFFER_LARGEST_ARB* = 0x00002033
+  WGL_PBUFFER_WIDTH_ARB* = 0x00002034
+  WGL_PBUFFER_HEIGHT_ARB* = 0x00002035
+  WGL_PBUFFER_LOST_ARB* = 0x00002036
+
+proc wglCreatePbufferARB*(hDC: HDC, iPixelFormat: TGLint, iWidth: TGLint, 
+                          iHeight: TGLint, piAttribList: PGLint): THandle{.
+    dynlib: dllname, importc: "wglCreatePbufferARB".}
+proc wglGetPbufferDCARB*(hPbuffer: THandle): HDC{.dynlib: dllname, 
+    importc: "wglGetPbufferDCARB".}
+proc wglReleasePbufferDCARB*(hPbuffer: THandle, hDC: HDC): TGLint{.
+    dynlib: dllname, importc: "wglReleasePbufferDCARB".}
+proc wglDestroyPbufferARB*(hPbuffer: THandle): BOOL{.dynlib: dllname, 
+    importc: "wglDestroyPbufferARB".}
+proc wglQueryPbufferARB*(hPbuffer: THandle, iAttribute: TGLint, piValue: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglQueryPbufferARB".}
+proc wglSwapIntervalEXT*(interval: TGLint): BOOL{.dynlib: dllname, 
+    importc: "wglSwapIntervalEXT".}
+proc wglGetSwapIntervalEXT*(): TGLint{.dynlib: dllname, 
+                                       importc: "wglGetSwapIntervalEXT".}
+const 
+  WGL_BIND_TO_TEXTURE_RGB_ARB* = 0x00002070
+  WGL_BIND_TO_TEXTURE_RGBA_ARB* = 0x00002071
+  WGL_TEXTURE_FORMAT_ARB* = 0x00002072
+  WGL_TEXTURE_TARGET_ARB* = 0x00002073
+  WGL_MIPMAP_TEXTURE_ARB* = 0x00002074
+  WGL_TEXTURE_RGB_ARB* = 0x00002075
+  WGL_TEXTURE_RGBA_ARB* = 0x00002076
+  WGL_NO_TEXTURE_ARB* = 0x00002077
+  WGL_TEXTURE_CUBE_MAP_ARB* = 0x00002078
+  WGL_TEXTURE_1D_ARB* = 0x00002079
+  WGL_TEXTURE_2D_ARB* = 0x0000207A # WGL_NO_TEXTURE_ARB  { already defined }
+  WGL_MIPMAP_LEVEL_ARB* = 0x0000207B
+  WGL_CUBE_MAP_FACE_ARB* = 0x0000207C
+  WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB* = 0x0000207D
+  WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB* = 0x0000207E
+  WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB* = 0x0000207F
+  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB* = 0x00002080
+  WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB* = 0x00002081
+  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB* = 0x00002082
+  WGL_FRONT_LEFT_ARB* = 0x00002083
+  WGL_FRONT_RIGHT_ARB* = 0x00002084
+  WGL_BACK_LEFT_ARB* = 0x00002085
+  WGL_BACK_RIGHT_ARB* = 0x00002086
+  WGL_AUX0_ARB* = 0x00002087
+  WGL_AUX1_ARB* = 0x00002088
+  WGL_AUX2_ARB* = 0x00002089
+  WGL_AUX3_ARB* = 0x0000208A
+  WGL_AUX4_ARB* = 0x0000208B
+  WGL_AUX5_ARB* = 0x0000208C
+  WGL_AUX6_ARB* = 0x0000208D
+  WGL_AUX7_ARB* = 0x0000208E
+  WGL_AUX8_ARB* = 0x0000208F
+  WGL_AUX9_ARB* = 0x00002090
+
+proc wglBindTexImageARB*(hPbuffer: THandle, iBuffer: TGLint): BOOL{.
+    dynlib: dllname, importc: "wglBindTexImageARB".}
+proc wglReleaseTexImageARB*(hPbuffer: THandle, iBuffer: TGLint): BOOL{.
+    dynlib: dllname, importc: "wglReleaseTexImageARB".}
+proc wglSetPbufferAttribARB*(hPbuffer: THandle, piAttribList: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglSetPbufferAttribARB".}
+proc wglGetExtensionsStringEXT*(): cstring{.dynlib: dllname, 
+    importc: "wglGetExtensionsStringEXT".}
+proc wglMakeContextCurrentEXT*(hDrawDC: HDC, hReadDC: HDC, hglrc: HGLRC): BOOL{.
+    dynlib: dllname, importc: "wglMakeContextCurrentEXT".}
+proc wglGetCurrentReadDCEXT*(): HDC{.dynlib: dllname, 
+                                     importc: "wglGetCurrentReadDCEXT".}
+const 
+  WGL_DRAW_TO_PBUFFER_EXT* = 0x0000202D
+  WGL_MAX_PBUFFER_PIXELS_EXT* = 0x0000202E
+  WGL_MAX_PBUFFER_WIDTH_EXT* = 0x0000202F
+  WGL_MAX_PBUFFER_HEIGHT_EXT* = 0x00002030
+  WGL_OPTIMAL_PBUFFER_WIDTH_EXT* = 0x00002031
+  WGL_OPTIMAL_PBUFFER_HEIGHT_EXT* = 0x00002032
+  WGL_PBUFFER_LARGEST_EXT* = 0x00002033
+  WGL_PBUFFER_WIDTH_EXT* = 0x00002034
+  WGL_PBUFFER_HEIGHT_EXT* = 0x00002035
+
+proc wglCreatePbufferEXT*(hDC: HDC, iPixelFormat: TGLint, iWidth: TGLint, 
+                          iHeight: TGLint, piAttribList: PGLint): THandle{.
+    dynlib: dllname, importc: "wglCreatePbufferEXT".}
+proc wglGetPbufferDCEXT*(hPbuffer: THandle): HDC{.dynlib: dllname, 
+    importc: "wglGetPbufferDCEXT".}
+proc wglReleasePbufferDCEXT*(hPbuffer: THandle, hDC: HDC): TGLint{.
+    dynlib: dllname, importc: "wglReleasePbufferDCEXT".}
+proc wglDestroyPbufferEXT*(hPbuffer: THandle): BOOL{.dynlib: dllname, 
+    importc: "wglDestroyPbufferEXT".}
+proc wglQueryPbufferEXT*(hPbuffer: THandle, iAttribute: TGLint, piValue: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglQueryPbufferEXT".}
+const 
+  WGL_NUMBER_PIXEL_FORMATS_EXT* = 0x00002000
+  WGL_DRAW_TO_WINDOW_EXT* = 0x00002001
+  WGL_DRAW_TO_BITMAP_EXT* = 0x00002002
+  WGL_ACCELERATION_EXT* = 0x00002003
+  WGL_NEED_PALETTE_EXT* = 0x00002004
+  WGL_NEED_SYSTEM_PALETTE_EXT* = 0x00002005
+  WGL_SWAP_LAYER_BUFFERS_EXT* = 0x00002006
+  WGL_SWAP_METHOD_EXT* = 0x00002007
+  WGL_NUMBER_OVERLAYS_EXT* = 0x00002008
+  WGL_NUMBER_UNDERLAYS_EXT* = 0x00002009
+  WGL_TRANSPARENT_EXT* = 0x0000200A
+  WGL_TRANSPARENT_VALUE_EXT* = 0x0000200B
+  WGL_SHARE_DEPTH_EXT* = 0x0000200C
+  WGL_SHARE_STENCIL_EXT* = 0x0000200D
+  WGL_SHARE_ACCUM_EXT* = 0x0000200E
+  WGL_SUPPORT_GDI_EXT* = 0x0000200F
+  WGL_SUPPORT_OPENGL_EXT* = 0x00002010
+  WGL_DOUBLE_BUFFER_EXT* = 0x00002011
+  WGL_STEREO_EXT* = 0x00002012
+  WGL_PIXEL_TYPE_EXT* = 0x00002013
+  WGL_COLOR_BITS_EXT* = 0x00002014
+  WGL_RED_BITS_EXT* = 0x00002015
+  WGL_RED_SHIFT_EXT* = 0x00002016
+  WGL_GREEN_BITS_EXT* = 0x00002017
+  WGL_GREEN_SHIFT_EXT* = 0x00002018
+  WGL_BLUE_BITS_EXT* = 0x00002019
+  WGL_BLUE_SHIFT_EXT* = 0x0000201A
+  WGL_ALPHA_BITS_EXT* = 0x0000201B
+  WGL_ALPHA_SHIFT_EXT* = 0x0000201C
+  WGL_ACCUM_BITS_EXT* = 0x0000201D
+  WGL_ACCUM_RED_BITS_EXT* = 0x0000201E
+  WGL_ACCUM_GREEN_BITS_EXT* = 0x0000201F
+  WGL_ACCUM_BLUE_BITS_EXT* = 0x00002020
+  WGL_ACCUM_ALPHA_BITS_EXT* = 0x00002021
+  WGL_DEPTH_BITS_EXT* = 0x00002022
+  WGL_STENCIL_BITS_EXT* = 0x00002023
+  WGL_AUX_BUFFERS_EXT* = 0x00002024
+  WGL_NO_ACCELERATION_EXT* = 0x00002025
+  WGL_GENERIC_ACCELERATION_EXT* = 0x00002026
+  WGL_FULL_ACCELERATION_EXT* = 0x00002027
+  WGL_SWAP_EXCHANGE_EXT* = 0x00002028
+  WGL_SWAP_COPY_EXT* = 0x00002029
+  WGL_SWAP_UNDEFINED_EXT* = 0x0000202A
+  WGL_TYPE_RGBA_EXT* = 0x0000202B
+  WGL_TYPE_COLORINDEX_EXT* = 0x0000202C
+
+proc wglGetPixelFormatAttribivEXT*(hdc: HDC, iPixelFormat: TGLint, 
+                                   iLayerPlane: TGLint, nAttributes: TGLuint, 
+                                   piAttributes: PGLint, piValues: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribivEXT".}
+proc wglGetPixelFormatAttribfvEXT*(hdc: HDC, iPixelFormat: TGLint, 
+                                   iLayerPlane: TGLint, nAttributes: TGLuint, 
+                                   piAttributes: PGLint, pfValues: PGLfloat): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribfvEXT".}
+proc wglChoosePixelFormatEXT*(hdc: HDC, piAttribIList: PGLint, 
+                              pfAttribFList: PGLfloat, nMaxFormats: TGLuint, 
+                              piFormats: PGLint, nNumFormats: PGLuint): BOOL{.
+    dynlib: dllname, importc: "wglChoosePixelFormatEXT".}
+const 
+  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D* = 0x00002050
+  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D* = 0x00002051
+  WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D* = 0x00002052
+  WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D* = 0x00002053
+
+proc wglGetDigitalVideoParametersI3D*(hDC: HDC, iAttribute: TGLint, 
+                                      piValue: PGLint): BOOL{.dynlib: dllname, 
+    importc: "wglGetDigitalVideoParametersI3D".}
+proc wglSetDigitalVideoParametersI3D*(hDC: HDC, iAttribute: TGLint, 
+                                      piValue: PGLint): BOOL{.dynlib: dllname, 
+    importc: "wglSetDigitalVideoParametersI3D".}
+const 
+  WGL_GAMMA_TABLE_SIZE_I3D* = 0x0000204E
+  WGL_GAMMA_EXCLUDE_DESKTOP_I3D* = 0x0000204F
+
+proc wglGetGammaTableParametersI3D*(hDC: HDC, iAttribute: TGLint, 
+                                    piValue: PGLint): BOOL{.dynlib: dllname, 
+    importc: "wglGetGammaTableParametersI3D".}
+proc wglSetGammaTableParametersI3D*(hDC: HDC, iAttribute: TGLint, 
+                                    piValue: PGLint): BOOL{.dynlib: dllname, 
+    importc: "wglSetGammaTableParametersI3D".}
+proc wglGetGammaTableI3D*(hDC: HDC, iEntries: TGLint, puRed: PGLUSHORT, 
+                          puGreen: PGLUSHORT, puBlue: PGLUSHORT): BOOL{.
+    dynlib: dllname, importc: "wglGetGammaTableI3D".}
+proc wglSetGammaTableI3D*(hDC: HDC, iEntries: TGLint, puRed: PGLUSHORT, 
+                          puGreen: PGLUSHORT, puBlue: PGLUSHORT): BOOL{.
+    dynlib: dllname, importc: "wglSetGammaTableI3D".}
+const 
+  WGL_GENLOCK_SOURCE_MULTIVIEW_I3D* = 0x00002044
+  WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D* = 0x00002045
+  WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D* = 0x00002046
+  WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D* = 0x00002047
+  WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D* = 0x00002048
+  WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D* = 0x00002049
+  WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D* = 0x0000204A
+  WGL_GENLOCK_SOURCE_EDGE_RISING_I3D* = 0x0000204B
+  WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D* = 0x0000204C
+  WGL_FLOAT_COMPONENTS_NV* = 0x000020B0
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV* = 0x000020B1
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV* = 0x000020B2
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV* = 0x000020B3
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV* = 0x000020B4
+  WGL_TEXTURE_FLOAT_R_NV* = 0x000020B5
+  WGL_TEXTURE_FLOAT_RG_NV* = 0x000020B6
+  WGL_TEXTURE_FLOAT_RGB_NV* = 0x000020B7
+  WGL_TEXTURE_FLOAT_RGBA_NV* = 0x000020B8
+
+proc wglEnableGenlockI3D*(hDC: HDC): BOOL{.dynlib: dllname, 
+    importc: "wglEnableGenlockI3D".}
+proc wglDisableGenlockI3D*(hDC: HDC): BOOL{.dynlib: dllname, 
+    importc: "wglDisableGenlockI3D".}
+proc wglIsEnabledGenlockI3D*(hDC: HDC, pFlag: PBOOL): BOOL{.dynlib: dllname, 
+    importc: "wglIsEnabledGenlockI3D".}
+proc wglGenlockSourceI3D*(hDC: HDC, uSource: TGLuint): BOOL{.dynlib: dllname, 
+    importc: "wglGenlockSourceI3D".}
+proc wglGetGenlockSourceI3D*(hDC: HDC, uSource: PGLUINT): BOOL{.dynlib: dllname, 
+    importc: "wglGetGenlockSourceI3D".}
+proc wglGenlockSourceEdgeI3D*(hDC: HDC, uEdge: TGLuint): BOOL{.dynlib: dllname, 
+    importc: "wglGenlockSourceEdgeI3D".}
+proc wglGetGenlockSourceEdgeI3D*(hDC: HDC, uEdge: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglGetGenlockSourceEdgeI3D".}
+proc wglGenlockSampleRateI3D*(hDC: HDC, uRate: TGLuint): BOOL{.dynlib: dllname, 
+    importc: "wglGenlockSampleRateI3D".}
+proc wglGetGenlockSampleRateI3D*(hDC: HDC, uRate: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglGetGenlockSampleRateI3D".}
+proc wglGenlockSourceDelayI3D*(hDC: HDC, uDelay: TGLuint): BOOL{.
+    dynlib: dllname, importc: "wglGenlockSourceDelayI3D".}
+proc wglGetGenlockSourceDelayI3D*(hDC: HDC, uDelay: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglGetGenlockSourceDelayI3D".}
+proc wglQueryGenlockMaxSourceDelayI3D*(hDC: HDC, uMaxLineDelay: PGLUINT, 
+                                       uMaxPixelDelay: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglQueryGenlockMaxSourceDelayI3D".}
+const 
+  WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV* = 0x000020A0
+  WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV* = 0x000020A1
+  WGL_TEXTURE_RECTANGLE_NV* = 0x000020A2
+
+const 
+  WGL_RGBA_FLOAT_MODE_ATI* = 0x00008820
+  WGL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI* = 0x00008835
+  WGL_TYPE_RGBA_FLOAT_ATI* = 0x000021A0
+
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
new file mode 100644
index 000000000..fcd0e8d24
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
@@ -0,0 +1,40 @@
+import zlib
+
+proc compress*(source: string): string =
+  var
+    sourcelen = source.len
+    destlen = sourcelen + (sourcelen.float * 0.1).int + 16
+  result = ""
+  result.setLen destLen
+  var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen)
+  if res != Z_OK:
+    echo "Error occurred: ", res
+  elif destLen < result.len:
+    result.setLen(destLen)
+
+proc uncompress*(source: string, destLen: var int): string =
+  result = ""
+  result.setLen destLen
+  var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len)
+  if res != Z_OK:
+    echo "Error occurred: ", res
+    
+
+when isMainModule:
+  import strutils
+  var r = compress("Hello")
+  echo repr(r)
+  var ln = "Hello".len
+  var rr = uncompress(r, ln)
+  echo repr(rr)
+  assert rr == "Hello"
+
+  proc `*`(a: string; b: int): string {.inline.} = result = repeat(a, b)
+  var s = "yo dude sup bruh homie" * 50
+  r = compress(s)
+  echo s.len, " -> ", r.len
+
+  ln = s.len
+  rr = uncompress(r, ln)
+  echo r.len, " -> ", rr.len
+  assert rr == s
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/dirserver_settings.json b/tests/manyloc/keineschweine/server/dirserver_settings.json
new file mode 100644
index 000000000..18c15fb46
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/dirserver_settings.json
@@ -0,0 +1,7 @@
+{
+ "network":"lamenet",
+ "port":2049,
+ "zones":[
+  {"name":"alphazone","key":"skittles"} 
+ ]
+}
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/nim.cfg b/tests/manyloc/keineschweine/server/nim.cfg
new file mode 100644
index 000000000..fdc45a8e1
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/nim.cfg
@@ -0,0 +1,6 @@
+debugger = off
+deadCodeElim = on
+path = ".."
+path = "../genpacket"
+path = "../helpers"
+define = NoSFML
diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim
new file mode 100644
index 000000000..897fc7d32
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_dirserver.nim
@@ -0,0 +1,201 @@
+## directory server
+## handles client authorization and assets
+
+import
+  sockets, times, streams, streams_enh, tables, json, os,
+  sg_packets, sg_assets, md5, server_utils, map_filter
+type
+  THandler = proc(client: PCLient; stream: PStream)
+var
+  server: TSocket
+  handlers = initTable[char, THandler](16)
+  thisZone = newScZoneRecord("local", "sup")
+  zoneList = newScZoneList()
+  thisZoneSettings: string
+  zoneSlots: seq[tuple[name: string; key: string]] = @[]
+  zones: seq[PClient] = @[]
+  ## I was high.
+  clients = initTable[TupAddress, PClient](16)
+  alias2client = initTable[string, PClient](32)
+  allClients: seq[PClient] = @[] 
+
+proc findClient*(host: string; port: int16): PClient =
+  let addy: TupAddress = (host, port)
+  if clients.hasKey(addy):
+    return clients[addy]
+  result = newClient(addy)
+  clients[addy] = result
+  allClients.add(result)
+
+proc loginZone(client: PClient; login: SdZoneLogin): bool =
+  if not client.auth:
+    for s in zoneSlots.items:
+      if s.name == login.name and s.key == login.key:
+        client.auth = true
+        client.kind = CServer
+        client.record = login.record
+        result = true
+        break
+
+proc sendZoneList(client: PClient) = 
+  echo(">> zonelist ", client, ' ', HZoneList)
+  client.send(HZonelist, zonelist)
+proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
+  var m = newScChat(CPriv, sender.alias, txt)
+  rcv.send(HChat, m)
+proc sendChat(client: PClient; kind: ChatType; txt: string) =
+  echo(">> chat ", client)
+  var m = newScChat(kind, "", txt)
+  client.send(HChat, m)
+
+
+
+var pubChatQueue = newIncomingBuffer()
+proc queuePub(sender: string, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
+  pubChatQueue.write(HChat)
+  chat.pack(pubChatQueue)
+
+handlers[HHello] = (proc(client: PClient; stream: PStream) =
+  var h = readCsHello(stream)
+  if h.i == 14:
+    var greet = newScHello("Well hello there")
+    client.send(HHello, greet))
+handlers[HLogin] = proc(client: PClient; stream: PStream) =
+  var loginInfo = readCsLogin(stream)
+  echo("** login: alias = ", loginInfo.alias)
+  if alias2client.hasKey(loginInfo.alias):
+    client.sendError("Alias in use.")
+    return
+  if client.loginPlayer(loginInfo):
+    alias2client[client.alias] = client
+    client.sendMessage("Welcome "& client.alias)
+    var session = newScLogin(client.id, client.alias, client.session)
+    client.send HLogin, session
+    client.sendZonelist()
+
+handlers[HZoneList] = proc(client: PClient; stream: PStream) =
+  var pinfo = readCsZoneList(stream)
+  echo("** zonelist req")
+  sendZoneList client
+handlers[HChat] = proc(client: PClient; stream: PStream) =
+  var chat = readCsChat(stream)
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  if chat.target != "": ##private
+    if alias2client.hasKey(chat.target):
+      alias2client[chat.target].forwardPrivate(client, chat.text)
+  else:
+    queuePub(client.alias, chat)
+
+proc sendServMsg(client: PClient; msg: string) =
+  var m = newDsMsg(msg)
+  client.send HDsMsg, m
+handlers[HZoneLogin] = proc(client: PClient; stream: PStream) =
+  var 
+    login = readSdZoneLogin(stream)
+  if not client.loginZone(login):
+    client.sendServMsg "Invalid login"
+  else:
+    client.sendServMsg "Welcome to the servers"
+    echo "** Zone logged in: ", login
+    zones.add client
+    zonelist.zones.add client.record
+
+
+handlers[HFileChallenge] = proc(client: PClient; stream: PStream) =
+  if client.auth:
+    if client.kind == CServer:
+      var chg = readScFileChallenge(stream)
+
+proc handlePkt(s: PClient; stream: PStream) =
+  while not stream.atEnd:  
+    var typ = readChar(stream)
+    if not handlers.hasKey(typ):
+      break
+    else:
+      handlers[typ](s, stream)
+
+proc createServer(port: TPort) =
+  if not server.isNil:
+    server.close()
+  server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
+  server.bindAddr(port)
+
+
+var clientIndex = 0
+var incoming = newIncomingBuffer()
+proc poll*(timeout: int = 250) =
+  if server.isNil: return
+  var 
+    reads = @[server]
+    writes = @[server]
+  if select(reads, timeout) > 0:
+    var
+      addy = ""
+      port: TPort
+    incoming.data.setLen 512
+    let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
+    if not res:
+      echo("No recv")
+      return
+    else:
+      var client = findClient(addy, port.int16)
+      echo "<< ", res, " ", client, ": ", len(incoming.data), " ", repr(incoming.data)
+      handlePkt(client, incoming)
+    incoming.flush()
+  if selectWrite(writes, timeout) > 0:
+    let nclients = allClients.len
+    if nclients == 0:
+      return
+    clientIndex = (clientIndex + 1) mod nclients
+    var c = allClients[clientIndex]
+    if c.outputBuf.getPosition > 0:
+      let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
+      echo("Write ", c, " result: ", res, " data: ", repr(c.outputBuf.data))
+      c.outputBuf.flush()
+
+when isMainModule:
+  import parseopt, matchers, strutils
+  var cfgFile = "dirserver_settings.json"
+  for kind, key, val in getOpt():
+    case kind
+    of cmdShortOption, cmdLongOption:
+      case key
+      of "f", "file": 
+        if existsFile(val):
+          cfgFile = val
+        else:
+          echo("File does not exist: ", val)
+      else:
+        echo("Unknown option: ", key," ", val)
+    else:
+      echo("Unknown option: ", key, " ", val)
+  var jsonSettings = parseFile(cfgFile)
+  let port = TPort(jsonSettings["port"].num)
+  zonelist.network = jsonSettings["network"].str
+  for slot in jsonSettings["zones"].items:
+    zoneSlots.add((slot["name"].str, slot["key"].str))
+  
+  createServer(port)
+  echo("Listening on port ", port, "...")
+  var pubChatTimer = cpuTime() #newClock()
+  const PubChatDelay = 1000/1000
+  while true:
+    poll(15)
+    ## TODO sort this type of thing VV into a queue api 
+    if cpuTime() - pubChatTimer > PubChatDelay:       #.getElapsedTime.asMilliseconds > 100:
+      pubChatTimer -= pubChatDelay
+      if pubChatQueue.getPosition > 0:
+        var cn = 0
+        let sizePubChat = pubChatQueue.data.len
+        var sent = 0
+        filterIt2(allClients, it.auth == true and it.kind == CPlayer):
+          it.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+          sent += 1
+        #for c in allClients:
+        #  c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+        pubChatQueue.flush()
+        echo "pubChatQueue flushed to ", sent, "clients"
+
diff --git a/tests/manyloc/keineschweine/server/old_server_utils.nim b/tests/manyloc/keineschweine/server/old_server_utils.nim
new file mode 100644
index 000000000..af9a1b01e
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_server_utils.nim
@@ -0,0 +1,98 @@
+import 
+  streams, md5, sockets, unsigned,
+  sg_packets, zlib_helpers, idgen
+type
+  TClientType* = enum
+    CServer = 0'i8, CPlayer, CUnknown
+  PClient* = ref TClient
+  TClient* = object of TObject
+    id*: int32
+    addy*: TupAddress
+    clientID*: uint16
+    auth*: bool
+    outputBuf*: PStringStream
+    case kind*: TClientType
+    of CPlayer:
+      alias*: string
+      session*: string
+      lastPing*: float
+      failedPings*: int
+    of CServer:
+      record*: ScZoneRecord
+      cfg*: TChecksumFile
+    of CUnknown: nil
+  TChecksumFile* = object
+    unpackedSize*: int
+    sum*: MD5Digest
+    compressed*: string
+  TupAddress* = tuple[host: string, port: int16]
+  PIDGen*[T: Ordinal] = ref TIDGen[T]
+  TIDGen[T: Ordinal] = object
+    max: T
+    freeIDs: seq[T]
+var cliID = newIdGen[int32]()
+
+proc sendMessage*(client: PClient; txt: string)
+proc sendError*(client: PClient; txt: string)
+proc `$`*(client: PClient): string
+
+proc newIncomingBuffer*(size = 1024): PStringStream =
+  result = newStringStream("")
+  result.data.setLen size
+  result.data.setLen 0
+  result.flushImpl = proc(stream: PStream) =
+    stream.setPosition(0)
+    PStringStream(stream).data.setLen(0)
+
+
+proc free*(c: PClient) =
+  echo "Client freed: ", c
+  cliID.del c.id
+  c.outputBuf.flush()
+  c.outputBuf = nil
+proc newClient*(addy: TupAddress): PClient =
+  new(result, free)
+  result.addy = addy
+  result.outputBuf = newStringStream("")
+  result.outputBuf.flushImpl = proc(stream: PStream) = 
+    stream.setPosition 0
+    PStringStream(stream).data.setLen 0
+
+proc loginPlayer*(client: PClient; login: CsLogin): bool =
+  if client.auth:
+    client.sendError("You are already logged in.")
+    return
+  client.id = cliID.next()
+  client.auth = true
+  client.kind = CPlayer
+  client.alias = login.alias
+  client.session = getMD5(client.alias & $rand(10000))
+  result = true
+
+proc `$`*(client: PClient): string =
+  if not client.auth: return $client.addy
+  case client.kind
+  of CPlayer: result = client.alias
+  of CServer: result = client.record.name
+  else: result = $client.addy
+proc send*[T](client: PClient; pktType: char; pkt: var T) =
+  client.outputBuf.write(pktType)
+  pkt.pack(client.outputBuf)
+
+proc sendMessage*(client: PClient; txt: string) =
+  var m = newScChat(CSystem, text = txt)
+  client.send HChat, m
+proc sendError*(client: PClient; txt: string) =
+  var m = newScChat(CError, text = txt)
+  client.send HChat, m
+
+proc checksumFile*(filename: string): TChecksumFile =
+  let fullText = readFile(filename)
+  result.unpackedSize = fullText.len
+  result.sum = toMD5(fullText)
+  result.compressed = compress(fullText)
+proc checksumStr*(str: string): TChecksumFile =
+  result.unpackedSize = str.len
+  result.sum = toMD5(str)
+  result.compressed = compress(str)
+
diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim
new file mode 100644
index 000000000..1e57c12a1
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_sg_server.nim
@@ -0,0 +1,254 @@
+import
+  sockets, times, streams, streams_enh, tables, json, os, unsigned,
+  sg_packets, sg_assets, md5, server_utils, client_helpers
+var
+  dirServer: PServer
+  thisZone = newScZoneRecord("local", "sup")
+  thisZoneSettings: PZoneSettings
+  dirServerConnected = false
+  ## I was high.
+  clients = initTable[TupAddress, PClient](16)
+  alias2client = initTable[string, PClient](32)
+  allClients: seq[PClient] = @[] 
+  zonePlayers: seq[PClient] = @[] 
+const
+  PubChatDelay = 100/1000 #100 ms
+
+import hashes
+proc hash*(x: uint16): THash {.inline.} = 
+  result = int32(x)
+
+proc findClient*(host: string; port: int16): PClient =
+  let addy: TupAddress = (host, port)
+  if clients.hasKey(addy):
+    return clients[addy]
+  result = newClient(addy)
+  clients[addy] = result
+  allClients.add(result)
+
+
+proc sendZoneList(client: PClient) = 
+  echo(">> zonelist ", client)
+  #client.send(HZonelist, zonelist)
+
+proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
+  var m = newScChat(CPriv, sender.alias, txt)
+  rcv.send(HChat, m)
+proc sendChat(client: PClient; kind: ChatType; txt: string) =
+  echo(">> chat ", client)
+  var m = newScChat(kind, "", txt)
+  client.send(HChat, m)
+
+var pubChatQueue = newStringStream("")
+pubChatQueue.flushImpl = proc(stream: PStream) =
+  stream.setPosition(0)
+  PStringStream(stream).data.setLen(0)
+proc queuePub(sender: string, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
+  pubChatQueue.write(HChat)
+  chat.pack(pubChatQueue)
+
+handlers[HHello] = (proc(client: PClient; stream: PStream) =
+  var h = readCsHello(stream)
+  if h.i == 14:
+    var greet = newScHello("Well hello there")
+    client.send(HHello, greet))
+handlers[HLogin] = proc(client: PClient; stream: PStream) =
+  var loginInfo = readCsLogin(stream)
+  echo("** login: alias = ", loginInfo.alias)
+  if not dirServerConnected and client.loginPlayer(loginInfo):
+    client.sendMessage("Welcome "& client.alias)
+    alias2client[client.alias] = client
+    client.sendZonelist()
+handlers[HZoneList] = proc(client: PClient; stream: PStream) =
+  var pinfo = readCsZoneList(stream)
+  echo("** zonelist req")
+handlers[HChat] = proc(client: PClient; stream: PStream) =
+  var chat = readCsChat(stream)
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  if chat.target != "": ##private
+    if alias2client.hasKey(chat.target):
+      alias2client[chat.target].forwardPrivate(client, chat.text)
+  else:
+    queuePub(client.alias, chat)
+handlers[HZoneQuery] = proc(client: PClient; stream: PStream) =
+  echo("Got zone query")
+  var q = readCsZoneQuery(stream)
+  var resp = newScZoneQuery(zonePlayers.len.uint16)
+  client.send(HZoneQuery, resp)
+
+
+
+handlers[HZoneJoinReq] = proc(client: PClient; stream: PStream) =
+  var req = readCsZoneJoinReq(stream)
+  echo "Join zone request from (",req.session.id,") ", req.session.alias 
+  if client.auth and client.kind == CPlayer:
+    echo "Client is authenticated, verifying filez"
+    client.startVerifyingFiles()
+  elif dirServerConnected:
+    echo "Dirserver is connected, verifying client"
+    dirServer.send HVerifyClient, req.session
+  else:
+    echo "Dirserver is disconnected =("
+    client.startVerifyingFiles()
+
+
+
+proc handlePkt(s: PClient; stream: PStream) =
+  while not stream.atEnd:  
+    var typ = readChar(stream)
+    if not handlers.hasKey(typ):
+      break
+    else:
+      handlers[typ](s, stream)
+
+proc createServer(port: TPort) =
+  if not server.isNil:
+    server.close()
+  server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
+  server.bindAddr(port)
+
+var clientIndex = 0
+var incoming = newIncomingBuffer()
+proc poll*(timeout: int = 250) =
+  if server.isNil: return
+  var 
+    reads = @[server]
+    writes = @[server]
+  if select(reads, timeout) > 0:
+    var
+      addy = ""
+      port: TPort
+    let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
+    if not res:
+      echo("No recv")
+      return
+    else:
+      var client = findClient(addy, port.int16)
+      #echo("<< ", res, " ", client.alias, ": ", len(line.data), " ", repr(line.data))
+      handlePkt(client, incoming)
+    incoming.flush()
+  if selectWrite(writes, timeout) > 0:
+    let nclients = allClients.len
+    if nclients == 0:
+      return
+    clientIndex = (clientIndex + 1) mod nclients
+    var c = allClients[clientIndex]
+    if c.outputBuf.getPosition > 0:
+      let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
+      echo("Write ", c, " result: ", res, " data: ", c.outputBuf.data)
+      c.outputBuf.flush()
+
+when isMainModule:
+  import parseopt, matchers, strutils
+  var zoneCfgFile = "./server_settings.json"
+  for kind, key, val in getOpt():
+    case kind
+    of cmdShortOption, cmdLongOption:
+      case key
+      of "f", "file": 
+        if existsFile(val):
+          zoneCfgFile = val
+        else:
+          echo("File does not exist: ", val)
+      else:
+        echo("Unknown option: ", key," ", val)
+    else:
+      echo("Unknown option: ", key, " ", val)
+  var jsonSettings = parseFile(zoneCfgFile)
+  let 
+    host = jsonSettings["host"].str
+    port = TPort(jsonSettings["port"].num)
+    zoneFile = jsonSettings["settings"].str
+    dirServerInfo = jsonSettings["dirserver"]
+  
+  var path = getAppDir()/../"data"/zoneFile
+  if not existsFile(path):
+    echo("Zone settings file does not exist: ../data/", zoneFile)
+    echo(path)
+    quit(1)
+  
+  ## Test file
+  block:
+    var 
+      TestFile: FileChallengePair
+      contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
+    testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
+    testFile.file = checksumStr(contents)
+    myAssets.add testFile
+  
+  setCurrentDir getAppDir().parentDir()
+  block:
+    let zonesettings = readFile(path)
+    var 
+      errors: seq[string] = @[]
+    if not loadSettings(zoneSettings, errors):
+      echo("You have errors in your zone settings:")
+      for e in errors: echo("**", e)
+      quit(1)
+    errors.setLen 0
+    
+    var pair: FileChallengePair
+    pair.challenge.file = zoneFile
+    pair.challenge.assetType = FZoneCfg
+    pair.challenge.fullLen = zoneSettings.len.int32
+    pair.file = checksumStr(zoneSettings)
+    myAssets.add pair
+    
+    allAssets:
+      if not load(asset):
+        echo "Invalid or missing file ", file
+      else:
+        var pair: FileChallengePair
+        pair.challenge.file = file
+        pair.challenge.assetType = assetType
+        pair.challenge.fullLen = getFileSize(
+          expandPath(assetType, file)).int32
+        pair.file = asset.contents
+        myAssets.add pair
+        
+    echo "Zone has ", myAssets.len, " associated assets"
+    
+      
+    dirServer = newServerConnection(dirServerInfo[0].str, dirServerInfo[1].num.TPort)
+    dirServer.handlers[HDsMsg] = proc(serv: PServer; stream: PStream) =
+      var m = readDsMsg(stream)
+      echo("DirServer> ", m.msg)
+    dirServer.handlers[HZoneLogin] = proc(serv: PServer; stream: PStream) =
+      let loggedIn = readDsZoneLogin(stream).status
+      if loggedIn:
+        dirServerConnected = true
+    dirServer.writePkt HZoneLogin, login
+  
+  thisZone.name = jsonSettings["name"].str
+  thisZone.desc = jsonSettings["desc"].str
+  thisZone.ip = "localhost"
+  thisZone.port = port
+  var login = newSdZoneLogin(
+    dirServerInfo[2].str, dirServerInfo[3].str,
+    thisZone)  
+  #echo "MY LOGIN: ", $login
+  
+  
+  
+  createServer(port)
+  echo("Listening on port ", port, "...")
+  var pubChatTimer = cpuTime()#newClock()
+  while true:
+    discard dirServer.pollServer(15)
+    poll(15)
+    ## TODO sort this type of thing VV into a queue api
+    #let now = cpuTime() 
+    if cpuTime() - pubChatTimer > PubChatDelay:       #.getElapsedTime.asMilliseconds > 100:
+      pubChatTimer -= pubChatDelay #.restart()
+      if pubChatQueue.getPosition > 0:
+        var cn = 0
+        let sizePubChat = pubChatQueue.data.len
+        for c in allClients:
+          c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+        pubChatQueue.flush()
+
+  
+  
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/sg_lobby.nim b/tests/manyloc/keineschweine/server/sg_lobby.nim
new file mode 100644
index 000000000..042d72337
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/sg_lobby.nim
@@ -0,0 +1,267 @@
+
+import
+  sockets, streams, tables, times, math, strutils, json, os, md5, 
+  sfml, sfml_vector, sfml_colors, 
+  streams_enh, input_helpers, zlib_helpers, client_helpers, sg_packets, sg_assets, sg_gui
+type
+  TClientSettings = object
+    resolution*: TVideoMode
+    offlineFile: string
+    dirserver: tuple[host: string, port: TPort]
+    website*: string
+var
+  clientSettings: TClientSettings
+  gui = newGuiContainer()
+  zonelist = newGuiContainer()
+  u_alias, u_passwd: PTextEntry
+  activeInput = 0
+  aliasText, passwdText: PText
+  fpsTimer: PButton
+  loginBtn: PButton
+  playBtn: PButton
+  keyClient = newKeyClient("lobby")
+  showZonelist = false
+  chatInput*: PTextEntry
+  messageArea*: PMessageArea
+  mySession*: ScLogin
+var
+  dirServer: PServer
+  zone*: PServer
+  activeServer: PServer
+  bConnected = false
+  outgoing = newStringStream("")
+  downloadProgress: PButton
+  connectionButtons: seq[PButton] #buttons that depend on connection to function
+
+template dispmessage(m: expr): stmt = 
+  messageArea.add(m)
+proc connectZone(host: string; port: TPort)
+proc connectToDirserv()
+
+proc writePkt[T](pid: PacketID; p: var T) =
+  if activeServer.isNil: return
+  activeServer.writePkt pid, p
+
+proc setConnected(state: bool) =
+  if state:
+    bConnected = true
+    for b in connectionButtons: enable(b)
+  else:
+    bConnected = false
+    for b in connectionButtons: disable(b)
+
+proc setActiveZone(ind: int; zone: ScZoneRecord) =
+  #hilight it or something
+  dispmessage("Selected " & zone.name)
+  connectZone(zone.ip, zone.port)
+  playBtn.enable()
+
+proc handleChat(serv: PServer; s: PStream) =
+  var msg = readScChat(s)
+  messageArea.add(msg)
+
+proc connectToDirserv() =
+  if dirServer.isNil:
+    dirServer = newServerConnection(clientSettings.dirserver.host, clientSettings.dirserver.port)
+    dirServer.handlers[HHello] = proc(serv: PServer; s: PStream) = 
+      let msg = readScHello(s)
+      dispMessage(msg.resp)
+      setConnected(true)
+    dirServer.handlers[HLogin] = proc(serv: PServer; s: PStream) =
+      mySession = readScLogin(s)
+      ##do something here
+    dirServer.handlers[HZonelist] = proc(serv: PServer; s: PStream) =
+      var 
+        info = readScZonelist(s)
+        zones = info.zones
+      if zones.len > 0:
+        zonelist.clearButtons()
+        var pos = vec2f(0.0, 0.0)
+        zonelist.newButton(
+          text = "Zonelist - "& info.network,
+          position = pos,
+          onClick = proc(b: PButton) =
+            dispmessage("Click on header"))
+        pos.y += 20
+        for i in 0..zones.len - 1:
+          var z = zones[i]
+          zonelist.newButton(
+            text = z.name, position = pos,
+            onClick = proc(b: PButton) = 
+              setActiveZone(i, z))
+          pos.y += 20
+        showZonelist = true
+    dirServer.handlers[HPoing] = proc(serv: PServer; s: PStream) = 
+      var ping = readPoing(s)
+      dispmessage("Ping: "& $ping.time)
+      ping.time = epochTime().float32
+      serv.writePkt HPoing, ping
+    dirServer.handlers[HChat] = handleChat
+    dirServer.handlers[HFileChallenge] = handleFileChallenge
+  var hello = newCsHello()
+  dirServer.writePkt HHello, hello
+  activeServer = dirServer
+
+
+proc zoneListReq() =
+  var pkt = newCsZonelist("sup")
+  writePkt HZonelist, pkt
+
+##key handlers
+keyClient.registerHandler(MouseMiddle, down, proc() = 
+  gui.setPosition(getMousePos()))
+
+keyClient.registerHandler(KeyO, down, proc() = 
+  if keyPressed(KeyRShift): echo(repr(outgoing)))
+keyClient.registerHandler(KeyTab, down, proc() =
+  activeInput = (activeInput + 1) mod 2) #does this work?
+keyClient.registerHandler(MouseLeft, down, proc() = 
+  let p = getMousePos()
+  gui.click(p)
+  if showZonelist: zonelist.click(p))
+var mptext = newText("", guiFont, 16)
+keyClient.registerHandler(MouseRight, down, proc() = 
+  let p = getMousePos()
+  mptext.setPosition(p)
+  mptext.setString("($1,$2)"%[$p.x.int,$p.y.int]))
+
+
+proc connectZone(host: string, port: TPort) =
+  echo "Connecting to zone at ", host, ':', port
+  if zone.isNil:
+    zone = newServerConnection(host, port)
+    zone.handlers[HFileChallenge] = handleFileChallenge
+    zone.handlers[HChallengeResult] = handleFileChallengeResult
+    zone.handlers[HFileTransfer] = handleFileTransfer
+    zone.handlers[HChat] = handleChat 
+  else:
+    zone.sock.connect(host, port)
+  var hello = newCsHello()
+  zone.writePkt HHello, hello
+  
+
+
+proc lobbyReady*() = 
+  keyClient.setActive()
+  gui.setActive(u_alias)
+
+proc tryConnect*(b: PButton) =
+  connectToDirserv()
+proc tryLogin*(b: PButton) =
+  var login = newCsLogin(
+    alias = u_alias.getText(),
+    passwd = u_passwd.getText())
+  writePkt HLogin, login
+proc tryTransition*(b: PButton) =
+  ##check if we're logged in
+  #<implementation censored by the church>
+  #var joinReq = newCsJ
+  zone.writePkt HZoneJoinReq, mySession
+  #var errors: seq[string] = @[]
+  #if loadSettings("", errors):
+  #  transition()
+  #else:
+  #  for e in errors: dispmessage(e)
+proc playOffline*(b: PButton) =
+  var errors: seq[string] = @[]
+  if loadSettingsFromFile(clientSettings.offlineFile, errors):
+    transition()
+  else:
+    dispmessage("Errors reading the file ("& clientSettings.offlineFile &"):")
+    for e in errors: dispmessage(e)
+
+proc getClientSettings*(): TClientSettings =
+  result = clientSettings
+
+proc lobbyInit*() =
+  var s = json.parseFile("./client_settings.json")
+  clientSettings.offlineFile = "data/"
+  clientSettings.offlineFile.add s["default-file"].str
+  let dirserv = s["directory-server"]
+  clientSettings.dirserver.host = dirserv["host"].str
+  clientSettings.dirserver.port = dirserv["port"].num.TPort
+  clientSettings.resolution.width = s["resolution"][0].num.cint
+  clientSettings.resolution.height= s["resolution"][1].num.cint
+  clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint
+  clientSettings.website = s["website"].str
+  zonelist.setPosition(vec2f(200.0, 100.0))
+  connectionButtons = @[]
+  
+  downloadProgress = gui.newButton(
+    text = "", position = vec2f(10, 130), onClick = nil) 
+  downloadProgress.bg.setFillColor(color(34, 139, 34))
+  downloadProgress.bg.setSize(vec2f(0, 0))
+  
+  var pos = vec2f(10, 10)
+  u_alias = gui.newTextEntry(
+    if s.existsKey("alias"): s["alias"].str else: "alias", 
+    pos)
+  pos.y += 20
+  u_passwd = gui.newTextEntry("buzz", pos)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Login", 
+    position = pos,
+    onClick = tryLogin,
+    startEnabled = false))
+  pos.y += 20
+  fpsText.setPosition(pos)
+  
+  playBtn = gui.newButton(
+    text = "Play",
+    position = vec2f(680.0, 8.0),
+    onClick = tryTransition,
+    startEnabled = false)
+  gui.newButton(
+    text = "Play Offline",
+    position = vec2f(680.0, 28.0),
+    onClick = playOffline)
+  fpsTimer = gui.newButton(
+    text = "FPS: ",
+    position = vec2f(10.0, 70.0),
+    onClick = proc(b: PButton) = nil)
+  gui.newButton(
+    text = "Connect",
+    position = vec2f(10.0, 90.0),
+    onClick = tryConnect)
+  connectionButtons.add(gui.newButton(
+    text = "Test Chat",
+    position = vec2f(10.0, 110.0),
+    onClick = (proc(b: PButton) = 
+      var pkt = newCsChat(text = "ohai")
+      writePkt HChat, pkt),
+    startEnabled = false))
+  chatInput = gui.newTextEntry("...", vec2f(10.0, 575.0), proc() =
+    sendChat dirServer, chatInput.getText()
+    chatInput.clearText())
+  messageArea = gui.newMessageArea(vec2f(10.0, 575.0 - 20.0))
+  messageArea.sizeVisible = 25
+  gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack += 1
+    update(messageArea))
+  gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = 
+    messageArea.scrollBack -= 1
+    update(messageArea))
+  gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) =
+    for i in 0.. <30: 
+      dispMessage($i))
+
+var i = 0
+proc lobbyUpdate*(dt: float) = 
+  #let res = disp.poll()
+  gui.update(dt)
+  i = (i + 1) mod 60
+  if i == 0:
+    fpsTimer.setString("FPS: "& $round(1.0/dt))
+  if not pollServer(dirServer, 5) and bConnected:
+    setConnected(false)
+    echo("Lost connection")
+  discard pollServer(zone, 5)
+
+proc lobbyDraw*(window: PRenderWindow) =
+  window.clear(Black)
+  window.draw messageArea
+  window.draw mptext
+  window.draw gui
+  if showZonelist: window.draw zonelist
+  window.display()
diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim
new file mode 100644
index 000000000..04b745003
--- /dev/null
+++ b/tests/manyloc/nake/nake.nim
@@ -0,0 +1,83 @@
+discard """
+DO AS THOU WILST PUBLIC LICENSE
+
+Whoever should stumble upon this document is henceforth and forever
+entitled to DO AS THOU WILST with aforementioned document and the
+contents thereof. 
+
+As said in the Olde Country, `Keepe it Gangster'."""
+
+import strutils, parseopt, tables, os
+
+type
+  PTask* = ref object
+    desc*: string
+    action*: TTaskFunction
+  TTaskFunction* = proc() {.closure.}
+var 
+  tasks* = initTable[string, PTask](16)
+
+proc newTask*(desc: string; action: TTaskFunction): PTask
+proc runTask*(name: string) {.inline.}
+proc shell*(cmd: varargs[string, `$`]): int {.discardable.}
+proc cd*(dir: string) {.inline.}
+
+template nakeImports*(): stmt {.immediate.} =
+  import tables, parseopt, strutils, os
+
+template task*(name: string; description: string; body: stmt): stmt {.dirty, immediate.} =
+  block:
+    var t = newTask(description, proc() {.closure.} =
+      body)
+    tasks[name] = t
+
+proc newTask*(desc: string; action: TTaskFunction): PTask =
+  new(result)
+  result.desc = desc
+  result.action = action
+proc runTask*(name: string) = tasks[name].action()
+
+proc shell*(cmd: varargs[string, `$`]): int =
+  result = execShellCmd(cmd.join(" "))
+proc cd*(dir: string) = setCurrentDir(dir)
+template withDir*(dir: string; body: stmt): stmt =
+  ## temporary cd
+  ## withDir "foo":
+  ##   # inside foo
+  ## #back to last dir
+  var curDir = getCurrentDir()
+  cd(dir)
+  body
+  cd(curDir)
+
+when isMainModule:
+  if not existsFile("nakefile.nim"):
+    echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
+    quit 1
+  var args = ""
+  for i in 1..paramCount():
+    args.add paramStr(i)
+    args.add " "
+  quit(shell("nim", "c", "-r", "nakefile.nim", args))
+else:
+  addQuitProc(proc() {.noconv.} =
+    var 
+      task: string
+      printTaskList: bool
+    for kind, key, val in getOpt():
+      case kind
+      of cmdLongOption, cmdShortOption:
+        case key.tolower
+        of "tasks", "t":
+          printTaskList = true
+        else: 
+          echo "Unknown option: ", key, ": ", val
+      of cmdArgument:
+        task = key
+      else: discard
+    if printTaskList or task.isNil or not(tasks.hasKey(task)):
+      echo "Available tasks:"
+      for name, task in pairs(tasks):
+        echo name, " - ", task.desc
+      quit 0
+    tasks[task].action())
diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim
new file mode 100644
index 000000000..d1d712964
--- /dev/null
+++ b/tests/manyloc/nake/nakefile.nim
@@ -0,0 +1,155 @@
+import nake
+import httpclient, zipfiles, times, math
+nakeImports
+
+randomize()
+
+const 
+  GameAssets = "http://dl.dropbox.com/u/37533467/data-08-01-2012.7z"
+  BinLibs = "http://dl.dropbox.com/u/37533467/libs-2012-09-12.zip"
+  ExeName = "keineschweine"
+  ServerDefines = "-d:NoSFML -d:NoChipmunk"
+  TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNim -d:debugKeys -d:foo -d:recordMode --forceBuild"
+  ReleaseDefines = "-d:release --deadCodeElim:on"
+  ReleaseTestDefines = "-d:debugWeps -d:debugKeys --forceBuild"
+
+task "testprofile", "..":
+  if shell("nim", TestBuildDefines, "--profiler:on", "--stacktrace:on", "compile", ExeName) == 0:
+    shell "."/ExeName, "offline"
+
+task "test", "Build with test defines":
+  if shell("nim", TestBuildDefines, "compile", ExeName) != 0:
+    quit "The build failed."
+
+task "testrun", "Build with test defines and run":
+  runTask "test"
+  shell "."/ExeName
+
+task "test2", "Build release test build test release build":
+  if shell("nim", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0:
+    shell "."/ExeName
+
+discard """task "dirserver", "build the directory server":
+  withDir "server":
+    if shell("nim", ServerDefines, "compile", "dirserver") != 0:
+      echo "Failed to build the dirserver"
+      quit 1"""
+
+task "zoneserver", "build the zone server":
+  withDir "enet_server":
+    if shell("nim", ServerDefines, "compile", "enet_server") != 0:
+      quit "Failed to build the zoneserver"
+task "zoneserver-gui", "build the zone server, with gui!":
+  withDir "enet_server":
+    if shell("nim", ServerDefines, "--app:gui", "compile", "enet_server") != 0:
+      quit "Failed to build the zoneserver"
+
+task "servers", "build the server and directory server":
+  #runTask "dirserver"
+  runTask "zoneserver"
+  echo "Successfully built both servers :')"
+
+task "all", "run SERVERS and TEST tasks":
+  runTask "servers"
+  runTask "test"
+
+task "release", "release build":
+  let res = shell("nim", ReleaseDefines, "compile", ExeName)
+  if res != 0:
+    echo "The build failed."
+    quit 1
+  else:
+    runTask "clean"
+    ## zip up all the files and such or something useful here 
+
+task "testskel", "create skeleton test dir for testing":
+  let dirname = "test-"& $random(5000)
+  removeDir dirName
+  createDir dirName/"data/fnt"
+  copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf"
+  copyFile "client_settings.json", dirName/"client_settings.json"
+  runTask "test"
+  copyFile ExeName, dirName/ExeName
+  withDir dirName:
+    shell "."/ExeName
+
+
+task "clean", "cleanup generated files":
+  var dirs = @["nimcache", "server"/"nimcache"]
+  dirs.map(proc(x: var string) =
+    if existsDir(x): removeDir(x))
+
+task "download", "download game assets":
+  var
+    skipAssets = false
+    path = expandFilename("data")
+  path.add DirSep
+  path.add(extractFilename(GameAssets))
+  if existsFile(path):
+    echo "The file already exists\n",
+      "[R]emove  [M]ove  [Q]uit  [S]kip    Source: ", GameAssets
+    case stdin.readLine.toLower
+    of "r":
+      removeFile path
+    of "m":
+      moveFile path, path/../(extractFilename(GameAssets)&"-old")
+    of "s":
+      skipAssets = true
+    else:
+      quit 0
+  else:
+    echo "Downloading from ", GameAssets
+  if not skipAssets:
+    echo "Downloading to ", path
+    downloadFile GameAssets, path
+    echo "Download finished"
+  
+    let targetDir = parentDir(parentDir(path))
+    when defined(linux):
+      let z7 = findExe("7z")
+      if z7 == "":
+        echo "Could not find 7z"
+      elif shell(z7, "t", path) != 0: ##note to self: make sure this is right
+        echo "Bad download"
+      else:
+        echo "Unpacking..."
+        shell(z7, "x", "-w[$1]" % targetDir, path)
+    else:
+      echo "I do not know how to unpack the data on this system. Perhaps you could ",
+        "fill this part in?"
+  
+  echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
+    "[Y]es [N]o   Source: ", BinLibs
+  case stdin.readline.toLower
+  of "y", "yes":
+    discard ## o_O
+  else:
+    return
+  path = extractFilename(BinLibs)
+  downloadFile BinLibs, path 
+  echo "Downloaded dem libs ", path
+  when true: echo "Unpack it yourself, sorry."
+  else:  ## this crashes, dunno why
+    var 
+      z: TZipArchive
+      destDir = getCurrentDir()/("unzip"& $random(5000))
+    if not z.open(path, fmRead):
+      echo "Could not open zip, bad download?"
+      return
+    echo "Extracting to ", destDir
+    createDir destDir
+    #z.extractAll destDir
+    for f in z.walkFiles():
+      z.extractFile(f, destDir/f)
+    z.close()
+    echo "Extracted the libs dir. Copy the ones you need to this dir."
+
+task "zip-lib", "zip up the libs dir":
+  var z: TZipArchive
+  if not z.open("libs-"& getDateStr() &".zip", fmReadWrite):
+    quit "Could not open zip"
+  for file in walkDirRec("libs", {pcFile, pcDir}):
+    echo "adding file ", file
+    z.addFile(file)
+  z.close()
+  echo "Great success!"
\ No newline at end of file
diff --git a/tests/manyloc/nake/nakefile.nim.cfg b/tests/manyloc/nake/nakefile.nim.cfg
new file mode 100644
index 000000000..6f3e86fe6
--- /dev/null
+++ b/tests/manyloc/nake/nakefile.nim.cfg
@@ -0,0 +1 @@
+path = "dependencies/nake"
diff --git a/tests/manyloc/named_argument_bug/gui.nim b/tests/manyloc/named_argument_bug/gui.nim
new file mode 100644
index 000000000..1e0bc6ffd
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/gui.nim
@@ -0,0 +1,44 @@
+import
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/math/rect,
+  tri_engine/math/vec
+
+type
+  TWidgetLayer* = enum
+    wlBg      = 100,
+    wlOverlap = 200,
+    wlMain    = 300,
+    wlOverlay = 400,
+    wlCursor  = 500
+  TWidgetLayerType = TWidgetLayer|int
+  TWidgetType* = enum
+    wtImg
+  PWidget* = ref object
+    `type`* : TWidgetType
+    layer*  : TWidgetLayer
+    rect*   : TRect
+    prim*   : PPrimitive
+
+const
+  baseZ = 5000
+
+proc newWidget*(`type`: TWidgetType, layer: TWidgetLayerType, rect: TRect): PWidget =
+  new(result)
+  result.`type` = `type`
+  result.layer = layer
+  result.rect = rect
+
+  var verts = newVert(rect)
+
+  # This works because z is accessible at this scope.
+  #var z = baseZ + layer.int
+  #result.prim = newPrimitive(verts, z=z)
+
+  # Doesn't work, because the compiler looks for a symbol called z in this scope,
+  # but it should only check that it is the name of one of the params.
+  #result.prim = newPrimitive(verts, z=baseZ + layer.int)
+
+  # This doesn't work either.
+  result.prim = newPrimitive(verts, z=0)
diff --git a/tests/manyloc/named_argument_bug/main.nim b/tests/manyloc/named_argument_bug/main.nim
new file mode 100644
index 000000000..767674428
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/main.nim
@@ -0,0 +1,23 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec,
+  tri_engine/math/circle,
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/tri_engine,
+  gui
+
+var isRunning = true
+
+block:
+  var renderer = newRenderer(w=10, h=10)
+
+  var primitive = newPrimitiveCircle(0.3.TR, color=white(0.5, 0.8), z=15)
+  renderer.addPrimitive(primitive)
+
+  var verts = newVert((min: newV2xy(-0.4), size: newV2xy(0.3)))
+  var primitive2 = newPrimitive(verts, color=red(0.5, 0.8), z=10)
+  renderer.addPrimitive(primitive2)
+
+  var mainMenuWidget = newWidget(wtImg, wlBg, rect=(newV2xy(-1.0), newV2xy(2.0)))
diff --git a/tests/manyloc/named_argument_bug/main.nim.cfg b/tests/manyloc/named_argument_bug/main.nim.cfg
new file mode 100644
index 000000000..27cf8e688
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/main.nim.cfg
@@ -0,0 +1,2 @@
+# this file only exists to mark 'main.nim' as the main file
+
diff --git a/tests/manyloc/named_argument_bug/tri_engine/config.nim b/tests/manyloc/named_argument_bug/tri_engine/config.nim
new file mode 100644
index 000000000..b90dc0b26
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/config.nim
@@ -0,0 +1,6 @@
+when defined(doublePrecision):
+  type
+    TR* = float64
+else:
+  type
+    TR* = float32
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
new file mode 100644
index 000000000..cdd5aaf03
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
@@ -0,0 +1,58 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+from strutils import
+  formatFloat,
+  TFloatFormat,
+  `%`,
+  ffDecimal
+
+from unsigned import
+  `shr`,
+  `and`
+
+type
+  TColor* = tuple[r, g, b, a: TR]
+
+converter toColor*(o: uint32): TColor =
+  ## Convert an integer to a color. This is mostly useful when the integer is specified as a hex
+  ## literal such as 0xFF00007F, which is 100% red, with 50% alpha.
+  ## TODO: turn this into a template that can take either 4 or 8 characters?
+  ((((o and 0xff000000'u32) shr 24).TR / 255.0).TR,
+   (((o and 0xff0000'u32) shr 16).TR / 255.0).TR,
+   (((o and 0xff00'u32) shr 8).TR / 255.0).TR,
+   (((o and 0xff'u32)).TR / 255.0).TR)
+
+converter toV4*(o: TColor): TV4[TR] =
+  cast[TV4[TR]](o)
+
+proc newColor*(r, g, b: TR=0.0, a: TR=1.0): TColor =
+  (r, g, b, a)
+
+proc white*(rgb, a: TR=1.0): TColor =
+  (rgb, rgb, rgb, a)
+
+proc red*(r, a: TR=1.0): TColor =
+  newColor(r=r, a=a)
+
+proc green*(g, a: TR=1.0): TColor =
+  newColor(g=g, a=a)
+
+proc yellow*(rg, a: TR=1.0): TColor =
+  newColor(r=rg, g=rg, a=a)
+
+proc blue*(b, a: TR=1.0): TColor =
+  newColor(b=b, a=a)
+
+proc cyan*(gb, a: TR=1.0): TColor =
+  newColor(g=gb, b=gb, a=a)
+
+proc purple*(rb, a: TR=1.0): TColor =
+  newColor(r=rb, b=rb, a=a)
+
+proc `$`*(o: TColor): string =
+  proc f(f: float): string =
+    f.formatFloat(precision=2, format=ffDecimal)
+
+  "(r: $#, g: $#, b: $#, s: $#)" % [f(o.r), f(o.g), f(o.b), f(o.a)]
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
new file mode 100644
index 000000000..22d36ef4d
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
@@ -0,0 +1,61 @@
+import
+  opengl,
+  tri_engine/math/vec
+
+export
+  opengl
+
+type
+  EGL* = object of E_Base
+  EGL_code* = object of EGL
+    code*: EGL_err
+  EGL_err {.pure.} = enum
+    none                 = GL_NO_ERROR
+    invalidEnum          = GL_INVALID_ENUM
+    invalidVal           = GL_INVALID_VALUE
+    invalidOp            = GL_INVALID_OPERATION
+    stackOverflow        = GL_STACK_OVERFLOW
+    stackUnderflow       = GL_STACK_UNDERFLOW
+    outOfMem             = GL_OUT_OF_MEMORY
+    invalidFramebufferOp = GL_INVALID_FRAMEBUFFER_OPERATION
+    unknown
+
+proc newGL_codeException*(msg: string, code: EGL_err): ref EGL_code =
+  result      = newException(EGL_code, $code)
+  result.code = code
+
+proc getErr*(): EGL_err =
+  result = glGetError().EGL_err
+  if result notin {EGL_err.none,
+                   EGL_err.invalidEnum,
+                   EGL_err.invalidVal,
+                   EGL_err.invalidOp,
+                   EGL_err.invalidFramebufferOp,
+                   EGL_err.outOfMem,
+                   EGL_err.stackUnderflow,
+                   EGL_err.stackOverflow}:
+    return EGL_err.unknown
+
+proc errCheck*() =
+  let err = getErr()
+  if err != EGL_err.none:
+    raise newGL_codeException($err, err)
+
+macro `?`*(call: expr{nkCall}): expr =
+  result = call
+  # Can't yet reference foreign symbols in macros.
+  #errCheck()
+
+when defined(doublePrecision):
+  const
+    glRealType* = cGLdouble
+else:
+  const
+    glRealType* = cGLfloat
+
+proc setUniformV4*[T](loc: GLint, vecs: var openarray[TV4[T]]) =
+  glUniform4fv(loc, vecs.len.GLsizei, cast[ptr GLfloat](vecs[0].addr))
+
+proc setUniformV4*[T](loc: GLint, vec: TV4[T]) =
+  var vecs = [vec]
+  setUniformV4(loc, vecs)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
new file mode 100644
index 000000000..8c26c04eb
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
@@ -0,0 +1,157 @@
+import
+  math,
+  tri_engine/config,
+  tri_engine/gfx/gl/gl,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/math/vec,
+  tri_engine/math/rect,
+  tri_engine/math/circle
+
+import strutils
+
+type
+  TVert* = tuple[pos: TV2[TR], texCoord: TV2[TR]]
+  TVertAttrib* = object
+    i*      : GLuint
+    size*   : GLint
+    stride* : GLsizei
+    offset* : GLvoid
+  TVertMode* = enum
+    vmTriStrip = GLtriangleStrip,
+    vmTriFan   = GLtriangleFan
+  TZ_range* = range[-100_000..100_000]
+  PPrimitive* = ref object
+    verts*        : seq[TVert]
+    indices*      : seq[GLushort]
+    arrBufId*     : GLuint
+    elemArrBufId* : GLuint
+    tex*          : TTex
+    color*        : TColor
+    vertMode*     : TVertMode
+    z*            : int
+
+proc newVert*(pos, texCoord: TV2): TVert =
+  (pos, texCoord)
+
+proc newVertQuad*(min, minRight, maxLeft, max: TV2[TR]): seq[TVert] =
+  @[newVert(min,      newV2()),
+    newVert(minRight, newV2(x=1.0)),
+    newVert(maxLeft,  newV2(y=1.0)),
+    newVert(max,      newV2xy(1.0))
+  ]
+
+proc newVert*(rect: rect.TRect): seq[TVert] =
+  newVertQuad(rect.min, newV2(rect.max.x, rect.min.y), newV2(rect.min.x, rect.max.y), rect.max)
+
+proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: GLvoid): TVertAttrib =
+  TVertAttrib(i: i, size: size, stride: stride, offset: offset)
+
+proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openarray[T]): GLuint =
+  result = 0.GLuint
+  ?glGenBuffers(1, result.addr)
+  ?glBindBuffer(vboTarget, result)
+
+  let size = (data.len * T.sizeof).GLsizeiptr
+  ?glBufferData(vboTarget, size, data[0].addr, objUsage)
+
+proc newPrimitive*(verts: var seq[TVert],
+                   vertMode=vmTriStrip,
+                   tex=whiteTex(),
+                   color=white(),
+                   z: TZ_range=0): PPrimitive =
+  var indices = newSeq[GLushort](verts.len)
+  for i in 0 .. <verts.len:
+    indices[i] = i.GLushort
+
+  new(result)
+  result.verts = verts
+  result.indices = indices
+
+  result.arrBufId     = genBuf(GLarrayBuffer, GL_STATIC_DRAW, verts)
+  result.elemArrBufId = genBuf(GLelementArrayBuffer, GL_STATIC_DRAW, indices)
+  result.tex = tex
+  result.color = color
+  result.vertMode = vertMode
+  result.z = z
+
+proc bindBufs*(o: PPrimitive) =
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+  ?glBindBuffer(GLelementArrayBuffer, o.elemArrBufId)
+
+proc enableVertAttribArrs*() =
+  ?glEnableVertexAttribArray(0)
+  ?glEnableVertexAttribArray(1)
+
+proc disableVertAttribArrs*() =
+  ?glDisableVertexAttribArray(1)
+  ?glDisableVertexAttribArray(0)
+
+proc setVertAttribPointers*() =
+  let vertSize {.global.} = TVert.sizeof.GLint
+  ?glVertexAttribPointer(0, 2, glRealType, false, vertSize, nil)
+  ?glVertexAttribPointer(1, 2, glRealType, false, vertSize, cast[GLvoid](TR.sizeof * 2))
+
+proc updVerts*(o: PPrimitive, start, `end`: int, f: proc(i: int, vert: var TVert)) =
+  assert start <= `end`
+  assert `end` < o.verts.len
+  for i in start..`end`:
+    f(i, o.verts[i])
+
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+
+  let byteLen = `end` - start + 1 * TVert.sizeof
+  let byteOffset = start * TVert.sizeof
+  ?glBufferSubData(GLarrayBuffer,
+                   byteOffset.GLintptr, # Offset. Is this right?
+                   byteLen.GLsizeiptr, # Size.
+                   cast[GLvoid](cast[int](o.verts[0].addr) + byteOffset))
+
+proc updAllVerts(o: PPrimitive, f: proc(i: int, vert: var TVert)) =
+  for i in 0 .. <o.verts.len:
+    f(i, o.verts[i])
+
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+
+  # Discard old buffer before creating a new one.
+  let byteLen = (o.verts.len * TVert.sizeof).GLsizeiptr
+  ?glBufferData(GLarrayBuffer, byteLen, nil, GLstaticDraw)
+  ?glBufferData(GLarrayBuffer, byteLen, o.verts[0].addr, GLstaticDraw)
+
+proc newVertCircle*(circle: TCircle, nSegs: Natural=0): seq[TVert] =
+  let nSegs = if nSegs == 0:
+      (circle.r.sqrt() * 400.0).int # TODO: Base this on the window resolution?
+    else:
+      max(nSegs, 3)
+
+  let theta: TR = (PI * 2.0) / (nSegs.TR)
+  let tanFactor = theta.tan()
+  let radialFactor = theta.cos()
+  var x = circle.r
+  var y: TR = 0.0
+
+  result = newSeq[TVert](nSegs)
+  #result[0] = newVert(circle.p, newV2xy(0.5))
+  for i in 1 .. <nSegs:
+    let pos = newV2(x + circle.p.x, y + circle.p.y)
+    let texCoord = pos * newV2xy(1.0 / circle.r)
+
+    result[i] = newVert(pos, texCoord)
+
+    let tx = -y
+    let ty = x
+    x += tx * tanFactor
+    y += ty * tanFactor
+
+    x *= radialFactor
+    y *= radialFactor
+
+  result.add(result[1])
+
+proc newPrimitiveCircle*(circle: TCircle,
+                         nSegs: Natural=0,
+                         tex=whiteTex(),
+                         color=white(),
+                         z: TZ_range=0): PPrimitive =
+  var verts = newVertCircle(circle, nSegs)
+  newPrimitive(verts, vmTriFan, tex, color, z)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
new file mode 100644
index 000000000..89bb76064
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
@@ -0,0 +1,103 @@
+import
+  pure/os,
+  tri_engine/gfx/gl/gl
+
+type
+  TShader* = object
+    id*: GL_handle
+  TShaderType* {.pure.} = enum
+    frag = GL_FRAGMENT_SHADER,
+    vert   = GL_VERTEX_SHADER
+  E_Shader* = object of E_Base
+  E_UnknownShaderType* = object of E_Shader
+
+converter pathToShaderType*(s: string): TShaderType =
+  case s.splitFile().ext:
+  of ".vs":
+    return TShaderType.vert
+  of ".fs":
+    return TShaderType.frag
+  else:
+    raise newException(E_UnknownShaderType, "Can't determine shader type from file extension: " & s)
+
+proc setSrc*(shader: TShader, src: string) =
+  var s = src.cstring
+  ?glShaderSource(shader.id, 1, cast[cstringarray](s.addr), nil)
+
+proc newShader*(id: GL_handle): TShader =
+  if id.int != 0 and not (?glIsShader(id)).bool:
+    raise newException(E_GL, "Invalid shader ID: " & $id)
+
+  result.id = id
+
+proc shaderInfoLog*(o: TShader): string =
+  var log {.global.}: array[0..1024, char]
+  var logLen: GLsizei
+  ?glGetShaderInfoLog(o.id.GLuint, log.len.GLsizei, addr logLen, cast[cstring](log.addr))
+  cast[string](log.addr).substr(0, logLen)
+
+proc compile*(shader: TShader, path="") =
+  ?glCompileShader(shader.id)
+  var compileStatus = 0.GLint
+  ?glGetShaderIv(shader.id, GL_COMPILE_STATUS, compileStatus.addr)
+
+  if compileStatus == 0:
+    raise newException(E_GL, if path.len == 0:
+        shaderInfoLog(shader)
+      else:
+        path & ":\n" & shaderInfoLog(shader)
+    )
+
+proc newShaderFromSrc*(src: string, `type`: TShaderType): TShader =
+  result.id = ?glCreateShader(`type`.GLenum)
+  result.setSrc(src)
+  result.compile()
+
+proc newShaderFromFile*(path: string): TShader =
+  newShaderFromSrc(readFile(path), path)
+
+type
+  TProgram* = object
+    id*: GL_handle
+    shaders: seq[TShader]
+
+proc attach*(o: TProgram, shader: TShader) =
+  ?glAttachShader(o.id, shader.id)
+
+proc infoLog*(o: TProgram): string =
+  var log {.global.}: array[0..1024, char]
+  var logLen: GLsizei
+  ?glGetProgramInfoLog(o.id.GLuint, log.len.GLsizei, addr logLen, cast[cstring](log.addr))
+  cast[string](log.addr).substr(0, logLen)
+
+proc link*(o: TProgram) =
+  ?glLinkProgram(o.id)
+  var linkStatus = 0.GLint
+  ?glGetProgramIv(o.id, GL_LINK_STATUS, linkStatus.addr)
+  if linkStatus == 0:
+    raise newException(E_GL, o.infoLog())
+
+proc validate*(o: TProgram) =
+  ?glValidateProgram(o.id)
+  var validateStatus = 0.GLint
+  ?glGetProgramIv(o.id, GL_VALIDATE_STATUS, validateStatus.addr)
+  if validateStatus == 0:
+    raise newException(E_GL, o.infoLog())
+
+proc newProgram*(shaders: seq[TShader]): TProgram =
+  result.id = ?glCreateProgram()
+  if result.id.int == 0:
+    return
+
+  for shader in shaders:
+    if shader.id.int == 0:
+      return
+
+    ?result.attach(shader)
+
+  result.shaders = shaders
+  result.link()
+  result.validate()
+
+proc use*(o: TProgram) =
+  ?glUseProgram(o.id)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
new file mode 100644
index 000000000..e5043ae34
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
@@ -0,0 +1,31 @@
+import
+  tri_engine/gfx/gl/gl
+
+type
+  TTex* = object
+    id*: GLuint
+
+var gWhiteTex = TTex(id: 0)
+
+proc setTexParams() =
+  ?glTexParameteri(GLtexture2D, GLtextureMinFilter, GLlinear)
+
+  #glTexParameteri(GLtexture2D, GLtextureMagFilter, GLlinear)
+  ?glTexParameteri(GLtexture2D, GLTextureMagFilter, GLnearest)
+
+  ?glTexParameteri(GLtexture2D, GLTextureWrapS, GLClampToEdge)
+  ?glTexParameteri(GLtexture2D, GLTextureWrapT, GLClampToEdge)
+
+proc whiteTex*(): TTex =
+  if gWhiteTex.id.int != 0:
+    return gWhiteTex
+
+  ?glGenTextures(1, gWhiteTex.id.addr)
+  ?glBindTexture(GLtexture2D, gWhiteTex.id)
+  setTexParams()
+
+  var pixel = [255'u8, 255'u8, 255'u8, 255'u8]
+  ?glTexImage2D(GLtexture2D, 0, GL_RGBA, 1, 1, 0, GL_BGRA, cGLUnsignedByte, pixel[0].addr)
+  ?glBindTexture(GLtexture2D, 0)
+
+  result = gWhiteTex
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim
new file mode 100644
index 000000000..7e7517998
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim
@@ -0,0 +1,9 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+type
+  TCircle* = tuple[p: TV2[TR], r: TR]
+
+converter toCircle*(o: TR): TCircle =
+  (newV2(), o)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim b/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim
new file mode 100644
index 000000000..b6fd9ce84
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim
@@ -0,0 +1,8 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+type
+  TRect* = tuple[min, size: TV2[TR]]
+
+proc max*(o: TRect): TV2[TR] = o.min + o.size
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
new file mode 100644
index 000000000..3b57acb8e
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
@@ -0,0 +1,55 @@
+import
+  macros,
+  tri_engine/config
+
+type
+  TV2*[T:SomeNumber=TR] = array[0..1, T]
+  TV3*[T:SomeNumber=TR] = array[0..2, T]
+  TV4*[T:SomeNumber=TR] = array[0..3, T]
+  TVT*[T:SomeNumber=TR] = TV2|TV3|TV4
+  #TV2* = array[0..1, TR]
+  #TV3* = array[0..2, TR]
+  #TV4* = array[0..3, TR]
+
+# TODO: Change to TVT when compiler issue is resolved.
+proc `$`*[T](o: TV2[T]): string =
+  result = "("
+  for i in 0 .. <o.len:
+    result &= $o[0]
+    if i != o.len - 1:
+      result &= ", "
+
+  result & ")"
+
+proc newV2T*[T](x, y: T=0): TV2[T] =
+  [x, y]
+
+proc newV2*(x, y: TR=0.0): TV2[TR] =
+  [x, y]
+
+proc newV2xy*(xy: TR): TV2[TR] =
+  [xy, xy]
+
+proc x*[T](o: TV2[T]): T =
+  o[0]
+
+proc y*[T](o: TV2[T]): T =
+  o[1]
+
+proc `*`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
+  [(lhs.x * rhs.x).TR, (lhs.y * rhs.y).TR]
+
+proc `+`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
+  [(lhs.x + rhs.x).TR, (lhs.y + rhs.y).TR]
+
+#proc dotProduct[T](a: TVT[T], b: TVT[T]): T =
+#  for i in 0 .. a.len - 1:
+#    result += a[i] * b[i]
+
+proc dot[T](a, b: TV2[T]): T =
+  for i in 0 .. <a.len:
+    result += a[i] * b[i]
+
+assert dot(newV2(), newV2()) == 0.0
+assert dot(newV2(2, 3), newV2(6, 7)) == 33.0
+assert dot([2.0, 3.0], [6.0, 7.0]) == 33.0
diff --git a/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim b/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
new file mode 100644
index 000000000..ba9989bbb
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
@@ -0,0 +1,106 @@
+import
+  algorithm,
+  tri_engine/config,
+  tri_engine/gfx/gl/gl,
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/gl/shader,
+  tri_engine/gfx/color
+
+const primitiveVs = """
+#version 330 core
+
+layout(location = 0) in vec2 pos;
+layout(location = 1) in vec2 texCoord;
+
+out vec2 uv;
+
+void main()
+{
+    gl_Position = vec4(pos, 0, 1);
+    uv = texCoord;
+}
+
+"""
+const primitiveFs = """
+#version 330 core
+
+in vec2 uv;
+out vec4 color;
+uniform sampler2D tex;
+uniform vec4 inColor;
+
+void main()
+{
+    color = texture(tex, uv) * inColor;
+}
+
+"""
+
+var gW, gH: Natural = 0
+
+proc w*(): int =
+  gW
+
+proc h*(): int =
+  gH
+
+type
+  PRenderer = ref object
+    primitiveProgram: TProgram
+    primitives: seq[PPrimitive]
+
+proc setupGL() =
+  ?glEnable(GLblend)
+  ?glBlendFunc(GLsrcAlpha, GLoneMinusSrcAlpha)
+  ?glClearColor(0.0, 0.0, 0.0, 1.0)
+  ?glPolygonMode(GLfrontAndBack, GLfill)
+
+proc newRenderer*(w, h: Positive): PRenderer =
+  gW = w
+  gH = h
+
+  new(result)
+  newSeq(result.primitives, 0)
+  loadExtensions()
+  setupGL()
+  result.primitiveProgram = newProgram(@[
+    newShaderFromSrc(primitiveVs, TShaderType.vert),
+    newShaderFromSrc(primitiveFs, TShaderType.frag)])
+
+proc draw(o: PRenderer, p: PPrimitive) =
+  let loc = proc(x: string): Glint =
+    result = glGetUniformLocation(o.primitiveProgram.id, x)
+    if result == -1:
+      raise newException(E_GL, "Shader error: " & x & " does not correspond to a uniform variable")
+
+  setUniformV4(loc("inColor"), p.color)
+  ?glActiveTexture(GLtexture0)
+  ?glBindTexture(GLtexture2D, p.tex.id.GLuint)
+  ?glUniform1i(loc("tex"), 0)
+
+  p.bindBufs()
+  setVertAttribPointers()
+
+  ?glDrawElements(p.vertMode.GLenum, p.indices.len.GLsizei, cGLunsignedShort, nil)
+
+proc draw*(o: PRenderer) =
+  ?glClear(GLcolorBufferBit)
+  o.primitiveProgram.use()
+
+  enableVertAttribArrs()
+  var zSortedPrimitives = o.primitives
+  zSortedPrimitives.sort(proc(x, y: PPrimitive): int =
+    if x.z < y.z:
+      -1
+    elif x.z > y.z:
+      1
+    else:
+      0)
+
+  for x in zSortedPrimitives:
+    o.draw(x)
+
+  disableVertAttribArrs()
+
+proc addPrimitive*(o: PRenderer, p: PPrimitive) =
+  o.primitives.add(p)
diff --git a/tests/manyloc/packages/noconflicts.nim b/tests/manyloc/packages/noconflicts.nim
new file mode 100644
index 000000000..2183d01a8
--- /dev/null
+++ b/tests/manyloc/packages/noconflicts.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''package1/strutils
+package2/strutils
+noconflicts
+new os.nim'''
+"""
+
+import package1/strutils as su1
+import package2.strutils as su2
+
+import os
+
+su1.foo()
+su2.foo()
+echo "noconflicts"
+yay()
diff --git a/tests/manyloc/packages/noconflicts.nim.cfg b/tests/manyloc/packages/noconflicts.nim.cfg
new file mode 100644
index 000000000..88974ab8c
--- /dev/null
+++ b/tests/manyloc/packages/noconflicts.nim.cfg
@@ -0,0 +1 @@
+# Mark noconflicts as project file
\ No newline at end of file
diff --git a/tests/manyloc/packages/os.nim b/tests/manyloc/packages/os.nim
new file mode 100644
index 000000000..8a59612f9
--- /dev/null
+++ b/tests/manyloc/packages/os.nim
@@ -0,0 +1,5 @@
+
+# Overrides lib/pure/os.nim
+
+proc yay* = echo "new os.nim"
+
diff --git a/tests/manyloc/packages/package1/p1.babel b/tests/manyloc/packages/package1/p1.babel
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/manyloc/packages/package1/p1.babel
diff --git a/tests/manyloc/packages/package1/strutils.nim b/tests/manyloc/packages/package1/strutils.nim
new file mode 100644
index 000000000..b283600ea
--- /dev/null
+++ b/tests/manyloc/packages/package1/strutils.nim
@@ -0,0 +1,5 @@
+
+# Overrides lib/pure/os.nim
+
+proc foo* = echo "package1/strutils"
+
diff --git a/tests/manyloc/packages/package2/p2.babel b/tests/manyloc/packages/package2/p2.babel
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/manyloc/packages/package2/p2.babel
diff --git a/tests/manyloc/packages/package2/strutils.nim b/tests/manyloc/packages/package2/strutils.nim
new file mode 100644
index 000000000..1fb4abd41
--- /dev/null
+++ b/tests/manyloc/packages/package2/strutils.nim
@@ -0,0 +1,5 @@
+
+# Overrides lib/pure/os.nim
+
+proc foo* = echo "package2/strutils"
+
diff --git a/tests/manyloc/standalone/barebone.nim b/tests/manyloc/standalone/barebone.nim
new file mode 100644
index 000000000..9d75f8f2e
--- /dev/null
+++ b/tests/manyloc/standalone/barebone.nim
@@ -0,0 +1,9 @@
+
+# bug  #2041: Macros need to be available for os:standalone!
+import macros
+
+proc printf(frmt: cstring) {.varargs, header: "<stdio.h>", cdecl.}
+
+var x = 0
+inc x
+printf("hi %ld\n", x+4777)
diff --git a/tests/manyloc/standalone/barebone.nim.cfg b/tests/manyloc/standalone/barebone.nim.cfg
new file mode 100644
index 000000000..52ec64e3f
--- /dev/null
+++ b/tests/manyloc/standalone/barebone.nim.cfg
@@ -0,0 +1,2 @@
+--os:standalone
+--deadCodeElim:on
diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim
new file mode 100644
index 000000000..d9b3f4388
--- /dev/null
+++ b/tests/manyloc/standalone/panicoverride.nim
@@ -0,0 +1,19 @@
+
+proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
+proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
+
+{.push stack_trace: off, profiler:off.}
+
+proc rawoutput(s: string) =
+  printf("%s\n", s)
+
+proc panic(s: string) {.noreturn.} =
+  rawoutput(s)
+  exit(1)
+
+# Alternatively we also could implement these 2 here:
+#
+# proc sysFatal(exceptn: typeDesc, message: string) {.noReturn.}
+# proc sysFatal(exceptn: typeDesc, message, arg: string) {.noReturn.}
+
+{.pop.}
diff --git a/tests/metatype/tautonotgeneric.nim b/tests/metatype/tautonotgeneric.nim
new file mode 100644
index 000000000..a55ae488e
--- /dev/null
+++ b/tests/metatype/tautonotgeneric.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "wof!"
+"""
+
+# bug #1659
+type Animal = ref object {.inheritable.}
+type Dog = ref object of Animal
+
+method say(a: Animal): auto = "wat!"
+method say(a: Dog): auto = "wof!"
+
+proc saySomething(a: Animal): auto = a.say()
+
+var a = Dog()
+echo saySomething(a)
diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim
new file mode 100644
index 000000000..ef5377096
--- /dev/null
+++ b/tests/metatype/tautoproc.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "empty"
+"""
+
+# bug #898
+
+import typetraits
+
+proc measureTime(e: auto) =
+  echo e.type.name
+
+proc generate(a: int): void =
+  discard
+
+proc runExample =
+  var builder: int = 0
+
+  measureTime:
+    builder.generate()
+
+measureTime:
+  discard
diff --git a/tests/metatype/tbindtypedesc.nim b/tests/metatype/tbindtypedesc.nim
new file mode 100644
index 000000000..84527362f
--- /dev/null
+++ b/tests/metatype/tbindtypedesc.nim
@@ -0,0 +1,88 @@
+discard """
+  msg: '''int int
+float float
+int int
+TFoo TFoo
+int float
+TFoo TFoo'''
+"""
+
+import typetraits
+
+type 
+  TFoo = object
+    x, y: int
+
+  TBar = tuple
+    x, y: int
+
+template accept(e: expr) =
+  static: assert(compiles(e))
+
+template reject(e: expr) =
+  static: assert(not compiles(e))
+
+proc genericParamRepeated[T: typedesc](a: T, b: T) =
+  static:
+    echo a.name, " ", b.name
+    
+accept genericParamRepeated(int, int)
+accept genericParamRepeated(float, float)
+
+reject genericParamRepeated(string, int)
+reject genericParamRepeated(int, float)
+
+proc genericParamOnce[T: typedesc](a, b: T) =
+  static:
+    echo a.name, " ", b.name
+
+accept genericParamOnce(int, int)
+accept genericParamOnce(TFoo, TFoo)
+
+reject genericParamOnce(string, int)
+reject genericParamOnce(TFoo, float)
+
+type
+  type1 = typedesc
+  type2 = typedesc
+
+proc typePairs(A, B: type1; C, D: type2) = nil
+
+accept typePairs(int, int, TFoo, TFOO)
+accept typePairs(TBAR, TBar, TBAR, TBAR)
+accept typePairs(int, int, string, string)
+
+reject typePairs(TBAR, TBar, TBar, TFoo)
+reject typePairs(string, int, TBAR, TBAR)
+
+proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil
+
+accept typePairs2(int, int, TFoo, TFOO)
+accept typePairs2(TBAR, TBar, TBAR, TBAR)
+accept typePairs2(int, int, string, string)
+
+reject typePairs2(TBAR, TBar, TBar, TFoo)
+reject typePairs2(string, int, TBAR, TBAR)
+
+proc dontBind(a: typedesc, b: typedesc) =
+  static:
+    echo a.name, " ", b.name
+
+accept dontBind(int, float)
+accept dontBind(TFoo, TFoo)
+
+proc dontBind2(a, b: typedesc) = nil
+
+accept dontBind2(int, float)
+accept dontBind2(TBar, int)
+
+proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil
+
+accept bindArg(int, string, 10, 20, "test", "nest")
+accept bindArg(int, int, 10, 20, 30, 40)
+
+reject bindArg(int, string, 10, "test", "test", "nest")
+reject bindArg(int, int, 10, 20, 30, "test")
+reject bindArg(int, string, 10.0, 20, "test", "nest")
+reject bindArg(int, string, "test", "nest", 10, 20)
+
diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim
new file mode 100644
index 000000000..1cb86e4d7
--- /dev/null
+++ b/tests/metatype/tcompositetypeclasses.nim
@@ -0,0 +1,59 @@
+template accept(e) =
+  static: assert(compiles(e))
+
+template reject(e) =
+  static: assert(not compiles(e))
+
+type
+  TFoo[T, U] = tuple
+    x: T
+    y: U
+
+  TBar[K] = TFoo[K, K]
+
+  TUserClass = int|string
+
+  TBaz = TBar[TUserClass]
+
+var
+  vfoo: TFoo[int, string]
+  vbar: TFoo[string, string]
+  vbaz: TFoo[int, int]
+  vnotbaz: TFoo[TObject, TObject]
+
+proc foo(x: TFoo) = echo "foo"
+proc bar(x: TBar) = echo "bar"
+proc baz(x: TBaz) = echo "baz"
+
+accept foo(vfoo)
+accept bar(vbar)
+accept baz(vbar)
+accept baz(vbaz)
+
+#reject baz(vnotbaz) # XXX this really shouldn't compile
+reject bar(vfoo)
+
+# https://github.com/Araq/Nim/issues/517
+type
+  TVecT*[T] = array[0..1, T]|array[0..2, T]|array[0..3, T]
+  TVec2* = array[0..1, float32]
+
+proc f[T](a: TVecT[T], b: TVecT[T]): T = discard
+
+var x: float = f([0.0'f32, 0.0'f32], [0.0'f32, 0.0'f32])
+var y = f(TVec2([0.0'f32, 0.0'f32]), TVec2([0.0'f32, 0.0'f32]))
+
+# https://github.com/Araq/Nim/issues/602
+type
+  TTest = object
+  TTest2* = object
+  TUnion = TTest | TTest2
+
+proc f(src: ptr TUnion, dst: ptr TUnion) =
+  echo("asd")
+
+var tx: TTest
+var ty: TTest2
+
+accept f(addr tx, addr tx)
+reject f(addr tx, addr ty)
diff --git a/tests/metatype/tconstraints.nim b/tests/metatype/tconstraints.nim
new file mode 100644
index 000000000..7aef0d645
--- /dev/null
+++ b/tests/metatype/tconstraints.nim
@@ -0,0 +1,15 @@
+
+
+proc myGenericProc[T: object|tuple|int|ptr|ref|distinct](x: T): string = 
+  result = $x
+
+type
+  TMyObj = tuple[x, y: int]
+
+var
+  x: TMyObj
+
+assert myGenericProc(232) == "232"
+assert myGenericProc(x) == "(x: 0, y: 0)"
+
+
diff --git a/tests/metatype/tmatrix.nim b/tests/metatype/tmatrix.nim
new file mode 100644
index 000000000..90dfde959
--- /dev/null
+++ b/tests/metatype/tmatrix.nim
@@ -0,0 +1,48 @@
+discard """
+  file: "tmatrix.nim"
+  output: "111"
+"""
+# Test overloading of [] with multiple indices
+
+type
+  TMatrix* = object
+    data: seq[float]
+    fWidth, fHeight: int
+
+template `|`(x, y: int): expr = y * m.fWidth + x
+
+proc createMatrix*(width, height: int): TMatrix = 
+  result.fWidth = width
+  result.fHeight = height
+  newSeq(result.data, width*height)
+
+proc width*(m: TMatrix): int {.inline.} = return m.fWidth
+proc height*(m: TMatrix): int {.inline.} = return m.fHeight
+
+proc `[]`*(m: TMatrix, x, y: int): float {.inline.} =
+  result = m.data[x|y]
+
+proc `[]=`*(m: var TMatrix, x, y: int, val: float) {.inline.} =
+  m.data[x|y] = val
+  
+proc `-|`*(m: TMatrix): TMatrix =
+  ## transposes a matrix
+  result = createMatrix(m.height, m.width)
+  for x in 0..m.width-1:
+    for y in 0..m.height-1: result[y,x] = m[x,y]
+
+#m.row(0, 2) # select row
+#m.col(0, 89) # select column
+
+const
+  w = 3
+  h = 20
+
+var m = createMatrix(w, h)
+for i in 0..w-1:
+  m[i, i] = 1.0
+
+for i in 0..w-1:
+  stdout.write(m[i,i]) #OUT 111
+
+
diff --git a/tests/metatype/tmatrix1.nim b/tests/metatype/tmatrix1.nim
new file mode 100644
index 000000000..0adf30b57
--- /dev/null
+++ b/tests/metatype/tmatrix1.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "right proc called"
+"""
+
+type
+  TMatrixNM*[M, N, T] = object 
+    aij*: array[M, array[N, T]]
+  TMatrix2x2*[T] = TMatrixNM[range[0..1], range[0..1], T]
+  TMatrix3x3*[T] = TMatrixNM[range[0..2], range[0..2], T]
+
+proc test*[T] (matrix: TMatrix2x2[T]) =
+  echo "wrong proc called"
+
+proc test*[T] (matrix: TMatrix3x3[T]) =
+  echo "right proc called"  
+
+var matrix: TMatrix3x3[float]
+
+matrix.test
diff --git a/tests/metatype/tmatrix2.nim b/tests/metatype/tmatrix2.nim
new file mode 100644
index 000000000..82990f1a5
--- /dev/null
+++ b/tests/metatype/tmatrix2.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "5.0"
+"""
+
+type
+  TMatrixNM*[M, N, T] = object 
+    aij*: T
+  TVectorN*[N, T] = TMatrixNM[range[0..0], N, T]
+  TVector3*[T] = TVectorN[range[0..2], T]
+
+proc coeffRef*[M, N, T] (matrix: var TMatrixNM[M, N, T], a: M, b: N): var T =
+  return matrix.aij
+
+proc coeffRef*[N, T] (vector: var TVectorN[N, T], i: N): var T = vector.aij
+
+var 
+  testVar: TVector3[float]
+
+testVar.aij = 2.0
+testVar.coeffRef(1) = 5.0
+
+echo testVar.aij
diff --git a/tests/metatype/tmatrix3.nim b/tests/metatype/tmatrix3.nim
new file mode 100644
index 000000000..a143e2bc9
--- /dev/null
+++ b/tests/metatype/tmatrix3.nim
@@ -0,0 +1,19 @@
+discard """
+  output: ""
+"""
+
+type Matrix[M,N: static[int]] = array[M, array[N, float]]
+
+let a = [[1.0,  1.0,  1.0,   1.0],
+         [2.0,  4.0,  8.0,  16.0],
+         [3.0,  9.0, 27.0,  81.0],
+         [4.0, 16.0, 64.0, 256.0]]
+
+proc `$`(m: Matrix): string =
+  result = ""
+
+proc `*`[M,N,M2,N2](a: Matrix[M,N2]; b: Matrix[M2,N]): Matrix[M,N] =
+  discard
+
+echo a * a
+
diff --git a/tests/metatype/tsemistatic.nim b/tests/metatype/tsemistatic.nim
new file mode 100644
index 000000000..a13175ba8
--- /dev/null
+++ b/tests/metatype/tsemistatic.nim
@@ -0,0 +1,31 @@
+discard """
+  msg: "static 10\ndynamic\nstatic 20\n"
+  output: "s\nd\nd\ns"
+"""
+
+type
+  semistatic[T] =
+    static[T] or T
+
+template isStatic*(x): expr =
+  compiles(static(x))
+
+proc foo(x: semistatic[int]) =
+  when isStatic(x):
+    static: echo "static ", x
+    echo "s"
+  else:
+    static: echo "dynamic"
+    echo "d"
+
+foo 10
+
+var
+  x = 10
+  y: int
+
+foo x
+foo y
+
+foo 20
+
diff --git a/tests/metatype/tstatic_overloading.nim b/tests/metatype/tstatic_overloading.nim
new file mode 100644
index 000000000..ce51052b7
--- /dev/null
+++ b/tests/metatype/tstatic_overloading.nim
@@ -0,0 +1,10 @@
+# bug #2266
+
+import macros
+
+proc impl(op: static[int]) = echo "impl 1 called"
+proc impl(op: static[int], init: int) = echo "impl 2 called"
+
+macro wrapper2: stmt = newCall(bindSym"impl", newLit(0), newLit(0))
+
+wrapper2() # Code generation for this fails.
diff --git a/tests/metatype/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim
new file mode 100644
index 000000000..e577efc56
--- /dev/null
+++ b/tests/metatype/tstaticparammacro.nim
@@ -0,0 +1,75 @@
+discard """
+  msg: '''letters
+aa
+bb
+numbers
+11
+22
+AST a 
+[(11, 22), (33, 44)]
+AST b 
+(e: [55, 66], f: [77, 88])
+55
+10
+20Test
+20
+'''
+  disabled: true
+"""
+
+import macros
+
+type
+  TConfig = tuple
+    letters: seq[string]
+    numbers:seq[int]
+
+const data: Tconfig = (@["aa", "bb"], @[11, 22])
+
+macro mymacro(data: static[TConfig]): stmt =
+  echo "letters"
+  for s in items(data.letters):
+    echo s
+  echo "numbers"
+  for n in items(data.numbers):
+    echo n
+
+mymacro(data)
+
+type
+  Ta = seq[tuple[c:int, d:int]]
+  Tb = tuple[e:seq[int], f:seq[int]]
+
+const
+  a : Ta = @[(11, 22), (33, 44)]
+  b : Tb = (@[55,66], @[77, 88])
+
+macro mA(data: static[Ta]): stmt =
+  echo "AST a \n", repr(data)
+
+macro mB(data: static[Tb]): stmt =
+  echo "AST b \n", repr(data)
+  echo data.e[0]
+
+mA(a)
+mB(b)
+
+type
+  Foo[N: static[int], Z: static[string]] = object
+
+macro staticIntMacro(f: static[int]): stmt = echo f
+staticIntMacro 10
+
+var
+  x: Foo[20, "Test"]
+
+macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): stmt =
+  echo N, Z
+
+genericMacro x
+
+template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
+
+static:
+  echo genericTemplate(x) # Error: internal error: (filename: compiler/evaltempl.nim, line: 39)
+
diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim
new file mode 100644
index 000000000..7fc5f479b
--- /dev/null
+++ b/tests/metatype/tstaticparams.nim
@@ -0,0 +1,142 @@
+discard """
+  file: "tstaticparams.nim"
+  output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang"
+"""
+
+type 
+  TFoo[T; Val: static[string]] = object
+    data: array[4, T]
+
+  TBar[T; I: static[int]] = object
+    data: array[I, T]
+
+  TA1[T; I: static[int]] = array[I, T]
+  TA2[T; I: static[int]] = array[0..I, T]
+  TA3[T; I: static[int]] = array[I-1, T]
+
+  TObj = object
+    x: TA3[int, 3]
+
+proc takeFoo(x: TFoo) =
+  echo "abracadabra"
+  echo TFoo.Val
+
+var x: TFoo[int, "test"]
+takeFoo(x)
+
+var y: TBar[float, 4]
+echo high(y.data)
+
+var
+  t1: TA1[float, 1]
+  t2: TA2[string, 4]
+  t3: TA3[int, 10]
+  t4: TObj
+
+# example from the manual:
+type
+  Matrix[M,N: static[int]; T] = array[0..(M*N - 1), T]
+    # Note how `Number` is just a type constraint here, while
+    # `static[int]` requires us to supply a compile-time int value
+
+  AffineTransform2D[T] = Matrix[3, 3, T]
+  AffineTransform3D[T] = Matrix[4, 4, T]
+
+var m: AffineTransform3D[float]
+echo high(m)
+
+proc getRows(mtx: Matrix): int =
+  result = mtx.M
+
+echo getRows(m)
+
+# issue 997
+type TTest[T: static[int], U: static[int]] = array[0..T*U, int]
+type TTestSub[N: static[int]] = TTest[1, N]
+
+var z: TTestSub[2]
+echo z.high
+
+# issue 1049
+proc matrix_1*[M, N, T](mat: Matrix[M,N,T], a: array[N, int]) = discard
+proc matrix_2*[M, N, T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
+
+proc matrix_3*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N, int]) = discard
+proc matrix_4*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
+
+var
+  tmat: Matrix[4,4,int]
+  ar1: array[4, int]
+  ar2: array[5, int]
+
+matrix_1(tmat, ar1)
+matrix_2(tmat, ar2)
+matrix_3(tmat, ar1)
+matrix_4(tmat, ar2)
+
+template reject(x): stmt =
+  static: assert(not compiles(x))
+
+# test with arrays of wrong size
+reject matrix_1(tmat, ar2)
+reject matrix_2(tmat, ar1)
+reject matrix_3(tmat, ar2)
+reject matrix_4(tmat, ar1)
+
+# bug 1820
+
+type
+  T1820_1[T; Y: static[int]] = object
+    bar: T
+
+proc intOrFloat*[Y](f: T1820_1[int, Y]) = echo "int"
+proc intOrFloat*[Y](f: T1820_1[float, Y]) = echo "float"
+proc threeOrFour*[T](f: T1820_1[T, 3]) =  echo "3"
+proc threeOrFour*[T](f: T1820_1[T, 4]) = echo "4"
+
+var foo_1: T1820_1[float, 3]
+
+foo_1.intOrFloat
+foo_1.threeOrFour
+
+type
+  YinAndYang = enum
+    Yin,
+    Yang
+
+  T1820_2[T; Y: static[YinAndYang]] = object
+    bar: T
+
+proc intOrFloat*[Y](f: T1820_2[int, Y]) = echo "int"
+proc intOrFloat*[Y](f: T1820_2[float, Y]) = echo "float"
+proc yinOrYang*[T](f: T1820_2[T, YinAndYang.Yin]) = echo "yin"
+proc yinOrYang*[T](f: T1820_2[T, Yang]) = echo "yang"
+
+var foo_2: T1820_2[float, Yin]
+var foo_3: T1820_2[float, YinAndYang.Yang]
+
+foo_2.intOrFloat
+foo_2.yinOrYang
+foo_3.yinOrYang
+
+# bug 1859
+
+type 
+  TypeWith2Params[N, M: static[int]] = object
+
+proc bindBothParams[N](x: TypeWith2Params[N, N]) = discard
+proc dontBind1[N,M](x: TypeWith2Params[N, M]) = discard
+proc dontBind2(x: TypeWith2Params) = discard
+
+var bb_1: TypeWith2Params[2, 2]
+var bb_2: TypeWith2Params[2, 3]
+
+bindBothParams(bb_1)
+reject bindBothParams(bb_2)
+
+dontBind1 bb_1
+dontBind1 bb_2
+
+dontBind2 bb_1
+dontBind2 bb_2
+
diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim
new file mode 100644
index 000000000..c9923f469
--- /dev/null
+++ b/tests/metatype/tstaticvector.nim
@@ -0,0 +1,17 @@
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+   
+  StaticMatrix*[R, C: static[int], T] = object
+    elements*: RectArray[R, C, T]
+   
+  StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T]
+ 
+proc foo*[N, T](a: StaticVector[N, T]): T = 0.T
+proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T
+ 
+ 
+var a: StaticVector[3, int]
+ 
+echo foo(a) # OK
+echo foobar(a, a) # <--- hangs compiler 
diff --git a/tests/metatype/ttypebar.nim b/tests/metatype/ttypebar.nim
new file mode 100644
index 000000000..304dfffcb
--- /dev/null
+++ b/tests/metatype/ttypebar.nim
@@ -0,0 +1,14 @@
+
+# bug #602
+
+type
+  TTest = object
+  TTest2* = object
+  TFoo = TTest | TTest2
+
+proc f(src: ptr TFoo, dst: ptr TFoo) =
+  echo("asd")
+
+var x: TTest
+f(addr x, addr x)
+
diff --git a/tests/metatype/ttypeclasses.nim b/tests/metatype/ttypeclasses.nim
new file mode 100644
index 000000000..db9db7713
--- /dev/null
+++ b/tests/metatype/ttypeclasses.nim
@@ -0,0 +1,70 @@
+discard """
+  output: '''12
+1xxx
+true0
+12
+testtest
+1010
+11string
+testtest1
+seq
+seq
+seq
+foo seq
+foo of numeric'''"""
+
+type
+  TFoo[T] = object
+    val: T
+
+  T1 = expr
+  T2 = expr
+
+  Numeric = int|float
+
+proc takesExpr(x, y) =
+  echo x, y
+
+proc same(x, y: T1) =
+  echo x, y
+
+proc takesFoo(x, y: TFoo) =
+  echo x.val, y.val
+
+proc takes2Types(x,y: T1, z: T2) =
+  echo x, y, z
+
+takesExpr(1, 2)
+takesExpr(1, "xxx")
+takesExpr[bool, int](true, 0)
+
+same(1, 2)
+same("test", "test")
+
+var f: TFoo[int]
+f.val = 10
+
+takesFoo(f, f)
+
+takes2Types(1, 1, "string")
+takes2Types[string, int]("test", "test", 1)
+
+proc takesSeq(x: seq) =
+  echo "seq"
+
+takesSeq(@[1, 2, 3])
+takesSeq(@["x", "y", "z"])
+
+proc takesSeqOfFoos(x: seq[TFoo]) =
+  echo "foo seq"
+
+var sf = newSeq[TFoo[int]](3)
+
+takesSeq(sf)
+takesSeqOfFoos(sf)
+
+proc takesFooOfNumeric(x: TFoo[Numeric]) =
+  echo "foo of numeric"
+
+takesFooOfNumeric(sf[0])
+
diff --git a/tests/metatype/ttypedesc1.nim b/tests/metatype/ttypedesc1.nim
new file mode 100644
index 000000000..0c6f5dce4
--- /dev/null
+++ b/tests/metatype/ttypedesc1.nim
@@ -0,0 +1,42 @@
+import unittest, typetraits
+
+type 
+  TFoo[T, U] = object
+    x: T
+    y: U
+
+proc getTypeName(t: typedesc): string = t.name
+
+proc foo(T: typedesc[float], a: expr): string =
+  result = "float " & $(a.len > 5)
+
+proc foo(T: typedesc[TFoo], a: int): string =
+  result = "TFoo "  & $(a)
+
+proc foo(T: typedesc[int or bool]): string =
+  var a: T
+  a = 10
+  result = "int or bool " & ($a)
+
+template foo(T: typedesc[seq]): expr = "seq"
+
+test "types can be used as proc params":
+  # XXX: `check` needs to know that TFoo[int, float] is a type and 
+  # cannot be assigned for a local variable for later inspection
+  check ((string.getTypeName == "string"))
+  check ((getTypeName(int) == "int"))
+  
+  check ((foo(TFoo[int, float], 1000) == "TFoo 1000"))
+  
+  var f = 10.0
+  check ((foo(float, "long string") == "float true"))
+  check ((foo(type(f), [1, 2, 3]) == "float false"))
+  
+  check ((foo(int) == "int or bool 10"))
+
+  check ((foo(seq[int]) == "seq"))
+  check ((foo(seq[TFoo[bool, string]]) == "seq"))
+
+when false:
+  proc foo(T: typedesc[seq], s: T) = nil
+
diff --git a/tests/metatype/ttypedesc2.nim b/tests/metatype/ttypedesc2.nim
new file mode 100644
index 000000000..e576ec91a
--- /dev/null
+++ b/tests/metatype/ttypedesc2.nim
@@ -0,0 +1,37 @@
+discard """
+  output: "(x: a)"
+"""
+
+type
+  Bar[T] = object
+    x: T
+
+proc infer(T: typeDesc): Bar[T] = Bar[T](x: 'a')
+
+let foo = infer(char)
+echo foo
+
+when true:
+  # bug #1783
+
+  type
+      uoffset_t* = uint32
+      FlatBufferBuilder* = object
+
+      uarray* {.unchecked.} [T]  = array [0..0, T]
+      Array* [T] = object
+          o*: uoffset_t
+          len*: int
+          data*: ptr uarray[T]
+
+  proc ca* (fbb: ptr FlatBufferBuilder, T: typedesc, len: int): Array[T] {.noinit.} =
+      result.len = len
+
+  var fbb: ptr FlatBufferBuilder
+  let boolarray = ca(fbb, bool, 2)
+  let boolarray2 = fbb.ca(bool, 2)
+
+# bug #1664
+type Point[T] = tuple[x, y: T]
+proc origin(T: typedesc): Point[T] = discard
+discard origin(int)
diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim
new file mode 100644
index 000000000..3d40b25b2
--- /dev/null
+++ b/tests/metatype/ttypedesc3.nim
@@ -0,0 +1,19 @@
+import typetraits
+
+type
+  Base = object of RootObj
+  Child = object of Base
+
+proc pr(T: typedesc[Base]) = echo "proc " & T.name
+method me(T: typedesc[Base]) = echo "method " & T.name
+iterator it(T: typedesc[Base]) = yield "yield " & T.name
+
+Base.pr
+Child.pr
+
+Base.me
+when false:
+  Child.me #<- bug #2710
+
+for s in Base.it: echo s
+for s in Child.it: echo s #<- bug #2662
diff --git a/tests/metatype/ttypeselectors.nim b/tests/metatype/ttypeselectors.nim
new file mode 100644
index 000000000..cca643e1f
--- /dev/null
+++ b/tests/metatype/ttypeselectors.nim
@@ -0,0 +1,39 @@
+import macros
+
+template selectType(x: int): typeDesc =
+  when x < 10:
+    int
+  else:
+    string
+
+template simpleTypeTempl: typeDesc =
+  string
+
+macro typeFromMacro: typedesc = string
+  
+proc t1*(x: int): simpleTypeTempl() =
+  result = "test"
+
+proc t2*(x: int): selectType(100) =
+  result = "test"
+
+proc t3*(x: int): selectType(1) =
+  result = 10
+
+proc t4*(x: int): typeFromMacro() =
+  result = "test"
+
+var x*: selectType(50) = "test"
+
+proc t5*(x: selectType(5)) =
+  var y = x + 10
+  echo y
+
+var y*: type(t2(100)) = "test"
+
+proc t6*(x: type(t3(0))): type(t1(0)) =
+  result = $x
+
+proc t7*(x: int): type($x) =
+  result = "test"
+
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
new file mode 100644
index 000000000..4c3ad9e0b
--- /dev/null
+++ b/tests/metatype/ttypetraits.nim
@@ -0,0 +1,60 @@
+discard """
+  msg:    "int\nstring\nTBar[int]"
+  output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
+  disabled: true
+"""
+
+import typetraits
+
+# simple case of type trait usage inside/outside of static blocks
+proc foo(x) =
+  static:
+    var t = type(x)
+    echo t.name
+
+  echo x.type.name
+
+type
+  TBar[U] = object
+    x: U
+
+var bar: TBar[int]
+
+foo 10
+foo "test"
+foo bar
+
+# generic params on user types work too
+proc foo2[T](x: TBar[T]) =
+  echo T.name
+
+foo2 bar
+
+# less usual generic params on built-in types
+var arr: array[0..2, int] = [1, 2, 3]
+
+proc foo3[R, T](x: array[R, T]) =
+  echo name(R)
+
+foo3 arr
+
+const TypeList = [int, string, seq[int]]
+
+macro selectType(inType: typedesc): typedesc =
+  var typeSeq = @[float, TBar[int]]
+  
+  for t in TypeList:
+    typeSeq.add(t)
+
+  typeSeq.add(inType)
+  typeSeq.add(type(10))
+  
+  var typeSeq2: seq[typedesc] = @[]
+  typeSeq2 = typeSeq
+
+  result = typeSeq2[5]
+  
+var xvar: selectType(string)
+xvar = "proba"
+echo xvar.type.name
+
diff --git a/tests/metatype/tymatrix.nim b/tests/metatype/tymatrix.nim
new file mode 100644
index 000000000..7d3d52f85
--- /dev/null
+++ b/tests/metatype/tymatrix.nim
@@ -0,0 +1,23 @@
+import typetraits
+
+template reject(e: expr) =
+  static: assert(not compiles(e))
+
+type
+  TMatrix[T; M, N: static[int]] = array[M*N, T]
+
+proc `*`[T; R, N, C](a: TMatrix[T, R, N], b: TMatrix[T, N, C]): TMatrix[T, R, C] =
+  discard
+
+var m1: TMatrix[int, 6, 4]
+var m2: TMatrix[int, 4, 3]
+var m3: TMatrix[int, 3, 3]
+
+var m4 = m1*m2
+static: assert m4.M == 6 and m4.N == 3
+
+reject m1 * m3 # not compatible
+
+var m5 = m2 * m3
+static: assert high(m5) == 11 # 4*3 - 1
+
diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim
new file mode 100644
index 000000000..fd2d307a9
--- /dev/null
+++ b/tests/metatype/typeclassinference.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "type mismatch: got (string) but expected 'ptr'"
+  line: 20
+  disabled: true
+"""
+
+import typetraits
+
+type
+  Vec[N: static[int]; T] = distinct array[N, T]
+
+var x = Vec([1, 2, 3])
+
+static:
+  assert x.type.name == "Vec[static[int](3), int]"
+
+var str1: string = "hello, world!"
+var ptr1: ptr = addr(str1)
+
+var str2: string = "hello, world!"
+var ptr2: ptr = str2
+
diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim
new file mode 100644
index 000000000..f6e526987
--- /dev/null
+++ b/tests/metatype/typedesc_as_value.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?"
+"""
+
+
+var x = int
+
+echo x
+
+
+
diff --git a/tests/metatype/utypeclasses.nim b/tests/metatype/utypeclasses.nim
new file mode 100644
index 000000000..06bab375e
--- /dev/null
+++ b/tests/metatype/utypeclasses.nim
@@ -0,0 +1,13 @@
+import unittest
+
+proc concat(a, b): string =
+  result = $a & $b
+
+test "if proc param types are not supplied, the params are assumed to be generic":
+  check concat(1, "test") == "1test"
+  check concat(1, 20) == "120"
+  check concat("foo", "bar") == "foobar"
+
+test "explicit param types can still be specified":
+  check concat[cstring, cstring]("x", "y") == "xy"
+
diff --git a/tests/method/mmultim3.nim b/tests/method/mmultim3.nim
new file mode 100644
index 000000000..3139a8089
--- /dev/null
+++ b/tests/method/mmultim3.nim
@@ -0,0 +1,12 @@
+type
+    TObj* = object {.inheritable.}
+
+var myObj* : ref TObj
+
+method test123(a : ref TObj) =
+    echo("Hi base!")
+
+proc testMyObj*() =
+    test123(myObj)
+
+
diff --git a/tests/method/temptybody.nim b/tests/method/temptybody.nim
new file mode 100644
index 000000000..26285d05b
--- /dev/null
+++ b/tests/method/temptybody.nim
@@ -0,0 +1,11 @@
+# bug #2401
+
+type MyClass = ref object of RootObj
+
+method HelloWorld*(obj: MyClass) =
+  when defined(myPragma):
+    echo("Hello World")
+  # discard # with this line enabled it works
+
+var obj = MyClass()
+obj.HelloWorld()
diff --git a/tests/method/tmethod.nim b/tests/method/tmethod.nim
new file mode 100644
index 000000000..0cfe24c70
--- /dev/null
+++ b/tests/method/tmethod.nim
@@ -0,0 +1,8 @@
+discard """
+  file: "tmethod.nim"
+  line: 7
+  errormsg: "\'method\' needs a parameter that has an object type"
+"""
+
+method m(i: int): int =
+  return 5
diff --git a/tests/method/tmethods1.nim b/tests/method/tmethods1.nim
new file mode 100644
index 000000000..43a260bca
--- /dev/null
+++ b/tests/method/tmethods1.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "do nothing"
+"""
+
+method somethin(obj: TObject) =
+  echo "do nothing"
+
+type
+  TNode* = object {.inheritable.}
+  PNode* = ref TNode
+
+  PNodeFoo* = ref object of TNode
+
+  TSomethingElse = object 
+  PSomethingElse = ref TSomethingElse
+
+method foo(a: PNode, b: PSomethingElse) = discard
+method foo(a: PNodeFoo, b: PSomethingElse) = discard
+
+var o: TObject
+o.somethin()
+
diff --git a/tests/method/tmproto.nim b/tests/method/tmproto.nim
new file mode 100644
index 000000000..5d75cff1a
--- /dev/null
+++ b/tests/method/tmproto.nim
@@ -0,0 +1,25 @@
+type
+  Obj1 = ref object {.inheritable.}
+  Obj2 = ref object of Obj1
+
+method beta(x: Obj1): int
+
+proc delta(x: Obj2): int =
+  beta(x)
+
+method beta(x: Obj2): int
+
+proc alpha(x: Obj1): int =
+  beta(x)
+
+method beta(x: Obj1): int = 1
+method beta(x: Obj2): int = 2
+
+proc gamma(x: Obj1): int =
+  beta(x)
+
+doAssert alpha(Obj1()) == 1
+doAssert gamma(Obj1()) == 1
+doAssert alpha(Obj2()) == 2
+doAssert gamma(Obj2()) == 2
+doAssert delta(Obj2()) == 2
diff --git a/tests/method/tmultim1.nim b/tests/method/tmultim1.nim
new file mode 100644
index 000000000..7f551aa64
--- /dev/null
+++ b/tests/method/tmultim1.nim
@@ -0,0 +1,29 @@
+discard """
+  file: "tmultim1.nim"
+  output: "7"
+"""
+# Test multi methods
+
+type
+  Expression = ref object {.inheritable.}
+  Literal = ref object of Expression
+    x: int
+  PlusExpr = ref object of Expression
+    a, b: Expression
+    
+method eval(e: Expression): int = quit "to override!"
+method eval(e: Literal): int = return e.x
+method eval(e: PlusExpr): int = return eval(e.a) + eval(e.b)
+
+proc newLit(x: int): Literal =
+  new(result)
+  result.x = x
+  
+proc newPlus(a, b: Expression): PlusExpr =
+  new(result)
+  result.a = a
+  result.b = b
+
+echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) #OUT 7
+
+
diff --git a/tests/method/tmultim2.nim b/tests/method/tmultim2.nim
new file mode 100644
index 000000000..c5fb568a0
--- /dev/null
+++ b/tests/method/tmultim2.nim
@@ -0,0 +1,39 @@
+discard """
+  file: "tmultim2.nim"
+  output: '''collide: unit, thing
+collide: unit, thing
+collide: thing, unit
+collide: thing, thing'''
+"""
+# Test multi methods
+
+type
+  TThing = object {.inheritable.}
+  TUnit = object of TThing
+    x: int
+  TParticle = object of TThing
+    a, b: int
+    
+method collide(a, b: TThing) {.inline.} =
+  echo "collide: thing, thing"
+  
+method collide(a: TThing, b: TUnit) {.inline.} =
+  echo "collide: thing, unit"
+
+method collide(a: TUnit, b: TThing) {.inline.} =
+  echo "collide: unit, thing"
+
+proc test(a, b: TThing) {.inline.} =
+  collide(a, b)
+
+proc staticCollide(a, b: TThing) {.inline.} =
+  procCall collide(a, b)
+
+
+var
+  a: TThing
+  b, c: TUnit
+collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing!
+test(b, c)
+collide(a, b)
+staticCollide(a, b)
diff --git a/tests/method/tmultim3.nim b/tests/method/tmultim3.nim
new file mode 100644
index 000000000..373c84c0e
--- /dev/null
+++ b/tests/method/tmultim3.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "tmultim3.nim"
+  output: "Hi derived!"
+"""
+import mmultim3
+
+type
+    TBObj* = object of TObj
+
+
+method test123(a : ref TBObj) =
+    echo("Hi derived!")
+
+var a : ref TBObj
+new(a)
+myObj = a
+testMyObj()
+
+
+
diff --git a/tests/method/tmultim4.nim b/tests/method/tmultim4.nim
new file mode 100644
index 000000000..d824086b2
--- /dev/null
+++ b/tests/method/tmultim4.nim
@@ -0,0 +1,47 @@
+discard """
+  file: "tmultim4.nim"
+  output: "hello"
+"""
+type
+  Test = object of TObject
+
+method doMethod(a: ref TObject) {.raises: [EIO].} =
+  quit "override"
+
+method doMethod(a: ref Test) =
+  echo "hello"
+  if a == nil:
+    raise newException(EIO, "arg")
+
+proc doProc(a: ref Test) =
+  echo "hello"
+
+proc newTest(): ref Test =
+  new(result)
+
+var s:ref Test = newTest()
+
+
+#doesn't work
+for z in 1..4:
+  s.doMethod()
+  break
+ 
+#works
+#for z in 1..4:
+#  s.doProc()
+#  break
+
+#works
+#while true:
+#  s.doMethod()
+#  break
+
+#works
+#while true:
+#  s.doProc()
+#  break
+
+
+
+
diff --git a/tests/method/tmultim6.nim b/tests/method/tmultim6.nim
new file mode 100644
index 000000000..5f45f572a
--- /dev/null
+++ b/tests/method/tmultim6.nim
@@ -0,0 +1,30 @@
+discard """
+  output: "collide: unit, thing | collide: unit, thing | collide: thing, unit |"
+"""
+# Test multi methods
+
+type
+  TThing = object {.inheritable.}
+  TUnit[T] = object of TThing
+    x: T
+  TParticle = object of TThing
+    a, b: int
+    
+method collide(a, b: TThing) {.inline.} =
+  quit "to override!"
+  
+method collide[T](a: TThing, b: TUnit[T]) {.inline.} =
+  write stdout, "collide: thing, unit | "
+
+method collide[T](a: TUnit[T], b: TThing) {.inline.} =
+  write stdout, "collide: unit, thing | "
+
+proc test(a, b: TThing) {.inline.} =
+  collide(a, b)
+
+var
+  a: TThing
+  b, c: TUnit[string]
+collide(b, TThing(c))
+test(b, c)
+collide(a, b)
diff --git a/tests/method/trecmeth.nim b/tests/method/trecmeth.nim
new file mode 100644
index 000000000..32f620f15
--- /dev/null
+++ b/tests/method/trecmeth.nim
@@ -0,0 +1,22 @@
+# Note: We only compile this to verify that code generation
+# for recursive methods works, no code is being executed
+
+type
+  Obj = ref object of TObject
+
+# Mutual recursion
+
+method alpha(x: Obj)
+method beta(x: Obj)
+
+method alpha(x: Obj) =
+  beta(x)
+
+method beta(x: Obj) =
+  alpha(x)
+
+# Simple recursion
+
+method gamma(x: Obj) =
+  gamma(x)
+
diff --git a/tests/method/tsimmeth.nim b/tests/method/tsimmeth.nim
new file mode 100644
index 000000000..11ff2674f
--- /dev/null
+++ b/tests/method/tsimmeth.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "tsimmeth.nim"
+  output: "HELLO WORLD!"
+"""
+# Test method simulation
+
+import strutils
+
+var x = "hello world!".toLower.toUpper
+x.echo()
+#OUT HELLO WORLD!
+
+
+
diff --git a/tests/misc/99bottles.nim b/tests/misc/99bottles.nim
new file mode 100644
index 000000000..14904ac0f
--- /dev/null
+++ b/tests/misc/99bottles.nim
@@ -0,0 +1 @@
+# Test if the compiler detects invalid module names
diff --git a/tests/misc/minit.nim b/tests/misc/minit.nim
new file mode 100644
index 000000000..75fcebb77
--- /dev/null
+++ b/tests/misc/minit.nim
@@ -0,0 +1,2 @@
+# Test the new initialization for modules

+write(stdout, "Hello from module! ")

diff --git a/tests/misc/mvarious.nim b/tests/misc/mvarious.nim
new file mode 100644
index 000000000..c0a8add73
--- /dev/null
+++ b/tests/misc/mvarious.nim
@@ -0,0 +1,6 @@
+# Test a submodule

+

+#type

+#  TStringArr = array [0.. *] of string

+

+proc exportme* = discard

diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim
new file mode 100644
index 000000000..68a61373f
--- /dev/null
+++ b/tests/misc/parsecomb.nim
@@ -0,0 +1,105 @@
+type Input[T] = object
+  toks: seq[T]
+  index: int
+
+type
+  ResultKind* = enum rkSuccess, rkFailure
+  Result*[T, O] = object
+    case kind*: ResultKind
+    of rkSuccess:
+      output*: O
+      input: Input[T]
+    of rkFailure:
+      nil
+
+type
+  Parser*[T, O] = distinct proc (input: Input[T]): Result[T, O]
+
+proc unit*[T, O](v: O): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    Result[T, O](kind: rkSuccess, output: v, input: inp))
+
+proc fail*[T, O](): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    Result(kind: rkFailure))
+
+method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] =
+  # hmmm ..
+  type tmp = proc (input: Input[T]): Result[T, O]
+  # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C.
+  tmp(self)(inp)
+
+method run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] =
+  self.runInput(Input[T](toks: toks, index: 0))
+
+method chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] =
+  Parser(proc (inp: Input[T]): Result[T, O2] =
+    let r = self.runInput(inp)
+    case r.kind:
+    of rkSuccess:
+      nextp(r.output).runInput(r.input)
+    of rkFailure:
+      Result[T, O2](kind: rkFailure))
+
+method skip[T](self: Input[T], n: int): Input[T] =
+  Input[T](toks: self.toks, index: self.index + n)
+
+proc pskip*[T](n: int): Parser[T, tuple[]] =
+  Parser(proc (inp: Input[T]): Result[T, tuple[]] =
+    if inp.index + n <= inp.toks.len:
+      Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n))
+    else:
+      Result[T, tuple[]](kind: rkFailure))
+
+proc tok*[T](t: T): Parser[T, T] =
+  Parser(proc (inp: Input[T]): Result[T, T] =
+    if inp.index < inp.toks.len and inp.toks[inp.index] == t:
+      pskip[T](1).then(unit[T, T](t)).runInput(inp)
+    else:
+      Result[T, T](kind: rkFailure))
+
+proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] =
+  Parser(proc (inp: Input[T]): Result[T, O] =
+    let r = first.runInput(inp)
+    case r.kind
+    of rkSuccess:
+      r
+    else:
+      second.runInput(inp))
+
+# end of primitives (definitions involving Parser(..))
+
+method map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    unit[T, O2](p(v)))
+
+method then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    next)
+
+proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] =
+  first.chain(proc (v1: O1): Parser[T, (O1, O2)] =
+    second.map(proc (v2: O2): (O1, O2) =
+      (v1, v2)))
+
+proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  var nothing = unit[T, seq[O]](@[])
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs)) + nothing
+
+proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs))
+
+proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] =
+  (inner*repeat0(after)).map(proc(ias: (O, seq[A])): O =
+    var (i, asx) = ias
+    for a in asx:
+      i = fold(i, a)
+    i)
+
+proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] =
+  unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] =
+    inner())
diff --git a/tests/misc/t99bott.nim b/tests/misc/t99bott.nim
new file mode 100644
index 000000000..b3b30d296
--- /dev/null
+++ b/tests/misc/t99bott.nim
@@ -0,0 +1,36 @@
+discard """
+  file: "t99bott.nim"
+  line: 26
+  errormsg: "cannot evaluate at compile time: bn"
+  disabled: false
+"""
+## 99 Bottles of Beer
+## http://www.99-bottles-of-beer.net/
+## Nim version
+
+## Author: Philippe Lhoste <PhiLho(a)GMX.net> http://Phi.Lho.free.fr
+# 2012-11-25
+# Loosely based on my old Lua version... Updated to current official lyrics.
+
+proc GetBottleNumber(n: int): string =
+  var bs: string
+  if n == 0:
+    bs = "No more bottles"
+  elif n == 1:
+    bs = "1 bottle"
+  else:
+    bs = $n & " bottles"
+  return bs & " of beer"
+
+for bn in countdown(99, 1):
+  const cur = GetBottleNumber(bn)
+  echo(cur, " on the wall, ", cur, ".")
+  echo("Take one down and pass it around, ", GetBottleNumber(bn-1), 
+       " on the wall.\n")
+
+echo "No more bottles of beer on the wall, no more bottles of beer."
+echo "Go to the store and buy some more, 99 bottles of beer on the wall."
+
+
+
+
diff --git a/tests/misc/tack.nim b/tests/misc/tack.nim
new file mode 100644
index 000000000..680ff567e
--- /dev/null
+++ b/tests/misc/tack.nim
@@ -0,0 +1,21 @@
+discard """
+  file: "tack.nim"
+  output: "125"
+"""
+# the Ackermann function

+

+proc ack(x, y: int): int =

+  if x != 0:

+    if y != 0:

+      return ack(x-1, ack(x, y-1))

+    return ack(x-1, 1)

+  else:

+    return y + 1

+#  if x == 0: return y + 1

+#  elif y == 0: return ack(x-1, 1)

+#  else: return ack(x-1, ack(x, y-1))

+

+# echo(ack(0, 0))

+write(stdout, ack(3, 4)) #OUT 125

+
+
diff --git a/tests/misc/tatomic.nim b/tests/misc/tatomic.nim
new file mode 100644
index 000000000..1fa0cff8d
--- /dev/null
+++ b/tests/misc/tatomic.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tatomic.nim"
+  line: 7
+  errormsg: "identifier expected, but found 'keyword atomic'"
+"""
+var 
+  atomic: int
+  
+echo atomic
+
+
+
diff --git a/tests/misc/tbug1217bracketquotes.nim b/tests/misc/tbug1217bracketquotes.nim
new file mode 100644
index 000000000..90e67d45b
--- /dev/null
+++ b/tests/misc/tbug1217bracketquotes.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "13{(.{}}{*4&*$**()&*@1235"
+"""
+
+type
+  Test = enum
+    `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`
+
+let `.}` = 1
+let `(}` = 2
+let `[` = 3
+let `]` = 5
+
+echo `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`, `.}`, `(}`, `[`, `]`
diff --git a/tests/misc/tbug511622.nim b/tests/misc/tbug511622.nim
new file mode 100644
index 000000000..a5360423d
--- /dev/null
+++ b/tests/misc/tbug511622.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tbug511622.nim"
+  output: "3"
+"""
+import StrUtils, Math
+
+proc FibonacciA(n: int): int64 =
+  var fn = float64(n)
+  var p: float64 = (1.0 + sqrt(5.0)) / 2.0
+  var q: float64 = 1.0 / p
+  return int64((pow(p, fn) + pow(q, fn)) / sqrt(5.0))
+
+echo FibonacciA(4) #OUT 3
+
+
+
diff --git a/tests/misc/tcharinc.nim b/tests/misc/tcharinc.nim
new file mode 100644
index 000000000..1b5d19c18
--- /dev/null
+++ b/tests/misc/tcharinc.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "1"
+"""
+
+var c = '\0'
+while true:
+  if c == '\xFF': break
+  inc c
+
+echo "1"
diff --git a/tests/misc/tcmdline.nim b/tests/misc/tcmdline.nim
new file mode 100644
index 000000000..f4ee20d31
--- /dev/null
+++ b/tests/misc/tcmdline.nim
@@ -0,0 +1,14 @@
+# Test the command line
+
+import
+  os, strutils
+
+var
+  i: int
+  params = paramCount()
+i = 0
+writeln(stdout, "This exe: " & getAppFilename())
+writeln(stdout, "Number of parameters: " & $params)
+while i <= params:
+  writeln(stdout, paramStr(i))
+  i = i + 1
diff --git a/tests/misc/tcolonisproc.nim b/tests/misc/tcolonisproc.nim
new file mode 100644
index 000000000..af4077284
--- /dev/null
+++ b/tests/misc/tcolonisproc.nim
@@ -0,0 +1,13 @@
+
+proc p(a, b: int, c: proc ()) =
+  c()
+
+when false:
+  # language spec changed:
+  p(1, 3):
+    echo 1
+    echo 3
+    
+p(1, 1, proc() =
+  echo 1
+  echo 2)
diff --git a/tests/misc/tdllvar.nim b/tests/misc/tdllvar.nim
new file mode 100644
index 000000000..5a31dfbbb
--- /dev/null
+++ b/tests/misc/tdllvar.nim
@@ -0,0 +1,16 @@
+import os
+
+proc getDllName: string = 
+  result = "mylib.dll"
+  if fileExists(result): return
+  result = "mylib2.dll"
+  if fileExists(result): return
+  quit("could not load dynamic library")
+
+proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}
+proc myImport2(s: int) {.cdecl, importc, dynlib: getDllName().}
+
+myImport("test2")
+myImport2(12)
+
+
diff --git a/tests/misc/temit.nim b/tests/misc/temit.nim
new file mode 100644
index 000000000..e2a9eaff1
--- /dev/null
+++ b/tests/misc/temit.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "temit.nim"
+  output: "509"
+"""
+# Test the new ``emit`` pragma: 
+
+{.emit: """
+static int cvariable = 420;
+
+""".}
+
+proc embedsC() = 
+  var nimVar = 89
+  {.emit: """printf("%d\n", cvariable + (int)`nimVar`);""".}
+
+embedsC()
+
+
+
+
diff --git a/tests/misc/temptyecho.nim b/tests/misc/temptyecho.nim
new file mode 100644
index 000000000..5f1aa6515
--- /dev/null
+++ b/tests/misc/temptyecho.nim
@@ -0,0 +1,2 @@
+echo()
+
diff --git a/tests/misc/tendian.nim b/tests/misc/tendian.nim
new file mode 100644
index 000000000..256e2653c
--- /dev/null
+++ b/tests/misc/tendian.nim
@@ -0,0 +1,3 @@
+# test the new endian magic
+
+writeln(stdout, repr(system.cpuEndian))
diff --git a/tests/misc/teventemitter.nim b/tests/misc/teventemitter.nim
new file mode 100644
index 000000000..c1cc3d3a9
--- /dev/null
+++ b/tests/misc/teventemitter.nim
@@ -0,0 +1,33 @@
+discard """
+  output: "pie"
+"""
+
+import tables, lists
+
+type
+  EventArgs = object of RootObj
+  EventEmitter = object of RootObj
+    events*: Table[string, DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]
+
+proc emit*(emitter: EventEmitter, event: string, args: EventArgs) =
+  for fn in nodes(emitter.events[event]):
+    fn.value(args) #call function with args.
+
+proc on*(emitter: var EventEmitter, event: string, 
+         fn: proc(e: EventArgs) {.nimcall.}) =
+  if not hasKey(emitter.events, event):
+    var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]
+    add(emitter.events, event, list) #if not, add it.
+  append(emitter.events.mget(event), fn)
+
+proc initEmitter(emitter: var EventEmitter) =
+  emitter.events = initTable[string, 
+    DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]()
+
+var 
+  ee: EventEmitter
+  args: EventArgs
+initEmitter(ee)
+ee.on("print", proc(e: EventArgs) = echo("pie"))
+ee.emit("print", args)
+
diff --git a/tests/misc/tevents.nim b/tests/misc/tevents.nim
new file mode 100644
index 000000000..fb94b1f79
--- /dev/null
+++ b/tests/misc/tevents.nim
@@ -0,0 +1,48 @@
+discard """
+file: "tevents.nim"
+output: '''HandlePrintEvent: Output -> Handled print event
+HandlePrintEvent2: Output -> printing for ME
+HandlePrintEvent2: Output -> printing for ME'''
+"""
+
+import events
+
+type
+  TPrintEventArgs = object of TEventArgs
+    user*: string
+
+proc handleprintevent*(e: TEventArgs) =
+    write(stdout, "HandlePrintEvent: Output -> Handled print event\n")
+        
+proc handleprintevent2*(e: TEventArgs) =
+    var args: TPrintEventArgs = TPrintEventArgs(e)
+    write(stdout, "HandlePrintEvent2: Output -> printing for " & args.user)
+    
+var ee = initEventEmitter()
+
+var eventargs: TPrintEventArgs
+eventargs.user = "ME\n"
+
+##method one test
+
+ee.on("print", handleprintevent)
+ee.on("print", handleprintevent2)
+
+ee.emit("print", eventargs)
+
+##method two test
+
+type
+  TSomeObject = object of TObject
+    PrintEvent: TEventHandler
+
+var obj: TSomeObject
+obj.PrintEvent = initEventHandler("print")
+obj.PrintEvent.addHandler(handleprintevent2)
+
+ee.emit(obj.PrintEvent, eventargs)
+
+obj.PrintEvent.removeHandler(handleprintevent2)
+
+ee.emit(obj.PrintEvent, eventargs)
+
diff --git a/tests/misc/tfib.nim b/tests/misc/tfib.nim
new file mode 100644
index 000000000..09a4d5038
--- /dev/null
+++ b/tests/misc/tfib.nim
@@ -0,0 +1,11 @@
+
+iterator fibonacci(): int = 
+  var a = 0
+  var b = 1
+  while true: 
+    yield a
+    var c = b
+    b = a
+    a = a + c
+
+
diff --git a/tests/misc/tfilter.nim b/tests/misc/tfilter.nim
new file mode 100644
index 000000000..5846d0efb
--- /dev/null
+++ b/tests/misc/tfilter.nim
@@ -0,0 +1,41 @@
+discard """
+  output: "02468101214161820\n15"
+"""
+
+proc filter[T](list: seq[T], f: proc (item: T): bool {.closure.}): seq[T] =
+  result = @[]
+  for i in items(list):
+    if f(i):
+      result.add(i)
+
+let nums = @[0, 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
+
+when true:
+  let nums2 = filter(nums,
+               (proc (item: int): bool =
+                 result = (item mod 2) == 0)
+               )
+
+proc outer =
+  # lets use a proper closure this time:
+  var modulo = 2
+  let nums2 = filter(nums,
+               (proc (item: int): bool = result = (item mod modulo) == 0)
+               )
+
+  for n in nums2: stdout.write(n)
+  stdout.write("\n")
+
+outer()
+
+import math
+proc compose[T](f1, f2: proc (x: T): T {.closure.}): proc (x: T): T {.closure.} =
+  result = (proc (x: T): T =
+             result = f1(f2(x)))
+
+
+proc add5(x: int): int = result = x + 5
+
+var test = compose(add5, add5)
+echo test(5)
+
diff --git a/tests/misc/tgenconstraints.nim b/tests/misc/tgenconstraints.nim
new file mode 100644
index 000000000..6e8fdc738
--- /dev/null
+++ b/tests/misc/tgenconstraints.nim
@@ -0,0 +1,32 @@
+discard """
+  file: "tgenconstraints.nim"
+  line: 25
+  disabled: true
+  errormsg: "cannot instantiate T2"
+"""
+
+type
+  T1[T: int|string] = object
+    x: T
+
+  T2[T: Ordinal] = object
+    x: T
+
+var x1: T1[int]
+var x2: T1[string]
+var x3: T2[int]
+
+proc foo[T](x: T): T2[T] {.discardable.} =
+  var o: T1[T]
+
+foo(10)
+
+# XXX: allow type intersections in situation like this
+proc bar(x: int|TNumber): T1[type(x)] {.discardable.} =
+  when type(x) is TNumber:
+    var o: T2[type(x)]
+
+bar "test"
+bar 100
+bar 1.1
+
diff --git a/tests/misc/tgetstartmilsecs.nim b/tests/misc/tgetstartmilsecs.nim
new file mode 100644
index 000000000..5a3368e0f
--- /dev/null
+++ b/tests/misc/tgetstartmilsecs.nim
@@ -0,0 +1,7 @@
+# 
+import times, os
+
+var start = epochTime()
+os.sleep(1000)
+
+echo epochTime() - start #OUT 1000
diff --git a/tests/misc/thallo.nim b/tests/misc/thallo.nim
new file mode 100644
index 000000000..cbeb45b97
--- /dev/null
+++ b/tests/misc/thallo.nim
@@ -0,0 +1,85 @@
+# Hallo
+
+import
+  os, strutils, macros
+
+type
+  TMyEnum = enum
+    meA, meB, meC, meD
+
+when isMainModule:
+  {.hint: "this is the main file".}
+
+proc fac[T](x: T): T =
+  # test recursive generic procs
+  if x <= 1: return 1
+  else: return x.`*`(fac(x-1))
+
+macro macrotest(n: expr): stmt {.immediate.} =
+  let n = callsite()
+  expectKind(n, nnkCall)
+  expectMinLen(n, 2)
+  result = newNimNode(nnkStmtList, n)
+  for i in 2..n.len-1:
+    result.add(newCall("write", n[1], n[i]))
+  result.add(newCall("writeln", n[1], newStrLitNode("")))
+
+macro debug(n: expr): stmt {.immediate.} =
+  let n = callsite()
+  result = newNimNode(nnkStmtList, n)
+  for i in 1..n.len-1:
+    result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+    result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+    result.add(newCall("writeln", newIdentNode("stdout"), n[i]))
+
+macrotest(stdout, "finally", 4, 5, "variable", "argument lists")
+macrotest(stdout)
+
+#GC_disable()
+
+echo("This was compiled by Nim version " & system.NimVersion)
+writeln(stdout, "Hello", " World", "!")
+
+echo(["a", "b", "c", "d"].len)
+for x in items(["What's", "your", "name", "?", ]):
+  echo(x)
+var `name` = readLine(stdin)
+{.breakpoint.}
+echo("Hi " & thallo.name & "!\n")
+debug(name)
+
+var testseq: seq[string] = @[
+  "a", "b", "c", "d", "e"
+]
+echo(repr(testseq))
+
+var dummy = "hello"
+echo(substr(dummy, 2, 3))
+
+echo($meC)
+
+# test tuples:
+for x, y in items([(1, 2), (3, 4), (6, 1), (5, 2)]):
+  echo x
+  echo y
+
+proc simpleConst(): int = return 34
+
+# test constant evaluation:
+const
+  constEval3 = simpleConst()
+  constEval = "abc".contains('b')
+  constEval2 = fac(7)
+
+echo(constEval3)
+echo(constEval)
+echo(constEval2)
+echo(1.`+`(2))
+
+for i in 2..6:
+  for j in countdown(i+4, 2):
+    echo(fac(i * j))
+
+when isMainModule:
+  {.hint: "this is the main file".}
+
diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim
new file mode 100644
index 000000000..aec140f42
--- /dev/null
+++ b/tests/misc/theaproots.nim
@@ -0,0 +1,71 @@
+type 
+  Bar = object
+    x: int
+  
+  Foo = object
+    rheap: ref Bar
+    rmaybe: ref Bar
+    rstack: ref Bar
+    list: seq[ref Bar]
+    listarr: array[0..5, ref Bar]
+    nestedtup: Tup
+    inner: TInner
+    inref: ref TInner
+
+  TInner = object
+    inref: ref Bar
+
+  Tup = tuple
+    tupbar: ref Bar
+    inner: TInner
+
+proc acc(x: var Foo): var ref Bar =
+  result = x.rheap
+
+proc test(maybeFoo: var Foo,
+          maybeSeq: var seq[ref Bar],
+          bars: var openarray[ref Bar],
+          maybeTup: var Tup) =
+  var bb: ref Bar
+  maybeFoo.rmaybe = bb
+  maybeFoo.list[3] = bb
+  maybeFoo.listarr[3] = bb
+  acc(maybeFoo) = bb
+  
+  var localFoo: Foo
+  localFoo.rstack = bb
+  localFoo.list[3] = bb
+  localFoo.listarr[3] = bb
+  acc(localFoo) = bb
+
+  var heapFoo: ref Foo
+  heapFoo.rheap = bb
+  heapFoo.list[3] = bb
+  heapFoo.listarr[3] = bb
+  acc(heapFoo[]) = bb
+
+  heapFoo.nestedtup.tupbar = bb
+  heapFoo.nestedtup.inner.inref = bb
+  heapFoo.inner.inref = bb
+  heapFoo.inref.inref = bb
+
+  var locseq: seq[ref Bar]
+  locseq[3] = bb
+
+  var locarr: array[0..4, ref Bar]
+  locarr[3] = bb
+
+  maybeSeq[3] = bb
+
+  bars[3] = bb
+
+  maybeTup[0] = bb
+
+var
+  ff: ref Foo
+  tt: Tup
+  gseq: seq[ref Bar]
+
+new(ff)
+
+test(ff[], gseq, gseq, tt)
diff --git a/tests/misc/thintoff.nim b/tests/misc/thintoff.nim
new file mode 100644
index 000000000..807ff44f3
--- /dev/null
+++ b/tests/misc/thintoff.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "thintoff.nim"
+  output: "0"
+"""
+
+{.hint[XDeclaredButNotUsed]: off.}
+var
+  x: int
+  
+echo x #OUT 0
+
+
diff --git a/tests/misc/tinc.nim b/tests/misc/tinc.nim
new file mode 100644
index 000000000..b74f85591
--- /dev/null
+++ b/tests/misc/tinc.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinc.nim"
+  line: 8
+  errormsg: "type mismatch: got (int)"
+"""
+var x = 0
+
+inc(x+1)
+
+
+
+
diff --git a/tests/misc/tinit.nim b/tests/misc/tinit.nim
new file mode 100644
index 000000000..5c75567ec
--- /dev/null
+++ b/tests/misc/tinit.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinit.nim"
+  output: "Hello from module! Hello from main module!"
+"""
+# Test the new init section in modules

+

+import minit

+

+write(stdout, "Hello from main module!\n")

+#OUT Hello from module! Hello from main module!

+
+
diff --git a/tests/misc/tinout.nim b/tests/misc/tinout.nim
new file mode 100644
index 000000000..4e5908428
--- /dev/null
+++ b/tests/misc/tinout.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tinout.nim"
+  line: 12
+  errormsg: "type mismatch: got (int literal(3))"
+"""
+# Test in out checking for parameters

+

+proc abc(x: var int) =

+    x = 0

+

+proc b() =

+    abc(3) #ERROR

+

+b()

+
+
diff --git a/tests/misc/tints.nim b/tests/misc/tints.nim
new file mode 100644
index 000000000..ded24fb5c
--- /dev/null
+++ b/tests/misc/tints.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''
+0 0
+0 0
+Success'''
+"""
+# Test the different integer operations
+
+var testNumber = 0
+
+template test(opr, a, b, c: expr): stmt {.immediate.} =
+  # test the expression at compile and runtime
+  block:
+    const constExpr = opr(a, b)
+    when constExpr != c:
+      {.error: "Test failed " & $constExpr & " " & $c.}
+    inc(testNumber)
+    #Echo("Test: " & $testNumber)
+    var aa = a
+    var bb = b
+    var varExpr = opr(aa, bb)
+    assert(varExpr == c)
+
+test(`+`, 12'i8, -13'i16, -1'i16)
+test(`shl`, 0b11, 0b100, 0b110000)
+test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64)
+test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32)
+
+test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16)
+test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16)
+
+test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0x0fffffffffffffff'i64)
+test(`shr`, 0xffff'i16, 0x4'i16, 0x0fff'i16)
+test(`shr`, 0xff'i8, 0x4'i8, 0x0f'i8)
+
+test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64)
+test(`shr`, 0xffffffff'i32, 0x4'i32, 0x0fffffff'i32)
+
+test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64)
+test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16)
+test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8)
+
+test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64)
+test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
+
+# bug #916
+proc unc(a: float): float =
+  return a
+
+echo int(unc(0.5)), " ", int(unc(-0.5))
+echo int(0.5), " ", int(-0.5)
+
+echo("Success") #OUT Success
+
diff --git a/tests/misc/tinvalidarrayaccess.nim b/tests/misc/tinvalidarrayaccess.nim
new file mode 100644
index 000000000..03105b41b
--- /dev/null
+++ b/tests/misc/tinvalidarrayaccess.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "index out of bounds"
+  line: 11
+"""
+
+
+type TTestArr = array[0..1, int16]
+var f: TTestArr
+f[0] = 30
+f[1] = 40
+f[2] = 50
+f[3] = 60
+
+echo(repr(f))
diff --git a/tests/misc/tinvalidnewseq.nim b/tests/misc/tinvalidnewseq.nim
new file mode 100644
index 000000000..957a25560
--- /dev/null
+++ b/tests/misc/tinvalidnewseq.nim
@@ -0,0 +1,27 @@
+discard """
+  file: "tinvalidnewseq.nim"
+  line: 15
+  errormsg: "type mismatch: got (array[0..6, string], int literal(7))"
+"""
+import re, strutils
+
+type
+  TURL = tuple[protocol, subdomain, domain, port: string, path: seq[string]]
+
+proc parseURL(url: string): TURL =
+  #([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?
+  var pattern: string = r"([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?"
+  var m: array[0..6, string] #Array with the matches
+  newSeq(m, 7) #ERROR
+  discard regexprs.match(url, re(pattern), m)
+ 
+  result = (protocol: m[1], subdomain: m[2], domain: m[3] & m[4], 
+            port: m[5], path: m[6].split('/'))
+ 
+var r: TUrl
+ 
+r = parseUrl(r"http://google.com/search?var=bleahdhsad")
+echo(r.domain)
+
+
+
diff --git a/tests/misc/tissue710.nim b/tests/misc/tissue710.nim
new file mode 100644
index 000000000..ecfdf653e
--- /dev/null
+++ b/tests/misc/tissue710.nim
@@ -0,0 +1,10 @@
+discard """
+  file: "tissue710.nim"
+  line: 8
+  errorMsg: "undeclared identifier: '||'"
+"""
+var sum = 0
+for x in 3..1000:
+  if (x mod 3 == 0) || (x mod 5 == 0):
+    sum += x
+echo(sum)
diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim
new file mode 100644
index 000000000..92ac922f7
--- /dev/null
+++ b/tests/misc/tlastmod.nim
@@ -0,0 +1,18 @@
+# test the new LastModificationTime() proc

+

+import

+  os, times, strutils

+

+proc main() =

+  var

+    a, b: TTime

+  a = getLastModificationTime(paramStr(1))

+  b = getLastModificationTime(paramStr(2))

+  writeln(stdout, $a)

+  writeln(stdout, $b)

+  if a < b:

+    write(stdout, "$2 is newer than $1\n" % [paramStr(1), paramStr(2)])

+  else:

+    write(stdout, "$1 is newer than $2\n" % [paramStr(1), paramStr(2)])

+

+main()

diff --git a/tests/misc/tlocals.nim b/tests/misc/tlocals.nim
new file mode 100644
index 000000000..af8a54946
--- /dev/null
+++ b/tests/misc/tlocals.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "(x: string here, a: 1)"
+"""
+
+proc simple[T](a: T) = 
+  var
+    x = "string here"
+  echo locals()
+  
+simple(1)
+
diff --git a/tests/misc/tloops.nim b/tests/misc/tloops.nim
new file mode 100644
index 000000000..1aada0298
--- /dev/null
+++ b/tests/misc/tloops.nim
@@ -0,0 +1,87 @@
+# Test nested loops and some other things
+
+proc andTest() =
+  var a = 0 == 5 and 6 == 6
+
+proc incx(x: var int) = # is built-in proc
+  x = x + 1
+
+proc decx(x: var int) =
+  x = x - 1
+
+proc First(y: var int) =
+  var x: int
+  i_ncx(x)
+  if x == 10:
+    y = 0
+  else:
+    if x == 0:
+      incx(x)
+    else:
+      x=11
+
+proc TestLoops() =
+  var i, j: int
+  while i >= 0:
+    if i mod 3 == 0:
+      break
+    i = i + 1
+    while j == 13:
+      j = 13
+      break
+    break
+
+  while true:
+    break
+
+
+proc Foo(n: int): int =
+    var
+        a, old: int
+        b, c: bool
+    F_irst(a)
+    if a == 10:
+        a = 30
+    elif a == 11:
+        a = 22
+    elif a == 12:
+        a = 23
+    elif b:
+        old = 12
+    else:
+        a = 40
+
+    #
+    b = false or 2 == 0 and 3 == 9
+    a = 0 + 3 * 5 + 6 + 7 + +8 # 36
+    while b:
+        a = a + 3
+    a = a + 5
+    write(stdout, "Hello!")
+
+
+# We should come till here :-)
+discard Foo(345)
+
+# test the new type symbol lookup feature:
+
+type
+  MyType[T] = tuple[
+    x, y, z: T]
+  MyType2 = tuple[x, y: float]
+
+proc main[T]() =
+  var myType: MyType[T]
+  var b: MyType[T]
+  b = (1, 2, 3)
+  myType = b
+  echo myType
+  
+  var myType2: MyType2
+  var c: MyType2
+  c = (1.0, 2.0)
+  myType2 = c
+  echo myType2
+
+main[int]()
+
diff --git a/tests/misc/tmandelbrot.nim b/tests/misc/tmandelbrot.nim
new file mode 100644
index 000000000..4228b0416
--- /dev/null
+++ b/tests/misc/tmandelbrot.nim
@@ -0,0 +1,57 @@
+discard """
+  cmd: "nim $target --hints:on -d:release $options $file"
+"""
+
+# -*- nim -*-
+
+import math
+import os
+import strutils
+
+type TComplex = tuple[re, im: float]
+
+proc `+` (a, b: TComplex): TComplex =
+    return (a.re + b.re, a.im + b.im)
+
+proc `*` (a, b: TComplex): TComplex =
+    result.re = a.re * b.re - a.im * b.im
+    result.im = a.re * b.im + a.im * b.re
+
+proc abs2 (a: TComplex): float =
+    return a.re * a.re + a.im * a.im
+
+var size    = parseInt (paramStr (1))
+var bit     = 128
+var byteAcc = 0
+
+stdout.writeln ("P4")
+stdout.write ($size)
+stdout.write (" ")
+stdout.writeln ($size)
+
+var fsize = float (size)
+for y in 0 .. size-1:
+    var fy = 2.0 * float (y) / fsize - 1.0
+    for x in 0 .. size-1:
+        var z = (0.0, 0.0)
+        var c = (float (2*x) / fsize - 1.5, fy)
+
+        block iter:
+            for i in 0 .. 49:
+                z = z*z + c
+                if abs2 (z) >= 4.0:
+                    break iter
+            byteAcc = byteAcc + bit
+
+        if bit > 1:
+            bit = bit div 2
+        else:
+            stdout.write (chr (byteAcc))
+            bit     = 128
+            byteAcc = 0
+
+    if bit != 128:
+        stdout.write (chr (byteAcc))
+        bit     = 128
+        byteAcc = 0
+
diff --git a/tests/misc/tmemoization.nim b/tests/misc/tmemoization.nim
new file mode 100644
index 000000000..180acd89b
--- /dev/null
+++ b/tests/misc/tmemoization.nim
@@ -0,0 +1,17 @@
+discard """
+  msg:    "test 1\ntest 2\ntest 3"
+  output: "TEST 1\nTEST 2\nTEST 3"
+"""
+
+import strutils
+
+proc foo(s: static[string]): string =
+  static: echo s
+
+  const R = s.toUpper
+  return R
+
+echo foo("test 1")
+echo foo("test 2")
+echo foo("test " & $3)
+
diff --git a/tests/misc/tmissingnilcheck.nim b/tests/misc/tmissingnilcheck.nim
new file mode 100644
index 000000000..c2f23ae87
--- /dev/null
+++ b/tests/misc/tmissingnilcheck.nim
@@ -0,0 +1,20 @@
+discard """
+  disabled: true
+"""
+
+type
+  PFutureBase = ref object
+    callback: proc () {.closure.}
+
+proc newConnection =
+  iterator newConnectionIter(): PFutureBase {.closure.} =
+    discard
+  var newConnectionIterVar = newConnectionIter
+  var first = newConnectionIterVar()
+
+  proc cb {.closure.} =
+    discard
+  
+  first.callback = cb
+
+newConnection()
diff --git a/tests/misc/tnew.nim b/tests/misc/tnew.nim
new file mode 100644
index 000000000..6527541a2
--- /dev/null
+++ b/tests/misc/tnew.nim
@@ -0,0 +1,49 @@
+# Test the implementation of the new operator

+# and the code generation for gc walkers

+# (and the garbage collector):

+

+type

+  PNode = ref TNode

+  TNode = object

+    data: int

+    str: string

+    le, ri: PNode

+

+  TStressTest = ref array [0..45, array [1..45, TNode]]

+

+proc finalizer(n: PNode) =

+  write(stdout, n.data)

+  write(stdout, " is now freed\n")

+

+proc newNode(data: int, le, ri: PNode): PNode =

+  new(result, finalizer)

+  result.le = le

+  result.ri = ri

+  result.data = data

+

+# now loop and build a tree

+proc main() =

+  var

+    i = 0

+    p: TStressTest

+  while i < 1000:

+    var n: PNode

+

+    n = newNode(i, nil, newNode(i + 10000, nil, nil))

+    inc(i)

+  new(p)

+

+  write(stdout, "Simple tree node allocation worked!\n")

+  i = 0

+  while i < 1000:

+    var m = newNode(i + 20000, nil, nil)

+    var k = newNode(i + 30000, nil, nil)

+    m.le = m

+    m.ri = k

+    k.le = m

+    k.ri = k

+    inc(i)

+

+  write(stdout, "Simple cycle allocation worked!\n")

+

+main()

diff --git a/tests/misc/tnewderef.nim b/tests/misc/tnewderef.nim
new file mode 100644
index 000000000..89dc4c8d1
--- /dev/null
+++ b/tests/misc/tnewderef.nim
@@ -0,0 +1,11 @@
+discard """
+  output: 3
+
+"""
+
+var x: ref int
+new(x)
+x[] = 3
+
+echo x[] 
+
diff --git a/tests/misc/tnewsets.nim b/tests/misc/tnewsets.nim
new file mode 100644
index 000000000..415fe8f7e
--- /dev/null
+++ b/tests/misc/tnewsets.nim
@@ -0,0 +1,6 @@
+# new test for sets:

+

+const elem = ' '

+

+var s: set[char] = {elem}

+assert(elem in s and 'a' not_in s and 'c' not_in s )

diff --git a/tests/misc/tnewuns.nim b/tests/misc/tnewuns.nim
new file mode 100644
index 000000000..5181e467c
--- /dev/null
+++ b/tests/misc/tnewuns.nim
@@ -0,0 +1,12 @@
+# test the new unsigned operations:

+

+import

+  strutils

+

+var

+  x, y: int

+

+x = 1

+y = high(int)

+

+writeln(stdout, $ ( x +% y ) )

diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim
new file mode 100644
index 000000000..342e757b8
--- /dev/null
+++ b/tests/misc/tnoforward.nim
@@ -0,0 +1,14 @@
+discard """
+  disabled: true
+"""
+
+{. noforward: on .}
+
+proc foo(x: int) =
+  bar x
+
+proc bar(x: int) =
+  echo x
+
+foo(10)
+
diff --git a/tests/misc/tnoinst.nim b/tests/misc/tnoinst.nim
new file mode 100644
index 000000000..4c8d9d1aa
--- /dev/null
+++ b/tests/misc/tnoinst.nim
@@ -0,0 +1,17 @@
+discard """
+  line: 12
+  errormsg: "instantiate 'notConcrete' explicitly"
+  disabled: "true"
+"""
+
+proc wrap[T]() =
+  proc notConcrete[T](x, y: int): int =
+    var dummy: T
+    result = x - y
+
+  var x: proc (x, y: T): int
+  x = notConcrete
+  
+
+wrap[int]()
+
diff --git a/tests/misc/tnolen.nim b/tests/misc/tnolen.nim
new file mode 100644
index 000000000..dcf6811eb
--- /dev/null
+++ b/tests/misc/tnolen.nim
@@ -0,0 +1,9 @@
+discard """
+  line: 8
+  errormsg: "type mismatch: got (int literal(3))"
+"""
+
+# please finally disallow Len(3)
+
+echo len(3)
+
diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim
new file mode 100644
index 000000000..10c2eb2ec
--- /dev/null
+++ b/tests/misc/tnoop.nim
@@ -0,0 +1,11 @@
+discard """
+  file: "tnoop.nim"
+  line: 11
+  errormsg: "undeclared identifier: 'a'"
+"""
+
+
+var
+  a: int
+
+a()
diff --git a/tests/misc/tnot.nim b/tests/misc/tnot.nim
new file mode 100644
index 000000000..6193e21e1
--- /dev/null
+++ b/tests/misc/tnot.nim
@@ -0,0 +1,22 @@
+discard """
+  file: "tnot.nim"
+  line: 14
+  errormsg: "type mismatch"
+"""
+# BUG: following compiles, but should not:
+
+proc nodeOfDegree(x: int): bool = 
+  result = false
+
+proc main = 
+  for j in 0..2:
+    for i in 0..10:
+      if not nodeOfDegree(1) >= 0: #ERROR_MSG type mismatch
+        echo "Yes"
+      else:
+        echo "No"
+
+main()
+
+
+
diff --git a/tests/misc/tparedef.nim b/tests/misc/tparedef.nim
new file mode 100644
index 000000000..dedebf6b7
--- /dev/null
+++ b/tests/misc/tparedef.nim
@@ -0,0 +1,4 @@
+# This test is now superfluous:

+

+proc a(a: int) = 

+  return

diff --git a/tests/misc/tparsecombnum.nim b/tests/misc/tparsecombnum.nim
new file mode 100644
index 000000000..6fe539813
--- /dev/null
+++ b/tests/misc/tparsecombnum.nim
@@ -0,0 +1,55 @@
+import parsecomb
+
+discard """
+  output: "-289096"
+"""
+
+type Num = int
+
+# forward stuff
+var exp3: Parser[string, Num]
+var exp = lazy(proc(): Parser[string, Num] = exp3)
+
+var digit = (proc(): Parser[string, Num] =
+  result = tok("0").then(unit[string, Num](Num(0)))
+  for n in 1..9:
+    result = result + tok($n).then(unit[string, Num](Num(n)))
+)()
+
+var num = repeat1(digit).map(proc(ds: seq[Num]): Num =
+  result = 0
+  for d in ds:
+    result = result*10 + d)
+
+type Op = proc(a, b: Num): Num
+
+var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b))
+var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b))
+var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b))
+var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b))
+
+var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num =
+  var (le, r) = ler
+  var (l, e) = le
+  e)
+
+proc foldOp(a: Num, ob: (Op, Num)): Num =
+  var (o, b) = ob
+  o(a, b)
+
+var exp0 = paren + num
+var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp)
+var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp)
+exp3 = exp2
+
+proc strsplit(s: string): seq[string] =
+  result = @[]
+  for i in 0 .. s.len - 1:
+    result.add($s[i])
+
+var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit)
+case r.kind:
+of rkSuccess:
+  echo r.output
+of rkFailure:
+  echo "failed"
diff --git a/tests/misc/tpos.nim b/tests/misc/tpos.nim
new file mode 100644
index 000000000..5560ef050
--- /dev/null
+++ b/tests/misc/tpos.nim
@@ -0,0 +1,35 @@
+discard """
+  file: "tpos.nim"
+  output: "6"
+"""
+# test this particular function

+

+proc mypos(sub, s: string, start: int = 0): int =

+  var

+    i, j, M, N: int

+  M = sub.len

+  N = s.len

+  i = start

+  j = 0

+  if i >= N:

+    result = -1

+  else:

+    while true:

+      if s[i] == sub[j]:

+        inc(i)

+        inc(j)

+      else:

+        i = i - j + 1

+        j = 0

+      if (j >= M) or (i >= N): break

+    if j >= M:

+      result = i - M

+    else:

+      result = -1

+

+var sub = "hello"

+var s = "world hello"

+write(stdout, mypos(sub, s))

+#OUT 6

+
+
diff --git a/tests/misc/tprep.nim b/tests/misc/tprep.nim
new file mode 100644
index 000000000..8f40300d6
--- /dev/null
+++ b/tests/misc/tprep.nim
@@ -0,0 +1,30 @@
+# Test the features that used to belong to the preprocessor
+
+import
+  times
+
+#{.warning: "This is only a test warning!".}
+
+const
+  case2 = true
+  case3 = true
+
+when defined(case1):
+  {.hint: "Case 1".}
+  when case3:
+    {.hint: "Case 1.3".}
+elif case2:
+  {.hint: "Case 2".}
+  when case3:
+    {.hint: "Case 2.3".}
+elif case3:
+  {.hint: "Case 3".}
+else:
+  {.hint: "unknown case".}
+
+var
+  s: string
+write(stdout, "compiled at " & system.CompileDate &
+              " " & CompileTime & "\n")
+echo getDateStr()
+echo getClockStr()
diff --git a/tests/misc/tquicksort.nim b/tests/misc/tquicksort.nim
new file mode 100644
index 000000000..6706a185e
--- /dev/null
+++ b/tests/misc/tquicksort.nim
@@ -0,0 +1,26 @@
+proc QuickSort(list: seq[int]): seq[int] =
+    if len(list) == 0:
+        return @[]
+    var pivot = list[0]
+    var left: seq[int] = @[]
+    var right: seq[int] = @[]
+    for i in low(list)..high(list):
+        if list[i] < pivot:
+            left.add(list[i])
+        elif list[i] > pivot:
+            right.add(list[i])
+    result = QuickSort(left) & 
+      pivot & 
+      QuickSort(right)
+    
+proc echoSeq(a: seq[int]) =
+    for i in low(a)..high(a):
+        echo(a[i])
+
+var
+    list: seq[int]
+        
+list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3])
+echoSeq(list)
+
+
diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim
new file mode 100644
index 000000000..311aa9ccd
--- /dev/null
+++ b/tests/misc/tradix.nim
@@ -0,0 +1,319 @@
+# implements and tests an efficient radix tree
+
+## another method to store an efficient array of pointers: 
+## We use a radix tree with node compression. 
+## There are two node kinds:
+
+const BitsPerUnit = 8*sizeof(int)
+
+type
+  TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear
+  PRadixNode = ptr TRadixNode
+  TRadixNode {.pure, inheritable.} = object
+    kind: TRadixNodeKind
+  TRadixNodeLinear = object of TRadixNode
+    len: int8
+    keys: array [0..31, int8]
+    vals: array [0..31, PRadixNode]
+  
+  TRadixNodeFull = object of TRadixNode
+    b: array [0..255, PRadixNode]
+  TRadixNodeLeafBits = object of TRadixNode
+    b: array [0..7, int]
+  TRadixNodeLeafLinear = object of TRadixNode
+    len: int8
+    keys: array [0..31, int8]
+
+var
+  root: PRadixNode
+
+proc searchInner(r: PRadixNode, a: int): PRadixNode = 
+  case r.kind
+  of rnLinear:
+    var x = cast[ptr TRadixNodeLinear](r)
+    for i in 0..ze(x.len)-1: 
+      if ze(x.keys[i]) == a: return x.vals[i]
+  of rnFull: 
+    var x = cast[ptr TRadixNodeFull](r)
+    return x.b[a]
+  else: assert(false)
+
+proc testBit(w, i: int): bool {.inline.} = 
+  result = (w and (1 shl (i %% BitsPerUnit))) != 0
+
+proc setBit(w: var int, i: int) {.inline.} = 
+  w = w or (1 shl (i %% BitsPerUnit))
+
+proc resetBit(w: var int, i: int) {.inline.} = 
+  w = w and not (1 shl (i %% BitsPerUnit))
+
+proc testOrSetBit(w: var int, i: int): bool {.inline.} = 
+  var x = (1 shl (i %% BitsPerUnit))
+  if (w and x) != 0: return true
+  w = w or x
+
+proc searchLeaf(r: PRadixNode, a: int): bool = 
+  case r.kind
+  of rnLeafBits:
+    var x = cast[ptr TRadixNodeLeafBits](r)
+    return testBit(x.b[a /% BitsPerUnit], a)
+  of rnLeafLinear:
+    var x = cast[ptr TRadixNodeLeafLinear](r)
+    for i in 0..ze(x.len)-1: 
+      if ze(x.keys[i]) == a: return true
+  else: assert(false)
+
+proc exclLeaf(r: PRadixNode, a: int) = 
+  case r.kind
+  of rnLeafBits:
+    var x = cast[ptr TRadixNodeLeafBits](r)
+    resetBit(x.b[a /% BitsPerUnit], a)
+  of rnLeafLinear:
+    var x = cast[ptr TRadixNodeLeafLinear](r)
+    var L = ze(x.len)
+    for i in 0..L-1: 
+      if ze(x.keys[i]) == a: 
+        x.keys[i] = x.keys[L-1]
+        dec(x.len)
+        return
+  else: assert(false)
+
+proc contains*(r: PRadixNode, a: ByteAddress): bool =
+  if r == nil: return false
+  var x = searchInner(r, a shr 24 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 16 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 8 and 0xff)
+  if x == nil: return false
+  return searchLeaf(x, a and 0xff)
+
+proc excl*(r: PRadixNode, a: ByteAddress): bool =
+  if r == nil: return false
+  var x = searchInner(r, a shr 24 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 16 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 8 and 0xff)
+  if x == nil: return false
+  exclLeaf(x, a and 0xff)
+
+proc addLeaf(r: var PRadixNode, a: int): bool = 
+  if r == nil:
+    # a linear node:
+    var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
+    x.kind = rnLeafLinear
+    x.len = 1'i8
+    x.keys[0] = toU8(a)
+    r = x
+    return false # not already in set
+  case r.kind 
+  of rnLeafBits: 
+    var x = cast[ptr TRadixNodeLeafBits](r)
+    return testOrSetBit(x.b[a /% BitsPerUnit], a)
+  of rnLeafLinear: 
+    var x = cast[ptr TRadixNodeLeafLinear](r)
+    var L = ze(x.len)
+    for i in 0..L-1: 
+      if ze(x.keys[i]) == a: return true
+    if L <= high(x.keys):
+      x.keys[L] = toU8(a)
+      inc(x.len)
+    else: 
+      # transform into a full node:
+      var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits)))
+      y.kind = rnLeafBits
+      for i in 0..ze(x.len)-1: 
+        var u = ze(x.keys[i])
+        setBit(y.b[u /% BitsPerUnit], u)
+      setBit(y.b[a /% BitsPerUnit], a)
+      dealloc(r)
+      r = y
+  else: assert(false)
+
+proc addInner(r: var PRadixNode, a: int, d: int): bool = 
+  if d == 0: 
+    return addLeaf(r, a and 0xff)
+  var k = a shr d and 0xff
+  if r == nil:
+    # a linear node:
+    var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
+    x.kind = rnLinear
+    x.len = 1'i8
+    x.keys[0] = toU8(k)
+    r = x
+    return addInner(x.vals[0], a, d-8)
+  case r.kind
+  of rnLinear:
+    var x = cast[ptr TRadixNodeLinear](r)
+    var L = ze(x.len)
+    for i in 0..L-1: 
+      if ze(x.keys[i]) == k: # already exists
+        return addInner(x.vals[i], a, d-8)
+    if L <= high(x.keys):
+      x.keys[L] = toU8(k)
+      inc(x.len)
+      return addInner(x.vals[L], a, d-8)
+    else: 
+      # transform into a full node:
+      var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull)))
+      y.kind = rnFull
+      for i in 0..L-1: y.b[ze(x.keys[i])] = x.vals[i]
+      dealloc(r)
+      r = y
+      return addInner(y.b[k], a, d-8)
+  of rnFull: 
+    var x = cast[ptr TRadixNodeFull](r)
+    return addInner(x.b[k], a, d-8)
+  else: assert(false)
+
+proc incl*(r: var PRadixNode, a: ByteAddress) {.inline.} = 
+  discard addInner(r, a, 24)
+  
+proc testOrIncl*(r: var PRadixNode, a: ByteAddress): bool {.inline.} = 
+  return addInner(r, a, 24)
+      
+iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] = 
+  if r != nil:
+    case r.kind 
+    of rnFull: 
+      var r = cast[ptr TRadixNodeFull](r)
+      for i in 0..high(r.b):
+        if r.b[i] != nil: 
+          yield (i, r.b[i])
+    of rnLinear: 
+      var r = cast[ptr TRadixNodeLinear](r)
+      for i in 0..ze(r.len)-1: 
+        yield (ze(r.keys[i]), r.vals[i])
+    else: assert(false)
+
+iterator leafElements(r: PRadixNode): int = 
+  if r != nil:
+    case r.kind
+    of rnLeafBits: 
+      var r = cast[ptr TRadixNodeLeafBits](r)
+      # iterate over any bit:
+      for i in 0..high(r.b): 
+        if r.b[i] != 0: # test all bits for zero
+          for j in 0..BitsPerUnit-1: 
+            if testBit(r.b[i], j): 
+              yield i*BitsPerUnit+j
+    of rnLeafLinear: 
+      var r = cast[ptr TRadixNodeLeafLinear](r)
+      for i in 0..ze(r.len)-1: 
+        yield ze(r.keys[i])
+    else: assert(false)
+    
+iterator elements*(r: PRadixNode): ByteAddress {.inline.} = 
+  for p1, n1 in innerElements(r): 
+    for p2, n2 in innerElements(n1):
+      for p3, n3 in innerElements(n2):
+        for p4 in leafElements(n3): 
+          yield p1 shl 24 or p2 shl 16 or p3 shl 8 or p4
+  
+proc main() =
+  const
+    numbers = [128, 1, 2, 3, 4, 255, 17, -8, 45, 19_000]
+  var
+    r: PRadixNode = nil
+  for x in items(numbers):
+    echo testOrIncl(r, x)
+  for x in elements(r): echo(x)
+
+main()
+
+
+when false:
+  proc traverse(r: PRadixNode, prefix: int, d: int) = 
+    if r == nil: return
+    case r.kind 
+    of rnLeafBits: 
+      assert(d == 0)
+      var x = cast[ptr TRadixNodeLeafBits](r)
+      # iterate over any bit:
+      for i in 0..high(x.b): 
+        if x.b[i] != 0: # test all bits for zero
+          for j in 0..BitsPerUnit-1: 
+            if testBit(x.b[i], j): 
+              visit(prefix or i*BitsPerUnit+j)
+    of rnLeafLinear: 
+      assert(d == 0)
+      var x = cast[ptr TRadixNodeLeafLinear](r)
+      for i in 0..ze(x.len)-1: 
+        visit(prefix or ze(x.keys[i]))
+    of rnFull: 
+      var x = cast[ptr TRadixNodeFull](r)
+      for i in 0..high(r.b):
+        if r.b[i] != nil: 
+          traverse(r.b[i], prefix or (i shl d), d-8)
+    of rnLinear: 
+      var x = cast[ptr TRadixNodeLinear](r)
+      for i in 0..ze(x.len)-1: 
+        traverse(x.vals[i], prefix or (ze(x.keys[i]) shl d), d-8)
+
+  type
+    TRadixIter {.final.} = object
+      r: PRadixNode
+      p: int
+      x: int
+
+  proc init(i: var TRadixIter, r: PRadixNode) =
+    i.r = r
+    i.x = 0
+    i.p = 0
+    
+  proc nextr(i: var TRadixIter): PRadixNode = 
+    if i.r == nil: return nil
+    case i.r.kind 
+    of rnFull: 
+      var r = cast[ptr TRadixNodeFull](i.r)
+      while i.x <= high(r.b):
+        if r.b[i.x] != nil: 
+          i.p = i.x
+          return r.b[i.x]
+        inc(i.x)
+    of rnLinear: 
+      var r = cast[ptr TRadixNodeLinear](i.r)
+      if i.x < ze(r.len): 
+        i.p = ze(r.keys[i.x])
+        result = r.vals[i.x]
+        inc(i.x)
+    else: assert(false)
+
+  proc nexti(i: var TRadixIter): int = 
+    result = -1
+    case i.r.kind 
+    of rnLeafBits: 
+      var r = cast[ptr TRadixNodeLeafBits](i.r)
+      # iterate over any bit:    
+      for i in 0..high(r.b): 
+        if x.b[i] != 0: # test all bits for zero
+          for j in 0..BitsPerUnit-1: 
+            if testBit(x.b[i], j): 
+              visit(prefix or i*BitsPerUnit+j)
+    of rnLeafLinear: 
+      var r = cast[ptr TRadixNodeLeafLinear](i.r)
+      if i.x < ze(r.len): 
+        result = ze(r.keys[i.x])
+        inc(i.x)
+
+  iterator elements(r: PRadixNode): ByteAddress {.inline.} = 
+    var
+      a, b, c, d: TRadixIter
+    init(a, r)
+    while true: 
+      var x = nextr(a)
+      if x != nil: 
+        init(b, x)
+        while true: 
+          var y = nextr(b)
+          if y != nil: 
+            init(c, y)
+            while true:
+              var z = nextr(c)
+              if z != nil: 
+                init(d, z)
+                while true:
+                  var q = nexti(d)
+                  if q != -1: 
+                    yield a.p shl 24 or b.p shl 16 or c.p shl 8 or q
diff --git a/tests/misc/trangechecks.nim b/tests/misc/trangechecks.nim
new file mode 100644
index 000000000..2c6f0f66d
--- /dev/null
+++ b/tests/misc/trangechecks.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''10
+10
+1
+1
+true'''
+"""
+
+# bug #1344
+
+var expected: int
+var x: range[1..10] = 10
+
+try:
+  x += 1
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+try:
+  inc x
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+x = 1
+try:
+  x -= 1
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+try:
+  dec x
+  echo x
+except OverflowError, RangeError:
+  expected += 1
+  echo x
+
+echo expected == 4
diff --git a/tests/misc/trawstr.nim b/tests/misc/trawstr.nim
new file mode 100644
index 000000000..ab2aae159
--- /dev/null
+++ b/tests/misc/trawstr.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "trawstr.nim"
+  line: 10
+  errormsg: "closing \" expected"
+"""
+# Test the new raw strings:

+

+const

+  xxx = r"This is a raw string!"

+  yyy = "This not\" #ERROR

+
+
diff --git a/tests/misc/treadln.nim b/tests/misc/treadln.nim
new file mode 100644
index 000000000..1edbea992
--- /dev/null
+++ b/tests/misc/treadln.nim
@@ -0,0 +1,12 @@
+# test the improved readline handling that does not care whether its
+# Macintosh, Unix or Windows text format.
+
+var
+  inp: File
+  line: string
+
+if open(inp, "readme.txt"):
+  while not endOfFile(inp):
+    line = readLine(inp)
+    echo("#" & line & "#")
+  close(inp)
diff --git a/tests/misc/treadx.nim b/tests/misc/treadx.nim
new file mode 100644
index 000000000..49b6ad691
--- /dev/null
+++ b/tests/misc/treadx.nim
@@ -0,0 +1,14 @@
+
+when not defined(windows):
+  import posix
+
+  var inp = ""
+  var buf: array[0..10, char]
+  while true:
+    var r = read(0, addr(buf), sizeof(buf)-1)
+    add inp, $buf
+    if r != sizeof(buf)-1: break
+
+  echo inp
+  #dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd
+
diff --git a/tests/misc/tromans.nim b/tests/misc/tromans.nim
new file mode 100644
index 000000000..fa6a63595
--- /dev/null
+++ b/tests/misc/tromans.nim
@@ -0,0 +1,71 @@
+discard """
+  file: "tromans.nim"
+  output: "success"
+"""
+import
+  strutils
+
+## Convert an integer to a Roman numeral
+# See http://en.wikipedia.org/wiki/Roman_numerals for reference
+
+proc raiseInvalidValue(msg: string) {.noreturn.} =
+  # Yes, we really need a shorthand for this code...
+  var e: ref EInvalidValue
+  new(e)
+  e.msg = msg
+  raise e
+
+# I should use a class, perhaps.
+# --> No. Why introduce additional state into such a simple and nice
+# interface? State is evil. :D
+
+proc RomanToDecimal(romanVal: string): int =
+  result = 0
+  var prevVal = 0
+  for i in countdown(romanVal.len - 1, 0):
+    var val = 0
+    case romanVal[i]
+    of 'I', 'i': val = 1
+    of 'V', 'v': val = 5
+    of 'X', 'x': val = 10
+    of 'L', 'l': val = 50
+    of 'C', 'c': val = 100
+    of 'D', 'd': val = 500
+    of 'M', 'm': val = 1000
+    else: raiseInvalidValue("Incorrect character in roman numeral! (" & 
+                            $romanVal[i] & ")")
+    if val >= prevVal:
+      inc(result, val)
+    else:
+      dec(result, val)
+    prevVal = val
+
+proc DecimalToRoman(decValParam: int): string =
+  # Apparently numbers cannot be above 4000
+  # Well, they can be (using overbar or parenthesis notation)
+  # but I see little interest (beside coding challenge) in coding them as
+  # we rarely use huge Roman numeral.
+  const romanComposites = [
+    ("M", 1000), ("CM", 900),
+    ("D", 500), ("CD", 400), ("C", 100),
+    ("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
+    ("V", 5), ("IV", 4), ("I", 1)]     
+  if decValParam < 1 or decValParam > 3999:
+    raiseInvalidValue("number not representable")
+  result = ""
+  var decVal = decValParam
+  for key, val in items(romanComposites):
+    while decVal >= val:
+      dec(decVal, val)
+      result.add(key)
+
+for i in 1..100:
+  if RomanToDecimal(DecimalToRoman(i)) != i: quit "BUG"
+
+for i in items([1238, 1777, 3830, 2401, 379, 33, 940, 3973]):
+  if RomanToDecimal(DecimalToRoman(i)) != i: quit "BUG"
+ 
+echo "success" #OUT success
+
+
+
diff --git a/tests/misc/tshadow_magic_type.nim b/tests/misc/tshadow_magic_type.nim
new file mode 100644
index 000000000..03c83079e
--- /dev/null
+++ b/tests/misc/tshadow_magic_type.nim
@@ -0,0 +1,24 @@
+type
+  TListItemType* = enum
+    RedisNil, RedisString
+
+  TListItem* = object
+    case kind*: TListItemType
+    of RedisString:
+      str*: string
+    else: nil
+  TRedisList* = seq[TListItem]
+
+# Caused by this.
+proc seq*() =
+  discard
+
+proc lrange*(key: string): TRedisList =
+  var foo: TListItem
+  foo.kind = RedisNil
+  result = @[foo]
+
+when isMainModule:
+  var p = lrange("mylist")
+  for i in items(p):
+    echo(i.str)
diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim
new file mode 100644
index 000000000..c282b3445
--- /dev/null
+++ b/tests/misc/tsimplesort.nim
@@ -0,0 +1,309 @@
+discard """
+  output: '''true'''
+"""
+  
+import hashes, math
+
+{.pragma: myShallow.}
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+  TTable* {.final, myShallow.}[A, B] = object
+    data: TKeyValuePairSeq[A, B]
+    counter: int
+
+proc len*[A, B](t: TTable[A, B]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: TTable[A, B]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield t.data[h].key
+
+iterator values*[A, B](t: TTable[A, B]): B =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield t.data[h].val
+
+const
+  growthFactor = 2
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc nextTry(h, maxHash: THash): THash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+template rawGetImpl() =
+  var h: THash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].slot != seEmpty:
+    if t.data[h].key == key and t.data[h].slot == seFilled:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+template rawInsertImpl() =
+  var h: THash = hash(key) and high(data)
+  while data[h].slot == seFilled:
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+  data[h].slot = seFilled
+
+proc rawGet[A, B](t: TTable[A, B], key: A): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: TTable[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
+                     key: A, val: B) =
+  rawInsertImpl()
+
+proc enlarge[A, B](t: var TTable[A, B]) =
+  var n: TKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+template putImpl() =
+  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 `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc del*[A, B](t: var TTable[A, B], key: A) =
+  ## deletes `key` from hash table `t`.
+  var index = rawGet(t, key)
+  if index >= 0:
+    t.data[index].slot = seDeleted
+    dec(t.counter)
+
+proc initTable*[A, B](initialSize=64): TTable[A, B] =
+  ## creates a new hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toTable*[A, B](pairs: openarray[tuple[key: A, 
+                    val: B]]): TTable[A, B] =
+  ## creates a new hash table that contains the given `pairs`.
+  result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
+  for key, val in items(pairs): result[key] = val
+
+template dollarImpl(): stmt =
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.add($key)
+      result.add(": ")
+      result.add($val)
+    result.add("}")
+
+proc `$`*[A, B](t: TTable[A, B]): string =
+  ## The `$` operator for hash tables.
+  dollarImpl()
+
+# ------------------------------ count tables -------------------------------
+
+type
+  TCountTable* {.final, myShallow.}[
+      A] = object ## table that counts the number of each key
+    data: seq[tuple[key: A, val: int]]
+    counter: int
+
+proc len*[A](t: TCountTable[A]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A](t: TCountTable[A]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].key
+
+iterator values*[A](t: TCountTable[A]): int =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+proc RawGet[A](t: TCountTable[A], key: A): int =
+  var h: THash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].val != 0:
+    if t.data[h].key == key: return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+proc `[]`*[A](t: TCountTable[A], key: A): int =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## 0 is returned. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A](t: TCountTable[A], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
+                  key: A, val: int) =
+  var h: THash = hash(key) and high(data)
+  while data[h].val != 0: h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+
+proc enlarge[A](t: var TCountTable[A]) =
+  var n: seq[tuple[key: A, val: int]]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) =
+  ## puts a (key, value)-pair into `t`. `val` has to be positive.
+  assert val > 0
+  putImpl()
+
+proc initCountTable*[A](initialSize=64): TCountTable[A] =
+  ## creates a new count table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toCountTable*[A](keys: openArray[A]): TCountTable[A] =
+  ## creates a new count table with every key in `keys` having a count of 1.
+  result = initCountTable[A](nextPowerOfTwo(keys.len+10))
+  for key in items(keys): result[key] = 1
+
+proc `$`*[A](t: TCountTable[A]): string =
+  ## The `$` operator for count tables.
+  dollarImpl()
+
+proc inc*[A](t: var TCountTable[A], key: A, val = 1) = 
+  ## increments `t[key]` by `val`.
+  var index = RawGet(t, key)
+  if index >= 0:
+    inc(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 smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## returns the largest (key,val)-pair. Efficiency: O(n)
+  assert t.len > 0
+  var minIdx = 0
+  for h in 1..high(t.data):
+    if t.data[h].val > 0 and t.data[minIdx].val > t.data[h].val: minIdx = h
+  result.key = t.data[minIdx].key
+  result.val = t.data[minIdx].val
+
+proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
+  assert t.len > 0
+  var maxIdx = 0
+  for h in 1..high(t.data):
+    if t.data[maxIdx].val < t.data[h].val: maxIdx = h
+  result.key = t.data[maxIdx].key
+  result.val = t.data[maxIdx].val
+
+proc sort*[A](t: var TCountTable[A]) =
+  ## sorts the count table so that the entry with the highest counter comes
+  ## first. This is destructive! You must not modify `t` afterwards!
+  ## You can use the iterators `pairs`,  `keys`, and `values` to iterate over
+  ## `t` in the sorted order.
+
+  # we use shellsort here; fast enough and simple
+  var h = 1
+  while true:
+    h = 3 * h + 1
+    if h >= high(t.data): break
+  while true:
+    h = h div 3
+    for i in countup(h, high(t.data)):
+      var j = i
+      while t.data[j-h].val <= t.data[j].val:
+        var xyz = t.data[j]
+        t.data[j] = t.data[j-h]
+        t.data[j-h] = xyz
+        j = j-h
+        if j < h: break
+    if h == 1: break
+
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+proc countTableTest1 =
+  var s = initTable[string, int](64)
+  for key, val in items(data): s[key] = val
+  var w: tuple[key: string, val: int] #type(otherCountTable.data[0])
+
+  var t = initCountTable[string]()
+  for k, v in items(data): t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert t.largest()[0] == "90"
+  t.sort()
+
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+countTableTest1()
+echo true
+
+
diff --git a/tests/misc/tsimtych.nim b/tests/misc/tsimtych.nim
new file mode 100644
index 000000000..dd969958c
--- /dev/null
+++ b/tests/misc/tsimtych.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tsimtych.nim"
+  line: 10
+  errormsg: "type mismatch: got (bool) but expected \'string\'"
+"""
+# Test 2

+# Simple type checking

+

+var a: string

+a = false #ERROR

+
+
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
new file mode 100644
index 000000000..f7b70dd4d
--- /dev/null
+++ b/tests/misc/tsizeof.nim
@@ -0,0 +1,10 @@
+# Test the sizeof proc

+

+type

+  TMyRecord {.final.} = object

+    x, y: int

+    b: bool

+    r: float

+    s: string

+

+write(stdout, sizeof(TMyRecord))

diff --git a/tests/misc/tslices.nim b/tests/misc/tslices.nim
new file mode 100644
index 000000000..388a46509
--- /dev/null
+++ b/tests/misc/tslices.nim
@@ -0,0 +1,59 @@
+discard """
+  file: "tslices.nim"
+  output: '''456456
+456456
+456456
+Zugr5nd
+egerichtetd
+verichtetd
+'''
+"""
+
+# Test the new slices.
+
+import strutils
+
+var mystr = "Abgrund"
+mystr[..1] = "Zu"
+
+mystr[4..4] = "5"
+
+type
+  TEnum = enum e1, e2, e3, e4, e5, e6
+
+var myarr: array[TEnum, int] = [1, 2, 3, 4, 5, 6]
+myarr[e1..e3] = myarr[e4..e6]
+myarr[..e3] = myarr[e4..e6]
+
+for x in items(myarr): stdout.write(x)
+echo()
+
+var myarr2: array[0..5, int] = [1, 2, 3, 4, 5, 6]
+myarr2[0..2] = myarr2[3..5]
+
+for x in items(myarr2): stdout.write(x)
+echo()
+
+
+var myseq = @[1, 2, 3, 4, 5, 6]
+myseq[0..2] = myseq[^3 .. ^1]
+
+for x in items(myseq): stdout.write(x)
+echo()
+
+echo mystr
+
+mystr[4..4] = "u"
+
+# test full replacement
+mystr[.. ^2] = "egerichtet"
+
+echo mystr
+
+mystr[0..2] = "ve"
+echo mystr
+
+var s = "abcdef"
+s[1 .. ^2] = "xyz"
+assert s == "axyzf"
+
diff --git a/tests/misc/tsortdev.nim b/tests/misc/tsortdev.nim
new file mode 100644
index 000000000..d7d42d22c
--- /dev/null
+++ b/tests/misc/tsortdev.nim
@@ -0,0 +1,59 @@
+discard """
+  output: "done"
+"""
+
+import algorithm, strutils
+
+proc cmpPlatforms(a, b: string): int =
+  if a == b: return 0
+  var dashes = a.split('-')
+  var dashes2 = b.split('-')
+  if dashes[0] == dashes2[0]:
+    if dashes[1] == dashes2[1]: return system.cmp(a,b)
+    case dashes[1]
+    of "x86":
+      return 1
+    of "x86_64":
+      if dashes2[1] == "x86": return -1
+      else: return 1
+    of "ppc64":
+      if dashes2[1] == "x86" or dashes2[1] == "x86_64": return -1
+      else: return 1
+    else:
+      return system.cmp(dashes[1], dashes2[1])
+  else:
+    case dashes[0]
+    of "linux":
+      return 1
+    of "windows":
+      if dashes2[0] == "linux": return -1
+      else: return 1
+    of "macosx":
+      if dashes2[0] == "linux" or dashes2[0] == "windows": return -1
+      else: return 1
+    else:
+      if dashes2[0] == "linux" or dashes2[0] == "windows" or
+         dashes2[0] == "macosx": return -1
+      else:
+        return system.cmp(a, b)
+
+proc sorted[T](a: openArray[T]): bool = 
+  result = true
+  for i in 0 .. < a.high:
+    if cmpPlatforms(a[i], a[i+1]) > 0: 
+      echo "Out of order: ", a[i], " ", a[i+1]
+      result = false
+
+proc main() =
+  var testData = @["netbsd-x86_64", "windows-x86", "linux-x86_64", "linux-x86", 
+    "linux-ppc64", "macosx-x86-1058", "macosx-x86-1068"]
+    
+  sort(testData, cmpPlatforms)
+
+  doAssert sorted(testData)
+
+for i in 0..1_000:
+  main()
+
+echo "done"
+
diff --git a/tests/misc/tstrace.nim b/tests/misc/tstrace.nim
new file mode 100644
index 000000000..3032a34a3
--- /dev/null
+++ b/tests/misc/tstrace.nim
@@ -0,0 +1,16 @@
+# Test the new stacktraces (great for debugging!)

+

+{.push stack_trace: on.}

+

+proc recTest(i: int) =

+  # enter

+  if i < 10:

+    recTest(i+1)

+  else: # should printStackTrace()

+    var p: ptr int = nil

+    p[] = 12

+  # leave

+

+{.pop.}

+

+recTest(0)

diff --git a/tests/misc/tstrange.nim b/tests/misc/tstrange.nim
new file mode 100644
index 000000000..8742011bb
--- /dev/null
+++ b/tests/misc/tstrange.nim
@@ -0,0 +1,28 @@
+discard """
+  file: "tstrange.nim"
+  output: '''hallo40
+1
+2'''
+"""
+# test for extremely strange bug

+

+proc ack(x: int, y: int): int =

+  if x != 0:

+    if y != 5:

+      return y

+    return x

+  return x+y

+

+proc gen[T](a: T) =

+  write(stdout, a)

+

+

+gen("hallo")

+write(stdout, ack(5, 4))

+#OUT hallo4

+

+# bug #1442
+let h=3
+for x in 0.. <h.int:
+  echo x
+
diff --git a/tests/misc/tstrdesc.nim b/tests/misc/tstrdesc.nim
new file mode 100644
index 000000000..1c2e85b4b
--- /dev/null
+++ b/tests/misc/tstrdesc.nim
@@ -0,0 +1,14 @@
+var

+  x: array [0..2, int]

+

+x = [0, 1, 2]

+

+type

+  TStringDesc {.final.} = object

+    len, space: int # len and space without counting the terminating zero

+    data: array [0..0, char] # for the '\0' character

+

+var

+  emptyString {.exportc: "emptyString".}: TStringDesc 

+

+

diff --git a/tests/misc/tstrdist.nim b/tests/misc/tstrdist.nim
new file mode 100644
index 000000000..3e1939e73
--- /dev/null
+++ b/tests/misc/tstrdist.nim
@@ -0,0 +1,26 @@
+# compute the edit distance between two strings
+
+proc editDistance(a, b: string): int =
+  var
+    c: seq[int]
+    n = a.len
+    m = b.len
+  newSeq(c, (n+1)*(m+1))
+  for i in 0..n:
+    c[i*n] = i # [i,0]
+  for j in 0..m:
+    c[j] = j # [0,j]
+
+  for i in 1..n:
+    for j in 1..m:
+      var x = c[(i-1)*n + j]+1
+      var y = c[i*n + j-1]+1
+      var z: int
+      if a[i-1] == b[j-1]:
+        z = c[(i-1)*n + j-1]
+      else:
+        z = c[(i-1)*n + j-1]+1
+      c[(i-1)*n + (j-1)] = min(x,min(y,z))
+  return c[n*m]
+
+write(stdout, editDistance("abc", "abd"))
diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim
new file mode 100644
index 000000000..3007405a2
--- /dev/null
+++ b/tests/misc/tunsigned64mod.nim
@@ -0,0 +1,26 @@
+
+# bug #1638
+
+import unsigned
+
+let v1 = 7
+let v2 = 7'u64
+
+let t1 = v1 mod 2 # works
+let t2 = 7'u64 mod 2'u64 # works
+let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64)
+let t4 = (v2 mod 2'u64).uint64 # works
+
+# bug #2550
+
+var x: uint # doesn't work
+echo x mod 2 == 0
+
+var y: uint64 # doesn't work
+echo y mod 2 == 0
+
+var z: uint32 # works
+echo z mod 2 == 0
+
+var a: int # works
+echo a mod 2 == 0
diff --git a/tests/misc/tunsignedcmp.nim b/tests/misc/tunsignedcmp.nim
new file mode 100644
index 000000000..a66fbaae1
--- /dev/null
+++ b/tests/misc/tunsignedcmp.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''true
+true
+true'''
+"""
+
+# bug 1420
+import unsigned
+
+var x = 40'u32
+var y = 30'u32
+echo x > y # works
+
+echo((40'i32) > (30'i32))
+echo((40'u32) > (30'u32)) # Error: ordinal type expected
diff --git a/tests/misc/tunsignedcomp.nim b/tests/misc/tunsignedcomp.nim
new file mode 100644
index 000000000..19c8876b1
--- /dev/null
+++ b/tests/misc/tunsignedcomp.nim
@@ -0,0 +1,136 @@
+discard """
+  output: ''''''
+  disabled: "true"
+"""
+
+# All operations involving uint64 are commented out
+# as they're not yet supported.
+# All other operations are handled by implicit conversions from uints to ints
+# uint64 could be supported but would need special implementation of the operators
+
+# unsigned < signed
+
+assert 10'u8 < 20'i8
+assert 10'u8 < 20'i16
+assert 10'u8 < 20'i32
+assert 10'u8 < 20'i64
+
+assert 10'u16 < 20'i8
+assert 10'u16 < 20'i16
+assert 10'u16 < 20'i32
+assert 10'u16 < 20'i64
+
+assert 10'u32 < 20'i8
+assert 10'u32 < 20'i16
+assert 10'u32 < 20'i32
+assert 10'u32 < 20'i64
+
+# assert 10'u64 < 20'i8
+# assert 10'u64 < 20'i16
+# assert 10'u64 < 20'i32
+# assert 10'u64 < 20'i64
+
+# signed < unsigned
+assert 10'i8 < 20'u8
+assert 10'i8 < 20'u16
+assert 10'i8 < 20'u32
+# assert 10'i8 < 20'u64
+
+assert 10'i16 < 20'u8
+assert 10'i16 < 20'u16
+assert 10'i16 < 20'u32
+# assert 10'i16 < 20'u64
+
+assert 10'i32 < 20'u8
+assert 10'i32 < 20'u16
+assert 10'i32 < 20'u32
+# assert 10'i32 < 20'u64
+
+assert 10'i64 < 20'u8
+assert 10'i64 < 20'u16
+assert 10'i64 < 20'u32
+# assert 10'i64 < 20'u64
+
+# unsigned <= signed
+assert 10'u8 <= 20'i8
+assert 10'u8 <= 20'i16
+assert 10'u8 <= 20'i32
+assert 10'u8 <= 20'i64
+
+assert 10'u16 <= 20'i8
+assert 10'u16 <= 20'i16
+assert 10'u16 <= 20'i32
+assert 10'u16 <= 20'i64
+
+assert 10'u32 <= 20'i8
+assert 10'u32 <= 20'i16
+assert 10'u32 <= 20'i32
+assert 10'u32 <= 20'i64
+
+# assert 10'u64 <= 20'i8
+# assert 10'u64 <= 20'i16
+# assert 10'u64 <= 20'i32
+# assert 10'u64 <= 20'i64
+
+# signed <= unsigned
+assert 10'i8 <= 20'u8
+assert 10'i8 <= 20'u16
+assert 10'i8 <= 20'u32
+# assert 10'i8 <= 20'u64
+
+assert 10'i16 <= 20'u8
+assert 10'i16 <= 20'u16
+assert 10'i16 <= 20'u32
+# assert 10'i16 <= 20'u64
+
+assert 10'i32 <= 20'u8
+assert 10'i32 <= 20'u16
+assert 10'i32 <= 20'u32
+# assert 10'i32 <= 20'u64
+
+assert 10'i64 <= 20'u8
+assert 10'i64 <= 20'u16
+assert 10'i64 <= 20'u32
+# assert 10'i64 <= 20'u64
+
+# signed == unsigned
+assert 10'i8 == 10'u8
+assert 10'i8 == 10'u16
+assert 10'i8 == 10'u32
+# assert 10'i8 == 10'u64
+
+assert 10'i16 == 10'u8
+assert 10'i16 == 10'u16
+assert 10'i16 == 10'u32
+# assert 10'i16 == 10'u64
+
+assert 10'i32 == 10'u8
+assert 10'i32 == 10'u16
+assert 10'i32 == 10'u32
+# assert 10'i32 == 10'u64
+
+assert 10'i64 == 10'u8
+assert 10'i64 == 10'u16
+assert 10'i64 == 10'u32
+# assert 10'i64 == 10'u64
+
+# unsigned == signed
+assert 10'u8 == 10'i8
+assert 10'u8 == 10'i16
+assert 10'u8 == 10'i32
+# assert 10'u8 == 10'i64
+
+assert 10'u16 == 10'i8
+assert 10'u16 == 10'i16
+assert 10'u16 == 10'i32
+# assert 10'u16 == 10'i64
+
+assert 10'u32 == 10'i8
+assert 10'u32 == 10'i16
+assert 10'u32 == 10'i32
+# assert 10'u32 == 10'i64
+
+# assert 10'u64 == 10'i8
+# assert 10'u64 == 10'i16
+# assert 10'u64 == 10'i32
+# assert 10'u64 == 10'i64
diff --git a/tests/misc/tunsignedconv.nim b/tests/misc/tunsignedconv.nim
new file mode 100644
index 000000000..3032f8de6
--- /dev/null
+++ b/tests/misc/tunsignedconv.nim
@@ -0,0 +1,43 @@
+
+import unsigned
+
+# Tests unsigned literals and implicit conversion between uints and ints
+# Passes if it compiles
+
+var h8:uint8 = 128
+var h16:uint16 = 32768
+var h32:uint32 = 2147483648'u32
+var h64:uint64 = 9223372036854775808'u64
+var foobar:uint64 = 9223372036854775813'u64 # Issue 728
+
+var v8:uint8 = 10
+var v16:uint16 = 10
+var v32:uint32 = 10
+var v64:uint64 = 10
+
+# u8 + literal produces u8:
+var a8: uint8 = v8 + 10
+var a16: uint16 = v16 + 10
+
+when false:
+  var d8  = v8 + 10'i8
+  var d16 = v8 + 10'i16
+  var d32 = v8 + 10'i32
+
+when false:
+  # these dont work yet because unsigned.nim is stupid. XXX We need to fix this.
+  var f8  = v16 + 10'u8
+  var f16 = v16 + 10'u16
+  var f32 = v16 + 10'u32
+
+  var g8  = v32 + 10'u8
+  var g16 = v32 + 10'u16
+  var g32 = v32 + 10'u32
+
+var ar: array[0..20, int]
+var n8 = ar[v8]
+var n16 = ar[v16]
+var n32 = ar[v32]
+var n64 = ar[v64]
+
+
diff --git a/tests/misc/tunsignedinc.nim b/tests/misc/tunsignedinc.nim
new file mode 100644
index 000000000..95622156f
--- /dev/null
+++ b/tests/misc/tunsignedinc.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''253'''
+"""
+
+# bug #2427
+
+import unsigned
+
+var x = 0'u8
+dec x # OverflowError
+x -= 1 # OverflowError
+x = x - 1 # No error
+
+echo x
diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim
new file mode 100644
index 000000000..8124b3fc7
--- /dev/null
+++ b/tests/misc/tvarious.nim
@@ -0,0 +1,68 @@
+# Test various aspects
+
+# bug #572
+var a=12345678901'u64
+
+var x = (x: 42, y: (a: 8, z: 10))
+echo x.y
+
+import
+  mvarious
+
+type
+  PA = ref TA
+  PB = ref TB
+
+  TB = object
+    a: PA
+
+  TA = object
+    b: TB
+    x: int
+
+proc getPA(): PA =
+  var
+    b: bool
+  b = not false
+  return nil
+
+# bug #501
+proc f(): int = 54
+
+var
+  global: int
+
+var
+  s: string
+  i: int
+  r: TA
+
+r.b.a.x = 0
+global = global + 1
+exportme()
+write(stdout, "Hallo wie heißt du? ")
+write(stdout, getPA().x)
+s = readLine(stdin)
+i = 0
+while i < s.len:
+  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
+  i = i + 1
+
+write(stdout, "Du heißt " & s)
+
+# bug #544
+
+# yay, fails again
+type Bar [T; I:range] = array[I, T]
+proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
+  when len(a) != 3:
+    # Error: constant expression expected
+    {.fatal:"Dimensions have to be 3".}
+  #...
+block:
+  var a, b: Bar[int, range[0..2]]
+  discard foo(a, b)
+
+# bug #1788
+
+echo "hello" & char(ord(' ')) & "world"
diff --git a/tests/misc/tvarious1.nim b/tests/misc/tvarious1.nim
new file mode 100644
index 000000000..1f2da2ae5
--- /dev/null
+++ b/tests/misc/tvarious1.nim
@@ -0,0 +1,48 @@
+discard """
+  file: "tlenopenarray.nim"
+  output: '''1
+0
+Whopie
+12
+1.7'''
+"""
+
+echo len([1_000_000]) #OUT 1
+
+type 
+  TArray = array[0..3, int]
+  TVector = distinct array[0..3, int]
+proc `[]`(v: TVector; idx: int): int = TArray(v)[idx]
+var v: TVector
+echo v[2]
+
+# bug #569
+
+import queues
+
+type
+  TWidget = object
+    names: TQueue[string]
+
+var w = TWidget(names: initQueue[string]())
+
+add(w.names, "Whopie")
+
+for n in w.names: echo(n)
+
+# bug #681
+
+type TSomeRange = object
+  hour: range[0..23]
+
+var value: string
+var val12 = TSomeRange(hour: 12)
+
+value = $(if val12.hour > 12: val12.hour - 12 else: val12.hour)
+echo value
+
+# bug #1334
+
+var ys = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2] 
+#var x = int(ys.high / 2) #echo ys[x] # Works 
+echo ys[int(ys.high / 2)] # Doesn't work
diff --git a/tests/misc/tvarnums.nim b/tests/misc/tvarnums.nim
new file mode 100644
index 000000000..b880cf006
--- /dev/null
+++ b/tests/misc/tvarnums.nim
@@ -0,0 +1,142 @@
+discard """
+  file: "tvarnums.nim"
+  output: "Success!"
+"""
+# Test variable length binary integers

+

+import

+  strutils

+

+type

+  TBuffer = array [0..10, int8]

+

+proc toVarNum(x: int32, b: var TBuffer) =

+  # encoding: first bit indicates end of number (0 if at end)

+  # second bit of the first byte denotes the sign (1 --> negative)

+  var a = x

+  if x != low(x):

+    # low(int) is a special case,

+    # because abs() does not work here!

+    # we leave x as it is and use the check >% instead of >

+    # for low(int) this is needed and positive numbers are not affected

+    # anyway

+    a = abs(x)

+  # first 6 bits:

+  b[0] = toU8(ord(a >% 63'i32) shl 7 or (ord(x < 0'i32) shl 6) or (int(a) and 63))

+  a = a shr 6'i32 # skip first 6 bits

+  var i = 1

+  while a != 0'i32:

+    b[i] = toU8(ord(a >% 127'i32) shl 7 or (int(a) and 127))

+    inc(i)

+    a = a shr 7'i32

+

+proc toVarNum64(x: int64, b: var TBuffer) =

+  # encoding: first bit indicates end of number (0 if at end)

+  # second bit of the first byte denotes the sign (1 --> negative)

+  var a = x

+  if x != low(x):

+    # low(int) is a special case,

+    # because abs() does not work here!

+    # we leave x as it is and use the check >% instead of >

+    # for low(int) this is needed and positive numbers are not affected

+    # anyway

+    a = abs(x)

+  # first 6 bits:

+  b[0] = toU8(ord(a >% 63'i64) shl 7 or (ord(x < 0'i64) shl 6) or int(a and 63))

+  a = a shr 6 # skip first 6 bits

+  var i = 1

+  while a != 0'i64:

+    b[i] = toU8(ord(a >% 127'i64) shl 7 or int(a and 127))

+    inc(i)

+    a = a shr 7

+

+proc toNum64(b: TBuffer): int64 =

+  # treat first byte different:

+  result = ze64(b[0]) and 63

+  var

+    i = 0

+    Shift = 6'i64

+  while (ze(b[i]) and 128) != 0:

+    inc(i)

+    result = result or ((ze64(b[i]) and 127) shl Shift)

+    inc(Shift, 7)

+  if (ze(b[0]) and 64) != 0: # sign bit set?

+    result = not result +% 1

+    # this is the same as ``- result``

+    # but gives no overflow error for low(int)

+

+proc toNum(b: TBuffer): int32 =

+  # treat first byte different:

+  result = ze(b[0]) and 63

+  var

+    i = 0

+    Shift = 6'i32

+  while (ze(b[i]) and 128) != 0:

+    inc(i)

+    result = result or ((int32(ze(b[i])) and 127'i32) shl Shift)

+    Shift = Shift + 7'i32

+  if (ze(b[0]) and (1 shl 6)) != 0: # sign bit set?

+    result = (not result) +% 1'i32

+    # this is the same as ``- result``

+    # but gives no overflow error for low(int)

+

+proc toBinary(x: int64): string =

+  result = newString(64)

+  for i in 0..63:

+    result[63-i] = chr((int(x shr i) and 1) + ord('0'))

+

+proc t64(i: int64) =

+  var

+    b: TBuffer

+  toVarNum64(i, b)

+  var x = toNum64(b)

+  if x != i:

+    writeln(stdout, $i)

+    writeln(stdout, toBinary(i))

+    writeln(stdout, toBinary(x))

+

+proc t32(i: int32) =

+  var

+    b: TBuffer

+  toVarNum(i, b)

+  var x = toNum(b)

+  if x != i:

+    writeln(stdout, toBinary(i))

+    writeln(stdout, toBinary(x))

+

+proc tm(i: int32) =

+  var

+    b: TBuffer

+  toVarNum64(i, b)

+  var x = toNum(b)

+  if x != i:

+    writeln(stdout, toBinary(i))

+    writeln(stdout, toBinary(x))

+

+t32(0)

+t32(1)

+t32(-1)

+t32(-100_000)

+t32(100_000)

+t32(low(int32))

+t32(high(int32))

+

+t64(low(int64))

+t64(high(int64))

+t64(0)

+t64(-1)

+t64(1)

+t64(1000_000)

+t64(-1000_000)

+

+tm(0)

+tm(1)

+tm(-1)

+tm(-100_000)

+tm(100_000)

+tm(low(int32))

+tm(high(int32))

+

+writeln(stdout, "Success!") #OUT Success!

+
+
diff --git a/tests/mmaptest.nim b/tests/mmaptest.nim
new file mode 100644
index 000000000..c304920af
--- /dev/null
+++ b/tests/mmaptest.nim
@@ -0,0 +1,48 @@
+# Small test program to test for mmap() weirdnesses
+
+include "lib/system/ansi_c"
+
+const
+  PageSize = 4096
+  PROT_READ  = 1             # page can be read 
+  PROT_WRITE = 2             # page can be written 
+  MAP_PRIVATE = 2            # Changes are private 
+
+when defined(macosx) or defined(bsd):
+  const MAP_ANONYMOUS = 0x1000
+elif defined(solaris): 
+  const MAP_ANONYMOUS = 0x100
+else:
+  var
+    MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint
+  
+proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
+          off: int): pointer {.header: "<sys/mman.h>".}
+
+proc munmap(adr: pointer, len: int) {.header: "<sys/mman.h>".}
+
+proc osAllocPages(size: int): pointer {.inline.} = 
+  result = mmap(nil, size, PROT_READ or PROT_WRITE, 
+                         MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
+  if result == nil or result == cast[pointer](-1):
+    quit 1
+  cfprintf(c_stdout, "allocated pages %p..%p\n", result, 
+                     cast[int](result) + size)
+    
+proc osDeallocPages(p: pointer, size: int) {.inline} =
+  cfprintf(c_stdout, "freed pages %p..%p\n", p, cast[int](p) + size)
+  munmap(p, size-1)
+
+proc `+!!`(p: pointer, size: int): pointer {.inline.} =
+  result = cast[pointer](cast[int](p) + size)
+
+var p = osAllocPages(3 * PageSize)
+
+osDeallocPages(p, PageSize)
+# If this fails the OS has freed the whole block starting at 'p':
+echo(cast[ptr int](p +!! (pageSize*2))[])
+
+osDeallocPages(p +!! PageSize*2, PageSize)
+osDeallocPages(p +!! PageSize, PageSize)
+
+
diff --git a/tests/modules/mexport2a.nim b/tests/modules/mexport2a.nim
new file mode 100644
index 000000000..3cf84337e
--- /dev/null
+++ b/tests/modules/mexport2a.nim
@@ -0,0 +1,7 @@
+
+import mexport2b
+export mexport2b
+proc printAbc*() = echo "abc"
+
+proc foo*() = echo "A.foo"
+
diff --git a/tests/modules/mexport2b.nim b/tests/modules/mexport2b.nim
new file mode 100644
index 000000000..1af034133
--- /dev/null
+++ b/tests/modules/mexport2b.nim
@@ -0,0 +1,3 @@
+proc printXyz*() = echo "xyz"
+
+proc foo*(x: int) = echo "B.foo"
diff --git a/tests/modules/mexporta.nim b/tests/modules/mexporta.nim
new file mode 100644
index 000000000..b7d4ddec9
--- /dev/null
+++ b/tests/modules/mexporta.nim
@@ -0,0 +1,8 @@
+# module A
+import mexportb
+export mexportb.TMyObject, mexportb.xyz
+
+export mexportb.q
+
+proc `$`*(x: TMyObject): string = "my object"
+
diff --git a/tests/modules/mexportb.nim b/tests/modules/mexportb.nim
new file mode 100644
index 000000000..10d89f388
--- /dev/null
+++ b/tests/modules/mexportb.nim
@@ -0,0 +1,7 @@
+# module B
+type TMyObject* = object
+
+const xyz* = 13
+
+proc q*(x: int): int = 6
+proc q*(x: string): string = "8"
diff --git a/tests/modules/mnamspc1.nim b/tests/modules/mnamspc1.nim
new file mode 100644
index 000000000..da13c5f24
--- /dev/null
+++ b/tests/modules/mnamspc1.nim
@@ -0,0 +1,2 @@
+import mnamspc2

+

diff --git a/tests/modules/mnamspc2.nim b/tests/modules/mnamspc2.nim
new file mode 100644
index 000000000..84ef8533e
--- /dev/null
+++ b/tests/modules/mnamspc2.nim
@@ -0,0 +1,3 @@
+# export an identifier:

+var

+  global*: int

diff --git a/tests/modules/mopaque.nim b/tests/modules/mopaque.nim
new file mode 100644
index 000000000..7eee4bd96
--- /dev/null
+++ b/tests/modules/mopaque.nim
@@ -0,0 +1,7 @@
+type

+  TLexer* {.final.} = object

+    line*: int

+    filename*: string

+    buffer: cstring

+
+proc noProcVar*(): int = 18
diff --git a/tests/modules/mrecmod.nim b/tests/modules/mrecmod.nim
new file mode 100644
index 000000000..fab9654d5
--- /dev/null
+++ b/tests/modules/mrecmod.nim
@@ -0,0 +1 @@
+import trecmod

diff --git a/tests/modules/mrecmod2.nim b/tests/modules/mrecmod2.nim
new file mode 100644
index 000000000..9557ce729
--- /dev/null
+++ b/tests/modules/mrecmod2.nim
@@ -0,0 +1,9 @@
+# Module B
+import trecmod2  
+
+proc p*(x: trecmod2.T1): trecmod2.T1 =
+  # this works because the compiler has already
+  # added T1 to trecmod2's interface symbol table
+  return x + 1
+  
+
diff --git a/tests/modules/texport.nim b/tests/modules/texport.nim
new file mode 100644
index 000000000..9515f9060
--- /dev/null
+++ b/tests/modules/texport.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "my object68"
+"""
+
+import mexporta
+
+# bug #1029:
+from rawsockets import accept
+
+# B.TMyObject has been imported implicitly here: 
+var x: TMyObject
+echo($x, q(0), q"0")
+
diff --git a/tests/modules/texport2.nim b/tests/modules/texport2.nim
new file mode 100644
index 000000000..6e55873c5
--- /dev/null
+++ b/tests/modules/texport2.nim
@@ -0,0 +1,11 @@
+# bug #1595, #1612
+
+import mexport2a
+
+proc main() =
+  echo "Import Test, two lines should follow. One with abc and one with xyz."
+  printAbc()
+  printXyz()
+
+main()
+foo(3)
diff --git a/tests/modules/timportexcept.nim b/tests/modules/timportexcept.nim
new file mode 100644
index 000000000..93a7fd642
--- /dev/null
+++ b/tests/modules/timportexcept.nim
@@ -0,0 +1,10 @@
+discard """
+  line: 9
+  errormsg: "undeclared identifier: '%'"
+"""
+
+import strutils except `%`
+
+# doesn't work
+echo "$1" % "abc"
+
diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim
new file mode 100644
index 000000000..325c729c0
--- /dev/null
+++ b/tests/modules/tmismatchedvisibility.nim
@@ -0,0 +1,9 @@
+discard """
+  line: 8
+  errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration in "
+"""
+
+proc foo(a: int): int
+
+proc foo*(a: int): int =
+  result = a + a
diff --git a/tests/modules/tnamspc.nim b/tests/modules/tnamspc.nim
new file mode 100644
index 000000000..1e2049cec
--- /dev/null
+++ b/tests/modules/tnamspc.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tnamspc.nim"
+  line: 10
+  errormsg: "undeclared identifier: \'global\'"
+"""
+# Test17 - test correct handling of namespaces

+

+import mnamspc1

+

+global = 9 #ERROR

+
+
diff --git a/tests/modules/topaque.nim b/tests/modules/topaque.nim
new file mode 100644
index 000000000..f0587c959
--- /dev/null
+++ b/tests/modules/topaque.nim
@@ -0,0 +1,18 @@
+discard """
+  file: "topaque.nim"
+  line: 16
+  errormsg: "undeclared identifier: \'buffer\'"
+"""
+# Test the new opaque types
+
+import 
+  mopaque
+  
+var
+  L: TLexer
+  
+L.filename = "ha"
+L.line = 34
+L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'
+
+
diff --git a/tests/modules/trecinca.nim b/tests/modules/trecinca.nim
new file mode 100644
index 000000000..14a91ba5c
--- /dev/null
+++ b/tests/modules/trecinca.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tests/reject/trecincb.nim"
+  line: 9
+  errormsg: "recursive dependency: 'tests/modules/trecincb.nim'"
+"""
+# Test recursive includes
+
+include trecincb
+
+echo "trecina"
+
+
diff --git a/tests/modules/trecincb.nim b/tests/modules/trecincb.nim
new file mode 100644
index 000000000..299a242e1
--- /dev/null
+++ b/tests/modules/trecincb.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "trecincb.nim"
+  line: 9
+  errormsg: "recursive dependency: 'tests/modules/trecincb.nim'"
+"""
+# Test recursive includes
+
+
+include trecincb
+
+echo "trecinb"
+
+
diff --git a/tests/modules/trecmod.nim b/tests/modules/trecmod.nim
new file mode 100644
index 000000000..9d39d3ff7
--- /dev/null
+++ b/tests/modules/trecmod.nim
@@ -0,0 +1,2 @@
+# recursive module

+import mrecmod

diff --git a/tests/modules/trecmod2.nim b/tests/modules/trecmod2.nim
new file mode 100644
index 000000000..85fe2215f
--- /dev/null
+++ b/tests/modules/trecmod2.nim
@@ -0,0 +1,10 @@
+type
+  T1* = int  # Module A exports the type ``T1``
+
+import mrecmod2   # the compiler starts parsing B
+
+proc main() =
+  var i = p(3) # works because B has been parsed completely here
+
+main()
+
diff --git a/tests/modules/tselfimport.nim b/tests/modules/tselfimport.nim
new file mode 100644
index 000000000..ddb3a5b09
--- /dev/null
+++ b/tests/modules/tselfimport.nim
@@ -0,0 +1,9 @@
+discard """
+  file: "tselfimport.nim"
+  line: 7
+  errormsg: "A module cannot import itself"
+"""
+import strutils as su # guard against regression
+import tselfimport #ERROR
+echo("Hello World")
+
diff --git a/tests/namedparams/tnamedparams.nim b/tests/namedparams/tnamedparams.nim
new file mode 100644
index 000000000..9397fea4a
--- /dev/null
+++ b/tests/namedparams/tnamedparams.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tnamedparams.nim"
+  line: 8
+  errormsg: "type mismatch: got (input: string, filename: string, line: int literal(1), col: int literal(23))"
+"""
+import pegs
+
+discard parsePeg(
+      input = "input", 
+      filename = "filename", 
+      line = 1, 
+      col = 23)
+
+
+
diff --git a/tests/namedparams/tnamedparams2.nim b/tests/namedparams/tnamedparams2.nim
new file mode 100644
index 000000000..4b0cd5361
--- /dev/null
+++ b/tests/namedparams/tnamedparams2.nim
@@ -0,0 +1,8 @@
+import pegs
+
+discard parsePeg(
+      pattern = "input", 
+      filename = "filename", 
+      line = 1, 
+      col = 23)
+
diff --git a/tests/notnil/tnotnil.nim b/tests/notnil/tnotnil.nim
new file mode 100644
index 000000000..fba7fa917
--- /dev/null
+++ b/tests/notnil/tnotnil.nim
@@ -0,0 +1,23 @@
+discard """
+  line: 22
+  errormsg: "type mismatch"
+"""
+
+type
+  PObj = ref TObj not nil
+  TObj = object
+    x: int
+  
+  MyString = string not nil
+
+#var x: PObj = nil
+
+proc p(x: string not nil): int =
+  result = 45
+
+proc q(x: MyString) = nil
+proc q2(x: string) = nil
+
+q2(nil)
+q(nil)
+
diff --git a/tests/notnil/tnotnil1.nim b/tests/notnil/tnotnil1.nim
new file mode 100644
index 000000000..863fe45f8
--- /dev/null
+++ b/tests/notnil/tnotnil1.nim
@@ -0,0 +1,40 @@
+discard """
+  errormsg: "'y' is provably nil"
+  line:38
+"""
+
+import strutils
+
+
+type
+  TObj = object
+    x, y: int
+
+type
+  superstring = string not nil
+
+
+proc q(s: superstring) =
+  echo s
+
+proc p2() =
+  var  a: string = "I am not nil" 
+  q(a) # but this should and does not
+
+p2()
+
+proc q(x: pointer not nil) =
+  nil
+
+proc p() =
+  var x: pointer
+  if not x.isNil:
+    q(x)
+  
+  let y = x
+  if not y.isNil:
+    q(y)
+  else:
+    q(y)
+
+p()
diff --git a/tests/notnil/tnotnil2.nim b/tests/notnil/tnotnil2.nim
new file mode 100644
index 000000000..bd6b8b675
--- /dev/null
+++ b/tests/notnil/tnotnil2.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "cannot prove 'y' is not nil"
+  line:20
+"""
+
+import strutils
+
+
+type
+  TObj = object
+    x, y: int
+
+proc q(x: pointer not nil) =
+  nil
+
+proc p() =
+  var x: pointer
+  let y = x
+  if not y.isNil or y != x:
+    q(y)
+  else:
+    q(y)
+
+p()
diff --git a/tests/notnil/tnotnil3.nim b/tests/notnil/tnotnil3.nim
new file mode 100644
index 000000000..b7c7a811d
--- /dev/null
+++ b/tests/notnil/tnotnil3.nim
@@ -0,0 +1,35 @@
+discard """
+  errormsg: "cannot prove 'variable' is not nil"
+  line: 31
+"""
+
+# bug #584
+# Testprogram for 'not nil' check
+
+const testWithResult = true
+
+type
+  A = object
+  B = object
+  C = object
+    a: ref A
+    b: ref B
+
+
+proc testNotNil(c: ref C not nil) =
+  discard
+
+
+when testWithResult:
+  proc testNotNilOnResult(): ref C =
+    new(result)
+    #result.testNotNil() # Here 'not nil' can't be proved
+
+
+var variable: ref C
+new(variable)
+variable.testNotNil() # Here 'not nil' is proved
+
+when testWithResult:
+  discard testNotNilOnResult()
+
diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim
new file mode 100644
index 000000000..2fa888357
--- /dev/null
+++ b/tests/notnil/tnotnil4.nim
@@ -0,0 +1,20 @@
+discard ""
+type
+   TObj = ref object
+
+proc check(a: TObj not nil) =
+  echo repr(a)
+
+proc doit() =
+   var x : array[0..1, TObj]
+
+   if x[0] != nil:
+      check(x[0])
+
+doit()
+
+# bug #2352
+
+proc p(x: proc() {.noconv.} not nil) = discard
+p(proc() {.noconv.} = discard)
+# Error: cannot prove 'proc () {.noconv.} = discard ' is not nil
diff --git a/tests/notnil/tnotnil_in_generic.nim b/tests/notnil/tnotnil_in_generic.nim
new file mode 100644
index 000000000..1e2d8b940
--- /dev/null
+++ b/tests/notnil/tnotnil_in_generic.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "cannot prove 'x' is not nil"
+"""
+
+# bug #2216
+
+type
+    A[T] = ref object
+        x: int
+        ud: T
+
+proc good[T](p: A[T]) = 
+    discard
+
+proc bad[T](p: A[T] not nil) = 
+    discard
+
+
+proc go() = 
+    let s = A[int](x: 1)
+
+    good(s)
+    bad(s)
+    var x: A[int]
+    bad(x)
+
+go()
diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim
new file mode 100644
index 000000000..2110bda8f
--- /dev/null
+++ b/tests/notnil/tnotnil_in_objconstr.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "field not initialized: bar"
+  line: "13"
+"""
+
+# bug #2355
+type
+  Foo = object
+    foo: string not nil
+    bar: string not nil
+
+# Create instance without initializaing the `bar` field
+var f = Foo(foo: "foo")
+echo f.bar.isNil # true
diff --git a/tests/objects/tillegal_recursion.nim b/tests/objects/tillegal_recursion.nim
new file mode 100644
index 000000000..171a04f87
--- /dev/null
+++ b/tests/objects/tillegal_recursion.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "illegal recursion in type 'object'"
+  line: 7
+"""
+# bug #1691
+type
+  Foo = ref object of Foo
diff --git a/tests/objects/tinherentedvalues.nim b/tests/objects/tinherentedvalues.nim
new file mode 100644
index 000000000..c96a0fd6d
--- /dev/null
+++ b/tests/objects/tinherentedvalues.nim
@@ -0,0 +1,55 @@
+discard """
+  output: '''tbObj of TC false
+false
+true
+5
+false'''
+"""
+
+# bug #1053
+type
+  TA = object of TObject
+    a: int
+
+  TB = object of TA
+    b: int
+
+  TC = object of TB
+    c: int
+
+proc test(p: TA) =
+  #echo "p of TB ", p of TB
+  if p of TB:
+    var tbObj = TB(p)
+
+    # tbObj is actually no longer compatible with TC:
+    echo "tbObj of TC ", tbObj of TC
+
+var v = TC()
+v.a = 1
+v.b = 2
+v.c = 3
+test(v)
+
+
+# bug #924
+type
+  MyObject = object of TObject
+    x: int
+
+var
+  asd: MyObject
+
+proc isMyObject(obj: TObject) =
+    echo obj of MyObject
+    if obj of MyObject:
+        let a = MyObject(obj)
+        echo a.x
+
+asd.x = 5
+
+var asdCopy = TObject(asd)
+echo asdCopy of MyObject
+
+isMyObject(asd)
+isMyObject(asdCopy)
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
new file mode 100644
index 000000000..226fe98f7
--- /dev/null
+++ b/tests/objects/tobjconstr.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''(k: kindA, a: (x: abc, z: [1, 1, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 2, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 3, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 4, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 5, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 6, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 7, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 8, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 9, 3]), method: ())
+(k: kindA, a: (x: abc, z: [1, 10, 3]), method: ())'''
+"""
+
+type
+  TArg = object
+    x: string
+    z: seq[int]
+  TKind = enum kindXY, kindA
+  TEmpty = object
+  TDummy = ref object
+    case k: TKind
+    of kindXY: x, y: int
+    of kindA:
+      a: TArg
+      `method`: TEmpty # bug #1791
+
+proc `$`[T](s: seq[T]): string =
+  # XXX why is that not in the stdlib?
+  result = "["
+  for i, x in s:
+    if i > 0: result.add(", ")
+    result.add($x)
+  result.add("]")
+
+proc main() =
+  for i in 1..10:
+    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), `method`: TEmpty())
+    echo d[]
+
+main()
+
diff --git a/tests/objects/tobjconstr2.nim b/tests/objects/tobjconstr2.nim
new file mode 100644
index 000000000..39683ddc5
--- /dev/null
+++ b/tests/objects/tobjconstr2.nim
@@ -0,0 +1,50 @@
+type TFoo{.exportc.} = object
+ x:int
+
+var s{.exportc.}: seq[TFoo] = @[]
+
+s.add TFoo(x: 42)
+
+echo s[0].x
+
+
+# bug #563
+type
+  Foo =
+    object {.inheritable.}
+      x: int
+
+  Bar =
+    object of Foo
+      y: int
+
+var a = Bar(y: 100, x: 200) # works
+var b = Bar(x: 100, y: 200) # used to fail
+
+# bug 1275
+
+type
+  Graphic = object of TObject
+    case kind: range[0..1]
+    of 0:
+      radius: float
+    of 1:
+      size: tuple[w, h: float]
+
+var d = Graphic(kind: 1, size: (12.9, 6.9))
+
+# bug #1274
+type
+  K = enum Koo, Kar
+  Graphic2 = object of RootObj
+    case kind: K
+    of Koo:
+      radius: float
+    of Kar:
+      size: tuple[w, h: float]
+
+type NamedGraphic = object of Graphic2
+  name: string
+
+var ngr = NamedGraphic(kind: Koo, radius: 6.9, name: "Foo")
+echo ngr.name
diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim
new file mode 100644
index 000000000..8391727f2
--- /dev/null
+++ b/tests/objects/tobjcov.nim
@@ -0,0 +1,17 @@
+# Covariance is not type safe:
+
+type
+  TA = object of TObject
+    a: int
+  TB = object of TA
+    b: array[0..5000_000, int]
+    
+proc ap(x: var TA) = x.a = -1
+proc bp(x: var TB) = x.b[high(x.b)] = -1
+    
+# in Nim proc (x: TB) is compatible to proc (x: TA),
+# but this is not type safe:
+var f = cast[proc (x: var TA) {.nimcall.}](bp)
+var a: TA
+f(a) # bp expects a TB, but gets a TA
+
diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim
new file mode 100644
index 000000000..5fec84441
--- /dev/null
+++ b/tests/objects/tobject.nim
@@ -0,0 +1,15 @@
+import unittest
+
+type Obj = object
+  foo: int
+
+proc makeObj(x: int): Obj = 
+  result.foo = x
+
+suite "object basic methods":
+  test "it should convert an object to a string":
+    var obj = makeObj(1)
+    # Should be "obj: (foo: 1)" or similar.
+    check($obj == "(foo: 1)")
+  test "it should test equality based on fields":
+    check(makeObj(1) == makeObj(1))
diff --git a/tests/objects/tobject2.nim b/tests/objects/tobject2.nim
new file mode 100644
index 000000000..0f1869695
--- /dev/null
+++ b/tests/objects/tobject2.nim
@@ -0,0 +1,21 @@
+# Tests the object implementation
+
+type
+  TPoint2d {.inheritable.} = object
+    x, y: int
+
+  TPoint3d = object of TPoint2d
+    z: int # added a field
+
+proc getPoint( p: var TPoint2d) =
+  {.breakpoint.}
+  writeln(stdout, p.x)
+
+var
+  p: TPoint3d
+
+TPoint2d(p).x = 34
+p.y = 98
+p.z = 343
+
+getPoint(p)
diff --git a/tests/objects/tobject3.nim b/tests/objects/tobject3.nim
new file mode 100644
index 000000000..85cf1cfe3
--- /dev/null
+++ b/tests/objects/tobject3.nim
@@ -0,0 +1,59 @@
+
+# It turned out that it's hard to generate correct for these two test cases at
+# the same time.
+
+type
+  TFoo = ref object of RootObj
+    Data: int  
+  TBar = ref object of TFoo
+    nil
+  TBar2 = ref object of TBar
+    d2: int
+
+template super(self: TBar): TFoo = self
+
+template super(self: TBar2): TBar = self
+
+proc Foo(self: TFoo) =
+  echo "TFoo"
+
+#proc Foo(self: TBar) =
+#  echo "TBar"
+#  Foo(super(self))
+# works when this code is uncommented
+
+proc Foo(self: TBar2) =
+  echo "TBar2"
+  Foo(super(self))
+
+var b: TBar2
+new(b)
+
+Foo(b)
+
+# bug #837
+type
+  PView* = ref TView
+  TView* {.inheritable.} = object
+    data: int
+
+  PWindow* = ref TWindow
+  TWindow* = object of TView
+    data3: int
+
+  PDesktop* = ref TDesktop
+  TDesktop* = object of TView
+    data2: int
+
+proc makeDesktop(): PDesktop = new(TDesktop)
+
+proc makeWindow(): PWindow = new(TWindow)
+
+proc thisCausesError(a: var PView, b: PView) =
+  discard
+
+var dd = makeDesktop()
+var aa = makeWindow()
+
+thisCausesError(dd, aa)
+
diff --git a/tests/objects/tobjects.nim b/tests/objects/tobjects.nim
new file mode 100644
index 000000000..06fa15583
--- /dev/null
+++ b/tests/objects/tobjects.nim
@@ -0,0 +1,52 @@
+type
+  TBase = object of TObject
+    x, y: int
+
+  TSubclassKind = enum ka, kb, kc, kd, ke, kf
+  TSubclass = object of TBase
+    case c: TSubclassKind
+    of ka, kb, kc, kd:
+      a, b: int
+    of ke:
+      d, e, f: char
+    else: nil
+    n: bool
+
+type
+  TMyObject = object of TObject
+    case disp: range[0..4]
+      of 0: arg: char
+      of 1: s: string
+      else: wtf: bool
+      
+var
+  x: TMyObject
+
+var
+  global: int
+
+var
+  s: string
+  r: float = 0.0
+  i: int = 500 + 400
+
+case i
+of 500..999: write(stdout, "ha!\n")
+of 1000..3000, 12: write(stdout, "ganz schön groß\n")
+of 1, 2, 3: write(stdout, "1 2 oder 3\n")
+else: write(stdout, "sollte nicht passieren\n")
+
+case readLine(stdin)
+of "Rumpf": write(stdout, "Hallo Meister!\n")
+of "Andreas": write(stdout, "Hallo Meister!\n")
+else: write(stdout, "Nicht mein Meister!\n")
+
+global = global + 1
+write(stdout, "Hallo wie heißt du? \n")
+s = readLine(stdin)
+i = 0
+while i < len(s):
+  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
+  i = i + 1
+
+write(stdout, "Du heißt " & s)
diff --git a/tests/objects/tobjloop.nim b/tests/objects/tobjloop.nim
new file mode 100644
index 000000000..9fea1e2fb
--- /dev/null
+++ b/tests/objects/tobjloop.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "is Nil false"
+"""
+# bug #1658
+
+type
+  Loop* = ref object
+    onBeforeSelect*: proc (L: Loop)
+
+var L: Loop
+new L
+L.onBeforeSelect = proc (bar: Loop) =
+  echo "is Nil ", bar.isNil
+
+L.onBeforeSelect(L)
diff --git a/tests/objects/tobjpragma.nim b/tests/objects/tobjpragma.nim
new file mode 100644
index 000000000..dda8057b6
--- /dev/null
+++ b/tests/objects/tobjpragma.nim
@@ -0,0 +1,52 @@
+discard """
+  file: "tobjpragma.nim"
+  output: '''2
+3
+9
+257
+1
+2
+3'''
+  disabled: "true"
+"""
+
+# Disabled since some versions of GCC ignore the 'packed' attribute
+
+# Test 
+
+type
+  Foo {.packed.} = object
+    a: int8
+    b: int8
+
+  Bar {.packed.} = object
+    a: int8
+    b: int16   
+    
+  Daz {.packed.} = object
+    a: int32
+    b: int8 
+    c: int32  
+
+
+var f = Foo(a: 1, b: 1)
+var b: Bar
+var d: Daz
+
+echo sizeof(f)
+echo sizeof(b)
+echo sizeof(d)
+echo (cast[ptr int16](f.addr)[])
+
+type
+  Union {.union.} = object
+    a: int8
+    b: int8
+
+var u: Union
+u.a = 1
+echo u.b
+u.a = 2
+echo u.b
+u.b = 3
+echo u.a
diff --git a/tests/objects/tofopr.nim b/tests/objects/tofopr.nim
new file mode 100644
index 000000000..961d81bd3
--- /dev/null
+++ b/tests/objects/tofopr.nim
@@ -0,0 +1,26 @@
+discard """
+  file: "tofopr.nim"
+  output: "falsetrue"
+"""
+# Test is operator
+
+type
+  TMyType = object {.inheritable.}
+    len: int
+    data: string
+    
+  TOtherType = object of TMyType
+   
+proc p(x: TMyType): bool = 
+  return x of TOtherType
+    
+var
+  m: TMyType
+  n: TOtherType
+
+write(stdout, p(m))
+write(stdout, p(n))
+
+#OUT falsetrue
+
+
diff --git a/tests/objects/toop.nim b/tests/objects/toop.nim
new file mode 100644
index 000000000..0b42c2c22
--- /dev/null
+++ b/tests/objects/toop.nim
@@ -0,0 +1,21 @@
+discard """
+  output: "b"
+"""
+
+type
+  TA = object of TObject
+    x, y: int
+  
+  TB = object of TA
+    z: int
+    
+  TC = object of TB
+    whatever: string
+  
+proc p(a: var TA) = echo "a"
+proc p(b: var TB) = echo "b"
+
+var c: TC
+
+p(c)
+
diff --git a/tests/objects/toop1.nim b/tests/objects/toop1.nim
new file mode 100644
index 000000000..0d8ba124b
--- /dev/null
+++ b/tests/objects/toop1.nim
@@ -0,0 +1,86 @@
+discard """
+  file: "toop1.nim"
+  output: "34[]o 5"
+"""
+# Test the stuff in the tutorial
+import macros
+
+type
+  TFigure = object of RootObj    # abstract base class:
+    draw: proc (my: var TFigure) {.nimcall.} # concrete classes implement this
+  
+proc init(f: var TFigure) = 
+  f.draw = nil
+
+type
+  TCircle = object of TFigure
+    radius: int
+  
+proc drawCircle(my: var TCircle) = stdout.writeln("o " & $my.radius)
+
+proc init(my: var TCircle) = 
+  init(TFigure(my)) # call base constructor
+  my.radius = 5
+  my.draw = cast[proc (my: var TFigure) {.nimcall.}](drawCircle)
+
+type
+  TRectangle = object of TFigure
+    width, height: int
+
+proc drawRectangle(my: var TRectangle) = stdout.write("[]")
+
+proc init(my: var TRectangle) = 
+  init(TFigure(my)) # call base constructor
+  my.width = 5
+  my.height = 10
+  my.draw = cast[proc (my: var TFigure) {.nimcall.}](drawRectangle)
+
+macro `!` (n: expr): stmt {.immediate.} = 
+  let n = callsite()
+  result = newNimNode(nnkCall, n)
+  var dot = newNimNode(nnkDotExpr, n)
+  dot.add(n[1])    # obj
+  if n[2].kind == nnkCall:
+    # transforms ``obj!method(arg1, arg2, ...)`` to
+    # ``(obj.method)(obj, arg1, arg2, ...)``
+    dot.add(n[2][0]) # method
+    result.add(dot)
+    result.add(n[1]) # obj
+    for i in 1..n[2].len-1:
+      result.add(n[2][i])
+  else:
+    # transforms ``obj!method`` to
+    # ``(obj.method)(obj)``
+    dot.add(n[2]) # method
+    result.add(dot)
+    result.add(n[1]) # obj
+
+type
+  TSocket* = object of RootObj
+    FHost: int # cannot be accessed from the outside of the module
+               # the `F` prefix is a convention to avoid clashes since
+               # the accessors are named `host`
+               
+proc `host=`*(s: var TSocket, value: int) {.inline.} = 
+  ## setter of hostAddr
+  s.FHost = value
+
+proc host*(s: TSocket): int {.inline.} =
+  ## getter of hostAddr
+  return s.FHost
+  
+var 
+  s: TSocket
+s.host = 34  # same as `host=`(s, 34)
+stdout.write(s.host)
+
+# now use these classes:
+var
+  r: TRectangle
+  c: TCircle
+init(r)
+init(c)
+r!draw
+c!draw() 
+
+#OUT 34[]o 5
diff --git a/tests/objects/trefobjsyntax.nim b/tests/objects/trefobjsyntax.nim
new file mode 100644
index 000000000..9b48de718
--- /dev/null
+++ b/tests/objects/trefobjsyntax.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''wohoo
+baz'''
+"""
+
+# Test to ensure the popular 'ref T' syntax works everywhere
+
+type
+  Foo = object
+    a, b: int
+    s: string
+
+  FooBar = object of RootObj
+    n, m: string
+  Baz = object of FooBar
+
+proc invoke(a: ref Baz) =
+  echo "baz"
+
+# check object construction:
+let x = (ref Foo)(a: 0, b: 45, s: "wohoo")
+echo x.s
+
+var y: ref FooBar = (ref Baz)(n: "n", m: "m")
+
+invoke((ref Baz)(y))
+
diff --git a/tests/objects/trefobjsyntax2.nim b/tests/objects/trefobjsyntax2.nim
new file mode 100644
index 000000000..8ee209cc7
--- /dev/null
+++ b/tests/objects/trefobjsyntax2.nim
@@ -0,0 +1,19 @@
+# bug #2508
+
+type
+  GenericNodeObj[T] = ref object
+    obj: T
+
+  Node* = ref object
+    children*: seq[Node]
+    parent*: Node
+
+    nodeObj*: GenericNodeObj[int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+    result = Node(nodeObj: nodeObj)
+    newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+
+var myNode = newNode(genericObj)
diff --git a/tests/objvariant/tadrdisc.nim b/tests/objvariant/tadrdisc.nim
new file mode 100644
index 000000000..1afe7d04f
--- /dev/null
+++ b/tests/objvariant/tadrdisc.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "tadrdisc.nim"
+  line: 20
+  errormsg: "type mismatch: got (TKind)"
+"""
+# Test that the address of a dicriminants cannot be taken
+
+type
+  TKind = enum ka, kb, kc
+  TA = object
+    case k: TKind
+    of ka: x, y: int
+    of kb: a, b: string
+    of kc: c, d: float
+
+proc setKind(k: var TKind) =
+  k = kc
+
+var a: TA
+setKind(a.k)
diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim
new file mode 100644
index 000000000..1963ceb8d
--- /dev/null
+++ b/tests/objvariant/tcheckedfield1.nim
@@ -0,0 +1,60 @@
+discard """
+  msg: "Warning: cannot prove that field 'x.s' is accessible [ProveField]"
+  line:51
+"""
+
+import strutils
+
+{.warning[ProveField]: on.}
+
+type
+  TNodeKind = enum
+    nkBinary, nkTernary, nkStr
+  PNode = ref TNode not nil
+  TNode = object
+    case k: TNodeKind
+    of nkBinary, nkTernary: a, b: PNode
+    of nkStr: s: string
+    
+  PList = ref object
+    data: string
+    next: PList
+
+proc getData(x: PList not nil) =
+  echo x.data
+
+var head: PList
+
+proc processList() =
+  var it = head
+  while it != nil:
+    getData(it)
+    it = it.next
+
+proc toString2(x: PNode): string =
+  if x.k < nkStr:
+    toString2(x.a) & " " & toString2(x.b)
+  else:
+    x.s
+
+proc toString(x: PNode): string =
+  case x.k
+  of nkTernary, nkBinary:
+    toString(x.a) & " " & toString(x.b)
+  of nkStr:
+    x.s
+
+proc toString3(x: PNode): string =
+  if x.k <= nkBinary:
+    toString3(x.a) & " " & toString3(x.b)
+  else:
+    x.s # x.k in {nkStr}  --> fact:  not (x.k <= nkBinary)
+
+proc p() =
+  var x: PNode = PNode(k: nkStr, s: "abc")
+  
+  let y = x
+  if not y.isNil:
+    echo toString(y), " ", toString2(y)
+
+p()
diff --git a/tests/objvariant/temptycaseobj.nim b/tests/objvariant/temptycaseobj.nim
new file mode 100644
index 000000000..5c012746e
--- /dev/null
+++ b/tests/objvariant/temptycaseobj.nim
@@ -0,0 +1,14 @@
+discard """
+  line: 11
+  errormsg: "identifier expected, but found 'keyword of'"
+"""
+
+type
+  TMyEnum = enum enA, enU, enO
+  TMyCase = object
+    case e: TMyEnum
+    of enA:
+    of enU: x, y: int
+    of enO: a, b: string
+
+
diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim
new file mode 100644
index 000000000..2938b30a3
--- /dev/null
+++ b/tests/objvariant/treassign.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "SUCCESS"
+"""
+
+type
+    BasicNumber = object of RootObj
+        value: float32
+    RefChild* = ref object
+        curr*: TokenObject
+    Token* {.pure.} = enum
+        foo,
+        bar,
+    TokenObject = object
+        case kind*: Token
+        of Token.foo:
+            foo*: string
+        of Token.bar:
+            bar*: BasicNumber
+
+
+var t = RefChild()
+
+t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34))
+
+t.curr = TokenObject(kind: Token.foo, foo: "foo")
+
+echo "SUCCESS"
diff --git a/tests/objvariant/tvariantstack.nim b/tests/objvariant/tvariantstack.nim
new file mode 100644
index 000000000..d81f6e001
--- /dev/null
+++ b/tests/objvariant/tvariantstack.nim
@@ -0,0 +1,52 @@
+discard """
+  file: "tvariantstack.nim"
+  output: "came here"
+"""
+#BUG
+type
+  TAnyKind = enum
+    nkInt,
+    nkFloat,
+    nkString
+  PAny = ref TAny
+  TAny = object
+    case kind: TAnyKind
+    of nkInt: intVal: int
+    of nkFloat: floatVal: float
+    of nkString: strVal: string
+
+  TStack* = object
+    list*: seq[TAny]
+
+proc newStack(): TStack =
+  result.list = @[]
+
+proc push(Stack: var TStack, item: TAny) =
+  var nSeq: seq[TAny] = @[item]
+  for i in items(Stack.list):
+    nSeq.add(i)
+  Stack.list = nSeq
+
+proc pop(Stack: var TStack): TAny =
+  result = Stack.list[0]
+  Stack.list.delete(0)
+
+var stack = newStack()
+
+var s: TAny
+s.kind = nkString
+s.strVal = "test"
+
+stack.push(s)
+
+var nr: TAny
+nr.kind = nkint
+nr.intVal = 78
+
+stack.push(nr)
+
+var t = stack.pop()
+echo "came here"
+
+
+
diff --git a/tests/objvariant/tyaoption.nim b/tests/objvariant/tyaoption.nim
new file mode 100644
index 000000000..7a29b8008
--- /dev/null
+++ b/tests/objvariant/tyaoption.nim
@@ -0,0 +1,47 @@
+discard """
+  output: '''some(str), some(5), none
+some(5!)
+some(10)'''
+"""
+
+import strutils
+
+type Option[A] = object
+  case isDefined*: bool
+    of true:
+      value*: A
+    of false:
+      nil
+
+proc some[A](value: A): Option[A] =
+  Option[A](isDefined: true, value: value)
+
+proc none[A](): Option[A] =
+  Option[A](isDefined: false)
+
+proc `$`[A](o: Option[A]): string =
+  if o.isDefined:
+    "some($1)" % [$o.value]
+  else:
+    "none"
+
+let x = some("str")
+let y = some(5)
+let z = none[int]()
+
+echo x, ", ", y, ", ", z
+
+proc intOrString[A : int | string](o: Option[A]): Option[A] =
+  when A is int:
+    some(o.value + 5)
+  elif A is string:
+    some(o.value & "!")
+  else:
+    o
+
+#let a1 = intOrString(none[String]())
+let a2 = intOrString(some("5"))
+let a3 = intOrString(some(5))
+#echo a1
+echo a2
+echo a3
diff --git a/tests/openarray/topena1.nim b/tests/openarray/topena1.nim
new file mode 100644
index 000000000..0dbc5506a
--- /dev/null
+++ b/tests/openarray/topena1.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "topena1.nim"
+  line: 9
+  errormsg: "invalid type"
+"""
+# Tests a special bug
+
+var
+  x: ref openarray[string] #ERROR_MSG invalid type
+
+
+
diff --git a/tests/openarray/topenarrayrepr.nim b/tests/openarray/topenarrayrepr.nim
new file mode 100644
index 000000000..d276756bc
--- /dev/null
+++ b/tests/openarray/topenarrayrepr.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "topenarrayrepr.nim"
+  output: "5 - [1]"
+"""
+type
+  TProc = proc (n: int, m: openarray[int64]) {.nimcall.}
+
+proc Foo(x: int, P: TProc) =
+  P(x, [ 1'i64 ])
+
+proc Bar(n: int, m: openarray[int64]) =
+  echo($n & " - " & repr(m))
+
+Foo(5, Bar) #OUT 5 - [1]
+
+
+
diff --git a/tests/openarray/topenlen.nim b/tests/openarray/topenlen.nim
new file mode 100644
index 000000000..fec8e87b7
--- /dev/null
+++ b/tests/openarray/topenlen.nim
@@ -0,0 +1,18 @@
+discard """
+  file: "topenlen.nim"
+  output: "7"
+"""
+# Tests a special bug
+
+proc choose(b: openArray[string]): string = return b[0]
+
+proc p(a, b: openarray[string]): int =
+  result = a.len + b.len - 1
+  for j in 0 .. a.len: inc(result)
+  discard choose(a)
+  discard choose(b)
+
+discard choose(["sh", "-c", $p([""], ["a"])])
+echo($p(["", "ha", "abc"], ["xyz"])) #OUT 7
+
+
diff --git a/tests/osproc/ta.nim b/tests/osproc/ta.nim
new file mode 100644
index 000000000..6c1495590
--- /dev/null
+++ b/tests/osproc/ta.nim
@@ -0,0 +1,3 @@
+import strutils
+let x = stdin.readLine()
+echo x.parseInt + 5
\ No newline at end of file
diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim
new file mode 100644
index 000000000..b491c2500
--- /dev/null
+++ b/tests/osproc/tstdin.nim
@@ -0,0 +1,19 @@
+discard """
+  file: "tstdin.nim"
+  output: "10"
+"""
+import osproc, os, streams
+
+const filename = when defined(Windows): "ta.exe" else: "ta"
+
+doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename)
+
+var p = startProcess(filename, getCurrentDir() / "tests" / "osproc")
+p.inputStream.write("5\n")
+p.inputStream.flush()
+while true:
+  let line = p.outputStream.readLine()
+  if line != "":
+    echo line
+  else:
+    break
diff --git a/tests/overflw/toverflw.nim b/tests/overflw/toverflw.nim
new file mode 100644
index 000000000..fbe0d0a38
--- /dev/null
+++ b/tests/overflw/toverflw.nim
@@ -0,0 +1,21 @@
+discard """
+  file: "toverflw.nim"
+  output: "the computation overflowed"
+"""
+# Tests nim's ability to detect overflows

+

+{.push overflowChecks: on.}

+

+var

+  a, b: int

+a = high(int)

+b = -2

+try:

+  writeln(stdout, b - a)

+except OverflowError:

+  writeln(stdout, "the computation overflowed")

+

+{.pop.} # overflow check

+#OUT the computation overflowed

+
+
diff --git a/tests/overflw/toverflw2.nim b/tests/overflw/toverflw2.nim
new file mode 100644
index 000000000..75bd4cdf5
--- /dev/null
+++ b/tests/overflw/toverflw2.nim
@@ -0,0 +1,10 @@
+discard """
+  file: "toverflw2.nim"
+  outputsub: "Error: unhandled exception: over- or underflow [OverflowError]"
+  exitcode: "1"
+"""
+var a : int32 = 2147483647
+var b : int32 = 2147483647
+var c = a + b
+
+
diff --git a/tests/overflw/tovfint.nim b/tests/overflw/tovfint.nim
new file mode 100644
index 000000000..f0b1ccaa6
--- /dev/null
+++ b/tests/overflw/tovfint.nim
@@ -0,0 +1,23 @@
+discard """
+  file: "tovfint.nim"
+  output: "works!"
+"""
+# this tests the new overflow literals

+

+var

+  i: int

+i = int(0xffffffff'i32)

+when defined(cpu64):

+  if i == -1:

+    write(stdout, "works!\n")

+  else:

+    write(stdout, "broken!\n")

+else:

+  if i == -1:

+    write(stdout, "works!\n")

+  else:

+    write(stdout, "broken!\n")

+

+#OUT works!

+
+
diff --git a/tests/overload/tissue966.nim b/tests/overload/tissue966.nim
new file mode 100644
index 000000000..2911348cf
--- /dev/null
+++ b/tests/overload/tissue966.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got (PTest)"
+"""
+
+type
+  PTest = ref object
+
+proc test(x: PTest, y: int) = nil
+
+var buf: PTest
+buf.test()
+
diff --git a/tests/overload/toverl.nim b/tests/overload/toverl.nim
new file mode 100644
index 000000000..807b643a4
--- /dev/null
+++ b/tests/overload/toverl.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "toverl.nim"
+  line: 11
+  errormsg: "redefinition of \'TNone\'"
+"""
+# Test for overloading
+
+type
+  TNone {.exportc: "_NONE", final.} = object
+
+proc TNone(a, b: int) = nil #ERROR_MSG attempt to redefine 'TNone'
+
+
diff --git a/tests/overload/toverl2.nim b/tests/overload/toverl2.nim
new file mode 100644
index 000000000..ea0249e9f
--- /dev/null
+++ b/tests/overload/toverl2.nim
@@ -0,0 +1,33 @@
+discard """
+  file: "toverl2.nim"
+  output: "true012innertrue"
+"""
+# Test new overloading resolution rules
+
+import strutils
+
+proc toverl2(x: int): string = return $x
+proc toverl2(x: bool): string = return $x
+
+iterator toverl2(x: int): int = 
+  var res = 0
+  while res < x: 
+    yield res
+    inc(res)
+
+var
+  pp: proc (x: bool): string {.nimcall.} = toverl2
+
+stdout.write(pp(true))
+
+for x in toverl2(3): 
+  stdout.write(toverl2(x))
+
+block:
+  proc toverl2(x: int): string = return "inner"
+  stdout.write(toverl2(5))
+  stdout.write(true)
+
+stdout.write("\n")
+#OUT true012innertrue
+
diff --git a/tests/overload/toverl3.nim b/tests/overload/toverl3.nim
new file mode 100644
index 000000000..b3e0f2fa7
--- /dev/null
+++ b/tests/overload/toverl3.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "toverl3.nim"
+  output: '''m1
+tup1'''
+"""
+
+# Tests more specific generic match:

+

+proc m[T](x: T) = echo "m2"
+proc m[T](x: var ref T) = echo "m1"
+
+proc tup[S, T](x: tuple[a: S, b: ref T]) = echo "tup1"
+proc tup[S, T](x: tuple[a: S, b: T]) = echo "tup2"
+
+var
+  obj: ref int
+  tu: tuple[a: int, b: ref bool]
+  
+m(obj)
+tup(tu)
diff --git a/tests/overload/toverl4.nim b/tests/overload/toverl4.nim
new file mode 100644
index 000000000..6bb3a53d1
--- /dev/null
+++ b/tests/overload/toverl4.nim
@@ -0,0 +1,77 @@
+discard """
+  output: '''true'''
+"""
+
+#bug #592
+
+type
+  ElementKind = enum inner, leaf
+  TElement[TKey, TData] = object
+    case kind: ElementKind
+    of inner:
+      key: TKey
+      left, right: ref TElement[Tkey, TData]
+    of leaf:
+      data: TData
+  PElement[TKey, TData] = ref TElement[TKey, TData]
+
+proc newElement[Tkey, TData](other: PElement[TKey, TData]): PElement[Tkey, TData] =
+  case other.kind:
+  of inner:
+    PElement[TKey, TData](kind: ElementKind.inner, key: other.key, left: other.left, right: other.right)
+  of leaf:
+    PElement[TKey, TData](kind: ElementKind.leaf, data: other.data)
+
+proc newElement[TKey, TData](key: TKey, left: PElement[TKey, TData] = nil, right: PElement[TKey, TData] = nil) : PElement[TKey, TData] =
+  PElement[TKey, TData](kind: ElementKind.inner, key: key, left: left, right: right)
+
+proc newElement[Tkey, TData](key: Tkey, data: TData) : PElement[Tkey, TData] =
+  PElement[TKey, TData](kind: ElementKind.leaf, data: data)
+
+proc find*[TKey, TData](root: PElement[TKey, TData], key: TKey): TData {.raises: [EInvalidKey].} =
+  if root.left == nil:
+    raise newException(EInvalidKey, "key does not exist: " & key)
+
+  var tmp_element = addr(root)
+
+  while tmp_element.kind == inner and tmp_element.right != nil:
+    tmp_element = if tmp_element.key > key:
+                    addr(tmp_element.left)
+                  else:
+                    addr(tmp_element.right)
+
+  if tmp_element.key == key:
+    return tmp_element.left.data
+  else:
+    raise newException(EInvalidKey, "key does not exist: " & key)
+
+proc add*[TKey, TData](root: var PElement[TKey, TData], key: TKey, data: TData) : bool =
+  if root.left == nil:
+    root.key = key
+    root.left = newElement[TKey, TData](key, data)
+    return true
+
+  var tmp_element = addr(root)
+
+  while tmp_element.kind == ElementKind.inner and tmp_element.right != nil:
+    tmp_element = if tmp_element.key > key:
+                    addr(tmp_element.left)
+                  else:
+                    addr(tmp_element.right)
+
+  if tmp_element.key == key:
+    return false
+
+  var old_element = newElement[TKey, TData](tmp_element[])
+  var new_element = newElement[TKey, TData](key, data)
+
+  tmp_element[] = if tmp_element.key < key:
+                    newElement(key, old_element, new_element)
+                  else:
+                    newElement(tmp_element.key, new_element, old_element)
+
+  return true
+
+var tree = PElement[int, int](kind: ElementKind.inner, key: 0, left: nil, right: nil)
+let result = add(tree, 1, 1)
+echo(result)
\ No newline at end of file
diff --git a/tests/overload/toverprc.nim b/tests/overload/toverprc.nim
new file mode 100644
index 000000000..78831f744
--- /dev/null
+++ b/tests/overload/toverprc.nim
@@ -0,0 +1,45 @@
+discard """
+  output: '''another number: 123
+yay'''
+"""
+
+# Test overloading of procs when used as function pointers
+
+import strutils
+
+proc parseInt(x: float): int {.noSideEffect.} = discard
+proc parseInt(x: bool): int {.noSideEffect.} = discard
+proc parseInt(x: float32): int {.noSideEffect.} = discard
+proc parseInt(x: int8): int {.noSideEffect.} = discard
+proc parseInt(x: TFile): int {.noSideEffect.} = discard
+proc parseInt(x: char): int {.noSideEffect.} = discard
+proc parseInt(x: int16): int {.noSideEffect.} = discard
+
+proc parseInt[T](x: T): int = echo x; 34
+
+type
+  TParseInt = proc (x: string): int {.noSideEffect.}
+
+var
+  q = TParseInt(parseInt)
+  p: TParseInt = parseInt
+
+proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int =
+  result = x("123")
+
+if false:
+  echo "Give a list of numbers (separated by spaces): "
+  var x = stdin.readline.split.map(parseInt).max
+  echo x, " is the maximum!"
+echo "another number: ", takeParseInt(parseInt)
+
+
+type
+  TFoo[a,b] = object
+    lorem: a
+    ipsum: b
+
+proc bar[a,b](f: TFoo[a,b], x: a) = echo(x, " ", f.lorem, f.ipsum)
+proc bar[a,b](f: TFoo[a,b], x: b) = echo(x, " ", f.lorem, f.ipsum)
+
+discard parseInt[string]("yay")
diff --git a/tests/overload/toverwr.nim b/tests/overload/toverwr.nim
new file mode 100644
index 000000000..32d50faaa
--- /dev/null
+++ b/tests/overload/toverwr.nim
@@ -0,0 +1,13 @@
+discard """

+  file: "toverwr.nim"

+  output: "hello"

+"""

+# Test the overloading resolution in connection with a qualifier

+

+proc write(t: TFile, s: string) =

+  discard # a nop

+

+system.write(stdout, "hello")

+#OUT hello

+

+

diff --git a/tests/overload/tparams_after_varargs.nim b/tests/overload/tparams_after_varargs.nim
new file mode 100644
index 000000000..a93e280b9
--- /dev/null
+++ b/tests/overload/tparams_after_varargs.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''a 1 b 2 x @[3, 4, 5] y 6 z 7
+yay
+12'''
+"""
+
+proc test(a, b: int, x: varargs[int]; y, z: int) =
+  echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z
+
+test 1, 2, 3, 4, 5, 6, 7
+
+template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+  blck
+  echo a, b
+
+takesBlock 1, 2, "some", 0.90, "random stuff":
+  echo "yay"
diff --git a/tests/overload/tprefer_specialized_generic.nim b/tests/overload/tprefer_specialized_generic.nim
new file mode 100644
index 000000000..2b41502d1
--- /dev/null
+++ b/tests/overload/tprefer_specialized_generic.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''ref ref T ptr S'''
+"""
+
+proc foo[T](x: T) =
+  echo "only T"
+
+proc foo[T](x: ref T) =
+  echo "ref T"
+
+proc foo[T, S](x: ref ref T; y: ptr S) =
+  echo "ref ref T ptr S"
+
+proc foo[T, S](x: ref T; y: ptr S) =
+  echo "ref T ptr S"
+
+proc foo[T](x: ref T; default = 0) =
+  echo "ref T; default"
+
+var x: ref ref int
+var y: ptr ptr int
+foo(x, y)
diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim
new file mode 100644
index 000000000..9787af06b
--- /dev/null
+++ b/tests/overload/tprefer_tygenericinst.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''Version 2 was called.
+This has the highest precedence.
+This has the second-highest precedence.
+This has the lowest precedence.'''
+"""
+
+# bug #2220
+when true:
+  type A[T] = object
+  type B = A[int]
+
+  proc q[X](x: X) =
+    echo "Version 1 was called."
+
+  proc q(x: B) =
+    echo "Version 2 was called."
+
+  q(B()) # This call reported as ambiguous.
+
+# bug #2219
+template testPred(a: expr) =
+  block:
+    type A = object of RootObj
+    type B = object of A
+    type SomeA = A|A # A hack to make "A" a typeclass.
+
+    when a >= 3:
+      proc p[X](x: X) =
+        echo "This has the highest precedence."
+    when a >= 2:
+      proc p[X: A](x: X) =
+        echo "This has the second-highest precedence."
+    when a >= 1:
+      proc p[X: SomeA](x: X) =
+        echo "This has the lowest precedence."
+
+    p(B())
+
+testPred(3)
+testPred(2)
+testPred(1)
diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim
new file mode 100644
index 000000000..f2002a390
--- /dev/null
+++ b/tests/overload/tspec.nim
@@ -0,0 +1,118 @@
+discard """
+  output: '''not a var
+not a var
+a var
+B
+int
+T
+int16
+T
+ref T
+123
+2
+1
+@[123, 2, 1]
+Called!
+merge with var
+merge no var'''
+"""
+
+# Things that's even in the spec now!
+
+proc byvar(x: var int) = echo "a var"
+proc byvar(x: int) = echo "not a var"
+byvar(89)
+
+let letSym = 0
+var varSym = 13
+
+byvar(letSym)
+byvar(varSym)
+
+type
+  A = object of RootObj
+  B = object of A
+  C = object of B
+
+proc p(obj: A) =
+  echo "A"
+
+proc p(obj: B) =
+  echo "B"
+
+var c = C()
+# not ambiguous, calls 'B', not 'A' since B is a subtype of A
+# but not vice versa:
+p(c)
+
+proc pp(obj: A, obj2: B) = echo "A B"
+proc pp(obj: B, obj2: A) = echo "B A"
+
+# but this is ambiguous:
+#pp(c, c)
+
+proc takesInt(x: int) = echo "int"
+proc takesInt[T](x: T) = echo "T"
+proc takesInt(x: int16) = echo "int16"
+
+takesInt(4) # "int"
+var x: int32
+takesInt(x) # "T"
+var y: int16
+takesInt(y) # "int16"
+var z: range[0..4] = 0
+takesInt(z) # "T"
+
+proc gen[T](x: ref ref T) = echo "ref ref T"
+proc gen[T](x: ref T) = echo "ref T"
+proc gen[T](x: T) = echo "T"
+
+var ri: ref int
+gen(ri) # "ref T"
+
+
+template rem(x: expr) = discard
+#proc rem[T](x: T) = discard
+
+rem unresolvedExpression(undeclaredIdentifier)
+
+
+proc takeV[T](a: varargs[T]) =
+  for x in a: echo x
+
+takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
+echo(@[123, 2, 1])
+
+# bug #2600
+
+type
+  FutureBase* = ref object of RootObj ## Untyped future.
+
+  Future*[T] = ref object of FutureBase ## Typed future.
+    value: T ## Stored value
+
+  FutureVar*[T] = distinct Future[T]
+
+proc newFuture*[T](): Future[T] =
+  new(result)
+
+proc newFutureVar*[T](): FutureVar[T] =
+  result = FutureVar[T](newFuture[T]())
+
+proc mget*[T](future: FutureVar[T]): var T =
+  Future[T](future).value
+
+proc reset*[T](future: FutureVar[T]) =
+  echo "Called!"
+
+proc merge[T](x: Future[T]) = echo "merge no var"
+proc merge[T](x: var Future[T]) = echo "merge with var"
+
+when true:
+  var foo = newFutureVar[string]()
+  foo.mget() = ""
+  foo.mget.add("Foobar")
+  foo.reset()
+  var bar = newFuture[int]()
+  bar.merge # merge with var
+  merge(newFuture[int]()) # merge no var
diff --git a/tests/overload/tstmtoverload.nim b/tests/overload/tstmtoverload.nim
new file mode 100644
index 000000000..f1944b637
--- /dev/null
+++ b/tests/overload/tstmtoverload.nim
@@ -0,0 +1,38 @@
+
+# bug #2481
+import math
+
+template test(loopCount: int, extraI: int, testBody: stmt): stmt =
+  block:
+    for i in 0..loopCount-1:
+      testBody
+    echo "done extraI=", extraI
+
+template test(loopCount: int, extraF: float, testBody: stmt): stmt =
+  block:
+    test(loopCount, round(extraF), testBody)
+
+template test(loopCount: int, testBody: stmt): stmt =
+  block:
+    test(loopCount, 0, testBody)
+    echo "done extraI passed 0"
+
+when isMainModule:
+  var
+    loops = 0
+
+  test 0, 0:
+    loops += 1
+  echo "test 0 complete, loops=", loops
+
+  test 1, 1.0:
+    loops += 1
+  echo "test 1.0 complete, loops=", loops
+
+  when true:
+    # when true we get the following compile time error:
+    #   b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
+    loops = 0
+    test 2:
+      loops += 1
+    echo "test no extra complete, loops=", loops
diff --git a/tests/overload/tsymtabchange_during_or.nim b/tests/overload/tsymtabchange_during_or.nim
new file mode 100644
index 000000000..b5551bcc7
--- /dev/null
+++ b/tests/overload/tsymtabchange_during_or.nim
@@ -0,0 +1,24 @@
+
+# bug #2229
+
+type Type1 = object
+        id: int
+
+type Type2 = object
+    id: int
+
+proc init(self: var Type1, a: int, b: ref Type2) =
+    echo "1"
+
+proc init(self: var Type2, a: int) =
+    echo """
+        Works when this proc commented out
+        Otherwise error:
+        test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2)
+    """
+
+var a: Type1
+init(a, 1, (
+    var b = new(Type2);
+    b
+))
diff --git a/tests/overload/tsystemcmp.nim b/tests/overload/tsystemcmp.nim
new file mode 100644
index 000000000..68cbf9fa7
--- /dev/null
+++ b/tests/overload/tsystemcmp.nim
@@ -0,0 +1,22 @@
+discard """
+  cmd: r"nim c --hints:on $options --threads:on $file"
+"""
+
+import algorithm
+
+# bug #1657
+var modules = @["hi", "ho", "ha", "huu"]
+sort(modules, system.cmp)
+
+type
+  MyType = object
+    x: string
+
+proc cmp(a, b: MyType): int = cmp(a.x, b.x)
+
+var modulesB = @[MyType(x: "ho"), MyType(x: "ha")]
+sort(modulesB, cmp)
+
+# bug #2397
+
+proc f(x: (proc(a,b: string): int) = system.cmp) = discard
diff --git a/tests/parallel/nim.cfg b/tests/parallel/nim.cfg
new file mode 100644
index 000000000..b81c89721
--- /dev/null
+++ b/tests/parallel/nim.cfg
@@ -0,0 +1 @@
+threads:on
diff --git a/tests/parallel/t5000.nim b/tests/parallel/t5000.nim
new file mode 100644
index 000000000..1dd47a61c
--- /dev/null
+++ b/tests/parallel/t5000.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''50005000'''
+  disabled: "true"
+"""
+
+# XXX this seems to deadlock certain Linux machines
+
+import threadpool, strutils
+
+proc foo(x: int): string = $x
+
+proc main() =
+  var a = newSeq[int]()
+  for i in 1..10000:
+    add(a, i)
+
+  var s = 0
+  for i in a:
+    s += parseInt(^spawn(foo(i)))
+  echo s
+
+setMaxPoolSize 2
+
+parallel:
+  spawn main()
diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim
new file mode 100644
index 000000000..11b523401
--- /dev/null
+++ b/tests/parallel/tarray_of_channels.nim
@@ -0,0 +1,26 @@
+# bug #2257
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim
new file mode 100644
index 000000000..dffe5339b
--- /dev/null
+++ b/tests/parallel/tconvexhull.nim
@@ -0,0 +1,64 @@
+discard """
+  output: '''true
+true
+true
+true
+true
+true'''
+
+ccodeCheck: "\\i ! @'deepCopy(' .*"
+"""
+
+# parallel convex hull for Nim bigbreak
+# nim c --threads:on -d:release pconvex_hull.nim
+import algorithm, sequtils, threadpool
+
+type Point = tuple[x, y: float]
+
+proc cmpPoint(a, b: Point): int =
+  result = cmp(a.x, b.x)
+  if result == 0:
+    result = cmp(a.y, b.y)
+
+template cross[T](o, a, b: T): expr =
+  (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x)
+
+template pro(): expr =
+  while lr1 > 0 and cross(result[lr1 - 1], result[lr1], p[i]) <= 0:
+    discard result.pop
+    lr1 -= 1
+  result.add(p[i])
+  lr1 += 1
+
+proc half[T](p: seq[T]; upper: bool): seq[T] =
+  var i, lr1: int
+  result = @[]
+  lr1 = -1
+  if upper:
+    i = 0
+    while i <= high(p):
+      pro()
+      i += 1
+  else:
+    i = high(p)
+    while i >= low(p):
+      pro()
+      i -= 1
+  discard result.pop
+
+proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : seq[T] =
+  if len(points) < 2: return points
+  points.sort(cmp)
+  var ul: array[2, FlowVar[seq[T]]]
+  parallel:
+    for k in 0..ul.high:
+      ul[k] = spawn half[T](points, k == 0)
+  result = concat(^ul[0], ^ul[1])
+
+var s = map(toSeq(0..999999), proc(x: int): Point = (float(x div 1000), float(x mod 1000)))
+setMaxPoolSize 2
+
+#echo convex_hull[Point](s, cmpPoint)
+for i in 0..5:
+  echo convex_hull[Point](s, cmpPoint) ==
+      @[(0.0, 0.0), (999.0, 0.0), (999.0, 999.0), (0.0, 999.0)]
diff --git a/tests/parallel/tdeepcopy.nim b/tests/parallel/tdeepcopy.nim
new file mode 100644
index 000000000..84e2edf3f
--- /dev/null
+++ b/tests/parallel/tdeepcopy.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''13 abc'''
+"""
+
+type
+  PBinaryTree = ref object
+    le, ri: PBinaryTree
+    value: int
+
+
+proc main =
+  var x: PBinaryTree
+  deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13))))
+  var y: string
+  deepCopy y, "abc"
+  echo x.ri.le.value, " ", y
+
+main()
diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim
new file mode 100644
index 000000000..8ffdcc5f2
--- /dev/null
+++ b/tests/parallel/tdeepcopy2.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''called deepCopy for int
+called deepCopy for int
+done999 999'''
+"""
+
+import threadpool
+
+
+type
+  Bar[T] = object
+    x: T
+
+proc deepCopy[T](b: ref Bar[T]): ref Bar[T] {.override.} =
+  result.new
+  result.x = b.x
+  when T is int:
+    echo "called deepCopy for int"
+  else:
+    echo "called deepCopy for something else"
+
+proc foo(b: ref Bar[int]): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+proc main =
+  var dummy: ref Bar[int]
+  new(dummy)
+  dummy.x = 44
+  #parallel:
+  let f = spawn foo(dummy)
+  let b = spawn foo(dummy)
+  echo "done", ^f, " ", ^b
+
+main()
diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim
new file mode 100644
index 000000000..c1d0e52f8
--- /dev/null
+++ b/tests/parallel/tdisjoint_slice1.nim
@@ -0,0 +1,21 @@
+discard """
+  outputsub: "EVEN 28"
+"""
+
+import threadpool
+
+proc odd(a: int) =  echo "ODD  ", a
+proc even(a: int) = echo "EVEN ", a
+
+proc main() =
+  var a: array[0..30, int]
+  for i in low(a)..high(a): a[i] = i
+  parallel:
+    var i = 0
+    while i <= 29:
+      spawn even(a[i])
+      spawn odd(a[i+1])
+      inc i, 2
+      # is correct here
+
+main()
diff --git a/tests/parallel/tdisjoint_slice2.nim b/tests/parallel/tdisjoint_slice2.nim
new file mode 100644
index 000000000..1e86ea644
--- /dev/null
+++ b/tests/parallel/tdisjoint_slice2.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''0
+1
+2
+3
+4
+5
+6
+7
+8'''
+  sortoutput: true
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9]
+  parallel:
+    spawn f(a[0..2])
+    #spawn f(a[16..30])
+    var i = 3
+    while i <= 8:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i, 2
+      # is correct here
+
+main()
diff --git a/tests/parallel/tdont_be_stupid.nim b/tests/parallel/tdont_be_stupid.nim
new file mode 100644
index 000000000..a7e82466a
--- /dev/null
+++ b/tests/parallel/tdont_be_stupid.nim
@@ -0,0 +1,15 @@
+
+import threadpool, os
+
+proc single(time: int) =
+  sleep time
+  echo time
+
+proc sleepsort(nums: openArray[int]) =
+  parallel:
+    var i = 0
+    while i <= len(nums) + -1:
+      spawn single(nums[i])
+      i += 1
+
+sleepsort([50,3,40,25])
diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim
new file mode 100644
index 000000000..fd3aa326e
--- /dev/null
+++ b/tests/parallel/tflowvar.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''foobarfoobar
+bazbearbazbear
+
+1'''
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+import threadpool
+
+proc computeSomething(a, b: string): string = a & b & a & b & "\n"
+
+proc main =
+  let fvA = spawn computeSomething("foo", "bar")
+  let fvB = spawn computeSomething("baz", "bear")
+
+  echo(^fvA, ^fvB)
+
+main()
+sync()
+
+
+type
+  TIntSeq = seq[int]
+
+proc t(): TIntSeq =
+  result = @[1]
+
+proc p(): int =
+  var a: FlowVar[TIntSeq]
+  parallel:
+    var aa = spawn t()
+    a = aa
+  result = (^a)[0]
+
+echo p()
diff --git a/tests/parallel/tforstmt.nim b/tests/parallel/tforstmt.nim
new file mode 100644
index 000000000..58de833f3
--- /dev/null
+++ b/tests/parallel/tforstmt.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''3
+4
+5
+6
+7'''
+  sortoutput: true
+"""
+
+import threadpool, os
+
+proc p(x: int) =
+  os.sleep(100 - x*10)
+  echo x
+
+proc testFor(a, b: int; foo: var openArray[int]) =
+  parallel:
+    for i in max(a, 0) .. min(b, foo.high):
+      spawn p(foo[i])
+
+var arr = [0, 1, 2, 3, 4, 5, 6, 7]
+
+testFor(3, 10, arr)
+
+
diff --git a/tests/parallel/tgc_unsafe.nim b/tests/parallel/tgc_unsafe.nim
new file mode 100644
index 000000000..6548bbec8
--- /dev/null
+++ b/tests/parallel/tgc_unsafe.nim
@@ -0,0 +1,32 @@
+discard """
+  errormsg: "'consumer' is not GC-safe"
+  line: 19
+"""
+
+# bug #2257
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo global
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 000000000..ec4605fe9
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,39 @@
+discard """
+  line: 28
+  nimout: '''tgc_unsafe2.nim(22, 5) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory
+tgc_unsafe2.nim(26, 5) Warning: 'track' is not GC-safe as it calls 'trick'
+tgc_unsafe2.nim(28, 5) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
+"""
+
+import threadpool
+
+type StringChannel = TChannel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc trick(ix: int) =
+  echo global.x
+  echo channels[ix].recv()
+
+proc track(ix: int) = trick(ix)
+
+proc consumer(ix: int) {.thread.} =
+  track(ix)
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim
new file mode 100644
index 000000000..d96e17589
--- /dev/null
+++ b/tests/parallel/tguard1.nim
@@ -0,0 +1,37 @@
+
+when false:
+  template lock(a, b: ptr TLock; body: stmt) =
+    if cast[ByteAddress](a) < cast[ByteAddress](b):
+      pthread_mutex_lock(a)
+      pthread_mutex_lock(b)
+    else:
+      pthread_mutex_lock(b)
+      pthread_mutex_lock(a)
+    {.locks: [a, b].}:
+      try:
+        body
+      finally:
+        pthread_mutex_unlock(a)
+        pthread_mutex_unlock(b)
+
+type
+  ProtectedCounter[T] = object
+    i {.guard: L.}: T
+    L: int
+
+var
+  c: ProtectedCounter[int]
+
+c.i = 89
+
+template atomicRead(L, x): expr =
+  {.locks: [L].}:
+    x
+
+proc main =
+  {.locks: [c.L].}:
+    inc c.i
+    discard
+  echo(atomicRead(c.L, c.i))
+
+main()
diff --git a/tests/parallel/tguard2.nim b/tests/parallel/tguard2.nim
new file mode 100644
index 000000000..b69ea3371
--- /dev/null
+++ b/tests/parallel/tguard2.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "unguarded access: c.i"
+  line: 25
+"""
+
+type
+  ProtectedCounter[T] = object
+    i {.guard: L.}: T
+    L: int
+
+var
+  c: ProtectedCounter[int]
+
+c.i = 89
+
+template atomicRead(L, x): expr =
+  {.locks: [L].}:
+    x
+
+proc main =
+  {.locks: [c.L].}:
+    inc c.i
+    discard
+  echo(atomicRead(c.L, c.i))
+  echo c.i
+
+main()
diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim
new file mode 100644
index 000000000..4c6065fd6
--- /dev/null
+++ b/tests/parallel/tinvalid_array_bounds.nim
@@ -0,0 +1,25 @@
+discard """
+  errormsg: "can prove: i + 1 > 30"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tinvalid_counter_usage.nim b/tests/parallel/tinvalid_counter_usage.nim
new file mode 100644
index 000000000..c6303c651
--- /dev/null
+++ b/tests/parallel/tinvalid_counter_usage.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "invalid usage of counter after increment"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      inc i
+      spawn f(a[i])
+      inc i
+      #spawn f(a[i+1])
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim
new file mode 100644
index 000000000..463ee1a47
--- /dev/null
+++ b/tests/parallel/tlet_spawn.nim
@@ -0,0 +1,14 @@
+
+import threadpool
+
+proc foo(): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+proc main =
+  parallel:
+    let f = spawn foo()
+    let b = spawn foo()
+  echo "done", f, " ", b
+
+main()
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
new file mode 100644
index 000000000..53481e4df
--- /dev/null
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -0,0 +1,40 @@
+discard """
+  ccodeCheck: "\\i @'deepCopy(' .*"
+"""
+
+# bug #2286
+
+import threadPool
+
+type
+  Person = ref object
+    name: string
+    friend: Person
+
+var
+  people: seq[Person] = @[]
+
+proc newPerson(name:string): Person =
+  result.new()
+  result.name = name
+
+proc greet(p:Person) =
+  p.friend.name &= "-MUT" # this line crashes the program
+  echo "Person {",
+    " name:", p.name, "(", cast[int](addr p.name),"),",
+    " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }"
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson("Person" & $(i + 1))
+  for i in 0 .. <20:
+    people[i].friend = people[19-i]
+
+proc update =
+  parallel:
+    for i in 0 .. people.high:
+      spawn people[i].greet()
+
+when isMainModule:
+  setup()
+  update()
diff --git a/tests/parallel/tnon_disjoint_slice1.nim b/tests/parallel/tnon_disjoint_slice1.nim
new file mode 100644
index 000000000..72d008bbd
--- /dev/null
+++ b/tests/parallel/tnon_disjoint_slice1.nim
@@ -0,0 +1,25 @@
+discard """
+  errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)"
+  line: 20
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    #spawn f(a[0..15])
+    #spawn f(a[16..30])
+    var i = 0
+    while i <= 29:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tpi.nim b/tests/parallel/tpi.nim
new file mode 100644
index 000000000..dcb9b8fc5
--- /dev/null
+++ b/tests/parallel/tpi.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''3.141792613595791
+3.141792613595791'''
+"""
+
+import strutils, math, threadpool
+
+proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1)
+
+proc piU(n: int): float =
+  var ch = newSeq[FlowVar[float]](n+1)
+  for k in 0..n:
+    ch[k] = spawn term(float(k))
+  for k in 0..n:
+    result += ^ch[k]
+
+proc piS(n: int): float =
+  var ch = newSeq[float](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = spawn term(float(k))
+  for k in 0..ch.high:
+    result += ch[k]
+
+echo formatFloat(piU(5000))
+echo formatFloat(piS(5000))
diff --git a/tests/parallel/treadafterwrite.nim b/tests/parallel/treadafterwrite.nim
new file mode 100644
index 000000000..f59ad5ae0
--- /dev/null
+++ b/tests/parallel/treadafterwrite.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "'foo' not disjoint from 'foo'"
+  line: 23
+  disabled: "true"
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat = 
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      let foo = (spawn term(float(k)))
+      assert foo != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
new file mode 100644
index 000000000..9874d3299
--- /dev/null
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -0,0 +1,41 @@
+# bug #2287
+
+import threadPool
+
+# If `nums` is an array instead of seq,
+# NONE of the iteration ways below work (including high / len-1)
+let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+proc log(n:int) =
+  echo n
+
+proc main =
+  parallel:
+    for n in nums: # Error: cannot prove: i <= len(nums) + -1
+      spawn log(n)
+    #for i in 0 .. <nums.len: # Error: cannot prove: i <= len(nums) + -1
+    #for i in 0 .. nums.len-1: # WORKS!
+    #for i in 0 .. <nums.len: # WORKS!
+    #  spawn log(nums[i])
+
+# Array needs explicit size to work, probably related to issue #2287
+#const a: array[0..5, int] = [1,2,3,4,5,6]
+
+#const a = [1,2,3,4,5,6] # Doesn't work
+const a = @[1,2,3,4,5,6] # Doesn't work
+proc f(n: int) = echo "Hello ", n
+
+proc maino =
+  parallel:
+    # while loop doesn't work:
+    var i = 0
+    while i < a.high:
+      #for i in countup(0, a.high-1, 2):
+      spawn f(a[i])
+      spawn f(a[i+1])
+      i += 2
+
+maino() # Doesn't work outside a proc
+
+when isMainModule:
+  main()
diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim
new file mode 100644
index 000000000..7244a5ee6
--- /dev/null
+++ b/tests/parallel/tsysspawn.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''4
+8'''
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+import threadpool
+
+var
+  x, y = 0
+
+proc p1 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc x
+
+proc p2 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc y, 2
+
+for i in 0.. 3:
+  spawn(p1())
+  spawn(p2())
+
+sync()
+
+echo x
+echo y
diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim
new file mode 100644
index 000000000..2d3ffd241
--- /dev/null
+++ b/tests/parallel/tsysspawnbadarg.nim
@@ -0,0 +1,9 @@
+discard """
+  line: 9
+  errormsg: "'spawn' takes a call expression"
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+import threadpool
+
+let foo = spawn(1)
diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim
new file mode 100644
index 000000000..95123e886
--- /dev/null
+++ b/tests/parallel/tuseafterdef.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "(k)..(k) not disjoint from (k)..(k)"
+  line: 23
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type 
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat = 
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = (spawn term(float(k)))
+      assert ch[k] != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim
new file mode 100644
index 000000000..db32a96d8
--- /dev/null
+++ b/tests/parallel/twrong_refcounts.nim
@@ -0,0 +1,53 @@
+discard """
+  output: "Success"
+"""
+
+import math, threadPool
+
+# ---
+
+type
+  Person = object
+    age: int
+    friend: ref Person
+
+var
+  people: seq[ref Person] = @[]
+
+proc newPerson(age:int): ref Person =
+  result.new()
+  result.age = age
+
+proc greet(p:Person) =
+  #echo p.age, ", ", p.friend.age
+  p.friend.age += 1
+
+# ---
+
+proc setup =
+  for i in 0 .. <20:
+    people.add newPerson(i + 1)
+  for i in 0 .. <20:
+    people[i].friend = people[random(20)]
+
+proc update =
+  var countA: array[20, int]
+  var countB: array[20, int]
+
+  for i, p in people:
+    countA[i] = getRefCount(p)
+  parallel:
+    for i in 0 .. people.high:
+      spawn greet(people[i][])
+  for i, p in people:
+    countB[i] = getRefCount(p)
+
+  for i in 0 .. <20:
+    doAssert countA[i] == countB[i]
+  echo "Success"
+
+# ---
+
+when isMainModule:
+  setup()
+  update()
diff --git a/tests/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
new file mode 100644
index 000000000..730e9cbb7
--- /dev/null
+++ b/tests/parser/tcommand_as_expr.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''140
+5-120-120
+359
+77'''
+"""
+#import math
+
+proc optarg(x:int, y:int = 0):int = x + 3 * y
+proc singlearg(x:int):int = 20*x
+echo optarg 1, singlearg 2
+
+
+proc foo(x: int): int = x-1
+proc foo(x, y: int): int = x-y
+
+let x = optarg foo 7.foo
+let y = singlearg foo(1, foo 8)
+let z = singlearg 1.foo foo 8
+
+echo x, y, z
+
+let a = [2,4,8].map do (d:int) -> int: d + 1
+echo a[0], a[1], a[2]
+
+echo(foo 8, foo 8)
diff --git a/tests/parser/tdomulttest.nim b/tests/parser/tdomulttest.nim
new file mode 100644
index 000000000..4ee6de128
--- /dev/null
+++ b/tests/parser/tdomulttest.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tdomulttest.nim"
+  output: "555\ntest\nmulti lines\n99999999\nend"
+  disabled: true
+"""
+proc foo(bar, baz: proc (x: int): int) =
+  echo bar(555)
+  echo baz(99999999)
+
+foo do (x: int) -> int:
+  return x
+do (x: int) -> int:
+  echo("test")
+  echo("multi lines")
+  return x
+
+echo("end")
\ No newline at end of file
diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim
new file mode 100644
index 000000000..cacde48bd
--- /dev/null
+++ b/tests/parser/tinvcolonlocation1.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinvcolonlocation1.nim"
+  line: 8
+  column: 3
+  errormsg: "':' expected"
+"""
+try #<- missing ':'
+  echo "try"
+except:
+  echo "except"
+finally:
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim
new file mode 100644
index 000000000..2b6a92b9d
--- /dev/null
+++ b/tests/parser/tinvcolonlocation2.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tinvcolonlocation2.nim"
+  line: 11
+  column: 1
+  errormsg: "':' expected"
+"""
+try:
+  echo "try"
+except #<- missing ':'
+  echo "except"
+finally:
+#<-- error will be here above, at the beginning of finally,
+#    since compiler tries to consome echo and part of except
+#    expression
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim
new file mode 100644
index 000000000..2b30b1dbe
--- /dev/null
+++ b/tests/parser/tinvcolonlocation3.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tinvcolonlocation3.nim"
+  line: 12
+  column: 3
+  errormsg: "':' expected"
+"""
+try:
+  echo "try"
+except:
+  echo "except"
+finally #<- missing ':'
+  echo "finally"
diff --git a/tests/parser/tinvwhen.nim b/tests/parser/tinvwhen.nim
new file mode 100644
index 000000000..5ff94cc6c
--- /dev/null
+++ b/tests/parser/tinvwhen.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tinvwhen.nim"
+  line: 11
+  errormsg: "invalid indentation"
+"""
+# This was parsed even though it should not!

+

+proc chdir(path: cstring): cint {.importc: "chdir", header: "dirHeader".}

+

+proc getcwd(buf: cstring, buflen: cint): cstring

+    when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation

+    elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}

+    else: {.error: "os library not ported to your OS. Please help!".}

+
+
diff --git a/tests/parser/toprprec.nim b/tests/parser/toprprec.nim
new file mode 100644
index 000000000..ce33934b5
--- /dev/null
+++ b/tests/parser/toprprec.nim
@@ -0,0 +1,39 @@
+discard """
+  file: "toprprec.nim"
+  output: "done"
+"""
+# Test operator precedence: 
+
+template `@` (x: expr): expr {.immediate.} = self.x
+template `@!` (x: expr): expr {.immediate.} = x
+template `===` (x: expr): expr {.immediate.} = x
+
+type
+  TO = object
+    x: int
+  TA = tuple[a, b: int, obj: TO]
+  
+proc init(self: var TA): string =
+  @a = 3
+  === @b = 4
+  @obj.x = 4
+  @! === result = "abc"
+  result = @b.`$`
+
+assert 3+5*5-2 == 28- -26-28
+
+proc `^-` (x, y: int): int =  
+  # now right-associative!
+  result = x - y
+  
+assert 34 ^- 6 ^- 2 == 30
+assert 34 - 6 - 2 == 26
+
+
+var s: TA
+assert init(s) == "4"
+
+echo "done"
+
+
+
diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim
new file mode 100644
index 000000000..d2c6d0b30
--- /dev/null
+++ b/tests/parser/tprecedence.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''holla
+true'''
+"""
+
+# Test top level semicolon works properly:
+import os; echo "holla"
+
+# Test the new predence rules
+
+proc `\+` (x, y: int): int = result = x + y
+proc `\*` (x, y: int): int = result = x * y
+
+echo 5 \+ 1 \* 9 == 6*9
+
diff --git a/tests/parser/tproctype_pragmas.nim b/tests/parser/tproctype_pragmas.nim
new file mode 100644
index 000000000..8c7acd0cf
--- /dev/null
+++ b/tests/parser/tproctype_pragmas.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''39
+40'''
+"""
+
+# bug 1802
+# Ensure proc pragmas are attached properly:
+
+proc makeStdcall(s: string): (proc(i: int) {.stdcall.}) =
+  (proc (x: int) {.stdcall.} = echo x)
+
+proc makeNimcall(s: string): (proc(i: int)) {.stdcall.} =
+  (proc (x: int) {.nimcall.} = echo x)
+
+let stdc: proc (y: int) {.stdcall.} = makeStdcall("bu")
+let nimc: proc (y: int) {.closure.} = makeNimcall("ba")
+
+stdc(39)
+nimc(40)
diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim
new file mode 100644
index 000000000..e70b91988
--- /dev/null
+++ b/tests/parser/tstrongspaces.nim
@@ -0,0 +1,83 @@
+#! strongSpaces
+
+discard """
+  output: '''35
+true
+true
+4
+true
+1
+false
+77
+(Field0: 1, Field1: 2, Field2: 2)
+ha
+true
+tester args
+all
+all args
+19
+-3
+false
+-2
+'''
+"""
+
+echo 2+5 * 5
+
+# Keyword operators
+echo 1 + 16 shl 1 == 1 + (16 shl 1)
+echo 2 and 1  in  {0, 30}
+echo 2+2 * 2 shr 1
+echo false  or  2 and 1  in  {0, 30}
+
+proc `^`(a, b: int): int = a + b div 2
+echo 19 mod 16 ^ 4  +  2 and 1
+echo 18 mod 16 ^ 4 > 0
+
+# echo $foo gotcha
+let foo = 77
+echo $foo
+
+echo (1, 2, 2)
+
+template `&`(a, b: int): expr = a and b
+template `|`(a, b: int): expr = a - b
+template `++`(a, b: int): expr = a + b == 8009
+
+when true:
+  let b = 66
+  let c = 90
+  let bar = 8000
+  if foo+4 * 4 == 8  and  b&c | 9  ++
+      bar:
+    echo "ho"
+  else:
+    echo "ha"
+
+  let booA = foo+4 * 4  -  b&c | 9  +
+      bar
+  # is parsed as
+  let booB = ((foo+4)*4) - ((b&c) | 9) + bar
+
+  echo booA == booB
+
+
+template `|`(a, b): expr = (if a.len > 0: a else: b)
+
+const
+  tester = "tester"
+  args = "args"
+
+echo tester & " " & args|"all"
+echo "all"  |  tester & " " & args
+echo "all"|tester & " " & args
+
+# Test arrow like operators. See also tests/macros/tclosuremacro.nim
+proc `+->`(a, b: int): int = a + b*4
+template `===>`(a, b: int): expr = a - b shr 1
+
+echo 3 +-> 2 + 2 and 4
+var arrowed = 3+->2 + 2 and 4  # arrowed = 4
+echo arrowed ===> 15
+echo (2 * 3+->2) == (2*3 +-> 2)
+echo arrowed ===> 2 + 3+->2
diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim
new file mode 100644
index 000000000..aaa06f9f4
--- /dev/null
+++ b/tests/parser/ttupleunpack.nim
@@ -0,0 +1,35 @@
+discard """
+  file: "ttupleunpack.nim"
+  output: ""
+  exitcode: 0
+"""
+
+proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+proc main2 =
+  let (x, _, z) = returnsTuple()
+
+proc main() =
+
+  proc foo(): tuple[x, y, z: int] =
+    return (4, 2, 3)
+
+  var (x, _, y) = foo()
+  doAssert x == 4
+  doAssert y == 3
+
+  var (a, _, _) = foo()
+  doAssert a == 4
+
+  var (aa, _, _) = foo()
+  doAssert aa == 4
+
+  iterator bar(): tuple[x, y, z: int] =
+    yield (1,2,3)
+
+  for x, y, _ in bar():
+    doAssert x == 1
+    doAssert y == 2
+
+main()
+main2()
diff --git a/tests/parser/ttypeof.nim b/tests/parser/ttypeof.nim
new file mode 100644
index 000000000..24f98059e
--- /dev/null
+++ b/tests/parser/ttypeof.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''12
+int
+int
+int'''
+"""
+
+import typetraits
+
+# bug #1805
+
+proc foob(x: int): string = "foo"
+proc barb(x: string): int = 12
+
+echo(foob(10).barb()) # works
+echo(type(10).name()) # doesn't work
+
+echo(name(type(10))) # works
+echo((type(10)).name()) # works
+
+
+# test that 'addr' still works
+proc poo(x, y: ptr int) = discard
+
+var someInt: int
+poo(addr someInt, addr someInt)
diff --git a/tests/parser/twhen_in_enum.nim b/tests/parser/twhen_in_enum.nim
new file mode 100644
index 000000000..d4a3ea56a
--- /dev/null
+++ b/tests/parser/twhen_in_enum.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "identifier expected, but found 'keyword when'"
+"""
+
+# bug #2123
+type num = enum
+    NUM_NONE = 0
+    NUM_ALL = 1
+    when defined(macosx): NUM_OSX = 10 # only this differs for real
+    NUM_XTRA = 20
+
diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim
new file mode 100644
index 000000000..5fb411a79
--- /dev/null
+++ b/tests/pragmas/tpush.nim
@@ -0,0 +1,15 @@
+# test the new pragmas

+

+{.push warnings: off, hints: off.}

+proc noWarning() =

+  var

+    x: int

+  echo(x)

+

+{.pop.}

+

+proc WarnMe() =

+  var

+    x: int

+  echo(x)

+

diff --git a/tests/pragmas/tuserpragma.nim b/tests/pragmas/tuserpragma.nim
new file mode 100644
index 000000000..784baa176
--- /dev/null
+++ b/tests/pragmas/tuserpragma.nim
@@ -0,0 +1,7 @@
+
+{.pragma: rtl, cdecl, exportc.}
+
+proc myproc(x, y: int): int {.rtl} =
+  nil
+
+
diff --git a/tests/proc/tnestprc.nim b/tests/proc/tnestprc.nim
new file mode 100644
index 000000000..c10ad6abf
--- /dev/null
+++ b/tests/proc/tnestprc.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tnestprc.nim"
+  output: "10"
+"""
+# Test nested procs without closures
+
+proc Add3(x: int): int = 
+  proc add(x, y: int): int {.noconv.} = 
+    result = x + y
+    
+  result = add(x, 3)
+  
+echo Add3(7) #OUT 10
+
+
+
diff --git a/tests/proc/tprocredef.nim b/tests/proc/tprocredef.nim
new file mode 100644
index 000000000..86ed92b62
--- /dev/null
+++ b/tests/proc/tprocredef.nim
@@ -0,0 +1,9 @@
+discard """
+  file: "tprocredef.nim"
+  line: 8
+  errormsg: "redefinition of \'foo\'"
+"""
+
+proc foo(a: int, b: string) = nil
+proc foo(a: int, b: string) = nil
+
diff --git a/tests/procvar/tgenericprocvar.nim b/tests/procvar/tgenericprocvar.nim
new file mode 100644
index 000000000..e642e3577
--- /dev/null
+++ b/tests/procvar/tgenericprocvar.nim
@@ -0,0 +1,5 @@
+proc foo[T](thing: T) =
+    discard thing
+
+var a: proc (thing: int) {.nimcall.} = foo[int]
+
diff --git a/tests/procvar/tprocvar.nim b/tests/procvar/tprocvar.nim
new file mode 100644
index 000000000..56f76c613
--- /dev/null
+++ b/tests/procvar/tprocvar.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "type mismatch"
+  line: 17
+  file: "tprocvar.nim"
+"""
+
+type
+  TCallback = proc (a, b: int)
+
+proc huh(x, y: var int) =
+  x = 0
+  y = x+1
+
+proc so(c: TCallback) =
+  c(2, 4)
+  
+so(huh)
+
diff --git a/tests/procvar/tprocvar2.nim b/tests/procvar/tprocvar2.nim
new file mode 100644
index 000000000..237e2ef7a
--- /dev/null
+++ b/tests/procvar/tprocvar2.nim
@@ -0,0 +1,32 @@
+discard """
+  file: "tprocvar.nim"
+  output: "papbpcpdpe7"
+"""
+# test variables of type proc

+
+proc pa() {.cdecl.} = write(stdout, "pa")
+proc pb() {.cdecl.} = write(stdout, "pb")
+proc pc() {.cdecl.} = write(stdout, "pc")
+proc pd() {.cdecl.} = write(stdout, "pd")
+proc pe() {.cdecl.} = write(stdout, "pe")
+
+const
+  algos = [pa, pb, pc, pd, pe]
+

+var

+  x: proc (a, b: int): int {.cdecl.}

+

+proc ha(c, d: int): int {.cdecl.} =

+  echo(c + d)

+  result = c + d

+
+for a in items(algos):
+  a()
+

+x = ha

+discard x(3, 4)

+

+#OUT papbpcpdpe7

+

+
+
diff --git a/tests/procvar/tprocvars.nim b/tests/procvar/tprocvars.nim
new file mode 100644
index 000000000..50d5d29f2
--- /dev/null
+++ b/tests/procvar/tprocvars.nim
@@ -0,0 +1,6 @@
+proc doSomething(v: int, x: proc(v:int):int): int = return x(v)
+proc doSomething(v: int, x: proc(v:int)) = x(v)
+
+
+echo doSomething(10, proc(v: int): int = return v div 2)
+
diff --git a/tests/range/compilehelpers.nim b/tests/range/compilehelpers.nim
new file mode 100644
index 000000000..cb26ca5b5
--- /dev/null
+++ b/tests/range/compilehelpers.nim
@@ -0,0 +1,6 @@
+template accept(e: expr) =
+  static: assert(compiles(e))
+
+template reject(e: expr) =
+  static: assert(not compiles(e))
+
diff --git a/tests/range/tbug499771.nim b/tests/range/tbug499771.nim
new file mode 100644
index 000000000..682148422
--- /dev/null
+++ b/tests/range/tbug499771.nim
@@ -0,0 +1,14 @@
+discard """
+  file: "tbug499771.nim"
+  output: '''TSubRange: 5 from 1 to 10
+true true true'''
+"""
+type 
+  TSubRange = range[1 .. 10]
+  TEnum = enum A, B, C
+var sr: TSubRange = 5
+echo("TSubRange: " & $sr & " from " & $low(TSubRange) & " to " & 
+     $high(TSubRange))
+
+const cset = {A} + {B}
+echo A in cset, " ", B in cset, " ", C notin cset
diff --git a/tests/range/tcolors.nim b/tests/range/tcolors.nim
new file mode 100644
index 000000000..9d1034405
--- /dev/null
+++ b/tests/range/tcolors.nim
@@ -0,0 +1,39 @@
+import strutils
+
+type
+  TColor = distinct int32
+
+proc rgb(r, g, b: range[0..255]): TColor = 
+  result = TColor(r or g shl 8 or b shl 16)
+
+proc `$`(c: TColor): string =
+  result = "#" & toHex(int32(c), 6)
+
+echo rgb(34, 55, 255)
+
+when false:
+  type
+    TColor = distinct int32
+    TColorComponent = distinct int8
+  
+  proc red(a: TColor): TColorComponent = 
+    result = TColorComponent(int32(a) and 0xff'i32)
+  
+  proc green(a: TColor): TColorComponent = 
+    result = TColorComponent(int32(a) shr 8'i32 and 0xff'i32)
+  
+  proc blue(a: TColor): TColorComponent = 
+    result = TColorComponent(int32(a) shr 16'i32 and 0xff'i32)
+  
+  proc rgb(r, g, b: range[0..255]): TColor = 
+    result = TColor(r or g shl 8 or b shl 8)
+  
+  proc `+!` (a, b: TColorComponent): TColorComponent =  
+    ## saturated arithmetic:
+    result = TColorComponent(min(ze(int8(a)) + ze(int8(b)), 255))
+  
+  proc `+` (a, b: TColor): TColor = 
+    ## saturated arithmetic for colors makes sense, I think:
+    return rgb(red(a) +! red(b), green(a) +! green(b), blue(a) +! blue(b))
+  
+  rgb(34, 55, 255)
diff --git a/tests/range/tmatrix3.nim b/tests/range/tmatrix3.nim
new file mode 100644
index 000000000..80d38d63d
--- /dev/null
+++ b/tests/range/tmatrix3.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''0.0
+0.0
+0
+0
+0
+'''
+"""
+
+include compilehelpers
+
+type
+  Matrix*[M, N, T] = object 
+    aij*: array[M, array[N, T]]
+  
+  Matrix2*[T] = Matrix[range[0..1], range[0..1], T]
+  
+  Matrix3*[T] = Matrix[range[0..2], range[0..2], T]
+
+proc mn(x: Matrix): Matrix.T = x.aij[0][0]
+
+proc m2(x: Matrix2): Matrix2.T = x.aij[0][0]
+
+proc m3(x: Matrix3): auto = x.aij[0][0]
+
+var 
+  matn: Matrix[range[0..3], range[0..2], int]
+  mat2: Matrix2[int]
+  mat3: Matrix3[float]
+
+echo m3(mat3)
+echo mn(mat3)
+echo m2(mat2)
+echo mn(mat2)
+echo mn(matn)
+
+reject m3(mat2)
+reject m3(matn)
+reject m2(mat3)
+reject m2(matn)
+
diff --git a/tests/range/tsubrange.nim b/tests/range/tsubrange.nim
new file mode 100644
index 000000000..b4a333bf3
--- /dev/null
+++ b/tests/range/tsubrange.nim
@@ -0,0 +1,21 @@
+discard """
+  line: 20
+  errormsg: "cannot convert 60 to TRange"
+"""
+
+type
+  TRange = range[0..40]
+  
+proc p(r: TRange) =
+  nil
+  
+var
+  r: TRange
+  y = 50
+r = y
+
+p y
+
+const
+  myConst: TRange = 60
+  
diff --git a/tests/range/tsubrange2.nim b/tests/range/tsubrange2.nim
new file mode 100644
index 000000000..759d16b9c
--- /dev/null
+++ b/tests/range/tsubrange2.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tsubrange2.nim"
+  outputsub: "value out of range: 50 [RangeError]"
+  exitcode: "1"
+"""
+
+type
+  TRange = range[0..40]
+  
+proc p(r: TRange) =
+  discard
+  
+var
+  r: TRange
+  y = 50
+p y
+  
diff --git a/tests/range/tsubrange3.nim b/tests/range/tsubrange3.nim
new file mode 100644
index 000000000..600161cfd
--- /dev/null
+++ b/tests/range/tsubrange3.nim
@@ -0,0 +1,18 @@
+discard """
+  file: "tsubrange.nim"
+  outputsub: "value out of range: 50 [RangeError]"
+  exitcode: "1"
+"""
+
+type
+  TRange = range[0..40]
+  
+proc p(r: TRange) =
+  discard
+  
+var
+  r: TRange
+  y = 50
+r = y
+
+#p y
diff --git a/tests/readme.txt b/tests/readme.txt
new file mode 100644
index 000000000..2cfc79f9a
--- /dev/null
+++ b/tests/readme.txt
@@ -0,0 +1,13 @@
+This directory contains the test cases.

+Each test must have a filename of the form: ``t*.nim``

+

+Each test can contain a spec in a ``discard """"""`` block.

+

+The folder ``rodfiles`` contains special tests that test incremental

+compilation via symbol files.

+

+The folder ``dll`` contains simple DLL tests.

+

+The folder ``realtimeGC`` contains a test for validating that the realtime GC

+can run properly without linking against the nimrtl.dll/so. It includes a C

+client and platform specific build files for manual compilation.

diff --git a/tests/realtimeGC/cmain.c b/tests/realtimeGC/cmain.c
new file mode 100644
index 000000000..e9a46d7ce
--- /dev/null
+++ b/tests/realtimeGC/cmain.c
@@ -0,0 +1,67 @@
+
+#ifdef WIN
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#define RUNTIME (15*60)
+
+
+typedef void (*pFunc)(void);
+
+int main(int argc, char* argv[])
+{
+    int i;
+    void* hndl;
+    pFunc status;
+    pFunc count;
+    pFunc checkOccupiedMem;
+
+#ifdef WIN
+    hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll");
+    status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status");
+    count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count");
+    checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem");
+#else /* OSX || NIX */
+    hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY);
+    status = (pFunc) dlsym(hndl, (char const*)"status");
+    count = (pFunc) dlsym(hndl, (char const*)"count");
+    checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem");
+#endif
+
+    assert(hndl);
+    assert(status);
+    assert(count);
+    assert(checkOccupiedMem);
+
+    time_t startTime = time((time_t*)0);
+    time_t runTime = (time_t)(RUNTIME);
+    time_t accumTime = 0;
+    while (accumTime < runTime) {
+        for (i = 0; i < 10; i++)
+            count();
+        /* printf("1. sleeping...\n"); */
+        sleep(1);
+        for (i = 0; i < 10; i++)
+            status();
+        /* printf("2. sleeping...\n"); */
+        sleep(1);
+        checkOccupiedMem();
+        accumTime = time((time_t*)0) - startTime;
+        /* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */
+    }
+    printf("Cleaning up the shared object pointer...\n");
+#ifdef WIN
+    FreeLibrary((HMODULE)hndl);
+#else /* OSX || NIX */
+    dlclose(hndl);
+#endif
+    printf("Done\n");
+    return 0;
+}
diff --git a/tests/realtimeGC/main.nim.cfg b/tests/realtimeGC/main.nim.cfg
new file mode 100644
index 000000000..fed4fa471
--- /dev/null
+++ b/tests/realtimeGC/main.nim.cfg
@@ -0,0 +1,6 @@
+
+--app:console
+--threads:on
+
+-d:release
+-d:useRealtimeGC
diff --git a/tests/realtimeGC/nmain.nim b/tests/realtimeGC/nmain.nim
new file mode 100644
index 000000000..c9f558dbc
--- /dev/null
+++ b/tests/realtimeGC/nmain.nim
@@ -0,0 +1,46 @@
+discard """
+  cmd: "nim $target --debuginfo $options $file"
+  output: "Done"
+"""
+
+import times, os, threadpool
+
+const RUNTIME = 15 * 60 # 15 minutes
+
+when defined(windows):
+  const dllname = "./tests/realtimeGC/shared.dll"
+elif defined(macosx):
+  const dllname = "./tests/realtimeGC/libshared.dylib"
+else:
+  const dllname = "./tests/realtimeGC/libshared.so"
+
+proc status() {.importc: "status", dynlib: dllname.}
+proc count() {.importc: "count", dynlib: dllname.}
+proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.}
+
+proc process() =
+  let startTime = getTime()
+  let runTime = cast[Time](RUNTIME) #
+  var accumTime: Time
+  while accumTime < runTime:
+    for i in 0..10:
+      count()
+    # echo("1. sleeping... ")
+    sleep(500)
+    for i in 0..10:
+      status()
+    # echo("2. sleeping... ")
+    sleep(500)
+    checkOccupiedMem()
+    accumTime = cast[Time]((getTime() - startTime))
+    # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60))
+
+proc main() =
+  process()
+  # parallel:
+  #   for i in 0..0:
+  #     spawn process()
+  # sync()
+  echo("Done")
+
+main()
diff --git a/tests/realtimeGC/readme.txt b/tests/realtimeGC/readme.txt
new file mode 100644
index 000000000..035a00001
--- /dev/null
+++ b/tests/realtimeGC/readme.txt
@@ -0,0 +1,21 @@
+Test the realtime GC without linking nimrtl.dll/so.

+

+Note, this is a long running test, default is 35 minutes. To change the

+the run time see RUNTIME in main.nim and main.c.

+

+You can build shared.nim, main.nim, and main.c by running make (nix systems)

+or maike.bat (Windows systems). They both assume GCC and that it's in your

+path. Output: shared.(dll/so), camin(.exe), nmain(.exe).

+

+To run the test: execute either nmain or cmain in a shell window.

+

+To build buy hand:

+

+  - build the shared object (shared.nim):

+

+    $ nim c shared.nim

+

+  - build the client executables:

+

+    $ nim c -o:nmain main.nim

+    $ gcc -o cmain main.c -ldl

diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim
new file mode 100644
index 000000000..2d1dd6c3c
--- /dev/null
+++ b/tests/realtimeGC/shared.nim
@@ -0,0 +1,63 @@
+discard """
+  cmd: "nim $target --debuginfo --hints:on --app:lib $options $file"
+"""
+
+import strutils
+
+# Global state, accessing with threads, no locks. Don't do this at
+# home.
+var gCounter: uint64
+var gTxStatus: bool
+var gRxStatus: bool
+var gConnectStatus: bool
+var gPttStatus: bool
+var gComm1Status: bool
+var gComm2Status: bool
+
+proc getTxStatus(): string =
+  result = if gTxStatus: "On" else: "Off"
+  gTxStatus = not gTxStatus
+
+proc getRxStatus(): string =
+  result = if gRxStatus: "On" else: "Off"
+  gRxStatus = not gRxStatus
+
+proc getConnectStatus(): string =
+  result = if gConnectStatus: "Yes" else: "No"
+  gConnectStatus = not gConnectStatus
+
+proc getPttStatus(): string =
+  result = if gPttStatus: "PTT: On" else: "PTT: Off"
+  gPttStatus = not gPttStatus
+
+proc getComm1Status(): string =
+  result = if gComm1Status: "On" else: "Off"
+  gComm1Status = not gComm1Status
+
+proc getComm2Status(): string =
+  result = if gComm2Status: "On" else: "Off"
+  gComm2Status = not gComm2Status
+
+proc status() {.exportc: "status", dynlib.} =
+  var tx_status = getTxStatus()
+  var rx_status = getRxStatus()
+  var connected = getConnectStatus()
+  var ptt_status = getPttStatus()
+  var str1: string = "[PilotEdge] Connected: $1  TX: $2  RX: $3" % [connected, tx_status, rx_status]
+  var a = getComm1Status()
+  var b = getComm2Status()
+  var str2: string = "$1  COM1: $2  COM2: $3" % [ptt_status, a, b]
+  # echo(str1)
+  # echo(str2)
+
+proc count() {.exportc: "count", dynlib.} =
+  var temp: uint64
+  for i in 0..100_000:
+    temp += 1
+  gCounter += 1
+  # echo("gCounter: ", gCounter)
+
+proc checkOccupiedMem() {.exportc: "checkOccupiedMem", dynlib.} =
+  if getOccupiedMem() > 10_000_000:
+    quit 1
+  discard
diff --git a/tests/realtimeGC/shared.nim.cfg b/tests/realtimeGC/shared.nim.cfg
new file mode 100644
index 000000000..e153b26fa
--- /dev/null
+++ b/tests/realtimeGC/shared.nim.cfg
@@ -0,0 +1,5 @@
+--app:lib
+--threads:on
+
+-d:release
+-d:useRealtimeGC
diff --git a/tests/rectest.nim b/tests/rectest.nim
new file mode 100644
index 000000000..f08306cfd
--- /dev/null
+++ b/tests/rectest.nim
@@ -0,0 +1,6 @@
+# Test the error message

+

+proc main() =

+  main()

+

+main()

diff --git a/tests/rodfiles/aconv.nim b/tests/rodfiles/aconv.nim
new file mode 100644
index 000000000..ffd8f3648
--- /dev/null
+++ b/tests/rodfiles/aconv.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "ugly conversion successful"
+"""
+
+import int2bool
+
+if 4:
+  echo "ugly conversion successful"
+
diff --git a/tests/rodfiles/amethods.nim b/tests/rodfiles/amethods.nim
new file mode 100644
index 000000000..c51d27d24
--- /dev/null
+++ b/tests/rodfiles/amethods.nim
@@ -0,0 +1,13 @@
+
+type
+  TBaseClass* = object of TObject
+
+proc newBaseClass*: ref TBaseClass =
+  new result
+  
+method echoType*(x: ref TBaseClass) =
+  echo "base class"
+
+proc echoAlias*(x: ref TBaseClass) =
+  echoType x
+
diff --git a/tests/rodfiles/bconv.nim b/tests/rodfiles/bconv.nim
new file mode 100644
index 000000000..2289a7f97
--- /dev/null
+++ b/tests/rodfiles/bconv.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "ugly conversion successful 2"
+"""
+
+import int2bool
+
+if 4:
+  echo "ugly conversion successful 2"
+
diff --git a/tests/rodfiles/bmethods.nim b/tests/rodfiles/bmethods.nim
new file mode 100644
index 000000000..995942ad6
--- /dev/null
+++ b/tests/rodfiles/bmethods.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''derived class
+base class
+'''
+"""
+
+import amethods
+
+
+type
+  TDerivedClass* = object of TBaseClass
+
+proc newDerivedClass: ref TDerivedClass =
+  new result
+  
+method echoType*(x: ref TDerivedClass) =
+  echo "derived class"
+
+var b, d: ref TBaseClass
+
+b = newBaseClass()
+d = newDerivedClass()
+
+#b.echoType()
+#d.echoType()
+
+echoAlias d
+echoAlias b
+
diff --git a/tests/rodfiles/bmethods2.nim b/tests/rodfiles/bmethods2.nim
new file mode 100644
index 000000000..ac24a2201
--- /dev/null
+++ b/tests/rodfiles/bmethods2.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''derived class 2
+base class
+'''
+"""
+
+import amethods
+
+
+type
+  TDerivedClass* = object of TBaseClass
+
+proc newDerivedClass: ref TDerivedClass =
+  new result
+  
+method echoType*(x: ref TDerivedClass) =
+  echo "derived class 2"
+
+var b, d: ref TBaseClass
+
+b = newBaseClass()
+d = newDerivedClass()
+
+#b.echoType()
+#d.echoType()
+
+echoAlias d
+echoAlias b
+
diff --git a/tests/rodfiles/deada.nim b/tests/rodfiles/deada.nim
new file mode 100644
index 000000000..3fa4192f8
--- /dev/null
+++ b/tests/rodfiles/deada.nim
@@ -0,0 +1,8 @@
+discard """
+  output: '''246
+'''
+"""
+
+import deadg, deadb
+
+
diff --git a/tests/rodfiles/deada2.nim b/tests/rodfiles/deada2.nim
new file mode 100644
index 000000000..2925b4d43
--- /dev/null
+++ b/tests/rodfiles/deada2.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''246
+xyzabc
+'''
+"""
+
+import deadg, deadb
+
+# now add call to previously unused proc p2:
+echo p2("xyz", "abc")
+
+
diff --git a/tests/rodfiles/deadb.nim b/tests/rodfiles/deadb.nim
new file mode 100644
index 000000000..776a07ac7
--- /dev/null
+++ b/tests/rodfiles/deadb.nim
@@ -0,0 +1,7 @@
+
+import deadg
+
+
+echo p1(123, 123)
+
+
diff --git a/tests/rodfiles/deadg.nim b/tests/rodfiles/deadg.nim
new file mode 100644
index 000000000..97bfbed4f
--- /dev/null
+++ b/tests/rodfiles/deadg.nim
@@ -0,0 +1,10 @@
+
+{.deadCodeElim: on.}
+
+proc p1*(x, y: int): int =
+  result = x + y
+  
+proc p2*(x, y: string): string =
+  result = x & y
+  
+
diff --git a/tests/rodfiles/gtkex1.nim b/tests/rodfiles/gtkex1.nim
new file mode 100644
index 000000000..8f4db4a40
--- /dev/null
+++ b/tests/rodfiles/gtkex1.nim
@@ -0,0 +1,14 @@
+import 

+  cairo, glib2, gtk2

+

+proc destroy(widget: pWidget, data: pgpointer) {.cdecl.} =

+  main_quit()

+

+var

+  window: pWidget

+nimrod_init()

+window = window_new(WINDOW_TOPLEVEL)

+discard signal_connect(window, "destroy",

+                       SIGNAL_FUNC(gtkex1.destroy), nil)

+show(window)

+main()

diff --git a/tests/rodfiles/gtkex2.nim b/tests/rodfiles/gtkex2.nim
new file mode 100644
index 000000000..3d181ba12
--- /dev/null
+++ b/tests/rodfiles/gtkex2.nim
@@ -0,0 +1,22 @@
+
+import 
+  glib2, gtk2
+
+proc destroy(widget: pWidget, data: pgpointer){.cdecl.} = 
+  main_quit()
+
+var 
+  window: PWidget
+  button: PWidget
+
+nimrod_init()
+window = window_new(WINDOW_TOPLEVEL)
+button = button_new("Click me")
+set_border_width(PContainer(Window), 5)
+add(PContainer(window), button)
+discard signal_connect(window, "destroy", 
+                           SIGNAL_FUNC(gtkex2.destroy), nil)
+show(button)
+show(window)
+main()
+
diff --git a/tests/rodfiles/hallo.nim b/tests/rodfiles/hallo.nim
new file mode 100644
index 000000000..ac45be9fa
--- /dev/null
+++ b/tests/rodfiles/hallo.nim
@@ -0,0 +1,6 @@
+discard """
+  output: "Hello World"
+"""
+
+echo "Hello World"
+
diff --git a/tests/rodfiles/hallo2.nim b/tests/rodfiles/hallo2.nim
new file mode 100644
index 000000000..a4b3957ec
--- /dev/null
+++ b/tests/rodfiles/hallo2.nim
@@ -0,0 +1,17 @@
+discard """
+  output: "Hello World"
+"""
+
+# Test incremental type information
+
+type
+  TNode = object {.pure.}
+    le, ri: ref TNode
+    data: string
+
+proc newNode(data: string): ref TNode =
+  new(result)
+  result.data = data
+  
+echo newNode("Hello World").data
+
diff --git a/tests/rodfiles/int2bool.nim b/tests/rodfiles/int2bool.nim
new file mode 100644
index 000000000..0f6fd14e6
--- /dev/null
+++ b/tests/rodfiles/int2bool.nim
@@ -0,0 +1,8 @@
+
+{.overflowchecks: on.}
+
+converter uglyToBool*(x: int): bool =
+  {.Breakpoint.}
+  result = x != 0
+
+
diff --git a/tests/rodfiles/nim.cfg b/tests/rodfiles/nim.cfg
new file mode 100644
index 000000000..78fc8db64
--- /dev/null
+++ b/tests/rodfiles/nim.cfg
@@ -0,0 +1,2 @@
+--nimcache:"$projectPath/nimcache"
+--symbolFiles:on
diff --git a/tests/rodfiles/tgeneric1.nim b/tests/rodfiles/tgeneric1.nim
new file mode 100644
index 000000000..a3f7b870b
--- /dev/null
+++ b/tests/rodfiles/tgeneric1.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "abcd"
+"""
+
+import tables
+
+var x = initTable[int, string]()
+
+x[2] = "ab"
+x[5] = "cd"
+
+echo x[2], x[5]
+
diff --git a/tests/rodfiles/tgeneric2.nim b/tests/rodfiles/tgeneric2.nim
new file mode 100644
index 000000000..552d60267
--- /dev/null
+++ b/tests/rodfiles/tgeneric2.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "abef"
+"""
+
+import tables
+
+var x = initTable[int, string]()
+
+x[2] = "ab"
+x[5] = "ef"
+
+echo x[2], x[5]
+
diff --git a/tests/seq/tseq2.nim b/tests/seq/tseq2.nim
new file mode 100644
index 000000000..e1271964c
--- /dev/null
+++ b/tests/seq/tseq2.nim
@@ -0,0 +1,11 @@
+proc `*` *(a, b: seq[int]): seq[int] = 
+  # allocate a new sequence:
+  newSeq(result, len(a))
+  # multiply two int sequences:
+  for i in 0..len(a)-1: result[i] = a[i] * b[i]
+
+when isMainModule: 
+  # test the new ``*`` operator for sequences:
+  assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
+
+
diff --git a/tests/seq/tseqcon.nim b/tests/seq/tseqcon.nim
new file mode 100644
index 000000000..6e0a5b56d
--- /dev/null
+++ b/tests/seq/tseqcon.nim
@@ -0,0 +1,51 @@
+discard """
+  file: "tseqcon.nim"
+  output: "Hithere, what\'s your name?Hathere, what\'s your name?"
+"""
+# Test the add proc for sequences and strings

+

+const

+  nestedFixed = true

+

+type

+  TRec {.final.} = object

+    x, y: int

+    s: string

+    seq: seq[string]

+  TRecSeq = seq[TRec]

+

+proc test() =

+  var s, b: seq[string]

+  s = @[]

+  add(s, "Hi")

+  add(s, "there, ")

+  add(s, "what's your name?")

+

+  b = s # deep copying here!

+  b[0][1] = 'a'

+

+  for i in 0 .. len(s)-1:

+    write(stdout, s[i])

+  for i in 0 .. len(b)-1:

+    write(stdout, b[i])

+

+

+when nestedFixed:

+  proc nested() =

+    var

+      s: seq[seq[string]]

+    for i in 0..10_000: # test if the garbage collector

+      # now works with sequences

+      s = @[

+        @["A", "B", "C", "D"],

+        @["E", "F", "G", "H"],

+        @["I", "J", "K", "L"],

+        @["M", "N", "O", "P"]]

+

+test()

+when nestedFixed:

+  nested()

+

+#OUT Hithere, what's your name?Hathere, what's your name?

+
+
diff --git a/tests/seq/tseqcon2.nim b/tests/seq/tseqcon2.nim
new file mode 100644
index 000000000..4f2763ffe
--- /dev/null
+++ b/tests/seq/tseqcon2.nim
@@ -0,0 +1,9 @@
+import os
+
+proc rec_dir(dir: string): seq[string] =
+  result = @[]
+  for kind, path in walk_dir(dir):
+    if kind == pcDir:
+      add(result, rec_dir(path))
+    else:
+      add(result, path)
diff --git a/tests/seq/tseqtuple.nim b/tests/seq/tseqtuple.nim
new file mode 100644
index 000000000..7ef92f7f1
--- /dev/null
+++ b/tests/seq/tseqtuple.nim
@@ -0,0 +1,28 @@
+discard """
+  file: "tseqtuple.nim"
+  output: "fA13msg1falsefB14msg2truefC15msg3false"
+"""
+
+type
+  TMsg = tuple[
+    file: string,
+    line: int,       
+    msg: string,
+    err: bool]
+
+var s: seq[TMsg] = @[]
+
+s.add(("fA", 13, "msg1", false))
+s.add(("fB", 14, "msg2", true))
+s.add(("fC", 15, "msg3", false))
+
+for file, line, msg, err in items(s):
+  stdout.write(file)
+  stdout.write($line)
+  stdout.write(msg)
+  stdout.write($err)
+
+#OUT fA13msg1falsefB14msg2truefC15msg3false
+
+
+
diff --git a/tests/seq/tsequtils.nim b/tests/seq/tsequtils.nim
new file mode 100644
index 000000000..ea85a7f21
--- /dev/null
+++ b/tests/seq/tsequtils.nim
@@ -0,0 +1,55 @@
+discard """
+file: "tsequtils.nim"
+output: '''Zip: [{"Field0": 1, "Field1": 2}, {"Field0": 3, "Field1": 4}, {"Field0": 5, "Field1": 6}]
+Filter Iterator: 3
+Filter Iterator: 5
+Filter Iterator: 7
+Filter: [3, 5, 7]
+FilterIt: [1, 3, 7]
+Concat: [1, 3, 5, 7, 2, 4, 6]
+Deduplicate: [1, 2, 3, 4, 5, 7]'''
+
+"""
+
+import sequtils, marshal
+
+proc testFindWhere(item : int) : bool =
+  if item != 1: return true
+
+var seq1: seq[int] = @[]
+
+seq1.add(1)
+seq1.add(3)
+seq1.add(5)
+seq1.add(7)
+
+var seq2: seq[int] = @[2, 4, 6]
+var final = zip(seq1, seq2)
+
+echo "Zip: ", $$(final)
+
+#Test findWhere as a iterator
+
+for itms in filter(seq1, testFindWhere):
+  echo "Filter Iterator: ", $$(itms)
+
+
+#Test findWhere as a proc
+
+var fullseq: seq[int] = filter(seq1, testFindWhere)
+
+echo "Filter: ", $$(fullseq)
+
+#Test findIt as a template
+
+var finditval: seq[int] = filterIt(seq1, it!=5)
+
+echo "FilterIt: ", $$(finditval)
+
+var concatseq = concat(seq1,seq2)
+echo "Concat: ", $$(concatseq)
+
+var seq3 = @[1,2,3,4,5,5,5,7]
+var dedupseq = deduplicate(seq3)
+echo "Deduplicate: ", $$(dedupseq)
+
diff --git a/tests/seq/ttoseq.nim b/tests/seq/ttoseq.nim
new file mode 100644
index 000000000..34cc4824b
--- /dev/null
+++ b/tests/seq/ttoseq.nim
@@ -0,0 +1,18 @@
+discard """
+  output: "2345623456"
+"""
+
+import sequtils
+
+for x in toSeq(countup(2, 6)): 
+  stdout.write(x)
+for x in items(toSeq(countup(2, 6))): 
+  stdout.write(x)
+
+import strutils
+
+var y: type("a b c".split)
+y = "xzy"
+
+
+
diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim
new file mode 100644
index 000000000..646175329
--- /dev/null
+++ b/tests/sets/tsets.nim
@@ -0,0 +1,204 @@
+discard """

+  file: "tsets.nim"

+  output: '''Ha ein F ist in s!

+false'''

+"""

+# Test the handling of sets

+

+import

+  strutils

+

+proc testSets(s: var set[char]) =

+  s = {'A', 'B', 'C', 'E'..'G'} + {'Z'} + s

+

+# test sets if the first element is different from 0:

+type

+  TAZ = range['a'..'z']

+  TAZset = set[TAZ]

+

+  TTokType* = enum

+    tkInvalid, tkEof,

+    tkSymbol,

+    tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst,

+    tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum,

+    tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies,

+    tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro,

+    tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc,

+    tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry,

+    tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield,

+    tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit,

+    tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit,

+    tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe,

+    tkCurlyRi, tkBracketDotLe, tkBracketDotRi,

+    tkCurlyDotLe, tkCurlyDotRi,

+    tkParDotLe, tkParDotRi,

+    tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr,

+    tkComment, tkAccent, tkInd, tkSad, tkDed,

+    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr

+  TTokTypeRange = range[tkSymbol..tkDed]

+  TTokTypes* = set[TTokTypeRange]

+

+const

+  toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit),

+                         tkStrLit..tkTripleStrLit}

+

+var

+  s: set[char]

+  a: TAZset

+s = {'0'..'9'}

+testSets(s)

+if 'F' in s: write(stdout, "Ha ein F ist in s!\n")

+else: write(stdout, "BUG: F ist nicht in s!\n")

+a = {} #{'a'..'z'}

+for x in low(TAZ) .. high(TAZ):

+  incl(a, x)

+  if x in a: discard

+  else: write(stdout, "BUG: something not in a!\n")

+

+for x in low(TTokTypeRange) .. high(TTokTypeRange):

+  if x in tokTypes:

+    discard

+    #writeln(stdout, "the token '$1' is in the set" % repr(x))

+

+#OUT Ha ein F ist in s!

+

+

+type

+  TMsgKind* = enum

+    errUnknown, errIllFormedAstX, errInternal, errCannotOpenFile, errGenerated,

+    errXCompilerDoesNotSupportCpp, errStringLiteralExpected,

+    errIntLiteralExpected, errInvalidCharacterConstant,

+    errClosingTripleQuoteExpected, errClosingQuoteExpected,

+    errTabulatorsAreNotAllowed, errInvalidToken, errLineTooLong,

+    errInvalidNumber, errNumberOutOfRange, errNnotAllowedInCharacter,

+    errClosingBracketExpected, errMissingFinalQuote, errIdentifierExpected,

+    errNewlineExpected,

+    errInvalidModuleName,

+    errOperatorExpected, errTokenExpected, errStringAfterIncludeExpected,

+    errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,

+    errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,

+    errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,

+    errExceptionExpected, errExceptionAlreadyHandled,

+    errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,

+    errInvalidNumberOfYieldExpr, errCannotReturnExpr, errAttemptToRedefine,

+    errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,

+    errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,

+    errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,

+    errOnOrOffExpectedButXFound, errNoneBoehmRefcExpectedButXFound,

+    errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,

+    errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,

+    errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,

+    errExprExpected, errUndeclaredIdentifier, errUseQualifier, errTypeExpected,

+    errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,

+    errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,

+    errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,

+    errConstantDivisionByZero, errOrdinalTypeExpected,

+    errOrdinalOrFloatTypeExpected, errOverOrUnderflow,

+    errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,

+    errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,

+    errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,

+    errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,

+    errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,

+    errCastNotInSafeMode, errExprCannotBeCastedToX, errCommaOrParRiExpected,

+    errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,

+    errMagicOnlyInSystem, errPowerOfTwoExpected,

+    errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,

+    errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,

+    errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,

+    errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,

+    errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,

+    errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,

+    errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,

+    errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,

+    errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,

+    errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,

+    errVarForOutParamNeeded,

+    errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,

+    errAmbiguousCallXYZ, errWrongNumberOfArguments,

+    errXCannotBePassedToProcVar,

+    errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed,

+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,

+    errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,

+    errInvalidOrderInArrayConstructor,

+    errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,

+    errOptionExpected, errXisNoLabel, errNotAllCasesCovered,

+    errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,

+    errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,

+    errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,

+    errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,

+    errXNotAllowedHere, errInvalidControlFlowX,

+    errXisNoType, errCircumNeedsPointer, errInvalidExpression,

+    errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,

+    errNamedExprNotAllowed, errXExpectsOneTypeParam,

+    errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,

+    errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,

+    errNoReturnTypeDeclared,

+    errInvalidCommandX, errXOnlyAtModuleScope,

+    errXNeedsParamObjectType,

+    errTemplateInstantiationTooNested, errInstantiationFrom,

+    errInvalidIndexValueForTuple, errCommandExpectsFilename,

+    errMainModuleMustBeSpecified,

+    errXExpected,

+    errTIsNotAConcreteType,

+    errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,

+    errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,

+    errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,

+    errOnlyACallOpCanBeDelegator, errUsingNoSymbol,

+    errMacroBodyDependsOnGenericTypes,

+    errDestructorNotGenericEnough,

+    errInlineIteratorsAsProcParams,

+    errXExpectsTwoArguments,

+    errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,

+    errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,

+    errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,

+    errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,

+    errXhasSideEffects, errIteratorExpected, errLetNeedsInit,

+    errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,

+    errXCannotBeClosure, errXMustBeCompileTime,

+    errCannotInferTypeOfTheLiteral,

+    errCannotInferReturnType,

+    errGenericLambdaNotAllowed,

+    errCompilerDoesntSupportTarget,

+    errUser,

+    warnCannotOpenFile,

+    warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,

+    warnDeprecated, warnConfigDeprecated,

+    warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,

+    warnUnknownSubstitutionX, warnLanguageXNotSupported,

+    warnFieldXNotSupported, warnCommentXIgnored,

+    warnNilStatement, warnTypelessParam,

+    warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,

+    warnEachIdentIsTuple, warnShadowIdent,

+    warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,

+    warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,

+    warnUser,

+    hintSuccess, hintSuccessX,

+    hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,

+    hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,

+    hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,

+    hintConditionAlwaysTrue, hintName, hintPattern,

+    hintUser

+

+const

+  fatalMin* = errUnknown

+  fatalMax* = errInternal

+  errMin* = errUnknown

+  errMax* = errUser

+  warnMin* = warnCannotOpenFile

+  warnMax* = pred(hintSuccess)

+  hintMin* = hintSuccess

+  hintMax* = high(TMsgKind)

+

+type

+  TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints

+  TNoteKinds* = set[TNoteKind]

+

+var

+  gNotes*: TNoteKinds = {low(TNoteKind)..high(TNoteKind)} -

+                        {warnShadowIdent, warnUninit,

+                         warnProveField, warnProveIndex, warnGcUnsafe}

+

+

+#import compiler.msgs

+

+echo warnUninit in gNotes

diff --git a/tests/sets/tsets2.nim b/tests/sets/tsets2.nim
new file mode 100644
index 000000000..7f313e14f
--- /dev/null
+++ b/tests/sets/tsets2.nim
@@ -0,0 +1,61 @@
+discard """
+  output: '''true'''
+"""
+
+import hashes, sets
+
+const
+  data = [
+    "34", "12",
+    "90", "0",
+    "1", "2",
+    "3", "4",
+    "5", "6",
+    "7", "8",
+    "9", "---00",
+    "10", "11", "19",
+    "20", "30", "40",
+    "50", "60", "70",
+    "80"]
+
+block tableTest1:
+  var t = initSet[tuple[x, y: int]]()
+  t.incl((0,0))
+  t.incl((1,0))
+  assert(not t.containsOrIncl((0,1)))
+  t.incl((1,1))
+
+  for x in 0..1:
+    for y in 0..1:
+      assert((x,y) in t)
+  #assert($t == 
+  #  "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}")
+
+block setTest2:
+  var t = initSet[string]()
+  t.incl("test")
+  t.incl("111")
+  t.incl("123")
+  t.excl("111")
+  
+  t.incl("012")
+  t.incl("123") # test duplicates
+  
+  assert "123" in t
+  assert "111" notin t # deleted
+  
+  for key in items(data): t.incl(key)
+  for key in items(data): assert key in t
+  
+
+block orderedSetTest1:
+  var t = data.toOrderedSet
+  for key in items(data): assert key in t
+  var i = 0
+  # `items` needs to yield in insertion order:
+  for key in items(t):
+    assert key == data[i]
+    inc(i)
+
+echo "true"
+
diff --git a/tests/sets/tsets3.nim b/tests/sets/tsets3.nim
new file mode 100644
index 000000000..f599f8e7d
--- /dev/null
+++ b/tests/sets/tsets3.nim
@@ -0,0 +1,100 @@
+include sets
+
+let
+  s1: TSet[int] = toSet([1, 2, 4, 8, 16])
+  s2: TSet[int] = toSet([1, 2, 3, 5, 8])
+  s3: TSet[int] = toSet([3, 5, 7])
+
+block union:
+  let
+    s1_s2 = union(s1, s2)
+    s1_s3 = s1 + s3
+    s2_s3 = s2 + s3
+
+  assert s1_s2.len == 7
+  assert s1_s3.len == 8
+  assert s2_s3.len == 6
+
+  for i in s1:
+    assert i in s1_s2
+    assert i in s1_s3
+  for i in s2:
+    assert i in s1_s2
+    assert i in s2_s3
+  for i in s3:
+    assert i in s1_s3
+    assert i in s2_s3
+
+  assert((s1 + s1) == s1)
+  assert((s2 + s1) == s1_s2)
+
+block intersection:
+  let
+    s1_s2 = intersection(s1, s2)
+    s1_s3 = intersection(s1, s3)
+    s2_s3 = s2 * s3
+
+  assert s1_s2.len == 3
+  assert s1_s3.len == 0
+  assert s2_s3.len == 2
+
+  for i in s1_s2:
+    assert i in s1
+    assert i in s2
+  for i in s1_s3:
+    assert i in s1
+    assert i in s3
+  for i in s2_s3:
+    assert i in s2
+    assert i in s3
+
+  assert((s2 * s2) == s2)
+  assert((s3 * s2) == s2_s3)
+
+block symmetricDifference:
+  let
+    s1_s2 = symmetricDifference(s1, s2)
+    s1_s3 = s1 -+- s3
+    s2_s3 = s2 -+- s3
+
+  assert s1_s2.len == 4
+  assert s1_s3.len == 8
+  assert s2_s3.len == 4
+
+  for i in s1:
+    assert i in s1_s2 xor i in s2
+    assert i in s1_s3 xor i in s3
+  for i in s2:
+    assert i in s1_s2 xor i in s1
+    assert i in s2_s3 xor i in s3
+  for i in s3:
+    assert i in s1_s3 xor i in s1
+    assert i in s2_s3 xor i in s2
+
+  assert((s3 -+- s3) == initSet[int]())
+  assert((s3 -+- s1) == s1_s3)
+
+block difference:
+  let
+    s1_s2 = difference(s1, s2)
+    s1_s3 = difference(s1, s3)
+    s2_s3 = s2 - s3
+
+  assert s1_s2.len == 2
+  assert s1_s3.len == 5
+  assert s2_s3.len == 3
+
+  for i in s1:
+    assert i in s1_s2 xor i in s2
+    assert i in s1_s3 xor i in s3
+  for i in s2:
+    assert i in s2_s3 xor i in s3
+
+  assert((s2 - s2) == initSet[int]())
+  assert((s1 - s3 - s1) == s1 -+- s3)
+
+block disjoint:
+  assert(not disjoint(s1, s2))
+  assert disjoint(s1, s3)
+  assert(not disjoint(s2, s3))
+  assert(not disjoint(s2, s2))
diff --git a/tests/sets/tsets_lt.nim b/tests/sets/tsets_lt.nim
new file mode 100644
index 000000000..6d0b3a60c
--- /dev/null
+++ b/tests/sets/tsets_lt.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''true
+true
+true'''
+"""
+
+var s, s1: set[char]
+s = {'a'..'d'}
+s1 = {'a'..'c'}
+echo s1 < s
+echo s1 * s == {'a'..'c'}
+echo s1 <= s
diff --git a/tests/showoff/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim
new file mode 100644
index 000000000..78f711325
--- /dev/null
+++ b/tests/showoff/tdrdobbs_examples.nim
@@ -0,0 +1,134 @@
+discard """
+  output: '''108
+11 -1 1936
+0.4
+true
+truefalse'''
+"""
+
+proc `++`(x: var int; y: int = 1; z: int = 0) =
+  x = x + y + z
+
+var g = 70
+++g
+g ++ 7
+g.`++`(10, 20)
+echo g
+
+
+#let lv = stdin.readline
+#var vv = stdin.readline
+#vv = "abc" # valid, reassignment allowed
+#lv = "abc" # fails at compile time
+
+#proc square(x: int): int = x*x
+
+template square(x: int): int =
+  # ensure 'x' is only evaluated once:
+  let y = x
+  y * y
+
+proc mostSignificantBit(n: int): int =
+  # naive algorithm:
+  var n = n
+  while n != 0:
+    n = n shr 1
+    result += 1
+  result -= 1
+
+const msb3999 = mostSignificantBit(3999)
+
+echo msb3999, " ", mostSignificantBit(0), " ", square(44)
+
+proc filter[T](a: openarray[T], predicate: proc (x: T): bool): seq[T] =
+  result = @[] # @[] constructs the empty seq
+  for x in a:
+    if predicate(x): result.add(x)
+
+proc map[T, S](a: openarray[T], fn: proc (x: T): S): seq[S] =
+  newSeq(result, a.len)
+  for i in 0 .. <a.len: result[i] = fn(a[i])
+
+
+type
+  FormulaKind = enum
+    fkVar,        ## element is a variable like 'X'
+    fkLit,        ## element is a literal like 0.1
+    fkAdd,        ## element is an addition operation
+    fkMul,        ## element is a multiplication operation
+    fkExp         ## element is an exponentiation operation
+
+type
+  Formula = ref object
+    case kind: FormulaKind
+    of fkVar: name: string
+    of fkLit: value: float
+    of fkAdd, fkMul, fkExp: left, right: Formula
+
+from math import pow
+
+proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
+  case n.kind
+  of fkVar: varToVal(n.name)
+  of fkLit: n.value
+  of fkAdd: evaluate(n.left, varToVal) + evaluate(n.right, varToVal)
+  of fkMul: evaluate(n.left, varToVal) * evaluate(n.right, varToVal)
+  of fkExp: pow(evaluate(n.left, varToVal), evaluate(n.right, varToVal))
+
+echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
+
+proc isPolyTerm(n: Formula): bool =
+  n.kind == fkMul and n.left.kind == fkLit and (let e = n.right;
+    e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
+
+proc isPolynomial(n: Formula): bool =
+  isPolyTerm(n) or
+    (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
+
+let myFormula = Formula(kind: fkMul,
+                        left: Formula(kind: fkLit, value: 2.0),
+                        right: Formula(kind: fkExp,
+                          left: Formula(kind: fkVar, name: "x"),
+                          right: Formula(kind: fkLit, value: 5.0)))
+
+echo isPolyTerm(myFormula)
+
+proc pat2kind(pattern: string): FormulaKind =
+  case pattern
+  of "^": fkExp
+  of "*": fkMul
+  of "+": fkAdd
+  of "x": fkVar
+  of "c": fkLit
+  else:   fkVar # no error reporting for reasons of simplicity
+
+import macros
+
+proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} =
+  template `@`(current, field: expr): expr =
+    newDotExpr(current, newIdentNode(astToStr(field)))
+
+  template `==@`(n, pattern: expr): expr =
+    newCall("==", n@kind, newIdentNode($pat2kind($pattern.ident)))
+
+  case pattern.kind
+  of CallNodes:
+    result = newCall("and",
+      n ==@ pattern[0],
+      matchAgainst(n@left, pattern[1]))
+    if pattern.len == 3:
+      result = newCall("and", result.copy,
+        matchAgainst(n@right, pattern[2]))
+  of nnkIdent:
+    result = n ==@ pattern
+  of nnkPar:
+    result = matchAgainst(n, pattern[0])
+  else:
+    error "invalid pattern"
+
+macro `=~` (n: Formula, pattern: expr): bool =
+  result = matchAgainst(n, pattern)
+
+proc isPolyTerm2(n: Formula): bool = n =~ c * x^c
+
+echo isPolyTerm2(myFormula), isPolyTerm2(Formula(kind: fkLit, value: 0.7))
diff --git a/tests/showoff/tformatopt.nim b/tests/showoff/tformatopt.nim
new file mode 100644
index 000000000..f33ed6921
--- /dev/null
+++ b/tests/showoff/tformatopt.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''(a: 3
+b: 4
+s: abc
+)'''
+"""
+
+import macros
+
+proc invalidFormatString() =
+  echo "invalidFormatString"
+
+template formatImpl(handleChar: expr) =
+  var i = 0
+  while i < f.len:
+    if f[i] == '$':
+      case f[i+1]
+      of '1'..'9':
+        var j = 0
+        i += 1
+        while f[i] in {'0'..'9'}:
+          j = j * 10 + ord(f[i]) - ord('0')
+          i += 1
+        result.add(a[j-1])
+      else:
+        invalidFormatString()
+    else:
+      result.add(handleChar(f[i]))
+      i += 1
+
+proc `%`*(f: string, a: openArray[string]): string =
+  template identity(x: expr): expr = x
+  result = ""
+  formatImpl(identity)
+
+macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): expr =
+  result = newNimNode(nnkBracket)
+  let f = f.strVal
+  formatImpl(newLit)
+  result = nestList(!"&", result)
+
+template optAdd1{x = y; add(x, z)}(x, y, z: string) =
+  x = y & z
+
+proc `/&` [T: object](x: T): string =
+  result = "("
+  for name, value in fieldPairs(x):
+    result.add("$1: $2\n" % [name, $value])
+  result.add(")")
+
+type
+  MyObject = object
+    a, b: int
+    s: string
+
+let obj = MyObject(a: 3, b: 4, s: "abc")
+echo(/&obj)
diff --git a/tests/showoff/thello2.nim b/tests/showoff/thello2.nim
new file mode 100644
index 000000000..d2e2f6227
--- /dev/null
+++ b/tests/showoff/thello2.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''(a: 3, b: 4, s: abc)'''
+"""
+
+type
+  MyObject = object
+        a, b: int
+        s: string
+
+let obj = MyObject(a: 3, b: 4, s: "abc")
+echo obj
diff --git a/tests/showoff/thtml1.nim b/tests/showoff/thtml1.nim
new file mode 100644
index 000000000..cd95c7971
--- /dev/null
+++ b/tests/showoff/thtml1.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "<br>"
+"""
+
+template htmlTag(tag: expr) {.immediate.} =
+  proc tag(): string = "<" & astToStr(tag) & ">"
+  
+htmlTag(br)
+htmlTag(html)
+
+echo br()
diff --git a/tests/showoff/thtml2.nim b/tests/showoff/thtml2.nim
new file mode 100644
index 000000000..faeb4e50d
--- /dev/null
+++ b/tests/showoff/thtml2.nim
@@ -0,0 +1,37 @@
+discard """
+  output: "<html><head><title>now look at this</title></head><body><ul><li>Nim is quite capable</li></ul></body></html>"
+"""
+
+import strutils
+
+template html(name: expr, matter: stmt) {.immediate.} =
+  proc name(): string =
+    result = "<html>"
+    matter
+    result.add("</html>")
+
+template nestedTag(tag: expr) {.immediate.} =
+  template tag(matter: stmt) {.immediate.} =
+    result.add("<" & astToStr(tag) & ">")
+    matter
+    result.add("</" & astToStr(tag) & ">")
+
+template simpleTag(tag: expr) {.immediate.} =
+  template tag(matter: expr) {.immediate.} =
+    result.add("<$1>$2</$1>" % [astToStr(tag), matter])
+
+nestedTag body
+nestedTag head
+nestedTag ul
+simpleTag title
+simpleTag li
+
+
+html mainPage:
+  head:
+    title "now look at this"
+  body:
+    ul:
+      li "Nim is quite capable"
+
+echo mainPage()
diff --git a/tests/showoff/tonce.nim b/tests/showoff/tonce.nim
new file mode 100644
index 000000000..6fc372e87
--- /dev/null
+++ b/tests/showoff/tonce.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''first call of p
+some call of p
+new instantiation
+some call of p'''
+"""
+
+template once(body: stmt) =
+  var x {.global.} = false
+  if not x:
+    x = true
+    body
+
+proc p() =
+  once:
+    echo "first call of p"
+  echo "some call of p"
+
+p()
+once:
+  echo "new instantiation"
+p()
diff --git a/tests/showoff/tquasiquote.nim b/tests/showoff/tquasiquote.nim
new file mode 100644
index 000000000..df7fccc33
--- /dev/null
+++ b/tests/showoff/tquasiquote.nim
@@ -0,0 +1,14 @@
+discard """
+  outputsub: '''tquasiquote.nim(14,8): Check failed: 1 > 2'''
+"""
+
+import macros
+
+macro check(ex: expr): stmt =
+  var info = ex.lineInfo
+  var expString = ex.toStrLit
+  result = quote do:
+    if not `ex`:
+      echo `info`, ": Check failed: ", `expString`
+
+check 1 > 2
diff --git a/tests/specialops/tdotops.nim b/tests/specialops/tdotops.nim
new file mode 100644
index 000000000..ce5b3942d
--- /dev/null
+++ b/tests/specialops/tdotops.nim
@@ -0,0 +1,66 @@
+discard """
+  output: '''
+10
+assigning z = 20
+reading field y
+20
+call to y
+dot call
+no params call to a
+100
+no params call to b
+100
+one param call to c with 10
+100'''
+"""
+
+type
+  T1 = object
+    x*: int
+
+  TD = distinct T1
+
+  T2 = object
+    x: int
+
+proc `.`*(v: T1, f: string): int =
+  echo "reading field ", f
+  return v.x
+
+proc `.=`(x: var T1, f: string{lit}, v: int) =
+  echo "assigning ", f, " = ", v
+  x.x = v
+
+template `.()`(x: T1, f: string, args: varargs[expr]): string =
+  echo "call to ", f
+  "dot call"
+
+echo ""
+
+var t = T1(x: 10)
+
+echo t.x
+t.z = 20
+echo t.y
+echo t.y()
+
+var d = TD(t)
+assert(not compiles(d.y))
+
+proc `.`(v: T2, f: string): int =
+  echo "no params call to ", f
+  return v.x
+
+proc `.`*(v: T2, f: string, a: int): int =
+  echo "one param call to ", f, " with ", a
+  return v.x
+
+var tt = T2(x: 100)
+
+echo tt.a
+echo tt.b()
+echo tt.c(10)
+
+assert(not compiles(tt.d("x")))
+assert(not compiles(tt.d(1, 2)))
+
diff --git a/tests/stckovfl.nim b/tests/stckovfl.nim
new file mode 100644
index 000000000..eeb499bed
--- /dev/null
+++ b/tests/stckovfl.nim
@@ -0,0 +1,10 @@
+# To test stack overflow message
+
+proc over(a: int): int = 
+  if a >= 10:
+    assert false
+    return
+  result = over(a+1)+5
+  
+Echo($over(0))
+
diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim
new file mode 100644
index 000000000..3ca425fbc
--- /dev/null
+++ b/tests/stdlib/talgorithm.nim
@@ -0,0 +1,11 @@
+import algorithm
+
+doAssert product[int](newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
+doAssert product[int](@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
+doAssert product(@[@[1,2]]) == @[@[1,2]], "a simple case of one element"
+doAssert product(@[@[1,2], @[3,4]]) == @[@[2,4],@[1,4],@[2,3],@[1,3]], "two elements"
+doAssert product(@[@[1,2], @[3,4], @[5,6]]) == @[@[2,4,6],@[1,4,6],@[2,3,6],@[1,3,6], @[2,4,5],@[1,4,5],@[2,3,5],@[1,3,5]], "three elements"
+doAssert product(@[@[1,2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
+doAssert lowerBound([1,2,4], 3, system.cmp[int]) == 2
+doAssert lowerBound([1,2,2,3], 4, system.cmp[int]) == 4
+doAssert lowerBound([1,2,3,10], 11) == 4
\ No newline at end of file
diff --git a/tests/stdlib/tcount.nim b/tests/stdlib/tcount.nim
new file mode 100644
index 000000000..ce1d14b6c
--- /dev/null
+++ b/tests/stdlib/tcount.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+done'''
+"""
+
+# bug #1845, #2224
+
+var arr = [3,2,1,5,4]
+
+# bubble sort
+for i in low(arr)..high(arr):
+  for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeError]
+    if arr[i] > arr[j]:
+      let tmp = arr[i]
+      arr[i] = arr[j]
+      arr[j] = tmp
+
+for i in low(arr)..high(arr):
+  echo arr[i]
+
+# check this terminates:
+for x in countdown('\255', '\0'):
+  discard
+
+echo "done"
diff --git a/tests/stdlib/tcputime.nim b/tests/stdlib/tcputime.nim
new file mode 100644
index 000000000..2fc46ee64
--- /dev/null
+++ b/tests/stdlib/tcputime.nim
@@ -0,0 +1,13 @@
+
+import times, os
+
+var e = epochTime()
+var c = cpuTime()
+
+os.sleep(1500)
+
+e = epochTime() - e
+c = cpuTime() - c
+
+echo "epochTime: ", e, " cpuTime: ", c
+
diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim
new file mode 100644
index 000000000..fb447b80b
--- /dev/null
+++ b/tests/stdlib/tcritbits.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''abc
+def
+definition
+prefix
+xyz
+def
+definition'''
+"""
+
+import critbits
+
+when isMainModule:
+  var r: TCritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+  doAssert r.contains"def"
+  #r.del "def"
+
+  for w in r.items:
+    echo w
+    
+  for w in r.itemsWithPrefix("de"):
+    echo w
+
diff --git a/tests/stdlib/techo.nim b/tests/stdlib/techo.nim
new file mode 100644
index 000000000..9cef9205f
--- /dev/null
+++ b/tests/stdlib/techo.nim
@@ -0,0 +1,3 @@
+# Simplest Nim program
+
+echo "Hello, World!"
diff --git a/tests/stdlib/testequivalence.nim b/tests/stdlib/testequivalence.nim
new file mode 100644
index 000000000..7acaad340
--- /dev/null
+++ b/tests/stdlib/testequivalence.nim
@@ -0,0 +1,14 @@
+discard """
+  output: ''''''
+"""
+import sets
+
+doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset")
+doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3]), "equivalent or subset")
+doAssert((not(toSet(@[1,2,3]) <= toSet(@[1,2]))), "equivalent or subset")
+doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "strict subset")
+doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2,3]))), "strict subset")
+doAssert((not(toSet(@[1,2,3]) < toSet(@[1,2]))), "strict subset")
+doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2,3,4]))), "==")
+doAssert(toSet(@[1,2,3]) == toSet(@[1,2,3]), "==")
+doAssert((not(toSet(@[1,2,3]) == toSet(@[1,2]))), "==")
diff --git a/tests/stdlib/tformat.nim b/tests/stdlib/tformat.nim
new file mode 100644
index 000000000..92c0c16f5
--- /dev/null
+++ b/tests/stdlib/tformat.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "tformat.nim"
+  output: "Hi Andreas! How do you feel, Rumpf?"
+"""
+# Tests the new format proc (including the & and &= operators)

+

+import strutils

+

+echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])

+#OUT Hi Andreas! How do you feel, Rumpf?

+
+
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
new file mode 100644
index 000000000..8a0538a5f
--- /dev/null
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -0,0 +1,96 @@
+discard """
+  output: ""
+"""
+
+import os, strutils
+# Cases
+#  1 - String : Existing File : Symlink true
+#  2 - String : Existing File : Symlink false
+#  3 - String : Non-existing File : Symlink true
+#  4 - String : Non-existing File : Symlink false
+#  5 - Handle : Valid File
+#  6 - Handle : Invalid File
+#  7 - Handle : Valid Handle
+#  8 - Handle : Invalid Handle
+
+proc genBadFileName(limit = 100): string =
+    ## Generates a filename of a nonexistant file.
+    ## Returns "" if generation fails.
+    result = "a"
+    var hitLimit = true
+
+    for i in 0..100:
+      if existsFile(result):
+        result.add("a")
+      else:
+        hitLimit = false
+        break
+    if hitLimit:
+      result = ""
+
+proc caseOneAndTwo(followLink: bool) =
+  try:
+    discard getFileInfo(getAppFilename(), followLink)
+    #echo("String : Existing File : Symlink $# : Success" % $followLink)
+  except OSError:
+    echo("String : Existing File : Symlink $# : Failure" % $followLink)
+
+proc caseThreeAndFour(followLink: bool) =
+  var invalidName = genBadFileName()
+  try:
+    discard getFileInfo(invalidName, true)
+    echo("String : Non-existing File : Symlink $# : Failure" % $followLink)
+  except OSError:
+    discard
+    #echo("String : Non-existing File : Symlink $# : Success" % $followLink)
+
+proc testGetFileInfo =
+  # Case 1
+  caseOneAndTwo(true)
+
+  # Case 2
+  caseOneAndTwo(false)
+
+  # Case 3
+  caseThreeAndFour(true)
+
+  # Case 4
+  caseThreeAndFour(false)
+
+  # Case 5 and 7
+  block:
+    let
+      testFile = open(getAppFilename())
+      testHandle = fileHandle(testFile)
+    try:
+      discard getFileInfo(testFile)
+      #echo("Handle : Valid File : Success")
+    except IOError:
+      echo("Handle : Valid File : Failure")
+
+    try:
+      discard getFileInfo(testHandle)
+      #echo("Handle : Valid File : Success")
+    except IOError:
+      echo("Handle : Valid File : Failure")
+
+  # Case 6 and 8
+  block:
+    let
+      testFile: TFile = nil
+      testHandle = TFileHandle(-1)
+    try:
+      discard getFileInfo(testFile)
+      echo("Handle : Invalid File : Failure")
+    except IOError, OSError:
+      discard
+      #echo("Handle : Invalid File : Success")
+
+    try:
+      discard getFileInfo(testHandle)
+      echo("Handle : Invalid File : Failure")
+    except IOError, OSError:
+      discard
+      #echo("Handle : Invalid File : Success")
+
+testGetFileInfo()
diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim
new file mode 100644
index 000000000..c442b43fb
--- /dev/null
+++ b/tests/stdlib/thashes.nim
@@ -0,0 +1,8 @@
+import unittest
+import hashes
+
+suite "hashes":
+  suite "hashing":
+    test "0.0 and -0.0 should have the same hash value":
+      var dummy = 0.0
+      check hash(dummy) == hash(-dummy)
diff --git a/tests/stdlib/tio.nim b/tests/stdlib/tio.nim
new file mode 100644
index 000000000..5ae119f77
--- /dev/null
+++ b/tests/stdlib/tio.nim
@@ -0,0 +1,7 @@
+# test the file-IO

+

+proc main() =

+  for line in lines("thello.nim"):

+    writeln(stdout, line)

+

+main()

diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim
new file mode 100644
index 000000000..7d5379945
--- /dev/null
+++ b/tests/stdlib/tlists.nim
@@ -0,0 +1,66 @@
+discard """
+  output: '''true'''
+"""
+
+import lists
+
+const
+  data = [1, 2, 3, 4, 5, 6]
+
+block SinglyLinkedListTest1:
+  var L: TSinglyLinkedList[int]
+  for d in items(data): L.prepend(d)
+  assert($L == "[6, 5, 4, 3, 2, 1]")
+  
+  assert(4 in L)
+
+block SinglyLinkedListTest2:
+  var L: TSinglyLinkedList[string]
+  for d in items(data): L.prepend($d)
+  assert($L == "[6, 5, 4, 3, 2, 1]")
+  
+  assert("4" in L)
+
+
+block DoublyLinkedListTest1:
+  var L: TDoublyLinkedList[int]
+  for d in items(data): L.prepend(d)
+  for d in items(data): L.append(d)
+  L.remove(L.find(1))
+  assert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
+  
+  assert(4 in L)
+
+block SinglyLinkedRingTest1:
+  var L: TSinglyLinkedRing[int]
+  L.prepend(4)
+  assert($L == "[4]")
+  L.prepend(4)
+
+  assert($L == "[4, 4]")
+  assert(4 in L)
+  
+
+block DoublyLinkedRingTest1:
+  var L: TDoublyLinkedRing[int]
+  L.prepend(4)
+  assert($L == "[4]")
+  L.prepend(4)
+
+  assert($L == "[4, 4]")
+  assert(4 in L)
+  
+  L.append(3)
+  L.append(5)
+  assert($L == "[4, 4, 3, 5]")
+
+  L.remove(L.find(3))
+  L.remove(L.find(5))
+  L.remove(L.find(4))
+  L.remove(L.find(4))
+  assert($L == "[]")
+  assert(4 notin L)
+  
+
+echo "true"
+
diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim
new file mode 100644
index 000000000..a778d2f77
--- /dev/null
+++ b/tests/stdlib/tmarshal.nim
@@ -0,0 +1,77 @@
+discard """
+  output: '''{"age": 12, "name": "Cletus"}'''
+"""
+
+import marshal
+
+template testit(x: expr) = discard $$to[type(x)]($$x)
+
+var x: array[0..4, array[0..4, string]] = [
+  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+  ["test", "1", "2", "3", "4"]]
+testit(x)
+var test2: tuple[name: string, s: int] = ("tuple test", 56)
+testit(test2)
+
+type
+  TE = enum
+    blah, blah2
+
+  TestObj = object
+    test, asd: int
+    case test2: TE
+    of blah:
+      help: string
+    else:
+      discard
+      
+  PNode = ref TNode
+  TNode = object
+    next, prev: PNode
+    data: string
+
+proc buildList(): PNode =
+  new(result)
+  new(result.next)
+  new(result.prev)
+  result.data = "middle"
+  result.next.data = "next"
+  result.prev.data = "prev"
+  result.next.next = result.prev
+  result.next.prev = result
+  result.prev.next = result
+  result.prev.prev = result.next
+
+var test3: TestObj
+test3.test = 42
+test3.test2 = blah
+testit(test3)
+
+var test4: ref tuple[a, b: string]
+new(test4)
+test4.a = "ref string test: A"
+test4.b = "ref string test: B"
+testit(test4)
+
+var test5 = @[(0,1),(2,3),(4,5)]
+testit(test5)
+
+var test7 = buildList()
+testit(test7)
+
+var test6: set[char] = {'A'..'Z', '_'}
+testit(test6)
+
+
+# bug #1352
+
+type
+  Entity = object of RootObj
+    name: string
+
+  Person = object of Entity
+    age: int
+
+var instance1 = Person(name: "Cletus", age: 12)
+echo($$instance1)
diff --git a/tests/stdlib/tmath.nim b/tests/stdlib/tmath.nim
new file mode 100644
index 000000000..fc9486093
--- /dev/null
+++ b/tests/stdlib/tmath.nim
@@ -0,0 +1,61 @@
+import math
+import unittest
+import sets
+
+suite "random int":
+  test "there might be some randomness":
+    var set = initSet[int](128)
+    randomize()
+    for i in 1..1000:
+      incl(set, random(high(int)))
+    check len(set) == 1000
+  test "single number bounds work":
+    randomize()
+    var rand: int
+    for i in 1..1000:
+      rand = random(1000)
+      check rand < 1000
+      check rand > -1
+  test "slice bounds work":
+    randomize()
+    var rand: int
+    for i in 1..1000:
+      rand = random(100..1000)
+      check rand < 1000
+      check rand >= 100
+  test "randomize() again gives new numbers":      
+    randomize()
+    var rand1 = random(1000000)
+    randomize()
+    var rand2 = random(1000000)
+    check rand1 != rand2
+    
+
+suite "random float":
+  test "there might be some randomness":
+    var set = initSet[float](128)
+    randomize()
+    for i in 1..100:
+      incl(set, random(1.0))
+    check len(set) == 100
+  test "single number bounds work":
+    randomize()
+    var rand: float
+    for i in 1..1000:
+      rand = random(1000.0)
+      check rand < 1000.0
+      check rand > -1.0
+  test "slice bounds work":
+    randomize()
+    var rand: float
+    for i in 1..1000:
+      rand = random(100.0..1000.0)
+      check rand < 1000.0
+      check rand >= 100.0
+  test "randomize() again gives new numbers":      
+    randomize()
+    var rand1:float = random(1000000.0)
+    randomize()
+    var rand2:float = random(1000000.0)
+    check rand1 != rand2
+
diff --git a/tests/stdlib/tmath2.nim b/tests/stdlib/tmath2.nim
new file mode 100644
index 000000000..88d96c80a
--- /dev/null
+++ b/tests/stdlib/tmath2.nim
@@ -0,0 +1,85 @@
+# tests for the interpreter

+

+proc loops(a: var int) =

+  discard

+  #var

+  #  b: int

+  #b = glob

+  #while b != 0:

+  #  b = b + 1

+  #a = b

+

+proc mymax(a, b: int): int =

+  #loops(result)

+  result = a

+  if b > a: result = b

+

+proc test(a, b: int) =

+  var

+    x, y: int

+  x = 0

+  y = 7

+  if x == a + b * 3 - 7 or

+      x == 8 or

+      x == y and y > -56 and y < 699:

+    y = 0

+  elif y == 78 and x == 0:

+    y = 1

+  elif y == 0 and x == 0:

+    y = 2

+  else:

+    y = 3

+

+type

+  TTokType = enum

+    tkNil, tkType, tkConst, tkVar, tkSymbol, tkIf,

+    tkWhile, tkFor, tkLoop, tkCase, tkLabel, tkGoto

+

+proc testCase(t: TTokType): int =

+  case t

+  of tkNil, tkType, tkConst: result = 0

+  of tkVar: result = 1

+  of tkSymbol: result = 2

+  of tkIf..tkFor: result = 3

+  of tkLoop: result = 56

+  else: result = -1

+  test(0, 9) # test the call

+

+proc TestLoops() =

+  var

+    i, j: int

+

+  while i >= 0:

+    if i mod 3 == 0:

+      break

+    i = i + 1

+    while j == 13:

+      j = 13

+      break

+    break

+

+  while true:

+    break

+

+

+var

+  glob: int

+  a: array [0..5, int]

+

+proc main() =

+  #glob = 0

+  #loops( glob )

+  var

+    res: int

+    s: string

+  #write(stdout, mymax(23, 45))

+  write(stdout, "Hallo! Wie heisst du? ")

+  s = readLine(stdin)

+  # test the case statement

+  case s

+  of "Andreas": write(stdout, "Du bist mein Meister!\n")

+  of "Rumpf": write(stdout, "Du bist in der Familie meines Meisters!\n")

+  else: write(stdout, "ich kenne dich nicht!\n")

+  write(stdout, "Du heisst " & s & "\n")

+

+main()

diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim
new file mode 100644
index 000000000..2c0a0392a
--- /dev/null
+++ b/tests/stdlib/tmitems.nim
@@ -0,0 +1,136 @@
+discard """
+  output: '''@[11, 12, 13]
+@[11, 12, 13]
+@[1, 3, 5]
+@[1, 3, 5]
+gppcbs
+gppcbs
+fpqeew
+fpqeew
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+{"key1": 11, "key2": 12, "key3": 13}
+[11, 12, 13]
+<Students>
+  <Student Name="Aprilfoo" />
+  <Student Name="bar" />
+</Students>'''
+"""
+
+block:
+  var xs = @[1,2,3]
+  for x in xs.mitems:
+    x += 10
+  echo xs
+
+block:
+  var xs = [1,2,3]
+  for x in xs.mitems:
+    x += 10
+  echo(@xs)
+
+block:
+  var xs = @[1,2,3]
+  for i, x in xs.mpairs:
+    x += i
+  echo xs
+
+block:
+  var xs = [1,2,3]
+  for i, x in xs.mpairs:
+    x += i
+  echo(@xs)
+
+block:
+  var x = "foobar"
+  for c in x.mitems:
+    inc c
+  echo x
+
+block:
+  var x = "foobar"
+  var y = cast[cstring](addr x[0])
+  for c in y.mitems:
+    inc c
+  echo x
+
+block:
+  var x = "foobar"
+  for i, c in x.mpairs:
+    inc c, i
+  echo x
+
+block:
+  var x = "foobar"
+  var y = cast[cstring](addr x[0])
+  for i, c in y.mpairs:
+    inc c, i
+  echo x
+
+import lists
+
+block:
+  var sl = initSinglyLinkedList[int]()
+  sl.prepend(3)
+  sl.prepend(2)
+  sl.prepend(1)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+block:
+  var sl = initDoublyLinkedList[int]()
+  sl.append(1)
+  sl.append(2)
+  sl.append(3)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+block:
+  var sl = initDoublyLinkedRing[int]()
+  sl.append(1)
+  sl.append(2)
+  sl.append(3)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+import queues
+
+block:
+  var q = initQueue[int]()
+  q.add(1)
+  q.add(2)
+  q.add(3)
+  for x in q.mitems:
+    x += 10
+  echo q
+
+import json
+
+block:
+  var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}"""
+  for key,val in j.pairs:
+    val.num += 10
+  echo j
+
+block:
+  var j = parseJson """[1, 2, 3]"""
+  for x in j.mitems:
+    x.num += 10
+  echo j
+
+import xmltree, xmlparser, streams, strtabs
+
+block:
+  var d = parseXml(newStringStream """<Students>
+    <Student Name="April" Gender="F" DateOfBirth="1989-01-02" />
+    <Student Name="Bob" Gender="M"  DateOfBirth="1990-03-04" />
+  </Students>""")
+  for x in d.mitems:
+    x = <>Student(Name=x.attrs["Name"] & "foo")
+  d.mget(1).attrs["Name"] = "bar"
+  echo d
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
new file mode 100644
index 000000000..e8ada05e7
--- /dev/null
+++ b/tests/stdlib/tnet.nim
@@ -0,0 +1,47 @@
+import net
+import unittest
+
+suite "isIpAddress tests":
+  test "127.0.0.1 is valid":
+    check isIpAddress("127.0.0.1") == true
+
+  test "ipv6 localhost is valid":
+    check isIpAddress("::1") == true
+
+  test "fqdn is not an ip address":
+    check isIpAddress("example.com") == false
+
+  test "random string is not an ipaddress":
+    check isIpAddress("foo bar") == false
+
+  test "5127.0.0.1 is invalid":
+    check isIpAddress("5127.0.0.1") == false
+
+  test "ipv6 is valid":
+    check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true
+
+  test "invalid ipv6":
+    check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false
+
+
+suite "parseIpAddress tests":
+  test "127.0.0.1 is valid":
+    discard parseIpAddress("127.0.0.1")
+
+  test "ipv6 localhost is valid":
+    discard parseIpAddress("::1")
+
+  test "fqdn is not an ip address":
+    expect(ValueError):
+      discard parseIpAddress("example.com")
+
+  test "random string is not an ipaddress":
+    expect(ValueError):
+      discard parseIpAddress("foo bar")
+
+  test "ipv6 is valid":
+    discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652")
+
+  test "invalid ipv6":
+    expect(ValueError):
+      discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652")
diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim
new file mode 100644
index 000000000..ebe577b00
--- /dev/null
+++ b/tests/stdlib/tos.nim
@@ -0,0 +1,12 @@
+# test some things of the os module
+
+import os
+
+proc walkDirTree(root: string) = 
+  for k, f in walkDir(root):
+    case k 
+    of pcFile, pcLinkToFile: echo(f)
+    of pcDir: walkDirTree(f)
+    of pcLinkToDir: discard
+
+walkDirTree(".")
diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim
new file mode 100644
index 000000000..fd044414c
--- /dev/null
+++ b/tests/stdlib/tosprocterminate.nim
@@ -0,0 +1,21 @@
+import os, osproc
+
+when defined(Windows):
+  const ProgramWhichDoesNotEnd = "notepad"
+else:
+  const ProgramWhichDoesNotEnd = "/bin/sh"
+
+echo("starting " & ProgramWhichDoesNotEnd)
+var process = startProcess(ProgramWhichDoesNotEnd)
+sleep(500)
+echo("stopping process")
+process.terminate()
+var TimeToWait = 5000
+while process.running() and TimeToWait > 0:
+  sleep(100)
+  TimeToWait = TimeToWait - 100
+  
+if process.running():
+  echo("FAILED")
+else:
+  echo("SUCCESS")
diff --git a/tests/stdlib/tparscfg.nim b/tests/stdlib/tparscfg.nim
new file mode 100644
index 000000000..618ecadd6
--- /dev/null
+++ b/tests/stdlib/tparscfg.nim
@@ -0,0 +1,25 @@
+
+import
+  os, parsecfg, strutils, streams
+  
+var f = newFileStream(paramStr(1), fmRead)
+if f != nil:
+  var p: TCfgParser
+  open(p, f, paramStr(1))
+  while true:
+    var e = next(p)
+    case e.kind
+    of cfgEof: 
+      echo("EOF!")
+      break
+    of cfgSectionStart:   ## a ``[section]`` has been parsed
+      echo("new section: " & e.section)
+    of cfgKeyValuePair:
+      echo("key-value-pair: " & e.key & ": " & e.value)
+    of cfgOption:
+      echo("command: " & e.key & ": " & e.value)
+    of cfgError:
+      echo(e.msg)
+  close(p)
+else:
+  echo("cannot open: " & paramStr(1))
diff --git a/tests/stdlib/tparsopt.nim b/tests/stdlib/tparsopt.nim
new file mode 100644
index 000000000..2b2da7e51
--- /dev/null
+++ b/tests/stdlib/tparsopt.nim
@@ -0,0 +1,27 @@
+# Test the new parseopt module
+
+import
+  parseopt
+
+proc writeHelp() = 
+  writeln(stdout, "Usage: tparsopt [options] filename [options]")
+
+proc writeVersion() = 
+  writeln(stdout, "Version: 1.0.0")
+  
+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()
+    else: 
+      writeln(stdout, "Unknown command line option: ", key, ": ", val)
+  of cmdEnd: assert(false) # cannot happen
+if filename == "":
+  # no filename has been given, so we show the help:
+  writeHelp()
diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim
new file mode 100644
index 000000000..cceea1693
--- /dev/null
+++ b/tests/stdlib/tpegs.nim
@@ -0,0 +1,1770 @@
+discard """
+  output: '''this
+is
+an
+example
+d
+e
+f
+('keyvalue' 'key'*)'''
+"""
+# PEGs module turned out to be a good test to detect memory management bugs.
+
+include "system/inclrtl"
+
+const
+  useUnicode = true ## change this to deactivate proper UTF-8 support
+
+import
+  strutils
+
+when useUnicode:
+  import unicode
+
+const
+  InlineThreshold = 5  ## number of leaves; -1 to disable inlining
+  MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that
+                       ## can be captured. More subpatterns cannot be captured! 
+
+type
+  TPegKind = enum
+    pkEmpty,
+    pkAny,              ## any character (.)
+    pkAnyRune,          ## any Unicode character (_)
+    pkNewLine,          ## CR-LF, LF, CR
+    pkLetter,           ## Unicode letter
+    pkLower,            ## Unicode lower case letter
+    pkUpper,            ## Unicode upper case letter
+    pkTitle,            ## Unicode title character
+    pkWhitespace,       ## Unicode whitespace character
+    pkTerminal,
+    pkTerminalIgnoreCase,
+    pkTerminalIgnoreStyle,
+    pkChar,             ## single character to match
+    pkCharChoice,
+    pkNonTerminal,
+    pkSequence,         ## a b c ... --> Internal DSL: peg(a, b, c)
+    pkOrderedChoice,    ## a / b / ... --> Internal DSL: a / b or /[a, b, c]
+    pkGreedyRep,        ## a*     --> Internal DSL: *a
+                        ## a+     --> (a a*)
+    pkGreedyRepChar,    ## x* where x is a single character (superop)
+    pkGreedyRepSet,     ## [set]* (superop)
+    pkGreedyAny,        ## .* or _* (superop)
+    pkOption,           ## a?     --> Internal DSL: ?a
+    pkAndPredicate,     ## &a     --> Internal DSL: &a
+    pkNotPredicate,     ## !a     --> Internal DSL: !a
+    pkCapture,          ## {a}    --> Internal DSL: capture(a)
+    pkBackRef,          ## $i     --> Internal DSL: backref(i)
+    pkBackRefIgnoreCase,
+    pkBackRefIgnoreStyle,
+    pkSearch,           ## @a     --> Internal DSL: !*a
+    pkCapturedSearch,   ## {@} a  --> Internal DSL: !*\a
+    pkRule,             ## a <- b
+    pkList,             ## a, b
+    pkStartAnchor       ## ^      --> Internal DSL: startAnchor()
+  TNonTerminalFlag = enum
+    ntDeclared, ntUsed
+  TNonTerminal {.final.} = object ## represents a non terminal symbol
+    name: string                  ## the name of the symbol
+    line: int                     ## line the symbol has been declared/used in
+    col: int                      ## column the symbol has been declared/used in
+    flags: set[TNonTerminalFlag]  ## the nonterminal's flags
+    rule: TNode                   ## the rule that the symbol refers to
+  TNode {.final, shallow.} = object
+    case kind: TPegKind
+    of pkEmpty..pkWhitespace: nil
+    of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string
+    of pkChar, pkGreedyRepChar: ch: char
+    of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char]
+    of pkNonTerminal: nt: PNonTerminal
+    of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns]
+    else: sons: seq[TNode]
+  PNonTerminal* = ref TNonTerminal
+  
+  TPeg* = TNode ## type that represents a PEG
+
+proc term*(t: string): TPeg {.rtl, extern: "npegs$1Str".} =
+  ## constructs a PEG from a terminal string
+  if t.len != 1:  
+    result.kind = pkTerminal
+    result.term = t
+  else:
+    result.kind = pkChar
+    result.ch = t[0]
+
+proc termIgnoreCase*(t: string): TPeg {.
+  rtl, extern: "npegs$1".} =
+  ## constructs a PEG from a terminal string; ignore case for matching
+  result.kind = pkTerminalIgnoreCase
+  result.term = t
+
+proc termIgnoreStyle*(t: string): TPeg {.
+  rtl, extern: "npegs$1".} =
+  ## constructs a PEG from a terminal string; ignore style for matching
+  result.kind = pkTerminalIgnoreStyle
+  result.term = t
+
+proc term*(t: char): TPeg {.rtl, extern: "npegs$1Char".} =
+  ## constructs a PEG from a terminal char
+  assert t != '\0'
+  result.kind = pkChar
+  result.ch = t
+  
+proc charSet*(s: set[char]): TPeg {.rtl, extern: "npegs$1".} =
+  ## constructs a PEG from a character set `s`
+  assert '\0' notin s
+  result.kind = pkCharChoice
+  new(result.charChoice)
+  result.charChoice[] = s
+
+proc len(a: TPeg): int {.inline.} = return a.sons.len
+proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s)
+
+proc copyPeg(a: TPeg): TPeg = 
+  result.kind = a.kind
+  case a.kind
+  of pkEmpty..pkWhitespace: discard
+  of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: 
+    result.term = a.term
+  of pkChar, pkGreedyRepChar: 
+    result.ch = a.ch
+  of pkCharChoice, pkGreedyRepSet: 
+    new(result.charChoice)
+    result.charChoice[] = a.charChoice[]
+  of pkNonTerminal: result.nt = a.nt
+  of pkBackRef..pkBackRefIgnoreStyle: 
+    result.index = a.index
+  else: 
+    result.sons = a.sons
+
+proc addChoice(dest: var TPeg, elem: TPeg) =
+  var L = dest.len-1
+  if L >= 0 and dest.sons[L].kind == pkCharChoice: 
+    # caution! Do not introduce false aliasing here!
+    case elem.kind
+    of pkCharChoice:
+      dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[])
+    of pkChar: 
+      dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch})
+    else: add(dest, elem)
+  else: add(dest, elem)
+
+template multipleOp(k: TPegKind, localOpt: expr) =
+  result.kind = k
+  result.sons = @[]
+  for x in items(a):
+    if x.kind == k:
+      for y in items(x.sons):
+        localOpt(result, y)
+    else:
+      localOpt(result, x)
+  if result.len == 1:
+    result = result.sons[0]
+
+proc `/`*(a: varargs[TPeg]): TPeg {.
+  rtl, extern: "npegsOrderedChoice".} =
+  ## constructs an ordered choice with the PEGs in `a`
+  multipleOp(pkOrderedChoice, addChoice)
+
+proc addSequence(dest: var TPeg, elem: TPeg) =
+  var L = dest.len-1
+  if L >= 0 and dest.sons[L].kind == pkTerminal: 
+    # caution! Do not introduce false aliasing here!
+    case elem.kind
+    of pkTerminal: 
+      dest.sons[L] = term(dest.sons[L].term & elem.term)
+    of pkChar: 
+      dest.sons[L] = term(dest.sons[L].term & elem.ch)
+    else: add(dest, elem)
+  else: add(dest, elem)
+
+proc sequence*(a: varargs[TPeg]): TPeg {.
+  rtl, extern: "npegs$1".} =
+  ## constructs a sequence with all the PEGs from `a`
+  multipleOp(pkSequence, addSequence)
+ 
+proc `?`*(a: TPeg): TPeg {.rtl, extern: "npegsOptional".} =
+  ## constructs an optional for the PEG `a`
+  if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar,
+                pkGreedyRepSet}:
+    # a* ?  --> a*
+    # a? ?  --> a?
+    result = a
+  else:
+    result.kind = pkOption
+    result.sons = @[a]
+
+proc `*`*(a: TPeg): TPeg {.rtl, extern: "npegsGreedyRep".} =
+  ## constructs a "greedy repetition" for the PEG `a`
+  case a.kind
+  of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption:
+    assert false
+    # produces endless loop!
+  of pkChar:
+    result.kind = pkGreedyRepChar
+    result.ch = a.ch
+  of pkCharChoice:
+    result.kind = pkGreedyRepSet
+    result.charChoice = a.charChoice # copying a reference suffices!
+  of pkAny, pkAnyRune:
+    result.kind = pkGreedyAny
+  else:
+    result.kind = pkGreedyRep
+    result.sons = @[a]
+
+proc `!*`*(a: TPeg): TPeg {.rtl, extern: "npegsSearch".} =
+  ## constructs a "search" for the PEG `a`
+  result.kind = pkSearch
+  result.sons = @[a]
+
+proc `!*\`*(a: TPeg): TPeg {.rtl, 
+                             extern: "npgegsCapturedSearch".} =
+  ## constructs a "captured search" for the PEG `a`
+  result.kind = pkCapturedSearch
+  result.sons = @[a]
+  
+when false:
+  proc contains(a: TPeg, k: TPegKind): bool =
+    if a.kind == k: return true
+    case a.kind
+    of pkEmpty, pkAny, pkAnyRune, pkGreedyAny, pkNewLine, pkTerminal,
+       pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar,
+       pkCharChoice, pkGreedyRepSet: discard
+    of pkNonTerminal: return true
+    else:
+      for i in 0..a.sons.len-1:
+        if contains(a.sons[i], k): return true
+
+proc `+`*(a: TPeg): TPeg {.rtl, extern: "npegsGreedyPosRep".} =
+  ## constructs a "greedy positive repetition" with the PEG `a`
+  return sequence(a, *a)
+  
+proc `&`*(a: TPeg): TPeg {.rtl, extern: "npegsAndPredicate".} =
+  ## constructs an "and predicate" with the PEG `a`
+  result.kind = pkAndPredicate
+  result.sons = @[a]
+
+proc `!`*(a: TPeg): TPeg {.rtl, extern: "npegsNotPredicate".} =
+  ## constructs a "not predicate" with the PEG `a`
+  result.kind = pkNotPredicate
+  result.sons = @[a]
+
+proc any*: TPeg {.inline.} =
+  ## constructs the PEG `any character`:idx: (``.``)
+  result.kind = pkAny
+
+proc anyRune*: TPeg {.inline.} =
+  ## constructs the PEG `any rune`:idx: (``_``)
+  result.kind = pkAnyRune
+
+proc newLine*: TPeg {.inline.} =
+  ## constructs the PEG `newline`:idx: (``\n``)
+  result.kind = pkNewline
+
+proc UnicodeLetter*: TPeg {.inline.} = 
+  ## constructs the PEG ``\letter`` which matches any Unicode letter.
+  result.kind = pkLetter
+  
+proc UnicodeLower*: TPeg {.inline.} = 
+  ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
+  result.kind = pkLower 
+
+proc UnicodeUpper*: TPeg {.inline.} = 
+  ## constructs the PEG ``\upper`` which matches any Unicode lowercase letter.
+  result.kind = pkUpper 
+  
+proc UnicodeTitle*: TPeg {.inline.} = 
+  ## constructs the PEG ``\title`` which matches any Unicode title letter.
+  result.kind = pkTitle
+
+proc UnicodeWhitespace*: TPeg {.inline.} = 
+  ## constructs the PEG ``\white`` which matches any Unicode 
+  ## whitespace character.
+  result.kind = pkWhitespace
+
+proc startAnchor*: TPeg {.inline.} = 
+  ## constructs the PEG ``^`` which matches the start of the input.  
+  result.kind = pkStartAnchor
+
+proc endAnchor*: TPeg {.inline.} = 
+  ## constructs the PEG ``$`` which matches the end of the input.  
+  result = !any()
+
+proc capture*(a: TPeg): TPeg {.rtl, extern: "npegsCapture".} =
+  ## constructs a capture with the PEG `a`
+  result.kind = pkCapture
+  result.sons = @[a]
+
+proc backref*(index: range[1..MaxSubPatterns]): TPeg {.
+  rtl, extern: "npegs$1".} = 
+  ## constructs a back reference of the given `index`. `index` starts counting
+  ## from 1.
+  result.kind = pkBackRef
+  result.index = index-1
+
+proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): TPeg {.
+  rtl, extern: "npegs$1".} = 
+  ## constructs a back reference of the given `index`. `index` starts counting
+  ## from 1. Ignores case for matching.
+  result.kind = pkBackRefIgnoreCase
+  result.index = index-1
+
+proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
+  rtl, extern: "npegs$1".}= 
+  ## constructs a back reference of the given `index`. `index` starts counting
+  ## from 1. Ignores style for matching.
+  result.kind = pkBackRefIgnoreStyle
+  result.index = index-1
+
+proc spaceCost(n: TPeg): int =
+  case n.kind
+  of pkEmpty: discard
+  of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
+     pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, 
+     pkAny..pkWhitespace, pkGreedyAny:
+    result = 1
+  of pkNonTerminal:
+    # we cannot inline a rule with a non-terminal
+    result = InlineThreshold+1
+  else:
+    for i in 0..n.len-1:
+      inc(result, spaceCost(n.sons[i]))
+      if result >= InlineThreshold: break
+
+proc nonterminal*(n: PNonTerminal): TPeg {.
+  rtl, extern: "npegs$1".} = 
+  ## constructs a PEG that consists of the nonterminal symbol
+  assert n != nil
+  if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold:
+    when false: echo "inlining symbol: ", n.name
+    result = n.rule # inlining of rule enables better optimizations
+  else:
+    result.kind = pkNonTerminal
+    result.nt = n
+
+proc newNonTerminal*(name: string, line, column: int): PNonTerminal {.
+  rtl, extern: "npegs$1".} =
+  ## constructs a nonterminal symbol
+  new(result)
+  result.name = name
+  result.line = line
+  result.col = column
+
+template letters*: expr =
+  ## expands to ``charset({'A'..'Z', 'a'..'z'})``
+  charset({'A'..'Z', 'a'..'z'})
+  
+template digits*: expr =
+  ## expands to ``charset({'0'..'9'})``
+  charset({'0'..'9'})
+
+template whitespace*: expr =
+  ## expands to ``charset({' ', '\9'..'\13'})``
+  charset({' ', '\9'..'\13'})
+  
+template identChars*: expr =
+  ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
+  charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})
+  
+template identStartChars*: expr =
+  ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
+  charset({'a'..'z', 'A'..'Z', '_'})
+
+template ident*: expr =
+  ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
+  sequence(charset({'a'..'z', 'A'..'Z', '_'}),
+           *charset({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
+  
+template natural*: expr =
+  ## same as ``\d+``
+  +digits
+
+# ------------------------- debugging -----------------------------------------
+
+proc esc(c: char, reserved = {'\0'..'\255'}): string = 
+  case c
+  of '\b': result = "\\b"
+  of '\t': result = "\\t"
+  of '\c': result = "\\c"
+  of '\L': result = "\\l"
+  of '\v': result = "\\v"
+  of '\f': result = "\\f"
+  of '\e': result = "\\e"
+  of '\a': result = "\\a"
+  of '\\': result = "\\\\"
+  of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c
+  elif c < ' ' or c >= '\128': result = '\\' & $ord(c)
+  elif c in reserved: result = '\\' & c
+  else: result = $c
+  
+proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
+
+proc singleQuoteEsc(str: string): string = 
+  result = "'"
+  for c in items(str): add result, esc(c, {'\''})
+  add result, '\''
+  
+proc charSetEscAux(cc: set[char]): string = 
+  const reserved = {'^', '-', ']'}
+  result = ""
+  var c1 = 0
+  while c1 <= 0xff: 
+    if chr(c1) in cc: 
+      var c2 = c1
+      while c2 < 0xff and chr(succ(c2)) in cc: inc(c2)
+      if c1 == c2: 
+        add result, esc(chr(c1), reserved)
+      elif c2 == succ(c1): 
+        add result, esc(chr(c1), reserved) & esc(chr(c2), reserved)
+      else: 
+        add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved)
+      c1 = c2
+    inc(c1)
+  
+proc charSetEsc(cc: set[char]): string =
+  if card(cc) >= 128+64: 
+    result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
+  else: 
+    result = '[' & charSetEscAux(cc) & ']'
+  
+proc toStrAux(r: TPeg, res: var string) = 
+  case r.kind
+  of pkEmpty: add(res, "()")
+  of pkAny: add(res, '.')
+  of pkAnyRune: add(res, '_')
+  of pkLetter: add(res, "\\letter")
+  of pkLower: add(res, "\\lower")
+  of pkUpper: add(res, "\\upper")
+  of pkTitle: add(res, "\\title")
+  of pkWhitespace: add(res, "\\white")
+
+  of pkNewline: add(res, "\\n")
+  of pkTerminal: add(res, singleQuoteEsc(r.term))
+  of pkTerminalIgnoreCase:
+    add(res, 'i')
+    add(res, singleQuoteEsc(r.term))
+  of pkTerminalIgnoreStyle:
+    add(res, 'y')
+    add(res, singleQuoteEsc(r.term))
+  of pkChar: add(res, singleQuoteEsc(r.ch))
+  of pkCharChoice: add(res, charSetEsc(r.charChoice[]))
+  of pkNonTerminal: add(res, r.nt.name)
+  of pkSequence:
+    add(res, '(')
+    toStrAux(r.sons[0], res)
+    for i in 1 .. high(r.sons):
+      add(res, ' ')
+      toStrAux(r.sons[i], res)
+    add(res, ')')
+  of pkOrderedChoice:
+    add(res, '(')
+    toStrAux(r.sons[0], res)
+    for i in 1 .. high(r.sons):
+      add(res, " / ")
+      toStrAux(r.sons[i], res)
+    add(res, ')')
+  of pkGreedyRep:
+    toStrAux(r.sons[0], res)
+    add(res, '*')
+  of pkGreedyRepChar:
+    add(res, singleQuoteEsc(r.ch))
+    add(res, '*')
+  of pkGreedyRepSet:
+    add(res, charSetEsc(r.charChoice[]))
+    add(res, '*')
+  of pkGreedyAny:
+    add(res, ".*")
+  of pkOption:
+    toStrAux(r.sons[0], res)
+    add(res, '?')
+  of pkAndPredicate:
+    add(res, '&')
+    toStrAux(r.sons[0], res)
+  of pkNotPredicate:
+    add(res, '!')
+    toStrAux(r.sons[0], res)
+  of pkSearch:
+    add(res, '@')
+    toStrAux(r.sons[0], res)
+  of pkCapturedSearch:
+    add(res, "{@}")
+    toStrAux(r.sons[0], res)
+  of pkCapture:
+    add(res, '{')
+    toStrAux(r.sons[0], res)    
+    add(res, '}')
+  of pkBackRef: 
+    add(res, '$')
+    add(res, $r.index)
+  of pkBackRefIgnoreCase: 
+    add(res, "i$")
+    add(res, $r.index)
+  of pkBackRefIgnoreStyle: 
+    add(res, "y$")
+    add(res, $r.index)
+  of pkRule:
+    toStrAux(r.sons[0], res)    
+    add(res, " <- ")
+    toStrAux(r.sons[1], res)
+  of pkList:
+    for i in 0 .. high(r.sons):
+      toStrAux(r.sons[i], res)
+      add(res, "\n")  
+  of pkStartAnchor:
+    add(res, '^')
+
+proc `$` *(r: TPeg): string {.rtl, extern: "npegsToString".} =
+  ## converts a PEG to its string representation
+  result = ""
+  toStrAux(r, result)
+
+# --------------------- core engine -------------------------------------------
+
+type
+  TCaptures* {.final.} = object ## contains the captured substrings.
+    matches: array[0..MaxSubpatterns-1, tuple[first, last: int]]
+    ml: int
+    origStart: int
+
+proc bounds*(c: TCaptures, 
+             i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = 
+  ## returns the bounds ``[first..last]`` of the `i`'th capture.
+  result = c.matches[i]
+
+when not useUnicode:
+  type
+    Rune = char
+  template fastRuneAt(s, i, ch: expr) =
+    ch = s[i]
+    inc(i)
+  template runeLenAt(s, i: expr): expr = 1
+
+  proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'}
+  proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'}
+  proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'}
+  proc isTitle(a: char): bool {.inline.} = return false
+  proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'}
+
+proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
+               rtl, extern: "npegs$1".} =
+  ## low-level matching proc that implements the PEG interpreter. Use this 
+  ## for maximum efficiency (every other PEG operation ends up calling this
+  ## proc).
+  ## Returns -1 if it does not match, else the length of the match
+  case p.kind
+  of pkEmpty: result = 0 # match of length 0
+  of pkAny:
+    if s[start] != '\0': result = 1
+    else: result = -1
+  of pkAnyRune:
+    if s[start] != '\0':
+      result = runeLenAt(s, start)
+    else:
+      result = -1
+  of pkLetter: 
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isAlpha(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkLower: 
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isLower(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkUpper: 
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isUpper(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkTitle: 
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isTitle(a): dec(result, start) 
+      else: result = -1
+    else:
+      result = -1
+  of pkWhitespace: 
+    if s[start] != '\0':
+      var a: Rune
+      result = start
+      fastRuneAt(s, result, a)
+      if isWhitespace(a): dec(result, start)
+      else: result = -1
+    else:
+      result = -1
+  of pkGreedyAny:
+    result = len(s) - start
+  of pkNewLine:
+    if s[start] == '\L': result = 1
+    elif s[start] == '\C':
+      if s[start+1] == '\L': result = 2
+      else: result = 1
+    else: result = -1
+  of pkTerminal:
+    result = len(p.term)
+    for i in 0..result-1:
+      if p.term[i] != s[start+i]:
+        result = -1
+        break
+  of pkTerminalIgnoreCase:
+    var
+      i = 0
+      a, b: Rune
+    result = start
+    while i < len(p.term):
+      fastRuneAt(p.term, i, a)
+      fastRuneAt(s, result, b)
+      if toLower(a) != toLower(b):
+        result = -1
+        break
+    dec(result, start)
+  of pkTerminalIgnoreStyle:
+    var
+      i = 0
+      a, b: Rune
+    result = start
+    while i < len(p.term):
+      while true:
+        fastRuneAt(p.term, i, a)
+        if a != Rune('_'): break
+      while true:
+        fastRuneAt(s, result, b)
+        if b != Rune('_'): break
+      if toLower(a) != toLower(b):
+        result = -1
+        break
+    dec(result, start)
+  of pkChar:
+    if p.ch == s[start]: result = 1
+    else: result = -1
+  of pkCharChoice:
+    if contains(p.charChoice[], s[start]): result = 1
+    else: result = -1
+  of pkNonTerminal:
+    var oldMl = c.ml
+    when false: echo "enter: ", p.nt.name
+    result = rawMatch(s, p.nt.rule, start, c)
+    when false: echo "leave: ", p.nt.name
+    if result < 0: c.ml = oldMl
+  of pkSequence:
+    var oldMl = c.ml  
+    result = 0
+    assert(not isNil(p.sons))
+    for i in 0..high(p.sons):
+      var x = rawMatch(s, p.sons[i], start+result, c)
+      if x < 0:
+        c.ml = oldMl
+        result = -1
+        break
+      else: inc(result, x)
+  of pkOrderedChoice:
+    var oldMl = c.ml
+    for i in 0..high(p.sons):
+      result = rawMatch(s, p.sons[i], start, c)
+      if result >= 0: break
+      c.ml = oldMl
+  of pkSearch:
+    var oldMl = c.ml
+    result = 0
+    while start+result < s.len:
+      var x = rawMatch(s, p.sons[0], start+result, c)
+      if x >= 0:
+        inc(result, x)
+        return
+      inc(result)
+    result = -1
+    c.ml = oldMl
+  of pkCapturedSearch:
+    var idx = c.ml # reserve a slot for the subpattern
+    inc(c.ml)
+    result = 0
+    while start+result < s.len:
+      var x = rawMatch(s, p.sons[0], start+result, c)
+      if x >= 0:
+        if idx < MaxSubpatterns:
+          c.matches[idx] = (start, start+result-1)
+        #else: silently ignore the capture
+        inc(result, x)
+        return
+      inc(result)
+    result = -1
+    c.ml = idx
+  of pkGreedyRep:
+    result = 0
+    while true:
+      var x = rawMatch(s, p.sons[0], start+result, c)
+      # if x == 0, we have an endless loop; so the correct behaviour would be
+      # not to break. But endless loops can be easily introduced:
+      # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the
+      # expected thing in this case.
+      if x <= 0: break
+      inc(result, x)
+  of pkGreedyRepChar:
+    result = 0
+    var ch = p.ch
+    while ch == s[start+result]: inc(result)
+  of pkGreedyRepSet:
+    result = 0
+    while contains(p.charChoice[], s[start+result]): inc(result)
+  of pkOption:
+    result = max(0, rawMatch(s, p.sons[0], start, c))
+  of pkAndPredicate:
+    var oldMl = c.ml
+    result = rawMatch(s, p.sons[0], start, c)
+    if result >= 0: result = 0 # do not consume anything
+    else: c.ml = oldMl
+  of pkNotPredicate:
+    var oldMl = c.ml
+    result = rawMatch(s, p.sons[0], start, c)
+    if result < 0: result = 0
+    else:
+      c.ml = oldMl
+      result = -1
+  of pkCapture:
+    var idx = c.ml # reserve a slot for the subpattern
+    inc(c.ml)
+    result = rawMatch(s, p.sons[0], start, c)
+    if result >= 0:
+      if idx < MaxSubpatterns:
+        c.matches[idx] = (start, start+result-1)
+      #else: silently ignore the capture
+    else:
+      c.ml = idx
+  of pkBackRef..pkBackRefIgnoreStyle: 
+    if p.index >= c.ml: return -1
+    var (a, b) = c.matches[p.index]
+    var n: TPeg
+    n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) 
+    n.term = s.substr(a, b)
+    result = rawMatch(s, n, start, c)
+  of pkStartAnchor:
+    if c.origStart == start: result = 0
+    else: result = -1
+  of pkRule, pkList: assert false
+
+proc match*(s: string, pattern: TPeg, matches: var openarray[string],
+            start = 0): bool {.rtl, extern: "npegs$1Capture".} =
+  ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
+  ## the captured substrings in the array ``matches``. If it does not
+  ## match, nothing is written into ``matches`` and ``false`` is
+  ## returned.
+  var c: TCaptures
+  c.origStart = start
+  result = rawMatch(s, pattern, start, c) == len(s) -start
+  if result:
+    for i in 0..c.ml-1:
+      matches[i] = substr(s, c.matches[i][0], c.matches[i][1])
+
+proc match*(s: string, pattern: TPeg, 
+            start = 0): bool {.rtl, extern: "npegs$1".} =
+  ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``.
+  var c: TCaptures
+  c.origStart = start
+  result = rawMatch(s, pattern, start, c) == len(s)-start
+
+proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string],
+               start = 0): int {.rtl, extern: "npegs$1Capture".} =
+  ## the same as ``match``, but it returns the length of the match,
+  ## if there is no match, -1 is returned. Note that a match length
+  ## of zero can happen. It's possible that a suffix of `s` remains
+  ## that does not belong to the match.
+  var c: TCaptures
+  c.origStart = start
+  result = rawMatch(s, pattern, start, c)
+  if result >= 0:
+    for i in 0..c.ml-1:
+      matches[i] = substr(s, c.matches[i][0], c.matches[i][1])
+
+proc matchLen*(s: string, pattern: TPeg, 
+               start = 0): int {.rtl, extern: "npegs$1".} =
+  ## the same as ``match``, but it returns the length of the match,
+  ## if there is no match, -1 is returned. Note that a match length
+  ## of zero can happen. It's possible that a suffix of `s` remains
+  ## that does not belong to the match.
+  var c: TCaptures
+  c.origStart = start
+  result = rawMatch(s, pattern, start, c)
+
+proc find*(s: string, pattern: TPeg, matches: var openarray[string],
+           start = 0): int {.rtl, extern: "npegs$1Capture".} =
+  ## returns the starting position of ``pattern`` in ``s`` and the captured
+  ## substrings in the array ``matches``. If it does not match, nothing
+  ## is written into ``matches`` and -1 is returned.
+  for i in start .. s.len-1:
+    if matchLen(s, pattern, matches, i) >= 0: return i
+  return -1
+  # could also use the pattern here: (!P .)* P
+  
+proc findBounds*(s: string, pattern: TPeg, matches: var openarray[string],
+                 start = 0): tuple[first, last: int] {.
+                 rtl, extern: "npegs$1Capture".} =
+  ## returns the starting position and end position of ``pattern`` in ``s`` 
+  ## and the captured
+  ## substrings in the array ``matches``. If it does not match, nothing
+  ## is written into ``matches`` and (-1,0) is returned.
+  for i in start .. s.len-1:
+    var L = matchLen(s, pattern, matches, i)
+    if L >= 0: return (i, i+L-1)
+  return (-1, 0)
+  
+proc find*(s: string, pattern: TPeg, 
+           start = 0): int {.rtl, extern: "npegs$1".} =
+  ## returns the starting position of ``pattern`` in ``s``. If it does not
+  ## match, -1 is returned.
+  for i in start .. s.len-1:
+    if matchLen(s, pattern, i) >= 0: return i
+  return -1
+  
+iterator findAll*(s: string, pattern: TPeg, start = 0): string = 
+  ## yields all matching captures of pattern in `s`.
+  var matches: array[0..MaxSubpatterns-1, string]
+  var i = start
+  while i < s.len:
+    var L = matchLen(s, pattern, matches, i)
+    if L < 0: break
+    for k in 0..MaxSubPatterns-1: 
+      if isNil(matches[k]): break
+      yield matches[k]
+    inc(i, L)
+    
+proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {.
+  rtl, extern: "npegs$1".} = 
+  ## returns all matching captures of pattern in `s`.
+  ## If it does not match, @[] is returned.
+  accumulateResult(findAll(s, pattern, start))
+  
+template `=~`*(s: string, pattern: TPeg): expr =
+  ## This calls ``match`` with an implicit declared ``matches`` array that 
+  ## can be used in the scope of the ``=~`` call: 
+  ## 
+  ## .. code-block:: nim
+  ##
+  ##   if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": 
+  ##     # matches a key=value pair:
+  ##     echo("Key: ", matches[0])
+  ##     echo("Value: ", matches[1])
+  ##   elif line =~ peg"\s*{'#'.*}":
+  ##     # matches a comment
+  ##     # note that the implicit ``matches`` array is different from the
+  ##     # ``matches`` array of the first branch
+  ##     echo("comment: ", matches[0])
+  ##   else:
+  ##     echo("syntax error")
+  ##  
+  when not declaredInScope(matches):
+    var matches {.inject.}: array[0..MaxSubpatterns-1, string]
+  match(s, pattern, matches)
+
+# ------------------------- more string handling ------------------------------
+
+proc contains*(s: string, pattern: TPeg, start = 0): bool {.
+  rtl, extern: "npegs$1".} =
+  ## same as ``find(s, pattern, start) >= 0``
+  return find(s, pattern, start) >= 0
+
+proc contains*(s: string, pattern: TPeg, matches: var openArray[string],
+              start = 0): bool {.rtl, extern: "npegs$1Capture".} =
+  ## same as ``find(s, pattern, matches, start) >= 0``
+  return find(s, pattern, matches, start) >= 0
+
+proc startsWith*(s: string, prefix: TPeg, start = 0): bool {.
+  rtl, extern: "npegs$1".} =
+  ## returns true if `s` starts with the pattern `prefix`
+  result = matchLen(s, prefix, start) >= 0
+
+proc endsWith*(s: string, suffix: TPeg, start = 0): bool {.
+  rtl, extern: "npegs$1".} =
+  ## returns true if `s` ends with the pattern `prefix`
+  for i in start .. s.len-1:
+    if matchLen(s, suffix, i) == s.len - i: return true
+
+proc replacef*(s: string, sub: TPeg, by: string): string {.
+  rtl, extern: "npegs$1".} =
+  ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
+  ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
+  ##
+  ## .. code-block:: nim
+  ##   "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2")
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   "var1<-keykey; val2<-key2key2"
+  result = ""
+  var i = 0
+  var caps: array[0..MaxSubpatterns-1, string]
+  while i < s.len:
+    var x = matchLen(s, sub, caps, i)
+    if x <= 0:
+      add(result, s[i])
+      inc(i)
+    else:
+      addf(result, by, caps)
+      inc(i, x)
+  add(result, substr(s, i))
+
+proc replace*(s: string, sub: TPeg, by = ""): string {.
+  rtl, extern: "npegs$1".} =
+  ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed
+  ## in `by`.
+  result = ""
+  var i = 0
+  var caps: array[0..MaxSubpatterns-1, string]
+  while i < s.len:
+    var x = matchLen(s, sub, caps, i)
+    if x <= 0:
+      add(result, s[i])
+      inc(i)
+    else:
+      addf(result, by, caps)
+      inc(i, x)
+  add(result, substr(s, i))
+  
+proc parallelReplace*(s: string, subs: varargs[
+                      tuple[pattern: TPeg, repl: string]]): string {.
+                      rtl, extern: "npegs$1".} = 
+  ## Returns a modified copy of `s` with the substitutions in `subs`
+  ## applied in parallel.
+  result = ""
+  var i = 0
+  var caps: array[0..MaxSubpatterns-1, string]
+  while i < s.len:
+    block searchSubs:
+      for j in 0..high(subs):
+        var x = matchLen(s, subs[j][0], caps, i)
+        if x > 0:
+          addf(result, subs[j][1], caps)
+          inc(i, x)
+          break searchSubs
+      add(result, s[i])
+      inc(i)
+  # copy the rest:
+  add(result, substr(s, i))  
+  
+proc transformFile*(infile, outfile: string,
+                    subs: varargs[tuple[pattern: TPeg, repl: string]]) {.
+                    rtl, extern: "npegs$1".} =
+  ## reads in the file `infile`, performs a parallel replacement (calls
+  ## `parallelReplace`) and writes back to `outfile`. Calls ``quit`` if an
+  ## error occurs. This is supposed to be used for quick scripting.
+  var x = readFile(infile)
+  if not isNil(x):
+    var f: File
+    if open(f, outfile, fmWrite):
+      write(f, x.parallelReplace(subs))
+      close(f)
+    else:
+      quit("cannot open for writing: " & outfile)
+  else:
+    quit("cannot open for reading: " & infile)
+  
+iterator split*(s: string, sep: TPeg): string =
+  ## Splits the string `s` into substrings.
+  ##
+  ## Substrings are separated by the PEG `sep`.
+  ## Examples:
+  ##
+  ## .. code-block:: nim
+  ##   for word in split("00232this02939is39an22example111", peg"\d+"):
+  ##     writeln(stdout, word)
+  ##
+  ## Results in:
+  ##
+  ## .. code-block:: nim
+  ##   "this"
+  ##   "is"
+  ##   "an"
+  ##   "example"
+  ##
+  var
+    first = 0
+    last = 0
+  while last < len(s):
+    var x = matchLen(s, sep, last)
+    if x > 0: inc(last, x)
+    first = last
+    while last < len(s):
+      inc(last)
+      x = matchLen(s, sep, last)
+      if x > 0: break
+    if first < last:
+      yield substr(s, first, last-1)
+
+proc split*(s: string, sep: TPeg): seq[string] {.
+  rtl, extern: "npegs$1".} =
+  ## Splits the string `s` into substrings.
+  accumulateResult(split(s, sep))
+
+# ------------------- scanner -------------------------------------------------
+
+type
+  TModifier = enum
+    modNone,
+    modVerbatim,
+    modIgnoreCase,
+    modIgnoreStyle
+  TTokKind = enum       ## enumeration of all tokens
+    tkInvalid,          ## invalid token
+    tkEof,              ## end of file reached
+    tkAny,              ## .
+    tkAnyRune,          ## _
+    tkIdentifier,       ## abc
+    tkStringLit,        ## "abc" or 'abc'
+    tkCharSet,          ## [^A-Z]
+    tkParLe,            ## '('
+    tkParRi,            ## ')'
+    tkCurlyLe,          ## '{'
+    tkCurlyRi,          ## '}'
+    tkCurlyAt,          ## '{@}'
+    tkArrow,            ## '<-'
+    tkBar,              ## '/'
+    tkStar,             ## '*'
+    tkPlus,             ## '+'
+    tkAmp,              ## '&'
+    tkNot,              ## '!'
+    tkOption,           ## '?'
+    tkAt,               ## '@'
+    tkBuiltin,          ## \identifier
+    tkEscaped,          ## \\
+    tkBackref,          ## '$'
+    tkDollar,           ## '$'
+    tkHat               ## '^'
+  
+  TToken {.final.} = object  ## a token
+    kind: TTokKind           ## the type of the token
+    modifier: TModifier
+    literal: string          ## the parsed (string) literal
+    charset: set[char]       ## if kind == tkCharSet
+    index: int               ## if kind == tkBackref
+  
+  TPegLexer {.inheritable.} = object          ## the lexer object.
+    bufpos: int               ## the current position within the buffer
+    buf: cstring              ## the buffer itself
+    lineNumber: int           ## the current line number
+    lineStart: int            ## index of last line start in buffer
+    colOffset: int            ## column to add
+    filename: string
+
+const
+  tokKindToStr: array[TTokKind, string] = [
+    "invalid", "[EOF]", ".", "_", "identifier", "string literal",
+    "character set", "(", ")", "{", "}", "{@}",
+    "<-", "/", "*", "+", "&", "!", "?",
+    "@", "built-in", "escaped", "$", "$", "^"
+  ]
+
+proc HandleCR(L: var TPegLexer, pos: int): int =
+  assert(L.buf[pos] == '\c')
+  inc(L.linenumber)
+  result = pos+1
+  if L.buf[result] == '\L': inc(result)
+  L.lineStart = result
+
+proc HandleLF(L: var TPegLexer, pos: int): int =
+  assert(L.buf[pos] == '\L')
+  inc(L.linenumber)
+  result = pos+1
+  L.lineStart = result
+
+proc init(L: var TPegLexer, input, filename: string, line = 1, col = 0) = 
+  L.buf = input
+  L.bufpos = 0
+  L.lineNumber = line
+  L.colOffset = col
+  L.lineStart = 0
+  L.filename = filename
+
+proc getColumn(L: TPegLexer): int {.inline.} = 
+  result = abs(L.bufpos - L.lineStart) + L.colOffset
+
+proc getLine(L: TPegLexer): int {.inline.} = 
+  result = L.linenumber
+  
+proc errorStr(L: TPegLexer, msg: string, line = -1, col = -1): string =
+  var line = if line < 0: getLine(L) else: line
+  var col = if col < 0: getColumn(L) else: col
+  result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg]
+
+proc handleHexChar(c: var TPegLexer, 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: discard
+
+proc getEscapedChar(c: var TPegLexer, tok: var TToken) = 
+  inc(c.bufpos)
+  case c.buf[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 'x', 'X': 
+    inc(c.bufpos)
+    var xi = 0
+    handleHexChar(c, xi)
+    handleHexChar(c, xi)
+    if xi == 0: tok.kind = tkInvalid
+    else: add(tok.literal, chr(xi))
+  of '0'..'9': 
+    var val = ord(c.buf[c.bufpos]) - ord('0')
+    inc(c.bufpos)
+    var i = 1
+    while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): 
+      val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
+      inc(c.bufpos)
+      inc(i)
+    if val > 0 and val <= 255: add(tok.literal, chr(val))
+    else: tok.kind = tkInvalid
+  of '\0'..'\31':
+    tok.kind = tkInvalid
+  elif c.buf[c.bufpos] in strutils.Letters:
+    tok.kind = tkInvalid
+  else:
+    add(tok.literal, c.buf[c.bufpos])
+    inc(c.bufpos)
+  
+proc skip(c: var TPegLexer) = 
+  var pos = c.bufpos
+  var buf = c.buf
+  while true: 
+    case buf[pos]
+    of ' ', '\t': 
+      inc(pos)
+    of '#':
+      while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
+    of '\c':
+      pos = HandleCR(c, pos)
+      buf = c.buf
+    of '\L': 
+      pos = HandleLF(c, pos)
+      buf = c.buf
+    else: 
+      break                   # EndOfFile also leaves the loop
+  c.bufpos = pos
+  
+proc getString(c: var TPegLexer, tok: var TToken) = 
+  tok.kind = tkStringLit
+  var pos = c.bufPos + 1
+  var buf = c.buf
+  var quote = buf[pos-1]
+  while true: 
+    case buf[pos]
+    of '\\':
+      c.bufpos = pos
+      getEscapedChar(c, tok)
+      pos = c.bufpos
+    of '\c', '\L', '\0':
+      tok.kind = tkInvalid
+      break
+    elif buf[pos] == quote:
+      inc(pos)
+      break      
+    else:
+      add(tok.literal, buf[pos])
+      inc(pos)
+  c.bufpos = pos
+  
+proc getDollar(c: var TPegLexer, tok: var TToken) = 
+  var pos = c.bufPos + 1
+  var buf = c.buf
+  if buf[pos] in {'0'..'9'}:
+    tok.kind = tkBackref
+    tok.index = 0
+    while buf[pos] in {'0'..'9'}:
+      tok.index = tok.index * 10 + ord(buf[pos]) - ord('0')
+      inc(pos)
+  else:
+    tok.kind = tkDollar
+  c.bufpos = pos
+  
+proc getCharSet(c: var TPegLexer, tok: var TToken) = 
+  tok.kind = tkCharSet
+  tok.charset = {}
+  var pos = c.bufPos + 1
+  var buf = c.buf
+  var caret = false
+  if buf[pos] == '^':
+    inc(pos)
+    caret = true
+  while true:
+    var ch: char
+    case buf[pos]
+    of ']':
+      inc(pos)
+      break
+    of '\\':
+      c.bufpos = pos
+      getEscapedChar(c, tok)
+      pos = c.bufpos
+      ch = tok.literal[tok.literal.len-1]
+    of '\C', '\L', '\0':
+      tok.kind = tkInvalid
+      break
+    else: 
+      ch = buf[pos]
+      inc(pos)
+    incl(tok.charset, ch)
+    if buf[pos] == '-':
+      if buf[pos+1] == ']':
+        incl(tok.charset, '-')
+        inc(pos)
+      else:
+        inc(pos)
+        var ch2: char
+        case buf[pos]
+        of '\\':
+          c.bufpos = pos
+          getEscapedChar(c, tok)
+          pos = c.bufpos
+          ch2 = tok.literal[tok.literal.len-1]
+        of '\C', '\L', '\0':
+          tok.kind = tkInvalid
+          break
+        else: 
+          ch2 = buf[pos]
+          inc(pos)
+        for i in ord(ch)+1 .. ord(ch2):
+          incl(tok.charset, chr(i))
+  c.bufpos = pos
+  if caret: tok.charset = {'\1'..'\xFF'} - tok.charset
+  
+proc getSymbol(c: var TPegLexer, tok: var TToken) = 
+  var pos = c.bufpos
+  var buf = c.buf
+  while true: 
+    add(tok.literal, buf[pos])
+    inc(pos)
+    if buf[pos] notin strutils.IdentChars: break
+  c.bufpos = pos
+  tok.kind = tkIdentifier
+
+proc getBuiltin(c: var TPegLexer, tok: var TToken) =
+  if c.buf[c.bufpos+1] in strutils.Letters:
+    inc(c.bufpos)
+    getSymbol(c, tok)
+    tok.kind = tkBuiltin
+  else:
+    tok.kind = tkEscaped
+    getEscapedChar(c, tok) # may set tok.kind to tkInvalid
+
+proc getTok(c: var TPegLexer, tok: var TToken) = 
+  tok.kind = tkInvalid
+  tok.modifier = modNone
+  setlen(tok.literal, 0)
+  skip(c)
+  case c.buf[c.bufpos]
+  of '{':
+    inc(c.bufpos)
+    if c.buf[c.bufpos] == '@' and c.buf[c.bufpos+1] == '}':
+      tok.kind = tkCurlyAt
+      inc(c.bufpos, 2)
+      add(tok.literal, "{@}")
+    else:
+      tok.kind = tkCurlyLe
+      add(tok.literal, '{')
+  of '}': 
+    tok.kind = tkCurlyRi
+    inc(c.bufpos)
+    add(tok.literal, '}')
+  of '[': 
+    getCharset(c, tok)
+  of '(':
+    tok.kind = tkParLe
+    inc(c.bufpos)
+    add(tok.literal, '(')
+  of ')':
+    tok.kind = tkParRi
+    inc(c.bufpos)
+    add(tok.literal, ')')
+  of '.': 
+    tok.kind = tkAny
+    inc(c.bufpos)
+    add(tok.literal, '.')
+  of '_':
+    tok.kind = tkAnyRune
+    inc(c.bufpos)
+    add(tok.literal, '_')
+  of '\\': 
+    getBuiltin(c, tok)
+  of '\'', '"': getString(c, tok)
+  of '$': getDollar(c, tok)
+  of '\0': 
+    tok.kind = tkEof
+    tok.literal = "[EOF]"
+  of 'a'..'z', 'A'..'Z', '\128'..'\255':
+    getSymbol(c, tok)
+    if c.buf[c.bufpos] in {'\'', '"'} or 
+        c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}:
+      case tok.literal
+      of "i": tok.modifier = modIgnoreCase
+      of "y": tok.modifier = modIgnoreStyle
+      of "v": tok.modifier = modVerbatim
+      else: discard
+      setLen(tok.literal, 0)
+      if c.buf[c.bufpos] == '$':
+        getDollar(c, tok)
+      else:
+        getString(c, tok)
+      if tok.modifier == modNone: tok.kind = tkInvalid
+  of '+':
+    tok.kind = tkPlus
+    inc(c.bufpos)
+    add(tok.literal, '+')
+  of '*':
+    tok.kind = tkStar
+    inc(c.bufpos)
+    add(tok.literal, '+')
+  of '<':
+    if c.buf[c.bufpos+1] == '-':
+      inc(c.bufpos, 2)
+      tok.kind = tkArrow
+      add(tok.literal, "<-")
+    else:
+      add(tok.literal, '<')
+  of '/':
+    tok.kind = tkBar
+    inc(c.bufpos)
+    add(tok.literal, '/')
+  of '?':
+    tok.kind = tkOption
+    inc(c.bufpos)
+    add(tok.literal, '?')
+  of '!':
+    tok.kind = tkNot
+    inc(c.bufpos)
+    add(tok.literal, '!')
+  of '&':
+    tok.kind = tkAmp
+    inc(c.bufpos)
+    add(tok.literal, '!')
+  of '@':
+    tok.kind = tkAt
+    inc(c.bufpos)
+    add(tok.literal, '@')
+    if c.buf[c.bufpos] == '@': 
+      tok.kind = tkCurlyAt
+      inc(c.bufpos)
+      add(tok.literal, '@')
+  of '^':
+    tok.kind = tkHat
+    inc(c.bufpos)
+    add(tok.literal, '^')
+  else:
+    add(tok.literal, c.buf[c.bufpos])
+    inc(c.bufpos)
+
+proc arrowIsNextTok(c: TPegLexer): bool =
+  # the only look ahead we need
+  var pos = c.bufpos
+  while c.buf[pos] in {'\t', ' '}: inc(pos)
+  result = c.buf[pos] == '<' and c.buf[pos+1] == '-'
+
+# ----------------------------- parser ----------------------------------------
+    
+type
+  EInvalidPeg* = object of ValueError ## raised if an invalid
+                                      ## PEG has been detected
+  TPegParser = object of TPegLexer ## the PEG parser object
+    tok: TToken
+    nonterms: seq[PNonTerminal]
+    modifier: TModifier
+    captures: int
+    identIsVerbatim: bool
+    skip: TPeg
+
+proc pegError(p: TPegParser, msg: string, line = -1, col = -1) =
+  var e: ref EInvalidPeg
+  new(e)
+  e.msg = errorStr(p, msg, line, col)
+  raise e
+
+proc getTok(p: var TPegParser) = 
+  getTok(p, p.tok)
+  if p.tok.kind == tkInvalid: pegError(p, "invalid token")
+
+proc eat(p: var TPegParser, kind: TTokKind) =
+  if p.tok.kind == kind: getTok(p)
+  else: pegError(p, tokKindToStr[kind] & " expected")
+
+proc parseExpr(p: var TPegParser): TPeg
+
+proc getNonTerminal(p: var TPegParser, name: string): PNonTerminal =
+  for i in 0..high(p.nonterms):
+    result = p.nonterms[i]
+    if cmpIgnoreStyle(result.name, name) == 0: return
+  # forward reference:
+  result = newNonTerminal(name, getLine(p), getColumn(p))
+  add(p.nonterms, result)
+
+proc modifiedTerm(s: string, m: TModifier): TPeg =
+  case m
+  of modNone, modVerbatim: result = term(s)
+  of modIgnoreCase: result = termIgnoreCase(s)
+  of modIgnoreStyle: result = termIgnoreStyle(s)
+
+proc modifiedBackref(s: int, m: TModifier): TPeg =
+  case m
+  of modNone, modVerbatim: result = backRef(s)
+  of modIgnoreCase: result = backRefIgnoreCase(s)
+  of modIgnoreStyle: result = backRefIgnoreStyle(s)
+
+proc builtin(p: var TPegParser): TPeg =
+  # do not use "y", "skip" or "i" as these would be ambiguous
+  case p.tok.literal
+  of "n": result = newLine()
+  of "d": result = charset({'0'..'9'})
+  of "D": result = charset({'\1'..'\xff'} - {'0'..'9'})
+  of "s": result = charset({' ', '\9'..'\13'})
+  of "S": result = charset({'\1'..'\xff'} - {' ', '\9'..'\13'})
+  of "w": result = charset({'a'..'z', 'A'..'Z', '_', '0'..'9'})
+  of "W": result = charset({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
+  of "a": result = charset({'a'..'z', 'A'..'Z'})
+  of "A": result = charset({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
+  of "ident": result = tpegs.ident
+  of "letter": result = UnicodeLetter()
+  of "upper": result = UnicodeUpper()
+  of "lower": result = UnicodeLower()
+  of "title": result = UnicodeTitle()
+  of "white": result = UnicodeWhitespace()
+  else: pegError(p, "unknown built-in: " & p.tok.literal)
+
+proc token(terminal: TPeg, p: TPegParser): TPeg = 
+  if p.skip.kind == pkEmpty: result = terminal
+  else: result = sequence(p.skip, terminal)
+
+proc primary(p: var TPegParser): TPeg =
+  case p.tok.kind
+  of tkAmp:
+    getTok(p)
+    return &primary(p)
+  of tkNot:
+    getTok(p)
+    return !primary(p)
+  of tkAt:
+    getTok(p)
+    return !*primary(p)
+  of tkCurlyAt:
+    getTok(p)
+    return !*\primary(p).token(p)
+  else: discard
+  case p.tok.kind
+  of tkIdentifier:
+    if p.identIsVerbatim: 
+      var m = p.tok.modifier
+      if m == modNone: m = p.modifier
+      result = modifiedTerm(p.tok.literal, m).token(p)
+      getTok(p)
+    elif not arrowIsNextTok(p):
+      var nt = getNonTerminal(p, p.tok.literal)
+      incl(nt.flags, ntUsed)
+      result = nonTerminal(nt).token(p)
+      getTok(p)
+    else:
+      pegError(p, "expression expected, but found: " & p.tok.literal)
+  of tkStringLit:
+    var m = p.tok.modifier
+    if m == modNone: m = p.modifier
+    result = modifiedTerm(p.tok.literal, m).token(p)
+    getTok(p)
+  of tkCharSet:
+    if '\0' in p.tok.charset:
+      pegError(p, "binary zero ('\\0') not allowed in character class")
+    result = charset(p.tok.charset).token(p)
+    getTok(p)
+  of tkParLe:
+    getTok(p)
+    result = parseExpr(p)
+    eat(p, tkParRi)
+  of tkCurlyLe:
+    getTok(p)
+    result = capture(parseExpr(p)).token(p)
+    eat(p, tkCurlyRi)
+    inc(p.captures)
+  of tkAny:
+    result = any().token(p)
+    getTok(p)
+  of tkAnyRune:
+    result = anyRune().token(p)
+    getTok(p)
+  of tkBuiltin:
+    result = builtin(p).token(p)
+    getTok(p)
+  of tkEscaped:
+    result = term(p.tok.literal[0]).token(p)
+    getTok(p)
+  of tkDollar: 
+    result = endAnchor()
+    getTok(p)
+  of tkHat: 
+    result = startAnchor()
+    getTok(p)
+  of tkBackref:
+    var m = p.tok.modifier
+    if m == modNone: m = p.modifier
+    result = modifiedBackRef(p.tok.index, m).token(p)
+    if p.tok.index < 0 or p.tok.index > p.captures: 
+      pegError(p, "invalid back reference index: " & $p.tok.index)
+    getTok(p)
+  else:
+    pegError(p, "expression expected, but found: " & p.tok.literal)
+    getTok(p) # we must consume a token here to prevent endless loops!
+  while true:
+    case p.tok.kind
+    of tkOption:
+      result = ?result
+      getTok(p)
+    of tkStar:
+      result = *result
+      getTok(p)
+    of tkPlus:
+      result = +result
+      getTok(p)
+    else: break
+
+proc seqExpr(p: var TPegParser): TPeg =
+  result = primary(p)
+  while true:
+    case p.tok.kind
+    of tkAmp, tkNot, tkAt, tkStringLit, tkCharset, tkParLe, tkCurlyLe,
+       tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, 
+       tkHat, tkCurlyAt:
+      result = sequence(result, primary(p))
+    of tkIdentifier:
+      if not arrowIsNextTok(p):
+        result = sequence(result, primary(p))
+      else: break
+    else: break
+
+proc parseExpr(p: var TPegParser): TPeg =
+  result = seqExpr(p)
+  while p.tok.kind == tkBar:
+    getTok(p)
+    result = result / seqExpr(p)
+  
+proc parseRule(p: var TPegParser): PNonTerminal =
+  if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
+    result = getNonTerminal(p, p.tok.literal)
+    if ntDeclared in result.flags:
+      pegError(p, "attempt to redefine: " & result.name)
+    result.line = getLine(p)
+    result.col = getColumn(p)
+    getTok(p)
+    eat(p, tkArrow)
+    result.rule = parseExpr(p)
+    incl(result.flags, ntDeclared) # NOW inlining may be attempted
+  else:
+    pegError(p, "rule expected, but found: " & p.tok.literal)
+  
+proc rawParse(p: var TPegParser): TPeg =
+  ## parses a rule or a PEG expression
+  while p.tok.kind == tkBuiltin:
+    case p.tok.literal
+    of "i":
+      p.modifier = modIgnoreCase
+      getTok(p)
+    of "y":
+      p.modifier = modIgnoreStyle
+      getTok(p)
+    of "skip":
+      getTok(p)
+      p.skip = ?primary(p)
+    else: break
+  if p.tok.kind == tkIdentifier and arrowIsNextTok(p):
+    result = parseRule(p).rule
+    while p.tok.kind != tkEof:
+      discard parseRule(p)
+  else:
+    p.identIsVerbatim = true
+    result = parseExpr(p)
+  if p.tok.kind != tkEof:
+    pegError(p, "EOF expected, but found: " & p.tok.literal)
+  for i in 0..high(p.nonterms):
+    var nt = p.nonterms[i]
+    if ntDeclared notin nt.flags:
+      pegError(p, "undeclared identifier: " & nt.name, nt.line, nt.col)
+    elif ntUsed notin nt.flags and i > 0:
+      pegError(p, "unused rule: " & nt.name, nt.line, nt.col)
+
+proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg =
+  ## constructs a TPeg object from `pattern`. `filename`, `line`, `col` are
+  ## used for error messages, but they only provide start offsets. `parsePeg`
+  ## keeps track of line and column numbers within `pattern`.
+  var p: TPegParser
+  init(TPegLexer(p), pattern, filename, line, col)
+  p.tok.kind = tkInvalid
+  p.tok.modifier = modNone
+  p.tok.literal = ""
+  p.tok.charset = {}
+  p.nonterms = @[]
+  p.identIsVerbatim = false
+  getTok(p)
+  result = rawParse(p)
+
+proc peg*(pattern: string): TPeg =
+  ## constructs a TPeg object from the `pattern`. The short name has been
+  ## chosen to encourage its use as a raw string modifier::
+  ##
+  ##   peg"{\ident} \s* '=' \s* {.*}"
+  result = parsePeg(pattern, "pattern")
+
+proc escapePeg*(s: string): string = 
+  ## escapes `s` so that it is matched verbatim when used as a peg.
+  result = ""
+  var inQuote = false
+  for c in items(s):  
+    case c
+    of '\0'..'\31', '\'', '"', '\\': 
+      if inQuote: 
+        result.add('\'')
+        inQuote = false
+      result.add("\\x")
+      result.add(toHex(ord(c), 2))
+    else:
+      if not inQuote: 
+        result.add('\'')
+        inQuote = true
+      result.add(c)
+  if inQuote: result.add('\'')
+
+when isMainModule:
+  doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
+  #doAssert match("(a b c)", peg"'(' @ ')'")
+  doAssert match("W_HI_Le", peg"\y 'while'")
+  doAssert(not match("W_HI_L", peg"\y 'while'"))
+  doAssert(not match("W_HI_Le", peg"\y v'while'"))
+  doAssert match("W_HI_Le", peg"y'while'")
+  
+  doAssert($ +digits == $peg"\d+")
+  doAssert "0158787".match(peg"\d+")
+  doAssert "ABC 0232".match(peg"\w+\s+\d+")
+  doAssert "ABC".match(peg"\d+ / \w+")
+
+  for word in split("00232this02939is39an22example111", peg"\d+"):
+    writeln(stdout, word)
+
+  doAssert matchLen("key", ident) == 3
+
+  var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
+  doAssert matchLen("key1=  cal9", pattern) == 11
+  
+  var ws = newNonTerminal("ws", 1, 1)
+  ws.rule = *whitespace
+  
+  var expr = newNonTerminal("expr", 1, 1)
+  expr.rule = sequence(capture(ident), *sequence(
+                nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
+  
+  var c: TCaptures
+  var s = "a+b +  c +d+e+f"
+  doAssert rawMatch(s, expr.rule, 0, c) == len(s)
+  var a = ""
+  for i in 0..c.ml-1:
+    a.add(substr(s, c.matches[i][0], c.matches[i][1]))
+  doAssert a == "abcdef"
+  #echo expr.rule
+
+  #const filename = "lib/devel/peg/grammar.txt"
+  #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
+  #echo "a <- [abc]*?".match(grammar)
+  doAssert find("_____abc_______", term("abc"), 2) == 5
+  doAssert match("_______ana", peg"A <- 'ana' / . A")
+  doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
+
+  if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
+    doAssert matches[0] == "abc"
+  else:
+    doAssert false
+  
+  var g2 = peg"""S <- A B / C D
+                 A <- 'a'+
+                 B <- 'b'+
+                 C <- 'c'+
+                 D <- 'd'+
+              """
+  doAssert($g2 == "((A B) / (C D))")
+  doAssert match("cccccdddddd", g2)
+  doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+         "var1<-keykey; var2<-key2key2")
+  doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
+
+  if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
+    doAssert matches[0] == "a"
+  else:
+    doAssert false
+  
+  block:
+    var matches: array[0..2, string]
+    if match("abcdefg", peg"c {d} ef {g}", matches, 2): 
+      doAssert matches[0] == "d"
+      doAssert matches[1] == "g"
+    else:
+      doAssert false
+
+  for x in findAll("abcdef", peg"{.}", 3):
+    echo x
+    
+  if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
+    doAssert matches[0] == "f"
+    doAssert matches[1] == "a, b"
+  else:
+    doAssert false
+  
+  doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
+  # ß is not a lower cased letter?!
+  doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
+  doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
+  doAssert(not match("456678", peg"(\letter)+"))
+
+  doAssert("var1 = key; var2 = key2".replacef(
+    peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
+         "var1<-keykey;var2<-key2key2")
+
+  doAssert match("prefix/start", peg"^start$", 7)
+  
+  # tricky test to check for false aliasing:
+  block:
+    var a = term"key"
+    echo($sequence(sequence(a, term"value"), *a))
+
diff --git a/tests/stdlib/tpermutations.nim b/tests/stdlib/tpermutations.nim
new file mode 100644
index 000000000..a6e07ded6
--- /dev/null
+++ b/tests/stdlib/tpermutations.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''@[0, 2, 1]
+@[1, 0, 2]
+@[1, 2, 0]
+@[2, 0, 1]
+@[2, 1, 0]
+@[2, 0, 1]
+@[1, 2, 0]
+@[1, 0, 2]
+@[0, 2, 1]
+@[0, 1, 2]'''
+"""
+import algorithm
+
+var v = @[0, 1, 2]
+while v.nextPermutation():
+  echo v
+while v.prevPermutation():
+  echo v
diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim
new file mode 100644
index 000000000..bf0b49586
--- /dev/null
+++ b/tests/stdlib/tposix.nim
@@ -0,0 +1,16 @@
+# Test Posix interface
+
+when not defined(windows):
+
+  import posix
+
+  var
+    u: Tutsname
+
+  discard uname(u)
+
+  writeln(stdout, u.sysname)
+  writeln(stdout, u.nodename)
+  writeln(stdout, u.release)
+  writeln(stdout, u.machine)
+
diff --git a/tests/stdlib/tquit.nim b/tests/stdlib/tquit.nim
new file mode 100644
index 000000000..d4dc1522d
--- /dev/null
+++ b/tests/stdlib/tquit.nim
@@ -0,0 +1,6 @@
+# Test the new beforeQuit variable: 

+

+proc myExit() {.noconv.} = 

+  write(stdout, "just exiting...\n")

+

+addQuitProc(myExit)

diff --git a/tests/stdlib/tregex.nim b/tests/stdlib/tregex.nim
new file mode 100644
index 000000000..bb4695f02
--- /dev/null
+++ b/tests/stdlib/tregex.nim
@@ -0,0 +1,31 @@
+discard """
+  file: "tregex.nim"
+  output: "key: keyAYes!"
+"""
+# Test the new regular expression module

+# which is based on the PCRE library

+
+when defined(powerpc64):
+  # cheat as our powerpc test machine has no PCRE installed:
+  echo "key: keyAYes!"
+
+else:

+  import

+    re

+

+  if "keyA = valueA" =~ re"\s*(\w+)\s*\=\s*(\w+)":

+    write(stdout, "key: ", matches[0])

+  elif "# comment!" =~ re.re"\s*(\#.*)": 

+    # test re.re"" syntax

+    echo("comment: ", matches[0])

+  else: 

+    echo("Bug!")

+

+  if "Username".match(re"[A-Za-z]+"):

+    echo("Yes!")

+  else:

+    echo("Bug!")

+

+  #OUT key: keyAYes!

+
+
diff --git a/tests/stdlib/treguse.nim b/tests/stdlib/treguse.nim
new file mode 100644
index 000000000..a610ad725
--- /dev/null
+++ b/tests/stdlib/treguse.nim
@@ -0,0 +1,27 @@
+discard """
+  file: "treguse.nim"
+  output: "055this should be the casehugh"
+"""
+# Test the register usage of the virtual machine and

+# the blocks in var statements

+

+proc main(a, b: int) =

+  var x = 0

+  write(stdout, x)

+  if x == 0:

+    var y = 55

+    write(stdout, y)

+    write(stdout, "this should be the case")

+    var input = "<no input>"

+    if input == "Andreas":

+      write(stdout, "wow")

+    else:

+      write(stdout, "hugh")

+  else:

+    var z = 66

+    write(stdout, z) # "bug!")

+

+main(45, 1000)

+#OUT 055this should be the casehugh

+
+
diff --git a/tests/stdlib/treloop.nim b/tests/stdlib/treloop.nim
new file mode 100644
index 000000000..35236708c
--- /dev/null
+++ b/tests/stdlib/treloop.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "@[(, +,  1,  2, )]"
+"""
+
+import re
+
+let str = "(+ 1 2)"
+var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
+echo str.findAll(tokenRE)
diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim
new file mode 100644
index 000000000..41c830621
--- /dev/null
+++ b/tests/stdlib/trepr.nim
@@ -0,0 +1,29 @@
+discard """
+  file: "trepr.nim"
+  output: "{a, b}{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}"
+"""
+
+type
+  TEnum = enum
+    a, b
+    
+var val = {a, b}
+stdout.write(repr(val))
+stdout.writeln(repr({'a'..'z', 'A'..'Z'}))
+
+type
+  TObj {.pure, inheritable.} = object
+    data: int
+  TFoo = ref object of TObj
+    d2: float
+var foo: TFoo
+new(foo)
+
+when false:
+  # cannot capture this output as it contains a memory address :-/
+  echo foo.repr
+#var testseq: seq[string] = @[
+#  "a", "b", "c", "d", "e"
+#]
+#echo(repr(testseq))
+
diff --git a/tests/stdlib/trepr2.nim b/tests/stdlib/trepr2.nim
new file mode 100644
index 000000000..b15081e48
--- /dev/null
+++ b/tests/stdlib/trepr2.nim
@@ -0,0 +1,32 @@
+# test the new "repr" built-in proc

+

+type

+  TEnum = enum

+    en1, en2, en3, en4, en5, en6

+

+  TPoint {.final.} = object

+    x, y, z: int

+    s: array [0..1, string]

+    e: TEnum

+

+var

+  p: TPoint

+  q: ref TPoint

+  s: seq[ref TPoint]

+

+p.x = 0

+p.y = 13

+p.z = 45

+p.s[0] = "abc"

+p.s[1] = "xyz"

+p.e = en6

+

+new(q)

+q[] = p

+

+s = @[q, q, q, q]

+

+writeln(stdout, repr(p))

+writeln(stdout, repr(q))

+writeln(stdout, repr(s))

+writeln(stdout, repr(en4))

diff --git a/tests/stdlib/tsinglylinkedring.nim b/tests/stdlib/tsinglylinkedring.nim
new file mode 100644
index 000000000..93f0c69cd
--- /dev/null
+++ b/tests/stdlib/tsinglylinkedring.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''[5]
+[4, 5]
+[3, 4, 5]
+[2, 3, 4, 5]
+[2, 3, 4, 5, 6]
+[2, 3, 4, 5, 6, 7]
+[2, 3, 4, 5, 6, 7, 8]
+[1, 2, 3, 4, 5, 6, 7, 8]'''
+"""
+import lists
+
+var r = initSinglyLinkedRing[int]()
+r.prepend(5)
+echo r
+r.prepend(4)
+echo r
+r.prepend(3)
+echo r
+r.prepend(2)
+echo r
+r.append(6)
+echo r
+r.append(7)
+echo r
+r.append(8)
+echo r
+r.prepend(1)
+echo r
diff --git a/tests/stdlib/tsortcall.nim b/tests/stdlib/tsortcall.nim
new file mode 100644
index 000000000..efe1d0b8b
--- /dev/null
+++ b/tests/stdlib/tsortcall.nim
@@ -0,0 +1,5 @@
+import algorithm
+
+proc foosort(ships: var seq[int]) = sort(ships, system.cmp[int])
+
+
diff --git a/tests/stdlib/tsplit.nim b/tests/stdlib/tsplit.nim
new file mode 100644
index 000000000..25bad33e2
--- /dev/null
+++ b/tests/stdlib/tsplit.nim
@@ -0,0 +1,20 @@
+discard """
+  file: "tsplit.nim"
+  output: "true"
+"""
+import strutils
+
+var s = ""
+for w in split("|abc|xy|z", {'|'}):
+  s.add("#")
+  s.add(w)
+
+if s == "#abc#xy#z":
+  echo "true"
+else:
+  echo "false"
+  
+#OUT true
+
+
+
diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim
new file mode 100644
index 000000000..640565a27
--- /dev/null
+++ b/tests/stdlib/tstreams.nim
@@ -0,0 +1,7 @@
+import streams
+
+var outp = newFileStream(stdout)
+var inp = newFileStream(stdin)
+write(outp, "Hello! What is your name?")
+var line = readLine(inp)
+write(outp, "Nice name: " & line)
diff --git a/tests/stdlib/tstrset.nim b/tests/stdlib/tstrset.nim
new file mode 100644
index 000000000..9cdb5ed35
--- /dev/null
+++ b/tests/stdlib/tstrset.nim
@@ -0,0 +1,74 @@
+# test a simple yet highly efficient set of strings
+
+type
+  TRadixNodeKind = enum rnLinear, rnFull, rnLeaf
+  PRadixNode = ref TRadixNode
+  TRadixNode = object {.inheritable.}
+    kind: TRadixNodeKind
+  TRadixNodeLinear = object of TRadixNode
+    len: int8
+    keys: array [0..31, char]
+    vals: array [0..31, PRadixNode]  
+  TRadixNodeFull = object of TRadixNode
+    b: array [char, PRadixNode]
+  TRadixNodeLeaf = object of TRadixNode
+    s: string
+  PRadixNodeLinear = ref TRadixNodeLinear
+  PRadixNodeFull = ref TRadixNodeFull
+  PRadixNodeLeaf = ref TRadixNodeLeaf
+    
+proc search(r: PRadixNode, s: string): PRadixNode =
+  var r = r
+  var i = 0
+  while r != nil:
+    case r.kind
+    of rnLinear:
+      var x = PRadixNodeLinear(r)
+      for j in 0..ze(x.len)-1:
+        if x.keys[j] == s[i]:
+          if s[i] == '\0': return r
+          r = x.vals[j]
+          inc(i)
+          break
+      break # character not found
+    of rnFull:
+      var x = PRadixNodeFull(r)
+      var y = x.b[s[i]]
+      if s[i] == '\0':
+        return if y != nil: r else: nil
+      r = y
+      inc(i)
+    of rnLeaf:
+      var x = PRadixNodeLeaf(r)
+      var j = 0
+      while true:
+        if x.s[j] != s[i]: return nil
+        if s[i] == '\0': return r
+        inc(j)
+        inc(i)
+
+proc contains*(r: PRadixNode, s: string): bool =
+  return search(r, s) != nil
+
+proc testOrincl*(r: var PRadixNode, s: string): bool =
+  nil
+    
+proc incl*(r: var PRadixNode, s: string) = discard testOrIncl(r, s)
+
+proc excl*(r: var PRadixNode, s: string) =
+  var x = search(r, s)
+  if x == nil: return
+  case x.kind
+  of rnLeaf: PRadixNodeLeaf(x).s = ""
+  of rnFull: PRadixNodeFull(x).b['\0'] = nil
+  of rnLinear:
+    var x = PRadixNodeLinear(x)
+    for i in 0..ze(x.len)-1:
+      if x.keys[i] == '\0':
+        swap(x.keys[i], x.keys[ze(x.len)-1])
+        dec(x.len)
+        break
+
+var
+  root: PRadixNode
+
diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim
new file mode 100644
index 000000000..251ec77ef
--- /dev/null
+++ b/tests/stdlib/tstrtabs.nim
@@ -0,0 +1,12 @@
+import strtabs
+
+var tab = newStringTable({"key1": "val1", "key2": "val2"}, 
+                         modeStyleInsensitive)
+for i in 0..80:
+  tab["key_" & $i] = "value" & $i
+  
+for key, val in pairs(tab):
+  writeln(stdout, key, ": ", val)
+writeln(stdout, "length of table ", $tab.len)
+
+writeln(stdout, `%`("$key1 = $key2; ${PATH}", tab, {useEnvironment}))
diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim
new file mode 100644
index 000000000..3db484faa
--- /dev/null
+++ b/tests/stdlib/tstrutil.nim
@@ -0,0 +1,58 @@
+discard """
+  file: "tstrutil.nim"
+  output: "ha/home/a1xyz/usr/bin"
+"""
+# test the new strutils module
+
+import
+  strutils
+
+proc testStrip() =
+  write(stdout, strip("  ha  "))
+
+proc main() = 
+  testStrip()
+  for p in split("/home/a1:xyz:/usr/bin", {':'}):
+    write(stdout, p)
+
+proc testDelete = 
+  var s = "0123456789ABCDEFGH"
+  delete(s, 4, 5)
+  assert s == "01236789ABCDEFGH"
+  delete(s, s.len-1, s.len-1)
+  assert s == "01236789ABCDEFG"
+  delete(s, 0, 0)
+  assert s == "1236789ABCDEFG"
+
+testDelete()  
+    
+assert(insertSep($1000_000) == "1_000_000")
+assert(insertSep($232) == "232")
+assert(insertSep($12345, ',') == "12,345")
+assert(insertSep($0) == "0")
+
+assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)
+assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)
+assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)
+assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)
+assert(editDistance("prefix__hallo_suffix", "prefix") == 14)
+assert(editDistance("prefix__hallo_suffix", "suffix") == 14)
+assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)
+
+assert "/1/2/3".rfind('/') == 4
+assert "/1/2/3".rfind('/', 1) == 0
+assert "/1/2/3".rfind('0') == -1
+
+assert(toHex(100i16, 32) == "00000000000000000000000000000064")
+assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C")
+
+assert(' '.repeat(8)== "        ")
+assert(" ".repeat(8) == "        ")
+assert(spaces(8) == "        ")
+
+assert(' '.repeat(0) == "")
+assert(" ".repeat(0) == "")
+assert(spaces(0) == "")
+
+main()
+#OUT ha/home/a1xyz/usr/bin
diff --git a/tests/stdlib/ttime.nim b/tests/stdlib/ttime.nim
new file mode 100644
index 000000000..bad818816
--- /dev/null
+++ b/tests/stdlib/ttime.nim
@@ -0,0 +1,6 @@
+# test the new time module

+

+import

+  times

+

+write(stdout, $getTime())

diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim
new file mode 100644
index 000000000..689453c76
--- /dev/null
+++ b/tests/stdlib/tunidecode.nim
@@ -0,0 +1,12 @@
+discard """
+  cmd: "nim $target --hints:on -d:embedUnidecodeTable $options $file"
+  output: "Ausserst"
+"""
+
+import unidecode
+
+loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
+
+#assert unidecode("\x53\x17\x4E\xB0") == "Bei Jing"
+echo unidecode("Äußerst")
+
diff --git a/tests/stdlib/twalker.nim b/tests/stdlib/twalker.nim
new file mode 100644
index 000000000..89e6c2b9d
--- /dev/null
+++ b/tests/stdlib/twalker.nim
@@ -0,0 +1,13 @@
+# iterate over all files with a given filter:

+

+import

+  "../../lib/pure/os.nim", ../../ lib / pure / times

+

+proc main(filter: string) =

+  for filename in walkFiles(filter):

+    writeln(stdout, filename)

+

+  for key, val in envPairs():

+    writeln(stdout, key & '=' & val)

+

+main("*.nim")

diff --git a/tests/stdlib/txmlgen.nim b/tests/stdlib/txmlgen.nim
new file mode 100644
index 000000000..fa1dffe56
--- /dev/null
+++ b/tests/stdlib/txmlgen.nim
@@ -0,0 +1,12 @@
+discard """
+  file: "txmlgen.nim"
+  output: "<h1><a href=\"http://force7.de/nim\">Nim</a></h1>"
+"""
+import htmlgen
+
+var nim = "Nim"
+echo h1(a(href="http://force7.de/nim", nim))
+
+
+
+
diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim
new file mode 100644
index 000000000..bfe2dc94a
--- /dev/null
+++ b/tests/stdlib/txmltree.nim
@@ -0,0 +1,13 @@
+discard """
+  file: "txmltree.nim"
+  output: "true"
+"""
+
+import xmltree, strtabs
+
+var x = <>a(href="nim.de", newText("www.nim-test.de"))
+
+echo($x == "<a href=\"nim.de\">www.nim-test.de</a>")
+
+
+
diff --git a/tests/system/alloc.nim b/tests/system/alloc.nim
new file mode 100644
index 000000000..7abefec2a
--- /dev/null
+++ b/tests/system/alloc.nim
@@ -0,0 +1,52 @@
+var x: ptr int
+
+x = cast[ptr int](alloc(7))
+assert x != nil
+x = cast[ptr int](x.realloc(2))
+assert x != nil
+x.dealloc()
+
+x = createU(int, 3)
+assert x != nil
+x.free()
+
+x = create(int, 4)
+assert cast[ptr array[4, int]](x)[0] == 0
+assert cast[ptr array[4, int]](x)[1] == 0
+assert cast[ptr array[4, int]](x)[2] == 0
+assert cast[ptr array[4, int]](x)[3] == 0
+
+x = x.resize(4)
+assert x != nil
+x.free()
+
+x = cast[ptr int](allocShared(100))
+assert x != nil
+deallocShared(x)
+
+x = createSharedU(int, 3)
+assert x != nil
+x.freeShared()
+
+x = createShared(int, 3)
+assert x != nil
+assert cast[ptr array[3, int]](x)[0] == 0
+assert cast[ptr array[3, int]](x)[1] == 0
+assert cast[ptr array[3, int]](x)[2] == 0
+
+assert x != nil
+x = cast[ptr int](x.resizeShared(2))
+assert x != nil
+x.freeShared()
+
+x = create(int, 10)
+assert x != nil
+x = x.resize(12)
+assert x != nil
+x.dealloc()
+
+x = createShared(int, 1)
+assert x != nil
+x = x.resizeShared(1)
+assert x != nil
+x.freeShared()
diff --git a/tests/system/helpers/readall_echo.nim b/tests/system/helpers/readall_echo.nim
new file mode 100644
index 000000000..79937bf6f
--- /dev/null
+++ b/tests/system/helpers/readall_echo.nim
@@ -0,0 +1,2 @@
+when isMainModule:
+  echo(stdin.readAll)
diff --git a/tests/system/io.nim b/tests/system/io.nim
new file mode 100644
index 000000000..ec9a1ed70
--- /dev/null
+++ b/tests/system/io.nim
@@ -0,0 +1,25 @@
+import
+  unittest, osproc, streams, os
+const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+const TEST_FILE = "tests/testdata/string.txt"
+
+proc echoLoop(str: string): string =
+  result = ""
+  var process = startProcess(findExe("tests/system/helpers/readall_echo"))
+  var input = process.inputStream
+  input.write(str)
+  input.close()
+  var output = process.outputStream
+  discard process.waitForExit
+  while not output.atEnd:
+    result.add(output.readLine)
+    
+suite "io":
+  suite "readAll":
+    test "stdin":
+      check:
+        echoLoop(STRING_DATA) == STRING_DATA
+        echoLoop(STRING_DATA[0..3999]) == STRING_DATA[0..3999]
+    test "file":
+      check:
+        readFile(TEST_FILE) == STRING_DATA
diff --git a/tests/system/params.nim b/tests/system/params.nim
new file mode 100644
index 000000000..1358212f2
--- /dev/null
+++ b/tests/system/params.nim
@@ -0,0 +1,18 @@
+import os
+import osproc
+import parseopt2
+import sequtils
+
+let argv = commandLineParams()
+
+if argv == @[]:
+  # this won't work with spaces
+  assert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0
+else:
+  let f = toSeq(getopt())
+  echo f.repr
+  assert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
+  assert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a"
+  assert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d"
+  assert f[3].kind == cmdLongOption and f[3].key == "ab" and f[3].val == ""
+  assert f[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == ""
diff --git a/tests/system/tfloatToString.nim b/tests/system/tfloatToString.nim
new file mode 100644
index 000000000..bb45a91d7
--- /dev/null
+++ b/tests/system/tfloatToString.nim
@@ -0,0 +1,22 @@
+discard """
+  output:'''2.3242
+2.982
+123912.1
+123912.1823
+5.0
+1e+100
+inf
+-inf
+nan
+'''
+"""
+
+echo($(2.3242))
+echo($(2.982))
+echo($(123912.1))
+echo($(123912.1823))
+echo($(5.0))
+echo($(1e100))
+echo($(1e1000000))
+echo($(-1e1000000))
+echo($(0.0/0.0))
diff --git a/tests/system/toString.nim b/tests/system/toString.nim
new file mode 100644
index 000000000..52e7a4b92
--- /dev/null
+++ b/tests/system/toString.nim
@@ -0,0 +1,9 @@
+discard """
+  output:'''@[23, 45]
+@[, foo, bar]'''
+"""
+
+echo($(@[23, 45]))
+echo($(@["", "foo", "bar"]))
+#echo($(["", "foo", "bar"]))
+#echo($([23, 45]))
diff --git a/tests/system/tsettostring.nim b/tests/system/tsettostring.nim
new file mode 100644
index 000000000..c6846ee99
--- /dev/null
+++ b/tests/system/tsettostring.nim
@@ -0,0 +1,8 @@
+discard """
+  output: "{a, b, c}"
+"""
+
+# bug #2395
+
+let alphaSet: set[char] = {'a'..'c'}
+echo alphaSet
diff --git a/tests/template/annotate.nim b/tests/template/annotate.nim
new file mode 100644
index 000000000..fa58030dc
--- /dev/null
+++ b/tests/template/annotate.nim
@@ -0,0 +1,113 @@
+import macros, parseutils
+
+# Generate tags
+macro make(names: openarray[expr]): stmt {.immediate.} =
+    result = newStmtList()
+
+    for i in 0 .. names.len-1:
+        result.add newProc(
+            name   = ident($names[i]).postfix("*"),
+            params = [
+                ident("string"),
+                newIdentDefs(
+                    ident("content"),
+                    ident("string")
+                )
+            ],
+            body = newStmtList(
+                parseStmt("reindent(content)")
+            )
+        )
+
+
+iterator lines(value: string): string =
+    var i = 0
+    while i < value.len:
+        var line: string
+        inc(i, value.parseUntil(line, 0x0A.char, i) + 1)
+        yield line
+
+
+proc reindent*(value: string, preset_indent = 0): string =
+    var indent = -1
+
+    # Detect indentation!
+    for ln in lines(value):
+        var read = ln.skipWhitespace()
+
+        # If the line is empty, ignore it for indentation
+        if read == ln.len: continue
+
+        indent = if indent < 0: read
+                 else: min(indent, read)
+
+    # Create a precursor indent as-needed
+    var precursor = newString(0)
+    for i in 1 .. preset_indent:
+        precursor.add(' ')
+
+    # Re-indent
+    result = newString(0)
+
+    for ln in lines(value):
+        var value = ln.substr(indent)
+
+        result.add(precursor)
+
+        if value.len > 0:
+            result.add(value)
+            result.add(0x0A.char)
+
+    return result
+
+
+#Define tags
+make([ html, xml, glsl, js, css, rst ])
+
+
+when isMainModule:
+    ## Test tags
+
+    const script = js"""
+        var x = 5;
+        console.log(x.toString());
+    """
+
+    const styles = css"""
+        .someRule {
+            width: 500px;
+        }
+    """
+
+    const body = html"""
+        <ul>
+            <li>1</li>
+            <li>2</li>
+            <li>
+                <a hef="#google">google</a>
+            </li>
+        </ul>
+    """
+
+    const info = xml"""
+        <item>
+            <i>1</i>
+            <i>2</i>
+        </item>
+    """
+
+    const shader = glsl"""
+        void main()
+        {
+            gl_Position = gl_ProjectionMatrix
+                        * gl_ModelViewMatrix
+                        * gl_Vertex;
+        }
+    """
+
+
+    echo script
+    echo styles
+    echo body
+    echo info
+    echo shader
\ No newline at end of file
diff --git a/tests/template/mcan_access_hidden_field.nim b/tests/template/mcan_access_hidden_field.nim
new file mode 100644
index 000000000..bf3592701
--- /dev/null
+++ b/tests/template/mcan_access_hidden_field.nim
@@ -0,0 +1,9 @@
+
+type
+  Foo* = object
+    fooa, foob: int
+
+proc createFoo*(a, b: int): Foo = Foo(fooa: a, foob: b)
+
+template geta*(f: Foo): expr = f.fooa
+
diff --git a/tests/template/mtempl5.nim b/tests/template/mtempl5.nim
new file mode 100644
index 000000000..51e8461b8
--- /dev/null
+++ b/tests/template/mtempl5.nim
@@ -0,0 +1,10 @@
+
+var 
+  gx = 88
+  gy = 44
+  
+template templ*(): int =
+  bind gx, gy
+  gx + gy
+  
+
diff --git a/tests/template/otests.nim b/tests/template/otests.nim
new file mode 100644
index 000000000..c885e23df
--- /dev/null
+++ b/tests/template/otests.nim
@@ -0,0 +1,219 @@
+# Fields

+const x = 5

+

+

+# Test substring

+static:

+    assert "test".substring(3)   == "t"

+    assert "test".substring(2,1) == "s"

+    assert "test".substring(3,2) == "t"

+    assert "test".substring(1,2) == "es"

+

+

+# Various parsing tests

+when true:

+

+    block: #no_substitution

+        proc actual: string = tmpli html"""

+            <p>Test!</p>

+        """

+        const expected = html"""

+            <p>Test!</p>

+        """

+        doAssert actual() == expected

+

+    block: #basic

+        proc actual: string = tmpli html"""

+            <p>Test $$x</p>

+            $x

+        """

+        const expected = html"""

+            <p>Test $x</p>

+            5

+        """

+        doAssert actual() == expected

+

+    block: #expression

+        proc actual: string = tmpli html"""

+            <p>Test $$(x * 5)</p>

+            $(x * 5)

+        """

+        const expected = html"""

+            <p>Test $(x * 5)</p>

+            25

+        """

+        doAssert actual() == expected

+

+    block: #escape

+        proc actual: string = tmpli js"""

+            [{

+                "hello world"

+            }]

+        """

+        const expected = js"""

+            [{

+                "hello world"

+            }]

+        """

+        doAssert actual() == expected

+

+    block: #forIn

+        proc actual: string = tmpli html"""

+            <p>Test for</p>

+            <ul>

+                $for y in 0..2 {

+                    <li>$y</li>

+                }

+            </ul>

+        """

+        const expected = html"""

+            <p>Test for</p>

+            <ul>

+                <li>0</li>

+                <li>1</li>

+                <li>2</li>

+            </ul>

+        """

+        doAssert actual() == expected

+

+    block: #while

+        proc actual: string = tmpli html"""

+            <p>Test while/stmt</p>

+            <ul>

+                ${ var y = 0 }

+                $while y < 4 {

+                    <li>$y</li>

+                    ${ inc(y) }

+                }

+            </ul>

+        """

+        const expected = html"""

+            <p>Test while/stmt</p>

+            <ul>

+                <li>0</li>

+                <li>1</li>

+                <li>2</li>

+                <li>3</li>

+            </ul>

+        """

+        doAssert actual() == expected

+

+    block: #ifElifElse

+        proc actual: string = tmpli html"""

+            <p>Test if/elif/else</p>

+            $if x == 8 {

+                <div>x is 8!</div>

+            }

+            $elif x == 7 {

+                <div>x is 7!</div>

+            }

+            $else {

+                <div>x is neither!</div>

+            }

+        """

+        const expected = html"""

+            <p>Test if/elif/else</p>

+            <div>x is neither!</div>

+        """

+        doAssert actual() == expected

+

+    block: #multiLineStatements

+        proc actual: string = tmpli html"""

+            <p>Test multiline statements</p>

+            ${

+                var x = 5

+                var y = 7

+            }

+            <span>$x</span><span>$y</span>

+        """

+        const expected = html"""

+            <p>Test multiline statements</p>

+            <span>5</span><span>7</span>

+        """

+        doAssert actual() == expected

+

+    block: #caseOfElse

+        proc actual: string = tmpli html"""

+            <p>Test case</p>

+            $case x

+            $of 5 {

+                <div>x == 5</div>

+            }

+            $of 6 {

+                <div>x == 6</div>

+            }

+            $else {}

+        """

+        const expected = html"""

+            <p>Test case</p>

+            <div>x == 5</div>

+        """

+        doAssert actual() == expected

+

+

+

+when true: #embeddingTest

+    proc no_substitution: string = tmpli html"""

+        <h1>Template test!</h1>

+    """

+

+    # # Single variable substitution

+    proc substitution(who = "nobody"): string = tmpli html"""

+        <div id="greeting">hello $who!</div>

+    """

+

+    # Expression template

+    proc test_expression(nums: openarray[int] = []): string =

+        var i = 2

+        tmpli html"""

+            $(no_substitution())

+            $(substitution("Billy"))

+            <div id="age">Age: $($nums[i] & "!!")</div>

+        """

+

+    proc test_statements(nums: openarray[int] = []): string =

+        tmpli html"""

+            $(test_expression(nums))

+            $if true {

+                <ul>

+                    $for i in nums {

+                        <li>$(i * 2)</li>

+                    }

+                </ul>

+            }

+        """

+

+    var actual = test_statements([0,1,2])

+    const expected = html"""

+        <h1>Template test!</h1>

+        <div id="greeting">hello Billy!</div>

+        <div id="age">Age: 2!!</div>

+        <ul>

+            <li>0</li>

+            <li>2</li>

+            <li>4</li>

+        </ul>

+    """

+    doAssert actual == expected

+

+

+when defined(future):

+    block: #tryCatch

+        proc actual: string = tmpli html"""

+            <p>Test try/catch</p>

+            <div>

+                $try {

+                    <div>Lets try this!</div>

+                }

+                $except {

+                    <div>Uh oh!</div>

+                }

+            </div>

+        """

+        const expected = html"""

+            <p>Test try/catch</p>

+            <div>

+                    <div>Lets try this!</div>

+            </div>

+        """

+        doAssert actual() == expected
\ No newline at end of file
diff --git a/tests/template/sunset.tmpl b/tests/template/sunset.tmpl
new file mode 100644
index 000000000..6475bac4e
--- /dev/null
+++ b/tests/template/sunset.tmpl
@@ -0,0 +1,68 @@
+#! stdtmpl
+#proc sunsetTemplate*(current, ticker, content: string,
+#                     tabs: openarray[array[0..1, string]]): string = 
+#  result = ""
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+
+<head>
+  <title>Nimrod Programming System</title>
+  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" type="text/css" href="style/style.css" />
+</head>
+
+<body>
+  <div id="main">
+    <div id="links">
+      <!-- **** INSERT LINKS HERE **** -->
+    </div>
+    <div id="logo"><h1>Nimrod Programming System</h1></div>
+    <div id="content">
+      <div id="menu">
+        <ul>
+  #for item in items(tabs):
+    #var name = item[0]
+    #var t = item[1]
+    #if t == current:
+          <li><a id="selected" href="${t}.html" title = "Nimrod - $name">$name</a></li>
+    #else:
+          <li><a               href="${t}.html" title = "Nimrod - $name">$name</a></li>
+    #end if
+  #end for
+        </ul>
+      </div>
+      <div id="column1">
+        <div class="sidebaritem">
+          <div class="sbihead">
+            <h1>latest news</h1>
+          </div>
+          <div class="sbicontent">
+            $ticker
+          </div>
+        </div>
+        <div class="sidebaritem">
+          <div class="sbihead">
+            <h1>additional links</h1>
+          </div>
+          <div class="sbilinks">
+            <!-- **** INSERT ADDITIONAL LINKS HERE **** -->
+            <ul>
+              <li><a class="reference" href="http://llvm.org">LLVM</a></li>
+              <li><a class="reference" href="http://gcc.gnu.org">GCC</a></li>
+            </ul>
+          </div>
+        </div>
+      </div>
+      <div id="column2">
+      $content
+      </div>
+    </div>
+    <div id="footer">
+      copyright &copy; 2008 Andreas Rumpf | Last update: ${getDateStr()}
+      | <a class="reference" href="http://validator.w3.org/check?uri=referer">XHTML 1.1</a>
+      | <a class="reference" href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>
+      | <a class="reference" href="http://www.dcarter.co.uk">design by dcarter</a>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/tests/template/t2do.nim b/tests/template/t2do.nim
new file mode 100644
index 000000000..b87e3328c
--- /dev/null
+++ b/tests/template/t2do.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "8.0"
+"""
+
+# bug #2057
+
+proc mpf_get_d(x: int): float = float(x)
+proc mpf_cmp_d(a: int; b: float): int = 0
+
+template toFloatHelper(result: expr; tooSmall, tooLarge: stmt) {.immediate.} =
+  result = mpf_get_d(a)
+  if result == 0.0 and mpf_cmp_d(a,0.0) != 0:
+    tooSmall
+  if result == Inf:
+    tooLarge
+
+proc toFloat*(a: int): float =
+  toFloatHelper(result)
+    do: raise newException(ValueError, "number too small"):
+        raise newException(ValueError, "number too large")
+
+echo toFloat(8)
diff --git a/tests/template/t_otemplates.nim b/tests/template/t_otemplates.nim
new file mode 100644
index 000000000..db535d818
--- /dev/null
+++ b/tests/template/t_otemplates.nim
@@ -0,0 +1,345 @@
+discard """
+  output: "Success"
+"""
+
+# Ref:

+# http://nim-lang.org/macros.html

+# http://nim-lang.org/parseutils.html

+

+

+# Imports

+import tables, parseutils, macros, strutils

+import annotate

+export annotate

+

+

+# Fields

+const identChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}

+

+

+# Procedure Declarations

+proc parse_template(node: NimNode, value: string) {.compiletime.}

+

+

+# Procedure Definitions

+proc substring(value: string, index: int, length = -1): string {.compiletime.} =

+    ## Returns a string at most `length` characters long, starting at `index`.

+    return if length < 0:    value.substr(index)

+           elif length == 0: ""

+           else:             value.substr(index, index + length-1)

+

+

+proc parse_thru_eol(value: string, index: int): int {.compiletime.} =

+    ## Reads until and past the end of the current line, unless

+    ## a non-whitespace character is encountered first

+    var remainder: string

+    var read = value.parseUntil(remainder, {0x0A.char}, index)

+    if remainder.skipWhitespace() == read:

+        return read + 1

+

+

+proc trim_after_eol(value: var string) {.compiletime.} =

+    ## Trims any whitespace at end after \n

+    var toTrim = 0

+    for i in countdown(value.len-1, 0):

+        # If \n, return

+        if value[i] in [' ', '\t']: inc(toTrim)

+        else: break

+

+    if toTrim > 0:

+        value = value.substring(0, value.len - toTrim)

+

+

+proc trim_eol(value: var string) {.compiletime.} =

+    ## Removes everything after the last line if it contains nothing but whitespace

+    for i in countdown(value.len - 1, 0):

+        # If \n, trim and return

+        if value[i] == 0x0A.char:

+            value = value.substr(0, i)

+            break

+

+        # This is the first character

+        if i == 0:

+            value = ""

+            break

+

+        # Skip change

+        if not (value[i] in [' ', '\t']): break

+

+

+proc detect_indent(value: string, index: int): int {.compiletime.} =

+    ## Detects how indented the line at `index` is.

+    # Seek to the beginning of the line.

+    var lastChar = index

+    for i in countdown(index, 0):

+        if value[i] == 0x0A.char:

+            # if \n, return the indentation level

+            return lastChar - i

+        elif not (value[i] in [' ', '\t']):

+            # if non-whitespace char, decrement lastChar

+            dec(lastChar)

+

+

+proc parse_thru_string(value: string, i: var int, strType = '"') {.compiletime.} =

+    ## Parses until ending " or ' is reached.

+    inc(i)

+    if i < value.len-1:

+        inc(i, value.skipUntil({'\\', strType}, i))

+

+

+proc parse_to_close(value: string, index: int, open='(', close=')', opened=0): int {.compiletime.} =

+    ## Reads until all opened braces are closed

+    ## ignoring any strings "" or ''

+    var remainder   = value.substring(index)

+    var open_braces = opened

+    result = 0

+

+    while result < remainder.len:

+        var c = remainder[result]

+

+        if   c == open:  inc(open_braces)

+        elif c == close: dec(open_braces)

+        elif c == '"':   remainder.parse_thru_string(result)

+        elif c == '\'':  remainder.parse_thru_string(result, '\'')

+

+        if open_braces == 0: break

+        else: inc(result)

+

+

+iterator parse_stmt_list(value: string, index: var int): string =

+    ## Parses unguided ${..} block

+    var read        = value.parse_to_close(index, open='{', close='}')

+    var expressions = value.substring(index + 1, read - 1).split({ ';', 0x0A.char })

+

+    for expression in expressions:

+        let value = expression.strip

+        if value.len > 0:

+            yield value

+

+    #Increment index & parse thru EOL

+    inc(index, read + 1)

+    inc(index, value.parse_thru_eol(index))

+

+

+iterator parse_compound_statements(value, identifier: string, index: int): string =

+    ## Parses through several statements, i.e. if {} elif {} else {}

+    ## and returns the initialization of each as an empty statement

+    ## i.e. if x == 5 { ... } becomes if x == 5: nil.

+

+    template get_next_ident(expected): stmt =

+        var nextIdent: string

+        discard value.parseWhile(nextIdent, {'$'} + identChars, i)

+

+        var next: string

+        var read: int

+

+        if nextIdent == "case":

+            # We have to handle case a bit differently

+            read = value.parseUntil(next, '$', i)

+            inc(i, read)

+            yield next.strip(leading=false) & "\n"

+

+        else:

+            read = value.parseUntil(next, '{', i)

+

+            if nextIdent in expected:

+                inc(i, read)

+                # Parse until closing }, then skip whitespace afterwards

+                read = value.parse_to_close(i, open='{', close='}')

+                inc(i, read + 1)

+                inc(i, value.skipWhitespace(i))

+                yield next & ": nil\n"

+

+            else: break

+

+

+    var i = index

+    while true:

+        # Check if next statement would be valid, given the identifier

+        if identifier in ["if", "when"]:

+            get_next_ident([identifier, "$elif", "$else"])

+

+        elif identifier == "case":

+            get_next_ident(["case", "$of", "$elif", "$else"])

+

+        elif identifier == "try":

+            get_next_ident(["try", "$except", "$finally"])

+

+

+proc parse_complex_stmt(value, identifier: string, index: var int): NimNode {.compiletime.} =

+    ## Parses if/when/try /elif /else /except /finally statements

+

+    # Build up complex statement string

+    var stmtString = newString(0)

+    var numStatements = 0

+    for statement in value.parse_compound_statements(identifier, index):

+        if statement[0] == '$': stmtString.add(statement.substr(1))

+        else:                   stmtString.add(statement)

+        inc(numStatements)

+

+    # Parse stmt string

+    result = parseExpr(stmtString)

+

+    var resultIndex = 0

+

+    # Fast forward a bit if this is a case statement

+    if identifier == "case":

+        inc(resultIndex)

+

+    while resultIndex < numStatements:

+

+        # Detect indentation

+        let indent = detect_indent(value, index)

+

+        # Parse until an open brace `{`

+        var read = value.skipUntil('{', index)

+        inc(index, read + 1)

+

+        # Parse through EOL

+        inc(index, value.parse_thru_eol(index))

+

+        # Parse through { .. }

+        read = value.parse_to_close(index, open='{', close='}', opened=1)

+

+        # Add parsed sub-expression into body

+        var body       = newStmtList()

+        var stmtString = value.substring(index, read)

+        trim_after_eol(stmtString)

+        stmtString = reindent(stmtString, indent)

+        parse_template(body, stmtString)

+        inc(index, read + 1)

+

+        # Insert body into result

+        var stmtIndex = macros.high(result[resultIndex])

+        result[resultIndex][stmtIndex] = body

+

+        # Parse through EOL again & increment result index

+        inc(index, value.parse_thru_eol(index))

+        inc(resultIndex)

+

+

+proc parse_simple_statement(value: string, index: var int): NimNode {.compiletime.} =

+    ## Parses for/while

+

+    # Detect indentation

+    let indent = detect_indent(value, index)

+

+    # Parse until an open brace `{`

+    var splitValue: string

+    var read = value.parseUntil(splitValue, '{', index)

+    result   = parseExpr(splitValue & ":nil")

+    inc(index, read + 1)

+

+    # Parse through EOL

+    inc(index, value.parse_thru_eol(index))

+

+    # Parse through { .. }

+    read = value.parse_to_close(index, open='{', close='}', opened=1)

+

+    # Add parsed sub-expression into body

+    var body       = newStmtList()

+    var stmtString = value.substring(index, read)

+    trim_after_eol(stmtString)

+    stmtString = reindent(stmtString, indent)

+    parse_template(body, stmtString)

+    inc(index, read + 1)

+

+    # Insert body into result

+    var stmtIndex = macros.high(result)

+    result[stmtIndex] = body

+

+    # Parse through EOL again

+    inc(index, value.parse_thru_eol(index))

+

+

+proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =

+    ## Parses a string until a $ symbol is encountered, if

+    ## two $$'s are encountered in a row, a split will happen

+    ## removing one of the $'s from the resulting output

+    var splitValue: string

+    var read = value.parseUntil(splitValue, '$', index)

+    var insertionPoint = node.len

+

+    inc(index, read + 1)

+    if index < value.len:

+

+        case value[index]

+        of '$':

+            # Check for duplicate `$`, meaning this is an escaped $

+            node.add newCall("add", ident("result"), newStrLitNode("$"))

+            inc(index)

+

+        of '(':

+            # Check for open `(`, which means parse as simple single-line expression.

+            trim_eol(splitValue)

+            read = value.parse_to_close(index) + 1

+            node.add newCall("add", ident("result"),

+                newCall(bindSym"strip", parseExpr("$" & value.substring(index, read)))

+            )

+            inc(index, read)

+

+        of '{':

+            # Check for open `{`, which means open statement list

+            trim_eol(splitValue)

+            for s in value.parse_stmt_list(index):

+                node.add parseExpr(s)

+

+        else:

+            # Otherwise parse while valid `identChars` and make expression w/ $

+            var identifier: string

+            read = value.parseWhile(identifier, identChars, index)

+

+            if identifier in ["for", "while"]:

+                ## for/while means open simple statement

+                trim_eol(splitValue)

+                node.add value.parse_simple_statement(index)

+

+            elif identifier in ["if", "when", "case", "try"]:

+                ## if/when/case/try means complex statement

+                trim_eol(splitValue)

+                node.add value.parse_complex_stmt(identifier, index)

+

+            elif identifier.len > 0:

+                ## Treat as simple variable

+                node.add newCall("add", ident("result"), newCall("$", ident(identifier)))

+                inc(index, read)

+

+        result = true

+

+    # Insert

+    if splitValue.len > 0:

+        node.insert insertionPoint, newCall("add", ident("result"), newStrLitNode(splitValue))

+

+

+proc parse_template(node: NimNode, value: string) =

+    ## Parses through entire template, outputing valid

+    ## Nim code into the input `node` AST.

+    var index = 0

+    while index < value.len and

+          parse_until_symbol(node, value, index): nil

+

+

+macro tmpli*(body: expr): stmt =

+    result = newStmtList()

+

+    result.add parseExpr("result = \"\"")

+

+    var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal

+                else: body[1].strVal

+

+    parse_template(result, reindent(value))

+

+

+macro tmpl*(body: expr): stmt =

+    result = newStmtList()

+

+    var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal

+                else: body[1].strVal

+

+    parse_template(result, reindent(value))

+

+

+# Run tests

+when isMainModule:

+    include otests
+    echo "Success"
diff --git a/tests/template/tcan_access_hidden_field.nim b/tests/template/tcan_access_hidden_field.nim
new file mode 100644
index 000000000..a6f6490cc
--- /dev/null
+++ b/tests/template/tcan_access_hidden_field.nim
@@ -0,0 +1,9 @@
+discard """
+  output: 33
+"""
+
+import mcan_access_hidden_field
+
+var myfoo = createFoo(33, 44)
+
+echo myfoo.geta
diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim
new file mode 100644
index 000000000..891166306
--- /dev/null
+++ b/tests/template/tdefault_nil.nim
@@ -0,0 +1,14 @@
+
+# bug #2629
+import sequtils, os
+
+template glob_rst(basedir: string = nil): expr =
+  if baseDir.isNil:
+    to_seq(walk_files("*.rst"))
+  else:
+    to_seq(walk_files(basedir/"*.rst"))
+
+let
+  rst_files = concat(glob_rst(), glob_rst("docs"))
+
+when isMainModule: echo rst_files
diff --git a/tests/template/texponential_eval.nim b/tests/template/texponential_eval.nim
new file mode 100644
index 000000000..32af9e8f7
--- /dev/null
+++ b/tests/template/texponential_eval.nim
@@ -0,0 +1,47 @@
+# bug #1940
+
+discard """
+  nimout: '''===
+merge (A) with (B)
+merge (A B) with (C)
+merge (A B C) with (D)
+merge (A B C D) with (E)
+merge (A B C D E) with (F)
+==='''
+"""
+
+type SqlStmt = tuple
+  sql: string
+  parts: int
+
+proc sql(q: string): SqlStmt =
+  result.sql = q
+  result.parts = 1
+
+template `&%%`(x, y: SqlStmt): SqlStmt =
+  const a = x
+  const b = y
+
+  static:
+    #echo "some merge"
+    echo "merge (", a.sql, ") with (", b.sql, ")"
+
+
+  const newSql = a.sql & " " & b.sql
+  const newParts = a.parts + b.parts
+
+  SqlStmt((sql: newSql, parts: newParts))
+
+static:
+  echo "==="
+
+let c =(sql("A") &%%
+        sql("B")) &%%
+        sql("C")  &%%
+        sql("D") &%%
+        sql("E") &%%
+        sql("F")
+echo c.sql
+
+static:
+  echo "==="
diff --git a/tests/template/thygienictempl.nim b/tests/template/thygienictempl.nim
new file mode 100644
index 000000000..3cdbac40e
--- /dev/null
+++ b/tests/template/thygienictempl.nim
@@ -0,0 +1,18 @@
+    
+var
+  e = "abc"
+    
+raise newException(EIO, e & "ha!")
+
+template t() = echo(foo)
+
+var foo = 12
+t()
+
+
+template test_in(a, b, c: expr): bool {.immediate, dirty.} =
+  var result {.gensym.}: bool = false
+  false
+
+when isMainModule:
+  assert test_in(ret2, "test", str_val)
diff --git a/tests/template/tissue909.nim b/tests/template/tissue909.nim
new file mode 100644
index 000000000..5b57a3558
--- /dev/null
+++ b/tests/template/tissue909.nim
@@ -0,0 +1,16 @@
+import macros
+
+template baz() =
+  proc bar() =
+    var x = 5
+    iterator foo(): int {.closure.} =
+      echo x
+    var y = foo
+    discard y()
+
+macro test(): stmt =
+  result = getAst(baz())
+  echo(treeRepr(result))
+
+test()
+bar()
diff --git a/tests/template/tissue993.nim b/tests/template/tissue993.nim
new file mode 100644
index 000000000..dae9df683
--- /dev/null
+++ b/tests/template/tissue993.nim
@@ -0,0 +1,21 @@
+
+type PNode* = ref object of RootObj
+
+template litNode (name, ty): stmt  =
+  type name* = ref object of PNode
+    val*: ty
+litNode PIntNode, int
+
+import json
+
+template withKey*(j: JsonNode; key: string; varname: expr;
+                  body:stmt): stmt {.immediate.} =
+  if j.hasKey(key):
+    let varname{.inject.}= j[key]
+    block:
+      body
+
+var j = parsejson("{\"zzz\":1}")
+withkey(j, "foo", x):
+  echo(x)
+
diff --git a/tests/template/tit.nim b/tests/template/tit.nim
new file mode 100644
index 000000000..9866711de
--- /dev/null
+++ b/tests/template/tit.nim
@@ -0,0 +1,11 @@
+
+# bug #1337
+
+template someIt(a, pred: expr): expr =
+  var it {.inject.} = 0
+  pred
+
+proc aProc(n) =
+  n.someIt(echo(it))
+
+aProc(89)
diff --git a/tests/template/tmodulealias.nim b/tests/template/tmodulealias.nim
new file mode 100644
index 000000000..a7d155e51
--- /dev/null
+++ b/tests/template/tmodulealias.nim
@@ -0,0 +1,19 @@
+discard """
+  disabled: true
+"""
+
+when defined(windows):
+  import winlean
+else:
+  import posix
+
+when defined(Windows):
+  template orig: expr = 
+    winlean
+else:
+  template orig: expr = 
+    posix
+
+proc socket(domain, typ, protocol: int): int =
+  result = orig.socket(ord(domain), ord(typ), ord(protocol)))
+
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
new file mode 100644
index 000000000..6c4413866
--- /dev/null
+++ b/tests/template/tparams_gensymed.nim
@@ -0,0 +1,62 @@
+
+# bug #1915
+
+import macros
+
+# Test that parameters are properly gensym'ed finally:
+
+template genNodeKind(kind, name: expr): stmt =
+  proc name*(children: varargs[PNimrodNode]): PNimrodNode {.compiletime.}=
+    result = newNimNode(kind)
+    for c in children:
+      result.add(c)
+
+genNodeKind(nnkNone, None)
+
+
+# Test that generics in templates still work (regression to fix #1915)
+
+# bug #2004
+
+type Something = object
+
+proc testA(x: Something) = discard
+
+template def(name: expr) {.immediate.} =
+  proc testB[T](reallyUniqueName: T) =
+    `test name`(reallyUniqueName)
+def A
+
+var x: Something
+testB(x)
+
+
+# bug #2215
+# Test that templates in generics still work (regression to fix the
+# regression...)
+
+template forStatic(index: expr, slice: Slice[int], predicate: stmt):
+                   stmt {.immediate.} =
+  const a = slice.a
+  const b = slice.b
+  when a <= b:
+    template iteration(i: int) =
+      block:
+        const index = i
+        predicate
+    template iterateStartingFrom(i: int): stmt =
+      when i <= b:
+        iteration i
+        iterateStartingFrom i + 1
+    iterateStartingFrom a
+
+proc concreteProc(x: int) =
+  forStatic i, 0..3:
+    echo i
+
+proc genericProc(x: any) =
+  forStatic i, 0..3:
+    echo i
+
+concreteProc(7) # This works
+genericProc(7)  # This doesn't compile
diff --git a/tests/template/tprefer_immediate.nim b/tests/template/tprefer_immediate.nim
new file mode 100644
index 000000000..578f447b0
--- /dev/null
+++ b/tests/template/tprefer_immediate.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''immediate'''
+"""
+
+# Test that immediate templates are preferred over non-immediate templates
+
+template foo(a, b: expr) = echo "foo expr"
+
+template foo(a, b: int) = echo "foo int"
+template foo(a, b: float) = echo "foo float"
+template foo(a, b: string) = echo "foo string"
+template foo(a, b: expr) {.immediate.} = echo "immediate"
+template foo(a, b: bool) = echo "foo bool"
+template foo(a, b: char) = echo "foo char"
+
+foo(undeclaredIdentifier, undeclaredIdentifier2)
+
diff --git a/tests/template/tscope.nim b/tests/template/tscope.nim
new file mode 100644
index 000000000..2d5841af3
--- /dev/null
+++ b/tests/template/tscope.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "redefinition of 'x'"
+"""
+
+var x = 1
+template quantity(): stmt {.immediate.} =
+  # Causes internal error in compiler/sem.nim
+  proc unit*(x = 1.0): float = 12
+  # Throws the correct error: redefinition of 'x'
+  #proc unit*(y = 1.0): float = 12
+quantity()
+var x = 2
diff --git a/tests/template/tstempl.nim b/tests/template/tstempl.nim
new file mode 100644
index 000000000..2b4a8baa0
--- /dev/null
+++ b/tests/template/tstempl.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''global = levB, arg = levA, test = false
+levB'''
+"""
+
+# tstempl.nim
+import strutils
+
+type 
+  TLev = enum
+    levA,
+    levB
+
+var abclev = levB
+
+template tstLev(abclev: TLev) =
+  bind tstempl.abclev, `%`
+  writeln(stdout, "global = $1, arg = $2, test = $3" % [
+    $tstempl.abclev, $abclev, $(tstempl.abclev == abclev)])
+  # evaluates to true, but must be false
+
+
+tstLev(levA)
+writeln(stdout, $abclev)
diff --git a/tests/template/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim
new file mode 100644
index 000000000..05c16c3c9
--- /dev/null
+++ b/tests/template/tstmt_semchecked_twice.nim
@@ -0,0 +1,30 @@
+
+# bug #2585
+
+type
+    RenderPass = object
+       state: ref int
+
+    RenderData* = object
+        fb: int
+        walls: seq[RenderPass]
+
+    Mat2 = int
+    Vector2[T] = T
+    Pixels=int
+
+template use*(fb: int, st: stmt) : stmt =
+    echo "a ", $fb
+    st
+    echo "a ", $fb
+
+proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
+            indexType = 1) =
+    for i in 0 .. <len(passes):
+        echo "blah ", repr(passes[i])
+
+
+
+proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
+    use rdat.fb:
+        render(rdat, rdat.walls, proj, 1)
diff --git a/tests/template/tsymchoicefield.nim b/tests/template/tsymchoicefield.nim
new file mode 100644
index 000000000..ab05500bf
--- /dev/null
+++ b/tests/template/tsymchoicefield.nim
@@ -0,0 +1,12 @@
+type Foo = object
+  len: int
+
+var f = Foo(len: 40)
+
+template getLen(f: Foo): expr = f.len
+
+echo f.getLen
+# This fails, because `len` gets the nkOpenSymChoice
+# treatment inside the template early pass and then
+# it can't be recognized as a field anymore
+
diff --git a/tests/template/ttempl.nim b/tests/template/ttempl.nim
new file mode 100644
index 000000000..2c4785325
--- /dev/null
+++ b/tests/template/ttempl.nim
@@ -0,0 +1,27 @@
+# Test the new template file mechanism
+
+import
+  os, times
+
+include "sunset.tmpl"
+
+const
+  tabs = [["home", "index"],
+          ["news", "news"],
+          ["documentation", "documentation"],
+          ["download", "download"],
+          ["FAQ", "question"],
+          ["links", "links"]]
+
+
+var i = 0
+for item in items(tabs): 
+  var content = $i
+  var file: TFile
+  if open(file, changeFileExt(item[1], "html"), fmWrite): 
+    write(file, sunsetTemplate(current=item[1], ticker="", content=content,
+                               tabs=tabs))
+    close(file)
+  else:
+    write(stdout, "cannot open file for writing")
+  inc(i)
diff --git a/tests/template/ttempl2.nim b/tests/template/ttempl2.nim
new file mode 100644
index 000000000..aaa2f1344
--- /dev/null
+++ b/tests/template/ttempl2.nim
@@ -0,0 +1,19 @@
+discard """
+  file: "ttempl2.nim"
+  line: 18
+  errormsg: "undeclared identifier: \'b\'"
+"""
+template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} =
+  var x: t
+
+template declareInNewScope(x: untyped, t: typeDesc): untyped {.immediate.} =
+  # open a new scope:
+  block:
+    var x: t
+
+declareInScope(a, int)
+a = 42  # works, `a` is known here
+
+declareInNewScope(b, int)
+b = 42  #ERROR_MSG undeclared identifier: 'b'
+
diff --git a/tests/template/ttempl3.nim b/tests/template/ttempl3.nim
new file mode 100644
index 000000000..59be24624
--- /dev/null
+++ b/tests/template/ttempl3.nim
@@ -0,0 +1,58 @@
+
+template withOpenFile(f: expr, filename: string, mode: TFileMode,
+                      actions: stmt): stmt {.immediate.} =
+  block:
+    # test that 'f' is implicitly 'injecting':
+    var f: TFile
+    if open(f, filename, mode):
+      try:
+        actions
+      finally:
+        close(f)
+    else:
+      quit("cannot open for writing: " & filename)
+    
+withOpenFile(txt, "ttempl3.txt", fmWrite):
+  writeln(txt, "line 1")
+  txt.writeln("line 2")
+  
+var
+  myVar: array[0..1, int]
+
+# Test zero argument template: 
+template ha: expr = myVar[0]
+  
+ha = 1  
+echo(ha)
+
+
+# Test identifier generation:
+template prefix(name: expr): expr {.immediate.} = `"hu" name`
+
+var `hu "XYZ"` = "yay"
+
+echo prefix(XYZ)
+
+template typedef(name: expr, typ: typeDesc) {.immediate, dirty.} =
+  type
+    `T name`* = typ
+    `P name`* = ref `T name`
+    
+typedef(myint, int)
+var x: PMyInt
+
+
+# Test UFCS
+
+type
+  Foo = object
+    arg: int
+
+proc initFoo(arg: int): Foo =
+  result.arg = arg
+
+template create(typ: typeDesc, arg: expr): expr = `init typ`(arg)
+
+var ff = Foo.create(12)
+
+echo ff.arg
diff --git a/tests/template/ttempl4.nim b/tests/template/ttempl4.nim
new file mode 100644
index 000000000..26c82e471
--- /dev/null
+++ b/tests/template/ttempl4.nim
@@ -0,0 +1,8 @@
+
+template `:=`(name, val: expr): stmt {.immediate.} =
+  var name = val
+
+ha := 1 * 4
+hu := "ta-da" == "ta-da"
+echo ha, hu
+
diff --git a/tests/template/ttempl5.nim b/tests/template/ttempl5.nim
new file mode 100644
index 000000000..a020a8e2c
--- /dev/null
+++ b/tests/template/ttempl5.nim
@@ -0,0 +1,29 @@
+
+import mtempl5
+
+echo templ()
+
+#bug #892
+
+proc parse_to_close(value: string, index: int, open='(', close=')'): int =
+    discard
+
+# Call parse_to_close
+template get_next_ident: stmt =
+    discard "{something}".parse_to_close(0, open = '{', close = '}')
+
+get_next_ident()
+
+
+#identifier expected, but found '(open|open|open)'
+
+#bug #880 (also example in the manual!)
+
+template typedef(name: expr, typ: typedesc) {.immediate.} =
+  type
+    `T name`* {.inject.} = typ
+    `P name`* {.inject.} = ref `T name`
+
+typedef(myint, int)
+var x: PMyInt
+
diff --git a/tests/template/ttemplreturntype.nim b/tests/template/ttemplreturntype.nim
new file mode 100644
index 000000000..642fa1b72
--- /dev/null
+++ b/tests/template/ttemplreturntype.nim
@@ -0,0 +1,4 @@
+
+template `=~` (a: int, b: int): bool = false
+var foo = 2 =~ 3
+
diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim
new file mode 100644
index 000000000..bca1292b8
--- /dev/null
+++ b/tests/template/twrongmapit.nim
@@ -0,0 +1,32 @@
+discard """
+  errormsg: "'"
+  file: "sequtils.nim"
+  line: 435
+"""
+# unfortunately our tester doesn't support multiple lines of compiler
+# error messages yet...
+
+# bug #1562
+type Foo* {.pure, final.} = object
+  elt: float
+
+template defineOpAssign(T: expr, op: expr) {.immediate.} =
+  proc op*(v: var T, w: T) {.inline.} =
+    for i in 0..1:
+      op(v.elt, w.elt)
+
+const ATTEMPT = 0
+
+when ATTEMPT == 0:
+  # FAILS: defining `/=` with template calling template
+  # ERROR about sem.nim line 144
+  template defineOpAssigns(T: expr) {.immediate.} =
+    mixin `/=`
+    defineOpAssign(T, `/=`)
+
+  defineOpAssigns(Foo)
+
+# bug #1543
+import sequtils
+
+(var i= @[""];i).mapIt(it)
diff --git a/tests/template/twrongopensymchoice.nim b/tests/template/twrongopensymchoice.nim
new file mode 100644
index 000000000..5a02a813c
--- /dev/null
+++ b/tests/template/twrongopensymchoice.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''10'''
+"""
+
+# bug #940
+
+type 
+  Foo* = ref object 
+    b*: int
+
+proc new*(this: var Foo) = 
+  assert this != nil
+  this.b = 10
+
+proc new*(T: typedesc[Foo]): Foo =
+  system.new(result)
+  twrongopensymchoice.new(result)
+
+proc main =
+  var f = Foo.new()
+  echo f.b
+
+when isMainModule:
+  main()
diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim
new file mode 100644
index 000000000..8b9ae5d26
--- /dev/null
+++ b/tests/template/utemplates.nim
@@ -0,0 +1,32 @@
+import unittest
+
+template t(a: int): expr = "int"
+template t(a: string): expr = "string"
+
+test "templates can be overloaded":
+  check t(10) == "int"
+  check t("test") == "string"
+
+test "previous definitions can be further overloaded or hidden in local scopes":
+  template t(a: bool): expr = "bool"
+
+  check t(true) == "bool"
+  check t(10) == "int"
+
+  template t(a: int): expr = "inner int"
+  check t(10) == "inner int"
+  check t("test") == "string"
+
+test "templates can be redefined multiple times":
+  template customAssert(cond: bool, msg: string): stmt {.immediate, dirty.} =
+    if not cond: fail(msg)
+
+  template assertion_failed(body: stmt) {.immediate, dirty.} =
+    template fail(msg: string): stmt = body
+
+  assertion_failed: check msg == "first fail path"
+  customAssert false, "first fail path"
+
+  assertion_failed: check msg == "second fail path"
+  customAssert false, "second fail path"
+
diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim
new file mode 100644
index 000000000..11743c337
--- /dev/null
+++ b/tests/testament/backend.nim
@@ -0,0 +1,121 @@
+#
+#
+#              The Nim Tester
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    Look at license.txt for more info.
+#    All rights reserved.
+
+import strutils, db_sqlite, os, osproc
+
+var db: TDbConn
+
+proc createDb() =
+  db.exec(sql"""
+    create table if not exists Machine(
+      id integer primary key,
+      name varchar(100) not null,
+      os varchar(20) not null,
+      cpu varchar(20) not null
+    );""")
+
+  db.exec(sql"""
+    create table if not exists [Commit](
+      id integer primary key,
+      hash varchar(256) not null,
+      branch varchar(50) not null
+    );""")
+
+  db.exec(sql"""
+    create table if not exists TestResult(
+      id integer primary key,
+      name varchar(100) not null,
+      category varchar(100) not null,
+      target varchar(20) not null,
+      action varchar(10) not null,
+      result varchar(30) not null,
+      [commit] int not null,
+      machine int not null,
+      expected varchar(10000) not null,
+      given varchar(10000) not null,
+      created timestamp not null default (DATETIME('now')),
+
+      foreign key ([commit]) references [commit](id),
+      foreign key (machine) references machine(id)
+    );""")
+
+  #db.exec(sql"""
+  #  --create unique index if not exists TsstNameIx on TestResult(name);
+  #  """, [])
+
+type
+  MachineId* = distinct int64
+  CommitId = distinct int64
+
+proc `$`*(id: MachineId): string {.borrow.}
+proc `$`(id: CommitId): string {.borrow.}
+
+var
+  thisMachine: MachineId
+  thisCommit: CommitId
+
+proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip
+
+proc getMachine*(db: TDbConn): MachineId =
+  var name = "hostname"()
+  if name.len == 0:
+    name = when defined(posix): getenv"HOSTNAME".string
+           else: getenv"COMPUTERNAME".string
+  if name.len == 0:
+    quit "cannot determine the machine name"
+
+  let id = db.getValue(sql"select id from Machine where name = ?", name)
+  if id.len > 0:
+    result = id.parseInt.MachineId
+  else:
+    result = db.insertId(sql"insert into Machine(name, os, cpu) values (?,?,?)",
+                         name, system.hostOS, system.hostCPU).MachineId
+
+proc getCommit(db: TDbConn): CommitId =
+  const commLen = "commit ".len
+  let hash = "git log -n 1"()[commLen..commLen+10]
+  let branch = "git symbolic-ref --short HEAD"()
+  if hash.len == 0 or branch.len == 0: quit "cannot determine git HEAD"
+  
+  let id = db.getValue(sql"select id from [Commit] where hash = ? and branch = ?",
+                       hash, branch)
+  if id.len > 0:
+    result = id.parseInt.CommitId
+  else:
+    result = db.insertId(sql"insert into [Commit](hash, branch) values (?, ?)", 
+                         hash, branch).CommitId
+
+proc writeTestResult*(name, category, target, 
+                      action, result, expected, given: string) =
+  let id = db.getValue(sql"""select id from TestResult 
+                             where name = ? and category = ? and target = ? and
+                                machine = ? and [commit] = ?""", 
+                                name, category, target,
+                                thisMachine, thisCommit)
+  if id.len > 0:
+    db.exec(sql"""update TestResult
+                  set action = ?, result = ?, expected = ?, given = ? 
+                  where id = ?""", action, result, expected, given, id)
+  else:
+    db.exec(sql"""insert into TestResult(name, category, target, 
+                                         action, 
+                                         result, expected, given,
+                                         [commit], machine)
+                  values (?,?,?,?,?,?,?,?,?) """, name, category, target, 
+                                        action,
+                                        result, expected, given, 
+                                        thisCommit, thisMachine)
+
+proc open*() =
+  db = open(connection="testament.db", user="testament", password="",
+            database="testament")
+  createDb()
+  thisMachine = getMachine(db)
+  thisCommit = getCommit(db)
+
+proc close*() = close(db)
diff --git a/tests/testament/caasdriver.nim b/tests/testament/caasdriver.nim
new file mode 100644
index 000000000..c61a9f108
--- /dev/null
+++ b/tests/testament/caasdriver.nim
@@ -0,0 +1,195 @@
+import osproc, streams, os, strutils, re
+{.experimental.}
+
+## Compiler as a service tester.
+##
+## Please read docs/idetools.txt for information about this.
+
+
+type
+  TRunMode = enum
+    ProcRun, CaasRun, SymbolProcRun
+
+  NimSession* = object
+    nim: Process # Holds the open process for CaasRun sessions, nil otherwise.
+    mode: TRunMode # Stores the type of run mode the session was started with.
+    lastOutput: string # Preserves the last output, needed for ProcRun mode.
+    filename: string # Appended to each command starting with '>'. Also a var.
+    modname: string # Like filename but without extension.
+    nimcache: string # Input script based name for the nimcache dir.
+
+const
+  modes = [CaasRun, ProcRun, SymbolProcRun]
+  filenameReplaceVar = "$TESTNIM"
+  moduleReplaceVar = "$MODULE"
+  silentReplaceVar = "$SILENT"
+  silentReplaceText = "--verbosity:0 --hints:off"
+
+var
+  TesterDir = getAppDir() / ".."
+  NimBin = TesterDir / "../bin/nim"
+
+proc replaceVars(session: var NimSession, text: string): string =
+  result = text.replace(filenameReplaceVar, session.filename)
+  result = result.replace(moduleReplaceVar, session.modname)
+  result = result.replace(silentReplaceVar, silentReplaceText)
+
+proc startNimSession(project, script: string, mode: TRunMode):
+                        NimSession =
+  let (dir, name, ext) = project.splitFile
+  result.mode = mode
+  result.lastOutput = ""
+  result.filename = name & ext
+  result.modname = name
+
+  let (nimcacheDir, nimcacheName, nimcacheExt) = script.splitFile
+  result.nimcache = "SymbolProcRun." & nimcacheName
+
+  if mode == SymbolProcRun:
+    removeDir(nimcacheDir / result.nimcache)
+  else:
+    removeDir(nimcacheDir / "nimcache")
+
+  if mode == CaasRun:
+    result.nim = startProcess(NimBin, workingDir = dir,
+      args = ["serve", "--server.type:stdin", name])
+
+proc doCaasCommand(session: var NimSession, command: string): string =
+  assert session.mode == CaasRun
+  session.nim.inputStream.write(session.replaceVars(command) & "\n")
+  session.nim.inputStream.flush
+
+  result = ""
+
+  while true:
+    var line = TaintedString("")
+    if session.nim.outputStream.readLine(line):
+      if line.string == "": break
+      result.add(line.string & "\n")
+    else:
+      result = "FAILED TO EXECUTE: " & command & "\n" & result
+      break
+
+proc doProcCommand(session: var NimSession, command: string): string =
+  try:
+    assert session.mode == ProcRun or session.mode == SymbolProcRun
+  except:
+    result = "FAILED TO EXECUTE: " & command & "\n" & result
+  var
+    process = startProcess(NimBin, args = session.replaceVars(command).split)
+    stream = outputStream(process)
+    line = TaintedString("")
+
+  result = ""
+  while stream.readLine(line):
+    if result.len > 0: result &= "\n"
+    result &= line.string
+
+  process.close()
+
+proc doCommand(session: var NimSession, command: string) =
+  if session.mode == CaasRun:
+    if not session.nim.running:
+      session.lastOutput = "FAILED TO EXECUTE: " & command & "\n" &
+          "Exit code " & $session.nim.peekExitCode
+      return
+    session.lastOutput = doCaasCommand(session,
+                                       command & " " & session.filename)
+  else:
+    var command = command
+    # For symbol runs we prepend the necessary parameters to avoid clobbering
+    # the normal nimcache.
+    if session.mode == SymbolProcRun:
+      command = "--symbolFiles:on --nimcache:" & session.nimcache &
+                " " & command
+    session.lastOutput = doProcCommand(session,
+                                       command & " " & session.filename)
+
+proc destroy(session: var NimSession) {.destructor.} =
+  if session.mode == CaasRun:
+    session.nim.close
+
+proc doScenario(script: string, output: Stream, mode: TRunMode, verbose: bool): bool =
+  result = true
+
+  var f = open(script)
+  var project = TaintedString("")
+
+  if f.readLine(project):
+    var
+      s = startNimSession(script.parentDir / project.string, script, mode)
+      tline = TaintedString("")
+      ln = 1
+
+    while f.readLine(tline):
+      var line = tline.string
+      inc ln
+
+      # Filter lines by run mode, removing the prefix if the mode is current.
+      for testMode in modes:
+        if line.startsWith($testMode):
+          if testMode != mode:
+            line = ""
+          else:
+            line = line[len($testMode)..len(line) - 1].strip
+          break
+
+      if line.strip.len == 0: continue
+
+      if line.startsWith("#"):
+        output.writeln line
+        continue
+      elif line.startsWith(">"):
+        s.doCommand(line.substr(1).strip)
+        output.writeln line, "\n", if verbose: s.lastOutput else: ""
+      else:
+        var expectMatch = true
+        var pattern = s.replaceVars(line)
+        if line.startsWith("!"):
+          pattern = pattern.substr(1).strip
+          expectMatch = false
+
+        let actualMatch =
+          s.lastOutput.find(re(pattern, flags = {reStudy})) != -1
+
+        if expectMatch == actualMatch:
+          output.writeln "SUCCESS ", line
+        else:
+          output.writeln "FAILURE ", line
+          result = false
+
+iterator caasTestsRunner*(filter = "", verbose = false): tuple[test,
+                                              output: string, status: bool,
+                                              mode: TRunMode] =
+  for scenario in os.walkFiles(TesterDir / "caas/*.txt"):
+    if filter.len > 0 and find(scenario, filter) == -1: continue
+    for mode in modes:
+      var outStream = newStringStream()
+      let r = doScenario(scenario, outStream, mode, verbose)
+      yield (scenario, outStream.data, r, mode)
+
+when isMainModule:
+  var
+    filter = ""
+    failures = 0
+    verbose = false
+
+  for i in 0..paramCount() - 1:
+    let param = string(paramStr(i + 1))
+    case param
+    of "verbose": verbose = true
+    else: filter = param
+
+  if verbose and len(filter) > 0:
+    echo "Running only test cases matching filter '$1'" % [filter]
+
+  for test, output, result, mode in caasTestsRunner(filter, verbose):
+    if not result or verbose:
+      echo "Mode ", $mode, " (", if result: "succeeded)" else: "failed)"
+      echo test
+      echo output
+      echo "---------\n"
+    if not result:
+      failures += 1
+
+  quit(failures)
diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim
new file mode 100644
index 000000000..4de1edeee
--- /dev/null
+++ b/tests/testament/categories.nim
@@ -0,0 +1,380 @@
+#
+#
+#            Nim Tester
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Include for the tester that contains test suites that test special features
+## of the compiler.
+
+# included from tester.nim
+# ---------------- ROD file tests ---------------------------------------------
+
+const
+  rodfilesDir = "tests/rodfiles"
+  nimcacheDir = rodfilesDir / "nimcache"
+
+proc delNimCache() =
+  try:
+    removeDir(nimcacheDir)
+  except OSError:
+    echo "[Warning] could not delete: ", nimcacheDir
+
+proc runRodFiles(r: var TResults, cat: Category, options: string) =
+  template test(filename: expr): stmt =
+    testSpec r, makeTest(rodfilesDir / filename, options, cat, actionRun)
+
+  delNimCache()
+
+  # test basic recompilation scheme:
+  test "hallo"
+  test "hallo"
+  # test incremental type information:
+  test "hallo2"
+  delNimCache()
+
+  # test type converters:
+  test "aconv"
+  test "bconv"
+  delNimCache()
+
+  # test G, A, B example from the documentation; test init sections:
+  test "deada"
+  test "deada2"
+  delNimCache()
+
+  # test method generation:
+  test "bmethods"
+  test "bmethods2"
+  delNimCache()
+
+  # test generics:
+  test "tgeneric1"
+  test "tgeneric2"
+  delNimCache()
+
+proc compileRodFiles(r: var TResults, cat: Category, options: string) =
+  template test(filename: expr): stmt =
+    testSpec r, makeTest(rodfilesDir / filename, options, cat)
+
+  delNimCache()
+  # test DLL interfacing:
+  test "gtkex1"
+  test "gtkex2"
+  delNimCache()
+
+# --------------------- DLL generation tests ----------------------------------
+
+proc safeCopyFile(src, dest: string) =
+  try:
+    copyFile(src, dest)
+  except OSError:
+    echo "[Warning] could not copy: ", src, " to ", dest
+
+proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
+  testSpec c, makeTest("lib/nimrtl.nim",
+    options & " --app:lib -d:createNimRtl", cat)
+  testSpec c, makeTest("tests/dll/server.nim",
+    options & " --app:lib -d:useNimRtl", cat)
+
+  when defined(Windows):
+    # windows looks in the dir of the exe (yay!):
+    var nimrtlDll = DynlibFormat % "nimrtl"
+    safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
+  else:
+    # posix relies on crappy LD_LIBRARY_PATH (ugh!):
+    var libpath = getEnv"LD_LIBRARY_PATH".string
+    # Temporarily add the lib directory to LD_LIBRARY_PATH:
+    putEnv("LD_LIBRARY_PATH", "lib:" & libpath)
+    var serverDll = DynlibFormat % "server"
+    safeCopyFile("tests/dll" / serverDll, "lib" / serverDll)
+
+  testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl",
+                       cat, actionRun)
+
+proc dllTests(r: var TResults, cat: Category, options: string) =
+  # dummy compile result:
+  var c = initResults()
+
+  runBasicDLLTest c, r, cat, options
+  runBasicDLLTest c, r, cat, options & " -d:release"
+  runBasicDLLTest c, r, cat, options & " --gc:boehm"
+  runBasicDLLTest c, r, cat, options & " -d:release --gc:boehm"
+
+# ------------------------------ GC tests -------------------------------------
+
+proc gcTests(r: var TResults, cat: Category, options: string) =
+  template testWithoutMs(filename: expr): stmt =
+    testSpec r, makeTest("tests/gc" / filename, options, cat, actionRun)
+    testSpec r, makeTest("tests/gc" / filename, options &
+                  " -d:release", cat, actionRun)
+    testSpec r, makeTest("tests/gc" / filename, options &
+                  " -d:release -d:useRealtimeGC", cat, actionRun)
+
+  template test(filename: expr): stmt =
+    testWithoutMs filename
+    testSpec r, makeTest("tests/gc" / filename, options &
+                  " --gc:markAndSweep", cat, actionRun)
+    testSpec r, makeTest("tests/gc" / filename, options &
+                  " -d:release --gc:markAndSweep", cat, actionRun)
+
+  test "growobjcrash"
+  test "gcbench"
+  test "gcleak"
+  test "gcleak2"
+  test "gctest"
+  test "gcleak3"
+  test "gcleak4"
+  # Disabled because it works and takes too long to run:
+  #test "gcleak5"
+  test "weakrefs"
+  test "cycleleak"
+  test "closureleak"
+  testWithoutMs "refarrayleak"
+
+  test "stackrefleak"
+  test "cyclecollector"
+
+proc longGCTests(r: var TResults, cat: Category, options: string) =
+  when defined(windows):
+    let cOptions = "gcc -ldl -DWIN"
+  else:
+    let cOptions = "gcc -ldl"
+
+  var c = initResults()
+  # According to ioTests, this should compile the file
+  testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile)
+  testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun)
+  testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun)
+
+# ------------------------- threading tests -----------------------------------
+
+proc threadTests(r: var TResults, cat: Category, options: string) =
+  template test(filename: expr): stmt =
+    testSpec r, makeTest("tests/threads" / filename, options, cat, actionRun)
+    testSpec r, makeTest("tests/threads" / filename, options &
+      " -d:release", cat, actionRun)
+    testSpec r, makeTest("tests/threads" / filename, options &
+      " --tlsEmulation:on", cat, actionRun)
+
+  test "tactors"
+  test "tactors2"
+  test "threadex"
+  # deactivated because output capturing still causes problems sometimes:
+  #test "trecursive_actor"
+  #test "threadring"
+  #test "tthreadanalysis"
+  #test "tthreadsort"
+  test "tthreadanalysis2"
+  #test "tthreadanalysis3"
+  test "tthreadheapviolation1"
+
+# ------------------------- IO tests ------------------------------------------
+
+proc ioTests(r: var TResults, cat: Category, options: string) =
+  # We need readall_echo to be compiled for this test to run.
+  # dummy compile result:
+  var c = initResults()
+  testSpec c, makeTest("tests/system/helpers/readall_echo", options, cat)
+  testSpec r, makeTest("tests/system/io", options, cat)
+
+# ------------------------- debugger tests ------------------------------------
+
+proc debuggerTests(r: var TResults, cat: Category, options: string) =
+  testNoSpec r, makeTest("tools/nimgrep", options & " --debugger:on", cat)
+
+# ------------------------- JS tests ------------------------------------------
+
+proc jsTests(r: var TResults, cat: Category, options: string) =
+  template test(filename: expr): stmt =
+    testSpec r, makeTest(filename, options & " -d:nodejs", cat,
+                         actionRun, targetJS)
+    testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat,
+                         actionRun, targetJS)
+
+  for t in os.walkFiles("tests/js/t*.nim"):
+    test(t)
+  for testfile in ["exception/texceptions", "exception/texcpt1",
+                   "exception/texcsub", "exception/tfinally",
+                   "exception/tfinally2", "exception/tfinally3",
+                   "actiontable/tactiontable", "method/tmultim1",
+                   "method/tmultim3", "method/tmultim4"]:
+    test "tests/" & testfile & ".nim"
+
+# ------------------------- manyloc -------------------------------------------
+#proc runSpecialTests(r: var TResults, options: string) =
+#  for t in ["lib/packages/docutils/highlite"]:
+#    testSpec(r, t, options)
+
+proc findMainFile(dir: string): string =
+  # finds the file belonging to ".nim.cfg"; if there is no such file
+  # it returns the some ".nim" file if there is only one:
+  const cfgExt = ".nim.cfg"
+  result = ""
+  var nimFiles = 0
+  for kind, file in os.walkDir(dir):
+    if kind == pcFile:
+      if file.endsWith(cfgExt): return file[.. ^(cfgExt.len+1)] & ".nim"
+      elif file.endsWith(".nim"):
+        if result.len == 0: result = file
+        inc nimFiles
+  if nimFiles != 1: result.setlen(0)
+
+proc manyLoc(r: var TResults, cat: Category, options: string) =
+  for kind, dir in os.walkDir("tests/manyloc"):
+    if kind == pcDir:
+      let mainfile = findMainFile(dir)
+      if mainfile != "":
+        testNoSpec r, makeTest(mainfile, options, cat)
+
+proc compileExample(r: var TResults, pattern, options: string, cat: Category) =
+  for test in os.walkFiles(pattern):
+    testNoSpec r, makeTest(test, options, cat)
+
+proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
+  for test in os.walkFiles(pattern):
+    let contents = readFile(test).string
+    if contents.contains("when isMainModule"):
+      testSpec r, makeTest(test, options, cat, actionRunNoSpec)
+    else:
+      testNoSpec r, makeTest(test, options, cat, actionCompile)
+
+# ----------------------------- nimble ----------------------------------------
+type PackageFilter = enum
+  pfCoreOnly
+  pfExtraOnly
+  pfAll
+
+let
+  nimbleExe = findExe("nimble")
+  nimbleDir = getHomeDir() / ".nimble"
+  packageDir = nimbleDir / "pkgs"
+  packageIndex = nimbleDir / "packages.json"
+
+proc waitForExitEx(p: Process): int =
+  var outp = outputStream(p)
+  var line = newStringOfCap(120).TaintedString
+  while true:
+    if outp.readLine(line):
+      discard
+    else:
+      result = peekExitCode(p)
+      if result != -1: break
+  close(p)
+
+proc getPackageDir(package: string): string =
+  ## TODO - Replace this with dom's version comparison magic.
+  var commandOutput = execCmdEx("nimble path $#" % package)
+  if commandOutput.exitCode != QuitSuccess:
+    return ""
+  else:
+    result = commandOutput[0].string
+
+iterator listPackages(filter: PackageFilter): tuple[name, url: string] =
+  let packageList = parseFile(packageIndex)
+
+  for package in packageList.items():
+    let
+      name = package["name"].str
+      url = package["url"].str
+      isCorePackage = "nim-lang" in normalize(url)
+    case filter:
+    of pfCoreOnly:
+      if isCorePackage:
+        yield (name, url)
+    of pfExtraOnly:
+      if not isCorePackage:
+        yield (name, url)
+    of pfAll:
+      yield (name, url)
+
+proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
+  if nimbleExe == "":
+    echo("[Warning] - Cannot run nimble tests: Nimble binary not found.")
+    return
+
+  if execCmd("$# update" % nimbleExe) == QuitFailure:
+    echo("[Warning] - Cannot run nimble tests: Nimble update failed.")
+    return
+
+  let packageFileTest = makeTest("PackageFileParsed", "", cat)
+  try:
+    for name, url in listPackages(filter):
+      var test = makeTest(name, "", cat)
+      echo(url)
+      let
+        installProcess = startProcess(nimbleExe, "", ["install", "-y", name])
+        installStatus = waitForExitEx(installProcess)
+      installProcess.close
+      if installStatus != QuitSuccess:
+        r.addResult(test, "", "", reInstallFailed)
+        continue
+
+      let
+        buildPath = getPackageDir(name).strip
+        buildProcess = startProcess(nimbleExe, buildPath, ["build"])
+        buildStatus = waitForExitEx(buildProcess)
+      buildProcess.close
+      if buildStatus != QuitSuccess:
+        r.addResult(test, "", "", reBuildFailed)
+      r.addResult(test, "", "", reSuccess)
+    r.addResult(packageFileTest, "", "", reSuccess)
+  except JsonParsingError:
+    echo("[Warning] - Cannot run nimble tests: Invalid package file.")
+    r.addResult(packageFileTest, "", "", reBuildFailed)
+
+
+# ----------------------------------------------------------------------------
+
+const AdditionalCategories = ["debugger", "examples", "lib"]
+
+proc `&.?`(a, b: string): string =
+  # candidate for the stdlib?
+  result = if b.startswith(a): b else: a & b
+
+proc `&?.`(a, b: string): string =
+  # candidate for the stdlib?
+  result = if a.endswith(b): a else: a & b
+
+proc processCategory(r: var TResults, cat: Category, options: string) =
+  case cat.string.normalize
+  of "rodfiles":
+    discard # Disabled for now
+    #compileRodFiles(r, cat, options)
+    #runRodFiles(r, cat, options)
+  of "js":
+    # XXX JS doesn't need to be special anymore
+    jsTests(r, cat, options)
+  of "dll":
+    dllTests(r, cat, options)
+  of "gc":
+    gcTests(r, cat, options)
+  of "longgc":
+    longGCTests(r, cat, options)
+  of "debugger":
+    debuggerTests(r, cat, options)
+  of "manyloc":
+    manyLoc r, cat, options
+  of "threads":
+    threadTests r, cat, options & " --threads:on"
+  of "io":
+    ioTests r, cat, options
+  of "lib":
+    testStdlib(r, "lib/pure/*.nim", options, cat)
+    testStdlib(r, "lib/packages/docutils/highlite", options, cat)
+  of "examples":
+    compileExample(r, "examples/*.nim", options, cat)
+    compileExample(r, "examples/gtk/*.nim", options, cat)
+    compileExample(r, "examples/talk/*.nim", options, cat)
+  of "nimble-core":
+    testNimblePackages(r, cat, pfCoreOnly)
+  of "nimble-extra":
+    testNimblePackages(r, cat, pfExtraOnly)
+  of "nimble-all":
+    testNimblePackages(r, cat, pfAll)
+  else:
+    for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
+      testSpec r, makeTest(name, options, cat)
diff --git a/tests/testament/css/boilerplate.css b/tests/testament/css/boilerplate.css
new file mode 100644
index 000000000..b209b5aa1
--- /dev/null
+++ b/tests/testament/css/boilerplate.css
@@ -0,0 +1,138 @@
+/* ==== Scroll down to find where to put your styles :) ==== */
+
+/*  HTML5 ✰ Boilerplate  */
+
+html, body, div, span, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
+small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section, summary,
+time, mark, audio, video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font-size: 100%;
+  font: inherit;
+  vertical-align: baseline;
+}
+
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+  display: block;
+}
+
+blockquote, q { quotes: none; }
+blockquote:before, blockquote:after,
+q:before, q:after { content: ''; content: none; }
+ins { background-color: #ff9; color: #000; text-decoration: none; }
+mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
+del { text-decoration: line-through; }
+abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
+table { border-collapse: collapse; border-spacing: 0; }
+hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
+input, select { vertical-align: middle; }
+
+body { font:13px/1.231 sans-serif; *font-size:small; } 
+select, input, textarea, button { font:99% sans-serif; }
+pre, code, kbd, samp { font-family: monospace, sans-serif; }
+
+html { overflow-y: scroll; }
+a:hover, a:active { outline: none; }
+ul, ol { margin-left: 2em; }
+ol { list-style-type: decimal; }
+nav ul, nav li { margin: 0; list-style:none; list-style-image: none; }
+small { font-size: 85%; }
+strong, th { font-weight: bold; }
+td { vertical-align: top; }
+
+sub, sup { font-size: 75%; line-height: 0; position: relative; }
+sup { top: -0.5em; }
+sub { bottom: -0.25em; }
+
+pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; }
+textarea { overflow: auto; }
+.ie6 legend, .ie7 legend { margin-left: -7px; } 
+input[type="radio"] { vertical-align: text-bottom; }
+input[type="checkbox"] { vertical-align: bottom; }
+.ie7 input[type="checkbox"] { vertical-align: baseline; }
+.ie6 input { vertical-align: text-bottom; }
+label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; }
+button, input, select, textarea { margin: 0; }
+input:valid, textarea:valid   {  }
+input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; }
+.no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; }
+
+a:link { -webkit-tap-highlight-color: #FF5E99; }
+
+button {  width: auto; overflow: visible; }
+.ie7 img { -ms-interpolation-mode: bicubic; }
+
+body, select, input, textarea {  color: #444; }
+h1, h2, h3, h4, h5, h6 { font-weight: bold; }
+a, a:active, a:visited { color: #607890; }
+a:hover { color: #036; }
+
+/*
+    // ========================================== \\
+   ||                                              ||
+   ||               Your styles !                  ||
+   ||                                              ||
+    \\ ========================================== //
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; }
+.hidden { display: none; visibility: hidden; }
+.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
+.visuallyhidden.focusable:active,
+.visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; }
+.invisible { visibility: hidden; }
+.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
+.clearfix:after { clear: both; }
+.clearfix { zoom: 1; }
+
+
+@media all and (orientation:portrait) {
+
+}
+
+@media all and (orientation:landscape) {
+
+}
+
+@media screen and (max-device-width: 480px) {
+
+  /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
+}
+
+
+@media print {
+  * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important;
+  -ms-filter: none !important; } 
+  a, a:visited { color: #444 !important; text-decoration: underline; }
+  a[href]:after { content: " (" attr(href) ")"; }
+  abbr[title]:after { content: " (" attr(title) ")"; }
+  .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }  
+  pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
+  thead { display: table-header-group; }
+  tr, img { page-break-inside: avoid; }
+  @page { margin: 0.5cm; }
+  p, h2, h3 { orphans: 3; widows: 3; }
+  h2, h3{ page-break-after: avoid; }
+}
diff --git a/tests/testament/css/style.css b/tests/testament/css/style.css
new file mode 100644
index 000000000..43a8add68
--- /dev/null
+++ b/tests/testament/css/style.css
@@ -0,0 +1,114 @@
+body {
+  font-size: medium;
+}
+
+div#header {
+  font-size: 2em;
+  background-color: #3d3d3d;
+  border-bottom: solid 2px #000000;
+  padding: 0.25em;
+  color: #ffffff;
+}
+
+div#content {
+  margin: 0.5em;
+}
+
+table {
+  text-align: left;
+  margin-bottom: 0.5em;
+}
+
+table td, table th {
+  padding: 0.15em 0.5em;
+}
+
+tr:nth-child(even) {
+  background-color: #eee;
+}
+
+/* Awesome buttons :P */
+
+a.button {
+  border-radius: 2px 2px 2px 2px;
+  background: -moz-linear-gradient(top, #f7f7f7, #ebebeb);
+  background: -webkit-linear-gradient(top, #f7f7f7, #ebebeb);
+  background: -o-linear-gradient(top, #f7f7f7, #ebebeb);
+  text-decoration: none;
+  color: #3d3d3d;
+  padding: 5px;
+  border: solid 1px #9d9d9d;
+  display: inline-block;
+  position: relative;
+  text-align: center;
+  font-size: small;
+}
+
+a.button.active {
+  background: -moz-linear-gradient(top, #00B40C, #03A90E);
+  background: -webkit-linear-gradient(top, #00B40C, #03A90E);
+  background: -o-linear-gradient(top, #00B40C, #03A90E);
+  border: solid 1px #148420;
+  color: #ffffff;
+}
+
+a.button.left {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+
+a.button.middle {
+  border-radius: 0;
+  border-left: 0;
+}
+
+a.button.right {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+  border-left: 0;
+}
+
+a.button:hover {
+  background: -moz-linear-gradient(top, #0099c7, #0294C1);
+  background: -webkit-linear-gradient(top, #0099c7, #0294C1);
+  background: -o-linear-gradient(top, #0099c7, #0294C1);
+  border: solid 1px #077A9C;
+  color: #ffffff;
+}
+
+a.button.middle:hover, a.button.right:hover {
+  border-left: 0;
+}
+
+a.button span.download {
+  background-image: url("../images/icons.png");
+  background-repeat: no-repeat;
+  display: inline-block;
+  margin: auto 3px auto auto;
+  height: 15px;
+  width: 14px;
+  position: relative;
+  background-position: 0 -30px;
+  top: 3px;
+}
+
+a.button span.book {
+  background-image: url("../images/icons.png");
+  background-repeat: no-repeat;
+  display: inline-block;
+  margin: auto 3px auto auto;
+  height: 15px;
+  width: 14px;
+  position: relative;
+  background-position: 0 0;
+  top: 3px;
+}
+
+a.button.active span.download, a.button:hover span.download {
+  background-position: 0 -45px;
+}
+
+a.button.active span.book, a.button:hover span.book {
+  background-position: 0 -15px;
+}
+
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
new file mode 100644
index 000000000..a9f739995
--- /dev/null
+++ b/tests/testament/htmlgen.nim
@@ -0,0 +1,228 @@
+#
+#
+#            Nim Tester
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## HTML generator for the tester.
+
+import db_sqlite, cgi, backend, strutils, json
+
+const
+  TableHeader = """<table border="1">
+                      <tr><td>Test</td><td>Category</td><td>Target</td>
+                          <td>Action</td>
+                          <td>Expected</td>
+                          <td>Given</td>
+                          <td>Success</td></tr>"""
+  TableFooter = "</table>"
+  HtmlBegin = """<html>
+    <head>
+      <title>Test results</title>
+      <style type="text/css">
+      <!--""" & slurp("css/boilerplate.css") & "\n" &
+                slurp("css/style.css") &
+      """
+ul#tabs { list-style-type: none; margin: 30px 0 0 0; padding: 0 0 0.3em 0; }
+ul#tabs li { display: inline; }
+ul#tabs li a { color: #42454a; background-color: #dedbde;
+               border: 1px solid #c9c3ba; border-bottom: none;
+               padding: 0.3em; text-decoration: none; }
+ul#tabs li a:hover { background-color: #f1f0ee; }
+ul#tabs li a.selected { color: #000; background-color: #f1f0ee;
+                        font-weight: bold; padding: 0.7em 0.3em 0.38em 0.3em; }
+div.tabContent { border: 1px solid #c9c3ba;
+                 padding: 0.5em; background-color: #f1f0ee; }
+div.tabContent.hide { display: none; }
+      -->
+    </style>
+    <script>
+
+    var tabLinks = new Array();
+    var contentDivs = new Array();
+
+    function init() {
+      // Grab the tab links and content divs from the page
+      var tabListItems = document.getElementById('tabs').childNodes;
+      for (var i = 0; i < tabListItems.length; i++) {
+        if (tabListItems[i].nodeName == "LI") {
+          var tabLink = getFirstChildWithTagName(tabListItems[i], 'A');
+          var id = getHash(tabLink.getAttribute('href'));
+          tabLinks[id] = tabLink;
+          contentDivs[id] = document.getElementById(id);
+        }
+      }
+      // Assign onclick events to the tab links, and
+      // highlight the first tab
+      var i = 0;
+      for (var id in tabLinks) {
+        tabLinks[id].onclick = showTab;
+        tabLinks[id].onfocus = function() { this.blur() };
+        if (i == 0) tabLinks[id].className = 'selected';
+        i++;
+      }
+      // Hide all content divs except the first
+      var i = 0;
+      for (var id in contentDivs) {
+        if (i != 0) contentDivs[id].className = 'tabContent hide';
+        i++;
+      }
+    }
+
+    function showTab() {
+      var selectedId = getHash(this.getAttribute('href'));
+
+      // Highlight the selected tab, and dim all others.
+      // Also show the selected content div, and hide all others.
+      for (var id in contentDivs) {
+        if (id == selectedId) {
+          tabLinks[id].className = 'selected';
+          contentDivs[id].className = 'tabContent';
+        } else {
+          tabLinks[id].className = '';
+          contentDivs[id].className = 'tabContent hide';
+        }
+      }
+      // Stop the browser following the link
+      return false;
+    }
+
+    function getFirstChildWithTagName(element, tagName) {
+      for (var i = 0; i < element.childNodes.length; i++) {
+        if (element.childNodes[i].nodeName == tagName) return element.childNodes[i];
+      }
+    }
+    function getHash(url) {
+      var hashPos = url.lastIndexOf('#');
+      return url.substring(hashPos + 1);
+    }
+    </script>
+
+    </head>
+    <body onload="init()">"""
+
+  HtmlEnd = "</body></html>"
+
+proc td(s: string): string =
+  result = "<td>" & s.substr(0, 200).xmlEncode & "</td>"
+
+proc getCommit(db: TDbConn, c: int): string =
+  var commit = c
+  for thisCommit in db.rows(sql"select id from [Commit] order by id desc"):
+    if commit == 0: result = thisCommit[0]
+    inc commit
+
+proc generateHtml*(filename: string, commit: int; onlyFailing: bool) =
+  const selRow = """select name, category, target, action,
+                           expected, given, result
+                    from TestResult
+                    where [commit] = ? and machine = ?
+                    order by category"""
+  var db = open(connection="testament.db", user="testament", password="",
+                database="testament")
+  # search for proper commit:
+  let lastCommit = db.getCommit(commit)
+
+  var outfile = open(filename, fmWrite)
+  outfile.write(HtmlBegin)
+
+  let commit = db.getValue(sql"select hash from [Commit] where id = ?",
+                            lastCommit)
+  let branch = db.getValue(sql"select branch from [Commit] where id = ?",
+                            lastCommit)
+  outfile.write("<p><b>$# $#</b></p>" % [branch, commit])
+
+  # generate navigation:
+  outfile.write("""<ul id="tabs">""")
+  for m in db.rows(sql"select id, name, os, cpu from Machine order by id"):
+    outfile.writeln """<li><a href="#$#">$#: $#, $#</a></li>""" % m
+  outfile.write("</ul>")
+
+  for currentMachine in db.rows(sql"select id from Machine order by id"):
+    let m = currentMachine[0]
+    outfile.write("""<div class="tabContent" id="$#">""" % m)
+
+    outfile.write(TableHeader)
+    for row in db.rows(sql(selRow), lastCommit, m):
+      if onlyFailing and row.len > 0 and row[row.high] == "reSuccess":
+        discard
+      else:
+        outfile.write("<tr>")
+        for x in row:
+          outfile.write(x.td)
+        outfile.write("</tr>")
+
+    outfile.write(TableFooter)
+    outfile.write("</div>")
+  outfile.write(HtmlEnd)
+  close(db)
+  close(outfile)
+
+proc generateJson*(filename: string, commit: int) =
+  const
+    selRow = """select count(*),
+                           sum(result = 'reSuccess'),
+                           sum(result = 'reIgnored')
+                from TestResult
+                where [commit] = ? and machine = ?
+                order by category"""
+    selDiff = """select A.category || '/' || A.target || '/' || A.name,
+                        A.result,
+                        B.result
+                from TestResult A
+                inner join TestResult B
+                on A.name = B.name and A.category = B.category
+                where A.[commit] = ? and B.[commit] = ? and A.machine = ?
+                   and A.result != B.result"""
+    selResults = """select
+                      category || '/' || target || '/' || name,
+                      category, target, action, result, expected, given
+                    from TestResult
+                    where [commit] = ?"""
+  var db = open(connection="testament.db", user="testament", password="",
+                database="testament")
+  let lastCommit = db.getCommit(commit)
+  if lastCommit.isNil:
+    quit "cannot determine commit " & $commit
+
+  let previousCommit = db.getCommit(commit-1)
+
+  var outfile = open(filename, fmWrite)
+
+  let machine = $backend.getMachine(db)
+  let data = db.getRow(sql(selRow), lastCommit, machine)
+
+  outfile.writeln("""{"total": $#, "passed": $#, "skipped": $#""" % data)
+
+  let results = newJArray()
+  for row in db.rows(sql(selResults), lastCommit):
+    var obj = newJObject()
+    obj["name"] = %row[0]
+    obj["category"] = %row[1]
+    obj["target"] = %row[2]
+    obj["action"] = %row[3]
+    obj["result"] = %row[4]
+    obj["expected"] = %row[5]
+    obj["given"] = %row[6]
+    results.add(obj)
+  outfile.writeln(""", "results": """)
+  outfile.write(results.pretty)
+
+  if not previousCommit.isNil:
+    let diff = newJArray()
+
+    for row in db.rows(sql(selDiff), previousCommit, lastCommit, machine):
+      var obj = newJObject()
+      obj["name"] = %row[0]
+      obj["old"] = %row[1]
+      obj["new"] = %row[2]
+      diff.add obj
+    outfile.writeln(""", "diff": """)
+    outfile.writeln(diff.pretty)
+
+  outfile.writeln "}"
+  close(db)
+  close(outfile)
diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim
new file mode 100644
index 000000000..9306bf025
--- /dev/null
+++ b/tests/testament/specs.nim
@@ -0,0 +1,151 @@
+#
+#
+#            Nim Tester
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import parseutils, strutils, os, osproc, streams, parsecfg
+
+const
+  cmdTemplate* = r"nim $target --hints:on -d:testing $options $file"
+
+type
+  TTestAction* = enum
+    actionCompile = "compile"
+    actionRun = "run"
+    actionReject = "reject"
+    actionRunNoSpec = "runNoSpec"
+  TResultEnum* = enum
+    reNimcCrash,     # nim compiler seems to have crashed
+    reMsgsDiffer,       # error messages differ
+    reFilesDiffer,      # expected and given filenames differ
+    reLinesDiffer,      # expected and given line numbers differ
+    reOutputsDiffer,
+    reExitcodesDiffer,
+    reInvalidPeg,
+    reCodegenFailure,
+    reCodeNotFound,
+    reExeNotFound,
+    reInstallFailed     # package installation failed
+    reBuildFailed       # package building failed
+    reIgnored,          # test is ignored
+    reSuccess           # test was successful
+  TTarget* = enum
+    targetC = "C"
+    targetCpp = "C++"
+    targetObjC = "ObjC"
+    targetJS = "JS"
+
+  TSpec* = object
+    action*: TTestAction
+    file*, cmd*: string
+    outp*: string
+    line*, column*: int
+    exitCode*: int
+    msg*: string
+    ccodeCheck*: string
+    err*: TResultEnum
+    substr*, sortoutput*: bool
+    targets*: set[TTarget]
+    nimout*: string
+
+const
+  targetToExt*: array[TTarget, string] = ["c", "cpp", "m", "js"]
+  targetToCmd*: array[TTarget, string] = ["c", "cpp", "objc", "js"]
+
+when not declared(parseCfgBool):
+  # candidate for the stdlib:
+  proc parseCfgBool(s: string): bool =
+    case normalize(s)
+    of "y", "yes", "true", "1", "on": result = true
+    of "n", "no", "false", "0", "off": result = false
+    else: raise newException(ValueError, "cannot interpret as a bool: " & s)
+
+proc extractSpec(filename: string): string =
+  const tripleQuote = "\"\"\""
+  var x = readFile(filename).string
+  var a = x.find(tripleQuote)
+  var b = x.find(tripleQuote, a+3)
+  # look for """ only in the first section
+  if a >= 0 and b > a and a < 40:
+    result = x.substr(a+3, b-1).replace("'''", tripleQuote)
+  else:
+    #echo "warning: file does not contain spec: " & filename
+    result = ""
+
+when not defined(nimhygiene):
+  {.pragma: inject.}
+
+template parseSpecAux(fillResult: untyped) =
+  var ss = newStringStream(extractSpec(filename))
+  var p {.inject.}: CfgParser
+  open(p, ss, filename, 1)
+  while true:
+    var e {.inject.} = next(p)
+    case e.kind
+    of cfgEof: break
+    of cfgSectionStart, cfgOption, cfgError:
+      echo ignoreMsg(p, e)
+    of cfgKeyValuePair:
+      fillResult
+  close(p)
+
+proc specDefaults*(result: var TSpec) =
+  result.msg = ""
+  result.outp = ""
+  result.nimout = ""
+  result.ccodeCheck = ""
+  result.cmd = cmdTemplate
+  result.line = 0
+  result.column = 0
+
+proc parseSpec*(filename: string): TSpec =
+  specDefaults(result)
+  result.file = filename
+  parseSpecAux:
+    case normalize(e.key)
+    of "action":
+      case e.value.normalize
+      of "compile": result.action = actionCompile
+      of "run": result.action = actionRun
+      of "reject": result.action = actionReject
+      else: echo ignoreMsg(p, e)
+    of "file": result.file = e.value
+    of "line": discard parseInt(e.value, result.line)
+    of "column": discard parseInt(e.value, result.column)
+    of "output":
+      result.action = actionRun
+      result.outp = e.value
+    of "outputsub":
+      result.action = actionRun
+      result.outp = e.value
+      result.substr = true
+    of "sortoutput":
+      result.sortoutput = parseCfgBool(e.value)
+    of "exitcode":
+      discard parseInt(e.value, result.exitCode)
+    of "msg":
+      result.msg = e.value
+      if result.action != actionRun:
+        result.action = actionCompile
+    of "errormsg":
+      result.msg = e.value
+      result.action = actionReject
+    of "nimout":
+      result.nimout = e.value
+    of "disabled":
+      if parseCfgBool(e.value): result.err = reIgnored
+    of "cmd": result.cmd = e.value
+    of "ccodecheck": result.ccodeCheck = e.value
+    of "target", "targets":
+      for v in e.value.normalize.split:
+        case v
+        of "c": result.targets.incl(targetC)
+        of "cpp", "c++": result.targets.incl(targetCpp)
+        of "objc": result.targets.incl(targetObjC)
+        of "js": result.targets.incl(targetJS)
+        else: echo ignoreMsg(p, e)
+    else: echo ignoreMsg(p, e)
diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim
new file mode 100644
index 000000000..62dafee80
--- /dev/null
+++ b/tests/testament/tester.nim
@@ -0,0 +1,360 @@
+#
+#
+#            Nim Tester
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This program verifies Nim against the testcases.
+
+import
+  parseutils, strutils, pegs, os, osproc, streams, parsecfg, json,
+  marshal, backend, parseopt, specs, htmlgen, browsers, terminal,
+  algorithm, compiler/nodejs
+
+const
+  resultsFile = "testresults.html"
+  jsonFile = "testresults.json"
+  Usage = """Usage:
+  tester [options] command [arguments]
+
+Command:
+  all                         run all tests
+  c|category <category>       run all the tests of a certain category
+  html [commit]               generate $1 from the database; uses the latest
+                              commit or a specific one (use -1 for the commit
+                              before latest etc)
+Arguments:
+  arguments are passed to the compiler
+Options:
+  --print                   also print results to the console
+  --failing                 only show failing/ignored tests
+  --pedantic                return non-zero status code if there are failures
+""" % resultsFile
+
+type
+  Category = distinct string
+  TResults = object
+    total, passed, skipped: int
+    data: string
+
+  TTest = object
+    name: string
+    cat: Category
+    options: string
+    target: TTarget
+    action: TTestAction
+
+# ----------------------------------------------------------------------------
+
+let
+  pegLineError =
+    peg"{[^(]*} '(' {\d+} ', ' {\d+} ') ' ('Error') ':' \s* {.*}"
+  pegOtherError = peg"'Error:' \s* {.*}"
+  pegSuccess = peg"'Hint: operation successful'.*"
+  pegOfInterest = pegLineError / pegOtherError
+
+proc callCompiler(cmdTemplate, filename, options: string,
+                  target: TTarget): TSpec =
+  let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
+                       "options", options, "file", filename.quoteShell])
+  var p = startProcess(command=c[0], args=c[1.. ^1],
+                       options={poStdErrToStdOut, poUseShell})
+  let outp = p.outputStream
+  var suc = ""
+  var err = ""
+  var x = newStringOfCap(120)
+  result.nimout = ""
+  while outp.readLine(x.TaintedString) or running(p):
+    result.nimout.add(x & "\n")
+    if x =~ pegOfInterest:
+      # `err` should contain the last error/warning message
+      err = x
+    elif x =~ pegSuccess:
+      suc = x
+  close(p)
+  result.msg = ""
+  result.file = ""
+  result.outp = ""
+  result.line = 0
+  result.column = 0
+  if err =~ pegLineError:
+    result.file = extractFilename(matches[0])
+    result.line = parseInt(matches[1])
+    result.column = parseInt(matches[2])
+    result.msg = matches[3]
+  elif err =~ pegOtherError:
+    result.msg = matches[0]
+  elif suc =~ pegSuccess:
+    result.err = reSuccess
+
+proc callCCompiler(cmdTemplate, filename, options: string,
+                  target: TTarget): TSpec =
+  let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
+                       "options", options, "file", filename.quoteShell])
+  var p = startProcess(command="gcc", args=c[5.. ^1],
+                       options={poStdErrToStdOut, poUsePath})
+  let outp = p.outputStream
+  var x = newStringOfCap(120)
+  result.nimout = ""
+  result.msg = ""
+  result.file = ""
+  result.outp = ""
+  result.line = -1
+  while outp.readLine(x.TaintedString) or running(p):
+    result.nimout.add(x & "\n")
+  close(p)
+  if p.peekExitCode == 0:
+    result.err = reSuccess
+
+proc initResults: TResults =
+  result.total = 0
+  result.passed = 0
+  result.skipped = 0
+  result.data = ""
+
+proc readResults(filename: string): TResults =
+  result = marshal.to[TResults](readFile(filename).string)
+
+proc writeResults(filename: string, r: TResults) =
+  writeFile(filename, $$r)
+
+proc `$`(x: TResults): string =
+  result = ("Tests passed: $1 / $3 <br />\n" &
+            "Tests skipped: $2 / $3 <br />\n") %
+            [$x.passed, $x.skipped, $x.total]
+
+proc addResult(r: var TResults, test: TTest,
+               expected, given: string, success: TResultEnum) =
+  let name = test.name.extractFilename & test.options
+  backend.writeTestResult(name = name,
+                          category = test.cat.string,
+                          target = $test.target,
+                          action = $test.action,
+                          result = $success,
+                          expected = expected,
+                          given = given)
+  r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success)
+  if success == reIgnored:
+    styledEcho styleBright, name, fgYellow, " [", $success, "]"
+  elif success != reSuccess:
+    styledEcho styleBright, name, fgRed, " [", $success, "]"
+    echo"Expected:"
+    styledEcho styleBright, expected
+    echo"Given:"
+    styledEcho styleBright, given
+
+proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
+  if strip(expected.msg) notin strip(given.msg):
+    r.addResult(test, expected.msg, given.msg, reMsgsDiffer)
+  elif extractFilename(expected.file) != extractFilename(given.file) and
+      "internal error:" notin expected.msg:
+    r.addResult(test, expected.file, given.file, reFilesDiffer)
+  elif expected.line   != given.line   and expected.line   != 0 or
+       expected.column != given.column and expected.column != 0:
+    r.addResult(test, $expected.line & ':' & $expected.column,
+                      $given.line    & ':' & $given.column,
+                      reLinesDiffer)
+  else:
+    r.addResult(test, expected.msg, given.msg, reSuccess)
+    inc(r.passed)
+
+proc generatedFile(path, name: string, target: TTarget): string =
+  let ext = targetToExt[target]
+  result = path / "nimcache" /
+    (if target == targetJS: path.splitPath.tail & "_" else: "compiler_") &
+    name.changeFileExt(ext)
+
+proc codegenCheck(test: TTest, check: string, given: var TSpec) =
+  try:
+    let (path, name, ext2) = test.name.splitFile
+    let genFile = generatedFile(path, name, test.target)
+    let contents = readFile(genFile).string
+    if check[0] == '\\':
+      # little hack to get 'match' support:
+      if not contents.match(check.peg):
+        given.err = reCodegenFailure
+    elif contents.find(check.peg) < 0:
+      given.err = reCodegenFailure
+  except ValueError:
+    given.err = reInvalidPeg
+    echo getCurrentExceptionMsg()
+  except IOError:
+    given.err = reCodeNotFound
+
+proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) =
+  let exp = expectedNimout.strip.replace("\C\L", "\L")
+  let giv = given.nimout.strip.replace("\C\L", "\L")
+  if exp notin giv:
+    given.err = reMsgsDiffer
+
+proc makeDeterministic(s: string): string =
+  var x = splitLines(s)
+  sort(x, system.cmp)
+  result = join(x, "\n")
+
+proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
+                         r: var TResults) =
+  var expectedmsg: string = ""
+  var givenmsg: string = ""
+  if given.err == reSuccess:
+    if expected.ccodeCheck.len > 0:
+      codegenCheck(test, expected.ccodeCheck, given)
+      expectedmsg = expected.ccodeCheck
+      givenmsg = given.msg
+    if expected.nimout.len > 0:
+      expectedmsg = expected.nimout
+      givenmsg = given.nimout.strip
+      nimoutCheck(test, expectedmsg, given)
+  if given.err == reSuccess: inc(r.passed)
+  r.addResult(test, expectedmsg, givenmsg, given.err)
+
+proc testSpec(r: var TResults, test: TTest) =
+  # major entry point for a single test
+  let tname = test.name.addFileExt(".nim")
+  inc(r.total)
+  styledEcho "Processing ", fgCyan, extractFilename(tname)
+  var expected: TSpec
+  if test.action != actionRunNoSpec:
+    expected = parseSpec(tname)
+  else:
+    specDefaults expected
+    expected.action = actionRunNoSpec
+  if expected.err == reIgnored:
+    r.addResult(test, "", "", reIgnored)
+    inc(r.skipped)
+  else:
+    case expected.action
+    of actionCompile:
+      var given = callCompiler(expected.cmd, test.name,
+        test.options & " --hint[Path]:off --hint[Processing]:off", test.target)
+      compilerOutputTests(test, given, expected, r)
+    of actionRun, actionRunNoSpec:
+      var given = callCompiler(expected.cmd, test.name, test.options,
+                               test.target)
+      if given.err != reSuccess:
+        r.addResult(test, "", given.msg, given.err)
+      else:
+        var exeFile: string
+        if test.target == targetJS:
+          let (dir, file, ext) = splitFile(tname)
+          exeFile = dir / "nimcache" / file & ".js"
+        else:
+          exeFile = changeFileExt(tname, ExeExt)
+        if existsFile(exeFile):
+          let nodejs = findNodeJs()
+          if test.target == targetJS and nodejs == "":
+            r.addResult(test, expected.outp, "nodejs binary not in PATH",
+                        reExeNotFound)
+            return
+          var (buf, exitCode) = execCmdEx(
+            (if test.target == targetJS: nodejs & " " else: "") & exeFile)
+          if exitCode != expected.exitCode:
+            r.addResult(test, "exitcode: " & $expected.exitCode,
+                              "exitcode: " & $exitCode, reExitCodesDiffer)
+          else:
+            var bufB = strip(buf.string)
+            if expected.sortoutput: bufB = makeDeterministic(bufB)
+            if bufB != strip(expected.outp):
+              if not (expected.substr and expected.outp in bufB):
+                given.err = reOutputsDiffer
+            compilerOutputTests(test, given, expected, r)
+        else:
+          r.addResult(test, expected.outp, "executable not found", reExeNotFound)
+    of actionReject:
+      var given = callCompiler(expected.cmd, test.name, test.options,
+                               test.target)
+      cmpMsgs(r, expected, given, test)
+
+proc testNoSpec(r: var TResults, test: TTest) =
+  # does not extract the spec because the file is not supposed to have any
+  let tname = test.name.addFileExt(".nim")
+  inc(r.total)
+  styledEcho "Processing ", fgCyan, extractFilename(tname)
+  let given = callCompiler(cmdTemplate, test.name, test.options, test.target)
+  r.addResult(test, "", given.msg, given.err)
+  if given.err == reSuccess: inc(r.passed)
+
+proc testC(r: var TResults, test: TTest) =
+  # runs C code. Doesn't support any specs, just goes by exit code.
+  let tname = test.name.addFileExt(".c")
+  inc(r.total)
+  styledEcho "Processing ", fgCyan, extractFilename(tname)
+  var given = callCCompiler(cmdTemplate, test.name & ".c", test.options, test.target)
+  if given.err != reSuccess:
+    r.addResult(test, "", given.msg, given.err)
+  elif test.action == actionRun:
+    let exeFile = changeFileExt(test.name, ExeExt)
+    var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell})
+    if exitCode != 0: given.err = reExitCodesDiffer
+  if given.err == reSuccess: inc(r.passed)
+
+proc makeTest(test, options: string, cat: Category, action = actionCompile,
+              target = targetC, env: string = ""): TTest =
+  # start with 'actionCompile', will be overwritten in the spec:
+  result = TTest(cat: cat, name: test, options: options,
+                 target: target, action: action)
+
+include categories
+
+# proc runCaasTests(r: var TResults) =
+#   for test, output, status, mode in caasTestsRunner():
+#     r.addResult(test, "", output & "-> " & $mode,
+#                 if status: reSuccess else: reOutputsDiffer)
+
+proc main() =
+  os.putenv "NIMTEST_NO_COLOR", "1"
+  os.putenv "NIMTEST_OUTPUT_LVL", "PRINT_FAILURES"
+
+  backend.open()
+  var optPrintResults = false
+  var optFailing = false
+  var optPedantic = false
+  var p = initOptParser()
+  p.next()
+  while p.kind == cmdLongoption:
+    case p.key.string.normalize
+    of "print", "verbose": optPrintResults = true
+    of "failing": optFailing = true
+    of "pedantic": optPedantic = true
+    else: quit Usage
+    p.next()
+  if p.kind != cmdArgument: quit Usage
+  var action = p.key.string.normalize
+  p.next()
+  var r = initResults()
+  case action
+  of "all":
+    let testsDir = "tests" & DirSep
+    for kind, dir in walkDir(testsDir):
+      assert testsDir.startsWith(testsDir)
+      let cat = dir[testsDir.len .. ^1]
+      if kind == pcDir and cat notin ["testament", "testdata", "nimcache"]:
+        processCategory(r, Category(cat), p.cmdLineRest.string)
+    for a in AdditionalCategories:
+      processCategory(r, Category(a), p.cmdLineRest.string)
+  of "c", "cat", "category":
+    var cat = Category(p.key)
+    p.next
+    processCategory(r, cat, p.cmdLineRest.string)
+  of "html":
+    var commit = 0
+    discard parseInt(p.cmdLineRest.string, commit)
+    generateHtml(resultsFile, commit, optFailing)
+    generateJson(jsonFile, commit)
+  else:
+    quit Usage
+
+  if optPrintResults:
+    if action == "html": openDefaultBrowser(resultsFile)
+    else: echo r, r.data
+  backend.close()
+  if optPedantic:
+    var failed = r.total - r.passed - r.skipped
+    if failed > 0 : quit(QuitFailure)
+
+if paramCount() == 0:
+  quit Usage
+main()
diff --git a/tests/testament/tester.nim.cfg b/tests/testament/tester.nim.cfg
new file mode 100644
index 000000000..27fd67075
--- /dev/null
+++ b/tests/testament/tester.nim.cfg
@@ -0,0 +1 @@
+path = "$nim" # For compiler/nodejs
diff --git a/tests/testdata/csvtest.csv b/tests/testdata/csvtest.csv
new file mode 100644
index 000000000..6e7e14103
--- /dev/null
+++ b/tests/testdata/csvtest.csv
@@ -0,0 +1,8 @@
+headerField1,headerField2,headerField3
+12,12132,"hallo ""
+ du"
+1,,
+,2,
+,,3
+1,2,3
+
diff --git a/tests/testdata/data.csv b/tests/testdata/data.csv
new file mode 100644
index 000000000..ea73f7387
--- /dev/null
+++ b/tests/testdata/data.csv
@@ -0,0 +1,6 @@
+Algo_A; Algo_B; Algo_C
+12; 12; 16
+2; 5; 9
+63; 65.3; 90
+0; 1.2; 3
+
diff --git a/tests/testdata/doc1.xml b/tests/testdata/doc1.xml
new file mode 100644
index 000000000..2895cc32f
--- /dev/null
+++ b/tests/testdata/doc1.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<root>
+  <tag>
+    <test arg="blah" arg2="test"/>
+    <test2>
+      bla ah absy hsh 
+      hsh
+      sjj
+    </test2>
+    <test><teh>bla</teh></test>
+  </tag>
+</root>
+
+
diff --git a/tests/testdata/jsontest.json b/tests/testdata/jsontest.json
new file mode 100644
index 000000000..3a815e50f
--- /dev/null
+++ b/tests/testdata/jsontest.json
@@ -0,0 +1,26 @@
+// Simple JSON test file
+// (c) 2011 Andreas Rumpf
+
+/* a long comment */
+
+{
+  "key1": null,
+  "obj": {"1": 2, "5": 4},
+  
+  "key2": [
+    {},
+    {   },
+    [],
+    
+    [ // empty array
+    ],
+    
+    -1e10 // another comment
+    
+  
+  ]        ,
+  "keyÄÖöoß\u00DF": false
+}
+
+// [{}, {899: 12, "x": "y"}, [], 123, 89, 89, "xyz", null, [], [], [1, 2, 3]]
+
diff --git a/tests/testdata/jsontest2.json b/tests/testdata/jsontest2.json
new file mode 100644
index 000000000..3a2294474
--- /dev/null
+++ b/tests/testdata/jsontest2.json
@@ -0,0 +1,80 @@
+{
+  "after": "b85008345e2faa23024b222e2e6b17f7ef8b6270", 
+  "before": "f469a6fba9a81ac06d813761e346673fbc8a6ef6", 
+  "commits": [
+    {
+      "added": [], 
+      "author": {
+        "email": "dominikpicheta@googlemail.com", 
+        "name": "dom96", 
+        "username": "dom96"
+      }, 
+      "id": "9e887b88a633c432d8e6859d7fab5429128aea7e", 
+      "message": "Added getPort and fixed a problem with the Disconnect event.", 
+      "modified": [
+        "Network\/SimpleIRC\/Core.hs"
+      ], 
+      "removed": [], 
+      "timestamp": "2010-10-24T03:16:30-07:00", 
+      "url": "https:\/\/github.com\/dom96\/SimpleIRC\/commit\/9e887b88a633c432d8e6859d7fab5429128aea7e"
+    }, 
+    {
+      "added": [
+        "tests\/channelNickTracking.hs"
+      ], 
+      "author": {
+        "email": "dominikpicheta@googlemail.com", 
+        "name": "dom96", 
+        "username": "dom96"
+      }, 
+      "id": "001c4a1834a95fa3cb4c6fefc3df9508c6e6b58a", 
+      "message": "Channel and nick tracking fully work now.", 
+      "modified": [
+        "Network\/SimpleIRC\/Core.hs", 
+        "Network\/SimpleIRC\/Messages.hs"
+      ], 
+      "removed": [], 
+      "timestamp": "2010-10-24T04:01:28-07:00", 
+      "url": "https:\/\/github.com\/dom96\/SimpleIRC\/commit\/001c4a1834a95fa3cb4c6fefc3df9508c6e6b58a"
+    }, 
+    {
+      "added": [], 
+      "author": {
+        "email": "dominikpicheta@googlemail.com", 
+        "name": "dom96", 
+        "username": "dom96"
+      }, 
+      "id": "b85008345e2faa23024b222e2e6b17f7ef8b6270", 
+      "message": "Forgot to export getPort.", 
+      "modified": [
+        "Network\/SimpleIRC\/Core.hs"
+      ], 
+      "removed": [], 
+      "timestamp": "2010-10-24T04:18:38-07:00", 
+      "url": "https:\/\/github.com\/dom96\/SimpleIRC\/commit\/b85008345e2faa23024b222e2e6b17f7ef8b6270"
+    }
+  ], 
+  "compare": "https:\/\/github.com\/dom96\/SimpleIRC\/compare\/f469a6f...b850083", 
+  "forced": false, 
+  "ref": "refs\/heads\/master", 
+  "repository": {
+    "created_at": "2010\/08\/13 10:24:57 -0700", 
+    "description": "IRC Library for Haskell", 
+    "fork": false, 
+    "forks": 1, 
+    "has_downloads": true, 
+    "has_issues": true, 
+    "has_wiki": true, 
+    "homepage": "http:\/\/hackage.haskell.org\/package\/simpleirc", 
+    "name": "SimpleIRC", 
+    "open_issues": 1, 
+    "owner": {
+      "email": "dominikpicheta@googlemail.com", 
+      "name": "dom96"
+    }, 
+    "private": false, 
+    "pushed_at": "2010\/10\/24 04:18:48 -0700", 
+    "url": "https:\/\/github.com\/dom96\/SimpleIRC", 
+    "watchers": 7
+  }
+}
diff --git a/tests/testdata/mycert.pem b/tests/testdata/mycert.pem
new file mode 100644
index 000000000..69039fe04
--- /dev/null
+++ b/tests/testdata/mycert.pem
@@ -0,0 +1,32 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAL9QXX/nuiFbizdI
+Uhg1D9gG0GIANENvKwdWTlOlZAoOqvjXPFLGh+87yhvkq4f5FcICkSDao2SfeZcP
+JsgD7T01owt8x48898+d91i7nIpr6IXGPyBxHOuaxAITY1D+MbbkhIGUVrEqKEOm
+qfS9cqPZaDNkx8xVef0HPCmqEme9AgMBAAECgYBxqrQCvJFQJG3QiL2N+GjTdyj0
+MR7cOf6cu2CKPifz+ccHVgpXO/Gj6Cgq7nAjt5B/1rqXhI+zxzSc1bm6+OpIfakS
+E0DLCFacECmL0v3c+XLxTtMhFZF5u7Yq0UMsuWmDSfRb4sbRjC+s+c51i5N0485k
+b3un/MDI/i/jD/YZGQJBAPLtcuMIwEblUR1uw7NFezXdauXCRFkekoSlJNvpdM/Z
+XDRcuWioek5yD8FvMpTz7H2e26Ev645JT5lIuN4Eti8CQQDJm+Qt9NYUohRsU279
+GYI3vXsXKKqmA22at4I3KRXPSeYV1vtQLYWWqGAXzgGkUEVBY0chmHyDcNwkUsNw
+svHTAkEAwOTpD/vX6bOXOD7GqKgoULozcqNScE2FXExhuzliJtTakT17f+4fyABs
+IFWynXIevBUTIqeRbJcr3HRRTwIAwwJBAJQ8XkL4IaxcG/4mPpY0ek13sZiumwKj
+xKQcx869E78tS9LFFlW2kuHafYUjQIvLRZC1aWinUO3oPsUqYW9s82cCQFjoods5
+YsWEJB2RKCT5nhyAXEZLehxF+FXr+JjLMHkuEINKTnHHKjHJ7LbMcTCKUJAcKDTA
+qZFEq5N1aT6DrAU=
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICgDCCAemgAwIBAgIJANpVfZSDAyNgMA0GCSqGSIb3DQEBBQUAMFkxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMjA2MDMxMjI4
+MDhaFw0xMzA2MDMxMjI4MDhaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l
+LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNV
+BAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAv1Bdf+e6
+IVuLN0hSGDUP2AbQYgA0Q28rB1ZOU6VkCg6q+Nc8UsaH7zvKG+Srh/kVwgKRINqj
+ZJ95lw8myAPtPTWjC3zHjzz3z533WLucimvohcY/IHEc65rEAhNjUP4xtuSEgZRW
+sSooQ6ap9L1yo9loM2THzFV5/Qc8KaoSZ70CAwEAAaNQME4wHQYDVR0OBBYEFF2n
+Of61swO+XSNrYb4T02tGx8afMB8GA1UdIwQYMBaAFF2nOf61swO+XSNrYb4T02tG
+x8afMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAEPHofdf4acaph5/e
++BzZGsMfRqdPgwp5sxjFKeTQI1A49VL7ykkb0iLKGfKZtvE8MjMrYjzt20E2bIZj
+8eCivT6TbNrVRoACCly/lH9fZfWOG6dBu/85IrTAhSKi8yjbRzmjWUkdrcEJ+ZtV
+1cahfFar4l4QwYgqp2pDd6ie+zE=
+-----END CERTIFICATE-----
diff --git a/tests/testdata/string.txt b/tests/testdata/string.txt
new file mode 100644
index 000000000..41bfe81b8
--- /dev/null
+++ b/tests/testdata/string.txt
@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
\ No newline at end of file
diff --git a/tests/testdata/wildhtml.html b/tests/testdata/wildhtml.html
new file mode 100644
index 000000000..dfab7ba95
--- /dev/null
+++ b/tests/testdata/wildhtml.html
@@ -0,0 +1,25 @@
+<!DOCTYPE some doctype >
+  
+<html>
+  <head>
+    <title>Test title!</title>
+  </head>
+
+  <body>
+    Ein Text mit vielen Zeichenumbr&uuml;chen. <br />
+    <br><br>
+    
+    <ul>
+      <li>first <span class = "34" >Item.</span>
+      <li>second Item.
+      <li>third item. Mit &auml;.
+    </ul>
+    
+    Para 0.
+    
+    <p>Para1. </p>
+    <p>Para 2.
+    
+  </body>
+</html>
+
diff --git a/tests/testdata/xmltest.html b/tests/testdata/xmltest.html
new file mode 100644
index 000000000..ca4abc4eb
--- /dev/null
+++ b/tests/testdata/xmltest.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+
+<head>
+  <title>Nimrod Programming Language</title>
+  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
+  <link rel="stylesheet" type="text/css" href="style/style.css" />
+</head>
+
+<>
+  <div id="main">
+    <div id="links">
+      <!-- **** INSERT LINKS HERE **** -->
+    </div>
+    <div id="logo"><h1>Nimrod Programming Language</h1></div>
+    <div id="content">
+      <div id="menu">
+        <ul>
+  <li><a
+  href="index.html" title = "Nimrod - home"   home</a></li>
+  <!-- error: > missing -->
+  
+  <li><a
+  href="news.html" title = "Nimrod - news">news</></>
+  <li><a
+  href="documentation.html" title = "Nimrod - docs">docs</a></li>
+  <li><a id="selected" 
+  href="download.html" title = "Nimrod - download">download</a></li>
+  <li><a
+  href="community.html" title = "Nimrod - community">community</a></li>
+  <li><a
+  href="question.html" title = "Nimrod - FAQ">FAQ</a></li>
+        </ul>
+      </div>
+      <div id="column1">
+        <div class="sidebaritem">
+          <div class="sbihead">
+            <h1>latest news</h1>
+          </div>
+          <div class="sbicontent">
+            <p><span class="newsdate">2009-01-22</span><br />Forum added!<br /><span class="newsdate">2009-01-07</span><br />Nimrod version 0.7.4 has been released! Get it <a class="reference external" href="./download.html">here</a>.<br /><span class="newsdate">2008-12-12</span><br />Nimrod version 0.7.2 has been released!<br /><span class="newsdate">2008-11-16</span><br />Nimrod version 0.7.0 has been released!<br /><span class="newsdate">2008-08-22</span><br />Nimrod version 0.6.0 has been released!<br /><span class="newsdate">2008-06-22</span><br />This page is finally online!<br /></p>
+
+
+          </div>
+        </div>
+        <div class="sidebaritem">
+          <div class="sbihead">
+            <h1>additional links</h1>
+          </div>
+          <div class="sbilinks">
+            <!-- **** INSERT ADDITIONAL LINKS HERE **** -->
+            <ul>
+             <li><a class="reference" href="http://gcc.gnu.org">GCC</a></li>
+             <li><a class="reference" href="http://llvm.org">LLVM</a></li>
+            </ul>
+          </div>
+        </div>
+      </div>
+      <div id="column2">
+      <blockquote><p>There are two major products that come out of Berkeley: LSD and UNIX. We don't believe this to be a coincidence. -- Jeremy S. Anderson.</p></blockquote>
+<p>Here you can download the latest version of the Nimrod Compiler. Please choose your platform:</p>
+<ul class="simple"><li>source-based installation: <a class="reference external" href="download/nimrod_0.7.4.zip">download/nimrod_0.7.4.zip</a></li>
+<li>installer for Windows (i386): <a class="reference external" href="download/nimrod_0.7.4.exe">download/nimrod_0.7.4.exe</a> (includes LLVM and everything else you need)</li>
+</ul>
+<p>The source-based installation should work on most UNIX-like systems. Currently, it has been tested on these systems:</p>
+<ul class="simple"><li>Linux: i386, AMD64</li>
+<li>Mac OS X: i386</li>
+<li>FreeBSD: i386</li>
+</ul>
+<h1 id="installation">Installation</h1><h2 id="installation-on-linux-unix">Installation on Linux/UNIX</h2><dl class="docutils"><dt>Note:</dt>
+<dd>A C compiler is required - knowledge of C is not!</dd>
+</dl>
+<p>The GNU C Compiler is fully supported, other compilers may work. The C compiler should be in your <tt class="docutils literal"><span class="pre">$PATH</span></tt> (most likely the case). Note that some few Linux distributions do not ship with a GCC compiler preinstalled - then you have to install it.</p>
+<p>Install Nimrod by downloading the appropriate <tt class="docutils literal"><span class="pre">.zip</span></tt> file and extracting it to a directory of your choice. The Nimrod Compiler will stay in this directory (unless you copy it somewhere else). The compiler does not need write access to its directory anymore, so copying the nimrod folder to <tt class="docutils literal"><span class="pre">/opt</span></tt> does work.</p>
+<p>Then run the following command:<pre>
+sh build.sh</pre>
+</p>
+<p>Unlike other software, Nimrod does not distribute its files over the whole file hierarchy. This has the advantage that you can deinstall it by just deleting its folder. The disadvantage is that you have to add it to your <tt class="docutils literal"><span class="pre">PATH</span></tt> manually. An alternative is to create a symbolic link in <tt class="docutils literal"><span class="pre">/usr/bin</span></tt>:<pre>
+[sudo] ln -s $your_install_dir/bin/nimrod  /usr/bin/nimrod</pre>
+</p>
+<h2 id="installation-on-the-macintosh">Installation on the Macintosh</h2><p>Only MacOS X is supported. Since MacOS X is UNIX based too, it works like the installation on Linux. You need to install Apple's developer's tools for the GNU Compiler Collection though.</p>
+<h2 id="installation-on-windows">Installation on Windows</h2><p>Install Nimrod by downloading and running the <tt class="docutils literal"><span class="pre">nimrod_$version.exe</span></tt> file. As default, the <tt class="docutils literal"><span class="pre">LLVM-GCC</span></tt> compiler is used that is bundled with this installer. You can change the configuration file to use another C compiler.</p>
+<p>Currently, the following C compilers are supported under Windows:</p>
+<ul class="simple"><li><p>Microsoft's Visual C++<br /><a class="reference external" href="http://msdn.microsoft.com/visualc">http://msdn.microsoft.com/visualc</a><br />(You need the SDK too - but not the full one: Essential are only the win32api header files and import libraries.)<br /></p></li>
+<li><p>Gnu C Compiler (the mingw version; the cygwin version has not been tested!)<br /><a class="reference external" href="http://www.mingw.org/download.shtml">http://www.mingw.org/download.shtml</a><br /></p></li>
+<li><p>LLVM with GNU C/C++ frontend<br /><a class="reference external" href="http://llvm.org/releases/download.html#2.2">http://llvm.org/releases/download.html#2.2</a><br /></p></li>
+<li><p>Digital Mars C++<br /><a class="reference external" href="http://www.digitalmars.com/download/freecompiler.html">http://www.digitalmars.com/download/freecompiler.html</a><br /></p></li>
+</ul>
+<p>For better compile times I recommend Digital Mars C++ -- it is easy to install and a small package.</p>
+
+
+<pre>
+  x < 0 && y >= 0
+</pre>
+
+
+      </div>
+    </div>
+    <div id="footer">
+      copyright &copy; 2009 Andreas Rumpf | Last update: 2009-02-10
+      | <a class="reference" href="http://validator.w3.org/check?uri=referer">XHTML 1.1</a>
+      | <a class="reference" href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a>
+      | <a class="reference" href="http://www.dcarter.co.uk">design by dcarter</a>
+    </div>
+  </div>
+</body>
+
+  <bugtest att="value" />
+
+</html>
+
diff --git a/tests/threads/nim.cfg b/tests/threads/nim.cfg
new file mode 100644
index 000000000..b81c89721
--- /dev/null
+++ b/tests/threads/nim.cfg
@@ -0,0 +1 @@
+threads:on
diff --git a/tests/threads/tactors.nim b/tests/threads/tactors.nim
new file mode 100644
index 000000000..45a03ebb7
--- /dev/null
+++ b/tests/threads/tactors.nim
@@ -0,0 +1,13 @@
+discard """
+  outputsub: "150"
+"""
+
+import actors
+
+var
+  pool: TActorPool[int, void]
+createActorPool(pool)
+for i in 0 .. < 300:
+  pool.spawn(i, proc (x: int) {.thread.} = echo x)
+pool.join()
+
diff --git a/tests/threads/tactors2.nim b/tests/threads/tactors2.nim
new file mode 100644
index 000000000..5683f98ba
--- /dev/null
+++ b/tests/threads/tactors2.nim
@@ -0,0 +1,25 @@
+discard """
+  output: "1"
+"""
+
+import actors
+
+type
+  some_type {.pure, final.} = object
+    bla: int
+
+proc thread_proc(input: some_type): some_type {.thread.} =
+  result.bla = 1
+
+proc main() =
+  var actorPool: TActorPool[some_type, some_type]
+  createActorPool(actorPool, 1)
+
+  var some_data: some_type
+  
+  var inchannel = spawn(actorPool, some_data, thread_proc)
+  var recv_data = ^inchannel
+  close(inchannel[])
+  echo recv_data.bla
+
+main()
diff --git a/tests/threads/threadex.nim b/tests/threads/threadex.nim
new file mode 100644
index 000000000..0360c8c04
--- /dev/null
+++ b/tests/threads/threadex.nim
@@ -0,0 +1,44 @@
+discard """
+  outputsub: "All rights reserved."
+"""
+
+type
+  TMsgKind = enum
+    mLine, mEof
+  TMsg = object {.pure, final.}
+    case k: TMsgKind
+    of mEof: nil
+    of mLine: data: string
+
+var
+  producer, consumer: TThread[void]
+  chan: TChannel[TMsg]
+  printedLines = 0
+
+proc consume() {.thread.} =
+  while true:
+    var x = recv(chan)
+    if x.k == mEof: break
+    echo x.data
+    atomicInc(printedLines)
+
+proc produce() {.thread.} =
+  var m: TMsg
+  var input = open("readme.txt")
+  var line = ""
+  while input.readLine(line):
+    m.data = line
+    chan.send(m)
+  close(input)
+  m.k = mEof
+  chan.send(m)
+  
+open(chan)
+createThread[void](consumer, consume)
+createThread[void](producer, produce)
+joinThread(consumer)
+joinThread(producer)
+
+close(chan)
+echo printedLines
+
diff --git a/tests/threads/trecursive_actor.nim b/tests/threads/trecursive_actor.nim
new file mode 100644
index 000000000..e2774704c
--- /dev/null
+++ b/tests/threads/trecursive_actor.nim
@@ -0,0 +1,19 @@
+discard """
+  outputsub: "0"
+"""
+
+import actors
+
+var
+  a: TActorPool[int, void]
+createActorPool(a)
+
+proc task(i: int) {.thread.} =
+  echo i
+  if i != 0: a.spawn (i-1, task)
+
+# count from 9 till 0 and check 0 is somewhere in the output
+a.spawn(9, task)
+a.join()
+
+
diff --git a/tests/threads/tthreadanalysis.nim b/tests/threads/tthreadanalysis.nim
new file mode 100644
index 000000000..b222f15a9
--- /dev/null
+++ b/tests/threads/tthreadanalysis.nim
@@ -0,0 +1,53 @@
+discard """
+  outputsub: "101"
+  errormsg: "'threadFunc' is not GC-safe"
+  line: 39
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+import os
+
+var
+  thr: array [0..5, TThread[tuple[a, b: int]]]
+
+proc doNothing() = discard
+
+type
+  PNode = ref TNode
+  TNode = object {.pure.}
+    le, ri: PNode
+    data: string
+
+var
+  root: PNode
+
+proc buildTree(depth: int): PNode =
+  if depth == 3: return nil
+  new(result)
+  result.le = buildTree(depth-1)
+  result.ri = buildTree(depth-1)
+  result.data = $depth
+
+proc echoLeTree(n: PNode) =
+  var it: PNode
+  it = nil
+  it = n
+  while it != nil:
+    echo it.data
+    it = it.le
+
+proc threadFunc(interval: tuple[a, b: int]) {.thread.} = 
+  doNothing()
+  for i in interval.a..interval.b: 
+    var r = buildTree(i)
+    echoLeTree(r) # for local data
+  echoLeTree(root) # and the same for foreign data :-)
+
+proc main =
+  root = buildTree(5)
+  for i in 0..high(thr):
+    createThread(thr[i], threadFunc, (i*3, i*3+2))
+  joinThreads(thr)
+
+main()
+
diff --git a/tests/threads/tthreadanalysis2.nim b/tests/threads/tthreadanalysis2.nim
new file mode 100644
index 000000000..d5b2cd430
--- /dev/null
+++ b/tests/threads/tthreadanalysis2.nim
@@ -0,0 +1,52 @@
+discard """
+  file: "tthreadanalysis2.nim"
+  line: 37
+  errormsg: "'threadFunc' is not GC-safe"
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+import os
+
+var
+  thr: array [0..5, TThread[tuple[a, b: int]]]
+
+proc doNothing() = discard
+
+type
+  PNode = ref TNode
+  TNode = object {.pure.}
+    le, ri: PNode
+    data: string
+
+var
+  root: PNode
+
+proc buildTree(depth: int): PNode =
+  if depth == 3: return nil
+  new(result)
+  result.le = buildTree(depth-1)
+  result.ri = buildTree(depth-1)
+  result.data = $depth
+
+proc echoLeTree(n: PNode) =
+  var it = n
+  while it != nil:
+    echo it.data
+    it = it.le
+
+proc threadFunc(interval: tuple[a, b: int]) {.thread.} = 
+  doNothing()
+  for i in interval.a..interval.b: 
+    var r = buildTree(i)
+    echoLeTree(r) # for local data
+  root = buildTree(2) # BAD!
+  #echoLeTree(root) # and the same for foreign data :-)
+
+proc main =
+  root = buildTree(5)
+  for i in 0..high(thr):
+    createThread(thr[i], threadFunc, (i*100, i*100+50))
+  joinThreads(thr)
+
+main()
+
diff --git a/tests/threads/tthreadheapviolation1.nim b/tests/threads/tthreadheapviolation1.nim
new file mode 100644
index 000000000..94e1b64db
--- /dev/null
+++ b/tests/threads/tthreadheapviolation1.nim
@@ -0,0 +1,20 @@
+discard """
+  line: 11
+  errormsg: "'horrible' is not GC-safe"
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+var 
+  global: string = "test string"
+  t: TThread[void]
+
+proc horrible() {.thread.} =
+  global = "string in thread local heap!"
+  var x = global
+  var mydata = (x, "my string too")
+  echo global
+
+createThread[void](t, horrible)
+joinThread(t)
+
+
diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim
new file mode 100644
index 000000000..acccf182c
--- /dev/null
+++ b/tests/threads/ttryrecv.nim
@@ -0,0 +1,35 @@
+discard """
+  outputsub: "channel is empty"
+"""
+
+# bug #1816
+
+from math import random
+from os import sleep
+
+type PComm = ptr TChannel[int]
+
+proc doAction(outC: PComm) {.thread.} =
+  for i in 0.. <5:
+    sleep(random(100))
+    send(outC[], i)
+
+var
+  thr: TThread[PComm]
+  chan: TChannel[int]
+
+open(chan)
+createThread[PComm](thr, doAction, addr(chan))
+
+while true:
+  let (flag, x) = tryRecv(chan)
+  if flag:
+    echo("received from chan: " & $x)
+  else:
+    echo "channel is empty"
+    break
+
+echo "Finished listening"
+
+joinThread(thr)                                                       
+close(chan)
diff --git a/tests/trmacros/targlist.nim b/tests/trmacros/targlist.nim
new file mode 100644
index 000000000..321b3d5d2
--- /dev/null
+++ b/tests/trmacros/targlist.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "12false3ha"
+"""
+
+proc f(x: varargs[string, `$`]) = discard
+template optF{f(x)}(x: varargs[expr]) = 
+  writeln(stdout, x)
+
+f 1, 2, false, 3, "ha"
diff --git a/tests/trmacros/tcse.nim b/tests/trmacros/tcse.nim
new file mode 100644
index 000000000..ff04f7d83
--- /dev/null
+++ b/tests/trmacros/tcse.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "4"
+"""
+
+template cse{f(a, a, x)}(a: expr{(nkDotExpr|call|nkBracketExpr)&noSideEffect},
+                         f: expr, x: varargs[expr]): expr =
+  let aa = a
+  f(aa, aa, x)+4
+  
+var
+  a: array[0..10, int]
+  i = 3
+echo a[i] + a[i]
diff --git a/tests/trmacros/tdisallowif.nim b/tests/trmacros/tdisallowif.nim
new file mode 100644
index 000000000..18dfd1c82
--- /dev/null
+++ b/tests/trmacros/tdisallowif.nim
@@ -0,0 +1,29 @@
+discard """
+  line: 24
+  errormsg: "usage of 'disallowIf' is a user-defined error"
+  disabled: true
+"""
+
+template optZero{x+x}(x: int): int = x*3
+template andthen{`*`(x,3)}(x: int): int = x*4
+template optSubstr1{x = substr(x, 0, b)}(x: string, b: int) = setlen(x, b+1)
+
+template disallowIf{
+  if cond: action
+  else: action2
+}(cond: bool, action, action2: stmt) {.error.} = action
+
+var y = 12
+echo y+y
+
+var s: array[0..2, string]
+s[0] = "hello"
+s[0] = substr(s[0], 0, 2)
+
+echo s[0]
+
+if s[0] != "hi":
+  echo "do it"
+  echo "more branches"
+else:
+  discard
diff --git a/tests/trmacros/thoist.nim b/tests/trmacros/thoist.nim
new file mode 100644
index 000000000..7d14c0abf
--- /dev/null
+++ b/tests/trmacros/thoist.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''true
+true'''
+"""
+
+import pegs
+
+template optPeg{peg(pattern)}(pattern: string{lit}): TPeg =
+  var gl {.global, gensym.} = peg(pattern)
+  gl
+
+echo match("(a b c)", peg"'(' @ ')'")
+echo match("W_HI_Le", peg"\y 'while'")
diff --git a/tests/trmacros/tmatrix.nim b/tests/trmacros/tmatrix.nim
new file mode 100644
index 000000000..c825a7792
--- /dev/null
+++ b/tests/trmacros/tmatrix.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "21"
+"""
+
+import macros
+
+type
+  TMat = object
+    dummy: int
+
+proc `*`(a, b: TMat): TMat = nil
+proc `+`(a, b: TMat): TMat = nil
+proc `-`(a, b: TMat): TMat = nil
+proc `$`(a: TMat): string = result = $a.dummy
+proc mat21(): TMat =
+  result.dummy = 21
+
+macro optOps{ (`+`|`-`|`*`) ** a }(a: TMat): expr =
+  echo treeRepr(a)
+  result = newCall(bindSym"mat21")
+
+#macro optPlus{ `+` * a }(a: varargs[TMat]): expr =
+#  result = newIntLitNode(21)
+
+var x, y, z: TMat
+
+echo x + y * z - x 
+
+#echo x + y + z
diff --git a/tests/trmacros/tnoalias.nim b/tests/trmacros/tnoalias.nim
new file mode 100644
index 000000000..1d5671362
--- /dev/null
+++ b/tests/trmacros/tnoalias.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "23"
+"""
+
+template optslice{a = b + c}(a: expr{noalias}, b, c: expr): stmt =
+  a = b
+  inc a, c
+
+var
+  x = 12
+  y = 10
+  z = 13
+
+x = y+z
+
+echo x
diff --git a/tests/trmacros/tnoalias2.nim b/tests/trmacros/tnoalias2.nim
new file mode 100644
index 000000000..5a816acb9
--- /dev/null
+++ b/tests/trmacros/tnoalias2.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''0'''
+"""
+
+# bug #206
+template optimizeOut{testFunc(a, b)}(a: int, b: int{alias}) : expr = 0
+
+proc testFunc(a, b: int): int = result = a + b
+var testVar = 1
+echo testFunc(testVar, testVar)
+
+
+template ex{a = b + c}(a : int{noalias}, b, c : int) =
+  a = b
+  inc a, b
+  echo "came here"
+
+var x = 5
+x = x + x
diff --git a/tests/trmacros/tnoendlessrec.nim b/tests/trmacros/tnoendlessrec.nim
new file mode 100644
index 000000000..53891bcc0
--- /dev/null
+++ b/tests/trmacros/tnoendlessrec.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "4"
+"""
+
+# test that an endless recursion is avoided:
+
+template optLen{len(x)}(x: expr): expr = len(x)
+
+var s = "lala"
+echo len(s)
diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim
new file mode 100644
index 000000000..500851582
--- /dev/null
+++ b/tests/trmacros/tor.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''3030
+true
+3'''
+"""
+
+template arithOps: expr = (`+` | `-` | `*`)
+template testOr{ (arithOps{f})(a, b) }(a, b, f: expr): expr = f(a+1, b)
+
+let xx = 10
+echo 10*xx
+
+template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt =
+  x = y
+  if x: x = z
+
+var
+  a = true
+  b = true
+  c = false
+a = b and a
+echo a
+
+# bug #798
+template t012{(0|1|2){x}}(x: expr): expr = x+1
+let z = 1
+# outputs 3 thanks to fixpoint iteration:
+echo z
diff --git a/tests/trmacros/tpartial.nim b/tests/trmacros/tpartial.nim
new file mode 100644
index 000000000..fdaa3414a
--- /dev/null
+++ b/tests/trmacros/tpartial.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''-2'''
+"""
+
+proc p(x, y: int; cond: bool): int =
+  result = if cond: x + y else: x - y
+
+template optP{p(x, y, true)}(x, y: expr): expr = x - y
+template optP{p(x, y, false)}(x, y: expr): expr = x + y
+
+echo p(2, 4, true)
diff --git a/tests/trmacros/tpatterns.nim b/tests/trmacros/tpatterns.nim
new file mode 100644
index 000000000..6bc8772e3
--- /dev/null
+++ b/tests/trmacros/tpatterns.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''48
+hel'''
+"""
+
+template optZero{x+x}(x: int): int = x*3
+template andthen{`*`(x,3)}(x: int): int = x*4
+template optSubstr1{x = substr(x, a, b)}(x: string, a, b: int) = setlen(x, b+1)
+
+var y = 12
+echo y+y
+
+var s: array[0..2, string]
+s[0] = "hello"
+s[0] = substr(s[0], 0, 2)
+
+echo s[0]
diff --git a/tests/trmacros/tstar.nim b/tests/trmacros/tstar.nim
new file mode 100644
index 000000000..8443268f4
--- /dev/null
+++ b/tests/trmacros/tstar.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "my awesome concat"
+"""
+
+var
+  calls = 0
+  
+proc `&&`(s: varargs[string]): string =
+  result = s[0]
+  for i in 1..len(s)-1: result.add s[i]
+  inc calls
+
+template optConc{ `&&` * a }(a: string): expr = &&a
+
+let space = " "
+echo "my" && (space & "awe" && "some " ) && "concat"
+
+# check that it's been optimized properly:
+doAssert calls == 1
diff --git a/tests/trmacros/tstmtlist.nim b/tests/trmacros/tstmtlist.nim
new file mode 100644
index 000000000..20cb5d688
--- /dev/null
+++ b/tests/trmacros/tstmtlist.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''0
+|12|
+34
+'''
+"""
+
+template optWrite{
+  write(f, x)
+  ((write|writeln){w})(f, y)
+}(x, y: varargs[expr], f, w: expr) =
+  w(f, "|", x, y, "|")
+
+if true:
+  echo "0"
+  write stdout, "1"
+  writeln stdout, "2"
+  write stdout, "3"
+  echo "4"
diff --git a/tests/tuples/tanontuples.nim b/tests/tuples/tanontuples.nim
new file mode 100644
index 000000000..49803e5ac
--- /dev/null
+++ b/tests/tuples/tanontuples.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''61, 125'''
+"""
+
+proc `^` (a, b: int): int =
+  result = 1
+  for i in 1..b: result = result * a
+
+var m = (0, 5)
+var n = (56, 3)
+
+m = (n[0] + m[1], m[1] ^ n[1])
+
+echo m[0], ", ", m[1]
diff --git a/tests/tuples/tdifferent_instantiations.nim b/tests/tuples/tdifferent_instantiations.nim
new file mode 100644
index 000000000..93b1777b5
--- /dev/null
+++ b/tests/tuples/tdifferent_instantiations.nim
@@ -0,0 +1,9 @@
+# bug #1910
+import tables
+
+var p: OrderedTable[tuple[a:int], int]
+var q: OrderedTable[tuple[x:int], int]
+for key in p.keys:
+  echo key.a
+for key in q.keys:
+  echo key.x
diff --git a/tests/tuples/tgeneric_tuple.nim b/tests/tuples/tgeneric_tuple.nim
new file mode 100644
index 000000000..32f081596
--- /dev/null
+++ b/tests/tuples/tgeneric_tuple.nim
@@ -0,0 +1,9 @@
+# bug #2121
+
+type
+  Item[K,V] = tuple
+    key: K
+    value: V
+
+var q = newseq[Item[int,int]](0)
+let (x,y) = q[0]
diff --git a/tests/tuples/tgeneric_tuple2.nim b/tests/tuples/tgeneric_tuple2.nim
new file mode 100644
index 000000000..c0c292388
--- /dev/null
+++ b/tests/tuples/tgeneric_tuple2.nim
@@ -0,0 +1,17 @@
+
+# bug #2369
+
+type HashedElem[T] = tuple[num: int, storedVal: ref T]
+
+proc append[T](tab: var seq[HashedElem[T]], n: int, val: ref T) =
+    #tab.add((num: n, storedVal: val))
+    var he: HashedElem[T] = (num: n, storedVal: val)
+    #tab.add(he)
+
+var g: seq[HashedElem[int]] = @[]
+
+proc foo() =
+    var x: ref int
+    new(x)
+    x[] = 77
+    g.append(44, x)
diff --git a/tests/tuples/tuint_tuple.nim b/tests/tuples/tuint_tuple.nim
new file mode 100644
index 000000000..24bcead5e
--- /dev/null
+++ b/tests/tuples/tuint_tuple.nim
@@ -0,0 +1,10 @@
+# bug #1986 found by gdmoore
+
+proc test(): int64 =
+  return 0xdeadbeef.int64
+
+const items = [
+  (var1: test(), var2: 100'u32),
+  (var1: test(), var2: 192'u32)
+]
+
diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim
new file mode 100644
index 000000000..26e4ae85e
--- /dev/null
+++ b/tests/tuples/tuple_with_nil.nim
@@ -0,0 +1,766 @@
+import macros
+from strutils import IdentStartChars
+import parseutils
+import unicode
+import math
+import fenv
+import unsigned
+import pegs
+import streams
+
+type
+  FormatError = object of Exception ## Error in the format string.
+
+  Writer = concept W
+    ## Writer to output a character `c`.
+    when (NimMajor, NimMinor, NimPatch) > (0, 10, 2):
+      write(W, 'c')
+    else:
+      block:
+        var x: W
+        write(x, char)
+
+  FmtAlign = enum ## Format alignment
+    faDefault  ## default for given format type
+    faLeft     ## left aligned
+    faRight    ## right aligned
+    faCenter   ## centered
+    faPadding  ## right aligned, fill characters after sign (numbers only)
+
+  FmtSign = enum ## Format sign
+    fsMinus    ## only unary minus, no reservered sign space for positive numbers
+    fsPlus     ## unary minus and unary plus
+    fsSpace    ## unary minus and reserved space for positive numbers
+
+  FmtType = enum ## Format type
+    ftDefault  ## default format for given parameter type
+    ftStr      ## string
+    ftChar     ## character
+    ftDec      ## decimal integer
+    ftBin      ## binary integer
+    ftOct      ## octal integer
+    ftHex      ## hexadecimal integer
+    ftFix      ## real number in fixed point notation
+    ftSci      ## real number in scientific notation
+    ftGen      ## real number in generic form (either fixed point or scientific)
+    ftPercent  ## real number multiplied by 100 and % added
+
+  Format = tuple ## Formatting information.
+    typ: FmtType     ## format type
+    precision: int    ## floating point precision
+    width: int        ## minimal width
+    fill: string      ## the fill character, UTF8
+    align: FmtAlign  ## aligment
+    sign: FmtSign    ## sign notation
+    baseprefix: bool  ## whether binary, octal, hex should be prefixed by 0b, 0x, 0o
+    upcase: bool      ## upper case letters in hex or exponential formats
+    comma: bool       ##
+    arysep: string    ## separator for array elements
+
+  PartKind = enum pkStr, pkFmt
+
+  Part = object
+    ## Information of a part of the target string.
+    case kind: PartKind ## type of the part
+    of pkStr:
+      str: string ## literal string
+    of pkFmt:
+      arg: int ## position argument
+      fmt: string ## format string
+      field: string ## field of argument to be accessed
+      index: int ## array index of argument to be accessed
+      nested: bool ## true if the argument contains nested formats
+
+const
+  DefaultPrec = 6 ## Default precision for floating point numbers.
+  DefaultFmt: Format = (ftDefault, -1, -1, nil, faDefault, fsMinus, false, false, false, nil)
+    ## Default format corresponding to the empty format string, i.e.
+    ##   `x.format("") == x.format(DefaultFmt)`.
+  round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005]
+    ## Rounding offset for floating point numbers up to precision 8.
+
+proc write(s: var string; c: char) =
+  s.add(c)
+
+proc has(c: Captures; i: range[0..pegs.MaxSubpatterns-1]): bool {.nosideeffect, inline.} =
+  ## Tests whether `c` contains a non-empty capture `i`.
+  let b = c.bounds(i)
+  result = b.first <= b.last
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: char): char {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str` casted
+  ## to `char`, otherwise return `def`.
+  result = if c.has(i): str[c.bounds(i).first] else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: string; begoff: int = 0): string {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str` as
+  ## string, otherwise return `def`.
+  let b = c.bounds(i)
+  result = if c.has(i): str.substr(b.first + begoff, b.last) else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: int; begoff: int = 0): int {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str`
+  ## converted to int, otherwise return `def`.
+  if c.has(i):
+    discard str.parseInt(result, c.bounds(i).first + begoff)
+  else:
+    result = def
+
+proc parse(fmt: string): Format {.nosideeffect.} =
+  # Converts the format string `fmt` into a `Format` structure.
+  let p =
+    sequence(capture(?sequence(anyRune(), &charSet({'<', '>', '=', '^'}))),
+             capture(?charSet({'<', '>', '=', '^'})),
+             capture(?charSet({'-', '+', ' '})),
+             capture(?charSet({'#'})),
+             capture(?(+digits())),
+             capture(?charSet({','})),
+             capture(?sequence(charSet({'.'}), +digits())),
+             capture(?charSet({'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'})),
+             capture(?sequence(charSet({'a'}), *pegs.any())))
+  # let p=peg"{(_&[<>=^])?}{[<>=^]?}{[-+ ]?}{[#]?}{[0-9]+?}{[,]?}{([.][0-9]+)?}{[bcdeEfFgGnosxX%]?}{(a.*)?}"
+
+  var caps: Captures
+  if fmt.rawmatch(p, 0, caps) < 0:
+    raise newException(FormatError, "Invalid format string")
+
+  result.fill = fmt.get(caps, 0, nil)
+
+  case fmt.get(caps, 1, 0.char)
+  of '<': result.align = faLeft
+  of '>': result.align = faRight
+  of '^': result.align = faCenter
+  of '=': result.align = faPadding
+  else: result.align = faDefault
+
+  case fmt.get(caps, 2, '-')
+  of '-': result.sign = fsMinus
+  of '+': result.sign = fsPlus
+  of ' ': result.sign = fsSpace
+  else: result.sign = fsMinus
+
+  result.baseprefix = caps.has(3)
+
+  result.width = fmt.get(caps, 4, -1)
+
+  if caps.has(4) and fmt[caps.bounds(4).first] == '0':
+    if result.fill != nil:
+      raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character")
+    if result.align != faDefault:
+      raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment")
+    result.fill = "0"
+    result.align = faPadding
+
+  result.comma = caps.has(5)
+
+  result.precision = fmt.get(caps, 6, -1, 1)
+
+  case fmt.get(caps, 7, 0.char)
+  of 's': result.typ = ftStr
+  of 'c': result.typ = ftChar
+  of 'd', 'n': result.typ = ftDec
+  of 'b': result.typ = ftBin
+  of 'o': result.typ = ftOct
+  of 'x': result.typ = ftHex
+  of 'X': result.typ = ftHex; result.upcase = true
+  of 'f', 'F': result.typ = ftFix
+  of 'e': result.typ = ftSci
+  of 'E': result.typ = ftSci; result.upcase = true
+  of 'g': result.typ = ftGen
+  of 'G': result.typ = ftGen; result.upcase = true
+  of '%': result.typ = ftPercent
+  else: result.typ = ftDefault
+
+  result.arysep = fmt.get(caps, 8, nil, 1)
+
+proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} =
+  ## Returns the number of left and right padding characters for a
+  ## given format alignment and width of the object to be printed.
+  ##
+  ## `fmt`
+  ##    the format data
+  ## `default`
+  ##    if `fmt.align == faDefault`, then this alignment is used
+  ## `slen`
+  ##    the width of the object to be printed.
+  ##
+  ## The returned values `(left, right)` will be as minimal as possible
+  ## so that `left + slen + right >= fmt.width`.
+  result.left = 0
+  result.right = 0
+  if (fmt.width >= 0) and (slen < fmt.width):
+    let alg = if fmt.align == faDefault: defalign else: fmt.align
+    case alg:
+    of faLeft: result.right = fmt.width - slen
+    of faRight, faPadding: result.left = fmt.width - slen
+    of faCenter:
+      result.left = (fmt.width - slen) div 2
+      result.right = fmt.width - slen - result.left
+    else: discard
+
+proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) =
+  ## Write characters for filling. This function also writes the sign
+  ## of a numeric format and handles the padding alignment
+  ## accordingly.
+  ##
+  ## `o`
+  ##   output object
+  ## `add`
+  ##   output function
+  ## `fmt`
+  ##   format to be used (important for padding aligment)
+  ## `n`
+  ##   the number of filling characters to be written
+  ## `signum`
+  ##   the sign of the number to be written, < 0 negative, > 0 positive, = 0 zero
+  if fmt.align == faPadding and signum != 0:
+    if signum < 0: write(o, '-')
+    elif fmt.sign == fsPlus: write(o, '+')
+    elif fmt.sign == fsSpace: write(o, ' ')
+
+  if fmt.fill == nil:
+    for i in 1..n: write(o, ' ')
+  else:
+    for i in 1..n:
+      for c in fmt.fill:
+        write(o, c)
+
+  if fmt.align != faPadding and signum != 0:
+    if signum < 0: write(o, '-')
+    elif fmt.sign == fsPlus: write(o, '+')
+    elif fmt.sign == fsSpace: write(o, ' ')
+
+proc writeformat(o: var Writer; s: string; fmt: Format) =
+  ## Write string `s` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if fmt.typ notin {ftDefault, ftStr}:
+    raise newException(FormatError, "String variable must have 's' format type")
+
+  # compute alignment
+  let len = if fmt.precision < 0: runelen(s) else: min(runelen(s), fmt.precision)
+  var alg = getalign(fmt, faLeft, len)
+  writefill(o, fmt, alg.left)
+  var pos = 0
+  for i in 0..len-1:
+    let rlen = runeLenAt(s, pos)
+    for j in pos..pos+rlen-1: write(o, s[j])
+    pos += rlen
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: char; fmt: Format) =
+  ## Write character `c` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if not (fmt.typ in {ftChar, ftDefault}):
+    raise newException(FormatError, "Character variable must have 'c' format type")
+
+  # compute alignment
+  var alg = getalign(fmt, faLeft, 1)
+  writefill(o, fmt, alg.left)
+  write(o, c)
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: Rune; fmt: Format) =
+  ## Write rune `c` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if not (fmt.typ in {ftChar, ftDefault}):
+    raise newException(FormatError, "Character variable must have 'c' format type")
+
+  # compute alignment
+  var alg = getalign(fmt, faLeft, 1)
+  writefill(o, fmt, alg.left)
+  let s = c.toUTF8
+  for c in s: write(o, c)
+  writefill(o, fmt, alg.right)
+
+proc abs(x: SomeUnsignedInt): SomeUnsignedInt {.inline.} = x
+  ## Return the absolute value of the unsigned int `x`.
+
+proc writeformat(o: var Writer; i: SomeInteger; fmt: Format) =
+  ## Write integer `i` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  var fmt = fmt
+  if fmt.typ == ftDefault:
+    fmt.typ = ftDec
+  if not (fmt.typ in {ftBin, ftOct, ftHex, ftDec}):
+    raise newException(FormatError, "Integer variable must of one of the following types: b,o,x,X,d,n")
+
+  var base: type(i)
+  var len = 0
+  case fmt.typ:
+  of ftDec:
+    base = 10
+  of ftBin:
+    base = 2
+    if fmt.baseprefix: len += 2
+  of ftOct:
+    base = 8
+    if fmt.baseprefix: len += 2
+  of ftHex:
+    base = 16
+    if fmt.baseprefix: len += 2
+  else: assert(false)
+
+  if fmt.sign != fsMinus or i < 0: len.inc
+
+  var x: type(i) = abs(i)
+  var irev: type(i) = 0
+  var ilen = 0
+  while x > 0.SomeInteger:
+    len.inc
+    ilen.inc
+    irev = irev * base + x mod base
+    x = x div base
+  if ilen == 0:
+    ilen.inc
+    len.inc
+
+  var alg = getalign(fmt, faRight, len)
+  writefill(o, fmt, alg.left, if i >= 0.SomeInteger: 1 else: -1)
+  if fmt.baseprefix:
+    case fmt.typ
+    of ftBin:
+      write(o, '0')
+      write(o, 'b')
+    of ftOct:
+      write(o, '0')
+      write(o, 'o')
+    of ftHex:
+      write(o, '0')
+      write(o, 'x')
+    else:
+      raise newException(FormatError, "# only allowed with b, o, x or X")
+  while ilen > 0:
+    ilen.dec
+    let c = irev mod base
+    irev = irev div base
+    if c < 10:
+      write(o, ('0'.int + c.int).char)
+    elif fmt.upcase:
+      write(o, ('A'.int + c.int - 10).char)
+    else:
+      write(o, ('a'.int + c.int - 10).char)
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; p: pointer; fmt: Format) =
+  ## Write pointer `i` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  ##
+  ## Pointers are casted to unsigned int and formated as hexadecimal
+  ## with prefix unless specified otherwise.
+  var f = fmt
+  if f.typ == 0.char:
+    f.typ = 'x'
+    f.baseprefix = true
+  writeformat(o, add, cast[uint](p), f)
+
+proc writeformat(o: var Writer; x: SomeReal; fmt: Format) =
+  ## Write real number `x` according to format `fmt` using output
+  ## object `o` and output function `add`.
+  var fmt = fmt
+  # handle default format
+  if fmt.typ == ftDefault:
+    fmt.typ = ftGen
+    if fmt.precision < 0: fmt.precision = DefaultPrec
+  if not (fmt.typ in {ftFix, ftSci, ftGen, ftPercent}):
+    raise newException(FormatError, "Integer variable must of one of the following types: f,F,e,E,g,G,%")
+
+  let positive = x >= 0 and classify(x) != fcNegZero
+  var len = 0
+
+  if fmt.sign != fsMinus or not positive: len.inc
+
+  var prec = if fmt.precision < 0: DefaultPrec else: fmt.precision
+  var y = abs(x)
+  var exp = 0
+  var numstr, frstr: array[0..31, char]
+  var numlen, frbeg, frlen = 0
+
+  if fmt.typ == ftPercent: y *= 100
+
+  case classify(x):
+  of fcNan:
+    numstr[0..2] = ['n', 'a', 'n']
+    numlen = 3
+  of fcInf, fcNegInf:
+    numstr[0..2] = ['f', 'n', 'i']
+    numlen = 3
+  of fcZero, fcNegZero:
+    numstr[0] = '0'
+    numlen = 1
+  else: # a usual fractional number
+    if not (fmt.typ in {ftFix, ftPercent}): # not fixed point
+      exp = int(floor(log10(y)))
+      if fmt.typ == ftGen:
+        if prec == 0: prec = 1
+        if -4 <= exp and exp < prec:
+          prec = prec-1-exp
+          exp = 0
+        else:
+          prec = prec - 1
+          len += 4 # exponent
+      else:
+        len += 4 # exponent
+      # shift y so that 1 <= abs(y) < 2
+      if exp > 0: y /= pow(10.SomeReal, abs(exp).SomeReal)
+      elif exp < 0: y *= pow(10.SomeReal, abs(exp).SomeReal)
+    elif fmt.typ == ftPercent:
+      len += 1 # percent sign
+
+    # handle rounding by adding +0.5 * LSB
+    if prec < len(round_nums): y += round_nums[prec]
+
+    # split into integer and fractional part
+    var mult = 1'i64
+    for i in 1..prec: mult *= 10
+    var num = y.int64
+    var fr = ((y - num.SomeReal) * mult.SomeReal).int64
+    # build integer part string
+    while num != 0:
+      numstr[numlen] = ('0'.int + (num mod 10)).char
+      numlen.inc
+      num = num div 10
+    if numlen == 0:
+      numstr[0] = '0'
+      numlen.inc
+    # build fractional part string
+    while fr != 0:
+      frstr[frlen] = ('0'.int + (fr mod 10)).char
+      frlen.inc
+      fr = fr div 10
+    while frlen < prec:
+      frstr[frlen] = '0'
+      frlen.inc
+    # possible remove trailing 0
+    if fmt.typ == ftGen:
+      while frbeg < frlen and frstr[frbeg] == '0': frbeg.inc
+  # update length of string
+  len += numlen;
+  if frbeg < frlen:
+    len += 1 + frlen - frbeg # decimal point and fractional string
+
+  let alg = getalign(fmt, faRight, len)
+  writefill(o, fmt, alg.left, if positive: 1 else: -1)
+  for i in (numlen-1).countdown(0): write(o, numstr[i])
+  if frbeg < frlen:
+    write(o, '.')
+    for i in (frlen-1).countdown(frbeg): write(o, frstr[i])
+  if fmt.typ == ftSci or (fmt.typ == ftGen and exp != 0):
+    write(o, if fmt.upcase: 'E' else: 'e')
+    if exp >= 0:
+      write(o, '+')
+    else:
+      write(o, '-')
+      exp = -exp
+    if exp < 10:
+      write(o, '0')
+      write(o, ('0'.int + exp).char)
+    else:
+      var i=0
+      while exp > 0:
+        numstr[i] = ('0'.int + exp mod 10).char
+        i+=1
+        exp = exp div 10
+      while i>0:
+        i-=1
+        write(o, numstr[i])
+  if fmt.typ == ftPercent: write(o, '%')
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; b: bool; fmt: Format) =
+  ## Write boolean value `b` according to format `fmt` using output
+  ## object `o`. A boolean may be formatted numerically or as string.
+  ## In the former case true is written as 1 and false as 0, in the
+  ## latter the strings "true" and "false" are shown, respectively.
+  ## The default is string format.
+  if fmt.typ in {ftStr, ftDefault}:
+    writeformat(o,
+                if b: "true"
+                else: "false",
+                fmt)
+  elif fmt.typ in {ftBin, ftOct, ftHex, ftDec}:
+    writeformat(o,
+                if b: 1
+                else: 0,
+                fmt)
+  else:
+    raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n")
+
+proc writeformat(o: var Writer; ary: openarray[any]; fmt: Format) =
+  ## Write array `ary` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if ary.len == 0: return
+
+  var sep: string
+  var nxtfmt = fmt
+  if fmt.arysep == nil:
+    sep = "\t"
+  elif fmt.arysep.len == 0:
+    sep = ""
+  else:
+    let sepch = fmt.arysep[0]
+    let nxt = 1 + skipUntil(fmt.arysep, sepch, 1)
+    if nxt >= 1:
+      nxtfmt.arysep = fmt.arysep.substr(nxt)
+      sep = fmt.arysep.substr(1, nxt-1)
+    else:
+      nxtfmt.arysep = ""
+      sep = fmt.arysep.substr(1)
+  writeformat(o, ary[0], nxtfmt)
+  for i in 1..ary.len-1:
+    for c in sep: write(o, c)
+    writeformat(o, ary[i], nxtfmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` formatted with `fmt` to `o`.
+  writeformat(o, x, fmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: string) {.inline.} =
+  ## The same as `addformat(o, x, parse(fmt))`.
+  addformat(o, x, fmt.parse)
+
+proc addformat(s: var string; x: string) {.inline.} =
+  ## Write `x` to `s`. This is a fast specialized version for
+  ## appending unformatted strings.
+  add(s, x)
+
+proc addformat(f: File; x: string) {.inline.} =
+  ## Write `x` to `f`. This is a fast specialized version for
+  ## writing unformatted strings to a file.
+  write(f, x)
+
+proc addformat[T](f: File; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` to file `f` using format `fmt`.
+  var g = f
+  writeformat(g, x, fmt)
+
+proc addformat[T](f: File; x: T; fmt: string) {.inline.} =
+  ## Write `x` to file `f` using format string `fmt`. This is the same
+  ## as `addformat(f, x, parse(fmt))`
+  addformat(f, x, parse(fmt))
+
+proc addformat(s: Stream; x: string) {.inline.} =
+  ## Write `x` to `s`. This is a fast specialized version for
+  ## writing unformatted strings to a stream.
+  write(s, x)
+
+proc addformat[T](s: Stream; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` to stream `s` using format `fmt`.
+  var g = s
+  writeformat(g, x, fmt)
+
+proc addformat[T](s: Stream; x: T; fmt: string) {.inline.} =
+  ## Write `x` to stream `s` using format string `fmt`. This is the same
+  ## as `addformat(s, x, parse(fmt))`
+  addformat(s, x, parse(fmt))
+
+proc format[T](x: T; fmt: Format): string =
+  ## Return `x` formatted as a string according to format `fmt`.
+  result = ""
+  addformat(result, x, fmt)
+
+proc format[T](x: T; fmt: string): string =
+  ## Return `x` formatted as a string according to format string `fmt`.
+  result = format(x, fmt.parse)
+
+proc format[T](x: T): string {.inline.} =
+  ## Return `x` formatted as a string according to the default format.
+  ## The default format corresponds to an empty format string.
+  var fmt {.global.} : Format = DefaultFmt
+  result = format(x, fmt)
+
+proc unquoted(s: string): string {.compileTime.} =
+  ## Return `s` {{ and }} by single { and }, respectively.
+  result = ""
+  var pos = 0
+  while pos < s.len:
+    let nxt = pos + skipUntil(s, {'{', '}'})
+    result.add(s.substr(pos, nxt))
+    pos = nxt + 2
+
+proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
+  ## Split format string `s` into a sequence of "parts".
+  ##
+
+  ## Each part is either a literal string or a format specification. A
+  ## format specification is a substring of the form
+  ## "{[arg][:format]}" where `arg` is either empty or a number
+  ## refering to the arg-th argument and an additional field or array
+  ## index. The format string is a string accepted by `parse`.
+  let subpeg = sequence(capture(digits()),
+                          capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),
+                          capture(?sequence(charSet({'['}), +digits(), charSet({']'}))),
+                          capture(?sequence(charSet({':'}), *pegs.any())))
+  result = @[]
+  var pos = 0
+  while true:
+    let oppos = pos + skipUntil(s, {'{', '}'}, pos)
+    # reached the end
+    if oppos >= s.len:
+      if pos < s.len:
+        result.add(Part(kind: pkStr, str: s.substr(pos).unquoted))
+      return
+    # skip double
+    if oppos + 1 < s.len and s[oppos] == s[oppos+1]:
+      result.add(Part(kind: pkStr, str: s.substr(pos, oppos)))
+      pos = oppos + 2
+      continue
+    if s[oppos] == '}':
+      error("Single '}' encountered in format string")
+    if oppos > pos:
+      result.add(Part(kind: pkStr, str: s.substr(pos, oppos-1).unquoted))
+    # find matching closing }
+    var lvl = 1
+    var nested = false
+    pos = oppos
+    while lvl > 0:
+      pos.inc
+      pos = pos + skipUntil(s, {'{', '}'}, pos)
+      if pos >= s.len:
+        error("Single '{' encountered in format string")
+      if s[pos] == '{':
+        lvl.inc
+        if lvl == 2:
+          nested = true
+        if lvl > 2:
+          error("Too many nested format levels")
+      else:
+        lvl.dec
+    let clpos = pos
+    var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: nil, index: int.high, nested: nested)
+    if fmtpart.fmt.len > 0:
+      var m: array[0..3, string]
+      if not fmtpart.fmt.match(subpeg, m):
+        error("invalid format string")
+
+      if m[1] != nil and m[1].len > 0:
+        fmtpart.field = m[1].substr(1)
+      if m[2] != nil and m[2].len > 0:
+        discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index)
+
+      if m[0].len > 0: discard parseInt(m[0], fmtpart.arg)
+      if m[3] == nil or m[3].len == 0:
+        fmtpart.fmt = ""
+      elif m[3][0] == ':':
+        fmtpart.fmt = m[3].substr(1)
+      else:
+        fmtpart.fmt = m[3]
+    result.add(fmtpart)
+    pos = clpos + 1
+
+proc literal(s: string): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of string `s`. This handles the case if
+  ## `s` is nil.
+  result = if s == nil: newNilLit() else: newLit(s)
+
+proc literal(b: bool): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of boolean `b`. This is either `true`
+  ## or `false` symbol.
+  result = if b: "true".ident else: "false".ident
+
+proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of value `x`.
+  when type(x) is enum:
+    result = ($x).ident
+  else:
+    result = newLit(x)
+
+proc generatefmt(fmtstr: string;
+                 args: var openarray[tuple[arg:NimNode, cnt:int]];
+                 arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} =
+  ## fmtstr
+  ##   the format string
+  ## args
+  ##   array of expressions for the arguments
+  ## arg
+  ##   the number of the next argument for automatic parsing
+  ##
+  ## If arg is < 0 then the functions assumes that explicit numbering
+  ## must be used, otherwise automatic numbering is used starting at
+  ## `arg`. The value of arg is updated according to the number of
+  ## arguments being used. If arg == 0 then automatic and manual
+  ## numbering is not decided (because no explicit manual numbering is
+  ## fixed und no automatically numbered argument has been used so
+  ## far).
+  ##
+  ## The function returns a list of pairs `(val, fmt)` where `val` is
+  ## an expression to be formatted and `fmt` is the format string (or
+  ## Format). Therefore, the resulting string can be generated by
+  ## concatenating expressions `val.format(fmt)`. If `fmt` is `nil`
+  ## then `val` is a (literal) string expression.
+  try:
+    result = @[]
+    for part in splitfmt(fmtstr):
+      case part.kind
+      of pkStr: result.add((newLit(part.str), nil))
+      of pkFmt:
+        # first compute the argument expression
+        # start with the correct index
+        var argexpr : NimNode
+        if part.arg >= 0:
+          if arg > 0:
+            error("Cannot switch from automatic field numbering to manual field specification")
+          if part.arg >= args.len:
+            error("Invalid explicit argument index: " & $part.arg)
+          argexpr = args[part.arg].arg
+          args[part.arg].cnt = args[part.arg].cnt + 1
+          arg = -1
+        else:
+          if arg < 0:
+            error("Cannot switch from manual field specification to automatic field numbering")
+          if arg >= args.len:
+            error("Too few arguments for format string")
+          argexpr = args[arg].arg
+          args[arg].cnt = args[arg].cnt + 1
+          arg.inc
+        # possible field access
+        if part.field != nil and part.field.len > 0:
+          argexpr = newDotExpr(argexpr, part.field.ident)
+        # possible array access
+        if part.index < int.high:
+          argexpr = newNimNode(nnkBracketExpr).add(argexpr, newLit(part.index))
+        # now the expression for the format data
+        var fmtexpr: NimNode
+        if part.nested:
+          # nested format string. Compute the format string by
+          # concatenating the parts of the substring.
+          for e in generatefmt(part.fmt, args, arg):
+            var newexpr = if part.fmt == nil: e.val else: newCall(bindsym"format", e.val, e.fmt)
+            if fmtexpr != nil and fmtexpr.kind != nnkNilLit:
+              fmtexpr = infix(fmtexpr, "&", newexpr)
+            else:
+              fmtexpr = newexpr
+        else:
+          # literal format string, precompute the format data
+          fmtexpr = newNimNode(nnkPar)
+          for field, val in part.fmt.parse.fieldPairs:
+            fmtexpr.add(newNimNode(nnkExprColonExpr).add(field.ident, literal(val)))
+        # add argument
+        result.add((argexpr, fmtexpr))
+  finally:
+    discard
+
+proc addfmtfmt(fmtstr: string; args: NimNode; retvar: NimNode): NimNode {.compileTime.} =
+  var argexprs = newseq[tuple[arg:NimNode; cnt:int]](args.len)
+  result = newNimNode(nnkStmtListExpr)
+  # generate let bindings for arguments
+  for i in 0..args.len-1:
+    let argsym = gensym(nskLet, "arg" & $i)
+    result.add(newLetStmt(argsym, args[i]))
+    argexprs[i].arg = argsym
+  # add result values
+  var arg = 0
+  for e in generatefmt(fmtstr, argexprs, arg):
+    if e.fmt == nil or e.fmt.kind == nnkNilLit:
+      result.add(newCall(bindsym"addformat", retvar, e.val))
+    else:
+      result.add(newCall(bindsym"addformat", retvar, e.val, e.fmt))
+  for i, arg in argexprs:
+    if arg.cnt == 0:
+      warning("Argument " & $(i+1) & " `" & args[i].repr & "` is not used in format string")
+
+macro addfmt(s: var string, fmtstr: string{lit}, args: varargs[expr]): expr =
+  ## The same as `s.add(fmtstr.fmt(args...))` but faster.
+  result = addfmtfmt($fmtstr, args, s)
+
+var s: string = ""
+s.addfmt("a:{}", 42)
diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim
new file mode 100644
index 000000000..39edb500f
--- /dev/null
+++ b/tests/tuples/tuple_with_seq.nim
@@ -0,0 +1,46 @@
+discard """
+  output: '''it's nil
+@[1, 2, 3]'''
+"""
+
+template foo(s: string = nil) =
+  if isNil(s):
+    echo "it's nil"
+  else:
+    echo s
+
+foo
+
+
+# bug #2632
+
+proc takeTup(x: tuple[s: string;x: seq[int]]) =
+  discard
+
+takeTup(("foo", @[]))
+
+
+#proc foobar(): () =
+
+proc f(xs: seq[int]) =
+  discard
+
+proc g(t: tuple[n:int, xs:seq[int]]) =
+  discard
+
+when isMainModule:
+  f(@[]) # OK
+  g((1,@[1])) # OK
+  g((0,@[])) # NG
+
+
+# bug #2630
+type T = tuple[a: seq[int], b: int]
+
+var t: T = (@[1,2,3], 7)
+
+proc test(s: seq[int]): T =
+  echo s
+  (s, 7)
+
+t = test(t.a)
diff --git a/tests/tuples/twrongtupleaccess.nim b/tests/tuples/twrongtupleaccess.nim
new file mode 100644
index 000000000..1a9ae64a2
--- /dev/null
+++ b/tests/tuples/twrongtupleaccess.nim
@@ -0,0 +1,10 @@
+discard """
+  file: "twrongtupleaccess.nim"
+  line: 9
+  errormsg: "undeclared identifier: \'setBLAH\'"
+"""
+# Bugfix
+
+var v = (5.0, 10.0)
+v.setBLAH(10)
+
diff --git a/tests/typerel/tcommontype.nim b/tests/typerel/tcommontype.nim
new file mode 100644
index 000000000..8215ebd5e
--- /dev/null
+++ b/tests/typerel/tcommontype.nim
@@ -0,0 +1,20 @@
+type
+  TAnimal=object {.inheritable.}
+  PAnimal=ref TAnimal
+
+  TDog=object of TAnimal
+  PDog=ref TDog
+
+  TCat=object of TAnimal
+  PCat=ref TCat
+
+  TAnimalArray=array[0..2,PAnimal]
+
+proc newDog():PDog = new(result)
+proc newCat():PCat = new(result)
+proc test(a:openarray[PAnimal])=
+  echo("dummy")
+
+#test(newDog(),newCat()) #does not work
+var myarray:TAnimalArray=[newDog(),newCat(),newDog()] #does not work
+#var myarray2:TAnimalArray=[newDog(),newDog(),newDog()] #does not work either
diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim
new file mode 100644
index 000000000..8aec9885a
--- /dev/null
+++ b/tests/typerel/texplicitcmp.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''[1 2 3 ]
+[1 2 3 ]
+[1 2 3 ]'''
+"""
+
+# bug #297
+
+import json, tables, algorithm
+
+proc outp(a: openarray[int]) =
+  stdout.write "["
+  for i in a: stdout.write($i & " ")
+  stdout.write "]\n"
+
+proc works() =
+  var f = @[3, 2, 1]
+  sort(f, system.cmp[int])
+  outp(f)
+
+proc weird(json_params: TTable) =
+  var f = @[3, 2, 1]
+  # The following line doesn't compile: type mismatch. Why?
+  sort(f, system.cmp[int])
+  outp(f)
+
+when isMainModule:
+  var t = @[3, 2, 1]
+  sort(t, system.cmp[int])
+  outp(t)
+  works()
+  weird(initTable[string, TJsonNode]())
diff --git a/tests/typerel/tno_gcmem_in_shared.nim b/tests/typerel/tno_gcmem_in_shared.nim
new file mode 100644
index 000000000..8c81e8db6
--- /dev/null
+++ b/tests/typerel/tno_gcmem_in_shared.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "shared memory may not refer to GC'ed thread local memory"
+  line: 14
+"""
+
+type
+  Region = object
+  Foo = Region ptr int
+
+  MyObject = object
+    a, b: string
+
+  Bar[T] = shared ptr T
+  Bzar = Bar[MyObject]
+
+proc bar(x: Region ptr int) =
+  discard
+
+var
+  s: Foo
+
+bar s
diff --git a/tests/typerel/tno_int_in_bool_context.nim b/tests/typerel/tno_int_in_bool_context.nim
new file mode 100644
index 000000000..755a02c0c
--- /dev/null
+++ b/tests/typerel/tno_int_in_bool_context.nim
@@ -0,0 +1,8 @@
+discard """
+  line: 6
+  errormsg: "type mismatch: got (int literal(1)) but expected 'bool'"
+"""
+
+if 1: 
+  echo "wtf?"
+  
diff --git a/tests/typerel/tnoargopenarray.nim b/tests/typerel/tnoargopenarray.nim
new file mode 100644
index 000000000..3e65194ff
--- /dev/null
+++ b/tests/typerel/tnoargopenarray.nim
@@ -0,0 +1,7 @@
+
+import db_sqlite
+
+var db: TDbConn
+exec(db, sql"create table blabla()")
+
+
diff --git a/tests/typerel/tnocontains.nim b/tests/typerel/tnocontains.nim
new file mode 100644
index 000000000..4f4951478
--- /dev/null
+++ b/tests/typerel/tnocontains.nim
@@ -0,0 +1,11 @@
+discard """
+  file: "tnocontains.nim"
+  line: 10
+  errormsg: "type mismatch: got (string, string)"
+"""
+
+# shouldn't compile since it doesn't do what you think it does without
+# importing strutils:
+
+let x = "abcdef".contains("abc")
+echo x
diff --git a/tests/typerel/trectuple.nim b/tests/typerel/trectuple.nim
new file mode 100644
index 000000000..334c4a911
--- /dev/null
+++ b/tests/typerel/trectuple.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "illegal recursion in type 'TNode'"
+  line: 8
+  disabled: true
+"""
+
+type
+    PNode = ref TNode
+    TNode = tuple # comment
+      self: PNode # comment
+      a, b: int # comment
+
+var node: PNode
+new(node)
+node.self = node
+
diff --git a/tests/typerel/trectuples.nim b/tests/typerel/trectuples.nim
new file mode 100644
index 000000000..a74e4859c
--- /dev/null
+++ b/tests/typerel/trectuples.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "illegal recursion in type 'Node'"
+  line: 6
+"""
+
+type Node = tuple[left: ref Node]
+
+proc traverse(root: ref Node) =
+  if root.left != nil: traverse(root.left)
+  
+type A = tuple[B: ptr A]
+proc C(D: ptr A) = C(D.B)
+
+
diff --git a/tests/typerel/trectype.nim b/tests/typerel/trectype.nim
new file mode 100644
index 000000000..7bb12a3b6
--- /dev/null
+++ b/tests/typerel/trectype.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "internal error: cannot generate C type for: PA"
+"""
+# Test recursive type descriptions
+# (mainly for the C code generator)
+
+type
+  PA = ref TA
+  TA = array [0..2, PA]
+
+  PRec = ref TRec
+  TRec {.final.} = object
+    a, b: TA
+
+  P1 = ref T1
+  PB = ref TB
+  TB = array [0..3, P1]
+  T1 = array [0..6, PB]
+
+var
+  x: PA
+new(x)
+#ERROR_MSG internal error: cannot generate C type for: PA
+
+
+
diff --git a/tests/typerel/trefs.nim b/tests/typerel/trefs.nim
new file mode 100644
index 000000000..b157ca2b5
--- /dev/null
+++ b/tests/typerel/trefs.nim
@@ -0,0 +1,23 @@
+discard """
+  file: "trefs.nim"
+  line: 20
+  errormsg: "type mismatch"
+"""
+# test for ref types (including refs to procs)

+

+type

+  TProc = proc (a, b: int): int {.stdcall.}

+

+proc foo(c, d: int): int {.stdcall.} =

+  return 0

+

+proc wrongfoo(c, e: int): int {.inline.} =

+  return 0

+

+var p: TProc

+p = foo

+write(stdout, "success!")

+p = wrongfoo  #ERROR_MSG type mismatch

+

+
+
diff --git a/tests/typerel/tregionptrs.nim b/tests/typerel/tregionptrs.nim
new file mode 100644
index 000000000..07387fed8
--- /dev/null
+++ b/tests/typerel/tregionptrs.nim
@@ -0,0 +1,16 @@
+discard """
+  line: 16
+  errormsg: "type mismatch: got (BPtr) but expected 'APtr'"
+"""
+
+type
+  RegionA = object
+  APtr = RegionA ptr int
+  RegionB = object
+  BPtr = RegionB ptr int
+  
+var x,xx: APtr
+var y: BPtr
+x = nil
+x = xx
+x = y
diff --git a/tests/typerel/tregionptrs2.nim b/tests/typerel/tregionptrs2.nim
new file mode 100644
index 000000000..3b32ff93d
--- /dev/null
+++ b/tests/typerel/tregionptrs2.nim
@@ -0,0 +1,23 @@
+
+# bug #2039
+
+type
+    RegionTy = object
+    ThingyPtr = RegionTy ptr Thingy
+    Thingy = object
+        next: ThingyPtr
+        name: string
+
+proc iname(t: ThingyPtr) = 
+    var x = t
+
+    while not x.isNil:
+        echo x.name
+        x = x.next
+
+proc go() = 
+    var athing : ThingyPtr
+
+    iname(athing)
+
+go()
diff --git a/tests/typerel/trettypeinference.nim b/tests/typerel/trettypeinference.nim
new file mode 100644
index 000000000..41b4aa5ef
--- /dev/null
+++ b/tests/typerel/trettypeinference.nim
@@ -0,0 +1,33 @@
+discard """
+  msg:    "instantiated for string\ninstantiated for int\ninstantiated for bool"
+  output: "int\nseq[string]\nA\nB\n100\ntrue"
+"""
+
+import typetraits
+
+proc plus(a, b): auto = a + b
+proc makePair(a, b): auto = (first: a, second: b)
+
+proc `+`(a, b: string): seq[string] = @[a, b]
+
+var i = plus(10, 20)
+var s = plus("A", "B")
+
+var p = makePair("key", 100)
+static: assert p[0].type is string
+
+echo i.type.name
+echo s.type.name
+
+proc inst(a): auto =
+  static: echo "instantiated for ", a.type.name
+  result = a
+
+echo inst("A")
+echo inst("B")
+echo inst(100)
+echo inst(true)
+
+# XXX: [string, tyGenericParam] is cached instead of [string, string]
+# echo inst[string, string]("C")
+
diff --git a/tests/typerel/tsecondarrayproperty.nim b/tests/typerel/tsecondarrayproperty.nim
new file mode 100644
index 000000000..07fdac1c4
--- /dev/null
+++ b/tests/typerel/tsecondarrayproperty.nim
@@ -0,0 +1,28 @@
+
+type
+  TFoo = object
+    data: array[0..100, int]
+  TSecond = distinct TFoo
+
+proc `[]` (self: var TFoo, x: int): var int =
+  return self.data[x]
+
+proc `[]=` (self: var TFoo, x, y: int) =
+  # only `[]` returning a 'var T' seems to not work for now :-/
+  self.data[x] = y
+
+proc second(self: var TFoo): var TSecond =
+  return TSecond(self)
+
+proc `[]`(self: var TSecond, x: int): var int =  
+  return TFoo(self).data[2*x]
+
+var f: TFoo
+
+for i in 0..f.data.high: f[i] = 2 * i
+
+echo f.second[1]
+
+#echo `second[]`(f,1)
+# this is the only way I could use it, but not what I expected
+
diff --git a/tests/typerel/tsymchoice_for_expr.nim b/tests/typerel/tsymchoice_for_expr.nim
new file mode 100644
index 000000000..4c1f52bef
--- /dev/null
+++ b/tests/typerel/tsymchoice_for_expr.nim
@@ -0,0 +1,15 @@
+# bug #1988
+
+template t(e: expr) = discard
+
+proc positive(x: int): int = +x
+proc negative(x: int): int = -x
+proc negative(x: float): float = -x
+
+proc p1 = t(negative)
+proc p2[X] = t(positive)
+proc p3[X] = t(negative)
+
+p1()      # This compiles.
+p2[int]() # This compiles.
+p3[int]() # This raises an error.
diff --git a/tests/typerel/ttuple1.nim b/tests/typerel/ttuple1.nim
new file mode 100644
index 000000000..5787cc309
--- /dev/null
+++ b/tests/typerel/ttuple1.nim
@@ -0,0 +1,16 @@
+const romanNumbers = [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1) ]
+
+var c = 0
+for key, val in items(romanNumbers):
+  inc(c)
+  stdout.write(key & "=" & $val)
+  if c < romanNumbers.len: stdout.write(", ") else: echo""
+#echo""
+
+proc PrintBiTuple(t: tuple[k: string, v: int]): int =
+  stdout.write(t.k & "=" & $t.v & ", ")
+  return 0
+  
+
diff --git a/tests/typerel/ttypelessemptyset.nim b/tests/typerel/ttypelessemptyset.nim
new file mode 100644
index 000000000..3e171387b
--- /dev/null
+++ b/tests/typerel/ttypelessemptyset.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "internal error: invalid kind for last(tyEmpty)"
+"""
+var q = false
+discard (if q: {} else: {})
+
diff --git a/tests/typerel/ttypenoval.nim b/tests/typerel/ttypenoval.nim
new file mode 100644
index 000000000..214b35e29
--- /dev/null
+++ b/tests/typerel/ttypenoval.nim
@@ -0,0 +1,55 @@
+discard """
+  file: "ttypenoval.nim"
+  line: 38
+  errormsg: "type mismatch: got (typedesc[int]) but expected 'int'"
+"""
+
+# A min-heap.
+type
+  TNode[T] = tuple[priority: int, data: T]
+
+  TBinHeap[T] = object
+    heap: seq[TNode[T]]
+    last: int
+  
+  PBinHeap[T] = ref TBinHeap[T]
+
+proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
+  new(heap)
+  heap.last = 0
+  newSeq(heap.heap, size)
+  #newSeq(heap.seq, size)
+ 
+proc parent(elem: int): int {.inline.} =
+  return (elem-1) div 2
+
+proc siftUp[T](heap: PBinHeap[T], elem: int) =
+  var idx = elem
+  while idx != 0:
+    var p = parent(idx)
+    if heap.heap[idx] < heap.heap[p]:
+      swap(heap.heap[idx], heap.heap[p])
+      idx = p
+    else:
+      break
+
+proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
+  var node: TNode[T]
+  node.priority = int
+  node.data = data
+  heap.heap[heap.last] = node
+  siftUp(heap, heap.last)
+  inc(heap.last)
+
+proc print*[T](heap: PBinHeap[T]) =
+  for i in countup(0, heap.last):
+    echo($heap.heap[i])
+
+var
+  heap: PBinHeap[int]
+
+newBinHeap(heap, 256)
+add(heap, 1, 100)
+print(heap)
+
+
diff --git a/tests/typerel/ttypenovalue.nim b/tests/typerel/ttypenovalue.nim
new file mode 100644
index 000000000..b86baf8b4
--- /dev/null
+++ b/tests/typerel/ttypenovalue.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "value expected, but got a type"
+  line: 7
+  disabled: true
+"""
+
+proc crashAndBurn() =
+  var stuff = seq[tuple[title, body: string]]
+
+
+crashAndBurn()
diff --git a/tests/typerel/tvarargsexpr.nim b/tests/typerel/tvarargsexpr.nim
new file mode 100644
index 000000000..fcb49af61
--- /dev/null
+++ b/tests/typerel/tvarargsexpr.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''success'''
+"""
+
+#bug #913
+
+import macros
+
+macro thirteen(args: varargs[expr]): expr = 
+  result = newIntLitNode(13)
+
+doAssert(13==thirteen([1,2])) # works
+doAssert(13==thirteen(1,2)) # works
+
+doAssert(13==thirteen(1,[2])) # does not work
+doAssert(13==thirteen([1], 2)) # does not work
+
+echo "success"
diff --git a/tests/typerel/tvoid.nim b/tests/typerel/tvoid.nim
new file mode 100644
index 000000000..d31936217
--- /dev/null
+++ b/tests/typerel/tvoid.nim
@@ -0,0 +1,37 @@
+discard """
+  output: '''12
+empty
+he, no return type;
+abc a string
+ha'''
+"""
+
+proc ReturnT[T](x: T): T =
+  when T is void:
+    echo "he, no return type;"
+  else:
+    result = x & " a string"
+
+proc nothing(x, y: void): void =
+  echo "ha"
+
+proc callProc[T](p: proc (x: T) {.nimcall.}, x: T) =
+  when T is void: 
+    p()
+  else:
+    p(x)
+
+proc intProc(x: int) =
+  echo x
+  
+proc emptyProc() =
+  echo "empty"
+
+callProc[int](intProc, 12)
+callProc[void](emptyProc)
+
+
+ReturnT[void]()
+echo ReturnT[string]("abc")
+nothing()
+
diff --git a/tests/typerel/typalias.nim b/tests/typerel/typalias.nim
new file mode 100644
index 000000000..55dcb9fa6
--- /dev/null
+++ b/tests/typerel/typalias.nim
@@ -0,0 +1,15 @@
+
+type
+  TMyObj = TYourObj
+  TYourObj = object of RootObj
+    x, y: int
+  
+proc init: TYourObj =
+  result.x = 0
+  result.y = -1
+  
+proc f(x: var TYourObj) =
+  discard
+  
+var m: TMyObj = init()
+f(m)
diff --git a/tests/typerel/typedescs.nim b/tests/typerel/typedescs.nim
new file mode 100644
index 000000000..23b9ce64f
--- /dev/null
+++ b/tests/typerel/typedescs.nim
@@ -0,0 +1,7 @@
+# bug #1774
+proc p(T: typedesc) = discard
+
+p(type((5, 6)))       # Compiles
+(type((5, 6))).p      # Doesn't compile (SIGSEGV: Illegal storage access.)
+type T = type((5, 6)) # Doesn't compile (SIGSEGV: Illegal storage access.)
+
diff --git a/tests/typerel/typredef.nim b/tests/typerel/typredef.nim
new file mode 100644
index 000000000..0b6aed875
--- /dev/null
+++ b/tests/typerel/typredef.nim
@@ -0,0 +1,8 @@
+discard """
+  file: "typredef.nim"
+  line: 7
+  errormsg: "illegal recursion in type \'Uint8\'"
+"""
+type
+  Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'
+
diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim
new file mode 100644
index 000000000..60e83c510
--- /dev/null
+++ b/tests/types/tauto_canbe_void.nim
@@ -0,0 +1,9 @@
+
+import future
+
+template tempo(s: expr) =
+  s("arg")
+
+tempo((s: string)->auto => echo(s))
+tempo((s: string) => echo(s))
+
diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim
new file mode 100644
index 000000000..834f63729
--- /dev/null
+++ b/tests/types/temptyseqs.nim
@@ -0,0 +1,90 @@
+discard """
+  output: '''1
+foo
+bar
+baz
+foo
+bar
+baz
+yes
+no'''
+"""
+
+# bug #1708
+let foo = {
+  "1" : (bar: @["1"]),
+  "2" : (bar: @[])
+}
+
+# bug #871
+
+when true:
+  import os
+
+  type
+    In_out = tuple[src, dest, options: string]
+
+  let
+    nil_var: In_out = ("hey"/"there", "something", nil)
+    #nil_var2 = ("hey"/"there", "something", nil)
+
+# bug #1721
+const foo2: seq[string] = @[]
+
+echo foo[0][0][0]
+
+proc takeEmpty(x: openArray[string] = []) = discard
+takeEmpty()
+takeEmpty([])
+
+proc takeEmpty2(x: openArray[string] = @[]) = discard
+takeEmpty2()
+takeEmpty2([])
+takeEmpty2(@[])
+
+#takeEmpty2([nil])
+
+#rawMessage(errExecutionOfProgramFailed, [])
+
+# bug #2470
+const
+  stuff: seq[string] = @[]
+
+for str in stuff:
+  echo "str=", str
+
+# bug #1354
+proc foo4[T](more: seq[T] = @[]) =
+  var more2 = more
+
+foo4[int]()
+
+proc maino: int =
+  var wd: cstring = nil
+  inc result
+
+discard maino()
+
+proc varargso(a: varargs[string]) =
+  for x in a:
+    echo x
+
+varargso(["foo", "bar", "baz"])
+varargso("foo", "bar", "baz")
+
+
+type
+  Flago = enum
+    tfNeedsInit, tfNotNil
+
+var s: set[Flago] = {tfNeedsInit}
+
+if {tfNeedsInit, tfNotNil} * s != {}:
+  echo "yes"
+else:
+  echo "no"
+
+if {tfNeedsInit, tfNotNil} * s <= {tfNotNil}:
+  echo "yes"
+else:
+  echo "no"
diff --git a/tests/types/tfinalobj.nim b/tests/types/tfinalobj.nim
new file mode 100644
index 000000000..1cd7fae28
--- /dev/null
+++ b/tests/types/tfinalobj.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "abc"
+"""
+
+type
+  TA = object {.pure, final.} 
+    x: string
+    
+var
+  a: TA
+a.x = "abc"
+
+doAssert TA.sizeof == string.sizeof
+
+echo a.x
+
diff --git a/tests/types/tforwty.nim b/tests/types/tforwty.nim
new file mode 100644
index 000000000..0f1d3697f
--- /dev/null
+++ b/tests/types/tforwty.nim
@@ -0,0 +1,9 @@
+# Test 13: forward types

+

+type

+  PSym = ref TSym

+

+  TSym = object

+    next: PSym

+

+var s: PSym

diff --git a/tests/types/tforwty2.nim b/tests/types/tforwty2.nim
new file mode 100644
index 000000000..52af1c7dd
--- /dev/null
+++ b/tests/types/tforwty2.nim
@@ -0,0 +1,22 @@
+# Test for a hard to fix internal error

+# occurred in the SDL library

+

+{.push dynlib: "SDL.dll", callconv: cdecl.}

+

+type

+  PSDL_semaphore = ptr TSDL_semaphore

+  TSDL_semaphore {.final.} = object

+    sem: pointer             #PSem_t;

+    when not defined(USE_NAMED_SEMAPHORES):

+      sem_data: int

+    when defined(BROKEN_SEMGETVALUE):

+      # This is a little hack for MacOS X -

+      # It's not thread-safe, but it's better than nothing

+      sem_value: cint

+

+type

+  PSDL_Sem = ptr TSDL_Sem

+  TSDL_Sem = TSDL_Semaphore

+

+proc SDL_CreateSemaphore(initial_value: int32): PSDL_Sem {.

+  importc: "SDL_CreateSemaphore".}

diff --git a/tests/types/tillegaltyperecursion.nim b/tests/types/tillegaltyperecursion.nim
new file mode 100644
index 000000000..ebdbc1d13
--- /dev/null
+++ b/tests/types/tillegaltyperecursion.nim
@@ -0,0 +1,66 @@
+discard """
+  cmd: "nim $target --threads:on $options $file"
+  errormsg: "illegal recursion in type 'TIRC'"
+  line: 16
+"""
+
+import events
+import sockets
+import strutils
+import os
+
+type
+    TMessageReceivedEventArgs = object of TEventArgs
+        Nick*: string
+        Message*: string
+    TIRC = object
+        EventEmitter: TEventEmitter
+        MessageReceivedHandler*: TEventHandler
+        Socket: TSocket
+        Thread: TThread[TIRC]
+        
+proc initIRC*(): TIRC =
+    result.Socket = socket()
+    result.EventEmitter = initEventEmitter()
+    result.MessageReceivedHandler = initEventHandler("MessageReceived")
+
+proc IsConnected*(irc: var TIRC): bool =
+    return running(irc.Thread)
+  
+   
+proc sendRaw*(irc: var TIRC, message: string) =
+    irc.Socket.send(message & "\r\L")
+proc handleData(irc: TIRC) {.thread.} =
+    var connected = False
+    while connected:
+        var tup = @[irc.Socket]
+        var o = select(tup, 200)
+        echo($o)
+        echo($len(tup))
+        if len(tup) == 1:
+            #Connected
+            connected = True
+            
+            #Parse data here
+            
+        else:
+            #Disconnected
+            connected = False
+            return
+   
+proc Connect*(irc: var TIRC, nick: string, host: string, port: int = 6667) =
+    connect(irc.Socket ,host ,TPort(port),TDomain.AF_INET)
+    send(irc.Socket,"USER " & nick & " " & nick & " " & nick & " " & nick &"\r\L")
+    send(irc.Socket,"NICK " & nick & "\r\L")
+    var thread: TThread[TIRC]
+    createThread(thread, handleData, irc)
+    irc.Thread = thread
+
+
+        
+        
+when isMainModule:
+    var irc = initIRC()
+    irc.Connect("AmryBot[Nim]","irc.freenode.net",6667)
+    irc.sendRaw("JOIN #nim")
+    os.Sleep(4000)
diff --git a/tests/types/tillrec.nim b/tests/types/tillrec.nim
new file mode 100644
index 000000000..18757140a
--- /dev/null
+++ b/tests/types/tillrec.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tillrec.nim"
+  line: 13
+  errormsg: "illegal recursion in type \'TIllegal\'"
+"""
+# test illegal recursive types
+
+type
+  TLegal {.final.} = object
+    x: int
+    kids: seq[TLegal]
+
+  TIllegal {.final.} = object  #ERROR_MSG illegal recursion in type 'TIllegal'
+    y: int
+    x: array[0..3, TIllegal]
+
diff --git a/tests/types/tinfiniterecursion.nim b/tests/types/tinfiniterecursion.nim
new file mode 100644
index 000000000..52eaaa93b
--- /dev/null
+++ b/tests/types/tinfiniterecursion.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "illegal recursion in type 'XIM'"
+  line: 8
+"""
+
+type
+  XIM* = ptr XIM
+  XIMProc* = proc (a2: XIM)
diff --git a/tests/types/tinheritref.nim b/tests/types/tinheritref.nim
new file mode 100644
index 000000000..e5de6a4be
--- /dev/null
+++ b/tests/types/tinheritref.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "23"
+"""
+
+# bug #554, #179
+
+type T[E] =
+  ref object
+    elem: E
+
+var ob: T[int]
+
+ob = T[int](elem: 23)
+echo ob.elem
+
+type
+  TTreeIteratorA* = ref object {.inheritable.}
+
+  TKeysIteratorA* = ref object of TTreeIteratorA  #compiles
+
+  TTreeIterator* [T,D] = ref object {.inheritable.}
+
+  TKeysIterator* [T,D] = ref object of TTreeIterator[T,D]  #this not
+  
+var
+  it: TKeysIterator[int, string] = nil
+
diff --git a/tests/types/tisop.nim b/tests/types/tisop.nim
new file mode 100644
index 000000000..05c6a1a06
--- /dev/null
+++ b/tests/types/tisop.nim
@@ -0,0 +1,48 @@
+discard """
+  disabled: true
+"""
+
+import typetraits
+
+type
+  TRecord = (tuple) or (object)
+  
+  TFoo[T, U] = object
+    x: int
+
+    when T is string:
+      y: float
+    else:
+      y: string
+
+    when U is TRecord:
+      z: float
+
+  E = enum A, B, C
+
+macro m(t: typedesc): typedesc =
+  if t is enum:
+    result = string
+  else:
+    result = int
+
+var f: TFoo[int, int]
+static: assert(f.y.type.name == "string")
+
+when compiles(f.z):
+  {.error: "Foo should not have a `z` field".}
+
+proc p(a, b) =
+  when a.type is int:
+    static: assert false
+
+  var f: TFoo[m(a.type), b.type]
+  static:
+    assert f.x.type.name == "int"
+    echo  f.y.type.name
+    assert f.y.type.name == "float"
+    echo  f.z.type.name
+    assert f.z.type.name == "float"
+
+p(A, f)
+
diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim
new file mode 100644
index 000000000..b9acfa5fb
--- /dev/null
+++ b/tests/types/tisopr.nim
@@ -0,0 +1,90 @@
+discard """
+  output: '''true true false yes
+false
+false
+false
+true
+true
+no'''
+"""
+
+proc IsVoid[T](): string =
+  when T is void:
+    result = "yes"
+  else:
+    result = "no"
+
+const x = int is int
+echo x, " ", float is float, " ", float is string, " ", IsVoid[void]()
+
+template yes(e: expr): stmt =
+  static: assert e
+
+template no(e: expr): stmt =
+  static: assert(not e)
+
+var s = @[1, 2, 3]
+
+yes s.items is iterator
+no  s.items is proc
+
+yes s.items is iterator: int
+no  s.items is iterator: float
+
+yes s.items is iterator: TNumber
+no  s.items is iterator: object
+
+type
+  Iter[T] = iterator: T
+
+yes s.items is Iter[TNumber]
+no  s.items is Iter[float]
+
+type
+  Foo[N: static[int], T] = object
+    field: array[1..N, T]
+
+  Bar[T] = Foo[4, T]
+  Baz[N: static[int]] = Foo[N, float]
+
+no Foo[2, float] is Foo[3, float]
+no Foo[2, float] is Foo[2, int]
+
+yes Foo[4, string] is Foo[4, string]
+yes Bar[int] is Foo[4, int]
+yes Foo[4, int] is Bar[int]
+
+no Foo[4, int] is Baz[4]
+yes Foo[4, float] is Baz[4]
+
+
+# bug #2505
+
+echo(8'i8 is int32)
+
+# bug #1853
+type SeqOrSet[E] = seq[E] or set[E]
+type SeqOfInt = seq[int]
+type SeqOrSetOfInt = SeqOrSet[int]
+
+# This prints "false", which seems less correct that (1) printing "true" or (2)
+# raising a compiler error.
+echo seq is SeqOrSet
+
+# This prints "false", as expected.
+echo seq is SeqOrSetOfInt
+
+# This prints "true", as expected.
+echo SeqOfInt is SeqOrSet
+
+# This causes an internal error (filename: compiler/semtypes.nim, line: 685).
+echo SeqOfInt is SeqOrSetOfInt
+
+# bug #2522
+proc test[T](x: T) =
+  when T is typedesc:
+    echo "yes"
+  else:
+    echo "no"
+
+test(7)
diff --git a/tests/usingstmt/tusingstatement.nim b/tests/usingstmt/tusingstatement.nim
new file mode 100644
index 000000000..0d76b2423
--- /dev/null
+++ b/tests/usingstmt/tusingstatement.nim
@@ -0,0 +1,89 @@
+discard """
+  file: "tusingstatement.nim"
+  output: "Using test.Closing test."
+"""
+
+import
+  macros
+
+# This macro mimics the using statement from C#
+#
+# It's kept only as a test for the macro system
+# Nim's destructors offer a mechanism for automatic
+# disposal of resources.
+#
+macro autoClose(e: expr): stmt {.immediate.} =
+  let e = callsite()
+  if e.len != 3:
+    error "Using statement: unexpected number of arguments. Got " &
+      $e.len & ", expected: 1 or more variable assignments and a block"
+
+  var args = e
+  var body = e[2]
+
+  var
+    variables : seq[NimNode]
+    closingCalls : seq[NimNode]
+
+  newSeq(variables, 0)
+  newSeq(closingCalls, 0)
+
+  for i in countup(1, args.len-2):
+    if args[i].kind == nnkExprEqExpr:
+      var varName = args[i][0]
+      var varValue = args[i][1]
+
+      var varAssignment = newNimNode(nnkIdentDefs)
+      varAssignment.add(varName)
+      varAssignment.add(newNimNode(nnkEmpty)) # empty means no type
+      varAssignment.add(varValue)
+      variables.add(varAssignment)
+
+      closingCalls.add(newCall(!"close", varName))
+    else:
+      error "Using statement: Unexpected expression. Got " &
+        $args[i].kind & " instead of assignment."
+
+  var varSection = newNimNode(nnkVarSection)
+  varSection.add(variables)
+
+  var finallyBlock = newNimNode(nnkStmtList)
+  finallyBlock.add(closingCalls)
+
+  # XXX: Use a template here once getAst is working properly
+  var targetAst = parseStmt"""block:
+    var
+      x = foo()
+      y = bar()
+
+    try:
+      body()
+
+    finally:
+      close x
+      close y
+  """
+
+  targetAst[0][1][0] = varSection
+  targetAst[0][1][1][0] = body
+  targetAst[0][1][1][1][0] = finallyBlock
+
+  result = targetAst
+
+type
+  TResource* = object
+    field*: string
+
+proc openResource(param: string): TResource =
+  result.field = param
+
+proc close(r: var TResource) =
+  write(stdout, "Closing " & r.field & ".")
+
+proc use(r: var TResource) =
+  write(stdout, "Using " & r.field & ".")
+
+autoClose(r = openResource("test")):
+  use r
+
+
diff --git a/tests/varres/tvarres1.nim b/tests/varres/tvarres1.nim
new file mode 100644
index 000000000..de4a505d3
--- /dev/null
+++ b/tests/varres/tvarres1.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tvarres1.nim"
+  line: 12
+  errormsg: "address of 'bla' may not escape its stack frame"
+"""
+
+var
+  g = 5
+
+proc p(): var int = 
+  var bla: int
+  result = bla
+  
+p() = 45
+
+echo g
+
diff --git a/tests/varres/tvarres2.nim b/tests/varres/tvarres2.nim
new file mode 100644
index 000000000..165e4a36e
--- /dev/null
+++ b/tests/varres/tvarres2.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tvarres2.nim"
+  line: 11
+  errormsg: "expression has no address"
+"""
+
+var
+  g = 5
+
+proc p(): var int = 
+  result = 89
+  
+p() = 45
+
+echo g
+
diff --git a/tests/varres/tvarres3.nim b/tests/varres/tvarres3.nim
new file mode 100644
index 000000000..a48c961df
--- /dev/null
+++ b/tests/varres/tvarres3.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "45"
+"""
+
+var
+  g = 5
+
+proc p(): var int = 
+  var bla = addr(g) #: array [0..7, int]
+  result = bla[]
+  
+p() = 45
+
+echo g
+
diff --git a/tests/varres/tvarres4.nim b/tests/varres/tvarres4.nim
new file mode 100644
index 000000000..119560e7b
--- /dev/null
+++ b/tests/varres/tvarres4.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "45 hallo"
+"""
+
+type
+  TKachel = tuple[i: int, s: string]
+  TSpielwiese = object
+    k: seq[TKachel]
+
+var
+  spielwiese: TSpielwiese
+newSeq(spielwiese.k, 64)
+
+proc at*(s: var TSpielwiese, x, y: int): var TKachel =
+  result = s.k[y * 8 + x]
+
+spielwiese.at(3, 4) = (45, "hallo")
+
+echo spielwiese.at(3,4)[0], " ", spielwiese.at(3,4)[1]
+
diff --git a/tests/varres/tvartup.nim b/tests/varres/tvartup.nim
new file mode 100644
index 000000000..f885cdf37
--- /dev/null
+++ b/tests/varres/tvartup.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tvartup.nim"
+  output: "2 3"
+"""
+# Test the new tuple unpacking
+
+proc divmod(a, b: int): tuple[di, mo: int] =
+  return (a div b, a mod b)
+  
+var (x, y) = divmod(15, 6)
+stdout.write(x)
+stdout.write(" ")
+stdout.write(y)
+
+#OUT 2 3
+
+
diff --git a/tests/varstmt/tlet.nim b/tests/varstmt/tlet.nim
new file mode 100644
index 000000000..138f34433
--- /dev/null
+++ b/tests/varstmt/tlet.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''Very funny, your name is name.
+nameabc'''
+"""
+
+proc main =
+  let name = "name"
+  if name == "":
+    echo("Poor soul, you lost your name?")
+  elif name == "name":
+    echo("Very funny, your name is name.")
+  else:
+    echo("Hi, ", name, "!")
+    
+  let (x, y) = ("abc", name)
+  echo y, x
+
+main()
+
diff --git a/tests/varstmt/tvardecl.nim b/tests/varstmt/tvardecl.nim
new file mode 100644
index 000000000..5cc6f4960
--- /dev/null
+++ b/tests/varstmt/tvardecl.nim
@@ -0,0 +1,15 @@
+discard """
+  file: "tvardecl.nim"
+  output: "44"
+"""
+# Test the new variable declaration syntax

+

+var

+  x = 0

+  s = "Hallo"

+  a, b: int = 4

+

+write(stdout, a)

+write(stdout, b) #OUT 44

+
+
diff --git a/tests/vm/tarrayboundeval.nim b/tests/vm/tarrayboundeval.nim
new file mode 100644
index 000000000..07aac4c4e
--- /dev/null
+++ b/tests/vm/tarrayboundeval.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''7
+8 8
+-2'''
+"""
+
+#bug 1063
+
+const
+  KeyMax = 227
+  myconst = int((KeyMax + 31) / 32)
+
+type
+  FU = array[int((KeyMax + 31) / 32), cuint]
+
+echo FU.high
+
+type 
+  PKeyboard* = ptr object
+  TKeyboardState* = object
+    display*: pointer
+    internal: array[int((KeyMax + 31)/32), cuint]
+    
+echo myconst, " ", int((KeyMax + 31) / 32)
+
+#bug 1304 or something:
+
+const constArray: array [-3..2, int] = [-3, -2, -1, 0, 1, 2]
+
+echo constArray[-2]
+
diff --git a/tests/vm/tasmparser.nim b/tests/vm/tasmparser.nim
new file mode 100644
index 000000000..67313c858
--- /dev/null
+++ b/tests/vm/tasmparser.nim
@@ -0,0 +1,174 @@
+
+# bug #1513
+
+import os, parseutils, strutils, ropes, macros
+
+var
+  code {.compileTime.} = ""
+  start {.compileTime.} = 0
+  line {.compileTime.} = 1
+  cpp {.compileTime.} = ""
+  token {.compileTime.} = ""
+
+proc log (msg: string) {.compileTime.} =
+    echo msg
+
+proc asmx64 () {.compileTime} =
+
+  #log "code = $1" % code
+
+  const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {"
+  const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} "
+
+  const xp = "x."
+
+  const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' }
+  const symbol = { '0'..'9' } + symbolStart
+  const eolComment = { ';' }
+  const endOfLine = { '\l', '\r' }
+  const leadingWhiteSpace = { ' ' }
+
+  const end_or_comment = endOfLine + eolComment + { '\0' }
+
+  const passthrough_start = { '{', '`' }
+  const passthrough_end = { '}', '`', '\0' }
+
+  const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start
+
+
+  proc abortAsmParse (err:string) =
+    discard
+
+  let codeLen = code.len
+  #let codeEnd = codeLen-1
+  cpp.add asmx64pre
+
+  #log "{$1}\n" % [code]
+
+  type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine
+
+  var state:asmParseState = leading
+
+  proc checkEnd (err:string) =
+    let ch = code [start]
+    if int (ch) == 0:
+      abortAsmParse (err)
+
+  proc get_passthrough () =
+    inc start
+    let prev_start = start
+    let prev_token = token
+    start += code.parseUntil (token, passthrough_end, start)
+    checkEnd ("Failed to find passthrough end delimiter from offset $1 for:$2\n$3" % [$prev_start, $(code [prev_start-prev_token.len..prev_start]), token[1..token.len-1]])
+    inc start
+    cpp.add "`"
+    cpp.add token
+    cpp.add "`"
+
+  var inparse = true
+
+  proc checkCmdEnd () =
+    if codeLen == start:
+      state = endCmd
+      inparse = false
+
+  while inparse:
+    checkCmdEnd ()
+
+    log ("state=$1 start=$2" % [$state, $start])
+
+    case state:
+    of leading:
+      
+      echo "b100 ", start
+      start += code.skipWhile (leadingWhiteSpace, start)
+      echo "b200 ", start
+      let ch = code [start]
+      if ch in endOfLine:
+        inc (line)
+        #echo "c100 ", start, ' ', code 
+        start += code.skipWhile (endOfline, start)
+        #echo "c200 ", start, ' ', code 
+        continue
+      elif ch in symbolStart:
+        state = mnemonic
+      elif ch in eolComment:
+        state = skipToEndOfLine
+      elif ch in passthrough_start:
+        get_passthrough ()        
+        echo "d100 ", start
+        start += code.parseUntil (token, end_or_symbol_or_comment_or_passthrough, start)
+        echo "d200 ", start
+        cpp.add token
+        state = mnemonic
+      elif int (ch) == 0:
+        break
+      else:
+        abortAsmParse ("after '$3' illegal character at offset $1: $2" % [$start, $(int (ch)), token])
+
+    of mnemonic:
+      echo "e100 ", start
+      start += code.parseWhile (token, symbol, start)
+      echo "e200 ", start
+      cpp.add xp
+      cpp.add token
+      cpp.add "("
+      state = betweenArguments
+
+    of betweenArguments:
+      let tmp = start
+      let rcode = code
+      start += rcode.parseUntil (token, end_or_symbol_or_comment_or_passthrough, tmp)
+      cpp.add token
+
+      if codeLen <= start:
+        state = endCmd
+        continue
+        
+      let ch = code [start]
+      if ch in passthrough_start:
+        get_passthrough ()
+        continue
+      if (ch in {'x', 'X'}) and ('0' == code [start-1]):
+        token = $(code [start])
+        cpp.add token
+        inc start
+        continue
+      state = arguments
+
+    of arguments:
+      if code [start] in end_or_comment:
+        state = endCmd
+        continue
+      start += code.parseWhile (token, symbol, start)
+      cpp.add xp
+      cpp.add token
+      state = betweenArguments
+
+    of endCmd:
+      cpp.add ");\n"
+      state = skipToEndOfLine
+    
+    of skipToEndOfLine:
+      echo "a100 ", start
+      start += code.skipUntil (endOfLine, start)
+      echo "a200 ", start
+      start += code.skipWhile (endOfline, start)
+      echo "a300 ", start
+      inc line
+      state = leading
+
+  cpp.add asmx64post
+
+  echo ($cpp)
+
+macro asmx64x (code_in:expr) : stmt =
+  code = $code_in
+  echo ("code.len = $1, code = >>>$2<<<" % [$code.len, code])
+  asmx64 ()
+  discard result
+
+asmx64x """
+    mov rax, {m}
+    ret
+"""
diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim
new file mode 100644
index 000000000..df6ead56f
--- /dev/null
+++ b/tests/vm/tcompiletimetable.nim
@@ -0,0 +1,49 @@
+discard """
+  msg: '''2
+3
+4:2
+Got Hi
+Got Hey'''
+"""
+
+# bug #404
+
+import macros, tables, strtabs
+
+var ZOOT{.compileTime.} = initTable[int, int](2)
+var iii {.compiletime.} = 1
+
+macro zoo:stmt=
+  ZOOT[iii] = iii*2
+  inc iii
+  echo iii
+
+zoo
+zoo
+
+
+macro tupleUnpack: stmt =
+  var (y,z) = (4, 2)
+  echo y, ":", z
+
+tupleUnpack
+
+# bug #903
+
+var x {.compileTime.}: StringTableRef
+
+macro addStuff(stuff, body: expr): stmt {.immediate.} =
+  result = newNimNode(nnkStmtList)
+
+  if x.isNil:
+    x = newStringTable(modeStyleInsensitive)
+  x[$stuff] = ""
+
+macro dump(): stmt =
+  result = newNimNode(nnkStmtList)
+  for y in x.keys: echo "Got ", y
+
+addStuff("Hey"): echo "Hey"
+addStuff("Hi"): echo "Hi"
+dump()
+
diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim
new file mode 100644
index 000000000..4459931c5
--- /dev/null
+++ b/tests/vm/tconsteval.nim
@@ -0,0 +1,31 @@
+discard """
+"""
+
+import strutils
+
+const
+  HelpText = """
++-----------------------------------------------------------------+
+|         Maintenance program for Nim                             |
+|             Version $1|
+|             (c) 2012 Andreas Rumpf                              |
++-----------------------------------------------------------------+
+Compiled at: $2, $3
+
+Usage:
+  koch [options] command [options for command]
+Options:
+  --force, -f, -B, -b      forces rebuild
+  --help, -h               shows this help and quits
+Possible Commands:
+  boot [options]           bootstraps with given command line options
+  clean                    cleans Nim project; removes generated files
+  web                      generates the website
+  csource [options]        builds the C sources for installation
+  zip                      builds the installation ZIP package
+  inno                     builds the Inno Setup installer
+""" % [NimVersion & spaces(44-len(NimVersion)), 
+       CompileDate, CompileTime]
+
+echo HelpText
+
diff --git a/tests/vm/tconsttable.nim b/tests/vm/tconsttable.nim
new file mode 100644
index 000000000..64a74a59d
--- /dev/null
+++ b/tests/vm/tconsttable.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''is
+finally
+nice!'''
+"""
+
+import tables
+
+const
+  foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+# protect against overly smart compiler:
+var x = "this"
+
+echo foo[x]
+x = "ah"
+echo foo[x]
+x = "possible."
+echo foo[x]
diff --git a/tests/vm/teval1.nim b/tests/vm/teval1.nim
new file mode 100644
index 000000000..cdb4ad8e2
--- /dev/null
+++ b/tests/vm/teval1.nim
@@ -0,0 +1,24 @@
+import macros
+
+proc testProc: string {.compileTime.} =
+  result = ""
+  result = result & ""
+
+when true:
+  macro test(n: stmt): stmt {.immediate.} =
+    result = newNimNode(nnkStmtList)
+    echo "#", testProc(), "#"
+  test:
+    "hi"
+
+const
+  x = testProc()
+  
+echo "##", x, "##"
+
+# bug #1310
+static:
+    var i, j: set[int8] = {}
+    var k = i + j
+
+
diff --git a/tests/vm/tldconst.nim b/tests/vm/tldconst.nim
new file mode 100644
index 000000000..9eabb7525
--- /dev/null
+++ b/tests/vm/tldconst.nim
@@ -0,0 +1,14 @@
+# Passes if it compiles
+# From issue #1946
+
+type
+  Part = object
+    index: int ## array index of argument to be accessed
+
+proc foobar(): int =
+    var x: Part
+    if x.index < high(int):
+        discard
+    0
+
+const x = foobar()
\ No newline at end of file
diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim
new file mode 100644
index 000000000..c36b9ed9b
--- /dev/null
+++ b/tests/vm/toverflowopcaddimmint.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.high
+    discard x + 1
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim
new file mode 100644
index 000000000..6d96afc78
--- /dev/null
+++ b/tests/vm/toverflowopcaddint.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.high
+      y = 1
+    discard x + y
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim
new file mode 100644
index 000000000..81b3234ba
--- /dev/null
+++ b/tests/vm/toverflowopcmulint.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = 1 shl 62
+    discard x * 2
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim
new file mode 100644
index 000000000..09d6f745b
--- /dev/null
+++ b/tests/vm/toverflowopcsubimmint.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var x = int64.low
+    discard x - 1
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim
new file mode 100644
index 000000000..8d114f200
--- /dev/null
+++ b/tests/vm/toverflowopcsubint.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.low
+      y = 1
+    discard x - y
+    assert false
+  p()
diff --git a/tests/vm/tquadplus.nim b/tests/vm/tquadplus.nim
new file mode 100644
index 000000000..552e8fef7
--- /dev/null
+++ b/tests/vm/tquadplus.nim
@@ -0,0 +1,17 @@
+# bug #1023
+
+discard """
+  output: "1 == 1"
+"""
+
+type Quadruple = tuple[a, b, c, d: int]
+
+proc `+`(s, t: Quadruple): Quadruple =
+  (a: s.a + t.a, b: s.b + t.b, c: s.c + t.c, d: s.d + t.d)
+
+const
+  A = (a: 0, b: -1, c: 0, d: 1)
+  B = (a: 0, b: -2, c: 1, d: 0)
+  C = A + B
+
+echo C.d, " == ", (A+B).d
diff --git a/tests/vm/trgba.nim b/tests/vm/trgba.nim
new file mode 100644
index 000000000..22eec4d6e
--- /dev/null
+++ b/tests/vm/trgba.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''[127, 127, 0, 255]
+[127, 127, 0, 255]
+'''
+"""
+
+#bug #1009
+type
+  TAggRgba8* = array[4, byte]
+
+template R*(self: TAggRgba8): byte = self[0]   
+template G*(self: TAggRgba8): byte = self[1]   
+template B*(self: TAggRgba8): byte = self[2]   
+template A*(self: TAggRgba8): byte = self[3]   
+
+template `R=`*(self: TAggRgba8, val: byte) = 
+  self[0] = val   
+template `G=`*(self: TAggRgba8, val: byte) =   
+  self[1] = val   
+template `B=`*(self: TAggRgba8, val: byte) =   
+  self[2] = val   
+template `A=`*(self: TAggRgba8, val: byte) =   
+  self[3] = val   
+
+proc ABGR* (val: int| int64): TAggRgba8 =
+  var V = val
+  result.R = V and 0xFF
+  V = V shr 8
+  result.G = V and 0xFF
+  V = V shr 8
+  result.B = V and 0xFF
+  result.A = (V shr 8) and 0xFF
+
+const
+  c1 = ABGR(0xFF007F7F) 
+echo ABGR(0xFF007F7F).repr, c1.repr
diff --git a/tests/vm/triangle_array.nim b/tests/vm/triangle_array.nim
new file mode 100644
index 000000000..054c66f22
--- /dev/null
+++ b/tests/vm/triangle_array.nim
@@ -0,0 +1,17 @@
+discard """
+  output: "56"
+"""
+
+# bug #1781
+
+proc initCombinations: array[11, array[11, int]] =
+  result[0]          = [1,2,3,4,5,6,7,8,9,10,11]
+  result[1][1 .. 10] =   [12,13,14,15,16,17,18,19,20,21]
+  result[2][2 .. 10] =     [22,23,24,25,26,27,28,29,30]
+  result[3][3 .. 10] =       [31,32,33,34,35,36,37,38]
+  result[4][4 .. 10] =         [39,40,41,42,43,44,45]
+  result[5][5 .. 10] =           [46,47,48,49,50,51]
+  result[6][6 .. 10] =             [52,53,54,55,56]
+
+const combinations = initCombinations()
+echo combinations[6][10]
diff --git a/tests/vm/tslurp.nim b/tests/vm/tslurp.nim
new file mode 100644
index 000000000..f9456ce6b
--- /dev/null
+++ b/tests/vm/tslurp.nim
@@ -0,0 +1,6 @@
+
+const
+  myRes = slurp"../../readme.txt"
+  
+echo myRes
+
diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim
new file mode 100644
index 000000000..b002d366c
--- /dev/null
+++ b/tests/vm/tstaticprintseq.nim
@@ -0,0 +1,82 @@
+discard """
+  msg: '''1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+aa
+bb
+11
+22
+aa
+bb
+24
+2147483647 2147483647'''
+"""
+
+const s = @[1,2,3]
+
+macro foo: stmt =
+  for e in s:
+    echo e
+
+foo()
+
+static:
+  for e in s:
+    echo e
+
+macro bar(x: static[seq[int]]): stmt =
+  for e in x:
+    echo e
+
+bar s
+bar(@[1, 2, 3])
+
+type
+  TData = tuple
+    letters: seq[string]
+    numbers: seq[int]
+
+const data: TData = (@["aa", "bb"], @[11, 22])
+
+static:
+  var m1 = data
+  for x in m1.letters: echo x
+
+  var m2: TData = data
+  for x in m2.numbers: echo x
+
+macro ff(d: static[TData]): stmt =
+  for x in d.letters:
+    echo x
+
+ff(data)
+
+# bug #1010
+
+proc `*==`(x: var int, y: int) {.inline, noSideEffect.} =
+  ## Binary `*=` operator for ordinals
+  x = x * y
+
+proc fac: int =
+  var x = 1;
+  for i in 1..4:
+    x *== i;
+  return x
+
+const y = fac()
+
+static:
+  echo y
+
+static:
+  var foo2 = int32.high
+  echo foo2, " ", int32.high
diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim
new file mode 100644
index 000000000..bb546b698
--- /dev/null
+++ b/tests/vm/tstringnil.nim
@@ -0,0 +1,50 @@
+# bug #1744
+
+import macros
+
+type
+  SuiteTest = object
+    suiteName: string
+    suiteDesc: string
+    testName: string
+    testDesc: string
+    testBlock: NimNode
+
+proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: seq[SuiteTest]]  {.compileTime.} =
+  var
+    tests:seq[SuiteTest] = @[]
+
+  for child in suiteBloc.children():
+    case $child[0].ident:
+    of "test":
+
+      var testObj = SuiteTest()
+      if suiteName.kind == nnkNilLit:
+        testObj.suiteName = nil
+      else:
+        testObj.suiteName = $suiteName
+      if suiteDesc.kind == nnkNilLit:
+        testObj.suiteDesc = nil
+      else:
+        testObj.suiteDesc = suiteDesc.strVal
+      testObj.testName = $child[1] # should not ever be nil
+      if child[2].kind == nnkNilLit:
+        testObj.testDesc = nil
+      else:
+        testObj.testDesc = child[2].strVal
+      testObj.testBlock = child[1]
+
+      tests.add(testObj)
+
+    else:
+      discard
+
+  return (tests: tests)
+
+macro suite(suiteName, suiteDesc: expr, suiteBloc: stmt): stmt {.immediate.} =
+  let contents = buildSuiteContents(suiteName, suiteDesc, suiteBloc)
+
+# Test above
+suite basics, "Description of such":
+  test(t5, nil):
+    assert false
diff --git a/tests/vm/twrongarray.nim b/tests/vm/twrongarray.nim
new file mode 100644
index 000000000..c1514d0e9
--- /dev/null
+++ b/tests/vm/twrongarray.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "cannot evaluate at compile time: size"
+  line: 16
+"""
+
+#bug #1343
+
+when false:
+  proc one(dummy: int, size: int) =
+    var x: array[size, int] # compile error: constant expression expected
+
+  proc three(size: int) =
+    var x: array[size * 1, int] # compile error: cannot evaluate at compile time: size
+
+proc two(dummy: int, size: int) =
+  var x: array[size * 1, int] # compiles, but shouldn't?
+  #assert(x.len == size) # just for fun
diff --git a/tests/vm/twrongconst.nim b/tests/vm/twrongconst.nim
new file mode 100644
index 000000000..68ab2757c
--- /dev/null
+++ b/tests/vm/twrongconst.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot evaluate at compile time: x"
+  line: 9
+"""
+
+var x: array[100, char]
+template foo : expr = x[42]
+
+const myConst = foo
diff --git a/tests/vm/twrongwhen.nim b/tests/vm/twrongwhen.nim
new file mode 100644
index 000000000..d67e42883
--- /dev/null
+++ b/tests/vm/twrongwhen.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "cannot evaluate at compile time: x"
+  line: 7
+"""
+
+proc bla(x:int) =
+  when x == 0:
+    echo "oops"
+  else:
+    echo "good"
+
+bla(2)  # echos "oops"
+
diff --git a/tinyc/arm-gen.c b/tinyc/arm-gen.c
new file mode 100644
index 000000000..050a8ad88
--- /dev/null
+++ b/tinyc/arm-gen.c
@@ -0,0 +1,1734 @@
+/*
+ *  ARMv4 code generator for TCC
+ * 
+ *  Copyright (c) 2003 Daniel Glöckner
+ *
+ *  Based on i386-gen.c by Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#ifdef TCC_ARM_EABI
+#define TCC_ARM_VFP
+#endif
+
+
+/* number of available registers */
+#ifdef TCC_ARM_VFP
+#define NB_REGS            13
+#else
+#define NB_REGS             9
+#endif
+
+/* a register can belong to several classes. The classes must be
+   sorted from more general to more precise (see gv2() code which does
+   assumptions on it). */
+#define RC_INT     0x0001 /* generic integer register */
+#define RC_FLOAT   0x0002 /* generic float register */
+#define RC_R0      0x0004
+#define RC_R1      0x0008 
+#define RC_R2      0x0010
+#define RC_R3      0x0020
+#define RC_R12     0x0040
+#define RC_F0      0x0080
+#define RC_F1      0x0100
+#define RC_F2      0x0200
+#define RC_F3      0x0400
+#ifdef TCC_ARM_VFP
+#define RC_F4      0x0800
+#define RC_F5      0x1000
+#define RC_F6      0x2000
+#define RC_F7      0x4000
+#endif
+#define RC_IRET    RC_R0  /* function return: integer register */
+#define RC_LRET    RC_R1  /* function return: second integer register */
+#define RC_FRET    RC_F0  /* function return: float register */
+
+/* pretty names for the registers */
+enum {
+    TREG_R0 = 0,
+    TREG_R1,
+    TREG_R2,
+    TREG_R3,
+    TREG_R12,
+    TREG_F0,
+    TREG_F1,
+    TREG_F2,
+    TREG_F3,
+#ifdef TCC_ARM_VFP
+    TREG_F4,
+    TREG_F5,
+    TREG_F6,
+    TREG_F7,
+#endif
+};
+
+int reg_classes[NB_REGS] = {
+    /* r0 */ RC_INT | RC_R0,
+    /* r1 */ RC_INT | RC_R1,
+    /* r2 */ RC_INT | RC_R2,
+    /* r3 */ RC_INT | RC_R3,
+    /* r12 */ RC_INT | RC_R12,
+    /* f0 */ RC_FLOAT | RC_F0,
+    /* f1 */ RC_FLOAT | RC_F1,
+    /* f2 */ RC_FLOAT | RC_F2,
+    /* f3 */ RC_FLOAT | RC_F3,
+#ifdef TCC_ARM_VFP
+ /* d4/s8 */ RC_FLOAT | RC_F4,
+/* d5/s10 */ RC_FLOAT | RC_F5,
+/* d6/s12 */ RC_FLOAT | RC_F6,
+/* d7/s14 */ RC_FLOAT | RC_F7,
+#endif
+};
+
+static int two2mask(int a,int b) {
+  return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
+}
+
+static int regmask(int r) {
+  return reg_classes[r]&~(RC_INT|RC_FLOAT);
+}
+
+#ifdef TCC_ARM_VFP
+#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
+#endif
+
+/* return registers for function */
+#define REG_IRET TREG_R0 /* single word int return register */
+#define REG_LRET TREG_R1 /* second word return register (for long long) */
+#define REG_FRET TREG_F0 /* float return register */
+
+#ifdef TCC_ARM_EABI
+#define TOK___divdi3 TOK___aeabi_ldivmod
+#define TOK___moddi3 TOK___aeabi_ldivmod
+#define TOK___udivdi3 TOK___aeabi_uldivmod
+#define TOK___umoddi3 TOK___aeabi_uldivmod
+#endif
+
+/* defined if function parameters must be evaluated in reverse order */
+#define INVERT_FUNC_PARAMS
+
+/* defined if structures are passed as pointers. Otherwise structures
+   are directly pushed on stack. */
+//#define FUNC_STRUCT_PARAM_AS_PTR
+
+#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
+static CType float_type, double_type, func_float_type, func_double_type;
+#define func_ldouble_type func_double_type
+#else
+#define func_float_type func_old_type
+#define func_double_type func_old_type
+#define func_ldouble_type func_old_type
+#endif
+
+/* pointer size, in bytes */
+#define PTR_SIZE 4
+
+/* long double size and alignment, in bytes */
+#ifdef TCC_ARM_VFP
+#define LDOUBLE_SIZE  8
+#endif
+
+#ifndef LDOUBLE_SIZE
+#define LDOUBLE_SIZE  8
+#endif
+
+#ifdef TCC_ARM_EABI
+#define LDOUBLE_ALIGN 8
+#else
+#define LDOUBLE_ALIGN 4
+#endif
+
+/* maximum alignment (for aligned attribute support) */
+#define MAX_ALIGN     8
+
+#define CHAR_IS_UNSIGNED
+
+/******************************************************/
+/* ELF defines */
+
+#define EM_TCC_TARGET EM_ARM
+
+/* relocation type for 32 bit data relocation */
+#define R_DATA_32   R_ARM_ABS32
+#define R_JMP_SLOT  R_ARM_JUMP_SLOT
+#define R_COPY      R_ARM_COPY
+
+#define ELF_START_ADDR 0x00008000
+#define ELF_PAGE_SIZE  0x1000
+
+/******************************************************/
+static unsigned long func_sub_sp_offset,last_itod_magic;
+static int leaffunc;
+
+void o(unsigned long i)
+{
+  /* this is a good place to start adding big-endian support*/
+  int ind1;
+
+  ind1 = ind + 4;
+  if (!cur_text_section)
+    error("compiler error! This happens f.ex. if the compiler\n"
+         "can't evaluate constant expressions outside of a function.");
+  if (ind1 > cur_text_section->data_allocated)
+    section_realloc(cur_text_section, ind1);
+  cur_text_section->data[ind++] = i&255;
+  i>>=8;
+  cur_text_section->data[ind++] = i&255;
+  i>>=8; 
+  cur_text_section->data[ind++] = i&255;
+  i>>=8;
+  cur_text_section->data[ind++] = i;
+}
+
+static unsigned long stuff_const(unsigned long op,unsigned long c)
+{
+  int try_neg=0;
+  unsigned long nc = 0,negop = 0;
+
+  switch(op&0x1F00000)
+  {
+    case 0x800000: //add
+    case 0x400000: //sub
+      try_neg=1;
+      negop=op^0xC00000;
+      nc=-c;
+      break;
+    case 0x1A00000: //mov
+    case 0x1E00000: //mvn
+      try_neg=1;
+      negop=op^0x400000;
+      nc=~c;
+      break;
+    case 0x200000: //xor
+      if(c==~0)
+	return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
+      break;
+    case 0x0: //and
+      if(c==~0)
+	return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
+    case 0x1C00000: //bic
+      try_neg=1;
+      negop=op^0x1C00000;
+      nc=~c;
+      break;
+    case 0x1800000: //orr
+      if(c==~0)
+	return (op&0xFFF0FFFF)|0x1E00000;
+      break;
+  }
+  do {
+    unsigned long m;
+    int i;
+    if(c<256) /* catch undefined <<32 */
+      return op|c;
+    for(i=2;i<32;i+=2) {
+      m=(0xff>>i)|(0xff<<(32-i));
+      if(!(c&~m))
+	return op|(i<<7)|(c<<i)|(c>>(32-i));
+    }
+    op=negop;
+    c=nc;
+  } while(try_neg--);
+  return 0;
+}
+
+
+//only add,sub
+void stuff_const_harder(unsigned long op,unsigned long v) {
+  unsigned long x;
+  x=stuff_const(op,v);
+  if(x)
+    o(x);
+  else {
+    unsigned long a[16],nv,no,o2,n2;
+    int i,j,k;
+    a[0]=0xff;
+    o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
+    for(i=1;i<16;i++)
+      a[i]=(a[i-1]>>2)|(a[i-1]<<30);
+    for(i=0;i<12;i++)
+      for(j=i<4?i+12:15;j>=i+4;j--)
+	if((v&(a[i]|a[j]))==v) {
+	  o(stuff_const(op,v&a[i]));
+	  o(stuff_const(o2,v&a[j]));
+	  return;
+	}
+    no=op^0xC00000;
+    n2=o2^0xC00000;
+    nv=-v;
+    for(i=0;i<12;i++)
+      for(j=i<4?i+12:15;j>=i+4;j--)
+	if((nv&(a[i]|a[j]))==nv) {
+	  o(stuff_const(no,nv&a[i]));
+	  o(stuff_const(n2,nv&a[j]));
+	  return;
+	}
+    for(i=0;i<8;i++)
+      for(j=i+4;j<12;j++)
+	for(k=i<4?i+12:15;k>=j+4;k--)
+	  if((v&(a[i]|a[j]|a[k]))==v) {
+	    o(stuff_const(op,v&a[i]));
+	    o(stuff_const(o2,v&a[j]));
+	    o(stuff_const(o2,v&a[k]));
+	    return;
+	  }
+    no=op^0xC00000;
+    nv=-v;
+    for(i=0;i<8;i++)
+      for(j=i+4;j<12;j++)
+	for(k=i<4?i+12:15;k>=j+4;k--)
+	  if((nv&(a[i]|a[j]|a[k]))==nv) {
+	    o(stuff_const(no,nv&a[i]));
+	    o(stuff_const(n2,nv&a[j]));
+	    o(stuff_const(n2,nv&a[k]));
+	    return;
+	  }
+    o(stuff_const(op,v&a[0]));
+    o(stuff_const(o2,v&a[4]));
+    o(stuff_const(o2,v&a[8]));
+    o(stuff_const(o2,v&a[12]));
+  }
+}
+
+unsigned long encbranch(int pos,int addr,int fail)
+{
+  addr-=pos+8;
+  addr/=4;
+  if(addr>=0x1000000 || addr<-0x1000000) {
+    if(fail)
+      error("FIXME: function bigger than 32MB");
+    return 0;
+  }
+  return 0x0A000000|(addr&0xffffff);
+}
+
+int decbranch(int pos)
+{
+  int x;
+  x=*(int *)(cur_text_section->data + pos);
+  x&=0x00ffffff;
+  if(x&0x800000)
+    x-=0x1000000;
+  return x*4+pos+8;
+}
+
+/* output a symbol and patch all calls to it */
+void gsym_addr(int t, int a)
+{
+  unsigned long *x;
+  int lt;
+  while(t) {
+    x=(unsigned long *)(cur_text_section->data + t);
+    t=decbranch(lt=t);
+    if(a==lt+4)
+      *x=0xE1A00000; // nop
+    else {
+      *x &= 0xff000000;
+      *x |= encbranch(lt,a,1);
+    }
+  }
+}
+
+void gsym(int t)
+{
+  gsym_addr(t, ind);
+}
+
+#ifdef TCC_ARM_VFP
+static unsigned long vfpr(int r)
+{
+  if(r<TREG_F0 || r>TREG_F7)
+    error("compiler error! register %i is no vfp register",r);
+  return r-5;
+}
+#else
+static unsigned long fpr(int r)
+{
+  if(r<TREG_F0 || r>TREG_F3)
+    error("compiler error! register %i is no fpa register",r);
+  return r-5;
+}
+#endif
+
+static unsigned long intr(int r)
+{
+  if(r==4)
+    return 12;
+  if((r<0 || r>4) && r!=14)
+    error("compiler error! register %i is no int register",r);
+  return r;
+}
+
+static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift)
+{
+  if(*off>maxoff || *off&((1<<shift)-1)) {
+    unsigned long x,y;
+    x=0xE280E000;
+    if(*sgn)
+      x=0xE240E000;
+    x|=(*base)<<16;
+    *base=14; // lr
+    y=stuff_const(x,*off&~maxoff);
+    if(y) {
+      o(y);
+      *off&=maxoff;
+      return;
+    }
+    y=stuff_const(x,(*off+maxoff)&~maxoff);
+    if(y) {
+      o(y);
+      *sgn=!*sgn;
+      *off=((*off+maxoff)&~maxoff)-*off;
+      return;
+    }
+    stuff_const_harder(x,*off&~maxoff);
+    *off&=maxoff;
+  }
+}
+
+static unsigned long mapcc(int cc)
+{
+  switch(cc)
+  {
+    case TOK_ULT:
+      return 0x30000000; /* CC/LO */
+    case TOK_UGE:
+      return 0x20000000; /* CS/HS */
+    case TOK_EQ:
+      return 0x00000000; /* EQ */
+    case TOK_NE:
+      return 0x10000000; /* NE */
+    case TOK_ULE:
+      return 0x90000000; /* LS */
+    case TOK_UGT:
+      return 0x80000000; /* HI */
+    case TOK_Nset:
+      return 0x40000000; /* MI */
+    case TOK_Nclear:
+      return 0x50000000; /* PL */
+    case TOK_LT:
+      return 0xB0000000; /* LT */
+    case TOK_GE:
+      return 0xA0000000; /* GE */
+    case TOK_LE:
+      return 0xD0000000; /* LE */
+    case TOK_GT:
+      return 0xC0000000; /* GT */
+  }
+  error("unexpected condition code");
+  return 0xE0000000; /* AL */
+}
+
+static int negcc(int cc)
+{
+  switch(cc)
+  {
+    case TOK_ULT:
+      return TOK_UGE;
+    case TOK_UGE:
+      return TOK_ULT;
+    case TOK_EQ:
+      return TOK_NE;
+    case TOK_NE:
+      return TOK_EQ;
+    case TOK_ULE:
+      return TOK_UGT;
+    case TOK_UGT:
+      return TOK_ULE;
+    case TOK_Nset:
+      return TOK_Nclear;
+    case TOK_Nclear:
+      return TOK_Nset;
+    case TOK_LT:
+      return TOK_GE;
+    case TOK_GE:
+      return TOK_LT;
+    case TOK_LE:
+      return TOK_GT;
+    case TOK_GT:
+      return TOK_LE;
+  }
+  error("unexpected condition code");
+  return TOK_NE;
+}
+
+/* load 'r' from value 'sv' */
+void load(int r, SValue *sv)
+{
+  int v, ft, fc, fr, sign;
+  unsigned long op;
+  SValue v1;
+
+  fr = sv->r;
+  ft = sv->type.t;
+  fc = sv->c.ul;
+
+  if(fc>=0)
+    sign=0;
+  else {
+    sign=1;
+    fc=-fc;
+  }
+  
+  v = fr & VT_VALMASK;
+  if (fr & VT_LVAL) {
+    unsigned long base=0xB; // fp
+    if(v == VT_LLOCAL) {
+      v1.type.t = VT_PTR;
+      v1.r = VT_LOCAL | VT_LVAL;
+      v1.c.ul = sv->c.ul;
+      load(base=14 /* lr */, &v1);
+      fc=sign=0;
+      v=VT_LOCAL;
+    } else if(v == VT_CONST) {
+      v1.type.t = VT_PTR;
+      v1.r = fr&~VT_LVAL;
+      v1.c.ul = sv->c.ul;
+      v1.sym=sv->sym;
+      load(base=14, &v1);
+      fc=sign=0;
+      v=VT_LOCAL;
+    } else if(v < VT_CONST) {
+      base=intr(v);
+      fc=sign=0;
+      v=VT_LOCAL;
+    }
+    if(v == VT_LOCAL) {
+      if(is_float(ft)) {
+	calcaddr(&base,&fc,&sign,1020,2);
+#ifdef TCC_ARM_VFP
+        op=0xED100A00; /* flds */
+        if(!sign)
+          op|=0x800000;
+        if ((ft & VT_BTYPE) != VT_FLOAT)
+          op|=0x100;   /* flds -> fldd */
+        o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
+#else
+	op=0xED100100;
+	if(!sign)
+	  op|=0x800000;
+#if LDOUBLE_SIZE == 8
+	if ((ft & VT_BTYPE) != VT_FLOAT)
+	  op|=0x8000;
+#else
+	if ((ft & VT_BTYPE) == VT_DOUBLE)
+	  op|=0x8000;
+	else if ((ft & VT_BTYPE) == VT_LDOUBLE)
+	  op|=0x400000;
+#endif
+	o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
+#endif
+      } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE
+                || (ft & VT_BTYPE) == VT_SHORT) {
+	calcaddr(&base,&fc,&sign,255,0);
+	op=0xE1500090;
+	if ((ft & VT_BTYPE) == VT_SHORT)
+	  op|=0x20;
+	if ((ft & VT_UNSIGNED) == 0)
+	  op|=0x40;
+	if(!sign)
+	  op|=0x800000;
+	o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
+      } else {
+	calcaddr(&base,&fc,&sign,4095,0);
+	op=0xE5100000;
+	if(!sign)
+	  op|=0x800000;
+        if ((ft & VT_BTYPE) == VT_BYTE)
+          op|=0x400000;
+        o(op|(intr(r)<<12)|fc|(base<<16));
+      }
+      return;
+    }
+  } else {
+    if (v == VT_CONST) {
+      op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
+      if (fr & VT_SYM || !op) {
+        o(0xE59F0000|(intr(r)<<12));
+        o(0xEA000000);
+        if(fr & VT_SYM)
+	  greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
+        o(sv->c.ul);
+      } else
+        o(op);
+      return;
+    } else if (v == VT_LOCAL) {
+      op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
+      if (fr & VT_SYM || !op) {
+	o(0xE59F0000|(intr(r)<<12));
+	o(0xEA000000);
+	if(fr & VT_SYM) // needed ?
+	  greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
+	o(sv->c.ul);
+	o(0xE08B0000|(intr(r)<<12)|intr(r));
+      } else
+	o(op);
+      return;
+    } else if(v == VT_CMP) {
+      o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
+      o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
+      return;
+    } else if (v == VT_JMP || v == VT_JMPI) {
+      int t;
+      t = v & 1;
+      o(0xE3A00000|(intr(r)<<12)|t);
+      o(0xEA000000);
+      gsym(sv->c.ul);
+      o(0xE3A00000|(intr(r)<<12)|(t^1));
+      return;
+    } else if (v < VT_CONST) {
+      if(is_float(ft))
+#ifdef TCC_ARM_VFP
+        o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */
+#else
+	o(0xEE008180|(fpr(r)<<12)|fpr(v));
+#endif
+      else
+	o(0xE1A00000|(intr(r)<<12)|intr(v));
+      return;
+    }
+  }
+  error("load unimplemented!");
+}
+
+/* store register 'r' in lvalue 'v' */
+void store(int r, SValue *sv)
+{
+  SValue v1;
+  int v, ft, fc, fr, sign;
+  unsigned long op;
+
+  fr = sv->r;
+  ft = sv->type.t;
+  fc = sv->c.ul;
+
+  if(fc>=0)
+    sign=0;
+  else {
+    sign=1;
+    fc=-fc;
+  }
+  
+  v = fr & VT_VALMASK; 
+  if (fr & VT_LVAL || fr == VT_LOCAL) {
+    unsigned long base=0xb;
+    if(v < VT_CONST) {
+      base=intr(v);
+      v=VT_LOCAL;
+      fc=sign=0;
+    } else if(v == VT_CONST) {
+      v1.type.t = ft;
+      v1.r = fr&~VT_LVAL;
+      v1.c.ul = sv->c.ul;
+      v1.sym=sv->sym;
+      load(base=14, &v1);
+      fc=sign=0;
+      v=VT_LOCAL;   
+    }
+    if(v == VT_LOCAL) {
+       if(is_float(ft)) {
+	calcaddr(&base,&fc,&sign,1020,2);
+#ifdef TCC_ARM_VFP
+        op=0xED000A00; /* fsts */
+        if(!sign) 
+          op|=0x800000; 
+        if ((ft & VT_BTYPE) != VT_FLOAT) 
+          op|=0x100;   /* fsts -> fstd */
+        o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
+#else
+	op=0xED000100;
+	if(!sign)
+	  op|=0x800000;
+#if LDOUBLE_SIZE == 8
+	if ((ft & VT_BTYPE) != VT_FLOAT)
+	  op|=0x8000;
+#else
+	if ((ft & VT_BTYPE) == VT_DOUBLE)
+	  op|=0x8000;
+	if ((ft & VT_BTYPE) == VT_LDOUBLE)
+	  op|=0x400000;
+#endif
+	o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
+#endif
+	return;
+      } else if((ft & VT_BTYPE) == VT_SHORT) {
+	calcaddr(&base,&fc,&sign,255,0);
+	op=0xE14000B0;
+	if(!sign)
+	  op|=0x800000;
+	o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
+      } else {
+	calcaddr(&base,&fc,&sign,4095,0);
+	op=0xE5000000;
+	if(!sign)
+	  op|=0x800000;
+        if ((ft & VT_BTYPE) == VT_BYTE)
+          op|=0x400000;
+        o(op|(intr(r)<<12)|fc|(base<<16));
+      }
+      return;
+    }
+  }
+  error("store unimplemented");
+}
+
+static void gadd_sp(int val)
+{
+  stuff_const_harder(0xE28DD000,val);
+}
+
+/* 'is_jmp' is '1' if it is a jump */
+static void gcall_or_jmp(int is_jmp)
+{
+  int r;
+  if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+    unsigned long x;
+    /* constant case */
+    x=encbranch(ind,ind+vtop->c.ul,0);
+    if(x) {
+      if (vtop->r & VT_SYM) {
+	/* relocation case */
+	greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
+      } else
+	put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
+      o(x|(is_jmp?0xE0000000:0xE1000000));
+    } else {
+      if(!is_jmp)
+	o(0xE28FE004); // add lr,pc,#4
+      o(0xE51FF004);   // ldr pc,[pc,#-4]
+      if (vtop->r & VT_SYM)
+	greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
+      o(vtop->c.ul);
+    }
+  } else {
+    /* otherwise, indirect call */
+    r = gv(RC_INT);
+    if(!is_jmp)
+      o(0xE1A0E00F);       // mov lr,pc
+    o(0xE1A0F000|intr(r)); // mov pc,r
+  }
+}
+
+/* Generate function call. The function address is pushed first, then
+   all the parameters in call order. This functions pops all the
+   parameters and the function address. */
+void gfunc_call(int nb_args)
+{
+  int size, align, r, args_size, i;
+  Sym *func_sym;
+  signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
+  int todo=0xf, keep, plan2[4]={0,0,0,0};
+
+  r = vtop->r & VT_VALMASK;
+  if (r == VT_CMP || (r & ~1) == VT_JMP)
+    gv(RC_INT);
+#ifdef TCC_ARM_EABI
+  if((vtop[-nb_args].type.ref->type.t & VT_BTYPE) == VT_STRUCT
+     && type_size(&vtop[-nb_args].type, &align) <= 4) {
+    SValue tmp;
+    tmp=vtop[-nb_args];
+    vtop[-nb_args]=vtop[-nb_args+1];
+    vtop[-nb_args+1]=tmp;
+    --nb_args;
+  }
+  
+  vpushi(0);
+  vtop->type.t = VT_LLONG;
+  args_size = 0;
+  for(i = nb_args + 1 ; i-- ;) {
+    size = type_size(&vtop[-i].type, &align);
+    if(args_size & (align-1)) {
+      vpushi(0);
+      vtop->type.t = VT_VOID; /* padding */
+      vrott(i+2);
+      args_size += 4;
+      ++nb_args;
+    }
+    args_size += (size + 3) & -4;
+  }
+  vtop--;
+#endif
+  args_size = 0;
+  for(i = nb_args ; i-- && args_size < 16 ;) {
+    switch(vtop[-i].type.t & VT_BTYPE) {
+      case VT_STRUCT:
+      case VT_FLOAT:
+      case VT_DOUBLE:
+      case VT_LDOUBLE:
+      size = type_size(&vtop[-i].type, &align);
+        size = (size + 3) & -4;
+      args_size += size;
+        break;
+      default:
+      plan[nb_args-1-i][0]=args_size/4;
+      args_size += 4;
+      if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) {
+	plan[nb_args-1-i][1]=args_size/4;
+	args_size += 4;
+      }
+    }
+  }
+  args_size = keep = 0;
+  for(i = 0;i < nb_args; i++) {
+    vnrott(keep+1);
+    if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
+      size = type_size(&vtop->type, &align);
+      /* align to stack align size */
+      size = (size + 3) & -4;
+      /* allocate the necessary size on stack */
+      gadd_sp(-size);
+      /* generate structure store */
+      r = get_reg(RC_INT);
+      o(0xE1A0000D|(intr(r)<<12));
+      vset(&vtop->type, r | VT_LVAL, 0);
+      vswap();
+      vstore();
+      vtop--;
+      args_size += size;
+    } else if (is_float(vtop->type.t)) {
+#ifdef TCC_ARM_VFP
+      r=vfpr(gv(RC_FLOAT))<<12;
+      size=4;
+      if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
+      {
+        size=8;
+        r|=0x101; /* fstms -> fstmd */
+      }
+      o(0xED2D0A01+r);
+#else
+      r=fpr(gv(RC_FLOAT))<<12;
+      if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
+        size = 4;
+      else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
+        size = 8;
+      else
+        size = LDOUBLE_SIZE;
+      
+      if (size == 12)
+	r|=0x400000;
+      else if(size == 8)
+	r|=0x8000;
+
+      o(0xED2D0100|r|(size>>2));
+#endif
+      vtop--;
+      args_size += size;
+    } else {
+      int s;
+      /* simple type (currently always same size) */
+      /* XXX: implicit cast ? */
+      size=4;
+      if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+	lexpand_nr();
+	s=RC_INT;
+	if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) {
+	  s=regmask(plan[nb_args-i-1][1]);
+	  todo&=~(1<<plan[nb_args-i-1][1]);
+	}
+	if(s==RC_INT) {
+	  r = gv(s);
+	  o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
+	  vtop--;
+	} else {
+	  plan2[keep]=s;
+	  keep++;
+          vswap();
+	}
+	size = 8;
+      }
+      s=RC_INT;
+      if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) {
+        s=regmask(plan[nb_args-i-1][0]);
+	todo&=~(1<<plan[nb_args-i-1][0]);
+      }
+#ifdef TCC_ARM_EABI
+      if(vtop->type.t == VT_VOID) {
+        if(s == RC_INT)
+          o(0xE24DD004); /* sub sp,sp,#4 */
+        vtop--;
+      } else
+#endif      
+      if(s == RC_INT) {
+	r = gv(s);
+	o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
+	vtop--;
+      } else {
+	plan2[keep]=s;
+	keep++;
+      }
+      args_size += size;
+    }
+  }
+  for(i=keep;i--;) {
+    gv(plan2[i]);
+    vrott(keep);
+  }
+save_regs(keep); /* save used temporary registers */
+  keep++;
+  if(args_size) {
+    int n;
+    n=args_size/4;
+    if(n>4)
+      n=4;
+    todo&=((1<<n)-1);
+    if(todo) {
+      int i;
+      o(0xE8BD0000|todo);
+      for(i=0;i<4;i++)
+	if(todo&(1<<i)) {
+	  vpushi(0);
+	  vtop->r=i;
+	  keep++;
+	}
+    }
+    args_size-=n*4;
+  }
+  vnrott(keep);
+  func_sym = vtop->type.ref;
+  gcall_or_jmp(0);
+  if (args_size)
+      gadd_sp(args_size);
+#ifdef TCC_ARM_EABI
+  if((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT
+     && type_size(&vtop->type.ref->type, &align) <= 4)
+  {
+    store(REG_IRET,vtop-keep);
+    ++keep;
+  }
+#ifdef TCC_ARM_VFP
+  else if(is_float(vtop->type.ref->type.t)) {
+    if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
+      o(0xEE000A10); /* fmsr s0,r0 */
+    } else {
+      o(0xEE000B10); /* fmdlr d0,r0 */
+      o(0xEE201B10); /* fmdhr d0,r1 */
+    }
+  }
+#endif
+#endif
+  vtop-=keep;
+  leaffunc = 0;
+}
+
+/* generate function prolog of type 't' */
+void gfunc_prolog(CType *func_type)
+{
+  Sym *sym,*sym2;
+  int n,addr,size,align;
+
+  sym = func_type->ref;
+  func_vt = sym->type;
+  
+  n = 0;
+  addr = 0;
+  if((func_vt.t & VT_BTYPE) == VT_STRUCT
+     && type_size(&func_vt,&align) > 4)
+  {
+    func_vc = addr;
+    addr += 4;
+    n++;
+  }
+  for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
+    size = type_size(&sym2->type, &align);
+    n += (size + 3) / 4;
+  }
+  o(0xE1A0C00D); /* mov ip,sp */
+  if(func_type->ref->c == FUNC_ELLIPSIS)
+    n=4;
+  if(n) {
+    if(n>4)
+      n=4;
+#ifdef TCC_ARM_EABI
+    n=(n+1)&-2;
+#endif
+    o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
+  }
+  o(0xE92D5800); /* save fp, ip, lr */
+  o(0xE28DB00C); /* add fp, sp, #12 */
+  func_sub_sp_offset = ind;
+  o(0xE1A00000); /* nop, leave space for stack adjustment */
+  while ((sym = sym->next)) {
+    CType *type;
+    type = &sym->type;
+    size = type_size(type, &align);
+    size = (size + 3) & -4;
+#ifdef TCC_ARM_EABI
+    addr = (addr + align - 1) & -align;
+#endif
+    sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
+    addr += size;
+  }
+  last_itod_magic=0;
+  leaffunc = 1;
+  loc = -12;
+}
+
+/* generate function epilog */
+void gfunc_epilog(void)
+{
+  unsigned long x;
+  int diff;
+#ifdef TCC_ARM_EABI
+  if(is_float(func_vt.t)) {
+    if((func_vt.t & VT_BTYPE) == VT_FLOAT)
+      o(0xEE100A10); /* fmrs r0, s0 */
+    else {
+      o(0xEE100B10); /* fmrdl r0, d0 */
+      o(0xEE301B10); /* fmrdh r1, d0 */
+    }
+  }
+#endif
+  o(0xE91BA800); /* restore fp, sp, pc */
+  diff = (-loc + 3) & -4;
+#ifdef TCC_ARM_EABI
+  if(!leaffunc)
+    diff = (diff + 7) & -8;
+#endif
+  if(diff > 12) {
+    x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
+    if(x)
+      *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x;
+    else {
+      unsigned long addr;
+      addr=ind;
+      o(0xE59FC004); /* ldr ip,[pc+4] */
+      o(0xE04BD00C); /* sub sp,fp,ip  */
+      o(0xE1A0F00E); /* mov pc,lr */
+      o(diff);
+      *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
+    }
+  }
+}
+
+/* generate a jump to a label */
+int gjmp(int t)
+{
+  int r;
+  r=ind;
+  o(0xE0000000|encbranch(r,t,1));
+  return r;
+}
+
+/* generate a jump to a fixed address */
+void gjmp_addr(int a)
+{
+  gjmp(a);
+}
+
+/* generate a test. set 'inv' to invert test. Stack entry is popped */
+int gtst(int inv, int t)
+{
+  int v, r;
+  unsigned long op;
+  v = vtop->r & VT_VALMASK;
+  r=ind;
+  if (v == VT_CMP) {
+    op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
+    op|=encbranch(r,t,1);
+    o(op);
+    t=r;
+  } else if (v == VT_JMP || v == VT_JMPI) {
+    if ((v & 1) == inv) {
+      if(!vtop->c.i)
+	vtop->c.i=t;
+      else {
+	unsigned long *x;
+	int p,lp;
+	if(t) {
+          p = vtop->c.i;
+          do {
+	    p = decbranch(lp=p);
+          } while(p);
+	  x = (unsigned long *)(cur_text_section->data + lp);
+	  *x &= 0xff000000;
+	  *x |= encbranch(lp,t,1);
+	}
+	t = vtop->c.i;
+      }
+    } else {
+      t = gjmp(t);
+      gsym(vtop->c.i);
+    }
+  } else {
+    if (is_float(vtop->type.t)) {
+      r=gv(RC_FLOAT);
+#ifdef TCC_ARM_VFP
+      o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */
+      o(0xEEF1FA10); /* fmstat */
+#else
+      o(0xEE90F118|(fpr(r)<<16));
+#endif
+      vtop->r = VT_CMP;
+      vtop->c.i = TOK_NE;
+      return gtst(inv, t);
+    } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+      /* constant jmp optimization */
+      if ((vtop->c.i != 0) != inv) 
+	t = gjmp(t);
+    } else {
+      v = gv(RC_INT);
+      o(0xE3300000|(intr(v)<<16));
+      vtop->r = VT_CMP;
+      vtop->c.i = TOK_NE;
+      return gtst(inv, t);
+    }   
+  }
+  vtop--;
+  return t;
+}
+
+/* generate an integer binary operation */
+void gen_opi(int op)
+{
+  int c, func = 0;
+  unsigned long opc = 0,r,fr;
+  unsigned short retreg = REG_IRET;
+
+  c=0;
+  switch(op) {
+    case '+':
+      opc = 0x8;
+      c=1;
+      break;
+    case TOK_ADDC1: /* add with carry generation */
+      opc = 0x9;
+      c=1;
+      break;
+    case '-':
+      opc = 0x4;
+      c=1;
+      break;
+    case TOK_SUBC1: /* sub with carry generation */
+      opc = 0x5;
+      c=1;
+      break;
+    case TOK_ADDC2: /* add with carry use */
+      opc = 0xA;
+      c=1;
+      break;
+    case TOK_SUBC2: /* sub with carry use */
+      opc = 0xC;
+      c=1;
+      break;
+    case '&':
+      opc = 0x0;
+      c=1;
+      break;
+    case '^':
+      opc = 0x2;
+      c=1;
+      break;
+    case '|':
+      opc = 0x18;
+      c=1;
+      break;
+    case '*':
+      gv2(RC_INT, RC_INT);
+      r = vtop[-1].r;
+      fr = vtop[0].r;
+      vtop--;
+      o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
+      return;
+    case TOK_SHL:
+      opc = 0;
+      c=2;
+      break;
+    case TOK_SHR:
+      opc = 1;
+      c=2;
+      break;
+    case TOK_SAR:
+      opc = 2;
+      c=2;
+      break;
+    case '/':
+    case TOK_PDIV:
+      func=TOK___divsi3;
+      c=3;
+      break;
+    case TOK_UDIV:
+      func=TOK___udivsi3;
+      c=3;
+      break;
+    case '%':
+#ifdef TCC_ARM_EABI
+      func=TOK___aeabi_idivmod;
+      retreg=REG_LRET;
+#else
+      func=TOK___modsi3;
+#endif
+      c=3;
+      break;
+    case TOK_UMOD:
+#ifdef TCC_ARM_EABI
+      func=TOK___aeabi_uidivmod;
+      retreg=REG_LRET;
+#else
+      func=TOK___umodsi3;
+#endif
+      c=3;
+      break;
+    case TOK_UMULL:
+      gv2(RC_INT, RC_INT);
+      r=intr(vtop[-1].r2=get_reg(RC_INT));
+      c=vtop[-1].r;
+      vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
+      vtop--;
+      o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
+      return;
+    default:
+      opc = 0x15;
+      c=1;
+      break;
+  }
+  switch(c) {
+    case 1:
+      if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+	if(opc == 4 || opc == 5 || opc == 0xc) {
+	  vswap();
+	  opc|=2; // sub -> rsb
+	}
+      }
+      if ((vtop->r & VT_VALMASK) == VT_CMP ||
+          (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
+        gv(RC_INT);
+      vswap();
+      c=intr(gv(RC_INT));
+      vswap();
+      opc=0xE0000000|(opc<<20)|(c<<16);
+      if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+	unsigned long x;
+	x=stuff_const(opc|0x2000000,vtop->c.i);
+	if(x) {
+	  r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
+	  o(x|(r<<12));
+	  goto done;
+	}
+      }
+      fr=intr(gv(RC_INT));
+      r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
+      o(opc|(r<<12)|fr);
+done:
+      vtop--;
+      if (op >= TOK_ULT && op <= TOK_GT) {
+        vtop->r = VT_CMP;
+        vtop->c.i = op;
+      }
+      break;
+    case 2:
+      opc=0xE1A00000|(opc<<5);
+      if ((vtop->r & VT_VALMASK) == VT_CMP ||
+          (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
+        gv(RC_INT);
+      vswap();
+      r=intr(gv(RC_INT));
+      vswap();
+      opc|=r;
+      if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+	fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
+	c = vtop->c.i & 0x1f;
+	o(opc|(c<<7)|(fr<<12));
+      } else {
+        fr=intr(gv(RC_INT));
+	c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
+	o(opc|(c<<12)|(fr<<8)|0x10);
+      }
+      vtop--;
+      break;
+    case 3:
+      vpush_global_sym(&func_old_type, func);
+      vrott(3);
+      gfunc_call(2);
+      vpushi(0);
+      vtop->r = retreg;
+      break;
+    default:
+      error("gen_opi %i unimplemented!",op);
+  }
+}
+
+#ifdef TCC_ARM_VFP
+static int is_zero(int i)
+{
+  if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
+    return 0;
+  if (vtop[i].type.t == VT_FLOAT)
+    return (vtop[i].c.f == 0.f);
+  else if (vtop[i].type.t == VT_DOUBLE)
+    return (vtop[i].c.d == 0.0);
+  return (vtop[i].c.ld == 0.l);
+}
+
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+ *    two operands are guaranted to have the same floating point type */
+void gen_opf(int op)
+{
+  unsigned long x;
+  int fneg=0,r;
+  x=0xEE000A00|T2CPR(vtop->type.t);
+  switch(op) {
+    case '+':
+      if(is_zero(-1))
+        vswap();
+      if(is_zero(0)) {
+        vtop--;
+        return;
+      }
+      x|=0x300000;
+      break;
+    case '-':
+      x|=0x300040;
+      if(is_zero(0)) {
+        vtop--;
+        return;
+      }
+      if(is_zero(-1)) {
+        x|=0x810000; /* fsubX -> fnegX */
+        vswap();
+        vtop--;
+        fneg=1;
+      }
+      break;
+    case '*':
+      x|=0x200000;
+      break;
+    case '/':
+      x|=0x800000;
+      break;
+    default:
+      if(op < TOK_ULT && op > TOK_GT) {
+        error("unknown fp op %x!",op);
+        return;
+      }
+      if(is_zero(-1)) {
+        vswap();
+        switch(op) {
+          case TOK_LT: op=TOK_GT; break;
+          case TOK_GE: op=TOK_ULE; break;
+          case TOK_LE: op=TOK_GE; break;
+          case TOK_GT: op=TOK_ULT; break;
+        }
+      }
+      x|=0xB40040; /* fcmpX */
+      if(op!=TOK_EQ && op!=TOK_NE)
+        x|=0x80; /* fcmpX -> fcmpeX */
+      if(is_zero(0)) {
+        vtop--;
+        o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
+      } else {
+        x|=vfpr(gv(RC_FLOAT));
+        vswap();
+        o(x|(vfpr(gv(RC_FLOAT))<<12));
+        vtop--;
+      }
+      o(0xEEF1FA10); /* fmstat */
+
+      switch(op) {
+        case TOK_LE: op=TOK_ULE; break;
+        case TOK_LT: op=TOK_ULT; break;
+        case TOK_UGE: op=TOK_GE; break;
+        case TOK_UGT: op=TOK_GT; break;
+      }
+      
+      vtop->r = VT_CMP;
+      vtop->c.i = op;
+      return;
+  }
+  r=gv(RC_FLOAT);
+  x|=vfpr(r);
+  r=regmask(r);
+  if(!fneg) {
+    int r2;
+    vswap();
+    r2=gv(RC_FLOAT);
+    x|=vfpr(r2)<<16;
+    r|=regmask(r2);
+  }
+  vtop->r=get_reg_ex(RC_FLOAT,r);
+  if(!fneg)
+    vtop--;
+  o(x|(vfpr(vtop->r)<<12));
+}
+
+#else
+static int is_fconst()
+{
+  long double f;
+  int r;
+  if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
+    return 0;
+  if (vtop->type.t == VT_FLOAT)
+    f = vtop->c.f;
+  else if (vtop->type.t == VT_DOUBLE)
+    f = vtop->c.d;
+  else
+    f = vtop->c.ld;
+  if(!ieee_finite(f))
+    return 0;
+  r=0x8;
+  if(f<0.0) {
+    r=0x18;
+    f=-f;
+  }
+  if(f==0.0)
+    return r;
+  if(f==1.0)
+    return r|1;
+  if(f==2.0)
+    return r|2;
+  if(f==3.0)
+    return r|3;
+  if(f==4.0)
+    return r|4;
+  if(f==5.0)
+    return r|5;
+  if(f==0.5)
+    return r|6;
+  if(f==10.0)
+    return r|7;
+  return 0;
+}
+
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+   two operands are guaranted to have the same floating point type */
+void gen_opf(int op)
+{
+  unsigned long x;
+  int r,r2,c1,c2;
+  //fputs("gen_opf\n",stderr);
+  vswap();
+  c1 = is_fconst();
+  vswap();
+  c2 = is_fconst();
+  x=0xEE000100;
+#if LDOUBLE_SIZE == 8
+  if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
+    x|=0x80;
+#else
+  if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
+    x|=0x80;
+  else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
+    x|=0x80000;
+#endif
+  switch(op)
+  {
+    case '+':
+      if(!c2) {
+	vswap();
+	c2=c1;
+      }
+      vswap();
+      r=fpr(gv(RC_FLOAT));
+      vswap();
+      if(c2) {
+	if(c2>0xf)
+	  x|=0x200000; // suf
+	r2=c2&0xf;
+      } else {
+	r2=fpr(gv(RC_FLOAT));
+      }
+      break;
+    case '-':
+      if(c2) {
+	if(c2<=0xf)
+	  x|=0x200000; // suf
+	r2=c2&0xf;
+	vswap();
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+      } else if(c1 && c1<=0xf) {
+	x|=0x300000; // rsf
+	r2=c1;
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+      } else {
+	x|=0x200000; // suf
+	vswap();
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+	r2=fpr(gv(RC_FLOAT));
+      }
+      break;
+    case '*':
+      if(!c2 || c2>0xf) {
+	vswap();
+	c2=c1;
+      }
+      vswap();
+      r=fpr(gv(RC_FLOAT));
+      vswap();
+      if(c2 && c2<=0xf)
+	r2=c2;
+      else
+	r2=fpr(gv(RC_FLOAT));
+      x|=0x100000; // muf
+      break;
+    case '/':
+      if(c2 && c2<=0xf) {
+	x|=0x400000; // dvf
+	r2=c2;
+	vswap();
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+      } else if(c1 && c1<=0xf) {
+	x|=0x500000; // rdf
+	r2=c1;
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+      } else {
+	x|=0x400000; // dvf
+	vswap();
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+	r2=fpr(gv(RC_FLOAT));
+      }     
+      break;
+    default:
+      if(op >= TOK_ULT && op <= TOK_GT) {
+	x|=0xd0f110; // cmfe
+/* bug (intention?) in Linux FPU emulator
+   doesn't set carry if equal */
+	switch(op) {
+	  case TOK_ULT:
+	  case TOK_UGE:
+	  case TOK_ULE:
+	  case TOK_UGT:
+            error("unsigned comparison on floats?");
+	    break;
+	  case TOK_LT:
+            op=TOK_Nset;
+	    break;
+	  case TOK_LE:
+            op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
+	    break;
+	  case TOK_EQ:
+	  case TOK_NE:
+	    x&=~0x400000; // cmfe -> cmf
+	    break;
+	}
+	if(c1 && !c2) {
+	  c2=c1;
+	  vswap();
+	  switch(op) {
+            case TOK_Nset:
+              op=TOK_GT;
+	      break;
+            case TOK_GE:
+	      op=TOK_ULE;
+	      break;
+	    case TOK_ULE:
+              op=TOK_GE;
+	      break;
+            case TOK_GT:
+              op=TOK_Nset;
+	      break;
+	  }
+	}
+	vswap();
+	r=fpr(gv(RC_FLOAT));
+	vswap();
+	if(c2) {
+	  if(c2>0xf)
+	    x|=0x200000;
+	  r2=c2&0xf;
+	} else {
+	  r2=fpr(gv(RC_FLOAT));
+	}
+	vtop[-1].r = VT_CMP;
+	vtop[-1].c.i = op;
+      } else {
+        error("unknown fp op %x!",op);
+	return;
+      }
+  }
+  if(vtop[-1].r == VT_CMP)
+    c1=15;
+  else {
+    c1=vtop->r;
+    if(r2&0x8)
+      c1=vtop[-1].r;
+    vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
+    c1=fpr(vtop[-1].r);
+  }
+  vtop--;
+  o(x|(r<<16)|(c1<<12)|r2);
+}
+#endif
+
+/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
+   and 'long long' cases. */
+void gen_cvt_itof1(int t)
+{
+  int r,r2,bt;
+  bt=vtop->type.t & VT_BTYPE;
+  if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
+#ifndef TCC_ARM_VFP
+    unsigned int dsize=0;
+#endif
+    r=intr(gv(RC_INT));
+#ifdef TCC_ARM_VFP
+    r2=vfpr(vtop->r=get_reg(RC_FLOAT));
+    o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
+    r2<<=12;
+    if(!(vtop->type.t & VT_UNSIGNED))
+      r2|=0x80;                /* fuitoX -> fsituX */
+    o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
+#else
+    r2=fpr(vtop->r=get_reg(RC_FLOAT));
+    if((t & VT_BTYPE) != VT_FLOAT)
+      dsize=0x80;    /* flts -> fltd */
+    o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
+    if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
+      unsigned int off=0;
+      o(0xE3500000|(r<<12));        /* cmp */
+      r=fpr(get_reg(RC_FLOAT));
+      if(last_itod_magic) {
+	off=ind+8-last_itod_magic;
+	off/=4;
+	if(off>255)
+	  off=0;
+      }
+      o(0xBD1F0100|(r<<12)|off);    /* ldflts */
+      if(!off) {
+        o(0xEA000000);              /* b */
+        last_itod_magic=ind;
+        o(0x4F800000);              /* 4294967296.0f */
+      }
+      o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
+    }
+#endif
+    return;
+  } else if(bt == VT_LLONG) {
+    int func;
+    CType *func_type = 0;
+    if((t & VT_BTYPE) == VT_FLOAT) {
+      func_type = &func_float_type;
+      if(vtop->type.t & VT_UNSIGNED)
+        func=TOK___floatundisf;
+      else
+        func=TOK___floatdisf;
+#if LDOUBLE_SIZE != 8
+    } else if((t & VT_BTYPE) == VT_LDOUBLE) {
+      func_type = &func_ldouble_type;
+      if(vtop->type.t & VT_UNSIGNED)
+        func=TOK___floatundixf;
+      else
+        func=TOK___floatdixf;
+    } else if((t & VT_BTYPE) == VT_DOUBLE) {
+#else
+    } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
+#endif
+      func_type = &func_double_type;
+      if(vtop->type.t & VT_UNSIGNED)
+        func=TOK___floatundidf;
+      else
+        func=TOK___floatdidf;
+    }
+    if(func_type) {
+      vpush_global_sym(func_type, func);
+      vswap();
+      gfunc_call(1);
+      vpushi(0);
+      vtop->r=TREG_F0;
+      return;
+    }
+  }
+  error("unimplemented gen_cvt_itof %x!",vtop->type.t);
+}
+
+/* convert fp to int 't' type */
+void gen_cvt_ftoi(int t)
+{
+  int r,r2,u,func=0;
+  u=t&VT_UNSIGNED;
+  t&=VT_BTYPE;
+  r2=vtop->type.t & VT_BTYPE;
+  if(t==VT_INT) {
+#ifdef TCC_ARM_VFP
+    r=vfpr(gv(RC_FLOAT));
+    u=u?0:0x10000;
+    o(0xEEBC0A40|(r<<12)|r|T2CPR(r2)); /* ftoXiY */
+    r2=intr(vtop->r=get_reg(RC_INT));
+    o(0xEE100A10|(r<<16)|(r2<<12));
+    return;
+#else
+    if(u) {
+      if(r2 == VT_FLOAT)
+        func=TOK___fixunssfsi;
+#if LDOUBLE_SIZE != 8
+      else if(r2 == VT_LDOUBLE)
+	func=TOK___fixunsxfsi;
+      else if(r2 == VT_DOUBLE)
+#else
+      else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
+#endif
+	func=TOK___fixunsdfsi;
+    } else {
+      r=fpr(gv(RC_FLOAT));
+      r2=intr(vtop->r=get_reg(RC_INT));
+      o(0xEE100170|(r2<<12)|r);
+      return;
+    }
+#endif
+  } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
+    if(r2 == VT_FLOAT)
+      func=TOK___fixsfdi;
+#if LDOUBLE_SIZE != 8
+    else if(r2 == VT_LDOUBLE)
+      func=TOK___fixxfdi;
+    else if(r2 == VT_DOUBLE)
+#else
+    else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
+#endif
+      func=TOK___fixdfdi;
+  }
+  if(func) {
+    vpush_global_sym(&func_old_type, func);
+    vswap();
+    gfunc_call(1);
+    vpushi(0);
+    if(t == VT_LLONG)
+      vtop->r2 = REG_LRET;
+    vtop->r = REG_IRET;
+    return;
+  }
+  error("unimplemented gen_cvt_ftoi!");
+}
+
+/* convert from one floating point type to another */
+void gen_cvt_ftof(int t)
+{
+#ifdef TCC_ARM_VFP
+  if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
+    int r=vfpr(gv(RC_FLOAT));
+    o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
+  }
+#else
+  /* all we have to do on i386 and FPA ARM is to put the float in a register */
+  gv(RC_FLOAT);
+#endif
+}
+
+/* computed goto support */
+void ggoto(void)
+{
+  gcall_or_jmp(1);
+  vtop--;
+}
+
+/* end of ARM code generator */
+/*************************************************************/
+
diff --git a/tinyc/c67-gen.c b/tinyc/c67-gen.c
new file mode 100644
index 000000000..77c68a279
--- /dev/null
+++ b/tinyc/c67-gen.c
@@ -0,0 +1,2548 @@
+/*
+ *  TMS320C67xx code generator for TCC
+ * 
+ *  Copyright (c) 2001, 2002 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+//#define ASSEMBLY_LISTING_C67
+
+/* number of available registers */
+#define NB_REGS            24
+
+/* a register can belong to several classes. The classes must be
+   sorted from more general to more precise (see gv2() code which does
+   assumptions on it). */
+#define RC_INT     0x0001	/* generic integer register */
+#define RC_FLOAT   0x0002	/* generic float register */
+#define RC_EAX     0x0004
+#define RC_ST0     0x0008
+#define RC_ECX     0x0010
+#define RC_EDX     0x0020
+#define RC_INT_BSIDE  0x00000040	/* generic integer register  on b side */
+#define RC_C67_A4     0x00000100
+#define RC_C67_A5     0x00000200
+#define RC_C67_B4     0x00000400
+#define RC_C67_B5     0x00000800
+#define RC_C67_A6     0x00001000
+#define RC_C67_A7     0x00002000
+#define RC_C67_B6     0x00004000
+#define RC_C67_B7     0x00008000
+#define RC_C67_A8     0x00010000
+#define RC_C67_A9     0x00020000
+#define RC_C67_B8     0x00040000
+#define RC_C67_B9     0x00080000
+#define RC_C67_A10    0x00100000
+#define RC_C67_A11    0x00200000
+#define RC_C67_B10    0x00400000
+#define RC_C67_B11    0x00800000
+#define RC_C67_A12    0x01000000
+#define RC_C67_A13    0x02000000
+#define RC_C67_B12    0x04000000
+#define RC_C67_B13    0x08000000
+#define RC_IRET    RC_C67_A4	/* function return: integer register */
+#define RC_LRET    RC_C67_A5	/* function return: second integer register */
+#define RC_FRET    RC_C67_A4	/* function return: float register */
+
+/* pretty names for the registers */
+enum {
+    TREG_EAX = 0,		// really A2
+    TREG_ECX,			// really A3
+    TREG_EDX,			// really B0
+    TREG_ST0,			// really B1
+    TREG_C67_A4,
+    TREG_C67_A5,
+    TREG_C67_B4,
+    TREG_C67_B5,
+    TREG_C67_A6,
+    TREG_C67_A7,
+    TREG_C67_B6,
+    TREG_C67_B7,
+    TREG_C67_A8,
+    TREG_C67_A9,
+    TREG_C67_B8,
+    TREG_C67_B9,
+    TREG_C67_A10,
+    TREG_C67_A11,
+    TREG_C67_B10,
+    TREG_C67_B11,
+    TREG_C67_A12,
+    TREG_C67_A13,
+    TREG_C67_B12,
+    TREG_C67_B13,
+};
+
+int reg_classes[NB_REGS] = {
+						/* eax */ RC_INT | RC_FLOAT | RC_EAX,
+						// only allow even regs for floats (allow for doubles)
+    /* ecx */ RC_INT | RC_ECX,
+								/* edx */ RC_INT | RC_INT_BSIDE | RC_FLOAT | RC_EDX,
+								// only allow even regs for floats (allow for doubles)
+    /* st0 */ RC_INT | RC_INT_BSIDE | RC_ST0,
+    /* A4  */ RC_C67_A4,
+    /* A5  */ RC_C67_A5,
+    /* B4  */ RC_C67_B4,
+    /* B5  */ RC_C67_B5,
+    /* A6  */ RC_C67_A6,
+    /* A7  */ RC_C67_A7,
+    /* B6  */ RC_C67_B6,
+    /* B7  */ RC_C67_B7,
+    /* A8  */ RC_C67_A8,
+    /* A9  */ RC_C67_A9,
+    /* B8  */ RC_C67_B8,
+    /* B9  */ RC_C67_B9,
+    /* A10  */ RC_C67_A10,
+    /* A11  */ RC_C67_A11,
+    /* B10  */ RC_C67_B10,
+    /* B11  */ RC_C67_B11,
+    /* A12  */ RC_C67_A10,
+    /* A13  */ RC_C67_A11,
+    /* B12  */ RC_C67_B10,
+    /* B13  */ RC_C67_B11
+};
+
+/* return registers for function */
+#define REG_IRET TREG_C67_A4	/* single word int return register */
+#define REG_LRET TREG_C67_A5	/* second word return register (for long long) */
+#define REG_FRET TREG_C67_A4	/* float return register */
+
+
+#define ALWAYS_ASSERT(x) \
+do {\
+   if (!(x))\
+       error("internal compiler error file at %s:%d", __FILE__, __LINE__);\
+} while (0)
+
+// although tcc thinks it is passing parameters on the stack,
+// the C67 really passes up to the first 10 params in special
+// regs or regs pairs (for 64 bit params).  So keep track of
+// the stack offsets so we can translate to the appropriate 
+// reg (pair)
+
+
+#define NoCallArgsPassedOnStack 10
+int NoOfCurFuncArgs;
+int TranslateStackToReg[NoCallArgsPassedOnStack];
+int ParamLocOnStack[NoCallArgsPassedOnStack];
+int TotalBytesPushedOnStack;
+
+/* defined if function parameters must be evaluated in reverse order */
+
+//#define INVERT_FUNC_PARAMS
+
+/* defined if structures are passed as pointers. Otherwise structures
+   are directly pushed on stack. */
+//#define FUNC_STRUCT_PARAM_AS_PTR
+
+/* pointer size, in bytes */
+#define PTR_SIZE 4
+
+/* long double size and alignment, in bytes */
+#define LDOUBLE_SIZE  12
+#define LDOUBLE_ALIGN 4
+/* maximum alignment (for aligned attribute support) */
+#define MAX_ALIGN     8
+
+/******************************************************/
+/* ELF defines */
+
+#define EM_TCC_TARGET EM_C60
+
+/* relocation type for 32 bit data relocation */
+#define R_DATA_32   R_C60_32
+#define R_JMP_SLOT  R_C60_JMP_SLOT
+#define R_COPY      R_C60_COPY
+
+#define ELF_START_ADDR 0x00000400
+#define ELF_PAGE_SIZE  0x1000
+
+/******************************************************/
+
+static unsigned long func_sub_sp_offset;
+static int func_ret_sub;
+
+
+static BOOL C67_invert_test;
+static int C67_compare_reg;
+
+#ifdef ASSEMBLY_LISTING_C67
+FILE *f = NULL;
+#endif
+
+
+void C67_g(int c)
+{
+    int ind1;
+
+#ifdef ASSEMBLY_LISTING_C67
+    fprintf(f, " %08X", c);
+#endif
+    ind1 = ind + 4;
+    if (ind1 > (int) cur_text_section->data_allocated)
+	section_realloc(cur_text_section, ind1);
+    cur_text_section->data[ind] = c & 0xff;
+    cur_text_section->data[ind + 1] = (c >> 8) & 0xff;
+    cur_text_section->data[ind + 2] = (c >> 16) & 0xff;
+    cur_text_section->data[ind + 3] = (c >> 24) & 0xff;
+    ind = ind1;
+}
+
+
+/* output a symbol and patch all calls to it */
+void gsym_addr(int t, int a)
+{
+    int n, *ptr;
+    while (t) {
+	ptr = (int *) (cur_text_section->data + t);
+	{
+	    Sym *sym;
+
+	    // extract 32 bit address from MVKH/MVKL
+	    n = ((*ptr >> 7) & 0xffff);
+	    n |= ((*(ptr + 1) >> 7) & 0xffff) << 16;
+
+	    // define a label that will be relocated
+
+	    sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
+	    greloc(cur_text_section, sym, t, R_C60LO16);
+	    greloc(cur_text_section, sym, t + 4, R_C60HI16);
+
+	    // clear out where the pointer was
+
+	    *ptr &= ~(0xffff << 7);
+	    *(ptr + 1) &= ~(0xffff << 7);
+	}
+	t = n;
+    }
+}
+
+void gsym(int t)
+{
+    gsym_addr(t, ind);
+}
+
+// these are regs that tcc doesn't really know about, 
+// but assign them unique values so the mapping routines
+// can distinquish them
+
+#define C67_A0 105
+#define C67_SP 106
+#define C67_B3 107
+#define C67_FP 108
+#define C67_B2 109
+#define C67_CREG_ZERO -1	// Special code for no condition reg test
+
+
+int ConvertRegToRegClass(int r)
+{
+    // only works for A4-B13
+
+    return RC_C67_A4 << (r - TREG_C67_A4);
+}
+
+
+// map TCC reg to C67 reg number
+
+int C67_map_regn(int r)
+{
+    if (r == 0)			// normal tcc regs
+	return 0x2;		// A2
+    else if (r == 1)		// normal tcc regs
+	return 3;		// A3
+    else if (r == 2)		// normal tcc regs
+	return 0;		// B0
+    else if (r == 3)		// normal tcc regs
+	return 1;		// B1
+    else if (r >= TREG_C67_A4 && r <= TREG_C67_B13)	// these form a pattern of alt pairs
+	return (((r & 0xfffffffc) >> 1) | (r & 1)) + 2;
+    else if (r == C67_A0)
+	return 0;		// set to A0 (offset reg)
+    else if (r == C67_B2)
+	return 2;		// set to B2 (offset reg)
+    else if (r == C67_B3)
+	return 3;		// set to B3 (return address reg)
+    else if (r == C67_SP)
+	return 15;		// set to SP (B15) (offset reg)
+    else if (r == C67_FP)
+	return 15;		// set to FP (A15) (offset reg)
+    else if (r == C67_CREG_ZERO)
+	return 0;		// Special code for no condition reg test
+    else
+	ALWAYS_ASSERT(FALSE);
+
+    return 0;
+}
+
+// mapping from tcc reg number to 
+// C67 register to condition code field
+//
+// valid condition code regs are:
+//
+// tcc reg 2 ->B0 -> 1
+// tcc reg 3 ->B1 -> 2
+// tcc reg 0 -> A2 -> 5
+// tcc reg 1 -> A3 -> X
+// tcc reg      B2 -> 3
+
+int C67_map_regc(int r)
+{
+    if (r == 0)			// normal tcc regs
+	return 0x5;
+    else if (r == 2)		// normal tcc regs
+	return 0x1;
+    else if (r == 3)		// normal tcc regs
+	return 0x2;
+    else if (r == C67_B2)	// normal tcc regs
+	return 0x3;
+    else if (r == C67_CREG_ZERO)
+	return 0;		// Special code for no condition reg test
+    else
+	ALWAYS_ASSERT(FALSE);
+
+    return 0;
+}
+
+
+// map TCC reg to C67 reg side A or B
+
+int C67_map_regs(int r)
+{
+    if (r == 0)			// normal tcc regs
+	return 0x0;
+    else if (r == 1)		// normal tcc regs
+	return 0x0;
+    else if (r == 2)		// normal tcc regs
+	return 0x1;
+    else if (r == 3)		// normal tcc regs
+	return 0x1;
+    else if (r >= TREG_C67_A4 && r <= TREG_C67_B13)	// these form a pattern of alt pairs
+	return (r & 2) >> 1;
+    else if (r == C67_A0)
+	return 0;		// set to A side 
+    else if (r == C67_B2)
+	return 1;		// set to B side 
+    else if (r == C67_B3)
+	return 1;		// set to B side
+    else if (r == C67_SP)
+	return 0x1;		// set to SP (B15) B side 
+    else if (r == C67_FP)
+	return 0x0;		// set to FP (A15) A side 
+    else
+	ALWAYS_ASSERT(FALSE);
+
+    return 0;
+}
+
+int C67_map_S12(char *s)
+{
+    if (strstr(s, ".S1") != NULL)
+	return 0;
+    else if (strcmp(s, ".S2"))
+	return 1;
+    else
+	ALWAYS_ASSERT(FALSE);
+
+    return 0;
+}
+
+int C67_map_D12(char *s)
+{
+    if (strstr(s, ".D1") != NULL)
+	return 0;
+    else if (strcmp(s, ".D2"))
+	return 1;
+    else
+	ALWAYS_ASSERT(FALSE);
+
+    return 0;
+}
+
+
+
+void C67_asm(char *s, int a, int b, int c)
+{
+    BOOL xpath;
+
+#ifdef ASSEMBLY_LISTING_C67
+    if (!f) {
+	f = fopen("TCC67_out.txt", "wt");
+    }
+    fprintf(f, "%04X ", ind);
+#endif
+
+    if (strstr(s, "MVKL") == s) {
+	C67_g((C67_map_regn(b) << 23) |
+	      ((a & 0xffff) << 7) | (0x0a << 2) | (C67_map_regs(b) << 1));
+    } else if (strstr(s, "MVKH") == s) {
+	C67_g((C67_map_regn(b) << 23) |
+	      (((a >> 16) & 0xffff) << 7) |
+	      (0x1a << 2) | (C67_map_regs(b) << 1));
+    } else if (strstr(s, "STW.D SP POST DEC") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (15 << 18) |	//SP B15
+	      (2 << 13) |	//ucst5 (must keep 8 byte boundary !!)
+	      (0xa << 9) |	//mode a = post dec ucst
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (1 << 7) |	//y D1/D2 use B side
+	      (7 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STB.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2 A side
+	      (3 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STH.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2 A side
+	      (5 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STB.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2 A side
+	      (3 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STH.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2 A side
+	      (5 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STW.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2 A side
+	      (7 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STW.D *") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (C67_map_regn(b) << 18) |	//base reg A0
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(b) << 7) |	//y D1/D2 base reg side
+	      (7 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STH.D *") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (C67_map_regn(b) << 18) |	//base reg A0
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(b) << 7) |	//y D1/D2 base reg side
+	      (5 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STB.D *") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (C67_map_regn(b) << 18) |	//base reg A0
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(b) << 7) |	//y D1/D2 base reg side
+	      (3 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "STW.D +*") == s) {
+	ALWAYS_ASSERT(c < 32);
+	C67_g((C67_map_regn(a) << 23) |	//src
+	      (C67_map_regn(b) << 18) |	//base reg A0
+	      (c << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(b) << 7) |	//y D1/D2 base reg side
+	      (7 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of src
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDW.D SP PRE INC") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg B15
+	      (2 << 13) |	//ucst5 (must keep 8 byte boundary)
+	      (9 << 9) |	//mode 9 = pre inc ucst5
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (1 << 7) |	//y D1/D2  B side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDDW.D SP PRE INC") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg B15
+	      (1 << 13) |	//ucst5 (must keep 8 byte boundary)
+	      (9 << 9) |	//mode 9 = pre inc ucst5
+	      (1 << 8) |	//r (LDDW bit 1)
+	      (1 << 7) |	//y D1/D2  B side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDW.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2  A side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDDW.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (1 << 8) |	//r (LDDW bit 1)
+	      (0 << 7) |	//y D1/D2  A side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDH.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2  A side
+	      (4 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDB.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2  A side
+	      (2 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDHU.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2  A side
+	      (0 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDBU.D *+SP[A0]") == s) {
+	C67_g((C67_map_regn(a) << 23) |	//dst
+	      (15 << 18) |	//base reg A15
+	      (0 << 13) |	//offset reg A0
+	      (5 << 9) |	//mode 5 = pos offset, base reg + off reg
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (0 << 7) |	//y D1/D2  A side
+	      (1 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(a) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDW.D *") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDDW.D *") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (1 << 8) |	//r (LDDW bit 1)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDH.D *") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (4 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDB.D *") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (2 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDHU.D *") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (0 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDBU.D *") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (0 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (1 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "LDW.D +*") == s) {
+	C67_g((C67_map_regn(b) << 23) |	//dst
+	      (C67_map_regn(a) << 18) |	//base reg A15
+	      (1 << 13) |	//cst5
+	      (1 << 9) |	//mode 1 = pos cst offset
+	      (0 << 8) |	//r (LDDW bit 0)
+	      (C67_map_regs(a) << 7) |	//y D1/D2  src side
+	      (6 << 4) |	//ldst 3=STB, 5=STH 5, 7=STW, 6=LDW 4=LDH 2=LDB 0=LDHU 1=LDBU 
+	      (1 << 2) |	//opcode
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPLTSP") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x3a << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPGTSP") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x39 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPEQSP") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x38 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    }
+
+    else if (strstr(s, "CMPLTDP") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x2a << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPGTDP") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x29 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPEQDP") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x28 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPLT") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x57 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPGT") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x47 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPEQ") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x53 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPLTU") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x5f << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "CMPGTU") == s) {
+	xpath = C67_map_regs(a) ^ C67_map_regs(b);
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1
+	      (xpath << 12) |	//x use cross path for src2
+	      (0x4f << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side for reg c
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "B DISP") == s) {
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//z
+	      (a << 7) |	//cnst
+	      (0x4 << 2) |	//opcode fixed
+	      (0 << 1) |	//S0/S1
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "B.") == s) {
+	xpath = C67_map_regs(c) ^ 1;
+
+	C67_g((C67_map_regc(b) << 29) |	//creg
+	      (a << 28) |	//inv
+	      (0 << 23) |	//dst
+	      (C67_map_regn(c) << 18) |	//src2
+	      (0 << 13) |	//
+	      (xpath << 12) |	//x cross path if !B side
+	      (0xd << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (1 << 1) |	//must be S2
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "MV.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (0 << 13) |	//src1 (cst5)
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x2 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SPTRUNC.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0xb << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "DPTRUNC.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      ((C67_map_regn(b) + 1) << 18) |	//src2   WEIRD CPU must specify odd reg for some reason
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x1 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "INTSP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2   
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x4a << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "INTSPU.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2  
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x49 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "INTDP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2  
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x39 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "INTDPU.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      ((C67_map_regn(b) + 1) << 18) |	//src2   WEIRD CPU must specify odd reg for some reason
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x3b << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SPDP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (0 << 13) |	//src1 NA
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x2 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "DPSP.L") == s) {
+	ALWAYS_ASSERT(C67_map_regs(b) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      ((C67_map_regn(b) + 1) << 18) |	//src2 WEIRD CPU must specify odd reg for some reason
+	      (0 << 13) |	//src1 NA
+	      (0 << 12) |	//x cross path if opposite sides
+	      (0x9 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "ADD.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x3 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SUB.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x7 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "OR.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x7f << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "AND.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x7b << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "XOR.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x6f << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "ADDSP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x10 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "ADDDP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x18 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SUBSP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x11 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SUBDP.L") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x19 << 5) |	//opcode
+	      (0x6 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "MPYSP.M") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x1c << 7) |	//opcode
+	      (0x0 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "MPYDP.M") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2 (possible x path)
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x0e << 7) |	//opcode
+	      (0x0 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "MPYI.M") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(a) == C67_map_regs(c));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1 (cst5)
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x4 << 7) |	//opcode
+	      (0x0 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SHR.S") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x37 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SHRU.S") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x27 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "SHL.S") == s) {
+	xpath = C67_map_regs(b) ^ C67_map_regs(c);
+
+	ALWAYS_ASSERT(C67_map_regs(c) == C67_map_regs(a));
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(c) << 23) |	//dst
+	      (C67_map_regn(b) << 18) |	//src2
+	      (C67_map_regn(a) << 13) |	//src1 
+	      (xpath << 12) |	//x cross path if opposite sides
+	      (0x33 << 6) |	//opcode
+	      (0x8 << 2) |	//opcode fixed
+	      (C67_map_regs(c) << 1) |	//side of dest
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "||ADDK") == s) {
+	xpath = 0;		// no xpath required just use the side of the src/dst
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(b) << 23) |	//dst
+	      (a << 07) |	//scst16
+	      (0x14 << 2) |	//opcode fixed
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (1 << 0));	//parallel
+    } else if (strstr(s, "ADDK") == s) {
+	xpath = 0;		// no xpath required just use the side of the src/dst
+
+	C67_g((0 << 29) |	//creg
+	      (0 << 28) |	//inv
+	      (C67_map_regn(b) << 23) |	//dst
+	      (a << 07) |	//scst16
+	      (0x14 << 2) |	//opcode fixed
+	      (C67_map_regs(b) << 1) |	//side of dst
+	      (0 << 0));	//parallel
+    } else if (strstr(s, "NOP") == s) {
+	C67_g(((a - 1) << 13) |	//no of cycles
+	      (0 << 0));	//parallel
+    } else
+	ALWAYS_ASSERT(FALSE);
+
+#ifdef ASSEMBLY_LISTING_C67
+    fprintf(f, " %s %d %d %d\n", s, a, b, c);
+#endif
+
+}
+
+//r=reg to load, fr=from reg, symbol for relocation, constant
+
+void C67_MVKL(int r, int fc)
+{
+    C67_asm("MVKL.", fc, r, 0);
+}
+
+void C67_MVKH(int r, int fc)
+{
+    C67_asm("MVKH.", fc, r, 0);
+}
+
+void C67_STB_SP_A0(int r)
+{
+    C67_asm("STB.D *+SP[A0]", r, 0, 0);	// STB  r,*+SP[A0]
+}
+
+void C67_STH_SP_A0(int r)
+{
+    C67_asm("STH.D *+SP[A0]", r, 0, 0);	// STH  r,*+SP[A0]
+}
+
+void C67_STW_SP_A0(int r)
+{
+    C67_asm("STW.D *+SP[A0]", r, 0, 0);	// STW  r,*+SP[A0]
+}
+
+void C67_STB_PTR(int r, int r2)
+{
+    C67_asm("STB.D *", r, r2, 0);	// STB  r, *r2
+}
+
+void C67_STH_PTR(int r, int r2)
+{
+    C67_asm("STH.D *", r, r2, 0);	// STH  r, *r2
+}
+
+void C67_STW_PTR(int r, int r2)
+{
+    C67_asm("STW.D *", r, r2, 0);	// STW  r, *r2
+}
+
+void C67_STW_PTR_PRE_INC(int r, int r2, int n)
+{
+    C67_asm("STW.D +*", r, r2, n);	// STW  r, *+r2
+}
+
+void C67_PUSH(int r)
+{
+    C67_asm("STW.D SP POST DEC", r, 0, 0);	// STW  r,*SP--
+}
+
+void C67_LDW_SP_A0(int r)
+{
+    C67_asm("LDW.D *+SP[A0]", r, 0, 0);	// LDW  *+SP[A0],r
+}
+
+void C67_LDDW_SP_A0(int r)
+{
+    C67_asm("LDDW.D *+SP[A0]", r, 0, 0);	// LDDW  *+SP[A0],r
+}
+
+void C67_LDH_SP_A0(int r)
+{
+    C67_asm("LDH.D *+SP[A0]", r, 0, 0);	// LDH  *+SP[A0],r
+}
+
+void C67_LDB_SP_A0(int r)
+{
+    C67_asm("LDB.D *+SP[A0]", r, 0, 0);	// LDB  *+SP[A0],r
+}
+
+void C67_LDHU_SP_A0(int r)
+{
+    C67_asm("LDHU.D *+SP[A0]", r, 0, 0);	// LDHU  *+SP[A0],r
+}
+
+void C67_LDBU_SP_A0(int r)
+{
+    C67_asm("LDBU.D *+SP[A0]", r, 0, 0);	// LDBU  *+SP[A0],r
+}
+
+void C67_LDW_PTR(int r, int r2)
+{
+    C67_asm("LDW.D *", r, r2, 0);	// LDW  *r,r2
+}
+
+void C67_LDDW_PTR(int r, int r2)
+{
+    C67_asm("LDDW.D *", r, r2, 0);	// LDDW  *r,r2
+}
+
+void C67_LDH_PTR(int r, int r2)
+{
+    C67_asm("LDH.D *", r, r2, 0);	// LDH  *r,r2
+}
+
+void C67_LDB_PTR(int r, int r2)
+{
+    C67_asm("LDB.D *", r, r2, 0);	// LDB  *r,r2
+}
+
+void C67_LDHU_PTR(int r, int r2)
+{
+    C67_asm("LDHU.D *", r, r2, 0);	// LDHU  *r,r2
+}
+
+void C67_LDBU_PTR(int r, int r2)
+{
+    C67_asm("LDBU.D *", r, r2, 0);	// LDBU  *r,r2
+}
+
+void C67_LDW_PTR_PRE_INC(int r, int r2)
+{
+    C67_asm("LDW.D +*", r, r2, 0);	// LDW  *+r,r2
+}
+
+void C67_POP(int r)
+{
+    C67_asm("LDW.D SP PRE INC", r, 0, 0);	// LDW  *++SP,r
+}
+
+void C67_POP_DW(int r)
+{
+    C67_asm("LDDW.D SP PRE INC", r, 0, 0);	// LDDW  *++SP,r
+}
+
+void C67_CMPLT(int s1, int s2, int dst)
+{
+    C67_asm("CMPLT.L1", s1, s2, dst);
+}
+
+void C67_CMPGT(int s1, int s2, int dst)
+{
+    C67_asm("CMPGT.L1", s1, s2, dst);
+}
+
+void C67_CMPEQ(int s1, int s2, int dst)
+{
+    C67_asm("CMPEQ.L1", s1, s2, dst);
+}
+
+void C67_CMPLTU(int s1, int s2, int dst)
+{
+    C67_asm("CMPLTU.L1", s1, s2, dst);
+}
+
+void C67_CMPGTU(int s1, int s2, int dst)
+{
+    C67_asm("CMPGTU.L1", s1, s2, dst);
+}
+
+
+void C67_CMPLTSP(int s1, int s2, int dst)
+{
+    C67_asm("CMPLTSP.S1", s1, s2, dst);
+}
+
+void C67_CMPGTSP(int s1, int s2, int dst)
+{
+    C67_asm("CMPGTSP.S1", s1, s2, dst);
+}
+
+void C67_CMPEQSP(int s1, int s2, int dst)
+{
+    C67_asm("CMPEQSP.S1", s1, s2, dst);
+}
+
+void C67_CMPLTDP(int s1, int s2, int dst)
+{
+    C67_asm("CMPLTDP.S1", s1, s2, dst);
+}
+
+void C67_CMPGTDP(int s1, int s2, int dst)
+{
+    C67_asm("CMPGTDP.S1", s1, s2, dst);
+}
+
+void C67_CMPEQDP(int s1, int s2, int dst)
+{
+    C67_asm("CMPEQDP.S1", s1, s2, dst);
+}
+
+
+void C67_IREG_B_REG(int inv, int r1, int r2)	// [!R] B  r2
+{
+    C67_asm("B.S2", inv, r1, r2);
+}
+
+
+// call with how many 32 bit words to skip
+// (0 would branch to the branch instruction)
+
+void C67_B_DISP(int disp)	//  B  +2  Branch with constant displacement
+{
+    // Branch point is relative to the 8 word fetch packet
+    //
+    // we will assume the text section always starts on an 8 word (32 byte boundary)
+    //
+    // so add in how many words into the fetch packet the branch is
+
+
+    C67_asm("B DISP", disp + ((ind & 31) >> 2), 0, 0);
+}
+
+void C67_NOP(int n)
+{
+    C67_asm("NOP", n, 0, 0);
+}
+
+void C67_ADDK(int n, int r)
+{
+    ALWAYS_ASSERT(abs(n) < 32767);
+
+    C67_asm("ADDK", n, r, 0);
+}
+
+void C67_ADDK_PARALLEL(int n, int r)
+{
+    ALWAYS_ASSERT(abs(n) < 32767);
+
+    C67_asm("||ADDK", n, r, 0);
+}
+
+void C67_Adjust_ADDK(int *inst, int n)
+{
+    ALWAYS_ASSERT(abs(n) < 32767);
+
+    *inst = (*inst & (~(0xffff << 7))) | ((n & 0xffff) << 7);
+}
+
+void C67_MV(int r, int v)
+{
+    C67_asm("MV.L", 0, r, v);
+}
+
+
+void C67_DPTRUNC(int r, int v)
+{
+    C67_asm("DPTRUNC.L", 0, r, v);
+}
+
+void C67_SPTRUNC(int r, int v)
+{
+    C67_asm("SPTRUNC.L", 0, r, v);
+}
+
+void C67_INTSP(int r, int v)
+{
+    C67_asm("INTSP.L", 0, r, v);
+}
+
+void C67_INTDP(int r, int v)
+{
+    C67_asm("INTDP.L", 0, r, v);
+}
+
+void C67_INTSPU(int r, int v)
+{
+    C67_asm("INTSPU.L", 0, r, v);
+}
+
+void C67_INTDPU(int r, int v)
+{
+    C67_asm("INTDPU.L", 0, r, v);
+}
+
+void C67_SPDP(int r, int v)
+{
+    C67_asm("SPDP.L", 0, r, v);
+}
+
+void C67_DPSP(int r, int v)	// note regs must be on the same side
+{
+    C67_asm("DPSP.L", 0, r, v);
+}
+
+void C67_ADD(int r, int v)
+{
+    C67_asm("ADD.L", v, r, v);
+}
+
+void C67_SUB(int r, int v)
+{
+    C67_asm("SUB.L", v, r, v);
+}
+
+void C67_AND(int r, int v)
+{
+    C67_asm("AND.L", v, r, v);
+}
+
+void C67_OR(int r, int v)
+{
+    C67_asm("OR.L", v, r, v);
+}
+
+void C67_XOR(int r, int v)
+{
+    C67_asm("XOR.L", v, r, v);
+}
+
+void C67_ADDSP(int r, int v)
+{
+    C67_asm("ADDSP.L", v, r, v);
+}
+
+void C67_SUBSP(int r, int v)
+{
+    C67_asm("SUBSP.L", v, r, v);
+}
+
+void C67_MPYSP(int r, int v)
+{
+    C67_asm("MPYSP.M", v, r, v);
+}
+
+void C67_ADDDP(int r, int v)
+{
+    C67_asm("ADDDP.L", v, r, v);
+}
+
+void C67_SUBDP(int r, int v)
+{
+    C67_asm("SUBDP.L", v, r, v);
+}
+
+void C67_MPYDP(int r, int v)
+{
+    C67_asm("MPYDP.M", v, r, v);
+}
+
+void C67_MPYI(int r, int v)
+{
+    C67_asm("MPYI.M", v, r, v);
+}
+
+void C67_SHL(int r, int v)
+{
+    C67_asm("SHL.S", r, v, v);
+}
+
+void C67_SHRU(int r, int v)
+{
+    C67_asm("SHRU.S", r, v, v);
+}
+
+void C67_SHR(int r, int v)
+{
+    C67_asm("SHR.S", r, v, v);
+}
+
+
+
+/* load 'r' from value 'sv' */
+void load(int r, SValue * sv)
+{
+    int v, t, ft, fc, fr, size = 0, element;
+    BOOL Unsigned = false;
+    SValue v1;
+
+    fr = sv->r;
+    ft = sv->type.t;
+    fc = sv->c.ul;
+
+    v = fr & VT_VALMASK;
+    if (fr & VT_LVAL) {
+	if (v == VT_LLOCAL) {
+	    v1.type.t = VT_INT;
+	    v1.r = VT_LOCAL | VT_LVAL;
+	    v1.c.ul = fc;
+	    load(r, &v1);
+	    fr = r;
+	} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+	    error("long double not supported");
+	} else if ((ft & VT_TYPE) == VT_BYTE) {
+	    size = 1;
+	} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
+	    size = 1;
+	    Unsigned = TRUE;
+	} else if ((ft & VT_TYPE) == VT_SHORT) {
+	    size = 2;
+	} else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
+	    size = 2;
+	    Unsigned = TRUE;
+	} else if ((ft & VT_BTYPE) == VT_DOUBLE) {
+	    size = 8;
+	} else {
+	    size = 4;
+	}
+
+	// check if fc is a positive reference on the stack, 
+	// if it is tcc is referencing what it thinks is a parameter
+	// on the stack, so check if it is really in a register.
+
+
+	if (v == VT_LOCAL && fc > 0) {
+	    int stack_pos = 8;
+
+	    for (t = 0; t < NoCallArgsPassedOnStack; t++) {
+		if (fc == stack_pos)
+		    break;
+
+		stack_pos += TranslateStackToReg[t];
+	    }
+
+	    // param has been pushed on stack, get it like a local var
+
+	    fc = ParamLocOnStack[t] - 8;
+	}
+
+	if ((fr & VT_VALMASK) < VT_CONST)	// check for pure indirect
+	{
+	    if (size == 1) {
+		if (Unsigned)
+		    C67_LDBU_PTR(v, r);	// LDBU  *v,r
+		else
+		    C67_LDB_PTR(v, r);	// LDB  *v,r
+	    } else if (size == 2) {
+		if (Unsigned)
+		    C67_LDHU_PTR(v, r);	// LDHU  *v,r
+		else
+		    C67_LDH_PTR(v, r);	// LDH  *v,r
+	    } else if (size == 4) {
+		C67_LDW_PTR(v, r);	// LDW  *v,r
+	    } else if (size == 8) {
+		C67_LDDW_PTR(v, r);	// LDDW  *v,r
+	    }
+
+	    C67_NOP(4);		// NOP 4
+	    return;
+	} else if (fr & VT_SYM) {
+	    greloc(cur_text_section, sv->sym, ind, R_C60LO16);	// rem the inst need to be patched
+	    greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16);
+
+
+	    C67_MVKL(C67_A0, fc);	//r=reg to load,  constant
+	    C67_MVKH(C67_A0, fc);	//r=reg to load,  constant
+
+
+	    if (size == 1) {
+		if (Unsigned)
+		    C67_LDBU_PTR(C67_A0, r);	// LDBU  *A0,r
+		else
+		    C67_LDB_PTR(C67_A0, r);	// LDB  *A0,r
+	    } else if (size == 2) {
+		if (Unsigned)
+		    C67_LDHU_PTR(C67_A0, r);	// LDHU  *A0,r
+		else
+		    C67_LDH_PTR(C67_A0, r);	// LDH  *A0,r
+	    } else if (size == 4) {
+		C67_LDW_PTR(C67_A0, r);	// LDW  *A0,r
+	    } else if (size == 8) {
+		C67_LDDW_PTR(C67_A0, r);	// LDDW  *A0,r
+	    }
+
+	    C67_NOP(4);		// NOP 4
+	    return;
+	} else {
+	    element = size;
+
+	    // divide offset in bytes to create element index
+	    C67_MVKL(C67_A0, (fc / element) + 8 / element);	//r=reg to load,  constant
+	    C67_MVKH(C67_A0, (fc / element) + 8 / element);	//r=reg to load,  constant
+
+	    if (size == 1) {
+		if (Unsigned)
+		    C67_LDBU_SP_A0(r);	// LDBU  r, SP[A0]
+		else
+		    C67_LDB_SP_A0(r);	// LDB  r, SP[A0]
+	    } else if (size == 2) {
+		if (Unsigned)
+		    C67_LDHU_SP_A0(r);	// LDHU  r, SP[A0]
+		else
+		    C67_LDH_SP_A0(r);	// LDH  r, SP[A0]
+	    } else if (size == 4) {
+		C67_LDW_SP_A0(r);	// LDW  r, SP[A0]
+	    } else if (size == 8) {
+		C67_LDDW_SP_A0(r);	// LDDW  r, SP[A0]
+	    }
+
+
+	    C67_NOP(4);		// NOP 4
+	    return;
+	}
+    } else {
+	if (v == VT_CONST) {
+	    if (fr & VT_SYM) {
+		greloc(cur_text_section, sv->sym, ind, R_C60LO16);	// rem the inst need to be patched
+		greloc(cur_text_section, sv->sym, ind + 4, R_C60HI16);
+	    }
+	    C67_MVKL(r, fc);	//r=reg to load, constant
+	    C67_MVKH(r, fc);	//r=reg to load, constant
+	} else if (v == VT_LOCAL) {
+	    C67_MVKL(r, fc + 8);	//r=reg to load, constant C67 stack points to next free
+	    C67_MVKH(r, fc + 8);	//r=reg to load, constant
+	    C67_ADD(C67_FP, r);	// MV v,r   v -> r
+	} else if (v == VT_CMP) {
+	    C67_MV(C67_compare_reg, r);	// MV v,r   v -> r
+	} else if (v == VT_JMP || v == VT_JMPI) {
+	    t = v & 1;
+	    C67_B_DISP(4);	//  Branch with constant displacement, skip over this branch, load, nop, load
+	    C67_MVKL(r, t);	//  r=reg to load, 0 or 1 (do this while branching)
+	    C67_NOP(4);		//  NOP 4
+	    gsym(fc);		//  modifies other branches to branch here
+	    C67_MVKL(r, t ^ 1);	//  r=reg to load, 0 or 1
+	} else if (v != r) {
+	    C67_MV(v, r);	// MV v,r   v -> r
+
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_MV(v + 1, r + 1);	// MV v,r   v -> r
+	}
+    }
+}
+
+
+/* store register 'r' in lvalue 'v' */
+void store(int r, SValue * v)
+{
+    int fr, bt, ft, fc, size, t, element;
+
+    ft = v->type.t;
+    fc = v->c.ul;
+    fr = v->r & VT_VALMASK;
+    bt = ft & VT_BTYPE;
+    /* XXX: incorrect if float reg to reg */
+
+    if (bt == VT_LDOUBLE) {
+	error("long double not supported");
+    } else {
+	if (bt == VT_SHORT)
+	    size = 2;
+	else if (bt == VT_BYTE)
+	    size = 1;
+	else if (bt == VT_DOUBLE)
+	    size = 8;
+	else
+	    size = 4;
+
+	if ((v->r & VT_VALMASK) == VT_CONST) {
+	    /* constant memory reference */
+
+	    if (v->r & VT_SYM) {
+		greloc(cur_text_section, v->sym, ind, R_C60LO16);	// rem the inst need to be patched
+		greloc(cur_text_section, v->sym, ind + 4, R_C60HI16);
+	    }
+	    C67_MVKL(C67_A0, fc);	//r=reg to load,  constant
+	    C67_MVKH(C67_A0, fc);	//r=reg to load,  constant
+
+	    if (size == 1)
+		C67_STB_PTR(r, C67_A0);	// STB  r, *A0
+	    else if (size == 2)
+		C67_STH_PTR(r, C67_A0);	// STH  r, *A0
+	    else if (size == 4 || size == 8)
+		C67_STW_PTR(r, C67_A0);	// STW  r, *A0
+
+	    if (size == 8)
+		C67_STW_PTR_PRE_INC(r + 1, C67_A0, 1);	// STW  r, *+A0[1]
+	} else if ((v->r & VT_VALMASK) == VT_LOCAL) {
+	    // check case of storing to passed argument that
+	    // tcc thinks is on the stack but for C67 is
+	    // passed as a reg.  However it may have been
+	    // saved to the stack, if that reg was required
+	    // for a call to a child function
+
+	    if (fc > 0)		// argument ??
+	    {
+		// walk through sizes and figure which param
+
+		int stack_pos = 8;
+
+		for (t = 0; t < NoCallArgsPassedOnStack; t++) {
+		    if (fc == stack_pos)
+			break;
+
+		    stack_pos += TranslateStackToReg[t];
+		}
+
+		// param has been pushed on stack, get it like a local var
+		fc = ParamLocOnStack[t] - 8;
+	    }
+
+	    if (size == 8)
+		element = 4;
+	    else
+		element = size;
+
+	    // divide offset in bytes to create word index
+	    C67_MVKL(C67_A0, (fc / element) + 8 / element);	//r=reg to load,  constant
+	    C67_MVKH(C67_A0, (fc / element) + 8 / element);	//r=reg to load,  constant
+
+
+
+	    if (size == 1)
+		C67_STB_SP_A0(r);	// STB  r, SP[A0]
+	    else if (size == 2)
+		C67_STH_SP_A0(r);	// STH  r, SP[A0]
+	    else if (size == 4 || size == 8)
+		C67_STW_SP_A0(r);	// STW  r, SP[A0]
+
+	    if (size == 8) {
+		C67_ADDK(1, C67_A0);	//  ADDK 1,A0
+		C67_STW_SP_A0(r + 1);	//  STW  r, SP[A0]
+	    }
+	} else {
+	    if (size == 1)
+		C67_STB_PTR(r, fr);	// STB  r, *fr
+	    else if (size == 2)
+		C67_STH_PTR(r, fr);	// STH  r, *fr
+	    else if (size == 4 || size == 8)
+		C67_STW_PTR(r, fr);	// STW  r, *fr
+
+	    if (size == 8) {
+		C67_STW_PTR_PRE_INC(r + 1, fr, 1);	// STW  r, *+fr[1]
+	    }
+	}
+    }
+}
+
+/* 'is_jmp' is '1' if it is a jump */
+static void gcall_or_jmp(int is_jmp)
+{
+    int r;
+    Sym *sym;
+
+    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+	/* constant case */
+	if (vtop->r & VT_SYM) {
+	    /* relocation case */
+
+	    // get add into A0, then start the jump B3
+
+	    greloc(cur_text_section, vtop->sym, ind, R_C60LO16);	// rem the inst need to be patched
+	    greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16);
+
+	    C67_MVKL(C67_A0, 0);	//r=reg to load, constant
+	    C67_MVKH(C67_A0, 0);	//r=reg to load, constant
+	    C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0);	//  B.S2x  A0
+
+	    if (is_jmp) {
+		C67_NOP(5);	// simple jump, just put NOP
+	    } else {
+		// Call, must load return address into B3 during delay slots
+
+		sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0);	// symbol for return address
+		greloc(cur_text_section, sym, ind, R_C60LO16);	// rem the inst need to be patched
+		greloc(cur_text_section, sym, ind + 4, R_C60HI16);
+		C67_MVKL(C67_B3, 0);	//r=reg to load, constant
+		C67_MVKH(C67_B3, 0);	//r=reg to load, constant
+		C67_NOP(3);	// put remaining NOPs
+	    }
+	} else {
+	    /* put an empty PC32 relocation */
+	    ALWAYS_ASSERT(FALSE);
+	}
+    } else {
+	/* otherwise, indirect call */
+	r = gv(RC_INT);
+	C67_IREG_B_REG(0, C67_CREG_ZERO, r);	//  B.S2x  r
+
+	if (is_jmp) {
+	    C67_NOP(5);		// simple jump, just put NOP
+	} else {
+	    // Call, must load return address into B3 during delay slots
+
+	    sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0);	// symbol for return address
+	    greloc(cur_text_section, sym, ind, R_C60LO16);	// rem the inst need to be patched
+	    greloc(cur_text_section, sym, ind + 4, R_C60HI16);
+	    C67_MVKL(C67_B3, 0);	//r=reg to load, constant
+	    C67_MVKH(C67_B3, 0);	//r=reg to load, constant
+	    C67_NOP(3);		// put remaining NOPs
+	}
+    }
+}
+
+/* generate function call with address in (vtop->t, vtop->c) and free function
+   context. Stack entry is popped */
+void gfunc_call(int nb_args)
+{
+    int i, r, size = 0;
+    int args_sizes[NoCallArgsPassedOnStack];
+
+    if (nb_args > NoCallArgsPassedOnStack) {
+	error("more than 10 function params not currently supported");
+	// handle more than 10, put some on the stack
+    }
+
+    for (i = 0; i < nb_args; i++) {
+	if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
+	    ALWAYS_ASSERT(FALSE);
+	} else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
+	    ALWAYS_ASSERT(FALSE);
+	} else {
+	    /* simple type (currently always same size) */
+	    /* XXX: implicit cast ? */
+
+
+	    if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+		error("long long not supported");
+	    } else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+		error("long double not supported");
+	    } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
+		size = 8;
+	    } else {
+		size = 4;
+	    }
+
+	    // put the parameter into the corresponding reg (pair)
+
+	    r = gv(RC_C67_A4 << (2 * i));
+
+	    // must put on stack because with 1 pass compiler , no way to tell
+	    // if an up coming nested call might overwrite these regs
+
+	    C67_PUSH(r);
+
+	    if (size == 8) {
+		C67_STW_PTR_PRE_INC(r + 1, C67_SP, 3);	// STW  r, *+SP[3] (go back and put the other)
+	    }
+	    args_sizes[i] = size;
+	}
+	vtop--;
+    }
+    // POP all the params on the stack into registers for the
+    // immediate call (in reverse order)
+
+    for (i = nb_args - 1; i >= 0; i--) {
+
+	if (args_sizes[i] == 8)
+	    C67_POP_DW(TREG_C67_A4 + i * 2);
+	else
+	    C67_POP(TREG_C67_A4 + i * 2);
+    }
+    gcall_or_jmp(0);
+    vtop--;
+}
+
+
+// to be compatible with Code Composer for the C67
+// the first 10 parameters must be passed in registers
+// (pairs for 64 bits) starting wit; A4:A5, then B4:B5 and
+// ending with B12:B13.
+//
+// When a call is made, if the caller has its parameters
+// in regs A4-B13 these must be saved before/as the call 
+// parameters are loaded and restored upon return (or if/when needed).
+
+/* generate function prolog of type 't' */
+void gfunc_prolog(CType * func_type)
+{
+    int addr, align, size, func_call, i;
+    Sym *sym;
+    CType *type;
+
+    sym = func_type->ref;
+    func_call = sym->r;
+    addr = 8;
+    /* if the function returns a structure, then add an
+       implicit pointer parameter */
+    func_vt = sym->type;
+    if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
+	func_vc = addr;
+	addr += 4;
+    }
+
+    NoOfCurFuncArgs = 0;
+
+    /* define parameters */
+    while ((sym = sym->next) != NULL) {
+	type = &sym->type;
+	sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
+	size = type_size(type, &align);
+	size = (size + 3) & ~3;
+
+	// keep track of size of arguments so
+	// we can translate where tcc thinks they
+	// are on the stack into the appropriate reg
+
+	TranslateStackToReg[NoOfCurFuncArgs] = size;
+	NoOfCurFuncArgs++;
+
+#ifdef FUNC_STRUCT_PARAM_AS_PTR
+	/* structs are passed as pointer */
+	if ((type->t & VT_BTYPE) == VT_STRUCT) {
+	    size = 4;
+	}
+#endif
+	addr += size;
+    }
+    func_ret_sub = 0;
+    /* pascal type call ? */
+    if (func_call == FUNC_STDCALL)
+	func_ret_sub = addr - 8;
+
+    C67_MV(C67_FP, C67_A0);	//  move FP -> A0
+    C67_MV(C67_SP, C67_FP);	//  move SP -> FP
+
+    // place all the args passed in regs onto the stack
+
+    loc = 0;
+    for (i = 0; i < NoOfCurFuncArgs; i++) {
+
+	ParamLocOnStack[i] = loc;	// remember where the param is
+	loc += -8;
+
+	C67_PUSH(TREG_C67_A4 + i * 2);
+
+	if (TranslateStackToReg[i] == 8) {
+	    C67_STW_PTR_PRE_INC(TREG_C67_A4 + i * 2 + 1, C67_SP, 3);	// STW  r, *+SP[1] (go back and put the other)
+	}
+    }
+
+    TotalBytesPushedOnStack = -loc;
+
+    func_sub_sp_offset = ind;	// remember where we put the stack instruction 
+    C67_ADDK(0, C67_SP);	//  ADDK.L2 loc,SP  (just put zero temporarily)
+
+    C67_PUSH(C67_A0);
+    C67_PUSH(C67_B3);
+}
+
+/* generate function epilog */
+void gfunc_epilog(void)
+{
+    {
+	int local = (-loc + 7) & -8;	// stack must stay aligned to 8 bytes for LDDW instr
+	C67_POP(C67_B3);
+	C67_NOP(4);		// NOP wait for load
+	C67_IREG_B_REG(0, C67_CREG_ZERO, C67_B3);	//  B.S2  B3
+	C67_POP(C67_FP);
+	C67_ADDK(local, C67_SP);	//  ADDK.L2 loc,SP  
+	C67_Adjust_ADDK((int *) (cur_text_section->data +
+				 func_sub_sp_offset),
+			-local + TotalBytesPushedOnStack);
+	C67_NOP(3);		// NOP 
+    }
+}
+
+/* generate a jump to a label */
+int gjmp(int t)
+{
+    int ind1 = ind;
+
+    C67_MVKL(C67_A0, t);	//r=reg to load,  constant
+    C67_MVKH(C67_A0, t);	//r=reg to load,  constant
+    C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0);	// [!R] B.S2x  A0
+    C67_NOP(5);
+    return ind1;
+}
+
+/* generate a jump to a fixed address */
+void gjmp_addr(int a)
+{
+    Sym *sym;
+    // I guess this routine is used for relative short
+    // local jumps, for now just handle it as the general
+    // case
+
+    // define a label that will be relocated
+
+    sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
+    greloc(cur_text_section, sym, ind, R_C60LO16);
+    greloc(cur_text_section, sym, ind + 4, R_C60HI16);
+
+    gjmp(0);			// place a zero there later the symbol will be added to it
+}
+
+/* generate a test. set 'inv' to invert test. Stack entry is popped */
+int gtst(int inv, int t)
+{
+    int ind1, n;
+    int v, *p;
+
+    v = vtop->r & VT_VALMASK;
+    if (v == VT_CMP) {
+	/* fast case : can jump directly since flags are set */
+	// C67 uses B2 sort of as flags register
+	ind1 = ind;
+	C67_MVKL(C67_A0, t);	//r=reg to load, constant
+	C67_MVKH(C67_A0, t);	//r=reg to load, constant
+
+	if (C67_compare_reg != TREG_EAX &&	// check if not already in a conditional test reg
+	    C67_compare_reg != TREG_EDX &&
+	    C67_compare_reg != TREG_ST0 && C67_compare_reg != C67_B2) {
+	    C67_MV(C67_compare_reg, C67_B2);
+	    C67_compare_reg = C67_B2;
+	}
+
+	C67_IREG_B_REG(C67_invert_test ^ inv, C67_compare_reg, C67_A0);	// [!R] B.S2x  A0
+	C67_NOP(5);
+	t = ind1;		//return where we need to patch
+
+    } else if (v == VT_JMP || v == VT_JMPI) {
+	/* && or || optimization */
+	if ((v & 1) == inv) {
+	    /* insert vtop->c jump list in t */
+	    p = &vtop->c.i;
+
+	    // I guess the idea is to traverse to the
+	    // null at the end of the list and store t
+	    // there
+
+	    n = *p;
+	    while (n != 0) {
+		p = (int *) (cur_text_section->data + n);
+
+		// extract 32 bit address from MVKH/MVKL
+		n = ((*p >> 7) & 0xffff);
+		n |= ((*(p + 1) >> 7) & 0xffff) << 16;
+	    }
+	    *p |= (t & 0xffff) << 7;
+	    *(p + 1) |= ((t >> 16) & 0xffff) << 7;
+	    t = vtop->c.i;
+
+	} else {
+	    t = gjmp(t);
+	    gsym(vtop->c.i);
+	}
+    } else {
+	if (is_float(vtop->type.t)) {
+	    vpushi(0);
+	    gen_op(TOK_NE);
+	}
+	if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+	    /* constant jmp optimization */
+	    if ((vtop->c.i != 0) != inv)
+		t = gjmp(t);
+	} else {
+	    // I think we need to get the value on the stack
+	    // into a register, test it, and generate a branch
+	    // return the address of the branch, so it can be
+	    // later patched
+
+	    v = gv(RC_INT);	// get value into a reg 
+	    ind1 = ind;
+	    C67_MVKL(C67_A0, t);	//r=reg to load, constant
+	    C67_MVKH(C67_A0, t);	//r=reg to load, constant
+
+	    if (v != TREG_EAX &&	// check if not already in a conditional test reg
+		v != TREG_EDX && v != TREG_ST0 && v != C67_B2) {
+		C67_MV(v, C67_B2);
+		v = C67_B2;
+	    }
+
+	    C67_IREG_B_REG(inv, v, C67_A0);	// [!R] B.S2x  A0
+	    C67_NOP(5);
+	    t = ind1;		//return where we need to patch
+	    ind1 = ind;
+	}
+    }
+    vtop--;
+    return t;
+}
+
+/* generate an integer binary operation */
+void gen_opi(int op)
+{
+    int r, fr, opc, t;
+
+    switch (op) {
+    case '+':
+    case TOK_ADDC1:		/* add with carry generation */
+	opc = 0;
+      gen_op8:
+
+
+// C67 can't do const compares, must load into a reg
+// so just go to gv2 directly - tktk
+
+
+
+	if (op >= TOK_ULT && op <= TOK_GT)
+	    gv2(RC_INT_BSIDE, RC_INT);	// make sure r (src1) is on the B Side of CPU
+	else
+	    gv2(RC_INT, RC_INT);
+
+	r = vtop[-1].r;
+	fr = vtop[0].r;
+
+	C67_compare_reg = C67_B2;
+
+
+	if (op == TOK_LT) {
+	    C67_CMPLT(r, fr, C67_B2);
+	    C67_invert_test = false;
+	} else if (op == TOK_GE) {
+	    C67_CMPLT(r, fr, C67_B2);
+	    C67_invert_test = true;
+	} else if (op == TOK_GT) {
+	    C67_CMPGT(r, fr, C67_B2);
+	    C67_invert_test = false;
+	} else if (op == TOK_LE) {
+	    C67_CMPGT(r, fr, C67_B2);
+	    C67_invert_test = true;
+	} else if (op == TOK_EQ) {
+	    C67_CMPEQ(r, fr, C67_B2);
+	    C67_invert_test = false;
+	} else if (op == TOK_NE) {
+	    C67_CMPEQ(r, fr, C67_B2);
+	    C67_invert_test = true;
+	} else if (op == TOK_ULT) {
+	    C67_CMPLTU(r, fr, C67_B2);
+	    C67_invert_test = false;
+	} else if (op == TOK_UGE) {
+	    C67_CMPLTU(r, fr, C67_B2);
+	    C67_invert_test = true;
+	} else if (op == TOK_UGT) {
+	    C67_CMPGTU(r, fr, C67_B2);
+	    C67_invert_test = false;
+	} else if (op == TOK_ULE) {
+	    C67_CMPGTU(r, fr, C67_B2);
+	    C67_invert_test = true;
+	} else if (op == '+')
+	    C67_ADD(fr, r);	// ADD  r,fr,r
+	else if (op == '-')
+	    C67_SUB(fr, r);	// SUB  r,fr,r
+	else if (op == '&')
+	    C67_AND(fr, r);	// AND  r,fr,r
+	else if (op == '|')
+	    C67_OR(fr, r);	// OR  r,fr,r
+	else if (op == '^')
+	    C67_XOR(fr, r);	// XOR  r,fr,r
+	else
+	    ALWAYS_ASSERT(FALSE);
+
+	vtop--;
+	if (op >= TOK_ULT && op <= TOK_GT) {
+	    vtop->r = VT_CMP;
+	    vtop->c.i = op;
+	}
+	break;
+    case '-':
+    case TOK_SUBC1:		/* sub with carry generation */
+	opc = 5;
+	goto gen_op8;
+    case TOK_ADDC2:		/* add with carry use */
+	opc = 2;
+	goto gen_op8;
+    case TOK_SUBC2:		/* sub with carry use */
+	opc = 3;
+	goto gen_op8;
+    case '&':
+	opc = 4;
+	goto gen_op8;
+    case '^':
+	opc = 6;
+	goto gen_op8;
+    case '|':
+	opc = 1;
+	goto gen_op8;
+    case '*':
+    case TOK_UMULL:
+	gv2(RC_INT, RC_INT);
+	r = vtop[-1].r;
+	fr = vtop[0].r;
+	vtop--;
+	C67_MPYI(fr, r);	// 32 bit bultiply  fr,r,fr
+	C67_NOP(8);		// NOP 8 for worst case
+	break;
+    case TOK_SHL:
+	gv2(RC_INT_BSIDE, RC_INT_BSIDE);	// shift amount must be on same side as dst
+	r = vtop[-1].r;
+	fr = vtop[0].r;
+	vtop--;
+	C67_SHL(fr, r);		// arithmetic/logical shift
+	break;
+
+    case TOK_SHR:
+	gv2(RC_INT_BSIDE, RC_INT_BSIDE);	// shift amount must be on same side as dst
+	r = vtop[-1].r;
+	fr = vtop[0].r;
+	vtop--;
+	C67_SHRU(fr, r);	// logical shift
+	break;
+
+    case TOK_SAR:
+	gv2(RC_INT_BSIDE, RC_INT_BSIDE);	// shift amount must be on same side as dst
+	r = vtop[-1].r;
+	fr = vtop[0].r;
+	vtop--;
+	C67_SHR(fr, r);		// arithmetic shift
+	break;
+
+    case '/':
+	t = TOK__divi;
+      call_func:
+	vswap();
+	/* call generic idiv function */
+	vpush_global_sym(&func_old_type, t);
+	vrott(3);
+	gfunc_call(2);
+	vpushi(0);
+	vtop->r = REG_IRET;
+	vtop->r2 = VT_CONST;
+	break;
+    case TOK_UDIV:
+    case TOK_PDIV:
+	t = TOK__divu;
+	goto call_func;
+    case '%':
+	t = TOK__remi;
+	goto call_func;
+    case TOK_UMOD:
+	t = TOK__remu;
+	goto call_func;
+
+    default:
+	opc = 7;
+	goto gen_op8;
+    }
+}
+
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+   two operands are guaranted to have the same floating point type */
+/* XXX: need to use ST1 too */
+void gen_opf(int op)
+{
+    int ft, fc, fr, r;
+
+    if (op >= TOK_ULT && op <= TOK_GT)
+	gv2(RC_EDX, RC_EAX);	// make sure src2 is on b side
+    else
+	gv2(RC_FLOAT, RC_FLOAT);	// make sure src2 is on b side
+
+    ft = vtop->type.t;
+    fc = vtop->c.ul;
+    r = vtop->r;
+    fr = vtop[-1].r;
+
+
+    if ((ft & VT_BTYPE) == VT_LDOUBLE)
+	error("long doubles not supported");
+
+    if (op >= TOK_ULT && op <= TOK_GT) {
+
+	r = vtop[-1].r;
+	fr = vtop[0].r;
+
+	C67_compare_reg = C67_B2;
+
+	if (op == TOK_LT) {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_CMPLTDP(r, fr, C67_B2);
+	    else
+		C67_CMPLTSP(r, fr, C67_B2);
+
+	    C67_invert_test = false;
+	} else if (op == TOK_GE) {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_CMPLTDP(r, fr, C67_B2);
+	    else
+		C67_CMPLTSP(r, fr, C67_B2);
+
+	    C67_invert_test = true;
+	} else if (op == TOK_GT) {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_CMPGTDP(r, fr, C67_B2);
+	    else
+		C67_CMPGTSP(r, fr, C67_B2);
+
+	    C67_invert_test = false;
+	} else if (op == TOK_LE) {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_CMPGTDP(r, fr, C67_B2);
+	    else
+		C67_CMPGTSP(r, fr, C67_B2);
+
+	    C67_invert_test = true;
+	} else if (op == TOK_EQ) {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_CMPEQDP(r, fr, C67_B2);
+	    else
+		C67_CMPEQSP(r, fr, C67_B2);
+
+	    C67_invert_test = false;
+	} else if (op == TOK_NE) {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE)
+		C67_CMPEQDP(r, fr, C67_B2);
+	    else
+		C67_CMPEQSP(r, fr, C67_B2);
+
+	    C67_invert_test = true;
+	} else {
+	    ALWAYS_ASSERT(FALSE);
+	}
+	vtop->r = VT_CMP;	// tell TCC that result is in "flags" actually B2
+    } else {
+	if (op == '+') {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE) {
+		C67_ADDDP(r, fr);	// ADD  fr,r,fr
+		C67_NOP(6);
+	    } else {
+		C67_ADDSP(r, fr);	// ADD  fr,r,fr
+		C67_NOP(3);
+	    }
+	    vtop--;
+	} else if (op == '-') {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE) {
+		C67_SUBDP(r, fr);	// SUB  fr,r,fr
+		C67_NOP(6);
+	    } else {
+		C67_SUBSP(r, fr);	// SUB  fr,r,fr
+		C67_NOP(3);
+	    }
+	    vtop--;
+	} else if (op == '*') {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE) {
+		C67_MPYDP(r, fr);	// MPY  fr,r,fr
+		C67_NOP(9);
+	    } else {
+		C67_MPYSP(r, fr);	// MPY  fr,r,fr
+		C67_NOP(3);
+	    }
+	    vtop--;
+	} else if (op == '/') {
+	    if ((ft & VT_BTYPE) == VT_DOUBLE) {
+		// must call intrinsic DP floating point divide
+		vswap();
+		/* call generic idiv function */
+		vpush_global_sym(&func_old_type, TOK__divd);
+		vrott(3);
+		gfunc_call(2);
+		vpushi(0);
+		vtop->r = REG_FRET;
+		vtop->r2 = REG_LRET;
+
+	    } else {
+		// must call intrinsic SP floating point divide
+		vswap();
+		/* call generic idiv function */
+		vpush_global_sym(&func_old_type, TOK__divf);
+		vrott(3);
+		gfunc_call(2);
+		vpushi(0);
+		vtop->r = REG_FRET;
+		vtop->r2 = VT_CONST;
+	    }
+	} else
+	    ALWAYS_ASSERT(FALSE);
+
+
+    }
+}
+
+
+/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
+   and 'long long' cases. */
+void gen_cvt_itof(int t)
+{
+    int r;
+
+    gv(RC_INT);
+    r = vtop->r;
+
+    if ((t & VT_BTYPE) == VT_DOUBLE) {
+	if (t & VT_UNSIGNED)
+	    C67_INTDPU(r, r);
+	else
+	    C67_INTDP(r, r);
+
+	C67_NOP(4);
+	vtop->type.t = VT_DOUBLE;
+    } else {
+	if (t & VT_UNSIGNED)
+	    C67_INTSPU(r, r);
+	else
+	    C67_INTSP(r, r);
+	C67_NOP(3);
+	vtop->type.t = VT_FLOAT;
+    }
+
+}
+
+/* convert fp to int 't' type */
+/* XXX: handle long long case */
+void gen_cvt_ftoi(int t)
+{
+    int r;
+
+    gv(RC_FLOAT);
+    r = vtop->r;
+
+    if (t != VT_INT)
+	error("long long not supported");
+    else {
+	if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
+	    C67_DPTRUNC(r, r);
+	    C67_NOP(3);
+	} else {
+	    C67_SPTRUNC(r, r);
+	    C67_NOP(3);
+	}
+
+	vtop->type.t = VT_INT;
+
+    }
+}
+
+/* convert from one floating point type to another */
+void gen_cvt_ftof(int t)
+{
+    int r, r2;
+
+    if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE &&
+	(t & VT_BTYPE) == VT_FLOAT) {
+	// convert double to float
+
+	gv(RC_FLOAT);		// get it in a register pair
+
+	r = vtop->r;
+
+	C67_DPSP(r, r);		// convert it to SP same register
+	C67_NOP(3);
+
+	vtop->type.t = VT_FLOAT;
+	vtop->r2 = VT_CONST;	// set this as unused
+    } else if ((vtop->type.t & VT_BTYPE) == VT_FLOAT &&
+	       (t & VT_BTYPE) == VT_DOUBLE) {
+	// convert float to double
+
+	gv(RC_FLOAT);		// get it in a register
+
+	r = vtop->r;
+
+	if (r == TREG_EAX) {	// make sure the paired reg is avail
+	    r2 = get_reg(RC_ECX);
+	} else if (r == TREG_EDX) {
+	    r2 = get_reg(RC_ST0);
+	} else {
+	    ALWAYS_ASSERT(FALSE);
+            r2 = 0; /* avoid warning */
+        }
+
+	C67_SPDP(r, r);		// convert it to DP same register
+	C67_NOP(1);
+
+	vtop->type.t = VT_DOUBLE;
+	vtop->r2 = r2;		// set this as unused
+    } else {
+	ALWAYS_ASSERT(FALSE);
+    }
+}
+
+/* computed goto support */
+void ggoto(void)
+{
+    gcall_or_jmp(1);
+    vtop--;
+}
+
+/* end of X86 code generator */
+/*************************************************************/
diff --git a/tinyc/coff.h b/tinyc/coff.h
new file mode 100644
index 000000000..38960b40f
--- /dev/null
+++ b/tinyc/coff.h
@@ -0,0 +1,446 @@
+/**************************************************************************/
+/*  COFF.H                                                                */
+/*     COFF data structures and related definitions used by the linker    */
+/**************************************************************************/
+
+/*------------------------------------------------------------------------*/
+/*  COFF FILE HEADER                                                      */
+/*------------------------------------------------------------------------*/
+struct filehdr {
+        unsigned short  f_magic;        /* magic number */
+        unsigned short  f_nscns;        /* number of sections */
+        long            f_timdat;       /* time & date stamp */
+        long            f_symptr;       /* file pointer to symtab */
+        long            f_nsyms;        /* number of symtab entries */
+        unsigned short  f_opthdr;       /* sizeof(optional hdr) */
+        unsigned short  f_flags;        /* flags */
+        unsigned short  f_TargetID;     /* for C6x = 0x0099 */
+        };
+
+/*------------------------------------------------------------------------*/
+/*  File header flags                                                     */
+/*------------------------------------------------------------------------*/
+#define  F_RELFLG   0x01       /* relocation info stripped from file       */
+#define  F_EXEC     0x02       /* file is executable (no unresolved refs)  */
+#define  F_LNNO     0x04       /* line nunbers stripped from file          */
+#define  F_LSYMS    0x08       /* local symbols stripped from file         */
+#define  F_GSP10    0x10       /* 34010 version                            */
+#define  F_GSP20    0x20       /* 34020 version                            */
+#define  F_SWABD    0x40       /* bytes swabbed (in names)                 */
+#define  F_AR16WR   0x80       /* byte ordering of an AR16WR (PDP-11)      */
+#define  F_LITTLE   0x100      /* byte ordering of an AR32WR (vax)         */
+#define  F_BIG      0x200      /* byte ordering of an AR32W (3B, maxi)     */
+#define  F_PATCH    0x400      /* contains "patch" list in optional header */
+#define  F_NODF     0x400   
+
+#define F_VERSION    (F_GSP10  | F_GSP20)   
+#define F_BYTE_ORDER (F_LITTLE | F_BIG)
+#define FILHDR  struct filehdr
+
+//#define FILHSZ  sizeof(FILHDR) 
+#define FILHSZ  22                // above rounds to align on 4 bytes which causes problems 
+
+#define COFF_C67_MAGIC 0x00c2
+
+/*------------------------------------------------------------------------*/
+/*  Macros to recognize magic numbers                                     */
+/*------------------------------------------------------------------------*/
+#define ISMAGIC(x)      (((unsigned short)(x))==(unsigned short)magic)
+#define ISARCHIVE(x)    ((((unsigned short)(x))==(unsigned short)ARTYPE))
+#define BADMAGIC(x)     (((unsigned short)(x) & 0x8080) && !ISMAGIC(x))
+
+
+/*------------------------------------------------------------------------*/
+/*  OPTIONAL FILE HEADER                                                  */
+/*------------------------------------------------------------------------*/
+typedef struct aouthdr {
+        short   magic;          /* see magic.h                          */
+        short   vstamp;         /* version stamp                        */
+        long    tsize;          /* text size in bytes, padded to FW bdry*/
+        long    dsize;          /* initialized data "  "                */
+        long    bsize;          /* uninitialized data "   "             */
+        long    entrypt;        /* entry pt.                            */
+        long    text_start;     /* base of text used for this file      */
+        long    data_start;     /* base of data used for this file      */
+} AOUTHDR;
+
+#define AOUTSZ  sizeof(AOUTHDR)
+
+/*----------------------------------------------------------------------*/
+/*      When a UNIX aout header is to be built in the optional header,  */
+/*      the following magic numbers can appear in that header:          */ 
+/*                                                                      */
+/*              AOUT1MAGIC : default : readonly sharable text segment   */
+/*              AOUT2MAGIC:          : writable text segment            */
+/*              PAGEMAGIC  :         : configured for paging            */
+/*----------------------------------------------------------------------*/
+#define AOUT1MAGIC 0410
+#define AOUT2MAGIC 0407
+#define PAGEMAGIC  0413
+
+
+/*------------------------------------------------------------------------*/
+/*  COMMON ARCHIVE FILE STRUCTURES                                        */
+/*                                                                        */
+/*       ARCHIVE File Organization:                                       */
+/*       _______________________________________________                  */
+/*       |__________ARCHIVE_MAGIC_STRING_______________|                  */
+/*       |__________ARCHIVE_FILE_MEMBER_1______________|                  */
+/*       |                                             |                  */
+/*       |       Archive File Header "ar_hdr"          |                  */
+/*       |.............................................|                  */
+/*       |       Member Contents                       |                  */
+/*       |               1. External symbol directory  |                  */
+/*       |               2. Text file                  |                  */
+/*       |_____________________________________________|                  */
+/*       |________ARCHIVE_FILE_MEMBER_2________________|                  */
+/*       |               "ar_hdr"                      |                  */
+/*       |.............................................|                  */
+/*       |       Member Contents (.o or text file)     |                  */
+/*       |_____________________________________________|                  */
+/*       |       .               .               .     |                  */
+/*       |       .               .               .     |                  */
+/*       |       .               .               .     |                  */
+/*       |_____________________________________________|                  */
+/*       |________ARCHIVE_FILE_MEMBER_n________________|                  */
+/*       |               "ar_hdr"                      |                  */
+/*       |.............................................|                  */
+/*       |               Member Contents               |                  */
+/*       |_____________________________________________|                  */
+/*                                                                        */
+/*------------------------------------------------------------------------*/
+
+#define COFF_ARMAG   "!<arch>\n"
+#define SARMAG  8
+#define ARFMAG  "`\n"
+
+struct ar_hdr           /* archive file member header - printable ascii */
+{
+        char    ar_name[16];    /* file member name - `/' terminated */
+        char    ar_date[12];    /* file member date - decimal */
+        char    ar_uid[6];      /* file member user id - decimal */
+        char    ar_gid[6];      /* file member group id - decimal */
+        char    ar_mode[8];     /* file member mode - octal */
+        char    ar_size[10];    /* file member size - decimal */
+        char    ar_fmag[2];     /* ARFMAG - string to end header */
+};
+
+
+/*------------------------------------------------------------------------*/
+/*  SECTION HEADER                                                        */
+/*------------------------------------------------------------------------*/
+struct scnhdr {
+        char            s_name[8];      /* section name */
+        long            s_paddr;        /* physical address */
+        long            s_vaddr;        /* virtual address */
+        long            s_size;         /* section size */
+        long            s_scnptr;       /* file ptr to raw data for section */
+        long            s_relptr;       /* file ptr to relocation */
+        long            s_lnnoptr;      /* file ptr to line numbers */
+        unsigned int	s_nreloc;       /* number of relocation entries */
+        unsigned int	s_nlnno;        /* number of line number entries */
+        unsigned int	s_flags;        /* flags */
+		unsigned short	s_reserved;     /* reserved byte */
+		unsigned short  s_page;         /* memory page id */
+        };
+
+#define SCNHDR  struct scnhdr
+#define SCNHSZ  sizeof(SCNHDR)
+
+/*------------------------------------------------------------------------*/
+/* Define constants for names of "special" sections                       */
+/*------------------------------------------------------------------------*/
+//#define _TEXT    ".text"
+#define _DATA    ".data"
+#define _BSS     ".bss"
+#define _CINIT   ".cinit"
+#define _TV      ".tv"
+
+/*------------------------------------------------------------------------*/
+/* The low 4 bits of s_flags is used as a section "type"                  */
+/*------------------------------------------------------------------------*/
+#define STYP_REG    0x00  /* "regular" : allocated, relocated, loaded */
+#define STYP_DSECT  0x01  /* "dummy"   : not allocated, relocated, not loaded */
+#define STYP_NOLOAD 0x02  /* "noload"  : allocated, relocated, not loaded */
+#define STYP_GROUP  0x04  /* "grouped" : formed of input sections */
+#define STYP_PAD    0x08  /* "padding" : not allocated, not relocated, loaded */
+#define STYP_COPY   0x10  /* "copy"    : used for C init tables - 
+                                                not allocated, relocated,
+                                                loaded;  reloc & lineno
+                                                entries processed normally */
+#define STYP_TEXT   0x20   /* section contains text only */
+#define STYP_DATA   0x40   /* section contains data only */
+#define STYP_BSS    0x80   /* section contains bss only */
+
+#define STYP_ALIGN  0x100  /* align flag passed by old version assemblers */
+#define ALIGN_MASK  0x0F00 /* part of s_flags that is used for align vals */
+#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8))
+
+
+/*------------------------------------------------------------------------*/
+/*  RELOCATION ENTRIES                                                    */
+/*------------------------------------------------------------------------*/
+struct reloc
+{
+   long            r_vaddr;        /* (virtual) address of reference */
+   short           r_symndx;       /* index into symbol table */
+   unsigned short  r_disp;         /* additional bits for address calculation */
+   unsigned short  r_type;         /* relocation type */
+};
+
+#define RELOC   struct reloc
+#define RELSZ   10                 /* sizeof(RELOC) */
+
+/*--------------------------------------------------------------------------*/
+/*   define all relocation types                                            */
+/*--------------------------------------------------------------------------*/
+
+#define R_ABS           0         /* absolute address - no relocation       */
+#define R_DIR16         01        /* UNUSED                                 */
+#define R_REL16         02        /* UNUSED                                 */
+#define R_DIR24         04        /* UNUSED                                 */
+#define R_REL24         05        /* 24 bits, direct                        */
+#define R_DIR32         06        /* UNUSED                                 */
+#define R_RELBYTE      017        /* 8 bits, direct                         */
+#define R_RELWORD      020        /* 16 bits, direct                        */
+#define R_RELLONG      021        /* 32 bits, direct                        */
+#define R_PCRBYTE      022        /* 8 bits, PC-relative                    */
+#define R_PCRWORD      023        /* 16 bits, PC-relative                   */
+#define R_PCRLONG      024        /* 32 bits, PC-relative                   */
+#define R_OCRLONG      030        /* GSP: 32 bits, one's complement direct  */
+#define R_GSPPCR16     031        /* GSP: 16 bits, PC relative (in words)   */
+#define R_GSPOPR32     032        /* GSP: 32 bits, direct big-endian        */
+#define R_PARTLS16     040        /* Brahma: 16 bit offset of 24 bit address*/
+#define R_PARTMS8      041        /* Brahma: 8 bit page of 24 bit address   */
+#define R_PARTLS7      050        /* DSP: 7 bit offset of 16 bit address    */
+#define R_PARTMS9      051        /* DSP: 9 bit page of 16 bit address      */
+#define R_REL13        052        /* DSP: 13 bits, direct                   */
+
+
+/*------------------------------------------------------------------------*/
+/*  LINE NUMBER ENTRIES                                                   */
+/*------------------------------------------------------------------------*/
+struct lineno
+{
+        union
+        {
+                long    l_symndx ;      /* sym. table index of function name
+                                                iff l_lnno == 0      */
+                long    l_paddr ;       /* (physical) address of line number */
+        }               l_addr ;
+        unsigned short  l_lnno ;        /* line number */
+};
+
+#define LINENO  struct lineno
+#define LINESZ  6       /* sizeof(LINENO) */
+
+
+/*------------------------------------------------------------------------*/
+/*   STORAGE CLASSES                                                      */
+/*------------------------------------------------------------------------*/
+#define  C_EFCN          -1    /* physical end of function */
+#define  C_NULL          0
+#define  C_AUTO          1     /* automatic variable */
+#define  C_EXT           2     /* external symbol */
+#define  C_STAT          3     /* static */
+#define  C_REG           4     /* register variable */
+#define  C_EXTDEF        5     /* external definition */
+#define  C_LABEL         6     /* label */
+#define  C_ULABEL        7     /* undefined label */
+#define  C_MOS           8     /* member of structure */
+#define  C_ARG           9     /* function argument */
+#define  C_STRTAG        10    /* structure tag */
+#define  C_MOU           11    /* member of union */
+#define  C_UNTAG         12    /* union tag */
+#define  C_TPDEF         13    /* type definition */
+#define C_USTATIC        14    /* undefined static */
+#define  C_ENTAG         15    /* enumeration tag */
+#define  C_MOE           16    /* member of enumeration */
+#define  C_REGPARM       17    /* register parameter */
+#define  C_FIELD         18    /* bit field */
+
+#define  C_BLOCK         100   /* ".bb" or ".eb" */
+#define  C_FCN           101   /* ".bf" or ".ef" */
+#define  C_EOS           102   /* end of structure */
+#define  C_FILE          103   /* file name */
+#define  C_LINE          104   /* dummy sclass for line number entry */
+#define  C_ALIAS         105   /* duplicate tag */
+#define  C_HIDDEN        106   /* special storage class for external */
+                               /* symbols in dmert public libraries  */
+
+/*------------------------------------------------------------------------*/
+/*  SYMBOL TABLE ENTRIES                                                  */
+/*------------------------------------------------------------------------*/
+
+#define  SYMNMLEN   8      /*  Number of characters in a symbol name */
+#define  FILNMLEN   14     /*  Number of characters in a file name */
+#define  DIMNUM     4      /*  Number of array dimensions in auxiliary entry */
+
+
+struct syment
+{
+        union
+        {
+                char            _n_name[SYMNMLEN];      /* old COFF version */
+                struct
+                {
+                        long    _n_zeroes;      /* new == 0 */
+                        long    _n_offset;      /* offset into string table */
+                } _n_n;
+                char            *_n_nptr[2];    /* allows for overlaying */
+        } _n;
+        long                    n_value;        /* value of symbol */
+        short                   n_scnum;        /* section number */
+        unsigned short          n_type;         /* type and derived type */
+        char                    n_sclass;       /* storage class */
+        char                    n_numaux;       /* number of aux. entries */
+};
+
+#define n_name          _n._n_name
+#define n_nptr          _n._n_nptr[1]
+#define n_zeroes        _n._n_n._n_zeroes
+#define n_offset        _n._n_n._n_offset
+
+/*------------------------------------------------------------------------*/
+/* Relocatable symbols have a section number of the                       */
+/* section in which they are defined.  Otherwise, section                 */
+/* numbers have the following meanings:                                   */
+/*------------------------------------------------------------------------*/
+#define  N_UNDEF  0                     /* undefined symbol */
+#define  N_ABS    -1                    /* value of symbol is absolute */
+#define  N_DEBUG  -2                    /* special debugging symbol  */
+#define  N_TV     (unsigned short)-3    /* needs transfer vector (preload) */
+#define  P_TV     (unsigned short)-4    /* needs transfer vector (postload) */
+
+
+/*------------------------------------------------------------------------*/
+/* The fundamental type of a symbol packed into the low                   */
+/* 4 bits of the word.                                                    */
+/*------------------------------------------------------------------------*/
+#define  _EF    ".ef"
+
+#define  T_NULL     0          /* no type info */
+#define  T_ARG      1          /* function argument (only used by compiler) */
+#define  T_CHAR     2          /* character */
+#define  T_SHORT    3          /* short integer */
+#define  T_INT      4          /* integer */
+#define  T_LONG     5          /* long integer */
+#define  T_FLOAT    6          /* floating point */
+#define  T_DOUBLE   7          /* double word */
+#define  T_STRUCT   8          /* structure  */
+#define  T_UNION    9          /* union  */
+#define  T_ENUM     10         /* enumeration  */
+#define  T_MOE      11         /* member of enumeration */
+#define  T_UCHAR    12         /* unsigned character */
+#define  T_USHORT   13         /* unsigned short */
+#define  T_UINT     14         /* unsigned integer */
+#define  T_ULONG    15         /* unsigned long */
+
+/*------------------------------------------------------------------------*/
+/* derived types are:                                                     */
+/*------------------------------------------------------------------------*/
+#define  DT_NON      0          /* no derived type */
+#define  DT_PTR      1          /* pointer */
+#define  DT_FCN      2          /* function */
+#define  DT_ARY      3          /* array */
+
+#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \
+       ((basic) | ((d1) <<  4) | ((d2) <<  6) | ((d3) <<  8) |\
+                  ((d4) << 10) | ((d5) << 12) | ((d6) << 14))
+
+/*------------------------------------------------------------------------*/
+/* type packing constants and macros                                      */
+/*------------------------------------------------------------------------*/
+#define  N_BTMASK_COFF     017
+#define  N_TMASK_COFF      060
+#define  N_TMASK1_COFF     0300
+#define  N_TMASK2_COFF     0360
+#define  N_BTSHFT_COFF     4
+#define  N_TSHIFT_COFF     2
+
+#define  BTYPE_COFF(x)  ((x) & N_BTMASK_COFF)  
+#define  ISINT(x)  (((x) >= T_CHAR && (x) <= T_LONG) ||   \
+		    ((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM)
+#define  ISFLT_COFF(x)  ((x) == T_DOUBLE || (x) == T_FLOAT)
+#define  ISPTR_COFF(x)  (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF)) 
+#define  ISFCN_COFF(x)  (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF))
+#define  ISARY_COFF(x)  (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF))
+#define  ISTAG_COFF(x)  ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG)
+
+#define  INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<<N_TSHIFT_COFF)|(DT_PTR<<N_BTSHFT_COFF)|(x&N_BTMASK_COFF))
+#define  DECREF_COFF(x) ((((x)>>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF))
+
+
+/*------------------------------------------------------------------------*/
+/*  AUXILIARY SYMBOL ENTRY                                                */
+/*------------------------------------------------------------------------*/
+union auxent
+{
+	struct
+	{
+		long            x_tagndx;       /* str, un, or enum tag indx */
+		union
+		{
+			struct
+			{
+				unsigned short  x_lnno; /* declaration line number */
+				unsigned short  x_size; /* str, union, array size */
+			} x_lnsz;
+			long    x_fsize;        /* size of function */
+		} x_misc;
+		union
+		{
+			struct                  /* if ISFCN, tag, or .bb */
+			{
+				long    x_lnnoptr;      /* ptr to fcn line # */
+				long    x_endndx;       /* entry ndx past block end */
+			}       x_fcn;
+			struct                  /* if ISARY, up to 4 dimen. */
+			{
+				unsigned short  x_dimen[DIMNUM];
+			}       x_ary;
+		}               x_fcnary;
+		unsigned short  x_regcount;   /* number of registers used by func */
+	}       x_sym;
+	struct
+	{
+		char    x_fname[FILNMLEN];
+	}       x_file;
+	struct
+	{
+		long    x_scnlen;          /* section length */
+		unsigned short  x_nreloc;  /* number of relocation entries */
+		unsigned short  x_nlinno;  /* number of line numbers */
+	}       x_scn;
+};
+
+#define SYMENT  struct syment
+#define SYMESZ  18      /* sizeof(SYMENT) */
+
+#define AUXENT  union auxent
+#define AUXESZ  18      /* sizeof(AUXENT) */
+
+/*------------------------------------------------------------------------*/
+/*  NAMES OF "SPECIAL" SYMBOLS                                            */
+/*------------------------------------------------------------------------*/
+#define _STEXT          ".text"
+#define _ETEXT          "etext"
+#define _SDATA          ".data"
+#define _EDATA          "edata"
+#define _SBSS           ".bss"
+#define _END            "end"
+#define _CINITPTR       "cinit"
+
+/*--------------------------------------------------------------------------*/
+/*  ENTRY POINT SYMBOLS                                                     */
+/*--------------------------------------------------------------------------*/
+#define _START          "_start"
+#define _MAIN           "_main"
+    /*  _CSTART         "_c_int00"          (defined in params.h)  */
+
+
+#define _TVORIG         "_tvorig"
+#define _TORIGIN        "_torigin"
+#define _DORIGIN        "_dorigin"
+
+#define _SORIGIN        "_sorigin"
diff --git a/tinyc/config.h b/tinyc/config.h
new file mode 100644
index 000000000..161a3e178
--- /dev/null
+++ b/tinyc/config.h
@@ -0,0 +1,22 @@
+/* Modified to not rely on a configure script: */
+#define CONFIG_SYSROOT ""
+#define TCC_VERSION "0.9.25"
+
+#if defined(WIN32) || defined(_WIN32)
+#  define TCC_TARGET_PE   1
+#  define TCC_TARGET_I386

+#  define CONFIG_TCCDIR "."

+#elif defined(__i386__)
+#  define CONFIG_USE_LIBGCC
+#  define TCC_TARGET_I386
+#  define CONFIG_TCCDIR "/usr/local/lib/tcc"
+#  define GCC_MAJOR 4
+#  define HOST_I386 1
+#else
+#  define CONFIG_USE_LIBGCC
+#  define TCC_TARGET_X86_64
+#  define CONFIG_TCCDIR "/usr/local/lib/tcc"
+#  define GCC_MAJOR 4
+#  define HOST_X86_64 1
+#endif
+
diff --git a/tinyc/config.mak b/tinyc/config.mak
new file mode 100644
index 000000000..1722d20b3
--- /dev/null
+++ b/tinyc/config.mak
@@ -0,0 +1,20 @@
+# Automatically generated by configure - do not modify
+prefix=/usr/local
+bindir=/usr/local/bin
+tccdir=/usr/local/lib/tcc
+libdir=/usr/local/lib
+includedir=/usr/local/include
+mandir=/usr/local/man
+docdir=/usr/local/share/doc/tcc
+CC=gcc
+GCC_MAJOR=4
+HOST_CC=gcc
+AR=ar
+STRIP=strip -s -R .comment -R .note
+CFLAGS=-O2
+LDFLAGS=
+LIBSUF=.a
+EXESUF=
+ARCH=x86-64
+VERSION=0.9.25
+SRC_PATH=/home/andreas/nimrod/tinyc
diff --git a/tinyc/config.texi b/tinyc/config.texi
new file mode 100644
index 000000000..2d90df0ee
--- /dev/null
+++ b/tinyc/config.texi
@@ -0,0 +1 @@
+@set VERSION 0.9.25
diff --git a/tinyc/config_edited.h b/tinyc/config_edited.h
new file mode 100644
index 000000000..edaf335bb
--- /dev/null
+++ b/tinyc/config_edited.h
@@ -0,0 +1,20 @@
+/* Modified to not rely on a configure script: */
+#define CONFIG_SYSROOT ""
+#define TCC_VERSION "0.9.25"
+
+#if defined(WIN32) || defined(_WIN32)
+#  define TCC_TARGET_PE   1
+#  define TCC_TARGET_I386

+#  define CONFIG_TCCDIR "."

+#elif defined(__i386__)
+#  define TCC_TARGET_I386
+#  define CONFIG_TCCDIR "/usr/local/lib/tcc"
+#  define GCC_MAJOR 4
+#  define HOST_I386 1
+#else
+#  define TCC_TARGET_X86_64
+#  define CONFIG_TCCDIR "/usr/local/lib/tcc"
+#  define GCC_MAJOR 4
+#  define HOST_X86_64 1
+#endif
+
diff --git a/tinyc/elf.h b/tinyc/elf.h
new file mode 100644
index 000000000..82fd7ed91
--- /dev/null
+++ b/tinyc/elf.h
@@ -0,0 +1,1714 @@
+/* This file defines standard ELF types, structures, and macros.
+   Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ian Lance Taylor <ian@cygnus.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _ELF_H
+#define _ELF_H 1
+
+#ifndef _WIN32
+#include <inttypes.h>
+#else
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+typedef long long int int64_t;
+#endif
+
+typedef unsigned char           uint8_t;
+typedef unsigned short int      uint16_t;
+typedef unsigned int            uint32_t;
+typedef unsigned long long int  uint64_t;
+#endif
+
+/* Standard ELF types.  */
+
+/* Type for a 16-bit quantity.  */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities.  */
+typedef uint32_t Elf32_Word;
+typedef int32_t  Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t  Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities.  */
+typedef uint64_t Elf32_Xword;
+typedef int64_t  Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t  Elf64_Sxword;
+
+/* Type of addresses.  */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets.  */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities.  */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type of symbol indices.  */
+typedef uint32_t Elf32_Symndx;
+typedef uint64_t Elf64_Symndx;
+
+
+/* The ELF file header.  This appears at the start of every ELF file.  */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf32_Half    e_type;                 /* Object file type */
+  Elf32_Half    e_machine;              /* Architecture */
+  Elf32_Word    e_version;              /* Object file version */
+  Elf32_Addr    e_entry;                /* Entry point virtual address */
+  Elf32_Off     e_phoff;                /* Program header table file offset */
+  Elf32_Off     e_shoff;                /* Section header table file offset */
+  Elf32_Word    e_flags;                /* Processor-specific flags */
+  Elf32_Half    e_ehsize;               /* ELF header size in bytes */
+  Elf32_Half    e_phentsize;            /* Program header table entry size */
+  Elf32_Half    e_phnum;                /* Program header table entry count */
+  Elf32_Half    e_shentsize;            /* Section header table entry size */
+  Elf32_Half    e_shnum;                /* Section header table entry count */
+  Elf32_Half    e_shstrndx;             /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
+  Elf64_Half    e_type;                 /* Object file type */
+  Elf64_Half    e_machine;              /* Architecture */
+  Elf64_Word    e_version;              /* Object file version */
+  Elf64_Addr    e_entry;                /* Entry point virtual address */
+  Elf64_Off     e_phoff;                /* Program header table file offset */
+  Elf64_Off     e_shoff;                /* Section header table file offset */
+  Elf64_Word    e_flags;                /* Processor-specific flags */
+  Elf64_Half    e_ehsize;               /* ELF header size in bytes */
+  Elf64_Half    e_phentsize;            /* Program header table entry size */
+  Elf64_Half    e_phnum;                /* Program header table entry count */
+  Elf64_Half    e_shentsize;            /* Section header table entry size */
+  Elf64_Half    e_shnum;                /* Section header table entry count */
+  Elf64_Half    e_shstrndx;             /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array.  The EI_* macros are indices into the
+   array.  The macros under each EI_* macro are the values the byte
+   may have.  */
+
+#define EI_MAG0         0               /* File identification byte 0 index */
+#define ELFMAG0         0x7f            /* Magic number byte 0 */
+
+#define EI_MAG1         1               /* File identification byte 1 index */
+#define ELFMAG1         'E'             /* Magic number byte 1 */
+
+#define EI_MAG2         2               /* File identification byte 2 index */
+#define ELFMAG2         'L'             /* Magic number byte 2 */
+
+#define EI_MAG3         3               /* File identification byte 3 index */
+#define ELFMAG3         'F'             /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word.  */
+#define ELFMAG          "\177ELF"
+#define SELFMAG         4
+
+#define EI_CLASS        4               /* File class byte index */
+#define ELFCLASSNONE    0               /* Invalid class */
+#define ELFCLASS32      1               /* 32-bit objects */
+#define ELFCLASS64      2               /* 64-bit objects */
+#define ELFCLASSNUM     3
+
+#define EI_DATA         5               /* Data encoding byte index */
+#define ELFDATANONE     0               /* Invalid data encoding */
+#define ELFDATA2LSB     1               /* 2's complement, little endian */
+#define ELFDATA2MSB     2               /* 2's complement, big endian */
+#define ELFDATANUM      3
+
+#define EI_VERSION      6               /* File version byte index */
+                                        /* Value must be EV_CURRENT */
+
+#define EI_OSABI        7               /* OS ABI identification */
+#define ELFOSABI_SYSV           0       /* UNIX System V ABI */
+#define ELFOSABI_HPUX           1       /* HP-UX */
+#define ELFOSABI_FREEBSD        9       /* Free BSD */
+#define ELFOSABI_ARM            97      /* ARM */
+#define ELFOSABI_STANDALONE     255     /* Standalone (embedded) application */
+
+#define EI_ABIVERSION   8               /* ABI version */
+
+#define EI_PAD          9               /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type).  */
+
+#define ET_NONE         0               /* No file type */
+#define ET_REL          1               /* Relocatable file */
+#define ET_EXEC         2               /* Executable file */
+#define ET_DYN          3               /* Shared object file */
+#define ET_CORE         4               /* Core file */
+#define ET_NUM          5               /* Number of defined types */
+#define ET_LOPROC       0xff00          /* Processor-specific */
+#define ET_HIPROC       0xffff          /* Processor-specific */
+
+/* Legal values for e_machine (architecture).  */
+
+#define EM_NONE          0              /* No machine */
+#define EM_M32           1              /* AT&T WE 32100 */
+#define EM_SPARC         2              /* SUN SPARC */
+#define EM_386           3              /* Intel 80386 */
+#define EM_68K           4              /* Motorola m68k family */
+#define EM_88K           5              /* Motorola m88k family */
+#define EM_486           6              /* Intel 80486 */
+#define EM_860           7              /* Intel 80860 */
+#define EM_MIPS          8              /* MIPS R3000 big-endian */
+#define EM_S370          9              /* Amdahl */
+#define EM_MIPS_RS4_BE  10              /* MIPS R4000 big-endian */
+#define EM_RS6000       11              /* RS6000 */
+
+#define EM_PARISC       15              /* HPPA */
+#define EM_nCUBE        16              /* nCUBE */
+#define EM_VPP500       17              /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS  18              /* Sun's "v8plus" */
+#define EM_960          19              /* Intel 80960 */
+#define EM_PPC          20              /* PowerPC */
+
+#define EM_V800         36              /* NEC V800 series */
+#define EM_FR20         37              /* Fujitsu FR20 */
+#define EM_RH32         38              /* TRW RH32 */
+#define EM_RCE          39              /* Motorola RCE */
+#define EM_ARM          40              /* ARM */
+#define EM_FAKE_ALPHA   41              /* Digital Alpha */
+#define EM_SH           42              /* Hitachi SH */
+#define EM_SPARCV9      43              /* SPARC v9 64-bit */
+#define EM_TRICORE      44              /* Siemens Tricore */
+#define EM_ARC          45              /* Argonaut RISC Core */
+#define EM_H8_300       46              /* Hitachi H8/300 */
+#define EM_H8_300H      47              /* Hitachi H8/300H */
+#define EM_H8S          48              /* Hitachi H8S */
+#define EM_H8_500       49              /* Hitachi H8/500 */
+#define EM_IA_64        50              /* Intel Merced */
+#define EM_MIPS_X       51              /* Stanford MIPS-X */
+#define EM_COLDFIRE     52              /* Motorola Coldfire */
+#define EM_68HC12       53              /* Motorola M68HC12 */
+#define EM_MMA          54              /* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP          55              /* Siemens PCP */
+#define EM_NCPU         56              /* Sony nCPU embeeded RISC */
+#define EM_NDR1         57              /* Denso NDR1 microprocessor */
+#define EM_STARCORE     58              /* Motorola Start*Core processor */
+#define EM_ME16         59              /* Toyota ME16 processor */
+#define EM_ST100        60              /* STMicroelectronic ST100 processor */
+#define EM_TINYJ        61              /* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64       62              /* AMD x86-64 architecture */
+#define EM_PDSP         63              /* Sony DSP Processor */
+#define EM_FX66         66              /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS      67              /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7          68              /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16       69              /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11       70              /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08       71              /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05       72              /* Motorola MC68HC05 microcontroller */
+#define EM_SVX          73              /* Silicon Graphics SVx */
+#define EM_ST19         74              /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX          75              /* Digital VAX */
+#define EM_CRIS         76              /* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN      77              /* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH     78              /* Element 14 64-bit DSP Processor */
+#define EM_ZSP          79              /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX         80              /* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY        81              /* Harvard University machine-independent object files */
+#define EM_PRISM        82              /* SiTera Prism */
+#define EM_AVR          83              /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30         84              /* Fujitsu FR30 */
+#define EM_D10V         85              /* Mitsubishi D10V */
+#define EM_D30V         86              /* Mitsubishi D30V */
+#define EM_V850         87              /* NEC v850 */
+#define EM_M32R         88              /* Mitsubishi M32R */
+#define EM_MN10300      89              /* Matsushita MN10300 */
+#define EM_MN10200      90              /* Matsushita MN10200 */
+#define EM_PJ           91              /* picoJava */
+#define EM_OPENRISC     92              /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5       93              /* ARC Cores Tangent-A5 */
+#define EM_XTENSA       94              /* Tensilica Xtensa Architecture */
+#define EM_NUM          95
+
+/* If it is necessary to assign new unofficial EM_* values, please
+   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+   chances of collision with official or non-GNU unofficial values.  */
+
+#define EM_ALPHA        0x9026
+#define EM_C60          0x9c60
+
+/* Legal values for e_version (version).  */
+
+#define EV_NONE         0               /* Invalid ELF version */
+#define EV_CURRENT      1               /* Current version */
+#define EV_NUM          2
+
+/* Section header.  */
+
+typedef struct
+{
+  Elf32_Word    sh_name;                /* Section name (string tbl index) */
+  Elf32_Word    sh_type;                /* Section type */
+  Elf32_Word    sh_flags;               /* Section flags */
+  Elf32_Addr    sh_addr;                /* Section virtual addr at execution */
+  Elf32_Off     sh_offset;              /* Section file offset */
+  Elf32_Word    sh_size;                /* Section size in bytes */
+  Elf32_Word    sh_link;                /* Link to another section */
+  Elf32_Word    sh_info;                /* Additional section information */
+  Elf32_Word    sh_addralign;           /* Section alignment */
+  Elf32_Word    sh_entsize;             /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf64_Word    sh_name;                /* Section name (string tbl index) */
+  Elf64_Word    sh_type;                /* Section type */
+  Elf64_Xword   sh_flags;               /* Section flags */
+  Elf64_Addr    sh_addr;                /* Section virtual addr at execution */
+  Elf64_Off     sh_offset;              /* Section file offset */
+  Elf64_Xword   sh_size;                /* Section size in bytes */
+  Elf64_Word    sh_link;                /* Link to another section */
+  Elf64_Word    sh_info;                /* Additional section information */
+  Elf64_Xword   sh_addralign;           /* Section alignment */
+  Elf64_Xword   sh_entsize;             /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices.  */
+
+#define SHN_UNDEF       0               /* Undefined section */
+#define SHN_LORESERVE   0xff00          /* Start of reserved indices */
+#define SHN_LOPROC      0xff00          /* Start of processor-specific */
+#define SHN_HIPROC      0xff1f          /* End of processor-specific */
+#define SHN_ABS         0xfff1          /* Associated symbol is absolute */
+#define SHN_COMMON      0xfff2          /* Associated symbol is common */
+#define SHN_HIRESERVE   0xffff          /* End of reserved indices */
+
+/* Legal values for sh_type (section type).  */
+
+#define SHT_NULL         0              /* Section header table entry unused */
+#define SHT_PROGBITS     1              /* Program data */
+#define SHT_SYMTAB       2              /* Symbol table */
+#define SHT_STRTAB       3              /* String table */
+#define SHT_RELA         4              /* Relocation entries with addends */
+#define SHT_HASH         5              /* Symbol hash table */
+#define SHT_DYNAMIC      6              /* Dynamic linking information */
+#define SHT_NOTE         7              /* Notes */
+#define SHT_NOBITS       8              /* Program space with no data (bss) */
+#define SHT_REL          9              /* Relocation entries, no addends */
+#define SHT_SHLIB        10             /* Reserved */
+#define SHT_DYNSYM       11             /* Dynamic linker symbol table */
+#define SHT_NUM          12             /* Number of defined types.  */
+#define SHT_LOOS         0x60000000     /* Start OS-specific */
+#define SHT_LOSUNW       0x6ffffffb     /* Sun-specific low bound.  */
+#define SHT_SUNW_COMDAT  0x6ffffffb
+#define SHT_SUNW_syminfo 0x6ffffffc
+#define SHT_GNU_verdef   0x6ffffffd     /* Version definition section.  */
+#define SHT_GNU_verneed  0x6ffffffe     /* Version needs section.  */
+#define SHT_GNU_versym   0x6fffffff     /* Version symbol table.  */
+#define SHT_HISUNW       0x6fffffff     /* Sun-specific high bound.  */
+#define SHT_HIOS         0x6fffffff     /* End OS-specific type */
+#define SHT_LOPROC       0x70000000     /* Start of processor-specific */
+#define SHT_ARM_EXIDX    0x70000001     /* Exception Index table */
+#define SHT_ARM_PREEMPTMAP 0x70000002   /* dynamic linking pre-emption map */
+#define SHT_ARM_ATTRIBUTES 0x70000003   /* Object file compatibility attrs */
+#define SHT_HIPROC       0x7fffffff     /* End of processor-specific */
+#define SHT_LOUSER       0x80000000     /* Start of application-specific */
+#define SHT_HIUSER       0x8fffffff     /* End of application-specific */
+
+/* Legal values for sh_flags (section flags).  */
+
+#define SHF_WRITE       (1 << 0)        /* Writable */
+#define SHF_ALLOC       (1 << 1)        /* Occupies memory during execution */
+#define SHF_EXECINSTR   (1 << 2)        /* Executable */
+#define SHF_MASKPROC    0xf0000000      /* Processor-specific */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word    st_name;                /* Symbol name (string tbl index) */
+  Elf32_Addr    st_value;               /* Symbol value */
+  Elf32_Word    st_size;                /* Symbol size */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* No defined meaning, 0 */
+  Elf32_Section st_shndx;               /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word    st_name;                /* Symbol name (string tbl index) */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* No defined meaning, 0 */
+  Elf64_Section st_shndx;               /* Section index */
+  Elf64_Addr    st_value;               /* Symbol value */
+  Elf64_Xword   st_size;                /* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+   every dynamic symbol.  */
+
+typedef struct
+{
+  Elf32_Half si_boundto;                /* Direct bindings, symbol bound to */
+  Elf32_Half si_flags;                  /* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+  Elf64_Half si_boundto;                /* Direct bindings, symbol bound to */
+  Elf64_Half si_flags;                  /* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto.  */
+#define SYMINFO_BT_SELF         0xffff  /* Symbol bound to self */
+#define SYMINFO_BT_PARENT       0xfffe  /* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE   0xff00  /* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags.  */
+#define SYMINFO_FLG_DIRECT      0x0001  /* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU    0x0002  /* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY        0x0004  /* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD    0x0008  /* Symbol bound to object to be lazy
+                                           loaded */
+/* Syminfo version values.  */
+#define SYMINFO_NONE            0
+#define SYMINFO_CURRENT         1
+#define SYMINFO_NUM             2
+
+
+/* Special section index.  */
+
+#define SHN_UNDEF       0               /* No section, undefined symbol.  */
+
+/* How to extract and insert information held in the st_info field.  */
+
+#define ELF32_ST_BIND(val)              (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val)              ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */
+#define ELF64_ST_BIND(val)              ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val)              ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type)       ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding).  */
+
+#define STB_LOCAL       0               /* Local symbol */
+#define STB_GLOBAL      1               /* Global symbol */
+#define STB_WEAK        2               /* Weak symbol */
+#define STB_NUM         3               /* Number of defined types.  */
+#define STB_LOOS        10              /* Start of OS-specific */
+#define STB_HIOS        12              /* End of OS-specific */
+#define STB_LOPROC      13              /* Start of processor-specific */
+#define STB_HIPROC      15              /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_NOTYPE      0               /* Symbol type is unspecified */
+#define STT_OBJECT      1               /* Symbol is a data object */
+#define STT_FUNC        2               /* Symbol is a code object */
+#define STT_SECTION     3               /* Symbol associated with a section */
+#define STT_FILE        4               /* Symbol's name is file name */
+#define STT_NUM         5               /* Number of defined types.  */
+#define STT_LOOS        11              /* Start of OS-specific */
+#define STT_HIOS        12              /* End of OS-specific */
+#define STT_LOPROC      13              /* Start of processor-specific */
+#define STT_HIPROC      15              /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+   of a symbol hash table section.  This special index value indicates
+   the end of a chain, meaning no further symbols are found in that bucket.  */
+
+#define STN_UNDEF       0               /* End of a chain.  */
+
+
+/* How to extract and insert information held in the st_other field.  */
+
+#define ELF32_ST_VISIBILITY(o)  ((o) & 0x03)
+
+/* For ELF64 the definitions are the same.  */
+#define ELF64_ST_VISIBILITY(o)  ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field.  */
+#define STV_DEFAULT     0               /* Default symbol visibility rules */
+#define STV_INTERNAL    1               /* Processor specific hidden class */
+#define STV_HIDDEN      2               /* Sym unavailable in other modules */
+#define STV_PROTECTED   3               /* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL).  */
+
+typedef struct
+{
+  Elf32_Addr    r_offset;               /* Address */
+  Elf32_Word    r_info;                 /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+   Elf64_Rela structures, so we'll leave them out until Novell (or
+   whoever) gets their act together.  */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */
+
+typedef struct
+{
+  Elf64_Addr    r_offset;               /* Address */
+  Elf64_Xword   r_info;                 /* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA).  */
+
+typedef struct
+{
+  Elf32_Addr    r_offset;               /* Address */
+  Elf32_Word    r_info;                 /* Relocation type and symbol index */
+  Elf32_Sword   r_addend;               /* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+  Elf64_Addr    r_offset;               /* Address */
+  Elf64_Xword   r_info;                 /* Relocation type and symbol index */
+  Elf64_Sxword  r_addend;               /* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field.  */
+
+#define ELF32_R_SYM(val)                ((val) >> 8)
+#define ELF32_R_TYPE(val)               ((val) & 0xff)
+#define ELF32_R_INFO(sym, type)         (((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i)                  ((i) >> 32)
+#define ELF64_R_TYPE(i)                 ((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type)          ((((Elf64_Xword)(sym)) << 32) + (type))
+
+/* Program segment header.  */
+
+typedef struct
+{
+  Elf32_Word    p_type;                 /* Segment type */
+  Elf32_Off     p_offset;               /* Segment file offset */
+  Elf32_Addr    p_vaddr;                /* Segment virtual address */
+  Elf32_Addr    p_paddr;                /* Segment physical address */
+  Elf32_Word    p_filesz;               /* Segment size in file */
+  Elf32_Word    p_memsz;                /* Segment size in memory */
+  Elf32_Word    p_flags;                /* Segment flags */
+  Elf32_Word    p_align;                /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+  Elf64_Word    p_type;                 /* Segment type */
+  Elf64_Word    p_flags;                /* Segment flags */
+  Elf64_Off     p_offset;               /* Segment file offset */
+  Elf64_Addr    p_vaddr;                /* Segment virtual address */
+  Elf64_Addr    p_paddr;                /* Segment physical address */
+  Elf64_Xword   p_filesz;               /* Segment size in file */
+  Elf64_Xword   p_memsz;                /* Segment size in memory */
+  Elf64_Xword   p_align;                /* Segment alignment */
+} Elf64_Phdr;
+
+/* Legal values for p_type (segment type).  */
+
+#define PT_NULL         0               /* Program header table entry unused */
+#define PT_LOAD         1               /* Loadable program segment */
+#define PT_DYNAMIC      2               /* Dynamic linking information */
+#define PT_INTERP       3               /* Program interpreter */
+#define PT_NOTE         4               /* Auxiliary information */
+#define PT_SHLIB        5               /* Reserved */
+#define PT_PHDR         6               /* Entry for header table itself */
+#define PT_NUM          7               /* Number of defined types.  */
+#define PT_LOOS         0x60000000      /* Start of OS-specific */
+#define PT_HIOS         0x6fffffff      /* End of OS-specific */
+#define PT_LOPROC       0x70000000      /* Start of processor-specific */
+#define PT_HIPROC       0x7fffffff      /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags).  */
+
+#define PF_X            (1 << 0)        /* Segment is executable */
+#define PF_W            (1 << 1)        /* Segment is writable */
+#define PF_R            (1 << 2)        /* Segment is readable */
+#define PF_MASKPROC     0xf0000000      /* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS     1               /* Contains copy of prstatus struct */
+#define NT_FPREGSET     2               /* Contains copy of fpregset struct */
+#define NT_PRPSINFO     3               /* Contains copy of prpsinfo struct */
+#define NT_PRXREG       4               /* Contains copy of prxregset struct */
+#define NT_PLATFORM     5               /* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV         6               /* Contains copy of auxv array */
+#define NT_GWINDOWS     7               /* Contains copy of gwindows struct */
+#define NT_PSTATUS      10              /* Contains copy of pstatus struct */
+#define NT_PSINFO       13              /* Contains copy of psinfo struct */
+#define NT_PRCRED       14              /* Contains copy of prcred struct */
+#define NT_UTSNAME      15              /* Contains copy of utsname struct */
+#define NT_LWPSTATUS    16              /* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO     17              /* Contains copy of lwpinfo struct */
+
+/* Legal values for the  note segment descriptor types for object files.  */
+
+#define NT_VERSION      1               /* Contains a version string.  */
+
+
+/* Dynamic section entry.  */
+
+typedef struct
+{
+  Elf32_Sword   d_tag;                  /* Dynamic entry type */
+  union
+    {
+      Elf32_Word d_val;                 /* Integer value */
+      Elf32_Addr d_ptr;                 /* Address value */
+    } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+  Elf64_Sxword  d_tag;                  /* Dynamic entry type */
+  union
+    {
+      Elf64_Xword d_val;                /* Integer value */
+      Elf64_Addr d_ptr;                 /* Address value */
+    } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type).  */
+
+#define DT_NULL         0               /* Marks end of dynamic section */
+#define DT_NEEDED       1               /* Name of needed library */
+#define DT_PLTRELSZ     2               /* Size in bytes of PLT relocs */
+#define DT_PLTGOT       3               /* Processor defined value */
+#define DT_HASH         4               /* Address of symbol hash table */
+#define DT_STRTAB       5               /* Address of string table */
+#define DT_SYMTAB       6               /* Address of symbol table */
+#define DT_RELA         7               /* Address of Rela relocs */
+#define DT_RELASZ       8               /* Total size of Rela relocs */
+#define DT_RELAENT      9               /* Size of one Rela reloc */
+#define DT_STRSZ        10              /* Size of string table */
+#define DT_SYMENT       11              /* Size of one symbol table entry */
+#define DT_INIT         12              /* Address of init function */
+#define DT_FINI         13              /* Address of termination function */
+#define DT_SONAME       14              /* Name of shared object */
+#define DT_RPATH        15              /* Library search path */
+#define DT_SYMBOLIC     16              /* Start symbol search here */
+#define DT_REL          17              /* Address of Rel relocs */
+#define DT_RELSZ        18              /* Total size of Rel relocs */
+#define DT_RELENT       19              /* Size of one Rel reloc */
+#define DT_PLTREL       20              /* Type of reloc in PLT */
+#define DT_DEBUG        21              /* For debugging; unspecified */
+#define DT_TEXTREL      22              /* Reloc might modify .text */
+#define DT_JMPREL       23              /* Address of PLT relocs */
+#define DT_BIND_NOW     24              /* Process relocations of object */
+#define DT_INIT_ARRAY   25              /* Array with addresses of init fct */
+#define DT_FINI_ARRAY   26              /* Array with addresses of fini fct */
+#define DT_INIT_ARRAYSZ 27              /* Size in bytes of DT_INIT_ARRAY */
+#define DT_FINI_ARRAYSZ 28              /* Size in bytes of DT_FINI_ARRAY */
+#define DT_NUM          29              /* Number used */
+#define DT_LOOS         0x60000000      /* Start of OS-specific */
+#define DT_HIOS         0x6fffffff      /* End of OS-specific */
+#define DT_LOPROC       0x70000000      /* Start of processor-specific */
+#define DT_HIPROC       0x7fffffff      /* End of processor-specific */
+#define DT_PROCNUM      DT_MIPS_NUM     /* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
+   approach.  */
+#define DT_VALRNGLO     0x6ffffd00
+#define DT_POSFLAG_1    0x6ffffdfd      /* Flags for DT_* entries, effecting
+                                           the following DT_* entry.  */
+#define DT_SYMINSZ      0x6ffffdfe      /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT     0x6ffffdff      /* Entry size of syminfo */
+#define DT_VALRNGHI     0x6ffffdff
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+   If any adjustment is made to the ELF object after it has been
+   built these entries will need to be adjusted.  */
+#define DT_ADDRRNGLO    0x6ffffe00
+#define DT_SYMINFO      0x6ffffeff      /* syminfo table */
+#define DT_ADDRRNGHI    0x6ffffeff
+
+/* The versioning entry types.  The next are defined as part of the
+   GNU extension.  */
+#define DT_VERSYM       0x6ffffff0
+
+/* These were chosen by Sun.  */
+#define DT_FLAGS_1      0x6ffffffb      /* State flags, see DF_1_* below.  */
+#define DT_VERDEF       0x6ffffffc      /* Address of version definition
+                                           table */
+#define DT_VERDEFNUM    0x6ffffffd      /* Number of version definitions */
+#define DT_VERNEED      0x6ffffffe      /* Address of table with needed
+                                           versions */
+#define DT_VERNEEDNUM   0x6fffffff      /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag)   (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+   range.  Be compatible.  */
+#define DT_AUXILIARY    0x7ffffffd      /* Shared object to load before self */
+#define DT_FILTER       0x7fffffff      /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag)     ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM     3
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+   entry in the dynamic section.  */
+#define DF_1_NOW        0x00000001      /* Set RTLD_NOW for this object.  */
+#define DF_1_GLOBAL     0x00000002      /* Set RTLD_GLOBAL for this object.  */
+#define DF_1_GROUP      0x00000004      /* Set RTLD_GROUP for this object.  */
+#define DF_1_NODELETE   0x00000008      /* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR   0x00000010      /* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST  0x00000020      /* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN     0x00000040      /* Set RTLD_NOOPEN for this object.  */
+
+/* Version definition sections.  */
+
+typedef struct
+{
+  Elf32_Half    vd_version;             /* Version revision */
+  Elf32_Half    vd_flags;               /* Version information */
+  Elf32_Half    vd_ndx;                 /* Version Index */
+  Elf32_Half    vd_cnt;                 /* Number of associated aux entries */
+  Elf32_Word    vd_hash;                /* Version name hash value */
+  Elf32_Word    vd_aux;                 /* Offset in bytes to verdaux array */
+  Elf32_Word    vd_next;                /* Offset in bytes to next verdef
+                                           entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+  Elf64_Half    vd_version;             /* Version revision */
+  Elf64_Half    vd_flags;               /* Version information */
+  Elf64_Half    vd_ndx;                 /* Version Index */
+  Elf64_Half    vd_cnt;                 /* Number of associated aux entries */
+  Elf64_Word    vd_hash;                /* Version name hash value */
+  Elf64_Word    vd_aux;                 /* Offset in bytes to verdaux array */
+  Elf64_Word    vd_next;                /* Offset in bytes to next verdef
+                                           entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision).  */
+#define VER_DEF_NONE    0               /* No version */
+#define VER_DEF_CURRENT 1               /* Current version */
+#define VER_DEF_NUM     2               /* Given version number */
+
+/* Legal values for vd_flags (version information flags).  */
+#define VER_FLG_BASE    0x1             /* Version definition of file itself */
+#define VER_FLG_WEAK    0x2             /* Weak version identifier */
+
+/* Auxialiary version information.  */
+
+typedef struct
+{
+  Elf32_Word    vda_name;               /* Version or dependency names */
+  Elf32_Word    vda_next;               /* Offset in bytes to next verdaux
+                                           entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+  Elf64_Word    vda_name;               /* Version or dependency names */
+  Elf64_Word    vda_next;               /* Offset in bytes to next verdaux
+                                           entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section.  */
+
+typedef struct
+{
+  Elf32_Half    vn_version;             /* Version of structure */
+  Elf32_Half    vn_cnt;                 /* Number of associated aux entries */
+  Elf32_Word    vn_file;                /* Offset of filename for this
+                                           dependency */
+  Elf32_Word    vn_aux;                 /* Offset in bytes to vernaux array */
+  Elf32_Word    vn_next;                /* Offset in bytes to next verneed
+                                           entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+  Elf64_Half    vn_version;             /* Version of structure */
+  Elf64_Half    vn_cnt;                 /* Number of associated aux entries */
+  Elf64_Word    vn_file;                /* Offset of filename for this
+                                           dependency */
+  Elf64_Word    vn_aux;                 /* Offset in bytes to vernaux array */
+  Elf64_Word    vn_next;                /* Offset in bytes to next verneed
+                                           entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision).  */
+#define VER_NEED_NONE    0              /* No version */
+#define VER_NEED_CURRENT 1              /* Current version */
+#define VER_NEED_NUM     2              /* Given version number */
+
+/* Auxiliary needed version information.  */
+
+typedef struct
+{
+  Elf32_Word    vna_hash;               /* Hash value of dependency name */
+  Elf32_Half    vna_flags;              /* Dependency specific information */
+  Elf32_Half    vna_other;              /* Unused */
+  Elf32_Word    vna_name;               /* Dependency name string offset */
+  Elf32_Word    vna_next;               /* Offset in bytes to next vernaux
+                                           entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+  Elf64_Word    vna_hash;               /* Hash value of dependency name */
+  Elf64_Half    vna_flags;              /* Dependency specific information */
+  Elf64_Half    vna_other;              /* Unused */
+  Elf64_Word    vna_name;               /* Dependency name string offset */
+  Elf64_Word    vna_next;               /* Offset in bytes to next vernaux
+                                           entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags.  */
+#define VER_FLG_WEAK    0x2             /* Weak version identifier */
+
+
+/* Auxiliary vector.  */
+
+/* This vector is normally only used by the program interpreter.  The
+   usual definition in an ABI supplement uses the name auxv_t.  The
+   vector is not usually defined in a standard <elf.h> file, but it
+   can't hurt.  We rename it to avoid conflicts.  The sizes of these
+   types are an arrangement between the exec server and the program
+   interpreter, so we don't fully specify them here.  */
+
+typedef struct
+{
+  int a_type;                   /* Entry type */
+  union
+    {
+      long int a_val;           /* Integer value */
+      void *a_ptr;              /* Pointer value */
+      void (*a_fcn) (void);     /* Function pointer value */
+    } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+  long int a_type;              /* Entry type */
+  union
+    {
+      long int a_val;           /* Integer value */
+      void *a_ptr;              /* Pointer value */
+      void (*a_fcn) (void);     /* Function pointer value */
+    } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type).  */
+
+#define AT_NULL         0               /* End of vector */
+#define AT_IGNORE       1               /* Entry should be ignored */
+#define AT_EXECFD       2               /* File descriptor of program */
+#define AT_PHDR         3               /* Program headers for program */
+#define AT_PHENT        4               /* Size of program header entry */
+#define AT_PHNUM        5               /* Number of program headers */
+#define AT_PAGESZ       6               /* System page size */
+#define AT_BASE         7               /* Base address of interpreter */
+#define AT_FLAGS        8               /* Flags */
+#define AT_ENTRY        9               /* Entry point of program */
+#define AT_NOTELF       10              /* Program is not ELF */
+#define AT_UID          11              /* Real uid */
+#define AT_EUID         12              /* Effective uid */
+#define AT_GID          13              /* Real gid */
+#define AT_EGID         14              /* Effective gid */
+
+/* Some more special a_type values describing the hardware.  */
+#define AT_PLATFORM     15              /* String identifying platform.  */
+#define AT_HWCAP        16              /* Machine dependent hints about
+                                           processor capabilities.  */
+
+/* This entry gives some information about the FPU initialization
+   performed by the kernel.  */
+#define AT_FPUCW        17              /* Used FPU control word.  */
+
+
+/* Note section contents.  Each entry in the note section begins with
+   a header of a fixed form.  */
+
+typedef struct
+{
+  Elf32_Word n_namesz;                  /* Length of the note's name.  */
+  Elf32_Word n_descsz;                  /* Length of the note's descriptor.  */
+  Elf32_Word n_type;                    /* Type of the note.  */
+} Elf32_Nhdr;
+
+typedef struct
+{
+  Elf64_Word n_namesz;                  /* Length of the note's name.  */
+  Elf64_Word n_descsz;                  /* Length of the note's descriptor.  */
+  Elf64_Word n_type;                    /* Type of the note.  */
+} Elf64_Nhdr;
+
+/* Known names of notes.  */
+
+/* Solaris entries in the note section have this name.  */
+#define ELF_NOTE_SOLARIS        "SUNW Solaris"
+
+/* Note entries for GNU systems have this name.  */
+#define ELF_NOTE_GNU            "GNU"
+
+
+/* Defined types of notes for Solaris.  */
+
+/* Value of descriptor (one word) is desired pagesize for the binary.  */
+#define ELF_NOTE_PAGESIZE_HINT  1
+
+
+/* Defined note types for GNU systems.  */
+
+/* ABI information.  The descriptor consists of words:
+   word 0: OS descriptor
+   word 1: major version of the ABI
+   word 2: minor version of the ABI
+   word 3: subminor version of the ABI
+*/
+#define ELF_NOTE_ABI            1
+
+/* Known OSes.  These value can appear in word 0 of an ELF_NOTE_ABI
+   note section entry.  */
+#define ELF_NOTE_OS_LINUX       0
+#define ELF_NOTE_OS_GNU         1
+#define ELF_NOTE_OS_SOLARIS2    2
+
+
+/* Motorola 68k specific definitions.  */
+
+/* m68k relocs.  */
+
+#define R_68K_NONE      0               /* No reloc */
+#define R_68K_32        1               /* Direct 32 bit  */
+#define R_68K_16        2               /* Direct 16 bit  */
+#define R_68K_8         3               /* Direct 8 bit  */
+#define R_68K_PC32      4               /* PC relative 32 bit */
+#define R_68K_PC16      5               /* PC relative 16 bit */
+#define R_68K_PC8       6               /* PC relative 8 bit */
+#define R_68K_GOT32     7               /* 32 bit PC relative GOT entry */
+#define R_68K_GOT16     8               /* 16 bit PC relative GOT entry */
+#define R_68K_GOT8      9               /* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O    10              /* 32 bit GOT offset */
+#define R_68K_GOT16O    11              /* 16 bit GOT offset */
+#define R_68K_GOT8O     12              /* 8 bit GOT offset */
+#define R_68K_PLT32     13              /* 32 bit PC relative PLT address */
+#define R_68K_PLT16     14              /* 16 bit PC relative PLT address */
+#define R_68K_PLT8      15              /* 8 bit PC relative PLT address */
+#define R_68K_PLT32O    16              /* 32 bit PLT offset */
+#define R_68K_PLT16O    17              /* 16 bit PLT offset */
+#define R_68K_PLT8O     18              /* 8 bit PLT offset */
+#define R_68K_COPY      19              /* Copy symbol at runtime */
+#define R_68K_GLOB_DAT  20              /* Create GOT entry */
+#define R_68K_JMP_SLOT  21              /* Create PLT entry */
+#define R_68K_RELATIVE  22              /* Adjust by program base */
+/* Keep this the last entry.  */
+#define R_68K_NUM       23
+
+/* Intel 80386 specific definitions.  */
+
+/* i386 relocs.  */
+
+#define R_386_NONE      0               /* No reloc */
+#define R_386_32        1               /* Direct 32 bit  */
+#define R_386_PC32      2               /* PC relative 32 bit */
+#define R_386_GOT32     3               /* 32 bit GOT entry */
+#define R_386_PLT32     4               /* 32 bit PLT address */
+#define R_386_COPY      5               /* Copy symbol at runtime */
+#define R_386_GLOB_DAT  6               /* Create GOT entry */
+#define R_386_JMP_SLOT  7               /* Create PLT entry */
+#define R_386_RELATIVE  8               /* Adjust by program base */
+#define R_386_GOTOFF    9               /* 32 bit offset to GOT */
+#define R_386_GOTPC     10              /* 32 bit PC relative offset to GOT */
+/* Keep this the last entry.  */
+#define R_386_NUM       11
+
+/* SUN SPARC specific definitions.  */
+
+/* Values for Elf64_Ehdr.e_flags.  */
+
+#define EF_SPARCV9_MM           3
+#define EF_SPARCV9_TSO          0
+#define EF_SPARCV9_PSO          1
+#define EF_SPARCV9_RMO          2
+#define EF_SPARC_EXT_MASK       0xFFFF00
+#define EF_SPARC_SUN_US1        0x000200
+#define EF_SPARC_HAL_R1         0x000400
+
+/* SPARC relocs.  */
+
+#define R_SPARC_NONE    0               /* No reloc */
+#define R_SPARC_8       1               /* Direct 8 bit */
+#define R_SPARC_16      2               /* Direct 16 bit */
+#define R_SPARC_32      3               /* Direct 32 bit */
+#define R_SPARC_DISP8   4               /* PC relative 8 bit */
+#define R_SPARC_DISP16  5               /* PC relative 16 bit */
+#define R_SPARC_DISP32  6               /* PC relative 32 bit */
+#define R_SPARC_WDISP30 7               /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22 8               /* PC relative 22 bit shifted */
+#define R_SPARC_HI22    9               /* High 22 bit */
+#define R_SPARC_22      10              /* Direct 22 bit */
+#define R_SPARC_13      11              /* Direct 13 bit */
+#define R_SPARC_LO10    12              /* Truncated 10 bit */
+#define R_SPARC_GOT10   13              /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13   14              /* 13 bit GOT entry */
+#define R_SPARC_GOT22   15              /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10    16              /* PC relative 10 bit truncated */
+#define R_SPARC_PC22    17              /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30  18              /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY    19              /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20             /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21             /* Create PLT entry */
+#define R_SPARC_RELATIVE 22             /* Adjust by program base */
+#define R_SPARC_UA32    23              /* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs.  */
+
+#define R_SPARC_PLT32   24              /* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22 25              /* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10 26              /* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32 27              /* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22 28              /* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10 29              /* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10      30              /* Direct 10 bit */
+#define R_SPARC_11      31              /* Direct 11 bit */
+#define R_SPARC_64      32              /* Direct 64 bit */
+#define R_SPARC_OLO10   33              /* ?? */
+#define R_SPARC_HH22    34              /* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10    35              /* High middle 10 bits of ... */
+#define R_SPARC_LM22    36              /* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22 37              /* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10 38              /* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22 39              /* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16 40              /* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19 41              /* PC relative 19 bit shifted */
+#define R_SPARC_7       43              /* Direct 7 bit */
+#define R_SPARC_5       44              /* Direct 5 bit */
+#define R_SPARC_6       45              /* Direct 6 bit */
+#define R_SPARC_DISP64  46              /* PC relative 64 bit */
+#define R_SPARC_PLT64   47              /* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22   48              /* High 22 bit complemented */
+#define R_SPARC_LOX10   49              /* Truncated 11 bit complemented */
+#define R_SPARC_H44     50              /* Direct high 12 of 44 bit */
+#define R_SPARC_M44     51              /* Direct mid 22 of 44 bit */
+#define R_SPARC_L44     52              /* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER 53             /* Global register usage */
+#define R_SPARC_UA64    54              /* Direct 64 bit unaligned */
+#define R_SPARC_UA16    55              /* Direct 16 bit unaligned */
+/* Keep this the last entry.  */
+#define R_SPARC_NUM     56
+
+/* AMD x86-64 relocations.  */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
+#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
+#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
+#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
+					   to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
+					   to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
+#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
+					   to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
+
+#define R_X86_64_NUM		24
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM    2
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH       1       /* The cpu supports flush insn.  */
+#define HWCAP_SPARC_STBAR       2
+#define HWCAP_SPARC_SWAP        4
+#define HWCAP_SPARC_MULDIV      8
+#define HWCAP_SPARC_V9          16      /* The cpu is v9, so v8plus is ok.  */
+
+/* MIPS R3000 specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_MIPS_NOREORDER   1           /* A .noreorder directive was used */
+#define EF_MIPS_PIC         2           /* Contains PIC code */
+#define EF_MIPS_CPIC        4           /* Uses PIC calling sequence */
+#define EF_MIPS_XGOT        8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2        32
+#define EF_MIPS_ABI_ON32    64
+#define EF_MIPS_ARCH        0xf0000000  /* MIPS architecture level */
+
+/* Legal values for MIPS architecture level.  */
+
+#define EF_MIPS_ARCH_1      0x00000000  /* -mips1 code.  */
+#define EF_MIPS_ARCH_2      0x10000000  /* -mips2 code.  */
+#define EF_MIPS_ARCH_3      0x20000000  /* -mips3 code.  */
+#define EF_MIPS_ARCH_4      0x30000000  /* -mips4 code.  */
+#define EF_MIPS_ARCH_5      0x40000000  /* -mips5 code.  */
+
+/* The following are non-official names and should not be used.  */
+
+#define E_MIPS_ARCH_1     0x00000000    /* -mips1 code.  */
+#define E_MIPS_ARCH_2     0x10000000    /* -mips2 code.  */
+#define E_MIPS_ARCH_3     0x20000000    /* -mips3 code.  */
+#define E_MIPS_ARCH_4     0x30000000    /* -mips4 code.  */
+#define E_MIPS_ARCH_5     0x40000000    /* -mips5 code.  */
+
+/* Special section indices.  */
+
+#define SHN_MIPS_ACOMMON 0xff00         /* Allocated common symbols */
+#define SHN_MIPS_TEXT    0xff01         /* Allocated test symbols.  */
+#define SHN_MIPS_DATA    0xff02         /* Allocated data symbols.  */
+#define SHN_MIPS_SCOMMON 0xff03         /* Small common symbols */
+#define SHN_MIPS_SUNDEFINED 0xff04      /* Small undefined symbols */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */
+#define SHT_MIPS_MSYM          0x70000001
+#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */
+#define SHT_MIPS_GPTAB         0x70000003 /* Global data area sizes */
+#define SHT_MIPS_UCODE         0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG         0x70000005 /* MIPS ECOFF debugging information*/
+#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */
+#define SHT_MIPS_PACKAGE       0x70000007
+#define SHT_MIPS_PACKSYM       0x70000008
+#define SHT_MIPS_RELD          0x70000009
+#define SHT_MIPS_IFACE         0x7000000b
+#define SHT_MIPS_CONTENT       0x7000000c
+#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */
+#define SHT_MIPS_SHDR          0x70000010
+#define SHT_MIPS_FDESC         0x70000011
+#define SHT_MIPS_EXTSYM        0x70000012
+#define SHT_MIPS_DENSE         0x70000013
+#define SHT_MIPS_PDESC         0x70000014
+#define SHT_MIPS_LOCSYM        0x70000015
+#define SHT_MIPS_AUXSYM        0x70000016
+#define SHT_MIPS_OPTSYM        0x70000017
+#define SHT_MIPS_LOCSTR        0x70000018
+#define SHT_MIPS_LINE          0x70000019
+#define SHT_MIPS_RFDESC        0x7000001a
+#define SHT_MIPS_DELTASYM      0x7000001b
+#define SHT_MIPS_DELTAINST     0x7000001c
+#define SHT_MIPS_DELTACLASS    0x7000001d
+#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */
+#define SHT_MIPS_DELTADECL     0x7000001f
+#define SHT_MIPS_SYMBOL_LIB    0x70000020
+#define SHT_MIPS_EVENTS        0x70000021 /* Event section.  */
+#define SHT_MIPS_TRANSLATE     0x70000022
+#define SHT_MIPS_PIXIE         0x70000023
+#define SHT_MIPS_XLATE         0x70000024
+#define SHT_MIPS_XLATE_DEBUG   0x70000025
+#define SHT_MIPS_WHIRL         0x70000026
+#define SHT_MIPS_EH_REGION     0x70000027
+#define SHT_MIPS_XLATE_OLD     0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_MIPS_GPREL   0x10000000     /* Must be part of global data area */
+#define SHF_MIPS_MERGE   0x20000000
+#define SHF_MIPS_ADDR    0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL   0x04000000
+#define SHF_MIPS_NAMES   0x02000000
+#define SHF_MIPS_NODUPE  0x01000000
+
+
+/* Symbol tables.  */
+
+/* MIPS specific values for `st_other'.  */
+#define STO_MIPS_DEFAULT                0x0
+#define STO_MIPS_INTERNAL               0x1
+#define STO_MIPS_HIDDEN                 0x2
+#define STO_MIPS_PROTECTED              0x3
+#define STO_MIPS_SC_ALIGN_UNUSED        0xff
+
+/* MIPS specific values for `st_info'.  */
+#define STB_MIPS_SPLIT_COMMON           13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB.  */
+
+typedef union
+{
+  struct
+    {
+      Elf32_Word gt_current_g_value;    /* -G value used for compilation */
+      Elf32_Word gt_unused;             /* Not used */
+    } gt_header;                        /* First entry in section */
+  struct
+    {
+      Elf32_Word gt_g_value;            /* If this value were used for -G */
+      Elf32_Word gt_bytes;              /* This many bytes would be used */
+    } gt_entry;                         /* Subsequent entries in section */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO.  */
+
+typedef struct
+{
+  Elf32_Word    ri_gprmask;             /* General registers used */
+  Elf32_Word    ri_cprmask[4];          /* Coprocessor registers used */
+  Elf32_Sword   ri_gp_value;            /* $gp register value */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS.  */
+
+typedef struct
+{
+  unsigned char kind;           /* Determines interpretation of the
+                                   variable part of descriptor.  */
+  unsigned char size;           /* Size of descriptor, including header.  */
+  Elf32_Section section;        /* Section header index of section affected,
+                                   0 for global options.  */
+  Elf32_Word info;              /* Kind-specific information.  */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options.  */
+
+#define ODK_NULL        0       /* Undefined.  */
+#define ODK_REGINFO     1       /* Register usage information.  */
+#define ODK_EXCEPTIONS  2       /* Exception processing options.  */
+#define ODK_PAD         3       /* Section padding options.  */
+#define ODK_HWPATCH     4       /* Hardware workarounds performed */
+#define ODK_FILL        5       /* record the fill value used by the linker. */
+#define ODK_TAGS        6       /* reserve space for desktop tools to write. */
+#define ODK_HWAND       7       /* HW workarounds.  'AND' bits when merging. */
+#define ODK_HWOR        8       /* HW workarounds.  'OR' bits when merging.  */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */
+
+#define OEX_FPU_MIN     0x1f    /* FPE's which MUST be enabled.  */
+#define OEX_FPU_MAX     0x1f00  /* FPE's which MAY be enabled.  */
+#define OEX_PAGE0       0x10000 /* page zero must be mapped.  */
+#define OEX_SMM         0x20000 /* Force sequential memory mode?  */
+#define OEX_FPDBUG      0x40000 /* Force floating point debug mode?  */
+#define OEX_PRECISEFP   OEX_FPDBUG
+#define OEX_DISMISS     0x80000 /* Dismiss invalid address faults?  */
+
+#define OEX_FPU_INVAL   0x10
+#define OEX_FPU_DIV0    0x08
+#define OEX_FPU_OFLO    0x04
+#define OEX_FPU_UFLO    0x02
+#define OEX_FPU_INEX    0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */
+
+#define OHW_R4KEOP      0x1     /* R4000 end-of-page patch.  */
+#define OHW_R8KPFETCH   0x2     /* may need R8000 prefetch patch.  */
+#define OHW_R5KEOP      0x4     /* R5000 end-of-page patch.  */
+#define OHW_R5KCVTL     0x8     /* R5000 cvt.[ds].l bug.  clean=1.  */
+
+#define OPAD_PREFIX     0x1
+#define OPAD_POSTFIX    0x2
+#define OPAD_SYMBOL     0x4
+
+/* Entry found in `.options' section.  */
+
+typedef struct
+{
+  Elf32_Word hwp_flags1;        /* Extra flags.  */
+  Elf32_Word hwp_flags2;        /* Extra flags.  */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */
+
+#define OHWA0_R4KEOP_CHECKED    0x00000001
+#define OHWA1_R4KEOP_CLEAN      0x00000002
+
+/* MIPS relocs.  */
+
+#define R_MIPS_NONE             0       /* No reloc */
+#define R_MIPS_16               1       /* Direct 16 bit */
+#define R_MIPS_32               2       /* Direct 32 bit */
+#define R_MIPS_REL32            3       /* PC relative 32 bit */
+#define R_MIPS_26               4       /* Direct 26 bit shifted */
+#define R_MIPS_HI16             5       /* High 16 bit */
+#define R_MIPS_LO16             6       /* Low 16 bit */
+#define R_MIPS_GPREL16          7       /* GP relative 16 bit */
+#define R_MIPS_LITERAL          8       /* 16 bit literal entry */
+#define R_MIPS_GOT16            9       /* 16 bit GOT entry */
+#define R_MIPS_PC16             10      /* PC relative 16 bit */
+#define R_MIPS_CALL16           11      /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32          12      /* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5           16
+#define R_MIPS_SHIFT6           17
+#define R_MIPS_64               18
+#define R_MIPS_GOT_DISP         19
+#define R_MIPS_GOT_PAGE         20
+#define R_MIPS_GOT_OFST         21
+#define R_MIPS_GOT_HI16         22
+#define R_MIPS_GOT_LO16         23
+#define R_MIPS_SUB              24
+#define R_MIPS_INSERT_A         25
+#define R_MIPS_INSERT_B         26
+#define R_MIPS_DELETE           27
+#define R_MIPS_HIGHER           28
+#define R_MIPS_HIGHEST          29
+#define R_MIPS_CALL_HI16        30
+#define R_MIPS_CALL_LO16        31
+#define R_MIPS_SCN_DISP         32
+#define R_MIPS_REL16            33
+#define R_MIPS_ADD_IMMEDIATE    34
+#define R_MIPS_PJUMP            35
+#define R_MIPS_RELGOT           36
+#define R_MIPS_JALR             37
+/* Keep this the last entry.  */
+#define R_MIPS_NUM              38
+
+/* Legal values for p_type field of Elf32_Phdr.  */
+
+#define PT_MIPS_REGINFO 0x70000000      /* Register usage information */
+#define PT_MIPS_RTPROC  0x70000001      /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+
+/* Special program header types.  */
+
+#define PF_MIPS_LOCAL   0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn.  */
+
+#define DT_MIPS_RLD_VERSION  0x70000001 /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP   0x70000002 /* Timestamp */
+#define DT_MIPS_ICHECKSUM    0x70000003 /* Checksum */
+#define DT_MIPS_IVERSION     0x70000004 /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS        0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
+#define DT_MIPS_MSYM         0x70000007
+#define DT_MIPS_CONFLICT     0x70000008 /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST      0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO  0x7000000a /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO   0x7000000b /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO    0x70000010 /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO     0x70000011 /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO   0x70000012 /* First external DYNSYM */
+#define DT_MIPS_GOTSYM       0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO     0x70000014 /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP      0x70000016 /* Address of run time loader map.  */
+#define DT_MIPS_DELTA_CLASS  0x70000017 /* Delta C++ class definition.  */
+#define DT_MIPS_DELTA_CLASS_NO    0x70000018 /* Number of entries in
+                                                DT_MIPS_DELTA_CLASS.  */
+#define DT_MIPS_DELTA_INSTANCE    0x70000019 /* Delta C++ class instances.  */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+                                                DT_MIPS_DELTA_INSTANCE.  */
+#define DT_MIPS_DELTA_RELOC  0x7000001b /* Delta relocations.  */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+                                             DT_MIPS_DELTA_RELOC.  */
+#define DT_MIPS_DELTA_SYM    0x7000001d /* Delta symbols that Delta
+                                           relocations refer to.  */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+                                           DT_MIPS_DELTA_SYM.  */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+                                             class declaration.  */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+                                                DT_MIPS_DELTA_CLASSSYM.  */
+#define DT_MIPS_CXX_FLAGS    0x70000022 /* Flags indicating for C++ flavor.  */
+#define DT_MIPS_PIXIE_INIT   0x70000023
+#define DT_MIPS_SYMBOL_LIB   0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS      0x70000029 /* Address of .options.  */
+#define DT_MIPS_INTERFACE    0x7000002a /* Address of .interface.  */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+                                                    function stored in GOT.  */
+#define DT_MIPS_PERF_SUFFIX  0x7000002e /* Default suffix of dso to be added
+                                           by rld on dlopen() calls.  */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
+#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
+#define DT_MIPS_NUM          0x32
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
+
+#define RHF_NONE                   0            /* No flags */
+#define RHF_QUICKSTART             (1 << 0)     /* Use quickstart */
+#define RHF_NOTPOT                 (1 << 1)     /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2)     /* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE                (1 << 3)
+#define RHF_SGI_ONLY               (1 << 4)
+#define RHF_GUARANTEE_INIT         (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS      (1 << 6)
+#define RHF_GUARANTEE_START_INIT   (1 << 7)
+#define RHF_PIXIE                  (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD     (1 << 9)
+#define RHF_REQUICKSTART           (1 << 10)
+#define RHF_REQUICKSTARTED         (1 << 11)
+#define RHF_CORD                   (1 << 12)
+#define RHF_NO_UNRES_UNDEF         (1 << 13)
+#define RHF_RLD_ORDER_SAFE         (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST.  */
+
+typedef struct
+{
+  Elf32_Word l_name;            /* Name (string table index) */
+  Elf32_Word l_time_stamp;      /* Timestamp */
+  Elf32_Word l_checksum;        /* Checksum */
+  Elf32_Word l_version;         /* Interface version */
+  Elf32_Word l_flags;           /* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+  Elf64_Word l_name;            /* Name (string table index) */
+  Elf64_Word l_time_stamp;      /* Timestamp */
+  Elf64_Word l_checksum;        /* Checksum */
+  Elf64_Word l_version;         /* Interface version */
+  Elf64_Word l_flags;           /* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags.  */
+
+#define LL_NONE           0
+#define LL_EXACT_MATCH    (1 << 0)      /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1)      /* Ignore interface version */
+#define LL_REQUIRE_MINOR  (1 << 2)
+#define LL_EXPORTS        (1 << 3)
+#define LL_DELAY_LOAD     (1 << 4)
+#define LL_DELTA          (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT.  */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNL        1       /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT           2       /* Program uses arch. extensions.  */
+#define EF_PARISC_ARCH          0xffff0000 /* Architecture version.  */
+/* Defined values are:
+                                0x020b  PA-RISC 1.0 big-endian
+                                0x0210  PA-RISC 1.1 big-endian
+                                0x028b  PA-RISC 1.0 little-endian
+                                0x0290  PA-RISC 1.1 little-endian
+*/
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_GOT          0x70000000 /* GOT for external data.  */
+#define SHT_PARISC_ARCH         0x70000001 /* Architecture extensions.  */
+#define SHT_PARISC_GLOBAL       0x70000002 /* Definition of $global$.  */
+#define SHT_PARISC_MILLI        0x70000003 /* Millicode routines.  */
+#define SHT_PARISC_UNWIND       0x70000004 /* Unwind information.  */
+#define SHT_PARISC_PLT          0x70000005 /* Procedure linkage table.  */
+#define SHT_PARISC_SDATA        0x70000006 /* Short initialized data.  */
+#define SHT_PARISC_SBSS         0x70000007 /* Short uninitialized data.  */
+#define SHT_PARISC_SYMEXTN      0x70000008 /* Argument/relocation info.  */
+#define SHT_PARISC_STUBS        0x70000009 /* Linker stubs.  */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_GLOBAL       0x10000000 /* Section defines dp.  */
+#define SHF_PARISC_SHORT        0x20000000 /* Section with short addressing. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE    13      /* Millicode function entry point.  */
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE           0       /* No reloc.  */
+#define R_PARISC_DIR32          1       /* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L         2       /* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R         3       /* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR14R         4       /* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL21L       5       /* PC-relative, left 21 bits.  */
+#define R_PARISC_PCREL14R       6       /* PC-relative, right 14 bits.  */
+#define R_PARISC_PCREL17C       7       /* Conditional PC-relative, ignore
+                                           if displacement > 17bits.  */
+#define R_PARISC_PCREL17F       8       /* Conditional PC-relative, must
+                                           fit in 17bits.  */
+#define R_PARISC_DPREL21L       9       /* DP-relative, left 21 bits.  */
+#define R_PARISC_DPREL14R       10      /* DP-relative, right 14 bits.  */
+#define R_PARISC_DPREL14F       11      /* DP-relative, must bit in 14 bits. */
+#define R_PARISC_DLTREL21L      12      /* DLT-relative, left 21 bits.  */
+#define R_PARISC_DLTREL14R      13      /* DLT-relative, right 14 bits.  */
+#define R_PARISC_DLTREL14F      14      /* DLT-relative, must fit in 14 bits.*/
+#define R_PARISC_DLTIND21L      15      /* DLT-relative indirect, left
+                                           21 bits.  */
+#define R_PARISC_DLTIND14R      16      /* DLT-relative indirect, right
+                                           14 bits.  */
+#define R_PARISC_DLTIND14F      17      /* DLT-relative indirect, must fit
+                                           int 14 bits.  */
+#define R_PARISC_PLABEL32       18      /* Direct 32-bit reference to proc.  */
+
+/* Alpha specific definitions.  */
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT          1       /* All addresses must be < 2GB.  */
+#define EF_ALPHA_CANRELAX       2       /* Relocations for relaxing exist.  */
+
+/* Legal values for sh_type field of Elf64_Shdr.  */
+
+/* These two are primerily concerned with ECOFF debugging info.  */
+#define SHT_ALPHA_DEBUG         0x70000001
+#define SHT_ALPHA_REGINFO       0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr.  */
+
+#define SHF_ALPHA_GPREL         0x10000000
+
+/* Legal values for st_other field of Elf64_Sym.  */
+#define STO_ALPHA_NOPV          0x80    /* No PV required.  */
+#define STO_ALPHA_STD_GPLOAD    0x88    /* PV only used for initial ldgp.  */
+
+/* Alpha relocs.  */
+
+#define R_ALPHA_NONE            0       /* No reloc */
+#define R_ALPHA_REFLONG         1       /* Direct 32 bit */
+#define R_ALPHA_REFQUAD         2       /* Direct 64 bit */
+#define R_ALPHA_GPREL32         3       /* GP relative 32 bit */
+#define R_ALPHA_LITERAL         4       /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE          5       /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP          6       /* Add displacement to GP */
+#define R_ALPHA_BRADDR          7       /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT            8       /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16          9       /* PC relative 16 bit */
+#define R_ALPHA_SREL32          10      /* PC relative 32 bit */
+#define R_ALPHA_SREL64          11      /* PC relative 64 bit */
+#define R_ALPHA_OP_PUSH         12      /* OP stack push */
+#define R_ALPHA_OP_STORE        13      /* OP stack pop and store */
+#define R_ALPHA_OP_PSUB         14      /* OP stack subtract */
+#define R_ALPHA_OP_PRSHIFT      15      /* OP stack right shift */
+#define R_ALPHA_GPVALUE         16
+#define R_ALPHA_GPRELHIGH       17
+#define R_ALPHA_GPRELLOW        18
+#define R_ALPHA_IMMED_GP_16     19
+#define R_ALPHA_IMMED_GP_HI32   20
+#define R_ALPHA_IMMED_SCN_HI32  21
+#define R_ALPHA_IMMED_BR_HI32   22
+#define R_ALPHA_IMMED_LO32      23
+#define R_ALPHA_COPY            24      /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT        25      /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT        26      /* Create PLT entry */
+#define R_ALPHA_RELATIVE        27      /* Adjust by program base */
+/* Keep this the last entry.  */
+#define R_ALPHA_NUM             28
+
+
+/* PowerPC specific declarations */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE              0
+#define R_PPC_ADDR32            1       /* 32bit absolute address */
+#define R_PPC_ADDR24            2       /* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16            3       /* 16bit absolute address */
+#define R_PPC_ADDR16_LO         4       /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI         5       /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA         6       /* adjusted high 16bit */
+#define R_PPC_ADDR14            7       /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN    8
+#define R_PPC_ADDR14_BRNTAKEN   9
+#define R_PPC_REL24             10      /* PC relative 26 bit */
+#define R_PPC_REL14             11      /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN     12
+#define R_PPC_REL14_BRNTAKEN    13
+#define R_PPC_GOT16             14
+#define R_PPC_GOT16_LO          15
+#define R_PPC_GOT16_HI          16
+#define R_PPC_GOT16_HA          17
+#define R_PPC_PLTREL24          18
+#define R_PPC_COPY              19
+#define R_PPC_GLOB_DAT          20
+#define R_PPC_JMP_SLOT          21
+#define R_PPC_RELATIVE          22
+#define R_PPC_LOCAL24PC         23
+#define R_PPC_UADDR32           24
+#define R_PPC_UADDR16           25
+#define R_PPC_REL32             26
+#define R_PPC_PLT32             27
+#define R_PPC_PLTREL32          28
+#define R_PPC_PLT16_LO          29
+#define R_PPC_PLT16_HI          30
+#define R_PPC_PLT16_HA          31
+#define R_PPC_SDAREL16          32
+#define R_PPC_SECTOFF           33
+#define R_PPC_SECTOFF_LO        34
+#define R_PPC_SECTOFF_HI        35
+#define R_PPC_SECTOFF_HA        36
+/* Keep this the last entry.  */
+#define R_PPC_NUM               37
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+   in the SVR4 ELF ABI.  */
+#define R_PPC_EMB_NADDR32       101
+#define R_PPC_EMB_NADDR16       102
+#define R_PPC_EMB_NADDR16_LO    103
+#define R_PPC_EMB_NADDR16_HI    104
+#define R_PPC_EMB_NADDR16_HA    105
+#define R_PPC_EMB_SDAI16        106
+#define R_PPC_EMB_SDA2I16       107
+#define R_PPC_EMB_SDA2REL       108
+#define R_PPC_EMB_SDA21         109     /* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF        110
+#define R_PPC_EMB_RELSEC16      111
+#define R_PPC_EMB_RELST_LO      112
+#define R_PPC_EMB_RELST_HI      113
+#define R_PPC_EMB_RELST_HA      114
+#define R_PPC_EMB_BIT_FLD       115
+#define R_PPC_EMB_RELSDA        116     /* 16 bit relative offset in SDA */
+
+/* Diab tool relocations.  */
+#define R_PPC_DIAB_SDA21_LO     180     /* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI     181     /* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA     182     /* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO    183     /* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI    184     /* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA    185     /* like EMB_RELSDA, adjusted high 16 */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+   that may still be in object files.  */
+#define R_PPC_TOC16             255
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_ARM_RELEXEC     0x01
+#define EF_ARM_HASENTRY    0x02
+#define EF_ARM_INTERWORK   0x04
+#define EF_ARM_APCS_26     0x08
+#define EF_ARM_APCS_FLOAT  0x10
+#define EF_ARM_PIC         0x20
+#define EF_ALIGN8          0x40         /* 8-bit structure alignment is in use */
+#define EF_NEW_ABI         0x80
+#define EF_OLD_ABI         0x100
+
+/* Additional symbol types for Thumb */
+#define STT_ARM_TFUNC      0xd
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT  0x10000000   /* Section contains an entry point */
+#define SHF_ARM_COMDEF     0x80000000   /* Section may be multiply defined
+                                           in the input to a link step */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB          0x10000000   /* Segment contains the location
+                                           addressed by the static base */
+
+/* ARM relocs.  */
+#define R_ARM_NONE              0       /* No reloc */
+#define R_ARM_PC24              1       /* PC relative 26 bit branch */
+#define R_ARM_ABS32             2       /* Direct 32 bit  */
+#define R_ARM_REL32             3       /* PC relative 32 bit */
+#define R_ARM_PC13              4
+#define R_ARM_ABS16             5       /* Direct 16 bit */
+#define R_ARM_ABS12             6       /* Direct 12 bit */
+#define R_ARM_THM_ABS5          7
+#define R_ARM_ABS8              8       /* Direct 8 bit */
+#define R_ARM_SBREL32           9
+#define R_ARM_THM_PC22          10
+#define R_ARM_THM_PC8           11
+#define R_ARM_AMP_VCALL9        12
+#define R_ARM_SWI24             13
+#define R_ARM_THM_SWI8          14
+#define R_ARM_XPC25             15
+#define R_ARM_THM_XPC22         16
+#define R_ARM_COPY              20      /* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT          21      /* Create GOT entry */
+#define R_ARM_JUMP_SLOT         22      /* Create PLT entry */
+#define R_ARM_RELATIVE          23      /* Adjust by program base */
+#define R_ARM_GOTOFF32          24      /* 32 bit offset to GOT */
+#define R_ARM_BASE_PREL         25      /* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT_BREL          26      /* 32 bit GOT entry */
+#define R_ARM_PLT32             27      /* 32 bit PLT address */
+#define R_ARM_CALL              28
+#define R_ARM_JUMP24            29
+#define R_ARM_PREL31            42
+#define R_ARM_GNU_VTENTRY       100
+#define R_ARM_GNU_VTINHERIT     101
+#define R_ARM_THM_PC11          102     /* thumb unconditional branch */
+#define R_ARM_THM_PC9           103     /* thumb conditional branch */
+#define R_ARM_RXPC25            249
+#define R_ARM_RSBREL32          250
+#define R_ARM_THM_RPC22         251
+#define R_ARM_RREL32            252
+#define R_ARM_RABS22            253
+#define R_ARM_RPC24             254
+#define R_ARM_RBASE             255
+/* Keep this the last entry.  */
+#define R_ARM_NUM               256
+
+/* TMS320C67xx specific declarations */
+/* XXX: no ELF standard yet */
+
+/* TMS320C67xx relocs. */
+#define R_C60_32       1
+#define R_C60_GOT32     3               /* 32 bit GOT entry */
+#define R_C60_PLT32     4               /* 32 bit PLT address */
+#define R_C60_COPY      5               /* Copy symbol at runtime */
+#define R_C60_GLOB_DAT  6               /* Create GOT entry */
+#define R_C60_JMP_SLOT  7               /* Create PLT entry */
+#define R_C60_RELATIVE  8               /* Adjust by program base */
+#define R_C60_GOTOFF    9               /* 32 bit offset to GOT */
+#define R_C60_GOTPC     10              /* 32 bit PC relative offset to GOT */
+
+#define R_C60HI16      0x55       // high 16 bit MVKH embedded
+#define R_C60LO16      0x54       // low 16 bit MVKL embedded
+
+#ifdef TCC_TARGET_X86_64
+#define TCC_ELFCLASS ELFCLASS64
+#define ElfW(type) Elf##64##_##type
+#define ELFW(type) ELF##64##_##type
+#else
+#define TCC_ELFCLASS ELFCLASS32
+#define ElfW(type) Elf##32##_##type
+#define ELFW(type) ELF##32##_##type
+#endif
+
+#endif  /* elf.h */
diff --git a/tinyc/examples/ex1.c b/tinyc/examples/ex1.c
new file mode 100644
index 000000000..28139f92e
--- /dev/null
+++ b/tinyc/examples/ex1.c
@@ -0,0 +1,8 @@
+#! /usr/local/bin/tcc -run
+#include <tcclib.h>
+
+int main()
+{
+    printf("Hello World\n");
+    return 0;
+}
diff --git a/tinyc/examples/ex2.c b/tinyc/examples/ex2.c
new file mode 100644
index 000000000..d415e39d7
--- /dev/null
+++ b/tinyc/examples/ex2.c
@@ -0,0 +1,98 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#define N 20
+
+int nb_num;
+int tab[N];
+int stack_ptr;
+int stack_op[N];
+int stack_res[60];
+int result;
+
+int find(int n, int i1, int a, int b, int op)
+{
+    int i, j;
+    int c;
+
+    if (stack_ptr >= 0) {
+        stack_res[3*stack_ptr] = a;
+        stack_op[stack_ptr] = op;
+        stack_res[3*stack_ptr+1] = b;
+        stack_res[3*stack_ptr+2] = n;
+        if (n == result)
+            return 1;
+        tab[i1] = n;
+    }
+
+    for(i=0;i<nb_num;i++) {
+        for(j=i+1;j<nb_num;j++) {
+            a = tab[i];
+            b = tab[j];
+            if (a != 0 && b != 0) {
+
+                tab[j] = 0;
+                stack_ptr++;
+
+                if (find(a + b, i, a, b, '+'))
+                    return 1;
+                if (find(a - b, i, a, b, '-'))
+                    return 1;
+                if (find(b - a, i, b, a, '-'))
+                    return 1;
+                if (find(a * b, i, a, b, '*'))
+                    return 1;
+                if (b != 0) {
+                    c = a / b;
+                    if (find(c, i, a, b, '/'))
+                        return 1;
+                }
+
+                if (a != 0) {
+                    c = b / a;
+                    if (find(c, i, b, a, '/'))
+                        return 1;
+                }
+
+                stack_ptr--;
+                tab[i] = a;
+                tab[j] = b;
+            }
+        }
+    }
+
+    return 0;
+}
+
+int main(int argc, char **argv)
+{
+    int i, res, p;
+
+    if (argc < 3) {
+        printf("usage: %s: result numbers...\n"
+               "Try to find result from numbers with the 4 basic operations.\n", argv[0]);
+        exit(1);
+    }
+
+    p = 1;
+    result = atoi(argv[p]);
+    printf("result=%d\n", result);
+    nb_num = 0;
+    for(i=p+1;i<argc;i++) {
+        tab[nb_num++] = atoi(argv[i]);
+    }
+
+    stack_ptr = -1;
+    res = find(0, 0, 0, 0, ' ');
+    if (res) {
+        for(i=0;i<=stack_ptr;i++) {
+            printf("%d %c %d = %d\n",
+                   stack_res[3*i], stack_op[i],
+                   stack_res[3*i+1], stack_res[3*i+2]);
+        }
+        return 0;
+    } else {
+        printf("Impossible\n");
+        return 1;
+    }
+}
diff --git a/tinyc/examples/ex3.c b/tinyc/examples/ex3.c
new file mode 100644
index 000000000..7c466ad54
--- /dev/null
+++ b/tinyc/examples/ex3.c
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int fib(n)
+{
+    if (n <= 2)
+        return 1;
+    else
+        return fib(n-1) + fib(n-2);
+}
+
+int main(int argc, char **argv)
+{
+    int n;
+    if (argc < 2) {
+        printf("usage: fib n\n"
+               "Compute nth Fibonacci number\n");
+        return 1;
+    }
+
+    n = atoi(argv[1]);
+    printf("fib(%d) = %d\n", n, fib(n, 2));
+    return 0;
+}
diff --git a/tinyc/examples/ex4.c b/tinyc/examples/ex4.c
new file mode 100644
index 000000000..b33b0331d
--- /dev/null
+++ b/tinyc/examples/ex4.c
@@ -0,0 +1,26 @@
+#!./tcc -run -L/usr/X11R6/lib -lX11
+#include <stdlib.h>
+#include <stdio.h>
+#include <X11/Xlib.h>
+
+/* Yes, TCC can use X11 too ! */
+
+int main(int argc, char **argv)
+{
+    Display *display;
+    Screen *screen;
+
+    display = XOpenDisplay("");
+    if (!display) {
+        fprintf(stderr, "Could not open X11 display\n");
+        exit(1);
+    }
+    printf("X11 display opened.\n");
+    screen = XScreenOfDisplay(display, 0);
+    printf("width = %d\nheight = %d\ndepth = %d\n",
+           screen->width,
+           screen->height,
+           screen->root_depth);
+    XCloseDisplay(display);
+    return 0;
+}
diff --git a/tinyc/examples/ex5.c b/tinyc/examples/ex5.c
new file mode 100644
index 000000000..156425e39
--- /dev/null
+++ b/tinyc/examples/ex5.c
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main()
+{
+    printf("Hello World\n");
+    return 0;
+}
diff --git a/tinyc/i386-asm.c b/tinyc/i386-asm.c
new file mode 100644
index 000000000..12ff8f2ba
--- /dev/null
+++ b/tinyc/i386-asm.c
@@ -0,0 +1,1211 @@
+/*
+ *  i386 specific functions for TCC assembler
+ * 
+ *  Copyright (c) 2001, 2002 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#define MAX_OPERANDS 3
+
+typedef struct ASMInstr {
+    uint16_t sym;
+    uint16_t opcode;
+    uint16_t instr_type;
+#define OPC_JMP       0x01  /* jmp operand */
+#define OPC_B         0x02  /* only used zith OPC_WL */
+#define OPC_WL        0x04  /* accepts w, l or no suffix */
+#define OPC_BWL       (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
+#define OPC_REG       0x08 /* register is added to opcode */
+#define OPC_MODRM     0x10 /* modrm encoding */
+#define OPC_FWAIT     0x20 /* add fwait opcode */
+#define OPC_TEST      0x40 /* test opcodes */
+#define OPC_SHIFT     0x80 /* shift opcodes */
+#define OPC_D16      0x0100 /* generate data16 prefix */
+#define OPC_ARITH    0x0200 /* arithmetic opcodes */
+#define OPC_SHORTJMP 0x0400 /* short jmp operand */
+#define OPC_FARITH   0x0800 /* FPU arithmetic opcodes */
+#define OPC_GROUP_SHIFT 13
+
+/* in order to compress the operand type, we use specific operands and
+   we or only with EA  */ 
+#define OPT_REG8  0 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_REG16 1 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_REG32 2 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_MMX   3 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_SSE   4 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_CR    5 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_TR    6 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_DB    7 /* warning: value is hardcoded from TOK_ASM_xxx */
+#define OPT_SEG   8
+#define OPT_ST    9
+#define OPT_IM8   10
+#define OPT_IM8S  11
+#define OPT_IM16  12
+#define OPT_IM32  13
+#define OPT_EAX   14 /* %al, %ax or %eax register */
+#define OPT_ST0   15 /* %st(0) register */
+#define OPT_CL    16 /* %cl register */
+#define OPT_DX    17 /* %dx register */
+#define OPT_ADDR  18 /* OP_EA with only offset */
+#define OPT_INDIR 19 /* *(expr) */
+
+/* composite types */ 
+#define OPT_COMPOSITE_FIRST   20
+#define OPT_IM       20 /* IM8 | IM16 | IM32 */
+#define OPT_REG      21 /* REG8 | REG16 | REG32 */ 
+#define OPT_REGW     22 /* REG16 | REG32 */
+#define OPT_IMW      23 /* IM16 | IM32 */ 
+
+/* can be ored with any OPT_xxx */
+#define OPT_EA    0x80
+
+    uint8_t nb_ops;
+    uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */
+} ASMInstr;
+
+typedef struct Operand {
+    uint32_t type;
+#define OP_REG8   (1 << OPT_REG8)
+#define OP_REG16  (1 << OPT_REG16)
+#define OP_REG32  (1 << OPT_REG32)
+#define OP_MMX    (1 << OPT_MMX)
+#define OP_SSE    (1 << OPT_SSE)
+#define OP_CR     (1 << OPT_CR)
+#define OP_TR     (1 << OPT_TR)
+#define OP_DB     (1 << OPT_DB)
+#define OP_SEG    (1 << OPT_SEG)
+#define OP_ST     (1 << OPT_ST)
+#define OP_IM8    (1 << OPT_IM8)
+#define OP_IM8S   (1 << OPT_IM8S)
+#define OP_IM16   (1 << OPT_IM16)
+#define OP_IM32   (1 << OPT_IM32)
+#define OP_EAX    (1 << OPT_EAX)
+#define OP_ST0    (1 << OPT_ST0)
+#define OP_CL     (1 << OPT_CL)
+#define OP_DX     (1 << OPT_DX)
+#define OP_ADDR   (1 << OPT_ADDR)
+#define OP_INDIR  (1 << OPT_INDIR)
+
+#define OP_EA     0x40000000
+#define OP_REG    (OP_REG8 | OP_REG16 | OP_REG32)
+#define OP_IM     OP_IM32
+    int8_t  reg; /* register, -1 if none */
+    int8_t  reg2; /* second register, -1 if none */
+    uint8_t shift;
+    ExprValue e;
+} Operand;
+
+static const uint8_t reg_to_size[5] = {
+/*
+    [OP_REG8] = 0,
+    [OP_REG16] = 1,
+    [OP_REG32] = 2,
+*/
+    0, 0, 1, 0, 2
+};
+    
+#define WORD_PREFIX_OPCODE 0x66
+
+#define NB_TEST_OPCODES 30
+
+static const uint8_t test_bits[NB_TEST_OPCODES] = {
+ 0x00, /* o */
+ 0x01, /* no */
+ 0x02, /* b */
+ 0x02, /* c */
+ 0x02, /* nae */
+ 0x03, /* nb */
+ 0x03, /* nc */
+ 0x03, /* ae */
+ 0x04, /* e */
+ 0x04, /* z */
+ 0x05, /* ne */
+ 0x05, /* nz */
+ 0x06, /* be */
+ 0x06, /* na */
+ 0x07, /* nbe */
+ 0x07, /* a */
+ 0x08, /* s */
+ 0x09, /* ns */
+ 0x0a, /* p */
+ 0x0a, /* pe */
+ 0x0b, /* np */
+ 0x0b, /* po */
+ 0x0c, /* l */
+ 0x0c, /* nge */
+ 0x0d, /* nl */
+ 0x0d, /* ge */
+ 0x0e, /* le */
+ 0x0e, /* ng */
+ 0x0f, /* nle */
+ 0x0f, /* g */
+};
+
+static const uint8_t segment_prefixes[] = {
+ 0x26, /* es */
+ 0x2e, /* cs */
+ 0x36, /* ss */
+ 0x3e, /* ds */
+ 0x64, /* fs */
+ 0x65  /* gs */
+};
+
+static const ASMInstr asm_instrs[] = {
+#define ALT(x) x
+#define DEF_ASM_OP0(name, opcode)
+#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 },
+#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},
+#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},
+#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }},
+#include "i386-asm.h"
+
+    /* last operation */
+    { 0, },
+};
+
+static const uint16_t op0_codes[] = {
+#define ALT(x)
+#define DEF_ASM_OP0(x, opcode) opcode,
+#define DEF_ASM_OP0L(name, opcode, group, instr_type)
+#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
+#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
+#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
+#include "i386-asm.h"
+};
+
+static inline int get_reg_shift(TCCState *s1)
+{
+    int shift, v;
+
+    v = asm_int_expr(s1);
+    switch(v) {
+    case 1:
+        shift = 0;
+        break;
+    case 2:
+        shift = 1;
+        break;
+    case 4:
+        shift = 2;
+        break;
+    case 8:
+        shift = 3;
+        break;
+    default:
+        expect("1, 2, 4 or 8 constant");
+        shift = 0;
+        break;
+    }
+    return shift;
+}
+
+static int asm_parse_reg(void)
+{
+    int reg;
+    if (tok != '%')
+        goto error_32;
+    next();
+    if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) {
+        reg = tok - TOK_ASM_eax;
+        next();
+        return reg;
+    } else {
+    error_32:
+        expect("32 bit register");
+        return 0;
+    }
+}
+
+static void parse_operand(TCCState *s1, Operand *op)
+{
+    ExprValue e;
+    int reg, indir;
+    const char *p;
+
+    indir = 0;
+    if (tok == '*') {
+        next();
+        indir = OP_INDIR;
+    }
+
+    if (tok == '%') {
+        next();
+        if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) {
+            reg = tok - TOK_ASM_al;
+            op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */
+            op->reg = reg & 7;
+            if ((op->type & OP_REG) && op->reg == TREG_EAX)
+                op->type |= OP_EAX;
+            else if (op->type == OP_REG8 && op->reg == TREG_ECX)
+                op->type |= OP_CL;
+            else if (op->type == OP_REG16 && op->reg == TREG_EDX)
+                op->type |= OP_DX;
+        } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) {
+            op->type = OP_DB;
+            op->reg = tok - TOK_ASM_dr0;
+        } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) {
+            op->type = OP_SEG;
+            op->reg = tok - TOK_ASM_es;
+        } else if (tok == TOK_ASM_st) {
+            op->type = OP_ST;
+            op->reg = 0;
+            next();
+            if (tok == '(') {
+                next();
+                if (tok != TOK_PPNUM)
+                    goto reg_error;
+                p = tokc.cstr->data;
+                reg = p[0] - '0';
+                if ((unsigned)reg >= 8 || p[1] != '\0')
+                    goto reg_error;
+                op->reg = reg;
+                next();
+                skip(')');
+            }
+            if (op->reg == 0)
+                op->type |= OP_ST0;
+            goto no_skip;
+        } else {
+        reg_error:
+            error("unknown register");
+        }
+        next();
+    no_skip: ;
+    } else if (tok == '$') {
+        /* constant value */
+        next();
+        asm_expr(s1, &e);
+        op->type = OP_IM32;
+        op->e.v = e.v;
+        op->e.sym = e.sym;
+        if (!op->e.sym) {
+            if (op->e.v == (uint8_t)op->e.v)
+                op->type |= OP_IM8;
+            if (op->e.v == (int8_t)op->e.v)
+                op->type |= OP_IM8S;
+            if (op->e.v == (uint16_t)op->e.v)
+                op->type |= OP_IM16;
+        }
+    } else {
+        /* address(reg,reg2,shift) with all variants */
+        op->type = OP_EA;
+        op->reg = -1;
+        op->reg2 = -1;
+        op->shift = 0;
+        if (tok != '(') {
+            asm_expr(s1, &e);
+            op->e.v = e.v;
+            op->e.sym = e.sym;
+        } else {
+            op->e.v = 0;
+            op->e.sym = NULL;
+        }
+        if (tok == '(') {
+            next();
+            if (tok != ',') {
+                op->reg = asm_parse_reg();
+            }
+            if (tok == ',') {
+                next();
+                if (tok != ',') {
+                    op->reg2 = asm_parse_reg();
+                } 
+                if (tok == ',') {
+                    next();
+                    op->shift = get_reg_shift(s1);
+                }
+            }
+            skip(')');
+        }
+        if (op->reg == -1 && op->reg2 == -1)
+            op->type |= OP_ADDR;
+    }
+    op->type |= indir;
+}
+
+/* XXX: unify with C code output ? */
+static void gen_expr32(ExprValue *pe)
+{
+    if (pe->sym)
+        greloc(cur_text_section, pe->sym, ind, R_386_32);
+    gen_le32(pe->v);
+}
+
+/* XXX: unify with C code output ? */
+static void gen_disp32(ExprValue *pe)
+{
+    Sym *sym;
+    sym = pe->sym;
+    if (sym) {
+        if (sym->r == cur_text_section->sh_num) {
+            /* same section: we can output an absolute value. Note
+               that the TCC compiler behaves differently here because
+               it always outputs a relocation to ease (future) code
+               elimination in the linker */
+            gen_le32(pe->v + (long)sym->next - ind - 4);
+        } else {
+            greloc(cur_text_section, sym, ind, R_386_PC32);
+            gen_le32(pe->v - 4);
+        }
+    } else {
+        /* put an empty PC32 relocation */
+        put_elf_reloc(symtab_section, cur_text_section, 
+                      ind, R_386_PC32, 0);
+        gen_le32(pe->v - 4);
+    }
+}
+
+
+static void gen_le16(int v)
+{
+    g(v);
+    g(v >> 8);
+}
+
+/* generate the modrm operand */
+static inline void asm_modrm(int reg, Operand *op)
+{
+    int mod, reg1, reg2, sib_reg1;
+
+    if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
+        g(0xc0 + (reg << 3) + op->reg);
+    } else if (op->reg == -1 && op->reg2 == -1) {
+        /* displacement only */
+        g(0x05 + (reg << 3));
+        gen_expr32(&op->e);
+    } else {
+        sib_reg1 = op->reg;
+        /* fist compute displacement encoding */
+        if (sib_reg1 == -1) {
+            sib_reg1 = 5;
+            mod = 0x00;
+        } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
+            mod = 0x00;
+        } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) {
+            mod = 0x40;
+        } else {
+            mod = 0x80;
+        }
+        /* compute if sib byte needed */
+        reg1 = op->reg;
+        if (op->reg2 != -1)
+            reg1 = 4;
+        g(mod + (reg << 3) + reg1);
+        if (reg1 == 4) {
+            /* add sib byte */
+            reg2 = op->reg2;
+            if (reg2 == -1)
+                reg2 = 4; /* indicate no index */
+            g((op->shift << 6) + (reg2 << 3) + sib_reg1);
+        }
+
+        /* add offset */
+        if (mod == 0x40) {
+            g(op->e.v);
+        } else if (mod == 0x80 || op->reg == -1) {
+            gen_expr32(&op->e);
+        }
+    }
+}
+
+static void asm_opcode(TCCState *s1, int opcode)
+{
+    const ASMInstr *pa;
+    int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;
+    int nb_ops, s, ss;
+    Operand ops[MAX_OPERANDS], *pop;
+    int op_type[3]; /* decoded op type */
+
+    /* get operands */
+    pop = ops;
+    nb_ops = 0;
+    seg_prefix = 0;
+    for(;;) {
+        if (tok == ';' || tok == TOK_LINEFEED)
+            break;
+        if (nb_ops >= MAX_OPERANDS) {
+            error("incorrect number of operands");
+        }
+        parse_operand(s1, pop);
+        if (tok == ':') {
+           if (pop->type != OP_SEG || seg_prefix) {
+               error("incorrect prefix");
+           }
+           seg_prefix = segment_prefixes[pop->reg];
+           next();
+           parse_operand(s1, pop);
+           if (!(pop->type & OP_EA)) {
+               error("segment prefix must be followed by memory reference");
+           }
+        }
+        pop++;
+        nb_ops++;
+        if (tok != ',')
+            break;
+        next();
+    }
+
+    is_short_jmp = 0;
+    s = 0; /* avoid warning */
+    
+    /* optimize matching by using a lookup table (no hashing is needed
+       !) */
+    for(pa = asm_instrs; pa->sym != 0; pa++) {
+        s = 0;
+        if (pa->instr_type & OPC_FARITH) {
+            v = opcode - pa->sym;
+            if (!((unsigned)v < 8 * 6 && (v % 6) == 0))
+                continue;
+        } else if (pa->instr_type & OPC_ARITH) {
+            if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 4))
+                continue;
+            goto compute_size;
+        } else if (pa->instr_type & OPC_SHIFT) {
+            if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 4))
+                continue;
+            goto compute_size;
+        } else if (pa->instr_type & OPC_TEST) {
+            if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
+                continue;
+        } else if (pa->instr_type & OPC_B) {
+            if (!(opcode >= pa->sym && opcode <= pa->sym + 3))
+                continue;
+        compute_size:
+            s = (opcode - pa->sym) & 3;
+        } else if (pa->instr_type & OPC_WL) {
+            if (!(opcode >= pa->sym && opcode <= pa->sym + 2))
+                continue;
+            s = opcode - pa->sym + 1;
+        } else {
+            if (pa->sym != opcode)
+                continue;
+        }
+        if (pa->nb_ops != nb_ops)
+            continue;
+        /* now decode and check each operand */
+        for(i = 0; i < nb_ops; i++) {
+            int op1, op2;
+            op1 = pa->op_type[i];
+            op2 = op1 & 0x1f;
+            switch(op2) {
+            case OPT_IM:
+                v = OP_IM8 | OP_IM16 | OP_IM32;
+                break;
+            case OPT_REG:
+                v = OP_REG8 | OP_REG16 | OP_REG32;
+                break;
+            case OPT_REGW:
+                v = OP_REG16 | OP_REG32;
+                break;
+            case OPT_IMW:
+                v = OP_IM16 | OP_IM32;
+                break;
+            default:
+                v = 1 << op2;
+                break;
+            }
+            if (op1 & OPT_EA)
+                v |= OP_EA;
+            op_type[i] = v;
+            if ((ops[i].type & v) == 0)
+                goto next;
+        }
+        /* all is matching ! */
+        break;
+    next: ;
+    }
+    if (pa->sym == 0) {
+        if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) {
+            int b;
+            b = op0_codes[opcode - TOK_ASM_pusha];
+            if (b & 0xff00) 
+                g(b >> 8);
+            g(b);
+            return;
+        } else {
+            error("unknown opcode '%s'", 
+                  get_tok_str(opcode, NULL));
+        }
+    }
+    /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
+    if (s == 3) {
+        for(i = 0; s == 3 && i < nb_ops; i++) {
+            if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX)))
+                s = reg_to_size[ops[i].type & OP_REG];
+        }
+        if (s == 3) {
+            if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && 
+                (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
+                s = 2;
+            else
+                error("cannot infer opcode suffix");
+        }
+    }
+
+    /* generate data16 prefix if needed */
+    ss = s;
+    if (s == 1 || (pa->instr_type & OPC_D16))
+        g(WORD_PREFIX_OPCODE);
+    else if (s == 2)
+        s = 1;
+    /* now generates the operation */
+    if (pa->instr_type & OPC_FWAIT)
+        g(0x9b);
+    if (seg_prefix)
+        g(seg_prefix);
+
+    v = pa->opcode;
+    if (v == 0x69 || v == 0x69) {
+        /* kludge for imul $im, %reg */
+        nb_ops = 3;
+        ops[2] = ops[1];
+    } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) {
+        v--; /* int $3 case */
+        nb_ops = 0;
+    } else if ((v == 0x06 || v == 0x07)) {
+        if (ops[0].reg >= 4) {
+            /* push/pop %fs or %gs */
+            v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3);
+        } else {
+            v += ops[0].reg << 3;
+        }
+        nb_ops = 0;
+    } else if (v <= 0x05) {
+        /* arith case */
+        v += ((opcode - TOK_ASM_addb) >> 2) << 3;
+    } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) {
+        /* fpu arith case */
+        v += ((opcode - pa->sym) / 6) << 3;
+    }
+    if (pa->instr_type & OPC_REG) {
+        for(i = 0; i < nb_ops; i++) {
+            if (op_type[i] & (OP_REG | OP_ST)) {
+                v += ops[i].reg;
+                break;
+            }
+        }
+        /* mov $im, %reg case */
+        if (pa->opcode == 0xb0 && s >= 1)
+            v += 7;
+    }
+    if (pa->instr_type & OPC_B)
+        v += s;
+    if (pa->instr_type & OPC_TEST)
+        v += test_bits[opcode - pa->sym]; 
+    if (pa->instr_type & OPC_SHORTJMP) {
+        Sym *sym;
+        int jmp_disp;
+
+        /* see if we can really generate the jump with a byte offset */
+        sym = ops[0].e.sym;
+        if (!sym)
+            goto no_short_jump;
+        if (sym->r != cur_text_section->sh_num)
+            goto no_short_jump;
+        jmp_disp = ops[0].e.v + (long)sym->next - ind - 2;
+        if (jmp_disp == (int8_t)jmp_disp) {
+            /* OK to generate jump */
+            is_short_jmp = 1;
+            ops[0].e.v = jmp_disp;
+        } else {
+        no_short_jump:
+            if (pa->instr_type & OPC_JMP) {
+                /* long jump will be allowed. need to modify the
+                   opcode slightly */
+                if (v == 0xeb)
+                    v = 0xe9;
+                else 
+                    v += 0x0f10;
+            } else {
+                error("invalid displacement");
+            }
+        }
+    }
+    op1 = v >> 8;
+    if (op1)
+        g(op1);
+    g(v);
+        
+    /* search which operand will used for modrm */
+    modrm_index = 0;
+    if (pa->instr_type & OPC_SHIFT) {
+        reg = (opcode - pa->sym) >> 2; 
+        if (reg == 6)
+            reg = 7;
+    } else if (pa->instr_type & OPC_ARITH) {
+        reg = (opcode - pa->sym) >> 2;
+    } else if (pa->instr_type & OPC_FARITH) {
+        reg = (opcode - pa->sym) / 6;
+    } else {
+        reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
+    }
+    if (pa->instr_type & OPC_MODRM) {
+        /* first look for an ea operand */
+        for(i = 0;i < nb_ops; i++) {
+            if (op_type[i] & OP_EA)
+                goto modrm_found;
+        }
+        /* then if not found, a register or indirection (shift instructions) */
+        for(i = 0;i < nb_ops; i++) {
+            if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR))
+                goto modrm_found;
+        }
+#ifdef ASM_DEBUG
+        error("bad op table");
+#endif      
+    modrm_found:
+        modrm_index = i;
+        /* if a register is used in another operand then it is
+           used instead of group */
+        for(i = 0;i < nb_ops; i++) {
+            v = op_type[i];
+            if (i != modrm_index && 
+                (v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) {
+                reg = ops[i].reg;
+                break;
+            }
+        }
+
+        asm_modrm(reg, &ops[modrm_index]);
+    }
+
+    /* emit constants */
+    if (pa->opcode == 0x9a || pa->opcode == 0xea) {
+        /* ljmp or lcall kludge */
+        gen_expr32(&ops[1].e);
+        if (ops[0].e.sym)
+            error("cannot relocate");
+        gen_le16(ops[0].e.v);
+    } else {
+        for(i = 0;i < nb_ops; i++) {
+            v = op_type[i];
+            if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM8S | OP_ADDR)) {
+                /* if multiple sizes are given it means we must look
+                   at the op size */
+                if (v == (OP_IM8 | OP_IM16 | OP_IM32) ||
+                    v == (OP_IM16 | OP_IM32)) {
+                    if (ss == 0)
+                        v = OP_IM8;
+                    else if (ss == 1)
+                        v = OP_IM16;
+                    else
+                        v = OP_IM32;
+                }
+                if (v & (OP_IM8 | OP_IM8S)) {
+                    if (ops[i].e.sym)
+                        goto error_relocate;
+                    g(ops[i].e.v);
+                } else if (v & OP_IM16) {
+                    if (ops[i].e.sym) {
+                    error_relocate:
+                        error("cannot relocate");
+                    }
+                    gen_le16(ops[i].e.v);
+                } else {
+                    if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
+                        if (is_short_jmp)
+                            g(ops[i].e.v);
+                        else
+                            gen_disp32(&ops[i].e);
+                    } else {
+                        gen_expr32(&ops[i].e);
+                    }
+                }
+            }
+        }
+    }
+}
+
+#define NB_SAVED_REGS 3
+#define NB_ASM_REGS 8
+
+/* return the constraint priority (we allocate first the lowest
+   numbered constraints) */
+static inline int constraint_priority(const char *str)
+{
+    int priority, c, pr;
+
+    /* we take the lowest priority */
+    priority = 0;
+    for(;;) {
+        c = *str;
+        if (c == '\0')
+            break;
+        str++;
+        switch(c) {
+        case 'A':
+            pr = 0;
+            break;
+        case 'a':
+        case 'b':
+        case 'c':
+        case 'd':
+        case 'S':
+        case 'D':
+            pr = 1;
+            break;
+        case 'q':
+            pr = 2;
+            break;
+        case 'r':
+            pr = 3;
+            break;
+        case 'N':
+        case 'M':
+        case 'I':
+        case 'i':
+        case 'm':
+        case 'g':
+            pr = 4;
+            break;
+        default:
+            error("unknown constraint '%c'", c);
+            pr = 0;
+        }
+        if (pr > priority)
+            priority = pr;
+    }
+    return priority;
+}
+
+static const char *skip_constraint_modifiers(const char *p)
+{
+    while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
+        p++;
+    return p;
+}
+
+#define REG_OUT_MASK 0x01
+#define REG_IN_MASK  0x02
+
+#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
+
+static void asm_compute_constraints(ASMOperand *operands, 
+                                    int nb_operands, int nb_outputs, 
+                                    const uint8_t *clobber_regs,
+                                    int *pout_reg)
+{
+    ASMOperand *op;
+    int sorted_op[MAX_ASM_OPERANDS];
+    int i, j, k, p1, p2, tmp, reg, c, reg_mask;
+    const char *str;
+    uint8_t regs_allocated[NB_ASM_REGS];
+    
+    /* init fields */
+    for(i=0;i<nb_operands;i++) {
+        op = &operands[i];
+        op->input_index = -1;
+        op->ref_index = -1;
+        op->reg = -1;
+        op->is_memory = 0;
+        op->is_rw = 0;
+    }
+    /* compute constraint priority and evaluate references to output
+       constraints if input constraints */
+    for(i=0;i<nb_operands;i++) {
+        op = &operands[i];
+        str = op->constraint;
+        str = skip_constraint_modifiers(str);
+        if (isnum(*str) || *str == '[') {
+            /* this is a reference to another constraint */
+            k = find_constraint(operands, nb_operands, str, NULL);
+            if ((unsigned)k >= i || i < nb_outputs)
+                error("invalid reference in constraint %d ('%s')",
+                      i, str);
+            op->ref_index = k;
+            if (operands[k].input_index >= 0)
+                error("cannot reference twice the same operand");
+            operands[k].input_index = i;
+            op->priority = 5;
+        } else {
+            op->priority = constraint_priority(str);
+        }
+    }
+    
+    /* sort operands according to their priority */
+    for(i=0;i<nb_operands;i++)
+        sorted_op[i] = i;
+    for(i=0;i<nb_operands - 1;i++) {
+        for(j=i+1;j<nb_operands;j++) {
+            p1 = operands[sorted_op[i]].priority; 
+            p2 = operands[sorted_op[j]].priority;
+            if (p2 < p1) {
+                tmp = sorted_op[i];
+                sorted_op[i] = sorted_op[j];
+                sorted_op[j] = tmp;
+            }
+        }
+    }
+
+    for(i = 0;i < NB_ASM_REGS; i++) {
+        if (clobber_regs[i])
+            regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
+        else
+            regs_allocated[i] = 0;
+    }
+    /* esp cannot be used */
+    regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK; 
+    /* ebp cannot be used yet */
+    regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK; 
+
+    /* allocate registers and generate corresponding asm moves */
+    for(i=0;i<nb_operands;i++) {
+        j = sorted_op[i];
+        op = &operands[j];
+        str = op->constraint;
+        /* no need to allocate references */
+        if (op->ref_index >= 0)
+            continue;
+        /* select if register is used for output, input or both */
+        if (op->input_index >= 0) {
+            reg_mask = REG_IN_MASK | REG_OUT_MASK;
+        } else if (j < nb_outputs) {
+            reg_mask = REG_OUT_MASK;
+        } else {
+            reg_mask = REG_IN_MASK;
+        }
+    try_next:
+        c = *str++;
+        switch(c) {
+        case '=':
+            goto try_next;
+        case '+':
+            op->is_rw = 1;
+            /* FALL THRU */
+        case '&':
+            if (j >= nb_outputs)
+                error("'%c' modifier can only be applied to outputs", c);
+            reg_mask = REG_IN_MASK | REG_OUT_MASK;
+            goto try_next;
+        case 'A':
+            /* allocate both eax and edx */
+            if (is_reg_allocated(TREG_EAX) || 
+                is_reg_allocated(TREG_EDX))
+                goto try_next;
+            op->is_llong = 1;
+            op->reg = TREG_EAX;
+            regs_allocated[TREG_EAX] |= reg_mask;
+            regs_allocated[TREG_EDX] |= reg_mask;
+            break;
+        case 'a':
+            reg = TREG_EAX;
+            goto alloc_reg;
+        case 'b':
+            reg = 3;
+            goto alloc_reg;
+        case 'c':
+            reg = TREG_ECX;
+            goto alloc_reg;
+        case 'd':
+            reg = TREG_EDX;
+            goto alloc_reg;
+        case 'S':
+            reg = 6;
+            goto alloc_reg;
+        case 'D':
+            reg = 7;
+        alloc_reg:
+            if (is_reg_allocated(reg))
+                goto try_next;
+            goto reg_found;
+        case 'q':
+            /* eax, ebx, ecx or edx */
+            for(reg = 0; reg < 4; reg++) {
+                if (!is_reg_allocated(reg))
+                    goto reg_found;
+            }
+            goto try_next;
+        case 'r':
+            /* any general register */
+            for(reg = 0; reg < 8; reg++) {
+                if (!is_reg_allocated(reg))
+                    goto reg_found;
+            }
+            goto try_next;
+        reg_found:
+            /* now we can reload in the register */
+            op->is_llong = 0;
+            op->reg = reg;
+            regs_allocated[reg] |= reg_mask;
+            break;
+        case 'i':
+            if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
+                goto try_next;
+            break;
+        case 'I':
+        case 'N':
+        case 'M':
+            if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
+                goto try_next;
+            break;
+        case 'm':
+        case 'g':
+            /* nothing special to do because the operand is already in
+               memory, except if the pointer itself is stored in a
+               memory variable (VT_LLOCAL case) */
+            /* XXX: fix constant case */
+            /* if it is a reference to a memory zone, it must lie
+               in a register, so we reserve the register in the
+               input registers and a load will be generated
+               later */
+            if (j < nb_outputs || c == 'm') {
+                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
+                    /* any general register */
+                    for(reg = 0; reg < 8; reg++) {
+                        if (!(regs_allocated[reg] & REG_IN_MASK))
+                            goto reg_found1;
+                    }
+                    goto try_next;
+                reg_found1:
+                    /* now we can reload in the register */
+                    regs_allocated[reg] |= REG_IN_MASK;
+                    op->reg = reg;
+                    op->is_memory = 1;
+                }
+            }
+            break;
+        default:
+            error("asm constraint %d ('%s') could not be satisfied", 
+                  j, op->constraint);
+            break;
+        }
+        /* if a reference is present for that operand, we assign it too */
+        if (op->input_index >= 0) {
+            operands[op->input_index].reg = op->reg;
+            operands[op->input_index].is_llong = op->is_llong;
+        }
+    }
+    
+    /* compute out_reg. It is used to store outputs registers to memory
+       locations references by pointers (VT_LLOCAL case) */
+    *pout_reg = -1;
+    for(i=0;i<nb_operands;i++) {
+        op = &operands[i];
+        if (op->reg >= 0 && 
+            (op->vt->r & VT_VALMASK) == VT_LLOCAL  &&
+            !op->is_memory) {
+            for(reg = 0; reg < 8; reg++) {
+                if (!(regs_allocated[reg] & REG_OUT_MASK))
+                    goto reg_found2;
+            }
+            error("could not find free output register for reloading");
+        reg_found2:
+            *pout_reg = reg;
+            break;
+        }
+    }
+    
+    /* print sorted constraints */
+#ifdef ASM_DEBUG
+    for(i=0;i<nb_operands;i++) {
+        j = sorted_op[i];
+        op = &operands[j];
+        printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n", 
+               j,                
+               op->id ? get_tok_str(op->id, NULL) : "", 
+               op->constraint,
+               op->vt->r,
+               op->reg);
+    }
+    if (*pout_reg >= 0)
+        printf("out_reg=%d\n", *pout_reg);
+#endif
+}
+
+static void subst_asm_operand(CString *add_str, 
+                              SValue *sv, int modifier)
+{
+    int r, reg, size, val;
+    char buf[64];
+
+    r = sv->r;
+    if ((r & VT_VALMASK) == VT_CONST) {
+        if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n')
+            cstr_ccat(add_str, '$');
+        if (r & VT_SYM) {
+            cstr_cat(add_str, get_tok_str(sv->sym->v, NULL));
+            if (sv->c.i != 0) {
+                cstr_ccat(add_str, '+');
+            } else {
+                return;
+            }
+        }
+        val = sv->c.i;
+        if (modifier == 'n')
+            val = -val;
+        snprintf(buf, sizeof(buf), "%d", sv->c.i);
+        cstr_cat(add_str, buf);
+    } else if ((r & VT_VALMASK) == VT_LOCAL) {
+        snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i);
+        cstr_cat(add_str, buf);
+    } else if (r & VT_LVAL) {
+        reg = r & VT_VALMASK;
+        if (reg >= VT_CONST)
+            error("internal compiler error");
+        snprintf(buf, sizeof(buf), "(%%%s)", 
+                 get_tok_str(TOK_ASM_eax + reg, NULL));
+        cstr_cat(add_str, buf);
+    } else {
+        /* register case */
+        reg = r & VT_VALMASK;
+        if (reg >= VT_CONST)
+            error("internal compiler error");
+
+        /* choose register operand size */
+        if ((sv->type.t & VT_BTYPE) == VT_BYTE)
+            size = 1;
+        else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
+            size = 2;
+        else
+            size = 4;
+        if (size == 1 && reg >= 4)
+            size = 4;
+
+        if (modifier == 'b') {
+            if (reg >= 4)
+                error("cannot use byte register");
+            size = 1;
+        } else if (modifier == 'h') {
+            if (reg >= 4)
+                error("cannot use byte register");
+            size = -1;
+        } else if (modifier == 'w') {
+            size = 2;
+        }
+
+        switch(size) {
+        case -1:
+            reg = TOK_ASM_ah + reg;
+            break;
+        case 1:
+            reg = TOK_ASM_al + reg;
+            break;
+        case 2:
+            reg = TOK_ASM_ax + reg;
+            break;
+        default:
+            reg = TOK_ASM_eax + reg;
+            break;
+        }
+        snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL));
+        cstr_cat(add_str, buf);
+    }
+}
+
+/* generate prolog and epilog code for asm statement */
+static void asm_gen_code(ASMOperand *operands, int nb_operands, 
+                         int nb_outputs, int is_output,
+                         uint8_t *clobber_regs,
+                         int out_reg)
+{
+    uint8_t regs_allocated[NB_ASM_REGS];
+    ASMOperand *op;
+    int i, reg;
+    static uint8_t reg_saved[NB_SAVED_REGS] = { 3, 6, 7 };
+
+    /* mark all used registers */
+    memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
+    for(i = 0; i < nb_operands;i++) {
+        op = &operands[i];
+        if (op->reg >= 0)
+            regs_allocated[op->reg] = 1;
+    }
+    if (!is_output) {
+        /* generate reg save code */
+        for(i = 0; i < NB_SAVED_REGS; i++) {
+            reg = reg_saved[i];
+            if (regs_allocated[reg]) 
+                g(0x50 + reg);
+        }
+
+        /* generate load code */
+        for(i = 0; i < nb_operands; i++) {
+            op = &operands[i];
+            if (op->reg >= 0) {
+                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
+                    op->is_memory) {
+                    /* memory reference case (for both input and
+                       output cases) */
+                    SValue sv;
+                    sv = *op->vt;
+                    sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
+                    load(op->reg, &sv);
+                } else if (i >= nb_outputs || op->is_rw) {
+                    /* load value in register */
+                    load(op->reg, op->vt);
+                    if (op->is_llong) {
+                        SValue sv;
+                        sv = *op->vt;
+                        sv.c.ul += 4;
+                        load(TREG_EDX, &sv);
+                    }
+                }
+            }
+        }
+    } else {
+        /* generate save code */
+        for(i = 0 ; i < nb_outputs; i++) {
+            op = &operands[i];
+            if (op->reg >= 0) {
+                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
+                    if (!op->is_memory) {
+                        SValue sv;
+                        sv = *op->vt;
+                        sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
+                        load(out_reg, &sv);
+
+                        sv.r = (sv.r & ~VT_VALMASK) | out_reg;
+                        store(op->reg, &sv);
+                    }
+                } else {
+                    store(op->reg, op->vt);
+                    if (op->is_llong) {
+                        SValue sv;
+                        sv = *op->vt;
+                        sv.c.ul += 4;
+                        store(TREG_EDX, &sv);
+                    }
+                }
+            }
+        }
+        /* generate reg restore code */
+        for(i = NB_SAVED_REGS - 1; i >= 0; i--) {
+            reg = reg_saved[i];
+            if (regs_allocated[reg]) 
+                g(0x58 + reg);
+        }
+    }
+}
+
+static void asm_clobber(uint8_t *clobber_regs, const char *str)
+{
+    int reg;
+    TokenSym *ts;
+
+    if (!strcmp(str, "memory") || 
+        !strcmp(str, "cc"))
+        return;
+    ts = tok_alloc(str, strlen(str));
+    reg = ts->tok;
+    if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {
+        reg -= TOK_ASM_eax;
+    } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
+        reg -= TOK_ASM_ax;
+    } else {
+        error("invalid clobber register '%s'", str);
+    }
+    clobber_regs[reg] = 1;
+}
diff --git a/tinyc/i386-asm.h b/tinyc/i386-asm.h
new file mode 100644
index 000000000..a3b28d4d9
--- /dev/null
+++ b/tinyc/i386-asm.h
@@ -0,0 +1,446 @@
+     DEF_ASM_OP0(pusha, 0x60) /* must be first OP0 */
+     DEF_ASM_OP0(popa, 0x61)
+     DEF_ASM_OP0(clc, 0xf8)
+     DEF_ASM_OP0(cld, 0xfc)
+     DEF_ASM_OP0(cli, 0xfa)
+     DEF_ASM_OP0(clts, 0x0f06)
+     DEF_ASM_OP0(cmc, 0xf5)
+     DEF_ASM_OP0(lahf, 0x9f)
+     DEF_ASM_OP0(sahf, 0x9e)
+     DEF_ASM_OP0(pushfl, 0x9c)
+     DEF_ASM_OP0(popfl, 0x9d)
+     DEF_ASM_OP0(pushf, 0x9c)
+     DEF_ASM_OP0(popf, 0x9d)
+     DEF_ASM_OP0(stc, 0xf9)
+     DEF_ASM_OP0(std, 0xfd)
+     DEF_ASM_OP0(sti, 0xfb)
+     DEF_ASM_OP0(aaa, 0x37)
+     DEF_ASM_OP0(aas, 0x3f)
+     DEF_ASM_OP0(daa, 0x27)
+     DEF_ASM_OP0(das, 0x2f)
+     DEF_ASM_OP0(aad, 0xd50a)
+     DEF_ASM_OP0(aam, 0xd40a)
+     DEF_ASM_OP0(cbw, 0x6698)
+     DEF_ASM_OP0(cwd, 0x6699)
+     DEF_ASM_OP0(cwde, 0x98)
+     DEF_ASM_OP0(cdq, 0x99)
+     DEF_ASM_OP0(cbtw, 0x6698)
+     DEF_ASM_OP0(cwtl, 0x98)
+     DEF_ASM_OP0(cwtd, 0x6699)
+     DEF_ASM_OP0(cltd, 0x99)
+     DEF_ASM_OP0(int3, 0xcc)
+     DEF_ASM_OP0(into, 0xce)
+     DEF_ASM_OP0(iret, 0xcf)
+     DEF_ASM_OP0(rsm, 0x0faa)
+     DEF_ASM_OP0(hlt, 0xf4)
+     DEF_ASM_OP0(wait, 0x9b)
+     DEF_ASM_OP0(nop, 0x90)
+     DEF_ASM_OP0(xlat, 0xd7)
+
+     /* strings */
+ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWL))
+ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWL))
+
+ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL))
+ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL))
+
+ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWL))
+ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWL))
+
+ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWL))
+ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWL))
+
+ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWL))
+ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWL))
+
+ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWL))
+ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWL))
+
+     /* bits */
+     
+ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
+ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
+
+ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
+
+ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
+
+ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
+
+ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
+
+     /* prefixes */
+     DEF_ASM_OP0(aword, 0x67)
+     DEF_ASM_OP0(addr16, 0x67)
+     DEF_ASM_OP0(word, 0x66)
+     DEF_ASM_OP0(data16, 0x66)
+     DEF_ASM_OP0(lock, 0xf0)
+     DEF_ASM_OP0(rep, 0xf3)
+     DEF_ASM_OP0(repe, 0xf3)
+     DEF_ASM_OP0(repz, 0xf3)
+     DEF_ASM_OP0(repne, 0xf2)
+     DEF_ASM_OP0(repnz, 0xf2)
+             
+     DEF_ASM_OP0(invd, 0x0f08)
+     DEF_ASM_OP0(wbinvd, 0x0f09)
+     DEF_ASM_OP0(cpuid, 0x0fa2)
+     DEF_ASM_OP0(wrmsr, 0x0f30)
+     DEF_ASM_OP0(rdtsc, 0x0f31)
+     DEF_ASM_OP0(rdmsr, 0x0f32)
+     DEF_ASM_OP0(rdpmc, 0x0f33)
+     DEF_ASM_OP0(ud2, 0x0f0b)
+
+     /* NOTE: we took the same order as gas opcode definition order */
+ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWL, OPT_ADDR, OPT_EAX))
+ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWL, OPT_EAX, OPT_ADDR))
+ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
+ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWL, OPT_IM, OPT_REG))
+ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_REG | OPT_EA))
+
+ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WL, OPT_SEG, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_SEG))
+
+ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WL, OPT_CR, OPT_REG32))
+ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WL, OPT_DB, OPT_REG32))
+ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WL, OPT_TR, OPT_REG32))
+ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_CR))
+ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_DB))
+ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_TR))
+
+ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
+ALT(DEF_ASM_OP2(movsbw, 0x0fbe, 0, OPC_MODRM | OPC_D16, OPT_REG8 | OPT_EA, OPT_REG16))
+ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
+ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WL, OPT_REG8 | OPT_EA, OPT_REGW))
+ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
+
+ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
+ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
+ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
+ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
+
+ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
+ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
+ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WL, OPT_SEG))
+
+ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_REG, OPT_EAX))
+ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_EAX, OPT_REG))
+ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
+
+ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX))
+ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8))
+ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX))
+ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX))
+
+ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8))
+ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8))
+ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX))
+ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX))
+
+ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WL, OPT_EA, OPT_REG))
+
+ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
+ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
+ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32))
+ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
+ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
+
+     /* arith */
+ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
+ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
+ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWL, OPT_IM, OPT_EAX))
+ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WL, OPT_IM8S, OPT_EA | OPT_REG))
+
+ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
+ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWL, OPT_IM, OPT_EAX))
+ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
+
+ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WL, OPT_REGW))
+ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WL, OPT_REGW))
+ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+
+ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+
+ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+
+ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WL, OPT_REG | OPT_EA, OPT_REG))
+ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
+ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW))
+ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
+ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW))
+
+ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
+ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
+ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
+
+     /* shifts */
+ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
+ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_EA | OPT_REG))
+
+ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
+ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
+ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
+ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
+ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
+ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
+
+ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR))
+ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR))
+ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
+ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR))
+
+ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
+ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA))
+ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32))
+ALT(DEF_ASM_OP1(ljmp, 0xff, 5, 0, OPT_EA))
+
+ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8))
+ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
+    DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8)
+    DEF_ASM_OP0(leave, 0xc9)
+    DEF_ASM_OP0(ret, 0xc3)
+ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16))
+    DEF_ASM_OP0(lret, 0xcb)
+ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
+
+ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP | OPC_TEST, OPT_ADDR))
+    DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
+    DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
+    DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
+    DEF_ASM_OP1(loopz, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
+    DEF_ASM_OP1(loop, 0xe2, 0, OPC_SHORTJMP, OPT_ADDR)
+    DEF_ASM_OP1(jecxz, 0xe3, 0, OPC_SHORTJMP, OPT_ADDR)
+     
+     /* float */
+     /* specific fcomp handling */
+ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0))
+
+ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST))
+ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0))
+ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH))
+ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST))
+ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0))
+ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST))
+ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH))
+ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA))
+ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA))
+ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA))
+ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA))
+
+     DEF_ASM_OP0(fucompp, 0xdae9)
+     DEF_ASM_OP0(ftst, 0xd9e4)
+     DEF_ASM_OP0(fxam, 0xd9e5)
+     DEF_ASM_OP0(fld1, 0xd9e8)
+     DEF_ASM_OP0(fldl2t, 0xd9e9)
+     DEF_ASM_OP0(fldl2e, 0xd9ea)
+     DEF_ASM_OP0(fldpi, 0xd9eb)
+     DEF_ASM_OP0(fldlg2, 0xd9ec)
+     DEF_ASM_OP0(fldln2, 0xd9ed)
+     DEF_ASM_OP0(fldz, 0xd9ee)
+
+     DEF_ASM_OP0(f2xm1, 0xd9f0)
+     DEF_ASM_OP0(fyl2x, 0xd9f1)
+     DEF_ASM_OP0(fptan, 0xd9f2)
+     DEF_ASM_OP0(fpatan, 0xd9f3)
+     DEF_ASM_OP0(fxtract, 0xd9f4)
+     DEF_ASM_OP0(fprem1, 0xd9f5)
+     DEF_ASM_OP0(fdecstp, 0xd9f6)
+     DEF_ASM_OP0(fincstp, 0xd9f7)
+     DEF_ASM_OP0(fprem, 0xd9f8)
+     DEF_ASM_OP0(fyl2xp1, 0xd9f9)
+     DEF_ASM_OP0(fsqrt, 0xd9fa)
+     DEF_ASM_OP0(fsincos, 0xd9fb)
+     DEF_ASM_OP0(frndint, 0xd9fc)
+     DEF_ASM_OP0(fscale, 0xd9fd)
+     DEF_ASM_OP0(fsin, 0xd9fe)
+     DEF_ASM_OP0(fcos, 0xd9ff)
+     DEF_ASM_OP0(fchs, 0xd9e0)
+     DEF_ASM_OP0(fabs, 0xd9e1)
+     DEF_ASM_OP0(fninit, 0xdbe3)
+     DEF_ASM_OP0(fnclex, 0xdbe2)
+     DEF_ASM_OP0(fnop, 0xd9d0)
+     DEF_ASM_OP0(fwait, 0x9b)
+
+    /* fp load */
+    DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST)
+    DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST)
+    DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA)
+ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA))
+    DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA)
+    DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA)
+    
+    /* fp store */
+    DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST)
+    DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST)
+    DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA)
+ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA))
+    DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA)
+
+    DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST)
+    DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA)
+
+    /* exchange */
+    DEF_ASM_OP0(fxch, 0xd9c9)
+ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST))
+
+    /* misc FPU */
+    DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST )
+    DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST )
+
+    DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT)
+    DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )
+    DEF_ASM_OP0(fnstsw, 0xdfe0)
+ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX ))
+ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA ))
+    DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX )
+ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT))
+ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
+    DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT)
+    DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA )
+    DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA )
+    DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST )
+    DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST )
+    DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA )
+    DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA )
+
+    /* segments */
+    DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
+    DEF_ASM_OP2(lar, 0x0f02, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG32)
+    DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG)
+    DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG)
+ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG))
+    DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG)
+    DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA)
+    DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA)
+    DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA)
+    DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG16| OPT_EA)
+    DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
+    DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
+
+    /* 486 */
+    DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
+ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
+ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
+    DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA )
+
+    DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA)
+    DEF_ASM_OP2(boundw, 0x62, 0, OPC_MODRM | OPC_D16, OPT_REG16, OPT_EA)
+
+    /* pentium */
+    DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
+    
+    /* pentium pro */
+    ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
+
+    DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 )
+
+    DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 )
+    DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 )
+
+    /* mmx */
+    DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */
+    DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMX )
+ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_REG32 ))
+    DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX ))
+    DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
+    DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+    DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
+
+#undef ALT
+#undef DEF_ASM_OP0
+#undef DEF_ASM_OP0L
+#undef DEF_ASM_OP1
+#undef DEF_ASM_OP2
+#undef DEF_ASM_OP3
diff --git a/tinyc/i386-gen.c b/tinyc/i386-gen.c
new file mode 100644
index 000000000..f958ab547
--- /dev/null
+++ b/tinyc/i386-gen.c
@@ -0,0 +1,1034 @@
+/*
+ *  X86 code generator for TCC
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+/* number of available registers */
+#define NB_REGS             4
+
+/* a register can belong to several classes. The classes must be
+   sorted from more general to more precise (see gv2() code which does
+   assumptions on it). */
+#define RC_INT     0x0001 /* generic integer register */
+#define RC_FLOAT   0x0002 /* generic float register */
+#define RC_EAX     0x0004
+#define RC_ST0     0x0008 
+#define RC_ECX     0x0010
+#define RC_EDX     0x0020
+#define RC_IRET    RC_EAX /* function return: integer register */
+#define RC_LRET    RC_EDX /* function return: second integer register */
+#define RC_FRET    RC_ST0 /* function return: float register */
+
+/* pretty names for the registers */
+enum {
+    TREG_EAX = 0,
+    TREG_ECX,
+    TREG_EDX,
+    TREG_ST0,
+};
+
+int reg_classes[NB_REGS] = {
+    /* eax */ RC_INT | RC_EAX,
+    /* ecx */ RC_INT | RC_ECX,
+    /* edx */ RC_INT | RC_EDX,
+    /* st0 */ RC_FLOAT | RC_ST0,
+};
+
+/* return registers for function */
+#define REG_IRET TREG_EAX /* single word int return register */
+#define REG_LRET TREG_EDX /* second word return register (for long long) */
+#define REG_FRET TREG_ST0 /* float return register */
+
+/* defined if function parameters must be evaluated in reverse order */
+#define INVERT_FUNC_PARAMS
+
+/* defined if structures are passed as pointers. Otherwise structures
+   are directly pushed on stack. */
+//#define FUNC_STRUCT_PARAM_AS_PTR
+
+/* pointer size, in bytes */
+#define PTR_SIZE 4
+
+/* long double size and alignment, in bytes */
+#define LDOUBLE_SIZE  12
+#define LDOUBLE_ALIGN 4
+/* maximum alignment (for aligned attribute support) */
+#define MAX_ALIGN     8
+
+/******************************************************/
+/* ELF defines */
+
+#define EM_TCC_TARGET EM_386
+
+/* relocation type for 32 bit data relocation */
+#define R_DATA_32   R_386_32
+#define R_JMP_SLOT  R_386_JMP_SLOT
+#define R_COPY      R_386_COPY
+
+#define ELF_START_ADDR 0x08048000
+#define ELF_PAGE_SIZE  0x1000
+
+/******************************************************/
+
+static unsigned long func_sub_sp_offset;
+static unsigned long func_bound_offset;
+static int func_ret_sub;
+
+/* XXX: make it faster ? */
+void g(int c)
+{
+    int ind1;
+    ind1 = ind + 1;
+    if (ind1 > cur_text_section->data_allocated)
+        section_realloc(cur_text_section, ind1);
+    cur_text_section->data[ind] = c;
+    ind = ind1;
+}
+
+void o(unsigned int c)
+{
+    while (c) {
+        g(c);
+        c = c >> 8;
+    }
+}
+
+void gen_le32(int c)
+{
+    g(c);
+    g(c >> 8);
+    g(c >> 16);
+    g(c >> 24);
+}
+
+/* output a symbol and patch all calls to it */
+void gsym_addr(int t, int a)
+{
+    int n, *ptr;
+    while (t) {
+        ptr = (int *)(cur_text_section->data + t);
+        n = *ptr; /* next value */
+        *ptr = a - t - 4;
+        t = n;
+    }
+}
+
+void gsym(int t)
+{
+    gsym_addr(t, ind);
+}
+
+/* psym is used to put an instruction with a data field which is a
+   reference to a symbol. It is in fact the same as oad ! */
+#define psym oad
+
+/* instruction + 4 bytes data. Return the address of the data */
+static int oad(int c, int s)
+{
+    int ind1;
+
+    o(c);
+    ind1 = ind + 4;
+    if (ind1 > cur_text_section->data_allocated)
+        section_realloc(cur_text_section, ind1);
+    *(int *)(cur_text_section->data + ind) = s;
+    s = ind;
+    ind = ind1;
+    return s;
+}
+
+/* output constant with relocation if 'r & VT_SYM' is true */
+static void gen_addr32(int r, Sym *sym, int c)
+{
+    if (r & VT_SYM)
+        greloc(cur_text_section, sym, ind, R_386_32);
+    gen_le32(c);
+}
+
+/* generate a modrm reference. 'op_reg' contains the addtionnal 3
+   opcode bits */
+static void gen_modrm(int op_reg, int r, Sym *sym, int c)
+{
+    op_reg = op_reg << 3;
+    if ((r & VT_VALMASK) == VT_CONST) {
+        /* constant memory reference */
+        o(0x05 | op_reg);
+        gen_addr32(r, sym, c);
+    } else if ((r & VT_VALMASK) == VT_LOCAL) {
+        /* currently, we use only ebp as base */
+        if (c == (char)c) {
+            /* short reference */
+            o(0x45 | op_reg);
+            g(c);
+        } else {
+            oad(0x85 | op_reg, c);
+        }
+    } else {
+        g(0x00 | op_reg | (r & VT_VALMASK));
+    }
+}
+
+
+/* load 'r' from value 'sv' */
+void load(int r, SValue *sv)
+{
+    int v, t, ft, fc, fr;
+    SValue v1;
+
+    fr = sv->r;
+    ft = sv->type.t;
+    fc = sv->c.ul;
+
+    v = fr & VT_VALMASK;
+    if (fr & VT_LVAL) {
+        if (v == VT_LLOCAL) {
+            v1.type.t = VT_INT;
+            v1.r = VT_LOCAL | VT_LVAL;
+            v1.c.ul = fc;
+            load(r, &v1);
+            fr = r;
+        }
+        if ((ft & VT_BTYPE) == VT_FLOAT) {
+            o(0xd9); /* flds */
+            r = 0;
+        } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
+            o(0xdd); /* fldl */
+            r = 0;
+        } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+            o(0xdb); /* fldt */
+            r = 5;
+        } else if ((ft & VT_TYPE) == VT_BYTE) {
+            o(0xbe0f);   /* movsbl */
+        } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
+            o(0xb60f);   /* movzbl */
+        } else if ((ft & VT_TYPE) == VT_SHORT) {
+            o(0xbf0f);   /* movswl */
+        } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
+            o(0xb70f);   /* movzwl */
+        } else {
+            o(0x8b);     /* movl */
+        }
+        gen_modrm(r, fr, sv->sym, fc);
+    } else {
+        if (v == VT_CONST) {
+            o(0xb8 + r); /* mov $xx, r */
+            gen_addr32(fr, sv->sym, fc);
+        } else if (v == VT_LOCAL) {
+            o(0x8d); /* lea xxx(%ebp), r */
+            gen_modrm(r, VT_LOCAL, sv->sym, fc);
+        } else if (v == VT_CMP) {
+            oad(0xb8 + r, 0); /* mov $0, r */
+            o(0x0f); /* setxx %br */
+            o(fc);
+            o(0xc0 + r);
+        } else if (v == VT_JMP || v == VT_JMPI) {
+            t = v & 1;
+            oad(0xb8 + r, t); /* mov $1, r */
+            o(0x05eb); /* jmp after */
+            gsym(fc);
+            oad(0xb8 + r, t ^ 1); /* mov $0, r */
+        } else if (v != r) {
+            o(0x89);
+            o(0xc0 + r + v * 8); /* mov v, r */
+        }
+    }
+}
+
+/* store register 'r' in lvalue 'v' */
+void store(int r, SValue *v)
+{
+    int fr, bt, ft, fc;
+
+    ft = v->type.t;
+    fc = v->c.ul;
+    fr = v->r & VT_VALMASK;
+    bt = ft & VT_BTYPE;
+    /* XXX: incorrect if float reg to reg */
+    if (bt == VT_FLOAT) {
+        o(0xd9); /* fsts */
+        r = 2;
+    } else if (bt == VT_DOUBLE) {
+        o(0xdd); /* fstpl */
+        r = 2;
+    } else if (bt == VT_LDOUBLE) {
+        o(0xc0d9); /* fld %st(0) */
+        o(0xdb); /* fstpt */
+        r = 7;
+    } else {
+        if (bt == VT_SHORT)
+            o(0x66);
+        if (bt == VT_BYTE || bt == VT_BOOL)
+            o(0x88);
+        else
+            o(0x89);
+    }
+    if (fr == VT_CONST ||
+        fr == VT_LOCAL ||
+        (v->r & VT_LVAL)) {
+        gen_modrm(r, v->r, v->sym, fc);
+    } else if (fr != r) {
+        o(0xc0 + fr + r * 8); /* mov r, fr */
+    }
+}
+
+static void gadd_sp(int val)
+{
+    if (val == (char)val) {
+        o(0xc483);
+        g(val);
+    } else {
+        oad(0xc481, val); /* add $xxx, %esp */
+    }
+}
+
+/* 'is_jmp' is '1' if it is a jump */
+static void gcall_or_jmp(int is_jmp)
+{
+    int r;
+    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+        /* constant case */
+        if (vtop->r & VT_SYM) {
+            /* relocation case */
+            greloc(cur_text_section, vtop->sym, 
+                   ind + 1, R_386_PC32);
+        } else {
+            /* put an empty PC32 relocation */
+            put_elf_reloc(symtab_section, cur_text_section, 
+                          ind + 1, R_386_PC32, 0);
+        }
+        oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
+    } else {
+        /* otherwise, indirect call */
+        r = gv(RC_INT);
+        o(0xff); /* call/jmp *r */
+        o(0xd0 + r + (is_jmp << 4));
+    }
+}
+
+static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
+static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
+
+/* Generate function call. The function address is pushed first, then
+   all the parameters in call order. This functions pops all the
+   parameters and the function address. */
+void gfunc_call(int nb_args)
+{
+    int size, align, r, args_size, i, func_call;
+    Sym *func_sym;
+    
+    args_size = 0;
+    for(i = 0;i < nb_args; i++) {
+        if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
+            size = type_size(&vtop->type, &align);
+            /* align to stack align size */
+            size = (size + 3) & ~3;
+            /* allocate the necessary size on stack */
+            oad(0xec81, size); /* sub $xxx, %esp */
+            /* generate structure store */
+            r = get_reg(RC_INT);
+            o(0x89); /* mov %esp, r */
+            o(0xe0 + r);
+            vset(&vtop->type, r | VT_LVAL, 0);
+            vswap();
+            vstore();
+            args_size += size;
+        } else if (is_float(vtop->type.t)) {
+            gv(RC_FLOAT); /* only one float register */
+            if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
+                size = 4;
+            else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
+                size = 8;
+            else
+                size = 12;
+            oad(0xec81, size); /* sub $xxx, %esp */
+            if (size == 12)
+                o(0x7cdb);
+            else
+                o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
+            g(0x24);
+            g(0x00);
+            args_size += size;
+        } else {
+            /* simple type (currently always same size) */
+            /* XXX: implicit cast ? */
+            r = gv(RC_INT);
+            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+                size = 8;
+                o(0x50 + vtop->r2); /* push r */
+            } else {
+                size = 4;
+            }
+            o(0x50 + r); /* push r */
+            args_size += size;
+        }
+        vtop--;
+    }
+    save_regs(0); /* save used temporary registers */
+    func_sym = vtop->type.ref;
+    func_call = FUNC_CALL(func_sym->r);
+    /* fast call case */
+    if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
+        func_call == FUNC_FASTCALLW) {
+        int fastcall_nb_regs;
+        uint8_t *fastcall_regs_ptr;
+        if (func_call == FUNC_FASTCALLW) {
+            fastcall_regs_ptr = fastcallw_regs;
+            fastcall_nb_regs = 2;
+        } else {
+            fastcall_regs_ptr = fastcall_regs;
+            fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
+        }
+        for(i = 0;i < fastcall_nb_regs; i++) {
+            if (args_size <= 0)
+                break;
+            o(0x58 + fastcall_regs_ptr[i]); /* pop r */
+            /* XXX: incorrect for struct/floats */
+            args_size -= 4;
+        }
+    }
+    gcall_or_jmp(0);
+    if (args_size && func_call != FUNC_STDCALL)
+        gadd_sp(args_size);
+    vtop--;
+}
+
+#ifdef TCC_TARGET_PE
+#define FUNC_PROLOG_SIZE 10
+#else
+#define FUNC_PROLOG_SIZE 9
+#endif
+
+/* generate function prolog of type 't' */
+void gfunc_prolog(CType *func_type)
+{
+    int addr, align, size, func_call, fastcall_nb_regs;
+    int param_index, param_addr;
+    uint8_t *fastcall_regs_ptr;
+    Sym *sym;
+    CType *type;
+
+    sym = func_type->ref;
+    func_call = FUNC_CALL(sym->r);
+    addr = 8;
+    loc = 0;
+    if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
+        fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
+        fastcall_regs_ptr = fastcall_regs;
+    } else if (func_call == FUNC_FASTCALLW) {
+        fastcall_nb_regs = 2;
+        fastcall_regs_ptr = fastcallw_regs;
+    } else {
+        fastcall_nb_regs = 0;
+        fastcall_regs_ptr = NULL;
+    }
+    param_index = 0;
+
+    ind += FUNC_PROLOG_SIZE;
+    func_sub_sp_offset = ind;
+    /* if the function returns a structure, then add an
+       implicit pointer parameter */
+    func_vt = sym->type;
+    if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
+        /* XXX: fastcall case ? */
+        func_vc = addr;
+        addr += 4;
+        param_index++;
+    }
+    /* define parameters */
+    while ((sym = sym->next) != NULL) {
+        type = &sym->type;
+        size = type_size(type, &align);
+        size = (size + 3) & ~3;
+#ifdef FUNC_STRUCT_PARAM_AS_PTR
+        /* structs are passed as pointer */
+        if ((type->t & VT_BTYPE) == VT_STRUCT) {
+            size = 4;
+        }
+#endif
+        if (param_index < fastcall_nb_regs) {
+            /* save FASTCALL register */
+            loc -= 4;
+            o(0x89);     /* movl */
+            gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
+            param_addr = loc;
+        } else {
+            param_addr = addr;
+            addr += size;
+        }
+        sym_push(sym->v & ~SYM_FIELD, type,
+                 VT_LOCAL | lvalue_type(type->t), param_addr);
+        param_index++;
+    }
+    func_ret_sub = 0;
+    /* pascal type call ? */
+    if (func_call == FUNC_STDCALL)
+        func_ret_sub = addr - 8;
+
+    /* leave some room for bound checking code */
+    if (tcc_state->do_bounds_check) {
+        oad(0xb8, 0); /* lbound section pointer */
+        oad(0xb8, 0); /* call to function */
+        func_bound_offset = lbounds_section->data_offset;
+    }
+}
+
+/* generate function epilog */
+void gfunc_epilog(void)
+{
+    int v, saved_ind;
+
+#ifdef CONFIG_TCC_BCHECK
+    if (tcc_state->do_bounds_check
+     && func_bound_offset != lbounds_section->data_offset) {
+        int saved_ind;
+        int *bounds_ptr;
+        Sym *sym, *sym_data;
+        /* add end of table info */
+        bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
+        *bounds_ptr = 0;
+        /* generate bound local allocation */
+        saved_ind = ind;
+        ind = func_sub_sp_offset;
+        sym_data = get_sym_ref(&char_pointer_type, lbounds_section, 
+                               func_bound_offset, lbounds_section->data_offset);
+        greloc(cur_text_section, sym_data,
+               ind + 1, R_386_32);
+        oad(0xb8, 0); /* mov %eax, xxx */
+        sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
+        greloc(cur_text_section, sym, 
+               ind + 1, R_386_PC32);
+        oad(0xe8, -4);
+        ind = saved_ind;
+        /* generate bound check local freeing */
+        o(0x5250); /* save returned value, if any */
+        greloc(cur_text_section, sym_data,
+               ind + 1, R_386_32);
+        oad(0xb8, 0); /* mov %eax, xxx */
+        sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
+        greloc(cur_text_section, sym, 
+               ind + 1, R_386_PC32);
+        oad(0xe8, -4);
+        o(0x585a); /* restore returned value, if any */
+    }
+#endif
+    o(0xc9); /* leave */
+    if (func_ret_sub == 0) {
+        o(0xc3); /* ret */
+    } else {
+        o(0xc2); /* ret n */
+        g(func_ret_sub);
+        g(func_ret_sub >> 8);
+    }
+    /* align local size to word & save local variables */
+    
+    v = (-loc + 3) & -4; 
+    saved_ind = ind;
+    ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
+#ifdef TCC_TARGET_PE
+    if (v >= 4096) {
+        Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
+        oad(0xb8, v); /* mov stacksize, %eax */
+        oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
+        greloc(cur_text_section, sym, ind-4, R_386_PC32);
+    } else
+#endif
+    {
+        o(0xe58955);  /* push %ebp, mov %esp, %ebp */
+        o(0xec81);  /* sub esp, stacksize */
+        gen_le32(v);
+#if FUNC_PROLOG_SIZE == 10
+        o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
+#endif
+    }
+    ind = saved_ind;
+}
+
+/* generate a jump to a label */
+int gjmp(int t)
+{
+    return psym(0xe9, t);
+}
+
+/* generate a jump to a fixed address */
+void gjmp_addr(int a)
+{
+    int r;
+    r = a - ind - 2;
+    if (r == (char)r) {
+        g(0xeb);
+        g(r);
+    } else {
+        oad(0xe9, a - ind - 5);
+    }
+}
+
+/* generate a test. set 'inv' to invert test. Stack entry is popped */
+int gtst(int inv, int t)
+{
+    int v, *p;
+
+    v = vtop->r & VT_VALMASK;
+    if (v == VT_CMP) {
+        /* fast case : can jump directly since flags are set */
+        g(0x0f);
+        t = psym((vtop->c.i - 16) ^ inv, t);
+    } else if (v == VT_JMP || v == VT_JMPI) {
+        /* && or || optimization */
+        if ((v & 1) == inv) {
+            /* insert vtop->c jump list in t */
+            p = &vtop->c.i;
+            while (*p != 0)
+                p = (int *)(cur_text_section->data + *p);
+            *p = t;
+            t = vtop->c.i;
+        } else {
+            t = gjmp(t);
+            gsym(vtop->c.i);
+        }
+    } else {
+        if (is_float(vtop->type.t) || 
+            (vtop->type.t & VT_BTYPE) == VT_LLONG) {
+            vpushi(0);
+            gen_op(TOK_NE);
+        }
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            /* constant jmp optimization */
+            if ((vtop->c.i != 0) != inv) 
+                t = gjmp(t);
+        } else {
+            v = gv(RC_INT);
+            o(0x85);
+            o(0xc0 + v * 9);
+            g(0x0f);
+            t = psym(0x85 ^ inv, t);
+        }
+    }
+    vtop--;
+    return t;
+}
+
+/* generate an integer binary operation */
+void gen_opi(int op)
+{
+    int r, fr, opc, c;
+
+    switch(op) {
+    case '+':
+    case TOK_ADDC1: /* add with carry generation */
+        opc = 0;
+    gen_op8:
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            /* constant case */
+            vswap();
+            r = gv(RC_INT);
+            vswap();
+            c = vtop->c.i;
+            if (c == (char)c) {
+                /* XXX: generate inc and dec for smaller code ? */
+                o(0x83);
+                o(0xc0 | (opc << 3) | r);
+                g(c);
+            } else {
+                o(0x81);
+                oad(0xc0 | (opc << 3) | r, c);
+            }
+        } else {
+            gv2(RC_INT, RC_INT);
+            r = vtop[-1].r;
+            fr = vtop[0].r;
+            o((opc << 3) | 0x01);
+            o(0xc0 + r + fr * 8); 
+        }
+        vtop--;
+        if (op >= TOK_ULT && op <= TOK_GT) {
+            vtop->r = VT_CMP;
+            vtop->c.i = op;
+        }
+        break;
+    case '-':
+    case TOK_SUBC1: /* sub with carry generation */
+        opc = 5;
+        goto gen_op8;
+    case TOK_ADDC2: /* add with carry use */
+        opc = 2;
+        goto gen_op8;
+    case TOK_SUBC2: /* sub with carry use */
+        opc = 3;
+        goto gen_op8;
+    case '&':
+        opc = 4;
+        goto gen_op8;
+    case '^':
+        opc = 6;
+        goto gen_op8;
+    case '|':
+        opc = 1;
+        goto gen_op8;
+    case '*':
+        gv2(RC_INT, RC_INT);
+        r = vtop[-1].r;
+        fr = vtop[0].r;
+        vtop--;
+        o(0xaf0f); /* imul fr, r */
+        o(0xc0 + fr + r * 8);
+        break;
+    case TOK_SHL:
+        opc = 4;
+        goto gen_shift;
+    case TOK_SHR:
+        opc = 5;
+        goto gen_shift;
+    case TOK_SAR:
+        opc = 7;
+    gen_shift:
+        opc = 0xc0 | (opc << 3);
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            /* constant case */
+            vswap();
+            r = gv(RC_INT);
+            vswap();
+            c = vtop->c.i & 0x1f;
+            o(0xc1); /* shl/shr/sar $xxx, r */
+            o(opc | r);
+            g(c);
+        } else {
+            /* we generate the shift in ecx */
+            gv2(RC_INT, RC_ECX);
+            r = vtop[-1].r;
+            o(0xd3); /* shl/shr/sar %cl, r */
+            o(opc | r);
+        }
+        vtop--;
+        break;
+    case '/':
+    case TOK_UDIV:
+    case TOK_PDIV:
+    case '%':
+    case TOK_UMOD:
+    case TOK_UMULL:
+        /* first operand must be in eax */
+        /* XXX: need better constraint for second operand */
+        gv2(RC_EAX, RC_ECX);
+        r = vtop[-1].r;
+        fr = vtop[0].r;
+        vtop--;
+        save_reg(TREG_EDX);
+        if (op == TOK_UMULL) {
+            o(0xf7); /* mul fr */
+            o(0xe0 + fr);
+            vtop->r2 = TREG_EDX;
+            r = TREG_EAX;
+        } else {
+            if (op == TOK_UDIV || op == TOK_UMOD) {
+                o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
+                o(0xf0 + fr);
+            } else {
+                o(0xf799); /* cltd, idiv fr, %eax */
+                o(0xf8 + fr);
+            }
+            if (op == '%' || op == TOK_UMOD)
+                r = TREG_EDX;
+            else
+                r = TREG_EAX;
+        }
+        vtop->r = r;
+        break;
+    default:
+        opc = 7;
+        goto gen_op8;
+    }
+}
+
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+   two operands are guaranted to have the same floating point type */
+/* XXX: need to use ST1 too */
+void gen_opf(int op)
+{
+    int a, ft, fc, swapped, r;
+
+    /* convert constants to memory references */
+    if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+        vswap();
+        gv(RC_FLOAT);
+        vswap();
+    }
+    if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
+        gv(RC_FLOAT);
+
+    /* must put at least one value in the floating point register */
+    if ((vtop[-1].r & VT_LVAL) &&
+        (vtop[0].r & VT_LVAL)) {
+        vswap();
+        gv(RC_FLOAT);
+        vswap();
+    }
+    swapped = 0;
+    /* swap the stack if needed so that t1 is the register and t2 is
+       the memory reference */
+    if (vtop[-1].r & VT_LVAL) {
+        vswap();
+        swapped = 1;
+    }
+    if (op >= TOK_ULT && op <= TOK_GT) {
+        /* load on stack second operand */
+        load(TREG_ST0, vtop);
+        save_reg(TREG_EAX); /* eax is used by FP comparison code */
+        if (op == TOK_GE || op == TOK_GT)
+            swapped = !swapped;
+        else if (op == TOK_EQ || op == TOK_NE)
+            swapped = 0;
+        if (swapped)
+            o(0xc9d9); /* fxch %st(1) */
+        o(0xe9da); /* fucompp */
+        o(0xe0df); /* fnstsw %ax */
+        if (op == TOK_EQ) {
+            o(0x45e480); /* and $0x45, %ah */
+            o(0x40fC80); /* cmp $0x40, %ah */
+        } else if (op == TOK_NE) {
+            o(0x45e480); /* and $0x45, %ah */
+            o(0x40f480); /* xor $0x40, %ah */
+            op = TOK_NE;
+        } else if (op == TOK_GE || op == TOK_LE) {
+            o(0x05c4f6); /* test $0x05, %ah */
+            op = TOK_EQ;
+        } else {
+            o(0x45c4f6); /* test $0x45, %ah */
+            op = TOK_EQ;
+        }
+        vtop--;
+        vtop->r = VT_CMP;
+        vtop->c.i = op;
+    } else {
+        /* no memory reference possible for long double operations */
+        if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+            load(TREG_ST0, vtop);
+            swapped = !swapped;
+        }
+        
+        switch(op) {
+        default:
+        case '+':
+            a = 0;
+            break;
+        case '-':
+            a = 4;
+            if (swapped)
+                a++;
+            break;
+        case '*':
+            a = 1;
+            break;
+        case '/':
+            a = 6;
+            if (swapped)
+                a++;
+            break;
+        }
+        ft = vtop->type.t;
+        fc = vtop->c.ul;
+        if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+            o(0xde); /* fxxxp %st, %st(1) */
+            o(0xc1 + (a << 3));
+        } else {
+            /* if saved lvalue, then we must reload it */
+            r = vtop->r;
+            if ((r & VT_VALMASK) == VT_LLOCAL) {
+                SValue v1;
+                r = get_reg(RC_INT);
+                v1.type.t = VT_INT;
+                v1.r = VT_LOCAL | VT_LVAL;
+                v1.c.ul = fc;
+                load(r, &v1);
+                fc = 0;
+            }
+
+            if ((ft & VT_BTYPE) == VT_DOUBLE)
+                o(0xdc);
+            else
+                o(0xd8);
+            gen_modrm(a, r, vtop->sym, fc);
+        }
+        vtop--;
+    }
+}
+
+/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
+   and 'long long' cases. */
+void gen_cvt_itof(int t)
+{
+    save_reg(TREG_ST0);
+    gv(RC_INT);
+    if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+        /* signed long long to float/double/long double (unsigned case
+           is handled generically) */
+        o(0x50 + vtop->r2); /* push r2 */
+        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
+        o(0x242cdf); /* fildll (%esp) */
+        o(0x08c483); /* add $8, %esp */
+    } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == 
+               (VT_INT | VT_UNSIGNED)) {
+        /* unsigned int to float/double/long double */
+        o(0x6a); /* push $0 */
+        g(0x00);
+        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
+        o(0x242cdf); /* fildll (%esp) */
+        o(0x08c483); /* add $8, %esp */
+    } else {
+        /* int to float/double/long double */
+        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
+        o(0x2404db); /* fildl (%esp) */
+        o(0x04c483); /* add $4, %esp */
+    }
+    vtop->r = TREG_ST0;
+}
+
+/* convert fp to int 't' type */
+/* XXX: handle long long case */
+void gen_cvt_ftoi(int t)
+{
+    int r, r2, size;
+    Sym *sym;
+    CType ushort_type;
+
+    ushort_type.t = VT_SHORT | VT_UNSIGNED;
+
+    gv(RC_FLOAT);
+    if (t != VT_INT)
+        size = 8;
+    else 
+        size = 4;
+    
+    o(0x2dd9); /* ldcw xxx */
+    sym = external_global_sym(TOK___tcc_int_fpu_control, 
+                              &ushort_type, VT_LVAL);
+    greloc(cur_text_section, sym, 
+           ind, R_386_32);
+    gen_le32(0);
+    
+    oad(0xec81, size); /* sub $xxx, %esp */
+    if (size == 4)
+        o(0x1cdb); /* fistpl */
+    else
+        o(0x3cdf); /* fistpll */
+    o(0x24);
+    o(0x2dd9); /* ldcw xxx */
+    sym = external_global_sym(TOK___tcc_fpu_control, 
+                              &ushort_type, VT_LVAL);
+    greloc(cur_text_section, sym, 
+           ind, R_386_32);
+    gen_le32(0);
+
+    r = get_reg(RC_INT);
+    o(0x58 + r); /* pop r */
+    if (size == 8) {
+        if (t == VT_LLONG) {
+            vtop->r = r; /* mark reg as used */
+            r2 = get_reg(RC_INT);
+            o(0x58 + r2); /* pop r2 */
+            vtop->r2 = r2;
+        } else {
+            o(0x04c483); /* add $4, %esp */
+        }
+    }
+    vtop->r = r;
+}
+
+/* convert from one floating point type to another */
+void gen_cvt_ftof(int t)
+{
+    /* all we have to do on i386 is to put the float in a register */
+    gv(RC_FLOAT);
+}
+
+/* computed goto support */
+void ggoto(void)
+{
+    gcall_or_jmp(1);
+    vtop--;
+}
+
+/* bound check support functions */
+#ifdef CONFIG_TCC_BCHECK
+
+/* generate a bounded pointer addition */
+void gen_bounded_ptr_add(void)
+{
+    Sym *sym;
+
+    /* prepare fast i386 function call (args in eax and edx) */
+    gv2(RC_EAX, RC_EDX);
+    /* save all temporary registers */
+    vtop -= 2;
+    save_regs(0);
+    /* do a fast function call */
+    sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
+    greloc(cur_text_section, sym, 
+           ind + 1, R_386_PC32);
+    oad(0xe8, -4);
+    /* returned pointer is in eax */
+    vtop++;
+    vtop->r = TREG_EAX | VT_BOUNDED;
+    /* address of bounding function call point */
+    vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); 
+}
+
+/* patch pointer addition in vtop so that pointer dereferencing is
+   also tested */
+void gen_bounded_ptr_deref(void)
+{
+    int func;
+    int size, align;
+    Elf32_Rel *rel;
+    Sym *sym;
+
+    size = 0;
+    /* XXX: put that code in generic part of tcc */
+    if (!is_float(vtop->type.t)) {
+        if (vtop->r & VT_LVAL_BYTE)
+            size = 1;
+        else if (vtop->r & VT_LVAL_SHORT)
+            size = 2;
+    }
+    if (!size)
+        size = type_size(&vtop->type, &align);
+    switch(size) {
+    case  1: func = TOK___bound_ptr_indir1; break;
+    case  2: func = TOK___bound_ptr_indir2; break;
+    case  4: func = TOK___bound_ptr_indir4; break;
+    case  8: func = TOK___bound_ptr_indir8; break;
+    case 12: func = TOK___bound_ptr_indir12; break;
+    case 16: func = TOK___bound_ptr_indir16; break;
+    default:
+        error("unhandled size when derefencing bounded pointer");
+        func = 0;
+        break;
+    }
+
+    /* patch relocation */
+    /* XXX: find a better solution ? */
+    rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
+    sym = external_global_sym(func, &func_old_type, 0);
+    if (!sym->c)
+        put_extern_sym(sym, NULL, 0, 0);
+    rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
+}
+#endif
+
+/* end of X86 code generator */
+/*************************************************************/
+
diff --git a/tinyc/il-gen.c b/tinyc/il-gen.c
new file mode 100644
index 000000000..29f052655
--- /dev/null
+++ b/tinyc/il-gen.c
@@ -0,0 +1,667 @@
+/*
+ *  CIL code generator for TCC
+ * 
+ *  Copyright (c) 2002 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+/* number of available registers */
+#define NB_REGS             3
+
+/* a register can belong to several classes. The classes must be
+   sorted from more general to more precise (see gv2() code which does
+   assumptions on it). */
+#define RC_ST      0x0001  /* any stack entry */
+#define RC_ST0     0x0002  /* top of stack */
+#define RC_ST1     0x0004  /* top - 1 */
+
+#define RC_INT     RC_ST
+#define RC_FLOAT   RC_ST
+#define RC_IRET    RC_ST0 /* function return: integer register */
+#define RC_LRET    RC_ST0 /* function return: second integer register */
+#define RC_FRET    RC_ST0 /* function return: float register */
+
+/* pretty names for the registers */
+enum {
+    REG_ST0 = 0,
+    REG_ST1,
+    REG_ST2,
+};
+
+int reg_classes[NB_REGS] = {
+    /* ST0 */ RC_ST | RC_ST0,
+    /* ST1 */ RC_ST | RC_ST1,
+    /* ST2 */ RC_ST,
+};
+
+/* return registers for function */
+#define REG_IRET REG_ST0 /* single word int return register */
+#define REG_LRET REG_ST0 /* second word return register (for long long) */
+#define REG_FRET REG_ST0 /* float return register */
+
+/* defined if function parameters must be evaluated in reverse order */
+//#define INVERT_FUNC_PARAMS
+
+/* defined if structures are passed as pointers. Otherwise structures
+   are directly pushed on stack. */
+//#define FUNC_STRUCT_PARAM_AS_PTR
+
+/* pointer size, in bytes */
+#define PTR_SIZE 4
+
+/* long double size and alignment, in bytes */
+#define LDOUBLE_SIZE  8
+#define LDOUBLE_ALIGN 8
+
+/* function call context */
+typedef struct GFuncContext {
+    int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */
+} GFuncContext;
+
+/******************************************************/
+/* opcode definitions */
+
+#define IL_OP_PREFIX 0xFE
+
+enum ILOPCodes {
+#define OP(name, str, n) IL_OP_ ## name = n,
+#include "il-opcodes.h"
+#undef OP
+};
+
+char *il_opcodes_str[] = {
+#define OP(name, str, n) [n] = str,
+#include "il-opcodes.h"
+#undef OP
+};
+
+/******************************************************/
+
+/* arguments variable numbers start from there */
+#define ARG_BASE 0x70000000
+
+static FILE *il_outfile;
+
+static void out_byte(int c)
+{
+    *(char *)ind++ = c;
+}
+
+static void out_le32(int c)
+{
+    out_byte(c);
+    out_byte(c >> 8);
+    out_byte(c >> 16);
+    out_byte(c >> 24);
+}
+
+static void init_outfile(void)
+{
+    if (!il_outfile) {
+        il_outfile = stdout;
+        fprintf(il_outfile, 
+                ".assembly extern mscorlib\n"
+                "{\n"
+                ".ver 1:0:2411:0\n"
+                "}\n\n");
+    }
+}
+
+static void out_op1(int op)
+{
+    if (op & 0x100)
+        out_byte(IL_OP_PREFIX);
+    out_byte(op & 0xff);
+}
+
+/* output an opcode with prefix */
+static void out_op(int op)
+{
+    out_op1(op);
+    fprintf(il_outfile, " %s\n", il_opcodes_str[op]);
+}
+
+static void out_opb(int op, int c)
+{
+    out_op1(op);
+    out_byte(c);
+    fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c);
+}
+
+static void out_opi(int op, int c)
+{
+    out_op1(op);
+    out_le32(c);
+    fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c);
+}
+
+/* XXX: not complete */
+static void il_type_to_str(char *buf, int buf_size, 
+                           int t, const char *varstr)
+{
+    int bt;
+    Sym *s, *sa;
+    char buf1[256];
+    const char *tstr;
+
+    t = t & VT_TYPE;
+    bt = t & VT_BTYPE;
+    buf[0] = '\0';
+    if (t & VT_UNSIGNED)
+        pstrcat(buf, buf_size, "unsigned ");
+    switch(bt) {
+    case VT_VOID:
+        tstr = "void";
+        goto add_tstr;
+    case VT_BOOL:
+        tstr = "bool";
+        goto add_tstr;
+    case VT_BYTE:
+        tstr = "int8";
+        goto add_tstr;
+    case VT_SHORT:
+        tstr = "int16";
+        goto add_tstr;
+    case VT_ENUM:
+    case VT_INT:
+    case VT_LONG:
+        tstr = "int32";
+        goto add_tstr;
+    case VT_LLONG:
+        tstr = "int64";
+        goto add_tstr;
+    case VT_FLOAT:
+        tstr = "float32";
+        goto add_tstr;
+    case VT_DOUBLE:
+    case VT_LDOUBLE:
+        tstr = "float64";
+    add_tstr:
+        pstrcat(buf, buf_size, tstr);
+        break;
+    case VT_STRUCT:
+        error("structures not handled yet");
+        break;
+    case VT_FUNC:
+        s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
+        il_type_to_str(buf, buf_size, s->t, varstr);
+        pstrcat(buf, buf_size, "(");
+        sa = s->next;
+        while (sa != NULL) {
+            il_type_to_str(buf1, sizeof(buf1), sa->t, NULL);
+            pstrcat(buf, buf_size, buf1);
+            sa = sa->next;
+            if (sa)
+                pstrcat(buf, buf_size, ", ");
+        }
+        pstrcat(buf, buf_size, ")");
+        goto no_var;
+    case VT_PTR:
+        s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
+        pstrcpy(buf1, sizeof(buf1), "*");
+        if (varstr)
+            pstrcat(buf1, sizeof(buf1), varstr);
+        il_type_to_str(buf, buf_size, s->t, buf1);
+        goto no_var;
+    }
+    if (varstr) {
+        pstrcat(buf, buf_size, " ");
+        pstrcat(buf, buf_size, varstr);
+    }
+ no_var: ;
+}
+
+
+/* patch relocation entry with value 'val' */
+void greloc_patch1(Reloc *p, int val)
+{
+}
+
+/* output a symbol and patch all calls to it */
+void gsym_addr(t, a)
+{
+}
+
+/* output jump and return symbol */
+static int out_opj(int op, int c)
+{
+    out_op1(op);
+    out_le32(0);
+    if (c == 0) {
+        c = ind - (int)cur_text_section->data;
+    }
+    fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c);
+    return c;
+}
+
+void gsym(int t)
+{
+    fprintf(il_outfile, "L%d:\n", t);
+}
+
+/* load 'r' from value 'sv' */
+void load(int r, SValue *sv)
+{
+    int v, fc, ft;
+
+    v = sv->r & VT_VALMASK;
+    fc = sv->c.i;
+    ft = sv->t;
+
+    if (sv->r & VT_LVAL) {
+        if (v == VT_LOCAL) {
+            if (fc >= ARG_BASE) {
+                fc -= ARG_BASE;
+                if (fc >= 0 && fc <= 4) {
+                    out_op(IL_OP_LDARG_0 + fc);
+                } else if (fc <= 0xff) {
+                    out_opb(IL_OP_LDARG_S, fc);
+                } else {
+                    out_opi(IL_OP_LDARG, fc);
+                }
+            } else {
+                if (fc >= 0 && fc <= 4) {
+                    out_op(IL_OP_LDLOC_0 + fc);
+                } else if (fc <= 0xff) {
+                    out_opb(IL_OP_LDLOC_S, fc);
+                } else {
+                    out_opi(IL_OP_LDLOC, fc);
+                }
+            }
+        } else if (v == VT_CONST) {
+                /* XXX: handle globals */
+                out_opi(IL_OP_LDSFLD, 0);
+        } else {
+            if ((ft & VT_BTYPE) == VT_FLOAT) {
+                out_op(IL_OP_LDIND_R4);
+            } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
+                out_op(IL_OP_LDIND_R8);
+            } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+                out_op(IL_OP_LDIND_R8);
+            } else if ((ft & VT_TYPE) == VT_BYTE)
+                out_op(IL_OP_LDIND_I1);
+            else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
+                out_op(IL_OP_LDIND_U1);
+            else if ((ft & VT_TYPE) == VT_SHORT)
+                out_op(IL_OP_LDIND_I2);
+            else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
+                out_op(IL_OP_LDIND_U2);
+            else
+                out_op(IL_OP_LDIND_I4);
+        } 
+    } else {
+        if (v == VT_CONST) {
+            /* XXX: handle globals */
+            if (fc >= -1 && fc <= 8) {
+                out_op(IL_OP_LDC_I4_M1 + fc + 1); 
+            } else {
+                out_opi(IL_OP_LDC_I4, fc);
+            }
+        } else if (v == VT_LOCAL) {
+            if (fc >= ARG_BASE) {
+                fc -= ARG_BASE;
+                if (fc <= 0xff) {
+                    out_opb(IL_OP_LDARGA_S, fc);
+                } else {
+                    out_opi(IL_OP_LDARGA, fc);
+                }
+            } else {
+                if (fc <= 0xff) {
+                    out_opb(IL_OP_LDLOCA_S, fc);
+                } else {
+                    out_opi(IL_OP_LDLOCA, fc);
+                }
+            }
+        } else {
+            /* XXX: do it */
+        }
+    }
+}
+
+/* store register 'r' in lvalue 'v' */
+void store(int r, SValue *sv)
+{
+    int v, fc, ft;
+
+    v = sv->r & VT_VALMASK;
+    fc = sv->c.i;
+    ft = sv->t;
+    if (v == VT_LOCAL) {
+        if (fc >= ARG_BASE) {
+            fc -= ARG_BASE;
+            /* XXX: check IL arg store semantics */
+            if (fc <= 0xff) {
+                out_opb(IL_OP_STARG_S, fc);
+            } else {
+                out_opi(IL_OP_STARG, fc);
+            }
+        } else {
+            if (fc >= 0 && fc <= 4) {
+                out_op(IL_OP_STLOC_0 + fc);
+            } else if (fc <= 0xff) {
+                out_opb(IL_OP_STLOC_S, fc);
+            } else {
+                out_opi(IL_OP_STLOC, fc);
+            }
+        }
+    } else if (v == VT_CONST) {
+        /* XXX: handle globals */
+        out_opi(IL_OP_STSFLD, 0);
+    } else {
+        if ((ft & VT_BTYPE) == VT_FLOAT)
+            out_op(IL_OP_STIND_R4);
+        else if ((ft & VT_BTYPE) == VT_DOUBLE)
+            out_op(IL_OP_STIND_R8);
+        else if ((ft & VT_BTYPE) == VT_LDOUBLE)
+            out_op(IL_OP_STIND_R8);
+        else if ((ft & VT_BTYPE) == VT_BYTE)
+            out_op(IL_OP_STIND_I1);
+        else if ((ft & VT_BTYPE) == VT_SHORT)
+            out_op(IL_OP_STIND_I2);
+        else
+            out_op(IL_OP_STIND_I4);
+    }
+}
+
+/* start function call and return function call context */
+void gfunc_start(GFuncContext *c, int func_call)
+{
+    c->func_call = func_call;
+}
+
+/* push function parameter which is in (vtop->t, vtop->c). Stack entry
+   is then popped. */
+void gfunc_param(GFuncContext *c)
+{
+    if ((vtop->t & VT_BTYPE) == VT_STRUCT) {
+        error("structures passed as value not handled yet");
+    } else {
+        /* simply push on stack */
+        gv(RC_ST0);
+    }
+    vtop--;
+}
+
+/* generate function call with address in (vtop->t, vtop->c) and free function
+   context. Stack entry is popped */
+void gfunc_call(GFuncContext *c)
+{
+    char buf[1024];
+
+    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+        /* XXX: more info needed from tcc */
+        il_type_to_str(buf, sizeof(buf), vtop->t, "xxx");
+        fprintf(il_outfile, " call %s\n", buf);
+    } else {
+        /* indirect call */
+        gv(RC_INT);
+        il_type_to_str(buf, sizeof(buf), vtop->t, NULL);
+        fprintf(il_outfile, " calli %s\n", buf);
+    }
+    vtop--;
+}
+
+/* generate function prolog of type 't' */
+void gfunc_prolog(int t)
+{
+    int addr, u, func_call;
+    Sym *sym;
+    char buf[1024];
+
+    init_outfile();
+
+    /* XXX: pass function name to gfunc_prolog */
+    il_type_to_str(buf, sizeof(buf), t, funcname);
+    fprintf(il_outfile, ".method static %s il managed\n", buf);
+    fprintf(il_outfile, "{\n");
+    /* XXX: cannot do better now */
+    fprintf(il_outfile, " .maxstack %d\n", NB_REGS);
+    fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n");
+    
+    if (!strcmp(funcname, "main"))
+        fprintf(il_outfile, " .entrypoint\n");
+        
+    sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
+    func_call = sym->r;
+
+    addr = ARG_BASE;
+    /* if the function returns a structure, then add an
+       implicit pointer parameter */
+    func_vt = sym->t;
+    if ((func_vt & VT_BTYPE) == VT_STRUCT) {
+        func_vc = addr;
+        addr++;
+    }
+    /* define parameters */
+    while ((sym = sym->next) != NULL) {
+        u = sym->t;
+        sym_push(sym->v & ~SYM_FIELD, u,
+                 VT_LOCAL | lvalue_type(sym->type.t), addr);
+        addr++;
+    }
+}
+
+/* generate function epilog */
+void gfunc_epilog(void)
+{
+    out_op(IL_OP_RET);
+    fprintf(il_outfile, "}\n\n");
+}
+
+/* generate a jump to a label */
+int gjmp(int t)
+{
+    return out_opj(IL_OP_BR, t);
+}
+
+/* generate a jump to a fixed address */
+void gjmp_addr(int a)
+{
+    /* XXX: handle syms */
+    out_opi(IL_OP_BR, a);
+}
+
+/* generate a test. set 'inv' to invert test. Stack entry is popped */
+int gtst(int inv, int t)
+{
+    int v, *p, c;
+
+    v = vtop->r & VT_VALMASK;
+    if (v == VT_CMP) {
+        c = vtop->c.i ^ inv;
+        switch(c) {
+        case TOK_EQ:
+            c = IL_OP_BEQ;
+            break;
+        case TOK_NE:
+            c = IL_OP_BNE_UN;
+            break;
+        case TOK_LT:
+            c = IL_OP_BLT;
+            break;
+        case TOK_LE:
+            c = IL_OP_BLE;
+            break;
+        case TOK_GT:
+            c = IL_OP_BGT;
+            break;
+        case TOK_GE:
+            c = IL_OP_BGE;
+            break;
+        case TOK_ULT:
+            c = IL_OP_BLT_UN;
+            break;
+        case TOK_ULE:
+            c = IL_OP_BLE_UN;
+            break;
+        case TOK_UGT:
+            c = IL_OP_BGT_UN;
+            break;
+        case TOK_UGE:
+            c = IL_OP_BGE_UN;
+            break;
+        }
+        t = out_opj(c, t);
+    } else if (v == VT_JMP || v == VT_JMPI) {
+        /* && or || optimization */
+        if ((v & 1) == inv) {
+            /* insert vtop->c jump list in t */
+            p = &vtop->c.i;
+            while (*p != 0)
+                p = (int *)*p;
+            *p = t;
+            t = vtop->c.i;
+        } else {
+            t = gjmp(t);
+            gsym(vtop->c.i);
+        }
+    } else {
+        if (is_float(vtop->t)) {
+            vpushi(0);
+            gen_op(TOK_NE);
+        }
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
+            /* constant jmp optimization */
+            if ((vtop->c.i != 0) != inv) 
+                t = gjmp(t);
+        } else {
+            v = gv(RC_INT);
+            t = out_opj(IL_OP_BRTRUE - inv, t);
+        }
+    }
+    vtop--;
+    return t;
+}
+
+/* generate an integer binary operation */
+void gen_opi(int op)
+{
+    gv2(RC_ST1, RC_ST0);
+    switch(op) {
+    case '+':
+        out_op(IL_OP_ADD);
+        goto std_op;
+    case '-':
+        out_op(IL_OP_SUB);
+        goto std_op;
+    case '&':
+        out_op(IL_OP_AND);
+        goto std_op;
+    case '^':
+        out_op(IL_OP_XOR);
+        goto std_op;
+    case '|':
+        out_op(IL_OP_OR);
+        goto std_op;
+    case '*':
+        out_op(IL_OP_MUL);
+        goto std_op;
+    case TOK_SHL:
+        out_op(IL_OP_SHL);
+        goto std_op;
+    case TOK_SHR:
+        out_op(IL_OP_SHR_UN);
+        goto std_op;
+    case TOK_SAR:
+        out_op(IL_OP_SHR);
+        goto std_op;
+    case '/':
+    case TOK_PDIV:
+        out_op(IL_OP_DIV);
+        goto std_op;
+    case TOK_UDIV:
+        out_op(IL_OP_DIV_UN);
+        goto std_op;
+    case '%':
+        out_op(IL_OP_REM);
+        goto std_op;
+    case TOK_UMOD:
+        out_op(IL_OP_REM_UN);
+    std_op:
+        vtop--;
+        vtop[0].r = REG_ST0;
+        break;
+    case TOK_EQ:
+    case TOK_NE:
+    case TOK_LT:
+    case TOK_LE:
+    case TOK_GT:
+    case TOK_GE:
+    case TOK_ULT:
+    case TOK_ULE:
+    case TOK_UGT:
+    case TOK_UGE:
+        vtop--;
+        vtop[0].r = VT_CMP;
+        vtop[0].c.i = op;
+        break;
+    }
+}
+
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+   two operands are guaranted to have the same floating point type */
+void gen_opf(int op)
+{
+    /* same as integer */
+    gen_opi(op);
+}
+
+/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
+   and 'long long' cases. */
+void gen_cvt_itof(int t)
+{
+    gv(RC_ST0);
+    if (t == VT_FLOAT)
+        out_op(IL_OP_CONV_R4);
+    else
+        out_op(IL_OP_CONV_R8);
+}
+
+/* convert fp to int 't' type */
+/* XXX: handle long long case */
+void gen_cvt_ftoi(int t)
+{
+    gv(RC_ST0);
+    switch(t) {
+    case VT_INT | VT_UNSIGNED:
+        out_op(IL_OP_CONV_U4);
+        break;
+    case VT_LLONG:
+        out_op(IL_OP_CONV_I8);
+        break;
+    case VT_LLONG | VT_UNSIGNED:
+        out_op(IL_OP_CONV_U8);
+        break;
+    default:
+        out_op(IL_OP_CONV_I4);
+        break;
+    }
+}
+
+/* convert from one floating point type to another */
+void gen_cvt_ftof(int t)
+{
+    gv(RC_ST0);
+    if (t == VT_FLOAT) {
+        out_op(IL_OP_CONV_R4);
+    } else {
+        out_op(IL_OP_CONV_R8);
+    }
+}
+
+/* end of CIL code generator */
+/*************************************************************/
+
diff --git a/tinyc/il-opcodes.h b/tinyc/il-opcodes.h
new file mode 100644
index 000000000..d53ffb2c5
--- /dev/null
+++ b/tinyc/il-opcodes.h
@@ -0,0 +1,251 @@
+/*
+ *  CIL opcode definition
+ * 
+ *  Copyright (c) 2002 Fabrice Bellard
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+OP(NOP, "nop", 0x00)
+OP(BREAK, "break", 0x01)
+OP(LDARG_0, "ldarg.0", 0x02)
+OP(LDARG_1, "ldarg.1", 0x03)
+OP(LDARG_2, "ldarg.2", 0x04)
+OP(LDARG_3, "ldarg.3", 0x05)
+OP(LDLOC_0, "ldloc.0", 0x06)
+OP(LDLOC_1, "ldloc.1", 0x07)
+OP(LDLOC_2, "ldloc.2", 0x08)
+OP(LDLOC_3, "ldloc.3", 0x09)
+OP(STLOC_0, "stloc.0", 0x0a)
+OP(STLOC_1, "stloc.1", 0x0b)
+OP(STLOC_2, "stloc.2", 0x0c)
+OP(STLOC_3, "stloc.3", 0x0d)
+OP(LDARG_S, "ldarg.s", 0x0e)
+OP(LDARGA_S, "ldarga.s", 0x0f)
+OP(STARG_S, "starg.s", 0x10)
+OP(LDLOC_S, "ldloc.s", 0x11)
+OP(LDLOCA_S, "ldloca.s", 0x12)
+OP(STLOC_S, "stloc.s", 0x13)
+OP(LDNULL, "ldnull", 0x14)
+OP(LDC_I4_M1, "ldc.i4.m1", 0x15)
+OP(LDC_I4_0, "ldc.i4.0", 0x16)
+OP(LDC_I4_1, "ldc.i4.1", 0x17)
+OP(LDC_I4_2, "ldc.i4.2", 0x18)
+OP(LDC_I4_3, "ldc.i4.3", 0x19)
+OP(LDC_I4_4, "ldc.i4.4", 0x1a)
+OP(LDC_I4_5, "ldc.i4.5", 0x1b)
+OP(LDC_I4_6, "ldc.i4.6", 0x1c)
+OP(LDC_I4_7, "ldc.i4.7", 0x1d)
+OP(LDC_I4_8, "ldc.i4.8", 0x1e)
+OP(LDC_I4_S, "ldc.i4.s", 0x1f)
+OP(LDC_I4, "ldc.i4", 0x20)
+OP(LDC_I8, "ldc.i8", 0x21)
+OP(LDC_R4, "ldc.r4", 0x22)
+OP(LDC_R8, "ldc.r8", 0x23)
+OP(LDPTR, "ldptr", 0x24)
+OP(DUP, "dup", 0x25)
+OP(POP, "pop", 0x26)
+OP(JMP, "jmp", 0x27)
+OP(CALL, "call", 0x28)
+OP(CALLI, "calli", 0x29)
+OP(RET, "ret", 0x2a)
+OP(BR_S, "br.s", 0x2b)
+OP(BRFALSE_S, "brfalse.s", 0x2c)
+OP(BRTRUE_S, "brtrue.s", 0x2d)
+OP(BEQ_S, "beq.s", 0x2e)
+OP(BGE_S, "bge.s", 0x2f)
+OP(BGT_S, "bgt.s", 0x30)
+OP(BLE_S, "ble.s", 0x31)
+OP(BLT_S, "blt.s", 0x32)
+OP(BNE_UN_S, "bne.un.s", 0x33)
+OP(BGE_UN_S, "bge.un.s", 0x34)
+OP(BGT_UN_S, "bgt.un.s", 0x35)
+OP(BLE_UN_S, "ble.un.s", 0x36)
+OP(BLT_UN_S, "blt.un.s", 0x37)
+OP(BR, "br", 0x38)
+OP(BRFALSE, "brfalse", 0x39)
+OP(BRTRUE, "brtrue", 0x3a)
+OP(BEQ, "beq", 0x3b)
+OP(BGE, "bge", 0x3c)
+OP(BGT, "bgt", 0x3d)
+OP(BLE, "ble", 0x3e)
+OP(BLT, "blt", 0x3f)
+OP(BNE_UN, "bne.un", 0x40)
+OP(BGE_UN, "bge.un", 0x41)
+OP(BGT_UN, "bgt.un", 0x42)
+OP(BLE_UN, "ble.un", 0x43)
+OP(BLT_UN, "blt.un", 0x44)
+OP(SWITCH, "switch", 0x45)
+OP(LDIND_I1, "ldind.i1", 0x46)
+OP(LDIND_U1, "ldind.u1", 0x47)
+OP(LDIND_I2, "ldind.i2", 0x48)
+OP(LDIND_U2, "ldind.u2", 0x49)
+OP(LDIND_I4, "ldind.i4", 0x4a)
+OP(LDIND_U4, "ldind.u4", 0x4b)
+OP(LDIND_I8, "ldind.i8", 0x4c)
+OP(LDIND_I, "ldind.i", 0x4d)
+OP(LDIND_R4, "ldind.r4", 0x4e)
+OP(LDIND_R8, "ldind.r8", 0x4f)
+OP(LDIND_REF, "ldind.ref", 0x50)
+OP(STIND_REF, "stind.ref", 0x51)
+OP(STIND_I1, "stind.i1", 0x52)
+OP(STIND_I2, "stind.i2", 0x53)
+OP(STIND_I4, "stind.i4", 0x54)
+OP(STIND_I8, "stind.i8", 0x55)
+OP(STIND_R4, "stind.r4", 0x56)
+OP(STIND_R8, "stind.r8", 0x57)
+OP(ADD, "add", 0x58)
+OP(SUB, "sub", 0x59)
+OP(MUL, "mul", 0x5a)
+OP(DIV, "div", 0x5b)
+OP(DIV_UN, "div.un", 0x5c)
+OP(REM, "rem", 0x5d)
+OP(REM_UN, "rem.un", 0x5e)
+OP(AND, "and", 0x5f)
+OP(OR, "or", 0x60)
+OP(XOR, "xor", 0x61)
+OP(SHL, "shl", 0x62)
+OP(SHR, "shr", 0x63)
+OP(SHR_UN, "shr.un", 0x64)
+OP(NEG, "neg", 0x65)
+OP(NOT, "not", 0x66)
+OP(CONV_I1, "conv.i1", 0x67)
+OP(CONV_I2, "conv.i2", 0x68)
+OP(CONV_I4, "conv.i4", 0x69)
+OP(CONV_I8, "conv.i8", 0x6a)
+OP(CONV_R4, "conv.r4", 0x6b)
+OP(CONV_R8, "conv.r8", 0x6c)
+OP(CONV_U4, "conv.u4", 0x6d)
+OP(CONV_U8, "conv.u8", 0x6e)
+OP(CALLVIRT, "callvirt", 0x6f)
+OP(CPOBJ, "cpobj", 0x70)
+OP(LDOBJ, "ldobj", 0x71)
+OP(LDSTR, "ldstr", 0x72)
+OP(NEWOBJ, "newobj", 0x73)
+OP(CASTCLASS, "castclass", 0x74)
+OP(ISINST, "isinst", 0x75)
+OP(CONV_R_UN, "conv.r.un", 0x76)
+OP(ANN_DATA_S, "ann.data.s", 0x77)
+OP(UNBOX, "unbox", 0x79)
+OP(THROW, "throw", 0x7a)
+OP(LDFLD, "ldfld", 0x7b)
+OP(LDFLDA, "ldflda", 0x7c)
+OP(STFLD, "stfld", 0x7d)
+OP(LDSFLD, "ldsfld", 0x7e)
+OP(LDSFLDA, "ldsflda", 0x7f)
+OP(STSFLD, "stsfld", 0x80)
+OP(STOBJ, "stobj", 0x81)
+OP(CONV_OVF_I1_UN, "conv.ovf.i1.un", 0x82)
+OP(CONV_OVF_I2_UN, "conv.ovf.i2.un", 0x83)
+OP(CONV_OVF_I4_UN, "conv.ovf.i4.un", 0x84)
+OP(CONV_OVF_I8_UN, "conv.ovf.i8.un", 0x85)
+OP(CONV_OVF_U1_UN, "conv.ovf.u1.un", 0x86)
+OP(CONV_OVF_U2_UN, "conv.ovf.u2.un", 0x87)
+OP(CONV_OVF_U4_UN, "conv.ovf.u4.un", 0x88)
+OP(CONV_OVF_U8_UN, "conv.ovf.u8.un", 0x89)
+OP(CONV_OVF_I_UN, "conv.ovf.i.un", 0x8a)
+OP(CONV_OVF_U_UN, "conv.ovf.u.un", 0x8b)
+OP(BOX, "box", 0x8c)
+OP(NEWARR, "newarr", 0x8d)
+OP(LDLEN, "ldlen", 0x8e)
+OP(LDELEMA, "ldelema", 0x8f)
+OP(LDELEM_I1, "ldelem.i1", 0x90)
+OP(LDELEM_U1, "ldelem.u1", 0x91)
+OP(LDELEM_I2, "ldelem.i2", 0x92)
+OP(LDELEM_U2, "ldelem.u2", 0x93)
+OP(LDELEM_I4, "ldelem.i4", 0x94)
+OP(LDELEM_U4, "ldelem.u4", 0x95)
+OP(LDELEM_I8, "ldelem.i8", 0x96)
+OP(LDELEM_I, "ldelem.i", 0x97)
+OP(LDELEM_R4, "ldelem.r4", 0x98)
+OP(LDELEM_R8, "ldelem.r8", 0x99)
+OP(LDELEM_REF, "ldelem.ref", 0x9a)
+OP(STELEM_I, "stelem.i", 0x9b)
+OP(STELEM_I1, "stelem.i1", 0x9c)
+OP(STELEM_I2, "stelem.i2", 0x9d)
+OP(STELEM_I4, "stelem.i4", 0x9e)
+OP(STELEM_I8, "stelem.i8", 0x9f)
+OP(STELEM_R4, "stelem.r4", 0xa0)
+OP(STELEM_R8, "stelem.r8", 0xa1)
+OP(STELEM_REF, "stelem.ref", 0xa2)
+OP(CONV_OVF_I1, "conv.ovf.i1", 0xb3)
+OP(CONV_OVF_U1, "conv.ovf.u1", 0xb4)
+OP(CONV_OVF_I2, "conv.ovf.i2", 0xb5)
+OP(CONV_OVF_U2, "conv.ovf.u2", 0xb6)
+OP(CONV_OVF_I4, "conv.ovf.i4", 0xb7)
+OP(CONV_OVF_U4, "conv.ovf.u4", 0xb8)
+OP(CONV_OVF_I8, "conv.ovf.i8", 0xb9)
+OP(CONV_OVF_U8, "conv.ovf.u8", 0xba)
+OP(REFANYVAL, "refanyval", 0xc2)
+OP(CKFINITE, "ckfinite", 0xc3)
+OP(MKREFANY, "mkrefany", 0xc6)
+OP(ANN_CALL, "ann.call", 0xc7)
+OP(ANN_CATCH, "ann.catch", 0xc8)
+OP(ANN_DEAD, "ann.dead", 0xc9)
+OP(ANN_HOISTED, "ann.hoisted", 0xca)
+OP(ANN_HOISTED_CALL, "ann.hoisted.call", 0xcb)
+OP(ANN_LAB, "ann.lab", 0xcc)
+OP(ANN_DEF, "ann.def", 0xcd)
+OP(ANN_REF_S, "ann.ref.s", 0xce)
+OP(ANN_PHI, "ann.phi", 0xcf)
+OP(LDTOKEN, "ldtoken", 0xd0)
+OP(CONV_U2, "conv.u2", 0xd1)
+OP(CONV_U1, "conv.u1", 0xd2)
+OP(CONV_I, "conv.i", 0xd3)
+OP(CONV_OVF_I, "conv.ovf.i", 0xd4)
+OP(CONV_OVF_U, "conv.ovf.u", 0xd5)
+OP(ADD_OVF, "add.ovf", 0xd6)
+OP(ADD_OVF_UN, "add.ovf.un", 0xd7)
+OP(MUL_OVF, "mul.ovf", 0xd8)
+OP(MUL_OVF_UN, "mul.ovf.un", 0xd9)
+OP(SUB_OVF, "sub.ovf", 0xda)
+OP(SUB_OVF_UN, "sub.ovf.un", 0xdb)
+OP(ENDFINALLY, "endfinally", 0xdc)
+OP(LEAVE, "leave", 0xdd)
+OP(LEAVE_S, "leave.s", 0xde)
+OP(STIND_I, "stind.i", 0xdf)
+OP(CONV_U, "conv.u", 0xe0)
+
+/* prefix instructions. we use an opcode >= 256 to ease coding */
+
+OP(ARGLIST, "arglist", 0x100)
+OP(CEQ, "ceq", 0x101)
+OP(CGT, "cgt", 0x102)
+OP(CGT_UN, "cgt.un", 0x103)
+OP(CLT, "clt", 0x104)
+OP(CLT_UN, "clt.un", 0x105)
+OP(LDFTN, "ldftn", 0x106)
+OP(LDVIRTFTN, "ldvirtftn", 0x107)
+OP(JMPI, "jmpi", 0x108)
+OP(LDARG, "ldarg", 0x109)
+OP(LDARGA, "ldarga", 0x10a)
+OP(STARG, "starg", 0x10b)
+OP(LDLOC, "ldloc", 0x10c)
+OP(LDLOCA, "ldloca", 0x10d)
+OP(STLOC, "stloc", 0x10e)
+OP(LOCALLOC, "localloc", 0x10f)
+OP(ENDFILTER, "endfilter", 0x111)
+OP(UNALIGNED, "unaligned", 0x112)
+OP(VOLATILE, "volatile", 0x113)
+OP(TAIL, "tail", 0x114)
+OP(INITOBJ, "initobj", 0x115)
+OP(ANN_LIVE, "ann.live", 0x116)
+OP(CPBLK, "cpblk", 0x117)
+OP(INITBLK, "initblk", 0x118)
+OP(ANN_REF, "ann.ref", 0x119)
+OP(RETHROW, "rethrow", 0x11a)
+OP(SIZEOF, "sizeof", 0x11c)
+OP(REFANYTYPE, "refanytype", 0x11d)
+OP(ANN_DATA, "ann.data", 0x122)
+OP(ANN_ARG, "ann.arg", 0x123)
diff --git a/tinyc/include/float.h b/tinyc/include/float.h
new file mode 100644
index 000000000..5f1c6f73c
--- /dev/null
+++ b/tinyc/include/float.h
@@ -0,0 +1,57 @@
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+
+#define FLT_RADIX 2
+
+/* IEEE float */
+#define FLT_MANT_DIG 24
+#define FLT_DIG 6
+#define FLT_ROUNDS 1
+#define FLT_EPSILON 1.19209290e-07F
+#define FLT_MIN_EXP (-125)
+#define FLT_MIN 1.17549435e-38F
+#define FLT_MIN_10_EXP (-37)
+#define FLT_MAX_EXP 128
+#define FLT_MAX 3.40282347e+38F
+#define FLT_MAX_10_EXP 38
+
+/* IEEE double */
+#define DBL_MANT_DIG 53
+#define DBL_DIG 15
+#define DBL_EPSILON 2.2204460492503131e-16
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014e-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157e+308
+#define DBL_MAX_10_EXP 308
+
+/* horrible intel long double */
+#ifdef __i386__
+
+#define LDBL_MANT_DIG 64
+#define LDBL_DIG 18
+#define LDBL_EPSILON 1.08420217248550443401e-19L
+#define LDBL_MIN_EXP (-16381)
+#define LDBL_MIN 3.36210314311209350626e-4932L
+#define LDBL_MIN_10_EXP (-4931)
+#define LDBL_MAX_EXP 16384
+#define LDBL_MAX 1.18973149535723176502e+4932L
+#define LDBL_MAX_10_EXP 4932
+
+#else
+
+/* same as IEEE double */
+#define LDBL_MANT_DIG 53
+#define LDBL_DIG 15
+#define LDBL_EPSILON 2.2204460492503131e-16
+#define LDBL_MIN_EXP (-1021)
+#define LDBL_MIN 2.2250738585072014e-308
+#define LDBL_MIN_10_EXP (-307)
+#define LDBL_MAX_EXP 1024
+#define LDBL_MAX 1.7976931348623157e+308
+#define LDBL_MAX_10_EXP 308
+
+#endif
+
+#endif /* _FLOAT_H_ */
diff --git a/tinyc/include/stdarg.h b/tinyc/include/stdarg.h
new file mode 100644
index 000000000..86e556ca3
--- /dev/null
+++ b/tinyc/include/stdarg.h
@@ -0,0 +1,67 @@
+#ifndef _STDARG_H
+#define _STDARG_H
+
+#ifdef __x86_64__
+#include <stdlib.h>
+
+/* GCC compatible definition of va_list. */
+struct __va_list_struct {
+    unsigned int gp_offset;
+    unsigned int fp_offset;
+    union {
+        unsigned int overflow_offset;
+        char *overflow_arg_area;
+    };
+    char *reg_save_area;
+};
+
+typedef struct __va_list_struct *va_list;
+
+/* we use __builtin_(malloc|free) to avoid #define malloc tcc_malloc */
+/* XXX: this lacks the support of aggregated types. */
+#define va_start(ap, last)                                              \
+    (ap = (va_list)__builtin_malloc(sizeof(struct __va_list_struct)),   \
+     *ap = *(struct __va_list_struct*)(                                 \
+         (char*)__builtin_frame_address(0) - 16),                       \
+     ap->overflow_arg_area = ((char *)__builtin_frame_address(0) +      \
+                              ap->overflow_offset),                     \
+     ap->reg_save_area = (char *)__builtin_frame_address(0) - 176 - 16  \
+        )
+#define va_arg(ap, type)                                        \
+    (*(type*)(__builtin_types_compatible_p(type, long double)   \
+              ? (ap->overflow_arg_area += 16,                   \
+                 ap->overflow_arg_area - 16)                    \
+              : __builtin_types_compatible_p(type, double)      \
+              ? (ap->fp_offset < 128 + 48                       \
+                 ? (ap->fp_offset += 16,                        \
+                    ap->reg_save_area + ap->fp_offset - 16)     \
+                 : (ap->overflow_arg_area += 8,                 \
+                    ap->overflow_arg_area - 8))                 \
+              : (ap->gp_offset < 48                             \
+                 ? (ap->gp_offset += 8,                         \
+                    ap->reg_save_area + ap->gp_offset - 8)      \
+                 : (ap->overflow_arg_area += 8,                 \
+                    ap->overflow_arg_area - 8))                 \
+        ))
+#define va_copy(dest, src)                                      \
+    ((dest) = (va_list)malloc(sizeof(struct __va_list_struct)), \
+     *(dest) = *(src))
+#define va_end(ap) __builtin_free(ap)
+
+#else
+
+typedef char *va_list;
+
+/* only correct for i386 */
+#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
+#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
+#define va_copy(dest, src) (dest) = (src)
+#define va_end(ap)
+
+#endif
+
+/* fix a buggy dependency on GCC in libio.h */
+typedef va_list __gnuc_va_list;
+#define _VA_LIST_DEFINED
+
+#endif /* _STDARG_H */
diff --git a/tinyc/include/stdbool.h b/tinyc/include/stdbool.h
new file mode 100644
index 000000000..6ed13a611
--- /dev/null
+++ b/tinyc/include/stdbool.h
@@ -0,0 +1,10 @@
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+/* ISOC99 boolean */
+
+#define bool	_Bool
+#define true	1
+#define false	0
+
+#endif /* _STDBOOL_H */
diff --git a/tinyc/include/stddef.h b/tinyc/include/stddef.h
new file mode 100644
index 000000000..aef5b3923
--- /dev/null
+++ b/tinyc/include/stddef.h
@@ -0,0 +1,20 @@
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#define NULL ((void *)0)
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+
+#ifndef __int8_t_defined
+#define __int8_t_defined
+typedef char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+typedef long long int int64_t;
+#endif
+
+void *alloca(size_t size);
+
+#endif
diff --git a/tinyc/include/tcclib.h b/tinyc/include/tcclib.h
new file mode 100644
index 000000000..42f8f3f57
--- /dev/null
+++ b/tinyc/include/tcclib.h
@@ -0,0 +1,78 @@
+/* Simple libc header for TCC 
+ * 
+ * Add any function you want from the libc there. This file is here
+ * only for your convenience so that you do not need to put the whole
+ * glibc include files on your floppy disk 
+ */
+#ifndef _TCCLIB_H
+#define _TCCLIB_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+/* stdlib.h */
+void *calloc(size_t nmemb, size_t size);
+void *malloc(size_t size);
+void free(void *ptr);
+void *realloc(void *ptr, size_t size);
+int atoi(const char *nptr);
+long int strtol(const char *nptr, char **endptr, int base);
+unsigned long int strtoul(const char *nptr, char **endptr, int base);
+void exit(int);
+
+/* stdio.h */
+typedef struct __FILE FILE;
+#define EOF (-1)
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+FILE *fopen(const char *path, const char *mode);
+FILE *fdopen(int fildes, const char *mode);
+FILE *freopen(const  char *path, const char *mode, FILE *stream);
+int fclose(FILE *stream);
+size_t  fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
+size_t  fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
+int fgetc(FILE *stream);
+char *fgets(char *s, int size, FILE *stream);
+int getc(FILE *stream);
+int getchar(void);
+char *gets(char *s);
+int ungetc(int c, FILE *stream);
+int fflush(FILE *stream);
+
+int printf(const char *format, ...);
+int fprintf(FILE *stream, const char *format, ...);
+int sprintf(char *str, const char *format, ...);
+int snprintf(char *str, size_t size, const  char  *format, ...);
+int asprintf(char **strp, const char *format, ...);
+int dprintf(int fd, const char *format, ...);
+int vprintf(const char *format, va_list ap);
+int vfprintf(FILE  *stream,  const  char *format, va_list ap);
+int vsprintf(char *str, const char *format, va_list ap);
+int vsnprintf(char *str, size_t size, const char  *format, va_list ap);
+int vasprintf(char  **strp,  const  char *format, va_list ap);
+int vdprintf(int fd, const char *format, va_list ap);
+
+void perror(const char *s);
+
+/* string.h */
+char *strcat(char *dest, const char *src);
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+char *strcpy(char *dest, const char *src);
+void *memcpy(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+void *memset(void *s, int c, size_t n);
+char *strdup(const char *s);
+
+/* dlfcn.h */
+#define RTLD_LAZY       0x001
+#define RTLD_NOW        0x002
+#define RTLD_GLOBAL     0x100
+
+void *dlopen(const char *filename, int flag);
+const char *dlerror(void);
+void *dlsym(void *handle, char *symbol);
+int dlclose(void *handle);
+
+#endif /* _TCCLIB_H */
diff --git a/tinyc/include/varargs.h b/tinyc/include/varargs.h
new file mode 100644
index 000000000..daee29e87
--- /dev/null
+++ b/tinyc/include/varargs.h
@@ -0,0 +1,11 @@
+#ifndef _VARARGS_H
+#define _VARARGS_H
+
+#include <stdarg.h>
+
+#define va_dcl
+#define va_alist __va_alist
+#undef va_start
+#define va_start(ap) ap = __builtin_varargs_start
+
+#endif
diff --git a/tinyc/lib/alloca86-bt.S b/tinyc/lib/alloca86-bt.S
new file mode 100644
index 000000000..994da2042
--- /dev/null
+++ b/tinyc/lib/alloca86-bt.S
@@ -0,0 +1,45 @@
+/* ---------------------------------------------- */
+/* alloca86b.S */
+
+#include "../config.h"
+
+.globl __bound_alloca
+
+__bound_alloca:
+    pop     %edx
+    pop     %eax
+    mov     %eax, %ecx
+    add     $3,%eax
+    and     $-4,%eax
+    jz      p6
+
+#ifdef TCC_TARGET_PE
+p4:
+    cmp     $4096,%eax
+    jle     p5
+    sub     $4096,%esp
+    sub     $4096,%eax
+    test    %eax,(%esp)
+    jmp p4
+
+p5:
+#endif
+
+    sub     %eax,%esp
+    mov     %esp,%eax
+
+    push    %edx
+    push    %eax
+    push    %ecx
+    push    %eax
+    call   __bound_new_region
+    add    $8, %esp
+    pop     %eax
+    pop     %edx
+
+p6:
+    push    %edx
+    push    %edx
+    ret
+
+/* ---------------------------------------------- */
diff --git a/tinyc/lib/alloca86.S b/tinyc/lib/alloca86.S
new file mode 100644
index 000000000..fb208a0ba
--- /dev/null
+++ b/tinyc/lib/alloca86.S
@@ -0,0 +1,33 @@
+/* ---------------------------------------------- */
+/* alloca86.S */
+
+#include "../config.h"
+
+.globl alloca
+
+alloca:
+    pop     %edx
+    pop     %eax
+    add     $3,%eax
+    and     $-4,%eax
+    jz      p3
+
+#ifdef TCC_TARGET_PE
+p1:
+    cmp     $4096,%eax
+    jle     p2
+    sub     $4096,%esp
+    sub     $4096,%eax
+    test    %eax,(%esp)
+    jmp p1
+p2:
+#endif
+
+    sub     %eax,%esp
+    mov     %esp,%eax
+p3:
+    push    %edx
+    push    %edx
+    ret
+
+/* ---------------------------------------------- */
diff --git a/tinyc/lib/bcheck.c b/tinyc/lib/bcheck.c
new file mode 100644
index 000000000..c59d04eb8
--- /dev/null
+++ b/tinyc/lib/bcheck.c
@@ -0,0 +1,868 @@
+/*
+ *  Tiny C Memory and bounds checker
+ * 
+ *  Copyright (c) 2002 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#if !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
+#include <malloc.h>
+#endif
+
+//#define BOUND_DEBUG
+
+/* define so that bound array is static (faster, but use memory if
+   bound checking not used) */
+//#define BOUND_STATIC
+
+/* use malloc hooks. Currently the code cannot be reliable if no hooks */
+#define CONFIG_TCC_MALLOC_HOOKS
+
+#define HAVE_MEMALIGN
+
+#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
+    || defined(__UCLIBC__) || defined(__OpenBSD__)
+#warning Bound checking not fully supported in this environment.
+#undef CONFIG_TCC_MALLOC_HOOKS
+#undef HAVE_MEMALIGN
+#endif
+
+#define BOUND_T1_BITS 13
+#define BOUND_T2_BITS 11
+#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
+
+#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
+#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
+#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
+#define BOUND_E_BITS  4
+
+#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
+#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
+
+
+/* this pointer is generated when bound check is incorrect */
+#define INVALID_POINTER ((void *)(-2))
+/* size of an empty region */
+#define EMPTY_SIZE        0xffffffff
+/* size of an invalid region */
+#define INVALID_SIZE      0
+
+typedef struct BoundEntry {
+    unsigned long start;
+    unsigned long size;
+    struct BoundEntry *next;
+    unsigned long is_invalid; /* true if pointers outside region are invalid */
+} BoundEntry;
+
+/* external interface */
+void __bound_init(void);
+void __bound_new_region(void *p, unsigned long size);
+int __bound_delete_region(void *p);
+
+#define FASTCALL __attribute__((regparm(3)))
+
+void *__bound_malloc(size_t size, const void *caller);
+void *__bound_memalign(size_t size, size_t align, const void *caller);
+void __bound_free(void *ptr, const void *caller);
+void *__bound_realloc(void *ptr, size_t size, const void *caller);
+static void *libc_malloc(size_t size);
+static void libc_free(void *ptr);
+static void install_malloc_hooks(void);
+static void restore_malloc_hooks(void);
+
+#ifdef CONFIG_TCC_MALLOC_HOOKS
+static void *saved_malloc_hook;
+static void *saved_free_hook;
+static void *saved_realloc_hook;
+static void *saved_memalign_hook;
+#endif
+
+/* linker definitions */
+extern char _end;
+
+/* TCC definitions */
+extern char __bounds_start; /* start of static bounds table */
+/* error message, just for TCC */
+const char *__bound_error_msg;
+
+/* runtime error output */
+extern void rt_error(unsigned long pc, const char *fmt, ...);
+
+#ifdef BOUND_STATIC
+static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
+#else
+static BoundEntry **__bound_t1; /* page table */
+#endif
+static BoundEntry *__bound_empty_t2;   /* empty page, for unused pages */
+static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
+
+static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
+{
+    unsigned long addr, tmp;
+    BoundEntry *e;
+
+    e = e1;
+    while (e != NULL) {
+        addr = (unsigned long)p;
+        addr -= e->start;
+        if (addr <= e->size) {
+            /* put region at the head */
+            tmp = e1->start;
+            e1->start = e->start;
+            e->start = tmp;
+            tmp = e1->size;
+            e1->size = e->size;
+            e->size = tmp;
+            return e1;
+        }
+        e = e->next;
+    }
+    /* no entry found: return empty entry or invalid entry */
+    if (e1->is_invalid)
+        return __bound_invalid_t2;
+    else
+        return __bound_empty_t2;
+}
+
+/* print a bound error message */
+static void bound_error(const char *fmt, ...)
+{
+    __bound_error_msg = fmt;
+    *(int *)0 = 0; /* force a runtime error */
+}
+
+static void bound_alloc_error(void)
+{
+    bound_error("not enough memory for bound checking code");
+}
+
+/* currently, tcc cannot compile that because we use GNUC extensions */
+#if !defined(__TINYC__)
+
+/* return '(p + offset)' for pointer arithmetic (a pointer can reach
+   the end of a region in this case */
+void * FASTCALL __bound_ptr_add(void *p, int offset)
+{
+    unsigned long addr = (unsigned long)p;
+    BoundEntry *e;
+#if defined(BOUND_DEBUG)
+    printf("add: 0x%x %d\n", (int)p, offset);
+#endif
+
+    e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
+    e = (BoundEntry *)((char *)e + 
+                       ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & 
+                        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
+    addr -= e->start;
+    if (addr > e->size) {
+        e = __bound_find_region(e, p);
+        addr = (unsigned long)p - e->start;
+    }
+    addr += offset;
+    if (addr > e->size)
+        return INVALID_POINTER; /* return an invalid pointer */
+    return p + offset;
+}
+
+/* return '(p + offset)' for pointer indirection (the resulting must
+   be strictly inside the region */
+#define BOUND_PTR_INDIR(dsize)                                          \
+void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset)        \
+{                                                                       \
+    unsigned long addr = (unsigned long)p;                              \
+    BoundEntry *e;                                                      \
+                                                                        \
+    e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];            \
+    e = (BoundEntry *)((char *)e +                                      \
+                       ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &      \
+                        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));        \
+    addr -= e->start;                                                   \
+    if (addr > e->size) {                                               \
+        e = __bound_find_region(e, p);                                  \
+        addr = (unsigned long)p - e->start;                             \
+    }                                                                   \
+    addr += offset + dsize;                                             \
+    if (addr > e->size)                                                 \
+        return INVALID_POINTER; /* return an invalid pointer */         \
+    return p + offset;                                                  \
+}
+
+#ifdef __i386__
+/* return the frame pointer of the caller */
+#define GET_CALLER_FP(fp)\
+{\
+    unsigned long *fp1;\
+    __asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
+    fp = fp1[0];\
+}
+#else
+#error put code to extract the calling frame pointer
+#endif
+
+/* called when entering a function to add all the local regions */
+void FASTCALL __bound_local_new(void *p1) 
+{
+    unsigned long addr, size, fp, *p = p1;
+    GET_CALLER_FP(fp);
+    for(;;) {
+        addr = p[0];
+        if (addr == 0)
+            break;
+        addr += fp;
+        size = p[1];
+        p += 2;
+        __bound_new_region((void *)addr, size);
+    }
+}
+
+/* called when leaving a function to delete all the local regions */
+void FASTCALL __bound_local_delete(void *p1) 
+{
+    unsigned long addr, fp, *p = p1;
+    GET_CALLER_FP(fp);
+    for(;;) {
+        addr = p[0];
+        if (addr == 0)
+            break;
+        addr += fp;
+        p += 2;
+        __bound_delete_region((void *)addr);
+    }
+}
+
+#else
+
+void __bound_local_new(void *p) 
+{
+}
+void __bound_local_delete(void *p) 
+{
+}
+
+void *__bound_ptr_add(void *p, int offset)
+{
+    return p + offset;
+}
+
+#define BOUND_PTR_INDIR(dsize)                               \
+void *__bound_ptr_indir ## dsize (void *p, int offset)       \
+{                                                            \
+    return p + offset;                                       \
+}
+#endif
+
+BOUND_PTR_INDIR(1)
+BOUND_PTR_INDIR(2)
+BOUND_PTR_INDIR(4)
+BOUND_PTR_INDIR(8)
+BOUND_PTR_INDIR(12)
+BOUND_PTR_INDIR(16)
+
+static BoundEntry *__bound_new_page(void)
+{
+    BoundEntry *page;
+    int i;
+
+    page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
+    if (!page)
+        bound_alloc_error();
+    for(i=0;i<BOUND_T2_SIZE;i++) {
+        /* put empty entries */
+        page[i].start = 0;
+        page[i].size = EMPTY_SIZE;
+        page[i].next = NULL;
+        page[i].is_invalid = 0;
+    }
+    return page;
+}
+
+/* currently we use malloc(). Should use bound_new_page() */
+static BoundEntry *bound_new_entry(void)
+{
+    BoundEntry *e;
+    e = libc_malloc(sizeof(BoundEntry));
+    return e;
+}
+
+static void bound_free_entry(BoundEntry *e)
+{
+    libc_free(e);
+}
+
+static inline BoundEntry *get_page(int index)
+{
+    BoundEntry *page;
+    page = __bound_t1[index];
+    if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
+        /* create a new page if necessary */
+        page = __bound_new_page();
+        __bound_t1[index] = page;
+    }
+    return page;
+}
+
+/* mark a region as being invalid (can only be used during init) */
+static void mark_invalid(unsigned long addr, unsigned long size)
+{
+    unsigned long start, end;
+    BoundEntry *page;
+    int t1_start, t1_end, i, j, t2_start, t2_end;
+
+    start = addr;
+    end = addr + size;
+
+    t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
+    if (end != 0)
+        t2_end = end >> BOUND_T3_BITS;
+    else
+        t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
+
+#if 0
+    printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
+#endif
+    
+    /* first we handle full pages */
+    t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
+    t1_end = t2_end >> BOUND_T2_BITS;
+
+    i = t2_start & (BOUND_T2_SIZE - 1);
+    j = t2_end & (BOUND_T2_SIZE - 1);
+    
+    if (t1_start == t1_end) {
+        page = get_page(t2_start >> BOUND_T2_BITS);
+        for(; i < j; i++) {
+            page[i].size = INVALID_SIZE;
+            page[i].is_invalid = 1;
+        }
+    } else {
+        if (i > 0) {
+            page = get_page(t2_start >> BOUND_T2_BITS);
+            for(; i < BOUND_T2_SIZE; i++) {
+                page[i].size = INVALID_SIZE;
+                page[i].is_invalid = 1;
+            }
+        }
+        for(i = t1_start; i < t1_end; i++) {
+            __bound_t1[i] = __bound_invalid_t2;
+        }
+        if (j != 0) {
+            page = get_page(t1_end);
+            for(i = 0; i < j; i++) {
+                page[i].size = INVALID_SIZE;
+                page[i].is_invalid = 1;
+            }
+        }
+    }
+}
+
+void __bound_init(void)
+{
+    int i;
+    BoundEntry *page;
+    unsigned long start, size;
+    int *p;
+
+    /* save malloc hooks and install bound check hooks */
+    install_malloc_hooks();
+
+#ifndef BOUND_STATIC
+    __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
+    if (!__bound_t1)
+        bound_alloc_error();
+#endif
+    __bound_empty_t2 = __bound_new_page();
+    for(i=0;i<BOUND_T1_SIZE;i++) {
+        __bound_t1[i] = __bound_empty_t2;
+    }
+
+    page = __bound_new_page();
+    for(i=0;i<BOUND_T2_SIZE;i++) {
+        /* put invalid entries */
+        page[i].start = 0;
+        page[i].size = INVALID_SIZE;
+        page[i].next = NULL;
+        page[i].is_invalid = 1;
+    }
+    __bound_invalid_t2 = page;
+
+    /* invalid pointer zone */
+    start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
+    size = BOUND_T23_SIZE;
+    mark_invalid(start, size);
+
+#if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS)
+    /* malloc zone is also marked invalid. can only use that with
+       hooks because all libs should use the same malloc. The solution
+       would be to build a new malloc for tcc. */
+    start = (unsigned long)&_end;
+    size = 128 * 0x100000;
+    mark_invalid(start, size);
+#endif
+
+    /* add all static bound check values */
+    p = (int *)&__bounds_start;
+    while (p[0] != 0) {
+        __bound_new_region((void *)p[0], p[1]);
+        p += 2;
+    }
+}
+
+static inline void add_region(BoundEntry *e, 
+                              unsigned long start, unsigned long size)
+{
+    BoundEntry *e1;
+    if (e->start == 0) {
+        /* no region : add it */
+        e->start = start;
+        e->size = size;
+    } else {
+        /* already regions in the list: add it at the head */
+        e1 = bound_new_entry();
+        e1->start = e->start;
+        e1->size = e->size;
+        e1->next = e->next;
+        e->start = start;
+        e->size = size;
+        e->next = e1;
+    }
+}
+
+/* create a new region. It should not already exist in the region list */
+void __bound_new_region(void *p, unsigned long size)
+{
+    unsigned long start, end;
+    BoundEntry *page, *e, *e2;
+    int t1_start, t1_end, i, t2_start, t2_end;
+
+    start = (unsigned long)p;
+    end = start + size;
+    t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
+    t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
+
+    /* start */
+    page = get_page(t1_start);
+    t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & 
+        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
+    t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & 
+        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
+#ifdef BOUND_DEBUG
+    printf("new %lx %lx %x %x %x %x\n", 
+           start, end, t1_start, t1_end, t2_start, t2_end);
+#endif
+
+    e = (BoundEntry *)((char *)page + t2_start);
+    add_region(e, start, size);
+
+    if (t1_end == t1_start) {
+        /* same ending page */
+        e2 = (BoundEntry *)((char *)page + t2_end);
+        if (e2 > e) {
+            e++;
+            for(;e<e2;e++) {
+                e->start = start;
+                e->size = size;
+            }
+            add_region(e, start, size);
+        }
+    } else {
+        /* mark until end of page */
+        e2 = page + BOUND_T2_SIZE;
+        e++;
+        for(;e<e2;e++) {
+            e->start = start;
+            e->size = size;
+        }
+        /* mark intermediate pages, if any */
+        for(i=t1_start+1;i<t1_end;i++) {
+            page = get_page(i);
+            e2 = page + BOUND_T2_SIZE;
+            for(e=page;e<e2;e++) {
+                e->start = start;
+                e->size = size;
+            }
+        }
+        /* last page */
+        page = get_page(t1_end);
+        e2 = (BoundEntry *)((char *)page + t2_end);
+        for(e=page;e<e2;e++) {
+            e->start = start;
+            e->size = size;
+        }
+        add_region(e, start, size);
+    }
+}
+
+/* delete a region */
+static inline void delete_region(BoundEntry *e, 
+                                 void *p, unsigned long empty_size)
+{
+    unsigned long addr;
+    BoundEntry *e1;
+
+    addr = (unsigned long)p;
+    addr -= e->start;
+    if (addr <= e->size) {
+        /* region found is first one */
+        e1 = e->next;
+        if (e1 == NULL) {
+            /* no more region: mark it empty */
+            e->start = 0;
+            e->size = empty_size;
+        } else {
+            /* copy next region in head */
+            e->start = e1->start;
+            e->size = e1->size;
+            e->next = e1->next;
+            bound_free_entry(e1);
+        }
+    } else {
+        /* find the matching region */
+        for(;;) {
+            e1 = e;
+            e = e->next;
+            /* region not found: do nothing */
+            if (e == NULL)
+                break;
+            addr = (unsigned long)p - e->start;
+            if (addr <= e->size) {
+                /* found: remove entry */
+                e1->next = e->next;
+                bound_free_entry(e);
+                break;
+            }
+        }
+    }
+}
+
+/* WARNING: 'p' must be the starting point of the region. */
+/* return non zero if error */
+int __bound_delete_region(void *p)
+{
+    unsigned long start, end, addr, size, empty_size;
+    BoundEntry *page, *e, *e2;
+    int t1_start, t1_end, t2_start, t2_end, i;
+
+    start = (unsigned long)p;
+    t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
+    t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & 
+        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
+    
+    /* find region size */
+    page = __bound_t1[t1_start];
+    e = (BoundEntry *)((char *)page + t2_start);
+    addr = start - e->start;
+    if (addr > e->size)
+        e = __bound_find_region(e, p);
+    /* test if invalid region */
+    if (e->size == EMPTY_SIZE || (unsigned long)p != e->start) 
+        return -1;
+    /* compute the size we put in invalid regions */
+    if (e->is_invalid)
+        empty_size = INVALID_SIZE;
+    else
+        empty_size = EMPTY_SIZE;
+    size = e->size;
+    end = start + size;
+
+    /* now we can free each entry */
+    t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
+    t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & 
+        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
+
+    delete_region(e, p, empty_size);
+    if (t1_end == t1_start) {
+        /* same ending page */
+        e2 = (BoundEntry *)((char *)page + t2_end);
+        if (e2 > e) {
+            e++;
+            for(;e<e2;e++) {
+                e->start = 0;
+                e->size = empty_size;
+            }
+            delete_region(e, p, empty_size);
+        }
+    } else {
+        /* mark until end of page */
+        e2 = page + BOUND_T2_SIZE;
+        e++;
+        for(;e<e2;e++) {
+            e->start = 0;
+            e->size = empty_size;
+        }
+        /* mark intermediate pages, if any */
+        /* XXX: should free them */
+        for(i=t1_start+1;i<t1_end;i++) {
+            page = get_page(i);
+            e2 = page + BOUND_T2_SIZE;
+            for(e=page;e<e2;e++) {
+                e->start = 0;
+                e->size = empty_size;
+            }
+        }
+        /* last page */
+        page = get_page(t2_end);
+        e2 = (BoundEntry *)((char *)page + t2_end);
+        for(e=page;e<e2;e++) {
+            e->start = 0;
+            e->size = empty_size;
+        }
+        delete_region(e, p, empty_size);
+    }
+    return 0;
+}
+
+/* return the size of the region starting at p, or EMPTY_SIZE if non
+   existent region. */
+static unsigned long get_region_size(void *p)
+{
+    unsigned long addr = (unsigned long)p;
+    BoundEntry *e;
+
+    e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
+    e = (BoundEntry *)((char *)e + 
+                       ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & 
+                        ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
+    addr -= e->start;
+    if (addr > e->size)
+        e = __bound_find_region(e, p);
+    if (e->start != (unsigned long)p)
+        return EMPTY_SIZE;
+    return e->size;
+}
+
+/* patched memory functions */
+
+static void install_malloc_hooks(void)
+{
+#ifdef CONFIG_TCC_MALLOC_HOOKS
+    saved_malloc_hook = __malloc_hook;
+    saved_free_hook = __free_hook;
+    saved_realloc_hook = __realloc_hook;
+    saved_memalign_hook = __memalign_hook;
+    __malloc_hook = __bound_malloc;
+    __free_hook = __bound_free;
+    __realloc_hook = __bound_realloc;
+    __memalign_hook = __bound_memalign;
+#endif
+}
+
+static void restore_malloc_hooks(void)
+{
+#ifdef CONFIG_TCC_MALLOC_HOOKS
+    __malloc_hook = saved_malloc_hook;
+    __free_hook = saved_free_hook;
+    __realloc_hook = saved_realloc_hook;
+    __memalign_hook = saved_memalign_hook;
+#endif
+}
+
+static void *libc_malloc(size_t size)
+{
+    void *ptr;
+    restore_malloc_hooks();
+    ptr = malloc(size);
+    install_malloc_hooks();
+    return ptr;
+}
+
+static void libc_free(void *ptr)
+{
+    restore_malloc_hooks();
+    free(ptr);
+    install_malloc_hooks();
+}
+
+/* XXX: we should use a malloc which ensure that it is unlikely that
+   two malloc'ed data have the same address if 'free' are made in
+   between. */
+void *__bound_malloc(size_t size, const void *caller)
+{
+    void *ptr;
+    
+    /* we allocate one more byte to ensure the regions will be
+       separated by at least one byte. With the glibc malloc, it may
+       be in fact not necessary */
+    ptr = libc_malloc(size + 1);
+    
+    if (!ptr)
+        return NULL;
+    __bound_new_region(ptr, size);
+    return ptr;
+}
+
+void *__bound_memalign(size_t size, size_t align, const void *caller)
+{
+    void *ptr;
+
+    restore_malloc_hooks();
+
+#ifndef HAVE_MEMALIGN
+    if (align > 4) {
+        /* XXX: handle it ? */
+        ptr = NULL;
+    } else {
+        /* we suppose that malloc aligns to at least four bytes */
+        ptr = malloc(size + 1);
+    }
+#else
+    /* we allocate one more byte to ensure the regions will be
+       separated by at least one byte. With the glibc malloc, it may
+       be in fact not necessary */
+    ptr = memalign(size + 1, align);
+#endif
+    
+    install_malloc_hooks();
+    
+    if (!ptr)
+        return NULL;
+    __bound_new_region(ptr, size);
+    return ptr;
+}
+
+void __bound_free(void *ptr, const void *caller)
+{
+    if (ptr == NULL)
+        return;
+    if (__bound_delete_region(ptr) != 0)
+        bound_error("freeing invalid region");
+
+    libc_free(ptr);
+}
+
+void *__bound_realloc(void *ptr, size_t size, const void *caller)
+{
+    void *ptr1;
+    int old_size;
+
+    if (size == 0) {
+        __bound_free(ptr, caller);
+        return NULL;
+    } else {
+        ptr1 = __bound_malloc(size, caller);
+        if (ptr == NULL || ptr1 == NULL)
+            return ptr1;
+        old_size = get_region_size(ptr);
+        if (old_size == EMPTY_SIZE)
+            bound_error("realloc'ing invalid pointer");
+        memcpy(ptr1, ptr, old_size);
+        __bound_free(ptr, caller);
+        return ptr1;
+    }
+}
+
+#ifndef CONFIG_TCC_MALLOC_HOOKS
+void *__bound_calloc(size_t nmemb, size_t size)
+{
+    void *ptr;
+    size = size * nmemb;
+    ptr = __bound_malloc(size, NULL);
+    if (!ptr)
+        return NULL;
+    memset(ptr, 0, size);
+    return ptr;
+}
+#endif
+
+#if 0
+static void bound_dump(void)
+{
+    BoundEntry *page, *e;
+    int i, j;
+
+    printf("region dump:\n");
+    for(i=0;i<BOUND_T1_SIZE;i++) {
+        page = __bound_t1[i];
+        for(j=0;j<BOUND_T2_SIZE;j++) {
+            e = page + j;
+            /* do not print invalid or empty entries */
+            if (e->size != EMPTY_SIZE && e->start != 0) {
+                printf("%08x:", 
+                       (i << (BOUND_T2_BITS + BOUND_T3_BITS)) + 
+                       (j << BOUND_T3_BITS));
+                do {
+                    printf(" %08lx:%08lx", e->start, e->start + e->size);
+                    e = e->next;
+                } while (e != NULL);
+                printf("\n");
+            }
+        }
+    }
+}
+#endif
+
+/* some useful checked functions */
+
+/* check that (p ... p + size - 1) lies inside 'p' region, if any */
+static void __bound_check(const void *p, size_t size)
+{
+    if (size == 0)
+        return;
+    p = __bound_ptr_add((void *)p, size);
+    if (p == INVALID_POINTER)
+        bound_error("invalid pointer");
+}
+
+void *__bound_memcpy(void *dst, const void *src, size_t size)
+{
+    __bound_check(dst, size);
+    __bound_check(src, size);
+    /* check also region overlap */
+    if (src >= dst && src < dst + size)
+        bound_error("overlapping regions in memcpy()");
+    return memcpy(dst, src, size);
+}
+
+void *__bound_memmove(void *dst, const void *src, size_t size)
+{
+    __bound_check(dst, size);
+    __bound_check(src, size);
+    return memmove(dst, src, size);
+}
+
+void *__bound_memset(void *dst, int c, size_t size)
+{
+    __bound_check(dst, size);
+    return memset(dst, c, size);
+}
+
+/* XXX: could be optimized */
+int __bound_strlen(const char *s)
+{
+    const char *p;
+    int len;
+
+    len = 0;
+    for(;;) {
+        p = __bound_ptr_indir1((char *)s, len);
+        if (p == INVALID_POINTER)
+            bound_error("bad pointer in strlen()");
+        if (*p == '\0')
+            break;
+        len++;
+    }
+    return len;
+}
+
+char *__bound_strcpy(char *dst, const char *src)
+{
+    int len;
+    len = __bound_strlen(src);
+    return __bound_memcpy(dst, src, len + 1);
+}
+
diff --git a/tinyc/lib/libtcc1.c b/tinyc/lib/libtcc1.c
new file mode 100644
index 000000000..b079477e4
--- /dev/null
+++ b/tinyc/lib/libtcc1.c
@@ -0,0 +1,607 @@
+/* TCC runtime library. 
+   Parts of this code are (c) 2002 Fabrice Bellard 
+
+   Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+This file 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  
+*/
+
+#define W_TYPE_SIZE   32
+#define BITS_PER_UNIT 8
+
+typedef int Wtype;
+typedef unsigned int UWtype;
+typedef unsigned int USItype;
+typedef long long DWtype;
+typedef unsigned long long UDWtype;
+
+struct DWstruct {
+    Wtype low, high;
+};
+
+typedef union
+{
+  struct DWstruct s;
+  DWtype ll;
+} DWunion;
+
+typedef long double XFtype;
+#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
+#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
+
+/* the following deal with IEEE single-precision numbers */
+#define EXCESS		126
+#define SIGNBIT		0x80000000
+#define HIDDEN		(1 << 23)
+#define SIGN(fp)	((fp) & SIGNBIT)
+#define EXP(fp)		(((fp) >> 23) & 0xFF)
+#define MANT(fp)	(((fp) & 0x7FFFFF) | HIDDEN)
+#define PACK(s,e,m)	((s) | ((e) << 23) | (m))
+
+/* the following deal with IEEE double-precision numbers */
+#define EXCESSD		1022
+#define HIDDEND		(1 << 20)
+#define EXPD(fp)	(((fp.l.upper) >> 20) & 0x7FF)
+#define SIGND(fp)	((fp.l.upper) & SIGNBIT)
+#define MANTD(fp)	(((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
+				(fp.l.lower >> 22))
+#define HIDDEND_LL	((long long)1 << 52)
+#define MANTD_LL(fp)	((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
+#define PACKD_LL(s,e,m)	(((long long)((s)+((e)<<20))<<32)|(m))
+
+/* the following deal with x86 long double-precision numbers */
+#define EXCESSLD	16382
+#define EXPLD(fp)	(fp.l.upper & 0x7fff)
+#define SIGNLD(fp)	((fp.l.upper) & 0x8000)
+
+/* only for x86 */
+union ldouble_long {
+    long double ld;
+    struct {
+        unsigned long long lower;
+        unsigned short upper;
+    } l;
+};
+
+union double_long {
+    double d;
+#if 1
+    struct {
+        unsigned int lower;
+        int upper;
+    } l;
+#else
+    struct {
+        int upper;
+        unsigned int lower;
+    } l;
+#endif
+    long long ll;
+};
+
+union float_long {
+    float f;
+    long l;
+};
+
+/* XXX: we don't support several builtin supports for now */
+#ifndef __x86_64__
+
+/* XXX: use gcc/tcc intrinsic ? */
+#if defined(__i386__)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subl %5,%1\n\tsbbl %3,%0"					\
+	   : "=r" ((USItype) (sh)),					\
+	     "=&r" ((USItype) (sl))					\
+	   : "0" ((USItype) (ah)),					\
+	     "g" ((USItype) (bh)),					\
+	     "1" ((USItype) (al)),					\
+	     "g" ((USItype) (bl)))
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mull %3"							\
+	   : "=a" ((USItype) (w0)),					\
+	     "=d" ((USItype) (w1))					\
+	   : "%0" ((USItype) (u)),					\
+	     "rm" ((USItype) (v)))
+#define udiv_qrnnd(q, r, n1, n0, dv) \
+  __asm__ ("divl %4"							\
+	   : "=a" ((USItype) (q)),					\
+	     "=d" ((USItype) (r))					\
+	   : "0" ((USItype) (n0)),					\
+	     "1" ((USItype) (n1)),					\
+	     "rm" ((USItype) (dv)))
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __cbtmp;							\
+    __asm__ ("bsrl %1,%0"						\
+	     : "=r" (__cbtmp) : "rm" ((USItype) (x)));			\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#else
+#error unsupported CPU type
+#endif
+
+/* most of this code is taken from libgcc2.c from gcc */
+
+static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
+{
+  DWunion ww;
+  DWunion nn, dd;
+  DWunion rr;
+  UWtype d0, d1, n0, n1, n2;
+  UWtype q0, q1;
+  UWtype b, bm;
+
+  nn.ll = n;
+  dd.ll = d;
+
+  d0 = dd.s.low;
+  d1 = dd.s.high;
+  n0 = nn.s.low;
+  n1 = nn.s.high;
+
+#if !UDIV_NEEDS_NORMALIZATION
+  if (d1 == 0)
+    {
+      if (d0 > n1)
+	{
+	  /* 0q = nn / 0D */
+
+	  udiv_qrnnd (q0, n0, n1, n0, d0);
+	  q1 = 0;
+
+	  /* Remainder in n0.  */
+	}
+      else
+	{
+	  /* qq = NN / 0d */
+
+	  if (d0 == 0)
+	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
+
+	  udiv_qrnnd (q1, n1, 0, n1, d0);
+	  udiv_qrnnd (q0, n0, n1, n0, d0);
+
+	  /* Remainder in n0.  */
+	}
+
+      if (rp != 0)
+	{
+	  rr.s.low = n0;
+	  rr.s.high = 0;
+	  *rp = rr.ll;
+	}
+    }
+
+#else /* UDIV_NEEDS_NORMALIZATION */
+
+  if (d1 == 0)
+    {
+      if (d0 > n1)
+	{
+	  /* 0q = nn / 0D */
+
+	  count_leading_zeros (bm, d0);
+
+	  if (bm != 0)
+	    {
+	      /* Normalize, i.e. make the most significant bit of the
+		 denominator set.  */
+
+	      d0 = d0 << bm;
+	      n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
+	      n0 = n0 << bm;
+	    }
+
+	  udiv_qrnnd (q0, n0, n1, n0, d0);
+	  q1 = 0;
+
+	  /* Remainder in n0 >> bm.  */
+	}
+      else
+	{
+	  /* qq = NN / 0d */
+
+	  if (d0 == 0)
+	    d0 = 1 / d0;	/* Divide intentionally by zero.  */
+
+	  count_leading_zeros (bm, d0);
+
+	  if (bm == 0)
+	    {
+	      /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
+		 conclude (the most significant bit of n1 is set) /\ (the
+		 leading quotient digit q1 = 1).
+
+		 This special case is necessary, not an optimization.
+		 (Shifts counts of W_TYPE_SIZE are undefined.)  */
+
+	      n1 -= d0;
+	      q1 = 1;
+	    }
+	  else
+	    {
+	      /* Normalize.  */
+
+	      b = W_TYPE_SIZE - bm;
+
+	      d0 = d0 << bm;
+	      n2 = n1 >> b;
+	      n1 = (n1 << bm) | (n0 >> b);
+	      n0 = n0 << bm;
+
+	      udiv_qrnnd (q1, n1, n2, n1, d0);
+	    }
+
+	  /* n1 != d0...  */
+
+	  udiv_qrnnd (q0, n0, n1, n0, d0);
+
+	  /* Remainder in n0 >> bm.  */
+	}
+
+      if (rp != 0)
+	{
+	  rr.s.low = n0 >> bm;
+	  rr.s.high = 0;
+	  *rp = rr.ll;
+	}
+    }
+#endif /* UDIV_NEEDS_NORMALIZATION */
+
+  else
+    {
+      if (d1 > n1)
+	{
+	  /* 00 = nn / DD */
+
+	  q0 = 0;
+	  q1 = 0;
+
+	  /* Remainder in n1n0.  */
+	  if (rp != 0)
+	    {
+	      rr.s.low = n0;
+	      rr.s.high = n1;
+	      *rp = rr.ll;
+	    }
+	}
+      else
+	{
+	  /* 0q = NN / dd */
+
+	  count_leading_zeros (bm, d1);
+	  if (bm == 0)
+	    {
+	      /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
+		 conclude (the most significant bit of n1 is set) /\ (the
+		 quotient digit q0 = 0 or 1).
+
+		 This special case is necessary, not an optimization.  */
+
+	      /* The condition on the next line takes advantage of that
+		 n1 >= d1 (true due to program flow).  */
+	      if (n1 > d1 || n0 >= d0)
+		{
+		  q0 = 1;
+		  sub_ddmmss (n1, n0, n1, n0, d1, d0);
+		}
+	      else
+		q0 = 0;
+
+	      q1 = 0;
+
+	      if (rp != 0)
+		{
+		  rr.s.low = n0;
+		  rr.s.high = n1;
+		  *rp = rr.ll;
+		}
+	    }
+	  else
+	    {
+	      UWtype m1, m0;
+	      /* Normalize.  */
+
+	      b = W_TYPE_SIZE - bm;
+
+	      d1 = (d1 << bm) | (d0 >> b);
+	      d0 = d0 << bm;
+	      n2 = n1 >> b;
+	      n1 = (n1 << bm) | (n0 >> b);
+	      n0 = n0 << bm;
+
+	      udiv_qrnnd (q0, n1, n2, n1, d1);
+	      umul_ppmm (m1, m0, q0, d0);
+
+	      if (m1 > n1 || (m1 == n1 && m0 > n0))
+		{
+		  q0--;
+		  sub_ddmmss (m1, m0, m1, m0, d1, d0);
+		}
+
+	      q1 = 0;
+
+	      /* Remainder in (n1n0 - m1m0) >> bm.  */
+	      if (rp != 0)
+		{
+		  sub_ddmmss (n1, n0, n1, n0, m1, m0);
+		  rr.s.low = (n1 << b) | (n0 >> bm);
+		  rr.s.high = n1 >> bm;
+		  *rp = rr.ll;
+		}
+	    }
+	}
+    }
+
+  ww.s.low = q0;
+  ww.s.high = q1;
+  return ww.ll;
+}
+
+#define __negdi2(a) (-(a))
+
+long long __divdi3(long long u, long long v)
+{
+    int c = 0;
+    DWunion uu, vv;
+    DWtype w;
+    
+    uu.ll = u;
+    vv.ll = v;
+    
+    if (uu.s.high < 0) {
+        c = ~c;
+        uu.ll = __negdi2 (uu.ll);
+    }
+    if (vv.s.high < 0) {
+        c = ~c;
+        vv.ll = __negdi2 (vv.ll);
+    }
+    w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
+    if (c)
+        w = __negdi2 (w);
+    return w;
+}
+
+long long __moddi3(long long u, long long v)
+{
+    int c = 0;
+    DWunion uu, vv;
+    DWtype w;
+    
+    uu.ll = u;
+    vv.ll = v;
+    
+    if (uu.s.high < 0) {
+        c = ~c;
+        uu.ll = __negdi2 (uu.ll);
+    }
+    if (vv.s.high < 0)
+        vv.ll = __negdi2 (vv.ll);
+    
+    __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
+    if (c)
+        w = __negdi2 (w);
+    return w;
+}
+
+unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
+{
+    return __udivmoddi4 (u, v, (UDWtype *) 0);
+}
+
+unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
+{
+    UDWtype w;
+    
+    __udivmoddi4 (u, v, &w);
+    return w;
+}
+
+/* XXX: fix tcc's code generator to do this instead */
+long long __ashrdi3(long long a, int b)
+{
+#ifdef __TINYC__
+    DWunion u;
+    u.ll = a;
+    if (b >= 32) {
+        u.s.low = u.s.high >> (b - 32);
+        u.s.high = u.s.high >> 31;
+    } else if (b != 0) {
+        u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
+        u.s.high = u.s.high >> b;
+    }
+    return u.ll;
+#else
+    return a >> b;
+#endif
+}
+
+/* XXX: fix tcc's code generator to do this instead */
+unsigned long long __lshrdi3(unsigned long long a, int b)
+{
+#ifdef __TINYC__
+    DWunion u;
+    u.ll = a;
+    if (b >= 32) {
+        u.s.low = (unsigned)u.s.high >> (b - 32);
+        u.s.high = 0;
+    } else if (b != 0) {
+        u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
+        u.s.high = (unsigned)u.s.high >> b;
+    }
+    return u.ll;
+#else
+    return a >> b;
+#endif
+}
+
+/* XXX: fix tcc's code generator to do this instead */
+long long __ashldi3(long long a, int b)
+{
+#ifdef __TINYC__
+    DWunion u;
+    u.ll = a;
+    if (b >= 32) {
+        u.s.high = (unsigned)u.s.low << (b - 32);
+        u.s.low = 0;
+    } else if (b != 0) {
+        u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
+        u.s.low = (unsigned)u.s.low << b;
+    }
+    return u.ll;
+#else
+    return a << b;
+#endif
+}
+
+#if defined(__i386__)
+/* FPU control word for rounding to nearest mode */
+unsigned short __tcc_fpu_control = 0x137f;
+/* FPU control word for round to zero mode for int conversion */
+unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
+#endif
+
+#endif /* !__x86_64__ */
+
+/* XXX: fix tcc's code generator to do this instead */
+float __floatundisf(unsigned long long a)
+{
+    DWunion uu; 
+    XFtype r;
+
+    uu.ll = a;
+    if (uu.s.high >= 0) {
+        return (float)uu.ll;
+    } else {
+        r = (XFtype)uu.ll;
+        r += 18446744073709551616.0;
+        return (float)r;
+    }
+}
+
+double __floatundidf(unsigned long long a)
+{
+    DWunion uu; 
+    XFtype r;
+
+    uu.ll = a;
+    if (uu.s.high >= 0) {
+        return (double)uu.ll;
+    } else {
+        r = (XFtype)uu.ll;
+        r += 18446744073709551616.0;
+        return (double)r;
+    }
+}
+
+long double __floatundixf(unsigned long long a)
+{
+    DWunion uu; 
+    XFtype r;
+
+    uu.ll = a;
+    if (uu.s.high >= 0) {
+        return (long double)uu.ll;
+    } else {
+        r = (XFtype)uu.ll;
+        r += 18446744073709551616.0;
+        return (long double)r;
+    }
+}
+
+unsigned long long __fixunssfdi (float a1)
+{
+    register union float_long fl1;
+    register int exp;
+    register unsigned long l;
+
+    fl1.f = a1;
+
+    if (fl1.l == 0)
+	return (0);
+
+    exp = EXP (fl1.l) - EXCESS - 24;
+
+    l = MANT(fl1.l);
+    if (exp >= 41)
+	return (unsigned long long)-1;
+    else if (exp >= 0)
+        return (unsigned long long)l << exp;
+    else if (exp >= -23)
+        return l >> -exp;
+    else
+        return 0;
+}
+
+unsigned long long __fixunsdfdi (double a1)
+{
+    register union double_long dl1;
+    register int exp;
+    register unsigned long long l;
+
+    dl1.d = a1;
+
+    if (dl1.ll == 0)
+	return (0);
+
+    exp = EXPD (dl1) - EXCESSD - 53;
+
+    l = MANTD_LL(dl1);
+
+    if (exp >= 12)
+	return (unsigned long long)-1;
+    else if (exp >= 0)
+        return l << exp;
+    else if (exp >= -52)
+        return l >> -exp;
+    else
+        return 0;
+}
+
+unsigned long long __fixunsxfdi (long double a1)
+{
+    register union ldouble_long dl1;
+    register int exp;
+    register unsigned long long l;
+
+    dl1.ld = a1;
+
+    if (dl1.l.lower == 0 && dl1.l.upper == 0)
+	return (0);
+
+    exp = EXPLD (dl1) - EXCESSLD - 64;
+
+    l = dl1.l.lower;
+
+    if (exp > 0)
+	return (unsigned long long)-1;
+    else if (exp >= -63) 
+        return l >> -exp;
+    else
+        return 0;
+}
+
diff --git a/tinyc/libtcc.c b/tinyc/libtcc.c
new file mode 100644
index 000000000..0d8702b5f
--- /dev/null
+++ b/tinyc/libtcc.c
@@ -0,0 +1,2259 @@
+/*
+ *  TCC - Tiny C Compiler
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#include "tcc.h"
+
+/********************************************************/
+/* global variables */
+
+/* display benchmark infos */
+int total_lines;
+int total_bytes;
+
+/* parser */
+static struct BufferedFile *file;
+static int ch, tok;
+static CValue tokc;
+static CString tokcstr; /* current parsed string, if any */
+/* additional informations about token */
+static int tok_flags;
+#define TOK_FLAG_BOL   0x0001 /* beginning of line before */
+#define TOK_FLAG_BOF   0x0002 /* beginning of file before */
+#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */
+#define TOK_FLAG_EOF   0x0008 /* end of file */
+
+static int *macro_ptr, *macro_ptr_allocated;
+static int *unget_saved_macro_ptr;
+static int unget_saved_buffer[TOK_MAX_SIZE + 1];
+static int unget_buffer_enabled;
+static int parse_flags;
+#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */
+#define PARSE_FLAG_TOK_NUM    0x0002 /* return numbers instead of TOK_PPNUM */
+#define PARSE_FLAG_LINEFEED   0x0004 /* line feed is returned as a
+                                        token. line feed is also
+                                        returned at eof */
+#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */
+#define PARSE_FLAG_SPACES     0x0010 /* next() returns space tokens (for -E) */
+ 
+static Section *text_section, *data_section, *bss_section; /* predefined sections */
+static Section *cur_text_section; /* current section where function code is
+                              generated */
+#ifdef CONFIG_TCC_ASM
+static Section *last_text_section; /* to handle .previous asm directive */
+#endif
+/* bound check related sections */
+static Section *bounds_section; /* contains global data bound description */
+static Section *lbounds_section; /* contains local data bound description */
+/* symbol sections */
+static Section *symtab_section, *strtab_section;
+
+/* debug sections */
+static Section *stab_section, *stabstr_section;
+
+/* loc : local variable index
+   ind : output code index
+   rsym: return symbol
+   anon_sym: anonymous symbol index
+*/
+static int rsym, anon_sym, ind, loc;
+/* expression generation modifiers */
+static int const_wanted; /* true if constant wanted */
+static int nocode_wanted; /* true if no code generation wanted for an expression */
+static int global_expr;  /* true if compound literals must be allocated
+                            globally (used during initializers parsing */
+static CType func_vt; /* current function return type (used by return
+                         instruction) */
+static int func_vc;
+static int last_line_num, last_ind, func_ind; /* debug last line number and pc */
+static int tok_ident;
+static TokenSym **table_ident;
+static TokenSym *hash_ident[TOK_HASH_SIZE];
+static char token_buf[STRING_MAX_SIZE + 1];
+static char *funcname;
+static Sym *global_stack, *local_stack;
+static Sym *define_stack;
+static Sym *global_label_stack, *local_label_stack;
+/* symbol allocator */
+#define SYM_POOL_NB (8192 / sizeof(Sym))
+static Sym *sym_free_first;
+static void **sym_pools;
+static int nb_sym_pools;
+
+static SValue vstack[VSTACK_SIZE], *vtop;
+/* some predefined types */
+static CType char_pointer_type, func_old_type, int_type;
+
+/* use GNU C extensions */
+static int gnu_ext = 1;
+
+/* use Tiny C extensions */
+static int tcc_ext = 1;
+
+/* max number of callers shown if error */
+#ifdef CONFIG_TCC_BACKTRACE
+int num_callers = 6;
+const char **rt_bound_error_msg;
+#endif
+
+/* XXX: get rid of this ASAP */
+static struct TCCState *tcc_state;
+
+/********************************************************/
+/* function prototypes */
+
+/* tccpp.c */
+static void next(void);
+char *get_tok_str(int v, CValue *cv);
+
+/* tccgen.c */
+static void parse_expr_type(CType *type);
+static void expr_type(CType *type);
+static void unary_type(CType *type);
+static void block(int *bsym, int *csym, int *case_sym, int *def_sym, 
+                  int case_reg, int is_expr);
+static int expr_const(void);
+static void expr_eq(void);
+static void gexpr(void);
+static void gen_inline_functions(void);
+static void decl(int l);
+static void decl_initializer(CType *type, Section *sec, unsigned long c, 
+                             int first, int size_only);
+static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, 
+                                   int has_init, int v, int scope);
+int gv(int rc);
+void gv2(int rc1, int rc2);
+void move_reg(int r, int s);
+void save_regs(int n);
+void save_reg(int r);
+void vpop(void);
+void vswap(void);
+void vdup(void);
+int get_reg(int rc);
+int get_reg_ex(int rc,int rc2);
+
+void gen_op(int op);
+void force_charshort_cast(int t);
+static void gen_cast(CType *type);
+void vstore(void);
+static Sym *sym_find(int v);
+static Sym *sym_push(int v, CType *type, int r, int c);
+
+/* type handling */
+static int type_size(CType *type, int *a);
+static inline CType *pointed_type(CType *type);
+static int pointed_size(CType *type);
+static int lvalue_type(int t);
+static int parse_btype(CType *type, AttributeDef *ad);
+static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
+static int compare_types(CType *type1, CType *type2, int unqualified);
+static int is_compatible_types(CType *type1, CType *type2);
+static int is_compatible_parameter_types(CType *type1, CType *type2);
+
+int ieee_finite(double d);
+void vpushi(int v);
+void vpushll(long long v);
+void vrott(int n);
+void vnrott(int n);
+void lexpand_nr(void);
+static void vpush_global_sym(CType *type, int v);
+void vset(CType *type, int r, int v);
+void type_to_str(char *buf, int buf_size, 
+                 CType *type, const char *varstr);
+static Sym *get_sym_ref(CType *type, Section *sec,
+                        unsigned long offset, unsigned long size);
+static Sym *external_global_sym(int v, CType *type, int r);
+
+/* section generation */
+static void section_realloc(Section *sec, unsigned long new_size);
+static void *section_ptr_add(Section *sec, unsigned long size);
+static void put_extern_sym(Sym *sym, Section *section, 
+                           unsigned long value, unsigned long size);
+static void greloc(Section *s, Sym *sym, unsigned long addr, int type);
+static int put_elf_str(Section *s, const char *sym);
+static int put_elf_sym(Section *s, 
+                       unsigned long value, unsigned long size,
+                       int info, int other, int shndx, const char *name);
+static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
+                       int info, int other, int sh_num, const char *name);
+static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
+                          int type, int symbol);
+static void put_stabs(const char *str, int type, int other, int desc, 
+                      unsigned long value);
+static void put_stabs_r(const char *str, int type, int other, int desc, 
+                        unsigned long value, Section *sec, int sym_index);
+static void put_stabn(int type, int other, int desc, int value);
+static void put_stabd(int type, int other, int desc);
+static int tcc_add_dll(TCCState *s, const char *filename, int flags);
+
+#define AFF_PRINT_ERROR     0x0001 /* print error if file not found */
+#define AFF_REFERENCED_DLL  0x0002 /* load a referenced dll from another dll */
+#define AFF_PREPROCESS      0x0004 /* preprocess file */
+static int tcc_add_file_internal(TCCState *s, const char *filename, int flags);
+
+/* tcccoff.c */
+int tcc_output_coff(TCCState *s1, FILE *f);
+
+/* tccpe.c */
+void *resolve_sym(TCCState *s1, const char *sym, int type);
+int pe_load_def_file(struct TCCState *s1, int fd);
+int pe_test_res_file(void *v, int size);
+int pe_load_res_file(struct TCCState *s1, int fd);
+void pe_add_runtime(struct TCCState *s1);
+void pe_guess_outfile(char *objfilename, int output_type);
+int pe_output_file(struct TCCState *s1, const char *filename);
+
+/* tccasm.c */
+#ifdef CONFIG_TCC_ASM
+static void asm_expr(TCCState *s1, ExprValue *pe);
+static int asm_int_expr(TCCState *s1);
+static int find_constraint(ASMOperand *operands, int nb_operands, 
+                           const char *name, const char **pp);
+
+static int tcc_assemble(TCCState *s1, int do_preprocess);
+#endif
+
+static void asm_instr(void);
+static void asm_global_instr(void);
+
+/********************************************************/
+/* global variables */
+
+#ifdef TCC_TARGET_I386
+#include "i386-gen.c"
+#endif
+
+#ifdef TCC_TARGET_ARM
+#include "arm-gen.c"
+#endif
+
+#ifdef TCC_TARGET_C67
+#include "c67-gen.c"
+#endif
+
+#ifdef TCC_TARGET_X86_64
+#include "x86_64-gen.c"
+#endif
+
+#ifdef CONFIG_TCC_STATIC
+
+#define RTLD_LAZY       0x001
+#define RTLD_NOW        0x002
+#define RTLD_GLOBAL     0x100
+#define RTLD_DEFAULT    NULL
+
+/* dummy function for profiling */
+void *dlopen(const char *filename, int flag)
+{
+    return NULL;
+}
+
+void dlclose(void *p)
+{
+}
+
+const char *dlerror(void)
+{
+    return "error";
+}
+
+typedef struct TCCSyms {
+    char *str;
+    void *ptr;
+} TCCSyms;
+
+#define TCCSYM(a) { #a, &a, },
+
+/* add the symbol you want here if no dynamic linking is done */
+static TCCSyms tcc_syms[] = {
+#if !defined(CONFIG_TCCBOOT)
+    TCCSYM(printf)
+    TCCSYM(fprintf)
+    TCCSYM(fopen)
+    TCCSYM(fclose)
+#endif
+    { NULL, NULL },
+};
+
+void *resolve_sym(TCCState *s1, const char *symbol, int type)
+{
+    TCCSyms *p;
+    p = tcc_syms;
+    while (p->str != NULL) {
+        if (!strcmp(p->str, symbol))
+            return p->ptr;
+        p++;
+    }
+    return NULL;
+}
+
+#elif !defined(_WIN32)
+
+#include <dlfcn.h>
+
+void *resolve_sym(TCCState *s1, const char *sym, int type)
+{
+    return dlsym(RTLD_DEFAULT, sym);
+}
+
+#endif
+
+/********************************************************/
+
+/* we use our own 'finite' function to avoid potential problems with
+   non standard math libs */
+/* XXX: endianness dependent */
+int ieee_finite(double d)
+{
+    int *p = (int *)&d;
+    return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
+}
+
+/* copy a string and truncate it. */
+char *pstrcpy(char *buf, int buf_size, const char *s)
+{
+    char *q, *q_end;
+    int c;
+
+    if (buf_size > 0) {
+        q = buf;
+        q_end = buf + buf_size - 1;
+        while (q < q_end) {
+            c = *s++;
+            if (c == '\0')
+                break;
+            *q++ = c;
+        }
+        *q = '\0';
+    }
+    return buf;
+}
+
+/* strcat and truncate. */
+char *pstrcat(char *buf, int buf_size, const char *s)
+{
+    int len;
+    len = strlen(buf);
+    if (len < buf_size) 
+        pstrcpy(buf + len, buf_size - len, s);
+    return buf;
+}
+
+/* extract the basename of a file */
+char *tcc_basename(const char *name)
+{
+    char *p = strchr(name, 0);
+    while (p > name && !IS_PATHSEP(p[-1]))
+        --p;
+    return p;
+}
+
+char *tcc_fileextension (const char *name)
+{
+    char *b = tcc_basename(name);
+    char *e = strrchr(b, '.');
+    return e ? e : strchr(b, 0);
+}
+
+#ifdef _WIN32
+char *normalize_slashes(char *path)
+{
+    char *p;
+    for (p = path; *p; ++p)
+        if (*p == '\\')
+            *p = '/';
+    return path;
+}
+
+void tcc_set_lib_path_w32(TCCState *s)
+{
+    /* on win32, we suppose the lib and includes are at the location
+       of 'tcc.exe' */
+    char path[1024], *p;
+    GetModuleFileNameA(NULL, path, sizeof path);
+    p = tcc_basename(normalize_slashes(strlwr(path)));
+    if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
+        p -= 5;
+    else if (p > path)
+        p--;
+    *p = 0;
+    tcc_set_lib_path(s, path);
+}
+#endif
+
+void set_pages_executable(void *ptr, unsigned long length)
+{
+#ifdef _WIN32
+    unsigned long old_protect;
+    VirtualProtect(ptr, length, PAGE_EXECUTE_READWRITE, &old_protect);
+#else
+    unsigned long start, end;
+    start = (unsigned long)ptr & ~(PAGESIZE - 1);
+    end = (unsigned long)ptr + length;
+    end = (end + PAGESIZE - 1) & ~(PAGESIZE - 1);
+    mprotect((void *)start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
+#endif            
+}
+
+/* memory management */
+#ifdef MEM_DEBUG
+int mem_cur_size;
+int mem_max_size;
+unsigned malloc_usable_size(void*);
+#endif
+
+void tcc_free(void *ptr)
+{
+#ifdef MEM_DEBUG
+    mem_cur_size -= malloc_usable_size(ptr);
+#endif
+    free(ptr);
+}
+
+void *tcc_malloc(unsigned long size)
+{
+    void *ptr;
+    ptr = malloc(size);
+    if (!ptr && size)
+        error("memory full");
+#ifdef MEM_DEBUG
+    mem_cur_size += malloc_usable_size(ptr);
+    if (mem_cur_size > mem_max_size)
+        mem_max_size = mem_cur_size;
+#endif
+    return ptr;
+}
+
+void *tcc_mallocz(unsigned long size)
+{
+    void *ptr;
+    ptr = tcc_malloc(size);
+    memset(ptr, 0, size);
+    return ptr;
+}
+
+void *tcc_realloc(void *ptr, unsigned long size)
+{
+    void *ptr1;
+#ifdef MEM_DEBUG
+    mem_cur_size -= malloc_usable_size(ptr);
+#endif
+    ptr1 = realloc(ptr, size);
+#ifdef MEM_DEBUG
+    /* NOTE: count not correct if alloc error, but not critical */
+    mem_cur_size += malloc_usable_size(ptr1);
+    if (mem_cur_size > mem_max_size)
+        mem_max_size = mem_cur_size;
+#endif
+    return ptr1;
+}
+
+char *tcc_strdup(const char *str)
+{
+    char *ptr;
+    ptr = tcc_malloc(strlen(str) + 1);
+    strcpy(ptr, str);
+    return ptr;
+}
+
+#define free(p) use_tcc_free(p)
+#define malloc(s) use_tcc_malloc(s)
+#define realloc(p, s) use_tcc_realloc(p, s)
+
+void dynarray_add(void ***ptab, int *nb_ptr, void *data)
+{
+    int nb, nb_alloc;
+    void **pp;
+    
+    nb = *nb_ptr;
+    pp = *ptab;
+    /* every power of two we double array size */
+    if ((nb & (nb - 1)) == 0) {
+        if (!nb)
+            nb_alloc = 1;
+        else
+            nb_alloc = nb * 2;
+        pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
+        if (!pp)
+            error("memory full");
+        *ptab = pp;
+    }
+    pp[nb++] = data;
+    *nb_ptr = nb;
+}
+
+void dynarray_reset(void *pp, int *n)
+{
+    void **p;
+    for (p = *(void***)pp; *n; ++p, --*n)
+        if (*p)
+            tcc_free(*p);
+    tcc_free(*(void**)pp);
+    *(void**)pp = NULL;
+}
+
+/* symbol allocator */
+static Sym *__sym_malloc(void)
+{
+    Sym *sym_pool, *sym, *last_sym;
+    int i;
+
+    sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym));
+    dynarray_add(&sym_pools, &nb_sym_pools, sym_pool);
+
+    last_sym = sym_free_first;
+    sym = sym_pool;
+    for(i = 0; i < SYM_POOL_NB; i++) {
+        sym->next = last_sym;
+        last_sym = sym;
+        sym++;
+    }
+    sym_free_first = last_sym;
+    return last_sym;
+}
+
+static inline Sym *sym_malloc(void)
+{
+    Sym *sym;
+    sym = sym_free_first;
+    if (!sym)
+        sym = __sym_malloc();
+    sym_free_first = sym->next;
+    return sym;
+}
+
+static inline void sym_free(Sym *sym)
+{
+    sym->next = sym_free_first;
+    sym_free_first = sym;
+}
+
+Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
+{
+    Section *sec;
+
+    sec = tcc_mallocz(sizeof(Section) + strlen(name));
+    strcpy(sec->name, name);
+    sec->sh_type = sh_type;
+    sec->sh_flags = sh_flags;
+    switch(sh_type) {
+    case SHT_HASH:
+    case SHT_REL:
+    case SHT_RELA:
+    case SHT_DYNSYM:
+    case SHT_SYMTAB:
+    case SHT_DYNAMIC:
+        sec->sh_addralign = 4;
+        break;
+    case SHT_STRTAB:
+        sec->sh_addralign = 1;
+        break;
+    default:
+        sec->sh_addralign = 32; /* default conservative alignment */
+        break;
+    }
+
+    if (sh_flags & SHF_PRIVATE) {
+        dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
+    } else {
+        sec->sh_num = s1->nb_sections;
+        dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
+    }
+
+    return sec;
+}
+
+static void free_section(Section *s)
+{
+    tcc_free(s->data);
+}
+
+/* realloc section and set its content to zero */
+static void section_realloc(Section *sec, unsigned long new_size)
+{
+    unsigned long size;
+    unsigned char *data;
+    
+    size = sec->data_allocated;
+    if (size == 0)
+        size = 1;
+    while (size < new_size)
+        size = size * 2;
+    data = tcc_realloc(sec->data, size);
+    if (!data)
+        error("memory full");
+    memset(data + sec->data_allocated, 0, size - sec->data_allocated);
+    sec->data = data;
+    sec->data_allocated = size;
+}
+
+/* reserve at least 'size' bytes in section 'sec' from
+   sec->data_offset. */
+static void *section_ptr_add(Section *sec, unsigned long size)
+{
+    unsigned long offset, offset1;
+
+    offset = sec->data_offset;
+    offset1 = offset + size;
+    if (offset1 > sec->data_allocated)
+        section_realloc(sec, offset1);
+    sec->data_offset = offset1;
+    return sec->data + offset;
+}
+
+/* return a reference to a section, and create it if it does not
+   exists */
+Section *find_section(TCCState *s1, const char *name)
+{
+    Section *sec;
+    int i;
+    for(i = 1; i < s1->nb_sections; i++) {
+        sec = s1->sections[i];
+        if (!strcmp(name, sec->name)) 
+            return sec;
+    }
+    /* sections are created as PROGBITS */
+    return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
+}
+
+/* update sym->c so that it points to an external symbol in section
+   'section' with value 'value' */
+static void put_extern_sym2(Sym *sym, Section *section, 
+                            unsigned long value, unsigned long size,
+                            int can_add_underscore)
+{
+    int sym_type, sym_bind, sh_num, info, other, attr;
+    ElfW(Sym) *esym;
+    const char *name;
+    char buf1[256];
+
+    if (section == NULL)
+        sh_num = SHN_UNDEF;
+    else if (section == SECTION_ABS) 
+        sh_num = SHN_ABS;
+    else
+        sh_num = section->sh_num;
+
+    other = attr = 0;
+
+    if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
+        sym_type = STT_FUNC;
+#ifdef TCC_TARGET_PE
+        if (sym->type.ref)
+            attr = sym->type.ref->r;
+        if (FUNC_EXPORT(attr))
+            other |= 1;
+        if (FUNC_CALL(attr) == FUNC_STDCALL)
+            other |= 2;
+#endif
+    } else {
+        sym_type = STT_OBJECT;
+    }
+
+    if (sym->type.t & VT_STATIC)
+        sym_bind = STB_LOCAL;
+    else
+        sym_bind = STB_GLOBAL;
+
+    if (!sym->c) {
+        name = get_tok_str(sym->v, NULL);
+#ifdef CONFIG_TCC_BCHECK
+        if (tcc_state->do_bounds_check) {
+            char buf[32];
+
+            /* XXX: avoid doing that for statics ? */
+            /* if bound checking is activated, we change some function
+               names by adding the "__bound" prefix */
+            switch(sym->v) {
+#if 0
+            /* XXX: we rely only on malloc hooks */
+            case TOK_malloc: 
+            case TOK_free: 
+            case TOK_realloc: 
+            case TOK_memalign: 
+            case TOK_calloc: 
+#endif
+            case TOK_memcpy: 
+            case TOK_memmove:
+            case TOK_memset:
+            case TOK_strlen:
+            case TOK_strcpy:
+            case TOK_alloca:
+                strcpy(buf, "__bound_");
+                strcat(buf, name);
+                name = buf;
+                break;
+            }
+        }
+#endif
+
+#ifdef TCC_TARGET_PE
+        if ((other & 2) && can_add_underscore) {
+            sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr));
+            name = buf1;
+        } else
+#endif
+        if (tcc_state->leading_underscore && can_add_underscore) {
+            buf1[0] = '_';
+            pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
+            name = buf1;
+        }
+        info = ELFW(ST_INFO)(sym_bind, sym_type);
+        sym->c = add_elf_sym(symtab_section, value, size, info, other, sh_num, name);
+    } else {
+        esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+        esym->st_value = value;
+        esym->st_size = size;
+        esym->st_shndx = sh_num;
+        esym->st_other |= other;
+    }
+}
+
+static void put_extern_sym(Sym *sym, Section *section, 
+                           unsigned long value, unsigned long size)
+{
+    put_extern_sym2(sym, section, value, size, 1);
+}
+
+/* add a new relocation entry to symbol 'sym' in section 's' */
+static void greloc(Section *s, Sym *sym, unsigned long offset, int type)
+{
+    if (!sym->c) 
+        put_extern_sym(sym, NULL, 0, 0);
+    /* now we can add ELF relocation info */
+    put_elf_reloc(symtab_section, s, offset, type, sym->c);
+}
+
+static inline int isid(int c)
+{
+    return (c >= 'a' && c <= 'z') ||
+        (c >= 'A' && c <= 'Z') ||
+        c == '_';
+}
+
+static inline int isnum(int c)
+{
+    return c >= '0' && c <= '9';
+}
+
+static inline int isoct(int c)
+{
+    return c >= '0' && c <= '7';
+}
+
+static inline int toup(int c)
+{
+    if (c >= 'a' && c <= 'z')
+        return c - 'a' + 'A';
+    else
+        return c;
+}
+
+static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
+{
+    int len;
+    len = strlen(buf);
+    vsnprintf(buf + len, buf_size - len, fmt, ap);
+}
+
+static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    strcat_vprintf(buf, buf_size, fmt, ap);
+    va_end(ap);
+}
+
+void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
+{
+    char buf[2048];
+    BufferedFile **f;
+    
+    buf[0] = '\0';
+    if (file) {
+        for(f = s1->include_stack; f < s1->include_stack_ptr; f++)
+            strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", 
+                          (*f)->filename, (*f)->line_num);
+        if (file->line_num > 0) {
+            strcat_printf(buf, sizeof(buf), 
+                          "%s:%d: ", file->filename, file->line_num);
+        } else {
+            strcat_printf(buf, sizeof(buf),
+                          "%s: ", file->filename);
+        }
+    } else {
+        strcat_printf(buf, sizeof(buf),
+                      "tcc: ");
+    }
+    if (is_warning)
+        strcat_printf(buf, sizeof(buf), "warning: ");
+    strcat_vprintf(buf, sizeof(buf), fmt, ap);
+
+    if (!s1->error_func) {
+        /* default case: stderr */
+        fprintf(stderr, "%s\n", buf);
+    } 
+    if (!is_warning || s1->warn_error) {
+        s1->error_func(s1->error_opaque, buf);
+        s1->nb_errors++;
+    }
+}
+
+void tcc_set_error_func(TCCState *s, void *error_opaque,
+                        void (*error_func)(void *opaque, const char *msg))
+{
+    s->error_opaque = error_opaque;
+    s->error_func = error_func;
+}
+
+/* error without aborting current compilation */
+void error_noabort(const char *fmt, ...)
+{
+    TCCState *s1 = tcc_state;
+    va_list ap;
+
+    va_start(ap, fmt);
+    error1(s1, 0, fmt, ap);
+    va_end(ap);
+}
+
+void error(const char *fmt, ...)
+{
+    TCCState *s1 = tcc_state;
+    va_list ap;
+
+    va_start(ap, fmt);
+    error1(s1, 0, fmt, ap);
+    va_end(ap);
+    /* better than nothing: in some cases, we accept to handle errors */
+    if (s1->error_set_jmp_enabled) {
+        longjmp(s1->error_jmp_buf, 1);
+    } else {
+        /* XXX: eliminate this someday */
+        exit(1);
+    }
+}
+
+void expect(const char *msg)
+{
+    error("%s expected", msg);
+}
+
+void warning(const char *fmt, ...)
+{
+    TCCState *s1 = tcc_state;
+    va_list ap;
+
+    if (s1->warn_none)
+        return;
+
+    va_start(ap, fmt);
+    error1(s1, 1, fmt, ap);
+    va_end(ap);
+}
+
+void skip(int c)
+{
+    if (tok != c)
+        error("'%c' expected", c);
+    next();
+}
+
+static void test_lvalue(void)
+{
+    if (!(vtop->r & VT_LVAL))
+        expect("lvalue");
+}
+
+/* CString handling */
+
+static void cstr_realloc(CString *cstr, int new_size)
+{
+    int size;
+    void *data;
+
+    size = cstr->size_allocated;
+    if (size == 0)
+        size = 8; /* no need to allocate a too small first string */
+    while (size < new_size)
+        size = size * 2;
+    data = tcc_realloc(cstr->data_allocated, size);
+    if (!data)
+        error("memory full");
+    cstr->data_allocated = data;
+    cstr->size_allocated = size;
+    cstr->data = data;
+}
+
+/* add a byte */
+static inline void cstr_ccat(CString *cstr, int ch)
+{
+    int size;
+    size = cstr->size + 1;
+    if (size > cstr->size_allocated)
+        cstr_realloc(cstr, size);
+    ((unsigned char *)cstr->data)[size - 1] = ch;
+    cstr->size = size;
+}
+
+static void cstr_cat(CString *cstr, const char *str)
+{
+    int c;
+    for(;;) {
+        c = *str;
+        if (c == '\0')
+            break;
+        cstr_ccat(cstr, c);
+        str++;
+    }
+}
+
+/* add a wide char */
+static void cstr_wccat(CString *cstr, int ch)
+{
+    int size;
+    size = cstr->size + sizeof(nwchar_t);
+    if (size > cstr->size_allocated)
+        cstr_realloc(cstr, size);
+    *(nwchar_t *)(((unsigned char *)cstr->data) + size - sizeof(nwchar_t)) = ch;
+    cstr->size = size;
+}
+
+static void cstr_new(CString *cstr)
+{
+    memset(cstr, 0, sizeof(CString));
+}
+
+/* free string and reset it to NULL */
+static void cstr_free(CString *cstr)
+{
+    tcc_free(cstr->data_allocated);
+    cstr_new(cstr);
+}
+
+#define cstr_reset(cstr) cstr_free(cstr)
+
+/* XXX: unicode ? */
+static void add_char(CString *cstr, int c)
+{
+    if (c == '\'' || c == '\"' || c == '\\') {
+        /* XXX: could be more precise if char or string */
+        cstr_ccat(cstr, '\\');
+    }
+    if (c >= 32 && c <= 126) {
+        cstr_ccat(cstr, c);
+    } else {
+        cstr_ccat(cstr, '\\');
+        if (c == '\n') {
+            cstr_ccat(cstr, 'n');
+        } else {
+            cstr_ccat(cstr, '0' + ((c >> 6) & 7));
+            cstr_ccat(cstr, '0' + ((c >> 3) & 7));
+            cstr_ccat(cstr, '0' + (c & 7));
+        }
+    }
+}
+
+/* push, without hashing */
+static Sym *sym_push2(Sym **ps, int v, int t, long c)
+{
+    Sym *s;
+    s = sym_malloc();
+    s->v = v;
+    s->type.t = t;
+    s->c = c;
+    s->next = NULL;
+    /* add in stack */
+    s->prev = *ps;
+    *ps = s;
+    return s;
+}
+
+/* find a symbol and return its associated structure. 's' is the top
+   of the symbol stack */
+static Sym *sym_find2(Sym *s, int v)
+{
+    while (s) {
+        if (s->v == v)
+            return s;
+        s = s->prev;
+    }
+    return NULL;
+}
+
+/* structure lookup */
+static inline Sym *struct_find(int v)
+{
+    v -= TOK_IDENT;
+    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
+        return NULL;
+    return table_ident[v]->sym_struct;
+}
+
+/* find an identifier */
+static inline Sym *sym_find(int v)
+{
+    v -= TOK_IDENT;
+    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
+        return NULL;
+    return table_ident[v]->sym_identifier;
+}
+
+/* push a given symbol on the symbol stack */
+static Sym *sym_push(int v, CType *type, int r, int c)
+{
+    Sym *s, **ps;
+    TokenSym *ts;
+
+    if (local_stack)
+        ps = &local_stack;
+    else
+        ps = &global_stack;
+    s = sym_push2(ps, v, type->t, c);
+    s->type.ref = type->ref;
+    s->r = r;
+    /* don't record fields or anonymous symbols */
+    /* XXX: simplify */
+    if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
+        /* record symbol in token array */
+        ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
+        if (v & SYM_STRUCT)
+            ps = &ts->sym_struct;
+        else
+            ps = &ts->sym_identifier;
+        s->prev_tok = *ps;
+        *ps = s;
+    }
+    return s;
+}
+
+/* push a global identifier */
+static Sym *global_identifier_push(int v, int t, int c)
+{
+    Sym *s, **ps;
+    s = sym_push2(&global_stack, v, t, c);
+    /* don't record anonymous symbol */
+    if (v < SYM_FIRST_ANOM) {
+        ps = &table_ident[v - TOK_IDENT]->sym_identifier;
+        /* modify the top most local identifier, so that
+           sym_identifier will point to 's' when popped */
+        while (*ps != NULL)
+            ps = &(*ps)->prev_tok;
+        s->prev_tok = NULL;
+        *ps = s;
+    }
+    return s;
+}
+
+/* pop symbols until top reaches 'b' */
+static void sym_pop(Sym **ptop, Sym *b)
+{
+    Sym *s, *ss, **ps;
+    TokenSym *ts;
+    int v;
+
+    s = *ptop;
+    while(s != b) {
+        ss = s->prev;
+        v = s->v;
+        /* remove symbol in token array */
+        /* XXX: simplify */
+        if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
+            ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
+            if (v & SYM_STRUCT)
+                ps = &ts->sym_struct;
+            else
+                ps = &ts->sym_identifier;
+            *ps = s->prev_tok;
+        }
+        sym_free(s);
+        s = ss;
+    }
+    *ptop = b;
+}
+
+/* I/O layer */
+
+BufferedFile *tcc_open(TCCState *s1, const char *filename)
+{
+    int fd;
+    BufferedFile *bf;
+
+    if (strcmp(filename, "-") == 0)
+        fd = 0, filename = "stdin";
+    else
+        fd = open(filename, O_RDONLY | O_BINARY);
+    if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
+        printf("%s %*s%s\n", fd < 0 ? "nf":"->",
+               (s1->include_stack_ptr - s1->include_stack), "", filename);
+    if (fd < 0)
+        return NULL;
+    bf = tcc_malloc(sizeof(BufferedFile));
+    bf->fd = fd;
+    bf->buf_ptr = bf->buffer;
+    bf->buf_end = bf->buffer;
+    bf->buffer[0] = CH_EOB; /* put eob symbol */
+    pstrcpy(bf->filename, sizeof(bf->filename), filename);
+#ifdef _WIN32
+    normalize_slashes(bf->filename);
+#endif
+    bf->line_num = 1;
+    bf->ifndef_macro = 0;
+    bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
+    //    printf("opening '%s'\n", filename);
+    return bf;
+}
+
+void tcc_close(BufferedFile *bf)
+{
+    total_lines += bf->line_num;
+    close(bf->fd);
+    tcc_free(bf);
+}
+
+#include "tccpp.c"
+#include "tccgen.c"
+
+
+/* compile the C file opened in 'file'. Return non zero if errors. */
+static int tcc_compile(TCCState *s1)
+{
+    Sym *define_start;
+    char buf[512];
+    volatile int section_sym;
+
+#ifdef INC_DEBUG
+    printf("%s: **** new file\n", file->filename);
+#endif
+    preprocess_init(s1);
+
+    cur_text_section = NULL;
+    funcname = "";
+    anon_sym = SYM_FIRST_ANOM; 
+
+    /* file info: full path + filename */
+    section_sym = 0; /* avoid warning */
+    if (s1->do_debug) {
+        section_sym = put_elf_sym(symtab_section, 0, 0, 
+                                  ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, 
+                                  text_section->sh_num, NULL);
+        getcwd(buf, sizeof(buf));
+#ifdef _WIN32
+        normalize_slashes(buf);
+#endif
+        pstrcat(buf, sizeof(buf), "/");
+        put_stabs_r(buf, N_SO, 0, 0, 
+                    text_section->data_offset, text_section, section_sym);
+        put_stabs_r(file->filename, N_SO, 0, 0, 
+                    text_section->data_offset, text_section, section_sym);
+    }
+    /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
+       symbols can be safely used */
+    put_elf_sym(symtab_section, 0, 0, 
+                ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, 
+                SHN_ABS, file->filename);
+
+    /* define some often used types */
+    int_type.t = VT_INT;
+
+    char_pointer_type.t = VT_BYTE;
+    mk_pointer(&char_pointer_type);
+
+    func_old_type.t = VT_FUNC;
+    func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
+
+#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
+    float_type.t = VT_FLOAT;
+    double_type.t = VT_DOUBLE;
+
+    func_float_type.t = VT_FUNC;
+    func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
+    func_double_type.t = VT_FUNC;
+    func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
+#endif
+
+#if 0
+    /* define 'void *alloca(unsigned int)' builtin function */
+    {
+        Sym *s1;
+
+        p = anon_sym++;
+        sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
+        s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
+        s1->next = NULL;
+        sym->next = s1;
+        sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
+    }
+#endif
+
+    define_start = define_stack;
+    nocode_wanted = 1;
+
+    if (setjmp(s1->error_jmp_buf) == 0) {
+        s1->nb_errors = 0;
+        s1->error_set_jmp_enabled = 1;
+
+        ch = file->buf_ptr[0];
+        tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
+        parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM;
+        next();
+        decl(VT_CONST);
+        if (tok != TOK_EOF)
+            expect("declaration");
+
+        /* end of translation unit info */
+        if (s1->do_debug) {
+            put_stabs_r(NULL, N_SO, 0, 0, 
+                        text_section->data_offset, text_section, section_sym);
+        }
+    }
+    s1->error_set_jmp_enabled = 0;
+
+    /* reset define stack, but leave -Dsymbols (may be incorrect if
+       they are undefined) */
+    free_defines(define_start); 
+
+    gen_inline_functions();
+
+    sym_pop(&global_stack, NULL);
+    sym_pop(&local_stack, NULL);
+
+    return s1->nb_errors != 0 ? -1 : 0;
+}
+
+int tcc_compile_string(TCCState *s, const char *str)
+{
+    BufferedFile bf1, *bf = &bf1;
+    int ret, len;
+    char *buf;
+
+    /* init file structure */
+    bf->fd = -1;
+    /* XXX: avoid copying */
+    len = strlen(str);
+    buf = tcc_malloc(len + 1);
+    if (!buf)
+        return -1;
+    memcpy(buf, str, len);
+    buf[len] = CH_EOB;
+    bf->buf_ptr = buf;
+    bf->buf_end = buf + len;
+    pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
+    bf->line_num = 1;
+    file = bf;
+    ret = tcc_compile(s);
+    file = NULL;
+    tcc_free(buf);
+
+    /* currently, no need to close */
+    return ret;
+}
+
+/* define a preprocessor symbol. A value can also be provided with the '=' operator */
+void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
+{
+    BufferedFile bf1, *bf = &bf1;
+
+    pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
+    pstrcat(bf->buffer, IO_BUF_SIZE, " ");
+    /* default value */
+    if (!value) 
+        value = "1";
+    pstrcat(bf->buffer, IO_BUF_SIZE, value);
+    
+    /* init file structure */
+    bf->fd = -1;
+    bf->buf_ptr = bf->buffer;
+    bf->buf_end = bf->buffer + strlen(bf->buffer);
+    *bf->buf_end = CH_EOB;
+    bf->filename[0] = '\0';
+    bf->line_num = 1;
+    file = bf;
+    
+    s1->include_stack_ptr = s1->include_stack;
+
+    /* parse with define parser */
+    ch = file->buf_ptr[0];
+    next_nomacro();
+    parse_define();
+    file = NULL;
+}
+
+/* undefine a preprocessor symbol */
+void tcc_undefine_symbol(TCCState *s1, const char *sym)
+{
+    TokenSym *ts;
+    Sym *s;
+    ts = tok_alloc(sym, strlen(sym));
+    s = define_find(ts->tok);
+    /* undefine symbol by putting an invalid name */
+    if (s)
+        define_undef(s);
+}
+
+#ifdef CONFIG_TCC_ASM
+
+#ifdef TCC_TARGET_I386
+#include "i386-asm.c"
+#endif
+#include "tccasm.c"
+
+#else
+static void asm_instr(void)
+{
+    error("inline asm() not supported");
+}
+static void asm_global_instr(void)
+{
+    error("inline asm() not supported");
+}
+#endif
+
+#include "tccelf.c"
+
+#ifdef TCC_TARGET_COFF
+#include "tcccoff.c"
+#endif
+
+#ifdef TCC_TARGET_PE
+#include "tccpe.c"
+#endif
+
+#ifdef CONFIG_TCC_BACKTRACE
+/* print the position in the source file of PC value 'pc' by reading
+   the stabs debug information */
+static void rt_printline(unsigned long wanted_pc)
+{
+    Stab_Sym *sym, *sym_end;
+    char func_name[128], last_func_name[128];
+    unsigned long func_addr, last_pc, pc;
+    const char *incl_files[INCLUDE_STACK_SIZE];
+    int incl_index, len, last_line_num, i;
+    const char *str, *p;
+
+    fprintf(stderr, "0x%08lx:", wanted_pc);
+
+    func_name[0] = '\0';
+    func_addr = 0;
+    incl_index = 0;
+    last_func_name[0] = '\0';
+    last_pc = 0xffffffff;
+    last_line_num = 1;
+    sym = (Stab_Sym *)stab_section->data + 1;
+    sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
+    while (sym < sym_end) {
+        switch(sym->n_type) {
+            /* function start or end */
+        case N_FUN:
+            if (sym->n_strx == 0) {
+                /* we test if between last line and end of function */
+                pc = sym->n_value + func_addr;
+                if (wanted_pc >= last_pc && wanted_pc < pc)
+                    goto found;
+                func_name[0] = '\0';
+                func_addr = 0;
+            } else {
+                str = stabstr_section->data + sym->n_strx;
+                p = strchr(str, ':');
+                if (!p) {
+                    pstrcpy(func_name, sizeof(func_name), str);
+                } else {
+                    len = p - str;
+                    if (len > sizeof(func_name) - 1)
+                        len = sizeof(func_name) - 1;
+                    memcpy(func_name, str, len);
+                    func_name[len] = '\0';
+                }
+                func_addr = sym->n_value;
+            }
+            break;
+            /* line number info */
+        case N_SLINE:
+            pc = sym->n_value + func_addr;
+            if (wanted_pc >= last_pc && wanted_pc < pc)
+                goto found;
+            last_pc = pc;
+            last_line_num = sym->n_desc;
+            /* XXX: slow! */
+            strcpy(last_func_name, func_name);
+            break;
+            /* include files */
+        case N_BINCL:
+            str = stabstr_section->data + sym->n_strx;
+        add_incl:
+            if (incl_index < INCLUDE_STACK_SIZE) {
+                incl_files[incl_index++] = str;
+            }
+            break;
+        case N_EINCL:
+            if (incl_index > 1)
+                incl_index--;
+            break;
+        case N_SO:
+            if (sym->n_strx == 0) {
+                incl_index = 0; /* end of translation unit */
+            } else {
+                str = stabstr_section->data + sym->n_strx;
+                /* do not add path */
+                len = strlen(str);
+                if (len > 0 && str[len - 1] != '/')
+                    goto add_incl;
+            }
+            break;
+        }
+        sym++;
+    }
+
+    /* second pass: we try symtab symbols (no line number info) */
+    incl_index = 0;
+    {
+        ElfW(Sym) *sym, *sym_end;
+        int type;
+
+        sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
+        for(sym = (ElfW(Sym) *)symtab_section->data + 1; 
+            sym < sym_end;
+            sym++) {
+            type = ELFW(ST_TYPE)(sym->st_info);
+            if (type == STT_FUNC) {
+                if (wanted_pc >= sym->st_value &&
+                    wanted_pc < sym->st_value + sym->st_size) {
+                    pstrcpy(last_func_name, sizeof(last_func_name),
+                            strtab_section->data + sym->st_name);
+                    goto found;
+                }
+            }
+        }
+    }
+    /* did not find any info: */
+    fprintf(stderr, " ???\n");
+    return;
+ found:
+    if (last_func_name[0] != '\0') {
+        fprintf(stderr, " %s()", last_func_name);
+    }
+    if (incl_index > 0) {
+        fprintf(stderr, " (%s:%d", 
+                incl_files[incl_index - 1], last_line_num);
+        for(i = incl_index - 2; i >= 0; i--)
+            fprintf(stderr, ", included from %s", incl_files[i]);
+        fprintf(stderr, ")");
+    }
+    fprintf(stderr, "\n");
+}
+
+#ifdef __i386__
+/* fix for glibc 2.1 */
+#ifndef REG_EIP
+#define REG_EIP EIP
+#define REG_EBP EBP
+#endif
+
+/* return the PC at frame level 'level'. Return non zero if not found */
+static int rt_get_caller_pc(unsigned long *paddr, 
+                            ucontext_t *uc, int level)
+{
+    unsigned long fp;
+    int i;
+
+    if (level == 0) {
+#if defined(__FreeBSD__)
+        *paddr = uc->uc_mcontext.mc_eip;
+#elif defined(__dietlibc__)
+        *paddr = uc->uc_mcontext.eip;
+#else
+        *paddr = uc->uc_mcontext.gregs[REG_EIP];
+#endif
+        return 0;
+    } else {
+#if defined(__FreeBSD__) 
+        fp = uc->uc_mcontext.mc_ebp;
+#elif defined(__dietlibc__)
+        fp = uc->uc_mcontext.ebp;
+#else
+        fp = uc->uc_mcontext.gregs[REG_EBP];
+#endif
+        for(i=1;i<level;i++) {
+            /* XXX: check address validity with program info */
+            if (fp <= 0x1000 || fp >= 0xc0000000)
+                return -1;
+            fp = ((unsigned long *)fp)[0];
+        }
+        *paddr = ((unsigned long *)fp)[1];
+        return 0;
+    }
+}
+#elif defined(__x86_64__)
+/* return the PC at frame level 'level'. Return non zero if not found */
+static int rt_get_caller_pc(unsigned long *paddr,
+                            ucontext_t *uc, int level)
+{
+    unsigned long fp;
+    int i;
+
+    if (level == 0) {
+        /* XXX: only support linux */
+        *paddr = uc->uc_mcontext.gregs[REG_RIP];
+        return 0;
+    } else {
+        fp = uc->uc_mcontext.gregs[REG_RBP];
+        for(i=1;i<level;i++) {
+            /* XXX: check address validity with program info */
+            if (fp <= 0x1000)
+                return -1;
+            fp = ((unsigned long *)fp)[0];
+        }
+        *paddr = ((unsigned long *)fp)[1];
+        return 0;
+    }
+}
+#else
+#warning add arch specific rt_get_caller_pc()
+static int rt_get_caller_pc(unsigned long *paddr,
+                            ucontext_t *uc, int level)
+{
+    return -1;
+}
+#endif
+
+/* emit a run time error at position 'pc' */
+void rt_error(ucontext_t *uc, const char *fmt, ...)
+{
+    va_list ap;
+    unsigned long pc;
+    int i;
+
+    va_start(ap, fmt);
+    fprintf(stderr, "Runtime error: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    for(i=0;i<num_callers;i++) {
+        if (rt_get_caller_pc(&pc, uc, i) < 0)
+            break;
+        if (i == 0)
+            fprintf(stderr, "at ");
+        else
+            fprintf(stderr, "by ");
+        rt_printline(pc);
+    }
+    exit(255);
+    va_end(ap);
+}
+
+/* signal handler for fatal errors */
+static void sig_error(int signum, siginfo_t *siginf, void *puc)
+{
+    ucontext_t *uc = puc;
+
+    switch(signum) {
+    case SIGFPE:
+        switch(siginf->si_code) {
+        case FPE_INTDIV:
+        case FPE_FLTDIV:
+            rt_error(uc, "division by zero");
+            break;
+        default:
+            rt_error(uc, "floating point exception");
+            break;
+        }
+        break;
+    case SIGBUS:
+    case SIGSEGV:
+        if (rt_bound_error_msg && *rt_bound_error_msg)
+            rt_error(uc, *rt_bound_error_msg);
+        else
+            rt_error(uc, "dereferencing invalid pointer");
+        break;
+    case SIGILL:
+        rt_error(uc, "illegal instruction");
+        break;
+    case SIGABRT:
+        rt_error(uc, "abort() called");
+        break;
+    default:
+        rt_error(uc, "caught signal %d", signum);
+        break;
+    }
+    exit(255);
+}
+
+#endif
+
+/* copy code into memory passed in by the caller and do all relocations
+   (needed before using tcc_get_symbol()).
+   returns -1 on error and required size if ptr is NULL */
+int tcc_relocate(TCCState *s1, void *ptr)
+{
+    Section *s;
+    unsigned long offset, length, mem;
+    int i;
+
+    if (0 == s1->runtime_added) {
+        s1->runtime_added = 1;
+        s1->nb_errors = 0;
+#ifdef TCC_TARGET_PE
+        pe_add_runtime(s1);
+        relocate_common_syms();
+        tcc_add_linker_symbols(s1);
+#else
+        tcc_add_runtime(s1);
+        relocate_common_syms();
+        tcc_add_linker_symbols(s1);
+        build_got_entries(s1);
+#endif
+    }
+
+    offset = 0, mem = (unsigned long)ptr;
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        if (0 == (s->sh_flags & SHF_ALLOC))
+            continue;
+        length = s->data_offset;
+        s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
+        offset = (offset + length + 15) & ~15;
+    }
+
+    /* relocate symbols */
+    relocate_syms(s1, 1);
+    if (s1->nb_errors)
+        return -1;
+
+#ifdef TCC_TARGET_X86_64
+    s1->runtime_plt_and_got_offset = 0;
+    s1->runtime_plt_and_got = (char *)(mem + offset);
+    /* double the size of the buffer for got and plt entries
+       XXX: calculate exact size for them? */
+    offset *= 2;
+#endif
+
+    if (0 == mem)
+        return offset + 15;
+
+    /* relocate each section */
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        if (s->reloc)
+            relocate_section(s1, s);
+    }
+
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        if (0 == (s->sh_flags & SHF_ALLOC))
+            continue;
+        length = s->data_offset;
+        // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
+        ptr = (void*)s->sh_addr;
+        if (NULL == s->data || s->sh_type == SHT_NOBITS)
+            memset(ptr, 0, length);
+        else
+            memcpy(ptr, s->data, length);
+        /* mark executable sections as executable in memory */
+        if (s->sh_flags & SHF_EXECINSTR)
+            set_pages_executable(ptr, length);
+    }
+#ifdef TCC_TARGET_X86_64
+    set_pages_executable(s1->runtime_plt_and_got,
+                         s1->runtime_plt_and_got_offset);
+#endif
+    return 0;
+}
+
+/* launch the compiled program with the given arguments */
+int tcc_run(TCCState *s1, int argc, char **argv)
+{
+    int (*prog_main)(int, char **);
+    void *ptr;
+    int ret;
+
+    ret = tcc_relocate(s1, NULL);
+    if (ret < 0)
+        return -1;
+    ptr = tcc_malloc(ret);
+    tcc_relocate(s1, ptr);
+
+    prog_main = tcc_get_symbol_err(s1, "main");
+    
+    if (s1->do_debug) {
+#ifdef CONFIG_TCC_BACKTRACE
+        struct sigaction sigact;
+        /* install TCC signal handlers to print debug info on fatal
+           runtime errors */
+        sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
+        sigact.sa_sigaction = sig_error;
+        sigemptyset(&sigact.sa_mask);
+        sigaction(SIGFPE, &sigact, NULL);
+        sigaction(SIGILL, &sigact, NULL);
+        sigaction(SIGSEGV, &sigact, NULL);
+        sigaction(SIGBUS, &sigact, NULL);
+        sigaction(SIGABRT, &sigact, NULL);
+#else        
+        error("debug mode not available");
+#endif
+    }
+
+#ifdef CONFIG_TCC_BCHECK
+    if (s1->do_bounds_check) {
+        void (*bound_init)(void);
+
+        /* set error function */
+        rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
+
+        /* XXX: use .init section so that it also work in binary ? */
+        bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init");
+        bound_init();
+    }
+#endif
+    ret = (*prog_main)(argc, argv);
+    tcc_free(ptr);
+    return ret;
+}
+
+void tcc_memstats(void)
+{
+#ifdef MEM_DEBUG
+    printf("memory in use: %d\n", mem_cur_size);
+#endif
+}
+
+static void tcc_cleanup(void)
+{
+    int i, n;
+
+    if (NULL == tcc_state)
+        return;
+    tcc_state = NULL;
+
+    /* free -D defines */
+    free_defines(NULL);
+
+    /* free tokens */
+    n = tok_ident - TOK_IDENT;
+    for(i = 0; i < n; i++)
+        tcc_free(table_ident[i]);
+    tcc_free(table_ident);
+
+    /* free sym_pools */
+    dynarray_reset(&sym_pools, &nb_sym_pools);
+    /* string buffer */
+    cstr_free(&tokcstr);
+    /* reset symbol stack */
+    sym_free_first = NULL;
+    /* cleanup from error/setjmp */
+    macro_ptr = NULL;
+}
+
+TCCState *tcc_new(void)
+{
+    TCCState *s;
+
+    tcc_cleanup();
+
+    s = tcc_mallocz(sizeof(TCCState));
+    if (!s)
+        return NULL;
+    tcc_state = s;
+    s->output_type = TCC_OUTPUT_MEMORY;
+    s->tcc_lib_path = CONFIG_TCCDIR;
+
+    preprocess_new();
+
+    /* we add dummy defines for some special macros to speed up tests
+       and to have working defined() */
+    define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
+    define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
+    define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
+    define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
+
+    /* standard defines */
+    tcc_define_symbol(s, "__STDC__", NULL);
+    tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
+#if defined(TCC_TARGET_I386)
+    tcc_define_symbol(s, "__i386__", NULL);
+#endif
+#if defined(TCC_TARGET_X86_64)
+    tcc_define_symbol(s, "__x86_64__", NULL);
+#endif
+#if defined(TCC_TARGET_ARM)
+    tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
+    tcc_define_symbol(s, "__arm_elf__", NULL);
+    tcc_define_symbol(s, "__arm_elf", NULL);
+    tcc_define_symbol(s, "arm_elf", NULL);
+    tcc_define_symbol(s, "__arm__", NULL);
+    tcc_define_symbol(s, "__arm", NULL);
+    tcc_define_symbol(s, "arm", NULL);
+    tcc_define_symbol(s, "__APCS_32__", NULL);
+#endif
+#ifdef TCC_TARGET_PE
+    tcc_define_symbol(s, "_WIN32", NULL);
+#else
+    tcc_define_symbol(s, "__unix__", NULL);
+    tcc_define_symbol(s, "__unix", NULL);
+#if defined(__linux)
+    tcc_define_symbol(s, "__linux__", NULL);
+    tcc_define_symbol(s, "__linux", NULL);
+#endif
+#endif
+    /* tiny C specific defines */
+    tcc_define_symbol(s, "__TINYC__", NULL);
+
+    /* tiny C & gcc defines */
+    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int");
+    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int");
+#ifdef TCC_TARGET_PE
+    tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
+#else
+    tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
+#endif
+    
+#ifndef TCC_TARGET_PE
+    /* default library paths */
+    tcc_add_library_path(s, CONFIG_SYSROOT "/usr/local/lib");
+    tcc_add_library_path(s, CONFIG_SYSROOT "/usr/lib");
+    tcc_add_library_path(s, CONFIG_SYSROOT "/lib");
+#endif
+
+    /* no section zero */
+    dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
+
+    /* create standard sections */
+    text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
+    data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
+    bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+
+    /* symbols are always generated for linking stage */
+    symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
+                                ".strtab",
+                                ".hashtab", SHF_PRIVATE); 
+    strtab_section = symtab_section->link;
+    
+    /* private symbol table for dynamic symbols */
+    s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
+                                      ".dynstrtab", 
+                                      ".dynhashtab", SHF_PRIVATE);
+    s->alacarte_link = 1;
+
+#ifdef CHAR_IS_UNSIGNED
+    s->char_is_unsigned = 1;
+#endif
+#if defined(TCC_TARGET_PE) && 0
+    /* XXX: currently the PE linker is not ready to support that */
+    s->leading_underscore = 1;
+#endif
+    return s;
+}
+
+void tcc_delete(TCCState *s1)
+{
+    int i;
+
+    tcc_cleanup();
+
+    /* free all sections */
+    for(i = 1; i < s1->nb_sections; i++)
+        free_section(s1->sections[i]);
+    dynarray_reset(&s1->sections, &s1->nb_sections);
+
+    for(i = 0; i < s1->nb_priv_sections; i++)
+        free_section(s1->priv_sections[i]);
+    dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
+        
+    /* free any loaded DLLs */
+    for ( i = 0; i < s1->nb_loaded_dlls; i++) {
+        DLLReference *ref = s1->loaded_dlls[i];
+        if ( ref->handle )
+            dlclose(ref->handle);
+    }
+    
+    /* free loaded dlls array */
+    dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
+
+    /* free library paths */
+    dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
+
+    /* free include paths */
+    dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
+    dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
+    dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
+
+    tcc_free(s1);
+}
+
+int tcc_add_include_path(TCCState *s1, const char *pathname)
+{
+    char *pathname1;
+    
+    pathname1 = tcc_strdup(pathname);
+    dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1);
+    return 0;
+}
+
+int tcc_add_sysinclude_path(TCCState *s1, const char *pathname)
+{
+    char *pathname1;
+    
+    pathname1 = tcc_strdup(pathname);
+    dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1);
+    return 0;
+}
+
+static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
+{
+    const char *ext;
+    ElfW(Ehdr) ehdr;
+    int fd, ret;
+    BufferedFile *saved_file;
+
+    /* find source file type with extension */
+    ext = tcc_fileextension(filename);
+    if (ext[0])
+        ext++;
+
+    /* open the file */
+    saved_file = file;
+    file = tcc_open(s1, filename);
+    if (!file) {
+        if (flags & AFF_PRINT_ERROR) {
+            error_noabort("file '%s' not found", filename);
+        }
+        ret = -1;
+        goto fail1;
+    }
+
+    if (flags & AFF_PREPROCESS) {
+        ret = tcc_preprocess(s1);
+    } else if (!ext[0] || !PATHCMP(ext, "c")) {
+        /* C file assumed */
+        ret = tcc_compile(s1);
+    } else 
+#ifdef CONFIG_TCC_ASM
+    if (!strcmp(ext, "S")) {
+        /* preprocessed assembler */
+        ret = tcc_assemble(s1, 1);
+    } else if (!strcmp(ext, "s")) {
+        /* non preprocessed assembler */
+        ret = tcc_assemble(s1, 0);
+    } else 
+#endif
+#ifdef TCC_TARGET_PE
+    if (!PATHCMP(ext, "def")) {
+        ret = pe_load_def_file(s1, file->fd);
+    } else
+#endif
+    {
+        fd = file->fd;
+        /* assume executable format: auto guess file type */
+        ret = read(fd, &ehdr, sizeof(ehdr));
+        lseek(fd, 0, SEEK_SET);
+        if (ret <= 0) {
+            error_noabort("could not read header");
+            goto fail;
+        } else if (ret != sizeof(ehdr)) {
+            goto try_load_script;
+        }
+
+        if (ehdr.e_ident[0] == ELFMAG0 &&
+            ehdr.e_ident[1] == ELFMAG1 &&
+            ehdr.e_ident[2] == ELFMAG2 &&
+            ehdr.e_ident[3] == ELFMAG3) {
+            file->line_num = 0; /* do not display line number if error */
+            if (ehdr.e_type == ET_REL) {
+                ret = tcc_load_object_file(s1, fd, 0);
+            } else if (ehdr.e_type == ET_DYN) {
+                if (s1->output_type == TCC_OUTPUT_MEMORY) {
+#ifdef TCC_TARGET_PE
+                    ret = -1;
+#else
+                    void *h;
+                    h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
+                    if (h)
+                        ret = 0;
+                    else
+                        ret = -1;
+#endif
+                } else {
+                    ret = tcc_load_dll(s1, fd, filename, 
+                                       (flags & AFF_REFERENCED_DLL) != 0);
+                }
+            } else {
+                error_noabort("unrecognized ELF file");
+                goto fail;
+            }
+        } else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
+            file->line_num = 0; /* do not display line number if error */
+            ret = tcc_load_archive(s1, fd);
+        } else 
+#ifdef TCC_TARGET_COFF
+        if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
+            ret = tcc_load_coff(s1, fd);
+        } else
+#endif
+#ifdef TCC_TARGET_PE
+        if (pe_test_res_file(&ehdr, ret)) {
+            ret = pe_load_res_file(s1, fd);
+        } else
+#endif
+        {
+            /* as GNU ld, consider it is an ld script if not recognized */
+        try_load_script:
+            ret = tcc_load_ldscript(s1);
+            if (ret < 0) {
+                error_noabort("unrecognized file type");
+                goto fail;
+            }
+        }
+    }
+ the_end:
+    tcc_close(file);
+ fail1:
+    file = saved_file;
+    return ret;
+ fail:
+    ret = -1;
+    goto the_end;
+}
+
+int tcc_add_file(TCCState *s, const char *filename)
+{
+    if (s->output_type == TCC_OUTPUT_PREPROCESS)
+        return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS);
+    else
+        return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR);
+}
+
+int tcc_add_library_path(TCCState *s, const char *pathname)
+{
+    char *pathname1;
+    
+    pathname1 = tcc_strdup(pathname);
+    dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1);
+    return 0;
+}
+
+/* find and load a dll. Return non zero if not found */
+/* XXX: add '-rpath' option support ? */
+static int tcc_add_dll(TCCState *s, const char *filename, int flags)
+{
+    char buf[1024];
+    int i;
+
+    for(i = 0; i < s->nb_library_paths; i++) {
+        snprintf(buf, sizeof(buf), "%s/%s", 
+                 s->library_paths[i], filename);
+        if (tcc_add_file_internal(s, buf, flags) == 0)
+            return 0;
+    }
+    return -1;
+}
+
+/* the library name is the same as the argument of the '-l' option */
+int tcc_add_library(TCCState *s, const char *libraryname)
+{
+    char buf[1024];
+    int i;
+    
+    /* first we look for the dynamic library if not static linking */
+    if (!s->static_link) {
+#ifdef TCC_TARGET_PE
+        snprintf(buf, sizeof(buf), "%s.def", libraryname);
+#else
+        snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
+#endif
+        if (tcc_add_dll(s, buf, 0) == 0)
+            return 0;
+    }
+
+    /* then we look for the static library */
+    for(i = 0; i < s->nb_library_paths; i++) {
+        snprintf(buf, sizeof(buf), "%s/lib%s.a", 
+                 s->library_paths[i], libraryname);
+        if (tcc_add_file_internal(s, buf, 0) == 0)
+            return 0;
+    }
+    return -1;
+}
+
+int tcc_add_symbol(TCCState *s, const char *name, void *val)
+{
+    add_elf_sym(symtab_section, (unsigned long)val, 0, 
+                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                SHN_ABS, name);
+    return 0;
+}
+
+int tcc_set_output_type(TCCState *s, int output_type)
+{
+    char buf[1024];
+
+    s->output_type = output_type;
+
+    if (!s->nostdinc) {
+        /* default include paths */
+        /* XXX: reverse order needed if -isystem support */
+#ifndef TCC_TARGET_PE
+        tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/local/include");
+        tcc_add_sysinclude_path(s, CONFIG_SYSROOT "/usr/include");
+#endif
+        snprintf(buf, sizeof(buf), "%s/include", s->tcc_lib_path);
+        tcc_add_sysinclude_path(s, buf);
+#ifdef TCC_TARGET_PE
+        snprintf(buf, sizeof(buf), "%s/include/winapi", s->tcc_lib_path);
+        tcc_add_sysinclude_path(s, buf);
+#endif
+    }
+
+    /* if bound checking, then add corresponding sections */
+#ifdef CONFIG_TCC_BCHECK
+    if (s->do_bounds_check) {
+        /* define symbol */
+        tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
+        /* create bounds sections */
+        bounds_section = new_section(s, ".bounds", 
+                                     SHT_PROGBITS, SHF_ALLOC);
+        lbounds_section = new_section(s, ".lbounds", 
+                                      SHT_PROGBITS, SHF_ALLOC);
+    }
+#endif
+
+    if (s->char_is_unsigned) {
+        tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
+    }
+
+    /* add debug sections */
+    if (s->do_debug) {
+        /* stab symbols */
+        stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
+        stab_section->sh_entsize = sizeof(Stab_Sym);
+        stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
+        put_elf_str(stabstr_section, "");
+        stab_section->link = stabstr_section;
+        /* put first entry */
+        put_stabs("", 0, 0, 0, 0);
+    }
+
+    /* add libc crt1/crti objects */
+#ifndef TCC_TARGET_PE
+    if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
+        !s->nostdlib) {
+        if (output_type != TCC_OUTPUT_DLL)
+            tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
+        tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
+    }
+#endif
+
+#ifdef TCC_TARGET_PE
+    snprintf(buf, sizeof(buf), "%s/lib", s->tcc_lib_path);
+    tcc_add_library_path(s, buf);
+#endif
+
+    return 0;
+}
+
+#define WD_ALL    0x0001 /* warning is activated when using -Wall */
+#define FD_INVERT 0x0002 /* invert value before storing */
+
+typedef struct FlagDef {
+    uint16_t offset;
+    uint16_t flags;
+    const char *name;
+} FlagDef;
+
+static const FlagDef warning_defs[] = {
+    { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
+    { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
+    { offsetof(TCCState, warn_error), 0, "error" },
+    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
+      "implicit-function-declaration" },
+};
+
+static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
+                    const char *name, int value)
+{
+    int i;
+    const FlagDef *p;
+    const char *r;
+
+    r = name;
+    if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
+        r += 3;
+        value = !value;
+    }
+    for(i = 0, p = flags; i < nb_flags; i++, p++) {
+        if (!strcmp(r, p->name))
+            goto found;
+    }
+    return -1;
+ found:
+    if (p->flags & FD_INVERT)
+        value = !value;
+    *(int *)((uint8_t *)s + p->offset) = value;
+    return 0;
+}
+
+
+/* set/reset a warning */
+int tcc_set_warning(TCCState *s, const char *warning_name, int value)
+{
+    int i;
+    const FlagDef *p;
+
+    if (!strcmp(warning_name, "all")) {
+        for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
+            if (p->flags & WD_ALL)
+                *(int *)((uint8_t *)s + p->offset) = 1;
+        }
+        return 0;
+    } else {
+        return set_flag(s, warning_defs, countof(warning_defs),
+                        warning_name, value);
+    }
+}
+
+static const FlagDef flag_defs[] = {
+    { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
+    { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
+    { offsetof(TCCState, nocommon), FD_INVERT, "common" },
+    { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
+};
+
+/* set/reset a flag */
+int tcc_set_flag(TCCState *s, const char *flag_name, int value)
+{
+    return set_flag(s, flag_defs, countof(flag_defs),
+                    flag_name, value);
+}
+
+/* set CONFIG_TCCDIR at runtime */
+void tcc_set_lib_path(TCCState *s, const char *path)
+{
+    s->tcc_lib_path = tcc_strdup(path);
+}
+
+void tcc_print_stats(TCCState *s, int64_t total_time)
+{
+    double tt;
+    tt = (double)total_time / 1000000.0;
+    if (tt < 0.001)
+        tt = 0.001;
+    if (total_bytes < 1)
+        total_bytes = 1;
+    printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n", 
+           tok_ident - TOK_IDENT, total_lines, total_bytes,
+           tt, (int)(total_lines / tt),
+           total_bytes / tt / 1000000.0);
+}
diff --git a/tinyc/libtcc.h b/tinyc/libtcc.h
new file mode 100644
index 000000000..96070e299
--- /dev/null
+++ b/tinyc/libtcc.h
@@ -0,0 +1,108 @@
+#ifndef LIBTCC_H
+#define LIBTCC_H
+
+#ifdef LIBTCC_AS_DLL
+#define LIBTCCAPI __declspec(dllexport)
+#else
+#define LIBTCCAPI
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct TCCState;
+
+typedef struct TCCState TCCState;
+
+/* create a new TCC compilation context */
+LIBTCCAPI TCCState *tcc_new(void);
+
+/* free a TCC compilation context */
+LIBTCCAPI void tcc_delete(TCCState *s);
+
+/* add debug information in the generated code */
+LIBTCCAPI void tcc_enable_debug(TCCState *s);
+
+/* set error/warning display callback */
+LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
+                        void (*error_func)(void *opaque, const char *msg));
+
+/* set/reset a warning */
+LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value);
+
+/*****************************/
+/* preprocessor */
+
+/* add include path */
+LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
+
+/* add in system include path */
+LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
+
+/* define preprocessor symbol 'sym'. Can put optional value */
+LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
+
+/* undefine preprocess symbol 'sym' */
+LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
+
+/*****************************/
+/* compiling */
+
+/* add a file (either a C file, dll, an object, a library or an ld
+   script). Return -1 if error. */
+LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
+
+/* compile a string containing a C source. Return non zero if
+   error. */
+LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
+
+/*****************************/
+/* linking commands */
+
+/* set output type. MUST BE CALLED before any compilation */
+#define TCC_OUTPUT_MEMORY   0 /* output will be ran in memory (no
+                                 output file) (default) */
+#define TCC_OUTPUT_EXE      1 /* executable file */
+#define TCC_OUTPUT_DLL      2 /* dynamic library */
+#define TCC_OUTPUT_OBJ      3 /* object file */
+#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */
+LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
+
+#define TCC_OUTPUT_FORMAT_ELF    0 /* default output format: ELF */
+#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
+#define TCC_OUTPUT_FORMAT_COFF   2 /* COFF */
+
+/* equivalent to -Lpath option */
+LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
+
+/* the library name is the same as the argument of the '-l' option */
+LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
+
+/* add a symbol to the compiled program */
+LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, void *val);
+
+/* output an executable, library or object file. DO NOT call
+   tcc_relocate() before. */
+LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
+
+/* link and run main() function and return its value. DO NOT call
+   tcc_relocate() before. */
+LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
+
+/* copy code into memory passed in by the caller and do all relocations
+   (needed before using tcc_get_symbol()).
+   returns -1 on error and required size if ptr is NULL */
+LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
+
+/* return symbol value or NULL if not found */
+LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
+
+/* set CONFIG_TCCDIR at runtime */
+LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tinyc/stab.def b/tinyc/stab.def
new file mode 100644
index 000000000..48ea231e6
--- /dev/null
+++ b/tinyc/stab.def
@@ -0,0 +1,234 @@
+/* Table of DBX symbol codes for the GNU system.
+   Copyright (C) 1988, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This contains contribution from Cygnus Support.  */
+
+/* Global variable.  Only the name is significant.
+   To find the address, look in the corresponding external symbol.  */
+__define_stab (N_GSYM, 0x20, "GSYM")
+
+/* Function name for BSD Fortran.  Only the name is significant.
+   To find the address, look in the corresponding external symbol.  */
+__define_stab (N_FNAME, 0x22, "FNAME")
+
+/* Function name or text-segment variable for C.  Value is its address.
+   Desc is supposedly starting line number, but GCC doesn't set it
+   and DBX seems not to miss it.  */
+__define_stab (N_FUN, 0x24, "FUN")
+
+/* Data-segment variable with internal linkage.  Value is its address.
+   "Static Sym".  */
+__define_stab (N_STSYM, 0x26, "STSYM")
+
+/* BSS-segment variable with internal linkage.  Value is its address.  */
+__define_stab (N_LCSYM, 0x28, "LCSYM")
+
+/* Name of main routine.  Only the name is significant.
+   This is not used in C.  */
+__define_stab (N_MAIN, 0x2a, "MAIN")
+
+/* Global symbol in Pascal.
+   Supposedly the value is its line number; I'm skeptical.  */
+__define_stab (N_PC, 0x30, "PC")
+
+/* Number of symbols:  0, files,,funcs,lines according to Ultrix V4.0. */
+__define_stab (N_NSYMS, 0x32, "NSYMS")
+
+/* "No DST map for sym: name, ,0,type,ignored"  according to Ultrix V4.0. */
+__define_stab (N_NOMAP, 0x34, "NOMAP")
+
+/* New stab from Solaris.  I don't know what it means, but it
+   don't seem to contain useful information.  */
+__define_stab (N_OBJ, 0x38, "OBJ")
+
+/* New stab from Solaris.  I don't know what it means, but it
+   don't seem to contain useful information.  Possibly related to the
+   optimization flags used in this module.  */
+__define_stab (N_OPT, 0x3c, "OPT")
+
+/* Register variable.  Value is number of register.  */
+__define_stab (N_RSYM, 0x40, "RSYM")
+
+/* Modula-2 compilation unit.  Can someone say what info it contains?  */
+__define_stab (N_M2C, 0x42, "M2C")
+
+/* Line number in text segment.  Desc is the line number;
+   value is corresponding address.  */
+__define_stab (N_SLINE, 0x44, "SLINE")
+
+/* Similar, for data segment.  */
+__define_stab (N_DSLINE, 0x46, "DSLINE")
+
+/* Similar, for bss segment.  */
+__define_stab (N_BSLINE, 0x48, "BSLINE")
+
+/* Sun's source-code browser stabs.  ?? Don't know what the fields are.
+   Supposedly the field is "path to associated .cb file".  THIS VALUE
+   OVERLAPS WITH N_BSLINE!  */
+__define_stab (N_BROWS, 0x48, "BROWS")
+
+/* GNU Modula-2 definition module dependency.  Value is the modification time
+   of the definition file.  Other is non-zero if it is imported with the
+   GNU M2 keyword %INITIALIZE.  Perhaps N_M2C can be used if there
+   are enough empty fields? */
+__define_stab(N_DEFD, 0x4a, "DEFD")
+
+/* THE FOLLOWING TWO STAB VALUES CONFLICT.  Happily, one is for Modula-2
+   and one is for C++.   Still,... */
+/* GNU C++ exception variable.  Name is variable name.  */
+__define_stab (N_EHDECL, 0x50, "EHDECL")
+/* Modula2 info "for imc":  name,,0,0,0  according to Ultrix V4.0.  */
+__define_stab (N_MOD2, 0x50, "MOD2")
+
+/* GNU C++ `catch' clause.  Value is its address.  Desc is nonzero if
+   this entry is immediately followed by a CAUGHT stab saying what exception
+   was caught.  Multiple CAUGHT stabs means that multiple exceptions
+   can be caught here.  If Desc is 0, it means all exceptions are caught
+   here.  */
+__define_stab (N_CATCH, 0x54, "CATCH")
+
+/* Structure or union element.  Value is offset in the structure.  */
+__define_stab (N_SSYM, 0x60, "SSYM")
+
+/* Name of main source file.
+   Value is starting text address of the compilation.  */
+__define_stab (N_SO, 0x64, "SO")
+
+/* Automatic variable in the stack.  Value is offset from frame pointer.
+   Also used for type descriptions.  */
+__define_stab (N_LSYM, 0x80, "LSYM")
+
+/* Beginning of an include file.  Only Sun uses this.
+   In an object file, only the name is significant.
+   The Sun linker puts data into some of the other fields.  */
+__define_stab (N_BINCL, 0x82, "BINCL")
+
+/* Name of sub-source file (#include file).
+   Value is starting text address of the compilation.  */
+__define_stab (N_SOL, 0x84, "SOL")
+
+/* Parameter variable.  Value is offset from argument pointer.
+   (On most machines the argument pointer is the same as the frame pointer.  */
+__define_stab (N_PSYM, 0xa0, "PSYM")
+
+/* End of an include file.  No name.
+   This and N_BINCL act as brackets around the file's output.
+   In an object file, there is no significant data in this entry.
+   The Sun linker puts data into some of the fields.  */
+__define_stab (N_EINCL, 0xa2, "EINCL")
+
+/* Alternate entry point.  Value is its address.  */
+__define_stab (N_ENTRY, 0xa4, "ENTRY")
+
+/* Beginning of lexical block.
+   The desc is the nesting level in lexical blocks.
+   The value is the address of the start of the text for the block.
+   The variables declared inside the block *precede* the N_LBRAC symbol.  */
+__define_stab (N_LBRAC, 0xc0, "LBRAC")
+
+/* Place holder for deleted include file.  Replaces a N_BINCL and everything
+   up to the corresponding N_EINCL.  The Sun linker generates these when
+   it finds multiple identical copies of the symbols from an include file.
+   This appears only in output from the Sun linker.  */
+__define_stab (N_EXCL, 0xc2, "EXCL")
+
+/* Modula-2 scope information.  Can someone say what info it contains?  */
+__define_stab (N_SCOPE, 0xc4, "SCOPE")
+
+/* End of a lexical block.  Desc matches the N_LBRAC's desc.
+   The value is the address of the end of the text for the block.  */
+__define_stab (N_RBRAC, 0xe0, "RBRAC")
+
+/* Begin named common block.  Only the name is significant.  */
+__define_stab (N_BCOMM, 0xe2, "BCOMM")
+
+/* End named common block.  Only the name is significant
+   (and it should match the N_BCOMM).  */
+__define_stab (N_ECOMM, 0xe4, "ECOMM")
+
+/* End common (local name): value is address.
+   I'm not sure how this is used.  */
+__define_stab (N_ECOML, 0xe8, "ECOML")
+
+/* These STAB's are used on Gould systems for Non-Base register symbols
+   or something like that.  FIXME.  I have assigned the values at random
+   since I don't have a Gould here.  Fixups from Gould folk welcome... */
+__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
+__define_stab (N_NBDATA, 0xF2, "NBDATA")
+__define_stab (N_NBBSS,  0xF4, "NBBSS")
+__define_stab (N_NBSTS,  0xF6, "NBSTS")
+__define_stab (N_NBLCS,  0xF8, "NBLCS")
+
+/* Second symbol entry containing a length-value for the preceding entry.
+   The value is the length.  */
+__define_stab (N_LENG, 0xfe, "LENG")
+
+/* The above information, in matrix format.
+
+			STAB MATRIX
+	_________________________________________________
+	| 00 - 1F are not dbx stab symbols		|
+	| In most cases, the low bit is the EXTernal bit|
+
+	| 00 UNDEF  | 02 ABS	| 04 TEXT   | 06 DATA	|
+	| 01  |EXT  | 03  |EXT	| 05  |EXT  | 07  |EXT	|
+
+	| 08 BSS    | 0A INDR	| 0C FN_SEQ | 0E   	|
+	| 09  |EXT  | 0B 	| 0D	    | 0F	|
+
+	| 10 	    | 12 COMM	| 14 SETA   | 16 SETT	|
+	| 11	    | 13	| 15 	    | 17	|
+
+	| 18 SETD   | 1A SETB	| 1C SETV   | 1E WARNING|
+	| 19	    | 1B	| 1D 	    | 1F FN	|
+
+	|_______________________________________________|
+	| Debug entries with bit 01 set are unused.	|
+	| 20 GSYM   | 22 FNAME	| 24 FUN    | 26 STSYM	|
+	| 28 LCSYM  | 2A MAIN	| 2C	    | 2E	|
+	| 30 PC	    | 32 NSYMS	| 34 NOMAP  | 36	|
+	| 38 OBJ    | 3A	| 3C OPT    | 3E	|
+	| 40 RSYM   | 42 M2C	| 44 SLINE  | 46 DSLINE |
+	| 48 BSLINE*| 4A DEFD	| 4C        | 4E	|
+	| 50 EHDECL*| 52	| 54 CATCH  | 56        |
+	| 58        | 5A        | 5C        | 5E	|
+	| 60 SSYM   | 62	| 64 SO	    | 66 	|
+	| 68 	    | 6A	| 6C	    | 6E	|
+	| 70	    | 72	| 74	    | 76	|
+	| 78	    | 7A	| 7C	    | 7E	|
+	| 80 LSYM   | 82 BINCL	| 84 SOL    | 86	|
+	| 88	    | 8A	| 8C	    | 8E	|
+	| 90	    | 92	| 94	    | 96	|
+	| 98	    | 9A	| 9C	    | 9E	|
+	| A0 PSYM   | A2 EINCL	| A4 ENTRY  | A6	|
+	| A8	    | AA	| AC	    | AE	|
+	| B0	    | B2	| B4	    | B6	|
+	| B8	    | BA	| BC	    | BE	|
+	| C0 LBRAC  | C2 EXCL	| C4 SCOPE  | C6	|
+	| C8	    | CA	| CC	    | CE	|
+	| D0	    | D2	| D4	    | D6	|
+	| D8	    | DA	| DC	    | DE	|
+	| E0 RBRAC  | E2 BCOMM	| E4 ECOMM  | E6	|
+	| E8 ECOML  | EA	| EC	    | EE	|
+	| F0	    | F2	| F4	    | F6	|
+	| F8	    | FA	| FC	    | FE LENG	|
+	+-----------------------------------------------+
+ * 50 EHDECL is also MOD2.
+ * 48 BSLINE is also BROWS.
+ */
diff --git a/tinyc/stab.h b/tinyc/stab.h
new file mode 100644
index 000000000..80bd594a3
--- /dev/null
+++ b/tinyc/stab.h
@@ -0,0 +1,17 @@
+#ifndef __GNU_STAB__
+
+/* Indicate the GNU stab.h is in use.  */
+
+#define __GNU_STAB__
+
+#define __define_stab(NAME, CODE, STRING) NAME=CODE,
+
+enum __stab_debug_code
+{
+#include "stab.def"
+LAST_UNUSED_STAB_CODE
+};
+
+#undef __define_stab
+
+#endif /* __GNU_STAB_ */
diff --git a/tinyc/tcc-doc.html b/tinyc/tcc-doc.html
new file mode 100644
index 000000000..bd856d256
--- /dev/null
+++ b/tinyc/tcc-doc.html
@@ -0,0 +1,2241 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd">
+<html>
+<!-- Created on May, 18 2009 by texi2html 1.78 -->
+<!--
+Written by: Lionel Cons <Lionel.Cons@cern.ch> (original author)
+            Karl Berry  <karl@freefriends.org>
+            Olaf Bachmann <obachman@mathematik.uni-kl.de>
+            and many others.
+Maintained by: Many creative people.
+Send bugs and suggestions to <texi2html-bug@nongnu.org>
+
+-->
+<head>
+<title>Tiny C Compiler Reference Documentation</title>
+
+<meta name="description" content="Tiny C Compiler Reference Documentation">
+<meta name="keywords" content="Tiny C Compiler Reference Documentation">
+<meta name="resource-type" content="document">
+<meta name="distribution" content="global">
+<meta name="Generator" content="texi2html 1.78">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style type="text/css">
+<!--
+a.summary-letter {text-decoration: none}
+pre.display {font-family: serif}
+pre.format {font-family: serif}
+pre.menu-comment {font-family: serif}
+pre.menu-preformatted {font-family: serif}
+pre.smalldisplay {font-family: serif; font-size: smaller}
+pre.smallexample {font-size: smaller}
+pre.smallformat {font-family: serif; font-size: smaller}
+pre.smalllisp {font-size: smaller}
+span.roman {font-family:serif; font-weight:normal;}
+span.sansserif {font-family:sans-serif; font-weight:normal;}
+ul.toc {list-style: none}
+-->
+</style>
+
+
+</head>
+
+<body lang="en" bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000">
+
+<a name="Top"></a>
+<a name="SEC_Top"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="settitle">Tiny C Compiler Reference Documentation</h1>
+
+<p>This manual documents version  of the Tiny C Compiler.
+</p>
+<table class="menu" border="0" cellspacing="0">
+<tr><td align="left" valign="top"><a href="#SEC1">1. Introduction</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                Introduction to tcc.
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC2">2. Command line invocation</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                      Invocation of tcc (command line, options).
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC5">3. C language support</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                       ANSI C and extensions.
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC10">4. TinyCC Assembler</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                         Assembler syntax.
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC16">5. TinyCC Linker</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                      Output file generation and supported targets.
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC21">6. TinyCC Memory and Bound checks</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                      Automatic bounds-checking of C code.
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC22">7. The <code>libtcc</code> library</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                      The libtcc library.
+</td></tr>
+<tr><td align="left" valign="top"><a href="#SEC23">8. Developer's guide</a></td><td>&nbsp;&nbsp;</td><td align="left" valign="top">                       Guide for Developers.
+</td></tr>
+</table>
+
+
+<hr size="1">
+<a name="Introduction"></a>
+<a name="SEC1"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC_Top" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[ &lt;&lt; ]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 1. Introduction </h1>
+
+<p>TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C
+compilers, it is meant to be self-relying: you do not need an
+external assembler or linker because TCC does that for you.
+</p>
+<p>TCC compiles so <em>fast</em> that even for big projects <code>Makefile</code>s may
+not be necessary.
+</p>
+<p>TCC not only supports ANSI C, but also most of the new ISO C99
+standard and many GNUC extensions including inline assembly.
+</p>
+<p>TCC can also be used to make <em>C scripts</em>, i.e. pieces of C source
+that you run as a Perl or Python script. Compilation is so fast that
+your script will be as fast as if it was an executable.
+</p>
+<p>TCC can also automatically generate memory and bound checks
+(see section <a href="#SEC21">TinyCC Memory and Bound checks</a>) while allowing all C pointers operations. TCC can do
+these checks even if non patched libraries are used.
+</p>
+<p>With <code>libtcc</code>, you can use TCC as a backend for dynamic code
+generation (see section <a href="#SEC22">The <code>libtcc</code> library</a>).
+</p>
+<p>TCC mainly supports the i386 target on Linux and Windows. There are alpha
+ports for the ARM (<code>arm-tcc</code>) and the TMS320C67xx targets
+(<code>c67-tcc</code>). More information about the ARM port is available at
+<a href="http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html">http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html</a>.
+</p>
+<p>For usage on Windows, see also tcc-win32.txt.
+</p>
+<hr size="6">
+<a name="Invoke"></a>
+<a name="SEC2"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC1" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC3" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC1" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 2. Command line invocation </h1>
+
+<hr size="6">
+<a name="SEC3"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC2" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC4" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 2.1 Quick start </h2>
+
+<table><tr><td>&nbsp;</td><td><pre class="example">usage: tcc [options] [<var>infile1</var> <var>infile2</var>&hellip;] [&lsquo;<samp>-run</samp>&rsquo; <var>infile</var> <var>args</var>&hellip;]
+</pre></td></tr></table>
+
+<p>TCC options are a very much like gcc options. The main difference is that TCC
+can also execute directly the resulting program and give it runtime
+arguments.
+</p>
+<p>Here are some examples to understand the logic:
+</p>
+<dl compact="compact">
+<dt> <code>&lsquo;<samp>tcc -run a.c</samp>&rsquo;</code></dt>
+<dd><p>Compile &lsquo;<tt>a.c</tt>&rsquo; and execute it directly
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -run a.c arg1</samp>&rsquo;</code></dt>
+<dd><p>Compile a.c and execute it directly. arg1 is given as first argument to
+the <code>main()</code> of a.c.
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc a.c -run b.c arg1</samp>&rsquo;</code></dt>
+<dd><p>Compile &lsquo;<tt>a.c</tt>&rsquo; and &lsquo;<tt>b.c</tt>&rsquo;, link them together and execute them. arg1 is given
+as first argument to the <code>main()</code> of the resulting program. 
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -o myprog a.c b.c</samp>&rsquo;</code></dt>
+<dd><p>Compile &lsquo;<tt>a.c</tt>&rsquo; and &lsquo;<tt>b.c</tt>&rsquo;, link them and generate the executable &lsquo;<tt>myprog</tt>&rsquo;.
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -o myprog a.o b.o</samp>&rsquo;</code></dt>
+<dd><p>link &lsquo;<tt>a.o</tt>&rsquo; and &lsquo;<tt>b.o</tt>&rsquo; together and generate the executable &lsquo;<tt>myprog</tt>&rsquo;.
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -c a.c</samp>&rsquo;</code></dt>
+<dd><p>Compile &lsquo;<tt>a.c</tt>&rsquo; and generate object file &lsquo;<tt>a.o</tt>&rsquo;.
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -c asmfile.S</samp>&rsquo;</code></dt>
+<dd><p>Preprocess with C preprocess and assemble &lsquo;<tt>asmfile.S</tt>&rsquo; and generate
+object file &lsquo;<tt>asmfile.o</tt>&rsquo;.
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -c asmfile.s</samp>&rsquo;</code></dt>
+<dd><p>Assemble (but not preprocess) &lsquo;<tt>asmfile.s</tt>&rsquo; and generate object file
+&lsquo;<tt>asmfile.o</tt>&rsquo;.
+</p>
+</dd>
+<dt> <code>&lsquo;<samp>tcc -r -o ab.o a.c b.c</samp>&rsquo;</code></dt>
+<dd><p>Compile &lsquo;<tt>a.c</tt>&rsquo; and &lsquo;<tt>b.c</tt>&rsquo;, link them together and generate the object file &lsquo;<tt>ab.o</tt>&rsquo;.
+</p>
+</dd>
+</dl>
+
+<p>Scripting:
+</p>
+<p>TCC can be invoked from <em>scripts</em>, just as shell scripts. You just
+need to add <code>#!/usr/local/bin/tcc -run</code> at the start of your C source:
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">#!/usr/local/bin/tcc -run
+#include &lt;stdio.h&gt;
+
+int main() 
+{
+    printf(&quot;Hello World\n&quot;);
+    return 0;
+}
+</pre></td></tr></table>
+
+<p>TCC can read C source code from <em>standard input</em> when &lsquo;<samp>-</samp>&rsquo; is used in 
+place of &lsquo;<samp>infile</samp>&rsquo;. Example:
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">echo 'main(){puts(&quot;hello&quot;);}' | tcc -run -
+</pre></td></tr></table>
+
+<hr size="6">
+<a name="SEC4"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC3" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 2.2 Option summary </h2>
+
+<p>General Options:
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-v</samp>&rsquo;</dt>
+<dd><p>Display current TCC version, increase verbosity.
+</p>
+</dd>
+<dt> &lsquo;<samp>-c</samp>&rsquo;</dt>
+<dd><p>Generate an object file (&lsquo;<samp>-o</samp>&rsquo; option must also be given).
+</p>
+</dd>
+<dt> &lsquo;<samp>-o outfile</samp>&rsquo;</dt>
+<dd><p>Put object file, executable, or dll into output file &lsquo;<tt>outfile</tt>&rsquo;.
+</p>
+</dd>
+<dt> &lsquo;<samp>-Bdir</samp>&rsquo;</dt>
+<dd><p>Set the path where the tcc internal libraries can be found (default is
+&lsquo;<tt>PREFIX/lib/tcc</tt>&rsquo;).
+</p>
+</dd>
+<dt> &lsquo;<samp>-bench</samp>&rsquo;</dt>
+<dd><p>Output compilation statistics.
+</p>
+</dd>
+<dt> &lsquo;<samp>-run source [args...]</samp>&rsquo;</dt>
+<dd><p>Compile file <var>source</var> and run it with the command line arguments
+<var>args</var>. In order to be able to give more than one argument to a
+script, several TCC options can be given <em>after</em> the
+&lsquo;<samp>-run</samp>&rsquo; option, separated by spaces. Example:
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">tcc &quot;-run -L/usr/X11R6/lib -lX11&quot; ex4.c
+</pre></td></tr></table>
+
+<p>In a script, it gives the following header:
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
+#include &lt;stdlib.h&gt;
+int main(int argc, char **argv)
+{
+    ...
+}
+</pre></td></tr></table>
+
+</dd>
+</dl>
+
+<p>Preprocessor options:
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-Idir</samp>&rsquo;</dt>
+<dd><p>Specify an additional include path. Include paths are searched in the
+order they are specified.
+</p>
+<p>System include paths are always searched after. The default system
+include paths are: &lsquo;<tt>/usr/local/include</tt>&rsquo;, &lsquo;<tt>/usr/include</tt>&rsquo;
+and &lsquo;<tt>PREFIX/lib/tcc/include</tt>&rsquo;. (&lsquo;<tt>PREFIX</tt>&rsquo; is usually
+&lsquo;<tt>/usr</tt>&rsquo; or &lsquo;<tt>/usr/local</tt>&rsquo;).
+</p>
+</dd>
+<dt> &lsquo;<samp>-Dsym[=val]</samp>&rsquo;</dt>
+<dd><p>Define preprocessor symbol &lsquo;<samp>sym</samp>&rsquo; to
+val. If val is not present, its value is &lsquo;<samp>1</samp>&rsquo;. Function-like macros can
+also be defined: &lsquo;<samp>-DF(a)=a+1</samp>&rsquo;
+</p>
+</dd>
+<dt> &lsquo;<samp>-Usym</samp>&rsquo;</dt>
+<dd><p>Undefine preprocessor symbol &lsquo;<samp>sym</samp>&rsquo;.
+</p></dd>
+</dl>
+
+<p>Compilation flags:
+</p>
+<p>Note: each of the following warning options has a negative form beginning with
+&lsquo;<samp>-fno-</samp>&rsquo;.
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-funsigned-char</samp>&rsquo;</dt>
+<dd><p>Let the <code>char</code> type be unsigned.
+</p>
+</dd>
+<dt> &lsquo;<samp>-fsigned-char</samp>&rsquo;</dt>
+<dd><p>Let the <code>char</code> type be signed.
+</p>
+</dd>
+<dt> &lsquo;<samp>-fno-common</samp>&rsquo;</dt>
+<dd><p>Do not generate common symbols for uninitialized data.
+</p>
+</dd>
+<dt> &lsquo;<samp>-fleading-underscore</samp>&rsquo;</dt>
+<dd><p>Add a leading underscore at the beginning of each C symbol.
+</p>
+</dd>
+</dl>
+
+<p>Warning options:
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-w</samp>&rsquo;</dt>
+<dd><p>Disable all warnings.
+</p>
+</dd>
+</dl>
+
+<p>Note: each of the following warning options has a negative form beginning with
+&lsquo;<samp>-Wno-</samp>&rsquo;.
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-Wimplicit-function-declaration</samp>&rsquo;</dt>
+<dd><p>Warn about implicit function declaration.
+</p>
+</dd>
+<dt> &lsquo;<samp>-Wunsupported</samp>&rsquo;</dt>
+<dd><p>Warn about unsupported GCC features that are ignored by TCC.
+</p>
+</dd>
+<dt> &lsquo;<samp>-Wwrite-strings</samp>&rsquo;</dt>
+<dd><p>Make string constants be of type <code>const char *</code> instead of <code>char
+*</code>.
+</p>
+</dd>
+<dt> &lsquo;<samp>-Werror</samp>&rsquo;</dt>
+<dd><p>Abort compilation if warnings are issued.
+</p>
+</dd>
+<dt> &lsquo;<samp>-Wall</samp>&rsquo; </dt>
+<dd><p>Activate all warnings, except &lsquo;<samp>-Werror</samp>&rsquo;, &lsquo;<samp>-Wunusupported</samp>&rsquo; and
+&lsquo;<samp>-Wwrite-strings</samp>&rsquo;.
+</p>
+</dd>
+</dl>
+
+<p>Linker options:
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-Ldir</samp>&rsquo;</dt>
+<dd><p>Specify an additional static library path for the &lsquo;<samp>-l</samp>&rsquo; option. The
+default library paths are &lsquo;<tt>/usr/local/lib</tt>&rsquo;, &lsquo;<tt>/usr/lib</tt>&rsquo; and &lsquo;<tt>/lib</tt>&rsquo;.
+</p>
+</dd>
+<dt> &lsquo;<samp>-lxxx</samp>&rsquo;</dt>
+<dd><p>Link your program with dynamic library libxxx.so or static library
+libxxx.a. The library is searched in the paths specified by the
+&lsquo;<samp>-L</samp>&rsquo; option.
+</p>
+</dd>
+<dt> &lsquo;<samp>-shared</samp>&rsquo;</dt>
+<dd><p>Generate a shared library instead of an executable (&lsquo;<samp>-o</samp>&rsquo; option
+must also be given).
+</p>
+</dd>
+<dt> &lsquo;<samp>-static</samp>&rsquo;</dt>
+<dd><p>Generate a statically linked executable (default is a shared linked
+executable) (&lsquo;<samp>-o</samp>&rsquo; option must also be given).
+</p>
+</dd>
+<dt> &lsquo;<samp>-rdynamic</samp>&rsquo;</dt>
+<dd><p>Export global symbols to the dynamic linker. It is useful when a library
+opened with <code>dlopen()</code> needs to access executable symbols.
+</p>
+</dd>
+<dt> &lsquo;<samp>-r</samp>&rsquo;</dt>
+<dd><p>Generate an object file combining all input files (&lsquo;<samp>-o</samp>&rsquo; option must
+also be given).
+</p>
+</dd>
+<dt> &lsquo;<samp>-Wl,-Ttext,address</samp>&rsquo;</dt>
+<dd><p>Set the start of the .text section to <var>address</var>.
+</p>
+</dd>
+<dt> &lsquo;<samp>-Wl,--oformat,fmt</samp>&rsquo;</dt>
+<dd><p>Use <var>fmt</var> as output format. The supported output formats are:
+</p><dl compact="compact">
+<dt> <code>elf32-i386</code></dt>
+<dd><p>ELF output format (default)
+</p></dd>
+<dt> <code>binary</code></dt>
+<dd><p>Binary image (only for executable output)
+</p></dd>
+<dt> <code>coff</code></dt>
+<dd><p>COFF output format (only for executable output for TMS320C67xx target)
+</p></dd>
+</dl>
+
+</dd>
+</dl>
+
+<p>Debugger options:
+</p>
+<dl compact="compact">
+<dt> &lsquo;<samp>-g</samp>&rsquo;</dt>
+<dd><p>Generate run time debug information so that you get clear run time
+error messages: <code> test.c:68: in function 'test5()': dereferencing
+invalid pointer</code> instead of the laconic <code>Segmentation
+fault</code>.
+</p>
+</dd>
+<dt> &lsquo;<samp>-b</samp>&rsquo;</dt>
+<dd><p>Generate additional support code to check
+memory allocations and array/pointer bounds. &lsquo;<samp>-g</samp>&rsquo; is implied. Note
+that the generated code is slower and bigger in this case.
+</p>
+</dd>
+<dt> &lsquo;<samp>-bt N</samp>&rsquo;</dt>
+<dd><p>Display N callers in stack traces. This is useful with &lsquo;<samp>-g</samp>&rsquo; or
+&lsquo;<samp>-b</samp>&rsquo;.
+</p>
+</dd>
+</dl>
+
+<p>Note: GCC options &lsquo;<samp>-Ox</samp>&rsquo;, &lsquo;<samp>-fx</samp>&rsquo; and &lsquo;<samp>-mx</samp>&rsquo; are
+ignored.
+</p>
+
+<hr size="6">
+<a name="Clang"></a>
+<a name="SEC5"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC4" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC6" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC2" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 3. C language support </h1>
+
+<hr size="6">
+<a name="SEC6"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC5" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC7" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 3.1 ANSI C </h2>
+
+<p>TCC implements all the ANSI C standard, including structure bit fields
+and floating point numbers (<code>long double</code>, <code>double</code>, and
+<code>float</code> fully supported).
+</p>
+<hr size="6">
+<a name="SEC7"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC6" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC8" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 3.2 ISOC99 extensions </h2>
+
+<p>TCC implements many features of the new C standard: ISO C99. Currently
+missing items are: complex and imaginary numbers and variable length
+arrays.
+</p>
+<p>Currently implemented ISOC99 features:
+</p>
+<ul class="toc">
+<li> 64 bit <code>long long</code> types are fully supported.
+
+</li><li> The boolean type <code>_Bool</code> is supported.
+
+</li><li> <code>__func__</code> is a string variable containing the current
+function name.
+
+</li><li> Variadic macros: <code>__VA_ARGS__</code> can be used for
+   function-like macros:
+<table><tr><td>&nbsp;</td><td><pre class="example">    #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)
+</pre></td></tr></table>
+
+<p><code>dprintf</code> can then be used with a variable number of parameters.
+</p>
+</li><li> Declarations can appear anywhere in a block (as in C++).
+
+</li><li> Array and struct/union elements can be initialized in any order by
+  using designators:
+<table><tr><td>&nbsp;</td><td><pre class="example">    struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 };
+
+    int tab[10] = { 1, 2, [5] = 5, [9] = 9};
+</pre></td></tr></table>
+    
+</li><li> Compound initializers are supported:
+<table><tr><td>&nbsp;</td><td><pre class="example">    int *p = (int []){ 1, 2, 3 };
+</pre></td></tr></table>
+<p>to initialize a pointer pointing to an initialized array. The same
+works for structures and strings.
+</p>
+</li><li> Hexadecimal floating point constants are supported:
+<table><tr><td>&nbsp;</td><td><pre class="example">          double d = 0x1234p10;
+</pre></td></tr></table>
+
+<p>is the same as writing 
+</p><table><tr><td>&nbsp;</td><td><pre class="example">          double d = 4771840.0;
+</pre></td></tr></table>
+
+</li><li> <code>inline</code> keyword is ignored.
+
+</li><li> <code>restrict</code> keyword is ignored.
+</li></ul>
+
+<hr size="6">
+<a name="SEC8"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC7" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC9" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 3.3 GNU C extensions </h2>
+
+<p>TCC implements some GNU C extensions:
+</p>
+<ul class="toc">
+<li> array designators can be used without '=': 
+<table><tr><td>&nbsp;</td><td><pre class="example">    int a[10] = { [0] 1, [5] 2, 3, 4 };
+</pre></td></tr></table>
+
+</li><li> Structure field designators can be a label: 
+<table><tr><td>&nbsp;</td><td><pre class="example">    struct { int x, y; } st = { x: 1, y: 1};
+</pre></td></tr></table>
+<p>instead of
+</p><table><tr><td>&nbsp;</td><td><pre class="example">    struct { int x, y; } st = { .x = 1, .y = 1};
+</pre></td></tr></table>
+
+</li><li> <code>\e</code> is ASCII character 27.
+
+</li><li> case ranges : ranges can be used in <code>case</code>s:
+<table><tr><td>&nbsp;</td><td><pre class="example">    switch(a) {
+    case 1 &hellip; 9:
+          printf(&quot;range 1 to 9\n&quot;);
+          break;
+    default:
+          printf(&quot;unexpected\n&quot;);
+          break;
+    }
+</pre></td></tr></table>
+
+<a name="IDX1"></a>
+<a name="IDX2"></a>
+<a name="IDX3"></a>
+<a name="IDX4"></a>
+<a name="IDX5"></a>
+<a name="IDX6"></a>
+<a name="IDX7"></a>
+<a name="IDX8"></a>
+
+</li><li> The keyword <code>__attribute__</code> is handled to specify variable or
+function attributes. The following attributes are supported:
+  
+<ul class="toc">
+<li> <code>aligned(n)</code>: align a variable or a structure field to n bytes
+(must be a power of two).
+
+  </li><li> <code>packed</code>: force alignment of a variable or a structure field to
+  1.
+
+  </li><li> <code>section(name)</code>: generate function or data in assembly section
+name (name is a string containing the section name) instead of the default
+section.
+
+  </li><li> <code>unused</code>: specify that the variable or the function is unused.
+
+  </li><li> <code>cdecl</code>: use standard C calling convention (default).
+
+  </li><li> <code>stdcall</code>: use Pascal-like calling convention.
+
+  </li><li> <code>regparm(n)</code>: use fast i386 calling convention. <var>n</var> must be
+between 1 and 3. The first <var>n</var> function parameters are respectively put in
+registers <code>%eax</code>, <code>%edx</code> and <code>%ecx</code>.
+
+  </li><li> <code>dllexport</code>: export function from dll/executable (win32 only)
+
+</li></ul>
+
+<p>Here are some examples:
+</p><table><tr><td>&nbsp;</td><td><pre class="example">    int a __attribute__ ((aligned(8), section(&quot;.mysection&quot;)));
+</pre></td></tr></table>
+
+<p>align variable <code>a</code> to 8 bytes and put it in section <code>.mysection</code>.
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">    int my_add(int a, int b) __attribute__ ((section(&quot;.mycodesection&quot;))) 
+    {
+        return a + b;
+    }
+</pre></td></tr></table>
+
+<p>generate function <code>my_add</code> in section <code>.mycodesection</code>.
+</p>
+</li><li> GNU style variadic macros:
+<table><tr><td>&nbsp;</td><td><pre class="example">    #define dprintf(fmt, args&hellip;) printf(fmt, ## args)
+
+    dprintf(&quot;no arg\n&quot;);
+    dprintf(&quot;one arg %d\n&quot;, 1);
+</pre></td></tr></table>
+
+</li><li> <code>__FUNCTION__</code> is interpreted as C99 <code>__func__</code> 
+(so it has not exactly the same semantics as string literal GNUC
+where it is a string literal).
+
+</li><li> The <code>__alignof__</code> keyword can be used as <code>sizeof</code> 
+to get the alignment of a type or an expression.
+
+</li><li> The <code>typeof(x)</code> returns the type of <code>x</code>. 
+<code>x</code> is an expression or a type.
+
+</li><li> Computed gotos: <code>&amp;&amp;label</code> returns a pointer of type 
+<code>void *</code> on the goto label <code>label</code>. <code>goto *expr</code> can be
+used to jump on the pointer resulting from <code>expr</code>.
+
+</li><li> Inline assembly with asm instruction:
+<a name="IDX9"></a>
+<a name="IDX10"></a>
+<a name="IDX11"></a>
+<table><tr><td>&nbsp;</td><td><pre class="example">static inline void * my_memcpy(void * to, const void * from, size_t n)
+{
+int d0, d1, d2;
+__asm__ __volatile__(
+        &quot;rep ; movsl\n\t&quot;
+        &quot;testb $2,%b4\n\t&quot;
+        &quot;je 1f\n\t&quot;
+        &quot;movsw\n&quot;
+        &quot;1:\ttestb $1,%b4\n\t&quot;
+        &quot;je 2f\n\t&quot;
+        &quot;movsb\n&quot;
+        &quot;2:&quot;
+        : &quot;=&amp;c&quot; (d0), &quot;=&amp;D&quot; (d1), &quot;=&amp;S&quot; (d2)
+        :&quot;0&quot; (n/4), &quot;q&quot; (n),&quot;1&quot; ((long) to),&quot;2&quot; ((long) from)
+        : &quot;memory&quot;);
+return (to);
+}
+</pre></td></tr></table>
+
+<a name="IDX12"></a>
+<p>TCC includes its own x86 inline assembler with a <code>gas</code>-like (GNU
+assembler) syntax. No intermediate files are generated. GCC 3.x named
+operands are supported.
+</p>
+</li><li> <code>__builtin_types_compatible_p()</code> and <code>__builtin_constant_p()</code> 
+are supported.
+
+</li><li> <code>#pragma pack</code> is supported for win32 compatibility.
+
+</li></ul>
+
+<hr size="6">
+<a name="SEC9"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC8" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 3.4 TinyCC extensions </h2>
+
+<ul class="toc">
+<li> <code>__TINYC__</code> is a predefined macro to <code>1</code> to
+indicate that you use TCC.
+
+</li><li> <code>#!</code> at the start of a line is ignored to allow scripting.
+
+</li><li> Binary digits can be entered (<code>0b101</code> instead of
+<code>5</code>).
+
+</li><li> <code>__BOUNDS_CHECKING_ON</code> is defined if bound checking is activated.
+
+</li></ul>
+
+<hr size="6">
+<a name="asm"></a>
+<a name="SEC10"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC9" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC11" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC5" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 4. TinyCC Assembler </h1>
+
+<p>Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
+assembler supports a gas-like syntax (GNU assembler). You can
+desactivate assembler support if you want a smaller TinyCC executable
+(the C compiler does not rely on the assembler).
+</p>
+<p>TinyCC Assembler is used to handle files with &lsquo;<tt>.S</tt>&rsquo; (C
+preprocessed assembler) and &lsquo;<tt>.s</tt>&rsquo; extensions. It is also used to
+handle the GNU inline assembler with the <code>asm</code> keyword.
+</p>
+<hr size="6">
+<a name="SEC11"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC10" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC12" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 4.1 Syntax </h2>
+
+<p>TinyCC Assembler supports most of the gas syntax. The tokens are the
+same as C.
+</p>
+<ul class="toc">
+<li> C and C++ comments are supported.
+
+</li><li> Identifiers are the same as C, so you cannot use '.' or '$'.
+
+</li><li> Only 32 bit integer numbers are supported.
+
+</li></ul>
+
+<hr size="6">
+<a name="SEC12"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC11" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC13" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 4.2 Expressions </h2>
+
+<ul class="toc">
+<li> Integers in decimal, octal and hexa are supported.
+
+</li><li> Unary operators: +, -, ~.
+
+</li><li> Binary operators in decreasing priority order:
+
+<ol>
+<li> *, /, %
+</li><li> &amp;, |, ^
+</li><li> +, -
+</li></ol>
+
+</li><li> A value is either an absolute number or a label plus an offset. 
+All operators accept absolute values except '+' and '-'. '+' or '-' can be
+used to add an offset to a label. '-' supports two labels only if they
+are the same or if they are both defined and in the same section.
+
+</li></ul>
+
+<hr size="6">
+<a name="SEC13"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC12" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC14" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 4.3 Labels </h2>
+
+<ul class="toc">
+<li> All labels are considered as local, except undefined ones.
+
+</li><li> Numeric labels can be used as local <code>gas</code>-like labels. 
+They can be defined several times in the same source. Use 'b'
+(backward) or 'f' (forward) as suffix to reference them:
+
+<table><tr><td>&nbsp;</td><td><pre class="example"> 1:
+      jmp 1b /* jump to '1' label before */
+      jmp 1f /* jump to '1' label after */
+ 1:
+</pre></td></tr></table>
+
+</li></ul>
+
+<hr size="6">
+<a name="SEC14"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC13" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC15" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 4.4 Directives </h2>
+
+<p>All directives are preceded by a '.'. The following directives are
+supported:
+</p>
+<ul class="toc">
+<li> .align n[,value]
+</li><li> .skip n[,value]
+</li><li> .space n[,value]
+</li><li> .byte value1[,...]
+</li><li> .word value1[,...]
+</li><li> .short value1[,...]
+</li><li> .int value1[,...]
+</li><li> .long value1[,...]
+</li><li> .quad immediate_value1[,...]
+</li><li> .globl symbol
+</li><li> .global symbol
+</li><li> .section section
+</li><li> .text
+</li><li> .data
+</li><li> .bss
+</li><li> .fill repeat[,size[,value]]
+</li><li> .org n
+</li><li> .previous
+</li><li> .string string[,...]
+</li><li> .asciz string[,...]
+</li><li> .ascii string[,...]
+</li></ul>
+
+<hr size="6">
+<a name="SEC15"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC14" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 4.5 X86 Assembler </h2>
+
+<p>All X86 opcodes are supported. Only ATT syntax is supported (source
+then destination operand order). If no size suffix is given, TinyCC
+tries to guess it from the operand sizes.
+</p>
+<p>Currently, MMX opcodes are supported but not SSE ones.
+</p>
+<hr size="6">
+<a name="linker"></a>
+<a name="SEC16"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC15" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC17" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC10" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 5. TinyCC Linker </h1>
+
+<hr size="6">
+<a name="SEC17"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC16" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC18" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 5.1 ELF file generation </h2>
+
+<p>TCC can directly output relocatable ELF files (object files),
+executable ELF files and dynamic ELF libraries without relying on an
+external linker.
+</p>
+<p>Dynamic ELF libraries can be output but the C compiler does not generate
+position independent code (PIC). It means that the dynamic library
+code generated by TCC cannot be factorized among processes yet.
+</p>
+<p>TCC linker eliminates unreferenced object code in libraries. A single pass is
+done on the object and library list, so the order in which object files and
+libraries are specified is important (same constraint as GNU ld). No grouping
+options (&lsquo;<samp>--start-group</samp>&rsquo; and &lsquo;<samp>--end-group</samp>&rsquo;) are supported.
+</p>
+<hr size="6">
+<a name="SEC18"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC17" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC19" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 5.2 ELF file loader </h2>
+
+<p>TCC can load ELF object files, archives (.a files) and dynamic
+libraries (.so).
+</p>
+<hr size="6">
+<a name="SEC19"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC18" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC20" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 5.3 PE-i386 file generation </h2>
+
+<p>TCC for Windows supports the native Win32 executable file format (PE-i386).  It
+generates EXE files (console and gui) and DLL files.
+</p>
+<p>For usage on Windows, see also tcc-win32.txt.
+</p>
+<hr size="6">
+<a name="SEC20"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC19" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 5.4 GNU Linker Scripts </h2>
+
+<p>Because on many Linux systems some dynamic libraries (such as
+&lsquo;<tt>/usr/lib/libc.so</tt>&rsquo;) are in fact GNU ld link scripts (horrible!),
+the TCC linker also supports a subset of GNU ld scripts.
+</p>
+<p>The <code>GROUP</code> and <code>FILE</code> commands are supported. <code>OUTPUT_FORMAT</code>
+and <code>TARGET</code> are ignored.
+</p>
+<p>Example from &lsquo;<tt>/usr/lib/libc.so</tt>&rsquo;:
+</p><table><tr><td>&nbsp;</td><td><pre class="example">/* GNU ld script
+   Use the shared library, but some functions are only in
+   the static library, so try that secondarily.  */
+GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
+</pre></td></tr></table>
+
+<hr size="6">
+<a name="Bounds"></a>
+<a name="SEC21"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC20" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC22" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC16" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC22" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 6. TinyCC Memory and Bound checks </h1>
+
+<p>This feature is activated with the &lsquo;<samp>-b</samp>&rsquo; (see section <a href="#SEC2">Command line invocation</a>).
+</p>
+<p>Note that pointer size is <em>unchanged</em> and that code generated
+with bound checks is <em>fully compatible</em> with unchecked
+code. When a pointer comes from unchecked code, it is assumed to be
+valid. Even very obscure C code with casts should work correctly.
+</p>
+<p>For more information about the ideas behind this method, see
+<a href="http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html">http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html</a>.
+</p>
+<p>Here are some examples of caught errors:
+</p>
+<dl compact="compact">
+<dt> Invalid range with standard string function:</dt>
+<dd><table><tr><td>&nbsp;</td><td><pre class="example">{
+    char tab[10];
+    memset(tab, 0, 11);
+}
+</pre></td></tr></table>
+
+</dd>
+<dt> Out of bounds-error in global or local arrays:</dt>
+<dd><table><tr><td>&nbsp;</td><td><pre class="example">{
+    int tab[10];
+    for(i=0;i&lt;11;i++) {
+        sum += tab[i];
+    }
+}
+</pre></td></tr></table>
+
+</dd>
+<dt> Out of bounds-error in malloc'ed data:</dt>
+<dd><table><tr><td>&nbsp;</td><td><pre class="example">{
+    int *tab;
+    tab = malloc(20 * sizeof(int));
+    for(i=0;i&lt;21;i++) {
+        sum += tab4[i];
+    }
+    free(tab);
+}
+</pre></td></tr></table>
+
+</dd>
+<dt> Access of freed memory:</dt>
+<dd><table><tr><td>&nbsp;</td><td><pre class="example">{
+    int *tab;
+    tab = malloc(20 * sizeof(int));
+    free(tab);
+    for(i=0;i&lt;20;i++) {
+        sum += tab4[i];
+    }
+}
+</pre></td></tr></table>
+
+</dd>
+<dt> Double free:</dt>
+<dd><table><tr><td>&nbsp;</td><td><pre class="example">{
+    int *tab;
+    tab = malloc(20 * sizeof(int));
+    free(tab);
+    free(tab);
+}
+</pre></td></tr></table>
+
+</dd>
+</dl>
+
+<hr size="6">
+<a name="Libtcc"></a>
+<a name="SEC22"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC21" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC21" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 7. The <code>libtcc</code> library </h1>
+
+<p>The <code>libtcc</code> library enables you to use TCC as a backend for
+dynamic code generation. 
+</p>
+<p>Read the &lsquo;<tt>libtcc.h</tt>&rsquo; to have an overview of the API. Read
+&lsquo;<tt>libtcc_test.c</tt>&rsquo; to have a very simple example.
+</p>
+<p>The idea consists in giving a C string containing the program you want
+to compile directly to <code>libtcc</code>. Then you can access to any global
+symbol (function or variable) defined.
+</p>
+<hr size="6">
+<a name="devel"></a>
+<a name="SEC23"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC22" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC24" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC22" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="chapter"> 8. Developer's guide </h1>
+
+<p>This chapter gives some hints to understand how TCC works. You can skip
+it if you do not intend to modify the TCC code.
+</p>
+<hr size="6">
+<a name="SEC24"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC23" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC25" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.1 File reading </h2>
+
+<p>The <code>BufferedFile</code> structure contains the context needed to read a
+file, including the current line number. <code>tcc_open()</code> opens a new
+file and <code>tcc_close()</code> closes it. <code>inp()</code> returns the next
+character.
+</p>
+<hr size="6">
+<a name="SEC25"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC24" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC26" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.2 Lexer </h2>
+
+<p><code>next()</code> reads the next token in the current
+file. <code>next_nomacro()</code> reads the next token without macro
+expansion.
+</p>
+<p><code>tok</code> contains the current token (see <code>TOK_xxx</code>)
+constants. Identifiers and keywords are also keywords. <code>tokc</code>
+contains additional infos about the token (for example a constant value
+if number or string token).
+</p>
+<hr size="6">
+<a name="SEC26"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC25" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC27" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.3 Parser </h2>
+
+<p>The parser is hardcoded (yacc is not necessary). It does only one pass,
+except:
+</p>
+<ul class="toc">
+<li> For initialized arrays with unknown size, a first pass 
+is done to count the number of elements.
+
+</li><li> For architectures where arguments are evaluated in 
+reverse order, a first pass is done to reverse the argument order.
+
+</li></ul>
+
+<hr size="6">
+<a name="SEC27"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC26" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC28" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.4 Types </h2>
+
+<p>The types are stored in a single 'int' variable. It was chosen in the
+first stages of development when tcc was much simpler. Now, it may not
+be the best solution.
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">#define VT_INT        0  /* integer type */
+#define VT_BYTE       1  /* signed byte type */
+#define VT_SHORT      2  /* short type */
+#define VT_VOID       3  /* void type */
+#define VT_PTR        4  /* pointer */
+#define VT_ENUM       5  /* enum definition */
+#define VT_FUNC       6  /* function type */
+#define VT_STRUCT     7  /* struct/union definition */
+#define VT_FLOAT      8  /* IEEE float */
+#define VT_DOUBLE     9  /* IEEE double */
+#define VT_LDOUBLE   10  /* IEEE long double */
+#define VT_BOOL      11  /* ISOC99 boolean type */
+#define VT_LLONG     12  /* 64 bit integer */
+#define VT_LONG      13  /* long integer (NEVER USED as type, only
+                            during parsing) */
+#define VT_BTYPE      0x000f /* mask for basic type */
+#define VT_UNSIGNED   0x0010  /* unsigned type */
+#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
+#define VT_BITFIELD   0x0040  /* bitfield modifier */
+
+#define VT_STRUCT_SHIFT 16   /* structure/enum name shift (16 bits left) */
+</pre></td></tr></table>
+
+<p>When a reference to another type is needed (for pointers, functions and
+structures), the <code>32 - VT_STRUCT_SHIFT</code> high order bits are used to
+store an identifier reference.
+</p>
+<p>The <code>VT_UNSIGNED</code> flag can be set for chars, shorts, ints and long
+longs.
+</p>
+<p>Arrays are considered as pointers <code>VT_PTR</code> with the flag
+<code>VT_ARRAY</code> set.
+</p>
+<p>The <code>VT_BITFIELD</code> flag can be set for chars, shorts, ints and long
+longs. If it is set, then the bitfield position is stored from bits
+VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored
+from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.
+</p>
+<p><code>VT_LONG</code> is never used except during parsing.
+</p>
+<p>During parsing, the storage of an object is also stored in the type
+integer:
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">#define VT_EXTERN  0x00000080  /* extern definition */
+#define VT_STATIC  0x00000100  /* static variable */
+#define VT_TYPEDEF 0x00000200  /* typedef definition */
+</pre></td></tr></table>
+
+<hr size="6">
+<a name="SEC28"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC27" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC29" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.5 Symbols </h2>
+
+<p>All symbols are stored in hashed symbol stacks. Each symbol stack
+contains <code>Sym</code> structures.
+</p>
+<p><code>Sym.v</code> contains the symbol name (remember
+an idenfier is also a token, so a string is never necessary to store
+it). <code>Sym.t</code> gives the type of the symbol. <code>Sym.r</code> is usually
+the register in which the corresponding variable is stored. <code>Sym.c</code> is
+usually a constant associated to the symbol.
+</p>
+<p>Four main symbol stacks are defined:
+</p>
+<dl compact="compact">
+<dt> <code>define_stack</code></dt>
+<dd><p>for the macros (<code>#define</code>s).
+</p>
+</dd>
+<dt> <code>global_stack</code></dt>
+<dd><p>for the global variables, functions and types.
+</p>
+</dd>
+<dt> <code>local_stack</code></dt>
+<dd><p>for the local variables, functions and types.
+</p>
+</dd>
+<dt> <code>global_label_stack</code></dt>
+<dd><p>for the local labels (for <code>goto</code>).
+</p>
+</dd>
+<dt> <code>label_stack</code></dt>
+<dd><p>for GCC block local labels (see the <code>__label__</code> keyword).
+</p>
+</dd>
+</dl>
+
+<p><code>sym_push()</code> is used to add a new symbol in the local symbol
+stack. If no local symbol stack is active, it is added in the global
+symbol stack.
+</p>
+<p><code>sym_pop(st,b)</code> pops symbols from the symbol stack <var>st</var> until
+the symbol <var>b</var> is on the top of stack. If <var>b</var> is NULL, the stack
+is emptied.
+</p>
+<p><code>sym_find(v)</code> return the symbol associated to the identifier
+<var>v</var>. The local stack is searched first from top to bottom, then the
+global stack.
+</p>
+<hr size="6">
+<a name="SEC29"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC28" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC30" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.6 Sections </h2>
+
+<p>The generated code and datas are written in sections. The structure
+<code>Section</code> contains all the necessary information for a given
+section. <code>new_section()</code> creates a new section. ELF file semantics
+is assumed for each section.
+</p>
+<p>The following sections are predefined:
+</p>
+<dl compact="compact">
+<dt> <code>text_section</code></dt>
+<dd><p>is the section containing the generated code. <var>ind</var> contains the
+current position in the code section.
+</p>
+</dd>
+<dt> <code>data_section</code></dt>
+<dd><p>contains initialized data
+</p>
+</dd>
+<dt> <code>bss_section</code></dt>
+<dd><p>contains uninitialized data
+</p>
+</dd>
+<dt> <code>bounds_section</code></dt>
+<dt> <code>lbounds_section</code></dt>
+<dd><p>are used when bound checking is activated
+</p>
+</dd>
+<dt> <code>stab_section</code></dt>
+<dt> <code>stabstr_section</code></dt>
+<dd><p>are used when debugging is activated to store debug information
+</p>
+</dd>
+<dt> <code>symtab_section</code></dt>
+<dt> <code>strtab_section</code></dt>
+<dd><p>contain the exported symbols (currently only used for debugging).
+</p>
+</dd>
+</dl>
+
+<hr size="6">
+<a name="SEC30"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC29" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC31" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.7 Code generation </h2>
+
+<hr size="6">
+<a name="SEC31"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC30" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC32" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC30" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h3 class="subsection"> 8.7.1 Introduction </h3>
+
+<p>The TCC code generator directly generates linked binary code in one
+pass. It is rather unusual these days (see gcc for example which
+generates text assembly), but it can be very fast and surprisingly
+little complicated.
+</p>
+<p>The TCC code generator is register based. Optimization is only done at
+the expression level. No intermediate representation of expression is
+kept except the current values stored in the <em>value stack</em>.
+</p>
+<p>On x86, three temporary registers are used. When more registers are
+needed, one register is spilled into a new temporary variable on the stack.
+</p>
+<hr size="6">
+<a name="SEC32"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC31" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC33" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC30" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h3 class="subsection"> 8.7.2 The value stack </h3>
+
+<p>When an expression is parsed, its value is pushed on the value stack
+(<var>vstack</var>). The top of the value stack is <var>vtop</var>. Each value
+stack entry is the structure <code>SValue</code>.
+</p>
+<p><code>SValue.t</code> is the type. <code>SValue.r</code> indicates how the value is
+currently stored in the generated code. It is usually a CPU register
+index (<code>REG_xxx</code> constants), but additional values and flags are
+defined:
+</p>
+<table><tr><td>&nbsp;</td><td><pre class="example">#define VT_CONST     0x00f0
+#define VT_LLOCAL    0x00f1
+#define VT_LOCAL     0x00f2
+#define VT_CMP       0x00f3
+#define VT_JMP       0x00f4
+#define VT_JMPI      0x00f5
+#define VT_LVAL      0x0100
+#define VT_SYM       0x0200
+#define VT_MUSTCAST  0x0400
+#define VT_MUSTBOUND 0x0800
+#define VT_BOUNDED   0x8000
+#define VT_LVAL_BYTE     0x1000
+#define VT_LVAL_SHORT    0x2000
+#define VT_LVAL_UNSIGNED 0x4000
+#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
+</pre></td></tr></table>
+
+<dl compact="compact">
+<dt> <code>VT_CONST</code></dt>
+<dd><p>indicates that the value is a constant. It is stored in the union
+<code>SValue.c</code>, depending on its type.
+</p>
+</dd>
+<dt> <code>VT_LOCAL</code></dt>
+<dd><p>indicates a local variable pointer at offset <code>SValue.c.i</code> in the
+stack.
+</p>
+</dd>
+<dt> <code>VT_CMP</code></dt>
+<dd><p>indicates that the value is actually stored in the CPU flags (i.e. the
+value is the consequence of a test). The value is either 0 or 1. The
+actual CPU flags used is indicated in <code>SValue.c.i</code>. 
+</p>
+<p>If any code is generated which destroys the CPU flags, this value MUST be
+put in a normal register.
+</p>
+</dd>
+<dt> <code>VT_JMP</code></dt>
+<dt> <code>VT_JMPI</code></dt>
+<dd><p>indicates that the value is the consequence of a conditional jump. For VT_JMP,
+it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted.
+</p>
+<p>These values are used to compile the <code>||</code> and <code>&amp;&amp;</code> logical
+operators.
+</p>
+<p>If any code is generated, this value MUST be put in a normal
+register. Otherwise, the generated code won't be executed if the jump is
+taken.
+</p>
+</dd>
+<dt> <code>VT_LVAL</code></dt>
+<dd><p>is a flag indicating that the value is actually an lvalue (left value of
+an assignment). It means that the value stored is actually a pointer to
+the wanted value. 
+</p>
+<p>Understanding the use <code>VT_LVAL</code> is very important if you want to
+understand how TCC works.
+</p>
+</dd>
+<dt> <code>VT_LVAL_BYTE</code></dt>
+<dt> <code>VT_LVAL_SHORT</code></dt>
+<dt> <code>VT_LVAL_UNSIGNED</code></dt>
+<dd><p>if the lvalue has an integer type, then these flags give its real
+type. The type alone is not enough in case of cast optimisations.
+</p>
+</dd>
+<dt> <code>VT_LLOCAL</code></dt>
+<dd><p>is a saved lvalue on the stack. <code>VT_LLOCAL</code> should be eliminated
+ASAP because its semantics are rather complicated.
+</p>
+</dd>
+<dt> <code>VT_MUSTCAST</code></dt>
+<dd><p>indicates that a cast to the value type must be performed if the value
+is used (lazy casting).
+</p>
+</dd>
+<dt> <code>VT_SYM</code></dt>
+<dd><p>indicates that the symbol <code>SValue.sym</code> must be added to the constant.
+</p>
+</dd>
+<dt> <code>VT_MUSTBOUND</code></dt>
+<dt> <code>VT_BOUNDED</code></dt>
+<dd><p>are only used for optional bound checking.
+</p>
+</dd>
+</dl>
+
+<hr size="6">
+<a name="SEC33"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC32" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC34" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC30" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h3 class="subsection"> 8.7.3 Manipulating the value stack </h3>
+
+<p><code>vsetc()</code> and <code>vset()</code> pushes a new value on the value
+stack. If the previous <var>vtop</var> was stored in a very unsafe place(for
+example in the CPU flags), then some code is generated to put the
+previous <var>vtop</var> in a safe storage.
+</p>
+<p><code>vpop()</code> pops <var>vtop</var>. In some cases, it also generates cleanup
+code (for example if stacked floating point registers are used as on
+x86).
+</p>
+<p>The <code>gv(rc)</code> function generates code to evaluate <var>vtop</var> (the
+top value of the stack) into registers. <var>rc</var> selects in which
+register class the value should be put. <code>gv()</code> is the <em>most
+important function</em> of the code generator.
+</p>
+<p><code>gv2()</code> is the same as <code>gv()</code> but for the top two stack
+entries.
+</p>
+<hr size="6">
+<a name="SEC34"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC33" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC35" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC30" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h3 class="subsection"> 8.7.4 CPU dependent code generation </h3>
+<p>See the &lsquo;<tt>i386-gen.c</tt>&rsquo; file to have an example.
+</p>
+<dl compact="compact">
+<dt> <code>load()</code></dt>
+<dd><p>must generate the code needed to load a stack value into a register.
+</p>
+</dd>
+<dt> <code>store()</code></dt>
+<dd><p>must generate the code needed to store a register into a stack value
+lvalue.
+</p>
+</dd>
+<dt> <code>gfunc_start()</code></dt>
+<dt> <code>gfunc_param()</code></dt>
+<dt> <code>gfunc_call()</code></dt>
+<dd><p>should generate a function call
+</p>
+</dd>
+<dt> <code>gfunc_prolog()</code></dt>
+<dt> <code>gfunc_epilog()</code></dt>
+<dd><p>should generate a function prolog/epilog.
+</p>
+</dd>
+<dt> <code>gen_opi(op)</code></dt>
+<dd><p>must generate the binary integer operation <var>op</var> on the two top
+entries of the stack which are guaranted to contain integer types.
+</p>
+<p>The result value should be put on the stack.
+</p>
+</dd>
+<dt> <code>gen_opf(op)</code></dt>
+<dd><p>same as <code>gen_opi()</code> for floating point operations. The two top
+entries of the stack are guaranted to contain floating point values of
+same types.
+</p>
+</dd>
+<dt> <code>gen_cvt_itof()</code></dt>
+<dd><p>integer to floating point conversion.
+</p>
+</dd>
+<dt> <code>gen_cvt_ftoi()</code></dt>
+<dd><p>floating point to integer conversion.
+</p>
+</dd>
+<dt> <code>gen_cvt_ftof()</code></dt>
+<dd><p>floating point to floating point of different size conversion.
+</p>
+</dd>
+<dt> <code>gen_bounded_ptr_add()</code></dt>
+<dt> <code>gen_bounded_ptr_deref()</code></dt>
+<dd><p>are only used for bounds checking.
+</p>
+</dd>
+</dl>
+
+<hr size="6">
+<a name="SEC35"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC34" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next section in reading order"> &gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Next chapter"> &gt;&gt; </a>]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h2 class="section"> 8.8 Optimizations done </h2>
+<p>Constant propagation is done for all operations. Multiplications and
+divisions are optimized to shifts when appropriate. Comparison
+operators are optimized by maintaining a special cache for the
+processor flags. &amp;&amp;, || and ! are optimized by maintaining a special
+'jump target' value. No other jump optimization is currently performed
+because it would require to store the code in a more abstract fashion.
+</p>
+<hr size="6">
+<a name="SEC36"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC35" title="Previous section in reading order"> &lt; </a>]</td>
+<td valign="middle" align="left">[ &gt; ]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC23" title="Beginning of this chapter or previous chapter"> &lt;&lt; </a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Up section"> Up </a>]</td>
+<td valign="middle" align="left">[ &gt;&gt; ]</td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left"> &nbsp; </td>
+<td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1 class="unnumbered"> Concept Index </h1>
+<table><tr><th valign="top">Jump to: &nbsp; </th><td><a href="#SEC36_0" class="summary-letter"><b>_</b></a>
+ &nbsp; 
+<br>
+<a href="#SEC36_1" class="summary-letter"><b>A</b></a>
+ &nbsp; 
+<a href="#SEC36_2" class="summary-letter"><b>B</b></a>
+ &nbsp; 
+<a href="#SEC36_3" class="summary-letter"><b>C</b></a>
+ &nbsp; 
+<a href="#SEC36_4" class="summary-letter"><b>D</b></a>
+ &nbsp; 
+<a href="#SEC36_5" class="summary-letter"><b>E</b></a>
+ &nbsp; 
+<a href="#SEC36_6" class="summary-letter"><b>F</b></a>
+ &nbsp; 
+<a href="#SEC36_7" class="summary-letter"><b>G</b></a>
+ &nbsp; 
+<a href="#SEC36_8" class="summary-letter"><b>I</b></a>
+ &nbsp; 
+<a href="#SEC36_9" class="summary-letter"><b>J</b></a>
+ &nbsp; 
+<a href="#SEC36_10" class="summary-letter"><b>L</b></a>
+ &nbsp; 
+<a href="#SEC36_11" class="summary-letter"><b>M</b></a>
+ &nbsp; 
+<a href="#SEC36_12" class="summary-letter"><b>O</b></a>
+ &nbsp; 
+<a href="#SEC36_13" class="summary-letter"><b>P</b></a>
+ &nbsp; 
+<a href="#SEC36_14" class="summary-letter"><b>Q</b></a>
+ &nbsp; 
+<a href="#SEC36_15" class="summary-letter"><b>R</b></a>
+ &nbsp; 
+<a href="#SEC36_16" class="summary-letter"><b>S</b></a>
+ &nbsp; 
+<a href="#SEC36_17" class="summary-letter"><b>T</b></a>
+ &nbsp; 
+<a href="#SEC36_18" class="summary-letter"><b>U</b></a>
+ &nbsp; 
+<a href="#SEC36_19" class="summary-letter"><b>V</b></a>
+ &nbsp; 
+<a href="#SEC36_20" class="summary-letter"><b>W</b></a>
+ &nbsp; 
+</td></tr></table>
+<table border="0" class="index-cp">
+<tr><td></td><th align="left">Index Entry</th><th align="left"> Section</th></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_0">_</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX11">__asm__</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_1">A</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">align directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX1">aligned attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">ascii directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">asciz directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC15">assembler</a></td><td valign="top"><a href="#SEC15">4.5 X86 Assembler</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">assembler directives</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX10">assembly, inline</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_2">B</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC21">bound checks</a></td><td valign="top"><a href="#SEC21">6. TinyCC Memory and Bound checks</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">bss directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">byte directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_3">C</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">caching processor flags</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX5">cdecl attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC30">code generation</a></td><td valign="top"><a href="#SEC30">8.7 Code generation</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">comparison operators</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">constant propagation</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC34">CPU dependent</a></td><td valign="top"><a href="#SEC34">8.7.4 CPU dependent code generation</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_4">D</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">data directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">directives, assembler</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX8">dllexport attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_5">E</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC17">ELF</a></td><td valign="top"><a href="#SEC17">5.1 ELF file generation</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_6">F</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC20">FILE, linker command</a></td><td valign="top"><a href="#SEC20">5.4 GNU Linker Scripts</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">fill directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">flags, caching</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_7">G</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX12">gas</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">global directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">globl directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC20">GROUP, linker command</a></td><td valign="top"><a href="#SEC20">5.4 GNU Linker Scripts</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_8">I</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX9">inline assembly</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">int directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_9">J</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">jump optimization</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_10">L</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC16">linker</a></td><td valign="top"><a href="#SEC16">5. TinyCC Linker</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC20">linker scripts</a></td><td valign="top"><a href="#SEC20">5.4 GNU Linker Scripts</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">long directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_11">M</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC21">memory checks</a></td><td valign="top"><a href="#SEC21">6. TinyCC Memory and Bound checks</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_12">O</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">optimizations</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">org directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC20">OUTPUT_FORMAT, linker command</a></td><td valign="top"><a href="#SEC20">5.4 GNU Linker Scripts</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_13">P</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX2">packed attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC19">PE-i386</a></td><td valign="top"><a href="#SEC19">5.3 PE-i386 file generation</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">previous directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_14">Q</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">quad directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_15">R</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX7">regparm attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_16">S</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC20">scripts, linker</a></td><td valign="top"><a href="#SEC20">5.4 GNU Linker Scripts</a></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX3">section attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">section directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">short directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">skip directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">space directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX6">stdcall attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC35">strength reduction</a></td><td valign="top"><a href="#SEC35">8.8 Optimizations done</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">string directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_17">T</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC20">TARGET, linker command</a></td><td valign="top"><a href="#SEC20">5.4 GNU Linker Scripts</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">text directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_18">U</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#IDX4">unused attribute</a></td><td valign="top"><a href="#SEC8">3.3 GNU C extensions</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_19">V</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC33">value stack</a></td><td valign="top"><a href="#SEC33">8.7.3 Manipulating the value stack</a></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC32">value stack, introduction</a></td><td valign="top"><a href="#SEC32">8.7.2 The value stack</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+<tr><th><a name="SEC36_20">W</a></th><td></td><td></td></tr>
+<tr><td></td><td valign="top"><a href="#SEC14">word directive</a></td><td valign="top"><a href="#SEC14">4.4 Directives</a></td></tr>
+<tr><td colspan="3"> <hr></td></tr>
+</table>
+<table><tr><th valign="top">Jump to: &nbsp; </th><td><a href="#SEC36_0" class="summary-letter"><b>_</b></a>
+ &nbsp; 
+<br>
+<a href="#SEC36_1" class="summary-letter"><b>A</b></a>
+ &nbsp; 
+<a href="#SEC36_2" class="summary-letter"><b>B</b></a>
+ &nbsp; 
+<a href="#SEC36_3" class="summary-letter"><b>C</b></a>
+ &nbsp; 
+<a href="#SEC36_4" class="summary-letter"><b>D</b></a>
+ &nbsp; 
+<a href="#SEC36_5" class="summary-letter"><b>E</b></a>
+ &nbsp; 
+<a href="#SEC36_6" class="summary-letter"><b>F</b></a>
+ &nbsp; 
+<a href="#SEC36_7" class="summary-letter"><b>G</b></a>
+ &nbsp; 
+<a href="#SEC36_8" class="summary-letter"><b>I</b></a>
+ &nbsp; 
+<a href="#SEC36_9" class="summary-letter"><b>J</b></a>
+ &nbsp; 
+<a href="#SEC36_10" class="summary-letter"><b>L</b></a>
+ &nbsp; 
+<a href="#SEC36_11" class="summary-letter"><b>M</b></a>
+ &nbsp; 
+<a href="#SEC36_12" class="summary-letter"><b>O</b></a>
+ &nbsp; 
+<a href="#SEC36_13" class="summary-letter"><b>P</b></a>
+ &nbsp; 
+<a href="#SEC36_14" class="summary-letter"><b>Q</b></a>
+ &nbsp; 
+<a href="#SEC36_15" class="summary-letter"><b>R</b></a>
+ &nbsp; 
+<a href="#SEC36_16" class="summary-letter"><b>S</b></a>
+ &nbsp; 
+<a href="#SEC36_17" class="summary-letter"><b>T</b></a>
+ &nbsp; 
+<a href="#SEC36_18" class="summary-letter"><b>U</b></a>
+ &nbsp; 
+<a href="#SEC36_19" class="summary-letter"><b>V</b></a>
+ &nbsp; 
+<a href="#SEC36_20" class="summary-letter"><b>W</b></a>
+ &nbsp; 
+</td></tr></table>
+
+<hr size="6">
+<a name="SEC_Contents"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1>Table of Contents</h1>
+<div class="contents">
+
+<ul class="toc">
+  <li><a name="TOC1" href="#SEC1">1. Introduction</a></li>
+  <li><a name="TOC2" href="#SEC2">2. Command line invocation</a>
+  <ul class="toc">
+    <li><a name="TOC3" href="#SEC3">2.1 Quick start</a></li>
+    <li><a name="TOC4" href="#SEC4">2.2 Option summary</a></li>
+  </ul></li>
+  <li><a name="TOC5" href="#SEC5">3. C language support</a>
+  <ul class="toc">
+    <li><a name="TOC6" href="#SEC6">3.1 ANSI C</a></li>
+    <li><a name="TOC7" href="#SEC7">3.2 ISOC99 extensions</a></li>
+    <li><a name="TOC8" href="#SEC8">3.3 GNU C extensions</a></li>
+    <li><a name="TOC9" href="#SEC9">3.4 TinyCC extensions</a></li>
+  </ul></li>
+  <li><a name="TOC10" href="#SEC10">4. TinyCC Assembler</a>
+  <ul class="toc">
+    <li><a name="TOC11" href="#SEC11">4.1 Syntax</a></li>
+    <li><a name="TOC12" href="#SEC12">4.2 Expressions</a></li>
+    <li><a name="TOC13" href="#SEC13">4.3 Labels</a></li>
+    <li><a name="TOC14" href="#SEC14">4.4 Directives</a></li>
+    <li><a name="TOC15" href="#SEC15">4.5 X86 Assembler</a></li>
+  </ul></li>
+  <li><a name="TOC16" href="#SEC16">5. TinyCC Linker</a>
+  <ul class="toc">
+    <li><a name="TOC17" href="#SEC17">5.1 ELF file generation</a></li>
+    <li><a name="TOC18" href="#SEC18">5.2 ELF file loader</a></li>
+    <li><a name="TOC19" href="#SEC19">5.3 PE-i386 file generation</a></li>
+    <li><a name="TOC20" href="#SEC20">5.4 GNU Linker Scripts</a></li>
+  </ul></li>
+  <li><a name="TOC21" href="#SEC21">6. TinyCC Memory and Bound checks</a></li>
+  <li><a name="TOC22" href="#SEC22">7. The <code>libtcc</code> library</a></li>
+  <li><a name="TOC23" href="#SEC23">8. Developer's guide</a>
+  <ul class="toc">
+    <li><a name="TOC24" href="#SEC24">8.1 File reading</a></li>
+    <li><a name="TOC25" href="#SEC25">8.2 Lexer</a></li>
+    <li><a name="TOC26" href="#SEC26">8.3 Parser</a></li>
+    <li><a name="TOC27" href="#SEC27">8.4 Types</a></li>
+    <li><a name="TOC28" href="#SEC28">8.5 Symbols</a></li>
+    <li><a name="TOC29" href="#SEC29">8.6 Sections</a></li>
+    <li><a name="TOC30" href="#SEC30">8.7 Code generation</a>
+    <ul class="toc">
+      <li><a name="TOC31" href="#SEC31">8.7.1 Introduction</a></li>
+      <li><a name="TOC32" href="#SEC32">8.7.2 The value stack</a></li>
+      <li><a name="TOC33" href="#SEC33">8.7.3 Manipulating the value stack</a></li>
+      <li><a name="TOC34" href="#SEC34">8.7.4 CPU dependent code generation</a></li>
+    </ul></li>
+    <li><a name="TOC35" href="#SEC35">8.8 Optimizations done</a></li>
+  </ul></li>
+  <li><a name="TOC36" href="#SEC36">Concept Index</a></li>
+</ul>
+</div>
+<hr size="1">
+<a name="SEC_About"></a>
+<table cellpadding="1" cellspacing="1" border="0">
+<tr><td valign="middle" align="left">[<a href="#SEC_Top" title="Cover (top) of document">Top</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_Contents" title="Table of contents">Contents</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC36" title="Index">Index</a>]</td>
+<td valign="middle" align="left">[<a href="#SEC_About" title="About (help)"> ? </a>]</td>
+</tr></table>
+<h1>About This Document</h1>
+<p>
+  This document was generated by <em>gr</em> on <em>May, 18 2009</em> using <a href="http://www.nongnu.org/texi2html/"><em>texi2html 1.78</em></a>.
+</p>
+<p>
+  The buttons in the navigation panels have the following meaning:
+</p>
+<table border="1">
+  <tr>
+    <th> Button </th>
+    <th> Name </th>
+    <th> Go to </th>
+    <th> From 1.2.3 go to</th>
+  </tr>
+  <tr>
+    <td align="center"> [ &lt; ] </td>
+    <td align="center">Back</td>
+    <td>Previous section in reading order</td>
+    <td>1.2.2</td>
+  </tr>
+  <tr>
+    <td align="center"> [ &gt; ] </td>
+    <td align="center">Forward</td>
+    <td>Next section in reading order</td>
+    <td>1.2.4</td>
+  </tr>
+  <tr>
+    <td align="center"> [ &lt;&lt; ] </td>
+    <td align="center">FastBack</td>
+    <td>Beginning of this chapter or previous chapter</td>
+    <td>1</td>
+  </tr>
+  <tr>
+    <td align="center"> [ Up ] </td>
+    <td align="center">Up</td>
+    <td>Up section</td>
+    <td>1.2</td>
+  </tr>
+  <tr>
+    <td align="center"> [ &gt;&gt; ] </td>
+    <td align="center">FastForward</td>
+    <td>Next chapter</td>
+    <td>2</td>
+  </tr>
+  <tr>
+    <td align="center"> [Top] </td>
+    <td align="center">Top</td>
+    <td>Cover (top) of document</td>
+    <td> &nbsp; </td>
+  </tr>
+  <tr>
+    <td align="center"> [Contents] </td>
+    <td align="center">Contents</td>
+    <td>Table of contents</td>
+    <td> &nbsp; </td>
+  </tr>
+  <tr>
+    <td align="center"> [Index] </td>
+    <td align="center">Index</td>
+    <td>Index</td>
+    <td> &nbsp; </td>
+  </tr>
+  <tr>
+    <td align="center"> [ ? ] </td>
+    <td align="center">About</td>
+    <td>About (help)</td>
+    <td> &nbsp; </td>
+  </tr>
+</table>
+
+<p>
+  where the <strong> Example </strong> assumes that the current position is at <strong> Subsubsection One-Two-Three </strong> of a document of the following structure:
+</p>
+
+<ul>
+  <li> 1. Section One
+    <ul>
+      <li>1.1 Subsection One-One
+        <ul>
+          <li>...</li>
+        </ul>
+      </li>
+      <li>1.2 Subsection One-Two
+        <ul>
+          <li>1.2.1 Subsubsection One-Two-One</li>
+          <li>1.2.2 Subsubsection One-Two-Two</li>
+          <li>1.2.3 Subsubsection One-Two-Three &nbsp; &nbsp;
+            <strong>&lt;== Current Position </strong></li>
+          <li>1.2.4 Subsubsection One-Two-Four</li>
+        </ul>
+      </li>
+      <li>1.3 Subsection One-Three
+        <ul>
+          <li>...</li>
+        </ul>
+      </li>
+      <li>1.4 Subsection One-Four</li>
+    </ul>
+  </li>
+</ul>
+
+<hr size="1">
+<p>
+ <font size="-1">
+  This document was generated by <em>gr</em> on <em>May, 18 2009</em> using <a href="http://www.nongnu.org/texi2html/"><em>texi2html 1.78</em></a>.
+ </font>
+ <br>
+
+</p>
+</body>
+</html>
diff --git a/tinyc/tcc-doc.texi b/tinyc/tcc-doc.texi
new file mode 100644
index 000000000..47a8c8b00
--- /dev/null
+++ b/tinyc/tcc-doc.texi
@@ -0,0 +1,1227 @@
+\input texinfo @c -*- texinfo -*-
+@c %**start of header
+@setfilename tcc-doc.info
+@settitle Tiny C Compiler Reference Documentation
+@c %**end of header
+
+@include config.texi
+
+@iftex
+@titlepage
+@afourpaper
+@sp 7
+@center @titlefont{Tiny C Compiler Reference Documentation}
+@sp 3
+@end titlepage
+@headings double
+@end iftex
+
+@contents
+
+@node Top, Introduction, (dir), (dir)
+@top Tiny C Compiler Reference Documentation
+
+This manual documents version @value{VERSION} of the Tiny C Compiler.
+
+@menu
+* Introduction::                Introduction to tcc.
+* Invoke::                      Invocation of tcc (command line, options).
+* Clang::                       ANSI C and extensions.
+* asm::                         Assembler syntax.
+* linker::                      Output file generation and supported targets.
+* Bounds::                      Automatic bounds-checking of C code.
+* Libtcc::                      The libtcc library.
+* devel::                       Guide for Developers.
+@end menu
+
+
+@node Introduction
+@chapter Introduction
+
+TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C
+compilers, it is meant to be self-relying: you do not need an
+external assembler or linker because TCC does that for you.
+
+TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may
+not be necessary.
+
+TCC not only supports ANSI C, but also most of the new ISO C99
+standard and many GNUC extensions including inline assembly.
+
+TCC can also be used to make @emph{C scripts}, i.e. pieces of C source
+that you run as a Perl or Python script. Compilation is so fast that
+your script will be as fast as if it was an executable.
+
+TCC can also automatically generate memory and bound checks
+(@pxref{Bounds}) while allowing all C pointers operations. TCC can do
+these checks even if non patched libraries are used.
+
+With @code{libtcc}, you can use TCC as a backend for dynamic code
+generation (@pxref{Libtcc}).
+
+TCC mainly supports the i386 target on Linux and Windows. There are alpha
+ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets
+(@code{c67-tcc}). More information about the ARM port is available at
+@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}.
+
+For usage on Windows, see also tcc-win32.txt.
+
+@node Invoke
+@chapter Command line invocation
+
+@section Quick start
+
+@example
+@c man begin SYNOPSIS
+usage: tcc [options] [@var{infile1} @var{infile2}@dots{}] [@option{-run} @var{infile} @var{args}@dots{}]
+@c man end
+@end example
+
+@noindent
+@c man begin DESCRIPTION
+TCC options are a very much like gcc options. The main difference is that TCC
+can also execute directly the resulting program and give it runtime
+arguments.
+
+Here are some examples to understand the logic:
+
+@table @code
+@item @samp{tcc -run a.c}
+Compile @file{a.c} and execute it directly
+
+@item @samp{tcc -run a.c arg1}
+Compile a.c and execute it directly. arg1 is given as first argument to
+the @code{main()} of a.c.
+
+@item @samp{tcc a.c -run b.c arg1}
+Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given
+as first argument to the @code{main()} of the resulting program. 
+@ignore 
+Because multiple C files are specified, @option{--} are necessary to clearly 
+separate the program arguments from the TCC options.
+@end ignore
+
+@item @samp{tcc -o myprog a.c b.c}
+Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}.
+
+@item @samp{tcc -o myprog a.o b.o}
+link @file{a.o} and @file{b.o} together and generate the executable @file{myprog}.
+
+@item @samp{tcc -c a.c}
+Compile @file{a.c} and generate object file @file{a.o}.
+
+@item @samp{tcc -c asmfile.S}
+Preprocess with C preprocess and assemble @file{asmfile.S} and generate
+object file @file{asmfile.o}.
+
+@item @samp{tcc -c asmfile.s}
+Assemble (but not preprocess) @file{asmfile.s} and generate object file
+@file{asmfile.o}.
+
+@item @samp{tcc -r -o ab.o a.c b.c}
+Compile @file{a.c} and @file{b.c}, link them together and generate the object file @file{ab.o}.
+
+@end table
+
+Scripting:
+
+TCC can be invoked from @emph{scripts}, just as shell scripts. You just
+need to add @code{#!/usr/local/bin/tcc -run} at the start of your C source:
+
+@example
+#!/usr/local/bin/tcc -run
+#include <stdio.h>
+
+int main() 
+@{
+    printf("Hello World\n");
+    return 0;
+@}
+@end example
+
+TCC can read C source code from @emph{standard input} when @option{-} is used in 
+place of @option{infile}. Example:
+
+@example
+echo 'main()@{puts("hello");@}' | tcc -run -
+@end example
+@c man end
+
+@section Option summary
+
+General Options:
+
+@c man begin OPTIONS
+@table @option
+@item -v
+Display current TCC version, increase verbosity.
+
+@item -c
+Generate an object file (@option{-o} option must also be given).
+
+@item -o outfile
+Put object file, executable, or dll into output file @file{outfile}.
+
+@item -Bdir
+Set the path where the tcc internal libraries can be found (default is
+@file{PREFIX/lib/tcc}).
+
+@item -bench
+Output compilation statistics.
+
+@item -run source [args...]
+Compile file @var{source} and run it with the command line arguments
+@var{args}. In order to be able to give more than one argument to a
+script, several TCC options can be given @emph{after} the
+@option{-run} option, separated by spaces. Example:
+
+@example
+tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
+@end example
+
+In a script, it gives the following header:
+
+@example
+#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
+#include <stdlib.h>
+int main(int argc, char **argv)
+@{
+    ...
+@}
+@end example
+
+@end table
+
+Preprocessor options:
+
+@table @option
+@item -Idir
+Specify an additional include path. Include paths are searched in the
+order they are specified.
+
+System include paths are always searched after. The default system
+include paths are: @file{/usr/local/include}, @file{/usr/include}
+and @file{PREFIX/lib/tcc/include}. (@file{PREFIX} is usually
+@file{/usr} or @file{/usr/local}).
+
+@item -Dsym[=val]
+Define preprocessor symbol @samp{sym} to
+val. If val is not present, its value is @samp{1}. Function-like macros can
+also be defined: @option{-DF(a)=a+1}
+
+@item -Usym
+Undefine preprocessor symbol @samp{sym}.
+@end table
+
+Compilation flags:
+
+Note: each of the following warning options has a negative form beginning with
+@option{-fno-}.
+
+@table @option
+@item -funsigned-char
+Let the @code{char} type be unsigned.
+
+@item -fsigned-char
+Let the @code{char} type be signed.
+
+@item -fno-common
+Do not generate common symbols for uninitialized data.
+
+@item -fleading-underscore
+Add a leading underscore at the beginning of each C symbol.
+
+@end table
+
+Warning options:
+
+@table @option
+@item -w
+Disable all warnings.
+
+@end table
+
+Note: each of the following warning options has a negative form beginning with
+@option{-Wno-}.
+
+@table @option
+@item -Wimplicit-function-declaration
+Warn about implicit function declaration.
+
+@item -Wunsupported
+Warn about unsupported GCC features that are ignored by TCC.
+
+@item -Wwrite-strings
+Make string constants be of type @code{const char *} instead of @code{char
+*}.
+
+@item -Werror
+Abort compilation if warnings are issued.
+
+@item -Wall 
+Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and
+@option{-Wwrite-strings}.
+
+@end table
+
+Linker options:
+
+@table @option
+@item -Ldir
+Specify an additional static library path for the @option{-l} option. The
+default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}.
+
+@item -lxxx
+Link your program with dynamic library libxxx.so or static library
+libxxx.a. The library is searched in the paths specified by the
+@option{-L} option.
+
+@item -shared
+Generate a shared library instead of an executable (@option{-o} option
+must also be given).
+
+@item -static
+Generate a statically linked executable (default is a shared linked
+executable) (@option{-o} option must also be given).
+
+@item -rdynamic
+Export global symbols to the dynamic linker. It is useful when a library
+opened with @code{dlopen()} needs to access executable symbols.
+
+@item -r
+Generate an object file combining all input files (@option{-o} option must
+also be given).
+
+@item -Wl,-Ttext,address
+Set the start of the .text section to @var{address}.
+
+@item -Wl,--oformat,fmt
+Use @var{fmt} as output format. The supported output formats are:
+@table @code
+@item elf32-i386
+ELF output format (default)
+@item binary
+Binary image (only for executable output)
+@item coff
+COFF output format (only for executable output for TMS320C67xx target)
+@end table
+
+@end table
+
+Debugger options:
+
+@table @option
+@item -g
+Generate run time debug information so that you get clear run time
+error messages: @code{ test.c:68: in function 'test5()': dereferencing
+invalid pointer} instead of the laconic @code{Segmentation
+fault}.
+
+@item -b
+Generate additional support code to check
+memory allocations and array/pointer bounds. @option{-g} is implied. Note
+that the generated code is slower and bigger in this case.
+
+@item -bt N
+Display N callers in stack traces. This is useful with @option{-g} or
+@option{-b}.
+
+@end table
+
+Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are
+ignored.
+@c man end
+
+@ignore
+
+@setfilename tcc
+@settitle Tiny C Compiler
+
+@c man begin SEEALSO
+gcc(1)
+@c man end
+
+@c man begin AUTHOR
+Fabrice Bellard
+@c man end
+
+@end ignore
+
+@node Clang
+@chapter C language support
+
+@section ANSI C
+
+TCC implements all the ANSI C standard, including structure bit fields
+and floating point numbers (@code{long double}, @code{double}, and
+@code{float} fully supported).
+
+@section ISOC99 extensions
+
+TCC implements many features of the new C standard: ISO C99. Currently
+missing items are: complex and imaginary numbers and variable length
+arrays.
+
+Currently implemented ISOC99 features:
+
+@itemize
+
+@item 64 bit @code{long long} types are fully supported.
+
+@item The boolean type @code{_Bool} is supported.
+
+@item @code{__func__} is a string variable containing the current
+function name.
+
+@item Variadic macros: @code{__VA_ARGS__} can be used for
+   function-like macros:
+@example
+    #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)
+@end example
+
+@noindent
+@code{dprintf} can then be used with a variable number of parameters.
+
+@item Declarations can appear anywhere in a block (as in C++).
+
+@item Array and struct/union elements can be initialized in any order by
+  using designators:
+@example
+    struct @{ int x, y; @} st[10] = @{ [0].x = 1, [0].y = 2 @};
+
+    int tab[10] = @{ 1, 2, [5] = 5, [9] = 9@};
+@end example
+    
+@item Compound initializers are supported:
+@example
+    int *p = (int [])@{ 1, 2, 3 @};
+@end example
+to initialize a pointer pointing to an initialized array. The same
+works for structures and strings.
+
+@item Hexadecimal floating point constants are supported:
+@example
+          double d = 0x1234p10;
+@end example
+
+@noindent
+is the same as writing 
+@example
+          double d = 4771840.0;
+@end example
+
+@item @code{inline} keyword is ignored.
+
+@item @code{restrict} keyword is ignored.
+@end itemize
+
+@section GNU C extensions
+
+TCC implements some GNU C extensions:
+
+@itemize
+
+@item array designators can be used without '=': 
+@example
+    int a[10] = @{ [0] 1, [5] 2, 3, 4 @};
+@end example
+
+@item Structure field designators can be a label: 
+@example
+    struct @{ int x, y; @} st = @{ x: 1, y: 1@};
+@end example
+instead of
+@example
+    struct @{ int x, y; @} st = @{ .x = 1, .y = 1@};
+@end example
+
+@item @code{\e} is ASCII character 27.
+
+@item case ranges : ranges can be used in @code{case}s:
+@example
+    switch(a) @{
+    case 1 @dots{} 9:
+          printf("range 1 to 9\n");
+          break;
+    default:
+          printf("unexpected\n");
+          break;
+    @}
+@end example
+
+@cindex aligned attribute
+@cindex packed attribute
+@cindex section attribute
+@cindex unused attribute
+@cindex cdecl attribute
+@cindex stdcall attribute
+@cindex regparm attribute
+@cindex dllexport attribute
+
+@item The keyword @code{__attribute__} is handled to specify variable or
+function attributes. The following attributes are supported:
+  @itemize
+
+  @item @code{aligned(n)}: align a variable or a structure field to n bytes
+(must be a power of two).
+
+  @item @code{packed}: force alignment of a variable or a structure field to
+  1.
+
+  @item @code{section(name)}: generate function or data in assembly section
+name (name is a string containing the section name) instead of the default
+section.
+
+  @item @code{unused}: specify that the variable or the function is unused.
+
+  @item @code{cdecl}: use standard C calling convention (default).
+
+  @item @code{stdcall}: use Pascal-like calling convention.
+
+  @item @code{regparm(n)}: use fast i386 calling convention. @var{n} must be
+between 1 and 3. The first @var{n} function parameters are respectively put in
+registers @code{%eax}, @code{%edx} and @code{%ecx}.
+
+  @item @code{dllexport}: export function from dll/executable (win32 only)
+
+  @end itemize
+
+Here are some examples:
+@example
+    int a __attribute__ ((aligned(8), section(".mysection")));
+@end example
+
+@noindent
+align variable @code{a} to 8 bytes and put it in section @code{.mysection}.
+
+@example
+    int my_add(int a, int b) __attribute__ ((section(".mycodesection"))) 
+    @{
+        return a + b;
+    @}
+@end example
+
+@noindent
+generate function @code{my_add} in section @code{.mycodesection}.
+
+@item GNU style variadic macros:
+@example
+    #define dprintf(fmt, args@dots{}) printf(fmt, ## args)
+
+    dprintf("no arg\n");
+    dprintf("one arg %d\n", 1);
+@end example
+
+@item @code{__FUNCTION__} is interpreted as C99 @code{__func__} 
+(so it has not exactly the same semantics as string literal GNUC
+where it is a string literal).
+
+@item The @code{__alignof__} keyword can be used as @code{sizeof} 
+to get the alignment of a type or an expression.
+
+@item The @code{typeof(x)} returns the type of @code{x}. 
+@code{x} is an expression or a type.
+
+@item Computed gotos: @code{&&label} returns a pointer of type 
+@code{void *} on the goto label @code{label}. @code{goto *expr} can be
+used to jump on the pointer resulting from @code{expr}.
+
+@item Inline assembly with asm instruction:
+@cindex inline assembly
+@cindex assembly, inline
+@cindex __asm__
+@example
+static inline void * my_memcpy(void * to, const void * from, size_t n)
+@{
+int d0, d1, d2;
+__asm__ __volatile__(
+        "rep ; movsl\n\t"
+        "testb $2,%b4\n\t"
+        "je 1f\n\t"
+        "movsw\n"
+        "1:\ttestb $1,%b4\n\t"
+        "je 2f\n\t"
+        "movsb\n"
+        "2:"
+        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
+        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+        : "memory");
+return (to);
+@}
+@end example
+
+@noindent
+@cindex gas
+TCC includes its own x86 inline assembler with a @code{gas}-like (GNU
+assembler) syntax. No intermediate files are generated. GCC 3.x named
+operands are supported.
+
+@item @code{__builtin_types_compatible_p()} and @code{__builtin_constant_p()} 
+are supported.
+
+@item @code{#pragma pack} is supported for win32 compatibility.
+
+@end itemize
+
+@section TinyCC extensions
+
+@itemize
+
+@item @code{__TINYC__} is a predefined macro to @code{1} to
+indicate that you use TCC.
+
+@item @code{#!} at the start of a line is ignored to allow scripting.
+
+@item Binary digits can be entered (@code{0b101} instead of
+@code{5}).
+
+@item @code{__BOUNDS_CHECKING_ON} is defined if bound checking is activated.
+
+@end itemize
+
+@node asm
+@chapter TinyCC Assembler
+
+Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
+assembler supports a gas-like syntax (GNU assembler). You can
+desactivate assembler support if you want a smaller TinyCC executable
+(the C compiler does not rely on the assembler).
+
+TinyCC Assembler is used to handle files with @file{.S} (C
+preprocessed assembler) and @file{.s} extensions. It is also used to
+handle the GNU inline assembler with the @code{asm} keyword.
+
+@section Syntax
+
+TinyCC Assembler supports most of the gas syntax. The tokens are the
+same as C.
+
+@itemize
+
+@item C and C++ comments are supported.
+
+@item Identifiers are the same as C, so you cannot use '.' or '$'.
+
+@item Only 32 bit integer numbers are supported.
+
+@end itemize
+
+@section Expressions
+
+@itemize
+
+@item Integers in decimal, octal and hexa are supported.
+
+@item Unary operators: +, -, ~.
+
+@item Binary operators in decreasing priority order:
+
+@enumerate
+@item *, /, %
+@item &, |, ^
+@item +, -
+@end enumerate
+
+@item A value is either an absolute number or a label plus an offset. 
+All operators accept absolute values except '+' and '-'. '+' or '-' can be
+used to add an offset to a label. '-' supports two labels only if they
+are the same or if they are both defined and in the same section.
+
+@end itemize
+
+@section Labels
+
+@itemize
+
+@item All labels are considered as local, except undefined ones.
+
+@item Numeric labels can be used as local @code{gas}-like labels. 
+They can be defined several times in the same source. Use 'b'
+(backward) or 'f' (forward) as suffix to reference them:
+
+@example
+ 1:
+      jmp 1b /* jump to '1' label before */
+      jmp 1f /* jump to '1' label after */
+ 1:
+@end example
+
+@end itemize
+
+@section Directives
+@cindex assembler directives
+@cindex directives, assembler
+@cindex align directive
+@cindex skip directive
+@cindex space directive
+@cindex byte directive
+@cindex word directive
+@cindex short directive
+@cindex int directive
+@cindex long directive
+@cindex quad directive
+@cindex globl directive
+@cindex global directive
+@cindex section directive
+@cindex text directive
+@cindex data directive
+@cindex bss directive
+@cindex fill directive
+@cindex org directive
+@cindex previous directive
+@cindex string directive
+@cindex asciz directive
+@cindex ascii directive
+
+All directives are preceded by a '.'. The following directives are
+supported:
+
+@itemize
+@item .align n[,value]
+@item .skip n[,value]
+@item .space n[,value]
+@item .byte value1[,...]
+@item .word value1[,...]
+@item .short value1[,...]
+@item .int value1[,...]
+@item .long value1[,...]
+@item .quad immediate_value1[,...]
+@item .globl symbol
+@item .global symbol
+@item .section section
+@item .text
+@item .data
+@item .bss
+@item .fill repeat[,size[,value]]
+@item .org n
+@item .previous
+@item .string string[,...]
+@item .asciz string[,...]
+@item .ascii string[,...]
+@end itemize
+
+@section X86 Assembler
+@cindex assembler
+
+All X86 opcodes are supported. Only ATT syntax is supported (source
+then destination operand order). If no size suffix is given, TinyCC
+tries to guess it from the operand sizes.
+
+Currently, MMX opcodes are supported but not SSE ones.
+
+@node linker
+@chapter TinyCC Linker
+@cindex linker
+
+@section ELF file generation
+@cindex ELF
+
+TCC can directly output relocatable ELF files (object files),
+executable ELF files and dynamic ELF libraries without relying on an
+external linker.
+
+Dynamic ELF libraries can be output but the C compiler does not generate
+position independent code (PIC). It means that the dynamic library
+code generated by TCC cannot be factorized among processes yet.
+
+TCC linker eliminates unreferenced object code in libraries. A single pass is
+done on the object and library list, so the order in which object files and
+libraries are specified is important (same constraint as GNU ld). No grouping
+options (@option{--start-group} and @option{--end-group}) are supported.
+
+@section ELF file loader
+
+TCC can load ELF object files, archives (.a files) and dynamic
+libraries (.so).
+
+@section PE-i386 file generation
+@cindex PE-i386
+
+TCC for Windows supports the native Win32 executable file format (PE-i386).  It
+generates EXE files (console and gui) and DLL files.
+
+For usage on Windows, see also tcc-win32.txt.
+
+@section GNU Linker Scripts
+@cindex scripts, linker
+@cindex linker scripts
+@cindex GROUP, linker command
+@cindex FILE, linker command
+@cindex OUTPUT_FORMAT, linker command
+@cindex TARGET, linker command
+
+Because on many Linux systems some dynamic libraries (such as
+@file{/usr/lib/libc.so}) are in fact GNU ld link scripts (horrible!),
+the TCC linker also supports a subset of GNU ld scripts.
+
+The @code{GROUP} and @code{FILE} commands are supported. @code{OUTPUT_FORMAT}
+and @code{TARGET} are ignored.
+
+Example from @file{/usr/lib/libc.so}:
+@example
+/* GNU ld script
+   Use the shared library, but some functions are only in
+   the static library, so try that secondarily.  */
+GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
+@end example
+
+@node Bounds
+@chapter TinyCC Memory and Bound checks
+@cindex bound checks
+@cindex memory checks
+
+This feature is activated with the @option{-b} (@pxref{Invoke}).
+
+Note that pointer size is @emph{unchanged} and that code generated
+with bound checks is @emph{fully compatible} with unchecked
+code. When a pointer comes from unchecked code, it is assumed to be
+valid. Even very obscure C code with casts should work correctly.
+
+For more information about the ideas behind this method, see
+@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}.
+
+Here are some examples of caught errors:
+
+@table @asis
+
+@item Invalid range with standard string function:
+@example
+@{
+    char tab[10];
+    memset(tab, 0, 11);
+@}
+@end example
+
+@item Out of bounds-error in global or local arrays:
+@example
+@{
+    int tab[10];
+    for(i=0;i<11;i++) @{
+        sum += tab[i];
+    @}
+@}
+@end example
+
+@item Out of bounds-error in malloc'ed data:
+@example
+@{
+    int *tab;
+    tab = malloc(20 * sizeof(int));
+    for(i=0;i<21;i++) @{
+        sum += tab4[i];
+    @}
+    free(tab);
+@}
+@end example
+
+@item Access of freed memory:
+@example
+@{
+    int *tab;
+    tab = malloc(20 * sizeof(int));
+    free(tab);
+    for(i=0;i<20;i++) @{
+        sum += tab4[i];
+    @}
+@}
+@end example
+
+@item Double free:
+@example
+@{
+    int *tab;
+    tab = malloc(20 * sizeof(int));
+    free(tab);
+    free(tab);
+@}
+@end example
+
+@end table
+
+@node Libtcc
+@chapter The @code{libtcc} library
+
+The @code{libtcc} library enables you to use TCC as a backend for
+dynamic code generation. 
+
+Read the @file{libtcc.h} to have an overview of the API. Read
+@file{libtcc_test.c} to have a very simple example.
+
+The idea consists in giving a C string containing the program you want
+to compile directly to @code{libtcc}. Then you can access to any global
+symbol (function or variable) defined.
+
+@node devel
+@chapter Developer's guide
+
+This chapter gives some hints to understand how TCC works. You can skip
+it if you do not intend to modify the TCC code.
+
+@section File reading
+
+The @code{BufferedFile} structure contains the context needed to read a
+file, including the current line number. @code{tcc_open()} opens a new
+file and @code{tcc_close()} closes it. @code{inp()} returns the next
+character.
+
+@section Lexer
+
+@code{next()} reads the next token in the current
+file. @code{next_nomacro()} reads the next token without macro
+expansion.
+
+@code{tok} contains the current token (see @code{TOK_xxx})
+constants. Identifiers and keywords are also keywords. @code{tokc}
+contains additional infos about the token (for example a constant value
+if number or string token).
+
+@section Parser
+
+The parser is hardcoded (yacc is not necessary). It does only one pass,
+except:
+
+@itemize
+
+@item For initialized arrays with unknown size, a first pass 
+is done to count the number of elements.
+
+@item For architectures where arguments are evaluated in 
+reverse order, a first pass is done to reverse the argument order.
+
+@end itemize
+
+@section Types
+
+The types are stored in a single 'int' variable. It was chosen in the
+first stages of development when tcc was much simpler. Now, it may not
+be the best solution.
+
+@example
+#define VT_INT        0  /* integer type */
+#define VT_BYTE       1  /* signed byte type */
+#define VT_SHORT      2  /* short type */
+#define VT_VOID       3  /* void type */
+#define VT_PTR        4  /* pointer */
+#define VT_ENUM       5  /* enum definition */
+#define VT_FUNC       6  /* function type */
+#define VT_STRUCT     7  /* struct/union definition */
+#define VT_FLOAT      8  /* IEEE float */
+#define VT_DOUBLE     9  /* IEEE double */
+#define VT_LDOUBLE   10  /* IEEE long double */
+#define VT_BOOL      11  /* ISOC99 boolean type */
+#define VT_LLONG     12  /* 64 bit integer */
+#define VT_LONG      13  /* long integer (NEVER USED as type, only
+                            during parsing) */
+#define VT_BTYPE      0x000f /* mask for basic type */
+#define VT_UNSIGNED   0x0010  /* unsigned type */
+#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
+#define VT_BITFIELD   0x0040  /* bitfield modifier */
+
+#define VT_STRUCT_SHIFT 16   /* structure/enum name shift (16 bits left) */
+@end example
+
+When a reference to another type is needed (for pointers, functions and
+structures), the @code{32 - VT_STRUCT_SHIFT} high order bits are used to
+store an identifier reference.
+
+The @code{VT_UNSIGNED} flag can be set for chars, shorts, ints and long
+longs.
+
+Arrays are considered as pointers @code{VT_PTR} with the flag
+@code{VT_ARRAY} set.
+
+The @code{VT_BITFIELD} flag can be set for chars, shorts, ints and long
+longs. If it is set, then the bitfield position is stored from bits
+VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored
+from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.
+
+@code{VT_LONG} is never used except during parsing.
+
+During parsing, the storage of an object is also stored in the type
+integer:
+
+@example
+#define VT_EXTERN  0x00000080  /* extern definition */
+#define VT_STATIC  0x00000100  /* static variable */
+#define VT_TYPEDEF 0x00000200  /* typedef definition */
+@end example
+
+@section Symbols
+
+All symbols are stored in hashed symbol stacks. Each symbol stack
+contains @code{Sym} structures.
+
+@code{Sym.v} contains the symbol name (remember
+an idenfier is also a token, so a string is never necessary to store
+it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually
+the register in which the corresponding variable is stored. @code{Sym.c} is
+usually a constant associated to the symbol.
+
+Four main symbol stacks are defined:
+
+@table @code
+
+@item define_stack
+for the macros (@code{#define}s).
+
+@item global_stack
+for the global variables, functions and types.
+
+@item local_stack
+for the local variables, functions and types.
+
+@item global_label_stack
+for the local labels (for @code{goto}).
+
+@item label_stack
+for GCC block local labels (see the @code{__label__} keyword).
+
+@end table
+
+@code{sym_push()} is used to add a new symbol in the local symbol
+stack. If no local symbol stack is active, it is added in the global
+symbol stack.
+
+@code{sym_pop(st,b)} pops symbols from the symbol stack @var{st} until
+the symbol @var{b} is on the top of stack. If @var{b} is NULL, the stack
+is emptied.
+
+@code{sym_find(v)} return the symbol associated to the identifier
+@var{v}. The local stack is searched first from top to bottom, then the
+global stack.
+
+@section Sections
+
+The generated code and datas are written in sections. The structure
+@code{Section} contains all the necessary information for a given
+section. @code{new_section()} creates a new section. ELF file semantics
+is assumed for each section.
+
+The following sections are predefined:
+
+@table @code
+
+@item text_section
+is the section containing the generated code. @var{ind} contains the
+current position in the code section.
+
+@item data_section
+contains initialized data
+
+@item bss_section
+contains uninitialized data
+
+@item bounds_section
+@itemx lbounds_section
+are used when bound checking is activated
+
+@item stab_section
+@itemx stabstr_section
+are used when debugging is activated to store debug information
+
+@item symtab_section
+@itemx strtab_section
+contain the exported symbols (currently only used for debugging).
+
+@end table
+
+@section Code generation
+@cindex code generation
+
+@subsection Introduction
+
+The TCC code generator directly generates linked binary code in one
+pass. It is rather unusual these days (see gcc for example which
+generates text assembly), but it can be very fast and surprisingly
+little complicated.
+
+The TCC code generator is register based. Optimization is only done at
+the expression level. No intermediate representation of expression is
+kept except the current values stored in the @emph{value stack}.
+
+On x86, three temporary registers are used. When more registers are
+needed, one register is spilled into a new temporary variable on the stack.
+
+@subsection The value stack
+@cindex value stack, introduction
+
+When an expression is parsed, its value is pushed on the value stack
+(@var{vstack}). The top of the value stack is @var{vtop}. Each value
+stack entry is the structure @code{SValue}.
+
+@code{SValue.t} is the type. @code{SValue.r} indicates how the value is
+currently stored in the generated code. It is usually a CPU register
+index (@code{REG_xxx} constants), but additional values and flags are
+defined:
+
+@example
+#define VT_CONST     0x00f0
+#define VT_LLOCAL    0x00f1
+#define VT_LOCAL     0x00f2
+#define VT_CMP       0x00f3
+#define VT_JMP       0x00f4
+#define VT_JMPI      0x00f5
+#define VT_LVAL      0x0100
+#define VT_SYM       0x0200
+#define VT_MUSTCAST  0x0400
+#define VT_MUSTBOUND 0x0800
+#define VT_BOUNDED   0x8000
+#define VT_LVAL_BYTE     0x1000
+#define VT_LVAL_SHORT    0x2000
+#define VT_LVAL_UNSIGNED 0x4000
+#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
+@end example
+
+@table @code
+
+@item VT_CONST
+indicates that the value is a constant. It is stored in the union
+@code{SValue.c}, depending on its type.
+
+@item VT_LOCAL
+indicates a local variable pointer at offset @code{SValue.c.i} in the
+stack.
+
+@item VT_CMP
+indicates that the value is actually stored in the CPU flags (i.e. the
+value is the consequence of a test). The value is either 0 or 1. The
+actual CPU flags used is indicated in @code{SValue.c.i}. 
+
+If any code is generated which destroys the CPU flags, this value MUST be
+put in a normal register.
+
+@item VT_JMP
+@itemx VT_JMPI
+indicates that the value is the consequence of a conditional jump. For VT_JMP,
+it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted.
+
+These values are used to compile the @code{||} and @code{&&} logical
+operators.
+
+If any code is generated, this value MUST be put in a normal
+register. Otherwise, the generated code won't be executed if the jump is
+taken.
+
+@item VT_LVAL
+is a flag indicating that the value is actually an lvalue (left value of
+an assignment). It means that the value stored is actually a pointer to
+the wanted value. 
+
+Understanding the use @code{VT_LVAL} is very important if you want to
+understand how TCC works.
+
+@item VT_LVAL_BYTE
+@itemx VT_LVAL_SHORT
+@itemx VT_LVAL_UNSIGNED
+if the lvalue has an integer type, then these flags give its real
+type. The type alone is not enough in case of cast optimisations.
+
+@item VT_LLOCAL
+is a saved lvalue on the stack. @code{VT_LLOCAL} should be eliminated
+ASAP because its semantics are rather complicated.
+
+@item VT_MUSTCAST
+indicates that a cast to the value type must be performed if the value
+is used (lazy casting).
+
+@item VT_SYM
+indicates that the symbol @code{SValue.sym} must be added to the constant.
+
+@item VT_MUSTBOUND
+@itemx VT_BOUNDED
+are only used for optional bound checking.
+
+@end table
+
+@subsection Manipulating the value stack
+@cindex value stack
+
+@code{vsetc()} and @code{vset()} pushes a new value on the value
+stack. If the previous @var{vtop} was stored in a very unsafe place(for
+example in the CPU flags), then some code is generated to put the
+previous @var{vtop} in a safe storage.
+
+@code{vpop()} pops @var{vtop}. In some cases, it also generates cleanup
+code (for example if stacked floating point registers are used as on
+x86).
+
+The @code{gv(rc)} function generates code to evaluate @var{vtop} (the
+top value of the stack) into registers. @var{rc} selects in which
+register class the value should be put. @code{gv()} is the @emph{most
+important function} of the code generator.
+
+@code{gv2()} is the same as @code{gv()} but for the top two stack
+entries.
+
+@subsection CPU dependent code generation
+@cindex CPU dependent
+See the @file{i386-gen.c} file to have an example.
+
+@table @code
+
+@item load()
+must generate the code needed to load a stack value into a register.
+
+@item store()
+must generate the code needed to store a register into a stack value
+lvalue.
+
+@item gfunc_start()
+@itemx gfunc_param()
+@itemx gfunc_call()
+should generate a function call
+
+@item gfunc_prolog()
+@itemx gfunc_epilog()
+should generate a function prolog/epilog.
+
+@item gen_opi(op)
+must generate the binary integer operation @var{op} on the two top
+entries of the stack which are guaranted to contain integer types.
+
+The result value should be put on the stack.
+
+@item gen_opf(op)
+same as @code{gen_opi()} for floating point operations. The two top
+entries of the stack are guaranted to contain floating point values of
+same types.
+
+@item gen_cvt_itof()
+integer to floating point conversion.
+
+@item gen_cvt_ftoi()
+floating point to integer conversion.
+
+@item gen_cvt_ftof()
+floating point to floating point of different size conversion.
+
+@item gen_bounded_ptr_add()
+@item gen_bounded_ptr_deref()
+are only used for bounds checking.
+
+@end table
+
+@section Optimizations done
+@cindex optimizations
+@cindex constant propagation
+@cindex strength reduction
+@cindex comparison operators
+@cindex caching processor flags
+@cindex flags, caching
+@cindex jump optimization
+Constant propagation is done for all operations. Multiplications and
+divisions are optimized to shifts when appropriate. Comparison
+operators are optimized by maintaining a special cache for the
+processor flags. &&, || and ! are optimized by maintaining a special
+'jump target' value. No other jump optimization is currently performed
+because it would require to store the code in a more abstract fashion.
+
+@unnumbered Concept Index
+@printindex cp
+
+@bye
+
+@c Local variables:
+@c fill-column: 78
+@c texinfo-column-for-description: 32
+@c End:
diff --git a/tinyc/tcc.c b/tinyc/tcc.c
new file mode 100644
index 000000000..3fce60804
--- /dev/null
+++ b/tinyc/tcc.c
@@ -0,0 +1,553 @@
+/*
+ *  TCC - Tiny C Compiler
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#include "libtcc.c"
+
+void help(void)
+{
+    printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2006 Fabrice Bellard\n"
+           "usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n"
+           "           [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-soname name]\n"
+           "           [-static] [infile1 infile2...] [-run infile args...]\n"
+           "\n"
+           "General options:\n"
+           "  -v          display current version, increase verbosity\n"
+           "  -c          compile only - generate an object file\n"
+           "  -o outfile  set output filename\n"
+           "  -Bdir       set tcc internal library path\n"
+           "  -bench      output compilation statistics\n"
+           "  -run        run compiled source\n"
+           "  -fflag      set or reset (with 'no-' prefix) 'flag' (see man page)\n"
+           "  -Wwarning   set or reset (with 'no-' prefix) 'warning' (see man page)\n"
+           "  -w          disable all warnings\n"
+           "Preprocessor options:\n"
+           "  -E          preprocess only\n"
+           "  -Idir       add include path 'dir'\n"
+           "  -Dsym[=val] define 'sym' with value 'val'\n"
+           "  -Usym       undefine 'sym'\n"
+           "Linker options:\n"
+           "  -Ldir       add library path 'dir'\n"
+           "  -llib       link with dynamic or static library 'lib'\n"
+           "  -shared     generate a shared library\n"
+           "  -soname     set name for shared library to be used at runtime\n"
+           "  -static     static linking\n"
+           "  -rdynamic   export all global symbols to dynamic linker\n"
+           "  -r          generate (relocatable) object file\n"
+           "Debugger options:\n"
+           "  -g          generate runtime debug info\n"
+#ifdef CONFIG_TCC_BCHECK
+           "  -b          compile with built-in memory and bounds checker (implies -g)\n"
+#endif
+#ifdef CONFIG_TCC_BACKTRACE
+           "  -bt N       show N callers in stack traces\n"
+#endif
+           );
+}
+
+static char **files;
+static int nb_files, nb_libraries;
+static int multiple_files;
+static int print_search_dirs;
+static int output_type;
+static int reloc_output;
+static const char *outfile;
+static int do_bench = 0;
+
+#define TCC_OPTION_HAS_ARG 0x0001
+#define TCC_OPTION_NOSEP   0x0002 /* cannot have space before option and arg */
+
+typedef struct TCCOption {
+    const char *name;
+    uint16_t index;
+    uint16_t flags;
+} TCCOption;
+
+enum {
+    TCC_OPTION_HELP,
+    TCC_OPTION_I,
+    TCC_OPTION_D,
+    TCC_OPTION_U,
+    TCC_OPTION_L,
+    TCC_OPTION_B,
+    TCC_OPTION_l,
+    TCC_OPTION_bench,
+    TCC_OPTION_bt,
+    TCC_OPTION_b,
+    TCC_OPTION_g,
+    TCC_OPTION_c,
+    TCC_OPTION_static,
+    TCC_OPTION_shared,
+    TCC_OPTION_soname,
+    TCC_OPTION_o,
+    TCC_OPTION_r,
+    TCC_OPTION_Wl,
+    TCC_OPTION_W,
+    TCC_OPTION_O,
+    TCC_OPTION_m,
+    TCC_OPTION_f,
+    TCC_OPTION_nostdinc,
+    TCC_OPTION_nostdlib,
+    TCC_OPTION_print_search_dirs,
+    TCC_OPTION_rdynamic,
+    TCC_OPTION_run,
+    TCC_OPTION_v,
+    TCC_OPTION_w,
+    TCC_OPTION_pipe,
+    TCC_OPTION_E,
+};
+
+static const TCCOption tcc_options[] = {
+    { "h", TCC_OPTION_HELP, 0 },
+    { "?", TCC_OPTION_HELP, 0 },
+    { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
+    { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
+    { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
+    { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
+    { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
+    { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "bench", TCC_OPTION_bench, 0 },
+    { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
+#ifdef CONFIG_TCC_BCHECK
+    { "b", TCC_OPTION_b, 0 },
+#endif
+    { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "c", TCC_OPTION_c, 0 },
+    { "static", TCC_OPTION_static, 0 },
+    { "shared", TCC_OPTION_shared, 0 },
+    { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
+    { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
+    { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "rdynamic", TCC_OPTION_rdynamic, 0 },
+    { "r", TCC_OPTION_r, 0 },
+    { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
+    { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "nostdinc", TCC_OPTION_nostdinc, 0 },
+    { "nostdlib", TCC_OPTION_nostdlib, 0 },
+    { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, 
+    { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
+    { "w", TCC_OPTION_w, 0 },
+    { "pipe", TCC_OPTION_pipe, 0},
+    { "E", TCC_OPTION_E, 0},
+    { NULL },
+};
+
+static int64_t getclock_us(void)
+{
+#ifdef _WIN32
+    struct _timeb tb;
+    _ftime(&tb);
+    return (tb.time * 1000LL + tb.millitm) * 1000LL;
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec * 1000000LL + tv.tv_usec;
+#endif
+}
+
+static int strstart(const char *str, const char *val, const char **ptr)
+{
+    const char *p, *q;
+    p = str;
+    q = val;
+    while (*q != '\0') {
+        if (*p != *q)
+            return 0;
+        p++;
+        q++;
+    }
+    if (ptr)
+        *ptr = p;
+    return 1;
+}
+
+/* convert 'str' into an array of space separated strings */
+static int expand_args(char ***pargv, const char *str)
+{
+    const char *s1;
+    char **argv, *arg;
+    int argc, len;
+
+    argc = 0;
+    argv = NULL;
+    for(;;) {
+        while (is_space(*str))
+            str++;
+        if (*str == '\0')
+            break;
+        s1 = str;
+        while (*str != '\0' && !is_space(*str))
+            str++;
+        len = str - s1;
+        arg = tcc_malloc(len + 1);
+        memcpy(arg, s1, len);
+        arg[len] = '\0';
+        dynarray_add((void ***)&argv, &argc, arg);
+    }
+    *pargv = argv;
+    return argc;
+}
+
+int parse_args(TCCState *s, int argc, char **argv)
+{
+    int optind;
+    const TCCOption *popt;
+    const char *optarg, *p1, *r1;
+    char *r;
+
+    optind = 0;
+    while (optind < argc) {
+
+        r = argv[optind++];
+        if (r[0] != '-' || r[1] == '\0') {
+            /* add a new file */
+            dynarray_add((void ***)&files, &nb_files, r);
+            if (!multiple_files) {
+                optind--;
+                /* argv[0] will be this file */
+                break;
+            }
+        } else {
+            /* find option in table (match only the first chars */
+            popt = tcc_options;
+            for(;;) {
+                p1 = popt->name;
+                if (p1 == NULL)
+                    error("invalid option -- '%s'", r);
+                r1 = r + 1;
+                for(;;) {
+                    if (*p1 == '\0')
+                        goto option_found;
+                    if (*r1 != *p1)
+                        break;
+                    p1++;
+                    r1++;
+                }
+                popt++;
+            }
+        option_found:
+            if (popt->flags & TCC_OPTION_HAS_ARG) {
+                if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) {
+                    optarg = r1;
+                } else {
+                    if (optind >= argc)
+                        error("argument to '%s' is missing", r);
+                    optarg = argv[optind++];
+                }
+            } else {
+                if (*r1 != '\0')
+                    return 0;
+                optarg = NULL;
+            }
+                
+            switch(popt->index) {
+            case TCC_OPTION_HELP:
+                return 0;
+
+            case TCC_OPTION_I:
+                if (tcc_add_include_path(s, optarg) < 0)
+                    error("too many include paths");
+                break;
+            case TCC_OPTION_D:
+                {
+                    char *sym, *value;
+                    sym = (char *)optarg;
+                    value = strchr(sym, '=');
+                    if (value) {
+                        *value = '\0';
+                        value++;
+                    }
+                    tcc_define_symbol(s, sym, value);
+                }
+                break;
+            case TCC_OPTION_U:
+                tcc_undefine_symbol(s, optarg);
+                break;
+            case TCC_OPTION_L:
+                tcc_add_library_path(s, optarg);
+                break;
+            case TCC_OPTION_B:
+                /* set tcc utilities path (mainly for tcc development) */
+                tcc_set_lib_path(s, optarg);
+                break;
+            case TCC_OPTION_l:
+                dynarray_add((void ***)&files, &nb_files, r);
+                nb_libraries++;
+                break;
+            case TCC_OPTION_bench:
+                do_bench = 1;
+                break;
+#ifdef CONFIG_TCC_BACKTRACE
+            case TCC_OPTION_bt:
+                num_callers = atoi(optarg);
+                break;
+#endif
+#ifdef CONFIG_TCC_BCHECK
+            case TCC_OPTION_b:
+                s->do_bounds_check = 1;
+                s->do_debug = 1;
+                break;
+#endif
+            case TCC_OPTION_g:
+                s->do_debug = 1;
+                break;
+            case TCC_OPTION_c:
+                multiple_files = 1;
+                output_type = TCC_OUTPUT_OBJ;
+                break;
+            case TCC_OPTION_static:
+                s->static_link = 1;
+                break;
+            case TCC_OPTION_shared:
+                output_type = TCC_OUTPUT_DLL;
+                break;
+            case TCC_OPTION_soname:
+                s->soname = optarg; 
+                break;
+            case TCC_OPTION_o:
+                multiple_files = 1;
+                outfile = optarg;
+                break;
+            case TCC_OPTION_r:
+                /* generate a .o merging several output files */
+                reloc_output = 1;
+                output_type = TCC_OUTPUT_OBJ;
+                break;
+            case TCC_OPTION_nostdinc:
+                s->nostdinc = 1;
+                break;
+            case TCC_OPTION_nostdlib:
+                s->nostdlib = 1;
+                break;
+            case TCC_OPTION_print_search_dirs:
+                print_search_dirs = 1;
+                break;
+            case TCC_OPTION_run:
+                {
+                    int argc1;
+                    char **argv1;
+                    argc1 = expand_args(&argv1, optarg);
+                    if (argc1 > 0) {
+                        parse_args(s, argc1, argv1);
+                    }
+                    multiple_files = 0;
+                    output_type = TCC_OUTPUT_MEMORY;
+                }
+                break;
+            case TCC_OPTION_v:
+                do {
+                    if (0 == s->verbose++)
+                        printf("tcc version %s\n", TCC_VERSION);
+                } while (*optarg++ == 'v');
+                break;
+            case TCC_OPTION_f:
+                if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
+                    goto unsupported_option;
+                break;
+            case TCC_OPTION_W:
+                if (tcc_set_warning(s, optarg, 1) < 0 && 
+                    s->warn_unsupported)
+                    goto unsupported_option;
+                break;
+            case TCC_OPTION_w:
+                s->warn_none = 1;
+                break;
+            case TCC_OPTION_rdynamic:
+                s->rdynamic = 1;
+                break;
+            case TCC_OPTION_Wl:
+                {
+                    const char *p;
+                    if (strstart(optarg, "-Ttext,", &p)) {
+                        s->text_addr = strtoul(p, NULL, 16);
+                        s->has_text_addr = 1;
+                    } else if (strstart(optarg, "--oformat,", &p)) {
+                        if (strstart(p, "elf32-", NULL)) {
+                            s->output_format = TCC_OUTPUT_FORMAT_ELF;
+                        } else if (!strcmp(p, "binary")) {
+                            s->output_format = TCC_OUTPUT_FORMAT_BINARY;
+                        } else
+#ifdef TCC_TARGET_COFF
+                        if (!strcmp(p, "coff")) {
+                            s->output_format = TCC_OUTPUT_FORMAT_COFF;
+                        } else
+#endif
+                        {
+                            error("target %s not found", p);
+                        }
+                    } else {
+                        error("unsupported linker option '%s'", optarg);
+                    }
+                }
+                break;
+            case TCC_OPTION_E:
+                output_type = TCC_OUTPUT_PREPROCESS;
+                break;
+            default:
+                if (s->warn_unsupported) {
+                unsupported_option:
+                    warning("unsupported option '%s'", r);
+                }
+                break;
+            }
+        }
+    }
+    return optind + 1;
+}
+
+int main(int argc, char **argv)
+{
+    int i;
+    TCCState *s;
+    int nb_objfiles, ret, optind;
+    char objfilename[1024];
+    int64_t start_time = 0;
+
+    s = tcc_new();
+#ifdef _WIN32
+    tcc_set_lib_path_w32(s);
+#endif
+    output_type = TCC_OUTPUT_EXE;
+    outfile = NULL;
+    multiple_files = 1;
+    files = NULL;
+    nb_files = 0;
+    nb_libraries = 0;
+    reloc_output = 0;
+    print_search_dirs = 0;
+    ret = 0;
+
+    optind = parse_args(s, argc - 1, argv + 1);
+    if (print_search_dirs) {
+        /* enough for Linux kernel */
+        printf("install: %s/\n", s->tcc_lib_path);
+        return 0;
+    }
+    if (optind == 0 || nb_files == 0) {
+        if (optind && s->verbose)
+            return 0;
+        help();
+        return 1;
+    }
+
+    nb_objfiles = nb_files - nb_libraries;
+
+    /* if outfile provided without other options, we output an
+       executable */
+    if (outfile && output_type == TCC_OUTPUT_MEMORY)
+        output_type = TCC_OUTPUT_EXE;
+
+    /* check -c consistency : only single file handled. XXX: checks file type */
+    if (output_type == TCC_OUTPUT_OBJ && !reloc_output) {
+        /* accepts only a single input file */
+        if (nb_objfiles != 1)
+            error("cannot specify multiple files with -c");
+        if (nb_libraries != 0)
+            error("cannot specify libraries with -c");
+    }
+    
+
+    if (output_type == TCC_OUTPUT_PREPROCESS) {
+        if (!outfile) {
+            s->outfile = stdout;
+        } else {
+            s->outfile = fopen(outfile, "w");
+            if (!s->outfile)
+                error("could not open '%s", outfile);
+        }
+    } else if (output_type != TCC_OUTPUT_MEMORY) {
+        if (!outfile) {
+            /* compute default outfile name */
+            char *ext;
+            const char *name = 
+                strcmp(files[0], "-") == 0 ? "a" : tcc_basename(files[0]);
+            pstrcpy(objfilename, sizeof(objfilename), name);
+            ext = tcc_fileextension(objfilename);
+#ifdef TCC_TARGET_PE
+            if (output_type == TCC_OUTPUT_DLL)
+                strcpy(ext, ".dll");
+            else
+            if (output_type == TCC_OUTPUT_EXE)
+                strcpy(ext, ".exe");
+            else
+#endif
+            if (output_type == TCC_OUTPUT_OBJ && !reloc_output && *ext)
+                strcpy(ext, ".o");
+            else
+                pstrcpy(objfilename, sizeof(objfilename), "a.out");
+            outfile = objfilename;
+        }
+    }
+
+    if (do_bench) {
+        start_time = getclock_us();
+    }
+
+    tcc_set_output_type(s, output_type);
+
+    /* compile or add each files or library */
+    for(i = 0; i < nb_files && ret == 0; i++) {
+        const char *filename;
+
+        filename = files[i];
+        if (filename[0] == '-' && filename[1]) {
+            if (tcc_add_library(s, filename + 2) < 0) {
+                error_noabort("cannot find %s", filename);
+                ret = 1;
+            }
+        } else {
+            if (1 == s->verbose)
+                printf("-> %s\n", filename);
+            if (tcc_add_file(s, filename) < 0)
+                ret = 1;
+        }
+    }
+
+    /* free all files */
+    tcc_free(files);
+
+    if (ret)
+        goto the_end;
+
+    if (do_bench)
+        tcc_print_stats(s, getclock_us() - start_time);
+
+    if (s->output_type == TCC_OUTPUT_PREPROCESS) {
+        if (outfile)
+            fclose(s->outfile);
+    } else if (s->output_type == TCC_OUTPUT_MEMORY) {
+        ret = tcc_run(s, argc - optind, argv + optind);
+    } else
+        ret = tcc_output_file(s, outfile) ? 1 : 0;
+ the_end:
+    /* XXX: cannot do it with bound checking because of the malloc hooks */
+    if (!s->do_bounds_check)
+        tcc_delete(s);
+
+#ifdef MEM_DEBUG
+    if (do_bench) {
+        printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size);
+    }
+#endif
+    return ret;
+}
+
diff --git a/tinyc/tcc.h b/tinyc/tcc.h
new file mode 100644
index 000000000..be9c4ccb0
--- /dev/null
+++ b/tinyc/tcc.h
@@ -0,0 +1,766 @@
+/*
+ *  TCC - Tiny C Compiler
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#ifdef CONFIG_TCCBOOT
+
+#include "tccboot.h"
+#define CONFIG_TCC_STATIC
+
+#else
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <time.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <sys/timeb.h>
+#include <io.h> /* open, close etc. */
+#include <direct.h> /* getcwd */
+#define inline __inline
+#define inp next_inp
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/ucontext.h>
+#include <sys/mman.h>
+#endif
+
+#endif /* !CONFIG_TCCBOOT */
+
+#ifndef PAGESIZE
+#define PAGESIZE 4096
+#endif
+
+#include "elf.h"
+#include "stab.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#include "libtcc.h"
+
+/* parser debug */
+//#define PARSE_DEBUG
+/* preprocessor debug */
+//#define PP_DEBUG
+/* include file debug */
+//#define INC_DEBUG
+
+//#define MEM_DEBUG
+
+/* assembler debug */
+//#define ASM_DEBUG
+
+/* target selection */
+//#define TCC_TARGET_I386   /* i386 code generator */
+//#define TCC_TARGET_ARM    /* ARMv4 code generator */
+//#define TCC_TARGET_C67    /* TMS320C67xx code generator */
+//#define TCC_TARGET_X86_64 /* x86-64 code generator */
+
+/* default target is I386 */
+#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
+    !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
+#define TCC_TARGET_I386
+#endif
+
+#if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
+    !defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
+#define CONFIG_TCC_BCHECK /* enable bound checking code */
+#endif
+
+#if defined(_WIN32) && !defined(TCC_TARGET_PE)
+#define CONFIG_TCC_STATIC
+#endif
+
+/* define it to include assembler support */
+#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) && \
+    !defined(TCC_TARGET_X86_64)
+#define CONFIG_TCC_ASM
+#endif
+
+/* object format selection */
+#if defined(TCC_TARGET_C67)
+#define TCC_TARGET_COFF
+#endif
+
+#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
+#define CONFIG_TCC_BACKTRACE
+#endif
+
+#define FALSE 0
+#define false 0
+#define TRUE 1
+#define true 1
+typedef int BOOL;
+
+/* path to find crt1.o, crti.o and crtn.o. Only needed when generating
+   executables or dlls */
+#define CONFIG_TCC_CRT_PREFIX CONFIG_SYSROOT "/usr/lib"
+
+#define INCLUDE_STACK_SIZE  32
+#define IFDEF_STACK_SIZE    64
+#define VSTACK_SIZE         256
+#define STRING_MAX_SIZE     1024
+#define PACK_STACK_SIZE     8
+
+#define TOK_HASH_SIZE       8192 /* must be a power of two */
+#define TOK_ALLOC_INCR      512  /* must be a power of two */
+#define TOK_MAX_SIZE        4 /* token max size in int unit when stored in string */
+
+/* token symbol management */
+typedef struct TokenSym {
+    struct TokenSym *hash_next;
+    struct Sym *sym_define; /* direct pointer to define */
+    struct Sym *sym_label; /* direct pointer to label */
+    struct Sym *sym_struct; /* direct pointer to structure */
+    struct Sym *sym_identifier; /* direct pointer to identifier */
+    int tok; /* token number */
+    int len;
+    char str[1];
+} TokenSym;
+
+#ifdef TCC_TARGET_PE
+typedef unsigned short nwchar_t;
+#else
+typedef int nwchar_t;
+#endif
+
+typedef struct CString {
+    int size; /* size in bytes */
+    void *data; /* either 'char *' or 'nwchar_t *' */
+    int size_allocated;
+    void *data_allocated; /* if non NULL, data has been malloced */
+} CString;
+
+/* type definition */
+typedef struct CType {
+    int t;
+    struct Sym *ref;
+} CType;
+
+/* constant value */
+typedef union CValue {
+    long double ld;
+    double d;
+    float f;
+    int i;
+    unsigned int ui;
+    unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */
+    long long ll;
+    unsigned long long ull;
+    struct CString *cstr;
+    void *ptr;
+    int tab[1];
+} CValue;
+
+/* value on stack */
+typedef struct SValue {
+    CType type;      /* type */
+    unsigned short r;      /* register + flags */
+    unsigned short r2;     /* second register, used for 'long long'
+                              type. If not used, set to VT_CONST */
+    CValue c;              /* constant, if VT_CONST */
+    struct Sym *sym;       /* symbol, if (VT_SYM | VT_CONST) */
+} SValue;
+
+/* symbol management */
+typedef struct Sym {
+    int v;    /* symbol token */
+    long r;    /* associated register */
+    long c;    /* associated number */
+    CType type;    /* associated type */
+    struct Sym *next; /* next related symbol */
+    struct Sym *prev; /* prev symbol in stack */
+    struct Sym *prev_tok; /* previous symbol for this token */
+} Sym;
+
+/* section definition */
+/* XXX: use directly ELF structure for parameters ? */
+/* special flag to indicate that the section should not be linked to
+   the other ones */
+#define SHF_PRIVATE 0x80000000
+
+/* special flag, too */
+#define SECTION_ABS ((void *)1)
+
+typedef struct Section {
+    unsigned long data_offset; /* current data offset */
+    unsigned char *data;       /* section data */
+    unsigned long data_allocated; /* used for realloc() handling */
+    int sh_name;             /* elf section name (only used during output) */
+    int sh_num;              /* elf section number */
+    int sh_type;             /* elf section type */
+    int sh_flags;            /* elf section flags */
+    int sh_info;             /* elf section info */
+    int sh_addralign;        /* elf section alignment */
+    int sh_entsize;          /* elf entry size */
+    unsigned long sh_size;   /* section size (only used during output) */
+    unsigned long sh_addr;      /* address at which the section is relocated */
+    unsigned long sh_offset;    /* file offset */
+    int nb_hashed_syms;      /* used to resize the hash table */
+    struct Section *link;    /* link to another section */
+    struct Section *reloc;   /* corresponding section for relocation, if any */
+    struct Section *hash;     /* hash table for symbols */
+    struct Section *next;
+    char name[1];           /* section name */
+} Section;
+
+typedef struct DLLReference {
+    int level;
+    void *handle;
+    char name[1];
+} DLLReference;
+
+/* GNUC attribute definition */
+typedef struct AttributeDef {
+    int aligned;
+    int packed; 
+    Section *section;
+    int func_attr; /* calling convention, exports, ... */
+} AttributeDef;
+
+/* -------------------------------------------------- */
+/* gr: wrappers for casting sym->r for other purposes */
+typedef struct {
+    unsigned
+      func_call : 8,
+      func_args : 8,
+      func_export : 1;
+} func_attr_t;
+
+#define FUNC_CALL(r) (((func_attr_t*)&(r))->func_call)
+#define FUNC_EXPORT(r) (((func_attr_t*)&(r))->func_export)
+#define FUNC_ARGS(r) (((func_attr_t*)&(r))->func_args)
+#define INLINE_DEF(r) (*(int **)&(r))
+/* -------------------------------------------------- */
+
+#define SYM_STRUCT     0x40000000 /* struct/union/enum symbol space */
+#define SYM_FIELD      0x20000000 /* struct/union field symbol space */
+#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
+
+/* stored in 'Sym.c' field */
+#define FUNC_NEW       1 /* ansi function prototype */
+#define FUNC_OLD       2 /* old function prototype */
+#define FUNC_ELLIPSIS  3 /* ansi function prototype with ... */
+
+/* stored in 'Sym.r' field */
+#define FUNC_CDECL     0 /* standard c call */
+#define FUNC_STDCALL   1 /* pascal c call */
+#define FUNC_FASTCALL1 2 /* first param in %eax */
+#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
+#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
+#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */
+
+/* field 'Sym.t' for macros */
+#define MACRO_OBJ      0 /* object like macro */
+#define MACRO_FUNC     1 /* function like macro */
+
+/* field 'Sym.r' for C labels */
+#define LABEL_DEFINED  0 /* label is defined */
+#define LABEL_FORWARD  1 /* label is forward defined */
+#define LABEL_DECLARED 2 /* label is declared but never used */
+
+/* type_decl() types */
+#define TYPE_ABSTRACT  1 /* type without variable */
+#define TYPE_DIRECT    2 /* type with variable */
+
+#define IO_BUF_SIZE 8192
+
+typedef struct BufferedFile {
+    uint8_t *buf_ptr;
+    uint8_t *buf_end;
+    int fd;
+    int line_num;    /* current line number - here to simplify code */
+    int ifndef_macro;  /* #ifndef macro / #endif search */
+    int ifndef_macro_saved; /* saved ifndef_macro */
+    int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
+    char inc_type;          /* type of include */
+    char inc_filename[512]; /* filename specified by the user */
+    char filename[1024];    /* current filename - here to simplify code */
+    unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */
+} BufferedFile;
+
+#define CH_EOB   '\\'       /* end of buffer or '\0' char in file */
+#define CH_EOF   (-1)   /* end of file */
+
+/* parsing state (used to save parser state to reparse part of the
+   source several times) */
+typedef struct ParseState {
+    int *macro_ptr;
+    int line_num;
+    int tok;
+    CValue tokc;
+} ParseState;
+
+/* used to record tokens */
+typedef struct TokenString {
+    int *str;
+    int len;
+    int allocated_len;
+    int last_line_num;
+} TokenString;
+
+/* include file cache, used to find files faster and also to eliminate
+   inclusion if the include file is protected by #ifndef ... #endif */
+typedef struct CachedInclude {
+    int ifndef_macro;
+    int hash_next; /* -1 if none */
+    char type; /* '"' or '>' to give include type */
+    char filename[1]; /* path specified in #include */
+} CachedInclude;
+
+#define CACHED_INCLUDES_HASH_SIZE 512
+
+#ifdef CONFIG_TCC_ASM
+typedef struct ExprValue {
+    uint32_t v;
+    Sym *sym;
+} ExprValue;
+
+#define MAX_ASM_OPERANDS 30
+typedef struct ASMOperand {
+    int id; /* GCC 3 optionnal identifier (0 if number only supported */
+    char *constraint;
+    char asm_str[16]; /* computed asm string for operand */
+    SValue *vt; /* C value of the expression */
+    int ref_index; /* if >= 0, gives reference to a output constraint */
+    int input_index; /* if >= 0, gives reference to an input constraint */
+    int priority; /* priority, used to assign registers */
+    int reg; /* if >= 0, register number used for this operand */
+    int is_llong; /* true if double register value */
+    int is_memory; /* true if memory operand */
+    int is_rw;     /* for '+' modifier */
+} ASMOperand;
+
+#endif
+
+struct TCCState {
+    int output_type;
+ 
+    BufferedFile **include_stack_ptr;
+    int *ifdef_stack_ptr;
+
+    /* include file handling */
+    char **include_paths;
+    int nb_include_paths;
+    char **sysinclude_paths;
+    int nb_sysinclude_paths;
+    CachedInclude **cached_includes;
+    int nb_cached_includes;
+
+    char **library_paths;
+    int nb_library_paths;
+
+    /* array of all loaded dlls (including those referenced by loaded
+       dlls) */
+    DLLReference **loaded_dlls;
+    int nb_loaded_dlls;
+
+    /* sections */
+    Section **sections;
+    int nb_sections; /* number of sections, including first dummy section */
+
+    Section **priv_sections;
+    int nb_priv_sections; /* number of private sections */
+
+    /* got handling */
+    Section *got;
+    Section *plt;
+    unsigned long *got_offsets;
+    int nb_got_offsets;
+    /* give the correspondance from symtab indexes to dynsym indexes */
+    int *symtab_to_dynsym;
+
+    /* temporary dynamic symbol sections (for dll loading) */
+    Section *dynsymtab_section;
+    /* exported dynamic symbol section */
+    Section *dynsym;
+
+    int nostdinc; /* if true, no standard headers are added */
+    int nostdlib; /* if true, no standard libraries are added */
+    int nocommon; /* if true, do not use common symbols for .bss data */
+
+    /* if true, static linking is performed */
+    int static_link;
+
+    /* soname as specified on the command line (-soname) */
+    const char *soname;
+
+    /* if true, all symbols are exported */
+    int rdynamic;
+
+    /* if true, only link in referenced objects from archive */
+    int alacarte_link;
+
+    /* address of text section */
+    unsigned long text_addr;
+    int has_text_addr;
+    
+    /* output format, see TCC_OUTPUT_FORMAT_xxx */
+    int output_format;
+
+    /* C language options */
+    int char_is_unsigned;
+    int leading_underscore;
+    
+    /* warning switches */
+    int warn_write_strings;
+    int warn_unsupported;
+    int warn_error;
+    int warn_none;
+    int warn_implicit_function_declaration;
+
+    /* display some information during compilation */
+    int verbose;
+    /* compile with debug symbol (and use them if error during execution) */
+    int do_debug;
+    /* compile with built-in memory and bounds checker */
+    int do_bounds_check;
+    /* give the path of the tcc libraries */
+    const char *tcc_lib_path;
+
+    /* error handling */
+    void *error_opaque;
+    void (*error_func)(void *opaque, const char *msg);
+    int error_set_jmp_enabled;
+    jmp_buf error_jmp_buf;
+    int nb_errors;
+
+    /* tiny assembler state */
+    Sym *asm_labels;
+
+    /* see include_stack_ptr */
+    BufferedFile *include_stack[INCLUDE_STACK_SIZE];
+
+    /* see ifdef_stack_ptr */
+    int ifdef_stack[IFDEF_STACK_SIZE];
+
+    /* see cached_includes */
+    int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE];
+
+    /* pack stack */
+    int pack_stack[PACK_STACK_SIZE];
+    int *pack_stack_ptr;
+
+    /* output file for preprocessing */
+    FILE *outfile;
+
+    /* for tcc_relocate */
+    int runtime_added;
+
+#ifdef TCC_TARGET_X86_64
+    /* write PLT and GOT here */
+    char *runtime_plt_and_got;
+    unsigned int runtime_plt_and_got_offset;
+#endif
+};
+
+/* The current value can be: */
+#define VT_VALMASK   0x00ff
+#define VT_CONST     0x00f0  /* constant in vc 
+                              (must be first non register value) */
+#define VT_LLOCAL    0x00f1  /* lvalue, offset on stack */
+#define VT_LOCAL     0x00f2  /* offset on stack */
+#define VT_CMP       0x00f3  /* the value is stored in processor flags (in vc) */
+#define VT_JMP       0x00f4  /* value is the consequence of jmp true (even) */
+#define VT_JMPI      0x00f5  /* value is the consequence of jmp false (odd) */
+#define VT_LVAL      0x0100  /* var is an lvalue */
+#define VT_SYM       0x0200  /* a symbol value is added */
+#define VT_MUSTCAST  0x0400  /* value must be casted to be correct (used for
+                                char/short stored in integer registers) */
+#define VT_MUSTBOUND 0x0800  /* bound checking must be done before
+                                dereferencing value */
+#define VT_BOUNDED   0x8000  /* value is bounded. The address of the
+                                bounding function call point is in vc */
+#define VT_LVAL_BYTE     0x1000  /* lvalue is a byte */
+#define VT_LVAL_SHORT    0x2000  /* lvalue is a short */
+#define VT_LVAL_UNSIGNED 0x4000  /* lvalue is unsigned */
+#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
+
+/* types */
+#define VT_INT        0  /* integer type */
+#define VT_BYTE       1  /* signed byte type */
+#define VT_SHORT      2  /* short type */
+#define VT_VOID       3  /* void type */
+#define VT_PTR        4  /* pointer */
+#define VT_ENUM       5  /* enum definition */
+#define VT_FUNC       6  /* function type */
+#define VT_STRUCT     7  /* struct/union definition */
+#define VT_FLOAT      8  /* IEEE float */
+#define VT_DOUBLE     9  /* IEEE double */
+#define VT_LDOUBLE   10  /* IEEE long double */
+#define VT_BOOL      11  /* ISOC99 boolean type */
+#define VT_LLONG     12  /* 64 bit integer */
+#define VT_LONG      13  /* long integer (NEVER USED as type, only
+                            during parsing) */
+#define VT_BTYPE      0x000f /* mask for basic type */
+#define VT_UNSIGNED   0x0010  /* unsigned type */
+#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
+#define VT_BITFIELD   0x0040  /* bitfield modifier */
+#define VT_CONSTANT   0x0800  /* const modifier */
+#define VT_VOLATILE   0x1000  /* volatile modifier */
+#define VT_SIGNED     0x2000  /* signed type */
+
+/* storage */
+#define VT_EXTERN  0x00000080  /* extern definition */
+#define VT_STATIC  0x00000100  /* static variable */
+#define VT_TYPEDEF 0x00000200  /* typedef definition */
+#define VT_INLINE  0x00000400  /* inline definition */
+
+#define VT_STRUCT_SHIFT 16   /* shift for bitfield shift values */
+
+/* type mask (except storage) */
+#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
+#define VT_TYPE    (~(VT_STORAGE))
+
+/* token values */
+
+/* warning: the following compare tokens depend on i386 asm code */
+#define TOK_ULT 0x92
+#define TOK_UGE 0x93
+#define TOK_EQ  0x94
+#define TOK_NE  0x95
+#define TOK_ULE 0x96
+#define TOK_UGT 0x97
+#define TOK_Nset 0x98
+#define TOK_Nclear 0x99
+#define TOK_LT  0x9c
+#define TOK_GE  0x9d
+#define TOK_LE  0x9e
+#define TOK_GT  0x9f
+
+#define TOK_LAND  0xa0
+#define TOK_LOR   0xa1
+
+#define TOK_DEC   0xa2
+#define TOK_MID   0xa3 /* inc/dec, to void constant */
+#define TOK_INC   0xa4
+#define TOK_UDIV  0xb0 /* unsigned division */
+#define TOK_UMOD  0xb1 /* unsigned modulo */
+#define TOK_PDIV  0xb2 /* fast division with undefined rounding for pointers */
+#define TOK_CINT   0xb3 /* number in tokc */
+#define TOK_CCHAR 0xb4 /* char constant in tokc */
+#define TOK_STR   0xb5 /* pointer to string in tokc */
+#define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
+#define TOK_LCHAR    0xb7
+#define TOK_LSTR     0xb8
+#define TOK_CFLOAT   0xb9 /* float constant */
+#define TOK_LINENUM  0xba /* line number info */
+#define TOK_CDOUBLE  0xc0 /* double constant */
+#define TOK_CLDOUBLE 0xc1 /* long double constant */
+#define TOK_UMULL    0xc2 /* unsigned 32x32 -> 64 mul */
+#define TOK_ADDC1    0xc3 /* add with carry generation */
+#define TOK_ADDC2    0xc4 /* add with carry use */
+#define TOK_SUBC1    0xc5 /* add with carry generation */
+#define TOK_SUBC2    0xc6 /* add with carry use */
+#define TOK_CUINT    0xc8 /* unsigned int constant */
+#define TOK_CLLONG   0xc9 /* long long constant */
+#define TOK_CULLONG  0xca /* unsigned long long constant */
+#define TOK_ARROW    0xcb
+#define TOK_DOTS     0xcc /* three dots */
+#define TOK_SHR      0xcd /* unsigned shift right */
+#define TOK_PPNUM    0xce /* preprocessor number */
+
+#define TOK_SHL   0x01 /* shift left */
+#define TOK_SAR   0x02 /* signed shift right */
+  
+/* assignement operators : normal operator or 0x80 */
+#define TOK_A_MOD 0xa5
+#define TOK_A_AND 0xa6
+#define TOK_A_MUL 0xaa
+#define TOK_A_ADD 0xab
+#define TOK_A_SUB 0xad
+#define TOK_A_DIV 0xaf
+#define TOK_A_XOR 0xde
+#define TOK_A_OR  0xfc
+#define TOK_A_SHL 0x81
+#define TOK_A_SAR 0x82
+
+#ifndef offsetof
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+#endif
+
+#ifndef countof
+#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
+#endif
+
+#define TOK_EOF       (-1)  /* end of file */
+#define TOK_LINEFEED  10    /* line feed */
+
+/* all identificators and strings have token above that */
+#define TOK_IDENT 256
+
+/* only used for i386 asm opcodes definitions */
+#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
+
+#define DEF_BWL(x) \
+ DEF(TOK_ASM_ ## x ## b, #x "b") \
+ DEF(TOK_ASM_ ## x ## w, #x "w") \
+ DEF(TOK_ASM_ ## x ## l, #x "l") \
+ DEF(TOK_ASM_ ## x, #x)
+
+#define DEF_WL(x) \
+ DEF(TOK_ASM_ ## x ## w, #x "w") \
+ DEF(TOK_ASM_ ## x ## l, #x "l") \
+ DEF(TOK_ASM_ ## x, #x)
+
+#define DEF_FP1(x) \
+ DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \
+ DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \
+ DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \
+ DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s")
+
+#define DEF_FP(x) \
+ DEF(TOK_ASM_ ## f ## x, "f" #x ) \
+ DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \
+ DEF_FP1(x)
+
+#define DEF_ASMTEST(x) \
+ DEF_ASM(x ## o) \
+ DEF_ASM(x ## no) \
+ DEF_ASM(x ## b) \
+ DEF_ASM(x ## c) \
+ DEF_ASM(x ## nae) \
+ DEF_ASM(x ## nb) \
+ DEF_ASM(x ## nc) \
+ DEF_ASM(x ## ae) \
+ DEF_ASM(x ## e) \
+ DEF_ASM(x ## z) \
+ DEF_ASM(x ## ne) \
+ DEF_ASM(x ## nz) \
+ DEF_ASM(x ## be) \
+ DEF_ASM(x ## na) \
+ DEF_ASM(x ## nbe) \
+ DEF_ASM(x ## a) \
+ DEF_ASM(x ## s) \
+ DEF_ASM(x ## ns) \
+ DEF_ASM(x ## p) \
+ DEF_ASM(x ## pe) \
+ DEF_ASM(x ## np) \
+ DEF_ASM(x ## po) \
+ DEF_ASM(x ## l) \
+ DEF_ASM(x ## nge) \
+ DEF_ASM(x ## nl) \
+ DEF_ASM(x ## ge) \
+ DEF_ASM(x ## le) \
+ DEF_ASM(x ## ng) \
+ DEF_ASM(x ## nle) \
+ DEF_ASM(x ## g)
+
+#define TOK_ASM_int TOK_INT
+
+enum tcc_token {
+    TOK_LAST = TOK_IDENT - 1,
+#define DEF(id, str) id,
+#include "tcctok.h"
+#undef DEF
+};
+
+#define TOK_UIDENT TOK_DEFINE
+
+#ifdef _WIN32
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#ifndef __GNUC__
+  #define strtold (long double)strtod
+  #define strtof (float)strtod
+  #define strtoll (long long)strtol
+#endif
+#elif defined(TCC_UCLIBC) || defined(__FreeBSD__) || defined(__DragonFly__) \
+    || defined(__OpenBSD__)
+/* currently incorrect */
+long double strtold(const char *nptr, char **endptr)
+{
+    return (long double)strtod(nptr, endptr);
+}
+float strtof(const char *nptr, char **endptr)
+{
+    return (float)strtod(nptr, endptr);
+}
+#else
+/* XXX: need to define this to use them in non ISOC99 context */
+extern float strtof (const char *__nptr, char **__endptr);
+extern long double strtold (const char *__nptr, char **__endptr);
+#endif
+
+#ifdef _WIN32
+#define IS_PATHSEP(c) (c == '/' || c == '\\')
+#define IS_ABSPATH(p) (IS_PATHSEP(p[0]) || (p[0] && p[1] == ':' && IS_PATHSEP(p[2])))
+#define PATHCMP stricmp
+#else
+#define IS_PATHSEP(c) (c == '/')
+#define IS_ABSPATH(p) IS_PATHSEP(p[0])
+#define PATHCMP strcmp
+#endif
+
+void error(const char *fmt, ...);
+void error_noabort(const char *fmt, ...);
+void warning(const char *fmt, ...);
+
+void tcc_set_lib_path_w32(TCCState *s);
+int tcc_set_flag(TCCState *s, const char *flag_name, int value);
+void tcc_print_stats(TCCState *s, int64_t total_time);
+
+void tcc_free(void *ptr);
+void *tcc_malloc(unsigned long size);
+void *tcc_mallocz(unsigned long size);
+void *tcc_realloc(void *ptr, unsigned long size);
+char *tcc_strdup(const char *str);
+
+char *tcc_basename(const char *name);
+char *tcc_fileextension (const char *name);
+char *pstrcpy(char *buf, int buf_size, const char *s);
+char *pstrcat(char *buf, int buf_size, const char *s);
+void dynarray_add(void ***ptab, int *nb_ptr, void *data);
+void dynarray_reset(void *pp, int *n);
+
+#ifdef CONFIG_TCC_BACKTRACE
+extern int num_callers;
+extern const char **rt_bound_error_msg;
+#endif
+
+/* true if float/double/long double type */
+static inline int is_float(int t)
+{
+    int bt;
+    bt = t & VT_BTYPE;
+    return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT;
+}
+
+/* space exlcuding newline */
+static inline int is_space(int ch)
+{
+    return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r';
+}
+
diff --git a/tinyc/tccasm.c b/tinyc/tccasm.c
new file mode 100644
index 000000000..9b5289f77
--- /dev/null
+++ b/tinyc/tccasm.c
@@ -0,0 +1,1021 @@
+/*
+ *  GAS like assembler for TCC
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+static int asm_get_local_label_name(TCCState *s1, unsigned int n)
+{
+    char buf[64];
+    TokenSym *ts;
+
+    snprintf(buf, sizeof(buf), "L..%u", n);
+    ts = tok_alloc(buf, strlen(buf));
+    return ts->tok;
+}
+
+static void asm_expr(TCCState *s1, ExprValue *pe);
+
+/* We do not use the C expression parser to handle symbols. Maybe the
+   C expression parser could be tweaked to do so. */
+
+static void asm_expr_unary(TCCState *s1, ExprValue *pe)
+{
+    Sym *sym;
+    int op, n, label;
+    const char *p;
+
+    switch(tok) {
+    case TOK_PPNUM:
+        p = tokc.cstr->data;
+        n = strtoul(p, (char **)&p, 0);
+        if (*p == 'b' || *p == 'f') {
+            /* backward or forward label */
+            label = asm_get_local_label_name(s1, n);
+            sym = label_find(label);
+            if (*p == 'b') {
+                /* backward : find the last corresponding defined label */
+                if (sym && sym->r == 0)
+                    sym = sym->prev_tok;
+                if (!sym)
+                    error("local label '%d' not found backward", n);
+            } else {
+                /* forward */
+                if (!sym || sym->r) {
+                    /* if the last label is defined, then define a new one */
+                    sym = label_push(&s1->asm_labels, label, 0);
+                    sym->type.t = VT_STATIC | VT_VOID;
+                }
+            }
+            pe->v = 0;
+            pe->sym = sym;
+        } else if (*p == '\0') {
+            pe->v = n;
+            pe->sym = NULL;
+        } else {
+            error("invalid number syntax");
+        }
+        next();
+        break;
+    case '+':
+        next();
+        asm_expr_unary(s1, pe);
+        break;
+    case '-':
+    case '~':
+        op = tok;
+        next();
+        asm_expr_unary(s1, pe);
+        if (pe->sym)
+            error("invalid operation with label");
+        if (op == '-')
+            pe->v = -pe->v;
+        else
+            pe->v = ~pe->v;
+        break;
+    case TOK_CCHAR:
+    case TOK_LCHAR:
+	pe->v = tokc.i;
+	pe->sym = NULL;
+	next();
+	break;
+    case '(':
+        next();
+        asm_expr(s1, pe);
+        skip(')');
+        break;
+    default:
+        if (tok >= TOK_IDENT) {
+            /* label case : if the label was not found, add one */
+            sym = label_find(tok);
+            if (!sym) {
+                sym = label_push(&s1->asm_labels, tok, 0);
+                /* NOTE: by default, the symbol is global */
+                sym->type.t = VT_VOID;
+            }
+            if (sym->r == SHN_ABS) {
+                /* if absolute symbol, no need to put a symbol value */
+                pe->v = (long)sym->next;
+                pe->sym = NULL;
+            } else {
+                pe->v = 0;
+                pe->sym = sym;
+            }
+            next();
+        } else {
+            error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
+        }
+        break;
+    }
+}
+    
+static void asm_expr_prod(TCCState *s1, ExprValue *pe)
+{
+    int op;
+    ExprValue e2;
+
+    asm_expr_unary(s1, pe);
+    for(;;) {
+        op = tok;
+        if (op != '*' && op != '/' && op != '%' && 
+            op != TOK_SHL && op != TOK_SAR)
+            break;
+        next();
+        asm_expr_unary(s1, &e2);
+        if (pe->sym || e2.sym)
+            error("invalid operation with label");
+        switch(op) {
+        case '*':
+            pe->v *= e2.v;
+            break;
+        case '/':  
+            if (e2.v == 0) {
+            div_error:
+                error("division by zero");
+            }
+            pe->v /= e2.v;
+            break;
+        case '%':  
+            if (e2.v == 0)
+                goto div_error;
+            pe->v %= e2.v;
+            break;
+        case TOK_SHL:
+            pe->v <<= e2.v;
+            break;
+        default:
+        case TOK_SAR:
+            pe->v >>= e2.v;
+            break;
+        }
+    }
+}
+
+static void asm_expr_logic(TCCState *s1, ExprValue *pe)
+{
+    int op;
+    ExprValue e2;
+
+    asm_expr_prod(s1, pe);
+    for(;;) {
+        op = tok;
+        if (op != '&' && op != '|' && op != '^')
+            break;
+        next();
+        asm_expr_prod(s1, &e2);
+        if (pe->sym || e2.sym)
+            error("invalid operation with label");
+        switch(op) {
+        case '&':
+            pe->v &= e2.v;
+            break;
+        case '|':  
+            pe->v |= e2.v;
+            break;
+        default:
+        case '^':
+            pe->v ^= e2.v;
+            break;
+        }
+    }
+}
+
+static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
+{
+    int op;
+    ExprValue e2;
+
+    asm_expr_logic(s1, pe);
+    for(;;) {
+        op = tok;
+        if (op != '+' && op != '-')
+            break;
+        next();
+        asm_expr_logic(s1, &e2);
+        if (op == '+') {
+            if (pe->sym != NULL && e2.sym != NULL)
+                goto cannot_relocate;
+            pe->v += e2.v;
+            if (pe->sym == NULL && e2.sym != NULL)
+                pe->sym = e2.sym;
+        } else {
+            pe->v -= e2.v;
+            /* NOTE: we are less powerful than gas in that case
+               because we store only one symbol in the expression */
+            if (!pe->sym && !e2.sym) {
+                /* OK */
+            } else if (pe->sym && !e2.sym) {
+                /* OK */
+            } else if (pe->sym && e2.sym) {
+                if (pe->sym == e2.sym) { 
+                    /* OK */
+                } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
+                    /* we also accept defined symbols in the same section */
+                    pe->v += (long)pe->sym->next - (long)e2.sym->next;
+                } else {
+                    goto cannot_relocate;
+                }
+                pe->sym = NULL; /* same symbols can be subtracted to NULL */
+            } else {
+            cannot_relocate:
+                error("invalid operation with label");
+            }
+        }
+    }
+}
+
+static void asm_expr(TCCState *s1, ExprValue *pe)
+{
+    asm_expr_sum(s1, pe);
+}
+
+static int asm_int_expr(TCCState *s1)
+{
+    ExprValue e;
+    asm_expr(s1, &e);
+    if (e.sym)
+        expect("constant");
+    return e.v;
+}
+
+/* NOTE: the same name space as C labels is used to avoid using too
+   much memory when storing labels in TokenStrings */
+static void asm_new_label1(TCCState *s1, int label, int is_local,
+                           int sh_num, int value)
+{
+    Sym *sym;
+
+    sym = label_find(label);
+    if (sym) {
+        if (sym->r) {
+            /* the label is already defined */
+            if (!is_local) {
+                error("assembler label '%s' already defined", 
+                      get_tok_str(label, NULL));
+            } else {
+                /* redefinition of local labels is possible */
+                goto new_label;
+            }
+        }
+    } else {
+    new_label:
+        sym = label_push(&s1->asm_labels, label, 0);
+        sym->type.t = VT_STATIC | VT_VOID;
+    }
+    sym->r = sh_num;
+    sym->next = (void *)value;
+}
+
+static void asm_new_label(TCCState *s1, int label, int is_local)
+{
+    asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
+}
+
+static void asm_free_labels(TCCState *st)
+{
+    Sym *s, *s1;
+    Section *sec;
+    
+    for(s = st->asm_labels; s != NULL; s = s1) {
+        s1 = s->prev;
+        /* define symbol value in object file */
+        if (s->r) {
+            if (s->r == SHN_ABS)
+                sec = SECTION_ABS;
+            else
+                sec = st->sections[s->r];
+            put_extern_sym2(s, sec, (long)s->next, 0, 0);
+        }
+        /* remove label */
+        table_ident[s->v - TOK_IDENT]->sym_label = NULL;
+        sym_free(s);
+    }
+    st->asm_labels = NULL;
+}
+
+static void use_section1(TCCState *s1, Section *sec)
+{
+    cur_text_section->data_offset = ind;
+    cur_text_section = sec;
+    ind = cur_text_section->data_offset;
+}
+
+static void use_section(TCCState *s1, const char *name)
+{
+    Section *sec;
+    sec = find_section(s1, name);
+    use_section1(s1, sec);
+}
+
+static void asm_parse_directive(TCCState *s1)
+{
+    int n, offset, v, size, tok1;
+    Section *sec;
+    uint8_t *ptr;
+
+    /* assembler directive */
+    next();
+    sec = cur_text_section;
+    switch(tok) {
+    case TOK_ASM_align:
+    case TOK_ASM_skip:
+    case TOK_ASM_space:
+        tok1 = tok;
+        next();
+        n = asm_int_expr(s1);
+        if (tok1 == TOK_ASM_align) {
+            if (n < 0 || (n & (n-1)) != 0)
+                error("alignment must be a positive power of two");
+            offset = (ind + n - 1) & -n;
+            size = offset - ind;
+            /* the section must have a compatible alignment */
+            if (sec->sh_addralign < n)
+                sec->sh_addralign = n;
+        } else {
+            size = n;
+        }
+        v = 0;
+        if (tok == ',') {
+            next();
+            v = asm_int_expr(s1);
+        }
+    zero_pad:
+        if (sec->sh_type != SHT_NOBITS) {
+            sec->data_offset = ind;
+            ptr = section_ptr_add(sec, size);
+            memset(ptr, v, size);
+        }
+        ind += size;
+        break;
+    case TOK_ASM_quad:
+        next();
+        for(;;) {
+            uint64_t vl;
+            const char *p;
+
+            p = tokc.cstr->data;
+            if (tok != TOK_PPNUM) {
+            error_constant:
+                error("64 bit constant");
+            }
+            vl = strtoll(p, (char **)&p, 0);
+            if (*p != '\0')
+                goto error_constant;
+            next();
+            if (sec->sh_type != SHT_NOBITS) {
+                /* XXX: endianness */
+                gen_le32(vl);
+                gen_le32(vl >> 32);
+            } else {
+                ind += 8;
+            }
+            if (tok != ',')
+                break;
+            next();
+        }
+        break;
+    case TOK_ASM_byte:
+        size = 1;
+        goto asm_data;
+    case TOK_ASM_word:
+    case TOK_SHORT:
+        size = 2;
+        goto asm_data;
+    case TOK_LONG:
+    case TOK_INT:
+        size = 4;
+    asm_data:
+        next();
+        for(;;) {
+            ExprValue e;
+            asm_expr(s1, &e);
+            if (sec->sh_type != SHT_NOBITS) {
+                if (size == 4) {
+                    gen_expr32(&e);
+                } else {
+                    if (e.sym)
+                        expect("constant");
+                    if (size == 1)
+                        g(e.v);
+                    else
+                        gen_le16(e.v);
+                }
+            } else {
+                ind += size;
+            }
+            if (tok != ',')
+                break;
+            next();
+        }
+        break;
+    case TOK_ASM_fill:
+        {
+            int repeat, size, val, i, j;
+            uint8_t repeat_buf[8];
+            next();
+            repeat = asm_int_expr(s1);
+            if (repeat < 0) {
+                error("repeat < 0; .fill ignored");
+                break;
+            }
+            size = 1;
+            val = 0;
+            if (tok == ',') {
+                next();
+                size = asm_int_expr(s1);
+                if (size < 0) {
+                    error("size < 0; .fill ignored");
+                    break;
+                }
+                if (size > 8)
+                    size = 8;
+                if (tok == ',') {
+                    next();
+                    val = asm_int_expr(s1);
+                }
+            }
+            /* XXX: endianness */
+            repeat_buf[0] = val;
+            repeat_buf[1] = val >> 8;
+            repeat_buf[2] = val >> 16;
+            repeat_buf[3] = val >> 24;
+            repeat_buf[4] = 0;
+            repeat_buf[5] = 0;
+            repeat_buf[6] = 0;
+            repeat_buf[7] = 0;
+            for(i = 0; i < repeat; i++) {
+                for(j = 0; j < size; j++) {
+                    g(repeat_buf[j]);
+                }
+            }
+        }
+        break;
+    case TOK_ASM_org:
+        {
+            unsigned long n;
+            next();
+            /* XXX: handle section symbols too */
+            n = asm_int_expr(s1);
+            if (n < ind)
+                error("attempt to .org backwards");
+            v = 0;
+            size = n - ind;
+            goto zero_pad;
+        }
+        break;
+    case TOK_ASM_globl:
+    case TOK_ASM_global:
+	{ 
+            Sym *sym;
+
+            next();
+            sym = label_find(tok);
+            if (!sym) {
+                sym = label_push(&s1->asm_labels, tok, 0);
+                sym->type.t = VT_VOID;
+            }
+            sym->type.t &= ~VT_STATIC;
+            next();
+	}
+	break;
+    case TOK_ASM_string:
+    case TOK_ASM_ascii:
+    case TOK_ASM_asciz:
+        {
+            const uint8_t *p;
+            int i, size, t;
+
+            t = tok;
+            next();
+            for(;;) {
+                if (tok != TOK_STR)
+                    expect("string constant");
+                p = tokc.cstr->data;
+                size = tokc.cstr->size;
+                if (t == TOK_ASM_ascii && size > 0)
+                    size--;
+                for(i = 0; i < size; i++)
+                    g(p[i]);
+                next();
+                if (tok == ',') {
+                    next();
+                } else if (tok != TOK_STR) {
+                    break;
+                }
+            }
+	}
+	break;
+    case TOK_ASM_text:
+    case TOK_ASM_data:
+    case TOK_ASM_bss:
+	{ 
+            char sname[64];
+            tok1 = tok;
+            n = 0;
+            next();
+            if (tok != ';' && tok != TOK_LINEFEED) {
+		n = asm_int_expr(s1);
+		next();
+            }
+            sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n);
+            use_section(s1, sname);
+	}
+	break;
+    case TOK_SECTION1:
+        {
+            char sname[256];
+
+            /* XXX: support more options */
+            next();
+            sname[0] = '\0';
+            while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
+                if (tok == TOK_STR)
+                    pstrcat(sname, sizeof(sname), tokc.cstr->data);
+                else
+                    pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
+                next();
+            }
+            if (tok == ',') {
+                /* skip section options */
+                next();
+                if (tok != TOK_STR)
+                    expect("string constant");
+                next();
+            }
+            last_text_section = cur_text_section;
+            use_section(s1, sname);
+        }
+        break;
+    case TOK_ASM_previous:
+        { 
+            Section *sec;
+            next();
+            if (!last_text_section)
+                error("no previous section referenced");
+            sec = cur_text_section;
+            use_section1(s1, last_text_section);
+            last_text_section = sec;
+        }
+        break;
+    default:
+        error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
+        break;
+    }
+}
+
+
+/* assemble a file */
+static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
+{
+    int opcode;
+
+#if 0
+    /* print stats about opcodes */
+    {
+        const ASMInstr *pa;
+        int freq[4];
+        int op_vals[500];
+        int nb_op_vals, i, j;
+
+        nb_op_vals = 0;
+        memset(freq, 0, sizeof(freq));
+        for(pa = asm_instrs; pa->sym != 0; pa++) {
+            freq[pa->nb_ops]++;
+            for(i=0;i<pa->nb_ops;i++) {
+                for(j=0;j<nb_op_vals;j++) {
+                    if (pa->op_type[i] == op_vals[j])
+                        goto found;
+                }
+                op_vals[nb_op_vals++] = pa->op_type[i];
+            found: ;
+            }
+        }
+        for(i=0;i<nb_op_vals;i++) {
+            int v = op_vals[i];
+            if ((v & (v - 1)) != 0)
+                printf("%3d: %08x\n", i, v);
+        }
+        printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
+               sizeof(asm_instrs), sizeof(asm_instrs) / sizeof(ASMInstr),
+               freq[0], freq[1], freq[2], freq[3]);
+    }
+#endif
+
+    /* XXX: undefine C labels */
+
+    ch = file->buf_ptr[0];
+    tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
+    parse_flags = PARSE_FLAG_ASM_COMMENTS;
+    if (do_preprocess)
+        parse_flags |= PARSE_FLAG_PREPROCESS;
+    next();
+    for(;;) {
+        if (tok == TOK_EOF)
+            break;
+        parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
+    redo:
+        if (tok == '#') {
+            /* horrible gas comment */
+            while (tok != TOK_LINEFEED)
+                next();
+        } else if (tok == '.') {
+            asm_parse_directive(s1);
+        } else if (tok == TOK_PPNUM) {
+            const char *p;
+            int n;
+            p = tokc.cstr->data;
+            n = strtoul(p, (char **)&p, 10);
+            if (*p != '\0')
+                expect("':'");
+            /* new local label */
+            asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
+            next();
+            skip(':');
+            goto redo;
+        } else if (tok >= TOK_IDENT) {
+            /* instruction or label */
+            opcode = tok;
+            next();
+            if (tok == ':') {
+                /* new label */
+                asm_new_label(s1, opcode, 0);
+                next();
+                goto redo;
+            } else if (tok == '=') {
+                int n;
+                next();
+                n = asm_int_expr(s1);
+                asm_new_label1(s1, opcode, 0, SHN_ABS, n);
+                goto redo;
+            } else {
+                asm_opcode(s1, opcode);
+            }
+        }
+        /* end of line */
+        if (tok != ';' && tok != TOK_LINEFEED){
+            expect("end of line");
+        }
+        parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
+        next();
+    }
+
+    asm_free_labels(s1);
+
+    return 0;
+}
+
+/* Assemble the current file */
+static int tcc_assemble(TCCState *s1, int do_preprocess)
+{
+    Sym *define_start;
+    int ret;
+
+    preprocess_init(s1);
+
+    /* default section is text */
+    cur_text_section = text_section;
+    ind = cur_text_section->data_offset;
+
+    define_start = define_stack;
+
+    ret = tcc_assemble_internal(s1, do_preprocess);
+
+    cur_text_section->data_offset = ind;
+
+    free_defines(define_start); 
+
+    return ret;
+}
+
+/********************************************************************/
+/* GCC inline asm support */
+
+/* assemble the string 'str' in the current C compilation unit without
+   C preprocessing. NOTE: str is modified by modifying the '\0' at the
+   end */
+static void tcc_assemble_inline(TCCState *s1, char *str, int len)
+{
+    BufferedFile *bf, *saved_file;
+    int saved_parse_flags, *saved_macro_ptr;
+
+    bf = tcc_malloc(sizeof(BufferedFile));
+    memset(bf, 0, sizeof(BufferedFile));
+    bf->fd = -1;
+    bf->buf_ptr = str;
+    bf->buf_end = str + len;
+    str[len] = CH_EOB;
+    /* same name as current file so that errors are correctly
+       reported */
+    pstrcpy(bf->filename, sizeof(bf->filename), file->filename);
+    bf->line_num = file->line_num;
+    saved_file = file;
+    file = bf;
+    saved_parse_flags = parse_flags;
+    saved_macro_ptr = macro_ptr;
+    macro_ptr = NULL;
+    
+    tcc_assemble_internal(s1, 0);
+
+    parse_flags = saved_parse_flags;
+    macro_ptr = saved_macro_ptr;
+    file = saved_file;
+    tcc_free(bf);
+}
+
+/* find a constraint by its number or id (gcc 3 extended
+   syntax). return -1 if not found. Return in *pp in char after the
+   constraint */
+static int find_constraint(ASMOperand *operands, int nb_operands, 
+                           const char *name, const char **pp)
+{
+    int index;
+    TokenSym *ts;
+    const char *p;
+
+    if (isnum(*name)) {
+        index = 0;
+        while (isnum(*name)) {
+            index = (index * 10) + (*name) - '0';
+            name++;
+        }
+        if ((unsigned)index >= nb_operands)
+            index = -1;
+    } else if (*name == '[') {
+        name++;
+        p = strchr(name, ']');
+        if (p) {
+            ts = tok_alloc(name, p - name);
+            for(index = 0; index < nb_operands; index++) {
+                if (operands[index].id == ts->tok)
+                    goto found;
+            }
+            index = -1;
+        found:
+            name = p + 1;
+        } else {
+            index = -1;
+        }
+    } else {
+        index = -1;
+    }
+    if (pp)
+        *pp = name;
+    return index;
+}
+
+static void subst_asm_operands(ASMOperand *operands, int nb_operands, 
+                               int nb_outputs,
+                               CString *out_str, CString *in_str)
+{
+    int c, index, modifier;
+    const char *str;
+    ASMOperand *op;
+    SValue sv;
+
+    cstr_new(out_str);
+    str = in_str->data;
+    for(;;) {
+        c = *str++;
+        if (c == '%') {
+            if (*str == '%') {
+                str++;
+                goto add_char;
+            }
+            modifier = 0;
+            if (*str == 'c' || *str == 'n' ||
+                *str == 'b' || *str == 'w' || *str == 'h')
+                modifier = *str++;
+            index = find_constraint(operands, nb_operands, str, &str);
+            if (index < 0)
+                error("invalid operand reference after %%");
+            op = &operands[index];
+            sv = *op->vt;
+            if (op->reg >= 0) {
+                sv.r = op->reg;
+                if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
+                    sv.r |= VT_LVAL;
+            }
+            subst_asm_operand(out_str, &sv, modifier);
+        } else {
+        add_char:
+            cstr_ccat(out_str, c);
+            if (c == '\0')
+                break;
+        }
+    }
+}
+
+
+static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
+                               int is_output)
+{
+    ASMOperand *op;
+    int nb_operands;
+
+    if (tok != ':') {
+        nb_operands = *nb_operands_ptr;
+        for(;;) {
+            if (nb_operands >= MAX_ASM_OPERANDS)
+                error("too many asm operands");
+            op = &operands[nb_operands++];
+            op->id = 0;
+            if (tok == '[') {
+                next();
+                if (tok < TOK_IDENT)
+                    expect("identifier");
+                op->id = tok;
+                next();
+                skip(']');
+            }
+            if (tok != TOK_STR)
+                expect("string constant");
+            op->constraint = tcc_malloc(tokc.cstr->size);
+            strcpy(op->constraint, tokc.cstr->data);
+            next();
+            skip('(');
+            gexpr();
+            if (is_output) {
+                test_lvalue();
+            } else {
+                /* we want to avoid LLOCAL case, except when the 'm'
+                   constraint is used. Note that it may come from
+                   register storage, so we need to convert (reg)
+                   case */
+                if ((vtop->r & VT_LVAL) &&
+                    ((vtop->r & VT_VALMASK) == VT_LLOCAL ||
+                     (vtop->r & VT_VALMASK) < VT_CONST) &&
+                    !strchr(op->constraint, 'm')) {
+                    gv(RC_INT);
+                }
+            }
+            op->vt = vtop;
+            skip(')');
+            if (tok == ',') {
+                next();
+            } else {
+                break;
+            }
+        }
+        *nb_operands_ptr = nb_operands;
+    }
+}
+
+static void parse_asm_str(CString *astr)
+{
+    skip('(');
+    /* read the string */
+    if (tok != TOK_STR)
+        expect("string constant");
+    cstr_new(astr);
+    while (tok == TOK_STR) {
+        /* XXX: add \0 handling too ? */
+        cstr_cat(astr, tokc.cstr->data);
+        next();
+    }
+    cstr_ccat(astr, '\0');
+}
+
+/* parse the GCC asm() instruction */
+static void asm_instr(void)
+{
+    CString astr, astr1;
+    ASMOperand operands[MAX_ASM_OPERANDS];
+    int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg;
+    uint8_t clobber_regs[NB_ASM_REGS];
+
+    next();
+    /* since we always generate the asm() instruction, we can ignore
+       volatile */
+    if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
+        next();
+    }
+    parse_asm_str(&astr);
+    nb_operands = 0;
+    nb_outputs = 0;
+    must_subst = 0;
+    memset(clobber_regs, 0, sizeof(clobber_regs));
+    if (tok == ':') {
+        next();
+        must_subst = 1;
+        /* output args */
+        parse_asm_operands(operands, &nb_operands, 1);
+        nb_outputs = nb_operands;
+        if (tok == ':') {
+            next();
+            if (tok != ')') {
+                /* input args */
+                parse_asm_operands(operands, &nb_operands, 0);
+                if (tok == ':') {
+                    /* clobber list */
+                    /* XXX: handle registers */
+                    next();
+                    for(;;) {
+                        if (tok != TOK_STR)
+                            expect("string constant");
+                        asm_clobber(clobber_regs, tokc.cstr->data);
+                        next();
+                        if (tok == ',') {
+                            next();
+                        } else {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    skip(')');
+    /* NOTE: we do not eat the ';' so that we can restore the current
+       token after the assembler parsing */
+    if (tok != ';')
+        expect("';'");
+    nb_inputs = nb_operands - nb_outputs;
+    
+    /* save all values in the memory */
+    save_regs(0);
+
+    /* compute constraints */
+    asm_compute_constraints(operands, nb_operands, nb_outputs, 
+                            clobber_regs, &out_reg);
+
+    /* substitute the operands in the asm string. No substitution is
+       done if no operands (GCC behaviour) */
+#ifdef ASM_DEBUG
+    printf("asm: \"%s\"\n", (char *)astr.data);
+#endif
+    if (must_subst) {
+        subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
+        cstr_free(&astr);
+    } else {
+        astr1 = astr;
+    }
+#ifdef ASM_DEBUG
+    printf("subst_asm: \"%s\"\n", (char *)astr1.data);
+#endif
+
+    /* generate loads */
+    asm_gen_code(operands, nb_operands, nb_outputs, 0, 
+                 clobber_regs, out_reg);    
+
+    /* assemble the string with tcc internal assembler */
+    tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
+
+    /* restore the current C token */
+    next();
+
+    /* store the output values if needed */
+    asm_gen_code(operands, nb_operands, nb_outputs, 1, 
+                 clobber_regs, out_reg);
+    
+    /* free everything */
+    for(i=0;i<nb_operands;i++) {
+        ASMOperand *op;
+        op = &operands[i];
+        tcc_free(op->constraint);
+        vpop();
+    }
+    cstr_free(&astr1);
+}
+
+static void asm_global_instr(void)
+{
+    CString astr;
+
+    next();
+    parse_asm_str(&astr);
+    skip(')');
+    /* NOTE: we do not eat the ';' so that we can restore the current
+       token after the assembler parsing */
+    if (tok != ';')
+        expect("';'");
+    
+#ifdef ASM_DEBUG
+    printf("asm_global: \"%s\"\n", (char *)astr.data);
+#endif
+    cur_text_section = text_section;
+    ind = cur_text_section->data_offset;
+
+    /* assemble the string with tcc internal assembler */
+    tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
+    
+    cur_text_section->data_offset = ind;
+
+    /* restore the current C token */
+    next();
+
+    cstr_free(&astr);
+}
diff --git a/tinyc/tcccoff.c b/tinyc/tcccoff.c
new file mode 100644
index 000000000..0dcbe50f0
--- /dev/null
+++ b/tinyc/tcccoff.c
@@ -0,0 +1,957 @@
+/*
+ *  COFF file handling for TCC
+ * 
+ *  Copyright (c) 2003, 2004 TK
+ *  Copyright (c) 2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+#include "coff.h"
+
+#define MAXNSCNS 255		/* MAXIMUM NUMBER OF SECTIONS         */
+#define MAX_STR_TABLE 1000000
+AOUTHDR o_filehdr;		/* OPTIONAL (A.OUT) FILE HEADER       */
+
+SCNHDR section_header[MAXNSCNS];
+
+#define MAX_FUNCS 1000
+#define MAX_FUNC_NAME_LENGTH 128
+
+int nFuncs;
+char Func[MAX_FUNCS][MAX_FUNC_NAME_LENGTH];
+char AssociatedFile[MAX_FUNCS][MAX_FUNC_NAME_LENGTH];
+int LineNoFilePtr[MAX_FUNCS];
+int EndAddress[MAX_FUNCS];
+int LastLineNo[MAX_FUNCS];
+int FuncEntries[MAX_FUNCS];
+
+BOOL OutputTheSection(Section * sect);
+short int GetCoffFlags(const char *s);
+void SortSymbolTable(void);
+Section *FindSection(TCCState * s1, const char *sname);
+
+int C67_main_entry_point;
+
+int FindCoffSymbolIndex(const char *func_name);
+int nb_syms;
+
+typedef struct {
+    long tag;
+    long size;
+    long fileptr;
+    long nextsym;
+    short int dummy;
+} AUXFUNC;
+
+typedef struct {
+    long regmask;
+    unsigned short lineno;
+    unsigned short nentries;
+    int localframe;
+    int nextentry;
+    short int dummy;
+} AUXBF;
+
+typedef struct {
+    long dummy;
+    unsigned short lineno;
+    unsigned short dummy1;
+    int dummy2;
+    int dummy3;
+    unsigned short dummy4;
+} AUXEF;
+
+int tcc_output_coff(TCCState *s1, FILE *f)
+{
+    Section *tcc_sect;
+    SCNHDR *coff_sec;
+    int file_pointer;
+    char *Coff_str_table, *pCoff_str_table;
+    int CoffTextSectionNo, coff_nb_syms;
+    FILHDR file_hdr;		/* FILE HEADER STRUCTURE              */
+    Section *stext, *sdata, *sbss;
+    int i, NSectionsToOutput = 0;
+
+    Coff_str_table = pCoff_str_table = NULL;
+
+    stext = FindSection(s1, ".text");
+    sdata = FindSection(s1, ".data");
+    sbss = FindSection(s1, ".bss");
+
+    nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
+    coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1");
+
+    file_hdr.f_magic = COFF_C67_MAGIC;	/* magic number */
+    file_hdr.f_timdat = 0;	/* time & date stamp */
+    file_hdr.f_opthdr = sizeof(AOUTHDR);	/* sizeof(optional hdr) */
+    file_hdr.f_flags = 0x1143;	/* flags (copied from what code composer does) */
+    file_hdr.f_TargetID = 0x99;	/* for C6x = 0x0099 */
+
+    o_filehdr.magic = 0x0108;	/* see magic.h                          */
+    o_filehdr.vstamp = 0x0190;	/* version stamp                        */
+    o_filehdr.tsize = stext->data_offset;	/* text size in bytes, padded to FW bdry */
+    o_filehdr.dsize = sdata->data_offset;	/* initialized data "  "                */
+    o_filehdr.bsize = sbss->data_offset;	/* uninitialized data "   "             */
+    o_filehdr.entrypt = C67_main_entry_point;	/* entry pt.                          */
+    o_filehdr.text_start = stext->sh_addr;	/* base of text used for this file      */
+    o_filehdr.data_start = sdata->sh_addr;	/* base of data used for this file      */
+
+
+    // create all the section headers
+
+    file_pointer = FILHSZ + sizeof(AOUTHDR);
+
+    CoffTextSectionNo = -1;
+
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (OutputTheSection(tcc_sect)) {
+	    NSectionsToOutput++;
+
+	    if (CoffTextSectionNo == -1 && tcc_sect == stext)
+		CoffTextSectionNo = NSectionsToOutput;	// rem which coff sect number the .text sect is
+
+	    strcpy(coff_sec->s_name, tcc_sect->name);	/* section name */
+
+	    coff_sec->s_paddr = tcc_sect->sh_addr;	/* physical address */
+	    coff_sec->s_vaddr = tcc_sect->sh_addr;	/* virtual address */
+	    coff_sec->s_size = tcc_sect->data_offset;	/* section size */
+	    coff_sec->s_scnptr = 0;	/* file ptr to raw data for section */
+	    coff_sec->s_relptr = 0;	/* file ptr to relocation */
+	    coff_sec->s_lnnoptr = 0;	/* file ptr to line numbers */
+	    coff_sec->s_nreloc = 0;	/* number of relocation entries */
+	    coff_sec->s_flags = GetCoffFlags(coff_sec->s_name);	/* flags */
+	    coff_sec->s_reserved = 0;	/* reserved byte */
+	    coff_sec->s_page = 0;	/* memory page id */
+
+	    file_pointer += sizeof(SCNHDR);
+	}
+    }
+
+    file_hdr.f_nscns = NSectionsToOutput;	/* number of sections */
+
+    // now loop through and determine file pointer locations
+    // for the raw data
+
+
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (OutputTheSection(tcc_sect)) {
+	    // put raw data
+	    coff_sec->s_scnptr = file_pointer;	/* file ptr to raw data for section */
+	    file_pointer += coff_sec->s_size;
+	}
+    }
+
+    // now loop through and determine file pointer locations
+    // for the relocation data
+
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (OutputTheSection(tcc_sect)) {
+	    // put relocations data
+	    if (coff_sec->s_nreloc > 0) {
+		coff_sec->s_relptr = file_pointer;	/* file ptr to relocation */
+		file_pointer += coff_sec->s_nreloc * sizeof(struct reloc);
+	    }
+	}
+    }
+
+    // now loop through and determine file pointer locations
+    // for the line number data
+
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	coff_sec->s_nlnno = 0;
+	coff_sec->s_lnnoptr = 0;
+
+	if (s1->do_debug && tcc_sect == stext) {
+	    // count how many line nos data
+
+	    // also find association between source file name and function
+	    // so we can sort the symbol table
+
+
+	    Stab_Sym *sym, *sym_end;
+	    char func_name[MAX_FUNC_NAME_LENGTH],
+		last_func_name[MAX_FUNC_NAME_LENGTH];
+	    unsigned long func_addr, last_pc, pc;
+	    const char *incl_files[INCLUDE_STACK_SIZE];
+	    int incl_index, len, last_line_num;
+	    const char *str, *p;
+
+	    coff_sec->s_lnnoptr = file_pointer;	/* file ptr to linno */
+
+
+	    func_name[0] = '\0';
+	    func_addr = 0;
+	    incl_index = 0;
+	    last_func_name[0] = '\0';
+	    last_pc = 0xffffffff;
+	    last_line_num = 1;
+	    sym = (Stab_Sym *) stab_section->data + 1;
+	    sym_end =
+		(Stab_Sym *) (stab_section->data +
+			      stab_section->data_offset);
+
+	    nFuncs = 0;
+	    while (sym < sym_end) {
+		switch (sym->n_type) {
+		    /* function start or end */
+		case N_FUN:
+		    if (sym->n_strx == 0) {
+			// end of function
+
+			coff_sec->s_nlnno++;
+			file_pointer += LINESZ;
+
+			pc = sym->n_value + func_addr;
+			func_name[0] = '\0';
+			func_addr = 0;
+			EndAddress[nFuncs] = pc;
+			FuncEntries[nFuncs] =
+			    (file_pointer -
+			     LineNoFilePtr[nFuncs]) / LINESZ - 1;
+			LastLineNo[nFuncs++] = last_line_num + 1;
+		    } else {
+			// beginning of function
+
+			LineNoFilePtr[nFuncs] = file_pointer;
+			coff_sec->s_nlnno++;
+			file_pointer += LINESZ;
+
+			str =
+			    (const char *) stabstr_section->data +
+			    sym->n_strx;
+
+			p = strchr(str, ':');
+			if (!p) {
+			    pstrcpy(func_name, sizeof(func_name), str);
+			    pstrcpy(Func[nFuncs], sizeof(func_name), str);
+			} else {
+			    len = p - str;
+			    if (len > sizeof(func_name) - 1)
+				len = sizeof(func_name) - 1;
+			    memcpy(func_name, str, len);
+			    memcpy(Func[nFuncs], str, len);
+			    func_name[len] = '\0';
+			}
+
+			// save the file that it came in so we can sort later
+			pstrcpy(AssociatedFile[nFuncs], sizeof(func_name),
+				incl_files[incl_index - 1]);
+
+			func_addr = sym->n_value;
+		    }
+		    break;
+
+		    /* line number info */
+		case N_SLINE:
+		    pc = sym->n_value + func_addr;
+
+		    last_pc = pc;
+		    last_line_num = sym->n_desc;
+
+		    /* XXX: slow! */
+		    strcpy(last_func_name, func_name);
+
+		    coff_sec->s_nlnno++;
+		    file_pointer += LINESZ;
+		    break;
+		    /* include files */
+		case N_BINCL:
+		    str =
+			(const char *) stabstr_section->data + sym->n_strx;
+		  add_incl:
+		    if (incl_index < INCLUDE_STACK_SIZE) {
+			incl_files[incl_index++] = str;
+		    }
+		    break;
+		case N_EINCL:
+		    if (incl_index > 1)
+			incl_index--;
+		    break;
+		case N_SO:
+		    if (sym->n_strx == 0) {
+			incl_index = 0;	/* end of translation unit */
+		    } else {
+			str =
+			    (const char *) stabstr_section->data +
+			    sym->n_strx;
+			/* do not add path */
+			len = strlen(str);
+			if (len > 0 && str[len - 1] != '/')
+			    goto add_incl;
+		    }
+		    break;
+		}
+		sym++;
+	    }
+	}
+
+    }
+
+    file_hdr.f_symptr = file_pointer;	/* file pointer to symtab */
+
+    if (s1->do_debug)
+	file_hdr.f_nsyms = coff_nb_syms;	/* number of symtab entries */
+    else
+	file_hdr.f_nsyms = 0;
+
+    file_pointer += file_hdr.f_nsyms * SYMNMLEN;
+
+    // OK now we are all set to write the file
+
+
+    fwrite(&file_hdr, FILHSZ, 1, f);
+    fwrite(&o_filehdr, sizeof(o_filehdr), 1, f);
+
+    // write section headers
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (OutputTheSection(tcc_sect)) {
+	    fwrite(coff_sec, sizeof(SCNHDR), 1, f);
+	}
+    }
+
+    // write raw data
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (OutputTheSection(tcc_sect)) {
+	    fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f);
+	}
+    }
+
+    // write relocation data
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (OutputTheSection(tcc_sect)) {
+	    // put relocations data
+	    if (coff_sec->s_nreloc > 0) {
+		fwrite(tcc_sect->reloc,
+		       coff_sec->s_nreloc * sizeof(struct reloc), 1, f);
+	    }
+	}
+    }
+
+
+    // group the symbols in order of filename, func1, func2, etc
+    // finally global symbols
+
+    if (s1->do_debug)
+	SortSymbolTable();
+
+    // write line no data
+
+    for (i = 1; i < s1->nb_sections; i++) {
+	coff_sec = &section_header[i];
+	tcc_sect = s1->sections[i];
+
+	if (s1->do_debug && tcc_sect == stext) {
+	    // count how many line nos data
+
+
+	    Stab_Sym *sym, *sym_end;
+	    char func_name[128], last_func_name[128];
+	    unsigned long func_addr, last_pc, pc;
+	    const char *incl_files[INCLUDE_STACK_SIZE];
+	    int incl_index, len, last_line_num;
+	    const char *str, *p;
+
+	    LINENO CoffLineNo;
+
+	    func_name[0] = '\0';
+	    func_addr = 0;
+	    incl_index = 0;
+	    last_func_name[0] = '\0';
+	    last_pc = 0;
+	    last_line_num = 1;
+	    sym = (Stab_Sym *) stab_section->data + 1;
+	    sym_end =
+		(Stab_Sym *) (stab_section->data +
+			      stab_section->data_offset);
+
+	    while (sym < sym_end) {
+		switch (sym->n_type) {
+		    /* function start or end */
+		case N_FUN:
+		    if (sym->n_strx == 0) {
+			// end of function
+
+			CoffLineNo.l_addr.l_paddr = last_pc;
+			CoffLineNo.l_lnno = last_line_num + 1;
+			fwrite(&CoffLineNo, 6, 1, f);
+
+			pc = sym->n_value + func_addr;
+			func_name[0] = '\0';
+			func_addr = 0;
+		    } else {
+			// beginning of function
+
+			str =
+			    (const char *) stabstr_section->data +
+			    sym->n_strx;
+
+
+			p = strchr(str, ':');
+			if (!p) {
+			    pstrcpy(func_name, sizeof(func_name), str);
+			} else {
+			    len = p - str;
+			    if (len > sizeof(func_name) - 1)
+				len = sizeof(func_name) - 1;
+			    memcpy(func_name, str, len);
+			    func_name[len] = '\0';
+			}
+			func_addr = sym->n_value;
+			last_pc = func_addr;
+			last_line_num = -1;
+
+			// output a function begin
+
+			CoffLineNo.l_addr.l_symndx =
+			    FindCoffSymbolIndex(func_name);
+			CoffLineNo.l_lnno = 0;
+
+			fwrite(&CoffLineNo, 6, 1, f);
+		    }
+		    break;
+
+		    /* line number info */
+		case N_SLINE:
+		    pc = sym->n_value + func_addr;
+
+
+		    /* XXX: slow! */
+		    strcpy(last_func_name, func_name);
+
+		    // output a line reference
+
+		    CoffLineNo.l_addr.l_paddr = last_pc;
+
+		    if (last_line_num == -1) {
+			CoffLineNo.l_lnno = sym->n_desc;
+		    } else {
+			CoffLineNo.l_lnno = last_line_num + 1;
+		    }
+
+		    fwrite(&CoffLineNo, 6, 1, f);
+
+		    last_pc = pc;
+		    last_line_num = sym->n_desc;
+
+		    break;
+
+		    /* include files */
+		case N_BINCL:
+		    str =
+			(const char *) stabstr_section->data + sym->n_strx;
+		  add_incl2:
+		    if (incl_index < INCLUDE_STACK_SIZE) {
+			incl_files[incl_index++] = str;
+		    }
+		    break;
+		case N_EINCL:
+		    if (incl_index > 1)
+			incl_index--;
+		    break;
+		case N_SO:
+		    if (sym->n_strx == 0) {
+			incl_index = 0;	/* end of translation unit */
+		    } else {
+			str =
+			    (const char *) stabstr_section->data +
+			    sym->n_strx;
+			/* do not add path */
+			len = strlen(str);
+			if (len > 0 && str[len - 1] != '/')
+			    goto add_incl2;
+		    }
+		    break;
+		}
+		sym++;
+	    }
+	}
+    }
+
+    // write symbol table
+    if (s1->do_debug) {
+	int k;
+	struct syment csym;
+	AUXFUNC auxfunc;
+	AUXBF auxbf;
+	AUXEF auxef;
+	int i;
+	Elf32_Sym *p;
+	const char *name;
+	int nstr;
+	int n = 0;
+
+	Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE);
+	pCoff_str_table = Coff_str_table;
+	nstr = 0;
+
+	p = (Elf32_Sym *) symtab_section->data;
+
+
+	for (i = 0; i < nb_syms; i++) {
+
+	    name = symtab_section->link->data + p->st_name;
+
+	    for (k = 0; k < 8; k++)
+		csym._n._n_name[k] = 0;
+
+	    if (strlen(name) <= 8) {
+		strcpy(csym._n._n_name, name);
+	    } else {
+		if (pCoff_str_table - Coff_str_table + strlen(name) >
+		    MAX_STR_TABLE - 1)
+		    error("String table too large");
+
+		csym._n._n_n._n_zeroes = 0;
+		csym._n._n_n._n_offset =
+		    pCoff_str_table - Coff_str_table + 4;
+
+		strcpy(pCoff_str_table, name);
+		pCoff_str_table += strlen(name) + 1;	// skip over null
+		nstr++;
+	    }
+
+	    if (p->st_info == 4) {
+		// put a filename symbol
+		csym.n_value = 33;	// ?????
+		csym.n_scnum = N_DEBUG;
+		csym.n_type = 0;
+		csym.n_sclass = C_FILE;
+		csym.n_numaux = 0;
+		fwrite(&csym, 18, 1, f);
+		n++;
+
+	    } else if (p->st_info == 0x12) {
+		// find the function data
+
+		for (k = 0; k < nFuncs; k++) {
+		    if (strcmp(name, Func[k]) == 0)
+			break;
+		}
+
+		if (k >= nFuncs) {
+		    char s[256];
+
+		    sprintf(s, "debug info can't find function: %s", name);
+
+		    error(s);
+		}
+		// put a Function Name
+
+		csym.n_value = p->st_value;	// physical address
+		csym.n_scnum = CoffTextSectionNo;
+		csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0);
+		csym.n_sclass = C_EXT;
+		csym.n_numaux = 1;
+		fwrite(&csym, 18, 1, f);
+
+		// now put aux info
+
+		auxfunc.tag = 0;
+		auxfunc.size = EndAddress[k] - p->st_value;
+		auxfunc.fileptr = LineNoFilePtr[k];
+		auxfunc.nextsym = n + 6;	// tktk
+		auxfunc.dummy = 0;
+		fwrite(&auxfunc, 18, 1, f);
+
+		// put a .bf
+
+		strcpy(csym._n._n_name, ".bf");
+		csym.n_value = p->st_value;	// physical address
+		csym.n_scnum = CoffTextSectionNo;
+		csym.n_type = 0;
+		csym.n_sclass = C_FCN;
+		csym.n_numaux = 1;
+		fwrite(&csym, 18, 1, f);
+
+		// now put aux info
+
+		auxbf.regmask = 0;
+		auxbf.lineno = 0;
+		auxbf.nentries = FuncEntries[k];
+		auxbf.localframe = 0;
+		auxbf.nextentry = n + 6;
+		auxbf.dummy = 0;
+		fwrite(&auxbf, 18, 1, f);
+
+		// put a .ef
+
+		strcpy(csym._n._n_name, ".ef");
+		csym.n_value = EndAddress[k];	// physical address  
+		csym.n_scnum = CoffTextSectionNo;
+		csym.n_type = 0;
+		csym.n_sclass = C_FCN;
+		csym.n_numaux = 1;
+		fwrite(&csym, 18, 1, f);
+
+		// now put aux info
+
+		auxef.dummy = 0;
+		auxef.lineno = LastLineNo[k];
+		auxef.dummy1 = 0;
+		auxef.dummy2 = 0;
+		auxef.dummy3 = 0;
+		auxef.dummy4 = 0;
+		fwrite(&auxef, 18, 1, f);
+
+		n += 6;
+
+	    } else {
+		// try an put some type info
+
+		if ((p->st_other & VT_BTYPE) == VT_DOUBLE) {
+		    csym.n_type = T_DOUBLE;	// int
+		    csym.n_sclass = C_EXT;
+		} else if ((p->st_other & VT_BTYPE) == VT_FLOAT) {
+		    csym.n_type = T_FLOAT;
+		    csym.n_sclass = C_EXT;
+		} else if ((p->st_other & VT_BTYPE) == VT_INT) {
+		    csym.n_type = T_INT;	// int
+		    csym.n_sclass = C_EXT;
+		} else if ((p->st_other & VT_BTYPE) == VT_SHORT) {
+		    csym.n_type = T_SHORT;
+		    csym.n_sclass = C_EXT;
+		} else if ((p->st_other & VT_BTYPE) == VT_BYTE) {
+		    csym.n_type = T_CHAR;
+		    csym.n_sclass = C_EXT;
+		} else {
+		    csym.n_type = T_INT;	// just mark as a label
+		    csym.n_sclass = C_LABEL;
+		}
+
+
+		csym.n_value = p->st_value;
+		csym.n_scnum = 2;
+		csym.n_numaux = 1;
+		fwrite(&csym, 18, 1, f);
+
+		auxfunc.tag = 0;
+		auxfunc.size = 0x20;
+		auxfunc.fileptr = 0;
+		auxfunc.nextsym = 0;
+		auxfunc.dummy = 0;
+		fwrite(&auxfunc, 18, 1, f);
+		n++;
+		n++;
+
+	    }
+
+	    p++;
+	}
+    }
+
+    if (s1->do_debug) {
+	// write string table
+
+	// first write the size
+	i = pCoff_str_table - Coff_str_table;
+	fwrite(&i, 4, 1, f);
+
+	// then write the strings
+	fwrite(Coff_str_table, i, 1, f);
+
+	tcc_free(Coff_str_table);
+    }
+
+    return 0;
+}
+
+
+
+// group the symbols in order of filename, func1, func2, etc
+// finally global symbols
+
+void SortSymbolTable(void)
+{
+    int i, j, k, n = 0;
+    Elf32_Sym *p, *p2, *NewTable;
+    char *name, *name2;
+
+    NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym));
+
+    p = (Elf32_Sym *) symtab_section->data;
+
+
+    // find a file symbol, copy it over
+    // then scan the whole symbol list and copy any function
+    // symbols that match the file association
+
+    for (i = 0; i < nb_syms; i++) {
+	if (p->st_info == 4) {
+	    name = (char *) symtab_section->link->data + p->st_name;
+
+	    // this is a file symbol, copy it over
+
+	    NewTable[n++] = *p;
+
+	    p2 = (Elf32_Sym *) symtab_section->data;
+
+	    for (j = 0; j < nb_syms; j++) {
+		if (p2->st_info == 0x12) {
+		    // this is a func symbol
+
+		    name2 =
+			(char *) symtab_section->link->data + p2->st_name;
+
+		    // find the function data index
+
+		    for (k = 0; k < nFuncs; k++) {
+			if (strcmp(name2, Func[k]) == 0)
+			    break;
+		    }
+
+		    if (k >= nFuncs) {
+			char s[256];
+
+			sprintf(s,
+				"debug (sort) info can't find function: %s",
+				name2);
+
+			error(s);
+		    }
+
+		    if (strcmp(AssociatedFile[k], name) == 0) {
+			// yes they match copy it over
+
+			NewTable[n++] = *p2;
+		    }
+		}
+		p2++;
+	    }
+	}
+	p++;
+    }
+
+    // now all the filename and func symbols should have been copied over
+    // copy all the rest over (all except file and funcs)
+
+    p = (Elf32_Sym *) symtab_section->data;
+    for (i = 0; i < nb_syms; i++) {
+	if (p->st_info != 4 && p->st_info != 0x12) {
+	    NewTable[n++] = *p;
+	}
+	p++;
+    }
+
+    if (n != nb_syms)
+	error("Internal Compiler error, debug info");
+
+    // copy it all back
+
+    p = (Elf32_Sym *) symtab_section->data;
+    for (i = 0; i < nb_syms; i++) {
+	*p++ = NewTable[i];
+    }
+
+    tcc_free(NewTable);
+}
+
+
+int FindCoffSymbolIndex(const char *func_name)
+{
+    int i, n = 0;
+    Elf32_Sym *p;
+    char *name;
+
+    p = (Elf32_Sym *) symtab_section->data;
+
+    for (i = 0; i < nb_syms; i++) {
+
+	name = (char *) symtab_section->link->data + p->st_name;
+
+	if (p->st_info == 4) {
+	    // put a filename symbol
+	    n++;
+	} else if (p->st_info == 0x12) {
+
+	    if (strcmp(func_name, name) == 0)
+		return n;
+
+	    n += 6;
+
+	    // put a Function Name
+
+	    // now put aux info
+
+	    // put a .bf
+
+	    // now put aux info
+
+	    // put a .ef
+
+	    // now put aux info
+
+	} else {
+	    n += 2;
+	}
+
+	p++;
+    }
+
+    return n;			// total number of symbols
+}
+
+BOOL OutputTheSection(Section * sect)
+{
+    const char *s = sect->name;
+
+    if (!strcmp(s, ".text"))
+	return true;
+    else if (!strcmp(s, ".data"))
+	return true;
+    else
+	return 0;
+}
+
+short int GetCoffFlags(const char *s)
+{
+    if (!strcmp(s, ".text"))
+	return STYP_TEXT | STYP_DATA | STYP_ALIGN | 0x400;
+    else if (!strcmp(s, ".data"))
+	return STYP_DATA;
+    else if (!strcmp(s, ".bss"))
+	return STYP_BSS;
+    else if (!strcmp(s, ".stack"))
+	return STYP_BSS | STYP_ALIGN | 0x200;
+    else if (!strcmp(s, ".cinit"))
+	return STYP_COPY | STYP_DATA | STYP_ALIGN | 0x200;
+    else
+	return 0;
+}
+
+Section *FindSection(TCCState * s1, const char *sname)
+{
+    Section *s;
+    int i;
+
+    for (i = 1; i < s1->nb_sections; i++) {
+	s = s1->sections[i];
+
+	if (!strcmp(sname, s->name))
+	    return s;
+    }
+
+    error("could not find section %s", sname);
+    return 0;
+}
+
+int tcc_load_coff(TCCState * s1, int fd)
+{
+// tktk TokenSym *ts;
+
+    FILE *f;
+    unsigned int str_size;
+    char *Coff_str_table, *name;
+    int i, k;
+    struct syment csym;
+    char name2[9];
+    FILHDR file_hdr;		/* FILE HEADER STRUCTURE              */
+
+    f = fdopen(fd, "rb");
+    if (!f) {
+	error("Unable to open .out file for input");
+    }
+
+    if (fread(&file_hdr, FILHSZ, 1, f) != 1)
+	error("error reading .out file for input");
+
+    if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1)
+	error("error reading .out file for input");
+
+    // first read the string table
+
+    if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET))
+	error("error reading .out file for input");
+
+    if (fread(&str_size, sizeof(int), 1, f) != 1)
+	error("error reading .out file for input");
+
+
+    Coff_str_table = (char *) tcc_malloc(str_size);
+
+    if (fread(Coff_str_table, str_size - 4, 1, f) != 1)
+	error("error reading .out file for input");
+
+    // read/process all the symbols
+
+    // seek back to symbols
+
+    if (fseek(f, file_hdr.f_symptr, SEEK_SET))
+	error("error reading .out file for input");
+
+    for (i = 0; i < file_hdr.f_nsyms; i++) {
+	if (fread(&csym, SYMESZ, 1, f) != 1)
+	    error("error reading .out file for input");
+
+	if (csym._n._n_n._n_zeroes == 0) {
+	    name = Coff_str_table + csym._n._n_n._n_offset - 4;
+	} else {
+	    name = csym._n._n_name;
+
+	    if (name[7] != 0) {
+		for (k = 0; k < 8; k++)
+		    name2[k] = name[k];
+
+		name2[8] = 0;
+
+		name = name2;
+	    }
+	}
+//              if (strcmp("_DAC_Buffer",name)==0)  // tktk
+//                      name[0]=0;
+
+	if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) ||	// structures
+	    (csym.n_type == 0x18 && csym.n_sclass == 0x2) ||	// pointer to structure
+	    (csym.n_type == 0x7 && csym.n_sclass == 0x2) ||	// doubles
+	    (csym.n_type == 0x6 && csym.n_sclass == 0x2))	// floats
+	{
+	    // strip off any leading underscore (except for other main routine)
+
+	    if (name[0] == '_' && strcmp(name, "_main") != 0)
+		name++;
+
+	    tcc_add_symbol(s1, name, (void*)csym.n_value);
+	}
+	// skip any aux records
+
+	if (csym.n_numaux == 1) {
+	    if (fread(&csym, SYMESZ, 1, f) != 1)
+		error("error reading .out file for input");
+	    i++;
+	}
+    }
+
+    return 0;
+}
diff --git a/tinyc/tccelf.c b/tinyc/tccelf.c
new file mode 100644
index 000000000..4020e249c
--- /dev/null
+++ b/tinyc/tccelf.c
@@ -0,0 +1,2732 @@
+/*
+ *  ELF file handling for TCC
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#ifdef TCC_TARGET_X86_64
+#define ElfW_Rel ElfW(Rela)
+#define SHT_RELX SHT_RELA
+#define REL_SECTION_FMT ".rela%s"
+/* x86-64 requires PLT for DLLs */
+#define TCC_OUTPUT_DLL_WITH_PLT
+#else
+#define ElfW_Rel ElfW(Rel)
+#define SHT_RELX SHT_REL
+#define REL_SECTION_FMT ".rel%s"
+#endif
+
+/* XXX: DLL with PLT would only work with x86-64 for now */
+//#define TCC_OUTPUT_DLL_WITH_PLT
+
+static int put_elf_str(Section *s, const char *sym)
+{
+    int offset, len;
+    char *ptr;
+
+    len = strlen(sym) + 1;
+    offset = s->data_offset;
+    ptr = section_ptr_add(s, len);
+    memcpy(ptr, sym, len);
+    return offset;
+}
+
+/* elf symbol hashing function */
+static unsigned long elf_hash(const unsigned char *name)
+{
+    unsigned long h = 0, g;
+    
+    while (*name) {
+        h = (h << 4) + *name++;
+        g = h & 0xf0000000;
+        if (g)
+            h ^= g >> 24;
+        h &= ~g;
+    }
+    return h;
+}
+
+/* rebuild hash table of section s */
+/* NOTE: we do factorize the hash table code to go faster */
+static void rebuild_hash(Section *s, unsigned int nb_buckets)
+{
+    ElfW(Sym) *sym;
+    int *ptr, *hash, nb_syms, sym_index, h;
+    char *strtab;
+
+    strtab = s->link->data;
+    nb_syms = s->data_offset / sizeof(ElfW(Sym));
+
+    s->hash->data_offset = 0;
+    ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
+    ptr[0] = nb_buckets;
+    ptr[1] = nb_syms;
+    ptr += 2;
+    hash = ptr;
+    memset(hash, 0, (nb_buckets + 1) * sizeof(int));
+    ptr += nb_buckets + 1;
+
+    sym = (ElfW(Sym) *)s->data + 1;
+    for(sym_index = 1; sym_index < nb_syms; sym_index++) {
+        if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
+            h = elf_hash(strtab + sym->st_name) % nb_buckets;
+            *ptr = hash[h];
+            hash[h] = sym_index;
+        } else {
+            *ptr = 0;
+        }
+        ptr++;
+        sym++;
+    }
+}
+
+/* return the symbol number */
+static int put_elf_sym(Section *s, 
+                       unsigned long value, unsigned long size,
+                       int info, int other, int shndx, const char *name)
+{
+    int name_offset, sym_index;
+    int nbuckets, h;
+    ElfW(Sym) *sym;
+    Section *hs;
+    
+    sym = section_ptr_add(s, sizeof(ElfW(Sym)));
+    if (name)
+        name_offset = put_elf_str(s->link, name);
+    else
+        name_offset = 0;
+    /* XXX: endianness */
+    sym->st_name = name_offset;
+    sym->st_value = value;
+    sym->st_size = size;
+    sym->st_info = info;
+    sym->st_other = other;
+    sym->st_shndx = shndx;
+    sym_index = sym - (ElfW(Sym) *)s->data;
+    hs = s->hash;
+    if (hs) {
+        int *ptr, *base;
+        ptr = section_ptr_add(hs, sizeof(int));
+        base = (int *)hs->data;
+        /* only add global or weak symbols */
+        if (ELFW(ST_BIND)(info) != STB_LOCAL) {
+            /* add another hashing entry */
+            nbuckets = base[0];
+            h = elf_hash(name) % nbuckets;
+            *ptr = base[2 + h];
+            base[2 + h] = sym_index;
+            base[1]++;
+            /* we resize the hash table */
+            hs->nb_hashed_syms++;
+            if (hs->nb_hashed_syms > 2 * nbuckets) {
+                rebuild_hash(s, 2 * nbuckets);
+            }
+        } else {
+            *ptr = 0;
+            base[1]++;
+        }
+    }
+    return sym_index;
+}
+
+/* find global ELF symbol 'name' and return its index. Return 0 if not
+   found. */
+static int find_elf_sym(Section *s, const char *name)
+{
+    ElfW(Sym) *sym;
+    Section *hs;
+    int nbuckets, sym_index, h;
+    const char *name1;
+    
+    hs = s->hash;
+    if (!hs)
+        return 0;
+    nbuckets = ((int *)hs->data)[0];
+    h = elf_hash(name) % nbuckets;
+    sym_index = ((int *)hs->data)[2 + h];
+    while (sym_index != 0) {
+        sym = &((ElfW(Sym) *)s->data)[sym_index];
+        name1 = s->link->data + sym->st_name;
+        if (!strcmp(name, name1))
+            return sym_index;
+        sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];
+    }
+    return 0;
+}
+
+/* return elf symbol value or error */
+void *tcc_get_symbol(TCCState *s, const char *name)
+{
+    int sym_index;
+    ElfW(Sym) *sym;
+    sym_index = find_elf_sym(symtab_section, name);
+    if (!sym_index)
+        return NULL;
+    sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+    return (void*)(long)sym->st_value;
+}
+
+void *tcc_get_symbol_err(TCCState *s, const char *name)
+{
+    void *sym;
+    sym = tcc_get_symbol(s, name);
+    if (!sym)
+        error("%s not defined", name);
+    return sym;
+}
+
+/* add an elf symbol : check if it is already defined and patch
+   it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
+static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
+                       int info, int other, int sh_num, const char *name)
+{
+    ElfW(Sym) *esym;
+    int sym_bind, sym_index, sym_type, esym_bind;
+    unsigned char sym_vis, esym_vis, new_vis;
+
+    sym_bind = ELFW(ST_BIND)(info);
+    sym_type = ELFW(ST_TYPE)(info);
+    sym_vis = ELFW(ST_VISIBILITY)(other);
+        
+    if (sym_bind != STB_LOCAL) {
+        /* we search global or weak symbols */
+        sym_index = find_elf_sym(s, name);
+        if (!sym_index)
+            goto do_def;
+        esym = &((ElfW(Sym) *)s->data)[sym_index];
+        if (esym->st_shndx != SHN_UNDEF) {
+            esym_bind = ELFW(ST_BIND)(esym->st_info);
+            /* propagate the most constraining visibility */
+            /* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */
+            esym_vis = ELFW(ST_VISIBILITY)(esym->st_other);
+            if (esym_vis == STV_DEFAULT) {
+                new_vis = sym_vis;
+            } else if (sym_vis == STV_DEFAULT) {
+                new_vis = esym_vis;
+            } else {
+                new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis;
+            }
+            esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
+                             | new_vis;
+            other = esym->st_other; /* in case we have to patch esym */
+            if (sh_num == SHN_UNDEF) {
+                /* ignore adding of undefined symbol if the
+                   corresponding symbol is already defined */
+            } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) {
+                /* global overrides weak, so patch */
+                goto do_patch;
+            } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {
+                /* weak is ignored if already global */
+            } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) {
+                /* ignore hidden symbols after */
+            } else if (esym->st_shndx == SHN_COMMON && sh_num < SHN_LORESERVE) {
+                /* gr: Happens with 'tcc ... -static tcctest.c' on e.g. Ubuntu 6.01
+                   No idea if this is the correct solution ... */
+                goto do_patch;
+            } else if (s == tcc_state->dynsymtab_section) {
+                /* we accept that two DLL define the same symbol */
+            } else {
+#if 1
+                printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
+                       sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis);
+#endif
+                error_noabort("'%s' defined twice", name);
+            }
+        } else {
+        do_patch:
+            esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
+            esym->st_shndx = sh_num;
+            esym->st_value = value;
+            esym->st_size = size;
+            esym->st_other = other;
+        }
+    } else {
+    do_def:
+        sym_index = put_elf_sym(s, value, size, 
+                                ELFW(ST_INFO)(sym_bind, sym_type), other, 
+                                sh_num, name);
+    }
+    return sym_index;
+}
+
+/* put relocation */
+static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
+                          int type, int symbol)
+{
+    char buf[256];
+    Section *sr;
+    ElfW_Rel *rel;
+
+    sr = s->reloc;
+    if (!sr) {
+        /* if no relocation section, create it */
+        snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
+        /* if the symtab is allocated, then we consider the relocation
+           are also */
+        sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags);
+        sr->sh_entsize = sizeof(ElfW_Rel);
+        sr->link = symtab;
+        sr->sh_info = s->sh_num;
+        s->reloc = sr;
+    }
+    rel = section_ptr_add(sr, sizeof(ElfW_Rel));
+    rel->r_offset = offset;
+    rel->r_info = ELFW(R_INFO)(symbol, type);
+#ifdef TCC_TARGET_X86_64
+    rel->r_addend = 0;
+#endif
+}
+
+/* put stab debug information */
+
+typedef struct {
+    unsigned int n_strx;         /* index into string table of name */
+    unsigned char n_type;         /* type of symbol */
+    unsigned char n_other;        /* misc info (usually empty) */
+    unsigned short n_desc;        /* description field */
+    unsigned int n_value;        /* value of symbol */
+} Stab_Sym;
+
+static void put_stabs(const char *str, int type, int other, int desc, 
+                      unsigned long value)
+{
+    Stab_Sym *sym;
+
+    sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
+    if (str) {
+        sym->n_strx = put_elf_str(stabstr_section, str);
+    } else {
+        sym->n_strx = 0;
+    }
+    sym->n_type = type;
+    sym->n_other = other;
+    sym->n_desc = desc;
+    sym->n_value = value;
+}
+
+static void put_stabs_r(const char *str, int type, int other, int desc, 
+                        unsigned long value, Section *sec, int sym_index)
+{
+    put_stabs(str, type, other, desc, value);
+    put_elf_reloc(symtab_section, stab_section, 
+                  stab_section->data_offset - sizeof(unsigned int),
+                  R_DATA_32, sym_index);
+}
+
+static void put_stabn(int type, int other, int desc, int value)
+{
+    put_stabs(NULL, type, other, desc, value);
+}
+
+static void put_stabd(int type, int other, int desc)
+{
+    put_stabs(NULL, type, other, desc, 0);
+}
+
+/* In an ELF file symbol table, the local symbols must appear below
+   the global and weak ones. Since TCC cannot sort it while generating
+   the code, we must do it after. All the relocation tables are also
+   modified to take into account the symbol table sorting */
+static void sort_syms(TCCState *s1, Section *s)
+{
+    int *old_to_new_syms;
+    ElfW(Sym) *new_syms;
+    int nb_syms, i;
+    ElfW(Sym) *p, *q;
+    ElfW_Rel *rel, *rel_end;
+    Section *sr;
+    int type, sym_index;
+
+    nb_syms = s->data_offset / sizeof(ElfW(Sym));
+    new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym)));
+    old_to_new_syms = tcc_malloc(nb_syms * sizeof(int));
+
+    /* first pass for local symbols */
+    p = (ElfW(Sym) *)s->data;
+    q = new_syms;
+    for(i = 0; i < nb_syms; i++) {
+        if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) {
+            old_to_new_syms[i] = q - new_syms;
+            *q++ = *p;
+        }
+        p++;
+    }
+    /* save the number of local symbols in section header */
+    s->sh_info = q - new_syms;
+
+    /* then second pass for non local symbols */
+    p = (ElfW(Sym) *)s->data;
+    for(i = 0; i < nb_syms; i++) {
+        if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) {
+            old_to_new_syms[i] = q - new_syms;
+            *q++ = *p;
+        }
+        p++;
+    }
+    
+    /* we copy the new symbols to the old */
+    memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym)));
+    tcc_free(new_syms);
+
+    /* now we modify all the relocations */
+    for(i = 1; i < s1->nb_sections; i++) {
+        sr = s1->sections[i];
+        if (sr->sh_type == SHT_RELX && sr->link == s) {
+            rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+            for(rel = (ElfW_Rel *)sr->data;
+                rel < rel_end;
+                rel++) {
+                sym_index = ELFW(R_SYM)(rel->r_info);
+                type = ELFW(R_TYPE)(rel->r_info);
+                sym_index = old_to_new_syms[sym_index];
+                rel->r_info = ELFW(R_INFO)(sym_index, type);
+            }
+        }
+    }
+    
+    tcc_free(old_to_new_syms);
+}
+
+/* relocate common symbols in the .bss section */
+static void relocate_common_syms(void)
+{
+    ElfW(Sym) *sym, *sym_end;
+    unsigned long offset, align;
+    
+    sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
+    for(sym = (ElfW(Sym) *)symtab_section->data + 1; 
+        sym < sym_end;
+        sym++) {
+        if (sym->st_shndx == SHN_COMMON) {
+            /* align symbol */
+            align = sym->st_value;
+            offset = bss_section->data_offset;
+            offset = (offset + align - 1) & -align;
+            sym->st_value = offset;
+            sym->st_shndx = bss_section->sh_num;
+            offset += sym->st_size;
+            bss_section->data_offset = offset;
+        }
+    }
+}
+
+/* relocate symbol table, resolve undefined symbols if do_resolve is
+   true and output error if undefined symbol. */
+static void relocate_syms(TCCState *s1, int do_resolve)
+{
+    ElfW(Sym) *sym, *esym, *sym_end;
+    int sym_bind, sh_num, sym_index;
+    const char *name;
+    unsigned long addr;
+
+    sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
+    for(sym = (ElfW(Sym) *)symtab_section->data + 1; 
+        sym < sym_end;
+        sym++) {
+        sh_num = sym->st_shndx;
+        if (sh_num == SHN_UNDEF) {
+            name = strtab_section->data + sym->st_name;
+            if (do_resolve) {
+                name = symtab_section->link->data + sym->st_name;
+                addr = (unsigned long)resolve_sym(s1, name, ELFW(ST_TYPE)(sym->st_info));
+                if (addr) {
+                    sym->st_value = addr;
+                    goto found;
+                }
+            } else if (s1->dynsym) {
+                /* if dynamic symbol exist, then use it */
+                sym_index = find_elf_sym(s1->dynsym, name);
+                if (sym_index) {
+                    esym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index];
+                    sym->st_value = esym->st_value;
+                    goto found;
+                }
+            }
+            /* XXX: _fp_hw seems to be part of the ABI, so we ignore
+               it */
+            if (!strcmp(name, "_fp_hw"))
+                goto found;
+            /* only weak symbols are accepted to be undefined. Their
+               value is zero */
+            sym_bind = ELFW(ST_BIND)(sym->st_info);
+            if (sym_bind == STB_WEAK) {
+                sym->st_value = 0;
+            } else {
+                error_noabort("undefined symbol '%s'", name);
+            }
+        } else if (sh_num < SHN_LORESERVE) {
+            /* add section base */
+            sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
+        }
+    found: ;
+    }
+}
+
+#ifdef TCC_TARGET_X86_64
+#define JMP_TABLE_ENTRY_SIZE 14
+static unsigned long add_jmp_table(TCCState *s1, unsigned long val)
+{
+    char *p = s1->runtime_plt_and_got + s1->runtime_plt_and_got_offset;
+    s1->runtime_plt_and_got_offset += JMP_TABLE_ENTRY_SIZE;
+    /* jmp *0x0(%rip) */
+    p[0] = 0xff;
+    p[1] = 0x25;
+    *(int *)(p + 2) = 0;
+    *(unsigned long *)(p + 6) = val;
+    return (unsigned long)p;
+}
+
+static unsigned long add_got_table(TCCState *s1, unsigned long val)
+{
+    unsigned long *p =(unsigned long *)(s1->runtime_plt_and_got +
+                                        s1->runtime_plt_and_got_offset);
+    s1->runtime_plt_and_got_offset += sizeof(void *);
+    *p = val;
+    return (unsigned long)p;
+}
+#endif
+
+/* relocate a given section (CPU dependent) */
+static void relocate_section(TCCState *s1, Section *s)
+{
+    Section *sr;
+    ElfW_Rel *rel, *rel_end, *qrel;
+    ElfW(Sym) *sym;
+    int type, sym_index;
+    unsigned char *ptr;
+    unsigned long val, addr;
+#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
+    int esym_index;
+#endif
+
+    sr = s->reloc;
+    rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+    qrel = (ElfW_Rel *)sr->data;
+    for(rel = qrel;
+        rel < rel_end;
+        rel++) {
+        ptr = s->data + rel->r_offset;
+
+        sym_index = ELFW(R_SYM)(rel->r_info);
+        sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+        val = sym->st_value;
+#ifdef TCC_TARGET_X86_64
+        /* XXX: not tested */
+        val += rel->r_addend;
+#endif
+        type = ELFW(R_TYPE)(rel->r_info);
+        addr = s->sh_addr + rel->r_offset;
+
+        /* CPU specific */
+        switch(type) {
+#if defined(TCC_TARGET_I386)
+        case R_386_32:
+            if (s1->output_type == TCC_OUTPUT_DLL) {
+                esym_index = s1->symtab_to_dynsym[sym_index];
+                qrel->r_offset = rel->r_offset;
+                if (esym_index) {
+                    qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
+                    qrel++;
+                    break;
+                } else {
+                    qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
+                    qrel++;
+                }
+            }
+            *(int *)ptr += val;
+            break;
+        case R_386_PC32:
+            if (s1->output_type == TCC_OUTPUT_DLL) {
+                /* DLL relocation */
+                esym_index = s1->symtab_to_dynsym[sym_index];
+                if (esym_index) {
+                    qrel->r_offset = rel->r_offset;
+                    qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
+                    qrel++;
+                    break;
+                }
+            }
+            *(int *)ptr += val - addr;
+            break;
+        case R_386_PLT32:
+            *(int *)ptr += val - addr;
+            break;
+        case R_386_GLOB_DAT:
+        case R_386_JMP_SLOT:
+            *(int *)ptr = val;
+            break;
+        case R_386_GOTPC:
+            *(int *)ptr += s1->got->sh_addr - addr;
+            break;
+        case R_386_GOTOFF:
+            *(int *)ptr += val - s1->got->sh_addr;
+            break;
+        case R_386_GOT32:
+            /* we load the got offset */
+            *(int *)ptr += s1->got_offsets[sym_index];
+            break;
+#elif defined(TCC_TARGET_ARM)
+        case R_ARM_PC24:
+        case R_ARM_CALL:
+        case R_ARM_JUMP24:
+        case R_ARM_PLT32:
+            {
+                int x;
+                x = (*(int *)ptr)&0xffffff;
+                (*(int *)ptr) &= 0xff000000;
+                if (x & 0x800000)
+                    x -= 0x1000000;
+                x *= 4;
+                x += val - addr;
+                if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000)
+                    error("can't relocate value at %x",addr);
+                x >>= 2;
+                x &= 0xffffff;
+                (*(int *)ptr) |= x;
+            }
+            break;
+        case R_ARM_PREL31:
+            {
+                int x;
+                x = (*(int *)ptr) & 0x7fffffff;
+                (*(int *)ptr) &= 0x80000000;
+                x = (x * 2) / 2;
+                x += val - addr;
+                if((x^(x>>1))&0x40000000)
+                    error("can't relocate value at %x",addr);
+                (*(int *)ptr) |= x & 0x7fffffff;
+            }
+        case R_ARM_ABS32:
+            *(int *)ptr += val;
+            break;
+        case R_ARM_BASE_PREL:
+            *(int *)ptr += s1->got->sh_addr - addr;
+            break;
+        case R_ARM_GOTOFF32:
+            *(int *)ptr += val - s1->got->sh_addr;
+            break;
+        case R_ARM_GOT_BREL:
+            /* we load the got offset */
+            *(int *)ptr += s1->got_offsets[sym_index];
+            break;
+        case R_ARM_COPY:
+            break;
+        default:
+            fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
+                    type,addr,(unsigned int )ptr,val);
+            break;
+#elif defined(TCC_TARGET_C67)
+        case R_C60_32:
+            *(int *)ptr += val;
+            break;
+        case R_C60LO16:
+            {
+                uint32_t orig;
+                
+                /* put the low 16 bits of the absolute address */
+                // add to what is already there
+                
+                orig  =   ((*(int *)(ptr  )) >> 7) & 0xffff;
+                orig |=  (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16;
+                
+                //patch both at once - assumes always in pairs Low - High
+                
+                *(int *) ptr    = (*(int *) ptr    & (~(0xffff << 7)) ) |  (((val+orig)      & 0xffff) << 7);
+                *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7);
+            }
+            break;
+        case R_C60HI16:
+            break;
+        default:
+            fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
+                    type,addr,(unsigned int )ptr,val);
+            break;
+#elif defined(TCC_TARGET_X86_64)
+        case R_X86_64_64:
+            if (s1->output_type == TCC_OUTPUT_DLL) {
+                qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
+                qrel->r_addend = *(long long *)ptr + val;
+                qrel++;
+            }
+            *(long long *)ptr += val;
+            break;
+        case R_X86_64_32:
+        case R_X86_64_32S:
+            if (s1->output_type == TCC_OUTPUT_DLL) {
+                /* XXX: this logic may depend on TCC's codegen
+                   now TCC uses R_X86_64_32 even for a 64bit pointer */
+                qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
+                qrel->r_addend = *(int *)ptr + val;
+                qrel++;
+            }
+            *(int *)ptr += val;
+            break;
+        case R_X86_64_PC32: {
+            if (s1->output_type == TCC_OUTPUT_DLL) {
+                /* DLL relocation */
+                esym_index = s1->symtab_to_dynsym[sym_index];
+                if (esym_index) {
+                    qrel->r_offset = rel->r_offset;
+                    qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
+                    qrel->r_addend = *(int *)ptr;
+                    qrel++;
+                    break;
+                }
+            }
+            long diff = val - addr;
+            if (diff <= -2147483647 || diff > 2147483647) {
+                /* XXX: naive support for over 32bit jump */
+                if (s1->output_type == TCC_OUTPUT_MEMORY) {
+                    val = add_jmp_table(s1, val);
+                    diff = val - addr;
+                }
+                if (diff <= -2147483647 || diff > 2147483647) {
+                    error("internal error: relocation failed");
+                }
+            }
+            *(int *)ptr += diff;
+        }
+            break;
+        case R_X86_64_PLT32:
+            *(int *)ptr += val - addr;
+            break;
+        case R_X86_64_GLOB_DAT:
+        case R_X86_64_JUMP_SLOT:
+            *(int *)ptr = val;
+            break;
+        case R_X86_64_GOTPCREL:
+            if (s1->output_type == TCC_OUTPUT_MEMORY) {
+                val = add_got_table(s1, val - rel->r_addend) + rel->r_addend;
+                *(int *)ptr += val - addr;
+                break;
+            }
+            *(int *)ptr += (s1->got->sh_addr - addr +
+                            s1->got_offsets[sym_index] - 4);
+            break;
+        case R_X86_64_GOTTPOFF:
+            *(int *)ptr += val - s1->got->sh_addr;
+            break;
+        case R_X86_64_GOT32:
+            /* we load the got offset */
+            *(int *)ptr += s1->got_offsets[sym_index];
+            break;
+#else
+#error unsupported processor
+#endif
+        }
+    }
+    /* if the relocation is allocated, we change its symbol table */
+    if (sr->sh_flags & SHF_ALLOC)
+        sr->link = s1->dynsym;
+}
+
+/* relocate relocation table in 'sr' */
+static void relocate_rel(TCCState *s1, Section *sr)
+{
+    Section *s;
+    ElfW_Rel *rel, *rel_end;
+    
+    s = s1->sections[sr->sh_info];
+    rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+    for(rel = (ElfW_Rel *)sr->data;
+        rel < rel_end;
+        rel++) {
+        rel->r_offset += s->sh_addr;
+    }
+}
+
+/* count the number of dynamic relocations so that we can reserve
+   their space */
+static int prepare_dynamic_rel(TCCState *s1, Section *sr)
+{
+    ElfW_Rel *rel, *rel_end;
+    int sym_index, esym_index, type, count;
+
+    count = 0;
+    rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
+    for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
+        sym_index = ELFW(R_SYM)(rel->r_info);
+        type = ELFW(R_TYPE)(rel->r_info);
+        switch(type) {
+#if defined(TCC_TARGET_I386)
+        case R_386_32:
+#elif defined(TCC_TARGET_X86_64)
+        case R_X86_64_32:
+        case R_X86_64_32S:
+        case R_X86_64_64:
+#endif
+            count++;
+            break;
+#if defined(TCC_TARGET_I386)
+        case R_386_PC32:
+#elif defined(TCC_TARGET_X86_64)
+        case R_X86_64_PC32:
+#endif
+            esym_index = s1->symtab_to_dynsym[sym_index];
+            if (esym_index)
+                count++;
+            break;
+        default:
+            break;
+        }
+    }
+    if (count) {
+        /* allocate the section */
+        sr->sh_flags |= SHF_ALLOC;
+        sr->sh_size = count * sizeof(ElfW_Rel);
+    }
+    return count;
+}
+
+static void put_got_offset(TCCState *s1, int index, unsigned long val)
+{
+    int n;
+    unsigned long *tab;
+
+    if (index >= s1->nb_got_offsets) {
+        /* find immediately bigger power of 2 and reallocate array */
+        n = 1;
+        while (index >= n)
+            n *= 2;
+        tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long));
+        if (!tab)
+            error("memory full");
+        s1->got_offsets = tab;
+        memset(s1->got_offsets + s1->nb_got_offsets, 0,
+               (n - s1->nb_got_offsets) * sizeof(unsigned long));
+        s1->nb_got_offsets = n;
+    }
+    s1->got_offsets[index] = val;
+}
+
+/* XXX: suppress that */
+static void put32(unsigned char *p, uint32_t val)
+{
+    p[0] = val;
+    p[1] = val >> 8;
+    p[2] = val >> 16;
+    p[3] = val >> 24;
+}
+
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \
+    defined(TCC_TARGET_X86_64)
+static uint32_t get32(unsigned char *p)
+{
+    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+#endif
+
+static void build_got(TCCState *s1)
+{
+    unsigned char *ptr;
+
+    /* if no got, then create it */
+    s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
+    s1->got->sh_entsize = 4;
+    add_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 
+                0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_");
+    ptr = section_ptr_add(s1->got, 3 * PTR_SIZE);
+#if PTR_SIZE == 4
+    /* keep space for _DYNAMIC pointer, if present */
+    put32(ptr, 0);
+    /* two dummy got entries */
+    put32(ptr + 4, 0);
+    put32(ptr + 8, 0);
+#else
+    /* keep space for _DYNAMIC pointer, if present */
+    put32(ptr, 0);
+    put32(ptr + 4, 0);
+    /* two dummy got entries */
+    put32(ptr + 8, 0);
+    put32(ptr + 12, 0);
+    put32(ptr + 16, 0);
+    put32(ptr + 20, 0);
+#endif
+}
+
+/* put a got entry corresponding to a symbol in symtab_section. 'size'
+   and 'info' can be modifed if more precise info comes from the DLL */
+static void put_got_entry(TCCState *s1,
+                          int reloc_type, unsigned long size, int info, 
+                          int sym_index)
+{
+    int index;
+    const char *name;
+    ElfW(Sym) *sym;
+    unsigned long offset;
+    int *ptr;
+
+    if (!s1->got)
+        build_got(s1);
+
+    /* if a got entry already exists for that symbol, no need to add one */
+    if (sym_index < s1->nb_got_offsets &&
+        s1->got_offsets[sym_index] != 0)
+        return;
+    
+    put_got_offset(s1, sym_index, s1->got->data_offset);
+
+    if (s1->dynsym) {
+        sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+        name = symtab_section->link->data + sym->st_name;
+        offset = sym->st_value;
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+        if (reloc_type ==
+#ifdef TCC_TARGET_X86_64
+            R_X86_64_JUMP_SLOT
+#else
+            R_386_JMP_SLOT
+#endif
+            ) {
+            Section *plt;
+            uint8_t *p;
+            int modrm;
+
+#if defined(TCC_OUTPUT_DLL_WITH_PLT)
+            modrm = 0x25;
+#else
+            /* if we build a DLL, we add a %ebx offset */
+            if (s1->output_type == TCC_OUTPUT_DLL)
+                modrm = 0xa3;
+            else
+                modrm = 0x25;
+#endif
+
+            /* add a PLT entry */
+            plt = s1->plt;
+            if (plt->data_offset == 0) {
+                /* first plt entry */
+                p = section_ptr_add(plt, 16);
+                p[0] = 0xff; /* pushl got + PTR_SIZE */
+                p[1] = modrm + 0x10;
+                put32(p + 2, PTR_SIZE);
+                p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
+                p[7] = modrm;
+                put32(p + 8, PTR_SIZE * 2);
+            }
+
+            p = section_ptr_add(plt, 16);
+            p[0] = 0xff; /* jmp *(got + x) */
+            p[1] = modrm;
+            put32(p + 2, s1->got->data_offset);
+            p[6] = 0x68; /* push $xxx */
+            put32(p + 7, (plt->data_offset - 32) >> 1);
+            p[11] = 0xe9; /* jmp plt_start */
+            put32(p + 12, -(plt->data_offset));
+
+            /* the symbol is modified so that it will be relocated to
+               the PLT */
+#if !defined(TCC_OUTPUT_DLL_WITH_PLT)
+            if (s1->output_type == TCC_OUTPUT_EXE)
+#endif
+                offset = plt->data_offset - 16;
+        }
+#elif defined(TCC_TARGET_ARM)
+        if (reloc_type == R_ARM_JUMP_SLOT) {
+            Section *plt;
+            uint8_t *p;
+            
+            /* if we build a DLL, we add a %ebx offset */
+            if (s1->output_type == TCC_OUTPUT_DLL)
+                error("DLLs unimplemented!");
+
+            /* add a PLT entry */
+            plt = s1->plt;
+            if (plt->data_offset == 0) {
+                /* first plt entry */
+                p = section_ptr_add(plt, 16);
+                put32(p     , 0xe52de004);
+                put32(p +  4, 0xe59fe010);
+                put32(p +  8, 0xe08fe00e);
+                put32(p + 12, 0xe5bef008);
+            }
+
+            p = section_ptr_add(plt, 16);
+            put32(p  , 0xe59fc004);
+            put32(p+4, 0xe08fc00c);
+            put32(p+8, 0xe59cf000);
+            put32(p+12, s1->got->data_offset);
+
+            /* the symbol is modified so that it will be relocated to
+               the PLT */
+            if (s1->output_type == TCC_OUTPUT_EXE)
+                offset = plt->data_offset - 16;
+        }
+#elif defined(TCC_TARGET_C67)
+        error("C67 got not implemented");
+#else
+#error unsupported CPU
+#endif
+        index = put_elf_sym(s1->dynsym, offset, 
+                            size, info, 0, sym->st_shndx, name);
+        /* put a got entry */
+        put_elf_reloc(s1->dynsym, s1->got, 
+                      s1->got->data_offset, 
+                      reloc_type, index);
+    }
+    ptr = section_ptr_add(s1->got, PTR_SIZE);
+    *ptr = 0;
+}
+
+/* build GOT and PLT entries */
+static void build_got_entries(TCCState *s1)
+{
+    Section *s, *symtab;
+    ElfW_Rel *rel, *rel_end;
+    ElfW(Sym) *sym;
+    int i, type, reloc_type, sym_index;
+
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        if (s->sh_type != SHT_RELX)
+            continue;
+        /* no need to handle got relocations */
+        if (s->link != symtab_section)
+            continue;
+        symtab = s->link;
+        rel_end = (ElfW_Rel *)(s->data + s->data_offset);
+        for(rel = (ElfW_Rel *)s->data;
+            rel < rel_end;
+            rel++) {
+            type = ELFW(R_TYPE)(rel->r_info);
+            switch(type) {
+#if defined(TCC_TARGET_I386)
+            case R_386_GOT32:
+            case R_386_GOTOFF:
+            case R_386_GOTPC:
+            case R_386_PLT32:
+                if (!s1->got)
+                    build_got(s1);
+                if (type == R_386_GOT32 || type == R_386_PLT32) {
+                    sym_index = ELFW(R_SYM)(rel->r_info);
+                    sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+                    /* look at the symbol got offset. If none, then add one */
+                    if (type == R_386_GOT32)
+                        reloc_type = R_386_GLOB_DAT;
+                    else
+                        reloc_type = R_386_JMP_SLOT;
+                    put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, 
+                                  sym_index);
+                }
+                break;
+#elif defined(TCC_TARGET_ARM)
+            case R_ARM_GOT_BREL:
+            case R_ARM_GOTOFF32:
+            case R_ARM_BASE_PREL:
+            case R_ARM_PLT32:
+                if (!s1->got)
+                    build_got(s1);
+                if (type == R_ARM_GOT_BREL || type == R_ARM_PLT32) {
+                    sym_index = ELFW(R_SYM)(rel->r_info);
+                    sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+                    /* look at the symbol got offset. If none, then add one */
+                    if (type == R_ARM_GOT_BREL)
+                        reloc_type = R_ARM_GLOB_DAT;
+                    else
+                        reloc_type = R_ARM_JUMP_SLOT;
+                    put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, 
+                                  sym_index);
+                }
+                break;
+#elif defined(TCC_TARGET_C67)
+            case R_C60_GOT32:
+            case R_C60_GOTOFF:
+            case R_C60_GOTPC:
+            case R_C60_PLT32:
+                if (!s1->got)
+                    build_got(s1);
+                if (type == R_C60_GOT32 || type == R_C60_PLT32) {
+                    sym_index = ELFW(R_SYM)(rel->r_info);
+                    sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+                    /* look at the symbol got offset. If none, then add one */
+                    if (type == R_C60_GOT32)
+                        reloc_type = R_C60_GLOB_DAT;
+                    else
+                        reloc_type = R_C60_JMP_SLOT;
+                    put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, 
+                                  sym_index);
+                }
+                break;
+#elif defined(TCC_TARGET_X86_64)
+            case R_X86_64_GOT32:
+            case R_X86_64_GOTTPOFF:
+            case R_X86_64_GOTPCREL:
+            case R_X86_64_PLT32:
+                if (!s1->got)
+                    build_got(s1);
+                if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL ||
+                    type == R_X86_64_PLT32) {
+                    sym_index = ELFW(R_SYM)(rel->r_info);
+                    sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+                    /* look at the symbol got offset. If none, then add one */
+                    if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL)
+                        reloc_type = R_X86_64_GLOB_DAT;
+                    else
+                        reloc_type = R_X86_64_JUMP_SLOT;
+                    put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, 
+                                  sym_index);
+                }
+                break;
+#else
+#error unsupported CPU
+#endif
+            default:
+                break;
+            }
+        }
+    }
+}
+
+static Section *new_symtab(TCCState *s1,
+                           const char *symtab_name, int sh_type, int sh_flags,
+                           const char *strtab_name, 
+                           const char *hash_name, int hash_sh_flags)
+{
+    Section *symtab, *strtab, *hash;
+    int *ptr, nb_buckets;
+
+    symtab = new_section(s1, symtab_name, sh_type, sh_flags);
+    symtab->sh_entsize = sizeof(ElfW(Sym));
+    strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags);
+    put_elf_str(strtab, "");
+    symtab->link = strtab;
+    put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL);
+    
+    nb_buckets = 1;
+
+    hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags);
+    hash->sh_entsize = sizeof(int);
+    symtab->hash = hash;
+    hash->link = symtab;
+
+    ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int));
+    ptr[0] = nb_buckets;
+    ptr[1] = 1;
+    memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
+    return symtab;
+}
+
+/* put dynamic tag */
+static void put_dt(Section *dynamic, int dt, unsigned long val)
+{
+    ElfW(Dyn) *dyn;
+    dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn)));
+    dyn->d_tag = dt;
+    dyn->d_un.d_val = val;
+}
+
+static void add_init_array_defines(TCCState *s1, const char *section_name)
+{
+    Section *s;
+    long end_offset;
+    char sym_start[1024];
+    char sym_end[1024];
+    
+    snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
+    snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
+
+    s = find_section(s1, section_name);
+    if (!s) {
+        end_offset = 0;
+        s = data_section;
+    } else {
+        end_offset = s->data_offset;
+    }
+
+    add_elf_sym(symtab_section, 
+                0, 0,
+                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                s->sh_num, sym_start);
+    add_elf_sym(symtab_section, 
+                end_offset, 0,
+                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                s->sh_num, sym_end);
+}
+
+/* add tcc runtime libraries */
+static void tcc_add_runtime(TCCState *s1)
+{
+#if defined(CONFIG_TCC_BCHECK) || !defined(CONFIG_USE_LIBGCC)
+    char buf[1024];
+#endif
+
+#ifdef CONFIG_TCC_BCHECK
+    if (s1->do_bounds_check) {
+        unsigned long *ptr;
+        Section *init_section;
+        unsigned char *pinit;
+        int sym_index;
+
+        /* XXX: add an object file to do that */
+        ptr = section_ptr_add(bounds_section, sizeof(unsigned long));
+        *ptr = 0;
+        add_elf_sym(symtab_section, 0, 0, 
+                    ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                    bounds_section->sh_num, "__bounds_start");
+        /* add bound check code */
+        snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o");
+        tcc_add_file(s1, buf);
+#ifdef TCC_TARGET_I386
+        if (s1->output_type != TCC_OUTPUT_MEMORY) {
+            /* add 'call __bound_init()' in .init section */
+            init_section = find_section(s1, ".init");
+            pinit = section_ptr_add(init_section, 5);
+            pinit[0] = 0xe8;
+            put32(pinit + 1, -4);
+            sym_index = find_elf_sym(symtab_section, "__bound_init");
+            put_elf_reloc(symtab_section, init_section, 
+                          init_section->data_offset - 4, R_386_PC32, sym_index);
+        }
+#endif
+    }
+#endif
+    /* add libc */
+    if (!s1->nostdlib) {
+        tcc_add_library(s1, "c");
+
+#ifdef CONFIG_USE_LIBGCC
+        tcc_add_file(s1, CONFIG_SYSROOT "/lib/libgcc_s.so.1");
+#else
+        snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "libtcc1.a");
+        tcc_add_file(s1, buf);
+#endif
+    }
+    /* add crt end if not memory output */
+    if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
+        tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o");
+    }
+}
+
+/* add various standard linker symbols (must be done after the
+   sections are filled (for example after allocating common
+   symbols)) */
+static void tcc_add_linker_symbols(TCCState *s1)
+{
+    char buf[1024];
+    int i;
+    Section *s;
+
+    add_elf_sym(symtab_section, 
+                text_section->data_offset, 0,
+                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                text_section->sh_num, "_etext");
+    add_elf_sym(symtab_section, 
+                data_section->data_offset, 0,
+                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                data_section->sh_num, "_edata");
+    add_elf_sym(symtab_section, 
+                bss_section->data_offset, 0,
+                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                bss_section->sh_num, "_end");
+    /* horrible new standard ldscript defines */
+    add_init_array_defines(s1, ".preinit_array");
+    add_init_array_defines(s1, ".init_array");
+    add_init_array_defines(s1, ".fini_array");
+    
+    /* add start and stop symbols for sections whose name can be
+       expressed in C */
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        if (s->sh_type == SHT_PROGBITS &&
+            (s->sh_flags & SHF_ALLOC)) {
+            const char *p;
+            int ch;
+
+            /* check if section name can be expressed in C */
+            p = s->name;
+            for(;;) {
+                ch = *p;
+                if (!ch)
+                    break;
+                if (!isid(ch) && !isnum(ch))
+                    goto next_sec;
+                p++;
+            }
+            snprintf(buf, sizeof(buf), "__start_%s", s->name);
+            add_elf_sym(symtab_section, 
+                        0, 0,
+                        ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                        s->sh_num, buf);
+            snprintf(buf, sizeof(buf), "__stop_%s", s->name);
+            add_elf_sym(symtab_section,
+                        s->data_offset, 0,
+                        ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+                        s->sh_num, buf);
+        }
+    next_sec: ;
+    }
+}
+
+/* name of ELF interpreter */
+#if defined __FreeBSD__
+static char elf_interp[] = "/usr/libexec/ld-elf.so.1";
+#elif defined TCC_ARM_EABI
+static char elf_interp[] = "/lib/ld-linux.so.3";
+#elif defined(TCC_TARGET_X86_64)
+static char elf_interp[] = "/lib/ld-linux-x86-64.so.2";
+#elif defined(TCC_UCLIBC)
+static char elf_interp[] = "/lib/ld-uClibc.so.0";
+#else
+static char elf_interp[] = "/lib/ld-linux.so.2";
+#endif
+
+static void tcc_output_binary(TCCState *s1, FILE *f,
+                              const int *section_order)
+{
+    Section *s;
+    int i, offset, size;
+
+    offset = 0;
+    for(i=1;i<s1->nb_sections;i++) {
+        s = s1->sections[section_order[i]];
+        if (s->sh_type != SHT_NOBITS &&
+            (s->sh_flags & SHF_ALLOC)) {
+            while (offset < s->sh_offset) {
+                fputc(0, f);
+                offset++;
+            }
+            size = s->sh_size;
+            fwrite(s->data, 1, size, f);
+            offset += size;
+        }
+    }
+}
+
+/* output an ELF file */
+/* XXX: suppress unneeded sections */
+int elf_output_file(TCCState *s1, const char *filename)
+{
+    ElfW(Ehdr) ehdr;
+    FILE *f;
+    int fd, mode, ret;
+    int *section_order;
+    int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index, k;
+    unsigned long addr;
+    Section *strsec, *s;
+    ElfW(Shdr) shdr, *sh;
+    ElfW(Phdr) *phdr, *ph;
+    Section *interp, *dynamic, *dynstr;
+    unsigned long saved_dynamic_data_offset;
+    ElfW(Sym) *sym;
+    int type, file_type;
+    unsigned long rel_addr, rel_size;
+    
+    file_type = s1->output_type;
+    s1->nb_errors = 0;
+
+    if (file_type != TCC_OUTPUT_OBJ) {
+        tcc_add_runtime(s1);
+    }
+
+    phdr = NULL;
+    section_order = NULL;
+    interp = NULL;
+    dynamic = NULL;
+    dynstr = NULL; /* avoid warning */
+    saved_dynamic_data_offset = 0; /* avoid warning */
+    
+    if (file_type != TCC_OUTPUT_OBJ) {
+        relocate_common_syms();
+
+        tcc_add_linker_symbols(s1);
+
+        if (!s1->static_link) {
+            const char *name;
+            int sym_index, index;
+            ElfW(Sym) *esym, *sym_end;
+            
+            if (file_type == TCC_OUTPUT_EXE) {
+                char *ptr;
+                /* add interpreter section only if executable */
+                interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
+                interp->sh_addralign = 1;
+                ptr = section_ptr_add(interp, sizeof(elf_interp));
+                strcpy(ptr, elf_interp);
+            }
+        
+            /* add dynamic symbol table */
+            s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC,
+                                    ".dynstr", 
+                                    ".hash", SHF_ALLOC);
+            dynstr = s1->dynsym->link;
+            
+            /* add dynamic section */
+            dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, 
+                                  SHF_ALLOC | SHF_WRITE);
+            dynamic->link = dynstr;
+            dynamic->sh_entsize = sizeof(ElfW(Dyn));
+        
+            /* add PLT */
+            s1->plt = new_section(s1, ".plt", SHT_PROGBITS, 
+                                  SHF_ALLOC | SHF_EXECINSTR);
+            s1->plt->sh_entsize = 4;
+
+            build_got(s1);
+
+            /* scan for undefined symbols and see if they are in the
+               dynamic symbols. If a symbol STT_FUNC is found, then we
+               add it in the PLT. If a symbol STT_OBJECT is found, we
+               add it in the .bss section with a suitable relocation */
+            sym_end = (ElfW(Sym) *)(symtab_section->data + 
+                                    symtab_section->data_offset);
+            if (file_type == TCC_OUTPUT_EXE) {
+                for(sym = (ElfW(Sym) *)symtab_section->data + 1; 
+                    sym < sym_end;
+                    sym++) {
+                    if (sym->st_shndx == SHN_UNDEF) {
+                        name = symtab_section->link->data + sym->st_name;
+                        sym_index = find_elf_sym(s1->dynsymtab_section, name);
+                        if (sym_index) {
+                            esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index];
+                            type = ELFW(ST_TYPE)(esym->st_info);
+                            if (type == STT_FUNC) {
+                                put_got_entry(s1, R_JMP_SLOT, esym->st_size, 
+                                              esym->st_info, 
+                                              sym - (ElfW(Sym) *)symtab_section->data);
+                            } else if (type == STT_OBJECT) {
+                                unsigned long offset;
+                                offset = bss_section->data_offset;
+                                /* XXX: which alignment ? */
+                                offset = (offset + 16 - 1) & -16;
+                                index = put_elf_sym(s1->dynsym, offset, esym->st_size, 
+                                                    esym->st_info, 0, 
+                                                    bss_section->sh_num, name);
+                                put_elf_reloc(s1->dynsym, bss_section, 
+                                              offset, R_COPY, index);
+                                offset += esym->st_size;
+                                bss_section->data_offset = offset;
+                            }
+                        } else {
+                                /* STB_WEAK undefined symbols are accepted */
+                                /* XXX: _fp_hw seems to be part of the ABI, so we ignore
+                                   it */
+                            if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
+                                !strcmp(name, "_fp_hw")) {
+                            } else {
+                                error_noabort("undefined symbol '%s'", name);
+                            }
+                        }
+                    } else if (s1->rdynamic && 
+                               ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
+                        /* if -rdynamic option, then export all non
+                           local symbols */
+                        name = symtab_section->link->data + sym->st_name;
+                        put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, 
+                                    sym->st_info, 0, 
+                                    sym->st_shndx, name);
+                    }
+                }
+            
+                if (s1->nb_errors)
+                    goto fail;
+
+                /* now look at unresolved dynamic symbols and export
+                   corresponding symbol */
+                sym_end = (ElfW(Sym) *)(s1->dynsymtab_section->data + 
+                                        s1->dynsymtab_section->data_offset);
+                for(esym = (ElfW(Sym) *)s1->dynsymtab_section->data + 1; 
+                    esym < sym_end;
+                    esym++) {
+                    if (esym->st_shndx == SHN_UNDEF) {
+                        name = s1->dynsymtab_section->link->data + esym->st_name;
+                        sym_index = find_elf_sym(symtab_section, name);
+                        if (sym_index) {
+                            /* XXX: avoid adding a symbol if already
+                               present because of -rdynamic ? */
+                            sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+                            put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, 
+                                        sym->st_info, 0, 
+                                        sym->st_shndx, name);
+                        } else {
+                            if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) {
+                                /* weak symbols can stay undefined */
+                            } else {
+                                warning("undefined dynamic symbol '%s'", name);
+                            }
+                        }
+                    }
+                }
+            } else {
+                int nb_syms;
+                /* shared library case : we simply export all the global symbols */
+                nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym));
+                s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
+                for(sym = (ElfW(Sym) *)symtab_section->data + 1; 
+                    sym < sym_end;
+                    sym++) {
+                    if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
+#if defined(TCC_OUTPUT_DLL_WITH_PLT)
+                        if (ELFW(ST_TYPE)(sym->st_info) == STT_FUNC &&
+                            sym->st_shndx == SHN_UNDEF) {
+                            put_got_entry(s1, R_JMP_SLOT, sym->st_size, 
+                                          sym->st_info, 
+                                          sym - (ElfW(Sym) *)symtab_section->data);
+                        }
+                        else if (ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT) {
+                            put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, 
+                                          sym->st_info, 
+                                          sym - (ElfW(Sym) *)symtab_section->data);
+                        }
+                        else
+#endif
+                        {
+                            name = symtab_section->link->data + sym->st_name;
+                            index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, 
+                                                sym->st_info, 0, 
+                                                sym->st_shndx, name);
+                            s1->symtab_to_dynsym[sym - 
+                                                 (ElfW(Sym) *)symtab_section->data] = 
+                                index;
+                        }
+                    }
+                }
+            }
+
+            build_got_entries(s1);
+        
+            /* add a list of needed dlls */
+            for(i = 0; i < s1->nb_loaded_dlls; i++) {
+                DLLReference *dllref = s1->loaded_dlls[i];
+                if (dllref->level == 0)
+                    put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
+            }
+            /* XXX: currently, since we do not handle PIC code, we
+               must relocate the readonly segments */
+            if (file_type == TCC_OUTPUT_DLL) {
+                if (s1->soname)
+                    put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
+                put_dt(dynamic, DT_TEXTREL, 0);
+            }
+
+            /* add necessary space for other entries */
+            saved_dynamic_data_offset = dynamic->data_offset;
+            dynamic->data_offset += sizeof(ElfW(Dyn)) * 9;
+        } else {
+            /* still need to build got entries in case of static link */
+            build_got_entries(s1);
+        }
+    }
+
+    memset(&ehdr, 0, sizeof(ehdr));
+
+    /* we add a section for symbols */
+    strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
+    put_elf_str(strsec, "");
+    
+    /* compute number of sections */
+    shnum = s1->nb_sections;
+
+    /* this array is used to reorder sections in the output file */
+    section_order = tcc_malloc(sizeof(int) * shnum);
+    section_order[0] = 0;
+    sh_order_index = 1;
+    
+    /* compute number of program headers */
+    switch(file_type) {
+    default:
+    case TCC_OUTPUT_OBJ:
+        phnum = 0;
+        break;
+    case TCC_OUTPUT_EXE:
+        if (!s1->static_link)
+            phnum = 4;
+        else
+            phnum = 2;
+        break;
+    case TCC_OUTPUT_DLL:
+        phnum = 3;
+        break;
+    }
+
+    /* allocate strings for section names and decide if an unallocated
+       section should be output */
+    /* NOTE: the strsec section comes last, so its size is also
+       correct ! */
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        s->sh_name = put_elf_str(strsec, s->name);
+#if 0 //gr       
+        printf("section: f=%08x t=%08x i=%08x %s %s\n", 
+               s->sh_flags, 
+               s->sh_type, 
+               s->sh_info, 
+               s->name, 
+               s->reloc ? s->reloc->name : "n"
+               ); 
+#endif
+        /* when generating a DLL, we include relocations but we may
+           patch them */
+        if (file_type == TCC_OUTPUT_DLL && 
+            s->sh_type == SHT_RELX && 
+            !(s->sh_flags & SHF_ALLOC)) {
+            /* //gr: avoid bogus relocs for empty (debug) sections */
+            if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)
+                prepare_dynamic_rel(s1, s);
+            else if (s1->do_debug)
+                s->sh_size = s->data_offset;
+        } else if (s1->do_debug ||
+            file_type == TCC_OUTPUT_OBJ || 
+            (s->sh_flags & SHF_ALLOC) ||
+            i == (s1->nb_sections - 1)) {
+            /* we output all sections if debug or object file */
+            s->sh_size = s->data_offset;
+        }
+    }
+
+    /* allocate program segment headers */
+    phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
+        
+    if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
+        file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
+    } else {
+        file_offset = 0;
+    }
+    if (phnum > 0) {
+        /* compute section to program header mapping */
+        if (s1->has_text_addr) { 
+            int a_offset, p_offset;
+            addr = s1->text_addr;
+            /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset %
+               ELF_PAGE_SIZE */
+            a_offset = addr & (ELF_PAGE_SIZE - 1);
+            p_offset = file_offset & (ELF_PAGE_SIZE - 1);
+            if (a_offset < p_offset) 
+                a_offset += ELF_PAGE_SIZE;
+            file_offset += (a_offset - p_offset);
+        } else {
+            if (file_type == TCC_OUTPUT_DLL)
+                addr = 0;
+            else
+                addr = ELF_START_ADDR;
+            /* compute address after headers */
+            addr += (file_offset & (ELF_PAGE_SIZE - 1));
+        }
+        
+        /* dynamic relocation table information, for .dynamic section */
+        rel_size = 0;
+        rel_addr = 0;
+
+        /* leave one program header for the program interpreter */
+        ph = &phdr[0];
+        if (interp)
+            ph++;
+
+        for(j = 0; j < 2; j++) {
+            ph->p_type = PT_LOAD;
+            if (j == 0)
+                ph->p_flags = PF_R | PF_X;
+            else
+                ph->p_flags = PF_R | PF_W;
+            ph->p_align = ELF_PAGE_SIZE;
+            
+            /* we do the following ordering: interp, symbol tables,
+               relocations, progbits, nobits */
+            /* XXX: do faster and simpler sorting */
+            for(k = 0; k < 5; k++) {
+                for(i = 1; i < s1->nb_sections; i++) {
+                    s = s1->sections[i];
+                    /* compute if section should be included */
+                    if (j == 0) {
+                        if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != 
+                            SHF_ALLOC)
+                            continue;
+                    } else {
+                        if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != 
+                            (SHF_ALLOC | SHF_WRITE))
+                            continue;
+                    }
+                    if (s == interp) {
+                        if (k != 0)
+                            continue;
+                    } else if (s->sh_type == SHT_DYNSYM ||
+                               s->sh_type == SHT_STRTAB ||
+                               s->sh_type == SHT_HASH) {
+                        if (k != 1)
+                            continue;
+                    } else if (s->sh_type == SHT_RELX) {
+                        if (k != 2)
+                            continue;
+                    } else if (s->sh_type == SHT_NOBITS) {
+                        if (k != 4)
+                            continue;
+                    } else {
+                        if (k != 3)
+                            continue;
+                    }
+                    section_order[sh_order_index++] = i;
+
+                    /* section matches: we align it and add its size */
+                    tmp = addr;
+                    addr = (addr + s->sh_addralign - 1) & 
+                        ~(s->sh_addralign - 1);
+                    file_offset += addr - tmp;
+                    s->sh_offset = file_offset;
+                    s->sh_addr = addr;
+                    
+                    /* update program header infos */
+                    if (ph->p_offset == 0) {
+                        ph->p_offset = file_offset;
+                        ph->p_vaddr = addr;
+                        ph->p_paddr = ph->p_vaddr;
+                    }
+                    /* update dynamic relocation infos */
+                    if (s->sh_type == SHT_RELX) {
+                        if (rel_size == 0)
+                            rel_addr = addr;
+                        rel_size += s->sh_size;
+                    }
+                    addr += s->sh_size;
+                    if (s->sh_type != SHT_NOBITS)
+                        file_offset += s->sh_size;
+                }
+            }
+            ph->p_filesz = file_offset - ph->p_offset;
+            ph->p_memsz = addr - ph->p_vaddr;
+            ph++;
+            if (j == 0) {
+                if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
+                    /* if in the middle of a page, we duplicate the page in
+                       memory so that one copy is RX and the other is RW */
+                    if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
+                        addr += ELF_PAGE_SIZE;
+                } else {
+                    addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1);
+                    file_offset = (file_offset + ELF_PAGE_SIZE - 1) & 
+                        ~(ELF_PAGE_SIZE - 1);
+                }
+            }
+        }
+
+        /* if interpreter, then add corresponing program header */
+        if (interp) {
+            ph = &phdr[0];
+            
+            ph->p_type = PT_INTERP;
+            ph->p_offset = interp->sh_offset;
+            ph->p_vaddr = interp->sh_addr;
+            ph->p_paddr = ph->p_vaddr;
+            ph->p_filesz = interp->sh_size;
+            ph->p_memsz = interp->sh_size;
+            ph->p_flags = PF_R;
+            ph->p_align = interp->sh_addralign;
+        }
+        
+        /* if dynamic section, then add corresponing program header */
+        if (dynamic) {
+            ElfW(Sym) *sym_end;
+
+            ph = &phdr[phnum - 1];
+            
+            ph->p_type = PT_DYNAMIC;
+            ph->p_offset = dynamic->sh_offset;
+            ph->p_vaddr = dynamic->sh_addr;
+            ph->p_paddr = ph->p_vaddr;
+            ph->p_filesz = dynamic->sh_size;
+            ph->p_memsz = dynamic->sh_size;
+            ph->p_flags = PF_R | PF_W;
+            ph->p_align = dynamic->sh_addralign;
+
+            /* put GOT dynamic section address */
+            put32(s1->got->data, dynamic->sh_addr);
+
+            /* relocate the PLT */
+            if (file_type == TCC_OUTPUT_EXE
+#if defined(TCC_OUTPUT_DLL_WITH_PLT)
+                || file_type == TCC_OUTPUT_DLL
+#endif
+                ) {
+                uint8_t *p, *p_end;
+
+                p = s1->plt->data;
+                p_end = p + s1->plt->data_offset;
+                if (p < p_end) {
+#if defined(TCC_TARGET_I386)
+                    put32(p + 2, get32(p + 2) + s1->got->sh_addr);
+                    put32(p + 8, get32(p + 8) + s1->got->sh_addr);
+                    p += 16;
+                    while (p < p_end) {
+                        put32(p + 2, get32(p + 2) + s1->got->sh_addr);
+                        p += 16;
+                    }
+#elif defined(TCC_TARGET_X86_64)
+                    int x = s1->got->sh_addr - s1->plt->sh_addr - 6;
+                    put32(p + 2, get32(p + 2) + x);
+                    put32(p + 8, get32(p + 8) + x - 6);
+                    p += 16;
+                    while (p < p_end) {
+                        put32(p + 2, get32(p + 2) + x + s1->plt->data - p);
+                        p += 16;
+                    }
+#elif defined(TCC_TARGET_ARM)
+                    int x;
+                    x=s1->got->sh_addr - s1->plt->sh_addr - 12;
+                    p +=16;
+                    while (p < p_end) {
+                        put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
+                        p += 16;
+                    }
+#elif defined(TCC_TARGET_C67)
+                    /* XXX: TODO */
+#else
+#error unsupported CPU
+#endif
+                }
+            }
+
+            /* relocate symbols in .dynsym */
+            sym_end = (ElfW(Sym) *)(s1->dynsym->data + s1->dynsym->data_offset);
+            for(sym = (ElfW(Sym) *)s1->dynsym->data + 1; 
+                sym < sym_end;
+                sym++) {
+                if (sym->st_shndx == SHN_UNDEF) {
+                    /* relocate to the PLT if the symbol corresponds
+                       to a PLT entry */
+                    if (sym->st_value)
+                        sym->st_value += s1->plt->sh_addr;
+                } else if (sym->st_shndx < SHN_LORESERVE) {
+                    /* do symbol relocation */
+                    sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
+                }
+            }
+
+            /* put dynamic section entries */
+            dynamic->data_offset = saved_dynamic_data_offset;
+            put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
+            put_dt(dynamic, DT_STRTAB, dynstr->sh_addr);
+            put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
+            put_dt(dynamic, DT_STRSZ, dynstr->data_offset);
+            put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));
+#ifdef TCC_TARGET_X86_64
+            put_dt(dynamic, DT_RELA, rel_addr);
+            put_dt(dynamic, DT_RELASZ, rel_size);
+            put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
+#else
+            put_dt(dynamic, DT_REL, rel_addr);
+            put_dt(dynamic, DT_RELSZ, rel_size);
+            put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
+#endif
+            if (s1->do_debug)
+                put_dt(dynamic, DT_DEBUG, 0);
+            put_dt(dynamic, DT_NULL, 0);
+        }
+
+        ehdr.e_phentsize = sizeof(ElfW(Phdr));
+        ehdr.e_phnum = phnum;
+        ehdr.e_phoff = sizeof(ElfW(Ehdr));
+    }
+
+    /* all other sections come after */
+    for(i = 1; i < s1->nb_sections; i++) {
+        s = s1->sections[i];
+        if (phnum > 0 && (s->sh_flags & SHF_ALLOC))
+            continue;
+        section_order[sh_order_index++] = i;
+        
+        file_offset = (file_offset + s->sh_addralign - 1) & 
+            ~(s->sh_addralign - 1);
+        s->sh_offset = file_offset;
+        if (s->sh_type != SHT_NOBITS)
+            file_offset += s->sh_size;
+    }
+    
+    /* if building executable or DLL, then relocate each section
+       except the GOT which is already relocated */
+    if (file_type != TCC_OUTPUT_OBJ) {
+        relocate_syms(s1, 0);
+
+        if (s1->nb_errors != 0) {
+        fail:
+            ret = -1;
+            goto the_end;
+        }
+
+        /* relocate sections */
+        /* XXX: ignore sections with allocated relocations ? */
+        for(i = 1; i < s1->nb_sections; i++) {
+            s = s1->sections[i];
+            if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr
+                relocate_section(s1, s);
+        }
+
+        /* relocate relocation entries if the relocation tables are
+           allocated in the executable */
+        for(i = 1; i < s1->nb_sections; i++) {
+            s = s1->sections[i];
+            if ((s->sh_flags & SHF_ALLOC) &&
+                s->sh_type == SHT_RELX) {
+                relocate_rel(s1, s);
+            }
+        }
+
+        /* get entry point address */
+        if (file_type == TCC_OUTPUT_EXE)
+            ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start");
+        else
+            ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
+    }
+
+    /* write elf file */
+    if (file_type == TCC_OUTPUT_OBJ)
+        mode = 0666;
+    else
+        mode = 0777;
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); 
+    if (fd < 0) {
+        error_noabort("could not write '%s'", filename);
+        goto fail;
+    }
+    f = fdopen(fd, "wb");
+    if (s1->verbose)
+        printf("<- %s\n", filename);
+
+#ifdef TCC_TARGET_COFF
+    if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) {
+        tcc_output_coff(s1, f);
+    } else
+#endif
+    if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
+        sort_syms(s1, symtab_section);
+        
+        /* align to 4 */
+        file_offset = (file_offset + 3) & -4;
+    
+        /* fill header */
+        ehdr.e_ident[0] = ELFMAG0;
+        ehdr.e_ident[1] = ELFMAG1;
+        ehdr.e_ident[2] = ELFMAG2;
+        ehdr.e_ident[3] = ELFMAG3;
+        ehdr.e_ident[4] = TCC_ELFCLASS;
+        ehdr.e_ident[5] = ELFDATA2LSB;
+        ehdr.e_ident[6] = EV_CURRENT;
+#ifdef __FreeBSD__
+        ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+#endif
+#ifdef TCC_TARGET_ARM
+#ifdef TCC_ARM_EABI
+        ehdr.e_ident[EI_OSABI] = 0;
+        ehdr.e_flags = 4 << 24;
+#else
+        ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
+#endif
+#endif
+        switch(file_type) {
+        default:
+        case TCC_OUTPUT_EXE:
+            ehdr.e_type = ET_EXEC;
+            break;
+        case TCC_OUTPUT_DLL:
+            ehdr.e_type = ET_DYN;
+            break;
+        case TCC_OUTPUT_OBJ:
+            ehdr.e_type = ET_REL;
+            break;
+        }
+        ehdr.e_machine = EM_TCC_TARGET;
+        ehdr.e_version = EV_CURRENT;
+        ehdr.e_shoff = file_offset;
+        ehdr.e_ehsize = sizeof(ElfW(Ehdr));
+        ehdr.e_shentsize = sizeof(ElfW(Shdr));
+        ehdr.e_shnum = shnum;
+        ehdr.e_shstrndx = shnum - 1;
+        
+        fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f);
+        fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f);
+        offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
+
+        for(i=1;i<s1->nb_sections;i++) {
+            s = s1->sections[section_order[i]];
+            if (s->sh_type != SHT_NOBITS) {
+                while (offset < s->sh_offset) {
+                    fputc(0, f);
+                    offset++;
+                }
+                size = s->sh_size;
+                fwrite(s->data, 1, size, f);
+                offset += size;
+            }
+        }
+
+        /* output section headers */
+        while (offset < ehdr.e_shoff) {
+            fputc(0, f);
+            offset++;
+        }
+    
+        for(i=0;i<s1->nb_sections;i++) {
+            sh = &shdr;
+            memset(sh, 0, sizeof(ElfW(Shdr)));
+            s = s1->sections[i];
+            if (s) {
+                sh->sh_name = s->sh_name;
+                sh->sh_type = s->sh_type;
+                sh->sh_flags = s->sh_flags;
+                sh->sh_entsize = s->sh_entsize;
+                sh->sh_info = s->sh_info;
+                if (s->link)
+                    sh->sh_link = s->link->sh_num;
+                sh->sh_addralign = s->sh_addralign;
+                sh->sh_addr = s->sh_addr;
+                sh->sh_offset = s->sh_offset;
+                sh->sh_size = s->sh_size;
+            }
+            fwrite(sh, 1, sizeof(ElfW(Shdr)), f);
+        }
+    } else {
+        tcc_output_binary(s1, f, section_order);
+    }
+    fclose(f);
+
+    ret = 0;
+ the_end:
+    tcc_free(s1->symtab_to_dynsym);
+    tcc_free(section_order);
+    tcc_free(phdr);
+    tcc_free(s1->got_offsets);
+    return ret;
+}
+
+int tcc_output_file(TCCState *s, const char *filename)
+{
+    int ret;
+#ifdef TCC_TARGET_PE
+    if (s->output_type != TCC_OUTPUT_OBJ) {
+        ret = pe_output_file(s, filename);
+    } else
+#endif
+    {
+        ret = elf_output_file(s, filename);
+    }
+    return ret;
+}
+
+static void *load_data(int fd, unsigned long file_offset, unsigned long size)
+{
+    void *data;
+
+    data = tcc_malloc(size);
+    lseek(fd, file_offset, SEEK_SET);
+    read(fd, data, size);
+    return data;
+}
+
+typedef struct SectionMergeInfo {
+    Section *s;            /* corresponding existing section */
+    unsigned long offset;  /* offset of the new section in the existing section */
+    uint8_t new_section;       /* true if section 's' was added */
+    uint8_t link_once;         /* true if link once section */
+} SectionMergeInfo;
+
+/* load an object file and merge it with current files */
+/* XXX: handle correctly stab (debug) info */
+static int tcc_load_object_file(TCCState *s1, 
+                                int fd, unsigned long file_offset)
+{ 
+    ElfW(Ehdr) ehdr;
+    ElfW(Shdr) *shdr, *sh;
+    int size, i, j, offset, offseti, nb_syms, sym_index, ret;
+    unsigned char *strsec, *strtab;
+    int *old_to_new_syms;
+    char *sh_name, *name;
+    SectionMergeInfo *sm_table, *sm;
+    ElfW(Sym) *sym, *symtab;
+    ElfW_Rel *rel, *rel_end;
+    Section *s;
+
+    int stab_index;
+    int stabstr_index;
+
+    stab_index = stabstr_index = 0;
+
+    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+        goto fail1;
+    if (ehdr.e_ident[0] != ELFMAG0 ||
+        ehdr.e_ident[1] != ELFMAG1 ||
+        ehdr.e_ident[2] != ELFMAG2 ||
+        ehdr.e_ident[3] != ELFMAG3)
+        goto fail1;
+    /* test if object file */
+    if (ehdr.e_type != ET_REL)
+        goto fail1;
+    /* test CPU specific stuff */
+    if (ehdr.e_ident[5] != ELFDATA2LSB ||
+        ehdr.e_machine != EM_TCC_TARGET) {
+    fail1:
+        error_noabort("invalid object file");
+        return -1;
+    }
+    /* read sections */
+    shdr = load_data(fd, file_offset + ehdr.e_shoff, 
+                     sizeof(ElfW(Shdr)) * ehdr.e_shnum);
+    sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum);
+    
+    /* load section names */
+    sh = &shdr[ehdr.e_shstrndx];
+    strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
+
+    /* load symtab and strtab */
+    old_to_new_syms = NULL;
+    symtab = NULL;
+    strtab = NULL;
+    nb_syms = 0;
+    for(i = 1; i < ehdr.e_shnum; i++) {
+        sh = &shdr[i];
+        if (sh->sh_type == SHT_SYMTAB) {
+            if (symtab) {
+                error_noabort("object must contain only one symtab");
+            fail:
+                ret = -1;
+                goto the_end;
+            }
+            nb_syms = sh->sh_size / sizeof(ElfW(Sym));
+            symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
+            sm_table[i].s = symtab_section;
+
+            /* now load strtab */
+            sh = &shdr[sh->sh_link];
+            strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
+        }
+    }
+        
+    /* now examine each section and try to merge its content with the
+       ones in memory */
+    for(i = 1; i < ehdr.e_shnum; i++) {
+        /* no need to examine section name strtab */
+        if (i == ehdr.e_shstrndx)
+            continue;
+        sh = &shdr[i];
+        sh_name = strsec + sh->sh_name;
+        /* ignore sections types we do not handle */
+        if (sh->sh_type != SHT_PROGBITS &&
+            sh->sh_type != SHT_RELX && 
+#ifdef TCC_ARM_EABI
+            sh->sh_type != SHT_ARM_EXIDX &&
+#endif
+            sh->sh_type != SHT_NOBITS && 
+            strcmp(sh_name, ".stabstr")
+            )
+            continue;
+        if (sh->sh_addralign < 1)
+            sh->sh_addralign = 1;
+        /* find corresponding section, if any */
+        for(j = 1; j < s1->nb_sections;j++) {
+            s = s1->sections[j];
+            if (!strcmp(s->name, sh_name)) {
+                if (!strncmp(sh_name, ".gnu.linkonce", 
+                             sizeof(".gnu.linkonce") - 1)) {
+                    /* if a 'linkonce' section is already present, we
+                       do not add it again. It is a little tricky as
+                       symbols can still be defined in
+                       it. */
+                    sm_table[i].link_once = 1;
+                    goto next;
+                } else {
+                    goto found;
+                }
+            }
+        }
+        /* not found: create new section */
+        s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags);
+        /* take as much info as possible from the section. sh_link and
+           sh_info will be updated later */
+        s->sh_addralign = sh->sh_addralign;
+        s->sh_entsize = sh->sh_entsize;
+        sm_table[i].new_section = 1;
+    found:
+        if (sh->sh_type != s->sh_type) {
+            error_noabort("invalid section type");
+            goto fail;
+        }
+
+        /* align start of section */
+        offset = s->data_offset;
+
+        if (0 == strcmp(sh_name, ".stab")) {
+            stab_index = i;
+            goto no_align;
+        }
+        if (0 == strcmp(sh_name, ".stabstr")) {
+            stabstr_index = i;
+            goto no_align;
+        }
+
+        size = sh->sh_addralign - 1;
+        offset = (offset + size) & ~size;
+        if (sh->sh_addralign > s->sh_addralign)
+            s->sh_addralign = sh->sh_addralign;
+        s->data_offset = offset;
+    no_align:
+        sm_table[i].offset = offset;
+        sm_table[i].s = s;
+        /* concatenate sections */
+        size = sh->sh_size;
+        if (sh->sh_type != SHT_NOBITS) {
+            unsigned char *ptr;
+            lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
+            ptr = section_ptr_add(s, size);
+            read(fd, ptr, size);
+        } else {
+            s->data_offset += size;
+        }
+    next: ;
+    }
+
+    /* //gr relocate stab strings */
+    if (stab_index && stabstr_index) {
+        Stab_Sym *a, *b;
+        unsigned o;
+        s = sm_table[stab_index].s;
+        a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
+        b = (Stab_Sym *)(s->data + s->data_offset);
+        o = sm_table[stabstr_index].offset;
+        while (a < b) 
+            a->n_strx += o, a++;
+    }
+
+    /* second short pass to update sh_link and sh_info fields of new
+       sections */
+    for(i = 1; i < ehdr.e_shnum; i++) {
+        s = sm_table[i].s;
+        if (!s || !sm_table[i].new_section)
+            continue;
+        sh = &shdr[i];
+        if (sh->sh_link > 0)
+            s->link = sm_table[sh->sh_link].s;
+        if (sh->sh_type == SHT_RELX) {
+            s->sh_info = sm_table[sh->sh_info].s->sh_num;
+            /* update backward link */
+            s1->sections[s->sh_info]->reloc = s;
+        }
+    }
+    sm = sm_table;
+
+    /* resolve symbols */
+    old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
+
+    sym = symtab + 1;
+    for(i = 1; i < nb_syms; i++, sym++) {
+        if (sym->st_shndx != SHN_UNDEF &&
+            sym->st_shndx < SHN_LORESERVE) {
+            sm = &sm_table[sym->st_shndx];
+            if (sm->link_once) {
+                /* if a symbol is in a link once section, we use the
+                   already defined symbol. It is very important to get
+                   correct relocations */
+                if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
+                    name = strtab + sym->st_name;
+                    sym_index = find_elf_sym(symtab_section, name);
+                    if (sym_index)
+                        old_to_new_syms[i] = sym_index;
+                }
+                continue;
+            }
+            /* if no corresponding section added, no need to add symbol */
+            if (!sm->s)
+                continue;
+            /* convert section number */
+            sym->st_shndx = sm->s->sh_num;
+            /* offset value */
+            sym->st_value += sm->offset;
+        }
+        /* add symbol */
+        name = strtab + sym->st_name;
+        sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, 
+                                sym->st_info, sym->st_other, 
+                                sym->st_shndx, name);
+        old_to_new_syms[i] = sym_index;
+    }
+
+    /* third pass to patch relocation entries */
+    for(i = 1; i < ehdr.e_shnum; i++) {
+        s = sm_table[i].s;
+        if (!s)
+            continue;
+        sh = &shdr[i];
+        offset = sm_table[i].offset;
+        switch(s->sh_type) {
+        case SHT_RELX:
+            /* take relocation offset information */
+            offseti = sm_table[sh->sh_info].offset;
+            rel_end = (ElfW_Rel *)(s->data + s->data_offset);
+            for(rel = (ElfW_Rel *)(s->data + offset);
+                rel < rel_end;
+                rel++) {
+                int type;
+                unsigned sym_index;
+                /* convert symbol index */
+                type = ELFW(R_TYPE)(rel->r_info);
+                sym_index = ELFW(R_SYM)(rel->r_info);
+                /* NOTE: only one symtab assumed */
+                if (sym_index >= nb_syms)
+                    goto invalid_reloc;
+                sym_index = old_to_new_syms[sym_index];
+                /* ignore link_once in rel section. */
+                if (!sym_index && !sm->link_once) {
+                invalid_reloc:
+                    error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x",
+                        i, strsec + sh->sh_name, rel->r_offset);
+                    goto fail;
+                }
+                rel->r_info = ELFW(R_INFO)(sym_index, type);
+                /* offset the relocation offset */
+                rel->r_offset += offseti;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    
+    ret = 0;
+ the_end:
+    tcc_free(symtab);
+    tcc_free(strtab);
+    tcc_free(old_to_new_syms);
+    tcc_free(sm_table);
+    tcc_free(strsec);
+    tcc_free(shdr);
+    return ret;
+}
+
+#define ARMAG  "!<arch>\012"    /* For COFF and a.out archives */
+
+typedef struct ArchiveHeader {
+    char ar_name[16];           /* name of this member */
+    char ar_date[12];           /* file mtime */
+    char ar_uid[6];             /* owner uid; printed as decimal */
+    char ar_gid[6];             /* owner gid; printed as decimal */
+    char ar_mode[8];            /* file mode, printed as octal   */
+    char ar_size[10];           /* file size, printed as decimal */
+    char ar_fmag[2];            /* should contain ARFMAG */
+} ArchiveHeader;
+
+static int get_be32(const uint8_t *b)
+{
+    return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
+}
+
+/* load only the objects which resolve undefined symbols */
+static int tcc_load_alacarte(TCCState *s1, int fd, int size)
+{
+    int i, bound, nsyms, sym_index, off, ret;
+    uint8_t *data;
+    const char *ar_names, *p;
+    const uint8_t *ar_index;
+    ElfW(Sym) *sym;
+
+    data = tcc_malloc(size);
+    if (read(fd, data, size) != size)
+        goto fail;
+    nsyms = get_be32(data);
+    ar_index = data + 4;
+    ar_names = ar_index + nsyms * 4;
+
+    do {
+        bound = 0;
+        for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
+            sym_index = find_elf_sym(symtab_section, p);
+            if(sym_index) {
+                sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+                if(sym->st_shndx == SHN_UNDEF) {
+                    off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader);
+#if 0
+                    printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx);
+#endif
+                    ++bound;
+                    lseek(fd, off, SEEK_SET);
+                    if(tcc_load_object_file(s1, fd, off) < 0) {
+                    fail:
+                        ret = -1;
+                        goto the_end;
+                    }
+                }
+            }
+        }
+    } while(bound);
+    ret = 0;
+ the_end:
+    tcc_free(data);
+    return ret;
+}
+
+/* load a '.a' file */
+static int tcc_load_archive(TCCState *s1, int fd)
+{
+    ArchiveHeader hdr;
+    char ar_size[11];
+    char ar_name[17];
+    char magic[8];
+    int size, len, i;
+    unsigned long file_offset;
+
+    /* skip magic which was already checked */
+    read(fd, magic, sizeof(magic));
+    
+    for(;;) {
+        len = read(fd, &hdr, sizeof(hdr));
+        if (len == 0)
+            break;
+        if (len != sizeof(hdr)) {
+            error_noabort("invalid archive");
+            return -1;
+        }
+        memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size));
+        ar_size[sizeof(hdr.ar_size)] = '\0';
+        size = strtol(ar_size, NULL, 0);
+        memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name));
+        for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) {
+            if (ar_name[i] != ' ')
+                break;
+        }
+        ar_name[i + 1] = '\0';
+        //        printf("name='%s' size=%d %s\n", ar_name, size, ar_size);
+        file_offset = lseek(fd, 0, SEEK_CUR);
+        /* align to even */
+        size = (size + 1) & ~1;
+        if (!strcmp(ar_name, "/")) {
+            /* coff symbol table : we handle it */
+            if(s1->alacarte_link)
+                return tcc_load_alacarte(s1, fd, size);
+        } else if (!strcmp(ar_name, "//") ||
+                   !strcmp(ar_name, "__.SYMDEF") ||
+                   !strcmp(ar_name, "__.SYMDEF/") ||
+                   !strcmp(ar_name, "ARFILENAMES/")) {
+            /* skip symbol table or archive names */
+        } else {
+            if (tcc_load_object_file(s1, fd, file_offset) < 0)
+                return -1;
+        }
+        lseek(fd, file_offset + size, SEEK_SET);
+    }
+    return 0;
+}
+
+/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
+   is referenced by the user (so it should be added as DT_NEEDED in
+   the generated ELF file) */
+static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
+{ 
+    ElfW(Ehdr) ehdr;
+    ElfW(Shdr) *shdr, *sh, *sh1;
+    int i, j, nb_syms, nb_dts, sym_bind, ret;
+    ElfW(Sym) *sym, *dynsym;
+    ElfW(Dyn) *dt, *dynamic;
+    unsigned char *dynstr;
+    const char *name, *soname;
+    DLLReference *dllref;
+    
+    read(fd, &ehdr, sizeof(ehdr));
+
+    /* test CPU specific stuff */
+    if (ehdr.e_ident[5] != ELFDATA2LSB ||
+        ehdr.e_machine != EM_TCC_TARGET) {
+        error_noabort("bad architecture");
+        return -1;
+    }
+
+    /* read sections */
+    shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum);
+
+    /* load dynamic section and dynamic symbols */
+    nb_syms = 0;
+    nb_dts = 0;
+    dynamic = NULL;
+    dynsym = NULL; /* avoid warning */
+    dynstr = NULL; /* avoid warning */
+    for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
+        switch(sh->sh_type) {
+        case SHT_DYNAMIC:
+            nb_dts = sh->sh_size / sizeof(ElfW(Dyn));
+            dynamic = load_data(fd, sh->sh_offset, sh->sh_size);
+            break;
+        case SHT_DYNSYM:
+            nb_syms = sh->sh_size / sizeof(ElfW(Sym));
+            dynsym = load_data(fd, sh->sh_offset, sh->sh_size);
+            sh1 = &shdr[sh->sh_link];
+            dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
+            break;
+        default:
+            break;
+        }
+    }
+    
+    /* compute the real library name */
+    soname = tcc_basename(filename);
+        
+    for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
+        if (dt->d_tag == DT_SONAME) {
+            soname = dynstr + dt->d_un.d_val;
+        }
+    }
+
+    /* if the dll is already loaded, do not load it */
+    for(i = 0; i < s1->nb_loaded_dlls; i++) {
+        dllref = s1->loaded_dlls[i];
+        if (!strcmp(soname, dllref->name)) {
+            /* but update level if needed */
+            if (level < dllref->level)
+                dllref->level = level;
+            ret = 0;
+            goto the_end;
+        }
+    }
+    
+    //    printf("loading dll '%s'\n", soname);
+
+    /* add the dll and its level */
+    dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
+    dllref->level = level;
+    strcpy(dllref->name, soname);
+    dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+
+    /* add dynamic symbols in dynsym_section */
+    for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
+        sym_bind = ELFW(ST_BIND)(sym->st_info);
+        if (sym_bind == STB_LOCAL)
+            continue;
+        name = dynstr + sym->st_name;
+        add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
+                    sym->st_info, sym->st_other, sym->st_shndx, name);
+    }
+
+    /* load all referenced DLLs */
+    for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
+        switch(dt->d_tag) {
+        case DT_NEEDED:
+            name = dynstr + dt->d_un.d_val;
+            for(j = 0; j < s1->nb_loaded_dlls; j++) {
+                dllref = s1->loaded_dlls[j];
+                if (!strcmp(name, dllref->name))
+                    goto already_loaded;
+            }
+            if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) {
+                error_noabort("referenced dll '%s' not found", name);
+                ret = -1;
+                goto the_end;
+            }
+        already_loaded:
+            break;
+        }
+    }
+    ret = 0;
+ the_end:
+    tcc_free(dynstr);
+    tcc_free(dynsym);
+    tcc_free(dynamic);
+    tcc_free(shdr);
+    return ret;
+}
+
+#define LD_TOK_NAME 256
+#define LD_TOK_EOF  (-1)
+
+/* return next ld script token */
+static int ld_next(TCCState *s1, char *name, int name_size)
+{
+    int c;
+    char *q;
+
+ redo:
+    switch(ch) {
+    case ' ':
+    case '\t':
+    case '\f':
+    case '\v':
+    case '\r':
+    case '\n':
+        inp();
+        goto redo;
+    case '/':
+        minp();
+        if (ch == '*') {
+            file->buf_ptr = parse_comment(file->buf_ptr);
+            ch = file->buf_ptr[0];
+            goto redo;
+        } else {
+            q = name;
+            *q++ = '/';
+            goto parse_name;
+        }
+        break;
+    /* case 'a' ... 'z': */
+    case 'a':
+       case 'b':
+       case 'c':
+       case 'd':
+       case 'e':
+       case 'f':
+       case 'g':
+       case 'h':
+       case 'i':
+       case 'j':
+       case 'k':
+       case 'l':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
+       case 'q':
+       case 'r':
+       case 's':
+       case 't':
+       case 'u':
+       case 'v':
+       case 'w':
+       case 'x':
+       case 'y':
+       case 'z':
+    /* case 'A' ... 'z': */
+    case 'A':
+       case 'B':
+       case 'C':
+       case 'D':
+       case 'E':
+       case 'F':
+       case 'G':
+       case 'H':
+       case 'I':
+       case 'J':
+       case 'K':
+       case 'L':
+       case 'M':
+       case 'N':
+       case 'O':
+       case 'P':
+       case 'Q':
+       case 'R':
+       case 'S':
+       case 'T':
+       case 'U':
+       case 'V':
+       case 'W':
+       case 'X':
+       case 'Y':
+       case 'Z':
+    case '_':
+    case '\\':
+    case '.':
+    case '$':
+    case '~':
+        q = name;
+    parse_name:
+        for(;;) {
+            if (!((ch >= 'a' && ch <= 'z') ||
+                  (ch >= 'A' && ch <= 'Z') ||
+                  (ch >= '0' && ch <= '9') ||
+                  strchr("/.-_+=$:\\,~", ch)))
+                break;
+            if ((q - name) < name_size - 1) {
+                *q++ = ch;
+            }
+            minp();
+        }
+        *q = '\0';
+        c = LD_TOK_NAME;
+        break;
+    case CH_EOF:
+        c = LD_TOK_EOF;
+        break;
+    default:
+        c = ch;
+        inp();
+        break;
+    }
+#if 0
+    printf("tok=%c %d\n", c, c);
+    if (c == LD_TOK_NAME)
+        printf("  name=%s\n", name);
+#endif
+    return c;
+}
+
+static int ld_add_file_list(TCCState *s1, int as_needed)
+{
+    char filename[1024];
+    int t, ret;
+
+    t = ld_next(s1, filename, sizeof(filename));
+    if (t != '(')
+        expect("(");
+    t = ld_next(s1, filename, sizeof(filename));
+    for(;;) {
+        if (t == LD_TOK_EOF) {
+            error_noabort("unexpected end of file");
+            return -1;
+        } else if (t == ')') {
+            break;
+        } else if (t != LD_TOK_NAME) {
+            error_noabort("filename expected");
+            return -1;
+        } 
+        if (!strcmp(filename, "AS_NEEDED")) {
+            ret = ld_add_file_list(s1, 1);
+            if (ret)
+                return ret;
+        } else {
+            /* TODO: Implement AS_NEEDED support. Ignore it for now */
+            if (!as_needed)
+                tcc_add_file(s1, filename);
+        }
+        t = ld_next(s1, filename, sizeof(filename));
+        if (t == ',') {
+            t = ld_next(s1, filename, sizeof(filename));
+        }
+    }
+    return 0;
+}
+
+/* interpret a subset of GNU ldscripts to handle the dummy libc.so
+   files */
+static int tcc_load_ldscript(TCCState *s1)
+{
+    char cmd[64];
+    char filename[1024];
+    int t, ret;
+    
+    ch = file->buf_ptr[0];
+    ch = handle_eob();
+    for(;;) {
+        t = ld_next(s1, cmd, sizeof(cmd));
+        if (t == LD_TOK_EOF)
+            return 0;
+        else if (t != LD_TOK_NAME)
+            return -1;
+        if (!strcmp(cmd, "INPUT") ||
+            !strcmp(cmd, "GROUP")) {
+            ret = ld_add_file_list(s1, 0);
+            if (ret)
+                return ret;
+        } else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
+                   !strcmp(cmd, "TARGET")) {
+            /* ignore some commands */
+            t = ld_next(s1, cmd, sizeof(cmd));
+            if (t != '(')
+                expect("(");
+            for(;;) {
+                t = ld_next(s1, filename, sizeof(filename));
+                if (t == LD_TOK_EOF) {
+                    error_noabort("unexpected end of file");
+                    return -1;
+                } else if (t == ')') {
+                    break;
+                }
+            }
+        } else {
+            return -1;
+        }
+    }
+    return 0;
+}
diff --git a/tinyc/tccgen.c b/tinyc/tccgen.c
new file mode 100644
index 000000000..a88f32819
--- /dev/null
+++ b/tinyc/tccgen.c
@@ -0,0 +1,5122 @@
+/*
+ *  TCC - Tiny C Compiler
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+void swap(int *p, int *q)
+{
+    int t;
+    t = *p;
+    *p = *q;
+    *q = t;
+}
+
+void vsetc(CType *type, int r, CValue *vc)
+{
+    int v;
+
+    if (vtop >= vstack + (VSTACK_SIZE - 1))
+        error("memory full");
+    /* cannot let cpu flags if other instruction are generated. Also
+       avoid leaving VT_JMP anywhere except on the top of the stack
+       because it would complicate the code generator. */
+    if (vtop >= vstack) {
+        v = vtop->r & VT_VALMASK;
+        if (v == VT_CMP || (v & ~1) == VT_JMP)
+            gv(RC_INT);
+    }
+    vtop++;
+    vtop->type = *type;
+    vtop->r = r;
+    vtop->r2 = VT_CONST;
+    vtop->c = *vc;
+}
+
+/* push integer constant */
+void vpushi(int v)
+{
+    CValue cval;
+    cval.i = v;
+    vsetc(&int_type, VT_CONST, &cval);
+}
+
+/* push long long constant */
+void vpushll(long long v)
+{
+    CValue cval;
+    CType ctype;
+    ctype.t = VT_LLONG;
+    cval.ull = v;
+    vsetc(&ctype, VT_CONST, &cval);
+}
+
+/* Return a static symbol pointing to a section */
+static Sym *get_sym_ref(CType *type, Section *sec, 
+                        unsigned long offset, unsigned long size)
+{
+    int v;
+    Sym *sym;
+
+    v = anon_sym++;
+    sym = global_identifier_push(v, type->t | VT_STATIC, 0);
+    sym->type.ref = type->ref;
+    sym->r = VT_CONST | VT_SYM;
+    put_extern_sym(sym, sec, offset, size);
+    return sym;
+}
+
+/* push a reference to a section offset by adding a dummy symbol */
+static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size)
+{
+    CValue cval;
+
+    cval.ul = 0;
+    vsetc(type, VT_CONST | VT_SYM, &cval);
+    vtop->sym = get_sym_ref(type, sec, offset, size);
+}
+
+/* define a new external reference to a symbol 'v' of type 'u' */
+static Sym *external_global_sym(int v, CType *type, int r)
+{
+    Sym *s;
+
+    s = sym_find(v);
+    if (!s) {
+        /* push forward reference */
+        s = global_identifier_push(v, type->t | VT_EXTERN, 0);
+        s->type.ref = type->ref;
+        s->r = r | VT_CONST | VT_SYM;
+    }
+    return s;
+}
+
+/* define a new external reference to a symbol 'v' of type 'u' */
+static Sym *external_sym(int v, CType *type, int r)
+{
+    Sym *s;
+
+    s = sym_find(v);
+    if (!s) {
+        /* push forward reference */
+        s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
+        s->type.t |= VT_EXTERN;
+    } else {
+        if (!is_compatible_types(&s->type, type))
+            error("incompatible types for redefinition of '%s'", 
+                  get_tok_str(v, NULL));
+    }
+    return s;
+}
+
+/* push a reference to global symbol v */
+static void vpush_global_sym(CType *type, int v)
+{
+    Sym *sym;
+    CValue cval;
+
+    sym = external_global_sym(v, type, 0);
+    cval.ul = 0;
+    vsetc(type, VT_CONST | VT_SYM, &cval);
+    vtop->sym = sym;
+}
+
+void vset(CType *type, int r, int v)
+{
+    CValue cval;
+
+    cval.i = v;
+    vsetc(type, r, &cval);
+}
+
+void vseti(int r, int v)
+{
+    CType type;
+    type.t = VT_INT;
+    vset(&type, r, v);
+}
+
+void vswap(void)
+{
+    SValue tmp;
+
+    tmp = vtop[0];
+    vtop[0] = vtop[-1];
+    vtop[-1] = tmp;
+}
+
+void vpushv(SValue *v)
+{
+    if (vtop >= vstack + (VSTACK_SIZE - 1))
+        error("memory full");
+    vtop++;
+    *vtop = *v;
+}
+
+void vdup(void)
+{
+    vpushv(vtop);
+}
+
+/* save r to the memory stack, and mark it as being free */
+void save_reg(int r)
+{
+    int l, saved, size, align;
+    SValue *p, sv;
+    CType *type;
+
+    /* modify all stack values */
+    saved = 0;
+    l = 0;
+    for(p=vstack;p<=vtop;p++) {
+        if ((p->r & VT_VALMASK) == r ||
+            ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) {
+            /* must save value on stack if not already done */
+            if (!saved) {
+                /* NOTE: must reload 'r' because r might be equal to r2 */
+                r = p->r & VT_VALMASK;
+                /* store register in the stack */
+                type = &p->type;
+                if ((p->r & VT_LVAL) ||
+                    (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
+#ifdef TCC_TARGET_X86_64
+                    type = &char_pointer_type;
+#else
+                    type = &int_type;
+#endif
+                size = type_size(type, &align);
+                loc = (loc - size) & -align;
+                sv.type.t = type->t;
+                sv.r = VT_LOCAL | VT_LVAL;
+                sv.c.ul = loc;
+                store(r, &sv);
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+                /* x86 specific: need to pop fp register ST0 if saved */
+                if (r == TREG_ST0) {
+                    o(0xd9dd); /* fstp %st(1) */
+                }
+#endif
+#ifndef TCC_TARGET_X86_64
+                /* special long long case */
+                if ((type->t & VT_BTYPE) == VT_LLONG) {
+                    sv.c.ul += 4;
+                    store(p->r2, &sv);
+                }
+#endif
+                l = loc;
+                saved = 1;
+            }
+            /* mark that stack entry as being saved on the stack */
+            if (p->r & VT_LVAL) {
+                /* also clear the bounded flag because the
+                   relocation address of the function was stored in
+                   p->c.ul */
+                p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
+            } else {
+                p->r = lvalue_type(p->type.t) | VT_LOCAL;
+            }
+            p->r2 = VT_CONST;
+            p->c.ul = l;
+        }
+    }
+}
+
+/* find a register of class 'rc2' with at most one reference on stack.
+ * If none, call get_reg(rc) */
+int get_reg_ex(int rc, int rc2) 
+{
+    int r;
+    SValue *p;
+    
+    for(r=0;r<NB_REGS;r++) {
+        if (reg_classes[r] & rc2) {
+            int n;
+            n=0;
+            for(p = vstack; p <= vtop; p++) {
+                if ((p->r & VT_VALMASK) == r ||
+                    (p->r2 & VT_VALMASK) == r)
+                    n++;
+            }
+            if (n <= 1)
+                return r;
+        }
+    }
+    return get_reg(rc);
+}
+
+/* find a free register of class 'rc'. If none, save one register */
+int get_reg(int rc)
+{
+    int r;
+    SValue *p;
+
+    /* find a free register */
+    for(r=0;r<NB_REGS;r++) {
+        if (reg_classes[r] & rc) {
+            for(p=vstack;p<=vtop;p++) {
+                if ((p->r & VT_VALMASK) == r ||
+                    (p->r2 & VT_VALMASK) == r)
+                    goto notfound;
+            }
+            return r;
+        }
+    notfound: ;
+    }
+    
+    /* no register left : free the first one on the stack (VERY
+       IMPORTANT to start from the bottom to ensure that we don't
+       spill registers used in gen_opi()) */
+    for(p=vstack;p<=vtop;p++) {
+        r = p->r & VT_VALMASK;
+        if (r < VT_CONST && (reg_classes[r] & rc))
+            goto save_found;
+        /* also look at second register (if long long) */
+        r = p->r2 & VT_VALMASK;
+        if (r < VT_CONST && (reg_classes[r] & rc)) {
+        save_found:
+            save_reg(r);
+            return r;
+        }
+    }
+    /* Should never comes here */
+    return -1;
+}
+
+/* save registers up to (vtop - n) stack entry */
+void save_regs(int n)
+{
+    int r;
+    SValue *p, *p1;
+    p1 = vtop - n;
+    for(p = vstack;p <= p1; p++) {
+        r = p->r & VT_VALMASK;
+        if (r < VT_CONST) {
+            save_reg(r);
+        }
+    }
+}
+
+/* move register 's' to 'r', and flush previous value of r to memory
+   if needed */
+void move_reg(int r, int s)
+{
+    SValue sv;
+
+    if (r != s) {
+        save_reg(r);
+        sv.type.t = VT_INT;
+        sv.r = s;
+        sv.c.ul = 0;
+        load(r, &sv);
+    }
+}
+
+/* get address of vtop (vtop MUST BE an lvalue) */
+void gaddrof(void)
+{
+    vtop->r &= ~VT_LVAL;
+    /* tricky: if saved lvalue, then we can go back to lvalue */
+    if ((vtop->r & VT_VALMASK) == VT_LLOCAL)
+        vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL;
+}
+
+#ifdef CONFIG_TCC_BCHECK
+/* generate lvalue bound code */
+void gbound(void)
+{
+    int lval_type;
+    CType type1;
+
+    vtop->r &= ~VT_MUSTBOUND;
+    /* if lvalue, then use checking code before dereferencing */
+    if (vtop->r & VT_LVAL) {
+        /* if not VT_BOUNDED value, then make one */
+        if (!(vtop->r & VT_BOUNDED)) {
+            lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
+            /* must save type because we must set it to int to get pointer */
+            type1 = vtop->type;
+            vtop->type.t = VT_INT;
+            gaddrof();
+            vpushi(0);
+            gen_bounded_ptr_add();
+            vtop->r |= lval_type;
+            vtop->type = type1;
+        }
+        /* then check for dereferencing */
+        gen_bounded_ptr_deref();
+    }
+}
+#endif
+
+/* store vtop a register belonging to class 'rc'. lvalues are
+   converted to values. Cannot be used if cannot be converted to
+   register value (such as structures). */
+int gv(int rc)
+{
+    int r, rc2, bit_pos, bit_size, size, align, i;
+
+    /* NOTE: get_reg can modify vstack[] */
+    if (vtop->type.t & VT_BITFIELD) {
+        CType type;
+        int bits = 32;
+        bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
+        bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+        /* remove bit field info to avoid loops */
+        vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
+        /* cast to int to propagate signedness in following ops */
+        if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+            type.t = VT_LLONG;
+            bits = 64;
+        } else
+            type.t = VT_INT;
+        if((vtop->type.t & VT_UNSIGNED) ||
+           (vtop->type.t & VT_BTYPE) == VT_BOOL)
+            type.t |= VT_UNSIGNED;
+        gen_cast(&type);
+        /* generate shifts */
+        vpushi(bits - (bit_pos + bit_size));
+        gen_op(TOK_SHL);
+        vpushi(bits - bit_size);
+        /* NOTE: transformed to SHR if unsigned */
+        gen_op(TOK_SAR);
+        r = gv(rc);
+    } else {
+        if (is_float(vtop->type.t) && 
+            (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+            Sym *sym;
+            int *ptr;
+            unsigned long offset;
+#if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP)
+            CValue check;
+#endif
+            
+            /* XXX: unify with initializers handling ? */
+            /* CPUs usually cannot use float constants, so we store them
+               generically in data segment */
+            size = type_size(&vtop->type, &align);
+            offset = (data_section->data_offset + align - 1) & -align;
+            data_section->data_offset = offset;
+            /* XXX: not portable yet */
+#if defined(__i386__) || defined(__x86_64__)
+            /* Zero pad x87 tenbyte long doubles */
+            if (size == LDOUBLE_SIZE)
+                vtop->c.tab[2] &= 0xffff;
+#endif
+            ptr = section_ptr_add(data_section, size);
+            size = size >> 2;
+#if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP)
+            check.d = 1;
+            if(check.tab[0])
+                for(i=0;i<size;i++)
+                    ptr[i] = vtop->c.tab[size-1-i];
+            else
+#endif
+            for(i=0;i<size;i++)
+                ptr[i] = vtop->c.tab[i];
+            sym = get_sym_ref(&vtop->type, data_section, offset, size << 2);
+            vtop->r |= VT_LVAL | VT_SYM;
+            vtop->sym = sym;
+            vtop->c.ul = 0;
+        }
+#ifdef CONFIG_TCC_BCHECK
+        if (vtop->r & VT_MUSTBOUND) 
+            gbound();
+#endif
+
+        r = vtop->r & VT_VALMASK;
+        rc2 = RC_INT;
+        if (rc == RC_IRET)
+            rc2 = RC_LRET;
+        /* need to reload if:
+           - constant
+           - lvalue (need to dereference pointer)
+           - already a register, but not in the right class */
+        if (r >= VT_CONST || 
+            (vtop->r & VT_LVAL) ||
+            !(reg_classes[r] & rc) ||
+            ((vtop->type.t & VT_BTYPE) == VT_LLONG && 
+             !(reg_classes[vtop->r2] & rc2))) {
+            r = get_reg(rc);
+#ifndef TCC_TARGET_X86_64
+            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+                int r2;
+                unsigned long long ll;
+                /* two register type load : expand to two words
+                   temporarily */
+                if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+                    /* load constant */
+                    ll = vtop->c.ull;
+                    vtop->c.ui = ll; /* first word */
+                    load(r, vtop);
+                    vtop->r = r; /* save register value */
+                    vpushi(ll >> 32); /* second word */
+                } else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */
+                           (vtop->r & VT_LVAL)) {
+                    /* We do not want to modifier the long long
+                       pointer here, so the safest (and less
+                       efficient) is to save all the other registers
+                       in the stack. XXX: totally inefficient. */
+                    save_regs(1);
+                    /* load from memory */
+                    load(r, vtop);
+                    vdup();
+                    vtop[-1].r = r; /* save register value */
+                    /* increment pointer to get second word */
+                    vtop->type.t = VT_INT;
+                    gaddrof();
+                    vpushi(4);
+                    gen_op('+');
+                    vtop->r |= VT_LVAL;
+                } else {
+                    /* move registers */
+                    load(r, vtop);
+                    vdup();
+                    vtop[-1].r = r; /* save register value */
+                    vtop->r = vtop[-1].r2;
+                }
+                /* allocate second register */
+                r2 = get_reg(rc2);
+                load(r2, vtop);
+                vpop();
+                /* write second register */
+                vtop->r2 = r2;
+            } else
+#endif
+            if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) {
+                int t1, t;
+                /* lvalue of scalar type : need to use lvalue type
+                   because of possible cast */
+                t = vtop->type.t;
+                t1 = t;
+                /* compute memory access type */
+                if (vtop->r & VT_LVAL_BYTE)
+                    t = VT_BYTE;
+                else if (vtop->r & VT_LVAL_SHORT)
+                    t = VT_SHORT;
+                if (vtop->r & VT_LVAL_UNSIGNED)
+                    t |= VT_UNSIGNED;
+                vtop->type.t = t;
+                load(r, vtop);
+                /* restore wanted type */
+                vtop->type.t = t1;
+            } else {
+                /* one register type load */
+                load(r, vtop);
+            }
+        }
+        vtop->r = r;
+#ifdef TCC_TARGET_C67
+        /* uses register pairs for doubles */
+        if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) 
+            vtop->r2 = r+1;
+#endif
+    }
+    return r;
+}
+
+/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */
+void gv2(int rc1, int rc2)
+{
+    int v;
+
+    /* generate more generic register first. But VT_JMP or VT_CMP
+       values must be generated first in all cases to avoid possible
+       reload errors */
+    v = vtop[0].r & VT_VALMASK;
+    if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) {
+        vswap();
+        gv(rc1);
+        vswap();
+        gv(rc2);
+        /* test if reload is needed for first register */
+        if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
+            vswap();
+            gv(rc1);
+            vswap();
+        }
+    } else {
+        gv(rc2);
+        vswap();
+        gv(rc1);
+        vswap();
+        /* test if reload is needed for first register */
+        if ((vtop[0].r & VT_VALMASK) >= VT_CONST) {
+            gv(rc2);
+        }
+    }
+}
+
+/* wrapper around RC_FRET to return a register by type */
+int rc_fret(int t)
+{
+#ifdef TCC_TARGET_X86_64
+    if (t == VT_LDOUBLE) {
+        return RC_ST0;
+    }
+#endif
+    return RC_FRET;
+}
+
+/* wrapper around REG_FRET to return a register by type */
+int reg_fret(int t)
+{
+#ifdef TCC_TARGET_X86_64
+    if (t == VT_LDOUBLE) {
+        return TREG_ST0;
+    }
+#endif
+    return REG_FRET;
+}
+
+/* expand long long on stack in two int registers */
+void lexpand(void)
+{
+    int u;
+
+    u = vtop->type.t & VT_UNSIGNED;
+    gv(RC_INT);
+    vdup();
+    vtop[0].r = vtop[-1].r2;
+    vtop[0].r2 = VT_CONST;
+    vtop[-1].r2 = VT_CONST;
+    vtop[0].type.t = VT_INT | u;
+    vtop[-1].type.t = VT_INT | u;
+}
+
+#ifdef TCC_TARGET_ARM
+/* expand long long on stack */
+void lexpand_nr(void)
+{
+    int u,v;
+
+    u = vtop->type.t & VT_UNSIGNED;
+    vdup();
+    vtop->r2 = VT_CONST;
+    vtop->type.t = VT_INT | u;
+    v=vtop[-1].r & (VT_VALMASK | VT_LVAL);
+    if (v == VT_CONST) {
+      vtop[-1].c.ui = vtop->c.ull;
+      vtop->c.ui = vtop->c.ull >> 32;
+      vtop->r = VT_CONST;
+    } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) {
+      vtop->c.ui += 4;
+      vtop->r = vtop[-1].r;
+    } else if (v > VT_CONST) {
+      vtop--;
+      lexpand();
+    } else
+      vtop->r = vtop[-1].r2;
+    vtop[-1].r2 = VT_CONST;
+    vtop[-1].type.t = VT_INT | u;
+}
+#endif
+
+/* build a long long from two ints */
+void lbuild(int t)
+{
+    gv2(RC_INT, RC_INT);
+    vtop[-1].r2 = vtop[0].r;
+    vtop[-1].type.t = t;
+    vpop();
+}
+
+/* rotate n first stack elements to the bottom 
+   I1 ... In -> I2 ... In I1 [top is right]
+*/
+void vrotb(int n)
+{
+    int i;
+    SValue tmp;
+
+    tmp = vtop[-n + 1];
+    for(i=-n+1;i!=0;i++)
+        vtop[i] = vtop[i+1];
+    vtop[0] = tmp;
+}
+
+/* rotate n first stack elements to the top 
+   I1 ... In -> In I1 ... I(n-1)  [top is right]
+ */
+void vrott(int n)
+{
+    int i;
+    SValue tmp;
+
+    tmp = vtop[0];
+    for(i = 0;i < n - 1; i++)
+        vtop[-i] = vtop[-i - 1];
+    vtop[-n + 1] = tmp;
+}
+
+#ifdef TCC_TARGET_ARM
+/* like vrott but in other direction
+   In ... I1 -> I(n-1) ... I1 In  [top is right]
+ */
+void vnrott(int n)
+{
+    int i;
+    SValue tmp;
+
+    tmp = vtop[-n + 1];
+    for(i = n - 1; i > 0; i--)
+        vtop[-i] = vtop[-i + 1];
+    vtop[0] = tmp;
+}
+#endif
+
+/* pop stack value */
+void vpop(void)
+{
+    int v;
+    v = vtop->r & VT_VALMASK;
+#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
+    /* for x86, we need to pop the FP stack */
+    if (v == TREG_ST0 && !nocode_wanted) {
+        o(0xd9dd); /* fstp %st(1) */
+    } else
+#endif
+    if (v == VT_JMP || v == VT_JMPI) {
+        /* need to put correct jump if && or || without test */
+        gsym(vtop->c.ul);
+    }
+    vtop--;
+}
+
+/* convert stack entry to register and duplicate its value in another
+   register */
+void gv_dup(void)
+{
+    int rc, t, r, r1;
+    SValue sv;
+
+    t = vtop->type.t;
+    if ((t & VT_BTYPE) == VT_LLONG) {
+        lexpand();
+        gv_dup();
+        vswap();
+        vrotb(3);
+        gv_dup();
+        vrotb(4);
+        /* stack: H L L1 H1 */
+        lbuild(t);
+        vrotb(3);
+        vrotb(3);
+        vswap();
+        lbuild(t);
+        vswap();
+    } else {
+        /* duplicate value */
+        rc = RC_INT;
+        sv.type.t = VT_INT;
+        if (is_float(t)) {
+            rc = RC_FLOAT;
+#ifdef TCC_TARGET_X86_64
+            if ((t & VT_BTYPE) == VT_LDOUBLE) {
+                rc = RC_ST0;
+            }
+#endif
+            sv.type.t = t;
+        }
+        r = gv(rc);
+        r1 = get_reg(rc);
+        sv.r = r;
+        sv.c.ul = 0;
+        load(r1, &sv); /* move r to r1 */
+        vdup();
+        /* duplicates value */
+        vtop->r = r1;
+    }
+}
+
+#ifndef TCC_TARGET_X86_64
+/* generate CPU independent (unsigned) long long operations */
+void gen_opl(int op)
+{
+    int t, a, b, op1, c, i;
+    int func;
+    unsigned short reg_iret = REG_IRET;
+    unsigned short reg_lret = REG_LRET;
+    SValue tmp;
+
+    switch(op) {
+    case '/':
+    case TOK_PDIV:
+        func = TOK___divdi3;
+        goto gen_func;
+    case TOK_UDIV:
+        func = TOK___udivdi3;
+        goto gen_func;
+    case '%':
+        func = TOK___moddi3;
+        goto gen_mod_func;
+    case TOK_UMOD:
+        func = TOK___umoddi3;
+    gen_mod_func:
+#ifdef TCC_ARM_EABI
+        reg_iret = TREG_R2;
+        reg_lret = TREG_R3;
+#endif
+    gen_func:
+        /* call generic long long function */
+        vpush_global_sym(&func_old_type, func);
+        vrott(3);
+        gfunc_call(2);
+        vpushi(0);
+        vtop->r = reg_iret;
+        vtop->r2 = reg_lret;
+        break;
+    case '^':
+    case '&':
+    case '|':
+    case '*':
+    case '+':
+    case '-':
+        t = vtop->type.t;
+        vswap();
+        lexpand();
+        vrotb(3);
+        lexpand();
+        /* stack: L1 H1 L2 H2 */
+        tmp = vtop[0];
+        vtop[0] = vtop[-3];
+        vtop[-3] = tmp;
+        tmp = vtop[-2];
+        vtop[-2] = vtop[-3];
+        vtop[-3] = tmp;
+        vswap();
+        /* stack: H1 H2 L1 L2 */
+        if (op == '*') {
+            vpushv(vtop - 1);
+            vpushv(vtop - 1);
+            gen_op(TOK_UMULL);
+            lexpand();
+            /* stack: H1 H2 L1 L2 ML MH */
+            for(i=0;i<4;i++)
+                vrotb(6);
+            /* stack: ML MH H1 H2 L1 L2 */
+            tmp = vtop[0];
+            vtop[0] = vtop[-2];
+            vtop[-2] = tmp;
+            /* stack: ML MH H1 L2 H2 L1 */
+            gen_op('*');
+            vrotb(3);
+            vrotb(3);
+            gen_op('*');
+            /* stack: ML MH M1 M2 */
+            gen_op('+');
+            gen_op('+');
+        } else if (op == '+' || op == '-') {
+            /* XXX: add non carry method too (for MIPS or alpha) */
+            if (op == '+')
+                op1 = TOK_ADDC1;
+            else
+                op1 = TOK_SUBC1;
+            gen_op(op1);
+            /* stack: H1 H2 (L1 op L2) */
+            vrotb(3);
+            vrotb(3);
+            gen_op(op1 + 1); /* TOK_xxxC2 */
+        } else {
+            gen_op(op);
+            /* stack: H1 H2 (L1 op L2) */
+            vrotb(3);
+            vrotb(3);
+            /* stack: (L1 op L2) H1 H2 */
+            gen_op(op);
+            /* stack: (L1 op L2) (H1 op H2) */
+        }
+        /* stack: L H */
+        lbuild(t);
+        break;
+    case TOK_SAR:
+    case TOK_SHR:
+    case TOK_SHL:
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            t = vtop[-1].type.t;
+            vswap();
+            lexpand();
+            vrotb(3);
+            /* stack: L H shift */
+            c = (int)vtop->c.i;
+            /* constant: simpler */
+            /* NOTE: all comments are for SHL. the other cases are
+               done by swaping words */
+            vpop();
+            if (op != TOK_SHL)
+                vswap();
+            if (c >= 32) {
+                /* stack: L H */
+                vpop();
+                if (c > 32) {
+                    vpushi(c - 32);
+                    gen_op(op);
+                }
+                if (op != TOK_SAR) {
+                    vpushi(0);
+                } else {
+                    gv_dup();
+                    vpushi(31);
+                    gen_op(TOK_SAR);
+                }
+                vswap();
+            } else {
+                vswap();
+                gv_dup();
+                /* stack: H L L */
+                vpushi(c);
+                gen_op(op);
+                vswap();
+                vpushi(32 - c);
+                if (op == TOK_SHL)
+                    gen_op(TOK_SHR);
+                else
+                    gen_op(TOK_SHL);
+                vrotb(3);
+                /* stack: L L H */
+                vpushi(c);
+                if (op == TOK_SHL)
+                    gen_op(TOK_SHL);
+                else
+                    gen_op(TOK_SHR);
+                gen_op('|');
+            }
+            if (op != TOK_SHL)
+                vswap();
+            lbuild(t);
+        } else {
+            /* XXX: should provide a faster fallback on x86 ? */
+            switch(op) {
+            case TOK_SAR:
+                func = TOK___ashrdi3;
+                goto gen_func;
+            case TOK_SHR:
+                func = TOK___lshrdi3;
+                goto gen_func;
+            case TOK_SHL:
+                func = TOK___ashldi3;
+                goto gen_func;
+            }
+        }
+        break;
+    default:
+        /* compare operations */
+        t = vtop->type.t;
+        vswap();
+        lexpand();
+        vrotb(3);
+        lexpand();
+        /* stack: L1 H1 L2 H2 */
+        tmp = vtop[-1];
+        vtop[-1] = vtop[-2];
+        vtop[-2] = tmp;
+        /* stack: L1 L2 H1 H2 */
+        /* compare high */
+        op1 = op;
+        /* when values are equal, we need to compare low words. since
+           the jump is inverted, we invert the test too. */
+        if (op1 == TOK_LT)
+            op1 = TOK_LE;
+        else if (op1 == TOK_GT)
+            op1 = TOK_GE;
+        else if (op1 == TOK_ULT)
+            op1 = TOK_ULE;
+        else if (op1 == TOK_UGT)
+            op1 = TOK_UGE;
+        a = 0;
+        b = 0;
+        gen_op(op1);
+        if (op1 != TOK_NE) {
+            a = gtst(1, 0);
+        }
+        if (op != TOK_EQ) {
+            /* generate non equal test */
+            /* XXX: NOT PORTABLE yet */
+            if (a == 0) {
+                b = gtst(0, 0);
+            } else {
+#if defined(TCC_TARGET_I386)
+                b = psym(0x850f, 0);
+#elif defined(TCC_TARGET_ARM)
+                b = ind;
+                o(0x1A000000 | encbranch(ind, 0, 1));
+#elif defined(TCC_TARGET_C67)
+                error("not implemented");
+#else
+#error not supported
+#endif
+            }
+        }
+        /* compare low. Always unsigned */
+        op1 = op;
+        if (op1 == TOK_LT)
+            op1 = TOK_ULT;
+        else if (op1 == TOK_LE)
+            op1 = TOK_ULE;
+        else if (op1 == TOK_GT)
+            op1 = TOK_UGT;
+        else if (op1 == TOK_GE)
+            op1 = TOK_UGE;
+        gen_op(op1);
+        a = gtst(1, a);
+        gsym(b);
+        vseti(VT_JMPI, a);
+        break;
+    }
+}
+#endif
+
+/* handle integer constant optimizations and various machine
+   independent opt */
+void gen_opic(int op)
+{
+    int c1, c2, t1, t2, n;
+    SValue *v1, *v2;
+    long long l1, l2;
+    typedef unsigned long long U;
+
+    v1 = vtop - 1;
+    v2 = vtop;
+    t1 = v1->type.t & VT_BTYPE;
+    t2 = v2->type.t & VT_BTYPE;
+
+    if (t1 == VT_LLONG)
+        l1 = v1->c.ll;
+    else if (v1->type.t & VT_UNSIGNED)
+        l1 = v1->c.ui;
+    else
+        l1 = v1->c.i;
+
+    if (t2 == VT_LLONG)
+        l2 = v2->c.ll;
+    else if (v2->type.t & VT_UNSIGNED)
+        l2 = v2->c.ui;
+    else
+        l2 = v2->c.i;
+
+    /* currently, we cannot do computations with forward symbols */
+    c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+    c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+    if (c1 && c2) {
+        switch(op) {
+        case '+': l1 += l2; break;
+        case '-': l1 -= l2; break;
+        case '&': l1 &= l2; break;
+        case '^': l1 ^= l2; break;
+        case '|': l1 |= l2; break;
+        case '*': l1 *= l2; break;
+
+        case TOK_PDIV:
+        case '/':
+        case '%':
+        case TOK_UDIV:
+        case TOK_UMOD:
+            /* if division by zero, generate explicit division */
+            if (l2 == 0) {
+                if (const_wanted)
+                    error("division by zero in constant");
+                goto general_case;
+            }
+            switch(op) {
+            default: l1 /= l2; break;
+            case '%': l1 %= l2; break;
+            case TOK_UDIV: l1 = (U)l1 / l2; break;
+            case TOK_UMOD: l1 = (U)l1 % l2; break;
+            }
+            break;
+        case TOK_SHL: l1 <<= l2; break;
+        case TOK_SHR: l1 = (U)l1 >> l2; break;
+        case TOK_SAR: l1 >>= l2; break;
+            /* tests */
+        case TOK_ULT: l1 = (U)l1 < (U)l2; break;
+        case TOK_UGE: l1 = (U)l1 >= (U)l2; break;
+        case TOK_EQ: l1 = l1 == l2; break;
+        case TOK_NE: l1 = l1 != l2; break;
+        case TOK_ULE: l1 = (U)l1 <= (U)l2; break;
+        case TOK_UGT: l1 = (U)l1 > (U)l2; break;
+        case TOK_LT: l1 = l1 < l2; break;
+        case TOK_GE: l1 = l1 >= l2; break;
+        case TOK_LE: l1 = l1 <= l2; break;
+        case TOK_GT: l1 = l1 > l2; break;
+            /* logical */
+        case TOK_LAND: l1 = l1 && l2; break;
+        case TOK_LOR: l1 = l1 || l2; break;
+        default:
+            goto general_case;
+        }
+        v1->c.ll = l1;
+        vtop--;
+    } else {
+        /* if commutative ops, put c2 as constant */
+        if (c1 && (op == '+' || op == '&' || op == '^' || 
+                   op == '|' || op == '*')) {
+            vswap();
+            c2 = c1; //c = c1, c1 = c2, c2 = c;
+            l2 = l1; //l = l1, l1 = l2, l2 = l;
+        }
+        /* Filter out NOP operations like x*1, x-0, x&-1... */
+        if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || 
+                     op == TOK_PDIV) && 
+                    l2 == 1) ||
+                   ((op == '+' || op == '-' || op == '|' || op == '^' || 
+                     op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && 
+                    l2 == 0) ||
+                   (op == '&' && 
+                    l2 == -1))) {
+            /* nothing to do */
+            vtop--;
+        } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
+            /* try to use shifts instead of muls or divs */
+            if (l2 > 0 && (l2 & (l2 - 1)) == 0) {
+                n = -1;
+                while (l2) {
+                    l2 >>= 1;
+                    n++;
+                }
+                vtop->c.ll = n;
+                if (op == '*')
+                    op = TOK_SHL;
+                else if (op == TOK_PDIV)
+                    op = TOK_SAR;
+                else
+                    op = TOK_SHR;
+            }
+            goto general_case;
+        } else if (c2 && (op == '+' || op == '-') &&
+                   ((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) ==
+                   (VT_CONST | VT_SYM) ||
+                   (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) {
+            /* symbol + constant case */
+            if (op == '-')
+                l2 = -l2;
+            vtop--;
+            vtop->c.ll += l2;
+        } else {
+        general_case:
+            if (!nocode_wanted) {
+                /* call low level op generator */
+                if (t1 == VT_LLONG || t2 == VT_LLONG) 
+                    gen_opl(op);
+                else
+                    gen_opi(op);
+            } else {
+                vtop--;
+            }
+        }
+    }
+}
+
+/* generate a floating point operation with constant propagation */
+void gen_opif(int op)
+{
+    int c1, c2;
+    SValue *v1, *v2;
+    long double f1, f2;
+
+    v1 = vtop - 1;
+    v2 = vtop;
+    /* currently, we cannot do computations with forward symbols */
+    c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+    c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+    if (c1 && c2) {
+        if (v1->type.t == VT_FLOAT) {
+            f1 = v1->c.f;
+            f2 = v2->c.f;
+        } else if (v1->type.t == VT_DOUBLE) {
+            f1 = v1->c.d;
+            f2 = v2->c.d;
+        } else {
+            f1 = v1->c.ld;
+            f2 = v2->c.ld;
+        }
+
+        /* NOTE: we only do constant propagation if finite number (not
+           NaN or infinity) (ANSI spec) */
+        if (!ieee_finite(f1) || !ieee_finite(f2))
+            goto general_case;
+
+        switch(op) {
+        case '+': f1 += f2; break;
+        case '-': f1 -= f2; break;
+        case '*': f1 *= f2; break;
+        case '/': 
+            if (f2 == 0.0) {
+                if (const_wanted)
+                    error("division by zero in constant");
+                goto general_case;
+            }
+            f1 /= f2; 
+            break;
+            /* XXX: also handles tests ? */
+        default:
+            goto general_case;
+        }
+        /* XXX: overflow test ? */
+        if (v1->type.t == VT_FLOAT) {
+            v1->c.f = f1;
+        } else if (v1->type.t == VT_DOUBLE) {
+            v1->c.d = f1;
+        } else {
+            v1->c.ld = f1;
+        }
+        vtop--;
+    } else {
+    general_case:
+        if (!nocode_wanted) {
+            gen_opf(op);
+        } else {
+            vtop--;
+        }
+    }
+}
+
+static int pointed_size(CType *type)
+{
+    int align;
+    return type_size(pointed_type(type), &align);
+}
+
+static inline int is_null_pointer(SValue *p)
+{
+    if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
+        return 0;
+    return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) ||
+        ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0);
+}
+
+static inline int is_integer_btype(int bt)
+{
+    return (bt == VT_BYTE || bt == VT_SHORT || 
+            bt == VT_INT || bt == VT_LLONG);
+}
+
+/* check types for comparison or subtraction of pointers */
+static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op)
+{
+    CType *type1, *type2, tmp_type1, tmp_type2;
+    int bt1, bt2;
+    
+    /* null pointers are accepted for all comparisons as gcc */
+    if (is_null_pointer(p1) || is_null_pointer(p2))
+        return;
+    type1 = &p1->type;
+    type2 = &p2->type;
+    bt1 = type1->t & VT_BTYPE;
+    bt2 = type2->t & VT_BTYPE;
+    /* accept comparison between pointer and integer with a warning */
+    if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') {
+        if (op != TOK_LOR && op != TOK_LAND )
+            warning("comparison between pointer and integer");
+        return;
+    }
+
+    /* both must be pointers or implicit function pointers */
+    if (bt1 == VT_PTR) {
+        type1 = pointed_type(type1);
+    } else if (bt1 != VT_FUNC) 
+        goto invalid_operands;
+
+    if (bt2 == VT_PTR) {
+        type2 = pointed_type(type2);
+    } else if (bt2 != VT_FUNC) { 
+    invalid_operands:
+        error("invalid operands to binary %s", get_tok_str(op, NULL));
+    }
+    if ((type1->t & VT_BTYPE) == VT_VOID || 
+        (type2->t & VT_BTYPE) == VT_VOID)
+        return;
+    tmp_type1 = *type1;
+    tmp_type2 = *type2;
+    tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
+    tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
+    if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
+        /* gcc-like error if '-' is used */
+        if (op == '-')
+            goto invalid_operands;
+        else
+            warning("comparison of distinct pointer types lacks a cast");
+    }
+}
+
+/* generic gen_op: handles types problems */
+void gen_op(int op)
+{
+    int u, t1, t2, bt1, bt2, t;
+    CType type1;
+
+    t1 = vtop[-1].type.t;
+    t2 = vtop[0].type.t;
+    bt1 = t1 & VT_BTYPE;
+    bt2 = t2 & VT_BTYPE;
+        
+    if (bt1 == VT_PTR || bt2 == VT_PTR) {
+        /* at least one operand is a pointer */
+        /* relationnal op: must be both pointers */
+        if (op >= TOK_ULT && op <= TOK_LOR) {
+            check_comparison_pointer_types(vtop - 1, vtop, op);
+            /* pointers are handled are unsigned */
+#ifdef TCC_TARGET_X86_64
+            t = VT_LLONG | VT_UNSIGNED;
+#else
+            t = VT_INT | VT_UNSIGNED;
+#endif
+            goto std_op;
+        }
+        /* if both pointers, then it must be the '-' op */
+        if (bt1 == VT_PTR && bt2 == VT_PTR) {
+            if (op != '-')
+                error("cannot use pointers here");
+            check_comparison_pointer_types(vtop - 1, vtop, op);
+            /* XXX: check that types are compatible */
+            u = pointed_size(&vtop[-1].type);
+            gen_opic(op);
+            /* set to integer type */
+#ifdef TCC_TARGET_X86_64
+            vtop->type.t = VT_LLONG;
+#else
+            vtop->type.t = VT_INT; 
+#endif
+            vpushi(u);
+            gen_op(TOK_PDIV);
+        } else {
+            /* exactly one pointer : must be '+' or '-'. */
+            if (op != '-' && op != '+')
+                error("cannot use pointers here");
+            /* Put pointer as first operand */
+            if (bt2 == VT_PTR) {
+                vswap();
+                swap(&t1, &t2);
+            }
+            type1 = vtop[-1].type;
+#ifdef TCC_TARGET_X86_64
+            vpushll(pointed_size(&vtop[-1].type));
+#else
+            /* XXX: cast to int ? (long long case) */
+            vpushi(pointed_size(&vtop[-1].type));
+#endif
+            gen_op('*');
+#ifdef CONFIG_TCC_BCHECK
+            /* if evaluating constant expression, no code should be
+               generated, so no bound check */
+            if (tcc_state->do_bounds_check && !const_wanted) {
+                /* if bounded pointers, we generate a special code to
+                   test bounds */
+                if (op == '-') {
+                    vpushi(0);
+                    vswap();
+                    gen_op('-');
+                }
+                gen_bounded_ptr_add();
+            } else
+#endif
+            {
+                gen_opic(op);
+            }
+            /* put again type if gen_opic() swaped operands */
+            vtop->type = type1;
+        }
+    } else if (is_float(bt1) || is_float(bt2)) {
+        /* compute bigger type and do implicit casts */
+        if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
+            t = VT_LDOUBLE;
+        } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
+            t = VT_DOUBLE;
+        } else {
+            t = VT_FLOAT;
+        }
+        /* floats can only be used for a few operations */
+        if (op != '+' && op != '-' && op != '*' && op != '/' &&
+            (op < TOK_ULT || op > TOK_GT))
+            error("invalid operands for binary operation");
+        goto std_op;
+    } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
+        /* cast to biggest op */
+        t = VT_LLONG;
+        /* convert to unsigned if it does not fit in a long long */
+        if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) ||
+            (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
+            t |= VT_UNSIGNED;
+        goto std_op;
+    } else {
+        /* integer operations */
+        t = VT_INT;
+        /* convert to unsigned if it does not fit in an integer */
+        if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) ||
+            (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
+            t |= VT_UNSIGNED;
+    std_op:
+        /* XXX: currently, some unsigned operations are explicit, so
+           we modify them here */
+        if (t & VT_UNSIGNED) {
+            if (op == TOK_SAR)
+                op = TOK_SHR;
+            else if (op == '/')
+                op = TOK_UDIV;
+            else if (op == '%')
+                op = TOK_UMOD;
+            else if (op == TOK_LT)
+                op = TOK_ULT;
+            else if (op == TOK_GT)
+                op = TOK_UGT;
+            else if (op == TOK_LE)
+                op = TOK_ULE;
+            else if (op == TOK_GE)
+                op = TOK_UGE;
+        }
+        vswap();
+        type1.t = t;
+        gen_cast(&type1);
+        vswap();
+        /* special case for shifts and long long: we keep the shift as
+           an integer */
+        if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL)
+            type1.t = VT_INT;
+        gen_cast(&type1);
+        if (is_float(t))
+            gen_opif(op);
+        else
+            gen_opic(op);
+        if (op >= TOK_ULT && op <= TOK_GT) {
+            /* relationnal op: the result is an int */
+            vtop->type.t = VT_INT;
+        } else {
+            vtop->type.t = t;
+        }
+    }
+}
+
+#ifndef TCC_TARGET_ARM
+/* generic itof for unsigned long long case */
+void gen_cvt_itof1(int t)
+{
+    if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == 
+        (VT_LLONG | VT_UNSIGNED)) {
+
+        if (t == VT_FLOAT)
+            vpush_global_sym(&func_old_type, TOK___floatundisf);
+#if LDOUBLE_SIZE != 8
+        else if (t == VT_LDOUBLE)
+            vpush_global_sym(&func_old_type, TOK___floatundixf);
+#endif
+        else
+            vpush_global_sym(&func_old_type, TOK___floatundidf);
+        vrott(2);
+        gfunc_call(1);
+        vpushi(0);
+        vtop->r = reg_fret(t);
+    } else {
+        gen_cvt_itof(t);
+    }
+}
+#endif
+
+/* generic ftoi for unsigned long long case */
+void gen_cvt_ftoi1(int t)
+{
+    int st;
+
+    if (t == (VT_LLONG | VT_UNSIGNED)) {
+        /* not handled natively */
+        st = vtop->type.t & VT_BTYPE;
+        if (st == VT_FLOAT)
+            vpush_global_sym(&func_old_type, TOK___fixunssfdi);
+#if LDOUBLE_SIZE != 8
+        else if (st == VT_LDOUBLE)
+            vpush_global_sym(&func_old_type, TOK___fixunsxfdi);
+#endif
+        else
+            vpush_global_sym(&func_old_type, TOK___fixunsdfdi);
+        vrott(2);
+        gfunc_call(1);
+        vpushi(0);
+        vtop->r = REG_IRET;
+        vtop->r2 = REG_LRET;
+    } else {
+        gen_cvt_ftoi(t);
+    }
+}
+
+/* force char or short cast */
+void force_charshort_cast(int t)
+{
+    int bits, dbt;
+    dbt = t & VT_BTYPE;
+    /* XXX: add optimization if lvalue : just change type and offset */
+    if (dbt == VT_BYTE)
+        bits = 8;
+    else
+        bits = 16;
+    if (t & VT_UNSIGNED) {
+        vpushi((1 << bits) - 1);
+        gen_op('&');
+    } else {
+        bits = 32 - bits;
+        vpushi(bits);
+        gen_op(TOK_SHL);
+        /* result must be signed or the SAR is converted to an SHL
+           This was not the case when "t" was a signed short
+           and the last value on the stack was an unsigned int */
+        vtop->type.t &= ~VT_UNSIGNED;
+        vpushi(bits);
+        gen_op(TOK_SAR);
+    }
+}
+
+/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */
+static void gen_cast(CType *type)
+{
+    int sbt, dbt, sf, df, c, p;
+
+    /* special delayed cast for char/short */
+    /* XXX: in some cases (multiple cascaded casts), it may still
+       be incorrect */
+    if (vtop->r & VT_MUSTCAST) {
+        vtop->r &= ~VT_MUSTCAST;
+        force_charshort_cast(vtop->type.t);
+    }
+
+    /* bitfields first get cast to ints */
+    if (vtop->type.t & VT_BITFIELD) {
+        gv(RC_INT);
+    }
+
+    dbt = type->t & (VT_BTYPE | VT_UNSIGNED);
+    sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED);
+
+    if (sbt != dbt) {
+        sf = is_float(sbt);
+        df = is_float(dbt);
+        c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+        p = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM);
+        if (c) {
+            /* constant case: we can do it now */
+            /* XXX: in ISOC, cannot do it if error in convert */
+            if (sbt == VT_FLOAT)
+                vtop->c.ld = vtop->c.f;
+            else if (sbt == VT_DOUBLE)
+                vtop->c.ld = vtop->c.d;
+
+            if (df) {
+                if ((sbt & VT_BTYPE) == VT_LLONG) {
+                    if (sbt & VT_UNSIGNED)
+                        vtop->c.ld = vtop->c.ull;
+                    else
+                        vtop->c.ld = vtop->c.ll;
+                } else if(!sf) {
+                    if (sbt & VT_UNSIGNED)
+                        vtop->c.ld = vtop->c.ui;
+                    else
+                        vtop->c.ld = vtop->c.i;
+                }
+
+                if (dbt == VT_FLOAT)
+                    vtop->c.f = (float)vtop->c.ld;
+                else if (dbt == VT_DOUBLE)
+                    vtop->c.d = (double)vtop->c.ld;
+            } else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) {
+                vtop->c.ull = (unsigned long long)vtop->c.ld;
+            } else if (sf && dbt == VT_BOOL) {
+                vtop->c.i = (vtop->c.ld != 0);
+            } else {
+                if(sf)
+                    vtop->c.ll = (long long)vtop->c.ld;
+                else if (sbt == (VT_LLONG|VT_UNSIGNED))
+                    vtop->c.ll = vtop->c.ull;
+                else if (sbt & VT_UNSIGNED)
+                    vtop->c.ll = vtop->c.ui;
+                else if (sbt != VT_LLONG)
+                    vtop->c.ll = vtop->c.i;
+
+                if (dbt == (VT_LLONG|VT_UNSIGNED))
+                    vtop->c.ull = vtop->c.ll;
+                else if (dbt == VT_BOOL)
+                    vtop->c.i = (vtop->c.ll != 0);
+                else if (dbt != VT_LLONG) {
+                    int s = 0;
+                    if ((dbt & VT_BTYPE) == VT_BYTE)
+                        s = 24;
+                    else if ((dbt & VT_BTYPE) == VT_SHORT)
+                        s = 16;
+
+                    if(dbt & VT_UNSIGNED)
+                        vtop->c.ui = ((unsigned int)vtop->c.ll << s) >> s;
+                    else
+                        vtop->c.i = ((int)vtop->c.ll << s) >> s;
+                }
+            }
+        } else if (p && dbt == VT_BOOL) {
+            vtop->r = VT_CONST;
+            vtop->c.i = 1;
+        } else if (!nocode_wanted) {
+            /* non constant case: generate code */
+            if (sf && df) {
+                /* convert from fp to fp */
+                gen_cvt_ftof(dbt);
+            } else if (df) {
+                /* convert int to fp */
+                gen_cvt_itof1(dbt);
+            } else if (sf) {
+                /* convert fp to int */
+                if (dbt == VT_BOOL) {
+                     vpushi(0);
+                     gen_op(TOK_NE);
+                } else {
+                    /* we handle char/short/etc... with generic code */
+                    if (dbt != (VT_INT | VT_UNSIGNED) &&
+                        dbt != (VT_LLONG | VT_UNSIGNED) &&
+                        dbt != VT_LLONG)
+                        dbt = VT_INT;
+                    gen_cvt_ftoi1(dbt);
+                    if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) {
+                        /* additional cast for char/short... */
+                        vtop->type.t = dbt;
+                        gen_cast(type);
+                    }
+                }
+#ifndef TCC_TARGET_X86_64
+            } else if ((dbt & VT_BTYPE) == VT_LLONG) {
+                if ((sbt & VT_BTYPE) != VT_LLONG) {
+                    /* scalar to long long */
+                    /* machine independent conversion */
+                    gv(RC_INT);
+                    /* generate high word */
+                    if (sbt == (VT_INT | VT_UNSIGNED)) {
+                        vpushi(0);
+                        gv(RC_INT);
+                    } else {
+                        if (sbt == VT_PTR) {
+                            /* cast from pointer to int before we apply
+                               shift operation, which pointers don't support*/
+                            gen_cast(&int_type);
+                        }
+                        gv_dup();
+                        vpushi(31);
+                        gen_op(TOK_SAR);
+                    }
+                    /* patch second register */
+                    vtop[-1].r2 = vtop->r;
+                    vpop();
+                }
+#else
+            } else if ((dbt & VT_BTYPE) == VT_LLONG ||
+                       (dbt & VT_BTYPE) == VT_PTR) {
+                /* XXX: not sure if this is perfect... need more tests */
+                if ((sbt & VT_BTYPE) != VT_LLONG) {
+                    int r = gv(RC_INT);
+                    if (sbt != (VT_INT | VT_UNSIGNED) &&
+                        sbt != VT_PTR && sbt != VT_FUNC) {
+                        /* x86_64 specific: movslq */
+                        o(0x6348);
+                        o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r));
+                    }
+                }
+#endif
+            } else if (dbt == VT_BOOL) {
+                /* scalar to bool */
+                vpushi(0);
+                gen_op(TOK_NE);
+            } else if ((dbt & VT_BTYPE) == VT_BYTE || 
+                       (dbt & VT_BTYPE) == VT_SHORT) {
+                if (sbt == VT_PTR) {
+                    vtop->type.t = VT_INT;
+                    warning("nonportable conversion from pointer to char/short");
+                }
+                force_charshort_cast(dbt);
+            } else if ((dbt & VT_BTYPE) == VT_INT) {
+                /* scalar to int */
+                if (sbt == VT_LLONG) {
+                    /* from long long: just take low order word */
+                    lexpand();
+                    vpop();
+                } 
+                /* if lvalue and single word type, nothing to do because
+                   the lvalue already contains the real type size (see
+                   VT_LVAL_xxx constants) */
+            }
+        }
+    } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) {
+        /* if we are casting between pointer types,
+           we must update the VT_LVAL_xxx size */
+        vtop->r = (vtop->r & ~VT_LVAL_TYPE)
+                  | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE);
+    }
+    vtop->type = *type;
+}
+
+/* return type size. Put alignment at 'a' */
+static int type_size(CType *type, int *a)
+{
+    Sym *s;
+    int bt;
+
+    bt = type->t & VT_BTYPE;
+    if (bt == VT_STRUCT) {
+        /* struct/union */
+        s = type->ref;
+        *a = s->r;
+        return s->c;
+    } else if (bt == VT_PTR) {
+        if (type->t & VT_ARRAY) {
+            int ts;
+
+            s = type->ref;
+            ts = type_size(&s->type, a);
+
+            if (ts < 0 && s->c < 0)
+                ts = -ts;
+
+            return ts * s->c;
+        } else {
+            *a = PTR_SIZE;
+            return PTR_SIZE;
+        }
+    } else if (bt == VT_LDOUBLE) {
+        *a = LDOUBLE_ALIGN;
+        return LDOUBLE_SIZE;
+    } else if (bt == VT_DOUBLE || bt == VT_LLONG) {
+#ifdef TCC_TARGET_I386
+#ifdef TCC_TARGET_PE
+        *a = 8;
+#else
+        *a = 4;
+#endif
+#elif defined(TCC_TARGET_ARM)
+#ifdef TCC_ARM_EABI
+        *a = 8; 
+#else
+        *a = 4;
+#endif
+#else
+        *a = 8;
+#endif
+        return 8;
+    } else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) {
+        *a = 4;
+        return 4;
+    } else if (bt == VT_SHORT) {
+        *a = 2;
+        return 2;
+    } else {
+        /* char, void, function, _Bool */
+        *a = 1;
+        return 1;
+    }
+}
+
+/* return the pointed type of t */
+static inline CType *pointed_type(CType *type)
+{
+    return &type->ref->type;
+}
+
+/* modify type so that its it is a pointer to type. */
+static void mk_pointer(CType *type)
+{
+    Sym *s;
+    s = sym_push(SYM_FIELD, type, 0, -1);
+    type->t = VT_PTR | (type->t & ~VT_TYPE);
+    type->ref = s;
+}
+
+/* compare function types. OLD functions match any new functions */
+static int is_compatible_func(CType *type1, CType *type2)
+{
+    Sym *s1, *s2;
+
+    s1 = type1->ref;
+    s2 = type2->ref;
+    if (!is_compatible_types(&s1->type, &s2->type))
+        return 0;
+    /* check func_call */
+    if (FUNC_CALL(s1->r) != FUNC_CALL(s2->r))
+        return 0;
+    /* XXX: not complete */
+    if (s1->c == FUNC_OLD || s2->c == FUNC_OLD)
+        return 1;
+    if (s1->c != s2->c)
+        return 0;
+    while (s1 != NULL) {
+        if (s2 == NULL)
+            return 0;
+        if (!is_compatible_parameter_types(&s1->type, &s2->type))
+            return 0;
+        s1 = s1->next;
+        s2 = s2->next;
+    }
+    if (s2)
+        return 0;
+    return 1;
+}
+
+/* return true if type1 and type2 are the same.  If unqualified is
+   true, qualifiers on the types are ignored.
+
+   - enums are not checked as gcc __builtin_types_compatible_p () 
+ */
+static int compare_types(CType *type1, CType *type2, int unqualified)
+{
+    int bt1, t1, t2;
+
+    t1 = type1->t & VT_TYPE;
+    t2 = type2->t & VT_TYPE;
+    if (unqualified) {
+        /* strip qualifiers before comparing */
+        t1 &= ~(VT_CONSTANT | VT_VOLATILE);
+        t2 &= ~(VT_CONSTANT | VT_VOLATILE);
+    }
+    /* XXX: bitfields ? */
+    if (t1 != t2)
+        return 0;
+    /* test more complicated cases */
+    bt1 = t1 & VT_BTYPE;
+    if (bt1 == VT_PTR) {
+        type1 = pointed_type(type1);
+        type2 = pointed_type(type2);
+        return is_compatible_types(type1, type2);
+    } else if (bt1 == VT_STRUCT) {
+        return (type1->ref == type2->ref);
+    } else if (bt1 == VT_FUNC) {
+        return is_compatible_func(type1, type2);
+    } else {
+        return 1;
+    }
+}
+
+/* return true if type1 and type2 are exactly the same (including
+   qualifiers). 
+*/
+static int is_compatible_types(CType *type1, CType *type2)
+{
+    return compare_types(type1,type2,0);
+}
+
+/* return true if type1 and type2 are the same (ignoring qualifiers).
+*/
+static int is_compatible_parameter_types(CType *type1, CType *type2)
+{
+    return compare_types(type1,type2,1);
+}
+
+/* print a type. If 'varstr' is not NULL, then the variable is also
+   printed in the type */
+/* XXX: union */
+/* XXX: add array and function pointers */
+void type_to_str(char *buf, int buf_size, 
+                 CType *type, const char *varstr)
+{
+    int bt, v, t;
+    Sym *s, *sa;
+    char buf1[256];
+    const char *tstr;
+
+    t = type->t & VT_TYPE;
+    bt = t & VT_BTYPE;
+    buf[0] = '\0';
+    if (t & VT_CONSTANT)
+        pstrcat(buf, buf_size, "const ");
+    if (t & VT_VOLATILE)
+        pstrcat(buf, buf_size, "volatile ");
+    if (t & VT_UNSIGNED)
+        pstrcat(buf, buf_size, "unsigned ");
+    switch(bt) {
+    case VT_VOID:
+        tstr = "void";
+        goto add_tstr;
+    case VT_BOOL:
+        tstr = "_Bool";
+        goto add_tstr;
+    case VT_BYTE:
+        tstr = "char";
+        goto add_tstr;
+    case VT_SHORT:
+        tstr = "short";
+        goto add_tstr;
+    case VT_INT:
+        tstr = "int";
+        goto add_tstr;
+    case VT_LONG:
+        tstr = "long";
+        goto add_tstr;
+    case VT_LLONG:
+        tstr = "long long";
+        goto add_tstr;
+    case VT_FLOAT:
+        tstr = "float";
+        goto add_tstr;
+    case VT_DOUBLE:
+        tstr = "double";
+        goto add_tstr;
+    case VT_LDOUBLE:
+        tstr = "long double";
+    add_tstr:
+        pstrcat(buf, buf_size, tstr);
+        break;
+    case VT_ENUM:
+    case VT_STRUCT:
+        if (bt == VT_STRUCT)
+            tstr = "struct ";
+        else
+            tstr = "enum ";
+        pstrcat(buf, buf_size, tstr);
+        v = type->ref->v & ~SYM_STRUCT;
+        if (v >= SYM_FIRST_ANOM)
+            pstrcat(buf, buf_size, "<anonymous>");
+        else
+            pstrcat(buf, buf_size, get_tok_str(v, NULL));
+        break;
+    case VT_FUNC:
+        s = type->ref;
+        type_to_str(buf, buf_size, &s->type, varstr);
+        pstrcat(buf, buf_size, "(");
+        sa = s->next;
+        while (sa != NULL) {
+            type_to_str(buf1, sizeof(buf1), &sa->type, NULL);
+            pstrcat(buf, buf_size, buf1);
+            sa = sa->next;
+            if (sa)
+                pstrcat(buf, buf_size, ", ");
+        }
+        pstrcat(buf, buf_size, ")");
+        goto no_var;
+    case VT_PTR:
+        s = type->ref;
+        pstrcpy(buf1, sizeof(buf1), "*");
+        if (varstr)
+            pstrcat(buf1, sizeof(buf1), varstr);
+        type_to_str(buf, buf_size, &s->type, buf1);
+        goto no_var;
+    }
+    if (varstr) {
+        pstrcat(buf, buf_size, " ");
+        pstrcat(buf, buf_size, varstr);
+    }
+ no_var: ;
+}
+
+/* verify type compatibility to store vtop in 'dt' type, and generate
+   casts if needed. */
+static void gen_assign_cast(CType *dt)
+{
+    CType *st, *type1, *type2, tmp_type1, tmp_type2;
+    char buf1[256], buf2[256];
+    int dbt, sbt;
+
+    st = &vtop->type; /* source type */
+    dbt = dt->t & VT_BTYPE;
+    sbt = st->t & VT_BTYPE;
+    if (dt->t & VT_CONSTANT)
+        warning("assignment of read-only location");
+    switch(dbt) {
+    case VT_PTR:
+        /* special cases for pointers */
+        /* '0' can also be a pointer */
+        if (is_null_pointer(vtop))
+            goto type_ok;
+        /* accept implicit pointer to integer cast with warning */
+        if (is_integer_btype(sbt)) {
+            warning("assignment makes pointer from integer without a cast");
+            goto type_ok;
+        }
+        type1 = pointed_type(dt);
+        /* a function is implicitly a function pointer */
+        if (sbt == VT_FUNC) {
+            if ((type1->t & VT_BTYPE) != VT_VOID &&
+                !is_compatible_types(pointed_type(dt), st))
+                goto error;
+            else
+                goto type_ok;
+        }
+        if (sbt != VT_PTR)
+            goto error;
+        type2 = pointed_type(st);
+        if ((type1->t & VT_BTYPE) == VT_VOID || 
+            (type2->t & VT_BTYPE) == VT_VOID) {
+            /* void * can match anything */
+        } else {
+            /* exact type match, except for unsigned */
+            tmp_type1 = *type1;
+            tmp_type2 = *type2;
+            tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
+            tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE);
+            if (!is_compatible_types(&tmp_type1, &tmp_type2))
+                warning("assignment from incompatible pointer type");
+        }
+        /* check const and volatile */
+        if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) ||
+            (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE)))
+            warning("assignment discards qualifiers from pointer target type");
+        break;
+    case VT_BYTE:
+    case VT_SHORT:
+    case VT_INT:
+    case VT_LLONG:
+        if (sbt == VT_PTR || sbt == VT_FUNC) {
+            warning("assignment makes integer from pointer without a cast");
+        }
+        /* XXX: more tests */
+        break;
+    case VT_STRUCT:
+        tmp_type1 = *dt;
+        tmp_type2 = *st;
+        tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
+        tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
+        if (!is_compatible_types(&tmp_type1, &tmp_type2)) {
+        error:
+            type_to_str(buf1, sizeof(buf1), st, NULL);
+            type_to_str(buf2, sizeof(buf2), dt, NULL);
+            error("cannot cast '%s' to '%s'", buf1, buf2);
+        }
+        break;
+    }
+ type_ok:
+    gen_cast(dt);
+}
+
+/* store vtop in lvalue pushed on stack */
+void vstore(void)
+{
+    int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast;
+
+    ft = vtop[-1].type.t;
+    sbt = vtop->type.t & VT_BTYPE;
+    dbt = ft & VT_BTYPE;
+    if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) ||
+        (sbt == VT_INT && dbt == VT_SHORT)) {
+        /* optimize char/short casts */
+        delayed_cast = VT_MUSTCAST;
+        vtop->type.t = ft & (VT_TYPE & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)));
+        /* XXX: factorize */
+        if (ft & VT_CONSTANT)
+            warning("assignment of read-only location");
+    } else {
+        delayed_cast = 0;
+        if (!(ft & VT_BITFIELD))
+            gen_assign_cast(&vtop[-1].type);
+    }
+
+    if (sbt == VT_STRUCT) {
+        /* if structure, only generate pointer */
+        /* structure assignment : generate memcpy */
+        /* XXX: optimize if small size */
+        if (!nocode_wanted) {
+            size = type_size(&vtop->type, &align);
+
+#ifdef TCC_ARM_EABI
+            if(!(align & 7))
+                vpush_global_sym(&func_old_type, TOK_memcpy8);
+            else if(!(align & 3))
+                vpush_global_sym(&func_old_type, TOK_memcpy4);
+            else
+#endif
+            vpush_global_sym(&func_old_type, TOK_memcpy);
+
+            /* destination */
+            vpushv(vtop - 2);
+            vtop->type.t = VT_PTR;
+            gaddrof();
+            /* source */
+            vpushv(vtop - 2);
+            vtop->type.t = VT_PTR;
+            gaddrof();
+            /* type size */
+            vpushi(size);
+            gfunc_call(3);
+            
+            vswap();
+            vpop();
+        } else {
+            vswap();
+            vpop();
+        }
+        /* leave source on stack */
+    } else if (ft & VT_BITFIELD) {
+        /* bitfield store handling */
+        bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f;
+        bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+        /* remove bit field info to avoid loops */
+        vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT));
+
+        /* duplicate source into other register */
+        gv_dup();
+        vswap();
+        vrott(3);
+
+        if((ft & VT_BTYPE) == VT_BOOL) {
+            gen_cast(&vtop[-1].type);
+            vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED);
+        }
+
+        /* duplicate destination */
+        vdup();
+        vtop[-1] = vtop[-2];
+
+        /* mask and shift source */
+        if((ft & VT_BTYPE) != VT_BOOL) {
+            if((ft & VT_BTYPE) == VT_LLONG) {
+                vpushll((1ULL << bit_size) - 1ULL);
+            } else {
+                vpushi((1 << bit_size) - 1);
+            }
+            gen_op('&');
+        }
+        vpushi(bit_pos);
+        gen_op(TOK_SHL);
+        /* load destination, mask and or with source */
+        vswap();
+        if((ft & VT_BTYPE) == VT_LLONG) {
+            vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos));
+        } else {
+            vpushi(~(((1 << bit_size) - 1) << bit_pos));
+        }
+        gen_op('&');
+        gen_op('|');
+        /* store result */
+        vstore();
+
+        /* pop off shifted source from "duplicate source..." above */
+        vpop();
+
+    } else {
+#ifdef CONFIG_TCC_BCHECK
+        /* bound check case */
+        if (vtop[-1].r & VT_MUSTBOUND) {
+            vswap();
+            gbound();
+            vswap();
+        }
+#endif
+        if (!nocode_wanted) {
+            rc = RC_INT;
+            if (is_float(ft)) {
+                rc = RC_FLOAT;
+#ifdef TCC_TARGET_X86_64
+                if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+                    rc = RC_ST0;
+                }
+#endif
+            }
+            r = gv(rc);  /* generate value */
+            /* if lvalue was saved on stack, must read it */
+            if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) {
+                SValue sv;
+                t = get_reg(RC_INT);
+#ifdef TCC_TARGET_X86_64
+                sv.type.t = VT_PTR;
+#else
+                sv.type.t = VT_INT;
+#endif
+                sv.r = VT_LOCAL | VT_LVAL;
+                sv.c.ul = vtop[-1].c.ul;
+                load(t, &sv);
+                vtop[-1].r = t | VT_LVAL;
+            }
+            store(r, vtop - 1);
+#ifndef TCC_TARGET_X86_64
+            /* two word case handling : store second register at word + 4 */
+            if ((ft & VT_BTYPE) == VT_LLONG) {
+                vswap();
+                /* convert to int to increment easily */
+                vtop->type.t = VT_INT;
+                gaddrof();
+                vpushi(4);
+                gen_op('+');
+                vtop->r |= VT_LVAL;
+                vswap();
+                /* XXX: it works because r2 is spilled last ! */
+                store(vtop->r2, vtop - 1);
+            }
+#endif
+        }
+        vswap();
+        vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
+        vtop->r |= delayed_cast;
+    }
+}
+
+/* post defines POST/PRE add. c is the token ++ or -- */
+void inc(int post, int c)
+{
+    test_lvalue();
+    vdup(); /* save lvalue */
+    if (post) {
+        gv_dup(); /* duplicate value */
+        vrotb(3);
+        vrotb(3);
+    }
+    /* add constant */
+    vpushi(c - TOK_MID); 
+    gen_op('+');
+    vstore(); /* store value */
+    if (post)
+        vpop(); /* if post op, return saved value */
+}
+
+/* Parse GNUC __attribute__ extension. Currently, the following
+   extensions are recognized:
+   - aligned(n) : set data/function alignment.
+   - packed : force data alignment to 1
+   - section(x) : generate data/code in this section.
+   - unused : currently ignored, but may be used someday.
+   - regparm(n) : pass function parameters in registers (i386 only)
+ */
+static void parse_attribute(AttributeDef *ad)
+{
+    int t, n;
+    
+    while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) {
+    next();
+    skip('(');
+    skip('(');
+    while (tok != ')') {
+        if (tok < TOK_IDENT)
+            expect("attribute name");
+        t = tok;
+        next();
+        switch(t) {
+        case TOK_SECTION1:
+        case TOK_SECTION2:
+            skip('(');
+            if (tok != TOK_STR)
+                expect("section name");
+            ad->section = find_section(tcc_state, (char *)tokc.cstr->data);
+            next();
+            skip(')');
+            break;
+        case TOK_ALIGNED1:
+        case TOK_ALIGNED2:
+            if (tok == '(') {
+                next();
+                n = expr_const();
+                if (n <= 0 || (n & (n - 1)) != 0) 
+                    error("alignment must be a positive power of two");
+                skip(')');
+            } else {
+                n = MAX_ALIGN;
+            }
+            ad->aligned = n;
+            break;
+        case TOK_PACKED1:
+        case TOK_PACKED2:
+            ad->packed = 1;
+            break;
+        case TOK_UNUSED1:
+        case TOK_UNUSED2:
+            /* currently, no need to handle it because tcc does not
+               track unused objects */
+            break;
+        case TOK_NORETURN1:
+        case TOK_NORETURN2:
+            /* currently, no need to handle it because tcc does not
+               track unused objects */
+            break;
+        case TOK_CDECL1:
+        case TOK_CDECL2:
+        case TOK_CDECL3:
+            FUNC_CALL(ad->func_attr) = FUNC_CDECL;
+            break;
+        case TOK_STDCALL1:
+        case TOK_STDCALL2:
+        case TOK_STDCALL3:
+            FUNC_CALL(ad->func_attr) = FUNC_STDCALL;
+            break;
+#ifdef TCC_TARGET_I386
+        case TOK_REGPARM1:
+        case TOK_REGPARM2:
+            skip('(');
+            n = expr_const();
+            if (n > 3) 
+                n = 3;
+            else if (n < 0)
+                n = 0;
+            if (n > 0)
+                FUNC_CALL(ad->func_attr) = FUNC_FASTCALL1 + n - 1;
+            skip(')');
+            break;
+        case TOK_FASTCALL1:
+        case TOK_FASTCALL2:
+        case TOK_FASTCALL3:
+            FUNC_CALL(ad->func_attr) = FUNC_FASTCALLW;
+            break;            
+#endif
+        case TOK_DLLEXPORT:
+            FUNC_EXPORT(ad->func_attr) = 1;
+            break;
+        default:
+            if (tcc_state->warn_unsupported)
+                warning("'%s' attribute ignored", get_tok_str(t, NULL));
+            /* skip parameters */
+            if (tok == '(') {
+                int parenthesis = 0;
+                do {
+                    if (tok == '(') 
+                        parenthesis++;
+                    else if (tok == ')') 
+                        parenthesis--;
+                    next();
+                } while (parenthesis && tok != -1);
+            }
+            break;
+        }
+        if (tok != ',')
+            break;
+        next();
+    }
+    skip(')');
+    skip(')');
+    }
+}
+
+/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
+static void struct_decl(CType *type, int u)
+{
+    int a, v, size, align, maxalign, c, offset;
+    int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt;
+    Sym *s, *ss, *ass, **ps;
+    AttributeDef ad;
+    CType type1, btype;
+
+    a = tok; /* save decl type */
+    next();
+    if (tok != '{') {
+        v = tok;
+        next();
+        /* struct already defined ? return it */
+        if (v < TOK_IDENT)
+            expect("struct/union/enum name");
+        s = struct_find(v);
+        if (s) {
+            if (s->type.t != a)
+                error("invalid type");
+            goto do_decl;
+        }
+    } else {
+        v = anon_sym++;
+    }
+    type1.t = a;
+    /* we put an undefined size for struct/union */
+    s = sym_push(v | SYM_STRUCT, &type1, 0, -1);
+    s->r = 0; /* default alignment is zero as gcc */
+    /* put struct/union/enum name in type */
+ do_decl:
+    type->t = u;
+    type->ref = s;
+    
+    if (tok == '{') {
+        next();
+        if (s->c != -1)
+            error("struct/union/enum already defined");
+        /* cannot be empty */
+        c = 0;
+        /* non empty enums are not allowed */
+        if (a == TOK_ENUM) {
+            for(;;) {
+                v = tok;
+                if (v < TOK_UIDENT)
+                    expect("identifier");
+                next();
+                if (tok == '=') {
+                    next();
+                    c = expr_const();
+                }
+                /* enum symbols have static storage */
+                ss = sym_push(v, &int_type, VT_CONST, c);
+                ss->type.t |= VT_STATIC;
+                if (tok != ',')
+                    break;
+                next();
+                c++;
+                /* NOTE: we accept a trailing comma */
+                if (tok == '}')
+                    break;
+            }
+            skip('}');
+        } else {
+            maxalign = 1;
+            ps = &s->next;
+            prevbt = VT_INT;
+            bit_pos = 0;
+            offset = 0;
+            while (tok != '}') {
+                parse_btype(&btype, &ad);
+                while (1) {
+                    bit_size = -1;
+                    v = 0;
+                    type1 = btype;
+                    if (tok != ':') {
+                        type_decl(&type1, &ad, &v, TYPE_DIRECT | TYPE_ABSTRACT);
+                        if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT)
+                            expect("identifier");
+                        if ((type1.t & VT_BTYPE) == VT_FUNC ||
+                            (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE)))
+                            error("invalid type for '%s'", 
+                                  get_tok_str(v, NULL));
+                    }
+                    if (tok == ':') {
+                        next();
+                        bit_size = expr_const();
+                        /* XXX: handle v = 0 case for messages */
+                        if (bit_size < 0)
+                            error("negative width in bit-field '%s'", 
+                                  get_tok_str(v, NULL));
+                        if (v && bit_size == 0)
+                            error("zero width for bit-field '%s'", 
+                                  get_tok_str(v, NULL));
+                    }
+                    size = type_size(&type1, &align);
+                    if (ad.aligned) {
+                        if (align < ad.aligned)
+                            align = ad.aligned;
+                    } else if (ad.packed) {
+                        align = 1;
+                    } else if (*tcc_state->pack_stack_ptr) {
+                        if (align > *tcc_state->pack_stack_ptr)
+                            align = *tcc_state->pack_stack_ptr;
+                    }
+                    lbit_pos = 0;
+                    if (bit_size >= 0) {
+                        bt = type1.t & VT_BTYPE;
+                        if (bt != VT_INT && 
+                            bt != VT_BYTE && 
+                            bt != VT_SHORT &&
+                            bt != VT_BOOL &&
+                            bt != VT_ENUM &&
+                            bt != VT_LLONG)
+                            error("bitfields must have scalar type");
+                        bsize = size * 8;
+                        if (bit_size > bsize) {
+                            error("width of '%s' exceeds its type",
+                                  get_tok_str(v, NULL));
+                        } else if (bit_size == bsize) {
+                            /* no need for bit fields */
+                            bit_pos = 0;
+                        } else if (bit_size == 0) {
+                            /* XXX: what to do if only padding in a
+                               structure ? */
+                            /* zero size: means to pad */
+                            bit_pos = 0;
+                        } else {
+                            /* we do not have enough room ?
+                               did the type change?
+                               is it a union? */
+                            if ((bit_pos + bit_size) > bsize ||
+                                bt != prevbt || a == TOK_UNION)
+                                bit_pos = 0;
+                            lbit_pos = bit_pos;
+                            /* XXX: handle LSB first */
+                            type1.t |= VT_BITFIELD | 
+                                (bit_pos << VT_STRUCT_SHIFT) |
+                                (bit_size << (VT_STRUCT_SHIFT + 6));
+                            bit_pos += bit_size;
+                        }
+                        prevbt = bt;
+                    } else {
+                        bit_pos = 0;
+                    }
+                    if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
+                        /* add new memory data only if starting
+                           bit field */
+                        if (lbit_pos == 0) {
+                            if (a == TOK_STRUCT) {
+                                c = (c + align - 1) & -align;
+                                offset = c;
+                                if (size > 0)
+                                    c += size;
+                            } else {
+                                offset = 0;
+                                if (size > c)
+                                    c = size;
+                            }
+                            if (align > maxalign)
+                                maxalign = align;
+                        }
+#if 0
+                        printf("add field %s offset=%d", 
+                               get_tok_str(v, NULL), offset);
+                        if (type1.t & VT_BITFIELD) {
+                            printf(" pos=%d size=%d", 
+                                   (type1.t >> VT_STRUCT_SHIFT) & 0x3f,
+                                   (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f);
+                        }
+                        printf("\n");
+#endif
+                    }
+                    if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) {
+                        ass = type1.ref;
+                        while ((ass = ass->next) != NULL) {
+                           ss = sym_push(ass->v, &ass->type, 0, offset + ass->c);
+                           *ps = ss;
+                           ps = &ss->next;
+                        }
+                    } else if (v) {
+                        ss = sym_push(v | SYM_FIELD, &type1, 0, offset);
+                        *ps = ss;
+                        ps = &ss->next;
+                    }
+                    if (tok == ';' || tok == TOK_EOF)
+                        break;
+                    skip(',');
+                }
+                skip(';');
+            }
+            skip('}');
+            /* store size and alignment */
+            s->c = (c + maxalign - 1) & -maxalign; 
+            s->r = maxalign;
+        }
+    }
+}
+
+/* return 0 if no type declaration. otherwise, return the basic type
+   and skip it. 
+ */
+static int parse_btype(CType *type, AttributeDef *ad)
+{
+    int t, u, type_found, typespec_found, typedef_found;
+    Sym *s;
+    CType type1;
+
+    memset(ad, 0, sizeof(AttributeDef));
+    type_found = 0;
+    typespec_found = 0;
+    typedef_found = 0;
+    t = 0;
+    while(1) {
+        switch(tok) {
+        case TOK_EXTENSION:
+            /* currently, we really ignore extension */
+            next();
+            continue;
+
+            /* basic types */
+        case TOK_CHAR:
+            u = VT_BYTE;
+        basic_type:
+            next();
+        basic_type1:
+            if ((t & VT_BTYPE) != 0)
+                error("too many basic types");
+            t |= u;
+            typespec_found = 1;
+            break;
+        case TOK_VOID:
+            u = VT_VOID;
+            goto basic_type;
+        case TOK_SHORT:
+            u = VT_SHORT;
+            goto basic_type;
+        case TOK_INT:
+            next();
+            typespec_found = 1;
+            break;
+        case TOK_LONG:
+            next();
+            if ((t & VT_BTYPE) == VT_DOUBLE) {
+                t = (t & ~VT_BTYPE) | VT_LDOUBLE;
+            } else if ((t & VT_BTYPE) == VT_LONG) {
+                t = (t & ~VT_BTYPE) | VT_LLONG;
+            } else {
+                u = VT_LONG;
+                goto basic_type1;
+            }
+            break;
+        case TOK_BOOL:
+            u = VT_BOOL;
+            goto basic_type;
+        case TOK_FLOAT:
+            u = VT_FLOAT;
+            goto basic_type;
+        case TOK_DOUBLE:
+            next();
+            if ((t & VT_BTYPE) == VT_LONG) {
+                t = (t & ~VT_BTYPE) | VT_LDOUBLE;
+            } else {
+                u = VT_DOUBLE;
+                goto basic_type1;
+            }
+            break;
+        case TOK_ENUM:
+            struct_decl(&type1, VT_ENUM);
+        basic_type2:
+            u = type1.t;
+            type->ref = type1.ref;
+            goto basic_type1;
+        case TOK_STRUCT:
+        case TOK_UNION:
+            struct_decl(&type1, VT_STRUCT);
+            goto basic_type2;
+
+            /* type modifiers */
+        case TOK_CONST1:
+        case TOK_CONST2:
+        case TOK_CONST3:
+            t |= VT_CONSTANT;
+            next();
+            break;
+        case TOK_VOLATILE1:
+        case TOK_VOLATILE2:
+        case TOK_VOLATILE3:
+            t |= VT_VOLATILE;
+            next();
+            break;
+        case TOK_SIGNED1:
+        case TOK_SIGNED2:
+        case TOK_SIGNED3:
+            typespec_found = 1;
+            t |= VT_SIGNED;
+            next();
+            break;
+        case TOK_REGISTER:
+        case TOK_AUTO:
+        case TOK_RESTRICT1:
+        case TOK_RESTRICT2:
+        case TOK_RESTRICT3:
+            next();
+            break;
+        case TOK_UNSIGNED:
+            t |= VT_UNSIGNED;
+            next();
+            typespec_found = 1;
+            break;
+
+            /* storage */
+        case TOK_EXTERN:
+            t |= VT_EXTERN;
+            next();
+            break;
+        case TOK_STATIC:
+            t |= VT_STATIC;
+            next();
+            break;
+        case TOK_TYPEDEF:
+            t |= VT_TYPEDEF;
+            next();
+            break;
+        case TOK_INLINE1:
+        case TOK_INLINE2:
+        case TOK_INLINE3:
+            t |= VT_INLINE;
+            next();
+            break;
+
+            /* GNUC attribute */
+        case TOK_ATTRIBUTE1:
+        case TOK_ATTRIBUTE2:
+            parse_attribute(ad);
+            break;
+            /* GNUC typeof */
+        case TOK_TYPEOF1:
+        case TOK_TYPEOF2:
+        case TOK_TYPEOF3:
+            next();
+            parse_expr_type(&type1);
+            goto basic_type2;
+        default:
+            if (typespec_found || typedef_found)
+                goto the_end;
+            s = sym_find(tok);
+            if (!s || !(s->type.t & VT_TYPEDEF))
+                goto the_end;
+            typedef_found = 1;
+            t |= (s->type.t & ~VT_TYPEDEF);
+            type->ref = s->type.ref;
+            next();
+            typespec_found = 1;
+            break;
+        }
+        type_found = 1;
+    }
+the_end:
+    if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED))
+        error("signed and unsigned modifier");
+    if (tcc_state->char_is_unsigned) {
+        if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE)
+            t |= VT_UNSIGNED;
+    }
+    t &= ~VT_SIGNED;
+
+    /* long is never used as type */
+    if ((t & VT_BTYPE) == VT_LONG)
+#ifndef TCC_TARGET_X86_64
+        t = (t & ~VT_BTYPE) | VT_INT;
+#else
+        t = (t & ~VT_BTYPE) | VT_LLONG;
+#endif
+    type->t = t;
+    return type_found;
+}
+
+/* convert a function parameter type (array to pointer and function to
+   function pointer) */
+static inline void convert_parameter_type(CType *pt)
+{
+    /* remove const and volatile qualifiers (XXX: const could be used
+       to indicate a const function parameter */
+    pt->t &= ~(VT_CONSTANT | VT_VOLATILE);
+    /* array must be transformed to pointer according to ANSI C */
+    pt->t &= ~VT_ARRAY;
+    if ((pt->t & VT_BTYPE) == VT_FUNC) {
+        mk_pointer(pt);
+    }
+}
+
+static void post_type(CType *type, AttributeDef *ad)
+{
+    int n, l, t1, arg_size, align;
+    Sym **plast, *s, *first;
+    AttributeDef ad1;
+    CType pt;
+
+    if (tok == '(') {
+        /* function declaration */
+        next();
+        l = 0;
+        first = NULL;
+        plast = &first;
+        arg_size = 0;
+        if (tok != ')') {
+            for(;;) {
+                /* read param name and compute offset */
+                if (l != FUNC_OLD) {
+                    if (!parse_btype(&pt, &ad1)) {
+                        if (l) {
+                            error("invalid type");
+                        } else {
+                            l = FUNC_OLD;
+                            goto old_proto;
+                        }
+                    }
+                    l = FUNC_NEW;
+                    if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')')
+                        break;
+                    type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT);
+                    if ((pt.t & VT_BTYPE) == VT_VOID)
+                        error("parameter declared as void");
+                    arg_size += (type_size(&pt, &align) + 3) & ~3;
+                } else {
+                old_proto:
+                    n = tok;
+                    if (n < TOK_UIDENT)
+                        expect("identifier");
+                    pt.t = VT_INT;
+                    next();
+                }
+                convert_parameter_type(&pt);
+                s = sym_push(n | SYM_FIELD, &pt, 0, 0);
+                *plast = s;
+                plast = &s->next;
+                if (tok == ')')
+                    break;
+                skip(',');
+                if (l == FUNC_NEW && tok == TOK_DOTS) {
+                    l = FUNC_ELLIPSIS;
+                    next();
+                    break;
+                }
+            }
+        }
+        /* if no parameters, then old type prototype */
+        if (l == 0)
+            l = FUNC_OLD;
+        skip(')');
+        t1 = type->t & VT_STORAGE;
+        /* NOTE: const is ignored in returned type as it has a special
+           meaning in gcc / C++ */
+        type->t &= ~(VT_STORAGE | VT_CONSTANT); 
+        post_type(type, ad);
+        /* we push a anonymous symbol which will contain the function prototype */
+        FUNC_ARGS(ad->func_attr) = arg_size;
+        s = sym_push(SYM_FIELD, type, ad->func_attr, l);
+        s->next = first;
+        type->t = t1 | VT_FUNC;
+        type->ref = s;
+    } else if (tok == '[') {
+        /* array definition */
+        next();
+        if (tok == TOK_RESTRICT1)
+            next();
+        n = -1;
+        if (tok != ']') {
+            n = expr_const();
+            if (n < 0)
+                error("invalid array size");    
+        }
+        skip(']');
+        /* parse next post type */
+        t1 = type->t & VT_STORAGE;
+        type->t &= ~VT_STORAGE;
+        post_type(type, ad);
+        
+        /* we push a anonymous symbol which will contain the array
+           element type */
+        s = sym_push(SYM_FIELD, type, 0, n);
+        type->t = t1 | VT_ARRAY | VT_PTR;
+        type->ref = s;
+    }
+}
+
+/* Parse a type declaration (except basic type), and return the type
+   in 'type'. 'td' is a bitmask indicating which kind of type decl is
+   expected. 'type' should contain the basic type. 'ad' is the
+   attribute definition of the basic type. It can be modified by
+   type_decl(). 
+ */
+static void type_decl(CType *type, AttributeDef *ad, int *v, int td)
+{
+    Sym *s;
+    CType type1, *type2;
+    int qualifiers;
+    
+    while (tok == '*') {
+        qualifiers = 0;
+    redo:
+        next();
+        switch(tok) {
+        case TOK_CONST1:
+        case TOK_CONST2:
+        case TOK_CONST3:
+            qualifiers |= VT_CONSTANT;
+            goto redo;
+        case TOK_VOLATILE1:
+        case TOK_VOLATILE2:
+        case TOK_VOLATILE3:
+            qualifiers |= VT_VOLATILE;
+            goto redo;
+        case TOK_RESTRICT1:
+        case TOK_RESTRICT2:
+        case TOK_RESTRICT3:
+            goto redo;
+        }
+        mk_pointer(type);
+        type->t |= qualifiers;
+    }
+    
+    /* XXX: clarify attribute handling */
+    if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
+        parse_attribute(ad);
+
+    /* recursive type */
+    /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */
+    type1.t = 0; /* XXX: same as int */
+    if (tok == '(') {
+        next();
+        /* XXX: this is not correct to modify 'ad' at this point, but
+           the syntax is not clear */
+        if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
+            parse_attribute(ad);
+        type_decl(&type1, ad, v, td);
+        skip(')');
+    } else {
+        /* type identifier */
+        if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) {
+            *v = tok;
+            next();
+        } else {
+            if (!(td & TYPE_ABSTRACT))
+                expect("identifier");
+            *v = 0;
+        }
+    }
+    post_type(type, ad);
+    if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2)
+        parse_attribute(ad);
+    if (!type1.t)
+        return;
+    /* append type at the end of type1 */
+    type2 = &type1;
+    for(;;) {
+        s = type2->ref;
+        type2 = &s->type;
+        if (!type2->t) {
+            *type2 = *type;
+            break;
+        }
+    }
+    *type = type1;
+}
+
+/* compute the lvalue VT_LVAL_xxx needed to match type t. */
+static int lvalue_type(int t)
+{
+    int bt, r;
+    r = VT_LVAL;
+    bt = t & VT_BTYPE;
+    if (bt == VT_BYTE || bt == VT_BOOL)
+        r |= VT_LVAL_BYTE;
+    else if (bt == VT_SHORT)
+        r |= VT_LVAL_SHORT;
+    else
+        return r;
+    if (t & VT_UNSIGNED)
+        r |= VT_LVAL_UNSIGNED;
+    return r;
+}
+
+/* indirection with full error checking and bound check */
+static void indir(void)
+{
+    if ((vtop->type.t & VT_BTYPE) != VT_PTR) {
+        if ((vtop->type.t & VT_BTYPE) == VT_FUNC)
+            return;
+        expect("pointer");
+    }
+    if ((vtop->r & VT_LVAL) && !nocode_wanted)
+        gv(RC_INT);
+    vtop->type = *pointed_type(&vtop->type);
+    /* Arrays and functions are never lvalues */
+    if (!(vtop->type.t & VT_ARRAY)
+        && (vtop->type.t & VT_BTYPE) != VT_FUNC) {
+        vtop->r |= lvalue_type(vtop->type.t);
+        /* if bound checking, the referenced pointer must be checked */
+        if (tcc_state->do_bounds_check)
+            vtop->r |= VT_MUSTBOUND;
+    }
+}
+
+/* pass a parameter to a function and do type checking and casting */
+static void gfunc_param_typed(Sym *func, Sym *arg)
+{
+    int func_type;
+    CType type;
+
+    func_type = func->c;
+    if (func_type == FUNC_OLD ||
+        (func_type == FUNC_ELLIPSIS && arg == NULL)) {
+        /* default casting : only need to convert float to double */
+        if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) {
+            type.t = VT_DOUBLE;
+            gen_cast(&type);
+        }
+    } else if (arg == NULL) {
+        error("too many arguments to function");
+    } else {
+        type = arg->type;
+        type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
+        gen_assign_cast(&type);
+    }
+}
+
+/* parse an expression of the form '(type)' or '(expr)' and return its
+   type */
+static void parse_expr_type(CType *type)
+{
+    int n;
+    AttributeDef ad;
+
+    skip('(');
+    if (parse_btype(type, &ad)) {
+        type_decl(type, &ad, &n, TYPE_ABSTRACT);
+    } else {
+        expr_type(type);
+    }
+    skip(')');
+}
+
+static void parse_type(CType *type)
+{
+    AttributeDef ad;
+    int n;
+
+    if (!parse_btype(type, &ad)) {
+        expect("type");
+    }
+    type_decl(type, &ad, &n, TYPE_ABSTRACT);
+}
+
+static void vpush_tokc(int t)
+{
+    CType type;
+    type.t = t;
+    vsetc(&type, VT_CONST, &tokc);
+}
+
+static void unary(void)
+{
+    int n, t, align, size, r;
+    CType type;
+    Sym *s;
+    AttributeDef ad;
+
+    /* XXX: GCC 2.95.3 does not generate a table although it should be
+       better here */
+ tok_next:
+    switch(tok) {
+    case TOK_EXTENSION:
+        next();
+        goto tok_next;
+    case TOK_CINT:
+    case TOK_CCHAR: 
+    case TOK_LCHAR:
+        vpushi(tokc.i);
+        next();
+        break;
+    case TOK_CUINT:
+        vpush_tokc(VT_INT | VT_UNSIGNED);
+        next();
+        break;
+    case TOK_CLLONG:
+        vpush_tokc(VT_LLONG);
+        next();
+        break;
+    case TOK_CULLONG:
+        vpush_tokc(VT_LLONG | VT_UNSIGNED);
+        next();
+        break;
+    case TOK_CFLOAT:
+        vpush_tokc(VT_FLOAT);
+        next();
+        break;
+    case TOK_CDOUBLE:
+        vpush_tokc(VT_DOUBLE);
+        next();
+        break;
+    case TOK_CLDOUBLE:
+        vpush_tokc(VT_LDOUBLE);
+        next();
+        break;
+    case TOK___FUNCTION__:
+        if (!gnu_ext)
+            goto tok_identifier;
+        /* fall thru */
+    case TOK___FUNC__:
+        {
+            void *ptr;
+            int len;
+            /* special function name identifier */
+            len = strlen(funcname) + 1;
+            /* generate char[len] type */
+            type.t = VT_BYTE;
+            mk_pointer(&type);
+            type.t |= VT_ARRAY;
+            type.ref->c = len;
+            vpush_ref(&type, data_section, data_section->data_offset, len);
+            ptr = section_ptr_add(data_section, len);
+            memcpy(ptr, funcname, len);
+            next();
+        }
+        break;
+    case TOK_LSTR:
+#ifdef TCC_TARGET_PE
+        t = VT_SHORT | VT_UNSIGNED;
+#else
+        t = VT_INT;
+#endif
+        goto str_init;
+    case TOK_STR:
+        /* string parsing */
+        t = VT_BYTE;
+    str_init:
+        if (tcc_state->warn_write_strings)
+            t |= VT_CONSTANT;
+        type.t = t;
+        mk_pointer(&type);
+        type.t |= VT_ARRAY;
+        memset(&ad, 0, sizeof(AttributeDef));
+        decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0);
+        break;
+    case '(':
+        next();
+        /* cast ? */
+        if (parse_btype(&type, &ad)) {
+            type_decl(&type, &ad, &n, TYPE_ABSTRACT);
+            skip(')');
+            /* check ISOC99 compound literal */
+            if (tok == '{') {
+                    /* data is allocated locally by default */
+                if (global_expr)
+                    r = VT_CONST;
+                else
+                    r = VT_LOCAL;
+                /* all except arrays are lvalues */
+                if (!(type.t & VT_ARRAY))
+                    r |= lvalue_type(type.t);
+                memset(&ad, 0, sizeof(AttributeDef));
+                decl_initializer_alloc(&type, &ad, r, 1, 0, 0);
+            } else {
+                unary();
+                gen_cast(&type);
+            }
+        } else if (tok == '{') {
+            /* save all registers */
+            save_regs(0); 
+            /* statement expression : we do not accept break/continue
+               inside as GCC does */
+            block(NULL, NULL, NULL, NULL, 0, 1);
+            skip(')');
+        } else {
+            gexpr();
+            skip(')');
+        }
+        break;
+    case '*':
+        next();
+        unary();
+        indir();
+        break;
+    case '&':
+        next();
+        unary();
+        /* functions names must be treated as function pointers,
+           except for unary '&' and sizeof. Since we consider that
+           functions are not lvalues, we only have to handle it
+           there and in function calls. */
+        /* arrays can also be used although they are not lvalues */
+        if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
+            !(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_LLOCAL))
+            test_lvalue();
+        mk_pointer(&vtop->type);
+        gaddrof();
+        break;
+    case '!':
+        next();
+        unary();
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            CType boolean;
+            boolean.t = VT_BOOL;
+            gen_cast(&boolean);
+            vtop->c.i = !vtop->c.i;
+        } else if ((vtop->r & VT_VALMASK) == VT_CMP)
+            vtop->c.i = vtop->c.i ^ 1;
+        else {
+            save_regs(1);
+            vseti(VT_JMP, gtst(1, 0));
+        }
+        break;
+    case '~':
+        next();
+        unary();
+        vpushi(-1);
+        gen_op('^');
+        break;
+    case '+':
+        next();
+        /* in order to force cast, we add zero */
+        unary();
+        if ((vtop->type.t & VT_BTYPE) == VT_PTR)
+            error("pointer not accepted for unary plus");
+        vpushi(0);
+        gen_op('+');
+        break;
+    case TOK_SIZEOF:
+    case TOK_ALIGNOF1:
+    case TOK_ALIGNOF2:
+        t = tok;
+        next();
+        if (tok == '(') {
+            parse_expr_type(&type);
+        } else {
+            unary_type(&type);
+        }
+        size = type_size(&type, &align);
+        if (t == TOK_SIZEOF) {
+            if (size < 0)
+                error("sizeof applied to an incomplete type");
+            vpushi(size);
+        } else {
+            vpushi(align);
+        }
+        vtop->type.t |= VT_UNSIGNED;
+        break;
+
+    case TOK_builtin_types_compatible_p:
+        {
+            CType type1, type2;
+            next();
+            skip('(');
+            parse_type(&type1);
+            skip(',');
+            parse_type(&type2);
+            skip(')');
+            type1.t &= ~(VT_CONSTANT | VT_VOLATILE);
+            type2.t &= ~(VT_CONSTANT | VT_VOLATILE);
+            vpushi(is_compatible_types(&type1, &type2));
+        }
+        break;
+    case TOK_builtin_constant_p:
+        {
+            int saved_nocode_wanted, res;
+            next();
+            skip('(');
+            saved_nocode_wanted = nocode_wanted;
+            nocode_wanted = 1;
+            gexpr();
+            res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
+            vpop();
+            nocode_wanted = saved_nocode_wanted;
+            skip(')');
+            vpushi(res);
+        }
+        break;
+    case TOK_builtin_frame_address:
+        {
+            CType type;
+            next();
+            skip('(');
+            if (tok != TOK_CINT) {
+                error("__builtin_frame_address only takes integers");
+            }
+            if (tokc.i != 0) {
+                error("TCC only supports __builtin_frame_address(0)");
+            }
+            next();
+            skip(')');
+            type.t = VT_VOID;
+            mk_pointer(&type);
+            vset(&type, VT_LOCAL, 0);
+        }
+        break;
+#ifdef TCC_TARGET_X86_64
+    case TOK_builtin_malloc:
+        tok = TOK_malloc;
+        goto tok_identifier;
+    case TOK_builtin_free:
+        tok = TOK_free;
+        goto tok_identifier;
+#endif
+    case TOK_INC:
+    case TOK_DEC:
+        t = tok;
+        next();
+        unary();
+        inc(0, t);
+        break;
+    case '-':
+        next();
+        vpushi(0);
+        unary();
+        gen_op('-');
+        break;
+    case TOK_LAND:
+        if (!gnu_ext)
+            goto tok_identifier;
+        next();
+        /* allow to take the address of a label */
+        if (tok < TOK_UIDENT)
+            expect("label identifier");
+        s = label_find(tok);
+        if (!s) {
+            s = label_push(&global_label_stack, tok, LABEL_FORWARD);
+        } else {
+            if (s->r == LABEL_DECLARED)
+                s->r = LABEL_FORWARD;
+        }
+        if (!s->type.t) {
+            s->type.t = VT_VOID;
+            mk_pointer(&s->type);
+            s->type.t |= VT_STATIC;
+        }
+        vset(&s->type, VT_CONST | VT_SYM, 0);
+        vtop->sym = s;
+        next();
+        break;
+    default:
+    tok_identifier:
+        t = tok;
+        next();
+        if (t < TOK_UIDENT)
+            expect("identifier");
+        s = sym_find(t);
+        if (!s) {
+            if (tok != '(')
+                error("'%s' undeclared", get_tok_str(t, NULL));
+            /* for simple function calls, we tolerate undeclared
+               external reference to int() function */
+            if (tcc_state->warn_implicit_function_declaration)
+                warning("implicit declaration of function '%s'",
+                        get_tok_str(t, NULL));
+            s = external_global_sym(t, &func_old_type, 0); 
+        }
+        if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) ==
+            (VT_STATIC | VT_INLINE | VT_FUNC)) {
+            /* if referencing an inline function, then we generate a
+               symbol to it if not already done. It will have the
+               effect to generate code for it at the end of the
+               compilation unit. Inline function as always
+               generated in the text section. */
+            if (!s->c)
+                put_extern_sym(s, text_section, 0, 0);
+            r = VT_SYM | VT_CONST;
+        } else {
+            r = s->r;
+        }
+        vset(&s->type, r, s->c);
+        /* if forward reference, we must point to s */
+        if (vtop->r & VT_SYM) {
+            vtop->sym = s;
+            vtop->c.ul = 0;
+        }
+        break;
+    }
+    
+    /* post operations */
+    while (1) {
+        if (tok == TOK_INC || tok == TOK_DEC) {
+            inc(1, tok);
+            next();
+        } else if (tok == '.' || tok == TOK_ARROW) {
+            /* field */ 
+            if (tok == TOK_ARROW) 
+                indir();
+            test_lvalue();
+            gaddrof();
+            next();
+            /* expect pointer on structure */
+            if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)
+                expect("struct or union");
+            s = vtop->type.ref;
+            /* find field */
+            tok |= SYM_FIELD;
+            while ((s = s->next) != NULL) {
+                if (s->v == tok)
+                    break;
+            }
+            if (!s)
+                error("field not found: %s",  get_tok_str(tok & ~SYM_FIELD, NULL));
+            /* add field offset to pointer */
+            vtop->type = char_pointer_type; /* change type to 'char *' */
+            vpushi(s->c);
+            gen_op('+');
+            /* change type to field type, and set to lvalue */
+            vtop->type = s->type;
+            /* an array is never an lvalue */
+            if (!(vtop->type.t & VT_ARRAY)) {
+                vtop->r |= lvalue_type(vtop->type.t);
+                /* if bound checking, the referenced pointer must be checked */
+                if (tcc_state->do_bounds_check)
+                    vtop->r |= VT_MUSTBOUND;
+            }
+            next();
+        } else if (tok == '[') {
+            next();
+            gexpr();
+            gen_op('+');
+            indir();
+            skip(']');
+        } else if (tok == '(') {
+            SValue ret;
+            Sym *sa;
+            int nb_args;
+
+            /* function call  */
+            if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
+                /* pointer test (no array accepted) */
+                if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) {
+                    vtop->type = *pointed_type(&vtop->type);
+                    if ((vtop->type.t & VT_BTYPE) != VT_FUNC)
+                        goto error_func;
+                } else {
+                error_func:
+                    expect("function pointer");
+                }
+            } else {
+                vtop->r &= ~VT_LVAL; /* no lvalue */
+            }
+            /* get return type */
+            s = vtop->type.ref;
+            next();
+            sa = s->next; /* first parameter */
+            nb_args = 0;
+            ret.r2 = VT_CONST;
+            /* compute first implicit argument if a structure is returned */
+            if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
+                /* get some space for the returned structure */
+                size = type_size(&s->type, &align);
+                loc = (loc - size) & -align;
+                ret.type = s->type;
+                ret.r = VT_LOCAL | VT_LVAL;
+                /* pass it as 'int' to avoid structure arg passing
+                   problems */
+                vseti(VT_LOCAL, loc);
+                ret.c = vtop->c;
+                nb_args++;
+            } else {
+                ret.type = s->type; 
+                /* return in register */
+                if (is_float(ret.type.t)) {
+                    ret.r = reg_fret(ret.type.t);
+                } else {
+                    if ((ret.type.t & VT_BTYPE) == VT_LLONG)
+                        ret.r2 = REG_LRET;
+                    ret.r = REG_IRET;
+                }
+                ret.c.i = 0;
+            }
+            if (tok != ')') {
+                for(;;) {
+                    expr_eq();
+                    gfunc_param_typed(s, sa);
+                    nb_args++;
+                    if (sa)
+                        sa = sa->next;
+                    if (tok == ')')
+                        break;
+                    skip(',');
+                }
+            }
+            if (sa)
+                error("too few arguments to function");
+            skip(')');
+            if (!nocode_wanted) {
+                gfunc_call(nb_args);
+            } else {
+                vtop -= (nb_args + 1);
+            }
+            /* return value */
+            vsetc(&ret.type, ret.r, &ret.c);
+            vtop->r2 = ret.r2;
+        } else {
+            break;
+        }
+    }
+}
+
+static void uneq(void)
+{
+    int t;
+    
+    unary();
+    if (tok == '=' ||
+        (tok >= TOK_A_MOD && tok <= TOK_A_DIV) ||
+        tok == TOK_A_XOR || tok == TOK_A_OR ||
+        tok == TOK_A_SHL || tok == TOK_A_SAR) {
+        test_lvalue();
+        t = tok;
+        next();
+        if (t == '=') {
+            expr_eq();
+        } else {
+            vdup();
+            expr_eq();
+            gen_op(t & 0x7f);
+        }
+        vstore();
+    }
+}
+
+static void expr_prod(void)
+{
+    int t;
+
+    uneq();
+    while (tok == '*' || tok == '/' || tok == '%') {
+        t = tok;
+        next();
+        uneq();
+        gen_op(t);
+    }
+}
+
+static void expr_sum(void)
+{
+    int t;
+
+    expr_prod();
+    while (tok == '+' || tok == '-') {
+        t = tok;
+        next();
+        expr_prod();
+        gen_op(t);
+    }
+}
+
+static void expr_shift(void)
+{
+    int t;
+
+    expr_sum();
+    while (tok == TOK_SHL || tok == TOK_SAR) {
+        t = tok;
+        next();
+        expr_sum();
+        gen_op(t);
+    }
+}
+
+static void expr_cmp(void)
+{
+    int t;
+
+    expr_shift();
+    while ((tok >= TOK_ULE && tok <= TOK_GT) ||
+           tok == TOK_ULT || tok == TOK_UGE) {
+        t = tok;
+        next();
+        expr_shift();
+        gen_op(t);
+    }
+}
+
+static void expr_cmpeq(void)
+{
+    int t;
+
+    expr_cmp();
+    while (tok == TOK_EQ || tok == TOK_NE) {
+        t = tok;
+        next();
+        expr_cmp();
+        gen_op(t);
+    }
+}
+
+static void expr_and(void)
+{
+    expr_cmpeq();
+    while (tok == '&') {
+        next();
+        expr_cmpeq();
+        gen_op('&');
+    }
+}
+
+static void expr_xor(void)
+{
+    expr_and();
+    while (tok == '^') {
+        next();
+        expr_and();
+        gen_op('^');
+    }
+}
+
+static void expr_or(void)
+{
+    expr_xor();
+    while (tok == '|') {
+        next();
+        expr_xor();
+        gen_op('|');
+    }
+}
+
+/* XXX: fix this mess */
+static void expr_land_const(void)
+{
+    expr_or();
+    while (tok == TOK_LAND) {
+        next();
+        expr_or();
+        gen_op(TOK_LAND);
+    }
+}
+
+/* XXX: fix this mess */
+static void expr_lor_const(void)
+{
+    expr_land_const();
+    while (tok == TOK_LOR) {
+        next();
+        expr_land_const();
+        gen_op(TOK_LOR);
+    }
+}
+
+/* only used if non constant */
+static void expr_land(void)
+{
+    int t;
+
+    expr_or();
+    if (tok == TOK_LAND) {
+        t = 0;
+        save_regs(1);
+        for(;;) {
+            t = gtst(1, t);
+            if (tok != TOK_LAND) {
+                vseti(VT_JMPI, t);
+                break;
+            }
+            next();
+            expr_or();
+        }
+    }
+}
+
+static void expr_lor(void)
+{
+    int t;
+
+    expr_land();
+    if (tok == TOK_LOR) {
+        t = 0;
+        save_regs(1);
+        for(;;) {
+            t = gtst(0, t);
+            if (tok != TOK_LOR) {
+                vseti(VT_JMP, t);
+                break;
+            }
+            next();
+            expr_land();
+        }
+    }
+}
+
+/* XXX: better constant handling */
+static void expr_eq(void)
+{
+    int tt, u, r1, r2, rc, t1, t2, bt1, bt2;
+    SValue sv;
+    CType type, type1, type2;
+
+    if (const_wanted) {
+        expr_lor_const();
+        if (tok == '?') {
+            CType boolean;
+            int c;
+            boolean.t = VT_BOOL;
+            vdup();
+            gen_cast(&boolean);
+            c = vtop->c.i;
+            vpop();
+            next();
+            if (tok != ':' || !gnu_ext) {
+                vpop();
+                gexpr();
+            }
+            if (!c)
+                vpop();
+            skip(':');
+            expr_eq();
+            if (c)
+                vpop();
+        }
+    } else {
+        expr_lor();
+        if (tok == '?') {
+            next();
+            if (vtop != vstack) {
+                /* needed to avoid having different registers saved in
+                   each branch */
+                if (is_float(vtop->type.t)) {
+                    rc = RC_FLOAT;
+#ifdef TCC_TARGET_X86_64
+                    if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+                        rc = RC_ST0;
+                    }
+#endif
+                }
+                else
+                    rc = RC_INT;
+                    gv(rc);
+                    save_regs(1);
+            }
+            if (tok == ':' && gnu_ext) {
+                gv_dup();
+                tt = gtst(1, 0);
+            } else {
+                tt = gtst(1, 0);
+                gexpr();
+            }
+            type1 = vtop->type;
+            sv = *vtop; /* save value to handle it later */
+            vtop--; /* no vpop so that FP stack is not flushed */
+            skip(':');
+            u = gjmp(0);
+            gsym(tt);
+            expr_eq();
+            type2 = vtop->type;
+
+            t1 = type1.t;
+            bt1 = t1 & VT_BTYPE;
+            t2 = type2.t;
+            bt2 = t2 & VT_BTYPE;
+            /* cast operands to correct type according to ISOC rules */
+            if (is_float(bt1) || is_float(bt2)) {
+                if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) {
+                    type.t = VT_LDOUBLE;
+                } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) {
+                    type.t = VT_DOUBLE;
+                } else {
+                    type.t = VT_FLOAT;
+                }
+            } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
+                /* cast to biggest op */
+                type.t = VT_LLONG;
+                /* convert to unsigned if it does not fit in a long long */
+                if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) ||
+                    (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
+                    type.t |= VT_UNSIGNED;
+            } else if (bt1 == VT_PTR || bt2 == VT_PTR) {
+                /* XXX: test pointer compatibility */
+                type = type1;
+            } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
+                /* XXX: test function pointer compatibility */
+                type = type1;
+            } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
+                /* XXX: test structure compatibility */
+                type = type1;
+            } else if (bt1 == VT_VOID || bt2 == VT_VOID) {
+                /* NOTE: as an extension, we accept void on only one side */
+                type.t = VT_VOID;
+            } else {
+                /* integer operations */
+                type.t = VT_INT;
+                /* convert to unsigned if it does not fit in an integer */
+                if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) ||
+                    (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
+                    type.t |= VT_UNSIGNED;
+            }
+                
+            /* now we convert second operand */
+            gen_cast(&type);
+            if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
+                gaddrof();
+            rc = RC_INT;
+            if (is_float(type.t)) {
+                rc = RC_FLOAT;
+#ifdef TCC_TARGET_X86_64
+                if ((type.t & VT_BTYPE) == VT_LDOUBLE) {
+                    rc = RC_ST0;
+                }
+#endif
+            } else if ((type.t & VT_BTYPE) == VT_LLONG) {
+                /* for long longs, we use fixed registers to avoid having
+                   to handle a complicated move */
+                rc = RC_IRET; 
+            }
+            
+            r2 = gv(rc);
+            /* this is horrible, but we must also convert first
+               operand */
+            tt = gjmp(0);
+            gsym(u);
+            /* put again first value and cast it */
+            *vtop = sv;
+            gen_cast(&type);
+            if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
+                gaddrof();
+            r1 = gv(rc);
+            move_reg(r2, r1);
+            vtop->r = r2;
+            gsym(tt);
+        }
+    }
+}
+
+static void gexpr(void)
+{
+    while (1) {
+        expr_eq();
+        if (tok != ',')
+            break;
+        vpop();
+        next();
+    }
+}
+
+/* parse an expression and return its type without any side effect. */
+static void expr_type(CType *type)
+{
+    int saved_nocode_wanted;
+
+    saved_nocode_wanted = nocode_wanted;
+    nocode_wanted = 1;
+    gexpr();
+    *type = vtop->type;
+    vpop();
+    nocode_wanted = saved_nocode_wanted;
+}
+
+/* parse a unary expression and return its type without any side
+   effect. */
+static void unary_type(CType *type)
+{
+    int a;
+
+    a = nocode_wanted;
+    nocode_wanted = 1;
+    unary();
+    *type = vtop->type;
+    vpop();
+    nocode_wanted = a;
+}
+
+/* parse a constant expression and return value in vtop.  */
+static void expr_const1(void)
+{
+    int a;
+    a = const_wanted;
+    const_wanted = 1;
+    expr_eq();
+    const_wanted = a;
+}
+
+/* parse an integer constant and return its value. */
+static int expr_const(void)
+{
+    int c;
+    expr_const1();
+    if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
+        expect("constant expression");
+    c = vtop->c.i;
+    vpop();
+    return c;
+}
+
+/* return the label token if current token is a label, otherwise
+   return zero */
+static int is_label(void)
+{
+    int last_tok;
+
+    /* fast test first */
+    if (tok < TOK_UIDENT)
+        return 0;
+    /* no need to save tokc because tok is an identifier */
+    last_tok = tok;
+    next();
+    if (tok == ':') {
+        next();
+        return last_tok;
+    } else {
+        unget_tok(last_tok);
+        return 0;
+    }
+}
+
+static void block(int *bsym, int *csym, int *case_sym, int *def_sym, 
+                  int case_reg, int is_expr)
+{
+    int a, b, c, d;
+    Sym *s;
+
+    /* generate line number info */
+    if (tcc_state->do_debug &&
+        (last_line_num != file->line_num || last_ind != ind)) {
+        put_stabn(N_SLINE, 0, file->line_num, ind - func_ind);
+        last_ind = ind;
+        last_line_num = file->line_num;
+    }
+
+    if (is_expr) {
+        /* default return value is (void) */
+        vpushi(0);
+        vtop->type.t = VT_VOID;
+    }
+
+    if (tok == TOK_IF) {
+        /* if test */
+        next();
+        skip('(');
+        gexpr();
+        skip(')');
+        a = gtst(1, 0);
+        block(bsym, csym, case_sym, def_sym, case_reg, 0);
+        c = tok;
+        if (c == TOK_ELSE) {
+            next();
+            d = gjmp(0);
+            gsym(a);
+            block(bsym, csym, case_sym, def_sym, case_reg, 0);
+            gsym(d); /* patch else jmp */
+        } else
+            gsym(a);
+    } else if (tok == TOK_WHILE) {
+        next();
+        d = ind;
+        skip('(');
+        gexpr();
+        skip(')');
+        a = gtst(1, 0);
+        b = 0;
+        block(&a, &b, case_sym, def_sym, case_reg, 0);
+        gjmp_addr(d);
+        gsym(a);
+        gsym_addr(b, d);
+    } else if (tok == '{') {
+        Sym *llabel;
+        
+        next();
+        /* record local declaration stack position */
+        s = local_stack;
+        llabel = local_label_stack;
+        /* handle local labels declarations */
+        if (tok == TOK_LABEL) {
+            next();
+            for(;;) {
+                if (tok < TOK_UIDENT)
+                    expect("label identifier");
+                label_push(&local_label_stack, tok, LABEL_DECLARED);
+                next();
+                if (tok == ',') {
+                    next();
+                } else {
+                    skip(';');
+                    break;
+                }
+            }
+        }
+        while (tok != '}') {
+            decl(VT_LOCAL);
+            if (tok != '}') {
+                if (is_expr)
+                    vpop();
+                block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
+            }
+        }
+        /* pop locally defined labels */
+        label_pop(&local_label_stack, llabel);
+        /* pop locally defined symbols */
+        if(is_expr) {
+            /* XXX: this solution makes only valgrind happy...
+               triggered by gcc.c-torture/execute/20000917-1.c */
+            Sym *p;
+            switch(vtop->type.t & VT_BTYPE) {
+            case VT_PTR:
+            case VT_STRUCT:
+            case VT_ENUM:
+            case VT_FUNC:
+                for(p=vtop->type.ref;p;p=p->prev)
+                    if(p->prev==s)
+                        error("unsupported expression type");
+            }
+        }
+        sym_pop(&local_stack, s);
+        next();
+    } else if (tok == TOK_RETURN) {
+        next();
+        if (tok != ';') {
+            gexpr();
+            gen_assign_cast(&func_vt);
+            if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
+                CType type;
+                /* if returning structure, must copy it to implicit
+                   first pointer arg location */
+#ifdef TCC_ARM_EABI
+                int align, size;
+                size = type_size(&func_vt,&align);
+                if(size <= 4)
+                {
+                    if((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & 3))
+                       && (align & 3))
+                    {
+                        int addr;
+                        loc = (loc - size) & -4;
+                        addr = loc;
+                        type = func_vt;
+                        vset(&type, VT_LOCAL | VT_LVAL, addr);
+                        vswap();
+                        vstore();
+                        vset(&int_type, VT_LOCAL | VT_LVAL, addr);
+                    }
+                    vtop->type = int_type;
+                    gv(RC_IRET);
+                } else {
+#endif
+                type = func_vt;
+                mk_pointer(&type);
+                vset(&type, VT_LOCAL | VT_LVAL, func_vc);
+                indir();
+                vswap();
+                /* copy structure value to pointer */
+                vstore();
+#ifdef TCC_ARM_EABI
+                }
+#endif
+            } else if (is_float(func_vt.t)) {
+                gv(rc_fret(func_vt.t));
+            } else {
+                gv(RC_IRET);
+            }
+            vtop--; /* NOT vpop() because on x86 it would flush the fp stack */
+        }
+        skip(';');
+        rsym = gjmp(rsym); /* jmp */
+    } else if (tok == TOK_BREAK) {
+        /* compute jump */
+        if (!bsym)
+            error("cannot break");
+        *bsym = gjmp(*bsym);
+        next();
+        skip(';');
+    } else if (tok == TOK_CONTINUE) {
+        /* compute jump */
+        if (!csym)
+            error("cannot continue");
+        *csym = gjmp(*csym);
+        next();
+        skip(';');
+    } else if (tok == TOK_FOR) {
+        int e;
+        next();
+        skip('(');
+        if (tok != ';') {
+            gexpr();
+            vpop();
+        }
+        skip(';');
+        d = ind;
+        c = ind;
+        a = 0;
+        b = 0;
+        if (tok != ';') {
+            gexpr();
+            a = gtst(1, 0);
+        }
+        skip(';');
+        if (tok != ')') {
+            e = gjmp(0);
+            c = ind;
+            gexpr();
+            vpop();
+            gjmp_addr(d);
+            gsym(e);
+        }
+        skip(')');
+        block(&a, &b, case_sym, def_sym, case_reg, 0);
+        gjmp_addr(c);
+        gsym(a);
+        gsym_addr(b, c);
+    } else 
+    if (tok == TOK_DO) {
+        next();
+        a = 0;
+        b = 0;
+        d = ind;
+        block(&a, &b, case_sym, def_sym, case_reg, 0);
+        skip(TOK_WHILE);
+        skip('(');
+        gsym(b);
+        gexpr();
+        c = gtst(0, 0);
+        gsym_addr(c, d);
+        skip(')');
+        gsym(a);
+        skip(';');
+    } else
+    if (tok == TOK_SWITCH) {
+        next();
+        skip('(');
+        gexpr();
+        /* XXX: other types than integer */
+        case_reg = gv(RC_INT);
+        vpop();
+        skip(')');
+        a = 0;
+        b = gjmp(0); /* jump to first case */
+        c = 0;
+        block(&a, csym, &b, &c, case_reg, 0);
+        /* if no default, jmp after switch */
+        if (c == 0)
+            c = ind;
+        /* default label */
+        gsym_addr(b, c);
+        /* break label */
+        gsym(a);
+    } else
+    if (tok == TOK_CASE) {
+        int v1, v2;
+        if (!case_sym)
+            expect("switch");
+        next();
+        v1 = expr_const();
+        v2 = v1;
+        if (gnu_ext && tok == TOK_DOTS) {
+            next();
+            v2 = expr_const();
+            if (v2 < v1)
+                warning("empty case range");
+        }
+        /* since a case is like a label, we must skip it with a jmp */
+        b = gjmp(0);
+        gsym(*case_sym);
+        vseti(case_reg, 0);
+        vpushi(v1);
+        if (v1 == v2) {
+            gen_op(TOK_EQ);
+            *case_sym = gtst(1, 0);
+        } else {
+            gen_op(TOK_GE);
+            *case_sym = gtst(1, 0);
+            vseti(case_reg, 0);
+            vpushi(v2);
+            gen_op(TOK_LE);
+            *case_sym = gtst(1, *case_sym);
+        }
+        gsym(b);
+        skip(':');
+        is_expr = 0;
+        goto block_after_label;
+    } else 
+    if (tok == TOK_DEFAULT) {
+        next();
+        skip(':');
+        if (!def_sym)
+            expect("switch");
+        if (*def_sym)
+            error("too many 'default'");
+        *def_sym = ind;
+        is_expr = 0;
+        goto block_after_label;
+    } else
+    if (tok == TOK_GOTO) {
+        next();
+        if (tok == '*' && gnu_ext) {
+            /* computed goto */
+            next();
+            gexpr();
+            if ((vtop->type.t & VT_BTYPE) != VT_PTR)
+                expect("pointer");
+            ggoto();
+        } else if (tok >= TOK_UIDENT) {
+            s = label_find(tok);
+            /* put forward definition if needed */
+            if (!s) {
+                s = label_push(&global_label_stack, tok, LABEL_FORWARD);
+            } else {
+                if (s->r == LABEL_DECLARED)
+                    s->r = LABEL_FORWARD;
+            }
+            /* label already defined */
+            if (s->r & LABEL_FORWARD) 
+                s->next = (void *)gjmp((long)s->next);
+            else
+                gjmp_addr((long)s->next);
+            next();
+        } else {
+            expect("label identifier");
+        }
+        skip(';');
+    } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) {
+        asm_instr();
+    } else {
+        b = is_label();
+        if (b) {
+            /* label case */
+            s = label_find(b);
+            if (s) {
+                if (s->r == LABEL_DEFINED)
+                    error("duplicate label '%s'", get_tok_str(s->v, NULL));
+                gsym((long)s->next);
+                s->r = LABEL_DEFINED;
+            } else {
+                s = label_push(&global_label_stack, b, LABEL_DEFINED);
+            }
+            s->next = (void *)ind;
+            /* we accept this, but it is a mistake */
+        block_after_label:
+            if (tok == '}') {
+                warning("deprecated use of label at end of compound statement");
+            } else {
+                if (is_expr)
+                    vpop();
+                block(bsym, csym, case_sym, def_sym, case_reg, is_expr);
+            }
+        } else {
+            /* expression case */
+            if (tok != ';') {
+                if (is_expr) {
+                    vpop();
+                    gexpr();
+                } else {
+                    gexpr();
+                    vpop();
+                }
+            }
+            skip(';');
+        }
+    }
+}
+
+/* t is the array or struct type. c is the array or struct
+   address. cur_index/cur_field is the pointer to the current
+   value. 'size_only' is true if only size info is needed (only used
+   in arrays) */
+static void decl_designator(CType *type, Section *sec, unsigned long c, 
+                            int *cur_index, Sym **cur_field, 
+                            int size_only)
+{
+    Sym *s, *f;
+    int notfirst, index, index_last, align, l, nb_elems, elem_size;
+    CType type1;
+
+    notfirst = 0;
+    elem_size = 0;
+    nb_elems = 1;
+    if (gnu_ext && (l = is_label()) != 0)
+        goto struct_field;
+    while (tok == '[' || tok == '.') {
+        if (tok == '[') {
+            if (!(type->t & VT_ARRAY))
+                expect("array type");
+            s = type->ref;
+            next();
+            index = expr_const();
+            if (index < 0 || (s->c >= 0 && index >= s->c))
+                expect("invalid index");
+            if (tok == TOK_DOTS && gnu_ext) {
+                next();
+                index_last = expr_const();
+                if (index_last < 0 || 
+                    (s->c >= 0 && index_last >= s->c) ||
+                    index_last < index)
+                    expect("invalid index");
+            } else {
+                index_last = index;
+            }
+            skip(']');
+            if (!notfirst)
+                *cur_index = index_last;
+            type = pointed_type(type);
+            elem_size = type_size(type, &align);
+            c += index * elem_size;
+            /* NOTE: we only support ranges for last designator */
+            nb_elems = index_last - index + 1;
+            if (nb_elems != 1) {
+                notfirst = 1;
+                break;
+            }
+        } else {
+            next();
+            l = tok;
+            next();
+        struct_field:
+            if ((type->t & VT_BTYPE) != VT_STRUCT)
+                expect("struct/union type");
+            s = type->ref;
+            l |= SYM_FIELD;
+            f = s->next;
+            while (f) {
+                if (f->v == l)
+                    break;
+                f = f->next;
+            }
+            if (!f)
+                expect("field");
+            if (!notfirst)
+                *cur_field = f;
+            /* XXX: fix this mess by using explicit storage field */
+            type1 = f->type;
+            type1.t |= (type->t & ~VT_TYPE);
+            type = &type1;
+            c += f->c;
+        }
+        notfirst = 1;
+    }
+    if (notfirst) {
+        if (tok == '=') {
+            next();
+        } else {
+            if (!gnu_ext)
+                expect("=");
+        }
+    } else {
+        if (type->t & VT_ARRAY) {
+            index = *cur_index;
+            type = pointed_type(type);
+            c += index * type_size(type, &align);
+        } else {
+            f = *cur_field;
+            if (!f)
+                error("too many field init");
+            /* XXX: fix this mess by using explicit storage field */
+            type1 = f->type;
+            type1.t |= (type->t & ~VT_TYPE);
+            type = &type1;
+            c += f->c;
+        }
+    }
+    decl_initializer(type, sec, c, 0, size_only);
+
+    /* XXX: make it more general */
+    if (!size_only && nb_elems > 1) {
+        unsigned long c_end;
+        uint8_t *src, *dst;
+        int i;
+
+        if (!sec)
+            error("range init not supported yet for dynamic storage");
+        c_end = c + nb_elems * elem_size;
+        if (c_end > sec->data_allocated)
+            section_realloc(sec, c_end);
+        src = sec->data + c;
+        dst = src;
+        for(i = 1; i < nb_elems; i++) {
+            dst += elem_size;
+            memcpy(dst, src, elem_size);
+        }
+    }
+}
+
+#define EXPR_VAL   0
+#define EXPR_CONST 1
+#define EXPR_ANY   2
+
+/* store a value or an expression directly in global data or in local array */
+static void init_putv(CType *type, Section *sec, unsigned long c, 
+                      int v, int expr_type)
+{
+    int saved_global_expr, bt, bit_pos, bit_size;
+    void *ptr;
+    unsigned long long bit_mask;
+    CType dtype;
+
+    switch(expr_type) {
+    case EXPR_VAL:
+        vpushi(v);
+        break;
+    case EXPR_CONST:
+        /* compound literals must be allocated globally in this case */
+        saved_global_expr = global_expr;
+        global_expr = 1;
+        expr_const1();
+        global_expr = saved_global_expr;
+        /* NOTE: symbols are accepted */
+        if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
+            error("initializer element is not constant");
+        break;
+    case EXPR_ANY:
+        expr_eq();
+        break;
+    }
+    
+    dtype = *type;
+    dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
+
+    if (sec) {
+        /* XXX: not portable */
+        /* XXX: generate error if incorrect relocation */
+        gen_assign_cast(&dtype);
+        bt = type->t & VT_BTYPE;
+        /* we'll write at most 12 bytes */
+        if (c + 12 > sec->data_allocated) {
+            section_realloc(sec, c + 12);
+        }
+        ptr = sec->data + c;
+        /* XXX: make code faster ? */
+        if (!(type->t & VT_BITFIELD)) {
+            bit_pos = 0;
+            bit_size = 32;
+            bit_mask = -1LL;
+        } else {
+            bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f;
+            bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f;
+            bit_mask = (1LL << bit_size) - 1;
+        }
+        if ((vtop->r & VT_SYM) &&
+            (bt == VT_BYTE ||
+             bt == VT_SHORT ||
+             bt == VT_DOUBLE ||
+             bt == VT_LDOUBLE ||
+             bt == VT_LLONG ||
+             (bt == VT_INT && bit_size != 32)))
+            error("initializer element is not computable at load time");
+        switch(bt) {
+        case VT_BOOL:
+            vtop->c.i = (vtop->c.i != 0);
+        case VT_BYTE:
+            *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+            break;
+        case VT_SHORT:
+            *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+            break;
+        case VT_DOUBLE:
+            *(double *)ptr = vtop->c.d;
+            break;
+        case VT_LDOUBLE:
+            *(long double *)ptr = vtop->c.ld;
+            break;
+        case VT_LLONG:
+            *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos;
+            break;
+        default:
+            if (vtop->r & VT_SYM) {
+                greloc(sec, vtop->sym, c, R_DATA_32);
+            }
+            *(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos;
+            break;
+        }
+        vtop--;
+    } else {
+        vset(&dtype, VT_LOCAL|VT_LVAL, c);
+        vswap();
+        vstore();
+        vpop();
+    }
+}
+
+/* put zeros for variable based init */
+static void init_putz(CType *t, Section *sec, unsigned long c, int size)
+{
+    if (sec) {
+        /* nothing to do because globals are already set to zero */
+    } else {
+        vpush_global_sym(&func_old_type, TOK_memset);
+        vseti(VT_LOCAL, c);
+        vpushi(0);
+        vpushi(size);
+        gfunc_call(3);
+    }
+}
+
+/* 't' contains the type and storage info. 'c' is the offset of the
+   object in section 'sec'. If 'sec' is NULL, it means stack based
+   allocation. 'first' is true if array '{' must be read (multi
+   dimension implicit array init handling). 'size_only' is true if
+   size only evaluation is wanted (only for arrays). */
+static void decl_initializer(CType *type, Section *sec, unsigned long c, 
+                             int first, int size_only)
+{
+    int index, array_length, n, no_oblock, nb, parlevel, i;
+    int size1, align1, expr_type;
+    Sym *s, *f;
+    CType *t1;
+
+    if (type->t & VT_ARRAY) {
+        s = type->ref;
+        n = s->c;
+        array_length = 0;
+        t1 = pointed_type(type);
+        size1 = type_size(t1, &align1);
+
+        no_oblock = 1;
+        if ((first && tok != TOK_LSTR && tok != TOK_STR) || 
+            tok == '{') {
+            skip('{');
+            no_oblock = 0;
+        }
+
+        /* only parse strings here if correct type (otherwise: handle
+           them as ((w)char *) expressions */
+        if ((tok == TOK_LSTR && 
+#ifdef TCC_TARGET_PE
+             (t1->t & VT_BTYPE) == VT_SHORT && (t1->t & VT_UNSIGNED)
+#else
+             (t1->t & VT_BTYPE) == VT_INT
+#endif
+            ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) {
+            while (tok == TOK_STR || tok == TOK_LSTR) {
+                int cstr_len, ch;
+                CString *cstr;
+
+                cstr = tokc.cstr;
+                /* compute maximum number of chars wanted */
+                if (tok == TOK_STR)
+                    cstr_len = cstr->size;
+                else
+                    cstr_len = cstr->size / sizeof(nwchar_t);
+                cstr_len--;
+                nb = cstr_len;
+                if (n >= 0 && nb > (n - array_length))
+                    nb = n - array_length;
+                if (!size_only) {
+                    if (cstr_len > nb)
+                        warning("initializer-string for array is too long");
+                    /* in order to go faster for common case (char
+                       string in global variable, we handle it
+                       specifically */
+                    if (sec && tok == TOK_STR && size1 == 1) {
+                        memcpy(sec->data + c + array_length, cstr->data, nb);
+                    } else {
+                        for(i=0;i<nb;i++) {
+                            if (tok == TOK_STR)
+                                ch = ((unsigned char *)cstr->data)[i];
+                            else
+                                ch = ((nwchar_t *)cstr->data)[i];
+                            init_putv(t1, sec, c + (array_length + i) * size1,
+                                      ch, EXPR_VAL);
+                        }
+                    }
+                }
+                array_length += nb;
+                next();
+            }
+            /* only add trailing zero if enough storage (no
+               warning in this case since it is standard) */
+            if (n < 0 || array_length < n) {
+                if (!size_only) {
+                    init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL);
+                }
+                array_length++;
+            }
+        } else {
+            index = 0;
+            while (tok != '}') {
+                decl_designator(type, sec, c, &index, NULL, size_only);
+                if (n >= 0 && index >= n)
+                    error("index too large");
+                /* must put zero in holes (note that doing it that way
+                   ensures that it even works with designators) */
+                if (!size_only && array_length < index) {
+                    init_putz(t1, sec, c + array_length * size1, 
+                              (index - array_length) * size1);
+                }
+                index++;
+                if (index > array_length)
+                    array_length = index;
+                /* special test for multi dimensional arrays (may not
+                   be strictly correct if designators are used at the
+                   same time) */
+                if (index >= n && no_oblock)
+                    break;
+                if (tok == '}')
+                    break;
+                skip(',');
+            }
+        }
+        if (!no_oblock)
+            skip('}');
+        /* put zeros at the end */
+        if (!size_only && n >= 0 && array_length < n) {
+            init_putz(t1, sec, c + array_length * size1, 
+                      (n - array_length) * size1);
+        }
+        /* patch type size if needed */
+        if (n < 0)
+            s->c = array_length;
+    } else if ((type->t & VT_BTYPE) == VT_STRUCT &&
+               (sec || !first || tok == '{')) {
+        int par_count;
+
+        /* NOTE: the previous test is a specific case for automatic
+           struct/union init */
+        /* XXX: union needs only one init */
+
+        /* XXX: this test is incorrect for local initializers
+           beginning with ( without {. It would be much more difficult
+           to do it correctly (ideally, the expression parser should
+           be used in all cases) */
+        par_count = 0;
+        if (tok == '(') {
+            AttributeDef ad1;
+            CType type1;
+            next();
+            while (tok == '(') {
+                par_count++;
+                next();
+            }
+            if (!parse_btype(&type1, &ad1))
+                expect("cast");
+            type_decl(&type1, &ad1, &n, TYPE_ABSTRACT);
+#if 0
+            if (!is_assignable_types(type, &type1))
+                error("invalid type for cast");
+#endif
+            skip(')');
+        }
+        no_oblock = 1;
+        if (first || tok == '{') {
+            skip('{');
+            no_oblock = 0;
+        }
+        s = type->ref;
+        f = s->next;
+        array_length = 0;
+        index = 0;
+        n = s->c;
+        while (tok != '}') {
+            decl_designator(type, sec, c, NULL, &f, size_only);
+            index = f->c;
+            if (!size_only && array_length < index) {
+                init_putz(type, sec, c + array_length, 
+                          index - array_length);
+            }
+            index = index + type_size(&f->type, &align1);
+            if (index > array_length)
+                array_length = index;
+            f = f->next;
+            if (no_oblock && f == NULL)
+                break;
+            if (tok == '}')
+                break;
+            skip(',');
+        }
+        /* put zeros at the end */
+        if (!size_only && array_length < n) {
+            init_putz(type, sec, c + array_length, 
+                      n - array_length);
+        }
+        if (!no_oblock)
+            skip('}');
+        while (par_count) {
+            skip(')');
+            par_count--;
+        }
+    } else if (tok == '{') {
+        next();
+        decl_initializer(type, sec, c, first, size_only);
+        skip('}');
+    } else if (size_only) {
+        /* just skip expression */
+        parlevel = 0;
+        while ((parlevel > 0 || (tok != '}' && tok != ',')) && 
+               tok != -1) {
+            if (tok == '(')
+                parlevel++;
+            else if (tok == ')')
+                parlevel--;
+            next();
+        }
+    } else {
+        /* currently, we always use constant expression for globals
+           (may change for scripting case) */
+        expr_type = EXPR_CONST;
+        if (!sec)
+            expr_type = EXPR_ANY;
+        init_putv(type, sec, c, 0, expr_type);
+    }
+}
+
+/* parse an initializer for type 't' if 'has_init' is non zero, and
+   allocate space in local or global data space ('r' is either
+   VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated
+   variable 'v' of scope 'scope' is declared before initializers are
+   parsed. If 'v' is zero, then a reference to the new object is put
+   in the value stack. If 'has_init' is 2, a special parsing is done
+   to handle string constants. */
+static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, 
+                                   int has_init, int v, int scope)
+{
+    int size, align, addr, data_offset;
+    int level;
+    ParseState saved_parse_state = {0};
+    TokenString init_str;
+    Section *sec;
+
+    size = type_size(type, &align);
+    /* If unknown size, we must evaluate it before
+       evaluating initializers because
+       initializers can generate global data too
+       (e.g. string pointers or ISOC99 compound
+       literals). It also simplifies local
+       initializers handling */
+    tok_str_new(&init_str);
+    if (size < 0) {
+        if (!has_init) 
+            error("unknown type size");
+        /* get all init string */
+        if (has_init == 2) {
+            /* only get strings */
+            while (tok == TOK_STR || tok == TOK_LSTR) {
+                tok_str_add_tok(&init_str);
+                next();
+            }
+        } else {
+            level = 0;
+            while (level > 0 || (tok != ',' && tok != ';')) {
+                if (tok < 0)
+                    error("unexpected end of file in initializer");
+                tok_str_add_tok(&init_str);
+                if (tok == '{')
+                    level++;
+                else if (tok == '}') {
+                    level--;
+                    if (level <= 0) {
+                        next();
+                        break;
+                    }
+                }
+                next();
+            }
+        }
+        tok_str_add(&init_str, -1);
+        tok_str_add(&init_str, 0);
+        
+        /* compute size */
+        save_parse_state(&saved_parse_state);
+
+        macro_ptr = init_str.str;
+        next();
+        decl_initializer(type, NULL, 0, 1, 1);
+        /* prepare second initializer parsing */
+        macro_ptr = init_str.str;
+        next();
+        
+        /* if still unknown size, error */
+        size = type_size(type, &align);
+        if (size < 0) 
+            error("unknown type size");
+    }
+    /* take into account specified alignment if bigger */
+    if (ad->aligned) {
+        if (ad->aligned > align)
+            align = ad->aligned;
+    } else if (ad->packed) {
+        align = 1;
+    }
+    if ((r & VT_VALMASK) == VT_LOCAL) {
+        sec = NULL;
+        if (tcc_state->do_bounds_check && (type->t & VT_ARRAY))
+            loc--;
+        loc = (loc - size) & -align;
+        addr = loc;
+        /* handles bounds */
+        /* XXX: currently, since we do only one pass, we cannot track
+           '&' operators, so we add only arrays */
+        if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
+            unsigned long *bounds_ptr;
+            /* add padding between regions */
+            loc--;
+            /* then add local bound info */
+            bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long));
+            bounds_ptr[0] = addr;
+            bounds_ptr[1] = size;
+        }
+        if (v) {
+            /* local variable */
+            sym_push(v, type, r, addr);
+        } else {
+            /* push local reference */
+            vset(type, r, addr);
+        }
+    } else {
+        Sym *sym;
+
+        sym = NULL;
+        if (v && scope == VT_CONST) {
+            /* see if the symbol was already defined */
+            sym = sym_find(v);
+            if (sym) {
+                if (!is_compatible_types(&sym->type, type))
+                    error("incompatible types for redefinition of '%s'", 
+                          get_tok_str(v, NULL));
+                if (sym->type.t & VT_EXTERN) {
+                    /* if the variable is extern, it was not allocated */
+                    sym->type.t &= ~VT_EXTERN;
+                    /* set array size if it was omitted in extern
+                       declaration */
+                    if ((sym->type.t & VT_ARRAY) && 
+                        sym->type.ref->c < 0 &&
+                        type->ref->c >= 0)
+                        sym->type.ref->c = type->ref->c;
+                } else {
+                    /* we accept several definitions of the same
+                       global variable. this is tricky, because we
+                       must play with the SHN_COMMON type of the symbol */
+                    /* XXX: should check if the variable was already
+                       initialized. It is incorrect to initialized it
+                       twice */
+                    /* no init data, we won't add more to the symbol */
+                    if (!has_init)
+                        goto no_alloc;
+                }
+            }
+        }
+
+        /* allocate symbol in corresponding section */
+        sec = ad->section;
+        if (!sec) {
+            if (has_init)
+                sec = data_section;
+            else if (tcc_state->nocommon)
+                sec = bss_section;
+        }
+        if (sec) {
+            data_offset = sec->data_offset;
+            data_offset = (data_offset + align - 1) & -align;
+            addr = data_offset;
+            /* very important to increment global pointer at this time
+               because initializers themselves can create new initializers */
+            data_offset += size;
+            /* add padding if bound check */
+            if (tcc_state->do_bounds_check)
+                data_offset++;
+            sec->data_offset = data_offset;
+            /* allocate section space to put the data */
+            if (sec->sh_type != SHT_NOBITS && 
+                data_offset > sec->data_allocated)
+                section_realloc(sec, data_offset);
+            /* align section if needed */
+            if (align > sec->sh_addralign)
+                sec->sh_addralign = align;
+        } else {
+            addr = 0; /* avoid warning */
+        }
+
+        if (v) {
+            if (scope != VT_CONST || !sym) {
+                sym = sym_push(v, type, r | VT_SYM, 0);
+            }
+            /* update symbol definition */
+            if (sec) {
+                put_extern_sym(sym, sec, addr, size);
+            } else {
+                ElfW(Sym) *esym;
+                /* put a common area */
+                put_extern_sym(sym, NULL, align, size);
+                /* XXX: find a nicer way */
+                esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+                esym->st_shndx = SHN_COMMON;
+            }
+        } else {
+            CValue cval;
+
+            /* push global reference */
+            sym = get_sym_ref(type, sec, addr, size);
+            cval.ul = 0;
+            vsetc(type, VT_CONST | VT_SYM, &cval);
+            vtop->sym = sym;
+        }
+
+        /* handles bounds now because the symbol must be defined
+           before for the relocation */
+        if (tcc_state->do_bounds_check) {
+            unsigned long *bounds_ptr;
+
+            greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_32);
+            /* then add global bound info */
+            bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long));
+            bounds_ptr[0] = 0; /* relocated */
+            bounds_ptr[1] = size;
+        }
+    }
+    if (has_init) {
+        decl_initializer(type, sec, addr, 1, 0);
+        /* restore parse state if needed */
+        if (init_str.str) {
+            tok_str_free(init_str.str);
+            restore_parse_state(&saved_parse_state);
+        }
+    }
+ no_alloc: ;
+}
+
+void put_func_debug(Sym *sym)
+{
+    char buf[512];
+
+    /* stabs info */
+    /* XXX: we put here a dummy type */
+    snprintf(buf, sizeof(buf), "%s:%c1", 
+             funcname, sym->type.t & VT_STATIC ? 'f' : 'F');
+    put_stabs_r(buf, N_FUN, 0, file->line_num, 0,
+                cur_text_section, sym->c);
+    /* //gr gdb wants a line at the function */
+    put_stabn(N_SLINE, 0, file->line_num, 0); 
+    last_ind = 0;
+    last_line_num = 0;
+}
+
+/* parse an old style function declaration list */
+/* XXX: check multiple parameter */
+static void func_decl_list(Sym *func_sym)
+{
+    AttributeDef ad;
+    int v;
+    Sym *s;
+    CType btype, type;
+
+    /* parse each declaration */
+    while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF) {
+        if (!parse_btype(&btype, &ad)) 
+            expect("declaration list");
+        if (((btype.t & VT_BTYPE) == VT_ENUM ||
+             (btype.t & VT_BTYPE) == VT_STRUCT) && 
+            tok == ';') {
+            /* we accept no variable after */
+        } else {
+            for(;;) {
+                type = btype;
+                type_decl(&type, &ad, &v, TYPE_DIRECT);
+                /* find parameter in function parameter list */
+                s = func_sym->next;
+                while (s != NULL) {
+                    if ((s->v & ~SYM_FIELD) == v)
+                        goto found;
+                    s = s->next;
+                }
+                error("declaration for parameter '%s' but no such parameter",
+                      get_tok_str(v, NULL));
+            found:
+                /* check that no storage specifier except 'register' was given */
+                if (type.t & VT_STORAGE)
+                    error("storage class specified for '%s'", get_tok_str(v, NULL)); 
+                convert_parameter_type(&type);
+                /* we can add the type (NOTE: it could be local to the function) */
+                s->type = type;
+                /* accept other parameters */
+                if (tok == ',')
+                    next();
+                else
+                    break;
+            }
+        }
+        skip(';');
+    }
+}
+
+/* parse a function defined by symbol 'sym' and generate its code in
+   'cur_text_section' */
+static void gen_function(Sym *sym)
+{
+    int saved_nocode_wanted = nocode_wanted;
+    nocode_wanted = 0;
+    ind = cur_text_section->data_offset;
+    /* NOTE: we patch the symbol size later */
+    put_extern_sym(sym, cur_text_section, ind, 0);
+    funcname = get_tok_str(sym->v, NULL);
+    func_ind = ind;
+    /* put debug symbol */
+    if (tcc_state->do_debug)
+        put_func_debug(sym);
+    /* push a dummy symbol to enable local sym storage */
+    sym_push2(&local_stack, SYM_FIELD, 0, 0);
+    gfunc_prolog(&sym->type);
+    rsym = 0;
+    block(NULL, NULL, NULL, NULL, 0, 0);
+    gsym(rsym);
+    gfunc_epilog();
+    cur_text_section->data_offset = ind;
+    label_pop(&global_label_stack, NULL);
+    sym_pop(&local_stack, NULL); /* reset local stack */
+    /* end of function */
+    /* patch symbol size */
+    ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = 
+        ind - func_ind;
+    if (tcc_state->do_debug) {
+        put_stabn(N_FUN, 0, 0, ind - func_ind);
+    }
+    /* It's better to crash than to generate wrong code */
+    cur_text_section = NULL;
+    funcname = ""; /* for safety */
+    func_vt.t = VT_VOID; /* for safety */
+    ind = 0; /* for safety */
+    nocode_wanted = saved_nocode_wanted;
+}
+
+static void gen_inline_functions(void)
+{
+    Sym *sym;
+    CType *type;
+    int *str, inline_generated;
+
+    /* iterate while inline function are referenced */
+    for(;;) {
+        inline_generated = 0;
+        for(sym = global_stack; sym != NULL; sym = sym->prev) {
+            type = &sym->type;
+            if (((type->t & VT_BTYPE) == VT_FUNC) &&
+                (type->t & (VT_STATIC | VT_INLINE)) == 
+                (VT_STATIC | VT_INLINE) &&
+                sym->c != 0) {
+                /* the function was used: generate its code and
+                   convert it to a normal function */
+                str = INLINE_DEF(sym->r);
+                sym->r = VT_SYM | VT_CONST;
+                sym->type.t &= ~VT_INLINE;
+
+                macro_ptr = str;
+                next();
+                cur_text_section = text_section;
+                gen_function(sym);
+                macro_ptr = NULL; /* fail safe */
+
+                tok_str_free(str);
+                inline_generated = 1;
+            }
+        }
+        if (!inline_generated)
+            break;
+    }
+
+    /* free all remaining inline function tokens */
+    for(sym = global_stack; sym != NULL; sym = sym->prev) {
+        type = &sym->type;
+        if (((type->t & VT_BTYPE) == VT_FUNC) &&
+            (type->t & (VT_STATIC | VT_INLINE)) == 
+            (VT_STATIC | VT_INLINE)) {
+            //gr printf("sym %d %s\n", sym->r, get_tok_str(sym->v, NULL));
+            if (sym->r == (VT_SYM | VT_CONST)) //gr beware!
+                continue;
+            str = INLINE_DEF(sym->r);
+            tok_str_free(str);
+            sym->r = 0; /* fail safe */
+        }
+    }
+}
+
+/* 'l' is VT_LOCAL or VT_CONST to define default storage type */
+static void decl(int l)
+{
+    int v, has_init, r;
+    CType type, btype;
+    Sym *sym;
+    AttributeDef ad;
+    
+    while (1) {
+        if (!parse_btype(&btype, &ad)) {
+            /* skip redundant ';' */
+            /* XXX: find more elegant solution */
+            if (tok == ';') {
+                next();
+                continue;
+            }
+            if (l == VT_CONST &&
+                (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) {
+                /* global asm block */
+                asm_global_instr();
+                continue;
+            }
+            /* special test for old K&R protos without explicit int
+               type. Only accepted when defining global data */
+            if (l == VT_LOCAL || tok < TOK_DEFINE)
+                break;
+            btype.t = VT_INT;
+        }
+        if (((btype.t & VT_BTYPE) == VT_ENUM ||
+             (btype.t & VT_BTYPE) == VT_STRUCT) && 
+            tok == ';') {
+            /* we accept no variable after */
+            next();
+            continue;
+        }
+        while (1) { /* iterate thru each declaration */
+            type = btype;
+            type_decl(&type, &ad, &v, TYPE_DIRECT);
+#if 0
+            {
+                char buf[500];
+                type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL));
+                printf("type = '%s'\n", buf);
+            }
+#endif
+            if ((type.t & VT_BTYPE) == VT_FUNC) {
+                /* if old style function prototype, we accept a
+                   declaration list */
+                sym = type.ref;
+                if (sym->c == FUNC_OLD)
+                    func_decl_list(sym);
+            }
+
+            if (tok == '{') {
+                if (l == VT_LOCAL)
+                    error("cannot use local functions");
+                if ((type.t & VT_BTYPE) != VT_FUNC)
+                    expect("function definition");
+
+                /* reject abstract declarators in function definition */
+                sym = type.ref;
+                while ((sym = sym->next) != NULL)
+                    if (!(sym->v & ~SYM_FIELD))
+                       expect("identifier");
+                
+                /* XXX: cannot do better now: convert extern line to static inline */
+                if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE))
+                    type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
+                
+                sym = sym_find(v);
+                if (sym) {
+                    if ((sym->type.t & VT_BTYPE) != VT_FUNC)
+                        goto func_error1;
+                    /* specific case: if not func_call defined, we put
+                       the one of the prototype */
+                    /* XXX: should have default value */
+                    r = sym->type.ref->r;
+                    if (FUNC_CALL(r) != FUNC_CDECL
+                     && FUNC_CALL(type.ref->r) == FUNC_CDECL)
+                        FUNC_CALL(type.ref->r) = FUNC_CALL(r);
+                    if (FUNC_EXPORT(r))
+                        FUNC_EXPORT(type.ref->r) = 1;
+
+                    if (!is_compatible_types(&sym->type, &type)) {
+                    func_error1:
+                        error("incompatible types for redefinition of '%s'", 
+                              get_tok_str(v, NULL));
+                    }
+                    /* if symbol is already defined, then put complete type */
+                    sym->type = type;
+                } else {
+                    /* put function symbol */
+                    sym = global_identifier_push(v, type.t, 0);
+                    sym->type.ref = type.ref;
+                }
+
+                /* static inline functions are just recorded as a kind
+                   of macro. Their code will be emitted at the end of
+                   the compilation unit only if they are used */
+                if ((type.t & (VT_INLINE | VT_STATIC)) == 
+                    (VT_INLINE | VT_STATIC)) {
+                    TokenString func_str;
+                    int block_level;
+                           
+                    tok_str_new(&func_str);
+                    
+                    block_level = 0;
+                    for(;;) {
+                        int t;
+                        if (tok == TOK_EOF)
+                            error("unexpected end of file");
+                        tok_str_add_tok(&func_str);
+                        t = tok;
+                        next();
+                        if (t == '{') {
+                            block_level++;
+                        } else if (t == '}') {
+                            block_level--;
+                            if (block_level == 0)
+                                break;
+                        }
+                    }
+                    tok_str_add(&func_str, -1);
+                    tok_str_add(&func_str, 0);
+                    INLINE_DEF(sym->r) = func_str.str;
+                } else {
+                    /* compute text section */
+                    cur_text_section = ad.section;
+                    if (!cur_text_section)
+                        cur_text_section = text_section;
+                    sym->r = VT_SYM | VT_CONST;
+                    gen_function(sym);
+                }
+                break;
+            } else {
+                if (btype.t & VT_TYPEDEF) {
+                    /* save typedefed type  */
+                    /* XXX: test storage specifiers ? */
+                    sym = sym_push(v, &type, 0, 0);
+                    sym->type.t |= VT_TYPEDEF;
+                } else if ((type.t & VT_BTYPE) == VT_FUNC) {
+                    /* external function definition */
+                    /* specific case for func_call attribute */
+                    if (ad.func_attr)
+                        type.ref->r = ad.func_attr;
+                    external_sym(v, &type, 0);
+                } else {
+                    /* not lvalue if array */
+                    r = 0;
+                    if (!(type.t & VT_ARRAY))
+                        r |= lvalue_type(type.t);
+                    has_init = (tok == '=');
+                    if ((btype.t & VT_EXTERN) || 
+                        ((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
+                         !has_init && l == VT_CONST && type.ref->c < 0)) {
+                        /* external variable */
+                        /* NOTE: as GCC, uninitialized global static
+                           arrays of null size are considered as
+                           extern */
+                        external_sym(v, &type, r);
+                    } else {
+                        type.t |= (btype.t & VT_STATIC); /* Retain "static". */
+                        if (type.t & VT_STATIC)
+                            r |= VT_CONST;
+                        else
+                            r |= l;
+                        if (has_init)
+                            next();
+                        decl_initializer_alloc(&type, &ad, r, 
+                                               has_init, v, l);
+                    }
+                }
+                if (tok != ',') {
+                    skip(';');
+                    break;
+                }
+                next();
+            }
+        }
+    }
+}
+
diff --git a/tinyc/tccpe.c b/tinyc/tccpe.c
new file mode 100644
index 000000000..1e3fdb369
--- /dev/null
+++ b/tinyc/tccpe.c
@@ -0,0 +1,1559 @@
+/*
+ *  TCCPE.C - PE file output for the Tiny C Compiler
+ *
+ *  Copyright (c) 2005-2007 grischka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#ifdef TCC_TARGET_PE
+
+#define ST_FN static
+#define ST_DATA static
+#define PUB_FN
+
+#ifndef _WIN32
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+#ifndef MAX_PATH
+#define MAX_PATH 260
+#endif
+
+#define PE_MERGE_DATA
+// #define PE_PRINT_SECTIONS
+
+/* ----------------------------------------------------------- */
+#ifndef IMAGE_NT_SIGNATURE
+/* ----------------------------------------------------------- */
+/* definitions below are from winnt.h */
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned long DWORD;
+#pragma pack(push, 1)
+
+typedef struct _IMAGE_DOS_HEADER {  /* DOS .EXE header */
+    WORD e_magic;         /* Magic number */
+    WORD e_cblp;          /* Bytes on last page of file */
+    WORD e_cp;            /* Pages in file */
+    WORD e_crlc;          /* Relocations */
+    WORD e_cparhdr;       /* Size of header in paragraphs */
+    WORD e_minalloc;      /* Minimum extra paragraphs needed */
+    WORD e_maxalloc;      /* Maximum extra paragraphs needed */
+    WORD e_ss;            /* Initial (relative) SS value */
+    WORD e_sp;            /* Initial SP value */
+    WORD e_csum;          /* Checksum */
+    WORD e_ip;            /* Initial IP value */
+    WORD e_cs;            /* Initial (relative) CS value */
+    WORD e_lfarlc;        /* File address of relocation table */
+    WORD e_ovno;          /* Overlay number */
+    WORD e_res[4];        /* Reserved words */
+    WORD e_oemid;         /* OEM identifier (for e_oeminfo) */
+    WORD e_oeminfo;       /* OEM information; e_oemid specific */
+    WORD e_res2[10];      /* Reserved words */
+    DWORD e_lfanew;        /* File address of new exe header */
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+#define IMAGE_NT_SIGNATURE  0x00004550  /* PE00 */
+#define SIZE_OF_NT_SIGNATURE 4
+
+typedef struct _IMAGE_FILE_HEADER {
+    WORD    Machine;
+    WORD    NumberOfSections;
+    DWORD   TimeDateStamp;
+    DWORD   PointerToSymbolTable;
+    DWORD   NumberOfSymbols;
+    WORD    SizeOfOptionalHeader;
+    WORD    Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+
+#define IMAGE_SIZEOF_FILE_HEADER 20
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+    DWORD   VirtualAddress;
+    DWORD   Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+    /* Standard fields. */
+    WORD    Magic;
+    BYTE    MajorLinkerVersion;
+    BYTE    MinorLinkerVersion;
+    DWORD   SizeOfCode;
+    DWORD   SizeOfInitializedData;
+    DWORD   SizeOfUninitializedData;
+    DWORD   AddressOfEntryPoint;
+    DWORD   BaseOfCode;
+    DWORD   BaseOfData;
+
+    /* NT additional fields. */
+    DWORD   ImageBase;
+    DWORD   SectionAlignment;
+    DWORD   FileAlignment;
+    WORD    MajorOperatingSystemVersion;
+    WORD    MinorOperatingSystemVersion;
+    WORD    MajorImageVersion;
+    WORD    MinorImageVersion;
+    WORD    MajorSubsystemVersion;
+    WORD    MinorSubsystemVersion;
+    DWORD   Win32VersionValue;
+    DWORD   SizeOfImage;
+    DWORD   SizeOfHeaders;
+    DWORD   CheckSum;
+    WORD    Subsystem;
+    WORD    DllCharacteristics;
+    DWORD   SizeOfStackReserve;
+    DWORD   SizeOfStackCommit;
+    DWORD   SizeOfHeapReserve;
+    DWORD   SizeOfHeapCommit;
+    DWORD   LoaderFlags;
+    DWORD   NumberOfRvaAndSizes;
+    IMAGE_DATA_DIRECTORY DataDirectory[16];
+
+} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
+
+
+#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   /* Export Directory */
+#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   /* Import Directory */
+#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   /* Resource Directory */
+#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   /* Exception Directory */
+#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   /* Security Directory */
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   /* Base Relocation Table */
+#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   /* Debug Directory */
+/*      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7      (X86 usage) */
+#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   /* Architecture Specific Data */
+#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   /* RVA of GP */
+#define IMAGE_DIRECTORY_ENTRY_TLS             9   /* TLS Directory */
+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   /* Load Configuration Directory */
+#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   /* Bound Import Directory in headers */
+#define IMAGE_DIRECTORY_ENTRY_IAT            12   /* Import Address Table */
+#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   /* Delay Load Import Descriptors */
+#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   /* COM Runtime descriptor */
+
+/* Section header format. */
+#define IMAGE_SIZEOF_SHORT_NAME         8
+
+typedef struct _IMAGE_SECTION_HEADER {
+    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
+    union {
+            DWORD   PhysicalAddress;
+            DWORD   VirtualSize;
+    } Misc;
+    DWORD   VirtualAddress;
+    DWORD   SizeOfRawData;
+    DWORD   PointerToRawData;
+    DWORD   PointerToRelocations;
+    DWORD   PointerToLinenumbers;
+    WORD    NumberOfRelocations;
+    WORD    NumberOfLinenumbers;
+    DWORD   Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_SIZEOF_SECTION_HEADER     40
+
+typedef struct _IMAGE_BASE_RELOCATION {
+    DWORD   VirtualAddress;
+    DWORD   SizeOfBlock;
+//  WORD    TypeOffset[1];
+} IMAGE_BASE_RELOCATION;
+
+#define IMAGE_SIZEOF_BASE_RELOCATION     8
+
+#define IMAGE_REL_BASED_ABSOLUTE         0
+#define IMAGE_REL_BASED_HIGH             1
+#define IMAGE_REL_BASED_LOW              2
+#define IMAGE_REL_BASED_HIGHLOW          3
+#define IMAGE_REL_BASED_HIGHADJ          4
+#define IMAGE_REL_BASED_MIPS_JMPADDR     5
+#define IMAGE_REL_BASED_SECTION          6
+#define IMAGE_REL_BASED_REL32            7
+
+#pragma pack(pop)
+
+/* ----------------------------------------------------------- */
+#endif /* ndef IMAGE_NT_SIGNATURE */
+/* ----------------------------------------------------------- */
+
+#pragma pack(push, 1)
+
+struct pe_header
+{
+    IMAGE_DOS_HEADER doshdr;
+    BYTE dosstub[0x40];
+    DWORD nt_sig;
+    IMAGE_FILE_HEADER filehdr;
+    IMAGE_OPTIONAL_HEADER opthdr;
+};
+
+struct pe_import_header {
+    DWORD first_entry;
+    DWORD time_date;
+    DWORD forwarder;
+    DWORD lib_name_offset;
+    DWORD first_thunk;
+};
+
+struct pe_export_header {
+    DWORD Characteristics;
+    DWORD TimeDateStamp;
+    DWORD Version;
+    DWORD Name;
+    DWORD Base;
+    DWORD NumberOfFunctions;
+    DWORD NumberOfNames;
+    DWORD AddressOfFunctions;
+    DWORD AddressOfNames;
+    DWORD AddressOfNameOrdinals;
+};
+
+struct pe_reloc_header {
+    DWORD offset;
+    DWORD size;
+};
+
+struct pe_rsrc_header {
+    struct _IMAGE_FILE_HEADER filehdr;
+    struct _IMAGE_SECTION_HEADER sectionhdr;
+};
+
+struct pe_rsrc_reloc {
+    DWORD offset;
+    DWORD size;
+    WORD type;
+};
+
+#pragma pack(pop)
+
+/* ----------------------------------------------------------- */
+ST_DATA struct pe_header pe_header = {
+{
+    /* IMAGE_DOS_HEADER doshdr */
+    0x5A4D, /*WORD e_magic;         Magic number */
+    0x0090, /*WORD e_cblp;          Bytes on last page of file */
+    0x0003, /*WORD e_cp;            Pages in file */
+    0x0000, /*WORD e_crlc;          Relocations */
+
+    0x0004, /*WORD e_cparhdr;       Size of header in paragraphs */
+    0x0000, /*WORD e_minalloc;      Minimum extra paragraphs needed */
+    0xFFFF, /*WORD e_maxalloc;      Maximum extra paragraphs needed */
+    0x0000, /*WORD e_ss;            Initial (relative) SS value */
+
+    0x00B8, /*WORD e_sp;            Initial SP value */
+    0x0000, /*WORD e_csum;          Checksum */
+    0x0000, /*WORD e_ip;            Initial IP value */
+    0x0000, /*WORD e_cs;            Initial (relative) CS value */
+    0x0040, /*WORD e_lfarlc;        File address of relocation table */
+    0x0000, /*WORD e_ovno;          Overlay number */
+    {0,0,0,0}, /*WORD e_res[4];     Reserved words */
+    0x0000, /*WORD e_oemid;         OEM identifier (for e_oeminfo) */
+    0x0000, /*WORD e_oeminfo;       OEM information; e_oemid specific */
+    {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10];      Reserved words */
+    0x00000080  /*DWORD   e_lfanew;        File address of new exe header */
+},{
+    /* BYTE dosstub[0x40] */
+    /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */
+    0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
+    0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
+    0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
+    0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+},
+    0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
+{
+    /* IMAGE_FILE_HEADER filehdr */
+    0x014C, /*WORD    Machine; */
+    0x0003, /*WORD    NumberOfSections; */
+    0x00000000, /*DWORD   TimeDateStamp; */
+    0x00000000, /*DWORD   PointerToSymbolTable; */
+    0x00000000, /*DWORD   NumberOfSymbols; */
+    0x00E0, /*WORD    SizeOfOptionalHeader; */
+    0x030F  /*WORD    Characteristics; */
+},{
+    /* IMAGE_OPTIONAL_HEADER opthdr */
+    /* Standard fields. */
+    0x010B, /*WORD    Magic; */
+    0x06, /*BYTE    MajorLinkerVersion; */
+    0x00, /*BYTE    MinorLinkerVersion; */
+    0x00000000, /*DWORD   SizeOfCode; */
+    0x00000000, /*DWORD   SizeOfInitializedData; */
+    0x00000000, /*DWORD   SizeOfUninitializedData; */
+    0x00000000, /*DWORD   AddressOfEntryPoint; */
+    0x00000000, /*DWORD   BaseOfCode; */
+    0x00000000, /*DWORD   BaseOfData; */
+
+    /* NT additional fields. */
+    0x00400000, /*DWORD   ImageBase; */
+    0x00001000, /*DWORD   SectionAlignment; */
+    0x00000200, /*DWORD   FileAlignment; */
+    0x0004, /*WORD    MajorOperatingSystemVersion; */
+    0x0000, /*WORD    MinorOperatingSystemVersion; */
+    0x0000, /*WORD    MajorImageVersion; */
+    0x0000, /*WORD    MinorImageVersion; */
+    0x0004, /*WORD    MajorSubsystemVersion; */
+    0x0000, /*WORD    MinorSubsystemVersion; */
+    0x00000000, /*DWORD   Win32VersionValue; */
+    0x00000000, /*DWORD   SizeOfImage; */
+    0x00000200, /*DWORD   SizeOfHeaders; */
+    0x00000000, /*DWORD   CheckSum; */
+    0x0002, /*WORD    Subsystem; */
+    0x0000, /*WORD    DllCharacteristics; */
+    0x00100000, /*DWORD   SizeOfStackReserve; */
+    0x00001000, /*DWORD   SizeOfStackCommit; */
+    0x00100000, /*DWORD   SizeOfHeapReserve; */
+    0x00001000, /*DWORD   SizeOfHeapCommit; */
+    0x00000000, /*DWORD   LoaderFlags; */
+    0x00000010, /*DWORD   NumberOfRvaAndSizes; */
+
+    /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */
+    {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0},
+     {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
+}};
+
+/* ------------------------------------------------------------- */
+/* internal temporary structures */
+
+/*
+#define IMAGE_SCN_CNT_CODE                  0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA      0x00000040
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA    0x00000080
+#define IMAGE_SCN_MEM_DISCARDABLE           0x02000000
+#define IMAGE_SCN_MEM_SHARED                0x10000000
+#define IMAGE_SCN_MEM_EXECUTE               0x20000000
+#define IMAGE_SCN_MEM_READ                  0x40000000
+#define IMAGE_SCN_MEM_WRITE                 0x80000000
+*/
+
+enum {
+    sec_text = 0,
+    sec_data ,
+    sec_bss ,
+    sec_idata ,
+    sec_other ,
+    sec_rsrc ,
+    sec_stab ,
+    sec_reloc ,
+    sec_last
+};
+
+ST_DATA DWORD pe_sec_flags[] = {
+    0x60000020, /* ".text"     , */
+    0xC0000040, /* ".data"     , */
+    0xC0000080, /* ".bss"      , */
+    0x40000040, /* ".idata"    , */
+    0xE0000060, /* < other >   , */
+    0x40000040, /* ".rsrc"     , */
+    0x42000802, /* ".stab"     , */
+    0x42000040, /* ".reloc"    , */
+};
+
+struct section_info {
+    int cls, ord;
+    char name[32];
+    DWORD sh_addr;
+    DWORD sh_size;
+    DWORD sh_flags;
+    unsigned char *data;
+    DWORD data_size;
+    IMAGE_SECTION_HEADER ish;
+};
+
+struct import_symbol {
+    int sym_index;
+    int iat_index;
+    int thk_offset;
+};
+
+struct pe_import_info {
+    int dll_index;
+    int sym_count;
+    struct import_symbol **symbols;
+};
+
+struct pe_info {
+    TCCState *s1;
+    Section *reloc;
+    Section *thunk;
+    const char *filename;
+    int type;
+    DWORD sizeofheaders;
+    DWORD imagebase;
+    DWORD start_addr;
+    DWORD imp_offs;
+    DWORD imp_size;
+    DWORD iat_offs;
+    DWORD iat_size;
+    DWORD exp_offs;
+    DWORD exp_size;
+    struct section_info *sec_info;
+    int sec_count;
+    struct pe_import_info **imp_info;
+    int imp_count;
+};
+
+/* ------------------------------------------------------------- */
+
+#define PE_NUL 0
+#define PE_DLL 1
+#define PE_GUI 2
+#define PE_EXE 3
+
+void error_noabort(const char *, ...);
+
+#ifdef _WIN32
+void dbg_printf (const char *fmt, ...)
+{
+    char buffer[4000];
+    va_list arg;
+    int x;
+    va_start(arg, fmt);
+    x = vsprintf (buffer, fmt, arg);
+    strcpy(buffer+x, "\n");
+    OutputDebugString(buffer);
+}
+#endif
+
+/* --------------------------------------------*/
+
+ST_FN const char* get_alt_symbol(char *buffer, const char *symbol)
+{
+    const char *p;
+    p = strrchr(symbol, '@');
+    if (p && isnum(p[1]) && symbol[0] == '_') { /* stdcall decor */
+        strcpy(buffer, symbol+1)[p-symbol-1] = 0;
+    } else if (symbol[0] != '_') { /* try non-ansi function */
+        buffer[0] = '_', strcpy(buffer + 1, symbol);
+    } else if (0 == memcmp(symbol, "__imp__", 7)) { /* mingw 2.0 */
+        strcpy(buffer, symbol + 6);
+    } else if (0 == memcmp(symbol, "_imp___", 7)) { /* mingw 3.7 */
+        strcpy(buffer, symbol + 6);
+    } else {
+        return symbol;
+    }
+    return buffer;
+}
+
+ST_FN int pe_find_import(TCCState * s1, const char *symbol)
+{
+    char buffer[200];
+    const char *s;
+    int sym_index, n = 0;
+    do {
+        s = n ? get_alt_symbol(buffer, symbol) : symbol;
+        sym_index = find_elf_sym(s1->dynsymtab_section, s);
+        // printf("find %d %s\n", sym_index, s);
+    } while (0 == sym_index && ++n < 2);
+    return sym_index;
+}
+
+#if defined _WIN32 || defined __CYGWIN__
+
+#ifdef __CYGWIN__
+# include <dlfcn.h>
+# define LoadLibrary(s) dlopen(s, RTLD_NOW)
+# define GetProcAddress(h,s) dlsym(h, s)
+#else
+# define dlclose(h) FreeLibrary(h)
+#endif
+
+/* for the -run option: dynamically load symbol from dll */
+void *resolve_sym(struct TCCState *s1, const char *symbol, int type)
+{
+    char buffer[100];
+    int sym_index, dll_index;
+    void *addr, **m;
+    DLLReference *dllref;
+
+    sym_index = pe_find_import(s1, symbol);
+    if (0 == sym_index)
+        return NULL;
+    dll_index = ((Elf32_Sym *)s1->dynsymtab_section->data + sym_index)->st_value;
+    dllref = s1->loaded_dlls[dll_index-1];
+    if ( !dllref->handle )
+    {
+        dllref->handle = LoadLibrary(dllref->name);
+    }
+    addr = GetProcAddress(dllref->handle, symbol);
+    if (NULL == addr)
+        addr = GetProcAddress(dllref->handle, get_alt_symbol(buffer, symbol));
+
+    if (addr && STT_OBJECT == type) {
+        /* need to return a pointer to the address for data objects */
+        m = (void**)tcc_malloc(sizeof addr), *m = addr, addr = m;
+#ifdef MEM_DEBUG
+        /* yep, we don't free it */
+        mem_cur_size -= sizeof (void*);
+#endif
+    }
+    return addr;
+}
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+ST_FN int dynarray_assoc(void **pp, int n, int key)
+{
+    int i;
+    for (i = 0; i < n; ++i, ++pp)
+    if (key == **(int **) pp)
+        return i;
+    return -1;
+}
+
+#if 0
+ST_FN DWORD umin(DWORD a, DWORD b)
+{
+    return a < b ? a : b;
+}
+#endif
+
+ST_FN DWORD umax(DWORD a, DWORD b)
+{
+    return a < b ? b : a;
+}
+
+ST_FN void pe_fpad(FILE *fp, DWORD new_pos)
+{
+    DWORD pos = ftell(fp);
+    while (++pos <= new_pos)
+        fputc(0, fp);
+}
+
+ST_FN DWORD pe_file_align(DWORD n)
+{
+    return (n + (0x200 - 1)) & ~(0x200 - 1);
+}
+
+ST_FN DWORD pe_virtual_align(DWORD n)
+{
+    return (n + (0x1000 - 1)) & ~(0x1000 - 1);
+}
+
+ST_FN void pe_align_section(Section *s, int a)
+{
+    int i = s->data_offset & (a-1);
+    if (i)
+        section_ptr_add(s, a - i);
+}
+
+ST_FN void pe_set_datadir(int dir, DWORD addr, DWORD size)
+{
+    pe_header.opthdr.DataDirectory[dir].VirtualAddress = addr;
+    pe_header.opthdr.DataDirectory[dir].Size = size;
+}
+
+/*----------------------------------------------------------------------------*/
+ST_FN int pe_write(struct pe_info *pe)
+{
+    int i;
+    FILE *op;
+    DWORD file_offset, r;
+
+    op = fopen(pe->filename, "wb");
+    if (NULL == op) {
+        error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
+        return 1;
+    }
+
+    pe->sizeofheaders = pe_file_align(
+        sizeof pe_header
+        + pe->sec_count * sizeof (IMAGE_SECTION_HEADER)
+        );
+
+    file_offset = pe->sizeofheaders;
+    pe_fpad(op, file_offset);
+
+    if (2 == pe->s1->verbose)
+        printf("-------------------------------"
+               "\n  virt   file   size  section" "\n");
+
+    for (i = 0; i < pe->sec_count; ++i) {
+        struct section_info *si = pe->sec_info + i;
+        const char *sh_name = si->name;
+        unsigned long addr = si->sh_addr - pe->imagebase;
+        unsigned long size = si->sh_size;
+        IMAGE_SECTION_HEADER *psh = &si->ish;
+
+        if (2 == pe->s1->verbose)
+            printf("%6lx %6lx %6lx  %s\n",
+                addr, file_offset, size, sh_name);
+
+        switch (si->cls) {
+            case sec_text:
+                pe_header.opthdr.BaseOfCode = addr;
+                pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr;
+                break;
+
+            case sec_data:
+                pe_header.opthdr.BaseOfData = addr;
+                break;
+
+            case sec_bss:
+                break;
+
+            case sec_reloc:
+                pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
+                break;
+
+            case sec_rsrc:
+                pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
+                break;
+
+            case sec_stab:
+                break;
+        }
+
+        if (pe->thunk == pe->s1->sections[si->ord]) {
+            if (pe->imp_size) {
+                pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT,
+                    pe->imp_offs + addr, pe->imp_size);
+                pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT,
+                    pe->iat_offs + addr, pe->iat_size);
+            }
+            if (pe->exp_size) {
+                pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT,
+                    pe->exp_offs + addr, pe->exp_size);
+            }
+        }
+
+        strcpy((char*)psh->Name, sh_name);
+
+        psh->Characteristics = pe_sec_flags[si->cls];
+        psh->VirtualAddress = addr;
+        psh->Misc.VirtualSize = size;
+        pe_header.opthdr.SizeOfImage =
+            umax(pe_virtual_align(size + addr), pe_header.opthdr.SizeOfImage); 
+
+        if (si->data_size) {
+            psh->PointerToRawData = r = file_offset;
+            fwrite(si->data, 1, si->data_size, op);
+            file_offset = pe_file_align(file_offset + si->data_size);
+            psh->SizeOfRawData = file_offset - r;
+            pe_fpad(op, file_offset);
+        }
+    }
+
+    // pe_header.filehdr.TimeDateStamp = time(NULL);
+    pe_header.filehdr.NumberOfSections = pe->sec_count;
+    pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
+    pe_header.opthdr.ImageBase = pe->imagebase;
+    if (PE_DLL == pe->type)
+        pe_header.filehdr.Characteristics = 0x230E;
+    else if (PE_GUI != pe->type)
+        pe_header.opthdr.Subsystem = 3;
+
+    fseek(op, SEEK_SET, 0);
+    fwrite(&pe_header,  1, sizeof pe_header, op);
+    for (i = 0; i < pe->sec_count; ++i)
+        fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op);
+    fclose (op);
+
+    if (2 == pe->s1->verbose)
+        printf("-------------------------------\n");
+    if (pe->s1->verbose)
+        printf("<- %s (%lu bytes)\n", pe->filename, file_offset);
+
+    return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+ST_FN struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
+{
+    int i;
+    int dll_index;
+    struct pe_import_info *p;
+    struct import_symbol *s;
+
+    dll_index = ((Elf32_Sym *)pe->s1->dynsymtab_section->data + sym_index)->st_value;
+    if (0 == dll_index)
+        return NULL;
+
+    i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index);
+    if (-1 != i) {
+        p = pe->imp_info[i];
+        goto found_dll;
+    }
+    p = tcc_mallocz(sizeof *p);
+    p->dll_index = dll_index;
+    dynarray_add((void***)&pe->imp_info, &pe->imp_count, p);
+
+found_dll:
+    i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index);
+    if (-1 != i)
+        return p->symbols[i];
+
+    s = tcc_mallocz(sizeof *s);
+    dynarray_add((void***)&p->symbols, &p->sym_count, s);
+    s->sym_index = sym_index;
+    return s;
+}
+
+/*----------------------------------------------------------------------------*/
+ST_FN void pe_build_imports(struct pe_info *pe)
+{
+    int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
+    DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
+    int ndlls = pe->imp_count;
+
+    for (sym_cnt = i = 0; i < ndlls; ++i)
+        sym_cnt += pe->imp_info[i]->sym_count;
+
+    if (0 == sym_cnt)
+        return;
+
+    pe_align_section(pe->thunk, 16);
+
+    pe->imp_offs = dll_ptr = pe->thunk->data_offset;
+    pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header);
+    pe->iat_offs = dll_ptr + pe->imp_size;
+    pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD);
+    section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
+
+    thk_ptr = pe->iat_offs;
+    ent_ptr = pe->iat_offs + pe->iat_size;
+
+    for (i = 0; i < pe->imp_count; ++i) {
+        struct pe_import_header *hdr;
+        int k, n, v;
+        struct pe_import_info *p = pe->imp_info[i];
+        const char *name = pe->s1->loaded_dlls[p->dll_index-1]->name;
+
+        /* put the dll name into the import header */
+        v = put_elf_str(pe->thunk, name);
+
+        hdr = (struct pe_import_header*)(pe->thunk->data + dll_ptr);
+        hdr->first_thunk     = thk_ptr + rva_base;
+        hdr->first_entry     = ent_ptr + rva_base;
+        hdr->lib_name_offset = v + rva_base;
+
+        for (k = 0, n = p->sym_count; k <= n; ++k) {
+            if (k < n) {
+                DWORD iat_index = p->symbols[k]->iat_index;
+                int sym_index = p->symbols[k]->sym_index;
+                Elf32_Sym *imp_sym = (Elf32_Sym *)pe->s1->dynsymtab_section->data + sym_index;
+                Elf32_Sym *org_sym = (Elf32_Sym *)symtab_section->data + iat_index;
+                const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
+
+                org_sym->st_value = thk_ptr;
+                org_sym->st_shndx = pe->thunk->sh_num;
+                v = pe->thunk->data_offset + rva_base;
+                section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
+                put_elf_str(pe->thunk, name);
+
+            } else {
+                v = 0; /* last entry is zero */
+            }
+            *(DWORD*)(pe->thunk->data+thk_ptr) =
+            *(DWORD*)(pe->thunk->data+ent_ptr) = v;
+            thk_ptr += sizeof (DWORD);
+            ent_ptr += sizeof (DWORD);
+        }
+        dll_ptr += sizeof(struct pe_import_header);
+        dynarray_reset(&p->symbols, &p->sym_count);
+    }
+    dynarray_reset(&pe->imp_info, &pe->imp_count);
+}
+
+/* ------------------------------------------------------------- */
+/*
+    For now only functions are exported. Export of data
+    would work, but import requires compiler support to
+    do an additional indirection.
+
+    For instance:
+        __declspec(dllimport) extern int something;
+
+    needs to be translated to:
+
+        *(int*)something
+*/
+
+ST_FN int sym_cmp(const void *va, const void *vb)
+{
+    const char *ca = ((const char **)va)[1];
+    const char *cb = ((const char **)vb)[1];
+    return strcmp(ca, cb);
+}
+
+ST_FN void pe_build_exports(struct pe_info *pe)
+{
+    Elf32_Sym *sym;
+    int sym_index, sym_end;
+    DWORD rva_base, func_o, name_o, ord_o, str_o;
+    struct pe_export_header *hdr;
+    int sym_count, n, ord, *sorted, *sp;
+
+    FILE *op;
+    char buf[MAX_PATH];
+    const char *dllname;
+    const char *name;
+
+    rva_base = pe->thunk->sh_addr - pe->imagebase;
+    sym_count = 0, n = 1, sorted = NULL, op = NULL;
+
+    sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
+    for (sym_index = 1; sym_index < sym_end; ++sym_index) {
+        sym = (Elf32_Sym*)symtab_section->data + sym_index;
+        name = symtab_section->link->data + sym->st_name;
+        if ((sym->st_other & 1)
+            /* export only symbols from actually written sections */
+            && pe->s1->sections[sym->st_shndx]->sh_addr) {
+            dynarray_add((void***)&sorted, &sym_count, (void*)n);
+            dynarray_add((void***)&sorted, &sym_count, (void*)name);
+        }
+        ++n;
+#if 0
+        if (sym->st_other & 1)
+            printf("export: %s\n", name);
+        if (sym->st_other & 2)
+            printf("stdcall: %s\n", name);
+#endif
+    }
+
+    if (0 == sym_count)
+        return;
+    sym_count /= 2;
+
+    qsort (sorted, sym_count, 2 * sizeof sorted[0], sym_cmp);
+    pe_align_section(pe->thunk, 16);
+    dllname = tcc_basename(pe->filename);
+
+    pe->exp_offs = pe->thunk->data_offset;
+    func_o = pe->exp_offs + sizeof(struct pe_export_header);
+    name_o = func_o + sym_count * sizeof (DWORD);
+    ord_o = name_o + sym_count * sizeof (DWORD);
+    str_o = ord_o + sym_count * sizeof(WORD);
+
+    hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
+    hdr->Characteristics        = 0;
+    hdr->Base                   = 1;
+    hdr->NumberOfFunctions      = sym_count;
+    hdr->NumberOfNames          = sym_count;
+    hdr->AddressOfFunctions     = func_o + rva_base;
+    hdr->AddressOfNames         = name_o + rva_base;
+    hdr->AddressOfNameOrdinals  = ord_o + rva_base;
+    hdr->Name                   = str_o + rva_base;
+    put_elf_str(pe->thunk, dllname);
+
+#if 1
+    /* automatically write exports to <output-filename>.def */
+    strcpy(buf, pe->filename);
+    strcpy(tcc_fileextension(buf), ".def");
+    op = fopen(buf, "w");
+    if (NULL == op) {
+        error_noabort("could not create '%s': %s", buf, strerror(errno));
+    } else {
+        fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
+        if (pe->s1->verbose)
+            printf("<- %s (%d symbols)\n", buf, sym_count);
+    }
+#endif
+
+    for (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2)
+    {
+        sym_index = sp[0], name = (const char *)sp[1];
+        /* insert actual address later in pe_relocate_rva */
+        put_elf_reloc(symtab_section, pe->thunk,
+            func_o, R_386_RELATIVE, sym_index);
+        *(DWORD*)(pe->thunk->data + name_o)
+            = pe->thunk->data_offset + rva_base;
+        *(WORD*)(pe->thunk->data + ord_o)
+            = ord;
+        put_elf_str(pe->thunk, name);
+        func_o += sizeof (DWORD);
+        name_o += sizeof (DWORD);
+        ord_o += sizeof (WORD);
+
+        if (op)
+            fprintf(op, "%s\n", name);
+    }
+    pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
+    tcc_free(sorted);
+}
+
+/* ------------------------------------------------------------- */
+ST_FN void pe_build_reloc (struct pe_info *pe)
+{
+    DWORD offset, block_ptr, addr;
+    int count, i;
+    Elf32_Rel *rel, *rel_end;
+    Section *s = NULL, *sr;
+
+    offset = addr = block_ptr = count = i = 0;
+    rel = rel_end = NULL;
+
+    for(;;) {
+        if (rel < rel_end) {
+            int type = ELF32_R_TYPE(rel->r_info);
+            addr = rel->r_offset + s->sh_addr;
+            ++ rel;
+            if (type != R_386_32)
+                continue;
+            if (count == 0) { /* new block */
+                block_ptr = pe->reloc->data_offset;
+                section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header));
+                offset = addr & 0xFFFFFFFF<<12;
+            }
+            if ((addr -= offset)  < (1<<12)) { /* one block spans 4k addresses */
+                WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD));
+                *wp = addr | IMAGE_REL_BASED_HIGHLOW<<12;
+                ++count;
+                continue;
+            }
+            -- rel;
+
+        } else if (i < pe->sec_count) {
+            sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
+            if (sr) {
+                rel = (Elf32_Rel *)sr->data;
+                rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
+            }
+            continue;
+        }
+
+        if (count) {
+            /* store the last block and ready for a new one */
+            struct pe_reloc_header *hdr;
+            if (count & 1) /* align for DWORDS */
+                section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
+            hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
+            hdr -> offset = offset - pe->imagebase;
+            hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
+            count = 0;
+        }
+
+        if (rel >= rel_end)
+            break;
+    }
+}
+
+/* ------------------------------------------------------------- */
+ST_FN int pe_section_class(Section *s)
+{
+    int type, flags;
+    const char *name;
+
+    type = s->sh_type;
+    flags = s->sh_flags;
+    name = s->name;
+    if (flags & SHF_ALLOC) {
+        if (type == SHT_PROGBITS) {
+            if (flags & SHF_EXECINSTR)
+                return sec_text;
+            if (flags & SHF_WRITE)
+                return sec_data;
+            if (0 == strcmp(name, ".rsrc"))
+                return sec_rsrc;
+            if (0 == strcmp(name, ".iedat"))
+                return sec_idata;
+            return sec_other;
+        } else if (type == SHT_NOBITS) {
+            if (flags & SHF_WRITE)
+                return sec_bss;
+        }
+    } else {
+        if (0 == strcmp(name, ".reloc"))
+            return sec_reloc;
+        if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */
+            return sec_stab;
+    }
+    return -1;
+}
+
+ST_FN int pe_assign_addresses (struct pe_info *pe)
+{
+    int i, k, o, c;
+    DWORD addr;
+    int *section_order;
+    struct section_info *si;
+    Section *s;
+
+    // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
+
+    section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
+    for (o = k = 0 ; k < sec_last; ++k) {
+        for (i = 1; i < pe->s1->nb_sections; ++i) {
+            s = pe->s1->sections[i];
+            if (k == pe_section_class(s)) {
+                // printf("%s %d\n", s->name, k);
+                s->sh_addr = pe->imagebase;
+                section_order[o++] = i;
+            }
+        }
+    }
+
+    pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
+    addr = pe->imagebase + 1;
+
+    for (i = 0; i < o; ++i)
+    {
+        k = section_order[i];
+        s = pe->s1->sections[k];
+        c = pe_section_class(s);
+        si = &pe->sec_info[pe->sec_count];
+
+#ifdef PE_MERGE_DATA
+        if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
+            /* append .bss to .data */
+            s->sh_addr = addr = ((addr-1) | 15) + 1;
+            addr += s->data_offset;
+            si[-1].sh_size = addr - si[-1].sh_addr;
+            continue;
+        }
+#endif
+        strcpy(si->name, s->name);
+        si->cls = c;
+        si->ord = k;
+        si->sh_addr = s->sh_addr = addr = pe_virtual_align(addr);
+        si->sh_flags = s->sh_flags;
+
+        if (c == sec_data && NULL == pe->thunk)
+            pe->thunk = s;
+
+        if (s == pe->thunk) {
+            pe_build_imports(pe);
+            pe_build_exports(pe);
+        }
+
+        if (c == sec_reloc)
+            pe_build_reloc (pe);
+
+        if (s->data_offset)
+        {
+            if (s->sh_type != SHT_NOBITS) {
+                si->data = s->data;
+                si->data_size = s->data_offset;
+            }
+
+            addr += s->data_offset;
+            si->sh_size = s->data_offset;
+            ++pe->sec_count;
+        }
+        // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name);
+    }
+
+#if 0
+    for (i = 1; i < pe->s1->nb_sections; ++i) {
+        Section *s = pe->s1->sections[i];
+        int type = s->sh_type;
+        int flags = s->sh_flags;
+        printf("section %-16s %-10s %5x %s,%s,%s\n",
+            s->name,
+            type == SHT_PROGBITS ? "progbits" :
+            type == SHT_NOBITS ? "nobits" :
+            type == SHT_SYMTAB ? "symtab" :
+            type == SHT_STRTAB ? "strtab" :
+            type == SHT_REL ? "rel" : "???",
+            s->data_offset,
+            flags & SHF_ALLOC ? "alloc" : "",
+            flags & SHF_WRITE ? "write" : "",
+            flags & SHF_EXECINSTR ? "exec" : ""
+            );
+    }
+    pe->s1->verbose = 2;
+#endif
+
+    tcc_free(section_order);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+ST_FN void pe_relocate_rva (struct pe_info *pe, Section *s)
+{
+    Section *sr = s->reloc;
+    Elf32_Rel *rel, *rel_end;
+    rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
+    for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++)
+        if (ELF32_R_TYPE(rel->r_info) == R_386_RELATIVE) {
+            int sym_index = ELF32_R_SYM(rel->r_info);
+            DWORD addr = s->sh_addr;
+            if (sym_index) {
+                Elf32_Sym *sym = (Elf32_Sym *)symtab_section->data + sym_index;
+                addr = sym->st_value;
+            }
+            *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
+        }
+}
+
+/*----------------------------------------------------------------------------*/
+ST_FN int pe_check_symbols(struct pe_info *pe)
+{
+    Elf32_Sym *sym;
+    int sym_index, sym_end;
+    int ret = 0;
+
+    pe_align_section(text_section, 8);
+
+    sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
+    for (sym_index = 1; sym_index < sym_end; ++sym_index) {
+
+        sym = (Elf32_Sym*)symtab_section->data + sym_index;
+        if (sym->st_shndx == SHN_UNDEF) {
+
+            const char *name = symtab_section->link->data + sym->st_name;
+            unsigned type = ELF32_ST_TYPE(sym->st_info);
+            int imp_sym = pe_find_import(pe->s1, name);
+            struct import_symbol *is;
+
+            if (0 == imp_sym)
+                goto not_found;
+            is = pe_add_import(pe, imp_sym);
+            if (!is)
+                goto not_found;
+
+            if (type == STT_FUNC) {
+                unsigned long offset = is->thk_offset;
+                if (offset) {
+                    /* got aliased symbol, like stricmp and _stricmp */
+
+                } else {
+                    char buffer[100];
+
+                    offset = text_section->data_offset;
+                    /* add the 'jmp IAT[x]' instruction */
+                    *(WORD*)section_ptr_add(text_section, 8) = 0x25FF;
+
+                    /* add a helper symbol, will be patched later in
+                       pe_build_imports */
+                    sprintf(buffer, "IAT.%s", name);
+                    is->iat_index = put_elf_sym(
+                        symtab_section, 0, sizeof(DWORD),
+                        ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT),
+                        0, SHN_UNDEF, buffer);
+                    put_elf_reloc(symtab_section, text_section, 
+                        offset + 2, R_386_32, is->iat_index);
+                    is->thk_offset = offset;
+                }
+
+                /* tcc_realloc might have altered sym's address */
+                sym = (Elf32_Sym*)symtab_section->data + sym_index;
+
+                /* patch the original symbol */
+                sym->st_value = offset;
+                sym->st_shndx = text_section->sh_num;
+                sym->st_other &= ~1; /* do not export */
+                continue;
+            }
+
+            if (type == STT_OBJECT) { /* data, ptr to that should be */
+                if (0 == is->iat_index) {
+                    /* original symbol will be patched later in pe_build_imports */
+                    is->iat_index = sym_index;
+                    continue;
+                }
+            }
+
+        not_found:
+            error_noabort("undefined symbol '%s'", name);
+            ret = 1;
+
+        } else if (pe->s1->rdynamic
+                   && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
+            /* if -rdynamic option, then export all non local symbols */
+            sym->st_other |= 1;
+        }
+    }
+    return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+#ifdef PE_PRINT_SECTIONS
+ST_FN void pe_print_section(FILE * f, Section * s)
+{
+    /* just if you'r curious */
+    BYTE *p, *e, b;
+    int i, n, l, m;
+    p = s->data;
+    e = s->data + s->data_offset;
+    l = e - p;
+
+    fprintf(f, "section  \"%s\"", s->name);
+    if (s->link)
+        fprintf(f, "\nlink     \"%s\"", s->link->name);
+    if (s->reloc)
+        fprintf(f, "\nreloc    \"%s\"", s->reloc->name);
+    fprintf(f, "\nv_addr   %08X", s->sh_addr);
+    fprintf(f, "\ncontents %08X", l);
+    fprintf(f, "\n\n");
+
+    if (s->sh_type == SHT_NOBITS)
+        return;
+
+    if (0 == l)
+        return;
+
+    if (s->sh_type == SHT_SYMTAB)
+        m = sizeof(Elf32_Sym);
+    if (s->sh_type == SHT_REL)
+        m = sizeof(Elf32_Rel);
+    else
+        m = 16;
+
+    fprintf(f, "%-8s", "offset");
+    for (i = 0; i < m; ++i)
+        fprintf(f, " %02x", i);
+    n = 56;
+
+    if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_REL) {
+        const char *fields1[] = {
+            "name",
+            "value",
+            "size",
+            "bind",
+            "type",
+            "other",
+            "shndx",
+            NULL
+        };
+
+        const char *fields2[] = {
+            "offs",
+            "type",
+            "symb",
+            NULL
+        };
+
+        const char **p;
+
+        if (s->sh_type == SHT_SYMTAB)
+            p = fields1, n = 106;
+        else
+            p = fields2, n = 58;
+
+        for (i = 0; p[i]; ++i)
+            fprintf(f, "%6s", p[i]);
+        fprintf(f, "  symbol");
+    }
+
+    fprintf(f, "\n");
+    for (i = 0; i < n; ++i)
+        fprintf(f, "-");
+    fprintf(f, "\n");
+
+    for (i = 0; i < l;)
+    {
+        fprintf(f, "%08X", i);
+        for (n = 0; n < m; ++n) {
+            if (n + i < l)
+                fprintf(f, " %02X", p[i + n]);
+            else
+                fprintf(f, "   ");
+        }
+
+        if (s->sh_type == SHT_SYMTAB) {
+            Elf32_Sym *sym = (Elf32_Sym *) (p + i);
+            const char *name = s->link->data + sym->st_name;
+            fprintf(f, "  %04X  %04X  %04X   %02X    %02X    %02X   %04X  \"%s\"",
+                    sym->st_name,
+                    sym->st_value,
+                    sym->st_size,
+                    ELF32_ST_BIND(sym->st_info),
+                    ELF32_ST_TYPE(sym->st_info),
+                    sym->st_other, sym->st_shndx, name);
+
+        } else if (s->sh_type == SHT_REL) {
+            Elf32_Rel *rel = (Elf32_Rel *) (p + i);
+            Elf32_Sym *sym =
+                (Elf32_Sym *) s->link->data + ELF32_R_SYM(rel->r_info);
+            const char *name = s->link->link->data + sym->st_name;
+            fprintf(f, "  %04X   %02X   %04X  \"%s\"",
+                    rel->r_offset,
+                    ELF32_R_TYPE(rel->r_info),
+                    ELF32_R_SYM(rel->r_info), name);
+        } else {
+            fprintf(f, "   ");
+            for (n = 0; n < m; ++n) {
+                if (n + i < l) {
+                    b = p[i + n];
+                    if (b < 32 || b >= 127)
+                        b = '.';
+                    fprintf(f, "%c", b);
+                }
+            }
+        }
+        i += m;
+        fprintf(f, "\n");
+    }
+    fprintf(f, "\n\n");
+}
+
+ST_FN void pe_print_sections(TCCState *s1, const char *fname)
+{
+    Section *s;
+    FILE *f;
+    int i;
+    f = fopen(fname, "wt");
+    for (i = 1; i < s1->nb_sections; ++i) {
+        s = s1->sections[i];
+        pe_print_section(f, s);
+    }
+    pe_print_section(f, s1->dynsymtab_section);
+    fclose(f);
+}
+#endif
+
+/* -------------------------------------------------------------
+ *  This is for compiled windows resources in 'coff' format
+ *  as generated by 'windres.exe -O coff ...'.
+ */
+
+PUB_FN int pe_test_res_file(void *v, int size)
+{
+    struct pe_rsrc_header *p = (struct pe_rsrc_header *)v;
+    return
+        size >= IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_SHORT_NAME /* = 28 */
+        && p->filehdr.Machine == 0x014C
+        && 1 == p->filehdr.NumberOfSections
+        && 0 == strcmp(p->sectionhdr.Name, ".rsrc")
+        ;
+}
+
+ST_FN int read_n(int fd, void *ptr, unsigned size)
+{
+    return size == read(fd, ptr, size);
+}
+
+PUB_FN int pe_load_res_file(TCCState *s1, int fd)
+{
+    struct pe_rsrc_header hdr;
+    Section *rsrc_section;
+    int i, ret = -1;
+    BYTE *ptr;
+
+    lseek (fd, 0, SEEK_SET);
+    if (!read_n(fd, &hdr, sizeof hdr))
+        goto quit;
+    if (!pe_test_res_file(&hdr, sizeof hdr))
+        goto quit;
+
+    rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
+    ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
+    lseek (fd, hdr.sectionhdr.PointerToRawData, SEEK_SET);
+    if (!read_n(fd, ptr, hdr.sectionhdr.SizeOfRawData))
+        goto quit;
+
+    lseek (fd, hdr.sectionhdr.PointerToRelocations, SEEK_SET);
+    for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
+    {
+        struct pe_rsrc_reloc rel;
+        if (!read_n(fd, &rel, sizeof rel))
+            goto quit;
+        // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
+        if (rel.type != 7) /* DIR32NB */
+            goto quit;
+        put_elf_reloc(symtab_section, rsrc_section,
+            rel.offset, R_386_RELATIVE, 0);
+    }
+    ret = 0;
+quit:
+    if (ret)
+        error_noabort("unrecognized resource file format");
+    return ret;
+}
+
+/* ------------------------------------------------------------- */
+ST_FN char *trimfront(char *p)
+{
+    while (*p && (unsigned char)*p <= ' ')
+        ++p;
+    return p;
+}
+
+ST_FN char *trimback(char *a, char *e)
+{
+    while (e > a && (unsigned char)e[-1] <= ' ')
+        --e;
+    *e = 0;;
+    return a;
+}
+
+ST_FN char *get_line(char *line, int size, FILE *fp)
+{
+    if (NULL == fgets(line, size, fp))
+        return NULL;
+    trimback(line, strchr(line, 0));
+    return trimfront(line);
+}
+
+/* ------------------------------------------------------------- */
+PUB_FN int pe_load_def_file(TCCState *s1, int fd)
+{
+    DLLReference *dllref;
+    int state = 0, ret = -1;
+    char line[400], dllname[80], *p;
+    FILE *fp = fdopen(dup(fd), "rb");
+
+    if (NULL == fp)
+        goto quit;
+
+    for (;;) {
+        p = get_line(line, sizeof line, fp);
+        if (NULL == p)
+            break;
+        if (0 == *p || ';' == *p)
+            continue;
+        switch (state) {
+        case 0:
+            if (0 != strnicmp(p, "LIBRARY", 7))
+                goto quit;
+            strcpy(dllname, trimfront(p+7));
+            ++state;
+            continue;
+
+        case 1:
+            if (0 != stricmp(p, "EXPORTS"))
+                goto quit;
+            ++state;
+            continue;
+
+        case 2:
+            dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname));
+            strcpy(dllref->name, dllname);
+            dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
+            ++state;
+
+        default:
+            add_elf_sym(s1->dynsymtab_section,
+                s1->nb_loaded_dlls, 0,
+                ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), 0,
+                text_section->sh_num, p);
+            continue;
+        }
+    }
+    ret = 0;
+quit:
+    if (fp)
+        fclose(fp);
+    if (ret)
+        error_noabort("unrecognized export definition file format");
+    return ret;
+}
+
+/* ------------------------------------------------------------- */
+
+ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
+{
+    const char *start_symbol;
+    unsigned long addr = 0;
+    int pe_type = 0;
+
+    if (find_elf_sym(symtab_section, "_WinMain@16"))
+        pe_type = PE_GUI;
+    else
+    if (TCC_OUTPUT_DLL == s1->output_type) {
+        pe_type = PE_DLL;
+        /* need this for 'tccelf.c:relocate_section()' */
+        s1->output_type = TCC_OUTPUT_EXE;
+    }
+
+    start_symbol =
+        TCC_OUTPUT_MEMORY == s1->output_type
+        ? PE_GUI == pe_type ? "_runwinmain" : NULL
+        : PE_DLL == pe_type ? "__dllstart@12"
+        : PE_GUI == pe_type ? "_winstart" : "_start"
+        ;
+
+    /* grab the startup code from libtcc1 */
+    if (start_symbol)
+        add_elf_sym(symtab_section,
+            0, 0,
+            ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
+            SHN_UNDEF, start_symbol);
+
+    if (0 == s1->nostdlib) {
+        tcc_add_library(s1, "tcc1");
+#ifdef __CYGWIN__
+        tcc_add_library(s1, "cygwin1");
+#else
+        tcc_add_library(s1, "msvcrt");
+#endif
+        tcc_add_library(s1, "kernel32");
+        if (PE_DLL == pe_type || PE_GUI == pe_type) {
+            tcc_add_library(s1, "user32");
+            tcc_add_library(s1, "gdi32");
+        }
+    }
+
+    if (start_symbol) {
+        addr = (unsigned long)tcc_get_symbol_err(s1, start_symbol);
+        if (s1->output_type == TCC_OUTPUT_MEMORY && addr)
+            /* for -run GUI's, put '_runwinmain' instead of 'main' */
+            add_elf_sym(symtab_section,
+                    addr, 0,
+                    ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
+                    text_section->sh_num, "main");
+    }
+
+    if (pe) {
+        pe->type = pe_type;
+        pe->start_addr = addr;
+    }
+}
+
+PUB_FN void pe_add_runtime(TCCState *s1)
+{
+    pe_add_runtime_ex(s1, NULL);
+}
+
+PUB_FN int pe_output_file(TCCState * s1, const char *filename)
+{
+    int ret;
+    struct pe_info pe;
+    int i;
+
+    memset(&pe, 0, sizeof pe);
+    pe.filename = filename;
+    pe.s1 = s1;
+
+    pe_add_runtime_ex(s1, &pe);
+    relocate_common_syms(); /* assign bss adresses */
+    tcc_add_linker_symbols(s1);
+
+    ret = pe_check_symbols(&pe);
+    if (0 == ret) {
+        if (PE_DLL == pe.type) {
+            pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
+            pe.imagebase = 0x10000000;
+        } else {
+            pe.imagebase = 0x00400000;
+        }
+        pe_assign_addresses(&pe);
+        relocate_syms(s1, 0);
+        for (i = 1; i < s1->nb_sections; ++i) {
+            Section *s = s1->sections[i];
+            if (s->reloc) {
+                relocate_section(s1, s);
+                pe_relocate_rva(&pe, s);
+            }
+        }
+        if (s1->nb_errors)
+            ret = 1;
+        else
+            ret = pe_write(&pe);
+        tcc_free(pe.sec_info);
+    }
+
+#ifdef PE_PRINT_SECTIONS
+    pe_print_sections(s1, "tcc.log");
+#endif
+    return ret;
+}
+
+/* ------------------------------------------------------------- */
+#endif /* def TCC_TARGET_PE */
+/* ------------------------------------------------------------- */
diff --git a/tinyc/tccpp.c b/tinyc/tccpp.c
new file mode 100644
index 000000000..ff17d8bed
--- /dev/null
+++ b/tinyc/tccpp.c
@@ -0,0 +1,2935 @@
+/*
+ *  TCC - Tiny C Compiler
+ * 
+ *  Copyright (c) 2001-2004 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+
+static const char tcc_keywords[] = 
+#define DEF(id, str) str "\0"
+#include "tcctok.h"
+#undef DEF
+;
+
+/* WARNING: the content of this string encodes token numbers */
+static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266";
+
+/* true if isid(c) || isnum(c) */
+static unsigned char isidnum_table[256-CH_EOF];
+
+
+struct macro_level {
+    struct macro_level *prev;
+    int *p;
+};
+
+static void next_nomacro(void);
+static void next_nomacro_spc(void);
+static void macro_subst(TokenString *tok_str, Sym **nested_list,
+                        const int *macro_str, struct macro_level **can_read_stream);
+
+
+/* allocate a new token */
+static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
+{
+    TokenSym *ts, **ptable;
+    int i;
+
+    if (tok_ident >= SYM_FIRST_ANOM) 
+        error("memory full");
+
+    /* expand token table if needed */
+    i = tok_ident - TOK_IDENT;
+    if ((i % TOK_ALLOC_INCR) == 0) {
+        ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
+        if (!ptable)
+            error("memory full");
+        table_ident = ptable;
+    }
+
+    ts = tcc_malloc(sizeof(TokenSym) + len);
+    table_ident[i] = ts;
+    ts->tok = tok_ident++;
+    ts->sym_define = NULL;
+    ts->sym_label = NULL;
+    ts->sym_struct = NULL;
+    ts->sym_identifier = NULL;
+    ts->len = len;
+    ts->hash_next = NULL;
+    memcpy(ts->str, str, len);
+    ts->str[len] = '\0';
+    *pts = ts;
+    return ts;
+}
+
+#define TOK_HASH_INIT 1
+#define TOK_HASH_FUNC(h, c) ((h) * 263 + (c))
+
+/* find a token and add it if not found */
+static TokenSym *tok_alloc(const char *str, int len)
+{
+    TokenSym *ts, **pts;
+    int i;
+    unsigned int h;
+    
+    h = TOK_HASH_INIT;
+    for(i=0;i<len;i++)
+        h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]);
+    h &= (TOK_HASH_SIZE - 1);
+
+    pts = &hash_ident[h];
+    for(;;) {
+        ts = *pts;
+        if (!ts)
+            break;
+        if (ts->len == len && !memcmp(ts->str, str, len))
+            return ts;
+        pts = &(ts->hash_next);
+    }
+    return tok_alloc_new(pts, str, len);
+}
+
+/* XXX: buffer overflow */
+/* XXX: float tokens */
+char *get_tok_str(int v, CValue *cv)
+{
+    static char buf[STRING_MAX_SIZE + 1];
+    static CString cstr_buf;
+    CString *cstr;
+    unsigned char *q;
+    char *p;
+    int i, len;
+
+    /* NOTE: to go faster, we give a fixed buffer for small strings */
+    cstr_reset(&cstr_buf);
+    cstr_buf.data = buf;
+    cstr_buf.size_allocated = sizeof(buf);
+    p = buf;
+
+    switch(v) {
+    case TOK_CINT:
+    case TOK_CUINT:
+        /* XXX: not quite exact, but only useful for testing */
+        sprintf(p, "%u", cv->ui);
+        break;
+    case TOK_CLLONG:
+    case TOK_CULLONG:
+        /* XXX: not quite exact, but only useful for testing  */
+        sprintf(p, "%Lu", cv->ull);
+        break;
+    case TOK_LCHAR:
+        cstr_ccat(&cstr_buf, 'L');
+    case TOK_CCHAR:
+        cstr_ccat(&cstr_buf, '\'');
+        add_char(&cstr_buf, cv->i);
+        cstr_ccat(&cstr_buf, '\'');
+        cstr_ccat(&cstr_buf, '\0');
+        break;
+    case TOK_PPNUM:
+        cstr = cv->cstr;
+        len = cstr->size - 1;
+        for(i=0;i<len;i++)
+            add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
+        cstr_ccat(&cstr_buf, '\0');
+        break;
+    case TOK_LSTR:
+        cstr_ccat(&cstr_buf, 'L');
+    case TOK_STR:
+        cstr = cv->cstr;
+        cstr_ccat(&cstr_buf, '\"');
+        if (v == TOK_STR) {
+            len = cstr->size - 1;
+            for(i=0;i<len;i++)
+                add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]);
+        } else {
+            len = (cstr->size / sizeof(nwchar_t)) - 1;
+            for(i=0;i<len;i++)
+                add_char(&cstr_buf, ((nwchar_t *)cstr->data)[i]);
+        }
+        cstr_ccat(&cstr_buf, '\"');
+        cstr_ccat(&cstr_buf, '\0');
+        break;
+    case TOK_LT:
+        v = '<';
+        goto addv;
+    case TOK_GT:
+        v = '>';
+        goto addv;
+    case TOK_DOTS:
+        return strcpy(p, "...");
+    case TOK_A_SHL:
+        return strcpy(p, "<<=");
+    case TOK_A_SAR:
+        return strcpy(p, ">>=");
+    default:
+        if (v < TOK_IDENT) {
+            /* search in two bytes table */
+            q = tok_two_chars;
+            while (*q) {
+                if (q[2] == v) {
+                    *p++ = q[0];
+                    *p++ = q[1];
+                    *p = '\0';
+                    return buf;
+                }
+                q += 3;
+            }
+        addv:
+            *p++ = v;
+            *p = '\0';
+        } else if (v < tok_ident) {
+            return table_ident[v - TOK_IDENT]->str;
+        } else if (v >= SYM_FIRST_ANOM) {
+            /* special name for anonymous symbol */
+            sprintf(p, "L.%u", v - SYM_FIRST_ANOM);
+        } else {
+            /* should never happen */
+            return NULL;
+        }
+        break;
+    }
+    return cstr_buf.data;
+}
+
+/* fill input buffer and peek next char */
+static int tcc_peekc_slow(BufferedFile *bf)
+{
+    int len;
+    /* only tries to read if really end of buffer */
+    if (bf->buf_ptr >= bf->buf_end) {
+        if (bf->fd != -1) {
+#if defined(PARSE_DEBUG)
+            len = 8;
+#else
+            len = IO_BUF_SIZE;
+#endif
+            len = read(bf->fd, bf->buffer, len);
+            if (len < 0)
+                len = 0;
+        } else {
+            len = 0;
+        }
+        total_bytes += len;
+        bf->buf_ptr = bf->buffer;
+        bf->buf_end = bf->buffer + len;
+        *bf->buf_end = CH_EOB;
+    }
+    if (bf->buf_ptr < bf->buf_end) {
+        return bf->buf_ptr[0];
+    } else {
+        bf->buf_ptr = bf->buf_end;
+        return CH_EOF;
+    }
+}
+
+/* return the current character, handling end of block if necessary
+   (but not stray) */
+static int handle_eob(void)
+{
+    return tcc_peekc_slow(file);
+}
+
+/* read next char from current input file and handle end of input buffer */
+static inline void inp(void)
+{
+    ch = *(++(file->buf_ptr));
+    /* end of buffer/file handling */
+    if (ch == CH_EOB)
+        ch = handle_eob();
+}
+
+/* handle '\[\r]\n' */
+static int handle_stray_noerror(void)
+{
+    while (ch == '\\') {
+        inp();
+        if (ch == '\n') {
+            file->line_num++;
+            inp();
+        } else if (ch == '\r') {
+            inp();
+            if (ch != '\n')
+                goto fail;
+            file->line_num++;
+            inp();
+        } else {
+        fail:
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static void handle_stray(void)
+{
+    if (handle_stray_noerror())
+        error("stray '\\' in program");
+}
+
+/* skip the stray and handle the \\n case. Output an error if
+   incorrect char after the stray */
+static int handle_stray1(uint8_t *p)
+{
+    int c;
+
+    if (p >= file->buf_end) {
+        file->buf_ptr = p;
+        c = handle_eob();
+        p = file->buf_ptr;
+        if (c == '\\')
+            goto parse_stray;
+    } else {
+    parse_stray:
+        file->buf_ptr = p;
+        ch = *p;
+        handle_stray();
+        p = file->buf_ptr;
+        c = *p;
+    }
+    return c;
+}
+
+/* handle just the EOB case, but not stray */
+#define PEEKC_EOB(c, p)\
+{\
+    p++;\
+    c = *p;\
+    if (c == '\\') {\
+        file->buf_ptr = p;\
+        c = handle_eob();\
+        p = file->buf_ptr;\
+    }\
+}
+
+/* handle the complicated stray case */
+#define PEEKC(c, p)\
+{\
+    p++;\
+    c = *p;\
+    if (c == '\\') {\
+        c = handle_stray1(p);\
+        p = file->buf_ptr;\
+    }\
+}
+
+/* input with '\[\r]\n' handling. Note that this function cannot
+   handle other characters after '\', so you cannot call it inside
+   strings or comments */
+static void minp(void)
+{
+    inp();
+    if (ch == '\\') 
+        handle_stray();
+}
+
+
+/* single line C++ comments */
+static uint8_t *parse_line_comment(uint8_t *p)
+{
+    int c;
+
+    p++;
+    for(;;) {
+        c = *p;
+    redo:
+        if (c == '\n' || c == CH_EOF) {
+            break;
+        } else if (c == '\\') {
+            file->buf_ptr = p;
+            c = handle_eob();
+            p = file->buf_ptr;
+            if (c == '\\') {
+                PEEKC_EOB(c, p);
+                if (c == '\n') {
+                    file->line_num++;
+                    PEEKC_EOB(c, p);
+                } else if (c == '\r') {
+                    PEEKC_EOB(c, p);
+                    if (c == '\n') {
+                        file->line_num++;
+                        PEEKC_EOB(c, p);
+                    }
+                }
+            } else {
+                goto redo;
+            }
+        } else {
+            p++;
+        }
+    }
+    return p;
+}
+
+/* C comments */
+static uint8_t *parse_comment(uint8_t *p)
+{
+    int c;
+    
+    p++;
+    for(;;) {
+        /* fast skip loop */
+        for(;;) {
+            c = *p;
+            if (c == '\n' || c == '*' || c == '\\')
+                break;
+            p++;
+            c = *p;
+            if (c == '\n' || c == '*' || c == '\\')
+                break;
+            p++;
+        }
+        /* now we can handle all the cases */
+        if (c == '\n') {
+            file->line_num++;
+            p++;
+        } else if (c == '*') {
+            p++;
+            for(;;) {
+                c = *p;
+                if (c == '*') {
+                    p++;
+                } else if (c == '/') {
+                    goto end_of_comment;
+                } else if (c == '\\') {
+                    file->buf_ptr = p;
+                    c = handle_eob();
+                    p = file->buf_ptr;
+                    if (c == '\\') {
+                        /* skip '\[\r]\n', otherwise just skip the stray */
+                        while (c == '\\') {
+                            PEEKC_EOB(c, p);
+                            if (c == '\n') {
+                                file->line_num++;
+                                PEEKC_EOB(c, p);
+                            } else if (c == '\r') {
+                                PEEKC_EOB(c, p);
+                                if (c == '\n') {
+                                    file->line_num++;
+                                    PEEKC_EOB(c, p);
+                                }
+                            } else {
+                                goto after_star;
+                            }
+                        }
+                    }
+                } else {
+                    break;
+                }
+            }
+        after_star: ;
+        } else {
+            /* stray, eob or eof */
+            file->buf_ptr = p;
+            c = handle_eob();
+            p = file->buf_ptr;
+            if (c == CH_EOF) {
+                error("unexpected end of file in comment");
+            } else if (c == '\\') {
+                p++;
+            }
+        }
+    }
+ end_of_comment:
+    p++;
+    return p;
+}
+
+#define cinp minp
+
+static inline void skip_spaces(void)
+{
+    while (is_space(ch))
+        cinp();
+}
+
+static inline int check_space(int t, int *spc) 
+{
+    if (is_space(t)) {
+        if (*spc) 
+            return 1;
+        *spc = 1;
+    } else 
+        *spc = 0;
+    return 0;
+}
+
+/* parse a string without interpreting escapes */
+static uint8_t *parse_pp_string(uint8_t *p,
+                                int sep, CString *str)
+{
+    int c;
+    p++;
+    for(;;) {
+        c = *p;
+        if (c == sep) {
+            break;
+        } else if (c == '\\') {
+            file->buf_ptr = p;
+            c = handle_eob();
+            p = file->buf_ptr;
+            if (c == CH_EOF) {
+            unterminated_string:
+                /* XXX: indicate line number of start of string */
+                error("missing terminating %c character", sep);
+            } else if (c == '\\') {
+                /* escape : just skip \[\r]\n */
+                PEEKC_EOB(c, p);
+                if (c == '\n') {
+                    file->line_num++;
+                    p++;
+                } else if (c == '\r') {
+                    PEEKC_EOB(c, p);
+                    if (c != '\n')
+                        expect("'\n' after '\r'");
+                    file->line_num++;
+                    p++;
+                } else if (c == CH_EOF) {
+                    goto unterminated_string;
+                } else {
+                    if (str) {
+                        cstr_ccat(str, '\\');
+                        cstr_ccat(str, c);
+                    }
+                    p++;
+                }
+            }
+        } else if (c == '\n') {
+            file->line_num++;
+            goto add_char;
+        } else if (c == '\r') {
+            PEEKC_EOB(c, p);
+            if (c != '\n') {
+                if (str)
+                    cstr_ccat(str, '\r');
+            } else {
+                file->line_num++;
+                goto add_char;
+            }
+        } else {
+        add_char:
+            if (str)
+                cstr_ccat(str, c);
+            p++;
+        }
+    }
+    p++;
+    return p;
+}
+
+/* skip block of text until #else, #elif or #endif. skip also pairs of
+   #if/#endif */
+void preprocess_skip(void)
+{
+    int a, start_of_line, c, in_warn_or_error;
+    uint8_t *p;
+
+    p = file->buf_ptr;
+    a = 0;
+redo_start:
+    start_of_line = 1;
+    in_warn_or_error = 0;
+    for(;;) {
+    redo_no_start:
+        c = *p;
+        switch(c) {
+        case ' ':
+        case '\t':
+        case '\f':
+        case '\v':
+        case '\r':
+            p++;
+            goto redo_no_start;
+        case '\n':
+            file->line_num++;
+            p++;
+            goto redo_start;
+        case '\\':
+            file->buf_ptr = p;
+            c = handle_eob();
+            if (c == CH_EOF) {
+                expect("#endif");
+            } else if (c == '\\') {
+                ch = file->buf_ptr[0];
+                handle_stray_noerror();
+            }
+            p = file->buf_ptr;
+            goto redo_no_start;
+        /* skip strings */
+        case '\"':
+        case '\'':
+            if (in_warn_or_error)
+                goto _default;
+            p = parse_pp_string(p, c, NULL);
+            break;
+        /* skip comments */
+        case '/':
+            if (in_warn_or_error)
+                goto _default;
+            file->buf_ptr = p;
+            ch = *p;
+            minp();
+            p = file->buf_ptr;
+            if (ch == '*') {
+                p = parse_comment(p);
+            } else if (ch == '/') {
+                p = parse_line_comment(p);
+            }
+            break;
+        case '#':
+            p++;
+            if (start_of_line) {
+                file->buf_ptr = p;
+                next_nomacro();
+                p = file->buf_ptr;
+                if (a == 0 && 
+                    (tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF))
+                    goto the_end;
+                if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF)
+                    a++;
+                else if (tok == TOK_ENDIF)
+                    a--;
+                else if( tok == TOK_ERROR || tok == TOK_WARNING)
+                    in_warn_or_error = 1;
+            }
+            break;
+_default:
+        default:
+            p++;
+            break;
+        }
+        start_of_line = 0;
+    }
+ the_end: ;
+    file->buf_ptr = p;
+}
+
+/* ParseState handling */
+
+/* XXX: currently, no include file info is stored. Thus, we cannot display
+   accurate messages if the function or data definition spans multiple
+   files */
+
+/* save current parse state in 's' */
+void save_parse_state(ParseState *s)
+{
+    s->line_num = file->line_num;
+    s->macro_ptr = macro_ptr;
+    s->tok = tok;
+    s->tokc = tokc;
+}
+
+/* restore parse state from 's' */
+void restore_parse_state(ParseState *s)
+{
+    file->line_num = s->line_num;
+    macro_ptr = s->macro_ptr;
+    tok = s->tok;
+    tokc = s->tokc;
+}
+
+/* return the number of additional 'ints' necessary to store the
+   token */
+static inline int tok_ext_size(int t)
+{
+    switch(t) {
+        /* 4 bytes */
+    case TOK_CINT:
+    case TOK_CUINT:
+    case TOK_CCHAR:
+    case TOK_LCHAR:
+    case TOK_CFLOAT:
+    case TOK_LINENUM:
+        return 1;
+    case TOK_STR:
+    case TOK_LSTR:
+    case TOK_PPNUM:
+        error("unsupported token");
+        return 1;
+    case TOK_CDOUBLE:
+    case TOK_CLLONG:
+    case TOK_CULLONG:
+        return 2;
+    case TOK_CLDOUBLE:
+        return LDOUBLE_SIZE / 4;
+    default:
+        return 0;
+    }
+}
+
+/* token string handling */
+
+static inline void tok_str_new(TokenString *s)
+{
+    s->str = NULL;
+    s->len = 0;
+    s->allocated_len = 0;
+    s->last_line_num = -1;
+}
+
+static void tok_str_free(int *str)
+{
+    tcc_free(str);
+}
+
+static int *tok_str_realloc(TokenString *s)
+{
+    int *str, len;
+
+    if (s->allocated_len == 0) {
+        len = 8;
+    } else {
+        len = s->allocated_len * 2;
+    }
+    str = tcc_realloc(s->str, len * sizeof(int));
+    if (!str)
+        error("memory full");
+    s->allocated_len = len;
+    s->str = str;
+    return str;
+}
+
+static void tok_str_add(TokenString *s, int t)
+{
+    int len, *str;
+
+    len = s->len;
+    str = s->str;
+    if (len >= s->allocated_len)
+        str = tok_str_realloc(s);
+    str[len++] = t;
+    s->len = len;
+}
+
+static void tok_str_add2(TokenString *s, int t, CValue *cv)
+{
+    int len, *str;
+
+    len = s->len;
+    str = s->str;
+
+    /* allocate space for worst case */
+    if (len + TOK_MAX_SIZE > s->allocated_len)
+        str = tok_str_realloc(s);
+    str[len++] = t;
+    switch(t) {
+    case TOK_CINT:
+    case TOK_CUINT:
+    case TOK_CCHAR:
+    case TOK_LCHAR:
+    case TOK_CFLOAT:
+    case TOK_LINENUM:
+        str[len++] = cv->tab[0];
+        break;
+    case TOK_PPNUM:
+    case TOK_STR:
+    case TOK_LSTR:
+        {
+            int nb_words;
+            CString *cstr;
+
+            nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2;
+            while ((len + nb_words) > s->allocated_len)
+                str = tok_str_realloc(s);
+            cstr = (CString *)(str + len);
+            cstr->data = NULL;
+            cstr->size = cv->cstr->size;
+            cstr->data_allocated = NULL;
+            cstr->size_allocated = cstr->size;
+            memcpy((char *)cstr + sizeof(CString), 
+                   cv->cstr->data, cstr->size);
+            len += nb_words;
+        }
+        break;
+    case TOK_CDOUBLE:
+    case TOK_CLLONG:
+    case TOK_CULLONG:
+#if LDOUBLE_SIZE == 8
+    case TOK_CLDOUBLE:
+#endif
+        str[len++] = cv->tab[0];
+        str[len++] = cv->tab[1];
+        break;
+#if LDOUBLE_SIZE == 12
+    case TOK_CLDOUBLE:
+        str[len++] = cv->tab[0];
+        str[len++] = cv->tab[1];
+        str[len++] = cv->tab[2];
+#elif LDOUBLE_SIZE == 16
+    case TOK_CLDOUBLE:
+        str[len++] = cv->tab[0];
+        str[len++] = cv->tab[1];
+        str[len++] = cv->tab[2];
+        str[len++] = cv->tab[3];
+#elif LDOUBLE_SIZE != 8
+#error add long double size support
+#endif
+        break;
+    default:
+        break;
+    }
+    s->len = len;
+}
+
+/* add the current parse token in token string 's' */
+static void tok_str_add_tok(TokenString *s)
+{
+    CValue cval;
+
+    /* save line number info */
+    if (file->line_num != s->last_line_num) {
+        s->last_line_num = file->line_num;
+        cval.i = s->last_line_num;
+        tok_str_add2(s, TOK_LINENUM, &cval);
+    }
+    tok_str_add2(s, tok, &tokc);
+}
+
+#if LDOUBLE_SIZE == 16
+#define LDOUBLE_GET(p, cv)                      \
+        cv.tab[0] = p[0];                       \
+        cv.tab[1] = p[1];                       \
+        cv.tab[2] = p[2];                       \
+        cv.tab[3] = p[3];
+#elif LDOUBLE_SIZE == 12
+#define LDOUBLE_GET(p, cv)                      \
+        cv.tab[0] = p[0];                       \
+        cv.tab[1] = p[1];                       \
+        cv.tab[2] = p[2];
+#elif LDOUBLE_SIZE == 8
+#define LDOUBLE_GET(p, cv)                      \
+        cv.tab[0] = p[0];                       \
+        cv.tab[1] = p[1];
+#else
+#error add long double size support
+#endif
+
+
+/* get a token from an integer array and increment pointer
+   accordingly. we code it as a macro to avoid pointer aliasing. */
+#define TOK_GET(t, p, cv)                       \
+{                                               \
+    t = *p++;                                   \
+    switch(t) {                                 \
+    case TOK_CINT:                              \
+    case TOK_CUINT:                             \
+    case TOK_CCHAR:                             \
+    case TOK_LCHAR:                             \
+    case TOK_CFLOAT:                            \
+    case TOK_LINENUM:                           \
+        cv.tab[0] = *p++;                       \
+        break;                                  \
+    case TOK_STR:                               \
+    case TOK_LSTR:                              \
+    case TOK_PPNUM:                             \
+        cv.cstr = (CString *)p;                 \
+        cv.cstr->data = (char *)p + sizeof(CString);\
+        p += (sizeof(CString) + cv.cstr->size + 3) >> 2;\
+        break;                                  \
+    case TOK_CDOUBLE:                           \
+    case TOK_CLLONG:                            \
+    case TOK_CULLONG:                           \
+        cv.tab[0] = p[0];                       \
+        cv.tab[1] = p[1];                       \
+        p += 2;                                 \
+        break;                                  \
+    case TOK_CLDOUBLE:                          \
+        LDOUBLE_GET(p, cv);                     \
+        p += LDOUBLE_SIZE / 4;                  \
+        break;                                  \
+    default:                                    \
+        break;                                  \
+    }                                           \
+}
+
+/* defines handling */
+static inline void define_push(int v, int macro_type, int *str, Sym *first_arg)
+{
+    Sym *s;
+
+    s = sym_push2(&define_stack, v, macro_type, (long)str);
+    s->next = first_arg;
+    table_ident[v - TOK_IDENT]->sym_define = s;
+}
+
+/* undefined a define symbol. Its name is just set to zero */
+static void define_undef(Sym *s)
+{
+    int v;
+    v = s->v;
+    if (v >= TOK_IDENT && v < tok_ident)
+        table_ident[v - TOK_IDENT]->sym_define = NULL;
+    s->v = 0;
+}
+
+static inline Sym *define_find(int v)
+{
+    v -= TOK_IDENT;
+    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
+        return NULL;
+    return table_ident[v]->sym_define;
+}
+
+/* free define stack until top reaches 'b' */
+static void free_defines(Sym *b)
+{
+    Sym *top, *top1;
+    int v;
+
+    top = define_stack;
+    while (top != b) {
+        top1 = top->prev;
+        /* do not free args or predefined defines */
+        if (top->c)
+            tok_str_free((int *)top->c);
+        v = top->v;
+        if (v >= TOK_IDENT && v < tok_ident)
+            table_ident[v - TOK_IDENT]->sym_define = NULL;
+        sym_free(top);
+        top = top1;
+    }
+    define_stack = b;
+}
+
+/* label lookup */
+static Sym *label_find(int v)
+{
+    v -= TOK_IDENT;
+    if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT))
+        return NULL;
+    return table_ident[v]->sym_label;
+}
+
+static Sym *label_push(Sym **ptop, int v, int flags)
+{
+    Sym *s, **ps;
+    s = sym_push2(ptop, v, 0, 0);
+    s->r = flags;
+    ps = &table_ident[v - TOK_IDENT]->sym_label;
+    if (ptop == &global_label_stack) {
+        /* modify the top most local identifier, so that
+           sym_identifier will point to 's' when popped */
+        while (*ps != NULL)
+            ps = &(*ps)->prev_tok;
+    }
+    s->prev_tok = *ps;
+    *ps = s;
+    return s;
+}
+
+/* pop labels until element last is reached. Look if any labels are
+   undefined. Define symbols if '&&label' was used. */
+static void label_pop(Sym **ptop, Sym *slast)
+{
+    Sym *s, *s1;
+    for(s = *ptop; s != slast; s = s1) {
+        s1 = s->prev;
+        if (s->r == LABEL_DECLARED) {
+            warning("label '%s' declared but not used", get_tok_str(s->v, NULL));
+        } else if (s->r == LABEL_FORWARD) {
+                error("label '%s' used but not defined",
+                      get_tok_str(s->v, NULL));
+        } else {
+            if (s->c) {
+                /* define corresponding symbol. A size of
+                   1 is put. */
+                put_extern_sym(s, cur_text_section, (long)s->next, 1);
+            }
+        }
+        /* remove label */
+        table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok;
+        sym_free(s);
+    }
+    *ptop = slast;
+}
+
+/* eval an expression for #if/#elif */
+static int expr_preprocess(void)
+{
+    int c, t;
+    TokenString str;
+    
+    tok_str_new(&str);
+    while (tok != TOK_LINEFEED && tok != TOK_EOF) {
+        next(); /* do macro subst */
+        if (tok == TOK_DEFINED) {
+            next_nomacro();
+            t = tok;
+            if (t == '(') 
+                next_nomacro();
+            c = define_find(tok) != 0;
+            if (t == '(')
+                next_nomacro();
+            tok = TOK_CINT;
+            tokc.i = c;
+        } else if (tok >= TOK_IDENT) {
+            /* if undefined macro */
+            tok = TOK_CINT;
+            tokc.i = 0;
+        }
+        tok_str_add_tok(&str);
+    }
+    tok_str_add(&str, -1); /* simulate end of file */
+    tok_str_add(&str, 0);
+    /* now evaluate C constant expression */
+    macro_ptr = str.str;
+    next();
+    c = expr_const();
+    macro_ptr = NULL;
+    tok_str_free(str.str);
+    return c != 0;
+}
+
+#if defined(PARSE_DEBUG) || defined(PP_DEBUG)
+static void tok_print(int *str)
+{
+    int t;
+    CValue cval;
+
+    printf("<");
+    while (1) {
+        TOK_GET(t, str, cval);
+        if (!t)
+            break;
+        printf("%s", get_tok_str(t, &cval));
+    }
+    printf(">\n");
+}
+#endif
+
+/* parse after #define */
+static void parse_define(void)
+{
+    Sym *s, *first, **ps;
+    int v, t, varg, is_vaargs, spc;
+    TokenString str;
+    
+    v = tok;
+    if (v < TOK_IDENT)
+        error("invalid macro name '%s'", get_tok_str(tok, &tokc));
+    /* XXX: should check if same macro (ANSI) */
+    first = NULL;
+    t = MACRO_OBJ;
+    /* '(' must be just after macro definition for MACRO_FUNC */
+    next_nomacro_spc();
+    if (tok == '(') {
+        next_nomacro();
+        ps = &first;
+        while (tok != ')') {
+            varg = tok;
+            next_nomacro();
+            is_vaargs = 0;
+            if (varg == TOK_DOTS) {
+                varg = TOK___VA_ARGS__;
+                is_vaargs = 1;
+            } else if (tok == TOK_DOTS && gnu_ext) {
+                is_vaargs = 1;
+                next_nomacro();
+            }
+            if (varg < TOK_IDENT)
+                error("badly punctuated parameter list");
+            s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0);
+            *ps = s;
+            ps = &s->next;
+            if (tok != ',')
+                break;
+            next_nomacro();
+        }
+        if (tok == ')')
+            next_nomacro_spc();
+        t = MACRO_FUNC;
+    }
+    tok_str_new(&str);
+    spc = 2;
+    /* EOF testing necessary for '-D' handling */
+    while (tok != TOK_LINEFEED && tok != TOK_EOF) {
+        /* remove spaces around ## and after '#' */        
+        if (TOK_TWOSHARPS == tok) {
+            if (1 == spc)
+                --str.len;
+            spc = 2;
+        } else if ('#' == tok) {
+            spc = 2;
+        } else if (check_space(tok, &spc)) {
+            goto skip;
+        }
+        tok_str_add2(&str, tok, &tokc);
+    skip:
+        next_nomacro_spc();
+    }
+    if (spc == 1)
+        --str.len; /* remove trailing space */
+    tok_str_add(&str, 0);
+#ifdef PP_DEBUG
+    printf("define %s %d: ", get_tok_str(v, NULL), t);
+    tok_print(str.str);
+#endif
+    define_push(v, t, str.str, first);
+}
+
+static inline int hash_cached_include(int type, const char *filename)
+{
+    const unsigned char *s;
+    unsigned int h;
+
+    h = TOK_HASH_INIT;
+    h = TOK_HASH_FUNC(h, type);
+    s = filename;
+    while (*s) {
+        h = TOK_HASH_FUNC(h, *s);
+        s++;
+    }
+    h &= (CACHED_INCLUDES_HASH_SIZE - 1);
+    return h;
+}
+
+/* XXX: use a token or a hash table to accelerate matching ? */
+static CachedInclude *search_cached_include(TCCState *s1,
+                                            int type, const char *filename)
+{
+    CachedInclude *e;
+    int i, h;
+    h = hash_cached_include(type, filename);
+    i = s1->cached_includes_hash[h];
+    for(;;) {
+        if (i == 0)
+            break;
+        e = s1->cached_includes[i - 1];
+        if (e->type == type && !PATHCMP(e->filename, filename))
+            return e;
+        i = e->hash_next;
+    }
+    return NULL;
+}
+
+static inline void add_cached_include(TCCState *s1, int type, 
+                                      const char *filename, int ifndef_macro)
+{
+    CachedInclude *e;
+    int h;
+
+    if (search_cached_include(s1, type, filename))
+        return;
+#ifdef INC_DEBUG
+    printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL));
+#endif
+    e = tcc_malloc(sizeof(CachedInclude) + strlen(filename));
+    if (!e)
+        return;
+    e->type = type;
+    strcpy(e->filename, filename);
+    e->ifndef_macro = ifndef_macro;
+    dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e);
+    /* add in hash table */
+    h = hash_cached_include(type, filename);
+    e->hash_next = s1->cached_includes_hash[h];
+    s1->cached_includes_hash[h] = s1->nb_cached_includes;
+}
+
+static void pragma_parse(TCCState *s1)
+{
+    int val;
+
+    next();
+    if (tok == TOK_pack) {
+        /*
+          This may be:
+          #pragma pack(1) // set
+          #pragma pack() // reset to default
+          #pragma pack(push,1) // push & set
+          #pragma pack(pop) // restore previous
+        */
+        next();
+        skip('(');
+        if (tok == TOK_ASM_pop) {
+            next();
+            if (s1->pack_stack_ptr <= s1->pack_stack) {
+            stk_error:
+                error("out of pack stack");
+            }
+            s1->pack_stack_ptr--;
+        } else {
+            val = 0;
+            if (tok != ')') {
+                if (tok == TOK_ASM_push) {
+                    next();
+                    if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1)
+                        goto stk_error;
+                    s1->pack_stack_ptr++;
+                    skip(',');
+                }
+                if (tok != TOK_CINT) {
+                pack_error:
+                    error("invalid pack pragma");
+                }
+                val = tokc.i;
+                if (val < 1 || val > 16 || (val & (val - 1)) != 0)
+                    goto pack_error;
+                next();
+            }
+            *s1->pack_stack_ptr = val;
+            skip(')');
+        }
+    }
+}
+
+/* is_bof is true if first non space token at beginning of file */
+static void preprocess(int is_bof)
+{
+    TCCState *s1 = tcc_state;
+    int i, c, n, saved_parse_flags;
+    char buf[1024], *q;
+    Sym *s;
+
+    saved_parse_flags = parse_flags;
+    parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | 
+        PARSE_FLAG_LINEFEED;
+    next_nomacro();
+ redo:
+    switch(tok) {
+    case TOK_DEFINE:
+        next_nomacro();
+        parse_define();
+        break;
+    case TOK_UNDEF:
+        next_nomacro();
+        s = define_find(tok);
+        /* undefine symbol by putting an invalid name */
+        if (s)
+            define_undef(s);
+        break;
+    case TOK_INCLUDE:
+    case TOK_INCLUDE_NEXT:
+        ch = file->buf_ptr[0];
+        /* XXX: incorrect if comments : use next_nomacro with a special mode */
+        skip_spaces();
+        if (ch == '<') {
+            c = '>';
+            goto read_name;
+        } else if (ch == '\"') {
+            c = ch;
+        read_name:
+            inp();
+            q = buf;
+            while (ch != c && ch != '\n' && ch != CH_EOF) {
+                if ((q - buf) < sizeof(buf) - 1)
+                    *q++ = ch;
+                if (ch == '\\') {
+                    if (handle_stray_noerror() == 0)
+                        --q;
+                } else
+                    inp();
+            }
+            *q = '\0';
+            minp();
+#if 0
+            /* eat all spaces and comments after include */
+            /* XXX: slightly incorrect */
+            while (ch1 != '\n' && ch1 != CH_EOF)
+                inp();
+#endif
+        } else {
+            /* computed #include : either we have only strings or
+               we have anything enclosed in '<>' */
+            next();
+            buf[0] = '\0';
+            if (tok == TOK_STR) {
+                while (tok != TOK_LINEFEED) {
+                    if (tok != TOK_STR) {
+                    include_syntax:
+                        error("'#include' expects \"FILENAME\" or <FILENAME>");
+                    }
+                    pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data);
+                    next();
+                }
+                c = '\"';
+            } else {
+                int len;
+                while (tok != TOK_LINEFEED) {
+                    pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc));
+                    next();
+                }
+                len = strlen(buf);
+                /* check syntax and remove '<>' */
+                if (len < 2 || buf[0] != '<' || buf[len - 1] != '>')
+                    goto include_syntax;
+                memmove(buf, buf + 1, len - 2);
+                buf[len - 2] = '\0';
+                c = '>';
+            }
+        }
+
+        if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE)
+            error("#include recursion too deep");
+
+        n = s1->nb_include_paths + s1->nb_sysinclude_paths;
+        for (i = -2; i < n; ++i) {
+            char buf1[sizeof file->filename];
+            BufferedFile *f;
+            CachedInclude *e;
+            const char *path;
+            int size;
+
+            if (i == -2) {
+                /* check absolute include path */
+                if (!IS_ABSPATH(buf))
+                    continue;
+                buf1[0] = 0;
+
+            } else if (i == -1) {
+                /* search in current dir if "header.h" */
+                if (c != '\"')
+                    continue;
+                size = tcc_basename(file->filename) - file->filename;
+                memcpy(buf1, file->filename, size);
+                buf1[size] = '\0';
+
+            } else {
+                /* search in all the include paths */
+                if (i < s1->nb_include_paths)
+                    path = s1->include_paths[i];
+                else
+                    path = s1->sysinclude_paths[i - s1->nb_include_paths];
+                pstrcpy(buf1, sizeof(buf1), path);
+                pstrcat(buf1, sizeof(buf1), "/");
+            }
+
+            pstrcat(buf1, sizeof(buf1), buf);
+
+            e = search_cached_include(s1, c, buf1);
+            if (e && define_find(e->ifndef_macro)) {
+                /* no need to parse the include because the 'ifndef macro'
+                   is defined */
+#ifdef INC_DEBUG
+                printf("%s: skipping %s\n", file->filename, buf);
+#endif
+                f = NULL;
+            }  else {
+                f = tcc_open(s1, buf1);
+                if (!f)
+                    continue;
+            }
+
+            if (tok == TOK_INCLUDE_NEXT) {
+                tok = TOK_INCLUDE;
+                if (f)
+                    tcc_close(f);
+                continue;
+            }
+
+            if (!f)
+                goto include_done;
+
+#ifdef INC_DEBUG
+            printf("%s: including %s\n", file->filename, buf1);
+#endif
+
+           /* XXX: fix current line init */
+           /* push current file in stack */
+            *s1->include_stack_ptr++ = file;
+            f->inc_type = c;
+            pstrcpy(f->inc_filename, sizeof(f->inc_filename), buf1);
+            file = f;
+            /* add include file debug info */
+            if (tcc_state->do_debug) {
+                put_stabs(file->filename, N_BINCL, 0, 0, 0);
+            }
+            tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
+            ch = file->buf_ptr[0];
+            goto the_end;
+        }
+        error("include file '%s' not found", buf);
+include_done:
+        break;
+    case TOK_IFNDEF:
+        c = 1;
+        goto do_ifdef;
+    case TOK_IF:
+        c = expr_preprocess();
+        goto do_if;
+    case TOK_IFDEF:
+        c = 0;
+    do_ifdef:
+        next_nomacro();
+        if (tok < TOK_IDENT)
+            error("invalid argument for '#if%sdef'", c ? "n" : "");
+        if (is_bof) {
+            if (c) {
+#ifdef INC_DEBUG
+                printf("#ifndef %s\n", get_tok_str(tok, NULL));
+#endif
+                file->ifndef_macro = tok;
+            }
+        }
+        c = (define_find(tok) != 0) ^ c;
+    do_if:
+        if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE)
+            error("memory full");
+        *s1->ifdef_stack_ptr++ = c;
+        goto test_skip;
+    case TOK_ELSE:
+        if (s1->ifdef_stack_ptr == s1->ifdef_stack)
+            error("#else without matching #if");
+        if (s1->ifdef_stack_ptr[-1] & 2)
+            error("#else after #else");
+        c = (s1->ifdef_stack_ptr[-1] ^= 3);
+        goto test_skip;
+    case TOK_ELIF:
+        if (s1->ifdef_stack_ptr == s1->ifdef_stack)
+            error("#elif without matching #if");
+        c = s1->ifdef_stack_ptr[-1];
+        if (c > 1)
+            error("#elif after #else");
+        /* last #if/#elif expression was true: we skip */
+        if (c == 1)
+            goto skip;
+        c = expr_preprocess();
+        s1->ifdef_stack_ptr[-1] = c;
+    test_skip:
+        if (!(c & 1)) {
+        skip:
+            preprocess_skip();
+            is_bof = 0;
+            goto redo;
+        }
+        break;
+    case TOK_ENDIF:
+        if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr)
+            error("#endif without matching #if");
+        s1->ifdef_stack_ptr--;
+        /* '#ifndef macro' was at the start of file. Now we check if
+           an '#endif' is exactly at the end of file */
+        if (file->ifndef_macro &&
+            s1->ifdef_stack_ptr == file->ifdef_stack_ptr) {
+            file->ifndef_macro_saved = file->ifndef_macro;
+            /* need to set to zero to avoid false matches if another
+               #ifndef at middle of file */
+            file->ifndef_macro = 0;
+            while (tok != TOK_LINEFEED)
+                next_nomacro();
+            tok_flags |= TOK_FLAG_ENDIF;
+            goto the_end;
+        }
+        break;
+    case TOK_LINE:
+        next();
+        if (tok != TOK_CINT)
+            error("#line");
+        file->line_num = tokc.i - 1; /* the line number will be incremented after */
+        next();
+        if (tok != TOK_LINEFEED) {
+            if (tok != TOK_STR)
+                error("#line");
+            pstrcpy(file->filename, sizeof(file->filename), 
+                    (char *)tokc.cstr->data);
+        }
+        break;
+    case TOK_ERROR:
+    case TOK_WARNING:
+        c = tok;
+        ch = file->buf_ptr[0];
+        skip_spaces();
+        q = buf;
+        while (ch != '\n' && ch != CH_EOF) {
+            if ((q - buf) < sizeof(buf) - 1)
+                *q++ = ch;
+            if (ch == '\\') {
+                if (handle_stray_noerror() == 0)
+                    --q;
+            } else
+                inp();
+        }
+        *q = '\0';
+        if (c == TOK_ERROR)
+            error("#error %s", buf);
+        else
+            warning("#warning %s", buf);
+        break;
+    case TOK_PRAGMA:
+        pragma_parse(s1);
+        break;
+    default:
+        if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) {
+            /* '!' is ignored to allow C scripts. numbers are ignored
+               to emulate cpp behaviour */
+        } else {
+            if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS))
+                warning("Ignoring unknown preprocessing directive #%s", get_tok_str(tok, &tokc));
+        }
+        break;
+    }
+    /* ignore other preprocess commands or #! for C scripts */
+    while (tok != TOK_LINEFEED)
+        next_nomacro();
+ the_end:
+    parse_flags = saved_parse_flags;
+}
+
+/* evaluate escape codes in a string. */
+static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long)
+{
+    int c, n;
+    const uint8_t *p;
+
+    p = buf;
+    for(;;) {
+        c = *p;
+        if (c == '\0')
+            break;
+        if (c == '\\') {
+            p++;
+            /* escape */
+            c = *p;
+            switch(c) {
+            case '0': case '1': case '2': case '3':
+            case '4': case '5': case '6': case '7':
+                /* at most three octal digits */
+                n = c - '0';
+                p++;
+                c = *p;
+                if (isoct(c)) {
+                    n = n * 8 + c - '0';
+                    p++;
+                    c = *p;
+                    if (isoct(c)) {
+                        n = n * 8 + c - '0';
+                        p++;
+                    }
+                }
+                c = n;
+                goto add_char_nonext;
+            case 'x':
+            case 'u':
+            case 'U':
+                p++;
+                n = 0;
+                for(;;) {
+                    c = *p;
+                    if (c >= 'a' && c <= 'f')
+                        c = c - 'a' + 10;
+                    else if (c >= 'A' && c <= 'F')
+                        c = c - 'A' + 10;
+                    else if (isnum(c))
+                        c = c - '0';
+                    else
+                        break;
+                    n = n * 16 + c;
+                    p++;
+                }
+                c = n;
+                goto add_char_nonext;
+            case 'a':
+                c = '\a';
+                break;
+            case 'b':
+                c = '\b';
+                break;
+            case 'f':
+                c = '\f';
+                break;
+            case 'n':
+                c = '\n';
+                break;
+            case 'r':
+                c = '\r';
+                break;
+            case 't':
+                c = '\t';
+                break;
+            case 'v':
+                c = '\v';
+                break;
+            case 'e':
+                if (!gnu_ext)
+                    goto invalid_escape;
+                c = 27;
+                break;
+            case '\'':
+            case '\"':
+            case '\\': 
+            case '?':
+                break;
+            default:
+            invalid_escape:
+                if (c >= '!' && c <= '~')
+                    warning("unknown escape sequence: \'\\%c\'", c);
+                else
+                    warning("unknown escape sequence: \'\\x%x\'", c);
+                break;
+            }
+        }
+        p++;
+    add_char_nonext:
+        if (!is_long)
+            cstr_ccat(outstr, c);
+        else
+            cstr_wccat(outstr, c);
+    }
+    /* add a trailing '\0' */
+    if (!is_long)
+        cstr_ccat(outstr, '\0');
+    else
+        cstr_wccat(outstr, '\0');
+}
+
+/* we use 64 bit numbers */
+#define BN_SIZE 2
+
+/* bn = (bn << shift) | or_val */
+void bn_lshift(unsigned int *bn, int shift, int or_val)
+{
+    int i;
+    unsigned int v;
+    for(i=0;i<BN_SIZE;i++) {
+        v = bn[i];
+        bn[i] = (v << shift) | or_val;
+        or_val = v >> (32 - shift);
+    }
+}
+
+void bn_zero(unsigned int *bn)
+{
+    int i;
+    for(i=0;i<BN_SIZE;i++) {
+        bn[i] = 0;
+    }
+}
+
+/* parse number in null terminated string 'p' and return it in the
+   current token */
+void parse_number(const char *p)
+{
+    int b, t, shift, frac_bits, s, exp_val, ch;
+    char *q;
+    unsigned int bn[BN_SIZE];
+    double d;
+
+    /* number */
+    q = token_buf;
+    ch = *p++;
+    t = ch;
+    ch = *p++;
+    *q++ = t;
+    b = 10;
+    if (t == '.') {
+        goto float_frac_parse;
+    } else if (t == '0') {
+        if (ch == 'x' || ch == 'X') {
+            q--;
+            ch = *p++;
+            b = 16;
+        } else if (tcc_ext && (ch == 'b' || ch == 'B')) {
+            q--;
+            ch = *p++;
+            b = 2;
+        }
+    }
+    /* parse all digits. cannot check octal numbers at this stage
+       because of floating point constants */
+    while (1) {
+        if (ch >= 'a' && ch <= 'f')
+            t = ch - 'a' + 10;
+        else if (ch >= 'A' && ch <= 'F')
+            t = ch - 'A' + 10;
+        else if (isnum(ch))
+            t = ch - '0';
+        else
+            break;
+        if (t >= b)
+            break;
+        if (q >= token_buf + STRING_MAX_SIZE) {
+        num_too_long:
+            error("number too long");
+        }
+        *q++ = ch;
+        ch = *p++;
+    }
+    if (ch == '.' ||
+        ((ch == 'e' || ch == 'E') && b == 10) ||
+        ((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) {
+        if (b != 10) {
+            /* NOTE: strtox should support that for hexa numbers, but
+               non ISOC99 libcs do not support it, so we prefer to do
+               it by hand */
+            /* hexadecimal or binary floats */
+            /* XXX: handle overflows */
+            *q = '\0';
+            if (b == 16)
+                shift = 4;
+            else 
+                shift = 2;
+            bn_zero(bn);
+            q = token_buf;
+            while (1) {
+                t = *q++;
+                if (t == '\0') {
+                    break;
+                } else if (t >= 'a') {
+                    t = t - 'a' + 10;
+                } else if (t >= 'A') {
+                    t = t - 'A' + 10;
+                } else {
+                    t = t - '0';
+                }
+                bn_lshift(bn, shift, t);
+            }
+            frac_bits = 0;
+            if (ch == '.') {
+                ch = *p++;
+                while (1) {
+                    t = ch;
+                    if (t >= 'a' && t <= 'f') {
+                        t = t - 'a' + 10;
+                    } else if (t >= 'A' && t <= 'F') {
+                        t = t - 'A' + 10;
+                    } else if (t >= '0' && t <= '9') {
+                        t = t - '0';
+                    } else {
+                        break;
+                    }
+                    if (t >= b)
+                        error("invalid digit");
+                    bn_lshift(bn, shift, t);
+                    frac_bits += shift;
+                    ch = *p++;
+                }
+            }
+            if (ch != 'p' && ch != 'P')
+                expect("exponent");
+            ch = *p++;
+            s = 1;
+            exp_val = 0;
+            if (ch == '+') {
+                ch = *p++;
+            } else if (ch == '-') {
+                s = -1;
+                ch = *p++;
+            }
+            if (ch < '0' || ch > '9')
+                expect("exponent digits");
+            while (ch >= '0' && ch <= '9') {
+                exp_val = exp_val * 10 + ch - '0';
+                ch = *p++;
+            }
+            exp_val = exp_val * s;
+            
+            /* now we can generate the number */
+            /* XXX: should patch directly float number */
+            d = (double)bn[1] * 4294967296.0 + (double)bn[0];
+            d = ldexp(d, exp_val - frac_bits);
+            t = toup(ch);
+            if (t == 'F') {
+                ch = *p++;
+                tok = TOK_CFLOAT;
+                /* float : should handle overflow */
+                tokc.f = (float)d;
+            } else if (t == 'L') {
+                ch = *p++;
+                tok = TOK_CLDOUBLE;
+                /* XXX: not large enough */
+                tokc.ld = (long double)d;
+            } else {
+                tok = TOK_CDOUBLE;
+                tokc.d = d;
+            }
+        } else {
+            /* decimal floats */
+            if (ch == '.') {
+                if (q >= token_buf + STRING_MAX_SIZE)
+                    goto num_too_long;
+                *q++ = ch;
+                ch = *p++;
+            float_frac_parse:
+                while (ch >= '0' && ch <= '9') {
+                    if (q >= token_buf + STRING_MAX_SIZE)
+                        goto num_too_long;
+                    *q++ = ch;
+                    ch = *p++;
+                }
+            }
+            if (ch == 'e' || ch == 'E') {
+                if (q >= token_buf + STRING_MAX_SIZE)
+                    goto num_too_long;
+                *q++ = ch;
+                ch = *p++;
+                if (ch == '-' || ch == '+') {
+                    if (q >= token_buf + STRING_MAX_SIZE)
+                        goto num_too_long;
+                    *q++ = ch;
+                    ch = *p++;
+                }
+                if (ch < '0' || ch > '9')
+                    expect("exponent digits");
+                while (ch >= '0' && ch <= '9') {
+                    if (q >= token_buf + STRING_MAX_SIZE)
+                        goto num_too_long;
+                    *q++ = ch;
+                    ch = *p++;
+                }
+            }
+            *q = '\0';
+            t = toup(ch);
+            errno = 0;
+            if (t == 'F') {
+                ch = *p++;
+                tok = TOK_CFLOAT;
+                tokc.f = strtof(token_buf, NULL);
+            } else if (t == 'L') {
+                ch = *p++;
+                tok = TOK_CLDOUBLE;
+                tokc.ld = strtold(token_buf, NULL);
+            } else {
+                tok = TOK_CDOUBLE;
+                tokc.d = strtod(token_buf, NULL);
+            }
+        }
+    } else {
+        unsigned long long n, n1;
+        int lcount, ucount;
+
+        /* integer number */
+        *q = '\0';
+        q = token_buf;
+        if (b == 10 && *q == '0') {
+            b = 8;
+            q++;
+        }
+        n = 0;
+        while(1) {
+            t = *q++;
+            /* no need for checks except for base 10 / 8 errors */
+            if (t == '\0') {
+                break;
+            } else if (t >= 'a') {
+                t = t - 'a' + 10;
+            } else if (t >= 'A') {
+                t = t - 'A' + 10;
+            } else {
+                t = t - '0';
+                if (t >= b)
+                    error("invalid digit");
+            }
+            n1 = n;
+            n = n * b + t;
+            /* detect overflow */
+            /* XXX: this test is not reliable */
+            if (n < n1)
+                error("integer constant overflow");
+        }
+        
+        /* XXX: not exactly ANSI compliant */
+        if ((n & 0xffffffff00000000LL) != 0) {
+            if ((n >> 63) != 0)
+                tok = TOK_CULLONG;
+            else
+                tok = TOK_CLLONG;
+        } else if (n > 0x7fffffff) {
+            tok = TOK_CUINT;
+        } else {
+            tok = TOK_CINT;
+        }
+        lcount = 0;
+        ucount = 0;
+        for(;;) {
+            t = toup(ch);
+            if (t == 'L') {
+                if (lcount >= 2)
+                    error("three 'l's in integer constant");
+                lcount++;
+                if (lcount == 2) {
+                    if (tok == TOK_CINT)
+                        tok = TOK_CLLONG;
+                    else if (tok == TOK_CUINT)
+                        tok = TOK_CULLONG;
+                }
+                ch = *p++;
+            } else if (t == 'U') {
+                if (ucount >= 1)
+                    error("two 'u's in integer constant");
+                ucount++;
+                if (tok == TOK_CINT)
+                    tok = TOK_CUINT;
+                else if (tok == TOK_CLLONG)
+                    tok = TOK_CULLONG;
+                ch = *p++;
+            } else {
+                break;
+            }
+        }
+        if (tok == TOK_CINT || tok == TOK_CUINT)
+            tokc.ui = n;
+        else
+            tokc.ull = n;
+    }
+    if (ch)
+        error("invalid number\n");
+}
+
+
+#define PARSE2(c1, tok1, c2, tok2)              \
+    case c1:                                    \
+        PEEKC(c, p);                            \
+        if (c == c2) {                          \
+            p++;                                \
+            tok = tok2;                         \
+        } else {                                \
+            tok = tok1;                         \
+        }                                       \
+        break;
+
+/* return next token without macro substitution */
+static inline void next_nomacro1(void)
+{
+    int t, c, is_long;
+    TokenSym *ts;
+    uint8_t *p, *p1;
+    unsigned int h;
+
+    p = file->buf_ptr;
+ redo_no_start:
+    c = *p;
+    switch(c) {
+    case ' ':
+    case '\t':
+        tok = c;
+        p++;
+        goto keep_tok_flags;
+    case '\f':
+    case '\v':
+    case '\r':
+        p++;
+        goto redo_no_start;
+    case '\\':
+        /* first look if it is in fact an end of buffer */
+        if (p >= file->buf_end) {
+            file->buf_ptr = p;
+            handle_eob();
+            p = file->buf_ptr;
+            if (p >= file->buf_end)
+                goto parse_eof;
+            else
+                goto redo_no_start;
+        } else {
+            file->buf_ptr = p;
+            ch = *p;
+            handle_stray();
+            p = file->buf_ptr;
+            goto redo_no_start;
+        }
+    parse_eof:
+        {
+            TCCState *s1 = tcc_state;
+            if ((parse_flags & PARSE_FLAG_LINEFEED)
+                && !(tok_flags & TOK_FLAG_EOF)) {
+                tok_flags |= TOK_FLAG_EOF;
+                tok = TOK_LINEFEED;
+                goto keep_tok_flags;
+            } else if (s1->include_stack_ptr == s1->include_stack ||
+                       !(parse_flags & PARSE_FLAG_PREPROCESS)) {
+                /* no include left : end of file. */
+                tok = TOK_EOF;
+            } else {
+                tok_flags &= ~TOK_FLAG_EOF;
+                /* pop include file */
+                
+                /* test if previous '#endif' was after a #ifdef at
+                   start of file */
+                if (tok_flags & TOK_FLAG_ENDIF) {
+#ifdef INC_DEBUG
+                    printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL));
+#endif
+                    add_cached_include(s1, file->inc_type, file->inc_filename,
+                                       file->ifndef_macro_saved);
+                }
+
+                /* add end of include file debug info */
+                if (tcc_state->do_debug) {
+                    put_stabd(N_EINCL, 0, 0);
+                }
+                /* pop include stack */
+                tcc_close(file);
+                s1->include_stack_ptr--;
+                file = *s1->include_stack_ptr;
+                p = file->buf_ptr;
+                goto redo_no_start;
+            }
+        }
+        break;
+
+    case '\n':
+        file->line_num++;
+        tok_flags |= TOK_FLAG_BOL;
+        p++;
+        if (0 == (parse_flags & PARSE_FLAG_LINEFEED))
+            goto redo_no_start;
+        tok = TOK_LINEFEED;
+        goto keep_tok_flags;
+
+    case '#':
+        /* XXX: simplify */
+        PEEKC(c, p);
+        if ((tok_flags & TOK_FLAG_BOL) && 
+            (parse_flags & PARSE_FLAG_PREPROCESS)) {
+            file->buf_ptr = p;
+            preprocess(tok_flags & TOK_FLAG_BOF);
+            p = file->buf_ptr;
+            goto redo_no_start;
+        } else {
+            if (c == '#') {
+                p++;
+                tok = TOK_TWOSHARPS;
+            } else {
+                if (parse_flags & PARSE_FLAG_ASM_COMMENTS) {
+                    p = parse_line_comment(p - 1);
+                    goto redo_no_start;
+                } else {
+                    tok = '#';
+                }
+            }
+        }
+        break;
+
+    case 'a': case 'b': case 'c': case 'd':
+    case 'e': case 'f': case 'g': case 'h':
+    case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p':
+    case 'q': case 'r': case 's': case 't':
+    case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z': 
+    case 'A': case 'B': case 'C': case 'D':
+    case 'E': case 'F': case 'G': case 'H':
+    case 'I': case 'J': case 'K': 
+    case 'M': case 'N': case 'O': case 'P':
+    case 'Q': case 'R': case 'S': case 'T':
+    case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z': 
+    case '_':
+    parse_ident_fast:
+        p1 = p;
+        h = TOK_HASH_INIT;
+        h = TOK_HASH_FUNC(h, c);
+        p++;
+        for(;;) {
+            c = *p;
+            if (!isidnum_table[c-CH_EOF])
+                break;
+            h = TOK_HASH_FUNC(h, c);
+            p++;
+        }
+        if (c != '\\') {
+            TokenSym **pts;
+            int len;
+
+            /* fast case : no stray found, so we have the full token
+               and we have already hashed it */
+            len = p - p1;
+            h &= (TOK_HASH_SIZE - 1);
+            pts = &hash_ident[h];
+            for(;;) {
+                ts = *pts;
+                if (!ts)
+                    break;
+                if (ts->len == len && !memcmp(ts->str, p1, len))
+                    goto token_found;
+                pts = &(ts->hash_next);
+            }
+            ts = tok_alloc_new(pts, p1, len);
+        token_found: ;
+        } else {
+            /* slower case */
+            cstr_reset(&tokcstr);
+
+            while (p1 < p) {
+                cstr_ccat(&tokcstr, *p1);
+                p1++;
+            }
+            p--;
+            PEEKC(c, p);
+        parse_ident_slow:
+            while (isidnum_table[c-CH_EOF]) {
+                cstr_ccat(&tokcstr, c);
+                PEEKC(c, p);
+            }
+            ts = tok_alloc(tokcstr.data, tokcstr.size);
+        }
+        tok = ts->tok;
+        break;
+    case 'L':
+        t = p[1];
+        if (t != '\\' && t != '\'' && t != '\"') {
+            /* fast case */
+            goto parse_ident_fast;
+        } else {
+            PEEKC(c, p);
+            if (c == '\'' || c == '\"') {
+                is_long = 1;
+                goto str_const;
+            } else {
+                cstr_reset(&tokcstr);
+                cstr_ccat(&tokcstr, 'L');
+                goto parse_ident_slow;
+            }
+        }
+        break;
+    case '0': case '1': case '2': case '3':
+    case '4': case '5': case '6': case '7':
+    case '8': case '9':
+
+        cstr_reset(&tokcstr);
+        /* after the first digit, accept digits, alpha, '.' or sign if
+           prefixed by 'eEpP' */
+    parse_num:
+        for(;;) {
+            t = c;
+            cstr_ccat(&tokcstr, c);
+            PEEKC(c, p);
+            if (!(isnum(c) || isid(c) || c == '.' ||
+                  ((c == '+' || c == '-') && 
+                   (t == 'e' || t == 'E' || t == 'p' || t == 'P'))))
+                break;
+        }
+        /* We add a trailing '\0' to ease parsing */
+        cstr_ccat(&tokcstr, '\0');
+        tokc.cstr = &tokcstr;
+        tok = TOK_PPNUM;
+        break;
+    case '.':
+        /* special dot handling because it can also start a number */
+        PEEKC(c, p);
+        if (isnum(c)) {
+            cstr_reset(&tokcstr);
+            cstr_ccat(&tokcstr, '.');
+            goto parse_num;
+        } else if (c == '.') {
+            PEEKC(c, p);
+            if (c != '.')
+                expect("'.'");
+            PEEKC(c, p);
+            tok = TOK_DOTS;
+        } else {
+            tok = '.';
+        }
+        break;
+    case '\'':
+    case '\"':
+        is_long = 0;
+    str_const:
+        {
+            CString str;
+            int sep;
+
+            sep = c;
+
+            /* parse the string */
+            cstr_new(&str);
+            p = parse_pp_string(p, sep, &str);
+            cstr_ccat(&str, '\0');
+            
+            /* eval the escape (should be done as TOK_PPNUM) */
+            cstr_reset(&tokcstr);
+            parse_escape_string(&tokcstr, str.data, is_long);
+            cstr_free(&str);
+
+            if (sep == '\'') {
+                int char_size;
+                /* XXX: make it portable */
+                if (!is_long)
+                    char_size = 1;
+                else
+                    char_size = sizeof(nwchar_t);
+                if (tokcstr.size <= char_size)
+                    error("empty character constant");
+                if (tokcstr.size > 2 * char_size)
+                    warning("multi-character character constant");
+                if (!is_long) {
+                    tokc.i = *(int8_t *)tokcstr.data;
+                    tok = TOK_CCHAR;
+                } else {
+                    tokc.i = *(nwchar_t *)tokcstr.data;
+                    tok = TOK_LCHAR;
+                }
+            } else {
+                tokc.cstr = &tokcstr;
+                if (!is_long)
+                    tok = TOK_STR;
+                else
+                    tok = TOK_LSTR;
+            }
+        }
+        break;
+
+    case '<':
+        PEEKC(c, p);
+        if (c == '=') {
+            p++;
+            tok = TOK_LE;
+        } else if (c == '<') {
+            PEEKC(c, p);
+            if (c == '=') {
+                p++;
+                tok = TOK_A_SHL;
+            } else {
+                tok = TOK_SHL;
+            }
+        } else {
+            tok = TOK_LT;
+        }
+        break;
+        
+    case '>':
+        PEEKC(c, p);
+        if (c == '=') {
+            p++;
+            tok = TOK_GE;
+        } else if (c == '>') {
+            PEEKC(c, p);
+            if (c == '=') {
+                p++;
+                tok = TOK_A_SAR;
+            } else {
+                tok = TOK_SAR;
+            }
+        } else {
+            tok = TOK_GT;
+        }
+        break;
+        
+    case '&':
+        PEEKC(c, p);
+        if (c == '&') {
+            p++;
+            tok = TOK_LAND;
+        } else if (c == '=') {
+            p++;
+            tok = TOK_A_AND;
+        } else {
+            tok = '&';
+        }
+        break;
+        
+    case '|':
+        PEEKC(c, p);
+        if (c == '|') {
+            p++;
+            tok = TOK_LOR;
+        } else if (c == '=') {
+            p++;
+            tok = TOK_A_OR;
+        } else {
+            tok = '|';
+        }
+        break;
+
+    case '+':
+        PEEKC(c, p);
+        if (c == '+') {
+            p++;
+            tok = TOK_INC;
+        } else if (c == '=') {
+            p++;
+            tok = TOK_A_ADD;
+        } else {
+            tok = '+';
+        }
+        break;
+        
+    case '-':
+        PEEKC(c, p);
+        if (c == '-') {
+            p++;
+            tok = TOK_DEC;
+        } else if (c == '=') {
+            p++;
+            tok = TOK_A_SUB;
+        } else if (c == '>') {
+            p++;
+            tok = TOK_ARROW;
+        } else {
+            tok = '-';
+        }
+        break;
+
+    PARSE2('!', '!', '=', TOK_NE)
+    PARSE2('=', '=', '=', TOK_EQ)
+    PARSE2('*', '*', '=', TOK_A_MUL)
+    PARSE2('%', '%', '=', TOK_A_MOD)
+    PARSE2('^', '^', '=', TOK_A_XOR)
+        
+        /* comments or operator */
+    case '/':
+        PEEKC(c, p);
+        if (c == '*') {
+            p = parse_comment(p);
+            goto redo_no_start;
+        } else if (c == '/') {
+            p = parse_line_comment(p);
+            goto redo_no_start;
+        } else if (c == '=') {
+            p++;
+            tok = TOK_A_DIV;
+        } else {
+            tok = '/';
+        }
+        break;
+        
+        /* simple tokens */
+    case '(':
+    case ')':
+    case '[':
+    case ']':
+    case '{':
+    case '}':
+    case ',':
+    case ';':
+    case ':':
+    case '?':
+    case '~':
+    case '$': /* only used in assembler */
+    case '@': /* dito */
+        tok = c;
+        p++;
+        break;
+    default:
+        error("unrecognized character \\x%02x", c);
+        break;
+    }
+    tok_flags = 0;
+keep_tok_flags:
+    file->buf_ptr = p;
+#if defined(PARSE_DEBUG)
+    printf("token = %s\n", get_tok_str(tok, &tokc));
+#endif
+}
+
+/* return next token without macro substitution. Can read input from
+   macro_ptr buffer */
+static void next_nomacro_spc(void)
+{
+    if (macro_ptr) {
+    redo:
+        tok = *macro_ptr;
+        if (tok) {
+            TOK_GET(tok, macro_ptr, tokc);
+            if (tok == TOK_LINENUM) {
+                file->line_num = tokc.i;
+                goto redo;
+            }
+        }
+    } else {
+        next_nomacro1();
+    }
+}
+
+static void next_nomacro(void)
+{
+    do {
+        next_nomacro_spc();
+    } while (is_space(tok));
+}
+ 
+/* substitute args in macro_str and return allocated string */
+static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
+{
+    int *st, last_tok, t, spc;
+    Sym *s;
+    CValue cval;
+    TokenString str;
+    CString cstr;
+
+    tok_str_new(&str);
+    last_tok = 0;
+    while(1) {
+        TOK_GET(t, macro_str, cval);
+        if (!t)
+            break;
+        if (t == '#') {
+            /* stringize */
+            TOK_GET(t, macro_str, cval);
+            if (!t)
+                break;
+            s = sym_find2(args, t);
+            if (s) {
+                cstr_new(&cstr);
+                st = (int *)s->c;
+                spc = 0;
+                while (*st) {
+                    TOK_GET(t, st, cval);
+                    if (!check_space(t, &spc))
+                        cstr_cat(&cstr, get_tok_str(t, &cval));
+                }
+                cstr.size -= spc;
+                cstr_ccat(&cstr, '\0');
+#ifdef PP_DEBUG
+                printf("stringize: %s\n", (char *)cstr.data);
+#endif
+                /* add string */
+                cval.cstr = &cstr;
+                tok_str_add2(&str, TOK_STR, &cval);
+                cstr_free(&cstr);
+            } else {
+                tok_str_add2(&str, t, &cval);
+            }
+        } else if (t >= TOK_IDENT) {
+            s = sym_find2(args, t);
+            if (s) {
+                st = (int *)s->c;
+                /* if '##' is present before or after, no arg substitution */
+                if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) {
+                    /* special case for var arg macros : ## eats the
+                       ',' if empty VA_ARGS variable. */
+                    /* XXX: test of the ',' is not 100%
+                       reliable. should fix it to avoid security
+                       problems */
+                    if (gnu_ext && s->type.t &&
+                        last_tok == TOK_TWOSHARPS && 
+                        str.len >= 2 && str.str[str.len - 2] == ',') {
+                        if (*st == 0) {
+                            /* suppress ',' '##' */
+                            str.len -= 2;
+                        } else {
+                            /* suppress '##' and add variable */
+                            str.len--;
+                            goto add_var;
+                        }
+                    } else {
+                        int t1;
+                    add_var:
+                        for(;;) {
+                            TOK_GET(t1, st, cval);
+                            if (!t1)
+                                break;
+                            tok_str_add2(&str, t1, &cval);
+                        }
+                    }
+                } else {
+                    /* NOTE: the stream cannot be read when macro
+                       substituing an argument */
+                    macro_subst(&str, nested_list, st, NULL);
+                }
+            } else {
+                tok_str_add(&str, t);
+            }
+        } else {
+            tok_str_add2(&str, t, &cval);
+        }
+        last_tok = t;
+    }
+    tok_str_add(&str, 0);
+    return str.str;
+}
+
+static char const ab_month_name[12][4] =
+{
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+/* do macro substitution of current token with macro 's' and add
+   result to (tok_str,tok_len). 'nested_list' is the list of all
+   macros we got inside to avoid recursing. Return non zero if no
+   substitution needs to be done */
+static int macro_subst_tok(TokenString *tok_str,
+                           Sym **nested_list, Sym *s, struct macro_level **can_read_stream)
+{
+    Sym *args, *sa, *sa1;
+    int mstr_allocated, parlevel, *mstr, t, t1, *p, spc;
+    TokenString str;
+    char *cstrval;
+    CValue cval;
+    CString cstr;
+    char buf[32];
+    
+    /* if symbol is a macro, prepare substitution */
+    /* special macros */
+    if (tok == TOK___LINE__) {
+        snprintf(buf, sizeof(buf), "%d", file->line_num);
+        cstrval = buf;
+        t1 = TOK_PPNUM;
+        goto add_cstr1;
+    } else if (tok == TOK___FILE__) {
+        cstrval = file->filename;
+        goto add_cstr;
+    } else if (tok == TOK___DATE__ || tok == TOK___TIME__) {
+        time_t ti;
+        struct tm *tm;
+
+        time(&ti);
+        tm = localtime(&ti);
+        if (tok == TOK___DATE__) {
+            snprintf(buf, sizeof(buf), "%s %2d %d", 
+                     ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900);
+        } else {
+            snprintf(buf, sizeof(buf), "%02d:%02d:%02d", 
+                     tm->tm_hour, tm->tm_min, tm->tm_sec);
+        }
+        cstrval = buf;
+    add_cstr:
+        t1 = TOK_STR;
+    add_cstr1:
+        cstr_new(&cstr);
+        cstr_cat(&cstr, cstrval);
+        cstr_ccat(&cstr, '\0');
+        cval.cstr = &cstr;
+        tok_str_add2(tok_str, t1, &cval);
+        cstr_free(&cstr);
+    } else {
+        mstr = (int *)s->c;
+        mstr_allocated = 0;
+        if (s->type.t == MACRO_FUNC) {
+            /* NOTE: we do not use next_nomacro to avoid eating the
+               next token. XXX: find better solution */
+        redo:
+            if (macro_ptr) {
+                p = macro_ptr;
+                while (is_space(t = *p) || TOK_LINEFEED == t) 
+                    ++p;
+                if (t == 0 && can_read_stream) {
+                    /* end of macro stream: we must look at the token
+                       after in the file */
+                    struct macro_level *ml = *can_read_stream;
+                    macro_ptr = NULL;
+                    if (ml)
+                    {
+                        macro_ptr = ml->p;
+                        ml->p = NULL;
+                        *can_read_stream = ml -> prev;
+                    }
+                    goto redo;
+                }
+            } else {
+                /* XXX: incorrect with comments */
+                ch = file->buf_ptr[0];
+                while (is_space(ch) || ch == '\n')
+                    cinp();
+                t = ch;
+            }
+            if (t != '(') /* no macro subst */
+                return -1;
+                    
+            /* argument macro */
+            next_nomacro();
+            next_nomacro();
+            args = NULL;
+            sa = s->next;
+            /* NOTE: empty args are allowed, except if no args */
+            for(;;) {
+                /* handle '()' case */
+                if (!args && !sa && tok == ')')
+                    break;
+                if (!sa)
+                    error("macro '%s' used with too many args",
+                          get_tok_str(s->v, 0));
+                tok_str_new(&str);
+                parlevel = spc = 0;
+                /* NOTE: non zero sa->t indicates VA_ARGS */
+                while ((parlevel > 0 || 
+                        (tok != ')' && 
+                         (tok != ',' || sa->type.t))) && 
+                       tok != -1) {
+                    if (tok == '(')
+                        parlevel++;
+                    else if (tok == ')')
+                        parlevel--;
+                    if (tok == TOK_LINEFEED)
+                        tok = ' ';
+                    if (!check_space(tok, &spc))
+                        tok_str_add2(&str, tok, &tokc);
+                    next_nomacro_spc();
+                }
+                str.len -= spc;
+                tok_str_add(&str, 0);
+                sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, (long)str.str);
+                sa = sa->next;
+                if (tok == ')') {
+                    /* special case for gcc var args: add an empty
+                       var arg argument if it is omitted */
+                    if (sa && sa->type.t && gnu_ext)
+                        continue;
+                    else
+                        break;
+                }
+                if (tok != ',')
+                    expect(",");
+                next_nomacro();
+            }
+            if (sa) {
+                error("macro '%s' used with too few args",
+                      get_tok_str(s->v, 0));
+            }
+
+            /* now subst each arg */
+            mstr = macro_arg_subst(nested_list, mstr, args);
+            /* free memory */
+            sa = args;
+            while (sa) {
+                sa1 = sa->prev;
+                tok_str_free((int *)sa->c);
+                sym_free(sa);
+                sa = sa1;
+            }
+            mstr_allocated = 1;
+        }
+        sym_push2(nested_list, s->v, 0, 0);
+        macro_subst(tok_str, nested_list, mstr, can_read_stream);
+        /* pop nested defined symbol */
+        sa1 = *nested_list;
+        *nested_list = sa1->prev;
+        sym_free(sa1);
+        if (mstr_allocated)
+            tok_str_free(mstr);
+    }
+    return 0;
+}
+
+/* handle the '##' operator. Return NULL if no '##' seen. Otherwise
+   return the resulting string (which must be freed). */
+static inline int *macro_twosharps(const int *macro_str)
+{
+    TokenSym *ts;
+    const int *ptr, *saved_macro_ptr;
+    int t;
+    const char *p1, *p2;
+    CValue cval;
+    TokenString macro_str1;
+    CString cstr;
+
+    /* we search the first '##' */
+    for(ptr = macro_str;;) {
+        TOK_GET(t, ptr, cval);
+        if (t == TOK_TWOSHARPS)
+            break;
+        /* nothing more to do if end of string */
+        if (t == 0)
+            return NULL;
+    }
+
+    /* we saw '##', so we need more processing to handle it */
+    cstr_new(&cstr);
+    tok_str_new(&macro_str1);
+    saved_macro_ptr = macro_ptr;
+    /* XXX: get rid of the use of macro_ptr here */
+    macro_ptr = (int *)macro_str;
+    for(;;) {
+        next_nomacro_spc();
+        if (tok == 0)
+            break;
+        if (tok == TOK_TWOSHARPS)
+            continue;
+        while (*macro_ptr == TOK_TWOSHARPS) {
+            t = *++macro_ptr;
+            if (t && t != TOK_TWOSHARPS) {
+                TOK_GET(t, macro_ptr, cval);
+                /* We concatenate the two tokens if we have an
+                   identifier or a preprocessing number */
+                cstr_reset(&cstr);
+                p1 = get_tok_str(tok, &tokc);
+                cstr_cat(&cstr, p1);
+                p2 = get_tok_str(t, &cval);
+                cstr_cat(&cstr, p2);
+                cstr_ccat(&cstr, '\0');
+
+                if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && 
+                    (t >= TOK_IDENT || t == TOK_PPNUM)) {
+                    if (tok == TOK_PPNUM) {
+                        /* if number, then create a number token */
+                        /* NOTE: no need to allocate because
+                           tok_str_add2() does it */
+                        cstr_reset(&tokcstr);
+                        tokcstr = cstr;
+                        cstr_new(&cstr);
+                        tokc.cstr = &tokcstr;
+                    } else {
+                        /* if identifier, we must do a test to
+                           validate we have a correct identifier */
+                        if (t == TOK_PPNUM) {
+                            const char *p;
+                            int c;
+
+                            p = p2;
+                            for(;;) {
+                                c = *p;
+                                if (c == '\0')
+                                    break;
+                                p++;
+                                if (!isnum(c) && !isid(c))
+                                    goto error_pasting;
+                            }
+                        }
+                        ts = tok_alloc(cstr.data, strlen(cstr.data));
+                        tok = ts->tok; /* modify current token */
+                    }
+                } else {
+                    const char *str = cstr.data;
+                    const unsigned char *q;
+
+                    /* we look for a valid token */
+                    /* XXX: do more extensive checks */
+                    if (!strcmp(str, ">>=")) {
+                        tok = TOK_A_SAR;
+                    } else if (!strcmp(str, "<<=")) {
+                        tok = TOK_A_SHL;
+                    } else if (strlen(str) == 2) {
+                        /* search in two bytes table */
+                        q = tok_two_chars;
+                        for(;;) {
+                            if (!*q)
+                                goto error_pasting;
+                            if (q[0] == str[0] && q[1] == str[1])
+                                break;
+                            q += 3;
+                        }
+                        tok = q[2];
+                    } else {
+                    error_pasting:
+                        /* NOTE: because get_tok_str use a static buffer,
+                           we must save it */
+                        cstr_reset(&cstr);
+                        p1 = get_tok_str(tok, &tokc);
+                        cstr_cat(&cstr, p1);
+                        cstr_ccat(&cstr, '\0');
+                        p2 = get_tok_str(t, &cval);
+                        warning("pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cstr.data, p2);
+                        /* cannot merge tokens: just add them separately */
+                        tok_str_add2(&macro_str1, tok, &tokc);
+                        /* XXX: free associated memory ? */
+                        tok = t;
+                        tokc = cval;
+                    }
+                }
+            }
+        }
+        tok_str_add2(&macro_str1, tok, &tokc);
+    }
+    macro_ptr = (int *)saved_macro_ptr;
+    cstr_free(&cstr);
+    tok_str_add(&macro_str1, 0);
+    return macro_str1.str;
+}
+
+
+/* do macro substitution of macro_str and add result to
+   (tok_str,tok_len). 'nested_list' is the list of all macros we got
+   inside to avoid recursing. */
+static void macro_subst(TokenString *tok_str, Sym **nested_list, 
+                        const int *macro_str, struct macro_level ** can_read_stream)
+{
+    Sym *s;
+    int *macro_str1;
+    const int *ptr;
+    int t, ret, spc;
+    CValue cval;
+    struct macro_level ml;
+    
+    /* first scan for '##' operator handling */
+    ptr = macro_str;
+    macro_str1 = macro_twosharps(ptr);
+    if (macro_str1) 
+        ptr = macro_str1;
+    spc = 0;
+    while (1) {
+        /* NOTE: ptr == NULL can only happen if tokens are read from
+           file stream due to a macro function call */
+        if (ptr == NULL)
+            break;
+        TOK_GET(t, ptr, cval);
+        if (t == 0)
+            break;
+        s = define_find(t);
+        if (s != NULL) {
+            /* if nested substitution, do nothing */
+            if (sym_find2(*nested_list, t))
+                goto no_subst;
+            ml.p = macro_ptr;
+            if (can_read_stream)
+                ml.prev = *can_read_stream, *can_read_stream = &ml;
+            macro_ptr = (int *)ptr;
+            tok = t;
+            ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream);
+            ptr = (int *)macro_ptr;
+            macro_ptr = ml.p;
+            if (can_read_stream && *can_read_stream == &ml)
+                *can_read_stream = ml.prev;
+            if (ret != 0)
+                goto no_subst;
+        } else {
+        no_subst:
+            if (!check_space(t, &spc)) 
+                tok_str_add2(tok_str, t, &cval);
+        }
+    }
+    if (macro_str1)
+        tok_str_free(macro_str1);
+}
+
+/* return next token with macro substitution */
+static void next(void)
+{
+    Sym *nested_list, *s;
+    TokenString str;
+    struct macro_level *ml;
+
+ redo:
+    if (parse_flags & PARSE_FLAG_SPACES)
+        next_nomacro_spc();
+    else
+        next_nomacro();
+    if (!macro_ptr) {
+        /* if not reading from macro substituted string, then try
+           to substitute macros */
+        if (tok >= TOK_IDENT &&
+            (parse_flags & PARSE_FLAG_PREPROCESS)) {
+            s = define_find(tok);
+            if (s) {
+                /* we have a macro: we try to substitute */
+                tok_str_new(&str);
+                nested_list = NULL;
+                ml = NULL;
+                if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) {
+                    /* substitution done, NOTE: maybe empty */
+                    tok_str_add(&str, 0);
+                    macro_ptr = str.str;
+                    macro_ptr_allocated = str.str;
+                    goto redo;
+                }
+            }
+        }
+    } else {
+        if (tok == 0) {
+            /* end of macro or end of unget buffer */
+            if (unget_buffer_enabled) {
+                macro_ptr = unget_saved_macro_ptr;
+                unget_buffer_enabled = 0;
+            } else {
+                /* end of macro string: free it */
+                tok_str_free(macro_ptr_allocated);
+                macro_ptr = NULL;
+            }
+            goto redo;
+        }
+    }
+    
+    /* convert preprocessor tokens into C tokens */
+    if (tok == TOK_PPNUM &&
+        (parse_flags & PARSE_FLAG_TOK_NUM)) {
+        parse_number((char *)tokc.cstr->data);
+    }
+}
+
+/* push back current token and set current token to 'last_tok'. Only
+   identifier case handled for labels. */
+static inline void unget_tok(int last_tok)
+{
+    int i, n;
+    int *q;
+    unget_saved_macro_ptr = macro_ptr;
+    unget_buffer_enabled = 1;
+    q = unget_saved_buffer;
+    macro_ptr = q;
+    *q++ = tok;
+    n = tok_ext_size(tok) - 1;
+    for(i=0;i<n;i++)
+        *q++ = tokc.tab[i];
+    *q = 0; /* end of token string */
+    tok = last_tok;
+}
+
+
+/* better than nothing, but needs extension to handle '-E' option
+   correctly too */
+static void preprocess_init(TCCState *s1)
+{
+    s1->include_stack_ptr = s1->include_stack;
+    /* XXX: move that before to avoid having to initialize
+       file->ifdef_stack_ptr ? */
+    s1->ifdef_stack_ptr = s1->ifdef_stack;
+    file->ifdef_stack_ptr = s1->ifdef_stack_ptr;
+
+    /* XXX: not ANSI compliant: bound checking says error */
+    vtop = vstack - 1;
+    s1->pack_stack[0] = 0;
+    s1->pack_stack_ptr = s1->pack_stack;
+}
+
+void preprocess_new()
+{
+    int i, c;
+    const char *p, *r;
+    TokenSym *ts;
+
+    /* init isid table */
+    for(i=CH_EOF;i<256;i++)
+        isidnum_table[i-CH_EOF] = isid(i) || isnum(i);
+
+    /* add all tokens */
+    table_ident = NULL;
+    memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
+    
+    tok_ident = TOK_IDENT;
+    p = tcc_keywords;
+    while (*p) {
+        r = p;
+        for(;;) {
+            c = *r++;
+            if (c == '\0')
+                break;
+        }
+        ts = tok_alloc(p, r - p - 1);
+        p = r;
+    }
+}
+
+/* Preprocess the current file */
+static int tcc_preprocess(TCCState *s1)
+{
+    Sym *define_start;
+    BufferedFile *file_ref;
+    int token_seen, line_ref;
+
+    preprocess_init(s1);
+    define_start = define_stack;
+    ch = file->buf_ptr[0];
+    tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
+    parse_flags = PARSE_FLAG_ASM_COMMENTS | PARSE_FLAG_PREPROCESS |
+        PARSE_FLAG_LINEFEED | PARSE_FLAG_SPACES;
+    token_seen = 0;
+    line_ref = 0;
+    file_ref = NULL;
+
+    for (;;) {
+        next();
+        if (tok == TOK_EOF) {
+            break;
+        } else if (tok == TOK_LINEFEED) {
+            if (!token_seen)
+                continue;
+            ++line_ref;
+            token_seen = 0;
+        } else if (!token_seen) {
+            int d = file->line_num - line_ref;
+            if (file != file_ref || d < 0 || d >= 8)
+                fprintf(s1->outfile, "# %d \"%s\"\n", file->line_num, file->filename);
+            else
+                while (d)
+                    fputs("\n", s1->outfile), --d;
+            line_ref = (file_ref = file)->line_num;
+            token_seen = 1;
+        }
+        fputs(get_tok_str(tok, &tokc), s1->outfile);
+    }
+    free_defines(define_start); 
+    return 0;
+}
+
diff --git a/tinyc/tcctok.h b/tinyc/tcctok.h
new file mode 100644
index 000000000..2be032fa4
--- /dev/null
+++ b/tinyc/tcctok.h
@@ -0,0 +1,469 @@
+/* keywords */
+     DEF(TOK_INT, "int")
+     DEF(TOK_VOID, "void")
+     DEF(TOK_CHAR, "char")
+     DEF(TOK_IF, "if")
+     DEF(TOK_ELSE, "else")
+     DEF(TOK_WHILE, "while")
+     DEF(TOK_BREAK, "break")
+     DEF(TOK_RETURN, "return")
+     DEF(TOK_FOR, "for")
+     DEF(TOK_EXTERN, "extern")
+     DEF(TOK_STATIC, "static")
+     DEF(TOK_UNSIGNED, "unsigned")
+     DEF(TOK_GOTO, "goto")
+     DEF(TOK_DO, "do")
+     DEF(TOK_CONTINUE, "continue")
+     DEF(TOK_SWITCH, "switch")
+     DEF(TOK_CASE, "case")
+
+     DEF(TOK_CONST1, "const")
+     DEF(TOK_CONST2, "__const") /* gcc keyword */
+     DEF(TOK_CONST3, "__const__") /* gcc keyword */
+     DEF(TOK_VOLATILE1, "volatile")
+     DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */
+     DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */
+     DEF(TOK_LONG, "long")
+     DEF(TOK_REGISTER, "register")
+     DEF(TOK_SIGNED1, "signed")
+     DEF(TOK_SIGNED2, "__signed") /* gcc keyword */
+     DEF(TOK_SIGNED3, "__signed__") /* gcc keyword */
+     DEF(TOK_AUTO, "auto")
+     DEF(TOK_INLINE1, "inline")
+     DEF(TOK_INLINE2, "__inline") /* gcc keyword */
+     DEF(TOK_INLINE3, "__inline__") /* gcc keyword */
+     DEF(TOK_RESTRICT1, "restrict")
+     DEF(TOK_RESTRICT2, "__restrict")
+     DEF(TOK_RESTRICT3, "__restrict__")
+     DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
+     
+     DEF(TOK_FLOAT, "float")
+     DEF(TOK_DOUBLE, "double")
+     DEF(TOK_BOOL, "_Bool")
+     DEF(TOK_SHORT, "short")
+     DEF(TOK_STRUCT, "struct")
+     DEF(TOK_UNION, "union")
+     DEF(TOK_TYPEDEF, "typedef")
+     DEF(TOK_DEFAULT, "default")
+     DEF(TOK_ENUM, "enum")
+     DEF(TOK_SIZEOF, "sizeof")
+     DEF(TOK_ATTRIBUTE1, "__attribute")
+     DEF(TOK_ATTRIBUTE2, "__attribute__")
+     DEF(TOK_ALIGNOF1, "__alignof")
+     DEF(TOK_ALIGNOF2, "__alignof__")
+     DEF(TOK_TYPEOF1, "typeof")
+     DEF(TOK_TYPEOF2, "__typeof")
+     DEF(TOK_TYPEOF3, "__typeof__")
+     DEF(TOK_LABEL, "__label__")
+     DEF(TOK_ASM1, "asm")
+     DEF(TOK_ASM2, "__asm")
+     DEF(TOK_ASM3, "__asm__")
+
+/*********************************************************************/
+/* the following are not keywords. They are included to ease parsing */
+/* preprocessor only */
+     DEF(TOK_DEFINE, "define")
+     DEF(TOK_INCLUDE, "include")
+     DEF(TOK_INCLUDE_NEXT, "include_next")
+     DEF(TOK_IFDEF, "ifdef")
+     DEF(TOK_IFNDEF, "ifndef")
+     DEF(TOK_ELIF, "elif")
+     DEF(TOK_ENDIF, "endif")
+     DEF(TOK_DEFINED, "defined")
+     DEF(TOK_UNDEF, "undef")
+     DEF(TOK_ERROR, "error")
+     DEF(TOK_WARNING, "warning")
+     DEF(TOK_LINE, "line")
+     DEF(TOK_PRAGMA, "pragma")
+     DEF(TOK___LINE__, "__LINE__")
+     DEF(TOK___FILE__, "__FILE__")
+     DEF(TOK___DATE__, "__DATE__")
+     DEF(TOK___TIME__, "__TIME__")
+     DEF(TOK___FUNCTION__, "__FUNCTION__")
+     DEF(TOK___VA_ARGS__, "__VA_ARGS__")
+     
+/* special identifiers */
+     DEF(TOK___FUNC__, "__func__")
+     
+/* attribute identifiers */
+/* XXX: handle all tokens generically since speed is not critical */
+     DEF(TOK_SECTION1, "section")
+     DEF(TOK_SECTION2, "__section__")
+     DEF(TOK_ALIGNED1, "aligned")
+     DEF(TOK_ALIGNED2, "__aligned__")
+     DEF(TOK_PACKED1, "packed")
+     DEF(TOK_PACKED2, "__packed__")
+     DEF(TOK_UNUSED1, "unused")
+     DEF(TOK_UNUSED2, "__unused__")
+     DEF(TOK_CDECL1, "cdecl")
+     DEF(TOK_CDECL2, "__cdecl")
+     DEF(TOK_CDECL3, "__cdecl__")
+     DEF(TOK_STDCALL1, "stdcall")
+     DEF(TOK_STDCALL2, "__stdcall")
+     DEF(TOK_STDCALL3, "__stdcall__")
+     DEF(TOK_FASTCALL1, "fastcall")
+     DEF(TOK_FASTCALL2, "__fastcall")
+     DEF(TOK_FASTCALL3, "__fastcall__")
+     DEF(TOK_DLLEXPORT, "dllexport")
+     DEF(TOK_NORETURN1, "noreturn")
+     DEF(TOK_NORETURN2, "__noreturn__")
+     DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
+     DEF(TOK_builtin_constant_p, "__builtin_constant_p")
+     DEF(TOK_builtin_frame_address, "__builtin_frame_address")
+#ifdef TCC_TARGET_X86_64
+     DEF(TOK_builtin_malloc, "__builtin_malloc")
+     DEF(TOK_builtin_free, "__builtin_free")
+     DEF(TOK_malloc, "malloc")
+     DEF(TOK_free, "free")
+#endif
+     DEF(TOK_REGPARM1, "regparm")
+     DEF(TOK_REGPARM2, "__regparm__")
+
+/* pragma */
+     DEF(TOK_pack, "pack")
+#if !defined(TCC_TARGET_I386)
+     /* already defined for assembler */
+     DEF(TOK_ASM_push, "push")
+     DEF(TOK_ASM_pop, "pop")
+#endif
+
+/* builtin functions or variables */
+#ifdef TCC_ARM_EABI
+     DEF(TOK_memcpy, "__aeabi_memcpy")
+     DEF(TOK_memcpy4, "__aeabi_memcpy4")
+     DEF(TOK_memcpy8, "__aeabi_memcpy8")
+     DEF(TOK_memset, "__aeabi_memset")
+     DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
+     DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
+#else
+     DEF(TOK_memcpy, "memcpy")
+     DEF(TOK_memset, "memset")
+     DEF(TOK___divdi3, "__divdi3")
+     DEF(TOK___moddi3, "__moddi3")
+     DEF(TOK___udivdi3, "__udivdi3")
+     DEF(TOK___umoddi3, "__umoddi3")
+#endif
+#if defined(TCC_TARGET_ARM)
+#ifdef TCC_ARM_EABI
+     DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
+     DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
+     DEF(TOK___divsi3, "__aeabi_idiv")
+     DEF(TOK___udivsi3, "__aeabi_uidiv")
+     DEF(TOK___floatdisf, "__aeabi_l2f")
+     DEF(TOK___floatdidf, "__aeabi_l2d")
+     DEF(TOK___fixsfdi, "__aeabi_f2lz")
+     DEF(TOK___fixdfdi, "__aeabi_d2lz")
+#else
+     DEF(TOK___modsi3, "__modsi3")
+     DEF(TOK___umodsi3, "__umodsi3")
+     DEF(TOK___divsi3, "__divsi3")
+     DEF(TOK___udivsi3, "__udivsi3")
+     DEF(TOK___floatdisf, "__floatdisf")
+     DEF(TOK___floatdidf, "__floatdidf")
+#ifndef TCC_ARM_VFP
+     DEF(TOK___floatdixf, "__floatdixf")
+     DEF(TOK___fixunssfsi, "__fixunssfsi")
+     DEF(TOK___fixunsdfsi, "__fixunsdfsi")
+     DEF(TOK___fixunsxfsi, "__fixunsxfsi")
+     DEF(TOK___fixxfdi, "__fixxfdi")
+#endif
+     DEF(TOK___fixsfdi, "__fixsfdi")
+     DEF(TOK___fixdfdi, "__fixdfdi")
+#endif
+#elif defined(TCC_TARGET_C67)
+     DEF(TOK__divi, "_divi")
+     DEF(TOK__divu, "_divu")
+     DEF(TOK__divf, "_divf")
+     DEF(TOK__divd, "_divd")
+     DEF(TOK__remi, "_remi")
+     DEF(TOK__remu, "_remu")
+#endif
+#ifdef TCC_TARGET_I386
+     DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
+     DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
+#endif
+#ifdef TCC_ARM_EABI
+     DEF(TOK___ashrdi3, "__aeabi_lasr")
+     DEF(TOK___lshrdi3, "__aeabi_llsr")
+     DEF(TOK___ashldi3, "__aeabi_llsl")
+     DEF(TOK___floatundisf, "__aeabi_ul2f")
+     DEF(TOK___floatundidf, "__aeabi_ul2d")
+     DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
+     DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
+#else
+     DEF(TOK___ashrdi3, "__ashrdi3")
+     DEF(TOK___lshrdi3, "__lshrdi3")
+     DEF(TOK___ashldi3, "__ashldi3")
+     DEF(TOK___floatundisf, "__floatundisf")
+     DEF(TOK___floatundidf, "__floatundidf")
+#ifndef TCC_ARM_VFP
+     DEF(TOK___floatundixf, "__floatundixf")
+     DEF(TOK___fixunsxfdi, "__fixunsxfdi")
+#endif
+     DEF(TOK___fixunssfdi, "__fixunssfdi")
+     DEF(TOK___fixunsdfdi, "__fixunsdfdi")
+#endif
+#ifdef TCC_TARGET_PE
+     DEF(TOK___chkstk, "__chkstk")
+#endif
+
+/* bound checking symbols */
+#ifdef CONFIG_TCC_BCHECK
+     DEF(TOK___bound_ptr_add, "__bound_ptr_add")
+     DEF(TOK___bound_ptr_indir1, "__bound_ptr_indir1")
+     DEF(TOK___bound_ptr_indir2, "__bound_ptr_indir2")
+     DEF(TOK___bound_ptr_indir4, "__bound_ptr_indir4")
+     DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
+     DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
+     DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
+     DEF(TOK___bound_local_new, "__bound_local_new")
+     DEF(TOK___bound_local_delete, "__bound_local_delete")
+#if 0
+     DEF(TOK_malloc, "malloc")
+     DEF(TOK_free, "free")
+     DEF(TOK_realloc, "realloc")
+     DEF(TOK_memalign, "memalign")
+     DEF(TOK_calloc, "calloc")
+#endif
+     DEF(TOK_memmove, "memmove")
+     DEF(TOK_strlen, "strlen")
+     DEF(TOK_strcpy, "strcpy")
+     DEF(TOK_alloca, "alloca")
+#endif
+
+/* Tiny Assembler */
+
+ DEF_ASM(byte)
+ DEF_ASM(align)
+ DEF_ASM(skip)
+ DEF_ASM(space)
+ DEF_ASM(string)
+ DEF_ASM(asciz)
+ DEF_ASM(ascii)
+ DEF_ASM(globl)
+ DEF_ASM(global)
+ DEF_ASM(text)
+ DEF_ASM(data)
+ DEF_ASM(bss)
+ DEF_ASM(previous)
+ DEF_ASM(fill)
+ DEF_ASM(org)
+ DEF_ASM(quad)
+
+#ifdef TCC_TARGET_I386
+
+/* WARNING: relative order of tokens is important. */
+ DEF_ASM(al)
+ DEF_ASM(cl)
+ DEF_ASM(dl)
+ DEF_ASM(bl)
+ DEF_ASM(ah)
+ DEF_ASM(ch)
+ DEF_ASM(dh)
+ DEF_ASM(bh)
+ DEF_ASM(ax)
+ DEF_ASM(cx)
+ DEF_ASM(dx)
+ DEF_ASM(bx)
+ DEF_ASM(sp)
+ DEF_ASM(bp)
+ DEF_ASM(si)
+ DEF_ASM(di)
+ DEF_ASM(eax)
+ DEF_ASM(ecx)
+ DEF_ASM(edx)
+ DEF_ASM(ebx)
+ DEF_ASM(esp)
+ DEF_ASM(ebp)
+ DEF_ASM(esi)
+ DEF_ASM(edi)
+ DEF_ASM(mm0)
+ DEF_ASM(mm1)
+ DEF_ASM(mm2)
+ DEF_ASM(mm3)
+ DEF_ASM(mm4)
+ DEF_ASM(mm5)
+ DEF_ASM(mm6)
+ DEF_ASM(mm7)
+ DEF_ASM(xmm0)
+ DEF_ASM(xmm1)
+ DEF_ASM(xmm2)
+ DEF_ASM(xmm3)
+ DEF_ASM(xmm4)
+ DEF_ASM(xmm5)
+ DEF_ASM(xmm6)
+ DEF_ASM(xmm7)
+ DEF_ASM(cr0)
+ DEF_ASM(cr1)
+ DEF_ASM(cr2)
+ DEF_ASM(cr3)
+ DEF_ASM(cr4)
+ DEF_ASM(cr5)
+ DEF_ASM(cr6)
+ DEF_ASM(cr7)
+ DEF_ASM(tr0)
+ DEF_ASM(tr1)
+ DEF_ASM(tr2)
+ DEF_ASM(tr3)
+ DEF_ASM(tr4)
+ DEF_ASM(tr5)
+ DEF_ASM(tr6)
+ DEF_ASM(tr7)
+ DEF_ASM(db0)
+ DEF_ASM(db1)
+ DEF_ASM(db2)
+ DEF_ASM(db3)
+ DEF_ASM(db4)
+ DEF_ASM(db5)
+ DEF_ASM(db6)
+ DEF_ASM(db7)
+ DEF_ASM(dr0)
+ DEF_ASM(dr1)
+ DEF_ASM(dr2)
+ DEF_ASM(dr3)
+ DEF_ASM(dr4)
+ DEF_ASM(dr5)
+ DEF_ASM(dr6)
+ DEF_ASM(dr7)
+ DEF_ASM(es)
+ DEF_ASM(cs)
+ DEF_ASM(ss)
+ DEF_ASM(ds)
+ DEF_ASM(fs)
+ DEF_ASM(gs)
+ DEF_ASM(st)
+
+ DEF_BWL(mov)
+
+ /* generic two operands */
+ DEF_BWL(add)
+ DEF_BWL(or)
+ DEF_BWL(adc)
+ DEF_BWL(sbb)
+ DEF_BWL(and)
+ DEF_BWL(sub)
+ DEF_BWL(xor)
+ DEF_BWL(cmp)
+
+ /* unary ops */
+ DEF_BWL(inc)
+ DEF_BWL(dec)
+ DEF_BWL(not)
+ DEF_BWL(neg)
+ DEF_BWL(mul)
+ DEF_BWL(imul)
+ DEF_BWL(div)
+ DEF_BWL(idiv)
+
+ DEF_BWL(xchg)
+ DEF_BWL(test)
+
+ /* shifts */
+ DEF_BWL(rol)
+ DEF_BWL(ror)
+ DEF_BWL(rcl)
+ DEF_BWL(rcr)
+ DEF_BWL(shl)
+ DEF_BWL(shr)
+ DEF_BWL(sar)
+
+ DEF_ASM(shldw)
+ DEF_ASM(shldl)
+ DEF_ASM(shld)
+ DEF_ASM(shrdw)
+ DEF_ASM(shrdl)
+ DEF_ASM(shrd)
+
+ DEF_ASM(pushw)
+ DEF_ASM(pushl)
+ DEF_ASM(push)
+ DEF_ASM(popw)
+ DEF_ASM(popl)
+ DEF_ASM(pop)
+ DEF_BWL(in)
+ DEF_BWL(out)
+
+ DEF_WL(movzb)
+
+ DEF_ASM(movzwl)
+ DEF_ASM(movsbw)
+ DEF_ASM(movsbl)
+ DEF_ASM(movswl)
+
+ DEF_WL(lea) 
+
+ DEF_ASM(les) 
+ DEF_ASM(lds) 
+ DEF_ASM(lss) 
+ DEF_ASM(lfs) 
+ DEF_ASM(lgs) 
+
+ DEF_ASM(call)
+ DEF_ASM(jmp)
+ DEF_ASM(lcall)
+ DEF_ASM(ljmp)
+ 
+ DEF_ASMTEST(j)
+
+ DEF_ASMTEST(set)
+ DEF_ASMTEST(cmov)
+
+ DEF_WL(bsf)
+ DEF_WL(bsr)
+ DEF_WL(bt)
+ DEF_WL(bts)
+ DEF_WL(btr)
+ DEF_WL(btc)
+
+ DEF_WL(lsl)
+
+ /* generic FP ops */
+ DEF_FP(add)
+ DEF_FP(mul)
+
+ DEF_ASM(fcom)
+ DEF_ASM(fcom_1) /* non existent op, just to have a regular table */
+ DEF_FP1(com)
+
+ DEF_FP(comp)
+ DEF_FP(sub)
+ DEF_FP(subr)
+ DEF_FP(div)
+ DEF_FP(divr)
+
+ DEF_BWL(xadd)
+ DEF_BWL(cmpxchg)
+
+ /* string ops */
+ DEF_BWL(cmps)
+ DEF_BWL(scmp)
+ DEF_BWL(ins)
+ DEF_BWL(outs)
+ DEF_BWL(lods)
+ DEF_BWL(slod)
+ DEF_BWL(movs)
+ DEF_BWL(smov)
+ DEF_BWL(scas)
+ DEF_BWL(ssca)
+ DEF_BWL(stos)
+ DEF_BWL(ssto)
+
+ /* generic asm ops */
+
+#define ALT(x)
+#define DEF_ASM_OP0(name, opcode) DEF_ASM(name)
+#define DEF_ASM_OP0L(name, opcode, group, instr_type)
+#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
+#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
+#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
+#include "i386-asm.h"
+
+#define ALT(x)
+#define DEF_ASM_OP0(name, opcode)
+#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name)
+#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name)
+#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name)
+#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name)
+#include "i386-asm.h"
+
+#endif
diff --git a/tinyc/tests/asmtest.S b/tinyc/tests/asmtest.S
new file mode 100644
index 000000000..358a8239f
--- /dev/null
+++ b/tinyc/tests/asmtest.S
@@ -0,0 +1,558 @@
+
+/* some directive tests */
+
+   .byte 0xff
+   .byte 1, 2, 3
+   .short 1, 2, 3
+   .word 1, 2, 3
+   .long 1, 2, 3
+   .int 1, 2, 3
+   .align 8
+   .byte 1
+   .align 16, 0x90
+   .skip 3
+   .skip 15, 0x90
+   .string "hello\0world"
+
+/* some label tests */
+
+        movl %eax, %ebx
+L1:
+        movl %eax, %ebx
+        mov 0x10000, %eax
+L2:
+        movl $L2 - L1, %ecx
+var1:
+        nop ; nop ; nop ; nop
+
+        mov var1, %eax
+
+/* instruction tests */
+movl %eax, %ebx
+mov 0x10000, %eax
+mov 0x10000, %ax
+mov 0x10000, %al
+mov %al, 0x10000
+                
+mov $1, %edx
+mov $1, %dx
+mov $1, %dl
+movb $2, 0x100(%ebx,%edx,2)
+movw $2, 0x100(%ebx,%edx,2)
+movl $2, 0x100(%ebx,%edx,2)
+movl %eax, 0x100(%ebx,%edx,2)
+movl 0x100(%ebx,%edx,2), %edx
+movw %ax, 0x100(%ebx,%edx,2)
+
+mov %eax, 0x12(,%edx,2)
+        
+mov %cr3, %edx
+mov %ecx, %cr3
+movl %cr3, %eax
+movl %tr3, %eax
+movl %db3, %ebx
+movl %dr6, %eax
+movl %fs, %ecx
+movl %ebx, %fs
+
+     movsbl 0x1000, %eax
+     movsbw 0x1000, %ax
+     movswl 0x1000, %eax
+
+     movzbl 0x1000, %eax
+     movzbw 0x1000, %ax
+     movzwl 0x1000, %eax
+            
+     movzb 0x1000, %eax
+     movzb 0x1000, %ax
+                
+        
+  pushl %eax
+  pushw %ax
+  push %eax
+  push %cs
+  push %gs
+  push $1
+  push $100
+                                                
+  popl %eax
+  popw %ax
+  pop %eax
+  pop %ds
+  pop %fs
+          
+  xchg %eax, %ecx
+  xchg %edx, %eax
+  xchg %bx, 0x10000
+  xchg 0x10000, %ebx
+  xchg 0x10000, %dl
+
+  in $100, %al               
+  in $100, %ax               
+  in $100, %eax
+  in %dx, %al
+  in %dx, %ax               
+  in %dx, %eax
+  inb %dx
+  inw %dx               
+  inl %dx
+
+  out %al, $100                       
+  out %ax, $100                       
+  out %eax, $100                       
+
+  /* NOTE: gas is bugged here, so size must be added */
+  outb %al, %dx                       
+  outw %ax, %dx                       
+  outl %eax, %dx                       
+
+  leal 0x1000(%ebx), %ecx
+  lea 0x1000(%ebx), %ecx
+
+  les 0x2000, %eax
+  lds 0x2000, %ebx
+  lfs 0x2000, %ecx
+  lgs 0x2000, %edx
+  lss 0x2000, %edx
+
+addl $0x123, %eax
+add $0x123, %ebx
+addl $0x123, 0x100
+addl $0x123, 0x100(%ebx)
+addl $0x123, 0x100(%ebx,%edx,2)
+addl $0x123, 0x100(%esp)
+addl $0x123, (%ebp)
+addl $0x123, (%esp)
+cmpl $0x123, (%esp)
+
+add %eax, (%ebx)
+add (%ebx), %eax
+                
+or %dx, (%ebx)
+or (%ebx), %si
+        
+add %cl, (%ebx)
+add (%ebx), %dl
+
+    inc %edx
+    incl 0x10000
+    incb 0x10000
+    dec %dx
+  
+  test $1, %al
+  test $1, %cl
+
+  testl $1, 0x1000
+  testb $1, 0x1000
+  testw $1, 0x1000
+  test %eax, %ebx
+  test %eax, 0x1000
+  test 0x1000, %edx
+
+    not %edx
+    notw 0x10000
+    notl 0x10000
+    notb 0x10000
+
+    neg %edx
+    negw 0x10000
+    negl 0x10000
+    negb 0x10000
+
+    imul %ecx
+    mul %edx
+    mulb %cl
+
+    imul %eax, %ecx
+    imul 0x1000, %cx
+    imul $10, %eax, %ecx
+    imul $10, %ax, %cx
+    imul $10, %eax
+    imul $0x1100000, %eax
+    imul $1, %eax
+    
+    idivw 0x1000
+    div %ecx
+    div %bl
+    div %ecx, %eax
+
+
+shl %edx
+shl $10, %edx
+shl %cl, %edx
+
+shld $1, %eax, %edx
+shld %cl, %eax, %edx
+shld %eax, %edx
+
+shrd $1, %eax, %edx
+shrd %cl, %eax, %edx
+shrd %eax, %edx
+
+L4:
+call 0x1000
+call L4
+call *%eax
+call *0x1000
+call func1
+
+lcall $0x100, $0x1000
+
+jmp 0x1000
+jmp *%eax
+jmp *0x1000
+
+ljmp $0x100, $0x1000
+
+ret
+
+ret $10
+
+lret
+
+lret $10
+
+enter $1234, $10
+
+L3:
+ jo 0x1000
+ jnp 0x1001
+ jne 0x1002
+ jg 0x1003
+
+ jo L3
+ jnp L3
+ jne L3
+ jg L3
+
+ loopne L3
+ loopnz L3
+ loope L3
+ loopz L3
+ loop L3
+ jecxz L3
+
+        
+ seto %al
+ setnp 0x1000
+ setl 0xaaaa
+ setg %dl
+
+ fadd
+ fadd %st(1), %st
+ fadd %st(3)
+
+ faddp %st(5)
+ faddp
+ faddp %st(1), %st
+
+ fadds 0x1000
+ fiadds 0x1002
+ faddl 0x1004
+ fiaddl 0x1006
+
+ fmul
+ fmul %st(1), %st
+ fmul %st(3)
+
+ fmulp %st(5)
+ fmulp
+ fmulp %st(1), %st
+
+ fmuls 0x1000
+ fimuls 0x1002
+ fmull 0x1004
+ fimull 0x1006
+
+ fsub
+ fsub %st(1), %st
+ fsub %st(3)
+
+ fsubp %st(5)
+ fsubp
+ fsubp %st(1), %st
+
+ fsubs 0x1000
+ fisubs 0x1002
+ fsubl 0x1004
+ fisubl 0x1006
+
+ fsubr
+ fsubr %st(1), %st
+ fsubr %st(3)
+
+ fsubrp %st(5)
+ fsubrp
+ fsubrp %st(1), %st
+
+ fsubrs 0x1000
+ fisubrs 0x1002
+ fsubrl 0x1004
+ fisubrl 0x1006
+
+ fdiv
+ fdiv %st(1), %st
+ fdiv %st(3)
+
+ fdivp %st(5)
+ fdivp
+ fdivp %st(1), %st
+
+ fdivs 0x1000
+ fidivs 0x1002
+ fdivl 0x1004
+ fidivl 0x1006
+
+ fcom %st(3)
+
+ fcoms 0x1000
+ ficoms 0x1002
+ fcoml 0x1004
+ ficoml 0x1006
+
+ fcomp %st(5)
+ fcomp
+ fcompp
+
+ fcomps 0x1000
+ ficomps 0x1002
+ fcompl 0x1004
+ ficompl 0x1006
+
+ fld %st(5)
+ fldl 0x1000
+ flds 0x1002
+ fildl 0x1004
+ fst %st(4)
+ fstp %st(6)
+ fstpt 0x1006
+ fbstp 0x1008
+
+ fxch
+ fxch %st(4)
+
+ fucom %st(6)
+ fucomp %st(3)
+ fucompp
+
+ finit
+ fninit
+ fldcw 0x1000
+ fnstcw 0x1002
+ fstcw 0x1002
+ fnstsw 0x1004
+ fnstsw %eax
+ fstsw 0x1004
+ fstsw %eax
+ fnclex
+ fclex
+ fnstenv 0x1000
+ fstenv 0x1000
+ fldenv 0x1000
+ fnsave 0x1002
+ fsave 0x1000
+ frstor 0x1000
+ ffree %st(7)
+ ffreep %st(6)
+ 
+    ftst
+    fxam
+    fld1
+    fldl2t
+    fldl2e
+    fldpi
+    fldlg2
+    fldln2
+    fldz
+
+    f2xm1
+    fyl2x
+    fptan
+    fpatan
+    fxtract
+    fprem1
+    fdecstp
+    fincstp
+    fprem
+    fyl2xp1
+    fsqrt
+    fsincos
+    frndint
+    fscale
+    fsin
+    fcos
+    fchs
+    fabs
+    fnop
+    fwait
+
+bswap %edx
+xadd %ecx, %edx
+xaddb %dl, 0x1000
+xaddw %ax, 0x1000
+xaddl %eax, 0x1000
+cmpxchg %ecx, %edx
+cmpxchgb %dl, 0x1000
+cmpxchgw %ax, 0x1000
+cmpxchgl %eax, 0x1000
+invlpg 0x1000
+cmpxchg8b 0x1002
+
+fcmovb %st(5), %st
+fcmove %st(5), %st
+fcmovbe %st(5), %st
+fcmovu %st(5), %st
+fcmovnb %st(5), %st
+fcmovne %st(5), %st
+fcmovnbe %st(5), %st
+fcmovnu %st(5), %st
+fcomi %st(5), %st
+fucomi %st(5), %st
+fcomip %st(5), %st
+fucomip %st(5), %st
+
+
+
+ cmovo 0x1000, %eax
+ cmovs 0x1000, %eax
+ cmovns %edx, %edi
+
+int $3
+int $0x10
+
+    pusha
+    popa
+    clc
+    cld
+    cli
+    clts
+    cmc
+    lahf
+    sahf
+    pushfl
+    popfl
+    pushf
+    popf
+    stc
+    std
+    sti
+    aaa
+    aas
+    daa
+    das
+    aad
+    aam
+    cbw
+    cwd
+    cwde
+    cdq
+    cbtw
+    cwtd
+    cwtl
+    cltd
+    leave
+    int3
+    into
+    iret
+    rsm
+    hlt
+    wait
+    nop
+
+    /* XXX: handle prefixes */
+#if 0
+    aword
+    addr16
+#endif
+    lock
+    rep
+    repe
+    repz
+    repne
+    repnz
+    
+    invd
+    wbinvd
+    cpuid
+    wrmsr
+    rdtsc
+    rdmsr
+    rdpmc
+    ud2
+
+    emms
+    movd %edx, %mm3
+    movd 0x1000, %mm2
+    movd %mm4, %ecx
+    movd %mm5, 0x1000
+                    
+    movq 0x1000, %mm2
+    movq %mm4, 0x1000
+    
+    pand 0x1000, %mm3
+    pand %mm4, %mm5
+    
+    psllw $1, %mm6
+    psllw 0x1000, %mm7
+    psllw %mm2, %mm7
+
+    xlat
+    cmpsb
+    scmpw
+    insl
+    outsw
+    lodsb
+    slodl
+    movsb
+    movsl
+    smovb
+    scasb
+    sscaw
+    stosw
+    sstol
+
+    bsf 0x1000, %ebx
+    bsr 0x1000, %ebx
+    bt %edx, 0x1000
+    btl $2, 0x1000
+    btc %edx, 0x1000
+    btcl $2, 0x1000
+    btr %edx, 0x1000
+    btrl $2, 0x1000
+    bts %edx, 0x1000
+    btsl $2, 0x1000
+
+        
+        
+    boundl %edx, 0x10000
+    boundw %bx, 0x1000
+    
+    arpl %bx, 0x1000
+    lar 0x1000, %eax
+    lgdt 0x1000
+    lidt 0x1000
+    lldt 0x1000
+    lmsw 0x1000
+    lsl 0x1000, %ecx
+    ltr 0x1000
+    
+    sgdt 0x1000
+    sidt 0x1000
+    sldt 0x1000
+    smsw 0x1000
+    str 0x1000
+    
+    verr 0x1000
+    verw 0x1000
+  
+    push %ds
+    pushw %ds
+    pushl %ds
+    pop %ds
+    popw %ds
+    popl %ds
+    fxsave 1(%ebx)
+    fxrstor 1(%ecx)
+    pushl $1
+    pushw $1
+    push $1
diff --git a/tinyc/tests/boundtest.c b/tinyc/tests/boundtest.c
new file mode 100644
index 000000000..9bc982803
--- /dev/null
+++ b/tinyc/tests/boundtest.c
@@ -0,0 +1,214 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NB_ITS 1000000
+//#define NB_ITS 1
+#define TAB_SIZE 100
+
+int tab[TAB_SIZE];
+int ret_sum;
+char tab3[256];
+
+int test1(void)
+{
+    int i, sum = 0;
+    for(i=0;i<TAB_SIZE;i++) {
+        sum += tab[i];
+    }
+    return sum;
+}
+
+/* error */
+int test2(void)
+{
+    int i, sum = 0;
+    for(i=0;i<TAB_SIZE + 1;i++) {
+        sum += tab[i];
+    }
+    return sum;
+}
+
+/* actually, profiling test */
+int test3(void)
+{
+    int sum;
+    int i, it;
+
+    sum = 0;
+    for(it=0;it<NB_ITS;it++) {
+        for(i=0;i<TAB_SIZE;i++) {
+            sum += tab[i];
+        }
+    }
+    return sum;
+}
+
+/* ok */
+int test4(void)
+{
+    int i, sum = 0;
+    int *tab4;
+
+    tab4 = malloc(20 * sizeof(int));
+    for(i=0;i<20;i++) {
+        sum += tab4[i];
+    }
+    free(tab4);
+
+    return sum;
+}
+
+/* error */
+int test5(void)
+{
+    int i, sum = 0;
+    int *tab4;
+
+    tab4 = malloc(20 * sizeof(int));
+    for(i=0;i<21;i++) {
+        sum += tab4[i];
+    }
+    free(tab4);
+
+    return sum;
+}
+
+/* error */
+/* XXX: currently: bug */
+int test6(void)
+{
+    int i, sum = 0;
+    int *tab4;
+    
+    tab4 = malloc(20 * sizeof(int));
+    free(tab4);
+    for(i=0;i<21;i++) {
+        sum += tab4[i];
+    }
+
+    return sum;
+}
+
+/* error */
+int test7(void)
+{
+    int i, sum = 0;
+    int *p;
+
+    for(i=0;i<TAB_SIZE + 1;i++) {
+        p = &tab[i];
+        if (i == TAB_SIZE)
+            printf("i=%d %x\n", i, p);
+        sum += *p;
+    }
+    return sum;
+}
+
+/* ok */
+int test8(void)
+{
+    int i, sum = 0;
+    int tab[10];
+
+    for(i=0;i<10;i++) {
+        sum += tab[i];
+    }
+    return sum;
+}
+
+/* error */
+int test9(void)
+{
+    int i, sum = 0;
+    char tab[10];
+
+    for(i=0;i<11;i++) {
+        sum += tab[i];
+    }
+    return sum;
+}
+
+/* ok */
+int test10(void)
+{
+    char tab[10];
+    char tab1[10];
+
+    memset(tab, 0, 10);
+    memcpy(tab, tab1, 10);
+    memmove(tab, tab1, 10);
+    return 0;
+}
+
+/* error */
+int test11(void)
+{
+    char tab[10];
+
+    memset(tab, 0, 11);
+    return 0;
+}
+
+/* error */
+int test12(void)
+{
+    void *ptr;
+    ptr = malloc(10);
+    free(ptr);
+    free(ptr);
+    return 0;
+}
+
+/* error */
+int test13(void)
+{
+    char pad1 = 0;
+    char tab[10];
+    char pad2 = 0;
+    memset(tab, 'a', sizeof(tab));
+    return strlen(tab);
+}
+
+int (*table_test[])(void) = {
+    test1,
+    test1,
+    test2,
+    test3,
+    test4,
+    test5,
+    test6,
+    test7,
+    test8,
+    test9,
+    test10,
+    test11,
+    test12,
+    test13,
+};
+
+int main(int argc, char **argv)
+{
+    int index;
+    int (*ftest)(void);
+
+    if (argc < 2) {
+        printf("usage: boundtest n\n"
+               "test TCC bound checking system\n"
+               );
+        exit(1);
+    }
+
+    index = 0;
+    if (argc >= 2)
+        index = atoi(argv[1]);
+    /* well, we also use bounds on this ! */
+    ftest = table_test[index];
+    ftest();
+
+    return 0;
+}
+
+/*
+ * without bound   0.77 s
+ * with bounds    4.73
+ */  
diff --git a/tinyc/tests/gcctestsuite.sh b/tinyc/tests/gcctestsuite.sh
new file mode 100644
index 000000000..bd9204b2b
--- /dev/null
+++ b/tinyc/tests/gcctestsuite.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
+TCC="./tcc -B. -I. -DNO_TRAMPOLINES" 
+rm -f tcc.sum tcc.log
+nb_failed="0"
+
+for src in $TESTSUITE_PATH/compile/*.c ; do
+  echo $TCC -o /tmp/test.o -c $src 
+  $TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
+  if [ "$?" == "0" ] ; then
+     result="PASS"
+  else
+     result="FAIL"
+     nb_failed=$[ $nb_failed + 1 ]
+  fi
+  echo "$result: $src"  >> tcc.sum
+done
+
+for src in $TESTSUITE_PATH/execute/*.c ; do
+  echo $TCC $src 
+  $TCC $src >> tcc.log 2>&1
+  if [ "$?" == "0" ] ; then
+     result="PASS"
+  else
+     result="FAIL"
+     nb_failed=$[ $nb_failed + 1 ]
+  fi
+  echo "$result: $src"  >> tcc.sum
+done
+
+echo "$nb_failed test(s) failed." >> tcc.sum
+echo "$nb_failed test(s) failed."
diff --git a/tinyc/tests/libtcc_test.c b/tinyc/tests/libtcc_test.c
new file mode 100644
index 000000000..a602fb0f4
--- /dev/null
+++ b/tinyc/tests/libtcc_test.c
@@ -0,0 +1,84 @@
+/*
+ * Simple Test program for libtcc
+ *
+ * libtcc can be useful to use tcc as a "backend" for a code generator.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libtcc.h"
+
+/* this function is called by the generated code */
+int add(int a, int b)
+{
+    return a + b;
+}
+
+char my_program[] =
+"int fib(int n)\n"
+"{\n"
+"    if (n <= 2)\n"
+"        return 1;\n"
+"    else\n"
+"        return fib(n-1) + fib(n-2);\n"
+"}\n"
+"\n"
+"int foo(int n)\n"
+"{\n"
+"    printf(\"Hello World!\\n\");\n"
+"    printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
+"    printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
+"    return 0;\n"
+"}\n";
+
+int main(int argc, char **argv)
+{
+    TCCState *s;
+    int (*func)(int);
+    void *mem;
+    int size;
+
+    s = tcc_new();
+    if (!s) {
+        fprintf(stderr, "Could not create tcc state\n");
+        exit(1);
+    }
+
+    /* if tcclib.h and libtcc1.a are not installed, where can we find them */
+    if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
+        tcc_set_lib_path(s, argv[1]+9);
+
+    /* MUST BE CALLED before any compilation */
+    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+
+    if (tcc_compile_string(s, my_program) == -1)
+        return 1;
+
+    /* as a test, we add a symbol that the compiled program can use.
+       You may also open a dll with tcc_add_dll() and use symbols from that */
+    tcc_add_symbol(s, "add", add);
+
+    /* get needed size of the code */
+    size = tcc_relocate(s, NULL);
+    if (size == -1)
+        return 1;
+
+    /* allocate memory and copy the code into it */
+    mem = malloc(size);
+    tcc_relocate(s, mem);
+
+    /* get entry symbol */
+    func = tcc_get_symbol(s, "foo");
+    if (!func)
+        return 1;
+
+    /* delete the state */
+    tcc_delete(s);
+
+    /* run the code */
+    func(32);
+
+    free(mem);
+    return 0;
+}
diff --git a/tinyc/tests/tcctest.c b/tinyc/tests/tcctest.c
new file mode 100644
index 000000000..a2d481a6a
--- /dev/null
+++ b/tinyc/tests/tcctest.c
@@ -0,0 +1,2202 @@
+/*
+ * TCC auto test program
+ */
+#include "../config.h"
+
+#if GCC_MAJOR >= 3
+
+/* Unfortunately, gcc version < 3 does not handle that! */
+#define ALL_ISOC99
+
+/* only gcc 3 handles _Bool correctly */
+#define BOOL_ISOC99
+
+/* gcc 2.95.3 does not handle correctly CR in strings or after strays */
+#define CORRECT_CR_HANDLING
+
+#endif
+
+/* deprecated and no longer supported in gcc 3.3 */
+//#define ACCEPT_CR_IN_STRINGS
+
+/* __VA_ARGS__ and __func__ support */
+#define C99_MACROS
+
+/* test various include syntaxes */
+
+#define TCCLIB_INC <tcclib.h>
+#define TCCLIB_INC1 <tcclib
+#define TCCLIB_INC2 h>
+#define TCCLIB_INC3 "tcclib"
+
+#include TCCLIB_INC
+
+#include TCCLIB_INC1.TCCLIB_INC2
+
+#include TCCLIB_INC1.h>
+
+/* gcc 3.2 does not accept that (bug ?) */
+//#include TCCLIB_INC3 ".h"
+
+#include <tcclib.h>
+
+#include "tcclib.h"
+
+void string_test();
+void expr_test();
+void macro_test();
+void scope_test();
+void forward_test();
+void funcptr_test();
+void loop_test();
+void switch_test();
+void goto_test();
+void enum_test();
+void typedef_test();
+void struct_test();
+void array_test();
+void expr_ptr_test();
+void bool_test();
+void expr2_test();
+void constant_expr_test();
+void expr_cmp_test();
+void char_short_test();
+void init_test(void);
+void compound_literal_test(void);
+int kr_test();
+void struct_assign_test(void);
+void cast_test(void);
+void bitfield_test(void);
+void c99_bool_test(void);
+void float_test(void);
+void longlong_test(void);
+void manyarg_test(void);
+void stdarg_test(void);
+void whitespace_test(void);
+void relocation_test(void);
+void old_style_function(void);
+void alloca_test(void);
+void sizeof_test(void);
+void typeof_test(void);
+void local_label_test(void);
+void statement_expr_test(void);
+void asm_test(void);
+void builtin_test(void);
+
+int fib(int n);
+void num(int n);
+void forward_ref(void);
+int isid(int c);
+
+#define A 2
+#define N 1234 + A
+#define pf printf
+#define M1(a, b)  (a) + (b)
+
+#define str\
+(s) # s
+#define glue(a, b) a ## b
+#define xglue(a, b) glue(a, b)
+#define HIGHLOW "hello"
+#define LOW LOW ", world"
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+#ifdef C99_MACROS
+#define dprintf(level,...) printf(__VA_ARGS__)
+#endif
+
+/* gcc vararg macros */
+#define dprintf1(level, fmt, args...) printf(fmt, ## args)
+
+#define MACRO_NOARGS()
+
+#define AAA 3
+#undef AAA
+#define AAA 4
+
+#if 1
+#define B3 1
+#elif 1
+#define B3 2
+#elif 0
+#define B3 3
+#else
+#define B3 4
+#endif
+
+#define __INT64_C(c)	c ## LL
+#define INT64_MIN	(-__INT64_C(9223372036854775807)-1)
+
+int qq(int x)
+{
+    return x + 40;
+}
+#define qq(x) x
+
+#define spin_lock(lock) do { } while (0)
+#define wq_spin_lock spin_lock
+#define TEST2() wq_spin_lock(a)
+
+void macro_test(void)
+{
+    printf("macro:\n");

+    pf("N=%d\n", N);
+    printf("aaa=%d\n", AAA);
+
+    printf("min=%d\n", min(1, min(2, -1)));
+
+    printf("s1=%s\n", glue(HIGH, LOW));
+    printf("s2=%s\n", xglue(HIGH, LOW));
+    printf("s3=%s\n", str("c"));
+    printf("s4=%s\n", str(a1));
+    printf("B3=%d\n", B3);
+
+#ifdef A
+    printf("A defined\n");
+#endif
+#ifdef B
+    printf("B defined\n");
+#endif
+#ifdef A
+    printf("A defined\n");
+#else
+    printf("A not defined\n");
+#endif
+#ifdef B
+    printf("B defined\n");
+#else
+    printf("B not defined\n");
+#endif
+
+#ifdef A
+    printf("A defined\n");
+#ifdef B
+    printf("B1 defined\n");
+#else
+    printf("B1 not defined\n");
+#endif
+#else
+    printf("A not defined\n");
+#ifdef B
+    printf("B2 defined\n");
+#else
+    printf("B2 not defined\n");
+#endif
+#endif
+
+#if 1+1
+    printf("test true1\n");
+#endif
+#if 0
+    printf("test true2\n");
+#endif
+#if 1-1
+    printf("test true3\n");
+#endif
+#if defined(A)
+    printf("test trueA\n");
+#endif
+#if defined(B)
+    printf("test trueB\n");
+#endif
+
+#if 0
+    printf("test 0\n");
+#elif 0
+    printf("test 1\n");
+#elif 2
+    printf("test 2\n");
+#else
+    printf("test 3\n");
+#endif
+
+    MACRO_NOARGS();
+
+#ifdef __LINE__
+    printf("__LINE__ defined\n");
+#endif
+
+    printf("__LINE__=%d __FILE__=%s\n",
+           __LINE__, __FILE__);
+#line 200
+    printf("__LINE__=%d __FILE__=%s\n",
+           __LINE__, __FILE__);
+#line 203 "test" 
+    printf("__LINE__=%d __FILE__=%s\n",
+           __LINE__, __FILE__);
+#line 227 "tcctest.c"
+
+    /* not strictly preprocessor, but we test it there */
+#ifdef C99_MACROS
+    printf("__func__ = %s\n", __func__);
+    dprintf(1, "vaarg=%d\n", 1);
+#endif
+    dprintf1(1, "vaarg1\n");
+    dprintf1(1, "vaarg1=%d\n", 2);
+    dprintf1(1, "vaarg1=%d %d\n", 1, 2);
+
+    /* gcc extension */
+    printf("func='%s'\n", __FUNCTION__);
+
+    /* complicated macros in glibc */
+    printf("INT64_MIN=%Ld\n", INT64_MIN);
+    {
+        int a;
+        a = 1;
+        glue(a+, +);
+        printf("a=%d\n", a);
+        glue(a <, <= 2);
+        printf("a=%d\n", a);
+    }
+    
+    /* macro function with argument outside the macro string */
+#define MF_s MF_hello
+#define MF_hello(msg) printf("%s\n",msg)
+
+#define MF_t printf("tralala\n"); MF_hello
+
+    MF_s("hi");
+    MF_t("hi");
+    
+    /* test macro substituion inside args (should not eat stream) */
+    printf("qq=%d\n", qq(qq)(2));
+
+    /* test zero argument case. NOTE: gcc 2.95.x does not accept a
+       null argument without a space. gcc 3.2 fixes that. */
+
+#define qq1(x) 1
+    printf("qq1=%d\n", qq1( ));
+
+    /* comment with stray handling *\
+/
+       /* this is a valid *\/ comment */
+       /* this is a valid comment *\*/
+    //  this is a valid\
+comment
+
+    /* test function macro substitution when the function name is
+       substituted */
+    TEST2();
+}
+
+int op(a,b)
+{
+    return a / b;
+}
+
+int ret(a)
+{
+    if (a == 2)
+        return 1;
+    if (a == 3)
+        return 2;
+    return 0;
+}
+
+void ps(const char *s)
+{
+    int c;
+    while (1) {
+        c = *s;
+        if (c == 0)
+            break;
+        printf("%c", c);
+        s++;
+    }
+}
+
+const char foo1_string[] = "\
+bar\n\
+test\14\
+1";
+
+void string_test()
+{
+    unsigned int b;
+    printf("string:\n");
+    printf("\141\1423\143\n");/* dezdez test */
+    printf("\x41\x42\x43\x3a\n");
+    printf("c=%c\n", 'r');
+    printf("wc=%C 0x%lx %C\n", L'a', L'\x1234', L'c');
+    printf("foo1_string='%s'\n", foo1_string);
+#if 0
+    printf("wstring=%S\n", L"abc");
+    printf("wstring=%S\n", L"abc" L"def" "ghi");
+    printf("'\\377'=%d '\\xff'=%d\n", '\377', '\xff');
+    printf("L'\\377'=%d L'\\xff'=%d\n", L'\377', L'\xff');
+#endif
+    ps("test\n");
+    b = 32;
+    while ((b = b + 1) < 96) {
+        printf("%c", b);
+    }
+    printf("\n");
+    printf("fib=%d\n", fib(33));
+    b = 262144;
+    while (b != 0x80000000) {
+        num(b);
+        b = b * 2;
+    }
+}
+
+void loop_test()
+{
+    int i;
+    i = 0;
+    while (i < 10)
+        printf("%d", i++);
+    printf("\n");
+    for(i = 0; i < 10;i++)
+        printf("%d", i);
+    printf("\n");
+    i = 0;
+    do {
+        printf("%d", i++);
+    } while (i < 10);
+    printf("\n");
+
+    /* break/continue tests */
+    i = 0;
+    while (1) {
+        if (i == 6)
+            break;
+        i++;
+        if (i == 3)
+            continue;
+        printf("%d", i);
+    }
+    printf("\n");
+
+    /* break/continue tests */
+    i = 0;
+    do {
+        if (i == 6)
+            break;
+        i++;
+        if (i == 3)
+            continue;
+        printf("%d", i);
+    } while(1);
+    printf("\n");
+
+    for(i = 0;i < 10;i++) {
+        if (i == 3)
+            continue;
+        printf("%d", i);
+    }
+    printf("\n");
+}
+
+
+void goto_test()
+{
+    int i;
+    static void *label_table[3] = { &&label1, &&label2, &&label3 };
+
+    printf("goto:\n");
+    i = 0;
+ s_loop:
+    if (i >= 10) 
+        goto s_end;
+    printf("%d", i);
+    i++;
+    goto s_loop;
+ s_end:
+    printf("\n");
+
+    /* we also test computed gotos (GCC extension) */
+    for(i=0;i<3;i++) {
+        goto *label_table[i];
+    label1:
+        printf("label1\n");
+        goto next;
+    label2:
+        printf("label2\n");
+        goto next;
+    label3:
+        printf("label3\n");
+    next: ;
+    }
+}
+
+enum {
+    E0,
+    E1 = 2,
+    E2 = 4,
+    E3,
+    E4,
+};
+
+enum test {
+    E5 = 1000,
+};
+
+void enum_test()
+{
+    enum test b1;
+    printf("enum:\n%d %d %d %d %d %d\n",
+           E0, E1, E2, E3, E4, E5);
+    b1 = 1;
+    printf("b1=%d\n", b1);
+}
+
+typedef int *my_ptr;
+
+typedef int mytype1;
+typedef int mytype2;
+
+void typedef_test()
+{
+    my_ptr a;
+    mytype1 mytype2;
+    int b;
+
+    a = &b;
+    *a = 1234;
+    printf("typedef:\n");
+    printf("a=%d\n", *a);
+    mytype2 = 2;
+    printf("mytype2=%d\n", mytype2);
+}
+
+void forward_test()
+{
+    printf("forward:\n");
+    forward_ref();
+    forward_ref();
+}
+
+
+void forward_ref(void)
+{
+    printf("forward ok\n");
+}
+
+typedef struct struct1 {
+    int f1;
+    int f2, f3;
+    union union1 {
+        int v1;
+        int v2;
+    } u;
+    char str[3];
+} struct1;
+
+struct struct2 {
+    int a;
+    char b;
+};
+
+union union2 {
+    int w1;
+    int w2;
+};
+
+struct struct1 st1, st2;
+
+int main(int argc, char **argv)
+{
+    string_test();
+    expr_test();
+    macro_test();
+    scope_test();
+    forward_test();
+    funcptr_test();
+    loop_test();
+    switch_test();
+    goto_test();
+    enum_test();
+    typedef_test();
+    struct_test();
+    array_test();
+    expr_ptr_test();
+    bool_test();
+    expr2_test();
+    constant_expr_test();
+    expr_cmp_test();
+    char_short_test();
+    init_test();
+    compound_literal_test();
+    kr_test();
+    struct_assign_test();
+    cast_test();
+    bitfield_test();
+    c99_bool_test();
+    float_test();
+    longlong_test();
+    manyarg_test();
+    stdarg_test();
+    whitespace_test();
+    relocation_test();
+    old_style_function();
+    alloca_test();
+    sizeof_test();
+    typeof_test();
+    statement_expr_test();
+    local_label_test();
+    asm_test();
+    builtin_test();
+    return 0; 
+}
+
+int tab[3];
+int tab2[3][2];
+
+int g;
+
+void f1(g)
+{
+    printf("g1=%d\n", g);
+}
+
+void scope_test()
+{
+    printf("scope:\n");
+    g = 2;
+    f1(1);
+    printf("g2=%d\n", g);
+    {
+        int g;
+        g = 3;
+        printf("g3=%d\n", g);
+        {
+            int g;
+            g = 4;
+            printf("g4=%d\n", g);
+        }
+    }
+    printf("g5=%d\n", g);
+}
+
+void array_test(int a[4])
+{
+    int i, j;
+
+    printf("array:\n");
+    printf("sizeof(a) = %d\n", sizeof(a));
+    printf("sizeof(\"a\") = %d\n", sizeof("a"));
+#ifdef C99_MACROS
+    printf("sizeof(__func__) = %d\n", sizeof(__func__));
+#endif
+    printf("sizeof tab %d\n", sizeof(tab));
+    printf("sizeof tab2 %d\n", sizeof tab2);
+    tab[0] = 1;
+    tab[1] = 2;
+    tab[2] = 3;
+    printf("%d %d %d\n", tab[0], tab[1], tab[2]);
+    for(i=0;i<3;i++)
+        for(j=0;j<2;j++)
+            tab2[i][j] = 10 * i + j;
+    for(i=0;i<3*2;i++) {
+        printf(" %3d", ((int *)tab2)[i]);
+    }
+    printf("\n");
+}
+
+void expr_test()
+{
+    int a, b;
+    a = 0;
+    printf("%d\n", a += 1);
+    printf("%d\n", a -= 2);
+    printf("%d\n", a *= 31232132);
+    printf("%d\n", a /= 4);
+    printf("%d\n", a %= 20);
+    printf("%d\n", a &= 6);
+    printf("%d\n", a ^= 7);
+    printf("%d\n", a |= 8);
+    printf("%d\n", a >>= 3);
+    printf("%d\n", a <<= 4);
+
+    a = 22321;
+    b = -22321;
+    printf("%d\n", a + 1);
+    printf("%d\n", a - 2);
+    printf("%d\n", a * 312);
+    printf("%d\n", a / 4);
+    printf("%d\n", b / 4);
+    printf("%d\n", (unsigned)b / 4);
+    printf("%d\n", a % 20);
+    printf("%d\n", b % 20);
+    printf("%d\n", (unsigned)b % 20);
+    printf("%d\n", a & 6);
+    printf("%d\n", a ^ 7);
+    printf("%d\n", a | 8);
+    printf("%d\n", a >> 3);
+    printf("%d\n", b >> 3);
+    printf("%d\n", (unsigned)b >> 3);
+    printf("%d\n", a << 4);
+    printf("%d\n", ~a);
+    printf("%d\n", -a);
+    printf("%d\n", +a);
+
+    printf("%d\n", 12 + 1);
+    printf("%d\n", 12 - 2);
+    printf("%d\n", 12 * 312);
+    printf("%d\n", 12 / 4);
+    printf("%d\n", 12 % 20);
+    printf("%d\n", 12 & 6);
+    printf("%d\n", 12 ^ 7);
+    printf("%d\n", 12 | 8);
+    printf("%d\n", 12 >> 2);
+    printf("%d\n", 12 << 4);
+    printf("%d\n", ~12);
+    printf("%d\n", -12);
+    printf("%d\n", +12);
+    printf("%d %d %d %d\n", 
+           isid('a'), 
+           isid('g'), 
+           isid('T'), 
+           isid('('));
+}
+
+int isid(int c)
+{
+    return (c >= 'a' & c <= 'z') | (c >= 'A' & c <= 'Z') | c == '_';
+}
+
+/**********************/
+
+int vstack[10], *vstack_ptr;
+
+void vpush(int vt, int vc)
+{
+    *vstack_ptr++ = vt;
+    *vstack_ptr++ = vc;
+}
+
+void vpop(int *ft, int *fc)
+{
+    *fc = *--vstack_ptr;
+    *ft = *--vstack_ptr;
+}
+
+void expr2_test()
+{
+    int a, b;
+
+    printf("expr2:\n");
+    vstack_ptr = vstack;
+    vpush(1432432, 2);
+    vstack_ptr[-2] &= ~0xffffff80;
+    vpop(&a, &b);
+    printf("res= %d %d\n", a, b);
+}
+
+void constant_expr_test()
+{
+    int a;
+    printf("constant_expr:\n");
+    a = 3;
+    printf("%d\n", a * 16);
+    printf("%d\n", a * 1);
+    printf("%d\n", a + 0);
+}
+
+int tab4[10];
+
+void expr_ptr_test()
+{
+    int *p, *q;
+    int i = -1;
+
+    printf("expr_ptr:\n");
+    p = tab4;
+    q = tab4 + 10;
+    printf("diff=%d\n", q - p);
+    p++;
+    printf("inc=%d\n", p - tab4);
+    p--;
+    printf("dec=%d\n", p - tab4);
+    ++p;
+    printf("inc=%d\n", p - tab4);
+    --p;
+    printf("dec=%d\n", p - tab4);
+    printf("add=%d\n", p + 3 - tab4);
+    printf("add=%d\n", 3 + p - tab4);
+
+    /* check if 64bit support is ok */
+    q = p = 0;
+    q += i;
+    printf("%p %p %ld\n", q, p, p-q);
+    printf("%d %d %d %d %d %d\n",
+           p == q, p != q, p < q, p <= q, p >= q, p > q);
+    i = 0xf0000000;
+    p += i;
+    printf("%p %p %ld\n", q, p, p-q);
+    printf("%d %d %d %d %d %d\n",
+           p == q, p != q, p < q, p <= q, p >= q, p > q);
+    p = (int *)((char *)p + 0xf0000000);
+    printf("%p %p %ld\n", q, p, p-q);
+    printf("%d %d %d %d %d %d\n",
+           p == q, p != q, p < q, p <= q, p >= q, p > q);
+    p += 0xf0000000;
+    printf("%p %p %ld\n", q, p, p-q);
+    printf("%d %d %d %d %d %d\n",
+           p == q, p != q, p < q, p <= q, p >= q, p > q);
+    {
+        struct size12 {
+            int i, j, k;
+        };
+        struct size12 s[2], *sp = s;
+        int i, j;
+        sp->i = 42;
+        sp++;
+        j = -1;
+        printf("%d\n", sp[j].i);
+    }
+}
+
+void expr_cmp_test()
+{
+    int a, b;
+    printf("constant_expr:\n");
+    a = -1;
+    b = 1;
+    printf("%d\n", a == a);
+    printf("%d\n", a != a);
+
+    printf("%d\n", a < b);
+    printf("%d\n", a <= b);
+    printf("%d\n", a <= a);
+    printf("%d\n", b >= a);
+    printf("%d\n", a >= a);
+    printf("%d\n", b > a);
+
+    printf("%d\n", (unsigned)a < b);
+    printf("%d\n", (unsigned)a <= b);
+    printf("%d\n", (unsigned)a <= a);
+    printf("%d\n", (unsigned)b >= a);
+    printf("%d\n", (unsigned)a >= a);
+    printf("%d\n", (unsigned)b > a);
+}
+
+struct empty {
+};
+
+struct aligntest1 {
+    char a[10];
+};
+
+struct aligntest2 {
+    int a;
+    char b[10];
+};
+
+struct aligntest3 {
+    double a, b;
+};
+
+struct aligntest4 {
+    double a[0];
+};
+
+void struct_test()
+{
+    struct1 *s;
+    union union2 u;
+
+    printf("struct:\n");
+    printf("sizes: %d %d %d %d\n",
+           sizeof(struct struct1),
+           sizeof(struct struct2),
+           sizeof(union union1),
+           sizeof(union union2));
+    st1.f1 = 1;
+    st1.f2 = 2;
+    st1.f3 = 3;
+    printf("st1: %d %d %d\n",
+           st1.f1, st1.f2, st1.f3);
+    st1.u.v1 = 1;
+    st1.u.v2 = 2;
+    printf("union1: %d\n", st1.u.v1);
+    u.w1 = 1;
+    u.w2 = 2;
+    printf("union2: %d\n", u.w1);
+    s = &st2;
+    s->f1 = 3;
+    s->f2 = 2;
+    s->f3 = 1;
+    printf("st2: %d %d %d\n",
+           s->f1, s->f2, s->f3);
+    printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1);
+
+    /* align / size tests */
+    printf("aligntest1 sizeof=%d alignof=%d\n",
+           sizeof(struct aligntest1), __alignof__(struct aligntest1));
+    printf("aligntest2 sizeof=%d alignof=%d\n",
+           sizeof(struct aligntest2), __alignof__(struct aligntest2));
+    printf("aligntest3 sizeof=%d alignof=%d\n",
+           sizeof(struct aligntest3), __alignof__(struct aligntest3));
+    printf("aligntest4 sizeof=%d alignof=%d\n",
+           sizeof(struct aligntest4), __alignof__(struct aligntest4));
+           
+    /* empty structures (GCC extension) */
+    printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
+    printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
+}
+
+/* XXX: depend on endianness */
+void char_short_test()
+{
+    int var1, var2;
+
+    printf("char_short:\n");
+
+    var1 = 0x01020304;
+    var2 = 0xfffefdfc;
+    printf("s8=%d %d\n", 
+           *(char *)&var1, *(char *)&var2);
+    printf("u8=%d %d\n", 
+           *(unsigned char *)&var1, *(unsigned char *)&var2);
+    printf("s16=%d %d\n", 
+           *(short *)&var1, *(short *)&var2);
+    printf("u16=%d %d\n", 
+           *(unsigned short *)&var1, *(unsigned short *)&var2);
+    printf("s32=%d %d\n", 
+           *(int *)&var1, *(int *)&var2);
+    printf("u32=%d %d\n", 
+           *(unsigned int *)&var1, *(unsigned int *)&var2);
+    *(char *)&var1 = 0x08;
+    printf("var1=%x\n", var1);
+    *(short *)&var1 = 0x0809;
+    printf("var1=%x\n", var1);
+    *(int *)&var1 = 0x08090a0b;
+    printf("var1=%x\n", var1);
+}
+
+/******************/
+
+typedef struct Sym {
+    int v;
+    int t;
+    int c;
+    struct Sym *next;
+    struct Sym *prev;
+} Sym;
+
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+
+static int toupper1(int a)
+{
+    return TOUPPER(a);
+}
+
+void bool_test()
+{
+    int *s, a, b, t, f, i;
+
+    a = 0;
+    s = (void*)0;
+    printf("!s=%d\n", !s);
+
+    if (!s || !s[0])
+        a = 1;
+    printf("a=%d\n", a);
+
+    printf("a=%d %d %d\n", 0 || 0, 0 || 1, 1 || 1);
+    printf("a=%d %d %d\n", 0 && 0, 0 && 1, 1 && 1);
+    printf("a=%d %d\n", 1 ? 1 : 0, 0 ? 1 : 0);
+#if 1 && 1
+    printf("a1\n");
+#endif
+#if 1 || 0
+    printf("a2\n");
+#endif
+#if 1 ? 0 : 1
+    printf("a3\n");
+#endif
+#if 0 ? 0 : 1
+    printf("a4\n");
+#endif
+
+    a = 4;
+    printf("b=%d\n", a + (0 ? 1 : a / 2));
+
+    /* test register spilling */
+    a = 10;
+    b = 10;
+    a = (a + b) * ((a < b) ?
+                   ((b - a) * (a - b)): a + b);
+    printf("a=%d\n", a);
+
+    /* test complex || or && expressions */
+    t = 1;
+    f = 0;
+    a = 32;
+    printf("exp=%d\n", f == (32 <= a && a <= 3));
+    printf("r=%d\n", (t || f) + (t && f));
+
+    /* test ? : cast */
+    {
+        int aspect_on;
+        int aspect_native = 65536;
+        double bfu_aspect = 1.0;
+        int aspect;
+        for(aspect_on = 0; aspect_on < 2; aspect_on++) {
+            aspect=aspect_on?(aspect_native*bfu_aspect+0.5):65535UL;
+            printf("aspect=%d\n", aspect);
+        }
+    }
+
+    /* test ? : GCC extension */
+    {
+        static int v1 = 34 ? : -1; /* constant case */
+        static int v2 = 0 ? : -1; /* constant case */
+        int a = 30;
+        
+        printf("%d %d\n", v1, v2);
+        printf("%d %d\n", a - 30 ? : a * 2, a + 1 ? : a * 2);
+    }
+
+    /* again complex expression */
+    for(i=0;i<256;i++) {
+        if (toupper1 (i) != TOUPPER (i))
+            printf("error %d\n", i);
+    }
+}
+
+/* GCC accepts that */
+static int tab_reinit[];
+static int tab_reinit[10];
+
+//int cinit1; /* a global variable can be defined several times without error ! */
+int cinit1; 
+int cinit1; 
+int cinit1 = 0;
+int *cinit2 = (int []){3, 2, 1};
+
+void compound_literal_test(void)
+{
+    int *p, i;
+    char *q, *q3;
+
+    printf("compound_test:\n");
+
+    p = (int []){1, 2, 3};
+    for(i=0;i<3;i++)
+        printf(" %d", p[i]);
+    printf("\n");
+
+    for(i=0;i<3;i++)
+        printf("%d", cinit2[i]);
+    printf("\n");
+
+    q = "tralala1";
+    printf("q1=%s\n", q);
+
+    q = (char *){ "tralala2" };
+    printf("q2=%s\n", q);
+
+    q3 = (char *){ q };
+    printf("q3=%s\n", q3);
+
+    q = (char []){ "tralala3" };
+    printf("q4=%s\n", q);
+
+#ifdef ALL_ISOC99
+    p = (int []){1, 2, cinit1 + 3};
+    for(i=0;i<3;i++)
+        printf(" %d", p[i]);
+    printf("\n");
+
+    for(i=0;i<3;i++) {
+        p = (int []){1, 2, 4 + i};
+        printf("%d %d %d\n", 
+               p[0],
+               p[1],
+               p[2]);
+    }
+#endif
+}
+
+/* K & R protos */
+
+kr_func1(a, b)
+{
+    return a + b;
+}
+
+int kr_func2(a, b)
+{
+    return a + b;
+}
+
+kr_test()
+{
+    printf("kr_test:\n");
+    printf("func1=%d\n", kr_func1(3, 4));
+    printf("func2=%d\n", kr_func2(3, 4));
+    return 0;
+}
+
+void num(int n)
+{
+    char *tab, *p;
+    tab = (char*)malloc(20); 
+    p = tab;
+    while (1) {
+        *p = 48 + (n % 10);
+        p++;
+        n = n / 10;
+        if (n == 0)
+            break;
+    }
+    while (p != tab) {
+        p--;
+        printf("%c", *p);
+    }
+    printf("\n");
+}
+
+/* structure assignment tests */
+struct structa1 {
+    int f1;
+    char f2;
+};
+
+struct structa1 ssta1;
+
+void struct_assign_test1(struct structa1 s1, int t)
+{
+    printf("%d %d %d\n", s1.f1, s1.f2, t);
+}
+
+struct structa1 struct_assign_test2(struct structa1 s1, int t)
+{
+    s1.f1 += t;
+    s1.f2 -= t;
+    return s1;
+}
+
+void struct_assign_test(void)
+{
+    struct structa1 lsta1, lsta2;
+    
+#if 0
+    printf("struct_assign_test:\n");
+
+    lsta1.f1 = 1;
+    lsta1.f2 = 2;
+    printf("%d %d\n", lsta1.f1, lsta1.f2);
+    lsta2 = lsta1;
+    printf("%d %d\n", lsta2.f1, lsta2.f2);
+#else
+    lsta2.f1 = 1;
+    lsta2.f2 = 2;
+#endif
+    struct_assign_test1(lsta2, 3);
+    
+    printf("before call: %d %d\n", lsta2.f1, lsta2.f2);
+    lsta2 = struct_assign_test2(lsta2, 4);
+    printf("after call: %d %d\n", lsta2.f1, lsta2.f2);
+}
+
+/* casts to short/char */
+
+void cast1(char a, short b, unsigned char c, unsigned short d)
+{
+    printf("%d %d %d %d\n", a, b, c, d);
+}
+
+char bcast;
+short scast;
+
+void cast_test()
+{
+    int a;
+    char c;
+    char tab[10];
+    unsigned b,d;
+    short s;
+    char *p = NULL;
+    p -= 0x700000000042;
+
+    printf("cast_test:\n");
+    a = 0xfffff;
+    cast1(a, a, a, a);
+    a = 0xffffe;
+    printf("%d %d %d %d\n",
+           (char)(a + 1),
+           (short)(a + 1),
+           (unsigned char)(a + 1),
+           (unsigned short)(a + 1));
+    printf("%d %d %d %d\n",
+           (char)0xfffff,
+           (short)0xfffff,
+           (unsigned char)0xfffff,
+           (unsigned short)0xfffff);
+
+    a = (bcast = 128) + 1;
+    printf("%d\n", a);
+    a = (scast = 65536) + 1;
+    printf("%d\n", a);
+    
+    printf("sizeof(c) = %d, sizeof((int)c) = %d\n", sizeof(c), sizeof((int)c));
+    
+    /* test cast from unsigned to signed short to int */
+    b = 0xf000;
+    d = (short)b;
+    printf("((unsigned)(short)0x%08x) = 0x%08x\n", b, d);
+    b = 0xf0f0;
+    d = (char)b;
+    printf("((unsigned)(char)0x%08x) = 0x%08x\n", b, d);
+    
+    /* test implicit int casting for array accesses */
+    c = 0;
+    tab[1] = 2;
+    tab[c] = 1;
+    printf("%d %d\n", tab[0], tab[1]);
+
+    /* test implicit casting on some operators */
+    printf("sizeof(+(char)'a') = %d\n", sizeof(+(char)'a'));
+    printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
+    printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
+
+    /* from pointer to integer types */
+    printf("%d %d %ld %ld %lld %lld\n",
+           (int)p, (unsigned int)p,
+           (long)p, (unsigned long)p,
+           (long long)p, (unsigned long long)p);
+
+    /* from integers to pointers */
+    printf("%p %p %p %p\n",
+           (void *)a, (void *)b, (void *)c, (void *)d);
+}
+
+/* initializers tests */
+struct structinit1 {
+    int f1;
+    char f2;
+    short f3;
+    int farray[3];
+};
+
+int sinit1 = 2;
+int sinit2 = { 3 };
+int sinit3[3] = { 1, 2, {{3}}, };
+int sinit4[3][2] = { {1, 2}, {3, 4}, {5, 6} };
+int sinit5[3][2] = { 1, 2, 3, 4, 5, 6 };
+int sinit6[] = { 1, 2, 3 };
+int sinit7[] = { [2] = 3, [0] = 1, 2 };
+char sinit8[] = "hello" "trala";
+
+struct structinit1 sinit9 = { 1, 2, 3 };
+struct structinit1 sinit10 = { .f2 = 2, 3, .f1 = 1 };
+struct structinit1 sinit11 = { .f2 = 2, 3, .f1 = 1, 
+#ifdef ALL_ISOC99
+                               .farray[0] = 10,
+                               .farray[1] = 11,
+                               .farray[2] = 12,
+#endif
+};
+
+char *sinit12 = "hello world";
+char *sinit13[] = {
+    "test1",
+    "test2",
+    "test3",
+};
+char sinit14[10] = { "abc" };
+int sinit15[3] = { sizeof(sinit15), 1, 2 };
+
+struct { int a[3], b; } sinit16[] = { { 1 }, 2 };
+
+struct bar {
+        char *s;
+        int len;
+} sinit17[] = {
+        "a1", 4,
+        "a2", 1
+};
+
+int sinit18[10] = {
+    [2 ... 5] = 20,
+    2,
+    [8] = 10,
+};
+
+void init_test(void)
+{
+    int linit1 = 2;
+    int linit2 = { 3 };
+    int linit4[3][2] = { {1, 2}, {3, 4}, {5, 6} };
+    int linit6[] = { 1, 2, 3 };
+    int i, j;
+    char linit8[] = "hello" "trala";
+    int linit12[10] = { 1, 2 };
+    int linit13[10] = { 1, 2, [7] = 3, [3] = 4, };
+    char linit14[10] = "abc";
+    int linit15[10] = { linit1, linit1 + 1, [6] = linit1 + 2, };
+    struct linit16 { int a1, a2, a3, a4; } linit16 = { 1, .a3 = 2 };
+    int linit17 = sizeof(linit17);
+    
+    printf("init_test:\n");
+
+    printf("sinit1=%d\n", sinit1);
+    printf("sinit2=%d\n", sinit2);
+    printf("sinit3=%d %d %d %d\n", 
+           sizeof(sinit3),
+           sinit3[0],
+           sinit3[1],
+           sinit3[2]
+           );
+    printf("sinit6=%d\n", sizeof(sinit6));
+    printf("sinit7=%d %d %d %d\n", 
+           sizeof(sinit7),
+           sinit7[0],
+           sinit7[1],
+           sinit7[2]
+           );
+    printf("sinit8=%s\n", sinit8);
+    printf("sinit9=%d %d %d\n", 
+           sinit9.f1,
+           sinit9.f2,
+           sinit9.f3
+           );
+    printf("sinit10=%d %d %d\n", 
+           sinit10.f1,
+           sinit10.f2,
+           sinit10.f3
+           );
+    printf("sinit11=%d %d %d %d %d %d\n", 
+           sinit11.f1,
+           sinit11.f2,
+           sinit11.f3,
+           sinit11.farray[0],
+           sinit11.farray[1],
+           sinit11.farray[2]
+           );
+
+    for(i=0;i<3;i++)
+        for(j=0;j<2;j++)
+            printf("[%d][%d] = %d %d %d\n", 
+                   i, j, sinit4[i][j], sinit5[i][j], linit4[i][j]);
+    printf("linit1=%d\n", linit1);
+    printf("linit2=%d\n", linit2);
+    printf("linit6=%d\n", sizeof(linit6));
+    printf("linit8=%d %s\n", sizeof(linit8), linit8);
+
+    printf("sinit12=%s\n", sinit12);
+    printf("sinit13=%d %s %s %s\n",
+           sizeof(sinit13), 
+           sinit13[0],
+           sinit13[1],
+           sinit13[2]);
+    printf("sinit14=%s\n", sinit14);
+
+    for(i=0;i<10;i++) printf(" %d", linit12[i]);
+    printf("\n");
+    for(i=0;i<10;i++) printf(" %d", linit13[i]);
+    printf("\n");
+    for(i=0;i<10;i++) printf(" %d", linit14[i]);
+    printf("\n");
+    for(i=0;i<10;i++) printf(" %d", linit15[i]);
+    printf("\n");
+    printf("%d %d %d %d\n", 
+           linit16.a1,
+           linit16.a2,
+           linit16.a3,
+           linit16.a4);
+    /* test that initialisation is done after variable declare */
+    printf("linit17=%d\n", linit17);
+    printf("sinit15=%d\n", sinit15[0]);
+    printf("sinit16=%d %d\n", sinit16[0].a[0], sinit16[1].a[0]);
+    printf("sinit17=%s %d %s %d\n",
+           sinit17[0].s, sinit17[0].len,
+           sinit17[1].s, sinit17[1].len);
+    for(i=0;i<10;i++)
+        printf("%x ", sinit18[i]);
+    printf("\n");
+}
+
+
+void switch_test()
+{
+    int i;
+
+    for(i=0;i<15;i++) {
+        switch(i) {
+        case 0:
+        case 1:
+            printf("a");
+            break;
+        default:
+            printf("%d", i);
+            break;
+        case 8 ... 12:
+            printf("c");
+            break;
+        case 3:
+            printf("b");
+            break;
+        }
+    }
+    printf("\n");
+}
+
+/* ISOC99 _Bool type */
+void c99_bool_test(void)
+{
+#ifdef BOOL_ISOC99
+    int a;
+    _Bool b;
+
+    printf("bool_test:\n");
+    printf("sizeof(_Bool) = %d\n", sizeof(_Bool));
+    a = 3;
+    printf("cast: %d %d %d\n", (_Bool)10, (_Bool)0, (_Bool)a);
+    b = 3;
+    printf("b = %d\n", b);
+    b++;
+    printf("b = %d\n", b);
+#endif
+}
+
+void bitfield_test(void)
+{
+    int a;
+    struct sbf1 {
+        int f1 : 3;
+        int : 2;
+        int f2 : 1;
+        int : 0;
+        int f3 : 5;
+        int f4 : 7;
+        unsigned int f5 : 7;
+    } st1;
+    printf("bitfield_test:");
+    printf("sizeof(st1) = %d\n", sizeof(st1));
+
+    st1.f1 = 3;
+    st1.f2 = 1;
+    st1.f3 = 15;
+    a = 120;
+    st1.f4 = a;
+    st1.f5 = a;
+    st1.f5++;
+    printf("%d %d %d %d %d\n",
+           st1.f1, st1.f2, st1.f3, st1.f4, st1.f5);
+
+    st1.f1 = 7;
+    if (st1.f1 == -1) 
+        printf("st1.f1 == -1\n");
+    else 
+        printf("st1.f1 != -1\n");
+    if (st1.f2 == -1) 
+        printf("st1.f2 == -1\n");
+    else 
+        printf("st1.f2 != -1\n");
+
+    /* bit sizes below must be bigger than 32 since GCC doesn't allow
+       long-long bitfields whose size is not bigger than int */
+    struct sbf2 {
+        long long f1 : 45;
+        long long : 2;
+        long long f2 : 35;
+        unsigned long long f3 : 38;
+    } st2;
+    st2.f1 = 0x123456789ULL;
+    a = 120;
+    st2.f2 = (long long)a << 25;
+    st2.f3 = a;
+    st2.f2++;
+    printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3);
+}
+
+#ifdef __x86_64__
+#define FLOAT_FMT "%f\n"
+#else
+/* x86's float isn't compatible with GCC */
+#define FLOAT_FMT "%.5f\n"
+#endif
+
+/* declare strto* functions as they are C99 */
+double strtod(const char *nptr, char **endptr);
+float strtof(const char *nptr, char **endptr);
+long double strtold(const char *nptr, char **endptr);
+
+#define FTEST(prefix, type, fmt)\
+void prefix ## cmp(type a, type b)\
+{\
+    printf("%d %d %d %d %d %d\n",\
+           a == b,\
+           a != b,\
+           a < b,\
+           a > b,\
+           a >= b,\
+           a <= b);\
+    printf(fmt " " fmt " " fmt " " fmt " " fmt " " fmt " " fmt "\n",\
+           a,\
+           b,\
+           a + b,\
+           a - b,\
+           a * b,\
+           a / b,\
+           -a);\
+    printf(fmt "\n", ++a);\
+    printf(fmt "\n", a++);\
+    printf(fmt "\n", a);\
+    b = 0;\
+    printf("%d %d\n", !a, !b);\
+}\
+void prefix ## fcast(type a)\
+{\
+    float fa;\
+    double da;\
+    long double la;\
+    int ia;\
+    unsigned int ua;\
+    type b;\
+    fa = a;\
+    da = a;\
+    la = a;\
+    printf("ftof: %f %f %Lf\n", fa, da, la);\
+    ia = (int)a;\
+    ua = (unsigned int)a;\
+    printf("ftoi: %d %u\n", ia, ua);\
+    ia = -1234;\
+    ua = 0x81234500;\
+    b = ia;\
+    printf("itof: " fmt "\n", b);\
+    b = ua;\
+    printf("utof: " fmt "\n", b);\
+}\
+\
+float prefix ## retf(type a) { return a; }\
+double prefix ## retd(type a) { return a; }\
+long double prefix ## retld(type a) { return a; }\
+\
+void prefix ## call(void)\
+{\
+    printf("float: " FLOAT_FMT, prefix ## retf(42.123456789));\
+    printf("double: %f\n", prefix ## retd(42.123456789));\
+    printf("long double: %Lf\n", prefix ## retld(42.123456789));\
+    printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\
+}\
+\
+void prefix ## test(void)\
+{\
+    printf("testing '%s'\n", #type);\
+    prefix ## cmp(1, 2.5);\
+    prefix ## cmp(2, 1.5);\
+    prefix ## cmp(1, 1);\
+    prefix ## fcast(234.6);\
+    prefix ## fcast(-2334.6);\
+    prefix ## call();\
+}
+
+FTEST(f, float, "%f")
+FTEST(d, double, "%f")
+FTEST(ld, long double, "%Lf")
+
+double ftab1[3] = { 1.2, 3.4, -5.6 };
+
+
+void float_test(void)
+{
+    float fa, fb;
+    double da, db;
+    int a;
+    unsigned int b;
+
+    printf("float_test:\n");
+    printf("sizeof(float) = %d\n", sizeof(float));
+    printf("sizeof(double) = %d\n", sizeof(double));
+    printf("sizeof(long double) = %d\n", sizeof(long double));
+    ftest();
+    dtest();
+    ldtest();
+    printf("%f %f %f\n", ftab1[0], ftab1[1], ftab1[2]);
+    printf("%f %f %f\n", 2.12, .5, 2.3e10);
+    //    printf("%f %f %f\n", 0x1234p12, 0x1e23.23p10, 0x12dp-10);
+    da = 123;
+    printf("da=%f\n", da);
+    fa = 123;
+    printf("fa=%f\n", fa);
+    a = 4000000000;
+    da = a;
+    printf("da = %f\n", da);
+    b = 4000000000;
+    db = b;
+    printf("db = %f\n", db);
+}
+
+int fib(int n)
+{
+    if (n <= 2)
+        return 1;
+    else
+        return fib(n-1) + fib(n-2);
+}
+
+void funcptr_test()
+{
+    void (*func)(int);
+    int a;
+    struct {
+        int dummy;
+        void (*func)(int);
+    } st1;
+
+    printf("funcptr:\n");
+    func = &num;
+    (*func)(12345);
+    func = num;
+    a = 1;
+    a = 1;
+    func(12345);
+    /* more complicated pointer computation */
+    st1.func = num;
+    st1.func(12346);
+    printf("sizeof1 = %d\n", sizeof(funcptr_test));
+    printf("sizeof2 = %d\n", sizeof funcptr_test);
+    printf("sizeof3 = %d\n", sizeof(&funcptr_test));
+    printf("sizeof4 = %d\n", sizeof &funcptr_test);
+}
+
+void lloptest(long long a, long long b)
+{
+    unsigned long long ua, ub;
+
+    ua = a;
+    ub = b;
+    /* arith */
+    printf("arith: %Ld %Ld %Ld\n",
+           a + b,
+           a - b,
+           a * b);
+    
+    if (b != 0) {
+        printf("arith1: %Ld %Ld\n",
+           a / b,
+           a % b);
+    }
+
+    /* binary */
+    printf("bin: %Ld %Ld %Ld\n",
+           a & b,
+           a | b,
+           a ^ b);
+
+    /* tests */
+    printf("test: %d %d %d %d %d %d\n",
+           a == b,
+           a != b,
+           a < b,
+           a > b,
+           a >= b,
+           a <= b);
+    
+    printf("utest: %d %d %d %d %d %d\n",
+           ua == ub,
+           ua != ub,
+           ua < ub,
+           ua > ub,
+           ua >= ub,
+           ua <= ub);
+
+    /* arith2 */
+    a++;
+    b++;
+    printf("arith2: %Ld %Ld\n", a, b);
+    printf("arith2: %Ld %Ld\n", a++, b++);
+    printf("arith2: %Ld %Ld\n", --a, --b);
+    printf("arith2: %Ld %Ld\n", a, b);
+    b = ub = 0;
+    printf("not: %d %d %d %d\n", !a, !ua, !b, !ub);
+}
+
+void llshift(long long a, int b)
+{
+    printf("shift: %Ld %Ld %Ld\n",
+           (unsigned long long)a >> b,
+           a >> b,
+           a << b);
+    printf("shiftc: %Ld %Ld %Ld\n",
+           (unsigned long long)a >> 3,
+           a >> 3,
+           a << 3);
+    printf("shiftc: %Ld %Ld %Ld\n",
+           (unsigned long long)a >> 35,
+           a >> 35,
+           a << 35);
+}
+
+void llfloat(void)
+{
+    float fa;
+    double da;
+    long double lda;
+    long long la, lb, lc;
+    unsigned long long ula, ulb, ulc;
+    la = 0x12345678;
+    ula = 0x72345678;
+    la = (la << 20) | 0x12345;
+    ula = ula << 33;
+    printf("la=%Ld ula=%Lu\n", la, ula);
+
+    fa = la;
+    da = la;
+    lda = la;
+    printf("lltof: %f %f %Lf\n", fa, da, lda);
+
+    la = fa;
+    lb = da;
+    lc = lda;
+    printf("ftoll: %Ld %Ld %Ld\n", la, lb, lc);
+
+    fa = ula;
+    da = ula;
+    lda = ula;
+    printf("ulltof: %f %f %Lf\n", fa, da, lda);
+
+    ula = fa;
+    ulb = da;
+    ulc = lda;
+    printf("ftoull: %Lu %Lu %Lu\n", ula, ulb, ulc);
+}
+
+long long llfunc1(int a)
+{
+    return a * 2;
+}
+
+struct S {
+    int id; 
+    char item;
+};
+
+long long int value(struct S *v)
+{
+    return ((long long int)v->item);
+}
+
+void longlong_test(void)
+{
+    long long a, b, c;
+    int ia;
+    unsigned int ua;
+    printf("longlong_test:\n");
+    printf("sizeof(long long) = %d\n", sizeof(long long));
+    ia = -1;
+    ua = -2;
+    a = ia;
+    b = ua;
+    printf("%Ld %Ld\n", a, b);
+    printf("%Ld %Ld %Ld %Lx\n", 
+           (long long)1, 
+           (long long)-2,
+           1LL,
+           0x1234567812345679);
+    a = llfunc1(-3);
+    printf("%Ld\n", a);
+
+    lloptest(1000, 23);
+    lloptest(0xff, 0x1234);
+    b = 0x72345678 << 10;
+    lloptest(-3, b);
+    llshift(0x123, 5);
+    llshift(-23, 5);
+    b = 0x72345678LL << 10;
+    llshift(b, 47);
+
+    llfloat();
+#if 1
+    b = 0x12345678;
+    a = -1;
+    c = a + b;
+    printf("%Lx\n", c);
+#endif
+
+    /* long long reg spill test */
+    {
+          struct S a;
+
+          a.item = 3;
+          printf("%lld\n", value(&a));
+    }
+    lloptest(0x80000000, 0);
+
+    /* another long long spill test */
+    {
+        long long *p, v;
+        v = 1;
+        p = &v;
+        p[0]++;
+        printf("%lld\n", *p);
+    }
+
+    a = 68719476720LL;
+    b = 4294967295LL;
+    printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b);
+
+    printf("%Ld\n", 0x123456789LLU);
+}
+
+void manyarg_test(void)
+{
+    long double ld = 1234567891234LL;
+    printf("manyarg_test:\n");
+    printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
+           1, 2, 3, 4, 5, 6, 7, 8,
+           0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
+    printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+           "%Ld %Ld %f %f\n",
+           1, 2, 3, 4, 5, 6, 7, 8,
+           0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+           1234567891234LL, 987654321986LL,
+           42.0, 43.0);
+    printf("%Lf %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+           "%Ld %Ld %f %f\n",
+           ld, 1, 2, 3, 4, 5, 6, 7, 8,
+           0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+           1234567891234LL, 987654321986LL,
+           42.0, 43.0);
+    /* XXX: known bug of x86-64 */
+#ifndef __x86_64__
+    printf("%d %d %d %d %d %d %d %d %Lf\n",
+           1, 2, 3, 4, 5, 6, 7, 8, ld);
+    printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+           "%Ld %Ld %f %f %Lf\n",
+           1, 2, 3, 4, 5, 6, 7, 8,
+           0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+           1234567891234LL, 987654321986LL,
+           42.0, 43.0, ld);
+    printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+           "%Lf %Ld %Ld %f %f %Lf\n",
+           1, 2, 3, 4, 5, 6, 7, 8,
+           0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+           ld, 1234567891234LL, 987654321986LL,
+           42.0, 43.0, ld);
+#endif
+}
+
+void vprintf1(const char *fmt, ...)
+{
+    va_list ap;
+    const char *p;
+    int c, i;
+    double d;
+    long long ll;
+    long double ld;
+
+    va_start(ap, fmt);
+    
+    p = fmt;
+    for(;;) {
+        c = *p;
+        if (c == '\0')
+            break;
+        p++;
+        if (c == '%') {
+            c = *p;
+            switch(c) {
+            case '\0':
+                goto the_end;
+            case 'd':
+                i = va_arg(ap, int);
+                printf("%d", i);
+                break;
+            case 'f':
+                d = va_arg(ap, double);
+                printf("%f", d);
+                break;
+            case 'l':
+                ll = va_arg(ap, long long);
+                printf("%Ld", ll);
+                break;
+            case 'F':
+                ld = va_arg(ap, long double);
+                printf("%Lf", ld);
+                break;
+            }
+            p++;
+        } else {
+            putchar(c);
+        }
+    }
+ the_end:
+    va_end(ap);
+}
+
+
+void stdarg_test(void)
+{
+    long double ld = 1234567891234LL;
+    vprintf1("%d %d %d\n", 1, 2, 3);
+    vprintf1("%f %d %f\n", 1.0, 2, 3.0);
+    vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0);
+    vprintf1("%F %F %F\n", 1.2L, 2.3L, 3.4L);
+#ifdef __x86_64__
+    /* a bug of x86's TCC */
+    vprintf1("%d %f %l %F %d %f %l %F\n",
+             1, 1.2, 3L, 4.5L, 6, 7.8, 9L, 0.1L);
+#endif
+    vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f\n",
+             1, 2, 3, 4, 5, 6, 7, 8,
+             0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8);
+    vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
+             1, 2, 3, 4, 5, 6, 7, 8,
+             0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
+    vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+             "%l %l %f %f\n",
+             1, 2, 3, 4, 5, 6, 7, 8,
+             0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+             1234567891234LL, 987654321986LL,
+             42.0, 43.0);
+    vprintf1("%F %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+             "%l %l %f %f\n",
+             ld, 1, 2, 3, 4, 5, 6, 7, 8,
+             0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+             1234567891234LL, 987654321986LL,
+             42.0, 43.0);
+    vprintf1("%d %d %d %d %d %d %d %d %F\n",
+             1, 2, 3, 4, 5, 6, 7, 8, ld);
+    vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+             "%l %l %f %f %F\n",
+             1, 2, 3, 4, 5, 6, 7, 8,
+             0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+             1234567891234LL, 987654321986LL,
+             42.0, 43.0, ld);
+    vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
+             "%F %l %l %f %f %F\n",
+             1, 2, 3, 4, 5, 6, 7, 8,
+             0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
+             ld, 1234567891234LL, 987654321986LL,
+             42.0, 43.0, ld);
+}
+
+void whitespace_test(void)
+{
+    char *str;
+
+
#if 1
+    pri\
+ntf("whitspace:\n");

+#endif
+    pf("N=%d\n", 2);
+
+#ifdef CORRECT_CR_HANDLING
+    pri\

+ntf("aaa=%d\n", 3);
+#endif
+
+    pri\
+\
+ntf("min=%d\n", 4);
+
+#ifdef ACCEPT_CR_IN_STRINGS
+    printf("len1=%d\n", strlen("
+"));
+#ifdef CORRECT_CR_HANDLING
+    str = "

+";
+    printf("len1=%d str[0]=%d\n", strlen(str), str[0]);
+#endif
+    printf("len1=%d\n", strlen("
a
+"));
+#endif /* ACCEPT_CR_IN_STRINGS */
+}
+
+int reltab[3] = { 1, 2, 3 };
+
+int *rel1 = &reltab[1];
+int *rel2 = &reltab[2];
+
+void relocation_test(void)
+{
+    printf("*rel1=%d\n", *rel1);
+    printf("*rel2=%d\n", *rel2);
+}
+
+void old_style_f(a,b,c)
+     int a, b;
+     double c;
+{
+    printf("a=%d b=%d b=%f\n", a, b, c);
+}
+
+void decl_func1(int cmpfn())
+{
+    printf("cmpfn=%lx\n", (long)cmpfn);
+}
+
+void decl_func2(cmpfn)
+int cmpfn();
+{
+    printf("cmpfn=%lx\n", (long)cmpfn);
+}
+
+void old_style_function(void)
+{
+    old_style_f((void *)1, 2, 3.0);
+    decl_func1(NULL);
+    decl_func2(NULL);
+}
+
+void alloca_test()
+{
+#if defined __i386__ || defined __x86_64__
+    char *p = alloca(16);
+    strcpy(p,"123456789012345");
+    printf("alloca: p is %s\n", p);
+    char *demo = "This is only a test.\n";
+    /* Test alloca embedded in a larger expression */
+    printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
+#endif
+}
+
+void sizeof_test(void)
+{
+    int a;
+    int **ptr;
+
+    printf("sizeof(int) = %d\n", sizeof(int));
+    printf("sizeof(unsigned int) = %d\n", sizeof(unsigned int));
+    printf("sizeof(long) = %d\n", sizeof(long));
+    printf("sizeof(unsigned long) = %d\n", sizeof(unsigned long));
+    printf("sizeof(short) = %d\n", sizeof(short));
+    printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short));
+    printf("sizeof(char) = %d\n", sizeof(char));
+    printf("sizeof(unsigned char) = %d\n", sizeof(unsigned char));
+    printf("sizeof(func) = %d\n", sizeof sizeof_test());
+    a = 1;
+    printf("sizeof(a++) = %d\n", sizeof a++);
+    printf("a=%d\n", a);
+    ptr = NULL;
+    printf("sizeof(**ptr) = %d\n", sizeof (**ptr));
+
+    /* some alignof tests */
+    printf("__alignof__(int) = %d\n", __alignof__(int));
+    printf("__alignof__(unsigned int) = %d\n", __alignof__(unsigned int));
+    printf("__alignof__(short) = %d\n", __alignof__(short));
+    printf("__alignof__(unsigned short) = %d\n", __alignof__(unsigned short));
+    printf("__alignof__(char) = %d\n", __alignof__(char));
+    printf("__alignof__(unsigned char) = %d\n", __alignof__(unsigned char));
+    printf("__alignof__(func) = %d\n", __alignof__ sizeof_test());
+}
+
+void typeof_test(void)
+{
+    double a;
+    typeof(a) b;
+    typeof(float) c;
+
+    a = 1.5;
+    b = 2.5;
+    c = 3.5;
+    printf("a=%f b=%f c=%f\n", a, b, c);
+}
+
+void statement_expr_test(void)
+{
+    int a, i;
+
+    a = 0;
+    for(i=0;i<10;i++) {
+        a += 1 + 
+            ( { int b, j; 
+                b = 0; 
+                for(j=0;j<5;j++) 
+                    b += j; b; 
+            } );
+    }
+    printf("a=%d\n", a);
+    
+}
+
+void local_label_test(void)
+{
+    int a;
+    goto l1;
+ l2:
+    a = 1 + ({
+        __label__ l1, l2, l3, l4;
+        goto l1;
+    l4:
+        printf("aa1\n");
+        goto l3;
+    l2:
+        printf("aa3\n");
+        goto l4;
+    l1:
+        printf("aa2\n");
+        goto l2;
+    l3:;
+        1;
+    });
+    printf("a=%d\n", a);
+    return;
+ l4:
+    printf("bb1\n");
+    goto l2;
+ l1:
+    printf("bb2\n");
+    goto l4;
+}
+
+/* inline assembler test */
+#ifdef __i386__
+
+/* from linux kernel */
+static char * strncat1(char * dest,const char * src,size_t count)
+{
+int d0, d1, d2, d3;
+__asm__ __volatile__(
+	"repne\n\t"
+	"scasb\n\t"
+	"decl %1\n\t"
+	"movl %8,%3\n"
+	"1:\tdecl %3\n\t"
+	"js 2f\n\t"
+	"lodsb\n\t"
+	"stosb\n\t"
+	"testb %%al,%%al\n\t"
+	"jne 1b\n"
+	"2:\txorl %2,%2\n\t"
+	"stosb"
+	: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+	: "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
+	: "memory");
+return dest;
+}
+
+static inline void * memcpy1(void * to, const void * from, size_t n)
+{
+int d0, d1, d2;
+__asm__ __volatile__(
+	"rep ; movsl\n\t"
+	"testb $2,%b4\n\t"
+	"je 1f\n\t"
+	"movsw\n"
+	"1:\ttestb $1,%b4\n\t"
+	"je 2f\n\t"
+	"movsb\n"
+	"2:"
+	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
+	:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
+	: "memory");
+return (to);
+}
+
+static __inline__ void sigaddset1(unsigned int *set, int _sig)
+{
+	__asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
+}
+
+static __inline__ void sigdelset1(unsigned int *set, int _sig)
+{
+	asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
+}
+
+static __inline__ __const__ unsigned int swab32(unsigned int x)
+{
+	__asm__("xchgb %b0,%h0\n\t"	/* swap lower bytes	*/
+		"rorl $16,%0\n\t"	/* swap words		*/
+		"xchgb %b0,%h0"		/* swap higher bytes	*/
+		:"=q" (x)
+		: "0" (x));
+	return x;
+}
+
+static __inline__ unsigned long long mul64(unsigned int a, unsigned int b)
+{
+    unsigned long long res;
+    __asm__("mull %2" : "=A" (res) : "a" (a), "r" (b));
+    return res;
+}
+
+static __inline__ unsigned long long inc64(unsigned long long a)
+{
+    unsigned long long res;
+    __asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a));
+    return res;
+}
+
+unsigned int set;
+
+void asm_test(void)
+{
+    char buf[128];
+    unsigned int val;
+
+    printf("inline asm:\n");
+    /* test the no operand case */
+    asm volatile ("xorl %eax, %eax");
+
+    memcpy1(buf, "hello", 6);
+    strncat1(buf, " worldXXXXX", 3);
+    printf("%s\n", buf);
+
+    /* 'A' constraint test */
+    printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234));
+    printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff));
+
+    set = 0xff;
+    sigdelset1(&set, 2);
+    sigaddset1(&set, 16);
+    /* NOTE: we test here if C labels are correctly restored after the
+       asm statement */
+    goto label1;
+ label2:
+    __asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
+#ifdef __GNUC__ // works strange with GCC 4.3
+    set=0x1080fd;
+#endif
+    printf("set=0x%x\n", set);
+    val = 0x01020304;
+    printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));
+    return;
+ label1:
+    goto label2;
+}
+
+#else
+
+void asm_test(void)
+{
+}
+
+#endif
+
+#define COMPAT_TYPE(type1, type2) \
+{\
+    printf("__builtin_types_compatible_p(%s, %s) = %d\n", #type1, #type2, \
+           __builtin_types_compatible_p (type1, type2));\
+}
+
+int constant_p_var;
+
+void builtin_test(void)
+{
+#if GCC_MAJOR >= 3
+    COMPAT_TYPE(int, int);
+    COMPAT_TYPE(int, unsigned int);
+    COMPAT_TYPE(int, char);
+    COMPAT_TYPE(int, const int);
+    COMPAT_TYPE(int, volatile int);
+    COMPAT_TYPE(int *, int *);
+    COMPAT_TYPE(int *, void *);
+    COMPAT_TYPE(int *, const int *);
+    COMPAT_TYPE(char *, unsigned char *);
+/* space is needed because tcc preprocessor introduces a space between each token */
+    COMPAT_TYPE(char * *, void *); 
+#endif
+    printf("res = %d\n", __builtin_constant_p(1));
+    printf("res = %d\n", __builtin_constant_p(1 + 2));
+    printf("res = %d\n", __builtin_constant_p(&constant_p_var));
+    printf("res = %d\n", __builtin_constant_p(constant_p_var));
+}
+
+
+void const_func(const int a)
+{
+}
+
+void const_warn_test(void)
+{
+    const_func(1);
+}
diff --git a/tinyc/texi2pod.pl b/tinyc/texi2pod.pl
new file mode 100644
index 000000000..d86e176f1
--- /dev/null
+++ b/tinyc/texi2pod.pl
@@ -0,0 +1,427 @@
+#! /usr/bin/perl -w
+
+#   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+
+# This file is part of GNU CC.
+
+# GNU CC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# GNU CC 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 General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GNU CC; see the file COPYING.  If not, write to
+# the Free Software Foundation, 59 Temple Place - Suite 330,
+# Boston MA 02111-1307, USA.
+
+# This does trivial (and I mean _trivial_) conversion of Texinfo
+# markup to Perl POD format.  It's intended to be used to extract
+# something suitable for a manpage from a Texinfo document.
+
+$output = 0;
+$skipping = 0;
+%sects = ();
+$section = "";
+@icstack = ();
+@endwstack = ();
+@skstack = ();
+@instack = ();
+$shift = "";
+%defs = ();
+$fnno = 1;
+$inf = "";
+$ibase = "";
+
+while ($_ = shift) {
+    if (/^-D(.*)$/) {
+	if ($1 ne "") {
+	    $flag = $1;
+	} else {
+	    $flag = shift;
+	}
+	$value = "";
+	($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
+	die "no flag specified for -D\n"
+	    unless $flag ne "";
+	die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
+	    unless $flag =~ /^[a-zA-Z0-9_-]+$/;
+	$defs{$flag} = $value;
+    } elsif (/^-/) {
+	usage();
+    } else {
+	$in = $_, next unless defined $in;
+	$out = $_, next unless defined $out;
+	usage();
+    }
+}
+
+if (defined $in) {
+    $inf = gensym();
+    open($inf, "<$in") or die "opening \"$in\": $!\n";
+    $ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
+} else {
+    $inf = \*STDIN;
+}
+
+if (defined $out) {
+    open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
+}
+
+while(defined $inf) {
+while(<$inf>) {
+    # Certain commands are discarded without further processing.
+    /^\@(?:
+	 [a-z]+index		# @*index: useful only in complete manual
+	 |need			# @need: useful only in printed manual
+	 |(?:end\s+)?group	# @group .. @end group: ditto
+	 |page			# @page: ditto
+	 |node			# @node: useful only in .info file
+	 |(?:end\s+)?ifnottex   # @ifnottex .. @end ifnottex: use contents
+	)\b/x and next;
+
+    chomp;
+
+    # Look for filename and title markers.
+    /^\@setfilename\s+([^.]+)/ and $fn = $1, next;
+    /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
+
+    # Identify a man title but keep only the one we are interested in.
+    /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
+	if (exists $defs{$1}) {
+	    $fn = $1;
+	    $tl = postprocess($2);
+	}
+	next;
+    };
+
+    # Look for blocks surrounded by @c man begin SECTION ... @c man end.
+    # This really oughta be @ifman ... @end ifman and the like, but such
+    # would require rev'ing all other Texinfo translators.
+    /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
+	$output = 1 if exists $defs{$2};
+        $sect = $1;
+	next;
+    };
+    /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
+    /^\@c\s+man\s+end/ and do {
+	$sects{$sect} = "" unless exists $sects{$sect};
+	$sects{$sect} .= postprocess($section);
+	$section = "";
+	$output = 0;
+	next;
+    };
+
+    # handle variables
+    /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
+	$defs{$1} = $2;
+	next;
+    };
+    /^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
+	delete $defs{$1};
+	next;
+    };
+
+    next unless $output;
+
+    # Discard comments.  (Can't do it above, because then we'd never see
+    # @c man lines.)
+    /^\@c\b/ and next;
+
+    # End-block handler goes up here because it needs to operate even
+    # if we are skipping.
+    /^\@end\s+([a-z]+)/ and do {
+	# Ignore @end foo, where foo is not an operation which may
+	# cause us to skip, if we are presently skipping.
+	my $ended = $1;
+	next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/;
+
+	die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
+	die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
+
+	$endw = pop @endwstack;
+
+	if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
+	    $skipping = pop @skstack;
+	    next;
+	} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
+	    $shift = "";
+	    $_ = "";	# need a paragraph break
+	} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
+	    $_ = "\n=back\n";
+	    $ic = pop @icstack;
+	} else {
+	    die "unknown command \@end $ended at line $.\n";
+	}
+    };
+
+    # We must handle commands which can cause skipping even while we
+    # are skipping, otherwise we will not process nested conditionals
+    # correctly.
+    /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
+	push @endwstack, $endw;
+	push @skstack, $skipping;
+	$endw = "ifset";
+	$skipping = 1 unless exists $defs{$1};
+	next;
+    };
+
+    /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
+	push @endwstack, $endw;
+	push @skstack, $skipping;
+	$endw = "ifclear";
+	$skipping = 1 if exists $defs{$1};
+	next;
+    };
+
+    /^\@(ignore|menu|iftex)\b/ and do {
+	push @endwstack, $endw;
+	push @skstack, $skipping;
+	$endw = $1;
+	$skipping = 1;
+	next;
+    };
+
+    next if $skipping;
+
+    # Character entities.  First the ones that can be replaced by raw text
+    # or discarded outright:
+    s/\@copyright\{\}/(c)/g;
+    s/\@dots\{\}/.../g;
+    s/\@enddots\{\}/..../g;
+    s/\@([.!? ])/$1/g;
+    s/\@[:-]//g;
+    s/\@bullet(?:\{\})?/*/g;
+    s/\@TeX\{\}/TeX/g;
+    s/\@pounds\{\}/\#/g;
+    s/\@minus(?:\{\})?/-/g;
+    s/\\,/,/g;
+
+    # Now the ones that have to be replaced by special escapes
+    # (which will be turned back into text by unmunge())
+    s/&/&amp;/g;
+    s/\@\{/&lbrace;/g;
+    s/\@\}/&rbrace;/g;
+    s/\@\@/&at;/g;
+
+    # Inside a verbatim block, handle @var specially.
+    if ($shift ne "") {
+	s/\@var\{([^\}]*)\}/<$1>/g;
+    }
+
+    # POD doesn't interpret E<> inside a verbatim block.
+    if ($shift eq "") {
+	s/</&lt;/g;
+	s/>/&gt;/g;
+    } else {
+	s/</&LT;/g;
+	s/>/&GT;/g;
+    }
+
+    # Single line command handlers.
+
+    /^\@include\s+(.+)$/ and do {
+	push @instack, $inf;
+	$inf = gensym();
+
+	# Try cwd and $ibase.
+	open($inf, "<" . $1) 
+	    or open($inf, "<" . $ibase . "/" . $1)
+		or die "cannot open $1 or $ibase/$1: $!\n";
+	next;
+    };
+
+    /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
+	and $_ = "\n=head2 $1\n";
+    /^\@subsection\s+(.+)$/
+	and $_ = "\n=head3 $1\n";
+
+    # Block command handlers:
+    /^\@itemize\s+(\@[a-z]+|\*|-)/ and do {
+	push @endwstack, $endw;
+	push @icstack, $ic;
+	$ic = $1;
+	$_ = "\n=over 4\n";
+	$endw = "itemize";
+    };
+
+    /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
+	push @endwstack, $endw;
+	push @icstack, $ic;
+	if (defined $1) {
+	    $ic = $1 . ".";
+	} else {
+	    $ic = "1.";
+	}
+	$_ = "\n=over 4\n";
+	$endw = "enumerate";
+    };
+
+    /^\@([fv]?table)\s+(\@[a-z]+)/ and do {
+	push @endwstack, $endw;
+	push @icstack, $ic;
+	$endw = $1;
+	$ic = $2;
+	$ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
+	$ic =~ s/\@(?:code|kbd)/C/;
+	$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
+	$ic =~ s/\@(?:file)/F/;
+	$_ = "\n=over 4\n";
+    };
+
+    /^\@((?:small)?example|display)/ and do {
+	push @endwstack, $endw;
+	$endw = $1;
+	$shift = "\t";
+	$_ = "";	# need a paragraph break
+    };
+
+    /^\@itemx?\s*(.+)?$/ and do {
+	if (defined $1) {
+	    # Entity escapes prevent munging by the <> processing below.
+	    $_ = "\n=item $ic\&LT;$1\&GT;\n";
+	} else {
+	    $_ = "\n=item $ic\n";
+	    $ic =~ y/A-Ya-y/B-Zb-z/;
+	    $ic =~ s/(\d+)/$1 + 1/eg;
+	}
+    };
+
+    $section .= $shift.$_."\n";
+}
+# End of current file.
+close($inf);
+$inf = pop @instack;
+}
+
+die "No filename or title\n" unless defined $fn && defined $tl;
+
+$sects{NAME} = "$fn \- $tl\n";
+$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
+
+for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
+	      BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
+    if(exists $sects{$sect}) {
+	$head = $sect;
+	$head =~ s/SEEALSO/SEE ALSO/;
+	print "=head1 $head\n\n";
+	print scalar unmunge ($sects{$sect});
+	print "\n";
+    }
+}
+
+sub usage
+{
+    die "usage: $0 [-D toggle...] [infile [outfile]]\n";
+}
+
+sub postprocess
+{
+    local $_ = $_[0];
+
+    # @value{foo} is replaced by whatever 'foo' is defined as.
+    while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
+	if (! exists $defs{$2}) {
+	    print STDERR "Option $2 not defined\n";
+	    s/\Q$1\E//;
+	} else {
+	    $value = $defs{$2};
+	    s/\Q$1\E/$value/;
+	}
+    }
+
+    # Formatting commands.
+    # Temporary escape for @r.
+    s/\@r\{([^\}]*)\}/R<$1>/g;
+    s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
+    s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
+    s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
+    s/\@sc\{([^\}]*)\}/\U$1/g;
+    s/\@file\{([^\}]*)\}/F<$1>/g;
+    s/\@w\{([^\}]*)\}/S<$1>/g;
+    s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
+
+    # Cross references are thrown away, as are @noindent and @refill.
+    # (@noindent is impossible in .pod, and @refill is unnecessary.)
+    # @* is also impossible in .pod; we discard it and any newline that
+    # follows it.  Similarly, our macro @gol must be discarded.
+
+    s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
+    s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
+    s/;\s+\@pxref\{(?:[^\}]*)\}//g;
+    s/\@noindent\s*//g;
+    s/\@refill//g;
+    s/\@gol//g;
+    s/\@\*\s*\n?//g;
+
+    # @uref can take one, two, or three arguments, with different
+    # semantics each time.  @url and @email are just like @uref with
+    # one argument, for our purposes.
+    s/\@(?:uref|url|email)\{([^\},]*)\}/&lt;B<$1>&gt;/g;
+    s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
+    s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
+
+    # Turn B<blah I<blah> blah> into B<blah> I<blah> B<blah> to
+    # match Texinfo semantics of @emph inside @samp.  Also handle @r
+    # inside bold.
+    s/&LT;/</g;
+    s/&GT;/>/g;
+    1 while s/B<((?:[^<>]|I<[^<>]*>)*)R<([^>]*)>/B<$1>${2}B</g;
+    1 while (s/B<([^<>]*)I<([^>]+)>/B<$1>I<$2>B</g);
+    1 while (s/I<([^<>]*)B<([^>]+)>/I<$1>B<$2>I</g);
+    s/[BI]<>//g;
+    s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
+    s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
+
+    # Extract footnotes.  This has to be done after all other
+    # processing because otherwise the regexp will choke on formatting
+    # inside @footnote.
+    while (/\@footnote/g) {
+	s/\@footnote\{([^\}]+)\}/[$fnno]/;
+	add_footnote($1, $fnno);
+	$fnno++;
+    }
+
+    return $_;
+}
+
+sub unmunge
+{
+    # Replace escaped symbols with their equivalents.
+    local $_ = $_[0];
+
+    s/&lt;/E<lt>/g;
+    s/&gt;/E<gt>/g;
+    s/&lbrace;/\{/g;
+    s/&rbrace;/\}/g;
+    s/&at;/\@/g;
+    s/&amp;/&/g;
+    return $_;
+}
+
+sub add_footnote
+{
+    unless (exists $sects{FOOTNOTES}) {
+	$sects{FOOTNOTES} = "\n=over 4\n\n";
+    }
+
+    $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
+    $sects{FOOTNOTES} .= $_[0];
+    $sects{FOOTNOTES} .= "\n\n";
+}
+
+# stolen from Symbol.pm
+{
+    my $genseq = 0;
+    sub gensym
+    {
+	my $name = "GEN" . $genseq++;
+	my $ref = \*{$name};
+	delete $::{$name};
+	return $ref;
+    }
+}
diff --git a/tinyc/win32/build-tcc.bat b/tinyc/win32/build-tcc.bat
new file mode 100644
index 000000000..9d3866c16
--- /dev/null
+++ b/tinyc/win32/build-tcc.bat
@@ -0,0 +1,28 @@
+@rem ----------------------------------------------------

+@rem batch file to build tcc using gcc and ar from mingw

+@rem ----------------------------------------------------

+:

+@echo>..\config.h #define TCC_VERSION "0.9.25"

+@echo>>..\config.h #define TCC_TARGET_PE 1

+@echo>>..\config.h #define CONFIG_TCCDIR "."

+@echo>>..\config.h #define CONFIG_SYSROOT ""

+:

+gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s

+gcc -Os -fno-strict-aliasing ../libtcc.c -c -o libtcc.o

+gcc -Os tools/tiny_impdef.c -o tiny_impdef.exe -s

+gcc -Os tools/tiny_libmaker.c -o tiny_libmaker.exe -s

+mkdir libtcc

+ar rcs libtcc/libtcc.a libtcc.o

+del libtcc.o

+copy ..\libtcc.h libtcc

+:

+.\tcc -c lib/crt1.c

+.\tcc -c lib/wincrt1.c

+.\tcc -c lib/dllcrt1.c

+.\tcc -c lib/dllmain.c

+.\tcc -c lib/chkstk.S

+.\tcc -c ../lib/libtcc1.c

+.\tcc -c ../lib/alloca86.S

+.\tcc -c ../lib/alloca86-bt.S

+ar rcs lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86.o alloca86-bt.o

+rem del *.o

diff --git a/tinyc/win32/examples/dll.c b/tinyc/win32/examples/dll.c
new file mode 100644
index 000000000..4202e99ca
--- /dev/null
+++ b/tinyc/win32/examples/dll.c
@@ -0,0 +1,15 @@
+//+---------------------------------------------------------------------------
+//
+//  dll.c - Windows DLL example - dynamically linked part
+//
+
+#include <windows.h>
+
+#define DLL_EXPORT __declspec(dllexport)
+
+
+DLL_EXPORT void HelloWorld (void)
+{
+	MessageBox (0, "Hello World!", "From DLL", MB_ICONINFORMATION);
+}
+
diff --git a/tinyc/win32/examples/fib.c b/tinyc/win32/examples/fib.c
new file mode 100644
index 000000000..6a4bdf5c4
--- /dev/null
+++ b/tinyc/win32/examples/fib.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <math.h>
+
+int fib(int n)
+{
+	if (n <= 2)
+		return 1;
+	else
+		return fib(n-1) + fib(n-2);
+}
+
+int main(int argc, char **argv) 
+{
+	int n;
+	if (argc < 2) {
+		printf("usage: fib n\n"
+			   "Compute nth Fibonacci number\n");
+		return 1;
+	}
+		
+	n = atoi(argv[1]);
+	printf("fib(%d) = %d\n", n, fib(n));
+	return 0;
+}
diff --git a/tinyc/win32/examples/hello_dll.c b/tinyc/win32/examples/hello_dll.c
new file mode 100644
index 000000000..7adba77ec
--- /dev/null
+++ b/tinyc/win32/examples/hello_dll.c
@@ -0,0 +1,19 @@
+//+---------------------------------------------------------------------------
+//
+//  HELLO_DLL.C - Windows DLL example - main application part
+//
+
+#include <windows.h>
+
+void HelloWorld (void);
+
+int WINAPI WinMain(
+	HINSTANCE hInstance,
+	HINSTANCE hPrevInstance,
+	LPSTR     lpCmdLine,
+	int       nCmdShow)
+{
+	HelloWorld();
+	return 0;
+}
+
diff --git a/tinyc/win32/examples/hello_win.c b/tinyc/win32/examples/hello_win.c
new file mode 100644
index 000000000..294b7279a
--- /dev/null
+++ b/tinyc/win32/examples/hello_win.c
@@ -0,0 +1,159 @@
+//+---------------------------------------------------------------------------
+//
+//  HELLO_WIN.C - Windows GUI 'Hello World!' Example
+//
+//+---------------------------------------------------------------------------
+
+#include <windows.h>
+
+#define APPNAME "HELLO_WIN"
+
+char szAppName[] = APPNAME; // The name of this application
+char szTitle[]   = APPNAME; // The title bar text
+char *pWindowText;
+
+HINSTANCE g_hInst;          // current instance
+
+void CenterWindow(HWND hWnd);
+
+//+---------------------------------------------------------------------------
+//
+//  Function:   WndProc
+//
+//  Synopsis:   very unusual type of function - gets called by system to
+//              process windows messages.
+//
+//  Arguments:  same as always.
+//----------------------------------------------------------------------------
+
+LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+	switch (message)
+	{
+		// ----------------------- first and last
+		case WM_CREATE:
+			CenterWindow(hwnd);
+			break;
+
+		case WM_DESTROY:
+			PostQuitMessage(0);
+			break;
+
+
+		// ----------------------- get out of it...
+		case WM_RBUTTONUP:
+			DestroyWindow(hwnd);
+			break;
+
+		case WM_KEYDOWN:
+			if (VK_ESCAPE == wParam)
+				DestroyWindow(hwnd);
+			break;
+
+
+		// ----------------------- display our minimal info
+		case WM_PAINT:
+		{
+			PAINTSTRUCT ps;
+			HDC         hdc;
+			RECT        rc;
+			hdc = BeginPaint(hwnd, &ps);
+
+			GetClientRect(hwnd, &rc);
+			SetTextColor(hdc, RGB(240,240,96));
+			SetBkMode(hdc, TRANSPARENT);
+			DrawText(hdc, pWindowText, -1, &rc, DT_CENTER|DT_SINGLELINE|DT_VCENTER);
+
+			EndPaint(hwnd, &ps);
+			break;
+		}
+
+		// ----------------------- let windows do all other stuff
+		default:
+			return DefWindowProc(hwnd, message, wParam, lParam);
+	}
+	return 0;
+}
+
+//+---------------------------------------------------------------------------
+//
+//  Function:   WinMain
+//
+//  Synopsis:   standard entrypoint for GUI Win32 apps
+//
+//----------------------------------------------------------------------------
+int APIENTRY WinMain(
+				HINSTANCE hInstance,
+				HINSTANCE hPrevInstance,
+				LPSTR     lpCmdLine,
+				int       nCmdShow)
+{
+	MSG msg;
+
+	WNDCLASS wc;
+
+	HWND hwnd;
+
+	// Fill in window class structure with parameters that describe
+	// the main window.
+
+	ZeroMemory(&wc, sizeof wc);
+	wc.hInstance     = hInstance;
+	wc.lpszClassName = szAppName;
+	wc.lpfnWndProc   = (WNDPROC)WndProc;
+	wc.style         = CS_DBLCLKS|CS_VREDRAW|CS_HREDRAW;
+	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+	wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
+	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
+
+	if (FALSE == RegisterClass(&wc)) return 0;
+
+	// create the browser
+	hwnd = CreateWindow(
+		szAppName,
+		szTitle,
+		WS_OVERLAPPEDWINDOW|WS_VISIBLE,
+		CW_USEDEFAULT,
+		CW_USEDEFAULT,
+		360,//CW_USEDEFAULT,
+		240,//CW_USEDEFAULT,
+		0,
+		0,
+		g_hInst,
+		0);
+
+	if (NULL == hwnd) return 0;
+
+	pWindowText = lpCmdLine[0] ? lpCmdLine : "Hello Windows!";
+
+	// Main message loop:
+	while (GetMessage(&msg, NULL, 0, 0) > 0)
+	{
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+
+	return msg.wParam;
+}
+
+//+---------------------------------------------------------------------------
+
+//+---------------------------------------------------------------------------
+
+void CenterWindow(HWND hwnd_self)
+{
+	RECT rw_self, rc_parent, rw_parent; HWND hwnd_parent;
+	hwnd_parent = GetParent(hwnd_self);
+	if (NULL==hwnd_parent) hwnd_parent = GetDesktopWindow();
+	GetWindowRect(hwnd_parent, &rw_parent);
+	GetClientRect(hwnd_parent, &rc_parent);
+	GetWindowRect(hwnd_self, &rw_self);
+	SetWindowPos(hwnd_self, NULL,
+		rw_parent.left + (rc_parent.right + rw_self.left - rw_self.right) / 2,
+		rw_parent.top  + (rc_parent.bottom + rw_self.top - rw_self.bottom) / 2,
+		0, 0,
+		SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE
+		);
+}
+
+//+---------------------------------------------------------------------------
diff --git a/tinyc/win32/include/_mingw.h b/tinyc/win32/include/_mingw.h
new file mode 100644
index 000000000..257c52376
--- /dev/null
+++ b/tinyc/win32/include/_mingw.h
@@ -0,0 +1,54 @@
+/*
+ * _mingw.h
+ *
+ *  This file is for TCC-PE and not part of the Mingw32 package.
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __MINGW_H
+#define __MINGW_H
+
+#include <stddef.h>
+
+#define __int64 long long
+#define __int32 long
+#define __int16 short
+#define __int8 char
+#define __cdecl __attribute__((__cdecl__))
+#define __stdcall __attribute__((__stdcall__))
+#define __declspec(x) __attribute__((x))
+
+#define __MINGW32_VERSION 2.0
+#define __MINGW32_MAJOR_VERSION 2
+#define __MINGW32_MINOR_VERSION 0
+
+#define __MSVCRT__ 1
+#define __MINGW_IMPORT extern
+#define _CRTIMP
+#define __CRT_INLINE extern __inline__
+
+#define WIN32 1
+
+#ifndef _WINT_T
+#define _WINT_T
+typedef unsigned int wint_t;
+#endif
+
+/* for winapi */
+#define _ANONYMOUS_UNION
+#define _ANONYMOUS_STRUCT
+#define DECLSPEC_NORETURN
+#define WIN32_LEAN_AND_MEAN
+#define DECLARE_STDCALL_P(type) __stdcall type
+
+#endif /* __MINGW_H */
diff --git a/tinyc/win32/include/assert.h b/tinyc/win32/include/assert.h
new file mode 100644
index 000000000..959c80351
--- /dev/null
+++ b/tinyc/win32/include/assert.h
@@ -0,0 +1,71 @@
+/* 
+ * assert.h
+ *
+ * Define the assert macro for debug output.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _ASSERT_H_
+#define	_ASSERT_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#ifndef RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef NDEBUG
+
+/*
+ * If not debugging, assert does nothing.
+ */
+#define assert(x)	((void)0)
+
+#else /* debugging enabled */
+
+/*
+ * CRTDLL nicely supplies a function which does the actual output and
+ * call to abort.
+ */
+void	_assert (const char*, const char*, int)
+#ifdef	__GNUC__
+	__attribute__ ((noreturn))
+#endif
+	;
+
+/*
+ * Definition of the assert macro.
+ */
+#define assert(e)       ((e) ? (void)0 : _assert(#e, __FILE__, __LINE__))
+#endif	/* NDEBUG */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* Not RC_INVOKED */
+
+#endif /* Not _ASSERT_H_ */
+
diff --git a/tinyc/win32/include/conio.h b/tinyc/win32/include/conio.h
new file mode 100644
index 000000000..c1f4151df
--- /dev/null
+++ b/tinyc/win32/include/conio.h
@@ -0,0 +1,159 @@
+/* A conio implementation for Mingw/Dev-C++.
+ *
+ * Written by:
+ * Hongli Lai <hongli@telekabel.nl>
+ * tkorrovi <tkorrovi@altavista.net> on 2002/02/26. 
+ * Andrew Westcott <ajwestco@users.sourceforge.net>
+ *
+ * Offered for use in the public domain without any warranty.
+ */
+
+#ifndef _CONIO_H_
+#define _CONIO_H_
+
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLINK 0
+
+typedef enum
+{
+    BLACK,
+    BLUE,
+    GREEN,
+    CYAN,
+    RED,
+    MAGENTA,
+    BROWN,
+    LIGHTGRAY,
+    DARKGRAY,
+    LIGHTBLUE,
+    LIGHTGREEN,
+    LIGHTCYAN,
+    LIGHTRED,
+    LIGHTMAGENTA,
+    YELLOW,
+    WHITE
+} COLORS;
+
+
+#define cgets	_cgets
+#define cprintf	_cprintf
+#define cputs	_cputs
+#define cscanf	_cscanf
+#define ScreenClear clrscr
+
+/* blinkvideo */
+
+void clreol (void);
+void clrscr (void);
+
+int _conio_gettext (int left, int top, int right, int bottom,
+                    char *str);
+/* _conio_kbhit */
+
+void delline (void);
+
+/* gettextinfo */
+void gotoxy(int x, int y);
+/*
+highvideo
+insline
+intensevideo
+lowvideo
+movetext
+normvideo
+*/
+
+void puttext (int left, int top, int right, int bottom, char *str);
+
+// Screen Variables
+
+/* ScreenCols
+ScreenGetChar
+ScreenGetCursor
+ScreenMode
+ScreenPutChar
+ScreenPutString
+ScreenRetrieve
+ScreenRows
+ScreenSetCursor
+ScreenUpdate
+ScreenUpdateLine
+ScreenVisualBell
+_set_screen_lines */
+
+void _setcursortype (int type);
+
+void textattr (int _attr);
+
+void textbackground (int color);
+
+void textcolor (int color);
+
+/* textmode */
+
+int wherex (void);
+
+int wherey (void);
+
+/* window */
+
+
+
+/*  The code below was part of Mingw's conio.h  */
+/*
+ * conio.h
+ *
+ * Low level console I/O functions. Pretty please try to use the ANSI
+ * standard ones if you are writing new code.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+char*	_cgets (char*);
+int	_cprintf (const char*, ...);
+int	_cputs (const char*);
+int	_cscanf (char*, ...);
+
+int	_getch (void);
+int	_getche (void);
+int	_kbhit (void);
+int	_putch (int);
+int	_ungetch (int);
+
+
+int	getch (void);
+int	getche (void);
+int	kbhit (void);
+int	putch (int);
+int	ungetch (int);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONIO_H_ */
diff --git a/tinyc/win32/include/ctype.h b/tinyc/win32/include/ctype.h
new file mode 100644
index 000000000..0c416a6e1
--- /dev/null
+++ b/tinyc/win32/include/ctype.h
@@ -0,0 +1,232 @@
+/* 
+ * ctype.h
+ *
+ * Functions for testing character types and converting characters.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _CTYPE_H_
+#define _CTYPE_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define	__need_wchar_t
+#define	__need_wint_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+
+/*
+ * The following flags are used to tell iswctype and _isctype what character
+ * types you are looking for.
+ */
+#define	_UPPER		0x0001
+#define	_LOWER		0x0002
+#define	_DIGIT		0x0004
+#define	_SPACE		0x0008 /* HT  LF  VT  FF  CR  SP */
+#define	_PUNCT		0x0010
+#define	_CONTROL	0x0020
+#define	_BLANK		0x0040 /* this is SP only, not SP and HT as in C99  */
+#define	_HEX		0x0080
+#define	_LEADBYTE	0x8000
+
+#define	_ALPHA		0x0103
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int	isalnum(int);
+int	isalpha(int);
+int	iscntrl(int);
+int	isdigit(int);
+int	isgraph(int);
+int	islower(int);
+int	isprint(int);
+int	ispunct(int);
+int	isspace(int);
+int	isupper(int);
+int	isxdigit(int);
+
+#ifndef __STRICT_ANSI__
+int	_isctype (int, int);
+#endif
+
+/* These are the ANSI versions, with correct checking of argument */
+int	tolower(int);
+int	toupper(int);
+
+/*
+ * NOTE: The above are not old name type wrappers, but functions exported
+ * explicitly by MSVCRT/CRTDLL. However, underscored versions are also
+ * exported.
+ */
+#ifndef	__STRICT_ANSI__
+/*
+ *  These are the cheap non-std versions: The return values are undefined
+ *  if the argument is not ASCII char or is not of appropriate case
+ */ 
+int	_tolower(int);
+int	_toupper(int);
+#endif
+
+/* Also defined in stdlib.h */
+#ifndef MB_CUR_MAX
+# ifdef __MSVCRT__
+#  define MB_CUR_MAX __mb_cur_max
+   __MINGW_IMPORT int __mb_cur_max;
+# else /* not __MSVCRT */
+#  define MB_CUR_MAX __mb_cur_max_dll
+   __MINGW_IMPORT int __mb_cur_max_dll;
+# endif /* not __MSVCRT */
+#endif  /* MB_CUR_MAX */
+
+__MINGW_IMPORT unsigned short _ctype[];
+#ifdef __MSVCRT__
+__MINGW_IMPORT unsigned short* _pctype;
+#else /* CRTDLL */
+__MINGW_IMPORT unsigned short* _pctype_dll;
+#define  _pctype _pctype_dll
+#endif
+
+/*
+ * Use inlines here rather than macros, because macros will upset 
+ * C++ usage (eg, ::isalnum), and so usually get undefined
+ *
+ * According to standard for SB chars, these function are defined only
+ * for input values representable by unsigned char or EOF.
+ * Thus, there is no range test.
+ * This reproduces behaviour of MSVCRT.dll lib implemention for SB chars.
+ *
+ * If no MB char support is needed, these can be simplified even
+ * more by command line define -DMB_CUR_MAX=1.  The compiler will then
+ * optimise away the constant condition.			
+ */
+
+
+#if ! (defined (__NO_CTYPE_INLINES) || defined (__STRICT_ANSI__ ))
+/* use  simple lookup if SB locale, else  _isctype()  */
+#define __ISCTYPE(c, mask)  (MB_CUR_MAX == 1 ? (_pctype[c] & mask) : _isctype(c, mask))
+extern __inline__ int isalnum(int c) {return __ISCTYPE(c, (_ALPHA|_DIGIT));}
+extern __inline__ int isalpha(int c) {return __ISCTYPE(c, _ALPHA);}
+extern __inline__ int iscntrl(int c) {return __ISCTYPE(c, _CONTROL);}
+extern __inline__ int isdigit(int c) {return __ISCTYPE(c, _DIGIT);}
+extern __inline__ int isgraph(int c) {return __ISCTYPE(c, (_PUNCT|_ALPHA|_DIGIT));}
+extern __inline__ int islower(int c) {return __ISCTYPE(c, _LOWER);}
+extern __inline__ int isprint(int c) {return __ISCTYPE(c, (_BLANK|_PUNCT|_ALPHA|_DIGIT));}
+extern __inline__ int ispunct(int c) {return __ISCTYPE(c, _PUNCT);}
+extern __inline__ int isspace(int c) {return __ISCTYPE(c, _SPACE);}
+extern __inline__ int isupper(int c) {return __ISCTYPE(c, _UPPER);}
+extern __inline__ int isxdigit(int c) {return __ISCTYPE(c, _HEX);}
+
+/* these reproduce behaviour of lib underscored versions  */
+extern __inline__ int _tolower(int c) {return ( c -'A'+'a');}
+extern __inline__ int _toupper(int c) {return ( c -'a'+'A');}
+
+/* TODO? Is it worth inlining ANSI tolower, toupper? Probably only
+   if we only want C-locale. */
+
+#endif /* _NO_CTYPE_INLINES */
+
+/* Wide character equivalents */
+
+#ifndef WEOF
+#define	WEOF	(wchar_t)(0xFFFF)
+#endif
+
+#ifndef _WCTYPE_T_DEFINED
+typedef wchar_t wctype_t;
+#define _WCTYPE_T_DEFINED
+#endif
+
+int	iswalnum(wint_t);
+int	iswalpha(wint_t);
+int	iswascii(wint_t);
+int	iswcntrl(wint_t);
+int	iswctype(wint_t, wctype_t);
+int	is_wctype(wint_t, wctype_t);	/* Obsolete! */
+int	iswdigit(wint_t);
+int	iswgraph(wint_t);
+int	iswlower(wint_t);
+int	iswprint(wint_t);
+int	iswpunct(wint_t);
+int	iswspace(wint_t);
+int	iswupper(wint_t);
+int	iswxdigit(wint_t);
+
+wchar_t	towlower(wchar_t);
+wchar_t	towupper(wchar_t);
+
+int	isleadbyte (int);
+
+/* Also in wctype.h */
+#if ! (defined(__NO_CTYPE_INLINES) || defined(__WCTYPE_INLINES_DEFINED))
+#define __WCTYPE_INLINES_DEFINED
+extern __inline__ int iswalnum(wint_t wc) {return (iswctype(wc,_ALPHA|_DIGIT));}
+extern __inline__ int iswalpha(wint_t wc) {return (iswctype(wc,_ALPHA));}
+extern __inline__ int iswascii(wint_t wc) {return (((unsigned)wc & 0x7F) ==0);}
+extern __inline__ int iswcntrl(wint_t wc) {return (iswctype(wc,_CONTROL));}
+extern __inline__ int iswdigit(wint_t wc) {return (iswctype(wc,_DIGIT));}
+extern __inline__ int iswgraph(wint_t wc) {return (iswctype(wc,_PUNCT|_ALPHA|_DIGIT));}
+extern __inline__ int iswlower(wint_t wc) {return (iswctype(wc,_LOWER));}
+extern __inline__ int iswprint(wint_t wc) {return (iswctype(wc,_BLANK|_PUNCT|_ALPHA|_DIGIT));}
+extern __inline__ int iswpunct(wint_t wc) {return (iswctype(wc,_PUNCT));}
+extern __inline__ int iswspace(wint_t wc) {return (iswctype(wc,_SPACE));}
+extern __inline__ int iswupper(wint_t wc) {return (iswctype(wc,_UPPER));}
+extern __inline__ int iswxdigit(wint_t wc) {return (iswctype(wc,_HEX));}
+extern __inline__ int isleadbyte(int c) {return (_pctype[(unsigned char)(c)] & _LEADBYTE);}
+#endif /* !(defined(__NO_CTYPE_INLINES) || defined(__WCTYPE_INLINES_DEFINED)) */
+
+#ifndef	__STRICT_ANSI__
+int	__isascii (int);
+int	__toascii (int);
+int	__iscsymf (int);	/* Valid first character in C symbol */
+int	__iscsym (int);		/* Valid character in C symbol (after first) */
+
+#ifndef __NO_CTYPE_INLINES
+extern __inline__ int __isascii(int c) {return (((unsigned)c & ~0x7F) == 0);} 
+extern __inline__ int __toascii(int c) {return (c & 0x7F);}
+extern __inline__ int __iscsymf(int c) {return (isalpha(c) || (c == '_'));}
+extern __inline__ int __iscsym(int c)  {return  (isalnum(c) || (c == '_'));}
+#endif /* __NO_CTYPE_INLINES */
+
+#ifndef	_NO_OLDNAMES
+int	isascii (int);
+int	toascii (int);
+int	iscsymf (int);
+int	iscsym (int);
+#endif	/* Not _NO_OLDNAMES */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _CTYPE_H_ */
+
diff --git a/tinyc/win32/include/dir.h b/tinyc/win32/include/dir.h
new file mode 100644
index 000000000..d759a0a61
--- /dev/null
+++ b/tinyc/win32/include/dir.h
@@ -0,0 +1,26 @@
+/* 
+ * dir.h
+ *
+ * This file OBSOLESCENT and only provided for backward compatibility.
+ * Please use io.h instead.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *             Mumit Khan <khan@xraylith.wisc.edu>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <io.h>
+
diff --git a/tinyc/win32/include/direct.h b/tinyc/win32/include/direct.h
new file mode 100644
index 000000000..925f4c54c
--- /dev/null
+++ b/tinyc/win32/include/direct.h
@@ -0,0 +1,95 @@
+/*
+ * direct.h
+ *
+ * Functions for manipulating paths and directories (included from io.h)
+ * plus functions for setting the current drive.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef __STRICT_ANSI__
+
+#ifndef	_DIRECT_H_
+#define	_DIRECT_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_wchar_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+#include <io.h>
+
+#ifndef RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifndef _DISKFREE_T_DEFINED
+/* needed by _getdiskfree (also in dos.h) */
+struct _diskfree_t {
+	unsigned total_clusters;
+	unsigned avail_clusters;
+	unsigned sectors_per_cluster;
+	unsigned bytes_per_sector;
+};
+#define _DISKFREE_T_DEFINED
+#endif  
+
+/*
+ * You really shouldn't be using these. Use the Win32 API functions instead.
+ * However, it does make it easier to port older code.
+ */
+int	_getdrive (void);
+unsigned long _getdrives(void);
+int	_chdrive (int);
+char*	_getdcwd (int, char*, int);
+unsigned _getdiskfree (unsigned, struct _diskfree_t *);
+
+#ifndef	_NO_OLDNAMES
+# define diskfree_t _diskfree_t
+#endif
+
+#ifndef _WDIRECT_DEFINED
+/* wide character versions. Also in wchar.h */
+#ifdef __MSVCRT__ 
+int _wchdir(const wchar_t*);
+wchar_t* _wgetcwd(wchar_t*, int);
+wchar_t* _wgetdcwd(int, wchar_t*, int);
+int _wmkdir(const wchar_t*);
+int _wrmdir(const wchar_t*);
+#endif	/* __MSVCRT__ */
+#define _WDIRECT_DEFINED
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _DIRECT_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/dirent.h b/tinyc/win32/include/dirent.h
new file mode 100644
index 000000000..41c3dd715
--- /dev/null
+++ b/tinyc/win32/include/dirent.h
@@ -0,0 +1,96 @@
+/*
+ * DIRENT.H (formerly DIRLIB.H)
+ *
+ * by M. J. Weinstein   Released to public domain 1-Jan-89
+ *
+ * Because I have heard that this feature (opendir, readdir, closedir)
+ * it so useful for programmers coming from UNIX or attempting to port
+ * UNIX code, and because it is reasonably light weight, I have included
+ * it in the Mingw32 package. I have also added an implementation of
+ * rewinddir, seekdir and telldir.
+ *   - Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  This code is distributed in the hope that is will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includeds but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef _DIRENT_H_
+#define _DIRENT_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#include <io.h>
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dirent
+{
+	long		d_ino;		/* Always zero. */
+	unsigned short	d_reclen;	/* Always zero. */
+	unsigned short	d_namlen;	/* Length of name in d_name. */
+	char*		d_name;		/* File name. */
+	/* NOTE: The name in the dirent structure points to the name in the
+	 *       finddata_t structure in the DIR. */
+};
+
+/*
+ * This is an internal data structure. Good programmers will not use it
+ * except as an argument to one of the functions below.
+ */
+typedef struct
+{
+	/* disk transfer area for this dir */
+	struct _finddata_t	dd_dta;
+
+	/* dirent struct to return from dir (NOTE: this makes this thread
+	 * safe as long as only one thread uses a particular DIR struct at
+	 * a time) */
+	struct dirent		dd_dir;
+
+	/* _findnext handle */
+	long			dd_handle;
+
+	/*
+         * Status of search:
+	 *   0 = not started yet (next entry to read is first entry)
+	 *  -1 = off the end
+	 *   positive = 0 based index of next entry
+	 */
+	short			dd_stat;
+
+	/* given path for dir with search pattern (struct is extended) */
+	char			dd_name[1];
+} DIR;
+
+
+DIR*		opendir (const char*);
+struct dirent*	readdir (DIR*);
+int		closedir (DIR*);
+void		rewinddir (DIR*);
+long		telldir (DIR*);
+void		seekdir (DIR*, long);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _DIRENT_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/dos.h b/tinyc/win32/include/dos.h
new file mode 100644
index 000000000..2cb380fba
--- /dev/null
+++ b/tinyc/win32/include/dos.h
@@ -0,0 +1,110 @@
+/*
+ * dos.h
+ *
+ * DOS-specific functions and structures.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by J.J. van der Heijden <J.J.vanderHeijden@student.utwente.nl>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_DOS_H_
+#define	_DOS_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_wchar_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+/* For DOS file attributes */
+#include <io.h>
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __MSVCRT__ /* these are in CRTDLL, but not MSVCRT */
+#ifndef __DECLSPEC_SUPPORTED
+extern unsigned int *__imp__basemajor_dll;
+extern unsigned int *__imp__baseminor_dll;
+extern unsigned int *__imp__baseversion_dll;
+extern unsigned int *__imp__osmajor_dll;
+extern unsigned int *__imp__osminor_dll;
+extern unsigned int *__imp__osmode_dll;
+
+#define _basemajor (*__imp__basemajor_dll)
+#define _baseminor (*__imp__baseminor_dll)
+#define _baseversion (*__imp__baseversion_dll)
+#define _osmajor (*__imp__osmajor_dll)
+#define _osminor (*__imp__osminor_dll)
+#define _osmode (*__imp__osmode_dll)
+
+#else /* __DECLSPEC_SUPPORTED */
+
+__MINGW_IMPORT unsigned int _basemajor_dll;
+__MINGW_IMPORT unsigned int _baseminor_dll;
+__MINGW_IMPORT unsigned int _baseversion_dll;
+__MINGW_IMPORT unsigned int _osmajor_dll;
+__MINGW_IMPORT unsigned int _osminor_dll;
+__MINGW_IMPORT unsigned int _osmode_dll;
+
+#define _basemajor _basemajor_dll
+#define _baseminor _baseminor_dll
+#define _baseversion _baseversion_dll
+#define _osmajor _osmajor_dll
+#define _osminor _osminor_dll
+#define _osmode _osmode_dll
+
+#endif /* __DECLSPEC_SUPPORTED */
+#endif /* ! __MSVCRT__ */
+
+#ifndef _DISKFREE_T_DEFINED
+/* needed by _getdiskfree (also in direct.h) */
+struct _diskfree_t {
+	unsigned total_clusters;
+	unsigned avail_clusters;
+	unsigned sectors_per_cluster;
+	unsigned bytes_per_sector;
+};
+#define _DISKFREE_T_DEFINED
+#endif  
+
+unsigned _getdiskfree (unsigned, struct _diskfree_t *);
+
+#ifndef	_NO_OLDNAMES
+# define diskfree_t _diskfree_t
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _DOS_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/errno.h b/tinyc/win32/include/errno.h
new file mode 100644
index 000000000..b41a70e01
--- /dev/null
+++ b/tinyc/win32/include/errno.h
@@ -0,0 +1,117 @@
+/* 
+ * errno.h
+ *
+ * Error numbers and access to error reporting.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _ERRNO_H_
+#define	_ERRNO_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * Error numbers.
+ * TODO: Can't be sure of some of these assignments, I guessed from the
+ * names given by strerror and the defines in the Cygnus errno.h. A lot
+ * of the names from the Cygnus errno.h are not represented, and a few
+ * of the descriptions returned by strerror do not obviously match
+ * their error naming.
+ */
+#define EPERM		1	/* Operation not permitted */
+#define	ENOFILE		2	/* No such file or directory */
+#define	ENOENT		2
+#define	ESRCH		3	/* No such process */
+#define	EINTR		4	/* Interrupted function call */
+#define	EIO		5	/* Input/output error */
+#define	ENXIO		6	/* No such device or address */
+#define	E2BIG		7	/* Arg list too long */
+#define	ENOEXEC		8	/* Exec format error */
+#define	EBADF		9	/* Bad file descriptor */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Resource temporarily unavailable */
+#define	ENOMEM		12	/* Not enough space */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+/* 15 - Unknown Error */
+#define	EBUSY		16	/* strerror reports "Resource device" */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Improper link (cross-device link?) */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* Too many open files in system */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Inappropriate I/O control operation */
+/* 26 - Unknown Error */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Invalid seek (seek on a pipe?) */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Domain error (math functions) */
+#define	ERANGE		34	/* Result too large (possibly too small) */
+/* 35 - Unknown Error */
+#define	EDEADLOCK	36	/* Resource deadlock avoided (non-Cyg) */
+#define	EDEADLK		36
+/* 37 - Unknown Error */
+#define	ENAMETOOLONG	38	/* Filename too long (91 in Cyg?) */
+#define	ENOLCK		39	/* No locks available (46 in Cyg?) */
+#define	ENOSYS		40	/* Function not implemented (88 in Cyg?) */
+#define	ENOTEMPTY	41	/* Directory not empty (90 in Cyg?) */
+#define	EILSEQ		42	/* Illegal byte sequence */
+
+/*
+ * NOTE: ENAMETOOLONG and ENOTEMPTY conflict with definitions in the
+ *       sockets.h header provided with windows32api-0.1.2.
+ *       You should go and put an #if 0 ... #endif around the whole block
+ *       of errors (look at the comment above them).
+ */
+
+#ifndef	RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Definitions of errno. For _doserrno, sys_nerr and * sys_errlist, see
+ * stdlib.h.
+ */
+#ifdef _UWIN
+#undef errno
+extern int errno;
+#else
+int*	_errno(void);
+#define	errno		(*_errno())
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _ERRNO_H_ */
diff --git a/tinyc/win32/include/excpt.h b/tinyc/win32/include/excpt.h
new file mode 100644
index 000000000..774612458
--- /dev/null
+++ b/tinyc/win32/include/excpt.h
@@ -0,0 +1,20 @@
+#ifndef _EXCPT_H
+#define _EXCPT_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+/* FIXME: This will make some code compile. The programs will most
+   likely crash when an exception is raised, but at least they will
+   compile. */
+#ifdef __GNUC__
+#define __try
+#define __except(x) if (0) /* don't execute handler */
+#define __finally
+
+#define _try __try
+#define _except __except
+#define _finally __finally
+#endif
+
+#endif
diff --git a/tinyc/win32/include/fcntl.h b/tinyc/win32/include/fcntl.h
new file mode 100644
index 000000000..d31bc84d5
--- /dev/null
+++ b/tinyc/win32/include/fcntl.h
@@ -0,0 +1,135 @@
+/*
+ * fcntl.h
+ *
+ * Access constants for _open. Note that the permissions constants are
+ * in sys/stat.h (ick).
+ *
+ * This code is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef __STRICT_ANSI__
+
+#ifndef _FCNTL_H_
+#define _FCNTL_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * It appears that fcntl.h should include io.h for compatibility...
+ */
+#include <io.h>
+
+/* Specifiy one of these flags to define the access mode. */
+#define	_O_RDONLY	0
+#define _O_WRONLY	1
+#define _O_RDWR		2
+
+/* Mask for access mode bits in the _open flags. */
+#define _O_ACCMODE	(_O_RDONLY|_O_WRONLY|_O_RDWR)
+
+#define	_O_APPEND	0x0008	/* Writes will add to the end of the file. */
+
+#define	_O_RANDOM	0x0010
+#define	_O_SEQUENTIAL	0x0020
+#define	_O_TEMPORARY	0x0040	/* Make the file disappear after closing.
+				 * WARNING: Even if not created by _open! */
+#define	_O_NOINHERIT	0x0080
+
+#define	_O_CREAT	0x0100	/* Create the file if it does not exist. */
+#define	_O_TRUNC	0x0200	/* Truncate the file if it does exist. */
+#define	_O_EXCL		0x0400	/* Open only if the file does not exist. */
+
+/* NOTE: Text is the default even if the given _O_TEXT bit is not on. */
+#define	_O_TEXT		0x4000	/* CR-LF in file becomes LF in memory. */
+#define	_O_BINARY	0x8000	/* Input and output is not translated. */
+#define	_O_RAW		_O_BINARY
+
+#ifndef	_NO_OLDNAMES
+
+/* POSIX/Non-ANSI names for increased portability */
+#define	O_RDONLY	_O_RDONLY
+#define O_WRONLY	_O_WRONLY
+#define O_RDWR		_O_RDWR
+#define O_ACCMODE	_O_ACCMODE
+#define	O_APPEND	_O_APPEND
+#define	O_CREAT		_O_CREAT
+#define	O_TRUNC		_O_TRUNC
+#define	O_EXCL		_O_EXCL
+#define	O_TEXT		_O_TEXT
+#define	O_BINARY	_O_BINARY
+#define	O_TEMPORARY	_O_TEMPORARY
+#define O_NOINHERIT	_O_NOINHERIT
+#define O_SEQENTIAL	_O_SEQUENTIAL
+#define	O_RANDOM	_O_RANDOM
+
+#endif	/* Not _NO_OLDNAMES */
+
+
+#ifndef RC_INVOKED
+
+/*
+ * This variable determines the default file mode.
+ * TODO: Which flags work?
+ */
+#ifndef __DECLSPEC_SUPPORTED
+
+#ifdef __MSVCRT__
+extern unsigned int* __imp__fmode;
+#define	_fmode	(*__imp__fmode)
+#else
+/* CRTDLL */
+extern unsigned int* __imp__fmode_dll;
+#define	_fmode	(*__imp__fmode_dll)
+#endif
+
+#else /* __DECLSPEC_SUPPORTED */
+
+#ifdef __MSVCRT__
+__MINGW_IMPORT unsigned int _fmode;
+#else /* ! __MSVCRT__ */
+__MINGW_IMPORT unsigned int _fmode_dll;
+#define	_fmode	_fmode_dll
+#endif /* ! __MSVCRT__ */
+
+#endif /* __DECLSPEC_SUPPORTED */
+
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int	_setmode (int, int);
+
+#ifndef	_NO_OLDNAMES
+int	setmode (int, int);
+#endif	/* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _FCNTL_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/fenv.h b/tinyc/win32/include/fenv.h
new file mode 100644
index 000000000..ddc43dfc8
--- /dev/null
+++ b/tinyc/win32/include/fenv.h
@@ -0,0 +1,85 @@
+#ifndef _FENV_H
+#define _FENV_H
+
+/*
+  For now, support only for the basic abstraction of flags that are
+  either set or clear. fexcept_t could be  structure that holds more info
+  about the fp environment.
+*/
+typedef unsigned short fexcept_t;
+
+/* This 28-byte struct represents the entire floating point
+   environment as stored by fnstenv or fstenv */
+typedef struct
+{
+  unsigned short __control_word;
+  unsigned short __unused0;
+  unsigned short __status_word;
+  unsigned short __unused1;
+  unsigned short __tag_word;
+  unsigned short __unused2;  
+  unsigned int	 __ip_offset;    /* instruction pointer offset */
+  unsigned short __ip_selector;  
+  unsigned short __opcode;
+  unsigned int	 __data_offset;
+  unsigned short __data_selector;  
+  unsigned short __unused3;
+} fenv_t;
+
+
+/* FPU status word exception flags */
+#define FE_INVALID	0x01
+#define FE_DENORMAL	0x02
+#define FE_DIVBYZERO	0x04
+#define FE_OVERFLOW	0x08
+#define FE_UNDERFLOW	0x10
+#define FE_INEXACT	0x20
+#define FE_ALL_EXCEPT (FE_INVALID | FE_DENORMAL | FE_DIVBYZERO \
+		       | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
+
+/* FPU control word rounding flags */
+#define FE_TONEAREST	0x0000
+#define FE_DOWNWARD	0x0400
+#define FE_UPWARD	0x0800
+#define FE_TOWARDZERO	0x0c00
+
+
+/* The default floating point environment */
+#define FE_DFL_ENV ((const fenv_t *)-1)
+
+
+#ifndef RC_INVOKED
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*TODO: Some of these could be inlined */
+/* 7.6.2 Exception */
+
+extern int feclearexcept (int);
+extern int fegetexceptflag (fexcept_t * flagp, int excepts);
+extern int feraiseexcept (int excepts );
+extern int fesetexceptflag (const fexcept_t *, int);
+extern int fetestexcept (int excepts);
+
+
+/* 7.6.3 Rounding */
+
+extern int fegetround (void);
+extern int fesetround (int mode);
+
+
+/* 7.6.4 Environment */
+
+extern int fegetenv (fenv_t * envp);
+extern int fesetenv (const fenv_t * );
+extern int feupdateenv (const fenv_t *);
+extern int feholdexcept (fenv_t *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif	/* Not RC_INVOKED */
+
+#endif /* ndef _FENV_H */
diff --git a/tinyc/win32/include/float.h b/tinyc/win32/include/float.h
new file mode 100644
index 000000000..a6fb6dbe0
--- /dev/null
+++ b/tinyc/win32/include/float.h
@@ -0,0 +1,224 @@
+/* 
+ * float.h
+ *
+ * Constants related to floating point arithmetic.
+ *
+ * Also included here are some non-ANSI bits for accessing the floating
+ * point controller.
+ *
+ * NOTE: GCC provides float.h, and it is probably more accurate than this,
+ *       but it doesn't include the non-standard stuff for accessing the
+ *       fp controller. (TODO: Move those bits elsewhere?) Thus it is
+ *       probably not a good idea to use the GCC supplied version instead
+ *       of this header.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define FLT_ROUNDS	1
+#define FLT_GUARD	1
+#define FLT_NORMALIZE	1
+
+/*
+ * The characteristics of float.
+ */
+
+/* The radix for floating point representation. */
+#define FLT_RADIX	2
+
+/* Decimal digits of precision. */
+#define FLT_DIG		6
+
+/* Smallest number such that 1+x != 1 */
+#define FLT_EPSILON	1.19209290e-07F
+
+/* The number of base FLT_RADIX digits in the mantissa. */
+#define FLT_MANT_DIG	24
+
+/* The maximum floating point number. */
+#define FLT_MAX		3.40282347e+38F
+
+/* Maximum n such that FLT_RADIX^n - 1 is representable. */
+#define FLT_MAX_EXP	128
+
+/* Maximum n such that 10^n is representable. */
+#define FLT_MAX_10_EXP	38
+
+/* Minimum normalized floating-point number. */
+#define FLT_MIN		1.17549435e-38F
+
+/* Minimum n such that FLT_RADIX^n is a normalized number. */
+#define FLT_MIN_EXP	(-125)
+
+/* Minimum n such that 10^n is a normalized number. */
+#define FLT_MIN_10_EXP	(-37)
+
+
+/*
+ * The characteristics of double.
+ */
+#define DBL_DIG		15
+#define DBL_EPSILON	1.1102230246251568e-16
+#define DBL_MANT_DIG	53
+#define DBL_MAX		1.7976931348623157e+308
+#define DBL_MAX_EXP	1024
+#define DBL_MAX_10_EXP	308
+#define DBL_MIN		2.2250738585072014e-308
+#define DBL_MIN_EXP	(-1021)
+#define DBL_MIN_10_EXP	(-307)
+
+
+/*
+ * The characteristics of long double.
+ * NOTE: long double is the same as double.
+ */
+#define LDBL_DIG	15
+#define LDBL_EPSILON	1.1102230246251568e-16L
+#define LDBL_MANT_DIG	53
+#define LDBL_MAX	1.7976931348623157e+308L
+#define LDBL_MAX_EXP	1024
+#define LDBL_MAX_10_EXP	308
+#define LDBL_MIN	2.2250738585072014e-308L
+#define LDBL_MIN_EXP	(-1021)
+#define LDBL_MIN_10_EXP	(-307)
+
+
+/*
+ * Functions and definitions for controlling the FPU.
+ */
+#ifndef	__STRICT_ANSI__
+
+/* TODO: These constants are only valid for x86 machines */
+
+/* Control word masks for unMask */
+#define	_MCW_EM		0x0008001F	/* Error masks */
+#define	_MCW_IC		0x00040000	/* Infinity */
+#define	_MCW_RC		0x00000300	/* Rounding */
+#define	_MCW_PC		0x00030000	/* Precision */
+
+/* Control word values for unNew (use with related unMask above) */
+#define	_EM_INVALID	0x00000010
+#define	_EM_DENORMAL	0x00080000
+#define	_EM_ZERODIVIDE	0x00000008
+#define	_EM_OVERFLOW	0x00000004
+#define	_EM_UNDERFLOW	0x00000002
+#define	_EM_INEXACT	0x00000001
+#define	_IC_AFFINE	0x00040000
+#define	_IC_PROJECTIVE	0x00000000
+#define	_RC_CHOP	0x00000300
+#define	_RC_UP		0x00000200
+#define	_RC_DOWN	0x00000100
+#define	_RC_NEAR	0x00000000
+#define	_PC_24		0x00020000
+#define	_PC_53		0x00010000
+#define	_PC_64		0x00000000
+
+/* These are also defined in Mingw math.h, needed to work around
+   GCC build issues.  */
+/* Return values for fpclass. */
+#ifndef __MINGW_FPCLASS_DEFINED
+#define __MINGW_FPCLASS_DEFINED 1
+#define	_FPCLASS_SNAN	0x0001	/* Signaling "Not a Number" */
+#define	_FPCLASS_QNAN	0x0002	/* Quiet "Not a Number" */
+#define	_FPCLASS_NINF	0x0004	/* Negative Infinity */
+#define	_FPCLASS_NN	0x0008	/* Negative Normal */
+#define	_FPCLASS_ND	0x0010	/* Negative Denormal */
+#define	_FPCLASS_NZ	0x0020	/* Negative Zero */
+#define	_FPCLASS_PZ	0x0040	/* Positive Zero */
+#define	_FPCLASS_PD	0x0080	/* Positive Denormal */
+#define	_FPCLASS_PN	0x0100	/* Positive Normal */
+#define	_FPCLASS_PINF	0x0200	/* Positive Infinity */
+#endif /* __MINGW_FPCLASS_DEFINED */
+
+/* invalid subconditions (_SW_INVALID also set) */
+#define _SW_UNEMULATED		0x0040  /* unemulated instruction */
+#define _SW_SQRTNEG		0x0080  /* square root of a neg number */
+#define _SW_STACKOVERFLOW	0x0200  /* FP stack overflow */
+#define _SW_STACKUNDERFLOW	0x0400  /* FP stack underflow */
+
+/*  Floating point error signals and return codes */
+#define _FPE_INVALID		0x81
+#define _FPE_DENORMAL		0x82
+#define _FPE_ZERODIVIDE		0x83
+#define _FPE_OVERFLOW		0x84
+#define _FPE_UNDERFLOW		0x85
+#define _FPE_INEXACT		0x86
+#define _FPE_UNEMULATED		0x87
+#define _FPE_SQRTNEG		0x88
+#define _FPE_STACKOVERFLOW	0x8a
+#define _FPE_STACKUNDERFLOW	0x8b
+#define _FPE_EXPLICITGEN	0x8c    /* raise( SIGFPE ); */
+
+#ifndef RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Set the FPU control word as cw = (cw & ~unMask) | (unNew & unMask),
+ * i.e. change the bits in unMask to have the values they have in unNew,
+ * leaving other bits unchanged. */
+unsigned int	_controlfp (unsigned int unNew, unsigned int unMask);
+unsigned int	_control87 (unsigned int unNew, unsigned int unMask);
+
+
+unsigned int	_clearfp (void);	/* Clear the FPU status word */
+unsigned int	_statusfp (void);	/* Report the FPU status word */
+#define		_clear87	_clearfp
+#define		_status87	_statusfp
+
+void		_fpreset (void);	/* Reset the FPU */
+void		fpreset (void);
+
+/* Global 'variable' for the current floating point error code. */
+int *	__fpecode(void);
+#define	_fpecode	(*(__fpecode()))
+
+/*
+ * IEEE recommended functions
+ */
+
+double	_chgsign	(double);
+double	_copysign	(double, double);
+double	_logb		(double);
+double	_nextafter	(double, double);
+double	_scalb		(double, long);
+
+int	_finite		(double);
+int	_fpclass	(double);
+int	_isnan		(double);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+#endif /* _FLOAT_H_ */
+
diff --git a/tinyc/win32/include/inttypes.h b/tinyc/win32/include/inttypes.h
new file mode 100644
index 000000000..74944f14b
--- /dev/null
+++ b/tinyc/win32/include/inttypes.h
@@ -0,0 +1,275 @@
+/* 7.8 Format conversion of integer types <inttypes.h> */
+
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <stdint.h>
+#define __need_wchar_t
+#include <stddef.h>
+
+#ifdef	__cplusplus
+extern	"C"	{
+#endif
+
+typedef struct {
+	intmax_t quot;
+	intmax_t rem;
+	} imaxdiv_t;
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)
+
+/* 7.8.1 Macros for format specifiers
+ * 
+ * MS runtime does not yet understand C9x standard "ll"
+ * length specifier. It appears to treat "ll" as "l".
+ * The non-standard I64 length specifier causes warning in GCC,
+ * but understood by MS runtime functions.
+ */
+
+/* fprintf macros for signed types */
+#define PRId8 "d"
+#define PRId16 "d"
+#define PRId32 "d"
+#define PRId64 "I64d"
+
+#define PRIdLEAST8 "d"
+#define PRIdLEAST16 "d"
+#define PRIdLEAST32 "d"
+#define PRIdLEAST64 "I64d"
+
+#define PRIdFAST8 "d"
+#define PRIdFAST16 "d"
+#define PRIdFAST32 "d"
+#define PRIdFAST64 "I64d"
+
+#define PRIdMAX "I64d"
+#define PRIdPTR "d"
+
+#define PRIi8 "i"
+#define PRIi16 "i"
+#define PRIi32 "i"
+#define PRIi64 "I64i"
+
+#define PRIiLEAST8 "i"
+#define PRIiLEAST16 "i"
+#define PRIiLEAST32 "i"
+#define PRIiLEAST64 "I64i"
+
+#define PRIiFAST8 "i"
+#define PRIiFAST16 "i"
+#define PRIiFAST32 "i"
+#define PRIiFAST64 "I64i"
+
+#define PRIiMAX "I64i"
+#define PRIiPTR "i"
+
+#define PRIo8 "o"
+#define PRIo16 "o"
+#define PRIo32 "o"
+#define PRIo64 "I64o"
+
+#define PRIoLEAST8 "o"
+#define PRIoLEAST16 "o"
+#define PRIoLEAST32 "o"
+#define PRIoLEAST64 "I64o"
+
+#define PRIoFAST8 "o"
+#define PRIoFAST16 "o"
+#define PRIoFAST32 "o"
+#define PRIoFAST64 "I64o"
+
+#define PRIoMAX "I64o"
+
+#define PRIoPTR "o"
+
+/* fprintf macros for unsigned types */
+#define PRIu8 "u"
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRIu64 "I64u"
+
+
+#define PRIuLEAST8 "u"
+#define PRIuLEAST16 "u"
+#define PRIuLEAST32 "u"
+#define PRIuLEAST64 "I64u"
+
+#define PRIuFAST8 "u"
+#define PRIuFAST16 "u"
+#define PRIuFAST32 "u"
+#define PRIuFAST64 "I64u"
+
+#define PRIuMAX "I64u"
+#define PRIuPTR "u"
+
+#define PRIx8 "x"
+#define PRIx16 "x"
+#define PRIx32 "x"
+#define PRIx64 "I64x"
+
+#define PRIxLEAST8 "x"
+#define PRIxLEAST16 "x"
+#define PRIxLEAST32 "x"
+#define PRIxLEAST64 "I64x"
+
+#define PRIxFAST8 "x"
+#define PRIxFAST16 "x"
+#define PRIxFAST32 "x"
+#define PRIxFAST64 "I64x"
+
+#define PRIxMAX "I64x"
+#define PRIxPTR "x"
+
+#define PRIX8 "X"
+#define PRIX16 "X"
+#define PRIX32 "X"
+#define PRIX64 "I64X"
+
+#define PRIXLEAST8 "X"
+#define PRIXLEAST16 "X"
+#define PRIXLEAST32 "X"
+#define PRIXLEAST64 "I64X"
+
+#define PRIXFAST8 "X"
+#define PRIXFAST16 "X"
+#define PRIXFAST32 "X"
+#define PRIXFAST64 "I64X"
+
+#define PRIXMAX "I64X"
+#define PRIXPTR "X"
+
+/*
+ *   fscanf macros for signed int types
+ *   NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t
+ *   (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have
+ *   no length identifiers
+ */
+
+#define SCNd16 "hd"
+#define SCNd32 "d"
+#define SCNd64 "I64d"
+
+#define SCNdLEAST16 "hd"
+#define SCNdLEAST32 "d"
+#define SCNdLEAST64 "I64d"
+
+#define SCNdFAST16 "hd"
+#define SCNdFAST32 "d"
+#define SCNdFAST64 "I64d"
+
+#define SCNdMAX "I64d"
+#define SCNdPTR "d"
+
+#define SCNi16 "hi"
+#define SCNi32 "i"
+#define SCNi64 "I64i"
+
+#define SCNiLEAST16 "hi"
+#define SCNiLEAST32 "i"
+#define SCNiLEAST64 "I64i"
+
+#define SCNiFAST16 "hi"
+#define SCNiFAST32 "i"
+#define SCNiFAST64 "I64i"
+
+#define SCNiMAX "I64i"
+#define SCNiPTR "i"
+
+#define SCNo16 "ho"
+#define SCNo32 "o"
+#define SCNo64 "I64o"
+
+#define SCNoLEAST16 "ho"
+#define SCNoLEAST32 "o"
+#define SCNoLEAST64 "I64o"
+
+#define SCNoFAST16 "ho"
+#define SCNoFAST32 "o"
+#define SCNoFAST64 "I64o"
+
+#define SCNoMAX "I64o"
+#define SCNoPTR "o"
+
+#define SCNx16 "hx"
+#define SCNx32 "x"
+#define SCNx64 "I64x"
+
+#define SCNxLEAST16 "hx"
+#define SCNxLEAST32 "x"
+#define SCNxLEAST64 "I64x"
+
+#define SCNxFAST16 "hx"
+#define SCNxFAST32 "x"
+#define SCNxFAST64 "I64x"
+
+#define SCNxMAX "I64x"
+#define SCNxPTR "x"
+
+
+/* fscanf macros for unsigned int types */
+
+#define SCNu16 "hu"
+#define SCNu32 "u"
+#define SCNu64 "I64u"
+
+#define SCNuLEAST16 "hu"
+#define SCNuLEAST32 "u"
+#define SCNuLEAST64 "I64u"
+
+#define SCNuFAST16 "hu"
+#define SCNuFAST32 "u"
+#define SCNuFAST64 "I64u"
+
+#define SCNuMAX "I64u"
+#define SCNuPTR "u"
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+/*
+ * no length modifier for char types prior to C9x
+ * MS runtime  scanf appears to treat "hh" as "h" 
+ */
+
+/* signed char */
+#define SCNd8 "hhd"
+#define SCNdLEAST8 "hhd"
+#define SCNdFAST8 "hhd"
+
+#define SCNi8 "hhi"
+#define SCNiLEAST8 "hhi"
+#define SCNiFAST8 "hhi"
+
+#define SCNo8 "hho"
+#define SCNoLEAST8 "hho"
+#define SCNoFAST8 "hho"
+
+#define SCNx8 "hhx"
+#define SCNxLEAST8 "hhx"
+#define SCNxFAST8 "hhx"
+
+/* unsigned char */
+#define SCNu8 "hhu"
+#define SCNuLEAST8 "hhu"
+#define SCNuFAST8 "hhu"
+#endif /* __STDC_VERSION__ >= 199901 */
+
+#endif	/* !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) */
+
+extern inline intmax_t	imaxabs (intmax_t j)
+	{return	(j >= 0 ? j : -j);}
+imaxdiv_t imaxdiv (intmax_t numer, intmax_t denom);
+
+/* 7.8.2 Conversion functions for greatest-width integer types */
+
+intmax_t   strtoimax (const char* __restrict__ nptr, char** __restrict__ endptr, int base);
+uintmax_t  strtoumax (const char* __restrict__ nptr, char** __restrict__ endptr, int base);
+
+intmax_t wcstoimax (const wchar_t* __restrict__ nptr, wchar_t** __restrict__ endptr,
+	   int base);
+uintmax_t wcstoumax (const wchar_t* __restrict__ nptr, wchar_t** __restrict__ endptr,
+	   int base);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* ndef _INTTYPES_H */
diff --git a/tinyc/win32/include/io.h b/tinyc/win32/include/io.h
new file mode 100644
index 000000000..8d5115e6c
--- /dev/null
+++ b/tinyc/win32/include/io.h
@@ -0,0 +1,296 @@
+/* 
+ * io.h
+ *
+ * System level I/O functions and types.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_IO_H_
+#define	_IO_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/* We need the definition of FILE anyway... */
+#include <stdio.h>
+
+/* MSVC's io.h contains the stuff from dir.h, so I will too.
+ * NOTE: This also defines off_t, the file offset type, through
+ *       an inclusion of sys/types.h */
+#ifndef __STRICT_ANSI__
+
+#include <sys/types.h>	/* To get time_t. */
+
+/*
+ * Attributes of files as returned by _findfirst et al.
+ */
+#define	_A_NORMAL	0x00000000
+#define	_A_RDONLY	0x00000001
+#define	_A_HIDDEN	0x00000002
+#define	_A_SYSTEM	0x00000004
+#define	_A_VOLID	0x00000008
+#define	_A_SUBDIR	0x00000010
+#define	_A_ARCH		0x00000020
+
+
+#ifndef RC_INVOKED
+
+#ifndef	_FSIZE_T_DEFINED
+typedef	unsigned long	_fsize_t;
+#define _FSIZE_T_DEFINED
+#endif
+
+/*
+ * The following structure is filled in by _findfirst or _findnext when
+ * they succeed in finding a match.
+ */
+struct _finddata_t
+{
+	unsigned	attrib;		/* Attributes, see constants above. */
+	time_t		time_create;
+	time_t		time_access;	/* always midnight local time */
+	time_t		time_write;
+	_fsize_t	size;
+	char		name[FILENAME_MAX];	/* may include spaces. */
+};
+
+struct _finddatai64_t {
+    unsigned    attrib;
+    time_t      time_create;
+    time_t      time_access;
+    time_t      time_write;
+    __int64     size;
+    char        name[FILENAME_MAX];
+};
+
+
+#ifndef _WFINDDATA_T_DEFINED
+struct _wfinddata_t {
+    	unsigned	attrib;
+    	time_t		time_create;	/* -1 for FAT file systems */
+    	time_t		time_access;	/* -1 for FAT file systems */
+    	time_t		time_write;
+    	_fsize_t	size;
+    	wchar_t		name[FILENAME_MAX];	/* may include spaces. */
+};
+struct _wfinddatai64_t {
+    unsigned    attrib;
+    time_t      time_create;
+    time_t      time_access;
+    time_t      time_write;
+    __int64     size;
+    wchar_t     name[FILENAME_MAX];
+};
+
+#define _WFINDDATA_T_DEFINED
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Functions for searching for files. _findfirst returns -1 if no match
+ * is found. Otherwise it returns a handle to be used in _findnext and
+ * _findclose calls. _findnext also returns -1 if no match could be found,
+ * and 0 if a match was found. Call _findclose when you are finished.
+ */
+int	_findfirst (const char*, struct _finddata_t*);
+int	_findnext (int, struct _finddata_t*);
+int	_findclose (int);
+
+int	_chdir (const char*);
+char*	_getcwd (char*, int);
+int	_mkdir (const char*);
+char*	_mktemp (char*);
+int	_rmdir (const char*);
+
+
+#ifdef __MSVCRT__
+__int64  _filelengthi64(int);
+long _findfirsti64(const char*, struct _finddatai64_t*);
+int _findnexti64(long, struct _finddatai64_t*);
+__int64  _lseeki64(int, __int64, int);
+__int64  _telli64(int);
+#endif /* __MSVCRT__ */
+
+
+#ifndef _NO_OLDNAMES
+
+#ifndef _UWIN
+int	chdir (const char*);
+char*	getcwd (char*, int);
+int	mkdir (const char*);
+char*	mktemp (char*);
+int	rmdir (const char*);
+#endif /* _UWIN */
+
+#endif /* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+/* TODO: Maximum number of open handles has not been tested, I just set
+ * it the same as FOPEN_MAX. */
+#define	HANDLE_MAX	FOPEN_MAX
+
+
+/* Some defines for _access nAccessMode (MS doesn't define them, but
+ * it doesn't seem to hurt to add them). */
+#define	F_OK	0	/* Check for file existence */
+#define	X_OK	1	/* Check for execute permission. */
+#define	W_OK	2	/* Check for write permission */
+#define	R_OK	4	/* Check for read permission */
+
+#ifndef RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int		_access (const char*, int);
+int		_chsize (int, long);
+int		_close (int);
+int		_commit(int);
+
+/* NOTE: The only significant bit in unPermissions appears to be bit 7 (0x80),
+ *       the "owner write permission" bit (on FAT). */
+int		_creat (const char*, unsigned);
+
+int		_dup (int);
+int		_dup2 (int, int);
+long		_filelength (int);
+int		_fileno (FILE*);
+long		_get_osfhandle (int);
+int		_isatty (int);
+
+/* In a very odd turn of events this function is excluded from those
+ * files which define _STREAM_COMPAT. This is required in order to
+ * build GNU libio because of a conflict with _eof in streambuf.h
+ * line 107. Actually I might just be able to change the name of
+ * the enum member in streambuf.h... we'll see. TODO */
+#ifndef	_STREAM_COMPAT
+int		_eof (int);
+#endif
+
+/* LK_... locking commands defined in sys/locking.h. */
+int		_locking (int, int, long);
+
+long		_lseek (int, long, int);
+
+/* Optional third argument is unsigned unPermissions. */
+int		_open (const char*, int, ...);
+
+int		_open_osfhandle (long, int);
+int		_pipe (int *, unsigned int, int);
+int		_read (int, void*, unsigned int);
+
+/* SH_... flags for nShFlags defined in share.h
+ * Optional fourth argument is unsigned unPermissions */
+int		_sopen (const char*, int, int, ...);
+
+long		_tell (int);
+/* Should umask be in sys/stat.h and/or sys/types.h instead? */
+int		_umask (int);
+int		_unlink (const char*);
+int		_write (int, const void*, unsigned int);
+
+/* Wide character versions. Also declared in wchar.h. */
+/* Not in crtdll.dll */
+#if !defined (_WIO_DEFINED)
+#if defined (__MSVCRT__)
+int 		_waccess(const wchar_t*, int);
+int 		_wchmod(const wchar_t*, int);
+int 		_wcreat(const wchar_t*, int);
+long 		_wfindfirst(wchar_t*, struct _wfinddata_t*);
+int 		_wfindnext(long, struct _wfinddata_t *);
+int 		_wunlink(const wchar_t*);
+int 		_wopen(const wchar_t*, int, ...);
+int 		_wsopen(const wchar_t*, int, int, ...);
+wchar_t * 	_wmktemp(wchar_t*);
+long  _wfindfirsti64(const wchar_t*, struct _wfinddatai64_t*);
+int  _wfindnexti64(long, struct _wfinddatai64_t*);
+#endif /* defined (__MSVCRT__) */
+#define _WIO_DEFINED
+#endif /* _WIO_DEFINED */
+
+#ifndef	_NO_OLDNAMES
+/*
+ * Non-underscored versions of non-ANSI functions to improve portability.
+ * These functions live in libmoldname.a.
+ */
+
+#ifndef _UWIN
+int		access (const char*, int);
+int		chsize (int, long );
+int		close (int);
+int		creat (const char*, int);
+int		dup (int);
+int		dup2 (int, int);
+int		eof (int);
+long		filelength (int);
+int		fileno (FILE*);
+int		isatty (int);
+long		lseek (int, long, int);
+int		open (const char*, int, ...);
+int		read (int, void*, unsigned int);
+int		sopen (const char*, int, int, ...);
+long		tell (int);
+int		umask (int);
+int		unlink (const char*);
+int		write (int, const void*, unsigned int);
+#endif /* _UWIN */
+
+/* Wide character versions. Also declared in wchar.h. */
+/* Where do these live? Not in libmoldname.a nor in libmsvcrt.a */
+#if 0
+int 		waccess(const wchar_t *, int);
+int 		wchmod(const wchar_t *, int);
+int 		wcreat(const wchar_t *, int);
+long 		wfindfirst(wchar_t *, struct _wfinddata_t *);
+int 		wfindnext(long, struct _wfinddata_t *);
+int 		wunlink(const wchar_t *);
+int 		wrename(const wchar_t *, const wchar_t *);
+int 		wopen(const wchar_t *, int, ...);
+int 		wsopen(const wchar_t *, int, int, ...);
+wchar_t * 	wmktemp(wchar_t *);
+#endif
+
+#endif	/* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* _IO_H_ not defined */
+
+#endif	/* Not strict ANSI */
+
diff --git a/tinyc/win32/include/limits.h b/tinyc/win32/include/limits.h
new file mode 100644
index 000000000..5dc6025fd
--- /dev/null
+++ b/tinyc/win32/include/limits.h
@@ -0,0 +1,115 @@
+/* 
+ * limits.h
+ *
+ * Defines constants for the sizes of integral types.
+ *
+ * NOTE: GCC should supply a version of this header and it should be safe to
+ *       use that version instead of this one (maybe safer).
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _LIMITS_H_
+#define _LIMITS_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * File system limits
+ *
+ * TODO: NAME_MAX and OPEN_MAX are file system limits or not? Are they the
+ *       same as FILENAME_MAX and FOPEN_MAX from stdio.h?
+ * NOTE: Apparently the actual size of PATH_MAX is 260, but a space is
+ *       required for the NUL. TODO: Test?
+ */
+#define PATH_MAX	(259)
+
+/*
+ * Characteristics of the char data type.
+ *
+ * TODO: Is MB_LEN_MAX correct?
+ */
+#define CHAR_BIT	8
+#define MB_LEN_MAX	2
+
+#define SCHAR_MIN	(-128)
+#define SCHAR_MAX	127
+
+#define UCHAR_MAX	255
+
+/* TODO: Is this safe? I think it might just be testing the preprocessor,
+ *       not the compiler itself... */
+#if	('\x80' < 0)
+#define CHAR_MIN	SCHAR_MIN
+#define CHAR_MAX	SCHAR_MAX
+#else
+#define CHAR_MIN	0
+#define CHAR_MAX	UCHAR_MAX
+#endif
+
+/*
+ * Maximum and minimum values for ints.
+ */
+#define INT_MAX		2147483647
+#define INT_MIN		(-INT_MAX-1)
+
+#define UINT_MAX	0xffffffff
+
+/*
+ * Maximum and minimum values for shorts.
+ */
+#define SHRT_MAX	32767
+#define SHRT_MIN	(-SHRT_MAX-1)
+
+#define USHRT_MAX	0xffff
+
+/*
+ * Maximum and minimum values for longs and unsigned longs.
+ *
+ * TODO: This is not correct for Alphas, which have 64 bit longs.
+ */
+#define LONG_MAX	2147483647L
+
+#define LONG_MIN	(-LONG_MAX-1)
+
+#define ULONG_MAX	0xffffffffUL
+
+
+/*
+ * The GNU C compiler also allows 'long long int'
+ */
+#if	!defined(__STRICT_ANSI__) && defined(__GNUC__)
+
+#define LONG_LONG_MAX	9223372036854775807LL
+#define LONG_LONG_MIN	(-LONG_LONG_MAX-1)
+
+#define ULONG_LONG_MAX	(2ULL * LONG_LONG_MAX + 1)
+
+/* ISO C9x macro names */
+#define LLONG_MAX LONG_LONG_MAX
+#define LLONG_MIN LONG_LONG_MIN
+#define ULLONG_MAX ULONG_LONG_MAX
+
+#endif /* Not Strict ANSI and GNU C compiler */
+
+
+#endif /* not _LIMITS_H_ */
diff --git a/tinyc/win32/include/locale.h b/tinyc/win32/include/locale.h
new file mode 100644
index 000000000..d0da14d6b
--- /dev/null
+++ b/tinyc/win32/include/locale.h
@@ -0,0 +1,100 @@
+/* 
+ * locale.h
+ *
+ * Functions and types for localization (ie. changing the appearance of
+ * output based on the standards of a certain country).
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	_LOCALE_H_
+#define	_LOCALE_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * NOTE: I have tried to test this, but I am limited by my knowledge of
+ *       locale issues. The structure does not bomb if you look at the
+ *       values, and 'decimal_point' even seems to be correct. But the
+ *       rest of the values are, by default, not particularly useful
+ *       (read meaningless and not related to the international settings
+ *       of the system).
+ */
+
+#define	LC_ALL		0
+#define LC_COLLATE	1
+#define LC_CTYPE	2
+#define	LC_MONETARY	3
+#define	LC_NUMERIC	4
+#define	LC_TIME		5
+#define	LC_MIN		LC_ALL
+#define	LC_MAX		LC_TIME
+
+#ifndef RC_INVOKED
+
+/*
+ * The structure returned by 'localeconv'.
+ */
+struct lconv
+{
+	char*	decimal_point;
+	char*	thousands_sep;
+	char*	grouping;
+	char*	int_curr_symbol;
+	char*	currency_symbol;
+	char*	mon_decimal_point;
+	char*	mon_thousands_sep;
+	char*	mon_grouping;
+	char*	positive_sign;
+	char*	negative_sign;
+	char	int_frac_digits;
+	char	frac_digits;
+	char	p_cs_precedes;
+	char	p_sep_by_space;
+	char	n_cs_precedes;
+	char	n_sep_by_space;
+	char	p_sign_posn;
+	char	n_sign_posn;
+};
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+char*		setlocale (int, const char*);
+struct lconv*	localeconv (void);
+
+#ifndef _WLOCALE_DEFINED  /* also declared in wchar.h */
+# define __need_wchar_t
+# include <stddef.h>
+  wchar_t* 	_wsetlocale(int, const wchar_t*);
+# define _WLOCALE_DEFINED
+#endif /* ndef _WLOCALE_DEFINED */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _LOCALE_H_ */
+
diff --git a/tinyc/win32/include/malloc.h b/tinyc/win32/include/malloc.h
new file mode 100644
index 000000000..ca4259689
--- /dev/null
+++ b/tinyc/win32/include/malloc.h
@@ -0,0 +1,87 @@
+/*
+ * malloc.h
+ *
+ * Support for programs which want to use malloc.h to get memory management
+ * functions. Unless you absolutely need some of these functions and they are
+ * not in the ANSI headers you should use the ANSI standard header files
+ * instead.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef _MALLOC_H_
+#define _MALLOC_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#include <stdlib.h>
+
+#ifndef RC_INVOKED
+
+/*
+ * The structure used to walk through the heap with _heapwalk.
+ */
+typedef	struct _heapinfo
+{
+	int*	_pentry;
+	size_t	_size;
+	int	_useflag;
+} _HEAPINFO;
+
+/* Values for _heapinfo.useflag */
+#define _USEDENTRY 0
+#define _FREEENTRY 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+/*
+   The _heap* memory allocation functions are supported on NT
+   but not W9x. On latter, they always set errno to ENOSYS.
+*/
+int	_heapwalk (_HEAPINFO*);
+
+#ifndef	_NO_OLDNAMES
+int	heapwalk (_HEAPINFO*);
+#endif	/* Not _NO_OLDNAMES */
+
+int	_heapchk (void);	/* Verify heap integrety. */
+int	_heapmin (void);	/* Return unused heap to the OS. */
+int	_heapset (unsigned int);
+
+size_t	_msize (void*);
+size_t	_get_sbh_threshold (void); 
+int	_set_sbh_threshold (size_t);
+void *	_expand (void*, size_t); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* RC_INVOKED */
+
+#endif /* Not _MALLOC_H_ */
+
+#endif /* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/math.h b/tinyc/win32/include/math.h
new file mode 100644
index 000000000..ffb133a2f
--- /dev/null
+++ b/tinyc/win32/include/math.h
@@ -0,0 +1,438 @@
+/* 
+ * math.h
+ *
+ * Mathematical functions.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _MATH_H_
+#define _MATH_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * Types for the _exception structure.
+ */
+
+#define	_DOMAIN		1	/* domain error in argument */
+#define	_SING		2	/* singularity */
+#define	_OVERFLOW	3	/* range overflow */
+#define	_UNDERFLOW	4	/* range underflow */
+#define	_TLOSS		5	/* total loss of precision */
+#define	_PLOSS		6	/* partial loss of precision */
+
+/*
+ * Exception types with non-ANSI names for compatibility.
+ */
+
+#ifndef	__STRICT_ANSI__
+#ifndef	_NO_OLDNAMES
+
+#define	DOMAIN		_DOMAIN
+#define	SING		_SING
+#define	OVERFLOW	_OVERFLOW
+#define	UNDERFLOW	_UNDERFLOW
+#define	TLOSS		_TLOSS
+#define	PLOSS		_PLOSS
+
+#endif	/* Not _NO_OLDNAMES */
+#endif	/* Not __STRICT_ANSI__ */
+
+
+/* These are also defined in Mingw float.h; needed here as well to work 
+   around GCC build issues.  */
+#ifndef	__STRICT_ANSI__
+#ifndef __MINGW_FPCLASS_DEFINED
+#define __MINGW_FPCLASS_DEFINED 1
+/* IEEE 754 classication */
+#define	_FPCLASS_SNAN	0x0001	/* Signaling "Not a Number" */
+#define	_FPCLASS_QNAN	0x0002	/* Quiet "Not a Number" */
+#define	_FPCLASS_NINF	0x0004	/* Negative Infinity */
+#define	_FPCLASS_NN	0x0008	/* Negative Normal */
+#define	_FPCLASS_ND	0x0010	/* Negative Denormal */
+#define	_FPCLASS_NZ	0x0020	/* Negative Zero */
+#define	_FPCLASS_PZ	0x0040	/* Positive Zero */
+#define	_FPCLASS_PD	0x0080	/* Positive Denormal */
+#define	_FPCLASS_PN	0x0100	/* Positive Normal */
+#define	_FPCLASS_PINF	0x0200	/* Positive Infinity */
+#endif /* __MINGW_FPCLASS_DEFINED */
+#endif	/* Not __STRICT_ANSI__ */
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * HUGE_VAL is returned by strtod when the value would overflow the
+ * representation of 'double'. There are other uses as well.
+ *
+ * __imp__HUGE is a pointer to the actual variable _HUGE in
+ * MSVCRT.DLL. If we used _HUGE directly we would get a pointer
+ * to a thunk function.
+ *
+ * NOTE: The CRTDLL version uses _HUGE_dll instead.
+ */
+
+#ifndef __DECLSPEC_SUPPORTED
+
+#ifdef __MSVCRT__
+extern double*	__imp__HUGE;
+#define	HUGE_VAL	(*__imp__HUGE)
+#else
+/* CRTDLL */
+extern double*	__imp__HUGE_dll;
+#define	HUGE_VAL	(*__imp__HUGE_dll)
+#endif
+
+#else /* __DECLSPEC_SUPPORTED */
+
+#ifdef __MSVCRT__
+__MINGW_IMPORT double	_HUGE;
+#define	HUGE_VAL	_HUGE
+#else
+/* CRTDLL */
+__MINGW_IMPORT double	_HUGE_dll;
+#define	HUGE_VAL	_HUGE_dll
+#endif
+
+#endif /* __DECLSPEC_SUPPORTED */
+
+struct _exception
+{
+	int	type;
+	char	*name;
+	double	arg1;
+	double	arg2;
+	double	retval;
+};
+
+
+double	sin (double);
+double	cos (double);
+double	tan (double);
+double	sinh (double);
+double	cosh (double);
+double	tanh (double);
+double	asin (double);
+double	acos (double);
+double	atan (double);
+double	atan2 (double, double);
+double	exp (double);
+double	log (double);
+double	log10 (double);
+double	pow (double, double);
+double	sqrt (double);
+double	ceil (double);
+double	floor (double);
+double	fabs (double);
+double	ldexp (double, int);
+double	frexp (double, int*);
+double	modf (double, double*);
+double	fmod (double, double);
+
+
+#ifndef	__STRICT_ANSI__
+
+/* Complex number (for cabs) */
+struct _complex
+{
+	double	x;	/* Real part */
+	double	y;	/* Imaginary part */
+};
+
+double	_cabs (struct _complex);
+double	_hypot (double, double);
+double	_j0 (double);
+double	_j1 (double);
+double	_jn (int, double);
+double	_y0 (double);
+double	_y1 (double);
+double	_yn (int, double);
+int	_matherr (struct _exception *);
+
+/* These are also declared in Mingw float.h; needed here as well to work 
+   around GCC build issues.  */
+/* BEGIN FLOAT.H COPY */
+/*
+ * IEEE recommended functions
+ */
+
+double	_chgsign	(double);
+double	_copysign	(double, double);
+double	_logb		(double);
+double	_nextafter	(double, double);
+double	_scalb		(double, long);
+
+int	_finite		(double);
+int	_fpclass	(double);
+int	_isnan		(double);
+
+/* END FLOAT.H COPY */
+
+#if !defined (_NO_OLDNAMES)  \
+   || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L )
+
+/*
+ * Non-underscored versions of non-ANSI functions. These reside in
+ * liboldnames.a. They are now also ISO C99 standand names.
+ * Provided for extra portability.
+ */
+
+double cabs (struct _complex);
+double hypot (double, double);
+double j0 (double);
+double j1 (double);
+double jn (int, double);
+double y0 (double);
+double y1 (double);
+double yn (int, double);
+
+#endif	/* Not _NO_OLDNAMES */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif	/* Not RC_INVOKED */
+
+
+#ifndef __NO_ISOCEXT
+
+#define INFINITY HUGE_VAL
+#define NAN (0.0F/0.0F)
+
+/*
+   Return values for fpclassify.
+   These are based on Intel x87 fpu condition codes
+   in the high byte of status word and differ from
+   the return values for MS IEEE 754 extension _fpclass()
+*/
+#define FP_NAN		0x0100
+#define FP_NORMAL	0x0400
+#define FP_INFINITE	(FP_NAN | FP_NORMAL)
+#define FP_ZERO		0x4000
+#define FP_SUBNORMAL	(FP_NORMAL | FP_ZERO)
+/* 0x0200 is signbit mask */
+
+#ifndef RC_INVOKED
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+double nan(const char *tagp);
+float nanf(const char *tagp);
+
+#ifndef __STRICT_ANSI__
+#define nan() nan("")
+#define nanf() nanf("")
+#endif
+
+
+/*
+  We can't inline float, because we want to ensure truncation
+  to semantic type before classification.  If we extend to long
+  double, we will also need to make double extern only.
+  (A normal long double value might become subnormal when 
+  converted to double, and zero when converted to float.)
+*/
+extern __inline__ int __fpclassify (double x){
+  unsigned short sw;
+  __asm__ ("fxam; fstsw %%ax;" : "=a" (sw): "t" (x));
+  return sw & (FP_NAN | FP_NORMAL | FP_ZERO );
+}
+
+extern int __fpclassifyf (float);
+
+#define fpclassify(x) ((sizeof(x) == sizeof(float)) ? __fpclassifyf(x) \
+		       :  __fpclassify(x))
+
+/* We don't need to worry about trucation here:
+   A NaN stays a NaN. */
+
+extern __inline__ int __isnan (double _x)
+{
+  unsigned short sw;
+  __asm__ ("fxam;"
+	   "fstsw %%ax": "=a" (sw) : "t" (_x));
+  return (sw & (FP_NAN | FP_NORMAL | FP_INFINITE | FP_ZERO | FP_SUBNORMAL))
+    == FP_NAN;
+}
+
+extern __inline__ int __isnanf (float _x)
+{
+  unsigned short sw;
+  __asm__ ("fxam;"
+	    "fstsw %%ax": "=a" (sw) : "t" (_x));
+  return (sw & (FP_NAN | FP_NORMAL | FP_INFINITE | FP_ZERO | FP_SUBNORMAL))
+    == FP_NAN;
+}
+
+#define isnan(x) ((sizeof(x) == sizeof(float)) ? __isnanf(x) \
+		       :  __isnan(x))
+
+
+#define isfinite(x) ((fpclassify(x) & FP_NAN) == 0)
+#define isinf(x) (fpclassify(x) == FP_INFINITE)
+#define isnormal(x) (fpclassify(x) == FP_NORMAL)
+
+
+extern __inline__ int __signbit (double x) {
+  unsigned short stw;
+  __asm__ ( "fxam; fstsw %%ax;": "=a" (stw) : "t" (x));
+  return stw & 0x0200;
+}
+
+extern  __inline__ int __signbitf (float x) {
+  unsigned short stw;
+  __asm__ ("fxam; fstsw %%ax;": "=a" (stw) : "t" (x));
+  return stw & 0x0200;
+}
+
+#define signbit(x) ((sizeof(x) == sizeof(float)) ? __signbitf(x) \
+		    : __signbit(x))
+/* 
+ *  With these functions, comparisons involving quiet NaNs set the FP
+ *  condition code to "unordered".  The IEEE floating-point spec
+ *  dictates that the result of floating-point comparisons should be
+ *  false whenever a NaN is involved, with the exception of the !=, 
+ *  which always returns true.
+ */
+
+#if __GNUC__ >= 3
+
+#define isgreater(x, y) __builtin_isgreater(x, y)
+#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y)
+#define isless(x, y) __builtin_isless(x, y)
+#define islessequal(x, y) __builtin_islessequal(x, y)
+#define islessgreater(x, y) __builtin_islessgreater(x, y)
+#define isunordered(x, y) __builtin_isunordered(x, y)
+
+#else
+/*  helper  */
+extern  __inline__ int __fp_unordered_compare (double x,  double y){
+  unsigned short retval;
+  __asm__ ("fucom %%st(1);"
+	   "fnstsw;": "=a" (retval) : "t" (x), "u" (y));
+  return retval;
+}
+
+#define isgreater(x, y) ((__fp_unordered_compare(x, y) \
+			   & 0x4500) == 0)
+#define isless(x, y) ((__fp_unordered_compare (y, x) \
+                       & 0x4500) == 0)
+#define isgreaterequal(x, y) ((__fp_unordered_compare (x, y) \
+                               & FP_INFINITE) == 0)
+#define islessequal(x, y) ((__fp_unordered_compare(y, x) \
+			    & FP_INFINITE) == 0)
+#define islessgreater(x, y) ((__fp_unordered_compare(x, y) \
+			      & FP_SUBNORMAL) == 0)
+#define isunordered(x, y) ((__fp_unordered_compare(x, y) \
+			    & 0x4500) == 0x4500)
+
+#endif
+
+/* round, using fpu control word settings */
+extern  __inline__ double rint (double x)
+{
+  double retval;
+  __asm__ ("frndint;": "=t" (retval) : "0" (x));
+  return retval;
+}
+
+extern  __inline__ float rintf (float x)
+{
+  float retval;
+  __asm__ ("frndint;" : "=t" (retval) : "0" (x) );
+  return retval;
+}
+
+/* round away from zero, regardless of fpu control word settings */
+extern double round (double);
+extern float roundf (float);
+
+/* round towards zero, regardless of fpu control word settings */
+extern double trunc (double);
+extern float truncf (float);
+
+
+/* fmax and fmin.
+   NaN arguments are treated as missing data: if one argument is a NaN and the other numeric, then the
+   these functions choose the numeric value.
+*/
+
+extern double fmax  (double, double);
+extern double fmin (double, double);
+extern float fmaxf (float, float);
+float fminf (float, float);
+
+/* return x * y + z as a ternary op */ 
+extern double fma (double, double, double);
+extern float fmaf (float, float, float);
+
+/* one lonely transcendental */
+extern double log2 (double _x);
+extern float log2f (float _x);
+
+/* The underscored versions are in MSVCRT.dll.
+   The stubs for these are in libmingwex.a */
+
+double copysign (double, double);
+float copysignf (float, float);
+double logb (double);
+float logbf (float);
+double nextafter (double, double);
+float nextafterf (float, float);
+double scalb (double, long);
+float scalbf (float, long);
+
+#if !defined (__STRICT_ANSI__)  /* inline using non-ANSI functions */
+extern  __inline__ double copysign (double x, double y)
+	{ return _copysign(x, y); }
+extern  __inline__ float copysignf (float x, float y)
+	{ return  _copysign(x, y); } 
+extern  __inline__ double logb (double x)
+	{ return _logb(x); }
+extern  __inline__ float logbf (float x)
+	{ return  _logb(x); }
+extern  __inline__ double nextafter(double x, double y)
+	{ return _nextafter(x, y); }
+extern  __inline__ float nextafterf(float x, float y)
+	{ return _nextafter(x, y); }
+extern  __inline__ double scalb (double x, long i)
+	{ return _scalb (x, i); }
+extern  __inline__ float scalbf (float x, long i)
+	{ return _scalb(x, i); }
+#endif /* (__STRICT_ANSI__)  */
+
+#ifdef __cplusplus
+}
+#endif
+#endif	/* Not RC_INVOKED */
+
+#endif /* __NO_ISOCEXT */
+
+#endif	/* Not _MATH_H_ */
+
diff --git a/tinyc/win32/include/mem.h b/tinyc/win32/include/mem.h
new file mode 100644
index 000000000..20c8fa4a5
--- /dev/null
+++ b/tinyc/win32/include/mem.h
@@ -0,0 +1,8 @@
+/*
+ * This file is part of the Mingw32 package.
+ *
+ * mem.h maps to string.h
+ */
+#ifndef	__STRICT_ANSI__
+#include <string.h>
+#endif
diff --git a/tinyc/win32/include/memory.h b/tinyc/win32/include/memory.h
new file mode 100644
index 000000000..e0c91d635
--- /dev/null
+++ b/tinyc/win32/include/memory.h
@@ -0,0 +1,9 @@
+/*
+ * This file is part of the Mingw32 package.
+ *
+ * memory.h maps to the standard string.h header.
+ */
+#ifndef	__STRICT_ANSI__
+#include	<string.h>
+#endif
+
diff --git a/tinyc/win32/include/process.h b/tinyc/win32/include/process.h
new file mode 100644
index 000000000..3d764df0f
--- /dev/null
+++ b/tinyc/win32/include/process.h
@@ -0,0 +1,158 @@
+/* 
+ * process.h
+ *
+ * Function calls for spawning child processes.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_PROCESS_H_
+#define	_PROCESS_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/* Includes a definition of _pid_t and pid_t */
+#include <sys/types.h>
+
+/*
+ * Constants for cwait actions.
+ * Obsolete for Win32.
+ */
+#define	_WAIT_CHILD		0
+#define	_WAIT_GRANDCHILD	1
+
+#ifndef	_NO_OLDNAMES
+#define	WAIT_CHILD		_WAIT_CHILD
+#define	WAIT_GRANDCHILD		_WAIT_GRANDCHILD
+#endif	/* Not _NO_OLDNAMES */
+
+/*
+ * Mode constants for spawn functions.
+ */
+#define	_P_WAIT		0
+#define	_P_NOWAIT	1
+#define	_P_OVERLAY	2
+#define	_OLD_P_OVERLAY	_P_OVERLAY
+#define	_P_NOWAITO	3
+#define	_P_DETACH	4
+
+#ifndef	_NO_OLDNAMES
+#define	P_WAIT		_P_WAIT
+#define	P_NOWAIT	_P_NOWAIT
+#define	P_OVERLAY	_P_OVERLAY
+#define	OLD_P_OVERLAY	_OLD_P_OVERLAY
+#define	P_NOWAITO	_P_NOWAITO
+#define	P_DETACH	_P_DETACH
+#endif	/* Not _NO_OLDNAMES */
+
+
+#ifndef RC_INVOKED
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+void	_cexit(void);
+void	_c_exit(void);
+
+int	_cwait (int*, _pid_t, int);
+
+_pid_t	_getpid(void);
+
+int	_execl		(const char*, const char*, ...);
+int	_execle		(const char*, const char*, ...);
+int	_execlp		(const char*, const char*, ...);
+int	_execlpe	(const char*, const char*, ...);
+int	_execv		(const char*, char* const*);
+int	_execve		(const char*, char* const*, char* const*);
+int	_execvp		(const char*, char* const*);
+int	_execvpe	(const char*, char* const*, char* const*);
+
+int	_spawnl		(int, const char*, const char*, ...);
+int	_spawnle	(int, const char*, const char*, ...);
+int	_spawnlp	(int, const char*, const char*, ...);
+int	_spawnlpe	(int, const char*, const char*, ...);
+int	_spawnv		(int, const char*, char* const*);
+int	_spawnve	(int, const char*, char* const*, char* const*);
+int	_spawnvp	(int, const char*, char* const*);
+int	_spawnvpe	(int, const char*, char* const*, char* const*);
+
+/*
+ * The functions _beginthreadex and _endthreadex are not provided by CRTDLL.
+ * They are provided by MSVCRT.
+ *
+ * NOTE: Apparently _endthread calls CloseHandle on the handle of the thread,
+ * making for race conditions if you are not careful. Basically you have to
+ * make sure that no-one is going to do *anything* with the thread handle
+ * after the thread calls _endthread or returns from the thread function.
+ *
+ * NOTE: No old names for these functions. Use the underscore.
+ */
+unsigned long
+	_beginthread	(void (*)(void *), unsigned, void*);
+void	_endthread	(void);
+
+#ifdef	__MSVCRT__
+unsigned long
+	_beginthreadex	(void *, unsigned, unsigned (__stdcall *) (void *), 
+			 void*, unsigned, unsigned*);
+void	_endthreadex	(unsigned);
+#endif
+
+
+#ifndef	_NO_OLDNAMES
+/*
+ * Functions without the leading underscore, for portability. These functions
+ * live in liboldnames.a.
+ */
+int	cwait (int*, pid_t, int);
+pid_t	getpid (void);
+int	execl (const char*, const char*, ...);
+int	execle (const char*, const char*, ...);
+int	execlp (const char*, const char*, ...);
+int	execlpe (const char*, const char*, ...);
+int	execv (const char*, char* const*);
+int	execve (const char*, char* const*, char* const*);
+int	execvp (const char*, char* const*);
+int	execvpe (const char*, char* const*, char* const*);
+int	spawnl (int, const char*, const char*, ...);
+int	spawnle (int, const char*, const char*, ...);
+int	spawnlp (int, const char*, const char*, ...);
+int	spawnlpe (int, const char*, const char*, ...);
+int	spawnv (int, const char*, char* const*);
+int	spawnve (int, const char*, char* const*, char* const*);
+int	spawnvp (int, const char*, char* const*);
+int	spawnvpe (int, const char*, char* const*, char* const*);
+#endif	/* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* _PROCESS_H_ not defined */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/setjmp.h b/tinyc/win32/include/setjmp.h
new file mode 100644
index 000000000..0d9897e63
--- /dev/null
+++ b/tinyc/win32/include/setjmp.h
@@ -0,0 +1,72 @@
+/* 
+ * setjmp.h
+ *
+ * Declarations supporting setjmp and longjump, a method for avoiding
+ * the normal function call return sequence. (Bleah!)
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _SETJMP_H_
+#define _SETJMP_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The buffer used by setjmp to store the information used by longjmp
+ * to perform it's evil goto-like work. The size of this buffer was
+ * determined through experimentation; it's contents are a mystery.
+ * NOTE: This was determined on an i386 (actually a Pentium). The
+ *       contents could be different on an Alpha or something else.
+ */
+#define _JBLEN 16
+#define _JBTYPE int
+typedef _JBTYPE jmp_buf[_JBLEN];
+
+/*
+ * The function provided by CRTDLL which appears to do the actual work
+ * of setjmp.
+ */
+int	_setjmp (jmp_buf);
+
+#define	setjmp(x)	_setjmp(x)
+
+/*
+ * Return to the last setjmp call and act as if setjmp had returned
+ * nVal (which had better be non-zero!).
+ */
+void	longjmp (jmp_buf, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _SETJMP_H_ */
+
diff --git a/tinyc/win32/include/share.h b/tinyc/win32/include/share.h
new file mode 100644
index 000000000..dd5bd452a
--- /dev/null
+++ b/tinyc/win32/include/share.h
@@ -0,0 +1,44 @@
+/*
+ * share.h
+ *
+ * Constants for file sharing functions.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_SHARE_H_
+#define	_SHARE_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define SH_COMPAT	0x00	/* Compatibility */
+#define	SH_DENYRW	0x10	/* Deny read/write */
+#define	SH_DENYWR	0x20	/* Deny write */
+#define	SH_DENYRD	0x30	/* Deny read */
+#define	SH_DENYNO	0x40	/* Deny nothing */
+
+#endif	/* Not _SHARE_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/signal.h b/tinyc/win32/include/signal.h
new file mode 100644
index 000000000..4eced969a
--- /dev/null
+++ b/tinyc/win32/include/signal.h
@@ -0,0 +1,111 @@
+/* 
+ * signal.h
+ *
+ * A way to set handlers for exceptional conditions (also known as signals).
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	_SIGNAL_H_
+#define	_SIGNAL_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * The actual signal values. Using other values with signal
+ * produces a SIG_ERR return value.
+ *
+ * NOTE: SIGINT is produced when the user presses Ctrl-C.
+ *       SIGILL has not been tested.
+ *       SIGFPE doesn't seem to work?
+ *       SIGSEGV does not catch writing to a NULL pointer (that shuts down
+ *               your app; can you say "segmentation violation core dump"?).
+ *       SIGTERM comes from what kind of termination request exactly?
+ *       SIGBREAK is indeed produced by pressing Ctrl-Break.
+ *       SIGABRT is produced by calling abort.
+ * TODO: The above results may be related to not installing an appropriate
+ *       structured exception handling frame. Results may be better if I ever
+ *       manage to get the SEH stuff down.
+ */
+#define	SIGINT		2	/* Interactive attention */
+#define	SIGILL		4	/* Illegal instruction */
+#define	SIGFPE		8	/* Floating point error */
+#define	SIGSEGV		11	/* Segmentation violation */
+#define	SIGTERM		15	/* Termination request */
+#define SIGBREAK	21	/* Control-break */
+#define	SIGABRT		22	/* Abnormal termination (abort) */
+
+#define NSIG 23     /* maximum signal number + 1 */
+
+#ifndef	RC_INVOKED
+
+#ifndef _SIG_ATOMIC_T_DEFINED
+typedef int sig_atomic_t;
+#define _SIG_ATOMIC_T_DEFINED
+#endif
+
+/*
+ * The prototypes (below) are the easy part. The hard part is figuring
+ * out what signals are available and what numbers they are assigned
+ * along with appropriate values of SIG_DFL and SIG_IGN.
+ */
+
+/*
+ * A pointer to a signal handler function. A signal handler takes a
+ * single int, which is the signal it handles.
+ */
+typedef	void (*__p_sig_fn_t)(int);
+
+/*
+ * These are special values of signal handler pointers which are
+ * used to send a signal to the default handler (SIG_DFL), ignore
+ * the signal (SIG_IGN), or indicate an error return (SIG_ERR).
+ */
+#define	SIG_DFL	((__p_sig_fn_t) 0)
+#define	SIG_IGN	((__p_sig_fn_t) 1)
+#define	SIG_ERR ((__p_sig_fn_t) -1)
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Call signal to set the signal handler for signal sig to the
+ * function pointed to by handler. Returns a pointer to the
+ * previous handler, or SIG_ERR if an error occurs. Initially
+ * unhandled signals defined above will return SIG_DFL.
+ */
+__p_sig_fn_t	signal(int, __p_sig_fn_t);
+
+/*
+ * Raise the signal indicated by sig. Returns non-zero on success.
+ */
+int	raise (int);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _SIGNAL_H_ */
+
diff --git a/tinyc/win32/include/stdarg.h b/tinyc/win32/include/stdarg.h
new file mode 100644
index 000000000..a9b22b7b6
--- /dev/null
+++ b/tinyc/win32/include/stdarg.h
@@ -0,0 +1,16 @@
+#ifndef _STDARG_H
+#define _STDARG_H
+
+typedef char *va_list;
+
+/* only correct for i386 */
+#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
+#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
+#define va_copy(dest, src) (dest) = (src)
+#define va_end(ap)
+
+/* fix a buggy dependency on GCC in libio.h */
+typedef va_list __gnuc_va_list;
+#define _VA_LIST_DEFINED
+
+#endif
diff --git a/tinyc/win32/include/stdbool.h b/tinyc/win32/include/stdbool.h
new file mode 100644
index 000000000..6ed13a611
--- /dev/null
+++ b/tinyc/win32/include/stdbool.h
@@ -0,0 +1,10 @@
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+/* ISOC99 boolean */
+
+#define bool	_Bool
+#define true	1
+#define false	0
+
+#endif /* _STDBOOL_H */
diff --git a/tinyc/win32/include/stddef.h b/tinyc/win32/include/stddef.h
new file mode 100644
index 000000000..6e4e2c88e
--- /dev/null
+++ b/tinyc/win32/include/stddef.h
@@ -0,0 +1,23 @@
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+#define NULL ((void *)0)
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#define offsetof(type, field) ((size_t) &((type *)0)->field)
+
+/* need to do that because of glibc 2.1 bug (should have a way to test
+   presence of 'long long' without __GNUC__, or TCC should define
+   __GNUC__ ? */
+#if !defined(__int8_t_defined) && !defined(__dietlibc__)
+#define __int8_t_defined
+typedef char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
+typedef long long int int64_t;
+#endif
+
+void *alloca(size_t);
+
+#endif
diff --git a/tinyc/win32/include/stdint.h b/tinyc/win32/include/stdint.h
new file mode 100644
index 000000000..71c6708ff
--- /dev/null
+++ b/tinyc/win32/include/stdint.h
@@ -0,0 +1,184 @@
+/* ISO C9x  7.18  Integer types <stdint.h>
+ * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794)
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz>
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  Date: 2000-12-02
+ */
+
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+/* 7.18.1.1  Exact-width integer types */
+typedef signed char int8_t;
+typedef unsigned char   uint8_t;
+typedef short  int16_t;
+typedef unsigned short  uint16_t;
+typedef int  int32_t;
+typedef unsigned   uint32_t;
+typedef long long  int64_t;
+typedef unsigned long long   uint64_t;
+
+/* 7.18.1.2  Minimum-width integer types */
+typedef signed char int_least8_t;
+typedef unsigned char   uint_least8_t;
+typedef short  int_least16_t;
+typedef unsigned short  uint_least16_t;
+typedef int  int_least32_t;
+typedef unsigned   uint_least32_t;
+typedef long long  int_least64_t;
+typedef unsigned long long   uint_least64_t;
+
+/*  7.18.1.3  Fastest minimum-width integer types 
+ *  Not actually guaranteed to be fastest for all purposes
+ *  Here we use the exact-width types for 8 and 16-bit ints. 
+ */
+typedef char int_fast8_t;
+typedef unsigned char uint_fast8_t;
+typedef short  int_fast16_t;
+typedef unsigned short  uint_fast16_t;
+typedef int  int_fast32_t;
+typedef unsigned  int  uint_fast32_t;
+typedef long long  int_fast64_t;
+typedef unsigned long long   uint_fast64_t;
+
+/* 7.18.1.4  Integer types capable of holding object pointers */
+typedef int intptr_t;
+typedef unsigned uintptr_t;
+
+/* 7.18.1.5  Greatest-width integer types */
+typedef long long  intmax_t;
+typedef unsigned long long   uintmax_t;
+
+/* 7.18.2  Limits of specified-width integer types */
+#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS)
+
+/* 7.18.2.1  Limits of exact-width integer types */
+#define INT8_MIN (-128) 
+#define INT16_MIN (-32768)
+#define INT32_MIN (-2147483647 - 1)
+#define INT64_MIN  (-9223372036854775807LL - 1)
+
+#define INT8_MAX 127
+#define INT16_MAX 32767
+#define INT32_MAX 2147483647
+#define INT64_MAX 9223372036854775807LL
+
+#define UINT8_MAX 0xff /* 255U */
+#define UINT16_MAX 0xffff /* 65535U */
+#define UINT32_MAX 0xffffffff  /* 4294967295U */
+#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */
+
+/* 7.18.2.2  Limits of minimum-width integer types */
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
+
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
+
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+/* 7.18.2.3  Limits of fastest minimum-width integer types */
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST64_MIN INT64_MIN
+
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MAX INT64_MAX
+
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+/* 7.18.2.4  Limits of integer types capable of holding
+    object pointers */ 
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+
+/* 7.18.2.5  Limits of greatest-width integer types */
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+/* 7.18.3  Limits of other integer types */
+#define PTRDIFF_MIN INT32_MIN
+#define PTRDIFF_MAX INT32_MAX
+
+#define SIG_ATOMIC_MIN INT32_MIN
+#define SIG_ATOMIC_MAX INT32_MAX
+
+#define SIZE_MAX UINT32_MAX
+
+#ifndef WCHAR_MIN  /* also in wchar.h */ 
+#define WCHAR_MIN 0
+#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */
+#endif
+
+/*
+ * wint_t is unsigned int in __MINGW32__,
+ * but unsigned short in MS runtime
+ */
+#define WINT_MIN 0
+#define WINT_MAX UINT32_MAX
+
+#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */
+
+
+/* 7.18.4  Macros for integer constants */
+#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS)
+
+/* 7.18.4.1  Macros for minimum-width integer constants
+
+    Accoding to Douglas Gwyn <gwyn@arl.mil>:
+	"This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
+	9899:1999 as initially published, the expansion was required
+	to be an integer constant of precisely matching type, which
+	is impossible to accomplish for the shorter types on most
+	platforms, because C99 provides no standard way to designate
+	an integer constant with width less than that of type int.
+	TC1 changed this to require just an integer constant
+	*expression* with *promoted* type."
+
+	The trick used here is from Clive D W Feather.
+*/
+
+#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val))
+#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val))
+#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val))
+#define INT64_C(val) (INT_LEAST64_MAX-INT_LEAST64_MAX+(val))
+
+#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val))
+#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val))
+#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val))
+#define UINT64_C(val) (UINT_LEAST64_MAX-UINT_LEAST64_MAX+(val))
+
+/* 7.18.4.2  Macros for greatest-width integer constants */
+#define INTMAX_C(val) (INTMAX_MAX-INTMAX_MAX+(val))
+#define UINTMAX_C(val) (UINTMAX_MAX-UINTMAX_MAX+(val))
+
+#endif  /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */
+
+#endif
diff --git a/tinyc/win32/include/stdio.h b/tinyc/win32/include/stdio.h
new file mode 100644
index 000000000..2d97e668c
--- /dev/null
+++ b/tinyc/win32/include/stdio.h
@@ -0,0 +1,413 @@
+/*
+ * stdio.h
+ *
+ * Definitions of types and prototypes of functions for standard input and
+ * output.
+ *
+ * NOTE: The file manipulation functions provided by Microsoft seem to
+ * work with either slash (/) or backslash (\) as the path separator.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _STDIO_H_
+#define	_STDIO_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_size_t
+#define __need_NULL
+#define __need_wchar_t
+#define	__need_wint_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+
+/* Flags for the iobuf structure  */
+#define	_IOREAD	1
+#define	_IOWRT	2
+#define	_IORW	0x0080 /* opened as "r+w" */
+
+
+/*
+ * The three standard file pointers provided by the run time library.
+ * NOTE: These will go to the bit-bucket silently in GUI applications!
+ */
+#define	STDIN_FILENO	0
+#define	STDOUT_FILENO	1
+#define	STDERR_FILENO	2
+
+/* Returned by various functions on end of file condition or error. */
+#define	EOF	(-1)
+
+/*
+ * The maximum length of a file name. You should use GetVolumeInformation
+ * instead of this constant. But hey, this works.
+ *
+ * NOTE: This is used in the structure _finddata_t (see io.h) so changing it
+ *       is probably not a good idea.
+ */
+#define	FILENAME_MAX	(260)
+
+/*
+ * The maximum number of files that may be open at once. I have set this to
+ * a conservative number. The actual value may be higher.
+ */
+#define FOPEN_MAX	(20)
+
+/* After creating this many names, tmpnam and tmpfile return NULL */
+#define TMP_MAX	32767
+/*
+ * Tmpnam, tmpfile and, sometimes, _tempnam try to create
+ * temp files in the root directory of the current drive
+ * (not in pwd, as suggested by some older MS doc's).
+ * Redefining these macros does not effect the CRT functions.
+ */
+#define _P_tmpdir   "\\"
+#define _wP_tmpdir  L"\\"
+
+/*
+ * The maximum size of name (including NUL) that will be put in the user
+ * supplied buffer caName for tmpnam.
+ * Inferred from the size of the static buffer returned by tmpnam
+ * when passed a NULL argument. May actually be smaller.
+ */
+#define L_tmpnam (16)
+
+#define _IOFBF		0x0000
+#define _IOLBF		0x0040
+#define _IONBF		0x0004
+
+/*
+ * The buffer size as used by setbuf such that it is equivalent to
+ * (void) setvbuf(fileSetBuffer, caBuffer, _IOFBF, BUFSIZ).
+ */
+#define	BUFSIZ	512
+
+/* Constants for nOrigin indicating the position relative to which fseek
+ * sets the file position. Enclosed in ifdefs because io.h could also
+ * define them. (Though not anymore since io.h includes this file now.) */
+#ifndef	SEEK_SET
+#define SEEK_SET	(0)
+#endif
+
+#ifndef	SEEK_CUR
+#define	SEEK_CUR	(1)
+#endif
+
+#ifndef	SEEK_END
+#define SEEK_END	(2)
+#endif
+
+
+#ifndef	RC_INVOKED
+
+/*
+ * I used to include stdarg.h at this point, in order to allow for the
+ * functions later on in the file which use va_list. That conflicts with
+ * using stdio.h and varargs.h in the same file, so I do the typedef myself.
+ */
+#ifndef	_VA_LIST
+#define _VA_LIST
+#if defined __GNUC__ && __GNUC__ >= 3
+typedef __builtin_va_list va_list;
+#else
+typedef char* va_list;
+#endif
+#endif
+/*
+ * The structure underlying the FILE type.
+ *
+ * I still believe that nobody in their right mind should make use of the
+ * internals of this structure. Provided by Pedro A. Aranda Gutiirrez
+ * <paag@tid.es>.
+ */
+#ifndef _FILE_DEFINED
+#define	_FILE_DEFINED
+typedef struct _iobuf
+{
+	char*	_ptr;
+	int	_cnt;
+	char*	_base;
+	int	_flag;
+	int	_file;
+	int	_charbuf;
+	int	_bufsiz;
+	char*	_tmpfname;
+} FILE;
+#endif	/* Not _FILE_DEFINED */
+
+
+/*
+ * The standard file handles
+ */
+#ifndef __DECLSPEC_SUPPORTED
+
+extern FILE (*__imp__iob)[];	/* A pointer to an array of FILE */
+
+#define _iob	(*__imp__iob)	/* An array of FILE */
+
+#else /* __DECLSPEC_SUPPORTED */
+
+__MINGW_IMPORT FILE _iob[];	/* An array of FILE imported from DLL. */
+
+#endif /* __DECLSPEC_SUPPORTED */
+
+#define stdin	(&_iob[STDIN_FILENO])
+#define stdout	(&_iob[STDOUT_FILENO])
+#define stderr	(&_iob[STDERR_FILENO])
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * File Operations
+ */
+FILE*	fopen (const char*, const char*);
+FILE*	freopen (const char*, const char*, FILE*);
+int	fflush (FILE*);
+int	fclose (FILE*);
+/* MS puts remove & rename (but not wide versions) in io.h  also */
+int	remove (const char*);
+int	rename (const char*, const char*);
+FILE*	tmpfile (void);
+char*	tmpnam (char*);
+char*	_tempnam (const char*, const char*);
+
+#ifndef	NO_OLDNAMES
+char*	tempnam (const char*, const char*);
+#endif
+
+int	setvbuf (FILE*, char*, int, size_t);
+
+void	setbuf (FILE*, char*);
+
+/*
+ * Formatted Output
+ */
+
+int	fprintf (FILE*, const char*, ...);
+int	printf (const char*, ...);
+int	sprintf (char*, const char*, ...);
+int	_snprintf (char*, size_t, const char*, ...);
+int	vfprintf (FILE*, const char*, va_list);
+int	vprintf (const char*, va_list);
+int	vsprintf (char*, const char*, va_list);
+int	_vsnprintf (char*, size_t, const char*, va_list);
+
+#ifndef __NO_ISOCEXT  /* externs in libmingwex.a */
+int snprintf(char* s, size_t n, const char*  format, ...);
+extern inline int vsnprintf (char* s, size_t n, const char* format,
+			   va_list arg)
+  { return _vsnprintf ( s, n, format, arg); }
+#endif
+
+/*
+ * Formatted Input
+ */
+
+int	fscanf (FILE*, const char*, ...);
+int	scanf (const char*, ...);
+int	sscanf (const char*, const char*, ...);
+/*
+ * Character Input and Output Functions
+ */
+
+int	fgetc (FILE*);
+char*	fgets (char*, int, FILE*);
+int	fputc (int, FILE*);
+int	fputs (const char*, FILE*);
+int	getc (FILE*);
+int	getchar (void);
+char*	gets (char*);
+int	putc (int, FILE*);
+int	putchar (int);
+int	puts (const char*);
+int	ungetc (int, FILE*);
+
+/*
+ * Direct Input and Output Functions
+ */
+
+size_t	fread (void*, size_t, size_t, FILE*);
+size_t	fwrite (const void*, size_t, size_t, FILE*);
+
+/*
+ * File Positioning Functions
+ */
+
+int	fseek (FILE*, long, int);
+long	ftell (FILE*);
+void	rewind (FILE*);
+
+#ifdef __USE_MINGW_FSEEK  /* These are in libmingwex.a */
+/*
+ * Workaround for limitations on win9x where a file contents are
+ * not zero'd out if you seek past the end and then write.
+ */
+
+int __mingw_fseek (FILE *, long, int);
+int __mingw_fwrite (const void*, size_t, size_t, FILE*);
+#define fseek(fp, offset, whence)  __mingw_fseek(fp, offset, whence)
+#define fwrite(buffer, size, count, fp)  __mingw_fwrite(buffer, size, count, fp)
+#endif /* __USE_MINGW_FSEEK */
+
+
+/*
+ * An opaque data type used for storing file positions... The contents of
+ * this type are unknown, but we (the compiler) need to know the size
+ * because the programmer using fgetpos and fsetpos will be setting aside
+ * storage for fpos_t structres. Actually I tested using a byte array and
+ * it is fairly evident that the fpos_t type is a long (in CRTDLL.DLL).
+ * Perhaps an unsigned long? TODO? It's definitely a 64-bit number in
+ * MSVCRT however, and for now `long long' will do.
+ */
+#ifdef __MSVCRT__
+typedef long long fpos_t;
+#else
+typedef long	fpos_t;
+#endif
+
+int	fgetpos	(FILE*, fpos_t*);
+int	fsetpos (FILE*, const fpos_t*);
+
+/*
+ * Error Functions
+ */
+
+void	clearerr (FILE*);
+int	feof (FILE*);
+int	ferror (FILE*);
+void	perror (const char*);
+
+
+#ifndef __STRICT_ANSI__
+/*
+ * Pipes
+ */
+FILE*	_popen (const char*, const char*);
+int	_pclose (FILE*);
+
+#ifndef NO_OLDNAMES
+FILE*	popen (const char*, const char*);
+int	pclose (FILE*);
+#endif
+
+/*
+ * Other Non ANSI functions
+ */
+int	_flushall (void);
+int	_fgetchar (void);
+int	_fputchar (int);
+FILE*	_fdopen (int, const char*);
+int	_fileno (FILE*);
+
+#ifndef _NO_OLDNAMES
+int	fgetchar (void);
+int	fputchar (int);
+FILE*	fdopen (int, const char*);
+int	fileno (FILE*);
+#endif	/* Not _NO_OLDNAMES */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+/* Wide  versions */
+
+#ifndef _WSTDIO_DEFINED
+/*  also in wchar.h - keep in sync */
+int	fwprintf (FILE*, const wchar_t*, ...);
+int	wprintf (const wchar_t*, ...);
+int	swprintf (wchar_t*, const wchar_t*, ...);
+int	_snwprintf (wchar_t*, size_t, const wchar_t*, ...);
+int	vfwprintf (FILE*, const wchar_t*, va_list);
+int	vwprintf (const wchar_t*, va_list);
+int	vswprintf (wchar_t*, const wchar_t*, va_list);
+int	_vsnwprintf (wchar_t*, size_t, const wchar_t*, va_list);
+int	fwscanf (FILE*, const wchar_t*, ...);
+int	wscanf (const wchar_t*, ...);
+int	swscanf (const wchar_t*, const wchar_t*, ...);
+wint_t	fgetwc (FILE*);
+wint_t	fputwc (wchar_t, FILE*);
+wint_t	ungetwc (wchar_t, FILE*);
+#ifdef __MSVCRT__ 
+wchar_t* fgetws (wchar_t*, int, FILE*);
+int	fputws (const wchar_t*, FILE*);
+wint_t	getwc (FILE*);
+wint_t	getwchar (void);
+wchar_t* _getws (wchar_t*);
+wint_t	putwc (wint_t, FILE*);
+int	_putws (const wchar_t*);
+wint_t	putwchar (wint_t);
+FILE*	_wfopen (const wchar_t*, const wchar_t*);
+FILE*	_wfreopen (const wchar_t*, const wchar_t*, FILE*);
+FILE*	_wfsopen (const wchar_t*, const wchar_t*, int);
+wchar_t* _wtmpnam (wchar_t*);
+wchar_t* _wtempnam (const wchar_t*, const wchar_t*);
+int	_wrename (const wchar_t*, const wchar_t*);
+int	_wremove (const wchar_t*);
+void	_wperror (const wchar_t*);
+FILE*	_wpopen (const wchar_t*, const wchar_t*);
+#endif	/* __MSVCRT__ */
+
+#ifndef __NO_ISOCEXT  /* externs in libmingwex.a */
+int snwprintf(wchar_t* s, size_t n, const wchar_t*  format, ...);
+extern inline int vsnwprintf (wchar_t* s, size_t n, const wchar_t* format,
+			   va_list arg)
+  { return _vsnwprintf ( s, n, format, arg); }
+#endif
+
+#define _WSTDIO_DEFINED
+#endif /* _WSTDIO_DEFINED */
+
+#ifndef __STRICT_ANSI__
+#ifdef __MSVCRT__
+#ifndef NO_OLDNAMES
+FILE*	wpopen (const wchar_t*, const wchar_t*);
+#endif /* not NO_OLDNAMES */
+#endif /* MSVCRT runtime */
+
+/*
+ * Other Non ANSI wide functions
+ */
+wint_t	_fgetwchar (void);
+wint_t	_fputwchar (wint_t);
+int	_getw (FILE*);
+int	_putw (int, FILE*);
+
+#ifndef _NO_OLDNAMES
+wint_t	fgetwchar (void);
+wint_t	fputwchar (wint_t);
+int	getw (FILE*);
+int	putw (int, FILE*);
+#endif	/* Not _NO_OLDNAMES */
+
+#endif /* __STRICT_ANSI */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif /* _STDIO_H_ */
diff --git a/tinyc/win32/include/stdlib.h b/tinyc/win32/include/stdlib.h
new file mode 100644
index 000000000..37fae4879
--- /dev/null
+++ b/tinyc/win32/include/stdlib.h
@@ -0,0 +1,482 @@
+/*
+ * stdlib.h
+ *
+ * Definitions for common types, variables, and functions.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _STDLIB_H_
+#define _STDLIB_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+
+#define __need_size_t
+#define __need_wchar_t
+#define __need_NULL
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif /* RC_INVOKED */
+
+/*
+ * RAND_MAX is the maximum value that may be returned by rand.
+ * The minimum is zero.
+ */
+#define	RAND_MAX	0x7FFF
+
+/*
+ * These values may be used as exit status codes.
+ */
+#define	EXIT_SUCCESS	0
+#define	EXIT_FAILURE	1
+
+/*
+ * Definitions for path name functions.
+ * NOTE: All of these values have simply been chosen to be conservatively high.
+ *       Remember that with long file names we can no longer depend on
+ *       extensions being short.
+ */
+#ifndef __STRICT_ANSI__
+
+#ifndef MAX_PATH
+#define	MAX_PATH	(260)
+#endif
+
+#define	_MAX_PATH	MAX_PATH
+#define	_MAX_DRIVE	(3)
+#define	_MAX_DIR	256
+#define	_MAX_FNAME	256
+#define	_MAX_EXT	256
+
+#endif	/* Not __STRICT_ANSI__ */
+
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This seems like a convenient place to declare these variables, which
+ * give programs using WinMain (or main for that matter) access to main-ish
+ * argc and argv. environ is a pointer to a table of environment variables.
+ * NOTE: Strings in _argv and environ are ANSI strings.
+ */
+extern int	_argc;
+extern char**	_argv;
+
+/* imports from runtime dll of the above variables */
+#ifdef __MSVCRT__
+
+extern int*     __p___argc(void);
+extern char***   __p___argv(void);
+extern wchar_t***   __p___wargv(void);
+
+#define __argc (*__p___argc())
+#define __argv (*__p___argv())
+#define __wargv (*__p___wargv())
+
+#else /* !MSVCRT */
+
+#ifndef __DECLSPEC_SUPPORTED
+
+extern int*    __imp___argc_dll;
+extern char***  __imp___argv_dll;
+#define __argc (*__imp___argc_dll)
+#define __argv (*__imp___argv_dll)
+
+#else /* __DECLSPEC_SUPPORTED */
+
+__MINGW_IMPORT int    __argc_dll;
+__MINGW_IMPORT char**  __argv_dll;
+#define __argc __argc_dll
+#define __argv __argv_dll
+
+#endif /* __DECLSPEC_SUPPORTED */
+
+#endif /* __MSVCRT */
+
+/*
+ * Also defined in ctype.h.
+ */
+
+#ifndef MB_CUR_MAX
+# ifdef __MSVCRT__
+#  define MB_CUR_MAX __mb_cur_max
+   __MINGW_IMPORT int __mb_cur_max;
+# else /* not __MSVCRT */
+#  define MB_CUR_MAX __mb_cur_max_dll
+   __MINGW_IMPORT int __mb_cur_max_dll;
+# endif /* not __MSVCRT */
+#endif  /* MB_CUR_MAX */
+
+/* 
+ * MS likes to declare errno in stdlib.h as well. 
+ */
+
+#ifdef _UWIN
+#undef errno
+extern int errno;
+#else
+int*	_errno(void);
+#define	errno		(*_errno())
+#endif
+int*	__doserrno(void);
+#define	_doserrno	(*__doserrno())
+
+/*
+ * Use environ from the DLL, not as a global. 
+ */
+
+#ifdef __MSVCRT__
+  extern char *** __p__environ(void);
+  extern wchar_t *** __p__wenviron(void);
+# define _environ (*__p__environ())
+# define _wenviron (*__p__wenviron())
+#else /* ! __MSVCRT__ */
+# ifndef __DECLSPEC_SUPPORTED
+    extern char *** __imp__environ_dll;
+#   define _environ (*__imp__environ_dll)
+# else /* __DECLSPEC_SUPPORTED */
+    __MINGW_IMPORT char ** _environ_dll;
+#   define _environ _environ_dll
+# endif /* __DECLSPEC_SUPPORTED */
+#endif /* ! __MSVCRT__ */
+
+#define environ _environ
+
+#ifdef	__MSVCRT__
+/* One of the MSVCRTxx libraries */
+
+#ifndef __DECLSPEC_SUPPORTED
+  extern int*	__imp__sys_nerr;
+# define	sys_nerr	(*__imp__sys_nerr)
+#else /* __DECLSPEC_SUPPORTED */
+  __MINGW_IMPORT int	_sys_nerr;
+# ifndef _UWIN
+#   define	sys_nerr	_sys_nerr
+# endif /* _UWIN */
+#endif /* __DECLSPEC_SUPPORTED */
+
+#else /* ! __MSVCRT__ */
+
+/* CRTDLL run time library */
+
+#ifndef __DECLSPEC_SUPPORTED
+  extern int*	__imp__sys_nerr_dll;
+# define sys_nerr	(*__imp__sys_nerr_dll)
+#else /* __DECLSPEC_SUPPORTED */
+  __MINGW_IMPORT int	_sys_nerr_dll;
+# define sys_nerr	_sys_nerr_dll
+#endif /* __DECLSPEC_SUPPORTED */
+
+#endif /* ! __MSVCRT__ */
+
+#ifndef __DECLSPEC_SUPPORTED
+extern char***	__imp__sys_errlist;
+#define	sys_errlist	(*__imp__sys_errlist)
+#else /* __DECLSPEC_SUPPORTED */
+__MINGW_IMPORT char*	_sys_errlist[];
+#ifndef _UWIN
+#define	sys_errlist	_sys_errlist
+#endif /* _UWIN */
+#endif /* __DECLSPEC_SUPPORTED */
+
+/*
+ * OS version and such constants.
+ */
+#ifndef __STRICT_ANSI__
+
+#ifdef	__MSVCRT__
+/* msvcrtxx.dll */
+
+extern unsigned int*	__p__osver(void);
+extern unsigned int*	__p__winver(void);
+extern unsigned int*	__p__winmajor(void);
+extern unsigned int*	__p__winminor(void);
+
+#define _osver		(*__p__osver())
+#define _winver		(*__p__winver())
+#define _winmajor	(*__p__winmajor())
+#define _winminor	(*__p__winminor())
+
+#else
+/* Not msvcrtxx.dll, thus crtdll.dll */
+
+#ifndef __DECLSPEC_SUPPORTED
+
+extern unsigned int*	_imp___osver_dll;
+extern unsigned int*	_imp___winver_dll;
+extern unsigned int*	_imp___winmajor_dll;
+extern unsigned int*	_imp___winminor_dll;
+
+#define _osver		(*_imp___osver_dll)
+#define _winver		(*_imp___winver_dll)
+#define _winmajor	(*_imp___winmajor_dll)
+#define _winminor	(*_imp___winminor_dll)
+
+#else /* __DECLSPEC_SUPPORTED */
+
+__MINGW_IMPORT unsigned int	_osver_dll;
+__MINGW_IMPORT unsigned int	_winver_dll;
+__MINGW_IMPORT unsigned int	_winmajor_dll;
+__MINGW_IMPORT unsigned int	_winminor_dll;
+
+#define _osver		_osver_dll
+#define _winver		_winver_dll
+#define _winmajor	_winmajor_dll
+#define _winminor	_winminor_dll
+
+#endif /* __DECLSPEC_SUPPORTED */
+
+#endif
+
+#if defined  __MSVCRT__
+/* although the _pgmptr is exported as DATA,
+ * be safe and use the access function __p__pgmptr() to get it. */
+char**  __p__pgmptr(void);
+#define _pgmptr     (*__p__pgmptr())
+wchar_t**  __p__wpgmptr(void);
+#define _wpgmptr    (*__p__wpgmptr())
+#else /* ! __MSVCRT__ */
+# ifndef __DECLSPEC_SUPPORTED
+  extern char** __imp__pgmptr_dll;
+# define _pgmptr (*__imp__pgmptr_dll)
+# else /* __DECLSPEC_SUPPORTED */
+ __MINGW_IMPORT char* _pgmptr_dll;
+# define _pgmptr _pgmptr_dll
+# endif /* __DECLSPEC_SUPPORTED */
+/* no wide version in CRTDLL */
+#endif /* __MSVCRT__ */
+
+#endif /* Not __STRICT_ANSI__ */
+
+#ifdef	__GNUC__
+#define	_ATTRIB_NORETURN	__attribute__ ((noreturn))
+#else	/* Not __GNUC__ */
+#define	_ATTRIB_NORETURN
+#endif	/* __GNUC__ */
+
+double	atof	(const char*);
+int	atoi	(const char*);
+long	atol	(const char*);
+int	_wtoi (const wchar_t *);
+long _wtol (const wchar_t *);
+
+double	strtod	(const char*, char**);
+#if !defined __NO_ISOCEXT  /* extern stubs in static libmingwex.a */
+extern __inline__ float strtof (const char *nptr, char **endptr)
+  { return (strtod (nptr, endptr));}
+#endif /* __NO_ISOCEXT */
+
+long	strtol	(const char*, char**, int);
+unsigned long	strtoul	(const char*, char**, int);
+
+#ifndef _WSTDLIB_DEFINED
+/*  also declared in wchar.h */
+double	wcstod	(const wchar_t*, wchar_t**);
+#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */
+extern __inline__ float wcstof( const wchar_t *nptr, wchar_t **endptr)
+{  return (wcstod(nptr, endptr)); }
+#endif /* __NO_ISOCEXT */
+
+long	wcstol	(const wchar_t*, wchar_t**, int);
+unsigned long	wcstoul (const wchar_t*, wchar_t**, int);
+#define _WSTDLIB_DEFINED
+#endif
+
+size_t	wcstombs	(char*, const wchar_t*, size_t);
+int	wctomb		(char*, wchar_t);
+
+int	mblen		(const char*, size_t);
+size_t	mbstowcs	(wchar_t*, const char*, size_t);
+int	mbtowc		(wchar_t*, const char*, size_t);
+
+int	rand	(void);
+void	srand	(unsigned int);
+
+void*	calloc	(size_t, size_t);
+void*	malloc	(size_t);
+void*	realloc	(void*, size_t);
+void	free	(void*);
+
+void	abort	(void) _ATTRIB_NORETURN;
+void	exit	(int) _ATTRIB_NORETURN;
+int	atexit	(void (*)(void));
+
+int	system	(const char*);
+char*	getenv	(const char*);
+
+void*	bsearch	(const void*, const void*, size_t, size_t, 
+                 int (*)(const void*, const void*));
+void	qsort	(const void*, size_t, size_t,
+                 int (*)(const void*, const void*));
+
+int	abs	(int);
+long	labs	(long);
+
+/*
+ * div_t and ldiv_t are structures used to return the results of div and
+ * ldiv.
+ *
+ * NOTE: div and ldiv appear not to work correctly unless
+ *       -fno-pcc-struct-return is specified. This is included in the
+ *       mingw32 specs file.
+ */
+typedef struct { int quot, rem; } div_t;
+typedef struct { long quot, rem; } ldiv_t;
+
+div_t	div	(int, int);
+ldiv_t	ldiv	(long, long);
+
+#ifndef	__STRICT_ANSI__
+
+/*
+ * NOTE: Officially the three following functions are obsolete. The Win32 API
+ *       functions SetErrorMode, Beep and Sleep are their replacements.
+ */
+void	_beep (unsigned int, unsigned int);
+void	_seterrormode (int);
+void	_sleep (unsigned long);
+
+void	_exit	(int) _ATTRIB_NORETURN;
+#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */
+/* C99 function name */
+void _Exit(int) _ATTRIB_NORETURN; /* Declare to get noreturn attribute.  */
+extern __inline__ void _Exit(int status)
+	{  _exit(status); }
+#endif
+/* _onexit is MS extension. Use atexit for portability.  */
+typedef  int (* _onexit_t)(void); 
+_onexit_t _onexit( _onexit_t );
+
+int	_putenv	(const char*);
+void	_searchenv (const char*, const char*, char*);
+
+
+char*	_ecvt (double, int, int*, int*);
+char*	_fcvt (double, int, int*, int*);
+char*	_gcvt (double, int, char*);
+
+void	_makepath (char*, const char*, const char*, const char*, const char*);
+void	_splitpath (const char*, char*, char*, char*, char*);
+char*	_fullpath (char*, const char*, size_t);
+
+
+char*	_itoa (int, char*, int);
+char*	_ltoa (long, char*, int);
+char*   _ultoa(unsigned long, char*, int);
+wchar_t*  _itow (int, wchar_t*, int);
+wchar_t*  _ltow (long, wchar_t*, int);
+wchar_t*  _ultow (unsigned long, wchar_t*, int);
+
+#ifdef __MSVCRT__
+__int64	_atoi64(const char *);
+char*	_i64toa(__int64, char *, int);
+char*	_ui64toa(unsigned __int64, char *, int);
+__int64	_wtoi64(const wchar_t *);
+wchar_t* _i64tow(__int64, wchar_t *, int);
+wchar_t* _ui64tow(unsigned __int64, wchar_t *, int);
+
+wchar_t* _wgetenv(const wchar_t*);
+int	 _wputenv(const wchar_t*);
+void	_wsearchenv(const wchar_t*, const wchar_t*, wchar_t*);
+void    _wmakepath(wchar_t*, const wchar_t*, const wchar_t*, const wchar_t*, const wchar_t*);
+void	_wsplitpath (const wchar_t*, wchar_t*, wchar_t*, wchar_t*, wchar_t*);
+wchar_t*    _wfullpath (wchar_t*, const wchar_t*, size_t);
+#endif
+
+#ifndef	_NO_OLDNAMES
+
+int	putenv (const char*);
+void	searchenv (const char*, const char*, char*);
+
+char*	itoa (int, char*, int);
+char*	ltoa (long, char*, int);
+
+#ifndef _UWIN
+char*	ecvt (double, int, int*, int*);
+char*	fcvt (double, int, int*, int*);
+char*	gcvt (double, int, char*);
+#endif /* _UWIN */
+#endif	/* Not _NO_OLDNAMES */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+/* C99 names */
+
+#if !defined __NO_ISOCEXT /* externs in static libmingwex.a */
+
+typedef struct { long long quot, rem; } lldiv_t;
+
+lldiv_t	lldiv (long long, long long);
+
+extern __inline__ long long llabs(long long _j)
+  {return (_j >= 0 ? _j : -_j);}
+
+long long strtoll (const char* __restrict__, char** __restrict, int);
+unsigned long long strtoull (const char* __restrict__, char** __restrict__, int);
+
+#if defined (__MSVCRT__) /* these are stubs for MS _i64 versions */ 
+long long atoll (const char *);
+
+#if !defined (__STRICT_ANSI__)
+long long wtoll(const wchar_t *);
+char* lltoa(long long, char *, int);
+char* ulltoa(unsigned long long , char *, int);
+wchar_t* lltow(long long, wchar_t *, int);
+wchar_t* ulltow(unsigned long long, wchar_t *, int);
+
+  /* inline using non-ansi functions */
+extern __inline__ long long atoll (const char * _c)
+	{ return _atoi64 (_c); }
+extern __inline__ char* lltoa(long long _n, char * _c, int _i)
+	{ return _i64toa (_n, _c, _i); }
+extern __inline__ char* ulltoa(unsigned long long _n, char * _c, int _i)
+	{ return _ui64toa (_n, _c, _i); }
+extern __inline__ long long wtoll(const wchar_t * _w)
+ 	{ return _wtoi64 (_w); }
+extern __inline__ wchar_t* lltow(long long _n, wchar_t * _w, int _i)
+	{ return _i64tow (_n, _w, _i); } 
+extern __inline__ wchar_t* ulltow(unsigned long long _n, wchar_t * _w, int _i)
+	{ return _ui64tow (_n, _w, _i); } 
+#endif /* (__STRICT_ANSI__)  */
+
+#endif /* __MSVCRT__ */
+
+#endif /* !__NO_ISOCEXT */
+
+/*
+ * Undefine the no return attribute used in some function definitions
+ */
+#undef	_ATTRIB_NORETURN
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _STDLIB_H_ */
+
diff --git a/tinyc/win32/include/string.h b/tinyc/win32/include/string.h
new file mode 100644
index 000000000..03dd48f8c
--- /dev/null
+++ b/tinyc/win32/include/string.h
@@ -0,0 +1,206 @@
+/*
+ * string.h
+ *
+ * Definitions for memory and string functions.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef _STRING_H_
+#define	_STRING_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * Define size_t, wchar_t and NULL
+ */
+#define __need_size_t
+#define __need_wchar_t
+#define	__need_NULL
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Prototypes of the ANSI Standard C library string functions.
+ */
+void*	memchr (const void*, int, size_t);
+int 	memcmp (const void*, const void*, size_t);
+void* 	memcpy (void*, const void*, size_t);
+void*	memmove (void*, const void*, size_t);
+void*	memset (void*, int, size_t);
+char*	strcat (char*, const char*);
+char*	strchr (const char*, int);
+int	strcmp (const char*, const char*);
+int	strcoll (const char*, const char*);	/* Compare using locale */
+char*	strcpy (char*, const char*);
+size_t	strcspn (const char*, const char*);
+char*	strerror (int); /* NOTE: NOT an old name wrapper. */
+char*	_strerror (const char *);
+size_t	strlen (const char*);
+char*	strncat (char*, const char*, size_t);
+int	strncmp (const char*, const char*, size_t);
+char*	strncpy (char*, const char*, size_t);
+char*	strpbrk (const char*, const char*);
+char*	strrchr (const char*, int);
+size_t	strspn (const char*, const char*);
+char*	strstr (const char*, const char*);
+char*	strtok (char*, const char*);
+size_t	strxfrm (char*, const char*, size_t);
+
+#ifndef __STRICT_ANSI__
+/*
+ * Extra non-ANSI functions provided by the CRTDLL library
+ */
+void*	_memccpy (void*, const void*, int, size_t);
+int 	_memicmp (const void*, const void*, size_t);
+char* 	_strdup (const char*);
+int	_strcmpi (const char*, const char*);
+int	_stricmp (const char*, const char*);
+int	_stricoll (const char*, const char*);
+char*	_strlwr (char*);
+int	_strnicmp (const char*, const char*, size_t);
+char*	_strnset (char*, int, size_t);
+char*	_strrev (char*);
+char*	_strset (char*, int);
+char*	_strupr (char*);
+void	_swab (const char*, char*, size_t);
+
+/*
+ * Multi-byte character functions
+ */
+unsigned char*	_mbschr (unsigned char*, unsigned char*);
+unsigned char*	_mbsncat (unsigned char*, const unsigned char*, size_t);
+unsigned char*	_mbstok (unsigned char*, unsigned char*);
+
+#ifdef __MSVCRT__
+int  _strncoll(const char*, const char*, size_t);
+int  _strnicoll(const char*, const char*, size_t);
+#endif
+
+#endif	/* Not __STRICT_ANSI__ */
+
+/*
+ * Unicode versions of the standard calls.
+ */
+wchar_t* wcscat (wchar_t*, const wchar_t*);
+wchar_t* wcschr (const wchar_t*, wchar_t);
+int	wcscmp (const wchar_t*, const wchar_t*);
+int	wcscoll (const wchar_t*, const wchar_t*);
+wchar_t* wcscpy (wchar_t*, const wchar_t*);
+size_t	wcscspn (const wchar_t*, const wchar_t*);
+/* Note: No wcserror in CRTDLL. */
+size_t	wcslen (const wchar_t*);
+wchar_t* wcsncat (wchar_t*, const wchar_t*, size_t);
+int	wcsncmp(const wchar_t*, const wchar_t*, size_t);
+wchar_t* wcsncpy(wchar_t*, const wchar_t*, size_t);
+wchar_t* wcspbrk(const wchar_t*, const wchar_t*);
+wchar_t* wcsrchr(const wchar_t*, wchar_t);
+size_t	wcsspn(const wchar_t*, const wchar_t*);
+wchar_t* wcsstr(const wchar_t*, const wchar_t*);
+wchar_t* wcstok(wchar_t*, const wchar_t*);
+size_t	wcsxfrm(wchar_t*, const wchar_t*, size_t);
+
+#ifndef	__STRICT_ANSI__
+/*
+ * Unicode versions of non-ANSI functions provided by CRTDLL.
+ */
+
+/* NOTE: _wcscmpi not provided by CRTDLL, this define is for portability */
+#define		_wcscmpi	_wcsicmp
+
+wchar_t* _wcsdup (wchar_t*);
+int	_wcsicmp (const wchar_t*, const wchar_t*);
+int	_wcsicoll (const wchar_t*, const wchar_t*);
+wchar_t* _wcslwr (wchar_t*);
+int	_wcsnicmp (const wchar_t*, const wchar_t*, size_t);
+wchar_t* _wcsnset (wchar_t*, wchar_t, size_t);
+wchar_t* _wcsrev (wchar_t*);
+wchar_t* _wcsset (wchar_t*, wchar_t);
+wchar_t* _wcsupr (wchar_t*);
+
+#ifdef __MSVCRT__
+int  _wcsncoll(const wchar_t*, const wchar_t*, size_t);
+int  _wcsnicoll(const wchar_t*, const wchar_t*, size_t);
+#endif
+
+
+#endif	/* Not __STRICT_ANSI__ */
+
+
+#ifndef	__STRICT_ANSI__
+#ifndef	_NO_OLDNAMES
+
+/*
+ * Non-underscored versions of non-ANSI functions. They live in liboldnames.a
+ * and provide a little extra portability. Also a few extra UNIX-isms like
+ * strcasecmp.
+ */
+
+void*	memccpy (void*, const void*, int, size_t);
+int	memicmp (const void*, const void*, size_t);
+char*	strdup (const char*);
+int	strcmpi (const char*, const char*);
+int	stricmp (const char*, const char*);
+int	strcasecmp (const char*, const char*);
+int	stricoll (const char*, const char*);
+char*	strlwr (char*);
+int	strnicmp (const char*, const char*, size_t);
+int	strncasecmp (const char*, const char*, size_t);
+char*	strnset (char*, int, size_t);
+char*	strrev (char*);
+char*	strset (char*, int);
+char*	strupr (char*);
+#ifndef _UWIN
+void	swab (const char*, char*, size_t);
+#endif /* _UWIN */
+
+/* NOTE: There is no _wcscmpi, but this is for compatibility. */
+int	wcscmpi	(const wchar_t*, const wchar_t*);
+wchar_t* wcsdup (wchar_t*);
+int	wcsicmp (const wchar_t*, const wchar_t*);
+int	wcsicoll (const wchar_t*, const wchar_t*);
+wchar_t* wcslwr (wchar_t*);
+int	wcsnicmp (const wchar_t*, const wchar_t*, size_t);
+wchar_t* wcsnset (wchar_t*, wchar_t, size_t);
+wchar_t* wcsrev (wchar_t*);
+wchar_t* wcsset (wchar_t*, wchar_t);
+wchar_t* wcsupr (wchar_t*);
+
+#endif	/* Not _NO_OLDNAMES */
+#endif	/* Not strict ANSI */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _STRING_H_ */
+
diff --git a/tinyc/win32/include/sys/fcntl.h b/tinyc/win32/include/sys/fcntl.h
new file mode 100644
index 000000000..b343f272f
--- /dev/null
+++ b/tinyc/win32/include/sys/fcntl.h
@@ -0,0 +1,8 @@
+/*
+ * This file is part of the Mingw32 package.
+ *
+ * This fcntl.h maps to the root fcntl.h
+ */
+#ifndef __STRICT_ANSI__
+#include <fcntl.h>
+#endif
diff --git a/tinyc/win32/include/sys/file.h b/tinyc/win32/include/sys/file.h
new file mode 100644
index 000000000..96c49e117
--- /dev/null
+++ b/tinyc/win32/include/sys/file.h
@@ -0,0 +1,9 @@
+/*
+ * This file is part of the Mingw32 package.
+ *
+ * This file.h maps to the root fcntl.h
+ * TODO?
+ */
+#ifndef __STRICT_ANSI__
+#include <fcntl.h>
+#endif
diff --git a/tinyc/win32/include/sys/locking.h b/tinyc/win32/include/sys/locking.h
new file mode 100644
index 000000000..2ecd11628
--- /dev/null
+++ b/tinyc/win32/include/sys/locking.h
@@ -0,0 +1,52 @@
+/*
+ * locking.h
+ *
+ * Constants for the mode parameter of the locking function.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_LOCKING_H_
+#define	_LOCKING_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define	_LK_UNLCK	0	/* Unlock */
+#define	_LK_LOCK	1	/* Lock */
+#define	_LK_NBLCK	2	/* Non-blocking lock */
+#define	_LK_RLCK	3	/* Lock for read only */
+#define	_LK_NBRLCK	4	/* Non-blocking lock for read only */
+
+#ifndef	NO_OLDNAMES
+#define	LK_UNLCK	_LK_UNLCK
+#define	LK_LOCK		_LK_LOCK
+#define	LK_NBLCK	_LK_NBLCK
+#define	LK_RLCK		_LK_RLCK
+#define	LK_NBRLCK	_LK_NBRLCK
+#endif	/* Not NO_OLDNAMES */
+
+#endif	/* Not _LOCKING_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/sys/stat.h b/tinyc/win32/include/sys/stat.h
new file mode 100644
index 000000000..0e2054942
--- /dev/null
+++ b/tinyc/win32/include/sys/stat.h
@@ -0,0 +1,190 @@
+/*
+ * stat.h
+ *
+ * Symbolic constants for opening and creating files, also stat, fstat and
+ * chmod functions.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef __STRICT_ANSI__
+
+#ifndef _STAT_H_
+#define _STAT_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_size_t
+#define __need_wchar_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif /* Not RC_INVOKED */
+
+#include <sys/types.h>
+
+/*
+ * Constants for the stat st_mode member.
+ */
+#define	_S_IFIFO	0x1000	/* FIFO */
+#define	_S_IFCHR	0x2000	/* Character */
+#define	_S_IFBLK	0x3000	/* Block: Is this ever set under w32? */
+#define	_S_IFDIR	0x4000	/* Directory */
+#define	_S_IFREG	0x8000	/* Regular */
+
+#define	_S_IFMT		0xF000	/* File type mask */
+
+#define	_S_IEXEC	0x0040
+#define	_S_IWRITE	0x0080
+#define	_S_IREAD	0x0100
+
+#define	_S_IRWXU	(_S_IREAD | _S_IWRITE | _S_IEXEC)
+#define	_S_IXUSR	_S_IEXEC
+#define	_S_IWUSR	_S_IWRITE
+#define	_S_IRUSR	_S_IREAD
+
+#define	_S_ISDIR(m)	(((m) & _S_IFMT) == _S_IFDIR)
+#define	_S_ISFIFO(m)	(((m) & _S_IFMT) == _S_IFIFO)
+#define	_S_ISCHR(m)	(((m) & _S_IFMT) == _S_IFCHR)
+#define	_S_ISBLK(m)	(((m) & _S_IFMT) == _S_IFBLK)
+#define	_S_ISREG(m)	(((m) & _S_IFMT) == _S_IFREG)
+
+#ifndef _NO_OLDNAMES
+
+#define	S_IFIFO		_S_IFIFO
+#define	S_IFCHR		_S_IFCHR
+#define	S_IFBLK		_S_IFBLK
+#define	S_IFDIR		_S_IFDIR
+#define	S_IFREG		_S_IFREG
+#define	S_IFMT		_S_IFMT
+#define	S_IEXEC		_S_IEXEC
+#define	S_IWRITE	_S_IWRITE
+#define	S_IREAD		_S_IREAD
+#define	S_IRWXU		_S_IRWXU
+#define	S_IXUSR		_S_IXUSR
+#define	S_IWUSR		_S_IWUSR
+#define	S_IRUSR		_S_IRUSR
+
+#define	S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
+#define	S_ISFIFO(m)	(((m) & S_IFMT) == S_IFIFO)
+#define	S_ISCHR(m)	(((m) & S_IFMT) == S_IFCHR)
+#define	S_ISBLK(m)	(((m) & S_IFMT) == S_IFBLK)
+#define	S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)
+
+#endif	/* Not _NO_OLDNAMES */
+
+#ifndef RC_INVOKED
+
+#ifndef _STAT_DEFINED
+/*
+ * The structure manipulated and returned by stat and fstat.
+ *
+ * NOTE: If called on a directory the values in the time fields are not only
+ * invalid, they will cause localtime et. al. to return NULL. And calling
+ * asctime with a NULL pointer causes an Invalid Page Fault. So watch it!
+ */
+struct _stat
+{
+	_dev_t	st_dev;		/* Equivalent to drive number 0=A 1=B ... */
+	_ino_t	st_ino;		/* Always zero ? */
+	_mode_t	st_mode;	/* See above constants */
+	short	st_nlink;	/* Number of links. */
+	short	st_uid;		/* User: Maybe significant on NT ? */
+	short	st_gid;		/* Group: Ditto */
+	_dev_t	st_rdev;	/* Seems useless (not even filled in) */
+	_off_t	st_size;	/* File size in bytes */
+	time_t	st_atime;	/* Accessed date (always 00:00 hrs local
+				 * on FAT) */
+	time_t	st_mtime;	/* Modified time */
+	time_t	st_ctime;	/* Creation time */
+};
+
+struct stat
+{
+	_dev_t	st_dev;		/* Equivalent to drive number 0=A 1=B ... */
+	_ino_t	st_ino;		/* Always zero ? */
+	_mode_t	st_mode;	/* See above constants */
+	short	st_nlink;	/* Number of links. */
+	short	st_uid;		/* User: Maybe significant on NT ? */
+	short	st_gid;		/* Group: Ditto */
+	_dev_t	st_rdev;	/* Seems useless (not even filled in) */
+	_off_t	st_size;	/* File size in bytes */
+	time_t	st_atime;	/* Accessed date (always 00:00 hrs local
+				 * on FAT) */
+	time_t	st_mtime;	/* Modified time */
+	time_t	st_ctime;	/* Creation time */
+};
+#if defined (__MSVCRT__)
+struct _stati64 {
+    _dev_t st_dev;
+    _ino_t st_ino;
+    unsigned short st_mode;
+    short st_nlink;
+    short st_uid;
+    short st_gid;
+    _dev_t st_rdev;
+    __int64 st_size;
+    time_t st_atime;
+    time_t st_mtime;
+    time_t st_ctime;
+};
+#endif /* __MSVCRT__ */
+#define _STAT_DEFINED
+#endif /* _STAT_DEFINED */
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int	_fstat (int, struct _stat*);
+int	_chmod (const char*, int);
+int	_stat (const char*, struct _stat*);
+
+#if defined (__MSVCRT__)
+int  _fstati64(int, struct _stati64 *);
+int  _stati64(const char *, struct _stati64 *);
+#if !defined ( _WSTAT_DEFINED) /* also declared in wchar.h */
+int	_wstat(const wchar_t*, struct _stat*);
+int	_wstati64 (const wchar_t*, struct _stati64*);
+#define _WSTAT_DEFINED
+#endif /* _WSTAT_DEFIND */
+#endif /* __MSVCRT__ */
+
+#ifndef	_NO_OLDNAMES
+
+/* These functions live in liboldnames.a. */
+int	fstat (int, struct stat*);
+int	chmod (const char*, int);
+int	stat (const char*, struct stat*);
+
+#endif	/* Not _NO_OLDNAMES */
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _STAT_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/sys/time.h b/tinyc/win32/include/sys/time.h
new file mode 100644
index 000000000..39d85f67b
--- /dev/null
+++ b/tinyc/win32/include/sys/time.h
@@ -0,0 +1,3 @@
+
+#include <time.h>
+
diff --git a/tinyc/win32/include/sys/timeb.h b/tinyc/win32/include/sys/timeb.h
new file mode 100644
index 000000000..b5bb0fc3d
--- /dev/null
+++ b/tinyc/win32/include/sys/timeb.h
@@ -0,0 +1,82 @@
+/*
+ * timeb.h
+ *
+ * Support for the UNIX System V ftime system call.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_TIMEB_H_
+#define	_TIMEB_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#ifndef	RC_INVOKED
+
+/*
+ * TODO: Structure not tested.
+ */
+struct _timeb
+{
+	long	time;
+	short	millitm;
+	short	timezone;
+	short	dstflag;
+};
+
+#ifndef	_NO_OLDNAMES
+/*
+ * TODO: Structure not tested.
+ */
+struct timeb
+{
+	long	time;
+	short	millitm;
+	short	timezone;
+	short	dstflag;
+};
+#endif
+
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* TODO: Not tested. */
+void	_ftime (struct _timeb*);
+
+#ifndef	_NO_OLDNAMES
+void	ftime (struct timeb*);
+#endif	/* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _TIMEB_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/sys/types.h b/tinyc/win32/include/sys/types.h
new file mode 100644
index 000000000..0679ac9b3
--- /dev/null
+++ b/tinyc/win32/include/sys/types.h
@@ -0,0 +1,118 @@
+/*
+ * types.h
+ *
+ * The definition of constants, data types and global variables.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *  Lots of types supplied by Pedro A. Aranda <paag@tid.es>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warrenties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	_TYPES_H_
+#define	_TYPES_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_wchar_t
+#define __need_size_t
+#define __need_ptrdiff_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+#ifndef RC_INVOKED
+
+#ifndef _TIME_T_DEFINED
+typedef	long	time_t;
+#define	_TIME_T_DEFINED
+#endif
+
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_OFF_T_
+#define	_OFF_T_
+typedef long _off_t;
+
+#ifndef	_NO_OLDNAMES
+typedef _off_t	off_t;
+#endif
+#endif	/* Not _OFF_T_ */
+
+
+#ifndef _DEV_T_
+#define	_DEV_T_
+#ifdef __MSVCRT__
+typedef unsigned int _dev_t;
+#else
+typedef short _dev_t;
+#endif
+
+#ifndef	_NO_OLDNAMES
+typedef _dev_t	dev_t;
+#endif
+#endif	/* Not _DEV_T_ */
+
+
+#ifndef _INO_T_
+#define	_INO_T_
+typedef short _ino_t;
+
+#ifndef	_NO_OLDNAMES
+typedef _ino_t	ino_t;
+#endif
+#endif	/* Not _INO_T_ */
+
+
+#ifndef _PID_T_
+#define	_PID_T_
+typedef int	_pid_t;
+
+#ifndef	_NO_OLDNAMES
+typedef _pid_t	pid_t;
+#endif
+#endif	/* Not _PID_T_ */
+
+
+#ifndef _MODE_T_
+#define	_MODE_T_
+typedef unsigned short _mode_t;
+
+#ifndef	_NO_OLDNAMES
+typedef _mode_t	mode_t;
+#endif
+#endif	/* Not _MODE_T_ */
+
+
+#ifndef _SIGSET_T_
+#define	_SIGSET_T_
+typedef int	_sigset_t;
+
+#ifndef	_NO_OLDNAMES
+typedef _sigset_t	sigset_t;
+#endif
+#endif	/* Not _SIGSET_T_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _TYPES_H_ */
diff --git a/tinyc/win32/include/sys/unistd.h b/tinyc/win32/include/sys/unistd.h
new file mode 100644
index 000000000..ed122d9dd
--- /dev/null
+++ b/tinyc/win32/include/sys/unistd.h
@@ -0,0 +1,9 @@
+/*
+ * This file is part of the Mingw32 package.
+ *
+ * unistd.h maps (roughly) to io.h
+ */
+#ifndef __STRICT_ANSI__
+#include <io.h>
+#endif
+
diff --git a/tinyc/win32/include/sys/utime.h b/tinyc/win32/include/sys/utime.h
new file mode 100644
index 000000000..049524bed
--- /dev/null
+++ b/tinyc/win32/include/sys/utime.h
@@ -0,0 +1,89 @@
+/*
+ * utime.h
+ *
+ * Support for the utime function.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_UTIME_H_
+#define	_UTIME_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_wchar_t
+#define __need_size_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+#include <sys/types.h>
+
+#ifndef	RC_INVOKED
+
+/*
+ * Structure used by _utime function.
+ */
+struct _utimbuf
+{
+	time_t	actime;		/* Access time */
+	time_t	modtime;	/* Modification time */
+};
+
+
+#ifndef	_NO_OLDNAMES
+/* NOTE: Must be the same as _utimbuf above. */
+struct utimbuf
+{
+	time_t	actime;
+	time_t	modtime;
+};
+#endif	/* Not _NO_OLDNAMES */
+
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int	_utime (const char*, struct _utimbuf*);
+int	_futime (int, struct _utimbuf*);
+
+/* The wide character version, only available for MSVCRT versions of the
+ * C runtime library. */
+#ifdef __MSVCRT__
+int	_wutime (const wchar_t*, struct _utimbuf*);
+#endif /* MSVCRT runtime */
+#ifndef	_NO_OLDNAMES
+int	utime (const char*, struct utimbuf*);
+#endif	/* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _UTIME_H_ */
+
+#endif	/* Not __STRICT_ANSI__ */
+
diff --git a/tinyc/win32/include/tchar.h b/tinyc/win32/include/tchar.h
new file mode 100644
index 000000000..72c1b3c81
--- /dev/null
+++ b/tinyc/win32/include/tchar.h
@@ -0,0 +1,367 @@
+/* 
+ * tchar.h
+ *
+ * Unicode mapping layer for the standard C library. By including this
+ * file and using the 't' names for string functions
+ * (eg. _tprintf) you can make code which can be easily adapted to both
+ * Unicode and non-unicode environments. In a unicode enabled compile define
+ * _UNICODE before including tchar.h, otherwise the standard non-unicode
+ * library functions will be used.
+ *
+ * Note that you still need to include string.h or stdlib.h etc. to define
+ * the appropriate functions. Also note that there are several defines
+ * included for non-ANSI functions which are commonly available (but using
+ * the convention of prepending an underscore to non-ANSI library function
+ * names).
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	_TCHAR_H_
+#define _TCHAR_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+/*
+ * NOTE: This tests _UNICODE, which is different from the UNICODE define
+ *       used to differentiate Win32 API calls.
+ */
+#ifdef	_UNICODE
+
+
+/*
+ * Use TCHAR instead of char or wchar_t. It will be appropriately translated
+ * if _UNICODE is correctly defined (or not).
+ */
+#ifndef _TCHAR_DEFINED
+#ifndef RC_INVOKED
+typedef	wchar_t	TCHAR;
+typedef wchar_t _TCHAR;
+#endif	/* Not RC_INVOKED */
+#define _TCHAR_DEFINED
+#endif
+
+
+/*
+ * __TEXT is a private macro whose specific use is to force the expansion of a
+ * macro passed as an argument to the macros _T or _TEXT.  DO NOT use this
+ * macro within your programs.  It's name and function could change without
+ * notice.
+ */
+#define	__TEXT(x)	L##x
+
+/*  for porting from other Windows compilers */
+#if 0  // no  wide startup module
+#define _tmain      wmain
+#define _tWinMain   wWinMain
+#define _tenviron   _wenviron
+#define __targv     __wargv
+#endif
+
+/*
+ * Unicode functions
+ */
+#define	_tprintf	wprintf
+#define	_ftprintf	fwprintf
+#define	_stprintf	swprintf
+#define	_sntprintf	_snwprintf
+#define	_vtprintf	vwprintf
+#define	_vftprintf	vfwprintf
+#define _vstprintf	vswprintf
+#define	_vsntprintf	_vsnwprintf
+#define	_tscanf		wscanf
+#define	_ftscanf	fwscanf
+#define	_stscanf	swscanf
+#define	_fgettc		fgetwc
+#define	_fgettchar	_fgetwchar
+#define	_fgetts		fgetws
+#define	_fputtc		fputwc
+#define	_fputtchar	_fputwchar
+#define	_fputts		fputws
+#define	_gettc		getwc
+#define	_getts		getws
+#define	_puttc		putwc
+#define	_putts		putws
+#define	_ungettc	ungetwc
+#define	_tcstod		wcstod
+#define	_tcstol		wcstol
+#define _tcstoul	wcstoul
+#define	_itot		_itow
+#define	_ltot		_ltow
+#define	_ultot		_ultow
+#define	_ttoi		_wtoi
+#define	_ttol		_wtol
+#define	_tcscat		wcscat
+#define _tcschr		wcschr
+#define _tcscmp		wcscmp
+#define _tcscpy		wcscpy
+#define _tcscspn	wcscspn
+#define	_tcslen		wcslen
+#define	_tcsncat	wcsncat
+#define	_tcsncmp	wcsncmp
+#define	_tcsncpy	wcsncpy
+#define	_tcspbrk	wcspbrk
+#define	_tcsrchr	wcsrchr
+#define _tcsspn		wcsspn
+#define	_tcsstr		wcsstr
+#define _tcstok		wcstok
+#define	_tcsdup		_wcsdup
+#define	_tcsicmp	_wcsicmp
+#define	_tcsnicmp	_wcsnicmp
+#define	_tcsnset	_wcsnset
+#define	_tcsrev		_wcsrev
+#define _tcsset		_wcsset
+#define	_tcslwr		_wcslwr
+#define	_tcsupr		_wcsupr
+#define	_tcsxfrm	wcsxfrm
+#define	_tcscoll	wcscoll
+#define	_tcsicoll	_wcsicoll
+#define	_istalpha	iswalpha
+#define	_istupper	iswupper
+#define	_istlower	iswlower
+#define	_istdigit	iswdigit
+#define	_istxdigit	iswxdigit
+#define	_istspace	iswspace
+#define	_istpunct	iswpunct
+#define	_istalnum	iswalnum
+#define	_istprint	iswprint
+#define	_istgraph	iswgraph
+#define	_istcntrl	iswcntrl
+#define	_istascii	iswascii
+#define _totupper	towupper
+#define	_totlower	towlower
+#define _tcsftime	wcsftime
+/* Macro functions */ 
+#define _tcsdec     _wcsdec
+#define _tcsinc     _wcsinc
+#define _tcsnbcnt   _wcsncnt
+#define _tcsnccnt   _wcsncnt
+#define _tcsnextc   _wcsnextc
+#define _tcsninc    _wcsninc
+#define _tcsspnp    _wcsspnp
+#define _wcsdec(_wcs1, _wcs2) ((_wcs1)>=(_wcs2) ? NULL : (_wcs2)-1)
+#define _wcsinc(_wcs)  ((_wcs)+1)
+#define _wcsnextc(_wcs) ((unsigned int) *(_wcs))
+#define _wcsninc(_wcs, _inc) (((_wcs)+(_inc)))
+#define _wcsncnt(_wcs, _cnt) ((wcslen(_wcs)>_cnt) ? _count : wcslen(_wcs))
+#define _wcsspnp(_wcs1, _wcs2) ((*((_wcs1)+wcsspn(_wcs1,_wcs2))) ? ((_wcs1)+wcsspn(_wcs1,_wcs2)) : NULL)
+
+#if 1  // defined __MSVCRT__
+/*
+ *   These wide functions not in crtdll.dll.
+ *   Define macros anyway so that _wfoo rather than _tfoo is undefined
+ */
+#define _ttoi64     _wtoi64
+#define _i64tot     _i64tow
+#define _ui64tot    _ui64tow
+#define	_tasctime	_wasctime
+#define	_tctime		_wctime
+#define	_tstrdate	_wstrdate
+#define	_tstrtime	_wstrtime
+#define	_tutime		_wutime
+#define _tcsnccoll  _wcsncoll
+#define _tcsncoll   _wcsncoll
+#define _tcsncicoll _wcsnicoll
+#define _tcsnicoll  _wcsnicoll
+#define _taccess    _waccess
+#define _tchmod     _wchmod
+#define _tcreat     _wcreat
+#define _tfindfirst _wfindfirst
+#define _tfindnext  _wfindnext
+#define _tfopen     _wfopen
+#define _tgetenv    _wgetenv
+#define _tmktemp    _wmktemp
+#define _topen      _wopen
+#define _tremove    _wremove
+#define _trename    _wrename
+#define _tsopen     _wsopen
+#define _tsetlocale _wsetlocale
+#define _tunlink    _wunlink
+#define _tfinddata_t    _wfinddata_t
+#define _tfindfirsti64  _wfindfirsti64
+#define _tfindnexti64   _wfindnexti64
+#define _tfinddatai64_t _wfinddatai64_t
+#endif  /* __MSVCRT__ */
+
+#else	/* Not _UNICODE */
+
+/*
+ * TCHAR, the type you should use instead of char.
+ */
+#ifndef _TCHAR_DEFINED
+#ifndef RC_INVOKED
+typedef char	TCHAR;
+typedef char	_TCHAR;
+#endif
+#define _TCHAR_DEFINED
+#endif
+
+/*
+ * __TEXT is a private macro whose specific use is to force the expansion of a
+ * macro passed as an argument to the macros _T or _TEXT.  DO NOT use this
+ * macro within your programs.  It's name and function could change without
+ * notice.
+ */
+#define	__TEXT(x)	x
+
+/*  for porting from other Windows compilers */
+#define _tmain      main
+#define _tWinMain   WinMain
+#define _tenviron  _environ
+#define __targv     __argv
+
+/*
+ * Non-unicode (standard) functions
+ */
+
+#define	_tprintf	printf
+#define _ftprintf	fprintf
+#define	_stprintf	sprintf
+#define	_sntprintf	_snprintf
+#define	_vtprintf	vprintf
+#define	_vftprintf	vfprintf
+#define _vstprintf	vsprintf
+#define	_vsntprintf	_vsnprintf
+#define	_tscanf		scanf
+#define	_ftscanf	fscanf
+#define	_stscanf	sscanf
+#define	_fgettc		fgetc
+#define	_fgettchar	_fgetchar
+#define	_fgetts		fgets
+#define	_fputtc		fputc
+#define	_fputtchar	_fputchar
+#define	_fputts		fputs
+#define	_tfopen		fopen
+#define	_tgetenv	getenv
+#define	_gettc		getc
+#define	_getts		gets
+#define	_puttc		putc
+#define	_putts		puts
+#define	_ungettc	ungetc
+#define	_tcstod		strtod
+#define	_tcstol		strtol
+#define _tcstoul	strtoul
+#define	_itot		_itoa
+#define	_ltot		_ltoa
+#define	_ultot		_ultoa
+#define	_ttoi		atoi
+#define	_ttol		atol
+#define	_tcscat		strcat
+#define _tcschr		strchr
+#define _tcscmp		strcmp
+#define _tcscpy		strcpy
+#define _tcscspn	strcspn
+#define	_tcslen		strlen
+#define	_tcsncat	strncat
+#define	_tcsncmp	strncmp
+#define	_tcsncpy	strncpy
+#define	_tcspbrk	strpbrk
+#define	_tcsrchr	strrchr
+#define _tcsspn		strspn
+#define	_tcsstr		strstr
+#define _tcstok		strtok
+#define	_tcsdup		_strdup
+#define	_tcsicmp	_stricmp
+#define	_tcsnicmp	_strnicmp
+#define	_tcsnset	_strnset
+#define	_tcsrev		_strrev
+#define _tcsset		_strset
+#define	_tcslwr		_strlwr
+#define	_tcsupr		_strupr
+#define	_tcsxfrm	strxfrm
+#define	_tcscoll	strcoll
+#define	_tcsicoll	_stricoll
+#define	_istalpha	isalpha
+#define	_istupper	isupper
+#define	_istlower	islower
+#define	_istdigit	isdigit
+#define	_istxdigit	isxdigit
+#define	_istspace	isspace
+#define	_istpunct	ispunct
+#define	_istalnum	isalnum
+#define	_istprint	isprint
+#define	_istgraph	isgraph
+#define	_istcntrl	iscntrl
+#define	_istascii	isascii
+#define _totupper	toupper
+#define	_totlower	tolower
+#define	_tasctime	asctime
+#define	_tctime		ctime
+#define	_tstrdate	_strdate
+#define	_tstrtime	_strtime
+#define	_tutime		_utime
+#define _tcsftime	strftime
+/* Macro functions */ 
+#define _tcsdec     _strdec
+#define _tcsinc     _strinc
+#define _tcsnbcnt   _strncnt
+#define _tcsnccnt   _strncnt
+#define _tcsnextc   _strnextc
+#define _tcsninc    _strninc
+#define _tcsspnp    _strspnp
+#define _strdec(_str1, _str2) ((_str1)>=(_str2) ? NULL : (_str2)-1)
+#define _strinc(_str)  ((_str)+1)
+#define _strnextc(_str) ((unsigned int) *(_str))
+#define _strninc(_str, _inc) (((_str)+(_inc)))
+#define _strncnt(_str, _cnt) ((strlen(_str)>_cnt) ? _count : strlen(_str))
+#define _strspnp(_str1, _str2) ((*((_str1)+strspn(_str1,_str2))) ? ((_str1)+strspn(_str1,_str2)) : NULL)
+
+#define _tchmod     _chmod
+#define _tcreat     _creat
+#define _tfindfirst _findfirst
+#define _tfindnext  _findnext
+#define _tmktemp    _mktemp
+#define _topen      _open
+#define _taccess    _access
+#define _tremove    remove
+#define _trename    rename
+#define _tsopen     _sopen
+#define _tsetlocale setlocale
+#define _tunlink    _unlink
+#define _tfinddata_t    _finddata_t
+
+
+#if 1  // defined __MSVCRT__
+/* Not in crtdll.dll. Define macros anyway? */
+#define _ttoi64     _atoi64
+#define _i64tot     _i64toa
+#define _ui64tot    _ui64toa
+#define _tcsnccoll  _strncoll
+#define _tcsncoll   _strncoll
+#define _tcsncicoll _strnicoll
+#define _tcsnicoll  _strnicoll
+#define _tfindfirsti64  _findfirsti64
+#define _tfindnexti64   _findnexti64
+#define _tfinddatai64_t _finddatai64_t
+#endif  /* __MSVCRT__ */
+
+#endif	/* Not _UNICODE */
+
+/*
+ * UNICODE a constant string when _UNICODE is defined else returns the string
+ * unmodified.  Also defined in w32api/winnt.h.
+ */
+#define _TEXT(x)	__TEXT(x)
+#define	_T(x)		__TEXT(x)
+
+#endif	/* Not _TCHAR_H_ */
+
diff --git a/tinyc/win32/include/time.h b/tinyc/win32/include/time.h
new file mode 100644
index 000000000..ade7f6db7
--- /dev/null
+++ b/tinyc/win32/include/time.h
@@ -0,0 +1,219 @@
+/* 
+ * time.h
+ *
+ * Date and time functions and types.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	_TIME_H_
+#define	_TIME_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define __need_wchar_t
+#define __need_size_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+/*
+ * Need a definition of time_t.
+ */
+#include <sys/types.h>
+
+/*
+ * Number of clock ticks per second. A clock tick is the unit by which
+ * processor time is measured and is returned by 'clock'.
+ */
+#define	CLOCKS_PER_SEC	((clock_t)1000)
+#define	CLK_TCK		CLOCKS_PER_SEC
+
+
+#ifndef RC_INVOKED
+
+/*
+ * A type for storing the current time and date. This is the number of
+ * seconds since midnight Jan 1, 1970.
+ * NOTE: Normally this is defined by the above include of sys/types.h
+ */
+#ifndef _TIME_T_DEFINED
+typedef	long	time_t;
+#define _TIME_T_DEFINED
+#endif
+
+/*
+ * A type for measuring processor time (in clock ticks).
+ */
+#ifndef _CLOCK_T_DEFINED
+typedef	long	clock_t;
+#define _CLOCK_T_DEFINED
+#endif
+
+
+/*
+ * A structure for storing all kinds of useful information about the
+ * current (or another) time.
+ */
+struct tm
+{
+	int	tm_sec;		/* Seconds: 0-59 (K&R says 0-61?) */
+	int	tm_min;		/* Minutes: 0-59 */
+	int	tm_hour;	/* Hours since midnight: 0-23 */
+	int	tm_mday;	/* Day of the month: 1-31 */
+	int	tm_mon;		/* Months *since* january: 0-11 */
+	int	tm_year;	/* Years since 1900 */
+	int	tm_wday;	/* Days since Sunday (0-6) */
+	int	tm_yday;	/* Days since Jan. 1: 0-365 */
+	int	tm_isdst;	/* +1 Daylight Savings Time, 0 No DST,
+				 * -1 don't know */
+};
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+clock_t	clock (void);
+time_t	time (time_t*);
+double	difftime (time_t, time_t);
+time_t	mktime (struct tm*);
+
+/*
+ * These functions write to and return pointers to static buffers that may
+ * be overwritten by other function calls. Yikes!
+ *
+ * NOTE: localtime, and perhaps the others of the four functions grouped
+ * below may return NULL if their argument is not 'acceptable'. Also note
+ * that calling asctime with a NULL pointer will produce an Invalid Page
+ * Fault and crap out your program. Guess how I know. Hint: stat called on
+ * a directory gives 'invalid' times in st_atime etc...
+ */
+char*		asctime (const struct tm*);
+char*		ctime (const time_t*);
+struct tm*	gmtime (const time_t*);
+struct tm*	localtime (const time_t*);
+
+
+size_t	strftime (char*, size_t, const char*, const struct tm*);
+
+size_t	wcsftime (wchar_t*, size_t, const wchar_t*, const struct tm*);
+
+#ifndef __STRICT_ANSI__
+extern void	_tzset (void);
+
+#ifndef _NO_OLDNAMES
+extern void	tzset (void);
+#endif
+
+size_t	strftime(char*, size_t, const char*, const struct tm*);
+char*	_strdate(char*);
+char*	_strtime(char*);
+
+#endif	/* Not __STRICT_ANSI__ */
+
+/*
+ * _daylight: non zero if daylight savings time is used.
+ * _timezone: difference in seconds between GMT and local time.
+ * _tzname: standard/daylight savings time zone names (an array with two
+ *          elements).
+ */
+#ifdef __MSVCRT__
+
+/* These are for compatibility with pre-VC 5.0 suppied MSVCRT. */
+extern int*	__p__daylight (void);
+extern long*	__p__timezone (void);
+extern char**	__p__tzname (void);
+
+__MINGW_IMPORT int	_daylight;
+__MINGW_IMPORT long	_timezone;
+__MINGW_IMPORT char 	*_tzname[2];
+
+#else /* not __MSVCRT (ie. crtdll) */
+
+#ifndef __DECLSPEC_SUPPORTED
+
+extern int*	__imp__daylight_dll;
+extern long*	__imp__timezone_dll;
+extern char**	__imp__tzname;
+
+#define _daylight	(*__imp__daylight_dll)
+#define _timezone	(*__imp__timezone_dll)
+#define _tzname		(__imp__tzname)
+
+#else /* __DECLSPEC_SUPPORTED */
+
+__MINGW_IMPORT int	_daylight_dll;
+__MINGW_IMPORT long	_timezone_dll;
+__MINGW_IMPORT char*	_tzname[2];
+
+#define _daylight	_daylight_dll
+#define _timezone	_timezone_dll
+
+#endif /* __DECLSPEC_SUPPORTED */
+
+#endif /* not __MSVCRT__ */
+
+#ifndef _NO_OLDNAMES
+
+#ifdef __MSVCRT__
+
+/* These go in the oldnames import library for MSVCRT. */
+__MINGW_IMPORT int	daylight;
+__MINGW_IMPORT long	timezone;
+__MINGW_IMPORT char 	*tzname[2];
+
+#ifndef _WTIME_DEFINED
+
+/* wide function prototypes, also declared in wchar.h */
+
+wchar_t *	_wasctime(const struct tm*);
+wchar_t *	_wctime(const time_t*);
+wchar_t*	_wstrdate(wchar_t*);
+wchar_t*	_wstrtime(wchar_t*);
+
+#define _WTIME_DEFINED
+#endif /* _WTIME_DEFINED */ 
+
+
+#else /* not __MSVCRT__ */
+
+/* CRTDLL is royally messed up when it comes to these macros.
+   TODO: import and alias these via oldnames import library instead 
+   of macros.  */
+
+#define daylight        _daylight
+/* NOTE: timezone not defined because it would conflict with sys/timeb.h.
+   Also, tzname used to a be macro, but now it's in moldname. */
+__MINGW_IMPORT char 	*tzname[2];
+
+#endif /* not __MSVCRT__ */
+
+#endif	/* Not _NO_OLDNAMES */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _TIME_H_ */
+
diff --git a/tinyc/win32/include/unistd.h b/tinyc/win32/include/unistd.h
new file mode 100644
index 000000000..8f51f7661
--- /dev/null
+++ b/tinyc/win32/include/unistd.h
@@ -0,0 +1,10 @@
+/*
+ * This file is part of the Mingw32 package.
+ *
+ * unistd.h maps (roughly) to io.h
+ */
+
+#ifndef __STRICT_ANSI__
+#include <io.h>
+#endif
+
diff --git a/tinyc/win32/include/values.h b/tinyc/win32/include/values.h
new file mode 100644
index 000000000..10e16a281
--- /dev/null
+++ b/tinyc/win32/include/values.h
@@ -0,0 +1,4 @@
+/*
+ * TODO: Nothing here yet. Should provide UNIX compatibility constants
+ * comparible to those in limits.h and float.h.
+ */
diff --git a/tinyc/win32/include/varargs.h b/tinyc/win32/include/varargs.h
new file mode 100644
index 000000000..daee29e87
--- /dev/null
+++ b/tinyc/win32/include/varargs.h
@@ -0,0 +1,11 @@
+#ifndef _VARARGS_H
+#define _VARARGS_H
+
+#include <stdarg.h>
+
+#define va_dcl
+#define va_alist __va_alist
+#undef va_start
+#define va_start(ap) ap = __builtin_varargs_start
+
+#endif
diff --git a/tinyc/win32/include/wchar.h b/tinyc/win32/include/wchar.h
new file mode 100644
index 000000000..4ad2ab9bf
--- /dev/null
+++ b/tinyc/win32/include/wchar.h
@@ -0,0 +1,318 @@
+/*
+ * wchar.h
+ *
+ * Defines of all functions for supporting wide characters. Actually it
+ * just includes all those headers, which is not a good thing to do from a
+ * processing time point of view, but it does mean that everything will be
+ * in sync.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Revision: 1.2 $
+ * $Author: bellard $
+ * $Date: 2005/04/17 13:14:29 $
+ *
+ */
+
+#ifndef	_WCHAR_H_
+#define	_WCHAR_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+
+#define __need_size_t
+#define __need_wint_t
+#define __need_wchar_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif /* Not RC_INVOKED */
+
+#define WCHAR_MIN	0
+#define WCHAR_MAX	((wchar_t)-1)
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus 
+extern "C" {
+#endif
+
+#ifndef	__STRICT_ANSI__
+
+#ifndef	_FSIZE_T_DEFINED
+typedef	unsigned long	_fsize_t;
+#define _FSIZE_T_DEFINED
+#endif
+
+#ifndef _WFINDDATA_T_DEFINED
+struct _wfinddata_t {
+    	unsigned	attrib;
+    	time_t		time_create;	/* -1 for FAT file systems */
+    	time_t		time_access;	/* -1 for FAT file systems */
+    	time_t		time_write;
+    	_fsize_t	size;
+    	wchar_t		name[FILENAME_MAX];	/* may include spaces. */
+};
+struct _wfinddatai64_t {
+    unsigned    attrib;
+    time_t      time_create;
+    time_t      time_access;
+    time_t      time_write;
+    __int64     size;
+    wchar_t     name[FILENAME_MAX];
+};
+#define _WFINDDATA_T_DEFINED
+#endif
+
+/* Wide character versions. Also defined in io.h. */
+/* CHECK: I believe these only exist in MSVCRT, and not in CRTDLL. Also
+   applies to other wide character versions? */
+#if !defined (_WIO_DEFINED)
+#if defined (__MSVCRT__)
+int	 _waccess (const wchar_t*, int);
+int	_wchmod (const wchar_t*, int);
+int	_wcreat (const wchar_t*, int);
+long	_wfindfirst (wchar_t*, struct _wfinddata_t *);
+int	_wfindnext (long, struct _wfinddata_t *);
+int	_wunlink (const wchar_t*);
+int	_wopen (const wchar_t*, int, ...);
+int	_wsopen (const wchar_t*, int, int, ...);
+wchar_t* _wmktemp (wchar_t*);
+long	_wfindfirsti64 (const wchar_t*, struct _wfinddatai64_t*);
+int 	_wfindnexti64 (long, struct _wfinddatai64_t*);
+#endif /* defined (__MSVCRT__) */
+#define _WIO_DEFINED
+#endif /* _WIO_DEFINED */
+
+#ifndef _WSTDIO_DEFINED
+/* also in stdio.h - keep in sync */
+int	fwprintf (FILE*, const wchar_t*, ...);
+int	wprintf (const wchar_t*, ...);
+int	swprintf (wchar_t*, const wchar_t*, ...);
+int	_snwprintf (wchar_t*, size_t, const wchar_t*, ...);
+int	vfwprintf (FILE*, const wchar_t*, va_list);
+int	vwprintf (const wchar_t*, va_list);
+int	vswprintf (wchar_t*, const wchar_t*, va_list);
+int	_vsnwprintf (wchar_t*, size_t, const wchar_t*, va_list);
+int	fwscanf (FILE*, const wchar_t*, ...);
+int	wscanf (const wchar_t*, ...);
+int	swscanf (const wchar_t*, const wchar_t*, ...);
+wint_t	fgetwc (FILE*);
+wint_t	fputwc (wchar_t, FILE*);
+wint_t	ungetwc (wchar_t, FILE*);
+
+#ifndef __NO_ISOCEXT  /* externs in libmingwex.a */
+int snwprintf(wchar_t* s, size_t n, const wchar_t*  format, ...);
+extern inline int vsnwprintf (wchar_t* s, size_t n, const wchar_t* format,
+			   va_list arg)
+  { return _vsnwprintf ( s, n, format, arg); }
+#endif
+
+#ifdef __MSVCRT__ 
+wchar_t* fgetws (wchar_t*, int, FILE*);
+int	fputws (const wchar_t*, FILE*);
+wint_t	getwc (FILE*);
+wint_t  getwchar (void);
+wchar_t* _getws (wchar_t*);
+wint_t	putwc (wint_t, FILE*);
+int	_putws (const wchar_t*);
+wint_t	putwchar (wint_t);
+
+FILE*	_wfopen (const wchar_t*, const wchar_t*);
+FILE*	_wfreopen (const wchar_t*, const wchar_t*, FILE*);
+FILE*   _wfsopen (const wchar_t*, const wchar_t*, int);
+wchar_t* _wtmpnam (wchar_t*);
+wchar_t* _wtempnam (const wchar_t*, const wchar_t*);
+int 	_wrename (const wchar_t*, const wchar_t*);
+int	_wremove (const wchar_t*)
+
+FILE*	  _wpopen (const wchar_t*, const wchar_t*)
+void	  _wperror (const wchar_t*);
+#endif	/* __MSVCRT__ */
+#define _WSTDIO_DEFINED
+#endif /* _WSTDIO_DEFINED */
+
+#ifndef _WDIRECT_DEFINED
+/* Also in direct.h */
+#ifdef __MSVCRT__ 
+int	  _wchdir (const wchar_t*);
+wchar_t*  _wgetcwd (wchar_t*, int);
+wchar_t*  _wgetdcwd (int, wchar_t*, int);
+int	  _wmkdir (const wchar_t*);
+int	  _wrmdir (const wchar_t*);
+#endif	/* __MSVCRT__ */
+#define _WDIRECT_DEFINED
+#endif /* _WDIRECT_DEFINED */
+
+#ifndef _STAT_DEFINED
+/*
+ * The structure manipulated and returned by stat and fstat.
+ *
+ * NOTE: If called on a directory the values in the time fields are not only
+ * invalid, they will cause localtime et. al. to return NULL. And calling
+ * asctime with a NULL pointer causes an Invalid Page Fault. So watch it!
+ */
+struct _stat
+{
+	_dev_t	st_dev;		/* Equivalent to drive number 0=A 1=B ... */
+	_ino_t	st_ino;		/* Always zero ? */
+	_mode_t	st_mode;	/* See above constants */
+	short	st_nlink;	/* Number of links. */
+	short	st_uid;		/* User: Maybe significant on NT ? */
+	short	st_gid;		/* Group: Ditto */
+	_dev_t	st_rdev;	/* Seems useless (not even filled in) */
+	_off_t	st_size;	/* File size in bytes */
+	time_t	st_atime;	/* Accessed date (always 00:00 hrs local
+				 * on FAT) */
+	time_t	st_mtime;	/* Modified time */
+	time_t	st_ctime;	/* Creation time */
+};
+
+struct stat
+{
+	_dev_t	st_dev;		/* Equivalent to drive number 0=A 1=B ... */
+	_ino_t	st_ino;		/* Always zero ? */
+	_mode_t	st_mode;	/* See above constants */
+	short	st_nlink;	/* Number of links. */
+	short	st_uid;		/* User: Maybe significant on NT ? */
+	short	st_gid;		/* Group: Ditto */
+	_dev_t	st_rdev;	/* Seems useless (not even filled in) */
+	_off_t	st_size;	/* File size in bytes */
+	time_t	st_atime;	/* Accessed date (always 00:00 hrs local
+				 * on FAT) */
+	time_t	st_mtime;	/* Modified time */
+	time_t	st_ctime;	/* Creation time */
+};
+#if defined (__MSVCRT__)
+struct _stati64 {
+    _dev_t st_dev;
+    _ino_t st_ino;
+    unsigned short st_mode;
+    short st_nlink;
+    short st_uid;
+    short st_gid;
+    _dev_t st_rdev;
+    __int64 st_size;
+    time_t st_atime;
+    time_t st_mtime;
+    time_t st_ctime;
+    };
+#endif  /* __MSVCRT__ */
+#define _STAT_DEFINED
+#endif /* _STAT_DEFINED */
+
+#if !defined ( _WSTAT_DEFINED)
+/* also declared in sys/stat.h */
+#if defined __MSVCRT__
+int	_wstat (const wchar_t*, struct _stat*);
+int	_wstati64 (const wchar_t*, struct _stati64*);
+#endif  /* __MSVCRT__ */
+#define _WSTAT_DEFINED
+#endif /* ! _WSTAT_DEFIND  */
+
+#ifndef _WTIME_DEFINED
+#ifdef __MSVCRT__
+/* wide function prototypes, also declared in time.h */
+wchar_t*	_wasctime (const struct tm*);
+wchar_t*	_wctime (const time_t*);
+wchar_t*	_wstrdate (wchar_t*);
+wchar_t*	_wstrtime (wchar_t*);
+#endif /* __MSVCRT__ */
+size_t		wcsftime (wchar_t*, size_t, const wchar_t*, const struct tm*);
+#define _WTIME_DEFINED
+#endif /* _WTIME_DEFINED */ 
+
+#ifndef _WLOCALE_DEFINED  /* also declared in locale.h */
+wchar_t* _wsetlocale (int, const wchar_t*);
+#define _WLOCALE_DEFINED
+#endif
+
+#ifndef _WSTDLIB_DEFINED /* also declared in stdlib.h */
+long	wcstol	(const wchar_t*, wchar_t**, int);
+unsigned long	wcstoul (const wchar_t*, wchar_t**, int);
+double	wcstod	(const wchar_t*, wchar_t**);
+#if !defined __NO_ISOCEXT /* extern stub in static libmingwex.a */
+extern __inline__ float wcstof( const wchar_t *nptr, wchar_t **endptr)
+{  return (wcstod(nptr, endptr)); }
+#endif /* __NO_ISOCEXT */
+#define  _WSTDLIB_DEFINED
+#endif
+
+
+#ifndef	_NO_OLDNAMES
+
+/* Wide character versions. Also declared in io.h. */
+/* CHECK: Are these in the oldnames???  NO! */
+#if (0)
+int		waccess (const wchar_t *, int);
+int		wchmod (const wchar_t *, int);
+int		wcreat (const wchar_t *, int);
+long		wfindfirst (wchar_t *, struct _wfinddata_t *);
+int		wfindnext (long, struct _wfinddata_t *);
+int		wunlink (const wchar_t *);
+int		wrename (const wchar_t *, const wchar_t *);
+int		wremove (const wchar_t *);
+int		wopen (const wchar_t *, int, ...);
+int		wsopen (const wchar_t *, int, int, ...);
+wchar_t*	wmktemp (wchar_t *);
+#endif
+#endif /* _NO_OLDNAMES */
+
+#endif /* not __STRICT_ANSI__ */
+
+/* These are resolved by -lmsvcp60 */
+/* If you don't have msvcp60.dll in your windows system directory, you can
+   easily obtain it with a search from your favorite search engine. */
+typedef int mbstate_t;
+typedef wchar_t _Wint_t;
+
+wint_t  btowc(int);
+size_t  mbrlen(const char *, size_t, mbstate_t *);
+size_t  mbrtowc(wchar_t *, const char *, size_t, mbstate_t *);
+size_t  mbsrtowcs(wchar_t *, const char **, size_t, mbstate_t *);
+
+size_t  wcrtomb(char *, wchar_t, mbstate_t *);
+size_t  wcsrtombs(char *, const wchar_t **, size_t, mbstate_t *);
+int  	wctob(wint_t);
+
+#ifndef __NO_ISOCEXT /* these need static lib libmingwex.a */
+extern inline int fwide(FILE* stream, int mode) {return -1;} /* limited to byte orientation */ 
+extern inline int mbsinit(const mbstate_t* ps) {return 1;}
+wchar_t* wmemset(wchar_t* s, wchar_t c, size_t n);
+wchar_t* wmemchr(const wchar_t* s, wchar_t c, size_t n);
+int wmemcmp(const wchar_t* s1, const wchar_t * s2, size_t n);
+wchar_t* wmemcpy(wchar_t* __restrict__ s1, const wchar_t* __restrict__ s2,
+		 size_t n);
+wchar_t* wmemmove(wchar_t* s1, const wchar_t* s2, size_t n);
+long long wcstoll(const wchar_t* __restrict__ nptr,
+		  wchar_t** __restrict__ endptr, int base);
+unsigned long long wcstoull(const wchar_t* __restrict__ nptr,
+			    wchar_t ** __restrict__ endptr, int base);
+
+#endif /* __NO_ISOCEXT */
+
+
+#ifdef __cplusplus
+}	/* end of extern "C" */
+#endif
+
+#endif /* Not RC_INVOKED */
+
+#endif /* not _WCHAR_H_ */
+
diff --git a/tinyc/win32/include/wctype.h b/tinyc/win32/include/wctype.h
new file mode 100644
index 000000000..1fb00fb3c
--- /dev/null
+++ b/tinyc/win32/include/wctype.h
@@ -0,0 +1,127 @@
+/* 
+ * wctype.h
+ *
+ * Functions for testing wide character types and converting characters.
+ *
+ * This file is part of the Mingw32 package.
+ *
+ * Contributors:
+ *  Created by Mumit Khan <khan@xraylith.wisc.edu>
+ *
+ *  THIS SOFTWARE IS NOT COPYRIGHTED
+ *
+ *  This source code is offered for use in the public domain. You may
+ *  use, modify or distribute it freely.
+ *
+ *  This code is distributed in the hope that it will be useful but
+ *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
+ *  DISCLAIMED. This includes but is not limited to warranties of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef _WCTYPE_H_
+#define _WCTYPE_H_
+
+/* All the headers include this file. */
+#include <_mingw.h>
+
+#define	__need_wchar_t
+#define	__need_wint_t
+#ifndef RC_INVOKED
+#include <stddef.h>
+#endif	/* Not RC_INVOKED */
+
+/*
+ * The following flags are used to tell iswctype and _isctype what character
+ * types you are looking for.
+ */
+#define	_UPPER		0x0001
+#define	_LOWER		0x0002
+#define	_DIGIT		0x0004
+#define	_SPACE		0x0008
+#define	_PUNCT		0x0010
+#define	_CONTROL	0x0020
+#define	_BLANK		0x0040
+#define	_HEX		0x0080
+#define	_LEADBYTE	0x8000
+
+#define	_ALPHA		0x0103
+
+#ifndef RC_INVOKED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WEOF
+#define	WEOF	(wchar_t)(0xFFFF)
+#endif
+
+#ifndef _WCTYPE_T_DEFINED
+typedef wchar_t wctype_t;
+#define _WCTYPE_T_DEFINED
+#endif
+
+/* Wide character equivalents - also in ctype.h */
+int	iswalnum(wint_t);
+int	iswalpha(wint_t);
+int	iswascii(wint_t);
+int	iswcntrl(wint_t);
+int	iswctype(wint_t, wctype_t);
+int	is_wctype(wint_t, wctype_t);	/* Obsolete! */
+int	iswdigit(wint_t);
+int	iswgraph(wint_t);
+int	iswlower(wint_t);
+int	iswprint(wint_t);
+int	iswpunct(wint_t);
+int	iswspace(wint_t);
+int	iswupper(wint_t);
+int	iswxdigit(wint_t);
+
+wchar_t	towlower(wchar_t);
+wchar_t	towupper(wchar_t);
+
+int	isleadbyte (int);
+
+/* Also in ctype.h */
+
+__MINGW_IMPORT unsigned short _ctype[];
+#ifdef __MSVCRT__
+__MINGW_IMPORT unsigned short* _pctype;
+#else
+__MINGW_IMPORT unsigned short* _pctype_dll;
+#define  _pctype _pctype_dll
+#endif
+
+#if !(defined(__NO_CTYPE_INLINES) || defined(__WCTYPE_INLINES_DEFINED))
+#define __WCTYPE_INLINES_DEFINED
+extern inline int iswalnum(wint_t wc) {return (iswctype(wc,_ALPHA|_DIGIT));}
+extern inline int iswalpha(wint_t wc) {return (iswctype(wc,_ALPHA));}
+extern inline int iswascii(wint_t wc) {return (((unsigned)wc & 0x7F) ==0);}
+extern inline int iswcntrl(wint_t wc) {return (iswctype(wc,_CONTROL));}
+extern inline int iswdigit(wint_t wc) {return (iswctype(wc,_DIGIT));}
+extern inline int iswgraph(wint_t wc) {return (iswctype(wc,_PUNCT|_ALPHA|_DIGIT));}
+extern inline int iswlower(wint_t wc) {return (iswctype(wc,_LOWER));}
+extern inline int iswprint(wint_t wc) {return (iswctype(wc,_BLANK|_PUNCT|_ALPHA|_DIGIT));}
+extern inline int iswpunct(wint_t wc) {return (iswctype(wc,_PUNCT));}
+extern inline int iswspace(wint_t wc) {return (iswctype(wc,_SPACE));}
+extern inline int iswupper(wint_t wc) {return (iswctype(wc,_UPPER));}
+extern inline int iswxdigit(wint_t wc) {return (iswctype(wc,_HEX));}
+extern inline int isleadbyte(int c) {return (_pctype[(unsigned char)(c)] & _LEADBYTE);}
+#endif /* !(defined(__NO_CTYPE_INLINES) || defined(__WCTYPE_INLINES_DEFINED)) */
+
+
+typedef wchar_t wctrans_t;
+wint_t 		towctrans(wint_t, wctrans_t);
+wctrans_t	wctrans(const char*);
+wctype_t	wctype(const char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* Not RC_INVOKED */
+
+#endif	/* Not _WCTYPE_H_ */
+
diff --git a/tinyc/win32/include/winapi/basetsd.h b/tinyc/win32/include/winapi/basetsd.h
new file mode 100644
index 000000000..d9c375dd9
--- /dev/null
+++ b/tinyc/win32/include/winapi/basetsd.h
@@ -0,0 +1,119 @@
+#ifndef _BASETSD_H
+#define _BASETSD_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __GNUC__
+#ifndef __int64
+#define __int64 long long
+#endif
+#endif
+
+#if defined(_WIN64)
+#define __int3264   __int64
+#define ADDRESS_TAG_BIT 0x40000000000UI64
+#else /*  !_WIN64 */
+#define __int3264   __int32
+#define ADDRESS_TAG_BIT 0x80000000UL
+#define HandleToUlong( h ) ((ULONG)(ULONG_PTR)(h) )
+#define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )
+#define LongToHandle( h) ((HANDLE)(LONG_PTR) (h))
+#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
+#define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )
+#define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )
+#define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+#define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )
+#define PtrToShort( p ) ((short)(LONG_PTR)(p) )
+#define IntToPtr( i )    ((VOID*)(INT_PTR)((int)i))
+#define UIntToPtr( ui )  ((VOID*)(UINT_PTR)((unsigned int)ui))
+#define LongToPtr( l )   ((VOID*)(LONG_PTR)((long)l))
+#define ULongToPtr( ul )  ((VOID*)(ULONG_PTR)((unsigned long)ul))
+#endif /* !_WIN64 */
+
+#define UlongToPtr(ul) ULongToPtr(ul)
+#define UintToPtr(ui) UIntToPtr(ui)
+#define MAXUINT_PTR  (~((UINT_PTR)0))
+#define MAXINT_PTR   ((INT_PTR)(MAXUINT_PTR >> 1))
+#define MININT_PTR   (~MAXINT_PTR)
+#define MAXULONG_PTR (~((ULONG_PTR)0))
+#define MAXLONG_PTR  ((LONG_PTR)(MAXULONG_PTR >> 1))
+#define MINLONG_PTR  (~MAXLONG_PTR)
+#define MAXUHALF_PTR ((UHALF_PTR)~0)
+#define MAXHALF_PTR  ((HALF_PTR)(MAXUHALF_PTR >> 1))
+#define MINHALF_PTR  (~MAXHALF_PTR)
+
+#ifndef RC_INVOKED
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef int LONG32, *PLONG32;
+#ifndef XFree86Server
+typedef int INT32, *PINT32;
+#endif /* ndef XFree86Server */
+typedef unsigned int ULONG32, *PULONG32;
+typedef unsigned int DWORD32, *PDWORD32;
+typedef unsigned int UINT32, *PUINT32;
+
+#if defined(_WIN64)
+typedef __int64 INT_PTR, *PINT_PTR;
+typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
+typedef __int64 LONG_PTR, *PLONG_PTR;
+typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
+typedef unsigned __int64 HANDLE_PTR;
+typedef unsigned int UHALF_PTR, *PUHALF_PTR;
+typedef int HALF_PTR, *PHALF_PTR;
+
+#if 0 /* TODO when WIN64 is here */
+inline unsigned long HandleToUlong(const void* h )
+    { return((unsigned long) h ); }
+inline long HandleToLong( const void* h )
+    { return((long) h ); }
+inline void* LongToHandle( const long h )
+    { return((void*) (INT_PTR) h ); }
+inline unsigned long PtrToUlong( const void* p)
+    { return((unsigned long) p ); }
+inline unsigned int PtrToUint( const void* p )
+    { return((unsigned int) p ); }
+inline unsigned short PtrToUshort( const void* p )
+    { return((unsigned short) p ); }
+inline long PtrToLong( const void* p )
+    { return((long) p ); }
+inline int PtrToInt( const void* p )
+    { return((int) p ); }
+inline short PtrToShort( const void* p )
+    { return((short) p ); }
+inline void* IntToPtr( const int i )
+    { return( (void*)(INT_PTR)i ); }
+inline void* UIntToPtr(const unsigned int ui)
+    { return( (void*)(UINT_PTR)ui ); }
+inline void* LongToPtr( const long l )
+    { return( (void*)(LONG_PTR)l ); }
+inline void* ULongToPtr( const unsigned long ul )
+    { return( (void*)(ULONG_PTR)ul ); }
+#endif /* 0_ */
+
+#else /*  !_WIN64 */
+typedef  int INT_PTR, *PINT_PTR;
+typedef  unsigned int UINT_PTR, *PUINT_PTR;
+typedef  long LONG_PTR, *PLONG_PTR;
+typedef  unsigned long ULONG_PTR, *PULONG_PTR;
+typedef unsigned short UHALF_PTR, *PUHALF_PTR;
+typedef short HALF_PTR, *PHALF_PTR;
+typedef unsigned long HANDLE_PTR;
+#endif /* !_WIN64 */
+
+typedef ULONG_PTR SIZE_T, *PSIZE_T;
+typedef LONG_PTR SSIZE_T, *PSSIZE_T;
+typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
+typedef __int64 LONG64, *PLONG64;
+typedef __int64 INT64,  *PINT64;
+typedef unsigned __int64 ULONG64, *PULONG64;
+typedef unsigned __int64 DWORD64, *PDWORD64;
+typedef unsigned __int64 UINT64,  *PUINT64;
+#ifdef __cplusplus
+}
+#endif
+#endif /* !RC_INVOKED */
+
+#endif /* _BASETSD_H */
diff --git a/tinyc/win32/include/winapi/basetyps.h b/tinyc/win32/include/winapi/basetyps.h
new file mode 100644
index 000000000..e1e36501b
--- /dev/null
+++ b/tinyc/win32/include/winapi/basetyps.h
@@ -0,0 +1,144 @@
+#ifndef _BASETYPS_H
+#define _BASETYPS_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifndef __OBJC__
+#ifdef __cplusplus
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C extern
+#endif  /* __cplusplus */ 
+#define STDMETHODCALLTYPE	__stdcall
+#define STDMETHODVCALLTYPE	__cdecl
+#define STDAPICALLTYPE	__stdcall
+#define STDAPIVCALLTYPE	__cdecl
+#define STDAPI	EXTERN_C HRESULT STDAPICALLTYPE
+#define STDAPI_(t)	EXTERN_C t STDAPICALLTYPE
+#define STDMETHODIMP	HRESULT STDMETHODCALLTYPE
+#define STDMETHODIMP_(t)	t STDMETHODCALLTYPE
+#define STDAPIV	EXTERN_C HRESULT STDAPIVCALLTYPE
+#define STDAPIV_(t)	EXTERN_C t STDAPIVCALLTYPE
+#define STDMETHODIMPV	HRESULT STDMETHODVCALLTYPE
+#define STDMETHODIMPV_(t)	t STDMETHODVCALLTYPE
+#define interface	struct
+#if defined(__cplusplus) && !defined(CINTERFACE)
+#define STDMETHOD(m)	virtual HRESULT STDMETHODCALLTYPE m
+#define STDMETHOD_(t,m)	virtual t STDMETHODCALLTYPE m
+#define PURE	=0
+#define THIS_
+#define THIS	void
+/*
+ __attribute__((com_interface)) is obsolete in __GNUC__ >= 3
+ g++ vtables are now COM-compatible by default
+*/
+#if defined(__GNUC__) &&  __GNUC__ < 3 && !defined(NOCOMATTRIBUTE)
+#define DECLARE_INTERFACE(i) interface __attribute__((com_interface)) i
+#define DECLARE_INTERFACE_(i,b) interface __attribute__((com_interface)) i : public b
+#else
+#define DECLARE_INTERFACE(i) interface i
+#define DECLARE_INTERFACE_(i,b) interface i : public b
+#endif
+#else
+#define STDMETHOD(m)	HRESULT(STDMETHODCALLTYPE *m)
+#define STDMETHOD_(t,m)	t(STDMETHODCALLTYPE *m)
+#define PURE
+#define THIS_	INTERFACE *,
+#define THIS	INTERFACE *
+#ifndef CONST_VTABLE
+#define CONST_VTABLE
+#endif
+#define DECLARE_INTERFACE(i) \
+typedef interface i { CONST_VTABLE struct i##Vtbl *lpVtbl; } i; \
+typedef CONST_VTABLE struct i##Vtbl i##Vtbl; \
+CONST_VTABLE struct i##Vtbl
+#define DECLARE_INTERFACE_(i,b) DECLARE_INTERFACE(i)
+#endif
+#define BEGIN_INTERFACE
+#define END_INTERFACE
+
+#define FWD_DECL(i) typedef interface i i
+#if defined(__cplusplus) && !defined(CINTERFACE)
+#define IENUM_THIS(T)
+#define IENUM_THIS_(T)
+#else
+#define IENUM_THIS(T) T*
+#define IENUM_THIS_(T) T*,
+#endif
+#define DECLARE_ENUMERATOR_(I,T) \
+DECLARE_INTERFACE_(I,IUnknown) \
+{ \
+	STDMETHOD(QueryInterface)(IENUM_THIS_(I) REFIID,PVOID*) PURE; \
+	STDMETHOD_(ULONG,AddRef)(IENUM_THIS(I)) PURE; \
+	STDMETHOD_(ULONG,Release)(IENUM_THIS(I)) PURE; \
+	STDMETHOD(Next)(IENUM_THIS_(I) ULONG,T*,ULONG*) PURE; \
+	STDMETHOD(Skip)(IENUM_THIS_(I) ULONG) PURE; \
+	STDMETHOD(Reset)(IENUM_THIS(I)) PURE; \
+	STDMETHOD(Clone)(IENUM_THIS_(I) I**) PURE; \
+}
+#define DECLARE_ENUMERATOR(T) DECLARE_ENUMERATOR_(IEnum##T,T)
+
+#endif /* __OBJC__ */
+
+#ifndef _GUID_DEFINED /* also defined in winnt.h */
+#define _GUID_DEFINED
+typedef struct _GUID
+{
+    unsigned long Data1;
+    unsigned short Data2;
+    unsigned short Data3;
+    unsigned char Data4[8];
+} GUID,*REFGUID,*LPGUID;
+#endif /* _GUID_DEFINED */
+#ifndef UUID_DEFINED
+#define UUID_DEFINED
+typedef GUID UUID;
+#endif /* UUID_DEFINED */
+typedef GUID IID;
+typedef GUID CLSID;
+typedef CLSID *LPCLSID;
+typedef IID *LPIID;
+typedef IID *REFIID;
+typedef CLSID *REFCLSID;
+typedef GUID FMTID;
+typedef FMTID *REFFMTID;
+typedef unsigned long error_status_t;
+#define uuid_t UUID
+typedef unsigned long PROPID;
+
+#ifndef _REFGUID_DEFINED
+#if defined (__cplusplus) && !defined (CINTERFACE)
+#define REFGUID const GUID&
+#define REFIID const IID&
+#define REFCLSID const CLSID&
+#else
+#define REFGUID const GUID* const
+#define REFIID const IID* const
+#define REFCLSID const CLSID* const
+#endif
+#define _REFGUID_DEFINED
+#define _REFGIID_DEFINED
+#define _REFCLSID_DEFINED
+#endif
+#ifndef GUID_SECTION
+#define GUID_SECTION ".text"
+#endif
+#ifdef __GNUC__
+#define GUID_SECT __attribute__ ((section (GUID_SECTION)))
+#else
+#define GUID_SECT
+#endif
+#if !defined(INITGUID) || (defined(INITGUID) && defined(__cplusplus))
+#define GUID_EXT EXTERN_C
+#else
+#define GUID_EXT
+#endif
+#ifdef INITGUID
+#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+#define DEFINE_OLEGUID(n,l,w1,w2) DEFINE_GUID(n,l,w1,w2,0xC0,0,0,0,0,0,0,0x46)
+#else
+#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n
+#define DEFINE_OLEGUID(n,l,w1,w2) DEFINE_GUID(n,l,w1,w2,0xC0,0,0,0,0,0,0,0x46)
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/winbase.h b/tinyc/win32/include/winapi/winbase.h
new file mode 100644
index 000000000..b3fab6c3d
--- /dev/null
+++ b/tinyc/win32/include/winapi/winbase.h
@@ -0,0 +1,1852 @@
+#ifndef _WINBASE_H
+#define _WINBASE_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#define WINBASEAPI DECLSPEC_IMPORT
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SP_SERIALCOMM 1
+#define PST_UNSPECIFIED	0
+#define PST_RS232	1
+#define PST_PARALLELPORT	2
+#define PST_RS422	3
+#define PST_RS423	4
+#define PST_RS449	5
+#define PST_MODEM	6
+#define PST_FAX	0x21
+#define PST_SCANNER	0x22
+#define PST_NETWORK_BRIDGE	0x100
+#define PST_LAT	0x101
+#define PST_TCPIP_TELNET	0x102
+#define PST_X25	0x103
+#define BAUD_075	1
+#define BAUD_110	2
+#define BAUD_134_5	4
+#define BAUD_150	8
+#define BAUD_300	16
+#define BAUD_600	32
+#define BAUD_1200	64
+#define BAUD_1800	128
+#define BAUD_2400	256
+#define BAUD_4800	512
+#define BAUD_7200	1024
+#define BAUD_9600	2048
+#define BAUD_14400	4096
+#define BAUD_19200	8192
+#define BAUD_38400	16384
+#define BAUD_56K	32768
+#define BAUD_128K	65536
+#define BAUD_115200	131072
+#define BAUD_57600	262144
+#define BAUD_USER	0x10000000
+#define PCF_DTRDSR	1
+#define PCF_RTSCTS	2
+#define PCF_RLSD	4
+#define PCF_PARITY_CHECK	8
+#define PCF_XONXOFF	16
+#define PCF_SETXCHAR	32
+#define PCF_TOTALTIMEOUTS	64
+#define PCF_INTTIMEOUTS	128
+#define PCF_SPECIALCHARS	256
+#define PCF_16BITMODE	512
+#define SP_PARITY	1
+#define SP_BAUD	2
+#define SP_DATABITS	4
+#define SP_STOPBITS	8
+#define SP_HANDSHAKING	16
+#define SP_PARITY_CHECK	32
+#define SP_RLSD	64
+#define DATABITS_5	1
+#define DATABITS_6	2
+#define DATABITS_7	4
+#define DATABITS_8	8
+#define DATABITS_16	16
+#define DATABITS_16X	32
+#define STOPBITS_10	1
+#define STOPBITS_15	2
+#define STOPBITS_20	4
+#define PARITY_NONE	256
+#define PARITY_ODD	512
+#define PARITY_EVEN	1024
+#define PARITY_MARK	2048
+#define PARITY_SPACE	4096
+#define EXCEPTION_DEBUG_EVENT	1
+#define CREATE_THREAD_DEBUG_EVENT	2
+#define CREATE_PROCESS_DEBUG_EVENT	3
+#define EXIT_THREAD_DEBUG_EVENT	4
+#define EXIT_PROCESS_DEBUG_EVENT	5
+#define LOAD_DLL_DEBUG_EVENT	6
+#define UNLOAD_DLL_DEBUG_EVENT	7
+#define OUTPUT_DEBUG_STRING_EVENT	8
+#define RIP_EVENT	9
+#define HFILE_ERROR ((HFILE)-1)
+#define FILE_BEGIN	0
+#define FILE_CURRENT	1
+#define FILE_END	2
+#define INVALID_SET_FILE_POINTER	((DWORD)-1)
+#define OF_READ 0
+#define OF_READWRITE	2
+#define OF_WRITE	1
+#define OF_SHARE_COMPAT	0
+#define OF_SHARE_DENY_NONE	64
+#define OF_SHARE_DENY_READ	48
+#define OF_SHARE_DENY_WRITE	32
+#define OF_SHARE_EXCLUSIVE	16
+#define OF_CANCEL	2048
+#define OF_CREATE	4096
+#define OF_DELETE	512
+#define OF_EXIST	16384
+#define OF_PARSE	256
+#define OF_PROMPT	8192
+#define OF_REOPEN	32768
+#define OF_VERIFY	1024
+#define NMPWAIT_NOWAIT	1
+#define NMPWAIT_WAIT_FOREVER	(-1)
+#define NMPWAIT_USE_DEFAULT_WAIT	0
+#define CE_BREAK	16
+#define CE_DNS	2048
+#define CE_FRAME	8
+#define CE_IOE	1024
+#define CE_MODE	32768
+#define CE_OOP	4096
+#define CE_OVERRUN	2
+#define CE_PTO	512
+#define CE_RXOVER	1
+#define CE_RXPARITY	4
+#define CE_TXFULL	256
+#define PROGRESS_CONTINUE	0
+#define PROGRESS_CANCEL	1
+#define PROGRESS_STOP	2
+#define PROGRESS_QUIET	3
+#define CALLBACK_CHUNK_FINISHED	0
+#define CALLBACK_STREAM_SWITCH	1
+#define COPY_FILE_FAIL_IF_EXISTS	1
+#define COPY_FILE_RESTARTABLE	2
+#define OFS_MAXPATHNAME 128
+#define DUPLICATE_CLOSE_SOURCE  1
+#define DUPLICATE_SAME_ACCESS   2
+#define FILE_MAP_ALL_ACCESS     0xf001f
+#define FILE_MAP_READ   4
+#define FILE_MAP_WRITE  2
+#define FILE_MAP_COPY   1
+#define MUTEX_ALL_ACCESS	0x1f0001
+#define MUTEX_MODIFY_STATE	1
+#define SEMAPHORE_ALL_ACCESS	0x1f0003
+#define SEMAPHORE_MODIFY_STATE	2
+#define EVENT_ALL_ACCESS	0x1f0003
+#define EVENT_MODIFY_STATE	2
+#define PIPE_ACCESS_DUPLEX      3
+#define PIPE_ACCESS_INBOUND     1
+#define PIPE_ACCESS_OUTBOUND    2
+#define PIPE_TYPE_BYTE	0
+#define PIPE_TYPE_MESSAGE	4
+#define PIPE_READMODE_BYTE	0
+#define PIPE_READMODE_MESSAGE	2
+#define PIPE_WAIT	0
+#define PIPE_NOWAIT	1
+#define PIPE_CLIENT_END 0
+#define PIPE_SERVER_END 1
+#define PIPE_UNLIMITED_INSTANCES 255
+#define CREATE_DEFAULT_ERROR_MODE	67108864
+#define DEBUG_PROCESS	1
+#define DEBUG_ONLY_THIS_PROCESS	2
+#define CREATE_SUSPENDED	4
+#define DETACHED_PROCESS	8
+#define CREATE_NEW_CONSOLE	16
+#define NORMAL_PRIORITY_CLASS	32
+#define IDLE_PRIORITY_CLASS	64
+#define HIGH_PRIORITY_CLASS	128
+#define REALTIME_PRIORITY_CLASS	256
+#define CREATE_NEW_PROCESS_GROUP	512
+#define CREATE_UNICODE_ENVIRONMENT	1024
+#define CREATE_SEPARATE_WOW_VDM	2048
+#define CREATE_SHARED_WOW_VDM 4096
+#define CREATE_FORCEDOS 8192
+#define CREATE_NO_WINDOW 0x8000000
+#define CONSOLE_TEXTMODE_BUFFER 1
+#define CREATE_NEW	1
+#define CREATE_ALWAYS	2
+#define OPEN_EXISTING	3
+#define OPEN_ALWAYS	4
+#define TRUNCATE_EXISTING	5
+#define FILE_FLAG_WRITE_THROUGH	0x80000000
+#define FILE_FLAG_OVERLAPPED	1073741824
+#define FILE_FLAG_NO_BUFFERING	536870912
+#define FILE_FLAG_RANDOM_ACCESS	268435456
+#define FILE_FLAG_SEQUENTIAL_SCAN	134217728
+#define FILE_FLAG_DELETE_ON_CLOSE	67108864
+#define FILE_FLAG_BACKUP_SEMANTICS	33554432
+#define FILE_FLAG_POSIX_SEMANTICS	16777216
+#define FILE_FLAG_OPEN_REPARSE_POINT	2097152
+#define FILE_FLAG_OPEN_NO_RECALL	1048576
+#define CLRDTR 6
+#define CLRRTS 4
+#define SETDTR 5
+#define SETRTS 3
+#define SETXOFF 1
+#define SETXON 2
+#define SETBREAK 8
+#define CLRBREAK 9
+#define STILL_ACTIVE 0x103
+#define FIND_FIRST_EX_CASE_SENSITIVE 1
+#define SCS_32BIT_BINARY 0
+#define SCS_DOS_BINARY 1
+#define SCS_OS216_BINARY 5
+#define SCS_PIF_BINARY 3
+#define SCS_POSIX_BINARY 4
+#define SCS_WOW_BINARY 2
+#define MAX_COMPUTERNAME_LENGTH 15
+#define HW_PROFILE_GUIDLEN	39
+#define MAX_PROFILE_LEN	80
+#define DOCKINFO_UNDOCKED	1
+#define DOCKINFO_DOCKED	2
+#define DOCKINFO_USER_SUPPLIED	4
+#define DOCKINFO_USER_UNDOCKED	(DOCKINFO_USER_SUPPLIED|DOCKINFO_UNDOCKED)
+#define DOCKINFO_USER_DOCKED	(DOCKINFO_USER_SUPPLIED|DOCKINFO_DOCKED)
+#define DRIVE_REMOVABLE 2
+#define DRIVE_FIXED 3
+#define DRIVE_REMOTE 4
+#define DRIVE_CDROM 5
+#define DRIVE_RAMDISK 6
+#define DRIVE_UNKNOWN 0
+#define DRIVE_NO_ROOT_DIR 1
+#define FILE_TYPE_UNKNOWN 0
+#define FILE_TYPE_DISK 1
+#define FILE_TYPE_CHAR 2
+#define FILE_TYPE_PIPE 3
+#define FILE_TYPE_REMOTE 0x8000
+#define HANDLE_FLAG_INHERIT 1
+#define HANDLE_FLAG_PROTECT_FROM_CLOSE 2
+#define STD_INPUT_HANDLE (DWORD)(0xfffffff6)
+#define STD_OUTPUT_HANDLE (DWORD)(0xfffffff5)
+#define STD_ERROR_HANDLE (DWORD)(0xfffffff4)
+#define INVALID_HANDLE_VALUE (HANDLE)(-1)
+#define GET_TAPE_MEDIA_INFORMATION 0
+#define GET_TAPE_DRIVE_INFORMATION 1
+#define SET_TAPE_MEDIA_INFORMATION 0
+#define SET_TAPE_DRIVE_INFORMATION 1
+#define THREAD_PRIORITY_ABOVE_NORMAL 1
+#define THREAD_PRIORITY_BELOW_NORMAL (-1)
+#define THREAD_PRIORITY_HIGHEST 2
+#define THREAD_PRIORITY_IDLE (-15)
+#define THREAD_PRIORITY_LOWEST (-2)
+#define THREAD_PRIORITY_NORMAL 0
+#define THREAD_PRIORITY_TIME_CRITICAL 15
+#define THREAD_PRIORITY_ERROR_RETURN 2147483647
+#define TIME_ZONE_ID_UNKNOWN 0
+#define TIME_ZONE_ID_STANDARD 1
+#define TIME_ZONE_ID_DAYLIGHT 2
+#define TIME_ZONE_ID_INVALID 0xFFFFFFFF
+#define FS_CASE_IS_PRESERVED 2
+#define FS_CASE_SENSITIVE 1
+#define FS_UNICODE_STORED_ON_DISK 4
+#define FS_PERSISTENT_ACLS 8
+#define FS_FILE_COMPRESSION 16
+#define FS_VOL_IS_COMPRESSED 32768
+#define GMEM_FIXED 0
+#define GMEM_MOVEABLE 2
+#define GMEM_MODIFY 128
+#define GPTR 64
+#define GHND 66
+#define GMEM_DDESHARE 8192
+#define GMEM_DISCARDABLE 256
+#define GMEM_LOWER 4096
+#define GMEM_NOCOMPACT 16
+#define GMEM_NODISCARD 32
+#define GMEM_NOT_BANKED 4096
+#define GMEM_NOTIFY 16384
+#define GMEM_SHARE 8192
+#define GMEM_ZEROINIT 64
+#define GMEM_DISCARDED 16384
+#define GMEM_INVALID_HANDLE 32768
+#define GMEM_LOCKCOUNT 255
+#define STATUS_WAIT_0 0
+#define STATUS_ABANDONED_WAIT_0 0x80
+#define STATUS_USER_APC 0xC0
+#define STATUS_TIMEOUT 0x102
+#define STATUS_PENDING 0x103
+#define STATUS_SEGMENT_NOTIFICATION 0x40000005
+#define STATUS_GUARD_PAGE_VIOLATION 0x80000001
+#define STATUS_DATATYPE_MISALIGNMENT 0x80000002
+#define STATUS_BREAKPOINT 0x80000003
+#define STATUS_SINGLE_STEP 0x80000004
+#define STATUS_ACCESS_VIOLATION 0xC0000005
+#define STATUS_IN_PAGE_ERROR 0xC0000006
+#define STATUS_INVALID_HANDLE 0xC0000008L
+#define STATUS_NO_MEMORY 0xC0000017
+#define STATUS_ILLEGAL_INSTRUCTION 0xC000001D
+#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025
+#define STATUS_INVALID_DISPOSITION 0xC0000026
+#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C
+#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D
+#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E
+#define STATUS_FLOAT_INEXACT_RESULT 0xC000008F
+#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090
+#define STATUS_FLOAT_OVERFLOW 0xC0000091
+#define STATUS_FLOAT_STACK_CHECK 0xC0000092
+#define STATUS_FLOAT_UNDERFLOW 0xC0000093
+#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
+#define STATUS_INTEGER_OVERFLOW 0xC0000095
+#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096
+#define STATUS_STACK_OVERFLOW 0xC00000FD
+#define STATUS_CONTROL_C_EXIT 0xC000013A
+#define EXCEPTION_ACCESS_VIOLATION	STATUS_ACCESS_VIOLATION
+#define EXCEPTION_DATATYPE_MISALIGNMENT	STATUS_DATATYPE_MISALIGNMENT
+#define EXCEPTION_BREAKPOINT	STATUS_BREAKPOINT
+#define EXCEPTION_SINGLE_STEP	STATUS_SINGLE_STEP
+#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED	STATUS_ARRAY_BOUNDS_EXCEEDED
+#define EXCEPTION_FLT_DENORMAL_OPERAND	STATUS_FLOAT_DENORMAL_OPERAND
+#define EXCEPTION_FLT_DIVIDE_BY_ZERO	STATUS_FLOAT_DIVIDE_BY_ZERO
+#define EXCEPTION_FLT_INEXACT_RESULT	STATUS_FLOAT_INEXACT_RESULT
+#define EXCEPTION_FLT_INVALID_OPERATION	STATUS_FLOAT_INVALID_OPERATION
+#define EXCEPTION_FLT_OVERFLOW	STATUS_FLOAT_OVERFLOW
+#define EXCEPTION_FLT_STACK_CHECK	STATUS_FLOAT_STACK_CHECK
+#define EXCEPTION_FLT_UNDERFLOW	STATUS_FLOAT_UNDERFLOW
+#define EXCEPTION_INT_DIVIDE_BY_ZERO	STATUS_INTEGER_DIVIDE_BY_ZERO
+#define EXCEPTION_INT_OVERFLOW	STATUS_INTEGER_OVERFLOW
+#define EXCEPTION_PRIV_INSTRUCTION	STATUS_PRIVILEGED_INSTRUCTION
+#define EXCEPTION_IN_PAGE_ERROR	STATUS_IN_PAGE_ERROR
+#define EXCEPTION_ILLEGAL_INSTRUCTION	STATUS_ILLEGAL_INSTRUCTION
+#define EXCEPTION_NONCONTINUABLE_EXCEPTION	STATUS_NONCONTINUABLE_EXCEPTION
+#define EXCEPTION_STACK_OVERFLOW	STATUS_STACK_OVERFLOW
+#define EXCEPTION_INVALID_DISPOSITION	STATUS_INVALID_DISPOSITION
+#define EXCEPTION_GUARD_PAGE	STATUS_GUARD_PAGE_VIOLATION
+#define EXCEPTION_INVALID_HANDLE	STATUS_INVALID_HANDLE
+#define CONTROL_C_EXIT	STATUS_CONTROL_C_EXIT
+#define PROCESS_HEAP_REGION 1
+#define PROCESS_HEAP_UNCOMMITTED_RANGE 2
+#define PROCESS_HEAP_ENTRY_BUSY 4
+#define PROCESS_HEAP_ENTRY_MOVEABLE 16
+#define PROCESS_HEAP_ENTRY_DDESHARE 32
+#define DONT_RESOLVE_DLL_REFERENCES 1
+#define LOAD_LIBRARY_AS_DATAFILE 2
+#define LOAD_WITH_ALTERED_SEARCH_PATH 8
+#define LMEM_FIXED 0
+#define LMEM_MOVEABLE 2
+#define LMEM_NONZEROLHND 2
+#define LMEM_NONZEROLPTR 0
+#define LMEM_DISCARDABLE 3840
+#define LMEM_NOCOMPACT 16
+#define LMEM_NODISCARD 32
+#define LMEM_ZEROINIT 64
+#define LMEM_DISCARDED 16384
+#define LMEM_MODIFY 128
+#define LMEM_INVALID_HANDLE 32768
+#define LMEM_LOCKCOUNT 255
+#define LPTR 64
+#define LHND 66
+#define NONZEROLHND 2
+#define NONZEROLPTR 0
+#define LOCKFILE_FAIL_IMMEDIATELY 1
+#define LOCKFILE_EXCLUSIVE_LOCK 2
+#define LOGON32_PROVIDER_DEFAULT	0
+#define LOGON32_PROVIDER_WINNT35	1
+#define LOGON32_LOGON_INTERACTIVE	2
+#define LOGON32_LOGON_BATCH	4
+#define LOGON32_LOGON_SERVICE	5
+#define MOVEFILE_REPLACE_EXISTING 1
+#define MOVEFILE_COPY_ALLOWED 2
+#define MOVEFILE_DELAY_UNTIL_REBOOT 4
+#define MOVEFILE_WRITE_THROUGH 8
+#define MAXIMUM_WAIT_OBJECTS 64
+#define MAXIMUM_SUSPEND_COUNT 0x7F
+#define WAIT_OBJECT_0 0
+#define WAIT_ABANDONED_0 128
+#define WAIT_TIMEOUT 0x102
+#define WAIT_IO_COMPLETION 0xC0
+#define WAIT_ABANDONED 128
+#define WAIT_FAILED 0xFFFFFFFF
+#define PURGE_TXABORT 1
+#define PURGE_RXABORT 2
+#define PURGE_TXCLEAR 4
+#define PURGE_RXCLEAR 8
+#define EVENTLOG_FORWARDS_READ 4
+#define EVENTLOG_BACKWARDS_READ 8
+#define EVENTLOG_SEEK_READ 2
+#define EVENTLOG_SEQUENTIAL_READ 1
+#define EVENTLOG_ERROR_TYPE 1
+#define EVENTLOG_WARNING_TYPE 2
+#define EVENTLOG_INFORMATION_TYPE 4
+#define EVENTLOG_AUDIT_SUCCESS 8
+#define EVENTLOG_AUDIT_FAILURE 16
+#define FORMAT_MESSAGE_ALLOCATE_BUFFER 256
+#define FORMAT_MESSAGE_IGNORE_INSERTS 512
+#define FORMAT_MESSAGE_FROM_STRING 1024
+#define FORMAT_MESSAGE_FROM_HMODULE 2048
+#define FORMAT_MESSAGE_FROM_SYSTEM 4096
+#define FORMAT_MESSAGE_ARGUMENT_ARRAY 8192
+#define FORMAT_MESSAGE_MAX_WIDTH_MASK 255
+#define EV_BREAK 64
+#define EV_CTS 8
+#define EV_DSR 16
+#define EV_ERR 128
+#define EV_EVENT1 2048
+#define EV_EVENT2 4096
+#define EV_PERR 512
+#define EV_RING 256
+#define EV_RLSD 32
+#define EV_RX80FULL 1024
+#define EV_RXCHAR 1
+#define EV_RXFLAG 2
+#define EV_TXEMPTY 4
+#define SEM_FAILCRITICALERRORS 1
+#define SEM_NOALIGNMENTFAULTEXCEPT 4
+#define SEM_NOGPFAULTERRORBOX 2
+#define SEM_NOOPENFILEERRORBOX 32768
+#define SLE_ERROR 1
+#define SLE_MINORERROR 2
+#define SLE_WARNING 3
+#define SHUTDOWN_NORETRY 1
+#define EXCEPTION_EXECUTE_HANDLER 1
+#define EXCEPTION_CONTINUE_EXECUTION (-1)
+#define EXCEPTION_CONTINUE_SEARCH 0
+#define MAXINTATOM 0xC000
+#define INVALID_ATOM ((ATOM)0)
+#define IGNORE	0
+#define INFINITE	0xFFFFFFFF
+#define NOPARITY	0
+#define ODDPARITY	1
+#define EVENPARITY	2
+#define MARKPARITY	3
+#define SPACEPARITY	4
+#define ONESTOPBIT	0
+#define ONE5STOPBITS	1
+#define TWOSTOPBITS	2
+#define CBR_110	110
+#define CBR_300	300
+#define CBR_600	600
+#define CBR_1200	1200
+#define CBR_2400	2400
+#define CBR_4800	4800
+#define CBR_9600	9600
+#define CBR_14400	14400
+#define CBR_19200	19200
+#define CBR_38400	38400
+#define CBR_56000	56000
+#define CBR_57600	57600
+#define CBR_115200	115200
+#define CBR_128000	128000
+#define CBR_256000	256000
+#define BACKUP_INVALID	0
+#define BACKUP_DATA 1
+#define BACKUP_EA_DATA 2
+#define BACKUP_SECURITY_DATA 3
+#define BACKUP_ALTERNATE_DATA 4
+#define BACKUP_LINK 5
+#define BACKUP_PROPERTY_DATA 6
+#define BACKUP_OBJECT_ID 7
+#define BACKUP_REPARSE_DATA 8
+#define BACKUP_SPARSE_BLOCK 9
+#define STREAM_NORMAL_ATTRIBUTE 0
+#define STREAM_MODIFIED_WHEN_READ 1
+#define STREAM_CONTAINS_SECURITY 2
+#define STREAM_CONTAINS_PROPERTIES 4
+#define STARTF_USESHOWWINDOW 1
+#define STARTF_USESIZE 2
+#define STARTF_USEPOSITION 4
+#define STARTF_USECOUNTCHARS 8
+#define STARTF_USEFILLATTRIBUTE 16
+#define STARTF_RUNFULLSCREEN 32
+#define STARTF_FORCEONFEEDBACK 64
+#define STARTF_FORCEOFFFEEDBACK 128
+#define STARTF_USESTDHANDLES 256
+#define STARTF_USEHOTKEY 512
+#define TC_NORMAL 0
+#define TC_HARDERR 1
+#define TC_GP_TRAP 2
+#define TC_SIGNAL 3
+#define AC_LINE_OFFLINE 0
+#define AC_LINE_ONLINE 1
+#define AC_LINE_BACKUP_POWER 2
+#define AC_LINE_UNKNOWN 255
+#define BATTERY_FLAG_HIGH 1
+#define BATTERY_FLAG_LOW 2
+#define BATTERY_FLAG_CRITICAL 4
+#define BATTERY_FLAG_CHARGING 8
+#define BATTERY_FLAG_NO_BATTERY 128
+#define BATTERY_FLAG_UNKNOWN 255
+#define BATTERY_PERCENTAGE_UNKNOWN 255
+#define BATTERY_LIFE_UNKNOWN 0xFFFFFFFF
+#define DDD_RAW_TARGET_PATH 1
+#define DDD_REMOVE_DEFINITION 2
+#define DDD_EXACT_MATCH_ON_REMOVE 4
+#define HINSTANCE_ERROR 32
+#define MS_CTS_ON 16
+#define MS_DSR_ON 32
+#define MS_RING_ON 64
+#define MS_RLSD_ON 128
+#define PROFILE_USER 0x10000000
+#define PROFILE_KERNEL 0x20000000
+#define PROFILE_SERVER 0x40000000
+#define DTR_CONTROL_DISABLE 0
+#define DTR_CONTROL_ENABLE 1
+#define DTR_CONTROL_HANDSHAKE 2
+#define RTS_CONTROL_DISABLE 0
+#define RTS_CONTROL_ENABLE 1
+#define RTS_CONTROL_HANDSHAKE 2
+#define RTS_CONTROL_TOGGLE 3
+#define SECURITY_ANONYMOUS (SecurityAnonymous<<16)
+#define SECURITY_IDENTIFICATION (SecurityIdentification<<16)
+#define SECURITY_IMPERSONATION (SecurityImpersonation<<16)
+#define SECURITY_DELEGATION (SecurityDelegation<<16)
+#define SECURITY_CONTEXT_TRACKING 0x40000
+#define SECURITY_EFFECTIVE_ONLY 0x80000
+#define SECURITY_SQOS_PRESENT 0x100000
+#define SECURITY_VALID_SQOS_FLAGS 0x1F0000
+#define INVALID_FILE_SIZE 0xFFFFFFFF
+#define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
+
+#ifndef RC_INVOKED
+typedef struct _FILETIME {
+	DWORD dwLowDateTime;
+	DWORD dwHighDateTime;
+} FILETIME,*PFILETIME,*LPFILETIME;
+typedef struct _BY_HANDLE_FILE_INFORMATION {
+	DWORD	dwFileAttributes;
+	FILETIME	ftCreationTime;
+	FILETIME	ftLastAccessTime;
+	FILETIME	ftLastWriteTime;
+	DWORD	dwVolumeSerialNumber;
+	DWORD	nFileSizeHigh;
+	DWORD	nFileSizeLow;
+	DWORD	nNumberOfLinks;
+	DWORD	nFileIndexHigh;
+	DWORD	nFileIndexLow;
+} BY_HANDLE_FILE_INFORMATION,*LPBY_HANDLE_FILE_INFORMATION;
+typedef struct _DCB {
+	DWORD DCBlength;
+	DWORD BaudRate;
+	DWORD fBinary:1;
+	DWORD fParity:1;
+	DWORD fOutxCtsFlow:1;
+	DWORD fOutxDsrFlow:1;
+	DWORD fDtrControl:2;
+	DWORD fDsrSensitivity:1;
+	DWORD fTXContinueOnXoff:1;
+	DWORD fOutX:1;
+	DWORD fInX:1;
+	DWORD fErrorChar:1;
+	DWORD fNull:1;
+	DWORD fRtsControl:2;
+	DWORD fAbortOnError:1;
+	DWORD fDummy2:17;
+	WORD wReserved;
+	WORD XonLim;
+	WORD XoffLim;
+	BYTE ByteSize;
+	BYTE Parity;
+	BYTE StopBits;
+	char XonChar;
+	char XoffChar;
+	char ErrorChar;
+	char EofChar;
+	char EvtChar;
+	WORD wReserved1;
+} DCB,*LPDCB;
+typedef struct _COMM_CONFIG {
+	DWORD dwSize;
+	WORD  wVersion;
+	WORD  wReserved;
+	DCB   dcb;
+	DWORD dwProviderSubType;
+	DWORD dwProviderOffset;
+	DWORD dwProviderSize;
+	WCHAR wcProviderData[1];
+} COMMCONFIG,*LPCOMMCONFIG;
+typedef struct _COMMPROP {
+	WORD	wPacketLength;
+	WORD	wPacketVersion;
+	DWORD	dwServiceMask;
+	DWORD	dwReserved1;
+	DWORD	dwMaxTxQueue;
+	DWORD	dwMaxRxQueue;
+	DWORD	dwMaxBaud;
+	DWORD	dwProvSubType;
+	DWORD	dwProvCapabilities;
+	DWORD	dwSettableParams;
+	DWORD	dwSettableBaud;
+	WORD	wSettableData;
+	WORD	wSettableStopParity;
+	DWORD	dwCurrentTxQueue;
+	DWORD	dwCurrentRxQueue;
+	DWORD	dwProvSpec1;
+	DWORD	dwProvSpec2;
+	WCHAR	wcProvChar[1];
+} COMMPROP,*LPCOMMPROP;
+typedef struct _COMMTIMEOUTS {
+	DWORD ReadIntervalTimeout;
+	DWORD ReadTotalTimeoutMultiplier;
+	DWORD ReadTotalTimeoutConstant;
+	DWORD WriteTotalTimeoutMultiplier;
+	DWORD WriteTotalTimeoutConstant;
+} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
+typedef struct _COMSTAT {
+	DWORD fCtsHold:1;
+	DWORD fDsrHold:1;
+	DWORD fRlsdHold:1;
+	DWORD fXoffHold:1;
+	DWORD fXoffSent:1;
+	DWORD fEof:1;
+	DWORD fTxim:1;
+	DWORD fReserved:25;
+	DWORD cbInQue;
+	DWORD cbOutQue;
+} COMSTAT,*LPCOMSTAT;
+typedef DWORD (WINAPI *LPTHREAD_START_ROUTINE)(LPVOID);
+typedef struct _CREATE_PROCESS_DEBUG_INFO {
+	HANDLE hFile;
+	HANDLE hProcess;
+	HANDLE hThread;
+	LPVOID lpBaseOfImage;
+	DWORD dwDebugInfoFileOffset;
+	DWORD nDebugInfoSize;
+	LPVOID lpThreadLocalBase;
+	LPTHREAD_START_ROUTINE lpStartAddress;
+	LPVOID lpImageName;
+	WORD fUnicode;
+} CREATE_PROCESS_DEBUG_INFO,*LPCREATE_PROCESS_DEBUG_INFO;
+typedef struct _CREATE_THREAD_DEBUG_INFO {
+	HANDLE hThread;
+	LPVOID lpThreadLocalBase;
+	LPTHREAD_START_ROUTINE lpStartAddress;
+} CREATE_THREAD_DEBUG_INFO,*LPCREATE_THREAD_DEBUG_INFO;
+typedef struct _EXCEPTION_DEBUG_INFO {
+	EXCEPTION_RECORD ExceptionRecord;
+	DWORD dwFirstChance;
+} EXCEPTION_DEBUG_INFO,*LPEXCEPTION_DEBUG_INFO;
+typedef struct _EXIT_THREAD_DEBUG_INFO {
+	DWORD dwExitCode;
+} EXIT_THREAD_DEBUG_INFO,*LPEXIT_THREAD_DEBUG_INFO;
+typedef struct _EXIT_PROCESS_DEBUG_INFO {
+	DWORD dwExitCode;
+} EXIT_PROCESS_DEBUG_INFO,*LPEXIT_PROCESS_DEBUG_INFO;
+typedef struct _LOAD_DLL_DEBUG_INFO {
+	HANDLE hFile;
+	LPVOID lpBaseOfDll;
+	DWORD dwDebugInfoFileOffset;
+	DWORD nDebugInfoSize;
+	LPVOID lpImageName;
+	WORD fUnicode;
+} LOAD_DLL_DEBUG_INFO,*LPLOAD_DLL_DEBUG_INFO;
+typedef struct _UNLOAD_DLL_DEBUG_INFO {
+	LPVOID lpBaseOfDll;
+} UNLOAD_DLL_DEBUG_INFO,*LPUNLOAD_DLL_DEBUG_INFO;
+typedef struct _OUTPUT_DEBUG_STRING_INFO {
+	LPSTR lpDebugStringData;
+	WORD fUnicode;
+	WORD nDebugStringLength;
+} OUTPUT_DEBUG_STRING_INFO,*LPOUTPUT_DEBUG_STRING_INFO;
+typedef struct _RIP_INFO {
+	DWORD dwError;
+	DWORD dwType;
+} RIP_INFO,*LPRIP_INFO;
+typedef struct _DEBUG_EVENT {
+	DWORD dwDebugEventCode;
+	DWORD dwProcessId;
+	DWORD dwThreadId;
+	union {
+		EXCEPTION_DEBUG_INFO Exception;
+		CREATE_THREAD_DEBUG_INFO CreateThread;
+		CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
+		EXIT_THREAD_DEBUG_INFO ExitThread;
+		EXIT_PROCESS_DEBUG_INFO ExitProcess;
+		LOAD_DLL_DEBUG_INFO LoadDll;
+		UNLOAD_DLL_DEBUG_INFO UnloadDll;
+		OUTPUT_DEBUG_STRING_INFO DebugString;
+		RIP_INFO RipInfo;
+	} u;
+} DEBUG_EVENT,*LPDEBUG_EVENT;
+typedef struct _OVERLAPPED {
+	DWORD Internal;
+	DWORD InternalHigh;
+	DWORD Offset;
+	DWORD OffsetHigh;
+	HANDLE hEvent;
+} OVERLAPPED,*POVERLAPPED,*LPOVERLAPPED;
+typedef struct _STARTUPINFOA {
+	DWORD	cb;
+	LPSTR	lpReserved;
+	LPSTR	lpDesktop;
+	LPSTR	lpTitle;
+	DWORD	dwX;
+	DWORD	dwY;
+	DWORD	dwXSize;
+	DWORD	dwYSize;
+	DWORD	dwXCountChars;
+	DWORD	dwYCountChars;
+	DWORD	dwFillAttribute;
+	DWORD	dwFlags;
+	WORD	wShowWindow;
+	WORD	cbReserved2;
+	PBYTE	lpReserved2;
+	HANDLE	hStdInput;
+	HANDLE	hStdOutput;
+	HANDLE	hStdError;
+} STARTUPINFOA,*LPSTARTUPINFOA;
+typedef struct _STARTUPINFOW {
+	DWORD	cb;
+	LPWSTR	lpReserved;
+	LPWSTR	lpDesktop;
+	LPWSTR	lpTitle;
+	DWORD	dwX;
+	DWORD	dwY;
+	DWORD	dwXSize;
+	DWORD	dwYSize;
+	DWORD	dwXCountChars;
+	DWORD	dwYCountChars;
+	DWORD	dwFillAttribute;
+	DWORD	dwFlags;
+	WORD	wShowWindow;
+	WORD	cbReserved2;
+	PBYTE	lpReserved2;
+	HANDLE	hStdInput;
+	HANDLE	hStdOutput;
+	HANDLE	hStdError;
+} STARTUPINFOW,*LPSTARTUPINFOW;
+typedef struct _PROCESS_INFORMATION {
+	HANDLE hProcess;
+	HANDLE hThread;
+	DWORD dwProcessId;
+	DWORD dwThreadId;
+} PROCESS_INFORMATION,*LPPROCESS_INFORMATION;
+typedef struct _CRITICAL_SECTION_DEBUG {
+	WORD Type;
+	WORD CreatorBackTraceIndex;
+	struct _CRITICAL_SECTION *CriticalSection;
+	LIST_ENTRY ProcessLocksList;
+	DWORD EntryCount;
+	DWORD ContentionCount;
+	DWORD Spare [2];
+} CRITICAL_SECTION_DEBUG,*PCRITICAL_SECTION_DEBUG;
+typedef struct _CRITICAL_SECTION {
+	PCRITICAL_SECTION_DEBUG DebugInfo;
+	LONG LockCount;
+	LONG RecursionCount;
+	HANDLE OwningThread;
+	HANDLE LockSemaphore;
+	DWORD SpinCount;
+} CRITICAL_SECTION,*PCRITICAL_SECTION,*LPCRITICAL_SECTION;
+typedef struct _SYSTEMTIME {
+	WORD wYear;
+	WORD wMonth;
+	WORD wDayOfWeek;
+	WORD wDay;
+	WORD wHour;
+	WORD wMinute;
+	WORD wSecond;
+	WORD wMilliseconds;
+} SYSTEMTIME,*LPSYSTEMTIME;
+typedef struct _WIN32_FILE_ATTRIBUTE_DATA {
+	DWORD	dwFileAttributes;
+	FILETIME	ftCreationTime;
+	FILETIME	ftLastAccessTime;
+	FILETIME	ftLastWriteTime;
+	DWORD	nFileSizeHigh;
+	DWORD	nFileSizeLow;
+} WIN32_FILE_ATTRIBUTE_DATA,*LPWIN32_FILE_ATTRIBUTE_DATA;
+typedef struct _WIN32_FIND_DATAA {
+	DWORD dwFileAttributes;
+	FILETIME ftCreationTime;
+	FILETIME ftLastAccessTime;
+	FILETIME ftLastWriteTime;
+	DWORD nFileSizeHigh;
+	DWORD nFileSizeLow;
+	DWORD dwReserved0;
+	DWORD dwReserved1;
+	CHAR cFileName[MAX_PATH];
+	CHAR cAlternateFileName[14];
+} WIN32_FIND_DATAA,*LPWIN32_FIND_DATAA;
+typedef struct _WIN32_FIND_DATAW {
+	DWORD dwFileAttributes;
+	FILETIME ftCreationTime;
+	FILETIME ftLastAccessTime;
+	FILETIME ftLastWriteTime;
+	DWORD nFileSizeHigh;
+	DWORD nFileSizeLow;
+	DWORD dwReserved0;
+	DWORD dwReserved1;
+	WCHAR cFileName[MAX_PATH];
+	WCHAR cAlternateFileName[14];
+} WIN32_FIND_DATAW,*LPWIN32_FIND_DATAW;
+typedef struct _WIN32_STREAM_ID {
+	DWORD dwStreamId;
+	DWORD dwStreamAttributes;
+	LARGE_INTEGER Size;
+	DWORD dwStreamNameSize;
+	WCHAR cStreamName[ANYSIZE_ARRAY];
+} WIN32_STREAM_ID;
+typedef enum _FINDEX_INFO_LEVELS {
+	FindExInfoStandard,
+	FindExInfoMaxInfoLevel
+} FINDEX_INFO_LEVELS;
+typedef enum _FINDEX_SEARCH_OPS {
+	FindExSearchNameMatch,
+	FindExSearchLimitToDirectories,
+	FindExSearchLimitToDevices,
+	FindExSearchMaxSearchOp
+} FINDEX_SEARCH_OPS;
+typedef enum _ACL_INFORMATION_CLASS {
+	AclRevisionInformation=1,
+	AclSizeInformation
+} ACL_INFORMATION_CLASS;
+typedef struct tagHW_PROFILE_INFOA {
+	DWORD dwDockInfo;
+	CHAR szHwProfileGuid[HW_PROFILE_GUIDLEN];
+	CHAR szHwProfileName[MAX_PROFILE_LEN];
+} HW_PROFILE_INFOA,*LPHW_PROFILE_INFOA;
+typedef struct tagHW_PROFILE_INFOW {
+	DWORD dwDockInfo;
+	WCHAR szHwProfileGuid[HW_PROFILE_GUIDLEN];
+	WCHAR szHwProfileName[MAX_PROFILE_LEN];
+} HW_PROFILE_INFOW,*LPHW_PROFILE_INFOW;
+typedef enum _GET_FILEEX_INFO_LEVELS {
+	GetFileExInfoStandard,
+	GetFileExMaxInfoLevel
+} GET_FILEEX_INFO_LEVELS;
+typedef struct _SYSTEM_INFO {
+	_ANONYMOUS_UNION union {
+		DWORD dwOemId;
+		_ANONYMOUS_STRUCT struct {
+			WORD wProcessorArchitecture;
+			WORD wReserved;
+		} DUMMYSTRUCTNAME;
+	} DUMMYUNIONNAME;
+	DWORD dwPageSize;
+	PVOID lpMinimumApplicationAddress;
+	PVOID lpMaximumApplicationAddress;
+	DWORD dwActiveProcessorMask;
+	DWORD dwNumberOfProcessors;
+	DWORD dwProcessorType;
+	DWORD dwAllocationGranularity;
+	WORD wProcessorLevel;
+	WORD wProcessorRevision;
+} SYSTEM_INFO,*LPSYSTEM_INFO;
+typedef struct _SYSTEM_POWER_STATUS {
+	BYTE ACLineStatus;
+	BYTE BatteryFlag;
+	BYTE BatteryLifePercent;
+	BYTE Reserved1;
+	DWORD BatteryLifeTime;
+	DWORD BatteryFullLifeTime;
+} SYSTEM_POWER_STATUS,*LPSYSTEM_POWER_STATUS;
+typedef struct _TIME_ZONE_INFORMATION {
+	LONG Bias;
+	WCHAR StandardName[32];
+	SYSTEMTIME StandardDate;
+	LONG StandardBias;
+	WCHAR DaylightName[32];
+	SYSTEMTIME DaylightDate;
+	LONG DaylightBias;
+} TIME_ZONE_INFORMATION,*LPTIME_ZONE_INFORMATION;
+typedef struct _MEMORYSTATUS {
+	DWORD dwLength;
+	DWORD dwMemoryLoad;
+	DWORD dwTotalPhys;
+	DWORD dwAvailPhys;
+	DWORD dwTotalPageFile;
+	DWORD dwAvailPageFile;
+	DWORD dwTotalVirtual;
+	DWORD dwAvailVirtual;
+} MEMORYSTATUS,*LPMEMORYSTATUS;
+typedef struct _LDT_ENTRY {
+	WORD LimitLow;
+	WORD BaseLow;
+	union {
+		struct {
+			BYTE BaseMid;
+			BYTE Flags1;
+			BYTE Flags2;
+			BYTE BaseHi;
+		} Bytes;
+		struct {
+			DWORD BaseMid:8;
+			DWORD Type:5;
+			DWORD Dpl:2;
+			DWORD Pres:1;
+			DWORD LimitHi:4;
+			DWORD Sys:1;
+			DWORD Reserved_0:1;
+			DWORD Default_Big:1;
+			DWORD Granularity:1;
+			DWORD BaseHi:8;
+		} Bits;
+	} HighWord;
+} LDT_ENTRY,*PLDT_ENTRY,*LPLDT_ENTRY;
+typedef struct _PROCESS_HEAP_ENTRY {
+	PVOID lpData;
+	DWORD cbData;
+	BYTE cbOverhead;
+	BYTE iRegionIndex;
+	WORD wFlags;
+	_ANONYMOUS_UNION union {
+		struct {
+			HANDLE hMem;
+			DWORD dwReserved[3];
+		} Block;
+		struct {
+			DWORD dwCommittedSize;
+			DWORD dwUnCommittedSize;
+			LPVOID lpFirstBlock;
+			LPVOID lpLastBlock;
+		} Region;
+	} DUMMYUNIONNAME;
+} PROCESS_HEAP_ENTRY,*LPPROCESS_HEAP_ENTRY;
+typedef struct _OFSTRUCT {
+	BYTE cBytes;
+	BYTE fFixedDisk;
+	WORD nErrCode;
+	WORD Reserved1;
+	WORD Reserved2;
+	CHAR szPathName[OFS_MAXPATHNAME];
+} OFSTRUCT,*LPOFSTRUCT,*POFSTRUCT;
+typedef struct _WIN_CERTIFICATE {
+      DWORD dwLength;
+      WORD wRevision;
+      WORD wCertificateType;
+      BYTE bCertificate[1];
+} WIN_CERTIFICATE, *LPWIN_CERTIFICATE;
+
+typedef DWORD(WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER,LARGE_INTEGER,LARGE_INTEGER,LARGE_INTEGER,DWORD,DWORD,HANDLE,HANDLE,LPVOID);
+typedef void(WINAPI *LPFIBER_START_ROUTINE)(PVOID);
+typedef BOOL(CALLBACK *ENUMRESLANGPROC)(HMODULE,LPCTSTR,LPCTSTR,WORD,LONG);
+typedef BOOL(CALLBACK *ENUMRESNAMEPROC)(HMODULE,LPCTSTR,LPTSTR,LONG);
+typedef BOOL(CALLBACK *ENUMRESTYPEPROC)(HMODULE,LPTSTR,LONG);
+typedef void(CALLBACK *LPOVERLAPPED_COMPLETION_ROUTINE)(DWORD,DWORD,LPOVERLAPPED);
+typedef LONG(CALLBACK *PTOP_LEVEL_EXCEPTION_FILTER)(LPEXCEPTION_POINTERS);
+typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;
+typedef void(APIENTRY *PAPCFUNC)(DWORD);
+typedef void(CALLBACK *PTIMERAPCROUTINE)(PVOID,DWORD,DWORD);
+#define MAKEINTATOM(i) (LPTSTR)((DWORD)((WORD)(i)))
+/* Functions */
+#ifndef UNDER_CE
+int APIENTRY WinMain(HINSTANCE,HINSTANCE,LPSTR,int);
+#else
+int APIENTRY WinMain(HINSTANCE,HINSTANCE,LPWSTR,int);
+#endif
+int APIENTRY wWinMain(HINSTANCE,HINSTANCE,LPWSTR,int);
+long WINAPI _hread(HFILE,LPVOID,long);
+long WINAPI _hwrite(HFILE,LPCSTR,long);
+HFILE WINAPI _lclose(HFILE);
+HFILE WINAPI _lcreat(LPCSTR,int);
+LONG WINAPI _llseek(HFILE,LONG,int);
+HFILE WINAPI _lopen(LPCSTR,int);
+UINT WINAPI _lread(HFILE,LPVOID,UINT);
+UINT WINAPI _lwrite(HFILE,LPCSTR,UINT);
+#define AbnormalTermination() FALSE
+BOOL WINAPI AccessCheck(PSECURITY_DESCRIPTOR,HANDLE,DWORD,PGENERIC_MAPPING,PPRIVILEGE_SET,PDWORD,PDWORD,PBOOL);
+BOOL WINAPI AccessCheckAndAuditAlarmA(LPCSTR,LPVOID,LPSTR,LPSTR,PSECURITY_DESCRIPTOR,DWORD,PGENERIC_MAPPING,BOOL,PDWORD,PBOOL,PBOOL);
+BOOL WINAPI AccessCheckAndAuditAlarmW(LPCWSTR,LPVOID,LPWSTR,LPWSTR,PSECURITY_DESCRIPTOR,DWORD,PGENERIC_MAPPING,BOOL,PDWORD,PBOOL,PBOOL);
+BOOL WINAPI AddAccessAllowedAce(PACL,DWORD,DWORD,PSID);
+BOOL WINAPI AddAccessDeniedAce(PACL,DWORD,DWORD,PSID);
+BOOL WINAPI AddAce(PACL,DWORD,DWORD,PVOID,DWORD);
+ATOM WINAPI AddAtomA(LPCSTR);
+ATOM WINAPI AddAtomW(LPCWSTR);
+BOOL WINAPI AddAuditAccessAce(PACL,DWORD,DWORD,PSID,BOOL,BOOL);
+BOOL WINAPI AdjustTokenGroups(HANDLE,BOOL,PTOKEN_GROUPS,DWORD,PTOKEN_GROUPS,PDWORD);
+BOOL WINAPI AdjustTokenPrivileges(HANDLE,BOOL,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD);
+BOOL WINAPI AllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID*);
+BOOL WINAPI AllocateLocallyUniqueId(PLUID);
+BOOL WINAPI AreAllAccessesGranted(DWORD,DWORD);
+BOOL WINAPI AreAnyAccessesGranted(DWORD,DWORD);
+BOOL WINAPI AreFileApisANSI(void);
+BOOL WINAPI BackupEventLogA(HANDLE,LPCSTR);
+BOOL WINAPI BackupEventLogW(HANDLE,LPCWSTR);
+BOOL WINAPI BackupRead(HANDLE,PBYTE,DWORD,PDWORD,BOOL,BOOL,PVOID);
+BOOL WINAPI BackupSeek(HANDLE,DWORD,DWORD,PDWORD,PDWORD,PVOID);
+BOOL WINAPI BackupWrite(HANDLE,PBYTE,DWORD,PDWORD,BOOL,BOOL,PVOID);
+BOOL WINAPI Beep(DWORD,DWORD);
+HANDLE WINAPI BeginUpdateResourceA(LPCSTR,BOOL);
+HANDLE WINAPI BeginUpdateResourceW(LPCWSTR,BOOL);
+BOOL WINAPI BuildCommDCBA(LPCSTR,LPDCB);
+BOOL WINAPI BuildCommDCBW(LPCWSTR,LPDCB);
+BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR,LPDCB,LPCOMMTIMEOUTS);
+BOOL WINAPI BuildCommDCBAndTimeoutsW(LPCWSTR,LPDCB,LPCOMMTIMEOUTS);
+BOOL WINAPI CallNamedPipeA(LPCSTR,PVOID,DWORD,PVOID,DWORD,PDWORD,DWORD);
+BOOL WINAPI CallNamedPipeW(LPCWSTR,PVOID,DWORD,PVOID,DWORD,PDWORD,DWORD);
+BOOL WINAPI CancelIo(HANDLE);
+BOOL WINAPI CancelWaitableTimer(HANDLE);
+BOOL WINAPI ClearCommBreak(HANDLE);
+BOOL WINAPI ClearCommError(HANDLE,PDWORD,LPCOMSTAT);
+BOOL WINAPI ClearEventLogA(HANDLE,LPCSTR);
+BOOL WINAPI ClearEventLogW(HANDLE,LPCWSTR);
+BOOL WINAPI CloseEventLog(HANDLE);
+BOOL WINAPI CloseHandle(HANDLE);
+BOOL WINAPI CommConfigDialogA(LPCSTR,HWND,LPCOMMCONFIG);
+BOOL WINAPI CommConfigDialogW(LPCWSTR,HWND,LPCOMMCONFIG);
+LONG WINAPI CompareFileTime(CONST FILETIME*,CONST FILETIME*);
+BOOL WINAPI ConnectNamedPipe(HANDLE,LPOVERLAPPED);
+BOOL WINAPI ContinueDebugEvent(DWORD,DWORD,DWORD);
+PVOID WINAPI ConvertThreadToFiber(PVOID);
+BOOL WINAPI CopyFileA(LPCSTR,LPCSTR,BOOL);
+BOOL WINAPI CopyFileW(LPCWSTR,LPCWSTR,BOOL);
+BOOL WINAPI CopyFileExA(LPCSTR,LPCSTR,LPPROGRESS_ROUTINE,LPVOID,LPBOOL,DWORD);
+BOOL WINAPI CopyFileExW(LPCWSTR,LPCWSTR,LPPROGRESS_ROUTINE,LPVOID,LPBOOL,DWORD);
+#define RtlMoveMemory memmove
+#define RtlCopyMemory memcpy
+#define RtlFillMemory(d,l,f) memset((d), (f), (l))
+#define RtlZeroMemory(d,l) RtlFillMemory((d),(l),0)
+#define MoveMemory RtlMoveMemory
+#define CopyMemory RtlCopyMemory
+#define FillMemory RtlFillMemory
+#define ZeroMemory RtlZeroMemory
+BOOL WINAPI CopySid(DWORD,PSID,PSID);
+BOOL WINAPI CreateDirectoryA(LPCSTR,LPSECURITY_ATTRIBUTES);
+BOOL WINAPI CreateDirectoryW(LPCWSTR,LPSECURITY_ATTRIBUTES);
+BOOL WINAPI CreateDirectoryExA(LPCSTR,LPCSTR,LPSECURITY_ATTRIBUTES);
+BOOL WINAPI CreateDirectoryExW(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
+HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR);
+HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCWSTR);
+LPVOID WINAPI CreateFiber(DWORD,LPFIBER_START_ROUTINE,LPVOID);
+HANDLE WINAPI CreateFileA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
+HANDLE WINAPI CreateFileW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE);
+HANDLE WINAPI CreateFileMappingA(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCSTR);
+HANDLE WINAPI CreateFileMappingW(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,DWORD,DWORD,LPCWSTR);
+HANDLE WINAPI CreateHardLinkA(LPCSTR,LPCSTR,LPSECURITY_ATTRIBUTES);
+HANDLE WINAPI CreateHardLinkW(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
+HANDLE WINAPI CreateIoCompletionPort(HANDLE,HANDLE,DWORD,DWORD);
+HANDLE WINAPI CreateMailslotA(LPCSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+HANDLE WINAPI CreateMailslotW(LPCWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR);
+HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR);
+HANDLE WINAPI CreateNamedPipeA(LPCSTR,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+HANDLE WINAPI CreateNamedPipeW(LPCWSTR,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+BOOL WINAPI CreatePipe(PHANDLE,PHANDLE,LPSECURITY_ATTRIBUTES,DWORD);
+BOOL WINAPI CreatePrivateObjectSecurity(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR*,BOOL,HANDLE,PGENERIC_MAPPING);
+BOOL WINAPI CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION);
+BOOL WINAPI CreateProcessW(LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION);
+BOOL WINAPI CreateProcessAsUserA(HANDLE,LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION);
+BOOL WINAPI CreateProcessAsUserW(HANDLE,LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,PVOID,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION);
+HANDLE WINAPI CreateRemoteThread(HANDLE,LPSECURITY_ATTRIBUTES,DWORD,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD);
+HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCSTR);
+HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCWSTR);
+DWORD WINAPI CreateTapePartition(HANDLE,DWORD,DWORD,DWORD);
+HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES,DWORD,LPTHREAD_START_ROUTINE,PVOID,DWORD,PDWORD);
+HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR);
+HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR);
+BOOL WINAPI DebugActiveProcess(DWORD);
+void WINAPI DebugBreak(void);
+BOOL WINAPI DefineDosDeviceA(DWORD,LPCSTR,LPCSTR);
+BOOL WINAPI DefineDosDeviceW(DWORD,LPCWSTR,LPCWSTR);
+#define DefineHandleTable(w) ((w),TRUE)
+BOOL WINAPI DeleteAce(PACL,DWORD);
+ATOM WINAPI DeleteAtom(ATOM);
+void WINAPI DeleteCriticalSection(PCRITICAL_SECTION);
+void WINAPI DeleteFiber(PVOID);
+BOOL WINAPI DeleteFileA(LPCSTR);
+BOOL WINAPI DeleteFileW(LPCWSTR);
+BOOL WINAPI DeregisterEventSource(HANDLE);
+BOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR*);
+BOOL WINAPI DeviceIoControl(HANDLE,DWORD,PVOID,DWORD,PVOID,DWORD,PDWORD,POVERLAPPED);
+BOOL WINAPI DisableThreadLibraryCalls(HMODULE);
+BOOL WINAPI DisconnectNamedPipe(HANDLE);
+BOOL WINAPI DosDateTimeToFileTime(WORD,WORD,LPFILETIME);
+BOOL WINAPI DuplicateHandle(HANDLE,HANDLE,HANDLE,PHANDLE,DWORD,BOOL,DWORD);
+BOOL WINAPI DuplicateToken(HANDLE,SECURITY_IMPERSONATION_LEVEL,PHANDLE);
+BOOL WINAPI DuplicateTokenEx(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
+BOOL WINAPI EndUpdateResourceA(HANDLE,BOOL);
+BOOL WINAPI EndUpdateResourceW(HANDLE,BOOL);
+void WINAPI EnterCriticalSection(LPCRITICAL_SECTION);
+BOOL WINAPI EnumResourceLanguagesA(HINSTANCE,LPCSTR,LPCSTR,ENUMRESLANGPROC,LONG);
+BOOL WINAPI EnumResourceLanguagesW(HINSTANCE,LPCWSTR,LPCWSTR,ENUMRESLANGPROC,LONG);
+BOOL WINAPI EnumResourceNamesA(HINSTANCE,LPCSTR,ENUMRESNAMEPROC,LONG);
+BOOL WINAPI EnumResourceNamesW(HINSTANCE,LPCWSTR,ENUMRESNAMEPROC,LONG);
+BOOL WINAPI EnumResourceTypesA(HINSTANCE,ENUMRESTYPEPROC,LONG);
+BOOL WINAPI EnumResourceTypesW(HINSTANCE,ENUMRESTYPEPROC,LONG);
+BOOL WINAPI EqualPrefixSid(PSID,PSID);
+BOOL WINAPI EqualSid(PSID,PSID);
+DWORD WINAPI EraseTape(HANDLE,DWORD,BOOL);
+BOOL WINAPI EscapeCommFunction(HANDLE,DWORD);
+DECLSPEC_NORETURN void WINAPI ExitProcess(UINT);
+DECLSPEC_NORETURN void WINAPI ExitThread(DWORD);
+DWORD WINAPI ExpandEnvironmentStringsA(LPCSTR,LPSTR,DWORD);
+DWORD WINAPI ExpandEnvironmentStringsW(LPCWSTR,LPWSTR,DWORD);
+void WINAPI FatalAppExitA(UINT,LPCSTR);
+void WINAPI FatalAppExitW(UINT,LPCWSTR);
+void WINAPI FatalExit(int);
+BOOL WINAPI FileTimeToDosDateTime(CONST FILETIME *,LPWORD,LPWORD);
+BOOL WINAPI FileTimeToLocalFileTime(FILETIME *,LPFILETIME);
+BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *,LPSYSTEMTIME);
+ATOM WINAPI FindAtomA(LPCSTR);
+ATOM WINAPI FindAtomW(LPCWSTR);
+BOOL WINAPI FindClose(HANDLE);
+BOOL WINAPI FindCloseChangeNotification(HANDLE);
+HANDLE WINAPI FindFirstChangeNotificationA(LPCSTR,BOOL,DWORD);
+HANDLE WINAPI FindFirstChangeNotificationW(LPCWSTR,BOOL,DWORD);
+HANDLE WINAPI FindFirstFileA(LPCSTR,LPWIN32_FIND_DATAA);
+HANDLE WINAPI FindFirstFileW(LPCWSTR,LPWIN32_FIND_DATAW);
+HANDLE WINAPI FindFirstFileExA(LPCSTR,FINDEX_INFO_LEVELS,PVOID,FINDEX_SEARCH_OPS,PVOID,DWORD);
+HANDLE WINAPI FindFirstFileExW(LPCWSTR,FINDEX_INFO_LEVELS,PVOID,FINDEX_SEARCH_OPS,PVOID,DWORD);
+BOOL WINAPI FindFirstFreeAce(PACL,PVOID*);
+BOOL WINAPI FindNextChangeNotification(HANDLE);
+BOOL WINAPI FindNextFileA(HANDLE,LPWIN32_FIND_DATAA);
+BOOL WINAPI FindNextFileW(HANDLE,LPWIN32_FIND_DATAW);
+HRSRC WINAPI FindResourceA(HMODULE,LPCSTR,LPCSTR);
+HRSRC WINAPI FindResourceW(HINSTANCE,LPCWSTR,LPCWSTR);
+HRSRC WINAPI FindResourceExA(HINSTANCE,LPCSTR,LPCSTR,WORD);
+HRSRC WINAPI FindResourceExW(HINSTANCE,LPCWSTR,LPCWSTR,WORD);
+BOOL WINAPI FlushFileBuffers(HANDLE);
+BOOL WINAPI FlushInstructionCache(HANDLE,PCVOID,DWORD);
+BOOL WINAPI FlushViewOfFile(PCVOID,DWORD);
+DWORD WINAPI FormatMessageA(DWORD,PCVOID,DWORD,DWORD,LPSTR,DWORD,va_list*);
+DWORD WINAPI FormatMessageW(DWORD,PCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list*);
+BOOL WINAPI FreeEnvironmentStringsA(LPSTR);
+BOOL WINAPI FreeEnvironmentStringsW(LPWSTR);
+BOOL WINAPI FreeLibrary(HMODULE);
+DECLSPEC_NORETURN void WINAPI FreeLibraryAndExitThread(HMODULE,DWORD);
+#define FreeModule(m) FreeLibrary(m)
+#define FreeProcInstance(p) (void)(p)
+#ifndef XFree86Server
+BOOL WINAPI FreeResource(HGLOBAL);
+#endif /* ndef XFree86Server */
+PVOID WINAPI FreeSid(PSID);
+BOOL WINAPI GetAce(PACL,DWORD,PVOID);
+BOOL WINAPI GetAclInformation(PACL,PVOID,DWORD,ACL_INFORMATION_CLASS);
+UINT WINAPI GetAtomNameA(ATOM,LPSTR,int);
+UINT WINAPI GetAtomNameW(ATOM,LPWSTR,int);
+BOOL WINAPI GetBinaryTypeA(LPCSTR,PDWORD);
+BOOL WINAPI GetBinaryTypeW(LPCWSTR,PDWORD);
+LPSTR WINAPI GetCommandLineA(VOID);
+LPWSTR WINAPI GetCommandLineW(VOID);
+BOOL WINAPI GetCommConfig(HANDLE,LPCOMMCONFIG,PDWORD);
+BOOL WINAPI GetCommMask(HANDLE,PDWORD);
+BOOL WINAPI GetCommModemStatus(HANDLE,PDWORD);
+BOOL WINAPI GetCommProperties(HANDLE,LPCOMMPROP);
+BOOL WINAPI GetCommState(HANDLE,LPDCB);
+BOOL WINAPI GetCommTimeouts(HANDLE,LPCOMMTIMEOUTS);
+DWORD WINAPI GetCompressedFileSizeA(LPCSTR,PDWORD);
+DWORD WINAPI GetCompressedFileSizeW(LPCWSTR,PDWORD);
+BOOL WINAPI GetComputerNameA(LPSTR,PDWORD);
+BOOL WINAPI GetComputerNameW(LPWSTR,PDWORD);
+DWORD WINAPI GetCurrentDirectoryA(DWORD,LPSTR);
+DWORD WINAPI GetCurrentDirectoryW(DWORD,LPWSTR);
+BOOL WINAPI GetCurrentHwProfileA(LPHW_PROFILE_INFOA);
+BOOL WINAPI GetCurrentHwProfileW(LPHW_PROFILE_INFOW);
+HANDLE WINAPI GetCurrentProcess(void);
+DWORD WINAPI GetCurrentProcessId(void);
+HANDLE WINAPI GetCurrentThread(void);
+DWORD WINAPI GetCurrentThreadId(void);
+#define GetCurrentTime GetTickCount
+BOOL WINAPI GetDefaultCommConfigA(LPCSTR,LPCOMMCONFIG,PDWORD);
+BOOL WINAPI GetDefaultCommConfigW(LPCWSTR,LPCOMMCONFIG,PDWORD);
+BOOL WINAPI GetDiskFreeSpaceA(LPCSTR,PDWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI GetDiskFreeSpaceW(LPCWSTR,PDWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI GetDiskFreeSpaceExA(LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
+BOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER);
+UINT WINAPI GetDriveTypeA(LPCSTR);
+UINT WINAPI GetDriveTypeW(LPCWSTR);
+LPSTR WINAPI GetEnvironmentStrings(void);
+LPSTR WINAPI GetEnvironmentStringsA(void);
+LPWSTR WINAPI GetEnvironmentStringsW(void);
+DWORD WINAPI GetEnvironmentVariableA(LPCSTR,LPSTR,DWORD);
+DWORD WINAPI GetEnvironmentVariableW(LPCWSTR,LPWSTR,DWORD);
+BOOL WINAPI GetExitCodeProcess(HANDLE,PDWORD);
+BOOL WINAPI GetExitCodeThread(HANDLE,PDWORD);
+DWORD WINAPI GetFileAttributesA(LPCSTR);
+DWORD WINAPI GetFileAttributesW(LPCWSTR);
+BOOL WINAPI GetFileAttributesExA(LPCSTR,GET_FILEEX_INFO_LEVELS,PVOID);
+BOOL WINAPI GetFileAttributesExW(LPCWSTR,GET_FILEEX_INFO_LEVELS,PVOID);
+BOOL WINAPI GetFileInformationByHandle(HANDLE,LPBY_HANDLE_FILE_INFORMATION);
+BOOL WINAPI GetFileSecurityA(LPCSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,PDWORD);
+BOOL WINAPI GetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,PDWORD);
+DWORD WINAPI GetFileSize(HANDLE,PDWORD);
+BOOL WINAPI GetFileTime(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME);
+DWORD WINAPI GetFileType(HANDLE);
+#define GetFreeSpace(w) (0x100000L)
+DWORD WINAPI GetFullPathNameA(LPCSTR,DWORD,LPSTR,LPSTR*);
+DWORD WINAPI GetFullPathNameW(LPCWSTR,DWORD,LPWSTR,LPWSTR*);
+BOOL WINAPI GetHandleInformation(HANDLE,PDWORD);
+BOOL WINAPI GetKernelObjectSecurity(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,PDWORD);
+DWORD WINAPI GetLengthSid(PSID);
+void WINAPI GetLocalTime(LPSYSTEMTIME);
+DWORD WINAPI GetLogicalDrives(void);
+DWORD WINAPI GetLogicalDriveStringsA(DWORD,LPSTR);
+DWORD WINAPI GetLogicalDriveStringsW(DWORD,LPWSTR);
+DWORD WINAPI GetLongPathNameA(LPCSTR,LPSTR,DWORD);
+DWORD WINAPI GetLongPathNameW(LPCWSTR,LPWSTR,DWORD);
+BOOL WINAPI GetMailslotInfo(HANDLE,PDWORD,PDWORD,PDWORD,PDWORD);
+DWORD WINAPI GetModuleFileNameA(HINSTANCE,LPSTR,DWORD);
+DWORD WINAPI GetModuleFileNameW(HINSTANCE,LPWSTR,DWORD);
+HMODULE WINAPI GetModuleHandleA(LPCSTR);
+HMODULE WINAPI GetModuleHandleW(LPCWSTR);
+BOOL WINAPI GetNamedPipeHandleStateA(HANDLE,PDWORD,PDWORD,PDWORD,PDWORD,LPSTR,DWORD);
+BOOL WINAPI GetNamedPipeHandleStateW(HANDLE,PDWORD,PDWORD,PDWORD,PDWORD,LPWSTR,DWORD);
+BOOL WINAPI GetNamedPipeInfo(HANDLE,PDWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI GetNumberOfEventLogRecords(HANDLE,PDWORD);
+BOOL WINAPI GetOldestEventLogRecord(HANDLE,PDWORD);
+BOOL WINAPI GetOverlappedResult(HANDLE,LPOVERLAPPED,PDWORD,BOOL);
+DWORD WINAPI GetPriorityClass(HANDLE);
+BOOL WINAPI GetPrivateObjectSecurity(PSECURITY_DESCRIPTOR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,PDWORD);
+UINT WINAPI GetPrivateProfileIntA(LPCSTR,LPCSTR,INT,LPCSTR);
+UINT WINAPI GetPrivateProfileIntW(LPCWSTR,LPCWSTR,INT,LPCWSTR);
+DWORD WINAPI GetPrivateProfileSectionA(LPCSTR,LPSTR,DWORD,LPCSTR);
+DWORD WINAPI GetPrivateProfileSectionW(LPCWSTR,LPWSTR,DWORD,LPCWSTR);
+DWORD WINAPI GetPrivateProfileSectionNamesA(LPSTR,DWORD,LPCSTR);
+DWORD WINAPI GetPrivateProfileSectionNamesW(LPWSTR,DWORD,LPCWSTR);
+DWORD WINAPI GetPrivateProfileStringA(LPCSTR,LPCSTR,LPCSTR,LPSTR,DWORD,LPCSTR);
+DWORD WINAPI GetPrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,DWORD,LPCWSTR);
+BOOL WINAPI GetPrivateProfileStructA(LPCSTR,LPCSTR,PVOID,UINT,LPCSTR);
+BOOL WINAPI GetPrivateProfileStructW(LPCWSTR,LPCWSTR,PVOID,UINT,LPCWSTR);
+FARPROC WINAPI GetProcAddress(HINSTANCE,LPCSTR);
+BOOL WINAPI GetProcessAffinityMask(HANDLE,PDWORD,PDWORD);
+HANDLE WINAPI GetProcessHeap(VOID);
+DWORD WINAPI GetProcessHeaps(DWORD,PHANDLE);
+BOOL WINAPI GetProcessPriorityBoost(HANDLE,PBOOL);
+BOOL WINAPI GetProcessShutdownParameters(PDWORD,PDWORD);
+BOOL WINAPI GetProcessTimes(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME,LPFILETIME);
+DWORD WINAPI GetProcessVersion(DWORD);
+HWINSTA WINAPI GetProcessWindowStation(void);
+BOOL WINAPI GetProcessWorkingSetSize(HANDLE,PDWORD,PDWORD);
+UINT WINAPI GetProfileIntA(LPCSTR,LPCSTR,INT);
+UINT WINAPI GetProfileIntW(LPCWSTR,LPCWSTR,INT);
+DWORD WINAPI GetProfileSectionA(LPCSTR,LPSTR,DWORD);
+DWORD WINAPI GetProfileSectionW(LPCWSTR,LPWSTR,DWORD);
+DWORD WINAPI GetProfileStringA(LPCSTR,LPCSTR,LPCSTR,LPSTR,DWORD);
+DWORD WINAPI GetProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,DWORD);
+BOOL WINAPI GetQueuedCompletionStatus(HANDLE,PDWORD,PDWORD,LPOVERLAPPED*,DWORD);
+BOOL WINAPI GetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR_CONTROL,PDWORD);
+BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,LPBOOL,PACL*,LPBOOL);
+BOOL WINAPI GetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR,PSID*,LPBOOL);
+DWORD WINAPI GetSecurityDescriptorLength(PSECURITY_DESCRIPTOR);
+BOOL WINAPI GetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR,PSID*,LPBOOL);
+BOOL WINAPI GetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR,LPBOOL,PACL*,LPBOOL);
+DWORD WINAPI GetShortPathNameA(LPCSTR,LPSTR,DWORD);
+DWORD WINAPI GetShortPathNameW(LPCWSTR,LPWSTR,DWORD);
+PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID);
+DWORD WINAPI GetSidLengthRequired(UCHAR);
+PDWORD WINAPI GetSidSubAuthority(PSID,DWORD);
+PUCHAR WINAPI GetSidSubAuthorityCount(PSID);
+VOID WINAPI GetStartupInfoA(LPSTARTUPINFOA);
+VOID WINAPI GetStartupInfoW(LPSTARTUPINFOW);
+HANDLE WINAPI GetStdHandle(DWORD);
+UINT WINAPI GetSystemDirectoryA(LPSTR,UINT);
+UINT WINAPI GetSystemDirectoryW(LPWSTR,UINT);
+VOID WINAPI GetSystemInfo(LPSYSTEM_INFO);
+BOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS);
+VOID WINAPI GetSystemTime(LPSYSTEMTIME);
+BOOL WINAPI GetSystemTimeAdjustment(PDWORD,PDWORD,PBOOL);
+void WINAPI GetSystemTimeAsFileTime(LPFILETIME);
+DWORD WINAPI GetTapeParameters(HANDLE,DWORD,PDWORD,PVOID);
+DWORD WINAPI GetTapePosition(HANDLE,DWORD,PDWORD,PDWORD,PDWORD);
+DWORD WINAPI GetTapeStatus(HANDLE);
+UINT WINAPI GetTempFileNameA(LPCSTR,LPCSTR,UINT,LPSTR);
+UINT WINAPI GetTempFileNameW(LPCWSTR,LPCWSTR,UINT,LPWSTR);
+DWORD WINAPI GetTempPathA(DWORD,LPSTR);
+DWORD WINAPI GetTempPathW(DWORD,LPWSTR);
+BOOL WINAPI GetThreadContext(HANDLE,LPCONTEXT);
+int WINAPI GetThreadPriority(HANDLE);
+BOOL WINAPI GetThreadPriorityBoost(HANDLE,PBOOL);
+BOOL WINAPI GetThreadSelectorEntry(HANDLE,DWORD,LPLDT_ENTRY);
+BOOL WINAPI GetThreadTimes(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME,LPFILETIME);
+DWORD WINAPI GetTickCount(void);
+DWORD WINAPI GetTimeZoneInformation(LPTIME_ZONE_INFORMATION);
+BOOL WINAPI GetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,DWORD,PDWORD);
+BOOL WINAPI GetUserNameA (LPSTR,PDWORD);
+BOOL WINAPI GetUserNameW(LPWSTR,PDWORD);
+DWORD WINAPI GetVersion(void);
+BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA);
+BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW);
+BOOL WINAPI GetVolumeInformationA(LPCSTR,LPSTR,DWORD,PDWORD,PDWORD,PDWORD,LPSTR,DWORD);
+BOOL WINAPI GetVolumeInformationW(LPCWSTR,LPWSTR,DWORD,PDWORD,PDWORD,PDWORD,LPWSTR,DWORD);
+UINT WINAPI GetWindowsDirectoryA(LPSTR,UINT);
+UINT WINAPI GetWindowsDirectoryW(LPWSTR,UINT);
+DWORD WINAPI GetWindowThreadProcessId(HWND,PDWORD);
+ATOM WINAPI GlobalAddAtomA(LPCSTR);
+ATOM WINAPI GlobalAddAtomW( LPCWSTR);
+HGLOBAL WINAPI GlobalAlloc(UINT,DWORD);
+UINT WINAPI GlobalCompact(DWORD);
+ATOM WINAPI GlobalDeleteAtom(ATOM);
+HGLOBAL GlobalDiscard(HGLOBAL);
+ATOM WINAPI GlobalFindAtomA(LPCSTR);
+ATOM WINAPI GlobalFindAtomW(LPCWSTR);
+VOID WINAPI GlobalFix(HGLOBAL);
+UINT WINAPI GlobalFlags(HGLOBAL);
+HGLOBAL WINAPI GlobalFree(HGLOBAL);
+UINT WINAPI GlobalGetAtomNameA(ATOM,LPSTR,int);
+UINT WINAPI GlobalGetAtomNameW(ATOM,LPWSTR,int);
+HGLOBAL WINAPI GlobalHandle(PCVOID);
+LPVOID WINAPI GlobalLock(HGLOBAL);
+VOID WINAPI GlobalMemoryStatus(LPMEMORYSTATUS);
+HGLOBAL WINAPI GlobalReAlloc(HGLOBAL,DWORD,UINT);
+DWORD WINAPI GlobalSize(HGLOBAL);
+VOID WINAPI GlobalUnfix(HGLOBAL);
+BOOL WINAPI GlobalUnlock(HGLOBAL);
+BOOL WINAPI GlobalUnWire(HGLOBAL);
+PVOID WINAPI GlobalWire(HGLOBAL);
+#define HasOverlappedIoCompleted(lpOverlapped)  ((lpOverlapped)->Internal != STATUS_PENDING)
+PVOID WINAPI HeapAlloc(HANDLE,DWORD,DWORD);
+UINT WINAPI HeapCompact(HANDLE,DWORD);
+HANDLE WINAPI HeapCreate(DWORD,DWORD,DWORD);
+BOOL WINAPI HeapDestroy(HANDLE);
+BOOL WINAPI HeapFree(HANDLE,DWORD,PVOID);
+BOOL WINAPI HeapLock(HANDLE);
+PVOID WINAPI HeapReAlloc(HANDLE,DWORD,PVOID,DWORD);
+DWORD WINAPI HeapSize(HANDLE,DWORD,PCVOID);
+BOOL WINAPI HeapUnlock(HANDLE);
+BOOL WINAPI HeapValidate(HANDLE,DWORD,PCVOID);
+BOOL WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY);
+BOOL WINAPI ImpersonateLoggedOnUser(HANDLE);
+BOOL WINAPI ImpersonateNamedPipeClient(HANDLE);
+BOOL WINAPI ImpersonateSelf(SECURITY_IMPERSONATION_LEVEL);
+BOOL WINAPI InitAtomTable(DWORD);
+BOOL WINAPI InitializeAcl(PACL,DWORD,DWORD);
+VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION);
+#if (_WIN32_WINNT >= 0x0403) /* Needs NT4, SP3 or later.  */
+BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION,DWORD);
+DWORD WINAPI SetCriticalSectionSpinCount(LPCRITICAL_SECTION,DWORD);
+#endif
+BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR,DWORD);
+BOOL WINAPI InitializeSid (PSID,PSID_IDENTIFIER_AUTHORITY,BYTE);
+LONG WINAPI InterlockedCompareExchange(LPLONG,LONG,LONG);
+/* PVOID WINAPI InterlockedCompareExchangePointer(PVOID*,PVOID,PVOID); */
+#define InterlockedCompareExchangePointer(d,e,c) \
+    (PVOID)InterlockedCompareExchange((LPLONG)(d),(LONG)(e),(LONG)(c))
+LONG WINAPI InterlockedDecrement(LPLONG);
+LONG WINAPI InterlockedExchange(LPLONG,LONG);
+/* PVOID WINAPI InterlockedExchangePointer(PVOID*,PVOID); */
+#define InterlockedExchangePointer(t,v) \
+    (PVOID)InterlockedExchange((LPLONG)(t),(LONG)(v))
+LONG WINAPI InterlockedExchangeAdd(PLONG,LONG);
+LONG WINAPI InterlockedIncrement(LPLONG);
+BOOL WINAPI IsBadCodePtr(FARPROC);
+BOOL WINAPI IsBadHugeReadPtr(PCVOID,UINT);
+BOOL WINAPI IsBadHugeWritePtr(PVOID,UINT);
+BOOL WINAPI IsBadReadPtr(PCVOID,UINT);
+BOOL WINAPI IsBadStringPtrA(LPCSTR,UINT);
+BOOL WINAPI IsBadStringPtrW(LPCWSTR,UINT);
+BOOL WINAPI IsBadWritePtr(PVOID,UINT);
+BOOL WINAPI IsDebuggerPresent(void);
+BOOL WINAPI IsProcessorFeaturePresent(DWORD);
+BOOL WINAPI IsTextUnicode(PCVOID,int,LPINT);
+BOOL WINAPI IsValidAcl(PACL);
+BOOL WINAPI IsValidSecurityDescriptor(PSECURITY_DESCRIPTOR);
+BOOL WINAPI IsValidSid(PSID);
+void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION);
+#define LimitEmsPages(n)
+HINSTANCE WINAPI LoadLibraryA(LPCSTR);
+HINSTANCE WINAPI LoadLibraryExA(LPCSTR,HANDLE,DWORD);
+HINSTANCE WINAPI LoadLibraryExW(LPCWSTR,HANDLE,DWORD);
+HINSTANCE WINAPI LoadLibraryW(LPCWSTR);
+DWORD WINAPI LoadModule(LPCSTR,PVOID);
+HGLOBAL WINAPI LoadResource(HINSTANCE,HRSRC);
+HLOCAL WINAPI LocalAlloc(UINT,UINT);
+UINT WINAPI LocalCompact(UINT);
+HLOCAL LocalDiscard(HLOCAL);
+BOOL WINAPI LocalFileTimeToFileTime(CONST FILETIME *,LPFILETIME);
+UINT WINAPI LocalFlags(HLOCAL);
+HLOCAL WINAPI LocalFree(HLOCAL);
+HLOCAL WINAPI LocalHandle(LPCVOID);
+PVOID WINAPI LocalLock(HLOCAL);
+HLOCAL WINAPI LocalReAlloc(HLOCAL,UINT,UINT);
+UINT WINAPI LocalShrink(HLOCAL,UINT);
+UINT WINAPI LocalSize(HLOCAL);
+BOOL WINAPI LocalUnlock(HLOCAL);
+BOOL WINAPI LockFile(HANDLE,DWORD,DWORD,DWORD,DWORD);
+BOOL WINAPI LockFileEx(HANDLE,DWORD,DWORD,DWORD,DWORD,LPOVERLAPPED);
+PVOID WINAPI LockResource(HGLOBAL);
+#define LockSegment(w) GlobalFix((HANDLE)(w))
+BOOL WINAPI LogonUserA(LPSTR,LPSTR,LPSTR,DWORD,DWORD,PHANDLE);
+BOOL WINAPI LogonUserW(LPWSTR,LPWSTR,LPWSTR,DWORD,DWORD,PHANDLE);
+BOOL WINAPI LookupAccountNameA(LPCSTR,LPCSTR,PSID,PDWORD,LPSTR,PDWORD,PSID_NAME_USE);
+BOOL WINAPI LookupAccountNameW(LPCWSTR,LPCWSTR,PSID,PDWORD,LPWSTR,PDWORD,PSID_NAME_USE);
+BOOL WINAPI LookupAccountSidA(LPCSTR,PSID,LPSTR,PDWORD,LPSTR,PDWORD,PSID_NAME_USE);
+BOOL WINAPI LookupAccountSidW(LPCWSTR,PSID,LPWSTR,PDWORD,LPWSTR,PDWORD,PSID_NAME_USE);
+BOOL WINAPI LookupPrivilegeDisplayNameA(LPCSTR,LPCSTR,LPSTR,PDWORD,PDWORD);
+BOOL WINAPI LookupPrivilegeDisplayNameW(LPCWSTR,LPCWSTR,LPWSTR,PDWORD,PDWORD);
+BOOL WINAPI LookupPrivilegeNameA(LPCSTR,PLUID,LPSTR,PDWORD);
+BOOL WINAPI LookupPrivilegeNameW(LPCWSTR,PLUID,LPWSTR,PDWORD);
+BOOL WINAPI LookupPrivilegeValueA(LPCSTR,LPCSTR,PLUID);
+BOOL WINAPI LookupPrivilegeValueW(LPCWSTR,LPCWSTR,PLUID);
+LPSTR WINAPI lstrcatA(LPSTR,LPCSTR);
+LPWSTR WINAPI lstrcatW(LPWSTR,LPCWSTR);
+int WINAPI lstrcmpA(LPCSTR,LPCSTR);
+int WINAPI lstrcmpiA(LPCSTR,LPCSTR);
+int WINAPI lstrcmpiW( LPCWSTR,LPCWSTR);
+int WINAPI lstrcmpW(LPCWSTR,LPCWSTR);
+LPSTR WINAPI lstrcpyA(LPSTR,LPCSTR);
+LPSTR WINAPI lstrcpynA(LPSTR,LPCSTR,int);
+LPWSTR WINAPI lstrcpynW(LPWSTR,LPCWSTR,int);
+LPWSTR WINAPI lstrcpyW(LPWSTR,LPCWSTR);
+int WINAPI lstrlenA(LPCSTR);
+int WINAPI lstrlenW(LPCWSTR);
+BOOL WINAPI MakeAbsoluteSD(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,PDWORD,PACL,PDWORD,PACL,PDWORD,PSID,PDWORD,PSID,PDWORD);
+#define MakeProcInstance(p,i) (p)
+BOOL WINAPI MakeSelfRelativeSD(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,PDWORD);
+VOID WINAPI MapGenericMask(PDWORD,PGENERIC_MAPPING);
+PVOID WINAPI MapViewOfFile(HANDLE,DWORD,DWORD,DWORD,DWORD);
+PVOID WINAPI MapViewOfFileEx(HANDLE,DWORD,DWORD,DWORD,DWORD,PVOID);
+BOOL WINAPI MoveFileA(LPCSTR,LPCSTR);
+BOOL WINAPI MoveFileExA(LPCSTR,LPCSTR,DWORD);
+BOOL WINAPI MoveFileExW(LPCWSTR,LPCWSTR,DWORD);
+BOOL WINAPI MoveFileW(LPCWSTR,LPCWSTR);
+int WINAPI MulDiv(int,int,int);
+BOOL WINAPI NotifyChangeEventLog(HANDLE,HANDLE);
+BOOL WINAPI ObjectCloseAuditAlarmA(LPCSTR,PVOID,BOOL);
+BOOL WINAPI ObjectCloseAuditAlarmW(LPCWSTR,PVOID,BOOL);
+BOOL WINAPI ObjectDeleteAuditAlarmA(LPCSTR,PVOID,BOOL);
+BOOL WINAPI ObjectDeleteAuditAlarmW(LPCWSTR,PVOID,BOOL);
+BOOL WINAPI ObjectOpenAuditAlarmA(LPCSTR,PVOID,LPSTR,LPSTR,PSECURITY_DESCRIPTOR,HANDLE,DWORD,DWORD,PPRIVILEGE_SET,BOOL,BOOL,PBOOL);
+BOOL WINAPI ObjectOpenAuditAlarmW(LPCWSTR,PVOID,LPWSTR,LPWSTR,PSECURITY_DESCRIPTOR,HANDLE,DWORD,DWORD,PPRIVILEGE_SET,BOOL,BOOL,PBOOL);
+BOOL WINAPI ObjectPrivilegeAuditAlarmA(LPCSTR,PVOID,HANDLE,DWORD,PPRIVILEGE_SET,BOOL);
+BOOL WINAPI ObjectPrivilegeAuditAlarmW(LPCWSTR,PVOID,HANDLE,DWORD,PPRIVILEGE_SET,BOOL);
+HANDLE WINAPI OpenBackupEventLogA(LPCSTR,LPCSTR);
+HANDLE WINAPI OpenBackupEventLogW(LPCWSTR,LPCWSTR);
+HANDLE WINAPI OpenEventA(DWORD,BOOL,LPCSTR);
+HANDLE WINAPI OpenEventLogA (LPCSTR,LPCSTR);
+HANDLE WINAPI OpenEventLogW(LPCWSTR,LPCWSTR);
+HANDLE WINAPI OpenEventW(DWORD,BOOL,LPCWSTR);
+HFILE WINAPI OpenFile(LPCSTR,LPOFSTRUCT,UINT);
+HANDLE WINAPI OpenFileMappingA(DWORD,BOOL,LPCSTR);
+HANDLE WINAPI OpenFileMappingW(DWORD,BOOL,LPCWSTR);
+HANDLE WINAPI OpenMutexA(DWORD,BOOL,LPCSTR);
+HANDLE WINAPI OpenMutexW(DWORD,BOOL,LPCWSTR);
+HANDLE WINAPI OpenProcess(DWORD,BOOL,DWORD);
+BOOL WINAPI OpenProcessToken(HANDLE,DWORD,PHANDLE);
+HANDLE WINAPI OpenSemaphoreA(DWORD,BOOL,LPCSTR);
+HANDLE WINAPI OpenSemaphoreW(DWORD,BOOL,LPCWSTR);
+BOOL WINAPI OpenThreadToken(HANDLE,DWORD,BOOL,PHANDLE);
+HANDLE WINAPI OpenWaitableTimerA(DWORD,BOOL,LPCSTR);
+HANDLE WINAPI OpenWaitableTimerW(DWORD,BOOL,LPCWSTR);
+void WINAPI OutputDebugStringA(LPCSTR);
+void WINAPI OutputDebugStringW(LPCWSTR);
+BOOL WINAPI PeekNamedPipe(HANDLE,PVOID,DWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI PostQueuedCompletionStatus(HANDLE,DWORD,DWORD,LPOVERLAPPED);
+DWORD WINAPI PrepareTape(HANDLE,DWORD,BOOL);
+BOOL WINAPI PrivilegeCheck (HANDLE,PPRIVILEGE_SET,PBOOL);
+BOOL WINAPI PrivilegedServiceAuditAlarmA(LPCSTR,LPCSTR,HANDLE,PPRIVILEGE_SET,BOOL);
+BOOL WINAPI PrivilegedServiceAuditAlarmW(LPCWSTR,LPCWSTR,HANDLE,PPRIVILEGE_SET,BOOL);
+BOOL WINAPI PulseEvent(HANDLE);
+BOOL WINAPI PurgeComm(HANDLE,DWORD);
+DWORD WINAPI QueryDosDeviceA(LPCSTR,LPSTR,DWORD);
+DWORD WINAPI QueryDosDeviceW(LPCWSTR,LPWSTR,DWORD);
+BOOL WINAPI QueryPerformanceCounter(PLARGE_INTEGER);
+BOOL WINAPI QueryPerformanceFrequency(PLARGE_INTEGER);
+DWORD WINAPI QueueUserAPC(PAPCFUNC,HANDLE,DWORD);
+void WINAPI RaiseException(DWORD,DWORD,DWORD,const DWORD*);
+BOOL WINAPI ReadDirectoryChangesW(HANDLE,PVOID,DWORD,BOOL,DWORD,PDWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);
+BOOL WINAPI ReadEventLogA(HANDLE,DWORD,DWORD,PVOID,DWORD,DWORD *,DWORD *);
+BOOL WINAPI ReadEventLogW(HANDLE,DWORD,DWORD,PVOID,DWORD,DWORD *,DWORD *);
+BOOL WINAPI ReadFile(HANDLE,PVOID,DWORD,PDWORD,LPOVERLAPPED);
+BOOL WINAPI ReadFileEx(HANDLE,PVOID,DWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);
+BOOL WINAPI ReadProcessMemory(HANDLE,PCVOID,PVOID,DWORD,PDWORD);
+HANDLE WINAPI RegisterEventSourceA (LPCSTR,LPCSTR);
+HANDLE WINAPI RegisterEventSourceW(LPCWSTR,LPCWSTR);
+BOOL WINAPI ReleaseMutex(HANDLE);
+BOOL WINAPI ReleaseSemaphore(HANDLE,LONG,LPLONG);
+BOOL WINAPI RemoveDirectoryA(LPCSTR);
+BOOL WINAPI RemoveDirectoryW(LPCWSTR);
+BOOL WINAPI ReportEventA(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCSTR*,PVOID);
+BOOL WINAPI ReportEventW(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCWSTR*,PVOID);
+BOOL WINAPI ResetEvent(HANDLE);
+DWORD WINAPI ResumeThread(HANDLE);
+BOOL WINAPI RevertToSelf(void);
+DWORD WINAPI SearchPathA(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*);
+DWORD WINAPI SearchPathW(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPWSTR,LPWSTR*);
+BOOL WINAPI SetAclInformation(PACL,PVOID,DWORD,ACL_INFORMATION_CLASS);
+BOOL WINAPI SetCommBreak(HANDLE);
+BOOL WINAPI SetCommConfig(HANDLE,LPCOMMCONFIG,DWORD);
+BOOL WINAPI SetCommMask(HANDLE,DWORD);
+BOOL WINAPI SetCommState(HANDLE,LPDCB);
+BOOL WINAPI SetCommTimeouts(HANDLE,LPCOMMTIMEOUTS);
+BOOL WINAPI SetComputerNameA(LPCSTR);
+BOOL WINAPI SetComputerNameW(LPCWSTR);
+BOOL WINAPI SetCurrentDirectoryA(LPCSTR);
+BOOL WINAPI SetCurrentDirectoryW(LPCWSTR);
+BOOL WINAPI SetDefaultCommConfigA(LPCSTR,LPCOMMCONFIG,DWORD);
+BOOL WINAPI SetDefaultCommConfigW(LPCWSTR,LPCOMMCONFIG,DWORD);
+BOOL WINAPI SetEndOfFile(HANDLE);
+BOOL WINAPI SetEnvironmentVariableA(LPCSTR,LPCSTR);
+BOOL WINAPI SetEnvironmentVariableW(LPCWSTR,LPCWSTR);
+UINT WINAPI SetErrorMode(UINT);
+BOOL WINAPI SetEvent(HANDLE);
+VOID WINAPI SetFileApisToANSI(void);
+VOID WINAPI SetFileApisToOEM(void);
+BOOL WINAPI SetFileAttributesA(LPCSTR,DWORD);
+BOOL WINAPI SetFileAttributesW(LPCWSTR,DWORD);
+DWORD WINAPI SetFilePointer(HANDLE,LONG,PLONG,DWORD);
+BOOL WINAPI SetFileSecurityA(LPCSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
+BOOL WINAPI SetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
+BOOL WINAPI SetFileTime(HANDLE,const FILETIME*,const FILETIME*,const FILETIME*);
+UINT WINAPI SetHandleCount(UINT);
+BOOL WINAPI SetHandleInformation(HANDLE,DWORD,DWORD);
+BOOL WINAPI SetKernelObjectSecurity(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
+void WINAPI SetLastError(DWORD);
+void WINAPI SetLastErrorEx(DWORD,DWORD);
+BOOL WINAPI SetLocalTime(const SYSTEMTIME*);
+BOOL WINAPI SetMailslotInfo(HANDLE,DWORD);
+BOOL WINAPI SetNamedPipeHandleState(HANDLE,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI SetPriorityClass(HANDLE,DWORD);
+BOOL WINAPI SetPrivateObjectSecurity(SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR *,PGENERIC_MAPPING,HANDLE);
+BOOL WINAPI SetProcessAffinityMask(HANDLE,DWORD);
+BOOL WINAPI SetProcessPriorityBoost(HANDLE,BOOL);
+BOOL WINAPI SetProcessShutdownParameters(DWORD,DWORD);
+BOOL WINAPI SetProcessWorkingSetSize(HANDLE,DWORD,DWORD);
+BOOL WINAPI SetSecurityDescriptorControl(PSECURITY_DESCRIPTOR,SECURITY_DESCRIPTOR_CONTROL,SECURITY_DESCRIPTOR_CONTROL);
+BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR,BOOL,PACL,BOOL);
+BOOL WINAPI SetSecurityDescriptorGroup(PSECURITY_DESCRIPTOR,PSID,BOOL);
+BOOL WINAPI SetSecurityDescriptorOwner(PSECURITY_DESCRIPTOR,PSID,BOOL);
+BOOL WINAPI SetSecurityDescriptorSacl(PSECURITY_DESCRIPTOR,BOOL,PACL,BOOL);
+BOOL WINAPI SetStdHandle(DWORD,HANDLE);
+#define SetSwapAreaSize(w) (w)
+BOOL WINAPI SetSystemPowerState(BOOL,BOOL);
+BOOL WINAPI SetSystemTime(const SYSTEMTIME*);
+BOOL WINAPI SetSystemTimeAdjustment(DWORD,BOOL);
+DWORD WINAPI SetTapeParameters(HANDLE,DWORD,PVOID);
+DWORD WINAPI SetTapePosition(HANDLE,DWORD,DWORD,DWORD,DWORD,BOOL);
+DWORD WINAPI SetThreadAffinityMask(HANDLE,DWORD);
+BOOL WINAPI SetThreadContext(HANDLE,const CONTEXT*);
+DWORD WINAPI SetThreadIdealProcessor(HANDLE,DWORD);
+BOOL WINAPI SetThreadPriority(HANDLE,int);
+BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL);
+BOOL WINAPI SetThreadToken (PHANDLE,HANDLE);
+BOOL WINAPI SetTimeZoneInformation(const TIME_ZONE_INFORMATION *);
+BOOL WINAPI SetTokenInformation(HANDLE,TOKEN_INFORMATION_CLASS,PVOID,DWORD);
+LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER);
+BOOL WINAPI SetupComm(HANDLE,DWORD,DWORD);
+BOOL WINAPI SetVolumeLabelA(LPCSTR,LPCSTR);
+BOOL WINAPI SetVolumeLabelW(LPCWSTR,LPCWSTR);
+BOOL WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,PVOID,BOOL);
+BOOL WINAPI SignalObjectAndWait(HANDLE,HANDLE,DWORD,BOOL);
+DWORD WINAPI SizeofResource(HINSTANCE,HRSRC);
+void WINAPI Sleep(DWORD);
+DWORD WINAPI SleepEx(DWORD,BOOL);
+DWORD WINAPI SuspendThread(HANDLE);
+void WINAPI SwitchToFiber(PVOID);
+BOOL WINAPI SwitchToThread(void);
+BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME*,LPFILETIME);
+BOOL WINAPI SystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION,LPSYSTEMTIME,LPSYSTEMTIME);
+BOOL WINAPI TerminateProcess(HANDLE,UINT);
+BOOL WINAPI TerminateThread(HANDLE,DWORD);
+DWORD WINAPI TlsAlloc(VOID);
+BOOL WINAPI TlsFree(DWORD);
+PVOID WINAPI TlsGetValue(DWORD);
+BOOL WINAPI TlsSetValue(DWORD,PVOID);
+BOOL WINAPI TransactNamedPipe(HANDLE,PVOID,DWORD,PVOID,DWORD,PDWORD,LPOVERLAPPED);
+BOOL WINAPI TransmitCommChar(HANDLE,char);
+BOOL WINAPI TryEnterCriticalSection(LPCRITICAL_SECTION);
+LONG WINAPI UnhandledExceptionFilter(LPEXCEPTION_POINTERS);
+BOOL WINAPI UnlockFile(HANDLE,DWORD,DWORD,DWORD,DWORD);
+BOOL WINAPI UnlockFileEx(HANDLE,DWORD,DWORD,DWORD,LPOVERLAPPED);
+#define UnlockResource(h) (h)
+#define UnlockSegment(w) GlobalUnfix((HANDLE)(w))
+BOOL WINAPI UnmapViewOfFile(PVOID);
+BOOL WINAPI UpdateResourceA(HANDLE,LPCSTR,LPCSTR,WORD,PVOID,DWORD);
+BOOL WINAPI UpdateResourceW(HANDLE,LPCWSTR,LPCWSTR,WORD,PVOID,DWORD);
+BOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA,DWORD,DWORDLONG);
+BOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW,DWORD,DWORDLONG);
+PVOID WINAPI VirtualAlloc(PVOID,DWORD,DWORD,DWORD);
+PVOID WINAPI VirtualAllocEx(HANDLE,PVOID,DWORD,DWORD,DWORD);
+BOOL WINAPI VirtualFree(PVOID,DWORD,DWORD);
+BOOL WINAPI VirtualFreeEx(HANDLE,PVOID,DWORD,DWORD);
+BOOL WINAPI VirtualLock(PVOID,DWORD);
+BOOL WINAPI VirtualProtect(PVOID,DWORD,DWORD,PDWORD);
+BOOL WINAPI VirtualProtectEx(HANDLE,PVOID,DWORD,DWORD,PDWORD);
+DWORD WINAPI VirtualQuery(LPCVOID,PMEMORY_BASIC_INFORMATION,DWORD);
+DWORD WINAPI VirtualQueryEx(HANDLE,LPCVOID,PMEMORY_BASIC_INFORMATION,DWORD);
+BOOL WINAPI VirtualUnlock(PVOID,DWORD);
+BOOL WINAPI WaitCommEvent(HANDLE,PDWORD,LPOVERLAPPED);
+BOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT,DWORD);
+DWORD WINAPI WaitForMultipleObjects(DWORD,const HANDLE*,BOOL,DWORD);
+DWORD WINAPI WaitForMultipleObjectsEx(DWORD,const HANDLE*,BOOL,DWORD,BOOL);
+DWORD WINAPI WaitForSingleObject(HANDLE,DWORD);
+DWORD WINAPI WaitForSingleObjectEx(HANDLE,DWORD,BOOL);
+BOOL WINAPI WaitNamedPipeA(LPCSTR,DWORD);
+BOOL WINAPI WaitNamedPipeW(LPCWSTR,DWORD);
+BOOL WINAPI WinLoadTrustProvider(GUID*);
+BOOL WINAPI WriteFile(HANDLE,PCVOID,DWORD,PDWORD,LPOVERLAPPED);
+BOOL WINAPI WriteFileEx(HANDLE,PCVOID,DWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);
+BOOL WINAPI WritePrivateProfileSectionA(LPCSTR,LPCSTR,LPCSTR);
+BOOL WINAPI WritePrivateProfileSectionW(LPCWSTR,LPCWSTR,LPCWSTR);
+BOOL WINAPI WritePrivateProfileStringA(LPCSTR,LPCSTR,LPCSTR,LPCSTR);
+BOOL WINAPI WritePrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR);
+BOOL WINAPI WritePrivateProfileStructA(LPCSTR,LPCSTR,PVOID,UINT,LPCSTR);
+BOOL WINAPI WritePrivateProfileStructW(LPCWSTR,LPCWSTR,PVOID,UINT,LPCWSTR);
+BOOL WINAPI WriteProcessMemory(HANDLE,PVOID,PVOID,DWORD,PDWORD);
+BOOL WINAPI WriteProfileSectionA(LPCSTR,LPCSTR);
+BOOL WINAPI WriteProfileSectionW(LPCWSTR,LPCWSTR);
+BOOL WINAPI WriteProfileStringA(LPCSTR,LPCSTR,LPCSTR);
+BOOL WINAPI WriteProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR);
+DWORD WINAPI WriteTapemark(HANDLE,DWORD,DWORD,BOOL);
+#define Yield()
+
+#ifdef UNICODE
+typedef STARTUPINFOW STARTUPINFO,*LPSTARTUPINFO;
+typedef WIN32_FIND_DATAW WIN32_FIND_DATA,*LPWIN32_FIND_DATA;
+typedef HW_PROFILE_INFOW HW_PROFILE_INFO,*LPHW_PROFILE_INFO;
+#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmW
+#define AddAtom AddAtomW
+#define BackupEventLog BackupEventLogW
+#define BeginUpdateResource BeginUpdateResourceW
+#define BuildCommDCB BuildCommDCBW
+#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW
+#define CallNamedPipe CallNamedPipeW
+#define ClearEventLog ClearEventLogW
+#define CommConfigDialog CommConfigDialogW
+#define CopyFile CopyFileW
+#define CopyFileEx CopyFileExW
+#define CreateDirectory CreateDirectoryW
+#define CreateDirectoryEx CreateDirectoryExW
+#define CreateEvent CreateEventW
+#define CreateFile CreateFileW
+#define CreateFileMapping CreateFileMappingW
+#define CreateHardLink CreateHardLinkW
+#define CreateMailslot CreateMailslotW
+#define CreateMutex CreateMutexW
+#define CreateNamedPipe CreateNamedPipeW
+#define CreateProcess CreateProcessW
+#define CreateProcessAsUser CreateProcessAsUserW
+#define CreateSemaphore CreateSemaphoreW
+#define CreateWaitableTimer CreateWaitableTimerW
+#define DefineDosDevice DefineDosDeviceW
+#define DeleteFile DeleteFileW
+#define EndUpdateResource EndUpdateResourceW
+#define EnumResourceLanguages EnumResourceLanguagesW
+#define EnumResourceNames EnumResourceNamesW
+#define EnumResourceTypes EnumResourceTypesW
+#define ExpandEnvironmentStrings ExpandEnvironmentStringsW
+#define FatalAppExit FatalAppExitW
+#define FindAtom FindAtomW
+#define FindFirstChangeNotification FindFirstChangeNotificationW
+#define FindFirstFile FindFirstFileW
+#define FindFirstFileEx FindFirstFileExW
+#define FindNextFile FindNextFileW
+#define FindResource FindResourceW
+#define FindResourceEx FindResourceExW
+#define FormatMessage FormatMessageW
+#define FreeEnvironmentStrings FreeEnvironmentStringsW
+#define GetAtomName GetAtomNameW
+#define GetBinaryType GetBinaryTypeW
+#define GetCommandLine GetCommandLineW
+#define GetCompressedFileSize GetCompressedFileSizeW
+#define GetComputerName GetComputerNameW
+#define GetCurrentDirectory GetCurrentDirectoryW
+#define GetDefaultCommConfig GetDefaultCommConfigW
+#define GetDiskFreeSpace GetDiskFreeSpaceW
+#define GetDiskFreeSpaceEx GetDiskFreeSpaceExW
+#define GetDriveType GetDriveTypeW
+#define GetEnvironmentStrings GetEnvironmentStringsW
+#define GetEnvironmentVariable GetEnvironmentVariableW
+#define GetFileAttributes GetFileAttributesW
+#define GetFileSecurity GetFileSecurityW
+#define GetFileAttributesEx GetFileAttributesExW
+#define GetFullPathName GetFullPathNameW
+#define GetLogicalDriveStrings GetLogicalDriveStringsW
+#define GetLongPathName GetLongPathNameW
+#define GetModuleFileName GetModuleFileNameW
+#define GetModuleHandle GetModuleHandleW
+#define GetNamedPipeHandleState GetNamedPipeHandleStateW
+#define GetPrivateProfileInt GetPrivateProfileIntW
+#define GetPrivateProfileSection GetPrivateProfileSectionW
+#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesW
+#define GetPrivateProfileString GetPrivateProfileStringW
+#define GetPrivateProfileStruct GetPrivateProfileStructW
+#define GetProfileInt GetProfileIntW
+#define GetProfileSection GetProfileSectionW
+#define GetProfileString GetProfileStringW
+#define GetShortPathName GetShortPathNameW
+#define GetStartupInfo GetStartupInfoW
+#define GetSystemDirectory GetSystemDirectoryW
+#define GetTempFileName GetTempFileNameW
+#define GetTempPath GetTempPathW
+#define GetUserName GetUserNameW
+#define GetVersionEx GetVersionExW
+#define GetVolumeInformation GetVolumeInformationW
+#define GetWindowsDirectory GetWindowsDirectoryW
+#define GlobalAddAtom GlobalAddAtomW
+#define GlobalFindAtom GlobalFindAtomW
+#define GlobalGetAtomName GlobalGetAtomNameW
+#define IsBadStringPtr IsBadStringPtrW
+#define LoadLibrary LoadLibraryW
+#define LoadLibraryEx LoadLibraryExW
+#define LogonUser LogonUserW
+#define LookupAccountName LookupAccountNameW
+#define LookupAccountSid LookupAccountSidW
+#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameW
+#define LookupPrivilegeName LookupPrivilegeNameW
+#define LookupPrivilegeValue LookupPrivilegeValueW
+#define lstrcat lstrcatW
+#define lstrcmp lstrcmpW
+#define lstrcmpi lstrcmpiW
+#define lstrcpy lstrcpyW
+#define lstrcpyn lstrcpynW
+#define lstrlen lstrlenW
+#define MoveFile MoveFileW
+#define MoveFileEx MoveFileExW
+#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmW
+#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmW
+#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmW
+#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmW
+#define OpenBackupEventLog OpenBackupEventLogW
+#define OpenEvent OpenEventW
+#define OpenEventLog OpenEventLogW
+#define OpenFileMapping OpenFileMappingW
+#define OpenMutex OpenMutexW
+#define OpenSemaphore OpenSemaphoreW
+#define OutputDebugString OutputDebugStringW
+#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmW
+#define QueryDosDevice QueryDosDeviceW
+#define ReadEventLog ReadEventLogW
+#define RegisterEventSource RegisterEventSourceW
+#define RemoveDirectory RemoveDirectoryW
+#define ReportEvent ReportEventW
+#define SearchPath SearchPathW
+#define SetComputerName SetComputerNameW
+#define SetCurrentDirectory SetCurrentDirectoryW
+#define SetDefaultCommConfig SetDefaultCommConfigW
+#define SetEnvironmentVariable SetEnvironmentVariableW
+#define SetFileAttributes SetFileAttributesW
+#define SetFileSecurity SetFileSecurityW
+#define SetVolumeLabel SetVolumeLabelW
+#define UpdateResource UpdateResourceW
+#define VerifyVersionInfo VerifyVersionInfoW
+#define WaitNamedPipe WaitNamedPipeW
+#define WritePrivateProfileSection WritePrivateProfileSectionW
+#define WritePrivateProfileString WritePrivateProfileStringW
+#define WritePrivateProfileStruct WritePrivateProfileStructW
+#define WriteProfileSection WriteProfileSectionW
+#define WriteProfileString WriteProfileStringW
+#else
+typedef STARTUPINFOA STARTUPINFO,*LPSTARTUPINFO;
+typedef WIN32_FIND_DATAA WIN32_FIND_DATA,*LPWIN32_FIND_DATA;
+typedef HW_PROFILE_INFOA HW_PROFILE_INFO,*LPHW_PROFILE_INFO;
+#define AccessCheckAndAuditAlarm AccessCheckAndAuditAlarmA
+#define AddAtom AddAtomA
+#define BackupEventLog BackupEventLogA
+#define BeginUpdateResource BeginUpdateResourceA
+#define BuildCommDCB BuildCommDCBA
+#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA
+#define CallNamedPipe CallNamedPipeA
+#define ClearEventLog ClearEventLogA
+#define CommConfigDialog CommConfigDialogA
+#define CopyFile CopyFileA
+#define CopyFileEx CopyFileExA
+#define CreateDirectory CreateDirectoryA
+#define CreateDirectoryEx CreateDirectoryExA
+#define CreateEvent CreateEventA
+#define CreateFile CreateFileA
+#define CreateFileMapping CreateFileMappingA
+#define CreateHardLink CreateHardLinkA
+#define CreateMailslot CreateMailslotA
+#define CreateMutex CreateMutexA
+#define CreateNamedPipe CreateNamedPipeA
+#define CreateProcess CreateProcessA
+#define CreateProcessAsUser CreateProcessAsUserA
+#define CreateSemaphore CreateSemaphoreA
+#define CreateWaitableTimer CreateWaitableTimerA
+#define DefineDosDevice DefineDosDeviceA
+#define DeleteFile DeleteFileA
+#define EndUpdateResource EndUpdateResourceA
+#define EnumResourceLanguages EnumResourceLanguagesA
+#define EnumResourceNames EnumResourceNamesA
+#define EnumResourceTypes EnumResourceTypesA
+#define ExpandEnvironmentStrings ExpandEnvironmentStringsA
+#define FatalAppExit FatalAppExitA
+#define FindAtom FindAtomA
+#define FindFirstChangeNotification FindFirstChangeNotificationA
+#define FindFirstFile FindFirstFileA
+#define FindFirstFileEx FindFirstFileExW
+#define FindNextFile FindNextFileA
+#define FindResource FindResourceA
+#define FindResourceEx FindResourceExA
+#define FormatMessage FormatMessageA
+#define FreeEnvironmentStrings FreeEnvironmentStringsA
+#define GetAtomName GetAtomNameA
+#define GetBinaryType GetBinaryTypeA
+#define GetCommandLine GetCommandLineA
+#define GetComputerName GetComputerNameA
+#define GetCompressedFileSize GetCompressedFileSizeA
+#define GetCurrentDirectory GetCurrentDirectoryA
+#define GetDefaultCommConfig GetDefaultCommConfigA
+#define GetDiskFreeSpace GetDiskFreeSpaceA
+#define GetDiskFreeSpaceEx GetDiskFreeSpaceExA
+#define GetDriveType GetDriveTypeA
+#define GetEnvironmentStringsA GetEnvironmentStrings
+#define GetEnvironmentVariable GetEnvironmentVariableA
+#define GetFileAttributes GetFileAttributesA
+#define GetFileSecurity GetFileSecurityA
+#define GetFileAttributesEx GetFileAttributesExA
+#define GetFullPathName GetFullPathNameA
+#define GetLogicalDriveStrings GetLogicalDriveStringsA
+#define GetLongPathName GetLongPathNameA
+#define GetNamedPipeHandleState GetNamedPipeHandleStateA
+#define GetModuleHandle GetModuleHandleA
+#define GetModuleFileName GetModuleFileNameA
+#define GetPrivateProfileInt GetPrivateProfileIntA
+#define GetPrivateProfileSection GetPrivateProfileSectionA
+#define GetPrivateProfileSectionNames GetPrivateProfileSectionNamesA
+#define GetPrivateProfileString GetPrivateProfileStringA
+#define GetPrivateProfileStruct GetPrivateProfileStructA
+#define GetProfileInt GetProfileIntA
+#define GetProfileSection GetProfileSectionA
+#define GetProfileString GetProfileStringA
+#define GetShortPathName GetShortPathNameA
+#define GetStartupInfo GetStartupInfoA
+#define GetSystemDirectory GetSystemDirectoryA
+#define GetTempFileName GetTempFileNameA
+#define GetTempPath GetTempPathA
+#define GetUserName GetUserNameA
+#define GetVersionEx GetVersionExA
+#define GetVolumeInformation GetVolumeInformationA
+#define GetWindowsDirectory GetWindowsDirectoryA
+#define GlobalAddAtom GlobalAddAtomA
+#define GlobalFindAtom GlobalFindAtomA
+#define GlobalGetAtomName GlobalGetAtomNameA
+#define IsBadStringPtr IsBadStringPtrA
+#define LoadLibrary LoadLibraryA
+#define LoadLibraryEx LoadLibraryExA
+#define LogonUser LogonUserA
+#define LookupAccountName LookupAccountNameA
+#define LookupAccountSid LookupAccountSidA
+#define LookupPrivilegeDisplayName LookupPrivilegeDisplayNameA
+#define LookupPrivilegeName LookupPrivilegeNameA
+#define LookupPrivilegeValue LookupPrivilegeValueA
+#define lstrcat lstrcatA
+#define lstrcmp lstrcmpA
+#define lstrcmpi lstrcmpiA
+#define lstrcpy lstrcpyA
+#define lstrcpyn lstrcpynA
+#define lstrlen lstrlenA
+#define MoveFile MoveFileA
+#define MoveFileEx MoveFileExA
+#define ObjectCloseAuditAlarm ObjectCloseAuditAlarmA
+#define ObjectDeleteAuditAlarm ObjectDeleteAuditAlarmA
+#define ObjectOpenAuditAlarm ObjectOpenAuditAlarmA
+#define ObjectPrivilegeAuditAlarm ObjectPrivilegeAuditAlarmA
+#define OpenBackupEventLog OpenBackupEventLogA
+#define OpenEvent OpenEventA
+#define OpenEventLog OpenEventLogA
+#define OpenFileMapping OpenFileMappingA
+#define OpenMutex OpenMutexA
+#define OpenSemaphore OpenSemaphoreA
+#define OutputDebugString OutputDebugStringA
+#define PrivilegedServiceAuditAlarm PrivilegedServiceAuditAlarmA
+#define QueryDosDevice QueryDosDeviceA
+#define ReadEventLog ReadEventLogA
+#define RegisterEventSource RegisterEventSourceA
+#define RemoveDirectory RemoveDirectoryA
+#define ReportEvent ReportEventA
+#define SearchPath SearchPathA
+#define SetComputerName SetComputerNameA
+#define SetCurrentDirectory SetCurrentDirectoryA
+#define SetDefaultCommConfig SetDefaultCommConfigA
+#define SetEnvironmentVariable SetEnvironmentVariableA
+#define SetFileAttributes SetFileAttributesA
+#define SetFileSecurity SetFileSecurityA
+#define SetVolumeLabel SetVolumeLabelA
+#define UpdateResource UpdateResourceA
+#define VerifyVersionInfo VerifyVersionInfoA
+#define WaitNamedPipe WaitNamedPipeA
+#define WritePrivateProfileSection WritePrivateProfileSectionA
+#define WritePrivateProfileString WritePrivateProfileStringA
+#define WritePrivateProfileStruct WritePrivateProfileStructA
+#define WriteProfileSection WriteProfileSectionA
+#define WriteProfileString WriteProfileStringA
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* _WINBASE_H */
diff --git a/tinyc/win32/include/winapi/wincon.h b/tinyc/win32/include/winapi/wincon.h
new file mode 100644
index 000000000..8539fe5c6
--- /dev/null
+++ b/tinyc/win32/include/winapi/wincon.h
@@ -0,0 +1,207 @@
+#ifndef _WINCON_H
+#define _WINCON_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FOREGROUND_BLUE	1
+#define FOREGROUND_GREEN	2
+#define FOREGROUND_RED	4
+#define FOREGROUND_INTENSITY	8
+#define BACKGROUND_BLUE	16
+#define BACKGROUND_GREEN	32
+#define BACKGROUND_RED	64
+#define BACKGROUND_INTENSITY	128
+#define CTRL_C_EVENT 0
+#define CTRL_BREAK_EVENT 1
+#define CTRL_CLOSE_EVENT 2
+#define CTRL_LOGOFF_EVENT 5
+#define CTRL_SHUTDOWN_EVENT 6
+#define ENABLE_LINE_INPUT 2
+#define ENABLE_ECHO_INPUT 4
+#define ENABLE_PROCESSED_INPUT 1
+#define ENABLE_WINDOW_INPUT 8
+#define ENABLE_MOUSE_INPUT 16
+#define ENABLE_PROCESSED_OUTPUT 1
+#define ENABLE_WRAP_AT_EOL_OUTPUT 2
+#define KEY_EVENT 1
+#define MOUSE_EVENT 2
+#define WINDOW_BUFFER_SIZE_EVENT 4
+#define MENU_EVENT 8
+#define FOCUS_EVENT 16
+#define CAPSLOCK_ON 128
+#define ENHANCED_KEY 256
+#define RIGHT_ALT_PRESSED 1
+#define LEFT_ALT_PRESSED 2
+#define RIGHT_CTRL_PRESSED 4
+#define LEFT_CTRL_PRESSED 8
+#define SHIFT_PRESSED 16
+#define NUMLOCK_ON 32
+#define SCROLLLOCK_ON 64
+#define FROM_LEFT_1ST_BUTTON_PRESSED 1
+#define RIGHTMOST_BUTTON_PRESSED 2
+#define FROM_LEFT_2ND_BUTTON_PRESSED 4
+#define FROM_LEFT_3RD_BUTTON_PRESSED 8
+#define FROM_LEFT_4TH_BUTTON_PRESSED 16
+#define MOUSE_MOVED	1
+#define DOUBLE_CLICK	2
+#define MOUSE_WHEELED	4
+
+typedef struct _CHAR_INFO {
+	union {
+		WCHAR UnicodeChar;
+		CHAR AsciiChar;
+	} Char;
+	WORD Attributes;
+} CHAR_INFO,*PCHAR_INFO;
+typedef struct _SMALL_RECT {
+	SHORT Left;
+	SHORT Top;
+	SHORT Right;
+	SHORT Bottom;
+} SMALL_RECT,*PSMALL_RECT;
+typedef struct _CONSOLE_CURSOR_INFO {
+	DWORD	dwSize;
+	BOOL	bVisible;
+} CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO;
+typedef struct _COORD {
+	SHORT X;
+	SHORT Y;
+} COORD;
+typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
+	COORD	dwSize;
+	COORD	dwCursorPosition;
+	WORD	wAttributes;
+	SMALL_RECT srWindow;
+	COORD	dwMaximumWindowSize;
+} CONSOLE_SCREEN_BUFFER_INFO,*PCONSOLE_SCREEN_BUFFER_INFO;
+typedef BOOL(CALLBACK *PHANDLER_ROUTINE)(DWORD);
+typedef struct _KEY_EVENT_RECORD {
+	BOOL bKeyDown;
+	WORD wRepeatCount;
+	WORD wVirtualKeyCode;
+	WORD wVirtualScanCode;
+	union {
+		WCHAR UnicodeChar;
+		CHAR AsciiChar;
+	} uChar;
+	DWORD dwControlKeyState;
+} 
+#ifdef __GNUC__
+/* gcc's alignment is not what win32 expects */
+ PACKED
+#endif
+KEY_EVENT_RECORD;
+
+typedef struct _MOUSE_EVENT_RECORD {
+	COORD dwMousePosition;
+	DWORD dwButtonState;
+	DWORD dwControlKeyState;
+	DWORD dwEventFlags;
+} MOUSE_EVENT_RECORD;
+typedef struct _WINDOW_BUFFER_SIZE_RECORD {	COORD dwSize; } WINDOW_BUFFER_SIZE_RECORD;
+typedef struct _MENU_EVENT_RECORD {	UINT dwCommandId; } MENU_EVENT_RECORD,*PMENU_EVENT_RECORD;
+typedef struct _FOCUS_EVENT_RECORD { BOOL bSetFocus; } FOCUS_EVENT_RECORD;
+typedef struct _INPUT_RECORD {
+	WORD EventType;
+	union {
+		KEY_EVENT_RECORD KeyEvent;
+		MOUSE_EVENT_RECORD MouseEvent;
+		WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
+		MENU_EVENT_RECORD MenuEvent;
+		FOCUS_EVENT_RECORD FocusEvent;
+	} Event;
+} INPUT_RECORD,*PINPUT_RECORD;
+
+BOOL WINAPI AllocConsole(void);
+HANDLE WINAPI CreateConsoleScreenBuffer(DWORD,DWORD,LPSECURITY_ATTRIBUTES,DWORD,PVOID);
+BOOL WINAPI FillConsoleOutputAttribute(HANDLE,WORD,DWORD,COORD,PDWORD);
+BOOL WINAPI FillConsoleOutputCharacterA(HANDLE,CHAR,DWORD,COORD,PDWORD);
+BOOL WINAPI FillConsoleOutputCharacterW(HANDLE,WCHAR,DWORD,COORD,PDWORD);
+BOOL WINAPI FlushConsoleInputBuffer(HANDLE);
+BOOL WINAPI FreeConsole(void);
+BOOL WINAPI GenerateConsoleCtrlEvent(DWORD,DWORD);
+UINT WINAPI GetConsoleCP(void);
+BOOL WINAPI GetConsoleCursorInfo(HANDLE,PCONSOLE_CURSOR_INFO);
+BOOL WINAPI GetConsoleMode(HANDLE,PDWORD);
+UINT WINAPI GetConsoleOutputCP(void);
+BOOL WINAPI GetConsoleScreenBufferInfo(HANDLE,PCONSOLE_SCREEN_BUFFER_INFO);
+DWORD WINAPI GetConsoleTitleA(LPSTR,DWORD);
+DWORD WINAPI GetConsoleTitleW(LPWSTR,DWORD);
+COORD WINAPI GetLargestConsoleWindowSize(HANDLE);
+BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE,PDWORD);
+BOOL WINAPI GetNumberOfConsoleMouseButtons(PDWORD);
+BOOL WINAPI PeekConsoleInputA(HANDLE,PINPUT_RECORD,DWORD,PDWORD);
+BOOL WINAPI PeekConsoleInputW(HANDLE,PINPUT_RECORD,DWORD,PDWORD);
+BOOL WINAPI ReadConsoleA(HANDLE,PVOID,DWORD,PDWORD,PVOID);
+BOOL WINAPI ReadConsoleW(HANDLE,PVOID,DWORD,PDWORD,PVOID);
+BOOL WINAPI ReadConsoleInputA(HANDLE,PINPUT_RECORD,DWORD,PDWORD);
+BOOL WINAPI ReadConsoleInputW(HANDLE,PINPUT_RECORD,DWORD,PDWORD);
+BOOL WINAPI ReadConsoleOutputAttribute(HANDLE,LPWORD,DWORD,COORD,LPDWORD);
+BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE,LPSTR,DWORD,COORD,PDWORD);
+BOOL WINAPI ReadConsoleOutputCharacterW(HANDLE,LPWSTR,DWORD,COORD,PDWORD);
+BOOL WINAPI ReadConsoleOutputA(HANDLE,PCHAR_INFO,COORD,COORD,PSMALL_RECT);
+BOOL WINAPI ReadConsoleOutputW(HANDLE,PCHAR_INFO,COORD,COORD,PSMALL_RECT);
+BOOL WINAPI ScrollConsoleScreenBufferA(HANDLE,const SMALL_RECT*,const SMALL_RECT*,COORD,const CHAR_INFO*);
+BOOL WINAPI ScrollConsoleScreenBufferW(HANDLE,const SMALL_RECT*,const SMALL_RECT*,COORD,const CHAR_INFO*);
+BOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE);
+BOOL WINAPI SetConsoleCP(UINT);
+BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE,BOOL);
+BOOL WINAPI SetConsoleCursorInfo(HANDLE,const CONSOLE_CURSOR_INFO*);
+BOOL WINAPI SetConsoleCursorPosition(HANDLE,COORD);
+BOOL WINAPI SetConsoleMode(HANDLE,DWORD);
+BOOL WINAPI SetConsoleOutputCP(UINT);
+BOOL WINAPI SetConsoleScreenBufferSize(HANDLE,COORD);
+BOOL WINAPI SetConsoleTextAttribute(HANDLE,WORD);
+BOOL WINAPI SetConsoleTitleA(LPCSTR);
+BOOL WINAPI SetConsoleTitleW(LPCWSTR);
+BOOL WINAPI SetConsoleWindowInfo(HANDLE,BOOL,const SMALL_RECT*);
+BOOL WINAPI WriteConsoleA(HANDLE,PCVOID,DWORD,PDWORD,PVOID);
+BOOL WINAPI WriteConsoleW(HANDLE,PCVOID,DWORD,PDWORD,PVOID);
+BOOL WINAPI WriteConsoleInputA(HANDLE,const INPUT_RECORD*,DWORD,PDWORD);
+BOOL WINAPI WriteConsoleInputW(HANDLE,const INPUT_RECORD*,DWORD,PDWORD);
+BOOL WINAPI WriteConsoleOutputA(HANDLE,const CHAR_INFO*,COORD,COORD,PSMALL_RECT);
+BOOL WINAPI WriteConsoleOutputW(HANDLE,const CHAR_INFO*,COORD,COORD,PSMALL_RECT);
+BOOL WINAPI WriteConsoleOutputAttribute(HANDLE,const WORD*,DWORD,COORD,PDWORD);
+BOOL WINAPI WriteConsoleOutputCharacterA(HANDLE,LPCSTR,DWORD,COORD,PDWORD);
+BOOL WINAPI WriteConsoleOutputCharacterW(HANDLE,LPCWSTR,DWORD,COORD,PDWORD);
+
+#ifdef UNICODE
+#define FillConsoleOutputCharacter FillConsoleOutputCharacterW
+#define GetConsoleTitle GetConsoleTitleW
+#define PeekConsoleInput PeekConsoleInputW
+#define ReadConsole ReadConsoleW
+#define ReadConsoleInput ReadConsoleInputW
+#define ReadConsoleOutput ReadConsoleOutputW
+#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterW
+#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferW
+#define SetConsoleTitle SetConsoleTitleW
+#define WriteConsole WriteConsoleW
+#define WriteConsoleInput WriteConsoleInputW
+#define WriteConsoleOutput WriteConsoleOutputW
+#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterW
+#else
+#define FillConsoleOutputCharacter FillConsoleOutputCharacterA
+#define GetConsoleTitle GetConsoleTitleA
+#define PeekConsoleInput PeekConsoleInputA
+#define ReadConsole ReadConsoleA
+#define ReadConsoleInput ReadConsoleInputA
+#define ReadConsoleOutput ReadConsoleOutputA
+#define ReadConsoleOutputCharacter ReadConsoleOutputCharacterA
+#define ScrollConsoleScreenBuffer ScrollConsoleScreenBufferA
+#define SetConsoleTitle SetConsoleTitleA
+#define WriteConsole WriteConsoleA
+#define WriteConsoleInput WriteConsoleInputA
+#define WriteConsoleOutput WriteConsoleOutputA
+#define WriteConsoleOutputCharacter WriteConsoleOutputCharacterA
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/windef.h b/tinyc/win32/include/winapi/windef.h
new file mode 100644
index 000000000..1ee3f39f6
--- /dev/null
+++ b/tinyc/win32/include/winapi/windef.h
@@ -0,0 +1,240 @@
+#ifndef _WINDEF_H
+#define _WINDEF_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WINVER
+#define WINVER 0x0400
+#endif
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT WINVER
+#endif
+#ifndef WIN32
+#define WIN32
+#endif
+#ifndef _WIN32
+#define _WIN32
+#endif
+#define FAR
+#define far
+#define NEAR
+#define near
+#ifndef CONST
+#define CONST const
+#endif
+#undef MAX_PATH
+#define MAX_PATH 260
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void*)0)
+#endif
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#define IN
+#define OUT
+#ifndef OPTIONAL
+#define OPTIONAL
+#endif
+
+#ifdef __GNUC__
+#define PACKED __attribute__((packed))
+#ifndef _stdcall
+#define _stdcall __attribute__((stdcall))
+#endif
+#ifndef __stdcall
+#define __stdcall __attribute__((stdcall))
+#endif
+#ifndef _cdecl
+#define _cdecl __attribute__((cdecl))
+#endif
+#ifndef __cdecl
+#define __cdecl __attribute__((cdecl))
+#endif
+#ifndef __declspec
+#define __declspec(e) __attribute__((e))
+#endif
+#ifndef _declspec
+#define _declspec(e) __attribute__((e))
+#endif
+#else
+#define PACKED
+#define _cdecl
+#define __cdecl
+#endif
+
+#undef pascal
+#undef _pascal
+#undef __pascal
+#define pascal __stdcall
+#define _pascal __stdcall
+#define __pascal __stdcall
+#define PASCAL _pascal
+#define CDECL _cdecl
+#define STDCALL __stdcall
+#define WINAPI __stdcall
+#define WINAPIV __cdecl
+#define APIENTRY __stdcall
+#define CALLBACK __stdcall
+#define APIPRIVATE __stdcall
+
+#define DECLSPEC_IMPORT __declspec(dllimport)
+#define DECLSPEC_EXPORT __declspec(dllexport)
+#ifdef __GNUC__
+#define DECLSPEC_NORETURN __declspec(noreturn)
+#define DECLARE_STDCALL_P( type ) __stdcall type
+#elif defined(__WATCOMC__)
+#define DECLSPEC_NORETURN
+#define DECLARE_STDCALL_P( type ) type __stdcall
+#endif /* __GNUC__/__WATCOMC__ */
+#define MAKEWORD(a,b)	((WORD)(((BYTE)(a))|(((WORD)((BYTE)(b)))<<8)))
+#define MAKELONG(a,b)	((LONG)(((WORD)(a))|(((DWORD)((WORD)(b)))<<16)))
+#define LOWORD(l)	((WORD)((DWORD)(l)))
+#define HIWORD(l)	((WORD)(((DWORD)(l)>>16)&0xFFFF))
+#define LOBYTE(w)	((BYTE)(w))
+#define HIBYTE(w)	((BYTE)(((WORD)(w)>>8)&0xFF))
+
+#ifndef _export
+#define _export
+#endif
+#ifndef __export
+#define __export
+#endif
+
+#ifndef NOMINMAX
+#ifndef max
+#define max(a,b) ((a)>(b)?(a):(b))
+#endif
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+#endif
+
+#define UNREFERENCED_PARAMETER(P) {(P)=(P);}
+#define UNREFERENCED_LOCAL_VARIABLE(L) {(L)=(L);}
+#define DBG_UNREFERENCED_PARAMETER(P)
+#define DBG_UNREFERENCED_LOCAL_VARIABLE(L)
+
+typedef unsigned long DWORD;
+typedef int WINBOOL,*PWINBOOL,*LPWINBOOL;
+/* FIXME: Is there a good solution to this? */
+#ifndef XFree86Server
+#ifndef __OBJC__
+typedef WINBOOL BOOL;
+#else
+#define BOOL WINBOOL
+#endif
+typedef unsigned char BYTE;
+#endif /* ndef XFree86Server */
+typedef BOOL *PBOOL,*LPBOOL;
+typedef unsigned short WORD;
+typedef float FLOAT;
+typedef FLOAT *PFLOAT;
+typedef BYTE *PBYTE,*LPBYTE;
+typedef int *PINT,*LPINT;
+typedef WORD *PWORD,*LPWORD;
+typedef long *LPLONG;
+typedef DWORD *PDWORD,*LPDWORD;
+typedef void *PVOID,*LPVOID;
+typedef CONST void *PCVOID,*LPCVOID;
+typedef int INT;
+typedef unsigned int UINT,*PUINT,*LPUINT;
+
+#include <winnt.h>
+
+typedef UINT WPARAM;
+typedef LONG LPARAM;
+typedef LONG LRESULT;
+#ifndef _HRESULT_DEFINED
+typedef LONG HRESULT;
+#define _HRESULT_DEFINED
+#endif
+#ifndef XFree86Server
+typedef WORD ATOM;
+#endif /* XFree86Server */
+typedef HANDLE HGLOBAL;
+typedef HANDLE HLOCAL;
+typedef HANDLE GLOBALHANDLE;
+typedef HANDLE LOCALHANDLE;
+typedef void *HGDIOBJ;
+DECLARE_HANDLE(HACCEL);
+DECLARE_HANDLE(HBITMAP);
+DECLARE_HANDLE(HBRUSH);
+DECLARE_HANDLE(HCOLORSPACE);
+DECLARE_HANDLE(HDC);
+DECLARE_HANDLE(HGLRC);
+DECLARE_HANDLE(HDESK);
+DECLARE_HANDLE(HENHMETAFILE);
+DECLARE_HANDLE(HFONT);
+DECLARE_HANDLE(HICON);
+DECLARE_HANDLE(HKEY);
+/* FIXME: How to handle these. SM_CMONITORS etc in winuser.h also. */
+/* #if (WINVER >= 0x0500) */
+DECLARE_HANDLE(HMONITOR);
+#define HMONITOR_DECLARED 1
+DECLARE_HANDLE(HTERMINAL);
+DECLARE_HANDLE(HWINEVENTHOOK);
+/* #endif */
+typedef HKEY *PHKEY;
+DECLARE_HANDLE(HMENU);
+DECLARE_HANDLE(HMETAFILE);
+DECLARE_HANDLE(HINSTANCE);
+typedef HINSTANCE HMODULE;
+DECLARE_HANDLE(HPALETTE);
+DECLARE_HANDLE(HPEN);
+DECLARE_HANDLE(HRGN);
+DECLARE_HANDLE(HRSRC);
+DECLARE_HANDLE(HSTR);
+DECLARE_HANDLE(HTASK);
+DECLARE_HANDLE(HWND);
+DECLARE_HANDLE(HWINSTA);
+DECLARE_HANDLE(HKL);
+typedef int HFILE;
+typedef HICON HCURSOR;
+typedef DWORD COLORREF;
+typedef int (WINAPI *FARPROC)();
+typedef int (WINAPI *NEARPROC)();
+typedef int (WINAPI *PROC)();
+typedef struct tagRECT {
+	LONG left;
+	LONG top;
+	LONG right;
+	LONG bottom;
+} RECT,*PRECT,*LPRECT;
+typedef const RECT *LPCRECT;
+typedef struct tagRECTL {
+	LONG left;
+	LONG top;
+	LONG right;
+	LONG bottom;
+} RECTL,*PRECTL,*LPRECTL;
+typedef const RECTL *LPCRECTL;
+typedef struct tagPOINT {
+	LONG x;
+	LONG y;
+} POINT,POINTL,*PPOINT,*LPPOINT,*PPOINTL,*LPPOINTL;
+typedef struct tagSIZE {
+	LONG cx;
+	LONG cy;
+} SIZE,SIZEL,*PSIZE,*LPSIZE,*PSIZEL,*LPSIZEL;
+typedef struct tagPOINTS {
+	SHORT x;
+	SHORT y;
+} POINTS,*PPOINTS,*LPPOINTS;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/windows.h b/tinyc/win32/include/winapi/windows.h
new file mode 100644
index 000000000..de2cf9b85
--- /dev/null
+++ b/tinyc/win32/include/winapi/windows.h
@@ -0,0 +1,176 @@
+/*
+	windows.h - main header file for the Win32 API
+
+	Written by Anders Norlander <anorland@hem2.passagen.se>
+
+	This file is part of a free library for the Win32 API.
+
+	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.
+
+*/
+#ifndef _WINDOWS_H
+#define _WINDOWS_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+/* translate GCC target defines to MS equivalents. Keep this synchronized
+   with winnt.h. */
+#if defined(__i686__) && !defined(_M_IX86)
+#define _M_IX86 600
+#elif defined(__i586__) && !defined(_M_IX86)
+#define _M_IX86 500
+#elif defined(__i486__) && !defined(_M_IX86)
+#define _M_IX86 400
+#elif defined(__i386__) && !defined(_M_IX86)
+#define _M_IX86 300
+#endif
+#if defined(_M_IX86) && !defined(_X86_)
+#define _X86_
+#elif defined(_M_ALPHA) && !defined(_ALPHA_)
+#define _ALPHA_
+#elif defined(_M_PPC) && !defined(_PPC_)
+#define _PPC_
+#elif defined(_M_MRX000) && !defined(_MIPS_)
+#define _MIPS_
+#elif defined(_M_M68K) && !defined(_68K_)
+#define _68K_
+#endif
+
+#ifdef RC_INVOKED
+/* winresrc.h includes the necessary headers */
+#include <winresrc.h>
+#else
+
+#ifdef __GNUC__
+#ifndef NONAMELESSUNION
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) 
+#define _ANONYMOUS_UNION __extension__
+#define _ANONYMOUS_STRUCT __extension__
+#else
+#if defined(__cplusplus)
+#define _ANONYMOUS_UNION __extension__
+#endif /* __cplusplus */
+#endif /* __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) */
+#endif /* NONAMELESSUNION */
+#elif defined(__WATCOMC__)
+#define _ANONYMOUS_UNION
+#define _ANONYMOUS_STRUCT
+#endif /* __GNUC__/__WATCOMC__ */
+
+#ifndef _ANONYMOUS_UNION
+#define _ANONYMOUS_UNION
+#define _UNION_NAME(x) x
+#define DUMMYUNIONNAME	u
+#define DUMMYUNIONNAME2	u2
+#define DUMMYUNIONNAME3	u3
+#define DUMMYUNIONNAME4	u4
+#define DUMMYUNIONNAME5	u5
+#define DUMMYUNIONNAME6	u6
+#define DUMMYUNIONNAME7	u7
+#define DUMMYUNIONNAME8	u8
+#else
+#define _UNION_NAME(x)
+#define DUMMYUNIONNAME
+#define DUMMYUNIONNAME2
+#define DUMMYUNIONNAME3
+#define DUMMYUNIONNAME4
+#define DUMMYUNIONNAME5
+#define DUMMYUNIONNAME6
+#define DUMMYUNIONNAME7
+#define DUMMYUNIONNAME8
+#endif
+#ifndef _ANONYMOUS_STRUCT
+#define _ANONYMOUS_STRUCT
+#define _STRUCT_NAME(x) x
+#define DUMMYSTRUCTNAME	s
+#define DUMMYSTRUCTNAME2 s2
+#define DUMMYSTRUCTNAME3 s3
+#else
+#define _STRUCT_NAME(x)
+#define DUMMYSTRUCTNAME
+#define DUMMYSTRUCTNAME2
+#define DUMMYSTRUCTNAME3
+#endif
+
+#ifndef NO_STRICT
+#ifndef STRICT
+#define STRICT 1
+#endif
+#endif
+
+#include <stdarg.h>
+#include <windef.h>
+#include <wincon.h>
+#include <basetyps.h>
+#include <excpt.h>
+#include <winbase.h>
+#ifndef _WINGDI_H
+#include <wingdi.h>
+#endif
+#ifndef _WINUSER_H
+#include <winuser.h>
+#endif
+#ifndef _WINNLS_H
+#include <winnls.h>
+#endif
+#ifndef _WINVER_H
+#include <winver.h>
+#endif
+#ifndef _WINNETWK_H
+#include <winnetwk.h>
+#endif
+#ifndef _WINREG_H
+#include <winreg.h>
+#endif
+#ifndef _WINSVC_H
+#include <winsvc.h>
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+#include <commdlg.h>
+#include <cderr.h>
+#include <dde.h>
+#include <ddeml.h>
+#include <dlgs.h>
+#include <lzexpand.h>
+#include <mmsystem.h>
+#include <nb30.h>
+#include <rpc.h>
+#include <shellapi.h>
+#include <winperf.h>
+#include <winspool.h>
+#if defined(Win32_Winsock)
+#warning "The  Win32_Winsock macro name is deprecated.\
+    Please use __USE_W32_SOCKETS instead"
+#ifndef __USE_W32_SOCKETS
+#define __USE_W32_SOCKETS
+#endif
+#endif
+#if defined(__USE_W32_SOCKETS) || !(defined(__CYGWIN__) || defined(__MSYS__) || defined(_UWIN))
+#if (_WIN32_WINNT >= 0x0400)
+#include <winsock2.h>
+/*
+ * MS likes to include mswsock.h here as well,
+ * but that can cause undefined symbols if
+ * winsock2.h is included before windows.h
+ */
+#else
+#include <winsock.h>
+#endif /*  (_WIN32_WINNT >= 0x0400) */
+#endif
+#endif /* WIN32_LEAN_AND_MEAN */
+
+#endif /* RC_INVOKED */
+
+#ifdef __OBJC__
+/* FIXME: Not undefining BOOL here causes all BOOLs to be WINBOOL (int),
+   but undefining it causes trouble as well if a file is included after
+   windows.h
+*/
+#undef BOOL
+#endif
+
+#endif
diff --git a/tinyc/win32/include/winapi/winerror.h b/tinyc/win32/include/winapi/winerror.h
new file mode 100644
index 000000000..8865d9782
--- /dev/null
+++ b/tinyc/win32/include/winapi/winerror.h
@@ -0,0 +1,1054 @@
+#ifndef _WINERROR_H
+#define _WINERROR_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#define ERROR_SUCCESS 0L
+#define NO_ERROR 0L
+#define ERROR_INVALID_FUNCTION 1L
+#define ERROR_FILE_NOT_FOUND 2L
+#define ERROR_PATH_NOT_FOUND 3L
+#define ERROR_TOO_MANY_OPEN_FILES 4L
+#define ERROR_ACCESS_DENIED 5L
+#define ERROR_INVALID_HANDLE 6L
+#define ERROR_ARENA_TRASHED 7L
+#define ERROR_NOT_ENOUGH_MEMORY 8L
+#define ERROR_INVALID_BLOCK 9L
+#define ERROR_BAD_ENVIRONMENT 10L
+#define ERROR_BAD_FORMAT 11L
+#define ERROR_INVALID_ACCESS 12L
+#define ERROR_INVALID_DATA 13L
+#define ERROR_OUTOFMEMORY 14L
+#define ERROR_INVALID_DRIVE 15L
+#define ERROR_CURRENT_DIRECTORY 16L
+#define ERROR_NOT_SAME_DEVICE 17L
+#define ERROR_NO_MORE_FILES 18L
+#define ERROR_WRITE_PROTECT 19L
+#define ERROR_BAD_UNIT 20L
+#define ERROR_NOT_READY 21L
+#define ERROR_BAD_COMMAND 22L
+#define ERROR_CRC 23L
+#define ERROR_BAD_LENGTH 24L
+#define ERROR_SEEK 25L
+#define ERROR_NOT_DOS_DISK 26L
+#define ERROR_SECTOR_NOT_FOUND 27L
+#define ERROR_OUT_OF_PAPER 28L
+#define ERROR_WRITE_FAULT 29L
+#define ERROR_READ_FAULT 30L
+#define ERROR_GEN_FAILURE 31L
+#define ERROR_SHARING_VIOLATION 32L
+#define ERROR_LOCK_VIOLATION 33L
+#define ERROR_WRONG_DISK 34L
+#define ERROR_SHARING_BUFFER_EXCEEDED 36L
+#define ERROR_HANDLE_EOF 38L
+#define ERROR_HANDLE_DISK_FULL 39L
+#define ERROR_NOT_SUPPORTED 50L
+#define ERROR_REM_NOT_LIST 51L
+#define ERROR_DUP_NAME 52L
+#define ERROR_BAD_NETPATH 53L
+#define ERROR_NETWORK_BUSY 54L
+#define ERROR_DEV_NOT_EXIST 55L
+#define ERROR_TOO_MANY_CMDS 56L
+#define ERROR_ADAP_HDW_ERR 57L
+#define ERROR_BAD_NET_RESP 58L
+#define ERROR_UNEXP_NET_ERR 59L
+#define ERROR_BAD_REM_ADAP 60L
+#define ERROR_PRINTQ_FULL 61L
+#define ERROR_NO_SPOOL_SPACE 62L
+#define ERROR_PRINT_CANCELLED 63L
+#define ERROR_NETNAME_DELETED 64L
+#define ERROR_NETWORK_ACCESS_DENIED 65L
+#define ERROR_BAD_DEV_TYPE 66L
+#define ERROR_BAD_NET_NAME 67L
+#define ERROR_TOO_MANY_NAMES 68L
+#define ERROR_TOO_MANY_SESS 69L
+#define ERROR_SHARING_PAUSED 70L
+#define ERROR_REQ_NOT_ACCEP 71L
+#define ERROR_REDIR_PAUSED 72L
+#define ERROR_FILE_EXISTS 80L
+#define ERROR_CANNOT_MAKE 82L
+#define ERROR_FAIL_I24 83L
+#define ERROR_OUT_OF_STRUCTURES 84L
+#define ERROR_ALREADY_ASSIGNED 85L
+#define ERROR_INVALID_PASSWORD 86L
+#define ERROR_INVALID_PARAMETER 87L
+#define ERROR_NET_WRITE_FAULT 88L
+#define ERROR_NO_PROC_SLOTS 89L
+#define ERROR_TOO_MANY_SEMAPHORES 100L
+#define ERROR_EXCL_SEM_ALREADY_OWNED 101L
+#define ERROR_SEM_IS_SET 102L
+#define ERROR_TOO_MANY_SEM_REQUESTS 103L
+#define ERROR_INVALID_AT_INTERRUPT_TIME 104L
+#define ERROR_SEM_OWNER_DIED 105L
+#define ERROR_SEM_USER_LIMIT 106L
+#define ERROR_DISK_CHANGE 107L
+#define ERROR_DRIVE_LOCKED 108L
+#define ERROR_BROKEN_PIPE 109L
+#define ERROR_OPEN_FAILED 110L
+#define ERROR_BUFFER_OVERFLOW 111L
+#define ERROR_DISK_FULL 112L
+#define ERROR_NO_MORE_SEARCH_HANDLES 113L
+#define ERROR_INVALID_TARGET_HANDLE 114L
+#define ERROR_INVALID_CATEGORY 117L
+#define ERROR_INVALID_VERIFY_SWITCH 118L
+#define ERROR_BAD_DRIVER_LEVEL 119L
+#define ERROR_CALL_NOT_IMPLEMENTED 120L
+#define ERROR_SEM_TIMEOUT 121L
+#define ERROR_INSUFFICIENT_BUFFER 122L
+#define ERROR_INVALID_NAME 123L
+#define ERROR_INVALID_LEVEL 124L
+#define ERROR_NO_VOLUME_LABEL 125L
+#define ERROR_MOD_NOT_FOUND 126L
+#define ERROR_PROC_NOT_FOUND 127L
+#define ERROR_WAIT_NO_CHILDREN 128L
+#define ERROR_CHILD_NOT_COMPLETE 129L
+#define ERROR_DIRECT_ACCESS_HANDLE 130L
+#define ERROR_NEGATIVE_SEEK 131L
+#define ERROR_SEEK_ON_DEVICE 132L
+#define ERROR_IS_JOIN_TARGET 133L
+#define ERROR_IS_JOINED 134L
+#define ERROR_IS_SUBSTED 135L
+#define ERROR_NOT_JOINED 136L
+#define ERROR_NOT_SUBSTED 137L
+#define ERROR_JOIN_TO_JOIN 138L
+#define ERROR_SUBST_TO_SUBST 139L
+#define ERROR_JOIN_TO_SUBST 140L
+#define ERROR_SUBST_TO_JOIN 141L
+#define ERROR_BUSY_DRIVE 142L
+#define ERROR_SAME_DRIVE 143L
+#define ERROR_DIR_NOT_ROOT 144L
+#define ERROR_DIR_NOT_EMPTY 145L
+#define ERROR_IS_SUBST_PATH 146L
+#define ERROR_IS_JOIN_PATH 147L
+#define ERROR_PATH_BUSY 148L
+#define ERROR_IS_SUBST_TARGET 149L
+#define ERROR_SYSTEM_TRACE 150L
+#define ERROR_INVALID_EVENT_COUNT 151L
+#define ERROR_TOO_MANY_MUXWAITERS 152L
+#define ERROR_INVALID_LIST_FORMAT 153L
+#define ERROR_LABEL_TOO_LONG 154L
+#define ERROR_TOO_MANY_TCBS 155L
+#define ERROR_SIGNAL_REFUSED 156L
+#define ERROR_DISCARDED 157L
+#define ERROR_NOT_LOCKED 158L
+#define ERROR_BAD_THREADID_ADDR 159L
+#define ERROR_BAD_ARGUMENTS 160L
+#define ERROR_BAD_PATHNAME 161L
+#define ERROR_SIGNAL_PENDING 162L
+#define ERROR_MAX_THRDS_REACHED 164L
+#define ERROR_LOCK_FAILED 167L
+#define ERROR_BUSY 170L
+#define ERROR_CANCEL_VIOLATION 173L
+#define ERROR_ATOMIC_LOCKS_NOT_SUPPORTED 174L
+#define ERROR_INVALID_SEGMENT_NUMBER 180L
+#define ERROR_INVALID_ORDINAL 182L
+#define ERROR_ALREADY_EXISTS 183L
+#define ERROR_INVALID_FLAG_NUMBER 186L
+#define ERROR_SEM_NOT_FOUND 187L
+#define ERROR_INVALID_STARTING_CODESEG 188L
+#define ERROR_INVALID_STACKSEG 189L
+#define ERROR_INVALID_MODULETYPE 190L
+#define ERROR_INVALID_EXE_SIGNATURE 191L
+#define ERROR_EXE_MARKED_INVALID 192L
+#define ERROR_BAD_EXE_FORMAT 193L
+#define ERROR_ITERATED_DATA_EXCEEDS_64k 194L
+#define ERROR_INVALID_MINALLOCSIZE 195L
+#define ERROR_DYNLINK_FROM_INVALID_RING 196L
+#define ERROR_IOPL_NOT_ENABLED 197L
+#define ERROR_INVALID_SEGDPL 198L
+#define ERROR_AUTODATASEG_EXCEEDS_64k 199L
+#define ERROR_RING2SEG_MUST_BE_MOVABLE 200L
+#define ERROR_RELOC_CHAIN_XEEDS_SEGLIM 201L
+#define ERROR_INFLOOP_IN_RELOC_CHAIN 202L
+#define ERROR_ENVVAR_NOT_FOUND 203L
+#define ERROR_NO_SIGNAL_SENT 205L
+#define ERROR_FILENAME_EXCED_RANGE 206L
+#define ERROR_RING2_STACK_IN_USE 207L
+#define ERROR_META_EXPANSION_TOO_LONG 208L
+#define ERROR_INVALID_SIGNAL_NUMBER 209L
+#define ERROR_THREAD_1_INACTIVE 210L
+#define ERROR_LOCKED 212L
+#define ERROR_TOO_MANY_MODULES 214L
+#define ERROR_NESTING_NOT_ALLOWED 215L
+#define ERROR_BAD_PIPE 230L
+#define ERROR_PIPE_BUSY 231L
+#define ERROR_NO_DATA 232L
+#define ERROR_PIPE_NOT_CONNECTED 233L
+#define ERROR_MORE_DATA 234L
+#define ERROR_VC_DISCONNECTED 240L
+#define ERROR_INVALID_EA_NAME 254L
+#define ERROR_EA_LIST_INCONSISTENT 255L
+#define ERROR_NO_MORE_ITEMS 259L
+#define ERROR_CANNOT_COPY 266L
+#define ERROR_DIRECTORY 267L
+#define ERROR_EAS_DIDNT_FIT 275L
+#define ERROR_EA_FILE_CORRUPT 276L
+#define ERROR_EA_TABLE_FULL 277L
+#define ERROR_INVALID_EA_HANDLE 278L
+#define ERROR_EAS_NOT_SUPPORTED 282L
+#define ERROR_NOT_OWNER 288L
+#define ERROR_TOO_MANY_POSTS 298L
+#define ERROR_PARTIAL_COPY 299L
+#define ERROR_MR_MID_NOT_FOUND 317L
+#define ERROR_INVALID_ADDRESS 487L
+#define ERROR_ARITHMETIC_OVERFLOW 534L
+#define ERROR_PIPE_CONNECTED 535L
+#define ERROR_PIPE_LISTENING 536L
+#define ERROR_EA_ACCESS_DENIED 994L
+#define ERROR_OPERATION_ABORTED 995L
+#define ERROR_IO_INCOMPLETE 996L
+#define ERROR_IO_PENDING 997L
+#define ERROR_NOACCESS 998L
+#define ERROR_SWAPERROR 999L
+#define ERROR_STACK_OVERFLOW 1001L
+#define ERROR_INVALID_MESSAGE 1002L
+#define ERROR_CAN_NOT_COMPLETE 1003L
+#define ERROR_INVALID_FLAGS 1004L
+#define ERROR_UNRECOGNIZED_VOLUME 1005L
+#define ERROR_FILE_INVALID 1006L
+#define ERROR_FULLSCREEN_MODE 1007L
+#define ERROR_NO_TOKEN 1008L
+#define ERROR_BADDB 1009L
+#define ERROR_BADKEY 1010L
+#define ERROR_CANTOPEN 1011L
+#define ERROR_CANTREAD 1012L
+#define ERROR_CANTWRITE 1013L
+#define ERROR_REGISTRY_RECOVERED 1014L
+#define ERROR_REGISTRY_CORRUPT 1015L
+#define ERROR_REGISTRY_IO_FAILED 1016L
+#define ERROR_NOT_REGISTRY_FILE 1017L
+#define ERROR_KEY_DELETED 1018L
+#define ERROR_NO_LOG_SPACE 1019L
+#define ERROR_KEY_HAS_CHILDREN 1020L
+#define ERROR_CHILD_MUST_BE_VOLATILE 1021L
+#define ERROR_NOTIFY_ENUM_DIR 1022L
+#define ERROR_DEPENDENT_SERVICES_RUNNING 1051L
+#define ERROR_INVALID_SERVICE_CONTROL 1052L
+#define ERROR_SERVICE_REQUEST_TIMEOUT 1053L
+#define ERROR_SERVICE_NO_THREAD 1054L
+#define ERROR_SERVICE_DATABASE_LOCKED 1055L
+#define ERROR_SERVICE_ALREADY_RUNNING 1056L
+#define ERROR_INVALID_SERVICE_ACCOUNT 1057L
+#define ERROR_SERVICE_DISABLED 1058L
+#define ERROR_CIRCULAR_DEPENDENCY 1059L
+#define ERROR_SERVICE_DOES_NOT_EXIST 1060L
+#define ERROR_SERVICE_CANNOT_ACCEPT_CTRL 1061L
+#define ERROR_SERVICE_NOT_ACTIVE 1062L
+#define ERROR_FAILED_SERVICE_CONTROLLER_CONNECT 1063L
+#define ERROR_EXCEPTION_IN_SERVICE 1064L
+#define ERROR_DATABASE_DOES_NOT_EXIST 1065L
+#define ERROR_SERVICE_SPECIFIC_ERROR 1066L
+#define ERROR_PROCESS_ABORTED 1067L
+#define ERROR_SERVICE_DEPENDENCY_FAIL 1068L
+#define ERROR_SERVICE_LOGON_FAILED 1069L
+#define ERROR_SERVICE_START_HANG 1070L
+#define ERROR_INVALID_SERVICE_LOCK 1071L
+#define ERROR_SERVICE_MARKED_FOR_DELETE 1072L
+#define ERROR_SERVICE_EXISTS 1073L
+#define ERROR_ALREADY_RUNNING_LKG 1074L
+#define ERROR_SERVICE_DEPENDENCY_DELETED 1075L
+#define ERROR_BOOT_ALREADY_ACCEPTED 1076L
+#define ERROR_SERVICE_NEVER_STARTED 1077L
+#define ERROR_DUPLICATE_SERVICE_NAME 1078L
+#define ERROR_END_OF_MEDIA 1100L
+#define ERROR_FILEMARK_DETECTED 1101L
+#define ERROR_BEGINNING_OF_MEDIA 1102L
+#define ERROR_SETMARK_DETECTED 1103L
+#define ERROR_NO_DATA_DETECTED 1104L
+#define ERROR_PARTITION_FAILURE 1105L
+#define ERROR_INVALID_BLOCK_LENGTH 1106L
+#define ERROR_DEVICE_NOT_PARTITIONED 1107L
+#define ERROR_UNABLE_TO_LOCK_MEDIA 1108L
+#define ERROR_UNABLE_TO_UNLOAD_MEDIA 1109L
+#define ERROR_MEDIA_CHANGED 1110L
+#define ERROR_BUS_RESET 1111L
+#define ERROR_NO_MEDIA_IN_DRIVE 1112L
+#define ERROR_NO_UNICODE_TRANSLATION 1113L
+#define ERROR_DLL_INIT_FAILED 1114L
+#define ERROR_SHUTDOWN_IN_PROGRESS 1115L
+#define ERROR_NO_SHUTDOWN_IN_PROGRESS 1116L
+#define ERROR_IO_DEVICE 1117L
+#define ERROR_SERIAL_NO_DEVICE 1118L
+#define ERROR_IRQ_BUSY 1119L
+#define ERROR_MORE_WRITES 1120L
+#define ERROR_COUNTER_TIMEOUT 1121L
+#define ERROR_FLOPPY_ID_MARK_NOT_FOUND 1122L
+#define ERROR_FLOPPY_WRONG_CYLINDER 1123L
+#define ERROR_FLOPPY_UNKNOWN_ERROR 1124L
+#define ERROR_FLOPPY_BAD_REGISTERS 1125L
+#define ERROR_DISK_RECALIBRATE_FAILED 1126L
+#define ERROR_DISK_OPERATION_FAILED 1127L
+#define ERROR_DISK_RESET_FAILED 1128L
+#define ERROR_EOM_OVERFLOW 1129L
+#define ERROR_NOT_ENOUGH_SERVER_MEMORY 1130L
+#define ERROR_POSSIBLE_DEADLOCK 1131L
+#define ERROR_MAPPED_ALIGNMENT 1132L
+#define ERROR_SET_POWER_STATE_VETOED 1140L
+#define ERROR_SET_POWER_STATE_FAILED 1141L
+#define ERROR_TOO_MANY_LINKS 1142L
+#define ERROR_OLD_WIN_VERSION 1150L
+#define ERROR_APP_WRONG_OS 1151L
+#define ERROR_SINGLE_INSTANCE_APP 1152L
+#define ERROR_RMODE_APP 1153L
+#define ERROR_INVALID_DLL 1154L
+#define ERROR_NO_ASSOCIATION 1155L
+#define ERROR_DDE_FAIL 1156L
+#define ERROR_DLL_NOT_FOUND 1157L
+#define ERROR_BAD_USERNAME 2202L
+#define ERROR_NOT_CONNECTED 2250L
+#define ERROR_OPEN_FILES 2401L
+#define ERROR_ACTIVE_CONNECTIONS 2402L
+#define ERROR_DEVICE_IN_USE 2404L
+#define ERROR_BAD_DEVICE 1200L
+#define ERROR_CONNECTION_UNAVAIL 1201L
+#define ERROR_DEVICE_ALREADY_REMEMBERED 1202L
+#define ERROR_NO_NET_OR_BAD_PATH 1203L
+#define ERROR_BAD_PROVIDER 1204L
+#define ERROR_CANNOT_OPEN_PROFILE 1205L
+#define ERROR_BAD_PROFILE 1206L
+#define ERROR_NOT_CONTAINER 1207L
+#define ERROR_EXTENDED_ERROR 1208L
+#define ERROR_INVALID_GROUPNAME 1209L
+#define ERROR_INVALID_COMPUTERNAME 1210L
+#define ERROR_INVALID_EVENTNAME 1211L
+#define ERROR_INVALID_DOMAINNAME 1212L
+#define ERROR_INVALID_SERVICENAME 1213L
+#define ERROR_INVALID_NETNAME 1214L
+#define ERROR_INVALID_SHARENAME 1215L
+#define ERROR_INVALID_PASSWORDNAME 1216L
+#define ERROR_INVALID_MESSAGENAME 1217L
+#define ERROR_INVALID_MESSAGEDEST 1218L
+#define ERROR_SESSION_CREDENTIAL_CONFLICT 1219L
+#define ERROR_REMOTE_SESSION_LIMIT_EXCEEDED 1220L
+#define ERROR_DUP_DOMAINNAME 1221L
+#define ERROR_NO_NETWORK 1222L
+#define ERROR_CANCELLED 1223L
+#define ERROR_USER_MAPPED_FILE 1224L
+#define ERROR_CONNECTION_REFUSED 1225L
+#define ERROR_GRACEFUL_DISCONNECT 1226L
+#define ERROR_ADDRESS_ALREADY_ASSOCIATED 1227L
+#define ERROR_ADDRESS_NOT_ASSOCIATED 1228L
+#define ERROR_CONNECTION_INVALID 1229L
+#define ERROR_CONNECTION_ACTIVE 1230L
+#define ERROR_NETWORK_UNREACHABLE 1231L
+#define ERROR_HOST_UNREACHABLE 1232L
+#define ERROR_PROTOCOL_UNREACHABLE 1233L
+#define ERROR_PORT_UNREACHABLE 1234L
+#define ERROR_REQUEST_ABORTED 1235L
+#define ERROR_CONNECTION_ABORTED 1236L
+#define ERROR_RETRY 1237L
+#define ERROR_CONNECTION_COUNT_LIMIT 1238L
+#define ERROR_LOGIN_TIME_RESTRICTION 1239L
+#define ERROR_LOGIN_WKSTA_RESTRICTION 1240L
+#define ERROR_INCORRECT_ADDRESS 1241L
+#define ERROR_ALREADY_REGISTERED 1242L
+#define ERROR_SERVICE_NOT_FOUND 1243L
+#define ERROR_NOT_AUTHENTICATED 1244L
+#define ERROR_NOT_LOGGED_ON 1245L
+#define ERROR_CONTINUE 1246L
+#define ERROR_ALREADY_INITIALIZED 1247L
+#define ERROR_NO_MORE_DEVICES 1248L
+#define ERROR_NOT_ALL_ASSIGNED 1300L
+#define ERROR_SOME_NOT_MAPPED 1301L
+#define ERROR_NO_QUOTAS_FOR_ACCOUNT 1302L
+#define ERROR_LOCAL_USER_SESSION_KEY 1303L
+#define ERROR_NULL_LM_PASSWORD 1304L
+#define ERROR_UNKNOWN_REVISION 1305L
+#define ERROR_REVISION_MISMATCH 1306L
+#define ERROR_INVALID_OWNER 1307L
+#define ERROR_INVALID_PRIMARY_GROUP 1308L
+#define ERROR_NO_IMPERSONATION_TOKEN 1309L
+#define ERROR_CANT_DISABLE_MANDATORY 1310L
+#define ERROR_NO_LOGON_SERVERS 1311L
+#define ERROR_NO_SUCH_LOGON_SESSION 1312L
+#define ERROR_NO_SUCH_PRIVILEGE 1313L
+#define ERROR_PRIVILEGE_NOT_HELD 1314L
+#define ERROR_INVALID_ACCOUNT_NAME 1315L
+#define ERROR_USER_EXISTS 1316L
+#define ERROR_NO_SUCH_USER 1317L
+#define ERROR_GROUP_EXISTS 1318L
+#define ERROR_NO_SUCH_GROUP 1319L
+#define ERROR_MEMBER_IN_GROUP 1320L
+#define ERROR_MEMBER_NOT_IN_GROUP 1321L
+#define ERROR_LAST_ADMIN 1322L
+#define ERROR_WRONG_PASSWORD 1323L
+#define ERROR_ILL_FORMED_PASSWORD 1324L
+#define ERROR_PASSWORD_RESTRICTION 1325L
+#define ERROR_LOGON_FAILURE 1326L
+#define ERROR_ACCOUNT_RESTRICTION 1327L
+#define ERROR_INVALID_LOGON_HOURS 1328L
+#define ERROR_INVALID_WORKSTATION 1329L
+#define ERROR_PASSWORD_EXPIRED 1330L
+#define ERROR_ACCOUNT_DISABLED 1331L
+#define ERROR_NONE_MAPPED 1332L
+#define ERROR_TOO_MANY_LUIDS_REQUESTED 1333L
+#define ERROR_LUIDS_EXHAUSTED 1334L
+#define ERROR_INVALID_SUB_AUTHORITY 1335L
+#define ERROR_INVALID_ACL 1336L
+#define ERROR_INVALID_SID 1337L
+#define ERROR_INVALID_SECURITY_DESCR 1338L
+#define ERROR_BAD_INHERITANCE_ACL 1340L
+#define ERROR_SERVER_DISABLED 1341L
+#define ERROR_SERVER_NOT_DISABLED 1342L
+#define ERROR_INVALID_ID_AUTHORITY 1343L
+#define ERROR_ALLOTTED_SPACE_EXCEEDED 1344L
+#define ERROR_INVALID_GROUP_ATTRIBUTES 1345L
+#define ERROR_BAD_IMPERSONATION_LEVEL 1346L
+#define ERROR_CANT_OPEN_ANONYMOUS 1347L
+#define ERROR_BAD_VALIDATION_CLASS 1348L
+#define ERROR_BAD_TOKEN_TYPE 1349L
+#define ERROR_NO_SECURITY_ON_OBJECT 1350L
+#define ERROR_CANT_ACCESS_DOMAIN_INFO 1351L
+#define ERROR_INVALID_SERVER_STATE 1352L
+#define ERROR_INVALID_DOMAIN_STATE 1353L
+#define ERROR_INVALID_DOMAIN_ROLE 1354L
+#define ERROR_NO_SUCH_DOMAIN 1355L
+#define ERROR_DOMAIN_EXISTS 1356L
+#define ERROR_DOMAIN_LIMIT_EXCEEDED 1357L
+#define ERROR_INTERNAL_DB_CORRUPTION 1358L
+#define ERROR_INTERNAL_ERROR 1359L
+#define ERROR_GENERIC_NOT_MAPPED 1360L
+#define ERROR_BAD_DESCRIPTOR_FORMAT 1361L
+#define ERROR_NOT_LOGON_PROCESS 1362L
+#define ERROR_LOGON_SESSION_EXISTS 1363L
+#define ERROR_NO_SUCH_PACKAGE 1364L
+#define ERROR_BAD_LOGON_SESSION_STATE 1365L
+#define ERROR_LOGON_SESSION_COLLISION 1366L
+#define ERROR_INVALID_LOGON_TYPE 1367L
+#define ERROR_CANNOT_IMPERSONATE 1368L
+#define ERROR_RXACT_INVALID_STATE 1369L
+#define ERROR_RXACT_COMMIT_FAILURE 1370L
+#define ERROR_SPECIAL_ACCOUNT 1371L
+#define ERROR_SPECIAL_GROUP 1372L
+#define ERROR_SPECIAL_USER 1373L
+#define ERROR_MEMBERS_PRIMARY_GROUP 1374L
+#define ERROR_TOKEN_ALREADY_IN_USE 1375L
+#define ERROR_NO_SUCH_ALIAS 1376L
+#define ERROR_MEMBER_NOT_IN_ALIAS 1377L
+#define ERROR_MEMBER_IN_ALIAS 1378L
+#define ERROR_ALIAS_EXISTS 1379L
+#define ERROR_LOGON_NOT_GRANTED 1380L
+#define ERROR_TOO_MANY_SECRETS 1381L
+#define ERROR_SECRET_TOO_LONG 1382L
+#define ERROR_INTERNAL_DB_ERROR 1383L
+#define ERROR_TOO_MANY_CONTEXT_IDS 1384L
+#define ERROR_LOGON_TYPE_NOT_GRANTED 1385L
+#define ERROR_NT_CROSS_ENCRYPTION_REQUIRED 1386L
+#define ERROR_NO_SUCH_MEMBER 1387L
+#define ERROR_INVALID_MEMBER 1388L
+#define ERROR_TOO_MANY_SIDS 1389L
+#define ERROR_LM_CROSS_ENCRYPTION_REQUIRED 1390L
+#define ERROR_NO_INHERITANCE 1391L
+#define ERROR_FILE_CORRUPT 1392L
+#define ERROR_DISK_CORRUPT 1393L
+#define ERROR_NO_USER_SESSION_KEY 1394L
+#define ERROR_LICENSE_QUOTA_EXCEEDED 1395L
+#define ERROR_INVALID_WINDOW_HANDLE 1400L
+#define ERROR_INVALID_MENU_HANDLE 1401L
+#define ERROR_INVALID_CURSOR_HANDLE 1402L
+#define ERROR_INVALID_ACCEL_HANDLE 1403L
+#define ERROR_INVALID_HOOK_HANDLE 1404L
+#define ERROR_INVALID_DWP_HANDLE 1405L
+#define ERROR_TLW_WITH_WSCHILD 1406L
+#define ERROR_CANNOT_FIND_WND_CLASS 1407L
+#define ERROR_WINDOW_OF_OTHER_THREAD 1408L
+#define ERROR_HOTKEY_ALREADY_REGISTERED 1409L
+#define ERROR_CLASS_ALREADY_EXISTS 1410L
+#define ERROR_CLASS_DOES_NOT_EXIST 1411L
+#define ERROR_CLASS_HAS_WINDOWS 1412L
+#define ERROR_INVALID_INDEX 1413L
+#define ERROR_INVALID_ICON_HANDLE 1414L
+#define ERROR_PRIVATE_DIALOG_INDEX 1415L
+#define ERROR_LISTBOX_ID_NOT_FOUND 1416L
+#define ERROR_NO_WILDCARD_CHARACTERS 1417L
+#define ERROR_CLIPBOARD_NOT_OPEN 1418L
+#define ERROR_HOTKEY_NOT_REGISTERED 1419L
+#define ERROR_WINDOW_NOT_DIALOG 1420L
+#define ERROR_CONTROL_ID_NOT_FOUND 1421L
+#define ERROR_INVALID_COMBOBOX_MESSAGE 1422L
+#define ERROR_WINDOW_NOT_COMBOBOX 1423L
+#define ERROR_INVALID_EDIT_HEIGHT 1424L
+#define ERROR_DC_NOT_FOUND 1425L
+#define ERROR_INVALID_HOOK_FILTER 1426L
+#define ERROR_INVALID_FILTER_PROC 1427L
+#define ERROR_HOOK_NEEDS_HMOD 1428L
+#define ERROR_GLOBAL_ONLY_HOOK 1429L
+#define ERROR_JOURNAL_HOOK_SET 1430L
+#define ERROR_HOOK_NOT_INSTALLED 1431L
+#define ERROR_INVALID_LB_MESSAGE 1432L
+#define ERROR_SETCOUNT_ON_BAD_LB 1433L
+#define ERROR_LB_WITHOUT_TABSTOPS 1434L
+#define ERROR_DESTROY_OBJECT_OF_OTHER_THREAD 1435L
+#define ERROR_CHILD_WINDOW_MENU 1436L
+#define ERROR_NO_SYSTEM_MENU 1437L
+#define ERROR_INVALID_MSGBOX_STYLE 1438L
+#define ERROR_INVALID_SPI_VALUE 1439L
+#define ERROR_SCREEN_ALREADY_LOCKED 1440L
+#define ERROR_HWNDS_HAVE_DIFF_PARENT 1441L
+#define ERROR_NOT_CHILD_WINDOW 1442L
+#define ERROR_INVALID_GW_COMMAND 1443L
+#define ERROR_INVALID_THREAD_ID 1444L
+#define ERROR_NON_MDICHILD_WINDOW 1445L
+#define ERROR_POPUP_ALREADY_ACTIVE 1446L
+#define ERROR_NO_SCROLLBARS 1447L
+#define ERROR_INVALID_SCROLLBAR_RANGE 1448L
+#define ERROR_INVALID_SHOWWIN_COMMAND 1449L
+#define ERROR_NO_SYSTEM_RESOURCES 1450L
+#define ERROR_NONPAGED_SYSTEM_RESOURCES 1451L
+#define ERROR_PAGED_SYSTEM_RESOURCES 1452L
+#define ERROR_WORKING_SET_QUOTA 1453L
+#define ERROR_PAGEFILE_QUOTA 1454L
+#define ERROR_COMMITMENT_LIMIT 1455L
+#define ERROR_MENU_ITEM_NOT_FOUND 1456L
+#define ERROR_EVENTLOG_FILE_CORRUPT 1500L
+#define ERROR_EVENTLOG_CANT_START 1501L
+#define ERROR_LOG_FILE_FULL 1502L
+#define ERROR_EVENTLOG_FILE_CHANGED 1503L
+#define RPC_S_INVALID_STRING_BINDING 1700L
+#define RPC_S_WRONG_KIND_OF_BINDING 1701L
+#define RPC_S_INVALID_BINDING 1702L
+#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703L
+#define RPC_S_INVALID_RPC_PROTSEQ 1704L
+#define RPC_S_INVALID_STRING_UUID 1705L
+#define RPC_S_INVALID_ENDPOINT_FORMAT 1706L
+#define RPC_S_INVALID_NET_ADDR 1707L
+#define RPC_S_NO_ENDPOINT_FOUND 1708L
+#define RPC_S_INVALID_TIMEOUT 1709L
+#define RPC_S_OBJECT_NOT_FOUND 1710L
+#define RPC_S_ALREADY_REGISTERED 1711L
+#define RPC_S_TYPE_ALREADY_REGISTERED 1712L
+#define RPC_S_ALREADY_LISTENING 1713L
+#define RPC_S_NO_PROTSEQS_REGISTERED 1714L
+#define RPC_S_NOT_LISTENING 1715L
+#define RPC_S_UNKNOWN_MGR_TYPE 1716L
+#define RPC_S_UNKNOWN_IF 1717L
+#define RPC_S_NO_BINDINGS 1718L
+#define RPC_S_NO_PROTSEQS 1719L
+#define RPC_S_CANT_CREATE_ENDPOINT 1720L
+#define RPC_S_OUT_OF_RESOURCES 1721L
+#define RPC_S_SERVER_UNAVAILABLE 1722L
+#define RPC_S_SERVER_TOO_BUSY 1723L
+#define RPC_S_INVALID_NETWORK_OPTIONS 1724L
+#define RPC_S_NO_CALL_ACTIVE 1725L
+#define RPC_S_CALL_FAILED 1726L
+#define RPC_S_CALL_FAILED_DNE 1727L
+#define RPC_S_PROTOCOL_ERROR 1728L
+#define RPC_S_UNSUPPORTED_TRANS_SYN 1730L
+#define RPC_S_UNSUPPORTED_TYPE 1732L
+#define RPC_S_INVALID_TAG 1733L
+#define RPC_S_INVALID_BOUND 1734L
+#define RPC_S_NO_ENTRY_NAME 1735L
+#define RPC_S_INVALID_NAME_SYNTAX 1736L
+#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737L
+#define RPC_S_UUID_NO_ADDRESS 1739L
+#define RPC_S_DUPLICATE_ENDPOINT 1740L
+#define RPC_S_UNKNOWN_AUTHN_TYPE 1741L
+#define RPC_S_MAX_CALLS_TOO_SMALL 1742L
+#define RPC_S_STRING_TOO_LONG 1743L
+#define RPC_S_PROTSEQ_NOT_FOUND 1744L
+#define RPC_S_PROCNUM_OUT_OF_RANGE 1745L
+#define RPC_S_BINDING_HAS_NO_AUTH 1746L
+#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747L
+#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748L
+#define RPC_S_INVALID_AUTH_IDENTITY 1749L
+#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750L
+#define EPT_S_INVALID_ENTRY 1751L
+#define EPT_S_CANT_PERFORM_OP 1752L
+#define EPT_S_NOT_REGISTERED 1753L
+#define RPC_S_NOTHING_TO_EXPORT 1754L
+#define RPC_S_INCOMPLETE_NAME 1755L
+#define RPC_S_INVALID_VERS_OPTION 1756L
+#define RPC_S_NO_MORE_MEMBERS 1757L
+#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758L
+#define RPC_S_INTERFACE_NOT_FOUND 1759L
+#define RPC_S_ENTRY_ALREADY_EXISTS 1760L
+#define RPC_S_ENTRY_NOT_FOUND 1761L
+#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762L
+#define RPC_S_INVALID_NAF_ID 1763L
+#define RPC_S_CANNOT_SUPPORT 1764L
+#define RPC_S_NO_CONTEXT_AVAILABLE 1765L
+#define RPC_S_INTERNAL_ERROR 1766L
+#define RPC_S_ZERO_DIVIDE 1767L
+#define RPC_S_ADDRESS_ERROR 1768L
+#define RPC_S_FP_DIV_ZERO 1769L
+#define RPC_S_FP_UNDERFLOW 1770L
+#define RPC_S_FP_OVERFLOW 1771L
+#define RPC_X_NO_MORE_ENTRIES 1772L
+#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773L
+#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774L
+#define RPC_X_SS_IN_NULL_CONTEXT 1775L
+#define RPC_X_SS_CONTEXT_DAMAGED 1777L
+#define RPC_X_SS_HANDLES_MISMATCH 1778L
+#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779L
+#define RPC_X_NULL_REF_POINTER 1780L
+#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781L
+#define RPC_X_BYTE_COUNT_TOO_SMALL 1782L
+#define RPC_X_BAD_STUB_DATA 1783L
+#define ERROR_INVALID_USER_BUFFER 1784L
+#define ERROR_UNRECOGNIZED_MEDIA 1785L
+#define ERROR_NO_TRUST_LSA_SECRET 1786L
+#define ERROR_NO_TRUST_SAM_ACCOUNT 1787L
+#define ERROR_TRUSTED_DOMAIN_FAILURE 1788L
+#define ERROR_TRUSTED_RELATIONSHIP_FAILURE 1789L
+#define ERROR_TRUST_FAILURE 1790L
+#define RPC_S_CALL_IN_PROGRESS 1791L
+#define ERROR_NETLOGON_NOT_STARTED 1792L
+#define ERROR_ACCOUNT_EXPIRED 1793L
+#define ERROR_REDIRECTOR_HAS_OPEN_HANDLES 1794L
+#define ERROR_PRINTER_DRIVER_ALREADY_INSTALLED 1795L
+#define ERROR_UNKNOWN_PORT 1796L
+#define ERROR_UNKNOWN_PRINTER_DRIVER 1797L
+#define ERROR_UNKNOWN_PRINTPROCESSOR 1798L
+#define ERROR_INVALID_SEPARATOR_FILE 1799L
+#define ERROR_INVALID_PRIORITY 1800L
+#define ERROR_INVALID_PRINTER_NAME 1801L
+#define ERROR_PRINTER_ALREADY_EXISTS 1802L
+#define ERROR_INVALID_PRINTER_COMMAND 1803L
+#define ERROR_INVALID_DATATYPE 1804L
+#define ERROR_INVALID_ENVIRONMENT 1805L
+#define RPC_S_NO_MORE_BINDINGS 1806L
+#define ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 1807L
+#define ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT 1808L
+#define ERROR_NOLOGON_SERVER_TRUST_ACCOUNT 1809L
+#define ERROR_DOMAIN_TRUST_INCONSISTENT 1810L
+#define ERROR_SERVER_HAS_OPEN_HANDLES 1811L
+#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L
+#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813L
+#define ERROR_RESOURCE_NAME_NOT_FOUND 1814L
+#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L
+#define ERROR_NOT_ENOUGH_QUOTA 1816L
+#define RPC_S_NO_INTERFACES 1817L
+#define RPC_S_CALL_CANCELLED 1818L
+#define RPC_S_BINDING_INCOMPLETE 1819L
+#define RPC_S_COMM_FAILURE 1820L
+#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821L
+#define RPC_S_NO_PRINC_NAME 1822L
+#define RPC_S_NOT_RPC_ERROR 1823L
+#define RPC_S_UUID_LOCAL_ONLY 1824L
+#define RPC_S_SEC_PKG_ERROR 1825L
+#define RPC_S_NOT_CANCELLED 1826L
+#define RPC_X_INVALID_ES_ACTION 1827L
+#define RPC_X_WRONG_ES_VERSION 1828L
+#define RPC_X_WRONG_STUB_VERSION 1829L
+#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898L
+#define EPT_S_CANT_CREATE 1899L
+#define RPC_S_INVALID_OBJECT 1900L
+#define ERROR_INVALID_TIME 1901L
+#define ERROR_INVALID_FORM_NAME 1902L
+#define ERROR_INVALID_FORM_SIZE 1903L
+#define ERROR_ALREADY_WAITING 1904L
+#define ERROR_PRINTER_DELETED 1905L
+#define ERROR_INVALID_PRINTER_STATE 1906L
+#define ERROR_PASSWORD_MUST_CHANGE 1907L
+#define ERROR_DOMAIN_CONTROLLER_NOT_FOUND 1908L
+#define ERROR_ACCOUNT_LOCKED_OUT 1909L
+#define ERROR_NO_BROWSER_SERVERS_FOUND 6118L
+#define ERROR_INVALID_PIXEL_FORMAT 2000L
+#define ERROR_BAD_DRIVER 2001L
+#define ERROR_INVALID_WINDOW_STYLE 2002L
+#define ERROR_METAFILE_NOT_SUPPORTED 2003L
+#define ERROR_TRANSFORM_NOT_SUPPORTED 2004L
+#define ERROR_CLIPPING_NOT_SUPPORTED 2005L
+#define ERROR_UNKNOWN_PRINT_MONITOR 3000L
+#define ERROR_PRINTER_DRIVER_IN_USE 3001L
+#define ERROR_SPOOL_FILE_NOT_FOUND 3002L
+#define ERROR_SPL_NO_STARTDOC 3003L
+#define ERROR_SPL_NO_ADDJOB 3004L
+#define ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED 3005L
+#define ERROR_PRINT_MONITOR_ALREADY_INSTALLED 3006L
+#define ERROR_WINS_INTERNAL 4000L
+#define ERROR_CAN_NOT_DEL_LOCAL_WINS 4001L
+#define ERROR_STATIC_INIT 4002L
+#define ERROR_INC_BACKUP 4003L
+#define ERROR_FULL_BACKUP 4004L
+#define ERROR_REC_NON_EXISTENT 4005L
+#define ERROR_RPL_NOT_ALLOWED 4006L
+#define SEVERITY_SUCCESS 0
+#define SEVERITY_ERROR 1
+#define FACILITY_WINDOWS 8
+#define FACILITY_STORAGE 3
+#define FACILITY_RPC 1
+#define FACILITY_WIN32 7
+#define FACILITY_CONTROL 10
+#define FACILITY_NULL 0
+#define FACILITY_ITF 4
+#define FACILITY_DISPATCH 2
+#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
+#define FAILED(Status) ((HRESULT)(Status)<0)
+#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR)
+#define HRESULT_CODE(r) ((r)&0xFFFF)
+#define SCODE_CODE(c) ((c)&0xFFFF)
+#define HRESULT_FACILITY(r) (((r)>>16)&0x1fff)
+#define SCODE_FACILITY(c) (((c)>>16)&0x1fff)
+#define HRESULT_SEVERITY(r) (((r)>>31)&0x1)
+#define SCODE_SEVERITY(c) (((c)>>31)&0x1)
+#define MAKE_HRESULT(s,f,c) ((HRESULT)(((unsigned long)(s)<<31)|((unsigned long)(f)<<16)|((unsigned long)(c))))
+#define MAKE_SCODE(s,f,c) ((SCODE)(((unsigned long)(s)<<31)|((unsigned long)(f)<<16)|((unsigned long)(c))) )
+#define FACILITY_NT_BIT 0x10000000
+#define HRESULT_FROM_WIN32(x) (x?((HRESULT)(((x)&0x0000FFFF)|(FACILITY_WIN32<<16)|0x80000000)):0)
+#define HRESULT_FROM_NT(x) ((HRESULT)((x)|FACILITY_NT_BIT))
+#define GetScode(hr) ((SCODE) (hr))
+#define ResultFromScode(sc) ((HRESULT) (sc))
+#define PropagateResult(hrPrevious, scBase) ((HRESULT) scBase)
+
+#define NOERROR S_OK
+#define E_UNEXPECTED 0x8000FFFFL
+#define E_NOTIMPL 0x80004001L
+#define E_OUTOFMEMORY 0x8007000EL
+#define E_INVALIDARG 0x80070057L
+#define E_NOINTERFACE 0x80004002L
+#define E_POINTER 0x80004003L
+#define E_HANDLE 0x80070006L
+#define E_ABORT 0x80004004L
+#define E_FAIL 0x80004005L
+#define E_ACCESSDENIED 0x80070005L
+#define E_PENDING 0x8000000AL
+#define CO_E_INIT_TLS 0x80004006L
+#define CO_E_INIT_SHARED_ALLOCATOR 0x80004007L
+#define CO_E_INIT_MEMORY_ALLOCATOR 0x80004008L
+#define CO_E_INIT_CLASS_CACHE 0x80004009L
+#define CO_E_INIT_RPC_CHANNEL 0x8000400AL
+#define CO_E_INIT_TLS_SET_CHANNEL_CONTROL 0x8000400BL
+#define CO_E_INIT_TLS_CHANNEL_CONTROL 0x8000400CL
+#define CO_E_INIT_UNACCEPTED_USER_ALLOCATOR 0x8000400DL
+#define CO_E_INIT_SCM_MUTEX_EXISTS 0x8000400EL
+#define CO_E_INIT_SCM_FILE_MAPPING_EXISTS 0x8000400FL
+#define CO_E_INIT_SCM_MAP_VIEW_OF_FILE 0x80004010L
+#define CO_E_INIT_SCM_EXEC_FAILURE 0x80004011L
+#define CO_E_INIT_ONLY_SINGLE_THREADED 0x80004012L
+#define S_OK (0x00000000L)
+#define S_FALSE (0x00000001L)
+#define OLE_E_FIRST 0x80040000L
+#define OLE_E_LAST 0x800400FFL
+#define OLE_S_FIRST 0x00040000L
+#define OLE_S_LAST 0x000400FFL
+#define OLE_E_OLEVERB 0x80040000L
+#define OLE_E_ADVF 0x80040001L
+#define OLE_E_ENUM_NOMORE 0x80040002L
+#define OLE_E_ADVISENOTSUPPORTED 0x80040003L
+#define OLE_E_NOCONNECTION 0x80040004L
+#define OLE_E_NOTRUNNING 0x80040005L
+#define OLE_E_NOCACHE 0x80040006L
+#define OLE_E_BLANK 0x80040007L
+#define OLE_E_CLASSDIFF 0x80040008L
+#define OLE_E_CANT_GETMONIKER 0x80040009L
+#define OLE_E_CANT_BINDTOSOURCE 0x8004000AL
+#define OLE_E_STATIC 0x8004000BL
+#define OLE_E_PROMPTSAVECANCELLED 0x8004000CL
+#define OLE_E_INVALIDRECT 0x8004000DL
+#define OLE_E_WRONGCOMPOBJ 0x8004000EL
+#define OLE_E_INVALIDHWND 0x8004000FL
+#define OLE_E_NOT_INPLACEACTIVE 0x80040010L
+#define OLE_E_CANTCONVERT 0x80040011L
+#define OLE_E_NOSTORAGE 0x80040012L
+#define DV_E_FORMATETC 0x80040064L
+#define DV_E_DVTARGETDEVICE 0x80040065L
+#define DV_E_STGMEDIUM 0x80040066L
+#define DV_E_STATDATA 0x80040067L
+#define DV_E_LINDEX 0x80040068L
+#define DV_E_TYMED 0x80040069L
+#define DV_E_CLIPFORMAT 0x8004006AL
+#define DV_E_DVASPECT 0x8004006BL
+#define DV_E_DVTARGETDEVICE_SIZE 0x8004006CL
+#define DV_E_NOIVIEWOBJECT 0x8004006DL
+#define DRAGDROP_E_FIRST 0x80040100L
+#define DRAGDROP_E_LAST 0x8004010FL
+#define DRAGDROP_S_FIRST 0x00040100L
+#define DRAGDROP_S_LAST 0x0004010FL
+#define DRAGDROP_E_NOTREGISTERED 0x80040100L
+#define DRAGDROP_E_ALREADYREGISTERED 0x80040101L
+#define DRAGDROP_E_INVALIDHWND 0x80040102L
+#define CLASSFACTORY_E_FIRST 0x80040110L
+#define CLASSFACTORY_E_LAST 0x8004011FL
+#define CLASSFACTORY_S_FIRST 0x00040110L
+#define CLASSFACTORY_S_LAST 0x0004011FL
+#define CLASS_E_NOAGGREGATION 0x80040110L
+#define CLASS_E_CLASSNOTAVAILABLE 0x80040111L
+#define MARSHAL_E_FIRST 0x80040120L
+#define MARSHAL_E_LAST 0x8004012FL
+#define MARSHAL_S_FIRST 0x00040120L
+#define MARSHAL_S_LAST 0x0004012FL
+#define DATA_E_FIRST 0x80040130L
+#define DATA_E_LAST 0x8004013FL
+#define DATA_S_FIRST 0x00040130L
+#define DATA_S_LAST 0x0004013FL
+#define VIEW_E_FIRST 0x80040140L
+#define VIEW_E_LAST 0x8004014FL
+#define VIEW_S_FIRST 0x00040140L
+#define VIEW_S_LAST 0x0004014FL
+#define VIEW_E_DRAW 0x80040140L
+#define REGDB_E_FIRST 0x80040150L
+#define REGDB_E_LAST 0x8004015FL
+#define REGDB_S_FIRST 0x00040150L
+#define REGDB_S_LAST 0x0004015FL
+#define REGDB_E_READREGDB 0x80040150L
+#define REGDB_E_WRITEREGDB 0x80040151L
+#define REGDB_E_KEYMISSING 0x80040152L
+#define REGDB_E_INVALIDVALUE 0x80040153L
+#define REGDB_E_CLASSNOTREG 0x80040154L
+#define REGDB_E_IIDNOTREG 0x80040155L
+#define CACHE_E_FIRST 0x80040170L
+#define CACHE_E_LAST 0x8004017FL
+#define CACHE_S_FIRST 0x00040170L
+#define CACHE_S_LAST 0x0004017FL
+#define CACHE_E_NOCACHE_UPDATED 0x80040170L
+#define OLEOBJ_E_FIRST 0x80040180L
+#define OLEOBJ_E_LAST 0x8004018FL
+#define OLEOBJ_S_FIRST 0x00040180L
+#define OLEOBJ_S_LAST 0x0004018FL
+#define OLEOBJ_E_NOVERBS 0x80040180L
+#define OLEOBJ_E_INVALIDVERB 0x80040181L
+#define CLIENTSITE_E_FIRST 0x80040190L
+#define CLIENTSITE_E_LAST 0x8004019FL
+#define CLIENTSITE_S_FIRST 0x00040190L
+#define CLIENTSITE_S_LAST 0x0004019FL
+#define INPLACE_E_NOTUNDOABLE 0x800401A0L
+#define INPLACE_E_NOTOOLSPACE 0x800401A1L
+#define INPLACE_E_FIRST 0x800401A0L
+#define INPLACE_E_LAST 0x800401AFL
+#define INPLACE_S_FIRST 0x000401A0L
+#define INPLACE_S_LAST 0x000401AFL
+#define ENUM_E_FIRST 0x800401B0L
+#define ENUM_E_LAST 0x800401BFL
+#define ENUM_S_FIRST 0x000401B0L
+#define ENUM_S_LAST 0x000401BFL
+#define CONVERT10_E_FIRST 0x800401C0L
+#define CONVERT10_E_LAST 0x800401CFL
+#define CONVERT10_S_FIRST 0x000401C0L
+#define CONVERT10_S_LAST 0x000401CFL
+#define CONVERT10_E_OLESTREAM_GET 0x800401C0L
+#define CONVERT10_E_OLESTREAM_PUT 0x800401C1L
+#define CONVERT10_E_OLESTREAM_FMT 0x800401C2L
+#define CONVERT10_E_OLESTREAM_BITMAP_TO_DIB 0x800401C3L
+#define CONVERT10_E_STG_FMT 0x800401C4L
+#define CONVERT10_E_STG_NO_STD_STREAM 0x800401C5L
+#define CONVERT10_E_STG_DIB_TO_BITMAP 0x800401C6L
+#define CLIPBRD_E_FIRST 0x800401D0L
+#define CLIPBRD_E_LAST 0x800401DFL
+#define CLIPBRD_S_FIRST 0x000401D0L
+#define CLIPBRD_S_LAST 0x000401DFL
+#define CLIPBRD_E_CANT_OPEN 0x800401D0L
+#define CLIPBRD_E_CANT_EMPTY 0x800401D1L
+#define CLIPBRD_E_CANT_SET 0x800401D2L
+#define CLIPBRD_E_BAD_DATA 0x800401D3L
+#define CLIPBRD_E_CANT_CLOSE 0x800401D4L
+#define MK_E_FIRST 0x800401E0L
+#define MK_E_LAST 0x800401EFL
+#define MK_S_FIRST 0x000401E0L
+#define MK_S_LAST 0x000401EFL
+#define MK_E_CONNECTMANUALLY 0x800401E0L
+#define MK_E_EXCEEDEDDEADLINE 0x800401E1L
+#define MK_E_NEEDGENERIC 0x800401E2L
+#define MK_E_UNAVAILABLE 0x800401E3L
+#define MK_E_SYNTAX 0x800401E4L
+#define MK_E_NOOBJECT 0x800401E5L
+#define MK_E_INVALIDEXTENSION 0x800401E6L
+#define MK_E_INTERMEDIATEINTERFACENOTSUPPORTED 0x800401E7L
+#define MK_E_NOTBINDABLE 0x800401E8L
+#define MK_E_NOTBOUND 0x800401E9L
+#define MK_E_CANTOPENFILE 0x800401EAL
+#define MK_E_MUSTBOTHERUSER 0x800401EBL
+#define MK_E_NOINVERSE 0x800401ECL
+#define MK_E_NOSTORAGE 0x800401EDL
+#define MK_E_NOPREFIX 0x800401EEL
+#define MK_E_ENUMERATION_FAILED 0x800401EFL
+#define CO_E_FIRST 0x800401F0L
+#define CO_E_LAST 0x800401FFL
+#define CO_S_FIRST 0x000401F0L
+#define CO_S_LAST 0x000401FFL
+#define CO_E_NOTINITIALIZED 0x800401F0L
+#define CO_E_ALREADYINITIALIZED 0x800401F1L
+#define CO_E_CANTDETERMINECLASS 0x800401F2L
+#define CO_E_CLASSSTRING 0x800401F3L
+#define CO_E_IIDSTRING 0x800401F4L
+#define CO_E_APPNOTFOUND 0x800401F5L
+#define CO_E_APPSINGLEUSE 0x800401F6L
+#define CO_E_ERRORINAPP 0x800401F7L
+#define CO_E_DLLNOTFOUND 0x800401F8L
+#define CO_E_ERRORINDLL 0x800401F9L
+#define CO_E_WRONGOSFORAPP 0x800401FAL
+#define CO_E_OBJNOTREG 0x800401FBL
+#define CO_E_OBJISREG 0x800401FCL
+#define CO_E_OBJNOTCONNECTED 0x800401FDL
+#define CO_E_APPDIDNTREG 0x800401FEL
+#define CO_E_RELEASED 0x800401FFL
+#define OLE_S_USEREG 0x00040000L
+#define OLE_S_STATIC 0x00040001L
+#define OLE_S_MAC_CLIPFORMAT 0x00040002L
+#define DRAGDROP_S_DROP 0x00040100L
+#define DRAGDROP_S_CANCEL 0x00040101L
+#define DRAGDROP_S_USEDEFAULTCURSORS 0x00040102L
+#define DATA_S_SAMEFORMATETC 0x00040130L
+#define VIEW_S_ALREADY_FROZEN 0x00040140L
+#define CACHE_S_FORMATETC_NOTSUPPORTED 0x00040170L
+#define CACHE_S_SAMECACHE 0x00040171L
+#define CACHE_S_SOMECACHES_NOTUPDATED 0x00040172L
+#define OLEOBJ_S_INVALIDVERB 0x00040180L
+#define OLEOBJ_S_CANNOT_DOVERB_NOW 0x00040181L
+#define OLEOBJ_S_INVALIDHWND 0x00040182L
+#define INPLACE_S_TRUNCATED 0x000401A0L
+#define CONVERT10_S_NO_PRESENTATION 0x000401C0L
+#define MK_S_REDUCED_TO_SELF 0x000401E2L
+#define MK_S_ME 0x000401E4L
+#define MK_S_HIM 0x000401E5L
+#define MK_S_US 0x000401E6L
+#define MK_S_MONIKERALREADYREGISTERED 0x000401E7L
+#define CO_E_CLASS_CREATE_FAILED 0x80080001L
+#define CO_E_SCM_ERROR 0x80080002L
+#define CO_E_SCM_RPC_FAILURE 0x80080003L
+#define CO_E_BAD_PATH 0x80080004L
+#define CO_E_SERVER_EXEC_FAILURE 0x80080005L
+#define CO_E_OBJSRV_RPC_FAILURE 0x80080006L
+#define MK_E_NO_NORMALIZED 0x80080007L
+#define CO_E_SERVER_STOPPING 0x80080008L
+#define MEM_E_INVALID_ROOT 0x80080009L
+#define MEM_E_INVALID_LINK 0x80080010L
+#define MEM_E_INVALID_SIZE 0x80080011L
+#define DISP_E_UNKNOWNINTERFACE 0x80020001L
+#define DISP_E_MEMBERNOTFOUND 0x80020003L
+#define DISP_E_PARAMNOTFOUND 0x80020004L
+#define DISP_E_TYPEMISMATCH 0x80020005L
+#define DISP_E_UNKNOWNNAME 0x80020006L
+#define DISP_E_NONAMEDARGS 0x80020007L
+#define DISP_E_BADVARTYPE 0x80020008L
+#define DISP_E_EXCEPTION 0x80020009L
+#define DISP_E_OVERFLOW 0x8002000AL
+#define DISP_E_BADINDEX 0x8002000BL
+#define DISP_E_UNKNOWNLCID 0x8002000CL
+#define DISP_E_ARRAYISLOCKED 0x8002000DL
+#define DISP_E_BADPARAMCOUNT 0x8002000EL
+#define DISP_E_PARAMNOTOPTIONAL 0x8002000FL
+#define DISP_E_BADCALLEE 0x80020010L
+#define DISP_E_NOTACOLLECTION 0x80020011L
+#define TYPE_E_BUFFERTOOSMALL 0x80028016L
+#define TYPE_E_INVDATAREAD 0x80028018L
+#define TYPE_E_UNSUPFORMAT 0x80028019L
+#define TYPE_E_REGISTRYACCESS 0x8002801CL
+#define TYPE_E_LIBNOTREGISTERED 0x8002801DL
+#define TYPE_E_UNDEFINEDTYPE 0x80028027L
+#define TYPE_E_QUALIFIEDNAMEDISALLOWED 0x80028028L
+#define TYPE_E_INVALIDSTATE 0x80028029L
+#define TYPE_E_WRONGTYPEKIND 0x8002802AL
+#define TYPE_E_ELEMENTNOTFOUND 0x8002802BL
+#define TYPE_E_AMBIGUOUSNAME 0x8002802CL
+#define TYPE_E_NAMECONFLICT 0x8002802DL
+#define TYPE_E_UNKNOWNLCID 0x8002802EL
+#define TYPE_E_DLLFUNCTIONNOTFOUND 0x8002802FL
+#define TYPE_E_BADMODULEKIND 0x800288BDL
+#define TYPE_E_SIZETOOBIG 0x800288C5L
+#define TYPE_E_DUPLICATEID 0x800288C6L
+#define TYPE_E_INVALIDID 0x800288CFL
+#define TYPE_E_TYPEMISMATCH 0x80028CA0L
+#define TYPE_E_OUTOFBOUNDS 0x80028CA1L
+#define TYPE_E_IOERROR 0x80028CA2L
+#define TYPE_E_CANTCREATETMPFILE 0x80028CA3L
+#define TYPE_E_CANTLOADLIBRARY 0x80029C4AL
+#define TYPE_E_INCONSISTENTPROPFUNCS 0x80029C83L
+#define TYPE_E_CIRCULARTYPE 0x80029C84L
+#define STG_E_INVALIDFUNCTION 0x80030001L
+#define STG_E_FILENOTFOUND 0x80030002L
+#define STG_E_PATHNOTFOUND 0x80030003L
+#define STG_E_TOOMANYOPENFILES 0x80030004L
+#define STG_E_ACCESSDENIED 0x80030005L
+#define STG_E_INVALIDHANDLE 0x80030006L
+#define STG_E_INSUFFICIENTMEMORY 0x80030008L
+#define STG_E_INVALIDPOINTER 0x80030009L
+#define STG_E_NOMOREFILES 0x80030012L
+#define STG_E_DISKISWRITEPROTECTED 0x80030013L
+#define STG_E_SEEKERROR 0x80030019L
+#define STG_E_WRITEFAULT 0x8003001DL
+#define STG_E_READFAULT 0x8003001EL
+#define STG_E_SHAREVIOLATION 0x80030020L
+#define STG_E_LOCKVIOLATION 0x80030021L
+#define STG_E_FILEALREADYEXISTS 0x80030050L
+#define STG_E_INVALIDPARAMETER 0x80030057L
+#define STG_E_MEDIUMFULL 0x80030070L
+#define STG_E_ABNORMALAPIEXIT 0x800300FAL
+#define STG_E_INVALIDHEADER 0x800300FBL
+#define STG_E_INVALIDNAME 0x800300FCL
+#define STG_E_UNKNOWN 0x800300FDL
+#define STG_E_UNIMPLEMENTEDFUNCTION 0x800300FEL
+#define STG_E_INVALIDFLAG 0x800300FFL
+#define STG_E_INUSE 0x80030100L
+#define STG_E_NOTCURRENT 0x80030101L
+#define STG_E_REVERTED 0x80030102L
+#define STG_E_CANTSAVE 0x80030103L
+#define STG_E_OLDFORMAT 0x80030104L
+#define STG_E_OLDDLL 0x80030105L
+#define STG_E_SHAREREQUIRED 0x80030106L
+#define STG_E_NOTFILEBASEDSTORAGE 0x80030107L
+#define STG_E_EXTANTMARSHALLINGS 0x80030108L
+#define STG_S_CONVERTED 0x00030200L
+#define RPC_E_CALL_REJECTED 0x80010001L
+#define RPC_E_CALL_CANCELED 0x80010002L
+#define RPC_E_CANTPOST_INSENDCALL 0x80010003L
+#define RPC_E_CANTCALLOUT_INASYNCCALL 0x80010004L
+#define RPC_E_CANTCALLOUT_INEXTERNALCALL 0x80010005L
+#define RPC_E_CONNECTION_TERMINATED 0x80010006L
+#define RPC_E_SERVER_DIED 0x80010007L
+#define RPC_E_CLIENT_DIED 0x80010008L
+#define RPC_E_INVALID_DATAPACKET 0x80010009L
+#define RPC_E_CANTTRANSMIT_CALL 0x8001000AL
+#define RPC_E_CLIENT_CANTMARSHAL_DATA 0x8001000BL
+#define RPC_E_CLIENT_CANTUNMARSHAL_DATA 0x8001000CL
+#define RPC_E_SERVER_CANTMARSHAL_DATA 0x8001000DL
+#define RPC_E_SERVER_CANTUNMARSHAL_DATA 0x8001000EL
+#define RPC_E_INVALID_DATA 0x8001000FL
+#define RPC_E_INVALID_PARAMETER 0x80010010L
+#define RPC_E_CANTCALLOUT_AGAIN 0x80010011L
+#define RPC_E_SERVER_DIED_DNE 0x80010012L
+#define RPC_E_SYS_CALL_FAILED 0x80010100L
+#define RPC_E_OUT_OF_RESOURCES 0x80010101L
+#define RPC_E_ATTEMPTED_MULTITHREAD 0x80010102L
+#define RPC_E_NOT_REGISTERED 0x80010103L
+#define RPC_E_FAULT 0x80010104L
+#define RPC_E_SERVERFAULT 0x80010105L
+#define RPC_E_CHANGED_MODE 0x80010106L
+#define RPC_E_INVALIDMETHOD 0x80010107L
+#define RPC_E_DISCONNECTED 0x80010108L
+#define RPC_E_RETRY 0x80010109L
+#define RPC_E_SERVERCALL_RETRYLATER 0x8001010AL
+#define RPC_E_SERVERCALL_REJECTED 0x8001010BL
+#define RPC_E_INVALID_CALLDATA 0x8001010CL
+#define RPC_E_CANTCALLOUT_ININPUTSYNCCALL 0x8001010DL
+#define RPC_E_WRONG_THREAD 0x8001010EL
+#define RPC_E_THREAD_NOT_INIT 0x8001010FL
+#define RPC_E_UNEXPECTED 0x8001FFFFL
+
+#define NTE_BAD_UID 0x80090001L
+#define NTE_BAD_HASH 0x80090002L
+#define NTE_BAD_KEY 0x80090003L
+#define NTE_BAD_LEN 0x80090004L
+#define NTE_BAD_DATA 0x80090005L
+#define NTE_BAD_SIGNATURE 0x80090006L
+#define NTE_BAD_VER 0x80090007L
+#define NTE_BAD_ALGID 0x80090008L
+#define NTE_BAD_FLAGS 0x80090009L
+#define NTE_BAD_TYPE 0x8009000AL
+#define NTE_BAD_KEY_STATE 0x8009000BL
+#define NTE_BAD_HASH_STATE 0x8009000CL
+#define NTE_NO_KEY 0x8009000DL
+#define NTE_NO_MEMORY 0x8009000EL
+#define NTE_EXISTS 0x8009000FL
+#define NTE_PERM 0x80090010L
+#define NTE_NOT_FOUND 0x80090011L
+#define NTE_DOUBLE_ENCRYPT 0x80090012L
+#define NTE_BAD_PROVIDER 0x80090013L
+#define NTE_BAD_PROV_TYPE 0x80090014L
+#define NTE_BAD_PUBLIC_KEY 0x80090015L
+#define NTE_BAD_KEYSET 0x80090016L
+#define NTE_PROV_TYPE_NOT_DEF 0x80090017L
+#define NTE_PROV_TYPE_ENTRY_BAD 0x80090018L
+#define NTE_KEYSET_NOT_DEF 0x80090019L
+#define NTE_KEYSET_ENTRY_BAD 0x8009001AL
+#define NTE_PROV_TYPE_NO_MATCH 0x8009001BL
+#define NTE_SIGNATURE_FILE_BAD 0x8009001CL
+#define NTE_PROVIDER_DLL_FAIL 0x8009001DL
+#define NTE_PROV_DLL_NOT_FOUND 0x8009001EL
+#define NTE_BAD_KEYSET_PARAM 0x8009001FL
+#define NTE_FAIL 0x80090020L
+#define NTE_SYS_ERR 0x80090021L
+/* #define NTE_TOKEN_KEYSET_STORAGE ??? */
+
+#endif
diff --git a/tinyc/win32/include/winapi/wingdi.h b/tinyc/win32/include/winapi/wingdi.h
new file mode 100644
index 000000000..b0af5adeb
--- /dev/null
+++ b/tinyc/win32/include/winapi/wingdi.h
@@ -0,0 +1,2843 @@
+#ifndef _WINGDI_H
+#define _WINGDI_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WINGDIAPI
+#define BI_RGB 0
+#define BI_RLE8 1
+#define BI_RLE4 2
+#define BI_BITFIELDS 3
+#define BI_JPEG 4
+#define BI_PNG 5
+#define LF_FACESIZE	32
+#define LF_FULLFACESIZE	64
+#define CA_NEGATIVE	1
+#define CA_LOG_FILTER	2
+#define ILLUMINANT_DEVICE_DEFAULT	0
+#define ILLUMINANT_A	1
+#define ILLUMINANT_B	2
+#define ILLUMINANT_C	3
+#define ILLUMINANT_D50	4
+#define ILLUMINANT_D55	5
+#define ILLUMINANT_D65	6
+#define ILLUMINANT_D75	7
+#define ILLUMINANT_F2	8
+#define ILLUMINANT_MAX_INDEX	ILLUMINANT_F2
+#define ILLUMINANT_TUNGSTEN	ILLUMINANT_A
+#define ILLUMINANT_DAYLIGHT	ILLUMINANT_C
+#define ILLUMINANT_FLUORESCENT	ILLUMINANT_F2
+#define ILLUMINANT_NTSC	ILLUMINANT_C
+#define RGB_GAMMA_MIN	2500
+#define RGB_GAMMA_MAX	65000
+#define REFERENCE_WHITE_MIN	6000
+#define REFERENCE_WHITE_MAX	10000
+#define REFERENCE_BLACK_MIN	0
+#define REFERENCE_BLACK_MAX	4000
+#define COLOR_ADJ_MIN	(-100)
+#define COLOR_ADJ_MAX	100
+#define CCHDEVICENAME 32
+#define CCHFORMNAME 32
+#define DI_COMPAT	4
+#define DI_DEFAULTSIZE	8
+#define DI_IMAGE	2
+#define DI_MASK	1
+#define DI_NORMAL	3
+#define DI_APPBANDING 1
+#define EMR_HEADER	1
+#define EMR_POLYBEZIER 2
+#define EMR_POLYGON	3
+#define EMR_POLYLINE	4
+#define EMR_POLYBEZIERTO	5
+#define EMR_POLYLINETO 6
+#define EMR_POLYPOLYLINE	7
+#define EMR_POLYPOLYGON 8
+#define EMR_SETWINDOWEXTEX	9
+#define EMR_SETWINDOWORGEX	10
+#define EMR_SETVIEWPORTEXTEX 11
+#define EMR_SETVIEWPORTORGEX 12
+#define EMR_SETBRUSHORGEX 13
+#define EMR_EOF 14
+#define EMR_SETPIXELV 15
+#define EMR_SETMAPPERFLAGS 16
+#define EMR_SETMAPMODE 17
+#define EMR_SETBKMODE 18
+#define EMR_SETPOLYFILLMODE 19
+#define EMR_SETROP2 20
+#define EMR_SETSTRETCHBLTMODE 21
+#define EMR_SETTEXTALIGN 22
+#define EMR_SETCOLORADJUSTMENT 23
+#define EMR_SETTEXTCOLOR 24
+#define EMR_SETBKCOLOR 25
+#define EMR_OFFSETCLIPRGN 26
+#define EMR_MOVETOEX 27
+#define EMR_SETMETARGN 28
+#define EMR_EXCLUDECLIPRECT 29
+#define EMR_INTERSECTCLIPRECT 30
+#define EMR_SCALEVIEWPORTEXTEX 31
+#define EMR_SCALEWINDOWEXTEX 32
+#define EMR_SAVEDC 33
+#define EMR_RESTOREDC 34
+#define EMR_SETWORLDTRANSFORM 35
+#define EMR_MODIFYWORLDTRANSFORM 36
+#define EMR_SELECTOBJECT 37
+#define EMR_CREATEPEN 38
+#define EMR_CREATEBRUSHINDIRECT 39
+#define EMR_DELETEOBJECT 40
+#define EMR_ANGLEARC 41
+#define EMR_ELLIPSE  42
+#define EMR_RECTANGLE 43
+#define EMR_ROUNDRECT 44
+#define EMR_ARC 45
+#define EMR_CHORD 46
+#define EMR_PIE 47
+#define EMR_SELECTPALETTE 48
+#define EMR_CREATEPALETTE 49
+#define EMR_SETPALETTEENTRIES 50
+#define EMR_RESIZEPALETTE 51
+#define EMR_REALIZEPALETTE 52
+#define EMR_EXTFLOODFILL 53
+#define EMR_LINETO 54
+#define EMR_ARCTO 55
+#define EMR_POLYDRAW 56
+#define EMR_SETARCDIRECTION 57
+#define EMR_SETMITERLIMIT 58
+#define EMR_BEGINPATH 59
+#define EMR_ENDPATH 60
+#define EMR_CLOSEFIGURE 61
+#define EMR_FILLPATH 62
+#define EMR_STROKEANDFILLPATH 63
+#define EMR_STROKEPATH 64
+#define EMR_FLATTENPATH 65
+#define EMR_WIDENPATH 66
+#define EMR_SELECTCLIPPATH 67
+#define EMR_ABORTPATH 68
+#define EMR_GDICOMMENT 70
+#define EMR_FILLRGN 71
+#define EMR_FRAMERGN 72
+#define EMR_INVERTRGN 73
+#define EMR_PAINTRGN 74
+#define EMR_EXTSELECTCLIPRGN 75
+#define EMR_BITBLT 76
+#define EMR_STRETCHBLT 77
+#define EMR_MASKBLT 78
+#define EMR_PLGBLT 79
+#define EMR_SETDIBITSTODEVICE 80
+#define EMR_STRETCHDIBITS 81
+#define EMR_EXTCREATEFONTINDIRECTW 82
+#define EMR_EXTTEXTOUTA 83
+#define EMR_EXTTEXTOUTW 84
+#define EMR_POLYBEZIER16 85
+#define EMR_POLYGON16 86
+#define EMR_POLYLINE16 87
+#define EMR_POLYBEZIERTO16 88
+#define EMR_POLYLINETO16 89
+#define EMR_POLYPOLYLINE16 90
+#define EMR_POLYPOLYGON16 91
+#define EMR_POLYDRAW16 92
+#define EMR_CREATEMONOBRUSH 93
+#define EMR_CREATEDIBPATTERNBRUSHPT 94
+#define EMR_EXTCREATEPEN 95
+#define EMR_POLYTEXTOUTA 96
+#define EMR_POLYTEXTOUTW 97
+#define EMR_SETICMMODE 98
+#define EMR_CREATECOLORSPACE 99
+#define EMR_SETCOLORSPACE 100
+#define EMR_DELETECOLORSPACE 101
+#define EMR_GLSRECORD 102
+#define EMR_GLSBOUNDEDRECORD 103
+#define EMR_PIXELFORMAT 104
+#define ENHMETA_SIGNATURE 1179469088
+#define EPS_SIGNATURE 0x46535045
+#define META_SETBKCOLOR	0x201
+#define META_SETBKMODE	0x102
+#define META_SETMAPMODE	0x103
+#define META_SETROP2	0x104
+#define META_SETRELABS	0x105
+#define META_SETPOLYFILLMODE	0x106
+#define META_SETSTRETCHBLTMODE	0x107
+#define META_SETTEXTCHAREXTRA	0x108
+#define META_SETTEXTCOLOR	0x209
+#define META_SETTEXTJUSTIFICATION	0x20A
+#define META_SETWINDOWORG	0x20B
+#define META_SETWINDOWEXT	0x20C
+#define META_SETVIEWPORTORG	0x20D
+#define META_SETVIEWPORTEXT	0x20E
+#define META_OFFSETWINDOWORG	0x20F
+#define META_SCALEWINDOWEXT	0x410
+#define META_OFFSETVIEWPORTORG	0x211
+#define META_SCALEVIEWPORTEXT	0x412
+#define META_LINETO	0x213
+#define META_MOVETO	0x214
+#define META_EXCLUDECLIPRECT	0x415
+#define META_INTERSECTCLIPRECT	0x416
+#define META_ARC	0x817
+#define META_ELLIPSE	0x418
+#define META_FLOODFILL	0x419
+#define META_PIE	0x81A
+#define META_RECTANGLE	0x41B
+#define META_ROUNDRECT	0x61C
+#define META_PATBLT	0x61D
+#define META_SAVEDC	0x1E
+#define META_SETPIXEL	0x41F
+#define META_OFFSETCLIPRGN	0x220
+#define META_TEXTOUT	0x521
+#define META_BITBLT	0x922
+#define META_STRETCHBLT	0xB23
+#define META_POLYGON	0x324
+#define META_POLYLINE	0x325
+#define META_ESCAPE	0x626
+#define META_RESTOREDC	0x127
+#define META_FILLREGION	0x228
+#define META_FRAMEREGION	0x429
+#define META_INVERTREGION	0x12A
+#define META_PAINTREGION	0x12B
+#define META_SELECTCLIPREGION	0x12C
+#define META_SELECTOBJECT	0x12D
+#define META_SETTEXTALIGN	0x12E
+#define META_CHORD	0x830
+#define META_SETMAPPERFLAGS	0x231
+#define META_EXTTEXTOUT	0xa32
+#define META_SETDIBTODEV	0xd33
+#define META_SELECTPALETTE	0x234
+#define META_REALIZEPALETTE	0x35
+#define META_ANIMATEPALETTE	0x436
+#define META_SETPALENTRIES	0x37
+#define META_POLYPOLYGON	0x538
+#define META_RESIZEPALETTE	0x139
+#define META_DIBBITBLT	0x940
+#define META_DIBSTRETCHBLT	0xb41
+#define META_DIBCREATEPATTERNBRUSH	0x142
+#define META_STRETCHDIB	0xf43
+#define META_EXTFLOODFILL	0x548
+#define META_DELETEOBJECT	0x1f0
+#define META_CREATEPALETTE	0xf7
+#define META_CREATEPATTERNBRUSH	0x1F9
+#define META_CREATEPENINDIRECT	0x2FA
+#define META_CREATEFONTINDIRECT	0x2FB
+#define META_CREATEBRUSHINDIRECT	0x2FC
+#define META_CREATEREGION	0x6FF
+#define PT_MOVETO	6
+#define PT_LINETO	2
+#define PT_BEZIERTO	4
+#define PT_CLOSEFIGURE 1
+#define ELF_VENDOR_SIZE	4
+#define ELF_VERSION	0
+#define ELF_CULTURE_LATIN	0
+#define PFD_TYPE_RGBA	0
+#define PFD_TYPE_COLORINDEX	1
+#define PFD_MAIN_PLANE	0
+#define PFD_OVERLAY_PLANE	1
+#define PFD_UNDERLAY_PLANE	(-1)
+#define PFD_DOUBLEBUFFER	1
+#define PFD_STEREO	2
+#define PFD_DRAW_TO_WINDOW	4
+#define PFD_DRAW_TO_BITMAP	8
+#define PFD_SUPPORT_GDI	16
+#define PFD_SUPPORT_OPENGL	32
+#define PFD_GENERIC_FORMAT	64
+#define PFD_NEED_PALETTE	128
+#define PFD_NEED_SYSTEM_PALETTE	0x00000100
+#define PFD_SWAP_EXCHANGE	0x00000200
+#define PFD_SWAP_COPY	0x00000400
+#define PFD_GENERIC_ACCELERATED	0x00001000
+#define PFD_DEPTH_DONTCARE	0x20000000
+#define PFD_DOUBLEBUFFER_DONTCARE	0x40000000
+#define PFD_STEREO_DONTCARE	0x80000000
+#define SP_ERROR	(-1)
+#define SP_OUTOFDISK	(-4)
+#define SP_OUTOFMEMORY	(-5)
+#define SP_USERABORT	(-3)
+#define SP_APPABORT	(-2)
+#define BLACKNESS	0x42
+#define NOTSRCERASE	0x1100A6
+#define NOTSRCCOPY	0x330008
+#define SRCERASE	0x440328
+#define DSTINVERT	0x550009
+#define PATINVERT	0x5A0049
+#define SRCINVERT	0x660046
+#define SRCAND	0x8800C6
+#define MERGEPAINT	0xBB0226
+#define MERGECOPY	0xC000CA
+#define SRCCOPY 0xCC0020
+#define SRCPAINT	0xEE0086
+#define PATCOPY	0xF00021
+#define PATPAINT	0xFB0A09
+#define WHITENESS	0xFF0062
+#define R2_BLACK	1
+#define R2_COPYPEN	13
+#define R2_MASKNOTPEN	3
+#define R2_MASKPEN	9
+#define R2_MASKPENNOT	5
+#define R2_MERGENOTPEN	12
+#define R2_MERGEPEN	15
+#define R2_MERGEPENNOT	14
+#define R2_NOP	11
+#define R2_NOT	6
+#define R2_NOTCOPYPEN	4
+#define R2_NOTMASKPEN	8
+#define R2_NOTMERGEPEN	2
+#define R2_NOTXORPEN	10
+#define R2_WHITE	16
+#define R2_XORPEN	7
+#define CM_OUT_OF_GAMUT	255
+#define CM_IN_GAMUT	0
+#define RGN_AND 1
+#define RGN_COPY	5
+#define RGN_DIFF	4
+#define RGN_OR	2
+#define RGN_XOR	3
+#define NULLREGION	1
+#define SIMPLEREGION	2
+#define COMPLEXREGION	3
+#define ERROR 0
+#define CBM_INIT	4
+#define DIB_PAL_COLORS	1
+#define DIB_RGB_COLORS	0
+#define FW_DONTCARE	0
+#define FW_THIN	100
+#define FW_EXTRALIGHT	200
+#define FW_ULTRALIGHT	FW_EXTRALIGHT
+#define FW_LIGHT	300
+#define FW_NORMAL	400
+#define FW_REGULAR	400
+#define FW_MEDIUM	500
+#define FW_SEMIBOLD	600
+#define FW_DEMIBOLD	FW_SEMIBOLD
+#define FW_BOLD	700
+#define FW_EXTRABOLD	800
+#define FW_ULTRABOLD	FW_EXTRABOLD
+#define FW_HEAVY	900
+#define FW_BLACK	FW_HEAVY
+#define ANSI_CHARSET	0
+#define DEFAULT_CHARSET	1
+#define SYMBOL_CHARSET	2
+#define SHIFTJIS_CHARSET	128
+#define HANGEUL_CHARSET	129
+#define HANGUL_CHARSET  129
+#define GB2312_CHARSET	134
+#define CHINESEBIG5_CHARSET	136
+#define GREEK_CHARSET	161
+#define TURKISH_CHARSET	162
+#define HEBREW_CHARSET	177
+#define ARABIC_CHARSET	178
+#define BALTIC_CHARSET	186
+#define RUSSIAN_CHARSET	204
+#define THAI_CHARSET	222
+#define EASTEUROPE_CHARSET	238
+#define OEM_CHARSET	255
+#define JOHAB_CHARSET	130
+#define VIETNAMESE_CHARSET	163
+#define MAC_CHARSET 77
+#define BALTIC_CHARSET 186
+#define JOHAB_CHARSET 130
+#define VIETNAMESE_CHARSET 163
+#define OUT_DEFAULT_PRECIS	0
+#define OUT_STRING_PRECIS	1
+#define OUT_CHARACTER_PRECIS	2
+#define OUT_STROKE_PRECIS	3
+#define OUT_TT_PRECIS	4
+#define OUT_DEVICE_PRECIS	5
+#define OUT_RASTER_PRECIS	6
+#define OUT_TT_ONLY_PRECIS	7
+#define OUT_OUTLINE_PRECIS	8
+#define CLIP_DEFAULT_PRECIS	0
+#define CLIP_CHARACTER_PRECIS	1
+#define CLIP_STROKE_PRECIS	2
+#define CLIP_MASK	15
+#define CLIP_LH_ANGLES	16
+#define CLIP_TT_ALWAYS	32
+#define CLIP_EMBEDDED	128
+#define DEFAULT_QUALITY	0
+#define DRAFT_QUALITY	1
+#define PROOF_QUALITY	2
+#define NONANTIALIASED_QUALITY 3
+#define ANTIALIASED_QUALITY 4
+#define DEFAULT_PITCH	0
+#define FIXED_PITCH	1
+#define VARIABLE_PITCH	2
+#define MONO_FONT 8
+#define FF_DECORATIVE	80
+#define FF_DONTCARE	0
+#define FF_MODERN	48
+#define FF_ROMAN	16
+#define FF_SCRIPT	64
+#define FF_SWISS	32
+#define PANOSE_COUNT 10
+#define PAN_FAMILYTYPE_INDEX 0
+#define PAN_SERIFSTYLE_INDEX 1
+#define PAN_WEIGHT_INDEX 2
+#define PAN_PROPORTION_INDEX 3
+#define PAN_CONTRAST_INDEX 4
+#define PAN_STROKEVARIATION_INDEX 5
+#define PAN_ARMSTYLE_INDEX 6
+#define PAN_LETTERFORM_INDEX 7
+#define PAN_MIDLINE_INDEX 8
+#define PAN_XHEIGHT_INDEX 9
+#define PAN_CULTURE_LATIN 0
+#define PAN_ANY 0
+#define PAN_NO_FIT 1
+#define PAN_FAMILY_TEXT_DISPLAY 2
+#define PAN_FAMILY_SCRIPT 3
+#define PAN_FAMILY_DECORATIVE 4
+#define PAN_FAMILY_PICTORIAL 5
+#define PAN_SERIF_COVE 2
+#define PAN_SERIF_OBTUSE_COVE 3
+#define PAN_SERIF_SQUARE_COVE 4
+#define PAN_SERIF_OBTUSE_SQUARE_COVE 5
+#define PAN_SERIF_SQUARE 6
+#define PAN_SERIF_THIN 7
+#define PAN_SERIF_BONE 8
+#define PAN_SERIF_EXAGGERATED 9
+#define PAN_SERIF_TRIANGLE 10
+#define PAN_SERIF_NORMAL_SANS 11
+#define PAN_SERIF_OBTUSE_SANS 12
+#define PAN_SERIF_PERP_SANS 13
+#define PAN_SERIF_FLARED 14
+#define PAN_SERIF_ROUNDED 15
+#define PAN_WEIGHT_VERY_LIGHT 2
+#define PAN_WEIGHT_LIGHT 3
+#define PAN_WEIGHT_THIN 4
+#define PAN_WEIGHT_BOOK 5
+#define PAN_WEIGHT_MEDIUM 6
+#define PAN_WEIGHT_DEMI 7
+#define PAN_WEIGHT_BOLD 8
+#define PAN_WEIGHT_HEAVY 9
+#define PAN_WEIGHT_BLACK 10
+#define PAN_WEIGHT_NORD 11
+#define PAN_PROP_OLD_STYLE 2
+#define PAN_PROP_MODERN 3
+#define PAN_PROP_EVEN_WIDTH 4
+#define PAN_PROP_EXPANDED 5
+#define PAN_PROP_CONDENSED 6
+#define PAN_PROP_VERY_EXPANDED 7
+#define PAN_PROP_VERY_CONDENSED 8
+#define PAN_PROP_MONOSPACED 9
+#define PAN_CONTRAST_NONE 2
+#define PAN_CONTRAST_VERY_LOW 3
+#define PAN_CONTRAST_LOW 4
+#define PAN_CONTRAST_MEDIUM_LOW 5
+#define PAN_CONTRAST_MEDIUM 6
+#define PAN_CONTRAST_MEDIUM_HIGH 7
+#define PAN_CONTRAST_HIGH 8
+#define PAN_CONTRAST_VERY_HIGH 9
+#define PAN_STROKE_GRADUAL_DIAG 2
+#define PAN_STROKE_GRADUAL_TRAN 3
+#define PAN_STROKE_GRADUAL_VERT 4
+#define PAN_STROKE_GRADUAL_HORZ 5
+#define PAN_STROKE_RAPID_VERT 6
+#define PAN_STROKE_RAPID_HORZ 7
+#define PAN_STROKE_INSTANT_VERT 8
+#define PAN_STRAIGHT_ARMS_HORZ 2
+#define PAN_STRAIGHT_ARMS_WEDGE 3
+#define PAN_STRAIGHT_ARMS_VERT 4
+#define PAN_STRAIGHT_ARMS_SINGLE_SERIF 5
+#define PAN_STRAIGHT_ARMS_DOUBLE_SERIF 6
+#define PAN_BENT_ARMS_HORZ 7
+#define PAN_BENT_ARMS_WEDGE 8
+#define PAN_BENT_ARMS_VERT 9
+#define PAN_BENT_ARMS_SINGLE_SERIF 10
+#define PAN_BENT_ARMS_DOUBLE_SERIF 11
+#define PAN_LETT_NORMAL_CONTACT 2
+#define PAN_LETT_NORMAL_WEIGHTED 3
+#define PAN_LETT_NORMAL_BOXED 4
+#define PAN_LETT_NORMAL_FLATTENED 5
+#define PAN_LETT_NORMAL_ROUNDED 6
+#define PAN_LETT_NORMAL_OFF_CENTER 7
+#define PAN_LETT_NORMAL_SQUARE 8
+#define PAN_LETT_OBLIQUE_CONTACT 9
+#define PAN_LETT_OBLIQUE_WEIGHTED 10
+#define PAN_LETT_OBLIQUE_BOXED 11
+#define PAN_LETT_OBLIQUE_FLATTENED 12
+#define PAN_LETT_OBLIQUE_ROUNDED 13
+#define PAN_LETT_OBLIQUE_OFF_CENTER 14
+#define PAN_LETT_OBLIQUE_SQUARE 15
+#define PAN_MIDLINE_STANDARD_TRIMMED 2
+#define PAN_MIDLINE_STANDARD_POINTED 3
+#define PAN_MIDLINE_STANDARD_SERIFED 4
+#define PAN_MIDLINE_HIGH_TRIMMED 5
+#define PAN_MIDLINE_HIGH_POINTED 6
+#define PAN_MIDLINE_HIGH_SERIFED 7
+#define PAN_MIDLINE_CONSTANT_TRIMMED 8
+#define PAN_MIDLINE_CONSTANT_POINTED 9
+#define PAN_MIDLINE_CONSTANT_SERIFED 10
+#define PAN_MIDLINE_LOW_TRIMMED 11
+#define PAN_MIDLINE_LOW_POINTED 12
+#define PAN_MIDLINE_LOW_SERIFED 13
+#define PAN_XHEIGHT_CONSTANT_SMALL 2
+#define PAN_XHEIGHT_CONSTANT_STD 3
+#define PAN_XHEIGHT_CONSTANT_LARGE 4
+#define PAN_XHEIGHT_DUCKING_SMALL 5
+#define PAN_XHEIGHT_DUCKING_STD 6
+#define PAN_XHEIGHT_DUCKING_LARGE 7
+#define FS_LATIN1 1
+#define FS_LATIN2 2
+#define FS_CYRILLIC 4
+#define FS_GREEK 8
+#define FS_TURKISH 16
+#define FS_HEBREW 32
+#define FS_ARABIC 64
+#define FS_BALTIC 128
+#define FS_THAI 0x10000
+#define FS_JISJAPAN 0x20000
+#define FS_CHINESESIMP 0x40000
+#define FS_WANSUNG 0x80000
+#define FS_CHINESETRAD 0x100000
+#define FS_JOHAB 0x200000
+#define FS_SYMBOL 0x80000000
+#define HS_BDIAGONAL	3
+#define HS_CROSS	4
+#define HS_DIAGCROSS	5
+#define HS_FDIAGONAL	2
+#define HS_HORIZONTAL	0
+#define HS_VERTICAL	1
+#define PS_GEOMETRIC	65536
+#define PS_COSMETIC	0
+#define PS_ALTERNATE	8
+#define PS_SOLID	0
+#define PS_DASH	1
+#define PS_DOT	2
+#define PS_DASHDOT	3
+#define PS_DASHDOTDOT	4
+#define PS_NULL	5
+#define PS_USERSTYLE	7
+#define PS_INSIDEFRAME	6
+#define PS_ENDCAP_ROUND	0
+#define PS_ENDCAP_SQUARE	256
+#define PS_ENDCAP_FLAT	512
+#define PS_JOIN_BEVEL	4096
+#define PS_JOIN_MITER	8192
+#define PS_JOIN_ROUND	0
+#define PS_STYLE_MASK	15
+#define PS_ENDCAP_MASK	3840
+#define PS_TYPE_MASK	983040
+#define ALTERNATE	1
+#define WINDING	2
+#define DC_BINNAMES	12
+#define DC_BINS	6
+#define DC_COPIES	18
+#define DC_DRIVER	11
+#define DC_DATATYPE_PRODUCED	21
+#define DC_DUPLEX	7
+#define DC_EMF_COMPLIANT	20
+#define DC_ENUMRESOLUTIONS	13
+#define DC_EXTRA	9
+#define DC_FIELDS	1
+#define DC_FILEDEPENDENCIES	14
+#define DC_MAXEXTENT	5
+#define DC_MINEXTENT	4
+#define DC_ORIENTATION	17
+#define DC_PAPERNAMES	16
+#define DC_PAPERS	2
+#define DC_PAPERSIZE	3
+#define DC_SIZE	8
+#define DC_TRUETYPE	15
+#define DCTT_BITMAP	1
+#define DCTT_DOWNLOAD	2
+#define DCTT_SUBDEV	4
+#define DCTT_DOWNLOAD_OUTLINE 8
+#define DC_VERSION	10
+#define DC_BINADJUST	19
+#define DC_EMF_COMPLIANT	20
+#define DC_DATATYPE_PRODUCED	21
+#define DC_MANUFACTURER	23
+#define DC_MODEL	24
+#define DCBA_FACEUPNONE	0
+#define DCBA_FACEUPCENTER	1
+#define DCBA_FACEUPLEFT	2
+#define DCBA_FACEUPRIGHT	3
+#define DCBA_FACEDOWNNONE	256
+#define DCBA_FACEDOWNCENTER	257
+#define DCBA_FACEDOWNLEFT	258
+#define DCBA_FACEDOWNRIGHT	259
+#define FLOODFILLBORDER 0
+#define FLOODFILLSURFACE 1
+#define ETO_CLIPPED 4
+#define ETO_GLYPH_INDEX 16
+#define ETO_OPAQUE 2
+#define ETO_RTLREADING 128
+#define GDICOMMENT_WINDOWS_METAFILE (-2147483647)
+#define GDICOMMENT_BEGINGROUP 2
+#define GDICOMMENT_ENDGROUP 3
+#define GDICOMMENT_MULTIFORMATS 1073741828
+#define GDICOMMENT_IDENTIFIER 1128875079
+#define AD_COUNTERCLOCKWISE 1
+#define AD_CLOCKWISE 2
+#define RDH_RECTANGLES	1
+#define GCPCLASS_LATIN	1
+#define GCPCLASS_HEBREW	2
+#define GCPCLASS_ARABIC	2
+#define GCPCLASS_NEUTRAL	3
+#define GCPCLASS_LOCALNUMBER	4
+#define GCPCLASS_LATINNUMBER	5
+#define GCPCLASS_LATINNUMERICTERMINATOR	6
+#define GCPCLASS_LATINNUMERICSEPARATOR	7
+#define GCPCLASS_NUMERICSEPARATOR	8
+#define GCPCLASS_PREBOUNDLTR	128
+#define GCPCLASS_PREBOUNDRTL	64
+#define GCPCLASS_POSTBOUNDLTR	32
+#define GCPCLASS_POSTBOUNDRTL	16
+#define GCPGLYPH_LINKBEFORE	0x8000
+#define GCPGLYPH_LINKAFTER	0x4000
+#define DCB_DISABLE 8
+#define DCB_ENABLE 4
+#define DCB_RESET 1
+#define DCB_SET 3
+#define DCB_ACCUMULATE 2
+#define DCB_DIRTY	2
+#define OBJ_BRUSH 2
+#define OBJ_PEN 1
+#define OBJ_PAL 5
+#define OBJ_FONT 6
+#define OBJ_BITMAP 7
+#define OBJ_EXTPEN 11
+#define OBJ_REGION 8
+#define OBJ_DC 3
+#define OBJ_MEMDC 10
+#define OBJ_METAFILE 9
+#define OBJ_METADC 4
+#define OBJ_ENHMETAFILE 13
+#define OBJ_ENHMETADC 12
+#define DRIVERVERSION 0
+#define TECHNOLOGY 2
+#define DT_PLOTTER 0
+#define DT_RASDISPLAY 1
+#define DT_RASPRINTER 2
+#define DT_RASCAMERA 3
+#define DT_CHARSTREAM 4
+#define DT_METAFILE 5
+#define DT_DISPFILE 6
+#define HORZSIZE 4
+#define VERTSIZE 6
+#define HORZRES 8
+#define VERTRES 10
+#define LOGPIXELSX 88
+#define LOGPIXELSY 90
+#define BITSPIXEL 12
+#define PLANES 14
+#define NUMBRUSHES 16
+#define NUMPENS 18
+#define NUMFONTS 22
+#define NUMCOLORS 24
+#define NUMMARKERS 20
+#define ASPECTX 40
+#define ASPECTY 42
+#define ASPECTXY 44
+#define PDEVICESIZE 26
+#define CLIPCAPS 36
+#define SIZEPALETTE 104
+#define NUMRESERVED 106
+#define COLORRES 108
+#define PHYSICALWIDTH 110
+#define PHYSICALHEIGHT 111
+#define PHYSICALOFFSETX 112
+#define PHYSICALOFFSETY 113
+#define SCALINGFACTORX 114
+#define SCALINGFACTORY 115
+#define VREFRESH 116
+#define DESKTOPHORZRES 118
+#define DESKTOPVERTRES 117
+#define BLTALIGNMENT 119
+#define RASTERCAPS 38
+#define RC_BANDING 2
+#define RC_BITBLT 1
+#define RC_BITMAP64 8
+#define RC_DI_BITMAP 128
+#define RC_DIBTODEV 512
+#define RC_FLOODFILL 4096
+#define RC_GDI20_OUTPUT 16
+#define RC_PALETTE 256
+#define RC_SCALING 4
+#define RC_STRETCHBLT 2048
+#define RC_STRETCHDIB 8192
+#define RC_DEVBITS 0x8000
+#define RC_OP_DX_OUTPUT 0x4000
+#define CURVECAPS 28
+#define CC_NONE 0
+#define CC_CIRCLES 1
+#define CC_PIE 2
+#define CC_CHORD 4
+#define CC_ELLIPSES 8
+#define CC_WIDE 16
+#define CC_STYLED 32
+#define CC_WIDESTYLED 64
+#define CC_INTERIORS 128
+#define CC_ROUNDRECT 256
+#define LINECAPS 30
+#define LC_NONE 0
+#define LC_POLYLINE 2
+#define LC_MARKER 4
+#define LC_POLYMARKER 8
+#define LC_WIDE 16
+#define LC_STYLED 32
+#define LC_WIDESTYLED 64
+#define LC_INTERIORS 128
+#define POLYGONALCAPS 32
+#define RC_BANDING 2
+#define RC_BIGFONT 1024
+#define RC_BITBLT 1
+#define RC_BITMAP64 8
+#define RC_DEVBITS 0x8000
+#define RC_DI_BITMAP 128
+#define RC_GDI20_OUTPUT 16
+#define RC_GDI20_STATE 32
+#define RC_NONE 0
+#define RC_OP_DX_OUTPUT 0x4000
+#define RC_PALETTE 256
+#define RC_SAVEBITMAP 64
+#define RC_SCALING 4
+#define PC_NONE 0
+#define PC_POLYGON 1
+#define PC_POLYPOLYGON 256
+#define PC_PATHS 512
+#define PC_RECTANGLE 2
+#define PC_WINDPOLYGON 4
+#define PC_SCANLINE 8
+#define PC_TRAPEZOID 4
+#define PC_WIDE 16
+#define PC_STYLED 32
+#define PC_WIDESTYLED 64
+#define PC_INTERIORS 128
+#define PC_PATHS 512
+#define TEXTCAPS 34
+#define TC_OP_CHARACTER 1
+#define TC_OP_STROKE 2
+#define TC_CP_STROKE 4
+#define TC_CR_90 8
+#define TC_CR_ANY 16
+#define TC_SF_X_YINDEP 32
+#define TC_SA_DOUBLE 64
+#define TC_SA_INTEGER 128
+#define TC_SA_CONTIN 256
+#define TC_EA_DOUBLE 512
+#define TC_IA_ABLE 1024
+#define TC_UA_ABLE 2048
+#define TC_SO_ABLE 4096
+#define TC_RA_ABLE 8192
+#define TC_VA_ABLE 16384
+#define TC_RESERVED 32768
+#define TC_SCROLLBLT 65536
+#define GCP_DBCS 1
+#define GCP_ERROR 0x8000
+#define GCP_CLASSIN 0x80000
+#define GCP_DIACRITIC 256
+#define GCP_DISPLAYZWG 0x400000
+#define GCP_GLYPHSHAPE 16
+#define GCP_JUSTIFY 0x10000
+#define GCP_JUSTIFYIN 0x200000
+#define GCP_KASHIDA 1024
+#define GCP_LIGATE 32
+#define GCP_MAXEXTENT 0x100000
+#define GCP_NEUTRALOVERRIDE 0x2000000
+#define GCP_NUMERICOVERRIDE 0x1000000
+#define GCP_NUMERICSLATIN 0x4000000
+#define GCP_NUMERICSLOCAL 0x8000000
+#define GCP_REORDER 2
+#define GCP_SYMSWAPOFF 0x800000
+#define GCP_USEKERNING 8
+#define FLI_GLYPHS 0x40000
+#define FLI_MASK 0x103b
+#define GGO_METRICS 0
+#define GGO_BITMAP 1
+#define GGO_NATIVE 2
+#define GGO_BEZIER 3
+#define GGO_GRAY2_BITMAP 4
+#define GGO_GRAY4_BITMAP 5
+#define GGO_GRAY8_BITMAP 6
+#define GGO_GLYPH_INDEX 128
+#define GGO_UNHINTED 256
+#define GM_COMPATIBLE 1
+#define GM_ADVANCED 2
+#define MM_ANISOTROPIC 8
+#define MM_HIENGLISH 5
+#define MM_HIMETRIC 3
+#define MM_ISOTROPIC 7
+#define MM_LOENGLISH 4
+#define MM_LOMETRIC 2
+#define MM_TEXT 1
+#define MM_TWIPS 6
+#define MM_MAX_FIXEDSCALE	MM_TWIPS
+#define ABSOLUTE	1
+#define RELATIVE	2
+#define PC_EXPLICIT 2
+#define PC_NOCOLLAPSE 4
+#define PC_RESERVED 1
+#define CLR_NONE 0xffffffff
+#define CLR_INVALID CLR_NONE
+#define CLR_DEFAULT 0xff000000
+#define PT_MOVETO 6
+#define PT_LINETO 2
+#define PT_BEZIERTO 4
+#define PT_CLOSEFIGURE 1
+#define TT_AVAILABLE 1
+#define TT_ENABLED 2
+#define BLACK_BRUSH 4
+#define DKGRAY_BRUSH 3
+#define GRAY_BRUSH 2
+#define HOLLOW_BRUSH 5
+#define LTGRAY_BRUSH 1
+#define NULL_BRUSH 5
+#define WHITE_BRUSH 0
+#define BLACK_PEN 7
+#define NULL_PEN 8
+#define WHITE_PEN 6
+#define ANSI_FIXED_FONT 11
+#define ANSI_VAR_FONT 12
+#define DEVICE_DEFAULT_FONT 14
+#define DEFAULT_GUI_FONT 17
+#define OEM_FIXED_FONT 10
+#define SYSTEM_FONT 13
+#define SYSTEM_FIXED_FONT 16
+#define DEFAULT_PALETTE 15
+#define SYSPAL_NOSTATIC 2
+#define SYSPAL_STATIC 1
+#define SYSPAL_ERROR 0
+#define TA_BASELINE 24
+#define TA_BOTTOM 8
+#define TA_TOP 0
+#define TA_CENTER 6
+#define TA_LEFT 0
+#define TA_RIGHT 2
+#define TA_RTLREADING 256
+#define TA_NOUPDATECP 0
+#define TA_UPDATECP 1
+#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING)
+#define VTA_BASELINE 24
+#define VTA_CENTER 6
+#define VTA_LEFT TA_BOTTOM
+#define VTA_RIGHT TA_TOP
+#define VTA_BOTTOM TA_RIGHT
+#define VTA_TOP TA_LEFT
+#define MWT_IDENTITY 1
+#define MWT_LEFTMULTIPLY 2
+#define MWT_RIGHTMULTIPLY 3
+#define OPAQUE 2
+#define TRANSPARENT 1
+#define BLACKONWHITE 1
+#define WHITEONBLACK 2
+#define COLORONCOLOR 3
+#define HALFTONE 4
+#define MAXSTRETCHBLTMODE 4
+#define STRETCH_ANDSCANS 1
+#define STRETCH_DELETESCANS 3
+#define STRETCH_HALFTONE 4
+#define STRETCH_ORSCANS 2
+#define TCI_SRCCHARSET 1
+#define TCI_SRCCODEPAGE 2
+#define TCI_SRCFONTSIG 3
+#define ICM_ON 2
+#define ICM_OFF 1
+#define ICM_QUERY 3
+#define NEWFRAME	1
+#define ABORTDOC	2
+#define NEXTBAND	3
+#define SETCOLORTABLE	4
+#define GETCOLORTABLE	5
+#define FLUSHOUTPUT	6
+#define DRAFTMODE	7
+#define QUERYESCSUPPORT	8
+#define SETABORTPROC	9
+#define STARTDOC	10
+#define ENDDOC	11
+#define GETPHYSPAGESIZE	12
+#define GETPRINTINGOFFSET	13
+#define GETSCALINGFACTOR	14
+#define MFCOMMENT	15
+#define GETPENWIDTH	16
+#define SETCOPYCOUNT	17
+#define SELECTPAPERSOURCE	18
+#define DEVICEDATA	19
+#define PASSTHROUGH	19
+#define GETTECHNOLGY	20
+#define GETTECHNOLOGY	20
+#define SETLINECAP	21
+#define SETLINEJOIN	22
+#define SETMITERLIMIT	23
+#define BANDINFO	24
+#define DRAWPATTERNRECT	25
+#define GETVECTORPENSIZE	26
+#define GETVECTORBRUSHSIZE	27
+#define ENABLEDUPLEX	28
+#define GETSETPAPERBINS	29
+#define GETSETPRINTORIENT	30
+#define ENUMPAPERBINS	31
+#define SETDIBSCALING	32
+#define EPSPRINTING	33
+#define ENUMPAPERMETRICS	34
+#define GETSETPAPERMETRICS	35
+#define POSTSCRIPT_DATA	37
+#define POSTSCRIPT_IGNORE	38
+#define MOUSETRAILS	39
+#define GETDEVICEUNITS	42
+#define GETEXTENDEDTEXTMETRICS	256
+#define GETEXTENTTABLE	257
+#define GETPAIRKERNTABLE	258
+#define GETTRACKKERNTABLE	259
+#define EXTTEXTOUT	512
+#define GETFACENAME	513
+#define DOWNLOADFACE	514
+#define ENABLERELATIVEWIDTHS	768
+#define ENABLEPAIRKERNING	769
+#define SETKERNTRACK	770
+#define SETALLJUSTVALUES	771
+#define SETCHARSET	772
+#define STRETCHBLT	2048
+#define GETSETSCREENPARAMS	3072
+#define QUERYDIBSUPPORT	3073
+#define BEGIN_PATH	4096
+#define CLIP_TO_PATH	4097
+#define END_PATH	4098
+#define EXT_DEVICE_CAPS	4099
+#define RESTORE_CTM	4100
+#define SAVE_CTM	4101
+#define SET_ARC_DIRECTION	4102
+#define SET_BACKGROUND_COLOR	4103
+#define SET_POLY_MODE	4104
+#define SET_SCREEN_ANGLE	4105
+#define SET_SPREAD	4106
+#define TRANSFORM_CTM	4107
+#define SET_CLIP_BOX	4108
+#define SET_BOUNDS	4109
+#define SET_MIRROR_MODE	4110
+#define OPENCHANNEL	4110
+#define DOWNLOADHEADER	4111
+#define CLOSECHANNEL	4112
+#define POSTSCRIPT_PASSTHROUGH	4115
+#define ENCAPSULATED_POSTSCRIPT	4116
+#define QDI_SETDIBITS	1
+#define QDI_GETDIBITS	2
+#define QDI_DIBTOSCREEN	4
+#define QDI_STRETCHDIB	8
+#define SP_NOTREPORTED	0x4000
+#define PR_JOBSTATUS	0
+#define ASPECT_FILTERING	1
+#define BS_SOLID	0
+#define BS_NULL	1
+#define BS_HOLLOW	1
+#define BS_HATCHED	2
+#define BS_PATTERN	3
+#define BS_INDEXED	4
+#define BS_DIBPATTERN	5
+#define BS_DIBPATTERNPT	6
+#define BS_PATTERN8X8	7
+#define BS_DIBPATTERN8X8	8
+#define LCS_CALIBRATED_RGB	0
+#define LCS_DEVICE_RGB	1
+#define LCS_DEVICE_CMYK	2
+#define LCS_GM_BUSINESS	1
+#define LCS_GM_GRAPHICS	2
+#define LCS_GM_IMAGES	4
+#define RASTER_FONTTYPE	1
+#define DEVICE_FONTTYPE	2
+#define TRUETYPE_FONTTYPE	4
+#define DMORIENT_PORTRAIT   1
+#define DMORIENT_LANDSCAPE  2
+#define DMPAPER_FIRST	1
+#define DMPAPER_LETTER	1
+#define DMPAPER_LETTERSMALL	2
+#define DMPAPER_TABLOID	3
+#define DMPAPER_LEDGER	4
+#define DMPAPER_LEGAL	5
+#define DMPAPER_STATEMENT	6
+#define DMPAPER_EXECUTIVE	7
+#define DMPAPER_A3	8
+#define DMPAPER_A4	9
+#define DMPAPER_A4SMALL	10
+#define DMPAPER_A5	11
+#define DMPAPER_B4	12
+#define DMPAPER_B5	13
+#define DMPAPER_FOLIO	14
+#define DMPAPER_QUARTO	15
+#define DMPAPER_10X14	16
+#define DMPAPER_11X17	17
+#define DMPAPER_NOTE	18
+#define DMPAPER_ENV_9	19
+#define DMPAPER_ENV_10	20
+#define DMPAPER_ENV_11	21
+#define DMPAPER_ENV_12	22
+#define DMPAPER_ENV_14	23
+#define DMPAPER_CSHEET	24
+#define DMPAPER_DSHEET	25
+#define DMPAPER_ESHEET	26
+#define DMPAPER_ENV_DL	27
+#define DMPAPER_ENV_C5	28
+#define DMPAPER_ENV_C3	29
+#define DMPAPER_ENV_C4	30
+#define DMPAPER_ENV_C6	31
+#define DMPAPER_ENV_C65	32
+#define DMPAPER_ENV_B4	33
+#define DMPAPER_ENV_B5	34
+#define DMPAPER_ENV_B6	35
+#define DMPAPER_ENV_ITALY	36
+#define DMPAPER_ENV_MONARCH	37
+#define DMPAPER_ENV_PERSONAL	38
+#define DMPAPER_FANFOLD_US	39
+#define DMPAPER_FANFOLD_STD_GERMAN	40
+#define DMPAPER_FANFOLD_LGL_GERMAN	41
+#define DMPAPER_ISO_B4	42
+#define DMPAPER_JAPANESE_POSTCARD	43
+#define DMPAPER_9X11	44
+#define DMPAPER_10X11	45
+#define DMPAPER_15X11	46
+#define DMPAPER_ENV_INVITE	47
+#define DMPAPER_RESERVED_48	48
+#define DMPAPER_RESERVED_49	49
+#define DMPAPER_LETTER_EXTRA	50
+#define DMPAPER_LEGAL_EXTRA	51
+#define DMPAPER_TABLOID_EXTRA	52
+#define DMPAPER_A4_EXTRA	53
+#define DMPAPER_LETTER_TRANSVERSE	54
+#define DMPAPER_A4_TRANSVERSE	55
+#define DMPAPER_LETTER_EXTRA_TRANSVERSE	56
+#define DMPAPER_A_PLUS	57
+#define DMPAPER_B_PLUS	58
+#define DMPAPER_LETTER_PLUS	59
+#define DMPAPER_A4_PLUS	60
+#define DMPAPER_A5_TRANSVERSE	61
+#define DMPAPER_B5_TRANSVERSE	62
+#define DMPAPER_A3_EXTRA	63
+#define DMPAPER_A5_EXTRA	64
+#define DMPAPER_B5_EXTRA	65
+#define DMPAPER_A2	66
+#define DMPAPER_A3_TRANSVERSE	67
+#define DMPAPER_A3_EXTRA_TRANSVERSE	68
+#define DMPAPER_LAST	68
+#define DMPAPER_USER	256
+#define DMBIN_FIRST	1
+#define DMBIN_UPPER	1
+#define DMBIN_ONLYONE	1
+#define DMBIN_LOWER	2
+#define DMBIN_MIDDLE	3
+#define DMBIN_MANUAL	4
+#define DMBIN_ENVELOPE	5
+#define DMBIN_ENVMANUAL	6
+#define DMBIN_AUTO	7
+#define DMBIN_TRACTOR	8
+#define DMBIN_SMALLFMT	9
+#define DMBIN_LARGEFMT	10
+#define DMBIN_LARGECAPACITY	11
+#define DMBIN_CASSETTE	14
+#define DMBIN_FORMSOURCE	15
+#define DMBIN_LAST	15
+#define DMBIN_USER	256
+#define DMRES_DRAFT	(-1)
+#define DMRES_LOW	(-2)
+#define DMRES_MEDIUM	(-3)
+#define DMRES_HIGH	(-4)
+#define DMCOLOR_MONOCHROME	1
+#define DMCOLOR_COLOR	2
+#define DMDUP_SIMPLEX	1
+#define DMDUP_VERTICAL	2
+#define DMDUP_HORIZONTAL	3
+#define DMTT_BITMAP	1
+#define DMTT_DOWNLOAD	2
+#define DMTT_SUBDEV	3
+#define DMTT_DOWNLOAD_OUTLINE	4
+#define DMCOLLATE_FALSE	0
+#define DMCOLLATE_TRUE	1
+#define DM_GRAYSCALE	1
+#define DM_INTERLACED	2
+#define DM_UPDATE	1
+#define DM_COPY	2
+#define DM_PROMPT	4
+#define DM_MODIFY	8
+#define DM_IN_BUFFER	DM_MODIFY
+#define DM_IN_PROMPT	DM_PROMPT
+#define DM_OUT_BUFFER	DM_COPY
+#define DM_OUT_DEFAULT	DM_UPDATE
+#define DM_ORIENTATION 1
+#define DM_PAPERSIZE 2
+#define DM_PAPERLENGTH 4
+#define DM_PAPERWIDTH 8
+#define DM_SCALE 16
+#define DM_COPIES 256
+#define DM_DEFAULTSOURCE 512
+#define DM_PRINTQUALITY 1024
+#define DM_COLOR 2048
+#define DM_DUPLEX 4096
+#define DM_YRESOLUTION 8192
+#define DM_TTOPTION 16384
+#define DM_COLLATE 32768
+#define DM_FORMNAME 65536
+#define DM_LOGPIXELS 0x20000
+#define DM_BITSPERPEL 0x40000
+#define DM_PELSWIDTH 0x80000
+#define DM_PELSHEIGHT 0x100000
+#define DM_DISPLAYFLAGS 0x200000
+#define DM_DISPLAYFREQUENCY 0x400000
+#define DM_ICMMETHOD 0x800000
+#define DM_ICMINTENT 0x1000000
+#define DM_MEDIATYPE 0x2000000
+#define DM_DITHERTYPE 0x4000000
+#define DMICMMETHOD_NONE	1
+#define DMICMMETHOD_SYSTEM	2
+#define DMICMMETHOD_DRIVER	3
+#define DMICMMETHOD_DEVICE	4
+#define DMICMMETHOD_USER	256
+#define DMICM_SATURATE	1
+#define DMICM_CONTRAST	2
+#define DMICM_COLORMETRIC	3
+#define DMICM_USER	256
+#define DMMEDIA_STANDARD	1
+#define DMMEDIA_TRANSPARENCY	2
+#define DMMEDIA_GLOSSY	3
+#define DMMEDIA_USER	256
+#define DMDITHER_NONE	1
+#define DMDITHER_COARSE	2
+#define DMDITHER_FINE	3
+#define DMDITHER_LINEART	4
+#define DMDITHER_ERRORDIFFUSION	5
+#define DMDITHER_RESERVED6	6
+#define DMDITHER_RESERVED7	7
+#define DMDITHER_RESERVED8	8
+#define DMDITHER_RESERVED9	9
+#define DMDITHER_GRAYSCALE	10
+#define DMDITHER_USER	256
+#define GDI_ERROR 0xFFFFFFFF
+#define HGDI_ERROR ((HANDLE)GDI_ERROR)
+#define TMPF_FIXED_PITCH 1
+#define TMPF_VECTOR 2
+#define TMPF_TRUETYPE 4
+#define TMPF_DEVICE 8
+#define NTM_ITALIC 1
+#define NTM_BOLD 32
+#define NTM_REGULAR 64
+#define TT_POLYGON_TYPE 24
+#define TT_PRIM_LINE 1
+#define TT_PRIM_QSPLINE 2
+#define FONTMAPPER_MAX 10
+#define ENHMETA_STOCK_OBJECT 0x80000000
+#define WGL_FONT_LINES 0
+#define WGL_FONT_POLYGONS 1
+#define LPD_DOUBLEBUFFER 1
+#define LPD_STEREO 2
+#define LPD_SUPPORT_GDI 16
+#define LPD_SUPPORT_OPENGL 32
+#define LPD_SHARE_DEPTH 64
+#define LPD_SHARE_STENCIL 128
+#define LPD_SHARE_ACCUM 256
+#define LPD_SWAP_EXCHANGE 512
+#define LPD_SWAP_COPY 1024
+#define LPD_TRANSPARENT 4096
+#define LPD_TYPE_RGBA 0
+#define LPD_TYPE_COLORINDEX 1
+#define WGL_SWAP_MAIN_PLANE 1
+#define WGL_SWAP_OVERLAY1 2
+#define WGL_SWAP_OVERLAY2 4
+#define WGL_SWAP_OVERLAY3 8
+#define WGL_SWAP_OVERLAY4 16
+#define WGL_SWAP_OVERLAY5 32
+#define WGL_SWAP_OVERLAY6 64
+#define WGL_SWAP_OVERLAY7 128
+#define WGL_SWAP_OVERLAY8 256
+#define WGL_SWAP_OVERLAY9 512
+#define WGL_SWAP_OVERLAY10 1024
+#define WGL_SWAP_OVERLAY11 2048
+#define WGL_SWAP_OVERLAY12 4096
+#define WGL_SWAP_OVERLAY13 8192
+#define WGL_SWAP_OVERLAY14 16384
+#define WGL_SWAP_OVERLAY15 32768
+#define WGL_SWAP_UNDERLAY1 65536
+#define WGL_SWAP_UNDERLAY2 0x20000
+#define WGL_SWAP_UNDERLAY3 0x40000
+#define WGL_SWAP_UNDERLAY4 0x80000
+#define WGL_SWAP_UNDERLAY5 0x100000
+#define WGL_SWAP_UNDERLAY6 0x200000
+#define WGL_SWAP_UNDERLAY7 0x400000
+#define WGL_SWAP_UNDERLAY8 0x800000
+#define WGL_SWAP_UNDERLAY9 0x1000000
+#define WGL_SWAP_UNDERLAY10 0x2000000
+#define WGL_SWAP_UNDERLAY11 0x4000000
+#define WGL_SWAP_UNDERLAY12 0x8000000
+#define WGL_SWAP_UNDERLAY13 0x10000000
+#define WGL_SWAP_UNDERLAY14 0x20000000
+#define WGL_SWAP_UNDERLAY15 0x40000000
+#define AC_SRC_OVER 0
+#define LAYOUT_RTL 1
+#define LAYOUT_BITMAPORIENTATIONPRESERVED 8
+
+#ifndef RC_INVOKED
+typedef struct _ABC {
+	int abcA;
+	UINT abcB;
+	int abcC;
+} ABC,*LPABC;
+typedef struct _ABCFLOAT {
+	FLOAT abcfA;
+	FLOAT abcfB;
+	FLOAT abcfC;
+} ABCFLOAT,*LPABCFLOAT;
+typedef struct tagBITMAP {
+	LONG	bmType;
+	LONG	bmWidth;
+	LONG	bmHeight;
+	LONG	bmWidthBytes;
+	WORD	bmPlanes;
+	WORD	bmBitsPixel;
+	LPVOID	bmBits;
+} BITMAP,*PBITMAP,*LPBITMAP;
+typedef struct tagBITMAPCOREHEADER {
+	DWORD	bcSize;
+	WORD	bcWidth;
+	WORD	bcHeight;
+	WORD	bcPlanes;
+	WORD	bcBitCount;
+} BITMAPCOREHEADER,*LPBITMAPCOREHEADER,*PBITMAPCOREHEADER;
+#pragma pack(push,1)
+typedef struct tagRGBTRIPLE {
+	BYTE rgbtBlue;
+	BYTE rgbtGreen;
+	BYTE rgbtRed;
+} RGBTRIPLE;
+#pragma pack(pop)
+#pragma pack(push,2)
+typedef struct tagBITMAPFILEHEADER {
+	WORD	bfType;
+	DWORD	bfSize;
+	WORD	bfReserved1;
+	WORD	bfReserved2;
+	DWORD	bfOffBits;
+} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;
+#pragma pack(pop)
+typedef struct _BITMAPCOREINFO {
+	BITMAPCOREHEADER	bmciHeader;
+	RGBTRIPLE	bmciColors[1];
+} BITMAPCOREINFO,*LPBITMAPCOREINFO,*PBITMAPCOREINFO;
+typedef struct tagBITMAPINFOHEADER{
+	DWORD	biSize;
+	LONG	biWidth;
+	LONG	biHeight;
+	WORD	biPlanes;
+	WORD	biBitCount;
+	DWORD	biCompression;
+	DWORD	biSizeImage;
+	LONG	biXPelsPerMeter;
+	LONG	biYPelsPerMeter;
+	DWORD	biClrUsed;
+	DWORD	biClrImportant;
+} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;
+typedef struct tagRGBQUAD {
+	BYTE	rgbBlue;
+	BYTE	rgbGreen;
+	BYTE	rgbRed;
+	BYTE	rgbReserved;
+} RGBQUAD;
+typedef struct tagBITMAPINFO {
+	BITMAPINFOHEADER bmiHeader;
+	RGBQUAD bmiColors[1];
+} BITMAPINFO,*LPBITMAPINFO,*PBITMAPINFO;
+typedef long FXPT16DOT16,*LPFXPT16DOT16;
+typedef long FXPT2DOT30,*LPFXPT2DOT30;
+typedef struct tagCIEXYZ {
+	FXPT2DOT30 ciexyzX;
+	FXPT2DOT30 ciexyzY;
+	FXPT2DOT30 ciexyzZ;
+} CIEXYZ,*LPCIEXYZ;
+typedef struct tagCIEXYZTRIPLE {
+	CIEXYZ ciexyzRed;
+	CIEXYZ ciexyzGreen;
+	CIEXYZ ciexyzBlue;
+} CIEXYZTRIPLE,*LPCIEXYZTRIPLE;
+typedef struct {
+	DWORD	bV4Size;
+	LONG	bV4Width;
+	LONG	bV4Height;
+	WORD	bV4Planes;
+	WORD	bV4BitCount;
+	DWORD	bV4V4Compression;
+	DWORD	bV4SizeImage;
+	LONG	bV4XPelsPerMeter;
+	LONG	bV4YPelsPerMeter;
+	DWORD	bV4ClrUsed;
+	DWORD	bV4ClrImportant;
+	DWORD	bV4RedMask;
+	DWORD	bV4GreenMask;
+	DWORD	bV4BlueMask;
+	DWORD	bV4AlphaMask;
+	DWORD	bV4CSType;
+	CIEXYZTRIPLE bV4Endpoints;
+	DWORD	bV4GammaRed;
+	DWORD	bV4GammaGreen;
+	DWORD	bV4GammaBlue;
+} BITMAPV4HEADER,*LPBITMAPV4HEADER,*PBITMAPV4HEADER;
+typedef struct tagFONTSIGNATURE {
+	DWORD	fsUsb[4];
+	DWORD	fsCsb[2];
+} FONTSIGNATURE,*LPFONTSIGNATURE;
+typedef struct {
+	UINT ciCharset;
+	UINT ciACP;
+	FONTSIGNATURE fs;
+} CHARSETINFO,*LPCHARSETINFO;
+typedef struct  tagCOLORADJUSTMENT {
+	WORD	caSize;
+	WORD	caFlags;
+	WORD	caIlluminantIndex;
+	WORD	caRedGamma;
+	WORD	caGreenGamma;
+	WORD	caBlueGamma;
+	WORD	caReferenceBlack;
+	WORD	caReferenceWhite;
+	SHORT	caContrast;
+	SHORT	caBrightness;
+	SHORT	caColorfulness;
+	SHORT	caRedGreenTint;
+} COLORADJUSTMENT,*LPCOLORADJUSTMENT;
+typedef struct _devicemodeA {
+	BYTE dmDeviceName[CCHDEVICENAME];
+	WORD dmSpecVersion;
+	WORD dmDriverVersion;
+	WORD dmSize;
+	WORD dmDriverExtra;
+	DWORD dmFields;
+	short dmOrientation;
+	short dmPaperSize;
+	short dmPaperLength;
+	short dmPaperWidth;
+	short dmScale;
+	short dmCopies;
+	short dmDefaultSource;
+	short dmPrintQuality;
+	short dmColor;
+	short dmDuplex;
+	short dmYResolution;
+	short dmTTOption;
+	short dmCollate;
+	BYTE dmFormName[CCHFORMNAME];
+	WORD dmLogPixels;
+	DWORD dmBitsPerPel;
+	DWORD dmPelsWidth;
+	DWORD dmPelsHeight;
+	DWORD dmDisplayFlags;
+	DWORD dmDisplayFrequency;
+	DWORD dmICMMethod;
+	DWORD dmICMIntent;
+	DWORD dmMediaType;
+	DWORD dmDitherType;
+	DWORD dmICCManufacturer;
+	DWORD dmICCModel;
+} DEVMODEA,*LPDEVMODEA,*PDEVMODEA;
+typedef struct _devicemodeW {
+	WCHAR dmDeviceName[CCHDEVICENAME];
+	WORD dmSpecVersion;
+	WORD dmDriverVersion;
+	WORD dmSize;
+	WORD dmDriverExtra;
+	DWORD dmFields;
+	short dmOrientation;
+	short dmPaperSize;
+	short dmPaperLength;
+	short dmPaperWidth;
+	short dmScale;
+	short dmCopies;
+	short dmDefaultSource;
+	short dmPrintQuality;
+	short dmColor;
+	short dmDuplex;
+	short dmYResolution;
+	short dmTTOption;
+	short dmCollate;
+	WCHAR dmFormName[CCHFORMNAME];
+	WORD dmLogPixels;
+	DWORD dmBitsPerPel;
+	DWORD dmPelsWidth;
+	DWORD dmPelsHeight;
+	DWORD dmDisplayFlags;
+	DWORD dmDisplayFrequency;
+	DWORD dmICMMethod;
+	DWORD dmICMIntent;
+	DWORD dmMediaType;
+	DWORD dmDitherType;
+	DWORD dmICCManufacturer;
+	DWORD dmICCModel;
+} DEVMODEW,*LPDEVMODEW,*PDEVMODEW;
+typedef struct tagDIBSECTION {
+	BITMAP dsBm;
+	BITMAPINFOHEADER dsBmih;
+	DWORD dsBitfields[3];
+	HANDLE dshSection;
+	DWORD dsOffset;
+} DIBSECTION;
+typedef struct _DOCINFOA {
+	int cbSize;
+	LPCTSTR lpszDocName;
+	LPCTSTR lpszOutput;
+	LPCTSTR lpszDatatype;
+	DWORD fwType;
+} DOCINFOA,*LPDOCINFOA;
+typedef struct _DOCINFOW {
+	int cbSize;
+	LPCWSTR lpszDocName;
+	LPCWSTR lpszOutput;
+	LPCWSTR lpszDatatype;
+	DWORD fwType;
+} DOCINFOW,*LPDOCINFOW;
+typedef struct tagEMR {
+	DWORD iType;
+	DWORD nSize;
+} EMR,*PEMR;
+typedef struct tagEMRANGLEARC {
+	EMR emr;
+	POINTL ptlCenter;
+	DWORD nRadius;
+	FLOAT eStartAngle;
+	FLOAT eSweepAngle;
+} EMRANGLEARC,*PEMRANGLEARC;
+typedef struct tagEMRARC {
+	EMR emr;
+	RECTL rclBox;
+	POINTL ptlStart;
+	POINTL ptlEnd;
+} EMRARC,*PEMRARC,EMRARCTO,*PEMRARCTO,EMRCHORD,*PEMRCHORD,EMRPIE,*PEMRPIE;
+typedef struct  _XFORM {
+	FLOAT eM11;
+	FLOAT eM12;
+	FLOAT eM21;
+	FLOAT eM22;
+	FLOAT eDx;
+	FLOAT eDy;
+} XFORM,*LPXFORM;
+typedef struct tagEMRBITBLT {
+	EMR emr;
+	RECTL rclBounds;
+	LONG xDest;
+	LONG yDest;
+	LONG cxDest;
+	LONG cyDest;
+	DWORD dwRop;
+	LONG xSrc;
+	LONG ySrc;
+	XFORM xformSrc;
+	COLORREF crBkColorSrc;
+	DWORD iUsageSrc;
+	DWORD offBmiSrc;
+	DWORD offBitsSrc;
+	DWORD cbBitsSrc;
+} EMRBITBLT,*PEMRBITBLT;
+typedef struct tagLOGBRUSH {
+	UINT lbStyle;
+	COLORREF lbColor;
+	LONG lbHatch;
+} LOGBRUSH,*LPLOGBRUSH;
+typedef LOGBRUSH PATTERN,*PPATTERN,*LPPATTERN;
+typedef struct tagEMRCREATEBRUSHINDIRECT {
+	EMR emr;
+	DWORD ihBrush;
+	LOGBRUSH lb;
+} EMRCREATEBRUSHINDIRECT,*PEMRCREATEBRUSHINDIRECT;
+typedef LONG LCSCSTYPE;
+typedef LONG LCSGAMUTMATCH;
+typedef struct tagLOGCOLORSPACEA {
+	DWORD lcsSignature;
+	DWORD lcsVersion;
+	DWORD lcsSize;
+	LCSCSTYPE lcsCSType;
+	LCSGAMUTMATCH lcsIntent;
+	CIEXYZTRIPLE lcsEndpoints;
+	DWORD lcsGammaRed;
+	DWORD lcsGammaGreen;
+	DWORD lcsGammaBlue;
+	CHAR lcsFilename[MAX_PATH];
+} LOGCOLORSPACEA,*LPLOGCOLORSPACEA;
+typedef struct tagLOGCOLORSPACEW {
+	DWORD lcsSignature;
+	DWORD lcsVersion;
+	DWORD lcsSize;
+	LCSCSTYPE lcsCSType;
+	LCSGAMUTMATCH lcsIntent;
+	CIEXYZTRIPLE lcsEndpoints;
+	DWORD lcsGammaRed;
+	DWORD lcsGammaGreen;
+	DWORD lcsGammaBlue;
+	WCHAR lcsFilename[MAX_PATH];
+} LOGCOLORSPACEW,*LPLOGCOLORSPACEW;
+typedef struct tagEMRCREATECOLORSPACE {
+	EMR emr;
+	DWORD ihCS;
+	LOGCOLORSPACEW lcs;
+} EMRCREATECOLORSPACE,*PEMRCREATECOLORSPACE;
+typedef struct tagEMRCREATEDIBPATTERNBRUSHPT {
+	EMR emr;
+	DWORD ihBrush;
+	DWORD iUsage;
+	DWORD offBmi;
+	DWORD cbBmi;
+	DWORD offBits;
+	DWORD cbBits;
+} EMRCREATEDIBPATTERNBRUSHPT,*PEMRCREATEDIBPATTERNBRUSHPT;
+typedef struct tagEMRCREATEMONOBRUSH {
+	EMR emr;
+	DWORD ihBrush;
+	DWORD iUsage;
+	DWORD offBmi;
+	DWORD cbBmi;
+	DWORD offBits;
+	DWORD cbBits;
+} EMRCREATEMONOBRUSH,*PEMRCREATEMONOBRUSH;
+typedef struct tagPALETTEENTRY {
+	BYTE peRed;
+	BYTE peGreen;
+	BYTE peBlue;
+	BYTE peFlags;
+} PALETTEENTRY,*LPPALETTEENTRY,*PPALETTEENTRY;
+typedef struct tagLOGPALETTE {
+	WORD palVersion;
+	WORD palNumEntries;
+	PALETTEENTRY palPalEntry[1];
+} LOGPALETTE,*NPLOGPALETTE,*PLOGPALETTE,*LPLOGPALETTE;
+typedef struct tagEMRCREATEPALETTE {
+	EMR emr;
+	DWORD ihPal;
+	LOGPALETTE lgpl;
+} EMRCREATEPALETTE,*PEMRCREATEPALETTE;
+typedef struct tagLOGPEN {
+	UINT lopnStyle;
+	POINT lopnWidth;
+	COLORREF lopnColor;
+} LOGPEN,*LPLOGPEN;
+typedef struct tagEMRCREATEPEN {
+	EMR emr;
+	DWORD ihPen;
+	LOGPEN lopn;
+} EMRCREATEPEN,*PEMRCREATEPEN;
+typedef struct tagEMRELLIPSE {
+	EMR emr;
+	RECTL rclBox;
+} EMRELLIPSE,*PEMRELLIPSE,EMRRECTANGLE,*PEMRRECTANGLE;
+typedef struct tagEMREOF {
+	EMR emr;
+	DWORD nPalEntries;
+	DWORD offPalEntries;
+	DWORD nSizeLast;
+} EMREOF,*PEMREOF;
+typedef struct tagEMREXCLUDECLIPRECT {
+	EMR emr;
+	RECTL rclClip;
+} EMREXCLUDECLIPRECT,*PEMREXCLUDECLIPRECT,EMRINTERSECTCLIPRECT,*PEMRINTERSECTCLIPRECT;
+typedef struct tagPANOSE {
+	BYTE bFamilyType;
+	BYTE bSerifStyle;
+	BYTE bWeight;
+	BYTE bProportion;
+	BYTE bContrast;
+	BYTE bStrokeVariation;
+	BYTE bArmStyle;
+	BYTE bLetterform;
+	BYTE bMidline;
+	BYTE bXHeight;
+} PANOSE;
+typedef struct tagLOGFONTA {
+	LONG	lfHeight;
+	LONG	lfWidth;
+	LONG	lfEscapement;
+	LONG	lfOrientation;
+	LONG	lfWeight;
+	BYTE	lfItalic;
+	BYTE	lfUnderline;
+	BYTE	lfStrikeOut;
+	BYTE	lfCharSet;
+	BYTE	lfOutPrecision;
+	BYTE	lfClipPrecision;
+	BYTE	lfQuality;
+	BYTE	lfPitchAndFamily;
+	CHAR	lfFaceName[LF_FACESIZE];
+} LOGFONTA,*PLOGFONTA,*LPLOGFONTA;
+typedef struct tagLOGFONTW {
+	LONG	lfHeight;
+	LONG	lfWidth;
+	LONG	lfEscapement;
+	LONG	lfOrientation;
+	LONG	lfWeight;
+	BYTE	lfItalic;
+	BYTE	lfUnderline;
+	BYTE	lfStrikeOut;
+	BYTE	lfCharSet;
+	BYTE	lfOutPrecision;
+	BYTE	lfClipPrecision;
+	BYTE	lfQuality;
+	BYTE	lfPitchAndFamily;
+	WCHAR	lfFaceName[LF_FACESIZE];
+} LOGFONTW,*PLOGFONTW,*LPLOGFONTW;
+typedef struct tagEXTLOGFONTA {
+	LOGFONTA	elfLogFont;
+	BYTE	elfFullName[LF_FULLFACESIZE];
+	BYTE	elfStyle[LF_FACESIZE];
+	DWORD	elfVersion;
+	DWORD	elfStyleSize;
+	DWORD	elfMatch;
+	DWORD	elfReserved;
+	BYTE	elfVendorId[ELF_VENDOR_SIZE];
+	DWORD	elfCulture;
+	PANOSE	elfPanose;
+} EXTLOGFONTA,*PEXTLOGFONTA,*LPEXTLOGFONTA;
+typedef struct tagEXTLOGFONTW {
+	LOGFONTW	elfLogFont;
+	WCHAR	elfFullName[LF_FULLFACESIZE];
+	WCHAR	elfStyle[LF_FACESIZE];
+	DWORD	elfVersion;
+	DWORD	elfStyleSize;
+	DWORD	elfMatch;
+	DWORD	elfReserved;
+	BYTE	elfVendorId[ELF_VENDOR_SIZE];
+	DWORD	elfCulture;
+	PANOSE	elfPanose;
+} EXTLOGFONTW,*PEXTLOGFONTW,*LPEXTLOGFONTW;
+typedef struct tagEMREXTCREATEFONTINDIRECTW {
+	EMR emr;
+	DWORD ihFont;
+	EXTLOGFONTW elfw;
+} EMREXTCREATEFONTINDIRECTW,*PEMREXTCREATEFONTINDIRECTW;
+typedef struct tagEXTLOGPEN {
+	UINT elpPenStyle;
+	UINT elpWidth;
+	UINT elpBrushStyle;
+	COLORREF elpColor;
+	LONG elpHatch;
+	DWORD elpNumEntries;
+	DWORD elpStyleEntry[1];
+} EXTLOGPEN,*PEXTLOGPEN,*LPEXTLOGPEN;
+typedef struct tagEMREXTCREATEPEN {
+	EMR emr;
+	DWORD ihPen;
+	DWORD offBmi;
+	DWORD cbBmi;
+	DWORD offBits;
+	DWORD cbBits;
+	EXTLOGPEN elp;
+} EMREXTCREATEPEN,*PEMREXTCREATEPEN;
+typedef struct tagEMREXTFLOODFILL {
+	EMR emr;
+	POINTL ptlStart;
+	COLORREF crColor;
+	DWORD iMode;
+} EMREXTFLOODFILL,*PEMREXTFLOODFILL;
+typedef struct tagEMREXTSELECTCLIPRGN {
+	EMR emr;
+	DWORD cbRgnData;
+	DWORD iMode;
+	BYTE RgnData[1];
+} EMREXTSELECTCLIPRGN,*PEMREXTSELECTCLIPRGN;
+typedef struct tagEMRTEXT {
+	POINTL ptlReference;
+	DWORD nChars;
+	DWORD offString;
+	DWORD fOptions;
+	RECTL rcl;
+	DWORD offDx;
+} EMRTEXT,*PEMRTEXT;
+typedef struct tagEMREXTTEXTOUTA {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD iGraphicsMode;
+	FLOAT exScale;
+	FLOAT eyScale;
+	EMRTEXT emrtext;
+} EMREXTTEXTOUTA,*PEMREXTTEXTOUTA,EMREXTTEXTOUTW,*PEMREXTTEXTOUTW;
+typedef struct tagEMRFILLPATH {
+	EMR emr;
+	RECTL rclBounds;
+} EMRFILLPATH,*PEMRFILLPATH,EMRSTROKEANDFILLPATH,*PEMRSTROKEANDFILLPATH,EMRSTROKEPATH,*PEMRSTROKEPATH;
+typedef struct tagEMRFILLRGN {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cbRgnData;
+	DWORD ihBrush;
+	BYTE RgnData[1];
+} EMRFILLRGN,*PEMRFILLRGN;
+typedef struct tagEMRFORMAT   {
+	DWORD dSignature;
+	DWORD nVersion;
+	DWORD cbData;
+	DWORD offData;
+} EMRFORMAT;
+typedef struct tagEMRFRAMERGN {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cbRgnData;
+	DWORD ihBrush;
+	SIZEL szlStroke;
+	BYTE RgnData[1];
+} EMRFRAMERGN,*PEMRFRAMERGN;
+typedef struct tagEMRGDICOMMENT {
+	EMR emr;
+	DWORD cbData;
+	BYTE Data[1];
+} EMRGDICOMMENT,*PEMRGDICOMMENT;
+typedef struct tagEMRINVERTRGN {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cbRgnData;
+	BYTE RgnData[1];
+} EMRINVERTRGN,*PEMRINVERTRGN,EMRPAINTRGN,*PEMRPAINTRGN;
+typedef struct tagEMRLINETO {
+	EMR emr;
+	POINTL ptl;
+} EMRLINETO,*PEMRLINETO,EMRMOVETOEX,*PEMRMOVETOEX;
+typedef struct tagEMRMASKBLT {
+	EMR emr;
+	RECTL rclBounds;
+	LONG xDest;
+	LONG yDest;
+	LONG cxDest;
+	LONG cyDest;
+	DWORD dwRop;
+	LONG xSrc;
+	LONG ySrc;
+	XFORM xformSrc;
+	COLORREF crBkColorSrc;
+	DWORD iUsageSrc;
+	DWORD offBmiSrc;
+	DWORD cbBmiSrc;
+	DWORD offBitsSrc;
+	DWORD cbBitsSrc;
+	LONG xMask;
+	LONG yMask;
+	DWORD iUsageMask;
+	DWORD offBmiMask;
+	DWORD cbBmiMask;
+	DWORD offBitsMask;
+	DWORD cbBitsMask;
+} EMRMASKBLT,*PEMRMASKBLT;
+typedef struct tagEMRMODIFYWORLDTRANSFORM {
+	EMR emr;
+	XFORM xform;
+	DWORD iMode;
+} EMRMODIFYWORLDTRANSFORM,*PEMRMODIFYWORLDTRANSFORM;
+typedef struct tagEMROFFSETCLIPRGN {
+	EMR emr;
+	POINTL ptlOffset;
+} EMROFFSETCLIPRGN,*PEMROFFSETCLIPRGN;
+typedef struct tagEMRPLGBLT {
+	EMR emr;
+	RECTL rclBounds;
+	POINTL aptlDest[3];
+	LONG xSrc;
+	LONG ySrc;
+	LONG cxSrc;
+	LONG cySrc;
+	XFORM xformSrc;
+	COLORREF crBkColorSrc;
+	DWORD iUsageSrc;
+	DWORD offBmiSrc;
+	DWORD cbBmiSrc;
+	DWORD offBitsSrc;
+	DWORD cbBitsSrc;
+	LONG xMask;
+	LONG yMask;
+	DWORD iUsageMask;
+	DWORD offBmiMask;
+	DWORD cbBmiMask;
+	DWORD offBitsMask;
+	DWORD cbBitsMask;
+} EMRPLGBLT,*PEMRPLGBLT;
+typedef struct tagEMRPOLYDRAW {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cptl;
+	POINTL aptl[1];
+	BYTE abTypes[1];
+} EMRPOLYDRAW,*PEMRPOLYDRAW;
+typedef struct tagEMRPOLYDRAW16 {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cpts;
+	POINTS apts[1];
+	BYTE abTypes[1];
+} EMRPOLYDRAW16,*PEMRPOLYDRAW16;
+typedef struct tagEMRPOLYLINE {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cptl;
+	POINTL aptl[1];
+} EMRPOLYLINE,*PEMRPOLYLINE,EMRPOLYBEZIER,*PEMRPOLYBEZIER,EMRPOLYGON,*PEMRPOLYGON,EMRPOLYBEZIERTO,*PEMRPOLYBEZIERTO,EMRPOLYLINETO,*PEMRPOLYLINETO;
+typedef struct tagEMRPOLYLINE16 {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD cpts;
+	POINTL apts[1];
+} EMRPOLYLINE16,*PEMRPOLYLINE16,EMRPOLYBEZIER16,*PEMRPOLYBEZIER16,EMRPOLYGON16,*PEMRPOLYGON16,EMRPOLYBEZIERTO16,*PEMRPOLYBEZIERTO16,EMRPOLYLINETO16,*PEMRPOLYLINETO16;
+typedef struct tagEMRPOLYPOLYLINE {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD nPolys;
+	DWORD cptl;
+	DWORD aPolyCounts[1];
+	POINTL aptl[1];
+} EMRPOLYPOLYLINE,*PEMRPOLYPOLYLINE,EMRPOLYPOLYGON,*PEMRPOLYPOLYGON;
+typedef struct tagEMRPOLYPOLYLINE16 {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD nPolys;
+	DWORD cpts;
+	DWORD aPolyCounts[1];
+	POINTS apts[1];
+} EMRPOLYPOLYLINE16,*PEMRPOLYPOLYLINE16,EMRPOLYPOLYGON16,*PEMRPOLYPOLYGON16;
+typedef struct tagEMRPOLYTEXTOUTA {
+	EMR emr;
+	RECTL rclBounds;
+	DWORD iGraphicsMode;
+	FLOAT exScale;
+	FLOAT eyScale;
+	LONG cStrings;
+	EMRTEXT aemrtext[1];
+} EMRPOLYTEXTOUTA,*PEMRPOLYTEXTOUTA,EMRPOLYTEXTOUTW,*PEMRPOLYTEXTOUTW;
+typedef struct tagEMRRESIZEPALETTE {
+	EMR emr;
+	DWORD ihPal;
+	DWORD cEntries;
+} EMRRESIZEPALETTE,*PEMRRESIZEPALETTE;
+typedef struct tagEMRRESTOREDC {
+	EMR emr;
+	LONG iRelative;
+} EMRRESTOREDC,*PEMRRESTOREDC;
+typedef struct tagEMRROUNDRECT {
+	EMR emr;
+	RECTL rclBox;
+	SIZEL szlCorner;
+} EMRROUNDRECT,*PEMRROUNDRECT;
+typedef struct tagEMRSCALEVIEWPORTEXTEX {
+	EMR emr;
+	LONG xNum;
+	LONG xDenom;
+	LONG yNum;
+	LONG yDenom;
+} EMRSCALEVIEWPORTEXTEX,*PEMRSCALEVIEWPORTEXTEX,EMRSCALEWINDOWEXTEX,*PEMRSCALEWINDOWEXTEX;
+typedef struct tagEMRSELECTCOLORSPACE {
+	EMR emr;
+	DWORD ihCS;
+} EMRSELECTCOLORSPACE,*PEMRSELECTCOLORSPACE,EMRDELETECOLORSPACE,*PEMRDELETECOLORSPACE;
+typedef struct tagEMRSELECTOBJECT {
+	EMR emr;
+	DWORD ihObject;
+} EMRSELECTOBJECT,*PEMRSELECTOBJECT,EMRDELETEOBJECT,*PEMRDELETEOBJECT;
+typedef struct tagEMRSELECTPALETTE {
+	EMR emr;
+	DWORD ihPal;
+} EMRSELECTPALETTE,*PEMRSELECTPALETTE;
+typedef struct tagEMRSETARCDIRECTION {
+	EMR emr;
+	DWORD iArcDirection;
+} EMRSETARCDIRECTION,*PEMRSETARCDIRECTION;
+typedef struct tagEMRSETTEXTCOLOR {
+	EMR emr;
+	COLORREF crColor;
+} EMRSETBKCOLOR,*PEMRSETBKCOLOR,EMRSETTEXTCOLOR,*PEMRSETTEXTCOLOR;
+typedef struct tagEMRSETCOLORADJUSTMENT {
+	EMR emr;
+	COLORADJUSTMENT ColorAdjustment;
+} EMRSETCOLORADJUSTMENT,*PEMRSETCOLORADJUSTMENT;
+typedef struct tagEMRSETDIBITSTODEVICE {
+	EMR emr;
+	RECTL rclBounds;
+	LONG xDest;
+	LONG yDest;
+	LONG xSrc;
+	LONG ySrc;
+	LONG cxSrc;
+	LONG cySrc;
+	DWORD offBmiSrc;
+	DWORD cbBmiSrc;
+	DWORD offBitsSrc;
+	DWORD cbBitsSrc;
+	DWORD iUsageSrc;
+	DWORD iStartScan;
+	DWORD cScans;
+} EMRSETDIBITSTODEVICE,*PEMRSETDIBITSTODEVICE;
+typedef struct tagEMRSETMAPPERFLAGS {
+	EMR emr;
+	DWORD dwFlags;
+} EMRSETMAPPERFLAGS,*PEMRSETMAPPERFLAGS;
+typedef struct tagEMRSETMITERLIMIT {
+	EMR emr;
+	FLOAT eMiterLimit;
+} EMRSETMITERLIMIT,*PEMRSETMITERLIMIT;
+typedef struct tagEMRSETPALETTEENTRIES {
+	EMR emr;
+	DWORD ihPal;
+	DWORD iStart;
+	DWORD cEntries;
+	PALETTEENTRY aPalEntries[1];
+} EMRSETPALETTEENTRIES,*PEMRSETPALETTEENTRIES;
+typedef struct tagEMRSETPIXELV {
+	EMR emr;
+	POINTL ptlPixel;
+	COLORREF crColor;
+} EMRSETPIXELV,*PEMRSETPIXELV;
+typedef struct tagEMRSETVIEWPORTEXTEX {
+	EMR emr;
+	SIZEL szlExtent;
+} EMRSETVIEWPORTEXTEX,*PEMRSETVIEWPORTEXTEX,EMRSETWINDOWEXTEX,*PEMRSETWINDOWEXTEX;
+typedef struct tagEMRSETVIEWPORTORGEX {
+	EMR emr;
+	POINTL ptlOrigin;
+} EMRSETVIEWPORTORGEX,*PEMRSETVIEWPORTORGEX,EMRSETWINDOWORGEX,*PEMRSETWINDOWORGEX,EMRSETBRUSHORGEX,*PEMRSETBRUSHORGEX;
+typedef struct tagEMRSETWORLDTRANSFORM {
+	EMR emr;
+	XFORM xform;
+} EMRSETWORLDTRANSFORM,*PEMRSETWORLDTRANSFORM;
+typedef struct tagEMRSTRETCHBLT {
+	EMR emr;
+	RECTL rclBounds;
+	LONG xDest;
+	LONG yDest;
+	LONG cxDest;
+	LONG cyDest;
+	DWORD dwRop;
+	LONG xSrc;
+	LONG ySrc;
+	XFORM xformSrc;
+	COLORREF crBkColorSrc;
+	DWORD iUsageSrc;
+	DWORD offBmiSrc;
+	DWORD cbBmiSrc;
+	DWORD offBitsSrc;
+	DWORD cbBitsSrc;
+	LONG cxSrc;
+	LONG cySrc;
+} EMRSTRETCHBLT,*PEMRSTRETCHBLT;
+typedef struct tagEMRSTRETCHDIBITS {
+	EMR emr;
+	RECTL rclBounds;
+	LONG xDest;
+	LONG yDest;
+	LONG xSrc;
+	LONG ySrc;
+	LONG cxSrc;
+	LONG cySrc;
+	DWORD offBmiSrc;
+	DWORD cbBmiSrc;
+	DWORD offBitsSrc;
+	DWORD cbBitsSrc;
+	DWORD iUsageSrc;
+	DWORD dwRop;
+	LONG cxDest;
+	LONG cyDest;
+} EMRSTRETCHDIBITS,*PEMRSTRETCHDIBITS;
+typedef struct tagABORTPATH {
+	EMR emr;
+} EMRABORTPATH,*PEMRABORTPATH,EMRBEGINPATH,*PEMRBEGINPATH,EMRENDPATH,*PEMRENDPATH,EMRCLOSEFIGURE,*PEMRCLOSEFIGURE,EMRFLATTENPATH,*PEMRFLATTENPATH,EMRWIDENPATH,*PEMRWIDENPATH,EMRSETMETARGN,*PEMRSETMETARGN,EMRSAVEDC,*PEMRSAVEDC,EMRREALIZEPALETTE,*PEMRREALIZEPALETTE;
+typedef struct tagEMRSELECTCLIPPATH {
+	EMR emr;
+	DWORD iMode;
+} EMRSELECTCLIPPATH,*PEMRSELECTCLIPPATH,EMRSETBKMODE,*PEMRSETBKMODE,EMRSETMAPMODE,*PEMRSETMAPMODE,EMRSETPOLYFILLMODE,*PEMRSETPOLYFILLMODE,EMRSETROP2,*PEMRSETROP2,EMRSETSTRETCHBLTMODE,*PEMRSETSTRETCHBLTMODE,EMRSETTEXTALIGN,*PEMRSETTEXTALIGN,EMRENABLEICM,*PEMRENABLEICM;
+#pragma pack(push,2)
+typedef struct tagMETAHEADER {
+	WORD mtType;
+	WORD mtHeaderSize;
+	WORD mtVersion;
+	DWORD mtSize;
+	WORD mtNoObjects;
+	DWORD mtMaxRecord;
+	WORD mtNoParameters;
+} METAHEADER,*PMETAHEADER,*LPMETAHEADER;
+#pragma pack(pop)
+typedef struct tagENHMETAHEADER {
+	DWORD iType;
+	DWORD nSize;
+	RECTL rclBounds;
+	RECTL rclFrame;
+	DWORD dSignature;
+	DWORD nVersion;
+	DWORD nBytes;
+	DWORD nRecords;
+	WORD nHandles;
+	WORD sReserved;
+	DWORD nDescription;
+	DWORD offDescription;
+	DWORD nPalEntries;
+	SIZEL szlDevice;
+	SIZEL szlMillimeters;
+} ENHMETAHEADER,*LPENHMETAHEADER;
+typedef struct tagMETARECORD {
+	DWORD rdSize;
+	WORD rdFunction;
+	WORD rdParm[1];
+} METARECORD,*PMETARECORD,*LPMETARECORD;
+typedef struct tagENHMETARECORD {
+	DWORD iType;
+	DWORD nSize;
+	DWORD dParm[1];
+} ENHMETARECORD,*LPENHMETARECORD;
+typedef struct tagHANDLETABLE {
+	HGDIOBJ objectHandle[1];
+} HANDLETABLE,*LPHANDLETABLE;
+typedef struct tagTEXTMETRICA {
+	LONG tmHeight;
+	LONG tmAscent;
+	LONG tmDescent;
+	LONG tmInternalLeading;
+	LONG tmExternalLeading;
+	LONG tmAveCharWidth;
+	LONG tmMaxCharWidth;
+	LONG tmWeight;
+	LONG tmOverhang;
+	LONG tmDigitizedAspectX;
+	LONG tmDigitizedAspectY;
+	BYTE tmFirstChar;
+	BYTE tmLastChar;
+	BYTE tmDefaultChar;
+	BYTE tmBreakChar;
+	BYTE tmItalic;
+	BYTE tmUnderlined;
+	BYTE tmStruckOut;
+	BYTE tmPitchAndFamily;
+	BYTE tmCharSet;
+} TEXTMETRICA,*PTEXTMETRICA,*LPTEXTMETRICA;
+typedef struct tagTEXTMETRICW {
+	LONG tmHeight;
+	LONG tmAscent;
+	LONG tmDescent;
+	LONG tmInternalLeading;
+	LONG tmExternalLeading;
+	LONG tmAveCharWidth;
+	LONG tmMaxCharWidth;
+	LONG tmWeight;
+	LONG tmOverhang;
+	LONG tmDigitizedAspectX;
+	LONG tmDigitizedAspectY;
+	WCHAR tmFirstChar;
+	WCHAR tmLastChar;
+	WCHAR tmDefaultChar;
+	WCHAR tmBreakChar;
+	BYTE tmItalic;
+	BYTE tmUnderlined;
+	BYTE tmStruckOut;
+	BYTE tmPitchAndFamily;
+	BYTE tmCharSet;
+} TEXTMETRICW,*PTEXTMETRICW,*LPTEXTMETRICW;
+typedef struct _RGNDATAHEADER {
+	DWORD dwSize;
+	DWORD iType;
+	DWORD nCount;
+	DWORD nRgnSize;
+	RECT rcBound;
+} RGNDATAHEADER;
+typedef struct _RGNDATA {
+	RGNDATAHEADER rdh;
+	char Buffer[1];
+} RGNDATA,*LPRGNDATA;
+/* for GetRandomRgn */
+#define SYSRGN  4
+typedef struct tagGCP_RESULTSA {
+	DWORD lStructSize;
+	LPSTR lpOutString;
+	UINT *lpOrder;
+	INT *lpDx;
+	INT *lpCaretPos;
+	LPSTR lpClass;
+	UINT *lpGlyphs;
+	UINT nGlyphs;
+	UINT nMaxFit;
+} GCP_RESULTSA,*LPGCP_RESULTSA;
+typedef struct tagGCP_RESULTSW {
+	DWORD lStructSize;
+	LPWSTR lpOutString;
+	UINT *lpOrder;
+	INT *lpDx;
+	INT *lpCaretPos;
+	LPWSTR lpClass;
+	UINT *lpGlyphs;
+	UINT nGlyphs;
+	UINT nMaxFit;
+} GCP_RESULTSW,*LPGCP_RESULTSW;
+typedef struct _GLYPHMETRICS {
+	UINT gmBlackBoxX;
+	UINT gmBlackBoxY;
+	POINT gmptGlyphOrigin;
+	short gmCellIncX;
+	short gmCellIncY;
+} GLYPHMETRICS,*LPGLYPHMETRICS;
+typedef struct tagKERNINGPAIR {
+	WORD wFirst;
+	WORD wSecond;
+	int iKernAmount;
+} KERNINGPAIR,*LPKERNINGPAIR;
+typedef struct _FIXED {
+	WORD fract;
+	short value;
+} FIXED;
+typedef struct _MAT2 {
+	FIXED eM11;
+	FIXED eM12;
+	FIXED eM21;
+	FIXED eM22;
+} MAT2,*LPMAT2;
+typedef struct _OUTLINETEXTMETRICA {
+	UINT otmSize;
+	TEXTMETRICA otmTextMetrics;
+	BYTE otmFiller;
+	PANOSE otmPanoseNumber;
+	UINT otmfsSelection;
+	UINT otmfsType;
+	int otmsCharSlopeRise;
+	int otmsCharSlopeRun;
+	int otmItalicAngle;
+	UINT otmEMSquare;
+	int otmAscent;
+	int otmDescent;
+	UINT otmLineGap;
+	UINT otmsCapEmHeight;
+	UINT otmsXHeight;
+	RECT otmrcFontBox;
+	int otmMacAscent;
+	int otmMacDescent;
+	UINT otmMacLineGap;
+	UINT otmusMinimumPPEM;
+	POINT otmptSubscriptSize;
+	POINT otmptSubscriptOffset;
+	POINT otmptSuperscriptSize;
+	POINT otmptSuperscriptOffset;
+	UINT otmsStrikeoutSize;
+	int otmsStrikeoutPosition;
+	int otmsUnderscoreSize;
+	int otmsUnderscorePosition;
+	PSTR otmpFamilyName;
+	PSTR otmpFaceName;
+	PSTR otmpStyleName;
+	PSTR otmpFullName;
+} OUTLINETEXTMETRICA,*POUTLINETEXTMETRICA,*LPOUTLINETEXTMETRICA;
+typedef struct _OUTLINETEXTMETRICW {
+	UINT otmSize;
+	TEXTMETRICW otmTextMetrics;
+	BYTE otmFiller;
+	PANOSE otmPanoseNumber;
+	UINT otmfsSelection;
+	UINT otmfsType;
+	int otmsCharSlopeRise;
+	int otmsCharSlopeRun;
+	int otmItalicAngle;
+	UINT otmEMSquare;
+	int otmAscent;
+	int otmDescent;
+	UINT otmLineGap;
+	UINT otmsCapEmHeight;
+	UINT otmsXHeight;
+	RECT otmrcFontBox;
+	int otmMacAscent;
+	int otmMacDescent;
+	UINT otmMacLineGap;
+	UINT otmusMinimumPPEM;
+	POINT otmptSubscriptSize;
+	POINT otmptSubscriptOffset;
+	POINT otmptSuperscriptSize;
+	POINT otmptSuperscriptOffset;
+	UINT otmsStrikeoutSize;
+	int otmsStrikeoutPosition;
+	int otmsUnderscoreSize;
+	int otmsUnderscorePosition;
+	PSTR otmpFamilyName;
+	PSTR otmpFaceName;
+	PSTR otmpStyleName;
+	PSTR otmpFullName;
+} OUTLINETEXTMETRICW,*POUTLINETEXTMETRICW,*LPOUTLINETEXTMETRICW;
+typedef struct _RASTERIZER_STATUS {
+	short nSize;
+	short wFlags;
+	short nLanguageID;
+} RASTERIZER_STATUS,*LPRASTERIZER_STATUS;
+typedef struct _POLYTEXTA {
+	int x;
+	int y;
+	UINT n;
+	LPCSTR lpstr;
+	UINT uiFlags;
+	RECT rcl;
+	int *pdx;
+} POLYTEXTA;
+typedef struct _POLYTEXTW {
+	int x;
+	int y;
+	UINT n;
+	LPCWSTR lpstr;
+	UINT uiFlags;
+	RECT rcl;
+	int *pdx;
+} POLYTEXTW;
+typedef struct tagPIXELFORMATDESCRIPTOR {
+	WORD nSize;
+	WORD nVersion;
+	DWORD dwFlags;
+	BYTE iPixelType;
+	BYTE cColorBits;
+	BYTE cRedBits;
+	BYTE cRedShift;
+	BYTE cGreenBits;
+	BYTE cGreenShift;
+	BYTE cBlueBits;
+	BYTE cBlueShift;
+	BYTE cAlphaBits;
+	BYTE cAlphaShift;
+	BYTE cAccumBits;
+	BYTE cAccumRedBits;
+	BYTE cAccumGreenBits;
+	BYTE cAccumBlueBits;
+	BYTE cAccumAlphaBits;
+	BYTE cDepthBits;
+	BYTE cStencilBits;
+	BYTE cAuxBuffers;
+	BYTE iLayerType;
+	BYTE bReserved;
+	DWORD dwLayerMask;
+	DWORD dwVisibleMask;
+	DWORD dwDamageMask;
+} PIXELFORMATDESCRIPTOR,*PPIXELFORMATDESCRIPTOR,*LPPIXELFORMATDESCRIPTOR;
+typedef struct tagMETAFILEPICT {
+	LONG mm;
+	LONG xExt;
+	LONG yExt;
+	HMETAFILE hMF;
+} METAFILEPICT,*LPMETAFILEPICT;
+typedef struct tagLOCALESIGNATURE {
+	DWORD lsUsb[4];
+	DWORD lsCsbDefault[2];
+	DWORD lsCsbSupported[2];
+} LOCALESIGNATURE,*PLOCALESIGNATURE,*LPLOCALESIGNATURE;
+typedef LONG LCSTYPE;
+#pragma pack(push,4)
+typedef struct tagNEWTEXTMETRICA {
+	LONG tmHeight;
+	LONG tmAscent;
+	LONG tmDescent;
+	LONG tmInternalLeading;
+	LONG tmExternalLeading;
+	LONG tmAveCharWidth;
+	LONG tmMaxCharWidth;
+	LONG tmWeight;
+	LONG tmOverhang;
+	LONG tmDigitizedAspectX;
+	LONG tmDigitizedAspectY;
+	BYTE tmFirstChar;
+	BYTE tmLastChar;
+	BYTE tmDefaultChar;
+	BYTE tmBreakChar;
+	BYTE tmItalic;
+	BYTE tmUnderlined;
+	BYTE tmStruckOut;
+	BYTE tmPitchAndFamily;
+	BYTE tmCharSet;
+	DWORD ntmFlags;
+	UINT ntmSizeEM;
+	UINT ntmCellHeight;
+	UINT ntmAvgWidth;
+} NEWTEXTMETRICA,*PNEWTEXTMETRICA,*LPNEWTEXTMETRICA;
+typedef struct tagNEWTEXTMETRICW {
+	LONG tmHeight;
+	LONG tmAscent;
+	LONG tmDescent;
+	LONG tmInternalLeading;
+	LONG tmExternalLeading;
+	LONG tmAveCharWidth;
+	LONG tmMaxCharWidth;
+	LONG tmWeight;
+	LONG tmOverhang;
+	LONG tmDigitizedAspectX;
+	LONG tmDigitizedAspectY;
+	WCHAR tmFirstChar;
+	WCHAR tmLastChar;
+	WCHAR tmDefaultChar;
+	WCHAR tmBreakChar;
+	BYTE tmItalic;
+	BYTE tmUnderlined;
+	BYTE tmStruckOut;
+	BYTE tmPitchAndFamily;
+	BYTE tmCharSet;
+	DWORD ntmFlags;
+	UINT ntmSizeEM;
+	UINT ntmCellHeight;
+	UINT ntmAvgWidth;
+} NEWTEXTMETRICW,*PNEWTEXTMETRICW,*LPNEWTEXTMETRICW;
+#pragma pack(pop)
+typedef struct tagNEWTEXTMETRICEXA {
+	NEWTEXTMETRICA ntmTm;
+	FONTSIGNATURE ntmFontSig;
+} NEWTEXTMETRICEXA;
+typedef struct tagNEWTEXTMETRICEXW {
+	NEWTEXTMETRICW ntmTm;
+	FONTSIGNATURE ntmFontSig;
+} NEWTEXTMETRICEXW;
+typedef struct tagPELARRAY {
+	LONG paXCount;
+	LONG paYCount;
+	LONG paXExt;
+	LONG paYExt;
+	BYTE paRGBs;
+} PELARRAY,*PPELARRAY,*LPPELARRAY;
+typedef struct tagENUMLOGFONTA {
+	LOGFONTA elfLogFont;
+	BYTE elfFullName[LF_FULLFACESIZE];
+	BYTE elfStyle[LF_FACESIZE];
+} ENUMLOGFONTA,*LPENUMLOGFONTA;
+typedef struct tagENUMLOGFONTW {
+	LOGFONTW elfLogFont;
+	WCHAR elfFullName[LF_FULLFACESIZE];
+	WCHAR elfStyle[LF_FACESIZE];
+} ENUMLOGFONTW,*LPENUMLOGFONTW;
+typedef struct tagENUMLOGFONTEXA {
+	LOGFONTA elfLogFont;
+	BYTE elfFullName[LF_FULLFACESIZE];
+	BYTE elfStyle[LF_FACESIZE];
+	BYTE elfScript[LF_FACESIZE];
+} ENUMLOGFONTEXA,*LPENUMLOGFONTEXA;
+typedef struct tagENUMLOGFONTEXW {
+	LOGFONTW elfLogFont;
+	WCHAR elfFullName[LF_FULLFACESIZE];
+	BYTE elfStyle[LF_FACESIZE];
+	BYTE elfScript[LF_FACESIZE];
+} ENUMLOGFONTEXW,*LPENUMLOGFONTEXW;
+typedef struct tagPOINTFX {
+	FIXED x;
+	FIXED y;
+} POINTFX,*LPPOINTFX;
+typedef struct tagTTPOLYCURVE {
+	WORD wType;
+	WORD cpfx;
+	POINTFX apfx[1];
+} TTPOLYCURVE,*LPTTPOLYCURVE;
+typedef struct tagTTPOLYGONHEADER {
+	DWORD cb;
+	DWORD dwType;
+	POINTFX pfxStart;
+} TTPOLYGONHEADER,*LPTTPOLYGONHEADER;
+typedef struct _POINTFLOAT {
+	FLOAT x;
+	FLOAT y;
+} POINTFLOAT,*PPOINTFLOAT;
+typedef struct _GLYPHMETRICSFLOAT {
+	FLOAT gmfBlackBoxX;
+	FLOAT gmfBlackBoxY;
+	POINTFLOAT gmfptGlyphOrigin;
+	FLOAT gmfCellIncX;
+	FLOAT gmfCellIncY;
+} GLYPHMETRICSFLOAT,*PGLYPHMETRICSFLOAT,*LPGLYPHMETRICSFLOAT;
+typedef struct tagLAYERPLANEDESCRIPTOR {
+	WORD nSize;
+	WORD nVersion;
+	DWORD dwFlags;
+	BYTE iPixelType;
+	BYTE cColorBits;
+	BYTE cRedBits;
+	BYTE cRedShift;
+	BYTE cGreenBits;
+	BYTE cGreenShift;
+	BYTE cBlueBits;
+	BYTE cBlueShift;
+	BYTE cAlphaBits;
+	BYTE cAlphaShift;
+	BYTE cAccumBits;
+	BYTE cAccumRedBits;
+	BYTE cAccumGreenBits;
+	BYTE cAccumBlueBits;
+	BYTE cAccumAlphaBits;
+	BYTE cDepthBits;
+	BYTE cStencilBits;
+	BYTE cAuxBuffers;
+	BYTE iLayerPlane;
+	BYTE bReserved;
+	COLORREF crTransparent;
+} LAYERPLANEDESCRIPTOR,*PLAYERPLANEDESCRIPTOR,*LPLAYERPLANEDESCRIPTOR;
+typedef struct _BLENDFUNCTION {
+    BYTE BlendOp;
+    BYTE BlendFlags;
+    BYTE SourceConstantAlpha;
+    BYTE AlphaFormat; 
+} BLENDFUNCTION,*PBLENDFUNCTION,*LPBLENDFUNCTION; 
+typedef BOOL (CALLBACK *ABORTPROC)(HDC,int);
+typedef int (CALLBACK *MFENUMPROC)(HDC,HANDLETABLE*,METARECORD*,int,LPARAM);
+typedef int (CALLBACK *ENHMFENUMPROC)(HDC,HANDLETABLE*,ENHMETARECORD*,int,LPARAM);
+typedef int (CALLBACK *OLDFONTENUMPROCA)(const LOGFONTA*,const TEXTMETRICA*,DWORD,LPARAM);
+typedef int (CALLBACK *OLDFONTENUMPROCW)(const LOGFONTW*,const TEXTMETRICW*,DWORD,LPARAM);
+typedef OLDFONTENUMPROCA FONTENUMPROCA;
+typedef OLDFONTENUMPROCW FONTENUMPROCW;
+typedef int (CALLBACK *ICMENUMPROCA)(LPSTR,LPARAM);
+typedef int (CALLBACK *ICMENUMPROCW)(LPWSTR,LPARAM);
+typedef void (CALLBACK *GOBJENUMPROC)(LPVOID,LPARAM);
+typedef void (CALLBACK *LINEDDAPROC)(int,int,LPARAM);
+typedef UINT (CALLBACK *LPFNDEVMODE)(HWND,HMODULE,LPDEVMODEA,LPSTR,LPSTR,LPDEVMODEA,LPSTR,UINT);
+typedef DWORD (CALLBACK *LPFNDEVCAPS)(LPSTR,LPSTR,UINT,LPSTR,LPDEVMODEA);
+
+
+#define RGB(r,g,b)	((DWORD)(((BYTE)(r)|((WORD)(g)<<8))|(((DWORD)(BYTE)(b))<<16)))
+#define MAKEPOINTS(l) (*((POINTS*)&(l)))
+#define MAKEROP4(f,b)	(DWORD)((((b)<<8)&0xFF000000)|(f))
+#define PALETTEINDEX(i)	((0x01000000|(COLORREF)(WORD)(i)))
+#define PALETTERGB(r,g,b)	(0x02000000|RGB(r,g,b))
+int WINAPI AbortDoc(HDC);
+BOOL WINAPI AbortPath(HDC);
+int WINAPI AddFontResourceA(LPCSTR);
+int WINAPI AddFontResourceW(LPCWSTR);
+BOOL WINAPI AngleArc(HDC,int,int,DWORD,FLOAT,FLOAT);
+BOOL WINAPI AnimatePalette(HPALETTE,UINT,UINT,const PALETTEENTRY*);
+BOOL WINAPI Arc(HDC,int,int,int,int,int,int,int,int);
+BOOL WINAPI ArcTo(HDC,int,int,int,int,int,int,int,int);
+BOOL WINAPI BeginPath(HDC);
+BOOL WINAPI BitBlt(HDC,int,int,int,int,HDC,int,int,DWORD);
+BOOL WINAPI CancelDC(HDC);
+BOOL WINAPI CheckColorsInGamut(HDC,PVOID,PVOID,DWORD);
+BOOL WINAPI Chord(HDC,int,int,int,int,int,int,int,int);
+int WINAPI ChoosePixelFormat(HDC,CONST PIXELFORMATDESCRIPTOR*);
+HENHMETAFILE WINAPI CloseEnhMetaFile(HDC);
+BOOL WINAPI CloseFigure(HDC);
+HMETAFILE WINAPI CloseMetaFile(HDC);
+BOOL WINAPI ColorMatchToTarget(HDC,HDC,DWORD);
+int WINAPI CombineRgn(HRGN,HRGN,HRGN,int);
+BOOL WINAPI CombineTransform(LPXFORM,const XFORM*,const XFORM*);
+HENHMETAFILE WINAPI CopyEnhMetaFileA(HENHMETAFILE,LPCSTR);
+HENHMETAFILE WINAPI CopyEnhMetaFileW(HENHMETAFILE,LPCWSTR);
+HMETAFILE WINAPI CopyMetaFileA(HMETAFILE,LPCSTR);
+HMETAFILE WINAPI CopyMetaFileW(HMETAFILE,LPCWSTR);
+HBITMAP WINAPI CreateBitmap(int,int,UINT,UINT,PCVOID);
+HBITMAP WINAPI CreateBitmapIndirect(const BITMAP*);
+HBRUSH WINAPI CreateBrushIndirect(const LOGBRUSH*);
+HCOLORSPACE WINAPI CreateColorSpaceA(LPLOGCOLORSPACEA);
+HCOLORSPACE WINAPI CreateColorSpaceW(LPLOGCOLORSPACEW);
+HBITMAP WINAPI CreateCompatibleBitmap(HDC,int,int);
+HDC WINAPI CreateCompatibleDC(HDC);
+HDC WINAPI CreateDCA(LPCSTR,LPCSTR,LPCSTR,const DEVMODEA*);
+HDC WINAPI CreateDCW(LPCWSTR,LPCWSTR,LPCWSTR,const DEVMODEW*);
+HBITMAP WINAPI CreateDIBitmap(HDC,const BITMAPINFOHEADER*,DWORD,PCVOID,const BITMAPINFO*,UINT);
+HBRUSH WINAPI CreateDIBPatternBrush(HGLOBAL,UINT);
+HBRUSH WINAPI CreateDIBPatternBrushPt(PCVOID,UINT);
+HBITMAP WINAPI CreateDIBSection(HDC,const BITMAPINFO*,UINT,void**,HANDLE,DWORD);
+HBITMAP WINAPI CreateDiscardableBitmap(HDC,int,int);
+HRGN WINAPI CreateEllipticRgn(int,int,int,int);
+HRGN WINAPI CreateEllipticRgnIndirect(LPCRECT);
+HDC WINAPI CreateEnhMetaFileA(HDC,LPCSTR,LPCRECT,LPCSTR);
+HDC WINAPI CreateEnhMetaFileW(HDC,LPCWSTR,LPCRECT,LPCWSTR);
+HFONT WINAPI CreateFontA(int,int,int,int,int,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,LPCSTR);
+HFONT WINAPI CreateFontW(int,int,int,int,int,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,LPCWSTR);
+HFONT WINAPI CreateFontIndirectA(const LOGFONTA*);
+HFONT WINAPI CreateFontIndirectW(const LOGFONTW*);
+HPALETTE WINAPI CreateHalftonePalette(HDC);
+HBRUSH WINAPI CreateHatchBrush(int,COLORREF);
+HDC WINAPI CreateICA(LPCSTR,LPCSTR,LPCSTR,const DEVMODEA*);
+HDC WINAPI CreateICW(LPCWSTR,LPCWSTR,LPCWSTR,const DEVMODEW*);
+HDC WINAPI CreateMetaFileA(LPCSTR);
+HDC WINAPI CreateMetaFileW(LPCWSTR);
+HPALETTE WINAPI CreatePalette(const LOGPALETTE*);
+HBRUSH WINAPI CreatePatternBrush(HBITMAP);
+HPEN WINAPI CreatePen(int,int,COLORREF);
+HPEN WINAPI CreatePenIndirect(const LOGPEN*);
+HRGN WINAPI CreatePolygonRgn(const POINT*,int,int);
+HRGN WINAPI CreatePolyPolygonRgn(const POINT*,const INT*,int,int);
+HRGN WINAPI CreateRectRgn(int,int,int,int);
+HRGN WINAPI CreateRectRgnIndirect(LPCRECT);
+HRGN WINAPI CreateRoundRectRgn(int,int,int,int,int,int);
+BOOL WINAPI CreateScalableFontResourceA(DWORD,LPCSTR,LPCSTR,LPCSTR);
+BOOL WINAPI CreateScalableFontResourceW(DWORD,LPCWSTR,LPCWSTR,LPCWSTR);
+HBRUSH WINAPI CreateSolidBrush(COLORREF);
+BOOL WINAPI DeleteColorSpace(HCOLORSPACE);
+BOOL WINAPI DeleteDC(HDC);
+BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE);
+BOOL WINAPI DeleteMetaFile(HMETAFILE);
+BOOL WINAPI DeleteObject(HGDIOBJ);
+int WINAPI DescribePixelFormat(HDC,int,UINT,LPPIXELFORMATDESCRIPTOR);
+DWORD WINAPI DeviceCapabilitiesA(LPCSTR,LPCSTR,WORD,LPSTR,const DEVMODEA*);
+DWORD WINAPI DeviceCapabilitiesW(LPCWSTR,LPCWSTR,WORD,LPWSTR,const DEVMODEW*);
+BOOL WINAPI DPtoLP(HDC,LPPOINT,int);
+int WINAPI DrawEscape(HDC,int,int,LPCSTR);
+BOOL WINAPI Ellipse(HDC,int,int,int,int);
+int WINAPI EndDoc(HDC);
+int WINAPI EndPage(HDC);
+BOOL WINAPI EndPath(HDC);
+BOOL WINAPI EnumEnhMetaFile(HDC,HENHMETAFILE,ENHMFENUMPROC,PVOID,LPCRECT);
+int WINAPI EnumFontFamiliesA(HDC,LPCSTR,FONTENUMPROCA,LPARAM);
+int WINAPI EnumFontFamiliesW(HDC,LPCWSTR,FONTENUMPROCW,LPARAM);
+int WINAPI EnumFontFamiliesExA(HDC,PLOGFONTA,FONTENUMPROCA,LPARAM,DWORD);
+int WINAPI EnumFontFamiliesExW(HDC,PLOGFONTW,FONTENUMPROCW,LPARAM,DWORD);
+int WINAPI EnumFontsA(HDC,LPCSTR,FONTENUMPROCA,LPARAM);
+int WINAPI EnumFontsW(HDC,LPCWSTR,FONTENUMPROCA,LPARAM);
+int WINAPI EnumICMProfilesA(HDC,ICMENUMPROCA,LPARAM);
+int WINAPI EnumICMProfilesW(HDC,ICMENUMPROCW,LPARAM);
+BOOL WINAPI EnumMetaFile(HDC,HMETAFILE,MFENUMPROC,LPARAM);
+int WINAPI EnumObjects(HDC,int,GOBJENUMPROC,LPARAM);
+BOOL WINAPI EqualRgn(HRGN,HRGN);
+int WINAPI Escape(HDC,int,int,LPCSTR,PVOID);
+int WINAPI ExcludeClipRect(HDC,int,int,int,int);
+int WINAPI ExcludeUpdateRgn(HDC,HWND);
+HPEN WINAPI ExtCreatePen(DWORD,DWORD,const LOGBRUSH*,DWORD,const DWORD*);
+HRGN WINAPI ExtCreateRegion(const XFORM*,DWORD,const RGNDATA*);
+int WINAPI ExtEscape(HDC,int,int,LPCSTR,int,LPSTR);
+BOOL WINAPI ExtFloodFill(HDC,int,int,COLORREF,UINT);
+int WINAPI ExtSelectClipRgn(HDC,HRGN,int);
+BOOL WINAPI ExtTextOutA(HDC,int,int,UINT,LPCRECT,LPCSTR,UINT,const INT*);
+BOOL WINAPI ExtTextOutW(HDC,int,int,UINT,LPCRECT,LPCWSTR,UINT,const INT*);
+BOOL WINAPI FillPath(HDC);
+int WINAPI FillRect(HDC,LPCRECT,HBRUSH);
+int WINAPI FillRgn(HDC,HRGN,HBRUSH);
+BOOL WINAPI FixBrushOrgEx(HDC,int,int,LPPOINT);
+BOOL WINAPI FlattenPath(HDC);
+BOOL WINAPI FloodFill(HDC,int,int,COLORREF);
+BOOL WINAPI GdiComment(HDC,UINT,const BYTE*);
+BOOL WINAPI GdiFlush(void);
+DWORD WINAPI GdiGetBatchLimit(void);
+DWORD WINAPI GdiSetBatchLimit(DWORD);
+#define GetCValue(cmyk) ((BYTE)(cmyk))
+#define GetMValue(cmyk) ((BYTE)((cmyk)>> 8))
+#define GetYValue(cmyk) ((BYTE)((cmyk)>>16))
+#define GetKValue(cmyk) ((BYTE)((cmyk)>>24))
+#define CMYK(c,m,y,k) ((COLORREF)((((BYTE)(c)|((WORD)((BYTE)(m))<<8))|(((DWORD)(BYTE)(y))<<16))|(((DWORD)(BYTE)(k))<<24)))
+#define GetRValue(c) ((BYTE)(c))
+#define GetGValue(c) ((BYTE)(((WORD)(c))>>8))
+#define GetBValue(c) ((BYTE)((c)>>16))
+int WINAPI GetArcDirection(HDC);
+BOOL WINAPI GetAspectRatioFilterEx(HDC,LPSIZE);
+LONG WINAPI GetBitmapBits(HBITMAP,LONG,PVOID);
+BOOL WINAPI GetBitmapDimensionEx(HBITMAP,LPSIZE);
+COLORREF WINAPI GetBkColor(HDC);
+int WINAPI GetBkMode(HDC);
+UINT WINAPI GetBoundsRect(HDC,LPRECT,UINT);
+BOOL WINAPI GetBrushOrgEx(HDC,LPPOINT);
+BOOL WINAPI GetCharABCWidthsA(HDC,UINT,UINT,LPABC);
+BOOL WINAPI GetCharABCWidthsW(HDC,UINT,UINT,LPABC);
+BOOL WINAPI GetCharABCWidthsFloatA(HDC,UINT,UINT,LPABCFLOAT);
+BOOL WINAPI GetCharABCWidthsFloatW(HDC,UINT,UINT,LPABCFLOAT);
+DWORD WINAPI GetCharacterPlacementA(HDC,LPCSTR,int,int,LPGCP_RESULTSA,DWORD);
+DWORD WINAPI GetCharacterPlacementW(HDC,LPCWSTR,int,int,LPGCP_RESULTSW,DWORD);
+BOOL WINAPI GetCharWidth32A(HDC,UINT,UINT,LPINT);
+BOOL WINAPI GetCharWidth32W(HDC,UINT,UINT,LPINT);
+BOOL WINAPI GetCharWidthA(HDC,UINT,UINT,LPINT);
+BOOL WINAPI GetCharWidthW(HDC,UINT,UINT,LPINT);
+BOOL WINAPI GetCharWidthFloatA(HDC,UINT,UINT,PFLOAT);
+BOOL WINAPI GetCharWidthFloatW(HDC,UINT,UINT,PFLOAT);
+int WINAPI GetClipBox(HDC,LPRECT);
+int WINAPI GetClipRgn(HDC,HRGN);
+BOOL WINAPI GetColorAdjustment(HDC,LPCOLORADJUSTMENT);
+HANDLE WINAPI GetColorSpace(HDC);
+HGDIOBJ WINAPI GetCurrentObject(HDC,UINT);
+BOOL WINAPI GetCurrentPositionEx(HDC,LPPOINT);
+HCURSOR WINAPI GetCursor(void);
+BOOL WINAPI GetDCOrgEx(HDC,LPPOINT);
+int WINAPI GetDeviceCaps(HDC,int);
+BOOL WINAPI GetDeviceGammaRamp(HDC,PVOID);
+UINT WINAPI GetDIBColorTable(HDC,UINT,UINT,RGBQUAD*);
+int WINAPI GetDIBits(HDC,HBITMAP,UINT,UINT,PVOID,LPBITMAPINFO,UINT);
+HENHMETAFILE WINAPI GetEnhMetaFileA(LPCSTR);
+HENHMETAFILE WINAPI GetEnhMetaFileW(LPCWSTR);
+UINT WINAPI GetEnhMetaFileDescriptionA(HENHMETAFILE,UINT,LPSTR);
+UINT WINAPI GetEnhMetaFileDescriptionW(HENHMETAFILE,UINT,LPWSTR);
+UINT WINAPI GetEnhMetaFileHeader(HENHMETAFILE,UINT,LPENHMETAHEADER);
+UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE,UINT,LPPALETTEENTRY);
+UINT WINAPI GetEnhMetaFilePixelFormat(HENHMETAFILE,DWORD,PIXELFORMATDESCRIPTOR*);
+DWORD WINAPI GetFontData(HDC,DWORD,DWORD,PVOID,DWORD);
+DWORD WINAPI GetFontLanguageInfo(HDC);
+DWORD WINAPI GetGlyphOutlineA(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,PVOID,const MAT2*);
+DWORD WINAPI GetGlyphOutlineW(HDC,UINT,UINT,LPGLYPHMETRICS,DWORD,PVOID,const MAT2*);
+int WINAPI GetGraphicsMode(HDC);
+BOOL WINAPI GetICMProfileA(HDC,DWORD,LPSTR);
+BOOL WINAPI GetICMProfileW(HDC,DWORD,LPWSTR);
+DWORD WINAPI GetKerningPairsA(HDC,DWORD,LPKERNINGPAIR);
+DWORD WINAPI GetKerningPairsW(HDC,DWORD,LPKERNINGPAIR);
+BOOL WINAPI GetLogColorSpaceA(HCOLORSPACE,LPLOGCOLORSPACEA,DWORD);
+BOOL WINAPI GetLogColorSpaceW(HCOLORSPACE,LPLOGCOLORSPACEW,DWORD);
+int WINAPI GetMapMode(HDC);
+HMETAFILE WINAPI GetMetaFileA(LPCSTR);
+HMETAFILE WINAPI GetMetaFileW(LPCWSTR);
+UINT WINAPI GetMetaFileBitsEx(HMETAFILE,UINT,PVOID);
+int WINAPI GetMetaRgn(HDC,HRGN);
+BOOL WINAPI GetMiterLimit(HDC,PFLOAT);
+COLORREF WINAPI GetNearestColor(HDC,COLORREF);
+UINT WINAPI GetNearestPaletteIndex(HPALETTE,COLORREF);
+int WINAPI GetObjectA(HGDIOBJ,int,PVOID);
+int WINAPI GetObjectW(HGDIOBJ,int,PVOID);
+DWORD WINAPI GetObjectType(HGDIOBJ);
+UINT WINAPI GetOutlineTextMetricsA(HDC,UINT,LPOUTLINETEXTMETRICA);
+UINT WINAPI GetOutlineTextMetricsW(HDC,UINT,LPOUTLINETEXTMETRICW);
+UINT WINAPI GetPaletteEntries(HPALETTE,UINT,UINT,LPPALETTEENTRY);
+int WINAPI GetPath(HDC,LPPOINT,PBYTE,int);
+COLORREF WINAPI GetPixel(HDC,int,int);
+int WINAPI GetPixelFormat(HDC);
+int WINAPI GetPolyFillMode(HDC);
+BOOL WINAPI GetRasterizerCaps(LPRASTERIZER_STATUS,UINT);
+int WINAPI GetRandomRgn (HDC,HRGN,INT);
+DWORD WINAPI GetRegionData(HRGN,DWORD,LPRGNDATA);
+int WINAPI GetRgnBox(HRGN,LPRECT);
+int WINAPI GetROP2(HDC);
+HGDIOBJ WINAPI GetStockObject(int);
+int WINAPI GetStretchBltMode(HDC);
+UINT WINAPI GetSystemPaletteEntries(HDC,UINT,UINT,LPPALETTEENTRY);
+UINT WINAPI GetSystemPaletteUse(HDC);
+UINT WINAPI GetTextAlign(HDC);
+int WINAPI GetTextCharacterExtra(HDC);
+int WINAPI GetTextCharset(HDC);
+int WINAPI GetTextCharsetInfo(HDC,LPFONTSIGNATURE,DWORD);
+COLORREF WINAPI GetTextColor(HDC);
+BOOL WINAPI GetTextExtentExPointA(HDC,LPCSTR,int,int,LPINT,LPINT,LPSIZE);
+BOOL WINAPI GetTextExtentExPointW( HDC,LPCWSTR,int,int,LPINT,LPINT,LPSIZE );
+BOOL WINAPI GetTextExtentPointA(HDC,LPCSTR,int,LPSIZE);
+BOOL WINAPI GetTextExtentPointW(HDC,LPCWSTR,int,LPSIZE);
+BOOL WINAPI GetTextExtentPoint32A(HDC,LPCSTR,int,LPSIZE);
+BOOL WINAPI GetTextExtentPoint32W( HDC,LPCWSTR,int,LPSIZE);
+int WINAPI GetTextFaceA(HDC,int,LPSTR);
+int WINAPI GetTextFaceW(HDC,int,LPWSTR);
+BOOL WINAPI GetTextMetricsA(HDC,LPTEXTMETRICA);
+BOOL WINAPI GetTextMetricsW(HDC,LPTEXTMETRICW);
+BOOL WINAPI GetViewportExtEx(HDC,LPSIZE);
+BOOL WINAPI GetViewportOrgEx(HDC,LPPOINT);
+BOOL WINAPI GetWindowExtEx(HDC,LPSIZE);
+BOOL WINAPI GetWindowOrgEx(HDC,LPPOINT);
+UINT WINAPI GetWinMetaFileBits(HENHMETAFILE,UINT,LPBYTE,INT,HDC);
+BOOL WINAPI GetWorldTransform(HDC,LPXFORM);
+int WINAPI IntersectClipRect(HDC,int,int,int,int);
+BOOL WINAPI InvertRgn(HDC,HRGN);
+BOOL WINAPI LineDDA(int,int,int,int,LINEDDAPROC,LPARAM);
+BOOL WINAPI LineTo(HDC,int,int);
+BOOL WINAPI LPtoDP(HDC,LPPOINT,int);
+BOOL WINAPI MaskBlt(HDC,int,int,int,int,HDC,int,int,HBITMAP,int,int,DWORD);
+BOOL WINAPI ModifyWorldTransform(HDC,const XFORM*,DWORD);
+BOOL WINAPI MoveToEx(HDC,int,int,LPPOINT);
+int WINAPI OffsetClipRgn(HDC,int,int);
+int WINAPI OffsetRgn(HRGN,int,int);
+BOOL WINAPI OffsetViewportOrgEx(HDC,int,int,LPPOINT);
+BOOL WINAPI OffsetWindowOrgEx(HDC,int,int,LPPOINT);
+BOOL WINAPI PaintRgn(HDC,HRGN);
+BOOL WINAPI PatBlt(HDC,int,int,int,int,DWORD);
+HRGN WINAPI PathToRegion(HDC);
+BOOL WINAPI Pie(HDC,int,int,int,int,int,int,int,int);
+BOOL WINAPI PlayEnhMetaFile(HDC,HENHMETAFILE,LPCRECT);
+BOOL WINAPI PlayEnhMetaFileRecord(HDC,LPHANDLETABLE,const ENHMETARECORD*,UINT);
+BOOL WINAPI PlayMetaFile(HDC,HMETAFILE);
+BOOL WINAPI PlayMetaFileRecord(HDC,LPHANDLETABLE,LPMETARECORD,UINT);
+BOOL WINAPI PlgBlt(HDC,const POINT*,HDC,int,int,int,int,HBITMAP,int,int);
+BOOL WINAPI PolyBezier(HDC,const POINT*,DWORD);
+BOOL WINAPI PolyBezierTo(HDC,const POINT*,DWORD);
+BOOL WINAPI PolyDraw(HDC,const POINT*,const BYTE*,int);
+BOOL WINAPI Polygon(HDC,const POINT*,int);
+BOOL WINAPI Polyline(HDC,const POINT*,int);
+BOOL WINAPI PolylineTo(HDC,const POINT*,DWORD);
+BOOL WINAPI PolyPolygon(HDC,const POINT*,const INT*,int);
+BOOL WINAPI PolyPolyline(HDC,const POINT*,const DWORD*,DWORD);
+BOOL WINAPI PolyTextOutA(HDC,const POLYTEXTA*,int);
+BOOL WINAPI PolyTextOutW(HDC,const POLYTEXTW*,int);
+BOOL WINAPI PtInRegion(HRGN,int,int);
+BOOL WINAPI PtVisible(HDC,int,int);
+UINT WINAPI RealizePalette(HDC);
+BOOL WINAPI Rectangle(HDC,int,int,int,int);
+BOOL WINAPI RectInRegion(HRGN,LPCRECT);
+BOOL WINAPI RectVisible(HDC,LPCRECT);
+BOOL WINAPI RemoveFontResourceA(LPCSTR);
+BOOL WINAPI RemoveFontResourceW(LPCWSTR);
+HDC WINAPI ResetDCA(HDC,const DEVMODEA*);
+HDC WINAPI ResetDCW(HDC,const DEVMODEW*);
+BOOL WINAPI ResizePalette(HPALETTE,UINT);
+BOOL WINAPI RestoreDC(HDC,int);
+BOOL WINAPI RoundRect(HDC,int,int,int,int,int,int);
+int WINAPI SaveDC(HDC);
+BOOL WINAPI ScaleViewportExtEx(HDC,int,int,int,int,LPSIZE);
+BOOL WINAPI ScaleWindowExtEx(HDC,int,int,int,int,LPSIZE);
+BOOL WINAPI SelectClipPath(HDC,int);
+int WINAPI SelectClipRgn(HDC,HRGN);
+HGDIOBJ WINAPI SelectObject(HDC,HGDIOBJ);
+HPALETTE WINAPI SelectPalette(HDC,HPALETTE,BOOL);
+int WINAPI SetAbortProc(HDC,ABORTPROC);
+int WINAPI SetArcDirection(HDC,int);
+LONG WINAPI SetBitmapBits(HBITMAP,DWORD,PCVOID);
+BOOL WINAPI SetBitmapDimensionEx(HBITMAP,int,int,LPSIZE);
+COLORREF WINAPI SetBkColor(HDC,COLORREF);
+int WINAPI SetBkMode(HDC,int);
+UINT WINAPI SetBoundsRect(HDC,LPCRECT,UINT);
+BOOL WINAPI SetBrushOrgEx(HDC,int,int,LPPOINT);
+BOOL WINAPI SetColorAdjustment(HDC,const COLORADJUSTMENT*);
+BOOL WINAPI SetColorSpace(HDC,HCOLORSPACE);
+BOOL WINAPI SetDeviceGammaRamp(HDC,PVOID);
+UINT WINAPI SetDIBColorTable(HDC,UINT,UINT,const RGBQUAD*);
+int WINAPI SetDIBits(HDC,HBITMAP,UINT,UINT,PCVOID,const BITMAPINFO*,UINT);
+int WINAPI SetDIBitsToDevice(HDC,int,int,DWORD,DWORD,int,int,UINT,UINT,PCVOID,const BITMAPINFO*,UINT);
+HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT,const BYTE*);
+int WINAPI SetGraphicsMode(HDC,int);
+int WINAPI SetICMMode(HDC,int);
+BOOL WINAPI SetICMProfileA(HDC,LPSTR);
+BOOL WINAPI SetICMProfileW(HDC,LPWSTR);
+int WINAPI SetMapMode(HDC,int);
+DWORD WINAPI SetMapperFlags(HDC,DWORD);
+HMETAFILE WINAPI SetMetaFileBitsEx(UINT,const BYTE *);
+int WINAPI SetMetaRgn(HDC);
+BOOL WINAPI SetMiterLimit(HDC,FLOAT,PFLOAT);
+UINT WINAPI SetPaletteEntries(HPALETTE,UINT,UINT,const PALETTEENTRY*);
+COLORREF WINAPI SetPixel(HDC,int,int,COLORREF);
+BOOL WINAPI SetPixelFormat(HDC,int,const PIXELFORMATDESCRIPTOR*);
+BOOL WINAPI SetPixelV(HDC,int,int,COLORREF);
+int WINAPI SetPolyFillMode(HDC,int);
+BOOL WINAPI SetRectRgn(HRGN,int,int,int,int);
+int WINAPI SetROP2(HDC,int);
+int WINAPI SetStretchBltMode(HDC,int);
+UINT WINAPI SetSystemPaletteUse(HDC,UINT);
+UINT WINAPI SetTextAlign(HDC,UINT);
+int WINAPI SetTextCharacterExtra(HDC,int);
+COLORREF WINAPI SetTextColor(HDC,COLORREF);
+BOOL WINAPI SetTextJustification(HDC,int,int);
+BOOL WINAPI SetViewportExtEx(HDC,int,int,LPSIZE);
+BOOL WINAPI SetViewportOrgEx(HDC,int,int,LPPOINT);
+BOOL WINAPI SetWindowExtEx(HDC,int,int,LPSIZE);
+BOOL WINAPI SetWindowOrgEx(HDC,int,int,LPPOINT);
+HENHMETAFILE WINAPI SetWinMetaFileBits(UINT,const BYTE*,HDC,const METAFILEPICT*);
+BOOL WINAPI SetWorldTransform(HDC,const XFORM *);
+int WINAPI StartDocA(HDC,const DOCINFOA*);
+int WINAPI StartDocW(HDC,const DOCINFOW*);
+int WINAPI StartPage(HDC);
+BOOL WINAPI StretchBlt(HDC,int,int,int,int,HDC,int,int,int,int,DWORD);
+int WINAPI StretchDIBits(HDC,int,int,int,int,int,int,int,int,const VOID *,const BITMAPINFO *,UINT,DWORD);
+BOOL WINAPI StrokeAndFillPath(HDC);
+BOOL WINAPI StrokePath(HDC);
+BOOL WINAPI SwapBuffers(HDC);
+BOOL WINAPI TextOutA(HDC,int,int,LPCSTR,int);
+BOOL WINAPI TextOutW(HDC,int,int,LPCWSTR,int);
+BOOL WINAPI TranslateCharsetInfo(PDWORD,LPCHARSETINFO,DWORD);
+BOOL WINAPI UnrealizeObject(HGDIOBJ);
+BOOL WINAPI UpdateColors(HDC);
+BOOL WINAPI UpdateICMRegKeyA(DWORD,DWORD,LPSTR,UINT);
+BOOL WINAPI UpdateICMRegKeyW(DWORD,DWORD,LPWSTR,UINT);
+BOOL WINAPI WidenPath(HDC);
+BOOL WINAPI wglCopyContext(HGLRC,HGLRC,UINT);
+HGLRC WINAPI wglCreateContext(HDC);
+HGLRC WINAPI wglCreateLayerContext(HDC,int);
+BOOL WINAPI wglDeleteContext(HGLRC);
+BOOL WINAPI wglDescribeLayerPlane(HDC,int,int,UINT,LPLAYERPLANEDESCRIPTOR);
+HGLRC WINAPI wglGetCurrentContext(void);
+HDC WINAPI wglGetCurrentDC(void);
+int WINAPI wglGetLayerPaletteEntries(HDC,int,int,int,COLORREF*);
+PROC WINAPI wglGetProcAddress(LPCSTR);
+BOOL WINAPI wglMakeCurrent(HDC,HGLRC);
+BOOL WINAPI wglRealizeLayerPalette(HDC,int,BOOL);
+int WINAPI wglSetLayerPaletteEntries(HDC,int,int,int,const COLORREF*);
+BOOL WINAPI wglShareLists(HGLRC,HGLRC);
+BOOL WINAPI wglSwapLayerBuffers(HDC,UINT);
+BOOL WINAPI wglUseFontBitmapsA(HDC,DWORD,DWORD,DWORD);
+BOOL WINAPI wglUseFontBitmapsW(HDC,DWORD,DWORD,DWORD);
+BOOL WINAPI wglUseFontOutlinesA(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT);
+BOOL WINAPI wglUseFontOutlinesW(HDC,DWORD,DWORD,DWORD,FLOAT,FLOAT,int,LPGLYPHMETRICSFLOAT);
+
+#ifdef UNICODE
+typedef WCHAR BCHAR;
+typedef DOCINFOW DOCINFO, *LPDOCINFO;
+typedef LOGFONTW LOGFONT,*PLOGFONT,*LPLOGFONT;
+typedef TEXTMETRICW TEXTMETRIC,*PTEXTMETRIC,*LPTEXTMETRIC;
+#define ICMENUMPROC ICMENUMPROCW
+#define FONTENUMPROC FONTENUMPROCW
+typedef DEVMODEW DEVMODE,*PDEVMODE,*LPDEVMODE;
+typedef EXTLOGFONTW EXTLOGFONT,*PEXTLOGFONT,*LPEXTLOGFONT;
+typedef GCP_RESULTSW GCP_RESULTS,*LPGCP_RESULTS;
+typedef OUTLINETEXTMETRICW OUTLINETEXTMETRIC,*POUTLINETEXTMETRIC,*LPOUTLINETEXTMETRIC;
+typedef POLYTEXTW POLYTEXT;
+typedef LOGCOLORSPACEW LOGCOLORSPACE,*LPLOGCOLORSPACE;
+typedef NEWTEXTMETRICW NEWTEXTMETRIC,*PNEWTEXTMETRIC,*LPNEWTEXTMETRIC;
+typedef NEWTEXTMETRICEXW NEWTEXTMETRICEX;
+typedef ENUMLOGFONTW ENUMLOGFONT,*LPENUMLOGFONT;
+typedef ENUMLOGFONTEXW ENUMLOGFONTEX,*LPENUMLOGFONTEX;
+#define AddFontResource AddFontResourceW
+#define CopyEnhMetaFile CopyEnhMetaFileW
+#define CopyMetaFile CopyMetaFileW
+#define CreateDC CreateDCW
+#define CreateEnhMetaFile CreateEnhMetaFileW
+#define CreateFont CreateFontW
+#define CreateFontIndirect CreateFontIndirectW
+#define CreateIC CreateICW
+#define CreateMetaFile CreateMetaFileW
+#define CreateScalableFontResource CreateScalableFontResourceW
+#define DeviceCapabilities DeviceCapabilitiesW
+#define EnumFontFamilies EnumFontFamiliesW
+#define EnumFontFamiliesEx EnumFontFamiliesExW
+#define EnumFonts EnumFontsW
+#define EnumICMProfiles EnumICMProfilesW
+#define ExtTextOut ExtTextOutW
+#define GetCharABCWidthsFloat GetCharABCWidthsFloatW
+#define GetCharABCWidths GetCharABCWidthsW
+#define GetCharacterPlacement GetCharacterPlacementW
+#define GetCharWidth32 GetCharWidth32W
+#define GetCharWidthFloat GetCharWidthFloatW
+#define GetCharWidth GetCharWidthW
+#define GetEnhMetaFile GetEnhMetaFileW
+#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionW
+#define GetGlyphOutline GetGlyphOutlineW
+#define GetICMProfile GetICMProfileW
+#define GetKerningPairs GetKerningPairsW
+#define GetLogColorSpace GetLogColorSpaceW
+#define GetMetaFile GetMetaFileW
+#define GetObject GetObjectW
+#define GetOutlineTextMetrics GetOutlineTextMetricsW
+#define GetTextExtentPoint GetTextExtentPointW
+#define GetTextExtentExPoint GetTextExtentExPointW
+#define GetTextExtentPoint32 GetTextExtentPoint32W
+#define GetTextFace GetTextFaceW
+#define GetTextMetrics GetTextMetricsW
+#define PolyTextOut PolyTextOutW
+#define RemoveFontResource RemoveFontResourceW
+#define ResetDC ResetDCW
+#define SetICMProfile SetICMProfileW
+#define StartDoc StartDocW
+#define TextOut TextOutW
+#define UpdateICMRegKey UpdateICMRegKeyW
+#define wglUseFontBitmaps wglUseFontBitmapsW
+#define wglUseFontOutlines wglUseFontOutlinesW
+#else
+typedef BYTE BCHAR;
+typedef DOCINFOA DOCINFO, *LPDOCINFO;
+typedef LOGFONTA LOGFONT,*PLOGFONT,*LPLOGFONT;
+typedef TEXTMETRICA TEXTMETRIC,*PTEXTMETRIC,*LPTEXTMETRIC;
+#define ICMENUMPROC ICMENUMPROCA
+#define FONTENUMPROC FONTENUMPROCA
+typedef DEVMODEA DEVMODE,*PDEVMODE,*LPDEVMODE;
+typedef EXTLOGFONTA EXTLOGFONT,*PEXTLOGFONT,*LPEXTLOGFONT;
+typedef GCP_RESULTSA GCP_RESULTS,*LPGCP_RESULTS;
+typedef OUTLINETEXTMETRICA OUTLINETEXTMETRIC,*POUTLINETEXTMETRIC,*LPOUTLINETEXTMETRIC;
+typedef POLYTEXTA POLYTEXT;
+typedef LOGCOLORSPACEA LOGCOLORSPACE,*LPLOGCOLORSPACE;
+typedef NEWTEXTMETRICA NEWTEXTMETRIC,*PNEWTEXTMETRIC,*LPNEWTEXTMETRIC;
+typedef NEWTEXTMETRICEXA NEWTEXTMETRICEX;
+typedef ENUMLOGFONTA ENUMLOGFONT,*LPENUMLOGFONT;
+typedef ENUMLOGFONTEXA ENUMLOGFONTEX,*LPENUMLOGFONTEX;
+#define AddFontResource AddFontResourceA
+#define CopyEnhMetaFile CopyEnhMetaFileA
+#define CopyMetaFile CopyMetaFileA
+#define CreateDC CreateDCA
+#define CreateEnhMetaFile CreateEnhMetaFileA
+#define CreateFont CreateFontA
+#define CreateFontIndirect CreateFontIndirectA
+#define CreateIC CreateICA
+#define CreateMetaFile CreateMetaFileA
+#define CreateScalableFontResource CreateScalableFontResourceA
+#define DeviceCapabilities DeviceCapabilitiesA
+#define EnumFontFamilies EnumFontFamiliesA
+#define EnumFontFamiliesEx EnumFontFamiliesExA
+#define EnumFonts EnumFontsA
+#define EnumICMProfiles EnumICMProfilesA
+#define ExtTextOut ExtTextOutA
+#define GetCharWidthFloat GetCharWidthFloatA
+#define GetCharWidth GetCharWidthA
+#define GetCharacterPlacement GetCharacterPlacementA
+#define GetCharABCWidths GetCharABCWidthsA
+#define GetCharABCWidthsFloat GetCharABCWidthsFloatA
+#define GetCharWidth32 GetCharWidth32A
+#define GetEnhMetaFile GetEnhMetaFileA
+#define GetEnhMetaFileDescription GetEnhMetaFileDescriptionA
+#define GetGlyphOutline GetGlyphOutlineA
+#define GetICMProfile GetICMProfileA
+#define GetKerningPairs GetKerningPairsA
+#define GetLogColorSpace GetLogColorSpaceA
+#define GetMetaFile GetMetaFileA
+#define GetObject GetObjectA
+#define GetOutlineTextMetrics GetOutlineTextMetricsA
+#define GetTextExtentPoint GetTextExtentPointA
+#define GetTextExtentExPoint GetTextExtentExPointA
+#define GetTextExtentPoint32 GetTextExtentPoint32A
+#define GetTextFace GetTextFaceA
+#define GetTextMetrics GetTextMetricsA
+#define PolyTextOut PolyTextOutA
+#define RemoveFontResource RemoveFontResourceA
+#define ResetDC ResetDCA
+#define SetICMProfile SetICMProfileA
+#define StartDoc StartDocA
+#define TextOut TextOutA
+#define UpdateICMRegKey UpdateICMRegKeyA
+#define wglUseFontBitmaps wglUseFontBitmapsA
+#define wglUseFontOutlines wglUseFontOutlinesA
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/winnetwk.h b/tinyc/win32/include/winapi/winnetwk.h
new file mode 100644
index 000000000..662fba9f8
--- /dev/null
+++ b/tinyc/win32/include/winapi/winnetwk.h
@@ -0,0 +1,346 @@
+#ifndef _WINNETWK_H
+#define _WINNETWK_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define WNNC_NET_MSNET      0x00010000
+#define WNNC_NET_LANMAN     0x00020000
+#define WNNC_NET_NETWARE    0x00030000
+#define WNNC_NET_VINES      0x00040000
+#define WNNC_NET_10NET      0x00050000
+#define WNNC_NET_LOCUS      0x00060000
+#define WNNC_NET_SUN_PC_NFS 0x00070000
+#define WNNC_NET_LANSTEP    0x00080000
+#define WNNC_NET_9TILES     0x00090000
+#define WNNC_NET_LANTASTIC  0x000A0000
+#define WNNC_NET_AS400      0x000B0000
+#define WNNC_NET_FTP_NFS    0x000C0000
+#define WNNC_NET_PATHWORKS  0x000D0000
+#define WNNC_NET_LIFENET    0x000E0000
+#define WNNC_NET_POWERLAN   0x000F0000
+#define WNNC_NET_BWNFS      0x00100000
+#define WNNC_NET_COGENT     0x00110000
+#define WNNC_NET_FARALLON	0x00120000
+#define WNNC_NET_APPLETALK	0x00130000
+#define WNNC_NET_INTERGRAPH	0x00140000
+#define WNNC_NET_SYMFONET   0x00150000
+#define WNNC_NET_CLEARCASE  0x00160000
+#define WNNC_NET_FRONTIER   0x00170000
+#define WNNC_NET_BMC        0x00180000
+#define WNNC_NET_DCE        0x00190000
+#define WNNC_NET_AVID       0x001A0000
+#define WNNC_NET_DOCUSPACE  0x001B0000
+#define WNNC_NET_MANGOSOFT  0x001C0000
+#define WNNC_NET_SERNET     0x001D0000
+#define WNNC_NET_DECORB     0x00200000
+#define WNNC_NET_PROTSTOR   0x00210000
+#define WNNC_NET_FJ_REDIR   0x00220000
+#define WNNC_NET_DISTINCT   0x00230000
+#define WNNC_NET_TWINS      0x00240000
+#define WNNC_NET_RDR2SAMPLE 0x00250000
+#define WNNC_NET_CSC        0x00260000
+#define WNNC_NET_3IN1       0x00270000
+#define WNNC_NET_EXTENDNET  0x00290000
+#define WNNC_NET_OBJECT_DIRE 0x00300000
+#define WNNC_NET_MASFAX     0x00310000
+#define WNNC_NET_HOB_NFS    0x00320000
+#define WNNC_NET_SHIVA      0x00330000
+#define WNNC_NET_IBMAL      0x00340000
+#define WNNC_CRED_MANAGER   0xFFFF0000
+
+#define RESOURCE_CONNECTED 1
+#define RESOURCE_GLOBALNET 2
+#define RESOURCE_REMEMBERED 3
+#define RESOURCE_RECENT 4
+#define RESOURCE_CONTEXT 5
+#define RESOURCETYPE_ANY 0
+#define RESOURCETYPE_DISK 1
+#define RESOURCETYPE_PRINT 2
+#define RESOURCETYPE_RESERVED 8
+#define RESOURCETYPE_UNKNOWN        0xFFFFFFFF
+#define RESOURCEUSAGE_CONNECTABLE   0x00000001
+#define RESOURCEUSAGE_CONTAINER     0x00000002
+#define RESOURCEUSAGE_NOLOCALDEVICE 0x00000004
+#define RESOURCEUSAGE_SIBLING       0x00000008
+#define RESOURCEUSAGE_ATTACHED      0x00000010
+#define RESOURCEUSAGE_ALL           (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED)
+#define RESOURCEUSAGE_RESERVED      0x80000000
+#define RESOURCEDISPLAYTYPE_GENERIC 0
+#define RESOURCEDISPLAYTYPE_DOMAIN 1
+#define RESOURCEDISPLAYTYPE_SERVER 2
+#define RESOURCEDISPLAYTYPE_SHARE 3
+#define RESOURCEDISPLAYTYPE_FILE 4
+#define RESOURCEDISPLAYTYPE_GROUP 5
+#define RESOURCEDISPLAYTYPE_NETWORK 6
+#define RESOURCEDISPLAYTYPE_ROOT 7
+#define RESOURCEDISPLAYTYPE_SHAREADMIN 8
+#define RESOURCEDISPLAYTYPE_DIRECTORY 9
+#define RESOURCEDISPLAYTYPE_TREE 10
+#define NETPROPERTY_PERSISTENT 1
+#define CONNECT_UPDATE_PROFILE 1
+#define CONNECT_UPDATE_RECENT 2
+#define CONNECT_TEMPORARY 4
+#define CONNECT_INTERACTIVE 8
+#define CONNECT_PROMPT 16
+#define CONNECT_NEED_DRIVE 32
+#define CONNECT_REFCOUNT 64
+#define CONNECT_REDIRECT 128
+#define CONNECT_LOCALDRIVE 256
+#define CONNECT_CURRENT_MEDIA 512
+#define CONNDLG_RO_PATH 1
+#define CONNDLG_CONN_POINT 2
+#define CONNDLG_USE_MRU 4
+#define CONNDLG_HIDE_BOX 8
+#define CONNDLG_PERSIST 16
+#define CONNDLG_NOT_PERSIST 32
+#define DISC_UPDATE_PROFILE 1
+#define DISC_NO_FORCE 64
+#define WNFMT_MULTILINE 1
+#define WNFMT_ABBREVIATED 2
+#define WNFMT_INENUM 16
+#define WNFMT_CONNECTION 32
+#define WN_SUCCESS NO_ERROR
+#define WN_NO_ERROR NO_ERROR
+#define WN_NOT_SUPPORTED ERROR_NOT_SUPPORTED
+#define WN_CANCEL ERROR_CANCELLED
+#define WN_RETRY ERROR_RETRY
+#define WN_NET_ERROR ERROR_UNEXP_NET_ERR
+#define WN_MORE_DATA ERROR_MORE_DATA
+#define WN_BAD_POINTER ERROR_INVALID_ADDRESS
+#define WN_BAD_VALUE ERROR_INVALID_PARAMETER
+#define WN_BAD_USER ERROR_BAD_USERNAME
+#define WN_BAD_PASSWORD ERROR_INVALID_PASSWORD
+#define WN_ACCESS_DENIED ERROR_ACCESS_DENIED
+#define WN_FUNCTION_BUSY ERROR_BUSY
+#define WN_WINDOWS_ERROR ERROR_UNEXP_NET_ERR
+#define WN_OUT_OF_MEMORY ERROR_NOT_ENOUGH_MEMORY
+#define WN_NO_NETWORK ERROR_NO_NETWORK
+#define WN_EXTENDED_ERROR ERROR_EXTENDED_ERROR
+#define WN_BAD_LEVEL ERROR_INVALID_LEVEL
+#define WN_BAD_HANDLE ERROR_INVALID_HANDLE
+#define WN_NOT_INITIALIZING ERROR_ALREADY_INITIALIZED
+#define WN_NO_MORE_DEVICES ERROR_NO_MORE_DEVICES
+#define WN_NOT_CONNECTED ERROR_NOT_CONNECTED
+#define WN_OPEN_FILES ERROR_OPEN_FILES
+#define WN_DEVICE_IN_USE ERROR_DEVICE_IN_USE
+#define WN_BAD_NETNAME ERROR_BAD_NET_NAME
+#define WN_BAD_LOCALNAME ERROR_BAD_DEVICE
+#define WN_ALREADY_CONNECTED ERROR_ALREADY_ASSIGNED
+#define WN_DEVICE_ERROR ERROR_GEN_FAILURE
+#define WN_CONNECTION_CLOSED ERROR_CONNECTION_UNAVAIL
+#define WN_NO_NET_OR_BAD_PATH ERROR_NO_NET_OR_BAD_PATH
+#define WN_BAD_PROVIDER ERROR_BAD_PROVIDER
+#define WN_CANNOT_OPEN_PROFILE ERROR_CANNOT_OPEN_PROFILE
+#define WN_BAD_PROFILE ERROR_BAD_PROFILE
+#define WN_BAD_DEV_TYPE ERROR_BAD_DEV_TYPE
+#define WN_DEVICE_ALREADY_REMEMBERED ERROR_DEVICE_ALREADY_REMEMBERED
+#define WN_NO_MORE_ENTRIES ERROR_NO_MORE_ITEMS
+#define WN_NOT_CONTAINER ERROR_NOT_CONTAINER
+#define WN_NOT_AUTHENTICATED ERROR_NOT_AUTHENTICATED
+#define WN_NOT_LOGGED_ON ERROR_NOT_LOGGED_ON
+#define WN_NOT_VALIDATED ERROR_NO_LOGON_SERVERS
+#define UNIVERSAL_NAME_INFO_LEVEL 1
+#define REMOTE_NAME_INFO_LEVEL 2
+#define NETINFO_DLL16 1
+#define NETINFO_DISKRED 4
+#define NETINFO_PRINTERRED 8
+#define RP_LOGON 1
+#define RP_INIFILE 2
+#define PP_DISPLAYERRORS 1
+#define WNCON_FORNETCARD 1
+#define WNCON_NOTROUTED 2
+#define WNCON_SLOWLINK 4
+#define WNCON_DYNAMIC 8
+
+#ifndef RC_INVOKED
+typedef struct _NETRESOURCEA {
+	DWORD dwScope;
+	DWORD dwType;
+	DWORD dwDisplayType;
+	DWORD dwUsage;
+	LPSTR lpLocalName;
+	LPSTR lpRemoteName;
+	LPSTR lpComment ;
+	LPSTR lpProvider;
+}NETRESOURCEA,*LPNETRESOURCEA;
+typedef struct _NETRESOURCEW {
+	DWORD dwScope;
+	DWORD dwType;
+	DWORD dwDisplayType;
+	DWORD dwUsage;
+	LPWSTR lpLocalName;
+	LPWSTR lpRemoteName;
+	LPWSTR lpComment ;
+	LPWSTR lpProvider;
+}NETRESOURCEW,*LPNETRESOURCEW;
+typedef struct _CONNECTDLGSTRUCTA{
+	DWORD cbStructure;
+	HWND hwndOwner;
+	LPNETRESOURCEA lpConnRes;
+	DWORD dwFlags;
+	DWORD dwDevNum;
+} CONNECTDLGSTRUCTA,*LPCONNECTDLGSTRUCTA;
+typedef struct _CONNECTDLGSTRUCTW{
+	DWORD cbStructure;
+	HWND hwndOwner;
+	LPNETRESOURCEW lpConnRes;
+	DWORD dwFlags;
+	DWORD dwDevNum;
+} CONNECTDLGSTRUCTW,*LPCONNECTDLGSTRUCTW;
+typedef struct _DISCDLGSTRUCTA{
+	DWORD cbStructure;
+	HWND hwndOwner;
+	LPSTR lpLocalName;
+	LPSTR lpRemoteName;
+	DWORD dwFlags;
+} DISCDLGSTRUCTA,*LPDISCDLGSTRUCTA;
+typedef struct _DISCDLGSTRUCTW{
+	DWORD cbStructure;
+	HWND hwndOwner;
+	LPWSTR lpLocalName;
+	LPWSTR lpRemoteName;
+	DWORD dwFlags;
+} DISCDLGSTRUCTW,*LPDISCDLGSTRUCTW;
+typedef struct _UNIVERSAL_NAME_INFOA { LPSTR lpUniversalName; }UNIVERSAL_NAME_INFOA,*LPUNIVERSAL_NAME_INFOA;
+typedef struct _UNIVERSAL_NAME_INFOW { LPWSTR lpUniversalName; }UNIVERSAL_NAME_INFOW,*LPUNIVERSAL_NAME_INFOW;
+typedef struct _REMOTE_NAME_INFOA {
+	LPSTR lpUniversalName;
+	LPSTR lpConnectionName;
+	LPSTR lpRemainingPath;
+}REMOTE_NAME_INFOA,*LPREMOTE_NAME_INFOA;
+typedef struct _REMOTE_NAME_INFOW {
+	LPWSTR lpUniversalName;
+	LPWSTR lpConnectionName;
+	LPWSTR lpRemainingPath;
+}REMOTE_NAME_INFOW,*LPREMOTE_NAME_INFOW;
+typedef struct _NETINFOSTRUCT{
+	DWORD cbStructure;
+	DWORD dwProviderVersion;
+	DWORD dwStatus;
+	DWORD dwCharacteristics;
+	DWORD dwHandle;
+	WORD wNetType;
+	DWORD dwPrinters;
+	DWORD dwDrives;
+} NETINFOSTRUCT,*LPNETINFOSTRUCT;
+typedef UINT(PASCAL *PFNGETPROFILEPATHA)(LPCSTR,LPSTR,UINT);
+typedef UINT(PASCAL *PFNGETPROFILEPATHW)(LPCWSTR,LPWSTR,UINT);
+typedef UINT(PASCAL *PFNRECONCILEPROFILEA)(LPCSTR,LPCSTR,DWORD);
+typedef UINT(PASCAL *PFNRECONCILEPROFILEW)(LPCWSTR,LPCWSTR,DWORD);
+typedef BOOL(PASCAL *PFNPROCESSPOLICIESA)(HWND,LPCSTR,LPCSTR,LPCSTR,DWORD);
+typedef BOOL(PASCAL *PFNPROCESSPOLICIESW)(HWND,LPCWSTR,LPCWSTR,LPCWSTR,DWORD);
+typedef struct _NETCONNECTINFOSTRUCT{
+	DWORD cbStructure;
+	DWORD dwFlags;
+	DWORD dwSpeed;
+	DWORD dwDelay;
+	DWORD dwOptDataSize;
+} NETCONNECTINFOSTRUCT,*LPNETCONNECTINFOSTRUCT;
+
+DWORD APIENTRY WNetAddConnectionA(LPCSTR,LPCSTR,LPCSTR);
+DWORD APIENTRY WNetAddConnectionW(LPCWSTR,LPCWSTR,LPCWSTR);
+DWORD APIENTRY WNetAddConnection2A(LPNETRESOURCEA,LPCSTR,LPCSTR,DWORD);
+DWORD APIENTRY WNetAddConnection2W(LPNETRESOURCEW,LPCWSTR,LPCWSTR,DWORD);
+DWORD APIENTRY WNetAddConnection3A(HWND,LPNETRESOURCEA,LPCSTR,LPCSTR,DWORD);
+DWORD APIENTRY WNetAddConnection3W(HWND,LPNETRESOURCEW,LPCWSTR,LPCWSTR,DWORD);
+DWORD APIENTRY WNetCancelConnectionA(LPCSTR,BOOL);
+DWORD APIENTRY WNetCancelConnectionW(LPCWSTR,BOOL);
+DWORD APIENTRY WNetCancelConnection2A(LPCSTR,DWORD,BOOL);
+DWORD APIENTRY WNetCancelConnection2W(LPCWSTR,DWORD,BOOL);
+DWORD APIENTRY WNetGetConnectionA(LPCSTR,LPSTR,PDWORD);
+DWORD APIENTRY WNetGetConnectionW(LPCWSTR,LPWSTR,PDWORD);
+DWORD APIENTRY WNetUseConnectionA(HWND,LPNETRESOURCEA,LPCSTR,LPCSTR,DWORD,LPSTR,PDWORD,PDWORD);
+DWORD APIENTRY WNetUseConnectionW(HWND,LPNETRESOURCEW,LPCWSTR,LPCWSTR,DWORD,LPWSTR,PDWORD,PDWORD);
+DWORD APIENTRY WNetSetConnectionA(LPCSTR,DWORD,PVOID);
+DWORD APIENTRY WNetSetConnectionW(LPCWSTR,DWORD,PVOID);
+DWORD APIENTRY WNetConnectionDialog(HWND,DWORD);
+DWORD APIENTRY WNetDisconnectDialog(HWND,DWORD);
+DWORD APIENTRY WNetConnectionDialog1A(LPCONNECTDLGSTRUCTA);
+DWORD APIENTRY WNetConnectionDialog1W(LPCONNECTDLGSTRUCTW);
+DWORD APIENTRY WNetDisconnectDialog1A(LPDISCDLGSTRUCTA);
+DWORD APIENTRY WNetDisconnectDialog1W(LPDISCDLGSTRUCTW);
+DWORD APIENTRY WNetOpenEnumA(DWORD,DWORD,DWORD,LPNETRESOURCEA,LPHANDLE);
+DWORD APIENTRY WNetOpenEnumW(DWORD,DWORD,DWORD,LPNETRESOURCEW,LPHANDLE);
+DWORD APIENTRY WNetEnumResourceA(HANDLE,PDWORD,PVOID,PDWORD);
+DWORD APIENTRY WNetEnumResourceW(HANDLE,PDWORD,PVOID,PDWORD);
+DWORD APIENTRY WNetCloseEnum(HANDLE);
+DWORD APIENTRY WNetGetUniversalNameA(LPCSTR,DWORD,PVOID,PDWORD);
+DWORD APIENTRY WNetGetUniversalNameW(LPCWSTR,DWORD,PVOID,PDWORD);
+DWORD APIENTRY WNetGetUserA(LPCSTR,LPSTR,PDWORD);
+DWORD APIENTRY WNetGetUserW(LPCWSTR,LPWSTR,PDWORD);
+DWORD APIENTRY WNetGetProviderNameA(DWORD,LPSTR,PDWORD);
+DWORD APIENTRY WNetGetProviderNameW(DWORD,LPWSTR,PDWORD);
+DWORD APIENTRY WNetGetNetworkInformationA(LPCSTR,LPNETINFOSTRUCT);
+DWORD APIENTRY WNetGetNetworkInformationW(LPCWSTR,LPNETINFOSTRUCT);
+DWORD APIENTRY WNetGetResourceInformationA(LPNETRESOURCEA,LPVOID,LPDWORD,LPCSTR*);
+DWORD APIENTRY WNetGetResourceInformationW(LPNETRESOURCEA,LPVOID,LPDWORD,LPCWSTR*);
+DWORD APIENTRY WNetGetLastErrorA(PDWORD,LPSTR,DWORD,LPSTR,DWORD);
+DWORD APIENTRY WNetGetLastErrorW(PDWORD,LPWSTR,DWORD,LPWSTR,DWORD);
+DWORD APIENTRY MultinetGetConnectionPerformanceA(LPNETRESOURCEA,LPNETCONNECTINFOSTRUCT);
+DWORD APIENTRY MultinetGetConnectionPerformanceW(LPNETRESOURCEW,LPNETCONNECTINFOSTRUCT);
+#ifdef UNICODE
+#define PFNPROCESSPOLICIES PFNPROCESSPOLICIESW
+#define PFNRECONCILEPROFILE PFNRECONCILEPROFILEW
+#define PFNGETPROFILEPATH PFNGETPROFILEPATHW
+typedef NETRESOURCEW NETRESOURCE,*LPNETRESOURCE;
+typedef CONNECTDLGSTRUCTW CONNECTDLGSTRUCT,*LPCONNECTDLGSTRUCT;
+typedef DISCDLGSTRUCTW DISCDLGSTRUCT,*LPDISCDLGSTRUCT;
+typedef REMOTE_NAME_INFOW REMOTE_NAME_INFO,*LPREMOTE_NAME_INFO;
+typedef UNIVERSAL_NAME_INFOW UNIVERSAL_NAME_INFO,*LPUNIVERSAL_NAME_INFO;
+#define WNetEnumResource WNetEnumResourceW
+#define WNetOpenEnum WNetOpenEnumW
+#define WNetGetResourceInformation WNetGetResourceInformationW
+#define WNetGetUniversalName WNetGetUniversalNameW
+#define WNetSetConnection WNetSetConnectionW
+#define WNetUseConnection WNetUseConnectionW
+#define WNetGetConnection WNetGetConnectionW
+#define WNetCancelConnection2 WNetCancelConnection2W
+#define WNetCancelConnection WNetCancelConnectionW
+#define WNetAddConnection3 WNetAddConnection3W
+#define WNetAddConnection2 WNetAddConnection2W
+#define WNetAddConnection WNetAddConnectionW
+#define WNetConnectionDialog1 WNetConnectionDialog1W
+#define WNetDisconnectDialog1 WNetDisconnectDialog1W
+#define WNetGetNetworkInformation WNetGetNetworkInformationW
+#define WNetGetProviderName WNetGetProviderNameW
+#define WNetGetUser WNetGetUserW
+#define MultinetGetConnectionPerformance MultinetGetConnectionPerformanceW
+#define WNetGetLastError WNetGetLastErrorW
+#else
+#define PFNGETPROFILEPATH PFNGETPROFILEPATHA
+#define PFNRECONCILEPROFILE PFNRECONCILEPROFILEA
+#define PFNPROCESSPOLICIES PFNPROCESSPOLICIESA
+typedef NETRESOURCEA NETRESOURCE,*LPNETRESOURCE;
+typedef CONNECTDLGSTRUCTA CONNECTDLGSTRUCT,*LPCONNECTDLGSTRUCT;
+typedef DISCDLGSTRUCTA DISCDLGSTRUCT,*LPDISCDLGSTRUCT;
+typedef UNIVERSAL_NAME_INFOA UNIVERSAL_NAME_INFO,*LPUNIVERSAL_NAME_INFO;
+typedef REMOTE_NAME_INFOA REMOTE_NAME_INFO,*LPREMOTE_NAME_INFO;
+#define WNetOpenEnum WNetOpenEnumA
+#define WNetEnumResource WNetEnumResourceA
+#define WNetGetResourceInformation WNetGetResourceInformationA
+#define WNetGetUniversalName WNetGetUniversalNameA
+#define WNetConnectionDialog1 WNetConnectionDialog1A
+#define WNetDisconnectDialog1 WNetDisconnectDialog1A
+#define WNetAddConnection2 WNetAddConnection2A
+#define WNetAddConnection3 WNetAddConnection3A
+#define WNetCancelConnection WNetCancelConnectionA
+#define WNetCancelConnection2 WNetCancelConnection2A
+#define WNetGetConnection WNetGetConnectionA
+#define WNetUseConnection WNetUseConnectionA
+#define WNetSetConnection WNetSetConnectionA
+#define WNetAddConnection WNetAddConnectionA
+#define WNetGetUser WNetGetUserA
+#define WNetGetProviderName WNetGetProviderNameA
+#define WNetGetNetworkInformation WNetGetNetworkInformationA
+#define WNetGetLastError WNetGetLastErrorA
+#define MultinetGetConnectionPerformance MultinetGetConnectionPerformanceA
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/winnls.h b/tinyc/win32/include/winapi/winnls.h
new file mode 100644
index 000000000..3933812b7
--- /dev/null
+++ b/tinyc/win32/include/winapi/winnls.h
@@ -0,0 +1,651 @@
+#ifndef _WINNLS_H
+#define _WINNLS_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_LEADBYTES 	12
+#define MAX_DEFAULTCHAR	2
+#define LOCALE_NOUSEROVERRIDE	0x80000000
+#define LOCALE_USE_CP_ACP	0x40000000
+#define LOCALE_ILANGUAGE	1
+#define LOCALE_SLANGUAGE	2
+#define LOCALE_SENGLANGUAGE	0x1001
+#define LOCALE_SABBREVLANGNAME	3
+#define LOCALE_SNATIVELANGNAME	4
+#define LOCALE_ICOUNTRY	5
+#define LOCALE_SCOUNTRY	6
+#define LOCALE_SENGCOUNTRY	0x1002
+#define LOCALE_SABBREVCTRYNAME	7
+#define LOCALE_SNATIVECTRYNAME	8
+#define LOCALE_IDEFAULTLANGUAGE	9
+#define LOCALE_IDEFAULTCOUNTRY	10
+#define LOCALE_IDEFAULTCODEPAGE	11
+#define LOCALE_IDEFAULTANSICODEPAGE 0x1004
+#define LOCALE_SLIST	12
+#define LOCALE_IMEASURE	13
+#define LOCALE_SDECIMAL	14
+#define LOCALE_STHOUSAND	15
+#define LOCALE_SGROUPING	16
+#define LOCALE_IDIGITS	17
+#define LOCALE_ILZERO	18
+#define LOCALE_INEGNUMBER	0x1010
+#define LOCALE_SNATIVEDIGITS	19
+#define LOCALE_SCURRENCY	20
+#define LOCALE_SINTLSYMBOL	21
+#define LOCALE_SMONDECIMALSEP	22
+#define LOCALE_SMONTHOUSANDSEP	23
+#define LOCALE_SMONGROUPING	24
+#define LOCALE_ICURRDIGITS	25
+#define LOCALE_IINTLCURRDIGITS	26
+#define LOCALE_ICURRENCY	27
+#define LOCALE_INEGCURR	28
+#define LOCALE_SDATE	29
+#define LOCALE_STIME	30
+#define LOCALE_SSHORTDATE	31
+#define LOCALE_SLONGDATE	32
+#define LOCALE_STIMEFORMAT	0x1003
+#define LOCALE_IDATE	33
+#define LOCALE_ILDATE	34
+#define LOCALE_ITIME	35
+#define LOCALE_ITIMEMARKPOSN	0x1005
+#define LOCALE_ICENTURY	36
+#define LOCALE_ITLZERO	37
+#define LOCALE_IDAYLZERO	38
+#define LOCALE_IMONLZERO	39
+#define LOCALE_S1159	40
+#define LOCALE_S2359	41
+#define LOCALE_ICALENDARTYPE	0x1009
+#define LOCALE_IOPTIONALCALENDAR	0x100B
+#define LOCALE_IFIRSTDAYOFWEEK	0x100C
+#define LOCALE_IFIRSTWEEKOFYEAR	0x100D
+#define LOCALE_SDAYNAME1	42
+#define LOCALE_SDAYNAME2	43
+#define LOCALE_SDAYNAME3	44
+#define LOCALE_SDAYNAME4	45
+#define LOCALE_SDAYNAME5	46
+#define LOCALE_SDAYNAME6	47
+#define LOCALE_SDAYNAME7	48
+#define LOCALE_SABBREVDAYNAME1	49
+#define LOCALE_SABBREVDAYNAME2	50
+#define LOCALE_SABBREVDAYNAME3	51
+#define LOCALE_SABBREVDAYNAME4	52
+#define LOCALE_SABBREVDAYNAME5	53
+#define LOCALE_SABBREVDAYNAME6	54
+#define LOCALE_SABBREVDAYNAME7	55
+#define LOCALE_SMONTHNAME1	56
+#define LOCALE_SMONTHNAME2	57
+#define LOCALE_SMONTHNAME3	58
+#define LOCALE_SMONTHNAME4	59
+#define LOCALE_SMONTHNAME5	60
+#define LOCALE_SMONTHNAME6	61
+#define LOCALE_SMONTHNAME7	62
+#define LOCALE_SMONTHNAME8	63
+#define LOCALE_SMONTHNAME9	64
+#define LOCALE_SMONTHNAME10	65
+#define LOCALE_SMONTHNAME11	66
+#define LOCALE_SMONTHNAME12	67
+#define LOCALE_SMONTHNAME13	0x100E
+#define LOCALE_SABBREVMONTHNAME1	68
+#define LOCALE_SABBREVMONTHNAME2	69
+#define LOCALE_SABBREVMONTHNAME3	70
+#define LOCALE_SABBREVMONTHNAME4	71
+#define LOCALE_SABBREVMONTHNAME5	72
+#define LOCALE_SABBREVMONTHNAME6	73
+#define LOCALE_SABBREVMONTHNAME7	74
+#define LOCALE_SABBREVMONTHNAME8	75
+#define LOCALE_SABBREVMONTHNAME9	76
+#define LOCALE_SABBREVMONTHNAME10	77
+#define LOCALE_SABBREVMONTHNAME11	78
+#define LOCALE_SABBREVMONTHNAME12	79
+#define LOCALE_SABBREVMONTHNAME13	0x100F
+#define LOCALE_SPOSITIVESIGN	80
+#define LOCALE_SNEGATIVESIGN	81
+#define LOCALE_IPOSSIGNPOSN	82
+#define LOCALE_INEGSIGNPOSN	83
+#define LOCALE_IPOSSYMPRECEDES	84
+#define LOCALE_IPOSSEPBYSPACE	85
+#define LOCALE_INEGSYMPRECEDES	86
+#define LOCALE_INEGSEPBYSPACE	87
+#define LOCALE_FONTSIGNATURE	88
+#define LOCALE_SISO639LANGNAME 89
+#define LOCALE_SISO3166CTRYNAME 90
+#define LOCALE_SYSTEM_DEFAULT	0x800
+#define LOCALE_USER_DEFAULT	0x400
+#define NORM_IGNORECASE	1
+#define NORM_IGNOREKANATYPE	65536
+#define NORM_IGNORENONSPACE	2
+#define NORM_IGNORESYMBOLS	4
+#define NORM_IGNOREWIDTH	131072
+#define SORT_STRINGSORT	4096
+#define LCMAP_LOWERCASE 0x00000100
+#define LCMAP_UPPERCASE 0x00000200
+#define LCMAP_SORTKEY 0x00000400
+#define LCMAP_BYTEREV 0x00000800
+#define LCMAP_HIRAGANA 0x00100000
+#define LCMAP_KATAKANA 0x00200000
+#define LCMAP_HALFWIDTH 0x00400000
+#define LCMAP_FULLWIDTH 0x00800000
+#define LCMAP_LINGUISTIC_CASING 0x01000000
+#define LCMAP_SIMPLIFIED_CHINESE 0x02000000
+#define LCMAP_TRADITIONAL_CHINESE 0x04000000
+#define ENUM_ALL_CALENDARS (-1)
+#define DATE_SHORTDATE 1
+#define DATE_LONGDATE 2
+#define DATE_USE_ALT_CALENDAR 4
+#define CP_INSTALLED 1
+#define CP_SUPPORTED 2
+#define LCID_INSTALLED 1
+#define LCID_SUPPORTED 2
+#define LCID_ALTERNATE_SORTS 4
+#define MAP_FOLDCZONE 16
+#define MAP_FOLDDIGITS 128
+#define MAP_PRECOMPOSED 32
+#define MAP_COMPOSITE 64
+#define CP_ACP 0
+#define CP_OEMCP 1
+#define CP_MACCP 2
+#define CP_THREAD_ACP 3
+#define CP_SYMBOL 42
+#define CP_UTF7 65000
+#define CP_UTF8 65001
+#define CT_CTYPE1 1
+#define CT_CTYPE2 2
+#define CT_CTYPE3 4
+#define C1_UPPER 1
+#define C1_LOWER 2
+#define C1_DIGIT 4
+#define C1_SPACE 8
+#define C1_PUNCT 16
+#define C1_CNTRL 32
+#define C1_BLANK 64
+#define C1_XDIGIT 128
+#define C1_ALPHA 256
+#define C2_LEFTTORIGHT 1
+#define C2_RIGHTTOLEFT 2
+#define C2_EUROPENUMBER 3
+#define C2_EUROPESEPARATOR 4
+#define C2_EUROPETERMINATOR 5
+#define C2_ARABICNUMBER 6
+#define C2_COMMONSEPARATOR 7
+#define C2_BLOCKSEPARATOR 8
+#define C2_SEGMENTSEPARATOR 9
+#define C2_WHITESPACE 10
+#define C2_OTHERNEUTRAL 11
+#define C2_NOTAPPLICABLE 0
+#define C3_NONSPACING 1
+#define C3_DIACRITIC 2
+#define C3_VOWELMARK 4
+#define C3_SYMBOL 8
+#define C3_KATAKANA 16
+#define C3_HIRAGANA 32
+#define C3_HALFWIDTH 64
+#define C3_FULLWIDTH 128
+#define C3_IDEOGRAPH 256
+#define C3_KASHIDA 512
+#define C3_LEXICAL 1024
+#define C3_ALPHA 32768
+#define C3_NOTAPPLICABLE 0
+#define TIME_NOMINUTESORSECONDS 1
+#define TIME_NOSECONDS 2
+#define TIME_NOTIMEMARKER 4
+#define TIME_FORCE24HOURFORMAT 8
+#define MB_PRECOMPOSED 1
+#define MB_COMPOSITE 2
+#define MB_ERR_INVALID_CHARS 8
+#define MB_USEGLYPHCHARS 4
+#define WC_COMPOSITECHECK 512
+#define WC_DISCARDNS 16
+#define WC_SEPCHARS 32
+#define WC_DEFAULTCHAR 64
+#define CTRY_DEFAULT 0
+#define CTRY_ALBANIA 355
+#define CTRY_ALGERIA 213
+#define CTRY_ARGENTINA 54
+#define CTRY_ARMENIA 374
+#define CTRY_AUSTRALIA 61
+#define CTRY_AUSTRIA 43
+#define CTRY_AZERBAIJAN 994
+#define CTRY_BAHRAIN 973
+#define CTRY_BELARUS 375
+#define CTRY_BELGIUM 32
+#define CTRY_BELIZE 501
+#define CTRY_BOLIVIA 591
+#define CTRY_BRAZIL 55
+#define CTRY_BRUNEI_DARUSSALAM 673
+#define CTRY_BULGARIA 359
+#define CTRY_CANADA 2
+#define CTRY_CARIBBEAN 1
+#define CTRY_CHILE 56
+#define CTRY_COLOMBIA 57
+#define CTRY_COSTA_RICA 506
+#define CTRY_CROATIA 385
+#define CTRY_CZECH 420
+#define CTRY_DENMARK 45
+#define CTRY_DOMINICAN_REPUBLIC 1
+#define CTRY_ECUADOR 593
+#define CTRY_EGYPT 20
+#define CTRY_EL_SALVADOR 503
+#define CTRY_ESTONIA 372
+#define CTRY_FAEROE_ISLANDS 298
+#define CTRY_FINLAND 358
+#define CTRY_FRANCE 33
+#define CTRY_GEORGIA 995
+#define CTRY_GERMANY 49
+#define CTRY_GREECE 30
+#define CTRY_GUATEMALA 502
+#define CTRY_HONDURAS 504
+#define CTRY_HONG_KONG 852
+#define CTRY_HUNGARY 36
+#define CTRY_ICELAND 354
+#define CTRY_INDIA 91
+#define CTRY_INDONESIA 62
+#define CTRY_IRAN 981
+#define CTRY_IRAQ 964
+#define CTRY_IRELAND 353
+#define CTRY_ISRAEL 972
+#define CTRY_ITALY 39
+#define CTRY_JAMAICA 1
+#define CTRY_JAPAN 81
+#define CTRY_JORDAN 962
+#define CTRY_KAZAKSTAN 7
+#define CTRY_KENYA 254
+#define CTRY_KUWAIT 965
+#define CTRY_LATVIA 371
+#define CTRY_LEBANON 961
+#define CTRY_LIBYA 218
+#define CTRY_LIECHTENSTEIN 41
+#define CTRY_LITHUANIA 370
+#define CTRY_LUXEMBOURG 352
+#define CTRY_MACAU 853
+#define CTRY_MACEDONIA 389
+#define CTRY_MALAYSIA 60
+#define CTRY_MEXICO 52
+#define CTRY_MONACO 33
+#define CTRY_MOROCCO 212
+#define CTRY_NETHERLANDS 31
+#define CTRY_NEW_ZEALAND 64
+#define CTRY_NICARAGUA 505
+#define CTRY_NORWAY 47
+#define CTRY_OMAN 968
+#define CTRY_PAKISTAN 92
+#define CTRY_PANAMA 507
+#define CTRY_PARAGUAY 595
+#define CTRY_PERU 51
+#define CTRY_PHILIPPINES 63
+#define CTRY_POLAND 48
+#define CTRY_PORTUGAL 351
+#define CTRY_PRCHINA 86
+#define CTRY_PUERTO_RICO 1
+#define CTRY_QATAR 974
+#define CTRY_ROMANIA 40
+#define CTRY_RUSSIA 7
+#define CTRY_SAUDI_ARABIA 966
+#define CTRY_SERBIA 381
+#define CTRY_SINGAPORE 65
+#define CTRY_SLOVAK 421
+#define CTRY_SLOVENIA 386
+#define CTRY_SOUTH_AFRICA 27
+#define CTRY_SOUTH_KOREA 82
+#define CTRY_SPAIN 34
+#define CTRY_SWEDEN 46
+#define CTRY_SWITZERLAND 41
+#define CTRY_SYRIA 963
+#define CTRY_TAIWAN 886
+#define CTRY_TATARSTAN 7
+#define CTRY_THAILAND 66
+#define CTRY_TRINIDAD_Y_TOBAGO 1
+#define CTRY_TUNISIA 216
+#define CTRY_TURKEY 90
+#define CTRY_UAE 971
+#define CTRY_UKRAINE 380
+#define CTRY_UNITED_KINGDOM 44
+#define CTRY_UNITED_STATES 1
+#define CTRY_URUGUAY 598
+#define CTRY_UZBEKISTAN 7
+#define CTRY_VENEZUELA 58
+#define CTRY_VIET_NAM 84
+#define CTRY_YEMEN 967
+#define CTRY_ZIMBABWE 263
+#define CAL_ICALINTVALUE 1
+#define CAL_SCALNAME 2
+#define CAL_IYEAROFFSETRANGE 3
+#define CAL_SERASTRING 4
+#define CAL_SSHORTDATE 5
+#define CAL_SLONGDATE 6
+#define CAL_SDAYNAME1 7
+#define CAL_SDAYNAME2 8
+#define CAL_SDAYNAME3 9
+#define CAL_SDAYNAME4 10
+#define CAL_SDAYNAME5 11
+#define CAL_SDAYNAME6 12
+#define CAL_SDAYNAME7 13
+#define CAL_SABBREVDAYNAME1 14
+#define CAL_SABBREVDAYNAME2 15
+#define CAL_SABBREVDAYNAME3 16
+#define CAL_SABBREVDAYNAME4 17
+#define CAL_SABBREVDAYNAME5 18
+#define CAL_SABBREVDAYNAME6 19
+#define CAL_SABBREVDAYNAME7 20
+#define CAL_SMONTHNAME1 21
+#define CAL_SMONTHNAME2 22
+#define CAL_SMONTHNAME3 23
+#define CAL_SMONTHNAME4 24
+#define CAL_SMONTHNAME5 25
+#define CAL_SMONTHNAME6 26
+#define CAL_SMONTHNAME7 27
+#define CAL_SMONTHNAME8 28
+#define CAL_SMONTHNAME9 29
+#define CAL_SMONTHNAME10 30
+#define CAL_SMONTHNAME11 31
+#define CAL_SMONTHNAME12 32
+#define CAL_SMONTHNAME13 33
+#define CAL_SABBREVMONTHNAME1 34
+#define CAL_SABBREVMONTHNAME2 35
+#define CAL_SABBREVMONTHNAME3 36
+#define CAL_SABBREVMONTHNAME4 37
+#define CAL_SABBREVMONTHNAME5 38
+#define CAL_SABBREVMONTHNAME6 39
+#define CAL_SABBREVMONTHNAME7 40
+#define CAL_SABBREVMONTHNAME8 41
+#define CAL_SABBREVMONTHNAME9 42
+#define CAL_SABBREVMONTHNAME10 43
+#define CAL_SABBREVMONTHNAME11 44
+#define CAL_SABBREVMONTHNAME12 45
+#define CAL_SABBREVMONTHNAME13 46
+#define CAL_GREGORIAN 1
+#define CAL_GREGORIAN_US 2
+#define CAL_JAPAN 3
+#define CAL_TAIWAN 4
+#define CAL_KOREA 5
+#define CAL_HIJRI 6
+#define CAL_THAI 7
+#define CAL_HEBREW 8
+#define CAL_GREGORIAN_ME_FRENCH 9
+#define CAL_GREGORIAN_ARABIC 10
+#define CAL_GREGORIAN_XLIT_ENGLISH 11
+#define CAL_GREGORIAN_XLIT_FRENCH 12
+#define CSTR_LESS_THAN 1
+#define CSTR_EQUAL 2
+#define CSTR_GREATER_THAN 3
+#define LGRPID_INSTALLED 1
+#define LGRPID_SUPPORTED 2
+#define LGRPID_WESTERN_EUROPE 1
+#define LGRPID_CENTRAL_EUROPE 2
+#define LGRPID_BALTIC 3
+#define LGRPID_GREEK 4
+#define LGRPID_CYRILLIC 5
+#define LGRPID_TURKISH 6
+#define LGRPID_JAPANESE 7
+#define LGRPID_KOREAN 8
+#define LGRPID_TRADITIONAL_CHINESE 9
+#define LGRPID_SIMPLIFIED_CHINESE 10
+#define LGRPID_THAI 11
+#define LGRPID_HEBREW 12
+#define LGRPID_ARABIC 13
+#define LGRPID_VIETNAMESE 14
+#define LGRPID_INDIC 15
+#define LGRPID_GEORGIAN 16
+#define LGRPID_ARMENIAN 17
+
+#if(WINVER >= 0x0500)
+#define LOCALE_SYEARMONTH 0x1006
+#define LOCALE_SENGCURRNAME 0x1007
+#define LOCALE_SNATIVECURRNAME 0x1008
+#define LOCALE_IDEFAULTEBCDICCODEPAGE 0x1012
+#define LOCALE_SSORTNAME 0x1013
+#define LOCALE_IDIGITSUBSTITUTION 0x1014
+#define LOCALE_IPAPERSIZE 0x100A
+#define DATE_YEARMONTH 8
+#define DATE_LTRREADING 16
+#define DATE_RTLREADING 32
+#define MAP_EXPAND_LIGATURES   0x2000
+#define WC_NO_BEST_FIT_CHARS 1024
+#define CAL_SYEARMONTH 47
+#define CAL_ITWODIGITYEARMAX 48
+#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE
+#define CAL_RETURN_NUMBER LOCALE_RETURN_NUMBER
+#define CAL_USE_CP_ACP LOCALE_USE_CP_ACP
+#endif /* WINVER >= 0x0500 */
+#ifndef  _BASETSD_H
+typedef long LONG_PTR;
+#endif 
+
+#ifndef RC_INVOKED
+typedef DWORD LCTYPE;
+typedef DWORD CALTYPE;
+typedef DWORD CALID;
+typedef DWORD LGRPID;
+typedef BOOL (CALLBACK *CALINFO_ENUMPROCA)(LPSTR);
+typedef BOOL (CALLBACK *CALINFO_ENUMPROCW)(LPWSTR);
+typedef BOOL (CALLBACK* CALINFO_ENUMPROCEXA)(LPSTR, CALID);
+typedef BOOL (CALLBACK* CALINFO_ENUMPROCEXW)(LPWSTR, CALID);
+typedef BOOL (CALLBACK* LANGUAGEGROUP_ENUMPROCA)(LGRPID, LPSTR, LPSTR, DWORD, LONG_PTR);
+typedef BOOL (CALLBACK* LANGUAGEGROUP_ENUMPROCW)(LGRPID, LPWSTR, LPWSTR, DWORD, LONG_PTR);
+typedef BOOL (CALLBACK* LANGGROUPLOCALE_ENUMPROCA)(LGRPID, LCID, LPSTR, LONG_PTR);
+typedef BOOL (CALLBACK* LANGGROUPLOCALE_ENUMPROCW)(LGRPID, LCID, LPWSTR, LONG_PTR);
+typedef BOOL (CALLBACK* UILANGUAGE_ENUMPROCW)(LPWSTR, LONG_PTR);
+typedef BOOL (CALLBACK* UILANGUAGE_ENUMPROCA)(LPSTR, LONG_PTR);
+typedef BOOL (CALLBACK *LOCALE_ENUMPROCA)(LPSTR);
+typedef BOOL (CALLBACK *LOCALE_ENUMPROCW)(LPWSTR);
+typedef BOOL (CALLBACK *CODEPAGE_ENUMPROCA)(LPSTR);
+typedef BOOL (CALLBACK *CODEPAGE_ENUMPROCW)(LPWSTR);
+typedef BOOL (CALLBACK *DATEFMT_ENUMPROCA)(LPSTR);
+typedef BOOL (CALLBACK *DATEFMT_ENUMPROCW)(LPWSTR);
+typedef BOOL (CALLBACK* DATEFMT_ENUMPROCEXA)(LPSTR, CALID);
+typedef BOOL (CALLBACK* DATEFMT_ENUMPROCEXW)(LPWSTR, CALID);
+typedef BOOL (CALLBACK *TIMEFMT_ENUMPROCA)(LPSTR);
+typedef BOOL (CALLBACK *TIMEFMT_ENUMPROCW)(LPWSTR);
+
+typedef struct _cpinfo {
+	UINT MaxCharSize;
+	BYTE DefaultChar[MAX_DEFAULTCHAR];
+	BYTE LeadByte[MAX_LEADBYTES];
+} CPINFO,*LPCPINFO;
+typedef struct _cpinfoexA {
+    UINT MaxCharSize;
+    BYTE DefaultChar[MAX_DEFAULTCHAR];
+    BYTE LeadByte[MAX_LEADBYTES];
+    WCHAR UnicodeDefaultChar;
+    UINT CodePage;
+    CHAR CodePageName[MAX_PATH];
+} CPINFOEXA, *LPCPINFOEXA;
+typedef struct _cpinfoexW {
+    UINT MaxCharSize;
+    BYTE DefaultChar[MAX_DEFAULTCHAR];
+    BYTE LeadByte[MAX_LEADBYTES];
+    WCHAR UnicodeDefaultChar;
+    UINT CodePage;
+    WCHAR CodePageName[MAX_PATH];
+} CPINFOEXW, *LPCPINFOEXW;
+typedef struct _currencyfmtA {
+	UINT NumDigits;
+	UINT LeadingZero;
+	UINT Grouping;
+	LPSTR lpDecimalSep;
+	LPSTR lpThousandSep;
+	UINT NegativeOrder;
+	UINT PositiveOrder;
+	LPSTR lpCurrencySymbol;
+} CURRENCYFMTA, *LPCURRENCYFMTA;
+typedef struct _currencyfmtW {
+	UINT NumDigits;
+	UINT LeadingZero;
+	UINT Grouping;
+	LPWSTR lpDecimalSep;
+	LPWSTR lpThousandSep;
+	UINT NegativeOrder;
+	UINT PositiveOrder;
+	LPWSTR lpCurrencySymbol;
+} CURRENCYFMTW, *LPCURRENCYFMTW;
+typedef struct _numberfmtA {
+	UINT NumDigits;
+	UINT LeadingZero;
+	UINT Grouping;
+	LPSTR lpDecimalSep;
+	LPSTR lpThousandSep;
+	UINT NegativeOrder;
+} NUMBERFMTA, *LPNUMBERFMTA;
+typedef struct _numberfmtW {
+	UINT NumDigits;
+	UINT LeadingZero;
+	UINT Grouping;
+	LPWSTR lpDecimalSep;
+	LPWSTR lpThousandSep;
+	UINT NegativeOrder;
+} NUMBERFMTW, *LPNUMBERFMTW;
+
+int WINAPI CompareStringA(LCID,DWORD,LPCSTR,int,LPCSTR,int);
+int WINAPI CompareStringW(LCID,DWORD,LPCWSTR,int,LPCWSTR,int);
+LCID WINAPI ConvertDefaultLocale(LCID);
+BOOL WINAPI EnumCalendarInfoA(CALINFO_ENUMPROCA,LCID,CALID,CALTYPE);
+BOOL WINAPI EnumCalendarInfoW(CALINFO_ENUMPROCW,LCID,CALID,CALTYPE);
+BOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA,LCID,DWORD);
+BOOL WINAPI EnumDateFormatsW(DATEFMT_ENUMPROCW,LCID,DWORD);
+BOOL WINAPI EnumSystemCodePagesA(CODEPAGE_ENUMPROCA,DWORD);
+BOOL WINAPI EnumSystemCodePagesW(CODEPAGE_ENUMPROCW,DWORD);
+BOOL WINAPI EnumSystemLocalesA(LOCALE_ENUMPROCA,DWORD);
+BOOL WINAPI EnumSystemLocalesW(LOCALE_ENUMPROCW,DWORD);
+BOOL WINAPI EnumTimeFormatsA(TIMEFMT_ENUMPROCA,LCID,DWORD);
+BOOL WINAPI EnumTimeFormatsW(TIMEFMT_ENUMPROCW,LCID,DWORD);
+int WINAPI FoldStringA(DWORD,LPCSTR,int,LPSTR,int);
+int WINAPI FoldStringW(DWORD,LPCWSTR,int,LPWSTR,int);
+UINT WINAPI GetACP(void);
+BOOL WINAPI GetCPInfo(UINT,LPCPINFO);
+BOOL WINAPI GetCPInfoExA(UINT,DWORD,LPCPINFOEXA);
+BOOL WINAPI GetCPInfoExW(UINT,DWORD,LPCPINFOEXW);
+int WINAPI GetCurrencyFormatA(LCID,DWORD,LPCSTR,const CURRENCYFMTA*,LPSTR,int);
+int WINAPI GetCurrencyFormatW(LCID,DWORD,LPCWSTR,const CURRENCYFMTW*,LPWSTR,int);
+int WINAPI GetDateFormatA(LCID,DWORD,const SYSTEMTIME*,LPCSTR,LPSTR,int);
+int WINAPI GetDateFormatW(LCID,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,int);
+int WINAPI GetLocaleInfoA(LCID,LCTYPE,LPSTR,int);
+int WINAPI GetLocaleInfoW(LCID,LCTYPE,LPWSTR,int);
+int WINAPI GetNumberFormatA(LCID,DWORD,LPCSTR,const NUMBERFMTA*,LPSTR,int);
+int WINAPI GetNumberFormatW(LCID,DWORD,LPCWSTR,const NUMBERFMTW*,LPWSTR,int);
+UINT WINAPI GetOEMCP(void);
+BOOL WINAPI GetStringTypeA(LCID,DWORD,LPCSTR,int,LPWORD);
+BOOL WINAPI GetStringTypeW(DWORD,LPCWSTR,int,LPWORD);
+BOOL WINAPI GetStringTypeExA(LCID,DWORD,LPCSTR,int,LPWORD);
+BOOL WINAPI GetStringTypeExW(LCID,DWORD,LPCWSTR,int,LPWORD);
+LANGID WINAPI GetSystemDefaultLangID(void);
+LCID WINAPI GetSystemDefaultLCID(void);
+LCID WINAPI GetThreadLocale(void);
+int WINAPI GetTimeFormatA(LCID,DWORD,const SYSTEMTIME*,LPCSTR,LPSTR,int);
+int WINAPI GetTimeFormatW(LCID,DWORD,const SYSTEMTIME*,LPCWSTR,LPWSTR,int);
+LANGID WINAPI GetUserDefaultLangID(void);
+LCID WINAPI GetUserDefaultLCID(void);
+BOOL WINAPI IsDBCSLeadByte(BYTE);
+BOOL WINAPI IsDBCSLeadByteEx(UINT,BYTE);
+BOOL WINAPI IsValidCodePage(UINT);
+BOOL WINAPI IsValidLocale(LCID,DWORD);
+int WINAPI LCMapStringA(LCID,DWORD,LPCSTR,int,LPSTR,int);
+int WINAPI LCMapStringW(LCID,DWORD,LPCWSTR,int,LPWSTR,int);
+int WINAPI MultiByteToWideChar(UINT,DWORD,LPCSTR,int,LPWSTR,int);
+BOOL WINAPI SetLocaleInfoA(LCID,LCTYPE,LPCSTR);
+BOOL WINAPI SetLocaleInfoW(LCID,LCTYPE,LPCWSTR);
+BOOL WINAPI SetThreadLocale(LCID);
+int WINAPI WideCharToMultiByte(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
+#if (WINVER >= 0x0500)
+BOOL WINAPI EnumCalendarInfoExA(CALINFO_ENUMPROCEXA,LCID,CALID,CALTYPE);
+BOOL WINAPI EnumCalendarInfoExW(CALINFO_ENUMPROCEXW,LCID,CALID,CALTYPE);
+BOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA,LCID,DWORD);
+BOOL WINAPI EnumDateFormatsExW(DATEFMT_ENUMPROCEXW,LCID,DWORD);
+BOOL WINAPI EnumSystemLanguageGroupsA(LANGUAGEGROUP_ENUMPROCA,DWORD,LONG_PTR);
+BOOL WINAPI EnumSystemLanguageGroupsW(LANGUAGEGROUP_ENUMPROCW,DWORD,LONG_PTR);
+BOOL WINAPI EnumLanguageGroupLocalesA(LANGGROUPLOCALE_ENUMPROCA,LGRPID,DWORD,LONG_PTR);
+BOOL WINAPI EnumLanguageGroupLocalesW(LANGGROUPLOCALE_ENUMPROCW,LGRPID,DWORD,LONG_PTR);
+BOOL WINAPI EnumUILanguagesA(UILANGUAGE_ENUMPROCA,DWORD,LONG_PTR);
+BOOL WINAPI EnumUILanguagesW(UILANGUAGE_ENUMPROCW,DWORD,LONG_PTR);
+LANGID WINAPI GetSystemDefaultUILanguage(void);
+LANGID WINAPI GetUserDefaultUILanguage(void);
+BOOL WINAPI IsValidLanguageGroup(LGRPID,DWORD);
+#endif /* (WINVER >= 0x0500) */
+
+#ifdef UNICODE
+#define CALINFO_ENUMPROC CALINFO_ENUMPROCW
+#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXW
+#define LOCALE_ENUMPROC LOCALE_ENUMPROCW
+#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCW
+#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCW
+#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXW
+#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCW
+#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCW
+#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCW
+#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCW
+typedef CPINFOEXW CPINFOEX;
+typedef LPCPINFOEXW LPCPINFOEX;
+typedef CURRENCYFMTW CURRENCYFMT;
+typedef LPCURRENCYFMTW LPCURRENCYFMT;
+typedef NUMBERFMTW NUMBERFMT;
+typedef LPNUMBERFMTW LPNUMBERFMT;
+#define CompareString CompareStringW
+#define EnumCalendarInfo EnumCalendarInfoW
+#define EnumSystemCodePages EnumSystemCodePagesW
+#define EnumSystemLocales EnumSystemLocalesW
+#define EnumTimeFormats EnumTimeFormatsW
+#define FoldString FoldStringW
+#define GetCPInfoEx GetCPInfoExW
+#define GetCurrencyFormat GetCurrencyFormatW
+#define GetDateFormat GetDateFormatW
+#define GetLocaleInfo GetLocaleInfoW
+#define GetNumberFormat GetNumberFormatW
+#define GetStringTypeEx GetStringTypeExW
+#define GetTimeFormat GetTimeFormatW
+#define LCMapString LCMapStringW
+#define SetLocaleInfo SetLocaleInfoW
+#if (WINVER >= 0x0500)
+#define EnumCalendarInfoEx EnumCalendarInfoExW;
+#define EnumDateFormatsEx EnumDateFormatsExW;
+#define EnumSystemLanguageGroups EnumSystemLanguageGroupsW;
+#define EnumLanguageGroupLocales EnumLanguageGroupLocalesW;
+#define EnumUILanguages EnumUILanguagesW;
+#endif /* (WINVER >= 0x0500) */
+#else
+#define CALINFO_ENUMPROC CALINFO_ENUMPROCA
+#define CALINFO_ENUMPROCEX CALINFO_ENUMPROCEXA
+#define LOCALE_ENUMPROC LOCALE_ENUMPROCA
+#define CODEPAGE_ENUMPROC CODEPAGE_ENUMPROCA
+#define DATEFMT_ENUMPROC DATEFMT_ENUMPROCA
+#define DATEFMT_ENUMPROCEX DATEFMT_ENUMPROCEXA
+#define TIMEFMT_ENUMPROC TIMEFMT_ENUMPROCA
+#define LANGUAGEGROUP_ENUMPROC LANGUAGEGROUP_ENUMPROCA
+#define LANGGROUPLOCALE_ENUMPROC LANGGROUPLOCALE_ENUMPROCA
+#define UILANGUAGE_ENUMPROC UILANGUAGE_ENUMPROCA
+typedef CPINFOEXA CPINFOEX;
+typedef LPCPINFOEXA LPCPINFOEX;
+typedef CURRENCYFMTA CURRENCYFMT;
+typedef LPCURRENCYFMTA LPCURRENCYFMT;
+typedef NUMBERFMTA NUMBERFMT;
+typedef LPNUMBERFMTA LPNUMBERFMT;
+#define CompareString CompareStringA
+#define EnumCalendarInfo EnumCalendarInfoA
+#define EnumSystemCodePages EnumSystemCodePagesA
+#define EnumSystemLocales EnumSystemLocalesA
+#define EnumTimeFormats EnumTimeFormatsA
+#define FoldString FoldStringA
+#define GetCPInfoEx GetCPInfoExA
+#define GetCurrencyFormat GetCurrencyFormatA
+#define GetDateFormat GetDateFormatA
+#define GetLocaleInfo GetLocaleInfoA
+#define GetNumberFormat GetNumberFormatA
+#define GetStringTypeEx GetStringTypeExA
+#define GetTimeFormat GetTimeFormatA
+#define LCMapString LCMapStringA
+#define SetLocaleInfo SetLocaleInfoA
+#if (WINVER >= 0x0500)
+#define EnumCalendarInfoEx EnumCalendarInfoExA;
+#define EnumDateFormatsEx EnumDateFormatsExA;
+#define EnumSystemLanguageGroups EnumSystemLanguageGroupsA;
+#define EnumLanguageGroupLocales EnumLanguageGroupLocalesA;
+#define EnumUILanguages EnumUILanguagesA;
+#endif /* (WINVER >= 0x0500) */
+#endif /* UNICODE */
+#endif /* RC_INVOKED */
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/winnt.h b/tinyc/win32/include/winapi/winnt.h
new file mode 100644
index 000000000..810d99158
--- /dev/null
+++ b/tinyc/win32/include/winapi/winnt.h
@@ -0,0 +1,2667 @@
+#ifndef _WINNT_H
+#define _WINNT_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+/* translate GCC target defines to MS equivalents. Keep this synchronized
+   with windows.h. */
+#if defined(__i686__) && !defined(_M_IX86)
+#define _M_IX86 600
+#elif defined(__i586__) && !defined(_M_IX86)
+#define _M_IX86 500
+#elif defined(__i486__) && !defined(_M_IX86)
+#define _M_IX86 400
+#elif defined(__i386__) && !defined(_M_IX86)
+#define _M_IX86 300
+#endif
+#if defined(_M_IX86) && !defined(_X86_)
+#define _X86_
+#elif defined(_M_ALPHA) && !defined(_ALPHA_)
+#define _ALPHA_
+#elif defined(_M_PPC) && !defined(_PPC_)
+#define _PPC_
+#elif defined(_M_MRX000) && !defined(_MIPS_)
+#define _MIPS_
+#elif defined(_M_M68K) && !defined(_68K_)
+#define _68K_
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <winerror.h>
+
+#ifndef RC_INVOKED
+#include <string.h>
+
+/* FIXME: add more architectures. Is there a way to specify this in GCC? */
+#ifdef _X86_
+#define UNALIGNED
+#else
+#define UNALIGNED
+#endif
+
+#ifndef VOID
+#define VOID void
+#endif
+typedef char CHAR;
+typedef short SHORT;
+typedef long LONG;
+typedef CHAR CCHAR;
+typedef unsigned char UCHAR,*PUCHAR;
+typedef unsigned short USHORT,*PUSHORT;
+typedef unsigned long ULONG,*PULONG;
+typedef char *PSZ;
+
+#ifndef _WCHAR_T_DEFINED
+#define _WCHAR_T_DEFINED
+#ifndef _WCHAR_T_
+#define _WCHAR_T_
+#undef __need_wchar_t
+#ifndef __cplusplus
+typedef unsigned short wchar_t;
+#endif
+#endif
+#endif
+
+typedef wchar_t WCHAR;
+typedef WCHAR *PWCHAR,*LPWCH,*PWCH,*NWPSTR,*LPWSTR,*PWSTR;
+typedef CONST WCHAR *LPCWCH,*PCWCH,*LPCWSTR,*PCWSTR;
+typedef CHAR *PCHAR,*LPCH,*PCH,*NPSTR,*LPSTR,*PSTR;
+typedef CONST CHAR *LPCCH,*PCSTR,*LPCSTR;
+#ifndef _TCHAR_DEFINED
+#define _TCHAR_DEFINED
+#ifdef UNICODE
+/*
+ * NOTE: This tests UNICODE, which is different from the _UNICODE define
+ *       used to differentiate standard C runtime calls.
+ */
+typedef WCHAR TCHAR;
+typedef WCHAR _TCHAR;
+#else
+typedef CHAR TCHAR;
+typedef CHAR _TCHAR;
+#endif
+#endif
+typedef TCHAR TBYTE,*PTCH,*PTBYTE;
+typedef TCHAR *LPTCH,*PTSTR,*LPTSTR,*LP,*PTCHAR;
+typedef const TCHAR *LPCTSTR;
+#ifdef UNICODE
+/*
+ * __TEXT is a private macro whose specific use is to force the expansion of a
+ * macro passed as an argument to the macro TEXT.  DO NOT use this
+ * macro within your programs.  It's name and function could change without
+ * notice.
+ */
+#define __TEXT(q) L##q
+#else
+#define __TEXT(q) q
+#endif
+/*
+ * UNICODE a constant string when UNICODE is defined, else returns the string
+ * unmodified.
+ * The corresponding macros  _TEXT() and _T() for mapping _UNICODE strings
+ * passed to C runtime functions are defined in mingw/tchar.h
+ */
+#define TEXT(q) __TEXT(q)    
+typedef SHORT *PSHORT;
+typedef LONG *PLONG;
+typedef void *HANDLE;
+typedef HANDLE *PHANDLE,*LPHANDLE;
+#ifdef STRICT
+#define DECLARE_HANDLE(n) typedef struct n##__{int i;}*n
+#else
+#define DECLARE_HANDLE(n) typedef HANDLE n
+#endif
+typedef DWORD LCID;
+typedef PDWORD PLCID;
+typedef WORD LANGID;
+#ifdef __GNUC__
+#define _HAVE_INT64
+#define _INTEGRAL_MAX_BITS 64
+#undef __int64
+#define __int64 long long
+#elif defined(__WATCOMC__) && (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64 )
+#define _HAVE_INT64
+#endif /* __GNUC__/__WATCOMC */
+#if defined(_HAVE_INT64) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64)
+typedef __int64 LONGLONG;
+typedef unsigned __int64 DWORDLONG;
+#else
+typedef double LONGLONG,DWORDLONG;
+#endif
+typedef LONGLONG *PLONGLONG;
+typedef DWORDLONG *PDWORDLONG;
+typedef DWORDLONG ULONGLONG,*PULONGLONG;
+typedef LONGLONG USN;
+#ifdef _HAVE_INT64
+#define Int32x32To64(a,b) ((LONGLONG)(a)*(LONGLONG)(b))
+#define UInt32x32To64(a,b) ((DWORDLONG)(a)*(DWORDLONG)(b))
+#define Int64ShllMod32(a,b) ((DWORDLONG)(a)<<(b))
+#define Int64ShraMod32(a,b) ((LONGLONG)(a)>>(b))
+#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b))
+#endif
+#define ANSI_NULL '\0'
+#define UNICODE_NULL L'\0'
+typedef BYTE BOOLEAN,*PBOOLEAN;
+#endif
+
+#define NTAPI __stdcall
+#include <basetsd.h>
+#define APPLICATION_ERROR_MASK       0x20000000
+#define ERROR_SEVERITY_SUCCESS       0x00000000
+#define ERROR_SEVERITY_INFORMATIONAL 0x40000000
+#define ERROR_SEVERITY_WARNING       0x80000000
+#define ERROR_SEVERITY_ERROR         0xC0000000
+#define COMPRESSION_FORMAT_NONE 0
+#define COMPRESSION_FORMAT_DEFAULT 1
+#define COMPRESSION_FORMAT_LZNT1 2
+#define COMPRESSION_ENGINE_STANDARD 0
+#define COMPRESSION_ENGINE_MAXIMUM 256
+#define ACCESS_ALLOWED_ACE_TYPE	0
+#define ACCESS_DENIED_ACE_TYPE	1
+#define ANYSIZE_ARRAY 1
+#define SYSTEM_AUDIT_ACE_TYPE	2
+#define SYSTEM_ALARM_ACE_TYPE	3
+#define OBJECT_INHERIT_ACE	1
+#define CONTAINER_INHERIT_ACE	2
+#define NO_PROPAGATE_INHERIT_ACE	4
+#define INHERIT_ONLY_ACE	8
+#define VALID_INHERIT_FLAGS	16
+#define SUCCESSFUL_ACCESS_ACE_FLAG	64
+#define FAILED_ACCESS_ACE_FLAG	128
+#define DELETE	0x00010000L
+#define READ_CONTROL	0x20000L
+#define WRITE_DAC	0x40000L
+#define WRITE_OWNER	0x80000L
+#define SYNCHRONIZE	0x100000L
+#define STANDARD_RIGHTS_REQUIRED	0xF0000
+#define STANDARD_RIGHTS_READ	0x20000
+#define STANDARD_RIGHTS_WRITE	0x20000
+#define STANDARD_RIGHTS_EXECUTE	0x20000
+#define STANDARD_RIGHTS_ALL	0x1F0000
+#define SPECIFIC_RIGHTS_ALL	0xFFFF
+#define ACCESS_SYSTEM_SECURITY	0x1000000
+#define MAXIMUM_ALLOWED	0x2000000
+#define GENERIC_READ	0x80000000
+#define GENERIC_WRITE	0x40000000
+#define GENERIC_EXECUTE	0x20000000
+#define GENERIC_ALL	0x10000000
+#define FILE_READ_DATA	1
+#define FILE_LIST_DIRECTORY	1
+#define FILE_WRITE_DATA	2
+#define FILE_ADD_FILE	2
+#define FILE_APPEND_DATA	4
+#define FILE_ADD_SUBDIRECTORY	4
+#define FILE_CREATE_PIPE_INSTANCE	4
+#define FILE_READ_EA	8
+#define FILE_READ_PROPERTIES	8
+#define FILE_WRITE_EA	16
+#define FILE_WRITE_PROPERTIES	16
+#define FILE_EXECUTE	32
+#define FILE_TRAVERSE	32
+#define FILE_DELETE_CHILD	64
+#define FILE_READ_ATTRIBUTES	128
+#define FILE_WRITE_ATTRIBUTES	256
+#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1FF)
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ|FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA|SYNCHRONIZE)
+#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE|FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_EA|FILE_APPEND_DATA|SYNCHRONIZE)
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE|FILE_READ_ATTRIBUTES|FILE_EXECUTE|SYNCHRONIZE)
+#define FILE_SHARE_READ	1
+#define FILE_SHARE_WRITE 2
+#define FILE_SHARE_DELETE 4
+#define FILE_ATTRIBUTE_READONLY	1
+#define FILE_ATTRIBUTE_HIDDEN	2
+#define FILE_ATTRIBUTE_SYSTEM	4
+#define FILE_ATTRIBUTE_DIRECTORY	16
+#define FILE_ATTRIBUTE_ARCHIVE	32
+#define FILE_ATTRIBUTE_DEVICE	64
+#define FILE_ATTRIBUTE_NORMAL	128
+#define FILE_ATTRIBUTE_TEMPORARY	256
+#define FILE_ATTRIBUTE_SPARSE_FILE	512
+#define FILE_ATTRIBUTE_REPARSE_POINT	1024
+#define FILE_ATTRIBUTE_COMPRESSED	2048
+#define FILE_ATTRIBUTE_OFFLINE	0x1000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED	0x2000
+#define FILE_ATTRIBUTE_ENCRYPTED	0x4000
+#define INVALID_FILE_ATTRIBUTES	((DWORD)-1)
+#define FILE_NOTIFY_CHANGE_FILE_NAME	1
+#define FILE_NOTIFY_CHANGE_DIR_NAME	2
+#define FILE_NOTIFY_CHANGE_ATTRIBUTES	4
+#define FILE_NOTIFY_CHANGE_SIZE	8
+#define FILE_NOTIFY_CHANGE_LAST_WRITE	16
+#define FILE_NOTIFY_CHANGE_LAST_ACCESS  32
+#define FILE_NOTIFY_CHANGE_CREATION	64
+#define FILE_NOTIFY_CHANGE_SECURITY	256
+#define MAILSLOT_NO_MESSAGE	((DWORD)-1)
+#define MAILSLOT_WAIT_FOREVER	((DWORD)-1)
+#define FILE_CASE_SENSITIVE_SEARCH	1
+#define FILE_CASE_PRESERVED_NAMES	2
+#define FILE_UNICODE_ON_DISK	4
+#define FILE_PERSISTENT_ACLS	8
+#define FILE_FILE_COMPRESSION	16
+#define FILE_VOLUME_QUOTAS      32
+#define FILE_SUPPORTS_SPARSE_FILES      64
+#define FILE_SUPPORTS_REPARSE_POINTS    128
+#define FILE_SUPPORTS_REMOTE_STORAGE    256
+#define FILE_VOLUME_IS_COMPRESSED	0x8000
+#define FILE_SUPPORTS_OBJECT_IDS        0x10000  
+#define FILE_SUPPORTS_ENCRYPTION        0x20000  
+#define FILE_NAMED_STREAMS              0x40000
+#define IO_COMPLETION_MODIFY_STATE	2
+#define IO_COMPLETION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|3)
+#define DUPLICATE_CLOSE_SOURCE	1
+#define DUPLICATE_SAME_ACCESS	2
+#define PROCESS_TERMINATE	1
+#define PROCESS_CREATE_THREAD	2
+#define PROCESS_VM_OPERATION	8
+#define PROCESS_VM_READ	16
+#define PROCESS_VM_WRITE	32
+#define PROCESS_DUP_HANDLE	64
+#define PROCESS_CREATE_PROCESS	128
+#define PROCESS_SET_QUOTA	256
+#define PROCESS_SET_INFORMATION	512
+#define PROCESS_QUERY_INFORMATION	1024
+#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xFFF)
+#define THREAD_TERMINATE	1
+#define THREAD_SUSPEND_RESUME	2
+#define THREAD_GET_CONTEXT	8
+#define THREAD_SET_CONTEXT	16
+#define THREAD_SET_INFORMATION	32
+#define THREAD_QUERY_INFORMATION	64
+#define THREAD_SET_THREAD_TOKEN	128
+#define THREAD_IMPERSONATE	256
+#define THREAD_DIRECT_IMPERSONATION	0x200
+#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3FF)
+#define EXCEPTION_NONCONTINUABLE	1
+#define EXCEPTION_MAXIMUM_PARAMETERS 15
+/*
+ * To prevent gcc compiler warnings, bracket these defines when initialising
+ * a  SID_IDENTIFIER_AUTHORITY, eg.
+ * SID_IDENTIFIER_AUTHORITY aNullSidAuthority = {SECURITY_NULL_SID_AUTHORITY};
+ */
+#define SECURITY_NULL_SID_AUTHORITY	{0,0,0,0,0,0}
+#define SECURITY_WORLD_SID_AUTHORITY	{0,0,0,0,0,1}
+#define SECURITY_LOCAL_SID_AUTHORITY	{0,0,0,0,0,2}
+#define SECURITY_CREATOR_SID_AUTHORITY	{0,0,0,0,0,3}
+#define SECURITY_NON_UNIQUE_AUTHORITY	{0,0,0,0,0,4}
+#define SECURITY_NT_AUTHORITY	{0,0,0,0,0,5}
+#define SECURITY_NULL_RID	0
+#define SECURITY_WORLD_RID	0
+#define SECURITY_LOCAL_RID	0
+#define SECURITY_CREATOR_OWNER_RID	0
+#define SECURITY_CREATOR_GROUP_RID	1
+#define SECURITY_DIALUP_RID	1
+#define SECURITY_NETWORK_RID	2
+#define SECURITY_BATCH_RID	3
+#define SECURITY_INTERACTIVE_RID	4
+#define SECURITY_LOGON_IDS_RID	5
+#define SECURITY_SERVICE_RID	6
+#define SECURITY_LOCAL_SYSTEM_RID	18
+#define SECURITY_BUILTIN_DOMAIN_RID   32
+#define SECURITY_PRINCIPAL_SELF_RID   10
+#define SID_REVISION 1
+#define DOMAIN_USER_RID_ADMIN 0x1F4L
+#define DOMAIN_USER_RID_GUEST 0x1F5L
+#define DOMAIN_GROUP_RID_ADMINS	0x200L
+#define DOMAIN_GROUP_RID_USERS	0x201L
+#define DOMAIN_ALIAS_RID_ADMINS	0x220L
+#define DOMAIN_ALIAS_RID_USERS	0x221L
+#define DOMAIN_ALIAS_RID_GUESTS	0x222L
+#define DOMAIN_ALIAS_RID_POWER_USERS	0x223L
+#define DOMAIN_ALIAS_RID_ACCOUNT_OPS	0x224L
+#define DOMAIN_ALIAS_RID_SYSTEM_OPS	0x225L
+#define DOMAIN_ALIAS_RID_PRINT_OPS	0x226L
+#define DOMAIN_ALIAS_RID_BACKUP_OPS	0x227L
+#define DOMAIN_ALIAS_RID_REPLICATOR	0x228L
+#define SE_CREATE_TOKEN_NAME	TEXT("SeCreateTokenPrivilege")
+#define SE_ASSIGNPRIMARYTOKEN_NAME	TEXT("SeAssignPrimaryTokenPrivilege")
+#define SE_LOCK_MEMORY_NAME	TEXT("SeLockMemoryPrivilege")
+#define SE_INCREASE_QUOTA_NAME	TEXT("SeIncreaseQuotaPrivilege")
+#define SE_UNSOLICITED_INPUT_NAME	TEXT("SeUnsolicitedInputPrivilege")
+#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege")
+#define SE_TCB_NAME	TEXT("SeTcbPrivilege")
+#define SE_SECURITY_NAME	TEXT("SeSecurityPrivilege")
+#define SE_TAKE_OWNERSHIP_NAME	TEXT("SeTakeOwnershipPrivilege")
+#define SE_LOAD_DRIVER_NAME	TEXT("SeLoadDriverPrivilege")
+#define SE_SYSTEM_PROFILE_NAME	TEXT("SeSystemProfilePrivilege")
+#define SE_SYSTEMTIME_NAME	TEXT("SeSystemtimePrivilege")
+#define SE_PROF_SINGLE_PROCESS_NAME	TEXT("SeProfileSingleProcessPrivilege")
+#define SE_INC_BASE_PRIORITY_NAME	TEXT("SeIncreaseBasePriorityPrivilege")
+#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege")
+#define SE_CREATE_PERMANENT_NAME	TEXT("SeCreatePermanentPrivilege")
+#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
+#define SE_RESTORE_NAME	TEXT("SeRestorePrivilege")
+#define SE_SHUTDOWN_NAME	TEXT("SeShutdownPrivilege")
+#define SE_DEBUG_NAME	TEXT("SeDebugPrivilege")
+#define SE_AUDIT_NAME	TEXT("SeAuditPrivilege")
+#define SE_SYSTEM_ENVIRONMENT_NAME	TEXT("SeSystemEnvironmentPrivilege")
+#define SE_CHANGE_NOTIFY_NAME	TEXT("SeChangeNotifyPrivilege")
+#define SE_REMOTE_SHUTDOWN_NAME	TEXT("SeRemoteShutdownPrivilege")
+#define SE_GROUP_MANDATORY 1
+#define SE_GROUP_ENABLED_BY_DEFAULT 2
+#define SE_GROUP_ENABLED 4
+#define SE_GROUP_OWNER 8
+#define SE_GROUP_USE_FOR_DENY_ONLY 16
+#define SE_GROUP_LOGON_ID 3221225472U
+#define SE_GROUP_RESOURCE 536870912
+#define LANG_NEUTRAL	0x00
+#define LANG_ARABIC 	0x01
+#define LANG_BULGARIAN 	0x02
+#define LANG_CATALAN 	0x03
+#define LANG_CHINESE	0x04
+#define LANG_CZECH	0x05
+#define LANG_DANISH	0x06
+#define LANG_GERMAN	0x07
+#define LANG_GREEK	0x08
+#define LANG_ENGLISH	0x09
+#define LANG_SPANISH	0x0a
+#define LANG_FINNISH	0x0b
+#define LANG_FRENCH	0x0c
+#define LANG_HEBREW	0x0d
+#define LANG_HUNGARIAN	0x0e
+#define LANG_ICELANDIC	0x0f
+#define LANG_ITALIAN	0x10
+#define LANG_JAPANESE	0x11
+#define LANG_KOREAN	0x12
+#define LANG_DUTCH	0x13
+#define LANG_NORWEGIAN	0x14
+#define LANG_POLISH	0x15
+#define LANG_PORTUGUESE	0x16
+#define LANG_ROMANIAN	0x18
+#define LANG_RUSSIAN	0x19
+#define LANG_CROATIAN	0x1a
+#define LANG_SERBIAN	0x1a
+#define LANG_SLOVAK	0x1b
+#define LANG_ALBANIAN	0x1c
+#define LANG_SWEDISH	0x1d
+#define LANG_THAI	0x1e
+#define LANG_TURKISH	0x1f
+#define LANG_URDU	0x20
+#define LANG_INDONESIAN	0x21
+#define LANG_UKRAINIAN	0x22
+#define LANG_BELARUSIAN	0x23
+#define LANG_SLOVENIAN	0x24
+#define LANG_ESTONIAN	0x25
+#define LANG_LATVIAN	0x26
+#define LANG_LITHUANIAN	0x27
+#define LANG_FARSI	0x29
+#define LANG_VIETNAMESE	0x2a
+#define LANG_ARMENIAN	0x2b
+#define LANG_AZERI	0x2c
+#define LANG_BASQUE	0x2d
+#define LANG_MACEDONIAN	0x2f
+#define LANG_AFRIKAANS	0x36
+#define LANG_GEORGIAN	0x37
+#define LANG_FAEROESE	0x38
+#define LANG_HINDI	0x39
+#define LANG_MALAY	0x3e
+#define LANG_KAZAK	0x3f
+#define LANG_SWAHILI	0x41
+#define LANG_UZBEK	0x43
+#define LANG_TATAR	0x44
+#define LANG_BENGALI	0x45
+#define LANG_PUNJABI	0x46
+#define LANG_GUJARATI	0x47
+#define LANG_ORIYA	0x48
+#define LANG_TAMIL	0x49
+#define LANG_TELUGU	0x4a
+#define LANG_KANNADA	0x4b
+#define LANG_MALAYALAM	0x4c
+#define LANG_ASSAMESE	0x4d
+#define LANG_MARATHI	0x4e
+#define LANG_SANSKRIT	0x4f
+#define LANG_KONKANI	0x57
+#define LANG_MANIPURI	0x58
+#define LANG_SINDHI	0x59
+#define LANG_KASHMIRI	0x60
+#define LANG_NEPALI	0x61
+#define SUBLANG_NEUTRAL	0x00
+#define SUBLANG_DEFAULT	0x01
+#define SUBLANG_SYS_DEFAULT	0x02
+#define SUBLANG_ARABIC_SAUDI_ARABIA	0x01
+#define SUBLANG_ARABIC_IRAQ	0x02
+#define SUBLANG_ARABIC_EGYPT	0x03
+#define SUBLANG_ARABIC_LIBYA	0x04
+#define SUBLANG_ARABIC_ALGERIA	0x05
+#define SUBLANG_ARABIC_MOROCCO	0x06
+#define SUBLANG_ARABIC_TUNISIA	0x07
+#define SUBLANG_ARABIC_OMAN	0x08
+#define SUBLANG_ARABIC_YEMEN	0x09
+#define SUBLANG_ARABIC_SYRIA	0x0a
+#define SUBLANG_ARABIC_JORDAN	0x0b
+#define SUBLANG_ARABIC_LEBANON	0x0c
+#define SUBLANG_ARABIC_KUWAIT	0x0d
+#define SUBLANG_ARABIC_UAE	0x0e
+#define SUBLANG_ARABIC_BAHRAIN	0x0f
+#define SUBLANG_ARABIC_QATAR	0x10
+#define SUBLANG_AZERI_CYRILLIC	0x01
+#define SUBLANG_AZERI_LATIN	0x02
+#define SUBLANG_CHINESE_TRADITIONAL	0x01
+#define SUBLANG_CHINESE_SIMPLIFIED	0x02
+#define SUBLANG_CHINESE_HONGKONG	0x03
+#define SUBLANG_CHINESE_SINGAPORE	0x04
+#define SUBLANG_CHINESE_MACAU	0x05
+#define SUBLANG_DUTCH	0x01
+#define SUBLANG_DUTCH_BELGIAN	0x02
+#define SUBLANG_ENGLISH_US	0x01
+#define SUBLANG_ENGLISH_UK	0x02
+#define SUBLANG_ENGLISH_AUS	0x03
+#define SUBLANG_ENGLISH_CAN	0x04
+#define SUBLANG_ENGLISH_NZ	0x05
+#define SUBLANG_ENGLISH_EIRE	0x06
+#define SUBLANG_ENGLISH_SOUTH_AFRICA	0x07
+#define SUBLANG_ENGLISH_JAMAICA	0x08
+#define SUBLANG_ENGLISH_CARIBBEAN	0x09
+#define SUBLANG_ENGLISH_BELIZE	0x0a
+#define SUBLANG_ENGLISH_TRINIDAD	0x0b
+#define SUBLANG_ENGLISH_PHILIPPINES	0x0c
+#define SUBLANG_ENGLISH_ZIMBABWE	0x0d
+#define SUBLANG_FRENCH	0x01
+#define SUBLANG_FRENCH_BELGIAN	0x02
+#define SUBLANG_FRENCH_CANADIAN	0x03
+#define SUBLANG_FRENCH_SWISS	0x04
+#define SUBLANG_FRENCH_LUXEMBOURG	0x05
+#define SUBLANG_FRENCH_MONACO	0x06
+#define SUBLANG_GERMAN	0x01
+#define SUBLANG_GERMAN_SWISS	0x02
+#define SUBLANG_GERMAN_AUSTRIAN	0x03
+#define SUBLANG_GERMAN_LUXEMBOURG	0x04
+#define SUBLANG_GERMAN_LIECHTENSTEIN	0x05
+#define SUBLANG_ITALIAN	0x01
+#define SUBLANG_ITALIAN_SWISS	0x02
+#define SUBLANG_KASHMIRI_INDIA	0x02
+#define SUBLANG_KOREAN	0x01
+#define SUBLANG_LITHUANIAN	0x01
+#define SUBLANG_MALAY_MALAYSIA	0x01
+#define SUBLANG_MALAY_BRUNEI_DARUSSALAM	0x02
+#define SUBLANG_NEPALI_INDIA	0x02
+#define SUBLANG_NORWEGIAN_BOKMAL	0x01
+#define SUBLANG_NORWEGIAN_NYNORSK	0x02
+#define SUBLANG_PORTUGUESE	0x01
+#define SUBLANG_PORTUGUESE_BRAZILIAN	0x02
+#define SUBLANG_SERBIAN_LATIN	0x02
+#define SUBLANG_SERBIAN_CYRILLIC	0x03
+#define SUBLANG_SPANISH	0x01
+#define SUBLANG_SPANISH_MEXICAN	0x02
+#define SUBLANG_SPANISH_MODERN	0x03
+#define SUBLANG_SPANISH_GUATEMALA	0x04
+#define SUBLANG_SPANISH_COSTA_RICA	0x05
+#define SUBLANG_SPANISH_PANAMA	0x06
+#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC	0x07
+#define SUBLANG_SPANISH_VENEZUELA	0x08
+#define SUBLANG_SPANISH_COLOMBIA	0x09
+#define SUBLANG_SPANISH_PERU	0x0a
+#define SUBLANG_SPANISH_ARGENTINA	0x0b
+#define SUBLANG_SPANISH_ECUADOR	0x0c
+#define SUBLANG_SPANISH_CHILE	0x0d
+#define SUBLANG_SPANISH_URUGUAY	0x0e
+#define SUBLANG_SPANISH_PARAGUAY	0x0f
+#define SUBLANG_SPANISH_BOLIVIA	0x10
+#define SUBLANG_SPANISH_EL_SALVADOR	0x11
+#define SUBLANG_SPANISH_HONDURAS	0x12
+#define SUBLANG_SPANISH_NICARAGUA	0x13
+#define SUBLANG_SPANISH_PUERTO_RICO	0x14
+#define SUBLANG_SWEDISH	0x01
+#define SUBLANG_SWEDISH_FINLAND	0x02
+#define SUBLANG_URDU_PAKISTAN	0x01
+#define SUBLANG_URDU_INDIA	0x02
+#define SUBLANG_UZBEK_LATIN	0x01
+#define SUBLANG_UZBEK_CYRILLIC	0x02
+#define NLS_VALID_LOCALE_MASK	1048575
+#define SORT_DEFAULT	0
+#define SORT_JAPANESE_XJIS	0
+#define SORT_JAPANESE_UNICODE	1
+#define SORT_CHINESE_BIG5	0
+#define SORT_CHINESE_PRCP	0
+#define SORT_CHINESE_UNICODE	1
+#define SORT_CHINESE_PRC	2
+#define SORT_CHINESE_BOPOMOFO	3
+#define SORT_KOREAN_KSC	0
+#define SORT_KOREAN_UNICODE	1
+#define SORT_GERMAN_PHONE_BOOK	1
+#define SORT_HUNGARIAN_DEFAULT	0
+#define SORT_HUNGARIAN_TECHNICAL	1
+#define SORT_GEORGIAN_TRADITIONAL	0
+#define SORT_GEORGIAN_MODERN	1
+#define MAKELANGID(p,s)	((((WORD)(s))<<10)|(WORD)(p))
+#define MAKELCID(l,s) ((DWORD)((((DWORD)((WORD)(s)))<<16)|((DWORD)((WORD)(l)))))
+#define PRIMARYLANGID(l)	((WORD)(l)&0x3ff)
+#define SORTIDFROMLCID(l)	((WORD)((((DWORD)(l))&NLS_VALID_LOCALE_MASK)>>16))
+#define SORTVERSIONFROMLCID(l) ((WORD)((((DWORD)(l))>>20)&0xf))
+#define SUBLANGID(l)	((WORD)(l)>>10)
+#define LANGIDFROMLCID(l)	((WORD)(l))
+#define LANG_SYSTEM_DEFAULT	MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT)
+#define LANG_USER_DEFAULT	MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
+#define LOCALE_NEUTRAL	MAKELCID(MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),SORT_DEFAULT)
+#define ACL_REVISION	2
+#define ACL_REVISION_DS 4
+#define ACL_REVISION1 1
+#define ACL_REVISION2 2
+#define ACL_REVISION3 3
+#define ACL_REVISION4 4
+#define MIN_ACL_REVISION 2
+#define MAX_ACL_REVISION 4
+#define MINCHAR	0x80
+#define MAXCHAR	0x7f
+#define MINSHORT	0x8000
+#define MAXSHORT	0x7fff
+#define MINLONG	0x80000000
+#define MAXLONG	0x7fffffff
+#define MAXBYTE	0xff
+#define MAXWORD	0xffff
+#define MAXDWORD	0xffffffff
+#define PROCESSOR_INTEL_386 386
+#define PROCESSOR_INTEL_486 486
+#define PROCESSOR_INTEL_PENTIUM 586
+#define PROCESSOR_MIPS_R4000 4000
+#define PROCESSOR_ALPHA_21064 21064
+#define PROCESSOR_ARCHITECTURE_INTEL 0
+#define PROCESSOR_ARCHITECTURE_MIPS 1
+#define PROCESSOR_ARCHITECTURE_ALPHA 2
+#define PROCESSOR_ARCHITECTURE_PPC 3
+#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF
+#define PF_FLOATING_POINT_PRECISION_ERRATA 0
+#define PF_FLOATING_POINT_EMULATED 1
+#define PF_COMPARE_EXCHANGE_DOUBLE 2
+#define PF_MMX_INSTRUCTIONS_AVAILABLE 3
+#define PF_PPC_MOVEMEM_64BIT_OK 4
+#define PF_ALPHA_BYTE_INSTRUCTIONS 5
+#define PF_XMMI_INSTRUCTIONS_AVAILABLE 6
+#define PF_3DNOW_INSTRUCTIONS_AVAILABLE 7
+#define PF_RDTSC_INSTRUCTION_AVAILABLE 8
+#define PF_PAE_ENABLED 9
+#define PAGE_READONLY 2
+#define PAGE_READWRITE 4
+#define PAGE_WRITECOPY 8
+#define FILE_ACTION_ADDED	1
+#define FILE_ACTION_REMOVED	2
+#define FILE_ACTION_MODIFIED	3
+#define FILE_ACTION_RENAMED_OLD_NAME	4
+#define FILE_ACTION_RENAMED_NEW_NAME	5
+#define HEAP_NO_SERIALIZE 1
+#define HEAP_GROWABLE 2
+#define HEAP_GENERATE_EXCEPTIONS 4
+#define HEAP_ZERO_MEMORY 8
+#define HEAP_REALLOC_IN_PLACE_ONLY 16
+#define HEAP_TAIL_CHECKING_ENABLED 32
+#define HEAP_FREE_CHECKING_ENABLED 64
+#define HEAP_DISABLE_COALESCE_ON_FREE 128
+#define HEAP_CREATE_ALIGN_16 0x0000
+#define HEAP_CREATE_ENABLE_TRACING 0x20000
+#define HEAP_MAXIMUM_TAG 0xFFF
+#define HEAP_PSEUDO_TAG_FLAG 0x8000
+#define HEAP_TAG_SHIFT 16
+#define HEAP_MAKE_TAG_FLAGS(b,o) ((DWORD)((b)+(o)<<16)))
+#define KEY_QUERY_VALUE 1
+#define KEY_SET_VALUE 2
+#define KEY_CREATE_SUB_KEY 4
+#define KEY_ENUMERATE_SUB_KEYS 8
+#define KEY_NOTIFY 16
+#define KEY_CREATE_LINK 32
+#define KEY_WRITE 0x20006
+#define KEY_EXECUTE 0x20019
+#define KEY_READ 0x20019
+#define KEY_ALL_ACCESS 0xf003f
+#define REG_WHOLE_HIVE_VOLATILE	1
+#define REG_REFRESH_HIVE	2
+#define REG_NO_LAZY_FLUSH	4
+#define REG_OPTION_RESERVED	0
+#define REG_OPTION_NON_VOLATILE	0
+#define REG_OPTION_VOLATILE	1
+#define REG_OPTION_CREATE_LINK	2
+#define REG_OPTION_BACKUP_RESTORE	4
+#define REG_OPTION_OPEN_LINK	8
+#define REG_LEGAL_OPTION	15
+#define OWNER_SECURITY_INFORMATION 1
+#define GROUP_SECURITY_INFORMATION 2
+#define DACL_SECURITY_INFORMATION 4
+#define SACL_SECURITY_INFORMATION 8
+#define MAXIMUM_PROCESSORS 32
+#define PAGE_EXECUTE 16
+#define PAGE_EXECUTE_READ 32
+#define PAGE_EXECUTE_READWRITE 64
+#define PAGE_GUARD 256
+#define PAGE_NOACCESS 1
+#define PAGE_NOCACHE 512
+#define MEM_COMMIT           0x1000
+#define MEM_RESERVE          0x2000
+#define MEM_DECOMMIT         0x4000
+#define MEM_RELEASE          0x8000
+#define MEM_FREE            0x10000
+#define MEM_PRIVATE         0x20000
+#define MEM_MAPPED          0x40000
+#define MEM_RESET           0x80000
+#define MEM_TOP_DOWN       0x100000
+#define MEM_WRITE_WATCH	   0x200000 /* 98/Me */
+#define MEM_PHYSICAL	   0x400000
+#define MEM_4MB_PAGES    0x80000000
+#define MEM_IMAGE 16777216
+#define SEC_FILE 0x800000
+#define SEC_IMAGE 0x1000000
+#define SEC_VLM 0x2000000
+#define SEC_RESERVE 0x4000000
+#define SEC_COMMIT 0x8000000
+#define SEC_NOCACHE 0x10000000
+#define PAGE_EXECUTE_WRITECOPY 128
+#define SECTION_EXTEND_SIZE 16
+#define SECTION_MAP_READ 4
+#define SECTION_MAP_WRITE 2
+#define SECTION_QUERY 1
+#define SECTION_ALL_ACCESS 0xf001f
+#define MESSAGE_RESOURCE_UNICODE 1
+#define RTL_CRITSECT_TYPE 0
+#define RTL_RESOURCE_TYPE 1
+#define FIELD_OFFSET(t,f) ((LONG)&(((t*)0)->f))
+#define IMAGE_SIZEOF_FILE_HEADER	20
+#define IMAGE_FILE_RELOCS_STRIPPED	1
+#define IMAGE_FILE_EXECUTABLE_IMAGE	2
+#define IMAGE_FILE_LINE_NUMS_STRIPPED	4
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED	8
+#define IMAGE_FILE_BYTES_REVERSED_LO	128
+#define IMAGE_FILE_32BIT_MACHINE	256
+#define IMAGE_FILE_DEBUG_STRIPPED	512
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP	1024
+#define IMAGE_FILE_NET_RUN_FROM_SWAP	2048
+#define IMAGE_FILE_SYSTEM	4096
+#define IMAGE_FILE_DLL	8192
+#define IMAGE_FILE_UP_SYSTEM_ONLY	16384
+#define IMAGE_FILE_BYTES_REVERSED_HI	32768
+#define IMAGE_FILE_MACHINE_UNKNOWN	0
+#define IMAGE_FILE_MACHINE_I386	332
+#define IMAGE_FILE_MACHINE_R3000	354
+#define IMAGE_FILE_MACHINE_R4000	358
+#define IMAGE_FILE_MACHINE_R10000	360
+#define IMAGE_FILE_MACHINE_ALPHA	388
+#define IMAGE_FILE_MACHINE_POWERPC	496
+#define IMAGE_DOS_SIGNATURE 0x5A4D
+#define IMAGE_OS2_SIGNATURE 0x454E
+#define IMAGE_OS2_SIGNATURE_LE 0x454C
+#define IMAGE_VXD_SIGNATURE 0x454C
+#define IMAGE_NT_SIGNATURE 0x00004550
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b
+#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
+#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56
+#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER 224
+#define IMAGE_SIZEOF_SHORT_NAME 8
+#define IMAGE_SIZEOF_SECTION_HEADER 40
+#define IMAGE_SIZEOF_SYMBOL 18
+#define IMAGE_SIZEOF_AUX_SYMBOL 18
+#define IMAGE_SIZEOF_RELOCATION 10
+#define IMAGE_SIZEOF_BASE_RELOCATION 8
+#define IMAGE_SIZEOF_LINENUMBER 6
+#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+#define SIZEOF_RFPO_DATA 16
+#define IMAGE_SUBSYSTEM_UNKNOWN	0
+#define IMAGE_SUBSYSTEM_NATIVE	1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI	2
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI	3
+#define IMAGE_SUBSYSTEM_OS2_CUI	5
+#define IMAGE_SUBSYSTEM_POSIX_CUI	7
+#define IMAGE_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((DWORD)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader))
+#define IMAGE_DIRECTORY_ENTRY_EXPORT	0
+#define IMAGE_DIRECTORY_ENTRY_IMPORT	1
+#define IMAGE_DIRECTORY_ENTRY_RESOURCE	2
+#define IMAGE_DIRECTORY_ENTRY_EXCEPTION	3
+#define IMAGE_DIRECTORY_ENTRY_SECURITY	4
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC	5
+#define IMAGE_DIRECTORY_ENTRY_DEBUG	6
+#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT	7
+#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR	8
+#define IMAGE_DIRECTORY_ENTRY_TLS	9
+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG	10
+#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT	11
+#define IMAGE_DIRECTORY_ENTRY_IAT	12
+#define IMAGE_SCN_TYPE_NO_PAD 8
+#define IMAGE_SCN_CNT_CODE 32
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 64
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 128
+#define IMAGE_SCN_LNK_OTHER 256
+#define IMAGE_SCN_LNK_INFO 512
+#define IMAGE_SCN_LNK_REMOVE 2048
+#define IMAGE_SCN_LNK_COMDAT 4096
+#define IMAGE_SCN_MEM_FARDATA 0x8000
+#define IMAGE_SCN_MEM_PURGEABLE 0x20000
+#define IMAGE_SCN_MEM_16BIT 0x20000
+#define IMAGE_SCN_MEM_LOCKED  0x40000
+#define IMAGE_SCN_MEM_PRELOAD 0x80000
+#define IMAGE_SCN_ALIGN_1BYTES 0x100000
+#define IMAGE_SCN_ALIGN_2BYTES 0x200000
+#define IMAGE_SCN_ALIGN_4BYTES 0x300000
+#define IMAGE_SCN_ALIGN_8BYTES 0x400000
+#define IMAGE_SCN_ALIGN_16BYTES 0x500000
+#define IMAGE_SCN_ALIGN_32BYTES 0x600000
+#define IMAGE_SCN_ALIGN_64BYTES 0x700000
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x1000000
+#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
+#define IMAGE_SCN_MEM_NOT_CACHED 0x4000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x8000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+#define IMAGE_SYM_UNDEFINED	0
+#define IMAGE_SYM_ABSOLUTE (-1)
+#define IMAGE_SYM_DEBUG	(-2)
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+#define IMAGE_SYM_TYPE_PCODE 32768
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 1
+#define IMAGE_SYM_DTYPE_FUNCTION 2
+#define IMAGE_SYM_DTYPE_ARRAY 3
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION	(-1)
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLASS_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#define IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define IMAGE_COMDAT_SELECT_ANY 2
+#define IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+#define IMAGE_COMDAT_SELECT_LARGEST 6
+#define IMAGE_COMDAT_SELECT_NEWEST 7
+#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+#define IMAGE_REL_I386_ABSOLUTE 0
+#define IMAGE_REL_I386_DIR16 1
+#define IMAGE_REL_I386_REL16 2
+#define IMAGE_REL_I386_DIR32 6
+#define IMAGE_REL_I386_DIR32NB 7
+#define IMAGE_REL_I386_SEG12 9
+#define IMAGE_REL_I386_SECTION 10
+#define IMAGE_REL_I386_SECREL 11
+#define IMAGE_REL_I386_REL32 20
+#define IMAGE_REL_MIPS_ABSOLUTE 0
+#define IMAGE_REL_MIPS_REFHALF 1
+#define IMAGE_REL_MIPS_REFWORD 2
+#define IMAGE_REL_MIPS_JMPADDR 3
+#define IMAGE_REL_MIPS_REFHI 4
+#define IMAGE_REL_MIPS_REFLO 5
+#define IMAGE_REL_MIPS_GPREL 6
+#define IMAGE_REL_MIPS_LITERAL 7
+#define IMAGE_REL_MIPS_SECTION 10
+#define IMAGE_REL_MIPS_SECREL 11
+#define IMAGE_REL_MIPS_SECRELLO 12
+#define IMAGE_REL_MIPS_SECRELHI 13
+#define IMAGE_REL_MIPS_REFWORDNB 34
+#define IMAGE_REL_MIPS_PAIR 35
+#define IMAGE_REL_ALPHA_ABSOLUTE 0
+#define IMAGE_REL_ALPHA_REFLONG 1
+#define IMAGE_REL_ALPHA_REFQUAD 2
+#define IMAGE_REL_ALPHA_GPREL32 3
+#define IMAGE_REL_ALPHA_LITERAL 4
+#define IMAGE_REL_ALPHA_LITUSE 5
+#define IMAGE_REL_ALPHA_GPDISP 6
+#define IMAGE_REL_ALPHA_BRADDR 7
+#define IMAGE_REL_ALPHA_HINT 8
+#define IMAGE_REL_ALPHA_INLINE_REFLONG 9
+#define IMAGE_REL_ALPHA_REFHI 10
+#define IMAGE_REL_ALPHA_REFLO 11
+#define IMAGE_REL_ALPHA_PAIR 12
+#define IMAGE_REL_ALPHA_MATCH 13
+#define IMAGE_REL_ALPHA_SECTION 14
+#define IMAGE_REL_ALPHA_SECREL 15
+#define IMAGE_REL_ALPHA_REFLONGNB 16
+#define IMAGE_REL_ALPHA_SECRELLO 17
+#define IMAGE_REL_ALPHA_SECRELHI 18
+#define IMAGE_REL_PPC_ABSOLUTE 0
+#define IMAGE_REL_PPC_ADDR64 1
+#define IMAGE_REL_PPC_ADDR32 2
+#define IMAGE_REL_PPC_ADDR24 3
+#define IMAGE_REL_PPC_ADDR16 4
+#define IMAGE_REL_PPC_ADDR14 5
+#define IMAGE_REL_PPC_REL24 6
+#define IMAGE_REL_PPC_REL14 7
+#define IMAGE_REL_PPC_TOCREL16 8
+#define IMAGE_REL_PPC_TOCREL14 9
+#define IMAGE_REL_PPC_ADDR32NB 10
+#define IMAGE_REL_PPC_SECREL 11
+#define IMAGE_REL_PPC_SECTION 12
+#define IMAGE_REL_PPC_IFGLUE 13
+#define IMAGE_REL_PPC_IMGLUE 14
+#define IMAGE_REL_PPC_SECREL16 15
+#define IMAGE_REL_PPC_REFHI 16
+#define IMAGE_REL_PPC_REFLO 17
+#define IMAGE_REL_PPC_PAIR 18
+#define IMAGE_REL_PPC_TYPEMASK 255
+#define IMAGE_REL_PPC_NEG 256
+#define IMAGE_REL_PPC_BRTAKEN 512
+#define IMAGE_REL_PPC_BRNTAKEN 1024
+#define IMAGE_REL_PPC_TOCDEFN 2048
+#define IMAGE_REL_BASED_ABSOLUTE 0
+#define IMAGE_REL_BASED_HIGH 1
+#define IMAGE_REL_BASED_LOW 2
+#define IMAGE_REL_BASED_HIGHLOW 3
+#define IMAGE_REL_BASED_HIGHADJ 4
+#define IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define IMAGE_ARCHIVE_START_SIZE 8
+#define IMAGE_ARCHIVE_START "!<arch>\n"
+#define IMAGE_ARCHIVE_END "`\n"
+#define IMAGE_ARCHIVE_PAD "\n"
+#define IMAGE_ARCHIVE_LINKER_MEMBER "/               "
+#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "//              "
+#define IMAGE_ORDINAL_FLAG 0x80000000
+#define IMAGE_SNAP_BY_ORDINAL(o) ((o&IMAGE_ORDINAL_FLAG)!=0)
+#define IMAGE_ORDINAL(o) (o&0xffff)
+#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000
+#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000
+#define IMAGE_DEBUG_TYPE_UNKNOWN 0
+#define IMAGE_DEBUG_TYPE_COFF 1
+#define IMAGE_DEBUG_TYPE_CODEVIEW 2
+#define IMAGE_DEBUG_TYPE_FPO 3
+#define IMAGE_DEBUG_TYPE_MISC 4
+#define IMAGE_DEBUG_TYPE_EXCEPTION 5
+#define IMAGE_DEBUG_TYPE_FIXUP 6
+#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7
+#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8
+#define FRAME_FPO 0
+#define FRAME_TRAP 1
+#define FRAME_TSS 2
+#define FRAME_NONFPO 3
+#define IMAGE_DEBUG_MISC_EXENAME 1
+#define N_BTMASK 0x000F
+#define N_TMASK 0x0030
+#define N_TMASK1 0x00C0
+#define N_TMASK2 0x00F0
+#define N_BTSHFT 4
+#define N_TSHIFT 2
+#define IS_TEXT_UNICODE_ASCII16 1
+#define IS_TEXT_UNICODE_REVERSE_ASCII16 16
+#define IS_TEXT_UNICODE_STATISTICS 2
+#define IS_TEXT_UNICODE_REVERSE_STATISTICS 32
+#define IS_TEXT_UNICODE_CONTROLS 4
+#define IS_TEXT_UNICODE_REVERSE_CONTROLS 64
+#define IS_TEXT_UNICODE_SIGNATURE 8
+#define IS_TEXT_UNICODE_REVERSE_SIGNATURE 128
+#define IS_TEXT_UNICODE_ILLEGAL_CHARS 256
+#define IS_TEXT_UNICODE_ODD_LENGTH 512
+#define IS_TEXT_UNICODE_NULL_BYTES 4096
+#define IS_TEXT_UNICODE_UNICODE_MASK 15
+#define IS_TEXT_UNICODE_REVERSE_MASK 240
+#define IS_TEXT_UNICODE_NOT_UNICODE_MASK 3840
+#define IS_TEXT_UNICODE_NOT_ASCII_MASK 61440
+#define SERVICE_KERNEL_DRIVER 1
+#define SERVICE_FILE_SYSTEM_DRIVER 2
+#define SERVICE_ADAPTER 4
+#define SERVICE_RECOGNIZER_DRIVER 8
+#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER|SERVICE_FILE_SYSTEM_DRIVER|SERVICE_RECOGNIZER_DRIVER)
+#define SERVICE_WIN32_OWN_PROCESS 16
+#define SERVICE_WIN32_SHARE_PROCESS 32
+#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS|SERVICE_WIN32_SHARE_PROCESS)
+#define SERVICE_INTERACTIVE_PROCESS 256
+#define SERVICE_TYPE_ALL (SERVICE_WIN32|SERVICE_ADAPTER|SERVICE_DRIVER|SERVICE_INTERACTIVE_PROCESS)
+#define SERVICE_BOOT_START 0
+#define SERVICE_SYSTEM_START 1
+#define SERVICE_AUTO_START 2
+#define SERVICE_DEMAND_START 3
+#define SERVICE_DISABLED 4
+#define SERVICE_ERROR_IGNORE 0
+#define SERVICE_ERROR_NORMAL 1
+#define SERVICE_ERROR_SEVERE 2
+#define SERVICE_ERROR_CRITICAL 3
+#define SE_OWNER_DEFAULTED 1
+#define SE_GROUP_DEFAULTED 2
+#define SE_DACL_PRESENT 4
+#define SE_DACL_DEFAULTED 8
+#define SE_SACL_PRESENT 16
+#define SE_SACL_DEFAULTED 32
+#define SE_DACL_AUTO_INHERIT_REQ 256
+#define SE_SACL_AUTO_INHERIT_REQ 512
+#define SE_DACL_AUTO_INHERITED 1024
+#define SE_SACL_AUTO_INHERITED 2048
+#define SE_DACL_PROTECTED 4096
+#define SE_SACL_PROTECTED 8192
+#define SE_SELF_RELATIVE 0x8000
+#define SECURITY_DESCRIPTOR_MIN_LENGTH 20
+#define SECURITY_DESCRIPTOR_REVISION 1
+#define SECURITY_DESCRIPTOR_REVISION1 1
+#define SE_PRIVILEGE_ENABLED_BY_DEFAULT 1
+#define SE_PRIVILEGE_ENABLED 2
+#define SE_PRIVILEGE_USED_FOR_ACCESS 0x80000000
+#define PRIVILEGE_SET_ALL_NECESSARY 1
+#define SECURITY_MAX_IMPERSONATION_LEVEL SecurityDelegation
+#define DEFAULT_IMPERSONATION_LEVEL SecurityImpersonation
+#define SECURITY_DYNAMIC_TRACKING TRUE
+#define SECURITY_STATIC_TRACKING FALSE
+#define TOKEN_SOURCE_LENGTH 8
+#define TOKEN_ADJUST_DEFAULT	128
+#define TOKEN_ADJUST_GROUPS	64
+#define TOKEN_ADJUST_PRIVILEGES	32
+#define TOKEN_ALL_ACCESS	0xf00ff
+#define TOKEN_ASSIGN_PRIMARY	1
+#define TOKEN_DUPLICATE	2
+#define TOKEN_EXECUTE	0x20000
+#define TOKEN_IMPERSONATE	4
+#define TOKEN_QUERY	8
+#define TOKEN_QUERY_SOURCE	16
+#define TOKEN_READ	0x20008
+#define TOKEN_WRITE	0x200e0
+#define DLL_PROCESS_DETACH	0
+#define DLL_PROCESS_ATTACH	1
+#define DLL_THREAD_ATTACH	2
+#define DLL_THREAD_DETACH	3
+#define DBG_CONTINUE 0x10002
+#define DBG_TERMINATE_THREAD 0x40010003
+#define DBG_TERMINATE_PROCESS 0x40010004
+#define DBG_CONTROL_C 0x40010005
+#define DBG_CONTROL_BREAK 0x40010008
+#define DBG_EXCEPTION_NOT_HANDLED 0x80010001
+#define TAPE_ABSOLUTE_POSITION 0
+#define TAPE_LOGICAL_POSITION 1
+#define TAPE_PSEUDO_LOGICAL_POSITION 2
+#define TAPE_REWIND 0
+#define TAPE_ABSOLUTE_BLOCK 1
+#define TAPE_LOGICAL_BLOCK 2
+#define TAPE_PSEUDO_LOGICAL_BLOCK 3
+#define TAPE_SPACE_END_OF_DATA 4
+#define TAPE_SPACE_RELATIVE_BLOCKS 5
+#define TAPE_SPACE_FILEMARKS 6
+#define TAPE_SPACE_SEQUENTIAL_FMKS 7
+#define TAPE_SPACE_SETMARKS 8
+#define TAPE_SPACE_SEQUENTIAL_SMKS 9
+#define TAPE_DRIVE_FIXED 1
+#define TAPE_DRIVE_SELECT 2
+#define TAPE_DRIVE_INITIATOR 4
+#define TAPE_DRIVE_ERASE_SHORT 16
+#define TAPE_DRIVE_ERASE_LONG 32
+#define TAPE_DRIVE_ERASE_BOP_ONLY 64
+#define TAPE_DRIVE_ERASE_IMMEDIATE 128
+#define TAPE_DRIVE_TAPE_CAPACITY 256
+#define TAPE_DRIVE_TAPE_REMAINING 512
+#define TAPE_DRIVE_FIXED_BLOCK 1024
+#define TAPE_DRIVE_VARIABLE_BLOCK 2048
+#define TAPE_DRIVE_WRITE_PROTECT 4096
+#define TAPE_DRIVE_EOT_WZ_SIZE 8192
+#define TAPE_DRIVE_ECC 0x10000
+#define TAPE_DRIVE_COMPRESSION 0x20000
+#define TAPE_DRIVE_PADDING 0x40000
+#define TAPE_DRIVE_REPORT_SMKS 0x80000
+#define TAPE_DRIVE_GET_ABSOLUTE_BLK 0x100000
+#define TAPE_DRIVE_GET_LOGICAL_BLK 0x200000
+#define TAPE_DRIVE_SET_EOT_WZ_SIZE 0x400000
+#define TAPE_DRIVE_EJECT_MEDIA 0x1000000
+#define TAPE_DRIVE_CLEAN_REQUESTS 0x2000000
+#define TAPE_DRIVE_SET_CMP_BOP_ONLY 0x4000000
+#define TAPE_DRIVE_RESERVED_BIT 0x80000000
+#define TAPE_DRIVE_LOAD_UNLOAD 0x80000001
+#define TAPE_DRIVE_TENSION 0x80000002
+#define TAPE_DRIVE_LOCK_UNLOCK 0x80000004
+#define TAPE_DRIVE_REWIND_IMMEDIATE 0x80000008
+#define TAPE_DRIVE_SET_BLOCK_SIZE 0x80000010
+#define TAPE_DRIVE_LOAD_UNLD_IMMED 0x80000020
+#define TAPE_DRIVE_TENSION_IMMED 0x80000040
+#define TAPE_DRIVE_LOCK_UNLK_IMMED 0x80000080
+#define TAPE_DRIVE_SET_ECC 0x80000100
+#define TAPE_DRIVE_SET_COMPRESSION 0x80000200
+#define TAPE_DRIVE_SET_PADDING 0x80000400
+#define TAPE_DRIVE_SET_REPORT_SMKS 0x80000800
+#define TAPE_DRIVE_ABSOLUTE_BLK 0x80001000
+#define TAPE_DRIVE_ABS_BLK_IMMED 0x80002000
+#define TAPE_DRIVE_LOGICAL_BLK 0x80004000
+#define TAPE_DRIVE_LOG_BLK_IMMED 0x80008000
+#define TAPE_DRIVE_END_OF_DATA 0x80010000
+#define TAPE_DRIVE_RELATIVE_BLKS 0x80020000
+#define TAPE_DRIVE_FILEMARKS 0x80040000
+#define TAPE_DRIVE_SEQUENTIAL_FMKS 0x80080000
+#define TAPE_DRIVE_SETMARKS 0x80100000
+#define TAPE_DRIVE_SEQUENTIAL_SMKS 0x80200000
+#define TAPE_DRIVE_REVERSE_POSITION 0x80400000
+#define TAPE_DRIVE_SPACE_IMMEDIATE 0x80800000
+#define TAPE_DRIVE_WRITE_SETMARKS 0x81000000
+#define TAPE_DRIVE_WRITE_FILEMARKS 0x82000000
+#define TAPE_DRIVE_WRITE_SHORT_FMKS 0x84000000
+#define TAPE_DRIVE_WRITE_LONG_FMKS 0x88000000
+#define TAPE_DRIVE_WRITE_MARK_IMMED 0x90000000
+#define TAPE_DRIVE_FORMAT 0xA0000000
+#define TAPE_DRIVE_FORMAT_IMMEDIATE 0xC0000000
+#define TAPE_DRIVE_HIGH_FEATURES 0x80000000
+#define TAPE_FIXED_PARTITIONS	0
+#define TAPE_INITIATOR_PARTITIONS	2
+#define TAPE_SELECT_PARTITIONS	1
+#define TAPE_FILEMARKS	1
+#define TAPE_LONG_FILEMARKS	3
+#define TAPE_SETMARKS	0
+#define TAPE_SHORT_FILEMARKS	2
+#define TAPE_ERASE_LONG 1
+#define TAPE_ERASE_SHORT 0
+#define TAPE_LOAD 0
+#define TAPE_UNLOAD 1
+#define TAPE_TENSION 2
+#define TAPE_LOCK 3
+#define TAPE_UNLOCK 4
+#define TAPE_FORMAT 5
+#define VER_PLATFORM_WIN32s 0
+#define VER_PLATFORM_WIN32_WINDOWS 1
+#define VER_PLATFORM_WIN32_NT 2
+#define VER_NT_WORKSTATION 1
+#define VER_NT_DOMAIN_CONTROLLER 2
+#define VER_NT_SERVER 3
+#define VER_SUITE_SMALLBUSINESS 1
+#define VER_SUITE_ENTERPRISE 2
+#define VER_SUITE_BACKOFFICE 4
+#define VER_SUITE_TERMINAL 16
+#define VER_SUITE_SMALLBUSINESS_RESTRICTED 32
+#define VER_SUITE_DATACENTER 128
+#define VER_SUITE_PERSONAL 512
+#define BTYPE(x) ((x)&N_BTMASK)
+#define ISPTR(x) (((x)&N_TMASK)==(IMAGE_SYM_DTYPE_POINTER<<N_BTSHFT))
+#define ISFCN(x) (((x)&N_TMASK)==(IMAGE_SYM_DTYPE_FUNCTION<<N_BTSHFT))
+#define ISARY(x) (((x)&N_TMASK)==(IMAGE_SYM_DTYPE_ARRAY<<N_BTSHFT))
+#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG||(x)==IMAGE_SYM_CLASS_UNION_TAG||(x)==IMAGE_SYM_CLASS_ENUM_TAG)
+#define INCREF(x) ((((x)&~N_BTMASK)<<N_TSHIFT)|(IMAGE_SYM_DTYPE_POINTER<<N_BTSHFT)|((x)&N_BTMASK))
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+#define TLS_MINIMUM_AVAILABLE 64
+#define REPARSE_DATA_BUFFER_HEADER_SIZE   FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
+#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE   FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer)
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE 16384
+#define IO_REPARSE_TAG_RESERVED_ZERO 0
+#define IO_REPARSE_TAG_RESERVED_ONE 1
+#define IO_REPARSE_TAG_RESERVED_RANGE IO_REPARSE_TAG_RESERVED_ONE
+#define IsReparseTagMicrosoft(x) ((x)&0x80000000)
+#define IsReparseTagHighLatency(x) ((x)&0x40000000)
+#define IsReparseTagNameSurrogate(x) ((x)&0x20000000)
+#define IO_REPARSE_TAG_VALID_VALUES 0xE000FFFF
+#define IsReparseTagValid(x) (!((x)&~IO_REPARSE_TAG_VALID_VALUES)&&((x)>IO_REPARSE_TAG_RESERVED_RANGE))
+#define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO
+#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#ifndef RC_INVOKED
+typedef DWORD ACCESS_MASK, *PACCESS_MASK;
+#ifndef _GUID_DEFINED /* also defined in basetyps.h */
+#define _GUID_DEFINED
+typedef struct _GUID {
+	unsigned long  Data1;
+	unsigned short Data2;
+	unsigned short Data3;
+	unsigned char  Data4[8];
+} GUID, *REFGUID, *LPGUID;
+#define SYSTEM_LUID { QuadPart:999 }
+#endif /* _GUID_DEFINED */
+typedef struct _GENERIC_MAPPING {
+	ACCESS_MASK GenericRead;
+	ACCESS_MASK GenericWrite;
+	ACCESS_MASK GenericExecute;
+	ACCESS_MASK GenericAll;
+} GENERIC_MAPPING, *PGENERIC_MAPPING;
+typedef struct _ACE_HEADER {
+	BYTE AceType;
+	BYTE AceFlags;
+	WORD AceSize;
+} ACE_HEADER;
+typedef struct _ACCESS_ALLOWED_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD SidStart;
+} ACCESS_ALLOWED_ACE;
+typedef struct _ACCESS_DENIED_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD SidStart;
+} ACCESS_DENIED_ACE;
+typedef struct _SYSTEM_AUDIT_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD SidStart;
+} SYSTEM_AUDIT_ACE;
+typedef SYSTEM_AUDIT_ACE *PSYSTEM_AUDIT_ACE;
+typedef struct _SYSTEM_ALARM_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD SidStart;
+} SYSTEM_ALARM_ACE,*PSYSTEM_ALARM_ACE;
+typedef struct _ACCESS_ALLOWED_OBJECT_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD Flags;
+	GUID ObjectType;
+	GUID InheritedObjectType;
+	DWORD SidStart;
+} ACCESS_ALLOWED_OBJECT_ACE,*PACCESS_ALLOWED_OBJECT_ACE;
+typedef struct _ACCESS_DENIED_OBJECT_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD Flags;
+	GUID ObjectType;
+	GUID InheritedObjectType;
+	DWORD SidStart;
+} ACCESS_DENIED_OBJECT_ACE,*PACCESS_DENIED_OBJECT_ACE;
+typedef struct _SYSTEM_AUDIT_OBJECT_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD Flags;
+	GUID ObjectType;
+	GUID InheritedObjectType;
+	DWORD SidStart;
+} SYSTEM_AUDIT_OBJECT_ACE,*PSYSTEM_AUDIT_OBJECT_ACE;
+typedef struct _SYSTEM_ALARM_OBJECT_ACE {
+	ACE_HEADER Header;
+	ACCESS_MASK Mask;
+	DWORD Flags;
+	GUID ObjectType;
+	GUID InheritedObjectType;
+	DWORD SidStart;
+} SYSTEM_ALARM_OBJECT_ACE,*PSYSTEM_ALARM_OBJECT_ACE;
+typedef struct _ACL {
+	BYTE AclRevision;
+	BYTE Sbz1;
+	WORD AclSize;
+	WORD AceCount;
+	WORD Sbz2;
+} ACL,*PACL;
+typedef struct _ACL_REVISION_INFORMATION {
+	DWORD AclRevision;
+} ACL_REVISION_INFORMATION;
+typedef struct _ACL_SIZE_INFORMATION {
+	DWORD   AceCount;
+	DWORD   AclBytesInUse;
+	DWORD   AclBytesFree;
+} ACL_SIZE_INFORMATION;
+
+/* FIXME: add more machines */
+#ifdef _X86_
+#define SIZE_OF_80387_REGISTERS	80
+#define CONTEXT_i386	0x10000
+#define CONTEXT_i486	0x10000
+#define CONTEXT_CONTROL	(CONTEXT_i386|0x00000001L)
+#define CONTEXT_INTEGER	(CONTEXT_i386|0x00000002L)
+#define CONTEXT_SEGMENTS	(CONTEXT_i386|0x00000004L)
+#define CONTEXT_FLOATING_POINT	(CONTEXT_i386|0x00000008L)
+#define CONTEXT_DEBUG_REGISTERS	(CONTEXT_i386|0x00000010L)
+#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386|0x00000020L)
+#define CONTEXT_FULL	(CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS)
+#define MAXIMUM_SUPPORTED_EXTENSION  512
+typedef struct _FLOATING_SAVE_AREA {
+	DWORD	ControlWord;
+	DWORD	StatusWord;
+	DWORD	TagWord;
+	DWORD	ErrorOffset;
+	DWORD	ErrorSelector;
+	DWORD	DataOffset;
+	DWORD	DataSelector;
+	BYTE	RegisterArea[80];
+	DWORD	Cr0NpxState;
+} FLOATING_SAVE_AREA;
+typedef struct _CONTEXT {
+	DWORD	ContextFlags;
+	DWORD	Dr0;
+	DWORD	Dr1;
+	DWORD	Dr2;
+	DWORD	Dr3;
+	DWORD	Dr6;
+	DWORD	Dr7;
+	FLOATING_SAVE_AREA FloatSave;
+	DWORD	SegGs;
+	DWORD	SegFs;
+	DWORD	SegEs;
+	DWORD	SegDs;
+	DWORD	Edi;
+	DWORD	Esi;
+	DWORD	Ebx;
+	DWORD	Edx;
+	DWORD	Ecx;
+	DWORD	Eax;
+	DWORD	Ebp;
+	DWORD	Eip;
+	DWORD	SegCs;
+	DWORD	EFlags;
+	DWORD	Esp;
+	DWORD	SegSs;
+	BYTE	ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
+} CONTEXT;
+#elif defined(_PPC_)
+#define CONTEXT_CONTROL	1L
+#define CONTEXT_FLOATING_POINT	2L
+#define CONTEXT_INTEGER	4L
+#define CONTEXT_DEBUG_REGISTERS	8L
+#define CONTEXT_FULL (CONTEXT_CONTROL|CONTEXT_FLOATING_POINT|CONTEXT_INTEGER)
+typedef struct {
+	double Fpr0;
+	double Fpr1;
+	double Fpr2;
+	double Fpr3;
+	double Fpr4;
+	double Fpr5;
+	double Fpr6;
+	double Fpr7;
+	double Fpr8;
+	double Fpr9;
+	double Fpr10;
+	double Fpr11;
+	double Fpr12;
+	double Fpr13;
+	double Fpr14;
+	double Fpr15;
+	double Fpr16;
+	double Fpr17;
+	double Fpr18;
+	double Fpr19;
+	double Fpr20;
+	double Fpr21;
+	double Fpr22;
+	double Fpr23;
+	double Fpr24;
+	double Fpr25;
+	double Fpr26;
+	double Fpr27;
+	double Fpr28;
+	double Fpr29;
+	double Fpr30;
+	double Fpr31;
+	double Fpscr;
+	DWORD Gpr0;
+	DWORD Gpr1;
+	DWORD Gpr2;
+	DWORD Gpr3;
+	DWORD Gpr4;
+	DWORD Gpr5;
+	DWORD Gpr6;
+	DWORD Gpr7;
+	DWORD Gpr8;
+	DWORD Gpr9;
+	DWORD Gpr10;
+	DWORD Gpr11;
+	DWORD Gpr12;
+	DWORD Gpr13;
+	DWORD Gpr14;
+	DWORD Gpr15;
+	DWORD Gpr16;
+	DWORD Gpr17;
+	DWORD Gpr18;
+	DWORD Gpr19;
+	DWORD Gpr20;
+	DWORD Gpr21;
+	DWORD Gpr22;
+	DWORD Gpr23;
+	DWORD Gpr24;
+	DWORD Gpr25;
+	DWORD Gpr26;
+	DWORD Gpr27;
+	DWORD Gpr28;
+	DWORD Gpr29;
+	DWORD Gpr30;
+	DWORD Gpr31;
+	DWORD Cr;
+	DWORD Xer;
+	DWORD Msr;
+	DWORD Iar;
+	DWORD Lr;
+	DWORD Ctr;
+	DWORD ContextFlags;
+	DWORD Fill[3];
+	DWORD Dr0;
+	DWORD Dr1;
+	DWORD Dr2;
+	DWORD Dr3;
+	DWORD Dr4;
+	DWORD Dr5;
+	DWORD Dr6;
+	DWORD Dr7;
+} CONTEXT;
+#elif defined(_ALPHA_)
+#define CONTEXT_ALPHA	0x20000
+#define CONTEXT_CONTROL	(CONTEXT_ALPHA|1L)
+#define CONTEXT_FLOATING_POINT	(CONTEXT_ALPHA|2L)
+#define CONTEXT_INTEGER	(CONTEXT_ALPHA|4L)
+#define CONTEXT_FULL	(CONTEXT_CONTROL|CONTEXT_FLOATING_POINT|CONTEXT_INTEGER)
+typedef struct _CONTEXT {
+	ULONGLONG FltF0;
+	ULONGLONG FltF1;
+	ULONGLONG FltF2;
+	ULONGLONG FltF3;
+	ULONGLONG FltF4;
+	ULONGLONG FltF5;
+	ULONGLONG FltF6;
+	ULONGLONG FltF7;
+	ULONGLONG FltF8;
+	ULONGLONG FltF9;
+	ULONGLONG FltF10;
+	ULONGLONG FltF11;
+	ULONGLONG FltF12;
+	ULONGLONG FltF13;
+	ULONGLONG FltF14;
+	ULONGLONG FltF15;
+	ULONGLONG FltF16;
+	ULONGLONG FltF17;
+	ULONGLONG FltF18;
+	ULONGLONG FltF19;
+	ULONGLONG FltF20;
+	ULONGLONG FltF21;
+	ULONGLONG FltF22;
+	ULONGLONG FltF23;
+	ULONGLONG FltF24;
+	ULONGLONG FltF25;
+	ULONGLONG FltF26;
+	ULONGLONG FltF27;
+	ULONGLONG FltF28;
+	ULONGLONG FltF29;
+	ULONGLONG FltF30;
+	ULONGLONG FltF31;
+	ULONGLONG IntV0;
+	ULONGLONG IntT0;
+	ULONGLONG IntT1;
+	ULONGLONG IntT2;
+	ULONGLONG IntT3;
+	ULONGLONG IntT4;
+	ULONGLONG IntT5;
+	ULONGLONG IntT6;
+	ULONGLONG IntT7;
+	ULONGLONG IntS0;
+	ULONGLONG IntS1;
+	ULONGLONG IntS2;
+	ULONGLONG IntS3;
+	ULONGLONG IntS4;
+	ULONGLONG IntS5;
+	ULONGLONG IntFp;
+	ULONGLONG IntA0;
+	ULONGLONG IntA1;
+	ULONGLONG IntA2;
+	ULONGLONG IntA3;
+	ULONGLONG IntA4;
+	ULONGLONG IntA5;
+	ULONGLONG IntT8;
+	ULONGLONG IntT9;
+	ULONGLONG IntT10;
+	ULONGLONG IntT11;
+	ULONGLONG IntRa;
+	ULONGLONG IntT12;
+	ULONGLONG IntAt;
+	ULONGLONG IntGp;
+	ULONGLONG IntSp;
+	ULONGLONG IntZero;
+	ULONGLONG Fpcr;
+	ULONGLONG SoftFpcr;
+	ULONGLONG Fir;
+	DWORD Psr;
+	DWORD ContextFlags;
+	DWORD Fill[4];
+} CONTEXT;
+#elif defined(SHx)
+
+/* These are the debug or break registers on the SH3 */
+typedef struct _DEBUG_REGISTERS {
+	ULONG  BarA;
+	UCHAR  BasrA;
+	UCHAR  BamrA;
+	USHORT BbrA;
+	ULONG  BarB;
+	UCHAR  BasrB;
+	UCHAR  BamrB;
+	USHORT BbrB;
+	ULONG  BdrB;
+	ULONG  BdmrB;
+	USHORT Brcr;
+	USHORT Align;
+} DEBUG_REGISTERS, *PDEBUG_REGISTERS;
+
+/* The following flags control the contents of the CONTEXT structure. */
+
+#define CONTEXT_SH3		0x00000040
+#define CONTEXT_SH4		0x000000c0	/* CONTEXT_SH3 | 0x80 - must contain the SH3 bits */
+
+#ifdef SH3
+#define CONTEXT_CONTROL         (CONTEXT_SH3 | 0x00000001L)
+#define CONTEXT_INTEGER         (CONTEXT_SH3 | 0x00000002L)
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_SH3 | 0x00000008L)
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_DEBUG_REGISTERS)
+#else	/* SH4 */
+#define CONTEXT_CONTROL         (CONTEXT_SH4 | 0x00000001L)
+#define CONTEXT_INTEGER         (CONTEXT_SH4 | 0x00000002L)
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_SH4 | 0x00000008L)
+#define CONTEXT_FLOATING_POINT  (CONTEXT_SH4 | 0x00000004L)
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_DEBUG_REGISTERS | CONTEXT_FLOATING_POINT)
+#endif
+
+/* Context Frame */
+
+/*  This frame is used to store a limited processor context into the */
+/* Thread structure for CPUs which have no floating point support. */
+
+typedef struct _CONTEXT {
+	/* The flags values within this flag control the contents of */
+	/* a CONTEXT record. */
+
+	/* If the context record is used as an input parameter, then */
+	/* for each portion of the context record controlled by a flag */
+	/* whose value is set, it is assumed that that portion of the */
+	/* context record contains valid context. If the context record */
+	/* is being used to modify a thread's context, then only that */
+	/* portion of the threads context will be modified. */
+
+	/* If the context record is used as an IN OUT parameter to capture */
+	/* the context of a thread, then only those portions of the thread's */
+	/* context corresponding to set flags will be returned. */
+
+	/* The context record is never used as an OUT only parameter. */
+
+
+	ULONG ContextFlags;
+
+	/* This section is specified/returned if the ContextFlags word contains */
+	/* the flag CONTEXT_INTEGER. */
+
+	/* N.B. The registers RA and R15 are defined in this section, but are */
+	/*  considered part of the control context rather than part of the integer */
+	/*  context. */
+
+	ULONG PR;
+	ULONG MACH;
+	ULONG MACL;
+	ULONG GBR;
+	ULONG R0;
+	ULONG R1;
+	ULONG R2;
+	ULONG R3;
+	ULONG R4;
+	ULONG R5;
+	ULONG R6;
+	ULONG R7;
+	ULONG R8;
+	ULONG R9;
+	ULONG R10;
+	ULONG R11;
+	ULONG R12;
+	ULONG R13;
+	ULONG R14;
+	ULONG R15;
+
+	/* This section is specified/returned if the ContextFlags word contains */
+	/* the flag CONTEXT_CONTROL. */
+
+	/* N.B. The registers r15 and ra are defined in the integer section, */
+	/*   but are considered part of the control context rather than part of */
+	/*   the integer context. */
+
+	ULONG Fir;
+	ULONG Psr;
+
+#if !defined(SH3e) && !defined(SH4)
+	ULONG	OldStuff[2];
+	DEBUG_REGISTERS DebugRegisters;
+#else
+	ULONG	Fpscr;
+	ULONG	Fpul;
+	ULONG	FRegs[16];
+#if defined(SH4)
+	ULONG	xFRegs[16];
+#endif
+#endif
+} CONTEXT;
+
+#elif defined(MIPS)
+
+/* The following flags control the contents of the CONTEXT structure. */
+
+#define CONTEXT_R4000   0x00010000    /* r4000 context */
+
+#define CONTEXT_CONTROL         (CONTEXT_R4000 | 0x00000001L)
+#define CONTEXT_FLOATING_POINT  (CONTEXT_R4000 | 0x00000002L)
+#define CONTEXT_INTEGER         (CONTEXT_R4000 | 0x00000004L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER)
+
+/* Context Frame */
+
+/*  N.B. This frame must be exactly a multiple of 16 bytes in length. */
+
+/*  This frame has a several purposes: 1) it is used as an argument to */
+/*  NtContinue, 2) it is used to constuct a call frame for APC delivery, */
+/*  3) it is used to construct a call frame for exception dispatching */
+/*  in user mode, and 4) it is used in the user level thread creation */
+/*  routines. */
+
+/*  The layout of the record conforms to a standard call frame. */
+
+
+typedef struct _CONTEXT {
+
+	/* This section is always present and is used as an argument build */
+	/* area. */
+
+	DWORD Argument[4];
+
+	/* This section is specified/returned if the ContextFlags word contains */
+	/* the flag CONTEXT_FLOATING_POINT. */
+
+	DWORD FltF0;
+	DWORD FltF1;
+	DWORD FltF2;
+	DWORD FltF3;
+	DWORD FltF4;
+	DWORD FltF5;
+	DWORD FltF6;
+	DWORD FltF7;
+	DWORD FltF8;
+	DWORD FltF9;
+	DWORD FltF10;
+	DWORD FltF11;
+	DWORD FltF12;
+	DWORD FltF13;
+	DWORD FltF14;
+	DWORD FltF15;
+	DWORD FltF16;
+	DWORD FltF17;
+	DWORD FltF18;
+	DWORD FltF19;
+	DWORD FltF20;
+	DWORD FltF21;
+	DWORD FltF22;
+	DWORD FltF23;
+	DWORD FltF24;
+	DWORD FltF25;
+	DWORD FltF26;
+	DWORD FltF27;
+	DWORD FltF28;
+	DWORD FltF29;
+	DWORD FltF30;
+	DWORD FltF31;
+
+	/* This section is specified/returned if the ContextFlags word contains */
+	/* the flag CONTEXT_INTEGER. */
+
+	/* N.B. The registers gp, sp, and ra are defined in this section, but are */
+	/*  considered part of the control context rather than part of the integer */
+	/*  context. */
+
+	/* N.B. Register zero is not stored in the frame. */
+
+	DWORD IntZero;
+	DWORD IntAt;
+	DWORD IntV0;
+	DWORD IntV1;
+	DWORD IntA0;
+	DWORD IntA1;
+	DWORD IntA2;
+	DWORD IntA3;
+	DWORD IntT0;
+	DWORD IntT1;
+	DWORD IntT2;
+	DWORD IntT3;
+	DWORD IntT4;
+	DWORD IntT5;
+	DWORD IntT6;
+	DWORD IntT7;
+	DWORD IntS0;
+	DWORD IntS1;
+	DWORD IntS2;
+	DWORD IntS3;
+	DWORD IntS4;
+	DWORD IntS5;
+	DWORD IntS6;
+	DWORD IntS7;
+	DWORD IntT8;
+	DWORD IntT9;
+	DWORD IntK0;
+	DWORD IntK1;
+	DWORD IntGp;
+	DWORD IntSp;
+	DWORD IntS8;
+	DWORD IntRa;
+	DWORD IntLo;
+	DWORD IntHi;
+
+	/* This section is specified/returned if the ContextFlags word contains */
+	/* the flag CONTEXT_FLOATING_POINT. */
+
+	DWORD Fsr;
+
+	/* This section is specified/returned if the ContextFlags word contains */
+	/* the flag CONTEXT_CONTROL. */
+
+	/* N.B. The registers gp, sp, and ra are defined in the integer section, */
+	/*   but are considered part of the control context rather than part of */
+	/*   the integer context. */
+
+	DWORD Fir;
+	DWORD Psr;
+
+	/* The flags values within this flag control the contents of */
+	/* a CONTEXT record. */
+
+	/* If the context record is used as an input parameter, then */
+	/* for each portion of the context record controlled by a flag */
+	/* whose value is set, it is assumed that that portion of the */
+	/* context record contains valid context. If the context record */
+	/* is being used to modify a thread's context, then only that */
+	/* portion of the threads context will be modified. */
+
+	/* If the context record is used as an IN OUT parameter to capture */
+	/* the context of a thread, then only those portions of the thread's */
+	/* context corresponding to set flags will be returned. */
+
+	/* The context record is never used as an OUT only parameter. */
+
+	DWORD ContextFlags;
+
+	DWORD Fill[2];
+
+} CONTEXT;
+#elif defined(ARM)
+
+/* The following flags control the contents of the CONTEXT structure. */
+
+#define CONTEXT_ARM    0x0000040
+#define CONTEXT_CONTROL         (CONTEXT_ARM | 0x00000001L)
+#define CONTEXT_INTEGER         (CONTEXT_ARM | 0x00000002L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER)
+
+typedef struct _CONTEXT {
+	/* The flags values within this flag control the contents of
+	   a CONTEXT record.
+	  
+	   If the context record is used as an input parameter, then
+	   for each portion of the context record controlled by a flag
+	   whose value is set, it is assumed that that portion of the
+	   context record contains valid context. If the context record
+	   is being used to modify a thread's context, then only that
+	   portion of the threads context will be modified.
+	  
+	   If the context record is used as an IN OUT parameter to capture
+	   the context of a thread, then only those portions of the thread's
+	   context corresponding to set flags will be returned.
+	  
+	   The context record is never used as an OUT only parameter. */
+
+	ULONG ContextFlags;
+
+	/* This section is specified/returned if the ContextFlags word contains
+	   the flag CONTEXT_INTEGER. */
+	ULONG R0;
+	ULONG R1;
+	ULONG R2;
+	ULONG R3;
+	ULONG R4;
+	ULONG R5;
+	ULONG R6;
+	ULONG R7;
+	ULONG R8;
+	ULONG R9;
+	ULONG R10;
+	ULONG R11;
+	ULONG R12;
+
+	ULONG Sp;
+	ULONG Lr;
+	ULONG Pc;
+	ULONG Psr;
+} CONTEXT;
+
+#else
+#error "undefined processor type"
+#endif
+typedef CONTEXT *PCONTEXT,*LPCONTEXT;
+typedef struct _EXCEPTION_RECORD {
+	DWORD ExceptionCode;
+	DWORD ExceptionFlags;
+	struct _EXCEPTION_RECORD *ExceptionRecord;
+	PVOID ExceptionAddress;
+	DWORD NumberParameters;
+	DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+} EXCEPTION_RECORD,*PEXCEPTION_RECORD;
+typedef struct _EXCEPTION_POINTERS {
+	PEXCEPTION_RECORD ExceptionRecord;
+	PCONTEXT ContextRecord;
+} EXCEPTION_POINTERS,*PEXCEPTION_POINTERS,*LPEXCEPTION_POINTERS;
+typedef union _LARGE_INTEGER {
+  struct {
+    DWORD LowPart;
+    LONG  HighPart;
+  } u;
+#if ! defined(NONAMELESSUNION) || defined(__cplusplus)
+  _ANONYMOUS_STRUCT struct {
+    DWORD LowPart;
+    LONG  HighPart;
+  };
+#endif /* NONAMELESSUNION */
+  LONGLONG QuadPart;
+} LARGE_INTEGER, *PLARGE_INTEGER;
+typedef union _ULARGE_INTEGER {
+  struct {
+    DWORD LowPart;
+    DWORD HighPart;
+  } u;
+#if ! defined(NONAMELESSUNION) || defined(__cplusplus)
+  _ANONYMOUS_STRUCT struct {
+    DWORD LowPart;
+    DWORD HighPart;
+  };
+#endif /* NONAMELESSUNION */
+  ULONGLONG QuadPart;
+} ULARGE_INTEGER, *PULARGE_INTEGER;
+typedef LARGE_INTEGER LUID,*PLUID;
+#pragma pack(push,4)
+typedef struct _LUID_AND_ATTRIBUTES {
+	LUID   Luid;
+	DWORD  Attributes;
+} LUID_AND_ATTRIBUTES;
+#pragma pack(pop)
+typedef LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY];
+typedef LUID_AND_ATTRIBUTES_ARRAY *PLUID_AND_ATTRIBUTES_ARRAY;
+typedef struct _PRIVILEGE_SET {
+	DWORD PrivilegeCount;
+	DWORD Control;
+	LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY];
+} PRIVILEGE_SET,*PPRIVILEGE_SET;
+typedef struct _SECURITY_ATTRIBUTES {
+	DWORD nLength;
+	LPVOID lpSecurityDescriptor;
+	BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES,*PSECURITY_ATTRIBUTES,*LPSECURITY_ATTRIBUTES;
+typedef enum _SECURITY_IMPERSONATION_LEVEL {
+	SecurityAnonymous,
+	SecurityIdentification,
+	SecurityImpersonation,
+	SecurityDelegation
+} SECURITY_IMPERSONATION_LEVEL;
+typedef BOOLEAN SECURITY_CONTEXT_TRACKING_MODE,*PSECURITY_CONTEXT_TRACKING_MODE;
+typedef struct _SECURITY_QUALITY_OF_SERVICE {
+	DWORD Length;
+	SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+	SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode;
+	BOOLEAN EffectiveOnly;
+} SECURITY_QUALITY_OF_SERVICE,*PSECURITY_QUALITY_OF_SERVICE;
+typedef PVOID PACCESS_TOKEN;
+typedef struct _SE_IMPERSONATION_STATE {
+	PACCESS_TOKEN Token;
+	BOOLEAN CopyOnOpen;
+	BOOLEAN EffectiveOnly;
+	SECURITY_IMPERSONATION_LEVEL Level;
+} SE_IMPERSONATION_STATE,*PSE_IMPERSONATION_STATE;
+typedef struct _SID_IDENTIFIER_AUTHORITY {
+	BYTE Value[6];
+} SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY,*LPSID_IDENTIFIER_AUTHORITY;
+typedef PVOID PSID;
+typedef struct _SID {
+   BYTE  Revision;
+   BYTE  SubAuthorityCount;
+   SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
+   DWORD SubAuthority[ANYSIZE_ARRAY];
+} SID, *PISID;
+typedef struct _SID_AND_ATTRIBUTES {
+	PSID Sid;
+	DWORD Attributes;
+} SID_AND_ATTRIBUTES;
+typedef SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES_ARRAY[ANYSIZE_ARRAY];
+typedef SID_AND_ATTRIBUTES_ARRAY *PSID_AND_ATTRIBUTES_ARRAY;
+typedef struct _TOKEN_SOURCE {
+	CHAR SourceName[TOKEN_SOURCE_LENGTH];
+	LUID SourceIdentifier;
+} TOKEN_SOURCE,*PTOKEN_SOURCE;
+typedef struct _TOKEN_CONTROL {
+	LUID TokenId;
+	LUID AuthenticationId;
+	LUID ModifiedId;
+	TOKEN_SOURCE TokenSource;
+} TOKEN_CONTROL,*PTOKEN_CONTROL;
+typedef struct _TOKEN_DEFAULT_DACL {
+	PACL DefaultDacl;
+} TOKEN_DEFAULT_DACL,*PTOKEN_DEFAULT_DACL;
+typedef struct _TOKEN_GROUPS {
+	DWORD GroupCount;
+	SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY];
+} TOKEN_GROUPS,*PTOKEN_GROUPS,*LPTOKEN_GROUPS;
+typedef struct _TOKEN_OWNER {
+	PSID Owner;
+} TOKEN_OWNER,*PTOKEN_OWNER;
+typedef struct _TOKEN_PRIMARY_GROUP {
+	PSID PrimaryGroup;
+} TOKEN_PRIMARY_GROUP,*PTOKEN_PRIMARY_GROUP;
+typedef struct _TOKEN_PRIVILEGES {
+	DWORD PrivilegeCount;
+	LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
+} TOKEN_PRIVILEGES,*PTOKEN_PRIVILEGES,*LPTOKEN_PRIVILEGES;
+typedef enum tagTOKEN_TYPE { TokenPrimary=1,TokenImpersonation }TOKEN_TYPE;
+typedef struct _TOKEN_STATISTICS {
+	LUID TokenId;
+	LUID AuthenticationId;
+	LARGE_INTEGER ExpirationTime;
+	TOKEN_TYPE TokenType;
+	SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+	DWORD DynamicCharged;
+	DWORD DynamicAvailable;
+	DWORD GroupCount;
+	DWORD PrivilegeCount;
+	LUID ModifiedId;
+} TOKEN_STATISTICS;
+typedef struct _TOKEN_USER {
+	SID_AND_ATTRIBUTES User;
+} TOKEN_USER, *PTOKEN_USER;
+typedef DWORD SECURITY_INFORMATION,*PSECURITY_INFORMATION;
+typedef WORD SECURITY_DESCRIPTOR_CONTROL,*PSECURITY_DESCRIPTOR_CONTROL;
+typedef struct _SECURITY_DESCRIPTOR {
+	BYTE Revision;
+	BYTE Sbz1;
+	SECURITY_DESCRIPTOR_CONTROL Control;
+	PSID Owner;
+	PSID Group;
+	PACL Sacl;
+	PACL Dacl;
+} SECURITY_DESCRIPTOR, *PSECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
+typedef enum _TOKEN_INFORMATION_CLASS {
+	TokenUser=1,TokenGroups,TokenPrivileges,TokenOwner,
+	TokenPrimaryGroup,TokenDefaultDacl,TokenSource,TokenType,
+	TokenImpersonationLevel,TokenStatistics,TokenRestrictedSids,
+	TokenSessionId
+} TOKEN_INFORMATION_CLASS;
+typedef enum _SID_NAME_USE {
+	SidTypeUser=1,SidTypeGroup,SidTypeDomain,SidTypeAlias,SidTypeWellKnownGroup,
+	SidTypeDeletedAccount,SidTypeInvalid,SidTypeUnknown
+} SID_NAME_USE,*PSID_NAME_USE;
+typedef struct _QUOTA_LIMITS {
+	SIZE_T PagedPoolLimit;
+	SIZE_T NonPagedPoolLimit;
+	SIZE_T MinimumWorkingSetSize;
+	SIZE_T MaximumWorkingSetSize;
+	SIZE_T PagefileLimit;
+	LARGE_INTEGER TimeLimit;
+} QUOTA_LIMITS,*PQUOTA_LIMITS;
+typedef struct _IO_COUNTERS {
+	ULONGLONG  ReadOperationCount;
+	ULONGLONG  WriteOperationCount;
+	ULONGLONG  OtherOperationCount;
+	ULONGLONG ReadTransferCount;
+	ULONGLONG WriteTransferCount;
+	ULONGLONG OtherTransferCount;
+} IO_COUNTERS, *PIO_COUNTERS;
+typedef struct _FILE_NOTIFY_INFORMATION {
+	DWORD NextEntryOffset;
+	DWORD Action;
+	DWORD FileNameLength;
+	WCHAR FileName[1];
+} FILE_NOTIFY_INFORMATION,*PFILE_NOTIFY_INFORMATION;
+typedef struct _TAPE_ERASE {
+	DWORD Type;
+	BOOLEAN Immediate;
+} TAPE_ERASE,*PTAPE_ERASE;
+typedef struct _TAPE_GET_DRIVE_PARAMETERS {
+	BOOLEAN ECC;
+	BOOLEAN Compression;
+	BOOLEAN DataPadding;
+	BOOLEAN ReportSetmarks;
+ 	DWORD DefaultBlockSize;
+ 	DWORD MaximumBlockSize;
+ 	DWORD MinimumBlockSize;
+ 	DWORD MaximumPartitionCount;
+ 	DWORD FeaturesLow;
+ 	DWORD FeaturesHigh;
+ 	DWORD EOTWarningZoneSize;
+} TAPE_GET_DRIVE_PARAMETERS,*PTAPE_GET_DRIVE_PARAMETERS;
+typedef struct _TAPE_GET_MEDIA_PARAMETERS {
+	LARGE_INTEGER Capacity;
+	LARGE_INTEGER Remaining;
+	DWORD BlockSize;
+	DWORD PartitionCount;
+	BOOLEAN WriteProtected;
+} TAPE_GET_MEDIA_PARAMETERS,*PTAPE_GET_MEDIA_PARAMETERS;
+typedef struct _TAPE_GET_POSITION {
+	ULONG Type;
+	ULONG Partition;
+	ULONG OffsetLow;
+	ULONG OffsetHigh;
+} TAPE_GET_POSITION,*PTAPE_GET_POSITION;
+typedef struct _TAPE_PREPARE {
+	DWORD Operation;
+	BOOLEAN Immediate;
+} TAPE_PREPARE,*PTAPE_PREPARE;
+typedef struct _TAPE_SET_DRIVE_PARAMETERS {
+	BOOLEAN ECC;
+	BOOLEAN Compression;
+	BOOLEAN DataPadding;
+	BOOLEAN ReportSetmarks;
+	ULONG EOTWarningZoneSize;
+} TAPE_SET_DRIVE_PARAMETERS,*PTAPE_SET_DRIVE_PARAMETERS;
+typedef struct _TAPE_SET_MEDIA_PARAMETERS {
+	ULONG BlockSize;
+} TAPE_SET_MEDIA_PARAMETERS,*PTAPE_SET_MEDIA_PARAMETERS;
+typedef struct _TAPE_SET_POSITION {
+	DWORD Method;
+	DWORD Partition;
+	LARGE_INTEGER Offset;
+	BOOLEAN Immediate;
+} TAPE_SET_POSITION,*PTAPE_SET_POSITION;
+typedef struct _TAPE_WRITE_MARKS {
+	DWORD Type;
+	DWORD Count;
+	BOOLEAN Immediate;
+} TAPE_WRITE_MARKS,*PTAPE_WRITE_MARKS;
+typedef struct _TAPE_CREATE_PARTITION {
+	DWORD Method;
+	DWORD Count;
+	DWORD Size;
+} TAPE_CREATE_PARTITION,*PTAPE_CREATE_PARTITION;
+typedef struct _MEMORY_BASIC_INFORMATION {
+	PVOID BaseAddress;
+	PVOID AllocationBase;
+	DWORD AllocationProtect;
+	DWORD RegionSize;
+	DWORD State;
+	DWORD Protect;
+	DWORD Type;
+} MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFORMATION;
+typedef struct _MESSAGE_RESOURCE_ENTRY {
+	WORD Length;
+	WORD Flags;
+	BYTE Text[1];
+} MESSAGE_RESOURCE_ENTRY,*PMESSAGE_RESOURCE_ENTRY;
+typedef struct _MESSAGE_RESOURCE_BLOCK {
+	DWORD LowId;
+	DWORD HighId;
+	DWORD OffsetToEntries;
+} MESSAGE_RESOURCE_BLOCK,*PMESSAGE_RESOURCE_BLOCK;
+typedef struct _MESSAGE_RESOURCE_DATA {
+	DWORD NumberOfBlocks;
+	MESSAGE_RESOURCE_BLOCK Blocks[1];
+} MESSAGE_RESOURCE_DATA,*PMESSAGE_RESOURCE_DATA;
+typedef struct _LIST_ENTRY {
+	struct _LIST_ENTRY *Flink;
+	struct _LIST_ENTRY *Blink;
+} LIST_ENTRY,*PLIST_ENTRY;
+typedef struct _RTL_CRITICAL_SECTION_DEBUG {
+	WORD Type;
+	WORD CreatorBackTraceIndex;
+	struct _RTL_CRITICAL_SECTION *CriticalSection;
+	LIST_ENTRY ProcessLocksList;
+	DWORD EntryCount;
+	DWORD ContentionCount;
+	DWORD Spare[2];
+} RTL_CRITICAL_SECTION_DEBUG,*PRTL_CRITICAL_SECTION_DEBUG;
+typedef struct _RTL_CRITICAL_SECTION {
+	PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
+	LONG LockCount;
+	LONG RecursionCount;
+	HANDLE OwningThread;
+	HANDLE LockSemaphore;
+	DWORD Reserved;
+} RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION;
+typedef struct _EVENTLOGRECORD {
+	DWORD Length;
+	DWORD Reserved;
+	DWORD RecordNumber;
+	DWORD TimeGenerated;
+	DWORD TimeWritten;
+	DWORD EventID;
+	WORD EventType;
+	WORD NumStrings;
+	WORD EventCategory;
+	WORD ReservedFlags;
+	DWORD ClosingRecordNumber;
+	DWORD StringOffset;
+	DWORD UserSidLength;
+	DWORD UserSidOffset;
+	DWORD DataLength;
+	DWORD DataOffset;
+} EVENTLOGRECORD,*PEVENTLOGRECORD;
+typedef struct _OSVERSIONINFOA {
+	DWORD dwOSVersionInfoSize;
+	DWORD dwMajorVersion;
+	DWORD dwMinorVersion;
+	DWORD dwBuildNumber;
+	DWORD dwPlatformId;
+	CHAR szCSDVersion[128];
+} OSVERSIONINFOA,*POSVERSIONINFOA,*LPOSVERSIONINFOA;
+typedef struct _OSVERSIONINFOW {
+	DWORD dwOSVersionInfoSize;
+	DWORD dwMajorVersion;
+	DWORD dwMinorVersion;
+	DWORD dwBuildNumber;
+	DWORD dwPlatformId;
+	WCHAR szCSDVersion[128];
+} OSVERSIONINFOW,*POSVERSIONINFOW,*LPOSVERSIONINFOW;
+typedef struct _OSVERSIONINFOEXA {
+	DWORD dwOSVersionInfoSize;
+	DWORD dwMajorVersion;
+	DWORD dwMinorVersion;
+	DWORD dwBuildNumber;
+	DWORD dwPlatformId;
+	CHAR szCSDVersion[128];
+	WORD wServicePackMajor;
+	WORD wServicePackMinor;
+	WORD wSuiteMask;
+	BYTE wProductType;
+	BYTE wReserved;
+} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;
+typedef struct _OSVERSIONINFOEXW {
+	DWORD dwOSVersionInfoSize;
+	DWORD dwMajorVersion;
+	DWORD dwMinorVersion;
+	DWORD dwBuildNumber;
+	DWORD dwPlatformId;
+	WCHAR szCSDVersion[128];
+	WORD wServicePackMajor;
+	WORD wServicePackMinor;
+	WORD wSuiteMask;
+	BYTE wProductType;
+	BYTE wReserved;
+} OSVERSIONINFOEXW, *POSVERSIONINFOEXW, *LPOSVERSIONINFOEXW;
+#pragma pack(push,2)
+typedef struct _IMAGE_VXD_HEADER {
+	WORD e32_magic;
+	BYTE e32_border;
+	BYTE e32_worder;
+	DWORD e32_level;
+	WORD e32_cpu;
+	WORD e32_os;
+	DWORD e32_ver;
+	DWORD e32_mflags;
+	DWORD e32_mpages;
+	DWORD e32_startobj;
+	DWORD e32_eip;
+	DWORD e32_stackobj;
+	DWORD e32_esp;
+	DWORD e32_pagesize;
+	DWORD e32_lastpagesize;
+	DWORD e32_fixupsize;
+	DWORD e32_fixupsum;
+	DWORD e32_ldrsize;
+	DWORD e32_ldrsum;
+	DWORD e32_objtab;
+	DWORD e32_objcnt;
+	DWORD e32_objmap;
+	DWORD e32_itermap;
+	DWORD e32_rsrctab;
+	DWORD e32_rsrccnt;
+	DWORD e32_restab;
+	DWORD e32_enttab;
+	DWORD e32_dirtab;
+	DWORD e32_dircnt;
+	DWORD e32_fpagetab;
+	DWORD e32_frectab;
+	DWORD e32_impmod;
+	DWORD e32_impmodcnt;
+	DWORD e32_impproc;
+	DWORD e32_pagesum;
+	DWORD e32_datapage;
+	DWORD e32_preload;
+	DWORD e32_nrestab;
+	DWORD e32_cbnrestab;
+	DWORD e32_nressum;
+	DWORD e32_autodata;
+	DWORD e32_debuginfo;
+	DWORD e32_debuglen;
+	DWORD e32_instpreload;
+	DWORD e32_instdemand;
+	DWORD e32_heapsize;
+	BYTE e32_res3[12];
+	DWORD e32_winresoff;
+	DWORD e32_winreslen;
+	WORD e32_devid;
+	WORD e32_ddkver;
+} IMAGE_VXD_HEADER,*PIMAGE_VXD_HEADER;
+#pragma pack(pop)
+#pragma pack(push,4)
+typedef struct _IMAGE_FILE_HEADER {
+	WORD Machine;
+	WORD NumberOfSections;
+	DWORD TimeDateStamp;
+	DWORD PointerToSymbolTable;
+	DWORD NumberOfSymbols;
+	WORD SizeOfOptionalHeader;
+	WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+typedef struct _IMAGE_DATA_DIRECTORY {
+	DWORD VirtualAddress;
+	DWORD Size;
+} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
+typedef struct _IMAGE_OPTIONAL_HEADER {
+	WORD Magic;
+	BYTE MajorLinkerVersion;
+	BYTE MinorLinkerVersion;
+	DWORD SizeOfCode;
+	DWORD SizeOfInitializedData;
+	DWORD SizeOfUninitializedData;
+	DWORD AddressOfEntryPoint;
+	DWORD BaseOfCode;
+	DWORD BaseOfData;
+	DWORD ImageBase;
+	DWORD SectionAlignment;
+	DWORD FileAlignment;
+	WORD MajorOperatingSystemVersion;
+	WORD MinorOperatingSystemVersion;
+	WORD MajorImageVersion;
+	WORD MinorImageVersion;
+	WORD MajorSubsystemVersion;
+	WORD MinorSubsystemVersion;
+	DWORD Reserved1;
+	DWORD SizeOfImage;
+	DWORD SizeOfHeaders;
+	DWORD CheckSum;
+	WORD Subsystem;
+	WORD DllCharacteristics;
+	DWORD SizeOfStackReserve;
+	DWORD SizeOfStackCommit;
+	DWORD SizeOfHeapReserve;
+	DWORD SizeOfHeapCommit;
+	DWORD LoaderFlags;
+	DWORD NumberOfRvaAndSizes;
+	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER,*PIMAGE_OPTIONAL_HEADER;
+typedef struct _IMAGE_ROM_OPTIONAL_HEADER {
+	WORD Magic;
+	BYTE MajorLinkerVersion;
+	BYTE MinorLinkerVersion;
+	DWORD SizeOfCode;
+	DWORD SizeOfInitializedData;
+	DWORD SizeOfUninitializedData;
+	DWORD AddressOfEntryPoint;
+	DWORD BaseOfCode;
+	DWORD BaseOfData;
+	DWORD BaseOfBss;
+	DWORD GprMask;
+	DWORD CprMask[4];
+	DWORD GpValue;
+} IMAGE_ROM_OPTIONAL_HEADER,*PIMAGE_ROM_OPTIONAL_HEADER;
+#pragma pack(pop)
+#pragma pack(push,2)
+typedef struct _IMAGE_DOS_HEADER {
+	WORD e_magic;
+	WORD e_cblp;
+	WORD e_cp;
+	WORD e_crlc;
+	WORD e_cparhdr;
+	WORD e_minalloc;
+	WORD e_maxalloc;
+	WORD e_ss;
+	WORD e_sp;
+	WORD e_csum;
+	WORD e_ip;
+	WORD e_cs;
+	WORD e_lfarlc;
+	WORD e_ovno;
+	WORD e_res[4];
+	WORD e_oemid;
+	WORD e_oeminfo;
+	WORD e_res2[10];
+	LONG e_lfanew;
+} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;
+typedef struct _IMAGE_OS2_HEADER {
+	WORD ne_magic;
+	CHAR ne_ver;
+	CHAR ne_rev;
+	WORD ne_enttab;
+	WORD ne_cbenttab;
+	LONG ne_crc;
+	WORD ne_flags;
+	WORD ne_autodata;
+	WORD ne_heap;
+	WORD ne_stack;
+	LONG ne_csip;
+	LONG ne_sssp;
+	WORD ne_cseg;
+	WORD ne_cmod;
+	WORD ne_cbnrestab;
+	WORD ne_segtab;
+	WORD ne_rsrctab;
+	WORD ne_restab;
+	WORD ne_modtab;
+	WORD ne_imptab;
+	LONG ne_nrestab;
+	WORD ne_cmovent;
+	WORD ne_align;
+	WORD ne_cres;
+	BYTE ne_exetyp;
+	BYTE ne_flagsothers;
+	WORD ne_pretthunks;
+	WORD ne_psegrefbytes;
+	WORD ne_swaparea;
+	WORD ne_expver;
+} IMAGE_OS2_HEADER,*PIMAGE_OS2_HEADER;
+#pragma pack(pop)
+#pragma pack(push,4)
+typedef struct _IMAGE_NT_HEADERS {
+	DWORD Signature;
+	IMAGE_FILE_HEADER FileHeader;
+	IMAGE_OPTIONAL_HEADER OptionalHeader;
+} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
+typedef struct _IMAGE_ROM_HEADERS {
+	IMAGE_FILE_HEADER FileHeader;
+	IMAGE_ROM_OPTIONAL_HEADER OptionalHeader;
+} IMAGE_ROM_HEADERS,*PIMAGE_ROM_HEADERS;
+typedef struct _IMAGE_SECTION_HEADER {
+	BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
+	union {
+		DWORD PhysicalAddress;
+		DWORD VirtualSize;
+	} Misc;
+	DWORD VirtualAddress;
+	DWORD SizeOfRawData;
+	DWORD PointerToRawData;
+	DWORD PointerToRelocations;
+	DWORD PointerToLinenumbers;
+	WORD NumberOfRelocations;
+	WORD NumberOfLinenumbers;
+	DWORD Characteristics;
+} IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;
+#pragma pack(pop)
+#pragma pack(push,2)
+typedef struct _IMAGE_SYMBOL {
+	union {
+		BYTE ShortName[8];
+		struct {
+			DWORD Short;
+			DWORD Long;
+		} Name;
+		PBYTE LongName[2];
+	} N;
+	DWORD Value;
+	SHORT SectionNumber;
+	WORD Type;
+	BYTE StorageClass;
+	BYTE NumberOfAuxSymbols;
+} IMAGE_SYMBOL,*PIMAGE_SYMBOL;
+typedef union _IMAGE_AUX_SYMBOL {
+	struct {
+		DWORD TagIndex;
+		union {
+			struct {
+				WORD Linenumber;
+				WORD Size;
+			} LnSz;
+			DWORD TotalSize;
+		} Misc;
+		union {
+			struct {
+				DWORD PointerToLinenumber;
+				DWORD PointerToNextFunction;
+			} Function;
+			struct {
+				WORD Dimension[4];
+			} Array;
+		} FcnAry;
+		WORD TvIndex;
+	} Sym;
+	struct {
+		BYTE Name[IMAGE_SIZEOF_SYMBOL];
+	} File;
+	struct {
+		DWORD Length;
+		WORD NumberOfRelocations;
+		WORD NumberOfLinenumbers;
+		DWORD CheckSum;
+		SHORT Number;
+		BYTE Selection;
+	} Section;
+} IMAGE_AUX_SYMBOL,*PIMAGE_AUX_SYMBOL;
+typedef struct _IMAGE_COFF_SYMBOLS_HEADER {
+	DWORD NumberOfSymbols;
+	DWORD LvaToFirstSymbol;
+	DWORD NumberOfLinenumbers;
+	DWORD LvaToFirstLinenumber;
+	DWORD RvaToFirstByteOfCode;
+	DWORD RvaToLastByteOfCode;
+	DWORD RvaToFirstByteOfData;
+	DWORD RvaToLastByteOfData;
+} IMAGE_COFF_SYMBOLS_HEADER,*PIMAGE_COFF_SYMBOLS_HEADER;
+typedef struct _IMAGE_RELOCATION {
+	_ANONYMOUS_UNION union {
+		DWORD VirtualAddress;
+		DWORD RelocCount;
+	} DUMMYUNIONNAME;
+	DWORD SymbolTableIndex;
+	WORD Type;
+} IMAGE_RELOCATION,*PIMAGE_RELOCATION;
+#pragma pack(pop)
+#pragma pack(push,4)
+typedef struct _IMAGE_BASE_RELOCATION {
+	DWORD VirtualAddress;
+	DWORD SizeOfBlock;
+} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION;
+#pragma pack(pop)
+#pragma pack(push,2)
+typedef struct _IMAGE_LINENUMBER {
+	union {
+		DWORD SymbolTableIndex;
+		DWORD VirtualAddress;
+	} Type;
+	WORD Linenumber;
+} IMAGE_LINENUMBER,*PIMAGE_LINENUMBER;
+#pragma pack(pop)
+#pragma pack(push,4)
+typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER {
+	BYTE Name[16];
+	BYTE Date[12];
+	BYTE UserID[6];
+	BYTE GroupID[6];
+	BYTE Mode[8];
+	BYTE Size[10];
+	BYTE EndHeader[2];
+} IMAGE_ARCHIVE_MEMBER_HEADER,*PIMAGE_ARCHIVE_MEMBER_HEADER;
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+	DWORD Characteristics;
+	DWORD TimeDateStamp;
+	WORD MajorVersion;
+	WORD MinorVersion;
+	DWORD Name;
+	DWORD Base;
+	DWORD NumberOfFunctions;
+	DWORD NumberOfNames;
+	PDWORD *AddressOfFunctions;
+	PDWORD *AddressOfNames;
+	PWORD *AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
+typedef struct _IMAGE_IMPORT_BY_NAME {
+	WORD Hint;
+	BYTE Name[1];
+} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
+typedef struct _IMAGE_THUNK_DATA {
+	union {
+		PBYTE ForwarderString;
+		PDWORD Function;
+		DWORD Ordinal;
+		PIMAGE_IMPORT_BY_NAME AddressOfData;
+	} u1;
+} IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;
+typedef struct _IMAGE_IMPORT_DESCRIPTOR {
+	_ANONYMOUS_UNION union {
+		DWORD Characteristics;
+		PIMAGE_THUNK_DATA OriginalFirstThunk;
+	} DUMMYUNIONNAME;
+	DWORD TimeDateStamp;
+	DWORD ForwarderChain;
+	DWORD Name;
+	PIMAGE_THUNK_DATA FirstThunk;
+} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
+typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
+	DWORD TimeDateStamp;
+	WORD OffsetModuleName;
+	WORD NumberOfModuleForwarderRefs;
+} IMAGE_BOUND_IMPORT_DESCRIPTOR,*PIMAGE_BOUND_IMPORT_DESCRIPTOR;
+typedef struct _IMAGE_BOUND_FORWARDER_REF {
+	DWORD TimeDateStamp;
+	WORD OffsetModuleName;
+	WORD Reserved;
+} IMAGE_BOUND_FORWARDER_REF,*PIMAGE_BOUND_FORWARDER_REF;
+typedef void(NTAPI *PIMAGE_TLS_CALLBACK)(PVOID,DWORD,PVOID);
+typedef struct _IMAGE_TLS_DIRECTORY {
+	DWORD StartAddressOfRawData;
+	DWORD EndAddressOfRawData;
+	PDWORD AddressOfIndex;
+	PIMAGE_TLS_CALLBACK *AddressOfCallBacks;
+	DWORD SizeOfZeroFill;
+	DWORD Characteristics;
+} IMAGE_TLS_DIRECTORY,*PIMAGE_TLS_DIRECTORY;
+typedef struct _IMAGE_RESOURCE_DIRECTORY {
+	DWORD Characteristics;
+	DWORD TimeDateStamp;
+	WORD MajorVersion;
+	WORD MinorVersion;
+	WORD NumberOfNamedEntries;
+	WORD NumberOfIdEntries;
+} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY;
+_ANONYMOUS_STRUCT typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
+	_ANONYMOUS_UNION union {
+		_ANONYMOUS_STRUCT struct {
+			DWORD NameOffset:31;
+			DWORD NameIsString:1;
+		}DUMMYSTRUCTNAME;
+		DWORD Name;
+		WORD Id;
+	} DUMMYUNIONNAME;
+	_ANONYMOUS_UNION union {
+		DWORD OffsetToData;
+		_ANONYMOUS_STRUCT struct {
+			DWORD OffsetToDirectory:31;
+			DWORD DataIsDirectory:1;
+		} DUMMYSTRUCTNAME2;
+	} DUMMYUNIONNAME2;
+} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY;
+typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING {
+	WORD Length;
+	CHAR NameString[1];
+} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING;
+typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
+	WORD Length;
+	WCHAR NameString[1];
+} IMAGE_RESOURCE_DIR_STRING_U,*PIMAGE_RESOURCE_DIR_STRING_U;
+typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
+	DWORD OffsetToData;
+	DWORD Size;
+	DWORD CodePage;
+	DWORD Reserved;
+} IMAGE_RESOURCE_DATA_ENTRY,*PIMAGE_RESOURCE_DATA_ENTRY;
+typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY {
+	DWORD Characteristics;
+	DWORD TimeDateStamp;
+	WORD MajorVersion;
+	WORD MinorVersion;
+	DWORD GlobalFlagsClear;
+	DWORD GlobalFlagsSet;
+	DWORD CriticalSectionDefaultTimeout;
+	DWORD DeCommitFreeBlockThreshold;
+	DWORD DeCommitTotalFreeThreshold;
+	PVOID LockPrefixTable;
+	DWORD MaximumAllocationSize;
+	DWORD VirtualMemoryThreshold;
+	DWORD ProcessHeapFlags;
+	DWORD Reserved[4];
+} IMAGE_LOAD_CONFIG_DIRECTORY,*PIMAGE_LOAD_CONFIG_DIRECTORY;
+typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
+	DWORD BeginAddress;
+	DWORD EndAddress;
+	PVOID ExceptionHandler;
+	PVOID HandlerData;
+	DWORD PrologEndAddress;
+} IMAGE_RUNTIME_FUNCTION_ENTRY,*PIMAGE_RUNTIME_FUNCTION_ENTRY;
+typedef struct _IMAGE_DEBUG_DIRECTORY {
+	DWORD Characteristics;
+	DWORD TimeDateStamp;
+	WORD MajorVersion;
+	WORD MinorVersion;
+	DWORD Type;
+	DWORD SizeOfData;
+	DWORD AddressOfRawData;
+	DWORD PointerToRawData;
+} IMAGE_DEBUG_DIRECTORY,*PIMAGE_DEBUG_DIRECTORY;
+typedef struct _FPO_DATA {
+	DWORD ulOffStart;
+	DWORD cbProcSize;
+	DWORD cdwLocals;
+	WORD cdwParams;
+	WORD cbProlog:8;
+	WORD cbRegs:3;
+	WORD fHasSEH:1;
+	WORD fUseBP:1;
+	WORD reserved:1;
+	WORD cbFrame:2;
+} FPO_DATA,*PFPO_DATA;
+typedef struct _IMAGE_DEBUG_MISC {
+	DWORD DataType;
+	DWORD Length;
+	BOOLEAN Unicode;
+	BYTE Reserved[3];
+	BYTE Data[1];
+} IMAGE_DEBUG_MISC,*PIMAGE_DEBUG_MISC;
+typedef struct _IMAGE_FUNCTION_ENTRY {
+	DWORD StartingAddress;
+	DWORD EndingAddress;
+	DWORD EndOfPrologue;
+} IMAGE_FUNCTION_ENTRY,*PIMAGE_FUNCTION_ENTRY;
+typedef struct _IMAGE_SEPARATE_DEBUG_HEADER {
+	WORD Signature;
+	WORD Flags;
+	WORD Machine;
+	WORD Characteristics;
+	DWORD TimeDateStamp;
+	DWORD CheckSum;
+	DWORD ImageBase;
+	DWORD SizeOfImage;
+	DWORD NumberOfSections;
+	DWORD ExportedNamesSize;
+	DWORD DebugDirectorySize;
+	DWORD Reserved[3];
+} IMAGE_SEPARATE_DEBUG_HEADER,*PIMAGE_SEPARATE_DEBUG_HEADER;
+#pragma pack(pop)
+typedef enum _CM_SERVICE_NODE_TYPE {
+	DriverType=SERVICE_KERNEL_DRIVER,
+	FileSystemType=SERVICE_FILE_SYSTEM_DRIVER,
+	Win32ServiceOwnProcess=SERVICE_WIN32_OWN_PROCESS,
+	Win32ServiceShareProcess=SERVICE_WIN32_SHARE_PROCESS,
+	AdapterType=SERVICE_ADAPTER,
+	RecognizerType=SERVICE_RECOGNIZER_DRIVER
+} SERVICE_NODE_TYPE;
+typedef enum _CM_SERVICE_LOAD_TYPE {
+	BootLoad=SERVICE_BOOT_START,
+	SystemLoad=SERVICE_SYSTEM_START,
+	AutoLoad=SERVICE_AUTO_START,
+	DemandLoad=SERVICE_DEMAND_START,
+	DisableLoad=SERVICE_DISABLED
+} SERVICE_LOAD_TYPE;
+typedef enum _CM_ERROR_CONTROL_TYPE {
+	IgnoreError=SERVICE_ERROR_IGNORE,
+	NormalError=SERVICE_ERROR_NORMAL,
+	SevereError=SERVICE_ERROR_SEVERE,
+	CriticalError=SERVICE_ERROR_CRITICAL
+} SERVICE_ERROR_TYPE;
+typedef struct _NT_TIB {
+	struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
+	PVOID StackBase;
+	PVOID StackLimit;
+	PVOID SubSystemTib;
+	_ANONYMOUS_UNION union {
+		PVOID FiberData;
+		DWORD Version;
+	} DUMMYUNIONNAME;
+	PVOID ArbitraryUserPointer;
+	struct _NT_TIB *Self;
+} NT_TIB,*PNT_TIB;
+typedef struct _REPARSE_DATA_BUFFER {
+	DWORD  ReparseTag;
+	WORD   ReparseDataLength;
+	WORD   Reserved;
+	_ANONYMOUS_UNION union {
+		struct {
+			WORD   SubstituteNameOffset;
+			WORD   SubstituteNameLength;
+			WORD   PrintNameOffset;
+			WORD   PrintNameLength;
+			WCHAR PathBuffer[1];
+		} SymbolicLinkReparseBuffer;
+		struct {
+			WORD   SubstituteNameOffset;
+			WORD   SubstituteNameLength;
+			WORD   PrintNameOffset;
+			WORD   PrintNameLength;
+			WCHAR PathBuffer[1];
+		} MountPointReparseBuffer;
+		struct {
+			BYTE   DataBuffer[1];
+		} GenericReparseBuffer;
+	} DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+typedef struct _REPARSE_GUID_DATA_BUFFER {
+	DWORD  ReparseTag;
+	WORD   ReparseDataLength;
+	WORD   Reserved;
+	GUID   ReparseGuid;
+	struct {
+		BYTE   DataBuffer[1];
+	} GenericReparseBuffer;
+} REPARSE_GUID_DATA_BUFFER, *PREPARSE_GUID_DATA_BUFFER;
+typedef struct _REPARSE_POINT_INFORMATION {
+	WORD   ReparseDataLength;
+	WORD   UnparsedNameLength;
+} REPARSE_POINT_INFORMATION, *PREPARSE_POINT_INFORMATION;
+
+#ifdef UNICODE
+typedef OSVERSIONINFOW OSVERSIONINFO,*POSVERSIONINFO,*LPOSVERSIONINFO;
+typedef OSVERSIONINFOEXW OSVERSIONINFOEX,*POSVERSIONINFOEX,*LPOSVERSIONINFOEX;
+#else
+typedef OSVERSIONINFOA OSVERSIONINFO,*POSVERSIONINFO,*LPOSVERSIONINFO;
+typedef OSVERSIONINFOEXA OSVERSIONINFOEX,*POSVERSIONINFOEX,*LPOSVERSIONINFOEX;
+#endif
+
+#if defined(__GNUC__)
+
+PVOID GetCurrentFiber(void);
+PVOID GetFiberData(void);
+
+PVOID GetCurrentFiber(void);
+extern __inline__ PVOID GetCurrentFiber(void)
+{
+    void* ret;
+    __asm__ volatile (
+	      "movl	%%fs:0x10,%0"
+	        : "=r" (ret) /* allow use of reg eax,ebx,ecx,edx,esi,edi */
+	        :
+		);
+    return ret;
+}
+
+PVOID GetFiberData(void);
+extern __inline__ PVOID GetFiberData(void)
+{
+    void* ret;
+    __asm__ volatile (
+	      "movl	%%fs:0x10,%0\n"
+	      "movl	(%0),%0"
+	       : "=r" (ret) /* allow use of reg eax,ebx,ecx,edx,esi,edi */
+	       :
+	      );
+    return ret;
+}
+
+#else
+
+extern PVOID GetCurrentFiber(void);
+#pragma aux GetCurrentFiber = \
+        "mov	eax, dword ptr fs:0x10" \
+        value [eax] \
+        modify [eax];
+
+extern PVOID GetFiberData(void);
+#pragma aux GetFiberData = \
+	"mov	eax, dword ptr fs:0x10" \
+	"mov	eax, [eax]" \
+        value [eax] \
+        modify [eax];
+        
+#endif /* __GNUC__ */
+
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/tinyc/win32/include/winapi/winreg.h b/tinyc/win32/include/winapi/winreg.h
new file mode 100644
index 000000000..21020b833
--- /dev/null
+++ b/tinyc/win32/include/winapi/winreg.h
@@ -0,0 +1,159 @@
+#ifndef _WINREG_H
+#define _WINREG_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define HKEY_CLASSES_ROOT	((HKEY)0x80000000)
+#define HKEY_CURRENT_USER	((HKEY)0x80000001)
+#define HKEY_LOCAL_MACHINE	((HKEY)0x80000002)
+#define HKEY_USERS	((HKEY)0x80000003)
+#define HKEY_PERFORMANCE_DATA	((HKEY)0x80000004)
+#define HKEY_CURRENT_CONFIG	((HKEY)0x80000005)
+#define HKEY_DYN_DATA	((HKEY)0x80000006)
+#define REG_OPTION_VOLATILE 1
+#define REG_OPTION_NON_VOLATILE 0
+#define REG_CREATED_NEW_KEY 1
+#define REG_OPENED_EXISTING_KEY 2
+#define REG_NONE 0
+#define REG_SZ 1
+#define REG_EXPAND_SZ 2
+#define REG_BINARY 3
+#define REG_DWORD 4
+#define REG_DWORD_BIG_ENDIAN 5
+#define REG_DWORD_LITTLE_ENDIAN 4
+#define REG_LINK 6
+#define REG_MULTI_SZ 7
+#define REG_RESOURCE_LIST 8
+#define REG_FULL_RESOURCE_DESCRIPTOR 9
+#define REG_RESOURCE_REQUIREMENTS_LIST 10
+#define REG_NOTIFY_CHANGE_NAME 1
+#define REG_NOTIFY_CHANGE_ATTRIBUTES 2
+#define REG_NOTIFY_CHANGE_LAST_SET 4
+#define REG_NOTIFY_CHANGE_SECURITY 8
+
+#ifndef RC_INVOKED
+typedef ACCESS_MASK REGSAM;
+typedef struct value_entA {
+	LPSTR ve_valuename;
+	DWORD ve_valuelen;
+	DWORD ve_valueptr;
+	DWORD ve_type;
+} VALENTA,*PVALENTA;
+typedef struct value_entW {
+	LPWSTR ve_valuename;
+	DWORD ve_valuelen;
+	DWORD ve_valueptr;
+	DWORD ve_type;
+} VALENTW,*PVALENTW;
+BOOL WINAPI AbortSystemShutdownA(LPCSTR);
+BOOL WINAPI AbortSystemShutdownW(LPCWSTR);
+BOOL WINAPI InitiateSystemShutdownA(LPSTR,LPSTR,DWORD,BOOL,BOOL);
+BOOL WINAPI InitiateSystemShutdownW(LPWSTR,LPWSTR,DWORD,BOOL,BOOL);
+LONG WINAPI RegCloseKey(HKEY);
+LONG WINAPI RegConnectRegistryA(LPSTR,HKEY,PHKEY);
+LONG WINAPI RegConnectRegistryW(LPWSTR,HKEY,PHKEY);
+LONG WINAPI RegCreateKeyA(HKEY,LPCSTR,PHKEY);
+LONG WINAPI RegCreateKeyExA(HKEY,LPCSTR,DWORD,LPSTR,DWORD,REGSAM,LPSECURITY_ATTRIBUTES,PHKEY,PDWORD);
+LONG WINAPI RegCreateKeyExW(HKEY,LPCWSTR,DWORD,LPWSTR,DWORD,REGSAM,LPSECURITY_ATTRIBUTES,PHKEY,PDWORD);
+LONG WINAPI RegCreateKeyW(HKEY,LPCWSTR,PHKEY);
+LONG WINAPI RegDeleteKeyA(HKEY,LPCSTR);
+LONG WINAPI RegDeleteKeyW(HKEY,LPCWSTR);
+LONG WINAPI RegDeleteValueA (HKEY,LPCSTR);
+LONG WINAPI RegDeleteValueW(HKEY,LPCWSTR);
+LONG WINAPI RegEnumKeyA (HKEY,DWORD,LPSTR,DWORD);
+LONG WINAPI RegEnumKeyW(HKEY,DWORD,LPWSTR,DWORD);
+LONG WINAPI RegEnumKeyExA(HKEY,DWORD,LPSTR,PDWORD,PDWORD,LPSTR,PDWORD,PFILETIME);
+LONG WINAPI RegEnumKeyExW(HKEY,DWORD,LPWSTR,PDWORD,PDWORD,LPWSTR,PDWORD,PFILETIME);
+LONG WINAPI RegEnumValueA(HKEY,DWORD,LPSTR,PDWORD,PDWORD,PDWORD,LPBYTE,PDWORD);
+LONG WINAPI RegEnumValueW(HKEY,DWORD,LPWSTR,PDWORD,PDWORD,PDWORD,LPBYTE,PDWORD);
+LONG WINAPI RegFlushKey(HKEY);
+LONG WINAPI RegGetKeySecurity(HKEY,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,PDWORD);
+LONG WINAPI RegLoadKeyA(HKEY,LPCSTR,LPCSTR);
+LONG WINAPI RegLoadKeyW(HKEY,LPCWSTR,LPCWSTR);
+LONG WINAPI RegNotifyChangeKeyValue(HKEY,BOOL,DWORD,HANDLE,BOOL);
+LONG WINAPI RegOpenKeyA(HKEY,LPCSTR,PHKEY);
+LONG WINAPI RegOpenKeyExA(HKEY,LPCSTR,DWORD,REGSAM,PHKEY);
+LONG WINAPI RegOpenKeyExW(HKEY,LPCWSTR,DWORD,REGSAM,PHKEY);
+LONG WINAPI RegOpenKeyW(HKEY,LPCWSTR,PHKEY);
+LONG WINAPI RegQueryInfoKeyA(HKEY,LPSTR,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PFILETIME);
+LONG WINAPI RegQueryInfoKeyW(HKEY,LPWSTR,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PDWORD,PFILETIME);
+LONG WINAPI RegQueryMultipleValuesA(HKEY,PVALENTA,DWORD,LPSTR,PDWORD);
+LONG WINAPI RegQueryMultipleValuesW(HKEY,PVALENTW,DWORD,LPWSTR,PDWORD);
+LONG WINAPI RegQueryValueA(HKEY,LPCSTR,LPSTR,PLONG);
+LONG WINAPI RegQueryValueExA (HKEY,LPCSTR,PDWORD,PDWORD,LPBYTE,PDWORD);
+LONG WINAPI RegQueryValueExW(HKEY,LPCWSTR,PDWORD,PDWORD,LPBYTE,PDWORD);
+LONG WINAPI RegQueryValueW(HKEY,LPCWSTR,LPWSTR,PLONG);
+LONG WINAPI RegReplaceKeyA(HKEY,LPCSTR,LPCSTR,LPCSTR);
+LONG WINAPI RegReplaceKeyW(HKEY,LPCWSTR,LPCWSTR,LPCWSTR);
+LONG WINAPI RegRestoreKeyA (HKEY,LPCSTR,DWORD);
+LONG WINAPI RegRestoreKeyW(HKEY,LPCWSTR,DWORD);
+LONG WINAPI RegSaveKeyA(HKEY,LPCSTR,LPSECURITY_ATTRIBUTES);
+LONG WINAPI RegSaveKeyW(HKEY,LPCWSTR,LPSECURITY_ATTRIBUTES);
+LONG WINAPI RegSetKeySecurity(HKEY,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
+LONG WINAPI RegSetValueA(HKEY,LPCSTR,DWORD,LPCSTR,DWORD);
+LONG WINAPI RegSetValueExA(HKEY,LPCSTR,DWORD,DWORD,const BYTE*,DWORD);
+LONG WINAPI RegSetValueExW(HKEY,LPCWSTR,DWORD,DWORD,const BYTE*,DWORD);
+LONG WINAPI RegSetValueW(HKEY,LPCWSTR,DWORD,LPCWSTR,DWORD);
+LONG WINAPI RegUnLoadKeyA(HKEY,LPCSTR);
+LONG WINAPI RegUnLoadKeyW(HKEY,LPCWSTR);
+
+#ifdef UNICODE
+typedef VALENTW VALENT,*PVALENT;
+#define AbortSystemShutdown AbortSystemShutdownW
+#define InitiateSystemShutdown InitiateSystemShutdownW
+#define RegConnectRegistry RegConnectRegistryW
+#define RegCreateKey RegCreateKeyW
+#define RegCreateKeyEx RegCreateKeyExW
+#define RegDeleteKey RegDeleteKeyW
+#define RegDeleteValue RegDeleteValueW
+#define RegEnumKey RegEnumKeyW
+#define RegEnumKeyEx RegEnumKeyExW
+#define RegEnumValue RegEnumValueW
+#define RegLoadKey RegLoadKeyW
+#define RegOpenKey RegOpenKeyW
+#define RegOpenKeyEx RegOpenKeyExW
+#define RegQueryInfoKey RegQueryInfoKeyW
+#define RegQueryMultipleValues RegQueryMultipleValuesW
+#define RegQueryValue RegQueryValueW
+#define RegQueryValueEx RegQueryValueExW
+#define RegReplaceKey RegReplaceKeyW
+#define RegRestoreKey RegRestoreKeyW
+#define RegSaveKey RegSaveKeyW
+#define RegSetValue RegSetValueW
+#define RegSetValueEx RegSetValueExW
+#define RegUnLoadKey RegUnLoadKeyW
+#else
+typedef VALENTA VALENT,*PVALENT;
+#define AbortSystemShutdown AbortSystemShutdownA
+#define InitiateSystemShutdown InitiateSystemShutdownA
+#define RegConnectRegistry RegConnectRegistryA
+#define RegCreateKey RegCreateKeyA
+#define RegCreateKeyEx RegCreateKeyExA
+#define RegDeleteKey RegDeleteKeyA
+#define RegDeleteValue RegDeleteValueA
+#define RegEnumKey RegEnumKeyA
+#define RegEnumKeyEx RegEnumKeyExA
+#define RegEnumValue RegEnumValueA
+#define RegLoadKey RegLoadKeyA
+#define RegOpenKey RegOpenKeyA
+#define RegOpenKeyEx RegOpenKeyExA
+#define RegQueryInfoKey RegQueryInfoKeyA
+#define RegQueryMultipleValues RegQueryMultipleValuesA
+#define RegQueryValue RegQueryValueA
+#define RegQueryValueEx RegQueryValueExA
+#define RegReplaceKey RegReplaceKeyA
+#define RegRestoreKey RegRestoreKeyA
+#define RegSaveKey RegSaveKeyA
+#define RegSetValue RegSetValueA
+#define RegSetValueEx RegSetValueExA
+#define RegUnLoadKey RegUnLoadKeyA
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/include/winapi/winsvc.h b/tinyc/win32/include/winapi/winsvc.h
new file mode 100644
index 000000000..ae60d46a2
--- /dev/null
+++ b/tinyc/win32/include/winapi/winsvc.h
@@ -0,0 +1,309 @@
+#ifndef _WINSVC_H
+#define _WINSVC_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define SERVICES_ACTIVE_DATABASEA "ServicesActive"
+#define SERVICES_ACTIVE_DATABASEW L"ServicesActive"
+#define SERVICES_FAILED_DATABASEA "ServicesFailed"
+#define SERVICES_FAILED_DATABASEW L"ServicesFailed"
+#define SC_GROUP_IDENTIFIERA '+'
+#define SC_GROUP_IDENTIFIERW L'+'
+#define SC_MANAGER_ALL_ACCESS	0xf003f
+#define SC_MANAGER_CONNECT	1
+#define SC_MANAGER_CREATE_SERVICE	2
+#define SC_MANAGER_ENUMERATE_SERVICE	4
+#define SC_MANAGER_LOCK	8
+#define SC_MANAGER_QUERY_LOCK_STATUS	16
+#define SC_MANAGER_MODIFY_BOOT_CONFIG	32
+#define SERVICE_NO_CHANGE	(-1)
+#define SERVICE_STOPPED	1
+#define SERVICE_START_PENDING	2
+#define SERVICE_STOP_PENDING	3
+#define SERVICE_RUNNING	4
+#define SERVICE_CONTINUE_PENDING	5
+#define SERVICE_PAUSE_PENDING	6
+#define SERVICE_PAUSED	7
+#define SERVICE_ACCEPT_STOP	1
+#define SERVICE_ACCEPT_PAUSE_CONTINUE	2
+#define SERVICE_ACCEPT_SHUTDOWN 4
+#define SERVICE_ACCEPT_PARAMCHANGE    8
+#define SERVICE_ACCEPT_NETBINDCHANGE  16
+#define SERVICE_ACCEPT_HARDWAREPROFILECHANGE   32
+#define SERVICE_ACCEPT_POWEREVENT              64
+#define SERVICE_ACCEPT_SESSIONCHANGE           128
+#define SERVICE_CONTROL_STOP	1
+#define SERVICE_CONTROL_PAUSE	2
+#define SERVICE_CONTROL_CONTINUE	3
+#define SERVICE_CONTROL_INTERROGATE	4
+#define SERVICE_CONTROL_SHUTDOWN	5
+#define SERVICE_CONTROL_PARAMCHANGE     6
+#define SERVICE_CONTROL_NETBINDADD      7
+#define SERVICE_CONTROL_NETBINDREMOVE   8
+#define SERVICE_CONTROL_NETBINDENABLE   9
+#define SERVICE_CONTROL_NETBINDDISABLE  10
+#define SERVICE_CONTROL_DEVICEEVENT     11
+#define SERVICE_CONTROL_HARDWAREPROFILECHANGE 12
+#define SERVICE_CONTROL_POWEREVENT            13
+#define SERVICE_CONTROL_SESSIONCHANGE         14
+#define SERVICE_ACTIVE 1
+#define SERVICE_INACTIVE 2
+#define SERVICE_STATE_ALL 3
+#define SERVICE_QUERY_CONFIG 1
+#define SERVICE_CHANGE_CONFIG 2
+#define SERVICE_QUERY_STATUS 4
+#define SERVICE_ENUMERATE_DEPENDENTS 8
+#define SERVICE_START 16
+#define SERVICE_STOP 32
+#define SERVICE_PAUSE_CONTINUE 64
+#define SERVICE_INTERROGATE 128
+#define SERVICE_USER_DEFINED_CONTROL 256
+#define SERVICE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SERVICE_QUERY_CONFIG|SERVICE_CHANGE_CONFIG|SERVICE_QUERY_STATUS|SERVICE_ENUMERATE_DEPENDENTS|SERVICE_START|SERVICE_STOP|SERVICE_PAUSE_CONTINUE|SERVICE_INTERROGATE|SERVICE_USER_DEFINED_CONTROL)
+#define SERVICE_RUNS_IN_SYSTEM_PROCESS 1
+#define SERVICE_CONFIG_DESCRIPTION     1
+#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+
+typedef struct _SERVICE_STATUS {
+	DWORD dwServiceType;
+	DWORD dwCurrentState;
+	DWORD dwControlsAccepted;
+	DWORD dwWin32ExitCode;
+	DWORD dwServiceSpecificExitCode;
+	DWORD dwCheckPoint;
+	DWORD dwWaitHint;
+} SERVICE_STATUS,*LPSERVICE_STATUS;
+typedef struct _SERVICE_STATUS_PROCESS {
+	DWORD dwServiceType;
+	DWORD dwCurrentState;
+	DWORD dwControlsAccepted;
+	DWORD dwWin32ExitCode;
+	DWORD dwServiceSpecificExitCode;
+	DWORD dwCheckPoint;
+	DWORD dwWaitHint;
+	DWORD dwProcessId;
+	DWORD dwServiceFlags;
+} SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;
+typedef enum _SC_STATUS_TYPE {
+	SC_STATUS_PROCESS_INFO = 0
+} SC_STATUS_TYPE;
+typedef enum _SC_ENUM_TYPE {
+        SC_ENUM_PROCESS_INFO = 0
+} SC_ENUM_TYPE;
+typedef struct _ENUM_SERVICE_STATUSA {
+	LPSTR lpServiceName;
+	LPSTR lpDisplayName;
+	SERVICE_STATUS ServiceStatus;
+} ENUM_SERVICE_STATUSA,*LPENUM_SERVICE_STATUSA;
+typedef struct _ENUM_SERVICE_STATUSW {
+	LPWSTR lpServiceName;
+	LPWSTR lpDisplayName;
+	SERVICE_STATUS ServiceStatus;
+} ENUM_SERVICE_STATUSW,*LPENUM_SERVICE_STATUSW;
+typedef struct _ENUM_SERVICE_STATUS_PROCESSA {
+	LPSTR lpServiceName;
+	LPSTR lpDisplayName;
+	SERVICE_STATUS_PROCESS ServiceStatusProcess;
+} ENUM_SERVICE_STATUS_PROCESSA,*LPENUM_SERVICE_STATUS_PROCESSA;
+typedef struct _ENUM_SERVICE_STATUS_PROCESSW {
+	LPWSTR lpServiceName;
+	LPWSTR lpDisplayName;
+	SERVICE_STATUS_PROCESS ServiceStatusProcess;
+} ENUM_SERVICE_STATUS_PROCESSW,*LPENUM_SERVICE_STATUS_PROCESSW;
+typedef struct _QUERY_SERVICE_CONFIGA {
+	DWORD dwServiceType;
+	DWORD dwStartType;
+	DWORD dwErrorControl;
+	LPSTR lpBinaryPathName;
+	LPSTR lpLoadOrderGroup;
+	DWORD dwTagId;
+	LPSTR lpDependencies;
+	LPSTR lpServiceStartName;
+	LPSTR lpDisplayName;
+} QUERY_SERVICE_CONFIGA,*LPQUERY_SERVICE_CONFIGA;
+typedef struct _QUERY_SERVICE_CONFIGW {
+	DWORD dwServiceType;
+	DWORD dwStartType;
+	DWORD dwErrorControl;
+	LPWSTR lpBinaryPathName;
+	LPWSTR lpLoadOrderGroup;
+	DWORD dwTagId;
+	LPWSTR lpDependencies;
+	LPWSTR lpServiceStartName;
+	LPWSTR lpDisplayName;
+} QUERY_SERVICE_CONFIGW,*LPQUERY_SERVICE_CONFIGW;
+typedef struct _QUERY_SERVICE_LOCK_STATUSA {
+	DWORD fIsLocked;
+	LPSTR lpLockOwner;
+	DWORD dwLockDuration;
+} QUERY_SERVICE_LOCK_STATUSA,*LPQUERY_SERVICE_LOCK_STATUSA;
+typedef struct _QUERY_SERVICE_LOCK_STATUSW {
+	DWORD fIsLocked;
+	LPWSTR lpLockOwner;
+	DWORD dwLockDuration;
+} QUERY_SERVICE_LOCK_STATUSW,*LPQUERY_SERVICE_LOCK_STATUSW;
+typedef void (WINAPI *LPSERVICE_MAIN_FUNCTIONA)(DWORD,LPSTR*);
+typedef void (WINAPI *LPSERVICE_MAIN_FUNCTIONW)(DWORD,LPWSTR*);
+typedef struct _SERVICE_TABLE_ENTRYA {
+	LPSTR lpServiceName;
+	LPSERVICE_MAIN_FUNCTIONA lpServiceProc;
+} SERVICE_TABLE_ENTRYA,*LPSERVICE_TABLE_ENTRYA;
+typedef struct _SERVICE_TABLE_ENTRYW {
+	LPWSTR lpServiceName;
+	LPSERVICE_MAIN_FUNCTIONW lpServiceProc;
+} SERVICE_TABLE_ENTRYW,*LPSERVICE_TABLE_ENTRYW;
+DECLARE_HANDLE(SC_HANDLE);
+typedef SC_HANDLE *LPSC_HANDLE;
+typedef PVOID SC_LOCK;
+typedef DWORD SERVICE_STATUS_HANDLE;
+typedef VOID(WINAPI *LPHANDLER_FUNCTION)(DWORD);
+typedef DWORD (WINAPI *LPHANDLER_FUNCTION_EX)(DWORD,DWORD,LPVOID,LPVOID);
+typedef struct _SERVICE_DESCRIPTIONA {
+	LPSTR lpDescription;
+} SERVICE_DESCRIPTIONA,*LPSERVICE_DESCRIPTIONA;
+typedef struct _SERVICE_DESCRIPTIONW {
+	LPWSTR lpDescription;
+} SERVICE_DESCRIPTIONW,*LPSERVICE_DESCRIPTIONW;
+typedef enum _SC_ACTION_TYPE {
+        SC_ACTION_NONE          = 0,
+        SC_ACTION_RESTART       = 1,
+        SC_ACTION_REBOOT        = 2,
+        SC_ACTION_RUN_COMMAND   = 3
+} SC_ACTION_TYPE;
+typedef struct _SC_ACTION {
+	SC_ACTION_TYPE	Type;
+	DWORD		Delay;
+} SC_ACTION,*LPSC_ACTION;
+typedef struct _SERVICE_FAILURE_ACTIONSA {
+	DWORD	dwResetPeriod;
+	LPSTR	lpRebootMsg;
+	LPSTR	lpCommand;
+	DWORD	cActions;
+	SC_ACTION * lpsaActions;
+} SERVICE_FAILURE_ACTIONSA,*LPSERVICE_FAILURE_ACTIONSA;
+typedef struct _SERVICE_FAILURE_ACTIONSW {
+	DWORD	dwResetPeriod;
+	LPWSTR	lpRebootMsg;
+	LPWSTR	lpCommand;
+	DWORD	cActions;
+	SC_ACTION * lpsaActions;
+} SERVICE_FAILURE_ACTIONSW,*LPSERVICE_FAILURE_ACTIONSW;
+
+BOOL WINAPI ChangeServiceConfigA(SC_HANDLE,DWORD,DWORD,DWORD,LPCSTR,LPCSTR,LPDWORD,LPCSTR,LPCSTR,LPCSTR,LPCSTR);
+BOOL WINAPI ChangeServiceConfigW(SC_HANDLE,DWORD,DWORD,DWORD,LPCWSTR,LPCWSTR,LPDWORD,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR);
+BOOL WINAPI ChangeServiceConfig2A(SC_HANDLE,DWORD,LPVOID);
+BOOL WINAPI ChangeServiceConfig2W(SC_HANDLE,DWORD,LPVOID);
+BOOL WINAPI CloseServiceHandle(SC_HANDLE);
+BOOL WINAPI ControlService(SC_HANDLE,DWORD,LPSERVICE_STATUS);
+SC_HANDLE WINAPI CreateServiceA(SC_HANDLE,LPCSTR,LPCSTR,DWORD,DWORD,DWORD,DWORD,LPCSTR,LPCSTR,PDWORD,LPCSTR,LPCSTR,LPCSTR);
+SC_HANDLE WINAPI CreateServiceW(SC_HANDLE,LPCWSTR,LPCWSTR,DWORD,DWORD,DWORD,DWORD,LPCWSTR,LPCWSTR,PDWORD,LPCWSTR,LPCWSTR,LPCWSTR);
+BOOL WINAPI DeleteService(SC_HANDLE);
+BOOL WINAPI EnumDependentServicesA(SC_HANDLE,DWORD,LPENUM_SERVICE_STATUSA,DWORD,PDWORD,PDWORD);
+BOOL WINAPI EnumDependentServicesW(SC_HANDLE,DWORD,LPENUM_SERVICE_STATUSW,DWORD,PDWORD,PDWORD);
+BOOL WINAPI EnumServicesStatusA(SC_HANDLE,DWORD,DWORD,LPENUM_SERVICE_STATUSA,DWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI EnumServicesStatusW(SC_HANDLE,DWORD,DWORD,LPENUM_SERVICE_STATUSW,DWORD,PDWORD,PDWORD,PDWORD);
+BOOL WINAPI EnumServicesStatusExA(SC_HANDLE,SC_ENUM_TYPE,DWORD,DWORD,LPBYTE,DWORD,LPDWORD,LPDWORD,LPDWORD,LPCSTR);
+BOOL WINAPI EnumServicesStatusExW(SC_HANDLE,SC_ENUM_TYPE,DWORD,DWORD,LPBYTE,DWORD,LPDWORD,LPDWORD,LPDWORD,LPCWSTR);
+BOOL WINAPI GetServiceDisplayNameA(SC_HANDLE,LPCSTR,LPSTR,PDWORD);
+BOOL WINAPI GetServiceDisplayNameW(SC_HANDLE,LPCWSTR,LPWSTR,PDWORD);
+BOOL WINAPI GetServiceKeyNameA(SC_HANDLE,LPCSTR,LPSTR,PDWORD);
+BOOL WINAPI GetServiceKeyNameW(SC_HANDLE,LPCWSTR,LPWSTR,PDWORD);
+SC_LOCK WINAPI LockServiceDatabase(SC_HANDLE);
+BOOL WINAPI NotifyBootConfigStatus(BOOL);
+SC_HANDLE WINAPI OpenSCManagerA(LPCSTR,LPCSTR,DWORD);
+SC_HANDLE WINAPI OpenSCManagerW(LPCWSTR,LPCWSTR,DWORD);
+SC_HANDLE WINAPI OpenServiceA(SC_HANDLE,LPCSTR,DWORD);
+SC_HANDLE WINAPI OpenServiceW(SC_HANDLE,LPCWSTR,DWORD);
+BOOL WINAPI QueryServiceConfigA(SC_HANDLE,LPQUERY_SERVICE_CONFIGA,DWORD,PDWORD);
+BOOL WINAPI QueryServiceConfigW(SC_HANDLE,LPQUERY_SERVICE_CONFIGW,DWORD,PDWORD);
+BOOL WINAPI QueryServiceConfig2A(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
+BOOL WINAPI QueryServiceConfig2W(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
+BOOL WINAPI QueryServiceLockStatusA(SC_HANDLE,LPQUERY_SERVICE_LOCK_STATUSA,DWORD,PDWORD);
+BOOL WINAPI QueryServiceLockStatusW(SC_HANDLE,LPQUERY_SERVICE_LOCK_STATUSW,DWORD,PDWORD);
+BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,LPDWORD);
+BOOL WINAPI QueryServiceStatus(SC_HANDLE,LPSERVICE_STATUS);
+BOOL WINAPI QueryServiceStatusEx(SC_HANDLE,SC_STATUS_TYPE,LPBYTE,DWORD,LPDWORD);
+SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA(LPCSTR,LPHANDLER_FUNCTION);
+SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW(LPCWSTR,LPHANDLER_FUNCTION);
+SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
+SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW(LPCWSTR,LPHANDLER_FUNCTION_EX,LPVOID);
+BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
+BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE,LPSERVICE_STATUS);
+BOOL WINAPI StartServiceA(SC_HANDLE,DWORD,LPCSTR*);
+BOOL WINAPI StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA);
+BOOL WINAPI StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW);
+BOOL WINAPI StartServiceW(SC_HANDLE,DWORD,LPCWSTR);
+BOOL WINAPI UnlockServiceDatabase(SC_LOCK);
+
+#ifdef UNICODE
+typedef ENUM_SERVICE_STATUSW ENUM_SERVICE_STATUS,*LPENUM_SERVICE_STATUS;
+typedef ENUM_SERVICE_STATUS_PROCESSW ENUM_SERVICE_STATUS_PROCESS;
+typedef LPENUM_SERVICE_STATUS_PROCESSW LPENUM_SERVICE_STATUS_PROCESS;
+typedef QUERY_SERVICE_CONFIGW QUERY_SERVICE_CONFIG,*LPQUERY_SERVICE_CONFIG;
+typedef QUERY_SERVICE_LOCK_STATUSW QUERY_SERVICE_LOCK_STATUS,*LPQUERY_SERVICE_LOCK_STATUS;
+typedef SERVICE_TABLE_ENTRYW SERVICE_TABLE_ENTRY,*LPSERVICE_TABLE_ENTRY;
+typedef LPSERVICE_MAIN_FUNCTIONW LPSERVICE_MAIN_FUNCTION;
+typedef SERVICE_DESCRIPTIONW SERVICE_DESCRIPTION;
+typedef LPSERVICE_DESCRIPTIONW LPSERVICE_DESCRIPTION;
+typedef SERVICE_FAILURE_ACTIONSW SERVICE_FAILURE_ACTIONS;
+typedef LPSERVICE_FAILURE_ACTIONSW LPSERVICE_FAILURE_ACTIONS;
+#define SERVICES_ACTIVE_DATABASE SERVICES_ACTIVE_DATABASEW
+#define SERVICES_FAILED_DATABASE SERVICES_FAILED_DATABASEW
+#define SC_GROUP_IDENTIFIER SC_GROUP_IDENTIFIERW
+#define ChangeServiceConfig ChangeServiceConfigW
+#define ChangeServiceConfig2 ChangeServiceConfig2W
+#define CreateService CreateServiceW
+#define EnumDependentServices EnumDependentServicesW
+#define EnumServicesStatus EnumServicesStatusW
+#define EnumServicesStatusEx  EnumServicesStatusExW
+#define GetServiceDisplayName GetServiceDisplayNameW
+#define GetServiceKeyName GetServiceKeyNameW
+#define OpenSCManager OpenSCManagerW
+#define OpenService OpenServiceW
+#define QueryServiceConfig QueryServiceConfigW
+#define QueryServiceConfig2 QueryServiceConfig2W
+#define QueryServiceLockStatus QueryServiceLockStatusW
+#define RegisterServiceCtrlHandler RegisterServiceCtrlHandlerW
+#define RegisterServiceCtrlHandlerEx RegisterServiceCtrlHandlerExW
+#define StartService StartServiceW
+#define StartServiceCtrlDispatcher StartServiceCtrlDispatcherW
+#else
+typedef ENUM_SERVICE_STATUSA ENUM_SERVICE_STATUS,*LPENUM_SERVICE_STATUS;
+typedef ENUM_SERVICE_STATUS_PROCESSA ENUM_SERVICE_STATUS_PROCESS;
+typedef LPENUM_SERVICE_STATUS_PROCESSA LPENUM_SERVICE_STATUS_PROCESS;
+typedef QUERY_SERVICE_CONFIGA QUERY_SERVICE_CONFIG,*LPQUERY_SERVICE_CONFIG;
+typedef QUERY_SERVICE_LOCK_STATUSA QUERY_SERVICE_LOCK_STATUS,*LPQUERY_SERVICE_LOCK_STATUS;
+typedef SERVICE_TABLE_ENTRYA SERVICE_TABLE_ENTRY,*LPSERVICE_TABLE_ENTRY;
+typedef LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION;
+typedef SERVICE_DESCRIPTIONA SERVICE_DESCRIPTION;
+typedef LPSERVICE_DESCRIPTIONA LPSERVICE_DESCRIPTION;
+typedef SERVICE_FAILURE_ACTIONSA SERVICE_FAILURE_ACTIONS;
+typedef LPSERVICE_FAILURE_ACTIONSA LPSERVICE_FAILURE_ACTIONS;
+#define SERVICES_ACTIVE_DATABASE SERVICES_ACTIVE_DATABASEA
+#define SERVICES_FAILED_DATABASE SERVICES_FAILED_DATABASEA
+#define SC_GROUP_IDENTIFIER SC_GROUP_IDENTIFIERA
+#define ChangeServiceConfig ChangeServiceConfigA
+#define ChangeServiceConfig2 ChangeServiceConfig2A
+#define CreateService CreateServiceA
+#define EnumDependentServices EnumDependentServicesA
+#define EnumServicesStatus EnumServicesStatusA
+#define EnumServicesStatusEx  EnumServicesStatusExA
+#define GetServiceDisplayName GetServiceDisplayNameA
+#define GetServiceKeyName GetServiceKeyNameA
+#define OpenSCManager OpenSCManagerA
+#define OpenService OpenServiceA
+#define QueryServiceConfig QueryServiceConfigA
+#define QueryServiceConfig2 QueryServiceConfig2A
+#define QueryServiceLockStatus QueryServiceLockStatusA
+#define RegisterServiceCtrlHandler RegisterServiceCtrlHandlerA
+#define RegisterServiceCtrlHandlerEx RegisterServiceCtrlHandlerExA
+#define StartService StartServiceA
+#define StartServiceCtrlDispatcher StartServiceCtrlDispatcherA
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* _WINSVC_H */
diff --git a/tinyc/win32/include/winapi/winuser.h b/tinyc/win32/include/winapi/winuser.h
new file mode 100644
index 000000000..8929c6be6
--- /dev/null
+++ b/tinyc/win32/include/winapi/winuser.h
@@ -0,0 +1,3472 @@
+#ifndef _WINUSER_H
+#define _WINUSER_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define WC_DIALOG MAKEINTATOM(0x8002)
+#define FALT	16
+#define FCONTROL	8
+#define FNOINVERT	2
+#define FSHIFT	4
+#define FVIRTKEY	1
+#define ATF_TIMEOUTON	1
+#define ATF_ONOFFFEEDBACK	2
+#define ATF_AVAILABLE	4 /* May be obsolete. Not in recent MS docs. */
+#define WH_MIN	(-1)
+#define WH_MSGFILTER	(-1)
+#define WH_JOURNALRECORD	0
+#define WH_JOURNALPLAYBACK	1
+#define WH_KEYBOARD	2
+#define WH_GETMESSAGE	3
+#define WH_CALLWNDPROC	4
+#define WH_CBT	5
+#define WH_SYSMSGFILTER	6
+#define WH_MOUSE	7
+#define WH_HARDWARE	8
+#define WH_DEBUG	9
+#define WH_SHELL	10
+#define WH_FOREGROUNDIDLE	11
+#define WH_CALLWNDPROCRET	12
+#define WH_KEYBOARD_LL	13
+#define WH_MOUSE_LL	14
+#define WH_MAX		14
+#define WH_MINHOOK	WH_MIN
+#define WH_MAXHOOK	WH_MAX
+#define HC_ACTION	0
+#define HC_GETNEXT	1
+#define HC_SKIP	2
+#define HC_NOREMOVE	3
+#define HC_NOREM	3
+#define HC_SYSMODALON	4
+#define HC_SYSMODALOFF	5
+#define HCBT_MOVESIZE	0
+#define HCBT_MINMAX	1
+#define HCBT_QS	2
+#define HCBT_CREATEWND	3
+#define HCBT_DESTROYWND	4
+#define HCBT_ACTIVATE	5
+#define HCBT_CLICKSKIPPED	6
+#define HCBT_KEYSKIPPED	7
+#define HCBT_SYSCOMMAND	8
+#define HCBT_SETFOCUS	9
+#define CF_TEXT	1
+#define CF_BITMAP	2
+#define CF_METAFILEPICT	3
+#define CF_SYLK	4
+#define CF_DIF	5
+#define CF_TIFF	6
+#define CF_OEMTEXT	7
+#define CF_DIB	8
+#define CF_PALETTE	9
+#define CF_PENDATA	10
+#define CF_RIFF	11
+#define CF_WAVE	12
+#define CF_UNICODETEXT	13
+#define CF_ENHMETAFILE	14
+#define CF_HDROP	15
+#define CF_LOCALE	16
+#define CF_MAX	17
+#define CF_OWNERDISPLAY	128
+#define CF_DSPTEXT	129
+#define CF_DSPBITMAP	130
+#define CF_DSPMETAFILEPICT	131
+#define CF_DSPENHMETAFILE	142
+#define CF_PRIVATEFIRST	512
+#define CF_PRIVATELAST	767
+#define CF_GDIOBJFIRST	768
+#define CF_GDIOBJLAST	1023
+#define HKL_NEXT	1
+#define HKL_PREV	0
+#define KLF_ACTIVATE	1
+#define KLF_SUBSTITUTE_OK	2
+#define KLF_UNLOADPREVIOUS	4
+#define KLF_REORDER	8
+#define KLF_REPLACELANG	16
+#define KLF_NOTELLSHELL	128
+#define KLF_SETFORPROCESS	256
+#define KL_NAMELENGTH 9
+#define MF_ENABLED	0
+#define MF_GRAYED	1
+#define MF_DISABLED	2
+#define MF_BITMAP	4
+#define MF_CHECKED	8
+#define MF_MENUBARBREAK 32
+#define MF_MENUBREAK	64
+#define MF_OWNERDRAW	256
+#define MF_POPUP	16
+#define MF_SEPARATOR	0x800
+#define MF_STRING	0
+#define MF_UNCHECKED	0
+#define MF_DEFAULT	4096
+#define MF_SYSMENU	0x2000
+#define MF_HELP	0x4000
+#define MF_END	128
+#define MF_RIGHTJUSTIFY	0x4000
+#define MF_MOUSESELECT	0x8000
+#define MF_INSERT 0
+#define MF_CHANGE 128
+#define MF_APPEND 256
+#define MF_DELETE 512
+#define MF_REMOVE 4096
+#define MF_USECHECKBITMAPS 512
+#define MF_UNHILITE 0
+#define MF_HILITE 128
+#define BSF_IGNORECURRENTTASK	2
+#define BSF_QUERY	1
+#define BSF_FLUSHDISK	4
+#define BSF_NOHANG	8
+#define BSF_POSTMESSAGE 16
+#define BSF_FORCEIFHUNG	32
+#define BSF_NOTIMEOUTIFNOTHUNG 64
+#define BSM_ALLCOMPONENTS	0
+#define BSM_APPLICATIONS	8
+#define BSM_ALLDESKTOPS		16
+#define BSM_INSTALLABLEDRIVERS	4
+#define BSM_NETDRIVER	2
+#define BSM_VXDS	1
+#define BROADCAST_QUERY_DENY	1112363332
+#define ENUM_CURRENT_SETTINGS	((DWORD)-1)
+#define ENUM_REGISTRY_SETTINGS	((DWORD)-2)
+#define DM_BITSPERPEL	0x40000
+#define DM_PELSWIDTH	0x80000
+#define DM_PELSHEIGHT	0x100000
+#define DM_DISPLAYFLAGS 0x200000
+#define DM_DISPLAYFREQUENCY 0x400000
+#define CDS_UPDATEREGISTRY	1
+#define CDS_TEST	2
+#define CDS_FULLSCREEN	4 
+#define CDS_GLOBAL	8 
+#define CDS_SET_PRIMARY	16
+#define CDS_RESET	0x40000000 
+#define CDS_SETRECT	0x20000000 
+#define CDS_NORESET	0x10000000 
+#define DISP_CHANGE_SUCCESSFUL	0
+#define DISP_CHANGE_RESTART	1
+#define DISP_CHANGE_BADFLAGS	(-4)
+#define DISP_CHANGE_BADPARAM	(-5)
+#define DISP_CHANGE_FAILED	(-1)
+#define DISP_CHANGE_BADMODE	(-2)
+#define DISP_CHANGE_NOTUPDATED	(-3)
+#define BST_CHECKED	1
+#define BST_INDETERMINATE	2
+#define BST_UNCHECKED	0
+#define BST_FOCUS	8
+#define BST_PUSHED	4
+#define MF_BYCOMMAND	0
+#define MF_BYPOSITION	1024
+#define MF_UNCHECKED	0
+#define MF_HILITE	128
+#define MF_UNHILITE	0
+#define CWP_ALL 0
+#define CWP_SKIPINVISIBLE	1
+#define CWP_SKIPDISABLED	2
+#define CWP_SKIPTRANSPARENT	4
+#define IMAGE_BITMAP	0
+#define IMAGE_ICON	1
+#define IMAGE_CURSOR	2
+#define IMAGE_ENHMETAFILE	3
+#define DF_ALLOWOTHERACCOUNTHOOK	1
+#define DESKTOP_CREATEMENU	4
+#define DESKTOP_CREATEWINDOW	2
+#define DESKTOP_ENUMERATE	64
+#define DESKTOP_HOOKCONTROL	8
+#define DESKTOP_JOURNALPLAYBACK	32
+#define DESKTOP_JOURNALRECORD	16
+#define DESKTOP_READOBJECTS	1
+#define DESKTOP_SWITCHDESKTOP	256
+#define DESKTOP_WRITEOBJECTS	128
+#define CW_USEDEFAULT	0x80000000
+#define WS_BORDER	0x800000
+#define WS_CAPTION	0xc00000
+#define WS_CHILD	0x40000000
+#define WS_CHILDWINDOW	0x40000000
+#define WS_CLIPCHILDREN 0x2000000
+#define WS_CLIPSIBLINGS 0x4000000
+#define WS_DISABLED	0x8000000
+#define WS_DLGFRAME	0x400000
+#define WS_GROUP	0x20000
+#define WS_HSCROLL	0x100000
+#define WS_ICONIC	0x20000000
+#define WS_MAXIMIZE	0x1000000
+#define WS_MAXIMIZEBOX	0x10000
+#define WS_MINIMIZE	0x20000000
+#define WS_MINIMIZEBOX	0x20000
+#define WS_OVERLAPPED	0
+#define WS_OVERLAPPEDWINDOW	0xcf0000
+#define WS_POPUP	0x80000000
+#define WS_POPUPWINDOW	0x80880000
+#define WS_SIZEBOX	0x40000
+#define WS_SYSMENU	0x80000
+#define WS_TABSTOP	0x10000
+#define WS_THICKFRAME	0x40000
+#define WS_TILED	0
+#define WS_TILEDWINDOW	0xcf0000
+#define WS_VISIBLE	0x10000000
+#define WS_VSCROLL	0x200000
+#define MDIS_ALLCHILDSTYLES	1
+#define BS_3STATE	5
+#define BS_AUTO3STATE	6
+#define BS_AUTOCHECKBOX	3
+#define BS_AUTORADIOBUTTON	9
+#define BS_BITMAP	128
+#define BS_BOTTOM	0x800
+#define BS_CENTER	0x300
+#define BS_CHECKBOX	2
+#define BS_DEFPUSHBUTTON	1
+#define BS_GROUPBOX	7
+#define BS_ICON	64
+#define BS_LEFT	256
+#define BS_LEFTTEXT	32
+#define BS_MULTILINE	0x2000
+#define BS_NOTIFY	0x4000
+#define BS_OWNERDRAW	0xb
+#define BS_PUSHBUTTON	0
+#define BS_PUSHLIKE	4096
+#define BS_RADIOBUTTON 4
+#define BS_RIGHT	512
+#define BS_RIGHTBUTTON	32
+#define BS_TEXT	0
+#define BS_TOP	0x400
+#define BS_USERBUTTON	8
+#define BS_VCENTER	0xc00
+#define BS_FLAT	0x8000
+#define CBS_AUTOHSCROLL	64
+#define CBS_DISABLENOSCROLL	0x800
+#define CBS_DROPDOWN	2
+#define CBS_DROPDOWNLIST	3
+#define CBS_HASSTRINGS	512
+#define CBS_LOWERCASE	0x4000
+#define CBS_NOINTEGRALHEIGHT	0x400
+#define CBS_OEMCONVERT	128
+#define CBS_OWNERDRAWFIXED	16
+#define CBS_OWNERDRAWVARIABLE	32
+#define CBS_SIMPLE	1
+#define CBS_SORT	256
+#define CBS_UPPERCASE	0x2000
+#define ES_AUTOHSCROLL	128
+#define ES_AUTOVSCROLL	64
+#define ES_CENTER	1
+#define ES_LEFT	0
+#define ES_LOWERCASE 16
+#define ES_MULTILINE 4
+#define ES_NOHIDESEL 256
+#define ES_NUMBER 0x2000
+#define ES_OEMCONVERT 0x400
+#define ES_PASSWORD 32
+#define ES_READONLY 0x800
+#define ES_RIGHT 2
+#define ES_UPPERCASE 8
+#define ES_WANTRETURN 4096
+#define LBS_DISABLENOSCROLL 4096
+#define LBS_EXTENDEDSEL 0x800
+#define LBS_HASSTRINGS 64
+#define LBS_MULTICOLUMN 512
+#define LBS_MULTIPLESEL 8
+#define LBS_NODATA	0x2000
+#define LBS_NOINTEGRALHEIGHT 256
+#define LBS_NOREDRAW 4
+#define LBS_NOSEL 0x4000
+#define LBS_NOTIFY 1
+#define LBS_OWNERDRAWFIXED 16
+#define LBS_OWNERDRAWVARIABLE 32
+#define LBS_SORT 2
+#define LBS_STANDARD 0xa00003
+#define LBS_USETABSTOPS 128
+#define LBS_WANTKEYBOARDINPUT 0x400
+#define SBS_BOTTOMALIGN 4
+#define SBS_HORZ 0
+#define SBS_LEFTALIGN 2
+#define SBS_RIGHTALIGN 4
+#define SBS_SIZEBOX 8
+#define SBS_SIZEBOXBOTTOMRIGHTALIGN 4
+#define SBS_SIZEBOXTOPLEFTALIGN 2
+#define SBS_SIZEGRIP 16
+#define SBS_TOPALIGN 2
+#define SBS_VERT 1
+#define SS_BITMAP 14
+#define SS_BLACKFRAME 7
+#define SS_BLACKRECT 4
+#define SS_CENTER 1
+#define SS_CENTERIMAGE 512
+#define SS_ENHMETAFILE 15
+#define SS_ETCHEDFRAME 18
+#define SS_ETCHEDHORZ 16
+#define SS_ETCHEDVERT 17
+#define SS_GRAYFRAME 8
+#define SS_GRAYRECT 5
+#define SS_ICON 3
+#define SS_LEFT 0
+#define SS_LEFTNOWORDWRAP 0xc
+#define SS_NOPREFIX 128
+#define SS_NOTIFY 256
+#define SS_OWNERDRAW 0xd
+#define SS_REALSIZEIMAGE 0x800
+#define SS_RIGHT 2
+#define SS_RIGHTJUST 0x400
+#define SS_SIMPLE 11
+#define SS_SUNKEN 4096
+#define SS_WHITEFRAME 9
+#define SS_WHITERECT	6
+#define SS_USERITEM	10
+#define SS_TYPEMASK	0x0000001FL
+#define SS_ENDELLIPSIS	0x00004000L
+#define SS_PATHELLIPSIS	0x00008000L
+#define SS_WORDELLIPSIS	0x0000C000L
+#define SS_ELLIPSISMASK 0x0000C000L
+#define DS_3DLOOK 4
+#define DS_ABSALIGN 1
+#define DS_CENTER 0x800
+#define DS_CENTERMOUSE 4096
+#define DS_CONTEXTHELP 0x2000
+#define DS_CONTROL 0x400
+#define DS_FIXEDSYS 8
+#define DS_LOCALEDIT 32
+#define DS_MODALFRAME 128
+#define DS_NOFAILCREATE 16
+#define DS_NOIDLEMSG	256
+#define DS_SETFONT 64
+#define DS_SETFOREGROUND 512
+#define DS_SYSMODAL 2
+#define WS_EX_ACCEPTFILES 16
+#define WS_EX_APPWINDOW	0x40000
+#define WS_EX_CLIENTEDGE 512
+#define WS_EX_COMPOSITED 0x2000000 /* XP */
+#define WS_EX_CONTEXTHELP 0x400
+#define WS_EX_CONTROLPARENT 0x10000
+#define WS_EX_DLGMODALFRAME 1
+#define WS_EX_LAYERED 0x80000   /* w2k */
+#define WS_EX_LAYOUTRTL 0x400000 /* w98, w2k */
+#define WS_EX_LEFT	0
+#define WS_EX_LEFTSCROLLBAR	0x4000
+#define WS_EX_LTRREADING	0
+#define WS_EX_MDICHILD	64
+#define WS_EX_NOACTIVATE 0x8000000 /* w2k */
+#define WS_EX_NOINHERITLAYOUT 0x100000 /* w2k */
+#define WS_EX_NOPARENTNOTIFY	4
+#define WS_EX_OVERLAPPEDWINDOW	0x300
+#define WS_EX_PALETTEWINDOW	0x188
+#define WS_EX_RIGHT	0x1000
+#define WS_EX_RIGHTSCROLLBAR	0
+#define WS_EX_RTLREADING	0x2000
+#define WS_EX_STATICEDGE	0x20000
+#define WS_EX_TOOLWINDOW	128
+#define WS_EX_TOPMOST	8
+#define WS_EX_TRANSPARENT	32
+#define WS_EX_WINDOWEDGE	256
+#define WINSTA_ACCESSCLIPBOARD	4
+#define WINSTA_ACCESSGLOBALATOMS	32
+#define WINSTA_CREATEDESKTOP	8
+#define WINSTA_ENUMDESKTOPS	1
+#define WINSTA_ENUMERATE	256
+#define WINSTA_EXITWINDOWS	64
+#define WINSTA_READATTRIBUTES	2
+#define WINSTA_READSCREEN	512
+#define WINSTA_WRITEATTRIBUTES	16
+#define DDL_READWRITE	0
+#define DDL_READONLY	1
+#define DDL_HIDDEN	2
+#define DDL_SYSTEM	4
+#define DDL_DIRECTORY	16
+#define DDL_ARCHIVE	32
+#define DDL_POSTMSGS	8192
+#define DDL_DRIVES	16384
+#define DDL_EXCLUSIVE	32768
+#define DC_ACTIVE	1
+#define DC_SMALLCAP	2
+#define DC_ICON	4
+#define DC_TEXT	8
+#define DC_INBUTTON	16
+#define DC_CAPTION	(DC_ICON|DC_TEXT|DC_BUTTONS)
+#define DC_NC	(DC_CAPTION|DC_FRAME)
+#define BDR_RAISEDOUTER	1
+#define BDR_SUNKENOUTER	2
+#define BDR_RAISEDINNER	4
+#define BDR_SUNKENINNER	8
+#define BDR_OUTER	3
+#define BDR_INNER	0xc
+#define BDR_RAISED	5
+#define BDR_SUNKEN	10
+#define EDGE_RAISED	(BDR_RAISEDOUTER|BDR_RAISEDINNER)
+#define EDGE_SUNKEN	(BDR_SUNKENOUTER|BDR_SUNKENINNER)
+#define EDGE_ETCHED	(BDR_SUNKENOUTER|BDR_RAISEDINNER)
+#define EDGE_BUMP	(BDR_RAISEDOUTER|BDR_SUNKENINNER)
+#define BF_LEFT	1
+#define BF_TOP	2
+#define BF_RIGHT	4
+#define BF_BOTTOM	8
+#define BF_TOPLEFT	(BF_TOP|BF_LEFT)
+#define BF_TOPRIGHT	(BF_TOP|BF_RIGHT)
+#define BF_BOTTOMLEFT	(BF_BOTTOM|BF_LEFT)
+#define BF_BOTTOMRIGHT	(BF_BOTTOM|BF_RIGHT)
+#define BF_RECT	(BF_LEFT|BF_TOP|BF_RIGHT|BF_BOTTOM)
+#define BF_DIAGONAL	16
+#define BF_DIAGONAL_ENDTOPRIGHT	(BF_DIAGONAL|BF_TOP|BF_RIGHT)
+#define BF_DIAGONAL_ENDTOPLEFT	(BF_DIAGONAL|BF_TOP|BF_LEFT)
+#define BF_DIAGONAL_ENDBOTTOMLEFT	(BF_DIAGONAL|BF_BOTTOM|BF_LEFT)
+#define BF_DIAGONAL_ENDBOTTOMRIGHT	(BF_DIAGONAL|BF_BOTTOM|BF_RIGHT)
+#define BF_MIDDLE	0x800
+#define BF_SOFT	0x1000
+#define BF_ADJUST	0x2000
+#define BF_FLAT	0x4000
+#define BF_MONO	0x8000
+#define DFC_CAPTION	1
+#define DFC_MENU	2
+#define DFC_SCROLL	3
+#define DFC_BUTTON	4
+#define DFCS_CAPTIONCLOSE	0
+#define DFCS_CAPTIONMIN	1
+#define DFCS_CAPTIONMAX	2
+#define DFCS_CAPTIONRESTORE	3
+#define DFCS_CAPTIONHELP	4
+#define DFCS_MENUARROW	0
+#define DFCS_MENUCHECK	1
+#define DFCS_MENUBULLET	2
+#define DFCS_MENUARROWRIGHT	4
+#define DFCS_SCROLLUP	0
+#define DFCS_SCROLLDOWN	1
+#define DFCS_SCROLLLEFT	2
+#define DFCS_SCROLLRIGHT	3
+#define DFCS_SCROLLCOMBOBOX	5
+#define DFCS_SCROLLSIZEGRIP	8
+#define DFCS_SCROLLSIZEGRIPRIGHT	16
+#define DFCS_BUTTONCHECK	0
+#define DFCS_BUTTONRADIOIMAGE	1
+#define DFCS_BUTTONRADIOMASK	2
+#define DFCS_BUTTONRADIO	4
+#define DFCS_BUTTON3STATE	8
+#define DFCS_BUTTONPUSH	16
+#define DFCS_INACTIVE	256
+#define DFCS_PUSHED	512
+#define DFCS_CHECKED	1024
+#define DFCS_ADJUSTRECT	0x2000
+#define DFCS_FLAT	0x4000
+#define DFCS_MONO	0x8000
+#define DST_COMPLEX	0
+#define DST_TEXT	1
+#define DST_PREFIXTEXT	2
+#define DST_ICON	3
+#define DST_BITMAP	4
+#define DSS_NORMAL	0
+#define DSS_UNION	16
+#define DSS_DISABLED	32
+#define DSS_MONO	128
+#define DSS_RIGHT	0x8000
+#define DT_BOTTOM	8
+#define DT_CALCRECT	1024
+#define DT_CENTER	1
+#define DT_EDITCONTROL	8192
+#define DT_END_ELLIPSIS	32768
+#define DT_PATH_ELLIPSIS	16384
+#define DT_WORD_ELLIPSIS 0x40000
+#define DT_EXPANDTABS	64
+#define DT_EXTERNALLEADING	512
+#define DT_LEFT	0
+#define DT_MODIFYSTRING	65536
+#define DT_NOCLIP	256
+#define DT_NOPREFIX	2048
+#define DT_RIGHT	2
+#define DT_RTLREADING	131072
+#define DT_SINGLELINE	32
+#define DT_TABSTOP	128
+#define DT_TOP	0
+#define DT_VCENTER	4
+#define DT_WORDBREAK	16
+#define DT_INTERNAL	4096
+#define WB_ISDELIMITER	2
+#define WB_LEFT	0
+#define WB_RIGHT	1
+#define SB_HORZ	0
+#define SB_VERT	1
+#define SB_CTL	2
+#define SB_BOTH	3
+#define ESB_DISABLE_BOTH	3
+#define ESB_DISABLE_DOWN	2
+#define ESB_DISABLE_LEFT	1
+#define ESB_DISABLE_LTUP	1
+#define ESB_DISABLE_RIGHT	2
+#define ESB_DISABLE_RTDN	2
+#define ESB_DISABLE_UP	1
+#define ESB_ENABLE_BOTH	0
+#define SB_LINEUP	0
+#define SB_LINEDOWN	1
+#define SB_LINELEFT	0
+#define SB_LINERIGHT	1
+#define SB_PAGEUP	2
+#define SB_PAGEDOWN	3
+#define SB_PAGELEFT	2
+#define SB_PAGERIGHT	3
+#define SB_THUMBPOSITION	4
+#define SB_THUMBTRACK	5
+#define SB_ENDSCROLL	8
+#define SB_LEFT	6
+#define SB_RIGHT	7
+#define SB_BOTTOM	7
+#define SB_TOP	6
+#define MAKEINTRESOURCEA(i) (LPSTR)((DWORD)((WORD)(i)))
+#define MAKEINTRESOURCEW(i) (LPWSTR)((DWORD)((WORD)(i)))
+#ifndef XFree86Server
+# define RT_CURSOR MAKEINTRESOURCE(1)
+# define RT_FONT MAKEINTRESOURCE(8)
+#endif /* ndef XFree86Server */
+#define RT_BITMAP MAKEINTRESOURCE(2)
+#define RT_ICON MAKEINTRESOURCE(3)
+#define RT_MENU MAKEINTRESOURCE(4)
+#define RT_DIALOG MAKEINTRESOURCE(5)
+#define RT_STRING MAKEINTRESOURCE(6)
+#define RT_FONTDIR MAKEINTRESOURCE(7)
+#define RT_ACCELERATOR MAKEINTRESOURCE(9)
+#define RT_RCDATA MAKEINTRESOURCE(10)
+#define RT_MESSAGETABLE MAKEINTRESOURCE(11)
+#define DIFFERENCE 11
+#define RT_GROUP_CURSOR MAKEINTRESOURCE((DWORD)RT_CURSOR+DIFFERENCE)
+#define RT_GROUP_ICON MAKEINTRESOURCE((DWORD)RT_ICON+DIFFERENCE)
+#define RT_VERSION MAKEINTRESOURCE(16)
+#define RT_DLGINCLUDE MAKEINTRESOURCE(17)
+#define RT_PLUGPLAY MAKEINTRESOURCE(19)
+#define RT_VXD MAKEINTRESOURCE(20)
+#define RT_ANICURSOR MAKEINTRESOURCE(21)
+#define RT_ANIICON MAKEINTRESOURCE(22)
+#define RT_HTML MAKEINTRESOURCE(23)
+#define EWX_FORCE 4
+#define EWX_LOGOFF 0
+#define EWX_POWEROFF 8
+#define EWX_REBOOT 2
+#define EWX_SHUTDOWN 1
+#define CS_BYTEALIGNCLIENT 4096
+#define CS_BYTEALIGNWINDOW 8192
+#define CS_KEYCVTWINDOW 4
+#define CS_NOKEYCVT 256
+#define CS_CLASSDC 64
+#define CS_DBLCLKS 8
+#define CS_GLOBALCLASS 16384
+#define CS_HREDRAW 2
+#define CS_NOCLOSE 512
+#define CS_OWNDC 32
+#define CS_PARENTDC 128
+#define CS_SAVEBITS 2048
+#define CS_VREDRAW 1
+#define CS_IME 0x10000
+#define GCW_ATOM (-32)
+#define GCL_CBCLSEXTRA (-20)
+#define GCL_CBWNDEXTRA (-18)
+#define GCL_HBRBACKGROUND (-10)
+#define GCL_HCURSOR (-12)
+#define GCL_HICON (-14)
+#define GCL_HICONSM (-34)
+#define GCL_HMODULE (-16)
+#define GCL_MENUNAME (-8)
+#define GCL_STYLE (-26)
+#define GCL_WNDPROC (-24)
+#if 0
+    /* This is supposed to be defined by the program using it not defined
+       in the win32api headers.  I've left it here for documentation purposes.
+    */
+#ifndef IDC_STATIC  /* May be predefined by resource compiler.  */
+#define IDC_STATIC (-1)
+#endif
+#endif
+#define IDC_ARROW MAKEINTRESOURCE(32512)
+#define IDC_IBEAM MAKEINTRESOURCE(32513)
+#define IDC_WAIT MAKEINTRESOURCE(32514)
+#define IDC_CROSS MAKEINTRESOURCE(32515)
+#define IDC_UPARROW MAKEINTRESOURCE(32516)
+#define IDC_SIZENWSE MAKEINTRESOURCE(32642)
+#define IDC_SIZENESW MAKEINTRESOURCE(32643)
+#define IDC_SIZEWE MAKEINTRESOURCE(32644)
+#define IDC_SIZENS MAKEINTRESOURCE(32645)
+#define IDC_SIZEALL MAKEINTRESOURCE(32646)
+#define IDC_NO MAKEINTRESOURCE(32648)
+#define IDC_HAND MAKEINTRESOURCE(32649)
+#define IDC_APPSTARTING MAKEINTRESOURCE(32650)
+#define IDC_HELP MAKEINTRESOURCE(32651)
+#define IDC_ICON MAKEINTRESOURCE(32641)
+#define IDC_SIZE MAKEINTRESOURCE(32640)
+#ifndef RC_INVOKED
+#define IDI_APPLICATION MAKEINTRESOURCE(32512)
+#define IDI_HAND MAKEINTRESOURCE(32513)
+#define IDI_QUESTION MAKEINTRESOURCE(32514)
+#define IDI_EXCLAMATION MAKEINTRESOURCE(32515)
+#define IDI_ASTERISK MAKEINTRESOURCE(32516)
+#define IDI_WINLOGO MAKEINTRESOURCE(32517)
+#else
+#define IDI_APPLICATION 32512
+#define IDI_HAND 32513
+#define IDI_QUESTION 32514
+#define IDI_EXCLAMATION 32515
+#define IDI_ASTERISK 32516
+#define IDI_WINLOGO 32517
+#endif
+#define IDI_WARNING IDI_EXCLAMATION
+#define IDI_ERROR IDI_HAND
+#define IDI_INFORMATION IDI_ASTERISK
+#define MIIM_STATE 1
+#define MIIM_ID 2
+#define MIIM_SUBMENU 4
+#define MIIM_CHECKMARKS 8
+#define MIIM_TYPE 16
+#define MIIM_DATA 32
+#define MIIM_STRING 64
+#define MIIM_BITMAP 128
+#define MIIM_FTYPE 256
+#define MFT_BITMAP 4
+#define MFT_MENUBARBREAK 32
+#define MFT_MENUBREAK 64
+#define MFT_OWNERDRAW 256
+#define MFT_RADIOCHECK 512
+#define MFT_RIGHTJUSTIFY 0x4000
+#define MFT_SEPARATOR 0x800
+#define MFT_RIGHTORDER 0x2000L
+#define MFT_STRING 0
+#define MFS_CHECKED 8
+#define MFS_DEFAULT 4096
+#define MFS_DISABLED 3
+#define MFS_ENABLED 0
+#define MFS_GRAYED 3
+#define MFS_HILITE 128
+#define MFS_UNCHECKED 0
+#define MFS_UNHILITE 0
+#define GW_HWNDNEXT 2
+#define GW_HWNDPREV 3
+#define GW_CHILD 5
+#define GW_HWNDFIRST 0
+#define GW_HWNDLAST 1
+#define GW_OWNER 4
+#define SW_HIDE 0
+#define SW_NORMAL 1
+#define SW_SHOWNORMAL 1
+#define SW_SHOWMINIMIZED 2
+#define SW_MAXIMIZE 3
+#define SW_SHOWMAXIMIZED 3
+#define SW_SHOWNOACTIVATE 4
+#define SW_SHOW 5
+#define SW_MINIMIZE 6
+#define SW_SHOWMINNOACTIVE 7
+#define SW_SHOWNA 8
+#define SW_RESTORE 9
+#define SW_SHOWDEFAULT 10
+#define SW_FORCEMINIMIZE 11
+#define SW_MAX  11
+#define MB_USERICON 128
+#define MB_ICONASTERISK 64
+#define MB_ICONEXCLAMATION 0x30
+#define MB_ICONWARNING 0x30
+#define MB_ICONERROR 16
+#define MB_ICONHAND 16
+#define MB_ICONQUESTION 32
+#define MB_OK 0
+#define MB_ABORTRETRYIGNORE 2
+#define MB_APPLMODAL 0
+#define MB_DEFAULT_DESKTOP_ONLY 0x20000
+#define MB_HELP 0x4000
+#define MB_RIGHT 0x80000
+#define MB_RTLREADING 0x100000
+#define MB_TOPMOST 0x40000
+#define MB_DEFBUTTON1 0
+#define MB_DEFBUTTON2 256
+#define MB_DEFBUTTON3 512
+#define MB_DEFBUTTON4 0x300
+#define MB_ICONINFORMATION 64
+#define MB_ICONSTOP 16
+#define MB_OKCANCEL 1
+#define MB_RETRYCANCEL 5
+#ifdef _WIN32_WINNT
+#if (_WIN32_WINNT >= 0x0400)
+#define MB_SERVICE_NOTIFICATION  0x00200000
+#else
+#define MB_SERVICE_NOTIFICATION  0x00040000
+#endif
+#define MB_SERVICE_NOTIFICATION_NT3X  0x00040000
+#endif
+#define MB_SETFOREGROUND 0x10000
+#define MB_SYSTEMMODAL 4096
+#define MB_TASKMODAL 0x2000
+#define MB_YESNO 4
+#define MB_YESNOCANCEL 3
+#define MB_ICONMASK 240
+#define MB_DEFMASK 3840
+#define MB_MODEMASK 0x00003000
+#define MB_MISCMASK 0x0000C000
+#define MB_NOFOCUS 0x00008000
+#define MB_TYPEMASK 15
+#define MB_TOPMOST 0x40000
+#define IDABORT 3
+#define IDCANCEL 2
+#define IDCLOSE 8
+#define IDHELP 9
+#define IDIGNORE 5
+#define IDNO 7
+#define IDOK 1
+#define IDRETRY 4
+#define IDYES 6
+#define GWL_EXSTYLE (-20)
+#define GWL_STYLE (-16)
+#define GWL_WNDPROC (-4)
+#define GWLP_WNDPROC (-4)
+#define GWL_HINSTANCE (-6)
+#define GWLP_HINSTANCE (-6)
+#define GWL_HWNDPARENT (-8)
+#define GWLP_HWNDPARENT (-8)
+#define GWL_ID (-12)
+#define GWLP_ID (-12)
+#define GWL_USERDATA (-21)
+#define GWLP_USERDATA (-21)
+#define DWL_DLGPROC 4
+#define DWLP_DLGPROC 4
+#define DWL_MSGRESULT 0
+#define DWLP_MSGRESULT 0
+#define DWL_USER 8
+#define DWLP_USER 8
+#define QS_ALLEVENTS 191
+#define QS_ALLINPUT 255
+#define QS_HOTKEY 128
+#define QS_INPUT 7
+#define QS_KEY 1
+#define QS_MOUSE 6
+#define QS_MOUSEBUTTON 4
+#define QS_MOUSEMOVE 2
+#define QS_PAINT 32
+#define QS_POSTMESSAGE 8
+#define QS_SENDMESSAGE 64
+#define QS_TIMER 16
+#define COLOR_3DDKSHADOW 21
+#define COLOR_3DFACE 15
+#define COLOR_3DHILIGHT 20
+#define COLOR_3DHIGHLIGHT 20
+#define COLOR_3DLIGHT 22
+#define COLOR_BTNHILIGHT 20
+#define COLOR_3DSHADOW 16
+#define COLOR_ACTIVEBORDER 10
+#define COLOR_ACTIVECAPTION 2
+#define COLOR_APPWORKSPACE 12
+#define COLOR_BACKGROUND 1
+#define COLOR_DESKTOP 1
+#define COLOR_BTNFACE 15
+#define COLOR_BTNHIGHLIGHT 20
+#define COLOR_BTNSHADOW 16
+#define COLOR_BTNTEXT 18
+#define COLOR_CAPTIONTEXT 9
+#define COLOR_GRAYTEXT 17
+#define COLOR_HIGHLIGHT 13
+#define COLOR_HIGHLIGHTTEXT 14
+#define COLOR_INACTIVEBORDER 11
+#define COLOR_INACTIVECAPTION 3
+#define COLOR_INACTIVECAPTIONTEXT 19
+#define COLOR_INFOBK 24
+#define COLOR_INFOTEXT 23
+#define COLOR_MENU 4
+#define COLOR_MENUTEXT 7
+#define COLOR_SCROLLBAR 0
+#define COLOR_WINDOW 5
+#define COLOR_WINDOWFRAME 6
+#define COLOR_WINDOWTEXT 8
+#define CTLCOLOR_MSGBOX 0
+#define CTLCOLOR_EDIT 1
+#define CTLCOLOR_LISTBOX 2
+#define CTLCOLOR_BTN 3
+#define CTLCOLOR_DLG 4
+#define CTLCOLOR_SCROLLBAR 5
+#define CTLCOLOR_STATIC 6
+#define CTLCOLOR_MAX 7
+#define SM_CXSCREEN 0
+#define SM_CYSCREEN 1
+#define SM_CXVSCROLL 2
+#define SM_CYHSCROLL 3
+#define SM_CYCAPTION 4
+#define SM_CXBORDER 5
+#define SM_CYBORDER 6
+#define SM_CXDLGFRAME 7
+#define SM_CXFIXEDFRAME 7
+#define SM_CYDLGFRAME 8
+#define SM_CYFIXEDFRAME 8
+#define SM_CYVTHUMB 9
+#define SM_CXHTHUMB 10
+#define SM_CXICON 11
+#define SM_CYICON 12
+#define SM_CXCURSOR 13
+#define SM_CYCURSOR 14
+#define SM_CYMENU 15
+#define SM_CXFULLSCREEN 16
+#define SM_CYFULLSCREEN 17
+#define SM_CYKANJIWINDOW 18
+#define SM_MOUSEPRESENT 19
+#define SM_CYVSCROLL 20
+#define SM_CXHSCROLL 21
+#define SM_DEBUG 22
+#define SM_SWAPBUTTON 23
+#define SM_RESERVED1 24
+#define SM_RESERVED2 25
+#define SM_RESERVED3 26
+#define SM_RESERVED4 27
+#define SM_CXMIN 28
+#define SM_CYMIN 29
+#define SM_CXSIZE 30
+#define SM_CYSIZE 31
+#define SM_CXSIZEFRAME 32
+#define SM_CXFRAME 32
+#define SM_CYSIZEFRAME 33
+#define SM_CYFRAME 33
+#define SM_CXMINTRACK 34
+#define SM_CYMINTRACK 35
+#define SM_CXDOUBLECLK 36
+#define SM_CYDOUBLECLK 37
+#define SM_CXICONSPACING 38
+#define SM_CYICONSPACING 39
+#define SM_MENUDROPALIGNMENT 40
+#define SM_PENWINDOWS 41
+#define SM_DBCSENABLED 42
+#define SM_CMOUSEBUTTONS 43
+#define SM_SECURE 44
+#define SM_CXEDGE 45
+#define SM_CYEDGE 46
+#define SM_CXMINSPACING 47
+#define SM_CYMINSPACING 48
+#define SM_CXSMICON 49
+#define SM_CYSMICON 50
+#define SM_CYSMCAPTION 51
+#define SM_CXSMSIZE 52
+#define SM_CYSMSIZE 53
+#define SM_CXMENUSIZE 54
+#define SM_CYMENUSIZE 55
+#define SM_ARRANGE 56
+#define SM_CXMINIMIZED 57
+#define SM_CYMINIMIZED 58
+#define SM_CXMAXTRACK 59
+#define SM_CYMAXTRACK 60
+#define SM_CXMAXIMIZED 61
+#define SM_CYMAXIMIZED 62
+#define SM_NETWORK 63
+#define LR_DEFAULTSIZE 64
+#define SM_CLEANBOOT 67
+#define SM_CXDRAG 68
+#define SM_CYDRAG 69
+#define SM_SHOWSOUNDS 70
+#define SM_CXMENUCHECK 71
+#define SM_CYMENUCHECK 72
+#define SM_SLOWMACHINE 73
+#define SM_MIDEASTENABLED 74
+#define SM_MOUSEWHEELPRESENT 75
+#define SM_XVIRTUALSCREEN 76
+#define SM_YVIRTUALSCREEN 77
+#define SM_CXVIRTUALSCREEN 78
+#define SM_CYVIRTUALSCREEN 79
+#define SM_CMONITORS 80
+#define SM_SAMEDISPLAYFORMAT 81
+#if (_WIN32_WINNT < 0x0400)
+#define SM_CMETRICS 76
+#else
+#define SM_CMETRICS 83
+#endif
+#define ARW_BOTTOMLEFT 0
+#define ARW_BOTTOMRIGHT 1
+#define ARW_HIDE 8
+#define ARW_TOPLEFT 2
+#define ARW_TOPRIGHT 3
+#define ARW_DOWN 4
+#define ARW_LEFT 0
+#define ARW_RIGHT 0
+#define ARW_UP 4
+#define UOI_FLAGS 1
+#define UOI_NAME 2
+#define UOI_TYPE 3
+#define UOI_USER_SID 4
+#define LR_DEFAULTCOLOR 0
+#define LR_MONOCHROME 1
+#define LR_COLOR 2
+#define LR_COPYRETURNORG 4
+#define LR_COPYDELETEORG 8
+#define LR_LOADFROMFILE 16
+#define LR_LOADTRANSPARENT 32
+#define LR_LOADREALSIZE 128
+#define LR_LOADMAP3DCOLORS 4096
+#define LR_CREATEDIBSECTION 8192
+#define LR_COPYFROMRESOURCE 0x4000
+#define LR_SHARED 32768
+#define KEYEVENTF_EXTENDEDKEY 1
+#define KEYEVENTF_KEYUP 2
+#define OBM_BTNCORNERS 32758
+#define OBM_BTSIZE 32761
+#define OBM_CHECK 32760
+#define OBM_CHECKBOXES 32759
+#define OBM_CLOSE 32754
+#define OBM_COMBO 32738
+#define OBM_DNARROW 32752
+#define OBM_DNARROWD 32742
+#define OBM_DNARROWI 32736
+#define OBM_LFARROW 32750
+#define OBM_LFARROWI 32734
+#define OBM_LFARROWD 32740
+#define OBM_MNARROW 32739
+#define OBM_OLD_CLOSE 32767
+#define OBM_OLD_DNARROW 32764
+#define OBM_OLD_LFARROW 32762
+#define OBM_OLD_REDUCE 32757
+#define OBM_OLD_RESTORE 32755
+#define OBM_OLD_RGARROW 32763
+#define OBM_OLD_UPARROW 32765
+#define OBM_OLD_ZOOM 32756
+#define OBM_REDUCE 32749
+#define OBM_REDUCED 32746
+#define OBM_RESTORE 32747
+#define OBM_RESTORED 32744
+#define OBM_RGARROW 32751
+#define OBM_RGARROWD 32741
+#define OBM_RGARROWI 32735
+#define OBM_SIZE 32766
+#define OBM_UPARROW 32753
+#define OBM_UPARROWD 32743
+#define OBM_UPARROWI 32737
+#define OBM_ZOOM 32748
+#define OBM_ZOOMD 32745
+#define OCR_NORMAL 32512
+#define OCR_IBEAM 32513
+#define OCR_WAIT 32514
+#define OCR_CROSS 32515
+#define OCR_UP 32516
+#define OCR_SIZE 32640
+#define OCR_ICON 32641
+#define OCR_SIZENWSE 32642
+#define OCR_SIZENESW 32643
+#define OCR_SIZEWE 32644
+#define OCR_SIZENS 32645
+#define OCR_SIZEALL 32646
+#define OCR_NO 32648
+#define OCR_APPSTARTING 32650
+#define OIC_SAMPLE 32512
+#define OIC_HAND 32513
+#define OIC_QUES 32514
+#define OIC_BANG 32515
+#define OIC_NOTE 32516
+#define OIC_WINLOGO 32517
+#define OIC_WARNING OIC_BANG
+#define OIC_ERROR OIC_HAND
+#define OIC_INFORMATION OIC_NOTE
+#define HELPINFO_MENUITEM 2
+#define HELPINFO_WINDOW 1
+#define MSGF_DIALOGBOX 0
+#define MSGF_MESSAGEBOX 1
+#define MSGF_MENU 2
+#define MSGF_MOVE 3
+#define MSGF_SIZE 4
+#define MSGF_SCROLLBAR 5
+#define MSGF_NEXTWINDOW 6
+#define MSGF_MAINLOOP 8
+#define MSGF_USER 4096
+#define MOUSEEVENTF_MOVE 1
+#define MOUSEEVENTF_LEFTDOWN 2
+#define MOUSEEVENTF_LEFTUP 4
+#define MOUSEEVENTF_RIGHTDOWN 8
+#define MOUSEEVENTF_RIGHTUP 16
+#define MOUSEEVENTF_MIDDLEDOWN 32
+#define MOUSEEVENTF_MIDDLEUP 64
+#define MOUSEEVENTF_WHEEL 0x0800 
+#define MOUSEEVENTF_ABSOLUTE 32768
+#define PM_NOREMOVE 0
+#define PM_REMOVE 1
+#define PM_NOYIELD 2
+#define HWND_BROADCAST  ((HWND)0xffff)
+#define HWND_BOTTOM ((HWND)1)
+#define HWND_NOTOPMOST ((HWND)(-2))
+#define HWND_TOP ((HWND)0)
+#define HWND_TOPMOST ((HWND)(-1))
+#define HWND_DESKTOP (HWND)0
+#define HWND_MESSAGE ((HWND)(-3)) /* w2k */
+#define RDW_ERASE 4
+#define RDW_FRAME 1024
+#define RDW_INTERNALPAINT 2
+#define RDW_INVALIDATE 1
+#define RDW_NOERASE 32
+#define RDW_NOFRAME 2048
+#define RDW_NOINTERNALPAINT 16
+#define RDW_VALIDATE 8
+#define RDW_ERASENOW 512
+#define RDW_UPDATENOW 256
+#define RDW_ALLCHILDREN 128
+#define RDW_NOCHILDREN 64
+#define SMTO_ABORTIFHUNG 2
+#define SMTO_BLOCK 1
+#define SMTO_NORMAL 0
+#define SIF_ALL 23
+#define SIF_PAGE 2
+#define SIF_POS 4
+#define SIF_RANGE 1
+#define SIF_DISABLENOSCROLL 8
+#define SIF_TRACKPOS   16
+#define SWP_DRAWFRAME 32
+#define SWP_FRAMECHANGED 32
+#define SWP_HIDEWINDOW 128
+#define SWP_NOACTIVATE 16
+#define SWP_NOCOPYBITS 256
+#define SWP_NOMOVE 2
+#define SWP_NOSIZE 1
+#define SWP_NOREDRAW 8
+#define SWP_NOZORDER 4
+#define SWP_SHOWWINDOW 64
+#define SWP_NOOWNERZORDER 512
+#define SWP_NOREPOSITION 512
+#define SWP_NOSENDCHANGING 1024
+#define SWP_DEFERERASE 8192
+#define SWP_ASYNCWINDOWPOS  16384
+#define HSHELL_ACTIVATESHELLWINDOW 3
+#define HSHELL_GETMINRECT 5
+#define HSHELL_LANGUAGE 8
+#define HSHELL_REDRAW 6
+#define HSHELL_TASKMAN 7
+#define HSHELL_WINDOWACTIVATED 4
+#define HSHELL_WINDOWCREATED 1
+#define HSHELL_WINDOWDESTROYED 2
+#define SPI_GETACCESSTIMEOUT 60
+#define SPI_GETANIMATION 72
+#define SPI_GETBEEP 1
+#define SPI_GETBORDER 5
+#define SPI_GETDEFAULTINPUTLANG 89
+#define SPI_GETDRAGFULLWINDOWS 38
+#define SPI_GETFASTTASKSWITCH 35
+#define SPI_GETFILTERKEYS 50
+#define SPI_GETFONTSMOOTHING 74
+#define SPI_GETGRIDGRANULARITY 18
+#define SPI_GETHIGHCONTRAST 66
+#define SPI_GETICONMETRICS 45
+#define SPI_GETICONTITLELOGFONT 31
+#define SPI_GETICONTITLEWRAP 25
+#define SPI_GETKEYBOARDDELAY 22
+#define SPI_GETKEYBOARDPREF 68
+#define SPI_GETKEYBOARDSPEED 10
+#define SPI_GETLOWPOWERACTIVE 83
+#define SPI_GETLOWPOWERTIMEOUT 79
+#define SPI_GETMENUDROPALIGNMENT 27
+#define SPI_GETMINIMIZEDMETRICS 43
+#define SPI_GETMOUSE 3
+#define SPI_GETMOUSEKEYS 54
+#define SPI_GETMOUSETRAILS 94
+#define SPI_GETNONCLIENTMETRICS 41
+#define SPI_GETPOWEROFFACTIVE 84
+#define SPI_GETPOWEROFFTIMEOUT 80
+#define SPI_GETSCREENREADER 70
+#define SPI_GETSCREENSAVEACTIVE 16
+#define SPI_GETSCREENSAVETIMEOUT 14
+#define SPI_GETSERIALKEYS 62
+#define SPI_GETSHOWSOUNDS 56
+#define SPI_GETSOUNDSENTRY 64
+#define SPI_GETSTICKYKEYS 58
+#define SPI_GETTOGGLEKEYS 52
+#define SPI_GETWINDOWSEXTENSION 92
+#define SPI_GETWORKAREA 48
+#define SPI_ICONHORIZONTALSPACING 13
+#define SPI_ICONVERTICALSPACING 24
+#define SPI_LANGDRIVER 12
+#define SPI_SCREENSAVERRUNNING 97
+#define SPI_SETACCESSTIMEOUT 61
+#define SPI_SETANIMATION 73
+#define SPI_SETBEEP 2
+#define SPI_SETBORDER 6
+#define SPI_SETDEFAULTINPUTLANG 90
+#define SPI_SETDESKPATTERN 21
+#define SPI_SETDESKWALLPAPER 20
+#define SPI_SETDOUBLECLICKTIME 32
+#define SPI_SETDOUBLECLKHEIGHT 30
+#define SPI_SETDOUBLECLKWIDTH 29
+#define SPI_SETDRAGFULLWINDOWS 37
+#define SPI_SETDRAGHEIGHT 77
+#define SPI_SETDRAGWIDTH 76
+#define SPI_SETFASTTASKSWITCH 36
+#define SPI_SETFILTERKEYS 51
+#define SPI_SETFONTSMOOTHING 75
+#define SPI_SETGRIDGRANULARITY 19
+#define SPI_SETHANDHELD 78
+#define SPI_SETHIGHCONTRAST 67
+#define SPI_SETICONMETRICS 46
+#define SPI_SETICONTITLELOGFONT 34
+#define SPI_SETICONTITLEWRAP 26
+#define SPI_SETKEYBOARDDELAY 23
+#define SPI_SETKEYBOARDPREF 69
+#define SPI_SETKEYBOARDSPEED 11
+#define SPI_SETLANGTOGGLE 91
+#define SPI_SETLOWPOWERACTIVE 85
+#define SPI_SETLOWPOWERTIMEOUT 81
+#define SPI_SETMENUDROPALIGNMENT 28
+#define SPI_SETMINIMIZEDMETRICS 44
+#define SPI_SETMOUSE 4
+#define SPI_SETMOUSEBUTTONSWAP 33
+#define SPI_SETMOUSEKEYS 55
+#define SPI_SETMOUSETRAILS 93
+#define SPI_SETNONCLIENTMETRICS 42
+#define SPI_SETPENWINDOWS 49
+#define SPI_SETPOWEROFFACTIVE 86
+#define SPI_SETPOWEROFFTIMEOUT 82
+#define SPI_SETSCREENREADER 71
+#define SPI_SETSCREENSAVEACTIVE 17
+#define SPI_SETSCREENSAVERRUNNING 97
+#define SPI_SETSCREENSAVETIMEOUT 15
+#define SPI_SETSERIALKEYS 63
+#define SPI_SETSHOWSOUNDS 57
+#define SPI_SETSOUNDSENTRY 65
+#define SPI_SETSTICKYKEYS 59
+#define SPI_SETTOGGLEKEYS 53
+#define SPI_SETWORKAREA 47
+#define SPIF_UPDATEINIFILE 1
+#define SPIF_SENDWININICHANGE 2
+#define SPIF_SENDCHANGE 2
+#define ATF_ONOFFFEEDBACK 2
+#define ATF_TIMEOUTON 1
+#define WM_APP 32768
+#define WM_ACTIVATE 6
+#define WM_ACTIVATEAPP 28
+/* FIXME/CHECK: Are WM_AFX{FIRST,LAST} valid for WINVER < 0x400? */
+#define WM_AFXFIRST 864
+#define WM_AFXLAST 895
+#define WM_ASKCBFORMATNAME 780
+#define WM_CANCELJOURNAL 75
+#define WM_CANCELMODE 31
+#define WM_CAPTURECHANGED 533
+#define WM_CHANGECBCHAIN 781
+#define WM_CHAR 258
+#define WM_CHARTOITEM 47
+#define WM_CHILDACTIVATE 34
+#define WM_CLEAR 771
+#define WM_CLOSE 16
+#define WM_COMMAND 273
+#define WM_COMMNOTIFY 68		/* obsolete */
+#define WM_COMPACTING 65
+#define WM_COMPAREITEM 57
+#define WM_CONTEXTMENU 123
+#define WM_COPY 769
+#define WM_COPYDATA 74
+#define WM_CREATE 1
+#define WM_CTLCOLORBTN 309
+#define WM_CTLCOLORDLG 310
+#define WM_CTLCOLOREDIT 307
+#define WM_CTLCOLORLISTBOX 308
+#define WM_CTLCOLORMSGBOX 306
+#define WM_CTLCOLORSCROLLBAR 311
+#define WM_CTLCOLORSTATIC 312
+#define WM_CUT 768
+#define WM_DEADCHAR 259
+#define WM_DELETEITEM 45
+#define WM_DESTROY 2
+#define WM_DESTROYCLIPBOARD 775
+#define WM_DEVICECHANGE 537
+#define WM_DEVMODECHANGE 27
+#define WM_DISPLAYCHANGE 126
+#define WM_DRAWCLIPBOARD 776
+#define WM_DRAWITEM 43
+#define WM_DROPFILES 563
+#define WM_ENABLE 10
+#define WM_ENDSESSION 22
+#define WM_ENTERIDLE 289
+#define WM_ENTERMENULOOP 529
+#define WM_ENTERSIZEMOVE 561
+#define WM_ERASEBKGND 20
+#define WM_EXITMENULOOP 530
+#define WM_EXITSIZEMOVE 562
+#define WM_FONTCHANGE 29
+#define WM_GETDLGCODE 135
+#define WM_GETFONT 49
+#define WM_GETHOTKEY 51
+#define WM_GETICON 127
+#define WM_GETMINMAXINFO 36
+#define WM_GETTEXT 13
+#define WM_GETTEXTLENGTH 14
+/* FIXME/CHECK: Are WM_HANDHEL{FIRST,LAST} valid for WINVER < 0x400? */
+#define WM_HANDHELDFIRST 856
+#define WM_HANDHELDLAST 863
+#define WM_HELP 83
+#define WM_HOTKEY 786
+#define WM_HSCROLL 276
+#define WM_HSCROLLCLIPBOARD 782
+#define WM_ICONERASEBKGND 39
+#define WM_INITDIALOG 272
+#define WM_INITMENU 278
+#define WM_INITMENUPOPUP 279
+#define WM_INPUTLANGCHANGE 81
+#define WM_INPUTLANGCHANGEREQUEST 80
+#define WM_KEYDOWN 256
+#define WM_KEYUP 257
+#define WM_KILLFOCUS 8
+#define WM_MDIACTIVATE 546
+#define WM_MDICASCADE 551
+#define WM_MDICREATE 544
+#define WM_MDIDESTROY 545
+#define WM_MDIGETACTIVE 553
+#define WM_MDIICONARRANGE 552
+#define WM_MDIMAXIMIZE 549
+#define WM_MDINEXT 548
+#define WM_MDIREFRESHMENU 564
+#define WM_MDIRESTORE 547
+#define WM_MDISETMENU 560
+#define WM_MDITILE 550
+#define WM_MEASUREITEM 44
+#define WM_MENUCHAR 288
+#define WM_MENUSELECT 287
+#define WM_NEXTMENU 531
+#define WM_MOVE 3
+#define WM_MOVING 534
+#define WM_NCACTIVATE 134
+#define WM_NCCALCSIZE 131
+#define WM_NCCREATE 129
+#define WM_NCDESTROY 130
+#define WM_NCHITTEST 132
+#define WM_NCLBUTTONDBLCLK 163
+#define WM_NCLBUTTONDOWN 161
+#define WM_NCLBUTTONUP 162
+#define WM_NCMBUTTONDBLCLK 169
+#define WM_NCMBUTTONDOWN 167
+#define WM_NCMBUTTONUP 168
+#define WM_NCMOUSEMOVE 160
+#define WM_NCPAINT 133
+#define WM_NCRBUTTONDBLCLK 166
+#define WM_NCRBUTTONDOWN 164
+#define WM_NCRBUTTONUP 165
+#define WM_NEXTDLGCTL 40
+#define WM_NEXTMENU 531
+#define WM_NOTIFY 78
+#define WM_NOTIFYFORMAT 85
+#define WM_NULL 0
+#define WM_PAINT 15
+#define WM_PAINTCLIPBOARD 777
+#define WM_PAINTICON 38
+#define WM_PALETTECHANGED 785
+#define WM_PALETTEISCHANGING 784
+#define WM_PARENTNOTIFY 528
+#define WM_PASTE 770
+#define WM_PENWINFIRST 896
+#define WM_PENWINLAST 911
+#define WM_POWER 72
+#define WM_POWERBROADCAST 536
+#define WM_PRINT 791
+#define WM_PRINTCLIENT 792
+#define WM_QUERYDRAGICON 55
+#define WM_QUERYENDSESSION 17
+#define WM_QUERYNEWPALETTE 783
+#define WM_QUERYOPEN 19
+#define WM_QUEUESYNC 35
+#define WM_QUIT 18
+#define WM_RENDERALLFORMATS 774
+#define WM_RENDERFORMAT 773
+#define WM_SETCURSOR 32
+#define WM_SETFOCUS 7
+#define WM_SETFONT 48
+#define WM_SETHOTKEY 50
+#define WM_SETICON 128
+#define WM_SETREDRAW 11
+#define WM_SETTEXT 12
+#define WM_SETTINGCHANGE 26
+#define WM_SHOWWINDOW 24
+#define WM_SIZE 5
+#define WM_SIZECLIPBOARD 779
+#define WM_SIZING 532
+#define WM_SPOOLERSTATUS 42
+#define WM_STYLECHANGED 125
+#define WM_STYLECHANGING 124
+#define WM_SYSCHAR 262
+#define WM_SYSCOLORCHANGE 21
+#define WM_SYSCOMMAND 274
+#define WM_SYSDEADCHAR 263
+#define WM_SYSKEYDOWN 260
+#define WM_SYSKEYUP 261
+#define WM_TCARD 82
+#define WM_TIMECHANGE 30
+#define WM_TIMER 275
+#define WM_UNDO 772
+#define WM_USER 1024
+#define WM_USERCHANGED 84
+#define WM_VKEYTOITEM 46
+#define WM_VSCROLL 277
+#define WM_VSCROLLCLIPBOARD 778
+#define WM_WINDOWPOSCHANGED 71
+#define WM_WINDOWPOSCHANGING 70
+#define WM_WININICHANGE 26
+#define WM_KEYFIRST 256
+#define WM_KEYLAST 264
+#define WM_SYNCPAINT  136
+#define WM_MOUSEACTIVATE 33
+#define WM_MOUSEMOVE 512
+#define WM_LBUTTONDOWN 513
+#define WM_LBUTTONUP 514
+#define WM_LBUTTONDBLCLK 515
+#define WM_RBUTTONDOWN 516
+#define WM_RBUTTONUP 517
+#define WM_RBUTTONDBLCLK 518
+#define WM_MBUTTONDOWN 519
+#define WM_MBUTTONUP 520
+#define WM_MBUTTONDBLCLK 521
+#define WM_MOUSEWHEEL 522
+#define WM_MOUSEFIRST 512
+#define WM_MOUSELAST 522
+#define WM_MOUSEHOVER	0x2A1
+#define WM_MOUSELEAVE	0x2A3
+#if(_WIN32_WINNT >= 0x0400)
+#define WHEEL_DELTA 120
+#define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD (wparam))
+#endif
+#define BM_CLICK 245
+#define BM_GETCHECK 240
+#define BM_GETIMAGE 246
+#define BM_GETSTATE 242
+#define BM_SETCHECK 241
+#define BM_SETIMAGE 247
+#define BM_SETSTATE 243
+#define BM_SETSTYLE 244
+#define BN_CLICKED 0
+#define BN_DBLCLK 5
+#define BN_DISABLE 4
+#define BN_DOUBLECLICKED 5
+#define BN_HILITE 2
+#define BN_KILLFOCUS 7
+#define BN_PAINT 1
+#define BN_PUSHED 2
+#define BN_SETFOCUS 6
+#define BN_UNHILITE 3
+#define BN_UNPUSHED 3
+#define CB_ADDSTRING 323
+#define CB_DELETESTRING 324
+#define CB_DIR 325
+#define CB_FINDSTRING 332
+#define CB_FINDSTRINGEXACT 344
+#define CB_GETCOUNT 326
+#define CB_GETCURSEL 327
+#define CB_GETDROPPEDCONTROLRECT 338
+#define CB_GETDROPPEDSTATE 343
+#define CB_GETDROPPEDWIDTH 351
+#define CB_GETEDITSEL 320
+#define CB_GETEXTENDEDUI 342
+#define CB_GETHORIZONTALEXTENT 349
+#define CB_GETITEMDATA 336
+#define CB_GETITEMHEIGHT 340
+#define CB_GETLBTEXT 328
+#define CB_GETLBTEXTLEN 329
+#define CB_GETLOCALE 346
+#define CB_GETTOPINDEX 347
+#define CB_INITSTORAGE 353
+#define CB_INSERTSTRING 330
+#define CB_LIMITTEXT 321
+#define CB_RESETCONTENT 331
+#define CB_SELECTSTRING 333
+#define CB_SETCURSEL 334
+#define CB_SETDROPPEDWIDTH 352
+#define CB_SETEDITSEL 322
+#define CB_SETEXTENDEDUI 341
+#define CB_SETHORIZONTALEXTENT 350
+#define CB_SETITEMDATA 337
+#define CB_SETITEMHEIGHT 339
+#define CB_SETLOCALE 345
+#define CB_SETTOPINDEX 348
+#define CB_SHOWDROPDOWN 335
+#define CBN_CLOSEUP 8
+#define CBN_DBLCLK 2
+#define CBN_DROPDOWN 7
+#define CBN_EDITCHANGE 5
+#define CBN_EDITUPDATE 6
+#define CBN_ERRSPACE (-1)
+#define CBN_KILLFOCUS 4
+#define CBN_SELCHANGE 1
+#define CBN_SELENDCANCEL 10
+#define CBN_SELENDOK 9
+#define CBN_SETFOCUS 3
+#define EM_CANUNDO 198
+#define EM_CHARFROMPOS 215
+#define EM_EMPTYUNDOBUFFER 205
+#define EM_FMTLINES 200
+#define EM_GETFIRSTVISIBLELINE 206
+#define EM_GETHANDLE 189
+#define EM_GETLIMITTEXT 213
+#define EM_GETLINE 196
+#define EM_GETLINECOUNT 186
+#define EM_GETMARGINS 212
+#define EM_GETMODIFY 184
+#define EM_GETPASSWORDCHAR 210
+#define EM_GETRECT 178
+#define EM_GETSEL 176
+#define EM_GETTHUMB 190
+#define EM_GETWORDBREAKPROC 209
+#define EM_LIMITTEXT 197
+#define EM_LINEFROMCHAR 201
+#define EM_LINEINDEX 187
+#define EM_LINELENGTH 193
+#define EM_LINESCROLL 182
+#define EM_POSFROMCHAR 214
+#define EM_REPLACESEL 194
+#define EM_SCROLL 181
+#define EM_SCROLLCARET 183
+#define EM_SETHANDLE 188
+#define EM_SETLIMITTEXT 197
+#define EM_SETMARGINS 211
+#define EM_SETMODIFY 185
+#define EM_SETPASSWORDCHAR 204
+#define EM_SETREADONLY 207
+#define EM_SETRECT 179
+#define EM_SETRECTNP 180
+#define EM_SETSEL 177
+#define EM_SETTABSTOPS 203
+#define EM_SETWORDBREAKPROC 208
+#define EM_UNDO 199
+#define EN_CHANGE 768
+#define EN_ERRSPACE 1280
+#define EN_HSCROLL 1537
+#define EN_KILLFOCUS 512
+#define EN_MAXTEXT 1281
+#define EN_SETFOCUS 256
+#define EN_UPDATE 1024
+#define EN_VSCROLL 1538
+#define LB_ADDFILE 406
+#define LB_ADDSTRING 384
+#define LB_DELETESTRING 386
+#define LB_DIR 397
+#define LB_FINDSTRING 399
+#define LB_FINDSTRINGEXACT 418
+#define LB_GETANCHORINDEX 413
+#define LB_GETCARETINDEX 415
+#define LB_GETCOUNT 395
+#define LB_GETCURSEL 392
+#define LB_GETHORIZONTALEXTENT 403
+#define LB_GETITEMDATA 409
+#define LB_GETITEMHEIGHT 417
+#define LB_GETITEMRECT 408
+#define LB_GETLOCALE 422
+#define LB_GETSEL 391
+#define LB_GETSELCOUNT 400
+#define LB_GETSELITEMS 401
+#define LB_GETTEXT 393
+#define LB_GETTEXTLEN 394
+#define LB_GETTOPINDEX 398
+#define LB_INITSTORAGE 424
+#define LB_INSERTSTRING 385
+#define LB_ITEMFROMPOINT 425
+#define LB_RESETCONTENT 388
+#define LB_SELECTSTRING 396
+#define LB_SELITEMRANGE 411
+#define LB_SELITEMRANGEEX 387
+#define LB_SETANCHORINDEX 412
+#define LB_SETCARETINDEX 414
+#define LB_SETCOLUMNWIDTH 405
+#define LB_SETCOUNT 423
+#define LB_SETCURSEL 390
+#define LB_SETHORIZONTALEXTENT 404
+#define LB_SETITEMDATA 410
+#define LB_SETITEMHEIGHT 416
+#define LB_SETLOCALE 421
+#define LB_SETSEL 389
+#define LB_SETTABSTOPS 402
+#define LB_SETTOPINDEX 407
+#define LBN_DBLCLK 2
+#define LBN_ERRSPACE (-2)
+#define LBN_KILLFOCUS 5
+#define LBN_SELCANCEL 3
+#define LBN_SELCHANGE 1
+#define LBN_SETFOCUS 4
+#define SBM_ENABLE_ARROWS 228
+#define SBM_GETPOS 225
+#define SBM_GETRANGE 227
+#define SBM_GETSCROLLINFO 234
+#define SBM_SETPOS 224
+#define SBM_SETRANGE 226
+#define SBM_SETRANGEREDRAW 230
+#define SBM_SETSCROLLINFO 233
+#define STM_GETICON 369
+#define STM_GETIMAGE 371
+#define STM_SETICON 368
+#define STM_SETIMAGE 370
+#define STN_CLICKED 0
+#define STN_DBLCLK 1
+#define STN_DISABLE 3
+#define STN_ENABLE 2
+#define DM_GETDEFID WM_USER
+#define DM_SETDEFID (WM_USER+1)
+#define DM_REPOSITION (WM_USER+2)
+#define PSM_PAGEINFO (WM_USER+100)
+#define PSM_SHEETINFO (WM_USER+101)
+#define PSI_SETACTIVE 1
+#define PSI_KILLACTIVE 2
+#define PSI_APPLY 3
+#define PSI_RESET 4
+#define PSI_HASHELP 5
+#define PSI_HELP 6
+#define PSI_CHANGED 1
+#define PSI_GUISTART 2
+#define PSI_REBOOT 3
+#define PSI_GETSIBLINGS 4
+#define DCX_WINDOW 1
+#define DCX_CACHE 2
+#define DCX_PARENTCLIP 32
+#define DCX_CLIPSIBLINGS 16
+#define DCX_CLIPCHILDREN 8
+#define DCX_NORESETATTRS 4
+#define DCX_LOCKWINDOWUPDATE 0x400
+#define DCX_EXCLUDERGN 64
+#define DCX_INTERSECTRGN 128
+#define DCX_VALIDATE 0x200000
+#define GMDI_GOINTOPOPUPS 2
+#define GMDI_USEDISABLED 1
+#define FKF_AVAILABLE 2
+#define FKF_CLICKON 64
+#define FKF_FILTERKEYSON 1
+#define FKF_HOTKEYACTIVE 4
+#define FKF_HOTKEYSOUND 16
+#define FKF_CONFIRMHOTKEY 8
+#define FKF_INDICATOR 32
+#define HCF_HIGHCONTRASTON 1
+#define HCF_AVAILABLE 2
+#define HCF_HOTKEYACTIVE 4
+#define HCF_CONFIRMHOTKEY 8
+#define HCF_HOTKEYSOUND 16
+#define HCF_INDICATOR 32
+#define HCF_HOTKEYAVAILABLE 64
+#define MKF_AVAILABLE 2
+#define MKF_CONFIRMHOTKEY 8
+#define MKF_HOTKEYACTIVE 4
+#define MKF_HOTKEYSOUND 16
+#define MKF_INDICATOR 32
+#define MKF_MOUSEKEYSON 1
+#define MKF_MODIFIERS 64
+#define MKF_REPLACENUMBERS 128
+#define SERKF_ACTIVE 8 /* May be obsolete. Not in recent MS docs. */
+#define SERKF_AVAILABLE 2
+#define SERKF_INDICATOR 4
+#define SERKF_SERIALKEYSON 1
+#define SSF_AVAILABLE 2
+#define SSF_SOUNDSENTRYON 1
+#define SSTF_BORDER 2
+#define SSTF_CHARS 1
+#define SSTF_DISPLAY 3
+#define SSTF_NONE 0
+#define SSGF_DISPLAY 3
+#define SSGF_NONE 0
+#define SSWF_CUSTOM 4
+#define SSWF_DISPLAY 3
+#define SSWF_NONE 0
+#define SSWF_TITLE 1
+#define SSWF_WINDOW 2
+#define SKF_AUDIBLEFEEDBACK 64
+#define SKF_AVAILABLE 2
+#define SKF_CONFIRMHOTKEY 8
+#define SKF_HOTKEYACTIVE 4
+#define SKF_HOTKEYSOUND 16
+#define SKF_INDICATOR 32
+#define SKF_STICKYKEYSON 1
+#define SKF_TRISTATE 128
+#define SKF_TWOKEYSOFF 256
+#define TKF_AVAILABLE 2
+#define TKF_CONFIRMHOTKEY 8
+#define TKF_HOTKEYACTIVE 4
+#define TKF_HOTKEYSOUND 16
+#define TKF_TOGGLEKEYSON 1
+#define MDITILE_SKIPDISABLED 2
+#define MDITILE_HORIZONTAL 1
+#define MDITILE_VERTICAL 0
+#define VK_LBUTTON	1
+#define VK_RBUTTON	2
+#define VK_CANCEL	3
+#define VK_MBUTTON	4
+#define VK_BACK	8
+#define VK_TAB	9
+#define VK_CLEAR	12
+#define VK_RETURN	13
+#define VK_KANA		15
+#define VK_SHIFT	16
+#define VK_CONTROL	17
+#define VK_MENU	18
+#define VK_PAUSE	19
+#define VK_CAPITAL	20
+#define VK_ESCAPE	0x1B
+#define VK_SPACE	32
+#define VK_PRIOR	33
+#define VK_NEXT	34
+#define VK_END	35
+#define VK_HOME	36
+#define VK_LEFT	37
+#define VK_UP	38
+#define VK_RIGHT	39
+#define VK_DOWN	40
+#define VK_SELECT	41
+#define VK_PRINT	42
+#define VK_EXECUTE	43
+#define VK_SNAPSHOT	44
+#define VK_INSERT	45
+#define VK_DELETE	46
+#define VK_HELP	47
+#define VK_LWIN	0x5B
+#define VK_RWIN	0x5C
+#define VK_APPS	0x5D
+#define VK_NUMPAD0	0x60
+#define VK_NUMPAD1	0x61
+#define VK_NUMPAD2	0x62
+#define VK_NUMPAD3	0x63
+#define VK_NUMPAD4	0x64
+#define VK_NUMPAD5	0x65
+#define VK_NUMPAD6	0x66
+#define VK_NUMPAD7	0x67
+#define VK_NUMPAD8	0x68
+#define VK_NUMPAD9	0x69
+#define VK_MULTIPLY	0x6A
+#define VK_ADD	0x6B
+#define VK_SEPARATOR	0x6C
+#define VK_SUBTRACT	0x6D
+#define VK_DECIMAL	0x6E
+#define VK_DIVIDE	0x6F
+#define VK_F1	0x70
+#define VK_F2	0x71
+#define VK_F3	0x72
+#define VK_F4	0x73
+#define VK_F5	0x74
+#define VK_F6	0x75
+#define VK_F7	0x76
+#define VK_F8	0x77
+#define VK_F9	0x78
+#define VK_F10	0x79
+#define VK_F11	0x7A
+#define VK_F12	0x7B
+#define VK_F13	0x7C
+#define VK_F14	0x7D
+#define VK_F15	0x7E
+#define VK_F16	0x7F
+#define VK_F17	0x80
+#define VK_F18	0x81
+#define VK_F19	0x82
+#define VK_F20	0x83
+#define VK_F21	0x84
+#define VK_F22	0x85
+#define VK_F23	0x86
+#define VK_F24	0x87
+#define VK_NUMLOCK	0x90
+#define VK_SCROLL	0x91
+#define VK_LSHIFT	0xA0
+#define VK_RSHIFT	0xA1
+#define VK_LCONTROL	0xA2
+#define VK_RCONTROL	0xA3
+#define VK_LMENU	0xA4
+#define VK_RMENU	0xA5
+#define VK_PROCESSKEY	0xE5
+#define VK_ATTN	0xF6
+#define VK_CRSEL	0xF7
+#define VK_EXSEL	0xF8
+#define VK_EREOF	0xF9
+#define VK_PLAY	0xFA
+#define VK_ZOOM	0xFB
+#define VK_NONAME	0xFC
+#define VK_PA1	0xFD
+#define VK_OEM_CLEAR	0xFE
+#define TME_HOVER	1
+#define TME_LEAVE	2
+#define TME_QUERY	0x40000000
+#define TME_CANCEL	0x80000000
+#define HOVER_DEFAULT	0xFFFFFFFF
+#define MK_LBUTTON	1
+#define MK_RBUTTON	2
+#define MK_SHIFT	4
+#define MK_CONTROL	8
+#define MK_MBUTTON	16
+#define TPM_CENTERALIGN 4
+#define TPM_LEFTALIGN 0
+#define TPM_RIGHTALIGN 8
+#define TPM_LEFTBUTTON 0
+#define TPM_RIGHTBUTTON 2
+#define TPM_HORIZONTAL 0
+#define TPM_VERTICAL 64
+#define TPM_TOPALIGN 0
+#define TPM_VCENTERALIGN 16
+#define TPM_BOTTOMALIGN 32
+#define TPM_NONOTIFY 128
+#define TPM_RETURNCMD 256
+#define HELP_COMMAND 0x102
+#define HELP_CONTENTS 3
+#define HELP_CONTEXT 1
+#define HELP_CONTEXTPOPUP 8
+#define HELP_FORCEFILE 9
+#define HELP_HELPONHELP 4
+#define HELP_INDEX 3
+#define HELP_KEY 0x101
+#define HELP_MULTIKEY 0x201
+#define HELP_PARTIALKEY 0x105
+#define HELP_QUIT 2
+#define HELP_SETCONTENTS 5
+#define HELP_SETINDEX 5
+#define HELP_CONTEXTMENU 0xa
+#define HELP_FINDER 0xb
+#define HELP_WM_HELP 0xc
+#define HELP_TCARD 0x8000
+#define HELP_TCARD_DATA 16
+#define HELP_TCARD_OTHER_CALLER 0x11
+#define IDH_NO_HELP	28440
+#define IDH_MISSING_CONTEXT	28441
+#define IDH_GENERIC_HELP_BUTTON	28442
+#define IDH_OK	28443
+#define IDH_CANCEL	28444
+#define IDH_HELP	28445
+#define LB_CTLCODE 0
+#define LB_OKAY 0
+#define LB_ERR (-1)
+#define LB_ERRSPACE (-2)
+#define CB_OKAY 0
+#define CB_ERR (-1)
+#define CB_ERRSPACE (-2)
+#define HIDE_WINDOW 0
+#define SHOW_OPENWINDOW 1
+#define SHOW_ICONWINDOW 2
+#define SHOW_FULLSCREEN 3
+#define SHOW_OPENNOACTIVATE 4
+#define SW_PARENTCLOSING 1
+#define SW_OTHERZOOM 2
+#define SW_PARENTOPENING 3
+#define SW_OTHERUNZOOM 4
+#define KF_EXTENDED 256
+#define KF_DLGMODE 2048
+#define KF_MENUMODE 4096
+#define KF_ALTDOWN 8192
+#define KF_REPEAT 16384
+#define KF_UP 32768
+#define WSF_VISIBLE 1
+#define PWR_OK 1
+#define PWR_FAIL (-1)
+#define PWR_SUSPENDREQUEST 1
+#define PWR_SUSPENDRESUME 2
+#define PWR_CRITICALRESUME 3
+#define NFR_ANSI 1
+#define NFR_UNICODE 2
+#define NF_QUERY 3
+#define NF_REQUERY 4
+#define MENULOOP_WINDOW 0
+#define MENULOOP_POPUP 1
+#define WMSZ_LEFT 1
+#define WMSZ_RIGHT 2
+#define WMSZ_TOP 3
+#define WMSZ_TOPLEFT 4
+#define WMSZ_TOPRIGHT 5
+#define WMSZ_BOTTOM 6
+#define WMSZ_BOTTOMLEFT 7
+#define WMSZ_BOTTOMRIGHT 8
+#define HTERROR (-2)
+#define HTTRANSPARENT (-1)
+#define HTNOWHERE 0
+#define HTCLIENT 1
+#define HTCAPTION 2
+#define HTSYSMENU 3
+#define HTGROWBOX 4
+#define HTSIZE 4
+#define HTMENU 5
+#define HTHSCROLL 6
+#define HTVSCROLL 7
+#define HTMINBUTTON 8
+#define HTMAXBUTTON 9
+#define HTREDUCE 8
+#define HTZOOM 9
+#define HTLEFT 10
+#define HTSIZEFIRST 10
+#define HTRIGHT 11
+#define HTTOP 12
+#define HTTOPLEFT 13
+#define HTTOPRIGHT 14
+#define HTBOTTOM 15
+#define HTBOTTOMLEFT 16
+#define HTBOTTOMRIGHT 17
+#define HTSIZELAST 17
+#define HTBORDER 18
+#define HTOBJECT 19
+#define HTCLOSE 20
+#define HTHELP 21
+#define MA_ACTIVATE 1
+#define MA_ACTIVATEANDEAT 2
+#define MA_NOACTIVATE 3
+#define MA_NOACTIVATEANDEAT 4
+#define SIZE_RESTORED 0
+#define SIZE_MINIMIZED 1
+#define SIZE_MAXIMIZED 2
+#define SIZE_MAXSHOW 3
+#define SIZE_MAXHIDE 4
+#define SIZENORMAL 0
+#define SIZEICONIC 1
+#define SIZEFULLSCREEN 2
+#define SIZEZOOMSHOW 3
+#define SIZEZOOMHIDE 4
+#define WVR_ALIGNTOP 16
+#define WVR_ALIGNLEFT 32
+#define WVR_ALIGNBOTTOM 64
+#define WVR_ALIGNRIGHT 128
+#define WVR_HREDRAW 256
+#define WVR_VREDRAW 512
+#define WVR_REDRAW (WVR_HREDRAW|WVR_VREDRAW)
+#define WVR_VALIDRECTS 1024
+#define PRF_CHECKVISIBLE 1
+#define PRF_NONCLIENT 2
+#define PRF_CLIENT 4
+#define PRF_ERASEBKGND 8
+#define PRF_CHILDREN 16
+#define PRF_OWNED 32
+#define IDANI_OPEN 1
+#define IDANI_CLOSE 2
+#define IDANI_CAPTION 3
+#define WPF_RESTORETOMAXIMIZED 2
+#define WPF_SETMINPOSITION 1
+#define ODT_MENU 1
+#define ODT_LISTBOX 2
+#define ODT_COMBOBOX 3
+#define ODT_BUTTON 4
+#define ODT_STATIC 5
+#define ODA_DRAWENTIRE 1
+#define ODA_SELECT 2
+#define ODA_FOCUS 4
+#define ODS_SELECTED 1
+#define ODS_GRAYED 2
+#define ODS_DISABLED 4
+#define ODS_CHECKED 8
+#define ODS_FOCUS 16
+#define ODS_DEFAULT 32
+#define ODS_COMBOBOXEDIT 4096
+#define IDHOT_SNAPWINDOW (-1)
+#define IDHOT_SNAPDESKTOP (-2)
+#define DBWF_LPARAMPOINTER 0x8000
+#define DLGWINDOWEXTRA 30
+#define MNC_IGNORE 0
+#define MNC_CLOSE 1
+#define MNC_EXECUTE 2
+#define MNC_SELECT 3
+#define DOF_EXECUTABLE 0x8001
+#define DOF_DOCUMENT 0x8002
+#define DOF_DIRECTORY 0x8003
+#define DOF_MULTIPLE 0x8004
+#define DOF_PROGMAN 1
+#define DOF_SHELLDATA 2
+#define DO_DROPFILE 0x454C4946
+#define DO_PRINTFILE 0x544E5250
+#define SW_SCROLLCHILDREN 1
+#define SW_INVALIDATE 2
+#define SW_ERASE 4
+#define SC_SIZE 0xF000
+#define SC_MOVE 0xF010
+#define SC_MINIMIZE 0xF020
+#define SC_ICON 0xf020
+#define SC_MAXIMIZE 0xF030
+#define SC_ZOOM 0xF030
+#define SC_NEXTWINDOW 0xF040
+#define SC_PREVWINDOW 0xF050
+#define SC_CLOSE 0xF060
+#define SC_VSCROLL 0xF070
+#define SC_HSCROLL 0xF080
+#define SC_MOUSEMENU 0xF090
+#define SC_KEYMENU 0xF100
+#define SC_ARRANGE 0xF110
+#define SC_RESTORE 0xF120
+#define SC_TASKLIST 0xF130
+#define SC_SCREENSAVE 0xF140
+#define SC_HOTKEY 0xF150
+#define SC_DEFAULT 0xF160
+#define SC_MONITORPOWER 0xF170
+#define SC_CONTEXTHELP 0xF180
+#define SC_SEPARATOR 0xF00F
+#define EC_LEFTMARGIN 1
+#define EC_RIGHTMARGIN 2
+#define EC_USEFONTINFO 0xffff
+#define DC_HASDEFID 0x534B
+#define DLGC_WANTARROWS 1
+#define DLGC_WANTTAB 2
+#define DLGC_WANTALLKEYS 4
+#define DLGC_WANTMESSAGE 4
+#define DLGC_HASSETSEL 8
+#define DLGC_DEFPUSHBUTTON 16
+#define DLGC_UNDEFPUSHBUTTON 32
+#define DLGC_RADIOBUTTON 64
+#define DLGC_WANTCHARS 128
+#define DLGC_STATIC 256
+#define DLGC_BUTTON 0x2000
+#define LB_CTLCODE 0
+#define WA_INACTIVE 0
+#define WA_ACTIVE 1
+#define WA_CLICKACTIVE 2
+#define ICON_SMALL 0
+#define ICON_BIG 1
+#define HBMMENU_CALLBACK ((HBITMAP) -1)
+#define HBMMENU_SYSTEM ((HBITMAP)1)
+#define HBMMENU_MBAR_RESTORE ((HBITMAP)2)
+#define HBMMENU_MBAR_MINIMIZE ((HBITMAP)3)
+#define HBMMENU_MBAR_CLOSE ((HBITMAP)5)
+#define HBMMENU_MBAR_CLOSE_D ((HBITMAP)6)
+#define HBMMENU_MBAR_MINIMIZE_D ((HBITMAP)7)
+#define HBMMENU_POPUP_CLOSE ((HBITMAP)8)
+#define HBMMENU_POPUP_RESTORE ((HBITMAP)9)
+#define HBMMENU_POPUP_MAXIMIZE ((HBITMAP)10)
+#define HBMMENU_POPUP_MINIMIZE ((HBITMAP)11)
+#define MOD_ALT 1
+#define MOD_CONTROL 2
+#define MOD_SHIFT 4
+#define MOD_WIN 8
+#define MOD_IGNORE_ALL_MODIFIER 1024
+#define MOD_ON_KEYUP  2048
+#define MOD_RIGHT 16384
+#define MOD_LEFT 32768
+#define LLKHF_ALTDOWN  0x00000020
+
+#ifndef RC_INVOKED
+typedef BOOL(CALLBACK *DLGPROC)(HWND,UINT,WPARAM,LPARAM);
+typedef VOID(CALLBACK *TIMERPROC)(HWND,UINT,UINT,DWORD);
+typedef BOOL(CALLBACK *GRAYSTRINGPROC)(HDC,LPARAM,int);
+typedef LRESULT(CALLBACK *HOOKPROC)(int,WPARAM,LPARAM);
+typedef BOOL(CALLBACK *PROPENUMPROCA)(HWND,LPCSTR,HANDLE);
+typedef BOOL(CALLBACK *PROPENUMPROCW)(HWND,LPCWSTR,HANDLE);
+typedef BOOL(CALLBACK *PROPENUMPROCEXA)(HWND,LPSTR,HANDLE,DWORD);
+typedef BOOL(CALLBACK *PROPENUMPROCEXW)(HWND,LPWSTR,HANDLE,DWORD);
+typedef int(CALLBACK *EDITWORDBREAKPROCA)(LPSTR,int,int,int);
+typedef int(CALLBACK *EDITWORDBREAKPROCW)(LPWSTR,int,int,int);
+typedef LRESULT(CALLBACK *WNDPROC)(HWND,UINT,WPARAM,LPARAM);
+typedef BOOL(CALLBACK *DRAWSTATEPROC)(HDC,LPARAM,WPARAM,int,int);
+typedef BOOL(CALLBACK *WNDENUMPROC)(HWND,LPARAM);
+typedef BOOL(CALLBACK *ENUMWINDOWSPROC)(HWND,LPARAM);
+typedef BOOL(CALLBACK* MONITORENUMPROC)(HMONITOR,HDC,LPRECT,LPARAM);
+typedef BOOL(CALLBACK *NAMEENUMPROCA)(LPSTR,LPARAM);
+typedef BOOL(CALLBACK *NAMEENUMPROCW)(LPWSTR,LPARAM);
+typedef NAMEENUMPROCA DESKTOPENUMPROCA;
+typedef NAMEENUMPROCW DESKTOPENUMPROCW;
+typedef NAMEENUMPROCA WINSTAENUMPROCA;
+typedef NAMEENUMPROCW WINSTAENUMPROCW;
+typedef void(CALLBACK *SENDASYNCPROC)(HWND,UINT,DWORD,LRESULT);
+DECLARE_HANDLE(HHOOK);
+DECLARE_HANDLE(HDWP);
+typedef struct tagACCEL {
+	BYTE fVirt;
+	WORD key;
+	WORD cmd;
+} ACCEL,*LPACCEL;
+typedef struct tagACCESSTIMEOUT {
+	UINT cbSize;
+	DWORD dwFlags;
+	DWORD iTimeOutMSec;
+} ACCESSTIMEOUT, *LPACCESSTIMEOUT;
+typedef struct tagANIMATIONINFO {
+	UINT cbSize;
+	int iMinAnimate;
+} ANIMATIONINFO,*LPANIMATIONINFO;
+typedef struct tagCREATESTRUCTA {
+	LPVOID	lpCreateParams;
+	HINSTANCE	hInstance;
+	HMENU	hMenu;
+	HWND	hwndParent;
+	int	cy;
+	int	cx;
+	int	y;
+	int	x;
+	LONG	style;
+	LPCSTR	lpszName;
+	LPCSTR	lpszClass;
+	DWORD	dwExStyle;
+} CREATESTRUCTA,*LPCREATESTRUCTA;
+typedef struct tagCREATESTRUCTW {
+	LPVOID	lpCreateParams;
+	HINSTANCE	hInstance;
+	HMENU	hMenu;
+	HWND	hwndParent;
+	int	cy;
+	int	cx;
+	int	y;
+	int	x;
+	LONG	style;
+	LPCWSTR	lpszName;
+	LPCWSTR	lpszClass;
+	DWORD	dwExStyle;
+} CREATESTRUCTW,*LPCREATESTRUCTW;
+typedef struct tagCBT_CREATEWNDA {
+	LPCREATESTRUCTA lpcs;
+	HWND	hwndInsertAfter;
+} CBT_CREATEWNDA, *LPCBT_CREATEWNDA;
+typedef struct tagCBT_CREATEWNDW {
+	LPCREATESTRUCTW lpcs;
+	HWND	hwndInsertAfter;
+} CBT_CREATEWNDW, *LPCBT_CREATEWNDW;
+typedef struct tagCBTACTIVATESTRUCT {
+	BOOL fMouse;
+	HWND hWndActive;
+} CBTACTIVATESTRUCT,*LPCBTACTIVATESTRUCT;
+typedef struct tagCLIENTCREATESTRUCT {
+	HANDLE	hWindowMenu;
+	UINT	idFirstChild;
+} CLIENTCREATESTRUCT,*LPCLIENTCREATESTRUCT;
+typedef struct tagCOMPAREITEMSTRUCT {
+	UINT	CtlType;
+	UINT	CtlID;
+	HWND	hwndItem;
+	UINT	itemID1;
+	DWORD	itemData1;
+	UINT	itemID2;
+	DWORD	itemData2;
+	DWORD	dwLocaleId;
+} COMPAREITEMSTRUCT,*LPCOMPAREITEMSTRUCT;
+typedef struct tagCOPYDATASTRUCT {
+	DWORD dwData;
+	DWORD cbData;
+	PVOID lpData;
+} COPYDATASTRUCT,*PCOPYDATASTRUCT;
+typedef struct tagCURSORSHAPE {
+	int xHotSpot;
+	int yHotSpot;
+	int cx;
+	int cy;
+	int cbWidth;
+    BYTE Planes;
+    BYTE BitsPixel;
+} CURSORSHAPE,*LPCURSORSHAPE;
+typedef struct tagCWPRETSTRUCT {
+	LRESULT lResult;
+	LPARAM lParam;
+	WPARAM wParam;
+	DWORD message;
+	HWND hwnd;
+} CWPRETSTRUCT;
+typedef struct tagCWPSTRUCT {
+	LPARAM lParam;
+	WPARAM wParam;
+	UINT message;
+	HWND hwnd;
+} CWPSTRUCT,*PCWPSTRUCT;
+typedef struct tagDEBUGHOOKINFO {
+	DWORD idThread;
+	DWORD idThreadInstaller;
+	LPARAM lParam;
+	WPARAM wParam;
+	int code;
+} DEBUGHOOKINFO,*PDEBUGHOOKINFO,*LPDEBUGHOOKINFO;
+typedef struct tagDELETEITEMSTRUCT {
+	UINT CtlType;
+	UINT CtlID;
+	UINT itemID;
+	HWND hwndItem;
+	UINT itemData;
+} DELETEITEMSTRUCT,*PDELETEITEMSTRUCT,*LPDELETEITEMSTRUCT;
+#pragma pack(push,2)
+typedef struct {
+	DWORD style;
+	DWORD dwExtendedStyle;
+	short x;
+	short y;
+	short cx;
+	short cy;
+	WORD id;
+} DLGITEMTEMPLATE,*LPDLGITEMTEMPLATE;
+typedef struct {
+	DWORD style;
+	DWORD dwExtendedStyle;
+	WORD cdit;
+	short x;
+	short y;
+	short cx;
+	short cy;
+} DLGTEMPLATE,*LPDLGTEMPLATE;
+typedef const DLGTEMPLATE *LPCDLGTEMPLATE;
+#pragma pack(pop)
+typedef struct tagDRAWITEMSTRUCT {
+	UINT CtlType;
+	UINT CtlID;
+	UINT itemID;
+	UINT itemAction;
+	UINT itemState;
+	HWND hwndItem;
+	HDC	hDC;
+	RECT rcItem;
+	DWORD itemData;
+} DRAWITEMSTRUCT,*LPDRAWITEMSTRUCT,*PDRAWITEMSTRUCT;
+typedef struct {
+	UINT cbSize;
+	int iTabLength;
+	int iLeftMargin;
+	int iRightMargin;
+	UINT uiLengthDrawn;
+} DRAWTEXTPARAMS,*LPDRAWTEXTPARAMS;
+typedef struct tagPAINTSTRUCT {
+	HDC	hdc;
+	BOOL fErase;
+	RECT rcPaint;
+	BOOL fRestore;
+	BOOL fIncUpdate;
+	BYTE rgbReserved[32];
+} PAINTSTRUCT,*LPPAINTSTRUCT;
+typedef struct tagMSG {
+	HWND hwnd;
+	UINT message;
+	WPARAM wParam;
+	LPARAM lParam;
+	DWORD time;
+	POINT pt;
+} MSG,*LPMSG,*PMSG;
+typedef struct _ICONINFO {
+	BOOL fIcon;
+	DWORD xHotspot;
+	DWORD yHotspot;
+	HBITMAP hbmMask;
+	HBITMAP hbmColor;
+} ICONINFO,*PICONINFO;
+typedef struct tagNMHDR {
+	HWND hwndFrom;
+	UINT idFrom;
+	UINT code;
+} NMHDR,*LPNMHDR;
+typedef struct _WNDCLASSA {
+	UINT style;
+	WNDPROC lpfnWndProc;
+	int cbClsExtra;
+	int cbWndExtra;
+	HANDLE hInstance;
+	HICON hIcon;
+	HCURSOR hCursor;
+	HBRUSH hbrBackground;
+	LPCSTR lpszMenuName;
+	LPCSTR lpszClassName;
+} WNDCLASSA,*LPWNDCLASSA,*PWNDCLASSA;
+typedef struct _WNDCLASSW {
+	UINT style;
+	WNDPROC lpfnWndProc;
+	int cbClsExtra;
+	int cbWndExtra;
+	HANDLE hInstance;
+	HICON hIcon;
+	HCURSOR hCursor;
+	HBRUSH hbrBackground;
+	LPCWSTR lpszMenuName;
+	LPCWSTR lpszClassName;
+} WNDCLASSW,*LPWNDCLASSW,*PWNDCLASSW;
+typedef struct _WNDCLASSEXA {
+	UINT cbSize;
+	UINT style;
+	WNDPROC lpfnWndProc;
+	int cbClsExtra;
+	int cbWndExtra;
+	HANDLE hInstance;
+	HICON hIcon;
+	HCURSOR hCursor;
+	HBRUSH hbrBackground;
+	LPCSTR lpszMenuName;
+	LPCSTR lpszClassName;
+	HICON hIconSm;
+} WNDCLASSEXA,*LPWNDCLASSEXA,*PWNDCLASSEXA;
+typedef struct _WNDCLASSEXW {
+	UINT cbSize;
+	UINT style;
+	WNDPROC lpfnWndProc;
+	int cbClsExtra;
+	int cbWndExtra;
+	HANDLE hInstance;
+	HICON hIcon;
+	HCURSOR hCursor;
+	HBRUSH hbrBackground;
+	LPCWSTR lpszMenuName;
+	LPCWSTR lpszClassName;
+	HICON hIconSm;
+} WNDCLASSEXW,*LPWNDCLASSEXW,*PWNDCLASSEXW;
+typedef struct tagMENUITEMINFOA {
+	UINT cbSize;
+	UINT fMask;
+	UINT fType;
+	UINT fState;
+	UINT wID;
+	HMENU hSubMenu;
+	HBITMAP hbmpChecked;
+	HBITMAP hbmpUnchecked;
+	DWORD dwItemData;
+	LPSTR dwTypeData;
+	UINT cch;
+#if (_WIN32_WINNT >= 0x0500)
+	HBITMAP hbmpItem;
+#endif
+} MENUITEMINFOA,*LPMENUITEMINFOA;
+typedef const MENUITEMINFOA *LPCMENUITEMINFOA;
+typedef struct tagMENUITEMINFOW {
+	UINT cbSize;
+	UINT fMask;
+	UINT fType;
+	UINT fState;
+	UINT wID;
+	HMENU hSubMenu;
+	HBITMAP hbmpChecked;
+	HBITMAP hbmpUnchecked;
+	DWORD dwItemData;
+	LPWSTR dwTypeData;
+	UINT cch;
+#if (_WIN32_WINNT >= 0x0500)
+	HBITMAP hbmpItem;
+#endif
+} MENUITEMINFOW,*LPMENUITEMINFOW;
+typedef const MENUITEMINFOW *LPCMENUITEMINFOW;
+typedef struct tagSCROLLINFO {
+	UINT cbSize;
+	UINT fMask;
+	int nMin;
+	int nMax;
+	UINT nPage;
+	int nPos;
+	int nTrackPos;
+} SCROLLINFO,*LPSCROLLINFO;
+typedef const SCROLLINFO *LPCSCROLLINFO;
+typedef struct _WINDOWPLACEMENT {
+	UINT length;
+	UINT flags;
+	UINT showCmd;
+	POINT ptMinPosition;
+	POINT ptMaxPosition;
+	RECT rcNormalPosition;
+} WINDOWPLACEMENT,*LPWINDOWPLACEMENT,*PWINDOWPLACEMENT;
+typedef struct {
+	WORD versionNumber;
+	WORD offset;
+} MENUITEMTEMPLATEHEADER;
+typedef struct {
+	WORD mtOption;
+	WORD mtID;
+	WCHAR mtString[1];
+} MENUITEMTEMPLATE;
+typedef void MENUTEMPLATE,MENUTEMPLATEA,MENUTEMPLATEW,*LPMENUTEMPLATEA,*LPMENUTEMPLATEW,*LPMENUTEMPLATE;
+typedef struct tagHELPINFO {
+	UINT cbSize;
+	int iContextType;
+	int iCtrlId;
+	HANDLE hItemHandle;
+	DWORD dwContextId;
+	POINT MousePos;
+} HELPINFO,*LPHELPINFO;
+typedef void(CALLBACK *MSGBOXCALLBACK)(LPHELPINFO);
+typedef struct {
+	UINT cbSize;
+	HWND hwndOwner;
+	HINSTANCE hInstance;
+	LPCSTR lpszText;
+	LPCSTR lpszCaption;
+	DWORD dwStyle;
+	LPCSTR lpszIcon;
+	DWORD dwContextHelpId;
+	MSGBOXCALLBACK lpfnMsgBoxCallback;
+	DWORD dwLanguageId;
+} MSGBOXPARAMSA,*PMSGBOXPARAMSA,*LPMSGBOXPARAMSA;
+typedef struct {
+	UINT cbSize;
+	HWND hwndOwner;
+	HINSTANCE hInstance;
+	LPCWSTR lpszText;
+	LPCWSTR lpszCaption;
+	DWORD dwStyle;
+	LPCWSTR lpszIcon;
+	DWORD dwContextHelpId;
+	MSGBOXCALLBACK lpfnMsgBoxCallback;
+	DWORD dwLanguageId;
+} MSGBOXPARAMSW,*PMSGBOXPARAMSW,*LPMSGBOXPARAMSW;
+typedef struct tagUSEROBJECTFLAGS {
+	BOOL fInherit;
+	BOOL fReserved;
+	DWORD dwFlags;
+} USEROBJECTFLAGS;
+typedef struct tagFILTERKEYS {
+	UINT cbSize;
+	DWORD dwFlags;
+	DWORD iWaitMSec;
+	DWORD iDelayMSec;
+	DWORD iRepeatMSec;
+	DWORD iBounceMSec;
+} FILTERKEYS;
+typedef struct tagHIGHCONTRASTA {
+	UINT cbSize;
+	DWORD dwFlags;
+	LPSTR lpszDefaultScheme;
+} HIGHCONTRASTA,*LPHIGHCONTRASTA;
+typedef struct tagHIGHCONTRASTW {
+	UINT cbSize;
+	DWORD dwFlags;
+	LPWSTR lpszDefaultScheme;
+} HIGHCONTRASTW,*LPHIGHCONTRASTW;
+typedef struct tagICONMETRICSA {
+	UINT cbSize;
+	int iHorzSpacing;
+	int iVertSpacing;
+	int iTitleWrap;
+	LOGFONTA lfFont;
+} ICONMETRICSA,*LPICONMETRICSA;
+typedef struct tagICONMETRICSW {
+	UINT cbSize;
+	int iHorzSpacing;
+	int iVertSpacing;
+	int iTitleWrap;
+	LOGFONTW lfFont;
+} ICONMETRICSW,*LPICONMETRICSW;
+typedef struct tagMINIMIZEDMETRICS {
+	UINT cbSize;
+	int iWidth;
+	int iHorzGap;
+	int iVertGap;
+	int iArrange;
+} MINIMIZEDMETRICS,*LPMINIMIZEDMETRICS;
+typedef struct tagMOUSEKEYS{
+	UINT cbSize;
+	DWORD dwFlags;
+	DWORD iMaxSpeed;
+	DWORD iTimeToMaxSpeed;
+	DWORD iCtrlSpeed;
+	DWORD dwReserved1;
+	DWORD dwReserved2;
+} MOUSEKEYS, *LPMOUSEKEYS;
+typedef struct tagNONCLIENTMETRICSA {
+	UINT cbSize;
+	int iBorderWidth;
+	int iScrollWidth;
+	int iScrollHeight;
+	int iCaptionWidth;
+	int iCaptionHeight;
+	LOGFONTA lfCaptionFont;
+	int iSmCaptionWidth;
+	int iSmCaptionHeight;
+	LOGFONTA lfSmCaptionFont;
+	int iMenuWidth;
+	int iMenuHeight;
+	LOGFONTA lfMenuFont;
+	LOGFONTA lfStatusFont;
+	LOGFONTA lfMessageFont;
+} NONCLIENTMETRICSA,*LPNONCLIENTMETRICSA;
+typedef struct tagNONCLIENTMETRICSW {
+	UINT cbSize;
+	int iBorderWidth;
+	int iScrollWidth;
+	int iScrollHeight;
+	int iCaptionWidth;
+	int iCaptionHeight;
+	LOGFONTW lfCaptionFont;
+	int iSmCaptionWidth;
+	int iSmCaptionHeight;
+	LOGFONTW lfSmCaptionFont;
+	int iMenuWidth;
+	int iMenuHeight;
+	LOGFONTW lfMenuFont;
+	LOGFONTW lfStatusFont;
+	LOGFONTW lfMessageFont;
+} NONCLIENTMETRICSW,*LPNONCLIENTMETRICSW;
+typedef struct tagSERIALKEYSA {
+	UINT cbSize;
+	DWORD dwFlags;
+	LPSTR lpszActivePort;
+	LPSTR lpszPort;
+	UINT iBaudRate;
+	UINT iPortState;
+	UINT iActive;
+} SERIALKEYSA,*LPSERIALKEYSA;
+typedef struct tagSERIALKEYSW {
+	UINT cbSize;
+	DWORD dwFlags;
+	LPWSTR lpszActivePort;
+	LPWSTR lpszPort;
+	UINT iBaudRate;
+	UINT iPortState;
+	UINT iActive;
+} SERIALKEYSW,*LPSERIALKEYSW;
+typedef struct tagSOUNDSENTRYA {
+	UINT cbSize;
+	DWORD dwFlags;
+	DWORD iFSTextEffect;
+	DWORD iFSTextEffectMSec;
+	DWORD iFSTextEffectColorBits;
+	DWORD iFSGrafEffect;
+	DWORD iFSGrafEffectMSec;
+	DWORD iFSGrafEffectColor;
+	DWORD iWindowsEffect;
+	DWORD iWindowsEffectMSec;
+	LPSTR lpszWindowsEffectDLL;
+	DWORD iWindowsEffectOrdinal;
+} SOUNDSENTRYA,*LPSOUNDSENTRYA;
+typedef struct tagSOUNDSENTRYW {
+	UINT cbSize;
+	DWORD dwFlags;
+	DWORD iFSTextEffect;
+	DWORD iFSTextEffectMSec;
+	DWORD iFSTextEffectColorBits;
+	DWORD iFSGrafEffect;
+	DWORD iFSGrafEffectMSec;
+	DWORD iFSGrafEffectColor;
+	DWORD iWindowsEffect;
+	DWORD iWindowsEffectMSec;
+	LPWSTR lpszWindowsEffectDLL;
+	DWORD iWindowsEffectOrdinal;
+} SOUNDSENTRYW,*LPSOUNDSENTRYW;
+typedef struct tagSTICKYKEYS {
+	DWORD cbSize;
+	DWORD dwFlags;
+} STICKYKEYS,*LPSTICKYKEYS;
+typedef struct tagTOGGLEKEYS {
+	DWORD cbSize;
+	DWORD dwFlags;
+} TOGGLEKEYS;
+typedef struct tagTRACKMOUSEEVENT {
+	DWORD cbSize;
+	DWORD dwFlags;
+	HWND  hwndTrack;
+	DWORD dwHoverTime;
+} TRACKMOUSEEVENT,*LPTRACKMOUSEEVENT;
+typedef struct tagTPMPARAMS {
+	UINT cbSize;
+	RECT rcExclude;
+} TPMPARAMS,*LPTPMPARAMS;
+typedef struct tagEVENTMSG {
+	UINT message;
+	UINT paramL;
+	UINT paramH;
+	DWORD time;
+	HWND hwnd;
+} EVENTMSG,*PEVENTMSGMSG,*LPEVENTMSGMSG, *PEVENTMSG, *LPEVENTMSG;
+typedef struct _WINDOWPOS {
+	HWND hwnd;
+	HWND hwndInsertAfter;
+	int x;
+	int y;
+	int cx;
+	int cy;
+	UINT flags;
+} WINDOWPOS,*PWINDOWPOS,*LPWINDOWPOS;
+typedef struct tagMDICREATESTRUCTA {
+	LPCSTR szClass;
+	LPCSTR szTitle;
+	HANDLE hOwner;
+	int x;
+	int y;
+	int cx;
+	int cy;
+	DWORD style;
+	LPARAM lParam;
+} MDICREATESTRUCTA,*LPMDICREATESTRUCTA;
+typedef struct tagMDICREATESTRUCTW {
+	LPCWSTR szClass;
+	LPCWSTR szTitle;
+	HANDLE hOwner;
+	int x;
+	int y;
+	int cx;
+	int cy;
+	DWORD style;
+	LPARAM lParam;
+} MDICREATESTRUCTW,*LPMDICREATESTRUCTW;
+typedef struct tagMINMAXINFO {
+	POINT ptReserved;
+	POINT ptMaxSize;
+	POINT ptMaxPosition;
+	POINT ptMinTrackSize;
+	POINT ptMaxTrackSize;
+} MINMAXINFO,*PMINMAXINFO,*LPMINMAXINFO;
+typedef struct tagMDINEXTMENU {
+	HMENU hmenuIn;
+	HMENU hmenuNext;
+	HWND hwndNext;
+} MDINEXTMENU,*PMDINEXTMENU,*LPMDINEXTMENU;
+typedef struct tagMEASUREITEMSTRUCT {
+	UINT CtlType;
+	UINT CtlID;
+	UINT itemID;
+	UINT itemWidth;
+	UINT itemHeight;
+	DWORD itemData;
+} MEASUREITEMSTRUCT,*PMEASUREITEMSTRUCT,*LPMEASUREITEMSTRUCT;
+typedef struct tagDROPSTRUCT {
+	HWND hwndSource;
+	HWND hwndSink;
+	DWORD wFmt;
+	DWORD dwData;
+	POINT ptDrop;
+	DWORD dwControlData;
+} DROPSTRUCT,*PDROPSTRUCT,*LPDROPSTRUCT;
+typedef DWORD HELPPOLY;
+typedef struct tagMULTIKEYHELPA {
+	DWORD mkSize;
+	CHAR mkKeylist;
+	CHAR szKeyphrase[1];
+} MULTIKEYHELPA,*PMULTIKEYHELPA,*LPMULTIKEYHELPA;
+typedef struct tagMULTIKEYHELPW {
+	DWORD mkSize;
+	WCHAR mkKeylist;
+	WCHAR szKeyphrase[1];
+} MULTIKEYHELPW,*PMULTIKEYHELPW,*LPMULTIKEYHELPW;
+typedef struct tagHELPWININFOA {
+	int wStructSize;
+	int x;
+	int y;
+	int dx;
+	int dy;
+	int wMax;
+	CHAR rgchMember[2];
+} HELPWININFOA,*PHELPWININFOA,*LPHELPWININFOA;
+typedef struct tagHELPWININFOW {
+	int wStructSize;
+	int x;
+	int y;
+	int dx;
+	int dy;
+	int wMax;
+	WCHAR rgchMember[2];
+} HELPWININFOW,*PHELPWININFOW,*LPHELPWININFOW;
+typedef struct tagSTYLESTRUCT {  
+	DWORD styleOld;
+	DWORD styleNew;
+} STYLESTRUCT,*LPSTYLESTRUCT;
+typedef struct tagALTTABINFO {
+	DWORD cbSize;
+	int   cItems;
+	int   cColumns;
+	int   cRows;
+	int   iColFocus;
+	int   iRowFocus;
+	int   cxItem;
+	int   cyItem;
+	POINT ptStart;
+} ALTTABINFO, *PALTTABINFO, *LPALTTABINFO;
+typedef struct tagCOMBOBOXINFO {
+	DWORD cbSize;
+	RECT rcItem;
+	RECT rcButton;
+	DWORD stateButton;
+	HWND hwndCombo;
+	HWND hwndItem;
+	HWND hwndList;
+} COMBOBOXINFO, *PCOMBOBOXINFO, *LPCOMBOBOXINFO;
+typedef struct tagCURSORINFO {
+	DWORD cbSize;
+	DWORD flags;
+	HCURSOR hCursor;
+	POINT ptScreenPos;
+} CURSORINFO,*PCURSORINFO,*LPCURSORINFO;
+typedef struct tagMENUBARINFO {
+	DWORD cbSize;
+	RECT  rcBar;
+	HMENU hMenu;
+	HWND  hwndMenu;
+	BOOL  fBarFocused:1;
+	BOOL  fFocused:1;
+} MENUBARINFO, *PMENUBARINFO;
+typedef struct tagMENUINFO {
+	DWORD cbSize;
+	DWORD fMask;
+	DWORD dwStyle;
+	UINT cyMax;
+	HBRUSH  hbrBack;
+	DWORD   dwContextHelpID;
+	ULONG_PTR dwMenuData;
+} MENUINFO, *LPMENUINFO;
+typedef MENUINFO CONST *LPCMENUINFO; 
+#define CCHILDREN_SCROLLBAR 5
+typedef struct tagSCROLLBARINFO {
+	DWORD cbSize;
+	RECT  rcScrollBar;
+	int   dxyLineButton;
+	int   xyThumbTop;
+	int   xyThumbBottom;
+	int   reserved;
+	DWORD rgstate[CCHILDREN_SCROLLBAR + 1];
+} SCROLLBARINFO, *PSCROLLBARINFO, *LPSCROLLBARINFO;
+#define CCHILDREN_TITLEBAR 5
+typedef struct tagTITLEBARINFO {
+	DWORD cbSize;
+	RECT  rcTitleBar;
+	DWORD rgstate[CCHILDREN_TITLEBAR + 1];
+} TITLEBARINFO, *PTITLEBARINFO, *LPTITLEBARINFO;
+typedef struct tagWINDOWINFO {
+	DWORD cbSize;
+	RECT  rcWindow;
+	RECT  rcClient;
+	DWORD dwStyle;
+	DWORD dwExStyle;
+	DWORD dwWindowStatus;
+	UINT  cxWindowBorders;
+	UINT  cyWindowBorders;
+	ATOM  atomWindowType;
+	WORD  wCreatorVersion;
+} WINDOWINFO, *PWINDOWINFO, *LPWINDOWINFO;
+typedef struct tagLASTINPUTINFO {
+	UINT cbSize;
+	DWORD dwTime;
+} LASTINPUTINFO, * PLASTINPUTINFO;
+typedef struct tagMONITORINFO {
+	DWORD cbSize;
+	RECT rcMonitor;
+	RECT rcWork;
+	DWORD dwFlags;
+} MONITORINFO,*LPMONITORINFO;
+typedef struct tagKBDLLHOOKSTRUCT {
+	DWORD vkCode;
+	DWORD scanCode;
+	DWORD flags;
+	DWORD time;
+	DWORD dwExtraInfo;
+} KBDLLHOOKSTRUCT, FAR *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
+
+
+#define AnsiToOem CharToOemA
+#define OemToAnsi OemToCharA
+#define AnsiToOemBuff CharToOemBuffA
+#define OemToAnsiBuff OemToCharBuffA
+#define AnsiUpper CharUpperA
+#define AnsiUpperBuff CharUpperBuffA
+#define AnsiLower CharLowerA
+#define AnsiLowerBuff CharLowerBuffA
+#define AnsiNext CharNextA
+#define AnsiPrev CharPrevA
+#define MAKELPARAM(l,h) ((LPARAM)MAKELONG(l,h))
+#define MAKEWPARAM(l,h) ((WPARAM)MAKELONG(l,h))
+#define MAKELRESULT(l,h) ((LRESULT)MAKELONG(l,h))
+#define POINTSTOPOINT(p,ps) { \
+  (p).x=LOWORD(*(DWORD *)&ps); \
+  (p).y=HIWORD(*(DWORD *)&ps); \
+}
+#define POINTTOPOINTS(p) ((POINTS)MAKELONG((p).x,(p).y))
+
+HKL WINAPI ActivateKeyboardLayout(HKL,UINT);
+BOOL WINAPI AdjustWindowRect(LPRECT,DWORD,BOOL);
+BOOL WINAPI AdjustWindowRectEx(LPRECT,DWORD,BOOL,DWORD);
+BOOL WINAPI AnyPopup(void);
+BOOL WINAPI AppendMenuA(HMENU,UINT,UINT,LPCSTR);
+BOOL WINAPI AppendMenuW(HMENU,UINT,UINT,LPCWSTR);
+UINT WINAPI ArrangeIconicWindows(HWND);
+BOOL WINAPI AttachThreadInput(DWORD,DWORD,BOOL);
+HDWP WINAPI BeginDeferWindowPos(int);
+HDC WINAPI BeginPaint(HWND,LPPAINTSTRUCT);
+BOOL WINAPI BringWindowToTop(HWND);
+long WINAPI BroadcastSystemMessage(DWORD,LPDWORD,UINT,WPARAM,LPARAM);
+BOOL WINAPI CallMsgFilter(PMSG,int);
+LRESULT WINAPI CallNextHookEx(HHOOK,int,WPARAM,LPARAM);
+LRESULT WINAPI CallWindowProcA(WNDPROC,HWND,UINT,WPARAM,LPARAM);
+LRESULT WINAPI CallWindowProcW(WNDPROC,HWND,UINT,WPARAM,LPARAM);
+WORD WINAPI CascadeWindows(HWND,UINT,LPCRECT,UINT,const HWND*);
+BOOL WINAPI ChangeClipboardChain(HWND,HWND);
+LONG WINAPI ChangeDisplaySettingsA(PDEVMODEA,DWORD);
+LONG WINAPI ChangeDisplaySettingsW(PDEVMODEW,DWORD);
+BOOL WINAPI ChangeMenuA(HMENU,UINT,LPCSTR,UINT,UINT);
+BOOL WINAPI ChangeMenuW(HMENU,UINT,LPCWSTR,UINT,UINT);
+LPSTR WINAPI CharLowerA(LPSTR);
+LPWSTR WINAPI CharLowerW(LPWSTR);
+DWORD WINAPI CharLowerBuffA(LPSTR,DWORD);
+DWORD WINAPI CharLowerBuffW(LPWSTR,DWORD);
+LPSTR WINAPI CharNextA(LPCSTR);
+LPWSTR WINAPI CharNextW(LPCWSTR);
+LPSTR WINAPI CharNextExA(WORD,LPCSTR,DWORD);
+LPWSTR WINAPI CharNextExW(WORD,LPCWSTR,DWORD);
+LPSTR WINAPI CharPrevA(LPCSTR,LPCSTR);
+LPWSTR WINAPI CharPrevW(LPCWSTR,LPCWSTR);
+LPSTR WINAPI CharPrevExA(WORD,LPCSTR,LPCSTR,DWORD);
+LPWSTR WINAPI CharPrevExW(WORD,LPCWSTR,LPCWSTR,DWORD);
+BOOL WINAPI CharToOemA(LPCSTR,LPSTR);
+BOOL WINAPI CharToOemW(LPCWSTR,LPSTR);
+BOOL WINAPI CharToOemBuffA(LPCSTR,LPSTR,DWORD);
+BOOL WINAPI CharToOemBuffW(LPCWSTR,LPSTR,DWORD);
+LPSTR WINAPI CharUpperA(LPSTR);
+LPWSTR WINAPI CharUpperW(LPWSTR);
+DWORD WINAPI CharUpperBuffA(LPSTR,DWORD);
+DWORD WINAPI CharUpperBuffW(LPWSTR,DWORD);
+BOOL WINAPI CheckDlgButton(HWND,int,UINT);
+DWORD WINAPI CheckMenuItem(HMENU,UINT,UINT);
+BOOL WINAPI CheckMenuRadioItem(HMENU,UINT,UINT,UINT,UINT);
+BOOL WINAPI CheckRadioButton(HWND,int,int,int);
+HWND WINAPI ChildWindowFromPoint(HWND,POINT);
+HWND WINAPI ChildWindowFromPointEx(HWND,POINT,UINT);
+BOOL WINAPI ClientToScreen(HWND,LPPOINT);
+BOOL WINAPI ClipCursor(LPCRECT);
+BOOL WINAPI CloseClipboard(void);
+BOOL WINAPI CloseDesktop(HDESK);
+BOOL WINAPI CloseWindow(HWND);
+BOOL WINAPI CloseWindowStation(HWINSTA);
+int WINAPI CopyAcceleratorTableA(HACCEL,LPACCEL,int);
+int WINAPI CopyAcceleratorTableW(HACCEL,LPACCEL,int);
+HCURSOR WINAPI CopyCursor(HCURSOR);
+HICON WINAPI CopyIcon(HICON);
+HANDLE WINAPI CopyImage(HANDLE,UINT,int,int,UINT);
+BOOL WINAPI CopyRect(LPRECT,LPCRECT);
+int WINAPI CountClipboardFormats(void);
+HACCEL WINAPI CreateAcceleratorTableA(LPACCEL,int);
+HACCEL WINAPI CreateAcceleratorTableW(LPACCEL,int);
+BOOL WINAPI CreateCaret(HWND,HBITMAP,int,int);
+HCURSOR WINAPI CreateCursor(HINSTANCE,int,int,int,int,PCVOID,PCVOID);
+HDESK WINAPI CreateDesktopA(LPSTR,LPSTR,LPDEVMODEA,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+HDESK WINAPI CreateDesktopW(LPWSTR,LPWSTR,LPDEVMODEW,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+#define CreateDialogA(h,n,w,f) CreateDialogParamA(h,n,w,f,0)
+#define CreateDialogW(h,n,w,f) CreateDialogParamW(h,n,w,f,0)
+#define CreateDialogIndirectA(h,t,w,f) CreateDialogIndirectParamA(h,t,w,f,0)
+#define CreateDialogIndirectW(h,t,w,f) CreateDialogIndirectParamW(h,t,w,f,0)
+HWND WINAPI CreateDialogIndirectParamA(HINSTANCE,LPCDLGTEMPLATE,HWND,DLGPROC,LPARAM);
+HWND WINAPI CreateDialogIndirectParamW(HINSTANCE,LPCDLGTEMPLATE,HWND,DLGPROC,LPARAM);
+HWND WINAPI CreateDialogParamA(HINSTANCE,LPCSTR,HWND,DLGPROC,LPARAM);
+HWND WINAPI CreateDialogParamW(HINSTANCE,LPCWSTR,HWND,DLGPROC,LPARAM);
+HICON WINAPI CreateIcon(HINSTANCE,int,int,BYTE,BYTE,const BYTE*,const BYTE*);
+HICON WINAPI CreateIconFromResource(PBYTE,DWORD,BOOL,DWORD);
+HICON WINAPI CreateIconFromResourceEx(PBYTE,DWORD,BOOL,DWORD,int,int,UINT);
+HICON WINAPI CreateIconIndirect(PICONINFO);
+HWND WINAPI CreateMDIWindowA(LPSTR,LPSTR,DWORD,int,int,int,int,HWND,HINSTANCE,LPARAM);
+HWND WINAPI CreateMDIWindowW(LPWSTR,LPWSTR,DWORD,int,int,int,int,HWND,HINSTANCE,LPARAM);
+HMENU WINAPI CreateMenu(void);
+HMENU WINAPI CreatePopupMenu(void);
+#define CreateWindowA(a,b,c,d,e,f,g,h,i,j,k) CreateWindowExA(0,a,b,c,d,e,f,g,h,i,j,k)
+#define CreateWindowW(a,b,c,d,e,f,g,h,i,j,k) CreateWindowExW(0,a,b,c,d,e,f,g,h,i,j,k)
+HWND WINAPI CreateWindowExA(DWORD,LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
+HWND WINAPI CreateWindowExW(DWORD,LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
+HWINSTA WINAPI CreateWindowStationA(LPSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+HWINSTA WINAPI CreateWindowStationW(LPWSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES);
+LRESULT WINAPI DefDlgProcA(HWND,UINT,WPARAM,LPARAM);
+LRESULT WINAPI DefDlgProcW(HWND,UINT,WPARAM,LPARAM);
+HDWP WINAPI DeferWindowPos(HDWP,HWND,HWND,int,int,int,int,UINT);
+LRESULT WINAPI DefFrameProcA(HWND,HWND,UINT,WPARAM,LPARAM);
+LRESULT WINAPI DefFrameProcW(HWND,HWND,UINT,WPARAM,LPARAM);
+#define DefHookProc(c,p,lp,h) CallNextHookEx((HHOOK)*h,c,p,lp)
+LRESULT WINAPI DefMDIChildProcA(HWND,UINT,WPARAM,LPARAM);
+LRESULT WINAPI DefMDIChildProcW(HWND,UINT,WPARAM,LPARAM);
+LRESULT WINAPI DefWindowProcA(HWND,UINT,WPARAM,LPARAM);
+LRESULT WINAPI DefWindowProcW(HWND,UINT,WPARAM,LPARAM);
+BOOL WINAPI DeleteMenu(HMENU,UINT,UINT);
+BOOL WINAPI DestroyAcceleratorTable(HACCEL);
+BOOL WINAPI DestroyCaret(void);
+BOOL WINAPI DestroyCursor(HCURSOR);
+BOOL WINAPI DestroyIcon(HICON);
+BOOL WINAPI DestroyMenu(HMENU);
+BOOL WINAPI DestroyWindow(HWND);
+#define DialogBoxA(i,t,p,f) DialogBoxParamA(i,t,p,f,0)
+#define DialogBoxW(i,t,p,f) DialogBoxParamW(i,t,p,f,0)
+#define DialogBoxIndirectA(i,t,p,f) DialogBoxIndirectParamA(i,t,p,f,0)
+#define DialogBoxIndirectW(i,t,p,f) DialogBoxIndirectParamW(i,t,p,f,0)
+int WINAPI DialogBoxIndirectParamA(HINSTANCE,LPCDLGTEMPLATE,HWND,DLGPROC,LPARAM);
+int WINAPI DialogBoxIndirectParamW(HINSTANCE,LPCDLGTEMPLATE,HWND,DLGPROC,LPARAM);
+int WINAPI DialogBoxParamA(HINSTANCE,LPCSTR,HWND,DLGPROC,LPARAM);
+int WINAPI DialogBoxParamW(HINSTANCE,LPCWSTR,HWND,DLGPROC,LPARAM);
+LONG WINAPI DispatchMessageA(const MSG*);
+LONG WINAPI DispatchMessageW(const MSG*);
+int WINAPI DlgDirListA(HWND,LPSTR,int,int,UINT);
+int WINAPI DlgDirListW(HWND,LPWSTR,int,int,UINT);
+int WINAPI DlgDirListComboBoxA(HWND,LPSTR,int,int,UINT);
+int WINAPI DlgDirListComboBoxW(HWND,LPWSTR,int,int,UINT);
+BOOL WINAPI DlgDirSelectComboBoxExA(HWND,LPSTR,int,int);
+BOOL WINAPI DlgDirSelectComboBoxExW(HWND,LPWSTR,int,int);
+BOOL WINAPI DlgDirSelectExA(HWND,LPSTR,int,int);
+BOOL WINAPI DlgDirSelectExW(HWND,LPWSTR,int,int);
+BOOL WINAPI DragDetect(HWND,POINT);
+DWORD WINAPI DragObject(HWND,HWND,UINT,DWORD,HCURSOR);
+BOOL WINAPI DrawAnimatedRects(HWND,int,LPCRECT,LPCRECT);
+BOOL WINAPI DrawCaption(HWND,HDC,LPCRECT,UINT);
+BOOL WINAPI DrawEdge(HDC,LPRECT,UINT,UINT);
+BOOL WINAPI DrawFocusRect(HDC,LPCRECT);
+BOOL WINAPI DrawFrameControl(HDC,LPRECT,UINT,UINT);
+BOOL WINAPI DrawIcon(HDC,int,int,HICON);
+BOOL WINAPI DrawIconEx(HDC,int,int,HICON,int,int,UINT,HBRUSH,UINT);
+BOOL WINAPI DrawMenuBar(HWND);
+BOOL WINAPI DrawStateA(HDC,HBRUSH,DRAWSTATEPROC,LPARAM,WPARAM,int,int,int,int,UINT);
+BOOL WINAPI DrawStateW(HDC,HBRUSH,DRAWSTATEPROC,LPARAM,WPARAM,int,int,int,int,UINT);
+int WINAPI DrawTextA(HDC,LPCSTR,int,LPRECT,UINT);
+int WINAPI DrawTextW(HDC,LPCWSTR,int,LPRECT,UINT);
+int WINAPI DrawTextExA(HDC,LPSTR,int,LPRECT,UINT,LPDRAWTEXTPARAMS);
+int WINAPI DrawTextExW(HDC,LPWSTR,int,LPRECT,UINT,LPDRAWTEXTPARAMS);
+BOOL WINAPI EmptyClipboard(void);
+BOOL WINAPI EnableMenuItem(HMENU,UINT,UINT);
+BOOL WINAPI EnableScrollBar(HWND,UINT,UINT);
+BOOL WINAPI EnableWindow(HWND,BOOL);
+BOOL WINAPI EndDeferWindowPos(HDWP);
+BOOL WINAPI EndDialog(HWND,int);
+BOOL WINAPI EndMenu(VOID);
+BOOL WINAPI EndPaint(HWND,const PAINTSTRUCT*);
+BOOL WINAPI EnumChildWindows(HWND,ENUMWINDOWSPROC,LPARAM);
+UINT WINAPI EnumClipboardFormats(UINT);
+BOOL WINAPI EnumDesktopsA(HWINSTA,DESKTOPENUMPROCA,LPARAM);
+BOOL WINAPI EnumDesktopsW(HWINSTA,DESKTOPENUMPROCW,LPARAM);
+BOOL WINAPI EnumDesktopWindows(HDESK,ENUMWINDOWSPROC,LPARAM);
+BOOL WINAPI EnumDisplayMonitors(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
+BOOL WINAPI EnumDisplaySettingsA(LPCSTR,DWORD,PDEVMODEA);
+BOOL WINAPI EnumDisplaySettingsW(LPCWSTR,DWORD,PDEVMODEW);
+int WINAPI EnumPropsA(HWND,PROPENUMPROCA);
+int WINAPI EnumPropsW(HWND,PROPENUMPROCW);
+int WINAPI EnumPropsExA(HWND,PROPENUMPROCEXA,LPARAM);
+int WINAPI EnumPropsExW(HWND,PROPENUMPROCEXW,LPARAM);
+#define EnumTaskWindows(h,f,p) EnumThreadWindows((DWORD)h,f,p)
+BOOL WINAPI EnumThreadWindows(DWORD,WNDENUMPROC,LPARAM);
+BOOL WINAPI EnumWindows(WNDENUMPROC,LPARAM);
+BOOL WINAPI EnumWindowStationsA(WINSTAENUMPROCA,LPARAM);
+BOOL WINAPI EnumWindowStationsW(WINSTAENUMPROCW,LPARAM);
+BOOL WINAPI EqualRect(LPCRECT,LPCRECT);
+#define ExitWindows(r,c) ExitWindowsEx(EWX_LOGOFF,0)
+BOOL WINAPI ExitWindowsEx(UINT,DWORD);
+HWND WINAPI FindWindowA(LPCSTR,LPCSTR);
+HWND WINAPI FindWindowExA(HWND,HWND,LPCSTR,LPCSTR);
+HWND WINAPI FindWindowExW(HWND,HWND,LPCWSTR,LPCWSTR);
+HWND WINAPI FindWindowW(LPCWSTR,LPCWSTR);
+BOOL WINAPI FlashWindow(HWND,BOOL);
+int WINAPI FrameRect(HDC,LPCRECT,HBRUSH);
+BOOL WINAPI FrameRgn(HDC,HRGN,HBRUSH,int,int);
+HWND WINAPI GetActiveWindow(void);
+SHORT WINAPI GetAsyncKeyState(int);
+HWND WINAPI GetCapture(void);
+UINT WINAPI GetCaretBlinkTime(void);
+BOOL WINAPI GetCaretPos(LPPOINT);
+BOOL WINAPI GetClassInfoA(HINSTANCE,LPCSTR,PWNDCLASSA);
+BOOL WINAPI GetClassInfoExA(HINSTANCE,LPCSTR,PWNDCLASSEXA);
+BOOL WINAPI GetClassInfoW(HINSTANCE,LPCWSTR,PWNDCLASSW);
+BOOL WINAPI GetClassInfoExW(HINSTANCE,LPCWSTR,PWNDCLASSEXW);
+DWORD WINAPI GetClassLongA(HWND,int);
+DWORD WINAPI GetClassLongW(HWND,int);
+int WINAPI GetClassNameA(HWND,LPSTR,int);
+int WINAPI GetClassNameW(HWND,LPWSTR,int);
+WORD WINAPI GetClassWord(HWND,int);
+BOOL WINAPI GetClientRect(HWND,LPRECT);
+HANDLE WINAPI GetClipboardData(UINT);
+int WINAPI GetClipboardFormatNameA(UINT,LPSTR,int);
+int WINAPI GetClipboardFormatNameW(UINT,LPWSTR,int);
+HWND WINAPI GetClipboardOwner(void);
+HWND WINAPI GetClipboardViewer(void);
+BOOL WINAPI GetClipCursor(LPRECT);
+BOOL WINAPI GetCursorPos(LPPOINT);
+HDC WINAPI GetDC(HWND);
+HDC WINAPI GetDCEx(HWND,HRGN,DWORD);
+HWND WINAPI GetDesktopWindow(void);
+long WINAPI GetDialogBaseUnits(void);
+int WINAPI GetDlgCtrlID(HWND);
+HWND WINAPI GetDlgItem(HWND,int);
+UINT WINAPI GetDlgItemInt(HWND,int,PBOOL,BOOL);
+UINT WINAPI GetDlgItemTextA(HWND,int,LPSTR,int);
+UINT WINAPI GetDlgItemTextW(HWND,int,LPWSTR,int);
+UINT WINAPI GetDoubleClickTime(void);
+HWND WINAPI GetFocus(void);
+HWND WINAPI GetForegroundWindow(void);
+BOOL WINAPI GetIconInfo(HICON,PICONINFO);
+BOOL WINAPI GetInputState(void);
+UINT WINAPI GetKBCodePage(void);
+HKL WINAPI GetKeyboardLayout(DWORD);
+int WINAPI GetKeyboardLayoutList(int,HKL*);
+BOOL WINAPI GetKeyboardLayoutNameA(LPSTR);
+BOOL WINAPI GetKeyboardLayoutNameW(LPWSTR);
+BOOL WINAPI GetKeyboardState(PBYTE);
+int WINAPI GetKeyboardType(int);
+int WINAPI GetKeyNameTextA(LONG,LPSTR,int);
+int WINAPI GetKeyNameTextW(LONG,LPWSTR,int);
+SHORT WINAPI GetKeyState(int);
+HWND WINAPI GetLastActivePopup(HWND);
+DWORD WINAPI GetLastError(void);
+HMENU WINAPI GetMenu(HWND);
+LONG WINAPI GetMenuCheckMarkDimensions(void);
+DWORD WINAPI GetMenuContextHelpId(HMENU);
+UINT WINAPI GetMenuDefaultItem(HMENU,UINT,UINT);
+int WINAPI GetMenuItemCount(HMENU);
+UINT WINAPI GetMenuItemID(HMENU,int);
+BOOL WINAPI GetMenuItemInfoA(HMENU,UINT,BOOL,LPMENUITEMINFOA);
+BOOL WINAPI GetMenuItemInfoW(HMENU,UINT,BOOL,LPMENUITEMINFOW);
+BOOL WINAPI GetMenuItemRect(HWND,HMENU,UINT,LPRECT);
+UINT WINAPI GetMenuState(HMENU,UINT,UINT);
+int WINAPI GetMenuStringA(HMENU,UINT,LPSTR,int,UINT);
+int WINAPI GetMenuStringW(HMENU,UINT,LPWSTR,int,UINT);
+BOOL WINAPI GetMessageA(LPMSG,HWND,UINT,UINT);
+BOOL WINAPI GetMessageW(LPMSG,HWND,UINT,UINT);
+LONG WINAPI GetMessageExtraInfo(void);
+DWORD WINAPI GetMessagePos(void);
+LONG WINAPI GetMessageTime(void);
+HWND WINAPI GetNextDlgGroupItem(HWND,HWND,BOOL);
+HWND WINAPI GetNextDlgTabItem(HWND,HWND,BOOL);
+#define GetNextWindow(h,c) GetWindow(h,c)
+HWND WINAPI GetOpenClipboardWindow(void);
+HWND WINAPI GetParent(HWND);
+int WINAPI GetPriorityClipboardFormat(UINT*,int);
+HANDLE WINAPI GetPropA(HWND,LPCSTR);
+HANDLE WINAPI GetPropW(HWND,LPCWSTR);
+DWORD WINAPI GetQueueStatus(UINT);
+BOOL WINAPI GetScrollInfo(HWND,int,LPSCROLLINFO);
+int WINAPI GetScrollPos(HWND,int);
+BOOL WINAPI GetScrollRange(HWND,int,LPINT,LPINT);
+HMENU WINAPI GetSubMenu(HMENU,int);
+DWORD WINAPI GetSysColor(int);
+HBRUSH WINAPI GetSysColorBrush(int);
+#define GetSysModalWindow() (NULL)
+HMENU WINAPI GetSystemMenu(HWND,BOOL);
+int WINAPI GetSystemMetrics(int);
+DWORD WINAPI GetTabbedTextExtentA(HDC,LPCSTR,int,int,LPINT);
+DWORD WINAPI GetTabbedTextExtentW(HDC,LPCWSTR,int,int,LPINT);
+LONG WINAPI GetWindowLongA(HWND,int);
+LONG WINAPI GetWindowLongW(HWND,int);
+#ifdef _WIN64
+LONG_PTR WINAPI GetWindowLongPtrA(HWND,int);
+LONG_PTR WINAPI GetWindowLongPtrW(HWND,int);
+#else
+#define GetWindowLongPtrA GetWindowLongA
+#define GetWindowLongPtrW GetWindowLongW
+#endif
+HDESK WINAPI GetThreadDesktop(DWORD);
+HWND WINAPI GetTopWindow(HWND);
+BOOL WINAPI GetUpdateRect(HWND,LPRECT,BOOL);
+int WINAPI GetUpdateRgn(HWND,HRGN,BOOL);
+BOOL WINAPI GetUserObjectInformationA(HANDLE,int,PVOID,DWORD,PDWORD);
+BOOL WINAPI GetUserObjectInformationW(HANDLE,int,PVOID,DWORD,PDWORD);
+BOOL WINAPI GetUserObjectSecurity(HANDLE,PSECURITY_INFORMATION,PSECURITY_DESCRIPTOR,DWORD,PDWORD);
+HWND WINAPI GetWindow(HWND,UINT);
+DWORD WINAPI GetWindowContextHelpId(HWND);
+HDC WINAPI GetWindowDC(HWND);
+BOOL WINAPI GetWindowExtEx(HDC,LPSIZE);
+BOOL WINAPI GetWindowPlacement(HWND,WINDOWPLACEMENT*);
+BOOL WINAPI GetWindowRect(HWND,LPRECT);
+int WINAPI GetWindowRgn(HWND,HRGN);
+#define GetWindowTask(hWnd) ((HANDLE)GetWindowThreadProcessId(hWnd, NULL))
+int WINAPI GetWindowTextA(HWND,LPSTR,int);
+int WINAPI GetWindowTextLengthA(HWND);
+int WINAPI GetWindowTextLengthW(HWND);
+int WINAPI GetWindowTextW(HWND,LPWSTR,int);
+WORD WINAPI GetWindowWord(HWND,int);
+BOOL WINAPI GetAltTabInfoA(HWND,int,PALTTABINFO,LPSTR,UINT);
+BOOL WINAPI GetAltTabInfoW(HWND,int,PALTTABINFO,LPWSTR,UINT);
+BOOL WINAPI GetComboBoxInfo(HWND,PCOMBOBOXINFO);
+BOOL WINAPI GetCursorInfo(PCURSORINFO);
+BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO);
+DWORD WINAPI GetListBoxInfo(HWND);
+BOOL WINAPI GetMenuBarInfo(HWND,LONG,LONG,PMENUBARINFO);
+BOOL WINAPI GetMenuInfo(HMENU,LPMENUINFO);
+BOOL WINAPI GetScrollBarInfo(HWND,LONG,PSCROLLBARINFO);
+BOOL WINAPI GetTitleBarInfo(HWND,PTITLEBARINFO);
+BOOL WINAPI GetWindowInfo(HWND,PWINDOWINFO);
+BOOL WINAPI GetMonitorInfoA(HMONITOR,LPMONITORINFO);
+BOOL WINAPI GetMonitorInfoW(HMONITOR,LPMONITORINFO);
+UINT WINAPI GetWindowModuleFileNameA(HWND,LPSTR,UINT);
+UINT WINAPI GetWindowModuleFileNameW(HWND,LPWSTR,UINT);
+BOOL WINAPI GrayStringA(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM,int,int,int,int,int);
+BOOL WINAPI GrayStringW(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM,int,int,int,int,int);
+BOOL WINAPI HideCaret(HWND);
+BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT);
+BOOL WINAPI InflateRect(LPRECT,int,int);
+BOOL WINAPI InSendMessage(VOID);
+BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR);
+BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR);
+BOOL WINAPI InsertMenuItemA(HMENU,UINT,BOOL,LPCMENUITEMINFOA);
+BOOL WINAPI InsertMenuItemW(HMENU,UINT,BOOL,LPCMENUITEMINFOW);
+BOOL WINAPI IntersectRect(LPRECT,LPCRECT,LPCRECT);
+BOOL WINAPI InvalidateRect(HWND,LPCRECT,BOOL);
+BOOL WINAPI InvalidateRgn(HWND,HRGN,BOOL);
+BOOL WINAPI InvertRect(HDC,LPCRECT);
+BOOL WINAPI IsCharAlphaA(CHAR ch);
+BOOL WINAPI IsCharAlphaNumericA(CHAR);
+BOOL WINAPI IsCharAlphaNumericW(WCHAR);
+BOOL WINAPI IsCharAlphaW(WCHAR);
+BOOL WINAPI IsCharLowerA(CHAR);
+BOOL WINAPI IsCharLowerW(WCHAR);
+BOOL WINAPI IsCharUpperA(CHAR);
+BOOL WINAPI IsCharUpperW(WCHAR);
+BOOL WINAPI IsChild(HWND,HWND);
+BOOL WINAPI IsClipboardFormatAvailable(UINT);
+BOOL WINAPI IsDialogMessageA(HWND,LPMSG);
+BOOL WINAPI IsDialogMessageW(HWND,LPMSG);
+UINT WINAPI IsDlgButtonChecked(HWND,int);
+BOOL WINAPI IsIconic(HWND);
+BOOL WINAPI IsMenu(HMENU);
+BOOL WINAPI IsRectEmpty(LPCRECT);
+BOOL WINAPI IsWindow(HWND);
+BOOL WINAPI IsWindowEnabled(HWND);
+BOOL WINAPI IsWindowUnicode(HWND);
+BOOL WINAPI IsWindowVisible(HWND);
+BOOL WINAPI IsZoomed(HWND);
+VOID WINAPI keybd_event(BYTE,BYTE,DWORD,DWORD);
+BOOL WINAPI KillTimer(HWND,UINT);
+HACCEL WINAPI LoadAcceleratorsA(HINSTANCE,LPCSTR);
+HACCEL WINAPI LoadAcceleratorsW(HINSTANCE,LPCWSTR);
+HBITMAP WINAPI LoadBitmapA(HINSTANCE,LPCSTR);
+HBITMAP WINAPI LoadBitmapW(HINSTANCE,LPCWSTR);
+HCURSOR WINAPI LoadCursorA(HINSTANCE,LPCSTR);
+HCURSOR WINAPI LoadCursorFromFileA(LPCSTR);
+HCURSOR WINAPI LoadCursorFromFileW(LPCWSTR);
+HCURSOR WINAPI LoadCursorW(HINSTANCE,LPCWSTR);
+HICON WINAPI LoadIconA(HINSTANCE,LPCSTR);
+HICON WINAPI LoadIconW(HINSTANCE,LPCWSTR);
+HANDLE WINAPI LoadImageA(HINSTANCE,LPCSTR,UINT,int,int,UINT);
+HANDLE WINAPI LoadImageW(HINSTANCE,LPCWSTR,UINT,int,int,UINT);
+HKL WINAPI LoadKeyboardLayoutA(LPCSTR,UINT);
+HKL WINAPI LoadKeyboardLayoutW(LPCWSTR,UINT);
+HMENU WINAPI LoadMenuA(HINSTANCE,LPCSTR);
+HMENU WINAPI LoadMenuIndirectA(const MENUTEMPLATE*);
+HMENU WINAPI LoadMenuIndirectW(const MENUTEMPLATE*);
+HMENU WINAPI LoadMenuW(HINSTANCE,LPCWSTR);
+int WINAPI LoadStringA(HINSTANCE,UINT,LPSTR,int);
+int WINAPI LoadStringW(HINSTANCE,UINT,LPWSTR,int);
+BOOL WINAPI LockWindowUpdate(HWND);
+int WINAPI LookupIconIdFromDirectory(PBYTE,BOOL);
+int WINAPI LookupIconIdFromDirectoryEx(PBYTE,BOOL,int,int,UINT);
+BOOL WINAPI MapDialogRect(HWND,LPRECT);
+UINT WINAPI MapVirtualKeyA(UINT,UINT);
+UINT WINAPI MapVirtualKeyExA(UINT,UINT,HKL);
+UINT WINAPI MapVirtualKeyExW(UINT,UINT,HKL);
+UINT WINAPI MapVirtualKeyW(UINT,UINT);
+int WINAPI MapWindowPoints(HWND,HWND,LPPOINT,UINT);
+int WINAPI MenuItemFromPoint(HWND,HMENU,POINT);
+BOOL WINAPI MessageBeep(UINT);
+int WINAPI MessageBoxA(HWND,LPCSTR,LPCSTR,UINT);
+int WINAPI MessageBoxW(HWND,LPCWSTR,LPCWSTR,UINT);
+int WINAPI MessageBoxExA(HWND,LPCSTR,LPCSTR,UINT,WORD);
+int WINAPI MessageBoxExW(HWND,LPCWSTR,LPCWSTR,UINT,WORD);
+int WINAPI MessageBoxIndirectA(LPMSGBOXPARAMSA);
+int WINAPI MessageBoxIndirectW(LPMSGBOXPARAMSW);
+BOOL WINAPI ModifyMenuA(HMENU,UINT,UINT,UINT,LPCSTR);
+BOOL WINAPI ModifyMenuW(HMENU,UINT,UINT,UINT,LPCWSTR);
+void WINAPI mouse_event(DWORD,DWORD,DWORD,DWORD,DWORD);
+BOOL WINAPI MoveWindow(HWND,int,int,int,int,BOOL);
+DWORD WINAPI MsgWaitForMultipleObjects(DWORD,LPHANDLE,BOOL,DWORD,DWORD);
+DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD,LPHANDLE,DWORD,DWORD,DWORD);
+DWORD WINAPI OemKeyScan(WORD);
+BOOL WINAPI OemToCharA(LPCSTR,LPSTR);
+BOOL WINAPI OemToCharBuffA(LPCSTR,LPSTR,DWORD);
+BOOL WINAPI OemToCharBuffW(LPCSTR,LPWSTR,DWORD);
+BOOL WINAPI OemToCharW(LPCSTR,LPWSTR);
+BOOL WINAPI OffsetRect(LPRECT,int,int);
+BOOL WINAPI OpenClipboard(HWND);
+HDESK WINAPI OpenDesktopA(LPSTR,DWORD,BOOL,DWORD);
+HDESK WINAPI OpenDesktopW(LPWSTR,DWORD,BOOL,DWORD);
+BOOL WINAPI OpenIcon(HWND);
+HDESK WINAPI OpenInputDesktop(DWORD,BOOL,DWORD);
+HWINSTA WINAPI OpenWindowStationA(LPSTR,BOOL,DWORD);
+HWINSTA WINAPI OpenWindowStationW(LPWSTR,BOOL,DWORD);
+BOOL WINAPI PaintDesktop(HDC);
+BOOL WINAPI PeekMessageA(LPMSG,HWND,UINT,UINT,UINT);
+BOOL WINAPI PeekMessageW(LPMSG,HWND,UINT,UINT,UINT);
+#define PostAppMessageA(t,m,w,l) PostThreadMessageA((DWORD)t,m,w,l)
+#define PostAppMessageW(t,m,w,l) PostThreadMessageW((DWORD)t,m,w,l)
+BOOL WINAPI PostMessageA(HWND,UINT,WPARAM,LPARAM);
+BOOL WINAPI PostMessageW(HWND,UINT,WPARAM,LPARAM);
+void WINAPI PostQuitMessage(int);
+BOOL WINAPI PostThreadMessageA(DWORD,UINT,WPARAM,LPARAM);
+BOOL WINAPI PostThreadMessageW(DWORD,UINT,WPARAM,LPARAM);
+BOOL WINAPI PtInRect(LPCRECT,POINT);
+BOOL WINAPI RedrawWindow(HWND,LPCRECT,HRGN,UINT);
+ATOM WINAPI RegisterClassA(const WNDCLASSA*);
+ATOM WINAPI RegisterClassW(const WNDCLASSW*);
+ATOM WINAPI RegisterClassExA(const WNDCLASSEXA*);
+ATOM WINAPI RegisterClassExW(const WNDCLASSEXW*);
+UINT WINAPI RegisterClipboardFormatA(LPCSTR);
+UINT WINAPI RegisterClipboardFormatW(LPCWSTR);
+BOOL WINAPI RegisterHotKey(HWND,int,UINT,UINT);
+UINT WINAPI RegisterWindowMessageA(LPCSTR);
+UINT WINAPI RegisterWindowMessageW(LPCWSTR);
+BOOL WINAPI ReleaseCapture(void);
+int WINAPI ReleaseDC(HWND,HDC);
+BOOL WINAPI RemoveMenu(HMENU,UINT,UINT);
+HANDLE WINAPI RemovePropA(HWND,LPCSTR);
+HANDLE WINAPI RemovePropW(HWND,LPCWSTR);
+BOOL WINAPI ReplyMessage(LRESULT);
+BOOL WINAPI ScreenToClient(HWND,LPPOINT);
+BOOL WINAPI ScrollDC(HDC,int,int,LPCRECT,LPCRECT,HRGN,LPRECT);
+BOOL WINAPI ScrollWindow(HWND,int,int,LPCRECT,LPCRECT);
+int WINAPI ScrollWindowEx(HWND,int,int,LPCRECT,LPCRECT,HRGN,LPRECT,UINT);
+LONG WINAPI SendDlgItemMessageA(HWND,int,UINT,WPARAM,LPARAM);
+LONG WINAPI SendDlgItemMessageW(HWND,int,UINT,WPARAM,LPARAM);
+LRESULT WINAPI SendMessageA(HWND,UINT,WPARAM,LPARAM);
+BOOL WINAPI SendMessageCallbackA(HWND,UINT,WPARAM,LPARAM,SENDASYNCPROC,DWORD);
+BOOL WINAPI SendMessageCallbackW(HWND,UINT,WPARAM,LPARAM,SENDASYNCPROC,DWORD);
+LRESULT WINAPI SendMessageTimeoutA(HWND,UINT,WPARAM,LPARAM,UINT,UINT,PDWORD);
+LRESULT WINAPI SendMessageTimeoutW(HWND,UINT,WPARAM,LPARAM,UINT,UINT,PDWORD);
+LRESULT WINAPI SendMessageW(HWND,UINT,WPARAM,LPARAM);
+BOOL WINAPI SendNotifyMessageA(HWND,UINT,WPARAM,LPARAM);
+BOOL WINAPI SendNotifyMessageW(HWND,UINT,WPARAM,LPARAM);
+HWND WINAPI SetActiveWindow(HWND);
+HWND WINAPI SetCapture(HWND hWnd);
+BOOL WINAPI SetCaretBlinkTime(UINT);
+BOOL WINAPI SetCaretPos(int,int);
+DWORD WINAPI SetClassLongA(HWND,int,LONG);
+DWORD WINAPI SetClassLongW(HWND,int,LONG);
+WORD WINAPI SetClassWord(HWND,int,WORD);
+HANDLE WINAPI SetClipboardData(UINT,HANDLE);
+HWND WINAPI SetClipboardViewer(HWND);
+HCURSOR WINAPI SetCursor(HCURSOR);
+BOOL WINAPI SetCursorPos(int,int);
+VOID WINAPI SetDebugErrorLevel(DWORD);
+BOOL WINAPI SetDlgItemInt(HWND,int,UINT,BOOL);
+BOOL WINAPI SetDlgItemTextA(HWND,int,LPCSTR);
+BOOL WINAPI SetDlgItemTextW(HWND,int,LPCWSTR);
+BOOL WINAPI SetDoubleClickTime(UINT);
+HWND WINAPI SetFocus(HWND);
+BOOL WINAPI SetForegroundWindow(HWND);
+BOOL WINAPI SetKeyboardState(PBYTE);
+BOOL WINAPI SetMenu(HWND,HMENU);
+BOOL WINAPI SetMenuContextHelpId(HMENU,DWORD);
+BOOL WINAPI SetMenuDefaultItem(HMENU,UINT,UINT);
+BOOL WINAPI SetMenuInfo(HMENU,LPCMENUINFO);
+BOOL WINAPI SetMenuItemBitmaps(HMENU,UINT,UINT,HBITMAP,HBITMAP);
+BOOL WINAPI SetMenuItemInfoA(HMENU,UINT,BOOL,LPCMENUITEMINFOA);
+BOOL WINAPI SetMenuItemInfoW( HMENU,UINT,BOOL,LPCMENUITEMINFOW);
+LPARAM WINAPI SetMessageExtraInfo(LPARAM);
+BOOL WINAPI SetMessageQueue(int);
+HWND WINAPI SetParent(HWND,HWND);
+BOOL WINAPI SetProcessWindowStation(HWINSTA);
+BOOL WINAPI SetPropA(HWND,LPCSTR,HANDLE);
+BOOL WINAPI SetPropW(HWND,LPCWSTR,HANDLE);
+BOOL WINAPI SetRect(LPRECT,int,int,int,int);
+BOOL WINAPI SetRectEmpty(LPRECT);
+int WINAPI SetScrollInfo(HWND,int,LPCSCROLLINFO,BOOL);
+int WINAPI SetScrollPos(HWND,int,int,BOOL);
+BOOL WINAPI SetScrollRange(HWND,int,int,int,BOOL);
+BOOL WINAPI SetSysColors(int,const INT *,const COLORREF *);
+#define SetSysModalWindow(h) (NULL)
+BOOL WINAPI SetSystemCursor(HCURSOR,DWORD);
+BOOL WINAPI SetThreadDesktop(HDESK);
+UINT WINAPI SetTimer(HWND,UINT,UINT,TIMERPROC);
+BOOL WINAPI SetUserObjectInformationA(HANDLE,int,PVOID,DWORD);
+BOOL WINAPI SetUserObjectInformationW(HANDLE,int,PVOID,DWORD);
+BOOL WINAPI SetUserObjectSecurity(HANDLE,PSECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
+BOOL WINAPI SetWindowContextHelpId(HWND,DWORD);
+LONG WINAPI SetWindowLongA(HWND,int,LONG);
+LONG WINAPI SetWindowLongW(HWND,int,LONG);
+#ifdef _WIN64
+LONG_PTR WINAPI SetWindowLongPtrA(HWND,int,LONG_PTR);
+LONG_PTR WINAPI SetWindowLongPtrW(HWND,int,LONG_PTR);
+#else 
+#define SetWindowLongPtrA SetWindowLongA
+#define SetWindowLongPtrW SetWindowLongW
+#endif
+BOOL WINAPI SetWindowPlacement(HWND hWnd,const WINDOWPLACEMENT*);
+BOOL WINAPI SetWindowPos(HWND,HWND,int,int,int,int,UINT);
+int WINAPI SetWindowRgn(HWND,HRGN,BOOL);
+HOOKPROC WINAPI SetWindowsHookA(int,HOOKPROC);
+HHOOK WINAPI SetWindowsHookExA(int,HOOKPROC,HINSTANCE,DWORD);
+HHOOK WINAPI SetWindowsHookExW(int,HOOKPROC,HINSTANCE,DWORD);
+BOOL WINAPI SetWindowTextA(HWND,LPCSTR);
+BOOL WINAPI SetWindowTextW(HWND,LPCWSTR);
+WORD WINAPI SetWindowWord(HWND,int,WORD);
+BOOL WINAPI ShowCaret(HWND);
+int WINAPI ShowCursor(BOOL);
+BOOL WINAPI ShowOwnedPopups(HWND,BOOL);
+BOOL WINAPI ShowScrollBar(HWND,int,BOOL);
+BOOL WINAPI ShowWindow(HWND,int);
+BOOL WINAPI ShowWindowAsync(HWND,int);
+BOOL WINAPI SubtractRect(LPRECT,LPCRECT,LPCRECT);
+BOOL WINAPI SwapMouseButton(BOOL);
+BOOL WINAPI SwitchDesktop(HDESK);
+BOOL WINAPI SystemParametersInfoA(UINT,UINT,PVOID,UINT);
+BOOL WINAPI SystemParametersInfoW(UINT,UINT,PVOID,UINT);
+LONG WINAPI TabbedTextOutA(HDC,int,int,LPCSTR,int,int,LPINT,int);
+LONG WINAPI TabbedTextOutW(HDC,int,int,LPCWSTR,int,int,LPINT,int);
+WORD WINAPI TileWindows(HWND,UINT,LPCRECT,UINT,const HWND *);
+int WINAPI ToAscii(UINT,UINT,PBYTE,LPWORD,UINT);
+int WINAPI ToAsciiEx(UINT,UINT,PBYTE,LPWORD,UINT,HKL);
+int WINAPI ToUnicode(UINT,UINT,PBYTE,LPWSTR,int,UINT);
+int WINAPI ToUnicodeEx(UINT,UINT,PBYTE,LPWSTR,int,UINT,HKL);
+BOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT);
+BOOL WINAPI TrackPopupMenu(HMENU,UINT,int,int,int,HWND,LPCRECT);
+BOOL WINAPI TrackPopupMenuEx(HMENU,UINT,int,int,HWND,LPTPMPARAMS);
+int WINAPI TranslateAcceleratorA(HWND,HACCEL,LPMSG);
+int WINAPI TranslateAcceleratorW(HWND,HACCEL,LPMSG);
+BOOL WINAPI TranslateMDISysAccel(HWND,LPMSG);
+BOOL WINAPI TranslateMessage(const MSG*);
+BOOL WINAPI UnhookWindowsHook(int,HOOKPROC);
+BOOL WINAPI UnhookWindowsHookEx(HHOOK);
+BOOL WINAPI UnionRect(LPRECT,LPCRECT,LPCRECT);
+BOOL WINAPI UnloadKeyboardLayout(HKL);
+BOOL WINAPI UnregisterClassA(LPCSTR,HINSTANCE);
+BOOL WINAPI UnregisterClassW(LPCWSTR,HINSTANCE);
+BOOL WINAPI UnregisterHotKey(HWND,int);
+BOOL WINAPI UpdateWindow(HWND);
+BOOL WINAPI ValidateRect(HWND,LPCRECT);
+BOOL WINAPI ValidateRgn(HWND,HRGN);
+SHORT WINAPI VkKeyScanA(CHAR);
+SHORT WINAPI VkKeyScanExA(CHAR,HKL);
+SHORT WINAPI VkKeyScanExW(WCHAR,HKL);
+SHORT WINAPI VkKeyScanW(WCHAR);
+DWORD WINAPI WaitForInputIdle(HANDLE,DWORD);
+BOOL WINAPI WaitMessage(void);
+HWND WINAPI WindowFromDC(HDC hDC);
+HWND WINAPI WindowFromPoint(POINT);
+UINT WINAPI WinExec(LPCSTR,UINT);
+BOOL WINAPI WinHelpA(HWND,LPCSTR,UINT,DWORD);
+BOOL WINAPI WinHelpW(HWND,LPCWSTR,UINT,DWORD);
+int WINAPIV wsprintfA(LPSTR,LPCSTR,...);
+int WINAPIV wsprintfW(LPWSTR,LPCWSTR,...);
+int WINAPI wvsprintfA(LPSTR,LPCSTR,va_list arglist);
+int WINAPI wvsprintfW(LPWSTR,LPCWSTR,va_list arglist);
+
+#ifdef UNICODE
+#define EDITWORDBREAKPROC EDITWORDBREAKPROCW
+#define PROPENUMPROC PROPENUMPROCW
+#define PROPENUMPROCEX PROPENUMPROCEXW
+#define DEKSTOPENUMPROC DEKSTOPENUMPROCW
+#define WINSTAENUMPROC WINSTAENUMPROCW
+#define PROPENUMPROC PROPENUMPROCW
+#define PROPENUMPROCEX PROPENUMPROCEXW
+#define MAKEINTRESOURCE MAKEINTRESOURCEW
+typedef WNDCLASSW WNDCLASS,*LPWNDCLASS,*PWNDCLASS;
+typedef WNDCLASSEXW WNDCLASSEX,*LPWNDCLASSEX,*PWNDCLASSEX;
+typedef MENUITEMINFOW MENUITEMINFO,*LPMENUITEMINFO;
+typedef LPCMENUITEMINFOW LPCMENUITEMINFO;
+typedef MSGBOXPARAMSW MSGBOXPARAMS,*PMSGBOXPARAMS,*LPMSGBOXPARAMS;
+typedef HIGHCONTRASTW HIGHCONTRAST,*LPHIGHCONTRAST;
+typedef ICONMETRICSW ICONMETRICS,*LPICONMETRICS;
+typedef NONCLIENTMETRICSW NONCLIENTMETRICS,*LPNONCLIENTMETRICS;
+typedef SERIALKEYSW SERIALKEYS,*LPSERIALKEYS;
+typedef SOUNDSENTRYW SOUNDSENTRY,*LPSOUNDSENTRY;
+typedef CREATESTRUCTW CREATESTRUCT, *LPCREATESTRUCT;
+typedef CBT_CREATEWNDW CBT_CREATEWND, *LPCBT_CREATEWND;
+typedef MDICREATESTRUCTW MDICREATESTRUCT,*LPMDICREATESTRUCT;
+typedef MULTIKEYHELPW MULTIKEYHELP,*PMULTIKEYHELP,*LPMULTIKEYHELP;
+#define AppendMenu AppendMenuW
+#define CallWindowProc CallWindowProcW
+#define ChangeDisplaySettings ChangeDisplaySettingsW
+#define ChangeMenu ChangeMenuW
+#define CharLower CharLowerW
+#define CharLowerBuff CharLowerBuffW
+#define CharNext CharNextW
+#define CharNextEx CharNextExW
+#define CharPrev CharPrevW
+#define CharPrevEx CharPrevExW
+#define CharToOem CharToOemW
+#define CharToOemBuff CharToOemBuffW
+#define CharUpper CharUpperW
+#define CharUpperBuff CharUpperBuffW
+#define CopyAcceleratorTable CopyAcceleratorTableW
+#define CreateAcceleratorTable CreateAcceleratorTableW
+#define CreateDesktop CreateDesktopW
+#define CreateDialog CreateDialogW
+#define CreateDialogIndirect CreateDialogIndirectW
+#define CreateDialogIndirectParam CreateDialogIndirectParamW
+#define CreateDialogParam CreateDialogParamW
+#define CreateMDIWindow CreateMDIWindowW
+#define CreateWindow CreateWindowW
+#define CreateWindowEx CreateWindowExW
+#define CreateWindowStation CreateWindowStationW
+#define DefDlgProc DefDlgProcW
+#define DefFrameProc DefFrameProcW
+#define DefMDIChildProc DefMDIChildProcW
+#define DefWindowProc DefWindowProcW
+#define DialogBox DialogBoxW
+#define DialogBoxIndirect DialogBoxIndirectW
+#define DialogBoxIndirectParam DialogBoxIndirectParamW
+#define DialogBoxParam DialogBoxParamW
+#define DispatchMessage DispatchMessageW
+#define DlgDirList DlgDirListW
+#define DlgDirListComboBox DlgDirListComboBoxW
+#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExW
+#define DlgDirSelectEx DlgDirSelectExW
+#define DrawState DrawStateW
+#define DrawText DrawTextW
+#define DrawTextEx DrawTextExW
+#define EnumDesktops EnumDesktopsW
+#define EnumDisplaySettings EnumDisplaySettingsW
+#define EnumProps EnumPropsW
+#define EnumPropsEx EnumPropsExW
+#define EnumWindowStations EnumWindowStationsW
+#define FindWindow FindWindowW
+#define FindWindowEx FindWindowExW
+#define GetClassInfo GetClassInfoW
+#define GetClassInfoEx GetClassInfoExW
+#define GetClassLong GetClassLongW
+#define GetClassName GetClassNameW
+#define GetClipboardFormatName GetClipboardFormatNameW
+#define GetDlgItemText GetDlgItemTextW
+#define GetKeyboardLayoutName GetKeyboardLayoutNameW
+#define GetKeyNameText GetKeyNameTextW
+#define GetMenuItemInfo GetMenuItemInfoW
+#define GetMenuString GetMenuStringW
+#define GetMessage GetMessageW
+#define GetMonitorInfo  GetMonitorInfoW
+#define GetProp GetPropW
+#define GetTabbedTextExtent GetTabbedTextExtentW
+#define GetUserObjectInformation GetUserObjectInformationW
+#define GetWindowLong GetWindowLongW
+#define GetWindowLongPtr GetWindowLongPtrW
+#define GetWindowText GetWindowTextW
+#define GetWindowTextLength GetWindowTextLengthW
+#define GetAltTabInfo GetAltTabInfoW
+#define GetWindowModuleFileName GetWindowModuleFileNameW
+#define GrayString GrayStringW
+#define InsertMenu InsertMenuW
+#define InsertMenuItem InsertMenuItemW
+#define IsCharAlpha IsCharAlphaW
+#define IsCharAlphaNumeric IsCharAlphaNumericW
+#define IsCharLower IsCharLowerW
+#define IsCharUpper IsCharUpperW
+#define IsDialogMessage IsDialogMessageW
+#define LoadAccelerators LoadAcceleratorsW
+#define LoadBitmap LoadBitmapW
+#define LoadCursor LoadCursorW
+#define LoadCursorFromFile LoadCursorFromFileW
+#define LoadIcon LoadIconW
+#define LoadImage LoadImageW
+#define LoadKeyboardLayout LoadKeyboardLayoutW
+#define LoadMenu LoadMenuW
+#define LoadMenuIndirect LoadMenuIndirectW
+#define LoadString LoadStringW
+#define MapVirtualKey MapVirtualKeyW
+#define MapVirtualKeyEx MapVirtualKeyExW
+#define MessageBox MessageBoxW
+#define MessageBoxEx MessageBoxExW
+#define MessageBoxIndirect MessageBoxIndirectW
+#define ModifyMenu ModifyMenuW
+#define OemToChar OemToCharW
+#define OemToCharBuff OemToCharBuffW
+#define OpenDesktop OpenDesktopW
+#define OpenWindowStation OpenWindowStationW
+#define PeekMessage PeekMessageW
+#define PostAppMessage PostAppMessageW
+#define PostMessage PostMessageW
+#define PostThreadMessage PostThreadMessageW
+#define RegisterClass RegisterClassW
+#define RegisterClassEx RegisterClassExW
+#define RegisterClipboardFormat RegisterClipboardFormatW
+#define RegisterWindowMessage RegisterWindowMessageW
+#define RemoveProp RemovePropW
+#define SendDlgItemMessage SendDlgItemMessageW
+#define SendMessage SendMessageW
+#define SendMessageCallback SendMessageCallbackW
+#define SendMessageTimeout SendMessageTimeoutW
+#define SendNotifyMessage SendNotifyMessageW
+#define SetClassLong SetClassLongW
+#define SetDlgItemText SetDlgItemTextW
+#define SetMenuItemInfo SetMenuItemInfoW
+#define SetProp SetPropW
+#define SetUserObjectInformation SetUserObjectInformationW
+#define SetWindowLong SetWindowLongW
+#define SetWindowLongPtr SetWindowLongPtrW
+#define SetWindowsHook SetWindowsHookW
+#define SetWindowsHookEx SetWindowsHookExW
+#define SetWindowText SetWindowTextW
+#define SystemParametersInfo SystemParametersInfoW
+#define TabbedTextOut TabbedTextOutW
+#define TranslateAccelerator TranslateAcceleratorW
+#define UnregisterClass UnregisterClassW
+#define VkKeyScan VkKeyScanW
+#define VkKeyScanEx VkKeyScanExW
+#define WinHelp WinHelpW
+#define wsprintf wsprintfW
+#define wvsprintf wvsprintfW
+#else
+#define EDITWORDBREAKPROC EDITWORDBREAKPROCA
+#define PROPENUMPROC PROPENUMPROCA
+#define PROPENUMPROCEX PROPENUMPROCEXA
+#define DEKSTOPENUMPROC DEKSTOPENUMPROCA
+#define WINSTAENUMPROC WINSTAENUMPROCA
+#define PROPENUMPROC PROPENUMPROCA
+#define PROPENUMPROCEX PROPENUMPROCEXA
+#define MAKEINTRESOURCE MAKEINTRESOURCEA
+typedef WNDCLASSA WNDCLASS,*LPWNDCLASS,*PWNDCLASS;
+typedef WNDCLASSEXA WNDCLASSEX,*LPWNDCLASSEX,*PWNDCLASSEX;
+typedef MENUITEMINFOA MENUITEMINFO,*LPMENUITEMINFO;
+typedef LPCMENUITEMINFOA LPCMENUITEMINFO;
+typedef MSGBOXPARAMSA MSGBOXPARAMS,*PMSGBOXPARAMS,*LPMSGBOXPARAMS;
+typedef HIGHCONTRASTA HIGHCONTRAST,*LPHIGHCONTRAST;
+typedef ICONMETRICSA ICONMETRICS,*LPICONMETRICS;
+typedef NONCLIENTMETRICSA NONCLIENTMETRICS,*LPNONCLIENTMETRICS;
+typedef SERIALKEYSA SERIALKEYS,*LPSERIALKEYS;
+typedef SOUNDSENTRYA SOUNDSENTRY,*LPSOUNDSENTRY;
+typedef CREATESTRUCTA CREATESTRUCT, *LPCREATESTRUCT;
+typedef CBT_CREATEWNDA CBT_CREATEWND, *LPCBT_CREATEWND;
+typedef MDICREATESTRUCTA MDICREATESTRUCT,*LPMDICREATESTRUCT;
+typedef MULTIKEYHELPA MULTIKEYHELP,*PMULTIKEYHELP,*LPMULTIKEYHELP;
+#define AppendMenu AppendMenuA
+#define CallWindowProc CallWindowProcA
+#define ChangeDisplaySettings ChangeDisplaySettingsA
+#define ChangeMenu ChangeMenuA
+#define CharLower CharLowerA
+#define CharLowerBuff CharLowerBuffA
+#define CharNext CharNextA
+#define CharNextEx CharNextExA
+#define CharPrev CharPrevA
+#define CharPrevEx CharPrevExA
+#define CharToOem CharToOemA
+#define CharToOemBuff CharToOemBuffA
+#define CharUpper CharUpperA
+#define CharUpperBuff CharUpperBuffA
+#define CopyAcceleratorTable CopyAcceleratorTableA
+#define CreateAcceleratorTable CreateAcceleratorTableA
+#define CreateDesktop CreateDesktopA
+#define CreateDialog CreateDialogA
+#define CreateDialogIndirect CreateDialogIndirectA
+#define CreateDialogIndirectParam CreateDialogIndirectParamA
+#define CreateDialogParam CreateDialogParamA
+#define CreateMDIWindow CreateMDIWindowA
+#define CreateWindow CreateWindowA
+#define CreateWindowEx CreateWindowExA
+#define CreateWindowStation CreateWindowStationA
+#define DefDlgProc DefDlgProcA
+#define DefFrameProc DefFrameProcA
+#define DefMDIChildProc DefMDIChildProcA
+#define DefWindowProc DefWindowProcA
+#define DialogBox DialogBoxA
+#define DialogBoxIndirect DialogBoxIndirectA
+#define DialogBoxIndirectParam DialogBoxIndirectParamA
+#define DialogBoxParam DialogBoxParamA
+#define DispatchMessage DispatchMessageA
+#define DlgDirList DlgDirListA
+#define DlgDirListComboBox DlgDirListComboBoxA
+#define DlgDirSelectComboBoxEx DlgDirSelectComboBoxExA
+#define DlgDirSelectEx DlgDirSelectExA
+#define DrawState DrawStateA
+#define DrawText DrawTextA
+#define DrawTextEx DrawTextExA
+#define EnumDesktops EnumDesktopsA
+#define EnumDisplaySettings EnumDisplaySettingsA
+#define EnumProps EnumPropsA
+#define EnumPropsEx EnumPropsExA
+#define EnumWindowStations EnumWindowStationsA
+#define FindWindow FindWindowA
+#define FindWindowEx FindWindowExA
+#define GetClassInfo GetClassInfoA
+#define GetClassInfoEx GetClassInfoExA
+#define GetClassLong GetClassLongA
+#define GetClassName GetClassNameA
+#define GetClipboardFormatName GetClipboardFormatNameA
+#define GetDlgItemText GetDlgItemTextA
+#define GetKeyboardLayoutName GetKeyboardLayoutNameA
+#define GetKeyNameText GetKeyNameTextA
+#define GetMenuItemInfo GetMenuItemInfoA
+#define GetMenuString GetMenuStringA
+#define GetMessage GetMessageA
+#define GetMonitorInfo  GetMonitorInfoA
+#define GetProp GetPropA
+#define GetTabbedTextExtent GetTabbedTextExtentA
+#define GetUserObjectInformation GetUserObjectInformationA
+#define GetWindowLong GetWindowLongA
+#define GetWindowLongPtr GetWindowLongPtrA
+#define GetWindowText GetWindowTextA
+#define GetWindowTextLength GetWindowTextLengthA
+#define GetAltTabInfo GetAltTabInfoA
+#define GetWindowModuleFileName GetWindowModuleFileNameA
+#define GrayString GrayStringA
+#define InsertMenu InsertMenuA
+#define InsertMenuItem InsertMenuItemA
+#define IsCharAlpha IsCharAlphaA
+#define IsCharAlphaNumeric IsCharAlphaNumericA
+#define IsCharLower IsCharLowerA
+#define IsCharUpper IsCharUpperA
+#define IsDialogMessage IsDialogMessageA
+#define LoadAccelerators LoadAcceleratorsA
+#define LoadBitmap LoadBitmapA
+#define LoadCursor LoadCursorA
+#define LoadIcon LoadIconA
+#define LoadCursorFromFile LoadCursorFromFileA
+#define LoadImage LoadImageA
+#define LoadKeyboardLayout LoadKeyboardLayoutA
+#define LoadMenu LoadMenuA
+#define LoadMenuIndirect LoadMenuIndirectA
+#define LoadString LoadStringA
+#define MapVirtualKey MapVirtualKeyA
+#define MapVirtualKeyEx MapVirtualKeyExA
+#define MessageBox MessageBoxA
+#define MessageBoxEx MessageBoxExA
+#define MessageBoxIndirect MessageBoxIndirectA
+#define ModifyMenu ModifyMenuA
+#define OemToChar OemToCharA
+#define OemToCharBuff OemToCharBuffA
+#define OpenDesktop OpenDesktopA
+#define OpenWindowStation OpenWindowStationA
+#define PeekMessage PeekMessageA
+#define PostAppMessage PostAppMessageA
+#define PostMessage PostMessageA
+#define PostThreadMessage PostThreadMessageA
+#define RegisterClass RegisterClassA
+#define RegisterClassEx RegisterClassExA
+#define RegisterClipboardFormat RegisterClipboardFormatA
+#define RegisterWindowMessage RegisterWindowMessageA
+#define RemoveProp RemovePropA
+#define SendDlgItemMessage SendDlgItemMessageA
+#define SendMessage SendMessageA
+#define SendMessageCallback SendMessageCallbackA
+#define SendMessageTimeout SendMessageTimeoutA
+#define SendNotifyMessage SendNotifyMessageA
+#define SetClassLong SetClassLongA
+#define SetDlgItemText SetDlgItemTextA
+#define SetMenuItemInfo SetMenuItemInfoA
+#define SetProp SetPropA
+#define SetUserObjectInformation SetUserObjectInformationA
+#define SetWindowLong SetWindowLongA
+#define SetWindowLongPtr SetWindowLongPtrA
+#define SetWindowsHook SetWindowsHookA
+#define SetWindowsHookEx SetWindowsHookExA
+#define SetWindowText SetWindowTextA
+#define SystemParametersInfo SystemParametersInfoA
+#define TabbedTextOut TabbedTextOutA
+#define TranslateAccelerator TranslateAcceleratorA
+#define UnregisterClass UnregisterClassA
+#define VkKeyScan VkKeyScanA
+#define VkKeyScanEx VkKeyScanExA
+#define WinHelp WinHelpA
+#define wsprintf wsprintfA
+#define wvsprintf wvsprintfA
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* _WINUSER_H */
diff --git a/tinyc/win32/include/winapi/winver.h b/tinyc/win32/include/winapi/winver.h
new file mode 100644
index 000000000..f20333ac8
--- /dev/null
+++ b/tinyc/win32/include/winapi/winver.h
@@ -0,0 +1,133 @@
+#ifndef _WINVER_H
+#define _WINVER_H
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define VS_FILE_INFO RT_VERSION
+#define VS_VERSION_INFO 1
+#define VS_USER_DEFINED 100
+#define VS_FFI_SIGNATURE 0xFEEF04BD
+#define VS_FFI_STRUCVERSION 0x10000
+#define VS_FFI_FILEFLAGSMASK 0x3F
+#define VS_FF_DEBUG 1
+#define VS_FF_PRERELEASE 2
+#define VS_FF_PATCHED 4
+#define VS_FF_PRIVATEBUILD 8
+#define VS_FF_INFOINFERRED 16
+#define VS_FF_SPECIALBUILD 32
+#define VOS_UNKNOWN 0
+#define VOS_DOS 0x10000
+#define VOS_OS216 0x20000
+#define VOS_OS232 0x30000
+#define VOS_NT 0x40000
+#define VOS__BASE 0
+#define VOS__WINDOWS16 1
+#define VOS__PM16 2
+#define VOS__PM32 3
+#define VOS__WINDOWS32 4
+#define VOS_DOS_WINDOWS16 0x10001
+#define VOS_DOS_WINDOWS32 0x10004
+#define VOS_OS216_PM16 0x20002
+#define VOS_OS232_PM32 0x30003
+#define VOS_NT_WINDOWS32 0x40004
+#define VFT_UNKNOWN 0
+#define VFT_APP 1
+#define VFT_DLL 2
+#define VFT_DRV 3
+#define VFT_FONT 4
+#define VFT_VXD 5
+#define VFT_STATIC_LIB 7
+#define VFT2_UNKNOWN 0
+#define VFT2_DRV_PRINTER 1
+#define VFT2_DRV_KEYBOARD 2
+#define VFT2_DRV_LANGUAGE 3
+#define VFT2_DRV_DISPLAY 4
+#define VFT2_DRV_MOUSE 5
+#define VFT2_DRV_NETWORK 6
+#define VFT2_DRV_SYSTEM 7
+#define VFT2_DRV_INSTALLABLE 8
+#define VFT2_DRV_SOUND 9
+#define VFT2_DRV_COMM 10
+#define VFT2_DRV_INPUTMETHOD 11
+#define VFT2_FONT_RASTER 1
+#define VFT2_FONT_VECTOR 2
+#define VFT2_FONT_TRUETYPE 3
+#define VFFF_ISSHAREDFILE 1
+#define VFF_CURNEDEST 1
+#define VFF_FILEINUSE 2
+#define VFF_BUFFTOOSMALL 4
+#define VIFF_FORCEINSTALL 1
+#define VIFF_DONTDELETEOLD 2
+#define VIF_TEMPFILE 1
+#define VIF_MISMATCH 2
+#define VIF_SRCOLD 4
+#define VIF_DIFFLANG 8
+#define VIF_DIFFCODEPG 16
+#define VIF_DIFFTYPE 32
+#define VIF_WRITEPROT 64
+#define VIF_FILEINUSE 128
+#define VIF_OUTOFSPACE 256
+#define VIF_ACCESSVIOLATION 512
+#define VIF_SHARINGVIOLATION 1024
+#define VIF_CANNOTCREATE 2048
+#define VIF_CANNOTDELETE 4096
+#define VIF_CANNOTRENAME 8192
+#define VIF_CANNOTDELETECUR 16384
+#define VIF_OUTOFMEMORY 32768
+#define VIF_CANNOTREADSRC  65536
+#define VIF_CANNOTREADDST 0x20000
+#define VIF_BUFFTOOSMALL 0x40000
+#ifndef RC_INVOKED
+typedef struct tagVS_FIXEDFILEINFO {
+	DWORD dwSignature;
+	DWORD dwStrucVersion;
+	DWORD dwFileVersionMS;
+	DWORD dwFileVersionLS;
+	DWORD dwProductVersionMS;
+	DWORD dwProductVersionLS;
+	DWORD dwFileFlagsMask;
+	DWORD dwFileFlags;
+	DWORD dwFileOS;
+	DWORD dwFileType;
+	DWORD dwFileSubtype;
+	DWORD dwFileDateMS;
+	DWORD dwFileDateLS;
+} VS_FIXEDFILEINFO;
+DWORD WINAPI VerFindFileA(DWORD,LPSTR,LPSTR,LPSTR,LPSTR,PUINT,LPSTR,PUINT);
+DWORD WINAPI VerFindFileW(DWORD,LPWSTR,LPWSTR,LPWSTR,LPWSTR,PUINT,LPWSTR,PUINT);
+DWORD WINAPI VerInstallFileA(DWORD,LPSTR,LPSTR,LPSTR,LPSTR,LPSTR,LPSTR,PUINT);
+DWORD WINAPI VerInstallFileW(DWORD,LPWSTR,LPWSTR,LPWSTR,LPWSTR,LPWSTR,LPWSTR,PUINT);
+DWORD WINAPI GetFileVersionInfoSizeA(LPSTR,PDWORD);
+DWORD WINAPI GetFileVersionInfoSizeW(LPWSTR,PDWORD);
+BOOL WINAPI GetFileVersionInfoA(LPSTR,DWORD,DWORD,PVOID);
+BOOL WINAPI GetFileVersionInfoW(LPWSTR,DWORD,DWORD,PVOID);
+DWORD WINAPI VerLanguageNameA(DWORD,LPSTR,DWORD);
+DWORD WINAPI VerLanguageNameW(DWORD,LPWSTR,DWORD);
+BOOL WINAPI VerQueryValueA(PCVOID,LPSTR,PVOID*,PUINT);
+BOOL WINAPI VerQueryValueW(PCVOID,LPWSTR,PVOID*,PUINT);
+#ifdef UNICODE
+#define VerFindFile VerFindFileW
+#define VerQueryValue VerQueryValueW
+#define VerInstallFile VerInstallFileW
+#define GetFileVersionInfoSize GetFileVersionInfoSizeW
+#define GetFileVersionInfo GetFileVersionInfoW
+#define VerLanguageName VerLanguageNameW
+#define VerQueryValue VerQueryValueW
+#else
+#define VerQueryValue VerQueryValueA
+#define VerFindFile VerFindFileA
+#define VerInstallFile VerInstallFileA
+#define GetFileVersionInfoSize GetFileVersionInfoSizeA
+#define GetFileVersionInfo GetFileVersionInfoA
+#define VerLanguageName VerLanguageNameA
+#define VerQueryValue VerQueryValueA
+#endif
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tinyc/win32/lib/chkstk.S b/tinyc/win32/lib/chkstk.S
new file mode 100644
index 000000000..837d8af2b
--- /dev/null
+++ b/tinyc/win32/lib/chkstk.S
@@ -0,0 +1,29 @@
+// =================================================
+// chkstk.s
+
+.text
+.globl __chkstk
+
+__chkstk:
+	xchg    (%esp), %ebp   // store ebp, get ret.addr
+	push    %ebp           // push ret.addr
+	lea     4(%esp), %ebp  // setup frame ptr
+	push    %ecx           // save ecx
+	mov     %ebp, %ecx
+P0:
+	sub     $4096,%ecx
+	test    %eax,(%ecx)
+	sub     $4096,%eax
+	cmp     $4096,%eax
+	jge     P0
+
+	sub     %eax,%ecx
+	mov     %esp,%eax
+	test    %eax,(%ecx)
+	mov     %ecx,%esp
+
+	mov     (%eax),%ecx     // restore ecx
+	mov     4(%eax),%eax
+	push    %eax
+	ret
+
diff --git a/tinyc/win32/lib/crt1.c b/tinyc/win32/lib/crt1.c
new file mode 100644
index 000000000..1cf12f294
--- /dev/null
+++ b/tinyc/win32/lib/crt1.c
@@ -0,0 +1,35 @@
+// =============================================
+// crt1.c
+
+#include <stdlib.h>
+
+#define __UNKNOWN_APP    0
+#define __CONSOLE_APP    1
+#define __GUI_APP        2
+void __set_app_type(int);
+void _controlfp(unsigned a, unsigned b);
+
+typedef struct
+{
+	int newmode;
+} _startupinfo;
+
+void __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
+
+int main(int argc, char **argv, char **env);
+
+int _start(void)
+{
+	int argc; char **argv; char **env; int ret;
+	_startupinfo start_info = {0};
+
+	_controlfp(0x10000, 0x30000);
+	__set_app_type(__CONSOLE_APP);
+	__getmainargs(&argc, &argv, &env, 0, &start_info);
+
+	ret = main(argc, argv, env);
+	exit(ret);
+}
+
+// =============================================
+
diff --git a/tinyc/win32/lib/dllcrt1.c b/tinyc/win32/lib/dllcrt1.c
new file mode 100644
index 000000000..9fc8339cf
--- /dev/null
+++ b/tinyc/win32/lib/dllcrt1.c
@@ -0,0 +1,13 @@
+//+---------------------------------------------------------------------------
+
+#include <windows.h>
+
+BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved);
+
+BOOL WINAPI _dllstart(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+	BOOL bRet;
+	bRet = DllMain (hDll, dwReason, lpReserved);
+	return bRet;
+}
+
diff --git a/tinyc/win32/lib/dllmain.c b/tinyc/win32/lib/dllmain.c
new file mode 100644
index 000000000..e32df481c
--- /dev/null
+++ b/tinyc/win32/lib/dllmain.c
@@ -0,0 +1,9 @@
+//+---------------------------------------------------------------------------
+
+#include <windows.h>
+
+BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+	return TRUE;
+}
+
diff --git a/tinyc/win32/lib/gdi32.def b/tinyc/win32/lib/gdi32.def
new file mode 100644
index 000000000..02766da43
--- /dev/null
+++ b/tinyc/win32/lib/gdi32.def
@@ -0,0 +1,337 @@
+LIBRARY gdi32.dll
+
+EXPORTS
+AbortDoc
+AbortPath
+AddFontResourceA
+AddFontResourceW
+AngleArc
+AnimatePalette
+Arc
+ArcTo
+BeginPath
+BitBlt
+ByeByeGDI
+CancelDC
+CheckColorsInGamut
+ChoosePixelFormat
+Chord
+CloseEnhMetaFile
+CloseFigure
+CloseMetaFile
+ColorCorrectPalette
+ColorMatchToTarget
+CombineRgn
+CombineTransform
+CopyEnhMetaFileA
+CopyEnhMetaFileW
+CopyMetaFileA
+CopyMetaFileW
+CreateBitmap
+CreateBitmapIndirect
+CreateBrushIndirect
+CreateColorSpaceA
+CreateColorSpaceW
+CreateCompatibleBitmap
+CreateCompatibleDC
+CreateDCA
+CreateDCW
+CreateDIBPatternBrush
+CreateDIBPatternBrushPt
+CreateDIBSection
+CreateDIBitmap
+CreateDiscardableBitmap
+CreateEllipticRgn
+CreateEllipticRgnIndirect
+CreateEnhMetaFileA
+CreateEnhMetaFileW
+CreateFontA
+CreateFontIndirectA
+CreateFontIndirectW
+CreateFontW
+CreateHalftonePalette
+CreateHatchBrush
+CreateICA
+CreateICW
+CreateMetaFileA
+CreateMetaFileW
+CreatePalette
+CreatePatternBrush
+CreatePen
+CreatePenIndirect
+CreatePolyPolygonRgn
+CreatePolygonRgn
+CreateRectRgn
+CreateRectRgnIndirect
+CreateRoundRectRgn
+CreateScalableFontResourceA
+CreateScalableFontResourceW
+CreateSolidBrush
+DPtoLP
+DeleteColorSpace
+DeleteDC
+DeleteEnhMetaFile
+DeleteMetaFile
+DeleteObject
+DescribePixelFormat
+DeviceCapabilitiesEx
+DeviceCapabilitiesExA
+DeviceCapabilitiesExW
+DrawEscape
+Ellipse
+EnableEUDC
+EndDoc
+EndPage
+EndPath
+EnumEnhMetaFile
+EnumFontFamiliesA
+EnumFontFamiliesExA
+EnumFontFamiliesExW
+EnumFontFamiliesW
+EnumFontsA
+EnumFontsW
+EnumICMProfilesA
+EnumICMProfilesW
+EnumMetaFile
+EnumObjects
+EqualRgn
+Escape
+ExcludeClipRect
+ExtCreatePen
+ExtCreateRegion
+ExtEscape
+ExtFloodFill
+ExtSelectClipRgn
+ExtTextOutA
+ExtTextOutW
+FillPath
+FillRgn
+FixBrushOrgEx
+FlattenPath
+FloodFill
+FrameRgn
+GdiComment
+GdiFlush
+GdiGetBatchLimit
+GdiPlayDCScript
+GdiPlayJournal
+GdiPlayScript
+GdiSetBatchLimit
+GetArcDirection
+GetAspectRatioFilterEx
+GetBitmapBits
+GetBitmapDimensionEx
+GetBkColor
+GetBkMode
+GetBoundsRect
+GetBrushOrgEx
+GetCharABCWidthsA
+GetCharABCWidthsFloatA
+GetCharABCWidthsFloatW
+GetCharABCWidthsW
+GetCharWidth32A
+GetCharWidth32W
+GetCharWidthA
+GetCharWidthFloatA
+GetCharWidthFloatW
+GetCharWidthW
+GetCharacterPlacementA
+GetCharacterPlacementW
+GetClipBox
+GetClipRgn
+GetColorAdjustment
+GetColorSpace
+GetCurrentObject
+GetCurrentPositionEx
+GetDCOrgEx
+GetDIBColorTable
+GetDIBits
+GetDeviceCaps
+GetDeviceGammaRamp
+GetEnhMetaFileA
+GetEnhMetaFileBits
+GetEnhMetaFileDescriptionA
+GetEnhMetaFileDescriptionW
+GetEnhMetaFileHeader
+GetEnhMetaFilePaletteEntries
+GetEnhMetaFileW
+GetFontData
+GetFontLanguageInfo
+GetFontResourceInfo
+GetGlyphOutline
+GetGlyphOutlineA
+GetGlyphOutlineW
+GetGraphicsMode
+GetICMProfileA
+GetICMProfileW
+GetKerningPairs
+GetKerningPairsA
+GetKerningPairsW
+GetLayout
+GetLogColorSpaceA
+GetLogColorSpaceW
+GetMapMode
+GetMetaFileA
+GetMetaFileBitsEx
+GetMetaFileW
+GetMetaRgn
+GetMiterLimit
+GetNearestColor
+GetNearestPaletteIndex
+GetObjectA
+GetObjectType
+GetObjectW
+GetOutlineTextMetricsA
+GetOutlineTextMetricsW
+GetPaletteEntries
+GetPath
+GetPixel
+GetPixelFormat
+GetPolyFillMode
+GetROP2
+GetRandomRgn
+GetRasterizerCaps
+GetRegionData
+GetRgnBox
+GetStockObject
+GetStretchBltMode
+GetSystemPaletteEntries
+GetSystemPaletteUse
+GetTextAlign
+GetTextCharacterExtra
+GetTextCharset
+GetTextCharsetInfo
+GetTextColor
+GetTextExtentExPointA
+GetTextExtentExPointW
+GetTextExtentPoint32A
+GetTextExtentPoint32W
+GetTextExtentPointA
+GetTextExtentPointW
+GetTextFaceA
+GetTextFaceW
+GetTextMetricsA
+GetTextMetricsW
+GetViewportExtEx
+GetViewportOrgEx
+GetWinMetaFileBits
+GetWindowExtEx
+GetWindowOrgEx
+GetWorldTransform
+IntersectClipRect
+InvertRgn
+LPtoDP
+LineDDA
+LineTo
+MaskBlt
+ModifyWorldTransform
+MoveToEx
+OffsetClipRgn
+OffsetRgn
+OffsetViewportOrgEx
+OffsetWindowOrgEx
+PaintRgn
+PatBlt
+PathToRegion
+Pie
+PlayEnhMetaFile
+PlayEnhMetaFileRecord
+PlayMetaFile
+PlayMetaFileRecord
+PlgBlt
+PolyBezier
+PolyBezierTo
+PolyDraw
+PolyPolygon
+PolyPolyline
+PolyTextOutA
+PolyTextOutW
+Polygon
+Polyline
+PolylineTo
+PtInRegion
+PtVisible
+RealizePalette
+RectInRegion
+RectVisible
+Rectangle
+RemoveFontResourceA
+RemoveFontResourceW
+ResetDCA
+ResetDCW
+ResizePalette
+RestoreDC
+RoundRect
+SaveDC
+ScaleViewportExtEx
+ScaleWindowExtEx
+SelectClipPath
+SelectClipRgn
+SelectObject
+SelectPalette
+SetAbortProc
+SetArcDirection
+SetBitmapBits
+SetBitmapDimensionEx
+SetBkColor
+SetBkMode
+SetBoundsRect
+SetBrushOrgEx
+SetColorAdjustment
+SetColorSpace
+SetDIBColorTable
+SetDIBits
+SetDIBitsToDevice
+SetDeviceGammaRamp
+SetEnhMetaFileBits
+SetFontEnumeration
+SetGraphicsMode
+SetICMMode
+SetICMProfileA
+SetICMProfileW
+SetLayout
+SetMagicColors
+SetMapMode
+SetMapperFlags
+SetMetaFileBitsEx
+SetMetaRgn
+SetMiterLimit
+SetObjectOwner
+SetPaletteEntries
+SetPixel
+SetPixelFormat
+SetPixelV
+SetPolyFillMode
+SetROP2
+SetRectRgn
+SetStretchBltMode
+SetSystemPaletteUse
+SetTextAlign
+SetTextCharacterExtra
+SetTextColor
+SetTextJustification
+SetViewportExtEx
+SetViewportOrgEx
+SetWinMetaFileBits
+SetWindowExtEx
+SetWindowOrgEx
+SetWorldTransform
+StartDocA
+StartDocW
+StartPage
+StretchBlt
+StretchDIBits
+StrokeAndFillPath
+StrokePath
+SwapBuffers
+TextOutA
+TextOutW
+TranslateCharsetInfo
+UnrealizeObject
+UpdateColors
+UpdateICMRegKeyA
+UpdateICMRegKeyW
+WidenPath
+gdiPlaySpoolStream
+pfnRealizePalette
+pfnSelectPalette
diff --git a/tinyc/win32/lib/kernel32.def b/tinyc/win32/lib/kernel32.def
new file mode 100644
index 000000000..85dd980d5
--- /dev/null
+++ b/tinyc/win32/lib/kernel32.def
@@ -0,0 +1,763 @@
+LIBRARY kernel32.dll
+
+EXPORTS
+AddAtomA
+AddAtomW
+AllocConsole
+AllocLSCallback
+AllocSLCallback
+AreFileApisANSI
+BackupRead
+BackupSeek
+BackupWrite
+Beep
+BeginUpdateResourceA
+BeginUpdateResourceW
+BuildCommDCBA
+BuildCommDCBAndTimeoutsA
+BuildCommDCBAndTimeoutsW
+BuildCommDCBW
+CallNamedPipeA
+CallNamedPipeW
+Callback12
+Callback16
+Callback20
+Callback24
+Callback28
+Callback32
+Callback36
+Callback4
+Callback40
+Callback44
+Callback48
+Callback52
+Callback56
+Callback60
+Callback64
+Callback8
+CancelDeviceWakeupRequest
+CancelIo
+CancelWaitableTimer
+ClearCommBreak
+ClearCommError
+CloseHandle
+CloseProfileUserMapping
+CloseSystemHandle
+CommConfigDialogA
+CommConfigDialogW
+CompareFileTime
+CompareStringA
+CompareStringW
+ConnectNamedPipe
+ContinueDebugEvent
+ConvertDefaultLocale
+ConvertThreadToFiber
+ConvertToGlobalHandle
+CopyFileA
+CopyFileExA
+CopyFileExW
+CopyFileW
+CreateConsoleScreenBuffer
+CreateDirectoryA
+CreateDirectoryExA
+CreateDirectoryExW
+CreateDirectoryW
+CreateEventA
+CreateEventW
+CreateFiber
+CreateFileA
+CreateFileMappingA
+CreateFileMappingW
+CreateFileW
+CreateIoCompletionPort
+CreateKernelThread
+CreateMailslotA
+CreateMailslotW
+CreateMutexA
+CreateMutexW
+CreateNamedPipeA
+CreateNamedPipeW
+CreatePipe
+CreateProcessA
+CreateProcessW
+CreateRemoteThread
+CreateSemaphoreA
+CreateSemaphoreW
+CreateSocketHandle
+CreateTapePartition
+CreateThread
+CreateToolhelp32Snapshot
+CreateWaitableTimerA
+CreateWaitableTimerW
+DebugActiveProcess
+DebugBreak
+DefineDosDeviceA
+DefineDosDeviceW
+DeleteAtom
+DeleteCriticalSection
+DeleteFiber
+DeleteFileA
+DeleteFileW
+DeviceIoControl
+DisableThreadLibraryCalls
+DisconnectNamedPipe
+DosDateTimeToFileTime
+DuplicateHandle
+EndUpdateResourceA
+EndUpdateResourceW
+EnterCriticalSection
+EnumCalendarInfoA
+EnumCalendarInfoExA
+EnumCalendarInfoExW
+EnumCalendarInfoW
+EnumDateFormatsA
+EnumDateFormatsExA
+EnumDateFormatsExW
+EnumDateFormatsW
+EnumLanguageGroupLocalesA
+EnumLanguageGroupLocalesW
+EnumResourceLanguagesA
+EnumResourceLanguagesW
+EnumResourceNamesA
+EnumResourceNamesW
+EnumResourceTypesA
+EnumResourceTypesW
+EnumSystemCodePagesA
+EnumSystemCodePagesW
+EnumSystemGeoID
+EnumSystemLanguageGroupsA
+EnumSystemLanguageGroupsW
+EnumSystemLocalesA
+EnumSystemLocalesW
+EnumTimeFormatsA
+EnumTimeFormatsW
+EnumUILanguagesA
+EnumUILanguagesW
+EraseTape
+EscapeCommFunction
+ExitProcess
+ExitThread
+ExpandEnvironmentStringsA
+ExpandEnvironmentStringsW
+FT_Exit0
+FT_Exit12
+FT_Exit16
+FT_Exit20
+FT_Exit24
+FT_Exit28
+FT_Exit32
+FT_Exit36
+FT_Exit4
+FT_Exit40
+FT_Exit44
+FT_Exit48
+FT_Exit52
+FT_Exit56
+FT_Exit8
+FT_Prolog
+FT_Thunk
+FatalAppExitA
+FatalAppExitW
+FatalExit
+FileTimeToDosDateTime
+FileTimeToLocalFileTime
+FileTimeToSystemTime
+FillConsoleOutputAttribute
+FillConsoleOutputCharacterA
+FillConsoleOutputCharacterW
+FindAtomA
+FindAtomW
+FindClose
+FindCloseChangeNotification
+FindFirstChangeNotificationA
+FindFirstChangeNotificationW
+FindFirstFileA
+FindFirstFileExA
+FindFirstFileExW
+FindFirstFileW
+FindNextChangeNotification
+FindNextFileA
+FindNextFileW
+FindResourceA
+FindResourceExA
+FindResourceExW
+FindResourceW
+FlushConsoleInputBuffer
+FlushFileBuffers
+FlushInstructionCache
+FlushViewOfFile
+FoldStringA
+FoldStringW
+FormatMessageA
+FormatMessageW
+FreeConsole
+FreeEnvironmentStringsA
+FreeEnvironmentStringsW
+FreeLSCallback
+FreeLibrary
+FreeLibraryAndExitThread
+FreeResource
+FreeSLCallback
+GenerateConsoleCtrlEvent
+GetACP
+GetAtomNameA
+GetAtomNameW
+GetBinaryType
+GetBinaryTypeA
+GetBinaryTypeW
+GetCPInfo
+GetCPInfoExA
+GetCPInfoExW
+GetCalendarInfoA
+GetCalendarInfoW
+GetCommConfig
+GetCommMask
+GetCommModemStatus
+GetCommProperties
+GetCommState
+GetCommTimeouts
+GetCommandLineA
+GetCommandLineW
+GetCompressedFileSizeA
+GetCompressedFileSizeW
+GetComputerNameA
+GetComputerNameW
+GetConsoleCP
+GetConsoleCursorInfo
+GetConsoleMode
+GetConsoleOutputCP
+GetConsoleScreenBufferInfo
+GetConsoleTitleA
+GetConsoleTitleW
+GetCurrencyFormatA
+GetCurrencyFormatW
+GetCurrentDirectoryA
+GetCurrentDirectoryW
+GetCurrentProcess
+GetCurrentProcessId
+GetCurrentThread
+GetCurrentThreadId
+GetDateFormatA
+GetDateFormatW
+GetDaylightFlag
+GetDefaultCommConfigA
+GetDefaultCommConfigW
+GetDevicePowerState
+GetDiskFreeSpaceA
+GetDiskFreeSpaceExA
+GetDiskFreeSpaceExW
+GetDiskFreeSpaceW
+GetDriveTypeA
+GetDriveTypeW
+GetEnvironmentStrings
+GetEnvironmentStringsA
+GetEnvironmentStringsW
+GetEnvironmentVariableA
+GetEnvironmentVariableW
+GetErrorMode
+GetExitCodeProcess
+GetExitCodeThread
+GetFileAttributesA
+GetFileAttributesExA
+GetFileAttributesExW
+GetFileAttributesW
+GetFileInformationByHandle
+GetFileSize
+GetFileTime
+GetFileType
+GetFullPathNameA
+GetFullPathNameW
+GetGeoInfoA
+GetGeoInfoW
+GetHandleContext
+GetHandleInformation
+GetLSCallbackTarget
+GetLSCallbackTemplate
+GetLargestConsoleWindowSize
+GetLastError
+GetLocalTime
+GetLocaleInfoA
+GetLocaleInfoW
+GetLogicalDriveStringsA
+GetLogicalDriveStringsW
+GetLogicalDrives
+GetLongPathNameA
+GetLongPathNameW
+GetMailslotInfo
+GetModuleFileNameA
+GetModuleFileNameW
+GetModuleHandleA
+GetModuleHandleW
+GetNamedPipeHandleStateA
+GetNamedPipeHandleStateW
+GetNamedPipeInfo
+GetNumberFormatA
+GetNumberFormatW
+GetNumberOfConsoleInputEvents
+GetNumberOfConsoleMouseButtons
+GetOEMCP
+GetOverlappedResult
+GetPriorityClass
+GetPrivateProfileIntA
+GetPrivateProfileIntW
+GetPrivateProfileSectionA
+GetPrivateProfileSectionNamesA
+GetPrivateProfileSectionNamesW
+GetPrivateProfileSectionW
+GetPrivateProfileStringA
+GetPrivateProfileStringW
+GetPrivateProfileStructA
+GetPrivateProfileStructW
+GetProcAddress
+GetProcessAffinityMask
+GetProcessFlags
+GetProcessHeap
+GetProcessHeaps
+GetProcessPriorityBoost
+GetProcessShutdownParameters
+GetProcessTimes
+GetProcessVersion
+GetProcessWorkingSetSize
+GetProductName
+GetProfileIntA
+GetProfileIntW
+GetProfileSectionA
+GetProfileSectionW
+GetProfileStringA
+GetProfileStringW
+GetQueuedCompletionStatus
+GetSLCallbackTarget
+GetSLCallbackTemplate
+GetShortPathNameA
+GetShortPathNameW
+GetStartupInfoA
+GetStartupInfoW
+GetStdHandle
+GetStringTypeA
+GetStringTypeExA
+GetStringTypeExW
+GetStringTypeW
+GetSystemDefaultLCID
+GetSystemDefaultLangID
+GetSystemDefaultUILanguage
+GetSystemDirectoryA
+GetSystemDirectoryW
+GetSystemInfo
+GetSystemPowerStatus
+GetSystemTime
+GetSystemTimeAdjustment
+GetSystemTimeAsFileTime
+GetTapeParameters
+GetTapePosition
+GetTapeStatus
+GetTempFileNameA
+GetTempFileNameW
+GetTempPathA
+GetTempPathW
+GetThreadContext
+GetThreadLocale
+GetThreadPriority
+GetThreadPriorityBoost
+GetThreadSelectorEntry
+GetThreadTimes
+GetTickCount
+GetTimeFormatA
+GetTimeFormatW
+GetTimeZoneInformation
+GetUserDefaultLCID
+GetUserDefaultLangID
+GetUserDefaultUILanguage
+GetUserGeoID
+GetVersion
+GetVersionExA
+GetVersionExW
+GetVolumeInformationA
+GetVolumeInformationW
+GetWindowsDirectoryA
+GetWindowsDirectoryW
+GetWriteWatch
+GlobalAddAtomA
+GlobalAddAtomW
+GlobalAlloc
+GlobalCompact
+GlobalDeleteAtom
+GlobalFindAtomA
+GlobalFindAtomW
+GlobalFix
+GlobalFlags
+GlobalFree
+GlobalGetAtomNameA
+GlobalGetAtomNameW
+GlobalHandle
+GlobalLock
+GlobalMemoryStatus
+GlobalReAlloc
+GlobalSize
+GlobalUnWire
+GlobalUnfix
+GlobalUnlock
+GlobalWire
+Heap32First
+Heap32ListFirst
+Heap32ListNext
+Heap32Next
+HeapAlloc
+HeapCompact
+HeapCreate
+HeapDestroy
+HeapFree
+HeapLock
+HeapReAlloc
+HeapSetFlags
+HeapSize
+HeapUnlock
+HeapValidate
+HeapWalk
+InitAtomTable
+InitializeCriticalSection
+InitializeCriticalSectionAndSpinCount
+InterlockedCompareExchange
+InterlockedDecrement
+InterlockedExchange
+InterlockedExchangeAdd
+InterlockedIncrement
+InvalidateNLSCache
+IsBadCodePtr
+IsBadHugeReadPtr
+IsBadHugeWritePtr
+IsBadReadPtr
+IsBadStringPtrA
+IsBadStringPtrW
+IsBadWritePtr
+IsDBCSLeadByte
+IsDBCSLeadByteEx
+IsDebuggerPresent
+IsLSCallback
+IsProcessorFeaturePresent
+IsSLCallback
+IsSystemResumeAutomatic
+IsValidCodePage
+IsValidLanguageGroup
+IsValidLocale
+K32Thk1632Epilog
+K32Thk1632Prolog
+K32_NtCreateFile
+K32_RtlNtStatusToDosError
+LCMapStringA
+LCMapStringW
+LeaveCriticalSection
+LoadLibraryA
+LoadLibraryExA
+LoadLibraryExW
+LoadLibraryW
+LoadModule
+LoadResource
+LocalAlloc
+LocalCompact
+LocalFileTimeToFileTime
+LocalFlags
+LocalFree
+LocalHandle
+LocalLock
+LocalReAlloc
+LocalShrink
+LocalSize
+LocalUnlock
+LockFile
+LockFileEx
+LockResource
+MakeCriticalSectionGlobal
+MapHInstLS
+MapHInstLS_PN
+MapHInstSL
+MapHInstSL_PN
+MapHModuleLS
+MapHModuleSL
+MapLS
+MapSL
+MapSLFix
+MapViewOfFile
+MapViewOfFileEx
+Module32First
+Module32Next
+MoveFileA
+MoveFileExA
+MoveFileExW
+MoveFileW
+MulDiv
+MultiByteToWideChar
+NotifyNLSUserCache
+OpenEventA
+OpenEventW
+OpenFile
+OpenFileMappingA
+OpenFileMappingW
+OpenMutexA
+OpenMutexW
+OpenProcess
+OpenProfileUserMapping
+OpenSemaphoreA
+OpenSemaphoreW
+OpenThread
+OpenVxDHandle
+OpenWaitableTimerA
+OpenWaitableTimerW
+OutputDebugStringA
+OutputDebugStringW
+PeekConsoleInputA
+PeekConsoleInputW
+PeekNamedPipe
+PostQueuedCompletionStatus
+PrepareTape
+Process32First
+Process32Next
+PulseEvent
+PurgeComm
+QT_Thunk
+QueryDosDeviceA
+QueryDosDeviceW
+QueryNumberOfEventLogRecords
+QueryOldestEventLogRecord
+QueryPerformanceCounter
+QueryPerformanceFrequency
+QueueUserAPC
+RaiseException
+ReadConsoleA
+ReadConsoleInputA
+ReadConsoleInputW
+ReadConsoleOutputA
+ReadConsoleOutputAttribute
+ReadConsoleOutputCharacterA
+ReadConsoleOutputCharacterW
+ReadConsoleOutputW
+ReadConsoleW
+ReadDirectoryChangesW
+ReadFile
+ReadFileEx
+ReadFileScatter
+ReadProcessMemory
+RegisterServiceProcess
+RegisterSysMsgHandler
+ReinitializeCriticalSection
+ReleaseMutex
+ReleaseSemaphore
+RemoveDirectoryA
+RemoveDirectoryW
+RequestDeviceWakeup
+RequestWakeupLatency
+ResetEvent
+ResetNLSUserInfoCache
+ResetWriteWatch
+ResumeThread
+RtlFillMemory
+RtlMoveMemory
+RtlUnwind
+RtlZeroMemory
+SMapLS
+SMapLS_IP_EBP_12
+SMapLS_IP_EBP_16
+SMapLS_IP_EBP_20
+SMapLS_IP_EBP_24
+SMapLS_IP_EBP_28
+SMapLS_IP_EBP_32
+SMapLS_IP_EBP_36
+SMapLS_IP_EBP_40
+SMapLS_IP_EBP_8
+SUnMapLS
+SUnMapLS_IP_EBP_12
+SUnMapLS_IP_EBP_16
+SUnMapLS_IP_EBP_20
+SUnMapLS_IP_EBP_24
+SUnMapLS_IP_EBP_28
+SUnMapLS_IP_EBP_32
+SUnMapLS_IP_EBP_36
+SUnMapLS_IP_EBP_40
+SUnMapLS_IP_EBP_8
+ScrollConsoleScreenBufferA
+ScrollConsoleScreenBufferW
+SearchPathA
+SearchPathW
+SetCalendarInfoA
+SetCalendarInfoW
+SetCommBreak
+SetCommConfig
+SetCommMask
+SetCommState
+SetCommTimeouts
+SetComputerNameA
+SetComputerNameW
+SetConsoleActiveScreenBuffer
+SetConsoleCP
+SetConsoleCtrlHandler
+SetConsoleCursorInfo
+SetConsoleCursorPosition
+SetConsoleMode
+SetConsoleOutputCP
+SetConsoleScreenBufferSize
+SetConsoleTextAttribute
+SetConsoleTitleA
+SetConsoleTitleW
+SetConsoleWindowInfo
+SetCriticalSectionSpinCount
+SetCurrentDirectoryA
+SetCurrentDirectoryW
+SetDaylightFlag
+SetDefaultCommConfigA
+SetDefaultCommConfigW
+SetEndOfFile
+SetEnvironmentVariableA
+SetEnvironmentVariableW
+SetErrorMode
+SetEvent
+SetFileApisToANSI
+SetFileApisToOEM
+SetFileAttributesA
+SetFileAttributesW
+SetFilePointer
+SetFileTime
+SetHandleContext
+SetHandleCount
+SetHandleInformation
+SetLastError
+SetLocalTime
+SetLocaleInfoA
+SetLocaleInfoW
+SetMailslotInfo
+SetMessageWaitingIndicator
+SetNamedPipeHandleState
+SetPriorityClass
+SetProcessAffinityMask
+SetProcessPriorityBoost
+SetProcessShutdownParameters
+SetProcessWorkingSetSize
+SetStdHandle
+SetSystemPowerState
+SetSystemTime
+SetSystemTimeAdjustment
+SetTapeParameters
+SetTapePosition
+SetThreadAffinityMask
+SetThreadContext
+SetThreadExecutionState
+SetThreadIdealProcessor
+SetThreadLocale
+SetThreadPriority
+SetThreadPriorityBoost
+SetTimeZoneInformation
+SetUnhandledExceptionFilter
+SetUserGeoID
+SetVolumeLabelA
+SetVolumeLabelW
+SetWaitableTimer
+SetupComm
+SignalObjectAndWait
+SignalSysMsgHandlers
+SizeofResource
+Sleep
+SleepEx
+SuspendThread
+SwitchToFiber
+SwitchToThread
+SystemTimeToFileTime
+SystemTimeToTzSpecificLocalTime
+TerminateProcess
+TerminateThread
+Thread32First
+Thread32Next
+ThunkConnect32
+TlsAlloc
+TlsAllocInternal
+TlsFree
+TlsFreeInternal
+TlsGetValue
+TlsSetValue
+Toolhelp32ReadProcessMemory
+TransactNamedPipe
+TransmitCommChar
+TryEnterCriticalSection
+UTRegister
+UTUnRegister
+UnMapLS
+UnMapSLFixArray
+UnhandledExceptionFilter
+UninitializeCriticalSection
+UnlockFile
+UnlockFileEx
+UnmapViewOfFile
+UpdateResourceA
+UpdateResourceW
+VerLanguageNameA
+VerLanguageNameW
+VirtualAlloc
+VirtualAllocEx
+VirtualFree
+VirtualFreeEx
+VirtualLock
+VirtualProtect
+VirtualProtectEx
+VirtualQuery
+VirtualQueryEx
+VirtualUnlock
+WaitCommEvent
+WaitForDebugEvent
+WaitForMultipleObjects
+WaitForMultipleObjectsEx
+WaitForSingleObject
+WaitForSingleObjectEx
+WaitNamedPipeA
+WaitNamedPipeW
+WideCharToMultiByte
+WinExec
+WriteConsoleA
+WriteConsoleInputA
+WriteConsoleInputW
+WriteConsoleOutputA
+WriteConsoleOutputAttribute
+WriteConsoleOutputCharacterA
+WriteConsoleOutputCharacterW
+WriteConsoleOutputW
+WriteConsoleW
+WriteFile
+WriteFileEx
+WriteFileGather
+WritePrivateProfileSectionA
+WritePrivateProfileSectionW
+WritePrivateProfileStringA
+WritePrivateProfileStringW
+WritePrivateProfileStructA
+WritePrivateProfileStructW
+WriteProcessMemory
+WriteProfileSectionA
+WriteProfileSectionW
+WriteProfileStringA
+WriteProfileStringW
+WriteTapemark
+_DebugOut
+_DebugPrintf
+_hread
+_hwrite
+_lclose
+_lcreat
+_llseek
+_lopen
+_lread
+_lwrite
+dprintf
+lstrcat
+lstrcatA
+lstrcatW
+lstrcmp
+lstrcmpA
+lstrcmpW
+lstrcmpi
+lstrcmpiA
+lstrcmpiW
+lstrcpy
+lstrcpyA
+lstrcpyW
+lstrcpyn
+lstrcpynA
+lstrcpynW
+lstrlen
+lstrlenA
+lstrlenW
diff --git a/tinyc/win32/lib/libtcc1.a b/tinyc/win32/lib/libtcc1.a
new file mode 100644
index 000000000..0062e8f93
--- /dev/null
+++ b/tinyc/win32/lib/libtcc1.a
Binary files differdiff --git a/tinyc/win32/lib/msvcrt.def b/tinyc/win32/lib/msvcrt.def
new file mode 100644
index 000000000..e4f202373
--- /dev/null
+++ b/tinyc/win32/lib/msvcrt.def
@@ -0,0 +1,782 @@
+LIBRARY msvcrt.dll
+
+EXPORTS
+$I10_OUTPUT
+??0__non_rtti_object@@QAE@ABV0@@Z
+??0__non_rtti_object@@QAE@PBD@Z
+??0bad_cast@@QAE@ABQBD@Z
+??0bad_cast@@QAE@ABV0@@Z
+??0bad_typeid@@QAE@ABV0@@Z
+??0bad_typeid@@QAE@PBD@Z
+??0exception@@QAE@ABQBD@Z
+??0exception@@QAE@ABV0@@Z
+??0exception@@QAE@XZ
+??1__non_rtti_object@@UAE@XZ
+??1bad_cast@@UAE@XZ
+??1bad_typeid@@UAE@XZ
+??1exception@@UAE@XZ
+??1type_info@@UAE@XZ
+??2@YAPAXI@Z
+??3@YAXPAX@Z
+??4__non_rtti_object@@QAEAAV0@ABV0@@Z
+??4bad_cast@@QAEAAV0@ABV0@@Z
+??4bad_typeid@@QAEAAV0@ABV0@@Z
+??4exception@@QAEAAV0@ABV0@@Z
+??8type_info@@QBEHABV0@@Z
+??9type_info@@QBEHABV0@@Z
+??_7__non_rtti_object@@6B@
+??_7bad_cast@@6B@
+??_7bad_typeid@@6B@
+??_7exception@@6B@
+??_E__non_rtti_object@@UAEPAXI@Z
+??_Ebad_cast@@UAEPAXI@Z
+??_Ebad_typeid@@UAEPAXI@Z
+??_Eexception@@UAEPAXI@Z
+??_G__non_rtti_object@@UAEPAXI@Z
+??_Gbad_cast@@UAEPAXI@Z
+??_Gbad_typeid@@UAEPAXI@Z
+??_Gexception@@UAEPAXI@Z
+??_U@YAPAXI@Z
+??_V@YAXPAX@Z
+?_query_new_handler@@YAP6AHI@ZXZ
+?_query_new_mode@@YAHXZ
+?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z
+?_set_new_mode@@YAHH@Z
+?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z
+?before@type_info@@QBEHABV1@@Z
+?name@type_info@@QBEPBDXZ
+?raw_name@type_info@@QBEPBDXZ
+?set_new_handler@@YAP6AXXZP6AXXZ@Z
+?set_terminate@@YAP6AXXZP6AXXZ@Z
+?set_unexpected@@YAP6AXXZP6AXXZ@Z
+?terminate@@YAXXZ
+?unexpected@@YAXXZ
+?what@exception@@UBEPBDXZ
+_CIacos
+_CIasin
+_CIatan
+_CIatan2
+_CIcos
+_CIcosh
+_CIexp
+_CIfmod
+_CIlog
+_CIlog10
+_CIpow
+_CIsin
+_CIsinh
+_CIsqrt
+_CItan
+_CItanh
+_CxxThrowException
+_EH_prolog
+_Getdays
+_Getmonths
+_Gettnames
+_HUGE
+_Strftime
+_XcptFilter
+__CxxFrameHandler
+__CxxLongjmpUnwind
+__RTCastToVoid
+__RTDynamicCast
+__RTtypeid
+__STRINGTOLD
+__argc
+__argv
+__badioinfo
+__crtCompareStringA
+__crtGetLocaleInfoW
+__crtLCMapStringA
+__dllonexit
+__doserrno
+__fpecode
+__getmainargs
+__initenv
+__isascii
+__iscsym
+__iscsymf
+__lc_codepage
+__lc_collate_cp
+__lc_handle
+__lconv_init
+__mb_cur_max
+__p___argc
+__p___argv
+__p___initenv
+__p___mb_cur_max
+__p___wargv
+__p___winitenv
+__p__acmdln
+__p__amblksiz
+__p__commode
+__p__daylight
+__p__dstbias
+__p__environ
+__p__fileinfo
+__p__fmode
+__p__iob
+__p__mbcasemap
+__p__mbctype
+__p__osver
+__p__pctype
+__p__pgmptr
+__p__pwctype
+__p__timezone
+__p__tzname
+__p__wcmdln
+__p__wenviron
+__p__winmajor
+__p__winminor
+__p__winver
+__p__wpgmptr
+__pioinfo
+__pxcptinfoptrs
+__set_app_type
+__setlc_active
+__setusermatherr
+__threadhandle
+__threadid
+__toascii
+__unDName
+__unDNameEx
+__unguarded_readlc_active
+__wargv
+__wgetmainargs
+__winitenv
+_abnormal_termination
+_access
+_acmdln
+_adj_fdiv_m16i
+_adj_fdiv_m32
+_adj_fdiv_m32i
+_adj_fdiv_m64
+_adj_fdiv_r
+_adj_fdivr_m16i
+_adj_fdivr_m32
+_adj_fdivr_m32i
+_adj_fdivr_m64
+_adj_fpatan
+_adj_fprem
+_adj_fprem1
+_adj_fptan
+_adjust_fdiv
+_aexit_rtn
+_amsg_exit
+_assert
+_atodbl
+_atoi64
+_atoldbl
+_beep
+_beginthread
+_beginthreadex
+_c_exit
+_cabs
+_callnewh
+_cexit
+_cgets
+_chdir
+_chdrive
+_chgsign
+_chkesp
+_chmod
+_chsize
+_clearfp
+_close
+_commit
+_commode
+_control87
+_controlfp
+_copysign
+_cprintf
+_cputs
+_creat
+_cscanf
+_ctime64
+_ctype
+_cwait
+_daylight
+_dstbias
+_dup
+_dup2
+_ecvt
+_endthread
+_endthreadex
+_environ
+_eof
+_errno
+_except_handler2
+_except_handler3
+_execl
+_execle
+_execlp
+_execlpe
+_execv
+_execve
+_execvp
+_execvpe
+_exit
+_expand
+_fcloseall
+_fcvt
+_fdopen
+_fgetchar
+_fgetwchar
+_filbuf
+_fileinfo
+_filelength
+_filelengthi64
+_fileno
+_findclose
+_findfirst
+_findfirst64
+_findfirsti64
+_findnext
+_findnext64
+_findnexti64
+_finite
+_flsbuf
+_flushall
+_fmode
+_fpclass
+_fpieee_flt
+_fpreset
+_fputchar
+_fputwchar
+_fsopen
+_fstat
+_fstat64
+_fstati64
+_ftime
+_ftime64
+_ftol
+_fullpath
+_futime
+_futime64
+_gcvt
+_get_osfhandle
+_get_sbh_threshold
+_getch
+_getche
+_getcwd
+_getdcwd
+_getdiskfree
+_getdllprocaddr
+_getdrive
+_getdrives
+_getmaxstdio
+_getmbcp
+_getpid
+_getsystime
+_getw
+_getws
+_global_unwind2
+_gmtime64
+_heapadd
+_heapchk
+_heapmin
+_heapset
+_heapused
+_heapwalk
+_hypot
+_i64toa
+_i64tow
+_initterm
+_inp
+_inpd
+_inpw
+_iob
+_isatty
+_isctype
+_ismbbalnum
+_ismbbalpha
+_ismbbgraph
+_ismbbkalnum
+_ismbbkana
+_ismbbkprint
+_ismbbkpunct
+_ismbblead
+_ismbbprint
+_ismbbpunct
+_ismbbtrail
+_ismbcalnum
+_ismbcalpha
+_ismbcdigit
+_ismbcgraph
+_ismbchira
+_ismbckata
+_ismbcl0
+_ismbcl1
+_ismbcl2
+_ismbclegal
+_ismbclower
+_ismbcprint
+_ismbcpunct
+_ismbcspace
+_ismbcsymbol
+_ismbcupper
+_ismbslead
+_ismbstrail
+_isnan
+_itoa
+_itow
+_j0
+_j1
+_jn
+_kbhit
+_lfind
+_loaddll
+_local_unwind2
+_localtime64
+_lock
+_locking
+_logb
+_longjmpex
+_lrotl
+_lrotr
+_lsearch
+_lseek
+_lseeki64
+_ltoa
+_ltow
+_makepath
+_mbbtombc
+_mbbtype
+_mbcasemap
+_mbccpy
+_mbcjistojms
+_mbcjmstojis
+_mbclen
+_mbctohira
+_mbctokata
+_mbctolower
+_mbctombb
+_mbctoupper
+_mbctype
+_mbsbtype
+_mbscat
+_mbschr
+_mbscmp
+_mbscoll
+_mbscpy
+_mbscspn
+_mbsdec
+_mbsdup
+_mbsicmp
+_mbsicoll
+_mbsinc
+_mbslen
+_mbslwr
+_mbsnbcat
+_mbsnbcmp
+_mbsnbcnt
+_mbsnbcoll
+_mbsnbcpy
+_mbsnbicmp
+_mbsnbicoll
+_mbsnbset
+_mbsncat
+_mbsnccnt
+_mbsncmp
+_mbsncoll
+_mbsncpy
+_mbsnextc
+_mbsnicmp
+_mbsnicoll
+_mbsninc
+_mbsnset
+_mbspbrk
+_mbsrchr
+_mbsrev
+_mbsset
+_mbsspn
+_mbsspnp
+_mbsstr
+_mbstok
+_mbstrlen
+_mbsupr
+_memccpy
+_memicmp
+_mkdir
+_mktemp
+_mktime64
+_msize
+_nextafter
+_onexit
+_open
+_open_osfhandle
+_osplatform
+_osver
+_outp
+_outpd
+_outpw
+_pclose
+_pctype
+_pgmptr
+_pipe
+_popen
+_purecall
+_putch
+_putenv
+_putw
+_putws
+_pwctype
+_read
+_rmdir
+_rmtmp
+_rotl
+_rotr
+_safe_fdiv
+_safe_fdivr
+_safe_fprem
+_safe_fprem1
+_scalb
+_searchenv
+_seh_longjmp_unwind
+_set_error_mode
+_set_sbh_threshold
+_seterrormode
+_setjmp
+_setjmp3
+_setmaxstdio
+_setmbcp
+_setmode
+_setsystime
+_sleep
+_snprintf
+_snwprintf
+_sopen
+_spawnl
+_spawnle
+_spawnlp
+_spawnlpe
+_spawnv
+_spawnve
+_spawnvp
+_spawnvpe
+_splitpath
+_stat
+_stat64
+_stati64
+_statusfp
+_strcmpi
+_strdate
+_strdup
+_strerror
+_stricmp
+_stricoll
+_strlwr
+_strncoll
+_strnicmp
+_strnicoll
+_strnset
+_strrev
+_strset
+_strtime
+_strupr
+_swab
+_sys_errlist
+_sys_nerr
+_tell
+_telli64
+_tempnam
+_time64
+_timezone
+_tolower
+_toupper
+_tzname
+_tzset
+_ui64toa
+_ui64tow
+_ultoa
+_ultow
+_umask
+_ungetch
+_unlink
+_unloaddll
+_unlock
+_utime
+_utime64
+_vsnprintf
+_vsnwprintf
+_waccess
+_wasctime
+_wchdir
+_wchmod
+_wcmdln
+_wcreat
+_wcsdup
+_wcsicmp
+_wcsicoll
+_wcslwr
+_wcsncoll
+_wcsnicmp
+_wcsnicoll
+_wcsnset
+_wcsrev
+_wcsset
+_wcsupr
+_wctime
+_wctime64
+_wenviron
+_wexecl
+_wexecle
+_wexeclp
+_wexeclpe
+_wexecv
+_wexecve
+_wexecvp
+_wexecvpe
+_wfdopen
+_wfindfirst
+_wfindfirst64
+_wfindfirsti64
+_wfindnext
+_wfindnext64
+_wfindnexti64
+_wfopen
+_wfreopen
+_wfsopen
+_wfullpath
+_wgetcwd
+_wgetdcwd
+_wgetenv
+_winmajor
+_winminor
+_winver
+_wmakepath
+_wmkdir
+_wmktemp
+_wopen
+_wperror
+_wpgmptr
+_wpopen
+_wputenv
+_wremove
+_wrename
+_write
+_wrmdir
+_wsearchenv
+_wsetlocale
+_wsopen
+_wspawnl
+_wspawnle
+_wspawnlp
+_wspawnlpe
+_wspawnv
+_wspawnve
+_wspawnvp
+_wspawnvpe
+_wsplitpath
+_wstat
+_wstat64
+_wstati64
+_wstrdate
+_wstrtime
+_wsystem
+_wtempnam
+_wtmpnam
+_wtoi
+_wtoi64
+_wtol
+_wunlink
+_wutime
+_wutime64
+_y0
+_y1
+_yn
+abort
+abs
+acos
+asctime
+asin
+atan
+atan2
+atexit
+atof
+atoi
+atol
+bsearch
+calloc
+ceil
+clearerr
+clock
+cos
+cosh
+ctime
+difftime
+div
+exit
+exp
+fabs
+fclose
+feof
+ferror
+fflush
+fgetc
+fgetpos
+fgets
+fgetwc
+fgetws
+floor
+fmod
+fopen
+fprintf
+fputc
+fputs
+fputwc
+fputws
+fread
+free
+freopen
+frexp
+fscanf
+fseek
+fsetpos
+ftell
+fwprintf
+fwrite
+fwscanf
+getc
+getchar
+getenv
+gets
+getwc
+getwchar
+gmtime
+is_wctype
+isalnum
+isalpha
+iscntrl
+isdigit
+isgraph
+isleadbyte
+islower
+isprint
+ispunct
+isspace
+isupper
+iswalnum
+iswalpha
+iswascii
+iswcntrl
+iswctype
+iswdigit
+iswgraph
+iswlower
+iswprint
+iswpunct
+iswspace
+iswupper
+iswxdigit
+isxdigit
+labs
+ldexp
+ldiv
+localeconv
+localtime
+log
+log10
+longjmp
+malloc
+mblen
+mbstowcs
+mbtowc
+memchr
+memcmp
+memcpy
+memmove
+memset
+mktime
+modf
+perror
+pow
+printf
+putc
+putchar
+puts
+putwc
+putwchar
+qsort
+raise
+rand
+realloc
+remove
+rename
+rewind
+scanf
+setbuf
+setlocale
+setvbuf
+signal
+sin
+sinh
+sprintf
+sqrt
+srand
+sscanf
+strcat
+strchr
+strcmp
+strcoll
+strcpy
+strcspn
+strerror
+strftime
+strlen
+strncat
+strncmp
+strncpy
+strpbrk
+strrchr
+strspn
+strstr
+strtod
+strtok
+strtol
+strtoul
+strxfrm
+swprintf
+swscanf
+system
+tan
+tanh
+time
+tmpfile
+tmpnam
+tolower
+toupper
+towlower
+towupper
+ungetc
+ungetwc
+vfprintf
+vfwprintf
+vprintf
+vsprintf
+vswprintf
+vwprintf
+wcscat
+wcschr
+wcscmp
+wcscoll
+wcscpy
+wcscspn
+wcsftime
+wcslen
+wcsncat
+wcsncmp
+wcsncpy
+wcspbrk
+wcsrchr
+wcsspn
+wcsstr
+wcstod
+wcstok
+wcstol
+wcstombs
+wcstoul
+wcsxfrm
+wctomb
+wprintf
+wscanf
diff --git a/tinyc/win32/lib/user32.def b/tinyc/win32/lib/user32.def
new file mode 100644
index 000000000..4d2f704e1
--- /dev/null
+++ b/tinyc/win32/lib/user32.def
@@ -0,0 +1,654 @@
+LIBRARY user32.dll
+
+EXPORTS
+ActivateKeyboardLayout
+AdjustWindowRect
+AdjustWindowRectEx
+AlignRects
+AllowSetForegroundWindow
+AnimateWindow
+AnyPopup
+AppendMenuA
+AppendMenuW
+ArrangeIconicWindows
+AttachThreadInput
+BeginDeferWindowPos
+BeginPaint
+BlockInput
+BringWindowToTop
+BroadcastSystemMessage
+BroadcastSystemMessageA
+BroadcastSystemMessageW
+CalcChildScroll
+CallMsgFilter
+CallMsgFilterA
+CallMsgFilterW
+CallNextHookEx
+CallWindowProcA
+CallWindowProcW
+CascadeChildWindows
+CascadeWindows
+ChangeClipboardChain
+ChangeDisplaySettingsA
+ChangeDisplaySettingsExA
+ChangeDisplaySettingsExW
+ChangeDisplaySettingsW
+ChangeMenuA
+ChangeMenuW
+CharLowerA
+CharLowerBuffA
+CharLowerBuffW
+CharLowerW
+CharNextA
+CharNextExA
+CharNextExW
+CharNextW
+CharPrevA
+CharPrevExA
+CharPrevExW
+CharPrevW
+CharToOemA
+CharToOemBuffA
+CharToOemBuffW
+CharToOemW
+CharUpperA
+CharUpperBuffA
+CharUpperBuffW
+CharUpperW
+CheckDlgButton
+CheckMenuItem
+CheckMenuRadioItem
+CheckRadioButton
+ChildWindowFromPoint
+ChildWindowFromPointEx
+ClientThreadConnect
+ClientToScreen
+ClipCursor
+CloseClipboard
+CloseDesktop
+CloseWindow
+CloseWindowStation
+CopyAcceleratorTableA
+CopyAcceleratorTableW
+CopyIcon
+CopyImage
+CopyRect
+CountClipboardFormats
+CreateAcceleratorTableA
+CreateAcceleratorTableW
+CreateCaret
+CreateCursor
+CreateDesktopA
+CreateDesktopW
+CreateDialogIndirectParamA
+CreateDialogIndirectParamW
+CreateDialogParamA
+CreateDialogParamW
+CreateIcon
+CreateIconFromResource
+CreateIconFromResourceEx
+CreateIconIndirect
+CreateMDIWindowA
+CreateMDIWindowW
+CreateMenu
+CreatePopupMenu
+CreateWindowExA
+CreateWindowExW
+CreateWindowStationA
+CreateWindowStationW
+DdeAbandonTransaction
+DdeAccessData
+DdeAddData
+DdeClientTransaction
+DdeCmpStringHandles
+DdeConnect
+DdeConnectList
+DdeCreateDataHandle
+DdeCreateStringHandleA
+DdeCreateStringHandleW
+DdeDisconnect
+DdeDisconnectList
+DdeEnableCallback
+DdeFreeDataHandle
+DdeFreeStringHandle
+DdeGetData
+DdeGetLastError
+DdeImpersonateClient
+DdeInitializeA
+DdeInitializeW
+DdeKeepStringHandle
+DdeNameService
+DdePostAdvise
+DdeQueryConvInfo
+DdeQueryNextServer
+DdeQueryStringA
+DdeQueryStringW
+DdeReconnect
+DdeSetQualityOfService
+DdeSetUserHandle
+DdeUnaccessData
+DdeUninitialize
+DefDlgProcA
+DefDlgProcW
+DefFrameProcA
+DefFrameProcW
+DefMDIChildProcA
+DefMDIChildProcW
+DefWindowProcA
+DefWindowProcW
+DeferWindowPos
+DeleteMenu
+DestroyAcceleratorTable
+DestroyCaret
+DestroyCursor
+DestroyIcon
+DestroyMenu
+DestroyWindow
+DialogBoxIndirectParamA
+DialogBoxIndirectParamW
+DialogBoxParamA
+DialogBoxParamW
+DispatchMessageA
+DispatchMessageW
+DlgDirListA
+DlgDirListComboBoxA
+DlgDirListComboBoxW
+DlgDirListW
+DlgDirSelectComboBoxExA
+DlgDirSelectComboBoxExW
+DlgDirSelectExA
+DlgDirSelectExW
+DragDetect
+DragObject
+DrawAnimatedRects
+DrawCaption
+DrawCaptionTempA
+DrawCaptionTempW
+DrawEdge
+DrawFocusRect
+DrawFrame
+DrawFrameControl
+DrawIcon
+DrawIconEx
+DrawMenuBar
+DrawMenuBarTemp
+DrawStateA
+DrawStateW
+DrawTextA
+DrawTextExA
+DrawTextExW
+DrawTextW
+EditWndProc
+EmptyClipboard
+EnableMenuItem
+EnableScrollBar
+EnableWindow
+EndDeferWindowPos
+EndDialog
+EndMenu
+EndPaint
+EndTask
+EnumChildWindows
+EnumClipboardFormats
+EnumDesktopWindows
+EnumDesktopsA
+EnumDesktopsW
+EnumDisplayDevicesA
+EnumDisplayDevicesW
+EnumDisplayMonitors
+EnumDisplaySettingsA
+EnumDisplaySettingsExA
+EnumDisplaySettingsExW
+EnumDisplaySettingsW
+EnumPropsA
+EnumPropsExA
+EnumPropsExW
+EnumPropsW
+EnumThreadWindows
+EnumWindowStationsA
+EnumWindowStationsW
+EnumWindows
+EqualRect
+ExcludeUpdateRgn
+ExitWindowsEx
+FillRect
+FindWindowA
+FindWindowExA
+FindWindowExW
+FindWindowW
+FlashWindow
+FlashWindowEx
+FrameRect
+FreeDDElParam
+GetActiveWindow
+GetAltTabInfo
+GetAncestor
+GetAsyncKeyState
+GetCapture
+GetCaretBlinkTime
+GetCaretPos
+GetClassInfoA
+GetClassInfoExA
+GetClassInfoExW
+GetClassInfoW
+GetClassLongA
+GetClassLongW
+GetClassNameA
+GetClassNameW
+GetClassWord
+GetClientRect
+GetClipCursor
+GetClipboardData
+GetClipboardFormatNameA
+GetClipboardFormatNameW
+GetClipboardOwner
+GetClipboardSequenceNumber
+GetClipboardViewer
+GetComboBoxInfo
+GetCursor
+GetCursorInfo
+GetCursorPos
+GetDC
+GetDCEx
+GetDesktopWindow
+GetDialogBaseUnits
+GetDlgCtrlID
+GetDlgItem
+GetDlgItemInt
+GetDlgItemTextA
+GetDlgItemTextW
+GetDoubleClickTime
+GetFocus
+GetForegroundWindow
+GetGUIThreadInfo
+GetGuiResources
+GetIconInfo
+GetInputDesktop
+GetInputState
+GetInternalWindowPos
+GetKBCodePage
+GetKeyNameTextA
+GetKeyNameTextW
+GetKeyState
+GetKeyboardLayout
+GetKeyboardLayoutList
+GetKeyboardLayoutNameA
+GetKeyboardLayoutNameW
+GetKeyboardState
+GetKeyboardType
+GetLastActivePopup
+GetListBoxInfo
+GetMenu
+GetMenuBarInfo
+GetMenuCheckMarkDimensions
+GetMenuContextHelpId
+GetMenuDefaultItem
+GetMenuInfo
+GetMenuItemCount
+GetMenuItemID
+GetMenuItemInfoA
+GetMenuItemInfoW
+GetMenuItemRect
+GetMenuState
+GetMenuStringA
+GetMenuStringW
+GetMessageA
+GetMessageExtraInfo
+GetMessagePos
+GetMessageTime
+GetMessageW
+GetMonitorInfoA
+GetMonitorInfoW
+GetMouseMovePoints
+GetMouseMovePointsEx
+GetNextDlgGroupItem
+GetNextDlgTabItem
+GetNextQueueWindow
+GetOpenClipboardWindow
+GetParent
+GetPriorityClipboardFormat
+GetProcessDefaultLayout
+GetProcessWindowStation
+GetPropA
+GetPropW
+GetQueueStatus
+GetScrollBarInfo
+GetScrollInfo
+GetScrollPos
+GetScrollRange
+GetShellWindow
+GetSubMenu
+GetSysColor
+GetSysColorBrush
+GetSystemMenu
+GetSystemMetrics
+GetTabbedTextExtentA
+GetTabbedTextExtentW
+GetThreadDesktop
+GetTitleBarInfo
+GetTopWindow
+GetUpdateRect
+GetUpdateRgn
+GetUserObjectInformationA
+GetUserObjectInformationW
+GetUserObjectSecurity
+GetWindow
+GetWindowContextHelpId
+GetWindowDC
+GetWindowInfo
+GetWindowLongA
+GetWindowLongW
+GetWindowModuleFileNameA
+GetWindowModuleFileNameW
+GetWindowPlacement
+GetWindowRect
+GetWindowRgn
+GetWindowTextA
+GetWindowTextLengthA
+GetWindowTextLengthW
+GetWindowTextW
+GetWindowThreadProcessId
+GetWindowWord
+GrayStringA
+GrayStringW
+HasSystemSleepStarted
+HideCaret
+HiliteMenuItem
+IMPGetIMEA
+IMPGetIMEW
+IMPQueryIMEA
+IMPQueryIMEW
+IMPSetIMEA
+IMPSetIMEW
+ImpersonateDdeClientWindow
+InSendMessage
+InSendMessageEx
+InflateRect
+InitSharedTable
+InitTask
+InsertMenuA
+InsertMenuItemA
+InsertMenuItemW
+InsertMenuW
+InternalGetWindowText
+IntersectRect
+InvalidateRect
+InvalidateRgn
+InvertRect
+IsCharAlphaA
+IsCharAlphaNumericA
+IsCharAlphaNumericW
+IsCharAlphaW
+IsCharLowerA
+IsCharLowerW
+IsCharUpperA
+IsCharUpperW
+IsChild
+IsClipboardFormatAvailable
+IsDialogMessage
+IsDialogMessageA
+IsDialogMessageW
+IsDlgButtonChecked
+IsHungThread
+IsIconic
+IsMenu
+IsRectEmpty
+IsWindow
+IsWindowEnabled
+IsWindowUnicode
+IsWindowVisible
+IsZoomed
+KillTimer
+LoadAcceleratorsA
+LoadAcceleratorsW
+LoadBitmapA
+LoadBitmapW
+LoadCursorA
+LoadCursorFromFileA
+LoadCursorFromFileW
+LoadCursorW
+LoadIconA
+LoadIconW
+LoadImageA
+LoadImageW
+LoadKeyboardLayoutA
+LoadKeyboardLayoutW
+LoadMenuA
+LoadMenuIndirectA
+LoadMenuIndirectW
+LoadMenuW
+LoadStringA
+LoadStringW
+LockSetForegroundWindow
+LockWindowStation
+LockWindowUpdate
+LookupIconIdFromDirectory
+LookupIconIdFromDirectoryEx
+MapDialogRect
+MapVirtualKeyA
+MapVirtualKeyExA
+MapVirtualKeyExW
+MapVirtualKeyW
+MapWindowPoints
+MenuItemFromPoint
+MessageBeep
+MessageBoxA
+MessageBoxExA
+MessageBoxExW
+MessageBoxIndirectA
+MessageBoxIndirectW
+MessageBoxW
+ModifyAccess
+ModifyMenuA
+ModifyMenuW
+MonitorFromPoint
+MonitorFromRect
+MonitorFromWindow
+MoveWindow
+MsgWaitForMultipleObjects
+MsgWaitForMultipleObjectsEx
+NotifyWinEvent
+OemKeyScan
+OemToCharA
+OemToCharBuffA
+OemToCharBuffW
+OemToCharW
+OffsetRect
+OpenClipboard
+OpenDesktopA
+OpenDesktopW
+OpenIcon
+OpenInputDesktop
+OpenWindowStationA
+OpenWindowStationW
+PackDDElParam
+PaintDesktop
+PeekMessageA
+PeekMessageW
+PlaySoundEvent
+PostMessageA
+PostMessageW
+PostQuitMessage
+PostThreadMessageA
+PostThreadMessageW
+PtInRect
+RealChildWindowFromPoint
+RealGetWindowClass
+RedrawWindow
+RegisterClassA
+RegisterClassExA
+RegisterClassExW
+RegisterClassW
+RegisterClipboardFormatA
+RegisterClipboardFormatW
+RegisterDeviceNotificationA
+RegisterDeviceNotificationW
+RegisterHotKey
+RegisterLogonProcess
+RegisterNetworkCapabilities
+RegisterSystemThread
+RegisterTasklist
+RegisterWindowMessageA
+RegisterWindowMessageW
+ReleaseCapture
+ReleaseDC
+RemoveMenu
+RemovePropA
+RemovePropW
+ReplyMessage
+ReuseDDElParam
+ScreenToClient
+ScrollDC
+ScrollWindow
+ScrollWindowEx
+SendDlgItemMessageA
+SendDlgItemMessageW
+SendIMEMessageExA
+SendIMEMessageExW
+SendInput
+SendMessageA
+SendMessageCallbackA
+SendMessageCallbackW
+SendMessageTimeoutA
+SendMessageTimeoutW
+SendMessageW
+SendNotifyMessageA
+SendNotifyMessageW
+SetActiveWindow
+SetCapture
+SetCaretBlinkTime
+SetCaretPos
+SetClassLongA
+SetClassLongW
+SetClassWord
+SetClipboardData
+SetClipboardViewer
+SetCursor
+SetCursorPos
+SetDebugErrorLevel
+SetDeskWallpaper
+SetDesktopBitmap
+SetDlgItemInt
+SetDlgItemTextA
+SetDlgItemTextW
+SetDoubleClickTime
+SetFocus
+SetForegroundWindow
+SetInternalWindowPos
+SetKeyboardState
+SetLastErrorEx
+SetLogonNotifyWindow
+SetMenu
+SetMenuContextHelpId
+SetMenuDefaultItem
+SetMenuInfo
+SetMenuItemBitmaps
+SetMenuItemInfoA
+SetMenuItemInfoW
+SetMessageExtraInfo
+SetMessageQueue
+SetParent
+SetProcessDefaultLayout
+SetProcessWindowStation
+SetPropA
+SetPropW
+SetRect
+SetRectEmpty
+SetScrollInfo
+SetScrollPos
+SetScrollRange
+SetShellWindow
+SetSysColors
+SetSysColorsTemp
+SetSystemCursor
+SetThreadDesktop
+SetTimer
+SetUserObjectInformationA
+SetUserObjectInformationW
+SetUserObjectSecurity
+SetWinEventHook
+SetWindowContextHelpId
+SetWindowFullScreenState
+SetWindowLongA
+SetWindowLongW
+SetWindowPlacement
+SetWindowPos
+SetWindowRgn
+SetWindowTextA
+SetWindowTextW
+SetWindowWord
+SetWindowsHookA
+SetWindowsHookExA
+SetWindowsHookExW
+SetWindowsHookW
+ShowCaret
+ShowCursor
+ShowOwnedPopups
+ShowScrollBar
+ShowWindow
+ShowWindowAsync
+SubtractRect
+SwapMouseButton
+SwitchDesktop
+SwitchToThisWindow
+SysErrorBox
+SystemParametersInfoA
+SystemParametersInfoW
+TabbedTextOutA
+TabbedTextOutW
+TileChildWindows
+TileWindows
+ToAscii
+ToAsciiEx
+ToUnicode
+ToUnicodeEx
+TrackMouseEvent
+TrackPopupMenu
+TrackPopupMenuEx
+TranslateAccelerator
+TranslateAcceleratorA
+TranslateAcceleratorW
+TranslateMDISysAccel
+TranslateMessage
+UnhookWinEvent
+UnhookWindowsHook
+UnhookWindowsHookEx
+UnionRect
+UnloadKeyboardLayout
+UnlockWindowStation
+UnpackDDElParam
+UnregisterClassA
+UnregisterClassW
+UnregisterDeviceNotification
+UnregisterHotKey
+UpdateWindow
+UserClientDllInitialize
+UserIsSystemResumeAutomatic
+UserSetDeviceHoldState
+UserSignalProc
+UserTickleTimer
+ValidateRect
+ValidateRgn
+VkKeyScanA
+VkKeyScanExA
+VkKeyScanExW
+VkKeyScanW
+WINNLSEnableIME
+WINNLSGetEnableStatus
+WINNLSGetIMEHotkey
+WNDPROC_CALLBACK
+WaitForInputIdle
+WaitMessage
+WinHelpA
+WinHelpW
+WinOldAppHackoMatic
+WindowFromDC
+WindowFromPoint
+YieldTask
+_SetProcessDefaultLayout
+keybd_event
+mouse_event
+wsprintfA
+wsprintfW
+wvsprintfA
+wvsprintfW
diff --git a/tinyc/win32/lib/wincrt1.c b/tinyc/win32/lib/wincrt1.c
new file mode 100644
index 000000000..98edb6b9b
--- /dev/null
+++ b/tinyc/win32/lib/wincrt1.c
@@ -0,0 +1,49 @@
+//+---------------------------------------------------------------------------
+
+#include <windows.h>
+
+#define __UNKNOWN_APP    0
+#define __CONSOLE_APP    1
+#define __GUI_APP        2
+void __set_app_type(int);
+void _controlfp(unsigned a, unsigned b);
+
+int _winstart(void)
+{
+	char *szCmd; STARTUPINFO startinfo;
+
+	__set_app_type(__GUI_APP);
+	_controlfp(0x10000, 0x30000);
+
+	szCmd = GetCommandLine();
+	if (szCmd)
+	{
+		while (' ' == *szCmd) szCmd++;
+		if ('\"' == *szCmd)
+		{
+			while (*++szCmd)
+				if ('\"' == *szCmd) { szCmd++; break; }
+		}
+		else
+		{
+			while (*szCmd && ' ' != *szCmd) szCmd++;
+		}
+		while (' ' == *szCmd) szCmd++;
+	}
+
+	GetStartupInfo(&startinfo);
+	exit(WinMain(GetModuleHandle(NULL), NULL, szCmd,
+		(startinfo.dwFlags & STARTF_USESHOWWINDOW) ?
+			startinfo.wShowWindow : SW_SHOWDEFAULT));
+}
+
+int _runwinmain(int argc, char **argv)
+{
+	char *szCmd = NULL;
+	char *p = GetCommandLine();
+	if (argc > 1) szCmd = strstr(p, argv[1]);
+	if (NULL == szCmd) szCmd = "";
+	else if (szCmd > p && szCmd[-1] == '\"') --szCmd;
+	return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
+}
+
diff --git a/tinyc/win32/libtcc/libtcc.a b/tinyc/win32/libtcc/libtcc.a
new file mode 100644
index 000000000..c2d107453
--- /dev/null
+++ b/tinyc/win32/libtcc/libtcc.a
Binary files differdiff --git a/tinyc/win32/libtcc/libtcc.h b/tinyc/win32/libtcc/libtcc.h
new file mode 100644
index 000000000..96070e299
--- /dev/null
+++ b/tinyc/win32/libtcc/libtcc.h
@@ -0,0 +1,108 @@
+#ifndef LIBTCC_H
+#define LIBTCC_H
+
+#ifdef LIBTCC_AS_DLL
+#define LIBTCCAPI __declspec(dllexport)
+#else
+#define LIBTCCAPI
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct TCCState;
+
+typedef struct TCCState TCCState;
+
+/* create a new TCC compilation context */
+LIBTCCAPI TCCState *tcc_new(void);
+
+/* free a TCC compilation context */
+LIBTCCAPI void tcc_delete(TCCState *s);
+
+/* add debug information in the generated code */
+LIBTCCAPI void tcc_enable_debug(TCCState *s);
+
+/* set error/warning display callback */
+LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
+                        void (*error_func)(void *opaque, const char *msg));
+
+/* set/reset a warning */
+LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value);
+
+/*****************************/
+/* preprocessor */
+
+/* add include path */
+LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
+
+/* add in system include path */
+LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
+
+/* define preprocessor symbol 'sym'. Can put optional value */
+LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
+
+/* undefine preprocess symbol 'sym' */
+LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
+
+/*****************************/
+/* compiling */
+
+/* add a file (either a C file, dll, an object, a library or an ld
+   script). Return -1 if error. */
+LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
+
+/* compile a string containing a C source. Return non zero if
+   error. */
+LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
+
+/*****************************/
+/* linking commands */
+
+/* set output type. MUST BE CALLED before any compilation */
+#define TCC_OUTPUT_MEMORY   0 /* output will be ran in memory (no
+                                 output file) (default) */
+#define TCC_OUTPUT_EXE      1 /* executable file */
+#define TCC_OUTPUT_DLL      2 /* dynamic library */
+#define TCC_OUTPUT_OBJ      3 /* object file */
+#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */
+LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
+
+#define TCC_OUTPUT_FORMAT_ELF    0 /* default output format: ELF */
+#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
+#define TCC_OUTPUT_FORMAT_COFF   2 /* COFF */
+
+/* equivalent to -Lpath option */
+LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
+
+/* the library name is the same as the argument of the '-l' option */
+LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
+
+/* add a symbol to the compiled program */
+LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, void *val);
+
+/* output an executable, library or object file. DO NOT call
+   tcc_relocate() before. */
+LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
+
+/* link and run main() function and return its value. DO NOT call
+   tcc_relocate() before. */
+LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
+
+/* copy code into memory passed in by the caller and do all relocations
+   (needed before using tcc_get_symbol()).
+   returns -1 on error and required size if ptr is NULL */
+LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
+
+/* return symbol value or NULL if not found */
+LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
+
+/* set CONFIG_TCCDIR at runtime */
+LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tinyc/win32/tcc-win32.txt b/tinyc/win32/tcc-win32.txt
new file mode 100644
index 000000000..5b8ddb404
--- /dev/null
+++ b/tinyc/win32/tcc-win32.txt
@@ -0,0 +1,158 @@
+
+    TinyCC
+    ======
+
+    This file contains specific information for usage of TinyCC
+    under MS-Windows.  See tcc-doc.html to have all the features.
+
+
+
+    Compilation from source:
+    ------------------------
+    * You can use the MinGW and MSYS tools available at
+
+    	http://www.mingw.org
+
+    Untar the TCC archive and type in the MSYS shell:
+    
+       ./configure
+       make
+       make install 
+
+    The default install location is c:\Program Files\tcc
+
+
+    * Alternatively you can compile TCC with just GCC from MinGW using
+
+	win32\build-tcc.bat
+
+    To install, copy the entire contents of the win32 directory to
+    where you want.
+
+
+
+    Installation from the binary ZIP package:
+    -----------------------------------------
+    Unzip the package to a directory of your choice.
+    
+    (Note that the binary package does not include libtcc.  If you
+    want TCC as dynamic code generator, please use the source code
+    distribution.)
+
+
+
+    Set the system PATH:
+    --------------------
+    To be able to invoke the compiler from everywhere on your computer by
+    just typing "tcc", please add the directory containing tcc.exe to your
+    system PATH.
+
+
+
+    Examples:
+    ---------
+    Open a console window (DOS box) and 'cd' to the examples directory.
+
+    For the 'Fibonacci' example type:
+
+	tcc fib.c
+
+    For the 'Hello Windows' GUI example type:
+
+	tcc hello_win.c
+
+    for the 'Hello DLL' example type
+
+	tcc -shared dll.c
+	tiny_impdef dll.dll (optional)
+        tcc hello_dll.c dll.def
+
+
+
+    Import Definition Files:
+    ------------------------
+    To link with Windows system DLLs, TCC uses import definition
+    files (.def) instead of libraries.
+
+    The included 'tiny_impdef' program may be used to make additional 
+    .def files for any DLL. For example:
+
+        tiny_impdef.exe opengl32.dll
+
+    Put opengl32.def into the tcc/lib directory.  Specify -lopengl32 at
+    the TCC commandline to link a program that uses opengl32.dll.
+
+
+
+    Header Files:
+    -------------
+    The system header files (except _mingw.h) are from the MinGW
+    distribution:
+
+	http://www.mingw.org/
+
+    From the windows headers, only a minimal set is included.  If you need
+    more,  get MinGW's "w32api" package.
+
+
+
+    Resource Files:
+    ---------------
+    TCC can link windows resources in coff format as generated by MinGW's
+    windres.exe.  For example:
+
+        windres -O coff app.rc -o appres.o
+        tcc app.c appres.o -o app.exe
+
+
+
+    Tiny Libmaker:
+    --------------
+    The included tiny_libmaker tool by Timovj Lahde can be used as
+    'ar' replacement to make a library from several object files:
+
+	tiny_libmaker [rcs] library objectfiles ...
+
+
+
+    Limitations:
+    ------------
+    - On the object file level, currently TCC supports only the ELF format,
+      not COFF as used by MinGW and MSVC.  It is not possible to exchange
+      object files or libraries between TCC and these compilers.  However
+      libraries for TCC from objects by TCC can be made using tiny_libmaker
+      or MinGW's ar.
+
+    - No leading underscore is generated in the ELF symbols.
+
+    - With DLLs, only functions (not data) can be im-/exported.
+
+    - Bounds checking (option -b) is not supported currently.
+
+    - 64-bit systems are not (yet) supported.
+
+
+
+    Documentation and License:
+    --------------------------
+    TCC is distributed under the GNU Lesser General Public License. (See
+    COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)
+
+    TinyCC homepage is at:
+
+	http://fabrice.bellard.free.fr/tcc/
+
+
+
+    WinAPI Help and 3rd-party tools:
+    --------------------------------
+    The Windows API documentation (Win95) in a single .hlp file is
+    available on the lcc-win32 site as "win32hlp.exe" or from other
+    locations as "win32hlp_big.zip".
+
+    A nice RAD tool to create windows resources (dialog boxes etc.) is
+    "ResEd", available at the RadASM website.
+
+
+
+    --- grischka
diff --git a/tinyc/win32/tools/tiny_impdef.c b/tinyc/win32/tools/tiny_impdef.c
new file mode 100644
index 000000000..040c53acc
--- /dev/null
+++ b/tinyc/win32/tools/tiny_impdef.c
@@ -0,0 +1,393 @@
+/* -------------------------------------------------------------- */
+/*
+ * tiny_impdef creates an export definition file (.def) from a dll
+ * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
+ * 
+ *  Copyright (c) 2005,2007 grischka
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdio.h>
+
+/* Offset to PE file signature */
+#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a                +  \
+                        ((PIMAGE_DOS_HEADER)a)->e_lfanew))
+
+/* MS-OS header identifies the NT PEFile signature dword;
+   the PEFILE header exists just after that dword. */
+#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a               +  \
+                         ((PIMAGE_DOS_HEADER)a)->e_lfanew +  \
+                             SIZE_OF_NT_SIGNATURE))
+
+/* PE optional header is immediately after PEFile header. */
+#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a               +  \
+                         ((PIMAGE_DOS_HEADER)a)->e_lfanew +  \
+                           SIZE_OF_NT_SIGNATURE           +  \
+                           sizeof (IMAGE_FILE_HEADER)))
+
+/* Section headers are immediately after PE optional header. */
+#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a               +  \
+                         ((PIMAGE_DOS_HEADER)a)->e_lfanew +  \
+                           SIZE_OF_NT_SIGNATURE           +  \
+                           sizeof (IMAGE_FILE_HEADER)     +  \
+                           sizeof (IMAGE_OPTIONAL_HEADER)))
+
+
+#define SIZE_OF_NT_SIGNATURE 4
+
+/* -------------------------------------------------------------- */
+
+int WINAPI NumOfSections (
+    LPVOID lpFile)
+{
+    /* Number of sections is indicated in file header. */
+    return (int)
+        ((PIMAGE_FILE_HEADER)
+            PEFHDROFFSET(lpFile))->NumberOfSections;
+}
+
+
+/* -------------------------------------------------------------- */
+
+LPVOID WINAPI ImageDirectoryOffset (
+    LPVOID lpFile,
+    DWORD dwIMAGE_DIRECTORY)
+{
+    PIMAGE_OPTIONAL_HEADER poh;
+    PIMAGE_SECTION_HEADER psh;
+    int nSections = NumOfSections (lpFile);
+    int i = 0;
+    LPVOID VAImageDir;
+
+    /* Retrieve offsets to optional and section headers. */
+    poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
+    psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
+
+    /* Must be 0 thru (NumberOfRvaAndSizes-1). */
+    if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
+        return NULL;
+
+    /* Locate image directory's relative virtual address. */
+    VAImageDir = (LPVOID)poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;
+
+    /* Locate section containing image directory. */
+    while (i++<nSections)
+    {
+        if (psh->VirtualAddress <= (DWORD)VAImageDir
+         && psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
+            break;
+        psh++;
+    }
+
+    if (i > nSections)
+        return NULL;
+
+    /* Return image import directory offset. */
+    return (LPVOID)(((int)lpFile +
+                     (int)VAImageDir - psh->VirtualAddress) +
+                    (int)psh->PointerToRawData);
+}
+
+/* -------------------------------------------------------------- */
+
+BOOL WINAPI GetSectionHdrByName (
+    LPVOID lpFile,
+    IMAGE_SECTION_HEADER *sh,
+    char *szSection)
+{
+    PIMAGE_SECTION_HEADER psh;
+    int nSections = NumOfSections (lpFile);
+    int i;
+
+    if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
+    {
+        /* find the section by name */
+        for (i=0; i<nSections; i++)
+        {
+            if (!strcmp (psh->Name, szSection))
+            {
+                /* copy data to header */
+                memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
+                return TRUE;
+            }
+            else
+                psh++;
+        }
+    }
+    return FALSE;
+}
+
+/* -------------------------------------------------------------- */
+
+BOOL WINAPI GetSectionHdrByAddress (
+    LPVOID lpFile,
+    IMAGE_SECTION_HEADER *sh,
+    DWORD addr)
+{
+    PIMAGE_SECTION_HEADER psh;
+    int nSections = NumOfSections (lpFile);
+    int i;
+
+    if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
+    {
+        /* find the section by name */
+        for (i=0; i<nSections; i++)
+        {
+            if (addr >= psh->VirtualAddress
+             && addr < psh->VirtualAddress + psh->SizeOfRawData)
+            {
+                /* copy data to header */
+                memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
+                return TRUE;
+            }
+            else
+                psh++;
+        }
+    }
+    return FALSE;
+}
+
+/* -------------------------------------------------------------- */
+
+int  WINAPI GetExportFunctionNames (
+    LPVOID lpFile,
+    HANDLE hHeap,
+    char **pszFunctions)
+{
+    IMAGE_SECTION_HEADER sh;
+    PIMAGE_EXPORT_DIRECTORY ped;
+    int *pNames, *pCnt;
+    char *pSrc, *pDest;
+    int i, nCnt;
+    DWORD VAImageDir;
+    PIMAGE_OPTIONAL_HEADER poh;
+    char *pOffset;
+
+    /* Get section header and pointer to data directory
+       for .edata section. */
+    if (NULL == (ped = (PIMAGE_EXPORT_DIRECTORY)
+        ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)))
+        return 0;
+
+    poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
+    VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+
+    if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir))
+        return 0;
+
+    pOffset = (char *)lpFile + (sh.PointerToRawData -  sh.VirtualAddress);
+
+    pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames);
+
+    /* Figure out how much memory to allocate for all strings. */
+    nCnt = 1;
+    for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
+    {
+        pSrc = (pOffset + *pCnt++);
+        if (pSrc)
+            nCnt += strlen(pSrc)+1;
+    }
+
+    /* Allocate memory off heap for function names. */
+    pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
+
+    /* Copy all strings to buffer. */
+    for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
+    {
+        pSrc = (pOffset + *pCnt++);
+        if (pSrc) {
+            strcpy(pDest, pSrc);
+            pDest += strlen(pSrc)+1;
+        }
+    }
+    *pDest = 0;
+
+    return ped->NumberOfNames;
+}
+
+/* -------------------------------------------------------------- */
+/* extract the basename of a file */
+
+static char *file_basename(const char *name)
+{
+    const char *p = strchr(name, 0);
+    while (p > name
+        && p[-1] != '/'
+        && p[-1] != '\\'
+        )
+        --p;
+    return (char*)p;
+}
+
+/* -------------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+    HANDLE hHeap;
+    HANDLE hFile;
+    HANDLE hMapObject;
+    VOID *pMem;
+
+    int nCnt, ret, n;
+    char *pNames;
+    char infile[MAX_PATH];
+    char buffer[MAX_PATH];
+    char outfile[MAX_PATH];
+    FILE *op;
+    char *p;
+
+    hHeap = NULL;
+    hFile = NULL;
+    hMapObject = NULL;
+    pMem = NULL;
+    infile[0] = 0;
+    outfile[0] = 0;
+    ret = 1;
+
+    for (n = 1; n < argc; ++n)
+    {
+        const char *a = argv[n];
+        if ('-' == a[0]) {
+            if (0 == strcmp(a, "-o")) {
+                if (++n == argc)
+                    goto usage;
+                strcpy(outfile, argv[n]);
+            }
+            else
+                goto usage;
+
+        } else if (0 == infile[0])
+            strcpy(infile, a);
+        else
+            goto usage;
+    }
+
+    if (0 == infile[0])
+    {
+usage:
+        fprintf(stderr,
+            "tiny_impdef creates an export definition file (.def) from a dll\n"
+            "Usage: tiny_impdef library.dll [-o outputfile]\n"
+            );
+        goto the_end;
+    }
+
+    if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL))
+        strcpy(infile, buffer);
+
+    if (0 == outfile[0])
+    {
+        char *p;
+        strcpy(outfile, file_basename(infile));
+        p = strrchr(outfile, '.');
+        if (NULL == p)
+            p = strchr(outfile, 0);
+        strcpy(p, ".def");
+    }
+
+    hFile = CreateFile(
+        infile,
+        GENERIC_READ,
+        FILE_SHARE_READ,
+        NULL,
+        OPEN_EXISTING,
+        0,
+        NULL
+        );
+
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        fprintf(stderr, "No such file: %s\n", infile);
+        goto the_end;
+    }
+
+
+    hMapObject = CreateFileMapping(
+        hFile,
+        NULL,
+        PAGE_READONLY,
+        0, 0,
+        NULL
+        );
+
+    if (NULL == hMapObject)
+    {
+        fprintf(stderr, "Could not create file mapping: %s\n", infile);
+        goto the_end;
+    }
+
+    pMem = MapViewOfFile(
+        hMapObject,     // object to map view of
+        FILE_MAP_READ,  // read access
+        0,              // high offset:  map from
+        0,              // low offset:   beginning
+        0);             // default: map entire file
+
+    if (NULL == pMem)
+    {
+        fprintf(stderr, "Could not map view of file: %s\n", infile);
+        goto the_end;
+    }
+
+    if (0 != strncmp(NTSIGNATURE(pMem), "PE", 2))
+    {
+        fprintf(stderr, "Not a PE file: %s\n", infile);
+        goto the_end;
+    }
+
+
+    hHeap = GetProcessHeap();
+    nCnt = GetExportFunctionNames(pMem, hHeap, &pNames);
+    if (0 == nCnt) {
+        fprintf(stderr, "Could not get exported function names: %s\n", infile);
+        goto the_end;
+    }
+
+    printf("--> %s\n", infile);
+
+    op = fopen(outfile, "w");
+    if (NULL == op)
+    {
+        fprintf(stderr, "Could not create file: %s\n", outfile);
+        goto the_end;
+    }
+
+    printf("<-- %s\n", outfile);
+
+    fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(infile));
+    for (n = 0, p = pNames; n < nCnt; ++n)
+    {
+        fprintf(op, "%s\n", p);
+        while (*p++);
+    }
+    ret = 0;
+
+the_end:
+    if (pMem)
+        UnmapViewOfFile(pMem);
+
+    if (hMapObject)
+        CloseHandle(hMapObject);
+
+    if (hFile)
+        CloseHandle(hFile);
+
+    return ret;
+}
+
+/* -------------------------------------------------------------- */
diff --git a/tinyc/win32/tools/tiny_libmaker.c b/tinyc/win32/tools/tiny_libmaker.c
new file mode 100644
index 000000000..cf9ac67bc
--- /dev/null
+++ b/tinyc/win32/tools/tiny_libmaker.c
@@ -0,0 +1,310 @@
+/*
+ * This program is for making libtcc1.a without ar
+ * tiny_libmaker - tiny elf lib maker
+ * usage: tiny_libmaker [lib] files...
+ * Copyright (c) 2007 Timppa
+ *
+ * This program is free software but WITHOUT ANY WARRANTY
+ */ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <io.h> /* for mktemp */
+#endif
+
+/* #include "ar-elf.h" */
+/*  "ar-elf.h" */
+/* ELF_v1.2.pdf */
+typedef unsigned short int Elf32_Half;
+typedef int Elf32_Sword;
+typedef unsigned int Elf32_Word;
+typedef unsigned int Elf32_Addr;
+typedef unsigned int Elf32_Off;
+typedef unsigned short int Elf32_Section;
+
+#define EI_NIDENT 16
+typedef struct {
+    unsigned char e_ident[EI_NIDENT];
+    Elf32_Half e_type;
+    Elf32_Half e_machine;
+    Elf32_Word e_version;
+    Elf32_Addr e_entry;
+    Elf32_Off e_phoff;
+    Elf32_Off e_shoff;
+    Elf32_Word e_flags;
+    Elf32_Half e_ehsize;
+    Elf32_Half e_phentsize;
+    Elf32_Half e_phnum;
+    Elf32_Half e_shentsize;
+    Elf32_Half e_shnum;
+    Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+    Elf32_Word sh_name;
+    Elf32_Word sh_type;
+    Elf32_Word sh_flags;
+    Elf32_Addr sh_addr;
+    Elf32_Off sh_offset;
+    Elf32_Word sh_size;
+    Elf32_Word sh_link;
+    Elf32_Word sh_info;
+    Elf32_Word sh_addralign;
+    Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+#define SHT_NOBITS 8
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+
+typedef struct {
+    Elf32_Word st_name;
+    Elf32_Addr st_value;
+    Elf32_Word st_size;
+    unsigned char st_info;
+    unsigned char st_other;
+    Elf32_Half st_shndx;
+} Elf32_Sym;
+
+#define ELF32_ST_BIND(i) ((i)>>4)
+#define ELF32_ST_TYPE(i) ((i)&0xf)
+#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
+
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+#define STT_LOPROC 13
+#define STT_HIPROC 15
+
+#define STB_LOCAL 0
+#define STB_GLOBAL 1
+#define STB_WEAK 2
+#define STB_LOPROC 13
+#define STB_HIPROC 15
+
+typedef struct {
+    Elf32_Word p_type;
+    Elf32_Off p_offset;
+    Elf32_Addr p_vaddr;
+    Elf32_Addr p_paddr;
+    Elf32_Word p_filesz;
+    Elf32_Word p_memsz;
+    Elf32_Word p_flags;
+    Elf32_Word p_align;
+} Elf32_Phdr;
+/* "ar-elf.h" ends */
+
+#define ARMAG  "!<arch>\n"
+#define ARFMAG "`\n"
+
+typedef struct ArHdr {
+    char ar_name[16];
+    char ar_date[12];
+    char ar_uid[6];
+    char ar_gid[6];
+    char ar_mode[8];
+    char ar_size[10];
+    char ar_fmag[2];
+} ArHdr;
+
+
+unsigned long le2belong(unsigned long ul) {
+    return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
+        ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
+}
+
+ArHdr arhdr = {
+    "/               ",
+    "            ",
+    "0     ",
+    "0     ",
+    "0       ",
+    "          ",
+    ARFMAG
+    };
+
+ArHdr arhdro = {
+    "                ",
+    "            ",
+    "0     ",
+    "0     ",
+    "0       ",
+    "          ",
+    ARFMAG
+    };
+
+int main(int argc, char **argv)
+{
+    FILE *fi, *fh, *fo;
+    Elf32_Ehdr *ehdr;
+    Elf32_Shdr *shdr;
+    Elf32_Sym *sym;
+    int i, fsize, iarg;
+    char *buf, *shstr, *symtab = NULL, *strtab = NULL;
+    int symtabsize = 0, strtabsize = 0;
+    char *anames = NULL;
+    int *afpos = NULL;
+    int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
+    char afile[260], tfile[260], stmp[20];
+
+
+    strcpy(afile, "ar_test.a");
+    iarg = 1;
+
+    if (argc < 2)
+    {
+        printf("usage: tiny_libmaker [lib] file...\n");
+        return 1;
+    }
+    for (i=1; i<argc; i++) {
+        istrlen = strlen(argv[i]);
+        if (argv[i][istrlen-2] == '.') {
+            if(argv[i][istrlen-1] == 'a')
+                strcpy(afile, argv[i]);
+            else if(argv[i][istrlen-1] == 'o') {
+                iarg = i;
+                break;
+            }
+        }
+    }
+
+    strcpy(tfile, "./XXXXXX");
+    if (!mktemp(tfile) || (fo = fopen(tfile, "wb+")) == NULL)
+    {
+        fprintf(stderr, "Can't open temporary file %s\n", tfile);
+        return 2;
+    }
+
+    if ((fh = fopen(afile, "wb")) == NULL)
+    {
+        fprintf(stderr, "Can't open file %s \n", afile);
+        remove(tfile);
+        return 2;
+    }
+
+    funcmax = 250;
+    afpos = realloc(NULL, funcmax * sizeof *afpos); // 250 func
+    memcpy(&arhdro.ar_mode, "100666", 6);
+
+    //iarg = 1;
+    while (iarg < argc)
+    {
+        if (!strcmp(argv[iarg], "rcs")) {
+            iarg++;
+            continue;
+        }
+        if ((fi = fopen(argv[iarg], "rb")) == NULL)
+        {
+            fprintf(stderr, "Can't open  file %s \n", argv[iarg]);
+            remove(tfile);
+            return 2;
+        }
+        fseek(fi, 0, SEEK_END);
+        fsize = ftell(fi);
+        fseek(fi, 0, SEEK_SET);
+        buf = malloc(fsize + 1);
+        fread(buf, fsize, 1, fi);
+        fclose(fi);
+
+        printf("%s:\n", argv[iarg]);
+        // elf header
+        ehdr = (Elf32_Ehdr *)buf;
+        shdr = (Elf32_Shdr *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
+        shstr = (char *)(buf + shdr->sh_offset);
+        for (i = 0; i < ehdr->e_shnum; i++)
+        {
+            shdr = (Elf32_Shdr *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
+            if (!shdr->sh_offset) continue;
+            if (shdr->sh_type == SHT_SYMTAB)
+            {
+                symtab = (char *)(buf + shdr->sh_offset);
+                symtabsize = shdr->sh_size;
+            }
+            if (shdr->sh_type == SHT_STRTAB)
+            {
+                if (!strcmp(shstr + shdr->sh_name, ".strtab"))
+                {
+                    strtab = (char *)(buf + shdr->sh_offset);
+                    strtabsize = shdr->sh_size;
+                }
+            }
+        }
+
+        if (symtab && symtabsize)
+        {
+            int nsym = symtabsize / sizeof(Elf32_Sym);
+            //printf("symtab: info size shndx name\n");
+            for (i = 1; i < nsym; i++)
+            {
+                sym = (Elf32_Sym *) (symtab + i * sizeof(Elf32_Sym));
+                if (sym->st_shndx && (sym->st_info == 0x11 || sym->st_info == 0x12)) {
+                    //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
+                    istrlen = strlen(strtab + sym->st_name)+1;
+                    anames = realloc(anames, strpos+istrlen);
+                    strcpy(anames + strpos, strtab + sym->st_name);
+                    strpos += istrlen;
+                    if (++funccnt >= funcmax) {
+                        funcmax += 250;
+                        afpos = realloc(afpos, funcmax * sizeof *afpos); // 250 func more
+                    }
+                    afpos[funccnt] = fpos;
+                }
+            }
+        }
+        memset(&arhdro.ar_name, ' ', sizeof(arhdr.ar_name));
+        strcpy(arhdro.ar_name, argv[iarg]);
+        arhdro.ar_name[strlen(argv[iarg])] = '/';
+        sprintf(stmp, "%-10d", fsize);
+        memcpy(&arhdro.ar_size, stmp, 10);
+        fwrite(&arhdro, sizeof(arhdro), 1, fo);
+        fwrite(buf, fsize, 1, fo);
+        free(buf);
+        iarg++;
+        fpos += (fsize + sizeof(arhdro));
+    }
+    hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
+    if ((hofs & 1)) {   // align
+        hofs++;
+        fpos = 1;
+    } else fpos = 0;
+    // write header
+    fwrite("!<arch>\n", 8, 1, fh);
+    sprintf(stmp, "%-10d", strpos + (funccnt+1) * sizeof(int));
+    memcpy(&arhdr.ar_size, stmp, 10);
+    fwrite(&arhdr, sizeof(arhdr), 1, fh);
+    afpos[0] = le2belong(funccnt);
+    for (i=1; i<=funccnt; i++) {
+        afpos[i] = le2belong(afpos[i] + hofs);
+    }
+    fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
+    fwrite(anames, strpos, 1, fh);
+    if (fpos) fwrite("", 1, 1, fh);
+    // write objects
+    fseek(fo, 0, SEEK_END);
+    fsize = ftell(fo);
+    fseek(fo, 0, SEEK_SET);
+    buf = malloc(fsize + 1);
+    fread(buf, fsize, 1, fo);
+    fclose(fo);
+    fwrite(buf, fsize, 1, fh);
+    fclose(fh);
+    free(buf);
+    if (anames)
+        free(anames);
+    if (afpos)
+        free(afpos);
+    remove(tfile);
+    return 0;
+}
diff --git a/tinyc/x86_64-gen.c b/tinyc/x86_64-gen.c
new file mode 100644
index 000000000..1227f41f0
--- /dev/null
+++ b/tinyc/x86_64-gen.c
@@ -0,0 +1,1419 @@
+/*
+ *  x86-64 code generator for TCC
+ *
+ *  Copyright (c) 2008 Shinichiro Hamaji
+ *
+ *  Based on i386-gen.c by Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ */
+
+#include <assert.h>
+
+/* number of available registers */
+#define NB_REGS             5
+
+/* a register can belong to several classes. The classes must be
+   sorted from more general to more precise (see gv2() code which does
+   assumptions on it). */
+#define RC_INT     0x0001 /* generic integer register */
+#define RC_FLOAT   0x0002 /* generic float register */
+#define RC_RAX     0x0004
+#define RC_RCX     0x0008
+#define RC_RDX     0x0010
+#define RC_XMM0    0x0020
+#define RC_ST0     0x0040 /* only for long double */
+#define RC_IRET    RC_RAX /* function return: integer register */
+#define RC_LRET    RC_RDX /* function return: second integer register */
+#define RC_FRET    RC_XMM0 /* function return: float register */
+
+/* pretty names for the registers */
+enum {
+    TREG_RAX = 0,
+    TREG_RCX = 1,
+    TREG_RDX = 2,
+    TREG_RSI = 6,
+    TREG_RDI = 7,
+    TREG_R8  = 8,
+    TREG_R9  = 9,
+    TREG_R10 = 10,
+    TREG_R11 = 11,
+
+    TREG_XMM0 = 3,
+    TREG_ST0 = 4,
+
+    TREG_MEM = 0x10,
+};
+
+#define REX_BASE(reg) (((reg) >> 3) & 1)
+#define REG_VALUE(reg) ((reg) & 7)
+
+int reg_classes[NB_REGS] = {
+    /* eax */ RC_INT | RC_RAX,
+    /* ecx */ RC_INT | RC_RCX,
+    /* edx */ RC_INT | RC_RDX,
+    /* xmm0 */ RC_FLOAT | RC_XMM0,
+    /* st0 */ RC_ST0,
+};
+
+/* return registers for function */
+#define REG_IRET TREG_RAX /* single word int return register */
+#define REG_LRET TREG_RDX /* second word return register (for long long) */
+#define REG_FRET TREG_XMM0 /* float return register */
+
+/* defined if function parameters must be evaluated in reverse order */
+#define INVERT_FUNC_PARAMS
+
+/* pointer size, in bytes */
+#define PTR_SIZE 8
+
+/* long double size and alignment, in bytes */
+#define LDOUBLE_SIZE  16
+#define LDOUBLE_ALIGN 8
+/* maximum alignment (for aligned attribute support) */
+#define MAX_ALIGN     8
+
+/******************************************************/
+/* ELF defines */
+
+#define EM_TCC_TARGET EM_X86_64
+
+/* relocation type for 32 bit data relocation */
+#define R_DATA_32   R_X86_64_64
+#define R_JMP_SLOT  R_X86_64_JUMP_SLOT
+#define R_COPY      R_X86_64_COPY
+
+#define ELF_START_ADDR 0x08048000
+#define ELF_PAGE_SIZE  0x1000
+
+/******************************************************/
+
+static unsigned long func_sub_sp_offset;
+static int func_ret_sub;
+
+/* XXX: make it faster ? */
+void g(int c)
+{
+    int ind1;
+    ind1 = ind + 1;
+    if (ind1 > cur_text_section->data_allocated)
+        section_realloc(cur_text_section, ind1);
+    cur_text_section->data[ind] = c;
+    ind = ind1;
+}
+
+void o(unsigned int c)
+{
+    while (c) {
+        g(c);
+        c = c >> 8;
+    }
+}
+
+void gen_le32(int c)
+{
+    g(c);
+    g(c >> 8);
+    g(c >> 16);
+    g(c >> 24);
+}
+
+void gen_le64(int64_t c)
+{
+    g(c);
+    g(c >> 8);
+    g(c >> 16);
+    g(c >> 24);
+    g(c >> 32);
+    g(c >> 40);
+    g(c >> 48);
+    g(c >> 56);
+}
+
+/* output a symbol and patch all calls to it */
+void gsym_addr(int t, int a)
+{
+    int n, *ptr;
+    while (t) {
+        ptr = (int *)(cur_text_section->data + t);
+        n = *ptr; /* next value */
+        *ptr = a - t - 4;
+        t = n;
+    }
+}
+
+void gsym(int t)
+{
+    gsym_addr(t, ind);
+}
+
+/* psym is used to put an instruction with a data field which is a
+   reference to a symbol. It is in fact the same as oad ! */
+#define psym oad
+
+static int is64_type(int t)
+{
+    return ((t & VT_BTYPE) == VT_PTR ||
+            (t & VT_BTYPE) == VT_FUNC ||
+            (t & VT_BTYPE) == VT_LLONG);
+}
+
+static int is_sse_float(int t) {
+    int bt;
+    bt = t & VT_BTYPE;
+    return bt == VT_DOUBLE || bt == VT_FLOAT;
+}
+
+/* instruction + 4 bytes data. Return the address of the data */
+static int oad(int c, int s)
+{
+    int ind1;
+
+    o(c);
+    ind1 = ind + 4;
+    if (ind1 > cur_text_section->data_allocated)
+        section_realloc(cur_text_section, ind1);
+    *(int *)(cur_text_section->data + ind) = s;
+    s = ind;
+    ind = ind1;
+    return s;
+}
+
+/* output constant with relocation if 'r & VT_SYM' is true */
+static void gen_addr64(int r, Sym *sym, int64_t c)
+{
+    if (r & VT_SYM)
+        greloc(cur_text_section, sym, ind, R_X86_64_64);
+    gen_le64(c);
+}
+
+/* output constant with relocation if 'r & VT_SYM' is true */
+static void gen_addrpc32(int r, Sym *sym, int c)
+{
+    if (r & VT_SYM)
+        greloc(cur_text_section, sym, ind, R_X86_64_PC32);
+    gen_le32(c-4);
+}
+
+/* output got address with relocation */
+static void gen_gotpcrel(int r, Sym *sym, int c)
+{
+    Section *sr;
+    ElfW(Rela) *rel;
+    greloc(cur_text_section, sym, ind, R_X86_64_GOTPCREL);
+    sr = cur_text_section->reloc;
+    rel = (ElfW(Rela) *)(sr->data + sr->data_offset - sizeof(ElfW(Rela)));
+    rel->r_addend = -4;
+    gen_le32(0);
+
+    if (c) {
+        /* we use add c, %xxx for displacement */
+        o(0x48 + REX_BASE(r));
+        o(0x81);
+        o(0xc0 + REG_VALUE(r));
+        gen_le32(c);
+    }
+}
+
+static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got)
+{
+    op_reg = REG_VALUE(op_reg) << 3;
+    if ((r & VT_VALMASK) == VT_CONST) {
+        /* constant memory reference */
+        o(0x05 | op_reg);
+        if (is_got) {
+            gen_gotpcrel(r, sym, c);
+        } else {
+            gen_addrpc32(r, sym, c);
+        }
+    } else if ((r & VT_VALMASK) == VT_LOCAL) {
+        /* currently, we use only ebp as base */
+        if (c == (char)c) {
+            /* short reference */
+            o(0x45 | op_reg);
+            g(c);
+        } else {
+            oad(0x85 | op_reg, c);
+        }
+    } else if ((r & VT_VALMASK) >= TREG_MEM) {
+        if (c) {
+            g(0x80 | op_reg | REG_VALUE(r));
+            gen_le32(c);
+        } else {
+            g(0x00 | op_reg | REG_VALUE(r));
+        }
+    } else {
+        g(0x00 | op_reg | (r & VT_VALMASK));
+    }
+}
+
+/* generate a modrm reference. 'op_reg' contains the addtionnal 3
+   opcode bits */
+static void gen_modrm(int op_reg, int r, Sym *sym, int c)
+{
+    gen_modrm_impl(op_reg, r, sym, c, 0);
+}
+
+/* generate a modrm reference. 'op_reg' contains the addtionnal 3
+   opcode bits */
+static void gen_modrm64(int opcode, int op_reg, int r, Sym *sym, int c)
+{
+    int is_got;
+    int rex = 0x48 | (REX_BASE(op_reg) << 2);
+    if ((r & VT_VALMASK) != VT_CONST &&
+        (r & VT_VALMASK) != VT_LOCAL) {
+        rex |= REX_BASE(VT_VALMASK & r);
+    }
+    o(rex);
+    o(opcode);
+    is_got = (op_reg & TREG_MEM) && !(sym->type.t & VT_STATIC);
+    gen_modrm_impl(op_reg, r, sym, c, is_got);
+}
+
+
+/* load 'r' from value 'sv' */
+void load(int r, SValue *sv)
+{
+    int v, t, ft, fc, fr;
+    SValue v1;
+
+    fr = sv->r;
+    ft = sv->type.t;
+    fc = sv->c.ul;
+
+    /* we use indirect access via got */
+    if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) &&
+        (fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) {
+        /* use the result register as a temporal register */
+        int tr = r | TREG_MEM;
+        if (is_float(ft)) {
+            /* we cannot use float registers as a temporal register */
+            tr = get_reg(RC_INT) | TREG_MEM;
+        }
+        gen_modrm64(0x8b, tr, fr, sv->sym, 0);
+
+        /* load from the temporal register */
+        fr = tr | VT_LVAL;
+    }
+
+    v = fr & VT_VALMASK;
+    if (fr & VT_LVAL) {
+        if (v == VT_LLOCAL) {
+            v1.type.t = VT_PTR;
+            v1.r = VT_LOCAL | VT_LVAL;
+            v1.c.ul = fc;
+            load(r, &v1);
+            fr = r;
+        }
+        if ((ft & VT_BTYPE) == VT_FLOAT) {
+            o(0x6e0f66); /* movd */
+            r = 0;
+        } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
+            o(0x7e0ff3); /* movq */
+            r = 0;
+        } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+            o(0xdb); /* fldt */
+            r = 5;
+        } else if ((ft & VT_TYPE) == VT_BYTE) {
+            o(0xbe0f);   /* movsbl */
+        } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
+            o(0xb60f);   /* movzbl */
+        } else if ((ft & VT_TYPE) == VT_SHORT) {
+            o(0xbf0f);   /* movswl */
+        } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
+            o(0xb70f);   /* movzwl */
+        } else if (is64_type(ft)) {
+            gen_modrm64(0x8b, r, fr, sv->sym, fc);
+            return;
+        } else {
+            o(0x8b);   /* movl */
+        }
+        gen_modrm(r, fr, sv->sym, fc);
+    } else {
+        if (v == VT_CONST) {
+            if ((ft & VT_BTYPE) == VT_LLONG) {
+                assert(!(fr & VT_SYM));
+                o(0x48);
+                o(0xb8 + REG_VALUE(r)); /* mov $xx, r */
+                gen_addr64(fr, sv->sym, sv->c.ull);
+            } else {
+                if (fr & VT_SYM) {
+                    if (sv->sym->type.t & VT_STATIC) {
+                        o(0x8d48);
+                        o(0x05 + REG_VALUE(r) * 8); /* lea xx(%rip), r */
+                        gen_addrpc32(fr, sv->sym, fc);
+                    } else {
+                        o(0x8b48);
+                        o(0x05 + REG_VALUE(r) * 8); /* mov xx(%rip), r */
+                        gen_gotpcrel(r, sv->sym, fc);
+                    }
+                } else {
+                    o(0xb8 + REG_VALUE(r)); /* mov $xx, r */
+                    gen_le32(fc);
+                }
+            }
+        } else if (v == VT_LOCAL) {
+            o(0x48 | REX_BASE(r));
+            o(0x8d); /* lea xxx(%ebp), r */
+            gen_modrm(r, VT_LOCAL, sv->sym, fc);
+        } else if (v == VT_CMP) {
+            oad(0xb8 + r, 0); /* mov $0, r */
+            o(0x0f); /* setxx %br */
+            o(fc);
+            o(0xc0 + r);
+        } else if (v == VT_JMP || v == VT_JMPI) {
+            t = v & 1;
+            oad(0xb8 + r, t); /* mov $1, r */
+            o(0x05eb); /* jmp after */
+            gsym(fc);
+            oad(0xb8 + r, t ^ 1); /* mov $0, r */
+        } else if (v != r) {
+            if (r == TREG_XMM0) {
+                assert(v == TREG_ST0);
+                /* gen_cvt_ftof(VT_DOUBLE); */
+                o(0xf0245cdd); /* fstpl -0x10(%rsp) */
+                /* movsd -0x10(%rsp),%xmm0 */
+                o(0x44100ff2);
+                o(0xf024);
+            } else if (r == TREG_ST0) {
+                assert(v == TREG_XMM0);
+                /* gen_cvt_ftof(VT_LDOUBLE); */
+                /* movsd %xmm0,-0x10(%rsp) */
+                o(0x44110ff2);
+                o(0xf024);
+                o(0xf02444dd); /* fldl -0x10(%rsp) */
+            } else {
+                o(0x48 | REX_BASE(r) | (REX_BASE(v) << 2));
+                o(0x89);
+                o(0xc0 + r + v * 8); /* mov v, r */
+            }
+        }
+    }
+}
+
+/* store register 'r' in lvalue 'v' */
+void store(int r, SValue *v)
+{
+    int fr, bt, ft, fc;
+    int op64 = 0;
+    /* store the REX prefix in this variable when PIC is enabled */
+    int pic = 0;
+
+    ft = v->type.t;
+    fc = v->c.ul;
+    fr = v->r & VT_VALMASK;
+    bt = ft & VT_BTYPE;
+
+    /* we need to access the variable via got */
+    if (fr == VT_CONST && (v->r & VT_SYM)) {
+        /* mov xx(%rip), %r11 */
+        o(0x1d8b4c);
+        gen_gotpcrel(TREG_R11, v->sym, v->c.ul);
+        pic = is64_type(bt) ? 0x49 : 0x41;
+    }
+
+    /* XXX: incorrect if float reg to reg */
+    if (bt == VT_FLOAT) {
+        o(0x66);
+        o(pic);
+        o(0x7e0f); /* movd */
+        r = 0;
+    } else if (bt == VT_DOUBLE) {
+        o(0x66);
+        o(pic);
+        o(0xd60f); /* movq */
+        r = 0;
+    } else if (bt == VT_LDOUBLE) {
+        o(0xc0d9); /* fld %st(0) */
+        o(pic);
+        o(0xdb); /* fstpt */
+        r = 7;
+    } else {
+        if (bt == VT_SHORT)
+            o(0x66);
+        o(pic);
+        if (bt == VT_BYTE || bt == VT_BOOL)
+            o(0x88);
+        else if (is64_type(bt))
+            op64 = 0x89;
+        else
+            o(0x89);
+    }
+    if (pic) {
+        /* xxx r, (%r11) where xxx is mov, movq, fld, or etc */
+        if (op64)
+            o(op64);
+        o(3 + (r << 3));
+    } else if (op64) {
+        if (fr == VT_CONST ||
+            fr == VT_LOCAL ||
+            (v->r & VT_LVAL)) {
+            gen_modrm64(op64, r, v->r, v->sym, fc);
+        } else if (fr != r) {
+            /* XXX: don't we really come here? */
+            abort();
+            o(0xc0 + fr + r * 8); /* mov r, fr */
+        }
+    } else {
+        if (fr == VT_CONST ||
+            fr == VT_LOCAL ||
+            (v->r & VT_LVAL)) {
+            gen_modrm(r, v->r, v->sym, fc);
+        } else if (fr != r) {
+            /* XXX: don't we really come here? */
+            abort();
+            o(0xc0 + fr + r * 8); /* mov r, fr */
+        }
+    }
+}
+
+static void gadd_sp(int val)
+{
+    if (val == (char)val) {
+        o(0xc48348);
+        g(val);
+    } else {
+        oad(0xc48148, val); /* add $xxx, %rsp */
+    }
+}
+
+/* 'is_jmp' is '1' if it is a jump */
+static void gcall_or_jmp(int is_jmp)
+{
+    int r;
+    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+        /* constant case */
+        if (vtop->r & VT_SYM) {
+            /* relocation case */
+            greloc(cur_text_section, vtop->sym,
+                   ind + 1, R_X86_64_PC32);
+        } else {
+            /* put an empty PC32 relocation */
+            put_elf_reloc(symtab_section, cur_text_section,
+                          ind + 1, R_X86_64_PC32, 0);
+        }
+        oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
+    } else {
+        /* otherwise, indirect call */
+        r = TREG_R11;
+        load(r, vtop);
+        o(0x41); /* REX */
+        o(0xff); /* call/jmp *r */
+        o(0xd0 + REG_VALUE(r) + (is_jmp << 4));
+    }
+}
+
+static uint8_t arg_regs[6] = {
+    TREG_RDI, TREG_RSI, TREG_RDX, TREG_RCX, TREG_R8, TREG_R9
+};
+/* Generate function call. The function address is pushed first, then
+   all the parameters in call order. This functions pops all the
+   parameters and the function address. */
+void gfunc_call(int nb_args)
+{
+    int size, align, r, args_size, i, func_call;
+    Sym *func_sym;
+    SValue *orig_vtop;
+    int nb_reg_args = 0;
+    int nb_sse_args = 0;
+    int sse_reg, gen_reg;
+
+    /* calculate the number of integer/float arguments */
+    args_size = 0;
+    for(i = 0; i < nb_args; i++) {
+        if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) {
+            args_size += type_size(&vtop->type, &align);
+        } else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) {
+            args_size += 16;
+        } else if (is_sse_float(vtop[-i].type.t)) {
+            nb_sse_args++;
+            if (nb_sse_args > 8) args_size += 8;
+        } else {
+            nb_reg_args++;
+            if (nb_reg_args > 6) args_size += 8;
+        }
+    }
+
+    /* for struct arguments, we need to call memcpy and the function
+       call breaks register passing arguments we are preparing.
+       So, we process arguments which will be passed by stack first. */
+    orig_vtop = vtop;
+    gen_reg = nb_reg_args;
+    sse_reg = nb_sse_args;
+    /* adjust stack to align SSE boundary */
+    if (args_size &= 8) {
+        o(0x50); /* push $rax */
+    }
+    for(i = 0; i < nb_args; i++) {
+        if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
+            size = type_size(&vtop->type, &align);
+            /* align to stack align size */
+            size = (size + 3) & ~3;
+            /* allocate the necessary size on stack */
+            o(0x48);
+            oad(0xec81, size); /* sub $xxx, %rsp */
+            /* generate structure store */
+            r = get_reg(RC_INT);
+            o(0x48 + REX_BASE(r));
+            o(0x89); /* mov %rsp, r */
+            o(0xe0 + r);
+            {
+                /* following code breaks vtop[1] */
+                SValue tmp = vtop[1];
+                vset(&vtop->type, r | VT_LVAL, 0);
+                vswap();
+                vstore();
+                vtop[1] = tmp;
+            }
+            args_size += size;
+        } else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+            gv(RC_ST0);
+            size = LDOUBLE_SIZE;
+            oad(0xec8148, size); /* sub $xxx, %rsp */
+            o(0x7cdb); /* fstpt 0(%rsp) */
+            g(0x24);
+            g(0x00);
+            args_size += size;
+        } else if (is_sse_float(vtop->type.t)) {
+            int j = --sse_reg;
+            if (j >= 8) {
+                gv(RC_FLOAT);
+                o(0x50); /* push $rax */
+                /* movq %xmm0, (%rsp) */
+                o(0x04d60f66);
+                o(0x24);
+                args_size += 8;
+            }
+        } else {
+            int j = --gen_reg;
+            /* simple type */
+            /* XXX: implicit cast ? */
+            if (j >= 6) {
+                r = gv(RC_INT);
+                o(0x50 + r); /* push r */
+                args_size += 8;
+            }
+        }
+        vtop--;
+    }
+    vtop = orig_vtop;
+
+    /* then, we prepare register passing arguments.
+       Note that we cannot set RDX and RCX in this loop because gv()
+       may break these temporary registers. Let's use R10 and R11
+       instead of them */
+    gen_reg = nb_reg_args;
+    sse_reg = nb_sse_args;
+    for(i = 0; i < nb_args; i++) {
+        if ((vtop->type.t & VT_BTYPE) == VT_STRUCT ||
+            (vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+        } else if (is_sse_float(vtop->type.t)) {
+            int j = --sse_reg;
+            if (j < 8) {
+                gv(RC_FLOAT); /* only one float register */
+                /* movaps %xmm0, %xmmN */
+                o(0x280f);
+                o(0xc0 + (sse_reg << 3));
+            }
+        } else {
+            int j = --gen_reg;
+            /* simple type */
+            /* XXX: implicit cast ? */
+            if (j < 6) {
+                r = gv(RC_INT);
+                if (j < 2) {
+                    o(0x8948); /* mov */
+                    o(0xc0 + r * 8 + arg_regs[j]);
+                } else if (j < 4) {
+                    o(0x8949); /* mov */
+                    /* j=2: r10, j=3: r11 */
+                    o(0xc0 + r * 8 + j);
+                } else {
+                    o(0x8949); /* mov */
+                    /* j=4: r8, j=5: r9 */
+                    o(0xc0 + r * 8 + j - 4);
+                }
+            }
+        }
+        vtop--;
+    }
+
+    save_regs(0); /* save used temporary registers */
+
+    /* Copy R10 and R11 into RDX and RCX, respectively */
+    if (nb_reg_args > 2) {
+        o(0xd2894c); /* mov %r10, %rdx */
+        if (nb_reg_args > 3) {
+            o(0xd9894c); /* mov %r11, %rcx */
+        }
+    }
+
+    func_sym = vtop->type.ref;
+    func_call = FUNC_CALL(func_sym->r);
+    oad(0xb8, nb_sse_args < 8 ? nb_sse_args : 8); /* mov nb_sse_args, %eax */
+    gcall_or_jmp(0);
+    if (args_size)
+        gadd_sp(args_size);
+    vtop--;
+}
+
+#ifdef TCC_TARGET_PE
+/* XXX: support PE? */
+#warning "PE isn't tested at all"
+#define FUNC_PROLOG_SIZE 12
+#else
+#define FUNC_PROLOG_SIZE 11
+#endif
+
+static void push_arg_reg(int i) {
+    loc -= 8;
+    gen_modrm64(0x89, arg_regs[i], VT_LOCAL, NULL, loc);
+}
+
+/* generate function prolog of type 't' */
+void gfunc_prolog(CType *func_type)
+{
+    int i, addr, align, size, func_call;
+    int param_index, param_addr, reg_param_index, sse_param_index;
+    Sym *sym;
+    CType *type;
+
+    func_ret_sub = 0;
+
+    sym = func_type->ref;
+    func_call = FUNC_CALL(sym->r);
+    addr = PTR_SIZE * 2;
+    loc = 0;
+    ind += FUNC_PROLOG_SIZE;
+    func_sub_sp_offset = ind;
+
+    if (func_type->ref->c == FUNC_ELLIPSIS) {
+        int seen_reg_num, seen_sse_num, seen_stack_size;
+        seen_reg_num = seen_sse_num = 0;
+        /* frame pointer and return address */
+        seen_stack_size = PTR_SIZE * 2;
+        /* count the number of seen parameters */
+        sym = func_type->ref;
+        while ((sym = sym->next) != NULL) {
+            type = &sym->type;
+            if (is_sse_float(type->t)) {
+                if (seen_sse_num < 8) {
+                    seen_sse_num++;
+                } else {
+                    seen_stack_size += 8;
+                }
+            } else if ((type->t & VT_BTYPE) == VT_STRUCT) {
+                size = type_size(type, &align);
+                size = (size + 3) & ~3;
+                seen_stack_size += size;
+            } else if ((type->t & VT_BTYPE) == VT_LDOUBLE) {
+                seen_stack_size += LDOUBLE_SIZE;
+            } else {
+                if (seen_reg_num < 6) {
+                    seen_reg_num++;
+                } else {
+                    seen_stack_size += 8;
+                }
+            }
+        }
+
+        loc -= 16;
+        /* movl $0x????????, -0x10(%rbp) */
+        o(0xf045c7);
+        gen_le32(seen_reg_num * 8);
+        /* movl $0x????????, -0xc(%rbp) */
+        o(0xf445c7);
+        gen_le32(seen_sse_num * 16 + 48);
+        /* movl $0x????????, -0x8(%rbp) */
+        o(0xf845c7);
+        gen_le32(seen_stack_size);
+
+        /* save all register passing arguments */
+        for (i = 0; i < 8; i++) {
+            loc -= 16;
+            o(0xd60f66); /* movq */
+            gen_modrm(7 - i, VT_LOCAL, NULL, loc);
+            /* movq $0, loc+8(%rbp) */
+            o(0x85c748);
+            gen_le32(loc + 8);
+            gen_le32(0);
+        }
+        for (i = 0; i < 6; i++) {
+            push_arg_reg(5 - i);
+        }
+    }
+
+    sym = func_type->ref;
+    param_index = 0;
+    reg_param_index = 0;
+    sse_param_index = 0;
+
+    /* if the function returns a structure, then add an
+       implicit pointer parameter */
+    func_vt = sym->type;
+    if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
+        push_arg_reg(reg_param_index);
+        param_addr = loc;
+
+        func_vc = loc;
+        param_index++;
+        reg_param_index++;
+    }
+    /* define parameters */
+    while ((sym = sym->next) != NULL) {
+        type = &sym->type;
+        size = type_size(type, &align);
+        size = (size + 3) & ~3;
+        if (is_sse_float(type->t)) {
+            if (sse_param_index < 8) {
+                /* save arguments passed by register */
+                loc -= 8;
+                o(0xd60f66); /* movq */
+                gen_modrm(sse_param_index, VT_LOCAL, NULL, loc);
+                param_addr = loc;
+            } else {
+                param_addr = addr;
+                addr += size;
+            }
+            sse_param_index++;
+        } else if ((type->t & VT_BTYPE) == VT_STRUCT ||
+                   (type->t & VT_BTYPE) == VT_LDOUBLE) {
+            param_addr = addr;
+            addr += size;
+        } else {
+            if (reg_param_index < 6) {
+                /* save arguments passed by register */
+                push_arg_reg(reg_param_index);
+                param_addr = loc;
+            } else {
+                param_addr = addr;
+                addr += 8;
+            }
+            reg_param_index++;
+        }
+        sym_push(sym->v & ~SYM_FIELD, type,
+                 VT_LOCAL | VT_LVAL, param_addr);
+        param_index++;
+    }
+}
+
+/* generate function epilog */
+void gfunc_epilog(void)
+{
+    int v, saved_ind;
+
+    o(0xc9); /* leave */
+    if (func_ret_sub == 0) {
+        o(0xc3); /* ret */
+    } else {
+        o(0xc2); /* ret n */
+        g(func_ret_sub);
+        g(func_ret_sub >> 8);
+    }
+    /* align local size to word & save local variables */
+    v = (-loc + 15) & -16;
+    saved_ind = ind;
+    ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
+#ifdef TCC_TARGET_PE
+    if (v >= 4096) {
+        Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
+        oad(0xb8, v); /* mov stacksize, %eax */
+        oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
+        greloc(cur_text_section, sym, ind-4, R_X86_64_PC32);
+    } else
+#endif
+    {
+        o(0xe5894855);  /* push %rbp, mov %rsp, %rbp */
+        o(0xec8148);  /* sub rsp, stacksize */
+        gen_le32(v);
+#if FUNC_PROLOG_SIZE == 12
+        o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
+#endif
+    }
+    ind = saved_ind;
+}
+
+/* generate a jump to a label */
+int gjmp(int t)
+{
+    return psym(0xe9, t);
+}
+
+/* generate a jump to a fixed address */
+void gjmp_addr(int a)
+{
+    int r;
+    r = a - ind - 2;
+    if (r == (char)r) {
+        g(0xeb);
+        g(r);
+    } else {
+        oad(0xe9, a - ind - 5);
+    }
+}
+
+/* generate a test. set 'inv' to invert test. Stack entry is popped */
+int gtst(int inv, int t)
+{
+    int v, *p;
+
+    v = vtop->r & VT_VALMASK;
+    if (v == VT_CMP) {
+        /* fast case : can jump directly since flags are set */
+        g(0x0f);
+        t = psym((vtop->c.i - 16) ^ inv, t);
+    } else if (v == VT_JMP || v == VT_JMPI) {
+        /* && or || optimization */
+        if ((v & 1) == inv) {
+            /* insert vtop->c jump list in t */
+            p = &vtop->c.i;
+            while (*p != 0)
+                p = (int *)(cur_text_section->data + *p);
+            *p = t;
+            t = vtop->c.i;
+        } else {
+            t = gjmp(t);
+            gsym(vtop->c.i);
+        }
+    } else {
+        if (is_float(vtop->type.t) ||
+            (vtop->type.t & VT_BTYPE) == VT_LLONG) {
+            vpushi(0);
+            gen_op(TOK_NE);
+        }
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            /* constant jmp optimization */
+            if ((vtop->c.i != 0) != inv)
+                t = gjmp(t);
+        } else {
+            v = gv(RC_INT);
+            o(0x85);
+            o(0xc0 + v * 9);
+            g(0x0f);
+            t = psym(0x85 ^ inv, t);
+        }
+    }
+    vtop--;
+    return t;
+}
+
+/* generate an integer binary operation */
+void gen_opi(int op)
+{
+    int r, fr, opc, c;
+
+    switch(op) {
+    case '+':
+    case TOK_ADDC1: /* add with carry generation */
+        opc = 0;
+    gen_op8:
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST &&
+            !is64_type(vtop->type.t)) {
+            /* constant case */
+            vswap();
+            r = gv(RC_INT);
+            if (is64_type(vtop->type.t)) {
+                o(0x48 | REX_BASE(r));
+            }
+            vswap();
+            c = vtop->c.i;
+            if (c == (char)c) {
+                /* XXX: generate inc and dec for smaller code ? */
+                o(0x83);
+                o(0xc0 | (opc << 3) | REG_VALUE(r));
+                g(c);
+            } else {
+                o(0x81);
+                oad(0xc0 | (opc << 3) | REG_VALUE(r), c);
+            }
+        } else {
+            gv2(RC_INT, RC_INT);
+            r = vtop[-1].r;
+            fr = vtop[0].r;
+            if (opc != 7 ||
+                is64_type(vtop[0].type.t) || (vtop[0].type.t & VT_UNSIGNED) ||
+                is64_type(vtop[-1].type.t) || (vtop[-1].type.t & VT_UNSIGNED)) {
+                o(0x48 | REX_BASE(r) | (REX_BASE(fr) << 2));
+            }
+            o((opc << 3) | 0x01);
+            o(0xc0 + REG_VALUE(r) + REG_VALUE(fr) * 8);
+        }
+        vtop--;
+        if (op >= TOK_ULT && op <= TOK_GT) {
+            vtop->r = VT_CMP;
+            vtop->c.i = op;
+        }
+        break;
+    case '-':
+    case TOK_SUBC1: /* sub with carry generation */
+        opc = 5;
+        goto gen_op8;
+    case TOK_ADDC2: /* add with carry use */
+        opc = 2;
+        goto gen_op8;
+    case TOK_SUBC2: /* sub with carry use */
+        opc = 3;
+        goto gen_op8;
+    case '&':
+        opc = 4;
+        goto gen_op8;
+    case '^':
+        opc = 6;
+        goto gen_op8;
+    case '|':
+        opc = 1;
+        goto gen_op8;
+    case '*':
+        gv2(RC_INT, RC_INT);
+        r = vtop[-1].r;
+        fr = vtop[0].r;
+        if (is64_type(vtop[0].type.t) || (vtop[0].type.t & VT_UNSIGNED) ||
+            is64_type(vtop[-1].type.t) || (vtop[-1].type.t & VT_UNSIGNED)) {
+            o(0x48 | REX_BASE(fr) | (REX_BASE(r) << 2));
+        }
+        vtop--;
+        o(0xaf0f); /* imul fr, r */
+        o(0xc0 + fr + r * 8);
+        break;
+    case TOK_SHL:
+        opc = 4;
+        goto gen_shift;
+    case TOK_SHR:
+        opc = 5;
+        goto gen_shift;
+    case TOK_SAR:
+        opc = 7;
+    gen_shift:
+        opc = 0xc0 | (opc << 3);
+        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+            /* constant case */
+            vswap();
+            r = gv(RC_INT);
+            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+                o(0x48 | REX_BASE(r));
+                c = 0x3f;
+            } else {
+                c = 0x1f;
+            }
+            vswap();
+            c &= vtop->c.i;
+            o(0xc1); /* shl/shr/sar $xxx, r */
+            o(opc | r);
+            g(c);
+        } else {
+            /* we generate the shift in ecx */
+            gv2(RC_INT, RC_RCX);
+            r = vtop[-1].r;
+            if ((vtop[-1].type.t & VT_BTYPE) == VT_LLONG) {
+                o(0x48 | REX_BASE(r));
+            }
+            o(0xd3); /* shl/shr/sar %cl, r */
+            o(opc | r);
+        }
+        vtop--;
+        break;
+    case '/':
+    case TOK_UDIV:
+    case TOK_PDIV:
+    case '%':
+    case TOK_UMOD:
+    case TOK_UMULL:
+        /* first operand must be in eax */
+        /* XXX: need better constraint for second operand */
+        gv2(RC_RAX, RC_RCX);
+        r = vtop[-1].r;
+        fr = vtop[0].r;
+        vtop--;
+        save_reg(TREG_RDX);
+        if (op == TOK_UMULL) {
+            o(0xf7); /* mul fr */
+            o(0xe0 + fr);
+            vtop->r2 = TREG_RDX;
+            r = TREG_RAX;
+        } else {
+            if (op == TOK_UDIV || op == TOK_UMOD) {
+                o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
+                o(0xf0 + fr);
+            } else {
+                if ((vtop->type.t & VT_BTYPE) & VT_LLONG) {
+                    o(0x9948); /* cqto */
+                    o(0x48 + REX_BASE(fr));
+                } else {
+                    o(0x99); /* cltd */
+                }
+                o(0xf7); /* idiv fr, %eax */
+                o(0xf8 + fr);
+            }
+            if (op == '%' || op == TOK_UMOD)
+                r = TREG_RDX;
+            else
+                r = TREG_RAX;
+        }
+        vtop->r = r;
+        break;
+    default:
+        opc = 7;
+        goto gen_op8;
+    }
+}
+
+void gen_opl(int op)
+{
+    gen_opi(op);
+}
+
+/* generate a floating point operation 'v = t1 op t2' instruction. The
+   two operands are guaranted to have the same floating point type */
+/* XXX: need to use ST1 too */
+void gen_opf(int op)
+{
+    int a, ft, fc, swapped, r;
+    int float_type =
+        (vtop->type.t & VT_BTYPE) == VT_LDOUBLE ? RC_ST0 : RC_FLOAT;
+
+    /* convert constants to memory references */
+    if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
+        vswap();
+        gv(float_type);
+        vswap();
+    }
+    if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
+        gv(float_type);
+
+    /* must put at least one value in the floating point register */
+    if ((vtop[-1].r & VT_LVAL) &&
+        (vtop[0].r & VT_LVAL)) {
+        vswap();
+        gv(float_type);
+        vswap();
+    }
+    swapped = 0;
+    /* swap the stack if needed so that t1 is the register and t2 is
+       the memory reference */
+    if (vtop[-1].r & VT_LVAL) {
+        vswap();
+        swapped = 1;
+    }
+    if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+        if (op >= TOK_ULT && op <= TOK_GT) {
+            /* load on stack second operand */
+            load(TREG_ST0, vtop);
+            save_reg(TREG_RAX); /* eax is used by FP comparison code */
+            if (op == TOK_GE || op == TOK_GT)
+                swapped = !swapped;
+            else if (op == TOK_EQ || op == TOK_NE)
+                swapped = 0;
+            if (swapped)
+                o(0xc9d9); /* fxch %st(1) */
+            o(0xe9da); /* fucompp */
+            o(0xe0df); /* fnstsw %ax */
+            if (op == TOK_EQ) {
+                o(0x45e480); /* and $0x45, %ah */
+                o(0x40fC80); /* cmp $0x40, %ah */
+            } else if (op == TOK_NE) {
+                o(0x45e480); /* and $0x45, %ah */
+                o(0x40f480); /* xor $0x40, %ah */
+                op = TOK_NE;
+            } else if (op == TOK_GE || op == TOK_LE) {
+                o(0x05c4f6); /* test $0x05, %ah */
+                op = TOK_EQ;
+            } else {
+                o(0x45c4f6); /* test $0x45, %ah */
+                op = TOK_EQ;
+            }
+            vtop--;
+            vtop->r = VT_CMP;
+            vtop->c.i = op;
+        } else {
+            /* no memory reference possible for long double operations */
+            load(TREG_ST0, vtop);
+            swapped = !swapped;
+
+            switch(op) {
+            default:
+            case '+':
+                a = 0;
+                break;
+            case '-':
+                a = 4;
+                if (swapped)
+                    a++;
+                break;
+            case '*':
+                a = 1;
+                break;
+            case '/':
+                a = 6;
+                if (swapped)
+                    a++;
+                break;
+            }
+            ft = vtop->type.t;
+            fc = vtop->c.ul;
+            o(0xde); /* fxxxp %st, %st(1) */
+            o(0xc1 + (a << 3));
+            vtop--;
+        }
+    } else {
+        if (op >= TOK_ULT && op <= TOK_GT) {
+            /* if saved lvalue, then we must reload it */
+            r = vtop->r;
+            fc = vtop->c.ul;
+            if ((r & VT_VALMASK) == VT_LLOCAL) {
+                SValue v1;
+                r = get_reg(RC_INT);
+                v1.type.t = VT_INT;
+                v1.r = VT_LOCAL | VT_LVAL;
+                v1.c.ul = fc;
+                load(r, &v1);
+                fc = 0;
+            }
+
+            if (op == TOK_EQ || op == TOK_NE) {
+                swapped = 0;
+            } else {
+                if (op == TOK_LE || op == TOK_LT)
+                    swapped = !swapped;
+                if (op == TOK_LE || op == TOK_GE) {
+                    op = 0x93; /* setae */
+                } else {
+                    op = 0x97; /* seta */
+                }
+            }
+
+            if (swapped) {
+                o(0x7e0ff3); /* movq */
+                gen_modrm(1, r, vtop->sym, fc);
+
+                if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
+                    o(0x66);
+                }
+                o(0x2e0f); /* ucomisd %xmm0, %xmm1 */
+                o(0xc8);
+            } else {
+                if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) {
+                    o(0x66);
+                }
+                o(0x2e0f); /* ucomisd */
+                gen_modrm(0, r, vtop->sym, fc);
+            }
+
+            vtop--;
+            vtop->r = VT_CMP;
+            vtop->c.i = op;
+        } else {
+            /* no memory reference possible for long double operations */
+            if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
+                load(TREG_XMM0, vtop);
+                swapped = !swapped;
+            }
+            switch(op) {
+            default:
+            case '+':
+                a = 0;
+                break;
+            case '-':
+                a = 4;
+                break;
+            case '*':
+                a = 1;
+                break;
+            case '/':
+                a = 6;
+                break;
+            }
+            ft = vtop->type.t;
+            fc = vtop->c.ul;
+            if ((ft & VT_BTYPE) == VT_LDOUBLE) {
+                o(0xde); /* fxxxp %st, %st(1) */
+                o(0xc1 + (a << 3));
+            } else {
+                /* if saved lvalue, then we must reload it */
+                r = vtop->r;
+                if ((r & VT_VALMASK) == VT_LLOCAL) {
+                    SValue v1;
+                    r = get_reg(RC_INT);
+                    v1.type.t = VT_INT;
+                    v1.r = VT_LOCAL | VT_LVAL;
+                    v1.c.ul = fc;
+                    load(r, &v1);
+                    fc = 0;
+                }
+                if (swapped) {
+                    /* movq %xmm0,%xmm1 */
+                    o(0x7e0ff3);
+                    o(0xc8);
+                    load(TREG_XMM0, vtop);
+                    /* subsd  %xmm1,%xmm0 (f2 0f 5c c1) */
+                    if ((ft & VT_BTYPE) == VT_DOUBLE) {
+                        o(0xf2);
+                    } else {
+                        o(0xf3);
+                    }
+                    o(0x0f);
+                    o(0x58 + a);
+                    o(0xc1);
+                } else {
+                    if ((ft & VT_BTYPE) == VT_DOUBLE) {
+                        o(0xf2);
+                    } else {
+                        o(0xf3);
+                    }
+                    o(0x0f);
+                    o(0x58 + a);
+                    gen_modrm(0, r, vtop->sym, fc);
+                }
+            }
+            vtop--;
+        }
+    }
+}
+
+/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
+   and 'long long' cases. */
+void gen_cvt_itof(int t)
+{
+    if ((t & VT_BTYPE) == VT_LDOUBLE) {
+        save_reg(TREG_ST0);
+        gv(RC_INT);
+        if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
+            /* signed long long to float/double/long double (unsigned case
+               is handled generically) */
+            o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
+            o(0x242cdf); /* fildll (%rsp) */
+            o(0x08c48348); /* add $8, %rsp */
+        } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
+                   (VT_INT | VT_UNSIGNED)) {
+            /* unsigned int to float/double/long double */
+            o(0x6a); /* push $0 */
+            g(0x00);
+            o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
+            o(0x242cdf); /* fildll (%rsp) */
+            o(0x10c48348); /* add $16, %rsp */
+        } else {
+            /* int to float/double/long double */
+            o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
+            o(0x2404db); /* fildl (%rsp) */
+            o(0x08c48348); /* add $8, %rsp */
+        }
+        vtop->r = TREG_ST0;
+    } else {
+        save_reg(TREG_XMM0);
+        gv(RC_INT);
+        o(0xf2 + ((t & VT_BTYPE) == VT_FLOAT));
+        if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
+            (VT_INT | VT_UNSIGNED) ||
+            (vtop->type.t & VT_BTYPE) == VT_LLONG) {
+            o(0x48); /* REX */
+        }
+        o(0x2a0f);
+        o(0xc0 + (vtop->r & VT_VALMASK)); /* cvtsi2sd */
+        vtop->r = TREG_XMM0;
+    }
+}
+
+/* convert from one floating point type to another */
+void gen_cvt_ftof(int t)
+{
+    int ft, bt, tbt;
+
+    ft = vtop->type.t;
+    bt = ft & VT_BTYPE;
+    tbt = t & VT_BTYPE;
+
+    if (bt == VT_FLOAT) {
+        gv(RC_FLOAT);
+        if (tbt == VT_DOUBLE) {
+            o(0xc0140f); /* unpcklps */
+            o(0xc05a0f); /* cvtps2pd */
+        } else if (tbt == VT_LDOUBLE) {
+            /* movss %xmm0,-0x10(%rsp) */
+            o(0x44110ff3);
+            o(0xf024);
+            o(0xf02444d9); /* flds -0x10(%rsp) */
+            vtop->r = TREG_ST0;
+        }
+    } else if (bt == VT_DOUBLE) {
+        gv(RC_FLOAT);
+        if (tbt == VT_FLOAT) {
+            o(0xc0140f66); /* unpcklpd */
+            o(0xc05a0f66); /* cvtpd2ps */
+        } else if (tbt == VT_LDOUBLE) {
+            /* movsd %xmm0,-0x10(%rsp) */
+            o(0x44110ff2);
+            o(0xf024);
+            o(0xf02444dd); /* fldl -0x10(%rsp) */
+            vtop->r = TREG_ST0;
+        }
+    } else {
+        gv(RC_ST0);
+        if (tbt == VT_DOUBLE) {
+            o(0xf0245cdd); /* fstpl -0x10(%rsp) */
+            /* movsd -0x10(%rsp),%xmm0 */
+            o(0x44100ff2);
+            o(0xf024);
+            vtop->r = TREG_XMM0;
+        } else if (tbt == VT_FLOAT) {
+            o(0xf0245cd9); /* fstps -0x10(%rsp) */
+            /* movss -0x10(%rsp),%xmm0 */
+            o(0x44100ff3);
+            o(0xf024);
+            vtop->r = TREG_XMM0;
+        }
+    }
+}
+
+/* convert fp to int 't' type */
+void gen_cvt_ftoi(int t)
+{
+    int ft, bt, size, r;
+    ft = vtop->type.t;
+    bt = ft & VT_BTYPE;
+    if (bt == VT_LDOUBLE) {
+        gen_cvt_ftof(VT_DOUBLE);
+        bt = VT_DOUBLE;
+    }
+
+    gv(RC_FLOAT);
+    if (t != VT_INT)
+        size = 8;
+    else
+        size = 4;
+
+    r = get_reg(RC_INT);
+    if (bt == VT_FLOAT) {
+        o(0xf3);
+    } else if (bt == VT_DOUBLE) {
+        o(0xf2);
+    } else {
+        assert(0);
+    }
+    if (size == 8) {
+        o(0x48 + REX_BASE(r));
+    }
+    o(0x2c0f); /* cvttss2si or cvttsd2si */
+    o(0xc0 + (REG_VALUE(r) << 3));
+    vtop->r = r;
+}
+
+/* computed goto support */
+void ggoto(void)
+{
+    gcall_or_jmp(1);
+    vtop--;
+}
+
+/* end of x86-64 code generator */
+/*************************************************************/
diff --git a/todo.txt b/todo.txt
new file mode 100644
index 000000000..4972015a7
--- /dev/null
+++ b/todo.txt
@@ -0,0 +1,103 @@
+version 0.11.2
+==============
+
+- The remaining bugs of the lambda lifting pass that is responsible to enable
+  closures and closure iterators need to be fixed.
+- ``concept`` needs to be refined, a nice name for the feature is not enough.
+- Destructors need to be refined.
+- make '--implicitStatic:on' the default; then we can also clean up the
+  'static[T]' mess in the compiler!
+
+- Finish the implementation of the 'parallel' statement.
+- Deprecate ``immediate`` for templates and macros
+- special case varargs[untyped] and varargs[typed]
+- make 'nil' work for 'add':
+  - resizeString
+  - incrSeq
+  - addChar
+
+
+version 1.0
+===========
+
+- macro support for '='; bind '=' to a memory region
+- remove   echo $foo  gotcha
+- add "all threads are blocked" detection to 'spawn'
+- figure out why C++ bootstrapping is so much slower
+- nimsuggest: auto-completion needs to work in 'class' macros
+- The bitwise 'not' operator will be renamed to 'bnot' to
+  prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs!
+- iterators always require a return type
+- make nimble part of the distribution
+- split docgen into separate tool
+- special rule for ``[]=``, items, pairs
+- BUG: echo with template `$`*(info: TLineInfo): expr = toFileLineCol(info)
+
+
+Concurrency
+-----------
+
+- test 'deepCopy' for closures
+- implement 'foo[1..4] = spawn(f[4..7])'
+
+Low priority:
+- support for exception propagation? (hard to implement)
+- the copying of the 'ref Promise' into the thead local storage only
+  happens to work due to the write barrier's implementation
+
+
+Misc
+----
+
+- make tuple unpacking work in a non-var/let context
+- built-in 'getImpl'
+- prevent 'alloc(TypeWithGCedMemory)'
+
+
+Bugs
+====
+
+- VM: Pegs do not work at compile-time
+- VM: ptr/ref T cannot work in general
+- scopes are still broken for generic instantiation!
+- blocks can "export" an identifier but the CCG generates {} for them ...
+- ConcreteTypes in a 'case' means we don't check for duplicated case branches
+- typedesc matches a generic type T!
+
+
+version 0.9.x
+=============
+
+- pragmas need 'bindSym' support
+- allow simple read accesses to global variables --> difficult to ensure that
+  no data races happen
+- pragmas need re-work: 'push' is dangerous, 'hasPragma' does not work
+  reliably with user-defined pragmas
+- memory manager: add a measure of fragmentation
+- implement 'bits' pragmas
+- we need a magic thisModule symbol
+- optimize 'genericReset'; 'newException' leads to code bloat
+- The 'do' notation might be trimmed so that its only purpose is to pass
+  multiple multi line constructs to a macro.
+
+
+version 0.9.X
+=============
+
+- macros as type pragmas
+- document NimMain and check whether it works for threading
+
+GC
+==
+
+- hybrid GC
+- use big blocks in the allocator
+- provide tool/API to track leaks/object counts
+- resizing of strings/sequences could take into account the memory that
+  is allocated
+
+
+CGEN
+====
+- codegen should use "NIM_CAST" macro and respect aliasing rules for GCC
+- ``restrict`` pragma + backend support
diff --git a/tools/cmerge.nim b/tools/cmerge.nim
new file mode 100644
index 000000000..d2e540481
--- /dev/null
+++ b/tools/cmerge.nim
@@ -0,0 +1,40 @@
+# Simple tool to merge C projects into a single C file
+
+import os, sets, pegs
+
+type
+  ProcessResult = enum prSkipIncludeDir, prAddIncludeDir
+
+proc process(dir, infile: string, outfile: File, 
+             processed: var HashSet[string]): ProcessResult =
+  if processed.containsOrIncl(infile): return prSkipIncludeDir
+  let toProcess = dir / infile
+  if not existsFile(toProcess):
+    echo "Warning: could not process: ", toProcess
+    return prAddIncludeDir
+  echo "adding: ", toProcess
+  for line in lines(toProcess):
+    if line =~ peg"""s <- ig '#include' ig '"' {[^"]+} '"' ig
+                     comment <- '/*' !'*/'* '*/' / '//' .*
+                     ig <- (comment / \s+)* """:
+      # follow the include file:
+      if process(dir, matches[0], outfile, processed) == prAddIncludeDir:
+        writeln(outfile, line)
+    else:
+      writeln(outfile, line)
+
+proc main(dir, outfile: string) =
+  var o: File
+  if open(o, outfile, fmWrite):
+    var processed = initSet[string]()
+    processed.incl(outfile)
+    for infile in walkfiles(dir / "*.c"):
+      discard process(dir, extractFilename(infile), o, processed)
+    close(o)
+  else:
+    quit("Cannot open for writing: " & outfile)
+
+if paramCount() != 2:
+  quit "Usage: cmerge directory outfile"
+else:
+  main(paramStr(1), addFileExt(paramStr(2), "c"))
diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim
new file mode 100644
index 000000000..77efdaacd
--- /dev/null
+++ b/tools/detect/detect.nim
@@ -0,0 +1,831 @@
+# Posix detect program
+# (c) 2010 Andreas Rumpf
+
+# This program produces a C program that produces a Nim include file.
+# The Nim include file lists the values of each POSIX constant.
+# This is needed because POSIX is brain-dead: It only cares for C, any other
+# language is ignored. It would have been easier had they specified the
+# concrete values of the constants. Sigh.
+
+import os, strutils
+
+const
+  cc = "gcc -o $# $#.c"
+
+  cfile = """
+/* Generated by detect.nim */
+
+#include <stdlib.h>
+#include <stdio.h>
+$1
+
+int main() {
+  FILE* f;
+  f = fopen("$3_$4_consts.nim", "w+");
+  fputs("# Generated by detect.nim\nconst\n", f);
+  $2
+  fclose(f);
+}
+"""
+
+type
+  TTypeKind = enum 
+    cint, cshort, clong, cstring, pointer
+
+var
+  hd = ""
+  tl = ""
+
+proc myExec(cmd: string): bool = 
+  echo "CMD ", cmd
+  return execShellCmd(cmd) == 0
+
+proc header(s: string): bool = 
+  const testh = "testh"
+  var f: TFile
+  if open(f, addFileExt(testh, "c"), fmWrite):
+    f.write("#include $1\n" % s)
+    f.write("int main() { return 0; }\n")
+    close(f)
+    result = myExec(cc % [testh.addFileExt(ExeExt), testh])
+    removeFile(addFileExt(testh, "c"))
+  if result:
+    addf(hd, "#include $1\n", s)
+    echo("Found: ", s)
+  else:
+    echo("Not found: ", s)
+
+proc main = 
+  const gen = "genconsts"
+  var f: TFile
+  if open(f, addFileExt(gen, "c"), fmWrite): 
+    f.write(cfile % [hd, tl, system.hostOS, system.hostCPU])
+    close(f)
+  if not myExec(cc % [gen.addFileExt(ExeExt), gen]): quit(1)
+  when defined(windows):
+    if not myExec(gen.addFileExt(ExeExt)): quit(1)
+  else:
+    if not myExec("./" & gen): quit(1)
+  #removeFile(addFileExt(gen, "c"))
+  echo("Success")
+
+proc v(name: string, typ: TTypeKind=cint) = 
+  var n = if name[0] == '_': substr(name, 1) else: name
+  var t = $typ
+  case typ
+  of pointer: 
+    addf(tl, 
+      "#ifdef $3\n  fprintf(f, \"  $1* = cast[$2](%p)\\n\", $3);\n#endif\n", 
+      n, t, name)
+  
+  of cstring:
+    addf(tl, 
+      "#ifdef $3\n  fprintf(f, \"  $1* = $2(\\\"%s\\\")\\n\", $3);\n#endif\n",
+      n, t, name)
+  of clong:
+    addf(tl, 
+      "#ifdef $3\n  fprintf(f, \"  $1* = $2(%ld)\\n\", $3);\n#endif\n", 
+      n, t, name)  
+  else:  
+    addf(tl, 
+      "#ifdef $3\n  fprintf(f, \"  $1* = $2(%d)\\n\", $3);\n#endif\n", 
+      n, t, name)
+
+if header("<aio.h>"):
+  v("AIO_ALLDONE")
+  v("AIO_CANCELED")
+  v("AIO_NOTCANCELED")
+  v("LIO_NOP")
+  v("LIO_NOWAIT")
+  v("LIO_READ")
+  v("LIO_WAIT")
+  v("LIO_WRITE")
+
+if header("<dlfcn.h>"):
+  v("RTLD_LAZY")
+  v("RTLD_NOW")
+  v("RTLD_GLOBAL")
+  v("RTLD_LOCAL")
+
+if header("<errno.h>"):
+  v("E2BIG")
+  v("EACCES")
+  v("EADDRINUSE")
+  v("EADDRNOTAVAIL")
+  v("EAFNOSUPPORT")
+  v("EAGAIN")
+  v("EALREADY")
+  v("EBADF")
+  v("EBADMSG")
+  v("EBUSY")
+  v("ECANCELED")
+  v("ECHILD")
+  v("ECONNABORTED")
+  v("ECONNREFUSED")
+  v("ECONNRESET")
+  v("EDEADLK")
+  v("EDESTADDRREQ")
+  v("EDOM")
+  v("EDQUOT")
+  v("EEXIST")
+  v("EFAULT")
+  v("EFBIG")
+  v("EHOSTUNREACH")
+  v("EIDRM")
+  v("EILSEQ")
+  v("EINPROGRESS")
+  v("EINTR")
+  v("EINVAL")
+  v("EIO")
+  v("EISCONN")
+  v("EISDIR")
+  v("ELOOP")
+  v("EMFILE")
+  v("EMLINK")
+  v("EMSGSIZE")
+  v("EMULTIHOP")
+  v("ENAMETOOLONG")
+  v("ENETDOWN")
+  v("ENETRESET")
+  v("ENETUNREACH")
+  v("ENFILE")
+  v("ENOBUFS")
+  v("ENODATA")
+  v("ENODEV")
+  v("ENOENT")
+  v("ENOEXEC")
+  v("ENOLCK")
+  v("ENOLINK")
+  v("ENOMEM")
+  v("ENOMSG")
+  v("ENOPROTOOPT")
+  v("ENOSPC")
+  v("ENOSR")
+  v("ENOSTR")
+  v("ENOSYS")
+  v("ENOTCONN")
+  v("ENOTDIR")
+  v("ENOTEMPTY")
+  v("ENOTSOCK")
+  v("ENOTSUP")
+  v("ENOTTY")
+  v("ENXIO")
+  v("EOPNOTSUPP")
+  v("EOVERFLOW")
+  v("EPERM")
+  v("EPIPE")
+  v("EPROTO")
+  v("EPROTONOSUPPORT")
+  v("EPROTOTYPE")
+  v("ERANGE")
+  v("EROFS")
+  v("ESPIPE")
+  v("ESRCH")
+  v("ESTALE")
+  v("ETIME")
+  v("ETIMEDOUT")
+  v("ETXTBSY")
+  v("EWOULDBLOCK")
+  v("EXDEV")
+  
+if header("<fcntl.h>"):
+  v("F_DUPFD")
+  v("F_GETFD")
+  v("F_SETFD")
+  v("F_GETFL")
+  v("F_SETFL")
+  v("F_GETLK")
+  v("F_SETLK")
+  v("F_SETLKW")
+  v("F_GETOWN")
+  v("F_SETOWN")
+  v("FD_CLOEXEC")
+  v("F_RDLCK")
+  v("F_UNLCK")
+  v("F_WRLCK")
+  v("O_CREAT")
+  v("O_EXCL")
+  v("O_NOCTTY")
+  v("O_TRUNC")
+  v("O_APPEND")
+  v("O_DSYNC")
+  v("O_NONBLOCK")
+  v("O_RSYNC")
+  v("O_SYNC")
+  v("O_ACCMODE")
+  v("O_RDONLY")
+  v("O_RDWR")
+  v("O_WRONLY")
+  v("POSIX_FADV_NORMAL")
+  v("POSIX_FADV_SEQUENTIAL")
+  v("POSIX_FADV_RANDOM")
+  v("POSIX_FADV_WILLNEED")
+  v("POSIX_FADV_DONTNEED")
+  v("POSIX_FADV_NOREUSE")
+
+if header("<fenv.h>"):
+  v("FE_DIVBYZERO")
+  v("FE_INEXACT")
+  v("FE_INVALID")
+  v("FE_OVERFLOW")
+  v("FE_UNDERFLOW")
+  v("FE_ALL_EXCEPT")
+  v("FE_DOWNWARD")
+  v("FE_TONEAREST")
+  v("FE_TOWARDZERO")
+  v("FE_UPWARD")
+  v("FE_DFL_ENV", pointer)
+
+if header("<fmtmsg.h>"):
+  v("MM_HARD")
+  v("MM_SOFT")
+  v("MM_FIRM")
+  v("MM_APPL")
+  v("MM_UTIL")
+  v("MM_OPSYS")
+  v("MM_RECOVER")
+  v("MM_NRECOV")
+  v("MM_HALT")
+  v("MM_ERROR")
+  v("MM_WARNING")
+  v("MM_INFO")
+  v("MM_NOSEV")
+  v("MM_PRINT")
+  v("MM_CONSOLE")
+  v("MM_OK")
+  v("MM_NOTOK")
+  v("MM_NOMSG")
+  v("MM_NOCON")
+
+if header("<fnmatch.h>"):
+  v("FNM_NOMATCH")
+  v("FNM_PATHNAME")
+  v("FNM_PERIOD")
+  v("FNM_NOESCAPE")
+  v("FNM_NOSYS")
+
+if header("<ftw.h>"):
+  v("FTW_F")
+  v("FTW_D")
+  v("FTW_DNR")
+  v("FTW_DP")
+  v("FTW_NS")
+  v("FTW_SL")
+  v("FTW_SLN")
+  v("FTW_PHYS")
+  v("FTW_MOUNT")
+  v("FTW_DEPTH")
+  v("FTW_CHDIR")
+
+if header("<glob.h>"):
+  v("GLOB_APPEND")
+  v("GLOB_DOOFFS")
+  v("GLOB_ERR")
+  v("GLOB_MARK")
+  v("GLOB_NOCHECK")
+  v("GLOB_NOESCAPE")
+  v("GLOB_NOSORT")
+  v("GLOB_ABORTED")
+  v("GLOB_NOMATCH")
+  v("GLOB_NOSPACE")
+  v("GLOB_NOSYS")
+
+if header("<langinfo.h>"):
+  v("CODESET")
+  v("D_T_FMT")
+  v("D_FMT")
+  v("T_FMT")
+  v("T_FMT_AMPM")
+  v("AM_STR")
+  v("PM_STR")
+  v("DAY_1")
+  v("DAY_2")
+  v("DAY_3")
+  v("DAY_4")
+  v("DAY_5")
+  v("DAY_6")
+  v("DAY_7")
+  v("ABDAY_1")
+  v("ABDAY_2")
+  v("ABDAY_3")
+  v("ABDAY_4")
+  v("ABDAY_5")
+  v("ABDAY_6")
+  v("ABDAY_7")
+  v("MON_1")
+  v("MON_2")
+  v("MON_3")
+  v("MON_4")
+  v("MON_5")
+  v("MON_6")
+  v("MON_7")
+  v("MON_8")
+  v("MON_9")
+  v("MON_10")
+  v("MON_11")
+  v("MON_12")
+  v("ABMON_1")
+  v("ABMON_2")
+  v("ABMON_3")
+  v("ABMON_4")
+  v("ABMON_5")
+  v("ABMON_6")
+  v("ABMON_7")
+  v("ABMON_8")
+  v("ABMON_9")
+  v("ABMON_10")
+  v("ABMON_11")
+  v("ABMON_12")
+  v("ERA")
+  v("ERA_D_FMT")
+  v("ERA_D_T_FMT")
+  v("ERA_T_FMT")
+  v("ALT_DIGITS")
+  v("RADIXCHAR")
+  v("THOUSEP")
+  v("YESEXPR")
+  v("NOEXPR")
+  v("CRNCYSTR")
+    
+if header("<locale.h>"):
+  v("LC_ALL") #{.importc, header: .}: cint
+  v("LC_COLLATE") #{.importc, header: "<locale.h>".}: cint
+  v("LC_CTYPE") #{.importc, header: "<locale.h>".}: cint
+  v("LC_MESSAGES") #{.importc, header: "<locale.h>".}: cint
+  v("LC_MONETARY") #{.importc, header: "<locale.h>".}: cint
+  v("LC_NUMERIC") #{.importc, header: "<locale.h>".}: cint
+  v("LC_TIME") #{.importc, header: "<locale.h>".}: cint
+
+if header("<pthread.h>"):
+  v("PTHREAD_BARRIER_SERIAL_THREAD")
+  v("PTHREAD_CANCEL_ASYNCHRONOUS") 
+  v("PTHREAD_CANCEL_ENABLE") 
+  v("PTHREAD_CANCEL_DEFERRED")
+  v("PTHREAD_CANCEL_DISABLE") 
+  #v("PTHREAD_CANCELED")
+  #v("PTHREAD_COND_INITIALIZER") 
+  v("PTHREAD_CREATE_DETACHED")
+  v("PTHREAD_CREATE_JOINABLE")
+  v("PTHREAD_EXPLICIT_SCHED")
+  v("PTHREAD_INHERIT_SCHED") 
+  v("PTHREAD_MUTEX_DEFAULT") 
+  v("PTHREAD_MUTEX_ERRORCHECK")
+  #v("PTHREAD_MUTEX_INITIALIZER") 
+  v("PTHREAD_MUTEX_NORMAL") 
+  v("PTHREAD_MUTEX_RECURSIVE") #{.importc, header: "<pthread.h>".}: cint
+  #v("PTHREAD_ONCE_INIT") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_PRIO_INHERIT") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_PRIO_NONE") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_PRIO_PROTECT") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_PROCESS_SHARED") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_PROCESS_PRIVATE") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_SCOPE_PROCESS") #{.importc, header: "<pthread.h>".}: cint
+  v("PTHREAD_SCOPE_SYSTEM") #{.importc, header: "<pthread.h>".}: cint
+
+if header("<unistd.h>"):
+  v("_POSIX_ASYNC_IO")
+  v("_POSIX_PRIO_IO")
+  v("_POSIX_SYNC_IO")
+  v("F_OK")
+  v("R_OK")
+  v("W_OK")
+  v("X_OK")
+
+  v("_CS_PATH")
+  v("_CS_POSIX_V6_ILP32_OFF32_CFLAGS") 
+  v("_CS_POSIX_V6_ILP32_OFF32_LDFLAGS") 
+  v("_CS_POSIX_V6_ILP32_OFF32_LIBS") 
+  v("_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS") 
+  v("_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS") 
+  v("_CS_POSIX_V6_ILP32_OFFBIG_LIBS") 
+  v("_CS_POSIX_V6_LP64_OFF64_CFLAGS") 
+  v("_CS_POSIX_V6_LP64_OFF64_LDFLAGS")
+  v("_CS_POSIX_V6_LP64_OFF64_LIBS") 
+  v("_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS") 
+  v("_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS") 
+  v("_CS_POSIX_V6_LPBIG_OFFBIG_LIBS") 
+  v("_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS")
+
+  v("F_LOCK") 
+  v("F_TEST") #{.importc: "F_TEST", header: "<unistd.h>".}: cint
+  v("F_TLOCK") #{.importc: "F_TLOCK", header: "<unistd.h>".}: cint
+  v("F_ULOCK") #{.importc: "F_ULOCK", header: "<unistd.h>".}: cint
+  v("_PC_2_SYMLINKS") #{.importc: "_PC_2_SYMLINKS", header: "<unistd.h>".}: cint
+  v("_PC_ALLOC_SIZE_MIN") 
+  v("_PC_ASYNC_IO") #{.importc: "_PC_ASYNC_IO", header: "<unistd.h>".}: cint
+  v("_PC_CHOWN_RESTRICTED") 
+  v("_PC_FILESIZEBITS") #{.importc: "_PC_FILESIZEBITS", header: "<unistd.h>".}: cint
+  v("_PC_LINK_MAX") #{.importc: "_PC_LINK_MAX", header: "<unistd.h>".}: cint
+  v("_PC_MAX_CANON") #{.importc: "_PC_MAX_CANON", header: "<unistd.h>".}: cint
+  v("_PC_MAX_INPUT") #{.importc: "_PC_MAX_INPUT", header: "<unistd.h>".}: cint
+  v("_PC_NAME_MAX") #{.importc: "_PC_NAME_MAX", header: "<unistd.h>".}: cint
+  v("_PC_NO_TRUNC") #{.importc: "_PC_NO_TRUNC", header: "<unistd.h>".}: cint
+  v("_PC_PATH_MAX") #{.importc: "_PC_PATH_MAX", header: "<unistd.h>".}: cint
+  v("_PC_PIPE_BUF") #{.importc: "_PC_PIPE_BUF", header: "<unistd.h>".}: cint
+  v("_PC_PRIO_IO") #{.importc: "_PC_PRIO_IO", header: "<unistd.h>".}: cint
+  v("_PC_REC_INCR_XFER_SIZE") 
+  v("_PC_REC_MIN_XFER_SIZE") 
+  v("_PC_REC_XFER_ALIGN") 
+  v("_PC_SYMLINK_MAX") #{.importc: "_PC_SYMLINK_MAX", header: "<unistd.h>".}: cint
+  v("_PC_SYNC_IO") #{.importc: "_PC_SYNC_IO", header: "<unistd.h>".}: cint
+  v("_PC_VDISABLE") #{.importc: "_PC_VDISABLE", header: "<unistd.h>".}: cint
+  v("_SC_2_C_BIND") #{.importc: "_SC_2_C_BIND", header: "<unistd.h>".}: cint
+  v("_SC_2_C_DEV") #{.importc: "_SC_2_C_DEV", header: "<unistd.h>".}: cint
+  v("_SC_2_CHAR_TERM") #{.importc: "_SC_2_CHAR_TERM", header: "<unistd.h>".}: cint
+  v("_SC_2_FORT_DEV") #{.importc: "_SC_2_FORT_DEV", header: "<unistd.h>".}: cint
+  v("_SC_2_FORT_RUN") #{.importc: "_SC_2_FORT_RUN", header: "<unistd.h>".}: cint
+  v("_SC_2_LOCALEDEF") #{.importc: "_SC_2_LOCALEDEF", header: "<unistd.h>".}: cint
+  v("_SC_2_PBS") #{.importc: "_SC_2_PBS", header: "<unistd.h>".}: cint
+  v("_SC_2_PBS_ACCOUNTING") 
+  v("_SC_2_PBS_CHECKPOINT") 
+  v("_SC_2_PBS_LOCATE") #{.importc: "_SC_2_PBS_LOCATE", header: "<unistd.h>".}: cint
+  v("_SC_2_PBS_MESSAGE") #{.importc: "_SC_2_PBS_MESSAGE", header: "<unistd.h>".}: cint
+  v("_SC_2_PBS_TRACK") #{.importc: "_SC_2_PBS_TRACK", header: "<unistd.h>".}: cint
+  v("_SC_2_SW_DEV") #{.importc: "_SC_2_SW_DEV", header: "<unistd.h>".}: cint
+  v("_SC_2_UPE") #{.importc: "_SC_2_UPE", header: "<unistd.h>".}: cint
+  v("_SC_2_VERSION") #{.importc: "_SC_2_VERSION", header: "<unistd.h>".}: cint
+  v("_SC_ADVISORY_INFO") #{.importc: "_SC_ADVISORY_INFO", header: "<unistd.h>".}: cint
+  v("_SC_AIO_LISTIO_MAX") 
+  v("_SC_AIO_MAX") #{.importc: "_SC_AIO_MAX", header: "<unistd.h>".}: cint
+  v("_SC_AIO_PRIO_DELTA_MAX") 
+  v("_SC_ARG_MAX") #{.importc: "_SC_ARG_MAX", header: "<unistd.h>".}: cint
+  v("_SC_ASYNCHRONOUS_IO") 
+  v("_SC_ATEXIT_MAX") #{.importc: "_SC_ATEXIT_MAX", header: "<unistd.h>".}: cint
+  v("_SC_BARRIERS") #{.importc: "_SC_BARRIERS", header: "<unistd.h>".}: cint
+  v("_SC_BC_BASE_MAX") #{.importc: "_SC_BC_BASE_MAX", header: "<unistd.h>".}: cint
+  v("_SC_BC_DIM_MAX") #{.importc: "_SC_BC_DIM_MAX", header: "<unistd.h>".}: cint
+  v("_SC_BC_SCALE_MAX") #{.importc: "_SC_BC_SCALE_MAX", header: "<unistd.h>".}: cint
+  v("_SC_BC_STRING_MAX") #{.importc: "_SC_BC_STRING_MAX", header: "<unistd.h>".}: cint
+  v("_SC_CHILD_MAX") #{.importc: "_SC_CHILD_MAX", header: "<unistd.h>".}: cint
+  v("_SC_CLK_TCK") #{.importc: "_SC_CLK_TCK", header: "<unistd.h>".}: cint
+  v("_SC_CLOCK_SELECTION") 
+  v("_SC_COLL_WEIGHTS_MAX")
+  v("_SC_CPUTIME") #{.importc: "_SC_CPUTIME", header: "<unistd.h>".}: cint
+  v("_SC_DELAYTIMER_MAX") 
+  v("_SC_EXPR_NEST_MAX") #{.importc: "_SC_EXPR_NEST_MAX", header: "<unistd.h>".}: cint
+  v("_SC_FSYNC") #{.importc: "_SC_FSYNC", header: "<unistd.h>".}: cint
+  v("_SC_GETGR_R_SIZE_MAX")
+  v("_SC_GETPW_R_SIZE_MAX")
+  v("_SC_HOST_NAME_MAX") #{.importc: "_SC_HOST_NAME_MAX", header: "<unistd.h>".}: cint
+  v("_SC_IOV_MAX") #{.importc: "_SC_IOV_MAX", header: "<unistd.h>".}: cint
+  v("_SC_IPV6") #{.importc: "_SC_IPV6", header: "<unistd.h>".}: cint
+  v("_SC_JOB_CONTROL") #{.importc: "_SC_JOB_CONTROL", header: "<unistd.h>".}: cint
+  v("_SC_LINE_MAX") #{.importc: "_SC_LINE_MAX", header: "<unistd.h>".}: cint
+  v("_SC_LOGIN_NAME_MAX") 
+  v("_SC_MAPPED_FILES") #{.importc: "_SC_MAPPED_FILES", header: "<unistd.h>".}: cint
+  v("_SC_MEMLOCK") #{.importc: "_SC_MEMLOCK", header: "<unistd.h>".}: cint
+  v("_SC_MEMLOCK_RANGE") #{.importc: "_SC_MEMLOCK_RANGE", header: "<unistd.h>".}: cint
+  v("_SC_MEMORY_PROTECTION")
+  v("_SC_MESSAGE_PASSING") 
+  v("_SC_MONOTONIC_CLOCK") 
+  v("_SC_MQ_OPEN_MAX") #{.importc: "_SC_MQ_OPEN_MAX", header: "<unistd.h>".}: cint
+  v("_SC_MQ_PRIO_MAX") #{.importc: "_SC_MQ_PRIO_MAX", header: "<unistd.h>".}: cint
+  v("_SC_NGROUPS_MAX") #{.importc: "_SC_NGROUPS_MAX", header: "<unistd.h>".}: cint
+  v("_SC_OPEN_MAX") #{.importc: "_SC_OPEN_MAX", header: "<unistd.h>".}: cint
+  v("_SC_PAGE_SIZE") #{.importc: "_SC_PAGE_SIZE", header: "<unistd.h>".}: cint
+  v("_SC_PRIORITIZED_IO") 
+  v("_SC_PRIORITY_SCHEDULING") 
+  v("_SC_RAW_SOCKETS") #{.importc: "_SC_RAW_SOCKETS", header: "<unistd.h>".}: cint
+  v("_SC_RE_DUP_MAX") #{.importc: "_SC_RE_DUP_MAX", header: "<unistd.h>".}: cint
+  v("_SC_READER_WRITER_LOCKS") 
+  v("_SC_REALTIME_SIGNALS") 
+  v("_SC_REGEXP") #{.importc: "_SC_REGEXP", header: "<unistd.h>".}: cint
+  v("_SC_RTSIG_MAX") #{.importc: "_SC_RTSIG_MAX", header: "<unistd.h>".}: cint
+  v("_SC_SAVED_IDS") #{.importc: "_SC_SAVED_IDS", header: "<unistd.h>".}: cint
+  v("_SC_SEM_NSEMS_MAX") #{.importc: "_SC_SEM_NSEMS_MAX", header: "<unistd.h>".}: cint
+  v("_SC_SEM_VALUE_MAX") #{.importc: "_SC_SEM_VALUE_MAX", header: "<unistd.h>".}: cint
+  v("_SC_SEMAPHORES") #{.importc: "_SC_SEMAPHORES", header: "<unistd.h>".}: cint
+  v("_SC_SHARED_MEMORY_OBJECTS") 
+  v("_SC_SHELL") #{.importc: "_SC_SHELL", header: "<unistd.h>".}: cint
+  v("_SC_SIGQUEUE_MAX") #{.importc: "_SC_SIGQUEUE_MAX", header: "<unistd.h>".}: cint
+  v("_SC_SPAWN") #{.importc: "_SC_SPAWN", header: "<unistd.h>".}: cint
+  v("_SC_SPIN_LOCKS") #{.importc: "_SC_SPIN_LOCKS", header: "<unistd.h>".}: cint
+  v("_SC_SPORADIC_SERVER") 
+  v("_SC_SS_REPL_MAX") #{.importc: "_SC_SS_REPL_MAX", header: "<unistd.h>".}: cint
+  v("_SC_STREAM_MAX") #{.importc: "_SC_STREAM_MAX", header: "<unistd.h>".}: cint
+  v("_SC_SYMLOOP_MAX") #{.importc: "_SC_SYMLOOP_MAX", header: "<unistd.h>".}: cint
+  v("_SC_SYNCHRONIZED_IO") 
+  v("_SC_THREAD_ATTR_STACKADDR") 
+  v("_SC_THREAD_ATTR_STACKSIZE") 
+  v("_SC_THREAD_CPUTIME") 
+  v("_SC_THREAD_DESTRUCTOR_ITERATIONS") 
+  v("_SC_THREAD_KEYS_MAX") 
+  v("_SC_THREAD_PRIO_INHERIT") 
+  v("_SC_THREAD_PRIO_PROTECT") 
+  v("_SC_THREAD_PRIORITY_SCHEDULING") 
+  v("_SC_THREAD_PROCESS_SHARED") 
+  v("_SC_THREAD_SAFE_FUNCTIONS") 
+  v("_SC_THREAD_SPORADIC_SERVER")
+  v("_SC_THREAD_STACK_MIN") 
+  v("_SC_THREAD_THREADS_MAX") 
+  v("_SC_THREADS") #{.importc: "_SC_THREADS", header: "<unistd.h>".}: cint
+  v("_SC_TIMEOUTS") #{.importc: "_SC_TIMEOUTS", header: "<unistd.h>".}: cint
+  v("_SC_TIMER_MAX") #{.importc: "_SC_TIMER_MAX", header: "<unistd.h>".}: cint
+  v("_SC_TIMERS") #{.importc: "_SC_TIMERS", header: "<unistd.h>".}: cint
+  v("_SC_TRACE") #{.importc: "_SC_TRACE", header: "<unistd.h>".}: cint
+  v("_SC_TRACE_EVENT_FILTER") 
+  v("_SC_TRACE_EVENT_NAME_MAX")
+  v("_SC_TRACE_INHERIT") #{.importc: "_SC_TRACE_INHERIT", header: "<unistd.h>".}: cint
+  v("_SC_TRACE_LOG") #{.importc: "_SC_TRACE_LOG", header: "<unistd.h>".}: cint
+  v("_SC_TRACE_NAME_MAX") 
+  v("_SC_TRACE_SYS_MAX") #{.importc: "_SC_TRACE_SYS_MAX", header: "<unistd.h>".}: cint
+  v("_SC_TRACE_USER_EVENT_MAX") 
+  v("_SC_TTY_NAME_MAX") #{.importc: "_SC_TTY_NAME_MAX", header: "<unistd.h>".}: cint
+  v("_SC_TYPED_MEMORY_OBJECTS") 
+  v("_SC_TZNAME_MAX") #{.importc: "_SC_TZNAME_MAX", header: "<unistd.h>".}: cint
+  v("_SC_V6_ILP32_OFF32") 
+  v("_SC_V6_ILP32_OFFBIG") 
+  v("_SC_V6_LP64_OFF64") #{.importc: "_SC_V6_LP64_OFF64", header: "<unistd.h>".}: cint
+  v("_SC_V6_LPBIG_OFFBIG") 
+  v("_SC_VERSION") #{.importc: "_SC_VERSION", header: "<unistd.h>".}: cint
+  v("_SC_XBS5_ILP32_OFF32") 
+  v("_SC_XBS5_ILP32_OFFBIG") 
+  v("_SC_XBS5_LP64_OFF64") 
+  v("_SC_XBS5_LPBIG_OFFBIG") 
+  v("_SC_XOPEN_CRYPT") #{.importc: "_SC_XOPEN_CRYPT", header: "<unistd.h>".}: cint
+  v("_SC_XOPEN_ENH_I18N") 
+  v("_SC_XOPEN_LEGACY") #{.importc: "_SC_XOPEN_LEGACY", header: "<unistd.h>".}: cint
+  v("_SC_XOPEN_REALTIME") 
+  v("_SC_XOPEN_REALTIME_THREADS") 
+  v("_SC_XOPEN_SHM") #{.importc: "_SC_XOPEN_SHM", header: "<unistd.h>".}: cint
+  v("_SC_XOPEN_STREAMS") #{.importc: "_SC_XOPEN_STREAMS", header: "<unistd.h>".}: cint
+  v("_SC_XOPEN_UNIX") #{.importc: "_SC_XOPEN_UNIX", header: "<unistd.h>".}: cint
+  v("_SC_XOPEN_VERSION") #{.importc: "_SC_XOPEN_VERSION", header: "<unistd.h>".}: cint
+
+  v("SEEK_SET") #{.importc, header: "<unistd.h>".}: cint
+  v("SEEK_CUR") #{.importc, header: "<unistd.h>".}: cint
+  v("SEEK_END") #{.importc, header: "<unistd.h>".}: cint
+
+
+if header("<semaphore.h>"):
+  v("SEM_FAILED", pointer)
+
+if header("<sys/ipc.h>"):
+  v("IPC_CREAT") #{.importc, header: .}: cint
+  v("IPC_EXCL") #{.importc, header: "<sys/ipc.h>".}: cint
+  v("IPC_NOWAIT") #{.importc, header: "<sys/ipc.h>".}: cint
+  v("IPC_PRIVATE") #{.importc, header: "<sys/ipc.h>".}: cint
+  v("IPC_RMID") #{.importc, header: "<sys/ipc.h>".}: cint
+  v("IPC_SET") #{.importc, header: "<sys/ipc.h>".}: cint
+  v("IPC_STAT") #{.importc, header: "<sys/ipc.h>".}: cint
+
+if header("<sys/stat.h>"):
+  v("S_IFMT") #{.importc, header: .}: cint
+  v("S_IFBLK") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IFCHR") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IFIFO") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IFREG") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IFDIR") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IFLNK") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IFSOCK") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IRWXU") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IRUSR") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IWUSR") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IXUSR") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IRWXG") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IRGRP") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IWGRP") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IXGRP") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IRWXO") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IROTH") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IWOTH") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_IXOTH") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_ISUID") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_ISGID") #{.importc, header: "<sys/stat.h>".}: cint
+  v("S_ISVTX") #{.importc, header: "<sys/stat.h>".}: cint
+
+if header("<sys/statvfs.h>"):
+  v("ST_RDONLY") #{.importc, header: .}: cint
+  v("ST_NOSUID") #{.importc, header: "<sys/statvfs.h>".}: cint
+       
+if header("<sys/mman.h>"):
+  v("PROT_READ") #{.importc, header: .}: cint
+  v("PROT_WRITE") #{.importc, header: "<sys/mman.h>".}: cint
+  v("PROT_EXEC") #{.importc, header: "<sys/mman.h>".}: cint
+  v("PROT_NONE") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MAP_SHARED") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MAP_PRIVATE") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MAP_FIXED") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MS_ASYNC") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MS_SYNC") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MS_INVALIDATE") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MCL_CURRENT") #{.importc, header: "<sys/mman.h>".}: cint
+  v("MCL_FUTURE") #{.importc, header: "<sys/mman.h>".}: cint
+
+  v("MAP_FAILED", pointer)
+  v("POSIX_MADV_NORMAL") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_MADV_SEQUENTIAL") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_MADV_RANDOM") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_MADV_WILLNEED") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_MADV_DONTNEED") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_TYPED_MEM_ALLOCATE") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_TYPED_MEM_ALLOCATE_CONTIG") #{.importc, header: "<sys/mman.h>".}: cint
+  v("POSIX_TYPED_MEM_MAP_ALLOCATABLE") #{.importc, header: "<sys/mman.h>".}: cint
+
+if header("<time.h>"):
+  v("CLOCKS_PER_SEC", clong) 
+  v("CLOCK_PROCESS_CPUTIME_ID")
+  v("CLOCK_THREAD_CPUTIME_ID")
+  v("CLOCK_REALTIME")
+  v("TIMER_ABSTIME") 
+  v("CLOCK_MONOTONIC") 
+
+if header("<sys/wait.h>"):
+  v("WNOHANG") #{.importc, header: .}: cint
+  v("WUNTRACED") #{.importc, header: "<sys/wait.h>".}: cint
+  #v("WEXITSTATUS") 
+  #v("WIFCONTINUED") 
+  #v("WIFEXITED") 
+  #v("WIFSIGNALED")
+  #v("WIFSTOPPED") 
+  #v("WSTOPSIG") 
+  #v("WTERMSIG") 
+  v("WEXITED") #{.importc, header: "<sys/wait.h>".}: cint
+  v("WSTOPPED") #{.importc, header: "<sys/wait.h>".}: cint
+  v("WCONTINUED") #{.importc, header: "<sys/wait.h>".}: cint
+  v("WNOWAIT") #{.importc, header: "<sys/wait.h>".}: cint
+  v("P_ALL") #{.importc, header: "<sys/wait.h>".}: cint 
+  v("P_PID") #{.importc, header: "<sys/wait.h>".}: cint 
+  v("P_PGID") #{.importc, header: "<sys/wait.h>".}: cint
+         
+if header("<signal.h>"):
+  v("SIGEV_NONE") #{.importc, header: "<signal.h>".}: cint
+  v("SIGEV_SIGNAL") #{.importc, header: "<signal.h>".}: cint
+  v("SIGEV_THREAD") #{.importc, header: "<signal.h>".}: cint
+  v("SIGABRT") #{.importc, header: "<signal.h>".}: cint
+  v("SIGALRM") #{.importc, header: "<signal.h>".}: cint
+  v("SIGBUS") #{.importc, header: "<signal.h>".}: cint
+  v("SIGCHLD") #{.importc, header: "<signal.h>".}: cint
+  v("SIGCONT") #{.importc, header: "<signal.h>".}: cint
+  v("SIGFPE") #{.importc, header: "<signal.h>".}: cint
+  v("SIGHUP") #{.importc, header: "<signal.h>".}: cint
+  v("SIGILL") #{.importc, header: "<signal.h>".}: cint
+  v("SIGINT") #{.importc, header: "<signal.h>".}: cint
+  v("SIGKILL") #{.importc, header: "<signal.h>".}: cint
+  v("SIGPIPE") #{.importc, header: "<signal.h>".}: cint
+  v("SIGQUIT") #{.importc, header: "<signal.h>".}: cint
+  v("SIGSEGV") #{.importc, header: "<signal.h>".}: cint
+  v("SIGSTOP") #{.importc, header: "<signal.h>".}: cint
+  v("SIGTERM") #{.importc, header: "<signal.h>".}: cint
+  v("SIGTSTP") #{.importc, header: "<signal.h>".}: cint
+  v("SIGTTIN") #{.importc, header: "<signal.h>".}: cint
+  v("SIGTTOU") #{.importc, header: "<signal.h>".}: cint
+  v("SIGUSR1") #{.importc, header: "<signal.h>".}: cint
+  v("SIGUSR2") #{.importc, header: "<signal.h>".}: cint
+  v("SIGPOLL") #{.importc, header: "<signal.h>".}: cint
+  v("SIGPROF") #{.importc, header: "<signal.h>".}: cint
+  v("SIGSYS") #{.importc, header: "<signal.h>".}: cint
+  v("SIGTRAP") #{.importc, header: "<signal.h>".}: cint
+  v("SIGURG") #{.importc, header: "<signal.h>".}: cint
+  v("SIGVTALRM") #{.importc, header: "<signal.h>".}: cint
+  v("SIGXCPU") #{.importc, header: "<signal.h>".}: cint
+  v("SIGXFSZ") #{.importc, header: "<signal.h>".}: cint
+  v("SA_NOCLDSTOP") #{.importc, header: "<signal.h>".}: cint
+  v("SIG_BLOCK") #{.importc, header: "<signal.h>".}: cint
+  v("SIG_UNBLOCK") #{.importc, header: "<signal.h>".}: cint
+  v("SIG_SETMASK") #{.importc, header: "<signal.h>".}: cint
+  v("SA_ONSTACK") #{.importc, header: "<signal.h>".}: cint
+  v("SA_RESETHAND") #{.importc, header: "<signal.h>".}: cint
+  v("SA_RESTART") #{.importc, header: "<signal.h>".}: cint
+  v("SA_SIGINFO") #{.importc, header: "<signal.h>".}: cint
+  v("SA_NOCLDWAIT") #{.importc, header: "<signal.h>".}: cint
+  v("SA_NODEFER") #{.importc, header: "<signal.h>".}: cint
+  v("SS_ONSTACK") #{.importc, header: "<signal.h>".}: cint
+  v("SS_DISABLE") #{.importc, header: "<signal.h>".}: cint
+  v("MINSIGSTKSZ") #{.importc, header: "<signal.h>".}: cint
+  v("SIGSTKSZ") #{.importc, header: "<signal.h>".}: cint
+
+if header("<nl_types.h>"):
+  v("NL_SETD") #{.importc, header: .}: cint
+  v("NL_CAT_LOCALE") #{.importc, header: "<nl_types.h>".}: cint
+
+if header("<sched.h>"):
+  v("SCHED_FIFO")
+  v("SCHED_RR")
+  v("SCHED_SPORADIC")
+  v("SCHED_OTHER")
+
+if header("<sys/select.h>"):
+  v("FD_SETSIZE")
+
+if header("<net/if.h>"):
+  v("IF_NAMESIZE")
+
+if header("<sys/socket.h>"):
+  v("SCM_RIGHTS") #{.importc, header: .}: cint
+  v("SOCK_DGRAM") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SOCK_RAW") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SOCK_SEQPACKET") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SOCK_STREAM") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SOL_SOCKET") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_ACCEPTCONN") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_BROADCAST") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_DEBUG") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_DONTROUTE") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_ERROR") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_KEEPALIVE") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_LINGER") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_OOBINLINE") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_RCVBUF") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_RCVLOWAT") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_RCVTIMEO") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_REUSEADDR") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_SNDBUF") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_SNDLOWAT") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_SNDTIMEO") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SO_TYPE") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SOMAXCONN") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_CTRUNC") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_DONTROUTE") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_EOR") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_OOB") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_PEEK") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_TRUNC") #{.importc, header: "<sys/socket.h>".}: cint
+  v("MSG_WAITALL") #{.importc, header: "<sys/socket.h>".}: cint
+  v("AF_INET") #{.importc, header: "<sys/socket.h>".}: cint
+  v("AF_INET6") #{.importc, header: "<sys/socket.h>".}: cint
+  v("AF_UNIX") #{.importc, header: "<sys/socket.h>".}: cint
+  v("AF_UNSPEC") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SHUT_RD") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SHUT_RDWR") #{.importc, header: "<sys/socket.h>".}: cint
+  v("SHUT_WR") #{.importc, header: "<sys/socket.h>".}: cint
+
+if header("<netinet/in.h>"):
+  v("IPPROTO_IP") #{.importc, header: .}: cint
+  v("IPPROTO_IPV6") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPPROTO_ICMP") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPPROTO_RAW") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPPROTO_TCP") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPPROTO_UDP") #{.importc, header: "<netinet/in.h>".}: cint
+  v("INADDR_ANY") #{.importc, header: "<netinet/in.h>".}: TinAddrScalar
+  v("INADDR_BROADCAST") #{.importc, header: "<netinet/in.h>".}: TinAddrScalar
+  v("INET_ADDRSTRLEN") #{.importc, header: "<netinet/in.h>".}: cint
+
+  v("IPV6_JOIN_GROUP") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPV6_LEAVE_GROUP") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPV6_MULTICAST_HOPS") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPV6_MULTICAST_IF") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPV6_MULTICAST_LOOP") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPV6_UNICAST_HOPS") #{.importc, header: "<netinet/in.h>".}: cint
+  v("IPV6_V6ONLY") #{.importc, header: "<netinet/in.h>".}: cint
+
+  v("TCP_NODELAY") #{.importc, header: "<netinet/tcp.h>".}: cint
+
+if header("<netdb.h>"):
+  v("IPPORT_RESERVED")
+
+  v("HOST_NOT_FOUND")
+  v("NO_DATA")
+  v("NO_RECOVERY") 
+  v("TRY_AGAIN") 
+
+  v("AI_PASSIVE") 
+  v("AI_CANONNAME") 
+  v("AI_NUMERICHOST") 
+  v("AI_NUMERICSERV") 
+  v("AI_V4MAPPED") 
+  v("AI_ALL") 
+  v("AI_ADDRCONFIG") 
+
+  v("NI_NOFQDN") 
+  v("NI_NUMERICHOST") 
+  v("NI_NAMEREQD") 
+  v("NI_NUMERICSERV") 
+  v("NI_NUMERICSCOPE") 
+  v("NI_DGRAM") 
+  v("EAI_AGAIN")
+  v("EAI_BADFLAGS")
+  v("EAI_FAIL")
+  v("EAI_FAMILY")
+  v("EAI_MEMORY")
+  v("EAI_NONAME")
+  v("EAI_SERVICE")
+  v("EAI_SOCKTYPE")
+  v("EAI_SYSTEM")
+  v("EAI_OVERFLOW")
+
+if header("<poll.h>"):
+  v("POLLIN", cshort)
+  v("POLLRDNORM", cshort)
+  v("POLLRDBAND", cshort)
+  v("POLLPRI", cshort)
+  v("POLLOUT", cshort)
+  v("POLLWRNORM", cshort)
+  v("POLLWRBAND", cshort)
+  v("POLLERR", cshort)
+  v("POLLHUP", cshort)
+  v("POLLNVAL", cshort)
+
+if header("<spawn.h>"):
+  v("POSIX_SPAWN_RESETIDS")
+  v("POSIX_SPAWN_SETPGROUP")
+  v("POSIX_SPAWN_SETSCHEDPARAM")
+  v("POSIX_SPAWN_SETSCHEDULER")
+  v("POSIX_SPAWN_SETSIGDEF")
+  v("POSIX_SPAWN_SETSIGMASK")
+
+if header("<stdio.h>"):
+  v "_IOFBF"
+  v "_IONBF"
+
+main()
diff --git a/tools/detect/linux_amd64_consts.nim b/tools/detect/linux_amd64_consts.nim
new file mode 100644
index 000000000..eb85da045
--- /dev/null
+++ b/tools/detect/linux_amd64_consts.nim
@@ -0,0 +1,631 @@
+# Generated by detect.nim
+const
+  AIO_ALLDONE* = cint(2)
+  AIO_CANCELED* = cint(0)
+  AIO_NOTCANCELED* = cint(1)
+  LIO_NOP* = cint(2)
+  LIO_NOWAIT* = cint(1)
+  LIO_READ* = cint(0)
+  LIO_WAIT* = cint(0)
+  LIO_WRITE* = cint(1)
+  RTLD_LAZY* = cint(1)
+  RTLD_NOW* = cint(2)
+  RTLD_GLOBAL* = cint(256)
+  RTLD_LOCAL* = cint(0)
+  E2BIG* = cint(7)
+  EACCES* = cint(13)
+  EADDRINUSE* = cint(98)
+  EADDRNOTAVAIL* = cint(99)
+  EAFNOSUPPORT* = cint(97)
+  EAGAIN* = cint(11)
+  EALREADY* = cint(114)
+  EBADF* = cint(9)
+  EBADMSG* = cint(74)
+  EBUSY* = cint(16)
+  ECANCELED* = cint(125)
+  ECHILD* = cint(10)
+  ECONNABORTED* = cint(103)
+  ECONNREFUSED* = cint(111)
+  ECONNRESET* = cint(104)
+  EDEADLK* = cint(35)
+  EDESTADDRREQ* = cint(89)
+  EDOM* = cint(33)
+  EDQUOT* = cint(122)
+  EEXIST* = cint(17)
+  EFAULT* = cint(14)
+  EFBIG* = cint(27)
+  EHOSTUNREACH* = cint(113)
+  EIDRM* = cint(43)
+  EILSEQ* = cint(84)
+  EINPROGRESS* = cint(115)
+  EINTR* = cint(4)
+  EINVAL* = cint(22)
+  EIO* = cint(5)
+  EISCONN* = cint(106)
+  EISDIR* = cint(21)
+  ELOOP* = cint(40)
+  EMFILE* = cint(24)
+  EMLINK* = cint(31)
+  EMSGSIZE* = cint(90)
+  EMULTIHOP* = cint(72)
+  ENAMETOOLONG* = cint(36)
+  ENETDOWN* = cint(100)
+  ENETRESET* = cint(102)
+  ENETUNREACH* = cint(101)
+  ENFILE* = cint(23)
+  ENOBUFS* = cint(105)
+  ENODATA* = cint(61)
+  ENODEV* = cint(19)
+  ENOENT* = cint(2)
+  ENOEXEC* = cint(8)
+  ENOLCK* = cint(37)
+  ENOLINK* = cint(67)
+  ENOMEM* = cint(12)
+  ENOMSG* = cint(42)
+  ENOPROTOOPT* = cint(92)
+  ENOSPC* = cint(28)
+  ENOSR* = cint(63)
+  ENOSTR* = cint(60)
+  ENOSYS* = cint(38)
+  ENOTCONN* = cint(107)
+  ENOTDIR* = cint(20)
+  ENOTEMPTY* = cint(39)
+  ENOTSOCK* = cint(88)
+  ENOTSUP* = cint(95)
+  ENOTTY* = cint(25)
+  ENXIO* = cint(6)
+  EOPNOTSUPP* = cint(95)
+  EOVERFLOW* = cint(75)
+  EPERM* = cint(1)
+  EPIPE* = cint(32)
+  EPROTO* = cint(71)
+  EPROTONOSUPPORT* = cint(93)
+  EPROTOTYPE* = cint(91)
+  ERANGE* = cint(34)
+  EROFS* = cint(30)
+  ESPIPE* = cint(29)
+  ESRCH* = cint(3)
+  ESTALE* = cint(116)
+  ETIME* = cint(62)
+  ETIMEDOUT* = cint(110)
+  ETXTBSY* = cint(26)
+  EWOULDBLOCK* = cint(11)
+  EXDEV* = cint(18)
+  F_DUPFD* = cint(0)
+  F_GETFD* = cint(1)
+  F_SETFD* = cint(2)
+  F_GETFL* = cint(3)
+  F_SETFL* = cint(4)
+  F_GETLK* = cint(5)
+  F_SETLK* = cint(6)
+  F_SETLKW* = cint(7)
+  F_GETOWN* = cint(9)
+  F_SETOWN* = cint(8)
+  FD_CLOEXEC* = cint(1)
+  F_RDLCK* = cint(0)
+  F_UNLCK* = cint(2)
+  F_WRLCK* = cint(1)
+  O_CREAT* = cint(64)
+  O_EXCL* = cint(128)
+  O_NOCTTY* = cint(256)
+  O_TRUNC* = cint(512)
+  O_APPEND* = cint(1024)
+  O_DSYNC* = cint(4096)
+  O_NONBLOCK* = cint(2048)
+  O_RSYNC* = cint(1052672)
+  O_SYNC* = cint(1052672)
+  O_ACCMODE* = cint(3)
+  O_RDONLY* = cint(0)
+  O_RDWR* = cint(2)
+  O_WRONLY* = cint(1)
+  POSIX_FADV_NORMAL* = cint(0)
+  POSIX_FADV_SEQUENTIAL* = cint(2)
+  POSIX_FADV_RANDOM* = cint(1)
+  POSIX_FADV_WILLNEED* = cint(3)
+  POSIX_FADV_DONTNEED* = cint(4)
+  POSIX_FADV_NOREUSE* = cint(5)
+  FE_DIVBYZERO* = cint(4)
+  FE_INEXACT* = cint(32)
+  FE_INVALID* = cint(1)
+  FE_OVERFLOW* = cint(8)
+  FE_UNDERFLOW* = cint(16)
+  FE_ALL_EXCEPT* = cint(61)
+  FE_DOWNWARD* = cint(1024)
+  FE_TONEAREST* = cint(0)
+  FE_TOWARDZERO* = cint(3072)
+  FE_UPWARD* = cint(2048)
+  FE_DFL_ENV* = cast[pointer](0xffffffffffffffff)
+  MM_HARD* = cint(1)
+  MM_SOFT* = cint(2)
+  MM_FIRM* = cint(4)
+  MM_APPL* = cint(8)
+  MM_UTIL* = cint(16)
+  MM_OPSYS* = cint(32)
+  MM_RECOVER* = cint(64)
+  MM_NRECOV* = cint(128)
+  MM_HALT* = cint(1)
+  MM_ERROR* = cint(2)
+  MM_WARNING* = cint(3)
+  MM_INFO* = cint(4)
+  MM_NOSEV* = cint(0)
+  MM_PRINT* = cint(256)
+  MM_CONSOLE* = cint(512)
+  MM_OK* = cint(0)
+  MM_NOTOK* = cint(-1)
+  MM_NOMSG* = cint(1)
+  MM_NOCON* = cint(4)
+  FNM_NOMATCH* = cint(1)
+  FNM_PATHNAME* = cint(1)
+  FNM_PERIOD* = cint(4)
+  FNM_NOESCAPE* = cint(2)
+  FTW_F* = cint(0)
+  FTW_D* = cint(1)
+  FTW_DNR* = cint(2)
+  FTW_NS* = cint(3)
+  FTW_SL* = cint(4)
+  GLOB_APPEND* = cint(32)
+  GLOB_DOOFFS* = cint(8)
+  GLOB_ERR* = cint(1)
+  GLOB_MARK* = cint(2)
+  GLOB_NOCHECK* = cint(16)
+  GLOB_NOESCAPE* = cint(64)
+  GLOB_NOSORT* = cint(4)
+  GLOB_ABORTED* = cint(2)
+  GLOB_NOMATCH* = cint(3)
+  GLOB_NOSPACE* = cint(1)
+  GLOB_NOSYS* = cint(4)
+  CODESET* = cint(14)
+  D_T_FMT* = cint(131112)
+  D_FMT* = cint(131113)
+  T_FMT* = cint(131114)
+  T_FMT_AMPM* = cint(131115)
+  AM_STR* = cint(131110)
+  PM_STR* = cint(131111)
+  DAY_1* = cint(131079)
+  DAY_2* = cint(131080)
+  DAY_3* = cint(131081)
+  DAY_4* = cint(131082)
+  DAY_5* = cint(131083)
+  DAY_6* = cint(131084)
+  DAY_7* = cint(131085)
+  ABDAY_1* = cint(131072)
+  ABDAY_2* = cint(131073)
+  ABDAY_3* = cint(131074)
+  ABDAY_4* = cint(131075)
+  ABDAY_5* = cint(131076)
+  ABDAY_6* = cint(131077)
+  ABDAY_7* = cint(131078)
+  MON_1* = cint(131098)
+  MON_2* = cint(131099)
+  MON_3* = cint(131100)
+  MON_4* = cint(131101)
+  MON_5* = cint(131102)
+  MON_6* = cint(131103)
+  MON_7* = cint(131104)
+  MON_8* = cint(131105)
+  MON_9* = cint(131106)
+  MON_10* = cint(131107)
+  MON_11* = cint(131108)
+  MON_12* = cint(131109)
+  ABMON_1* = cint(131086)
+  ABMON_2* = cint(131087)
+  ABMON_3* = cint(131088)
+  ABMON_4* = cint(131089)
+  ABMON_5* = cint(131090)
+  ABMON_6* = cint(131091)
+  ABMON_7* = cint(131092)
+  ABMON_8* = cint(131093)
+  ABMON_9* = cint(131094)
+  ABMON_10* = cint(131095)
+  ABMON_11* = cint(131096)
+  ABMON_12* = cint(131097)
+  ERA* = cint(131116)
+  ERA_D_FMT* = cint(131118)
+  ERA_D_T_FMT* = cint(131120)
+  ERA_T_FMT* = cint(131121)
+  ALT_DIGITS* = cint(131119)
+  RADIXCHAR* = cint(65536)
+  THOUSEP* = cint(65537)
+  YESEXPR* = cint(327680)
+  NOEXPR* = cint(327681)
+  CRNCYSTR* = cint(262159)
+  LC_ALL* = cint(6)
+  LC_COLLATE* = cint(3)
+  LC_CTYPE* = cint(0)
+  LC_MESSAGES* = cint(5)
+  LC_MONETARY* = cint(4)
+  LC_NUMERIC* = cint(1)
+  LC_TIME* = cint(2)
+  PTHREAD_BARRIER_SERIAL_THREAD* = cint(-1)
+  PTHREAD_CANCEL_ASYNCHRONOUS* = cint(1)
+  PTHREAD_CANCEL_ENABLE* = cint(0)
+  PTHREAD_CANCEL_DEFERRED* = cint(0)
+  PTHREAD_CANCEL_DISABLE* = cint(1)
+  PTHREAD_CREATE_DETACHED* = cint(1)
+  PTHREAD_CREATE_JOINABLE* = cint(0)
+  PTHREAD_EXPLICIT_SCHED* = cint(1)
+  PTHREAD_INHERIT_SCHED* = cint(0)
+  PTHREAD_PROCESS_SHARED* = cint(1)
+  PTHREAD_PROCESS_PRIVATE* = cint(0)
+  PTHREAD_SCOPE_PROCESS* = cint(1)
+  PTHREAD_SCOPE_SYSTEM* = cint(0)
+  POSIX_ASYNC_IO* = cint(1)
+  F_OK* = cint(0)
+  R_OK* = cint(4)
+  W_OK* = cint(2)
+  X_OK* = cint(1)
+  CS_PATH* = cint(0)
+  CS_POSIX_V6_ILP32_OFF32_CFLAGS* = cint(1116)
+  CS_POSIX_V6_ILP32_OFF32_LDFLAGS* = cint(1117)
+  CS_POSIX_V6_ILP32_OFF32_LIBS* = cint(1118)
+  CS_POSIX_V6_ILP32_OFFBIG_CFLAGS* = cint(1120)
+  CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS* = cint(1121)
+  CS_POSIX_V6_ILP32_OFFBIG_LIBS* = cint(1122)
+  CS_POSIX_V6_LP64_OFF64_CFLAGS* = cint(1124)
+  CS_POSIX_V6_LP64_OFF64_LDFLAGS* = cint(1125)
+  CS_POSIX_V6_LP64_OFF64_LIBS* = cint(1126)
+  CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS* = cint(1128)
+  CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS* = cint(1129)
+  CS_POSIX_V6_LPBIG_OFFBIG_LIBS* = cint(1130)
+  CS_POSIX_V6_WIDTH_RESTRICTED_ENVS* = cint(1)
+  F_LOCK* = cint(1)
+  F_TEST* = cint(3)
+  F_TLOCK* = cint(2)
+  F_ULOCK* = cint(0)
+  PC_2_SYMLINKS* = cint(20)
+  PC_ALLOC_SIZE_MIN* = cint(18)
+  PC_ASYNC_IO* = cint(10)
+  PC_CHOWN_RESTRICTED* = cint(6)
+  PC_FILESIZEBITS* = cint(13)
+  PC_LINK_MAX* = cint(0)
+  PC_MAX_CANON* = cint(1)
+  PC_MAX_INPUT* = cint(2)
+  PC_NAME_MAX* = cint(3)
+  PC_NO_TRUNC* = cint(7)
+  PC_PATH_MAX* = cint(4)
+  PC_PIPE_BUF* = cint(5)
+  PC_PRIO_IO* = cint(11)
+  PC_REC_INCR_XFER_SIZE* = cint(14)
+  PC_REC_MIN_XFER_SIZE* = cint(16)
+  PC_REC_XFER_ALIGN* = cint(17)
+  PC_SYMLINK_MAX* = cint(19)
+  PC_SYNC_IO* = cint(9)
+  PC_VDISABLE* = cint(8)
+  SC_2_C_BIND* = cint(47)
+  SC_2_C_DEV* = cint(48)
+  SC_2_CHAR_TERM* = cint(95)
+  SC_2_FORT_DEV* = cint(49)
+  SC_2_FORT_RUN* = cint(50)
+  SC_2_LOCALEDEF* = cint(52)
+  SC_2_PBS* = cint(168)
+  SC_2_PBS_ACCOUNTING* = cint(169)
+  SC_2_PBS_CHECKPOINT* = cint(175)
+  SC_2_PBS_LOCATE* = cint(170)
+  SC_2_PBS_MESSAGE* = cint(171)
+  SC_2_PBS_TRACK* = cint(172)
+  SC_2_SW_DEV* = cint(51)
+  SC_2_UPE* = cint(97)
+  SC_2_VERSION* = cint(46)
+  SC_ADVISORY_INFO* = cint(132)
+  SC_AIO_LISTIO_MAX* = cint(23)
+  SC_AIO_MAX* = cint(24)
+  SC_AIO_PRIO_DELTA_MAX* = cint(25)
+  SC_ARG_MAX* = cint(0)
+  SC_ASYNCHRONOUS_IO* = cint(12)
+  SC_ATEXIT_MAX* = cint(87)
+  SC_BARRIERS* = cint(133)
+  SC_BC_BASE_MAX* = cint(36)
+  SC_BC_DIM_MAX* = cint(37)
+  SC_BC_SCALE_MAX* = cint(38)
+  SC_BC_STRING_MAX* = cint(39)
+  SC_CHILD_MAX* = cint(1)
+  SC_CLK_TCK* = cint(2)
+  SC_CLOCK_SELECTION* = cint(137)
+  SC_COLL_WEIGHTS_MAX* = cint(40)
+  SC_CPUTIME* = cint(138)
+  SC_DELAYTIMER_MAX* = cint(26)
+  SC_EXPR_NEST_MAX* = cint(42)
+  SC_FSYNC* = cint(15)
+  SC_GETGR_R_SIZE_MAX* = cint(69)
+  SC_GETPW_R_SIZE_MAX* = cint(70)
+  SC_HOST_NAME_MAX* = cint(180)
+  SC_IOV_MAX* = cint(60)
+  SC_IPV6* = cint(235)
+  SC_JOB_CONTROL* = cint(7)
+  SC_LINE_MAX* = cint(43)
+  SC_LOGIN_NAME_MAX* = cint(71)
+  SC_MAPPED_FILES* = cint(16)
+  SC_MEMLOCK* = cint(17)
+  SC_MEMLOCK_RANGE* = cint(18)
+  SC_MEMORY_PROTECTION* = cint(19)
+  SC_MESSAGE_PASSING* = cint(20)
+  SC_MONOTONIC_CLOCK* = cint(149)
+  SC_MQ_OPEN_MAX* = cint(27)
+  SC_MQ_PRIO_MAX* = cint(28)
+  SC_NGROUPS_MAX* = cint(3)
+  SC_OPEN_MAX* = cint(4)
+  SC_PAGE_SIZE* = cint(30)
+  SC_PRIORITIZED_IO* = cint(13)
+  SC_PRIORITY_SCHEDULING* = cint(10)
+  SC_RAW_SOCKETS* = cint(236)
+  SC_RE_DUP_MAX* = cint(44)
+  SC_READER_WRITER_LOCKS* = cint(153)
+  SC_REALTIME_SIGNALS* = cint(9)
+  SC_REGEXP* = cint(155)
+  SC_RTSIG_MAX* = cint(31)
+  SC_SAVED_IDS* = cint(8)
+  SC_SEM_NSEMS_MAX* = cint(32)
+  SC_SEM_VALUE_MAX* = cint(33)
+  SC_SEMAPHORES* = cint(21)
+  SC_SHARED_MEMORY_OBJECTS* = cint(22)
+  SC_SHELL* = cint(157)
+  SC_SIGQUEUE_MAX* = cint(34)
+  SC_SPAWN* = cint(159)
+  SC_SPIN_LOCKS* = cint(154)
+  SC_SPORADIC_SERVER* = cint(160)
+  SC_SS_REPL_MAX* = cint(241)
+  SC_STREAM_MAX* = cint(5)
+  SC_SYMLOOP_MAX* = cint(173)
+  SC_SYNCHRONIZED_IO* = cint(14)
+  SC_THREAD_ATTR_STACKADDR* = cint(77)
+  SC_THREAD_ATTR_STACKSIZE* = cint(78)
+  SC_THREAD_CPUTIME* = cint(139)
+  SC_THREAD_DESTRUCTOR_ITERATIONS* = cint(73)
+  SC_THREAD_KEYS_MAX* = cint(74)
+  SC_THREAD_PRIO_INHERIT* = cint(80)
+  SC_THREAD_PRIO_PROTECT* = cint(81)
+  SC_THREAD_PRIORITY_SCHEDULING* = cint(79)
+  SC_THREAD_PROCESS_SHARED* = cint(82)
+  SC_THREAD_SAFE_FUNCTIONS* = cint(68)
+  SC_THREAD_SPORADIC_SERVER* = cint(161)
+  SC_THREAD_STACK_MIN* = cint(75)
+  SC_THREAD_THREADS_MAX* = cint(76)
+  SC_THREADS* = cint(67)
+  SC_TIMEOUTS* = cint(164)
+  SC_TIMER_MAX* = cint(35)
+  SC_TIMERS* = cint(11)
+  SC_TRACE* = cint(181)
+  SC_TRACE_EVENT_FILTER* = cint(182)
+  SC_TRACE_EVENT_NAME_MAX* = cint(242)
+  SC_TRACE_INHERIT* = cint(183)
+  SC_TRACE_LOG* = cint(184)
+  SC_TRACE_NAME_MAX* = cint(243)
+  SC_TRACE_SYS_MAX* = cint(244)
+  SC_TRACE_USER_EVENT_MAX* = cint(245)
+  SC_TTY_NAME_MAX* = cint(72)
+  SC_TYPED_MEMORY_OBJECTS* = cint(165)
+  SC_TZNAME_MAX* = cint(6)
+  SC_V6_ILP32_OFF32* = cint(176)
+  SC_V6_ILP32_OFFBIG* = cint(177)
+  SC_V6_LP64_OFF64* = cint(178)
+  SC_V6_LPBIG_OFFBIG* = cint(179)
+  SC_VERSION* = cint(29)
+  SC_XBS5_ILP32_OFF32* = cint(125)
+  SC_XBS5_ILP32_OFFBIG* = cint(126)
+  SC_XBS5_LP64_OFF64* = cint(127)
+  SC_XBS5_LPBIG_OFFBIG* = cint(128)
+  SC_XOPEN_CRYPT* = cint(92)
+  SC_XOPEN_ENH_I18N* = cint(93)
+  SC_XOPEN_LEGACY* = cint(129)
+  SC_XOPEN_REALTIME* = cint(130)
+  SC_XOPEN_REALTIME_THREADS* = cint(131)
+  SC_XOPEN_SHM* = cint(94)
+  SC_XOPEN_STREAMS* = cint(246)
+  SC_XOPEN_UNIX* = cint(91)
+  SC_XOPEN_VERSION* = cint(89)
+  SEEK_SET* = cint(0)
+  SEEK_CUR* = cint(1)
+  SEEK_END* = cint(2)
+  SEM_FAILED* = cast[pointer]((nil))
+  IPC_CREAT* = cint(512)
+  IPC_EXCL* = cint(1024)
+  IPC_NOWAIT* = cint(2048)
+  IPC_PRIVATE* = cint(0)
+  IPC_RMID* = cint(0)
+  IPC_SET* = cint(1)
+  IPC_STAT* = cint(2)
+  S_IFMT* = cint(61440)
+  S_IFBLK* = cint(24576)
+  S_IFCHR* = cint(8192)
+  S_IFIFO* = cint(4096)
+  S_IFREG* = cint(32768)
+  S_IFDIR* = cint(16384)
+  S_IFLNK* = cint(40960)
+  S_IFSOCK* = cint(49152)
+  S_IRWXU* = cint(448)
+  S_IRUSR* = cint(256)
+  S_IWUSR* = cint(128)
+  S_IXUSR* = cint(64)
+  S_IRWXG* = cint(56)
+  S_IRGRP* = cint(32)
+  S_IWGRP* = cint(16)
+  S_IXGRP* = cint(8)
+  S_IRWXO* = cint(7)
+  S_IROTH* = cint(4)
+  S_IWOTH* = cint(2)
+  S_IXOTH* = cint(1)
+  S_ISUID* = cint(2048)
+  S_ISGID* = cint(1024)
+  S_ISVTX* = cint(512)
+  ST_RDONLY* = cint(1)
+  ST_NOSUID* = cint(2)
+  PROT_READ* = cint(1)
+  PROT_WRITE* = cint(2)
+  PROT_EXEC* = cint(4)
+  PROT_NONE* = cint(0)
+  MAP_SHARED* = cint(1)
+  MAP_PRIVATE* = cint(2)
+  MAP_FIXED* = cint(16)
+  MS_ASYNC* = cint(1)
+  MS_SYNC* = cint(4)
+  MS_INVALIDATE* = cint(2)
+  MCL_CURRENT* = cint(1)
+  MCL_FUTURE* = cint(2)
+  MAP_FAILED* = cast[pointer](0xffffffffffffffff)
+  POSIX_MADV_NORMAL* = cint(0)
+  POSIX_MADV_SEQUENTIAL* = cint(2)
+  POSIX_MADV_RANDOM* = cint(1)
+  POSIX_MADV_WILLNEED* = cint(3)
+  POSIX_MADV_DONTNEED* = cint(4)
+  CLOCKS_PER_SEC* = clong(1000000)
+  CLOCK_PROCESS_CPUTIME_ID* = cint(2)
+  CLOCK_THREAD_CPUTIME_ID* = cint(3)
+  CLOCK_REALTIME* = cint(0)
+  TIMER_ABSTIME* = cint(1)
+  CLOCK_MONOTONIC* = cint(1)
+  WNOHANG* = cint(1)
+  WUNTRACED* = cint(2)
+  WEXITED* = cint(4)
+  WSTOPPED* = cint(2)
+  WCONTINUED* = cint(8)
+  WNOWAIT* = cint(16777216)
+  SIGEV_NONE* = cint(1)
+  SIGEV_SIGNAL* = cint(0)
+  SIGEV_THREAD* = cint(2)
+  SIGABRT* = cint(6)
+  SIGALRM* = cint(14)
+  SIGBUS* = cint(7)
+  SIGCHLD* = cint(17)
+  SIGCONT* = cint(18)
+  SIGFPE* = cint(8)
+  SIGHUP* = cint(1)
+  SIGILL* = cint(4)
+  SIGINT* = cint(2)
+  SIGKILL* = cint(9)
+  SIGPIPE* = cint(13)
+  SIGQUIT* = cint(3)
+  SIGSEGV* = cint(11)
+  SIGSTOP* = cint(19)
+  SIGTERM* = cint(15)
+  SIGTSTP* = cint(20)
+  SIGTTIN* = cint(21)
+  SIGTTOU* = cint(22)
+  SIGUSR1* = cint(10)
+  SIGUSR2* = cint(12)
+  SIGPOLL* = cint(29)
+  SIGPROF* = cint(27)
+  SIGSYS* = cint(31)
+  SIGTRAP* = cint(5)
+  SIGURG* = cint(23)
+  SIGVTALRM* = cint(26)
+  SIGXCPU* = cint(24)
+  SIGXFSZ* = cint(25)
+  SA_NOCLDSTOP* = cint(1)
+  SIG_BLOCK* = cint(0)
+  SIG_UNBLOCK* = cint(1)
+  SIG_SETMASK* = cint(2)
+  SA_ONSTACK* = cint(134217728)
+  SA_RESETHAND* = cint(-2147483648)
+  SA_RESTART* = cint(268435456)
+  SA_SIGINFO* = cint(4)
+  SA_NOCLDWAIT* = cint(2)
+  SA_NODEFER* = cint(1073741824)
+  SS_ONSTACK* = cint(1)
+  SS_DISABLE* = cint(2)
+  MINSIGSTKSZ* = cint(2048)
+  SIGSTKSZ* = cint(8192)
+  NL_SETD* = cint(1)
+  NL_CAT_LOCALE* = cint(1)
+  SCHED_FIFO* = cint(1)
+  SCHED_RR* = cint(2)
+  SCHED_OTHER* = cint(0)
+  FD_SETSIZE* = cint(1024)
+  IF_NAMESIZE* = cint(16)
+  SCM_RIGHTS* = cint(1)
+  SOCK_DGRAM* = cint(2)
+  SOCK_RAW* = cint(3)
+  SOCK_SEQPACKET* = cint(5)
+  SOCK_STREAM* = cint(1)
+  SOL_SOCKET* = cint(1)
+  SO_ACCEPTCONN* = cint(30)
+  SO_BROADCAST* = cint(6)
+  SO_DEBUG* = cint(1)
+  SO_DONTROUTE* = cint(5)
+  SO_ERROR* = cint(4)
+  SO_KEEPALIVE* = cint(9)
+  SO_LINGER* = cint(13)
+  SO_OOBINLINE* = cint(10)
+  SO_RCVBUF* = cint(8)
+  SO_RCVLOWAT* = cint(18)
+  SO_RCVTIMEO* = cint(20)
+  SO_REUSEADDR* = cint(2)
+  SO_SNDBUF* = cint(7)
+  SO_SNDLOWAT* = cint(19)
+  SO_SNDTIMEO* = cint(21)
+  SO_TYPE* = cint(3)
+  SOMAXCONN* = cint(128)
+  MSG_CTRUNC* = cint(8)
+  MSG_DONTROUTE* = cint(4)
+  MSG_EOR* = cint(128)
+  MSG_OOB* = cint(1)
+  MSG_PEEK* = cint(2)
+  MSG_TRUNC* = cint(32)
+  MSG_WAITALL* = cint(256)
+  AF_INET* = cint(2)
+  AF_INET6* = cint(10)
+  AF_UNIX* = cint(1)
+  AF_UNSPEC* = cint(0)
+  SHUT_RD* = cint(0)
+  SHUT_RDWR* = cint(2)
+  SHUT_WR* = cint(1)
+  IPPROTO_IP* = cint(0)
+  IPPROTO_IPV6* = cint(41)
+  IPPROTO_ICMP* = cint(1)
+  IPPROTO_RAW* = cint(255)
+  IPPROTO_TCP* = cint(6)
+  IPPROTO_UDP* = cint(17)
+  INADDR_ANY* = cint(0)
+  INADDR_BROADCAST* = cint(-1)
+  INET_ADDRSTRLEN* = cint(16)
+  IPV6_JOIN_GROUP* = cint(20)
+  IPV6_LEAVE_GROUP* = cint(21)
+  IPV6_MULTICAST_HOPS* = cint(18)
+  IPV6_MULTICAST_IF* = cint(17)
+  IPV6_MULTICAST_LOOP* = cint(19)
+  IPV6_UNICAST_HOPS* = cint(16)
+  IPV6_V6ONLY* = cint(26)
+  IPPORT_RESERVED* = cint(1024)
+  HOST_NOT_FOUND* = cint(1)
+  NO_DATA* = cint(4)
+  NO_RECOVERY* = cint(3)
+  TRY_AGAIN* = cint(2)
+  AI_PASSIVE* = cint(1)
+  AI_CANONNAME* = cint(2)
+  AI_NUMERICHOST* = cint(4)
+  AI_NUMERICSERV* = cint(1024)
+  AI_V4MAPPED* = cint(8)
+  AI_ALL* = cint(16)
+  AI_ADDRCONFIG* = cint(32)
+  NI_NOFQDN* = cint(4)
+  NI_NUMERICHOST* = cint(1)
+  NI_NAMEREQD* = cint(8)
+  NI_NUMERICSERV* = cint(2)
+  NI_DGRAM* = cint(16)
+  EAI_AGAIN* = cint(-3)
+  EAI_BADFLAGS* = cint(-1)
+  EAI_FAIL* = cint(-4)
+  EAI_FAMILY* = cint(-6)
+  EAI_MEMORY* = cint(-10)
+  EAI_NONAME* = cint(-2)
+  EAI_SERVICE* = cint(-8)
+  EAI_SOCKTYPE* = cint(-7)
+  EAI_SYSTEM* = cint(-11)
+  EAI_OVERFLOW* = cint(-12)
+  POLLIN* = cshort(1)
+  POLLRDNORM* = cshort(64)
+  POLLRDBAND* = cshort(128)
+  POLLPRI* = cshort(2)
+  POLLOUT* = cshort(4)
+  POLLWRNORM* = cshort(256)
+  POLLWRBAND* = cshort(512)
+  POLLERR* = cshort(8)
+  POLLHUP* = cshort(16)
+  POLLNVAL* = cshort(32)
+  POSIX_SPAWN_RESETIDS* = cint(1)
+  POSIX_SPAWN_SETPGROUP* = cint(2)
+  POSIX_SPAWN_SETSCHEDPARAM* = cint(16)
+  POSIX_SPAWN_SETSCHEDULER* = cint(32)
+  POSIX_SPAWN_SETSIGDEF* = cint(4)
+  POSIX_SPAWN_SETSIGMASK* = cint(8)
+  IOFBF* = cint(0)
+  IONBF* = cint(2)
diff --git a/tools/detect/macosx_consts.nim b/tools/detect/macosx_consts.nim
new file mode 100644
index 000000000..e8be56e5f
--- /dev/null
+++ b/tools/detect/macosx_consts.nim
@@ -0,0 +1,629 @@
+# Generated by detect.nim
+const
+  AIO_ALLDONE* = cint(1)
+  AIO_CANCELED* = cint(2)
+  AIO_NOTCANCELED* = cint(4)
+  LIO_NOP* = cint(0)
+  LIO_NOWAIT* = cint(1)
+  LIO_READ* = cint(1)
+  LIO_WAIT* = cint(2)
+  LIO_WRITE* = cint(2)
+  RTLD_LAZY* = cint(1)
+  RTLD_NOW* = cint(2)
+  RTLD_GLOBAL* = cint(8)
+  RTLD_LOCAL* = cint(4)
+  E2BIG* = cint(7)
+  EACCES* = cint(13)
+  EADDRINUSE* = cint(48)
+  EADDRNOTAVAIL* = cint(49)
+  EAFNOSUPPORT* = cint(47)
+  EAGAIN* = cint(35)
+  EALREADY* = cint(37)
+  EBADF* = cint(9)
+  EBADMSG* = cint(94)
+  EBUSY* = cint(16)
+  ECANCELED* = cint(89)
+  ECHILD* = cint(10)
+  ECONNABORTED* = cint(53)
+  ECONNREFUSED* = cint(61)
+  ECONNRESET* = cint(54)
+  EDEADLK* = cint(11)
+  EDESTADDRREQ* = cint(39)
+  EDOM* = cint(33)
+  EDQUOT* = cint(69)
+  EEXIST* = cint(17)
+  EFAULT* = cint(14)
+  EFBIG* = cint(27)
+  EHOSTUNREACH* = cint(65)
+  EIDRM* = cint(90)
+  EILSEQ* = cint(92)
+  EINPROGRESS* = cint(36)
+  EINTR* = cint(4)
+  EINVAL* = cint(22)
+  EIO* = cint(5)
+  EISCONN* = cint(56)
+  EISDIR* = cint(21)
+  ELOOP* = cint(62)
+  EMFILE* = cint(24)
+  EMLINK* = cint(31)
+  EMSGSIZE* = cint(40)
+  EMULTIHOP* = cint(95)
+  ENAMETOOLONG* = cint(63)
+  ENETDOWN* = cint(50)
+  ENETRESET* = cint(52)
+  ENETUNREACH* = cint(51)
+  ENFILE* = cint(23)
+  ENOBUFS* = cint(55)
+  ENODATA* = cint(96)
+  ENODEV* = cint(19)
+  ENOENT* = cint(2)
+  ENOEXEC* = cint(8)
+  ENOLCK* = cint(77)
+  ENOLINK* = cint(97)
+  ENOMEM* = cint(12)
+  ENOMSG* = cint(91)
+  ENOPROTOOPT* = cint(42)
+  ENOSPC* = cint(28)
+  ENOSR* = cint(98)
+  ENOSTR* = cint(99)
+  ENOSYS* = cint(78)
+  ENOTCONN* = cint(57)
+  ENOTDIR* = cint(20)
+  ENOTEMPTY* = cint(66)
+  ENOTSOCK* = cint(38)
+  ENOTSUP* = cint(45)
+  ENOTTY* = cint(25)
+  ENXIO* = cint(6)
+  EOPNOTSUPP* = cint(102)
+  EOVERFLOW* = cint(84)
+  EPERM* = cint(1)
+  EPIPE* = cint(32)
+  EPROTO* = cint(100)
+  EPROTONOSUPPORT* = cint(43)
+  EPROTOTYPE* = cint(41)
+  ERANGE* = cint(34)
+  EROFS* = cint(30)
+  ESPIPE* = cint(29)
+  ESRCH* = cint(3)
+  ESTALE* = cint(70)
+  ETIME* = cint(101)
+  ETIMEDOUT* = cint(60)
+  ETXTBSY* = cint(26)
+  EWOULDBLOCK* = cint(35)
+  EXDEV* = cint(18)
+  F_DUPFD* = cint(0)
+  F_GETFD* = cint(1)
+  F_SETFD* = cint(2)
+  F_GETFL* = cint(3)
+  F_SETFL* = cint(4)
+  F_GETLK* = cint(7)
+  F_SETLK* = cint(8)
+  F_SETLKW* = cint(9)
+  F_GETOWN* = cint(5)
+  F_SETOWN* = cint(6)
+  FD_CLOEXEC* = cint(1)
+  F_RDLCK* = cint(1)
+  F_UNLCK* = cint(2)
+  F_WRLCK* = cint(3)
+  O_CREAT* = cint(512)
+  O_EXCL* = cint(2048)
+  O_NOCTTY* = cint(131072)
+  O_TRUNC* = cint(1024)
+  O_APPEND* = cint(8)
+  O_DSYNC* = cint(4194304)
+  O_NONBLOCK* = cint(4)
+  O_SYNC* = cint(128)
+  O_ACCMODE* = cint(3)
+  O_RDONLY* = cint(0)
+  O_RDWR* = cint(2)
+  O_WRONLY* = cint(1)
+  FE_DIVBYZERO* = cint(4)
+  FE_INEXACT* = cint(32)
+  FE_INVALID* = cint(1)
+  FE_OVERFLOW* = cint(8)
+  FE_UNDERFLOW* = cint(16)
+  FE_ALL_EXCEPT* = cint(63)
+  FE_DOWNWARD* = cint(1024)
+  FE_TONEAREST* = cint(0)
+  FE_TOWARDZERO* = cint(3072)
+  FE_UPWARD* = cint(2048)
+  FE_DFL_ENV* = when defined(amd64): cast[pointer](0x7fff9533b1b4)
+                else: cast[pointer](0x904797f4)
+  MM_HARD* = cint(1)
+  MM_SOFT* = cint(2)
+  MM_FIRM* = cint(4)
+  MM_APPL* = cint(16)
+  MM_UTIL* = cint(32)
+  MM_OPSYS* = cint(64)
+  MM_RECOVER* = cint(4096)
+  MM_NRECOV* = cint(8192)
+  MM_HALT* = cint(1)
+  MM_ERROR* = cint(2)
+  MM_WARNING* = cint(3)
+  MM_INFO* = cint(4)
+  MM_NOSEV* = cint(0)
+  MM_PRINT* = cint(256)
+  MM_CONSOLE* = cint(512)
+  MM_OK* = cint(0)
+  MM_NOTOK* = cint(3)
+  MM_NOMSG* = cint(1)
+  MM_NOCON* = cint(2)
+  FNM_NOMATCH* = cint(1)
+  FNM_PATHNAME* = cint(2)
+  FNM_PERIOD* = cint(4)
+  FNM_NOESCAPE* = cint(1)
+  FNM_NOSYS* = cint(-1)
+  FTW_F* = cint(0)
+  FTW_D* = cint(1)
+  FTW_DNR* = cint(2)
+  FTW_DP* = cint(3)
+  FTW_NS* = cint(4)
+  FTW_SL* = cint(5)
+  FTW_SLN* = cint(6)
+  FTW_PHYS* = cint(1)
+  FTW_MOUNT* = cint(2)
+  FTW_DEPTH* = cint(4)
+  FTW_CHDIR* = cint(8)
+  GLOB_APPEND* = cint(1)
+  GLOB_DOOFFS* = cint(2)
+  GLOB_ERR* = cint(4)
+  GLOB_MARK* = cint(8)
+  GLOB_NOCHECK* = cint(16)
+  GLOB_NOESCAPE* = cint(8192)
+  GLOB_NOSORT* = cint(32)
+  GLOB_ABORTED* = cint(-2)
+  GLOB_NOMATCH* = cint(-3)
+  GLOB_NOSPACE* = cint(-1)
+  GLOB_NOSYS* = cint(-4)
+  CODESET* = cint(0)
+  D_T_FMT* = cint(1)
+  D_FMT* = cint(2)
+  T_FMT* = cint(3)
+  T_FMT_AMPM* = cint(4)
+  AM_STR* = cint(5)
+  PM_STR* = cint(6)
+  DAY_1* = cint(7)
+  DAY_2* = cint(8)
+  DAY_3* = cint(9)
+  DAY_4* = cint(10)
+  DAY_5* = cint(11)
+  DAY_6* = cint(12)
+  DAY_7* = cint(13)
+  ABDAY_1* = cint(14)
+  ABDAY_2* = cint(15)
+  ABDAY_3* = cint(16)
+  ABDAY_4* = cint(17)
+  ABDAY_5* = cint(18)
+  ABDAY_6* = cint(19)
+  ABDAY_7* = cint(20)
+  MON_1* = cint(21)
+  MON_2* = cint(22)
+  MON_3* = cint(23)
+  MON_4* = cint(24)
+  MON_5* = cint(25)
+  MON_6* = cint(26)
+  MON_7* = cint(27)
+  MON_8* = cint(28)
+  MON_9* = cint(29)
+  MON_10* = cint(30)
+  MON_11* = cint(31)
+  MON_12* = cint(32)
+  ABMON_1* = cint(33)
+  ABMON_2* = cint(34)
+  ABMON_3* = cint(35)
+  ABMON_4* = cint(36)
+  ABMON_5* = cint(37)
+  ABMON_6* = cint(38)
+  ABMON_7* = cint(39)
+  ABMON_8* = cint(40)
+  ABMON_9* = cint(41)
+  ABMON_10* = cint(42)
+  ABMON_11* = cint(43)
+  ABMON_12* = cint(44)
+  ERA* = cint(45)
+  ERA_D_FMT* = cint(46)
+  ERA_D_T_FMT* = cint(47)
+  ERA_T_FMT* = cint(48)
+  ALT_DIGITS* = cint(49)
+  RADIXCHAR* = cint(50)
+  THOUSEP* = cint(51)
+  YESEXPR* = cint(52)
+  NOEXPR* = cint(53)
+  CRNCYSTR* = cint(56)
+  LC_ALL* = cint(0)
+  LC_COLLATE* = cint(1)
+  LC_CTYPE* = cint(2)
+  LC_MESSAGES* = cint(6)
+  LC_MONETARY* = cint(3)
+  LC_NUMERIC* = cint(4)
+  LC_TIME* = cint(5)
+  PTHREAD_CANCEL_ASYNCHRONOUS* = cint(0)
+  PTHREAD_CANCEL_ENABLE* = cint(1)
+  PTHREAD_CANCEL_DEFERRED* = cint(2)
+  PTHREAD_CANCEL_DISABLE* = cint(0)
+  PTHREAD_CREATE_DETACHED* = cint(2)
+  PTHREAD_CREATE_JOINABLE* = cint(1)
+  PTHREAD_EXPLICIT_SCHED* = cint(2)
+  PTHREAD_INHERIT_SCHED* = cint(1)
+  PTHREAD_MUTEX_DEFAULT* = cint(0)
+  PTHREAD_MUTEX_ERRORCHECK* = cint(1)
+  PTHREAD_MUTEX_NORMAL* = cint(0)
+  PTHREAD_MUTEX_RECURSIVE* = cint(2)
+  PTHREAD_PRIO_INHERIT* = cint(1)
+  PTHREAD_PRIO_NONE* = cint(0)
+  PTHREAD_PRIO_PROTECT* = cint(2)
+  PTHREAD_PROCESS_SHARED* = cint(1)
+  PTHREAD_PROCESS_PRIVATE* = cint(2)
+  PTHREAD_SCOPE_PROCESS* = cint(2)
+  PTHREAD_SCOPE_SYSTEM* = cint(1)
+  F_OK* = cint(0)
+  R_OK* = cint(4)
+  W_OK* = cint(2)
+  X_OK* = cint(1)
+  CS_PATH* = cint(1)
+  CS_POSIX_V6_ILP32_OFF32_CFLAGS* = cint(2)
+  CS_POSIX_V6_ILP32_OFF32_LDFLAGS* = cint(3)
+  CS_POSIX_V6_ILP32_OFF32_LIBS* = cint(4)
+  CS_POSIX_V6_ILP32_OFFBIG_CFLAGS* = cint(5)
+  CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS* = cint(6)
+  CS_POSIX_V6_ILP32_OFFBIG_LIBS* = cint(7)
+  CS_POSIX_V6_LP64_OFF64_CFLAGS* = cint(8)
+  CS_POSIX_V6_LP64_OFF64_LDFLAGS* = cint(9)
+  CS_POSIX_V6_LP64_OFF64_LIBS* = cint(10)
+  CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS* = cint(11)
+  CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS* = cint(12)
+  CS_POSIX_V6_LPBIG_OFFBIG_LIBS* = cint(13)
+  CS_POSIX_V6_WIDTH_RESTRICTED_ENVS* = cint(14)
+  F_LOCK* = cint(1)
+  F_TEST* = cint(3)
+  F_TLOCK* = cint(2)
+  F_ULOCK* = cint(0)
+  PC_2_SYMLINKS* = cint(15)
+  PC_ALLOC_SIZE_MIN* = cint(16)
+  PC_ASYNC_IO* = cint(17)
+  PC_CHOWN_RESTRICTED* = cint(7)
+  PC_FILESIZEBITS* = cint(18)
+  PC_LINK_MAX* = cint(1)
+  PC_MAX_CANON* = cint(2)
+  PC_MAX_INPUT* = cint(3)
+  PC_NAME_MAX* = cint(4)
+  PC_NO_TRUNC* = cint(8)
+  PC_PATH_MAX* = cint(5)
+  PC_PIPE_BUF* = cint(6)
+  PC_PRIO_IO* = cint(19)
+  PC_REC_INCR_XFER_SIZE* = cint(20)
+  PC_REC_MIN_XFER_SIZE* = cint(22)
+  PC_REC_XFER_ALIGN* = cint(23)
+  PC_SYMLINK_MAX* = cint(24)
+  PC_SYNC_IO* = cint(25)
+  PC_VDISABLE* = cint(9)
+  SC_2_C_BIND* = cint(18)
+  SC_2_C_DEV* = cint(19)
+  SC_2_CHAR_TERM* = cint(20)
+  SC_2_FORT_DEV* = cint(21)
+  SC_2_FORT_RUN* = cint(22)
+  SC_2_LOCALEDEF* = cint(23)
+  SC_2_PBS* = cint(59)
+  SC_2_PBS_ACCOUNTING* = cint(60)
+  SC_2_PBS_CHECKPOINT* = cint(61)
+  SC_2_PBS_LOCATE* = cint(62)
+  SC_2_PBS_MESSAGE* = cint(63)
+  SC_2_PBS_TRACK* = cint(64)
+  SC_2_SW_DEV* = cint(24)
+  SC_2_UPE* = cint(25)
+  SC_2_VERSION* = cint(17)
+  SC_ADVISORY_INFO* = cint(65)
+  SC_AIO_LISTIO_MAX* = cint(42)
+  SC_AIO_MAX* = cint(43)
+  SC_AIO_PRIO_DELTA_MAX* = cint(44)
+  SC_ARG_MAX* = cint(1)
+  SC_ASYNCHRONOUS_IO* = cint(28)
+  SC_ATEXIT_MAX* = cint(107)
+  SC_BARRIERS* = cint(66)
+  SC_BC_BASE_MAX* = cint(9)
+  SC_BC_DIM_MAX* = cint(10)
+  SC_BC_SCALE_MAX* = cint(11)
+  SC_BC_STRING_MAX* = cint(12)
+  SC_CHILD_MAX* = cint(2)
+  SC_CLK_TCK* = cint(3)
+  SC_CLOCK_SELECTION* = cint(67)
+  SC_COLL_WEIGHTS_MAX* = cint(13)
+  SC_CPUTIME* = cint(68)
+  SC_DELAYTIMER_MAX* = cint(45)
+  SC_EXPR_NEST_MAX* = cint(14)
+  SC_FSYNC* = cint(38)
+  SC_GETGR_R_SIZE_MAX* = cint(70)
+  SC_GETPW_R_SIZE_MAX* = cint(71)
+  SC_HOST_NAME_MAX* = cint(72)
+  SC_IOV_MAX* = cint(56)
+  SC_IPV6* = cint(118)
+  SC_JOB_CONTROL* = cint(6)
+  SC_LINE_MAX* = cint(15)
+  SC_LOGIN_NAME_MAX* = cint(73)
+  SC_MAPPED_FILES* = cint(47)
+  SC_MEMLOCK* = cint(30)
+  SC_MEMLOCK_RANGE* = cint(31)
+  SC_MEMORY_PROTECTION* = cint(32)
+  SC_MESSAGE_PASSING* = cint(33)
+  SC_MONOTONIC_CLOCK* = cint(74)
+  SC_MQ_OPEN_MAX* = cint(46)
+  SC_MQ_PRIO_MAX* = cint(75)
+  SC_NGROUPS_MAX* = cint(4)
+  SC_OPEN_MAX* = cint(5)
+  SC_PAGE_SIZE* = cint(29)
+  SC_PRIORITIZED_IO* = cint(34)
+  SC_PRIORITY_SCHEDULING* = cint(35)
+  SC_RAW_SOCKETS* = cint(119)
+  SC_RE_DUP_MAX* = cint(16)
+  SC_READER_WRITER_LOCKS* = cint(76)
+  SC_REALTIME_SIGNALS* = cint(36)
+  SC_REGEXP* = cint(77)
+  SC_RTSIG_MAX* = cint(48)
+  SC_SAVED_IDS* = cint(7)
+  SC_SEM_NSEMS_MAX* = cint(49)
+  SC_SEM_VALUE_MAX* = cint(50)
+  SC_SEMAPHORES* = cint(37)
+  SC_SHARED_MEMORY_OBJECTS* = cint(39)
+  SC_SHELL* = cint(78)
+  SC_SIGQUEUE_MAX* = cint(51)
+  SC_SPAWN* = cint(79)
+  SC_SPIN_LOCKS* = cint(80)
+  SC_SPORADIC_SERVER* = cint(81)
+  SC_SS_REPL_MAX* = cint(126)
+  SC_STREAM_MAX* = cint(26)
+  SC_SYMLOOP_MAX* = cint(120)
+  SC_SYNCHRONIZED_IO* = cint(40)
+  SC_THREAD_ATTR_STACKADDR* = cint(82)
+  SC_THREAD_ATTR_STACKSIZE* = cint(83)
+  SC_THREAD_CPUTIME* = cint(84)
+  SC_THREAD_DESTRUCTOR_ITERATIONS* = cint(85)
+  SC_THREAD_KEYS_MAX* = cint(86)
+  SC_THREAD_PRIO_INHERIT* = cint(87)
+  SC_THREAD_PRIO_PROTECT* = cint(88)
+  SC_THREAD_PRIORITY_SCHEDULING* = cint(89)
+  SC_THREAD_PROCESS_SHARED* = cint(90)
+  SC_THREAD_SAFE_FUNCTIONS* = cint(91)
+  SC_THREAD_SPORADIC_SERVER* = cint(92)
+  SC_THREAD_STACK_MIN* = cint(93)
+  SC_THREAD_THREADS_MAX* = cint(94)
+  SC_THREADS* = cint(96)
+  SC_TIMEOUTS* = cint(95)
+  SC_TIMER_MAX* = cint(52)
+  SC_TIMERS* = cint(41)
+  SC_TRACE* = cint(97)
+  SC_TRACE_EVENT_FILTER* = cint(98)
+  SC_TRACE_EVENT_NAME_MAX* = cint(127)
+  SC_TRACE_INHERIT* = cint(99)
+  SC_TRACE_LOG* = cint(100)
+  SC_TRACE_NAME_MAX* = cint(128)
+  SC_TRACE_SYS_MAX* = cint(129)
+  SC_TRACE_USER_EVENT_MAX* = cint(130)
+  SC_TTY_NAME_MAX* = cint(101)
+  SC_TYPED_MEMORY_OBJECTS* = cint(102)
+  SC_TZNAME_MAX* = cint(27)
+  SC_V6_ILP32_OFF32* = cint(103)
+  SC_V6_ILP32_OFFBIG* = cint(104)
+  SC_V6_LP64_OFF64* = cint(105)
+  SC_V6_LPBIG_OFFBIG* = cint(106)
+  SC_VERSION* = cint(8)
+  SC_XBS5_ILP32_OFF32* = cint(122)
+  SC_XBS5_ILP32_OFFBIG* = cint(123)
+  SC_XBS5_LP64_OFF64* = cint(124)
+  SC_XBS5_LPBIG_OFFBIG* = cint(125)
+  SC_XOPEN_CRYPT* = cint(108)
+  SC_XOPEN_ENH_I18N* = cint(109)
+  SC_XOPEN_LEGACY* = cint(110)
+  SC_XOPEN_REALTIME* = cint(111)
+  SC_XOPEN_REALTIME_THREADS* = cint(112)
+  SC_XOPEN_SHM* = cint(113)
+  SC_XOPEN_STREAMS* = cint(114)
+  SC_XOPEN_UNIX* = cint(115)
+  SC_XOPEN_VERSION* = cint(116)
+  SEEK_SET* = cint(0)
+  SEEK_CUR* = cint(1)
+  SEEK_END* = cint(2)
+  SEM_FAILED* = cast[pointer](-1)
+  IPC_CREAT* = cint(512)
+  IPC_EXCL* = cint(1024)
+  IPC_NOWAIT* = cint(2048)
+  IPC_PRIVATE* = cint(0)
+  IPC_RMID* = cint(0)
+  IPC_SET* = cint(1)
+  IPC_STAT* = cint(2)
+  S_IFMT* = cint(61440)
+  S_IFBLK* = cint(24576)
+  S_IFCHR* = cint(8192)
+  S_IFIFO* = cint(4096)
+  S_IFREG* = cint(32768)
+  S_IFDIR* = cint(16384)
+  S_IFLNK* = cint(40960)
+  S_IFSOCK* = cint(49152)
+  S_IRWXU* = cint(448)
+  S_IRUSR* = cint(256)
+  S_IWUSR* = cint(128)
+  S_IXUSR* = cint(64)
+  S_IRWXG* = cint(56)
+  S_IRGRP* = cint(32)
+  S_IWGRP* = cint(16)
+  S_IXGRP* = cint(8)
+  S_IRWXO* = cint(7)
+  S_IROTH* = cint(4)
+  S_IWOTH* = cint(2)
+  S_IXOTH* = cint(1)
+  S_ISUID* = cint(2048)
+  S_ISGID* = cint(1024)
+  S_ISVTX* = cint(512)
+  ST_RDONLY* = cint(1)
+  ST_NOSUID* = cint(2)
+  PROT_READ* = cint(1)
+  PROT_WRITE* = cint(2)
+  PROT_EXEC* = cint(4)
+  PROT_NONE* = cint(0)
+  MAP_SHARED* = cint(1)
+  MAP_PRIVATE* = cint(2)
+  MAP_FIXED* = cint(16)
+  MS_ASYNC* = cint(1)
+  MS_SYNC* = cint(16)
+  MS_INVALIDATE* = cint(2)
+  MCL_CURRENT* = cint(1)
+  MCL_FUTURE* = cint(2)
+  MAP_FAILED* = cast[pointer](-1)
+  POSIX_MADV_NORMAL* = cint(0)
+  POSIX_MADV_SEQUENTIAL* = cint(2)
+  POSIX_MADV_RANDOM* = cint(1)
+  POSIX_MADV_WILLNEED* = cint(3)
+  POSIX_MADV_DONTNEED* = cint(4)
+  CLOCKS_PER_SEC* = clong(1000000)
+  WNOHANG* = cint(1)
+  WUNTRACED* = cint(2)
+  WEXITED* = cint(4)
+  WSTOPPED* = cint(8)
+  WCONTINUED* = cint(16)
+  WNOWAIT* = cint(32)
+  SIGEV_NONE* = cint(0)
+  SIGEV_SIGNAL* = cint(1)
+  SIGEV_THREAD* = cint(3)
+  SIGABRT* = cint(6)
+  SIGALRM* = cint(14)
+  SIGBUS* = cint(10)
+  SIGCHLD* = cint(20)
+  SIGCONT* = cint(19)
+  SIGFPE* = cint(8)
+  SIGHUP* = cint(1)
+  SIGILL* = cint(4)
+  SIGINT* = cint(2)
+  SIGKILL* = cint(9)
+  SIGPIPE* = cint(13)
+  SIGQUIT* = cint(3)
+  SIGSEGV* = cint(11)
+  SIGSTOP* = cint(17)
+  SIGTERM* = cint(15)
+  SIGTSTP* = cint(18)
+  SIGTTIN* = cint(21)
+  SIGTTOU* = cint(22)
+  SIGUSR1* = cint(30)
+  SIGUSR2* = cint(31)
+  SIGPROF* = cint(27)
+  SIGSYS* = cint(12)
+  SIGTRAP* = cint(5)
+  SIGURG* = cint(16)
+  SIGVTALRM* = cint(26)
+  SIGXCPU* = cint(24)
+  SIGXFSZ* = cint(25)
+  SA_NOCLDSTOP* = cint(8)
+  SIG_BLOCK* = cint(1)
+  SIG_UNBLOCK* = cint(2)
+  SIG_SETMASK* = cint(3)
+  SA_ONSTACK* = cint(1)
+  SA_RESETHAND* = cint(4)
+  SA_RESTART* = cint(2)
+  SA_SIGINFO* = cint(64)
+  SA_NOCLDWAIT* = cint(32)
+  SA_NODEFER* = cint(16)
+  SS_ONSTACK* = cint(1)
+  SS_DISABLE* = cint(4)
+  MINSIGSTKSZ* = cint(32768)
+  SIGSTKSZ* = cint(131072)
+  NL_SETD* = cint(1)
+  NL_CAT_LOCALE* = cint(1)
+  SCHED_FIFO* = cint(4)
+  SCHED_RR* = cint(2)
+  SCHED_OTHER* = cint(1)
+  FD_SETSIZE* = cint(1024)
+  SCM_RIGHTS* = cint(1)
+  SOCK_DGRAM* = cint(2)
+  SOCK_RAW* = cint(3)
+  SOCK_SEQPACKET* = cint(5)
+  SOCK_STREAM* = cint(1)
+  SOL_SOCKET* = cint(65535)
+  SO_ACCEPTCONN* = cint(2)
+  SO_BROADCAST* = cint(32)
+  SO_DEBUG* = cint(1)
+  SO_DONTROUTE* = cint(16)
+  SO_ERROR* = cint(4103)
+  SO_KEEPALIVE* = cint(8)
+  SO_LINGER* = cint(128)
+  SO_OOBINLINE* = cint(256)
+  SO_RCVBUF* = cint(4098)
+  SO_RCVLOWAT* = cint(4100)
+  SO_RCVTIMEO* = cint(4102)
+  SO_REUSEADDR* = cint(4)
+  SO_SNDBUF* = cint(4097)
+  SO_SNDLOWAT* = cint(4099)
+  SO_SNDTIMEO* = cint(4101)
+  SO_TYPE* = cint(4104)
+  SOMAXCONN* = cint(128)
+  MSG_CTRUNC* = cint(32)
+  MSG_DONTROUTE* = cint(4)
+  MSG_EOR* = cint(8)
+  MSG_OOB* = cint(1)
+  MSG_PEEK* = cint(2)
+  MSG_TRUNC* = cint(16)
+  MSG_WAITALL* = cint(64)
+  AF_INET* = cint(2)
+  AF_INET6* = cint(30)
+  AF_UNIX* = cint(1)
+  AF_UNSPEC* = cint(0)
+  SHUT_RD* = cint(0)
+  SHUT_RDWR* = cint(2)
+  SHUT_WR* = cint(1)
+  IPPROTO_IP* = cint(0)
+  IPPROTO_IPV6* = cint(41)
+  IPPROTO_ICMP* = cint(1)
+  IPPROTO_RAW* = cint(255)
+  IPPROTO_TCP* = cint(6)
+  IPPROTO_UDP* = cint(17)
+  INADDR_ANY* = cint(0)
+  INADDR_BROADCAST* = cint(-1)
+  INET_ADDRSTRLEN* = cint(16)
+  IPV6_JOIN_GROUP* = cint(12)
+  IPV6_LEAVE_GROUP* = cint(13)
+  IPV6_MULTICAST_HOPS* = cint(10)
+  IPV6_MULTICAST_IF* = cint(9)
+  IPV6_MULTICAST_LOOP* = cint(11)
+  IPV6_UNICAST_HOPS* = cint(4)
+  IPV6_V6ONLY* = cint(27)
+  IPPORT_RESERVED* = cint(1024)
+  HOST_NOT_FOUND* = cint(1)
+  NO_DATA* = cint(4)
+  NO_RECOVERY* = cint(3)
+  TRY_AGAIN* = cint(2)
+  AI_PASSIVE* = cint(1)
+  AI_CANONNAME* = cint(2)
+  AI_NUMERICHOST* = cint(4)
+  AI_NUMERICSERV* = cint(4096)
+  AI_V4MAPPED* = cint(2048)
+  AI_ALL* = cint(256)
+  AI_ADDRCONFIG* = cint(1024)
+  NI_NOFQDN* = cint(1)
+  NI_NUMERICHOST* = cint(2)
+  NI_NAMEREQD* = cint(4)
+  NI_NUMERICSERV* = cint(8)
+  NI_DGRAM* = cint(16)
+  EAI_AGAIN* = cint(2)
+  EAI_BADFLAGS* = cint(3)
+  EAI_FAIL* = cint(4)
+  EAI_FAMILY* = cint(5)
+  EAI_MEMORY* = cint(6)
+  EAI_NONAME* = cint(8)
+  EAI_SERVICE* = cint(9)
+  EAI_SOCKTYPE* = cint(10)
+  EAI_SYSTEM* = cint(11)
+  EAI_OVERFLOW* = cint(14)
+  POLLIN* = cshort(1)
+  POLLRDNORM* = cshort(64)
+  POLLRDBAND* = cshort(128)
+  POLLPRI* = cshort(2)
+  POLLOUT* = cshort(4)
+  POLLWRNORM* = cshort(4)
+  POLLWRBAND* = cshort(256)
+  POLLERR* = cshort(8)
+  POLLHUP* = cshort(16)
+  POLLNVAL* = cshort(32)
+  POSIX_SPAWN_RESETIDS* = cint(1)
+  POSIX_SPAWN_SETPGROUP* = cint(2)
+  POSIX_SPAWN_SETSIGDEF* = cint(4)
+  POSIX_SPAWN_SETSIGMASK* = cint(8)
+  IOFBF* = cint(0)
+  IONBF* = cint(2)
+
diff --git a/tools/detect/timesize.c b/tools/detect/timesize.c
new file mode 100644
index 000000000..35fc90982
--- /dev/null
+++ b/tools/detect/timesize.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main(void) {
+  printf("%ld\n", sizeof(time_t));
+  return 0;
+}
+
diff --git a/tools/detect/windows_amd64_consts.nim b/tools/detect/windows_amd64_consts.nim
new file mode 100644
index 000000000..d72c9786d
--- /dev/null
+++ b/tools/detect/windows_amd64_consts.nim
@@ -0,0 +1,152 @@
+# Generated by detect.nim
+const
+  E2BIG* = cint(7)
+  EACCES* = cint(13)
+  EADDRINUSE* = cint(100)
+  EADDRNOTAVAIL* = cint(101)
+  EAFNOSUPPORT* = cint(102)
+  EAGAIN* = cint(11)
+  EALREADY* = cint(103)
+  EBADF* = cint(9)
+  EBUSY* = cint(16)
+  ECANCELED* = cint(105)
+  ECHILD* = cint(10)
+  ECONNABORTED* = cint(106)
+  ECONNREFUSED* = cint(107)
+  ECONNRESET* = cint(108)
+  EDEADLK* = cint(36)
+  EDESTADDRREQ* = cint(109)
+  EDOM* = cint(33)
+  EEXIST* = cint(17)
+  EFAULT* = cint(14)
+  EFBIG* = cint(27)
+  EHOSTUNREACH* = cint(110)
+  EILSEQ* = cint(42)
+  EINPROGRESS* = cint(112)
+  EINTR* = cint(4)
+  EINVAL* = cint(22)
+  EIO* = cint(5)
+  EISCONN* = cint(113)
+  EISDIR* = cint(21)
+  ELOOP* = cint(114)
+  EMFILE* = cint(24)
+  EMLINK* = cint(31)
+  EMSGSIZE* = cint(115)
+  ENAMETOOLONG* = cint(38)
+  ENETDOWN* = cint(116)
+  ENETRESET* = cint(117)
+  ENETUNREACH* = cint(118)
+  ENFILE* = cint(23)
+  ENOBUFS* = cint(119)
+  ENODEV* = cint(19)
+  ENOENT* = cint(2)
+  ENOEXEC* = cint(8)
+  ENOLCK* = cint(39)
+  ENOMEM* = cint(12)
+  ENOPROTOOPT* = cint(123)
+  ENOSPC* = cint(28)
+  ENOSYS* = cint(40)
+  ENOTCONN* = cint(126)
+  ENOTDIR* = cint(20)
+  ENOTEMPTY* = cint(41)
+  ENOTSOCK* = cint(128)
+  ENOTSUP* = cint(129)
+  ENOTTY* = cint(25)
+  ENXIO* = cint(6)
+  EOPNOTSUPP* = cint(130)
+  EOVERFLOW* = cint(132)
+  EPERM* = cint(1)
+  EPIPE* = cint(32)
+  EPROTO* = cint(134)
+  EPROTONOSUPPORT* = cint(135)
+  EPROTOTYPE* = cint(136)
+  ERANGE* = cint(34)
+  EROFS* = cint(30)
+  ESPIPE* = cint(29)
+  ESRCH* = cint(3)
+  ETIMEDOUT* = cint(138)
+  EWOULDBLOCK* = cint(140)
+  EXDEV* = cint(18)
+  O_CREAT* = cint(256)
+  O_EXCL* = cint(1024)
+  O_TRUNC* = cint(512)
+  O_APPEND* = cint(8)
+  O_ACCMODE* = cint(3)
+  O_RDONLY* = cint(0)
+  O_RDWR* = cint(2)
+  O_WRONLY* = cint(1)
+  FE_DIVBYZERO* = cint(4)
+  FE_INEXACT* = cint(32)
+  FE_INVALID* = cint(1)
+  FE_OVERFLOW* = cint(8)
+  FE_UNDERFLOW* = cint(16)
+  FE_ALL_EXCEPT* = cint(63)
+  FE_DOWNWARD* = cint(1024)
+  FE_TONEAREST* = cint(0)
+  FE_TOWARDZERO* = cint(3072)
+  FE_UPWARD* = cint(2048)
+  FE_DFL_ENV* = pointer(nil)
+  LC_ALL* = cint(0)
+  LC_COLLATE* = cint(1)
+  LC_CTYPE* = cint(2)
+  LC_MONETARY* = cint(3)
+  LC_NUMERIC* = cint(4)
+  LC_TIME* = cint(5)
+  PTHREAD_BARRIER_SERIAL_THREAD* = cint(1)
+  PTHREAD_CANCEL_ASYNCHRONOUS* = cint(2)
+  PTHREAD_CANCEL_ENABLE* = cint(1)
+  PTHREAD_CANCEL_DEFERRED* = cint(0)
+  PTHREAD_CANCEL_DISABLE* = cint(0)
+  PTHREAD_CREATE_DETACHED* = cint(4)
+  PTHREAD_CREATE_JOINABLE* = cint(0)
+  PTHREAD_EXPLICIT_SCHED* = cint(0)
+  PTHREAD_INHERIT_SCHED* = cint(8)
+  PTHREAD_MUTEX_DEFAULT* = cint(0)
+  PTHREAD_MUTEX_ERRORCHECK* = cint(1)
+  PTHREAD_MUTEX_NORMAL* = cint(0)
+  PTHREAD_MUTEX_RECURSIVE* = cint(2)
+  PTHREAD_PRIO_INHERIT* = cint(8)
+  PTHREAD_PRIO_NONE* = cint(0)
+  PTHREAD_PRIO_PROTECT* = cint(16)
+  PTHREAD_PROCESS_SHARED* = cint(1)
+  PTHREAD_PROCESS_PRIVATE* = cint(0)
+  PTHREAD_SCOPE_PROCESS* = cint(0)
+  PTHREAD_SCOPE_SYSTEM* = cint(16)
+  F_OK* = cint(0)
+  R_OK* = cint(4)
+  W_OK* = cint(2)
+  X_OK* = cint(1)
+  SEEK_SET* = cint(0)
+  SEEK_CUR* = cint(1)
+  SEEK_END* = cint(2)
+  SEM_FAILED* = pointer(nil)
+  S_IFMT* = cint(61440)
+  S_IFBLK* = cint(12288)
+  S_IFCHR* = cint(8192)
+  S_IFIFO* = cint(4096)
+  S_IFREG* = cint(32768)
+  S_IFDIR* = cint(16384)
+  S_IRWXU* = cint(448)
+  S_IRUSR* = cint(256)
+  S_IWUSR* = cint(128)
+  S_IXUSR* = cint(64)
+  CLOCKS_PER_SEC* = clong(1000)
+  CLOCK_PROCESS_CPUTIME_ID* = cint(2)
+  CLOCK_THREAD_CPUTIME_ID* = cint(3)
+  CLOCK_REALTIME* = cint(0)
+  TIMER_ABSTIME* = cint(1)
+  CLOCK_MONOTONIC* = cint(1)
+  SIGABRT* = cint(22)
+  SIGFPE* = cint(8)
+  SIGILL* = cint(4)
+  SIGINT* = cint(2)
+  SIGSEGV* = cint(11)
+  SIGTERM* = cint(15)
+  SIG_BLOCK* = cint(0)
+  SIG_UNBLOCK* = cint(1)
+  SIG_SETMASK* = cint(2)
+  SCHED_FIFO* = cint(1)
+  SCHED_RR* = cint(2)
+  SCHED_OTHER* = cint(0)
+  IOFBF* = cint(0)
+  IONBF* = cint(4)
diff --git a/tools/detect/windows_i386_consts.nim b/tools/detect/windows_i386_consts.nim
new file mode 100644
index 000000000..cd6c475f4
--- /dev/null
+++ b/tools/detect/windows_i386_consts.nim
@@ -0,0 +1,96 @@
+# Generated by detect.nim

+const

+  E2BIG* = cint(7)

+  EACCES* = cint(13)

+  EAGAIN* = cint(11)

+  EBADF* = cint(9)

+  EBUSY* = cint(16)

+  ECHILD* = cint(10)

+  EDEADLK* = cint(36)

+  EDOM* = cint(33)

+  EEXIST* = cint(17)

+  EFAULT* = cint(14)

+  EFBIG* = cint(27)

+  EILSEQ* = cint(42)

+  EINTR* = cint(4)

+  EINVAL* = cint(22)

+  EIO* = cint(5)

+  EISDIR* = cint(21)

+  EMFILE* = cint(24)

+  EMLINK* = cint(31)

+  ENAMETOOLONG* = cint(38)

+  ENFILE* = cint(23)

+  ENODEV* = cint(19)

+  ENOENT* = cint(2)

+  ENOEXEC* = cint(8)

+  ENOLCK* = cint(39)

+  ENOMEM* = cint(12)

+  ENOSPC* = cint(28)

+  ENOSYS* = cint(40)

+  ENOTDIR* = cint(20)

+  ENOTEMPTY* = cint(41)

+  ENOTSUP* = cint(48)

+  ENOTTY* = cint(25)

+  ENXIO* = cint(6)

+  EPERM* = cint(1)

+  EPIPE* = cint(32)

+  ERANGE* = cint(34)

+  EROFS* = cint(30)

+  ESPIPE* = cint(29)

+  ESRCH* = cint(3)

+  ETIMEDOUT* = cint(10060)

+  EXDEV* = cint(18)

+  O_CREAT* = cint(256)

+  O_EXCL* = cint(1024)

+  O_TRUNC* = cint(512)

+  O_APPEND* = cint(8)

+  O_ACCMODE* = cint(3)

+  O_RDONLY* = cint(0)

+  O_RDWR* = cint(2)

+  O_WRONLY* = cint(1)

+  FE_DIVBYZERO* = cint(4)

+  FE_INEXACT* = cint(32)

+  FE_INVALID* = cint(1)

+  FE_OVERFLOW* = cint(8)

+  FE_UNDERFLOW* = cint(16)

+  FE_ALL_EXCEPT* = cint(63)

+  FE_DOWNWARD* = cint(1024)

+  FE_TONEAREST* = cint(0)

+  FE_TOWARDZERO* = cint(3072)

+  FE_UPWARD* = cint(2048)

+  FE_DFL_ENV* = pointer(nil)

+  LC_ALL* = cint(0)

+  LC_COLLATE* = cint(1)

+  LC_CTYPE* = cint(2)

+  LC_MONETARY* = cint(3)

+  LC_NUMERIC* = cint(4)

+  LC_TIME* = cint(5)

+  F_OK* = cint(0)

+  R_OK* = cint(4)

+  W_OK* = cint(2)

+  X_OK* = cint(1)

+  SEEK_SET* = cint(0)

+  SEEK_CUR* = cint(1)

+  SEEK_END* = cint(2)

+  S_IFMT* = cint(61440)

+  S_IFBLK* = cint(12288)

+  S_IFCHR* = cint(8192)

+  S_IFIFO* = cint(4096)

+  S_IFREG* = cint(32768)

+  S_IFDIR* = cint(16384)

+  S_IRWXU* = cint(448)

+  S_IRUSR* = cint(256)

+  S_IWUSR* = cint(128)

+  S_IXUSR* = cint(64)

+  CLOCKS_PER_SEC* = clong(1000)

+  SIGABRT* = cint(22)

+  SIGFPE* = cint(8)

+  SIGILL* = cint(4)

+  SIGINT* = cint(2)

+  SIGSEGV* = cint(11)

+  SIGTERM* = cint(15)

+  SIG_BLOCK* = cint(0)

+  SIG_UNBLOCK* = cint(1)

+  SIG_SETMASK* = cint(2)

+  IOFBF* = cint(0)

+  IONBF* = cint(4)

diff --git a/tools/fakedeps.nim b/tools/fakedeps.nim
new file mode 100644
index 000000000..80623fafb
--- /dev/null
+++ b/tools/fakedeps.nim
@@ -0,0 +1,18 @@
+import strutils, os, pegs, strtabs, math, threadpool, times
+
+proc fakeCppDep(x: ptr float) {.importcpp: "fakeCppDep", header: "<vector>".}
+proc fakeTimeDep() = echo(times.getDateStr())
+proc fakedeps() =
+  var x = 0.4
+  {.emit: "#if 0\n".}
+  fakeCppDep(addr x)
+  {.emit: "#endif\n".}
+
+  # this is not true:
+  if math.sin(x) > 0.6:
+    spawn(fakeTimeDep())
+
+proc main =
+  fakedeps()
+when isMainModule:
+  main()
\ No newline at end of file
diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim
new file mode 100644
index 000000000..72e4adc07
--- /dev/null
+++ b/tools/nimgrep.nim
@@ -0,0 +1,334 @@
+#
+#
+#           Nim Grep Utility
+#        (c) Copyright 2012 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  os, strutils, parseopt, pegs, re, terminal
+
+const
+  Version = "0.9"
+  Usage = "nimgrep - Nim Grep Utility Version " & Version & """
+
+  (c) 2012 Andreas Rumpf
+Usage:
+  nimgrep [options] [pattern] [replacement] (file/directory)*
+Options:
+  --find, -f          find the pattern (default)
+  --replace, -r       replace the pattern
+  --peg               pattern is a peg
+  --re                pattern is a regular expression (default); extended 
+                      syntax for the regular expression is always turned on
+  --recursive         process directories recursively
+  --confirm           confirm each occurrence/replacement; there is a chance 
+                      to abort any time without touching the file
+  --stdin             read pattern from stdin (to avoid the shell's confusing
+                      quoting rules)
+  --word, -w          the match should have word boundaries (buggy for pegs!)
+  --ignoreCase, -i    be case insensitive
+  --ignoreStyle, -y   be style insensitive
+  --ext:EX1|EX2|...   only search the files with the given extension(s)
+  --nocolor           output will be given without any colours.
+  --verbose           be verbose: list every processed file
+  --help, -h          shows this help
+  --version, -v       shows the version
+"""
+
+type
+  TOption = enum 
+    optFind, optReplace, optPeg, optRegex, optRecursive, optConfirm, optStdin,
+    optWord, optIgnoreCase, optIgnoreStyle, optVerbose
+  TOptions = set[TOption]
+  TConfirmEnum = enum 
+    ceAbort, ceYes, ceAll, ceNo, ceNone
+    
+var
+  filenames: seq[string] = @[]
+  pattern = ""
+  replacement = ""
+  extensions: seq[string] = @[]
+  options: TOptions = {optRegex}
+  useWriteStyled = true
+
+proc ask(msg: string): string =
+  stdout.write(msg)
+  result = stdin.readLine()
+
+proc confirm: TConfirmEnum = 
+  while true:
+    case normalize(ask("     [a]bort; [y]es, a[l]l, [n]o, non[e]: "))
+    of "a", "abort": return ceAbort 
+    of "y", "yes": return ceYes
+    of "l", "all": return ceAll
+    of "n", "no": return ceNo
+    of "e", "none": return ceNone
+    else: discard
+
+proc countLines(s: string, first, last: int): int = 
+  var i = first
+  while i <= last:
+    if s[i] == '\13': 
+      inc result
+      if i < last and s[i+1] == '\10': inc(i)
+    elif s[i] == '\10': 
+      inc result
+    inc i
+
+proc beforePattern(s: string, first: int): int = 
+  result = first-1
+  while result >= 0:
+    if s[result] in NewLines: break
+    dec(result)
+  inc(result)
+
+proc afterPattern(s: string, last: int): int = 
+  result = last+1
+  while result < s.len:
+    if s[result] in NewLines: break
+    inc(result)
+  dec(result)
+
+proc writeColored(s: string) =
+  if useWriteStyled:
+    terminal.writeStyled(s, {styleUnderscore, styleBright})
+  else:
+    stdout.write(s)
+
+proc highlight(s, match, repl: string, t: tuple[first, last: int],
+               line: int, showRepl: bool) = 
+  const alignment = 6
+  stdout.write(line.`$`.align(alignment), ": ")
+  var x = beforePattern(s, t.first)
+  var y = afterPattern(s, t.last)
+  for i in x .. t.first-1: stdout.write(s[i])
+  writeColored(match)
+  for i in t.last+1 .. y: stdout.write(s[i])
+  stdout.write("\n")
+  if showRepl:
+    stdout.write(spaces(alignment-1), "-> ")
+    for i in x .. t.first-1: stdout.write(s[i])
+    writeColored(repl)
+    for i in t.last+1 .. y: stdout.write(s[i])
+    stdout.write("\n")
+
+proc processFile(filename: string) =
+  var filenameShown = false
+  template beforeHighlight =
+    if not filenameShown and optVerbose notin options: 
+      stdout.writeln(filename)
+      filenameShown = true
+  
+  var buffer: string
+  try:
+    buffer = system.readFile(filename)
+  except IOError: 
+    echo "cannot open file: ", filename
+    return
+  if optVerbose in options: stdout.writeln(filename)
+  var pegp: TPeg
+  var rep: Regex
+  var result: string
+
+  if optRegex in options:
+    if {optIgnoreCase, optIgnoreStyle} * options != {}:
+      rep = re(pattern, {reExtended, reIgnoreCase})
+    else:
+      rep = re(pattern)
+  else:
+    pegp = peg(pattern)
+    
+  if optReplace in options:
+    result = newStringOfCap(buffer.len)
+    
+  var line = 1
+  var i = 0
+  var matches: array[0..re.MaxSubpatterns-1, string]
+  for j in 0..high(matches): matches[j] = ""
+  var reallyReplace = true
+  while i < buffer.len:
+    var t: tuple[first, last: int]
+    if optRegex notin options:
+      t = findBounds(buffer, pegp, matches, i)
+    else:
+      t = findBounds(buffer, rep, matches, i)
+    if t.first <= 0: break
+    inc(line, countLines(buffer, i, t.first-1))
+    
+    var wholeMatch = buffer.substr(t.first, t.last)
+    
+    beforeHighlight()
+    if optReplace notin options: 
+      highlight(buffer, wholeMatch, "", t, line, showRepl=false)
+    else:
+      var r: string
+      if optRegex notin options:
+        r = replace(wholeMatch, pegp, replacement % matches)
+      else: 
+        r = replace(wholeMatch, rep, replacement % matches)
+      if optConfirm in options: 
+        highlight(buffer, wholeMatch, r, t, line, showRepl=true)
+        case confirm()
+        of ceAbort: quit(0)
+        of ceYes: reallyReplace = true 
+        of ceAll: 
+          reallyReplace = true
+          options.excl(optConfirm)
+        of ceNo:
+          reallyReplace = false
+        of ceNone:
+          reallyReplace = false
+          options.excl(optConfirm)
+      else:
+        highlight(buffer, wholeMatch, r, t, line, showRepl=reallyReplace)
+      if reallyReplace:
+        result.add(buffer.substr(i, t.first-1))
+        result.add(r)
+      else:
+        result.add(buffer.substr(i, t.last))
+
+    inc(line, countLines(buffer, t.first, t.last))
+    i = t.last+1
+  if optReplace in options:
+    result.add(substr(buffer, i))
+    var f: File
+    if open(f, filename, fmWrite):
+      f.write(result)
+      f.close()
+    else:
+      quit "cannot open file for overwriting: " & filename
+
+proc hasRightExt(filename: string, exts: seq[string]): bool =
+  var y = splitFile(filename).ext.substr(1) # skip leading '.'
+  for x in items(exts): 
+    if os.cmpPaths(x, y) == 0: return true
+
+proc styleInsensitive(s: string): string = 
+  template addx: stmt = 
+    result.add(s[i])
+    inc(i)
+  result = ""
+  var i = 0
+  var brackets = 0
+  while i < s.len:
+    case s[i]
+    of 'A'..'Z', 'a'..'z', '0'..'9': 
+      addx()
+      if brackets == 0: result.add("_?")
+    of '_':
+      addx()
+      result.add('?')
+    of '[':
+      addx()
+      inc(brackets)
+    of ']':
+      addx()
+      if brackets > 0: dec(brackets)
+    of '?':
+      addx()
+      if s[i] == '<':
+        addx()
+        while s[i] != '>' and s[i] != '\0': addx()
+    of '\\':
+      addx()
+      if s[i] in strutils.Digits: 
+        while s[i] in strutils.Digits: addx()
+      else:
+        addx()
+    else: addx()
+
+proc walker(dir: string) = 
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile: 
+      if extensions.len == 0 or path.hasRightExt(extensions):
+        processFile(path)
+    of pcDir: 
+      if optRecursive in options:
+        walker(path)
+    else: discard
+  if existsFile(dir): processFile(dir)
+
+proc writeHelp() = 
+  stdout.write(Usage)
+  quit(0)
+
+proc writeVersion() = 
+  stdout.write(Version & "\n")
+  quit(0)
+
+proc checkOptions(subset: TOptions, a, b: string) =
+  if subset <= options:
+    quit("cannot specify both '$#' and '$#'" % [a, b])
+
+for kind, key, val in getopt():
+  case kind
+  of cmdArgument:
+    if options.contains(optStdin): 
+      filenames.add(key)
+    elif pattern.len == 0: 
+      pattern = key
+    elif options.contains(optReplace) and replacement.len == 0:
+      replacement = key
+    else:
+      filenames.add(key)
+  of cmdLongoption, cmdShortOption:
+    case normalize(key)
+    of "find", "f": incl(options, optFind)
+    of "replace", "r": incl(options, optReplace)
+    of "peg":
+      excl(options, optRegex)
+      incl(options, optPeg)
+    of "re":
+      incl(options, optRegex)
+      excl(options, optPeg)
+    of "recursive": incl(options, optRecursive)
+    of "confirm": incl(options, optConfirm)
+    of "stdin": incl(options, optStdin)
+    of "word", "w": incl(options, optWord)
+    of "ignorecase", "i": incl(options, optIgnoreCase)
+    of "ignorestyle", "y": incl(options, optIgnoreStyle)
+    of "ext": extensions = val.split('|')
+    of "nocolor": useWriteStyled = false
+    of "verbose": incl(options, optVerbose)
+    of "help", "h": writeHelp()
+    of "version", "v": writeVersion()
+    else: writeHelp()
+  of cmdEnd: assert(false) # cannot happen
+
+when defined(posix):
+  useWriteStyled = terminal.isatty(stdout)
+
+checkOptions({optFind, optReplace}, "find", "replace")
+checkOptions({optPeg, optRegex}, "peg", "re")
+checkOptions({optIgnoreCase, optIgnoreStyle}, "ignore_case", "ignore_style")
+
+if optStdin in options: 
+  pattern = ask("pattern [ENTER to exit]: ")
+  if isNil(pattern) or pattern.len == 0: quit(0)
+  if optReplace in options:
+    replacement = ask("replacement [supports $1, $# notations]: ")
+
+if pattern.len == 0:
+  writeHelp()
+else: 
+  if filenames.len == 0: 
+    filenames.add(os.getCurrentDir())
+  if optRegex notin options: 
+    if optWord in options:
+      pattern = r"(^ / !\letter)(" & pattern & r") !\letter"
+    if optIgnoreStyle in options: 
+      pattern = "\\y " & pattern
+    elif optIgnoreCase in options:
+      pattern = "\\i " & pattern
+  else:
+    if optIgnoreStyle in options: 
+      pattern = styleInsensitive(pattern)
+    if optWord in options:
+      pattern = r"\b (:?" & pattern & r") \b"
+  for f in items(filenames):
+    walker(f)
+
diff --git a/tools/nimgrep.nim.cfg b/tools/nimgrep.nim.cfg
new file mode 100644
index 000000000..6d0ea5aad
--- /dev/null
+++ b/tools/nimgrep.nim.cfg
@@ -0,0 +1,5 @@
+# The GC is stable enough now:
+
+#--gc:none
+
+
diff --git a/tools/niminst/EnvVarUpdate.nsh b/tools/niminst/EnvVarUpdate.nsh
new file mode 100644
index 000000000..4340b8f3c
--- /dev/null
+++ b/tools/niminst/EnvVarUpdate.nsh
@@ -0,0 +1,346 @@
+/**
+ *  EnvVarUpdate.nsh
+ *    : Environmental Variables: append, prepend, and remove entries
+ *
+ *     WARNING: If you use StrFunc.nsh header then include it before this file
+ *              with all required definitions. This is to avoid conflicts
+ *
+ *  Usage:
+ *    ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
+ *
+ *  Credits:
+ *  Version 1.0 
+ *  * Cal Turney (turnec2)
+ *  * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
+ *    function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
+ *    WriteEnvStr, and un.DeleteEnvStr
+ *  * Diego Pedroso (deguix) for StrTok
+ *  * Kevin English (kenglish_hi) for StrContains
+ *  * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry  
+ *    (dandaman32) for StrReplace
+ *
+ *  Version 1.1 (compatibility with StrFunc.nsh)
+ *  * techtonik
+ *
+ *  http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
+ *
+ */
+
+
+!ifndef ENVVARUPDATE_FUNCTION
+!define ENVVARUPDATE_FUNCTION
+!verbose push
+!verbose 3
+!include "LogicLib.nsh"
+!include "WinMessages.NSH"
+!include "StrFunc.nsh"
+
+; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
+!macro _IncludeStrFunction StrFuncName
+  !ifndef ${StrFuncName}_INCLUDED
+    ${${StrFuncName}}
+  !endif
+  !ifndef Un${StrFuncName}_INCLUDED
+    ${Un${StrFuncName}}
+  !endif
+  !define un.${StrFuncName} "${Un${StrFuncName}}"
+!macroend
+
+!insertmacro _IncludeStrFunction StrTok
+!insertmacro _IncludeStrFunction StrStr
+!insertmacro _IncludeStrFunction StrRep
+
+; ---------------------------------- Macro Definitions ----------------------------------------
+!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
+  Push "${EnvVarName}"
+  Push "${Action}"
+  Push "${RegLoc}"
+  Push "${PathString}"
+    Call EnvVarUpdate
+  Pop "${ResultVar}"
+!macroend
+!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
+ 
+!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
+  Push "${EnvVarName}"
+  Push "${Action}"
+  Push "${RegLoc}"
+  Push "${PathString}"
+    Call un.EnvVarUpdate
+  Pop "${ResultVar}"
+!macroend
+!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
+; ---------------------------------- Macro Definitions end-------------------------------------
+ 
+;----------------------------------- EnvVarUpdate start----------------------------------------
+!define hklm_all_users     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
+!define hkcu_current_user  'HKCU "Environment"'
+ 
+!macro EnvVarUpdate UN
+ 
+Function ${UN}EnvVarUpdate
+ 
+  Push $0
+  Exch 4
+  Exch $1
+  Exch 3
+  Exch $2
+  Exch 2
+  Exch $3
+  Exch
+  Exch $4
+  Push $5
+  Push $6
+  Push $7
+  Push $8
+  Push $9
+  Push $R0
+ 
+  /* After this point:
+  -------------------------
+     $0 = ResultVar     (returned)
+     $1 = EnvVarName    (input)
+     $2 = Action        (input)
+     $3 = RegLoc        (input)
+     $4 = PathString    (input)
+     $5 = Orig EnvVar   (read from registry)
+     $6 = Len of $0     (temp)
+     $7 = tempstr1      (temp)
+     $8 = Entry counter (temp)
+     $9 = tempstr2      (temp)
+     $R0 = tempChar     (temp)  */
+ 
+  ; Step 1:  Read contents of EnvVarName from RegLoc
+  ;
+  ; Check for empty EnvVarName
+  ${If} $1 == ""
+    SetErrors
+    DetailPrint "ERROR: EnvVarName is blank"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Check for valid Action
+  ${If}    $2 != "A"
+  ${AndIf} $2 != "P"
+  ${AndIf} $2 != "R"
+    SetErrors
+    DetailPrint "ERROR: Invalid Action - must be A, P, or R"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ${If} $3 == HKLM
+    ReadRegStr $5 ${hklm_all_users} $1     ; Get EnvVarName from all users into $5
+  ${ElseIf} $3 == HKCU
+    ReadRegStr $5 ${hkcu_current_user} $1  ; Read EnvVarName from current user into $5
+  ${Else}
+    SetErrors
+    DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Check for empty PathString
+  ${If} $4 == ""
+    SetErrors
+    DetailPrint "ERROR: PathString is blank"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  Push $6
+  Push $7
+  Push $8
+  StrLen $7 $4  
+  StrLen $6 $5
+  IntOp $8 $6 + $7
+  ${If} $5 == ""
+  ${OrIf} $8 >= ${NSIS_MAX_STRLEN}
+    SetErrors
+    DetailPrint "Current $1 length ($6) too long to modify in NSIS; set manually if needed"
+    Pop $8
+    Pop $7
+    Pop $6
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+  Pop $8
+  Pop $7
+  Pop $6
+
+  ; Make sure we've got some work to do
+  ${If} $5 == ""
+  ${AndIf} $2 == "R"
+    SetErrors
+    DetailPrint "$1 is empty - Nothing to remove"
+    Goto EnvVarUpdate_Restore_Vars
+  ${EndIf}
+ 
+  ; Step 2: Scrub EnvVar
+  ;
+  StrCpy $0 $5                             ; Copy the contents to $0
+  ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
+  ; after the last one are not removed here but instead in Step 3)
+  ${If} $0 != ""                           ; If EnvVar is not empty ...
+    ${Do}
+      ${${UN}StrStr} $7 $0 " ;"
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 " ;" ";"         ; Remove '<space>;'
+    ${Loop}
+    ${Do}
+      ${${UN}StrStr} $7 $0 "; "
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 "; " ";"         ; Remove ';<space>'
+    ${Loop}
+    ${Do}
+      ${${UN}StrStr} $7 $0 ";;" 
+      ${If} $7 == ""
+        ${ExitDo}
+      ${EndIf}
+      ${${UN}StrRep} $0  $0 ";;" ";"
+    ${Loop}
+ 
+    ; Remove a leading or trailing semicolon from EnvVar
+    StrCpy  $7  $0 1 0
+    ${If} $7 == ";"
+      StrCpy $0  $0 "" 1                   ; Change ';<EnvVar>' to '<EnvVar>'
+    ${EndIf}
+    StrLen $6 $0
+    IntOp $6 $6 - 1
+    StrCpy $7  $0 1 $6
+    ${If} $7 == ";"
+     StrCpy $0  $0 $6                      ; Change ';<EnvVar>' to '<EnvVar>'
+    ${EndIf}
+    ; DetailPrint "Scrubbed $1: [$0]"      ; Uncomment to debug
+  ${EndIf}
+ 
+  /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
+     $6 = bool flag (1 = found and removed PathString)
+     $7 = a string (e.g. path) delimited by semicolon(s)
+     $8 = entry counter starting at 0
+     $9 = copy of $0
+     $R0 = tempChar      */
+ 
+  ${If} $5 != ""                           ; If EnvVar is not empty ...
+    StrCpy $9 $0
+    StrCpy $0 ""
+    StrCpy $8 0
+    StrCpy $6 0
+ 
+    ${Do}
+      ${${UN}StrTok} $7 $9 ";" $8 "0"      ; $7 = next entry, $8 = entry counter
+ 
+      ${If} $7 == ""                       ; If we've run out of entries,
+        ${ExitDo}                          ;    were done
+      ${EndIf}                             ;
+ 
+      ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
+      ${Do}
+        StrCpy $R0  $7 1
+        ${If} $R0 != " "
+          ${ExitDo}
+        ${EndIf}
+        StrCpy $7   $7 "" 1                ;  Remove leading space
+      ${Loop}
+      ${Do}
+        StrCpy $R0  $7 1 -1
+        ${If} $R0 != " "
+          ${ExitDo}
+        ${EndIf}
+        StrCpy $7   $7 -1                  ;  Remove trailing space
+      ${Loop}
+      ${If} $7 == $4                       ; If string matches, remove it by not appending it
+        StrCpy $6 1                        ; Set 'found' flag
+      ${ElseIf} $7 != $4                   ; If string does NOT match
+      ${AndIf}  $0 == ""                   ;    and the 1st string being added to $0,
+        StrCpy $0 $7                       ;    copy it to $0 without a prepended semicolon
+      ${ElseIf} $7 != $4                   ; If string does NOT match
+      ${AndIf}  $0 != ""                   ;    and this is NOT the 1st string to be added to $0,
+        StrCpy $0 $0;$7                    ;    append path to $0 with a prepended semicolon
+      ${EndIf}                             ;
+ 
+      IntOp $8 $8 + 1                      ; Bump counter
+    ${Loop}                                ; Check for duplicates until we run out of paths
+  ${EndIf}
+ 
+  ; Step 4:  Perform the requested Action
+  ;
+  ${If} $2 != "R"                          ; If Append or Prepend
+    ${If} $6 == 1                          ; And if we found the target
+      DetailPrint "Target is already present in $1. It will be removed and"
+    ${EndIf}
+    ${If} $0 == ""                         ; If EnvVar is (now) empty
+      StrCpy $0 $4                         ;   just copy PathString to EnvVar
+      ${If} $6 == 0                        ; If found flag is either 0
+      ${OrIf} $6 == ""                     ; or blank (if EnvVarName is empty)
+        DetailPrint "$1 was empty and has been updated with the target"
+      ${EndIf}
+    ${ElseIf} $2 == "A"                    ;  If Append (and EnvVar is not empty),
+      StrCpy $0 $0;$4                      ;     append PathString
+      ${If} $6 == 1
+        DetailPrint "appended to $1"
+      ${Else}
+        DetailPrint "Target was appended to $1"
+      ${EndIf}
+    ${Else}                                ;  If Prepend (and EnvVar is not empty),
+      StrCpy $0 $4;$0                      ;     prepend PathString
+      ${If} $6 == 1
+        DetailPrint "prepended to $1"
+      ${Else}
+        DetailPrint "Target was prepended to $1"
+      ${EndIf}
+    ${EndIf}
+  ${Else}                                  ; If Action = Remove
+    ${If} $6 == 1                          ;   and we found the target
+      DetailPrint "Target was found and removed from $1"
+    ${Else}
+      DetailPrint "Target was NOT found in $1 (nothing to remove)"
+    ${EndIf}
+    ${If} $0 == ""
+      DetailPrint "$1 is now empty"
+    ${EndIf}
+  ${EndIf}
+ 
+  ; Step 5:  Update the registry at RegLoc with the updated EnvVar and announce the change
+  ;
+  ClearErrors
+  ${If} $3  == HKLM
+    WriteRegExpandStr ${hklm_all_users} $1 $0     ; Write it in all users section
+  ${ElseIf} $3 == HKCU
+    WriteRegExpandStr ${hkcu_current_user} $1 $0  ; Write it to current user section
+  ${EndIf}
+ 
+  IfErrors 0 +4
+    MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
+    DetailPrint "Could not write updated $1 to $3"
+    Goto EnvVarUpdate_Restore_Vars
+ 
+  ; "Export" our change
+  SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ 
+  EnvVarUpdate_Restore_Vars:
+  ;
+  ; Restore the user's variables and return ResultVar
+  Pop $R0
+  Pop $9
+  Pop $8
+  Pop $7
+  Pop $6
+  Pop $5
+  Pop $4
+  Pop $3
+  Pop $2
+  Pop $1
+  Push $0  ; Push my $0 (ResultVar)
+  Exch
+  Pop $0   ; Restore his $0
+ 
+FunctionEnd
+ 
+!macroend   ; EnvVarUpdate UN
+!insertmacro EnvVarUpdate ""
+!insertmacro EnvVarUpdate "un."
+;----------------------------------- EnvVarUpdate end----------------------------------------
+ 
+!verbose pop
+!endif
diff --git a/tools/niminst/buildbat.tmpl b/tools/niminst/buildbat.tmpl
new file mode 100644
index 000000000..3a11715bf
--- /dev/null
+++ b/tools/niminst/buildbat.tmpl
@@ -0,0 +1,41 @@
+#! stdtmpl(subsChar='?') | standard
+#proc generateBuildBatchScript(c: ConfigData, winIndex, cpuIndex: int): string = 
+#  result = "@echo off\nREM Generated by niminst\n"
+SET CC=gcc
+SET LINKER=gcc
+SET COMP_FLAGS=?{c.ccompiler.flags}
+SET LINK_FLAGS=?{c.linker.flags}
+SET BIN_DIR=?{firstBinPath(c).toWin}
+
+if EXIST ..\koch.nim SET BIN_DIR=..\bin
+
+if NOT EXIST %BIN_DIR%\nul mkdir %BIN_DIR%
+
+REM call the compiler:
+
+#  block win32:
+#    var linkCmd = ""
+#    for ff in items(c.cfiles[winIndex][cpuIndex]):
+#      let f = ff.toWin
+ECHO %CC% %COMP_FLAGS% -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")}
+%CC% %COMP_FLAGS% -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")}
+#      linkCmd.add(" " & changeFileExt(f, "o"))
+IF ERRORLEVEL 1 (GOTO:END)
+#    end for
+
+ECHO %LINKER% -o ?{"%BIN_DIR%"\toLower(c.name)}.exe ?linkCmd %LINK_FLAGS%
+%LINKER% -o ?{"%BIN_DIR%"\toLower(c.name)}.exe ?linkCmd %LINK_FLAGS%
+
+#  end block
+
+:END
+IF ERRORLEVEL 1 (
+    ECHO FAILURE
+    ECHO.
+    ECHO CSource compilation failed. Please check that the gcc compiler is in
+    ECHO the PATH environment variable, and that you are calling the batch script
+    ECHO that matches the target architecture of the compiler.
+) ELSE (
+    ECHO SUCCESS
+)
+exit /b %ERRORLEVEL%
diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl
new file mode 100644
index 000000000..52da351be
--- /dev/null
+++ b/tools/niminst/buildsh.tmpl
@@ -0,0 +1,158 @@
+#! stdtmpl(subsChar='?') | standard
+#proc generateBuildShellScript(c: ConfigData): string = 
+#  result = "#! /bin/sh\n# Generated from niminst\n" &
+#           "# Template is in tools/niminst/buildsh.tmpl\n" &
+#           "# To regenerate run ``niminst csource`` or ``koch csource``\n"
+
+set -e
+
+while :
+do
+  case "$1" in
+    --extraBuildArgs)
+      extraBuildArgs=" $2"
+      shift 2
+      ;;
+    --) # End of all options
+      shift
+      break;
+      ;;
+    -*)
+      echo "Error: Unknown option: $1" >&2
+      exit 1
+      ;;
+    *)  # No more options
+      break
+      ;;
+  esac
+done
+
+CC="gcc"
+LINKER="gcc"
+COMP_FLAGS="?{c.ccompiler.flags}$extraBuildArgs"
+LINK_FLAGS="?{c.linker.flags}"
+#  add(result, "# platform detection\n")
+ucpu=`uname -m`
+uos=`uname`
+#  add(result, "# bin dir detection\n")
+binDir=?{firstBinPath(c).toUnix}
+
+if [ -s ../koch.nim ]; then
+  binDir="../bin"
+fi
+
+if [ ! -d $binDir ]; then
+  mkdir $binDir
+fi
+
+#  add(result, "# convert to lower case:\n")
+ucpu=`echo $ucpu | tr "[:upper:]" "[:lower:]"`
+uos=`echo $uos | tr "[:upper:]" "[:lower:]"`
+
+case $uos in
+  *linux* ) 
+    myos="linux" 
+    LINK_FLAGS="$LINK_FLAGS -ldl -lm"
+    ;;
+  *dragonfly* )
+    myos="freebsd"
+    LINK_FLAGS="$LINK_FLAGS -lm"
+    ;;
+  *freebsd* )
+    myos="freebsd"
+    CC="clang"
+    LINKER="clang"
+    LINK_FLAGS="$LINK_FLAGS -lm"
+    ;;
+  *openbsd* )
+    myos="openbsd" 
+    LINK_FLAGS="$LINK_FLAGS -lm"
+    ;;
+  *netbsd* )
+    myos="netbsd"
+    LINK_FLAGS="$LINK_FLAGS -lm"
+    ;;
+  *darwin* ) 
+    myos="macosx"
+    CC="clang"
+    LINKER="clang"
+    LINK_FLAGS="$LINK_FLAGS -ldl -lm"
+    if [ "$HOSTTYPE" = "x86_64" ] ; then
+      ucpu="amd64"
+    fi
+    ;;
+  *aix* )
+    myos="aix"
+    LINK_FLAGS="$LINK_FLAGS -ldl -lm"    
+    ;;
+  *solaris* | *sun* ) 
+    myos="solaris"
+    LINK_FLAGS="$LINK_FLAGS -ldl -lm -lsocket -lnsl"
+    ;;
+  *haiku* )
+    myos="haiku"
+    ;;
+  *) 
+    echo "Error: unknown operating system: $uos"
+    exit 1
+    ;;
+esac
+
+case $ucpu in
+  *i386* | *i486* | *i586* | *i686* | *bepc* | *i86pc* ) 
+    mycpu="i386" ;;
+  *amd*64* | *x86-64* | *x86_64* ) 
+    mycpu="amd64" ;;
+  *sparc*|*sun* ) 
+    mycpu="sparc" ;;
+  *ppc64* ) 
+    if [ "$myos" = "linux" ] ; then
+      COMP_FLAGS="$COMP_FLAGS -m64"
+      LINK_FLAGS="$LINK_FLAGS -m64"
+    fi
+    mycpu="powerpc64" ;;
+  *power*|*ppc* ) 
+    mycpu="powerpc" ;;
+  *mips* ) 
+    mycpu="mips" ;;
+  *arm*|*armv6l* )
+    mycpu="arm" ;;
+  *) 
+    echo "Error: unknown processor: $ucpu"
+    exit 1
+    ;;
+esac
+
+#  add(result, "# call the compiler:\n")
+
+case $myos in
+#  for osA in 1..c.oses.len:
+?{c.oses[osA-1]}) 
+  case $mycpu in
+#    for cpuA in 1..c.cpus.len:
+  ?{c.cpus[cpuA-1]})
+#      var linkCmd = ""
+#      for ff in items(c.cfiles[osA][cpuA]):
+#        let f = ff.toUnix
+    echo "$CC $COMP_FLAGS -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")}"
+    $CC $COMP_FLAGS -Ic_code -c ?{f} -o ?{changeFileExt(f, "o")}
+#        add(linkCmd, " \\\n" & changeFileExt(f, "o"))
+#      end for
+    echo "$LINKER -o ?{"$binDir/" & toLower(c.name)} ?linkCmd $LINK_FLAGS"
+    $LINKER -o ?{"$binDir/" & toLower(c.name)} ?linkCmd $LINK_FLAGS
+    ;;
+#    end for
+  *)
+    echo "Error: no C code generated for: [$myos: $mycpu]"
+    exit 1
+    ;;
+  esac
+  ;;
+#  end for
+*) 
+  echo "Error: no C code generated for: [$myos: $mycpu]"
+  exit 1
+  ;;
+esac
+
+echo "SUCCESS"
diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim
new file mode 100644
index 000000000..bbd997981
--- /dev/null
+++ b/tools/niminst/debcreation.nim
@@ -0,0 +1,235 @@
+#
+#
+#        The Nim Installation Generator
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import osproc, times, os, strutils
+
+# http://www.debian.org/doc/manuals/maint-guide/
+
+# Required files for debhelper.
+# -- control
+# -- copyright
+# -- changelog
+# -- rules
+
+type
+  TDebOptions* = object
+    buildDepends*, pkgDepends*, shortDesc*: string
+    licenses*: seq[tuple[files, license: string]]
+
+template addN(r: string) =
+  result.add(r)
+  result.add("\n")
+
+proc createControl(pkgName, maintainer, shortDesc, desc: string,
+                   buildDepends, pkgDepends: string = ""): string =
+  ## pkgName: Should be the package name, no spaces.
+  ## maintainer: firstName lastName <email>
+  ## shortDesc: short description of the application
+  ## desc: long description of the application
+  ## buildDepends: what the build depends on (compiling from source),
+  ##               this needs to be in the format deb accepts. For example,
+  ##               for gcc: ``gcc (>= 4:4.3.2)``
+  ##               Multiple dependencies should be separated by commas.
+  ## pkgDepends: Same as buildDepends except that this specifies the
+  ##             dependencies that the compiled application depends on.
+  
+  
+  result = ""
+  
+  addN("Source: " & pkgName)
+  addN("Maintainer: " & maintainer)
+  addN("Section: misc")
+  addN("Priority: optional")
+  addN("Standards-Version: 3.9.2")
+  addN("Build-Depends: debhelper (>= 8)" & 
+        (if buildDepends != "": ", " & buildDepends else: ""))
+  addN("\n")
+  addN("Package: " & pkgName)
+  addN("Architecture: any")
+  addN("Depends: ${shlibs:Depends}, ${misc:Depends}" &
+        (if pkgDepends != "": ", " & pkgDepends else: ""))
+  
+  var formattedDesc = ""
+  for line in splitLines(desc):
+    if line == "":
+      formattedDesc.add(" .\n")
+    else:
+      formattedDesc.add(" " & line & "\n")
+  
+  addN("Description: " & shortDesc & "\n" & formattedDesc)
+
+proc createCopyright(pkgName, mtnName, mtnEmail, version: string, 
+                     licenses: seq[tuple[files, license: string]]): string =
+  ## pkgName: Package name
+  ## mtnName: Maintainer name
+  ## mtnEmail: Maintainer email
+  ## version: package version
+  ## licenses: files: This specifies the files that the `license` covers,
+  ##           for example, it might be ``lib/*`` to cover the whole ``lib`` dir
+  ##           license: This specifies the license, for example gpl2, or lgpl.
+  
+  result = ""
+  addN("Maintainer name: " & mtnName)
+  addN("Email-Address: " & mtnEmail)
+  addN("Date: " & $getTime())
+  addN("Package Name: " & pkgName)
+  addN("Version: " & version)
+  for f, license in items(licenses):
+    addN("Files: " & f)
+    addN("License: " & license)
+
+proc formatDateTime(t: TimeInfo, timezone: string): string =
+  var day = ($t.weekday)[0..2] & ", "
+  
+  return "$1$2 $3 $4 $5:$6:$7 $8" % [day, intToStr(t.monthday, 2),
+    ($t.month)[0..2], $t.year, intToStr(t.hour, 2), intToStr(t.minute, 2),
+    intToStr(t.second, 2), timezone]
+
+proc createChangelog(pkgName, version, maintainer: string): string =
+  ## pkgName: package name
+  ## version: package version
+  ## maintainer: firstName lastName <email>
+  result = ""
+  addN(pkgName & " (" & version & "-1) unstable; urgency=low")
+  addN("")
+  addN("  * Initial release.")
+  addN("")
+  addN(" -- " & maintainer & "  " &
+       formatDateTime(getGMTime(getTime()), "+0000"))
+
+proc createRules(): string =
+  ## Creates a nim application-agnostic rules file for building deb packages.
+  ## Please note: this assumes the c sources have been built and the
+  ## ``build.sh`` and ``install.sh`` files are available.
+  result = ""
+  addN("#!/usr/bin/make -f")
+  addN("%:")
+  addN("\tdh $@\n")
+  addN("dh_install:")
+  addN("\tdh_install --sourcedir=debian/tmp")
+  addN("override_dh_auto_clean:")
+  addN("\tfind . -name *.o -exec rm {} \\;")
+  addN("override_dh_auto_build:")
+  addN("\t./build.sh")
+  addN("override_dh_auto_install:")
+  addN("\t./install.sh debian/tmp")
+
+proc createIncludeBinaries(binaries: seq[string]): string =
+  return join(binaries, "\n")
+
+proc createDotInstall(pkgName: string, binaries, config, docs,
+    lib: seq[string]): string =
+  result = ""
+  for b in binaries:
+    addN(pkgName / b & " " & "usr/bin/")
+  for c in config:
+    addN(pkgName / c & " " & "etc/")
+  for d in docs:
+    addN(pkgName / d & " " & "usr/share/doc/nim/")
+  for l1 in lib:
+    addN(pkgName / l1 & " " & "usr/lib/nim")
+
+proc makeMtn(name, email: string): string =
+  return name & " <" & email & ">"
+
+proc assertSuccess(exitCode: int) =
+  doAssert(exitCode == QuitSuccess)
+
+proc prepDeb*(packName, version, mtnName, mtnEmail, shortDesc, desc: string,
+              licenses: seq[tuple[files, license: string]], binaries,
+              config, docs, lib: seq[string],
+              buildDepends, pkgDepends = "") =
+  ## binaries/config/docs/lib: files relative to nim's root, that need to
+  ##   be installed.
+  
+  let pkgName = packName.toLower()
+  
+  var workingDir = getTempDir() / "niminst" / "deb"
+  var upstreamSource = (pkgName & "-" & version)
+  
+  echo("Making sure build.sh and install.sh are +x")
+  assertSuccess execCmd("chmod +x \"" & 
+    (workingDir / upstreamSource / "build.sh") & "\"")
+  assertSuccess execCmd("chmod +x \"" & 
+    (workingDir / upstreamSource / "install.sh") & "\"")
+  
+  var tarCmd = "tar pczf \"" & 
+      (pkgName & "_" & version & ".orig.tar.gz") &
+      "\" \"" & upstreamSource & "\"" 
+  echo(tarCmd)
+  assertSuccess execCmd("cd \"" & workingDir & "\" && " & tarCmd)
+  
+  echo("Creating necessary files in debian/")
+  createDir(workingDir / upstreamSource / "debian")
+  
+  template writeDebian(f, s: string): expr =
+    writeFile(workingDir / upstreamSource / "debian" / f, s)
+  
+  var controlFile = createControl(pkgName, makeMtn(mtnName, mtnEmail),
+      shortDesc, desc, buildDepends, pkgDepends)
+  echo("debian/control")
+  writeDebian("control", controlFile)
+  
+  var copyrightFile = createCopyright(pkgName, mtnName, mtnEmail, version,
+      licenses)
+  echo("debian/copyright")
+  writeDebian("copyright", copyrightFile)
+
+  var changelogFile = createChangelog(pkgName, version, 
+      makeMtn(mtnName, mtnEmail))
+  echo("debian/changelog")
+  writeDebian("changelog", changelogFile)
+
+  echo("debian/rules")
+  writeDebian("rules", createRules())
+
+  echo("debian/compat")
+  writeDebian("compat", "8")
+
+  echo("debian/" & pkgName & ".install")
+  writeDebian(pkgName & ".install",
+    createDotInstall(pkgName, binaries, config, docs, lib))
+
+  # Other things..
+  createDir(workingDir / upstreamSource / "debian" / "source")
+  echo("debian/source/format")
+  writeDebian("source" / "format",
+            "3.0 (quilt)")
+  echo("debian/source/include-binaries")
+  writeFile(workingDir / upstreamSource / "debian" / "source" / "include-binaries",
+            createIncludeBinaries(binaries))
+
+  echo("All done, you can now build.")
+  echo("Before you do however, make sure the files in " & 
+    workingDir / upstreamSource / "debian" & " are correct.")
+  echo("Change your directory to: " & workingDir / upstreamSource)
+  echo("And execute `debuild -us -uc` to build the .deb")
+
+when isMainModule:
+  #var controlFile = createControl("nim", "Dominik Picheta <morfeusz8@gmail.com>",
+  # "The Nim compiler", "Compiler for the Nim programming language", "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")
+  
+  #echo(controlFile)
+  
+  #var copyrightFile = createCopyright("nim", "Dominik Picheta", "morfeusz8@a.b", "0.8.14",
+  #    @[("bin/nim", "gpl2"), ("lib/*", "lgpl")])
+      
+  #echo copyrightFile
+  
+  #var changelogFile = createChangelog("nim", "0.8.14", "Dom P <m@b.c>")
+  #echo(changelogFile)
+  
+  #echo(createRules())
+
+  prepDeb("nim", "0.9.2", "Dominik Picheta", "morfeusz8@gmail.com", 
+    "The Nim compiler", "Compiler for the Nim programming language",
+    @[("bin/nim", "MIT"), ("lib/*", "MIT")], 
+    @["bin/nim"], @["config/*"], @["doc/*"], @["lib/*"],
+    "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)")
+
diff --git a/tools/niminst/deinstall.tmpl b/tools/niminst/deinstall.tmpl
new file mode 100644
index 000000000..c4717a257
--- /dev/null
+++ b/tools/niminst/deinstall.tmpl
@@ -0,0 +1,64 @@
+#! stdtmpl(subsChar='?') | standard
+#proc generateDeinstallScript(c: ConfigData): string = 
+#  result = "#! /bin/sh\n# Generated by niminst\n"
+#  var proj = c.name.toLower
+
+if [ $# -eq 1 ] ; then
+  case $1 in
+    "--help"|"-h"|"help"|"h")
+      echo "?c.displayName deinstallation script"
+      echo "Usage: [sudo] sh deinstall.sh DIR"
+      echo "Where DIR may be:"
+      echo "  /usr/bin"
+      echo "  /usr/local/bin"
+      echo "  /opt"
+      echo "  <some other dir> (treated like '/opt')"
+      exit 1
+      ;;
+    "/usr/bin")
+      bindir=/usr/bin
+      configdir=/etc
+      libdir=/usr/lib/?proj
+      docdir=/usr/share/?proj/doc
+      datadir=/usr/share/?proj/data
+      ;;
+    "/usr/local/bin")
+      bindir=/usr/local/bin
+      configdir=/etc
+      libdir=/usr/local/lib/?proj
+      docdir=/usr/local/share/?proj/doc
+      datadir=/usr/local/share/?proj/data
+      ;;
+    *)
+      bindir="$1/?proj/bin"
+      configdir="$1/?proj/config"
+      libdir="$1/?proj/lib"
+      docdir="$1/?proj/doc"
+      datadir="$1/?proj/data"
+      ;;
+  esac
+  echo "removing files..."
+
+#for ff in items(c.cat[fcUnixBin]):
+  #let f = ff.toUnix
+  rm -f $bindir/?f.skipRoot
+#end for
+#for ff in items(c.cat[fcConfig]): 
+  #let f = ff.toUnix
+  rm -f $configdir/?f.skipRoot
+#end for
+  rm -rf $docdir
+  rm -rf $datadir
+  rm -rf $libdir
+
+  echo "deinstallation successful"
+else
+  echo "?c.displayName deinstallation script"
+  echo "Usage: [sudo] sh deinstall.sh DIR"
+  echo "Where DIR may be:"
+  echo "  /usr/bin"
+  echo "  /usr/local/bin"
+  echo "  /opt"
+  echo "  <some other dir> (treated like '/opt')"
+  exit 1
+fi
diff --git a/tools/niminst/inno.tmpl b/tools/niminst/inno.tmpl
new file mode 100644
index 000000000..4acf0557c
--- /dev/null
+++ b/tools/niminst/inno.tmpl
@@ -0,0 +1,182 @@
+#! stdtmpl | standard
+#proc generateInnoSetup(c: ConfigData): string =
+#  result = ""
+; Default Template for NimInst
+[Setup]
+AppName=$c.displayName
+AppVerName=$c.displayName $c.version
+DefaultDirName={code:GiveMeAPath|$c.displayName}
+DefaultGroupName=$c.displayName
+AllowNoIcons=yes
+LicenseFile=${expandFilename(c.license)}
+OutputBaseFilename=${c.name}_${c.version}
+Compression=lzma
+SolidCompression=yes
+PrivilegesRequired=none
+ChangesEnvironment=yes
+
+[Languages]
+Name: english; MessagesFile: compiler:Default.isl
+
+[Files] 
+  #for i in low(FileCategory)..fcWindows:
+  #  for f in items(c.cat[i]):
+Source: ${expandFilename(f).toWin}; DestDir: {app}\${splitFile(f).dir.toWin}; Flags: ignoreversion
+  #  end for
+  #end for
+
+[Icons]
+  #if c.app == appConsole:
+Name: {group}\Console for $c.displayName; Filename: {cmd}
+  #else:
+Name: {group}\$c.displayName; Filename: {app}\${c.name}.exe
+  #end if
+  #for f in items(c.cat[fcDocStart]):
+Name: {group}\Documentation; Filename: {app}\${f.toWin}
+  #end for
+Name: {group}\{cm:UninstallProgram,$c.displayName}; Filename: {uninstallexe}
+
+  #if c.binPaths.len > 0:
+[Tasks]
+Name: modifypath; Description: &Add $c.displayName to your system path (if not in path already);
+  #end if
+
+[Code]
+function GiveMeAPath(const DefaultPathName: string): string;
+begin
+  if IsAdminLoggedOn then result := ExpandConstant('{pf}')
+  else result := ExpandConstant('{userdocs}');
+  result := result + '\' + DefaultPathName;
+end;
+
+  #if c.binPaths.len > 0:
+// ----------------------------------------------------------------------------
+//
+// Inno Setup Ver:  5.2.1
+// Script Version:  1.3.1
+// Author:          Jared Breland <jbreland@legroom.net>
+// Homepage:    http://www.legroom.net/software
+//
+// Script Function:
+//  Enable modification of system path directly from Inno Setup installers
+
+function ModPathDir(): TArrayOfString;
+begin
+  setArrayLength(result, $c.binPaths.len);
+    #var i = 0
+    #for b in items(c.binPaths):
+  result[$i] := ExpandConstant('{app}') + '\${b.toWin}';
+      #inc(i)
+    #end for
+end;
+
+procedure ModPath();
+var
+  oldpath, newpath, aExecFile: String;
+  pathArr, aExecArr, pathdir: TArrayOfString;
+  i, d: Integer;
+begin
+  // Get array of new directories and act on each individually
+  pathdir := ModPathDir();
+  for d := 0 to GetArrayLength(pathdir)-1 do begin
+    // Modify WinNT path
+    if UsingWinNT() then begin
+      // Get current path, split into an array
+      RegQueryStringValue(HKEY_LOCAL_MACHINE,
+        'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
+        'Path', oldpath);
+      oldpath := oldpath + ';';
+      i := 0;
+      while (Pos(';', oldpath) > 0) do begin
+        SetArrayLength(pathArr, i+1);
+        pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
+        oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
+        i := i + 1;
+        // Check if current directory matches app dir
+        if pathdir[d] = pathArr[i-1] then begin
+          // if uninstalling, remove dir from path
+          if IsUninstaller() then continue
+          // if installing, abort because dir was already in path
+          else abort;
+        end;
+        // Add current directory to new path
+        if i = 1 then newpath := pathArr[i-1]
+        else newpath := newpath + ';' + pathArr[i-1];
+      end;
+      // Append app dir to path if not already included
+      if not IsUninstaller() then
+        newpath := newpath + ';' + pathdir[d];
+      // Write new path
+      RegWriteStringValue(HKEY_LOCAL_MACHINE,
+        'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
+        'Path', newpath);
+    end
+    else begin
+      // Modify Win9x path
+      // Convert to shortened dirname
+      pathdir[d] := GetShortName(pathdir[d]);
+      // If autoexec.bat exists, check if app dir already exists in path
+      aExecFile := 'C:\AUTOEXEC.BAT';
+      if FileExists(aExecFile) then begin
+        LoadStringsFromFile(aExecFile, aExecArr);
+        for i := 0 to GetArrayLength(aExecArr)-1 do begin
+          if not IsUninstaller() then begin
+            // If app dir already exists while installing, abort add
+            if (Pos(pathdir[d], aExecArr[i]) > 0) then
+              abort;
+          end
+          else begin
+            // If app dir exists and = what we originally set,
+            // then delete at uninstall
+            if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
+              aExecArr[i] := '';
+          end;
+        end;
+      end;
+      // If app dir not found, or autoexec.bat didn't exist, then
+      // (create and) append to current path
+      if not IsUninstaller() then begin
+        SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d],
+                         True);
+      end
+      else begin
+        // If uninstalling, write the full autoexec out
+        SaveStringsToFile(aExecFile, aExecArr, False);
+      end;
+    end;
+
+    // Write file to flag modifypath was selected
+    // Workaround since IsTaskSelected() cannot be called at uninstall and
+    // AppName and AppId cannot be "read" in Code section
+    if not IsUninstaller() then
+      SaveStringToFile(ExpandConstant('{app}') + '\uninsTasks.txt',
+                       WizardSelectedTasks(False), False);
+  end;
+end;
+
+procedure CurStepChanged(CurStep: TSetupStep);
+begin
+  if CurStep = ssPostInstall then begin
+    if IsTaskSelected('modifypath') then
+      ModPath();
+  end
+end;
+
+procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
+var
+  appdir, selectedTasks: String;
+begin
+  appdir := ExpandConstant('{app}');
+  if CurUninstallStep = usUninstall then begin
+    if LoadStringFromFile(appdir + '\uninsTasks.txt', selectedTasks) then
+      if Pos('modifypath', selectedTasks) > 0 then
+        ModPath();
+    DeleteFile(appdir + '\uninsTasks.txt')
+  end;
+end;
+
+function NeedRestart(): Boolean;
+begin
+  result := IsTaskSelected('modifypath') and not UsingWinNT()
+end;
+  #end if
diff --git a/tools/niminst/install.tmpl b/tools/niminst/install.tmpl
new file mode 100644
index 000000000..3ec42c287
--- /dev/null
+++ b/tools/niminst/install.tmpl
@@ -0,0 +1,111 @@
+#! stdtmpl(subsChar = '?') | standard
+#proc generateInstallScript(c: ConfigData): string = 
+#  result = "#! /bin/sh\n# Generated by niminst\n"
+#  var proj = c.name.toLower
+
+set -e
+
+if [ $# -eq 1 ] ; then
+# if c.cat[fcUnixBin].len > 0:
+  if test -f ?{c.cat[fcUnixBin][0].toUnix}
+  then 
+    echo "?c.displayName build detected"
+  else
+    echo "Please build ?c.displayName before installing it"
+    exit 1
+  fi
+#  end if
+  case $1 in
+    "--help"|"-h"|"help"|"h")
+      echo "?c.displayName installation script"
+      echo "Usage: [sudo] sh install.sh DIR"
+      echo "Where DIR may be:"
+      echo "  /usr/bin"
+      echo "  /usr/local/bin"
+      echo "  /opt"
+      echo "  <some other dir> (treated like '/opt')"
+      echo "To deinstall, use the command:"
+      echo "sh deinstall.sh DIR"
+      exit 1
+      ;;
+    "/usr/bin")
+      bindir=/usr/bin
+      configdir=/etc
+      libdir=/usr/lib/?proj
+      docdir=/usr/share/?proj/doc
+      datadir=/usr/share/?proj/data
+      ;;
+    "/usr/local/bin")
+      bindir=/usr/local/bin
+      configdir=/etc
+      libdir=/usr/local/lib/?proj
+      docdir=/usr/local/share/?proj/doc
+      datadir=/usr/local/share/?proj/data
+      ;;
+    *)
+      bindir="$1/?proj/bin"
+      configdir="$1/?proj/config"
+      libdir="$1/?proj/lib"
+      docdir="$1/?proj/doc"
+      datadir="$1/?proj/data"
+      
+      mkdir -p $1/?proj
+      mkdir -p $bindir
+      mkdir -p $configdir
+      ;;
+  esac
+  mkdir -p $libdir
+  mkdir -p $docdir
+  echo "copying files..."
+#var createdDirs = newStringTable()
+#for cat in fcConfig..fcLib:
+#  for f in items(c.cat[cat]):
+#    var mk = splitFile(f.skipRoot).dir
+#    if mk.len > 0:
+#      mk = unixDirVars[cat] & "/" & mk
+#      if not createdDirs.hasKey(mk):
+#        createdDirs[mk] = "true"
+  mkdir -p ?{mk.toUnix}
+#      end if
+#    end if
+#  end for
+#end for
+
+#for f in items(c.cat[fcUnixBin]):
+  cp ?f.toUnix $bindir/?f.skipRoot.toUnix
+  chmod 755 $bindir/?f.skipRoot.toUnix
+#end for
+#for f in items(c.cat[fcConfig]): 
+  cp ?f.toUnix $configdir/?f.skipRoot.toUnix
+  chmod 644 $configdir/?f.skipRoot.toUnix
+#end for
+#for f in items(c.cat[fcData]): 
+  if [ -f ?f.toUnix ]; then
+    cp ?f.toUnix $datadir/?f.skipRoot.toUnix
+    chmod 644 $datadir/?f.skipRoot.toUnix
+  fi
+#end for
+#for f in items(c.cat[fcDoc]):
+  if [ -f ?f.toUnix ]; then
+    cp ?f.toUnix $docdir/?f.skipRoot.toUnix
+    chmod 644 $docdir/?f.skipRoot.toUnix
+  fi
+#end for
+#for f in items(c.cat[fcLib]):
+  cp ?f.toUnix $libdir/?f.skipRoot.toUnix
+  chmod 644 $libdir/?f.skipRoot.toUnix
+#end for
+  
+  echo "installation successful"
+else
+  echo "?c.displayName installation script"
+  echo "Usage: [sudo] sh install.sh DIR"
+  echo "Where DIR may be:"
+  echo "  /usr/bin"
+  echo "  /usr/local/bin"
+  echo "  /opt"
+  echo "  <some other dir> (treated like '/opt')"
+  echo "To deinstall, use the command:"
+  echo "sh deinstall.sh DIR"
+  exit 1
+fi
diff --git a/tools/niminst/makefile.tmpl b/tools/niminst/makefile.tmpl
new file mode 100644
index 000000000..8ab3b89d1
--- /dev/null
+++ b/tools/niminst/makefile.tmpl
@@ -0,0 +1,168 @@
+#! stdtmpl(subsChar='?') | standard
+#proc generateMakefile(c: ConfigData): string = 
+#  result = "# Generated from niminst\n" &
+#           "# Template is in tools/niminst/makefile.tmpl\n" &
+#           "# To regenerate run ``niminst csource`` or ``koch csource``\n"
+
+CC = gcc
+LINKER = gcc
+COMP_FLAGS = ?{c.ccompiler.flags}
+LINK_FLAGS = ?{c.linker.flags}
+binDir = ?{firstBinPath(c).toUnix}
+
+koch := $(shell sh -c 'test -s ../koch.nim && echo "yes"')
+ifeq ($(koch),yes)
+	binDir = ../bin
+endif
+
+ucpu := $(shell sh -c 'uname -m | tr "[:upper:]" "[:lower:]"')
+uos := $(shell sh -c 'uname | tr "[:upper:]" "[:lower:]"')
+
+ifeq ($(uos),linux)
+	myos = linux
+	LINK_FLAGS += -ldl -lm
+endif
+ifeq ($(uos),dragonfly)
+	myos = freebsd
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),freebsd)
+	myos= freebsd
+	CC = clang
+	LINKER = clang
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),openbsd)
+	myos = openbsd
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),netbsd)
+	myos = netbsd
+	LINK_FLAGS += -lm
+endif
+ifeq ($(uos),darwin)
+	myos = macosx
+	CC = clang
+	LINKER = clang
+	LINK_FLAGS += -ldl -lm
+	ifeq ($HOSTTYPE,x86_64)
+		ucpu = amd64
+	endif
+endif
+ifeq ($(uos),aix)
+	myos = aix
+	LINK_FLAGS += -dl -lm
+endif
+ifeq ($(uos),solaris)
+	myos = solaris
+	LINK_FLAGS += -ldl -lm -lsocket -lnsl
+endif
+ifeq ($(uos),sun)
+	myos = solaris
+	LINK_FLAGS += -ldl -lm -lsocket -lnsl
+endif
+ifeq ($(uos),haiku)
+	myos = haiku
+endif
+ifndef uos
+	@echo "Error: unknown operating system: $(uos)"
+	@exit 1
+endif
+
+ifeq ($(ucpu),i386)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i486)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i586)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i686)
+	mycpu = i386
+endif
+ifeq ($(ucpu),bepc)
+	mycpu = i386
+endif
+ifeq ($(ucpu),i86pc)
+	mycpu = i386
+endif
+ifeq ($(ucpu),amd64)
+	mycpu = amd64
+endif
+ifeq ($(ucpu),x86-64)
+	mycpu = amd64
+endif
+ifeq ($(ucpu),x86_64)
+	mycpu = amd64
+endif
+ifeq ($(ucpu),sparc)
+	mycpu = sparc
+endif
+ifeq ($(ucpu),sun)
+	mycpu = sparc
+endif
+ifeq ($(ucpu),ppc64)
+	mycpu = powerpc64
+	ifeq ($(myos),linux)
+		COMP_FLAGS += -m64
+		LINK_FLAGS += -m64
+	endif
+endif
+ifeq ($(ucpu),powerpc)
+	mycpu = powerpc
+endif
+ifeq ($(ucpu),ppc)
+	mycpu = ppc
+endif
+ifeq ($(ucpu),mips)
+	mycpu = mips
+endif
+ifeq ($(ucpu),arm)
+	mycpu = arm
+endif
+ifeq ($(ucpu),armeb)
+	mycpu = arm
+endif
+ifeq ($(ucpu),armel)
+	mycpu = arm
+endif
+ifeq ($(ucpu),armv6l)
+	mycpu = arm
+endif
+ifndef ucpu
+	@echo "Error: unknown processor : $(ucpu)"
+	@exit 1
+endif
+
+# for osA in 1..c.oses.len:
+ifeq ($(myos),?{c.oses[osA-1]})
+#   for cpuA in 1..c.cpus.len:
+	ifeq ($(mycpu),?{c.cpus[cpuA-1]})
+#     var oFiles = ""
+#     for ff in c.cfiles[osA][cpuA].items:
+#       oFiles.add(" " & changeFileExt(ff.toUnix, "o"))
+#     end for
+		oFiles =?oFiles
+	endif
+#   end for
+endif
+# end for
+
+ifeq ($(strip $(oFiles)),)
+	@echo "Error: no C code generated for: [$(myos): $(mycpu)]"
+	@exit 1
+endif
+
+%.o: %.c
+	$(CC) $(COMP_FLAGS) -Ic_code -c $< -o $@
+
+?{"$(binDir)/" & toLower(c.name)}: $(oFiles)
+	@mkdir -p $(binDir)
+	$(LINKER) -o $@ $^ $(LINK_FLAGS)
+	@echo "SUCCESS"
+
+.PHONY: clean
+
+clean:
+	rm -f $(oFiles) ?{"$(binDir)/" & toLower(c.name)}
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
new file mode 100644
index 000000000..99befa92d
--- /dev/null
+++ b/tools/niminst/niminst.nim
@@ -0,0 +1,670 @@
+#
+#
+#        The Nim Installation Generator
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+const
+  haveZipLib = defined(unix)
+
+when haveZipLib:
+  import zipfiles
+
+import
+  os, osproc, strutils, parseopt, parsecfg, strtabs, streams, debcreation
+
+const
+  maxOS = 20 # max number of OSes
+  maxCPU = 10 # max number of CPUs
+  buildShFile = "build.sh"
+  buildBatFile32 = "build.bat"
+  buildBatFile64 = "build64.bat"
+  makeFile = "makefile"
+  installShFile = "install.sh"
+  deinstallShFile = "deinstall.sh"
+
+type
+  AppType = enum appConsole, appGUI
+  Action = enum
+    actionNone,   # action not yet known
+    actionCSource # action: create C sources
+    actionInno,   # action: create Inno Setup installer
+    actionNsis,   # action: create NSIS installer
+    actionScripts # action: create install and deinstall scripts
+    actionZip,    # action: create zip file
+    actionXz,     # action: create xz file
+    actionDeb     # action: prepare deb package
+
+  FileCategory = enum
+    fcWinBin,     # binaries for Windows
+    fcConfig,     # configuration files
+    fcData,       # data files
+    fcDoc,        # documentation files
+    fcLib,        # library files
+    fcOther,      # other files; will not be copied on UNIX
+    fcWindows,    # files only for Windows
+    fcUnix,       # files only for Unix; must be after ``fcWindows``
+    fcUnixBin,    # binaries for Unix
+    fcDocStart    # links to documentation for Windows installer
+
+  ConfigData = object of RootObj
+    actions: set[Action]
+    cat: array[FileCategory, seq[string]]
+    binPaths, authors, oses, cpus, downloads: seq[string]
+    cfiles: array[1..maxOS, array[1..maxCPU, seq[string]]]
+    platforms: array[1..maxOS, array[1..maxCPU, bool]]
+    ccompiler, linker, innosetup, nsisSetup: tuple[path, flags: string]
+    name, displayName, version, description, license, infile, outdir: string
+    mainfile, libpath: string
+    innoSetupFlag, installScript, uninstallScript: bool
+    explicitPlatforms: bool
+    vars: StringTableRef
+    app: AppType
+    nimArgs: string
+    debOpts: TDebOptions
+
+const
+  unixDirVars: array[fcConfig..fcLib, string] = [
+    "$configdir", "$datadir", "$docdir", "$libdir"
+  ]
+
+proc iniConfigData(c: var ConfigData) =
+  c.actions = {}
+  for i in low(FileCategory)..high(FileCategory): c.cat[i] = @[]
+  c.binPaths = @[]
+  c.authors = @[]
+  c.oses = @[]
+  c.cpus = @[]
+  c.downloads = @[]
+  c.ccompiler = ("", "")
+  c.linker = ("", "")
+  c.innosetup = ("", "")
+  c.nsisSetup = ("", "")
+  c.name = ""
+  c.displayName = ""
+  c.version = ""
+  c.description = ""
+  c.license = ""
+  c.infile = ""
+  c.mainfile = ""
+  c.outdir = ""
+  c.nimArgs = ""
+  c.libpath = ""
+  c.innoSetupFlag = false
+  c.installScript = false
+  c.uninstallScript = false
+  c.vars = newStringTable(modeStyleInsensitive)
+
+  c.debOpts.buildDepends = ""
+  c.debOpts.pkgDepends = ""
+  c.debOpts.shortDesc = ""
+  c.debOpts.licenses = @[]
+
+proc firstBinPath(c: ConfigData): string =
+  if c.binPaths.len > 0: result = c.binPaths[0]
+  else: result = ""
+
+proc `\`(a, b: string): string =
+  result = if a.len == 0: b else: a & '\\' & b
+
+template toUnix(s: string): string = s.replace('\\', '/')
+template toWin(s: string): string = s.replace('/', '\\')
+
+proc skipRoot(f: string): string =
+  # "abc/def/xyz" --> "def/xyz"
+  var i = 0
+  result = ""
+  for component in split(f, {DirSep, AltSep}):
+    if i > 0: result = result / component
+    inc i
+  if result.len == 0: result = f
+
+include "inno.tmpl"
+include "nsis.tmpl"
+include "buildsh.tmpl"
+include "makefile.tmpl"
+include "buildbat.tmpl"
+include "install.tmpl"
+include "deinstall.tmpl"
+
+# ------------------------- configuration file -------------------------------
+
+const
+  Version = "1.0"
+  Usage = "niminst - Nim Installation Generator Version " & Version & """
+
+  (c) 2015 Andreas Rumpf
+Usage:
+  niminst [options] command[;command2...] ini-file[.ini] [compile_options]
+Command:
+  csource             build C source code for source based installations
+  scripts             build install and deinstall scripts
+  zip                 build the ZIP file
+  inno                build the Inno Setup installer
+  nsis                build the NSIS Setup installer
+  deb                 create files for debhelper
+Options:
+  -o, --output:dir    set the output directory
+  -m, --main:file     set the main nim file, by default ini-file with .nim
+                      extension
+  --var:name=value    set the value of a variable
+  -h, --help          shows this help
+  -v, --version       shows the version
+Compile_options:
+  will be passed to the Nim compiler
+"""
+
+proc parseCmdLine(c: var ConfigData) =
+  var p = initOptParser()
+  while true:
+    next(p)
+    var kind = p.kind
+    var key = p.key
+    var val = p.val.string
+    case kind
+    of cmdArgument:
+      if c.actions == {}:
+        for a in split(normalize(key.string), {';', ','}):
+          case a
+          of "csource": incl(c.actions, actionCSource)
+          of "scripts": incl(c.actions, actionScripts)
+          of "zip": incl(c.actions, actionZip)
+          of "xz": incl(c.actions, actionXz)
+          of "inno": incl(c.actions, actionInno)
+          of "nsis": incl(c.actions, actionNsis)
+          of "deb": incl(c.actions, actionDeb)
+          else: quit(Usage)
+      else:
+        c.infile = addFileExt(key.string, "ini")
+        c.nimArgs = cmdLineRest(p).string
+        break
+    of cmdLongoption, cmdShortOption:
+      case normalize(key.string)
+      of "help", "h":
+        stdout.write(Usage)
+        quit(0)
+      of "version", "v":
+        stdout.write(Version & "\n")
+        quit(0)
+      of "o", "output": c.outdir = val
+      of "m", "main": c.mainfile = changeFileExt(val, "nim")
+      of "var":
+        var idx = val.find('=')
+        if idx < 0: quit("invalid command line")
+        c.vars[substr(val, 0, idx-1)] = substr(val, idx+1)
+      else: quit(Usage)
+    of cmdEnd: break
+  if c.infile.len == 0: quit(Usage)
+  if c.mainfile.len == 0: c.mainfile = changeFileExt(c.infile, "nim")
+
+proc walkDirRecursively(s: var seq[string], root: string) =
+  for k, f in walkDir(root):
+    case k
+    of pcFile, pcLinkToFile: add(s, unixToNativePath(f))
+    of pcDir: walkDirRecursively(s, f)
+    of pcLinkToDir: discard
+
+proc addFiles(s: var seq[string], patterns: seq[string]) =
+  for p in items(patterns):
+    if existsDir(p):
+      walkDirRecursively(s, p)
+    else:
+      var i = 0
+      for f in walkFiles(p):
+        add(s, unixToNativePath(f))
+        inc(i)
+      if i == 0: echo("[Warning] No file found that matches: " & p)
+
+proc pathFlags(p: var CfgParser, k, v: string,
+               t: var tuple[path, flags: string]) =
+  case normalize(k)
+  of "path": t.path = v
+  of "flags": t.flags = v
+  else: quit(errorStr(p, "unknown variable: " & k))
+
+proc filesOnly(p: var CfgParser, k, v: string, dest: var seq[string]) =
+  case normalize(k)
+  of "files": addFiles(dest, split(v, {';'}))
+  else: quit(errorStr(p, "unknown variable: " & k))
+
+proc yesno(p: var CfgParser, v: string): bool =
+  case normalize(v)
+  of "yes", "y", "on", "true":
+    result = true
+  of "no", "n", "off", "false":
+    result = false
+  else: quit(errorStr(p, "unknown value; use: yes|no"))
+
+proc incl(s: var seq[string], x: string): int =
+  for i in 0.. <s.len:
+    if cmpIgnoreStyle(s[i], x) == 0: return i
+  s.add(x)
+  result = s.len-1
+
+proc platforms(c: var ConfigData, v: string) =
+  for line in splitLines(v):
+    let p = line.find(": ")
+    if p <= 1: continue
+    let os = line.substr(0, p-1).strip
+    let cpus = line.substr(p+1).strip
+    c.oses.add(os)
+    for cpu in cpus.split(';'):
+      let cpuIdx = c.cpus.incl(cpu)
+      c.platforms[c.oses.len][cpuIdx+1] = true
+
+proc parseIniFile(c: var ConfigData) =
+  var
+    p: CfgParser
+    section = ""
+    hasCpuOs = false
+  var input = newFileStream(c.infile, fmRead)
+  if input != nil:
+    open(p, input, c.infile)
+    while true:
+      var k = next(p)
+      case k.kind
+      of cfgEof: break
+      of cfgSectionStart:
+        section = normalize(k.section)
+      of cfgKeyValuePair:
+        var v = k.value % c.vars
+        c.vars[k.key] = v
+
+        case section
+        of "project":
+          case normalize(k.key)
+          of "name": c.name = v
+          of "displayname": c.displayName = v
+          of "version": c.version = v
+          of "os":
+            c.oses = split(v, {';'})
+            hasCpuOs = true
+            if c.explicitPlatforms:
+              quit(errorStr(p, "you cannot have both 'platforms' and 'os'"))
+          of "cpu":
+            c.cpus = split(v, {';'})
+            hasCpuOs = true
+            if c.explicitPlatforms:
+              quit(errorStr(p, "you cannot have both 'platforms' and 'cpu'"))
+          of "platforms":
+            platforms(c, v)
+            c.explicitPlatforms = true
+            if hasCpuOs:
+              quit(errorStr(p, "you cannot have both 'platforms' and 'os'"))
+          of "authors": c.authors = split(v, {';'})
+          of "description": c.description = v
+          of "app":
+            case normalize(v)
+            of "console": c.app = appConsole
+            of "gui": c.app = appGUI
+            else: quit(errorStr(p, "expected: console or gui"))
+          of "license": c.license = unixToNativePath(k.value)
+          else: quit(errorStr(p, "unknown variable: " & k.key))
+        of "var": discard
+        of "winbin": filesOnly(p, k.key, v, c.cat[fcWinBin])
+        of "config": filesOnly(p, k.key, v, c.cat[fcConfig])
+        of "data": filesOnly(p, k.key, v, c.cat[fcData])
+        of "documentation":
+          case normalize(k.key)
+          of "files": addFiles(c.cat[fcDoc], split(v, {';'}))
+          of "start": addFiles(c.cat[fcDocStart], split(v, {';'}))
+          else: quit(errorStr(p, "unknown variable: " & k.key))
+        of "lib": filesOnly(p, k.key, v, c.cat[fcLib])
+        of "other": filesOnly(p, k.key, v, c.cat[fcOther])
+        of "windows":
+          case normalize(k.key)
+          of "files": addFiles(c.cat[fcWindows], split(v, {';'}))
+          of "binpath": c.binPaths = split(v, {';'})
+          of "innosetup": c.innoSetupFlag = yesno(p, v)
+          of "download": c.downloads.add(v)
+          else: quit(errorStr(p, "unknown variable: " & k.key))
+        of "unix":
+          case normalize(k.key)
+          of "files": addFiles(c.cat[fcUnix], split(v, {';'}))
+          of "installscript": c.installScript = yesno(p, v)
+          of "uninstallscript": c.uninstallScript = yesno(p, v)
+          else: quit(errorStr(p, "unknown variable: " & k.key))
+        of "unixbin": filesOnly(p, k.key, v, c.cat[fcUnixBin])
+        of "innosetup": pathFlags(p, k.key, v, c.innosetup)
+        of "nsis": pathFlags(p, k.key, v, c.nsisSetup)
+        of "ccompiler": pathFlags(p, k.key, v, c.ccompiler)
+        of "linker": pathFlags(p, k.key, v, c.linker)
+        of "deb":
+          case normalize(k.key)
+          of "builddepends":
+            c.debOpts.buildDepends = v
+          of "packagedepends", "pkgdepends":
+            c.debOpts.pkgDepends = v
+          of "shortdesc":
+            c.debOpts.shortDesc = v
+          of "licenses":
+            # file,license;file,license;
+            var i = 0
+            var file = ""
+            var license = ""
+            var afterComma = false
+            while i < v.len():
+              case v[i]
+              of ',':
+                afterComma = true
+              of ';':
+                if file == "" or license == "":
+                  quit(errorStr(p, "Invalid `licenses` key."))
+                c.debOpts.licenses.add((file, license))
+                afterComma = false
+                file = ""
+                license = ""
+              else:
+                if afterComma: license.add(v[i])
+                else: file.add(v[i])
+              inc(i)
+          else: quit(errorStr(p, "unknown variable: " & k.key))
+        else: quit(errorStr(p, "invalid section: " & section))
+
+      of cfgOption: quit(errorStr(p, "syntax error"))
+      of cfgError: quit(errorStr(p, k.msg))
+    close(p)
+    if c.name.len == 0: c.name = changeFileExt(extractFilename(c.mainfile), "")
+    if c.displayName.len == 0: c.displayName = c.name
+  else:
+    quit("cannot open: " & c.infile)
+
+# ------------------------- generate source based installation ---------------
+
+proc readCFiles(c: var ConfigData, osA, cpuA: int) =
+  var p: CfgParser
+  var f = splitFile(c.infile).dir / "mapping.txt"
+  c.cfiles[osA][cpuA] = @[]
+  var input = newFileStream(f, fmRead)
+  var section = ""
+  if input != nil:
+    open(p, input, f)
+    while true:
+      var k = next(p)
+      case k.kind
+      of cfgEof: break
+      of cfgSectionStart:
+        section = normalize(k.section)
+      of cfgKeyValuePair:
+        case section
+        of "ccompiler": pathFlags(p, k.key, k.value, c.ccompiler)
+        of "linker":
+          pathFlags(p, k.key, k.value, c.linker)
+          # HACK: we conditionally add ``-lm -ldl``, so remove them from the
+          # linker flags:
+          c.linker.flags = c.linker.flags.replaceWord("-lm").replaceWord(
+                           "-ldl").strip
+        else:
+          if cmpIgnoreStyle(k.key, "libpath") == 0:
+            c.libpath = k.value
+      of cfgOption:
+        if section == "cfiles" and cmpIgnoreStyle(k.key, "file") == 0:
+          add(c.cfiles[osA][cpuA], k.value)
+      of cfgError: quit(errorStr(p, k.msg))
+    close(p)
+  else:
+    quit("Cannot open: " & f)
+
+proc buildDir(os, cpu: int): string =
+  return "c_code" / ($os & "_" & $cpu)
+
+proc getOutputDir(c: var ConfigData): string =
+  if c.outdir.len > 0: c.outdir else: "build"
+
+proc writeFile(filename, content, newline: string) =
+  var f: File
+  if open(f, filename, fmWrite):
+    for x in splitLines(content):
+      write(f, x)
+      write(f, newline)
+    close(f)
+  else:
+    quit("Cannot open for writing: " & filename)
+
+proc removeDuplicateFiles(c: var ConfigData) =
+  for osA in countdown(c.oses.len, 1):
+    for cpuA in countdown(c.cpus.len, 1):
+      if c.cfiles[osA][cpuA].isNil: c.cfiles[osA][cpuA] = @[]
+      if c.explicitPlatforms and not c.platforms[osA][cpuA]: continue
+      for i in 0..c.cfiles[osA][cpuA].len-1:
+        var dup = c.cfiles[osA][cpuA][i]
+        var f = extractFilename(dup)
+        for osB in 1..c.oses.len:
+          for cpuB in 1..c.cpus.len:
+            if osB != osA or cpuB != cpuA:
+              var orig = buildDir(osB, cpuB) / f
+              if existsFile(orig) and existsFile(dup) and
+                  sameFileContent(orig, dup):
+                # file is identical, so delete duplicate:
+                removeFile(dup)
+                c.cfiles[osA][cpuA][i] = orig
+
+proc writeInstallScripts(c: var ConfigData) =
+  if c.installScript:
+    writeFile(installShFile, generateInstallScript(c), "\10")
+    inclFilePermissions(installShFile, {fpUserExec, fpGroupExec, fpOthersExec})
+  if c.uninstallScript:
+    writeFile(deinstallShFile, generateDeinstallScript(c), "\10")
+    inclFilePermissions(deinstallShFile, {fpUserExec, fpGroupExec, fpOthersExec})
+
+proc srcdist(c: var ConfigData) =
+  if not existsDir(getOutputDir(c) / "c_code"):
+    createDir(getOutputDir(c) / "c_code")
+  for x in walkFiles(c.libpath / "lib/*.h"):
+    echo(getOutputDir(c) / "c_code" / extractFilename(x))
+    copyFile(dest=getOutputDir(c) / "c_code" / extractFilename(x), source=x)
+  var winIndex = -1
+  var intel32Index = -1
+  var intel64Index = -1
+  for osA in 1..c.oses.len:
+    let osname = c.oses[osA-1]
+    if osname.cmpIgnoreStyle("windows") == 0: winIndex = osA
+    for cpuA in 1..c.cpus.len:
+      if c.explicitPlatforms and not c.platforms[osA][cpuA]: continue
+      let cpuname = c.cpus[cpuA-1]
+      if cpuname.cmpIgnoreStyle("i386") == 0: intel32Index = cpuA
+      elif cpuname.cmpIgnoreStyle("amd64") == 0: intel64Index = cpuA
+      var dir = getOutputDir(c) / buildDir(osA, cpuA)
+      if existsDir(dir): removeDir(dir)
+      createDir(dir)
+      var cmd = ("nim compile -f --symbolfiles:off --compileonly " &
+                 "--gen_mapping --cc:gcc --skipUserCfg" &
+                 " --os:$# --cpu:$# $# $#") %
+                 [osname, cpuname, c.nimArgs, c.mainfile]
+      echo(cmd)
+      if execShellCmd(cmd) != 0:
+        quit("Error: call to nim compiler failed")
+      readCFiles(c, osA, cpuA)
+      for i in 0 .. c.cfiles[osA][cpuA].len-1:
+        let dest = dir / extractFilename(c.cfiles[osA][cpuA][i])
+        let relDest = buildDir(osA, cpuA) / extractFilename(c.cfiles[osA][cpuA][i])
+        copyFile(dest=dest, source=c.cfiles[osA][cpuA][i])
+        c.cfiles[osA][cpuA][i] = relDest
+  # second pass: remove duplicate files
+  removeDuplicateFiles(c)
+  writeFile(getOutputDir(c) / buildShFile, generateBuildShellScript(c), "\10")
+  inclFilePermissions(getOutputDir(c) / buildShFile, {fpUserExec, fpGroupExec, fpOthersExec})
+  writeFile(getOutputDir(c) / makeFile, generateMakefile(c), "\10")
+  if winIndex >= 0:
+    if intel32Index >= 0:
+      writeFile(getOutputDir(c) / buildBatFile32,
+                generateBuildBatchScript(c, winIndex, intel32Index), "\13\10")
+    if intel64Index >= 0:
+      writeFile(getOutputDir(c) / buildBatFile64,
+                generateBuildBatchScript(c, winIndex, intel64Index), "\13\10")
+  writeInstallScripts(c)
+
+# --------------------- generate inno setup -----------------------------------
+proc setupDist(c: var ConfigData) =
+  let scrpt = generateInnoSetup(c)
+  let n = "build" / "install_$#_$#.iss" % [toLower(c.name), c.version]
+  writeFile(n, scrpt, "\13\10")
+  when defined(windows):
+    if c.innosetup.path.len == 0:
+      c.innosetup.path = "iscc.exe"
+    let outcmd = if c.outdir.len == 0: "build" else: c.outdir
+    let cmd = "$# $# /O$# $#" % [quoteShell(c.innosetup.path),
+                                 c.innosetup.flags, outcmd, n]
+    echo(cmd)
+    if execShellCmd(cmd) == 0:
+      removeFile(n)
+    else:
+      quit("External program failed")
+
+# --------------------- generate NSIS setup -----------------------------------
+proc setupDist2(c: var ConfigData) =
+  let scrpt = generateNsisSetup(c)
+  let n = "build" / "install_$#_$#.nsi" % [toLower(c.name), c.version]
+  writeFile(n, scrpt, "\13\10")
+  when defined(windows):
+    if c.nsisSetup.path.len == 0:
+      c.nsisSetup.path = "makensis.exe"
+    let outcmd = if c.outdir.len == 0: "build" else: c.outdir
+    let cmd = "$# $# /O$# $#" % [quoteShell(c.nsisSetup.path),
+                                 c.nsisSetup.flags, outcmd, n]
+    echo(cmd)
+    if execShellCmd(cmd) == 0:
+      removeFile(n)
+    else:
+      quit("External program failed")
+
+# ------------------ generate ZIP file ---------------------------------------
+when haveZipLib:
+  proc zipDist(c: var ConfigData) =
+    var proj = toLower(c.name) & "-" & c.version
+    var n = "$#.zip" % proj
+    if c.outdir.len == 0: n = "build" / n
+    else: n = c.outdir / n
+    var z: TZipArchive
+    if open(z, n, fmWrite):
+      addFile(z, proj / buildBatFile32, "build" / buildBatFile32)
+      addFile(z, proj / buildBatFile64, "build" / buildBatFile64)
+      addFile(z, proj / buildShFile, "build" / buildShFile)
+      addFile(z, proj / makeFile, "build" / makeFile)
+      addFile(z, proj / installShFile, installShFile)
+      addFile(z, proj / deinstallShFile, deinstallShFile)
+      for f in walkFiles(c.libpath / "lib/*.h"):
+        addFile(z, proj / "c_code" / extractFilename(f), f)
+      for osA in 1..c.oses.len:
+        for cpuA in 1..c.cpus.len:
+          var dir = buildDir(osA, cpuA)
+          for k, f in walkDir("build" / dir):
+            if k == pcFile: addFile(z, proj / dir / extractFilename(f), f)
+
+      for cat in items({fcConfig..fcOther, fcUnix}):
+        for f in items(c.cat[cat]): addFile(z, proj / f, f)
+      close(z)
+    else:
+      quit("Cannot open for writing: " & n)
+
+proc xzDist(c: var ConfigData) =
+  let proj = toLower(c.name) & "-" & c.version
+  var n = "$#.tar.xz" % proj
+  let tmpDir = if c.outdir.len == 0: "build" else: c.outdir
+
+  template processFile(z, dest, src) =
+    let s = src
+    let d = dest
+    echo "Copying ", s, " to ", tmpDir / d
+    let destdir = tmpdir / d.splitFile.dir
+    if not dirExists(destdir): createDir(destdir)
+    copyFileWithPermissions(s, tmpDir / d)
+
+  processFile(z, proj / buildBatFile32, "build" / buildBatFile32)
+  processFile(z, proj / buildBatFile64, "build" / buildBatFile64)
+  processFile(z, proj / buildShFile, "build" / buildShFile)
+  processFile(z, proj / makeFile, "build" / makeFile)
+  processFile(z, proj / installShFile, installShFile)
+  processFile(z, proj / deinstallShFile, deinstallShFile)
+  for f in walkFiles(c.libpath / "lib/*.h"):
+    processFile(z, proj / "c_code" / extractFilename(f), f)
+  for osA in 1..c.oses.len:
+    for cpuA in 1..c.cpus.len:
+      var dir = buildDir(osA, cpuA)
+      for k, f in walkDir("build" / dir):
+        if k == pcFile: processFile(z, proj / dir / extractFilename(f), f)
+
+  for cat in items({fcConfig..fcOther, fcUnix}):
+    for f in items(c.cat[cat]): processFile(z, proj / f, f)
+
+  let oldDir = getCurrentDir()
+  setCurrentDir(tmpDir)
+  try:
+    if execShellCmd("XZ_OPT=-9 tar Jcf $1.tar.xz $1" % proj) != 0:
+      echo("External program failed")
+  finally:
+    setCurrentDir(oldDir)
+
+# -- prepare build files for .deb creation
+
+proc debDist(c: var ConfigData) =
+  if not existsFile(getOutputDir(c) / "build.sh"): quit("No build.sh found.")
+  if not existsFile(getOutputDir(c) / "install.sh"): quit("No install.sh found.")
+
+  if c.debOpts.shortDesc == "": quit("shortDesc must be set in the .ini file.")
+  if c.debOpts.licenses.len == 0:
+    echo("[Warning] No licenses specified for .deb creation.")
+
+  # -- Copy files into /tmp/..
+  echo("Copying source to tmp/niminst/deb/")
+  var currentSource = getCurrentDir()
+  var workingDir = getTempDir() / "niminst" / "deb"
+  var upstreamSource = (c.name.toLower() & "-" & c.version)
+
+  createDir(workingDir / upstreamSource)
+
+  template copyNimDist(f, dest: string): stmt =
+    createDir((workingDir / upstreamSource / dest).splitFile.dir)
+    copyFile(currentSource / f, workingDir / upstreamSource / dest)
+
+  # Don't copy all files, only the ones specified in the config:
+  copyNimDist(buildShFile, buildShFile)
+  copyNimDist(makeFile, makeFile)
+  copyNimDist(installShFile, installShFile)
+  createDir(workingDir / upstreamSource / "build")
+  for f in walkFiles(c.libpath / "lib/*.h"):
+    copyNimDist(f, "build" / extractFilename(f))
+  for osA in 1..c.oses.len:
+    for cpuA in 1..c.cpus.len:
+      var dir = buildDir(osA, cpuA)
+      for k, f in walkDir(dir):
+        if k == pcFile: copyNimDist(f, dir / extractFilename(f))
+  for cat in items({fcConfig..fcOther, fcUnix}):
+    for f in items(c.cat[cat]): copyNimDist(f, f)
+
+  # -- Create necessary build files for debhelper.
+
+  let mtnName = c.vars["mtnname"]
+  let mtnEmail = c.vars["mtnemail"]
+
+  prepDeb(c.name, c.version, mtnName, mtnEmail, c.debOpts.shortDesc,
+          c.description, c.debOpts.licenses, c.cat[fcUnixBin], c.cat[fcConfig],
+          c.cat[fcDoc], c.cat[fcLib], c.debOpts.buildDepends,
+          c.debOpts.pkgDepends)
+
+# ------------------- main ----------------------------------------------------
+
+var c: ConfigData
+iniConfigData(c)
+parseCmdLine(c)
+parseIniFile(c)
+if actionInno in c.actions:
+  setupDist(c)
+if actionNsis in c.actions:
+  setupDist2(c)
+if actionCSource in c.actions:
+  srcdist(c)
+if actionScripts in c.actions:
+  writeInstallScripts(c)
+if actionZip in c.actions:
+  when haveZipLib:
+    zipDist(c)
+  else:
+    quit("libzip is not installed")
+if actionXz in c.actions:
+  xzDist(c)
+if actionDeb in c.actions:
+  debDist(c)
diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl
new file mode 100644
index 000000000..843a8cf44
--- /dev/null
+++ b/tools/niminst/nsis.tmpl
@@ -0,0 +1,258 @@
+#! stdtmpl(subsChar='?') | standard
+#proc generateNsisSetup(c: ConfigData): string =
+#  result = "; NSIS script generated by niminst\n" &
+#           "; To regenerate run ``niminst nsis`` or ``koch nsis``\n"
+
+;--------------------------------
+; Included headers
+  ; Modern User Interface 2.0 Header
+  !include "MUI2.nsh"
+
+  ; File Functions Header, used to get the current drive root.
+  !include "FileFunc.nsh"
+
+  ; *Patched* Environment Variable Manipulation Header, used to add
+  ; tools to the user's PATH environment variable.
+  !include "EnvVarUpdate.nsh"
+
+;--------------------------------
+; Global variables and defines
+  !define PRODUCT_NAME "?c.displayName"
+  !define PRODUCT_VERSION "?c.version"
+  !define PRODUCT_PUBLISHER "?c.authors"
+  !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\?{c.name}.exe"
+  !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+  !define PRODUCT_UNINST_ROOT_KEY "HKCU"
+  !define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"
+
+
+;--------------------------------
+; General Setup Information
+
+  ; Name and output file
+  Name "?{c.name} ?{c.version}"
+  OutFile "?{c.name}_?{c.version}.exe"
+
+  ; Default installation folder
+  ; This is changed later (in .onInit) to the root directory, if possible.
+  InstallDir "$LOCALAPPDATA\?{c.name}-?{c.version}"
+
+  ; Get installation folder from registry if available
+  InstallDirRegKey HKCU "Software\c.name\c.version" ""
+
+  ; Request user level application privileges.
+  RequestExecutionLevel user
+
+  ; Allow installation to the root drive directory.
+  AllowRootDirInstall true
+
+  ; Maximum compression!
+  SetCompressor /SOLID /FINAL lzma
+
+  ; Installer and Uninstaller Icons
+  ; Icon "nim.ico"
+  ; UninstallIcon "nim.ico"
+
+  ; Set installation details to be shown by default
+  ShowInstDetails show
+  ShowUnInstDetails show
+
+;--------------------------------
+; Interface Settings
+
+  ; Warn the user if aborting during installation/uninstallation
+  !define MUI_ABORTWARNING
+  !define MUI_UNABORTWARNING
+
+  ; Don't show a description for sections
+  !define MUI_COMPONENTSPAGE_NODESC
+
+;--------------------------------
+; Pages
+
+  ; Setup the installer pages
+  !insertmacro MUI_PAGE_WELCOME
+  !insertmacro MUI_PAGE_LICENSE "?{expandFilename(c.license)}"
+  !insertmacro MUI_PAGE_COMPONENTS
+  !insertmacro MUI_PAGE_DIRECTORY
+
+  ; Setup the start menu entry page
+  var ICONS_GROUP
+  !define MUI_STARTMENUPAGE_DEFAULTFOLDER "?{c.displayName}"
+  !define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
+  !define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
+  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
+  !insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP
+
+  !insertmacro MUI_PAGE_INSTFILES
+  !insertmacro MUI_PAGE_FINISH
+
+  ; Setup the uninstaller pages
+  !insertmacro MUI_UNPAGE_CONFIRM
+  !insertmacro MUI_UNPAGE_INSTFILES
+
+;--------------------------------
+;Languages
+
+  !insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+;Installer Sections
+
+  ; The core section. This is comprised of a base Nim installation,
+  ; such as what would be retrieved via git, and an already bootstrapped
+  ; Nim binary.
+  Section "Core Files" CoreSection
+    ; This is a mandotory section
+    SectionIn RO
+
+    ; Output files to the base installation directory
+    SetOutPath "$INSTDIR"
+
+    ; Only overwrite newer files
+    SetOverwrite ifnewer
+
+    ; Write all the files to the output directory.
+    #for i in low(FileCategory)..fcWindows:
+    #  for f in items(c.cat[i]):
+         SetOutPath "$INSTDIR\?{splitFile(f).dir.toWin}"
+         File "?{expandFilename(f).toWin}"
+    #  end for
+    #end for
+
+    ; Write out the uninstaller
+    WriteUninstaller "$INSTDIR\uninstaller.exe"
+  SectionEnd
+
+  Section "-Add Registry Keys" RegistrySection
+    ; Write application registry keys
+    WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\bin\?{c.name}.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninstaller.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\bin\?{c.name}.exe"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
+    WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
+    ; Reset the output path
+    SetOutPath "$INSTDIR"
+  SectionEnd
+
+  ; Section for adding the shortcuts related to files and applications
+  Section "-Setup Shortcuts" ShortcutsSection
+    !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+      CreateDirectory "$SMPROGRAMS\$ICONS_GROUP"
+
+      #if c.app == appConsole:
+        CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\start.bat"
+        CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\start.bat"
+      #else:
+        CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe"
+        CreateShortCut "$DESKTOP\?{c.displayName}.lnk" "$INSTDIR\?{c.name}.exe"
+      #end if
+
+      ; Write the shortcut to the uninstaller
+      CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninstaller.exe"
+    !insertmacro MUI_STARTMENU_WRITE_END
+  SectionEnd
+
+  ; Section for adding tools to the PATH variable
+  Section "Setup Path Environment" PathSection
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\dist\mingw"
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\dist\mingw\bin"
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\bin"
+     ${EnvVarUpdate} $R0 "PATH" "A" "HKCU" "$INSTDIR\dist\babel"
+  SectionEnd
+
+  ; The downloadable sections. These sections are automatically generated by
+  ; niminst and the template filters.
+  #var i = 0
+  #for download in c.downloads:
+  #  inc i
+  #  let d = download.split('|')
+  #  if d.len != 5 and d.len != 6:
+  #    quit("download string needs 5..6 parts: " & download)
+  #  end if
+  #  let sectionName = d[0]
+  #  let dir = d[1]
+  #  let zipName = d[2]
+  #  let size = d[3]
+  #  let url = d[4]
+  Section /o "?sectionName" ?{i}Section
+    ; Add the section size to the total size.
+    AddSize ?size
+
+    ; Download the file, and if successful, extract it to the given directory
+    ; otherwise,
+    retry:
+    NSISdl::download "?url" "$TEMP\?zipName"
+    Pop $0
+    ${If} $0 == "success"
+      ZipDLL::extractall "$TEMP\?zipName" "$INSTDIR\?dir"
+      Delete "$TEMP\?zipName"
+    ${ElseIf} $0 == "cancel"
+      MessageBox MB_ICONQUESTION|MB_YESNO|MB_TOPMOST \
+                 "Download of component '?sectionName' cancelled. Continue installation process??" \
+                 IDYES ignore
+      abort
+    ${Else}
+      MessageBox MB_ICONSTOP|MB_ABORTRETRYIGNORE|MB_TOPMOST "Error: $0" \
+                 IDRETRY retry IDIGNORE ignore
+      abort
+    ${EndIf}
+
+    ; Shortcuts
+    #  if d.len >= 6:
+    #    let startMenuEntry = d[5]
+    #    let e = splitFile(startMenuEntry).name.capitalize
+      !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
+        CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\?{e}.lnk" "$INSTDIR\?dir\?{startMenuEntry.toWin}"
+      !insertmacro MUI_STARTMENU_WRITE_END
+    #  end if
+
+    ignore:
+  SectionEnd
+  #end
+
+;--------------------------------
+; Section Descriptions
+  ; Series of strings describing each section
+  ; LangString DESC_CoreSection ${LANG_ENGLISH} "Core Nim files"
+
+  ; The macros to actually insert the descriptions into the sections.
+  ; Each description above should have a corresponding MUI_DESCRIPTION_TEXT
+  ; macro linking the section to the description.
+  ; !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+  ;   !insertmacro MUI_DESCRIPTION_TEXT ${CoreSection} $(DESC_CoreSection)
+  ; !insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+
+;--------------------------------
+; Uninstaller Sections
+
+  Section "Uninstall"
+    ; Remove previously created shortcuts
+    !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
+    Delete "$DESKTOP\?{c.displayName}.lnk"
+
+    ; Remove installed application files
+    RMDir /r "$SMPROGRAMS\$ICONS_GROUP"
+    RMDir /r "$INSTDIR"
+
+    ; Remove the previously created registry key
+    DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
+    DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}"
+    SetAutoClose true
+
+    ; Remove entries from the PATH environment variable
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\dist\mingw"
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\dist\mingw\bin"
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\bin"
+    ${un.EnvVarUpdate} $R0 "PATH" "R" "HKCU" "$INSTDIR\dist\babel"
+  SectionEnd
+
+;--------------------------------
+; Function hooks
+
+  Function .onInit
+    ${GetRoot} "$EXEDIR" $R0
+    strCpy $INSTDIR "$R0\?{c.name}"
+  FunctionEnd
diff --git a/tools/nimrepl.nim b/tools/nimrepl.nim
new file mode 100644
index 000000000..3d818a556
--- /dev/null
+++ b/tools/nimrepl.nim
@@ -0,0 +1,172 @@
+#
+#
+#              Nim REPL
+#        (c) Copyright 2012 Dominik Picheta
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import glib2, gtk2, gdk2, os, osproc, dialogs, strutils
+
+when defined(tinyc):
+  const runCmd = "run"
+else:
+  const runCmd = "c -r"
+
+var nimExe = findExe("nim")
+if nimExe.len == 0: nimExe = "../bin" / addFileExt("nim", os.exeExt)
+
+proc execCode(code: string): string =
+  var f: TFile
+  if open(f, "temp.nim", fmWrite):
+    f.write(code)
+    f.close()
+    result = osproc.execProcess(
+      "$# $# --verbosity:0 --hint[Conf]:off temp.nim" % [nimExe, runCmd],
+      options = {poStdErrToStdOut})
+  else:
+    result = "cannot open file 'temp.nim'"
+
+var shiftPressed = False
+var w: gtk2.PWindow
+var InputTextBuffer: PTextBuffer
+var OutputTextBuffer: PTextBuffer
+
+proc destroy(widget: PWidget, data: pgpointer){.cdecl.} = 
+  main_quit()
+
+proc fileOpenClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} =
+  var path = ChooseFileToOpen(w)
+  if path != "":
+    var file = readFile(path)
+    if file != nil:
+      set_text(InputTextBuffer, file, len(file).gint)
+    else:
+      error(w, "Unable to read from file")
+
+proc fileSaveClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} =
+  var path = ChooseFileToSave(w)
+  
+  if path == "": return
+  var startIter: TTextIter
+  var endIter: TTextIter
+  get_start_iter(InputTextBuffer, addr(startIter))
+  get_end_iter(InputTextBuffer, addr(endIter))
+  var InputText = get_text(InputTextBuffer, addr(startIter), 
+                           addr(endIter), False)
+  var f: TFile
+  if open(f, path, fmWrite):
+    f.write(InputText)
+    f.close()
+  else:
+    error(w, "Unable to write to file")
+
+proc inputKeyPressed(widget: PWidget, event: PEventKey, 
+                     userdata: pgpointer): bool {.cdecl.} =
+  if ($keyval_name(event.keyval)).tolower() == "shift_l":
+    # SHIFT is pressed
+    shiftPressed = True
+  
+proc setError(msg: string) = 
+  outputTextBuffer.setText(msg, msg.len.gint)
+  
+proc inputKeyReleased(widget: PWidget, event: PEventKey, 
+                      userdata: pgpointer): bool {.cdecl.} =
+  #echo(keyval_name(event.keyval))
+  if ($keyval_name(event.keyval)).tolower() == "shift_l":
+    # SHIFT is released
+    shiftPressed = False
+    
+  if ($keyval_name(event.keyval)).tolower() == "return":
+    #echo($keyval_name(event.keyval), "Shift_L")
+    # Enter pressed
+    if shiftPressed == False:
+      var startIter: TTextIter
+      var endIter: TTextIter
+      get_start_iter(InputTextBuffer, addr(startIter))
+      get_end_iter(InputTextBuffer, addr(endIter))
+      var InputText = get_text(InputTextBuffer, addr(startIter), 
+                               addr(endIter), False)
+
+      try:
+        var r = execCode($InputText)
+        set_text(OutputTextBuffer, r, len(r).gint)
+      except EIO:
+        setError("Error: Could not open file temp.nim")
+
+
+proc initControls() =
+  w = window_new(gtk2.WINDOW_TOPLEVEL)
+  set_default_size(w, 500, 600)
+  set_title(w, "Nimrod REPL")
+  discard signal_connect(w, "destroy", SIGNAL_FUNC(nimrepl.destroy), nil)
+  
+  # MainBox (vbox)
+  var MainBox = vbox_new(False, 0)
+  add(w, MainBox)
+  
+  # TopMenu (MenuBar)
+  var TopMenu = menu_bar_new()
+  show(TopMenu)
+  
+  var FileMenu = menu_new()
+  var OpenMenuItem = menu_item_new("Open")
+  append(FileMenu, OpenMenuItem)
+  show(OpenMenuItem)
+  discard signal_connect(OpenMenuItem, "activate", 
+                          SIGNAL_FUNC(fileOpenClicked), nil)
+  var SaveMenuItem = menu_item_new("Save...")
+  append(FileMenu, SaveMenuItem)
+  show(SaveMenuItem)
+  discard signal_connect(SaveMenuItem, "activate", 
+                          SIGNAL_FUNC(fileSaveClicked), nil)
+  var FileMenuItem = menu_item_new("File")
+
+  
+  set_submenu(FileMenuItem, FileMenu)
+  show(FileMenuItem)
+  append(TopMenu, FileMenuItem)
+  
+  pack_start(MainBox, TopMenu, False, False, 0)
+
+  # VPaned - Separates the InputTextView and the OutputTextView
+  var paned = vpaned_new()
+  set_position(paned, 450)
+  pack_start(MainBox, paned, True, True, 0)
+  show(paned)
+
+  # Init the TextBuffers
+  InputTextBuffer = text_buffer_new(nil)
+  OutputTextBuffer = text_buffer_new(nil)
+
+  # InputTextView (TextView)
+  var InputScrolledWindow = scrolled_window_new(nil, nil)
+  set_policy(InputScrolledWindow, POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+  var InputTextView = text_view_new(InputTextBuffer)
+  add_with_viewport(InputScrolledWindow, InputTextView)
+  add1(paned, InputScrolledWindow)
+  show(InputScrolledWindow)
+  show(InputTextView)
+  
+  discard signal_connect(InputTextView, "key-release-event", 
+                          SIGNAL_FUNC(inputKeyReleased), nil)
+  discard signal_connect(InputTextView, "key-press-event", 
+                          SIGNAL_FUNC(inputKeyPressed), nil)
+  
+  # OutputTextView (TextView)
+  var OutputScrolledWindow = scrolled_window_new(nil, nil)
+  set_policy(OutputScrolledWindow, POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+  var OutputTextView = text_view_new(OutputTextBuffer)
+  add_with_viewport(OutputScrolledWindow, OutputTextView)
+  add2(paned, OutputScrolledWindow)
+  show(OutputScrolledWindow)
+  show(OutputTextView)
+  
+  show(w)
+  show(MainBox)
+  
+nimrod_init()
+initControls()
+main()
+
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
new file mode 100644
index 000000000..a7301195e
--- /dev/null
+++ b/tools/nimweb.nim
@@ -0,0 +1,458 @@
+#
+#
+#           Nim Website Generator
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+import
+  os, strutils, times, parseopt, parsecfg, streams, strtabs, tables,
+  re, htmlgen, macros, md5, osproc
+
+type
+  TKeyValPair = tuple[key, id, val: string]
+  TConfigData = object of RootObj
+    tabs, links: seq[TKeyValPair]
+    doc, srcdoc, srcdoc2, webdoc, pdf: seq[string]
+    authors, projectName, projectTitle, logo, infile, outdir, ticker: string
+    vars: StringTableRef
+    nimArgs: string
+    gitRepo: string
+    gitCommit: string
+    quotations: Table[string, tuple[quote, author: string]]
+    numProcessors: int # Set by parallelBuild:n, only works for values > 0.
+    gaId: string  # google analytics ID, nil means analytics are disabled
+  TRssItem = object
+    year, month, day, title: string
+  TAction = enum
+    actAll, actOnlyWebsite, actPdf
+
+var action: TAction
+
+proc initConfigData(c: var TConfigData) =
+  c.tabs = @[]
+  c.links = @[]
+  c.doc = @[]
+  c.srcdoc = @[]
+  c.srcdoc2 = @[]
+  c.webdoc = @[]
+  c.pdf = @[]
+  c.infile = ""
+  c.outdir = ""
+  c.nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off "
+  c.authors = ""
+  c.projectTitle = ""
+  c.projectName = ""
+  c.logo = ""
+  c.ticker = ""
+  c.vars = newStringTable(modeStyleInsensitive)
+  c.gitRepo = "https://github.com/Araq/Nim/tree"
+  c.gitCommit = "master"
+  c.numProcessors = countProcessors()
+  # Attempts to obtain the git current commit.
+  when false:
+    let (output, code) = execCmdEx("git log -n 1 --format=%H")
+    if code == 0 and output.strip.len == 40:
+      c.gitCommit = output.strip
+  c.quotations = initTable[string, tuple[quote, author: string]]()
+
+include "website.tmpl"
+
+# ------------------------- configuration file -------------------------------
+
+const
+  version = "0.7"
+  usage = "nimweb - Nim Website Generator Version " & version & """
+
+  (c) 2015 Andreas Rumpf
+Usage:
+  nimweb [options] ini-file[.ini] [compile_options]
+Options:
+  -o, --output:dir    set the output directory (default: same as ini-file)
+  --var:name=value    set the value of a variable
+  -h, --help          shows this help
+  -v, --version       shows the version
+  --website           only build the website, not the full documentation
+  --pdf               build the PDF version of the documentation
+Compile_options:
+  will be passed to the Nim compiler
+"""
+
+  rYearMonthDayTitle = r"(\d{4})-(\d{2})-(\d{2})\s+(.*)"
+  rssUrl = "http://nim-lang.org/news.xml"
+  rssNewsUrl = "http://nim-lang.org/news.html"
+  validAnchorCharacters = Letters + Digits
+
+
+macro id(e: expr): expr {.immediate.} =
+  ## generates the rss xml ``id`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "id")
+
+macro updated(e: expr): expr {.immediate.} =
+  ## generates the rss xml ``updated`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "updated")
+
+proc updatedDate(year, month, day: string): string =
+  ## wrapper around the update macro with easy input.
+  result = updated("$1-$2-$3T00:00:00Z" % [year,
+    repeat("0", 2 - len(month)) & month,
+    repeat("0", 2 - len(day)) & day])
+
+macro entry(e: expr): expr {.immediate.} =
+  ## generates the rss xml ``entry`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "entry")
+
+macro content(e: expr): expr {.immediate.} =
+  ## generates the rss xml ``content`` element.
+  let e = callsite()
+  result = xmlCheckedTag(e, "content", reqAttr = "type")
+
+proc parseCmdLine(c: var TConfigData) =
+  var p = initOptParser()
+  while true:
+    next(p)
+    var kind = p.kind
+    var key = p.key
+    var val = p.val
+    case kind
+    of cmdArgument:
+      c.infile = addFileExt(key, "ini")
+      c.nimArgs.add(cmdLineRest(p))
+      break
+    of cmdLongOption, cmdShortOption:
+      case normalize(key)
+      of "help", "h": 
+        stdout.write(usage)
+        quit(0)
+      of "version", "v": 
+        stdout.write(version & "\n")
+        quit(0)
+      of "o", "output": c.outdir = val
+      of "parallelbuild":
+        try:
+          let num = parseInt(val)
+          if num != 0: c.numProcessors = num
+        except ValueError:
+          quit("invalid numeric value for --parallelBuild")
+      of "var":
+        var idx = val.find('=')
+        if idx < 0: quit("invalid command line")
+        c.vars[substr(val, 0, idx-1)] = substr(val, idx+1)
+      of "website": action = actOnlyWebsite
+      of "pdf": action = actPdf
+      of "googleanalytics":
+        c.gaId = val
+        c.nimArgs.add("--doc.googleAnalytics:" & val & " ")
+      else:
+        echo("Invalid argument $1" % [key])
+        quit(usage)
+    of cmdEnd: break
+  if c.infile.len == 0: quit(usage)
+
+proc walkDirRecursively(s: var seq[string], root, ext: string) =
+  for k, f in walkDir(root):
+    case k
+    of pcFile, pcLinkToFile:
+      if cmpIgnoreCase(ext, splitFile(f).ext) == 0:
+        add(s, f)
+    of pcDir: walkDirRecursively(s, f, ext)
+    of pcLinkToDir: discard
+
+proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) =
+  for p in items(patterns):
+    if existsDir(dir / p):
+      walkDirRecursively(s, dir / p, ext)
+    else:
+      add(s, dir / addFileExt(p, ext))
+
+proc parseIniFile(c: var TConfigData) =
+  var
+    p: CfgParser
+    section: string # current section
+  var input = newFileStream(c.infile, fmRead)
+  if input == nil: quit("cannot open: " & c.infile)
+  open(p, input, c.infile)
+  while true:
+    var k = next(p)
+    case k.kind
+    of cfgEof: break
+    of cfgSectionStart:
+      section = normalize(k.section)
+      case section
+      of "project", "links", "tabs", "ticker", "documentation", "var": discard
+      else: echo("[Warning] Skipping unknown section: " & section)
+
+    of cfgKeyValuePair:
+      var v = k.value % c.vars
+      c.vars[k.key] = v
+
+      case section
+      of "project":
+        case normalize(k.key)
+        of "name": c.projectName = v
+        of "title": c.projectTitle = v
+        of "logo": c.logo = v
+        of "authors": c.authors = v
+        else: quit(errorStr(p, "unknown variable: " & k.key))
+      of "var": discard
+      of "links":
+        let valID = v.split(';')
+        add(c.links, (k.key.replace('_', ' '), valID[1], valID[0]))
+      of "tabs": add(c.tabs, (k.key, "", v))
+      of "ticker": c.ticker = v
+      of "documentation":
+        case normalize(k.key)
+        of "doc": addFiles(c.doc, "doc", ".txt", split(v, {';'}))
+        of "pdf": addFiles(c.pdf, "doc", ".txt", split(v, {';'}))
+        of "srcdoc": addFiles(c.srcdoc, "lib", ".nim", split(v, {';'}))
+        of "srcdoc2": addFiles(c.srcdoc2, "lib", ".nim", split(v, {';'}))
+        of "webdoc": addFiles(c.webdoc, "lib", ".nim", split(v, {';'}))
+        of "parallelbuild":
+          try:
+            let num = parseInt(v)
+            if num != 0: c.numProcessors = num
+          except ValueError:
+            quit("invalid numeric value for --parallelBuild in config")
+        else: quit(errorStr(p, "unknown variable: " & k.key))
+      of "quotations":
+        let vSplit = v.split('-')
+        doAssert vSplit.len == 2
+        c.quotations[k.key.normalize] = (vSplit[0], vSplit[1])
+      else: discard
+    of cfgOption: quit(errorStr(p, "syntax error"))
+    of cfgError: quit(errorStr(p, k.msg))
+  close(p)
+  if c.projectName.len == 0:
+    c.projectName = changeFileExt(extractFilename(c.infile), "")
+  if c.outdir.len == 0:
+    c.outdir = splitFile(c.infile).dir
+  # Ugly hack to override git command output when building private repo.
+  if c.vars.hasKey("githash"):
+    let githash = c.vars["githash"].strip
+    if githash.len > 0:
+      c.gitCommit = githash
+
+# ------------------- main ----------------------------------------------------
+
+proc exec(cmd: string) =
+  echo(cmd)
+  if os.execShellCmd(cmd) != 0: quit("external program failed")
+
+proc sexec(cmds: openarray[string]) =
+  ## Serial queue wrapper around exec.
+  for cmd in cmds: exec(cmd)
+
+proc mexec(cmds: openarray[string], processors: int) =
+  ## Multiprocessor version of exec
+  if processors < 2:
+    sexec(cmds)
+    return
+  if execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}) != 0:
+    echo "external program failed, retrying serial work queue for logs!"
+    sexec(cmds)
+
+proc buildDocSamples(c: var TConfigData, destPath: string) =
+  ## Special case documentation sample proc.
+  ##
+  ## The docgen sample needs to be generated twice with different commands, so
+  ## it didn't make much sense to integrate into the existing generic
+  ## documentation builders.
+  const src = "doc"/"docgen_sample.nim"
+  exec("nim doc $# -o:$# $#" %
+    [c.nimArgs, destPath / "docgen_sample.html", src])
+  exec("nim doc2 $# -o:$# $#" %
+    [c.nimArgs, destPath / "docgen_sample2.html", src])
+
+proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/')
+
+proc buildDoc(c: var TConfigData, destPath: string) =
+  # call nim for the documentation:
+  var
+    commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2))
+    i = 0
+  for d in items(c.doc):
+    commands[i] = "nim rst2html $# --docSeeSrcUrl:$#/$#/$# -o:$# --index:on $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, d.pathPart,
+      destPath / changeFileExt(splitFile(d).name, "html"), d]
+    i.inc
+  for d in items(c.srcdoc):
+    commands[i] = "nim doc $# --docSeeSrcUrl:$#/$#/$# -o:$# --index:on $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, d.pathPart,
+      destPath / changeFileExt(splitFile(d).name, "html"), d]
+    i.inc
+  for d in items(c.srcdoc2):
+    commands[i] = "nim doc2 $# --docSeeSrcUrl:$#/$#/$# -o:$# --index:on $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, d.pathPart,
+      destPath / changeFileExt(splitFile(d).name, "html"), d]
+    i.inc
+
+  mexec(commands, c.numProcessors)
+  exec("nim buildIndex -o:$1/theindex.html $1" % [destPath])
+
+proc buildPdfDoc(c: var TConfigData, destPath: string) =
+  if os.execShellCmd("pdflatex -version") != 0:
+    echo "pdflatex not found; no PDF documentation generated"
+  else:
+    for d in items(c.pdf):
+      exec("nim rst2tex $# $#" % [c.nimArgs, d])
+      # call LaTeX twice to get cross references right:
+      exec("pdflatex " & changeFileExt(d, "tex"))
+      exec("pdflatex " & changeFileExt(d, "tex"))
+      # delete all the crappy temporary files:
+      let pdf = splitFile(d).name & ".pdf"
+      let dest = destPath / pdf
+      removeFile(dest)
+      moveFile(dest=dest, source=pdf)
+      removeFile(changeFileExt(pdf, "aux"))
+      if existsFile(changeFileExt(pdf, "toc")):
+        removeFile(changeFileExt(pdf, "toc"))
+      removeFile(changeFileExt(pdf, "log"))
+      removeFile(changeFileExt(pdf, "out"))
+      removeFile(changeFileExt(d, "tex"))
+
+proc buildAddDoc(c: var TConfigData, destPath: string) =
+  # build additional documentation (without the index):
+  var commands = newSeq[string](c.webdoc.len)
+  for i, doc in pairs(c.webdoc):
+    commands[i] = "nim doc2 $# --docSeeSrcUrl:$#/$#/$# -o:$# $#" %
+      [c.nimArgs, c.gitRepo, c.gitCommit, doc.pathPart,
+      destPath / changeFileExt(splitFile(doc).name, "html"), doc]
+  mexec(commands, c.numProcessors)
+
+proc parseNewsTitles(inputFilename: string): seq[TRssItem] =
+  # parses the file for titles and returns them as TRssItem blocks.
+  let reYearMonthDayTitle = re(rYearMonthDayTitle)
+  var
+    input: File
+    line = ""
+
+  result = @[]
+  if not open(input, inputFilename):
+    quit("Could not read $1 for rss generation" % [inputFilename])
+  finally: input.close()
+  while input.readLine(line):
+    if line =~ reYearMonthDayTitle:
+      result.add(TRssItem(year: matches[0], month: matches[1], day: matches[2],
+        title: matches[3]))
+
+proc genUUID(text: string): string =
+  # Returns a valid RSS uuid, which is basically md5 with dashes and a prefix.
+  result = getMD5(text)
+  result.insert("-", 20)
+  result.insert("-", 16)
+  result.insert("-", 12)
+  result.insert("-", 8)
+  result.insert("urn:uuid:")
+
+proc genNewsLink(title: string): string =
+  # Mangles a title string into an expected news.html anchor.
+  result = title
+  result.insert("Z")
+  for i in 1..len(result)-1:
+    let letter = result[i].toLower()
+    if letter in validAnchorCharacters:
+      result[i] = letter
+    else:
+      result[i] = '-'
+  result.insert(rssNewsUrl & "#")
+
+proc generateRss(outputFilename: string, news: seq[TRssItem]) =
+  # Given a list of rss items generates an rss overwriting destination.
+  var
+    output: File
+
+  if not open(output, outputFilename, mode = fmWrite):
+    quit("Could not write to $1 for rss generation" % [outputFilename])
+  finally: output.close()
+
+  output.write("""<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+""")
+  output.write(title("Nim website news"))
+  output.write(link(href = rssUrl, rel = "self"))
+  output.write(link(href = rssNewsUrl))
+  output.write(id(rssNewsUrl))
+
+  let now = getGMTime(getTime())
+  output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday))
+
+  for rss in news:
+    let joinedTitle = "$1-$2-$3 $4" % [rss.year, rss.month, rss.day, rss.title]
+    output.write(entry(
+        title(joinedTitle),
+        id(genUUID(joinedTitle)),
+        link(`type` = "text/html", rel = "alternate",
+          href = genNewsLink(joinedTitle)),
+        updatedDate(rss.year, rss.month, rss.day),
+        "<author><name>Nim</name></author>",
+        content(joinedTitle, `type` = "text"),
+      ))
+
+  output.write("""</feed>""")
+
+proc buildNewsRss(c: var TConfigData, destPath: string) =
+  # generates an xml feed from the web/news.txt file
+  let
+    srcFilename = "web" / "news.txt"
+    destFilename = destPath / changeFileExt(splitFile(srcFilename).name, "xml")
+
+  generateRss(destFilename, parseNewsTitles(srcFilename))
+
+proc buildJS(destPath: string) =
+  exec("nim js -d:release --out:$1 web/nimblepkglist.nim" %
+      [destPath / "nimblepkglist.js"])
+
+proc buildWebsite(c: var TConfigData) =
+  const
+    cmd = "nim rst2html --compileonly $1 -o:web/$2.temp web/$2.txt"
+  if c.ticker.len > 0:
+    try:
+      c.ticker = readFile("web" / c.ticker)
+    except IOError:
+      quit("[Error] cannot open: " & c.ticker)
+  for i in 0..c.tabs.len-1:
+    var file = c.tabs[i].val
+    let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: ""
+    if '.' in file: continue
+    exec(cmd % [c.nimArgs, file])
+    var temp = "web" / changeFileExt(file, "temp")
+    var content: string
+    try:
+      content = readFile(temp)
+    except IOError:
+      quit("[Error] cannot open: " & temp)
+    var f: File
+    var outfile = "web/upload/$#.html" % file
+    if not existsDir("web/upload"):
+      createDir("web/upload")
+    if open(f, outfile, fmWrite):
+      writeln(f, generateHTMLPage(c, file, content, rss))
+      close(f)
+    else:
+      quit("[Error] cannot write file: " & outfile)
+    removeFile(temp)
+  copyDir("web/assets", "web/upload/assets")
+  buildNewsRss(c, "web/upload")
+
+proc main(c: var TConfigData) =
+  buildWebsite(c)
+  buildJS("web/upload")
+  buildAddDoc(c, "web/upload")
+  buildDocSamples(c, "web/upload")
+  buildDoc(c, "web/upload")
+  buildDocSamples(c, "doc")
+  buildDoc(c, "doc")
+
+var c: TConfigData
+initConfigData(c)
+parseCmdLine(c)
+parseIniFile(c)
+case action
+of actOnlyWebsite: buildWebsite(c)
+of actPdf: buildPdfDoc(c, "doc")
+of actAll: main(c)
diff --git a/tools/noprefix.nim b/tools/noprefix.nim
new file mode 100644
index 000000000..fe03a9efc
--- /dev/null
+++ b/tools/noprefix.nim
@@ -0,0 +1,32 @@
+# strip those silly GTK/ATK prefixes...
+
+import
+  expandimportc, os
+
+const
+  filelist = [
+    ("sdl/sdl", "sdl"),
+    ("sdl/sdl_net", "sdl"),
+    ("sdl/sdl_gfx", "sdl"),
+    ("sdl/sdl_image", "sdl"),
+    ("sdl/sdl_mixer_nosmpeg", "sdl"),
+    ("sdl/sdl_mixer", "sdl"),
+    ("sdl/sdl_ttf", "sdl"),
+    ("sdl/smpeg", "sdl"),
+    
+    ("libcurl", "curl"),
+    ("mysql", "mysql"),
+    ("postgres", ""),
+    ("sqlite3", "sqlite3"),
+    
+    ("pcre/pcre", "pcre")
+  ]
+
+proc createDirs =
+  createDir("lib/newwrap/sdl")
+  createDir("lib/newwrap/pcre")
+
+for filename, prefix in items(filelist):
+  var f = addFileExt(filename, "nim")
+  main("lib/wrappers" / f, "lib/newwrap" / f, prefix)
+
diff --git a/tools/restorecc.nim b/tools/restorecc.nim
new file mode 100644
index 000000000..f5d8f0bb3
--- /dev/null
+++ b/tools/restorecc.nim
@@ -0,0 +1,16 @@
+
+import os, strutils
+
+proc main(dir: string, wanted: string) =

+  for kind, path in walkDir(dir):

+    case kind

+    of pcFile:
+      let name = extractFilename(path)
+      if name == wanted:
+        let newLoc = path.replace("mingw_backup", "mingw")
+        echo "creating ", newLoc
+        copyFile(path, newLoc)

+    of pcDir: main(path, wanted)

+    else: discard

+
+main("dist/mingw_backup", paramStr(1))
diff --git a/tools/trimcc.nim b/tools/trimcc.nim
new file mode 100644
index 000000000..276ea1dbe
--- /dev/null
+++ b/tools/trimcc.nim
@@ -0,0 +1,174 @@
+# Trim C compiler installation to a minimum
+
+import strutils, os, pegs, strtabs, math, threadpool, times
+
+const
+  Essential = """gcc.exe g++.exe gdb.exe ld.exe as.exe c++.exe cpp.exe cc1.exe
+crtbegin.o crtend.o crt2.o dllcrt2.o libgcc_s_dw2-1.dll libgcc_s_sjlj-1.dll
+libgcc_s_seh-1.dll libexpat-1.dll libwinpthread-1.dll aio.h dlfcn.h fcntl.h
+fenv.h fmtmsg.h fnmatch.h ftw.h errno.h glob.h gtmath.h if.h in.h ipc.h
+langinfo.h locale.h math.h mman.h netdb.h nl_types.h poll.h pthread.h pwd.h
+sched.h select.h semaphore.h signal.h socket.h spawn.h stat.h statvfs.h stdio.h
+stdlib.h string.h strings.h tcp.h time.h types.h ucontext.h uio.h utsname.h
+unistd.h wait.h varargs.h windows.h zlib.h
+""".split
+
+proc includes(headerpath, headerfile: string, whitelist: StringTableRef) =
+  whitelist[headerfile] = "processed"
+  for line in lines(headerpath):
+    if line =~ peg"""s <- ws '#include' ws ('"' / '<') {[^">]+} ('"' / '>') ws
+                     comment <- '/*' @ '*/' / '//' .*
+                     ws <- (comment / \s+)* """:
+      let m = matches[0].extractFilename
+      if whitelist[m] != "processed":
+        whitelist[m] = "found"
+
+proc processIncludes(dir: string, whitelist: StringTableRef) =
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile:
+      let name = extractFilename(path)
+      if ('.' notin name and "include" in path) or ("c++" in path):
+        let n = whitelist[name]
+        if n != "processed": whitelist[name] = "found"
+      if name.endswith(".h"):
+        let n = whitelist[name]
+        if n == "found": includes(path, name, whitelist)
+    of pcDir: processIncludes(path, whitelist)
+    else: discard
+
+proc gatherFiles(dir: string, whitelist: StringTableRef, result: var seq[string]) =
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile:
+      let name = extractFilename(path)
+      if not whitelist.hasKey(name):
+        result.add(path)
+    of pcDir:
+      gatherFiles(path, whitelist, result)
+    else:
+      discard
+
+proc gatherEmptyFolders(dir: string, whitelist: StringTableRef, result: var seq[string]) =
+  var empty = true
+  for kind, path in walkDir(dir):
+    case kind
+    of pcFile:
+      empty = false
+    of pcDir:
+      let (none, name) = splitPath(path)
+      if not whitelist.hasKey(name):
+        gatherEmptyFolders(path, whitelist, result)
+      empty = false
+    else:
+      discard
+  if empty:
+    result.add(dir)
+
+proc newName(f: string): string =
+  let (dir, name, ext) = splitFile(f)
+  return dir / "trim_" & name & ext
+
+proc ccStillWorks(): bool =
+  const
+    c1 = r"nim c --verbosity:0 --force_build koch"
+    c2 = r"nim c --verbosity:0 --force_build --threads:on --out:tempOne.exe trimcc"
+    c3 = r"nim c --verbosity:0 --force_build --threads:on --out:tempTwo.exe fakeDeps"
+    c4 = r".\koch.exe"
+    c5 = r".\tempOne.exe"
+    c6 = r".\tempTwo.exe"
+  result = execShellCmd(c1) == 0 and execShellCmd(c2) == 0 and
+           execShellCmd(c3) == 0 and execShellCmd(c4) == 0 and
+           execShellCmd(c5) == 0 and execShellCmd(c6) == 0
+
+proc trialDeletion(files: seq[string], a, b: int, whitelist: StringTableRef): bool =
+  result = true
+  var single = (a == min(b, files.high))
+  for path in files[a .. min(b, files.high)]:
+    try:
+      moveFile(dest=newName(path), source=path)
+    except OSError:
+      return false
+
+  # Test if compilation still works, even with the moved files.
+  if ccStillWorks():
+    for path in files[a .. min(b, files.high)]:
+      try:
+        removeFile(newName(path))
+        echo "Optional: ", path
+      except OSError:
+        echo "Warning, couldn't move ", path
+        moveFile(dest=path, source=newName(path))
+        return false
+  else:
+    for path in files[a .. min(b, files.high)]:
+      echo "Required: ", path
+      moveFile(dest=path, source=newName(path))
+      if single:
+        whitelist[path] = "found"
+      result = false
+
+proc main(dir: string) =
+  # Construct a whitelist of files to not remove
+  var whitelist = newStringTable(modeCaseInsensitive)
+  for e in Essential:
+    whitelist[e] = "found"
+  while true:
+    let oldLen = whitelist.len
+    processIncludes(dir, whitelist)
+    if oldLen == whitelist.len:
+      break
+
+  # Remove batches of files
+  var nearlyDone = false
+  while true:
+    # Gather files to test
+    var allFiles = newSeq[string]()
+    gatherFiles(dir, whitelist, allFiles)
+
+    # Determine the initial size of groups to check
+    var
+      maxBucketSize = len(allFiles)
+      bucketSize = 1
+
+    # Loop through the list of files, deleting batches
+    var i = 0
+    while i < allFiles.len:
+      var success = trialDeletion(allFiles, i, i+bucketSize-1, whitelist)
+      inc i, bucketSize
+
+      # If we aren't on the last pass, adjust the batch size based on success
+      if not nearlyDone:
+        if success:
+          bucketSize = min(bucketSize * 2, maxBucketSize)
+        else:
+          bucketSize = max(bucketSize div 2, 1)
+      echo "Bucket size is now ", bucketSize
+
+    # After looping through all the files, check if we need to break.
+    if nearlyDone:
+      break
+    if bucketSize == 1:
+      nearlyDone = true
+
+  while true:
+    var
+      emptyFolders = newSeq[string]()
+      changed = false
+
+    gatherEmptyFolders(dir, whitelist, emptyFolders)
+    for path in emptyFolders:
+      removeDir(path)
+      if not ccStillWorks():
+        createDir(path)
+        whitelist[path] = "found"
+      else:
+        changed = true
+    if not changed:
+      break
+
+if paramCount() == 1:
+  doAssert ccStillWorks()
+  main(paramStr(1))
+else:
+  quit "Usage: trimcc c_compiler_directory", QuitSuccess
diff --git a/tools/website.tmpl b/tools/website.tmpl
new file mode 100644
index 000000000..bc3ed8e2c
--- /dev/null
+++ b/tools/website.tmpl
@@ -0,0 +1,210 @@
+#! stdtmpl | standard
+#proc generateHTMLPage(c: var TConfigData, currentTab, content, rss: string): string = 
+#  result = ""
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    <title>$c.projectTitle</title>
+    <link rel="stylesheet" type="text/css" href="assets/style.css" />
+    <link rel="shortcut icon" href="assets/images/favicon.ico">
+  #if len(rss) > 0:
+    <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate">
+  #end if
+  </head>
+  <body>
+    <header id="head">
+      <div class="page-layout tall">
+        <div id="head-logo"></div>
+        <a id="head-logo-link" href="index.html"></a>
+        <nav id="head-links">
+      #for i in 0.. c.tabs.len-1:
+      # let t = c.tabs[i].val
+      # if t != "index" and t != "community" and t != "news":
+      #   let name = c.tabs[i].key
+      #   if currentTab == t:
+            <a class="active" 
+      #   else:
+            <a
+      #   end if
+      #   if t.contains('.'):
+            href="${t}" title = "$c.projectName - $name">$name</a>
+      #   else:
+            href="${t}.html" title = "$c.projectName - $name">$name</a>
+      #   end if
+      # end if
+      #end for
+        </nav>
+      </div>
+    </header>
+
+#  if currentTab == "index":
+    <section id="neck" class="home">
+#  else:
+    <section id="neck">
+#  end
+      <div class="page-layout tall">
+        <div id="glow-arrow"></div>
+
+#  if currentTab == "index":
+        <div id="slideshow">
+          <!-- slides -->
+          <div id="slide0" class="active">
+            <h2><a name="why-should-i-be-excited">Why should I be excited?</a></h2>
+            <span class="desc">Nim is the only language that leverages automated proof technology to perform a <i>disjoint check</i> for your parallel code. Working on disjoint data means no locking is required and yet data races are impossible:</span><br><br>
+<pre>
+<span class="kwd">parallel</span>:
+<span class="tab">  </span><span class="kwd">var</span> i = <span class="val">0</span>
+<span class="tab">  </span><span class="kwd">while</span> i <= a.high:
+<span class="tab">  <span class="tab">  </span></span></span><span class="kwd">spawn</span> f(a[i])
+<span class="tab">  <span class="tab">  </span></span></span><span class="kwd">spawn</span> f(a[i+<span class="val">1</span>])
+<span class="tab">  <span class="tab">  </span></span></span><span class="cmt"># ERROR: cannot prove a[i] is disjoint from a[i+1]</span>
+<span class="tab">  <span class="tab">  </span></span></span><span class="cmt"># BUT: replace 'i += 1' with 'i += 2' and the code compiles!</span>
+<span class="tab end">  <span class="tab end">  </span></span>i += <span class="val">1</span>
+</pre>
+          </div>
+          <div id="slide1">
+            <div>
+              <h2>Nim is simple..</h2>
+<pre>
+<span class="cmt"># compute average line length</span>
+<span class="kwd">var</span>
+<span class="tab">  </span>sum = <span class="val">0</span>
+<span class="tab end">  </span>count = <span class="val">0</span>
+
+<span class="kwd">for</span> line <span class="kwd">in</span> stdin.lines:
+<span class="tab">  </span>sum += line.len
+<span class="tab end">  </span>count += <span class="val">1</span>
+
+echo(<span class="val">"Average line length: "</span>,
+  <span class="kwd">if</span> count &gt; <span class="val">0</span>: sum / count <span class="kwd">else</span>: <span class="val">0</span>)
+</pre>
+            </div>
+            <div>
+               <h2>..and type safe...</h2>
+<pre>
+<span class="cmt"># create and greet someone</span>
+<span class="kwd">type</span> <span class="def">Person</span> = <span class="kwd">object</span>
+<span class="tab">  </span>name: <span class="typ">string</span>
+<span class="tab end">  </span>age: <span class="typ">int</span>
+
+<span class="kwd">proc</span> <span class="def">greet</span>(p: <span class="typ">Person</span>) =
+<span class="tab">  </span>echo <span class="val">"Hi, I'm "</span>, p.name, <span class="val">"."</span>
+<span class="tab end">  </span>echo <span class="val">"I am "</span>, p.age, <span class="val">" years old."</span>
+
+<span class="kwd">let</span> p = <span class="typ">Person</span>(name:<span class="val">"Jon"</span>, age:<span class="val">18</span>)
+p.greet() <span class="cmt"># or greet(p)</span>
+</pre>
+             </div>
+          </div>
+          <div id="slide2" class="">
+            <div>
+              <h2>C FFI is easy in Nim..</h2>
+<pre>
+<span class="cmt"># declare a C procedure..</span>
+<span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>, s: <span class="typ">cstring</span>)
+<span class="tab">  </span>{.varargs,
+<span class="tab">    </span>importc: <span class="val">"fscanf"</span>, 
+<span class="tab end">    </span>header: <span class="val">"&lt;stdio.h&gt;"</span>.}
+
+<span class="cmt"># ..and use it...</span>
+<span class="kwd">var</span> x: <span class="typ">cint</span>
+stdin.unsafeScanf(<span class="val">"%d"</span>, <span class="kwd">addr</span> x)
+</pre>
+              <p><span class="desc"><b>Compile and run with:</b><br>&nbsp;&nbsp;&nbsp;&nbsp;&#36; nim c -r example.nim</span></p>
+            </div>
+            <div>
+              <h2>..and DSLs are too...</h2>
+<pre>
+<span class="cmt"># a simple html server</span>
+<span class="kwd">import</span>
+  jester, asyncdispatch, htmlgen
+
+<span class="kwd">routes</span>:
+<span class="tab">  </span><span class="kwd">get</span> <span class="val">"/"</span>:
+<span class="tab end">  <span class="tab end">  </span></span><span class="kwd">resp</span> h1(<span class="val">"Hello world"</span>)
+
+runForever()
+</pre>
+              <p><span class="desc"><b>View in browser at:</b><br>&nbsp;&nbsp;&nbsp;&nbsp;localhost:5000</span></p>
+            </div>
+          </div>
+        </div>
+        <div id="slideshow-nav">
+          <div id="slideControl0" onclick="slideshow_click(0)" class="active"></div>
+          <div id="slideControl1" onclick="slideshow_click(1)"></div>
+          <div id="slideControl2" onclick="slideshow_click(2)"></div>
+        </div>
+#  end
+        <aside id="sidebar">
+
+#  if len(c.links) > 0:
+          <h3>More Links</h3>
+          <div id="sidebar-links">
+#         for i in 0..c.links.len-1:
+          <a href="${c.links[i].val}" id="${c.links[i].id}">${c.links[i].key}</a>
+#         end for
+          </div>
+#  end if
+#  if len(c.ticker) > 0:
+					<h3 class="blue">Latest News</h3>
+					<div id="sidebar-news">
+          $c.ticker
+					</div>
+#  end if
+				</aside>
+			</div>
+		</section>
+
+		<section id="body">
+			<div id="body-border"></div>
+			<div id="glow-line"></div>
+			<div class="page-layout">
+				<article id="content" class="page">
+				$content
+				</article>
+			</div>
+		</section>
+
+		<!--- #foot --->
+		<footer id="foot" class="home">
+			<div class="page-layout tall">
+				<div id="foot-links">
+					<div>
+						<h4>Documentation</h4>
+						<a href="documentation.html">Stable Documentation</a>
+						<a href="learn.html">Learning Resources</a>
+					<!--	<a href="">Development Documentation</a> -->
+						<a href="https://github.com/Araq/Nimrod">Issues &amp; Requests</a>
+					</div>
+					<div>
+						<h4>Community</h4>
+						<a href="http://forum.nim-lang.org">User Forum</a>
+            <a href="http://webchat.freenode.net/?channels=nim">Online IRC</a>
+            <a href="http://irclogs.nim-lang.org/">IRC Logs</a>
+					</div>
+				</div>
+				<div id="foot-legal">
+					<h4>Written in Nim - Powered by <a href="https://github.com/dom96/jester">Jester</a></h4>
+					Web Design by <a href="http://reign-studios.net/philipwitte/">Philip Witte</a> &amp; <a href="http://picheta.me/">Dominik Picheta</a><br>
+					Copyright © 2015 - <a href="http://nim-lang.org/blog/">Andreas Rumpf</a> &amp; <a href="https://github.com/Araq/Nimrod/graphs/contributors">Contributors</a>
+				</div>
+			</div>
+		</footer>
+  
+#  if currentTab == "index":
+  <script src="assets/index.js"></script>
+# end if
+#  if c.gaId != nil:
+  <script>
+    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+    ga('create', '${c.gaId}', 'nim-lang.org');
+    ga('send', 'pageview');
+  </script>
+#  end if
+</body>
+</html>
diff --git a/web/assets/images/bg.png b/web/assets/images/bg.png
new file mode 100644
index 000000000..91f335913
--- /dev/null
+++ b/web/assets/images/bg.png
Binary files differdiff --git a/web/assets/images/docs-articles.png b/web/assets/images/docs-articles.png
new file mode 100644
index 000000000..7f800ea33
--- /dev/null
+++ b/web/assets/images/docs-articles.png
Binary files differdiff --git a/web/assets/images/docs-examples.png b/web/assets/images/docs-examples.png
new file mode 100644
index 000000000..e6d27e034
--- /dev/null
+++ b/web/assets/images/docs-examples.png
Binary files differdiff --git a/web/assets/images/docs-internals.png b/web/assets/images/docs-internals.png
new file mode 100644
index 000000000..e03a952d5
--- /dev/null
+++ b/web/assets/images/docs-internals.png
Binary files differdiff --git a/web/assets/images/docs-libraries.png b/web/assets/images/docs-libraries.png
new file mode 100644
index 000000000..b14952f7d
--- /dev/null
+++ b/web/assets/images/docs-libraries.png
Binary files differdiff --git a/web/assets/images/docs-tools.png b/web/assets/images/docs-tools.png
new file mode 100644
index 000000000..d83f0faaa
--- /dev/null
+++ b/web/assets/images/docs-tools.png
Binary files differdiff --git a/web/assets/images/docs-tutorials.png b/web/assets/images/docs-tutorials.png
new file mode 100644
index 000000000..926a4b58b
--- /dev/null
+++ b/web/assets/images/docs-tutorials.png
Binary files differdiff --git a/web/assets/images/favicon.ico b/web/assets/images/favicon.ico
new file mode 100644
index 000000000..aed71adb4
--- /dev/null
+++ b/web/assets/images/favicon.ico
Binary files differdiff --git a/web/assets/images/foot.png b/web/assets/images/foot.png
new file mode 100644
index 000000000..dc2561cf3
--- /dev/null
+++ b/web/assets/images/foot.png
Binary files differdiff --git a/web/assets/images/glow-arrow.png b/web/assets/images/glow-arrow.png
new file mode 100644
index 000000000..436d32f03
--- /dev/null
+++ b/web/assets/images/glow-arrow.png
Binary files differdiff --git a/web/assets/images/glow-line.png b/web/assets/images/glow-line.png
new file mode 100644
index 000000000..6607bdee9
--- /dev/null
+++ b/web/assets/images/glow-line.png
Binary files differdiff --git a/web/assets/images/head-link.png b/web/assets/images/head-link.png
new file mode 100644
index 000000000..d97cba5b8
--- /dev/null
+++ b/web/assets/images/head-link.png
Binary files differdiff --git a/web/assets/images/head-link_hover.png b/web/assets/images/head-link_hover.png
new file mode 100644
index 000000000..27edf3b05
--- /dev/null
+++ b/web/assets/images/head-link_hover.png
Binary files differdiff --git a/web/assets/images/head.png b/web/assets/images/head.png
new file mode 100644
index 000000000..009f86728
--- /dev/null
+++ b/web/assets/images/head.png
Binary files differdiff --git a/web/assets/images/link_aporia.png b/web/assets/images/link_aporia.png
new file mode 100644
index 000000000..145e5ddf2
--- /dev/null
+++ b/web/assets/images/link_aporia.png
Binary files differdiff --git a/web/assets/images/link_forum.png b/web/assets/images/link_forum.png
new file mode 100644
index 000000000..2973b42bc
--- /dev/null
+++ b/web/assets/images/link_forum.png
Binary files differdiff --git a/web/assets/images/link_nimbuild.png b/web/assets/images/link_nimbuild.png
new file mode 100644
index 000000000..4b3f943fe
--- /dev/null
+++ b/web/assets/images/link_nimbuild.png
Binary files differdiff --git a/web/assets/images/logo.png b/web/assets/images/logo.png
new file mode 100644
index 000000000..85d3d2e51
--- /dev/null
+++ b/web/assets/images/logo.png
Binary files differdiff --git a/web/assets/images/mascot.png b/web/assets/images/mascot.png
new file mode 100644
index 000000000..9beb62c01
--- /dev/null
+++ b/web/assets/images/mascot.png
Binary files differdiff --git a/web/assets/images/more-links_editors.png b/web/assets/images/more-links_editors.png
new file mode 100644
index 000000000..f5970ff1f
--- /dev/null
+++ b/web/assets/images/more-links_editors.png
Binary files differdiff --git a/web/assets/images/more-links_forum.png b/web/assets/images/more-links_forum.png
new file mode 100644
index 000000000..f33277777
--- /dev/null
+++ b/web/assets/images/more-links_forum.png
Binary files differdiff --git a/web/assets/images/more-links_github.png b/web/assets/images/more-links_github.png
new file mode 100644
index 000000000..4a6a844f4
--- /dev/null
+++ b/web/assets/images/more-links_github.png
Binary files differdiff --git a/web/assets/images/more-links_nimbuild.png b/web/assets/images/more-links_nimbuild.png
new file mode 100644
index 000000000..473fbe4cd
--- /dev/null
+++ b/web/assets/images/more-links_nimbuild.png
Binary files differdiff --git a/web/assets/images/nim-logo.svg b/web/assets/images/nim-logo.svg
new file mode 100644
index 000000000..feae6c3d7
--- /dev/null
+++ b/web/assets/images/nim-logo.svg
@@ -0,0 +1,500 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="163.84375"
+   height="124.67096"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient3833">
+      <stop
+         style="stop-color:#f7c41a;stop-opacity:1;"
+         offset="0"
+         id="stop3835" />
+      <stop
+         style="stop-color:#bd9510;stop-opacity:1;"
+         offset="1"
+         id="stop3837" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3825">
+      <stop
+         style="stop-color:#f3d673;stop-opacity:1;"
+         offset="0"
+         id="stop3827" />
+      <stop
+         style="stop-color:#c7a23a;stop-opacity:1;"
+         offset="1"
+         id="stop3829" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient3831"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,1.3722368,813.17816)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient3839"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,4.9030359,1024.9638)"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3839-8"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,4.9030359,1024.9638)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3833-7">
+      <stop
+         style="stop-color:#f4d779;stop-opacity:1;"
+         offset="0"
+         id="stop3835-5" />
+      <stop
+         style="stop-color:#bd9510;stop-opacity:1;"
+         offset="1"
+         id="stop3837-4" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3831-8"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,1.3722368,813.17816)"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3825-5">
+      <stop
+         style="stop-color:#f3d673;stop-opacity:1;"
+         offset="0"
+         id="stop3827-3" />
+      <stop
+         style="stop-color:#c7a23a;stop-opacity:1;"
+         offset="1"
+         id="stop3829-7" />
+    </linearGradient>
+    <radialGradient
+       r="80.321426"
+       fy="414.17612"
+       fx="407.17349"
+       cy="414.17612"
+       cx="407.17349"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3870"
+       xlink:href="#linearGradient3833-7"
+       inkscape:collect="always" />
+    <radialGradient
+       r="80.321426"
+       fy="414.24271"
+       fx="406.47156"
+       cy="414.24271"
+       cx="406.47156"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3872"
+       xlink:href="#linearGradient3825-5"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3908"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3910"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3914"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3916"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3918"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3920"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-7"
+       id="radialGradient3924"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-153.01531,1007.7817)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3926"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-156.54611,795.9961)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3933"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,19.13339,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient3935"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,4.9030359,1024.9638)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient3937"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,1.3722368,813.17816)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient3941"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-75.408823,1015.0037)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient3943"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-78.939622,803.21805)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3949"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,19.13339,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3953"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,19.13339,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3957"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,-70.86661,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-5"
+       id="radialGradient3961"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01462336,-0.89388887,0.97447651,-0.01594169,-70.86661,796.92442)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833-79"
+       id="radialGradient3941-1"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-75.408823,1015.0037)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <linearGradient
+       id="linearGradient3833-79">
+      <stop
+         style="stop-color:#f4d779;stop-opacity:1;"
+         offset="0"
+         id="stop3835-55" />
+      <stop
+         style="stop-color:#bd9510;stop-opacity:1;"
+         offset="1"
+         id="stop3837-5" />
+    </linearGradient>
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825-3"
+       id="radialGradient3943-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-78.939622,803.21805)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <linearGradient
+       id="linearGradient3825-3">
+      <stop
+         style="stop-color:#f3d673;stop-opacity:1;"
+         offset="0"
+         id="stop3827-0" />
+      <stop
+         style="stop-color:#c7a23a;stop-opacity:1;"
+         offset="1"
+         id="stop3829-2" />
+    </linearGradient>
+    <radialGradient
+       r="80.321426"
+       fy="414.24271"
+       fx="406.47156"
+       cy="414.24271"
+       cx="406.47156"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,91.271992,815.08835)"
+       gradientUnits="userSpaceOnUse"
+       id="radialGradient3985"
+       xlink:href="#linearGradient3825-3"
+       inkscape:collect="always" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient4029"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,-75.408823,1015.0037)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3825"
+       id="radialGradient4031"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.01492027,-0.91203843,0.99426233,-0.01626537,-78.939622,803.21805)"
+       cx="406.47156"
+       cy="414.24271"
+       fx="406.47156"
+       fy="414.24271"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient4037"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,71.056847,1015.1237)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3833"
+       id="radialGradient4047"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.0234034,-1.430605,0.9942623,-0.01626526,71.056847,1015.1237)"
+       cx="407.17349"
+       cy="414.17612"
+       fx="407.17349"
+       fy="414.17612"
+       r="80.321426" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#595959"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.7"
+     inkscape:cx="-296.38002"
+     inkscape:cy="91.425689"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer2"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1027"
+     inkscape:window-x="0"
+     inkscape:window-y="29"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     sodipodi:insensitive="true"
+     style="display:none"
+     transform="translate(-391.875,-406.1875)">
+    <image
+       y="392.14789"
+       x="-90.714287"
+       id="image3047"
+       xlink:href="file:///home/tomasi/Projects/nimrod/logo/new-symbols.png"
+       height="329"
+       width="800" />
+  </g>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Layer"
+     style="display:inline"
+     transform="translate(-391.875,-406.1875)">
+    <g
+       id="g4041">
+      <path
+         id="path4019"
+         d="m 474.37925,408.23965 c 0,0 -6.12468,5.3771 -12.34375,10.6875 -6.39764,-0.22532 -18.88846,1.38269 -25.6875,4.125 -6.26333,-4.40055 -11.8125,-9.28125 -11.8125,-9.28125 0,0 -4.69884,9.01564 -7.65625,14.28125 -4.38598,2.58703 -8.76277,5.43142 -12.6875,9.28125 -4.63902,-2.04302 -10.1875,-4.65625 -10.1875,-4.65625 l 6.25,27.875 0.9375,1.875 -1.09375,-1.875 c 0,0 8.86172,24.01192 14.8125,40 25.2159,36.89492 89.61617,39.46428 117.68751,0.71875 5.37871,-13.44336 11.62618,-31.71161 13.90625,-38.4375 l 1.25,-2.8125 5.90625,-26.78125 c 0,0 -6.87234,2.50886 -11.0625,4.28125 -2.40446,-3.40619 -6.05177,-7.01378 -11.25,-9.46875 -3.05538,-6.20497 -7.5,-14.65625 -7.5,-14.65625 0,0 -5.33268,4.38488 -11.4375,9.125 -8.24767,-1.68845 -18.23488,-3.72666 -26.62501,-3.21875 -5.71156,-5.20637 -11.40625,-11.0625 -11.40625,-11.0625 z"
+         style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cccccccccccccccccccc"
+         inkscape:connector-curvature="0"
+         id="path3054"
+         d="m 400.26095,460.55777 -6.25,-27.85715 c 0,0 5.53955,2.59984 10.17857,4.64286 3.92473,-3.84983 8.2926,-6.69868 12.67858,-9.28571 2.95741,-5.26561 7.67857,-14.28572 7.67857,-14.28572 0,0 5.52238,4.88517 11.78571,9.28572 6.79904,-2.74231 19.31665,-4.33247 25.71429,-4.10715 6.21906,-5.3104 12.32143,-10.71428 12.32143,-10.71428 0,0 5.71701,5.86506 11.42857,11.07143 8.39013,-0.50791 18.35947,1.52583 26.60714,3.21428 6.10482,-4.74012 11.42857,-9.10714 11.42857,-9.10714 0,0 4.44462,8.43789 7.5,14.64286 5.19824,2.45497 8.84554,6.05809 11.25,9.46428 4.19017,-1.77239 11.07143,-4.28571 11.07143,-4.28571 l -5.89286,26.78571 -6.60714,14.82143 c 0,0 -4.31067,-2.70091 -7.32143,-4.28571 -16.93933,-45.69195 -106.71744,-37.02003 -119.46428,-0.71429 -5.78255,1.30574 -8.39286,2.32143 -8.39286,2.32143 z"
+         style="fill:url(#radialGradient4047);fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="cccccccccccccc"
+         inkscape:connector-curvature="0"
+         id="path3051"
+         d="m 400.08238,460.55777 c 0,0 8.87064,24.01192 14.82143,40 25.2159,36.89492 89.60723,39.45981 117.67857,0.71428 6.64277,-16.60268 15,-41.60714 15,-41.60714 l -6.07143,11.42857 -7.63525,-0.35714 -11.82903,15 -16.96429,5 -31.07143,-17.85715 -31.25,17.5 -16.96428,-4.82142 -11.54402,-15.59885 -7.56312,2.02742 z"
+         style="fill:#ffffff;stroke:none" />
+      <path
+         sodipodi:nodetypes="scccccccccs"
+         id="path3054-8"
+         d="m 474.88371,439.45394 c 26.96263,-0.0368 50.75931,9.32331 58.9643,31.09821 0.11438,0.0602 0.25716,0.12428 0.375,0.1875 l -0.34375,0 -11.84375,15 -16.93751,5 -31.09375,-17.875 -31.25,17.5 -16.96875,-4.8125 -11.31751,-16.02955 c 6.01205,-17.4758 32.67194,-30.03082 60.41572,-30.06866 z"
+         style="fill:none;stroke:#000000;stroke-width:1.10000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+         inkscape:connector-curvature="0" />
+    </g>
+  </g>
+</svg>
diff --git a/web/assets/images/quote.png b/web/assets/images/quote.png
new file mode 100644
index 000000000..e9426158c
--- /dev/null
+++ b/web/assets/images/quote.png
Binary files differdiff --git a/web/assets/images/quotes.png b/web/assets/images/quotes.png
new file mode 100644
index 000000000..0d75b4cc2
--- /dev/null
+++ b/web/assets/images/quotes.png
Binary files differdiff --git a/web/assets/images/sidebar.png b/web/assets/images/sidebar.png
new file mode 100644
index 000000000..142db93cf
--- /dev/null
+++ b/web/assets/images/sidebar.png
Binary files differdiff --git a/web/assets/images/sidebar_h2.png b/web/assets/images/sidebar_h2.png
new file mode 100644
index 000000000..d1409b57f
--- /dev/null
+++ b/web/assets/images/sidebar_h2.png
Binary files differdiff --git a/web/assets/images/sidebar_head.png b/web/assets/images/sidebar_head.png
new file mode 100644
index 000000000..05885d9f3
--- /dev/null
+++ b/web/assets/images/sidebar_head.png
Binary files differdiff --git a/web/assets/images/site_foot.png b/web/assets/images/site_foot.png
new file mode 100644
index 000000000..a2efa0460
--- /dev/null
+++ b/web/assets/images/site_foot.png
Binary files differdiff --git a/web/assets/images/site_neck.png b/web/assets/images/site_neck.png
new file mode 100644
index 000000000..d4f42c6b7
--- /dev/null
+++ b/web/assets/images/site_neck.png
Binary files differdiff --git a/web/assets/images/slideshow-nav.png b/web/assets/images/slideshow-nav.png
new file mode 100644
index 000000000..fbfff3e5d
--- /dev/null
+++ b/web/assets/images/slideshow-nav.png
Binary files differdiff --git a/web/assets/images/slideshow-nav_active.png b/web/assets/images/slideshow-nav_active.png
new file mode 100644
index 000000000..525caf355
--- /dev/null
+++ b/web/assets/images/slideshow-nav_active.png
Binary files differdiff --git a/web/assets/images/tabEnd.png b/web/assets/images/tabEnd.png
new file mode 100644
index 000000000..a94af90f1
--- /dev/null
+++ b/web/assets/images/tabEnd.png
Binary files differdiff --git a/web/assets/index.js b/web/assets/index.js
new file mode 100644
index 000000000..f10dc603d
--- /dev/null
+++ b/web/assets/index.js
@@ -0,0 +1,34 @@
+"use strict";
+
+var timer;
+var prevIndex = 0;
+var slideCount = 2;
+
+function setSlideShow(index, short) {
+  if (index >= slideCount) index = 0;
+  document.getElementById("slide"+prevIndex).className = "";
+  document.getElementById("slide"+index).className = "active";
+  document.getElementById("slideControl"+prevIndex).className = "";
+  document.getElementById("slideControl"+index).className = "active";
+  prevIndex = index;
+  startTimer(short ? 8000 : 32000);
+}
+
+function nextSlide() { setSlideShow(prevIndex + 1, true); }
+function startTimer(t) { timer = setTimeout(nextSlide, t); }
+
+function slideshow_enter() { clearTimeout(timer); }
+function slideshow_exit () { startTimer(16000); }
+
+function slideshow_click(index) {
+  clearTimeout(timer);
+  setSlideShow(index, false);
+}
+
+window.onload = function() {
+  var slideshow = document.getElementById("slideshow");
+  slideshow.onmouseenter = slideshow_enter;
+  slideshow.onmouseleave = slideshow_exit;
+  slideCount = slideshow.children.length;
+  startTimer(8000);
+};
\ No newline at end of file
diff --git a/web/assets/style.css b/web/assets/style.css
new file mode 100644
index 000000000..17541a118
--- /dev/null
+++ b/web/assets/style.css
@@ -0,0 +1,558 @@
+
+* { cursor:default; }
+a, a * { cursor:pointer; }
+
+html { margin:0; overflow-x:auto; }
+body {
+	overflow-x:hidden;
+	min-width:1030px;
+	margin:0;
+	font:13pt "arial";
+	background:#152534 url("images/bg.png") no-repeat center top; 
+	color:rgba(0,0,0,.8); }
+
+pre {
+  color:#fff;
+  margin:0;
+  padding:15px 10px;
+  font:10pt monospace;
+  line-height:14pt;
+  background:rgba(0,0,0,.4);
+  border-left:8px solid rgba(0,0,0,.3);
+  box-shadow:1px 2px 16px rgba(28,180,236,.4); }
+pre, pre * { cursor:text; }
+pre .cmt { color:rgb(255,229,106); }
+pre .kwd { color:#43A8CF; font-weight:bold; }
+pre .typ { color:#128B7D; font-weight:bold; }
+pre .atr { color:#128B7D; font-weight:bold; font-style:italic; }
+pre .def { color:#CAD6E4; font-weight:bold; }
+pre .prg { color:#854D6A; font-weight:bold; font-style:italic; }
+pre .val { color:#8AB647; }
+pre .tab { border-left:1px dotted rgba(67,168,207,0.4); }
+pre .end { background:url("images/tabEnd.png") no-repeat left bottom; }
+
+.page pre { background:rgba(0,0,0,.8); }
+.page pre > .Comment { color:rgb(255,229,106); }
+.page pre > .Keyword { color:#43A8CF; font-weight:bold; }
+.page pre > .StringLit,
+.page pre > .DecNumber { color:#8AB647; }
+
+.tall { height:100%; }
+.pre { padding:1px 5px; font:11pt monospace; background:#96A9B7; border-radius:3px; }
+
+.page-layout { margin:0 auto; width:1000px; }
+.docs-layout { margin:0 40px; }
+.talk-layout { margin:0 40px; }
+.wide-layout { margin:0 auto; }
+
+#head { height:100px; background:url("images/head.png") repeat-x bottom; }
+#head.docs { margin-left:280px; background:rgba(0,0,0,.25) url("images/head-fade.png") no-repeat right top; }
+#head > div { position:relative }
+	
+	#head-logo {
+		position:absolute;
+		left:-390px;
+		top:0;
+		width:917px;
+		height:268px;
+		pointer-events:none;
+		background:url("images/logo.png") no-repeat; }
+	#head.docs #head-logo { left:-381px; position:fixed; }
+	#head.forum #head-logo { left:-370px; }
+	
+  #head-logo-link {
+    position:absolute;
+    display:block;
+    top:10px;
+    left:10px;
+    width:236px;
+    height:85px; }
+  #head.docs #head-logo-link { left:-260px; }
+  #head.forum #head-logo-link { left:30px; }
+	
+	#head-links { position:absolute; right:0; bottom:13px; }
+	#head.docs #head-links,
+	#head.forum #head-links { right:20px; }
+	#head-links > a {
+		display:block;
+		float:left;
+		padding:10px 25px 25px 25px;
+		color:rgba(255,255,255,.5);
+		font-size:14pt;
+		text-decoration:none;
+		letter-spacing:1px;
+		background:url("images/head-link.png") no-repeat center bottom;
+		transition:
+			color 0.3s ease-in-out,
+			text-shadow 0.4s ease-in-out; }
+	#head-links > a:hover,
+	#head-links > a.active {
+		color:#1cb3ec;
+		text-shadow:0 0 4px rgba(28,179,236,.8);
+		background-image:url("images/head-link_hover.png"); }
+
+	#head-banner { width:200px; height:100px; background:#000; }
+
+#neck { z-index:0; height:40px; }
+#neck.home { height:370px; }
+#neck > div { position:relative }
+	
+	#glow-arrow {
+		position:absolute;
+		top:-9px;
+		left:0;
+		right:-16px;
+		height:48px;
+		background:url("images/glow-arrow.png") no-repeat right; }
+  #glow-arrow.docs { left:280px; }
+	
+	#glow-line-vert {
+		position:fixed;
+		top:100px;
+		left:280px;
+		width:3px;
+		height:844px;
+		background:url("images/glow-line-vert.png") no-repeat; }
+	
+	#slideshow { position:absolute; top:10px; left:10px; width:700px; height: 1000px; }
+	#slideshow > div {
+    position:absolute;
+    margin:30px 0 0 10px;
+    visibility:hidden;
+    opacity:0;
+    transition:
+      visibility 0s linear 1s,
+      opacity 1s ease-in-out; }
+	#slideshow > div.active { visibility:visible; opacity:1; transition-delay:0s; }
+	#slideshow > div.init { transition-delay:0s; }
+	#slideshow-nav { z-index:3; position:absolute; top:341px; left:18px; }
+	#slideshow-nav > div { display:inline-block; margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; }
+	#slideshow-nav > div:hover { background-image:url("images/slideshow-nav_active.png"); opacity:0.5; }
+	#slideshow-nav > div.active { background-image:url("images/slideshow-nav_active.png"); opacity:1; }
+    
+		#slide0 { float:left; width:680px; font:10pt monospace; }
+		#slide0 > div:first-child { margin:0 40px 0 0; }
+		#slide0 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); }
+		#slide0 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); font:13pt "arial"; }
+		
+		#slide1 > div { float:left; width:320px; font:10pt monospace; }
+		#slide1 > div:first-child { margin:0 40px 0 0; }
+		#slide1 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); }
+    
+		#slide2 > div { float:left; width:320px; font:10pt monospace; }
+		#slide2 > div:first-child { margin:0 40px 0 0; }
+		#slide2 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); }
+    
+		#slide2 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); font:13pt "arial"; }
+    
+		/* back when slide1 was the quote:
+		#slide1 { margin-top:50px; }
+		#slide1 > p {
+			padding:40px 20px 0 20px;
+			font-style:italic;
+			color:rgba(162,198,223,.78);
+			letter-spacing:1px;
+			line-height:25pt;
+			background:url("images/quotes.png") top left no-repeat; }
+		#slide1 > div {
+			float:right;
+			margin-right:40px;
+			font-style:italic;
+			font-weight:bold;
+			color:rgba(93,155,199,.44); }
+    */
+	#sidebar {
+		z-index:2;
+		position:absolute;
+		top:5px; right:0;
+		width:275px;
+		height:726px;
+		padding:210px 0 0 0;
+		background:url("images/sidebar.png") no-repeat; }
+	#sidebar > h3 { margin:0 30px 0 30px; color:rgba(255,255,255,.5); }
+	#sidebar > h3.blue { color:rgba(28,180,236,.5); }
+	#sidebar-links,
+	#sidebar-news {
+		margin:10px 30px 50px 30px;
+		padding:10px 0;
+		background:rgba(0,0,0,.6); }
+	#sidebar-links { box-shadow:1px 2px 12px rgba(255,255,255,.4); }
+	#sidebar-news { box-shadow:1px 2px 12px rgba(28,180,236,.6); }
+	#sidebar-links > a {
+		display:block;
+		margin-left:15px;
+		padding:12px 20px 12px 45px;
+		font-weight:bold;
+		text-decoration:none;
+		letter-spacing:1px;
+		color:rgba(255,255,255,.4);
+		transition:
+			color 0.1s ease-in-out,
+			text-shadow 0.2s ease-in-out; }
+	#sidebar-news > a { transition: color 0.3s ease-in-out; }
+	#sidebar-news > a > h4 { transition: color 0.1s ease-in-out, text-shadow 0.2s ease-in-out; }
+	#sidebar-links > a:hover { color:#fff; text-shadow:0 0 6px #fff; }
+	#sidebar-news > a { display:block; padding:15px; color:rgba(255,255,255,.4); text-decoration:none; }
+	#sidebar-news > a > h4 { margin:0 0 5px 0; color:rgba(28,180,236,.5); }
+	#sidebar-news > a:hover > h4 { margin:0 0 5px 0; color:rgba(28,180,236,.8); text-shadow:0 0 6px rgba(28,180,236,.6); }
+	#sidebar-news > a:hover { color:rgba(255,255,255,1); }
+	#sidebar-news > a.blue { color:rgba(28,180,236,.5); font-weight:bold; }
+	#sidebar-news > a.blue:hover { color:#fff; }
+		
+		#link_forum { background:url("images/more-links_forum.png") no-repeat left center; }
+		#link_github { background:url("images/more-links_github.png") no-repeat left center; }
+		#link_editors { background:url("images/more-links_editors.png") no-repeat left center; }
+		#link_aporia { background:url("images/more-links_editors.png") no-repeat left center; }
+		#link_nimbuild { background:url("images/more-links_nimbuild.png") no-repeat left center; }
+	
+	#overview-bg {
+		position:fixed;
+		top:0;
+		bottom:0;
+		left:0;
+		width:280px;
+		background:rgba(0,0,0,0.25); }
+	#overview {
+		z-index:3;
+		position:fixed;
+		overflow:auto;
+		top:115px;
+		bottom:20px;
+		left:20px;
+		width:245px; }
+	#overview::-webkit-scrollbar { width:5px; }
+	#overview::-webkit-scrollbar-track { border-radius:2px; background:rgba(255,255,255,.03); }
+	#overview::-webkit-scrollbar-thumb { border-radius:2px; background:rgba(28,179,236,.5); }
+	#overview > div { overflow:auto; margin-bottom:40px; }
+	#overview a {
+		display:block;
+		padding:0 10px;
+		margin:2px 5px 2px 0;
+		color:rgba(255,255,255,.6);
+		background:rgba(255,255,255,0.03);
+    border-radius:2px;
+		letter-spacing:1px;
+		text-decoration:none; }
+	#overview a:hover { color:#fff; background:rgba(255,255,255,0.05); }
+	#overview > .types a { border-left:2px solid rgba(28,179,236,.4); }
+	#overview > .procs a { border-left:2px solid rgba(255,223,53,.4); }
+	#overview > .iters a { border-left:2px solid rgba(255,134,53,.4); }
+	#overview > div > h4 {
+		margin:0 5px 10px 0;
+		padding:5px 10px;
+		letter-spacing:1px;
+		color:#fff;
+		border-left:2px solid #fff;
+    border-radius:2px;
+		background:rgba(255,255,255,0.1); }
+	#overview > .types h4 { color:#1cb3ec; border-color:#1cb3ec; }
+	#overview > .procs h4 { color:#ffdf35; border-color:#ffdf35; }
+	#overview > .iters h4 { color:#ff8635; border-color:#ff8635; }
+	#overview h5 {
+		color:rgba(28,179,236,.6);
+		margin:10px 0 5px 0;
+		padding:5px 5px;
+		letter-spacing:1px; }
+
+#body { z-index:1; position:relative; background:rgba(220,231,248,0.8); }
+#body.docs { margin:0 40px 20px 320px; }
+#body.forum { margin:0 40px 20px 40px; }
+	
+	#body-border {
+		position:absolute;
+		top:-25px;
+		left:0;
+		right:0;
+		height:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body-border-left {
+		position:absolute;
+		left:-25px;
+		top:-25px;
+		bottom:-25px;
+		width:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body-border-right {
+		position:absolute;
+		right:-25px;
+		top:-25px;
+		bottom:-25px;
+		width:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body-border-bottom {
+		position:absolute;
+		left:10px;
+		right:10px;
+		bottom:-25px;
+		height:35px;
+		background:rgba(0,0,0,.25); }
+	
+	#body.docs #body-border,
+	#body.forum #body-border { left:10px; right:10px; }
+	
+	#glow-line {
+		position:absolute;
+		top:-27px;
+		left:100px;
+		right:-25px;
+		height:3px;
+		background:url("images/glow-line.png") no-repeat left; }
+	#glow-line-bottom {
+		position:absolute;
+		bottom:-27px;
+		left:-25px;
+		right:100px;
+		height:3px;
+		background:url("images/glow-line2.png") no-repeat right; }
+	
+	#content { padding:40px 0; line-height:150%; }
+	#content.page { width:680px; min-height:800px; padding-left:20px; }
+	#content h1 { font-size:20pt; letter-spacing:1px; color:rgba(0,0,0,.75); }
+	#content h2 { font-size:16pt; letter-spacing:1px; color:rgba(0,0,0,.7); margin-top:40px; }
+	#content p { text-align:justify; }
+	#content a { color:#0E65D1; text-decoration:none; }
+	#content a:hover { text-decoration:underline; }
+	#content ul { padding-left:20px; }
+	#content li { margin-bottom:10px; text-align:justify; }
+	
+		#body.docs #content > div { margin-top:40px; padding-top:40px; border-top:1px dashed rgba(0,0,0,.25); }
+		#body.docs #content > div:first-child { margin-top:0; padding-top:0; border:none; }
+		#body.docs #content > div > h3 {
+			color:#fff;
+			margin:0 0 10px 0;
+			padding:10px 20px;
+			letter-spacing:1px;
+			border-left:8px solid #fff;
+      border-radius:3px;
+			background:rgba(0,0,0,.7);
+			box-shadow:1px 3px 12px rgba(0,0,0,.4); }
+		#body.docs #content > #types-wrap > h3 { color:#1cb3ec; border-color:#1cb3ec; }
+		#body.docs #content > #procs-wrap > h3 { color:#ffdf35; border-color:#ffdf35; }
+		#body.docs #content > #iters-wrap > h3 { color:#ff8635; border-color:#ff8635; }
+		#body.docs #content > div > div > div {
+			overflow:auto;
+			margin:10px 0;
+			border-left:8px solid #fff;
+      border-radius:3px;
+			background:rgba(0,0,0,.1); }
+		#body.docs #content > #types-wrap > div > div { border-color:rgba(28,179,236,.5); }
+		#body.docs #content > #procs-wrap > div > div { border-color:rgba(255,223,53,.5); }
+		#body.docs #content > #iters-wrap > div > div { border-color:rgba(255,134,53,.5); }
+		#body.docs #content > #procs-wrap > div > div.overload-head { margin-bottom:0; }
+		#body.docs #content > #procs-wrap > div > div.overload-tail { margin-top:0; border-top:1px dashed rgba(255,223,53,.5); }
+		#body.docs #content > #procs-wrap > div > div.overload { margin-top:0; margin-bottom:0; border-top:1px dashed rgba(255,223,53,.5); }
+		#body.docs #content > #iters-wrap > div > div.overload-head { margin-bottom:0; }
+		#body.docs #content > #iters-wrap > div > div.overload-tail { margin-top:0; border-top:1px dashed rgba(255,134,53,.5); }
+		#body.docs #content > #iters-wrap > div > div.overload { margin-top:0; margin-bottom:0; border-top:1px dashed rgba(255,134,53,.5); }
+		#body.docs #content > div > div > p { margin:20px 10px 10px 10px; }
+		
+		#body.docs #content > div > div > div > div { float:left; }
+		#body.docs #content > div > div > div > div.head { width:60%; }
+		#body.docs #content > div > div > div > div.data { width:40%; }
+    
+    #body.docs #content > h1 > .symbol {
+      padding:0 8px;
+      border-radius:5px;
+      background:rgba(206,218,233,.4); }
+    
+		#body.docs #content > div > div > div > div.head > .sign {
+			margin:0 10px 5px 10px;
+			padding:10px 10px 0 10px;
+			font-weight:bold;
+			border-bottom:1px dashed rgba(0,0,0,.25); }
+		#body.docs #content > div > div > div > div.head > .desc {
+			padding:0 20px 10px 20px;
+			color:rgba(0,0,0,.75); }
+		#body.docs #content > div > #types > div > div.head > .sign > .symbol {
+			padding:0 5px;
+			border-radius:3px;
+			background:rgba(28,179,236,.4); }
+		#body.docs #content > div > #procs > div > div.head > .sign > .symbol {
+			padding:0 5px;
+			border-radius:3px;
+			background:rgba(255,223,53,.3); }
+		#body.docs #content > div > #iters > div > div.head > .sign > .symbol {
+			padding:0 5px;
+			border-radius:3px;
+			background:rgba(255,134,53,.3); }
+			
+		#body.docs #content > div > div > div > div.data > div {
+			margin:0 20px 5px 10px;
+			padding:10px 0 0 10px;
+			font-style:italic;
+			color:rgba(0,0,0,.6);
+			border-bottom:1px dashed rgba(0,0,0,.25); }
+		#body.docs #content > div > div > div > div.data > ul { margin:0; padding:0 10px; }
+		#body.docs #content > div > div > div > div.data > ul:last-child { margin-bottom:5px; padding-bottom:10px; }
+		#body.docs #content > div > div > div > div.data > ul .symbol { padding:0 5px; border-radius:3px; background:rgba(23,192,23,.25); }
+		#body.docs #content > div > div > div > div.data > ul.pragmas .symbol { background:rgba(106,50,145,.25); }
+		#body.docs #content > div > div > div > div.data > ul > li { margin:0; padding:0 10px; list-style:none; }
+		
+		#body.docs #content pre {
+			overflow:auto;
+			margin:10px 0;
+			padding:15px 10px;
+			font-size:10pt;
+			font-style:normal;
+			line-height:14pt;
+			background:rgba(0,0,0,.75);
+			border-left:8px solid rgba(0,0,0,.3); }
+    
+    #docs-sort { float:right; font-size:75%; }
+    #docs-sort > a {
+      cursor:default;
+      margin:0 0 0 10px;
+      padding:2px 10px;
+      border-radius:5px;
+      color:rgba(0,0,0,.25);
+      background:rgba(0,0,0,.1);
+      box-shadow:inset 0 1px 8px rgba(0,0,0,.4); }
+    #docs-sort > a:hover,
+    #docs-sort > a.active { color:#000; background:rgba(0,0,0,.2); }
+    
+    #talk-heads { overflow:auto; margin:0 8px 0 8px; }
+    #talk-heads > div { float:left; font-size:120%; font-weight:bold; }
+    #talk-heads > .topic { width:55%; }
+    #talk-heads > .detail { width:15%; }
+    #talk-heads > .author { width:15%; }
+    #talk-heads > .reply { width:15%; }
+    #talk-heads > div > div { margin:0 10px 10px 10px; padding:0 10px 10px 10px; border-bottom:1px dashed rgba(0,0,0,0.4); }
+    #talk-heads > .topic > div { margin-left:0; }
+    #talk-heads > .author > div { margin-right:0; }
+    
+    #talk-thread  > div,
+    #talk-threads > div {
+      position:relative;
+      margin:5px 0;
+      overflow:auto;
+      border-radius:3px;
+      border:8px solid rgba(0,0,0,.8);
+      border-top:none;
+      border-bottom:none;
+      background:rgba(0,0,0,0.1); }
+    #talk-thread  > div:nth-child(odd) { background:rgba(255,255,255,0.1); }
+    #talk-threads > div:nth-child(odd) { background:rgba(0,0,0,0.2); }
+    #talk-thread  > div > div,
+    #talk-threads > div > div { float:left; }
+    #talk-thread  > div > div > div,
+    #talk-threads > div > div > div { margin:10px 20px; }
+    #talk-threads > div > .topic { width:55%; }
+    #talk-threads > div > .reply { width:15%; overflow:hidden; }
+    #talk-threads > div > .detail { width:15%; overflow:hidden; }
+    #talk-thread  > div > .author,
+    #talk-threads > div > .author {
+      position:absolute;
+      right:0;
+      top:0;
+      bottom:0;
+      width:15%;
+      overflow:hidden;
+      background:rgba(0,0,0,0.8); }
+    #talk-thread  > div > .author a,
+    #talk-threads > div > .author a { color:#1cb3ec !important; }
+    #talk-thread  > div > .author a:hover,
+    #talk-threads > div > .author a:hover { color:#fff !important; }
+    #talk-threads > div > .topic .pages { float:right; }
+    #talk-threads > div > .topic > div > a { font-weight:bold; }
+    #talk-threads > div > .detail > div { float:left; margin:0; }
+    #talk-threads > div > .detail > div > div { margin-left:20px; padding:10px 10px 10px 22px; }
+    #talk-threads > div > .detail > div { width:50%; }
+    #talk-threads > div > .detail > div:first-child > div { background:url("images/forum-views.png") no-repeat left; }
+    #talk-threads > div > .detail > div:last-child > div { background:url("images/forum-posts.png") no-repeat left; }
+    
+    #talk-thread > div {  margin:20px 0; min-height:150px; box-shadow:1px 3px 12px rgba(0,0,0,.4) }
+    #talk-thread > div > .author > div > .avatar { margin-top:20px; }
+    #talk-thread > div > .author > div > .avatar > img { box-shadow:0 0 12px #1cb3ec; }
+    #talk-thread > div > .author > div > .name { }
+    #talk-thread > div > .topic { width:85%; padding-bottom:10px; }
+    #talk-thread > div > .topic pre {
+      overflow:auto;
+      margin:0;
+      padding:15px 10px;
+      font-size:10pt;
+      font-style:normal;
+      line-height:14pt;
+      background:rgba(0,0,0,.75);
+      border-left:8px solid rgba(0,0,0,.3); }
+    
+    #talk-head,
+    #talk-info {
+      overflow:auto;
+      border-radius:3px;
+      border:8px solid rgba(0,0,0,.2);
+      border-top:none;
+      border-bottom:none;
+      background:rgba(0,0,0,0.1); }
+    #talk-head { margin-bottom:20px; }
+    #talk-info { margin-top:20px; }
+    #talk-head > div,
+    #talk-info > div { float:left; }
+    #talk-head > .info,
+    #talk-info > .info { width:85%; }
+    #talk-head > .user,
+    #talk-info > .user { width:15%; background:rgba(0,0,0,.2); }
+    #talk-info > .user > div > .reply { font-weight:bold; padding-left:22px; background:url("images/forum-reply.png") no-repeat left; }
+    #talk-head > div > div,
+    #talk-info > div > div { padding:5px 20px; }
+    #talk-head > .detail > div { float:left; margin:0; }
+    #talk-head > .detail > div > div { padding-left:22px; }
+    #talk-head > .detail > div:first-child > div { background:url("images/forum-views.png") no-repeat left; }
+    #talk-head > .detail > div:last-child > div { background:url("images/forum-posts.png") no-repeat left; }
+    
+    #talk-nav { margin:20px 8px 0 8px; padding-top:10px; border-top:1px dashed rgba(0,0,0,0.4); text-align:center; }
+    #talk-nav > a.active { text-decoration:underline !important; }
+    
+    .standout {
+      padding:5px 30px;
+      margin-bottom:20px;
+      border:8px solid rgba(0,0,0,.8);
+      border-right-width:16px;
+      border-top-width:0;
+      border-bottom-width:0;
+      border-radius:3px;
+      background:rgba(0,0,0,0.1);
+      box-shadow:1px 3px 12px rgba(0,0,0,.4); }
+    .standout h2 { margin-bottom:10px; padding-bottom:10px; border-bottom:1px dashed rgba(0,0,0,.8); }
+    .standout li { margin:0 !important; padding-top:10px; border-top:1px dashed rgba(0,0,0,.2); }
+    .standout ul { padding-bottom:5px; }
+    .standout .tools     ul { list-style:url("images/docs-tools.png"); }
+    .standout .libraries ul { list-style:url("images/docs-libraries.png"); }
+    .standout .internals ul { list-style:url("images/docs-internals.png"); }
+    .standout .tutorials ul { list-style:url("images/docs-tutorials.png"); }
+    .standout .examples  ul { list-style:url("images/docs-examples.png"); }
+    .standout .articles  ul { list-style:url("images/docs-articles.png"); }
+    .standout li:first-child { padding-top:0; border-top:none; }
+    .standout li p { margin:0 0 10px 0 !important; line-height:130%; }
+    .standout li p > a { font-weight:bold; }
+    
+    .forum-user-info,
+    .forum-user-info * { cursor:help }
+
+#foot { height:150px; position:relative; top:-10px; letter-spacing:1px; }
+#foot.home { background:url("images/foot.png") repeat-x top; height:200px; }
+#foot.docs { margin-left:320px; margin-right:40px; }
+#foot.forum { margin-left:40px; margin-right:40px; }
+#foot > div { position:relative; }
+#foot.home > div { width:960px; }
+#foot h4 { font-size:11pt; color:rgba(255,255,255,.4); margin:40px 0 6px 0; }
+#foot a:hover { color:#fff; }
+	
+	#foot-links { float:left; }
+	#foot-links > div { float:left; padding:0 40px 0 0; line-height:120%; }
+	#foot-links a { display:block; font-size:10pt; color:rgba(255,255,255,.3); text-decoration:none; }
+	#foot-legal { float:right; font-size:10pt; color:rgba(255,255,255,.3); line-height:150%; text-align:right; }
+	#foot-legal a { color:inherit; text-decoration:none; }
+	#foot-legal > h4 > a { color:inherit; }
+
+
+#body .docutils th {
+    border-bottom: 2px solid #1A1A1A;
+    font-weight: normal;
+    padding: 8px; }
+#body table.docutils {
+    border-collapse: collapse;
+    text-align: left;
+    border-spacing: 0px; }
diff --git a/web/community.txt b/web/community.txt
new file mode 100644
index 000000000..5d9343c98
--- /dev/null
+++ b/web/community.txt
@@ -0,0 +1,124 @@
+Nim's Community
+===============
+
+.. container:: standout
+
+  Forum
+  -----
+
+  The `Nim forum <http://forum.nim-lang.org/>`_ is the place where most 
+  discussions related to the language happen. It not only includes discussions
+  relating to the design of Nim but also allows for beginners to ask questions
+  relating to Nim.
+
+
+.. container:: standout
+
+  Mailing list
+  ------------
+
+  The mailing list can be found here: http://www.freelists.org/list/nim-dev
+  There is no consensus yet about what is discussed via the forum as opposed
+  to the mailing list. Join whatever you like!
+
+
+.. container:: standout
+
+  IRC
+  ----
+
+  Many Nim developers are a part of the
+  `#nim IRC channel <http://webchat.freenode.net/?channels=nim>`_ on
+  Freenode. That is the place where the rest of the discussion relating to Nim
+  occurs. Be sure to join us there if you wish to discuss Nim in real-time.
+  IRC is the perfect place for people just starting to learn Nim and we
+  welcome any questions that you may have!
+
+  You may also be interested in reading the
+  `IRC logs <http://irclogs.nim-lang.org/>`_ which are an archive of all
+  of the previous discussions that took place in the IRC channel.
+
+
+.. container:: standout
+
+  Github
+  ------
+
+  Nim's `source code <http://github.com/Araq/Nim>`_ is hosted on Github.
+  Together with the `wiki <http://github.com/Araq/Nim/wiki>`_ and
+  `issue tracker <http://github.com/Araq/Nim/issues>`_.
+
+  Github also hosts other projects relating to Nim. These projects are a part
+  of the `nim-lang organisation <http://github.com/nim-lang>`_.
+  This includes the `Nimble package manager <https://github.com/nim-lang/nimble>`_
+  and its `package repository <http://github.com/nim-lang/packages>`_. 
+
+
+.. container:: standout
+
+  Twitter
+  -------
+
+  Follow us `@nim_lang <http://twitter.com/nim_lang>`_ for latest news about
+  Nim.
+
+.. container:: standout
+
+  Reddit
+  ------
+
+  Subscribe to `/r/nim <http://reddit.com/r/nim>`_ for latest news about
+  Nim.
+
+.. container:: standout
+
+  StackOverflow
+  -------------
+
+  When asking a question relating to Nim, be sure to use the
+  `Nim <http://stackoverflow.com/questions/tagged/nim>`_ tag in your 
+  question.
+
+.. container:: standout
+
+  How to help
+  -----------
+
+  There are always many things to be done in the main
+  `Nim repository <https://github.com/Araq/Nim>`_, check out the 
+  `issues <https://github.com/Araq/Nim/issues>`_ for 
+  things to do; pull requests are always welcome. You can
+  also contribute to the many other projects hosted by the
+  `nim-lang <https://github.com/nim-lang>`_ organisation on github. If you
+  can't find anything you fancy doing, you can always ask for inspiration on IRC
+  (irc.freenode.net #nim) or on the `Nim forums <http://forum.nim-lang.org>`_.
+
+
+.. container:: standout
+
+  Donations
+  ---------
+
+  If you love what we do and are feeling generous then you can always donate.
+  Contributions of any quantity are greatly appreciated and will contribute to
+  making Nim even better!
+
+  Gittip
+    .. raw:: html
+
+      <iframe style="border: 0; margin: 0; padding: 0;"
+               src="https://www.gittip.com/Araq/widget.html"
+               width="64pt" height="22pt"></iframe>
+
+  Paypal
+    .. raw:: html
+
+      <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
+      <input type="hidden" name="cmd" value="_s-xclick">
+      <input type="hidden" name="hosted_button_id" value="ZQC6CVEEYNTLN">
+      <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
+      <img alt="" border="0" src="https://www.paypalobjects.com/de_DE/i/scr/pixel.gif" width="1" height="1">
+      </form>
+
+  Bitcoin
+    Bitcoin address: 1BXfuKM2uvoD6mbx4g5xM3eQhLzkCK77tJ
diff --git a/web/documentation.txt b/web/documentation.txt
new file mode 100644
index 000000000..67f8b4070
--- /dev/null
+++ b/web/documentation.txt
@@ -0,0 +1,57 @@
+Nim's Documentation
+===================
+
+.. container:: standout
+
+  Standards & Guides
+  ------------------
+
+  .. container:: libraries
+
+    - | `Standard Library <docs/lib.html>`_
+      | This document describes Nim's standard library.
+
+    - | `Language Manual <docs/manual.html>`_
+      | The Nim manual is a draft that will evolve into a proper specification.
+
+    - | `Compiler User Guide <docs/nimc.html>`_
+      | The user guide lists command line arguments, special features of the
+        compiler, etc.
+
+
+.. container:: standout
+
+  Tools & Features
+  ----------------
+
+  .. container:: tools
+
+    - | `Source Code Filters <docs/filters.html>`_
+      | The Nim compiler supports source code filters as a simple yet powerful
+        builtin templating system.
+
+    - | `Tools Documentation <docs/tools.html>`_
+      | Description of some tools that come with the standard distribution.
+
+
+.. container:: standout
+
+  Internal Details
+  ----------------
+
+  .. container:: internals
+
+    - | `Garbage Collector <docs/gc.html>`_
+      | Additional documentation about Nim's GC and how to operate it in a
+        realtime setting.
+
+    - | `Internal Documentation <docs/intern.html>`_
+      | The internal documentation describes how the compiler is implemented.
+        Read this if you want to hack the compiler.
+
+
+Search Options
+--------------
+
+`Documentation Index <docs/theindex.html>`_ - The generated
+index. **Index + (Ctrl+F) == Joy**
diff --git a/web/download.txt b/web/download.txt
new file mode 100644
index 000000000..6acc80b53
--- /dev/null
+++ b/web/download.txt
@@ -0,0 +1,57 @@
+Download the compiler
+=====================
+
+You can download the latest version of the Nim compiler here.
+
+**Note:** The Nim compiler requires a C compiler to compile software. On
+Windows we recommend that you use
+`Mingw-w64 <http://mingw-w64.sourceforge.net/>`_. GCC is recommended on Linux
+and Clang on Mac.
+
+
+Binaries
+--------
+
+Unfortunately for now we only provide builds for Windows.
+* 32 bit: `nim-0.11.2_x32.exe <download/nim-0.11.2_x32.exe>`_
+* 64 bit: `nim-0.11.2_x64.exe <download/nim-0.11.2_x64.exe>`_
+
+
+Installation based on generated C code
+--------------------------------------
+
+This installation method is the preferred way for Linux, Mac OS X, and other Unix
+like systems. Binary packages may be provided later.
+
+
+Download one of these:
+
+* `nim-0.11.2.zip (28 MB) <download/nim-0.11.2.zip>`_
+* `nim-0.11.2.tar.xz (2.6MB) <download/nim-0.11.2.tar.xz>`_
+
+Extract the file and follow these instructions:
+
+* sh build.sh
+* Add ``$your_install_dir/bin`` to your PATH.
+
+There are other ways to install Nim (like using the ``install.sh`` script),
+but these tend to cause more problems.
+
+
+Installation from github
+------------------------
+
+Use the following commands to build the compiler from source.
+Change the branch to suit your needs::
+
+  git clone -b master git://github.com/Araq/Nim.git
+  cd Nim
+  git clone -b master --depth 1 git://github.com/nim-lang/csources
+  cd csources && sh build.sh
+  cd ..
+  bin/nim c koch
+  ./koch boot -d:release
+
+The ``master`` branch always contains the latest stable version of the compiler.
+If you want bleeding edge then switch to the ``devel`` branch and follow
+the same instructions outlined above.
diff --git a/web/index.txt b/web/index.txt
new file mode 100644
index 000000000..95cac9316
--- /dev/null
+++ b/web/index.txt
@@ -0,0 +1,89 @@
+====
+Home
+====
+
+Welcome to Nim
+--------------
+
+**Nim** (formerly known as "Nimrod") is a statically typed, imperative
+programming language that tries to give the programmer ultimate power without
+compromises on runtime efficiency. This means it focuses on compile-time
+mechanisms in all their various forms.
+
+Beneath a nice infix/indentation based syntax with a
+powerful (AST based, hygienic) macro system lies a semantic model that supports
+a soft realtime GC on thread local heaps. Asynchronous message passing is used
+between threads, so no "stop the world" mechanism is necessary. An unsafe
+shared memory heap is also provided for the increased efficiency that results
+from that model.
+
+
+Nim is efficient
+================
+
+* Native code generation (currently via compilation to C), not dependent on a
+  virtual machine: **Nim produces small executables without dependencies
+  for easy redistribution.**
+* A fast **non-tracing** garbage collector that supports soft
+  real-time systems (like games).
+* System programming features: Ability to manage your own memory and access the
+  hardware directly. Pointers to garbage collected memory are distinguished
+  from pointers to manually managed memory.
+* Zero-overhead iterators.
+* Cross-module inlining.
+* Dynamic method binding with inlining and without virtual method table.
+* Compile time evaluation of user-defined functions.
+* Whole program dead code elimination: Only *used functions* are included in
+  the executable.
+* Value-based datatypes: For instance, objects and arrays can be allocated on
+  the stack.
+
+
+Nim is expressive
+=================
+
+* **The Nim compiler and all of the standard libraries are implemented in
+  Nim.**
+* Built-in high level datatypes: strings, sets, sequences, etc.
+* Modern type system with local type inference, tuples, variants,
+  generics, etc.
+* User-defineable operators; code with new operators is often easier to read
+  than code which overloads built-in operators. For example, a
+  ``=~`` operator is defined in the ``re`` module.
+* Macros can modify the abstract syntax tree at compile time.
+
+
+Nim is elegant
+==============
+
+* Macros can use the imperative paradigm to construct parse trees. Nim
+  does not require a different coding style for meta programming.
+* Macros cannot change Nim's syntax because there is no need for it.
+  Nim's syntax is flexible enough.
+* Statements are grouped by indentation but can span multiple lines.
+  Indentation must not contain tabulators so the compiler always sees
+  the code the same way as you do.
+
+
+Nim plays nice with others
+==========================
+
+* The Nim Compiler runs on Windows, Linux, BSD and Mac OS X.
+  Porting to other platforms is easy.
+* **The Nim Compiler can also generate C++ or Objective C for easier
+  interfacing.**
+* There are lots of bindings: for example, bindings to GTK2, the Windows API,
+  the POSIX API, OpenGL, SDL, Cairo, Python, Lua, TCL, X11, libzip, PCRE,
+  libcurl, mySQL and SQLite are included in the standard distribution or
+  can easily be obtained via the
+  `Nimble package manager <https://github.com/nim-lang/nimble>`_.
+* A C to Nim conversion utility: New bindings to C libraries are easily
+  generated by ``c2nim``.
+
+
+Roadmap to 1.0
+==============
+
+Please have a look at
+this `wiki page <https://github.com/Araq/Nim/wiki/Roadmap>`_ for
+an up-to-date overview.
diff --git a/web/learn.txt b/web/learn.txt
new file mode 100644
index 000000000..bf0cc43ef
--- /dev/null
+++ b/web/learn.txt
@@ -0,0 +1,56 @@
+Learning Nim
+============
+
+.. container:: standout
+
+  Tutorials
+  ---------
+
+  .. container:: tutorials
+
+    - | `Tutorial (part I) <docs/tut1.html>`_
+      | Learn the basics of Nim's types, variables, procedures, control flow, etc...
+
+    - | `Tutorial (part II) <docs/tut2.html>`_
+      | Learn Nim's more advanced features such as OOP, generics, macros, etc...
+
+
+.. container:: standout
+
+  Examples
+  --------
+
+  .. container:: examples
+
+    - | `Nim by Example <http://nim-by-example.github.io/>`_
+      | Nim by Example is an excellent starting place for beginners.
+
+    - | `Nim on Rosetta Code <http://rosettacode.org/wiki/Category:Nimrod>`_
+      | Many different Nim code examples comparable to other languages for reference.
+
+    - | `Nim for C/C++ Programmers <https://github.com/Araq/Nim/wiki/Nim-for-C-programmers>`_
+      | A useful cheat-sheet for those most familiar with C/C++ languages.
+
+
+.. container:: standout
+
+  Articles
+  --------
+
+  .. container:: articles
+
+    - `How I Start: Nim <http://howistart.org/posts/nim/1>`_
+    - `Getting Started With Nim <https://akehrer.github.io/nim/2015/01/05/getting-started-with-nim.html>`_
+    - `Getting Started With Nim - Part 2 <https://akehrer.github.io/nim/2015/01/14/getting-started-with-nim-pt2.html>`_
+    - `What is special about Nim? <http://hookrace.net/blog/what-is-special-about-nim>`_
+    - `What makes Nim practical? <http://hookrace.net/blog/what-makes-nim-practical>`_
+    - `Learn Nim in minutes <http://learnxinyminutes.com/docs/nim>`_
+    - `Dr Dobbs Nimrod Publication <http://www.drdobbs.com/open-source/nimrod-a-new-systems-programming-languag/240165321>`_
+    - `Nim articles by Göran Krampe <http://goran.krampe.se/category/nim>`_
+
+
+Documentation
+-------------
+
+More examples of Nim code can be found in the `Nim Language Documentation <docs/manual.html>`_.
+
diff --git a/web/links.txt b/web/links.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/web/links.txt
diff --git a/web/news.txt b/web/news.txt
new file mode 100644
index 000000000..22ea03157
--- /dev/null
+++ b/web/news.txt
@@ -0,0 +1,1712 @@
+====
+News
+====
+
+..
+  2015-05-05 Version 0.11.2 released
+  ==================================
+
+  Changes affecting backwards compatibility
+  -----------------------------------------
+
+  - The ``miliseconds`` property of ``times.TimeInterval`` is now ``milliseconds``.
+    Code accessing that property is deprecated and code using ``miliseconds``
+    during object initialization or as a named parameter of ``initInterval()``
+    will need to be updated.
+
+  Language Additions
+  ------------------
+
+
+  Bugfixes
+  --------
+
+
+2015-05-04 Version 0.11.2 released
+==================================
+
+This is just a bugfix release that fixes the most pressing regressions we
+introduced with version 0.11.0. The way types are computed was
+changed significantly causing all sort of problems. Sorry for the
+inconvenience; we grew overconfident our large test suite would prevent these
+things.
+
+
+2015-04-30 Version 0.11.0 released
+==================================
+
+With this release we are one step closer to reaching version 1.0 and by
+extension the persistence of the Nim specification. As mentioned in the
+previous release notes, starting with version 1.0, we will not be introducing
+any more breaking changes to Nim.
+
+The *language* itself is very close to 1.0, the primary area that requires
+more work is the standard library.
+
+Take a look at the `download <download.html>`_ page for binaries (Windows-only)
+and 0.11.0 snapshots of the source code. The Windows installer now also
+includes `Aporia <https://github.com/nim-lang/aporia>`_,
+`Nimble <https://github.com/nim-lang/nimble>`_ and other useful tools to get
+you started with Nim.
+
+What's left to be done
+~~~~~~~~~~~~~~~~~~~~~~
+
+The 1.0 release is expected by the end of this year. Rumors say it will be in
+summer 2015. What's left:
+
+* Bug fixes, bug fixes, bug fixes, in particular:
+  - The remaining bugs of the lambda lifting pass that is responsible to enable
+    closures and closure iterators need to be fixed.
+  - ``concept`` needs to be refined, a nice name for the feature is not enough.
+  - Destructors need to be refined.
+  - ``static[T]`` needs to be fixed.
+  - Finish the implementation of the 'parallel' statement.
+* ``immediate`` templates and macros will be deprecated as these will soon be
+  completely unnecessary, instead the ``typed`` or ``untyped`` metatypes can
+  be used.
+* More of the standard library should be moved to Nimble packages and what's
+  left should use the features we have for concurrency and parallelism.
+
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- Parameter names are finally properly ``gensym``'ed. This can break
+  templates though that used to rely on the fact that they are not.
+  (Bug #1915.) This means this doesn't compile anymore:
+
+.. code-block:: nim
+
+  template doIt(body: stmt) {.immediate.} =
+    # this used to inject the 'str' parameter:
+    proc res(str: string) =
+      body
+
+  doIt:
+    echo str # Error: undeclared identifier: 'str'
+..
+
+  This used to inject the ``str`` parameter into the scope of the body.
+  Declare the ``doIt`` template as ``immediate, dirty`` to get the old
+  behaviour.
+- Tuple field names are not ignored anymore, this caused too many problems
+  in practice so now the behaviour is as it was for version 0.9.6: If field
+  names exist for the tuple type, they are checked.
+- ``logging.level`` and ``logging.handlers`` are no longer exported.
+  ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter``
+  should be used instead.
+- ``nim idetools`` has been replaced by a separate
+  tool `nimsuggest <0.11.0/nimsuggest.html>`_.
+- *arrow like* operators are not right associative anymore and are required
+  to end with either ``->``, ``~>`` or
+  ``=>``, not just ``>``. Examples of operators still considered arrow like:
+  ``->``, ``==>``, ``+=>``. On the other hand, the following operators are now
+  considered regular operators again: ``|>``, ``-+>``, etc.
+- Typeless parameters are now only allowed in templates and macros. The old
+  way turned out to be too error-prone.
+- The 'addr' and 'type' operators are now parsed as unary function
+  application. This means ``type(x).name`` is now parsed as ``(type(x)).name``
+  and not as ``type((x).name)``. Note that this also affects the AST
+  structure; for immediate macro parameters ``nkCall('addr', 'x')`` is
+  produced instead of ``nkAddr('x')``.
+- ``concept`` is now a keyword and is used instead of ``generic``.
+- The ``inc``, ``dec``, ``+=``, ``-=`` builtins now produce OverflowError
+  exceptions. This means code like the following:
+
+.. code-block:: nim
+  var x = low(T)
+  while x <= high(T):
+    echo x
+    inc x
+
+Needs to be replaced by something like this:
+
+.. code-block:: nim
+  var x = low(T).int
+  while x <= high(T).int:
+    echo x.T
+    inc x
+
+- **Negative indexing for slicing does not work anymore!** Instead
+  of ``a[0.. -1]`` you can
+  use ``a[0.. ^1]``. This also works with accessing a single
+  element ``a[^1]``. Note that we cannot detect this reliably as it is
+  determined at **runtime** whether negative indexing is used!
+  ``a[0.. -1]`` now produces the empty string/sequence.
+- The compiler now warns about code like ``foo +=1`` which uses inconsistent
+  spacing around binary operators. Later versions of the language will parse
+  these as unary operators instead so that ``echo $foo`` finally can do what
+  people expect it to do.
+- ``system.untyped`` and ``system.typed`` have been introduced as aliases
+  for ``expr`` and ``stmt``. The new names capture the semantics much better
+  and most likely  ``expr`` and ``stmt`` will be deprecated in favor of the
+  new names.
+- The ``split`` method in module ``re`` has changed. It now handles the case
+  of matches having a length of 0, and empty strings being yielded from the
+  iterator. A notable change might be that a pattern being matched at the
+  beginning and end of a string, will result in an empty string being produced
+  at the start and the end of the iterator.
+- The compiler and nimsuggest now count columns starting with 1, not 0 for
+  consistency with the rest of the world.
+
+
+Language Additions
+------------------
+
+- For empty ``case object`` branches ``discard`` can finally be used instead
+  of ``nil``.
+- Automatic dereferencing is now done for the first argument of a routine
+  call if overloading resolution produces no match otherwise. This feature
+  has to be enabled with
+  the `experimental <0.11.0/manual.html#pragmas-experimental-pragma>`_ pragma.
+- Objects that do not use inheritance nor ``case`` can be put into ``const``
+  sections. This means that finally this is possible and produces rather
+  nice code:
+
+.. code-block:: nim
+  import tables
+
+  const
+    foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+
+- Ordinary parameters can follow after a varargs parameter. This means the
+  following is finally accepted by the compiler:
+
+.. code-block:: nim
+  template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) =
+    blck
+    echo a, b
+
+  takesBlock 1, 2, "some", 0.90, "random stuff":
+    echo "yay"
+
+- Overloading by 'var T' is now finally possible:
+
+.. code-block:: nim
+  proc varOrConst(x: var int) = echo "var"
+  proc varOrConst(x: int) = echo "const"
+
+  var x: int
+  varOrConst(x) # "var"
+  varOrConst(45) # "const"
+
+- Array and seq indexing can now use the builtin ``^`` operator to access
+  things from backwards: ``a[^1]`` is like Python's ``a[-1]``.
+- A first version of the specification and implementation of the overloading
+  of the assignment operator has arrived!
+- ``system.len`` for strings and sequences now returns 0 for nil.
+
+- A single underscore can now be used to discard values when unpacking tuples:
+
+.. code-block:: nim
+  let (path, _, _) = os.splitFile("path/file.ext")
+
+
+- ``marshal.$$`` and ``marshal.to`` can be executed at compile-time.
+- Interoperability with C++ improved tremendously; C++'s templates and
+  operators can be wrapped directly. See
+  `this <0.11.0/nimc.html#additional-features-importcpp-pragma>`_
+  for more information.
+- ``macros.getType`` can be used to query an AST's type at compile-time. This
+  enables more powerful macros, for instance *currying* can now be done with
+  a macro.
+
+
+Library additions
+-----------------
+
+- ``reversed`` proc added to the ``unicode`` module.
+- Added multipart param to httpclient's ``post`` and ``postContent`` together
+  with a ``newMultipartData`` proc.
+- Added `%*` operator for JSON.
+- The compiler is now available as Nimble package for c2nim.
+- Added ``..^`` and ``..<`` templates to system so that the rather annoying
+  space between ``.. <`` and ``.. ^`` is not necessary anymore.
+- Added ``system.xlen`` for strings and sequences to get back the old ``len``
+  operation that doesn't check for ``nil`` for efficiency.
+- Added sexp.nim to parse and generate sexp.
+
+
+Bugfixes
+--------
+
+- Fixed internal compiler error when using ``char()`` in an echo call
+  (`#1788 <https://github.com/Araq/Nim/issues/1788>`_).
+- Fixed Windows cross-compilation on Linux.
+- Overload resolution now works for types distinguished only by a
+  ``static[int]`` param
+  (`#1056 <https://github.com/Araq/Nim/issues/1056>`_).
+- Other fixes relating to generic types and static params.
+- Fixed some compiler crashes with unnamed tuples
+  (`#1774 <https://github.com/Araq/Nim/issues/1774>`_).
+- Fixed ``channels.tryRecv`` blocking
+  (`#1816 <https://github.com/Araq/Nim/issues/1816>`_).
+- Fixed generic instantiation errors with ``typedesc``
+  (`#419 <https://github.com/Araq/Nim/issues/419>`_).
+- Fixed generic regression where the compiler no longer detected constant
+  expressions properly (`#544 <https://github.com/Araq/Nim/issues/544>`_).
+- Fixed internal error with generic proc using ``static[T]`` in a specific
+  way (`#1049 <https://github.com/Araq/Nim/issues/1049>`_).
+- More fixes relating to generics (`#1820 <https://github.com/Araq/Nim/issues/1820>`_,
+  `#1050 <https://github.com/Araq/Nim/issues/1050>`_,
+  `#1859 <https://github.com/Araq/Nim/issues/1859>`_,
+  `#1858 <https://github.com/Araq/Nim/issues/1858>`_).
+- Fixed httpclient to properly encode queries.
+- Many fixes to the ``uri`` module.
+- Async sockets are now closed on error.
+- Fixes to httpclient's handling of multipart data.
+- Fixed GC segfaults with asynchronous sockets
+  (`#1796 <https://github.com/Araq/Nim/issues/1796>`_).
+- Added more versions to openssl's DLL version list
+  (`076f993 <https://github.com/Araq/Nim/commit/076f993>`_).
+- Fixed shallow copy in iterators being broken
+  (`#1803 <https://github.com/Araq/Nim/issues/1803>`_).
+- ``nil`` can now be inserted into tables with the ``db_sqlite`` module
+  (`#1866 <https://github.com/Araq/Nim/issues/1866>`_).
+- Fixed "Incorrect assembler generated"
+  (`#1907 <https://github.com/Araq/Nim/issues/1907>`_)
+- Fixed "Expression templates that define macros are unusable in some contexts"
+  (`#1903 <https://github.com/Araq/Nim/issues/1903>`_)
+- Fixed "a second level generic subclass causes the compiler to crash"
+  (`#1919 <https://github.com/Araq/Nim/issues/1919>`_)
+- Fixed "nim 0.10.2 generates invalid AsyncHttpClient C code for MSVC "
+  (`#1901 <https://github.com/Araq/Nim/issues/1901>`_)
+- Fixed "1 shl n produces wrong C code"
+  (`#1928 <https://github.com/Araq/Nim/issues/1928>`_)
+- Fixed "Internal error on tuple yield"
+  (`#1838 <https://github.com/Araq/Nim/issues/1838>`_)
+- Fixed "ICE with template"
+  (`#1915 <https://github.com/Araq/Nim/issues/1915>`_)
+- Fixed "include the tool directory in the installer as it is required by koch"
+  (`#1947 <https://github.com/Araq/Nim/issues/1947>`_)
+- Fixed "Can't compile if file location contains spaces on Windows"
+  (`#1955 <https://github.com/Araq/Nim/issues/1955>`_)
+- Fixed "List comprehension macro only supports infix checks as guards"
+  (`#1920 <https://github.com/Araq/Nim/issues/1920>`_)
+- Fixed "wrong field names of compatible tuples in generic types"
+  (`#1910 <https://github.com/Araq/Nim/issues/1910>`_)
+- Fixed "Macros within templates no longer work as expected"
+  (`#1944 <https://github.com/Araq/Nim/issues/1944>`_)
+- Fixed "Compiling for Standalone AVR broken in 0.10.2"
+  (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
+- Fixed "Compiling for Standalone AVR broken in 0.10.2"
+  (`#1964 <https://github.com/Araq/Nim/issues/1964>`_)
+- Fixed "Code generation for mitems with tuple elements"
+  (`#1833 <https://github.com/Araq/Nim/issues/1833>`_)
+- Fixed "httpclient.HttpMethod should not be an enum"
+  (`#1962 <https://github.com/Araq/Nim/issues/1962>`_)
+- Fixed "terminal / eraseScreen() throws an OverflowError"
+  (`#1906 <https://github.com/Araq/Nim/issues/1906>`_)
+- Fixed "setControlCHook(nil) disables registered quit procs"
+  (`#1546 <https://github.com/Araq/Nim/issues/1546>`_)
+- Fixed "Unexpected idetools behaviour"
+  (`#325 <https://github.com/Araq/Nim/issues/325>`_)
+- Fixed "Unused lifted lambda does not compile"
+  (`#1642 <https://github.com/Araq/Nim/issues/1642>`_)
+- Fixed "'low' and 'high' don't work with cstring asguments"
+  (`#2030 <https://github.com/Araq/Nim/issues/2030>`_)
+- Fixed "Converting to int does not round in JS backend"
+  (`#1959 <https://github.com/Araq/Nim/issues/1959>`_)
+- Fixed "Internal error genRecordField 2 when adding region to pointer."
+  (`#2039 <https://github.com/Araq/Nim/issues/2039>`_)
+- Fixed "Macros fail to compile when compiled with --os:standalone"
+  (`#2041 <https://github.com/Araq/Nim/issues/2041>`_)
+- Fixed "Reading from {.compileTime.} variables can cause code generation to fail"
+  (`#2022 <https://github.com/Araq/Nim/issues/2022>`_)
+- Fixed "Passing overloaded symbols to templates fails inside generic procedures"
+  (`#1988 <https://github.com/Araq/Nim/issues/1988>`_)
+- Fixed "Compiling iterator with object assignment in release mode causes "var not init""
+  (`#2023 <https://github.com/Araq/Nim/issues/2023>`_)
+- Fixed "calling a large number of macros doing some computation fails"
+  (`#1989 <https://github.com/Araq/Nim/issues/1989>`_)
+- Fixed "Can't get Koch to install nim under Windows"
+  (`#2061 <https://github.com/Araq/Nim/issues/2061>`_)
+- Fixed "Template with two stmt parameters segfaults compiler"
+  (`#2057 <https://github.com/Araq/Nim/issues/2057>`_)
+- Fixed "`noSideEffect` not affected by `echo`"
+  (`#2011 <https://github.com/Araq/Nim/issues/2011>`_)
+- Fixed "Compiling with the cpp backend ignores --passc"
+  (`#1601 <https://github.com/Araq/Nim/issues/1601>`_)
+- Fixed "Put untyped procedure parameters behind the experimental pragma"
+  (`#1956 <https://github.com/Araq/Nim/issues/1956>`_)
+- Fixed "generic regression"
+  (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
+- Fixed "generic regression"
+  (`#2073 <https://github.com/Araq/Nim/issues/2073>`_)
+- Fixed "Regression in template lookup with generics"
+  (`#2004 <https://github.com/Araq/Nim/issues/2004>`_)
+- Fixed "GC's growObj is wrong for edge cases"
+  (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
+- Fixed "Compiler internal error when creating an array out of a typeclass"
+  (`#1131 <https://github.com/Araq/Nim/issues/1131>`_)
+- Fixed "GC's growObj is wrong for edge cases"
+  (`#2070 <https://github.com/Araq/Nim/issues/2070>`_)
+- Fixed "Invalid Objective-C code generated when calling class method"
+  (`#2068 <https://github.com/Araq/Nim/issues/2068>`_)
+- Fixed "walkDirRec Error"
+  (`#2116 <https://github.com/Araq/Nim/issues/2116>`_)
+- Fixed "Typo in code causes compiler SIGSEGV in evalAtCompileTime"
+  (`#2113 <https://github.com/Araq/Nim/issues/2113>`_)
+- Fixed "Regression on exportc"
+  (`#2118 <https://github.com/Araq/Nim/issues/2118>`_)
+- Fixed "Error message"
+  (`#2102 <https://github.com/Araq/Nim/issues/2102>`_)
+- Fixed "hint[path] = off not working in nim.cfg"
+  (`#2103 <https://github.com/Araq/Nim/issues/2103>`_)
+- Fixed "compiler crashes when getting a tuple from a sequence of generic tuples"
+  (`#2121 <https://github.com/Araq/Nim/issues/2121>`_)
+- Fixed "nim check hangs with when"
+  (`#2123 <https://github.com/Araq/Nim/issues/2123>`_)
+- Fixed "static[T] param in nested type resolve/caching issue"
+  (`#2125 <https://github.com/Araq/Nim/issues/2125>`_)
+- Fixed "repr should display ``\0``"
+  (`#2124 <https://github.com/Araq/Nim/issues/2124>`_)
+- Fixed "'nim check' never ends in case of recursive dependency "
+  (`#2051 <https://github.com/Araq/Nim/issues/2051>`_)
+- Fixed "From macros: Error: unhandled exception: sons is not accessible"
+  (`#2167 <https://github.com/Araq/Nim/issues/2167>`_)
+- Fixed "`fieldPairs` doesn't work inside templates"
+  (`#1902 <https://github.com/Araq/Nim/issues/1902>`_)
+- Fixed "fields iterator misbehavior on break statement"
+  (`#2134 <https://github.com/Araq/Nim/issues/2134>`_)
+- Fixed "Fix for compiler not building anymore since #c3244ef1ff"
+  (`#2193 <https://github.com/Araq/Nim/issues/2193>`_)
+- Fixed "JSON parser fails in cpp output mode"
+  (`#2199 <https://github.com/Araq/Nim/issues/2199>`_)
+- Fixed "macros.getType mishandles void return"
+  (`#2211 <https://github.com/Araq/Nim/issues/2211>`_)
+- Fixed "Regression involving templates instantiated within generics"
+  (`#2215 <https://github.com/Araq/Nim/issues/2215>`_)
+- Fixed ""Error: invalid type" for 'not nil' on generic type."
+  (`#2216 <https://github.com/Araq/Nim/issues/2216>`_)
+- Fixed "--threads:on breaks async"
+  (`#2074 <https://github.com/Araq/Nim/issues/2074>`_)
+- Fixed "Type mismatch not always caught, can generate bad code for C backend."
+  (`#2169 <https://github.com/Araq/Nim/issues/2169>`_)
+- Fixed "Failed C compilation when storing proc to own type in object"
+  (`#2233 <https://github.com/Araq/Nim/issues/2233>`_)
+- Fixed "Unknown line/column number in constant declaration type conversion error"
+  (`#2252 <https://github.com/Araq/Nim/issues/2252>`_)
+- Fixed "Adding {.compile.} fails if nimcache already exists."
+  (`#2247 <https://github.com/Araq/Nim/issues/2247>`_)
+- Fixed "Two different type names generated for a single type (C backend)"
+  (`#2250 <https://github.com/Araq/Nim/issues/2250>`_)
+- Fixed "Ambigous call when it should not be"
+  (`#2229 <https://github.com/Araq/Nim/issues/2229>`_)
+- Fixed "Make sure we can load root urls"
+  (`#2227 <https://github.com/Araq/Nim/issues/2227>`_)
+- Fixed "Failure to slice a string with an int subrange type"
+  (`#794 <https://github.com/Araq/Nim/issues/794>`_)
+- Fixed "documentation error"
+  (`#2205 <https://github.com/Araq/Nim/issues/2205>`_)
+- Fixed "Code growth when using `const`"
+  (`#1940 <https://github.com/Araq/Nim/issues/1940>`_)
+- Fixed "Instances of generic types confuse overload resolution"
+  (`#2220 <https://github.com/Araq/Nim/issues/2220>`_)
+- Fixed "Compiler error when initializing sdl2's EventType"
+  (`#2316 <https://github.com/Araq/Nim/issues/2316>`_)
+- Fixed "Parallel disjoint checking can't handle `<`, `items`, or arrays"
+  (`#2287 <https://github.com/Araq/Nim/issues/2287>`_)
+- Fixed "Strings aren't copied in parallel loop"
+  (`#2286 <https://github.com/Araq/Nim/issues/2286>`_)
+- Fixed "JavaScript compiler crash with tables"
+  (`#2298 <https://github.com/Araq/Nim/issues/2298>`_)
+- Fixed "Range checker too restrictive"
+  (`#1845 <https://github.com/Araq/Nim/issues/1845>`_)
+- Fixed "Failure to slice a string with an int subrange type"
+  (`#794 <https://github.com/Araq/Nim/issues/794>`_)
+- Fixed "Remind user when compiling in debug mode"
+  (`#1868 <https://github.com/Araq/Nim/issues/1868>`_)
+- Fixed "Compiler user guide has jumbled options/commands."
+  (`#1819 <https://github.com/Araq/Nim/issues/1819>`_)
+- Fixed "using `method`: 1 in a objects constructor fails when compiling"
+  (`#1791 <https://github.com/Araq/Nim/issues/1791>`_)
+
+
+2014-12-29 Version 0.10.2 released
+==================================
+
+This release marks the completion of a very important change to the project:
+the official renaming from Nimrod to Nim. Version 0.10.2 contains many language
+changes, some of which may break your existing code. For your convenience, we
+added a new tool called `nimfix <nimfix.html>`_ that will help you convert your
+existing projects so that it works with the latest version of the compiler.
+
+Progress towards version 1.0
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although Nim is still pre-1.0, we were able to keep the number of breaking
+changes to a minimum so far. Starting with version 1.0, we will not introduce
+any breaking changes between major release versions.
+One of Nim's goals is to ensure that the compiler is as efficient as possible.
+Take a look at the
+`latest benchmarks <https://github.com/logicchains/LPATHBench/blob/master/writeup.md>`_,
+which show that Nim is consistently near
+the top and already nearly as fast as C and C++. Recent developments, such as
+the new ``asyncdispatch`` module will allow you to write efficient web server
+applications using non-blocking code. Nim now also has a built-in thread pool
+for lightweight threading through the use of ``spawn``.
+
+The unpopular "T" and "P" prefixes on types have been deprecated. Nim also
+became more expressive by weakening the distinction between statements and
+expressions. We also added a new and searchable forum, a new website, and our
+documentation generator ``docgen`` has seen major improvements. Many thanks to
+Nick Greenfield for the much more beautiful documentation!
+
+
+
+What's left to be done
+~~~~~~~~~~~~~~~~~~~~~~
+
+The 1.0 release is actually very close. Apart from bug fixes, there are
+two major features missing or incomplete:
+
+* ``static[T]`` needs to be defined precisely and the bugs in the
+  implementation need to be fixed.
+* Overloading of the assignment operator is required for some generic
+  containers and needs to be implemented.
+
+This means that fancy matrix libraries will finally start to work, which used
+to be a major point of pain in the language.
+
+
+Nimble and other Nim tools
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Outside of the language and the compiler itself many Nim tools have seen
+considerable improvements.
+
+Babel the Nim package manager has been renamed to Nimble. Nimble's purpose
+is the installation of packages containing libraries and/or applications
+written in Nim.
+Even though Nimble is still very young it already is very
+functional. It can install packages by name, it does so by accessing a
+packages repository which is hosted on a Github repo. Packages can also be
+installed via a Git repo URL or Mercurial repo URL. The package repository
+is searchable through Nimble. Anyone is free to add their own packages to
+the package repository by forking the
+`nim-lang/packages <https://github.com/nim-lang/packages>`_ repo and creating
+a pull request. Nimble is fully cross-platform and should be fully functional
+on all major operating systems.
+It is of course completely written in Nim.
+
+Changelog
+~~~~~~~~~
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- **The language has been renamed from Nimrod to Nim.** The name of the
+  compiler changed from ``nimrod`` to ``nim`` too.
+- ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to
+  prevent name conflicts with the new type ``FileHandle``.
+- Comments are now not part of the AST anymore, as such you cannot use them
+  in place of ``discard``.
+- Large parts of the stdlib got rid of the T/P type prefixes. Instead most
+  types now simply start with an uppercased letter. The
+  so called "partial case sensitivity" rule is now active allowing for code
+  like ``var foo: Foo`` in more contexts.
+- String case (or any non-ordinal case) statements
+  without 'else' are deprecated.
+- Recursive tuple types are not allowed anymore. Use ``object`` instead.
+- The PEGS module returns ``nil`` instead of ``""`` when an optional capture
+  fails to match.
+- The re module returns ``nil`` instead of ``""`` when an optional capture
+  fails to match.
+- The "symmetric set difference" operator (``-+-``) never worked and has been
+  removed.
+- ``defer`` is a keyword now.
+- ``func`` is a keyword now.
+- The ``using`` language feature now needs to be activated via the new
+  ``{.experimental.}`` pragma that enables experimental language features.
+- Destructors are now officially *experimental*.
+- Standalone ``except`` and ``finally`` statements are deprecated now.
+  The standalone ``finally`` can be replaced with ``defer``,
+  standalone ``except`` requires an explicit ``try``.
+- Operators ending in ``>`` are considered as "arrow like" and have their
+  own priority level and are right associative. This means that
+  the ``=>`` and ``->`` operators from the `future <future.html>`_ module
+  work better.
+- Field names in tuples are now ignored for type comparisons. This allows
+  for greater interoperability between different modules.
+- Statement lists are not converted to an implicit ``do`` block anymore. This
+  means the confusing ``nnkDo`` nodes when working with macros are gone for
+  good.
+
+
+Language Additions
+------------------
+
+- The new concurrency model has been implemented including ``locks`` sections,
+  lock levels and object field ``guards``.
+- The ``parallel`` statement has been implemented.
+- ``deepCopy`` has been added to the language.
+- The builtin ``procCall`` can be used to get ``super``-like functionality
+  for multi methods.
+- There is a new pragma ``{.experimental.}`` that enables experimental
+  language features per module, or you can enable these features on a global
+  level with the ``--experimental`` command line option.
+
+
+Compiler Additions
+------------------
+
+- The compiler now supports *mixed* Objective C / C++ / C code generation:
+  The modules that use ``importCpp`` or ``importObjc`` are compiled to C++
+  or Objective C code, any other module is compiled to C code. This
+  improves interoperability.
+- There is a new ``parallel`` statement for safe fork&join parallel computing.
+- ``guard`` and ``lock`` pragmas have been implemented to support safer
+  concurrent programming.
+- The following procs are now available at compile-time::
+
+    math.sqrt, math.ln, math.log10, math.log2, math.exp, math.round,
+    math.arccos, math.arcsin, math.arctan, math.arctan2, math.cos,
+    math.cosh, math.hypot, math.sinh, math.sin, math.tan, math.tanh,
+    math.pow, math.trunc, math.floor, math.ceil, math.fmod,
+    os.getEnv, os.existsEnv, os.dirExists, os.fileExists,
+    system.writeFile
+
+- Two backticks now produce a single backtick within an ``emit`` or ``asm``
+  statement.
+- There is a new tool, `nimfix <nimfix.html>`_ to help you in updating your
+  code from Nimrod to Nim.
+- The compiler's output has been prettified.
+
+Library Additions
+-----------------
+
+- Added module ``fenv`` to control the handling of floating-point rounding and
+  exceptions (overflow, division by zero, etc.).
+- ``system.setupForeignThreadGc`` can be used for better interaction with
+  foreign libraries that create threads and run a Nim callback from these
+  foreign threads.
+- List comprehensions have been implemented as a macro in the ``future``
+  module.
+- The new Async module (``asyncnet``) now supports SSL.
+- The ``smtp`` module now has an async implementation.
+- Added module ``asyncfile`` which implements asynchronous file reading
+  and writing.
+- ``osproc.kill`` has been added.
+- ``asyncnet`` and ``asynchttpserver`` now support ``SO_REUSEADDR``.
+
+Bugfixes
+--------
+
+- ``nil`` and ``NULL`` are now preserved between Nim and databases in the
+  ``db_*`` modules.
+- Fixed issue with OS module in non-unicode mode on Windows.
+- Fixed issue with ``x.low``
+  (`#1366 <https://github.com/Araq/Nim/issues/1366>`_).
+- Fixed tuple unpacking issue inside closure iterators
+  (`#1067 <https://github.com/Araq/Nim/issues/1067>`_).
+- Fixed ENDB compilation issues.
+- Many ``asynchttpserver`` fixes.
+- Macros can now keep global state across macro calls
+  (`#903 <https://github.com/Araq/Nim/issues/903>`_).
+- ``osproc`` fixes on Windows.
+- ``osproc.terminate`` fixed.
+- Improvements to exception handling in async procedures.
+  (`#1487 <https://github.com/Araq/Nim/issues/1487>`_).
+- ``try`` now works at compile-time.
+- Fixes ``T = ref T`` to be an illegal recursive type.
+- Self imports are now disallowed.
+- Improved effect inference.
+- Fixes for the ``math`` module on Windows.
+- User defined pragmas will now work for generics that have
+  been instantiated in different modules.
+- Fixed queue exhaustion bug.
+- Many, many more.
+
+2014-12-09 New website design!
+==============================
+
+A brand new website including an improved forum is now live.
+All thanks go to Philip Witte and
+Dominik Picheta, Philip Witte for the design of the website (together with
+the logo) as well as the HTML and CSS code for his template, and Dominik Picheta
+for integrating Philip's design with Nim's forum. We're sure you will
+agree that Philip's design is beautiful.
+
+
+
+2014-10-19 Version 0.9.6 released
+=================================
+
+**Note: 0.9.6 is the last release of Nimrod. The language is being renamed to
+Nim. Nim slightly breaks compatibility.**
+
+This is a maintenance release. The upcoming 0.10.0 release has
+the new features and exciting developments.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- ``spawn`` now uses an elaborate self-adapting thread pool and as such
+  has been moved into its own module. So to use it, you now have to import
+  ``threadpool``.
+- The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is
+  now considered for implicit early binding.
+- ``c2nim`` moved into its own repository and is now a Babel package.
+- ``pas2nim`` moved into its own repository and is now a Babel package.
+- ``system.$`` for floating point types now produces a human friendly string
+  representation.
+- ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour
+  of the new ``TUri`` type in the ``uri`` module.
+- The ``destructor`` pragma has been deprecated. Use the ``override`` pragma
+  instead. The destructor's name has to be ``destroy`` now.
+- ``lambda`` is not a keyword anymore.
+- **system.defined has been split into system.defined and system.declared**.
+  You have to use ``--symbol`` to declare new conditional symbols that can be
+  set via ``--define``.
+- ``--threadanalysis:on`` is now the default. To make your program compile
+  you can disable it but this is only a temporary solution as this option
+  will disappear soon!
+
+
+Compiler improvements
+---------------------
+
+- Multi method dispatching performance has been improved by a factor of 10x for
+  pathological cases.
+
+
+Language Additions
+------------------
+
+- This version introduces the ``deprecated`` pragma statement that is used
+  to handle the upcoming massive amount of symbol renames.
+- ``spawn`` can now wrap proc that has a return value. It then returns a data
+  flow variable of the wrapped return type.
+
+
+Library Additions
+-----------------
+
+- Added module ``cpuinfo``.
+- Added module ``threadpool``.
+- ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
+- Added ``algorithm.reversed``
+- Added ``uri.combine`` and ``uri.parseUri``.
+- Some sockets procedures now support a ``SafeDisconn`` flag which causes
+  them to handle disconnection errors and not raise them.
+
+
+2014-04-21 Version 0.9.4 released
+=================================
+
+The Nimrod development community is proud to announce the release of version
+0.9.4 of the Nimrod compiler and tools. **Note: This release has to be
+considered beta quality! Lots of new features have been implemented but
+unfortunately some do not fulfill our quality standards yet.**
+
+Prebuilt binaries and instructions for building from source are available
+on the `download page <download.html>`_.
+
+This release includes about
+`1400 changes <https://github.com/Araq/Nimrod/compare/v0.9.2...v0.9.4>`_
+in total including various bug
+fixes, new languages features and standard library additions and improvements.
+This release brings with it support for user-defined type classes, a brand
+new VM for executing Nimrod code at compile-time and new symbol binding
+rules for clean templates.
+
+It also introduces support for the brand new
+`Babel package manager <https://github.com/nimrod-code/babel>`_ which
+has itself seen its first release recently. Many of the wrappers that were
+present in the standard library have been moved to separate repositories
+and should now be installed using Babel.
+
+Apart from that a new **experimental** Asynchronous IO API has been added via
+the ``asyncdispatch`` and ``asyncnet`` modules. The ``net`` and ``rawsockets``
+modules have also been added and they will likely replace the sockets
+module in the next release. The Asynchronous IO API has been designed to
+take advantage of Linux's epoll and Windows' IOCP APIs, support for BSD's
+kqueue has not been implemented yet but will be in the future.
+The Asynchronous IO API provides both
+a callback interface and an interface which allows you to write code as you
+would if you were writing synchronous code. The latter is done through
+the use of an ``await`` macro which behaves similar to C#'s await. The
+following is a very simple chat server demonstrating Nimrod's new async
+capabilities.
+
+.. code-block::nim
+  import asyncnet, asyncdispatch
+
+  var clients: seq[PAsyncSocket] = @[]
+
+  proc processClient(client: PAsyncSocket) {.async.} =
+    while true:
+      let line = await client.recvLine()
+      for c in clients:
+        await c.send(line & "\c\L")
+
+  proc serve() {.async.} =
+    var server = newAsyncSocket()
+    server.bindAddr(TPort(12345))
+    server.listen()
+
+    while true:
+      let client = await server.accept()
+      clients.add client
+
+      processClient(client)
+
+  serve()
+  runForever()
+
+
+Note that this feature has been implemented with Nimrod's macro system and so
+``await`` and ``async`` are no keywords.
+
+Syntactic sugar for anonymous procedures has also been introduced. It too has
+been implemented as a macro. The following shows some simple usage of the new
+syntax:
+
+.. code-block::nim
+  import future
+
+  var s = @[1, 2, 3, 4, 5]
+  echo(s.map((x: int) => x * 5))
+
+A list of changes follows, for a comprehensive list of changes take a look
+`here <https://github.com/Araq/Nimrod/compare/v0.9.2...v0.9.4>`_.
+
+Library Additions
+-----------------
+
+- Added ``macros.genSym`` builtin for AST generation.
+- Added ``macros.newLit`` procs for easier AST generation.
+- Added module ``logging``.
+- Added module ``asyncdispatch``.
+- Added module ``asyncnet``.
+- Added module ``net``.
+- Added module ``rawsockets``.
+- Added module ``selectors``.
+- Added module ``asynchttpserver``.
+- Added support for the new asynchronous IO in the ``httpclient`` module.
+- Added a Python-inspired ``future`` module that features upcoming additions
+  to the ``system`` module.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- The scoping rules for the ``if`` statement changed for better interaction
+  with the new syntactic construct ``(;)``.
+- ``OSError`` family of procedures has been deprecated. Procedures with the same
+  name but which take different parameters have been introduced. These procs now
+  require an error code to be passed to them. This error code can be retrieved
+  using the new ``OSLastError`` proc.
+- ``os.parentDir`` now returns "" if there is no parent dir.
+- In CGI scripts stacktraces are shown to the user only
+  if ``cgi.setStackTraceStdout`` is used.
+- The symbol binding rules for clean templates changed: ``bind`` for any
+  symbol that's not a parameter is now the default. ``mixin`` can be used
+  to require instantiation scope for a symbol.
+- ``quoteIfContainsWhite`` now escapes argument in such way that it can be safely
+  passed to shell, instead of just adding double quotes.
+- ``macros.dumpTree`` and ``macros.dumpLisp`` have been made ``immediate``,
+  ``dumpTreeImm`` and ``dumpLispImm`` are now deprecated.
+- The ``nil`` statement has been deprecated, use an empty ``discard`` instead.
+- ``sockets.select`` now prunes sockets that are **not** ready from the list
+  of sockets given to it.
+- The ``noStackFrame`` pragma has been renamed to ``asmNoStackFrame`` to
+  ensure you only use it when you know what you're doing.
+- Many of the wrappers that were present in the standard library have been
+  moved to separate repositories and should now be installed using Babel.
+
+
+Compiler Additions
+------------------
+
+- The compiler can now warn about "uninitialized" variables. (There are no
+  real uninitialized variables in Nimrod as they are initialized to binary
+  zero). Activate via ``{.warning[Uninit]:on.}``.
+- The compiler now enforces the ``not nil`` constraint.
+- The compiler now supports a ``codegenDecl`` pragma for even more control
+  over the generated code.
+- The compiler now supports a ``computedGoto`` pragma to support very fast
+  dispatching for interpreters and the like.
+- The old evaluation engine has been replaced by a proper register based
+  virtual machine. This fixes numerous bugs for ``nimrod i`` and for macro
+  evaluation.
+- ``--gc:none`` produces warnings when code uses the GC.
+- A ``union`` pragma for better C interoperability is now supported.
+- A ``packed`` pragma to control the memory packing/alignment of fields in
+  an object.
+- Arrays can be annotated to be ``unchecked`` for easier low level
+  manipulations of memory.
+- Support for the new Babel package manager.
+
+
+Language Additions
+------------------
+
+- Arrays can now be declared with a single integer literal ``N`` instead of a
+  range; the range is then ``0..N-1``.
+- Added ``requiresInit`` pragma to enforce explicit initialization.
+- Exported templates are allowed to access hidden fields.
+- The ``using statement`` enables you to more easily author domain-specific
+  languages and libraries providing OOP-like syntactic sugar.
+- Added the possibility to override various dot operators in order to handle
+  calls to missing procs and reads from undeclared fields at compile-time.
+- The overload resolution now supports ``static[T]`` params that must be
+  evaluable at compile-time.
+- Support for user-defined type classes has been added.
+- The *command syntax* is supported in a lot more contexts.
+- Anonymous iterators are now supported and iterators can capture variables
+  of an outer proc.
+- The experimental ``strongSpaces`` parsing mode has been implemented.
+- You can annotate pointer types with regions for increased type safety.
+- Added support for the builtin ``spawn`` for easy thread pool usage.
+
+
+Tools improvements
+------------------
+
+- c2nim can deal with a subset of C++. Use the ``--cpp`` command line option
+  to activate.
+
+
+2014-02-11 Nimrod Featured in Dr. Dobb's Journal
+================================================
+
+Nimrod has been `featured<http://www.drdobbs.com/open-source/nimrod-a-new-systems-programming-languag/240165321>`_
+as the cover story in the February 2014 issue of Dr. Dobb's Journal.
+
+
+2014-01-15 Andreas Rumpf's talk on Nimrod at Strange Loop 2013 is now online
+============================================================================
+
+Andreas Rumpf presented *Nimrod: A New Approach to Metaprogramming* at
+`Strange Loop 2013<https://thestrangeloop.com/sessions/nimrod-a-new-approach-to-meta-programming>`_.
+The `video and slides<http://www.infoq.com/presentations/nimrod>`_
+of the talk are now available.
+
+
+2013-05-20 New website design!
+==============================
+
+A brand new website is now live. All thanks go to Philip Witte and
+Dominik Picheta, Philip Witte for the design of the website (together with
+the logo) as well as the HTML and CSS code for his template, and Dominik Picheta
+for integrating Philip's design with the ``nimweb`` utility. We're sure you will
+agree that Philip's design is beautiful.
+
+
+2013-05-20 Version 0.9.2 released
+=================================
+
+We are pleased to announce that version 0.9.2 of the Nimrod compiler has been
+released. This release has attracted by far the most contributions in comparison
+to any other release.
+
+This release brings with it many new features and bug fixes, a list of which
+can be seen later. One of the major new features is the effect system together
+with exception tracking which allows for checked exceptions and more,
+for further details check out the `manual <manual.html#effect-system>`_.
+Another major new feature is the introduction of statement list expressions,
+more details on these can be found `here <manual.html#statement-list-expression>`_.
+The ability to exclude symbols from modules has also been
+implemented, this feature can be used like so: ``import module except symbol``.
+
+Thanks to all `contributors <https://github.com/Araq/Nimrod/contributors>`_!
+
+Bugfixes
+--------
+
+- The old GC never collected cycles correctly. Fixed but it can cause
+  performance regressions. However you can deactivate the cycle collector
+  with ``GC_disableMarkAndSweep`` and run it explicitly at an appropriate time
+  or not at all. There is also a new GC you can activate
+  with ``--gc:markAndSweep`` which does not have this problem but is slower in
+  general and has no realtime guarantees.
+- ``cast`` for floating point types now does the bitcast as specified in the
+  manual. This breaks code that erroneously uses ``cast`` to convert different
+  floating point values.
+- SCGI module's performance has been improved greatly, it will no longer block
+  on many concurrent requests.
+- In total fixed over 70 github issues and merged over 60 pull requests.
+
+
+Library Additions
+-----------------
+
+- There is a new experimental mark&sweep GC which can be faster (or much
+  slower) than the default GC. Enable with ``--gc:markAndSweep``.
+- Added ``system.onRaise`` to support a condition system.
+- Added ``system.locals`` that provides access to a proc's locals.
+- Added ``macros.quote`` for AST quasi-quoting.
+- Added ``system.unsafeNew`` to support hacky variable length objects.
+- ``system.fields`` and ``system.fieldPairs`` support ``object`` too; they
+  used to only support tuples.
+- Added ``system.CurrentSourcePath`` returning the full file-system path of
+  the current source file.
+- The ``macros`` module now contains lots of useful helpers for building up
+  abstract syntax trees.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- ``shared`` is a keyword now.
+- Deprecated ``sockets.recvLine`` and ``asyncio.recvLine``, added
+  ``readLine`` instead.
+- The way indentation is handled in the parser changed significantly. However,
+  this affects very little (if any) real world code.
+- The expression/statement unification has been implemented. Again this
+  only affects edge cases and no known real world code.
+- Changed the async interface of the ``scgi`` module.
+- WideStrings are now garbage collected like other string types.
+
+
+Compiler Additions
+------------------
+
+- The ``doc2`` command does not generate output for the whole project anymore.
+  Use the new ``--project`` switch to enable this behaviour.
+- The compiler can now warn about shadowed local variables. However, this needs
+  to be turned on explicitly via ``--warning[ShadowIdent]:on``.
+- The compiler now supports almost every pragma in a ``push`` pragma.
+- Generic converters have been implemented.
+- Added a **highly experimental** ``noforward`` pragma enabling a special
+  compilation mode that largely eliminates the need for forward declarations.
+
+Language Additions
+------------------
+
+- ``case expressions`` are now supported.
+- Table constructors now mimic more closely the syntax of the ``case``
+  statement.
+- Nimrod can now infer the return type of a proc from its body.
+- Added a ``mixin`` declaration to affect symbol binding rules in generics.
+- Exception tracking has been added and the ``doc2`` command annotates possible
+  exceptions for you.
+- User defined effects ("tags") tracking has been added and the ``doc2``
+  command annotates possible tags for you.
+- Types can be annotated with the new syntax ``not nil`` to explicitly state
+  that ``nil`` is not allowed. However currently the compiler performs no
+  advanced static checking for this; for now it's merely for documentation
+  purposes.
+- An ``export`` statement has been added to the language: It can be used for
+  symbol forwarding so client modules don't have to import a module's
+  dependencies explicitly.
+- Overloading based on ASTs has been implemented.
+- Generics are now supported for multi methods.
+- Objects can be initialized via an *object constructor expression*.
+- There is a new syntactic construct ``(;)`` unifying expressions and
+  statements.
+- You can now use ``from module import nil`` if you want to import the module
+  but want to enforce fully qualified access to every symbol in ``module``.
+
+
+Notes for the future
+--------------------
+
+- The scope rules of ``if`` statements will change in 0.9.4. This affects the
+  ``=~`` pegs/re templates.
+- The ``sockets`` module will become a low-level wrapper of OS-specific socket
+  functions. All the high-level features of the current ``sockets`` module
+  will be moved to a ``network`` module.
+
+
+2012-09-23 Version 0.9.0 released
+=================================
+
+Summary
+-------
+
+* Unsigned integers have been added.
+* The integer type promotion rules changed.
+* The template and macro system evolved.
+* Closures have been implemented.
+* Term rewriting macros have been implemented.
+* First steps to unify expressions and statements have been taken.
+* Symbol lookup rules in generics have become stricter to catch more errors.
+
+
+Bugfixes
+--------
+
+- Fixed a bug where the compiler would "optimize away" valid constant parts of
+  a string concatenation.
+- Fixed a bug concerning implicit type conversions in ``case`` statements.
+- Fixed a serious code generation bug that caused ``algorithm.sort`` to
+  produce segmentation faults.
+- Fixed ambiguity in recvLine which meant that receiving ``\r\L`` was
+  indistinguishable from disconnections.
+- Many more bugfixes, too many to list them all.
+
+
+Library Additions
+-----------------
+
+- Added the (already existing) module ``htmlgen`` to the documentation.
+- Added the (already existing) module ``cookies`` to the documentation.
+- Added ``system.shallow`` that can be used to speed up string and sequence
+  assignments.
+- Added ``system.eval`` that can execute an anonymous block of code at
+  compile time as if was a macro.
+- Added ``system.staticExec`` and ``system.gorge`` for compile-time execution
+  of external programs.
+- Added ``system.staticRead`` as a synonym for ``system.slurp``.
+- Added ``macros.emit`` that can emit an arbitrary computed string as nimrod
+  code during compilation.
+- Added ``strutils.parseEnum``.
+- Added ``json.%`` constructor operator.
+- The stdlib can now be avoided to a point where C code generation for 16bit
+  micro controllers is feasible.
+- Added module ``oids``.
+- Added module ``endians``.
+- Added a new OpenGL wrapper that supports OpenGL up to version 4.2.
+- Added a wrapper for ``libsvm``.
+- Added a wrapper for ``mongodb``.
+- Added ``terminal.isatty``.
+- Added an overload for ``system.items`` that can be used to iterate over the
+  values of an enum.
+- Added ``system.TInteger`` and ``system.TNumber`` type classes matching
+  any of the corresponding types available in Nimrod.
+- Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
+- Added ``strutils.continuesWith``.
+- Added ``system.getStackTrace``.
+- Added ``system.||`` for parallel ``for`` loop support.
+- The GC supports (soft) realtime systems via ``GC_setMaxPause``
+  and ``GC_step`` procs.
+- The sockets module now supports ssl through the OpenSSL library, ``recvLine``
+  is now much more efficient thanks to the newly implemented sockets buffering.
+- The httpclient module now supports ssl/tls.
+- Added ``times.format`` as well as many other utility functions
+  for managing time.
+- Added ``system.@`` for converting an ``openarray`` to a ``seq`` (it used to
+  only support fixed length arrays).
+- Added ``system.compiles`` which can be used to check whether a type supports
+  some operation.
+- Added ``strutils.format``, ``subexes.format`` which use the
+  new ``varargs`` type.
+- Added module ``fsmonitor``.
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- On Windows filenames and paths are supposed to be in UTF-8.
+  The ``system``, ``os``, ``osproc`` and ``memfiles`` modules use the wide
+  string versions of the WinAPI. Use the ``-d:useWinAnsi`` switch to revert
+  back to the old behaviour which uses the Ansi string versions.
+- ``static``, ``do``, ``interface`` and ``mixin`` are now keywords.
+- Templates now participate in overloading resolution which can break code that
+  uses templates in subtle ways. Use the new ``immediate`` pragma for templates
+  to get a template of old behaviour.
+- There is now a proper distinction in the type system between ``expr`` and
+  ``PNimrodNode`` which unfortunately breaks the old macro system.
+- ``pegs.@`` has been renamed to ``pegs.!*`` and ``pegs.@@`` has been renamed
+  to ``pegs.!*\`` as ``@`` operators now have different precedence.
+- The type ``proc`` (without any params or return type) is now considered a
+  type class matching all proc types. Use ``proc ()`` to get the old meaning
+  denoting a proc expecing no arguments and returing no value.
+- Deprecated ``system.GC_setStrategy``.
+- ``re.findAll`` and ``pegs.findAll`` don't return *captures* anymore but
+  matching *substrings*.
+- RTTI and thus the ``marshall`` module don't contain the proper field names
+  of tuples anymore. This had to be changed as the old behaviour never
+  produced consistent results.
+- Deprecated the ``ssl`` module.
+- Deprecated ``nimrod pretty`` as it never worked good enough and has some
+  inherent problems.
+- The integer promotion rules changed; the compiler is now less picky in some
+  situations and more picky in other situations: In particular implicit
+  conversions from ``int`` to ``int32`` are now forbidden.
+- ``system.byte`` is now an alias for ``uint8``; it used to be an alias
+  to ``int8``.
+- ``bind`` expressions in templates are not properly supported anymore. Use
+  the declarative ``bind`` statement instead.
+- The default calling convention for a procedural **type** is now ``closure``,
+  for procs it remains ``nimcall`` (which is compatible to ``closure``).
+  Activate the warning ``ImplicitClosure`` to make the compiler list the
+  occurrences of proc types which are affected.
+- The Nimrod type system now distinguishes ``openarray`` from ``varargs``.
+- Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old
+  behaviour.
+- Objects that have no ancestor are now implicitly ``final``. Use
+  the ``inheritable`` pragma to introduce new object roots apart
+  from ``TObject``.
+- Macros now receive parameters like templates do; use the ``callsite`` builtin
+  to gain access to the invocation AST.
+- Symbol lookup rules in generics have become stricter to catch more errors.
+
+
+Compiler Additions
+------------------
+
+- Win64 is now an officially supported target.
+- The Nimrod compiler works on BSD again, but has some issues
+  as ``os.getAppFilename`` and ``os.getAppDir`` cannot work reliably on BSD.
+- The compiler can detect and evaluate calls that can be evaluated at compile
+  time for optimization purposes with the ``--implicitStatic`` command line
+  option or pragma.
+- The compiler now generates marker procs that the GC can use instead of RTTI.
+  This speeds up the GC quite a bit.
+- The compiler now includes a new advanced documentation generator
+  via the ``doc2`` command. This new generator uses all of the semantic passes
+  of the compiler and can thus generate documentation for symbols hiding in
+  macros.
+- The compiler now supports the ``dynlib`` pragma for variables.
+- The compiler now supports ``bycopy`` and ``byref`` pragmas that affect how
+  objects/tuples are passed.
+- The embedded profiler became a stack trace profiler and has been documented.
+
+
+Language Additions
+------------------
+
+- Added explicit ``static`` sections for enforced compile time evaluation.
+- Added an alternative notation for lambdas with ``do``.
+- ``addr`` is now treated like a prefix operator syntactically.
+- Added ``global`` pragma that can be used to introduce new global variables
+  from within procs.
+- ``when`` expressions are now allowed just like ``if`` expressions.
+- The precedence for operators starting with ``@`` is different now
+  allowing for *sigil-like* operators.
+- Stand-alone ``finally`` and ``except`` blocks are now supported.
+- Macros and templates can now be invoked as pragmas.
+- The apostrophe in type suffixes for numerical literals is now optional.
+- Unsigned integer types have been added.
+- The integer promotion rules changed.
+- Nimrod now tracks proper intervals for ``range`` over some built-in operators.
+- In parameter lists a semicolon instead of a comma can be used to improve
+  readability: ``proc divmod(a, b: int; resA, resB: var int)``.
+- A semicolon can now be used to have multiple simple statements on a single
+  line: ``inc i; inc j``.
+- ``bind`` supports overloaded symbols and operators.
+- A ``distinct`` type can now borrow from generic procs.
+- Added the pragmas ``gensym``, ``inject`` and ``dirty`` for hygiene
+  in templates.
+- Comments can be continued with a backslash continuation character so that
+  comment pieces don't have to align on the same column.
+- Enums can be annotated with ``pure`` so that their field names do not pollute
+  the current scope.
+- A proc body can consist of an expression that has a type. This is rewritten
+  to ``result = expression`` then.
+- Term rewriting macros (see `trmacros <http://nimrod-code.org/trmacros.html>`_)
+  have been implemented but are still in alpha.
+
+
+2012-02-09 Version 0.8.14 released
+==================================
+
+Version 0.8.14 has been released!
+
+Bugfixes
+--------
+
+- Fixed a serious memory corruption concerning message passing.
+- Fixed a serious bug concerning different instantiations of a generic proc.
+- Fixed a newly introduced bug where a wrong ``EIO`` exception was raised for
+  the end of file for text files that do not end with a newline.
+- Bugfix c2nim, c2pas: the ``--out`` option has never worked properly.
+- Bugfix: forwarding of generic procs never worked.
+- Some more bugfixes for macros and compile-time evaluation.
+- The GC now takes into account interior pointers on the stack which may be
+  introduced by aggressive C optimizers.
+- Nimrod's native allocator/GC now works on PowerPC.
+- Lots of other bugfixes: Too many to list them all.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- Removed deprecated ``os.AppendFileExt``, ``os.executeShellCommand``,
+  ``os.iterOverEnvironment``, ``os.pcDirectory``, ``os.pcLinkToDirectory``,
+  ``os.SplitPath``, ``os.extractDir``, ``os.SplitFilename``,
+  ``os.extractFileTrunk``, ``os.extractFileExt``, ``osproc.executeProcess``,
+  ``osproc.executeCommand``.
+- Removed deprecated ``parseopt.init``, ``parseopt.getRestOfCommandLine``.
+- Moved ``strutils.validEmailAddress`` to ``matchers.validEmailAddress``.
+- The pointer dereference operator ``^`` has been removed, so that ``^``
+  can now be a user-defined operator.
+- ``implies`` is no keyword anymore.
+- The ``is`` operator is now the ``of`` operator.
+- The ``is`` operator is now used to check type equivalence in generic code.
+- The ``pure`` pragma for procs has been renamed to ``noStackFrame``.
+- The threading API has been completely redesigned.
+- The ``unidecode`` module is now thread-safe and its interface has changed.
+- The ``bind`` expression is deprecated, use a ``bind`` declaration instead.
+- ``system.raiseHook`` is now split into ``system.localRaiseHook`` and
+  ``system.globalRaiseHook`` to distinguish between thread local and global
+  raise hooks.
+- Changed exception handling/error reporting for ``os.removeFile`` and
+  ``os.removeDir``.
+- The algorithm for searching and loading configuration files has been changed.
+- Operators now have diffent precedence rules: Assignment-like operators
+  (like ``*=``) are now special-cased.
+- The fields in ``TStream`` have been renamed to have an ``Impl`` suffix
+  because they should not be used directly anymore.
+  Wrapper procs have been created that should be used instead.
+- ``export`` is now a keyword.
+- ``assert`` is now implemented in pure Nimrod as a template; it's easy
+  to implement your own assertion templates with ``system.astToStr``.
+
+
+Language Additions
+------------------
+
+- Added new ``is`` and ``of`` operators.
+- The built-in type ``void`` can be used to denote the absence of any type.
+  This is useful in generic code.
+- Return types may be of the type ``var T`` to return an l-value.
+- The error pragma can now be used to mark symbols whose *usage* should trigger
+  a compile-time error.
+- There is a new ``discardable`` pragma that can be used to mark a routine
+  so that its result can be discarded implicitly.
+- Added a new ``noinit`` pragma to prevent automatic initialization to zero
+  of variables.
+- Constants can now have the type ``seq``.
+- There is a new user-definable syntactic construct ``a{i, ...}``
+  that has no semantics yet for built-in types and so can be overloaded to your
+  heart's content.
+- ``bind`` (used for symbol binding in templates and generics) is now a
+  declarative statement.
+- Nimrod now supports single assignment variables via the ``let`` statement.
+- Iterators named ``items`` and ``pairs`` are implicitly invoked when
+  an explicit iterator is missing.
+- The slice assignment ``a[i..j] = b`` where ``a`` is a sequence or string
+  now supports *splicing*.
+
+
+Compiler Additions
+------------------
+
+- The compiler can generate C++ code for easier interfacing with C++.
+- The compiler can generate Objective C code for easier interfacing with
+  Objective C.
+- The new pragmas ``importcpp`` and ``importobjc`` make interfacing with C++
+  and Objective C somewhat easier.
+- Added a new pragma ``incompleteStruct`` to deal with incomplete C struct
+  definitions.
+- Added a ``--nimcache:PATH`` configuration option for control over the output
+  directory for generated code.
+- The ``--genScript`` option now produces different compilation scripts
+  which do not contain absolute paths.
+- Added ``--cincludes:dir``, ``--clibdir:lib`` configuration options for
+  modifying the C compiler's header/library search path in cross-platform way.
+- Added ``--clib:lib`` configuration option for specifying additional
+  C libraries to be linked.
+- Added ``--mainmodule:file`` configuration options for specifying the main
+  project file. This is intended to be used in project configuration files to
+  allow commands like ``nimrod c`` or ``nimrod check`` to be executed anywhere
+  within the project's directory structure.
+- Added a ``--app:staticlib`` option for creating static libraries.
+- Added a ``--tlsEmulation:on|off`` switch for control over thread local
+  storage emulation.
+- The compiler and standard library now support a *taint mode*. Input strings
+  are declared with the ``TaintedString`` string type. If the taint
+  mode is turned on it is a distinct string type which helps to detect input
+  validation errors.
+- The compiler now supports the compilation cache via ``--symbolFiles:on``.
+  This potentially speeds up compilations by an order of magnitude, but is
+  still highly experimental!
+- Added ``--import:file`` and ``--include:file`` configuration options
+  for specifying modules that will be automatically imported/incluced.
+- ``nimrod i`` can now optionally be given a module to execute.
+- The compiler now performs a simple alias analysis to generate better code.
+- The compiler and ENDB now support *watchpoints*.
+- The compiler now supports proper compile time expressions of type ``bool``
+  for ``on|off`` switches in pragmas. In order to not break existing code,
+  ``on`` and ``off`` are now aliases for ``true`` and ``false`` and declared
+  in the system module.
+- The compiler finally supports **closures**. This is a preliminary
+  implementation, which does not yet support nestings deeper than 1 level
+  and still has many known bugs.
+
+
+Library Additions
+-----------------
+
+- Added ``system.allocShared``, ``system.allocShared0``,
+  ``system.deallocShared``, ``system.reallocShared``.
+- Slicing as implemented by the system module now supports *splicing*.
+- Added explicit channels for thread communication.
+- Added ``matchers`` module for email address etc. matching.
+- Added ``strutils.unindent``, ``strutils.countLines``,
+  ``strutils.replaceWord``.
+- Added ``system.slurp`` for easy resource embedding.
+- Added ``system.running`` for threads.
+- Added ``system.programResult``.
+- Added ``xmltree.innerText``.
+- Added ``os.isAbsolute``, ``os.dynLibFormat``, ``os.isRootDir``,
+  ``os.parentDirs``.
+- Added ``parseutils.interpolatedFragments``.
+- Added ``macros.treeRepr``, ``macros.lispRepr``, ``macros.dumpTree``,
+  ``macros.dumpLisp``, ``macros.parseExpr``, ``macros.parseStmt``,
+  ``macros.getAst``.
+- Added ``locks`` core module for more flexible locking support.
+- Added ``irc`` module.
+- Added ``ftpclient`` module.
+- Added ``memfiles`` module.
+- Added ``subexes`` module.
+- Added ``critbits`` module.
+- Added ``asyncio`` module.
+- Added ``actors`` module.
+- Added ``algorithm`` module for generic ``sort``, ``reverse`` etc. operations.
+- Added ``osproc.startCmd``, ``osproc.execCmdEx``.
+- The ``osproc`` module now uses ``posix_spawn`` instead of ``fork``
+  and ``exec`` on Posix systems. Define the symbol ``useFork`` to revert to
+  the old implementation.
+- Added ``intsets.assign``.
+- Added ``system.astToStr`` and ``system.rand``, ``system.doAssert``.
+- Added ``system.pairs`` for built-in types like arrays and strings.
+
+
+2011-07-10 Version 0.8.12 released
+==================================
+
+Bugfixes
+--------
+
+- Bugfix: ``httpclient`` correct passes the path starting with ``/``.
+- Bugfixes for the ``htmlparser`` module.
+- Bugfix: ``pegs.find`` did not respect ``start`` parameter.
+- Bugfix: ``dialogs.ChooseFilesToOpen`` did not work if only one file is
+  selected.
+- Bugfix: niminst: ``nimrod`` is not default dir for *every* project.
+- Bugfix: Multiple yield statements in iterators did not cause local vars to be
+  copied.
+- Bugfix: The compiler does not emit very inaccurate floating point literals
+  anymore.
+- Bugfix: Subclasses are taken into account for ``try except`` matching.
+- Bugfix: Generics and macros are more stable. There are still known bugs left
+  though.
+- Bugfix: Generated type information for tuples was sometimes wrong, causing
+  random crashes.
+- Lots of other bugfixes: Too many to list them all.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- Operators starting with ``^`` are now right-associative and have the highest
+  priority.
+- Deprecated ``os.getApplicationFilename``: Use ``os.getAppFilename`` instead.
+- Deprecated ``os.getApplicationDir``: Use ``os.getAppDir`` instead.
+- Deprecated ``system.copy``: Use ``substr`` or string slicing instead.
+- Changed and documented how generalized string literals work: The syntax
+  ``module.re"abc"`` is now supported.
+- Changed the behaviour of ``strutils.%``, ``ropes.%``
+  if both notations ``$#`` and ``$i`` are involved.
+- The ``pegs`` and ``re`` modules distinguish between ``replace``
+  and ``replacef`` operations.
+- The pointer dereference operation ``p^`` is deprecated and might become
+  ``^p`` in later versions or be dropped entirely since it is rarely used.
+  Use the new notation ``p[]`` in the rare cases where you need to
+  dereference a pointer explicitly.
+- ``system.readFile`` does not return ``nil`` anymore but raises an ``EIO``
+  exception instead.
+- Unsound co-/contravariance for procvars has been removed.
+
+
+Language Additions
+------------------
+
+- Source code filters are now documented.
+- Added the ``linearScanEnd``, ``unroll``, ``shallow`` pragmas.
+- Added ``emit`` pragma for direct code generator control.
+- Case statement branches support constant sets for programming convenience.
+- Tuple unpacking is not enforced in ``for`` loops anymore.
+- The compiler now supports array, sequence and string slicing.
+- A field in an ``enum`` may be given an explicit string representation.
+  This yields more maintainable code than using a constant
+  ``array[TMyEnum, string]`` mapping.
+- Indices in array literals may be explicitly given, enhancing readability:
+  ``[enumValueA: "a", enumValueB: "b"]``.
+- Added thread support via the ``threads`` core module and
+  the ``--threads:on`` command line switch.
+- The built-in iterators ``system.fields`` and ``system.fieldPairs`` can be
+  used to iterate over any field of a tuple. With this mechanism operations
+  like ``==`` and ``hash`` are lifted to tuples.
+- The slice ``..`` is now a first-class operator, allowing code like:
+  ``x in 1000..100_000``.
+
+
+Compiler Additions
+------------------
+
+- The compiler supports IDEs via the new group of ``idetools`` command line
+  options.
+- The *interactive mode* (REPL) has been improved and documented for the
+  first time.
+- The compiler now might use hashing for string case statements depending
+  on the number of string literals in the case statement.
+
+
+Library Additions
+-----------------
+
+- Added ``lists`` module which contains generic linked lists.
+- Added ``sets`` module which contains generic hash sets.
+- Added ``tables`` module which contains generic hash tables.
+- Added ``queues`` module which contains generic sequence based queues.
+- Added ``intsets`` module which contains a specialized int set data type.
+- Added ``scgi`` module.
+- Added ``smtp`` module.
+- Added ``encodings`` module.
+- Added ``re.findAll``, ``pegs.findAll``.
+- Added ``os.findExe``.
+- Added ``parseutils.parseUntil`` and ``parseutils.parseWhile``.
+- Added ``strutils.align``, ``strutils.tokenize``, ``strutils.wordWrap``.
+- Pegs support a *captured search loop operator* ``{@}``.
+- Pegs support new built-ins: ``\letter``, ``\upper``, ``\lower``,
+  ``\title``, ``\white``.
+- Pegs support the new built-in ``\skip`` operation.
+- Pegs support the ``$`` and ``^`` anchors.
+- Additional operations were added to the ``complex`` module.
+- Added ``strutils.formatFloat``,  ``strutils.formatBiggestFloat``.
+- Added unary ``<`` for nice looking excluding upper bounds in ranges.
+- Added ``math.floor``.
+- Added ``system.reset`` and a version of ``system.open`` that
+  returns a ``TFile`` and raises an exception in case of an error.
+- Added a wrapper for ``redis``.
+- Added a wrapper for ``0mq`` via the ``zmq`` module.
+- Added a wrapper for ``sphinx``.
+- Added ``system.newStringOfCap``.
+- Added ``system.raiseHook`` and ``system.outOfMemHook``.
+- Added ``system.writeFile``.
+- Added ``system.shallowCopy``.
+- ``system.echo`` is guaranteed to be thread-safe.
+- Added ``prelude`` include file for scripting convenience.
+- Added ``typeinfo`` core module for access to runtime type information.
+- Added ``marshal`` module for JSON serialization.
+
+
+2010-10-20 Version 0.8.10 released
+==================================
+
+Bugfixes
+--------
+
+- Bugfix: Command line parsing on Windows and ``os.parseCmdLine`` now adheres
+  to the same parsing rules as Microsoft's C/C++ startup code.
+- Bugfix: Passing a ``ref`` pointer to the untyped ``pointer`` type is invalid.
+- Bugfix: Updated ``keyval`` example.
+- Bugfix: ``system.splitChunk`` still contained code for debug output.
+- Bugfix: ``dialogs.ChooseFileToSave`` uses ``STOCK_SAVE`` instead of
+  ``STOCK_OPEN`` for the GTK backend.
+- Bugfix: Various bugs concerning exception handling fixed.
+- Bugfix: ``low(somestring)`` crashed the compiler.
+- Bugfix: ``strutils.endsWith`` lacked range checking.
+- Bugfix: Better detection for AMD64 on Mac OS X.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- Reversed parameter order for ``os.copyFile`` and ``os.moveFile``!!!
+- Procs not marked as ``procvar`` cannot only be passed to a procvar anymore,
+  unless they are used in the same module.
+- Deprecated ``times.getStartMilsecs``: Use ``epochTime`` or ``cpuTime``
+  instead.
+- Removed ``system.OpenFile``.
+- Removed ``system.CloseFile``.
+- Removed ``strutils.replaceStr``.
+- Removed ``strutils.deleteStr``.
+- Removed ``strutils.splitLinesSeq``.
+- Removed ``strutils.splitSeq``.
+- Removed ``strutils.toString``.
+- If a DLL cannot be loaded (via the ``dynlib`` pragma) ``EInvalidLibrary``
+  is not raised anymore. Instead ``system.quit()`` is called. This is because
+  raising an exception requires heap allocations. However the memory manager
+  might be contained in the DLL that failed to load.
+- The ``re`` module (and the ``pcre`` wrapper) now depend on the pcre dll.
+
+
+Additions
+---------
+
+- The ``{.compile: "file.c".}`` pragma uses a CRC check to see if the file
+  needs to be recompiled.
+- Added ``system.reopen``.
+- Added ``system.getCurrentException``.
+- Added ``system.appType``.
+- Added ``system.compileOption``.
+- Added ``times.epochTime`` and ``times.cpuTime``.
+- Implemented explicit type arguments for generics.
+- Implemented ``{.size: sizeof(cint).}`` pragma for enum types. This is useful
+  for interfacing with C.
+- Implemented ``{.pragma.}`` pragma for user defined pragmas.
+- Implemented ``{.extern.}`` pragma for better control of name mangling.
+- The ``importc`` and ``exportc`` pragmas support format strings:
+  ``proc p{.exportc: "nim_$1".}`` exports ``p`` as ``nim_p``. This is useful
+  for user defined pragmas.
+- The standard library can be built as a DLL. Generating DLLs has been
+  improved.
+- Added ``expat`` module.
+- Added ``json`` module.
+- Added support for a *Tiny C* backend. Currently this only works on Linux.
+  You need to bootstrap with ``-d:tinyc`` to enable Tiny C support. Nimrod
+  can then execute code directly via ``nimrod run myfile``.
+
+
+2010-03-14 Version 0.8.8 released
+=================================
+
+Bugfixes
+--------
+- The Posix version of ``os.copyFile`` has better error handling.
+- Fixed bug #502670 (underscores in identifiers).
+- Fixed a bug in the ``parsexml`` module concerning the parsing of
+  ``<tag attr="value" />``.
+- Fixed a bug in the ``parsexml`` module concerning the parsing of
+  enities like ``&ltXX``.
+- ``system.write(f: TFile, s: string)`` now works even if ``s`` contains binary
+  zeros.
+- Fixed a bug in ``os.setFilePermissions`` for Windows.
+- An overloadable symbol can now have the same name as an imported module.
+- Fixed a serious bug in ``strutils.cmpIgnoreCase``.
+- Fixed ``unicode.toUTF8``.
+- The compiler now rejects ``'\n'`` (use ``"\n"`` instead).
+- ``times.getStartMilsecs()`` now works on Mac OS X.
+- Fixed a bug in ``pegs.match`` concerning start offsets.
+- Lots of other little bugfixes.
+
+
+Additions
+---------
+- Added ``system.cstringArrayToSeq``.
+- Added ``system.lines(f: TFile)`` iterator.
+- Added ``system.delete``, ``system.del`` and ``system.insert`` for sequences.
+- Added ``system./`` for int.
+- Exported ``system.newException`` template.
+- Added ``cgi.decodeData(data: string): tuple[key, value: string]``.
+- Added ``strutils.insertSep``.
+- Added ``math.trunc``.
+- Added ``ropes`` module.
+- Added ``sockets`` module.
+- Added ``browsers`` module.
+- Added ``httpserver`` module.
+- Added ``httpclient`` module.
+- Added ``parseutils`` module.
+- Added ``unidecode`` module.
+- Added ``xmldom`` module.
+- Added ``xmldomparser`` module.
+- Added ``xmltree`` module.
+- Added ``xmlparser`` module.
+- Added ``htmlparser`` module.
+- Added ``re`` module.
+- Added ``graphics`` module.
+- Added ``colors`` module.
+- Many wrappers now do not contain redundant name prefixes (like ``GTK_``,
+  ``lua``). The old wrappers are still available in ``lib/oldwrappers``.
+  You can change your configuration file to use these.
+- Triple quoted strings allow for ``"`` in more contexts.
+- ``""`` within raw string literals stands for a single quotation mark.
+- Arguments to ``openArray`` parameters can be left out.
+- More extensive subscript operator overloading. (To be documented.)
+- The documentation generator supports the ``.. raw:: html`` directive.
+- The Pegs module supports back references via the notation ``$capture_index``.
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+
+- Overloading of the subscript operator only works if the type does not provide
+  a built-in one.
+- The search order for libraries which is affected by the ``path`` option
+  has been reversed, so that the project's path is searched before
+  the standard library's path.
+- The compiler does not include a Pascal parser for bootstrapping purposes any
+  more. Instead there is a ``pas2nim`` tool that contains the old functionality.
+- The procs ``os.copyFile`` and ``os.moveFile`` have been deprecated
+  temporarily, so that the compiler warns about their usage. Use them with
+  named arguments only, because the parameter order will change the next
+  version!
+- ``atomic`` and ``let`` are now keywords.
+- The ``\w`` character class for pegs now includes the digits ``'0'..'9'``.
+- Many wrappers now do not contain redundant name prefixes (like ``GTK_``,
+  ``lua``) anymore.
+- Arguments to ``openArray`` parameters can be left out.
+
+
+2009-12-21 Version 0.8.6 released
+=================================
+
+The version jump from 0.8.2 to 0.8.6 acknowledges the fact that all development
+of the compiler is now done in Nimrod.
+
+
+Bugfixes
+--------
+- The pragmas ``hint[X]:off`` and ``warning[X]:off`` now work.
+- Method call syntax for iterators works again (``for x in lines.split()``).
+- Fixed a typo in ``removeDir`` for POSIX that lead to an infinite recursion.
+- The compiler now checks that module filenames are valid identifiers.
+- Empty patterns for the ``dynlib`` pragma are now possible.
+- ``os.parseCmdLine`` returned wrong results for trailing whitespace.
+- Inconsequent tuple usage (using the same tuple with and without named fields)
+  does not crash the code generator anymore.
+- A better error message is provided when the loading of a proc within a
+  dynamic lib fails.
+
+
+Additions
+---------
+- Added ``system.contains`` for open arrays.
+- The PEG module now supports the *search loop operator* ``@``.
+- Grammar/parser: ``SAD|IND`` is allowed before any kind of closing bracket.
+  This allows for more flexible source code formating.
+- The compiler now uses a *bind* table for symbol lookup within a ``bind``
+  context. (See `<manual.html#templates>`_ for details.)
+- ``discard """my long comment"""`` is now optimized away.
+- New ``--floatChecks: on|off`` switches and pragmas for better debugging
+  of floating point operations. (See
+  `<manual.html#pre-defined-floating-point-types>`_ for details.)
+- The manual has been improved. (Many thanks to Philippe Lhoste!)
+
+
+Changes affecting backwards compatibility
+-----------------------------------------
+- The compiler does not skip the linking step anymore even if no file
+  has changed.
+- ``os.splitFile(".xyz")`` now returns ``("", ".xyz", "")`` instead of
+  ``("", "", ".xyz")``. So filenames starting with a dot are handled
+  differently.
+- ``strutils.split(s: string, seps: set[char])`` never yields the empty string
+  anymore. This behaviour is probably more appropriate for whitespace splitting.
+- The compiler now stops after the ``--version`` command line switch.
+- Removed support for enum inheritance in the parser; enum inheritance has
+  never been documented anyway.
+- The ``msg`` field of ``system.E_base`` has now the type ``string``, instead
+  of ``cstring``. This improves memory safety.
+
+
+2009-10-21 Version 0.8.2 released
+=================================
+
+
+2009-09-12 Version 0.8.0 released
+=================================
+
+
+2009-06-08 Version 0.7.10 released
+==================================
+
+
+2009-05-08 Version 0.7.8 released
+=================================
+
+
+2009-04-22 Version 0.7.6 released
+=================================
+
+
+2008-11-16 Version 0.7.0 released
+=================================
+
+
+2008-08-22 Version 0.6.0 released
+=================================
+
+Nimrod version 0.6.0 has been released!
+**This is the first version of the compiler that is able to compile itself!**
diff --git a/web/nimblepkglist.nim b/web/nimblepkglist.nim
new file mode 100644
index 000000000..7070f281b
--- /dev/null
+++ b/web/nimblepkglist.nim
@@ -0,0 +1,76 @@
+import base64, strutils, json, htmlgen, dom, algorithm
+
+type
+  TData = object
+    content {.importc.}: cstring
+
+proc decodeContent(content: string): string =
+  result = ""
+  for line in content.splitLines:
+    if line != "":
+      result.add decode(line)
+
+proc contains(x: seq[JSonNode], s: string): bool =
+  for i in x:
+    assert i.kind == JString
+    if i.str == s: return true
+
+proc processContent(content: string) =
+  var jsonDoc = parseJson(content)
+  assert jsonDoc.kind == JArray
+  var jsonArr = jsonDoc.elems
+
+  jsonArr.sort do (x, y: JsonNode) -> int:
+    strutils.cmpIgnoreCase(x["name"].str, y["name"].str)
+
+  var
+    officialList = ""
+    officialCount = 0
+    unofficialList = ""
+    unofficialCount = 0
+  let
+    endings = {'.', '!'}
+
+  for pkg in jsonArr:
+    assert pkg.kind == JObject
+    let pkgWeb =
+      if pkg.hasKey("web"): pkg["web"].str
+      else: pkg["url"].str
+    let
+      desc = pkg["description"].str
+      dot = if desc.high > 0 and desc[desc.high] in endings: "" else: "."
+      listItem = li(a(href=pkgWeb, pkg["name"].str), " ", desc & dot)
+    if pkg["url"].str.startsWith("git://github.com/nimrod-code") or
+       pkg["url"].str.startsWith("git://github.com/nim-lang") or
+       "official" in pkg["tags"].elems:
+      officialCount.inc
+      officialList.add listItem & "\n"
+    else:
+      unofficialCount.inc
+      unofficialList.add listItem & "\n"
+
+  var officialPkgListDiv = document.getElementById("officialPkgList")
+
+  officialPkgListDiv.innerHTML =
+    p("There are currently " & $officialCount &
+      " official packages in the Nimble package repository.") &
+    ul(officialList)
+
+  var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
+
+  unofficialPkgListDiv.innerHTML =
+    p("There are currently " & $unofficialCount &
+      " unofficial packages in the Nimble package repository.") &
+    ul(unofficialList)
+
+proc gotPackageList(apiReply: TData) {.exportc.} =
+  let decoded = decodeContent($apiReply.content)
+  try:
+    processContent(decoded)
+  except:
+    var officialPkgListDiv = document.getElementById("officialPkgList")
+    var unofficialPkgListDiv = document.getElementById("unofficialPkgList")
+    let msg = p("Unable to retrieve package list: ",
+      code(getCurrentExceptionMsg()))
+    officialPkgListDiv.innerHTML = msg
+    unofficialPkgListDiv.innerHTML = msg
diff --git a/web/question.txt b/web/question.txt
new file mode 100644
index 000000000..c4d997922
--- /dev/null
+++ b/web/question.txt
@@ -0,0 +1,169 @@
+===========================================
+         Questions and Answers
+===========================================
+
+
+General FAQ
+===========
+
+
+.. container:: standout
+
+  What is Nim?
+  ------------
+
+  Nim (formerly known as "Nimrod") is a statically typed, imperative programming
+  language that tries to give the programmer ultimate power without compromises
+  on runtime efficiency.
+  This means it focuses on compile-time mechanisms in all their
+  various forms. Beneath a nice infix/indentation based syntax with a
+  powerful (AST based, hygienic) macro system lies a semantic model that supports
+  a soft realtime GC on thread local heaps. Asynchronous message passing is used
+  between threads, so no "stop the world" mechanism is necessary. An unsafe
+  shared memory heap is also provided for the increased efficiency that results
+  from that model.
+
+
+.. container:: standout
+
+  Why yet another programming language?
+  -------------------------------------
+
+  Nim is one of the very few *programmable* statically typed languages, and
+  one of the even fewer that produces native binaries that require no
+  runtime or interpreter.
+
+
+.. container:: standout
+
+  What have been the major influences in the language's design?
+  -------------------------------------------------------------
+
+  The language borrows heavily from (in order of impact): Modula 3, Delphi, Ada,
+  C++, Python, Lisp, Oberon.
+
+
+.. container:: standout
+
+  What is Nim's take on concurrency?
+  ----------------------------------
+
+  Nim primarily focusses on thread local (and garbage collected) heaps and
+  message passing between threads. Each thread has its own GC, so no
+  "stop the world" mechanism is necessary. An unsafe shared memory heap is also
+  provided.
+
+  Future versions will additionally include a GC "per thread group"
+  and Nim's type system will be enhanced to accurately model this shared
+  memory heap.
+
+
+.. container:: standout
+
+  How is Nim licensed?
+  --------------------
+
+  The Nim compiler and the library are MIT licensed.
+  This means that you can use any license for your own programs developed with
+  Nim.
+
+
+.. container:: standout
+
+  How stable is Nim?
+  ------------------
+
+  The compiler is in development and some important features are still missing.
+  However, the compiler is quite stable already: It is able to compile itself
+  and a substantial body of other code. Until version 1.0.0 is released,
+  minor incompatibilities with older versions of the compiler will be introduced.
+
+
+.. container:: standout
+
+  How fast is Nim?
+  ----------------
+  Benchmarks show it to be comparable to C. Some language features (methods,
+  closures, message passing) are not yet as optimized as they could and will be.
+  The only overhead Nim has over C is the GC which has been tuned
+  for years but still needs some work.
+
+
+.. container:: standout
+
+  What about JVM/CLR backends?
+  ----------------------------
+
+  A JVM backend is almost impossible. The JVM is not expressive enough. It has
+  never been designed as a general purpose VM anyway. A CLR backend is possible
+  but would require much work.
+
+
+.. container:: standout
+
+  What about editor support?
+  --------------------------
+
+  - Nim IDE: https://github.com/nim-lang/Aporia
+  - Emacs: https://github.com/reactormonk/nim-mode
+  - Vim: https://github.com/zah/nimrod.vim/
+  - Scite: Included
+  - Gedit: The `Aporia .lang file <https://github.com/nim-lang/Aporia/blob/master/share/gtksourceview-2.0/language-specs/nim.lang>`_
+  - jEdit: https://github.com/exhu/nimrod-misc/tree/master/jedit
+  - TextMate: Available in bundle installer (`Repository <https://github.com/textmate/nim.tmbundle>`_)
+  - Sublime Text: Available via Package Control (`Repository <https://github.com/Varriount/NimLime>`_)
+  - LiClipse: http://www.liclipse.com/ (Eclipse based plugin)
+
+
+.. container:: standout
+
+  Why is it named ``proc``?
+  -------------------------
+
+  *Procedure* used to be the common term as opposed to a *function* which is a
+  mathematical entity that has no side effects. It is planned to have ``func``
+  as syntactic sugar for ``proc {.noSideEffect.}`` and ``func`` is already a
+  keyword.
+
+
+Compilation FAQ
+===============
+
+.. container:: standout
+
+  Which option to use for the fastest executable?
+  -----------------------------------------------
+
+  For the standard configuration file, ``-d:release`` does the trick.
+
+.. container:: standout
+
+  Which option to use for the smallest executable?
+  ------------------------------------------------
+
+  For the standard configuration file, ``-d:quick --opt:size`` does the trick.
+
+.. container:: standout
+
+  How do I use a different C compiler than the default one?
+  ---------------------------------------------------------
+
+  Edit the ``config/nim.cfg`` file.
+  Change the value of the ``cc`` variable to one of the following:
+
+  ================  ============================================
+  **Abbreviation**  **C/C++ Compiler**
+  ================  ============================================
+  ``vcc``           Microsoft's Visual C++
+  ``gcc``           Gnu C
+  ``llvm_gcc``      LLVM-GCC compiler
+  ``icc``           Intel C++ compiler
+  ``clang``         Clang compiler
+  ``ucc``           Generic UNIX C compiler
+  ================  ============================================
+
+  Other C compilers are not officially supported, but might work too.
+
+  If your C compiler is not in the above list, try using the
+  *generic UNIX C compiler* (``ucc``). If the C compiler needs
+  different command line arguments try the ``--passc`` and ``--passl`` switches.
diff --git a/web/snippets/snippet1.nim b/web/snippets/snippet1.nim
new file mode 100644
index 000000000..85cb98142
--- /dev/null
+++ b/web/snippets/snippet1.nim
@@ -0,0 +1,4 @@
+import strutils
+echo "Give a list of integers (separated by spaces): ", 
+     stdin.readLine.split.each(parseInt).max,
+     " is the maximum!"

diff --git a/web/support.txt b/web/support.txt
new file mode 100644
index 000000000..f8375b6aa
--- /dev/null
+++ b/web/support.txt
@@ -0,0 +1,39 @@
+Commercial and Community Support
+================================
+
+We offer a multitude of support networks including those in both a community
+and commercial setting.
+
+Commercial support includes:
+
+.. container:: standout
+
+  Priority Bug Fixes
+  ------------------
+
+  File a bug report and we will address them with the highest priority. Once
+  fixed, you will be able to access either the current Git build or at your
+  request a custom build against the latest release with your bug fixed.
+
+
+.. container:: standout
+
+  Feature Requests
+  ----------------
+
+  Suggest to us any feature that you might need, we will examine your request with
+  care and provide a proper answer about its potential for inclusion.
+
+  Communication happens via email or for a slightly higher fee via Skype.
+  The pricing is based on the amount of hours spent on the bugfix / feature
+  implementation and is open to negotiation.
+
+
+All interested parties should email ``support@nim-lang.org``. 
+The bid for contracting work is a commercial offer provided by:
+
+| **Andreas Rumpf**
+| St.-Quentin-Ring 47
+| 67663 Kaiserslautern
+| GERMANY
+| EU VAT-IN: DE297783450
diff --git a/web/ticker.txt b/web/ticker.txt
new file mode 100644
index 000000000..4840e4039
--- /dev/null
+++ b/web/ticker.txt
@@ -0,0 +1,16 @@
+<a class="news" href="news.html#Z2015-05-04-version-0-11-2-released">
+  <h4>May 4, 2015</h4>
+  <p>Nim version 0.11.2 has been released!</p>
+</a>
+
+<a class="news" href="news.html#Z2014-12-29-version-0-10-2-released">
+  <h4>Dec 29, 2014</h4>
+  <p>Nim version 0.10.2 has been released!</p>
+</a>
+
+<a class="news" href="news.html#Z2014-02-11-nimrod-featured-in-dr-dobb-s-journal">
+  <h4>Feb 11, 2014</h4>
+  <p>Nimrod featured in Dr. Dobb's Journal</p>
+</a>
+
+<a href="news.html" class="blue">See All News...</a>
diff --git a/web/website.ini b/web/website.ini
new file mode 100644
index 000000000..bb9f1b204
--- /dev/null
+++ b/web/website.ini
@@ -0,0 +1,84 @@
+[Project]
+Name: "Nim"
+Title: "Nim Programming Language"
+Logo: "efficient, expressive, elegant"
+Authors: "Andreas Rumpf and contributors"
+
+[Links]
+# Underscores are replaced with a space.
+# Everything after ; is the ID
+Community: "community.html;link_forum"
+Aporia_IDE: "https://github.com/nim-lang/Aporia;link_aporia"
+Github_Repo: "http://github.com/Araq/Nim;link_github"
+
+
+[Tabs]
+# Menu entry: filename
+home: index
+learn: learn
+docs: documentation
+download: download
+support: support
+forum: "http://forum.nim-lang.org"
+faq: question
+# these two are not in the list of "tabs", but do exist:
+community: community
+news: news
+
+[Ticker]
+file: ticker.txt
+
+[Documentation]
+doc: "endb;intern;apis;lib;manual.txt;tut1;tut2;nimc;overview;filters"
+doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
+doc: "nimfix.txt;nimsuggest.txt"
+pdf: "manual.txt;lib;tut1;tut2;nimc;niminst;gc"
+srcdoc2: "system.nim"
+srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
+srcdoc2: "impure/re;pure/sockets;pure/typetraits"
+srcdoc2: "pure/concurrency/threadpool.nim;pure/concurrency/cpuinfo.nim"
+srcdoc: "system/threads.nim;system/channels.nim;js/dom"
+srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"
+srcdoc2: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib"
+srcdoc2: "pure/parseopt;pure/parseopt2;pure/hashes;pure/strtabs;pure/lexbase"
+srcdoc2: "pure/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql"
+srcdoc2: "pure/streams;pure/terminal;pure/cgi;pure/unicode"
+srcdoc2: "impure/zipfiles;pure/htmlgen;pure/parseutils;pure/browsers"
+srcdoc2: "impure/db_postgres;impure/db_mysql;impure/db_sqlite"
+srcdoc2: "pure/httpserver;pure/httpclient;pure/smtp;impure/ssl;pure/fsmonitor"
+srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser"
+srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes"
+srcdoc2: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics"
+srcdoc2: "impure/rdstdin;impure/dialogs"
+srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists"
+srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings"
+srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies"
+srcdoc2: "pure/ftpclient;pure/memfiles;pure/subexes;pure/collections/critbits"
+srcdoc2: "pure/asyncio;pure/actors;core/locks;pure/oids;pure/endians;pure/uri"
+srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite"
+srcdoc2: "packages/docutils/rst;packages/docutils/rstast"
+srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet"
+srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future"
+srcdoc2: "pure/asyncfile"
+srcdoc2: "pure/md5;pure/rationals"
+srcdoc2: "posix/posix"
+srcdoc2: "pure/fenv"
+srcdoc2: "pure/basic2d;pure/basic3d"
+
+; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers
+; should live here
+
+webdoc: "wrappers/mysql;wrappers/iup;wrappers/sphinx"
+webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc;wrappers/odbcsql"
+webdoc: "wrappers/expat;wrappers/pcre"
+webdoc: "wrappers/tre;wrappers/openssl"
+webdoc: "wrappers/libuv;wrappers/joyent_http_parser"
+
+webdoc: "posix/posix;wrappers/odbcsql"
+webdoc: "wrappers/zip/zlib;wrappers/zip/libzip"
+webdoc: "wrappers/libsvm.nim"
+webdoc: "windows"
+webdoc: "wrappers/readline/readline;wrappers/readline/history"
+webdoc: "wrappers/readline/rltypedefs"
+
+